From befc7a40781cea62819e8d6de64bb2b848f22f93 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Sun, 25 May 2014 15:46:23 +0200 Subject: [PATCH 0001/3725] adding column for the content of the container --- CMakeLists.txt | 4 -- apps/opencs/model/world/columns.hpp | 1 + apps/opencs/model/world/idtable.cpp | 1 + apps/opencs/model/world/refidadapterimp.cpp | 4 +- apps/opencs/model/world/refidadapterimp.hpp | 7 ++-- apps/opencs/model/world/refidcollection.cpp | 5 ++- apps/opencs/model/world/refiddata.hpp | 42 ++++++++++----------- 7 files changed, 33 insertions(+), 31 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 392fdfc66..9168d9a5a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -38,16 +38,12 @@ if(EXISTS ${PROJECT_SOURCE_DIR}/.git) set(GIT_VERSION "${GIT_VERSION_MAJOR}.${GIT_VERSION_MINOR}.${GIT_VERSION_RELEASE}") - if(NOT ${OPENMW_VERSION} STREQUAL ${GIT_VERSION}) - message(FATAL_ERROR "Silly Zini forgot to update the version again...") - else(NOT ${OPENMW_VERSION} STREQUAL ${GIT_VERSION}) set(OPENMW_VERSION_MAJOR ${GIT_VERSION_MAJOR}) set(OPENMW_VERSION_MINOR ${GIT_VERSION_MINOR}) set(OPENMW_VERSION_RELEASE ${GIT_VERSION_RELEASE}) set(OPENMW_VERSION_COMMITHASH "${COMMITHASH}") set(OPENMW_VERSION_TAGHASH "${TAGHASH}") - endif(NOT ${OPENMW_VERSION} STREQUAL ${GIT_VERSION}) message(STATUS "OpenMW version ${OPENMW_VERSION}") else(MATCH) diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 855e89cad..fa9c92e7d 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -167,6 +167,7 @@ namespace CSMWorld ColumnId_PcRank = 154, ColumnId_Scope = 155, ColumnId_ReferenceableId = 156, + ColumnId_ContainerContent = 157, // Allocated to a separate value range, so we don't get a collision should we ever need // to extend the number of use values. diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 50998c36f..31797d081 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -130,6 +130,7 @@ void CSMWorld::IdTable::cloneRecord(const std::string& origin, CSMWorld::UniversalId::Type type) { int index = mIdCollection->getAppendIndex (destination); + beginInsertRows (QModelIndex(), index, index); mIdCollection->cloneRecord(origin, destination, type); endInsertRows(); diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index f00e9fc77..afb61acc6 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -173,9 +173,9 @@ void CSMWorld::ClothingRefIdAdapter::setData (const RefIdColumn *column, RefIdDa } CSMWorld::ContainerRefIdAdapter::ContainerRefIdAdapter (const NameColumns& columns, - const RefIdColumn *weight, const RefIdColumn *organic, const RefIdColumn *respawn) + const RefIdColumn *weight, const RefIdColumn *organic, const RefIdColumn *respawn, const RefIdColumn *content) : NameRefIdAdapter (UniversalId::Type_Container, columns), mWeight (weight), - mOrganic (organic), mRespawn (respawn) + mOrganic (organic), mRespawn (respawn), mContent(content) {} QVariant CSMWorld::ContainerRefIdAdapter::getData (const RefIdColumn *column, const RefIdData& data, diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index bd509a86b..59c8c6461 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -34,7 +34,7 @@ namespace CSMWorld BaseRefIdAdapter (UniversalId::Type type, const BaseColumns& base); virtual std::string getId (const RecordBase& record) const; - + virtual void setId (RecordBase& record, const std::string& id); virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index) @@ -57,7 +57,7 @@ namespace CSMWorld { (dynamic_cast&> (record).get().mId) = id; } - + template std::string BaseRefIdAdapter::getId (const RecordBase& record) const { @@ -610,11 +610,12 @@ namespace CSMWorld const RefIdColumn *mWeight; const RefIdColumn *mOrganic; const RefIdColumn *mRespawn; + const RefIdColumn *mContent; public: ContainerRefIdAdapter (const NameColumns& columns, const RefIdColumn *weight, - const RefIdColumn *organic, const RefIdColumn *respawn); + const RefIdColumn *organic, const RefIdColumn *respawn, const RefIdColumn *content); virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index) const; diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index f515e34d8..1745ce957 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -165,6 +165,9 @@ CSMWorld::RefIdCollection::RefIdCollection() mColumns.push_back (RefIdColumn (Columns::ColumnId_Respawn, ColumnBase::Display_Boolean)); const RefIdColumn *respawn = &mColumns.back(); + mColumns.push_back(RefIdColumn (Columns::ColumnId_ContainerContent, ColumnBase::Display_None, ColumnBase::Flag_Dialogue, false, false)); + const RefIdColumn *content = &mColumns.back(); + CreatureColumns creatureColumns (actorsColumns); mColumns.push_back (RefIdColumn (Columns::ColumnId_CreatureType, ColumnBase::Display_CreatureType)); @@ -340,7 +343,7 @@ CSMWorld::RefIdCollection::RefIdCollection() mAdapters.insert (std::make_pair (UniversalId::Type_Clothing, new ClothingRefIdAdapter (enchantableColumns, clothingType))); mAdapters.insert (std::make_pair (UniversalId::Type_Container, - new ContainerRefIdAdapter (nameColumns, weightCapacity, organic, respawn))); + new ContainerRefIdAdapter (nameColumns, weightCapacity, organic, respawn, content))); mAdapters.insert (std::make_pair (UniversalId::Type_Creature, new CreatureRefIdAdapter (creatureColumns))); mAdapters.insert (std::make_pair (UniversalId::Type_Door, diff --git a/apps/opencs/model/world/refiddata.hpp b/apps/opencs/model/world/refiddata.hpp index 1b600364c..535e914ee 100644 --- a/apps/opencs/model/world/refiddata.hpp +++ b/apps/opencs/model/world/refiddata.hpp @@ -231,27 +231,27 @@ namespace CSMWorld void save (int index, ESM::ESMWriter& writer) const; - //RECORD CONTAINERS ACCESS METHODS - const RefIdDataContainer& getBooks() const; - const RefIdDataContainer& getActivators() const; - const RefIdDataContainer& getPotions() const; - const RefIdDataContainer& getApparati() const; - const RefIdDataContainer& getArmors() const; - const RefIdDataContainer& getClothing() const; - const RefIdDataContainer& getContainers() const; - const RefIdDataContainer& getCreatures() const; - const RefIdDataContainer& getDoors() const; - const RefIdDataContainer& getIngredients() const; - const RefIdDataContainer& getCreatureLevelledLists() const; - const RefIdDataContainer& getItemLevelledList() const; - const RefIdDataContainer& getLights() const; - const RefIdDataContainer& getLocpicks() const; - const RefIdDataContainer& getMiscellaneous() const; - const RefIdDataContainer& getNPCs() const; - const RefIdDataContainer& getWeapons() const; - const RefIdDataContainer& getProbes() const; - const RefIdDataContainer& getRepairs() const; - const RefIdDataContainer& getStatics() const; + //RECORD CONTAINERS ACCESS METHODS + const RefIdDataContainer& getBooks() const; + const RefIdDataContainer& getActivators() const; + const RefIdDataContainer& getPotions() const; + const RefIdDataContainer& getApparati() const; + const RefIdDataContainer& getArmors() const; + const RefIdDataContainer& getClothing() const; + const RefIdDataContainer& getContainers() const; + const RefIdDataContainer& getCreatures() const; + const RefIdDataContainer& getDoors() const; + const RefIdDataContainer& getIngredients() const; + const RefIdDataContainer& getCreatureLevelledLists() const; + const RefIdDataContainer& getItemLevelledList() const; + const RefIdDataContainer& getLights() const; + const RefIdDataContainer& getLocpicks() const; + const RefIdDataContainer& getMiscellaneous() const; + const RefIdDataContainer& getNPCs() const; + const RefIdDataContainer& getWeapons() const; + const RefIdDataContainer& getProbes() const; + const RefIdDataContainer& getRepairs() const; + const RefIdDataContainer& getStatics() const; }; } From 41db48720d49d0b87bc1bc8d705bfb4ae7785ef5 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Tue, 27 May 2014 14:01:15 +0200 Subject: [PATCH 0002/3725] does not compile --- apps/opencs/model/world/refidadapter.cpp | 16 +++++- apps/opencs/model/world/refidadapter.hpp | 7 +++ apps/opencs/model/world/refidadapterimp.cpp | 60 +++++++++++++++++++++ apps/opencs/model/world/refidadapterimp.hpp | 8 +++ 4 files changed, 90 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/world/refidadapter.cpp b/apps/opencs/model/world/refidadapter.cpp index 94ae38c3c..283f062fe 100644 --- a/apps/opencs/model/world/refidadapter.cpp +++ b/apps/opencs/model/world/refidadapter.cpp @@ -1,6 +1,20 @@ #include "refidadapter.hpp" +#include "cassert" +#include + CSMWorld::RefIdAdapter::RefIdAdapter() {} -CSMWorld::RefIdAdapter::~RefIdAdapter() {} \ No newline at end of file +CSMWorld::RefIdAdapter::~RefIdAdapter() {} + +QVariant CSMWorld::RefIdAdapter::getData (const CSMWorld::RefIdColumn* column, const CSMWorld::RefIdData& data, int idnex, int subRowIndex, int subColIndex) const +{ + assert(false); + return QVariant(); +} + +void CSMWorld::RefIdAdapter::setData (const CSMWorld::RefIdColumn* column, CSMWorld::RefIdData& data, const QVariant& value, int index, int subRowIndex, int subColIndex) const +{ + assert(false); +} diff --git a/apps/opencs/model/world/refidadapter.hpp b/apps/opencs/model/world/refidadapter.hpp index 0870a2d3e..673b1f5a4 100644 --- a/apps/opencs/model/world/refidadapter.hpp +++ b/apps/opencs/model/world/refidadapter.hpp @@ -30,6 +30,13 @@ namespace CSMWorld const QVariant& value) const = 0; ///< If the data type does not match an exception is thrown. + virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, + int idnex, int subRowIndex, int subColIndex) const; + + virtual void setData (const RefIdColumn *column, RefIdData& data, + const QVariant& value, int index, + int subRowIndex, int subColIndex) const; + virtual std::string getId (const RecordBase& record) const = 0; virtual void setId(RecordBase& record, const std::string& id) = 0; }; diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index afb61acc6..df64e9f05 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -222,6 +222,66 @@ void CSMWorld::ContainerRefIdAdapter::setData (const RefIdColumn *column, RefIdD NameRefIdAdapter::setData (column, data, index, value); } +void CSMWorld::ContainerRefIdAdapter::setData(const RefIdColumn *column, RefIdData& data, + int index, + const QVariant& value, + int subRowIndex, + int subColIndex) +{ + using RefIdAdapter::setData; + Record& record = static_cast&> ( + data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Container))); + + if (column==mContent) + { + switch (subColIndex) + { + case 0: + record.get().mInventory.mList.at(subRowIndex).mItem.assign(std::string(value.toString().toUtf8().constData())); + break; + + case 1: + record.get().mInventory.mList.at(subRowIndex).mCount = value.toInt(); + break; + } + } else + { + throw "This column does not hold multiple values."; + } +} + +QVariant CSMWorld::ContainerRefIdAdapter::getData (const CSMWorld::RefIdColumn* column, + const CSMWorld::RefIdData& data, + int index, + int subRowIndex, + int subColIndex) const +{ + using RefIdAdapter::getData; + const Record& record = static_cast&> ( + data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Container))); + + if (column==mContent) + { + const ESM::ContItem& content = record.get().mInventory.mList.at(subRowIndex); + + switch (subColIndex) + { + case 0: + return QString::fromUtf8(content.mItem.toString().c_str()); + + case 1: + return content.mCount; + + default: + throw "Trying to access non-existing column in the nested table!"; + } + } else + { + throw "This column does not hold multiple values."; + } +} + + CSMWorld::CreatureColumns::CreatureColumns (const ActorColumns& actorColumns) : ActorColumns (actorColumns) {} diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index 59c8c6461..f29501698 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -617,9 +617,17 @@ namespace CSMWorld ContainerRefIdAdapter (const NameColumns& columns, const RefIdColumn *weight, const RefIdColumn *organic, const RefIdColumn *respawn, const RefIdColumn *content); + using RefIdAdapter::getData; + virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index, + int subRowIndex, int subColIndex) const; + virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index) const; + using RefIdAdapter::setData; + virtual void setData (const RefIdColumn *column, RefIdData& data, int index, + const QVariant& value, int subRowIndex, int subColIndex) const; + virtual void setData (const RefIdColumn *column, RefIdData& data, int index, const QVariant& value) const; ///< If the data type does not match an exception is thrown. From 6720d85a04315ddd1d1807dfeb7646b438159790 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Tue, 27 May 2014 14:50:21 +0200 Subject: [PATCH 0003/3725] fixed compilation, thanks greye --- apps/opencs/model/world/refidadapterimp.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index df64e9f05..8c98e1808 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -226,9 +226,8 @@ void CSMWorld::ContainerRefIdAdapter::setData(const RefIdColumn *column, RefIdDa int index, const QVariant& value, int subRowIndex, - int subColIndex) + int subColIndex) const { - using RefIdAdapter::setData; Record& record = static_cast&> ( data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Container))); @@ -256,7 +255,6 @@ QVariant CSMWorld::ContainerRefIdAdapter::getData (const CSMWorld::RefIdColumn* int subRowIndex, int subColIndex) const { - using RefIdAdapter::getData; const Record& record = static_cast&> ( data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Container))); From 55d451febef1d0e204d5782b71c9330a2f8cd2d7 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Mon, 2 Jun 2014 20:41:37 +0200 Subject: [PATCH 0004/3725] changes in the model (idtable) to support nested data --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/world/collection.hpp | 8 +++ apps/opencs/model/world/collectionbase.cpp | 1 + apps/opencs/model/world/collectionbase.hpp | 2 + apps/opencs/model/world/columnbase.hpp | 10 +++- apps/opencs/model/world/idtable.cpp | 54 ++++++++++++++++++--- apps/opencs/model/world/idtable.hpp | 11 +++++ apps/opencs/model/world/refidadapter.cpp | 4 +- apps/opencs/model/world/refidadapter.hpp | 4 +- apps/opencs/model/world/refidadapterimp.cpp | 7 ++- apps/opencs/model/world/refidadapterimp.hpp | 6 +-- apps/opencs/model/world/refidcollection.cpp | 12 ++++- apps/opencs/model/world/refidcollection.hpp | 2 + apps/opencs/view/world/dialoguesubview.cpp | 46 ++++++++++-------- apps/opencs/view/world/util.cpp | 3 +- 15 files changed, 133 insertions(+), 39 deletions(-) diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index cbe90b1d3..d41a015ca 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -18,7 +18,7 @@ opencs_hdrs_noqt (model/doc opencs_units (model/world - idtable idtableproxymodel regionmap data + idtable idtableproxymodel regionmap data nestedtablemodel ) diff --git a/apps/opencs/model/world/collection.hpp b/apps/opencs/model/world/collection.hpp index 1fb3e1f1d..88ef59ace 100644 --- a/apps/opencs/model/world/collection.hpp +++ b/apps/opencs/model/world/collection.hpp @@ -82,6 +82,8 @@ namespace CSMWorld virtual QVariant getData (int index, int column) const; + virtual QVariant getNestedData(int row, int column, int subRow, int subColumn) const; + virtual void setData (int index, int column, const QVariant& data); virtual const ColumnBase& getColumn (int column) const; @@ -277,6 +279,12 @@ namespace CSMWorld return mColumns.at (column)->get (mRecords.at (index)); } + template + QVariant Collection::getNestedData(int row, int column, int subRow, int subColumn) const + { + return 10; //TODO + } + template void Collection::setData (int index, int column, const QVariant& data) { diff --git a/apps/opencs/model/world/collectionbase.cpp b/apps/opencs/model/world/collectionbase.cpp index 241f198cb..7b6912575 100644 --- a/apps/opencs/model/world/collectionbase.cpp +++ b/apps/opencs/model/world/collectionbase.cpp @@ -2,6 +2,7 @@ #include "collectionbase.hpp" #include +#include #include "columnbase.hpp" diff --git a/apps/opencs/model/world/collectionbase.hpp b/apps/opencs/model/world/collectionbase.hpp index 442055d5f..19017047b 100644 --- a/apps/opencs/model/world/collectionbase.hpp +++ b/apps/opencs/model/world/collectionbase.hpp @@ -44,6 +44,8 @@ namespace CSMWorld virtual QVariant getData (int index, int column) const = 0; + virtual QVariant getNestedData(int row, int column, int subRow, int subColumn) const = 0; + virtual void setData (int index, int column, const QVariant& data) = 0; // Not in use. Temporarily removed so that the implementation of RefIdCollection can continue without diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index fe310d0aa..c8670a03b 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -89,7 +89,9 @@ namespace CSMWorld Display_RefRecordType, Display_DialogueType, Display_QuestStatusType, - Display_Gender + Display_Gender, + + Display_Nested }; int mColumnId; @@ -125,6 +127,12 @@ namespace CSMWorld throw std::logic_error ("Column " + getTitle() + " is not editable"); } }; + + template + struct NestedColumn + { + virtual QVariant getNested(const Record& record, int subColumn, int subSow) const = 0; + }; } #endif diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 31797d081..04d1b333b 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -36,7 +36,13 @@ QVariant CSMWorld::IdTable::data (const QModelIndex & index, int role) const if (role==Qt::EditRole && !mIdCollection->getColumn (index.column()).isEditable()) return QVariant(); - return mIdCollection->getData (index.row(), index.column()); + if (index.internalId() != 0) + { + std::pair parentAdress(unfoldIndexAdress(index.internalId())); + return mIdCollection->getNestedData(index.row(), index.column(), parentAdress.first, parentAdress.second); + } else { + return mIdCollection->getData (index.row(), index.column()); + } } QVariant CSMWorld::IdTable::headerData (int section, Qt::Orientation orientation, int role) const @@ -97,8 +103,11 @@ bool CSMWorld::IdTable::removeRows (int row, int count, const QModelIndex& paren QModelIndex CSMWorld::IdTable::index (int row, int column, const QModelIndex& parent) const { + unsigned int encodedId = 0; if (parent.isValid()) - return QModelIndex(); + { + encodedId = this->foldIndexAdress(parent); + } if (row<0 || row>=mIdCollection->getSize()) return QModelIndex(); @@ -106,12 +115,24 @@ QModelIndex CSMWorld::IdTable::index (int row, int column, const QModelIndex& pa if (column<0 || column>=mIdCollection->getColumns()) return QModelIndex(); - return createIndex (row, column); + return createIndex(row, column, encodedId); } QModelIndex CSMWorld::IdTable::parent (const QModelIndex& index) const { - return QModelIndex(); + if (index.internalId() == 0) //0 is used for indexs with invalid parent (top level data) + { + return QModelIndex(); + } + + unsigned int id = index.internalId(); + const std::pair& adress(unfoldIndexAdress(id)); + + if (adress.first >= this->rowCount() || adress.second >= this->columnCount()) + { + throw "Parent index is not present in the model"; + } + return createIndex(adress.first, adress.second); } void CSMWorld::IdTable::addRecord (const std::string& id, UniversalId::Type type) @@ -136,10 +157,10 @@ void CSMWorld::IdTable::cloneRecord(const std::string& origin, endInsertRows(); } - +///This method can return only indexes to the top level table cells QModelIndex CSMWorld::IdTable::getModelIndex (const std::string& id, int column) const { - return index (mIdCollection->getIndex (id), column); + return index(mIdCollection->getIndex (id), column); } void CSMWorld::IdTable::setRecord (const std::string& id, const RecordBase& record) @@ -238,7 +259,28 @@ std::pair CSMWorld::IdTable::view (int row) return std::make_pair (UniversalId (UniversalId::Type_Scene, id), hint); } +///For top level data/columns int CSMWorld::IdTable::getColumnId(int column) const { return mIdCollection->getColumn(column).getId(); +} + +unsigned int CSMWorld::IdTable::foldIndexAdress (const QModelIndex& index) const +{ + unsigned int out = index.row() * this->columnCount(); + out += index.column(); + return ++out; +} + +std::pair< int, int > CSMWorld::IdTable::unfoldIndexAdress (unsigned int id) const +{ + if (id == 0) + { + throw "Attempt to unfold index id of the top level data cell"; + } + + --id; + int row = id / this->columnCount(); + int column = id - row * this->columnCount(); + return std::make_pair(row, column); } \ No newline at end of file diff --git a/apps/opencs/model/world/idtable.hpp b/apps/opencs/model/world/idtable.hpp index 8b5462825..deb07a1b2 100644 --- a/apps/opencs/model/world/idtable.hpp +++ b/apps/opencs/model/world/idtable.hpp @@ -8,6 +8,15 @@ #include "universalid.hpp" #include "columns.hpp" +/*! \brief + * Clas for holding the model. Uses typical qt table abstraction/interface for granting access to the individiual fields of the records, + * Some records are holding nested data (for instance inventory list of the npc). In casses like this, table model offers interface + * to access nested data in the qt way – that is specify parent. Since some of those nested data require multiple columns to + * represent informations, single int (default way to index model in the qmodelindex) is not sufficiant. Therefore tablemodelindex class + * can hold two ints for the sake of indexing two dimensions of the table. This model does not support multiple levels of the nested + * data. Vast majority of methods makes sense only for the top level data. + */ + namespace CSMWorld { class CollectionBase; @@ -44,6 +53,8 @@ namespace CSMWorld // not implemented IdTable (const IdTable&); IdTable& operator= (const IdTable&); + unsigned int foldIndexAdress(const QModelIndex& index) const; + std::pair unfoldIndexAdress(unsigned int id) const; public: diff --git a/apps/opencs/model/world/refidadapter.cpp b/apps/opencs/model/world/refidadapter.cpp index 283f062fe..2259a6e44 100644 --- a/apps/opencs/model/world/refidadapter.cpp +++ b/apps/opencs/model/world/refidadapter.cpp @@ -8,13 +8,13 @@ CSMWorld::RefIdAdapter::RefIdAdapter() {} CSMWorld::RefIdAdapter::~RefIdAdapter() {} -QVariant CSMWorld::RefIdAdapter::getData (const CSMWorld::RefIdColumn* column, const CSMWorld::RefIdData& data, int idnex, int subRowIndex, int subColIndex) const +QVariant CSMWorld::RefIdAdapter::getNestedData (const CSMWorld::RefIdColumn* column, const CSMWorld::RefIdData& data, int idnex, int subRowIndex, int subColIndex) const { assert(false); return QVariant(); } -void CSMWorld::RefIdAdapter::setData (const CSMWorld::RefIdColumn* column, CSMWorld::RefIdData& data, const QVariant& value, int index, int subRowIndex, int subColIndex) const +void CSMWorld::RefIdAdapter::setNestedData (const CSMWorld::RefIdColumn* column, CSMWorld::RefIdData& data, const QVariant& value, int index, int subRowIndex, int subColIndex) const { assert(false); } diff --git a/apps/opencs/model/world/refidadapter.hpp b/apps/opencs/model/world/refidadapter.hpp index 673b1f5a4..c9c778020 100644 --- a/apps/opencs/model/world/refidadapter.hpp +++ b/apps/opencs/model/world/refidadapter.hpp @@ -30,10 +30,10 @@ namespace CSMWorld const QVariant& value) const = 0; ///< If the data type does not match an exception is thrown. - virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, + virtual QVariant getNestedData (const RefIdColumn *column, const RefIdData& data, int idnex, int subRowIndex, int subColIndex) const; - virtual void setData (const RefIdColumn *column, RefIdData& data, + virtual void setNestedData (const RefIdColumn *column, RefIdData& data, const QVariant& value, int index, int subRowIndex, int subColIndex) const; diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index 8c98e1808..750e4af87 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -222,7 +222,7 @@ void CSMWorld::ContainerRefIdAdapter::setData (const RefIdColumn *column, RefIdD NameRefIdAdapter::setData (column, data, index, value); } -void CSMWorld::ContainerRefIdAdapter::setData(const RefIdColumn *column, RefIdData& data, +void CSMWorld::ContainerRefIdAdapter::setNestedData(const RefIdColumn *column, RefIdData& data, int index, const QVariant& value, int subRowIndex, @@ -242,6 +242,9 @@ void CSMWorld::ContainerRefIdAdapter::setData(const RefIdColumn *column, RefIdDa case 1: record.get().mInventory.mList.at(subRowIndex).mCount = value.toInt(); break; + + default: + throw "Trying to access non-existing column in the nested table!"; } } else { @@ -249,7 +252,7 @@ void CSMWorld::ContainerRefIdAdapter::setData(const RefIdColumn *column, RefIdDa } } -QVariant CSMWorld::ContainerRefIdAdapter::getData (const CSMWorld::RefIdColumn* column, +QVariant CSMWorld::ContainerRefIdAdapter::getNestedData (const CSMWorld::RefIdColumn* column, const CSMWorld::RefIdData& data, int index, int subRowIndex, diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index f29501698..eab0151b5 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -617,15 +617,13 @@ namespace CSMWorld ContainerRefIdAdapter (const NameColumns& columns, const RefIdColumn *weight, const RefIdColumn *organic, const RefIdColumn *respawn, const RefIdColumn *content); - using RefIdAdapter::getData; - virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index, + virtual QVariant getNestedData (const RefIdColumn *column, const RefIdData& data, int index, int subRowIndex, int subColIndex) const; virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index) const; - using RefIdAdapter::setData; - virtual void setData (const RefIdColumn *column, RefIdData& data, int index, + virtual void setNestedData (const RefIdColumn *column, RefIdData& data, int index, const QVariant& value, int subRowIndex, int subColIndex) const; virtual void setData (const RefIdColumn *column, RefIdData& data, int index, diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 1745ce957..74aa67e3b 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -165,7 +165,7 @@ CSMWorld::RefIdCollection::RefIdCollection() mColumns.push_back (RefIdColumn (Columns::ColumnId_Respawn, ColumnBase::Display_Boolean)); const RefIdColumn *respawn = &mColumns.back(); - mColumns.push_back(RefIdColumn (Columns::ColumnId_ContainerContent, ColumnBase::Display_None, ColumnBase::Flag_Dialogue, false, false)); + mColumns.push_back(RefIdColumn (Columns::ColumnId_ContainerContent, ColumnBase::Display_Nested, ColumnBase::Flag_Dialogue, false, false)); const RefIdColumn *content = &mColumns.back(); CreatureColumns creatureColumns (actorsColumns); @@ -419,6 +419,16 @@ QVariant CSMWorld::RefIdCollection::getData (int index, int column) const return adaptor.getData (&mColumns.at (column), mData, localIndex.first); } +QVariant CSMWorld::RefIdCollection::getNestedData (int row, int column, int subRow, int subColumn) const +{ + RefIdData::LocalIndex localIndex = mData.globalToLocalIndex(row); + + const RefIdAdapter& adaptor = findAdaptor (localIndex.second); + + //if this overloaded, base class method was not overriden, crash will happen (assert(false)) Don't try to use this method for non-nested columns! + return adaptor.getNestedData(&mColumns.at(column), mData, localIndex.first, subRow, subColumn); +} + void CSMWorld::RefIdCollection::setData (int index, int column, const QVariant& data) { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (index); diff --git a/apps/opencs/model/world/refidcollection.hpp b/apps/opencs/model/world/refidcollection.hpp index dd6213677..d03b45814 100644 --- a/apps/opencs/model/world/refidcollection.hpp +++ b/apps/opencs/model/world/refidcollection.hpp @@ -65,6 +65,8 @@ namespace CSMWorld virtual QVariant getData (int index, int column) const; + virtual QVariant getNestedData(int row, int column, int subRow, int subColumn) const; + virtual void setData (int index, int column, const QVariant& data); virtual void removeRows (int index, int count); diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index abdc33103..4ac8e8780 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -295,7 +295,7 @@ QWidget* CSVWorld::DialogueDelegateDispatcher::makeEditor(CSMWorld::ColumnBase:: { connect(editor, SIGNAL(editingFinished()), proxy, SLOT(editorDataCommited())); skip = true; - } + } //lisp cond pairs would be nice in the C++ connect(proxy, SIGNAL(editorDataCommited(QWidget*, const QModelIndex&, CSMWorld::ColumnBase::Display)), this, SLOT(editorDataCommited(QWidget*, const QModelIndex&, CSMWorld::ColumnBase::Display))); mProxys.push_back(proxy); //deleted in the destructor @@ -361,6 +361,7 @@ void CSVWorld::EditWidget::remake(int row) int unlocked = 0; int locked = 0; const int columns = mTable->columnCount(); + for (int i=0; iheaderData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Flags).toInt(); @@ -368,28 +369,35 @@ void CSVWorld::EditWidget::remake(int row) if (flags & CSMWorld::ColumnBase::Flag_Dialogue) { CSMWorld::ColumnBase::Display display = static_cast - (mTable->headerData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Display).toInt()); - - mDispatcher.makeDelegate(display); - QWidget *editor = mDispatcher.makeEditor(display, (mTable->index (row, i))); + (mTable->headerData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Display).toInt()); - if (editor) + if (display != CSMWorld::ColumnBase::Display_Nested) { - mWidgetMapper->addMapping (editor, i); - QLabel* label = new QLabel(mTable->headerData (i, Qt::Horizontal).toString(), mMainWidget); - label->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - editor->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); - if (! (mTable->flags (mTable->index (row, i)) & Qt::ItemIsEditable)) - { - lockedLayout->addWidget (label, locked, 0); - lockedLayout->addWidget (editor, locked, 1); - ++locked; - } else + mDispatcher.makeDelegate (display); + QWidget* editor = mDispatcher.makeEditor (display, (mTable->index (row, i))); + + if (editor) { - unlockedLayout->addWidget (label, unlocked, 0); - unlockedLayout->addWidget (editor, unlocked, 1); - ++unlocked; + mWidgetMapper->addMapping (editor, i); + QLabel* label = new QLabel (mTable->headerData (i, Qt::Horizontal).toString(), mMainWidget); + label->setSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed); + editor->setSizePolicy (QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); + + if (! (mTable->flags (mTable->index (row, i)) & Qt::ItemIsEditable)) + { + lockedLayout->addWidget (label, locked, 0); + lockedLayout->addWidget (editor, locked, 1); + ++locked; + } else + { + unlockedLayout->addWidget (label, unlocked, 0); + unlockedLayout->addWidget (editor, unlocked, 1); + ++unlocked; + } } + } else + { + //TODO } } } diff --git a/apps/opencs/view/world/util.cpp b/apps/opencs/view/world/util.cpp index b2a32b551..5fa93fe79 100644 --- a/apps/opencs/view/world/util.cpp +++ b/apps/opencs/view/world/util.cpp @@ -172,7 +172,8 @@ QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleO display == CSMWorld::ColumnBase::Display_Class || display == CSMWorld::ColumnBase::Display_Faction || display == CSMWorld::ColumnBase::Display_Miscellaneous || - display == CSMWorld::ColumnBase::Display_Sound) + display == CSMWorld::ColumnBase::Display_Sound || + display == CSMWorld::ColumnBase::Display_Region) { return new DropLineEdit(parent); } From 29231b8fc9a10fc3e4122bd70cfa88e571ad3ad2 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Mon, 9 Jun 2014 10:26:53 +0200 Subject: [PATCH 0005/3725] starting new branch --- apps/opencs/view/world/dialoguesubview.cpp | 39 +++++++++++++++------- apps/opencs/view/world/dialoguesubview.hpp | 4 +-- 2 files changed, 29 insertions(+), 14 deletions(-) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 4ac8e8780..d537ac4f1 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -19,6 +19,8 @@ #include #include #include +#include +#include #include "../../model/world/columnbase.hpp" #include "../../model/world/idtable.hpp" @@ -261,6 +263,7 @@ QWidget* CSVWorld::DialogueDelegateDispatcher::makeEditor(CSMWorld::ColumnBase:: } std::map::iterator delegateIt(mDelegates.find(display)); + if (delegateIt != mDelegates.end()) { editor = delegateIt->second->createEditor(qobject_cast(mParent), QStyleOptionViewItem(), index, display); @@ -371,7 +374,20 @@ void CSVWorld::EditWidget::remake(int row) CSMWorld::ColumnBase::Display display = static_cast (mTable->headerData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Display).toInt()); - if (display != CSMWorld::ColumnBase::Display_Nested) + if (display == CSMWorld::ColumnBase::Display_Nested) + { + const QModelIndex& parent = mTable->index(row, i); + if (parent.data().isValid() && mTable->hasChildren(parent)) + { + qDebug()<setModel(mTable); + table->setRootIndex(mTable->index(row, i)); + } + //TODO + } else { mDispatcher.makeDelegate (display); QWidget* editor = mDispatcher.makeEditor (display, (mTable->index (row, i))); @@ -394,10 +410,9 @@ void CSVWorld::EditWidget::remake(int row) unlockedLayout->addWidget (editor, unlocked, 1); ++unlocked; } - } - } else - { - //TODO + } else { + qDebug()<<"No edit widget"; + } } } } @@ -421,13 +436,12 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSM mMainLayout(NULL), mUndoStack(document.getUndoStack()), mTable(dynamic_cast(document.getData().getTableModel(id))), - mRow (-1), mLocked(false), mDocument(document) { connect(mTable, SIGNAL(dataChanged (const QModelIndex&, const QModelIndex&)), this, SLOT(dataChanged(const QModelIndex&))); - mRow = mTable->getModelIndex (id.getId(), 0).row(); + mCurrentId(id.getId()); QWidget *mainWidget = new QWidget(this); QHBoxLayout *buttonsLayout = new QHBoxLayout; @@ -477,7 +491,7 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSM mMainLayout = new QVBoxLayout(mainWidget); - mEditWidget = new EditWidget(mainWidget, mRow, mTable, mUndoStack, false); + mEditWidget = new EditWidget(mainWidget, mCurrentId, mTable, mUndoStack, false); connect(mEditWidget, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*)), this, SLOT(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*))); @@ -498,14 +512,15 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSM deleteButton->setDisabled(true); } - dataChanged(mTable->index(mRow, 0)); + dataChanged(getModelIndex(mCurrentId, 0)); mMainLayout->addLayout(buttonsLayout); setWidget(mainWidget); } void CSVWorld::DialogueSubView::prevId() { - int newRow = mRow - 1; + int new Row = getModelIndex(mCurrentId, 0).row() - 1; + if (newRow < 0) { return; @@ -552,12 +567,12 @@ void CSVWorld::DialogueSubView::nextId() } CSMWorld::RecordBase::State state = static_cast(mTable->data (mTable->index (newRow, 1)).toInt()); - if (!(state == CSMWorld::RecordBase::State_Deleted || state == CSMWorld::RecordBase::State_Erased)) + if (!(state == CSMWorld::RecordBase::State_Deleted)) { mEditWidget->remake(newRow); setUniversalId(CSMWorld::UniversalId (static_cast (mTable->data (mTable->index (newRow, 2)).toInt()), mTable->data (mTable->index (newRow, 0)).toString().toUtf8().constData())); - mRow = newRow; + mCurrentId = std::string(mTable->data (mTable->index (newRow, 0)).toString().toUtf8().constData()); mEditWidget->setDisabled(mLocked); return; } diff --git a/apps/opencs/view/world/dialoguesubview.hpp b/apps/opencs/view/world/dialoguesubview.hpp index 5642f46a0..dd14b3095 100644 --- a/apps/opencs/view/world/dialoguesubview.hpp +++ b/apps/opencs/view/world/dialoguesubview.hpp @@ -165,7 +165,7 @@ namespace CSVWorld QVBoxLayout* mMainLayout; CSMWorld::IdTable* mTable; QUndoStack& mUndoStack; - int mRow; + std::string mCurrentId; bool mLocked; const CSMDoc::Document& mDocument; TableBottomBox* mBottom; @@ -206,4 +206,4 @@ namespace CSVWorld }; } -#endif \ No newline at end of file +#endif From 21a1f6f4aef555775cdd66e4b4d7483d95f9b8cb Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Mon, 9 Jun 2014 10:35:39 +0200 Subject: [PATCH 0006/3725] working on the issue --- apps/opencs/model/world/collection.hpp | 20 ++++- apps/opencs/model/world/collectionbase.cpp | 19 +++- apps/opencs/model/world/collectionbase.hpp | 8 +- apps/opencs/model/world/idtable.cpp | 89 +++++++++++++++++-- apps/opencs/model/world/idtable.hpp | 22 +++++ apps/opencs/model/world/refidadapter.cpp | 10 ++- apps/opencs/model/world/refidadapter.hpp | 22 ++++- apps/opencs/model/world/refidadapterimp.cpp | 98 ++++++++++++++++++++- apps/opencs/model/world/refidadapterimp.hpp | 25 +++++- apps/opencs/model/world/refidcollection.cpp | 41 +++++++++ apps/opencs/model/world/refidcollection.hpp | 6 ++ 11 files changed, 342 insertions(+), 18 deletions(-) diff --git a/apps/opencs/model/world/collection.hpp b/apps/opencs/model/world/collection.hpp index 1fb3e1f1d..3f110b4dd 100644 --- a/apps/opencs/model/world/collection.hpp +++ b/apps/opencs/model/world/collection.hpp @@ -73,6 +73,10 @@ namespace CSMWorld ///< Add a new record (modified) virtual int getSize() const; + + virtual int getNestedColumnsCount(int column) const; + + virtual int getNestedRowsCount(int row, int column) const; virtual std::string getId (int index) const; @@ -92,7 +96,7 @@ namespace CSMWorld virtual void purge(); ///< Remove records that are flagged as erased. - virtual void removeRows (int index, int count) ; + virtual void removeRows (int index, int count); virtual void appendBlankRecord (const std::string& id, UniversalId::Type type = UniversalId::Type_None); @@ -247,6 +251,20 @@ namespace CSMWorld { return mRecords.size(); } + + template + int Collection::getNestedRowsCount(int row, int column) const + { + //TODO + return 0; + } + + template + int Collection::getNestedColumnsCount(int column) const + { + //TODO + return 0; + } template std::string Collection::getId (int index) const diff --git a/apps/opencs/model/world/collectionbase.cpp b/apps/opencs/model/world/collectionbase.cpp index 241f198cb..eed157a7b 100644 --- a/apps/opencs/model/world/collectionbase.cpp +++ b/apps/opencs/model/world/collectionbase.cpp @@ -28,4 +28,21 @@ int CSMWorld::CollectionBase::findColumnIndex (Columns::ColumnId id) const throw std::logic_error ("invalid column index"); return index; -} \ No newline at end of file +} + +void CSMWorld::CollectionBase::setNestedData(int row, int column, const QVariant& data, int subRow, int subColumn) +{ + assert(false); //TODO remove and make pure abstract +} + +int CSMWorld::CollectionBase::getNestedColumnsCount(int row, int column) const +{ + assert(false); //TODO remove and make pure abstract + return 0; +} + +int CSMWorld::CollectionBase::getNestedRowsCount(int row, int column) const +{ + assert(false); //TODO, make pure abstract + return 0; +} diff --git a/apps/opencs/model/world/collectionbase.hpp b/apps/opencs/model/world/collectionbase.hpp index 442055d5f..4c3afc092 100644 --- a/apps/opencs/model/world/collectionbase.hpp +++ b/apps/opencs/model/world/collectionbase.hpp @@ -33,6 +33,10 @@ namespace CSMWorld virtual ~CollectionBase(); virtual int getSize() const = 0; + + virtual int getNestedRowsCount(int row, int column) const; + + virtual int getNestedColumnsCount(int row, int column) const; virtual std::string getId (int index) const = 0; @@ -46,6 +50,8 @@ namespace CSMWorld virtual void setData (int index, int column, const QVariant& data) = 0; + virtual void setNestedData(int row, int column, const QVariant& data, int subRow, int subColumn); + // Not in use. Temporarily removed so that the implementation of RefIdCollection can continue without // these functions for now. // virtual void merge() = 0; @@ -106,4 +112,4 @@ namespace CSMWorld }; } -#endif \ No newline at end of file +#endif diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 50998c36f..59fc3a508 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -1,6 +1,8 @@ #include "idtable.hpp" +#include + #include "collectionbase.hpp" #include "columnbase.hpp" @@ -14,16 +16,21 @@ CSMWorld::IdTable::~IdTable() int CSMWorld::IdTable::rowCount (const QModelIndex & parent) const { - if (parent.isValid()) - return 0; - + if (hasChildren(parent)) + { + int nestedRows = mIdCollection->getNestedRowsCount(parent.row(), parent.column()); + return nestedRows; + } + return mIdCollection->getSize(); } int CSMWorld::IdTable::columnCount (const QModelIndex & parent) const { if (parent.isValid()) - return 0; + { + return mIdCollection->getNestedColumnsCount(parent.row(), parent.column()); + } return mIdCollection->getColumns(); } @@ -36,7 +43,17 @@ QVariant CSMWorld::IdTable::data (const QModelIndex & index, int role) const if (role==Qt::EditRole && !mIdCollection->getColumn (index.column()).isEditable()) return QVariant(); +<<<<<<< Updated upstream return mIdCollection->getData (index.row(), index.column()); +======= + if (index.internalId() != 0) + { + std::pair parentAdress(unfoldIndexAdress(index.internalId())); + return mIdCollection->getNestedData(parentAdress.first, parentAdress.second, index.row(), index.column()); + } else { + return mIdCollection->getData (index.row(), index.column()); + } +>>>>>>> Stashed changes } QVariant CSMWorld::IdTable::headerData (int section, Qt::Orientation orientation, int role) const @@ -60,11 +77,18 @@ bool CSMWorld::IdTable::setData ( const QModelIndex &index, const QVariant &valu { if (mIdCollection->getColumn (index.column()).isEditable() && role==Qt::EditRole) { - mIdCollection->setData (index.row(), index.column(), value); + if (index.internalId() == 0) + { + mIdCollection->setData (index.row(), index.column(), value); - emit dataChanged (CSMWorld::IdTable::index (index.row(), 0), - CSMWorld::IdTable::index (index.row(), mIdCollection->getColumns()-1)); + emit dataChanged (CSMWorld::IdTable::index (index.row(), 0), + CSMWorld::IdTable::index (index.row(), mIdCollection->getColumns()-1)); + } else + { + const std::pair& parentAdress(unfoldIndexAdress(index.internalId())); + mIdCollection->setNestedData(parentAdress.first, parentAdress.second, value, index.row(), index.column()); + } return true; } @@ -111,7 +135,23 @@ QModelIndex CSMWorld::IdTable::index (int row, int column, const QModelIndex& pa QModelIndex CSMWorld::IdTable::parent (const QModelIndex& index) const { +<<<<<<< Updated upstream return QModelIndex(); +======= + if (index.internalId() == 0) //0 is used for indexs with invalid parent (top level data) + { + return QModelIndex(); + } + + const std::pair& adress(unfoldIndexAdress(index.internalId())); + + if (adress.first >= this->rowCount() || adress.second >= this->columnCount()) + { + qDebug()<<"Parent index is not present in the model"; + throw "Parent index is not present in the model"; + } + return createIndex(adress.first, adress.second, 0); +>>>>>>> Stashed changes } void CSMWorld::IdTable::addRecord (const std::string& id, UniversalId::Type type) @@ -240,4 +280,37 @@ std::pair CSMWorld::IdTable::view (int row) int CSMWorld::IdTable::getColumnId(int column) const { return mIdCollection->getColumn(column).getId(); -} \ No newline at end of file +<<<<<<< Updated upstream +} +======= +} + +bool CSMWorld::IdTable::hasChildren(const QModelIndex& index) const +{ + return (index.isValid() && + mIdCollection->getColumn (index.column()).mDisplayType == ColumnBase::Display_Nested && + index.data().isValid()); +} + +unsigned int CSMWorld::IdTable::foldIndexAdress (const QModelIndex& index) const +{ + unsigned int out = index.row() * this->columnCount(); + out += index.column(); + ++out; + return out; +} + +std::pair< int, int > CSMWorld::IdTable::unfoldIndexAdress (unsigned int id) const +{ + if (id == 0) + { + qDebug()<<"Attempt to unfold index id of the top level data cell"; + throw "Attempt to unfold index id of the top level data cell"; + } + + --id; + int row = id / this->columnCount(); + int column = id - row * this->columnCount(); + return std::make_pair(row, column); +} +>>>>>>> Stashed changes diff --git a/apps/opencs/model/world/idtable.hpp b/apps/opencs/model/world/idtable.hpp index 8b5462825..bf9f4a555 100644 --- a/apps/opencs/model/world/idtable.hpp +++ b/apps/opencs/model/world/idtable.hpp @@ -8,6 +8,19 @@ #include "universalid.hpp" #include "columns.hpp" +<<<<<<< Updated upstream +======= +/*! \brief + * Clas for holding the model. Uses typical qt table abstraction/interface for granting access to the individiual fields of the records, + * Some records are holding nested data (for instance inventory list of the npc). In casses like this, table model offers interface + * to access nested data in the qt way – that is specify parent. The parent is encoded in the internalid of the index model + * See methods fold and unfold adress to see why. This approach has some serious limitations: it allows only + * a single level of the nesting. At the point of creating this code this seemed to be a good enough solution. + * If for some reason it turned out that in fact multiple levels of nesting are needed, change in the addressing of the + * index is most likely the very first to be considered. + */ + +>>>>>>> Stashed changes namespace CSMWorld { class CollectionBase; @@ -44,6 +57,13 @@ namespace CSMWorld // not implemented IdTable (const IdTable&); IdTable& operator= (const IdTable&); +<<<<<<< Updated upstream +======= + + unsigned int foldIndexAdress(const QModelIndex& index) const; + + std::pair unfoldIndexAdress(unsigned int id) const; +>>>>>>> Stashed changes public: @@ -71,6 +91,8 @@ namespace CSMWorld const; virtual QModelIndex parent (const QModelIndex& index) const; + + virtual bool hasChildren (const QModelIndex& index) const; void addRecord (const std::string& id, UniversalId::Type type = UniversalId::Type_None); ///< \param type Will be ignored, unless the collection supports multiple record types diff --git a/apps/opencs/model/world/refidadapter.cpp b/apps/opencs/model/world/refidadapter.cpp index 94ae38c3c..785e98d5e 100644 --- a/apps/opencs/model/world/refidadapter.cpp +++ b/apps/opencs/model/world/refidadapter.cpp @@ -3,4 +3,12 @@ CSMWorld::RefIdAdapter::RefIdAdapter() {} -CSMWorld::RefIdAdapter::~RefIdAdapter() {} \ No newline at end of file +<<<<<<< Updated upstream +CSMWorld::RefIdAdapter::~RefIdAdapter() {} +======= +CSMWorld::RefIdAdapter::~RefIdAdapter() {} + +CSMWorld::NestedRefIdAdapter::NestedRefIdAdapter() {} + +CSMWorld::NestedRefIdAdapter::~NestedRefIdAdapter() {} +>>>>>>> Stashed changes diff --git a/apps/opencs/model/world/refidadapter.hpp b/apps/opencs/model/world/refidadapter.hpp index 0870a2d3e..3a9d02dca 100644 --- a/apps/opencs/model/world/refidadapter.hpp +++ b/apps/opencs/model/world/refidadapter.hpp @@ -31,8 +31,28 @@ namespace CSMWorld ///< If the data type does not match an exception is thrown. virtual std::string getId (const RecordBase& record) const = 0; + virtual void setId(RecordBase& record, const std::string& id) = 0; }; + + class NestedRefIdAdapter + { + public: + NestedRefIdAdapter(); + + virtual ~NestedRefIdAdapter(); + + virtual void setNestedData (const RefIdColumn *column, RefIdData& data, int row, + const QVariant& value, int subRowIndex, int subColIndex) const = 0; + + virtual QVariant getNestedData (const RefIdColumn *column, const RefIdData& data, + int index, int subRowIndex, int subColIndex) const = 0; + + + virtual int getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const = 0; + + virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const = 0; + }; } -#endif \ No newline at end of file +#endif diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index f00e9fc77..b67b26cdb 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -1,6 +1,8 @@ #include "refidadapterimp.hpp" +#include + CSMWorld::PotionRefIdAdapter::PotionRefIdAdapter (const InventoryColumns& columns, const RefIdColumn *autoCalc) : InventoryRefIdAdapter (UniversalId::Type_Potion, columns), @@ -178,6 +180,32 @@ CSMWorld::ContainerRefIdAdapter::ContainerRefIdAdapter (const NameColumns& colum mOrganic (organic), mRespawn (respawn) {} +int CSMWorld::ContainerRefIdAdapter::getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const +{ + qDebug()<<"getting nested columns count"; + if (column==mContent) + { + return 2; + } else { + throw "Trying to obtain nested columns count, but column does not have nested columns!"; + } +} + +int CSMWorld::ContainerRefIdAdapter::getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const +{ + qDebug()<<"getting nested rows count"; + const Record& record = static_cast&> ( + data.getRecord(RefIdData::LocalIndex (index, UniversalId::Type_Container))); + + qDebug() << "exception above"; + if (column==mContent) + { + qDebug() << record.get().mInventory.mList.size(); + return record.get().mInventory.mList.size(); + } else { + throw "Trying to obtain nested rows count, but column does not have nested columns!"; + } +} QVariant CSMWorld::ContainerRefIdAdapter::getData (const RefIdColumn *column, const RefIdData& data, int index) const { @@ -192,6 +220,9 @@ QVariant CSMWorld::ContainerRefIdAdapter::getData (const RefIdColumn *column, co if (column==mRespawn) return (record.get().mFlags & ESM::Container::Respawn)!=0; + + if (column==mContent) + return true; return NameRefIdAdapter::getData (column, data, index); } @@ -222,6 +253,71 @@ void CSMWorld::ContainerRefIdAdapter::setData (const RefIdColumn *column, RefIdD NameRefIdAdapter::setData (column, data, index, value); } +<<<<<<< Updated upstream +======= +void CSMWorld::ContainerRefIdAdapter::setNestedData(const RefIdColumn *column, RefIdData& data, + int row, + const QVariant& value, + int subRowIndex, + int subColIndex) const +{ + Record& record = static_cast&> ( + data.getRecord (RefIdData::LocalIndex (row, UniversalId::Type_Container))); + + if (column==mContent) + { + switch (subColIndex) + { + case 0: + record.get().mInventory.mList.at(subRowIndex).mItem.assign(std::string(value.toString().toUtf8().constData())); + break; + + case 1: + record.get().mInventory.mList.at(subRowIndex).mCount = value.toInt(); + break; + + default: + throw "Trying to access non-existing column in the nested table!"; + } + } else + { + throw "This column does not hold multiple values."; + } +} + +QVariant CSMWorld::ContainerRefIdAdapter::getNestedData (const CSMWorld::RefIdColumn* column, + const CSMWorld::RefIdData& data, + int index, + int subRowIndex, + int subColIndex) const +{ + qDebug()<<"Accessing content column"; + const Record& record = static_cast&> ( + data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Container))); + + if (column==mContent) + { + const ESM::ContItem& content = record.get().mInventory.mList.at(subRowIndex); + + switch (subColIndex) + { + case 0: + return QString::fromUtf8(content.mItem.toString().c_str()); + + case 1: + return content.mCount; + + default: + throw "Trying to access non-existing column in the nested table!"; + } + } else + { + throw "This column does not hold multiple values."; + } +} + + +>>>>>>> Stashed changes CSMWorld::CreatureColumns::CreatureColumns (const ActorColumns& actorColumns) : ActorColumns (actorColumns) {} @@ -572,4 +668,4 @@ void CSMWorld::WeaponRefIdAdapter::setData (const RefIdColumn *column, RefIdData else EnchantableRefIdAdapter::setData (column, data, index, value); } -} \ No newline at end of file +} diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index bd509a86b..ed6c50fe3 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -23,6 +23,7 @@ namespace CSMWorld }; /// \brief Base adapter for all refereceable record types + /// Adapters that can handle nested tables, needs to return valid qvariant for parent columns template class BaseRefIdAdapter : public RefIdAdapter { @@ -605,7 +606,7 @@ namespace CSMWorld ///< If the data type does not match an exception is thrown. }; - class ContainerRefIdAdapter : public NameRefIdAdapter + class ContainerRefIdAdapter : public NameRefIdAdapter, public NestedRefIdAdapter { const RefIdColumn *mWeight; const RefIdColumn *mOrganic; @@ -614,14 +615,30 @@ namespace CSMWorld public: ContainerRefIdAdapter (const NameColumns& columns, const RefIdColumn *weight, +<<<<<<< Updated upstream const RefIdColumn *organic, const RefIdColumn *respawn); +======= + const RefIdColumn *organic, const RefIdColumn *respawn, const RefIdColumn *content); - virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index) - const; + virtual QVariant getNestedData (const RefIdColumn *column, const RefIdData& data, + int index, int subRowIndex, int subColIndex) const; +>>>>>>> Stashed changes + + virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index) const; +<<<<<<< Updated upstream +======= + virtual void setNestedData (const RefIdColumn *column, RefIdData& data, int index, + const QVariant& value, int subRowIndex, int subColIndex) const; + +>>>>>>> Stashed changes virtual void setData (const RefIdColumn *column, RefIdData& data, int index, - const QVariant& value) const; + const QVariant& value) const; ///< If the data type does not match an exception is thrown. + + virtual int getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const; + + virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const; }; struct CreatureColumns : public ActorColumns diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index f515e34d8..c9d6700b5 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -3,6 +3,7 @@ #include #include +#include #include @@ -416,6 +417,19 @@ QVariant CSMWorld::RefIdCollection::getData (int index, int column) const return adaptor.getData (&mColumns.at (column), mData, localIndex.first); } +<<<<<<< Updated upstream +======= +QVariant CSMWorld::RefIdCollection::getNestedData (int row, int column, int subRow, int subColumn) const +{ + RefIdData::LocalIndex localIndex = mData.globalToLocalIndex(row); + + const CSMWorld::NestedRefIdAdapter& adaptor = dynamic_cast(findAdaptor (localIndex.second)); + + //if this overloaded, base class method was not overriden, crash will happen (assert(false)) Don't try to use this method for non-nested columns! + return adaptor.getNestedData (&mColumns.at (column), mData, localIndex.first, subRow, subColumn); +} + +>>>>>>> Stashed changes void CSMWorld::RefIdCollection::setData (int index, int column, const QVariant& data) { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (index); @@ -425,6 +439,15 @@ void CSMWorld::RefIdCollection::setData (int index, int column, const QVariant& adaptor.setData (&mColumns.at (column), mData, localIndex.first, data); } +void CSMWorld::RefIdCollection::setNestedData(int row, int column, const QVariant& data, int subRow, int subColumn) +{ + RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); + + const RefIdAdapter& adaptor = findAdaptor (localIndex.second); + + dynamic_cast(adaptor).setNestedData (&mColumns.at (column), mData, localIndex.first, data, subRow, subColumn); +} + void CSMWorld::RefIdCollection::removeRows (int index, int count) { mData.erase (index, count); @@ -566,3 +589,21 @@ const CSMWorld::RefIdData& CSMWorld::RefIdCollection::getDataSet() const return mData; } +int CSMWorld::RefIdCollection::getNestedRowsCount(int row, int column) const +{ + RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); + + const CSMWorld::NestedRefIdAdapter& adaptor = dynamic_cast(findAdaptor (localIndex.second)); + + const int count = adaptor.getNestedRowsCount(&mColumns.at(column), mData, localIndex.first); + return count; +} + +int CSMWorld::RefIdCollection::getNestedColumnsCount(int row, int column) const +{ + RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); + + const CSMWorld::NestedRefIdAdapter& adaptor = dynamic_cast(findAdaptor (localIndex.second)); + + return adaptor.getNestedColumnsCount(&mColumns.at(column), mData); +} diff --git a/apps/opencs/model/world/refidcollection.hpp b/apps/opencs/model/world/refidcollection.hpp index dd6213677..f4ac556cf 100644 --- a/apps/opencs/model/world/refidcollection.hpp +++ b/apps/opencs/model/world/refidcollection.hpp @@ -55,6 +55,10 @@ namespace CSMWorld virtual int getSize() const; + virtual int getNestedRowsCount(int row, int column) const; + + virtual int getNestedColumnsCount(int row, int column) const; + virtual std::string getId (int index) const; virtual int getIndex (const std::string& id) const; @@ -67,6 +71,8 @@ namespace CSMWorld virtual void setData (int index, int column, const QVariant& data); + virtual void setNestedData(int row, int column, const QVariant& data, int subRow, int subColumn); + virtual void removeRows (int index, int count); virtual void cloneRecord(const std::string& origin, From 6f5935edb38dd30e00360053b9d1fd8b26b28b05 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Mon, 9 Jun 2014 11:37:48 +0200 Subject: [PATCH 0007/3725] subview does not store row number anymore --- apps/opencs/view/world/dialoguesubview.cpp | 93 +++++++++++++--------- 1 file changed, 56 insertions(+), 37 deletions(-) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index d537ac4f1..03321728b 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -379,14 +379,15 @@ void CSVWorld::EditWidget::remake(int row) const QModelIndex& parent = mTable->index(row, i); if (parent.data().isValid() && mTable->hasChildren(parent)) { + /* qDebug()<setModel(mTable); table->setRootIndex(mTable->index(row, i)); + */ } - //TODO } else { mDispatcher.makeDelegate (display); @@ -410,9 +411,7 @@ void CSVWorld::EditWidget::remake(int row) unlockedLayout->addWidget (editor, unlocked, 1); ++unlocked; } - } else { - qDebug()<<"No edit widget"; - } + } } } } @@ -441,7 +440,7 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSM { connect(mTable, SIGNAL(dataChanged (const QModelIndex&, const QModelIndex&)), this, SLOT(dataChanged(const QModelIndex&))); - mCurrentId(id.getId()); + mCurrentId = id.getId(); QWidget *mainWidget = new QWidget(this); QHBoxLayout *buttonsLayout = new QHBoxLayout; @@ -491,7 +490,7 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSM mMainLayout = new QVBoxLayout(mainWidget); - mEditWidget = new EditWidget(mainWidget, mCurrentId, mTable, mUndoStack, false); + mEditWidget = new EditWidget(mainWidget, mTable->getModelIndex(mCurrentId, 0).row(), mTable, mUndoStack, false); connect(mEditWidget, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*)), this, SLOT(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*))); @@ -512,14 +511,14 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSM deleteButton->setDisabled(true); } - dataChanged(getModelIndex(mCurrentId, 0)); + dataChanged(mTable->getModelIndex(mCurrentId, 0)); mMainLayout->addLayout(buttonsLayout); setWidget(mainWidget); } void CSVWorld::DialogueSubView::prevId() { - int new Row = getModelIndex(mCurrentId, 0).row() - 1; + int newRow = mTable->getModelIndex(mCurrentId, 0).row() - 1; if (newRow < 0) { @@ -540,7 +539,7 @@ void CSVWorld::DialogueSubView::prevId() mEditWidget->remake(newRow); setUniversalId(CSMWorld::UniversalId (static_cast (mTable->data (mTable->index (newRow, 2)).toInt()), mTable->data (mTable->index (newRow, 0)).toString().toUtf8().constData())); - mRow = newRow; + mCurrentId = std::string(mTable->data (mTable->index (newRow, 0)).toString().toUtf8().constData()); mEditWidget->setDisabled(mLocked); return; } @@ -550,7 +549,7 @@ void CSVWorld::DialogueSubView::prevId() void CSVWorld::DialogueSubView::nextId() { - int newRow = mRow + 1; + int newRow = mTable->getModelIndex(mCurrentId, 0).row() + 1; if (newRow >= mTable->rowCount()) { @@ -571,7 +570,7 @@ void CSVWorld::DialogueSubView::nextId() { mEditWidget->remake(newRow); setUniversalId(CSMWorld::UniversalId (static_cast (mTable->data (mTable->index (newRow, 2)).toInt()), - mTable->data (mTable->index (newRow, 0)).toString().toUtf8().constData())); + mTable->data (mTable->index (newRow, 0)).toString().toUtf8().constData())); mCurrentId = std::string(mTable->data (mTable->index (newRow, 0)).toString().toUtf8().constData()); mEditWidget->setDisabled(mLocked); return; @@ -583,8 +582,10 @@ void CSVWorld::DialogueSubView::nextId() void CSVWorld::DialogueSubView::setEditLock (bool locked) { mLocked = locked; - CSMWorld::RecordBase::State state = static_cast(mTable->data (mTable->index (mRow, 1)).toInt()); - if (state == CSMWorld::RecordBase::State_Deleted || state == CSMWorld::RecordBase::State_Erased) + QModelIndex index(mTable->getModelIndex(mCurrentId, 0)); + + CSMWorld::RecordBase::State state = static_cast(mTable->data (mTable->index (index.row(), 1)).toInt()); + if (state == CSMWorld::RecordBase::State_Deleted) { mEditWidget->setDisabled(true); } else @@ -595,10 +596,12 @@ void CSVWorld::DialogueSubView::setEditLock (bool locked) void CSVWorld::DialogueSubView::dataChanged(const QModelIndex & index) { - if (index.row() == mRow) + QModelIndex currentIndex(mTable->getModelIndex(mCurrentId, 0)); + + if (!currentIndex.isValid() && index.row() == currentIndex.row()) { - CSMWorld::RecordBase::State state = static_cast(mTable->data (mTable->index (mRow, 1)).toInt()); - if (state == CSMWorld::RecordBase::State_Deleted || state == CSMWorld::RecordBase::State_Erased) + CSMWorld::RecordBase::State state = static_cast(mTable->data (mTable->index (currentIndex.row(), 1)).toInt()); + if (state == CSMWorld::RecordBase::State_Deleted) { mEditWidget->setDisabled(true); } else @@ -621,15 +624,24 @@ void CSVWorld::DialogueSubView::tableMimeDataDropped(QWidget* editor, void CSVWorld::DialogueSubView::revertRecord() { - int rows = mTable->rowCount(); - if (!mLocked && mTable->columnCount() > 0 && mRow < mTable->rowCount() ) + const int rows = mTable->rowCount(); + QModelIndex currentIndex(mTable->getModelIndex(mCurrentId, 0)); + + if (!currentIndex.isValid()) + { + return; + } + + const int currentRow = currentIndex.row(); + + if (!mLocked && mTable->columnCount() > 0 && currentRow < mTable->rowCount() ) { CSMWorld::RecordBase::State state = - static_cast (mTable->data (mTable->index (mRow, 1)).toInt()); + static_cast (mTable->data (mTable->index (currentRow, 1)).toInt()); if (state!=CSMWorld::RecordBase::State_BaseOnly) { - mUndoStack.push(new CSMWorld::RevertCommand(*mTable, mTable->data(mTable->index (mRow, 0)).toString().toUtf8().constData())); + mUndoStack.push(new CSMWorld::RevertCommand(*mTable, mCurrentId)); } if (rows != mTable->rowCount()) { @@ -638,11 +650,11 @@ void CSVWorld::DialogueSubView::revertRecord() mEditWidget->setDisabled(true); //closing the editor is other option return; } - if (mRow >= mTable->rowCount()) + if (currentIndex.row() >= mTable->rowCount()) { prevId(); } else { - dataChanged(mTable->index(mRow, 0)); + dataChanged(currentIndex); } } } @@ -650,19 +662,20 @@ void CSVWorld::DialogueSubView::revertRecord() void CSVWorld::DialogueSubView::deleteRecord() { - int rows = mTable->rowCount(); + const int rows = mTable->rowCount(); + QModelIndex currentIndex(mTable->getModelIndex(mCurrentId, 0)); //easier than disabling the button - CSMWorld::RecordBase::State state = static_cast(mTable->data (mTable->index (mRow, 1)).toInt()); - bool deledetedOrErased = (state == CSMWorld::RecordBase::State_Deleted || state == CSMWorld::RecordBase::State_Erased); + CSMWorld::RecordBase::State state = static_cast(mTable->data (mTable->index (currentIndex.row(), 1)).toInt()); + bool deledetedOrErased = (state == CSMWorld::RecordBase::State_Deleted); if (!mLocked && mTable->columnCount() > 0 && !deledetedOrErased && - mRow < rows && + currentIndex.row() < rows && mBottom->canCreateAndDelete()) { - mUndoStack.push(new CSMWorld::DeleteCommand(*mTable, mTable->data(mTable->index (mRow, 0)).toString().toUtf8().constData())); + mUndoStack.push(new CSMWorld::DeleteCommand(*mTable, mCurrentId)); if (rows != mTable->rowCount()) { if (mTable->rowCount() == 0) @@ -670,11 +683,11 @@ void CSVWorld::DialogueSubView::deleteRecord() mEditWidget->setDisabled(true); //closing the editor is other option return; } - if (mRow >= mTable->rowCount()) + if (currentIndex.row() >= mTable->rowCount()) { prevId(); } else { - dataChanged(mTable->index(mRow, 0)); + dataChanged(currentIndex); } } } @@ -682,29 +695,35 @@ void CSVWorld::DialogueSubView::deleteRecord() void CSVWorld::DialogueSubView::requestFocus (const std::string& id) { - mRow = mTable->getModelIndex (id, 0).row(); - mEditWidget->remake(mRow); + mCurrentId = std::string(id); + mEditWidget->remake(mTable->getModelIndex (id, 0).row()); } void CSVWorld::DialogueSubView::cloneRequest () { - mBottom->cloneRequest(mTable->data(mTable->index (mRow, 0)).toString().toUtf8().constData(), - static_cast(mTable->data(mTable->index(mRow, 2)).toInt())); + mBottom->cloneRequest(mCurrentId, static_cast(mTable->data(mTable->getModelIndex(mCurrentId, 2)).toInt())); } void CSVWorld::DialogueSubView::showPreview () { - if (mTable->hasPreview() && mRow < mTable->rowCount()) + QModelIndex currentIndex(mTable->getModelIndex(mCurrentId, 0)); + + if (currentIndex.isValid() && + mTable->hasPreview() && + currentIndex.row() < mTable->rowCount()) { - emit focusId(CSMWorld::UniversalId(CSMWorld::UniversalId::Type_Preview, mTable->data(mTable->index (mRow, 0)).toString().toUtf8().constData()), ""); + emit focusId(CSMWorld::UniversalId(CSMWorld::UniversalId::Type_Preview, mCurrentId), ""); } } void CSVWorld::DialogueSubView::viewRecord() { - if (mRow < mTable->rowCount()) + QModelIndex currentIndex(mTable->getModelIndex(mCurrentId, 0)); + + if (currentIndex.isValid() && + currentIndex.row() < mTable->rowCount()) { - std::pair params = mTable->view (mRow); + std::pair params = mTable->view (currentIndex.row()); if (params.first.getType()!=CSMWorld::UniversalId::Type_None) emit focusId (params.first, params.second); From 649ce543698db2f87460f9b26c0d84c9b48606a2 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Mon, 9 Jun 2014 11:53:06 +0200 Subject: [PATCH 0008/3725] merging --- CMakeLists.txt | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 874d65af3..3632f1e08 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,19 +36,8 @@ if(EXISTS ${PROJECT_SOURCE_DIR}/.git) string(REGEX REPLACE "^openmw-[0-9]+\\.([0-9]+).*" "\\1" GIT_VERSION_MINOR "${VERSION}") string(REGEX REPLACE "^openmw-[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" GIT_VERSION_RELEASE "${VERSION}") -<<<<<<< HEAD - set(GIT_VERSION "${GIT_VERSION_MAJOR}.${GIT_VERSION_MINOR}.${GIT_VERSION_RELEASE}") - - set(OPENMW_VERSION_MAJOR ${GIT_VERSION_MAJOR}) - set(OPENMW_VERSION_MINOR ${GIT_VERSION_MINOR}) - set(OPENMW_VERSION_RELEASE ${GIT_VERSION_RELEASE}) - - set(OPENMW_VERSION_COMMITHASH "${COMMITHASH}") - set(OPENMW_VERSION_TAGHASH "${TAGHASH}") -======= set(OPENMW_VERSION_COMMITHASH "${COMMITHASH}") set(OPENMW_VERSION_TAGHASH "${TAGHASH}") ->>>>>>> master/refs message(STATUS "OpenMW version ${OPENMW_VERSION}") else(MATCH) From c8458654ac19121fdf2851658a3737121829bf94 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Mon, 9 Jun 2014 13:16:10 +0200 Subject: [PATCH 0009/3725] correcting problems --- apps/opencs/view/world/dialoguesubview.cpp | 41 +++++++--------------- 1 file changed, 13 insertions(+), 28 deletions(-) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 523b358ae..db80af025 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -20,7 +20,6 @@ #include #include #include -#include #include "../../model/world/columnbase.hpp" #include "../../model/world/idtable.hpp" @@ -375,22 +374,21 @@ void CSVWorld::EditWidget::remake(int row) { CSMWorld::ColumnBase::Display display = static_cast (mTable->headerData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Display).toInt()); - +/* commented out for now TODO if (display == CSMWorld::ColumnBase::Display_Nested) { const QModelIndex& parent = mTable->index(row, i); if (parent.data().isValid() && mTable->hasChildren(parent)) { - /* qDebug()<setModel(mTable); table->setRootIndex(mTable->index(row, i)); - */ + } - } else + } else */ { mDispatcher.makeDelegate (display); QWidget* editor = mDispatcher.makeEditor (display, (mTable->index (row, i))); @@ -583,40 +581,28 @@ void CSVWorld::DialogueSubView::nextId() void CSVWorld::DialogueSubView::setEditLock (bool locked) { mLocked = locked; - QModelIndex index(mTable->getModelIndex(mCurrentId, 0)); + QModelIndex currentIndex(mTable->getModelIndex(mCurrentId, 0)); - CSMWorld::RecordBase::State state = static_cast(mTable->data (mTable->index (index.row(), 1)).toInt()); - if (state == CSMWorld::RecordBase::State_Deleted) - { - mEditWidget->setDisabled(true); - } else + mEditWidget->setDisabled (state==CSMWorld::RecordBase::State_Deleted || locked); + + if (currentIndex.isValid()) { - mEditWidget->setDisabled(mLocked); - } - - CSMWorld::RecordBase::State state = static_cast(mTable->data (mTable->index (mRow, 1)).toInt()); + CSMWorld::RecordBase::State state = static_cast(mTable->data (mTable->index (currentIndex.row(), 1)).toInt()); - mEditWidget->setDisabled (state==CSMWorld::RecordBase::State_Deleted || locked); + mCommandDispatcher.setEditLock (locked); + } - mCommandDispatcher.setEditLock (locked); } void CSVWorld::DialogueSubView::dataChanged(const QModelIndex & index) { QModelIndex currentIndex(mTable->getModelIndex(mCurrentId, 0)); - if (!currentIndex.isValid() && index.row() == currentIndex.row()) + mEditWidget->setDisabled (state==CSMWorld::RecordBase::State_Deleted || mLocked); + + if (currentIndex.isValid() && index.row() == currentIndex.row()) { CSMWorld::RecordBase::State state = static_cast(mTable->data (mTable->index (currentIndex.row(), 1)).toInt()); - if (state == CSMWorld::RecordBase::State_Deleted) - { - mEditWidget->setDisabled(true); - } else - { - mEditWidget->setDisabled(mLocked); - } - - mEditWidget->setDisabled (state==CSMWorld::RecordBase::State_Deleted || mLocked); } } @@ -719,7 +705,6 @@ void CSVWorld::DialogueSubView::showPreview () if (currentIndex.isValid() && mTable->getFeatures() & CSMWorld::IdTable::Feature_Preview && - mTable->hasPreview() && currentIndex.row() < mTable->rowCount()) { emit focusId(CSMWorld::UniversalId(CSMWorld::UniversalId::Type_Preview, mCurrentId), ""); From 9ee00534b9818226232bc7b7aaf832b37cbcd4b0 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Mon, 9 Jun 2014 13:18:17 +0200 Subject: [PATCH 0010/3725] check if index is valid before attempting to use it --- apps/opencs/view/world/dialoguesubview.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index db80af025..8ffc0da56 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -660,11 +660,11 @@ void CSVWorld::DialogueSubView::deleteRecord() const int rows = mTable->rowCount(); QModelIndex currentIndex(mTable->getModelIndex(mCurrentId, 0)); - //easier than disabling the button CSMWorld::RecordBase::State state = static_cast(mTable->data (mTable->index (currentIndex.row(), 1)).toInt()); bool deledetedOrErased = (state == CSMWorld::RecordBase::State_Deleted); if (!mLocked && + currentIndex.isValid() && mTable->columnCount() > 0 && !deledetedOrErased && currentIndex.row() < rows && From 8763309a1bdc0e15839cdfd3509ed68e28fc0917 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Mon, 9 Jun 2014 13:31:15 +0200 Subject: [PATCH 0011/3725] reformatting to make code easier to read --- apps/opencs/view/world/dialoguesubview.cpp | 63 ++++++++++++++-------- 1 file changed, 42 insertions(+), 21 deletions(-) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 8ffc0da56..9d6538c1c 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -133,25 +133,25 @@ void CSVWorld::DialogueDelegateDispatcherProxy::tableMimeDataDropped(const std:: if (mDisplay == CSMWorld::ColumnBase::Display_Referenceable) { if ( type == CSMWorld::UniversalId::Type_Activator - || type == CSMWorld::UniversalId::Type_Potion - || type == CSMWorld::UniversalId::Type_Apparatus - || type == CSMWorld::UniversalId::Type_Armor - || type == CSMWorld::UniversalId::Type_Book - || type == CSMWorld::UniversalId::Type_Clothing - || type == CSMWorld::UniversalId::Type_Container - || type == CSMWorld::UniversalId::Type_Creature - || type == CSMWorld::UniversalId::Type_Door - || type == CSMWorld::UniversalId::Type_Ingredient - || type == CSMWorld::UniversalId::Type_CreatureLevelledList - || type == CSMWorld::UniversalId::Type_ItemLevelledList - || type == CSMWorld::UniversalId::Type_Light - || type == CSMWorld::UniversalId::Type_Lockpick - || type == CSMWorld::UniversalId::Type_Miscellaneous - || type == CSMWorld::UniversalId::Type_Npc - || type == CSMWorld::UniversalId::Type_Probe - || type == CSMWorld::UniversalId::Type_Repair - || type == CSMWorld::UniversalId::Type_Static - || type == CSMWorld::UniversalId::Type_Weapon) + || type == CSMWorld::UniversalId::Type_Potion + || type == CSMWorld::UniversalId::Type_Apparatus + || type == CSMWorld::UniversalId::Type_Armor + || type == CSMWorld::UniversalId::Type_Book + || type == CSMWorld::UniversalId::Type_Clothing + || type == CSMWorld::UniversalId::Type_Container + || type == CSMWorld::UniversalId::Type_Creature + || type == CSMWorld::UniversalId::Type_Door + || type == CSMWorld::UniversalId::Type_Ingredient + || type == CSMWorld::UniversalId::Type_CreatureLevelledList + || type == CSMWorld::UniversalId::Type_ItemLevelledList + || type == CSMWorld::UniversalId::Type_Light + || type == CSMWorld::UniversalId::Type_Lockpick + || type == CSMWorld::UniversalId::Type_Miscellaneous + || type == CSMWorld::UniversalId::Type_Npc + || type == CSMWorld::UniversalId::Type_Probe + || type == CSMWorld::UniversalId::Type_Repair + || type == CSMWorld::UniversalId::Type_Static + || type == CSMWorld::UniversalId::Type_Weapon) { type = CSMWorld::UniversalId::Type_Referenceable; } @@ -266,16 +266,20 @@ QWidget* CSVWorld::DialogueDelegateDispatcher::makeEditor(CSMWorld::ColumnBase:: if (delegateIt != mDelegates.end()) { editor = delegateIt->second->createEditor(qobject_cast(mParent), QStyleOptionViewItem(), index, display); + DialogueDelegateDispatcherProxy* proxy = new DialogueDelegateDispatcherProxy(editor, display); bool skip = false; if (qobject_cast(editor)) { connect(editor, SIGNAL(editingFinished()), proxy, SLOT(editorDataCommited())); + connect(editor, SIGNAL(tableMimeDataDropped(const std::vector&, const CSMDoc::Document*)), proxy, SLOT(tableMimeDataDropped(const std::vector&, const CSMDoc::Document*))); + connect(proxy, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*)), this, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*))); + skip = true; } if(!skip && qobject_cast(editor)) @@ -299,7 +303,9 @@ QWidget* CSVWorld::DialogueDelegateDispatcher::makeEditor(CSMWorld::ColumnBase:: skip = true; } //lisp cond pairs would be nice in the C++ - connect(proxy, SIGNAL(editorDataCommited(QWidget*, const QModelIndex&, CSMWorld::ColumnBase::Display)), this, SLOT(editorDataCommited(QWidget*, const QModelIndex&, CSMWorld::ColumnBase::Display))); + connect(proxy, SIGNAL(editorDataCommited(QWidget*, const QModelIndex&, CSMWorld::ColumnBase::Display)), + this, SLOT(editorDataCommited(QWidget*, const QModelIndex&, CSMWorld::ColumnBase::Display))); + mProxys.push_back(proxy); //deleted in the destructor } return editor; @@ -326,7 +332,9 @@ mUndoStack(undoStack), mTable(table) { remake (row); - connect(&mDispatcher, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*)), this, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*))); + + connect(&mDispatcher, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*)), + this, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*))); } void CSVWorld::EditWidget::remake(int row) @@ -345,6 +353,7 @@ void CSVWorld::EditWidget::remake(int row) mWidgetMapper = 0; } mWidgetMapper = new QDataWidgetMapper (this); + mWidgetMapper->setModel(mTable); mWidgetMapper->setItemDelegate(&mDispatcher); @@ -536,10 +545,14 @@ void CSVWorld::DialogueSubView::prevId() if (!(state == CSMWorld::RecordBase::State_Deleted || state == CSMWorld::RecordBase::State_Erased)) { mEditWidget->remake(newRow); + setUniversalId(CSMWorld::UniversalId (static_cast (mTable->data (mTable->index (newRow, 2)).toInt()), mTable->data (mTable->index (newRow, 0)).toString().toUtf8().constData())); + mCurrentId = std::string(mTable->data (mTable->index (newRow, 0)).toString().toUtf8().constData()); + mEditWidget->setDisabled(mLocked); + return; } --newRow; @@ -568,10 +581,14 @@ void CSVWorld::DialogueSubView::nextId() if (!(state == CSMWorld::RecordBase::State_Deleted)) { mEditWidget->remake(newRow); + setUniversalId(CSMWorld::UniversalId (static_cast (mTable->data (mTable->index (newRow, 2)).toInt()), mTable->data (mTable->index (newRow, 0)).toString().toUtf8().constData())); + mCurrentId = std::string(mTable->data (mTable->index (newRow, 0)).toString().toUtf8().constData()); + mEditWidget->setDisabled(mLocked); + return; } ++newRow; @@ -620,6 +637,7 @@ void CSVWorld::DialogueSubView::tableMimeDataDropped(QWidget* editor, void CSVWorld::DialogueSubView::revertRecord() { const int rows = mTable->rowCount(); + QModelIndex currentIndex(mTable->getModelIndex(mCurrentId, 0)); if (!currentIndex.isValid()) @@ -643,6 +661,7 @@ void CSVWorld::DialogueSubView::revertRecord() if (mTable->rowCount() == 0) { mEditWidget->setDisabled(true); //closing the editor is other option + return; } if (currentIndex.row() >= mTable->rowCount()) @@ -676,6 +695,7 @@ void CSVWorld::DialogueSubView::deleteRecord() if (mTable->rowCount() == 0) { mEditWidget->setDisabled(true); //closing the editor is other option + return; } if (currentIndex.row() >= mTable->rowCount()) @@ -691,6 +711,7 @@ void CSVWorld::DialogueSubView::deleteRecord() void CSVWorld::DialogueSubView::requestFocus (const std::string& id) { mCurrentId = std::string(id); + mEditWidget->remake(mTable->getModelIndex (id, 0).row()); } From 7eb82f74aecfc97cadc014c8f13bfaaf50661016 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Mon, 16 Jun 2014 10:22:14 +0200 Subject: [PATCH 0012/3725] Fixed complitaion. --- apps/opencs/view/world/dialoguesubview.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 9d6538c1c..e9910f42b 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -600,12 +600,12 @@ void CSVWorld::DialogueSubView::setEditLock (bool locked) mLocked = locked; QModelIndex currentIndex(mTable->getModelIndex(mCurrentId, 0)); - mEditWidget->setDisabled (state==CSMWorld::RecordBase::State_Deleted || locked); - if (currentIndex.isValid()) { CSMWorld::RecordBase::State state = static_cast(mTable->data (mTable->index (currentIndex.row(), 1)).toInt()); + mEditWidget->setDisabled (state==CSMWorld::RecordBase::State_Deleted || locked); + mCommandDispatcher.setEditLock (locked); } @@ -615,11 +615,12 @@ void CSVWorld::DialogueSubView::dataChanged(const QModelIndex & index) { QModelIndex currentIndex(mTable->getModelIndex(mCurrentId, 0)); - mEditWidget->setDisabled (state==CSMWorld::RecordBase::State_Deleted || mLocked); if (currentIndex.isValid() && index.row() == currentIndex.row()) { CSMWorld::RecordBase::State state = static_cast(mTable->data (mTable->index (currentIndex.row(), 1)).toInt()); + + mEditWidget->setDisabled (state==CSMWorld::RecordBase::State_Deleted || mLocked); } } From 786c68f09a2f31c699c7753faa785d117f18b0e5 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Mon, 16 Jun 2014 11:31:57 +0200 Subject: [PATCH 0013/3725] refactoring dialogue subview --- apps/opencs/view/world/dialoguesubview.cpp | 20 ++++++++++++++++---- apps/opencs/view/world/dialoguesubview.hpp | 3 +++ 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index e9910f42b..0f2ae73dd 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -448,7 +448,9 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSM mCommandDispatcher (document, CSMWorld::UniversalId::getParentType (id.getType())) { connect(mTable, SIGNAL(dataChanged (const QModelIndex&, const QModelIndex&)), this, SLOT(dataChanged(const QModelIndex&))); - mCurrentId = id.getId(); + + changeCurrentId(id.getId()); + QWidget *mainWidget = new QWidget(this); QHBoxLayout *buttonsLayout = new QHBoxLayout; @@ -509,7 +511,9 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSM new TableBottomBox (creatorFactory, document.getData(), document.getUndoStack(), id, this)); mBottom->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed); + connect(mBottom, SIGNAL(requestFocus(const std::string&)), this, SLOT(requestFocus(const std::string&))); + connect(addButton, SIGNAL(clicked()), mBottom, SLOT(createRequest())); if(!mBottom->canCreateAndDelete()) @@ -549,7 +553,7 @@ void CSVWorld::DialogueSubView::prevId() setUniversalId(CSMWorld::UniversalId (static_cast (mTable->data (mTable->index (newRow, 2)).toInt()), mTable->data (mTable->index (newRow, 0)).toString().toUtf8().constData())); - mCurrentId = std::string(mTable->data (mTable->index (newRow, 0)).toString().toUtf8().constData()); + changeCurrentId(std::string(mTable->data (mTable->index (newRow, 0)).toString().toUtf8().constData())); mEditWidget->setDisabled(mLocked); @@ -585,7 +589,7 @@ void CSVWorld::DialogueSubView::nextId() setUniversalId(CSMWorld::UniversalId (static_cast (mTable->data (mTable->index (newRow, 2)).toInt()), mTable->data (mTable->index (newRow, 0)).toString().toUtf8().constData())); - mCurrentId = std::string(mTable->data (mTable->index (newRow, 0)).toString().toUtf8().constData()); + changeCurrentId(std::string(mTable->data (mTable->index (newRow, 0)).toString().toUtf8().constData())); mEditWidget->setDisabled(mLocked); @@ -615,7 +619,6 @@ void CSVWorld::DialogueSubView::dataChanged(const QModelIndex & index) { QModelIndex currentIndex(mTable->getModelIndex(mCurrentId, 0)); - if (currentIndex.isValid() && index.row() == currentIndex.row()) { CSMWorld::RecordBase::State state = static_cast(mTable->data (mTable->index (currentIndex.row(), 1)).toInt()); @@ -746,3 +749,12 @@ void CSVWorld::DialogueSubView::viewRecord() emit focusId (params.first, params.second); } } + +void CSVWorld::DialogueSubView::changeCurrentId(const std::string& newId) +{ + std::vector selection; + mCurrentId = std::string(newId); + + selection.push_back(mCurrentId); + mCommandDispatcher.setSelection(selection); +} diff --git a/apps/opencs/view/world/dialoguesubview.hpp b/apps/opencs/view/world/dialoguesubview.hpp index 2a9dd2e4f..2fdceacb1 100644 --- a/apps/opencs/view/world/dialoguesubview.hpp +++ b/apps/opencs/view/world/dialoguesubview.hpp @@ -181,6 +181,9 @@ namespace CSVWorld bool sorting = false); virtual void setEditLock (bool locked); + + private: + void changeCurrentId(const std::string& newCurrent); private slots: From d6288a805512b1113896c8f2d09b052045af7369 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Mon, 16 Jun 2014 11:58:55 +0200 Subject: [PATCH 0014/3725] Remove unneded revert and delete slots --- apps/opencs/view/world/dialoguesubview.cpp | 80 +--------------------- apps/opencs/view/world/dialoguesubview.hpp | 4 -- 2 files changed, 3 insertions(+), 81 deletions(-) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 0f2ae73dd..e798c8320 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -495,8 +495,8 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSM connect(nextButton, SIGNAL(clicked()), this, SLOT(nextId())); connect(prevButton, SIGNAL(clicked()), this, SLOT(prevId())); connect(cloneButton, SIGNAL(clicked()), this, SLOT(cloneRequest())); - connect(revertButton, SIGNAL(clicked()), this, SLOT(revertRecord())); - connect(deleteButton, SIGNAL(clicked()), this, SLOT(deleteRecord())); + connect(revertButton, SIGNAL(clicked()), &mCommandDispatcher, SLOT(executeRevert())); + connect(deleteButton, SIGNAL(clicked()), &mCommandDispatcher, SLOT(executeDelete())); mMainLayout = new QVBoxLayout(mainWidget); @@ -638,83 +638,9 @@ void CSVWorld::DialogueSubView::tableMimeDataDropped(QWidget* editor, } } -void CSVWorld::DialogueSubView::revertRecord() -{ - const int rows = mTable->rowCount(); - - QModelIndex currentIndex(mTable->getModelIndex(mCurrentId, 0)); - - if (!currentIndex.isValid()) - { - return; - } - - const int currentRow = currentIndex.row(); - - if (!mLocked && mTable->columnCount() > 0 && currentRow < mTable->rowCount() ) - { - CSMWorld::RecordBase::State state = - static_cast (mTable->data (mTable->index (currentRow, 1)).toInt()); - - if (state!=CSMWorld::RecordBase::State_BaseOnly) - { - mUndoStack.push(new CSMWorld::RevertCommand(*mTable, mCurrentId)); - } - if (rows != mTable->rowCount()) - { - if (mTable->rowCount() == 0) - { - mEditWidget->setDisabled(true); //closing the editor is other option - - return; - } - if (currentIndex.row() >= mTable->rowCount()) - { - prevId(); - } else { - dataChanged(currentIndex); - } - } - } -} - -void CSVWorld::DialogueSubView::deleteRecord() -{ - const int rows = mTable->rowCount(); - QModelIndex currentIndex(mTable->getModelIndex(mCurrentId, 0)); - - CSMWorld::RecordBase::State state = static_cast(mTable->data (mTable->index (currentIndex.row(), 1)).toInt()); - bool deledetedOrErased = (state == CSMWorld::RecordBase::State_Deleted); - - if (!mLocked && - currentIndex.isValid() && - mTable->columnCount() > 0 && - !deledetedOrErased && - currentIndex.row() < rows && - mBottom->canCreateAndDelete()) - { - mUndoStack.push(new CSMWorld::DeleteCommand(*mTable, mCurrentId)); - if (rows != mTable->rowCount()) - { - if (mTable->rowCount() == 0) - { - mEditWidget->setDisabled(true); //closing the editor is other option - - return; - } - if (currentIndex.row() >= mTable->rowCount()) - { - prevId(); - } else { - dataChanged(currentIndex); - } - } - } -} - void CSVWorld::DialogueSubView::requestFocus (const std::string& id) { - mCurrentId = std::string(id); + changeCurrentId(id); mEditWidget->remake(mTable->getModelIndex (id, 0).row()); } diff --git a/apps/opencs/view/world/dialoguesubview.hpp b/apps/opencs/view/world/dialoguesubview.hpp index 2fdceacb1..050aad947 100644 --- a/apps/opencs/view/world/dialoguesubview.hpp +++ b/apps/opencs/view/world/dialoguesubview.hpp @@ -195,10 +195,6 @@ namespace CSVWorld void viewRecord(); - void revertRecord(); - - void deleteRecord(); - void cloneRequest(); void dataChanged(const QModelIndex & index); From bbe7854968d5ecb44b767bc1b64963fd8bceddcc Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Tue, 17 Jun 2014 10:46:54 +0200 Subject: [PATCH 0015/3725] Corrected formatting to follow our standard better. --- apps/opencs/view/world/dialoguesubview.cpp | 32 +++++++++++----------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index e798c8320..bc2a6048a 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -518,17 +518,17 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSM if(!mBottom->canCreateAndDelete()) { - cloneButton->setDisabled(true); - addButton->setDisabled(true); - deleteButton->setDisabled(true); + cloneButton->setDisabled (true); + addButton->setDisabled (true); + deleteButton->setDisabled (true); } - dataChanged(mTable->getModelIndex(mCurrentId, 0)); - mMainLayout->addLayout(buttonsLayout); - setWidget(mainWidget); + dataChanged(mTable->getModelIndex (mCurrentId, 0)); + mMainLayout->addLayout (buttonsLayout); + setWidget (mainWidget); } -void CSVWorld::DialogueSubView::prevId() +void CSVWorld::DialogueSubView::prevId () { int newRow = mTable->getModelIndex(mCurrentId, 0).row() - 1; @@ -563,7 +563,7 @@ void CSVWorld::DialogueSubView::prevId() } } -void CSVWorld::DialogueSubView::nextId() +void CSVWorld::DialogueSubView::nextId () { int newRow = mTable->getModelIndex(mCurrentId, 0).row() + 1; @@ -615,7 +615,7 @@ void CSVWorld::DialogueSubView::setEditLock (bool locked) } -void CSVWorld::DialogueSubView::dataChanged(const QModelIndex & index) +void CSVWorld::DialogueSubView::dataChanged (const QModelIndex & index) { QModelIndex currentIndex(mTable->getModelIndex(mCurrentId, 0)); @@ -627,10 +627,10 @@ void CSVWorld::DialogueSubView::dataChanged(const QModelIndex & index) } } -void CSVWorld::DialogueSubView::tableMimeDataDropped(QWidget* editor, - const QModelIndex& index, - const CSMWorld::UniversalId& id, - const CSMDoc::Document* document) +void CSVWorld::DialogueSubView::tableMimeDataDropped (QWidget* editor, + const QModelIndex& index, + const CSMWorld::UniversalId& id, + const CSMDoc::Document* document) { if (document == &mDocument) { @@ -662,9 +662,9 @@ void CSVWorld::DialogueSubView::showPreview () } } -void CSVWorld::DialogueSubView::viewRecord() +void CSVWorld::DialogueSubView::viewRecord () { - QModelIndex currentIndex(mTable->getModelIndex(mCurrentId, 0)); + QModelIndex currentIndex(mTable->getModelIndex (mCurrentId, 0)); if (currentIndex.isValid() && currentIndex.row() < mTable->rowCount()) @@ -676,7 +676,7 @@ void CSVWorld::DialogueSubView::viewRecord() } } -void CSVWorld::DialogueSubView::changeCurrentId(const std::string& newId) +void CSVWorld::DialogueSubView::changeCurrentId (const std::string& newId) { std::vector selection; mCurrentId = std::string(newId); From 32fcc9ad6194533f7e367f46ae500c133cffb102 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Tue, 17 Jun 2014 11:14:12 +0200 Subject: [PATCH 0016/3725] Trying to merge. --- apps/opencs/model/world/idtable.cpp | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 59fc3a508..cbfb7f923 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -43,9 +43,6 @@ QVariant CSMWorld::IdTable::data (const QModelIndex & index, int role) const if (role==Qt::EditRole && !mIdCollection->getColumn (index.column()).isEditable()) return QVariant(); -<<<<<<< Updated upstream - return mIdCollection->getData (index.row(), index.column()); -======= if (index.internalId() != 0) { std::pair parentAdress(unfoldIndexAdress(index.internalId())); @@ -53,7 +50,6 @@ QVariant CSMWorld::IdTable::data (const QModelIndex & index, int role) const } else { return mIdCollection->getData (index.row(), index.column()); } ->>>>>>> Stashed changes } QVariant CSMWorld::IdTable::headerData (int section, Qt::Orientation orientation, int role) const @@ -135,9 +131,6 @@ QModelIndex CSMWorld::IdTable::index (int row, int column, const QModelIndex& pa QModelIndex CSMWorld::IdTable::parent (const QModelIndex& index) const { -<<<<<<< Updated upstream - return QModelIndex(); -======= if (index.internalId() == 0) //0 is used for indexs with invalid parent (top level data) { return QModelIndex(); @@ -151,7 +144,6 @@ QModelIndex CSMWorld::IdTable::parent (const QModelIndex& index) const throw "Parent index is not present in the model"; } return createIndex(adress.first, adress.second, 0); ->>>>>>> Stashed changes } void CSMWorld::IdTable::addRecord (const std::string& id, UniversalId::Type type) @@ -280,9 +272,6 @@ std::pair CSMWorld::IdTable::view (int row) int CSMWorld::IdTable::getColumnId(int column) const { return mIdCollection->getColumn(column).getId(); -<<<<<<< Updated upstream -} -======= } bool CSMWorld::IdTable::hasChildren(const QModelIndex& index) const @@ -313,4 +302,3 @@ std::pair< int, int > CSMWorld::IdTable::unfoldIndexAdress (unsigned int id) con int column = id - row * this->columnCount(); return std::make_pair(row, column); } ->>>>>>> Stashed changes From 5bee682bb3dce1ccddddcb6bb4cf82e7055c2564 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Tue, 17 Jun 2014 14:58:25 +0200 Subject: [PATCH 0017/3725] modified: ../../view/world/dialoguesubview.cpp --- apps/opencs/model/world/idtable.cpp | 2 +- apps/opencs/model/world/refidadapterimp.hpp | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 2a0ba43ea..7db4662ba 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -42,7 +42,7 @@ QVariant CSMWorld::IdTable::data (const QModelIndex & index, int role) const if (role==Qt::EditRole && !mIdCollection->getColumn (index.column()).isEditable()) return QVariant(); - if (index.hasChildren()) + if (hasChildren(index)) { std::pair parentAdress(unfoldIndexAdress(index.internalId())); return mIdCollection->getNestedData(parentAdress.first, parentAdress.second, index.row(), index.column()); diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index cde5dc455..a01e59371 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -624,11 +624,7 @@ namespace CSMWorld virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index) const; virtual void setNestedData (const RefIdColumn *column, RefIdData& data, int index, -<<<<<<< HEAD const QVariant& value, int subRowIndex, int subColIndex) const; -======= - const QVariant& value, int subRowIndex, int subColIndex) const; ->>>>>>> 187fccc8cc630f1f469b4f5fc4e23a28ad8253ec virtual void setData (const RefIdColumn *column, RefIdData& data, int index, const QVariant& value) const; From ce5e889015ca9d8b585db2f1f24854e854ff5064 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Tue, 17 Jun 2014 18:28:49 +0200 Subject: [PATCH 0018/3725] Nested table sits inside it's own layout now. --- apps/opencs/model/world/idtable.cpp | 25 ++++---- apps/opencs/model/world/refidcollection.cpp | 3 +- apps/opencs/view/world/dialoguesubview.cpp | 59 +++++++++---------- apps/opencs/view/world/dialoguesubview.hpp | 64 ++++++++++++++------- 4 files changed, 88 insertions(+), 63 deletions(-) diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 7db4662ba..49d23bed4 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -1,4 +1,3 @@ - #include "idtable.hpp" #include @@ -17,8 +16,7 @@ int CSMWorld::IdTable::rowCount (const QModelIndex & parent) const { if (hasChildren(parent)) { - int nestedRows = mIdCollection->getNestedRowsCount(parent.row(), parent.column()); - return nestedRows; + return mIdCollection->getNestedRowsCount(parent.row(), parent.column()); } return mIdCollection->getSize(); @@ -26,7 +24,8 @@ int CSMWorld::IdTable::rowCount (const QModelIndex & parent) const int CSMWorld::IdTable::columnCount (const QModelIndex & parent) const { - if (parent.isValid()) + if (parent.isValid() && + parent.data().isValid()) { return mIdCollection->getNestedColumnsCount(parent.row(), parent.column()); } @@ -42,16 +41,21 @@ QVariant CSMWorld::IdTable::data (const QModelIndex & index, int role) const if (role==Qt::EditRole && !mIdCollection->getColumn (index.column()).isEditable()) return QVariant(); - if (hasChildren(index)) + if (index.internalId() != 0) { std::pair parentAdress(unfoldIndexAdress(index.internalId())); - return mIdCollection->getNestedData(parentAdress.first, parentAdress.second, index.row(), index.column()); + return mIdCollection->getNestedData(parentAdress.first, + parentAdress.second, + index.row(), + index.column()); } else { return mIdCollection->getData (index.row(), index.column()); } } -QVariant CSMWorld::IdTable::headerData (int section, Qt::Orientation orientation, int role) const +QVariant CSMWorld::IdTable::headerData (int section, + Qt::Orientation orientation, + int role) const { if (orientation==Qt::Vertical) return QVariant(); @@ -68,7 +72,7 @@ QVariant CSMWorld::IdTable::headerData (int section, Qt::Orientation orientation return QVariant(); } -bool CSMWorld::IdTable::setData ( const QModelIndex &index, const QVariant &value, int role) +bool CSMWorld::IdTable::setData (const QModelIndex &index, const QVariant &value, int role) { if (mIdCollection->getColumn (index.column()).isEditable() && role==Qt::EditRole) { @@ -291,10 +295,7 @@ std::pair< int, int > CSMWorld::IdTable::unfoldIndexAdress (unsigned int id) con bool CSMWorld::IdTable::hasChildren(const QModelIndex& index) const { return (index.isValid() && - CSMWorld::ColumnBase::Display_Nested == static_cast (headerData - (index.column(), - Qt::Horizontal, - CSMWorld::ColumnBase::Role_Display).toInt()) && + CSMWorld::ColumnBase::Display_Nested == static_cast (headerData (index.column(), Qt::Horizontal, CSMWorld::ColumnBase::Role_Display).toInt()) && index.internalId() == 0 && index.data().isValid()); } diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index ad7fbd049..936663399 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -601,8 +601,7 @@ int CSMWorld::RefIdCollection::getNestedRowsCount(int row, int column) const const CSMWorld::NestedRefIdAdapter& adaptor = dynamic_cast(findAdaptor (localIndex.second)); - const int count = adaptor.getNestedRowsCount(&mColumns.at(column), mData, localIndex.first); - return count; + return adaptor.getNestedRowsCount(&mColumns.at(column), mData, localIndex.first); } int CSMWorld::RefIdCollection::getNestedColumnsCount(int row, int column) const diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index a9a1bb96e..08bac8b08 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include "../../model/world/columnbase.hpp" #include "../../model/world/idtable.hpp" @@ -133,25 +134,25 @@ void CSVWorld::DialogueDelegateDispatcherProxy::tableMimeDataDropped(const std:: if (mDisplay == CSMWorld::ColumnBase::Display_Referenceable) { if ( type == CSMWorld::UniversalId::Type_Activator - || type == CSMWorld::UniversalId::Type_Potion - || type == CSMWorld::UniversalId::Type_Apparatus - || type == CSMWorld::UniversalId::Type_Armor - || type == CSMWorld::UniversalId::Type_Book - || type == CSMWorld::UniversalId::Type_Clothing - || type == CSMWorld::UniversalId::Type_Container - || type == CSMWorld::UniversalId::Type_Creature - || type == CSMWorld::UniversalId::Type_Door - || type == CSMWorld::UniversalId::Type_Ingredient - || type == CSMWorld::UniversalId::Type_CreatureLevelledList - || type == CSMWorld::UniversalId::Type_ItemLevelledList - || type == CSMWorld::UniversalId::Type_Light - || type == CSMWorld::UniversalId::Type_Lockpick - || type == CSMWorld::UniversalId::Type_Miscellaneous - || type == CSMWorld::UniversalId::Type_Npc - || type == CSMWorld::UniversalId::Type_Probe - || type == CSMWorld::UniversalId::Type_Repair - || type == CSMWorld::UniversalId::Type_Static - || type == CSMWorld::UniversalId::Type_Weapon) + || type == CSMWorld::UniversalId::Type_Potion + || type == CSMWorld::UniversalId::Type_Apparatus + || type == CSMWorld::UniversalId::Type_Armor + || type == CSMWorld::UniversalId::Type_Book + || type == CSMWorld::UniversalId::Type_Clothing + || type == CSMWorld::UniversalId::Type_Container + || type == CSMWorld::UniversalId::Type_Creature + || type == CSMWorld::UniversalId::Type_Door + || type == CSMWorld::UniversalId::Type_Ingredient + || type == CSMWorld::UniversalId::Type_CreatureLevelledList + || type == CSMWorld::UniversalId::Type_ItemLevelledList + || type == CSMWorld::UniversalId::Type_Light + || type == CSMWorld::UniversalId::Type_Lockpick + || type == CSMWorld::UniversalId::Type_Miscellaneous + || type == CSMWorld::UniversalId::Type_Npc + || type == CSMWorld::UniversalId::Type_Probe + || type == CSMWorld::UniversalId::Type_Repair + || type == CSMWorld::UniversalId::Type_Static + || type == CSMWorld::UniversalId::Type_Weapon) { type = CSMWorld::UniversalId::Type_Referenceable; } @@ -304,7 +305,7 @@ QWidget* CSVWorld::DialogueDelegateDispatcher::makeEditor(CSMWorld::ColumnBase:: } //lisp cond pairs would be nice in the C++ connect(proxy, SIGNAL(editorDataCommited(QWidget*, const QModelIndex&, CSMWorld::ColumnBase::Display)), - this, SLOT(editorDataCommited(QWidget*, const QModelIndex&, CSMWorld::ColumnBase::Display))); + this, SLOT(editorDataCommited(QWidget*, const QModelIndex&, CSMWorld::ColumnBase::Display))); mProxys.push_back(proxy); //deleted in the destructor } @@ -334,7 +335,7 @@ mTable(table) remake (row); connect(&mDispatcher, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*)), - this, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*))); + this, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*))); } void CSVWorld::EditWidget::remake(int row) @@ -366,9 +367,12 @@ void CSVWorld::EditWidget::remake(int row) QVBoxLayout *mainLayout = new QVBoxLayout(mMainWidget); QGridLayout *unlockedLayout = new QGridLayout(); QGridLayout *lockedLayout = new QGridLayout(); + QVBoxLayout *tablesLayout = new QVBoxLayout(); + mainLayout->addLayout(lockedLayout, 0); mainLayout->addWidget(line, 1); mainLayout->addLayout(unlockedLayout, 2); + mainLayout->addLayout(tablesLayout, 3); mainLayout->addStretch(1); int unlocked = 0; @@ -384,15 +388,12 @@ void CSVWorld::EditWidget::remake(int row) CSMWorld::ColumnBase::Display display = static_cast (mTable->headerData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Display).toInt()); - if (display == CSMWorld::ColumnBase::Display_Nested) + if (mTable->hasChildren(mTable->index(row, i))) { - const QModelIndex& parent = mTable->index(row, i); - if (parent.data().isValid() && mTable->hasChildren(parent)) - { - QTableView* table = new QTableView(this); - table->setModel(mTable); - table->setRootIndex(mTable->index(row, i)); - } + QTableView* table = new QTableView(); + table->setModel(mTable); + table->setRootIndex(mTable->index(row, i)); + tablesLayout->addWidget(table); } else { mDispatcher.makeDelegate (display); diff --git a/apps/opencs/view/world/dialoguesubview.hpp b/apps/opencs/view/world/dialoguesubview.hpp index 050aad947..f36785e88 100644 --- a/apps/opencs/view/world/dialoguesubview.hpp +++ b/apps/opencs/view/world/dialoguesubview.hpp @@ -38,16 +38,23 @@ namespace CSVWorld { const CSMWorld::IdTable* mTable; public: - NotEditableSubDelegate(const CSMWorld::IdTable* table, QObject * parent = 0); + NotEditableSubDelegate(const CSMWorld::IdTable* table, + QObject * parent = 0); - virtual void setEditorData (QLabel* editor, const QModelIndex& index) const; + virtual void setEditorData (QLabel* editor, + const QModelIndex& index) const; - virtual void setModelData (QWidget* editor, QAbstractItemModel* model, const QModelIndex& index, CSMWorld::ColumnBase::Display display) const; + virtual void setModelData (QWidget* editor, QAbstractItemModel* model, + const QModelIndex& index, + CSMWorld::ColumnBase::Display display) const; - virtual void paint (QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const; + virtual void paint (QPainter* painter, + const QStyleOptionViewItem& option, + const QModelIndex& index) const; ///< does nothing - virtual QSize sizeHint (const QStyleOptionViewItem& option, const QModelIndex& index) const; + virtual QSize sizeHint (const QStyleOptionViewItem& option, + const QModelIndex& index) const; ///< does nothing virtual QWidget *createEditor (QWidget *parent, @@ -75,16 +82,20 @@ namespace CSVWorld std::auto_ptr mIndexWrapper; public: - DialogueDelegateDispatcherProxy(QWidget* editor, CSMWorld::ColumnBase::Display display); + DialogueDelegateDispatcherProxy(QWidget* editor, + CSMWorld::ColumnBase::Display display); QWidget* getEditor() const; public slots: void editorDataCommited(); void setIndex(const QModelIndex& index); - void tableMimeDataDropped(const std::vector& data, const CSMDoc::Document* document); + void tableMimeDataDropped(const std::vector& data, + const CSMDoc::Document* document); signals: - void editorDataCommited(QWidget* editor, const QModelIndex& index, CSMWorld::ColumnBase::Display display); + void editorDataCommited(QWidget* editor, + const QModelIndex& index, + CSMWorld::ColumnBase::Display display); void tableMimeDataDropped(QWidget* editor, const QModelIndex& index, const CSMWorld::UniversalId& id, @@ -105,30 +116,42 @@ namespace CSVWorld NotEditableSubDelegate mNotEditableDelegate; - std::vector mProxys; //once we move to the C++11 we should use unique_ptr + std::vector mProxys; +//once we move to the C++11 we should use unique_ptr public: - DialogueDelegateDispatcher(QObject* parent, CSMWorld::IdTable* table, QUndoStack& undoStack); + DialogueDelegateDispatcher(QObject* parent, + CSMWorld::IdTable* table, + QUndoStack& undoStack); ~DialogueDelegateDispatcher(); CSVWorld::CommandDelegate* makeDelegate(CSMWorld::ColumnBase::Display display); - QWidget* makeEditor(CSMWorld::ColumnBase::Display display, const QModelIndex& index); + QWidget* makeEditor(CSMWorld::ColumnBase::Display display, + const QModelIndex& index); ///< will return null if delegate is not present, parent of the widget is same as for dispatcher itself - virtual void setEditorData (QWidget* editor, const QModelIndex& index) const; + virtual void setEditorData (QWidget* editor, + const QModelIndex& index) const; - virtual void setModelData (QWidget* editor, QAbstractItemModel* model, const QModelIndex& index, CSMWorld::ColumnBase::Display display) const; + virtual void setModelData (QWidget* editor, + QAbstractItemModel* model, + const QModelIndex& index, + CSMWorld::ColumnBase::Display display) const; - virtual void paint (QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const; + virtual void paint (QPainter* painter, + const QStyleOptionViewItem& option, + const QModelIndex& index) const; ///< does nothing - virtual QSize sizeHint (const QStyleOptionViewItem& option, const QModelIndex& index) const; + virtual QSize sizeHint (const QStyleOptionViewItem& option, + const QModelIndex& index) const; ///< does nothing private slots: - void editorDataCommited(QWidget* editor, const QModelIndex& index, CSMWorld::ColumnBase::Display display); + void editorDataCommited(QWidget* editor, const QModelIndex& index, + CSMWorld::ColumnBase::Display display); signals: void tableMimeDataDropped(QWidget* editor, const QModelIndex& index, @@ -149,7 +172,8 @@ namespace CSVWorld public: - EditWidget (QWidget *parent, int row, CSMWorld::IdTable* table, QUndoStack& undoStack, bool createAndDelete = false); + EditWidget (QWidget *parent, int row, CSMWorld::IdTable* table, + QUndoStack& undoStack, bool createAndDelete = false); void remake(int row); @@ -167,7 +191,7 @@ namespace CSVWorld QVBoxLayout* mMainLayout; CSMWorld::IdTable* mTable; QUndoStack& mUndoStack; - std::string mCurrentId; + std::string mCurrentId; bool mLocked; const CSMDoc::Document& mDocument; TableBottomBox* mBottom; @@ -181,9 +205,9 @@ namespace CSVWorld bool sorting = false); virtual void setEditLock (bool locked); - + private: - void changeCurrentId(const std::string& newCurrent); + void changeCurrentId(const std::string& newCurrent); private slots: From 75b5513c6c4d6f59eced88b4e60deae43ad218fb Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Tue, 17 Jun 2014 22:02:20 +0200 Subject: [PATCH 0019/3725] Column is responsible for telling that it can nest columns now. --- apps/opencs/model/world/columnbase.cpp | 11 ++++++++--- apps/opencs/model/world/columnbase.hpp | 11 +++++++---- apps/opencs/model/world/idtable.cpp | 4 +--- apps/opencs/model/world/refidcollection.cpp | 6 +++--- apps/opencs/model/world/refidcollection.hpp | 4 ++-- 5 files changed, 21 insertions(+), 15 deletions(-) diff --git a/apps/opencs/model/world/columnbase.cpp b/apps/opencs/model/world/columnbase.cpp index f6363fe2e..e81943843 100644 --- a/apps/opencs/model/world/columnbase.cpp +++ b/apps/opencs/model/world/columnbase.cpp @@ -3,8 +3,8 @@ #include "columns.hpp" -CSMWorld::ColumnBase::ColumnBase (int columnId, Display displayType, int flags) -: mColumnId (columnId), mDisplayType (displayType), mFlags (flags) +CSMWorld::ColumnBase::ColumnBase (int columnId, Display displayType, int flags, bool canNest) + : mColumnId (columnId), mDisplayType (displayType), mFlags (flags), mCanNest(canNest) {} CSMWorld::ColumnBase::~ColumnBase() {} @@ -22,4 +22,9 @@ std::string CSMWorld::ColumnBase::getTitle() const int CSMWorld::ColumnBase::getId() const { return mColumnId; -} \ No newline at end of file +} + +bool CSMWorld::ColumnBase::canHaveNestedColumns() const +{ + return mCanNest; +} diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index c8670a03b..9761b95aa 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -91,14 +91,15 @@ namespace CSMWorld Display_QuestStatusType, Display_Gender, - Display_Nested + Display_NestedItemList }; int mColumnId; int mFlags; Display mDisplayType; + const bool mCanNest; - ColumnBase (int columnId, Display displayType, int flag); + ColumnBase (int columnId, Display displayType, int flag, bool canNest = false); virtual ~ColumnBase(); @@ -110,6 +111,8 @@ namespace CSMWorld virtual std::string getTitle() const; virtual int getId() const; + + bool canHaveNestedColumns() const; }; template @@ -117,8 +120,8 @@ namespace CSMWorld { int mFlags; - Column (int columnId, Display displayType, int flags = Flag_Table | Flag_Dialogue) - : ColumnBase (columnId, displayType, flags) {} + Column (int columnId, Display displayType, int flags = Flag_Table | Flag_Dialogue, bool canNest = false) + : ColumnBase (columnId, displayType, flags, canNest) {} virtual QVariant get (const Record& record) const = 0; diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 49d23bed4..6aba322c1 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -1,7 +1,5 @@ #include "idtable.hpp" -#include - #include "collectionbase.hpp" #include "columnbase.hpp" @@ -295,7 +293,7 @@ std::pair< int, int > CSMWorld::IdTable::unfoldIndexAdress (unsigned int id) con bool CSMWorld::IdTable::hasChildren(const QModelIndex& index) const { return (index.isValid() && - CSMWorld::ColumnBase::Display_Nested == static_cast (headerData (index.column(), Qt::Horizontal, CSMWorld::ColumnBase::Role_Display).toInt()) && index.internalId() == 0 && + mIdCollection->getColumn (index.column()).canHaveNestedColumns() && index.data().isValid()); } diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 936663399..a8fac216b 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -12,8 +12,8 @@ #include "columns.hpp" CSMWorld::RefIdColumn::RefIdColumn (int columnId, Display displayType, int flag, - bool editable, bool userEditable) -: ColumnBase (columnId, displayType, flag), mEditable (editable), mUserEditable (userEditable) + bool editable, bool userEditable, bool canNest) + : ColumnBase (columnId, displayType, flag, canNest), mEditable (editable), mUserEditable (userEditable) {} bool CSMWorld::RefIdColumn::isEditable() const @@ -166,7 +166,7 @@ CSMWorld::RefIdCollection::RefIdCollection() mColumns.push_back (RefIdColumn (Columns::ColumnId_Respawn, ColumnBase::Display_Boolean)); const RefIdColumn *respawn = &mColumns.back(); - mColumns.push_back(RefIdColumn (Columns::ColumnId_ContainerContent, ColumnBase::Display_Nested, ColumnBase::Flag_Dialogue, false, false)); + mColumns.push_back(RefIdColumn (Columns::ColumnId_ContainerContent, ColumnBase::Display_NestedItemList, ColumnBase::Flag_Dialogue, true, true, true)); const RefIdColumn *content = &mColumns.back(); CreatureColumns creatureColumns (actorsColumns); diff --git a/apps/opencs/model/world/refidcollection.hpp b/apps/opencs/model/world/refidcollection.hpp index cb0baa45b..fec621ac1 100644 --- a/apps/opencs/model/world/refidcollection.hpp +++ b/apps/opencs/model/world/refidcollection.hpp @@ -26,8 +26,8 @@ namespace CSMWorld public: RefIdColumn (int columnId, Display displayType, - int flag = Flag_Table | Flag_Dialogue, bool editable = true, - bool userEditable = true); + int flag = Flag_Table | Flag_Dialogue, bool editable = true, + bool userEditable = true, bool canNest = false); virtual bool isEditable() const; From 1fb18873cbe88d3e41c6e66c1a4fce7132d72c11 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Wed, 18 Jun 2014 15:35:31 +0200 Subject: [PATCH 0020/3725] adding proxy model that is ment to be used by the dialoguesubview --- apps/opencs/CMakeLists.txt | 1 + apps/opencs/model/world/columns.hpp | 1 + apps/opencs/model/world/nestedtablemodel.cpp | 34 ++++++++++++++++ apps/opencs/model/world/nestedtablemodel.hpp | 42 ++++++++++++++++++++ 4 files changed, 78 insertions(+) create mode 100644 apps/opencs/model/world/nestedtablemodel.cpp create mode 100644 apps/opencs/model/world/nestedtablemodel.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index d9cac95f3..e76e64610 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -19,6 +19,7 @@ opencs_hdrs_noqt (model/doc opencs_units (model/world idtable idtableproxymodel regionmap data commanddispatcher + nestedtablemodel ) diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index fa9c92e7d..e824c4392 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -168,6 +168,7 @@ namespace CSMWorld ColumnId_Scope = 155, ColumnId_ReferenceableId = 156, ColumnId_ContainerContent = 157, + ColumnId_ItemCount = 158, // Allocated to a separate value range, so we don't get a collision should we ever need // to extend the number of use values. diff --git a/apps/opencs/model/world/nestedtablemodel.cpp b/apps/opencs/model/world/nestedtablemodel.cpp new file mode 100644 index 000000000..20a68faad --- /dev/null +++ b/apps/opencs/model/world/nestedtablemodel.cpp @@ -0,0 +1,34 @@ +#include "nestedtablemodel.hpp" + +#include "./idtable.hpp" + +CSMWorld::NestedTableModel::NestedTableModel(const QModelIndex& parent, + ColumnBase::Display columnId, + CSMWorld::IdTable* parentModel) + : mParentColumn(parent.column()) +{ + const int parentRow = parent.row(); + mId = std::string(parentModel->index(parentRow, 0).data().toString().toUtf8()); + QAbstractProxyModel::setSourceModel(parentModel); +} + +QModelIndex CSMWorld::NestedTableModel::mapFromSource(const QModelIndex& sourceIndex) const +{ + const QModelIndex& testedParent = sourceModel()->parent(sourceIndex); + const QModelIndex& parent = dynamic_cast(sourceModel())->getModelIndex (mId, mParentColumn); + if (testedParent == parent) + { + return createIndex(sourceIndex.row(), sourceIndex.column()); + } + else + { + return QModelIndex(); + } + +} + +QModelIndex CSMWorld::NestedTableModel::mapToSource(const QModelIndex& proxyIndex) const +{ + const QModelIndex& parent = dynamic_cast(sourceModel())->getModelIndex (mId, mParentColumn); + return sourceModel()->index(proxyIndex.row(), proxyIndex.column(), parent); +} diff --git a/apps/opencs/model/world/nestedtablemodel.hpp b/apps/opencs/model/world/nestedtablemodel.hpp new file mode 100644 index 000000000..acab1f851 --- /dev/null +++ b/apps/opencs/model/world/nestedtablemodel.hpp @@ -0,0 +1,42 @@ + +#ifndef CSM_WOLRD_NESTEDTABLEMODEL_H +#define CSM_WOLRD_NESTEDTABLEMODEL_H + +#include + +#include + +#include "universalid.hpp" +#include "columns.hpp" +#include "columnbase.hpp" + +/*! \brief + * Proxy model used to connect view in the dialogue into the nested columns of the main model. + */ + +namespace CSMWorld +{ + class CollectionBase; + class RecordBase; + class IdTable; + + class NestedTableModel : public QAbstractProxyModel + { + const int mParentColumn; + std::string mId; + std::vector mHeaderTitle; + std::vector mHeaderDisplay; + + public: + NestedTableModel(const QModelIndex& parent, + ColumnBase::Display displayType, + IdTable* parentModel); + //parent is the parent of columns to work with. Columnid provides information about the column + + virtual QModelIndex mapFromSource(const QModelIndex& sourceIndex) const; + + virtual QModelIndex mapToSource(const QModelIndex& proxyIndex) const; + }; +} + +#endif From b63f2f4cd538651643d9084f89d30cebbdcee89d Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Wed, 18 Jun 2014 16:53:46 +0200 Subject: [PATCH 0021/3725] Actually using new nestedmodel --- apps/opencs/model/world/nestedtablemodel.cpp | 48 +++++++++++++++++++- apps/opencs/model/world/nestedtablemodel.hpp | 15 ++++-- apps/opencs/view/world/dialoguesubview.cpp | 23 ++++++++-- apps/opencs/view/world/dialoguesubview.hpp | 4 ++ 4 files changed, 81 insertions(+), 9 deletions(-) diff --git a/apps/opencs/model/world/nestedtablemodel.cpp b/apps/opencs/model/world/nestedtablemodel.cpp index 20a68faad..9a685557e 100644 --- a/apps/opencs/model/world/nestedtablemodel.cpp +++ b/apps/opencs/model/world/nestedtablemodel.cpp @@ -1,10 +1,11 @@ #include "nestedtablemodel.hpp" +#include #include "./idtable.hpp" CSMWorld::NestedTableModel::NestedTableModel(const QModelIndex& parent, ColumnBase::Display columnId, - CSMWorld::IdTable* parentModel) + CSMWorld::IdTable* parentModel) : mParentColumn(parent.column()) { const int parentRow = parent.row(); @@ -20,7 +21,7 @@ QModelIndex CSMWorld::NestedTableModel::mapFromSource(const QModelIndex& sourceI { return createIndex(sourceIndex.row(), sourceIndex.column()); } - else + else { return QModelIndex(); } @@ -32,3 +33,46 @@ QModelIndex CSMWorld::NestedTableModel::mapToSource(const QModelIndex& proxyInde const QModelIndex& parent = dynamic_cast(sourceModel())->getModelIndex (mId, mParentColumn); return sourceModel()->index(proxyIndex.row(), proxyIndex.column(), parent); } + +int CSMWorld::NestedTableModel::rowCount(const QModelIndex& index) const +{ + assert (!index.isValid()); + + CSMWorld::IdTable* table = dynamic_cast(sourceModel()); + + return table->rowCount(table->getModelIndex(mId, mParentColumn)); +} + +int CSMWorld::NestedTableModel::columnCount(const QModelIndex& parent) const +{ + assert (!parent.isValid()); + + CSMWorld::IdTable* table = dynamic_cast(sourceModel()); + + return table->columnCount(table->getModelIndex(mId, mParentColumn)); +} + +QModelIndex CSMWorld::NestedTableModel::index(int row, int column, const QModelIndex& parent) const +{ + assert (!parent.isValid()); + + CSMWorld::IdTable* table = dynamic_cast(sourceModel()); + + unsigned rows = table->rowCount(parent); + usigned columns = table->columnCount(parent); + + if (row < 0 || + row >= rows || + column < 0 || + column >= columns) + { + return QModelIndex(); + } + + return createIndex(row, column); +} + +QModelIndex CSMWorld::NestedTableModel::parent(const QModelIndex& index) const +{ + return QModelIndex(); +} diff --git a/apps/opencs/model/world/nestedtablemodel.hpp b/apps/opencs/model/world/nestedtablemodel.hpp index acab1f851..be29be2ca 100644 --- a/apps/opencs/model/world/nestedtablemodel.hpp +++ b/apps/opencs/model/world/nestedtablemodel.hpp @@ -1,4 +1,3 @@ - #ifndef CSM_WOLRD_NESTEDTABLEMODEL_H #define CSM_WOLRD_NESTEDTABLEMODEL_H @@ -26,16 +25,24 @@ namespace CSMWorld std::string mId; std::vector mHeaderTitle; std::vector mHeaderDisplay; - + public: NestedTableModel(const QModelIndex& parent, ColumnBase::Display displayType, IdTable* parentModel); //parent is the parent of columns to work with. Columnid provides information about the column - + virtual QModelIndex mapFromSource(const QModelIndex& sourceIndex) const; - + virtual QModelIndex mapToSource(const QModelIndex& proxyIndex) const; + + virtual int rowCount(const QModelIndex& parent) const; + + virtual int columnCount(const QModelIndex& parent) const; + + virtual QModelIndex index(int row, int column, const QModelIndex& parent) const; + + virtual QModelIndex parent(const QModelIndex& index) const; }; } diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 08bac8b08..7a0e2efec 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -22,6 +22,7 @@ #include #include +#include "../../model/world/nestedtablemodel.hpp" #include "../../model/world/columnbase.hpp" #include "../../model/world/idtable.hpp" #include "../../model/world/columns.hpp" @@ -324,6 +325,14 @@ CSVWorld::DialogueDelegateDispatcher::~DialogueDelegateDispatcher() =============================================================EditWidget===================================================== */ +CSVWorld::EditWidget::~EditWidget() +{ + for (unsigned i = 0; i < mNestedModels.size(); ++i) + { + delete mNestedModels[i]; + } +} + CSVWorld::EditWidget::EditWidget(QWidget *parent, int row, CSMWorld::IdTable* table, QUndoStack& undoStack, bool createAndDelete) : mDispatcher(this, table, undoStack), QScrollArea(parent), @@ -340,6 +349,11 @@ mTable(table) void CSVWorld::EditWidget::remake(int row) { + for (unsigned i = 0; i < mNestedModels.size(); ++i) + { + delete mNestedModels[i]; + } + if (mMainWidget) { delete mMainWidget; @@ -379,7 +393,7 @@ void CSVWorld::EditWidget::remake(int row) int locked = 0; const int columns = mTable->columnCount(); - for (int i=0; iheaderData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Flags).toInt(); @@ -390,9 +404,12 @@ void CSVWorld::EditWidget::remake(int row) if (mTable->hasChildren(mTable->index(row, i))) { + mNestedModels.push_back(new CSMWorld::NestedTableModel (mTable->index(row, i), display, mTable)); + QTableView* table = new QTableView(); - table->setModel(mTable); - table->setRootIndex(mTable->index(row, i)); + + table->setModel(*(mNestedModels.rbegin())); + tablesLayout->addWidget(table); } else { diff --git a/apps/opencs/view/world/dialoguesubview.hpp b/apps/opencs/view/world/dialoguesubview.hpp index f36785e88..90a365592 100644 --- a/apps/opencs/view/world/dialoguesubview.hpp +++ b/apps/opencs/view/world/dialoguesubview.hpp @@ -21,6 +21,7 @@ class QVBoxLayout; namespace CSMWorld { class IdTable; + class NestedTableModel; } namespace CSMDoc @@ -169,12 +170,15 @@ namespace CSVWorld QWidget* mMainWidget; CSMWorld::IdTable* mTable; QUndoStack& mUndoStack; + std::vector mNestedModels; //Plain, raw C pointers, deleted in the dtor public: EditWidget (QWidget *parent, int row, CSMWorld::IdTable* table, QUndoStack& undoStack, bool createAndDelete = false); + ~EditWidget(); + void remake(int row); signals: From 873cfcf447136b4e442b550c48573d8efc55ad47 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Wed, 18 Jun 2014 17:34:21 +0200 Subject: [PATCH 0022/3725] implemented basic headerData (still work in progress) --- apps/opencs/model/world/nestedtablemodel.cpp | 44 +++++++++++++++++++- apps/opencs/model/world/nestedtablemodel.hpp | 5 +++ apps/opencs/view/world/dialoguesubview.cpp | 2 +- 3 files changed, 48 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/world/nestedtablemodel.cpp b/apps/opencs/model/world/nestedtablemodel.cpp index 9a685557e..9ae4bdfd3 100644 --- a/apps/opencs/model/world/nestedtablemodel.cpp +++ b/apps/opencs/model/world/nestedtablemodel.cpp @@ -9,8 +9,12 @@ CSMWorld::NestedTableModel::NestedTableModel(const QModelIndex& parent, : mParentColumn(parent.column()) { const int parentRow = parent.row(); + mId = std::string(parentModel->index(parentRow, 0).data().toString().toUtf8()); + QAbstractProxyModel::setSourceModel(parentModel); + + setupHeaderVectors(columnId); } QModelIndex CSMWorld::NestedTableModel::mapFromSource(const QModelIndex& sourceIndex) const @@ -58,8 +62,8 @@ QModelIndex CSMWorld::NestedTableModel::index(int row, int column, const QModelI CSMWorld::IdTable* table = dynamic_cast(sourceModel()); - unsigned rows = table->rowCount(parent); - usigned columns = table->columnCount(parent); + int rows = table->rowCount(parent); + int columns = table->columnCount(parent); if (row < 0 || row >= rows || @@ -76,3 +80,39 @@ QModelIndex CSMWorld::NestedTableModel::parent(const QModelIndex& index) const { return QModelIndex(); } + +QVariant CSMWorld::NestedTableModel::headerData(int section, + Qt::Orientation orientation, + int role) const +{ + if (orientation==Qt::Vertical) + return QVariant(); + + if (role==Qt::DisplayRole) + return tr (mHeaderTitle[section].c_str()); + + if (role==ColumnBase::Role_Flags) + return QVariant(); //TODO + + if (role==ColumnBase::Role_Display) + return mHeaderDisplay[section]; + + return QVariant(); +} + +void CSMWorld::NestedTableModel::setupHeaderVectors(ColumnBase::Display columnId) +{ + switch(columnId) + { + case ColumnBase::Display_NestedItemList: + mHeaderTitle.push_back("test1"); + mHeaderTitle.push_back("test2"); + + mHeaderDisplay.push_back(ColumnBase::Display_String); + mHeaderDisplay.push_back(ColumnBase::Display_Integer); + break; + + default: + assert(false); + } +} diff --git a/apps/opencs/model/world/nestedtablemodel.hpp b/apps/opencs/model/world/nestedtablemodel.hpp index be29be2ca..80c7f5a8e 100644 --- a/apps/opencs/model/world/nestedtablemodel.hpp +++ b/apps/opencs/model/world/nestedtablemodel.hpp @@ -43,6 +43,11 @@ namespace CSMWorld virtual QModelIndex index(int row, int column, const QModelIndex& parent) const; virtual QModelIndex parent(const QModelIndex& index) const; + + virtual QVariant headerData ( int section, Qt::Orientation orientation, int role ) const; + + private: + void setupHeaderVectors(ColumnBase::Display columnId); }; } diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 7a0e2efec..109f0c3fa 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -393,7 +393,7 @@ void CSVWorld::EditWidget::remake(int row) int locked = 0; const int columns = mTable->columnCount(); - for (unsigned i=0; iheaderData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Flags).toInt(); From 256b075914b97194e408d208c6db7b6fe5300f76 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Thu, 19 Jun 2014 16:11:31 +0200 Subject: [PATCH 0023/3725] getting rid of not needed abstract class --- apps/opencs/model/world/columnbase.hpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index 9761b95aa..164ca4302 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -130,12 +130,6 @@ namespace CSMWorld throw std::logic_error ("Column " + getTitle() + " is not editable"); } }; - - template - struct NestedColumn - { - virtual QVariant getNested(const Record& record, int subColumn, int subSow) const = 0; - }; } #endif From a076798f8febb9034b9dc0944c7899230d867b16 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Thu, 19 Jun 2014 18:46:09 +0200 Subject: [PATCH 0024/3725] Quick and dirty prototype of actual nested header data implementation --- apps/opencs/model/world/columnbase.cpp | 14 +++++ apps/opencs/model/world/columnbase.hpp | 6 ++ apps/opencs/model/world/columns.cpp | 15 +++++ apps/opencs/model/world/columns.hpp | 4 ++ apps/opencs/model/world/idtable.cpp | 21 +++++++ apps/opencs/model/world/idtable.hpp | 2 + apps/opencs/model/world/nestedtablemodel.cpp | 58 ++++---------------- apps/opencs/model/world/nestedtablemodel.hpp | 3 +- apps/opencs/model/world/refidcollection.cpp | 2 + 9 files changed, 76 insertions(+), 49 deletions(-) diff --git a/apps/opencs/model/world/columnbase.cpp b/apps/opencs/model/world/columnbase.cpp index e81943843..c0a264a1f 100644 --- a/apps/opencs/model/world/columnbase.cpp +++ b/apps/opencs/model/world/columnbase.cpp @@ -3,6 +3,8 @@ #include "columns.hpp" +#include + CSMWorld::ColumnBase::ColumnBase (int columnId, Display displayType, int flags, bool canNest) : mColumnId (columnId), mDisplayType (displayType), mFlags (flags), mCanNest(canNest) {} @@ -28,3 +30,15 @@ bool CSMWorld::ColumnBase::canHaveNestedColumns() const { return mCanNest; } + +std::string CSMWorld::ColumnBase::getNestedColumnTitle(int columnNumber) const +{ + return Columns::getName (mDisplayType, columnNumber); +} + +void CSMWorld::ColumnBase::addNestedColumnDisplay(CSMWorld::ColumnBase::Display displayDefinition) +{ + assert (canHaveNestedColumns()); + + mNestedDisplayType.push_back(displayDefinition); +} diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index 164ca4302..0cd1f722f 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -2,6 +2,7 @@ #define CSM_WOLRD_COLUMNBASE_H #include +#include #include #include @@ -97,6 +98,7 @@ namespace CSMWorld int mColumnId; int mFlags; Display mDisplayType; + std::vector mNestedDisplayType; const bool mCanNest; ColumnBase (int columnId, Display displayType, int flag, bool canNest = false); @@ -110,6 +112,10 @@ namespace CSMWorld virtual std::string getTitle() const; + std::string getNestedColumnTitle(int columnNumber) const; + + virtual void addNestedColumnDisplay(Display displayDefinition); + virtual int getId() const; bool canHaveNestedColumns() const; diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 7410780e0..e39badeb5 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -216,6 +216,21 @@ std::string CSMWorld::Columns::getName (ColumnId column) return ""; } +std::string CSMWorld::Columns::getName(CSMWorld::ColumnBase::Display displayType, int columnNumber) +{ +//TODO, this is just temporary solution + switch (displayType) + { + case CSMWorld::ColumnBase::Display_NestedItemList: + if (columnNumber == 0) + return "ID"; + + if (columnNumber == 1) + return "Count"; + } + return "Do yourself a favor and take a look at the columns.cpp"; +} + int CSMWorld::Columns::getId (const std::string& name) { std::string name2 = Misc::StringUtils::lowerCase (name); diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index e824c4392..436ca1334 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -4,6 +4,8 @@ #include #include +#include "columnbase.hpp" + namespace CSMWorld { namespace Columns @@ -208,6 +210,8 @@ namespace CSMWorld std::string getName (ColumnId column); + std::string getName (ColumnBase::Display displayType, int columnNumber); + int getId (const std::string& name); ///< Will return -1 for an invalid name. diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 6aba322c1..fd2547ecf 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -1,5 +1,7 @@ #include "idtable.hpp" +#include + #include "collectionbase.hpp" #include "columnbase.hpp" @@ -70,6 +72,25 @@ QVariant CSMWorld::IdTable::headerData (int section, return QVariant(); } +QVariant CSMWorld::IdTable::nestedHeaderData(int section, int subSection, Qt::Orientation orientation, int role) const +{ + assert(mIdCollection->getColumn(section).canHaveNestedColumns()); + + if (orientation==Qt::Vertical) + return QVariant(); + + if (role==Qt::DisplayRole) + return tr (mIdCollection->getColumn(section).getNestedColumnTitle(subSection).c_str()); + + if (role==ColumnBase::Role_Flags) + return mIdCollection->getColumn (section).mFlags; + + if (role==ColumnBase::Role_Display) + return mIdCollection->getColumn (section).mNestedDisplayType.at(subSection); + + return QVariant(); +} + bool CSMWorld::IdTable::setData (const QModelIndex &index, const QVariant &value, int role) { if (mIdCollection->getColumn (index.column()).isEditable() && role==Qt::EditRole) diff --git a/apps/opencs/model/world/idtable.hpp b/apps/opencs/model/world/idtable.hpp index 6dc6f3e33..29d1f134a 100644 --- a/apps/opencs/model/world/idtable.hpp +++ b/apps/opencs/model/world/idtable.hpp @@ -72,6 +72,8 @@ namespace CSMWorld virtual QVariant headerData (int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; + QVariant nestedHeaderData(int section, int subSection, Qt::Orientation orientation, int role = Qt::DisplayRole) const; + virtual bool setData ( const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); virtual Qt::ItemFlags flags (const QModelIndex & index) const; diff --git a/apps/opencs/model/world/nestedtablemodel.cpp b/apps/opencs/model/world/nestedtablemodel.cpp index 9ae4bdfd3..534ec5d10 100644 --- a/apps/opencs/model/world/nestedtablemodel.cpp +++ b/apps/opencs/model/world/nestedtablemodel.cpp @@ -6,21 +6,20 @@ CSMWorld::NestedTableModel::NestedTableModel(const QModelIndex& parent, ColumnBase::Display columnId, CSMWorld::IdTable* parentModel) - : mParentColumn(parent.column()) + : mParentColumn(parent.column()), + mMainModel(parentModel) { const int parentRow = parent.row(); mId = std::string(parentModel->index(parentRow, 0).data().toString().toUtf8()); QAbstractProxyModel::setSourceModel(parentModel); - - setupHeaderVectors(columnId); } QModelIndex CSMWorld::NestedTableModel::mapFromSource(const QModelIndex& sourceIndex) const { - const QModelIndex& testedParent = sourceModel()->parent(sourceIndex); - const QModelIndex& parent = dynamic_cast(sourceModel())->getModelIndex (mId, mParentColumn); + const QModelIndex& testedParent = mMainModel->parent(sourceIndex); + const QModelIndex& parent = mMainModel->getModelIndex (mId, mParentColumn); if (testedParent == parent) { return createIndex(sourceIndex.row(), sourceIndex.column()); @@ -34,36 +33,30 @@ QModelIndex CSMWorld::NestedTableModel::mapFromSource(const QModelIndex& sourceI QModelIndex CSMWorld::NestedTableModel::mapToSource(const QModelIndex& proxyIndex) const { - const QModelIndex& parent = dynamic_cast(sourceModel())->getModelIndex (mId, mParentColumn); - return sourceModel()->index(proxyIndex.row(), proxyIndex.column(), parent); + const QModelIndex& parent = mMainModel->getModelIndex (mId, mParentColumn); + return mMainModel->index(proxyIndex.row(), proxyIndex.column(), parent); } int CSMWorld::NestedTableModel::rowCount(const QModelIndex& index) const { assert (!index.isValid()); - CSMWorld::IdTable* table = dynamic_cast(sourceModel()); - - return table->rowCount(table->getModelIndex(mId, mParentColumn)); + return mMainModel->rowCount(mMainModel->getModelIndex(mId, mParentColumn)); } int CSMWorld::NestedTableModel::columnCount(const QModelIndex& parent) const { assert (!parent.isValid()); - CSMWorld::IdTable* table = dynamic_cast(sourceModel()); - - return table->columnCount(table->getModelIndex(mId, mParentColumn)); + return mMainModel->columnCount(mMainModel->getModelIndex(mId, mParentColumn)); } QModelIndex CSMWorld::NestedTableModel::index(int row, int column, const QModelIndex& parent) const { assert (!parent.isValid()); - CSMWorld::IdTable* table = dynamic_cast(sourceModel()); - - int rows = table->rowCount(parent); - int columns = table->columnCount(parent); + int rows = mMainModel->rowCount(parent); + int columns = mMainModel->columnCount(parent); if (row < 0 || row >= rows || @@ -85,34 +78,5 @@ QVariant CSMWorld::NestedTableModel::headerData(int section, Qt::Orientation orientation, int role) const { - if (orientation==Qt::Vertical) - return QVariant(); - - if (role==Qt::DisplayRole) - return tr (mHeaderTitle[section].c_str()); - - if (role==ColumnBase::Role_Flags) - return QVariant(); //TODO - - if (role==ColumnBase::Role_Display) - return mHeaderDisplay[section]; - - return QVariant(); -} - -void CSMWorld::NestedTableModel::setupHeaderVectors(ColumnBase::Display columnId) -{ - switch(columnId) - { - case ColumnBase::Display_NestedItemList: - mHeaderTitle.push_back("test1"); - mHeaderTitle.push_back("test2"); - - mHeaderDisplay.push_back(ColumnBase::Display_String); - mHeaderDisplay.push_back(ColumnBase::Display_Integer); - break; - - default: - assert(false); - } + return mMainModel->nestedHeaderData(mParentColumn, section, orientation, role); } diff --git a/apps/opencs/model/world/nestedtablemodel.hpp b/apps/opencs/model/world/nestedtablemodel.hpp index 80c7f5a8e..404051efc 100644 --- a/apps/opencs/model/world/nestedtablemodel.hpp +++ b/apps/opencs/model/world/nestedtablemodel.hpp @@ -22,9 +22,8 @@ namespace CSMWorld class NestedTableModel : public QAbstractProxyModel { const int mParentColumn; + IdTable* mMainModel; std::string mId; - std::vector mHeaderTitle; - std::vector mHeaderDisplay; public: NestedTableModel(const QModelIndex& parent, diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index a8fac216b..47c8ec800 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -168,6 +168,8 @@ CSMWorld::RefIdCollection::RefIdCollection() mColumns.push_back(RefIdColumn (Columns::ColumnId_ContainerContent, ColumnBase::Display_NestedItemList, ColumnBase::Flag_Dialogue, true, true, true)); const RefIdColumn *content = &mColumns.back(); + (&mColumns.back())->addNestedColumnDisplay(CSMWorld::ColumnBase::Display_String); + (&mColumns.back())->addNestedColumnDisplay(CSMWorld::ColumnBase::Display_Integer); CreatureColumns creatureColumns (actorsColumns); From 894c98ee89479294fff69a674030a51d93353493 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Fri, 20 Jun 2014 13:40:54 +0200 Subject: [PATCH 0025/3725] Added extra columnid type to use for ID of the inventory item --- apps/opencs/model/world/columnbase.cpp | 16 ++++++++++++---- apps/opencs/model/world/columnbase.hpp | 12 ++++++++---- apps/opencs/model/world/columns.cpp | 17 ++--------------- apps/opencs/model/world/columns.hpp | 3 +-- apps/opencs/model/world/refidcollection.cpp | 2 ++ 5 files changed, 25 insertions(+), 25 deletions(-) diff --git a/apps/opencs/model/world/columnbase.cpp b/apps/opencs/model/world/columnbase.cpp index c0a264a1f..59ee39126 100644 --- a/apps/opencs/model/world/columnbase.cpp +++ b/apps/opencs/model/world/columnbase.cpp @@ -1,4 +1,3 @@ - #include "columnbase.hpp" #include "columns.hpp" @@ -33,12 +32,21 @@ bool CSMWorld::ColumnBase::canHaveNestedColumns() const std::string CSMWorld::ColumnBase::getNestedColumnTitle(int columnNumber) const { - return Columns::getName (mDisplayType, columnNumber); + assert (mCanNest); + + return Columns::getName(static_cast(mNestedColumnId[columnNumber])); } void CSMWorld::ColumnBase::addNestedColumnDisplay(CSMWorld::ColumnBase::Display displayDefinition) { - assert (canHaveNestedColumns()); - + assert (mCanNest); + mNestedDisplayType.push_back(displayDefinition); } + +void CSMWorld::ColumnBase::addNestedColumnId(int columnId) +{ + assert (mCanNest); + + mNestedColumnId.push_back(columnId); +} diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index 0cd1f722f..1cc45780f 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -31,7 +31,7 @@ namespace CSMWorld Display_String, Display_LongString, - //CONCRETE TYPES STARTS HERE + //CONCRETE TYPES STARTS HERE (for drag and drop) Display_Skill, Display_Class, Display_Faction, @@ -92,13 +92,15 @@ namespace CSMWorld Display_QuestStatusType, Display_Gender, + //Those are top level columns that nest other columns Display_NestedItemList }; int mColumnId; int mFlags; Display mDisplayType; - std::vector mNestedDisplayType; + std::vector mNestedDisplayType; //used only for the columns that actually nest other columns + std::vector mNestedColumnId; //used only for the columns that actually nest other columns const bool mCanNest; ColumnBase (int columnId, Display displayType, int flag, bool canNest = false); @@ -113,8 +115,10 @@ namespace CSMWorld virtual std::string getTitle() const; std::string getNestedColumnTitle(int columnNumber) const; - - virtual void addNestedColumnDisplay(Display displayDefinition); + + void addNestedColumnDisplay(Display displayDefinition); + + void addNestedColumnId(int columnId); virtual int getId() const; diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index e39badeb5..1898277a5 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -174,6 +174,8 @@ namespace CSMWorld { ColumnId_PcRank, "PC Rank" }, { ColumnId_Scope, "Scope" }, { ColumnId_ReferenceableId, "Referenceable ID" }, + { ColumnId_InventoryItemId, "ID"}, + { ColumnId_ItemCount, "Count"}, { ColumnId_UseValue1, "Use value 1" }, { ColumnId_UseValue2, "Use value 2" }, @@ -216,21 +218,6 @@ std::string CSMWorld::Columns::getName (ColumnId column) return ""; } -std::string CSMWorld::Columns::getName(CSMWorld::ColumnBase::Display displayType, int columnNumber) -{ -//TODO, this is just temporary solution - switch (displayType) - { - case CSMWorld::ColumnBase::Display_NestedItemList: - if (columnNumber == 0) - return "ID"; - - if (columnNumber == 1) - return "Count"; - } - return "Do yourself a favor and take a look at the columns.cpp"; -} - int CSMWorld::Columns::getId (const std::string& name) { std::string name2 = Misc::StringUtils::lowerCase (name); diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 436ca1334..5d8ddb87d 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -171,6 +171,7 @@ namespace CSMWorld ColumnId_ReferenceableId = 156, ColumnId_ContainerContent = 157, ColumnId_ItemCount = 158, + ColumnId_InventoryItemId = 159, // Allocated to a separate value range, so we don't get a collision should we ever need // to extend the number of use values. @@ -210,8 +211,6 @@ namespace CSMWorld std::string getName (ColumnId column); - std::string getName (ColumnBase::Display displayType, int columnNumber); - int getId (const std::string& name); ///< Will return -1 for an invalid name. diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 47c8ec800..9fe42af96 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -170,6 +170,8 @@ CSMWorld::RefIdCollection::RefIdCollection() const RefIdColumn *content = &mColumns.back(); (&mColumns.back())->addNestedColumnDisplay(CSMWorld::ColumnBase::Display_String); (&mColumns.back())->addNestedColumnDisplay(CSMWorld::ColumnBase::Display_Integer); + (&mColumns.back())->addNestedColumnId(Columns::ColumnId_InventoryItemId); + (&mColumns.back())->addNestedColumnId(Columns::ColumnId_ItemCount); CreatureColumns creatureColumns (actorsColumns); From 88c5288eafb5a7260e616c0943eba3f6935f3daf Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Tue, 24 Jun 2014 10:22:42 +0200 Subject: [PATCH 0026/3725] Create removeNestedRow (for deleting rows of nested columns) --- apps/opencs/model/world/refidadapter.hpp | 2 + apps/opencs/model/world/refidadapterimp.cpp | 52 ++++++++++++--------- apps/opencs/model/world/refidadapterimp.hpp | 3 ++ 3 files changed, 35 insertions(+), 22 deletions(-) diff --git a/apps/opencs/model/world/refidadapter.hpp b/apps/opencs/model/world/refidadapter.hpp index 039f44a5e..928c0eaab 100644 --- a/apps/opencs/model/world/refidadapter.hpp +++ b/apps/opencs/model/world/refidadapter.hpp @@ -51,6 +51,8 @@ namespace CSMWorld virtual int getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const = 0; virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const = 0; + + virtual void removeNestedRow (const RefIdColumn *column, RefIdData& data, int index, unsigned rowToRemove) const = 0; }; } diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index 19b8b06b8..6377db040 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -1,7 +1,6 @@ - #include "refidadapterimp.hpp" -#include +#include CSMWorld::PotionRefIdAdapter::PotionRefIdAdapter (const InventoryColumns& columns, const RefIdColumn *autoCalc) @@ -182,26 +181,21 @@ CSMWorld::ContainerRefIdAdapter::ContainerRefIdAdapter (const NameColumns& colum int CSMWorld::ContainerRefIdAdapter::getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const { - if (column==mContent) - { - return 2; - } else { - throw "Trying to obtain nested columns count, but column does not have nested columns!"; - } + assert(column==mContent); + + return 2; } int CSMWorld::ContainerRefIdAdapter::getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const { + assert(column==mContent); + const Record& record = static_cast&> ( data.getRecord(RefIdData::LocalIndex (index, UniversalId::Type_Container))); - if (column==mContent) - { - return record.get().mInventory.mList.size(); - } else { - throw "Trying to obtain nested rows count, but column does not have nested columns!"; - } + return record.get().mInventory.mList.size(); } + QVariant CSMWorld::ContainerRefIdAdapter::getData (const RefIdColumn *column, const RefIdData& data, int index) const { @@ -223,6 +217,18 @@ QVariant CSMWorld::ContainerRefIdAdapter::getData (const RefIdColumn *column, co return NameRefIdAdapter::getData (column, data, index); } +void CSMWorld::ContainerRefIdAdapter::removeNestedRow (const RefIdColumn *column, RefIdData& data, int index, unsigned rowToRemove) const +{ + assert(column==mContent); + + std::vector& list = static_cast&> ( + data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Container))).get().mInventory.mList; + + list.erase (list.begin () + rowToRemove); +} + + + void CSMWorld::ContainerRefIdAdapter::setData (const RefIdColumn *column, RefIdData& data, int index, const QVariant& value) const { @@ -249,17 +255,19 @@ void CSMWorld::ContainerRefIdAdapter::setData (const RefIdColumn *column, RefIdD NameRefIdAdapter::setData (column, data, index, value); } -void CSMWorld::ContainerRefIdAdapter::setNestedData(const RefIdColumn *column, RefIdData& data, - int index, - const QVariant& value, - int subRowIndex, - int subColIndex) const +void CSMWorld::ContainerRefIdAdapter::setNestedData(const RefIdColumn *column, + RefIdData& data, + int index, + const QVariant& value, + int subRowIndex, + int subColIndex) const { - Record& record = static_cast&> ( - data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Container))); if (column==mContent) { + Record& record = static_cast&> ( + data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Container))); + switch (subColIndex) { case 0: @@ -275,7 +283,7 @@ void CSMWorld::ContainerRefIdAdapter::setNestedData(const RefIdColumn *column, R } } else { - throw "This column does not hold multiple values."; + assert(false); } } diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index a01e59371..eeb859d84 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -633,6 +633,9 @@ namespace CSMWorld virtual int getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const; virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const; + + + virtual void removeNestedRow (const RefIdColumn *column, RefIdData& data, int index, unsigned rowToRemove) const; }; struct CreatureColumns : public ActorColumns From c45061614b22fc9244a59ec34109866759cb8416 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Tue, 24 Jun 2014 12:21:40 +0200 Subject: [PATCH 0027/3725] Added code to delete nestedRows --- apps/opencs/model/world/collectionbase.cpp | 5 +++++ apps/opencs/model/world/collectionbase.hpp | 2 ++ apps/opencs/model/world/idtable.cpp | 8 +++++++- apps/opencs/model/world/refidadapter.hpp | 2 +- apps/opencs/model/world/refidadapterimp.cpp | 4 +--- apps/opencs/model/world/refidadapterimp.hpp | 3 +-- apps/opencs/model/world/refidcollection.cpp | 9 +++++++++ apps/opencs/model/world/refidcollection.hpp | 2 ++ apps/opencs/model/world/refiddata.hpp | 4 ++-- 9 files changed, 30 insertions(+), 9 deletions(-) diff --git a/apps/opencs/model/world/collectionbase.cpp b/apps/opencs/model/world/collectionbase.cpp index 7ea25770a..70f1fdf9f 100644 --- a/apps/opencs/model/world/collectionbase.cpp +++ b/apps/opencs/model/world/collectionbase.cpp @@ -47,3 +47,8 @@ int CSMWorld::CollectionBase::getNestedRowsCount(int row, int column) const assert(false); //TODO, make pure abstract return 0; } + +void CSMWorld::CollectionBase::removeNestedRows(int row, int column, int subRow) +{ + assert(false); //todo, make pure abstract +} diff --git a/apps/opencs/model/world/collectionbase.hpp b/apps/opencs/model/world/collectionbase.hpp index b6aad7eff..01fde1c8c 100644 --- a/apps/opencs/model/world/collectionbase.hpp +++ b/apps/opencs/model/world/collectionbase.hpp @@ -64,6 +64,8 @@ namespace CSMWorld virtual void removeRows (int index, int count) = 0; + virtual void removeNestedRows(int row, int column, int subRow); + virtual void appendBlankRecord (const std::string& id, UniversalId::Type type = UniversalId::Type_None) = 0; ///< \param type Will be ignored, unless the collection supports multiple record types diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index fd2547ecf..6e43cfeac 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -126,7 +126,13 @@ Qt::ItemFlags CSMWorld::IdTable::flags (const QModelIndex & index) const bool CSMWorld::IdTable::removeRows (int row, int count, const QModelIndex& parent) { if (parent.isValid()) - return false; + { + for (int i = 0; i < count; ++i) + { + mIdCollection->removeNestedRows(parent.row(), parent.column(), row+i); + } + return true; + } beginRemoveRows (parent, row, row+count-1); diff --git a/apps/opencs/model/world/refidadapter.hpp b/apps/opencs/model/world/refidadapter.hpp index 928c0eaab..fddb073a2 100644 --- a/apps/opencs/model/world/refidadapter.hpp +++ b/apps/opencs/model/world/refidadapter.hpp @@ -52,7 +52,7 @@ namespace CSMWorld virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const = 0; - virtual void removeNestedRow (const RefIdColumn *column, RefIdData& data, int index, unsigned rowToRemove) const = 0; + virtual void removeNestedRow (const RefIdColumn *column, RefIdData& data, int index, int rowToRemove) const = 0; }; } diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index 6377db040..01652ea7e 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -217,7 +217,7 @@ QVariant CSMWorld::ContainerRefIdAdapter::getData (const RefIdColumn *column, co return NameRefIdAdapter::getData (column, data, index); } -void CSMWorld::ContainerRefIdAdapter::removeNestedRow (const RefIdColumn *column, RefIdData& data, int index, unsigned rowToRemove) const +void CSMWorld::ContainerRefIdAdapter::removeNestedRow (const RefIdColumn *column, RefIdData& data, int index, int rowToRemove) const { assert(column==mContent); @@ -227,8 +227,6 @@ void CSMWorld::ContainerRefIdAdapter::removeNestedRow (const RefIdColumn *column list.erase (list.begin () + rowToRemove); } - - void CSMWorld::ContainerRefIdAdapter::setData (const RefIdColumn *column, RefIdData& data, int index, const QVariant& value) const { diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index eeb859d84..1f3a07dc0 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -633,9 +633,8 @@ namespace CSMWorld virtual int getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const; virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const; - - virtual void removeNestedRow (const RefIdColumn *column, RefIdData& data, int index, unsigned rowToRemove) const; + virtual void removeNestedRow (const RefIdColumn *column, RefIdData& data, int index, int rowToRemove) const; }; struct CreatureColumns : public ActorColumns diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 9fe42af96..47e52289f 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -463,6 +463,15 @@ void CSMWorld::RefIdCollection::removeRows (int index, int count) mData.erase (index, count); } +void CSMWorld::RefIdCollection::removeNestedRows(int row, int column, int subRow) +{ + RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); + + const RefIdAdapter& adaptor = findAdaptor (localIndex.second); + + dynamic_cast(adaptor).removeNestedRow(&mColumns.at (column), mData, localIndex.first, subRow); +} + void CSMWorld::RefIdCollection::appendBlankRecord (const std::string& id, UniversalId::Type type) { mData.appendRecord (type, id, false); diff --git a/apps/opencs/model/world/refidcollection.hpp b/apps/opencs/model/world/refidcollection.hpp index fec621ac1..08fb410a5 100644 --- a/apps/opencs/model/world/refidcollection.hpp +++ b/apps/opencs/model/world/refidcollection.hpp @@ -76,6 +76,8 @@ namespace CSMWorld virtual void setNestedData(int row, int column, const QVariant& data, int subRow, int subColumn); virtual void removeRows (int index, int count); + + virtual void removeNestedRows(int row, int column, int subRow); virtual void cloneRecord(const std::string& origin, const std::string& destination, diff --git a/apps/opencs/model/world/refiddata.hpp b/apps/opencs/model/world/refiddata.hpp index 535e914ee..bfdd4f9ee 100644 --- a/apps/opencs/model/world/refiddata.hpp +++ b/apps/opencs/model/world/refiddata.hpp @@ -52,7 +52,7 @@ namespace CSMWorld virtual void load (int index, ESM::ESMReader& reader, bool base) = 0; virtual void erase (int index, int count) = 0; - + virtual std::string getId (int index) const = 0; virtual void save (int index, ESM::ESMWriter& writer) const = 0; @@ -134,7 +134,7 @@ namespace CSMWorld throw std::runtime_error ("invalid RefIdDataContainer index"); mContainer.erase (mContainer.begin()+index, mContainer.begin()+index+count); - } + } template std::string RefIdDataContainer::getId (int index) const From 7430e1e1bbc2232cb3656bc50303f51819b2394b Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Tue, 24 Jun 2014 12:35:26 +0200 Subject: [PATCH 0028/3725] Added delete nested rows command (undo still needs to be done) --- apps/opencs/model/world/commands.cpp | 43 ++++++++++++++++++++++++++-- apps/opencs/model/world/commands.hpp | 26 +++++++++++++++-- 2 files changed, 65 insertions(+), 4 deletions(-) diff --git a/apps/opencs/model/world/commands.cpp b/apps/opencs/model/world/commands.cpp index b60ffeb29..019a3d397 100644 --- a/apps/opencs/model/world/commands.cpp +++ b/apps/opencs/model/world/commands.cpp @@ -1,4 +1,3 @@ - #include "commands.hpp" #include @@ -171,4 +170,44 @@ void CSMWorld::CloneCommand::redo() void CSMWorld::CloneCommand::undo() { mModel.removeRow (mModel.getModelIndex (mIdDestination, 0).row()); -} \ No newline at end of file +} + +CSMWorld::DeleteNestedCommand::DeleteNestedCommand (IdTable& model, const std::string& id, int nestedRow, int parentColumn, QUndoCommand* parent) + : mId(id), + mModel(model), + mParentColumn(parentColumn), + QUndoCommand(parent), + mNestedRow(nestedRow) +{ + setText (("Delete nested row in " + mId).c_str()); + + const QModelIndex& parentIndex = mModel.getModelIndex(mId, mParentColumn); + + const int columnsCount = mModel.columnCount(parentIndex); + + for (int i = 0; i < columnsCount; ++i) + { + const QModelIndex& childIndex = mModel.index(nestedRow, i, parentIndex); + + QVariant data = childIndex.data(); + if (!data.isValid()) + { + data = childIndex.data(Qt::DisplayRole); + } + + mOld.push_back(data); + } +} + +void CSMWorld::DeleteNestedCommand::redo() +{ + const QModelIndex& parentIndex = mModel.getModelIndex(mId, mParentColumn); + + mModel.removeRows (mNestedRow, 1, parentIndex); +} + + +void CSMWorld::DeleteNestedCommand::undo() +{ + //TODO +} diff --git a/apps/opencs/model/world/commands.hpp b/apps/opencs/model/world/commands.hpp index ec6350658..192b161ef 100644 --- a/apps/opencs/model/world/commands.hpp +++ b/apps/opencs/model/world/commands.hpp @@ -10,6 +10,7 @@ #include #include #include +#include #include "universalid.hpp" @@ -49,7 +50,7 @@ namespace CSMWorld public: - CloneCommand (IdTable& model, const std::string& idOrigin, + CloneCommand (IdTable& model, const std::string& idOrigin, const std::string& IdDestination, const UniversalId::Type type, QUndoCommand* parent = 0); @@ -135,6 +136,27 @@ namespace CSMWorld virtual void undo(); }; + + class DeleteNestedCommand : public QUndoCommand + { + IdTable& mModel; + + std::string mId; + + std::vector mOld; + + int mParentColumn; + + int mNestedRow; + + public: + + DeleteNestedCommand (IdTable& model, const std::string& id, int nestedRow, int parentColumn, QUndoCommand* parent); + + virtual void redo(); + + virtual void undo(); + }; } -#endif \ No newline at end of file +#endif From befdeb18897d5e9da0b0678de74e49b45d2658a0 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Tue, 24 Jun 2014 12:42:49 +0200 Subject: [PATCH 0029/3725] use beginRemovRow when removing nested row. --- apps/opencs/model/world/idtable.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 6e43cfeac..90d7e35b5 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -127,10 +127,12 @@ bool CSMWorld::IdTable::removeRows (int row, int count, const QModelIndex& paren { if (parent.isValid()) { + beginRemoveRows(parent, row, row+count-1); for (int i = 0; i < count; ++i) { mIdCollection->removeNestedRows(parent.row(), parent.column(), row+i); } + endRemoveRows(); return true; } From 7b5bf637abd3cf884dcb7fcb49cad8c64b5e876c Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Tue, 24 Jun 2014 19:03:29 +0200 Subject: [PATCH 0030/3725] Changes needed to add new nested row. --- apps/opencs/model/world/collectionbase.cpp | 5 +++++ apps/opencs/model/world/collectionbase.hpp | 2 ++ apps/opencs/model/world/idtable.cpp | 7 +++++++ apps/opencs/model/world/idtable.hpp | 2 ++ apps/opencs/model/world/refidadapter.hpp | 2 ++ apps/opencs/model/world/refidadapterimp.cpp | 19 +++++++++++++++++++ apps/opencs/model/world/refidadapterimp.hpp | 2 ++ apps/opencs/model/world/refidcollection.cpp | 9 +++++++++ apps/opencs/model/world/refidcollection.hpp | 2 ++ 9 files changed, 50 insertions(+) diff --git a/apps/opencs/model/world/collectionbase.cpp b/apps/opencs/model/world/collectionbase.cpp index 70f1fdf9f..a1f4f4a70 100644 --- a/apps/opencs/model/world/collectionbase.cpp +++ b/apps/opencs/model/world/collectionbase.cpp @@ -52,3 +52,8 @@ void CSMWorld::CollectionBase::removeNestedRows(int row, int column, int subRow) { assert(false); //todo, make pure abstract } + +void CSMWorld::CollectionBase::addNestedRow(int row, int col, int position) +{ + assert(false); +} diff --git a/apps/opencs/model/world/collectionbase.hpp b/apps/opencs/model/world/collectionbase.hpp index 01fde1c8c..aad40d36b 100644 --- a/apps/opencs/model/world/collectionbase.hpp +++ b/apps/opencs/model/world/collectionbase.hpp @@ -66,6 +66,8 @@ namespace CSMWorld virtual void removeNestedRows(int row, int column, int subRow); + virtual void addNestedRow(int row, int col, int position); + virtual void appendBlankRecord (const std::string& id, UniversalId::Type type = UniversalId::Type_None) = 0; ///< \param type Will be ignored, unless the collection supports multiple record types diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 90d7e35b5..a4e4972b4 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -145,6 +145,13 @@ bool CSMWorld::IdTable::removeRows (int row, int count, const QModelIndex& paren return true; } +void CSMWorld::IdTable::addNestedRow(const QModelIndex& parent, int position) +{ + assert(parent.isValid()); + + mIdCollection->addNestedRow(parent.row(), parent.column(), position); +} + QModelIndex CSMWorld::IdTable::index (int row, int column, const QModelIndex& parent) const { unsigned int encodedId = 0; diff --git a/apps/opencs/model/world/idtable.hpp b/apps/opencs/model/world/idtable.hpp index 29d1f134a..bf72b8026 100644 --- a/apps/opencs/model/world/idtable.hpp +++ b/apps/opencs/model/world/idtable.hpp @@ -80,6 +80,8 @@ namespace CSMWorld virtual bool removeRows (int row, int count, const QModelIndex& parent = QModelIndex()); + void addNestedRow (const QModelIndex& parent, int position); + virtual QModelIndex index (int row, int column, const QModelIndex& parent = QModelIndex()) const; diff --git a/apps/opencs/model/world/refidadapter.hpp b/apps/opencs/model/world/refidadapter.hpp index fddb073a2..068347fda 100644 --- a/apps/opencs/model/world/refidadapter.hpp +++ b/apps/opencs/model/world/refidadapter.hpp @@ -53,6 +53,8 @@ namespace CSMWorld virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const = 0; virtual void removeNestedRow (const RefIdColumn *column, RefIdData& data, int index, int rowToRemove) const = 0; + + virtual void addNestedRow (const RefIdColumn *column, RefIdData& data, int index, int position) const = 0; }; } diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index 01652ea7e..5b92ae941 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -227,6 +227,25 @@ void CSMWorld::ContainerRefIdAdapter::removeNestedRow (const RefIdColumn *column list.erase (list.begin () + rowToRemove); } +void CSMWorld::ContainerRefIdAdapter::addNestedRow (const RefIdColumn *column, RefIdData& data, int index, int position) const +{ + assert(column==mContent); + + std::vector& list = static_cast&> ( + data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Container))).get().mInventory.mList; + + ESM::ContItem newRow = {0, ""}; + if (position >= (int)list.size()) + { + list.push_back(newRow); + return; + } + + list.insert(list.begin()+position, newRow); + + return; +} + void CSMWorld::ContainerRefIdAdapter::setData (const RefIdColumn *column, RefIdData& data, int index, const QVariant& value) const { diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index 1f3a07dc0..6fc56271b 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -635,6 +635,8 @@ namespace CSMWorld virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const; virtual void removeNestedRow (const RefIdColumn *column, RefIdData& data, int index, int rowToRemove) const; + + virtual void addNestedRow (const RefIdColumn *column, RefIdData& data, int index, int position) const; }; struct CreatureColumns : public ActorColumns diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 47e52289f..57a42d9fb 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -625,3 +625,12 @@ int CSMWorld::RefIdCollection::getNestedColumnsCount(int row, int column) const return adaptor.getNestedColumnsCount(&mColumns.at(column), mData); } + +void CSMWorld::RefIdCollection::addNestedRow(int row, int col, int position) +{ + RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); + + const CSMWorld::NestedRefIdAdapter& adaptor = dynamic_cast(findAdaptor (localIndex.second)); + + adaptor.addNestedRow(&mColumns.at(col), mData, localIndex.first, position); +} diff --git a/apps/opencs/model/world/refidcollection.hpp b/apps/opencs/model/world/refidcollection.hpp index 08fb410a5..7801811ff 100644 --- a/apps/opencs/model/world/refidcollection.hpp +++ b/apps/opencs/model/world/refidcollection.hpp @@ -79,6 +79,8 @@ namespace CSMWorld virtual void removeNestedRows(int row, int column, int subRow); + virtual void addNestedRow(int row, int col, int position); + virtual void cloneRecord(const std::string& origin, const std::string& destination, const UniversalId::Type type); From d73f4cbd7bf3829ee277caaadcc0bd609f32fa4b Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Tue, 24 Jun 2014 19:19:40 +0200 Subject: [PATCH 0031/3725] added add nested command --- apps/opencs/model/world/commands.cpp | 24 ++++++++++++++++++++++++ apps/opencs/model/world/commands.hpp | 19 +++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/apps/opencs/model/world/commands.cpp b/apps/opencs/model/world/commands.cpp index 019a3d397..42a5a7f7e 100644 --- a/apps/opencs/model/world/commands.cpp +++ b/apps/opencs/model/world/commands.cpp @@ -211,3 +211,27 @@ void CSMWorld::DeleteNestedCommand::undo() { //TODO } + +CSMWorld::AddNestedCommand::AddNestedCommand(IdTable& model, const std::string& id, int nestedRow, int parentColumn, QUndoCommand* parent) + : mModel(model), + mId(id), + mNewRow(nestedRow), + mParentColumn(parentColumn), + QUndoCommand(parent) +{ + setText (("Added nested row in " + mId).c_str()); +} + +void CSMWorld::AddNestedCommand::redo() +{ + const QModelIndex& parentIndex = mModel.getModelIndex(mId, mParentColumn); + + mModel.addNestedRow (parentIndex, mNewRow); +} + +void CSMWorld::AddNestedCommand::undo() +{ + const QModelIndex& parentIndex = mModel.getModelIndex(mId, mParentColumn); + + mModel.removeRows(mNewRow, 1, parentIndex); +} diff --git a/apps/opencs/model/world/commands.hpp b/apps/opencs/model/world/commands.hpp index 192b161ef..9cfc0b293 100644 --- a/apps/opencs/model/world/commands.hpp +++ b/apps/opencs/model/world/commands.hpp @@ -157,6 +157,25 @@ namespace CSMWorld virtual void undo(); }; + + class AddNestedCommand : public QUndoCommand + { + IdTable& mModel; + + std::string mId; + + int mNewRow; + + int mParentColumn; + + public: + + AddNestedCommand(IdTable& model, const std::string& id, int nestedRow, int parentColumn, QUndoCommand* parent); + + virtual void redo(); + + virtual void undo(); + }; } #endif From a0146e2e28cc58c409962c719f3047529327fa32 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Tue, 24 Jun 2014 19:34:02 +0200 Subject: [PATCH 0032/3725] Added undo for delete command --- apps/opencs/model/world/commands.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/world/commands.cpp b/apps/opencs/model/world/commands.cpp index 42a5a7f7e..012736697 100644 --- a/apps/opencs/model/world/commands.cpp +++ b/apps/opencs/model/world/commands.cpp @@ -209,7 +209,16 @@ void CSMWorld::DeleteNestedCommand::redo() void CSMWorld::DeleteNestedCommand::undo() { - //TODO + const QModelIndex& parentIndex = mModel.getModelIndex(mId, mParentColumn); + + mModel.addNestedRow(parentIndex, mNestedRow); + + for (int i = 0; i < mModel.columnCount(parentIndex); ++i) + { + const QModelIndex& current = mModel.index(mNestedRow, i, parentIndex); + + mModel.setData(current, mOld[i]); + } } CSMWorld::AddNestedCommand::AddNestedCommand(IdTable& model, const std::string& id, int nestedRow, int parentColumn, QUndoCommand* parent) From 8c6a0d9a4f1b2729dd078c51d4c51697945aaf39 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Sun, 29 Jun 2014 21:12:31 +0200 Subject: [PATCH 0033/3725] created new files --- apps/opencs/view/world/dialoguesubview.hpp | 2 +- apps/opencs/view/world/nestedtable.cpp | 20 +++++++++++++ apps/opencs/view/world/nestedtable.hpp | 34 ++++++++++++++++++++++ 3 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 apps/opencs/view/world/nestedtable.cpp create mode 100644 apps/opencs/view/world/nestedtable.hpp diff --git a/apps/opencs/view/world/dialoguesubview.hpp b/apps/opencs/view/world/dialoguesubview.hpp index 90a365592..a6b944d7a 100644 --- a/apps/opencs/view/world/dialoguesubview.hpp +++ b/apps/opencs/view/world/dialoguesubview.hpp @@ -170,7 +170,7 @@ namespace CSVWorld QWidget* mMainWidget; CSMWorld::IdTable* mTable; QUndoStack& mUndoStack; - std::vector mNestedModels; //Plain, raw C pointers, deleted in the dtor + std::vector mNestedModels; //Plain, raw C pointers, deleted in the dtor public: diff --git a/apps/opencs/view/world/nestedtable.cpp b/apps/opencs/view/world/nestedtable.cpp new file mode 100644 index 000000000..beeafed90 --- /dev/null +++ b/apps/opencs/view/world/nestedtable.cpp @@ -0,0 +1,20 @@ +#include "nestedtable.hpp" + +NestedTable::NestedTable(CSMDoc::Document& document, CSMWorld::NestedTableModel* model, const CSMWorld::UniversalId& id, QWidget* parent) + : QTableView(parent) +{ + QTableView::setModel(model); + setAcceptDrops(true); + + int columns = mModel->columnCount(); + + for(int i = 0 ; i < columns; ++i) + { + CSMWorld::ColumnBase::Display display = static_cast ( + mModel->headerData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Display).toInt()); + + CommandDelegate *delegate = CommandDelegateFactoryCollection::get().makeDelegate(display, + document.getUndoStack(), + this); + } +} diff --git a/apps/opencs/view/world/nestedtable.hpp b/apps/opencs/view/world/nestedtable.hpp new file mode 100644 index 000000000..200a73798 --- /dev/null +++ b/apps/opencs/view/world/nestedtable.hpp @@ -0,0 +1,34 @@ +#ifndef CSV_WORLD_NESTEDTABLE_H +#define CSV_WORLD_TABLE_H + +#include +#include + +class QUndoStack; +class QAction; + +namespace CSMWorld +{ + class NestedTableModel; +} + +namespace CSVWorld +{ + class NestedTable : public QTableView + { + Q_OBJECT + + std::vector mDelegates; + QAction *mAddNewRowAction; + QAction *mRemoveRowAction; + CSMWorld::CommandDispatcher *mDispatcher; + + public: + NestedTable(CSMDoc::Document& document, CSMWorld::NestedTableModel* model, const CSMWorld::UniversalId& id, QWidget* parent = NULL); + + protected: + void dragEnterEvent(QDragEnterEvent *event); + + void dragMoveEvent(QDragMoveEvent *event); + }; +} From 5eac32e3d3d2af1f4378a3bdcbd87d0fbbcc93ea Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Mon, 30 Jun 2014 13:09:10 +0200 Subject: [PATCH 0034/3725] added nestedtable for displaying nested content. --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/view/world/dialoguesubview.cpp | 6 ++---- apps/opencs/view/world/nestedtable.cpp | 25 +++++++++++++++++----- apps/opencs/view/world/nestedtable.hpp | 16 ++++++++++---- 4 files changed, 35 insertions(+), 14 deletions(-) diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index e76e64610..eec1b653d 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -61,7 +61,7 @@ opencs_hdrs_noqt (view/doc opencs_units (view/world table tablesubview scriptsubview util regionmapsubview tablebottombox creator genericcreator cellcreator referenceablecreator referencecreator scenesubview scenetoolbar scenetool - scenetoolmode infocreator scriptedit dialoguesubview previewsubview regionmap dragrecordtable + scenetoolmode infocreator scriptedit dialoguesubview previewsubview regionmap dragrecordtable nestedtable ) opencs_units (view/render diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 109f0c3fa..122b173e6 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -19,7 +19,6 @@ #include #include #include -#include #include #include "../../model/world/nestedtablemodel.hpp" @@ -34,6 +33,7 @@ #include "recordstatusdelegate.hpp" #include "util.hpp" #include "tablebottombox.hpp" +#include "nestedtable.hpp" /* ==============================NotEditableSubDelegate========================================== */ @@ -406,9 +406,7 @@ void CSVWorld::EditWidget::remake(int row) { mNestedModels.push_back(new CSMWorld::NestedTableModel (mTable->index(row, i), display, mTable)); - QTableView* table = new QTableView(); - - table->setModel(*(mNestedModels.rbegin())); + NestedTable* table = new NestedTable(mUndoStack, *(mNestedModels.rbegin()), this); tablesLayout->addWidget(table); } else diff --git a/apps/opencs/view/world/nestedtable.cpp b/apps/opencs/view/world/nestedtable.cpp index beeafed90..bfadfc08c 100644 --- a/apps/opencs/view/world/nestedtable.cpp +++ b/apps/opencs/view/world/nestedtable.cpp @@ -1,20 +1,35 @@ #include "nestedtable.hpp" +#include "../../model/world/nestedtablemodel.hpp" +#include "../../model/world/universalid.hpp" +#include "util.hpp" -NestedTable::NestedTable(CSMDoc::Document& document, CSMWorld::NestedTableModel* model, const CSMWorld::UniversalId& id, QWidget* parent) +CSVWorld::NestedTable::NestedTable(QUndoStack& undoStack, + CSMWorld::NestedTableModel* model, + QWidget* parent) : QTableView(parent) { - QTableView::setModel(model); + setModel(model); setAcceptDrops(true); - int columns = mModel->columnCount(); + int columns = model->columnCount(QModelIndex()); for(int i = 0 ; i < columns; ++i) { CSMWorld::ColumnBase::Display display = static_cast ( - mModel->headerData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Display).toInt()); + model->headerData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Display).toInt()); CommandDelegate *delegate = CommandDelegateFactoryCollection::get().makeDelegate(display, - document.getUndoStack(), + undoStack, this); + + setItemDelegateForColumn(i, delegate); } } + +void CSVWorld::NestedTable::dragEnterEvent(QDragEnterEvent *event) +{ +} + +void CSVWorld::NestedTable::dragMoveEvent(QDragMoveEvent *event) +{ +} diff --git a/apps/opencs/view/world/nestedtable.hpp b/apps/opencs/view/world/nestedtable.hpp index 200a73798..fe6214151 100644 --- a/apps/opencs/view/world/nestedtable.hpp +++ b/apps/opencs/view/world/nestedtable.hpp @@ -1,5 +1,5 @@ #ifndef CSV_WORLD_NESTEDTABLE_H -#define CSV_WORLD_TABLE_H +#define CSV_WORLD_NESTEDTABLE_H #include #include @@ -10,6 +10,12 @@ class QAction; namespace CSMWorld { class NestedTableModel; + class UniversalId; +} + +namespace CSMDoc +{ + class Document; } namespace CSVWorld @@ -18,13 +24,13 @@ namespace CSVWorld { Q_OBJECT - std::vector mDelegates; QAction *mAddNewRowAction; QAction *mRemoveRowAction; - CSMWorld::CommandDispatcher *mDispatcher; public: - NestedTable(CSMDoc::Document& document, CSMWorld::NestedTableModel* model, const CSMWorld::UniversalId& id, QWidget* parent = NULL); + NestedTable(QUndoStack& undoStack, + CSMWorld::NestedTableModel* model, + QWidget* parent = NULL); protected: void dragEnterEvent(QDragEnterEvent *event); @@ -32,3 +38,5 @@ namespace CSVWorld void dragMoveEvent(QDragMoveEvent *event); }; } + +#endif From c96d48fb914923a75d2e979ec1852415200e38ab Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Mon, 30 Jun 2014 14:12:57 +0200 Subject: [PATCH 0035/3725] Nested model supports editing now. --- apps/opencs/model/world/nestedtablemodel.cpp | 11 +++++++++++ apps/opencs/model/world/nestedtablemodel.hpp | 4 ++++ apps/opencs/view/world/nestedtable.cpp | 15 ++++++++++++--- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/world/nestedtablemodel.cpp b/apps/opencs/model/world/nestedtablemodel.cpp index 534ec5d10..20fbd81e1 100644 --- a/apps/opencs/model/world/nestedtablemodel.cpp +++ b/apps/opencs/model/world/nestedtablemodel.cpp @@ -80,3 +80,14 @@ QVariant CSMWorld::NestedTableModel::headerData(int section, { return mMainModel->nestedHeaderData(mParentColumn, section, orientation, role); } + + +bool CSMWorld::NestedTableModel::setData ( const QModelIndex & index, const QVariant & value, int role) +{ + return mMainModel->setData(mapToSource(index), value, role); +} + +Qt::ItemFlags CSMWorld::NestedTableModel::flags(const QModelIndex& index) const +{ + return mMainModel->flags(mMainModel->index(0, mParentColumn)); +} diff --git a/apps/opencs/model/world/nestedtablemodel.hpp b/apps/opencs/model/world/nestedtablemodel.hpp index 404051efc..0af261f4d 100644 --- a/apps/opencs/model/world/nestedtablemodel.hpp +++ b/apps/opencs/model/world/nestedtablemodel.hpp @@ -45,6 +45,10 @@ namespace CSMWorld virtual QVariant headerData ( int section, Qt::Orientation orientation, int role ) const; + virtual bool setData ( const QModelIndex & index, const QVariant & value, int role = Qt::EditRole ); + + virtual Qt::ItemFlags flags(const QModelIndex& index) const; + private: void setupHeaderVectors(ColumnBase::Display columnId); }; diff --git a/apps/opencs/view/world/nestedtable.cpp b/apps/opencs/view/world/nestedtable.cpp index bfadfc08c..b4bb63f3a 100644 --- a/apps/opencs/view/world/nestedtable.cpp +++ b/apps/opencs/view/world/nestedtable.cpp @@ -3,13 +3,19 @@ #include "../../model/world/universalid.hpp" #include "util.hpp" +#include + CSVWorld::NestedTable::NestedTable(QUndoStack& undoStack, CSMWorld::NestedTableModel* model, QWidget* parent) : QTableView(parent) { - setModel(model); - setAcceptDrops(true); + + setSelectionBehavior (QAbstractItemView::SelectRows); + setSelectionMode (QAbstractItemView::ExtendedSelection); + + horizontalHeader()->setResizeMode (QHeaderView::Interactive); + verticalHeader()->hide(); int columns = model->columnCount(QModelIndex()); @@ -17,13 +23,16 @@ CSVWorld::NestedTable::NestedTable(QUndoStack& undoStack, { CSMWorld::ColumnBase::Display display = static_cast ( model->headerData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Display).toInt()); - + CommandDelegate *delegate = CommandDelegateFactoryCollection::get().makeDelegate(display, undoStack, this); setItemDelegateForColumn(i, delegate); } + + setModel(model); + setAcceptDrops(true); } void CSVWorld::NestedTable::dragEnterEvent(QDragEnterEvent *event) From 6dc199743c489ea5ae8d5586131bf39298e71280 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Mon, 30 Jun 2014 16:03:38 +0200 Subject: [PATCH 0036/3725] store undoStack in the nestedtable --- apps/opencs/view/world/nestedtable.cpp | 3 ++- apps/opencs/view/world/nestedtable.hpp | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/opencs/view/world/nestedtable.cpp b/apps/opencs/view/world/nestedtable.cpp index b4bb63f3a..ec5d01bbe 100644 --- a/apps/opencs/view/world/nestedtable.cpp +++ b/apps/opencs/view/world/nestedtable.cpp @@ -8,7 +8,8 @@ CSVWorld::NestedTable::NestedTable(QUndoStack& undoStack, CSMWorld::NestedTableModel* model, QWidget* parent) - : QTableView(parent) + : QTableView(parent), + mUndoStack(undoStack) { setSelectionBehavior (QAbstractItemView::SelectRows); diff --git a/apps/opencs/view/world/nestedtable.hpp b/apps/opencs/view/world/nestedtable.hpp index fe6214151..14a46480e 100644 --- a/apps/opencs/view/world/nestedtable.hpp +++ b/apps/opencs/view/world/nestedtable.hpp @@ -26,6 +26,7 @@ namespace CSVWorld QAction *mAddNewRowAction; QAction *mRemoveRowAction; + QUndoStack& mUndoStack; public: NestedTable(QUndoStack& undoStack, From 3ebc469f04d5c9ab03b942fdc683b0194a090ebf Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Mon, 30 Jun 2014 20:06:18 +0200 Subject: [PATCH 0037/3725] prepering for merge --- apps/opencs/view/world/nestedtable.cpp | 6 ++++++ apps/opencs/view/world/nestedtable.hpp | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/apps/opencs/view/world/nestedtable.cpp b/apps/opencs/view/world/nestedtable.cpp index ec5d01bbe..ffb1aaa47 100644 --- a/apps/opencs/view/world/nestedtable.cpp +++ b/apps/opencs/view/world/nestedtable.cpp @@ -4,6 +4,7 @@ #include "util.hpp" #include +#include CSVWorld::NestedTable::NestedTable(QUndoStack& undoStack, CSMWorld::NestedTableModel* model, @@ -43,3 +44,8 @@ void CSVWorld::NestedTable::dragEnterEvent(QDragEnterEvent *event) void CSVWorld::NestedTable::dragMoveEvent(QDragMoveEvent *event) { } + +void CSVWorld::NestedTable::contextMenuEvent (QContextMenuEvent *event) +{ + QModelIndexList selectedRows = selectionModel()->selectedRows(); +} diff --git a/apps/opencs/view/world/nestedtable.hpp b/apps/opencs/view/world/nestedtable.hpp index 14a46480e..bdd3db3fa 100644 --- a/apps/opencs/view/world/nestedtable.hpp +++ b/apps/opencs/view/world/nestedtable.hpp @@ -6,6 +6,7 @@ class QUndoStack; class QAction; +class QContextMenuEvent; namespace CSMWorld { @@ -37,6 +38,9 @@ namespace CSVWorld void dragEnterEvent(QDragEnterEvent *event); void dragMoveEvent(QDragMoveEvent *event); + + private: + void contextMenuEvent (QContextMenuEvent *event); }; } From fcd082c6a53ea2b2d69167a25cc0f8d0992e0830 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Tue, 1 Jul 2014 20:52:27 +0200 Subject: [PATCH 0038/3725] added option to add or remove rows --- apps/opencs/model/world/commands.hpp | 4 +- apps/opencs/model/world/nestedtablemodel.cpp | 15 +++++++ apps/opencs/model/world/nestedtablemodel.hpp | 6 +++ apps/opencs/view/world/nestedtable.cpp | 41 +++++++++++++++++++- apps/opencs/view/world/nestedtable.hpp | 11 ++++++ 5 files changed, 74 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/world/commands.hpp b/apps/opencs/model/world/commands.hpp index 9cfc0b293..e6f2d9724 100644 --- a/apps/opencs/model/world/commands.hpp +++ b/apps/opencs/model/world/commands.hpp @@ -151,7 +151,7 @@ namespace CSMWorld public: - DeleteNestedCommand (IdTable& model, const std::string& id, int nestedRow, int parentColumn, QUndoCommand* parent); + DeleteNestedCommand (IdTable& model, const std::string& id, int nestedRow, int parentColumn, QUndoCommand* parent = 0); virtual void redo(); @@ -170,7 +170,7 @@ namespace CSMWorld public: - AddNestedCommand(IdTable& model, const std::string& id, int nestedRow, int parentColumn, QUndoCommand* parent); + AddNestedCommand(IdTable& model, const std::string& id, int nestedRow, int parentColumn, QUndoCommand* parent = 0); virtual void redo(); diff --git a/apps/opencs/model/world/nestedtablemodel.cpp b/apps/opencs/model/world/nestedtablemodel.cpp index 20fbd81e1..133520d1d 100644 --- a/apps/opencs/model/world/nestedtablemodel.cpp +++ b/apps/opencs/model/world/nestedtablemodel.cpp @@ -91,3 +91,18 @@ Qt::ItemFlags CSMWorld::NestedTableModel::flags(const QModelIndex& index) const { return mMainModel->flags(mMainModel->index(0, mParentColumn)); } + +std::string CSMWorld::NestedTableModel::getParentId() const +{ + return mId; +} + +int CSMWorld::NestedTableModel::getParentColumn() const +{ + return mParentColumn; +} + +CSMWorld::IdTable* CSMWorld::NestedTableModel::model() const +{ + return mMainModel; +} diff --git a/apps/opencs/model/world/nestedtablemodel.hpp b/apps/opencs/model/world/nestedtablemodel.hpp index 0af261f4d..18563b389 100644 --- a/apps/opencs/model/world/nestedtablemodel.hpp +++ b/apps/opencs/model/world/nestedtablemodel.hpp @@ -31,6 +31,12 @@ namespace CSMWorld IdTable* parentModel); //parent is the parent of columns to work with. Columnid provides information about the column + std::string getParentId() const; + + int getParentColumn() const; + + CSMWorld::IdTable* model() const; + virtual QModelIndex mapFromSource(const QModelIndex& sourceIndex) const; virtual QModelIndex mapToSource(const QModelIndex& proxyIndex) const; diff --git a/apps/opencs/view/world/nestedtable.cpp b/apps/opencs/view/world/nestedtable.cpp index ffb1aaa47..ebcce15d5 100644 --- a/apps/opencs/view/world/nestedtable.cpp +++ b/apps/opencs/view/world/nestedtable.cpp @@ -1,16 +1,19 @@ #include "nestedtable.hpp" #include "../../model/world/nestedtablemodel.hpp" #include "../../model/world/universalid.hpp" +#include "../../model/world/commands.hpp" #include "util.hpp" #include #include +#include CSVWorld::NestedTable::NestedTable(QUndoStack& undoStack, CSMWorld::NestedTableModel* model, QWidget* parent) : QTableView(parent), - mUndoStack(undoStack) + mUndoStack(undoStack), + mModel(model) { setSelectionBehavior (QAbstractItemView::SelectRows); @@ -34,7 +37,16 @@ CSVWorld::NestedTable::NestedTable(QUndoStack& undoStack, } setModel(model); + setAcceptDrops(true); + + mAddNewRowAction = new QAction (tr ("Add new row"), this); + connect(mAddNewRowAction, SIGNAL(triggered()), + this, SLOT(addNewRowActionTriggered())); + + mRemoveRowAction = new QAction (tr ("Remove row"), this); + connect(mRemoveRowAction, SIGNAL(triggered()), + this, SLOT(removeRowActionTriggered())); } void CSVWorld::NestedTable::dragEnterEvent(QDragEnterEvent *event) @@ -48,4 +60,31 @@ void CSVWorld::NestedTable::dragMoveEvent(QDragMoveEvent *event) void CSVWorld::NestedTable::contextMenuEvent (QContextMenuEvent *event) { QModelIndexList selectedRows = selectionModel()->selectedRows(); + + QMenu menu(this); + + if (selectionModel()->selectedRows().size() == 1) + menu.addAction(mRemoveRowAction); + + menu.addAction(mAddNewRowAction); + + menu.exec (event->globalPos()); +} + +void CSVWorld::NestedTable::removeRowActionTriggered() +{ + mUndoStack.push(new CSMWorld::DeleteNestedCommand(*(mModel->model()), + mModel->getParentId(), + selectionModel()->selectedRows().begin()->row(), + mModel->getParentColumn())); + +} + +void CSVWorld::NestedTable::addNewRowActionTriggered() +{ + mUndoStack.push(new CSMWorld::AddNestedCommand(*(mModel->model()), + mModel->getParentId(), + selectionModel()->selectedRows().size(), + mModel->getParentColumn())); + } diff --git a/apps/opencs/view/world/nestedtable.hpp b/apps/opencs/view/world/nestedtable.hpp index bdd3db3fa..eb73cd885 100644 --- a/apps/opencs/view/world/nestedtable.hpp +++ b/apps/opencs/view/world/nestedtable.hpp @@ -28,6 +28,7 @@ namespace CSVWorld QAction *mAddNewRowAction; QAction *mRemoveRowAction; QUndoStack& mUndoStack; + CSMWorld::NestedTableModel* mModel; public: NestedTable(QUndoStack& undoStack, @@ -41,6 +42,16 @@ namespace CSVWorld private: void contextMenuEvent (QContextMenuEvent *event); + + private slots: + void removeRowActionTriggered(); + + void addNewRowActionTriggered(); + + signals: + void addNewRow(); + + void removeRow(int row); }; } From c50cecdc642eec35cffa39c404b4ffd334d42c5e Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Tue, 1 Jul 2014 21:13:27 +0200 Subject: [PATCH 0039/3725] Small cleanup --- apps/opencs/model/world/idtable.cpp | 8 +++++--- apps/opencs/view/world/nestedtable.cpp | 2 -- apps/opencs/view/world/nestedtable.hpp | 5 ----- 3 files changed, 5 insertions(+), 10 deletions(-) diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index a4e4972b4..29d2a543e 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -127,12 +127,10 @@ bool CSMWorld::IdTable::removeRows (int row, int count, const QModelIndex& paren { if (parent.isValid()) { - beginRemoveRows(parent, row, row+count-1); for (int i = 0; i < count; ++i) { mIdCollection->removeNestedRows(parent.row(), parent.column(), row+i); } - endRemoveRows(); return true; } @@ -149,7 +147,11 @@ void CSMWorld::IdTable::addNestedRow(const QModelIndex& parent, int position) { assert(parent.isValid()); - mIdCollection->addNestedRow(parent.row(), parent.column(), position); + int row = parent.row(); + mIdCollection->addNestedRow(row, parent.column(), position); + + emit dataChanged (CSMWorld::IdTable::index (row, 0), + CSMWorld::IdTable::index (row, mIdCollection->getColumns()-1)); } QModelIndex CSMWorld::IdTable::index (int row, int column, const QModelIndex& parent) const diff --git a/apps/opencs/view/world/nestedtable.cpp b/apps/opencs/view/world/nestedtable.cpp index ebcce15d5..2eef2e915 100644 --- a/apps/opencs/view/world/nestedtable.cpp +++ b/apps/opencs/view/world/nestedtable.cpp @@ -77,7 +77,6 @@ void CSVWorld::NestedTable::removeRowActionTriggered() mModel->getParentId(), selectionModel()->selectedRows().begin()->row(), mModel->getParentColumn())); - } void CSVWorld::NestedTable::addNewRowActionTriggered() @@ -86,5 +85,4 @@ void CSVWorld::NestedTable::addNewRowActionTriggered() mModel->getParentId(), selectionModel()->selectedRows().size(), mModel->getParentColumn())); - } diff --git a/apps/opencs/view/world/nestedtable.hpp b/apps/opencs/view/world/nestedtable.hpp index eb73cd885..35fa22494 100644 --- a/apps/opencs/view/world/nestedtable.hpp +++ b/apps/opencs/view/world/nestedtable.hpp @@ -47,11 +47,6 @@ namespace CSVWorld void removeRowActionTriggered(); void addNewRowActionTriggered(); - - signals: - void addNewRow(); - - void removeRow(int row); }; } From 77afb754e5d972489e028bd3146bd46ec561ceab Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Wed, 2 Jul 2014 13:13:03 +0200 Subject: [PATCH 0040/3725] adding new rows works --- apps/opencs/model/world/idtable.cpp | 4 +++ apps/opencs/model/world/nestedtablemodel.cpp | 36 ++++++++++++++++++++ apps/opencs/model/world/nestedtablemodel.hpp | 9 +++++ apps/opencs/view/world/nestedtable.cpp | 22 ++++++------ 4 files changed, 61 insertions(+), 10 deletions(-) diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 29d2a543e..f71c367f0 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -148,10 +148,14 @@ void CSMWorld::IdTable::addNestedRow(const QModelIndex& parent, int position) assert(parent.isValid()); int row = parent.row(); + + beginInsertRows(parent, position, position); mIdCollection->addNestedRow(row, parent.column(), position); emit dataChanged (CSMWorld::IdTable::index (row, 0), CSMWorld::IdTable::index (row, mIdCollection->getColumns()-1)); + + endInsertRows(); } QModelIndex CSMWorld::IdTable::index (int row, int column, const QModelIndex& parent) const diff --git a/apps/opencs/model/world/nestedtablemodel.cpp b/apps/opencs/model/world/nestedtablemodel.cpp index 133520d1d..17bf7b30c 100644 --- a/apps/opencs/model/world/nestedtablemodel.cpp +++ b/apps/opencs/model/world/nestedtablemodel.cpp @@ -2,6 +2,7 @@ #include #include "./idtable.hpp" +#include CSMWorld::NestedTableModel::NestedTableModel(const QModelIndex& parent, ColumnBase::Display columnId, @@ -14,6 +15,13 @@ CSMWorld::NestedTableModel::NestedTableModel(const QModelIndex& parent, mId = std::string(parentModel->index(parentRow, 0).data().toString().toUtf8()); QAbstractProxyModel::setSourceModel(parentModel); + + connect(mMainModel, SIGNAL(rowsAboutToBeInserted(const QModelIndex &, int, int)), + this, SLOT(forwardRowsAboutToInserted(const QModelIndex &, int, int))); + + connect(mMainModel, SIGNAL(rowsInserted(const QModelIndex &, int, int)), + this, SLOT(forwardRowsInserted(const QModelIndex &, int, int))); + } QModelIndex CSMWorld::NestedTableModel::mapFromSource(const QModelIndex& sourceIndex) const @@ -106,3 +114,31 @@ CSMWorld::IdTable* CSMWorld::NestedTableModel::model() const { return mMainModel; } + +void CSMWorld::NestedTableModel::forwardRowsAboutToInserted(const QModelIndex& parent, int first, int last) +{ + if (indexIsParent(parent)) + { + qDebug()<<"Adding new rows "<< first<<":"<data(mMainModel->index(index.row(), 0)).toString().toUtf8().constData() == mId); +} diff --git a/apps/opencs/model/world/nestedtablemodel.hpp b/apps/opencs/model/world/nestedtablemodel.hpp index 18563b389..2263524cf 100644 --- a/apps/opencs/model/world/nestedtablemodel.hpp +++ b/apps/opencs/model/world/nestedtablemodel.hpp @@ -21,6 +21,8 @@ namespace CSMWorld class NestedTableModel : public QAbstractProxyModel { + Q_OBJECT + const int mParentColumn; IdTable* mMainModel; std::string mId; @@ -57,6 +59,13 @@ namespace CSMWorld private: void setupHeaderVectors(ColumnBase::Display columnId); + + bool indexIsParent(const QModelIndex& index); + + private slots: + void forwardRowsAboutToInserted(const QModelIndex & parent, int first, int last); + + void forwardRowsInserted(const QModelIndex & parent, int first, int last); }; } diff --git a/apps/opencs/view/world/nestedtable.cpp b/apps/opencs/view/world/nestedtable.cpp index 2eef2e915..a185fc7ce 100644 --- a/apps/opencs/view/world/nestedtable.cpp +++ b/apps/opencs/view/world/nestedtable.cpp @@ -28,23 +28,25 @@ CSVWorld::NestedTable::NestedTable(QUndoStack& undoStack, { CSMWorld::ColumnBase::Display display = static_cast ( model->headerData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Display).toInt()); - + CommandDelegate *delegate = CommandDelegateFactoryCollection::get().makeDelegate(display, undoStack, this); - + setItemDelegateForColumn(i, delegate); } setModel(model); setAcceptDrops(true); - + mAddNewRowAction = new QAction (tr ("Add new row"), this); - connect(mAddNewRowAction, SIGNAL(triggered()), + + connect(mAddNewRowAction, SIGNAL(triggered()), this, SLOT(addNewRowActionTriggered())); - + mRemoveRowAction = new QAction (tr ("Remove row"), this); + connect(mRemoveRowAction, SIGNAL(triggered()), this, SLOT(removeRowActionTriggered())); } @@ -60,21 +62,21 @@ void CSVWorld::NestedTable::dragMoveEvent(QDragMoveEvent *event) void CSVWorld::NestedTable::contextMenuEvent (QContextMenuEvent *event) { QModelIndexList selectedRows = selectionModel()->selectedRows(); - + QMenu menu(this); if (selectionModel()->selectedRows().size() == 1) menu.addAction(mRemoveRowAction); menu.addAction(mAddNewRowAction); - + menu.exec (event->globalPos()); } void CSVWorld::NestedTable::removeRowActionTriggered() { - mUndoStack.push(new CSMWorld::DeleteNestedCommand(*(mModel->model()), - mModel->getParentId(), + mUndoStack.push(new CSMWorld::DeleteNestedCommand(*(mModel->model()), + mModel->getParentId(), selectionModel()->selectedRows().begin()->row(), mModel->getParentColumn())); } @@ -82,7 +84,7 @@ void CSVWorld::NestedTable::removeRowActionTriggered() void CSVWorld::NestedTable::addNewRowActionTriggered() { mUndoStack.push(new CSMWorld::AddNestedCommand(*(mModel->model()), - mModel->getParentId(), + mModel->getParentId(), selectionModel()->selectedRows().size(), mModel->getParentColumn())); } From bb675ff41d1a7a5f38d8a18d6f6d5fd188c9c074 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Wed, 2 Jul 2014 13:29:25 +0200 Subject: [PATCH 0041/3725] Removing rows and undo works --- apps/opencs/model/world/idtable.cpp | 11 ++++++---- apps/opencs/model/world/nestedtablemodel.cpp | 21 ++++++++++++++++++++ apps/opencs/model/world/nestedtablemodel.hpp | 4 ++++ 3 files changed, 32 insertions(+), 4 deletions(-) diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index f71c367f0..a74bd629b 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -125,18 +125,21 @@ Qt::ItemFlags CSMWorld::IdTable::flags (const QModelIndex & index) const bool CSMWorld::IdTable::removeRows (int row, int count, const QModelIndex& parent) { + beginRemoveRows (parent, row, row+count-1); + if (parent.isValid()) { for (int i = 0; i < count; ++i) { mIdCollection->removeNestedRows(parent.row(), parent.column(), row+i); } - return true; - } + } else + { - beginRemoveRows (parent, row, row+count-1); + beginRemoveRows (parent, row, row+count-1); - mIdCollection->removeRows (row, count); + mIdCollection->removeRows (row, count); + } endRemoveRows(); diff --git a/apps/opencs/model/world/nestedtablemodel.cpp b/apps/opencs/model/world/nestedtablemodel.cpp index 17bf7b30c..6d6618590 100644 --- a/apps/opencs/model/world/nestedtablemodel.cpp +++ b/apps/opencs/model/world/nestedtablemodel.cpp @@ -22,6 +22,11 @@ CSMWorld::NestedTableModel::NestedTableModel(const QModelIndex& parent, connect(mMainModel, SIGNAL(rowsInserted(const QModelIndex &, int, int)), this, SLOT(forwardRowsInserted(const QModelIndex &, int, int))); + connect(mMainModel, SIGNAL(rowsAboutToBeRemoved(const QModelIndex &, int, int)), + this, SLOT(forwardRowsAboutToRemoved(const QModelIndex &, int, int))); + + connect(mMainModel, SIGNAL(rowsRemoved(const QModelIndex &, int, int)), + this, SLOT(forwardRowsRemoved(const QModelIndex &, int, int))); } QModelIndex CSMWorld::NestedTableModel::mapFromSource(const QModelIndex& sourceIndex) const @@ -142,3 +147,19 @@ bool CSMWorld::NestedTableModel::indexIsParent(const QModelIndex& index) index.column() == mParentColumn && mMainModel->data(mMainModel->index(index.row(), 0)).toString().toUtf8().constData() == mId); } + +void CSMWorld::NestedTableModel::forwardRowsAboutToRemoved(const QModelIndex& parent, int first, int last) +{ + if (indexIsParent(parent)) + { + beginRemoveRows(QModelIndex(), first, last); + } +} + +void CSMWorld::NestedTableModel::forwardRowsRemoved(const QModelIndex& parent, int first, int last) +{ + if (indexIsParent(parent)) + { + endRemoveRows(); + } +} diff --git a/apps/opencs/model/world/nestedtablemodel.hpp b/apps/opencs/model/world/nestedtablemodel.hpp index 2263524cf..dfb231124 100644 --- a/apps/opencs/model/world/nestedtablemodel.hpp +++ b/apps/opencs/model/world/nestedtablemodel.hpp @@ -66,6 +66,10 @@ namespace CSMWorld void forwardRowsAboutToInserted(const QModelIndex & parent, int first, int last); void forwardRowsInserted(const QModelIndex & parent, int first, int last); + + void forwardRowsAboutToRemoved(const QModelIndex & parent, int first, int last); + + void forwardRowsRemoved(const QModelIndex & parent, int first, int last); }; } From 0bfc408ea2653c0d455f6239aa2cce21ea8b964c Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Wed, 2 Jul 2014 14:10:11 +0200 Subject: [PATCH 0042/3725] removed debug code --- apps/opencs/model/world/nestedtablemodel.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/apps/opencs/model/world/nestedtablemodel.cpp b/apps/opencs/model/world/nestedtablemodel.cpp index 6d6618590..cb7943f5e 100644 --- a/apps/opencs/model/world/nestedtablemodel.cpp +++ b/apps/opencs/model/world/nestedtablemodel.cpp @@ -2,7 +2,6 @@ #include #include "./idtable.hpp" -#include CSMWorld::NestedTableModel::NestedTableModel(const QModelIndex& parent, ColumnBase::Display columnId, @@ -140,9 +139,6 @@ void CSMWorld::NestedTableModel::forwardRowsInserted(const QModelIndex& parent, bool CSMWorld::NestedTableModel::indexIsParent(const QModelIndex& index) { - qDebug()<<"Testing for parenty"; - qDebug()<data(mMainModel->index(index.row(), 0)).toString().toUtf8().constData() == mId); From 851d2f061b45ce8f758cdb22242d34af8567f675 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Thu, 3 Jul 2014 11:14:51 +0200 Subject: [PATCH 0043/3725] Removed qdebug calls (forgot about those). --- apps/opencs/model/world/nestedtablemodel.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/opencs/model/world/nestedtablemodel.cpp b/apps/opencs/model/world/nestedtablemodel.cpp index cb7943f5e..d0648e5e9 100644 --- a/apps/opencs/model/world/nestedtablemodel.cpp +++ b/apps/opencs/model/world/nestedtablemodel.cpp @@ -123,7 +123,6 @@ void CSMWorld::NestedTableModel::forwardRowsAboutToInserted(const QModelIndex& p { if (indexIsParent(parent)) { - qDebug()<<"Adding new rows "<< first<<":"< Date: Mon, 7 Jul 2014 10:23:40 +0200 Subject: [PATCH 0044/3725] fixed segfault --- apps/opencs/view/world/dialoguesubview.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 122b173e6..673d3573f 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -353,6 +353,7 @@ void CSVWorld::EditWidget::remake(int row) { delete mNestedModels[i]; } + mNestedModels.clear(); if (mMainWidget) { From 3262f8d774ae3503944345c28c4caf0cea1553b4 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Mon, 7 Jul 2014 10:27:48 +0200 Subject: [PATCH 0045/3725] make dtor virtual --- apps/opencs/view/world/dialoguesubview.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/view/world/dialoguesubview.hpp b/apps/opencs/view/world/dialoguesubview.hpp index a6b944d7a..c1bc96211 100644 --- a/apps/opencs/view/world/dialoguesubview.hpp +++ b/apps/opencs/view/world/dialoguesubview.hpp @@ -177,7 +177,7 @@ namespace CSVWorld EditWidget (QWidget *parent, int row, CSMWorld::IdTable* table, QUndoStack& undoStack, bool createAndDelete = false); - ~EditWidget(); + virtual ~EditWidget(); void remake(int row); From d221486a140cd81233b8f1f5b7897b59bd7bcc90 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Mon, 7 Jul 2014 12:07:29 +0200 Subject: [PATCH 0046/3725] Fixed problem in the idtable. --- apps/opencs/model/world/idtable.cpp | 38 +++++++++++++++++--------- apps/opencs/view/world/nestedtable.cpp | 3 +- 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index a74bd629b..c2eb32fa5 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -1,4 +1,5 @@ #include "idtable.hpp" +#include #include @@ -93,23 +94,34 @@ QVariant CSMWorld::IdTable::nestedHeaderData(int section, int subSection, Qt::Or bool CSMWorld::IdTable::setData (const QModelIndex &index, const QVariant &value, int role) { - if (mIdCollection->getColumn (index.column()).isEditable() && role==Qt::EditRole) + if (index.internalId() != 0) { - if (index.internalId() == 0) - { - mIdCollection->setData (index.row(), index.column(), value); - - emit dataChanged (CSMWorld::IdTable::index (index.row(), 0), - CSMWorld::IdTable::index (index.row(), mIdCollection->getColumns()-1)); - } else + if (mIdCollection->getColumn(parent(index).column()).isEditable() && role==Qt::EditRole) { const std::pair& parentAdress(unfoldIndexAdress(index.internalId())); mIdCollection->setNestedData(parentAdress.first, parentAdress.second, value, index.row(), index.column()); + + emit dataChanged (CSMWorld::IdTable::index (parentAdress.first, 0), + CSMWorld::IdTable::index (parentAdress.second, mIdCollection->getColumns()-1)); + + return true; + } else + { + return false; } - return true; } - + + if (mIdCollection->getColumn (index.column()).isEditable() && role==Qt::EditRole) + { + mIdCollection->setData (index.row(), index.column(), value); + + emit dataChanged (CSMWorld::IdTable::index (index.row(), 0), + CSMWorld::IdTable::index (index.row(), mIdCollection->getColumns()-1)); + + return true; + } + return false; } @@ -131,9 +143,9 @@ bool CSMWorld::IdTable::removeRows (int row, int count, const QModelIndex& paren { for (int i = 0; i < count; ++i) { - mIdCollection->removeNestedRows(parent.row(), parent.column(), row+i); + mIdCollection->removeNestedRows(parent.row(), parent.column(), row+i); } - } else + } else { beginRemoveRows (parent, row, row+count-1); @@ -157,7 +169,7 @@ void CSMWorld::IdTable::addNestedRow(const QModelIndex& parent, int position) emit dataChanged (CSMWorld::IdTable::index (row, 0), CSMWorld::IdTable::index (row, mIdCollection->getColumns()-1)); - + endInsertRows(); } diff --git a/apps/opencs/view/world/nestedtable.cpp b/apps/opencs/view/world/nestedtable.cpp index a185fc7ce..21bef504b 100644 --- a/apps/opencs/view/world/nestedtable.cpp +++ b/apps/opencs/view/world/nestedtable.cpp @@ -7,6 +7,7 @@ #include #include #include +#include CSVWorld::NestedTable::NestedTable(QUndoStack& undoStack, CSMWorld::NestedTableModel* model, @@ -32,7 +33,7 @@ CSVWorld::NestedTable::NestedTable(QUndoStack& undoStack, CommandDelegate *delegate = CommandDelegateFactoryCollection::get().makeDelegate(display, undoStack, this); - + setItemDelegateForColumn(i, delegate); } From 72392ad68c025ea634fcfc2ec280e9611969e0b4 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Mon, 7 Jul 2014 12:22:04 +0200 Subject: [PATCH 0047/3725] emit data changed signal when adding and removing the nested row --- apps/opencs/model/world/idtable.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index c2eb32fa5..0b5f9c5a3 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -155,6 +155,9 @@ bool CSMWorld::IdTable::removeRows (int row, int count, const QModelIndex& paren endRemoveRows(); + emit dataChanged (CSMWorld::IdTable::index (parent.row(), 0), + CSMWorld::IdTable::index (parent.row(), mIdCollection->getColumns()-1)); + return true; } @@ -167,10 +170,10 @@ void CSMWorld::IdTable::addNestedRow(const QModelIndex& parent, int position) beginInsertRows(parent, position, position); mIdCollection->addNestedRow(row, parent.column(), position); + endInsertRows(); + emit dataChanged (CSMWorld::IdTable::index (row, 0), CSMWorld::IdTable::index (row, mIdCollection->getColumns()-1)); - - endInsertRows(); } QModelIndex CSMWorld::IdTable::index (int row, int column, const QModelIndex& parent) const From 0252d021eba082f6f30736248520b17ca20b7ffc Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Sun, 13 Jul 2014 12:37:05 +0200 Subject: [PATCH 0048/3725] removed pointless member field --- apps/opencs/model/world/columnbase.hpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index 3f9e7e1a3..bf03ab563 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -93,6 +93,7 @@ namespace CSMWorld //Those are top level columns that nest other columns Display_NestedItemList, + Display_EnchantmentType, Display_BodyPartType, Display_MeshType, @@ -138,8 +139,6 @@ namespace CSMWorld template struct Column : public ColumnBase { - int mFlags; - Column (int columnId, Display displayType, int flags = Flag_Table | Flag_Dialogue, bool canNest = false) : ColumnBase (columnId, displayType, flags, canNest) {} From f0c6ef185eb8f2735e17470d836c5475c9388544 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Wed, 16 Jul 2014 13:13:22 +0200 Subject: [PATCH 0049/3725] Nest columns directly, created NestedColumn class and NestColumn. --- apps/opencs/model/world/columnbase.cpp | 40 +++++++++++++-------- apps/opencs/model/world/columnbase.hpp | 37 ++++++++++++++----- apps/opencs/model/world/idtable.cpp | 8 ++--- apps/opencs/model/world/refidadapterimp.cpp | 7 ++-- apps/opencs/model/world/refidcollection.cpp | 8 ++--- apps/opencs/model/world/refidcollection.hpp | 2 +- 6 files changed, 66 insertions(+), 36 deletions(-) diff --git a/apps/opencs/model/world/columnbase.cpp b/apps/opencs/model/world/columnbase.cpp index 59ee39126..60e201ba4 100644 --- a/apps/opencs/model/world/columnbase.cpp +++ b/apps/opencs/model/world/columnbase.cpp @@ -2,8 +2,6 @@ #include "columns.hpp" -#include - CSMWorld::ColumnBase::ColumnBase (int columnId, Display displayType, int flags, bool canNest) : mColumnId (columnId), mDisplayType (displayType), mFlags (flags), mCanNest(canNest) {} @@ -25,28 +23,42 @@ int CSMWorld::ColumnBase::getId() const return mColumnId; } -bool CSMWorld::ColumnBase::canHaveNestedColumns() const +bool CSMWorld::NestColumn::canHaveNestedColumns() const { return mCanNest; } -std::string CSMWorld::ColumnBase::getNestedColumnTitle(int columnNumber) const +void CSMWorld::NestColumn::addNestedColumn(int columnId, Display displayType) { - assert (mCanNest); - - return Columns::getName(static_cast(mNestedColumnId[columnNumber])); + if (!mCanNest) + throw std::logic_error("Tried to nest inside of the non-nest column"); + + mNestedColumns.push_back(CSMWorld::NestedColumn(columnId, displayType, mFlags, this)); } -void CSMWorld::ColumnBase::addNestedColumnDisplay(CSMWorld::ColumnBase::Display displayDefinition) +const CSMWorld::ColumnBase& CSMWorld::NestColumn::nestedColumn(int subColumn) const { - assert (mCanNest); - - mNestedDisplayType.push_back(displayDefinition); + if (!mCanNest) + throw std::logic_error("Tried to access nested column of the non-nest column"); + + return mNestedColumns.at(subColumn); } -void CSMWorld::ColumnBase::addNestedColumnId(int columnId) +int CSMWorld::NestColumn::nestedColumnCount() const { - assert (mCanNest); + if (!mCanNest) + throw std::logic_error("Tried to access number of the subcolumns in the non-nest column"); + + return mNestedColumns.size(); +} - mNestedColumnId.push_back(columnId); +CSMWorld::NestColumn::NestColumn(int columnId, Display displayType, int flags, bool canNest) + : CSMWorld::ColumnBase(columnId, displayType, flags, canNest) {} + +CSMWorld::NestedColumn::NestedColumn(int columnId, Display displayType, int flag, const CSMWorld::NestColumn* parent) + : mParent(parent), CSMWorld::ColumnBase(columnId, displayType, flag) {} + +bool CSMWorld::NestedColumn::isEditable() const +{ + return mParent->isEditable(); } diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index bf03ab563..096491f1e 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -110,9 +111,7 @@ namespace CSMWorld int mColumnId; int mFlags; Display mDisplayType; - std::vector mNestedDisplayType; //used only for the columns that actually nest other columns - std::vector mNestedColumnId; //used only for the columns that actually nest other columns - const bool mCanNest; + bool mCanNest; ColumnBase (int columnId, Display displayType, int flag, bool canNest = false); @@ -125,22 +124,42 @@ namespace CSMWorld virtual std::string getTitle() const; - std::string getNestedColumnTitle(int columnNumber) const; + virtual int getId() const; + }; - void addNestedColumnDisplay(Display displayDefinition); + class NestedColumn; - void addNestedColumnId(int columnId); + class NestColumn : public ColumnBase + { + std::vector mNestedColumns; - virtual int getId() const; + public: + NestColumn(int columnId, Display displayType, int flags, bool canNest); + + void addNestedColumn(int columnId, Display displayType); bool canHaveNestedColumns() const; + + const ColumnBase& nestedColumn(int subColumn) const; + + int nestedColumnCount() const; }; + class NestedColumn : public ColumnBase + { + const ColumnBase* mParent; + + public: + NestedColumn(int columnId, Display displayType, int flag, const NestColumn* parent); + + virtual bool isEditable() const; + }; + template - struct Column : public ColumnBase + struct Column : public NestColumn { Column (int columnId, Display displayType, int flags = Flag_Table | Flag_Dialogue, bool canNest = false) - : ColumnBase (columnId, displayType, flags, canNest) {} + : NestColumn (columnId, displayType, canNest, flags) {} virtual QVariant get (const Record& record) const = 0; diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 00cfbd145..a3435180c 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -75,19 +75,19 @@ QVariant CSMWorld::IdTable::headerData (int section, QVariant CSMWorld::IdTable::nestedHeaderData(int section, int subSection, Qt::Orientation orientation, int role) const { - assert(mIdCollection->getColumn(section).canHaveNestedColumns()); + const NestColumn& parentColumn = dynamic_cast(mIdCollection->getColumn(section)); if (orientation==Qt::Vertical) return QVariant(); if (role==Qt::DisplayRole) - return tr (mIdCollection->getColumn(section).getNestedColumnTitle(subSection).c_str()); + return tr(parentColumn.nestedColumn(subSection).getTitle().c_str()); if (role==ColumnBase::Role_Flags) return mIdCollection->getColumn (section).mFlags; if (role==ColumnBase::Role_Display) - return mIdCollection->getColumn (section).mNestedDisplayType.at(subSection); + return parentColumn.nestedColumn(subSection).mDisplayType; return QVariant(); } @@ -354,6 +354,6 @@ bool CSMWorld::IdTable::hasChildren(const QModelIndex& index) const { return (index.isValid() && index.internalId() == 0 && - mIdCollection->getColumn (index.column()).canHaveNestedColumns() && + mIdCollection->getColumn(index.column()).mCanNest && index.data().isValid()); } diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index 7033140ca..8d6ab838d 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -1,6 +1,7 @@ #include "refidadapterimp.hpp" #include +#include CSMWorld::PotionRefIdAdapter::PotionRefIdAdapter (const InventoryColumns& columns, const RefIdColumn *autoCalc) @@ -296,7 +297,7 @@ void CSMWorld::ContainerRefIdAdapter::setNestedData(const RefIdColumn *column, break; default: - throw "Trying to access non-existing column in the nested table!"; + throw std::logic_error("Trying to access non-existing column in the nested table!"); } } else { @@ -326,11 +327,11 @@ QVariant CSMWorld::ContainerRefIdAdapter::getNestedData (const CSMWorld::RefIdCo return content.mCount; default: - throw "Trying to access non-existing column in the nested table!"; + throw std::logic_error("Trying to access non-existing column in the nested table!"); } } else { - throw "This column does not hold multiple values."; + throw std::logic_error("This column does not hold multiple values."); } } diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 7aa1d7753..62daef903 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -13,7 +13,7 @@ CSMWorld::RefIdColumn::RefIdColumn (int columnId, Display displayType, int flag, bool editable, bool userEditable, bool canNest) - : ColumnBase (columnId, displayType, flag, canNest), mEditable (editable), mUserEditable (userEditable) + : NestColumn (columnId, displayType, flag, canNest), mEditable (editable), mUserEditable (userEditable) {} bool CSMWorld::RefIdColumn::isEditable() const @@ -168,10 +168,8 @@ CSMWorld::RefIdCollection::RefIdCollection() mColumns.push_back(RefIdColumn (Columns::ColumnId_ContainerContent, ColumnBase::Display_NestedItemList, ColumnBase::Flag_Dialogue, true, true, true)); const RefIdColumn *content = &mColumns.back(); - (&mColumns.back())->addNestedColumnDisplay(CSMWorld::ColumnBase::Display_String); - (&mColumns.back())->addNestedColumnDisplay(CSMWorld::ColumnBase::Display_Integer); - (&mColumns.back())->addNestedColumnId(Columns::ColumnId_InventoryItemId); - (&mColumns.back())->addNestedColumnId(Columns::ColumnId_ItemCount); + (&mColumns.back())->addNestedColumn(Columns::ColumnId_InventoryItemId, CSMWorld::ColumnBase::Display_String); + (&mColumns.back())->addNestedColumn(Columns::ColumnId_ItemCount, CSMWorld::ColumnBase::Display_Integer); CreatureColumns creatureColumns (actorsColumns); diff --git a/apps/opencs/model/world/refidcollection.hpp b/apps/opencs/model/world/refidcollection.hpp index 7801811ff..d1bb197e8 100644 --- a/apps/opencs/model/world/refidcollection.hpp +++ b/apps/opencs/model/world/refidcollection.hpp @@ -18,7 +18,7 @@ namespace CSMWorld { class RefIdAdapter; - class RefIdColumn : public ColumnBase + class RefIdColumn : public NestColumn { bool mEditable; bool mUserEditable; From ca73ce3fe23e94fbc9d1fdceb957c9d9c756f94e Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Thu, 17 Jul 2014 12:41:43 +0200 Subject: [PATCH 0050/3725] trying to fix indending --- apps/opencs/model/world/refidcollection.hpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/apps/opencs/model/world/refidcollection.hpp b/apps/opencs/model/world/refidcollection.hpp index d1bb197e8..02b77400b 100644 --- a/apps/opencs/model/world/refidcollection.hpp +++ b/apps/opencs/model/world/refidcollection.hpp @@ -18,7 +18,7 @@ namespace CSMWorld { class RefIdAdapter; - class RefIdColumn : public NestColumn + class RefIdColumn : public NestColumn { bool mEditable; bool mUserEditable; @@ -76,11 +76,11 @@ namespace CSMWorld virtual void setNestedData(int row, int column, const QVariant& data, int subRow, int subColumn); virtual void removeRows (int index, int count); - + virtual void removeNestedRows(int row, int column, int subRow); virtual void addNestedRow(int row, int col, int position); - + virtual void cloneRecord(const std::string& origin, const std::string& destination, const UniversalId::Type type); @@ -124,9 +124,8 @@ namespace CSMWorld void save (int index, ESM::ESMWriter& writer) const; - const RefIdData& getDataSet() const; //I can't figure out a better name for this one :( + const RefIdData& getDataSet() const; //I can't figure out a better name for this one :( }; } #endif - From 6e07568b43fea79c1b3acffb07f4b9aa30d1c35c Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Thu, 17 Jul 2014 12:56:51 +0200 Subject: [PATCH 0051/3725] Corrected syntax. --- apps/opencs/model/world/refidcollection.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 62daef903..1a164d12f 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -168,8 +168,8 @@ CSMWorld::RefIdCollection::RefIdCollection() mColumns.push_back(RefIdColumn (Columns::ColumnId_ContainerContent, ColumnBase::Display_NestedItemList, ColumnBase::Flag_Dialogue, true, true, true)); const RefIdColumn *content = &mColumns.back(); - (&mColumns.back())->addNestedColumn(Columns::ColumnId_InventoryItemId, CSMWorld::ColumnBase::Display_String); - (&mColumns.back())->addNestedColumn(Columns::ColumnId_ItemCount, CSMWorld::ColumnBase::Display_Integer); + mColumns.back().addNestedColumn(Columns::ColumnId_InventoryItemId, CSMWorld::ColumnBase::Display_String); + mColumns.back().addNestedColumn(Columns::ColumnId_ItemCount, CSMWorld::ColumnBase::Display_Integer); CreatureColumns creatureColumns (actorsColumns); From 5671a4b8e2b55f48b11fdc4c2a221bb0883a1cdb Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Thu, 17 Jul 2014 12:58:14 +0200 Subject: [PATCH 0052/3725] corrected include to follow our standards. --- apps/opencs/model/world/nestedtablemodel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/world/nestedtablemodel.cpp b/apps/opencs/model/world/nestedtablemodel.cpp index d0648e5e9..f0b510244 100644 --- a/apps/opencs/model/world/nestedtablemodel.cpp +++ b/apps/opencs/model/world/nestedtablemodel.cpp @@ -1,7 +1,7 @@ #include "nestedtablemodel.hpp" #include -#include "./idtable.hpp" +#include "idtable.hpp" CSMWorld::NestedTableModel::NestedTableModel(const QModelIndex& parent, ColumnBase::Display columnId, From 16292bf23ee73dd1f32332d4af0af1d2ae6d9a03 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Thu, 17 Jul 2014 13:03:53 +0200 Subject: [PATCH 0053/3725] removed useless todo statments. --- apps/opencs/model/world/collection.hpp | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/apps/opencs/model/world/collection.hpp b/apps/opencs/model/world/collection.hpp index 3b39dc6f9..904587eaf 100644 --- a/apps/opencs/model/world/collection.hpp +++ b/apps/opencs/model/world/collection.hpp @@ -73,10 +73,10 @@ namespace CSMWorld ///< Add a new record (modified) virtual int getSize() const; - - virtual int getNestedColumnsCount(int column) const; - virtual int getNestedRowsCount(int row, int column) const; + virtual int getNestedColumnsCount(int column) const; + + virtual int getNestedRowsCount(int row, int column) const; virtual std::string getId (int index) const; @@ -253,19 +253,17 @@ namespace CSMWorld { return mRecords.size(); } - + template int Collection::getNestedRowsCount(int row, int column) const { - //TODO - return 0; + return 0; } template int Collection::getNestedColumnsCount(int column) const { - //TODO - return 0; + return 0; } template @@ -300,7 +298,7 @@ namespace CSMWorld template QVariant Collection::getNestedData(int row, int column, int subRow, int subColumn) const { - return 10; //TODO + return QVariant(); } template From 1ff8abb240e4f235e8d66af9c169cc92735e0c21 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Fri, 18 Jul 2014 18:26:22 +0200 Subject: [PATCH 0054/3725] store whole container representing the nested table inside of the command Static nature of C++ forced me to use templates. Bit frustraiting. --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/world/collection.hpp | 18 ++++++++++ apps/opencs/model/world/collectionbase.hpp | 11 ++++-- apps/opencs/model/world/commands.cpp | 36 ++++--------------- apps/opencs/model/world/commands.hpp | 6 +++- apps/opencs/model/world/idtable.cpp | 21 +++++++++++ apps/opencs/model/world/idtable.hpp | 5 +++ .../opencs/model/world/nestedtablewrapper.cpp | 7 ++++ .../opencs/model/world/nestedtablewrapper.hpp | 33 +++++++++++++++++ apps/opencs/model/world/refidadapter.hpp | 9 +++-- apps/opencs/model/world/refidadapterimp.cpp | 23 ++++++++++++ apps/opencs/model/world/refidadapterimp.hpp | 6 ++++ apps/opencs/model/world/refidcollection.cpp | 21 ++++++++++- apps/opencs/model/world/refidcollection.hpp | 7 +++- 14 files changed, 167 insertions(+), 38 deletions(-) create mode 100644 apps/opencs/model/world/nestedtablewrapper.cpp create mode 100644 apps/opencs/model/world/nestedtablewrapper.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 3871a4d5a..bcc64b60a 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -19,7 +19,7 @@ opencs_hdrs_noqt (model/doc opencs_units (model/world idtable idtableproxymodel regionmap data commanddispatcher - idtablebase resourcetable nestedtablemodel + idtablebase resourcetable nestedtablemodel nestedtablewrapper ) diff --git a/apps/opencs/model/world/collection.hpp b/apps/opencs/model/world/collection.hpp index 904587eaf..ac4351986 100644 --- a/apps/opencs/model/world/collection.hpp +++ b/apps/opencs/model/world/collection.hpp @@ -16,6 +16,8 @@ #include "collectionbase.hpp" +#include "nestedtablewrapper.hpp" + namespace CSMWorld { /// \brief Access to ID field in records @@ -90,6 +92,10 @@ namespace CSMWorld virtual void setData (int index, int column, const QVariant& data); + virtual NestedTableWrapperBase nestedTable(int row, int column) const; + + virtual void setNestedTable(int row, int column, const NestedTableWrapperBase& nestedTable); + virtual const ColumnBase& getColumn (int column) const; virtual void merge(); @@ -300,6 +306,18 @@ namespace CSMWorld { return QVariant(); } + + template + NestedTableWrapperBase Collection::nestedTable(int row, int column) const + { + return NestedTableWrapperBase(); + } + + template + void Collection::setNestedTable(int row, int column, const NestedTableWrapperBase& nestedTable) + { + throw std::logic_error("setNestedTable was not overriden"); + } template void Collection::setData (int index, int column, const QVariant& data) diff --git a/apps/opencs/model/world/collectionbase.hpp b/apps/opencs/model/world/collectionbase.hpp index aad40d36b..62f4079fc 100644 --- a/apps/opencs/model/world/collectionbase.hpp +++ b/apps/opencs/model/world/collectionbase.hpp @@ -13,6 +13,7 @@ namespace CSMWorld { struct ColumnBase; struct RecordBase; + class NestedTableWrapperBase; /// \brief Base class for record collections /// @@ -33,10 +34,10 @@ namespace CSMWorld virtual ~CollectionBase(); virtual int getSize() const = 0; - - virtual int getNestedRowsCount(int row, int column) const; - virtual int getNestedColumnsCount(int row, int column) const; + virtual int getNestedRowsCount(int row, int column) const; + + virtual int getNestedColumnsCount(int row, int column) const; virtual std::string getId (int index) const = 0; @@ -50,6 +51,10 @@ namespace CSMWorld virtual QVariant getNestedData(int row, int column, int subRow, int subColumn) const = 0; + virtual NestedTableWrapperBase nestedTable(int row, int column) const = 0; + + virtual void setNestedTable(int row, int column, const NestedTableWrapperBase& nestedTable) = 0; + virtual void setData (int index, int column, const QVariant& data) = 0; virtual void setNestedData(int row, int column, const QVariant& data, int subRow, int subColumn); diff --git a/apps/opencs/model/world/commands.cpp b/apps/opencs/model/world/commands.cpp index 012736697..5e886bdb4 100644 --- a/apps/opencs/model/world/commands.cpp +++ b/apps/opencs/model/world/commands.cpp @@ -177,26 +177,10 @@ CSMWorld::DeleteNestedCommand::DeleteNestedCommand (IdTable& model, const std::s mModel(model), mParentColumn(parentColumn), QUndoCommand(parent), - mNestedRow(nestedRow) + mNestedRow(nestedRow), + mOld(model.nestedTable(model.getModelIndex(id, parentColumn))) { setText (("Delete nested row in " + mId).c_str()); - - const QModelIndex& parentIndex = mModel.getModelIndex(mId, mParentColumn); - - const int columnsCount = mModel.columnCount(parentIndex); - - for (int i = 0; i < columnsCount; ++i) - { - const QModelIndex& childIndex = mModel.index(nestedRow, i, parentIndex); - - QVariant data = childIndex.data(); - if (!data.isValid()) - { - data = childIndex.data(Qt::DisplayRole); - } - - mOld.push_back(data); - } } void CSMWorld::DeleteNestedCommand::redo() @@ -211,14 +195,7 @@ void CSMWorld::DeleteNestedCommand::undo() { const QModelIndex& parentIndex = mModel.getModelIndex(mId, mParentColumn); - mModel.addNestedRow(parentIndex, mNestedRow); - - for (int i = 0; i < mModel.columnCount(parentIndex); ++i) - { - const QModelIndex& current = mModel.index(mNestedRow, i, parentIndex); - - mModel.setData(current, mOld[i]); - } + mModel.setNestedTable(parentIndex, mOld); } CSMWorld::AddNestedCommand::AddNestedCommand(IdTable& model, const std::string& id, int nestedRow, int parentColumn, QUndoCommand* parent) @@ -226,7 +203,8 @@ CSMWorld::AddNestedCommand::AddNestedCommand(IdTable& model, const std::string& mId(id), mNewRow(nestedRow), mParentColumn(parentColumn), - QUndoCommand(parent) + QUndoCommand(parent), + mOld(model.nestedTable(model.getModelIndex(id, parentColumn))) { setText (("Added nested row in " + mId).c_str()); } @@ -241,6 +219,6 @@ void CSMWorld::AddNestedCommand::redo() void CSMWorld::AddNestedCommand::undo() { const QModelIndex& parentIndex = mModel.getModelIndex(mId, mParentColumn); - - mModel.removeRows(mNewRow, 1, parentIndex); + + mModel.setNestedTable(parentIndex, mOld); } diff --git a/apps/opencs/model/world/commands.hpp b/apps/opencs/model/world/commands.hpp index e6f2d9724..214a5157e 100644 --- a/apps/opencs/model/world/commands.hpp +++ b/apps/opencs/model/world/commands.hpp @@ -13,6 +13,7 @@ #include #include "universalid.hpp" +#include "nestedtablewrapper.hpp" class QModelIndex; class QAbstractItemModel; @@ -22,6 +23,7 @@ namespace CSMWorld class IdTable; class IdTable; class RecordBase; + class NestedTableWrapperBase; class ModifyCommand : public QUndoCommand { @@ -143,7 +145,7 @@ namespace CSMWorld std::string mId; - std::vector mOld; + NestedTableWrapperBase mOld; int mParentColumn; @@ -164,6 +166,8 @@ namespace CSMWorld std::string mId; + NestedTableWrapperBase mOld; + int mNewRow; int mParentColumn; diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index a3435180c..df0f4546d 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -2,6 +2,7 @@ #include #include +#include "nestedtablewrapper.hpp" #include "collectionbase.hpp" #include "columnbase.hpp" @@ -357,3 +358,23 @@ bool CSMWorld::IdTable::hasChildren(const QModelIndex& index) const mIdCollection->getColumn(index.column()).mCanNest && index.data().isValid()); } + +void CSMWorld::IdTable::setNestedTable(const QModelIndex& index, const CSMWorld::NestedTableWrapperBase& nestedTable) +{ + if (!hasChildren(index)) + { + throw std::logic_error("Tried to set nested table, but index has no children"); + } + + mIdCollection->setNestedTable(index.row(), index.column(), nestedTable); +} + +CSMWorld::NestedTableWrapperBase CSMWorld::IdTable::nestedTable(const QModelIndex& index) const +{ + if (!hasChildren(index)) + { + throw std::logic_error("Tried to retrive nested table, but index has no children"); + } + + return mIdCollection->nestedTable(index.row(), index.column()); +} diff --git a/apps/opencs/model/world/idtable.hpp b/apps/opencs/model/world/idtable.hpp index fcb87c8b2..fd3f699ba 100644 --- a/apps/opencs/model/world/idtable.hpp +++ b/apps/opencs/model/world/idtable.hpp @@ -20,6 +20,7 @@ namespace CSMWorld { class CollectionBase; class RecordBase; + class NestedTableWrapperBase; class IdTable : public IdTableBase { @@ -51,6 +52,10 @@ namespace CSMWorld virtual QVariant headerData (int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; QVariant nestedHeaderData(int section, int subSection, Qt::Orientation orientation, int role = Qt::DisplayRole) const; + + NestedTableWrapperBase nestedTable(const QModelIndex &index) const; + + void setNestedTable(const QModelIndex &index, const NestedTableWrapperBase& nestedTable); virtual bool setData ( const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); diff --git a/apps/opencs/model/world/nestedtablewrapper.cpp b/apps/opencs/model/world/nestedtablewrapper.cpp new file mode 100644 index 000000000..387bc6e7b --- /dev/null +++ b/apps/opencs/model/world/nestedtablewrapper.cpp @@ -0,0 +1,7 @@ +#include "nestedtablewrapper.hpp" + +CSMWorld::NestedTableWrapperBase::NestedTableWrapperBase() +{} + +CSMWorld::NestedTableWrapperBase::~NestedTableWrapperBase() +{} diff --git a/apps/opencs/model/world/nestedtablewrapper.hpp b/apps/opencs/model/world/nestedtablewrapper.hpp new file mode 100644 index 000000000..9fc21f8e0 --- /dev/null +++ b/apps/opencs/model/world/nestedtablewrapper.hpp @@ -0,0 +1,33 @@ +#ifndef CSM_WOLRD_NESTEDTABLEWRAPPER_H +#define CSM_WOLRD_NESTEDTABLEWRAPPER_H + +#include + +#include +namespace CSMWorld +{ + struct NestedTableWrapperBase + { + virtual ~NestedTableWrapperBase(); + + NestedTableWrapperBase(); + }; + + template + class NestedTableWrapper : public NestedTableWrapperBase + { + NestedTable mNestedTable; + + public: + + NestedTableWrapper(const NestedTable& nestedTable) {} + + NestedTable getNestedTable() const + { + return mNestedTable; + } + + virtual ~NestedTableWrapper() {} + }; +} +#endif diff --git a/apps/opencs/model/world/refidadapter.hpp b/apps/opencs/model/world/refidadapter.hpp index 068347fda..f4aa769fd 100644 --- a/apps/opencs/model/world/refidadapter.hpp +++ b/apps/opencs/model/world/refidadapter.hpp @@ -10,6 +10,7 @@ namespace CSMWorld class RefIdColumn; class RefIdData; class RecordBase; + class NestedTableWrapperBase; class RefIdAdapter { @@ -41,7 +42,7 @@ namespace CSMWorld NestedRefIdAdapter(); virtual ~NestedRefIdAdapter(); - + virtual void setNestedData (const RefIdColumn *column, RefIdData& data, int row, const QVariant& value, int subRowIndex, int subColIndex) const = 0; @@ -53,8 +54,12 @@ namespace CSMWorld virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const = 0; virtual void removeNestedRow (const RefIdColumn *column, RefIdData& data, int index, int rowToRemove) const = 0; - + virtual void addNestedRow (const RefIdColumn *column, RefIdData& data, int index, int position) const = 0; + + virtual void setNestedTable (const RefIdColumn* column, RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) = 0; + + virtual NestedTableWrapperBase nestedTable (const RefIdColumn * column, const RefIdData& data, int index) const = 0; }; } diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index 8d6ab838d..cb078ab74 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -1,7 +1,9 @@ #include "refidadapterimp.hpp" +#include "nestedtablewrapper.hpp" #include #include +#include CSMWorld::PotionRefIdAdapter::PotionRefIdAdapter (const InventoryColumns& columns, const RefIdColumn *autoCalc) @@ -305,6 +307,27 @@ void CSMWorld::ContainerRefIdAdapter::setNestedData(const RefIdColumn *column, } } +void CSMWorld::ContainerRefIdAdapter::setNestedTable(const RefIdColumn* column, + RefIdData& data, + int index, + const NestedTableWrapperBase& nestedTable) +{ + Record& record = dynamic_cast&> ( + data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Container))); + + record.get().mInventory.mList = dynamic_cast >&>(nestedTable).getNestedTable(); +} + +CSMWorld::NestedTableWrapperBase CSMWorld::ContainerRefIdAdapter::nestedTable (const RefIdColumn* column, + const RefIdData& data, + int index) const +{ + const Record& record = dynamic_cast&> ( + data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Container))); + + return NestedTableWrapper >(record.get().mInventory.mList); +} + QVariant CSMWorld::ContainerRefIdAdapter::getNestedData (const CSMWorld::RefIdColumn* column, const CSMWorld::RefIdData& data, int index, diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index 500b18ef8..4198fb367 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -15,6 +15,8 @@ namespace CSMWorld { + class NestedTableWrapperBase; + struct BaseColumns { const RefIdColumn *mId; @@ -637,6 +639,10 @@ namespace CSMWorld virtual void removeNestedRow (const RefIdColumn *column, RefIdData& data, int index, int rowToRemove) const; virtual void addNestedRow (const RefIdColumn *column, RefIdData& data, int index, int position) const; + + virtual NestedTableWrapperBase nestedTable (const RefIdColumn * column, const RefIdData& data, int index) const; + + virtual void setNestedTable (const RefIdColumn* column, RefIdData& data, int index, const NestedTableWrapperBase& nestedTable); }; struct CreatureColumns : public ActorColumns diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 1a164d12f..6ff0df802 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -10,6 +10,7 @@ #include "refidadapter.hpp" #include "refidadapterimp.hpp" #include "columns.hpp" +#include "nestedtablewrapper.hpp" CSMWorld::RefIdColumn::RefIdColumn (int columnId, Display displayType, int flag, bool editable, bool userEditable, bool canNest) @@ -27,7 +28,7 @@ bool CSMWorld::RefIdColumn::isUserEditable() const } -const CSMWorld::RefIdAdapter& CSMWorld::RefIdCollection::findAdaptor (UniversalId::Type type) const +CSMWorld::RefIdAdapter& CSMWorld::RefIdCollection::findAdaptor (UniversalId::Type type) const { std::map::const_iterator iter = mAdapters.find (type); @@ -641,3 +642,21 @@ void CSMWorld::RefIdCollection::addNestedRow(int row, int col, int position) adaptor.addNestedRow(&mColumns.at(col), mData, localIndex.first, position); } + +void CSMWorld::RefIdCollection::setNestedTable(int row, int column, const CSMWorld::NestedTableWrapperBase& nestedTable) +{ + RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); + + CSMWorld::NestedRefIdAdapter& adaptor = dynamic_cast(findAdaptor (localIndex.second)); + + adaptor.setNestedTable(&mColumns.at(column), mData, localIndex.first, nestedTable); +} + +CSMWorld::NestedTableWrapperBase CSMWorld::RefIdCollection::nestedTable(int row, int column) const +{ + RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); + + const CSMWorld::NestedRefIdAdapter& adaptor = dynamic_cast(findAdaptor (localIndex.second)); + + return adaptor.nestedTable(&mColumns.at(column), mData, localIndex.first); +} diff --git a/apps/opencs/model/world/refidcollection.hpp b/apps/opencs/model/world/refidcollection.hpp index 02b77400b..927331c93 100644 --- a/apps/opencs/model/world/refidcollection.hpp +++ b/apps/opencs/model/world/refidcollection.hpp @@ -17,6 +17,7 @@ namespace ESM namespace CSMWorld { class RefIdAdapter; + class NestedTableWrapperBase; class RefIdColumn : public NestColumn { @@ -44,7 +45,7 @@ namespace CSMWorld private: - const RefIdAdapter& findAdaptor (UniversalId::Type) const; + RefIdAdapter& findAdaptor (UniversalId::Type) const; ///< Throws an exception if no adaptor for \a Type can be found. public: @@ -70,6 +71,10 @@ namespace CSMWorld virtual QVariant getData (int index, int column) const; virtual QVariant getNestedData(int row, int column, int subRow, int subColumn) const; + + virtual NestedTableWrapperBase nestedTable(int row, int column) const; + + virtual void setNestedTable(int row, int column, const NestedTableWrapperBase& nestedTable); virtual void setData (int index, int column, const QVariant& data); From 0017fc68ef719135cdf82060fbf19e1df4582377 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Sat, 19 Jul 2014 13:08:28 +0200 Subject: [PATCH 0055/3725] fixed ctor of nestedwrapper (missing initialization of member data field) --- apps/opencs/model/world/nestedtablewrapper.hpp | 3 ++- apps/opencs/model/world/refidadapterimp.cpp | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/world/nestedtablewrapper.hpp b/apps/opencs/model/world/nestedtablewrapper.hpp index 9fc21f8e0..c13a12c62 100644 --- a/apps/opencs/model/world/nestedtablewrapper.hpp +++ b/apps/opencs/model/world/nestedtablewrapper.hpp @@ -20,7 +20,8 @@ namespace CSMWorld public: - NestedTableWrapper(const NestedTable& nestedTable) {} + NestedTableWrapper(const NestedTable& nestedTable) + : mNestedTable(nestedTable) {} NestedTable getNestedTable() const { diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index cb078ab74..d669a369c 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -1,9 +1,10 @@ #include "refidadapterimp.hpp" -#include "nestedtablewrapper.hpp" #include #include + #include +#include "nestedtablewrapper.hpp" CSMWorld::PotionRefIdAdapter::PotionRefIdAdapter (const InventoryColumns& columns, const RefIdColumn *autoCalc) @@ -315,7 +316,7 @@ void CSMWorld::ContainerRefIdAdapter::setNestedTable(const RefIdColumn* column, Record& record = dynamic_cast&> ( data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Container))); - record.get().mInventory.mList = dynamic_cast >&>(nestedTable).getNestedTable(); + record.get().mInventory.mList = (dynamic_cast >&>(nestedTable)).getNestedTable(); } CSMWorld::NestedTableWrapperBase CSMWorld::ContainerRefIdAdapter::nestedTable (const RefIdColumn* column, From 4d79034dbfa1f5c19e05c56045b779430919cf59 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Sun, 20 Jul 2014 18:52:35 +0200 Subject: [PATCH 0056/3725] correctly handling the nestedTable for undo (but removing and adding rows in proper QT way is still TODO) --- apps/opencs/model/world/collection.hpp | 8 +++++--- apps/opencs/model/world/collectionbase.hpp | 2 +- apps/opencs/model/world/commands.cpp | 19 +++++++++++++++---- apps/opencs/model/world/commands.hpp | 8 ++++++-- apps/opencs/model/world/idtable.cpp | 5 ++++- apps/opencs/model/world/idtable.hpp | 2 +- .../opencs/model/world/nestedtablewrapper.hpp | 14 ++------------ apps/opencs/model/world/refidadapter.hpp | 2 +- apps/opencs/model/world/refidadapterimp.cpp | 18 +++++++++--------- apps/opencs/model/world/refidadapterimp.hpp | 2 +- apps/opencs/model/world/refidcollection.cpp | 2 +- apps/opencs/model/world/refidcollection.hpp | 2 +- 12 files changed, 47 insertions(+), 37 deletions(-) diff --git a/apps/opencs/model/world/collection.hpp b/apps/opencs/model/world/collection.hpp index ac4351986..591074372 100644 --- a/apps/opencs/model/world/collection.hpp +++ b/apps/opencs/model/world/collection.hpp @@ -7,6 +7,7 @@ #include #include #include +#include #include @@ -92,7 +93,7 @@ namespace CSMWorld virtual void setData (int index, int column, const QVariant& data); - virtual NestedTableWrapperBase nestedTable(int row, int column) const; + virtual NestedTableWrapperBase* nestedTable(int row, int column) const; virtual void setNestedTable(int row, int column, const NestedTableWrapperBase& nestedTable); @@ -308,9 +309,10 @@ namespace CSMWorld } template - NestedTableWrapperBase Collection::nestedTable(int row, int column) const + NestedTableWrapperBase* Collection::nestedTable(int row, int column) const { - return NestedTableWrapperBase(); + assert(false); + return new NestedTableWrapperBase(); } template diff --git a/apps/opencs/model/world/collectionbase.hpp b/apps/opencs/model/world/collectionbase.hpp index 62f4079fc..a6ee34e56 100644 --- a/apps/opencs/model/world/collectionbase.hpp +++ b/apps/opencs/model/world/collectionbase.hpp @@ -51,7 +51,7 @@ namespace CSMWorld virtual QVariant getNestedData(int row, int column, int subRow, int subColumn) const = 0; - virtual NestedTableWrapperBase nestedTable(int row, int column) const = 0; + virtual NestedTableWrapperBase* nestedTable(int row, int column) const = 0; virtual void setNestedTable(int row, int column, const NestedTableWrapperBase& nestedTable) = 0; diff --git a/apps/opencs/model/world/commands.cpp b/apps/opencs/model/world/commands.cpp index 5e886bdb4..f464d75c8 100644 --- a/apps/opencs/model/world/commands.cpp +++ b/apps/opencs/model/world/commands.cpp @@ -4,6 +4,7 @@ #include "idtable.hpp" #include +#include "nestedtablewrapper.hpp" CSMWorld::ModifyCommand::ModifyCommand (QAbstractItemModel& model, const QModelIndex& index, const QVariant& new_, QUndoCommand* parent) @@ -178,7 +179,7 @@ CSMWorld::DeleteNestedCommand::DeleteNestedCommand (IdTable& model, const std::s mParentColumn(parentColumn), QUndoCommand(parent), mNestedRow(nestedRow), - mOld(model.nestedTable(model.getModelIndex(id, parentColumn))) + mOld (model.nestedTable(model.getModelIndex(id, parentColumn))) { setText (("Delete nested row in " + mId).c_str()); } @@ -195,7 +196,12 @@ void CSMWorld::DeleteNestedCommand::undo() { const QModelIndex& parentIndex = mModel.getModelIndex(mId, mParentColumn); - mModel.setNestedTable(parentIndex, mOld); + mModel.setNestedTable(parentIndex, *mOld); +} + +CSMWorld::DeleteNestedCommand::~DeleteNestedCommand() +{ + delete mOld; } CSMWorld::AddNestedCommand::AddNestedCommand(IdTable& model, const std::string& id, int nestedRow, int parentColumn, QUndoCommand* parent) @@ -204,7 +210,7 @@ CSMWorld::AddNestedCommand::AddNestedCommand(IdTable& model, const std::string& mNewRow(nestedRow), mParentColumn(parentColumn), QUndoCommand(parent), - mOld(model.nestedTable(model.getModelIndex(id, parentColumn))) + mOld (model.nestedTable(model.getModelIndex(id, parentColumn))) { setText (("Added nested row in " + mId).c_str()); } @@ -220,5 +226,10 @@ void CSMWorld::AddNestedCommand::undo() { const QModelIndex& parentIndex = mModel.getModelIndex(mId, mParentColumn); - mModel.setNestedTable(parentIndex, mOld); + mModel.setNestedTable(parentIndex, *mOld); +} + +CSMWorld::AddNestedCommand::~AddNestedCommand() +{ + delete mOld; } diff --git a/apps/opencs/model/world/commands.hpp b/apps/opencs/model/world/commands.hpp index 214a5157e..d45ec1e36 100644 --- a/apps/opencs/model/world/commands.hpp +++ b/apps/opencs/model/world/commands.hpp @@ -145,7 +145,7 @@ namespace CSMWorld std::string mId; - NestedTableWrapperBase mOld; + NestedTableWrapperBase* mOld; int mParentColumn; @@ -155,6 +155,8 @@ namespace CSMWorld DeleteNestedCommand (IdTable& model, const std::string& id, int nestedRow, int parentColumn, QUndoCommand* parent = 0); + ~DeleteNestedCommand(); + virtual void redo(); virtual void undo(); @@ -166,7 +168,7 @@ namespace CSMWorld std::string mId; - NestedTableWrapperBase mOld; + NestedTableWrapperBase* mOld; int mNewRow; @@ -175,6 +177,8 @@ namespace CSMWorld public: AddNestedCommand(IdTable& model, const std::string& id, int nestedRow, int parentColumn, QUndoCommand* parent = 0); + + ~AddNestedCommand(); virtual void redo(); diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index df0f4546d..dd045cb78 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -367,9 +367,12 @@ void CSMWorld::IdTable::setNestedTable(const QModelIndex& index, const CSMWorld: } mIdCollection->setNestedTable(index.row(), index.column(), nestedTable); + + emit dataChanged (CSMWorld::IdTable::index (index.row(), 0), + CSMWorld::IdTable::index (index.row(), mIdCollection->getColumns()-1)); } -CSMWorld::NestedTableWrapperBase CSMWorld::IdTable::nestedTable(const QModelIndex& index) const +CSMWorld::NestedTableWrapperBase* CSMWorld::IdTable::nestedTable(const QModelIndex& index) const { if (!hasChildren(index)) { diff --git a/apps/opencs/model/world/idtable.hpp b/apps/opencs/model/world/idtable.hpp index fd3f699ba..b7ba8c342 100644 --- a/apps/opencs/model/world/idtable.hpp +++ b/apps/opencs/model/world/idtable.hpp @@ -53,7 +53,7 @@ namespace CSMWorld QVariant nestedHeaderData(int section, int subSection, Qt::Orientation orientation, int role = Qt::DisplayRole) const; - NestedTableWrapperBase nestedTable(const QModelIndex &index) const; + NestedTableWrapperBase* nestedTable(const QModelIndex &index) const; void setNestedTable(const QModelIndex &index, const NestedTableWrapperBase& nestedTable); diff --git a/apps/opencs/model/world/nestedtablewrapper.hpp b/apps/opencs/model/world/nestedtablewrapper.hpp index c13a12c62..70e35f68a 100644 --- a/apps/opencs/model/world/nestedtablewrapper.hpp +++ b/apps/opencs/model/world/nestedtablewrapper.hpp @@ -1,9 +1,6 @@ #ifndef CSM_WOLRD_NESTEDTABLEWRAPPER_H #define CSM_WOLRD_NESTEDTABLEWRAPPER_H -#include - -#include namespace CSMWorld { struct NestedTableWrapperBase @@ -14,20 +11,13 @@ namespace CSMWorld }; template - class NestedTableWrapper : public NestedTableWrapperBase + struct NestedTableWrapper : public NestedTableWrapperBase { NestedTable mNestedTable; - public: - - NestedTableWrapper(const NestedTable& nestedTable) + NestedTableWrapper(const NestedTable& nestedTable) : mNestedTable(nestedTable) {} - NestedTable getNestedTable() const - { - return mNestedTable; - } - virtual ~NestedTableWrapper() {} }; } diff --git a/apps/opencs/model/world/refidadapter.hpp b/apps/opencs/model/world/refidadapter.hpp index f4aa769fd..f7064ab66 100644 --- a/apps/opencs/model/world/refidadapter.hpp +++ b/apps/opencs/model/world/refidadapter.hpp @@ -59,7 +59,7 @@ namespace CSMWorld virtual void setNestedTable (const RefIdColumn* column, RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) = 0; - virtual NestedTableWrapperBase nestedTable (const RefIdColumn * column, const RefIdData& data, int index) const = 0; + virtual NestedTableWrapperBase* nestedTable (const RefIdColumn* column, const RefIdData& data, int index) const = 0; }; } diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index d669a369c..173e89f56 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -227,24 +227,24 @@ void CSMWorld::ContainerRefIdAdapter::removeNestedRow (const RefIdColumn *column std::vector& list = static_cast&> ( data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Container))).get().mInventory.mList; - + list.erase (list.begin () + rowToRemove); } void CSMWorld::ContainerRefIdAdapter::addNestedRow (const RefIdColumn *column, RefIdData& data, int index, int position) const { assert(column==mContent); - + std::vector& list = static_cast&> ( data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Container))).get().mInventory.mList; - + ESM::ContItem newRow = {0, ""}; if (position >= (int)list.size()) { list.push_back(newRow); return; } - + list.insert(list.begin()+position, newRow); return; @@ -310,23 +310,23 @@ void CSMWorld::ContainerRefIdAdapter::setNestedData(const RefIdColumn *column, void CSMWorld::ContainerRefIdAdapter::setNestedTable(const RefIdColumn* column, RefIdData& data, - int index, + int index, const NestedTableWrapperBase& nestedTable) { Record& record = dynamic_cast&> ( data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Container))); - record.get().mInventory.mList = (dynamic_cast >&>(nestedTable)).getNestedTable(); + record.get().mInventory.mList = (static_cast >&>(nestedTable)).mNestedTable; } -CSMWorld::NestedTableWrapperBase CSMWorld::ContainerRefIdAdapter::nestedTable (const RefIdColumn* column, - const RefIdData& data, +CSMWorld::NestedTableWrapperBase* CSMWorld::ContainerRefIdAdapter::nestedTable (const RefIdColumn* column, + const RefIdData& data, int index) const { const Record& record = dynamic_cast&> ( data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Container))); - return NestedTableWrapper >(record.get().mInventory.mList); + return new NestedTableWrapper >(record.get().mInventory.mList); } QVariant CSMWorld::ContainerRefIdAdapter::getNestedData (const CSMWorld::RefIdColumn* column, diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index 4198fb367..ab05cfbc5 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -640,7 +640,7 @@ namespace CSMWorld virtual void addNestedRow (const RefIdColumn *column, RefIdData& data, int index, int position) const; - virtual NestedTableWrapperBase nestedTable (const RefIdColumn * column, const RefIdData& data, int index) const; + virtual NestedTableWrapperBase* nestedTable (const RefIdColumn * column, const RefIdData& data, int index) const; virtual void setNestedTable (const RefIdColumn* column, RefIdData& data, int index, const NestedTableWrapperBase& nestedTable); }; diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 6ff0df802..80ac1cc3b 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -652,7 +652,7 @@ void CSMWorld::RefIdCollection::setNestedTable(int row, int column, const CSMWor adaptor.setNestedTable(&mColumns.at(column), mData, localIndex.first, nestedTable); } -CSMWorld::NestedTableWrapperBase CSMWorld::RefIdCollection::nestedTable(int row, int column) const +CSMWorld::NestedTableWrapperBase* CSMWorld::RefIdCollection::nestedTable(int row, int column) const { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); diff --git a/apps/opencs/model/world/refidcollection.hpp b/apps/opencs/model/world/refidcollection.hpp index 927331c93..cc7609a58 100644 --- a/apps/opencs/model/world/refidcollection.hpp +++ b/apps/opencs/model/world/refidcollection.hpp @@ -72,7 +72,7 @@ namespace CSMWorld virtual QVariant getNestedData(int row, int column, int subRow, int subColumn) const; - virtual NestedTableWrapperBase nestedTable(int row, int column) const; + virtual NestedTableWrapperBase* nestedTable(int row, int column) const; virtual void setNestedTable(int row, int column, const NestedTableWrapperBase& nestedTable); From 87eed066c24ddd10095b8c680fe730103718a164 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Sun, 20 Jul 2014 22:39:39 +0200 Subject: [PATCH 0057/3725] undo works now --- apps/opencs/CMakeLists.txt | 4 ++-- apps/opencs/model/world/idtable.cpp | 12 ++++++++++++ apps/opencs/model/world/idtable.hpp | 9 +++++++-- apps/opencs/model/world/nestedtablemodel.cpp | 18 ++++++++++++++++++ apps/opencs/model/world/nestedtablemodel.hpp | 4 ++++ apps/opencs/model/world/nestedtablewrapper.cpp | 5 +++++ apps/opencs/model/world/nestedtablewrapper.hpp | 9 ++++++++- 7 files changed, 56 insertions(+), 5 deletions(-) diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index bcc64b60a..a9c56f9fa 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -19,12 +19,12 @@ opencs_hdrs_noqt (model/doc opencs_units (model/world idtable idtableproxymodel regionmap data commanddispatcher - idtablebase resourcetable nestedtablemodel nestedtablewrapper + idtablebase resourcetable nestedtablemodel ) opencs_units_noqt (model/world - universalid record commands columnbase scriptcontext cell refidcollection + nestedtablewrapper universalid record commands columnbase scriptcontext cell refidcollection refidadapter refiddata refidadapterimp ref collectionbase refcollection columns infocollection tablemimedata cellcoordinates cellselection resources resourcesmanager ) diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index dd045cb78..be31d0503 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -366,10 +366,22 @@ void CSMWorld::IdTable::setNestedTable(const QModelIndex& index, const CSMWorld: throw std::logic_error("Tried to set nested table, but index has no children"); } + bool removeRowsMode = false; + if (nestedTable.size() != this->nestedTable(index)->size()) + { + emit resetStart(this->index(index.row(), 0).data().toString()); + removeRowsMode = true; + } + mIdCollection->setNestedTable(index.row(), index.column(), nestedTable); emit dataChanged (CSMWorld::IdTable::index (index.row(), 0), CSMWorld::IdTable::index (index.row(), mIdCollection->getColumns()-1)); + + if (removeRowsMode) + { + emit resetEnd(this->index(index.row(), 0).data().toString()); + } } CSMWorld::NestedTableWrapperBase* CSMWorld::IdTable::nestedTable(const QModelIndex& index) const diff --git a/apps/opencs/model/world/idtable.hpp b/apps/opencs/model/world/idtable.hpp index b7ba8c342..d755822b5 100644 --- a/apps/opencs/model/world/idtable.hpp +++ b/apps/opencs/model/world/idtable.hpp @@ -52,9 +52,9 @@ namespace CSMWorld virtual QVariant headerData (int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; QVariant nestedHeaderData(int section, int subSection, Qt::Orientation orientation, int role = Qt::DisplayRole) const; - + NestedTableWrapperBase* nestedTable(const QModelIndex &index) const; - + void setNestedTable(const QModelIndex &index, const NestedTableWrapperBase& nestedTable); virtual bool setData ( const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); @@ -105,6 +105,11 @@ namespace CSMWorld virtual bool isDeleted (const std::string& id) const; int getColumnId(int column) const; + + signals: + void resetStart(const QString& id); + + void resetEnd(const QString& id); }; } diff --git a/apps/opencs/model/world/nestedtablemodel.cpp b/apps/opencs/model/world/nestedtablemodel.cpp index f0b510244..734047b8d 100644 --- a/apps/opencs/model/world/nestedtablemodel.cpp +++ b/apps/opencs/model/world/nestedtablemodel.cpp @@ -26,6 +26,12 @@ CSMWorld::NestedTableModel::NestedTableModel(const QModelIndex& parent, connect(mMainModel, SIGNAL(rowsRemoved(const QModelIndex &, int, int)), this, SLOT(forwardRowsRemoved(const QModelIndex &, int, int))); + + connect(mMainModel, SIGNAL(resetStart(const QString&)), + this, SLOT(forwardResetStart(const QString&))); + + connect(mMainModel, SIGNAL(resetEnd(const QString&)), + this, SLOT(forwardResetEnd(const QString&))); } QModelIndex CSMWorld::NestedTableModel::mapFromSource(const QModelIndex& sourceIndex) const @@ -157,3 +163,15 @@ void CSMWorld::NestedTableModel::forwardRowsRemoved(const QModelIndex& parent, i endRemoveRows(); } } + +void CSMWorld::NestedTableModel::forwardResetStart(const QString& id) +{ + if (id.toUtf8() == mId.c_str()) + beginResetModel(); +} + +void CSMWorld::NestedTableModel::forwardResetEnd(const QString& id) +{ + if (id.toUtf8() == mId.c_str()) + endResetModel(); +} diff --git a/apps/opencs/model/world/nestedtablemodel.hpp b/apps/opencs/model/world/nestedtablemodel.hpp index dfb231124..5fea5c006 100644 --- a/apps/opencs/model/world/nestedtablemodel.hpp +++ b/apps/opencs/model/world/nestedtablemodel.hpp @@ -70,6 +70,10 @@ namespace CSMWorld void forwardRowsAboutToRemoved(const QModelIndex & parent, int first, int last); void forwardRowsRemoved(const QModelIndex & parent, int first, int last); + + void forwardResetStart(const QString& id); + + void forwardResetEnd(const QString& id); }; } diff --git a/apps/opencs/model/world/nestedtablewrapper.cpp b/apps/opencs/model/world/nestedtablewrapper.cpp index 387bc6e7b..3966dbc57 100644 --- a/apps/opencs/model/world/nestedtablewrapper.cpp +++ b/apps/opencs/model/world/nestedtablewrapper.cpp @@ -5,3 +5,8 @@ CSMWorld::NestedTableWrapperBase::NestedTableWrapperBase() CSMWorld::NestedTableWrapperBase::~NestedTableWrapperBase() {} + +int CSMWorld::NestedTableWrapperBase::size() const +{ + return -5; +} diff --git a/apps/opencs/model/world/nestedtablewrapper.hpp b/apps/opencs/model/world/nestedtablewrapper.hpp index 70e35f68a..f0ca00dbe 100644 --- a/apps/opencs/model/world/nestedtablewrapper.hpp +++ b/apps/opencs/model/world/nestedtablewrapper.hpp @@ -7,9 +7,11 @@ namespace CSMWorld { virtual ~NestedTableWrapperBase(); + virtual int size() const; + NestedTableWrapperBase(); }; - + template struct NestedTableWrapper : public NestedTableWrapperBase { @@ -19,6 +21,11 @@ namespace CSMWorld : mNestedTable(nestedTable) {} virtual ~NestedTableWrapper() {} + + virtual int size() const + { + return mNestedTable.size(); //i hope that this will be enough + } }; } #endif From 3dd2ca15da9228f1463d59800b71dfc54a31f95d Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Mon, 21 Jul 2014 09:52:09 +0200 Subject: [PATCH 0058/3725] Reduced code duplication through new common base class --- apps/opencs/model/world/commands.cpp | 23 +++++++++++++---------- apps/opencs/model/world/commands.hpp | 26 ++++++++++++++++---------- 2 files changed, 29 insertions(+), 20 deletions(-) diff --git a/apps/opencs/model/world/commands.cpp b/apps/opencs/model/world/commands.cpp index f464d75c8..0d9f6c773 100644 --- a/apps/opencs/model/world/commands.cpp +++ b/apps/opencs/model/world/commands.cpp @@ -179,7 +179,7 @@ CSMWorld::DeleteNestedCommand::DeleteNestedCommand (IdTable& model, const std::s mParentColumn(parentColumn), QUndoCommand(parent), mNestedRow(nestedRow), - mOld (model.nestedTable(model.getModelIndex(id, parentColumn))) + NestedTableStoring(model, id, parentColumn) { setText (("Delete nested row in " + mId).c_str()); } @@ -196,12 +196,7 @@ void CSMWorld::DeleteNestedCommand::undo() { const QModelIndex& parentIndex = mModel.getModelIndex(mId, mParentColumn); - mModel.setNestedTable(parentIndex, *mOld); -} - -CSMWorld::DeleteNestedCommand::~DeleteNestedCommand() -{ - delete mOld; + mModel.setNestedTable(parentIndex, getOld()); } CSMWorld::AddNestedCommand::AddNestedCommand(IdTable& model, const std::string& id, int nestedRow, int parentColumn, QUndoCommand* parent) @@ -210,7 +205,7 @@ CSMWorld::AddNestedCommand::AddNestedCommand(IdTable& model, const std::string& mNewRow(nestedRow), mParentColumn(parentColumn), QUndoCommand(parent), - mOld (model.nestedTable(model.getModelIndex(id, parentColumn))) + NestedTableStoring(model, id, parentColumn) { setText (("Added nested row in " + mId).c_str()); } @@ -226,10 +221,18 @@ void CSMWorld::AddNestedCommand::undo() { const QModelIndex& parentIndex = mModel.getModelIndex(mId, mParentColumn); - mModel.setNestedTable(parentIndex, *mOld); + mModel.setNestedTable(parentIndex, getOld()); } -CSMWorld::AddNestedCommand::~AddNestedCommand() +CSMWorld::NestedTableStoring::NestedTableStoring(const IdTable& model, const std::string& id, int parentColumn) + : mOld(model.nestedTable(model.getModelIndex(id, parentColumn))) {} + +CSMWorld::NestedTableStoring::~NestedTableStoring() { delete mOld; } + +const CSMWorld::NestedTableWrapperBase& CSMWorld::NestedTableStoring::getOld() const +{ + return *mOld; +} diff --git a/apps/opencs/model/world/commands.hpp b/apps/opencs/model/world/commands.hpp index d45ec1e36..d868ccf46 100644 --- a/apps/opencs/model/world/commands.hpp +++ b/apps/opencs/model/world/commands.hpp @@ -139,14 +139,26 @@ namespace CSMWorld virtual void undo(); }; - class DeleteNestedCommand : public QUndoCommand + class NestedTableStoring + { + NestedTableWrapperBase* mOld; + + public: + NestedTableStoring(const IdTable& model, const std::string& id, int parentColumn); + + ~NestedTableStoring(); + + protected: + + const NestedTableWrapperBase& getOld() const; + }; + + class DeleteNestedCommand : public QUndoCommand, private NestedTableStoring { IdTable& mModel; std::string mId; - NestedTableWrapperBase* mOld; - int mParentColumn; int mNestedRow; @@ -155,21 +167,17 @@ namespace CSMWorld DeleteNestedCommand (IdTable& model, const std::string& id, int nestedRow, int parentColumn, QUndoCommand* parent = 0); - ~DeleteNestedCommand(); - virtual void redo(); virtual void undo(); }; - class AddNestedCommand : public QUndoCommand + class AddNestedCommand : public QUndoCommand, private NestedTableStoring { IdTable& mModel; std::string mId; - NestedTableWrapperBase* mOld; - int mNewRow; int mParentColumn; @@ -177,8 +185,6 @@ namespace CSMWorld public: AddNestedCommand(IdTable& model, const std::string& id, int nestedRow, int parentColumn, QUndoCommand* parent = 0); - - ~AddNestedCommand(); virtual void redo(); From c4598d6200e21de1df91234dad7637a04c62f36d Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Mon, 21 Jul 2014 14:09:00 +0200 Subject: [PATCH 0059/3725] added inventory helper (since npc and containers share same way of handling items) --- apps/opencs/CMakeLists.txt | 3 +- apps/opencs/model/world/nestedadaptors.cpp | 1 + apps/opencs/model/world/nestedadaptors.hpp | 56 +++++++++++++++++++++ apps/opencs/model/world/refidadapterimp.cpp | 12 ++--- apps/opencs/model/world/refidadapterimp.hpp | 3 ++ 5 files changed, 65 insertions(+), 10 deletions(-) create mode 100644 apps/opencs/model/world/nestedadaptors.cpp create mode 100644 apps/opencs/model/world/nestedadaptors.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index a9c56f9fa..08c105c92 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -25,7 +25,8 @@ opencs_units (model/world opencs_units_noqt (model/world nestedtablewrapper universalid record commands columnbase scriptcontext cell refidcollection - refidadapter refiddata refidadapterimp ref collectionbase refcollection columns infocollection tablemimedata cellcoordinates cellselection resources resourcesmanager + refidadapter refiddata refidadapterimp ref collectionbase refcollection columns infocollection + tablemimedata cellcoordinates cellselection resources resourcesmanager nestedadaptors ) opencs_hdrs_noqt (model/world diff --git a/apps/opencs/model/world/nestedadaptors.cpp b/apps/opencs/model/world/nestedadaptors.cpp new file mode 100644 index 000000000..8ed1819b8 --- /dev/null +++ b/apps/opencs/model/world/nestedadaptors.cpp @@ -0,0 +1 @@ +#include "nestedadaptors.hpp" diff --git a/apps/opencs/model/world/nestedadaptors.hpp b/apps/opencs/model/world/nestedadaptors.hpp new file mode 100644 index 000000000..c0ca9744c --- /dev/null +++ b/apps/opencs/model/world/nestedadaptors.hpp @@ -0,0 +1,56 @@ +#ifndef CSM_WORLD_NESTEDADAPTORS_H +#define CSM_WORLD_NESTEDADAPTORS_H + +#include + +#include "universalid.hpp" +#include "nestedtablewrapper.hpp" +#include +#include "record.hpp" +#include "refiddata.hpp" +#include "refidadapter.hpp" + +namespace CSMWorld +{ + template + class InventoryHelper + { + CSMWorld::UniversalId::Type mType; + + public: + + InventoryHelper(CSMWorld::UniversalId::Type type) : mType(type) {}; + + void setNestedTable(const RefIdColumn* column, + RefIdData& data, + int index, + const NestedTableWrapperBase& nestedTable) + { + getRecord(data, index).get().mInventory.mList = + (static_cast >&>(nestedTable)).mNestedTable; + } + + NestedTableWrapperBase* nestedTable(const RefIdColumn* column, + const RefIdData& data, + int index) const + { + return new NestedTableWrapper >(getRecord(data, index).get().mInventory.mList); + } + + private: + + const Record& getRecord(const RefIdData& data, int index) const + { + return dynamic_cast&> ( + data.getRecord (RefIdData::LocalIndex (index, mType))); + } + + Record& getRecord(RefIdData& data, int index) const + { + return dynamic_cast&> ( + data.getRecord (RefIdData::LocalIndex (index, mType))); + } + }; +} + +#endif diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index 173e89f56..08d890957 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -180,7 +180,7 @@ void CSMWorld::ClothingRefIdAdapter::setData (const RefIdColumn *column, RefIdDa CSMWorld::ContainerRefIdAdapter::ContainerRefIdAdapter (const NameColumns& columns, const RefIdColumn *weight, const RefIdColumn *organic, const RefIdColumn *respawn, const RefIdColumn *content) : NameRefIdAdapter (UniversalId::Type_Container, columns), mWeight (weight), - mOrganic (organic), mRespawn (respawn), mContent(content) + mOrganic (organic), mRespawn (respawn), mContent(content), mHelper(InventoryHelper(UniversalId::Type_Container)) {} int CSMWorld::ContainerRefIdAdapter::getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const @@ -313,20 +313,14 @@ void CSMWorld::ContainerRefIdAdapter::setNestedTable(const RefIdColumn* column, int index, const NestedTableWrapperBase& nestedTable) { - Record& record = dynamic_cast&> ( - data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Container))); - - record.get().mInventory.mList = (static_cast >&>(nestedTable)).mNestedTable; + mHelper.setNestedTable(column, data, index, nestedTable); } CSMWorld::NestedTableWrapperBase* CSMWorld::ContainerRefIdAdapter::nestedTable (const RefIdColumn* column, const RefIdData& data, int index) const { - const Record& record = dynamic_cast&> ( - data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Container))); - - return new NestedTableWrapper >(record.get().mInventory.mList); + return mHelper.nestedTable(column, data, index); } QVariant CSMWorld::ContainerRefIdAdapter::getNestedData (const CSMWorld::RefIdColumn* column, diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index ab05cfbc5..aac2ba807 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -12,6 +12,7 @@ #include "refiddata.hpp" #include "universalid.hpp" #include "refidadapter.hpp" +#include "nestedadaptors.hpp" namespace CSMWorld { @@ -614,6 +615,8 @@ namespace CSMWorld const RefIdColumn *mOrganic; const RefIdColumn *mRespawn; const RefIdColumn *mContent; + + InventoryHelper mHelper; public: From 6573e3f319e27d7bbcdc3e209f941fae9fb257df Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Mon, 21 Jul 2014 14:24:54 +0200 Subject: [PATCH 0060/3725] moved responsibility for getNestedData to the inventory helper --- apps/opencs/model/world/nestedadaptors.hpp | 23 +++++++++++++++++++++ apps/opencs/model/world/refidadapterimp.cpp | 17 +-------------- 2 files changed, 24 insertions(+), 16 deletions(-) diff --git a/apps/opencs/model/world/nestedadaptors.hpp b/apps/opencs/model/world/nestedadaptors.hpp index c0ca9744c..d5edf3358 100644 --- a/apps/opencs/model/world/nestedadaptors.hpp +++ b/apps/opencs/model/world/nestedadaptors.hpp @@ -10,6 +10,8 @@ #include "refiddata.hpp" #include "refidadapter.hpp" +#include + namespace CSMWorld { template @@ -37,6 +39,27 @@ namespace CSMWorld return new NestedTableWrapper >(getRecord(data, index).get().mInventory.mList); } + QVariant getNestedData(const CSMWorld::RefIdColumn* column, + const CSMWorld::RefIdData& data, + int index, + int subRowIndex, + int subColIndex) const + { + const ESM::ContItem& content = getRecord(data, index).get().mInventory.mList.at(subRowIndex); + + switch (subColIndex) + { + case 0: + return QString::fromUtf8(content.mItem.toString().c_str()); + + case 1: + return content.mCount; + + default: + throw std::logic_error("Trying to access non-existing column in the nested table!"); + } + } + private: const Record& getRecord(const RefIdData& data, int index) const diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index 08d890957..3622c77af 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -329,24 +329,9 @@ QVariant CSMWorld::ContainerRefIdAdapter::getNestedData (const CSMWorld::RefIdCo int subRowIndex, int subColIndex) const { - const Record& record = static_cast&> ( - data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Container))); - if (column==mContent) { - const ESM::ContItem& content = record.get().mInventory.mList.at(subRowIndex); - - switch (subColIndex) - { - case 0: - return QString::fromUtf8(content.mItem.toString().c_str()); - - case 1: - return content.mCount; - - default: - throw std::logic_error("Trying to access non-existing column in the nested table!"); - } + return mHelper.getNestedData(column, data, index, subRowIndex, subColIndex); } else { throw std::logic_error("This column does not hold multiple values."); From cb004936e03cc802211d31ee165f3670fcbe1989 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Mon, 21 Jul 2014 14:34:48 +0200 Subject: [PATCH 0061/3725] moved setNestedData to the helper as well --- apps/opencs/model/world/nestedadaptors.hpp | 23 +++++++++++++++++++++ apps/opencs/model/world/refidadapterimp.cpp | 19 ++--------------- 2 files changed, 25 insertions(+), 17 deletions(-) diff --git a/apps/opencs/model/world/nestedadaptors.hpp b/apps/opencs/model/world/nestedadaptors.hpp index d5edf3358..8f82482d8 100644 --- a/apps/opencs/model/world/nestedadaptors.hpp +++ b/apps/opencs/model/world/nestedadaptors.hpp @@ -2,6 +2,7 @@ #define CSM_WORLD_NESTEDADAPTORS_H #include +#include #include "universalid.hpp" #include "nestedtablewrapper.hpp" @@ -59,6 +60,28 @@ namespace CSMWorld throw std::logic_error("Trying to access non-existing column in the nested table!"); } } + + void setNestedData (const RefIdColumn *column, + RefIdData& data, + int index, + const QVariant& value, + int subRowIndex, + int subColIndex) const + { + switch(subColIndex) + { + case 0: + getRecord(data, index).get().mInventory.mList.at(subRowIndex).mItem.assign(std::string(value.toString().toUtf8().constData())); + break; + + case 1: + getRecord(data, index).get().mInventory.mList.at(subRowIndex).mCount = value.toInt(); + break; + + default: + throw std::logic_error("Trying to access non-existing column in the nested table!"); + } + } private: diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index 3622c77af..3600562d3 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -285,23 +285,8 @@ void CSMWorld::ContainerRefIdAdapter::setNestedData(const RefIdColumn *column, { if (column==mContent) - { - Record& record = static_cast&> ( - data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Container))); - - switch (subColIndex) - { - case 0: - record.get().mInventory.mList.at(subRowIndex).mItem.assign(std::string(value.toString().toUtf8().constData())); - break; - - case 1: - record.get().mInventory.mList.at(subRowIndex).mCount = value.toInt(); - break; - - default: - throw std::logic_error("Trying to access non-existing column in the nested table!"); - } + { + mHelper.setNestedData(column, data, index, value, subRowIndex, subColIndex); } else { assert(false); From c018ca43ac1f00b4ece1215f0776b069941f71ce Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Mon, 21 Jul 2014 14:44:48 +0200 Subject: [PATCH 0062/3725] getting rid of the asserts --- apps/opencs/model/world/refidadapterimp.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index 3600562d3..f85138d97 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -223,7 +223,10 @@ QVariant CSMWorld::ContainerRefIdAdapter::getData (const RefIdColumn *column, co void CSMWorld::ContainerRefIdAdapter::removeNestedRow (const RefIdColumn *column, RefIdData& data, int index, int rowToRemove) const { - assert(column==mContent); + if(column!=mContent) + { + throw std::logic_error("This column does not hold multiple values."); + } std::vector& list = static_cast&> ( data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Container))).get().mInventory.mList; @@ -289,7 +292,7 @@ void CSMWorld::ContainerRefIdAdapter::setNestedData(const RefIdColumn *column, mHelper.setNestedData(column, data, index, value, subRowIndex, subColIndex); } else { - assert(false); + throw std::logic_error("This column do not nest other columns"); } } @@ -319,7 +322,7 @@ QVariant CSMWorld::ContainerRefIdAdapter::getNestedData (const CSMWorld::RefIdCo return mHelper.getNestedData(column, data, index, subRowIndex, subColIndex); } else { - throw std::logic_error("This column does not hold multiple values."); + throw std::logic_error("This column do not nest other columns"); } } From 427d6efd1904a1b574f2566114c32e6147468871 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Mon, 21 Jul 2014 14:49:47 +0200 Subject: [PATCH 0063/3725] Moved removeNestedRow responsibility to the helper. --- apps/opencs/model/world/nestedadaptors.hpp | 7 +++++++ apps/opencs/model/world/refidadapterimp.cpp | 6 +----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/apps/opencs/model/world/nestedadaptors.hpp b/apps/opencs/model/world/nestedadaptors.hpp index 8f82482d8..a961d19e4 100644 --- a/apps/opencs/model/world/nestedadaptors.hpp +++ b/apps/opencs/model/world/nestedadaptors.hpp @@ -61,6 +61,13 @@ namespace CSMWorld } } + void removeNestedRow (const RefIdColumn *column, RefIdData& data, int index, int rowToRemove) const + { + std::vector& list = getRecord(data, index).get().mInventory.mList; + + list.erase (list.begin () + rowToRemove); + } + void setNestedData (const RefIdColumn *column, RefIdData& data, int index, diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index f85138d97..2a8fec01d 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -227,11 +227,7 @@ void CSMWorld::ContainerRefIdAdapter::removeNestedRow (const RefIdColumn *column { throw std::logic_error("This column does not hold multiple values."); } - - std::vector& list = static_cast&> ( - data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Container))).get().mInventory.mList; - - list.erase (list.begin () + rowToRemove); + mHelper.removeNestedRow(column, data, index, rowToRemove); } void CSMWorld::ContainerRefIdAdapter::addNestedRow (const RefIdColumn *column, RefIdData& data, int index, int position) const From dcd90faaef82820d738f34976f7a57daf0907056 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Mon, 21 Jul 2014 14:58:45 +0200 Subject: [PATCH 0064/3725] moved add nested to the helper --- apps/opencs/model/world/nestedadaptors.hpp | 14 ++++++++++++++ apps/opencs/model/world/refidadapterimp.cpp | 15 +++------------ 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/apps/opencs/model/world/nestedadaptors.hpp b/apps/opencs/model/world/nestedadaptors.hpp index a961d19e4..9e747164a 100644 --- a/apps/opencs/model/world/nestedadaptors.hpp +++ b/apps/opencs/model/world/nestedadaptors.hpp @@ -90,6 +90,20 @@ namespace CSMWorld } } + void addNestedRow (const RefIdColumn *column, RefIdData& data, int index, int position) const + { + std::vector& list = getRecord(data, index).get().mInventory.mList; + + ESM::ContItem newRow = {0, ""}; + if (position >= (int)list.size()) + { + list.push_back(newRow); + return; + } + + list.insert(list.begin()+position, newRow); + } + private: const Record& getRecord(const RefIdData& data, int index) const diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index 2a8fec01d..5681b8bae 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -232,21 +232,12 @@ void CSMWorld::ContainerRefIdAdapter::removeNestedRow (const RefIdColumn *column void CSMWorld::ContainerRefIdAdapter::addNestedRow (const RefIdColumn *column, RefIdData& data, int index, int position) const { - assert(column==mContent); - - std::vector& list = static_cast&> ( - data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Container))).get().mInventory.mList; - - ESM::ContItem newRow = {0, ""}; - if (position >= (int)list.size()) + if(column!=mContent) { - list.push_back(newRow); - return; + throw std::logic_error("This column does not hold multiple values."); } - list.insert(list.begin()+position, newRow); - - return; + mHelper.addNestedRow(column, data, index, position); } void CSMWorld::ContainerRefIdAdapter::setData (const RefIdColumn *column, RefIdData& data, int index, From 24eb034ba357f6aa93f944d38a0f948e0bb1d4ad Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Tue, 22 Jul 2014 10:27:45 +0200 Subject: [PATCH 0065/3725] major refactorisation --- apps/opencs/model/world/nestedadaptors.cpp | 7 ++ apps/opencs/model/world/nestedadaptors.hpp | 93 ++++++++++++++++----- apps/opencs/model/world/refidadapter.cpp | 84 ++++++++++++++++++- apps/opencs/model/world/refidadapter.hpp | 45 +++++++++- apps/opencs/model/world/refidadapterimp.cpp | 93 ++------------------- apps/opencs/model/world/refidadapterimp.hpp | 20 ----- 6 files changed, 210 insertions(+), 132 deletions(-) diff --git a/apps/opencs/model/world/nestedadaptors.cpp b/apps/opencs/model/world/nestedadaptors.cpp index 8ed1819b8..1e8425229 100644 --- a/apps/opencs/model/world/nestedadaptors.cpp +++ b/apps/opencs/model/world/nestedadaptors.cpp @@ -1 +1,8 @@ #include "nestedadaptors.hpp" + +CSMWorld::HelperBase::HelperBase(CSMWorld::UniversalId::Type type) + : mType(type) +{} + +CSMWorld::HelperBase::~HelperBase() +{} diff --git a/apps/opencs/model/world/nestedadaptors.hpp b/apps/opencs/model/world/nestedadaptors.hpp index 9e747164a..806dc587d 100644 --- a/apps/opencs/model/world/nestedadaptors.hpp +++ b/apps/opencs/model/world/nestedadaptors.hpp @@ -6,45 +6,85 @@ #include "universalid.hpp" #include "nestedtablewrapper.hpp" -#include #include "record.hpp" #include "refiddata.hpp" #include "refidadapter.hpp" +#include #include namespace CSMWorld { - template - class InventoryHelper + class RefIdColumn; + + class HelperBase { - CSMWorld::UniversalId::Type mType; + protected: + const CSMWorld::UniversalId::Type mType; public: + HelperBase(CSMWorld::UniversalId::Type type); + + virtual ~HelperBase(); + + virtual void setNestedTable(RefIdData& data, + int index, + const NestedTableWrapperBase& nestedTable) = 0; + + virtual NestedTableWrapperBase* nestedTable(const RefIdData& data, + int index) const = 0; + + virtual QVariant getNestedData(const CSMWorld::RefIdData& data, + int index, + int subRowIndex, + int subColIndex) const = 0; + + virtual void removeNestedRow (RefIdData& data, + int index, + int rowToRemove) const = 0; + + virtual void setNestedData (RefIdData& data, + int index, + const QVariant& value, + int subRowIndex, + int subColIndex) const = 0; + + virtual void addNestedRow (RefIdData& data, + int index, + int position) const = 0; - InventoryHelper(CSMWorld::UniversalId::Type type) : mType(type) {}; + virtual int getNestedColumnsCount(const RefIdData& data) const = 0; - void setNestedTable(const RefIdColumn* column, - RefIdData& data, - int index, - const NestedTableWrapperBase& nestedTable) + virtual int getNestedRowsCount(const RefIdData& data, + int index) const = 0; + }; + + template + class InventoryHelper : public HelperBase + { + public: + + InventoryHelper(CSMWorld::UniversalId::Type type) + : HelperBase(type) {} + + virtual void setNestedTable(RefIdData& data, + int index, + const NestedTableWrapperBase& nestedTable) { getRecord(data, index).get().mInventory.mList = (static_cast >&>(nestedTable)).mNestedTable; } - NestedTableWrapperBase* nestedTable(const RefIdColumn* column, - const RefIdData& data, - int index) const + virtual NestedTableWrapperBase* nestedTable(const RefIdData& data, + int index) const { return new NestedTableWrapper >(getRecord(data, index).get().mInventory.mList); } - QVariant getNestedData(const CSMWorld::RefIdColumn* column, - const CSMWorld::RefIdData& data, - int index, - int subRowIndex, - int subColIndex) const + virtual QVariant getNestedData(const CSMWorld::RefIdData& data, + int index, + int subRowIndex, + int subColIndex) const { const ESM::ContItem& content = getRecord(data, index).get().mInventory.mList.at(subRowIndex); @@ -61,15 +101,14 @@ namespace CSMWorld } } - void removeNestedRow (const RefIdColumn *column, RefIdData& data, int index, int rowToRemove) const + virtual void removeNestedRow (RefIdData& data, int index, int rowToRemove) const { std::vector& list = getRecord(data, index).get().mInventory.mList; list.erase (list.begin () + rowToRemove); } - void setNestedData (const RefIdColumn *column, - RefIdData& data, + void setNestedData (RefIdData& data, int index, const QVariant& value, int subRowIndex, @@ -90,7 +129,7 @@ namespace CSMWorld } } - void addNestedRow (const RefIdColumn *column, RefIdData& data, int index, int position) const + virtual void addNestedRow (RefIdData& data, int index, int position) const { std::vector& list = getRecord(data, index).get().mInventory.mList; @@ -104,6 +143,18 @@ namespace CSMWorld list.insert(list.begin()+position, newRow); } + virtual int getNestedColumnsCount(const RefIdData& data) const + { + return 2; + } + + + virtual int getNestedRowsCount(const RefIdData& data, + int index) const + { + return getRecord(data, index).get().mInventory.mList.size(); + } + private: const Record& getRecord(const RefIdData& data, int index) const diff --git a/apps/opencs/model/world/refidadapter.cpp b/apps/opencs/model/world/refidadapter.cpp index 50314e7a2..631c192fd 100644 --- a/apps/opencs/model/world/refidadapter.cpp +++ b/apps/opencs/model/world/refidadapter.cpp @@ -1,13 +1,89 @@ - #include "refidadapter.hpp" -#include "cassert" +#include "nestedtablewrapper.hpp" + #include CSMWorld::RefIdAdapter::RefIdAdapter() {} CSMWorld::RefIdAdapter::~RefIdAdapter() {} -CSMWorld::NestedRefIdAdapter::NestedRefIdAdapter() {} +CSMWorld::NestedRefIdAdapterBase::NestedRefIdAdapterBase() {} + +CSMWorld::NestedRefIdAdapterBase::~NestedRefIdAdapterBase() {} + +CSMWorld::NestedRefIdAdapter::NestedRefIdAdapter() +{} + +CSMWorld::NestedRefIdAdapter::~NestedRefIdAdapter() +{ + for (unsigned i = 0; i < mAssociatedColumns.size(); ++i) + { + delete mAssociatedColumns[i].second; + } +} + +void CSMWorld::NestedRefIdAdapter::setNestedData (const RefIdColumn *column, RefIdData& data, int row, + const QVariant& value, int subRowIndex, int subColIndex) const +{ + getHelper(column)->setNestedData(data, row, value, subRowIndex, subColIndex); +} + +QVariant CSMWorld::NestedRefIdAdapter::getNestedData(const RefIdColumn *column, const RefIdData& data, + int index, int subRowIndex, int subColIndex) const +{ + return getHelper(column)->getNestedData(data, index, subRowIndex, subColIndex); +} + +int CSMWorld::NestedRefIdAdapter::getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const +{ + return getHelper(column)->getNestedColumnsCount(data); +} + + +int CSMWorld::NestedRefIdAdapter::getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const +{ + return getHelper(column)->getNestedRowsCount(data, index); +} + + +void CSMWorld::NestedRefIdAdapter::removeNestedRow (const RefIdColumn *column, RefIdData& data, int index, int rowToRemove) const +{ + getHelper(column)->removeNestedRow(data, index, rowToRemove); +} + +void CSMWorld::NestedRefIdAdapter::addNestedRow (const RefIdColumn *column, RefIdData& data, int index, int position) const +{ + getHelper(column)->addNestedRow(data, index, position); //This code grows more boring and boring. I would love some macros. +} + +void CSMWorld::NestedRefIdAdapter::setNestedTable (const RefIdColumn* column, RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) +{ + getHelper(column)->setNestedTable(data, index, nestedTable); +} + + +CSMWorld::NestedTableWrapperBase* CSMWorld::NestedRefIdAdapter::nestedTable (const RefIdColumn* column, const RefIdData& data, int index) const +{ + return getHelper(column)->nestedTable(data, index); +} + +CSMWorld::HelperBase* CSMWorld::NestedRefIdAdapter::getHelper(const RefIdColumn *column) const +{ + for (unsigned i = 0; i < mAssociatedColumns.size(); ++i) + { + if (mAssociatedColumns[i].first == column) + { + return mAssociatedColumns[i].second; + } + } + + throw std::logic_error("No such column in the nestedrefidadapter"); + + return NULL; +} -CSMWorld::NestedRefIdAdapter::~NestedRefIdAdapter() {} \ No newline at end of file +void CSMWorld::NestedRefIdAdapter::setAssocColumns(const std::vector >& assocColumns) +{ + mAssociatedColumns = assocColumns; +} diff --git a/apps/opencs/model/world/refidadapter.hpp b/apps/opencs/model/world/refidadapter.hpp index f7064ab66..dd2248e92 100644 --- a/apps/opencs/model/world/refidadapter.hpp +++ b/apps/opencs/model/world/refidadapter.hpp @@ -2,6 +2,9 @@ #define CSM_WOLRD_REFIDADAPTER_H #include +#include + +#include "nestedadaptors.hpp" class QVariant; @@ -11,6 +14,7 @@ namespace CSMWorld class RefIdData; class RecordBase; class NestedTableWrapperBase; + class HelperBase; class RefIdAdapter { @@ -36,12 +40,12 @@ namespace CSMWorld virtual void setId(RecordBase& record, const std::string& id) = 0; }; - class NestedRefIdAdapter + class NestedRefIdAdapterBase { public: - NestedRefIdAdapter(); + NestedRefIdAdapterBase(); - virtual ~NestedRefIdAdapter(); + virtual ~NestedRefIdAdapterBase(); virtual void setNestedData (const RefIdColumn *column, RefIdData& data, int row, const QVariant& value, int subRowIndex, int subColIndex) const = 0; @@ -61,6 +65,41 @@ namespace CSMWorld virtual NestedTableWrapperBase* nestedTable (const RefIdColumn* column, const RefIdData& data, int index) const = 0; }; + + class NestedRefIdAdapter : public NestedRefIdAdapterBase + { + std::vector > mAssociatedColumns; //basicly, i wanted map, but with pointer key + + public: + NestedRefIdAdapter(); + + virtual ~NestedRefIdAdapter(); + + virtual void setNestedData (const RefIdColumn *column, RefIdData& data, int row, + const QVariant& value, int subRowIndex, int subColIndex) const; + + virtual QVariant getNestedData (const RefIdColumn *column, const RefIdData& data, + int index, int subRowIndex, int subColIndex) const; + + virtual int getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const; + + virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const; + + virtual void removeNestedRow (const RefIdColumn *column, RefIdData& data, int index, int rowToRemove) const; + + virtual void addNestedRow (const RefIdColumn *column, RefIdData& data, int index, int position) const; + + virtual void setNestedTable (const RefIdColumn* column, RefIdData& data, int index, const NestedTableWrapperBase& nestedTable); + + virtual NestedTableWrapperBase* nestedTable (const RefIdColumn* column, const RefIdData& data, int index) const; + + protected: + void setAssocColumns(const std::vector >& assocColumns); + + private: + + HelperBase* getHelper(const RefIdColumn *column) const; + }; } #endif diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index 5681b8bae..18287d596 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include "nestedtablewrapper.hpp" @@ -180,28 +181,18 @@ void CSMWorld::ClothingRefIdAdapter::setData (const RefIdColumn *column, RefIdDa CSMWorld::ContainerRefIdAdapter::ContainerRefIdAdapter (const NameColumns& columns, const RefIdColumn *weight, const RefIdColumn *organic, const RefIdColumn *respawn, const RefIdColumn *content) : NameRefIdAdapter (UniversalId::Type_Container, columns), mWeight (weight), - mOrganic (organic), mRespawn (respawn), mContent(content), mHelper(InventoryHelper(UniversalId::Type_Container)) -{} - -int CSMWorld::ContainerRefIdAdapter::getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const -{ - assert(column==mContent); - - return 2; -} - -int CSMWorld::ContainerRefIdAdapter::getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const + mOrganic (organic), mRespawn (respawn), mContent(content) { - assert(column==mContent); - - const Record& record = static_cast&> ( - data.getRecord(RefIdData::LocalIndex (index, UniversalId::Type_Container))); + std::vector > assoCol; - return record.get().mInventory.mList.size(); + assoCol.push_back(std::make_pair(content, new InventoryHelper(UniversalId::Type_Container))); + + setAssocColumns(assoCol); } -QVariant CSMWorld::ContainerRefIdAdapter::getData (const RefIdColumn *column, const RefIdData& data, - int index) const +QVariant CSMWorld::ContainerRefIdAdapter::getData (const RefIdColumn *column, + const RefIdData& data, + int index) const { const Record& record = static_cast&> ( data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Container))); @@ -221,24 +212,6 @@ QVariant CSMWorld::ContainerRefIdAdapter::getData (const RefIdColumn *column, co return NameRefIdAdapter::getData (column, data, index); } -void CSMWorld::ContainerRefIdAdapter::removeNestedRow (const RefIdColumn *column, RefIdData& data, int index, int rowToRemove) const -{ - if(column!=mContent) - { - throw std::logic_error("This column does not hold multiple values."); - } - mHelper.removeNestedRow(column, data, index, rowToRemove); -} - -void CSMWorld::ContainerRefIdAdapter::addNestedRow (const RefIdColumn *column, RefIdData& data, int index, int position) const -{ - if(column!=mContent) - { - throw std::logic_error("This column does not hold multiple values."); - } - - mHelper.addNestedRow(column, data, index, position); -} void CSMWorld::ContainerRefIdAdapter::setData (const RefIdColumn *column, RefIdData& data, int index, const QVariant& value) const @@ -266,54 +239,6 @@ void CSMWorld::ContainerRefIdAdapter::setData (const RefIdColumn *column, RefIdD NameRefIdAdapter::setData (column, data, index, value); } -void CSMWorld::ContainerRefIdAdapter::setNestedData(const RefIdColumn *column, - RefIdData& data, - int index, - const QVariant& value, - int subRowIndex, - int subColIndex) const -{ - - if (column==mContent) - { - mHelper.setNestedData(column, data, index, value, subRowIndex, subColIndex); - } else - { - throw std::logic_error("This column do not nest other columns"); - } -} - -void CSMWorld::ContainerRefIdAdapter::setNestedTable(const RefIdColumn* column, - RefIdData& data, - int index, - const NestedTableWrapperBase& nestedTable) -{ - mHelper.setNestedTable(column, data, index, nestedTable); -} - -CSMWorld::NestedTableWrapperBase* CSMWorld::ContainerRefIdAdapter::nestedTable (const RefIdColumn* column, - const RefIdData& data, - int index) const -{ - return mHelper.nestedTable(column, data, index); -} - -QVariant CSMWorld::ContainerRefIdAdapter::getNestedData (const CSMWorld::RefIdColumn* column, - const CSMWorld::RefIdData& data, - int index, - int subRowIndex, - int subColIndex) const -{ - if (column==mContent) - { - return mHelper.getNestedData(column, data, index, subRowIndex, subColIndex); - } else - { - throw std::logic_error("This column do not nest other columns"); - } -} - - CSMWorld::CreatureColumns::CreatureColumns (const ActorColumns& actorColumns) : ActorColumns (actorColumns) {} diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index aac2ba807..ee069dd38 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -616,36 +616,16 @@ namespace CSMWorld const RefIdColumn *mRespawn; const RefIdColumn *mContent; - InventoryHelper mHelper; - public: ContainerRefIdAdapter (const NameColumns& columns, const RefIdColumn *weight, const RefIdColumn *organic, const RefIdColumn *respawn, const RefIdColumn *content); - virtual QVariant getNestedData (const RefIdColumn *column, const RefIdData& data, int index, - int subRowIndex, int subColIndex) const; - virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index) const; - virtual void setNestedData (const RefIdColumn *column, RefIdData& data, int index, - const QVariant& value, int subRowIndex, int subColIndex) const; - virtual void setData (const RefIdColumn *column, RefIdData& data, int index, const QVariant& value) const; ///< If the data type does not match an exception is thrown. - - virtual int getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const; - - virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const; - - virtual void removeNestedRow (const RefIdColumn *column, RefIdData& data, int index, int rowToRemove) const; - - virtual void addNestedRow (const RefIdColumn *column, RefIdData& data, int index, int position) const; - - virtual NestedTableWrapperBase* nestedTable (const RefIdColumn * column, const RefIdData& data, int index) const; - - virtual void setNestedTable (const RefIdColumn* column, RefIdData& data, int index, const NestedTableWrapperBase& nestedTable); }; struct CreatureColumns : public ActorColumns From 9defb188ea83a9de4edba735f688a15dc1329e65 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Tue, 22 Jul 2014 13:08:32 +0200 Subject: [PATCH 0066/3725] handle inventory in the actors --- apps/opencs/model/world/columns.hpp | 1 + apps/opencs/model/world/refidadapterimp.hpp | 14 ++++++++++++-- apps/opencs/model/world/refidcollection.cpp | 4 ++++ 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 283e15db7..6812bbae9 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -179,6 +179,7 @@ namespace CSMWorld ColumnId_Vampire = 164, ColumnId_BodyPartType = 165, ColumnId_MeshType = 166, + ColumnId_ActorInventory = 167, // Allocated to a separate value range, so we don't get a collision should we ever need // to extend the number of use values. diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index ee069dd38..6fe479150 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -445,6 +445,7 @@ namespace CSMWorld const RefIdColumn *mFlee; const RefIdColumn *mFight; const RefIdColumn *mAlarm; + const RefIdColumn *mInventory; std::map mServices; ActorColumns (const NameColumns& base) : NameColumns (base) {} @@ -452,7 +453,7 @@ namespace CSMWorld /// \brief Adapter for actor IDs (handles common AI functionality) template - class ActorRefIdAdapter : public NameRefIdAdapter + class ActorRefIdAdapter : public NameRefIdAdapter, public NestedRefIdAdapter { ActorColumns mActors; @@ -472,7 +473,13 @@ namespace CSMWorld ActorRefIdAdapter::ActorRefIdAdapter (UniversalId::Type type, const ActorColumns& columns) : NameRefIdAdapter (type, columns), mActors (columns) - {} + { + std::vector > assoCol; + + assoCol.push_back(std::make_pair(mActors.mInventory, new InventoryHelper(type))); + + setAssocColumns(assoCol); + } template QVariant ActorRefIdAdapter::getData (const RefIdColumn *column, const RefIdData& data, @@ -496,6 +503,9 @@ namespace CSMWorld if (column==mActors.mAlarm) return record.get().mAiData.mAlarm; + if (column==mActors.mInventory) + return true; + std::map::const_iterator iter = mActors.mServices.find (column); diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 80ac1cc3b..493b716eb 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -99,6 +99,10 @@ CSMWorld::RefIdCollection::RefIdCollection() actorsColumns.mFight = &mColumns.back(); mColumns.push_back (RefIdColumn (Columns::ColumnId_AiAlarm, ColumnBase::Display_Integer)); actorsColumns.mAlarm = &mColumns.back(); + mColumns.push_back(RefIdColumn (Columns::ColumnId_ActorInventory, ColumnBase::Display_NestedItemList, ColumnBase::Flag_Dialogue, true, true, true)); + actorsColumns.mInventory = &mColumns.back(); + mColumns.back().addNestedColumn(Columns::ColumnId_InventoryItemId, CSMWorld::ColumnBase::Display_String); + mColumns.back().addNestedColumn(Columns::ColumnId_ItemCount, CSMWorld::ColumnBase::Display_Integer); static const struct { From 72b129b90e662c10df1d756ea0875197bb517523 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Tue, 22 Jul 2014 17:44:56 +0200 Subject: [PATCH 0067/3725] Code shuffling. Created CastableHelper to store actually usefull function. --- apps/opencs/model/world/nestedadaptors.hpp | 55 +++++++++++++--------- 1 file changed, 32 insertions(+), 23 deletions(-) diff --git a/apps/opencs/model/world/nestedadaptors.hpp b/apps/opencs/model/world/nestedadaptors.hpp index 806dc587d..3807f0219 100644 --- a/apps/opencs/model/world/nestedadaptors.hpp +++ b/apps/opencs/model/world/nestedadaptors.hpp @@ -60,25 +60,47 @@ namespace CSMWorld }; template - class InventoryHelper : public HelperBase + class CastableHelper : public HelperBase + { + + public: + CastableHelper(CSMWorld::UniversalId::Type type) + : HelperBase(type) {} + + protected: + const Record& getRecord(const RefIdData& data, int index) const + { + return dynamic_cast&> ( + data.getRecord (RefIdData::LocalIndex (index, mType))); + } + + Record& getRecord(RefIdData& data, int index) const + { + return dynamic_cast&> ( + data.getRecord (RefIdData::LocalIndex (index, mType))); + } + }; + + template + class InventoryHelper : public CastableHelper { public: InventoryHelper(CSMWorld::UniversalId::Type type) - : HelperBase(type) {} + : CastableHelper(type) {} virtual void setNestedTable(RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) { - getRecord(data, index).get().mInventory.mList = + CastableHelper::getRecord(data, index).get().mInventory.mList = (static_cast >&>(nestedTable)).mNestedTable; } virtual NestedTableWrapperBase* nestedTable(const RefIdData& data, int index) const { - return new NestedTableWrapper >(getRecord(data, index).get().mInventory.mList); + return new NestedTableWrapper >(CastableHelper::getRecord(data, index).get().mInventory.mList); } virtual QVariant getNestedData(const CSMWorld::RefIdData& data, @@ -86,7 +108,7 @@ namespace CSMWorld int subRowIndex, int subColIndex) const { - const ESM::ContItem& content = getRecord(data, index).get().mInventory.mList.at(subRowIndex); + const ESM::ContItem& content = CastableHelper::getRecord(data, index).get().mInventory.mList.at(subRowIndex); switch (subColIndex) { @@ -103,7 +125,7 @@ namespace CSMWorld virtual void removeNestedRow (RefIdData& data, int index, int rowToRemove) const { - std::vector& list = getRecord(data, index).get().mInventory.mList; + std::vector& list = CastableHelper::getRecord(data, index).get().mInventory.mList; list.erase (list.begin () + rowToRemove); } @@ -117,11 +139,11 @@ namespace CSMWorld switch(subColIndex) { case 0: - getRecord(data, index).get().mInventory.mList.at(subRowIndex).mItem.assign(std::string(value.toString().toUtf8().constData())); + CastableHelper::getRecord(data, index).get().mInventory.mList.at(subRowIndex).mItem.assign(std::string(value.toString().toUtf8().constData())); break; case 1: - getRecord(data, index).get().mInventory.mList.at(subRowIndex).mCount = value.toInt(); + CastableHelper::getRecord(data, index).get().mInventory.mList.at(subRowIndex).mCount = value.toInt(); break; default: @@ -131,7 +153,7 @@ namespace CSMWorld virtual void addNestedRow (RefIdData& data, int index, int position) const { - std::vector& list = getRecord(data, index).get().mInventory.mList; + std::vector& list = CastableHelper::getRecord(data, index).get().mInventory.mList; ESM::ContItem newRow = {0, ""}; if (position >= (int)list.size()) @@ -152,22 +174,9 @@ namespace CSMWorld virtual int getNestedRowsCount(const RefIdData& data, int index) const { - return getRecord(data, index).get().mInventory.mList.size(); - } - - private: - - const Record& getRecord(const RefIdData& data, int index) const - { - return dynamic_cast&> ( - data.getRecord (RefIdData::LocalIndex (index, mType))); + return CastableHelper::getRecord(data, index).get().mInventory.mList.size(); } - Record& getRecord(RefIdData& data, int index) const - { - return dynamic_cast&> ( - data.getRecord (RefIdData::LocalIndex (index, mType))); - } }; } From a676f6bc2cad308e924e2a32b3f51e679d99c4f6 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Wed, 23 Jul 2014 20:33:52 +0200 Subject: [PATCH 0068/3725] comments added --- apps/opencs/model/world/nestedadaptors.hpp | 4 ++++ apps/opencs/model/world/refidadapter.hpp | 10 ++++++++++ 2 files changed, 14 insertions(+) diff --git a/apps/opencs/model/world/nestedadaptors.hpp b/apps/opencs/model/world/nestedadaptors.hpp index 3807f0219..0bb998316 100644 --- a/apps/opencs/model/world/nestedadaptors.hpp +++ b/apps/opencs/model/world/nestedadaptors.hpp @@ -13,6 +13,10 @@ #include +/*! \brief + * Nested adapter redirects responsibility to the helper class. Helper classes are polymorhpic (vide HelperBase and CastableHelper) and most likely templates. + */ + namespace CSMWorld { class RefIdColumn; diff --git a/apps/opencs/model/world/refidadapter.hpp b/apps/opencs/model/world/refidadapter.hpp index dd2248e92..22941fd9f 100644 --- a/apps/opencs/model/world/refidadapter.hpp +++ b/apps/opencs/model/world/refidadapter.hpp @@ -6,6 +6,12 @@ #include "nestedadaptors.hpp" +/*! \brief + * Adaptors acts as indirection layer, abstracting details of the record types (in the wrappers) from the higher levels of model. + * Please notice that nested adaptor uses helper classes for actually performing any actions. Different record types require different helpers (needs to be created in the subclass and then fetched via member function). + * Important point: don't forget to make sure that getData on the nestedColumn returns true (otherwise code will not treat the index pointing to the column as having childs! + */ + class QVariant; namespace CSMWorld @@ -30,6 +36,7 @@ namespace CSMWorld virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int idnex) const = 0; + ///< If called on the nest column, should return QVariant(true). virtual void setData (const RefIdColumn *column, RefIdData& data, int index, const QVariant& value) const = 0; @@ -95,6 +102,9 @@ namespace CSMWorld protected: void setAssocColumns(const std::vector >& assocColumns); + ///The ownership of the Helper pointers is transfered. + ///The ownership of the column pointers it not transfered (it is not surprising, since columns are created by collection). + ///You MUST call this method to setup the nested adaptor! private: From 864b93e745fd9072b9810c82c866e7fb3e1210b4 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Fri, 25 Jul 2014 11:25:36 +0200 Subject: [PATCH 0069/3725] added enums for spells --- apps/opencs/model/world/columns.cpp | 1 + apps/opencs/model/world/columns.hpp | 2 ++ apps/opencs/model/world/refidadapterimp.hpp | 1 + apps/opencs/model/world/refidcollection.cpp | 4 ++++ 4 files changed, 8 insertions(+) diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 83d0ccc79..1f13645da 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -175,6 +175,7 @@ namespace CSMWorld { ColumnId_Scope, "Scope" }, { ColumnId_ReferenceableId, "Referenceable ID" }, { ColumnId_InventoryItemId, "ID"}, + { ColumnId_SpellId, "ID"}, { ColumnId_ItemCount, "Count"}, { ColumnId_CombatState, "Combat" }, { ColumnId_MagicState, "Magic" }, diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 6812bbae9..908165e9d 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -180,6 +180,8 @@ namespace CSMWorld ColumnId_BodyPartType = 165, ColumnId_MeshType = 166, ColumnId_ActorInventory = 167, + ColumnId_ActorSpells = 168, + ColumnId_SpellId = 169, // Allocated to a separate value range, so we don't get a collision should we ever need // to extend the number of use values. diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index 6fe479150..ee2a58624 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -446,6 +446,7 @@ namespace CSMWorld const RefIdColumn *mFight; const RefIdColumn *mAlarm; const RefIdColumn *mInventory; + const RefIdColumn *mSpells; std::map mServices; ActorColumns (const NameColumns& base) : NameColumns (base) {} diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 493b716eb..89469feac 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -104,6 +104,10 @@ CSMWorld::RefIdCollection::RefIdCollection() mColumns.back().addNestedColumn(Columns::ColumnId_InventoryItemId, CSMWorld::ColumnBase::Display_String); mColumns.back().addNestedColumn(Columns::ColumnId_ItemCount, CSMWorld::ColumnBase::Display_Integer); + mColumns.push_back(RefIdColumn (Columns::ColumnId_ActorSpells, ColumnBase::Display_NestedSpellList, ColumnBase::Flag_Dialogue, true, true, true)); + actorsColumns.mSpells = &mColumns.back(); + mColumns.back().addNestedColumn(Columns::ColumnId_SpellId, CSMWorld::ColumnBase::Display_String); + static const struct { int mName; From 39545670a887fb29266964e6c4506dd2a1cc2c02 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Fri, 25 Jul 2014 12:09:25 +0200 Subject: [PATCH 0070/3725] Added spells table (and it works!) --- apps/opencs/model/world/columnbase.hpp | 1 + apps/opencs/model/world/nestedadaptors.hpp | 87 +++++++++++++++++++++ apps/opencs/model/world/refidadapterimp.hpp | 4 + apps/opencs/model/world/refidcollection.cpp | 4 +- 4 files changed, 94 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index 096491f1e..5e4dac3ce 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -94,6 +94,7 @@ namespace CSMWorld //Those are top level columns that nest other columns Display_NestedItemList, + Display_NestedSpellList, Display_EnchantmentType, Display_BodyPartType, diff --git a/apps/opencs/model/world/nestedadaptors.hpp b/apps/opencs/model/world/nestedadaptors.hpp index 0bb998316..095bcdf95 100644 --- a/apps/opencs/model/world/nestedadaptors.hpp +++ b/apps/opencs/model/world/nestedadaptors.hpp @@ -2,6 +2,7 @@ #define CSM_WORLD_NESTEDADAPTORS_H #include +#include #include #include "universalid.hpp" @@ -85,6 +86,92 @@ namespace CSMWorld } }; + template + class SpellsHelper : public CastableHelper + { + public: + + SpellsHelper(CSMWorld::UniversalId::Type type) + : CastableHelper(type) {} + + virtual void setNestedTable(RefIdData& data, + int index, + const NestedTableWrapperBase& nestedTable) + { + CastableHelper::getRecord(data, index).get().mSpells.mList = + (static_cast >&>(nestedTable)).mNestedTable; + } + + virtual NestedTableWrapperBase* nestedTable(const RefIdData& data, + int index) const + { + return new NestedTableWrapper >(CastableHelper::getRecord(data, index).get().mSpells.mList); + } + + virtual QVariant getNestedData(const CSMWorld::RefIdData& data, + int index, + int subRowIndex, + int subColIndex) const + { + const std::string& content = CastableHelper::getRecord(data, index).get().mSpells.mList.at(subRowIndex); + + if (subColIndex == 0) + { + return QString::fromUtf8(content.c_str()); + } + + throw std::logic_error("Trying to access non-existing column in the nested table!"); + } + + virtual void removeNestedRow (RefIdData& data, int index, int rowToRemove) const + { + std::vector& list = CastableHelper::getRecord(data, index).get().mSpells.mList; + + list.erase (list.begin () + rowToRemove); + } + + void setNestedData (RefIdData& data, + int index, + const QVariant& value, + int subRowIndex, + int subColIndex) const + { + if (subColIndex == 0) + { + CastableHelper::getRecord(data, index).get().mSpells.mList.at(subRowIndex) = std::string(value.toString().toUtf8()); + } + + throw std::logic_error("Trying to access non-existing column in the nested table!"); + } + + virtual void addNestedRow (RefIdData& data, int index, int position) const + { + std::vector& list = CastableHelper::getRecord(data, index).get().mSpells.mList; + + std::string newString; + if (position >= (int)list.size()) + { + list.push_back(newString); + return; + } + + list.insert(list.begin()+position, newString); + } + + virtual int getNestedColumnsCount(const RefIdData& data) const + { + return 1; + } + + + virtual int getNestedRowsCount(const RefIdData& data, + int index) const + { + return CastableHelper::getRecord(data, index).get().mSpells.mList.size(); + } + + }; + template class InventoryHelper : public CastableHelper { diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index ee2a58624..4c65da85c 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -478,6 +478,7 @@ namespace CSMWorld std::vector > assoCol; assoCol.push_back(std::make_pair(mActors.mInventory, new InventoryHelper(type))); + assoCol.push_back(std::make_pair(mActors.mSpells, new SpellsHelper(type))); setAssocColumns(assoCol); } @@ -507,6 +508,9 @@ namespace CSMWorld if (column==mActors.mInventory) return true; + if (column==mActors.mSpells) + return true; + std::map::const_iterator iter = mActors.mServices.find (column); diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 89469feac..eb25b277e 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -1,4 +1,3 @@ - #include "refidcollection.hpp" #include @@ -99,6 +98,7 @@ CSMWorld::RefIdCollection::RefIdCollection() actorsColumns.mFight = &mColumns.back(); mColumns.push_back (RefIdColumn (Columns::ColumnId_AiAlarm, ColumnBase::Display_Integer)); actorsColumns.mAlarm = &mColumns.back(); + mColumns.push_back(RefIdColumn (Columns::ColumnId_ActorInventory, ColumnBase::Display_NestedItemList, ColumnBase::Flag_Dialogue, true, true, true)); actorsColumns.mInventory = &mColumns.back(); mColumns.back().addNestedColumn(Columns::ColumnId_InventoryItemId, CSMWorld::ColumnBase::Display_String); @@ -665,6 +665,6 @@ CSMWorld::NestedTableWrapperBase* CSMWorld::RefIdCollection::nestedTable(int row RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); const CSMWorld::NestedRefIdAdapter& adaptor = dynamic_cast(findAdaptor (localIndex.second)); - + return adaptor.nestedTable(&mColumns.at(column), mData, localIndex.first); } From ade27293be7cd76163c917602c8d092925623367 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Fri, 25 Jul 2014 17:11:18 +0200 Subject: [PATCH 0071/3725] handling destination for guides --- apps/opencs/model/world/columnbase.hpp | 1 + apps/opencs/model/world/columns.cpp | 9 ++ apps/opencs/model/world/columns.hpp | 8 ++ apps/opencs/model/world/nestedadaptors.hpp | 145 ++++++++++++++++++++ apps/opencs/model/world/refidadapter.cpp | 5 + apps/opencs/model/world/refidadapter.hpp | 3 + apps/opencs/model/world/refidadapterimp.cpp | 9 +- apps/opencs/model/world/refidadapterimp.hpp | 1 + apps/opencs/model/world/refidcollection.cpp | 10 ++ 9 files changed, 189 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index 5e4dac3ce..05fecaec0 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -95,6 +95,7 @@ namespace CSMWorld //Those are top level columns that nest other columns Display_NestedItemList, Display_NestedSpellList, + Display_NestedDestinationsList, Display_EnchantmentType, Display_BodyPartType, diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 1f13645da..212772450 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -174,6 +174,7 @@ namespace CSMWorld { ColumnId_PcRank, "PC Rank" }, { ColumnId_Scope, "Scope" }, { ColumnId_ReferenceableId, "Referenceable ID" }, + { ColumnId_NpcDestinations, "Destinations" }, { ColumnId_InventoryItemId, "ID"}, { ColumnId_SpellId, "ID"}, { ColumnId_ItemCount, "Count"}, @@ -184,6 +185,14 @@ namespace CSMWorld { ColumnId_Vampire, "Vampire" }, { ColumnId_BodyPartType, "Bodypart Type" }, { ColumnId_MeshType, "Mesh Type" }, + + { ColumnId_NpcDestinations, "Cell"}, + { ColumnId_PosX, "X"}, + { ColumnId_PosY, "Y"}, + { ColumnId_PosZ, "Z"}, + { ColumnId_RotX, "Rotation X"}, + { ColumnId_RotY, "Rotation Y"}, + { ColumnId_RotZ, "Rotation Z"}, { ColumnId_UseValue1, "Use value 1" }, { ColumnId_UseValue2, "Use value 2" }, diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 908165e9d..7efaf2bd0 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -182,6 +182,14 @@ namespace CSMWorld ColumnId_ActorInventory = 167, ColumnId_ActorSpells = 168, ColumnId_SpellId = 169, + ColumnId_NpcDestinations = 170, + ColumnId_PosX = 171, + ColumnId_PosY = 172, + ColumnId_PosZ = 173, + ColumnId_RotX = 174, + ColumnId_RotY = 175, + ColumnId_RotZ = 176, + ColumnId_DestinationCell = 177, // Allocated to a separate value range, so we don't get a collision should we ever need // to extend the number of use values. diff --git a/apps/opencs/model/world/nestedadaptors.hpp b/apps/opencs/model/world/nestedadaptors.hpp index 095bcdf95..319fe1569 100644 --- a/apps/opencs/model/world/nestedadaptors.hpp +++ b/apps/opencs/model/world/nestedadaptors.hpp @@ -11,6 +11,8 @@ #include "refiddata.hpp" #include "refidadapter.hpp" #include +#include +#include #include @@ -172,6 +174,149 @@ namespace CSMWorld }; + template + class DestinationsHelper : public CastableHelper + { + public: + + DestinationsHelper(CSMWorld::UniversalId::Type type) + : CastableHelper(type) {} + + virtual void setNestedTable(RefIdData& data, + int index, + const NestedTableWrapperBase& nestedTable) + { + CastableHelper::getRecord(data, index).get().mTransport = + (static_cast >&>(nestedTable)).mNestedTable; + } + + virtual NestedTableWrapperBase* nestedTable(const RefIdData& data, + int index) const + { + return new NestedTableWrapper >(CastableHelper::getRecord(data, index).get().mTransport); + } + + virtual QVariant getNestedData(const CSMWorld::RefIdData& data, + int index, + int subRowIndex, + int subColIndex) const + { + const ESM::NPC::Dest& content = CastableHelper::getRecord(data, index).get().mTransport.at(subRowIndex); + + switch (subColIndex) + { + case 0: + return QString::fromUtf8(content.mCellName.c_str()); + + case 1: + return content.mPos.pos[0]; + + case 2: + return content.mPos.pos[1]; + + case 3: + return content.mPos.pos[2]; + + case 4: + return content.mPos.rot[0]; + + case 5: + return content.mPos.rot[1]; + + case 6: + return content.mPos.rot[2]; + + default: + throw std::logic_error("Trying to access non-existing column in the nested table!"); + } + } + + virtual void removeNestedRow (RefIdData& data, int index, int rowToRemove) const + { + std::vector& list = CastableHelper::getRecord(data, index).get().mTransport; + + list.erase (list.begin () + rowToRemove); + } + + void setNestedData (RefIdData& data, + int index, + const QVariant& value, + int subRowIndex, + int subColIndex) const + { + switch(subColIndex) + { + case 0: + CastableHelper::getRecord(data, index).get().mTransport.at(subRowIndex).mCellName = std::string(value.toString().toUtf8().constData()); + break; + + case 1: + CastableHelper::getRecord(data, index).get().mTransport.at(subRowIndex).mPos.pos[0] = value.toFloat(); + break; + + case 2: + CastableHelper::getRecord(data, index).get().mTransport.at(subRowIndex).mPos.pos[1] = value.toFloat(); + break; + + case 3: + CastableHelper::getRecord(data, index).get().mTransport.at(subRowIndex).mPos.pos[2] = value.toFloat(); + break; + + case 4: + CastableHelper::getRecord(data, index).get().mTransport.at(subRowIndex).mPos.rot[0] = value.toFloat(); + break; + + case 5: + CastableHelper::getRecord(data, index).get().mTransport.at(subRowIndex).mPos.rot[1] = value.toFloat(); + break; + + case 6: + CastableHelper::getRecord(data, index).get().mTransport.at(subRowIndex).mPos.rot[2] = value.toFloat(); + break; + + default: + throw std::logic_error("Trying to access non-existing column in the nested table!"); + } + } + + virtual void addNestedRow (RefIdData& data, int index, int position) const + { + std::vector& list = CastableHelper::getRecord(data, index).get().mTransport; + + ESM::Position newPos; + for (unsigned i = 0; i < 3; ++i) + { + newPos.pos[i] = 0; + newPos.rot[i] = 0; + } + + ESM::NPC::Dest newRow; + newRow.mPos = newPos; + newRow.mCellName = ""; + + if (position >= (int)list.size()) + { + list.push_back(newRow); + return; + } + + list.insert(list.begin()+position, newRow); + } + + virtual int getNestedColumnsCount(const RefIdData& data) const + { + return 7; + } + + + virtual int getNestedRowsCount(const RefIdData& data, + int index) const + { + return CastableHelper::getRecord(data, index).get().mTransport.size(); + } + + }; + template class InventoryHelper : public CastableHelper { diff --git a/apps/opencs/model/world/refidadapter.cpp b/apps/opencs/model/world/refidadapter.cpp index 631c192fd..58b775f47 100644 --- a/apps/opencs/model/world/refidadapter.cpp +++ b/apps/opencs/model/world/refidadapter.cpp @@ -87,3 +87,8 @@ void CSMWorld::NestedRefIdAdapter::setAssocColumns(const std::vector& assocColumn) +{ + mAssociatedColumns.push_back(assocColumn); +} diff --git a/apps/opencs/model/world/refidadapter.hpp b/apps/opencs/model/world/refidadapter.hpp index 22941fd9f..d18e7f02e 100644 --- a/apps/opencs/model/world/refidadapter.hpp +++ b/apps/opencs/model/world/refidadapter.hpp @@ -106,6 +106,9 @@ namespace CSMWorld ///The ownership of the column pointers it not transfered (it is not surprising, since columns are created by collection). ///You MUST call this method to setup the nested adaptor! + void addAssocColumn(const std::pair & assocColumn); + ///Like setAssocColumn, when it is impossible to set all columns at once + private: HelperBase* getHelper(const RefIdColumn *column) const; diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index 18287d596..ac546db51 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -452,7 +452,9 @@ CSMWorld::NpcColumns::NpcColumns (const ActorColumns& actorColumns) : ActorColum CSMWorld::NpcRefIdAdapter::NpcRefIdAdapter (const NpcColumns& columns) : ActorRefIdAdapter (UniversalId::Type_Npc, columns), mColumns (columns) -{} +{ + NestedRefIdAdapter::addAssocColumn(std::make_pair(columns.mDestinations, new DestinationsHelper(UniversalId::Type_Npc))); +} QVariant CSMWorld::NpcRefIdAdapter::getData (const RefIdColumn *column, const RefIdData& data, int index) const @@ -474,13 +476,16 @@ QVariant CSMWorld::NpcRefIdAdapter::getData (const RefIdColumn *column, const Re if (column==mColumns.mHead) return QString::fromUtf8 (record.get().mHead.c_str()); + + if (column==mColumns.mDestinations) + return true; std::map::const_iterator iter = mColumns.mFlags.find (column); if (iter!=mColumns.mFlags.end()) return (record.get().mFlags & iter->second)!=0; - + return ActorRefIdAdapter::getData (column, data, index); } diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index 4c65da85c..6fd42b00e 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -742,6 +742,7 @@ namespace CSMWorld const RefIdColumn *mFaction; const RefIdColumn *mHair; const RefIdColumn *mHead; + const RefIdColumn *mDestinations; NpcColumns (const ActorColumns& actorColumns); }; diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index eb25b277e..d776931f8 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -315,6 +315,16 @@ CSMWorld::RefIdCollection::RefIdCollection() npcColumns.mFlags.insert (std::make_pair (metalBlood, ESM::NPC::Metal)); + mColumns.push_back(RefIdColumn (Columns::ColumnId_NpcDestinations, ColumnBase::Display_NestedDestinationsList, ColumnBase::Flag_Dialogue, true, true, true)); + npcColumns.mDestinations = &mColumns.back(); + mColumns.back().addNestedColumn(Columns::ColumnId_DestinationCell, CSMWorld::ColumnBase::Display_String); + mColumns.back().addNestedColumn(Columns::ColumnId_PosX, CSMWorld::ColumnBase::Display_Float); + mColumns.back().addNestedColumn(Columns::ColumnId_PosY, CSMWorld::ColumnBase::Display_Float); + mColumns.back().addNestedColumn(Columns::ColumnId_PosZ, CSMWorld::ColumnBase::Display_Float); + mColumns.back().addNestedColumn(Columns::ColumnId_RotX, CSMWorld::ColumnBase::Display_Float); + mColumns.back().addNestedColumn(Columns::ColumnId_RotY, CSMWorld::ColumnBase::Display_Float); + mColumns.back().addNestedColumn(Columns::ColumnId_RotZ, CSMWorld::ColumnBase::Display_Float); + WeaponColumns weaponColumns (enchantableColumns); mColumns.push_back (RefIdColumn (Columns::ColumnId_WeaponType, ColumnBase::Display_WeaponType)); From 6a9c7c9f8699e852c0fc712cab5dec4f4ce49fb5 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Mon, 28 Jul 2014 17:33:21 +0200 Subject: [PATCH 0072/3725] fix for bug 1672 --- apps/opencs/model/doc/document.cpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 23a47b313..644d32e84 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -1,6 +1,7 @@ #include "document.hpp" #include +#include #include @@ -2217,16 +2218,18 @@ CSMDoc::Document::Document (const Files::ConfigurationManager& configuration, if (!boost::filesystem::exists (mProjectPath)) { - boost::filesystem::path locCustomFiltersPath (configuration.getUserDataPath()); - locCustomFiltersPath /= "defaultfilters"; + boost::filesystem::path customFiltersPath (configuration.getUserDataPath()); + customFiltersPath /= "defaultfilters"; + + std::string destinationPath = mProjectPath.string() + "/defaultfilters"; + std::ofstream dst(destinationPath.c_str(), std::ios::binary); - if (boost::filesystem::exists (locCustomFiltersPath)) + if (boost::filesystem::exists (customFiltersPath)) { - boost::filesystem::copy_file (locCustomFiltersPath, mProjectPath); - } - else + dst< Date: Wed, 30 Jul 2014 17:07:11 +0200 Subject: [PATCH 0073/3725] saving progress --- apps/opencs/model/doc/document.cpp | 4 +- apps/opencs/model/world/columns.cpp | 7 ++ apps/opencs/model/world/columns.hpp | 1 + apps/opencs/model/world/commands.cpp | 18 +-- apps/opencs/model/world/nestedadaptors.hpp | 128 ++++++++++++++++++++- apps/opencs/view/world/enumdelegate.cpp | 1 - 6 files changed, 148 insertions(+), 11 deletions(-) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 644d32e84..eb03be085 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -2,6 +2,7 @@ #include #include +#include #include @@ -2221,8 +2222,7 @@ CSMDoc::Document::Document (const Files::ConfigurationManager& configuration, boost::filesystem::path customFiltersPath (configuration.getUserDataPath()); customFiltersPath /= "defaultfilters"; - std::string destinationPath = mProjectPath.string() + "/defaultfilters"; - std::ofstream dst(destinationPath.c_str(), std::ios::binary); + std::ofstream dst(mProjectPath.c_str(), std::ios::binary); if (boost::filesystem::exists (customFiltersPath)) { diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 212772450..0c44c2dcb 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -24,6 +24,7 @@ namespace CSMWorld { ColumnId_ValueType, "Value Type" }, { ColumnId_Description, "Description" }, { ColumnId_Specialisation, "Specialisation" }, + { ColumnId_Skill, "Skill" }, { ColumnId_Attribute, "Attribute" }, { ColumnId_Name, "Name" }, { ColumnId_Playable, "Playable" }, @@ -248,6 +249,11 @@ int CSMWorld::Columns::getId (const std::string& name) namespace { + static const char *sSkills[] = + { + "Long Blade" + }; + static const char *sSpecialisations[] = { "Combat", "Magic", "Stealth", 0 @@ -339,6 +345,7 @@ namespace switch (column) { case CSMWorld::Columns::ColumnId_Specialisation: return sSpecialisations; + case CSMWorld::Columns::ColumnId_Skill: return sSkills; case CSMWorld::Columns::ColumnId_Attribute: return sAttributes; case CSMWorld::Columns::ColumnId_SpellType: return sSpellTypes; case CSMWorld::Columns::ColumnId_ApparatusType: return sApparatusTypes; diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 7efaf2bd0..b06018dd4 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -190,6 +190,7 @@ namespace CSMWorld ColumnId_RotY = 175, ColumnId_RotZ = 176, ColumnId_DestinationCell = 177, + ColumnId_Skill = 178, // Allocated to a separate value range, so we don't get a collision should we ever need // to extend the number of use values. diff --git a/apps/opencs/model/world/commands.cpp b/apps/opencs/model/world/commands.cpp index 0d9f6c773..30c4bb892 100644 --- a/apps/opencs/model/world/commands.cpp +++ b/apps/opencs/model/world/commands.cpp @@ -173,13 +173,17 @@ void CSMWorld::CloneCommand::undo() mModel.removeRow (mModel.getModelIndex (mIdDestination, 0).row()); } -CSMWorld::DeleteNestedCommand::DeleteNestedCommand (IdTable& model, const std::string& id, int nestedRow, int parentColumn, QUndoCommand* parent) - : mId(id), - mModel(model), - mParentColumn(parentColumn), - QUndoCommand(parent), - mNestedRow(nestedRow), - NestedTableStoring(model, id, parentColumn) +CSMWorld::DeleteNestedCommand::DeleteNestedCommand (IdTable& model, + const std::string& id, + int nestedRow, + int parentColumn, + QUndoCommand* parent) : + mId(id), + mModel(model), + mParentColumn(parentColumn), + QUndoCommand(parent), + mNestedRow(nestedRow), + NestedTableStoring(model, id, parentColumn) { setText (("Delete nested row in " + mId).c_str()); } diff --git a/apps/opencs/model/world/nestedadaptors.hpp b/apps/opencs/model/world/nestedadaptors.hpp index 319fe1569..6e3d447b2 100644 --- a/apps/opencs/model/world/nestedadaptors.hpp +++ b/apps/opencs/model/world/nestedadaptors.hpp @@ -13,6 +13,9 @@ #include #include #include +#include +#include +#include #include @@ -174,6 +177,129 @@ namespace CSMWorld }; + /* + template + class MagicEffectsHelper : public CastableHelper + { + public: + + MagicEffectsHelper(CSMWorld::UniversalId::Type type) + : CastableHelper(type) {} + + virtual void setNestedTable(RefIdData& data, + int index, + const NestedTableWrapperBase& nestedTable) + { + CastableHelper::getRecord(data, index).get().mEffects = + (static_cast&>(nestedTable)).mNestedTable; + } + + virtual NestedTableWrapperBase* nestedTable(const RefIdData& data, + int index) const + { + return new NestedTableWrapper(CastableHelper::getRecord(data, index).get().mEffects); + } + + virtual QVariant getNestedData(const CSMWorld::RefIdData& data, + int index, + int subRowIndex, + int subColIndex) const + { + const ESM::EffectList& content = CastableHelper::getRecord(data, index).get().mEffects; + + switch (subColIndex) + { + case 0: + return content.at(subRowIndex).mEffectID; + + case 1: + return content.at(subRowIndex).mRange; + + case 2: + return content.at(subRowIndex).mDuration; + + case 3: + return content.at(subRowIndex).mArea; + + case 4: + return content.at(subRowIndex).mMagMin; + + case 5: + return content.at(subRowIndex).mMagMax; + + case 6: + return (int)content.at(rubRowIndex).mSkill; + + case 7: + return (int)content.at(subRowIndex).mAttribute; + + default: + throw std::logic_error("Trying to access non-existing column in the nested table!"); + } + } + + virtual void removeNestedRow (RefIdData& data, int index, int rowToRemove) const + { + ESM::EffectList& list = CastableHelper::getRecord(data, index).get().mEffects; + + list.erase (list.begin () + rowToRemove); + } + + void setNestedData (RefIdData& data, + int index, + const QVariant& value, + int subRowIndex, + int subColIndex) const + { + switch(subColIndex) + { + case 0: + CastableHelper::getRecord(data, index).get().mEffects.at(subRowIndex).mEffectID = value.toInt(); + break; + + default: + throw std::logic_error("Trying to access non-existing column in the nested table!"); + } + } + + virtual void addNestedRow (RefIdData& data, int index, int position) const + { + std::vector& list = CastableHelper::getRecord(data, index).get().mTransport; + + ESM::Position newPos; + for (unsigned i = 0; i < 3; ++i) + { + newPos.pos[i] = 0; + newPos.rot[i] = 0; + } + + ESM::NPC::Dest newRow; + newRow.mPos = newPos; + newRow.mCellName = ""; + + if (position >= (int)list.size()) + { + list.push_back(newRow); + return; + } + + list.insert(list.begin()+position, newRow); + } + + virtual int getNestedColumnsCount(const RefIdData& data) const + { + return 7; + } + + + virtual int getNestedRowsCount(const RefIdData& data, + int index) const + { + return CastableHelper::getRecord(data, index).get().mTransport.size(); + } + + }; + */ template class DestinationsHelper : public CastableHelper { @@ -316,7 +442,7 @@ namespace CSMWorld } }; - + template class InventoryHelper : public CastableHelper { diff --git a/apps/opencs/view/world/enumdelegate.cpp b/apps/opencs/view/world/enumdelegate.cpp index 377f479bf..16f38938d 100644 --- a/apps/opencs/view/world/enumdelegate.cpp +++ b/apps/opencs/view/world/enumdelegate.cpp @@ -46,7 +46,6 @@ QWidget *CSVWorld::EnumDelegate::createEditor(QWidget *parent, const QModelIndex& index) const { return createEditor(parent, option, index, CSMWorld::ColumnBase::Display_None); - //overloading virtual functions is HARD } QWidget *CSVWorld::EnumDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem& option, From c6194e7ea3352918e41d2bd7118294909651d7e8 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Wed, 30 Jul 2014 22:08:55 +0200 Subject: [PATCH 0074/3725] inserted additional class for nested collections --- apps/opencs/model/world/collection.hpp | 43 --------------------- apps/opencs/model/world/collectionbase.cpp | 27 ------------- apps/opencs/model/world/collectionbase.hpp | 40 +++++++++++-------- apps/opencs/model/world/idtable.cpp | 30 +++++++------- apps/opencs/model/world/refidcollection.hpp | 2 +- 5 files changed, 40 insertions(+), 102 deletions(-) diff --git a/apps/opencs/model/world/collection.hpp b/apps/opencs/model/world/collection.hpp index 591074372..252e84c38 100644 --- a/apps/opencs/model/world/collection.hpp +++ b/apps/opencs/model/world/collection.hpp @@ -17,8 +17,6 @@ #include "collectionbase.hpp" -#include "nestedtablewrapper.hpp" - namespace CSMWorld { /// \brief Access to ID field in records @@ -77,10 +75,6 @@ namespace CSMWorld virtual int getSize() const; - virtual int getNestedColumnsCount(int column) const; - - virtual int getNestedRowsCount(int row, int column) const; - virtual std::string getId (int index) const; virtual int getIndex (const std::string& id) const; @@ -89,14 +83,8 @@ namespace CSMWorld virtual QVariant getData (int index, int column) const; - virtual QVariant getNestedData(int row, int column, int subRow, int subColumn) const; - virtual void setData (int index, int column, const QVariant& data); - virtual NestedTableWrapperBase* nestedTable(int row, int column) const; - - virtual void setNestedTable(int row, int column, const NestedTableWrapperBase& nestedTable); - virtual const ColumnBase& getColumn (int column) const; virtual void merge(); @@ -261,18 +249,6 @@ namespace CSMWorld return mRecords.size(); } - template - int Collection::getNestedRowsCount(int row, int column) const - { - return 0; - } - - template - int Collection::getNestedColumnsCount(int column) const - { - return 0; - } - template std::string Collection::getId (int index) const { @@ -302,25 +278,6 @@ namespace CSMWorld return mColumns.at (column)->get (mRecords.at (index)); } - template - QVariant Collection::getNestedData(int row, int column, int subRow, int subColumn) const - { - return QVariant(); - } - - template - NestedTableWrapperBase* Collection::nestedTable(int row, int column) const - { - assert(false); - return new NestedTableWrapperBase(); - } - - template - void Collection::setNestedTable(int row, int column, const NestedTableWrapperBase& nestedTable) - { - throw std::logic_error("setNestedTable was not overriden"); - } - template void Collection::setData (int index, int column, const QVariant& data) { diff --git a/apps/opencs/model/world/collectionbase.cpp b/apps/opencs/model/world/collectionbase.cpp index a1f4f4a70..5b0c359c9 100644 --- a/apps/opencs/model/world/collectionbase.cpp +++ b/apps/opencs/model/world/collectionbase.cpp @@ -30,30 +30,3 @@ int CSMWorld::CollectionBase::findColumnIndex (Columns::ColumnId id) const return index; } - -void CSMWorld::CollectionBase::setNestedData(int row, int column, const QVariant& data, int subRow, int subColumn) -{ - assert(false); //TODO remove and make pure abstract -} - -int CSMWorld::CollectionBase::getNestedColumnsCount(int row, int column) const -{ - assert(false); //TODO remove and make pure abstract - return 0; -} - -int CSMWorld::CollectionBase::getNestedRowsCount(int row, int column) const -{ - assert(false); //TODO, make pure abstract - return 0; -} - -void CSMWorld::CollectionBase::removeNestedRows(int row, int column, int subRow) -{ - assert(false); //todo, make pure abstract -} - -void CSMWorld::CollectionBase::addNestedRow(int row, int col, int position) -{ - assert(false); -} diff --git a/apps/opencs/model/world/collectionbase.hpp b/apps/opencs/model/world/collectionbase.hpp index a6ee34e56..29ac33bc8 100644 --- a/apps/opencs/model/world/collectionbase.hpp +++ b/apps/opencs/model/world/collectionbase.hpp @@ -13,7 +13,7 @@ namespace CSMWorld { struct ColumnBase; struct RecordBase; - class NestedTableWrapperBase; + class NestedTableWrapperBase; /// \brief Base class for record collections /// @@ -35,10 +35,6 @@ namespace CSMWorld virtual int getSize() const = 0; - virtual int getNestedRowsCount(int row, int column) const; - - virtual int getNestedColumnsCount(int row, int column) const; - virtual std::string getId (int index) const = 0; virtual int getIndex (const std::string& id) const = 0; @@ -49,16 +45,8 @@ namespace CSMWorld virtual QVariant getData (int index, int column) const = 0; - virtual QVariant getNestedData(int row, int column, int subRow, int subColumn) const = 0; - - virtual NestedTableWrapperBase* nestedTable(int row, int column) const = 0; - - virtual void setNestedTable(int row, int column, const NestedTableWrapperBase& nestedTable) = 0; - virtual void setData (int index, int column, const QVariant& data) = 0; - virtual void setNestedData(int row, int column, const QVariant& data, int subRow, int subColumn); - // Not in use. Temporarily removed so that the implementation of RefIdCollection can continue without // these functions for now. // virtual void merge() = 0; @@ -69,10 +57,6 @@ namespace CSMWorld virtual void removeRows (int index, int count) = 0; - virtual void removeNestedRows(int row, int column, int subRow); - - virtual void addNestedRow(int row, int col, int position); - virtual void appendBlankRecord (const std::string& id, UniversalId::Type type = UniversalId::Type_None) = 0; ///< \param type Will be ignored, unless the collection supports multiple record types @@ -121,6 +105,28 @@ namespace CSMWorld ///< Return index of column with the given \a id. If no such column exists, an exception is /// thrown. }; + + class NestedCollection : public CollectionBase + { + public: + virtual void addNestedRow(int row, int col, int position) = 0; + + virtual QVariant getNestedData(int row, int column, int subRow, int subColumn) const = 0; + + virtual NestedTableWrapperBase* nestedTable(int row, int column) const = 0; + + virtual void setNestedTable(int row, int column, const NestedTableWrapperBase& nestedTable) = 0; + + virtual void setNestedData(int row, int column, const QVariant& data, int subRow, int subColumn) = 0; + + virtual int getNestedRowsCount(int row, int column) const = 0; + + virtual int getNestedColumnsCount(int row, int column) const = 0; + + virtual void removeNestedRows(int row, int column, int subRow) = 0; + + + }; } #endif diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index be31d0503..4e4ccb1c1 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -18,7 +18,7 @@ int CSMWorld::IdTable::rowCount (const QModelIndex & parent) const { if (hasChildren(parent)) { - return mIdCollection->getNestedRowsCount(parent.row(), parent.column()); + return dynamic_cast(mIdCollection)->getNestedRowsCount(parent.row(), parent.column()); } return mIdCollection->getSize(); @@ -26,10 +26,9 @@ int CSMWorld::IdTable::rowCount (const QModelIndex & parent) const int CSMWorld::IdTable::columnCount (const QModelIndex & parent) const { - if (parent.isValid() && - parent.data().isValid()) + if (hasChildren(parent)) { - return mIdCollection->getNestedColumnsCount(parent.row(), parent.column()); + return dynamic_cast(mIdCollection)->getNestedColumnsCount(parent.row(), parent.column()); } return mIdCollection->getColumns(); @@ -46,10 +45,10 @@ QVariant CSMWorld::IdTable::data (const QModelIndex & index, int role) const if (index.internalId() != 0) { std::pair parentAdress(unfoldIndexAdress(index.internalId())); - return mIdCollection->getNestedData(parentAdress.first, - parentAdress.second, - index.row(), - index.column()); + return dynamic_cast(mIdCollection)->getNestedData(parentAdress.first, + parentAdress.second, + index.row(), + index.column()); } else { return mIdCollection->getData (index.row(), index.column()); } @@ -101,7 +100,7 @@ bool CSMWorld::IdTable::setData (const QModelIndex &index, const QVariant &value { const std::pair& parentAdress(unfoldIndexAdress(index.internalId())); - mIdCollection->setNestedData(parentAdress.first, parentAdress.second, value, index.row(), index.column()); + dynamic_cast(mIdCollection)->setNestedData(parentAdress.first, parentAdress.second, value, index.row(), index.column()); emit dataChanged (CSMWorld::IdTable::index (parentAdress.first, 0), CSMWorld::IdTable::index (parentAdress.second, mIdCollection->getColumns()-1)); @@ -144,7 +143,7 @@ bool CSMWorld::IdTable::removeRows (int row, int count, const QModelIndex& paren { for (int i = 0; i < count; ++i) { - mIdCollection->removeNestedRows(parent.row(), parent.column(), row+i); + dynamic_cast(mIdCollection)->removeNestedRows(parent.row(), parent.column(), row+i); } } else { @@ -164,12 +163,15 @@ bool CSMWorld::IdTable::removeRows (int row, int count, const QModelIndex& paren void CSMWorld::IdTable::addNestedRow(const QModelIndex& parent, int position) { - assert(parent.isValid()); + if (!hasChildren(parent)) + { + throw std::logic_error("Tried to set nested table, but index has no children"); + } int row = parent.row(); beginInsertRows(parent, position, position); - mIdCollection->addNestedRow(row, parent.column(), position); + dynamic_cast(mIdCollection)->addNestedRow(row, parent.column(), position); endInsertRows(); @@ -373,7 +375,7 @@ void CSMWorld::IdTable::setNestedTable(const QModelIndex& index, const CSMWorld: removeRowsMode = true; } - mIdCollection->setNestedTable(index.row(), index.column(), nestedTable); + dynamic_cast(mIdCollection)->setNestedTable(index.row(), index.column(), nestedTable); emit dataChanged (CSMWorld::IdTable::index (index.row(), 0), CSMWorld::IdTable::index (index.row(), mIdCollection->getColumns()-1)); @@ -391,5 +393,5 @@ CSMWorld::NestedTableWrapperBase* CSMWorld::IdTable::nestedTable(const QModelInd throw std::logic_error("Tried to retrive nested table, but index has no children"); } - return mIdCollection->nestedTable(index.row(), index.column()); + return dynamic_cast(mIdCollection)->nestedTable(index.row(), index.column()); } diff --git a/apps/opencs/model/world/refidcollection.hpp b/apps/opencs/model/world/refidcollection.hpp index cc7609a58..62616d369 100644 --- a/apps/opencs/model/world/refidcollection.hpp +++ b/apps/opencs/model/world/refidcollection.hpp @@ -35,7 +35,7 @@ namespace CSMWorld virtual bool isUserEditable() const; }; - class RefIdCollection : public CollectionBase + class RefIdCollection : public NestedCollection { private: From 40edf15ab095f11c5485ff9a36912ac9e6cb7ce2 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Thu, 31 Jul 2014 12:18:24 +0200 Subject: [PATCH 0075/3725] cleaning up the code --- apps/opencs/model/world/collection.hpp | 1 + apps/opencs/model/world/columnimp.hpp | 1 + apps/opencs/model/world/idtable.cpp | 13 ++++++++----- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/apps/opencs/model/world/collection.hpp b/apps/opencs/model/world/collection.hpp index 252e84c38..5c32e7716 100644 --- a/apps/opencs/model/world/collection.hpp +++ b/apps/opencs/model/world/collection.hpp @@ -2,6 +2,7 @@ #define CSM_WOLRD_COLLECTION_H #include +#include #include #include #include diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index 3fad05f65..e416c332b 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -4,6 +4,7 @@ #include #include +#include #include diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 4e4ccb1c1..410e0d3f0 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -2,6 +2,7 @@ #include #include +#include #include "nestedtablewrapper.hpp" #include "collectionbase.hpp" @@ -30,7 +31,7 @@ int CSMWorld::IdTable::columnCount (const QModelIndex & parent) const { return dynamic_cast(mIdCollection)->getNestedColumnsCount(parent.row(), parent.column()); } - + return mIdCollection->getColumns(); } @@ -46,9 +47,9 @@ QVariant CSMWorld::IdTable::data (const QModelIndex & index, int role) const { std::pair parentAdress(unfoldIndexAdress(index.internalId())); return dynamic_cast(mIdCollection)->getNestedData(parentAdress.first, - parentAdress.second, - index.row(), - index.column()); + parentAdress.second, + index.row(), + index.column()); } else { return mIdCollection->getData (index.row(), index.column()); } @@ -68,8 +69,10 @@ QVariant CSMWorld::IdTable::headerData (int section, return mIdCollection->getColumn (section).mFlags; if (role==ColumnBase::Role_Display) + { return mIdCollection->getColumn (section).mDisplayType; - + } + return QVariant(); } From e413bebe99b0dc2ab1e5f07c8d20b594f6a4c5f4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 16 Oct 2014 15:07:51 +0200 Subject: [PATCH 0076/3725] Toggle addon files when activated or clicked on checkbox rather than clicked (Fixes #1980) --- apps/opencs/view/doc/filedialog.cpp | 10 +++++++--- apps/opencs/view/doc/filedialog.hpp | 1 + components/contentselector/model/contentmodel.cpp | 4 ++-- components/contentselector/view/contentselector.cpp | 11 +++-------- components/contentselector/view/contentselector.hpp | 6 +++--- 5 files changed, 16 insertions(+), 16 deletions(-) diff --git a/apps/opencs/view/doc/filedialog.cpp b/apps/opencs/view/doc/filedialog.cpp index 300656f33..c0e5502ec 100644 --- a/apps/opencs/view/doc/filedialog.cpp +++ b/apps/opencs/view/doc/filedialog.cpp @@ -125,13 +125,17 @@ void CSVDoc::FileDialog::buildOpenFileView() if(!mDialogBuilt) { - connect (mSelector, SIGNAL (signalAddonFileSelected (int)), this, SLOT (slotUpdateAcceptButton (int))); - connect (mSelector, SIGNAL (signalAddonFileUnselected (int)), this, SLOT (slotUpdateAcceptButton (int))); + connect (mSelector, SIGNAL (signalAddonDataChanged (const QModelIndex&, const QModelIndex&)), this, SLOT (slotAddonDataChanged(const QModelIndex&, const QModelIndex&))); } connect (ui.projectButtonBox, SIGNAL (accepted()), this, SLOT (slotOpenFile())); } -void CSVDoc::FileDialog::slotUpdateAcceptButton (int) +void CSVDoc::FileDialog::slotAddonDataChanged(const QModelIndex &topleft, const QModelIndex &bottomright) +{ + slotUpdateAcceptButton(0); +} + +void CSVDoc::FileDialog::slotUpdateAcceptButton(int) { QString name = ""; diff --git a/apps/opencs/view/doc/filedialog.hpp b/apps/opencs/view/doc/filedialog.hpp index 111cc0d80..3c23a5cb5 100644 --- a/apps/opencs/view/doc/filedialog.hpp +++ b/apps/opencs/view/doc/filedialog.hpp @@ -70,6 +70,7 @@ namespace CSVDoc void slotUpdateAcceptButton (int); void slotUpdateAcceptButton (const QString &, bool); void slotRejected(); + void slotAddonDataChanged(const QModelIndex& topleft, const QModelIndex& bottomright); }; } #endif // FILEDIALOG_HPP diff --git a/components/contentselector/model/contentmodel.cpp b/components/contentselector/model/contentmodel.cpp index 0d4f2365a..fde6223f1 100644 --- a/components/contentselector/model/contentmodel.cpp +++ b/components/contentselector/model/contentmodel.cpp @@ -106,7 +106,7 @@ Qt::ItemFlags ContentSelectorModel::ContentModel::flags(const QModelIndex &index //game files can always be checked if (file->isGameFile()) - return Qt::ItemIsEnabled | Qt::ItemIsSelectable; + return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable; Qt::ItemFlags returnFlags; bool allDependenciesFound = true; @@ -145,7 +145,7 @@ Qt::ItemFlags ContentSelectorModel::ContentModel::flags(const QModelIndex &index if (gamefileChecked) { if (allDependenciesFound) - returnFlags = returnFlags | Qt::ItemIsEnabled | Qt::ItemIsSelectable | mDragDropFlags; + returnFlags = returnFlags | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | mDragDropFlags; else returnFlags = Qt::ItemIsSelectable; } diff --git a/components/contentselector/view/contentselector.cpp b/components/contentselector/view/contentselector.cpp index e9599de49..4508d7bd7 100644 --- a/components/contentselector/view/contentselector.cpp +++ b/components/contentselector/view/contentselector.cpp @@ -58,7 +58,8 @@ void ContentSelectorView::ContentSelector::buildAddonView() ui.addonView->setModel(mAddonProxyModel); - connect(ui.addonView, SIGNAL(clicked(const QModelIndex &)), this, SLOT(slotAddonTableItemClicked(const QModelIndex &))); + connect(ui.addonView, SIGNAL(activated(const QModelIndex&)), this, SLOT(slotAddonTableItemActivated(const QModelIndex&))); + connect(mContentModel, SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&)), this, SIGNAL(signalAddonDataChanged(QModelIndex,QModelIndex))); } void ContentSelectorView::ContentSelector::setProfileContent(const QStringList &fileList) @@ -181,7 +182,7 @@ void ContentSelectorView::ContentSelector::slotCurrentGameFileIndexChanged(int i emit signalCurrentGamefileIndexChanged (index); } -void ContentSelectorView::ContentSelector::slotAddonTableItemClicked(const QModelIndex &index) +void ContentSelectorView::ContentSelector::slotAddonTableItemActivated(const QModelIndex &index) { QModelIndex sourceIndex = mAddonProxyModel->mapToSource (index); @@ -194,10 +195,4 @@ void ContentSelectorView::ContentSelector::slotAddonTableItemClicked(const QMode checkState = Qt::Checked; mContentModel->setData(sourceIndex, checkState, Qt::CheckStateRole); - - if (checkState == Qt::Checked) - emit signalAddonFileSelected (index.row()); - else - emit signalAddonFileUnselected (index.row()); - } diff --git a/components/contentselector/view/contentselector.hpp b/components/contentselector/view/contentselector.hpp index a25eb20ae..5fba9cd2e 100644 --- a/components/contentselector/view/contentselector.hpp +++ b/components/contentselector/view/contentselector.hpp @@ -55,13 +55,13 @@ namespace ContentSelectorView signals: void signalCurrentGamefileIndexChanged (int); - void signalAddonFileSelected (int); - void signalAddonFileUnselected (int); + + void signalAddonDataChanged (const QModelIndex& topleft, const QModelIndex& bottomright); private slots: void slotCurrentGameFileIndexChanged(int index); - void slotAddonTableItemClicked(const QModelIndex &index); + void slotAddonTableItemActivated(const QModelIndex& index); }; } From dd8964da99a2d2ace31fb0ed4f68b689d495c8b2 Mon Sep 17 00:00:00 2001 From: Bodillium Date: Wed, 22 Oct 2014 21:54:37 +1100 Subject: [PATCH 0077/3725] Begin reworking files and directories section First attempt at LaTeX and Git! --- manual/opencs/files_and_directories.tex | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/manual/opencs/files_and_directories.tex b/manual/opencs/files_and_directories.tex index fc9ae878a..39d918b46 100644 --- a/manual/opencs/files_and_directories.tex +++ b/manual/opencs/files_and_directories.tex @@ -1,22 +1,23 @@ \section{Files and Directories} \subsection{Introduction} -This section of the manual covers usage of files and directories by the OpenCS. Files and directories are file system concepts, -and you are probably already familiar with it. We won't try to explain this concepts, we will just focus on \OCS. +This section of the manual describes the directories and file types used by OpenCS. A file is a resource for storing data, identified by its +filename extension (e.g. .exe, .jpg, .txt), whereas a directory is a folder or file system structure in which these files are stored. You +are most likely already familiar with these concepts. \subsection{Used terms} %TODO \subsection{Basics} \paragraph{Directories} -OpenMW and \OCS{} uses multiple directories on file systems. First of, there is a \textbf{user directory} that holds configuration -files and few different folders. The location of the user directory is hard coded for each supported operating system. +OpenMW and \OCS{} store their files in multiple directories. Firstly, there is the \textbf{user directory} that holds configuration +files and several other folders. The location of the user directory is hard coded for each supported operating system. %TODO list paths. -In addition to this single hard coded directory, both \OMW{} and \OCS{} need a~place to seek for actual data files of the game: -textures, models, sounds and files that store records of objects in game; dialogues and so one -- so called content files. We support -multiple such paths (we call it \textbf{data paths}) as specified in the configuration. Usually one data path points to the directory -where original \MW{} is either installed or unpacked. You are free to specify as many data paths as you would like, -however, there is one special data path that, as described later, is used to store newly created content files. +In addition to the user directory, both \OMW{} and \OCS{} need a place to store the game’s actual data files: for example, the +textures, models, sounds and records of in-game objects. We support multiple paths to these files (termed \textbf{data paths}), +as specified in the configuration. Usually, one data path points to the directory where \MW{} is installed, however, you are +free to specify as many data paths as you would like. In addition, one particular data path, as described below, is used to store +newly created content files. \paragraph{Content files} \BS{} \MW{} engine is using two types of files: ESM (master) and ESP (plugin). The distinction between those From f70ddb5e980b543e146d4d95662a0d09f0bff400 Mon Sep 17 00:00:00 2001 From: Bodillium Date: Thu, 23 Oct 2014 15:46:43 +1100 Subject: [PATCH 0078/3725] Finish reworking files and directories section --- manual/opencs/files_and_directories.tex | 137 ++++++++++++------------ 1 file changed, 66 insertions(+), 71 deletions(-) diff --git a/manual/opencs/files_and_directories.tex b/manual/opencs/files_and_directories.tex index 39d918b46..21774093e 100644 --- a/manual/opencs/files_and_directories.tex +++ b/manual/opencs/files_and_directories.tex @@ -13,109 +13,104 @@ OpenMW and \OCS{} store their files in multiple directories. Firstly, there is t files and several other folders. The location of the user directory is hard coded for each supported operating system. %TODO list paths. -In addition to the user directory, both \OMW{} and \OCS{} need a place to store the game’s actual data files: for example, the -textures, models, sounds and records of in-game objects. We support multiple paths to these files (termed \textbf{data paths}), -as specified in the configuration. Usually, one data path points to the directory where \MW{} is installed, however, you are -free to specify as many data paths as you would like. In addition, one particular data path, as described below, is used to store +In addition to the user directory, both \OMW{} and \OCS{} need a place to store the game’s actual data files: for example, the +textures, models, sounds and records of in-game objects. We support multiple paths to these files (termed \textbf{data paths}), +as specified in the configuration. Usually, one data path points to the directory where \MW{} is installed, however, you are +free to specify as many data paths as you would like. In addition, one particular data path, as described below, is used to store newly created content files. \paragraph{Content files} -\BS{} \MW{} engine is using two types of files: ESM (master) and ESP (plugin). The distinction between those -is not clear, and often confusing. You would expect the ESM (master) file is used to specify one master, that is modified by the ESPs plugins, -and indeed: this is the basic idea. However, original expansions also were made as ESM files, even though they essentially could be -described as a really large plugins, and therefore rather use ESP files. There were technical reasons behind this decision -- somewhat valid -in the case of original engine, but clearly it's better to create a system that can be used is more sensible way. \OMW{} achieves -this with our own content file types. +\BS{} \MW{} engine uses two file types: ESM (master) and ESP (plugin). The distinction between the two is often confusing. +You would expect that the ESM (master) file is used to specify a single master which is modified by the ESP files (plugins), and indeed: +this is the basic idea. However, the original expansions are also ESM files, even though they can be described as a really large plugins. +There were technical reasons behind this decision -- somewhat valid in the case of original engine, but a more logical file system is +much preferable. \OMW{} achieves this through the creation of our own types of content file. -We support both ESM and ESP files, but in order to make use of new features of OpenMW one should consider using new file types designed -with our engine in mind: game files and addon files together called ``content files``. +We support both ESM and ESP files, but, in order to make use of \OMW{}'s new features, one should consider using new file types designed +with our engine in mind: game files and addon files, collectively termed \textbf{content files}. \subparagraph{OpenMW content files} -Game and Addon files are concept somewhat similar to the old ESM/ESP, only in the way it should be from the very beginning. Nothing easier -to describe. If you want to make new game using \OMW{} as engine (so called ``total conversion'') you should create a game file. -If you want to create a addon for existing game file -- simply create addon file. Nothing else matters: The only distinction you should -consider is if your project is about changing other game, or creating a new one. Simple as that. +The distinction between game and addon files is similar to that between ESM and ESP, however their relationship to each other is +strictly defined -– the former are always master files, and the latter are always plugins. If you want to make a new game using the \OMW{} +engine (i.e. a ``total conversion''), you should create a game file. If you want to create an addon for an existing game file, simply +create an addon file. Nothing else matters: the only distinction you should consider is whether your project involves changing another game, +or creating a new one. Simple as that. -Other simple thing about content files are extensions. We are using .omwaddon for addon files and .omwgame for game files. +Furthermore, our content files’ extensions are .omwaddon for addon files and .omwgame for game files. %TODO describe what content files contains. and what not. \subparagraph{\MW{} content files} -Using our content files is recommended solution for projects that are intended to used with \OMW{} engine. However some players -wish to use original \MW{} engine, even with it large flaws and lacking features\footnote{If this is actually wrong, we are very -successful project. Yay!}. Also, since 2002 thousands of ESP/ESM files were created, some with really outstanding content. -Because of this \OCS{} simply has no other choice but support ESP/ESM files. However, if you decided to choose ESP/ESM file instead -using our own content file types you are most likely aim at the original engine compatibility. This subject is covered in the very -last section of this manual. %not finished TODO add the said section. Most likely when more features are present. +Using our content files is the recommended solution for projects that employ the \OMW{} engine. However, some players will wish to use +the original \MW{} engine, despite its large flaws and lacking features\footnote{If this is wrong, we are a very successful project. Yay!}. +In addition, since 2002 thousands of ESP/ESM files have been created, some with truly outstanding content. Because of this, \OCS{} is +committed to supporting ESP/ESM files. If you do decide to use ESP/ESM files rather than our own content files, you are most likely aiming +for original engine compatibility. This subject is covered in the very last section of the manual. +%not finished TODO add the said section. Most likely when more features are present. -The actual creation of new files is described in the next chapter. Here we are gonna focus only on details that you need to know -in order to create your first \OCS{} file while full understanding your needs. For now let's jut remember that content files -are created inside the user directory, in the the \textbf{data} subfolder (that is the one special data directory mentioned earlier). +The actual creation of new files is described in the next chapter. Here we are going to focus only on the essential information needed +to create your first \OCS{} file. For now, let's jut remember that content files are stored in the user directory, in the \textbf{data} subfolder (the particular data directory mentioned above). \subparagraph{Dependencies} -Since addon is supposed to change the game it is logical that it also depends on the said game. It simply can not work otherwise. -Just think about it: your modification is changing prize of the iron sword. But what if there is no iron sword in game? That is right: -we get nonsense. What you want to do is to tie your addon to the files you are changing. Those can be either game files (expansion island -for a game) or other addon files (house on the said island). It is a good idea to be dependent only on files that are really changed -in your addon obviously, but sadly there is no other way to achieve this than knowing what you want to do. Again, please remember that -this section of the manual does not cover creating the content files -- it is only theoretical introduction to the subject. For now just -keep in mind that dependencies exist, and is up to you what to decide if your content file should depend on other content file. - -Game files are not intend to have any dependencies for a very simple reasons: player is using only one game file (excluding original -and dirty {ESP/ESM} system) at the time and therefore no game file can depend on other game file, and since game file makes the base -for addon files -- it can not depend on addon files. +Since addons aim to modify an existing game, it is logical that they also depend on the said game: otherwise they will not function. +For example, your modification changes the price of iron swords. But what if there are no iron swords in the game? That is right: +it is nonsense. Therefore, it is necessary to make your addon a dependency of other content files. These can be either game files +(e.g. an entirely new island), or other addon files (e.g. a house on the island). It is a good idea for addons to depend only on the +content files they modify, but this is up to the end user to determine. + +Game files do not depend on any other content files, as they act as master files. A player can only use one game file at a time +(although this does not apply to the original and dirty ESP/ESM system). %\subparagraph{Loading order} %TODO \paragraph{Project files} -Project files act as containers for data not used by the \OMW{} game engine itself, but still useful for OpenCS. The shining example -of this data category are without doubt record filters (described in the later section of the manual you are reading currently). -As a mod author you probably do not need and/or want to distribute project files at all, they are meant to be used only by you. +Project files contain data not used by the \OMW{} game engine but which are still needed by OpenCS. Good examples of this data type +are the record filters (described below). As a mod author, you probably do not need and/or want to distribute project files at all, +as they are meant to be used only by you. + +Since project files govern how content files are used in OpenCS, they are always used in conjunction with your specific project. +In fact, each time work commences on a new content file without a corresponding project file, a new project file will be created. -As you would imagine, project file makes sense only in combination with actual content files. In fact, each time you start to work -on new content file and project file was not found, it will be created. -Project files extension is, to not surprise ``.project''. The whole name of the project file is the whole name of the content file -with appended extensions. For instance swords.omwaddon file is associated with swords.omwaddon.project file. +Project file extension is ``.project''. The name of the project file is the whole name of the content file with appended extensions. +For instance, a content file named swords.omwaddon is associated with the project file swords.omwaddon.project. %TODO where are they stored. -Project files are stored inside the user directory, in the \textbf{projects} subfolder. This is the path location for both freshly -created project files, and a place where \OCS{} looks for already existing files. +Project files are stored inside the user directory, in the \textbf{projects} subfolder. This is both the location of newly created +project files, and the place where \OCS{} looks for already existing files. -\paragraph{Resources files} +\paragraph{Resource files} %textures, sounds, whatever -Unless we are talking about the fully text based game, like Zork or Rogue, you are expecting that a video game is using some media files: -models with textures, pictures acting as icons, sounds and everything else. Since content files, no matter if it is ESP, ESM or new \OMW{} -file type do not contain any of those, it is clear that they have to be deliver with a different file. It is also clear that this, -let's call it ``resources file``, have to be supported by the engine. Without code handling those files, it is nothing more than -a mathematical abstraction -- something, that lacks meaning for human beings\footnote{Unless we call programmers a human beings.}. -Therefore this section must cover ways to add resources files to your content file, and point out what is supported. We are going -to do just that. Later, you will learn how to make use of those files in your content. +The vast majority of modern video games use what we shall term \textbf{resource files}: models, textures, icons, sounds and so on. +ESPs, ESMs and \OMW{} content files do not contain these files, merely instructions on how they are used. It follows that the \OMW{} +engine must be capable of supporting these resource files in order for them to function. Therefore this section cover ways to add +resource files to your content file, and outlines which formats are supported. Later, you will learn how to make use of these files +in your content. \subparagraph{Audio} -OpenMW is using {FFmpeg} for audio playback, and so we support every audio type that is supported by this library. This makes a huge list. -Below is only small portion of supported file types. +OpenMW utilises {FFmpeg} for audio playback, so we support every audio type supported by this library. This is a huge list. +Below is only a small sample of supported file types. \begin{description} - \item mp3 ({MPEG}-1 {Part 3 Layer 3}) popular audio file format and \textit{de facto} standard for storing audio. Used by the \MW{} game. - \item ogg open source, multimedia container file using high quality vorbis audio codec. Recommended. + \item mp3 ({MPEG}-1 {Part 3 Layer 3}) A popular audio file format and the \textit{de facto} standard for storing audio. Used by + the \MW{} game. + \item ogg Open source, multimedia container file which uses the high quality vorbis audio codec. Recommended. \end{description} \subparagraph{Video} -As in the case of audio files, we are using {FFmepg} to decode video files. The list of supported files is long, we will cover -only the most significant. +As in the case of audio files, we use {FFmpeg} to decode video files. The list of supported files is long -– only the most +significant will be covered. \begin{description} - \item bik videos used by original \MW{} game. - \item mp4 multimedia container which use more advanced codecs ({MPEG-4 Parts 2,3,10}) with a better audio and video compression rate, - but also requiring more {CPU} intensive decoding -- this makes it probably less suited for storing sounds in computer games, but good for videos. - \item webm is a new, shiny and open source video format with excellent compression. It needs quite a lot of processing power to be decoded, + \item bik Format used by the original \MW{} game. + \item mp4 Multimedia container which use more advanced codecs ({MPEG-4 Parts 2,3,10}) with a better audio and video compression rate, + but which require more {CPU} intensive decoding -- this probably makes it less suited for storing sounds in computer games, but good for videos. + \item webm A new, shiny and open source video format with excellent compression. It needs quite a lot of processing power to be decoded, but since game logic is not running during cut scenes we can recommend it for use with \OMW. - \item ogv alternative, open source container using theora codec for video and vorbis for audio. + \item ogv An alternative, open source container using theora codec for video and vorbis for audio. \end{description} \subparagraph{Textures and images} -Original \MW{} game uses {DDS} and {TGA} files for all kind of two dimensional images and textures alike. In addition, engine supported BMP -files for some reason ({BMP} is a terrible format for a video game). We also support extended set of image files -- including {JPEG} and {PNG}. -JPEG and PNG files can be useful in some cases, for instance JPEG file is a valid option for skybox texture and PNG can useful for masks. -However please, keep in mind that JPEG can grow into large sizes quickly and are not the best option with {DirectX} rendering backend. You probabbly still want -to use {DDS} files for textures. - +\MW{} uses {DDS} and {TGA} files for all kinds of two dimensional images and textures. In addition, the original engine supported BMP +files (although {BMP} is a terrible format for a video game). We also support an extended set of image files -- including {JPEG} and {PNG}. +JPEG and PNG files can be useful in some cases. For instance, a JPEG file is a valid option for a skybox texture and PNG can useful for masks. +However, keep in mind that a JPEG can grow large quickly and so are not the best option with a {DirectX} rendering backend. DDS files +are therefore recommended for textures. %\subparagraph{Meshes} %TODO once we will support something more than just nifs \ No newline at end of file From 20aa89e785a5e61f80057584b3aebddcee11f187 Mon Sep 17 00:00:00 2001 From: Bodillium Date: Thu, 23 Oct 2014 23:32:24 +1100 Subject: [PATCH 0079/3725] Minor tweaks to files and directories --- manual/opencs/files_and_directories.tex | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/manual/opencs/files_and_directories.tex b/manual/opencs/files_and_directories.tex index 21774093e..1b07fe267 100644 --- a/manual/opencs/files_and_directories.tex +++ b/manual/opencs/files_and_directories.tex @@ -22,8 +22,8 @@ newly created content files. \paragraph{Content files} \BS{} \MW{} engine uses two file types: ESM (master) and ESP (plugin). The distinction between the two is often confusing. You would expect that the ESM (master) file is used to specify a single master which is modified by the ESP files (plugins), and indeed: -this is the basic idea. However, the original expansions are also ESM files, even though they can be described as a really large plugins. -There were technical reasons behind this decision -- somewhat valid in the case of original engine, but a more logical file system is +this is the basic idea. However, the original expansions are also ESM files, even though they can be described as very large plugins. +There were technical reasons behind this decision -- somewhat valid in the case of the original engine, but a more logical file system is much preferable. \OMW{} achieves this through the creation of our own types of content file. We support both ESM and ESP files, but, in order to make use of \OMW{}'s new features, one should consider using new file types designed @@ -48,7 +48,8 @@ for original engine compatibility. This subject is covered in the very last sect %not finished TODO add the said section. Most likely when more features are present. The actual creation of new files is described in the next chapter. Here we are going to focus only on the essential information needed -to create your first \OCS{} file. For now, let's jut remember that content files are stored in the user directory, in the \textbf{data} subfolder (the particular data directory mentioned above). +to create your first \OCS{} file. For now, let's jut remember that content files are stored in the user directory, in the \textbf{data} +subfolder (the particular data directory mentioned above). \subparagraph{Dependencies} Since addons aim to modify an existing game, it is logical that they also depend on the said game: otherwise they will not function. @@ -67,9 +68,9 @@ are the record filters (described below). As a mod author, you probably do not n as they are meant to be used only by you. Since project files govern how content files are used in OpenCS, they are always used in conjunction with your specific project. -In fact, each time work commences on a new content file without a corresponding project file, a new project file will be created. +In fact, each time work commences on a content file that does not have a corresponding project file, a new project file will be created. -Project file extension is ``.project''. The name of the project file is the whole name of the content file with appended extensions. +The project file extension is ``.project''. The name of the project file is the whole name of the content file with appended extensions. For instance, a content file named swords.omwaddon is associated with the project file swords.omwaddon.project. %TODO where are they stored. @@ -80,7 +81,7 @@ project files, and the place where \OCS{} looks for already existing files. %textures, sounds, whatever The vast majority of modern video games use what we shall term \textbf{resource files}: models, textures, icons, sounds and so on. ESPs, ESMs and \OMW{} content files do not contain these files, merely instructions on how they are used. It follows that the \OMW{} -engine must be capable of supporting these resource files in order for them to function. Therefore this section cover ways to add +engine must be capable of supporting these resource files in order for them to function. Therefore this section covers ways to add resource files to your content file, and outlines which formats are supported. Later, you will learn how to make use of these files in your content. @@ -101,7 +102,8 @@ significant will be covered. \begin{description} \item bik Format used by the original \MW{} game. \item mp4 Multimedia container which use more advanced codecs ({MPEG-4 Parts 2,3,10}) with a better audio and video compression rate, - but which require more {CPU} intensive decoding -- this probably makes it less suited for storing sounds in computer games, but good for videos. + but which require more {CPU} intensive decoding -- this probably makes it less suited for storing sounds in computer games, but + good for videos. \item webm A new, shiny and open source video format with excellent compression. It needs quite a lot of processing power to be decoded, but since game logic is not running during cut scenes we can recommend it for use with \OMW. \item ogv An alternative, open source container using theora codec for video and vorbis for audio. From 6741fbe7a9ff84f226db2fdbc37c5bdca00af3a1 Mon Sep 17 00:00:00 2001 From: Internecine Date: Wed, 5 Nov 2014 15:22:44 +1300 Subject: [PATCH 0080/3725] Fixes bug #2031 --- apps/openmw/mwmechanics/spellcasting.cpp | 30 +++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index d33bb6ad1..e124c8b79 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -434,7 +434,8 @@ namespace MWMechanics float magnitude = effectIt->mMagnMin + (effectIt->mMagnMax - effectIt->mMagnMin) * random; magnitude *= magnitudeMult; - bool hasDuration = !(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration); + bool hasDuration = !(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration) && effectIt->mDuration > 0; + std::cout << (hasDuration == true ? "true" : "false") << std::endl; if (target.getClass().isActor() && hasDuration) { ActiveSpells::ActiveEffect effect; @@ -578,6 +579,33 @@ namespace MWMechanics value.restore(magnitude); target.getClass().getCreatureStats(target).setAttribute(attribute, value); } + else if (effectId == ESM::MagicEffect::DamageHealth || effectId == ESM::MagicEffect::RestoreHealth) + { + MWMechanics::DynamicStat health = target.getClass().getCreatureStats(target).getHealth(); + if (effectId == ESM::MagicEffect::DamageHealth) + health.setCurrent(health.getCurrent() - magnitude); + else + health.setCurrent(health.getCurrent() + magnitude); + target.getClass().getCreatureStats(target).setHealth(health); + } + else if (effectId == ESM::MagicEffect::DamageFatigue || effectId == ESM::MagicEffect::RestoreFatigue) + { + MWMechanics::DynamicStat fatigue = target.getClass().getCreatureStats(target).getFatigue(); + if (effectId == ESM::MagicEffect::DamageFatigue) + fatigue.setCurrent(fatigue.getCurrent() - magnitude); + else + fatigue.setCurrent(fatigue.getCurrent() + magnitude); + target.getClass().getCreatureStats(target).setHealth(fatigue); + } + else if (effectId == ESM::MagicEffect::DamageMagicka || effectId == ESM::MagicEffect::RestoreMagicka) + { + MWMechanics::DynamicStat magicka = target.getClass().getCreatureStats(target).getMagicka(); + if (effectId == ESM::MagicEffect::DamageMagicka) + magicka.setCurrent(magicka.getCurrent() - magnitude); + else + magicka.setCurrent(magicka.getCurrent() + magnitude); + target.getClass().getCreatureStats(target).setHealth(magicka); + } else if (effectId == ESM::MagicEffect::DamageSkill || effectId == ESM::MagicEffect::RestoreSkill) { if (target.getTypeName() != typeid(ESM::NPC).name()) From edc51ab768d7413ac894f23e7044e7c55e74ce74 Mon Sep 17 00:00:00 2001 From: Internecine Date: Wed, 5 Nov 2014 15:26:13 +1300 Subject: [PATCH 0081/3725] Removed debug output --- apps/openmw/mwmechanics/spellcasting.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index e124c8b79..fd4c9406c 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -435,7 +435,6 @@ namespace MWMechanics magnitude *= magnitudeMult; bool hasDuration = !(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration) && effectIt->mDuration > 0; - std::cout << (hasDuration == true ? "true" : "false") << std::endl; if (target.getClass().isActor() && hasDuration) { ActiveSpells::ActiveEffect effect; From c37881ead1ce513bbd4a90d5f56ab5c45957feac Mon Sep 17 00:00:00 2001 From: Digmaster Date: Mon, 8 Dec 2014 21:57:32 -0600 Subject: [PATCH 0082/3725] Joystick Support --- apps/openmw/engine.cpp | 2 +- apps/openmw/mwbase/inputmanager.hpp | 16 +- apps/openmw/mwgui/settingswindow.cpp | 46 +- apps/openmw/mwgui/settingswindow.hpp | 5 + apps/openmw/mwinput/inputmanagerimp.cpp | 471 +++++++++++-- apps/openmw/mwinput/inputmanagerimp.hpp | 44 +- apps/openmw/mwscript/interpretercontext.cpp | 4 +- extern/oics/ICSControl.cpp | 18 +- extern/oics/ICSInputControlSystem.cpp | 286 +++----- extern/oics/ICSInputControlSystem.h | 74 +- .../oics/ICSInputControlSystem_joystick.cpp | 630 ++++-------------- extern/sdl4ogre/events.h | 18 +- extern/sdl4ogre/sdlinputwrapper.cpp | 36 +- extern/sdl4ogre/sdlinputwrapper.hpp | 4 +- files/CMakeLists.txt | 2 + files/gamecontrollerdb.txt | 75 +++ 16 files changed, 894 insertions(+), 837 deletions(-) create mode 100644 files/gamecontrollerdb.txt diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index d7b23c096..0e636e054 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -190,7 +190,7 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) std::srand ( std::time(NULL) ); MWClass::registerClasses(); - Uint32 flags = SDL_INIT_VIDEO|SDL_INIT_NOPARACHUTE; + Uint32 flags = SDL_INIT_VIDEO|SDL_INIT_NOPARACHUTE|SDL_INIT_GAMECONTROLLER|SDL_INIT_JOYSTICK; if(SDL_WasInit(flags) == 0) { //kindly ask SDL not to trash our OGL context diff --git a/apps/openmw/mwbase/inputmanager.hpp b/apps/openmw/mwbase/inputmanager.hpp index d44da4974..3ffa7148a 100644 --- a/apps/openmw/mwbase/inputmanager.hpp +++ b/apps/openmw/mwbase/inputmanager.hpp @@ -37,11 +37,19 @@ namespace MWBase virtual bool getControlSwitch (const std::string& sw) = 0; virtual std::string getActionDescription (int action) = 0; - virtual std::string getActionBindingName (int action) = 0; - virtual std::vector getActionSorting () = 0; + virtual std::string getActionKeyBindingName (int action) = 0; + virtual std::string getActionControllerBindingName (int action) = 0; + virtual std::string sdlControllerAxisToString(int axis) = 0; + virtual std::string sdlControllerButtonToString(int button) = 0; + ///Actions available for binding to keyboard buttons + virtual std::vector getActionKeySorting() = 0; + ///Actions available for binding to controller buttons + virtual std::vector getActionControllerSorting() = 0; virtual int getNumActions() = 0; - virtual void enableDetectingBindingMode (int action) = 0; - virtual void resetToDefaultBindings() = 0; + ///If keyboard is true, only pay attention to keyboard events. If false, only pay attention to cntroller events (excluding esc) + virtual void enableDetectingBindingMode (int action, bool keyboard) = 0; + virtual void resetToDefaultKeyBindings() = 0; + virtual void resetToDefaultControllerBindings() = 0; }; } diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 8ef0a331a..619a0c87d 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -156,7 +156,8 @@ namespace MWGui } SettingsWindow::SettingsWindow() : - WindowBase("openmw_settings_window.layout") + WindowBase("openmw_settings_window.layout"), + mKeyboardMode(true) { configureWidgets(mMainWidget); @@ -180,6 +181,8 @@ namespace MWGui getWidget(mResetControlsButton, "ResetControlsButton"); getWidget(mRefractionButton, "RefractionButton"); getWidget(mDifficultySlider, "DifficultySlider"); + getWidget(mKeyboardSwitch, "KeyboardButton"); + getWidget(mControllerSwitch, "ControllerButton"); mMainWidget->castType()->eventWindowChangeCoord += MyGUI::newDelegate(this, &SettingsWindow::onWindowResize); @@ -191,6 +194,9 @@ namespace MWGui mShadowsTextureSize->eventComboChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onShadowTextureSizeChanged); + mKeyboardSwitch->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onKeyboardSwitchClicked); + mControllerSwitch->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onControllerSwitchClicked); + center(); mResetControlsButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onResetDefaultBindings); @@ -436,14 +442,33 @@ namespace MWGui MWBase::Environment::get().getInputManager()->processChangedSettings(changed); } + void SettingsWindow::onKeyboardSwitchClicked(MyGUI::Widget* _sender) + { + if(mKeyboardMode) + return; + mKeyboardMode = true; + updateControlsBox(); + } + + void SettingsWindow::onControllerSwitchClicked(MyGUI::Widget* _sender) + { + if(!mKeyboardMode) + return; + mKeyboardMode = false; + updateControlsBox(); + } + void SettingsWindow::updateControlsBox() { while (mControlsBox->getChildCount()) MyGUI::Gui::getInstance().destroyWidget(mControlsBox->getChildAt(0)); - MWBase::Environment::get().getWindowManager ()->removeStaticMessageBox(); - - std::vector actions = MWBase::Environment::get().getInputManager()->getActionSorting (); + MWBase::Environment::get().getWindowManager()->removeStaticMessageBox(); + std::vector actions; + if(mKeyboardMode) + actions = MWBase::Environment::get().getInputManager()->getActionKeySorting(); + else + actions = MWBase::Environment::get().getInputManager()->getActionControllerSorting(); const int h = 18; const int w = mControlsBox->getWidth() - 28; @@ -454,7 +479,11 @@ namespace MWGui if (desc == "") continue; - std::string binding = MWBase::Environment::get().getInputManager()->getActionBindingName (*it); + std::string binding; + if(mKeyboardMode) + binding = MWBase::Environment::get().getInputManager()->getActionKeyBindingName(*it); + else + binding = MWBase::Environment::get().getInputManager()->getActionControllerBindingName(*it); Gui::SharedStateButton* leftText = mControlsBox->createWidget("SandTextButton", MyGUI::IntCoord(0,curH,w,h), MyGUI::Align::Default); leftText->setCaptionWithReplacing(desc); @@ -488,7 +517,7 @@ namespace MWGui MWBase::Environment::get().getWindowManager ()->staticMessageBox ("#{sControlsMenu3}"); MWBase::Environment::get().getWindowManager ()->disallowMouse(); - MWBase::Environment::get().getInputManager ()->enableDetectingBindingMode (actionId); + MWBase::Environment::get().getInputManager ()->enableDetectingBindingMode (actionId, mKeyboardMode); } @@ -511,7 +540,10 @@ namespace MWGui void SettingsWindow::onResetDefaultBindingsAccept() { - MWBase::Environment::get().getInputManager ()->resetToDefaultBindings (); + if(mKeyboardMode) + MWBase::Environment::get().getInputManager ()->resetToDefaultKeyBindings (); + else + MWBase::Environment::get().getInputManager()->resetToDefaultControllerBindings(); updateControlsBox (); } diff --git a/apps/openmw/mwgui/settingswindow.hpp b/apps/openmw/mwgui/settingswindow.hpp index 2619943f9..b4c3004af 100644 --- a/apps/openmw/mwgui/settingswindow.hpp +++ b/apps/openmw/mwgui/settingswindow.hpp @@ -45,6 +45,9 @@ namespace MWGui // controls MyGUI::ScrollView* mControlsBox; MyGUI::Button* mResetControlsButton; + MyGUI::Button* mKeyboardSwitch; + MyGUI::Button* mControllerSwitch; + bool mKeyboardMode; //if true, setting up the keyboard. Otherwise, it's controller void onOkButtonClicked(MyGUI::Widget* _sender); void onFpsToggled(MyGUI::Widget* _sender); @@ -62,6 +65,8 @@ namespace MWGui void onInputTabMouseWheel(MyGUI::Widget* _sender, int _rel); void onResetDefaultBindings(MyGUI::Widget* _sender); void onResetDefaultBindingsAccept (); + void onKeyboardSwitchClicked(MyGUI::Widget* _sender); + void onControllerSwitchClicked(MyGUI::Widget* _sender); void onWindowResize(MyGUI::Window* _sender); diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index b0d2bfeff..a25bb727c 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -2,6 +2,7 @@ #include #include +#include #include @@ -32,6 +33,8 @@ #include "../mwgui/windowbase.hpp" +#include + using namespace ICS; namespace @@ -120,6 +123,7 @@ namespace MWInput , mAlwaysRunActive(Settings::Manager::getBool("always run", "Input")) , mAttemptJump(false) , mControlsDisabled(false) + , mJoystickLastUsed(false) { Ogre::RenderWindow* window = ogre.getWindow (); @@ -128,6 +132,7 @@ namespace MWInput mInputManager->setMouseEventCallback (this); mInputManager->setKeyboardEventCallback (this); mInputManager->setWindowEventCallback(this); + mInputManager->setControllerEventCallback(this); std::string file = userFileExists ? userFile : ""; mInputBinder = new ICS::InputControlSystem(file, true, this, NULL, A_Last); @@ -135,6 +140,7 @@ namespace MWInput adjustMouseRegion (window->getWidth(), window->getHeight()); loadKeyDefaults(); + loadControllerDefaults(); for (int i = 0; i < A_Last; ++i) { @@ -190,6 +196,15 @@ namespace MWInput int action = channel->getNumber(); + if(currentValue > .8) currentValue = 1.0; + else if(currentValue < .6) currentValue = 0.0; + else return; + + if(previousValue > .8) previousValue = 1.0; + else if(previousValue < .6) previousValue = 0.0; + + if(currentValue == previousValue) return; + if (mControlSwitch["playercontrols"]) { if (action == A_Use) @@ -326,6 +341,47 @@ namespace MWInput mInputManager->warpMouse(mMouseX, mMouseY); } + if(mJoystickLastUsed) + { + if (mGuiCursorEnabled) + { + float xAxis = mInputBinder->getChannel(A_MoveLeftRight)->getValue()*2.0f-1.0f; + float yAxis = mInputBinder->getChannel(A_MoveForwardBackward)->getValue()*2.0f-1.0f; + float zAxis = mInputBinder->getChannel(A_LookUpDown)->getValue()*2.0f-1.0f; + const MyGUI::IntSize& viewSize = MyGUI::RenderManager::getInstance().getViewSize(); + + // We keep track of our own mouse position, so that moving the mouse while in + // game mode does not move the position of the GUI cursor + mMouseX += xAxis * dt * 1500.0f; + mMouseY += yAxis * dt * 1500.0f; + mMouseWheel -= zAxis * dt * 1500.0f; + + mMouseX = std::max(0.f, std::min(mMouseX, float(viewSize.width))); + mMouseY = std::max(0.f, std::min(mMouseY, float(viewSize.height))); + + MyGUI::InputManager::getInstance().injectMouseMove( mMouseX, mMouseY, mMouseWheel); + mInputManager->warpMouse(mMouseX, mMouseY); + } + if (mMouseLookEnabled) + { + float xAxis = mInputBinder->getChannel(A_LookLeftRight)->getValue()*2.0f-1.0f; + float yAxis = mInputBinder->getChannel(A_LookUpDown)->getValue()*2.0f-1.0f; + resetIdleTime(); + + float rot[3]; + rot[0] = yAxis * (dt * 100.0f) * 10.0f * mCameraSensitivity * (1.0f/256.f) * (mInvertY ? -1 : 1) * mCameraYMultiplier; + rot[1] = 0.0f; + rot[2] = xAxis * (dt * 100.0f) * 10.0f * mCameraSensitivity * (1.0f/256.f); + + // Only actually turn player when we're not in vanity mode + if(!MWBase::Environment::get().getWorld()->vanityRotateCamera(rot)) + { + mPlayer->yaw(rot[2]); + mPlayer->pitch(rot[0]); + } + } + } + // Disable movement in Gui mode if (!(MWBase::Environment::get().getWindowManager()->isGuiMode() || MWBase::Environment::get().getStateManager()->getState() != MWBase::StateManager::State_Running)) @@ -335,34 +391,74 @@ namespace MWInput if (mControlSwitch["playercontrols"]) { bool triedToMove = false; - if (actionIsActive(A_MoveLeft)) - { - triedToMove = true; - mPlayer->setLeftRight (-1); - } - else if (actionIsActive(A_MoveRight)) + bool isRunning = false; + if(mJoystickLastUsed) { - triedToMove = true; - mPlayer->setLeftRight (1); - } + float xAxis = mInputBinder->getChannel(A_MoveLeftRight)->getValue(); + float yAxis = mInputBinder->getChannel(A_MoveForwardBackward)->getValue(); + if (xAxis < .5) + { + triedToMove = true; + mPlayer->setLeftRight (-1); + } + else if (xAxis > .5) + { + triedToMove = true; + mPlayer->setLeftRight (1); + } - if (actionIsActive(A_MoveForward)) - { - triedToMove = true; - mPlayer->setAutoMove (false); - mPlayer->setForwardBackward (1); + if (yAxis < .5) + { + triedToMove = true; + mPlayer->setAutoMove (false); + mPlayer->setForwardBackward (1); + } + else if (yAxis > .5) + { + triedToMove = true; + mPlayer->setAutoMove (false); + mPlayer->setForwardBackward (-1); + } + + else if(mPlayer->getAutoMove()) + { + triedToMove = true; + mPlayer->setForwardBackward (1); + } + isRunning = xAxis > .75 || xAxis < .25 || yAxis > .75 || yAxis < .25; + if(triedToMove) resetIdleTime(); } - else if (actionIsActive(A_MoveBackward)) + else { - triedToMove = true; - mPlayer->setAutoMove (false); - mPlayer->setForwardBackward (-1); - } + if (actionIsActive(A_MoveLeft)) + { + triedToMove = true; + mPlayer->setLeftRight (-1); + } + else if (actionIsActive(A_MoveRight)) + { + triedToMove = true; + mPlayer->setLeftRight (1); + } - else if(mPlayer->getAutoMove()) - { - triedToMove = true; - mPlayer->setForwardBackward (1); + if (actionIsActive(A_MoveForward)) + { + triedToMove = true; + mPlayer->setAutoMove (false); + mPlayer->setForwardBackward (1); + } + else if (actionIsActive(A_MoveBackward)) + { + triedToMove = true; + mPlayer->setAutoMove (false); + mPlayer->setForwardBackward (-1); + } + + else if(mPlayer->getAutoMove()) + { + triedToMove = true; + mPlayer->setForwardBackward (1); + } } mPlayer->setSneak(actionIsActive(A_Sneak)); @@ -374,7 +470,7 @@ namespace MWInput mOverencumberedMessageDelay = 0.f; } - if (mAlwaysRunActive) + if (mAlwaysRunActive || isRunning) mPlayer->setRunState(!actionIsActive(A_Run)); else mPlayer->setRunState(actionIsActive(A_Run)); @@ -519,6 +615,7 @@ namespace MWInput } if (!mControlsDisabled && !consumed) mInputBinder->keyPressed (arg); + mJoystickLastUsed = false; } void InputManager::textInput(const SDL_TextInputEvent &arg) @@ -531,6 +628,7 @@ namespace MWInput void InputManager::keyReleased(const SDL_KeyboardEvent &arg ) { + mJoystickLastUsed = false; OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(arg.keysym.sym); setPlayerControlsEnabled(!MyGUI::InputManager::getInstance().injectKeyRelease(MyGUI::KeyCode::Enum(kc))); @@ -539,6 +637,7 @@ namespace MWInput void InputManager::mousePressed( const SDL_MouseButtonEvent &arg, Uint8 id ) { + mJoystickLastUsed = false; bool guiMode = false; if (id == SDL_BUTTON_LEFT || id == SDL_BUTTON_RIGHT) // MyGUI only uses these mouse events @@ -563,7 +662,8 @@ namespace MWInput } void InputManager::mouseReleased( const SDL_MouseButtonEvent &arg, Uint8 id ) - { + { + mJoystickLastUsed = false; if(mInputBinder->detectingBindingState()) { @@ -583,6 +683,7 @@ namespace MWInput { mInputBinder->mouseMoved (arg); + mJoystickLastUsed = false; resetIdleTime (); if (mGuiCursorEnabled) @@ -631,6 +732,75 @@ namespace MWInput } } + void InputManager::buttonPressed( const SDL_ControllerButtonEvent &arg ) + { + mJoystickLastUsed = true; + bool guiMode = false; + + if (arg.button == SDL_CONTROLLER_BUTTON_A || arg.button == SDL_CONTROLLER_BUTTON_B) // We'll pretend that A is left click and B is right click + { + guiMode = MWBase::Environment::get().getWindowManager()->isGuiMode(); + guiMode = MyGUI::InputManager::getInstance().injectMousePress(mMouseX, mMouseY, sdlButtonToMyGUI((arg.button == SDL_CONTROLLER_BUTTON_B) ? SDL_BUTTON_RIGHT : SDL_BUTTON_LEFT)) && guiMode; + if (MyGUI::InputManager::getInstance ().getMouseFocusWidget () != 0) + { + MyGUI::Button* b = MyGUI::InputManager::getInstance ().getMouseFocusWidget ()->castType(false); + if (b && b->getEnabled()) + { + MWBase::Environment::get().getSoundManager ()->playSound ("Menu Click", 1.f, 1.f); + } + } + } + + setPlayerControlsEnabled(!guiMode); + + //esc, to leave inital movie screen + OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(SDLK_ESCAPE); + bool guiFocus = MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::Enum(kc), 0); + setPlayerControlsEnabled(!guiFocus); + + if (!mControlsDisabled) + mInputBinder->buttonPressed(arg); + } + + void InputManager::buttonReleased( const SDL_ControllerButtonEvent &arg ) + { + mJoystickLastUsed = true; + if(mInputBinder->detectingBindingState()) + mInputBinder->buttonReleased(arg); + else if(arg.button == SDL_CONTROLLER_BUTTON_A || arg.button == SDL_CONTROLLER_BUTTON_B) + { + bool guiMode = MWBase::Environment::get().getWindowManager()->isGuiMode(); + guiMode = MyGUI::InputManager::getInstance().injectMouseRelease(mMouseX, mMouseY, sdlButtonToMyGUI((arg.button == SDL_CONTROLLER_BUTTON_B) ? SDL_BUTTON_RIGHT : SDL_BUTTON_LEFT)) && guiMode; + + if(mInputBinder->detectingBindingState()) return; // don't allow same mouseup to bind as initiated bind + + setPlayerControlsEnabled(!guiMode); + mInputBinder->buttonReleased(arg); + } + else + mInputBinder->buttonReleased(arg); + + //to escape inital movie + OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(SDLK_ESCAPE); + setPlayerControlsEnabled(!MyGUI::InputManager::getInstance().injectKeyRelease(MyGUI::KeyCode::Enum(kc))); + } + + void InputManager::axisMoved( const SDL_ControllerAxisEvent &arg ) + { + mJoystickLastUsed = true; + if (!mControlsDisabled) + mInputBinder->axisMoved(arg); + } + + void InputManager::controllerAdded(const SDL_ControllerDeviceEvent &arg) + { + mInputBinder->controllerAdded(arg); + } + void InputManager::controllerRemoved(const SDL_ControllerDeviceEvent &arg) + { + mInputBinder->controllerRemoved(arg); + } + void InputManager::windowFocusChange(bool have_focus) { } @@ -877,7 +1047,7 @@ namespace MWInput bool InputManager::actionIsActive (int id) { - return mInputBinder->getChannel (id)->getValue () == 1; + return (mInputBinder->getChannel (id)->getValue ()!=0.0); } void InputManager::loadKeyDefaults (bool force) @@ -945,14 +1115,80 @@ namespace MWInput && mInputBinder->getMouseButtonBinding (control, ICS::Control::INCREASE) == ICS_MAX_DEVICE_BUTTONS )) { - clearAllBindings (control); + clearAllKeyBindings(control); if (defaultKeyBindings.find(i) != defaultKeyBindings.end() && !mInputBinder->isKeyBound(defaultKeyBindings[i])) + { mInputBinder->addKeyBinding(control, defaultKeyBindings[i], ICS::Control::INCREASE); + } else if (defaultMouseButtonBindings.find(i) != defaultMouseButtonBindings.end() && !mInputBinder->isMouseButtonBound(defaultMouseButtonBindings[i])) + { mInputBinder->addMouseButtonBinding (control, defaultMouseButtonBindings[i], ICS::Control::INCREASE); + } + } + } + } + + void InputManager::loadControllerDefaults(bool force) + { + // using hardcoded key defaults is inevitable, if we want the configuration files to stay valid + // across different versions of OpenMW (in the case where another input action is added) + std::map defaultButtonBindings; + + defaultButtonBindings[A_Activate] = SDL_CONTROLLER_BUTTON_A; + defaultButtonBindings[A_ToggleWeapon] = SDL_CONTROLLER_BUTTON_X; + defaultButtonBindings[A_ToggleSpell] = SDL_CONTROLLER_BUTTON_LEFTSHOULDER; + //defaultButtonBindings[A_QuickButtonsMenu] = SDL_GetButtonFromScancode(SDL_SCANCODE_F1); // Need to implement, should be ToggleSpell(5) AND Wait(9) + defaultButtonBindings[A_Sneak] = SDL_CONTROLLER_BUTTON_RIGHTSTICK; + defaultButtonBindings[A_Jump] = SDL_CONTROLLER_BUTTON_Y; + defaultButtonBindings[A_Journal] = SDL_CONTROLLER_BUTTON_RIGHTSHOULDER; + defaultButtonBindings[A_Rest] = SDL_CONTROLLER_BUTTON_BACK; + defaultButtonBindings[A_TogglePOV] = SDL_CONTROLLER_BUTTON_LEFTSTICK; + defaultButtonBindings[A_Inventory] = SDL_CONTROLLER_BUTTON_B; + defaultButtonBindings[A_GameMenu] = SDL_CONTROLLER_BUTTON_START; + defaultButtonBindings[A_QuickSave] = SDL_CONTROLLER_BUTTON_GUIDE; + defaultButtonBindings[A_QuickKey1] = SDL_CONTROLLER_BUTTON_DPAD_UP; + defaultButtonBindings[A_QuickKey2] = SDL_CONTROLLER_BUTTON_DPAD_LEFT; + defaultButtonBindings[A_QuickKey3] = SDL_CONTROLLER_BUTTON_DPAD_DOWN; + defaultButtonBindings[A_QuickKey4] = SDL_CONTROLLER_BUTTON_DPAD_RIGHT; + + std::map defaultAxisBindings; + defaultAxisBindings[A_MoveForwardBackward] = SDL_CONTROLLER_AXIS_LEFTY; + defaultAxisBindings[A_MoveLeftRight] = SDL_CONTROLLER_AXIS_LEFTX; + defaultAxisBindings[A_LookUpDown] = SDL_CONTROLLER_AXIS_RIGHTY; + defaultAxisBindings[A_LookLeftRight] = SDL_CONTROLLER_AXIS_RIGHTX; + defaultAxisBindings[A_Use] = SDL_CONTROLLER_AXIS_TRIGGERRIGHT; + + for (int i = 0; i < A_Last; i++) + { + ICS::Control* control; + bool controlExists = mInputBinder->getChannel(i)->getControlsCount () != 0; + if (!controlExists) + { + control = new ICS::Control(boost::lexical_cast(i), false, true, 0, ICS::ICS_MAX, ICS::ICS_MAX); + mInputBinder->addControl(control); + control->attachChannel(mInputBinder->getChannel(i), ICS::Channel::DIRECT); + } + else + { + control = mInputBinder->getChannel(i)->getAttachedControls ().front().control; + } + + if (!controlExists || force || ( mInputBinder->getJoystickAxisBinding (control, ICS::Control::INCREASE) == ICS::InputControlSystem::UNASSIGNED && mInputBinder->getJoystickButtonBinding (control, ICS::Control::INCREASE) == ICS_MAX_DEVICE_BUTTONS )) + { + clearAllControllerBindings(control); + + if (defaultButtonBindings.find(i) != defaultButtonBindings.end()) + { + control->setValue(0.5f); + mInputBinder->addJoystickButtonBinding(control, defaultButtonBindings[i], ICS::Control::INCREASE); + } + else if (defaultAxisBindings.find(i) != defaultAxisBindings.end()) + { + mInputBinder->addJoystickAxisBinding(control, defaultAxisBindings[i], ICS::Control::INCREASE); + } } } } @@ -1002,7 +1238,7 @@ namespace MWInput return "#{" + descriptions[action] + "}"; } - std::string InputManager::getActionBindingName (int action) + std::string InputManager::getActionKeyBindingName (int action) { if (mInputBinder->getChannel (action)->getControlsCount () == 0) return "#{sNone}"; @@ -1017,7 +1253,81 @@ namespace MWInput return "#{sNone}"; } - std::vector InputManager::getActionSorting() + std::string InputManager::getActionControllerBindingName (int action) + { + if (mInputBinder->getChannel (action)->getControlsCount () == 0) + return "#{sNone}"; + + ICS::Control* c = mInputBinder->getChannel (action)->getAttachedControls ().front().control; + + if (mInputBinder->getJoystickAxisBinding (c, ICS::Control::INCREASE) != ICS::InputControlSystem::UNASSIGNED) + return sdlControllerAxisToString(mInputBinder->getJoystickAxisBinding (c, ICS::Control::INCREASE)); + else if (mInputBinder->getJoystickButtonBinding (c, ICS::Control::INCREASE) != ICS_MAX_DEVICE_BUTTONS ) + return sdlControllerButtonToString(mInputBinder->getJoystickButtonBinding (c, ICS::Control::INCREASE)); + else + return "#{sNone}"; + } + + std::string InputManager::sdlControllerButtonToString(int button) + { + switch(button) + { + case SDL_CONTROLLER_BUTTON_A: + return "A Button"; + case SDL_CONTROLLER_BUTTON_B: + return "B Button"; + case SDL_CONTROLLER_BUTTON_BACK: + return "Back Button"; + case SDL_CONTROLLER_BUTTON_DPAD_DOWN: + return "DPad Down"; + case SDL_CONTROLLER_BUTTON_DPAD_LEFT: + return "DPad Left"; + case SDL_CONTROLLER_BUTTON_DPAD_RIGHT: + return "DPad Right"; + case SDL_CONTROLLER_BUTTON_DPAD_UP: + return "DPad Up"; + case SDL_CONTROLLER_BUTTON_GUIDE: + return "Guide Button"; + case SDL_CONTROLLER_BUTTON_LEFTSHOULDER: + return "Left Shoulder"; + case SDL_CONTROLLER_BUTTON_LEFTSTICK: + return "Left Stick Button"; + case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER: + return "Right Shoulder"; + case SDL_CONTROLLER_BUTTON_RIGHTSTICK: + return "Right Stick Button"; + case SDL_CONTROLLER_BUTTON_START: + return "Start Button"; + case SDL_CONTROLLER_BUTTON_X: + return "X Button"; + case SDL_CONTROLLER_BUTTON_Y: + return "Y Button"; + default: + return "Button " + boost::lexical_cast(button); + } + } + std::string InputManager::sdlControllerAxisToString(int axis) + { + switch(axis) + { + case SDL_CONTROLLER_AXIS_LEFTX: + return "Left Stick X"; + case SDL_CONTROLLER_AXIS_LEFTY: + return "Left Stick Y"; + case SDL_CONTROLLER_AXIS_RIGHTX: + return "Right Stick X"; + case SDL_CONTROLLER_AXIS_RIGHTY: + return "Right Stick Y"; + case SDL_CONTROLLER_AXIS_TRIGGERLEFT: + return "Left Trigger"; + case SDL_CONTROLLER_AXIS_TRIGGERRIGHT: + return "Right Trigger"; + default: + return "Axis " + boost::lexical_cast(axis); + } + } + + std::vector InputManager::getActionKeySorting() { std::vector ret; ret.push_back(A_MoveForward); @@ -1055,11 +1365,42 @@ namespace MWInput return ret; } + std::vector InputManager::getActionControllerSorting() + { + std::vector ret; + ret.push_back(A_TogglePOV); + ret.push_back(A_Sneak); + ret.push_back(A_Activate); + ret.push_back(A_Use); + ret.push_back(A_ToggleWeapon); + ret.push_back(A_ToggleSpell); + ret.push_back(A_AutoMove); + ret.push_back(A_Jump); + ret.push_back(A_Inventory); + ret.push_back(A_Journal); + ret.push_back(A_Rest); + ret.push_back(A_QuickSave); + ret.push_back(A_QuickLoad); + ret.push_back(A_Screenshot); + ret.push_back(A_QuickKeysMenu); + ret.push_back(A_QuickKey1); + ret.push_back(A_QuickKey2); + ret.push_back(A_QuickKey3); + ret.push_back(A_QuickKey4); + ret.push_back(A_QuickKey5); + ret.push_back(A_QuickKey6); + ret.push_back(A_QuickKey7); + ret.push_back(A_QuickKey8); + ret.push_back(A_QuickKey9); + ret.push_back(A_QuickKey10); + + return ret; + } - void InputManager::enableDetectingBindingMode (int action) + void InputManager::enableDetectingBindingMode (int action, bool keyboard) { + mDetectingKeyboard = keyboard; ICS::Control* c = mInputBinder->getChannel (action)->getAttachedControls ().front().control; - mInputBinder->enableDetectingBindingState (c, ICS::Control::INCREASE); } @@ -1075,9 +1416,16 @@ namespace MWInput { //Disallow binding escape key if(key==SDL_SCANCODE_ESCAPE) + { + //Stop binding if esc pressed + mInputBinder->cancelDetectingBindingState(); + MWBase::Environment::get().getWindowManager ()->notifyInputActionBound (); + return; + } + if(!mDetectingKeyboard) return; - clearAllBindings(control); + clearAllKeyBindings(control); ICS::DetectingBindingListener::keyBindingDetected (ICS, control, key, direction); MWBase::Environment::get().getWindowManager ()->notifyInputActionBound (); } @@ -1085,59 +1433,66 @@ namespace MWInput void InputManager::mouseButtonBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control , unsigned int button, ICS::Control::ControlChangingDirection direction) { - clearAllBindings(control); + if(!mDetectingKeyboard) + return; + clearAllKeyBindings(control); ICS::DetectingBindingListener::mouseButtonBindingDetected (ICS, control, button, direction); MWBase::Environment::get().getWindowManager ()->notifyInputActionBound (); } void InputManager::joystickAxisBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control - , int deviceId, int axis, ICS::Control::ControlChangingDirection direction) + , int axis, ICS::Control::ControlChangingDirection direction) { - clearAllBindings(control); - ICS::DetectingBindingListener::joystickAxisBindingDetected (ICS, control, deviceId, axis, direction); - MWBase::Environment::get().getWindowManager ()->notifyInputActionBound (); - } - - void InputManager::joystickButtonBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control - , int deviceId, unsigned int button, ICS::Control::ControlChangingDirection direction) - { - clearAllBindings(control); - ICS::DetectingBindingListener::joystickButtonBindingDetected (ICS, control, deviceId, button, direction); - MWBase::Environment::get().getWindowManager ()->notifyInputActionBound (); - } + //only allow binding to the trigers + if(axis != SDL_CONTROLLER_AXIS_TRIGGERLEFT && axis != SDL_CONTROLLER_AXIS_TRIGGERRIGHT) + return; + if(mDetectingKeyboard) + return; - void InputManager::joystickPOVBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control - , int deviceId, int pov,ICS:: InputControlSystem::POVAxis axis, ICS::Control::ControlChangingDirection direction) - { - clearAllBindings(control); - ICS::DetectingBindingListener::joystickPOVBindingDetected (ICS, control, deviceId, pov, axis, direction); + clearAllControllerBindings(control); + control->setValue(0.5f); //axis bindings must start at 0.5 + ICS::DetectingBindingListener::joystickAxisBindingDetected (ICS, control, axis, direction); MWBase::Environment::get().getWindowManager ()->notifyInputActionBound (); } - void InputManager::joystickSliderBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control - , int deviceId, int slider, ICS::Control::ControlChangingDirection direction) + void InputManager::joystickButtonBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control + , unsigned int button, ICS::Control::ControlChangingDirection direction) { - clearAllBindings(control); - ICS::DetectingBindingListener::joystickSliderBindingDetected (ICS, control, deviceId, slider, direction); + if(mDetectingKeyboard) + return; + clearAllControllerBindings(control); + ICS::DetectingBindingListener::joystickButtonBindingDetected (ICS, control, button, direction); MWBase::Environment::get().getWindowManager ()->notifyInputActionBound (); } - void InputManager::clearAllBindings (ICS::Control* control) + void InputManager::clearAllKeyBindings (ICS::Control* control) { // right now we don't really need multiple bindings for the same action, so remove all others first if (mInputBinder->getKeyBinding (control, ICS::Control::INCREASE) != SDL_SCANCODE_UNKNOWN) mInputBinder->removeKeyBinding (mInputBinder->getKeyBinding (control, ICS::Control::INCREASE)); if (mInputBinder->getMouseButtonBinding (control, ICS::Control::INCREASE) != ICS_MAX_DEVICE_BUTTONS) mInputBinder->removeMouseButtonBinding (mInputBinder->getMouseButtonBinding (control, ICS::Control::INCREASE)); + } - /// \todo add joysticks here once they are added + void InputManager::clearAllControllerBindings (ICS::Control* control) + { + // right now we don't really need multiple bindings for the same action, so remove all others first + if (mInputBinder->getJoystickAxisBinding (control, ICS::Control::INCREASE) != SDL_SCANCODE_UNKNOWN) + mInputBinder->removeJoystickAxisBinding (mInputBinder->getJoystickAxisBinding (control, ICS::Control::INCREASE)); + if (mInputBinder->getJoystickButtonBinding (control, ICS::Control::INCREASE) != ICS_MAX_DEVICE_BUTTONS) + mInputBinder->removeJoystickButtonBinding (mInputBinder->getJoystickButtonBinding (control, ICS::Control::INCREASE)); } - void InputManager::resetToDefaultBindings() + void InputManager::resetToDefaultKeyBindings() { loadKeyDefaults(true); } + void InputManager::resetToDefaultControllerBindings() + { + loadControllerDefaults(true); + } + MyGUI::MouseButton InputManager::sdlButtonToMyGUI(Uint8 button) { //The right button is the second button, according to MyGUI diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 346e02ff9..61dbf18f8 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -55,6 +55,7 @@ namespace MWInput public SFO::KeyListener, public SFO::MouseListener, public SFO::WindowListener, + public SFO::ControllerListener, public ICS::ChannelListener, public ICS::DetectingBindingListener { @@ -82,11 +83,16 @@ namespace MWInput virtual bool getControlSwitch (const std::string& sw); virtual std::string getActionDescription (int action); - virtual std::string getActionBindingName (int action); + virtual std::string getActionKeyBindingName (int action); + virtual std::string getActionControllerBindingName (int action); + virtual std::string sdlControllerAxisToString(int axis); + virtual std::string sdlControllerButtonToString(int button); virtual int getNumActions() { return A_Last; } - virtual std::vector getActionSorting (); - virtual void enableDetectingBindingMode (int action); - virtual void resetToDefaultBindings(); + virtual std::vector getActionKeySorting(); + virtual std::vector getActionControllerSorting(); + virtual void enableDetectingBindingMode (int action, bool keyboard); + virtual void resetToDefaultKeyBindings(); + virtual void resetToDefaultControllerBindings(); public: virtual void keyPressed(const SDL_KeyboardEvent &arg ); @@ -97,6 +103,12 @@ namespace MWInput virtual void mouseReleased( const SDL_MouseButtonEvent &arg, Uint8 id ); virtual void mouseMoved( const SFO::MouseMotionEvent &arg ); + virtual void buttonPressed( const SDL_ControllerButtonEvent &arg); + virtual void buttonReleased( const SDL_ControllerButtonEvent &arg); + virtual void axisMoved( const SDL_ControllerAxisEvent &arg); + virtual void controllerAdded( const SDL_ControllerDeviceEvent &arg); + virtual void controllerRemoved( const SDL_ControllerDeviceEvent &arg); + virtual void windowVisibilityChange( bool visible ); virtual void windowFocusChange( bool have_focus ); virtual void windowResized (int x, int y); @@ -114,20 +126,16 @@ namespace MWInput , unsigned int button, ICS::Control::ControlChangingDirection direction); virtual void joystickAxisBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control - , int deviceId, int axis, ICS::Control::ControlChangingDirection direction); + , int axis, ICS::Control::ControlChangingDirection direction); virtual void joystickButtonBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control - , int deviceId, unsigned int button, ICS::Control::ControlChangingDirection direction); - - virtual void joystickPOVBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control - , int deviceId, int pov,ICS:: InputControlSystem::POVAxis axis, ICS::Control::ControlChangingDirection direction); - - virtual void joystickSliderBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control - , int deviceId, int slider, ICS::Control::ControlChangingDirection direction); + , unsigned int button, ICS::Control::ControlChangingDirection direction); - void clearAllBindings (ICS::Control* control); + void clearAllKeyBindings (ICS::Control* control); + void clearAllControllerBindings (ICS::Control* control); private: + bool mJoystickLastUsed; OEngine::Render::OgreRenderer &mOgre; MWWorld::Player* mPlayer; OMW::Engine& mEngine; @@ -156,6 +164,8 @@ namespace MWInput bool mMouseLookEnabled; bool mGuiCursorEnabled; + bool mDetectingKeyboard; + float mOverencumberedMessageDelay; float mMouseX; @@ -191,12 +201,15 @@ namespace MWInput void quickLoad(); void quickSave(); + bool isAReverse(int action); + void quickKey (int index); void showQuickKeysMenu(); bool actionIsActive (int id); void loadKeyDefaults(bool force = false); + void loadControllerDefaults(bool force = false); private: enum Actions @@ -261,6 +274,11 @@ namespace MWInput A_ToggleDebug, + A_LookUpDown, //Joystick look + A_LookLeftRight, + A_MoveForwardBackward, + A_MoveLeftRight, + A_Last // Marker for the last item }; }; diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index d8d13a921..b71e92555 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -268,7 +268,7 @@ namespace MWScript std::string InterpreterContext::getActionBinding(const std::string& action) const { - std::vector actions = MWBase::Environment::get().getInputManager()->getActionSorting (); + std::vector actions = MWBase::Environment::get().getInputManager()->getActionKeySorting (); for (std::vector::const_iterator it = actions.begin(); it != actions.end(); ++it) { std::string desc = MWBase::Environment::get().getInputManager()->getActionDescription (*it); @@ -276,7 +276,7 @@ namespace MWScript continue; if(desc == action) - return MWBase::Environment::get().getInputManager()->getActionBindingName (*it); + return MWBase::Environment::get().getInputManager()->getActionKeyBindingName (*it); } return "None"; diff --git a/extern/oics/ICSControl.cpp b/extern/oics/ICSControl.cpp index 7c804d6ee..974d69f08 100644 --- a/extern/oics/ICSControl.cpp +++ b/extern/oics/ICSControl.cpp @@ -43,10 +43,10 @@ namespace ICS , mAxisBindable(axisBindable) , currentChangingDirection(STOP) { - + } - Control::~Control() + Control::~Control() { mAttachedChannels.clear(); } @@ -92,7 +92,7 @@ namespace ICS } void Control::setChangingDirection(ControlChangingDirection direction) - { + { currentChangingDirection = direction; mPendingActions.push_back(direction); } @@ -102,9 +102,9 @@ namespace ICS if(!mPendingActions.empty()) { size_t timedActionsCount = 0; - + std::list::iterator cached_end = mPendingActions.end(); - for(std::list::iterator it = mPendingActions.begin() ; + for(std::list::iterator it = mPendingActions.begin() ; it != cached_end ; ++it) { if( (*it) != Control::STOP ) @@ -112,14 +112,14 @@ namespace ICS timedActionsCount++; } } - + float timeSinceLastFramePart = timeSinceLastFrame / std::max(1, timedActionsCount); - for(std::list::iterator it = mPendingActions.begin() ; + for(std::list::iterator it = mPendingActions.begin() ; it != cached_end ; ++it) { if( (*it) != Control::STOP ) { - this->setValue(mValue + + this->setValue(mValue + (((int)(*it)) * mStepSize * mStepsPerSeconds * (timeSinceLastFramePart))); } else if(mAutoReverseToInitialValue && !mIgnoreAutoReverse && mValue != mInitialValue ) @@ -141,7 +141,7 @@ namespace ICS } else if( currentChangingDirection != Control::STOP ) { - this->setValue(mValue + + this->setValue(mValue + (((int)currentChangingDirection) * mStepSize * mStepsPerSeconds * (timeSinceLastFrame))); } else if(mAutoReverseToInitialValue && !mIgnoreAutoReverse && mValue != mInitialValue ) diff --git a/extern/oics/ICSInputControlSystem.cpp b/extern/oics/ICSInputControlSystem.cpp index 7dc026c7e..4237060bb 100644 --- a/extern/oics/ICSInputControlSystem.cpp +++ b/extern/oics/ICSInputControlSystem.cpp @@ -57,10 +57,10 @@ namespace ICS xmlDoc = new TiXmlDocument(file.c_str()); xmlDoc->LoadFile(); - if(xmlDoc->Error()) + if(xmlDoc->Error()) { - std::ostringstream message; - message << "TinyXml reported an error reading \""+ file + "\". Row " << + std::ostringstream message; + message << "TinyXml reported an error reading \""+ file + "\". Row " << (int)xmlDoc->ErrorRow() << ", Col " << (int)xmlDoc->ErrorCol() << ": " << xmlDoc->ErrorDesc() ; ICS_LOG(message.str()); @@ -78,10 +78,10 @@ namespace ICS TiXmlElement* xmlControl = xmlRoot->FirstChildElement("Control"); - size_t controlChannelCount = 0; - while(xmlControl) + size_t controlChannelCount = 0; + while(xmlControl) { - TiXmlElement* xmlChannel = xmlControl->FirstChildElement("Channel"); + TiXmlElement* xmlChannel = xmlControl->FirstChildElement("Channel"); while(xmlChannel) { controlChannelCount = std::max(channelCount, FromString(xmlChannel->Attribute("number"))+1); @@ -108,7 +108,7 @@ namespace ICS // // - TiXmlElement* xmlChannelFilter = xmlRoot->FirstChildElement("ChannelFilter"); + TiXmlElement* xmlChannelFilter = xmlRoot->FirstChildElement("ChannelFilter"); while(xmlChannelFilter) { int ch = FromString(xmlChannelFilter->Attribute("number")); @@ -130,12 +130,12 @@ namespace ICS float step = FromString(xmlInterval->Attribute("step")); ICS_LOG("Applying Bezier filter to channel [number=" - + ToString(ch) + ", startX=" - + ToString(startX) + ", startY=" - + ToString(startY) + ", midX=" - + ToString(midX) + ", midY=" - + ToString(midY) + ", endX=" - + ToString(endX) + ", endY=" + + ToString(ch) + ", startX=" + + ToString(startX) + ", startY=" + + ToString(startY) + ", midX=" + + ToString(midX) + ", midY=" + + ToString(midY) + ", endX=" + + ToString(endX) + ", endY=" + ToString(endY) + ", step=" + ToString(step) + "]"); @@ -149,8 +149,8 @@ namespace ICS xmlChannelFilter = xmlChannelFilter->NextSiblingElement("ChannelFilter"); } - xmlControl = xmlRoot->FirstChildElement("Control"); - while(xmlControl) + xmlControl = xmlRoot->FirstChildElement("Control"); + while(xmlControl) { bool axisBindable = true; if(xmlControl->Attribute("axisBindable")) @@ -173,11 +173,11 @@ namespace ICS std::string value(xmlControl->Attribute("stepSize")); if(value == "MAX") { - _stepSize = ICS_MAX; + _stepSize = ICS_MAX; } else { - _stepSize = FromString(value.c_str()); + _stepSize = FromString(value.c_str()); } } else @@ -191,7 +191,7 @@ namespace ICS std::string value(xmlControl->Attribute("stepsPerSeconds")); if(value == "MAX") { - _stepsPerSeconds = ICS_MAX; + _stepsPerSeconds = ICS_MAX; } else { @@ -221,12 +221,8 @@ namespace ICS loadJoystickButtonBinders(xmlControl); - loadJoystickPOVBinders(xmlControl); - - loadJoystickSliderBinders(xmlControl); - // Attach controls to channels - TiXmlElement* xmlChannel = xmlControl->FirstChildElement("Channel"); + TiXmlElement* xmlChannel = xmlControl->FirstChildElement("Channel"); while(xmlChannel) { ICS_LOG("\tAttaching control to channel [number=" @@ -247,7 +243,7 @@ namespace ICS { percentage = val; } - } + } else { ICS_LOG("ERROR: attaching percentage value range is [0,1]"); @@ -277,6 +273,35 @@ namespace ICS } delete xmlDoc; + } + + /* Joystick Init */ + + //Load controller mappings + int res = SDL_GameControllerAddMappingsFromFile("resources/gamecontrollerdb.txt"); + if(res == -1) + { + ICS_LOG(std::string("Error loading controller bindings: ")+SDL_GetError()); + } + else + { + ICS_LOG(std::string("Loaded ")+boost::lexical_cast(res)+" Game controller bindings"); + } + + //Open all presently connected sticks + int numSticks = SDL_NumJoysticks(); + for(int i = 0; i < numSticks; i++) + { + if(SDL_IsGameController(i)) + { + SDL_ControllerDeviceEvent evt; + evt.which = i; + controllerAdded(evt); + } + else + { + ICS_LOG(std::string("Unusable controller plugged in: ")+SDL_JoystickNameForIndex(i)); + } } ICS_LOG(" - InputControlSystem Created - "); @@ -335,7 +360,7 @@ namespace ICS for(std::vector::const_iterator o = mChannels.begin() ; o != mChannels.end(); ++o) { ICS::IntervalList intervals = (*o)->getIntervals(); - + if(intervals.size() > 1) // all channels have a default linear filter { TiXmlElement ChannelFilter( "ChannelFilter" ); @@ -368,7 +393,7 @@ namespace ICS ChannelFilter.InsertEndChild(XMLInterval); } - + ++interval; } @@ -398,7 +423,7 @@ namespace ICS control.SetAttribute( "autoReverseToInitialValue", "false" ); } control.SetAttribute( "initialValue", ToString((*o)->getInitialValue()).c_str() ); - + if((*o)->getStepSize() == ICS_MAX) { control.SetAttribute( "stepSize", "MAX" ); @@ -442,12 +467,12 @@ namespace ICS control.InsertEndChild(keyBinder); } - if(getMouseAxisBinding(*o, Control/*::ControlChangingDirection*/::INCREASE) + if(getMouseAxisBinding(*o, Control/*::ControlChangingDirection*/::INCREASE) != InputControlSystem/*::NamedAxis*/::UNASSIGNED) { TiXmlElement binder( "MouseBinder" ); - InputControlSystem::NamedAxis axis = + InputControlSystem::NamedAxis axis = getMouseAxisBinding(*o, Control/*::ControlChangingDirection*/::INCREASE); if(axis == InputControlSystem/*::NamedAxis*/::X) { @@ -466,12 +491,12 @@ namespace ICS control.InsertEndChild(binder); } - if(getMouseAxisBinding(*o, Control/*::ControlChangingDirection*/::DECREASE) + if(getMouseAxisBinding(*o, Control/*::ControlChangingDirection*/::DECREASE) != InputControlSystem/*::NamedAxis*/::UNASSIGNED) { TiXmlElement binder( "MouseBinder" ); - InputControlSystem::NamedAxis axis = + InputControlSystem::NamedAxis axis = getMouseAxisBinding(*o, Control/*::ControlChangingDirection*/::DECREASE); if(axis == InputControlSystem/*::NamedAxis*/::X) { @@ -490,7 +515,7 @@ namespace ICS control.InsertEndChild(binder); } - if(getMouseButtonBinding(*o, Control/*::ControlChangingDirection*/::INCREASE) + if(getMouseButtonBinding(*o, Control/*::ControlChangingDirection*/::INCREASE) != ICS_MAX_DEVICE_BUTTONS) { TiXmlElement binder( "MouseButtonBinder" ); @@ -516,7 +541,7 @@ namespace ICS control.InsertEndChild(binder); } - if(getMouseButtonBinding(*o, Control/*::ControlChangingDirection*/::DECREASE) + if(getMouseButtonBinding(*o, Control/*::ControlChangingDirection*/::DECREASE) != ICS_MAX_DEVICE_BUTTONS) { TiXmlElement binder( "MouseButtonBinder" ); @@ -541,152 +566,57 @@ namespace ICS binder.SetAttribute( "direction", "DECREASE" ); control.InsertEndChild(binder); } + if(getJoystickAxisBinding(*o, Control/*::ControlChangingDirection*/::INCREASE) + != /*NamedAxis::*/UNASSIGNED) + { + TiXmlElement binder( "JoystickAxisBinder" ); - JoystickIDList::const_iterator it = mJoystickIDList.begin(); - while(it != mJoystickIDList.end()) - { - int deviceId = *it; - - if(getJoystickAxisBinding(*o, deviceId, Control/*::ControlChangingDirection*/::INCREASE) - != /*NamedAxis::*/UNASSIGNED) - { - TiXmlElement binder( "JoystickAxisBinder" ); - - binder.SetAttribute( "axis", ToString( - getJoystickAxisBinding(*o, deviceId, Control/*::ControlChangingDirection*/::INCREASE)).c_str() ); - - binder.SetAttribute( "direction", "INCREASE" ); - - binder.SetAttribute( "deviceId", ToString(deviceId).c_str() ); - - control.InsertEndChild(binder); - } - - if(getJoystickAxisBinding(*o, deviceId, Control/*::ControlChangingDirection*/::DECREASE) - != /*NamedAxis::*/UNASSIGNED) - { - TiXmlElement binder( "JoystickAxisBinder" ); - - binder.SetAttribute( "axis", ToString( - getJoystickAxisBinding(*o, deviceId, Control/*::ControlChangingDirection*/::DECREASE)).c_str() ); - - binder.SetAttribute( "direction", "DECREASE" ); + binder.SetAttribute( "axis", ToString( + getJoystickAxisBinding(*o, Control/*::ControlChangingDirection*/::INCREASE)).c_str() ); - binder.SetAttribute( "deviceId", ToString(deviceId).c_str() ); - - control.InsertEndChild(binder); - } + binder.SetAttribute( "direction", "INCREASE" ); - if(getJoystickButtonBinding(*o, deviceId, Control/*::ControlChangingDirection*/::INCREASE) - != ICS_MAX_DEVICE_BUTTONS) - { - TiXmlElement binder( "JoystickButtonBinder" ); + control.InsertEndChild(binder); + } - binder.SetAttribute( "button", ToString( - getJoystickButtonBinding(*o, deviceId, Control/*::ControlChangingDirection*/::INCREASE)).c_str() ); + if(getJoystickAxisBinding(*o, Control/*::ControlChangingDirection*/::DECREASE) + != /*NamedAxis::*/UNASSIGNED) + { + TiXmlElement binder( "JoystickAxisBinder" ); - binder.SetAttribute( "direction", "INCREASE" ); + binder.SetAttribute( "axis", ToString( + getJoystickAxisBinding(*o, Control/*::ControlChangingDirection*/::DECREASE)).c_str() ); - binder.SetAttribute( "deviceId", ToString(deviceId).c_str() ); - - control.InsertEndChild(binder); - } + binder.SetAttribute( "direction", "DECREASE" ); - if(getJoystickButtonBinding(*o, deviceId, Control/*::ControlChangingDirection*/::DECREASE) - != ICS_MAX_DEVICE_BUTTONS) - { - TiXmlElement binder( "JoystickButtonBinder" ); + control.InsertEndChild(binder); + } - binder.SetAttribute( "button", ToString( - getJoystickButtonBinding(*o, *it, Control/*::ControlChangingDirection*/::DECREASE)).c_str() ); + if(getJoystickButtonBinding(*o, Control/*::ControlChangingDirection*/::INCREASE) + != ICS_MAX_DEVICE_BUTTONS) + { + TiXmlElement binder( "JoystickButtonBinder" ); - binder.SetAttribute( "direction", "DECREASE" ); + binder.SetAttribute( "button", ToString( + getJoystickButtonBinding(*o, Control/*::ControlChangingDirection*/::INCREASE)).c_str() ); - binder.SetAttribute( "deviceId", ToString(deviceId).c_str() ); - - control.InsertEndChild(binder); - } + binder.SetAttribute( "direction", "INCREASE" ); - if(getJoystickPOVBinding(*o, deviceId, Control/*::ControlChangingDirection*/::INCREASE).index >= 0) - { - TiXmlElement binder( "JoystickPOVBinder" ); + control.InsertEndChild(binder); + } - POVBindingPair POVPair = getJoystickPOVBinding(*o, deviceId, Control/*::ControlChangingDirection*/::INCREASE); - - binder.SetAttribute( "pov", ToString(POVPair.index).c_str() ); + if(getJoystickButtonBinding(*o, Control/*::ControlChangingDirection*/::DECREASE) + != ICS_MAX_DEVICE_BUTTONS) + { + TiXmlElement binder( "JoystickButtonBinder" ); - binder.SetAttribute( "direction", "INCREASE" ); + binder.SetAttribute( "button", ToString( + getJoystickButtonBinding(*o, Control/*::ControlChangingDirection*/::DECREASE)).c_str() ); - binder.SetAttribute( "deviceId", ToString(deviceId).c_str() ); + binder.SetAttribute( "direction", "DECREASE" ); - if(POVPair.axis == ICS::InputControlSystem::EastWest) - { - binder.SetAttribute( "axis", "EastWest" ); - } - else - { - binder.SetAttribute( "axis", "NorthSouth" ); - } - - control.InsertEndChild(binder); - } - - if(getJoystickPOVBinding(*o, deviceId, Control/*::ControlChangingDirection*/::DECREASE).index >= 0) - { - TiXmlElement binder( "JoystickPOVBinder" ); - - POVBindingPair POVPair = getJoystickPOVBinding(*o, deviceId, Control/*::ControlChangingDirection*/::DECREASE); - - binder.SetAttribute( "pov", ToString(POVPair.index).c_str() ); - - binder.SetAttribute( "direction", "DECREASE" ); - - binder.SetAttribute( "deviceId", ToString(deviceId).c_str() ); - - if(POVPair.axis == ICS::InputControlSystem::EastWest) - { - binder.SetAttribute( "axis", "EastWest" ); - } - else - { - binder.SetAttribute( "axis", "NorthSouth" ); - } - - control.InsertEndChild(binder); - } - - if(getJoystickSliderBinding(*o, deviceId, Control/*::ControlChangingDirection*/::INCREASE) - != /*NamedAxis::*/UNASSIGNED) - { - TiXmlElement binder( "JoystickSliderBinder" ); - - binder.SetAttribute( "slider", ToString( - getJoystickSliderBinding(*o, deviceId, Control/*::ControlChangingDirection*/::INCREASE)).c_str() ); - - binder.SetAttribute( "direction", "INCREASE" ); - - binder.SetAttribute( "deviceId", ToString(deviceId).c_str() ); - - control.InsertEndChild(binder); - } - - if(getJoystickSliderBinding(*o, deviceId, Control/*::ControlChangingDirection*/::DECREASE) - != /*NamedAxis::*/UNASSIGNED) - { - TiXmlElement binder( "JoystickSliderBinder" ); - - binder.SetAttribute( "slider", ToString( - getJoystickSliderBinding(*o, deviceId, Control/*::ControlChangingDirection*/::DECREASE)).c_str() ); - - binder.SetAttribute( "direction", "DECREASE" ); - - binder.SetAttribute( "deviceId", ToString(deviceId).c_str() ); - - control.InsertEndChild(binder); - } - - ++it; - } + control.InsertEndChild(binder); + } std::list channels = (*o)->getAttachedChannels(); @@ -697,19 +627,19 @@ namespace ICS binder.SetAttribute( "number", ToString((*it)->getNumber()).c_str() ); - Channel::ChannelDirection direction = (*it)->getAttachedControlBinding(*o).direction; + Channel::ChannelDirection direction = (*it)->getAttachedControlBinding(*o).direction; if(direction == Channel/*::ChannelDirection*/::DIRECT) { binder.SetAttribute( "direction", "DIRECT" ); - } + } else { binder.SetAttribute( "direction", "INVERSE" ); } - + float percentage = (*it)->getAttachedControlBinding(*o).percentage; binder.SetAttribute( "percentage", ToString(percentage).c_str() ); - + control.InsertEndChild(binder); } @@ -731,7 +661,7 @@ namespace ICS } } - //! @todo Future versions should consider channel exponentials and mixtures, so + //! @todo Future versions should consider channel exponentials and mixtures, so // after updating Controls, Channels should be updated according to their values } @@ -745,24 +675,6 @@ namespace ICS return mControls[i]->getValue(); } - void InputControlSystem::addJoystick(int deviceId) - { - ICS_LOG("Adding joystick (device id: " + ToString(deviceId) + ")"); - - for(int j = 0 ; j < ICS_MAX_JOYSTICK_AXIS ; j++) - { - if(mControlsJoystickAxisBinderMap[deviceId].find(j) == mControlsJoystickAxisBinderMap[deviceId].end()) - { - ControlAxisBinderItem controlJoystickBinderItem; - controlJoystickBinderItem.direction = Control::STOP; - controlJoystickBinderItem.control = NULL; - mControlsJoystickAxisBinderMap[deviceId][j] = controlJoystickBinderItem; - } - } - - mJoystickIDList.push_back(deviceId); - } - Control* InputControlSystem::findControl(std::string name) { if(mActive) diff --git a/extern/oics/ICSInputControlSystem.h b/extern/oics/ICSInputControlSystem.h index 6a6a6bf09..0bdd67b34 100644 --- a/extern/oics/ICSInputControlSystem.h +++ b/extern/oics/ICSInputControlSystem.h @@ -32,7 +32,9 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "ICSControl.h" #include "ICSChannel.h" -#include "../sdl4ogre/events.h" +#include "../sdl4ogre/events.h" + +#include "boost/lexical_cast.hpp" #define ICS_LOG(text) if(mLog) mLog->logMessage( ("ICS: " + std::string(text)).c_str() ); #define ICS_MAX_JOYSTICK_AXIS 16 @@ -43,16 +45,16 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. namespace ICS { - class DllExport InputControlSystemLog + class DllExport InputControlSystemLog { public: virtual void logMessage(const char* text) = 0; }; - class DllExport InputControlSystem : + class DllExport InputControlSystem : public SFO::MouseListener, public SFO::KeyListener, - public SFO::JoyListener + public SFO::ControllerListener { public: @@ -62,7 +64,7 @@ namespace ICS typedef NamedAxis MouseAxis; // MouseAxis is deprecated. It will be removed in future versions - typedef std::list JoystickIDList; + typedef std::map JoystickIDList; typedef struct { @@ -72,7 +74,7 @@ namespace ICS InputControlSystem(std::string file = "", bool active = true , DetectingBindingListener* detectingBindingListener = NULL - , InputControlSystemLog* log = NULL, size_t channelCount = 16); + , InputControlSystemLog* log = NULL, size_t channelCount = 16); ~InputControlSystem(); std::string getFileName(){ return mFileName; }; @@ -98,50 +100,42 @@ namespace ICS inline void activate(){ this->mActive = true; }; inline void deactivate(){ this->mActive = false; }; - void addJoystick(int deviceId); + void controllerAdded (const SDL_ControllerDeviceEvent &args); + void controllerRemoved(const SDL_ControllerDeviceEvent &args); JoystickIDList& getJoystickIdList(){ return mJoystickIDList; }; - + // MouseListener void mouseMoved(const SFO::MouseMotionEvent &evt); void mousePressed(const SDL_MouseButtonEvent &evt, Uint8); void mouseReleased(const SDL_MouseButtonEvent &evt, Uint8); - + // KeyListener void keyPressed(const SDL_KeyboardEvent &evt); void keyReleased(const SDL_KeyboardEvent &evt); - - // JoyStickListener - void buttonPressed(const SDL_JoyButtonEvent &evt, int button); - void buttonReleased(const SDL_JoyButtonEvent &evt, int button); - void axisMoved(const SDL_JoyAxisEvent &evt, int axis); - void povMoved(const SDL_JoyHatEvent &evt, int index); - //TODO: does this have an SDL equivalent? - //bool sliderMoved(const OIS::JoyStickEvent &evt, int index); + + // ControllerListener + void buttonPressed(const SDL_ControllerButtonEvent &evt); + void buttonReleased(const SDL_ControllerButtonEvent &evt); + void axisMoved(const SDL_ControllerAxisEvent &evt); void addKeyBinding(Control* control, SDL_Scancode key, Control::ControlChangingDirection direction); bool isKeyBound(SDL_Scancode key) const; void addMouseAxisBinding(Control* control, NamedAxis axis, Control::ControlChangingDirection direction); void addMouseButtonBinding(Control* control, unsigned int button, Control::ControlChangingDirection direction); bool isMouseButtonBound(unsigned int button) const; - void addJoystickAxisBinding(Control* control, int deviceId, int axis, Control::ControlChangingDirection direction); - void addJoystickButtonBinding(Control* control, int deviceId, unsigned int button, Control::ControlChangingDirection direction); - void addJoystickPOVBinding(Control* control, int deviceId, int index, POVAxis axis, Control::ControlChangingDirection direction); - void addJoystickSliderBinding(Control* control, int deviceId, int index, Control::ControlChangingDirection direction); + void addJoystickAxisBinding(Control* control, int axis, Control::ControlChangingDirection direction); + void addJoystickButtonBinding(Control* control, unsigned int button, Control::ControlChangingDirection direction); void removeKeyBinding(SDL_Scancode key); void removeMouseAxisBinding(NamedAxis axis); void removeMouseButtonBinding(unsigned int button); - void removeJoystickAxisBinding(int deviceId, int axis); - void removeJoystickButtonBinding(int deviceId, unsigned int button); - void removeJoystickPOVBinding(int deviceId, int index, POVAxis axis); - void removeJoystickSliderBinding(int deviceId, int index); + void removeJoystickAxisBinding(int axis); + void removeJoystickButtonBinding(unsigned int button); SDL_Scancode getKeyBinding(Control* control, ICS::Control::ControlChangingDirection direction); NamedAxis getMouseAxisBinding(Control* control, ICS::Control::ControlChangingDirection direction); unsigned int getMouseButtonBinding(Control* control, ICS::Control::ControlChangingDirection direction); - int getJoystickAxisBinding(Control* control, int deviceId, ICS::Control::ControlChangingDirection direction); - unsigned int getJoystickButtonBinding(Control* control, int deviceId, ICS::Control::ControlChangingDirection direction); - POVBindingPair getJoystickPOVBinding(Control* control, int deviceId, ICS::Control::ControlChangingDirection direction); - int getJoystickSliderBinding(Control* control, int deviceId, ICS::Control::ControlChangingDirection direction); + int getJoystickAxisBinding(Control* control, ICS::Control::ControlChangingDirection direction); + unsigned int getJoystickButtonBinding(Control* control, ICS::Control::ControlChangingDirection direction); std::string scancodeToString(SDL_Scancode key); @@ -193,17 +187,10 @@ namespace ICS typedef std::map ControlsPOVBinderMapType; // typedef std::map ControlsSliderBinderMapType; // - typedef std::map JoystickAxisBinderMapType; // > - typedef std::map JoystickButtonBinderMapType; // > - typedef std::map > JoystickPOVBinderMapType; // > > - typedef std::map JoystickSliderBinderMapType; // > - ControlsAxisBinderMapType mControlsMouseAxisBinderMap; // ControlsButtonBinderMapType mControlsMouseButtonBinderMap; // - JoystickAxisBinderMapType mControlsJoystickAxisBinderMap; // > - JoystickButtonBinderMapType mControlsJoystickButtonBinderMap; // > - JoystickPOVBinderMapType mControlsJoystickPOVBinderMap; // > > - JoystickSliderBinderMapType mControlsJoystickSliderBinderMap; // > + ControlsAxisBinderMapType mControlsJoystickAxisBinderMap; // + ControlsButtonBinderMapType mControlsJoystickButtonBinderMap; // std::vector mControls; std::vector mChannels; @@ -212,7 +199,7 @@ namespace ICS bool mActive; InputControlSystemLog* mLog; - + DetectingBindingListener* mDetectingBindingListener; Control* mDetectingBindingControl; Control::ControlChangingDirection mDetectingBindingDirection; @@ -243,16 +230,11 @@ namespace ICS , unsigned int button, Control::ControlChangingDirection direction); virtual void joystickAxisBindingDetected(InputControlSystem* ICS, Control* control - , int deviceId, int axis, Control::ControlChangingDirection direction); + , int axis, Control::ControlChangingDirection direction); virtual void joystickButtonBindingDetected(InputControlSystem* ICS, Control* control - , int deviceId, unsigned int button, Control::ControlChangingDirection direction); - - virtual void joystickPOVBindingDetected(InputControlSystem* ICS, Control* control - , int deviceId, int pov, InputControlSystem::POVAxis axis, Control::ControlChangingDirection direction); + , unsigned int button, Control::ControlChangingDirection direction); - virtual void joystickSliderBindingDetected(InputControlSystem* ICS, Control* control - , int deviceId, int slider, Control::ControlChangingDirection direction); }; static const float ICS_MAX = std::numeric_limits::max(); diff --git a/extern/oics/ICSInputControlSystem_joystick.cpp b/extern/oics/ICSInputControlSystem_joystick.cpp index 8bf931788..9cd9b1461 100644 --- a/extern/oics/ICSInputControlSystem_joystick.cpp +++ b/extern/oics/ICSInputControlSystem_joystick.cpp @@ -27,14 +27,15 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "ICSInputControlSystem.h" #define SDL_JOY_AXIS_MIN -32768 -#define SDL_JOY_AXIS_MAX 32767 +#define SDL_JOY_AXIS_MAX 32767 +#define DEADZONE 0.1f namespace ICS { // load xml void InputControlSystem::loadJoystickAxisBinders(TiXmlElement* xmlControlNode) { - TiXmlElement* xmlJoystickBinder = xmlControlNode->FirstChildElement("JoystickAxisBinder"); + TiXmlElement* xmlJoystickBinder = xmlControlNode->FirstChildElement("JoystickAxisBinder"); while(xmlJoystickBinder) { Control::ControlChangingDirection dir = Control::STOP; @@ -47,8 +48,7 @@ namespace ICS dir = Control::DECREASE; } - addJoystickAxisBinding(mControls.back(), FromString(xmlJoystickBinder->Attribute("deviceId")) - , FromString(xmlJoystickBinder->Attribute("axis")), dir); + addJoystickAxisBinding(mControls.back(), FromString(xmlJoystickBinder->Attribute("axis")), dir); xmlJoystickBinder = xmlJoystickBinder->NextSiblingElement("JoystickAxisBinder"); } @@ -56,7 +56,7 @@ namespace ICS void InputControlSystem::loadJoystickButtonBinders(TiXmlElement* xmlControlNode) { - TiXmlElement* xmlJoystickButtonBinder = xmlControlNode->FirstChildElement("JoystickButtonBinder"); + TiXmlElement* xmlJoystickButtonBinder = xmlControlNode->FirstChildElement("JoystickButtonBinder"); while(xmlJoystickButtonBinder) { Control::ControlChangingDirection dir = Control::STOP; @@ -69,335 +69,168 @@ namespace ICS dir = Control::DECREASE; } - addJoystickButtonBinding(mControls.back(), FromString(xmlJoystickButtonBinder->Attribute("deviceId")) - , FromString(xmlJoystickButtonBinder->Attribute("button")), dir); + addJoystickButtonBinding(mControls.back(), FromString(xmlJoystickButtonBinder->Attribute("button")), dir); xmlJoystickButtonBinder = xmlJoystickButtonBinder->NextSiblingElement("JoystickButtonBinder"); } } - void InputControlSystem::loadJoystickPOVBinders(TiXmlElement* xmlControlNode) - { - TiXmlElement* xmlJoystickPOVBinder = xmlControlNode->FirstChildElement("JoystickPOVBinder"); - while(xmlJoystickPOVBinder) - { - Control::ControlChangingDirection dir = Control::STOP; - if(std::string(xmlJoystickPOVBinder->Attribute("direction")) == "INCREASE") - { - dir = Control::INCREASE; - } - else if(std::string(xmlJoystickPOVBinder->Attribute("direction")) == "DECREASE") - { - dir = Control::DECREASE; - } - - InputControlSystem::POVAxis axis = /*POVAxis::*/NorthSouth; - if(std::string(xmlJoystickPOVBinder->Attribute("axis")) == "EastWest") - { - axis = /*POVAxis::*/EastWest; - } - - addJoystickPOVBinding(mControls.back(), FromString(xmlJoystickPOVBinder->Attribute("deviceId")) - , FromString(xmlJoystickPOVBinder->Attribute("pov")), axis, dir); - - xmlJoystickPOVBinder = xmlJoystickPOVBinder->NextSiblingElement("JoystickPOVBinder"); - } - } - - void InputControlSystem::loadJoystickSliderBinders(TiXmlElement* xmlControlNode) - { - TiXmlElement* xmlJoystickSliderBinder = xmlControlNode->FirstChildElement("JoystickSliderBinder"); - while(xmlJoystickSliderBinder) - { - Control::ControlChangingDirection dir = Control::STOP; - if(std::string(xmlJoystickSliderBinder->Attribute("direction")) == "INCREASE") - { - dir = Control::INCREASE; - } - else if(std::string(xmlJoystickSliderBinder->Attribute("direction")) == "DECREASE") - { - dir = Control::DECREASE; - } - - addJoystickSliderBinding(mControls.back(), FromString(xmlJoystickSliderBinder->Attribute("deviceId")) - , FromString(xmlJoystickSliderBinder->Attribute("slider")), dir); - - xmlJoystickSliderBinder = xmlJoystickSliderBinder->NextSiblingElement("JoystickSliderBinder"); - } - } - // add bindings - void InputControlSystem::addJoystickAxisBinding(Control* control, int deviceId, int axis, Control::ControlChangingDirection direction) + void InputControlSystem::addJoystickAxisBinding(Control* control, int axis, Control::ControlChangingDirection direction) { - ICS_LOG("\tAdding AxisBinder [deviceid=" - + ToString(deviceId) + ", axis=" + ICS_LOG("\tAdding AxisBinder [axis=" + ToString(axis) + ", direction=" - + ToString(direction) + "]"); + + ToString(direction) + "]"); + + control->setValue(0.5f); //all joystick axis start at .5, so do that ControlAxisBinderItem controlAxisBinderItem; controlAxisBinderItem.control = control; controlAxisBinderItem.direction = direction; - mControlsJoystickAxisBinderMap[ deviceId ][ axis ] = controlAxisBinderItem; + mControlsJoystickAxisBinderMap[ axis ] = controlAxisBinderItem; } - void InputControlSystem::addJoystickButtonBinding(Control* control, int deviceId, unsigned int button, Control::ControlChangingDirection direction) + void InputControlSystem::addJoystickButtonBinding(Control* control, unsigned int button, Control::ControlChangingDirection direction) { - ICS_LOG("\tAdding JoystickButtonBinder [deviceId=" - + ToString(deviceId) + ", button=" + ICS_LOG("\tAdding JoystickButtonBinder [button=" + ToString(button) + ", direction=" + ToString(direction) + "]"); ControlButtonBinderItem controlJoystickButtonBinderItem; controlJoystickButtonBinderItem.direction = direction; controlJoystickButtonBinderItem.control = control; - mControlsJoystickButtonBinderMap[ deviceId ][ button ] = controlJoystickButtonBinderItem; - } - - void InputControlSystem::addJoystickPOVBinding(Control* control, int deviceId, int index, InputControlSystem::POVAxis axis, Control::ControlChangingDirection direction) - { - ICS_LOG("\tAdding JoystickPOVBinder [deviceId=" - + ToString(deviceId) + ", pov=" - + ToString(index) + ", axis=" - + ToString(axis) + ", direction=" - + ToString(direction) + "]"); - - ControlPOVBinderItem ControlPOVBinderItem; - ControlPOVBinderItem.direction = direction; - ControlPOVBinderItem.control = control; - mControlsJoystickPOVBinderMap[ deviceId ][ index ][ axis ] = ControlPOVBinderItem; - } - - void InputControlSystem::addJoystickSliderBinding(Control* control, int deviceId, int index, Control::ControlChangingDirection direction) - { - ICS_LOG("\tAdding JoystickSliderBinder [deviceId=" - + ToString(deviceId) + ", direction=" - + ToString(index) + ", direction=" - + ToString(direction) + "]"); - - ControlSliderBinderItem ControlSliderBinderItem; - ControlSliderBinderItem.direction = direction; - ControlSliderBinderItem.control = control; - mControlsJoystickSliderBinderMap[ deviceId ][ index ] = ControlSliderBinderItem; + mControlsJoystickButtonBinderMap[ button ] = controlJoystickButtonBinderItem; } // get bindings - int InputControlSystem::getJoystickAxisBinding(Control* control, int deviceId, ICS::Control::ControlChangingDirection direction) + int InputControlSystem::getJoystickAxisBinding(Control* control, ICS::Control::ControlChangingDirection direction) { - if(mControlsJoystickAxisBinderMap.find(deviceId) != mControlsJoystickAxisBinderMap.end()) - { - ControlsAxisBinderMapType::iterator it = mControlsJoystickAxisBinderMap[deviceId].begin(); - while(it != mControlsJoystickAxisBinderMap[deviceId].end()) - { - if(it->first >= 0 && it->second.control == control && it->second.direction == direction) - { - return it->first; - } - ++it; - } - } + ControlsAxisBinderMapType::iterator it = mControlsJoystickAxisBinderMap.begin(); + while(it != mControlsJoystickAxisBinderMap.end()) + { + if(it->first >= 0 && it->second.control == control && it->second.direction == direction) + { + return it->first; + } + ++it; + } return /*NamedAxis::*/UNASSIGNED; } - unsigned int InputControlSystem::getJoystickButtonBinding(Control* control, int deviceId, ICS::Control::ControlChangingDirection direction) + unsigned int InputControlSystem::getJoystickButtonBinding(Control* control, ICS::Control::ControlChangingDirection direction) { - if(mControlsJoystickButtonBinderMap.find(deviceId) != mControlsJoystickButtonBinderMap.end()) - { - ControlsButtonBinderMapType::iterator it = mControlsJoystickButtonBinderMap[deviceId].begin(); - while(it != mControlsJoystickButtonBinderMap[deviceId].end()) - { - if(it->second.control == control && it->second.direction == direction) - { - return it->first; - } - ++it; - } - } + ControlsButtonBinderMapType::iterator it = mControlsJoystickButtonBinderMap.begin(); + while(it != mControlsJoystickButtonBinderMap.end()) + { + if(it->second.control == control && it->second.direction == direction) + { + return it->first; + } + ++it; + } return ICS_MAX_DEVICE_BUTTONS; } - InputControlSystem::POVBindingPair InputControlSystem::getJoystickPOVBinding(Control* control, int deviceId, ICS::Control::ControlChangingDirection direction) - { - POVBindingPair result; - result.index = -1; - - if(mControlsJoystickPOVBinderMap.find(deviceId) != mControlsJoystickPOVBinderMap.end()) - { - //ControlsAxisBinderMapType::iterator it = mControlsJoystickPOVBinderMap[deviceId].begin(); - std::map::iterator it = mControlsJoystickPOVBinderMap[deviceId].begin(); - while(it != mControlsJoystickPOVBinderMap[deviceId].end()) - { - ControlsPOVBinderMapType::const_iterator it2 = it->second.begin(); - while(it2 != it->second.end()) - { - if(it2->second.control == control && it2->second.direction == direction) - { - result.index = it->first; - result.axis = (POVAxis)it2->first; - return result; - } - it2++; - } - - it++; - } - } - - return result; - } - - int InputControlSystem::getJoystickSliderBinding(Control* control, int deviceId, ICS::Control::ControlChangingDirection direction) - { - if(mControlsJoystickSliderBinderMap.find(deviceId) != mControlsJoystickSliderBinderMap.end()) - { - ControlsButtonBinderMapType::iterator it = mControlsJoystickSliderBinderMap[deviceId].begin(); - while(it != mControlsJoystickSliderBinderMap[deviceId].end()) - { - if(it->second.control == control && it->second.direction == direction) - { - return it->first; - } - it++; - } - } - - return /*NamedAxis::*/UNASSIGNED; - } - // remove bindings - void InputControlSystem::removeJoystickAxisBinding(int deviceId, int axis) + void InputControlSystem::removeJoystickAxisBinding(int axis) { - if(mControlsJoystickAxisBinderMap.find(deviceId) != mControlsJoystickAxisBinderMap.end()) - { - ControlsButtonBinderMapType::iterator it = mControlsJoystickAxisBinderMap[deviceId].find(axis); - if(it != mControlsJoystickAxisBinderMap[deviceId].end()) - { - mControlsJoystickAxisBinderMap[deviceId].erase(it); - } - } + ControlsButtonBinderMapType::iterator it = mControlsJoystickAxisBinderMap.find(axis); + if(it != mControlsJoystickAxisBinderMap.end()) + { + mControlsJoystickAxisBinderMap.erase(it); + } } - void InputControlSystem::removeJoystickButtonBinding(int deviceId, unsigned int button) + void InputControlSystem::removeJoystickButtonBinding(unsigned int button) { - if(mControlsJoystickButtonBinderMap.find(deviceId) != mControlsJoystickButtonBinderMap.end()) - { - ControlsButtonBinderMapType::iterator it = mControlsJoystickButtonBinderMap[deviceId].find(button); - if(it != mControlsJoystickButtonBinderMap[deviceId].end()) - { - mControlsJoystickButtonBinderMap[deviceId].erase(it); - } - } - } - - void InputControlSystem::removeJoystickPOVBinding(int deviceId, int index, POVAxis axis) - { - if(mControlsJoystickPOVBinderMap.find(deviceId) != mControlsJoystickPOVBinderMap.end()) - { - std::map::iterator it = mControlsJoystickPOVBinderMap[deviceId].find(index); - if(it != mControlsJoystickPOVBinderMap[deviceId].end()) - { - if(it->second.find(axis) != it->second.end()) - { - mControlsJoystickPOVBinderMap[deviceId].find(index)->second.erase( it->second.find(axis) ); - } - } - } - } - - void InputControlSystem::removeJoystickSliderBinding(int deviceId, int index) - { - if(mControlsJoystickSliderBinderMap.find(deviceId) != mControlsJoystickSliderBinderMap.end()) - { - ControlsButtonBinderMapType::iterator it = mControlsJoystickSliderBinderMap[deviceId].find(index); - if(it != mControlsJoystickSliderBinderMap[deviceId].end()) - { - mControlsJoystickSliderBinderMap[deviceId].erase(it); - } - } + ControlsButtonBinderMapType::iterator it = mControlsJoystickButtonBinderMap.find(button); + if(it != mControlsJoystickButtonBinderMap.end()) + { + mControlsJoystickButtonBinderMap.erase(it); + } } // joyStick listeners - void InputControlSystem::buttonPressed(const SDL_JoyButtonEvent &evt, int button) + void InputControlSystem::buttonPressed(const SDL_ControllerButtonEvent &evt) { - if(mActive) + if(mActive) { if(!mDetectingBindingControl) { - if(mControlsJoystickButtonBinderMap.find(evt.which) != mControlsJoystickButtonBinderMap.end()) - { - ControlsButtonBinderMapType::const_iterator it = mControlsJoystickButtonBinderMap[evt.which].find(button); - if(it != mControlsJoystickButtonBinderMap[evt.which].end()) - { - it->second.control->setIgnoreAutoReverse(false); - if(!it->second.control->getAutoChangeDirectionOnLimitsAfterStop()) - { - it->second.control->setChangingDirection(it->second.direction); - } - else - { - if(it->second.control->getValue() == 1) - { - it->second.control->setChangingDirection(Control::DECREASE); - } - else if(it->second.control->getValue() == 0) - { - it->second.control->setChangingDirection(Control::INCREASE); - } - } - } - } + ControlsButtonBinderMapType::const_iterator it = mControlsJoystickButtonBinderMap.find(evt.button); + if(it != mControlsJoystickButtonBinderMap.end()) + { + it->second.control->setIgnoreAutoReverse(false); + if(!it->second.control->getAutoChangeDirectionOnLimitsAfterStop()) + { + it->second.control->setChangingDirection(it->second.direction); + } + else + { + if(it->second.control->getValue() == 1) + { + it->second.control->setChangingDirection(Control::DECREASE); + } + else if(it->second.control->getValue() == 0) + { + it->second.control->setChangingDirection(Control::INCREASE); + } + } + } } else if(mDetectingBindingListener) { mDetectingBindingListener->joystickButtonBindingDetected(this, - mDetectingBindingControl, evt.which, button, mDetectingBindingDirection); + mDetectingBindingControl, evt.button, mDetectingBindingDirection); } } } - void InputControlSystem::buttonReleased(const SDL_JoyButtonEvent &evt, int button) + void InputControlSystem::buttonReleased(const SDL_ControllerButtonEvent &evt) { if(mActive) { - if(mControlsJoystickButtonBinderMap.find(evt.which) != mControlsJoystickButtonBinderMap.end()) - { - ControlsButtonBinderMapType::const_iterator it = mControlsJoystickButtonBinderMap[evt.which].find(button); - if(it != mControlsJoystickButtonBinderMap[evt.which].end()) - { - it->second.control->setChangingDirection(Control::STOP); - } - } + ControlsButtonBinderMapType::const_iterator it = mControlsJoystickButtonBinderMap.find(evt.button); + if(it != mControlsJoystickButtonBinderMap.end()) + { + it->second.control->setChangingDirection(Control::STOP); + } } } - void InputControlSystem::axisMoved(const SDL_JoyAxisEvent &evt, int axis) + void InputControlSystem::axisMoved(const SDL_ControllerAxisEvent &evt) { if(mActive) { if(!mDetectingBindingControl) { - if(mControlsJoystickAxisBinderMap.find(evt.which) != mControlsJoystickAxisBinderMap.end()) - { - ControlAxisBinderItem joystickBinderItem = mControlsJoystickAxisBinderMap[ evt.which ][ axis ]; // joystic axis start at 0 index - Control* ctrl = joystickBinderItem.control; - if(ctrl) - { - ctrl->setIgnoreAutoReverse(true); - - float axisRange = SDL_JOY_AXIS_MAX - SDL_JOY_AXIS_MIN; - float valDisplaced = (float)(evt.value - SDL_JOY_AXIS_MIN); - - if(joystickBinderItem.direction == Control::INCREASE) - { - ctrl->setValue( valDisplaced / axisRange ); - } - else if(joystickBinderItem.direction == Control::DECREASE) - { - ctrl->setValue( 1 - ( valDisplaced / axisRange ) ); - } - } - } + ControlAxisBinderItem joystickBinderItem = mControlsJoystickAxisBinderMap[evt.axis]; // joystic axis start at 0 index + Control* ctrl = joystickBinderItem.control; + if(ctrl) + { + ctrl->setIgnoreAutoReverse(true); + + float axisRange = SDL_JOY_AXIS_MAX - SDL_JOY_AXIS_MIN; + float valDisplaced = (float)(evt.value - SDL_JOY_AXIS_MIN); + float percent = valDisplaced / axisRange * (1+DEADZONE*2) - DEADZONE; //Assures all values, 0 through 1, are seen + if(percent > .5-DEADZONE && percent < .5+DEADZONE) //close enough to center + percent = .5; + else if(percent > .5) + percent -= DEADZONE; + else + percent += DEADZONE; + + if(joystickBinderItem.direction == Control::INCREASE) + { + ctrl->setValue( percent ); + } + else if(joystickBinderItem.direction == Control::DECREASE) + { + ctrl->setValue( 1 - ( percent ) ); + } + } } else if(mDetectingBindingListener) { @@ -409,249 +242,74 @@ namespace ICS if( abs( evt.value ) > ICS_JOYSTICK_AXIS_BINDING_MARGIN) { mDetectingBindingListener->joystickAxisBindingDetected(this, - mDetectingBindingControl, evt.which, axis, mDetectingBindingDirection); + mDetectingBindingControl, evt.axis, mDetectingBindingDirection); } } } } - } - - //Here be dragons, apparently - void InputControlSystem::povMoved(const SDL_JoyHatEvent &evt, int index) + } + + void InputControlSystem::controllerAdded(const SDL_ControllerDeviceEvent &args) { - if(mActive) - { - if(!mDetectingBindingControl) - { - if(mControlsJoystickPOVBinderMap.find(evt.which) != mControlsJoystickPOVBinderMap.end()) - { - std::map::const_iterator i = mControlsJoystickPOVBinderMap[ evt.which ].find(index); - if(i != mControlsJoystickPOVBinderMap[ evt.which ].end()) - { - if(evt.value != SDL_HAT_LEFT - && evt.value != SDL_HAT_RIGHT - && evt.value != SDL_HAT_CENTERED) - { - ControlsPOVBinderMapType::const_iterator it = i->second.find( /*POVAxis::*/NorthSouth ); - if(it != i->second.end()) - { - it->second.control->setIgnoreAutoReverse(false); - if(!it->second.control->getAutoChangeDirectionOnLimitsAfterStop()) - { - if(evt.value == SDL_HAT_UP - || evt.value == SDL_HAT_LEFTUP - || evt.value == SDL_HAT_RIGHTUP) - { - it->second.control->setChangingDirection(it->second.direction); - } - else - { - it->second.control->setChangingDirection((Control::ControlChangingDirection)(-1 * it->second.direction)); - } - } - else - { - if(it->second.control->getValue() == 1) - { - it->second.control->setChangingDirection(Control::DECREASE); - } - else if(it->second.control->getValue() == 0) - { - it->second.control->setChangingDirection(Control::INCREASE); - } - } - } - } - - if(evt.value != SDL_HAT_UP - && evt.value != SDL_HAT_DOWN - && evt.value != SDL_HAT_CENTERED) - { - ControlsPOVBinderMapType::const_iterator it = i->second.find( /*POVAxis::*/EastWest ); - if(it != i->second.end()) - { - it->second.control->setIgnoreAutoReverse(false); - if(!it->second.control->getAutoChangeDirectionOnLimitsAfterStop()) - { - if(evt.value == SDL_HAT_RIGHT - || evt.value == SDL_HAT_RIGHTUP - || evt.value == SDL_HAT_RIGHTDOWN) - { - it->second.control->setChangingDirection(it->second.direction); - } - else - { - it->second.control->setChangingDirection((Control::ControlChangingDirection)(-1 * it->second.direction)); - } - } - else - { - if(it->second.control->getValue() == 1) - { - it->second.control->setChangingDirection(Control::DECREASE); - } - else if(it->second.control->getValue() == 0) - { - it->second.control->setChangingDirection(Control::INCREASE); - } - } - } - } - - if(evt.value == SDL_HAT_CENTERED) - { - ControlsPOVBinderMapType::const_iterator it = i->second.find( /*POVAxis::*/NorthSouth ); - if(it != i->second.end()) - { - it->second.control->setChangingDirection(Control::STOP); - } - - it = i->second.find( /*POVAxis::*/EastWest ); - if(it != i->second.end()) - { - it->second.control->setChangingDirection(Control::STOP); - } - } - } - } - } - else if(mDetectingBindingListener) - { - if(mDetectingBindingControl && mDetectingBindingControl->isAxisBindable()) - { - if(evt.value == SDL_HAT_LEFT - || evt.value == SDL_HAT_RIGHT - || evt.value == SDL_HAT_UP - || evt.value == SDL_HAT_DOWN) - { - POVAxis povAxis = NorthSouth; - if(evt.value == SDL_HAT_LEFT - || evt.value == SDL_HAT_RIGHT) - { - povAxis = EastWest; - } - - mDetectingBindingListener->joystickPOVBindingDetected(this, - mDetectingBindingControl, evt.which, index, povAxis, mDetectingBindingDirection); - } - } - } - } + ICS_LOG("Adding joystick (index: " + ToString(args.which) + ")"); + SDL_GameController* cntrl = SDL_GameControllerOpen(args.which); + int instanceID = SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(cntrl)); + if(mJoystickIDList.empty()) // + { + for(int j = 0 ; j < ICS_MAX_JOYSTICK_AXIS ; j++) + { + if(mControlsJoystickAxisBinderMap.find(j) == mControlsJoystickAxisBinderMap.end()) + { + ControlAxisBinderItem controlJoystickBinderItem; + controlJoystickBinderItem.direction = Control::STOP; + controlJoystickBinderItem.control = NULL; + mControlsJoystickAxisBinderMap[j] = controlJoystickBinderItem; + } + } + } + + mJoystickIDList[instanceID] = cntrl; + } + void InputControlSystem::controllerRemoved(const SDL_ControllerDeviceEvent &args) + { + ICS_LOG("Removing joystick (instance id: " + ToString(args.which) + ")"); + if(mJoystickIDList.count(args.which)!=0) + { + SDL_GameControllerClose(mJoystickIDList.at(args.which)); + mJoystickIDList.erase(args.which); + } } - //TODO: does this have an SDL equivalent? - /* - void InputControlSystem::sliderMoved(const OIS::JoyStickEvent &evt, int index) - { - if(mActive) - { - if(!mDetectingBindingControl) - { - if(mControlsJoystickSliderBinderMap.find(evt.device->getID()) != mControlsJoystickSliderBinderMap.end()) - { - ControlSliderBinderItem joystickBinderItem = mControlsJoystickSliderBinderMap[ evt.device->getID() ][ index ]; - Control* ctrl = joystickBinderItem.control; - if(ctrl) - { - ctrl->setIgnoreAutoReverse(true); - if(joystickBinderItem.direction == Control::INCREASE) - { - float axisRange = OIS::JoyStick::MAX_AXIS - OIS::JoyStick::MIN_AXIS; - float valDisplaced = (float)( evt.state.mSliders[index].abX - OIS::JoyStick::MIN_AXIS); - - ctrl->setValue( valDisplaced / axisRange ); - } - else if(joystickBinderItem.direction == Control::DECREASE) - { - float axisRange = OIS::JoyStick::MAX_AXIS - OIS::JoyStick::MIN_AXIS; - float valDisplaced = (float)(evt.state.mSliders[index].abX - OIS::JoyStick::MIN_AXIS); - - ctrl->setValue( 1 - ( valDisplaced / axisRange ) ); - } - } - } - } - else if(mDetectingBindingListener) - { - if(mDetectingBindingControl && mDetectingBindingControl->isAxisBindable()) - { - if( abs( evt.state.mSliders[index].abX ) > ICS_JOYSTICK_SLIDER_BINDING_MARGIN) - { - mDetectingBindingListener->joystickSliderBindingDetected(this, - mDetectingBindingControl, evt.device->getID(), index, mDetectingBindingDirection); - } - } - } - } - } - */ - // joystick auto bindings - void DetectingBindingListener::joystickAxisBindingDetected(InputControlSystem* ICS, Control* control - , int deviceId, int axis, Control::ControlChangingDirection direction) + void DetectingBindingListener::joystickAxisBindingDetected(InputControlSystem* ICS, Control* control, int axis, Control::ControlChangingDirection direction) { // if the joystick axis is used by another control, remove it - ICS->removeJoystickAxisBinding(deviceId, axis); + ICS->removeJoystickAxisBinding(axis); // if the control has an axis assigned, remove it - int oldAxis = ICS->getJoystickAxisBinding(control, deviceId, direction); - if(oldAxis != InputControlSystem::UNASSIGNED) + int oldAxis = ICS->getJoystickAxisBinding(control, direction); + if(oldAxis != InputControlSystem::UNASSIGNED) { - ICS->removeJoystickAxisBinding(deviceId, oldAxis); + ICS->removeJoystickAxisBinding(oldAxis); } - ICS->addJoystickAxisBinding(control, deviceId, axis, direction); + ICS->addJoystickAxisBinding(control, axis, direction); ICS->cancelDetectingBindingState(); } void DetectingBindingListener::joystickButtonBindingDetected(InputControlSystem* ICS, Control* control - , int deviceId, unsigned int button, Control::ControlChangingDirection direction) + , unsigned int button, Control::ControlChangingDirection direction) { // if the joystick button is used by another control, remove it - ICS->removeJoystickButtonBinding(deviceId, button); + ICS->removeJoystickButtonBinding(button); // if the control has a joystick button assigned, remove it - unsigned int oldButton = ICS->getJoystickButtonBinding(control, deviceId, direction); + unsigned int oldButton = ICS->getJoystickButtonBinding(control, direction); if(oldButton != ICS_MAX_DEVICE_BUTTONS) { - ICS->removeJoystickButtonBinding(deviceId, oldButton); - } - - ICS->addJoystickButtonBinding(control, deviceId, button, direction); - ICS->cancelDetectingBindingState(); - } - - - void DetectingBindingListener::joystickPOVBindingDetected(InputControlSystem* ICS, Control* control - , int deviceId, int pov, InputControlSystem::POVAxis axis, Control::ControlChangingDirection direction) - { - // if the joystick slider is used by another control, remove it - ICS->removeJoystickPOVBinding(deviceId, pov, axis); - - // if the control has a joystick button assigned, remove it - ICS::InputControlSystem::POVBindingPair oldPOV = ICS->getJoystickPOVBinding(control, deviceId, direction); - if(oldPOV.index >= 0 && oldPOV.axis == axis) - { - ICS->removeJoystickPOVBinding(deviceId, oldPOV.index, oldPOV.axis); - } - - ICS->addJoystickPOVBinding(control, deviceId, pov, axis, direction); - ICS->cancelDetectingBindingState(); - } - - void DetectingBindingListener::joystickSliderBindingDetected(InputControlSystem* ICS, Control* control - , int deviceId, int slider, Control::ControlChangingDirection direction) - { - // if the joystick slider is used by another control, remove it - ICS->removeJoystickSliderBinding(deviceId, slider); - - // if the control has a joystick slider assigned, remove it - int oldSlider = ICS->getJoystickSliderBinding(control, deviceId, direction); - if(oldSlider != InputControlSystem::/*NamedAxis::*/UNASSIGNED) - { - ICS->removeJoystickSliderBinding(deviceId, oldSlider); + ICS->removeJoystickButtonBinding(oldButton); } - ICS->addJoystickSliderBinding(control, deviceId, slider, direction); + ICS->addJoystickButtonBinding(control, button, direction); ICS->cancelDetectingBindingState(); } } diff --git a/extern/sdl4ogre/events.h b/extern/sdl4ogre/events.h index 0fb4d6f06..ebabb4cbb 100644 --- a/extern/sdl4ogre/events.h +++ b/extern/sdl4ogre/events.h @@ -40,23 +40,25 @@ public: virtual void keyReleased(const SDL_KeyboardEvent &arg) = 0; }; -class JoyListener +class ControllerListener { public: - virtual ~JoyListener() {} + virtual ~ControllerListener() {} /** @remarks Joystick button down event */ - virtual void buttonPressed( const SDL_JoyButtonEvent &evt, int button ) = 0; + virtual void buttonPressed( const SDL_ControllerButtonEvent &evt) = 0; /** @remarks Joystick button up event */ - virtual void buttonReleased( const SDL_JoyButtonEvent &evt, int button ) = 0; + virtual void buttonReleased( const SDL_ControllerButtonEvent &evt) = 0; /** @remarks Joystick axis moved event */ - virtual void axisMoved( const SDL_JoyAxisEvent &arg, int axis ) = 0; + virtual void axisMoved( const SDL_ControllerAxisEvent &arg) = 0; - //-- Not so common control events, so are not required --// + /** @remarks Joystick Added **/ + virtual void controllerAdded( const SDL_ControllerDeviceEvent &arg) = 0; + + /** @remarks Joystick Removed **/ + virtual void controllerRemoved( const SDL_ControllerDeviceEvent &arg) = 0; - //! Joystick Event, and povID - virtual void povMoved( const SDL_JoyHatEvent &arg, int index) {} }; class WindowListener diff --git a/extern/sdl4ogre/sdlinputwrapper.cpp b/extern/sdl4ogre/sdlinputwrapper.cpp index db46a4af9..f211811cc 100644 --- a/extern/sdl4ogre/sdlinputwrapper.cpp +++ b/extern/sdl4ogre/sdlinputwrapper.cpp @@ -20,7 +20,7 @@ namespace SFO mMouseY(0), mMouseX(0), mMouseInWindow(true), - mJoyListener(NULL), + mConListener(NULL), mKeyboardListener(NULL), mMouseListener(NULL), mWindowListener(NULL), @@ -88,24 +88,32 @@ namespace SFO case SDL_TEXTINPUT: mKeyboardListener->textInput(evt.text); break; + case SDL_JOYHATMOTION: //As we manage everything with GameController, don't even bother with these. case SDL_JOYAXISMOTION: - if (mJoyListener) - mJoyListener->axisMoved(evt.jaxis, evt.jaxis.axis); - break; case SDL_JOYBUTTONDOWN: - if (mJoyListener) - mJoyListener->buttonPressed(evt.jbutton, evt.jbutton.button); - break; case SDL_JOYBUTTONUP: - if (mJoyListener) - mJoyListener->buttonReleased(evt.jbutton, evt.jbutton.button); - break; case SDL_JOYDEVICEADDED: - //SDL_JoystickOpen(evt.jdevice.which); - //std::cout << "Detected a new joystick: " << SDL_JoystickNameForIndex(evt.jdevice.which) << std::endl; - break; case SDL_JOYDEVICEREMOVED: - //std::cout << "A joystick has been removed" << std::endl; + break; + case SDL_CONTROLLERDEVICEADDED: + if(mConListener) + mConListener->controllerAdded(evt.cdevice); + break; + case SDL_CONTROLLERDEVICEREMOVED: + if(mConListener) + mConListener->controllerRemoved(evt.cdevice); + break; + case SDL_CONTROLLERBUTTONDOWN: + if(mConListener) + mConListener->buttonPressed(evt.cbutton); + break; + case SDL_CONTROLLERBUTTONUP: + if(mConListener) + mConListener->buttonReleased(evt.cbutton); + break; + case SDL_CONTROLLERAXISMOTION: + if(mConListener) + mConListener->axisMoved(evt.caxis); break; case SDL_WINDOWEVENT: handleWindowEvent(evt); diff --git a/extern/sdl4ogre/sdlinputwrapper.hpp b/extern/sdl4ogre/sdlinputwrapper.hpp index 339e99de1..efc71f1a1 100644 --- a/extern/sdl4ogre/sdlinputwrapper.hpp +++ b/extern/sdl4ogre/sdlinputwrapper.hpp @@ -24,7 +24,7 @@ namespace SFO void setMouseEventCallback(MouseListener* listen) { mMouseListener = listen; } void setKeyboardEventCallback(KeyListener* listen) { mKeyboardListener = listen; } void setWindowEventCallback(WindowListener* listen) { mWindowListener = listen; } - void setJoyEventCallback(JoyListener* listen) { mJoyListener = listen; } + void setControllerEventCallback(ControllerListener* listen) { mConListener = listen; } void capture(bool windowEventsOnly); bool isModifierHeld(SDL_Keymod mod); @@ -54,7 +54,7 @@ namespace SFO SFO::MouseListener* mMouseListener; SFO::KeyListener* mKeyboardListener; SFO::WindowListener* mWindowListener; - SFO::JoyListener* mJoyListener; + SFO::ControllerListener* mConListener; typedef boost::unordered_map KeyMap; KeyMap mKeyMap; diff --git a/files/CMakeLists.txt b/files/CMakeLists.txt index 9b2325744..b7417a51d 100644 --- a/files/CMakeLists.txt +++ b/files/CMakeLists.txt @@ -52,3 +52,5 @@ set(MATERIAL_FILES copy_all_files(${CMAKE_CURRENT_SOURCE_DIR}/water "${OpenMW_BINARY_DIR}/resources/water/" "${WATER_FILES}") copy_all_files(${CMAKE_CURRENT_SOURCE_DIR}/materials "${OpenMW_BINARY_DIR}/resources/materials/" "${MATERIAL_FILES}") + +file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/gamecontrollerdb.txt ${OpenMW_BINARY_DIR}/resources/) diff --git a/files/gamecontrollerdb.txt b/files/gamecontrollerdb.txt new file mode 100644 index 000000000..9ad8778a0 --- /dev/null +++ b/files/gamecontrollerdb.txt @@ -0,0 +1,75 @@ +# Windows - DINPUT +8f0e1200000000000000504944564944,Acme,platform:Windows,x:b2,a:b0,b:b1,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2, +341a3608000000000000504944564944,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +ffff0000000000000000504944564944,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +6d0416c2000000000000504944564944,Generic DirectInput Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +6d0419c2000000000000504944564944,Logitech F710 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +88880803000000000000504944564944,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b9,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b0,y:b3,platform:Windows, +4c056802000000000000504944564944,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Windows, +25090500000000000000504944564944,PS3 DualShock,a:b2,b:b1,back:b9,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b0,y:b3,platform:Windows, +4c05c405000000000000504944564944,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +xinput,X360 Controller,a:b10,b:b11,back:b5,dpdown:b1,dpleft:b2,dpright:b3,dpup:b0,guide:b14,leftshoulder:b8,leftstick:b6,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b7,righttrigger:a5,rightx:a2,righty:a3,start:b4,x:b12,y:b13,platform:Windows, +6d0418c2000000000000504944564944,Logitech RumblePad 2 USB,platform:Windows,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3, +36280100000000000000504944564944,OUYA Controller,platform:Windows,a:b0,b:b3,y:b2,x:b1,start:b14,guide:b15,leftstick:b6,rightstick:b7,leftshoulder:b4,rightshoulder:b5,dpup:b8,dpleft:b10,dpdown:b9,dpright:b11,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b12,righttrigger:b13, +4f0400b3000000000000504944564944,Thrustmaster Firestorm Dual Power,a:b0,b:b2,y:b3,x:b1,start:b10,guide:b8,back:b9,leftstick:b11,rightstick:b12,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Windows, +00f00300000000000000504944564944,RetroUSB.com RetroPad,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Windows, +00f0f100000000000000504944564944,RetroUSB.com Super RetroPort,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Windows, +28040140000000000000504944564944,GamePad Pro USB,platform:Windows,a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,lefttrigger:b6,righttrigger:b7, +ff113133000000000000504944564944,SVEN X-PAD,platform:Windows,a:b2,b:b3,y:b1,x:b0,start:b5,back:b4,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a4,lefttrigger:b8,righttrigger:b9, + +# OS X +0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X, +6d0400000000000016c2000000000000,Logitech F310 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +6d0400000000000018c2000000000000,Logitech F510 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +6d040000000000001fc2000000000000,Logitech F710 Gamepad (XInput),a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +6d0400000000000019c2000000000000,Logitech Wireless Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +4c050000000000006802000000000000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Mac OS X, +4c05000000000000c405000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,Platform:Mac OS X, +5e040000000000008e02000000000000,X360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +891600000000000000fd000000000000,Razer Onza Tournament,a:b0,b:b1,y:b3,x:b2,start:b8,guide:b10,back:b9,leftstick:b6,rightstick:b7,leftshoulder:b4,rightshoulder:b5,dpup:b11,dpleft:b13,dpdown:b12,dpright:b14,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Mac OS X, +4f0400000000000000b3000000000000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,y:b3,x:b1,start:b10,guide:b8,back:b9,leftstick:b11,rightstick:,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Mac OS X, + +# Linux +0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, +03000000ba2200002010000001010000,Jess Technology USB Game Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux, +030000006d04000019c2000010010000,Logitech Cordless RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000006d0400001dc2000014400000,Logitech F310 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006d0400001ec2000020200000,Logitech F510 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006d04000019c2000011010000,Logitech F710 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000006d0400001fc2000005030000,Logitech F710 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000004c0500006802000011010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux, +030000004c050000c405000011010000,Sony DualShock 4,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:b6,righttrigger:b7,platform:Linux, +03000000de280000ff11000001000000,Valve Streaming Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e0400008e02000014010000,X360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e0400008e02000010010000,X360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e0400001907000000010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000100800000100000010010000,Twin USB PS2 Adapter,a:b2,b:b1,y:b0,x:b3,start:b9,guide:,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b4,righttrigger:b5,platform:Linux, +03000000a306000023f6000011010000,Saitek Cyborg V.1 Game Pad,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a4,lefttrigger:b6,righttrigger:b7,platform:Linux, +030000004f04000020b3000010010000,Thrustmaster 2 in 1 DT,a:b0,b:b2,y:b3,x:b1,start:b9,guide:,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Linux, +030000004f04000023b3000000010000,Thrustmaster Dual Trigger 3-in-1,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a5, +030000008f0e00000300000010010000,GreenAsia Inc. USB Joystick ,platform:Linux,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2, +030000008f0e00001200000010010000,GreenAsia Inc. USB Joystick ,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2, +030000005e0400009102000007010000,X360 Wireless Controller,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:b13,dpleft:b11,dpdown:b14,dpright:b12,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux, +030000006d04000016c2000010010000,Logitech Logitech Dual Action,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3, +03000000260900008888000000010000,GameCube {WiseGroup USB box},a:b0,b:b2,y:b3,x:b1,start:b7,leftshoulder:,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,rightstick:,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:Linux, +030000006d04000011c2000010010000,Logitech WingMan Cordless RumblePad,a:b0,b:b1,y:b4,x:b3,start:b8,guide:b5,back:b2,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b9,righttrigger:b10,platform:Linux, +030000006d04000018c2000010010000,Logitech Logitech RumblePad 2 USB,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3, +05000000d6200000ad0d000001000000,Moga Pro,platform:Linux,a:b0,b:b1,y:b3,x:b2,start:b6,leftstick:b7,rightstick:b8,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a5,righttrigger:a4, +030000004f04000009d0000000010000,Thrustmaster Run N Drive Wireless PS3,platform:Linux,a:b1,b:b2,x:b0,y:b3,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7, +030000004f04000008d0000000010000,Thrustmaster Run N Drive Wireless,platform:Linux,a:b1,b:b2,x:b0,y:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:b6,righttrigger:b7, +0300000000f000000300000000010000,RetroUSB.com RetroPad,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Linux, +0300000000f00000f100000000010000,RetroUSB.com Super RetroPort,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Linux, +030000006f0e00001f01000000010000,Generic X-Box pad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4, +03000000280400000140000000010000,Gravis GamePad Pro USB ,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftx:a0,lefty:a1, +030000005e0400008902000021010000,Microsoft X-Box pad v2 (US),platform:Linux,x:b3,a:b0,b:b1,y:b4,back:b6,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b5,lefttrigger:a2,rightshoulder:b2,righttrigger:a5,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a3,righty:a4, +030000006f0e00001e01000011010000,Rock Candy Gamepad for PS3,platform:Linux,a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,guide:b12,leftshoulder:b4,rightshoulder:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2, +03000000250900000500000000010000,Sony PS2 pad with SmartJoy adapter,platform:Linux,a:b2,b:b1,y:b0,x:b3,start:b8,back:b9,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b4,righttrigger:b5, +030000008916000000fd000024010000,Razer Onza Tournament,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:b13,dpleft:b11,dpdown:b14,dpright:b12,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux, +030000004f04000000b3000010010000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,y:b3,x:b1,start:b10,guide:b8,back:b9,leftstick:b11,rightstick:b12,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Linux, +03000000ad1b000001f5000033050000,Hori Pad EX Turbo 2,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux, +050000004c050000c405000000010000,PS4 Controller (Bluetooth),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +060000004c0500006802000000010000,PS3 Controller (Bluetooth),a:b14,b:b13,y:b12,x:b15,start:b3,guide:b16,back:b0,leftstick:b1,rightstick:b2,leftshoulder:b10,rightshoulder:b11,dpup:b4,dpleft:b7,dpdown:b6,dpright:b5,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b8,righttrigger:b9,platform:Linux, +03000000790000000600000010010000,DragonRise Inc. Generic USB Joystick ,platform:Linux,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a4, +03000000666600000488000000010000,Super Joy Box 5 Pro,platform:Linux,a:b2,b:b1,x:b3,y:b0,back:b9,start:b8,leftshoulder:b6,rightshoulder:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b4,righttrigger:b5,dpup:b12,dpleft:b15,dpdown:b14,dpright:b13, +05000000362800000100000002010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,platform:Linux,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2, +05000000362800000100000003010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,platform:Linux,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2, From 073a2f067417b4d4c1ceb3f802198f1111647608 Mon Sep 17 00:00:00 2001 From: Digmaster Date: Tue, 9 Dec 2014 00:02:18 -0600 Subject: [PATCH 0083/3725] Fixed issue with walking --- apps/openmw/mwinput/inputmanagerimp.cpp | 2 +- files/CMakeLists.txt | 6 ++++- files/mygui/openmw_settings_window.layout | 28 ++++++++++++++--------- 3 files changed, 23 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index a25bb727c..2cb9075bd 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -1047,7 +1047,7 @@ namespace MWInput bool InputManager::actionIsActive (int id) { - return (mInputBinder->getChannel (id)->getValue ()!=0.0); + return (mInputBinder->getChannel (id)->getValue ()==1.0); } void InputManager::loadKeyDefaults (bool force) diff --git a/files/CMakeLists.txt b/files/CMakeLists.txt index b7417a51d..4635cbfa4 100644 --- a/files/CMakeLists.txt +++ b/files/CMakeLists.txt @@ -49,8 +49,12 @@ set(MATERIAL_FILES mygui.shaderset ) +set(ETC_FILES + gamecontrollerdb.txt +) + copy_all_files(${CMAKE_CURRENT_SOURCE_DIR}/water "${OpenMW_BINARY_DIR}/resources/water/" "${WATER_FILES}") copy_all_files(${CMAKE_CURRENT_SOURCE_DIR}/materials "${OpenMW_BINARY_DIR}/resources/materials/" "${MATERIAL_FILES}") -file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/gamecontrollerdb.txt ${OpenMW_BINARY_DIR}/resources/) +copy_all_files(${CMAKE_CURRENT_SOURCE_DIR} "${OpenMW_BINARY_DIR}/resources/" "${ETC_FILES}") diff --git a/files/mygui/openmw_settings_window.layout b/files/mygui/openmw_settings_window.layout index fd84be3e9..11751b7ec 100644 --- a/files/mygui/openmw_settings_window.layout +++ b/files/mygui/openmw_settings_window.layout @@ -1,10 +1,10 @@  - + - + - + @@ -172,15 +172,21 @@ - + + + + + + + - + - + @@ -190,10 +196,10 @@ - + - + @@ -203,11 +209,11 @@ - + - + @@ -460,7 +466,7 @@ - + From ad54e095934d0660308c8e9fe21aa9c6d9b916af Mon Sep 17 00:00:00 2001 From: Digmaster Date: Tue, 9 Dec 2014 11:16:17 -0600 Subject: [PATCH 0084/3725] Inital value for joysticks is 0.5 --- apps/openmw/mwinput/inputmanagerimp.cpp | 16 ++++++++++++++-- extern/oics/ICSControl.h | 7 ++++--- extern/oics/ICSInputControlSystem.cpp | 2 ++ 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 2cb9075bd..633ae10d4 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -1120,11 +1120,13 @@ namespace MWInput if (defaultKeyBindings.find(i) != defaultKeyBindings.end() && !mInputBinder->isKeyBound(defaultKeyBindings[i])) { + control->setInitialValue(0.0f); mInputBinder->addKeyBinding(control, defaultKeyBindings[i], ICS::Control::INCREASE); } else if (defaultMouseButtonBindings.find(i) != defaultMouseButtonBindings.end() && !mInputBinder->isMouseButtonBound(defaultMouseButtonBindings[i])) { + control->setInitialValue(0.0f); mInputBinder->addMouseButtonBinding (control, defaultMouseButtonBindings[i], ICS::Control::INCREASE); } } @@ -1167,7 +1169,11 @@ namespace MWInput bool controlExists = mInputBinder->getChannel(i)->getControlsCount () != 0; if (!controlExists) { - control = new ICS::Control(boost::lexical_cast(i), false, true, 0, ICS::ICS_MAX, ICS::ICS_MAX); + int inital; + if (defaultButtonBindings.find(i) != defaultButtonBindings.end()) + inital = 0.0f; + else inital = 0.5f; + control = new ICS::Control(boost::lexical_cast(i), false, true, inital, ICS::ICS_MAX, ICS::ICS_MAX); mInputBinder->addControl(control); control->attachChannel(mInputBinder->getChannel(i), ICS::Channel::DIRECT); } @@ -1182,11 +1188,13 @@ namespace MWInput if (defaultButtonBindings.find(i) != defaultButtonBindings.end()) { - control->setValue(0.5f); + control->setInitialValue(0.0f); mInputBinder->addJoystickButtonBinding(control, defaultButtonBindings[i], ICS::Control::INCREASE); } else if (defaultAxisBindings.find(i) != defaultAxisBindings.end()) { + control->setValue(0.5f); + control->setInitialValue(0.5f); mInputBinder->addJoystickAxisBinding(control, defaultAxisBindings[i], ICS::Control::INCREASE); } } @@ -1426,6 +1434,7 @@ namespace MWInput return; clearAllKeyBindings(control); + control->setInitialValue(0.0f); ICS::DetectingBindingListener::keyBindingDetected (ICS, control, key, direction); MWBase::Environment::get().getWindowManager ()->notifyInputActionBound (); } @@ -1436,6 +1445,7 @@ namespace MWInput if(!mDetectingKeyboard) return; clearAllKeyBindings(control); + control->setInitialValue(0.0f); ICS::DetectingBindingListener::mouseButtonBindingDetected (ICS, control, button, direction); MWBase::Environment::get().getWindowManager ()->notifyInputActionBound (); } @@ -1451,6 +1461,7 @@ namespace MWInput clearAllControllerBindings(control); control->setValue(0.5f); //axis bindings must start at 0.5 + control->setInitialValue(0.5f); ICS::DetectingBindingListener::joystickAxisBindingDetected (ICS, control, axis, direction); MWBase::Environment::get().getWindowManager ()->notifyInputActionBound (); } @@ -1461,6 +1472,7 @@ namespace MWInput if(mDetectingKeyboard) return; clearAllControllerBindings(control); + control->setInitialValue(0.0f); ICS::DetectingBindingListener::joystickButtonBindingDetected (ICS, control, button, direction); MWBase::Environment::get().getWindowManager ()->notifyInputActionBound (); } diff --git a/extern/oics/ICSControl.h b/extern/oics/ICSControl.h index ebf75a3fe..1ed437652 100644 --- a/extern/oics/ICSControl.h +++ b/extern/oics/ICSControl.h @@ -34,7 +34,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. namespace ICS { - + class DllExport Control { public: @@ -52,9 +52,10 @@ namespace ICS void setValue(float value); inline float getValue(){ return mValue; }; - inline float getInitialValue(){ return mInitialValue; }; + inline float getInitialValue(){ return mInitialValue; }; + inline void setInitialValue(float i) {mInitialValue = i;}; - void attachChannel(Channel* channel, Channel::ChannelDirection direction, float percentage = 1.0); + void attachChannel(Channel* channel, Channel::ChannelDirection direction, float percentage = 1.0); std::list getAttachedChannels(){ return mAttachedChannels; }; inline float getStepSize(){ return mStepSize; }; diff --git a/extern/oics/ICSInputControlSystem.cpp b/extern/oics/ICSInputControlSystem.cpp index 4237060bb..3c719151b 100644 --- a/extern/oics/ICSInputControlSystem.cpp +++ b/extern/oics/ICSInputControlSystem.cpp @@ -278,6 +278,7 @@ namespace ICS /* Joystick Init */ //Load controller mappings +#if SDL_VERSION_ATLEAST(2,0,2) int res = SDL_GameControllerAddMappingsFromFile("resources/gamecontrollerdb.txt"); if(res == -1) { @@ -287,6 +288,7 @@ namespace ICS { ICS_LOG(std::string("Loaded ")+boost::lexical_cast(res)+" Game controller bindings"); } +#endif //Open all presently connected sticks int numSticks = SDL_NumJoysticks(); From a7a211860aa691c0169fdd8c6ba44a997d5478d7 Mon Sep 17 00:00:00 2001 From: Digmaster Date: Tue, 9 Dec 2014 12:12:38 -0600 Subject: [PATCH 0085/3725] Fixed binding controls to A on joystick --- apps/openmw/mwinput/inputmanagerimp.cpp | 13 +++++++---- .../oics/ICSInputControlSystem_joystick.cpp | 23 +++++++++++-------- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 633ae10d4..2dbbea662 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -740,13 +740,16 @@ namespace MWInput if (arg.button == SDL_CONTROLLER_BUTTON_A || arg.button == SDL_CONTROLLER_BUTTON_B) // We'll pretend that A is left click and B is right click { guiMode = MWBase::Environment::get().getWindowManager()->isGuiMode(); - guiMode = MyGUI::InputManager::getInstance().injectMousePress(mMouseX, mMouseY, sdlButtonToMyGUI((arg.button == SDL_CONTROLLER_BUTTON_B) ? SDL_BUTTON_RIGHT : SDL_BUTTON_LEFT)) && guiMode; - if (MyGUI::InputManager::getInstance ().getMouseFocusWidget () != 0) + if(!mInputBinder->detectingBindingState()) { - MyGUI::Button* b = MyGUI::InputManager::getInstance ().getMouseFocusWidget ()->castType(false); - if (b && b->getEnabled()) + guiMode = MyGUI::InputManager::getInstance().injectMousePress(mMouseX, mMouseY, sdlButtonToMyGUI((arg.button == SDL_CONTROLLER_BUTTON_B) ? SDL_BUTTON_RIGHT : SDL_BUTTON_LEFT)) && guiMode; + if (MyGUI::InputManager::getInstance ().getMouseFocusWidget () != 0) { - MWBase::Environment::get().getSoundManager ()->playSound ("Menu Click", 1.f, 1.f); + MyGUI::Button* b = MyGUI::InputManager::getInstance ().getMouseFocusWidget ()->castType(false); + if (b && b->getEnabled()) + { + MWBase::Environment::get().getSoundManager ()->playSound ("Menu Click", 1.f, 1.f); + } } } } diff --git a/extern/oics/ICSInputControlSystem_joystick.cpp b/extern/oics/ICSInputControlSystem_joystick.cpp index 9cd9b1461..d8dbfa112 100644 --- a/extern/oics/ICSInputControlSystem_joystick.cpp +++ b/extern/oics/ICSInputControlSystem_joystick.cpp @@ -180,23 +180,26 @@ namespace ICS } } } - else if(mDetectingBindingListener) - { - mDetectingBindingListener->joystickButtonBindingDetected(this, - mDetectingBindingControl, evt.button, mDetectingBindingDirection); - } } } void InputControlSystem::buttonReleased(const SDL_ControllerButtonEvent &evt) { if(mActive) - { - ControlsButtonBinderMapType::const_iterator it = mControlsJoystickButtonBinderMap.find(evt.button); - if(it != mControlsJoystickButtonBinderMap.end()) + { + if(!mDetectingBindingControl) { - it->second.control->setChangingDirection(Control::STOP); - } + ControlsButtonBinderMapType::const_iterator it = mControlsJoystickButtonBinderMap.find(evt.button); + if(it != mControlsJoystickButtonBinderMap.end()) + { + it->second.control->setChangingDirection(Control::STOP); + } + } + else if(mDetectingBindingListener) + { + mDetectingBindingListener->joystickButtonBindingDetected(this, + mDetectingBindingControl, evt.button, mDetectingBindingDirection); + } } } From bb6ed06a4eacf1dc0c3fa852eb9cec70e138cc11 Mon Sep 17 00:00:00 2001 From: Digmaster Date: Tue, 9 Dec 2014 14:37:32 -0600 Subject: [PATCH 0086/3725] read gamecontrollerdb file location from settings file --- apps/openmw/mwinput/inputmanagerimp.cpp | 4 ++-- extern/oics/ICSInputControlSystem.cpp | 21 ++++++++++++--------- extern/oics/ICSInputControlSystem.h | 3 ++- files/settings-default.cfg | 2 ++ 4 files changed, 18 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 2dbbea662..3d1239f54 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -135,8 +135,8 @@ namespace MWInput mInputManager->setControllerEventCallback(this); std::string file = userFileExists ? userFile : ""; - mInputBinder = new ICS::InputControlSystem(file, true, this, NULL, A_Last); - + std::string controllerdb = Settings::Manager::getString("gamecontrollerdb file", "Input"); + mInputBinder = new ICS::InputControlSystem(file, true, this, NULL, controllerdb, A_Last); adjustMouseRegion (window->getWidth(), window->getHeight()); loadKeyDefaults(); diff --git a/extern/oics/ICSInputControlSystem.cpp b/extern/oics/ICSInputControlSystem.cpp index 3c719151b..4db28d3f1 100644 --- a/extern/oics/ICSInputControlSystem.cpp +++ b/extern/oics/ICSInputControlSystem.cpp @@ -30,7 +30,7 @@ namespace ICS { InputControlSystem::InputControlSystem(std::string file, bool active , DetectingBindingListener* detectingBindingListener - , InputControlSystemLog* log, size_t channelCount) + , InputControlSystemLog* log, std::string controllerdb, size_t channelCount) : mFileName(file) , mDetectingBindingListener(detectingBindingListener) , mDetectingBindingControl(NULL) @@ -279,14 +279,17 @@ namespace ICS //Load controller mappings #if SDL_VERSION_ATLEAST(2,0,2) - int res = SDL_GameControllerAddMappingsFromFile("resources/gamecontrollerdb.txt"); - if(res == -1) - { - ICS_LOG(std::string("Error loading controller bindings: ")+SDL_GetError()); - } - else - { - ICS_LOG(std::string("Loaded ")+boost::lexical_cast(res)+" Game controller bindings"); + if(!controllerdb.empty()) + { + int res = SDL_GameControllerAddMappingsFromFile(controllerdb.c_str()); + if(res == -1) + { + ICS_LOG(std::string("Error loading controller bindings: ")+SDL_GetError()); + } + else + { + ICS_LOG(std::string("Loaded ")+boost::lexical_cast(res)+" Game controller bindings"); + } } #endif diff --git a/extern/oics/ICSInputControlSystem.h b/extern/oics/ICSInputControlSystem.h index 0bdd67b34..f58d242fc 100644 --- a/extern/oics/ICSInputControlSystem.h +++ b/extern/oics/ICSInputControlSystem.h @@ -74,7 +74,8 @@ namespace ICS InputControlSystem(std::string file = "", bool active = true , DetectingBindingListener* detectingBindingListener = NULL - , InputControlSystemLog* log = NULL, size_t channelCount = 16); + , InputControlSystemLog* log = NULL, std::string controllerdb = "" + , size_t channelCount = 16); ~InputControlSystem(); std::string getFileName(){ return mFileName; }; diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 7566994e2..ae0a468cd 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -181,6 +181,8 @@ always run = false allow third person zoom = false +gamecontrollerdb file = resources/gamecontrollerdb.txt + [Game] # Always use the most powerful attack when striking with a weapon (chop, slash or thrust) best attack = false From 95219a7936be2aaca207b9c1b2712f218e0ad69c Mon Sep 17 00:00:00 2001 From: Digmaster Date: Tue, 9 Dec 2014 14:48:34 -0600 Subject: [PATCH 0087/3725] Show currently selected input type for settings window --- apps/openmw/mwgui/settingswindow.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 619a0c87d..a07fa032a 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -245,6 +245,9 @@ namespace MWGui MyGUI::TextBox* diffText; getWidget(diffText, "DifficultyText"); diffText->setCaptionWithReplacing("#{sDifficulty} (" + boost::lexical_cast(int(Settings::Manager::getInt("difficulty", "Game"))) + ")"); + + mKeyboardSwitch->setStateSelected(true); + mControllerSwitch->setStateSelected(false); } void SettingsWindow::onOkButtonClicked(MyGUI::Widget* _sender) @@ -447,6 +450,8 @@ namespace MWGui if(mKeyboardMode) return; mKeyboardMode = true; + mKeyboardSwitch->setStateSelected(true); + mControllerSwitch->setStateSelected(false); updateControlsBox(); } @@ -455,6 +460,8 @@ namespace MWGui if(!mKeyboardMode) return; mKeyboardMode = false; + mKeyboardSwitch->setStateSelected(false); + mControllerSwitch->setStateSelected(true); updateControlsBox(); } From e076e8a9bd3303cbce04d475ce9cdc0c2091df14 Mon Sep 17 00:00:00 2001 From: Digmaster Date: Tue, 9 Dec 2014 14:53:50 -0600 Subject: [PATCH 0088/3725] Fixed error when downgrading openmw versions --- extern/oics/ICSInputControlSystem.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/extern/oics/ICSInputControlSystem.cpp b/extern/oics/ICSInputControlSystem.cpp index 4db28d3f1..a8efd54bc 100644 --- a/extern/oics/ICSInputControlSystem.cpp +++ b/extern/oics/ICSInputControlSystem.cpp @@ -579,7 +579,9 @@ namespace ICS binder.SetAttribute( "axis", ToString( getJoystickAxisBinding(*o, Control/*::ControlChangingDirection*/::INCREASE)).c_str() ); - binder.SetAttribute( "direction", "INCREASE" ); + binder.SetAttribute( "direction", "INCREASE" ); + + binder.SetAttribute( "deviceId", "1" ); //completely useless, but required for backwards compatability control.InsertEndChild(binder); } @@ -592,7 +594,9 @@ namespace ICS binder.SetAttribute( "axis", ToString( getJoystickAxisBinding(*o, Control/*::ControlChangingDirection*/::DECREASE)).c_str() ); - binder.SetAttribute( "direction", "DECREASE" ); + binder.SetAttribute( "direction", "DECREASE" ); + + binder.SetAttribute( "deviceId", "1" ); //completely useless, but required for backwards compatability control.InsertEndChild(binder); } @@ -605,7 +609,9 @@ namespace ICS binder.SetAttribute( "button", ToString( getJoystickButtonBinding(*o, Control/*::ControlChangingDirection*/::INCREASE)).c_str() ); - binder.SetAttribute( "direction", "INCREASE" ); + binder.SetAttribute( "direction", "INCREASE" ); + + binder.SetAttribute( "deviceId", "1" ); //completely useless, but required for backwards compatability control.InsertEndChild(binder); } @@ -618,7 +624,9 @@ namespace ICS binder.SetAttribute( "button", ToString( getJoystickButtonBinding(*o, Control/*::ControlChangingDirection*/::DECREASE)).c_str() ); - binder.SetAttribute( "direction", "DECREASE" ); + binder.SetAttribute( "direction", "DECREASE" ); + + binder.SetAttribute( "deviceId", "1" ); //completely useless, but required for backwards compatability control.InsertEndChild(binder); } From 61d73d186dafd98eea27d9ce1404a23b631a6f7a Mon Sep 17 00:00:00 2001 From: Digmaster Date: Tue, 9 Dec 2014 14:56:40 -0600 Subject: [PATCH 0089/3725] Fixed part of settings window being in the incorrect place --- files/mygui/openmw_settings_window.layout | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/mygui/openmw_settings_window.layout b/files/mygui/openmw_settings_window.layout index 11751b7ec..d0ab0a7bc 100644 --- a/files/mygui/openmw_settings_window.layout +++ b/files/mygui/openmw_settings_window.layout @@ -213,7 +213,7 @@ - + From 1b9209df4a2ad0030faeed309b7b740a38d3c5a9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 17 Dec 2014 16:07:50 +0100 Subject: [PATCH 0090/3725] Allow blocking of hand-to-hand attacks --- apps/openmw/mwclass/creature.cpp | 2 +- apps/openmw/mwclass/npc.cpp | 2 +- apps/openmw/mwmechanics/combat.cpp | 9 +++++++-- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 5fd5f4dde..323fafbb6 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -324,7 +324,7 @@ namespace MWClass MWMechanics::applyElementalShields(ptr, victim); - if (!weapon.isEmpty() && MWMechanics::blockMeleeAttack(ptr, victim, weapon, damage)) + if (MWMechanics::blockMeleeAttack(ptr, victim, weapon, damage)) damage = 0; if (damage > 0) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 4814879ac..2c68b4c72 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -641,7 +641,7 @@ namespace MWClass MWMechanics::applyElementalShields(ptr, victim); - if (!weapon.isEmpty() && MWMechanics::blockMeleeAttack(ptr, victim, weapon, damage)) + if (MWMechanics::blockMeleeAttack(ptr, victim, weapon, damage)) damage = 0; if (healthdmg && damage > 0) diff --git a/apps/openmw/mwmechanics/combat.cpp b/apps/openmw/mwmechanics/combat.cpp index 4d484469c..e52dbdde7 100644 --- a/apps/openmw/mwmechanics/combat.cpp +++ b/apps/openmw/mwmechanics/combat.cpp @@ -91,7 +91,11 @@ namespace MWMechanics blockerTerm *= gmst.find("fBlockStillBonus")->getFloat(); blockerTerm *= blockerStats.getFatigueTerm(); - float attackerSkill = attacker.getClass().getSkill(attacker, weapon.getClass().getEquipmentSkill(weapon)); + float attackerSkill = 0.f; + if (weapon.isEmpty()) + attackerSkill = attacker.getClass().getSkill(attacker, ESM::Skill::HandToHand); + else + attackerSkill = attacker.getClass().getSkill(attacker, weapon.getClass().getEquipmentSkill(weapon)); float attackerTerm = attackerSkill + 0.2 * attackerStats.getAttribute(ESM::Attribute::Agility).getModified() + 0.1 * attackerStats.getAttribute(ESM::Attribute::Luck).getModified(); attackerTerm *= attackerStats.getFatigueTerm(); @@ -120,7 +124,8 @@ namespace MWMechanics float normalizedEncumbrance = blocker.getClass().getNormalizedEncumbrance(blocker); normalizedEncumbrance = std::min(1.f, normalizedEncumbrance); float fatigueLoss = fFatigueBlockBase + normalizedEncumbrance * fFatigueBlockMult; - fatigueLoss += weapon.getClass().getWeight(weapon) * attackerStats.getAttackStrength() * fWeaponFatigueBlockMult; + if (!weapon.isEmpty()) + fatigueLoss += weapon.getClass().getWeight(weapon) * attackerStats.getAttackStrength() * fWeaponFatigueBlockMult; fatigue.setCurrent(fatigue.getCurrent() - fatigueLoss); blockerStats.setFatigue(fatigue); From f931ba2efc64af5914136e2ea320cf7d2d92e4f8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 18 Dec 2014 03:24:10 +0100 Subject: [PATCH 0091/3725] Fix some static analysis issues (coverity) --- apps/bsatool/bsatool.cpp | 43 +++--- apps/esmtool/esmtool.cpp | 34 +++-- apps/launcher/main.cpp | 80 ++++++----- apps/mwiniimporter/main.cpp | 130 +++++++++--------- apps/opencs/main.cpp | 66 +++++---- apps/opencs/view/doc/filedialog.cpp | 2 +- apps/opencs/view/render/cell.cpp | 16 +-- apps/opencs/view/render/mousestate.cpp | 2 +- apps/openmw/mwgui/bookpage.cpp | 3 +- apps/openmw/mwgui/class.cpp | 1 + apps/openmw/mwgui/itemview.cpp | 2 +- apps/openmw/mwgui/mainmenu.cpp | 13 +- apps/openmw/mwgui/savegamedialog.cpp | 2 +- apps/openmw/mwgui/spellmodel.hpp | 1 + apps/openmw/mwgui/windowmanagerimp.cpp | 13 +- apps/openmw/mwmechanics/alchemy.cpp | 3 +- apps/openmw/mwmechanics/character.cpp | 7 +- apps/openmw/mwmechanics/spellcasting.cpp | 7 +- apps/openmw/mwrender/characterpreview.cpp | 5 +- apps/openmw/mwrender/localmap.cpp | 5 +- apps/openmw/mwrender/sky.cpp | 3 +- apps/openmw/mwworld/physicssystem.cpp | 5 +- apps/openmw/mwworld/store.hpp | 24 ++-- apps/openmw/mwworld/worldimp.cpp | 4 +- .../contentselector/model/contentmodel.cpp | 7 - components/contentselector/view/combobox.cpp | 2 +- components/esm/loadcell.cpp | 2 + components/nifogre/ogrenifloader.cpp | 2 + components/to_utf8/to_utf8.cpp | 2 + .../oics/ICSInputControlSystem_joystick.cpp | 2 +- extern/sdl4ogre/sdlinputwrapper.cpp | 6 +- 31 files changed, 268 insertions(+), 226 deletions(-) diff --git a/apps/bsatool/bsatool.cpp b/apps/bsatool/bsatool.cpp index 7e47d0b8f..5b1f7d6bb 100644 --- a/apps/bsatool/bsatool.cpp +++ b/apps/bsatool/bsatool.cpp @@ -150,34 +150,33 @@ int extractAll(Bsa::BSAFile& bsa, Arguments& info); int main(int argc, char** argv) { - Arguments info; - if(!parseOptions (argc, argv, info)) - return 1; - - // Open file - Bsa::BSAFile bsa; try { + Arguments info; + if(!parseOptions (argc, argv, info)) + return 1; + + // Open file + Bsa::BSAFile bsa; bsa.open(info.filename); + + if (info.mode == "list") + return list(bsa, info); + else if (info.mode == "extract") + return extract(bsa, info); + else if (info.mode == "extractall") + return extractAll(bsa, info); + else + { + std::cout << "Unsupported mode. That is not supposed to happen." << std::endl; + return 1; + } } - catch(std::exception &e) + catch (std::exception& e) { - std::cout << "ERROR reading BSA archive '" << info.filename - << "'\nDetails:\n" << e.what() << std::endl; + std::cerr << "ERROR reading BSA archive\nDetails:\n" << e.what() << std::endl; return 2; } - - if (info.mode == "list") - return list(bsa, info); - else if (info.mode == "extract") - return extract(bsa, info); - else if (info.mode == "extractall") - return extractAll(bsa, info); - else - { - std::cout << "Unsupported mode. That is not supposed to happen." << std::endl; - return 1; - } } int list(Bsa::BSAFile& bsa, Arguments& info) @@ -189,9 +188,11 @@ int list(Bsa::BSAFile& bsa, Arguments& info) if(info.longformat) { // Long format + std::ios::fmtflags f(std::cout.flags()); std::cout << std::setw(50) << std::left << files[i].name; std::cout << std::setw(8) << std::left << std::dec << files[i].fileSize; std::cout << "@ 0x" << std::hex << files[i].offset << std::endl; + std::cout.flags(f); } else std::cout << files[i].name << std::endl; diff --git a/apps/esmtool/esmtool.cpp b/apps/esmtool/esmtool.cpp index ea908590a..a18736bf2 100644 --- a/apps/esmtool/esmtool.cpp +++ b/apps/esmtool/esmtool.cpp @@ -203,19 +203,27 @@ int comp(Arguments& info); int main(int argc, char**argv) { - Arguments info; - if(!parseOptions (argc, argv, info)) - return 1; - - if (info.mode == "dump") - return load(info); - else if (info.mode == "clone") - return clone(info); - else if (info.mode == "comp") - return comp(info); - else + try + { + Arguments info; + if(!parseOptions (argc, argv, info)) + return 1; + + if (info.mode == "dump") + return load(info); + else if (info.mode == "clone") + return clone(info); + else if (info.mode == "comp") + return comp(info); + else + { + std::cout << "Invalid or no mode specified, dying horribly. Have a nice day." << std::endl; + return 1; + } + } + catch (std::exception& e) { - std::cout << "Invalid or no mode specified, dying horribly. Have a nice day." << std::endl; + std::cerr << "ERROR: " << e.what() << std::endl; return 1; } @@ -273,8 +281,10 @@ void printRaw(ESM::ESMReader &esm) esm.getSubName(); esm.skipHSub(); n = esm.retSubName(); + std::ios::fmtflags f(std::cout.flags()); std::cout << " " << n.toString() << " - " << esm.getSubSize() << " bytes @ 0x" << std::hex << offs << "\n"; + std::cout.flags(f); } } } diff --git a/apps/launcher/main.cpp b/apps/launcher/main.cpp index 562f5c779..3dc82bc54 100644 --- a/apps/launcher/main.cpp +++ b/apps/launcher/main.cpp @@ -15,53 +15,61 @@ int main(int argc, char *argv[]) { - SDL_SetHint(SDL_HINT_RENDER_DRIVER, "software"); - SDL_SetMainReady(); - if (SDL_Init(SDL_INIT_VIDEO) != 0) + try { - qDebug() << "SDL_Init failed: " << QString::fromStdString(SDL_GetError()); - return 0; - } + SDL_SetHint(SDL_HINT_RENDER_DRIVER, "software"); + SDL_SetMainReady(); + if (SDL_Init(SDL_INIT_VIDEO) != 0) + { + qDebug() << "SDL_Init failed: " << QString::fromStdString(SDL_GetError()); + return 0; + } - QApplication app(argc, argv); + QApplication app(argc, argv); - // Now we make sure the current dir is set to application path - QDir dir(QCoreApplication::applicationDirPath()); + // Now we make sure the current dir is set to application path + QDir dir(QCoreApplication::applicationDirPath()); - #ifdef Q_OS_MAC - if (dir.dirName() == "MacOS") { - dir.cdUp(); - dir.cdUp(); - dir.cdUp(); - } + #ifdef Q_OS_MAC + if (dir.dirName() == "MacOS") { + dir.cdUp(); + dir.cdUp(); + dir.cdUp(); + } - // force Qt to load only LOCAL plugins, don't touch system Qt installation - QDir pluginsPath(QCoreApplication::applicationDirPath()); - pluginsPath.cdUp(); - pluginsPath.cd("Plugins"); + // force Qt to load only LOCAL plugins, don't touch system Qt installation + QDir pluginsPath(QCoreApplication::applicationDirPath()); + pluginsPath.cdUp(); + pluginsPath.cd("Plugins"); - QStringList libraryPaths; - libraryPaths << pluginsPath.path() << QCoreApplication::applicationDirPath(); - app.setLibraryPaths(libraryPaths); - #endif + QStringList libraryPaths; + libraryPaths << pluginsPath.path() << QCoreApplication::applicationDirPath(); + app.setLibraryPaths(libraryPaths); + #endif - QDir::setCurrent(dir.absolutePath()); + QDir::setCurrent(dir.absolutePath()); - // Support non-latin characters - QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8")); + // Support non-latin characters + QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8")); - Launcher::MainDialog mainWin; + Launcher::MainDialog mainWin; - if (!mainWin.showFirstRunDialog()) - return 0; + if (!mainWin.showFirstRunDialog()) + return 0; -// if (!mainWin.setup()) { -// return 0; -// } + // if (!mainWin.setup()) { + // return 0; + // } - mainWin.show(); + mainWin.show(); - int returnValue = app.exec(); - SDL_Quit(); - return returnValue; + int returnValue = app.exec(); + SDL_Quit(); + return returnValue; + } + catch (std::exception& e) + { + std::cerr << "ERROR: " << e.what() << std::endl; + return 0; + } } diff --git a/apps/mwiniimporter/main.cpp b/apps/mwiniimporter/main.cpp index fdf6db804..316737c1d 100644 --- a/apps/mwiniimporter/main.cpp +++ b/apps/mwiniimporter/main.cpp @@ -56,93 +56,87 @@ int wmain(int argc, wchar_t *wargv[]) { char **argv = converter.get(); boost::filesystem::path::imbue(boost::locale::generator().generate("")); #endif - bpo::options_description desc("Syntax: mwiniimporter inifile configfile\nAllowed options"); - bpo::positional_options_description p_desc; - desc.add_options() - ("help,h", "produce help message") - ("verbose,v", "verbose output") - ("ini,i", bpo::value(), "morrowind.ini file") - ("cfg,c", bpo::value(), "openmw.cfg file") - ("output,o", bpo::value()->default_value(""), "openmw.cfg file") - ("game-files,g", "import esm and esp files") - ("no-archives,A", "disable bsa archives import") - ("encoding,e", bpo::value()-> default_value("win1252"), - "Character encoding used in OpenMW game messages:\n" - "\n\twin1250 - Central and Eastern European such as Polish, Czech, Slovak, Hungarian, Slovene, Bosnian, Croatian, Serbian (Latin script), Romanian and Albanian languages\n" - "\n\twin1251 - Cyrillic alphabet such as Russian, Bulgarian, Serbian Cyrillic and other languages\n" - "\n\twin1252 - Western European (Latin) alphabet, used by default") - ; - p_desc.add("ini", 1).add("cfg", 1); - - bpo::variables_map vm; - + try { + bpo::options_description desc("Syntax: mwiniimporter inifile configfile\nAllowed options"); + bpo::positional_options_description p_desc; + desc.add_options() + ("help,h", "produce help message") + ("verbose,v", "verbose output") + ("ini,i", bpo::value(), "morrowind.ini file") + ("cfg,c", bpo::value(), "openmw.cfg file") + ("output,o", bpo::value()->default_value(""), "openmw.cfg file") + ("game-files,g", "import esm and esp files") + ("no-archives,A", "disable bsa archives import") + ("encoding,e", bpo::value()-> default_value("win1252"), + "Character encoding used in OpenMW game messages:\n" + "\n\twin1250 - Central and Eastern European such as Polish, Czech, Slovak, Hungarian, Slovene, Bosnian, Croatian, Serbian (Latin script), Romanian and Albanian languages\n" + "\n\twin1251 - Cyrillic alphabet such as Russian, Bulgarian, Serbian Cyrillic and other languages\n" + "\n\twin1252 - Western European (Latin) alphabet, used by default") + ; + p_desc.add("ini", 1).add("cfg", 1); + + bpo::variables_map vm; + bpo::parsed_options parsed = bpo::command_line_parser(argc, argv) .options(desc) .positional(p_desc) .run(); bpo::store(parsed, vm); - } - catch(boost::program_options::unknown_option & x) - { - std::cerr << "ERROR: " << x.what() << std::endl; - return false; - } - catch(boost::program_options::invalid_command_line_syntax & x) - { - std::cerr << "ERROR: " << x.what() << std::endl; - return false; - } - - if(vm.count("help") || !vm.count("ini") || !vm.count("cfg")) { - std::cout << desc; - return 0; - } - bpo::notify(vm); + if(vm.count("help") || !vm.count("ini") || !vm.count("cfg")) { + std::cout << desc; + return 0; + } - std::string iniFile = vm["ini"].as(); - std::string cfgFile = vm["cfg"].as(); + bpo::notify(vm); - // if no output is given, write back to cfg file - std::string outputFile(vm["output"].as()); - if(vm["output"].defaulted()) { - outputFile = vm["cfg"].as(); - } + std::string iniFile = vm["ini"].as(); + std::string cfgFile = vm["cfg"].as(); - if(!boost::filesystem::exists(iniFile)) { - std::cerr << "ini file does not exist" << std::endl; - return -3; - } - if(!boost::filesystem::exists(cfgFile)) - std::cerr << "cfg file does not exist" << std::endl; + // if no output is given, write back to cfg file + std::string outputFile(vm["output"].as()); + if(vm["output"].defaulted()) { + outputFile = vm["cfg"].as(); + } - MwIniImporter importer; - importer.setVerbose(vm.count("verbose")); + if(!boost::filesystem::exists(iniFile)) { + std::cerr << "ini file does not exist" << std::endl; + return -3; + } + if(!boost::filesystem::exists(cfgFile)) + std::cerr << "cfg file does not exist" << std::endl; - // Font encoding settings - std::string encoding(vm["encoding"].as()); - importer.setInputEncoding(ToUTF8::calculateEncoding(encoding)); + MwIniImporter importer; + importer.setVerbose(vm.count("verbose")); - MwIniImporter::multistrmap ini = importer.loadIniFile(iniFile); - MwIniImporter::multistrmap cfg = importer.loadCfgFile(cfgFile); + // Font encoding settings + std::string encoding(vm["encoding"].as()); + importer.setInputEncoding(ToUTF8::calculateEncoding(encoding)); - importer.merge(cfg, ini); - importer.mergeFallback(cfg, ini); + MwIniImporter::multistrmap ini = importer.loadIniFile(iniFile); + MwIniImporter::multistrmap cfg = importer.loadCfgFile(cfgFile); - if(vm.count("game-files")) { - importer.importGameFiles(cfg, ini); - } + importer.merge(cfg, ini); + importer.mergeFallback(cfg, ini); - if(!vm.count("no-archives")) { - importer.importArchives(cfg, ini); - } + if(vm.count("game-files")) { + importer.importGameFiles(cfg, ini); + } - std::cout << "write to: " << outputFile << std::endl; - bfs::ofstream file((bfs::path(outputFile))); - importer.writeToFile(file, cfg); + if(!vm.count("no-archives")) { + importer.importArchives(cfg, ini); + } + std::cout << "write to: " << outputFile << std::endl; + bfs::ofstream file((bfs::path(outputFile))); + importer.writeToFile(file, cfg); + } + catch (std::exception& e) + { + std::cerr << "ERROR: " << e.what() << std::endl; + } return 0; } diff --git a/apps/opencs/main.cpp b/apps/opencs/main.cpp index dd20324d1..0b8da61ef 100644 --- a/apps/opencs/main.cpp +++ b/apps/opencs/main.cpp @@ -46,47 +46,55 @@ class Application : public QApplication int main(int argc, char *argv[]) { - Q_INIT_RESOURCE (resources); + try + { + Q_INIT_RESOURCE (resources); - qRegisterMetaType ("std::string"); - qRegisterMetaType ("CSMWorld::UniversalId"); + qRegisterMetaType ("std::string"); + qRegisterMetaType ("CSMWorld::UniversalId"); - OgreInit::OgreInit ogreInit; + OgreInit::OgreInit ogreInit; - std::auto_ptr shinyFactory; + std::auto_ptr shinyFactory; - Application application (argc, argv); + Application application (argc, argv); -#ifdef Q_OS_MAC - QDir dir(QCoreApplication::applicationDirPath()); - if (dir.dirName() == "MacOS") { - dir.cdUp(); - dir.cdUp(); - dir.cdUp(); - } - QDir::setCurrent(dir.absolutePath()); + #ifdef Q_OS_MAC + QDir dir(QCoreApplication::applicationDirPath()); + if (dir.dirName() == "MacOS") { + dir.cdUp(); + dir.cdUp(); + dir.cdUp(); + } + QDir::setCurrent(dir.absolutePath()); - // force Qt to load only LOCAL plugins, don't touch system Qt installation - QDir pluginsPath(QCoreApplication::applicationDirPath()); - pluginsPath.cdUp(); - pluginsPath.cd("Plugins"); + // force Qt to load only LOCAL plugins, don't touch system Qt installation + QDir pluginsPath(QCoreApplication::applicationDirPath()); + pluginsPath.cdUp(); + pluginsPath.cd("Plugins"); - QStringList libraryPaths; - libraryPaths << pluginsPath.path() << QCoreApplication::applicationDirPath(); - application.setLibraryPaths(libraryPaths); -#endif + QStringList libraryPaths; + libraryPaths << pluginsPath.path() << QCoreApplication::applicationDirPath(); + application.setLibraryPaths(libraryPaths); + #endif - application.setWindowIcon (QIcon (":./opencs.png")); + application.setWindowIcon (QIcon (":./opencs.png")); - CS::Editor editor (ogreInit); + CS::Editor editor (ogreInit); - if(!editor.makeIPCServer()) + if(!editor.makeIPCServer()) + { + editor.connectToIPCServer(); + return 0; + } + + shinyFactory = editor.setupGraphics(); + return editor.run(); + } + catch (std::exception& e) { - editor.connectToIPCServer(); + std::cerr << "ERROR: " << e.what() << std::endl; return 0; } - shinyFactory = editor.setupGraphics(); - - return editor.run(); } diff --git a/apps/opencs/view/doc/filedialog.cpp b/apps/opencs/view/doc/filedialog.cpp index 300656f33..c6f76cddf 100644 --- a/apps/opencs/view/doc/filedialog.cpp +++ b/apps/opencs/view/doc/filedialog.cpp @@ -18,7 +18,7 @@ #include "adjusterwidget.hpp" CSVDoc::FileDialog::FileDialog(QWidget *parent) : - QDialog(parent), mSelector (0), mFileWidget (0), mAdjusterWidget (0), mDialogBuilt(false) + QDialog(parent), mSelector (0), mFileWidget (0), mAdjusterWidget (0), mDialogBuilt(false), mAction(ContentAction_Undefined) { ui.setupUi (this); resize(400, 400); diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index 1fb7809be..a0d0f6e71 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -61,7 +61,7 @@ bool CSVRender::Cell::addObjects (int start, int end) CSVRender::Cell::Cell (CSMWorld::Data& data, Ogre::SceneManager *sceneManager, const std::string& id, boost::shared_ptr physics, const Ogre::Vector3& origin) -: mData (data), mId (Misc::StringUtils::lowerCase (id)), mSceneMgr(sceneManager), mPhysics(physics) +: mData (data), mId (Misc::StringUtils::lowerCase (id)), mSceneMgr(sceneManager), mPhysics(physics), mX(0), mY(0) { mCellNode = sceneManager->getRootSceneNode()->createChildSceneNode(); mCellNode->setPosition (origin); @@ -77,15 +77,14 @@ CSVRender::Cell::Cell (CSMWorld::Data& data, Ogre::SceneManager *sceneManager, int landIndex = land.searchId(mId); if (landIndex != -1) { - mTerrain.reset(new Terrain::TerrainGrid(sceneManager, new TerrainStorage(mData), Element_Terrain, true, - Terrain::Align_XY)); - const ESM::Land* esmLand = land.getRecord(mId).get().mLand.get(); - mTerrain->loadCell(esmLand->mX, - esmLand->mY); - if(esmLand) { + mTerrain.reset(new Terrain::TerrainGrid(sceneManager, new TerrainStorage(mData), Element_Terrain, true, + Terrain::Align_XY)); + mTerrain->loadCell(esmLand->mX, + esmLand->mY); + float verts = ESM::Land::LAND_SIZE; float worldsize = ESM::Land::REAL_SIZE; mX = esmLand->mX; @@ -98,7 +97,8 @@ CSVRender::Cell::Cell (CSMWorld::Data& data, Ogre::SceneManager *sceneManager, CSVRender::Cell::~Cell() { - mPhysics->removeHeightField(mSceneMgr, mX, mY); + if (mTerrain.get()) + mPhysics->removeHeightField(mSceneMgr, mX, mY); for (std::map::iterator iter (mObjects.begin()); iter!=mObjects.end(); ++iter) diff --git a/apps/opencs/view/render/mousestate.cpp b/apps/opencs/view/render/mousestate.cpp index 988819fcb..a94f4f8ab 100644 --- a/apps/opencs/view/render/mousestate.cpp +++ b/apps/opencs/view/render/mousestate.cpp @@ -346,7 +346,7 @@ namespace CSVRender //plane X, upvector Y, mOffset x : x-z plane, wheel closer/further std::pair MouseState::planeAxis() { - bool screenCoord = true; + const bool screenCoord = true; Ogre::Vector3 dir = getCamera()->getDerivedDirection(); QString wheelDir = "Closer/Further"; diff --git a/apps/openmw/mwgui/bookpage.cpp b/apps/openmw/mwgui/bookpage.cpp index 57cb3e7a9..0f2df494a 100644 --- a/apps/openmw/mwgui/bookpage.cpp +++ b/apps/openmw/mwgui/bookpage.cpp @@ -639,7 +639,8 @@ namespace MyGUI::Vertex* vertices, RenderXform const & renderXform) : mZ(Z), mOrigin (left, top), mFont (font), mVertices (vertices), - mRenderXform (renderXform) + mRenderXform (renderXform), + mC(0) { mVertexColourType = MyGUI::RenderManager::getInstance().getVertexFormat(); } diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index 4e45f1a7c..62167142f 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -770,6 +770,7 @@ namespace MWGui SelectSkillDialog::SelectSkillDialog() : WindowModal("openmw_chargen_select_skill.layout") + , mSkillId(ESM::Skill::Block) { // Centre dialog center(); diff --git a/apps/openmw/mwgui/itemview.cpp b/apps/openmw/mwgui/itemview.cpp index ed2002d72..b4ce97924 100644 --- a/apps/openmw/mwgui/itemview.cpp +++ b/apps/openmw/mwgui/itemview.cpp @@ -60,7 +60,7 @@ void ItemView::layoutWidgets() int rows = maxHeight/42; rows = std::max(rows, 1); - bool showScrollbar = std::ceil(dragArea->getChildCount()/float(rows)) > mScrollView->getWidth()/42; + bool showScrollbar = int(std::ceil(dragArea->getChildCount()/float(rows))) > mScrollView->getWidth()/42; if (showScrollbar) maxHeight -= 18; diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index bb003c481..f1e7b4fc5 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -176,13 +176,16 @@ namespace MWGui int screenHeight = viewSize.height; mVideoBackground->setSize(screenWidth, screenHeight); - double imageaspect = static_cast(mVideo->getVideoWidth())/mVideo->getVideoHeight(); + if (mVideo->getVideoHeight() > 0) + { + double imageaspect = static_cast(mVideo->getVideoWidth())/mVideo->getVideoHeight(); - int leftPadding = std::max(0.0, (screenWidth - screenHeight * imageaspect) / 2); - int topPadding = std::max(0.0, (screenHeight - screenWidth / imageaspect) / 2); + int leftPadding = std::max(0.0, (screenWidth - screenHeight * imageaspect) / 2); + int topPadding = std::max(0.0, (screenHeight - screenWidth / imageaspect) / 2); - mVideo->setCoord(leftPadding, topPadding, - screenWidth - leftPadding*2, screenHeight - topPadding*2); + mVideo->setCoord(leftPadding, topPadding, + screenWidth - leftPadding*2, screenHeight - topPadding*2); + } mVideo->setVisible(true); } diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index 66c7a9238..72f242bdb 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -304,7 +304,7 @@ namespace MWGui mOkButton->setEnabled(pos != MyGUI::ITEM_NONE || mSaving); mDeleteButton->setEnabled(pos != MyGUI::ITEM_NONE); - if (pos == MyGUI::ITEM_NONE) + if (pos == MyGUI::ITEM_NONE || !mCurrentCharacter) { mCurrentSlot = NULL; mInfoText->setCaption(""); diff --git a/apps/openmw/mwgui/spellmodel.hpp b/apps/openmw/mwgui/spellmodel.hpp index 1f7a0cb7c..7859c8a7b 100644 --- a/apps/openmw/mwgui/spellmodel.hpp +++ b/apps/openmw/mwgui/spellmodel.hpp @@ -26,6 +26,7 @@ namespace MWGui Spell() : mSelected(false) , mActive(false) + , mType(Type_Spell) { } }; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 9d24fb19b..72805dd31 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1691,13 +1691,16 @@ namespace MWGui // Use black bars to correct aspect ratio mVideoBackground->setSize(screenWidth, screenHeight); - double imageaspect = static_cast(mVideoWidget->getVideoWidth())/mVideoWidget->getVideoHeight(); + if (mVideoWidget->getVideoHeight() > 0) + { + double imageaspect = static_cast(mVideoWidget->getVideoWidth())/mVideoWidget->getVideoHeight(); - int leftPadding = std::max(0.0, (screenWidth - screenHeight * imageaspect) / 2); - int topPadding = std::max(0.0, (screenHeight - screenWidth / imageaspect) / 2); + int leftPadding = std::max(0.0, (screenWidth - screenHeight * imageaspect) / 2); + int topPadding = std::max(0.0, (screenHeight - screenWidth / imageaspect) / 2); - mVideoWidget->setCoord(leftPadding, topPadding, - screenWidth - leftPadding*2, screenHeight - topPadding*2); + mVideoWidget->setCoord(leftPadding, topPadding, + screenWidth - leftPadding*2, screenHeight - topPadding*2); + } } WindowModal* WindowManager::getCurrentModal() const diff --git a/apps/openmw/mwmechanics/alchemy.cpp b/apps/openmw/mwmechanics/alchemy.cpp index da2492a77..f3d376a70 100644 --- a/apps/openmw/mwmechanics/alchemy.cpp +++ b/apps/openmw/mwmechanics/alchemy.cpp @@ -286,7 +286,8 @@ void MWMechanics::Alchemy::addPotion (const std::string& name) if (!iter->isEmpty()) newRecord.mData.mWeight += iter->get()->mBase->mData.mWeight; - newRecord.mData.mWeight /= countIngredients(); + if (countIngredients() > 0) + newRecord.mData.mWeight /= countIngredients(); newRecord.mData.mValue = mValue; newRecord.mData.mAutoCalc = 0; diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index d675b0157..6f092f5a4 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1644,7 +1644,7 @@ void CharacterController::update(float duration) world->queueMovement(mPtr, Ogre::Vector3(0.0f)); } - if(mAnimation && !mSkipAnim) + if(!mSkipAnim) { Ogre::Vector3 moved = mAnimation->runAnimation(duration); if(duration > 0.0f) @@ -1762,10 +1762,7 @@ bool CharacterController::kill() playRandomDeath(); - if(mAnimation) - { - mAnimation->disable(mCurrentIdle); - } + mAnimation->disable(mCurrentIdle); mIdleState = CharState_None; mCurrentIdle.clear(); diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index d33bb6ad1..a831cc8bb 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -687,12 +687,11 @@ namespace MWMechanics // Failure sound int school = 0; - for (std::vector::const_iterator effectIt (enchantment->mEffects.mList.begin()); - effectIt!=enchantment->mEffects.mList.end(); ++effectIt) + if (!enchantment->mEffects.mList.empty()) { - const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get().find(effectIt->mEffectID); + short effectId = enchantment->mEffects.mList.front().mEffectID; + const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get().find(effectId); school = magicEffect->mData.mSchool; - break; } static const std::string schools[] = { "alteration", "conjuration", "destruction", "illusion", "mysticism", "restoration" diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 66052a96e..8d693e966 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -330,7 +330,10 @@ namespace MWRender void RaceSelectionPreview::updateCamera() { Ogre::Vector3 scale = mNode->getScale(); - Ogre::Vector3 headOffset = mAnimation->getNode("Bip01 Head")->_getDerivedPosition(); + Ogre::Node* headNode = mAnimation->getNode("Bip01 Head"); + if (!headNode) + return; + Ogre::Vector3 headOffset = headNode->_getDerivedPosition(); headOffset = mNode->convertLocalToWorldPosition(headOffset); mCamera->setPosition(headOffset + mPosition * scale); diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index f4388eec5..f8c3a64ef 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -24,8 +24,9 @@ using namespace MWRender; using namespace Ogre; -LocalMap::LocalMap(OEngine::Render::OgreRenderer* rend, MWRender::RenderingManager* rendering) : - mInterior(false) +LocalMap::LocalMap(OEngine::Render::OgreRenderer* rend, MWRender::RenderingManager* rendering) + : mInterior(false) + , mAngle(0.f) { mRendering = rend; mRenderingManager = rendering; diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 184102127..131e12a5c 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -104,7 +104,7 @@ BillboardObject::BillboardObject( const String& textureName, } BillboardObject::BillboardObject() -: mNode(NULL), mMaterial(NULL), mEntity(NULL) +: mNode(NULL), mMaterial(NULL), mEntity(NULL), mVisibility(1.f) { } @@ -186,6 +186,7 @@ Moon::Moon( const String& textureName, SceneNode* rootNode, const std::string& material) : BillboardObject(textureName, initialSize, position, rootNode, material) + , mType(Type_Masser) { setVisibility(1.0); diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index d9941bafd..3879e0cd0 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -283,10 +283,13 @@ namespace MWWorld return position; OEngine::Physic::PhysicActor *physicActor = engine->getCharacter(ptr.getRefData().getHandle()); + if (!physicActor) + return position; + // Reset per-frame data physicActor->setWalkingOnWater(false); /* Anything to collide with? */ - if(!physicActor || !physicActor->getCollisionMode()) + if(!physicActor->getCollisionMode()) { return position + (Ogre::Quaternion(Ogre::Radian(refpos.rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z) * Ogre::Quaternion(Ogre::Radian(refpos.rot[0]), Ogre::Vector3::NEGATIVE_UNIT_X)) diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index a0d34b228..4fa8b7f54 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -630,9 +630,6 @@ namespace MWWorld } const ESM::Cell *searchOrCreate(int x, int y) { - ESM::Cell cell; - cell.mData.mX = x, cell.mData.mY = y; - std::pair key(x, y); DynamicExt::const_iterator it = mExt.find(key); if (it != mExt.end()) { @@ -644,13 +641,15 @@ namespace MWWorld return &dit->second; } - ESM::Cell *newCell = new ESM::Cell; - newCell->mData.mX = x; - newCell->mData.mY = y; - mExt[std::make_pair(x, y)] = *newCell; - delete newCell; - - return &mExt[std::make_pair(x, y)]; + ESM::Cell newCell; + newCell.mData.mX = x; + newCell.mData.mY = y; + newCell.mData.mFlags = ESM::Cell::HasWater; + newCell.mAmbi.mAmbient = 0; + newCell.mAmbi.mSunlight = 0; + newCell.mAmbi.mFog = 0; + newCell.mAmbi.mFogDensity = 0; + return &mExt.insert(std::make_pair(key, newCell)).first->second; } const ESM::Cell *find(const std::string &id) const { @@ -853,6 +852,11 @@ namespace MWWorld public: + Store() + : mCells(NULL) + { + } + void setCells(Store& cells) { mCells = &cells; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 17a45f9f1..a68d72dd4 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2554,7 +2554,7 @@ namespace MWWorld if (!selectedSpell.empty()) { - const ESM::Spell* spell = getStore().get().search(selectedSpell); + const ESM::Spell* spell = getStore().get().find(selectedSpell); // Check mana MWMechanics::DynamicStat magicka = stats.getMagicka(); @@ -2641,7 +2641,7 @@ namespace MWWorld if (!selectedSpell.empty()) { - const ESM::Spell* spell = getStore().get().search(selectedSpell); + const ESM::Spell* spell = getStore().get().find(selectedSpell); // A power can be used once per 24h if (spell->mData.mType == ESM::Spell::ST_Power) diff --git a/components/contentselector/model/contentmodel.cpp b/components/contentselector/model/contentmodel.cpp index 0d4f2365a..d72ba53c0 100644 --- a/components/contentselector/model/contentmodel.cpp +++ b/components/contentselector/model/contentmodel.cpp @@ -177,7 +177,6 @@ QVariant ContentSelectorModel::ContentModel::data(const QModelIndex &index, int return file->fileProperty(static_cast(column)); return QVariant(); - break; } case Qt::TextAlignmentRole: @@ -193,8 +192,6 @@ QVariant ContentSelectorModel::ContentModel::data(const QModelIndex &index, int default: return Qt::AlignLeft + Qt::AlignVCenter; } - return QVariant(); - break; } case Qt::ToolTipRole: @@ -203,7 +200,6 @@ QVariant ContentSelectorModel::ContentModel::data(const QModelIndex &index, int return QVariant(); return file->toolTip(); - break; } case Qt::CheckStateRole: @@ -212,8 +208,6 @@ QVariant ContentSelectorModel::ContentModel::data(const QModelIndex &index, int return QVariant(); return mCheckStates[file->filePath()]; - - break; } case Qt::UserRole: @@ -229,7 +223,6 @@ QVariant ContentSelectorModel::ContentModel::data(const QModelIndex &index, int case Qt::UserRole + 1: return isChecked(file->filePath()); - break; } return QVariant(); } diff --git a/components/contentselector/view/combobox.cpp b/components/contentselector/view/combobox.cpp index 1d773b62d..18cafc2dc 100644 --- a/components/contentselector/view/combobox.cpp +++ b/components/contentselector/view/combobox.cpp @@ -30,7 +30,7 @@ void ContentSelectorView::ComboBox::paintEvent(QPaintEvent *) // draw the icon and text if (!opt.editable && currentIndex() == -1) // <<< we adjust the text displayed when nothing is selected opt.currentText = mPlaceholderText; - painter.drawControl(QStyle::CE_ComboBoxLabel, opt); + painter.drawControl(QStyle::CE_ComboBoxLabel, opt); } void ContentSelectorView::ComboBox::setPlaceholderText(const QString &text) diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index 347f3fde4..e4f847dec 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -242,6 +242,8 @@ bool Cell::getNextMVRF(ESMReader &esm, MovedCellRef &mref) else { id.mWorldspace = Misc::StringUtils::lowerCase (mName); + id.mIndex.mX = 0; + id.mIndex.mY = 0; } return id; diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 22685f548..ef4b9e985 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -928,6 +928,8 @@ class NIFObjectLoader particledata = static_cast(partnode)->data.getPtr(); else if(partnode->recType == Nif::RC_NiRotatingParticles) particledata = static_cast(partnode)->data.getPtr(); + else + throw std::runtime_error("Unexpected particle node type"); std::string fullname = name+"@index="+Ogre::StringConverter::toString(partnode->recIndex); if(partnode->name.length() > 0) diff --git a/components/to_utf8/to_utf8.cpp b/components/to_utf8/to_utf8.cpp index c53cf62b5..cb9680441 100644 --- a/components/to_utf8/to_utf8.cpp +++ b/components/to_utf8/to_utf8.cpp @@ -319,7 +319,9 @@ void Utf8Encoder::copyFromArray2(const char*& chp, char* &out) } } + std::ios::fmtflags f(std::cout.flags()); std::cout << "Could not find glyph " << std::hex << (int)ch << " " << (int)ch2 << " " << (int)ch3 << std::endl; + std::cout.flags(f); *(out++) = ch; // Could not find glyph, just put whatever } diff --git a/extern/oics/ICSInputControlSystem_joystick.cpp b/extern/oics/ICSInputControlSystem_joystick.cpp index 8bf931788..0fcd36bbd 100644 --- a/extern/oics/ICSInputControlSystem_joystick.cpp +++ b/extern/oics/ICSInputControlSystem_joystick.cpp @@ -299,7 +299,7 @@ namespace ICS { if(it->second.find(axis) != it->second.end()) { - mControlsJoystickPOVBinderMap[deviceId].find(index)->second.erase( it->second.find(axis) ); + it->second.erase( it->second.find(axis) ); } } } diff --git a/extern/sdl4ogre/sdlinputwrapper.cpp b/extern/sdl4ogre/sdlinputwrapper.cpp index db46a4af9..0c29be939 100644 --- a/extern/sdl4ogre/sdlinputwrapper.cpp +++ b/extern/sdl4ogre/sdlinputwrapper.cpp @@ -28,7 +28,9 @@ namespace SFO mWantGrab(false), mWantRelative(false), mWantMouseVisible(false), - mAllowGrab(grab) + mAllowGrab(grab), + mWarpX(0), + mWarpY(0) { _setupOISKeys(); } @@ -117,7 +119,9 @@ namespace SFO case SDL_CLIPBOARDUPDATE: break; // We don't need this event, clipboard is retrieved on demand default: + std::ios::fmtflags f(std::cerr.flags()); std::cerr << "Unhandled SDL event of type 0x" << std::hex << evt.type << std::endl; + std::cerr.flags(f); break; } } From a29abb85f19e56175359ea96c29c4d6c668ef155 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 18 Dec 2014 17:05:24 +0100 Subject: [PATCH 0092/3725] Fix ItemView sizing bug --- apps/openmw/mwgui/itemview.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/itemview.cpp b/apps/openmw/mwgui/itemview.cpp index b4ce97924..bf8bf1adf 100644 --- a/apps/openmw/mwgui/itemview.cpp +++ b/apps/openmw/mwgui/itemview.cpp @@ -56,7 +56,7 @@ void ItemView::layoutWidgets() int x = 0; int y = 0; MyGUI::Widget* dragArea = mScrollView->getChildAt(0); - int maxHeight = dragArea->getHeight(); + int maxHeight = mScrollView->getHeight(); int rows = maxHeight/42; rows = std::max(rows, 1); From 8a210c49e995f8fdb89ee99a6e1e9cb536423b36 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 18 Dec 2014 17:12:41 +0100 Subject: [PATCH 0093/3725] Improve AI prioritising health potions --- apps/openmw/mwmechanics/aicombataction.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/aicombataction.cpp b/apps/openmw/mwmechanics/aicombataction.cpp index 9bb495842..175b98001 100644 --- a/apps/openmw/mwmechanics/aicombataction.cpp +++ b/apps/openmw/mwmechanics/aicombataction.cpp @@ -294,7 +294,10 @@ namespace MWMechanics // Effect doesn't heal more than we need, *or* we are below 1/2 health if (current.getModified() - current.getCurrent() > toHeal || current.getCurrent() < current.getModified()*0.5) - return 10000.f * priority; + { + return 10000.f * priority + - (toHeal - (current.getModified()-current.getCurrent())); // prefer the most fitting potion + } else return -10000.f * priority; // Save for later } From 105f0f87169baf5f54f65b56f9793eea299ecf2a Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 18 Dec 2014 17:36:38 +0100 Subject: [PATCH 0094/3725] Head tracking: don't look at dead actors --- apps/openmw/mwmechanics/actors.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 3a9ba5618..abab1f9e5 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -293,6 +293,9 @@ namespace MWMechanics if (sqrDist > maxDistance*maxDistance) return; + if (targetActor.getClass().getCreatureStats(targetActor).isDead()) + return; + // stop tracking when target is behind the actor Ogre::Vector3 actorDirection (actor.getRefData().getBaseNode()->getOrientation().yAxis()); Ogre::Vector3 targetDirection (Ogre::Vector3(actor2Pos.pos) - Ogre::Vector3(actor1Pos.pos)); From 4aed5158cc1fba40a6eb807ae895d0ba4e4295c6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 18 Dec 2014 17:48:46 +0100 Subject: [PATCH 0095/3725] Support region names in cell dialogue filter (Fixes #2113) --- apps/openmw/mwdialogue/filter.cpp | 5 +++-- apps/openmw/mwscript/cellextensions.cpp | 13 ++----------- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index af8a5754f..2d55069e9 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -126,7 +126,7 @@ bool MWDialogue::Filter::testPlayer (const ESM::DialInfo& info) const if (!info.mCell.empty()) { // supports partial matches, just like getPcCell - const std::string& playerCell = player.getCell()->getCell()->mName; + const std::string& playerCell = MWBase::Environment::get().getWorld()->getCellName(player.getCell()); bool match = playerCell.length()>=info.mCell.length() && Misc::StringUtils::ciEqual(playerCell.substr (0, info.mCell.length()), info.mCell); if (!match) @@ -451,7 +451,8 @@ bool MWDialogue::Filter::getSelectStructBoolean (const SelectWrapper& select) co case SelectWrapper::Function_NotCell: - return !Misc::StringUtils::ciEqual(mActor.getCell()->getCell()->mName, select.getName()); + return !Misc::StringUtils::ciEqual(MWBase::Environment::get().getWorld()->getCellName(mActor.getCell()) + , select.getName()); case SelectWrapper::Function_NotLocal: { diff --git a/apps/openmw/mwscript/cellextensions.cpp b/apps/openmw/mwscript/cellextensions.cpp index a568b7943..43d213c5a 100644 --- a/apps/openmw/mwscript/cellextensions.cpp +++ b/apps/openmw/mwscript/cellextensions.cpp @@ -117,18 +117,9 @@ namespace MWScript runtime.push(0); return; } - const ESM::Cell *cell = MWBase::Environment::get().getWorld()->getPlayerPtr().getCell()->getCell(); + const MWWorld::CellStore *cell = MWBase::Environment::get().getWorld()->getPlayerPtr().getCell(); - std::string current = cell->mName; - - if (!(cell->mData.mFlags & ESM::Cell::Interior) && current.empty() - && !cell->mRegion.empty()) - { - const ESM::Region *region = - MWBase::Environment::get().getWorld()->getStore().get().find (cell->mRegion); - - current = region->mName; - } + std::string current = MWBase::Environment::get().getWorld()->getCellName(cell); Misc::StringUtils::toLower(current); bool match = current.length()>=name.length() && From 35d2bfabcaee786257fd83a2573e11ec94b5f674 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 18 Dec 2014 18:02:09 +0100 Subject: [PATCH 0096/3725] Adjust NPC response to pickpocket attempts (Fixes #2219) --- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 520b6b8a7..d43ca61f1 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1053,7 +1053,7 @@ namespace MWMechanics if (type == OT_Trespassing || type == OT_SleepingInOwnedBed) fight = esmStore.get().find("iFightTrespass")->getInt(); else if (type == OT_Pickpocket) - fight = esmStore.get().find("iFightPickpocket")->getInt(); + fight = esmStore.get().find("iFightPickpocket")->getInt() * 4; // *4 according to research wiki else if (type == OT_Assault) // Note: iFightAttack is for the victim, iFightAttacking for witnesses? fight = esmStore.get().find("iFightAttack")->getInt(); else if (type == OT_Murder) From efa9ff3a76bbe319055822d233be8f7cd087716d Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 18 Dec 2014 18:08:51 +0100 Subject: [PATCH 0097/3725] Fix incorrect implementation of iWerewolfBounty --- apps/openmw/mwmechanics/npcstats.cpp | 8 ++------ apps/openmw/mwworld/worldimp.cpp | 14 ++++++++++---- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index 13fc14318..ec7b232a2 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -336,16 +336,12 @@ bool MWMechanics::NpcStats::hasBeenUsed (const std::string& id) const int MWMechanics::NpcStats::getBounty() const { - if (mIsWerewolf) - return MWBase::Environment::get().getWorld()->getStore().get().find("iWereWolfBounty")->getInt(); - else - return mBounty; + return mBounty; } void MWMechanics::NpcStats::setBounty (int bounty) { - if (!mIsWerewolf) - mBounty = bounty; + mBounty = bounty; } int MWMechanics::NpcStats::getFactionReputation (const std::string& faction) const diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index a68d72dd4..d370ad453 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2476,7 +2476,7 @@ namespace MWWorld getStore().get().search("fAlarmRadius")->getFloat(), closeActors); - bool detected = false; + bool detected = false, reported = false; for (std::vector::const_iterator it = closeActors.begin(); it != closeActors.end(); ++it) { if (*it == actor) @@ -2486,16 +2486,22 @@ namespace MWWorld continue; if (getLOS(*it, actor) && MWBase::Environment::get().getMechanicsManager()->awarenessCheck(actor, *it)) - { detected = true; - break; - } + if (it->getClass().getCreatureStats(*it).getAiSetting(MWMechanics::CreatureStats::AI_Alarm).getModified() > 0) + reported = true; } if (detected) { windowManager->messageBox("#{sWerewolfAlarmMessage}"); setGlobalInt("pcknownwerewolf", 1); + + if (reported) + { + npcStats.setBounty(npcStats.getBounty()+ + MWBase::Environment::get().getWorld()->getStore().get().find("iWereWolfBounty")->getInt()); + windowManager->messageBox("#{sCrimeMessage}"); + } } } } From cc9af9562b7157943968d396d18c57d5348915f7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 18 Dec 2014 18:33:14 +0100 Subject: [PATCH 0098/3725] Function_CreatureTargetted should return '2' for werewolfs This makes NPCs say the correct attack voice files when fighting a werewolf. --- apps/openmw/mwdialogue/filter.cpp | 19 +++++++++++++++---- apps/openmw/mwdialogue/selectwrapper.cpp | 2 +- apps/openmw/mwmechanics/creaturestats.cpp | 10 ---------- apps/openmw/mwmechanics/creaturestats.hpp | 2 -- 4 files changed, 16 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index 2d55069e9..7c67cdc5c 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -417,6 +417,21 @@ int MWDialogue::Filter::getSelectStructInteger (const SelectWrapper& select) con return value; } + case SelectWrapper::Function_CreatureTargetted: + + { + MWWorld::Ptr target; + mActor.getClass().getCreatureStats(mActor).getAiSequence().getCombatTarget(target); + if (target) + { + if (target.getClass().isNpc() && target.getClass().getNpcStats(target).isWerewolf()) + return 2; + if (target.getTypeName() == typeid(ESM::Creature).name()) + return 1; + } + } + return 0; + default: throw std::runtime_error ("unknown integer select function"); @@ -532,10 +547,6 @@ bool MWDialogue::Filter::getSelectStructBoolean (const SelectWrapper& select) co return MWBase::Environment::get().getMechanicsManager()->isAggressive(mActor, MWBase::Environment::get().getWorld()->getPlayerPtr()); - case SelectWrapper::Function_CreatureTargetted: - - return mActor.getClass().getCreatureStats (mActor).getCreatureTargetted(); - case SelectWrapper::Function_Werewolf: return mActor.getClass().getNpcStats (mActor).isWerewolf(); diff --git a/apps/openmw/mwdialogue/selectwrapper.cpp b/apps/openmw/mwdialogue/selectwrapper.cpp index 3f22998f0..fa0fbfe13 100644 --- a/apps/openmw/mwdialogue/selectwrapper.cpp +++ b/apps/openmw/mwdialogue/selectwrapper.cpp @@ -205,6 +205,7 @@ MWDialogue::SelectWrapper::Type MWDialogue::SelectWrapper::getType() const Function_Reputation, Function_FactionRankDiff, Function_WerewolfKills, Function_RankLow, Function_RankHigh, + Function_CreatureTargetted, Function_None // end marker }; @@ -225,7 +226,6 @@ MWDialogue::SelectWrapper::Type MWDialogue::SelectWrapper::getType() const Function_PcVampire, Function_TalkedToPc, Function_Alarmed, Function_Detected, Function_Attacked, Function_ShouldAttack, - Function_CreatureTargetted, Function_Werewolf, Function_None // end marker }; diff --git a/apps/openmw/mwmechanics/creaturestats.cpp b/apps/openmw/mwmechanics/creaturestats.cpp index 72a710c65..ac6f88d44 100644 --- a/apps/openmw/mwmechanics/creaturestats.cpp +++ b/apps/openmw/mwmechanics/creaturestats.cpp @@ -329,16 +329,6 @@ namespace MWMechanics mAttacked = attacked; } - bool CreatureStats::getCreatureTargetted() const - { - MWWorld::Ptr targetPtr; - if (mAiSequence.getCombatTarget(targetPtr)) - { - return targetPtr.getTypeName() == typeid(ESM::Creature).name(); - } - return false; - } - float CreatureStats::getEvasion() const { float evasion = (getAttribute(ESM::Attribute::Agility).getModified() / 5.0f) + diff --git a/apps/openmw/mwmechanics/creaturestats.hpp b/apps/openmw/mwmechanics/creaturestats.hpp index d13ced3b3..9a08b58c9 100644 --- a/apps/openmw/mwmechanics/creaturestats.hpp +++ b/apps/openmw/mwmechanics/creaturestats.hpp @@ -199,8 +199,6 @@ namespace MWMechanics bool getAttacked() const; void setAttacked (bool attacked); - bool getCreatureTargetted() const; - float getEvasion() const; void setKnockedDown(bool value); From 191032746934a3a1df309eecda181f216cc0a554 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 18 Dec 2014 22:27:09 +0100 Subject: [PATCH 0099/3725] Implement disposition changes due to crimes --- .../mwmechanics/mechanicsmanagerimp.cpp | 48 ++++++++++++++----- 1 file changed, 35 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index d43ca61f1..720f0c4f5 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1001,16 +1001,31 @@ namespace MWMechanics victim.getClass().getCreatureStats(victim).notifyMurder(); // Bounty for each type of crime + float dispTerm = 0.f, dispTermVictim = 0.f; if (type == OT_Trespassing || type == OT_SleepingInOwnedBed) + { arg = store.find("iCrimeTresspass")->getInt(); + dispTerm = dispTermVictim = store.find("iDispTresspass")->getInt(); + } else if (type == OT_Pickpocket) + { arg = store.find("iCrimePickPocket")->getInt(); + dispTerm = dispTermVictim = store.find("fDispPickPocketMod")->getFloat(); + } else if (type == OT_Assault) + { arg = store.find("iCrimeAttack")->getInt(); + dispTerm = store.find("fDispAttacking")->getFloat(); + dispTermVictim = store.find("iDispAttackMod")->getInt(); + } else if (type == OT_Murder) + { arg = store.find("iCrimeKilling")->getInt(); + dispTerm = dispTermVictim = store.find("iDispKilling")->getInt(); + } else if (type == OT_Theft) { + dispTerm = dispTermVictim = store.find("fDispStealing")->getFloat() * arg; arg *= store.find("fCrimeStealing")->getFloat(); arg = std::max(1, arg); // Minimum bounty of 1, in case items with zero value are stolen } @@ -1049,19 +1064,23 @@ namespace MWMechanics // What amount of provocation did this crime generate? // Controls whether witnesses will engage combat with the criminal. - int fight = 0; + int fight = 0, fightVictim = 0; if (type == OT_Trespassing || type == OT_SleepingInOwnedBed) - fight = esmStore.get().find("iFightTrespass")->getInt(); + fight = fightVictim = esmStore.get().find("iFightTrespass")->getInt(); else if (type == OT_Pickpocket) - fight = esmStore.get().find("iFightPickpocket")->getInt() * 4; // *4 according to research wiki - else if (type == OT_Assault) // Note: iFightAttack is for the victim, iFightAttacking for witnesses? + { + fight = esmStore.get().find("iFightPickpocket")->getInt(); + fightVictim = esmStore.get().find("iFightPickpocket")->getInt() * 4; // *4 according to research wiki + } + else if (type == OT_Assault) + { fight = esmStore.get().find("iFightAttack")->getInt(); + fightVictim = esmStore.get().find("iFightAttacking")->getInt(); + } else if (type == OT_Murder) - fight = esmStore.get().find("iFightKilling")->getInt(); + fight = fightVictim = esmStore.get().find("iFightKilling")->getInt(); else if (type == OT_Theft) - fight = esmStore.get().find("fFightStealing")->getFloat(); - - const int iFightAttacking = esmStore.get().find("iFightAttacking")->getInt(); + fight = fightVictim = esmStore.get().find("fFightStealing")->getFloat(); // Tell everyone (including the original reporter) in alarm range for (std::vector::iterator it = neighbors.begin(); it != neighbors.end(); ++it) @@ -1069,11 +1088,7 @@ namespace MWMechanics if ( *it == player || !it->getClass().isNpc() || it->getClass().getCreatureStats(*it).isDead()) continue; - int aggression = fight; - - // Note: iFightAttack is used for the victim, iFightAttacking for witnesses? - if (*it != victim && type == OT_Assault) - aggression = iFightAttacking; + int aggression = (*it == victim) ? fightVictim : fight; if (it->getClass().getCreatureStats(*it).getAiSequence().isInCombat(victim)) continue; @@ -1091,6 +1106,11 @@ namespace MWMechanics } else { + int dispChange = (*it == victim) ? dispTermVictim : dispTerm; + NpcStats& observerStats = it->getClass().getNpcStats(*it); + int originalDisposition = observerStats.getBaseDisposition(); + observerStats.setBaseDisposition(originalDisposition+dispChange); + bool aggressive = MWBase::Environment::get().getMechanicsManager()->isAggressive(*it, player, aggression, true); if (aggressive) { @@ -1108,6 +1128,8 @@ namespace MWMechanics // Mark as Alarmed for dialogue it->getClass().getCreatureStats(*it).setAlarmed(true); } + else + observerStats.setBaseDisposition(originalDisposition); } } } From 307b84e9f6447cd9b5b317ab5a31e778ccc81749 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 19 Dec 2014 19:51:36 +0100 Subject: [PATCH 0100/3725] Add enemy health bar fading and use relevant GMSTs --- apps/openmw/mwgui/hud.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 2593e6e77..a5703682f 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -618,6 +618,11 @@ namespace MWGui // Health is usually cast to int before displaying. Actors die whenever they are < 1 health. // Therefore any value < 1 should show as an empty health bar. We do the same in statswindow :) mEnemyHealth->setProgressPosition(int(stats.getHealth().getCurrent()) / stats.getHealth().getModified() * 100); + + static const float fNPCHealthBarFade = MWBase::Environment::get().getWorld()->getStore().get().find("fNPCHealthBarFade")->getFloat(); + if (fNPCHealthBarFade > 0.f) + mEnemyHealth->setAlpha(std::max(0.f, std::min(1.f, mEnemyHealthTimer/fNPCHealthBarFade))); + } void HUD::update() @@ -639,7 +644,7 @@ namespace MWGui void HUD::setEnemy(const MWWorld::Ptr &enemy) { mEnemyActorId = enemy.getClass().getCreatureStats(enemy).getActorId(); - mEnemyHealthTimer = 5; + mEnemyHealthTimer = MWBase::Environment::get().getWorld()->getStore().get().find("fNPCHealthBarTime")->getFloat(); if (!mEnemyHealth->getVisible()) mWeaponSpellBox->setPosition(mWeaponSpellBox->getPosition() - MyGUI::IntPoint(0,20)); mEnemyHealth->setVisible(true); From 866fdfe8bdcde3cf07d22872f55a2a617201c0f0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 19 Dec 2014 21:45:26 +0100 Subject: [PATCH 0101/3725] Crime system improvements - If someone saw the crime, they will notify everyone else in range, even if the Alarm rating of the witness is 0. - Pickpocket and selling stolen items now works properly, i.e. honors the victim's Alarm rating instead of always being reported. --- apps/openmw/mwbase/mechanicsmanager.hpp | 10 +-- apps/openmw/mwgui/container.cpp | 10 +-- apps/openmw/mwgui/enchantingdialog.cpp | 5 +- apps/openmw/mwgui/tradewindow.cpp | 5 +- .../mwmechanics/mechanicsmanagerimp.cpp | 82 +++++++++---------- .../mwmechanics/mechanicsmanagerimp.hpp | 14 ++-- 6 files changed, 57 insertions(+), 69 deletions(-) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index c92459183..fe4b5fb63 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -118,16 +118,14 @@ namespace MWBase OT_Pickpocket // Entering pickpocket mode, leaving it, and being detected. Any items stolen are a separate crime (Theft) }; /** - * @brief Commit a crime. If any actors witness the crime and report it, - * reportCrime will be called automatically. * @note victim may be empty * @param arg Depends on \a type, e.g. for Theft, the value of the item that was stolen. - * @return was the crime reported? + * @param victimAware Is the victim already aware of the crime? + * If this parameter is false, it will be determined by a line-of-sight and awareness check. + * @return was the crime seen? */ virtual bool commitCrime (const MWWorld::Ptr& ptr, const MWWorld::Ptr& victim, - OffenseType type, int arg=0) = 0; - virtual void reportCrime (const MWWorld::Ptr& ptr, const MWWorld::Ptr& victim, - OffenseType type, int arg=0) = 0; + OffenseType type, int arg=0, bool victimAware=false) = 0; /// @return false if the attack was considered a "friendly hit" and forgiven virtual bool actorAttacked (const MWWorld::Ptr& victim, const MWWorld::Ptr& attacker) = 0; /// Utility to check if taking this item is illegal and calling commitCrime if so diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 6df8a3f44..ee1d28592 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -301,10 +301,9 @@ namespace MWGui MWMechanics::Pickpocket pickpocket(player, mPtr); if (pickpocket.finish()) { - MWBase::Environment::get().getMechanicsManager()->reportCrime( - player, mPtr, MWBase::MechanicsManager::OT_Pickpocket); + MWBase::Environment::get().getMechanicsManager()->commitCrime( + player, mPtr, MWBase::MechanicsManager::OT_Pickpocket, 0, true); MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Container); - MWBase::Environment::get().getDialogueManager()->say(mPtr, "Thief"); mPickpocketDetected = true; return; } @@ -384,10 +383,9 @@ namespace MWGui if (pickpocket.pick(item.mBase, count)) { int value = item.mBase.getClass().getValue(item.mBase) * count; - MWBase::Environment::get().getMechanicsManager()->reportCrime( - player, MWWorld::Ptr(), MWBase::MechanicsManager::OT_Theft, value); + MWBase::Environment::get().getMechanicsManager()->commitCrime( + player, MWWorld::Ptr(), MWBase::MechanicsManager::OT_Theft, value, true); MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Container); - MWBase::Environment::get().getDialogueManager()->say(mPtr, "Thief"); mPickpocketDetected = true; return false; } diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 56caa6513..d4c10d568 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -338,9 +338,8 @@ namespace MWGui if (msg.find("%s") != std::string::npos) msg.replace(msg.find("%s"), 2, item.getClass().getName(item)); MWBase::Environment::get().getWindowManager()->messageBox(msg); - MWBase::Environment::get().getDialogueManager()->say(mPtr, "Thief"); - MWBase::Environment::get().getMechanicsManager()->reportCrime(player, mPtr, MWBase::MechanicsManager::OT_Theft, - item.getClass().getValue(item)); + MWBase::Environment::get().getMechanicsManager()->commitCrime(player, mPtr, MWBase::MechanicsManager::OT_Theft, + item.getClass().getValue(item), true); MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Enchanting); MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); return; diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 0f98598fd..6499a66d5 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -290,10 +290,9 @@ namespace MWGui if (msg.find("%s") != std::string::npos) msg.replace(msg.find("%s"), 2, it->mBase.getClass().getName(it->mBase)); MWBase::Environment::get().getWindowManager()->messageBox(msg); - MWBase::Environment::get().getDialogueManager()->say(mPtr, "Thief"); - MWBase::Environment::get().getMechanicsManager()->reportCrime(player, mPtr, MWBase::MechanicsManager::OT_Theft, + MWBase::Environment::get().getMechanicsManager()->commitCrime(player, mPtr, MWBase::MechanicsManager::OT_Theft, it->mBase.getClass().getValue(it->mBase) - * it->mCount); + * it->mCount, true); onCancelButtonClicked(mCancelButton); MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); return; diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 720f0c4f5..88a0b2640 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -917,24 +917,19 @@ namespace MWMechanics commitCrime(ptr, victim, OT_Theft, item.getClass().getValue(item) * count); } - bool MechanicsManager::commitCrime(const MWWorld::Ptr &player, const MWWorld::Ptr &victim, OffenseType type, int arg) + bool MechanicsManager::commitCrime(const MWWorld::Ptr &player, const MWWorld::Ptr &victim, OffenseType type, int arg, bool victimAware) { - // NOTE: int arg can be from itemTaken() so DON'T modify it, since it is - // passed to reportCrime later on in this function. - // NOTE: victim may be empty // Only player can commit crime if (player.getRefData().getHandle() != "player") return false; - const MWWorld::ESMStore& esmStore = MWBase::Environment::get().getWorld()->getStore(); - - // Find all the actors within the alarm radius std::vector neighbors; Ogre::Vector3 from = Ogre::Vector3(player.getRefData().getPosition().pos); + const MWWorld::ESMStore& esmStore = MWBase::Environment::get().getWorld()->getStore(); float radius = esmStore.get().find("fAlarmRadius")->getFloat(); mActors.getObjectsInRange(from, radius, neighbors); @@ -943,11 +938,8 @@ namespace MWMechanics if (!victim.isEmpty() && from.squaredDistance(Ogre::Vector3(victim.getRefData().getPosition().pos)) > radius*radius) neighbors.push_back(victim); - bool victimAware = false; - - // Find actors who directly witnessed the crime + // Did anyone see it? bool crimeSeen = false; - bool reported = false; for (std::vector::iterator it = neighbors.begin(); it != neighbors.end(); ++it) { if (*it == player) @@ -955,17 +947,13 @@ namespace MWMechanics if (it->getClass().getCreatureStats(*it).isDead()) continue; - // Was the crime seen? - if ((MWBase::Environment::get().getWorld()->getLOS(player, *it) && awarenessCheck(player, *it) ) + if ((*it == victim && victimAware) + || (MWBase::Environment::get().getWorld()->getLOS(player, *it) && awarenessCheck(player, *it) ) // Murder crime can be reported even if no one saw it (hearing is enough, I guess). // TODO: Add mod support for stealth executions! || (type == OT_Murder && *it != victim)) { - if (*it == victim) - victimAware = true; - - // TODO: are there other messages? - if (type == OT_Theft) + if (type == OT_Theft || type == OT_Pickpocket) MWBase::Environment::get().getDialogueManager()->say(*it, "thief"); // Crime reporting only applies to NPCs @@ -977,20 +965,13 @@ namespace MWMechanics crimeSeen = true; } - - // Will the witness report the crime? - if (it->getClass().getCreatureStats(*it).getAiSetting(CreatureStats::AI_Alarm).getBase() >= 100) - { - reported = true; - } } - if (crimeSeen && reported) + if (crimeSeen) reportCrime(player, victim, type, arg); - else if (victimAware && !victim.isEmpty() && type == OT_Assault) - startCombat(victim, player); - - return reported; + else if (type == OT_Assault && !victim.isEmpty()) + startCombat(victim, player); // TODO: combat should be started with an "unaware" flag, which makes the victim flee? + return crimeSeen; } void MechanicsManager::reportCrime(const MWWorld::Ptr &player, const MWWorld::Ptr &victim, OffenseType type, int arg) @@ -1030,22 +1011,6 @@ namespace MWMechanics arg = std::max(1, arg); // Minimum bounty of 1, in case items with zero value are stolen } - MWBase::Environment::get().getWindowManager()->messageBox("#{sCrimeMessage}"); - player.getClass().getNpcStats(player).setBounty(player.getClass().getNpcStats(player).getBounty() - + arg); - - // If committing a crime against a faction member, expell from the faction - if (!victim.isEmpty() && victim.getClass().isNpc()) - { - std::string factionID; - if(!victim.getClass().getNpcStats(victim).getFactionRanks().empty()) - factionID = victim.getClass().getNpcStats(victim).getFactionRanks().begin()->first; - if (player.getClass().getNpcStats(player).isSameFaction(victim.getClass().getNpcStats(victim))) - { - player.getClass().getNpcStats(player).expell(factionID); - } - } - // Make surrounding actors within alarm distance respond to the crime std::vector neighbors; @@ -1082,6 +1047,8 @@ namespace MWMechanics else if (type == OT_Theft) fight = fightVictim = esmStore.get().find("fFightStealing")->getFloat(); + bool reported = false; + // Tell everyone (including the original reporter) in alarm range for (std::vector::iterator it = neighbors.begin(); it != neighbors.end(); ++it) { @@ -1093,6 +1060,12 @@ namespace MWMechanics if (it->getClass().getCreatureStats(*it).getAiSequence().isInCombat(victim)) continue; + // Will the witness report the crime? + if (it->getClass().getCreatureStats(*it).getAiSetting(CreatureStats::AI_Alarm).getBase() >= 100) + { + reported = true; + } + if (it->getClass().isClass(*it, "guard")) { // Mark as Alarmed for dialogue @@ -1132,6 +1105,25 @@ namespace MWMechanics observerStats.setBaseDisposition(originalDisposition); } } + + if (reported) + { + MWBase::Environment::get().getWindowManager()->messageBox("#{sCrimeMessage}"); + player.getClass().getNpcStats(player).setBounty(player.getClass().getNpcStats(player).getBounty() + + arg); + + // If committing a crime against a faction member, expell from the faction + if (!victim.isEmpty() && victim.getClass().isNpc()) + { + std::string factionID; + if(!victim.getClass().getNpcStats(victim).getFactionRanks().empty()) + factionID = victim.getClass().getNpcStats(victim).getFactionRanks().begin()->first; + if (player.getClass().getNpcStats(player).isSameFaction(victim.getClass().getNpcStats(victim))) + { + player.getClass().getNpcStats(player).expell(factionID); + } + } + } } bool MechanicsManager::actorAttacked(const MWWorld::Ptr &ptr, const MWWorld::Ptr &attacker) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index 489da7541..74b4247fa 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -110,16 +110,14 @@ namespace MWMechanics virtual void startCombat (const MWWorld::Ptr& ptr, const MWWorld::Ptr& target); /** - * @brief Commit a crime. If any actors witness the crime and report it, - * reportCrime will be called automatically. * @note victim may be empty * @param arg Depends on \a type, e.g. for Theft, the value of the item that was stolen. - * @return was the crime reported? + * @param victimAware Is the victim already aware of the crime? + * If this parameter is false, it will be determined by a line-of-sight and awareness check. + * @return was the crime seen? */ virtual bool commitCrime (const MWWorld::Ptr& ptr, const MWWorld::Ptr& victim, - OffenseType type, int arg=0); - virtual void reportCrime (const MWWorld::Ptr& ptr, const MWWorld::Ptr& victim, - OffenseType type, int arg=0); + OffenseType type, int arg=0, bool victimAware=false); /// @return false if the attack was considered a "friendly hit" and forgiven virtual bool actorAttacked (const MWWorld::Ptr& victim, const MWWorld::Ptr& attacker); /// Utility to check if taking this item is illegal and calling commitCrime if so @@ -171,6 +169,10 @@ namespace MWMechanics virtual void keepPlayerAlive(); virtual bool isReadyToBlock (const MWWorld::Ptr& ptr) const; + + private: + void reportCrime (const MWWorld::Ptr& ptr, const MWWorld::Ptr& victim, + OffenseType type, int arg=0); }; } From 37e11b7272b227902a26f3cdbbc05397e4536780 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 20 Dec 2014 00:04:24 +0100 Subject: [PATCH 0102/3725] Adjust loading box size for large captions --- apps/openmw/mwgui/loadingscreen.cpp | 6 ++++++ apps/openmw/mwgui/loadingscreen.hpp | 2 ++ files/mygui/openmw_loading_screen.layout | 4 ++-- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index a446266d9..4ff6b0c89 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -34,6 +34,7 @@ namespace MWGui getWidget(mLoadingText, "LoadingText"); getWidget(mProgressBar, "ProgressBar"); + getWidget(mLoadingBox, "LoadingBox"); mProgressBar->setScrollViewPage(1); @@ -46,6 +47,11 @@ namespace MWGui void LoadingScreen::setLabel(const std::string &label) { mLoadingText->setCaptionWithReplacing(label); + int padding = mLoadingBox->getWidth() - mLoadingText->getWidth(); + MyGUI::IntSize size(mLoadingText->getTextSize().width+padding, mLoadingBox->getHeight()); + size.width = std::max(300, size.width); + mLoadingBox->setSize(size); + mLoadingBox->setPosition(mMainWidget->getWidth()/2 - mLoadingBox->getWidth()/2, mLoadingBox->getTop()); } LoadingScreen::~LoadingScreen() diff --git a/apps/openmw/mwgui/loadingscreen.hpp b/apps/openmw/mwgui/loadingscreen.hpp index 310a6df3c..892710433 100644 --- a/apps/openmw/mwgui/loadingscreen.hpp +++ b/apps/openmw/mwgui/loadingscreen.hpp @@ -47,6 +47,8 @@ namespace MWGui size_t mProgress; + MyGUI::Widget* mLoadingBox; + MyGUI::TextBox* mLoadingText; MyGUI::ScrollBar* mProgressBar; BackgroundImage* mBackgroundImage; diff --git a/files/mygui/openmw_loading_screen.layout b/files/mygui/openmw_loading_screen.layout index 49ee0a1de..8a1514f84 100644 --- a/files/mygui/openmw_loading_screen.layout +++ b/files/mygui/openmw_loading_screen.layout @@ -4,9 +4,9 @@ - + - + From c7be8501625c23633f150d2feac6339c72656882 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 20 Dec 2014 00:06:14 +0100 Subject: [PATCH 0103/3725] Add messagebox escape characters for spell/weapon cycling hotkeys --- components/interpreter/defines.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/components/interpreter/defines.cpp b/components/interpreter/defines.cpp index 94916ee85..4881274f0 100644 --- a/components/interpreter/defines.cpp +++ b/components/interpreter/defines.cpp @@ -47,10 +47,10 @@ namespace Interpreter{ retval << context.getActionBinding("#{sReady_Magic}"); } else if((found = check(temp, "actionprevweapon", &i, &start))){ - retval << "PLACEHOLDER_ACTION_PREV_WEAPON"; + retval << context.getActionBinding("#{sPrevWeapon}"); } else if((found = check(temp, "actionnextweapon", &i, &start))){ - retval << "PLACEHOLDER_ACTION_PREV_WEAPON"; + retval << context.getActionBinding("#{sNextWeapon}"); } else if((found = check(temp, "actiontogglerun", &i, &start))){ retval << context.getActionBinding("#{sAuto_Run}"); @@ -62,10 +62,10 @@ namespace Interpreter{ retval << context.getActionBinding("#{sReady_Weapon}"); } else if((found = check(temp, "actionprevspell", &i, &start))){ - retval << "PLACEHOLDER_ACTION_PREV_SPELL"; + retval << context.getActionBinding("#{sPrevSpell}"); } else if((found = check(temp, "actionnextspell", &i, &start))){ - retval << "PLACEHOLDER_ACTION_NEXT_SPELL"; + retval << context.getActionBinding("#{sNextSpell}"); } else if((found = check(temp, "actionrestmenu", &i, &start))){ retval << context.getActionBinding("#{sRestKey}"); From f3738e9a98f89ba5e9276ce1d723f5f23a29a8da Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 20 Dec 2014 00:18:58 +0100 Subject: [PATCH 0104/3725] Say an "intruder" voice dialogue for trespassing crimes (Fixes #1082) Seems to be broken in the original engine, but according to the TES-CS help this is how the intruder voices should be used. There are legitimate entries for "intruder" in the game's files, so we might as well use them. --- apps/openmw/mwbase/mechanicsmanager.hpp | 2 +- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index fe4b5fb63..41d6c6310 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -113,7 +113,7 @@ namespace MWBase OT_Theft, // Taking items owned by an NPC or a faction you are not a member of OT_Assault, // Attacking a peaceful NPC OT_Murder, // Murdering a peaceful NPC - OT_Trespassing, // Staying in a cell you are not allowed in (where is this defined?) + OT_Trespassing, // Picking the lock of an owned door/chest OT_SleepingInOwnedBed, // Sleeping in a bed owned by an NPC or a faction you are not a member of OT_Pickpocket // Entering pickpocket mode, leaving it, and being detected. Any items stolen are a separate crime (Theft) }; diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 88a0b2640..82b0d556d 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -955,6 +955,8 @@ namespace MWMechanics { if (type == OT_Theft || type == OT_Pickpocket) MWBase::Environment::get().getDialogueManager()->say(*it, "thief"); + else if (type == OT_Trespassing) + MWBase::Environment::get().getDialogueManager()->say(*it, "intruder"); // Crime reporting only applies to NPCs if (!it->getClass().isNpc()) From 9ed71765a92e0fe59bb5b441e141145a12df3286 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 20 Dec 2014 19:53:38 +0100 Subject: [PATCH 0105/3725] Fix deleted containers showing in merchant inventories --- apps/openmw/mwworld/worldimp.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index d370ad453..1867cf84c 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2259,6 +2259,8 @@ namespace MWWorld for (CellRefList::List::iterator container = refList.begin(); container != refList.end(); ++container) { MWWorld::Ptr ptr (&*container, *cellIt); + if (ptr.getRefData().isDeleted()) + continue; if (Misc::StringUtils::ciEqual(ptr.getCellRef().getOwner(), npc.getCellRef().getRefId())) out.push_back(ptr); } From 1bcc4430e0c9df3c3519f413c7032e18496acd4b Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 20 Dec 2014 20:13:27 +0100 Subject: [PATCH 0106/3725] Fix owner not getting set on restocked items --- apps/openmw/mwworld/containerstore.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 45728371b..747926877 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -474,7 +474,7 @@ void MWWorld::ContainerStore::restock (const ESM::InventoryList& items, const MW { int currentCount = count(item); if (currentCount < std::abs(it->mCount)) - add (item, std::abs(it->mCount) - currentCount, ptr); + addInitialItem(item, owner, faction, std::abs(it->mCount) - currentCount, true); } } flagAsModified(); From fb542a64ec0fa022cd42790b9a9ddee5ead61d4e Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 20 Dec 2014 20:17:14 +0100 Subject: [PATCH 0107/3725] Merchant items should be restocked instantly --- apps/openmw/mwgui/dialogue.cpp | 11 +---------- apps/openmw/mwgui/tradewindow.cpp | 16 ++++++++++++++++ apps/openmw/mwgui/tradewindow.hpp | 2 ++ 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index eb548d596..3b4ac8dea 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -415,20 +415,11 @@ namespace MWGui MWMechanics::CreatureStats &sellerStats = mPtr.getClass().getCreatureStats(mPtr); float delay = MWBase::Environment::get().getWorld()->getStore().get().find("fBarterGoldResetDelay")->getFloat(); + // Gold is restocked every 24h if (MWBase::Environment::get().getWorld()->getTimeStamp() >= sellerStats.getLastRestockTime() + delay) { sellerStats.setGoldPool(mPtr.getClass().getBaseGold(mPtr)); - mPtr.getClass().restock(mPtr); - - // Also restock any containers owned by this merchant, which are also available to buy in the trade window - std::vector itemSources; - MWBase::Environment::get().getWorld()->getContainersOwnedBy(mPtr, itemSources); - for (std::vector::iterator it = itemSources.begin(); it != itemSources.end(); ++it) - { - it->getClass().restock(*it); - } - sellerStats.setLastRestockTime(MWBase::Environment::get().getWorld()->getTimeStamp()); } } diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 6499a66d5..6f0074e7e 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -94,6 +94,20 @@ namespace MWGui setCoord(400, 0, 400, 300); } + void TradeWindow::restock() + { + // Restock items on the actor inventory + mPtr.getClass().restock(mPtr); + + // Also restock any containers owned by this merchant, which are also available to buy in the trade window + std::vector itemSources; + MWBase::Environment::get().getWorld()->getContainersOwnedBy(mPtr, itemSources); + for (std::vector::iterator it = itemSources.begin(); it != itemSources.end(); ++it) + { + it->getClass().restock(*it); + } + } + void TradeWindow::startTrade(const MWWorld::Ptr& actor) { mPtr = actor; @@ -101,6 +115,8 @@ namespace MWGui mCurrentBalance = 0; mCurrentMerchantOffer = 0; + restock(); + std::vector itemSources; MWBase::Environment::get().getWorld()->getContainersOwnedBy(actor, itemSources); diff --git a/apps/openmw/mwgui/tradewindow.hpp b/apps/openmw/mwgui/tradewindow.hpp index 47de9215a..b8bdfe648 100644 --- a/apps/openmw/mwgui/tradewindow.hpp +++ b/apps/openmw/mwgui/tradewindow.hpp @@ -98,6 +98,8 @@ namespace MWGui virtual void onReferenceUnavailable(); int getMerchantGold(); + + void restock(); }; } From 703b9c59e9b535d8ee8b396c8c146a05e858628a Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 20 Dec 2014 20:39:13 +0100 Subject: [PATCH 0108/3725] Add missing tooltips to spell creation dialog --- files/mygui/openmw_enchanting_dialog.layout | 6 ++--- .../mygui/openmw_spellcreation_dialog.layout | 22 +++++++++++++++++++ 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/files/mygui/openmw_enchanting_dialog.layout b/files/mygui/openmw_enchanting_dialog.layout index 811a214e3..4fdb91602 100644 --- a/files/mygui/openmw_enchanting_dialog.layout +++ b/files/mygui/openmw_enchanting_dialog.layout @@ -133,13 +133,13 @@ - - - + + + diff --git a/files/mygui/openmw_spellcreation_dialog.layout b/files/mygui/openmw_spellcreation_dialog.layout index 78d3f3de7..fac0497db 100644 --- a/files/mygui/openmw_spellcreation_dialog.layout +++ b/files/mygui/openmw_spellcreation_dialog.layout @@ -7,6 +7,9 @@ + + + @@ -20,23 +23,36 @@ + + + + + + + + + + + + + @@ -44,6 +60,9 @@ + + + @@ -60,6 +79,9 @@ + + + From 877e07823d4e2a82616744ec580015c510faf409 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 20 Dec 2014 20:48:22 +0100 Subject: [PATCH 0109/3725] Fix incorrect sound for spell creation success --- apps/openmw/mwgui/spellcreationdialog.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index 5da33c67a..c8510c0e1 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -371,7 +371,7 @@ namespace MWGui MWMechanics::CreatureStats& npcStats = mPtr.getClass().getCreatureStats(mPtr); npcStats.setGoldPool(npcStats.getGoldPool() + price); - MWBase::Environment::get().getSoundManager()->playSound ("Item Gold Up", 1.0, 1.0); + MWBase::Environment::get().getSoundManager()->playSound ("Mysticism Hit", 1.0, 1.0); const ESM::Spell* spell = MWBase::Environment::get().getWorld()->createRecord(mSpell); @@ -379,8 +379,6 @@ namespace MWGui MWMechanics::Spells& spells = stats.getSpells(); spells.add (spell->mId); - MWBase::Environment::get().getSoundManager()->playSound ("Item Gold Up", 1.0, 1.0); - MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_SpellCreation); } From 0081a683762d12a268cfd36208c67a948121ccfa Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 20 Dec 2014 20:56:44 +0100 Subject: [PATCH 0110/3725] Use fMagicStartIconBlink for spell effect indicator fading --- apps/openmw/mwgui/spellicons.cpp | 17 +++++++++++++---- apps/openmw/mwgui/spellicons.hpp | 6 ++++-- apps/openmw/mwmechanics/activespells.cpp | 2 +- apps/openmw/mwmechanics/actors.cpp | 4 ++-- apps/openmw/mwmechanics/magiceffects.hpp | 2 +- 5 files changed, 21 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwgui/spellicons.cpp b/apps/openmw/mwgui/spellicons.cpp index dbd91ab75..419969574 100644 --- a/apps/openmw/mwgui/spellicons.cpp +++ b/apps/openmw/mwgui/spellicons.cpp @@ -24,7 +24,7 @@ namespace MWGui void EffectSourceVisitor::visit (MWMechanics::EffectKey key, const std::string& sourceName, int casterActorId, - float magnitude, float remainingTime) + float magnitude, float remainingTime, float totalTime) { MagicEffectInfo newEffectSource; newEffectSource.mKey = key; @@ -32,6 +32,7 @@ namespace MWGui newEffectSource.mPermanent = mIsPermanent; newEffectSource.mRemainingTime = remainingTime; newEffectSource.mSource = sourceName; + newEffectSource.mTotalTime = totalTime; mEffectSources[key.mId].push_back(newEffectSource); } @@ -67,10 +68,11 @@ namespace MWGui MWBase::Environment::get().getWorld ()->getStore ().get().find(it->first); float remainingDuration = 0; + float totalDuration = 0; std::string sourcesDescription; - const float fadeTime = 5.f; + static const float fadeTime = MWBase::Environment::get().getWorld()->getStore().get().find("fMagicStartIconBlink")->getFloat(); for (std::vector::const_iterator effectIt = it->second.begin(); effectIt != it->second.end(); ++effectIt) @@ -80,9 +82,15 @@ namespace MWGui // if at least one of the effect sources is permanent, the effect will never wear off if (effectIt->mPermanent) + { remainingDuration = fadeTime; + totalDuration = fadeTime; + } else + { remainingDuration = std::max(remainingDuration, effectIt->mRemainingTime); + totalDuration = std::max(totalDuration, effectIt->mTotalTime); + } sourcesDescription += effectIt->mSource; @@ -158,8 +166,9 @@ namespace MWGui ToolTipInfo* tooltipInfo = image->getUserData(); tooltipInfo->text = sourcesDescription; - // Fade out during the last 5 seconds - image->setAlpha(std::min(remainingDuration/fadeTime, 1.f)); + // Fade out + if (totalDuration >= fadeTime && fadeTime > 0.f) + image->setAlpha(std::min(remainingDuration/fadeTime, 1.f)); } else if (mWidgetMap.find(it->first) != mWidgetMap.end()) { diff --git a/apps/openmw/mwgui/spellicons.hpp b/apps/openmw/mwgui/spellicons.hpp index 7df9ad8b9..e9d9967ea 100644 --- a/apps/openmw/mwgui/spellicons.hpp +++ b/apps/openmw/mwgui/spellicons.hpp @@ -26,12 +26,14 @@ namespace MWGui MagicEffectInfo() : mPermanent(false) , mMagnitude(0) - , mRemainingTime(0) + , mRemainingTime(0.f) + , mTotalTime(0.f) {} std::string mSource; // display name for effect source (e.g. potion name) MWMechanics::EffectKey mKey; int mMagnitude; float mRemainingTime; + float mTotalTime; bool mPermanent; // the effect is permanent }; @@ -46,7 +48,7 @@ namespace MWGui virtual void visit (MWMechanics::EffectKey key, const std::string& sourceName, int casterActorId, - float magnitude, float remainingTime = -1); + float magnitude, float remainingTime = -1, float totalTime = -1); }; class SpellIcons diff --git a/apps/openmw/mwmechanics/activespells.cpp b/apps/openmw/mwmechanics/activespells.cpp index d87e22543..717a63be8 100644 --- a/apps/openmw/mwmechanics/activespells.cpp +++ b/apps/openmw/mwmechanics/activespells.cpp @@ -195,7 +195,7 @@ namespace MWMechanics float magnitude = effectIt->mMagnitude; if (magnitude) - visitor.visit(MWMechanics::EffectKey(effectIt->mEffectId, effectIt->mArg), name, it->second.mCasterActorId, magnitude, remainingTime); + visitor.visit(MWMechanics::EffectKey(effectIt->mEffectId, effectIt->mArg), name, it->second.mCasterActorId, magnitude, remainingTime, effectIt->mDuration); } } } diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index abab1f9e5..f824fd6f4 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -102,7 +102,7 @@ public: virtual void visit (MWMechanics::EffectKey key, const std::string& sourceName, int casterActorId, - float magnitude, float remainingTime = -1) + float magnitude, float remainingTime = -1, float totalTime = -1) { MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); if ( ((key.mId == ESM::MagicEffect::CommandHumanoid && mActor.getClass().isNpc()) @@ -200,7 +200,7 @@ namespace MWMechanics virtual void visit (MWMechanics::EffectKey key, const std::string& sourceName, int casterActorId, - float magnitude, float remainingTime = -1) + float magnitude, float remainingTime = -1, float totalTime = -1) { if (key.mId != ESM::MagicEffect::Soultrap) return; diff --git a/apps/openmw/mwmechanics/magiceffects.hpp b/apps/openmw/mwmechanics/magiceffects.hpp index 0a8392dab..88d8d988f 100644 --- a/apps/openmw/mwmechanics/magiceffects.hpp +++ b/apps/openmw/mwmechanics/magiceffects.hpp @@ -74,7 +74,7 @@ namespace MWMechanics { virtual void visit (MWMechanics::EffectKey key, const std::string& sourceName, int casterActorId, - float magnitude, float remainingTime = -1) = 0; + float magnitude, float remainingTime = -1, float totalTime = -1) = 0; }; /// \brief Effects currently affecting a NPC or creature From 3912ee2b1d0a958f2d8d785608f2b22aa8298282 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 20 Dec 2014 22:00:45 +0100 Subject: [PATCH 0111/3725] Fix faction rank not being set on items in faction-owned containers --- apps/openmw/mwclass/container.cpp | 4 ++-- apps/openmw/mwclass/creature.cpp | 4 ++-- apps/openmw/mwclass/npc.cpp | 4 ++-- apps/openmw/mwworld/cellref.cpp | 9 +++++++++ apps/openmw/mwworld/cellref.hpp | 1 + apps/openmw/mwworld/containerstore.cpp | 17 +++++++++-------- apps/openmw/mwworld/containerstore.hpp | 6 +++--- 7 files changed, 28 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index 59e51e461..72a9802e8 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -59,7 +59,7 @@ namespace MWClass ptr.get(); data->mContainerStore.fill( - ref->mBase->mInventory, ptr.getCellRef().getOwner(), ptr.getCellRef().getFaction(), MWBase::Environment::get().getWorld()->getStore()); + ref->mBase->mInventory, ptr.getCellRef().getOwner(), ptr.getCellRef().getFaction(), ptr.getCellRef().getFactionRank(), MWBase::Environment::get().getWorld()->getStore()); // store ptr.getRefData().setCustomData (data.release()); @@ -81,7 +81,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); const ESM::InventoryList& list = ref->mBase->mInventory; MWWorld::ContainerStore& store = getContainerStore(ptr); - store.restock(list, ptr, ptr.getCellRef().getOwner(), ptr.getCellRef().getFaction()); + store.restock(list, ptr, ptr.getCellRef().getOwner(), ptr.getCellRef().getFaction(), ptr.getCellRef().getFactionRank()); } void Container::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 323fafbb6..c69081c2e 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -139,7 +139,7 @@ namespace MWClass // store ptr.getRefData().setCustomData(data.release()); - getContainerStore(ptr).fill(ref->mBase->mInventory, getId(ptr), "", + getContainerStore(ptr).fill(ref->mBase->mInventory, getId(ptr), "", -1, MWBase::Environment::get().getWorld()->getStore()); if (ref->mBase->mFlags & ESM::Creature::Weapon) @@ -888,7 +888,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); const ESM::InventoryList& list = ref->mBase->mInventory; MWWorld::ContainerStore& store = getContainerStore(ptr); - store.restock(list, ptr, ptr.getCellRef().getRefId(), ptr.getCellRef().getFaction()); + store.restock(list, ptr, ptr.getCellRef().getRefId(), "", -1); } int Creature::getBaseFightRating(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 2c68b4c72..3fe23772d 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -403,7 +403,7 @@ namespace MWClass } // inventory - data->mInventoryStore.fill(ref->mBase->mInventory, getId(ptr), "", + data->mInventoryStore.fill(ref->mBase->mInventory, getId(ptr), "", -1, MWBase::Environment::get().getWorld()->getStore()); data->mNpcStats.setGoldPool(gold); @@ -1376,7 +1376,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); const ESM::InventoryList& list = ref->mBase->mInventory; MWWorld::ContainerStore& store = getContainerStore(ptr); - store.restock(list, ptr, ptr.getCellRef().getRefId(), ptr.getCellRef().getFaction()); + store.restock(list, ptr, ptr.getCellRef().getRefId(), "", -1); } int Npc::getBaseFightRating (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwworld/cellref.cpp b/apps/openmw/mwworld/cellref.cpp index c0b3bb6af..3ea3ed8bf 100644 --- a/apps/openmw/mwworld/cellref.cpp +++ b/apps/openmw/mwworld/cellref.cpp @@ -99,6 +99,15 @@ namespace MWWorld return mCellRef.mGlobalVariable; } + void CellRef::setFactionRank(int factionRank) + { + if (factionRank != mCellRef.mFactionRank) + { + mChanged = true; + mCellRef.mFactionRank = factionRank; + } + } + int CellRef::getFactionRank() const { return mCellRef.mFactionRank; diff --git a/apps/openmw/mwworld/cellref.hpp b/apps/openmw/mwworld/cellref.hpp index d2e4fdf1c..d7c0ce221 100644 --- a/apps/openmw/mwworld/cellref.hpp +++ b/apps/openmw/mwworld/cellref.hpp @@ -79,6 +79,7 @@ namespace MWWorld void setFaction (const std::string& faction); // PC faction rank required to use the item. Sometimes is -1, which means "any rank". + void setFactionRank(int factionRank); int getFactionRank() const; // Lock level for doors and containers diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 747926877..e9c968a07 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -396,19 +396,19 @@ int MWWorld::ContainerStore::remove(const Ptr& item, int count, const Ptr& actor return count - toRemove; } -void MWWorld::ContainerStore::fill (const ESM::InventoryList& items, const std::string& owner, const std::string& faction, const MWWorld::ESMStore& store) +void MWWorld::ContainerStore::fill (const ESM::InventoryList& items, const std::string& owner, const std::string& faction, int factionRank, const MWWorld::ESMStore& store) { for (std::vector::const_iterator iter (items.mList.begin()); iter!=items.mList.end(); ++iter) { std::string id = Misc::StringUtils::lowerCase(iter->mItem.toString()); - addInitialItem(id, owner, faction, iter->mCount); + addInitialItem(id, owner, faction, factionRank, iter->mCount); } flagAsModified(); } -void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std::string& owner, const std::string& faction, +void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std::string& owner, const std::string& faction, int factionRank, int count, bool topLevel, const std::string& levItem) { ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), id, count); @@ -420,7 +420,7 @@ void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std:: if (topLevel && std::abs(count) > 1 && levItem->mFlags & ESM::ItemLevList::Each) { for (int i=0; i 0 ? 1 : -1, true, levItem->mId); + addInitialItem(id, owner, faction, factionRank, count > 0 ? 1 : -1, true, levItem->mId); return; } else @@ -428,7 +428,7 @@ void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std:: std::string id = MWMechanics::getLevelledItem(ref.getPtr().get()->mBase, false); if (id.empty()) return; - addInitialItem(id, owner, faction, count, false, levItem->mId); + addInitialItem(id, owner, faction, factionRank, count, false, levItem->mId); } } else @@ -445,11 +445,12 @@ void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std:: ref.getPtr().getCellRef().setOwner(owner); ref.getPtr().getCellRef().setFaction(faction); + ref.getPtr().getCellRef().setFactionRank(factionRank); addImp (ref.getPtr(), count); } } -void MWWorld::ContainerStore::restock (const ESM::InventoryList& items, const MWWorld::Ptr& ptr, const std::string& owner, const std::string& faction) +void MWWorld::ContainerStore::restock (const ESM::InventoryList& items, const MWWorld::Ptr& ptr, const std::string& owner, const std::string& faction, int factionRank) { // Remove the items already spawned by levelled items that will restock for (std::map::iterator it = mLevelledItemMap.begin(); it != mLevelledItemMap.end(); ++it) @@ -468,13 +469,13 @@ void MWWorld::ContainerStore::restock (const ESM::InventoryList& items, const MW if (MWBase::Environment::get().getWorld()->getStore().get().search(it->mItem.toString())) { - addInitialItem(item, owner, faction, it->mCount, true); + addInitialItem(item, owner, faction, factionRank, it->mCount, true); } else { int currentCount = count(item); if (currentCount < std::abs(it->mCount)) - addInitialItem(item, owner, faction, std::abs(it->mCount) - currentCount, true); + addInitialItem(item, owner, faction, factionRank, std::abs(it->mCount) - currentCount, true); } } flagAsModified(); diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index 6d9d7a6bb..33255138a 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -74,7 +74,7 @@ namespace MWWorld mutable float mCachedWeight; mutable bool mWeightUpToDate; ContainerStoreIterator addImp (const Ptr& ptr, int count); - void addInitialItem (const std::string& id, const std::string& owner, const std::string& faction, int count, bool topLevel=true, const std::string& levItem = ""); + void addInitialItem (const std::string& id, const std::string& owner, const std::string& faction, int factionRank, int count, bool topLevel=true, const std::string& levItem = ""); template ContainerStoreIterator getState (CellRefList& collection, @@ -153,10 +153,10 @@ namespace MWWorld virtual bool stacks (const Ptr& ptr1, const Ptr& ptr2); ///< @return true if the two specified objects can stack with each other - void fill (const ESM::InventoryList& items, const std::string& owner, const std::string& faction, const MWWorld::ESMStore& store); + void fill (const ESM::InventoryList& items, const std::string& owner, const std::string& faction, int factionRank, const MWWorld::ESMStore& store); ///< Insert items into *this. - void restock (const ESM::InventoryList& items, const MWWorld::Ptr& ptr, const std::string& owner, const std::string& faction); + void restock (const ESM::InventoryList& items, const MWWorld::Ptr& ptr, const std::string& owner, const std::string& faction, int factionRank); virtual void clear(); ///< Empty container. From e73e97529112e46ab9222ef22da9e2f52c1eb568 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 21 Dec 2014 00:09:50 +0100 Subject: [PATCH 0112/3725] Fix player being able to activate objects when knocked out --- apps/openmw/engine.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 3d8aa5530..e89bcfa1d 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -508,6 +508,10 @@ void OMW::Engine::activate() if (MWBase::Environment::get().getWindowManager()->isGuiMode()) return; + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + if (player.getClass().getCreatureStats(player).getKnockedDown()) + return; + MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getFacedObject(); if (ptr.isEmpty()) From b35f87ae7e4ff247079669064b1bff379021205a Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 21 Dec 2014 01:28:06 +0100 Subject: [PATCH 0113/3725] Improve font file error handling --- components/fontloader/fontloader.cpp | 48 ++++++++++++++++++++++------ 1 file changed, 38 insertions(+), 10 deletions(-) diff --git a/components/fontloader/fontloader.cpp b/components/fontloader/fontloader.cpp index e01e4b7bc..17c630fd9 100644 --- a/components/fontloader/fontloader.cpp +++ b/components/fontloader/fontloader.cpp @@ -1,5 +1,7 @@ #include "fontloader.hpp" +#include + #include #include @@ -121,6 +123,15 @@ namespace return encoder.getUtf8(std::string(1, c)); } + void fail (Ogre::DataStreamPtr file, const std::string& fileName, const std::string& message) + { + std::stringstream error; + error << "Font loading error: " << message; + error << "\n File: " << fileName; + error << "\n Offset: 0x" << std::hex << file->tell(); + throw std::runtime_error(error.str()); + } + } namespace Gui @@ -173,20 +184,30 @@ namespace Gui Ogre::DataStreamPtr file = Ogre::ResourceGroupManager::getSingleton().openResource(fileName); float fontSize; + if (file->read(&fontSize, sizeof(fontSize)) < sizeof(fontSize)) + fail(file, fileName, "File too small to be a valid font"); + int one; - file->read(&fontSize, sizeof(fontSize)); + if (file->read(&one, sizeof(int)) < sizeof(int)) + fail(file, fileName, "File too small to be a valid font"); - file->read(&one, sizeof(int)); - assert(one == 1); - file->read(&one, sizeof(int)); - assert(one == 1); + if (one != 1) + fail(file, fileName, "Unexpected value"); + + if (file->read(&one, sizeof(int)) < sizeof(int)) + fail(file, fileName, "File too small to be a valid font"); + + if (one != 1) + fail(file, fileName, "Unexpected value"); char name_[284]; - file->read(name_, sizeof(name_)); + if (file->read(name_, sizeof(name_)) < sizeof(name_)) + fail(file, fileName, "File too small to be a valid font"); std::string name(name_); GlyphInfo data[256]; - file->read(data, sizeof(data)); + if (file->read(data, sizeof(data)) < sizeof(data)) + fail(file, fileName, "File too small to be a valid font"); file->close(); // Create the font texture @@ -194,12 +215,19 @@ namespace Gui Ogre::DataStreamPtr bitmapFile = Ogre::ResourceGroupManager::getSingleton().openResource(bitmapFilename); int width, height; - bitmapFile->read(&width, sizeof(int)); - bitmapFile->read(&height, sizeof(int)); + if (bitmapFile->read(&width, sizeof(int)) < sizeof(int)) + fail(bitmapFile, bitmapFilename, "File too small to be a valid bitmap"); + + if (bitmapFile->read(&height, sizeof(int)) < sizeof(int)) + fail(bitmapFile, bitmapFilename, "File too small to be a valid bitmap"); + + if (width <= 0 || height <= 0) + fail(bitmapFile, bitmapFilename, "Width and height must be positive"); std::vector textureData; textureData.resize(width*height*4); - bitmapFile->read(&textureData[0], width*height*4); + if (bitmapFile->read(&textureData[0], width*height*4) < (size_t)(width*height*4)) + fail(bitmapFile, bitmapFilename, "Bitmap does not contain the specified number of pixels"); bitmapFile->close(); std::string resourceName; From 2410d7941081a5b396aa2ca69d4442d78bd8a2a0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 21 Dec 2014 01:53:32 +0100 Subject: [PATCH 0114/3725] Fix iFightAttack and iFightAttacking being swapped Looks like the research wiki page was incorrect, the higher value (iFightAttack) being for the victim makes more sense, is consistent with iDispAttackMod/fDispAttacking, and seems to be how the original game behaves as well. --- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 82b0d556d..f88538507 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1041,8 +1041,8 @@ namespace MWMechanics } else if (type == OT_Assault) { - fight = esmStore.get().find("iFightAttack")->getInt(); - fightVictim = esmStore.get().find("iFightAttacking")->getInt(); + fight = esmStore.get().find("iFightAttacking")->getInt(); + fightVictim = esmStore.get().find("iFightAttack")->getInt(); } else if (type == OT_Murder) fight = fightVictim = esmStore.get().find("iFightKilling")->getInt(); From 9e5dfb6e98d0e99cbdeef0a259edcde6c2117c84 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 21 Dec 2014 02:45:37 +0100 Subject: [PATCH 0115/3725] Update crime system according to research wiki for more accurate attack responses --- apps/openmw/mwbase/mechanicsmanager.hpp | 4 +- .../mwmechanics/mechanicsmanagerimp.cpp | 101 +++++++++++------- .../mwmechanics/mechanicsmanagerimp.hpp | 4 +- 3 files changed, 63 insertions(+), 46 deletions(-) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index 41d6c6310..a51e3a301 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -197,9 +197,7 @@ namespace MWBase virtual void clear() = 0; - /// @param bias Can be used to add an additional aggression bias towards the target, - /// making it more likely for the function to return true. - virtual bool isAggressive (const MWWorld::Ptr& ptr, const MWWorld::Ptr& target, int bias=0, bool ignoreDistance=false) = 0; + virtual bool isAggressive (const MWWorld::Ptr& ptr, const MWWorld::Ptr& target) = 0; /// Resurrects the player if necessary virtual void keepPlayerAlive() = 0; diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index f88538507..54d53512a 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -23,6 +23,33 @@ #include +namespace +{ + + float getFightDistanceBias(const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2) + { + Ogre::Vector3 pos1 (actor1.getRefData().getPosition().pos); + Ogre::Vector3 pos2 (actor2.getRefData().getPosition().pos); + + float d = pos1.distance(pos2); + + static const int iFightDistanceBase = MWBase::Environment::get().getWorld()->getStore().get().find( + "iFightDistanceBase")->getInt(); + static const float fFightDistanceMultiplier = MWBase::Environment::get().getWorld()->getStore().get().find( + "fFightDistanceMultiplier")->getFloat(); + + return (iFightDistanceBase - fFightDistanceMultiplier * d); + } + + float getFightDispositionBias(float disposition) + { + static const float fFightDispMult = MWBase::Environment::get().getWorld()->getStore().get().find( + "fFightDispMult")->getFloat(); + return ((50.f - disposition) * fFightDispMult); + } + +} + namespace MWMechanics { void MechanicsManager::buildPlayer() @@ -983,32 +1010,32 @@ namespace MWMechanics if (type == OT_Murder && !victim.isEmpty()) victim.getClass().getCreatureStats(victim).notifyMurder(); - // Bounty for each type of crime - float dispTerm = 0.f, dispTermVictim = 0.f; + // Bounty and disposition penalty for each type of crime + float disp = 0.f, dispVictim = 0.f; if (type == OT_Trespassing || type == OT_SleepingInOwnedBed) { arg = store.find("iCrimeTresspass")->getInt(); - dispTerm = dispTermVictim = store.find("iDispTresspass")->getInt(); + disp = dispVictim = store.find("iDispTresspass")->getInt(); } else if (type == OT_Pickpocket) { arg = store.find("iCrimePickPocket")->getInt(); - dispTerm = dispTermVictim = store.find("fDispPickPocketMod")->getFloat(); + disp = dispVictim = store.find("fDispPickPocketMod")->getFloat(); } else if (type == OT_Assault) { arg = store.find("iCrimeAttack")->getInt(); - dispTerm = store.find("fDispAttacking")->getFloat(); - dispTermVictim = store.find("iDispAttackMod")->getInt(); + disp = store.find("fDispAttacking")->getFloat(); + dispVictim = store.find("iDispAttackMod")->getInt(); } else if (type == OT_Murder) { arg = store.find("iCrimeKilling")->getInt(); - dispTerm = dispTermVictim = store.find("iDispKilling")->getInt(); + disp = dispVictim = store.find("iDispKilling")->getInt(); } else if (type == OT_Theft) { - dispTerm = dispTermVictim = store.find("fDispStealing")->getFloat() * arg; + disp = dispVictim = store.find("fDispStealing")->getFloat() * arg; arg *= store.find("fCrimeStealing")->getFloat(); arg = std::max(1, arg); // Minimum bounty of 1, in case items with zero value are stolen } @@ -1057,8 +1084,6 @@ namespace MWMechanics if ( *it == player || !it->getClass().isNpc() || it->getClass().getCreatureStats(*it).isDead()) continue; - int aggression = (*it == victim) ? fightVictim : fight; - if (it->getClass().getCreatureStats(*it).getAiSequence().isInCombat(victim)) continue; @@ -1081,30 +1106,41 @@ namespace MWMechanics } else { - int dispChange = (*it == victim) ? dispTermVictim : dispTerm; - NpcStats& observerStats = it->getClass().getNpcStats(*it); - int originalDisposition = observerStats.getBaseDisposition(); - observerStats.setBaseDisposition(originalDisposition+dispChange); + float dispTerm = (*it == victim) ? dispVictim : disp; + + float alarmTerm = 0.01 * it->getClass().getCreatureStats(*it).getAiSetting(CreatureStats::AI_Alarm).getBase(); + if (*it != victim) + dispTerm *= alarmTerm; + + float fightTerm = (*it == victim) ? fightVictim : fight; + fightTerm += getFightDispositionBias(dispTerm); + fightTerm += getFightDistanceBias(*it, player); + if (type != OT_Pickpocket) // type check not in the wiki, but this seems to be needed for MW behaviour + fightTerm *= alarmTerm; - bool aggressive = MWBase::Environment::get().getMechanicsManager()->isAggressive(*it, player, aggression, true); - if (aggressive) + int observerFightRating = it->getClass().getCreatureStats(*it).getAiSetting(CreatureStats::AI_Fight).getBase(); + if (observerFightRating + fightTerm > 100) + fightTerm = 100 - observerFightRating; + fightTerm = std::max(0.f, fightTerm); + + if (observerFightRating + fightTerm >= 100) { startCombat(*it, player); + NpcStats& observerStats = it->getClass().getNpcStats(*it); // Apply aggression value to the base Fight rating, so that the actor can continue fighting // after a Calm spell wears off - int fightBase = it->getClass().getCreatureStats(*it).getAiSetting(CreatureStats::AI_Fight).getBase(); - it->getClass().getCreatureStats(*it).setAiSetting(CreatureStats::AI_Fight, fightBase + aggression); + observerStats.setAiSetting(CreatureStats::AI_Fight, observerFightRating + fightTerm); + + observerStats.setBaseDisposition(observerStats.getBaseDisposition()+dispTerm); // Set the crime ID, which we will use to calm down participants // once the bounty has been paid. - it->getClass().getNpcStats(*it).setCrimeId(id); + observerStats.setCrimeId(id); // Mark as Alarmed for dialogue - it->getClass().getCreatureStats(*it).setAlarmed(true); + observerStats.setAlarmed(true); } - else - observerStats.setBaseDisposition(originalDisposition); } } @@ -1318,30 +1354,15 @@ namespace MWMechanics mActors.clear(); } - bool MechanicsManager::isAggressive(const MWWorld::Ptr &ptr, const MWWorld::Ptr &target, int bias, bool ignoreDistance) + bool MechanicsManager::isAggressive(const MWWorld::Ptr &ptr, const MWWorld::Ptr &target) { - Ogre::Vector3 pos1 (ptr.getRefData().getPosition().pos); - Ogre::Vector3 pos2 (target.getRefData().getPosition().pos); - - float d = 0; - if (!ignoreDistance) - d = pos1.distance(pos2); - - static int iFightDistanceBase = MWBase::Environment::get().getWorld()->getStore().get().find( - "iFightDistanceBase")->getInt(); - static float fFightDistanceMultiplier = MWBase::Environment::get().getWorld()->getStore().get().find( - "fFightDistanceMultiplier")->getFloat(); - static float fFightDispMult = MWBase::Environment::get().getWorld()->getStore().get().find( - "fFightDispMult")->getFloat(); - int disposition = 50; if (ptr.getClass().isNpc()) disposition = getDerivedDisposition(ptr); int fight = std::max(0.f, ptr.getClass().getCreatureStats(ptr).getAiSetting(CreatureStats::AI_Fight).getModified() - + (iFightDistanceBase - fFightDistanceMultiplier * d) - + ((50 - disposition) * fFightDispMult)) - + bias; + + getFightDistanceBias(ptr, target) + + getFightDispositionBias(disposition)); if (ptr.getClass().isNpc() && target.getClass().isNpc()) { diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index 74b4247fa..fc9c58974 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -162,9 +162,7 @@ namespace MWMechanics virtual void clear(); - /// @param bias Can be used to add an additional aggression bias towards the target, - /// making it more likely for the function to return true. - virtual bool isAggressive (const MWWorld::Ptr& ptr, const MWWorld::Ptr& target, int bias=0, bool ignoreDistance=false); + virtual bool isAggressive (const MWWorld::Ptr& ptr, const MWWorld::Ptr& target); virtual void keepPlayerAlive(); From 8bc7eb5530b0df34d691061440cfafc434490e76 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 21 Dec 2014 15:29:20 +0100 Subject: [PATCH 0116/3725] PlayGroup: Don't loop animations with no loop keys (Fixes #2223) --- apps/openmw/mwmechanics/character.cpp | 4 ++-- apps/openmw/mwrender/animation.cpp | 18 +++++++++++++----- apps/openmw/mwrender/animation.hpp | 9 ++++++--- apps/openmw/mwrender/characterpreview.cpp | 2 +- 4 files changed, 22 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 6f092f5a4..e553b6cdc 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -325,7 +325,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat mCurrentIdle = idle; if(!mCurrentIdle.empty()) mAnimation->play(mCurrentIdle, Priority_Default, MWRender::Animation::Group_All, false, - 1.0f, "start", "stop", 0.0f, ~0ul); + 1.0f, "start", "stop", 0.0f, ~0ul, true); } updateIdleStormState(); @@ -1289,7 +1289,7 @@ bool CharacterController::updateWeaponState() { mAnimation->play("torch", Priority_Torch, MWRender::Animation::Group_LeftArm, - false, 1.0f, "start", "stop", 0.0f, (~(size_t)0)); + false, 1.0f, "start", "stop", 0.0f, (~(size_t)0), true); } else if (mAnimation->isPlaying("torch")) { diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index ecaaba0b9..213fd5f61 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -613,7 +613,7 @@ void Animation::updatePosition(float oldtime, float newtime, Ogre::Vector3 &posi mAccumRoot->setPosition(-off); } -bool Animation::reset(AnimState &state, const NifOgre::TextKeyMap &keys, const std::string &groupname, const std::string &start, const std::string &stop, float startpoint) +bool Animation::reset(AnimState &state, const NifOgre::TextKeyMap &keys, const std::string &groupname, const std::string &start, const std::string &stop, float startpoint, bool loopfallback) { // Look for text keys in reverse. This normally wouldn't matter, but for some reason undeadwolf_2.nif has two // separate walkforward keys, and the last one is supposed to be used. @@ -654,8 +654,16 @@ bool Animation::reset(AnimState &state, const NifOgre::TextKeyMap &keys, const s return false; state.mStartTime = startkey->first; - state.mLoopStartTime = startkey->first; - state.mLoopStopTime = stopkey->first; + if (loopfallback) + { + state.mLoopStartTime = startkey->first; + state.mLoopStopTime = stopkey->first; + } + else + { + state.mLoopStartTime = startkey->first; + state.mLoopStopTime = std::numeric_limits::max(); + } state.mStopTime = stopkey->first; state.mTime = state.mStartTime + ((state.mStopTime - state.mStartTime) * startpoint); @@ -850,7 +858,7 @@ void Animation::stopLooping(const std::string& groupname) } } -void Animation::play(const std::string &groupname, int priority, int groups, bool autodisable, float speedmult, const std::string &start, const std::string &stop, float startpoint, size_t loops) +void Animation::play(const std::string &groupname, int priority, int groups, bool autodisable, float speedmult, const std::string &start, const std::string &stop, float startpoint, size_t loops, bool loopfallback) { if(!mSkelBase || mAnimSources.empty()) return; @@ -886,7 +894,7 @@ void Animation::play(const std::string &groupname, int priority, int groups, boo for(;iter != mAnimSources.rend();++iter) { const NifOgre::TextKeyMap &textkeys = (*iter)->mTextKeys; - if(reset(state, textkeys, groupname, start, stop, startpoint)) + if(reset(state, textkeys, groupname, start, stop, startpoint, loopfallback)) { state.mSource = *iter; state.mSpeedMult = speedmult; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 1a420582c..712069036 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -173,7 +173,7 @@ protected: */ bool reset(AnimState &state, const NifOgre::TextKeyMap &keys, const std::string &groupname, const std::string &start, const std::string &stop, - float startpoint); + float startpoint, bool loopfallback); void handleTextKey(AnimState &state, const std::string &groupname, const NifOgre::TextKeyMap::const_iterator &key, const NifOgre::TextKeyMap& map); @@ -255,11 +255,14 @@ public: * at the start marker, 1 starts at the stop marker. * \param loops How many times to loop the animation. This will use the * "loop start" and "loop stop" markers if they exist, - * otherwise it will use "start" and "stop". + * otherwise it may fall back to "start" and "stop", but only if + * the \a loopFallback parameter is true. + * \param loopFallback Allow looping an animation that has no loop keys, i.e. fall back to use + * the "start" and "stop" keys for looping? */ void play(const std::string &groupname, int priority, int groups, bool autodisable, float speedmult, const std::string &start, const std::string &stop, - float startpoint, size_t loops); + float startpoint, size_t loops, bool loopfallback=false); /** If the given animation group is currently playing, set its remaining loop count to '0'. */ diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 8d693e966..57b4c4f68 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -242,7 +242,7 @@ namespace MWRender { if(!mAnimation->getInfo("torch")) mAnimation->play("torch", 2, MWRender::Animation::Group_LeftArm, false, - 1.0f, "start", "stop", 0.0f, ~0ul); + 1.0f, "start", "stop", 0.0f, ~0ul, true); } else if(mAnimation->getInfo("torch")) mAnimation->disable("torch"); From 42d63a4eb233065427cf4450a15d6080116d98ad Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 21 Dec 2014 15:33:37 +0100 Subject: [PATCH 0117/3725] Fix position flicker after an animation ends --- apps/openmw/mwrender/animation.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 213fd5f61..4894378c7 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1002,6 +1002,9 @@ void Animation::resetActiveGroups() break; } } + + if (mAccumRoot && mNonAccumCtrl) + mAccumRoot->setPosition(-mNonAccumCtrl->getTranslation(state->second.mTime)*mAccumulate); } From edc128572dfb0bca5681d575588f76e07636fb7a Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 21 Dec 2014 16:45:30 +0100 Subject: [PATCH 0118/3725] Add MWMechanics::Actor class for temporary actor state, move AiState there --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwmechanics/actor.cpp | 28 ++++++ apps/openmw/mwmechanics/actor.hpp | 42 +++++++++ apps/openmw/mwmechanics/actors.cpp | 88 ++++++++++--------- apps/openmw/mwmechanics/actors.hpp | 11 +-- apps/openmw/mwmechanics/character.hpp | 6 -- .../mwmechanics/mechanicsmanagerimp.cpp | 2 +- 7 files changed, 124 insertions(+), 55 deletions(-) create mode 100644 apps/openmw/mwmechanics/actor.cpp create mode 100644 apps/openmw/mwmechanics/actor.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 28eadc517..c645e1a0a 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -76,7 +76,7 @@ add_openmw_dir (mwmechanics mechanicsmanagerimp stat character creaturestats magiceffects movement actors objects drawstate spells activespells npcstats aipackage aisequence aipursue alchemy aiwander aitravel aifollow aiavoiddoor aiescort aiactivate aicombat repair enchanting pathfinding pathgrid security spellsuccess spellcasting - disease pickpocket levelledlist combat steering obstacle autocalcspell difficultyscaling aicombataction + disease pickpocket levelledlist combat steering obstacle autocalcspell difficultyscaling aicombataction actor ) add_openmw_dir (mwstate diff --git a/apps/openmw/mwmechanics/actor.cpp b/apps/openmw/mwmechanics/actor.cpp new file mode 100644 index 000000000..675bd160a --- /dev/null +++ b/apps/openmw/mwmechanics/actor.cpp @@ -0,0 +1,28 @@ +#include "actor.hpp" + +#include "character.hpp" + +namespace MWMechanics +{ + + Actor::Actor(const MWWorld::Ptr &ptr, MWRender::Animation *animation) + { + mCharacterController.reset(new CharacterController(ptr, animation)); + } + + void Actor::updatePtr(const MWWorld::Ptr &newPtr) + { + mCharacterController->updatePtr(newPtr); + } + + CharacterController* Actor::getCharacterController() + { + return mCharacterController.get(); + } + + AiState& Actor::getAiState() + { + return mAiState; + } + +} diff --git a/apps/openmw/mwmechanics/actor.hpp b/apps/openmw/mwmechanics/actor.hpp new file mode 100644 index 000000000..846af1467 --- /dev/null +++ b/apps/openmw/mwmechanics/actor.hpp @@ -0,0 +1,42 @@ +#ifndef OPENMW_MECHANICS_ACTOR_H +#define OPENMW_MECHANICS_ACTOR_H + +#include + +#include "aistate.hpp" + +namespace MWRender +{ + class Animation; +} +namespace MWWorld +{ + class Ptr; +} + +namespace MWMechanics +{ + class CharacterController; + + /// @brief Holds temporary state for an actor that will be discarded when the actor leaves the scene. + class Actor + { + public: + Actor(const MWWorld::Ptr& ptr, MWRender::Animation* animation); + + /// Notify this actor of its new base object Ptr, use when the object changed cells + void updatePtr(const MWWorld::Ptr& newPtr); + + CharacterController* getCharacterController(); + + AiState& getAiState(); + + private: + std::auto_ptr mCharacterController; + + AiState mAiState; + }; + +} + +#endif diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index f824fd6f4..1a1d8c154 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -35,6 +35,8 @@ #include "aifollow.hpp" #include "aipursue.hpp" +#include "actor.hpp" + namespace { @@ -920,10 +922,10 @@ namespace MWMechanics void Actors::updateDrowning(const MWWorld::Ptr& ptr, float duration) { - PtrControllerMap::iterator it = mActors.find(ptr); + PtrActorMap::iterator it = mActors.find(ptr); if (it == mActors.end()) return; - CharacterController* ctrl = it->second; + CharacterController* ctrl = it->second->getCharacterController(); NpcStats &stats = ptr.getClass().getNpcStats(ptr); MWBase::World *world = MWBase::Environment::get().getWorld(); @@ -1128,14 +1130,14 @@ namespace MWMechanics removeActor(ptr); MWRender::Animation *anim = MWBase::Environment::get().getWorld()->getAnimation(ptr); - mActors.insert(std::make_pair(ptr, new CharacterController(ptr, anim))); + mActors.insert(std::make_pair(ptr, new Actor(ptr, anim))); if (updateImmediately) - mActors[ptr]->update(0); + mActors[ptr]->getCharacterController()->update(0); } void Actors::removeActor (const MWWorld::Ptr& ptr) { - PtrControllerMap::iterator iter = mActors.find(ptr); + PtrActorMap::iterator iter = mActors.find(ptr); if(iter != mActors.end()) { delete iter->second; @@ -1145,20 +1147,20 @@ namespace MWMechanics void Actors::updateActor(const MWWorld::Ptr &old, const MWWorld::Ptr &ptr) { - PtrControllerMap::iterator iter = mActors.find(old); + PtrActorMap::iterator iter = mActors.find(old); if(iter != mActors.end()) { - CharacterController *ctrl = iter->second; + Actor *actor = iter->second; mActors.erase(iter); - ctrl->updatePtr(ptr); - mActors.insert(std::make_pair(ptr, ctrl)); + actor->updatePtr(ptr); + mActors.insert(std::make_pair(ptr, actor)); } } void Actors::dropActors (const MWWorld::CellStore *cellStore, const MWWorld::Ptr& ignore) { - PtrControllerMap::iterator iter = mActors.begin(); + PtrActorMap::iterator iter = mActors.begin(); while(iter != mActors.end()) { if(iter->first.getCell()==cellStore && iter->first != ignore) @@ -1192,8 +1194,10 @@ namespace MWMechanics // using higher values will make a quest in Bloodmoon harder or impossible to complete (bug #1876) const float sqrProcessingDistance = 7168*7168; + /// \todo move update logic to Actor class where appropriate + // AI and magic effects update - for(PtrControllerMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter) + for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter) { if (!iter->first.getClass().getCreatureStats(iter->first).isDead()) { @@ -1207,7 +1211,7 @@ namespace MWMechanics if (iter->first != player) adjustCommandedActor(iter->first); - for(PtrControllerMap::iterator it(mActors.begin()); it != mActors.end(); ++it) + for(PtrActorMap::iterator it(mActors.begin()); it != mActors.end(); ++it) { if (it->first == iter->first || iter->first == player) // player is not AI-controlled continue; @@ -1219,13 +1223,13 @@ namespace MWMechanics float sqrHeadTrackDistance = std::numeric_limits::max(); MWWorld::Ptr headTrackTarget; - for(PtrControllerMap::iterator it(mActors.begin()); it != mActors.end(); ++it) + for(PtrActorMap::iterator it(mActors.begin()); it != mActors.end(); ++it) { if (it->first == iter->first) continue; updateHeadTracking(iter->first, it->first, headTrackTarget, sqrHeadTrackDistance); } - iter->second->setHeadTrackTarget(headTrackTarget); + iter->second->getCharacterController()->setHeadTrackTarget(headTrackTarget); } if (iter->first.getClass().isNpc() && iter->first != player) @@ -1254,12 +1258,12 @@ namespace MWMechanics // Reaching the text keys may trigger Hit / Spellcast (and as such, particles), // so updating VFX immediately after that would just remove the particle effects instantly. // There needs to be a magic effect update in between. - for(PtrControllerMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter) - iter->second->updateContinuousVfx(); + for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter) + iter->second->getCharacterController()->updateContinuousVfx(); // Animation/movement update CharacterController* playerCharacter = NULL; - for(PtrControllerMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter) + for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter) { if (iter->first != player && Ogre::Vector3(player.getRefData().getPosition().pos).squaredDistance(Ogre::Vector3(iter->first.getRefData().getPosition().pos)) @@ -1268,22 +1272,22 @@ namespace MWMechanics if (iter->first.getClass().getCreatureStats(iter->first).getMagicEffects().get( ESM::MagicEffect::Paralyze).getMagnitude() > 0) - iter->second->skipAnim(); + iter->second->getCharacterController()->skipAnim(); // Handle player last, in case a cell transition occurs by casting a teleportation spell // (would invalidate the iterator) if (iter->first.getCellRef().getRefId() == "player") { - playerCharacter = iter->second; + playerCharacter = iter->second->getCharacterController(); continue; } - iter->second->update(duration); + iter->second->getCharacterController()->update(duration); } if (playerCharacter) playerCharacter->update(duration); - for(PtrControllerMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter) + for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter) { const MWWorld::Class &cls = iter->first.getClass(); CreatureStats &stats = cls.getCreatureStats(iter->first); @@ -1341,7 +1345,7 @@ namespace MWMechanics bool detected = false; - for (PtrControllerMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter) + for (PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter) { if (iter->first == player) // not the player continue; @@ -1384,32 +1388,32 @@ namespace MWMechanics void Actors::killDeadActors() { - for(PtrControllerMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter) + for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter) { const MWWorld::Class &cls = iter->first.getClass(); CreatureStats &stats = cls.getCreatureStats(iter->first); if(!stats.isDead()) { - if(iter->second->isDead()) + if(iter->second->getCharacterController()->isDead()) { // Actor has been resurrected. Notify the CharacterController and re-enable collision. MWBase::Environment::get().getWorld()->enableActorCollision(iter->first, true); - iter->second->resurrect(); + iter->second->getCharacterController()->resurrect(); } if(!stats.isDead()) continue; } - if (iter->second->kill()) + if (iter->second->getCharacterController()->kill()) { iter->first.getClass().getCreatureStats(iter->first).notifyDied(); ++mDeathCount[Misc::StringUtils::lowerCase(iter->first.getCellRef().getRefId())]; // Make sure spell effects with CasterLinked flag are removed - for (PtrControllerMap::iterator iter2(mActors.begin());iter2 != mActors.end();++iter2) + for (PtrActorMap::iterator iter2(mActors.begin());iter2 != mActors.end();++iter2) { MWMechanics::ActiveSpells& spells = iter2->first.getClass().getCreatureStats(iter2->first).getActiveSpells(); spells.purge(stats.getActorId()); @@ -1438,7 +1442,7 @@ namespace MWMechanics void Actors::restoreDynamicStats(bool sleep) { - for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) + for(PtrActorMap::iterator iter(mActors.begin());iter != mActors.end();++iter) restoreDynamicStats(iter->first, sleep); } @@ -1470,35 +1474,35 @@ namespace MWMechanics void Actors::forceStateUpdate(const MWWorld::Ptr & ptr) { - PtrControllerMap::iterator iter = mActors.find(ptr); + PtrActorMap::iterator iter = mActors.find(ptr); if(iter != mActors.end()) - iter->second->forceStateUpdate(); + iter->second->getCharacterController()->forceStateUpdate(); } void Actors::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number) { - PtrControllerMap::iterator iter = mActors.find(ptr); + PtrActorMap::iterator iter = mActors.find(ptr); if(iter != mActors.end()) - iter->second->playGroup(groupName, mode, number); + iter->second->getCharacterController()->playGroup(groupName, mode, number); } void Actors::skipAnimation(const MWWorld::Ptr& ptr) { - PtrControllerMap::iterator iter = mActors.find(ptr); + PtrActorMap::iterator iter = mActors.find(ptr); if(iter != mActors.end()) - iter->second->skipAnim(); + iter->second->getCharacterController()->skipAnim(); } bool Actors::checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string& groupName) { - PtrControllerMap::iterator iter = mActors.find(ptr); + PtrActorMap::iterator iter = mActors.find(ptr); if(iter != mActors.end()) - return iter->second->isAnimPlaying(groupName); + return iter->second->getCharacterController()->isAnimPlaying(groupName); return false; } void Actors::getObjectsInRange(const Ogre::Vector3& position, float radius, std::vector& out) { - for (PtrControllerMap::iterator iter = mActors.begin(); iter != mActors.end(); ++iter) + for (PtrActorMap::iterator iter = mActors.begin(); iter != mActors.end(); ++iter) { if (Ogre::Vector3(iter->first.getRefData().getPosition().pos).squaredDistance(position) <= radius*radius) out.push_back(iter->first); @@ -1508,7 +1512,7 @@ namespace MWMechanics std::list Actors::getActorsFollowing(const MWWorld::Ptr& actor) { std::list list; - for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) + for(PtrActorMap::iterator iter(mActors.begin());iter != mActors.end();++iter) { const MWWorld::Class &cls = iter->first.getClass(); CreatureStats &stats = cls.getCreatureStats(iter->first); @@ -1538,7 +1542,7 @@ namespace MWMechanics std::list Actors::getActorsFollowingIndices(const MWWorld::Ptr &actor) { std::list list; - for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) + for(PtrActorMap::iterator iter(mActors.begin());iter != mActors.end();++iter) { const MWWorld::Class &cls = iter->first.getClass(); CreatureStats &stats = cls.getCreatureStats(iter->first); @@ -1611,7 +1615,7 @@ namespace MWMechanics void Actors::clear() { - PtrControllerMap::iterator it(mActors.begin()); + PtrActorMap::iterator it(mActors.begin()); for (; it != mActors.end(); ++it) { delete it->second; @@ -1631,10 +1635,10 @@ namespace MWMechanics bool Actors::isReadyToBlock(const MWWorld::Ptr &ptr) const { - PtrControllerMap::const_iterator it = mActors.find(ptr); + PtrActorMap::const_iterator it = mActors.find(ptr); if (it == mActors.end()) return false; - return it->second->isReadyToBlock(); + return it->second->getCharacterController()->isReadyToBlock(); } } diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index 321229571..91bfad170 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -6,7 +6,6 @@ #include #include -#include "character.hpp" #include "movement.hpp" #include "../mwbase/world.hpp" @@ -23,6 +22,8 @@ namespace MWWorld namespace MWMechanics { + class Actor; + class Actors { std::map mDeathCount; @@ -51,10 +52,10 @@ namespace MWMechanics Actors(); ~Actors(); - typedef std::map PtrControllerMap; + typedef std::map PtrActorMap; - PtrControllerMap::const_iterator begin() { return mActors.begin(); } - PtrControllerMap::const_iterator end() { return mActors.end(); } + PtrActorMap::const_iterator begin() { return mActors.begin(); } + PtrActorMap::const_iterator end() { return mActors.end(); } /// Update magic effects for an actor. Usually done automatically once per frame, but if we're currently /// paused we may want to do it manually (after equipping permanent enchantment) @@ -131,7 +132,7 @@ namespace MWMechanics bool isReadyToBlock(const MWWorld::Ptr& ptr) const; private: - PtrControllerMap mActors; + PtrActorMap mActors; }; } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 5b2c57b0a..8a77494b9 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -6,7 +6,6 @@ #include #include "../mwworld/ptr.hpp" -#include "aistate.hpp" namespace MWWorld { @@ -140,9 +139,6 @@ class CharacterController MWWorld::Ptr mPtr; MWRender::Animation *mAnimation; - // - AiState mAiState; - typedef std::deque > AnimationQueue; AnimationQueue mAnimQueue; @@ -229,8 +225,6 @@ public: void forceStateUpdate(); - AiState& getAiState() { return mAiState; } - bool isReadyToBlock() const; bool isKnockedOut() const; diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 54d53512a..20c52e7b4 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1289,7 +1289,7 @@ namespace MWMechanics // if guard starts combat with player, guards pursuing player should do the same if (ptr.getClass().isClass(ptr, "Guard")) { - for (Actors::PtrControllerMap::const_iterator iter = mActors.begin(); iter != mActors.end(); ++iter) + for (Actors::PtrActorMap::const_iterator iter = mActors.begin(); iter != mActors.end(); ++iter) { if (iter->first.getClass().isClass(iter->first, "Guard")) { From e5de253169f529c9e81ccabc3690f5ca4f05647a Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 21 Dec 2014 16:56:14 +0100 Subject: [PATCH 0119/3725] Use maximum step size of 62 units for stepping down (Fixes #1809) --- apps/openmw/mwworld/physicssystem.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 3879e0cd0..af1191ad9 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -93,7 +93,9 @@ namespace MWWorld { static const float sMaxSlope = 49.0f; - static const float sStepSize = 32.0f; + static const float sStepSizeUp = 34.0f; + static const float sStepSizeDown = 62.0f; + // Arbitrary number. To prevent infinite loops. They shouldn't happen but it's good to be prepared. static const int sMaxIterations = 8; @@ -155,7 +157,7 @@ namespace MWWorld */ OEngine::Physic::ActorTracer tracer, stepper; - stepper.doTrace(colobj, position, position+Ogre::Vector3(0.0f,0.0f,sStepSize), engine); + stepper.doTrace(colobj, position, position+Ogre::Vector3(0.0f,0.0f,sStepSizeUp), engine); if(stepper.mFraction < std::numeric_limits::epsilon()) return false; // didn't even move the smallest representable amount // (TODO: shouldn't this be larger? Why bother with such a small amount?) @@ -178,7 +180,7 @@ namespace MWWorld return false; // didn't even move the smallest representable amount /* - * Try moving back down sStepSize using stepper. + * Try moving back down sStepSizeDown using stepper. * NOTE: if there is an obstacle below (e.g. stairs), we'll be "stepping up". * Below diagram is the case where we "stepped over" an obstacle in front. * @@ -192,7 +194,7 @@ namespace MWWorld * +--+ +--+ * ============================================== */ - stepper.doTrace(colobj, tracer.mEndPos, tracer.mEndPos-Ogre::Vector3(0.0f,0.0f,sStepSize), engine); + stepper.doTrace(colobj, tracer.mEndPos, tracer.mEndPos-Ogre::Vector3(0.0f,0.0f,sStepSizeDown), engine); if(stepper.mFraction < 1.0f && getSlope(stepper.mPlaneNormal) <= sMaxSlope) { // don't allow stepping up other actors @@ -453,7 +455,7 @@ namespace MWWorld { Ogre::Vector3 from = newPosition; Ogre::Vector3 to = newPosition - (physicActor->getOnGround() ? - Ogre::Vector3(0,0,sStepSize+2.f) : Ogre::Vector3(0,0,2.f)); + Ogre::Vector3(0,0,sStepSizeDown+2.f) : Ogre::Vector3(0,0,2.f)); tracer.doTrace(colobj, from, to, engine); if(tracer.mFraction < 1.0f && getSlope(tracer.mPlaneNormal) <= sMaxSlope && tracer.mHitObject->getBroadphaseHandle()->m_collisionFilterGroup != OEngine::Physic::CollisionType_Actor) From 019cd96719b4338415d1913aa936215b5b80d227 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 21 Dec 2014 17:34:34 +0100 Subject: [PATCH 0120/3725] Stop AiPursue when target has invisibility or chameleon>=75 --- apps/openmw/mwmechanics/aipursue.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/openmw/mwmechanics/aipursue.cpp b/apps/openmw/mwmechanics/aipursue.cpp index 0c3de9643..8c31a10db 100644 --- a/apps/openmw/mwmechanics/aipursue.cpp +++ b/apps/openmw/mwmechanics/aipursue.cpp @@ -43,6 +43,10 @@ bool AiPursue::execute (const MWWorld::Ptr& actor, AiState& state, float duratio ) return true; //Target doesn't exist + if (target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::Invisibility).getMagnitude() > 0 + || target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::Chameleon).getMagnitude() > 75) + return true; + if(target.getClass().getCreatureStats(target).isDead()) return true; From d55fe43fc95bfaec681c65b57aff378e6703f894 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 22 Dec 2014 18:50:24 +0100 Subject: [PATCH 0121/3725] Support animation groups for Light and Door objects (Fixes #2039) --- apps/openmw/mwclass/door.cpp | 8 +++++-- apps/openmw/mwclass/light.cpp | 9 +++++--- apps/openmw/mwrender/activatoranimation.cpp | 25 +++++++++++++++++++++ apps/openmw/mwrender/activatoranimation.hpp | 3 +++ apps/openmw/mwrender/actors.cpp | 11 ++++++++- apps/openmw/mwrender/actors.hpp | 2 +- apps/openmw/mwrender/animation.cpp | 17 -------------- apps/openmw/mwrender/animation.hpp | 3 --- apps/openmw/mwrender/objects.cpp | 10 +-------- apps/openmw/mwrender/objects.hpp | 2 +- 10 files changed, 53 insertions(+), 37 deletions(-) diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index fa9db9e16..41f9f3686 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -8,6 +8,7 @@ #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwbase/soundmanager.hpp" +#include "../mwbase/mechanicsmanager.hpp" #include "../mwworld/ptr.hpp" #include "../mwworld/nullaction.hpp" @@ -22,7 +23,7 @@ #include "../mwgui/tooltips.hpp" -#include "../mwrender/objects.hpp" +#include "../mwrender/actors.hpp" #include "../mwrender/renderinginterface.hpp" namespace @@ -51,7 +52,8 @@ namespace MWClass { const std::string model = getModel(ptr); if (!model.empty()) { - renderingInterface.getObjects().insertModel(ptr, model); + MWRender::Actors& actors = renderingInterface.getActors(); + actors.insertActivator(ptr); } } @@ -70,6 +72,8 @@ namespace MWClass MWBase::Environment::get().getWorld()->activateDoor(ptr, customData.mDoorState); } } + + MWBase::Environment::get().getMechanicsManager()->add(ptr); } std::string Door::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index e6d266de2..7ad81232d 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -8,6 +8,7 @@ #include "../mwbase/world.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwbase/mechanicsmanager.hpp" #include "../mwworld/ptr.hpp" #include "../mwworld/actiontake.hpp" @@ -22,6 +23,7 @@ #include "../mwgui/tooltips.hpp" #include "../mwrender/objects.hpp" +#include "../mwrender/actors.hpp" #include "../mwrender/renderinginterface.hpp" namespace @@ -54,13 +56,12 @@ namespace MWClass void Light::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const { - const std::string model = getModel(ptr); - MWWorld::LiveCellRef *ref = ptr.get(); // Insert even if model is empty, so that the light is added - renderingInterface.getObjects().insertModel(ptr, model, false, !(ref->mBase->mData.mFlags & ESM::Light::OffDefault)); + MWRender::Actors& actors = renderingInterface.getActors(); + actors.insertActivator(ptr, !(ref->mBase->mData.mFlags & ESM::Light::OffDefault)); } void Light::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const @@ -78,6 +79,8 @@ namespace MWClass MWBase::Environment::get().getSoundManager()->playSound3D(ptr, ref->mBase->mSound, 1.0, 1.0, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_Loop); + + MWBase::Environment::get().getMechanicsManager()->add(ptr); } std::string Light::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwrender/activatoranimation.cpp b/apps/openmw/mwrender/activatoranimation.cpp index 540876a3e..4c63e2cf2 100644 --- a/apps/openmw/mwrender/activatoranimation.cpp +++ b/apps/openmw/mwrender/activatoranimation.cpp @@ -1,5 +1,8 @@ #include "activatoranimation.hpp" +#include +#include + #include #include "../mwbase/world.hpp" @@ -27,6 +30,28 @@ ActivatorAnimation::ActivatorAnimation(const MWWorld::Ptr &ptr) addAnimSource(model); } + else + { + // No model given. Create an object root anyway, so that lights can be added to it if needed. + mObjectRoot = NifOgre::ObjectScenePtr (new NifOgre::ObjectScene(mInsert->getCreator())); + } +} + +void ActivatorAnimation::addLight(const ESM::Light *light) +{ + addExtraLight(mInsert->getCreator(), mObjectRoot, light); +} + +void ActivatorAnimation::removeParticles() +{ + for (unsigned int i=0; imParticles.size(); ++i) + { + // Don't destroyParticleSystem, the ParticleSystemController is still holding a pointer to it. + // Don't setVisible, this could conflict with a VisController. + // The following will remove all spawned particles, then set the speed factor to zero so that no new ones will be spawned. + mObjectRoot->mParticles[i]->setSpeedFactor(0.f); + mObjectRoot->mParticles[i]->clear(); + } } } diff --git a/apps/openmw/mwrender/activatoranimation.hpp b/apps/openmw/mwrender/activatoranimation.hpp index eb3e5815e..ec0114ccd 100644 --- a/apps/openmw/mwrender/activatoranimation.hpp +++ b/apps/openmw/mwrender/activatoranimation.hpp @@ -15,6 +15,9 @@ namespace MWRender public: ActivatorAnimation(const MWWorld::Ptr& ptr); virtual ~ActivatorAnimation(); + + void addLight(const ESM::Light *light); + void removeParticles(); }; } diff --git a/apps/openmw/mwrender/actors.cpp b/apps/openmw/mwrender/actors.cpp index b7e9f5730..06acf4b3c 100644 --- a/apps/openmw/mwrender/actors.cpp +++ b/apps/openmw/mwrender/actors.cpp @@ -83,10 +83,19 @@ void Actors::insertCreature (const MWWorld::Ptr& ptr, bool weaponsShields) mAllActors[ptr] = anim; mRendering->addWaterRippleEmitter (ptr); } -void Actors::insertActivator (const MWWorld::Ptr& ptr) +void Actors::insertActivator (const MWWorld::Ptr& ptr, bool addLight) { insertBegin(ptr); ActivatorAnimation* anim = new ActivatorAnimation(ptr); + + if(ptr.getTypeName() == typeid(ESM::Light).name()) + { + if (addLight) + anim->addLight(ptr.get()->mBase); + else + anim->removeParticles(); + } + delete mAllActors[ptr]; mAllActors[ptr] = anim; } diff --git a/apps/openmw/mwrender/actors.hpp b/apps/openmw/mwrender/actors.hpp index d5d6c52bb..177c8a732 100644 --- a/apps/openmw/mwrender/actors.hpp +++ b/apps/openmw/mwrender/actors.hpp @@ -41,7 +41,7 @@ namespace MWRender void insertNPC(const MWWorld::Ptr& ptr); void insertCreature (const MWWorld::Ptr& ptr, bool weaponsShields); - void insertActivator (const MWWorld::Ptr& ptr); + void insertActivator (const MWWorld::Ptr& ptr, bool addLight=false); bool deleteObject (const MWWorld::Ptr& ptr); ///< \return found? diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 4894378c7..af9fdf853 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1507,23 +1507,6 @@ ObjectAnimation::ObjectAnimation(const MWWorld::Ptr& ptr, const std::string &mod } } -void ObjectAnimation::addLight(const ESM::Light *light) -{ - addExtraLight(mInsert->getCreator(), mObjectRoot, light); -} - -void ObjectAnimation::removeParticles() -{ - for (unsigned int i=0; imParticles.size(); ++i) - { - // Don't destroyParticleSystem, the ParticleSystemController is still holding a pointer to it. - // Don't setVisible, this could conflict with a VisController. - // The following will remove all spawned particles, then set the speed factor to zero so that no new ones will be spawned. - mObjectRoot->mParticles[i]->setSpeedFactor(0.f); - mObjectRoot->mParticles[i]->clear(); - } -} - class FindEntityTransparency { public: diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 712069036..73d10fd06 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -346,9 +346,6 @@ class ObjectAnimation : public Animation { public: ObjectAnimation(const MWWorld::Ptr& ptr, const std::string &model); - void addLight(const ESM::Light *light); - void removeParticles(); - bool canBatch() const; void fillBatch(Ogre::StaticGeometry *sg); }; diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 96decbb36..96cce178e 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -73,20 +73,12 @@ void Objects::insertBegin(const MWWorld::Ptr& ptr) ptr.getRefData().setBaseNode(insert); } -void Objects::insertModel(const MWWorld::Ptr &ptr, const std::string &mesh, bool batch, bool addLight) +void Objects::insertModel(const MWWorld::Ptr &ptr, const std::string &mesh, bool batch) { insertBegin(ptr); std::auto_ptr anim(new ObjectAnimation(ptr, mesh)); - if(ptr.getTypeName() == typeid(ESM::Light).name()) - { - if (addLight) - anim->addLight(ptr.get()->mBase); - else - anim->removeParticles(); - } - if (!mesh.empty()) { Ogre::AxisAlignedBox bounds = anim->getWorldBounds(); diff --git a/apps/openmw/mwrender/objects.hpp b/apps/openmw/mwrender/objects.hpp index 7f740dbab..02e974e2d 100644 --- a/apps/openmw/mwrender/objects.hpp +++ b/apps/openmw/mwrender/objects.hpp @@ -41,7 +41,7 @@ public: , mRootNode(NULL) {} ~Objects(){} - void insertModel(const MWWorld::Ptr& ptr, const std::string &model, bool batch=false, bool addLight=false); + void insertModel(const MWWorld::Ptr& ptr, const std::string &model, bool batch=false); ObjectAnimation* getAnimation(const MWWorld::Ptr &ptr); From 59f21c61058e6966566440649aa3dc9f16d4e2bd Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 22 Dec 2014 19:58:18 +0100 Subject: [PATCH 0122/3725] Use "hair" as filter for PRT_Hair parts (Fixes #2218) --- apps/openmw/mwrender/animation.cpp | 2 +- apps/openmw/mwrender/creatureanimation.cpp | 2 +- apps/openmw/mwrender/npcanimation.cpp | 11 +++++++---- apps/openmw/mwrender/npcanimation.hpp | 1 + apps/openmw/mwrender/weaponanimation.cpp | 7 +++++-- components/nifogre/ogrenifloader.cpp | 9 ++++----- components/nifogre/ogrenifloader.hpp | 1 + 7 files changed, 20 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index af9fdf853..a922fa170 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1270,7 +1270,7 @@ void Animation::addEffect(const std::string &model, int effectId, bool loop, con if (bonename.empty()) params.mObjects = NifOgre::Loader::createObjects(mInsert, model); else - params.mObjects = NifOgre::Loader::createObjects(mSkelBase, bonename, mInsert, model); + params.mObjects = NifOgre::Loader::createObjects(mSkelBase, bonename, "", mInsert, model); // TODO: turn off shadow casting setRenderProperties(params.mObjects, RV_Misc, diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index fef9fa644..c1957d7a8 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -106,7 +106,7 @@ void CreatureWeaponAnimation::updatePart(NifOgre::ObjectScenePtr& scene, int slo else bonename = "Shield Bone"; - scene = NifOgre::Loader::createObjects(mSkelBase, bonename, mInsert, item.getClass().getModel(item)); + scene = NifOgre::Loader::createObjects(mSkelBase, bonename, bonename, mInsert, item.getClass().getModel(item)); Ogre::Vector3 glowColor = getEnchantmentColor(item); setRenderProperties(scene, RV_Actors, RQG_Main, RQG_Alpha, 0, diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 3b0b4e08b..1cc9ad232 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -160,7 +160,7 @@ static NpcAnimation::PartBoneMap createPartListMap() { NpcAnimation::PartBoneMap result; result.insert(std::make_pair(ESM::PRT_Head, "Head")); - result.insert(std::make_pair(ESM::PRT_Hair, "Head")); + result.insert(std::make_pair(ESM::PRT_Hair, "Head")); // note it uses "Head" as attach bone, but "Hair" as filter result.insert(std::make_pair(ESM::PRT_Neck, "Neck")); result.insert(std::make_pair(ESM::PRT_Cuirass, "Chest")); result.insert(std::make_pair(ESM::PRT_Groin, "Groin")); @@ -574,9 +574,9 @@ public: } }; -NifOgre::ObjectScenePtr NpcAnimation::insertBoundedPart(const std::string &model, int group, const std::string &bonename, bool enchantedGlow, Ogre::Vector3* glowColor) +NifOgre::ObjectScenePtr NpcAnimation::insertBoundedPart(const std::string &model, int group, const std::string &bonename, const std::string &bonefilter, bool enchantedGlow, Ogre::Vector3* glowColor) { - NifOgre::ObjectScenePtr objects = NifOgre::Loader::createObjects(mSkelBase, bonename, mInsert, model); + NifOgre::ObjectScenePtr objects = NifOgre::Loader::createObjects(mSkelBase, bonename, bonefilter, mInsert, model); setRenderProperties(objects, (mViewMode == VM_FirstPerson) ? RV_FirstPerson : mVisibilityFlags, RQG_Main, RQG_Alpha, 0, enchantedGlow, glowColor); @@ -690,7 +690,10 @@ bool NpcAnimation::addOrReplaceIndividualPart(ESM::PartReferenceType type, int g mPartPriorities[type] = priority; try { - mObjectParts[type] = insertBoundedPart(mesh, group, sPartList.at(type), enchantedGlow, glowColor); + const std::string& bonename = sPartList.at(type); + // PRT_Hair seems to be the only type that breaks consistency and uses a filter that's different from the attachment bone + const std::string bonefilter = (type == ESM::PRT_Hair) ? "hair" : bonename; + mObjectParts[type] = insertBoundedPart(mesh, group, bonename, bonefilter, enchantedGlow, glowColor); } catch (std::exception& e) { diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index f3603fe14..90b1c269b 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -106,6 +106,7 @@ private: void updateNpcBase(); NifOgre::ObjectScenePtr insertBoundedPart(const std::string &model, int group, const std::string &bonename, + const std::string &bonefilter, bool enchantedGlow, Ogre::Vector3* glowColor=NULL); void removeIndividualPart(ESM::PartReferenceType type); diff --git a/apps/openmw/mwrender/weaponanimation.cpp b/apps/openmw/mwrender/weaponanimation.cpp index c59a93feb..7a52ce7ea 100644 --- a/apps/openmw/mwrender/weaponanimation.cpp +++ b/apps/openmw/mwrender/weaponanimation.cpp @@ -55,8 +55,11 @@ void WeaponAnimation::attachArrow(MWWorld::Ptr actor) return; std::string model = ammo->getClass().getModel(*ammo); - assert(weapon->mSkelBase && "Need a skeleton to attach the arrow to"); - mAmmunition = NifOgre::Loader::createObjects(weapon->mSkelBase, "ArrowBone", weapon->mSkelBase->getParentSceneNode(), model); + if (!weapon->mSkelBase) + throw std::runtime_error("Need a skeleton to attach the arrow to"); + + const std::string bonename = "ArrowBone"; + mAmmunition = NifOgre::Loader::createObjects(weapon->mSkelBase, bonename, bonename, weapon->mSkelBase->getParentSceneNode(), model); configureAddedObject(mAmmunition, *ammo, MWWorld::InventoryStore::Slot_Ammunition); } } diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index ef4b9e985..b55248784 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -1383,6 +1383,7 @@ ObjectScenePtr Loader::createObjects(Ogre::SceneNode *parentNode, std::string na } ObjectScenePtr Loader::createObjects(Ogre::Entity *parent, const std::string &bonename, + const std::string& bonefilter, Ogre::SceneNode *parentNode, std::string name, const std::string &group) { @@ -1408,11 +1409,9 @@ ObjectScenePtr Loader::createObjects(Ogre::Entity *parent, const std::string &bo if(isskinned) { - // Apparently both are allowed. Sigh. - // This could also mean that filters are supposed to work on the actual node - // hierarchy, rather than just trishapes, and the 'tri ' should be omitted? - std::string filter = "@shape=tri "+bonename; - std::string filter2 = "@shape="+bonename; + // accepts anything named "filter*" or "tri filter*" + std::string filter = "@shape=tri "+bonefilter; + std::string filter2 = "@shape="+bonefilter; Misc::StringUtils::toLower(filter); Misc::StringUtils::toLower(filter2); for(size_t i = 0;i < scene->mEntities.size();i++) diff --git a/components/nifogre/ogrenifloader.hpp b/components/nifogre/ogrenifloader.hpp index 485495a38..fd5ddca7d 100644 --- a/components/nifogre/ogrenifloader.hpp +++ b/components/nifogre/ogrenifloader.hpp @@ -97,6 +97,7 @@ class Loader { public: static ObjectScenePtr createObjects(Ogre::Entity *parent, const std::string &bonename, + const std::string& filter, Ogre::SceneNode *parentNode, std::string name, const std::string &group="General"); From 7f0d71f8f49c77cf3bccde32b2e8fd2600157de7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 22 Dec 2014 23:58:16 +0100 Subject: [PATCH 0123/3725] Swap use of iDispAttackMod/fDispAttacking (thanks Hrnchamd) --- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 20c52e7b4..5c4422fa1 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1025,8 +1025,8 @@ namespace MWMechanics else if (type == OT_Assault) { arg = store.find("iCrimeAttack")->getInt(); - disp = store.find("fDispAttacking")->getFloat(); - dispVictim = store.find("iDispAttackMod")->getInt(); + disp = store.find("iDispAttackMod")->getInt(); + dispVictim = store.find("fDispAttacking")->getFloat(); } else if (type == OT_Murder) { From a47de06492b2c671ec3b344f53be97b39d6aa107 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 23 Dec 2014 01:54:37 +0100 Subject: [PATCH 0124/3725] Make local map resolution configurable and use lower default value This seems to be the resolution the original engine is using. The change also significantly reduces cell loading time. --- apps/openmw/mwrender/globalmap.cpp | 6 ++++-- apps/openmw/mwrender/localmap.cpp | 5 +++-- apps/openmw/mwrender/localmap.hpp | 2 +- files/settings-default.cfg | 2 ++ 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/globalmap.cpp b/apps/openmw/mwrender/globalmap.cpp index fd8b91936..5546c401b 100644 --- a/apps/openmw/mwrender/globalmap.cpp +++ b/apps/openmw/mwrender/globalmap.cpp @@ -209,8 +209,10 @@ namespace MWRender if (!localMapTexture.isNull()) { + int mapWidth = localMapTexture->getWidth(); + int mapHeight = localMapTexture->getHeight(); mOverlayTexture->load(); - mOverlayTexture->getBuffer()->blit(localMapTexture->getBuffer(), Ogre::Image::Box(0,0,512,512), + mOverlayTexture->getBuffer()->blit(localMapTexture->getBuffer(), Ogre::Image::Box(0,0,mapWidth,mapHeight), Ogre::Image::Box(originX,originY,originX+mCellSize,originY+mCellSize)); Ogre::Image backup; @@ -218,7 +220,7 @@ namespace MWRender data.resize(mCellSize*mCellSize*4, 0); backup.loadDynamicImage(&data[0], mCellSize, mCellSize, Ogre::PF_A8B8G8R8); - localMapTexture->getBuffer()->blitToMemory(Ogre::Image::Box(0,0,512,512), backup.getPixelBox()); + localMapTexture->getBuffer()->blitToMemory(Ogre::Image::Box(0,0,mapWidth,mapHeight), backup.getPixelBox()); for (int x=0; xgetBuffer()->blit(mRenderTexture->getBuffer()); diff --git a/apps/openmw/mwrender/localmap.hpp b/apps/openmw/mwrender/localmap.hpp index 4c60cbb11..7cfa38814 100644 --- a/apps/openmw/mwrender/localmap.hpp +++ b/apps/openmw/mwrender/localmap.hpp @@ -87,7 +87,7 @@ namespace MWRender OEngine::Render::OgreRenderer* mRendering; MWRender::RenderingManager* mRenderingManager; - static const int sMapResolution = 512; + int mMapResolution; // the dynamic texture is a bottleneck, so don't set this too high static const int sFogOfWarResolution = 32; diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 7566994e2..658c2da6d 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -115,6 +115,8 @@ use static geometry = true # Adjusts the scale of the global map global map cell size = 18 +local map resolution = 256 + [Viewing distance] # Limit the rendering distance of small objects limit small object distance = false From 5d7dcafa53ef12f80c9249787ddfb72401dafd3d Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 23 Dec 2014 02:33:14 +0100 Subject: [PATCH 0125/3725] Make local map widget size configurable --- apps/openmw/mwgui/hud.cpp | 2 +- apps/openmw/mwgui/mapwindow.cpp | 38 ++++++++++++++-------------- apps/openmw/mwgui/mapwindow.hpp | 4 ++- files/mygui/openmw_hud.layout | 2 -- files/mygui/openmw_map_window.layout | 2 -- files/settings-default.cfg | 3 +++ 6 files changed, 26 insertions(+), 25 deletions(-) diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index a5703682f..2fd6dd6b9 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -162,7 +162,7 @@ namespace MWGui getWidget(mTriangleCounter, "TriangleCounter"); getWidget(mBatchCounter, "BatchCounter"); - LocalMapBase::init(mMinimap, mCompass); + LocalMapBase::init(mMinimap, mCompass, Settings::Manager::getInt("local map hud widget size", "Map")); mMainWidget->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onWorldClicked); mMainWidget->eventMouseMove += MyGUI::newDelegate(this, &HUD::onWorldMouseOver); diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 0262c4d0e..cc87cdd7b 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -22,8 +22,6 @@ namespace { - const int widgetSize = 512; - const int cellSize = 8192; enum LocalMapWidgetDepth @@ -164,6 +162,7 @@ namespace MWGui , mCompass(NULL) , mMarkerUpdateTimer(0.0f) , mCustomMarkers(markers) + , mMapWidgetSize(0) { mCustomMarkers.eventMarkersChanged += MyGUI::newDelegate(this, &LocalMapBase::updateCustomMarkers); } @@ -173,26 +172,28 @@ namespace MWGui mCustomMarkers.eventMarkersChanged -= MyGUI::newDelegate(this, &LocalMapBase::updateCustomMarkers); } - void LocalMapBase::init(MyGUI::ScrollView* widget, MyGUI::ImageBox* compass) + void LocalMapBase::init(MyGUI::ScrollView* widget, MyGUI::ImageBox* compass, int mapWidgetSize) { mLocalMap = widget; mCompass = compass; + mMapWidgetSize = mapWidgetSize; + + mLocalMap->setCanvasSize(mMapWidgetSize*3, mMapWidgetSize*3); mCompass->setDepth(Local_CompassLayer); mCompass->setNeedMouseFocus(false); - // create 3x3 map widgets, 512x512 each, holding a 1024x1024 texture each for (int mx=0; mx<3; ++mx) { for (int my=0; my<3; ++my) { MyGUI::ImageBox* map = mLocalMap->createWidget("ImageBox", - MyGUI::IntCoord(mx*widgetSize, my*widgetSize, widgetSize, widgetSize), + MyGUI::IntCoord(mx*mMapWidgetSize, my*mMapWidgetSize, mMapWidgetSize, mMapWidgetSize), MyGUI::Align::Top | MyGUI::Align::Left); map->setDepth(Local_MapLayer); MyGUI::ImageBox* fog = mLocalMap->createWidget("ImageBox", - MyGUI::IntCoord(mx*widgetSize, my*widgetSize, widgetSize, widgetSize), + MyGUI::IntCoord(mx*mMapWidgetSize, my*mMapWidgetSize, mMapWidgetSize, mMapWidgetSize), MyGUI::Align::Top | MyGUI::Align::Left); fog->setDepth(Local_FogLayer); @@ -258,8 +259,8 @@ namespace MWGui markerPos.cellX = cellX; markerPos.cellY = cellY; - widgetPos = MyGUI::IntPoint(nX * widgetSize + (1+cellDx) * widgetSize, - nY * widgetSize - (cellDy-1) * widgetSize); + widgetPos = MyGUI::IntPoint(nX * mMapWidgetSize + (1+cellDx) * mMapWidgetSize, + nY * mMapWidgetSize - (cellDy-1) * mMapWidgetSize); } else { @@ -271,8 +272,8 @@ namespace MWGui markerPos.cellY = cellY; // Image space is -Y up, cells are Y up - widgetPos = MyGUI::IntPoint(nX * widgetSize + (1+(cellX-mCurX)) * widgetSize, - nY * widgetSize + (1-(cellY-mCurY)) * widgetSize); + widgetPos = MyGUI::IntPoint(nX * mMapWidgetSize + (1+(cellX-mCurX)) * mMapWidgetSize, + nY * mMapWidgetSize + (1-(cellY-mCurY)) * mMapWidgetSize); } markerPos.nX = nX; @@ -425,9 +426,9 @@ namespace MWGui void LocalMapBase::setPlayerPos(int cellX, int cellY, const float nx, const float ny) { - MyGUI::IntPoint pos(widgetSize+nx*widgetSize-16, widgetSize+ny*widgetSize-16); - pos.left += (cellX - mCurX) * widgetSize; - pos.top -= (cellY - mCurY) * widgetSize; + MyGUI::IntPoint pos(mMapWidgetSize+nx*mMapWidgetSize-16, mMapWidgetSize+ny*mMapWidgetSize-16); + pos.left += (cellX - mCurX) * mMapWidgetSize; + pos.top -= (cellY - mCurY) * mMapWidgetSize; if (pos != mCompass->getPosition()) { @@ -612,8 +613,7 @@ namespace MWGui mEventBoxLocal->eventMouseButtonPressed += MyGUI::newDelegate(this, &MapWindow::onDragStart); mEventBoxLocal->eventMouseButtonDoubleClick += MyGUI::newDelegate(this, &MapWindow::onMapDoubleClicked); - LocalMapBase::init(mLocalMap, mPlayerArrowLocal); - } + LocalMapBase::init(mLocalMap, mPlayerArrowLocal, Settings::Manager::getInt("local map widget size", "Map")); } void MapWindow::onNoteEditOk() { @@ -657,10 +657,10 @@ namespace MWGui MyGUI::IntPoint clickedPos = MyGUI::InputManager::getInstance().getMousePosition(); MyGUI::IntPoint widgetPos = clickedPos - mEventBoxLocal->getAbsolutePosition(); - int x = int(widgetPos.left/float(widgetSize))-1; - int y = (int(widgetPos.top/float(widgetSize))-1)*-1; - float nX = widgetPos.left/float(widgetSize) - int(widgetPos.left/float(widgetSize)); - float nY = widgetPos.top/float(widgetSize) - int(widgetPos.top/float(widgetSize)); + int x = int(widgetPos.left/float(mMapWidgetSize))-1; + int y = (int(widgetPos.top/float(mMapWidgetSize))-1)*-1; + float nX = widgetPos.left/float(mMapWidgetSize) - int(widgetPos.left/float(mMapWidgetSize)); + float nY = widgetPos.top/float(mMapWidgetSize) - int(widgetPos.top/float(mMapWidgetSize)); x += mCurX; y += mCurY; diff --git a/apps/openmw/mwgui/mapwindow.hpp b/apps/openmw/mwgui/mapwindow.hpp index a8aaa8e45..118fee0f6 100644 --- a/apps/openmw/mwgui/mapwindow.hpp +++ b/apps/openmw/mwgui/mapwindow.hpp @@ -70,7 +70,7 @@ namespace MWGui public: LocalMapBase(CustomMarkerCollection& markers); virtual ~LocalMapBase(); - void init(MyGUI::ScrollView* widget, MyGUI::ImageBox* compass); + void init(MyGUI::ScrollView* widget, MyGUI::ImageBox* compass, int mapWidgetSize); void setCellPrefix(const std::string& prefix); void setActiveCell(const int x, const int y, bool interior=false); @@ -99,6 +99,8 @@ namespace MWGui bool mChanged; bool mFogOfWar; + int mMapWidgetSize; + // Stores markers that were placed by a player. May be shared between multiple map views. CustomMarkerCollection& mCustomMarkers; diff --git a/files/mygui/openmw_hud.layout b/files/mygui/openmw_hud.layout index 640e5867f..84fd9d247 100644 --- a/files/mygui/openmw_hud.layout +++ b/files/mygui/openmw_hud.layout @@ -108,8 +108,6 @@ - - diff --git a/files/mygui/openmw_map_window.layout b/files/mygui/openmw_map_window.layout index 605c3d6ff..b38097dce 100644 --- a/files/mygui/openmw_map_window.layout +++ b/files/mygui/openmw_map_window.layout @@ -6,8 +6,6 @@ - - diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 658c2da6d..530366e89 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -117,6 +117,9 @@ global map cell size = 18 local map resolution = 256 +local map widget size = 512 +local map hud widget size = 512 + [Viewing distance] # Limit the rendering distance of small objects limit small object distance = false From 9b33eca36879ad9cc4ae6dc17430510b14c399b4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 23 Dec 2014 02:33:29 +0100 Subject: [PATCH 0126/3725] Use scaling factor for HUD map to match original MW --- files/settings-default.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 530366e89..37e3d45fb 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -118,7 +118,7 @@ global map cell size = 18 local map resolution = 256 local map widget size = 512 -local map hud widget size = 512 +local map hud widget size = 256 [Viewing distance] # Limit the rendering distance of small objects From b8fa73dfa9c27733238f0f71800a018ac7c53cff Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 23 Dec 2014 15:28:02 +0100 Subject: [PATCH 0127/3725] Preserve record ordering in Store This fixes the default head/hair used for some races in the chargen UI. --- apps/openmw/mwgui/race.cpp | 13 +++++-- apps/openmw/mwworld/store.hpp | 69 ++++++++++++----------------------- 2 files changed, 32 insertions(+), 50 deletions(-) diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index bcb766f8f..925480334 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -345,8 +345,7 @@ namespace MWGui const MWWorld::Store &races = MWBase::Environment::get().getWorld()->getStore().get(); - - int index = 0; + std::map items; // ID, name MWWorld::Store::iterator it = races.begin(); for (; it != races.end(); ++it) { @@ -354,8 +353,14 @@ namespace MWGui if (!playable) // Only display playable races continue; - mRaceList->addItem(it->mName, it->mId); - if (Misc::StringUtils::ciEqual(it->mId, mCurrentRaceId)) + items[it->mId] = it->mName; + } + + int index = 0; + for (std::map::const_iterator it = items.begin(); it != items.end(); ++it) + { + mRaceList->addItem(it->second, it->first); + if (Misc::StringUtils::ciEqual(it->first, mCurrentRaceId)) mRaceList->setIndexSelected(index); ++index; } diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index 4fa8b7f54..dcfbb4eb1 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -99,7 +99,9 @@ namespace MWWorld class Store : public StoreBase { std::map mStatic; - std::vector mShared; + std::vector mShared; // Preserves the record order as it came from the content files (this + // is relevant for the spell autocalc code and selection order + // for heads/hairs in the character creation) std::map mDynamic; typedef std::map Dynamic; @@ -137,8 +139,9 @@ namespace MWWorld // setUp needs to be called again after virtual void clearDynamic() { + // remove the dynamic part of mShared + mShared.erase(mShared.begin() + mStatic.size(), mShared.end()); mDynamic.clear(); - mShared.clear(); } const T *search(const std::string &id) const { @@ -203,18 +206,18 @@ namespace MWWorld void load(ESM::ESMReader &esm, const std::string &id) { std::string idLower = Misc::StringUtils::lowerCase(id); - mStatic[idLower] = T(); - mStatic[idLower].mId = idLower; - mStatic[idLower].load(esm); + + std::pair inserted = mStatic.insert(std::make_pair(idLower, T())); + if (inserted.second) + mShared.push_back(&inserted.first->second); + + inserted.first->second.mId = idLower; + inserted.first->second.load(esm); } void setUp() { - mShared.clear(); - mShared.reserve(mStatic.size()); - typename std::map::iterator it = mStatic.begin(); - for (; it != mStatic.end(); ++it) { - mShared.push_back(&(it->second)); - } + // remove the dynamic part of mShared + mShared.erase(mShared.begin() + mStatic.size(), mShared.end()); } iterator begin() const { @@ -356,10 +359,9 @@ namespace MWWorld std::map::iterator it = mStatic.find(idLower); if (it == mStatic.end()) { it = mStatic.insert( std::make_pair( idLower, ESM::Dialogue() ) ).first; - it->second.mId = id; // don't smash case here, as this line is printed... I think + it->second.mId = id; // don't smash case here, as this line is printed } - //I am not sure is it need to load the dialog from a plugin if it was already loaded from prevois plugins it->second.load(esm); } @@ -368,7 +370,10 @@ namespace MWWorld ESM::Script scpt; scpt.load(esm); Misc::StringUtils::toLower(scpt.mId); - mStatic[scpt.mId] = scpt; + + std::pair inserted = mStatic.insert(std::make_pair(scpt.mId, scpt)); + if (inserted.second) + mShared.push_back(&inserted.first->second); } template <> @@ -376,7 +381,10 @@ namespace MWWorld ESM::StartScript s; s.load(esm); s.mId = Misc::StringUtils::toLower(s.mScript); - mStatic[s.mId] = s; + + std::pair inserted = mStatic.insert(std::make_pair(s.mId, s)); + if (inserted.second) + mShared.push_back(&inserted.first->second); } template <> @@ -1067,37 +1075,6 @@ namespace MWWorld } }; - - // Specialisation for ESM::Spell to preserve record order as it was in the content files. - // The NPC spell autocalc code heavily depends on this order. - // We could also do this in the base class, but it's usually not a good idea to depend on record order. - template<> - inline void Store::clearDynamic() - { - // remove the dynamic part of mShared - mShared.erase(mShared.begin() + mStatic.size(), mShared.end()); - mDynamic.clear(); - } - - template<> - inline void Store::load(ESM::ESMReader &esm, const std::string &id) { - std::string idLower = Misc::StringUtils::lowerCase(id); - - std::pair inserted = mStatic.insert(std::make_pair(idLower, ESM::Spell())); - if (inserted.second) - mShared.push_back(&mStatic[idLower]); - - inserted.first->second.mId = idLower; - inserted.first->second.load(esm); - } - - template<> - inline void Store::setUp() - { - // remove the dynamic part of mShared - mShared.erase(mShared.begin() + mStatic.size(), mShared.end()); - } - template<> inline void Store::setUp() { From 768c4a57577455f1810fd6284d98495a97d57cc5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 23 Dec 2014 16:38:30 +0100 Subject: [PATCH 0128/3725] Update crime response to pickpocket attempts (thanks Hrnchamd) --- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 5c4422fa1..c0c16eaf9 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1109,14 +1109,16 @@ namespace MWMechanics float dispTerm = (*it == victim) ? dispVictim : disp; float alarmTerm = 0.01 * it->getClass().getCreatureStats(*it).getAiSetting(CreatureStats::AI_Alarm).getBase(); + if (type == OT_Pickpocket && alarmTerm <= 0) + alarmTerm = 1.0; + if (*it != victim) dispTerm *= alarmTerm; float fightTerm = (*it == victim) ? fightVictim : fight; fightTerm += getFightDispositionBias(dispTerm); fightTerm += getFightDistanceBias(*it, player); - if (type != OT_Pickpocket) // type check not in the wiki, but this seems to be needed for MW behaviour - fightTerm *= alarmTerm; + fightTerm *= alarmTerm; int observerFightRating = it->getClass().getCreatureStats(*it).getAiSetting(CreatureStats::AI_Fight).getBase(); if (observerFightRating + fightTerm > 100) From 9a1bde684f16253ec6f274e2d9fa28bf21f896ab Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 23 Dec 2014 19:31:39 +0100 Subject: [PATCH 0129/3725] Sort class list in select class dialog --- apps/openmw/mwgui/class.cpp | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index 62167142f..84474d4a7 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -9,6 +9,16 @@ #undef min #undef max +namespace +{ + + bool sortClasses(const std::pair& left, const std::pair& right) + { + return left.second.compare(right.second) < 0; + } + +} + namespace MWGui { @@ -129,8 +139,6 @@ namespace MWGui if (Misc::StringUtils::ciEqual(*mClassList->getItemDataAt(i), classId)) { mClassList->setIndexSelected(i); - MyGUI::Button* okButton; - getWidget(okButton, "OKButton"); break; } } @@ -165,9 +173,6 @@ namespace MWGui if (_index == MyGUI::ITEM_NONE) return; - MyGUI::Button* okButton; - getWidget(okButton, "OKButton"); - const std::string *classId = mClassList->getItemDataAt(_index); if (Misc::StringUtils::ciEqual(mCurrentClassId, *classId)) return; @@ -184,7 +189,7 @@ namespace MWGui const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); - int index = 0; + std::vector > items; // class id, class name MWWorld::Store::iterator it = store.get().begin(); for (; it != store.get().end(); ++it) { @@ -192,8 +197,15 @@ namespace MWGui if (!playable) // Only display playable classes continue; - const std::string &id = it->mId; - mClassList->addItem(it->mName, id); + items.push_back(std::make_pair(it->mId, it->mName)); + } + std::sort(items.begin(), items.end(), sortClasses); + + int index = 0; + for (std::vector >::const_iterator it = items.begin(); it != items.end(); ++it) + { + const std::string &id = it->first; + mClassList->addItem(it->second, id); if (mCurrentClassId.empty()) { mCurrentClassId = id; From 2e5e7370ba3afbf134a474d16c95e8e11d3a3f3b Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 23 Dec 2014 19:51:17 +0100 Subject: [PATCH 0130/3725] Adjust default angle, FOV and viewport of character preview (Fixes #2220) --- apps/openmw/mwgui/birth.cpp | 5 ---- apps/openmw/mwgui/race.cpp | 29 +++++++++++++---------- apps/openmw/mwgui/textinput.cpp | 8 +------ apps/openmw/mwrender/characterpreview.cpp | 19 +++++++++------ apps/openmw/mwrender/characterpreview.hpp | 4 ++++ 5 files changed, 34 insertions(+), 31 deletions(-) diff --git a/apps/openmw/mwgui/birth.cpp b/apps/openmw/mwgui/birth.cpp index a7f90c00b..4df95c3bc 100644 --- a/apps/openmw/mwgui/birth.cpp +++ b/apps/openmw/mwgui/birth.cpp @@ -80,8 +80,6 @@ namespace MWGui if (Misc::StringUtils::ciEqual(*mBirthList->getItemDataAt(i), birthId)) { mBirthList->setIndexSelected(i); - MyGUI::Button* okButton; - getWidget(okButton, "OKButton"); break; } } @@ -116,9 +114,6 @@ namespace MWGui if (_index == MyGUI::ITEM_NONE) return; - MyGUI::Button* okButton; - getWidget(okButton, "OKButton"); - const std::string *birthId = mBirthList->getItemDataAt(_index); if (Misc::StringUtils::ciEqual(mCurrentBirthId, *birthId)) return; diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index 925480334..9c01a39ef 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -20,6 +20,12 @@ namespace else return index; } + + bool sortRaces(const std::pair& left, const std::pair& right) + { + return left.second.compare(right.second) < 0; + } + } namespace MWGui @@ -122,7 +128,7 @@ namespace MWGui mPreview.reset(new MWRender::RaceSelectionPreview()); mPreview->setup(); - mPreview->update (0); + mPreview->update (mCurrentAngle); const ESM::NPC proto = mPreview->getPrototype(); setRaceId(proto.mRace); @@ -143,8 +149,11 @@ namespace MWGui mPreviewImage->setImageTexture (textureName); mPreviewDirty = true; - } + size_t initialPos = mHeadRotate->getScrollRange()/2+mHeadRotate->getScrollRange()/10; + mHeadRotate->setScrollPosition(initialPos); + onHeadRotate(mHeadRotate, initialPos); + } void RaceDialog::setRaceId(const std::string &raceId) { @@ -156,8 +165,6 @@ namespace MWGui if (Misc::StringUtils::ciEqual(*mRaceList->getItemDataAt(i), raceId)) { mRaceList->setIndexSelected(i); - MyGUI::Button* okButton; - getWidget(okButton, "OKButton"); break; } } @@ -191,10 +198,9 @@ namespace MWGui void RaceDialog::onHeadRotate(MyGUI::ScrollBar* scroll, size_t _position) { float angle = (float(_position) / (scroll->getScrollRange()-1) - 0.5) * 3.14 * 2; - float diff = angle - mCurrentAngle; - mPreview->update (diff); + mPreview->update (angle); mPreviewDirty = true; - mCurrentAngle += diff; + mCurrentAngle = angle; } void RaceDialog::onSelectPreviousGender(MyGUI::Widget*) @@ -242,8 +248,6 @@ namespace MWGui if (_index == MyGUI::ITEM_NONE) return; - MyGUI::Button* okButton; - getWidget(okButton, "OKButton"); const std::string *raceId = mRaceList->getItemDataAt(_index); if (Misc::StringUtils::ciEqual(mCurrentRaceId, *raceId)) return; @@ -345,7 +349,7 @@ namespace MWGui const MWWorld::Store &races = MWBase::Environment::get().getWorld()->getStore().get(); - std::map items; // ID, name + std::vector > items; // ID, name MWWorld::Store::iterator it = races.begin(); for (; it != races.end(); ++it) { @@ -353,11 +357,12 @@ namespace MWGui if (!playable) // Only display playable races continue; - items[it->mId] = it->mName; + items.push_back(std::make_pair(it->mId, it->mName)); } + std::sort(items.begin(), items.end(), sortRaces); int index = 0; - for (std::map::const_iterator it = items.begin(); it != items.end(); ++it) + for (std::vector >::const_iterator it = items.begin(); it != items.end(); ++it) { mRaceList->addItem(it->second, it->first); if (Misc::StringUtils::ciEqual(it->first, mCurrentRaceId)) diff --git a/apps/openmw/mwgui/textinput.cpp b/apps/openmw/mwgui/textinput.cpp index 954bc41ab..80652b430 100644 --- a/apps/openmw/mwgui/textinput.cpp +++ b/apps/openmw/mwgui/textinput.cpp @@ -61,13 +61,7 @@ namespace MWGui void TextInputDialog::onTextAccepted(MyGUI::Edit* _sender) { - if (mTextEdit->getCaption() == "") - { - MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage37}"); - MWBase::Environment::get().getWindowManager()->setKeyFocusWidget (mTextEdit); - } - else - eventDone(this); + onOkClicked(_sender); } } diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 57b4c4f68..831efce4f 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -72,14 +72,15 @@ namespace MWRender l->setDirection (Ogre::Vector3(0.3, -0.7, 0.3)); l->setDiffuseColour (Ogre::ColourValue(1,1,1)); - mSceneMgr->setAmbientLight (Ogre::ColourValue(0.5, 0.5, 0.5)); + mSceneMgr->setAmbientLight (Ogre::ColourValue(0.25, 0.25, 0.25)); mCamera = mSceneMgr->createCamera (mName); + mCamera->setFOVy(Ogre::Degree(12.3)); mCamera->setAspectRatio (float(mSizeX) / float(mSizeY)); Ogre::SceneNode* renderRoot = mSceneMgr->getRootSceneNode()->createChildSceneNode("renderRoot"); - //we do this with mwRoot in renderingManager, do it here too. + // leftover of old coordinate system. TODO: remove this and adjust positions/orientations to match renderRoot->pitch(Ogre::Degree(-90)); mNode = renderRoot->createChildSceneNode(); @@ -91,7 +92,7 @@ namespace MWRender mCamera->setPosition(mPosition * scale); mCamera->lookAt(mLookAt * scale); - mCamera->setNearClipDistance (0.01); + mCamera->setNearClipDistance (1); mCamera->setFarClipDistance (1000); mTexture = Ogre::TextureManager::getSingleton().createManual(mName, @@ -159,7 +160,7 @@ namespace MWRender InventoryPreview::InventoryPreview(MWWorld::Ptr character) - : CharacterPreview(character, 512, 1024, "CharacterPreview", Ogre::Vector3(0, 65, -180), Ogre::Vector3(0,65,0)) + : CharacterPreview(character, 512, 1024, "CharacterPreview", Ogre::Vector3(0, 71, -700), Ogre::Vector3(0,71,0)) , mSelectionBuffer(NULL) , mSizeX(0) , mSizeY(0) @@ -288,9 +289,10 @@ namespace MWRender RaceSelectionPreview::RaceSelectionPreview() : CharacterPreview(MWBase::Environment::get().getWorld()->getPlayerPtr(), - 512, 512, "CharacterHeadPreview", Ogre::Vector3(0, 6, -35), Ogre::Vector3(0,125,0)) + 512, 512, "CharacterHeadPreview", Ogre::Vector3(0, 8, -125), Ogre::Vector3(0,127,0)) , mBase (*mCharacter.get()->mBase) , mRef(&mBase) + , mPitch(Ogre::Degree(6)) { mCharacter = MWWorld::Ptr(&mRef, NULL); } @@ -298,7 +300,9 @@ namespace MWRender void RaceSelectionPreview::update(float angle) { mAnimation->runAnimation(0.0f); - mNode->roll(Ogre::Radian(angle), Ogre::SceneNode::TS_LOCAL); + + mNode->setOrientation(Ogre::Quaternion(Ogre::Radian(angle), Ogre::Vector3::UNIT_Z) + * Ogre::Quaternion(mPitch, Ogre::Vector3::UNIT_X)); updateCamera(); } @@ -317,7 +321,8 @@ namespace MWRender mBase = proto; mBase.mId = "player"; rebuild(); - update(0); + mAnimation->runAnimation(0.0f); + updateCamera(); } void RaceSelectionPreview::onSetup () diff --git a/apps/openmw/mwrender/characterpreview.hpp b/apps/openmw/mwrender/characterpreview.hpp index 711de0d15..80dbe18b4 100644 --- a/apps/openmw/mwrender/characterpreview.hpp +++ b/apps/openmw/mwrender/characterpreview.hpp @@ -120,6 +120,10 @@ namespace MWRender } void setPrototype(const ESM::NPC &proto); + + private: + + Ogre::Radian mPitch; }; } From 6f72989cb1afe8cd9dd6cc82ad1f49c2ac0b3ce4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 24 Dec 2014 15:41:48 +0100 Subject: [PATCH 0131/3725] SpellModel, SortFilterItemModel: case insensitive sorting --- apps/openmw/mwgui/sortfilteritemmodel.cpp | 9 ++++++--- apps/openmw/mwgui/spellmodel.cpp | 6 ++++-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwgui/sortfilteritemmodel.cpp b/apps/openmw/mwgui/sortfilteritemmodel.cpp index 3bb599161..6c164df88 100644 --- a/apps/openmw/mwgui/sortfilteritemmodel.cpp +++ b/apps/openmw/mwgui/sortfilteritemmodel.cpp @@ -1,5 +1,7 @@ #include "sortfilteritemmodel.hpp" +#include + #include #include #include @@ -52,9 +54,10 @@ namespace if (left.mBase.getTypeName() == right.mBase.getTypeName()) { - int cmp = left.mBase.getClass().getName(left.mBase).compare( - right.mBase.getClass().getName(right.mBase)); - return cmp < 0; + std::string leftName = Misc::StringUtils::lowerCase(left.mBase.getClass().getName(left.mBase)); + std::string rightName = Misc::StringUtils::lowerCase(right.mBase.getClass().getName(right.mBase)); + + return leftName.compare(rightName) < 0; } else return compareType(left.mBase.getTypeName(), right.mBase.getTypeName()); diff --git a/apps/openmw/mwgui/spellmodel.cpp b/apps/openmw/mwgui/spellmodel.cpp index 37f0fa5be..ad9a913fa 100644 --- a/apps/openmw/mwgui/spellmodel.cpp +++ b/apps/openmw/mwgui/spellmodel.cpp @@ -21,8 +21,10 @@ namespace if (left.mType != right.mType) return left.mType < right.mType; - int cmp = left.mName.compare(right.mName); - return cmp < 0; + std::string leftName = Misc::StringUtils::lowerCase(left.mName); + std::string rightName = Misc::StringUtils::lowerCase(right.mName); + + return leftName.compare(rightName) < 0; } } From 2f0793390f9921a43c1188c83bd858af20d5bd75 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 27 Dec 2014 01:25:26 +0100 Subject: [PATCH 0132/3725] Fix cut off text for some widgets in the stats window --- apps/openmw/mwgui/statswindow.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/statswindow.cpp b/apps/openmw/mwgui/statswindow.cpp index baa779c1c..dcf85ddb7 100644 --- a/apps/openmw/mwgui/statswindow.cpp +++ b/apps/openmw/mwgui/statswindow.cpp @@ -342,10 +342,14 @@ namespace MWGui { MyGUI::TextBox* skillNameWidget; - skillNameWidget = mSkillView->createWidget("SandText", coord1 + MyGUI::IntSize(coord2.width, 0), MyGUI::Align::Default); + skillNameWidget = mSkillView->createWidget("SandText", coord1, MyGUI::Align::Default); + skillNameWidget->setCaption(text); skillNameWidget->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); + int textWidth = skillNameWidget->getTextSize().width; + skillNameWidget->setSize(textWidth, skillNameWidget->getHeight()); + mSkillWidgets.push_back(skillNameWidget); coord1.top += sLineHeight; From a87fe71ddf643fc6231f3cb90a831ed76942187c Mon Sep 17 00:00:00 2001 From: Internecine Date: Sat, 27 Dec 2014 19:46:54 +1300 Subject: [PATCH 0133/3725] Added a helper function to handle dynamic stat changes --- apps/openmw/mwmechanics/spellcasting.cpp | 28 +++++++++--------------- apps/openmw/mwmechanics/spellcasting.hpp | 2 ++ 2 files changed, 12 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index fd4c9406c..3ec52cf46 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -580,30 +580,15 @@ namespace MWMechanics } else if (effectId == ESM::MagicEffect::DamageHealth || effectId == ESM::MagicEffect::RestoreHealth) { - MWMechanics::DynamicStat health = target.getClass().getCreatureStats(target).getHealth(); - if (effectId == ESM::MagicEffect::DamageHealth) - health.setCurrent(health.getCurrent() - magnitude); - else - health.setCurrent(health.getCurrent() + magnitude); - target.getClass().getCreatureStats(target).setHealth(health); + applyDynamicStatsEffect(0, target, magnitude); } else if (effectId == ESM::MagicEffect::DamageFatigue || effectId == ESM::MagicEffect::RestoreFatigue) { - MWMechanics::DynamicStat fatigue = target.getClass().getCreatureStats(target).getFatigue(); - if (effectId == ESM::MagicEffect::DamageFatigue) - fatigue.setCurrent(fatigue.getCurrent() - magnitude); - else - fatigue.setCurrent(fatigue.getCurrent() + magnitude); - target.getClass().getCreatureStats(target).setHealth(fatigue); + applyDynamicStatsEffect(1, target, magnitude); } else if (effectId == ESM::MagicEffect::DamageMagicka || effectId == ESM::MagicEffect::RestoreMagicka) { - MWMechanics::DynamicStat magicka = target.getClass().getCreatureStats(target).getMagicka(); - if (effectId == ESM::MagicEffect::DamageMagicka) - magicka.setCurrent(magicka.getCurrent() - magnitude); - else - magicka.setCurrent(magicka.getCurrent() + magnitude); - target.getClass().getCreatureStats(target).setHealth(magicka); + applyDynamicStatsEffect(2, target, magnitude); } else if (effectId == ESM::MagicEffect::DamageSkill || effectId == ESM::MagicEffect::RestoreSkill) { @@ -666,6 +651,13 @@ namespace MWMechanics } } } + + void CastSpell::applyDynamicStatsEffect(int attribute, const MWWorld::Ptr& target, float magnitude) + { + DynamicStat value = target.getClass().getCreatureStats(target).getDynamic(attribute); + value.modify(magnitude); + target.getClass().getCreatureStats(target).setDynamic(attribute, value); + } bool CastSpell::cast(const std::string &id) { diff --git a/apps/openmw/mwmechanics/spellcasting.hpp b/apps/openmw/mwmechanics/spellcasting.hpp index 395ae043b..d76478146 100644 --- a/apps/openmw/mwmechanics/spellcasting.hpp +++ b/apps/openmw/mwmechanics/spellcasting.hpp @@ -93,6 +93,8 @@ namespace MWMechanics /// @note \a caster can be any type of object, or even an empty object. void applyInstantEffect (const MWWorld::Ptr& target, const MWWorld::Ptr& caster, const MWMechanics::EffectKey& effect, float magnitude); + + void applyDynamicStatsEffect (int attribute, const MWWorld::Ptr& target, float magnitude); }; } From 5f9540318a99dc3c551abf6c66a26a6428a1c0a9 Mon Sep 17 00:00:00 2001 From: Internecine Date: Sat, 27 Dec 2014 19:49:14 +1300 Subject: [PATCH 0134/3725] Fixed incorrect indexes --- apps/openmw/mwmechanics/spellcasting.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 3ec52cf46..352db88b4 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -584,11 +584,11 @@ namespace MWMechanics } else if (effectId == ESM::MagicEffect::DamageFatigue || effectId == ESM::MagicEffect::RestoreFatigue) { - applyDynamicStatsEffect(1, target, magnitude); + applyDynamicStatsEffect(2, target, magnitude); } else if (effectId == ESM::MagicEffect::DamageMagicka || effectId == ESM::MagicEffect::RestoreMagicka) { - applyDynamicStatsEffect(2, target, magnitude); + applyDynamicStatsEffect(1, target, magnitude); } else if (effectId == ESM::MagicEffect::DamageSkill || effectId == ESM::MagicEffect::RestoreSkill) { From 50e31877ab67f5f4a5f996d3fc22c83ec54acbf4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 27 Dec 2014 14:43:07 +0100 Subject: [PATCH 0135/3725] Fix crash when northmarker has been disabled (Bug #2230) --- apps/openmw/mwworld/worldimp.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 1867cf84c..41f399471 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1699,8 +1699,9 @@ namespace MWWorld MWWorld::LiveCellRef* ref = statics.find("northmarker"); if (!ref) return Vector2(0, 1); - Ogre::SceneNode* node = ref->mData.getBaseNode(); - Vector3 dir = node->_getDerivedOrientation() * Ogre::Vector3(0,1,0); + + Ogre::Quaternion orient (Ogre::Radian(-ref->mData.getPosition().rot[2]), Ogre::Vector3::UNIT_Z); + Vector3 dir = orient * Ogre::Vector3(0,1,0); Vector2 d = Vector2(dir.x, dir.y); return d; } From a62fe38a1b1892d9d3ca814fe9a1deab5fd6d138 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 27 Dec 2014 15:02:05 +0100 Subject: [PATCH 0136/3725] Fix unsafe use of BaseNode --- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index c0c16eaf9..8c6833497 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1214,7 +1214,7 @@ namespace MWMechanics bool MechanicsManager::awarenessCheck(const MWWorld::Ptr &ptr, const MWWorld::Ptr &observer) { - if (observer.getClass().getCreatureStats(observer).isDead()) + if (observer.getClass().getCreatureStats(observer).isDead() || !observer.getRefData().isEnabled()) return false; const MWWorld::Store& store = MWBase::Environment::get().getWorld()->getStore().get(); From 0a2dd4c6cbdb85069bac3842479fbb4253c7663e Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 27 Dec 2014 17:20:37 +0100 Subject: [PATCH 0137/3725] Fix unsafe use of BaseNode in Move script instruction --- apps/openmw/mwscript/transformationextensions.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index b39b3507a..7568f604d 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -689,7 +689,11 @@ namespace MWScript else throw std::runtime_error ("invalid movement axis: " + axis); + if (!ptr.getRefData().getBaseNode()) + return; + Ogre::Vector3 worldPos = ptr.getRefData().getBaseNode()->convertLocalToWorldPosition(posChange); + dynamic_cast(runtime.getContext()).updatePtr( MWBase::Environment::get().getWorld()->moveObject(ptr, worldPos.x, worldPos.y, worldPos.z)); } From 25954a80f57fb6f98de3068a2b4c54af6fddc5cf Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 28 Dec 2014 01:06:49 +0100 Subject: [PATCH 0138/3725] Fix recharging of items in player inventory --- apps/openmw/mwworld/inventorystore.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index fef34d67b..de3537759 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -418,6 +418,7 @@ void MWWorld::InventoryStore::updateMagicEffects(const Ptr& actor) void MWWorld::InventoryStore::flagAsModified() { ContainerStore::flagAsModified(); + mRechargingItemsUpToDate = false; } bool MWWorld::InventoryStore::stacks(const Ptr& ptr1, const Ptr& ptr2) From de9d3470189550b5aa14d41191325e7f30a113fc Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 28 Dec 2014 01:51:12 +0100 Subject: [PATCH 0139/3725] Fix on touch area effect spells (Fixes #2233) --- apps/openmw/mwbase/world.hpp | 2 +- apps/openmw/mwmechanics/spellcasting.cpp | 2 +- apps/openmw/mwworld/projectilemanager.cpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 5 ++--- apps/openmw/mwworld/worldimp.hpp | 2 +- 5 files changed, 6 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 32beadf18..cdfdfc358 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -546,7 +546,7 @@ namespace MWBase virtual void spawnEffect (const std::string& model, const std::string& textureOverride, const Ogre::Vector3& worldPos) = 0; virtual void explodeSpell (const Ogre::Vector3& origin, const ESM::EffectList& effects, - const MWWorld::Ptr& caster, const std::string& id, const std::string& sourceName) = 0; + const MWWorld::Ptr& caster, int rangeType, const std::string& id, const std::string& sourceName) = 0; virtual void activate (const MWWorld::Ptr& object, const MWWorld::Ptr& actor) = 0; diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index a831cc8bb..ee1e07dad 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -514,7 +514,7 @@ namespace MWMechanics } if (!exploded) - MWBase::Environment::get().getWorld()->explodeSpell(mHitPosition, effects, caster, mId, mSourceName); + MWBase::Environment::get().getWorld()->explodeSpell(mHitPosition, effects, caster, range, mId, mSourceName); if (!reflectedEffects.mList.empty()) inflict(caster, target, reflectedEffects, range, true, exploded); diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index afda6fe60..100ff0ba9 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -206,7 +206,7 @@ namespace MWWorld if (hit) { MWWorld::Ptr caster = MWBase::Environment::get().getWorld()->searchPtrViaActorId(it->mActorId); - MWBase::Environment::get().getWorld()->explodeSpell(pos, it->mEffects, caster, it->mSpellId, it->mSourceName); + MWBase::Environment::get().getWorld()->explodeSpell(pos, it->mEffects, caster, ESM::RT_Target, it->mSpellId, it->mSourceName); MWBase::Environment::get().getSoundManager()->stopSound(it->mSound); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 41f399471..fdfa19af4 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -3094,7 +3094,7 @@ namespace MWWorld mRendering->spawnEffect(model, textureOverride, worldPos); } - void World::explodeSpell(const Vector3 &origin, const ESM::EffectList &effects, const Ptr &caster, + void World::explodeSpell(const Vector3 &origin, const ESM::EffectList &effects, const Ptr &caster, int rangeType, const std::string& id, const std::string& sourceName) { std::map > toApply; @@ -3130,7 +3130,6 @@ namespace MWWorld std::vector objects; MWBase::Environment::get().getMechanicsManager()->getObjectsInRange( origin, feetToGameUnits(effectIt->mArea), objects); - for (std::vector::iterator affected = objects.begin(); affected != objects.end(); ++affected) toApply[*affected].push_back(*effectIt); } @@ -3154,7 +3153,7 @@ namespace MWWorld cast.mStack = false; ESM::EffectList effects; effects.mList = apply->second; - cast.inflict(apply->first, caster, effects, ESM::RT_Target, false, true); + cast.inflict(apply->first, caster, effects, (ESM::RangeType)rangeType, false, true); } } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 2a0da917b..5810fe42f 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -622,7 +622,7 @@ namespace MWWorld virtual void spawnEffect (const std::string& model, const std::string& textureOverride, const Ogre::Vector3& worldPos); virtual void explodeSpell (const Ogre::Vector3& origin, const ESM::EffectList& effects, - const MWWorld::Ptr& caster, const std::string& id, const std::string& sourceName); + const MWWorld::Ptr& caster, int rangeType, const std::string& id, const std::string& sourceName); virtual void activate (const MWWorld::Ptr& object, const MWWorld::Ptr& actor); From 377b79d5baecf4e6ebe0f11d86f8bca62f0f0dee Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 28 Dec 2014 02:39:54 +0100 Subject: [PATCH 0140/3725] Use SoundGen fallback for type Land only (Fixes #2228) --- apps/openmw/mwclass/creature.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index c69081c2e..59ab9dc90 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -678,7 +678,6 @@ namespace MWClass if(type >= 0) { std::vector sounds; - std::vector fallbacksounds; MWWorld::LiveCellRef* ref = ptr.get(); @@ -689,16 +688,15 @@ namespace MWClass { if (type == sound->mType && !sound->mCreature.empty() && (Misc::StringUtils::ciEqual(ourId, sound->mCreature))) sounds.push_back(&*sound); - if (type == sound->mType && sound->mCreature.empty()) - fallbacksounds.push_back(&*sound); ++sound; } if(!sounds.empty()) return sounds[(int)(rand()/(RAND_MAX+1.0)*sounds.size())]->mSound; - if (!fallbacksounds.empty()) - return fallbacksounds[(int)(rand()/(RAND_MAX+1.0)*fallbacksounds.size())]->mSound; } + if (type == ESM::SoundGenerator::Land) + return "Body Fall Large"; + return ""; } From 1bd3ab8a2d8d71c0d4d4561aff0d4feda172d9a9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 28 Dec 2014 14:09:27 +0100 Subject: [PATCH 0141/3725] Fix torch animation playing when torch is hidden (Fixes #2236) --- apps/openmw/mwmechanics/character.cpp | 2 +- apps/openmw/mwrender/characterpreview.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index e553b6cdc..633573ad9 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1285,7 +1285,7 @@ bool CharacterController::updateWeaponState() MWWorld::ContainerStoreIterator torch = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft); if(torch != inv.end() && torch->getTypeName() == typeid(ESM::Light).name() - && mWeaponType != WeapType_Spell && mWeaponType != WeapType_HandToHand) + && updateCarriedLeftVisible(mWeaponType)) { mAnimation->play("torch", Priority_Torch, MWRender::Animation::Group_LeftArm, diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 831efce4f..756c79ad8 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -239,7 +239,7 @@ namespace MWRender mAnimation->play(mCurrentAnimGroup, 1, Animation::Group_All, false, 1.0f, "start", "stop", 0.0f, 0); MWWorld::ContainerStoreIterator torch = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft); - if(torch != inv.end() && torch->getTypeName() == typeid(ESM::Light).name()) + if(torch != inv.end() && torch->getTypeName() == typeid(ESM::Light).name() && showCarriedLeft) { if(!mAnimation->getInfo("torch")) mAnimation->play("torch", 2, MWRender::Animation::Group_LeftArm, false, From a58bc9f2f7d07c792ee3fb65a101055117c35a38 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 28 Dec 2014 14:45:20 +0100 Subject: [PATCH 0142/3725] Remove sneaking effect on combat AI (Fixes #2237) --- apps/openmw/mwmechanics/aicombat.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 624960632..a23634ea3 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -300,6 +300,14 @@ namespace MWMechanics //Update with period = tReaction + // Stop attacking if target is not seen + if (target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::Invisibility).getMagnitude() > 0 + || target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::Chameleon).getMagnitude() > 75) + { + movement.mPosition[1] = movement.mPosition[0] = 0; + return false; // TODO: run away instead of doing nothing + } + timerReact = 0; const MWWorld::CellStore*& currentCell = storage.mCell; bool cellChange = currentCell && (actor.getCell() != currentCell); @@ -326,10 +334,6 @@ namespace MWMechanics actionCooldown = currentAction->getActionCooldown(); } - // Stop attacking if target is not seen - if (!MWBase::Environment::get().getMechanicsManager()->awarenessCheck(target, actor)) - return true; - if (currentAction.get()) currentAction->getCombatRange(rangeAttack, rangeFollow); From 6c9875969a5e0a12bb427b79cad7d2dc65e0256e Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 28 Dec 2014 15:34:47 +0100 Subject: [PATCH 0143/3725] Stop idle animations for non-biped creatures when attacking/moving The idle animation wouldn't be visible anyway, since these creatures don't have animation layers. However sounds tagged in the animation would still play. --- apps/openmw/mwclass/npc.cpp | 5 +++++ apps/openmw/mwclass/npc.hpp | 2 ++ apps/openmw/mwmechanics/character.cpp | 7 +++++++ 3 files changed, 14 insertions(+) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 3fe23772d..30445612a 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -1384,4 +1384,9 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mAiData.mFight; } + + bool Npc::isBipedal(const MWWorld::Ptr &ptr) const + { + return true; + } } diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index 3bc450088..8c89686af 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -182,6 +182,8 @@ namespace MWClass return true; } + virtual bool isBipedal (const MWWorld::Ptr &ptr) const; + virtual void respawn (const MWWorld::Ptr& ptr) const; virtual void restock (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 633573ad9..23ff9afff 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1586,7 +1586,14 @@ void CharacterController::update(float duration) clearAnimQueue(); if(mAnimQueue.empty()) + { idlestate = (inwater ? CharState_IdleSwim : (sneak ? CharState_IdleSneak : CharState_Idle)); + if ((mUpperBodyState != UpperCharState_Nothing + || mMovementState != CharState_None + || mHitState != CharState_None) + && !mPtr.getClass().isBipedal(mPtr)) + idlestate = CharState_None; + } else if(mAnimQueue.size() > 1) { if(mAnimation->isPlaying(mAnimQueue.front().first) == false) From cee72d021d114b96500a9f7e17775df5fba3d915 Mon Sep 17 00:00:00 2001 From: mrcheko Date: Mon, 29 Dec 2014 19:51:19 +0300 Subject: [PATCH 0144/3725] contrast and gamma post-processing effect added initial values are set to approximate vanilla --- apps/openmw/engine.cpp | 1 + apps/openmw/mwrender/renderingmanager.cpp | 11 ++++++ .../brightness_contrast_gamma.compositor | 24 +++++++++++++ files/materials/brightness_contrast_gamma.mat | 14 ++++++++ .../brightness_contrast_gamma.shader | 20 +++++++++++ .../brightness_contrast_gamma.shaderset | 7 ++++ files/mygui/openmw_settings_window.layout | 34 ++++++++++++++++--- files/settings-default.cfg | 2 ++ 8 files changed, 109 insertions(+), 4 deletions(-) create mode 100644 files/materials/brightness_contrast_gamma.compositor create mode 100644 files/materials/brightness_contrast_gamma.mat create mode 100644 files/materials/brightness_contrast_gamma.shader create mode 100644 files/materials/brightness_contrast_gamma.shaderset diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 99a642454..8f695ed8d 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -347,6 +347,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) addResourcesDirectory(mResDir / "mygui"); addResourcesDirectory(mResDir / "water"); addResourcesDirectory(mResDir / "shadows"); + addResourcesDirectory(mResDir / "materials"); OEngine::Render::WindowSettings windowSettings; windowSettings.fullscreen = settings.getBool("fullscreen", "Video"); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 2cddbce75..36aba70fb 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -13,6 +13,7 @@ #include #include #include +#include // for post-processing effects #include @@ -136,6 +137,9 @@ RenderingManager::RenderingManager(OEngine::Render::OgreRenderer& _rend, const b Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups(); + Ogre::CompositorManager::getSingleton().addCompositor(mRendering.getViewport(), "brightness_contrast_gamma"); + Ogre::CompositorManager::getSingleton().setCompositorEnabled(mRendering.getViewport(), "brightness_contrast_gamma", true); + // disable unsupported effects if (!Settings::Manager::getBool("shaders", "Objects")) Settings::Manager::setBool("enabled", "Shadows", false); @@ -155,6 +159,8 @@ RenderingManager::RenderingManager(OEngine::Render::OgreRenderer& _rend, const b sh::Factory::getInstance ().setGlobalSetting ("refraction", Settings::Manager::getBool("refraction", "Water") ? "true" : "false"); sh::Factory::getInstance ().setGlobalSetting ("viewproj_fix", "false"); sh::Factory::getInstance ().setSharedParameter ("vpRow2Fix", sh::makeProperty (new sh::Vector4(0,0,0,0))); + sh::Factory::getInstance ().setSharedParameter ("contrast_invGamma", sh::makeProperty(new sh::Vector2( + Settings::Manager::getFloat("contrast", "General"), 1.0f/Settings::Manager::getFloat("gamma", "General")))); mRootNode = mRendering.getScene()->getRootSceneNode(); mRootNode->createChildSceneNode("player"); @@ -757,6 +763,11 @@ void RenderingManager::processChangedSettings(const Settings::CategorySettingVec changeRes = true; else if (it->second == "field of view" && it->first == "General") mRendering.setFov(Settings::Manager::getFloat("field of view", "General")); + else if ((it->second == "gamma" || it->second == "contrast") && it->first == "General") + { + sh::Factory::getInstance ().setSharedParameter ("contrast_invGamma", sh::makeProperty(new sh::Vector2( + Settings::Manager::getFloat("contrast", "General"), 1.0f/Settings::Manager::getFloat("gamma", "General")))); + } else if ((it->second == "texture filtering" && it->first == "General") || (it->second == "anisotropy" && it->first == "General")) { diff --git a/files/materials/brightness_contrast_gamma.compositor b/files/materials/brightness_contrast_gamma.compositor new file mode 100644 index 000000000..c5c189dd1 --- /dev/null +++ b/files/materials/brightness_contrast_gamma.compositor @@ -0,0 +1,24 @@ +compositor brightness_contrast_gamma +{ + technique + { + // render scene into texture + texture SceneBuffer target_width target_height PF_A8R8G8B8 + + target SceneBuffer + { + input previous + } + + target_output + { + input none + + pass render_quad + { + material mat_brightness_contrast_gamma + input 0 SceneBuffer + } + } + } +} diff --git a/files/materials/brightness_contrast_gamma.mat b/files/materials/brightness_contrast_gamma.mat new file mode 100644 index 000000000..0a85a1a9c --- /dev/null +++ b/files/materials/brightness_contrast_gamma.mat @@ -0,0 +1,14 @@ +material mat_brightness_contrast_gamma +{ + pass + { + vertex_program transform_vertex + fragment_program openmw_brightness_contrast_gamma_fragment + + depth_check off + + texture_unit SceneBuffer + { + } + } +} diff --git a/files/materials/brightness_contrast_gamma.shader b/files/materials/brightness_contrast_gamma.shader new file mode 100644 index 000000000..7a8f6a82a --- /dev/null +++ b/files/materials/brightness_contrast_gamma.shader @@ -0,0 +1,20 @@ +#include "core.h" + +#ifdef SH_FRAGMENT_SHADER + + SH_BEGIN_PROGRAM + shInput(float2, UV) + shSampler2D(SceneBuffer) + shUniform(float2, contrast_invGamma) @shSharedParameter(contrast_invGamma) + SH_START_PROGRAM + { + shOutputColour(0) = shSample(SceneBuffer, UV); + + // contrast + shOutputColour(0).xyz = (shOutputColour(0).xyz - float3(0.5,0.5,0.5)) * contrast_invGamma.x + float3(0.5,0.5,0.5); + shOutputColour(0).xyz = shSaturate(shOutputColour(0).xyz); + // gamma + shOutputColour(0).xyz = pow(shOutputColour(0).xyz, contrast_invGamma.yyy); + } + +#endif diff --git a/files/materials/brightness_contrast_gamma.shaderset b/files/materials/brightness_contrast_gamma.shaderset new file mode 100644 index 000000000..2dc4ff698 --- /dev/null +++ b/files/materials/brightness_contrast_gamma.shaderset @@ -0,0 +1,7 @@ +shader_set openmw_brightness_contrast_gamma_fragment +{ + source brightness_contrast_gamma.shader + type fragment + profiles_cg ps_2_x ps_2_0 ps fp40 arbfp1 + profiles_hlsl ps_2_0 +} diff --git a/files/mygui/openmw_settings_window.layout b/files/mygui/openmw_settings_window.layout index e2f46f2d1..b3da0b9f6 100644 --- a/files/mygui/openmw_settings_window.layout +++ b/files/mygui/openmw_settings_window.layout @@ -1,8 +1,8 @@  - + - + @@ -214,7 +214,7 @@ - + @@ -292,6 +292,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -470,7 +496,7 @@ - + diff --git a/files/settings-default.cfg b/files/settings-default.cfg index df8266f7a..bd4eb208b 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -48,6 +48,8 @@ werewolf overlay = true [General] # Camera field of view field of view = 55 +gamma = 0.88 +contrast = 0.86 # Texture filtering mode. valid values: # none From c47b337fb0b205faede7132e15db91b276a970ec Mon Sep 17 00:00:00 2001 From: mrcheko Date: Mon, 29 Dec 2014 23:10:22 +0300 Subject: [PATCH 0145/3725] fix tabulation --- apps/openmw/engine.cpp | 2 +- apps/openmw/mwrender/renderingmanager.cpp | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 8f695ed8d..105d5ee05 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -347,7 +347,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) addResourcesDirectory(mResDir / "mygui"); addResourcesDirectory(mResDir / "water"); addResourcesDirectory(mResDir / "shadows"); - addResourcesDirectory(mResDir / "materials"); + addResourcesDirectory(mResDir / "materials"); OEngine::Render::WindowSettings windowSettings; windowSettings.fullscreen = settings.getBool("fullscreen", "Video"); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 36aba70fb..0bcbb9a78 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -137,8 +137,8 @@ RenderingManager::RenderingManager(OEngine::Render::OgreRenderer& _rend, const b Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups(); - Ogre::CompositorManager::getSingleton().addCompositor(mRendering.getViewport(), "brightness_contrast_gamma"); - Ogre::CompositorManager::getSingleton().setCompositorEnabled(mRendering.getViewport(), "brightness_contrast_gamma", true); + Ogre::CompositorManager::getSingleton().addCompositor(mRendering.getViewport(), "brightness_contrast_gamma"); + Ogre::CompositorManager::getSingleton().setCompositorEnabled(mRendering.getViewport(), "brightness_contrast_gamma", true); // disable unsupported effects if (!Settings::Manager::getBool("shaders", "Objects")) @@ -159,8 +159,8 @@ RenderingManager::RenderingManager(OEngine::Render::OgreRenderer& _rend, const b sh::Factory::getInstance ().setGlobalSetting ("refraction", Settings::Manager::getBool("refraction", "Water") ? "true" : "false"); sh::Factory::getInstance ().setGlobalSetting ("viewproj_fix", "false"); sh::Factory::getInstance ().setSharedParameter ("vpRow2Fix", sh::makeProperty (new sh::Vector4(0,0,0,0))); - sh::Factory::getInstance ().setSharedParameter ("contrast_invGamma", sh::makeProperty(new sh::Vector2( - Settings::Manager::getFloat("contrast", "General"), 1.0f/Settings::Manager::getFloat("gamma", "General")))); + sh::Factory::getInstance ().setSharedParameter ("contrast_invGamma", sh::makeProperty(new sh::Vector2( + Settings::Manager::getFloat("contrast", "General"), 1.0f/Settings::Manager::getFloat("gamma", "General")))); mRootNode = mRendering.getScene()->getRootSceneNode(); mRootNode->createChildSceneNode("player"); @@ -763,11 +763,11 @@ void RenderingManager::processChangedSettings(const Settings::CategorySettingVec changeRes = true; else if (it->second == "field of view" && it->first == "General") mRendering.setFov(Settings::Manager::getFloat("field of view", "General")); - else if ((it->second == "gamma" || it->second == "contrast") && it->first == "General") - { - sh::Factory::getInstance ().setSharedParameter ("contrast_invGamma", sh::makeProperty(new sh::Vector2( - Settings::Manager::getFloat("contrast", "General"), 1.0f/Settings::Manager::getFloat("gamma", "General")))); - } + else if ((it->second == "gamma" || it->second == "contrast") && it->first == "General") + { + sh::Factory::getInstance ().setSharedParameter ("contrast_invGamma", sh::makeProperty(new sh::Vector2( + Settings::Manager::getFloat("contrast", "General"), 1.0f/Settings::Manager::getFloat("gamma", "General")))); + } else if ((it->second == "texture filtering" && it->first == "General") || (it->second == "anisotropy" && it->first == "General")) { From e2346d7c37967f227f4f4a2ef2d36fd08093aff4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 30 Dec 2014 01:36:31 +0100 Subject: [PATCH 0146/3725] Store permanent magic effects in savegame (Fixes #1648) --- apps/openmw/mwworld/containerstore.hpp | 4 +-- apps/openmw/mwworld/inventorystore.cpp | 37 ++++++++++++++++++++++++++ apps/openmw/mwworld/inventorystore.hpp | 4 +++ components/esm/inventorystate.cpp | 27 +++++++++++++++++++ components/esm/inventorystate.hpp | 3 +++ 5 files changed, 73 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index 33255138a..1863984b2 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -170,9 +170,9 @@ namespace MWWorld Ptr search (const std::string& id); - void writeState (ESM::InventoryState& state) const; + virtual void writeState (ESM::InventoryState& state) const; - void readState (const ESM::InventoryState& state); + virtual void readState (const ESM::InventoryState& state); friend class ContainerStoreIterator; }; diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index de3537759..9c329ce72 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -5,6 +5,7 @@ #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -654,3 +655,39 @@ bool MWWorld::InventoryStore::isEquipped(const MWWorld::Ptr &item) } return false; } + +void MWWorld::InventoryStore::writeState(ESM::InventoryState &state) const +{ + MWWorld::ContainerStore::writeState(state); + + for (TEffectMagnitudes::const_iterator it = mPermanentMagicEffectMagnitudes.begin(); it != mPermanentMagicEffectMagnitudes.end(); ++it) + { + std::vector > params; + for (std::vector::const_iterator pIt = it->second.begin(); pIt != it->second.end(); ++pIt) + { + params.push_back(std::make_pair(pIt->mRandom, pIt->mMultiplier)); + } + + state.mPermanentMagicEffectMagnitudes[it->first] = params; + } +} + +void MWWorld::InventoryStore::readState(const ESM::InventoryState &state) +{ + MWWorld::ContainerStore::readState(state); + + for (ESM::InventoryState::TEffectMagnitudes::const_iterator it = state.mPermanentMagicEffectMagnitudes.begin(); + it != state.mPermanentMagicEffectMagnitudes.end(); ++it) + { + std::vector params; + for (std::vector >::const_iterator pIt = it->second.begin(); pIt != it->second.end(); ++pIt) + { + EffectParams p; + p.mRandom = pIt->first; + p.mMultiplier = pIt->second; + params.push_back(p); + } + + mPermanentMagicEffectMagnitudes[it->first] = params; + } +} diff --git a/apps/openmw/mwworld/inventorystore.hpp b/apps/openmw/mwworld/inventorystore.hpp index 30abc2ea5..48742b557 100644 --- a/apps/openmw/mwworld/inventorystore.hpp +++ b/apps/openmw/mwworld/inventorystore.hpp @@ -205,6 +205,10 @@ namespace MWWorld virtual void clear(); ///< Empty container. + + virtual void writeState (ESM::InventoryState& state) const; + + virtual void readState (const ESM::InventoryState& state); }; } diff --git a/components/esm/inventorystate.cpp b/components/esm/inventorystate.cpp index 2154faa83..a2d49b144 100644 --- a/components/esm/inventorystate.cpp +++ b/components/esm/inventorystate.cpp @@ -59,6 +59,21 @@ void ESM::InventoryState::load (ESMReader &esm) esm.getHNT (count, "COUN"); mLevelledItemMap[id] = count; } + + while (esm.isNextSub("MAGI")) + { + std::string id = esm.getHString(); + + std::vector > params; + while (esm.isNextSub("RAND")) + { + float rand, multiplier; + esm.getHT (rand); + esm.getHNT (multiplier, "MULT"); + params.push_back(std::make_pair(rand, multiplier)); + } + mPermanentMagicEffectMagnitudes[id] = params; + } } void ESM::InventoryState::save (ESMWriter &esm) const @@ -75,4 +90,16 @@ void ESM::InventoryState::save (ESMWriter &esm) const esm.writeHNString ("LEVM", it->first); esm.writeHNT ("COUN", it->second); } + + for (TEffectMagnitudes::const_iterator it = mPermanentMagicEffectMagnitudes.begin(); it != mPermanentMagicEffectMagnitudes.end(); ++it) + { + esm.writeHNString("MAGI", it->first); + + const std::vector >& params = it->second; + for (std::vector >::const_iterator pIt = params.begin(); pIt != params.end(); ++pIt) + { + esm.writeHNT ("RAND", pIt->first); + esm.writeHNT ("MULT", pIt->second); + } + } } diff --git a/components/esm/inventorystate.hpp b/components/esm/inventorystate.hpp index 4aa79f575..bd0b46a22 100644 --- a/components/esm/inventorystate.hpp +++ b/components/esm/inventorystate.hpp @@ -24,6 +24,9 @@ namespace ESM std::map mLevelledItemMap; + typedef std::map > > TEffectMagnitudes; + TEffectMagnitudes mPermanentMagicEffectMagnitudes; + virtual ~InventoryState() {} virtual void load (ESMReader &esm); From a62e15d93d6d0350c9807ae71870357926eef17c Mon Sep 17 00:00:00 2001 From: dteviot Date: Tue, 30 Dec 2014 17:25:19 +1300 Subject: [PATCH 0147/3725] Read profile files from LauncherSettings in load order. --- apps/launcher/datafilespage.cpp | 20 ++++++++++++++------ apps/launcher/datafilespage.hpp | 2 ++ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index 3c4d36de7..a0ef97ff9 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -94,20 +94,28 @@ bool Launcher::DataFilesPage::loadSettings() if (!currentProfile.isEmpty()) addProfile(currentProfile, true); - QStringList files = mLauncherSettings.values(QString("Profiles/") + currentProfile + QString("/content"), Qt::MatchExactly); + mSelector->setProfileContent(filesInProfile(currentProfile, pathIterator)); + + return true; +} + +QStringList Launcher::DataFilesPage::filesInProfile(const QString& profileName, PathIterator& pathIterator) +{ + QStringList files = mLauncherSettings.values(QString("Profiles/") + profileName + QString("/content"), Qt::MatchExactly); QStringList filepaths; - foreach (const QString &file, files) + // mLauncherSettings.values() returns the files in reverse load order + QListIterator i(files); + i.toBack(); + while (i.hasPrevious()) { - QString filepath = pathIterator.findFirstPath (file); + QString filepath = pathIterator.findFirstPath(i.previous()); if (!filepath.isEmpty()) filepaths << filepath; } - mSelector->setProfileContent (filepaths); - - return true; + return filepaths; } void Launcher::DataFilesPage::saveSettings(const QString &profile) diff --git a/apps/launcher/datafilespage.hpp b/apps/launcher/datafilespage.hpp index 15fa00308..c2fc22461 100644 --- a/apps/launcher/datafilespage.hpp +++ b/apps/launcher/datafilespage.hpp @@ -134,6 +134,8 @@ namespace Launcher } }; + + QStringList filesInProfile(const QString& profileName, PathIterator& pathIterator); }; } #endif From 18fb3f831a8a9003458dd7e44633ed38d64cce59 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 30 Dec 2014 15:46:33 +0100 Subject: [PATCH 0148/3725] Make the maximum horizontal stepping distance independent of movement speed (Fixes #1638) --- apps/openmw/mwworld/physicssystem.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index af1191ad9..1374dc37a 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -428,7 +428,10 @@ namespace MWWorld Ogre::Vector3 oldPosition = newPosition; // We hit something. Try to step up onto it. (NOTE: stepMove does not allow stepping over) // NOTE: stepMove modifies newPosition if successful - if(stepMove(colobj, newPosition, velocity, remainingTime, engine)) + bool result = stepMove(colobj, newPosition, velocity, remainingTime, engine); + if (!result) + result = stepMove(colobj, newPosition, velocity.normalisedCopy()*300.f, remainingTime, engine); + if(result) { // don't let pure water creatures move out of water after stepMove if((ptr.getClass().canSwim(ptr) && !ptr.getClass().canWalk(ptr)) From 9c693d078b42e7ca0bc4e96782851abfa5b3091a Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 30 Dec 2014 16:22:06 +0100 Subject: [PATCH 0149/3725] Fix equipment update removing ammunition (Fixes #2144) --- apps/openmw/mwrender/npcanimation.cpp | 5 +++++ apps/openmw/mwrender/weaponanimation.cpp | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 1cc9ad232..32c1e7e05 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -361,6 +361,8 @@ void NpcAnimation::updateParts() }; static const size_t slotlistsize = sizeof(slotlist)/sizeof(slotlist[0]); + bool wasArrowAttached = (mAmmunition.get()); + MWWorld::InventoryStore& inv = mPtr.getClass().getInventoryStore(mPtr); for(size_t i = 0;i < slotlistsize && mViewMode != VM_HeadOnly;i++) { @@ -555,6 +557,9 @@ void NpcAnimation::updateParts() "meshes\\"+bodypart->mModel); } } + + if (wasArrowAttached) + attachArrow(); } void NpcAnimation::addFirstPersonOffset(const Ogre::Vector3 &offset) diff --git a/apps/openmw/mwrender/weaponanimation.cpp b/apps/openmw/mwrender/weaponanimation.cpp index 7a52ce7ea..8a9feef03 100644 --- a/apps/openmw/mwrender/weaponanimation.cpp +++ b/apps/openmw/mwrender/weaponanimation.cpp @@ -49,6 +49,8 @@ void WeaponAnimation::attachArrow(MWWorld::Ptr actor) else { NifOgre::ObjectScenePtr weapon = getWeapon(); + if (!weapon.get()) + return; MWWorld::ContainerStoreIterator ammo = inv.getSlot(MWWorld::InventoryStore::Slot_Ammunition); if (ammo == inv.end()) @@ -66,6 +68,9 @@ void WeaponAnimation::attachArrow(MWWorld::Ptr actor) void WeaponAnimation::releaseArrow(MWWorld::Ptr actor) { + if (!mAmmunition.get()) + return; + MWWorld::InventoryStore& inv = actor.getClass().getInventoryStore(actor); MWWorld::ContainerStoreIterator weapon = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); if (weapon == inv.end()) From 04d95810d158148bf56d292f21d92f6978f8d23e Mon Sep 17 00:00:00 2001 From: mrcheko Date: Tue, 30 Dec 2014 18:33:11 +0300 Subject: [PATCH 0150/3725] gamma/contrast system reworked --- apps/openmw/engine.cpp | 2 ++ apps/openmw/mwrender/renderingmanager.cpp | 4 +++ files/mygui/openmw_settings_window.layout | 34 ++++++++++++++++++++--- files/settings-default.cfg | 2 ++ libs/openengine/ogre/renderer.cpp | 26 +++++++++++++++++ libs/openengine/ogre/renderer.hpp | 9 +++++- 6 files changed, 72 insertions(+), 5 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 99a642454..8912cb19e 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -358,6 +358,8 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) windowSettings.icon = "openmw.png"; std::string aa = settings.getString("antialiasing", "Video"); windowSettings.fsaa = (aa.substr(0, 4) == "MSAA") ? aa.substr(5, aa.size()-5) : "0"; + windowSettings.gamma = Settings::Manager::getFloat("gamma", "General"); + windowSettings.contrast = Settings::Manager::getFloat("contrast", "General"); SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, settings.getBool("minimize on focus loss", "Video") ? "1" : "0"); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 2cddbce75..44edcf03b 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -757,6 +757,10 @@ void RenderingManager::processChangedSettings(const Settings::CategorySettingVec changeRes = true; else if (it->second == "field of view" && it->first == "General") mRendering.setFov(Settings::Manager::getFloat("field of view", "General")); + else if ((it->second == "gamma" || it->second == "contrast") && it->first == "General") + { + mRendering.setWindowGammaContrast(Settings::Manager::getFloat("gamma", "General"), Settings::Manager::getFloat("contrast", "General")); + } else if ((it->second == "texture filtering" && it->first == "General") || (it->second == "anisotropy" && it->first == "General")) { diff --git a/files/mygui/openmw_settings_window.layout b/files/mygui/openmw_settings_window.layout index e2f46f2d1..b3da0b9f6 100644 --- a/files/mygui/openmw_settings_window.layout +++ b/files/mygui/openmw_settings_window.layout @@ -1,8 +1,8 @@  - + - + @@ -214,7 +214,7 @@ - + @@ -292,6 +292,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -470,7 +496,7 @@ - + diff --git a/files/settings-default.cfg b/files/settings-default.cfg index df8266f7a..6bd10dc21 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -48,6 +48,8 @@ werewolf overlay = true [General] # Camera field of view field of view = 55 +gamma = 1.34 +contrast = 0.98 # Texture filtering mode. valid values: # none diff --git a/libs/openengine/ogre/renderer.cpp b/libs/openengine/ogre/renderer.cpp index 404602c30..e20d72190 100644 --- a/libs/openengine/ogre/renderer.cpp +++ b/libs/openengine/ogre/renderer.cpp @@ -23,6 +23,12 @@ using namespace Ogre; using namespace OEngine::Render; +OgreRenderer::~OgreRenderer() +{ + cleanup(); + // restore system gamma ramp + SDL_SetWindowGammaRamp(mSDLWindow, mOldSystemGammaRamp, &mOldSystemGammaRamp[256], &mOldSystemGammaRamp[512]); +} void OgreRenderer::cleanup() { @@ -138,6 +144,8 @@ void OgreRenderer::createWindow(const std::string &title, const WindowSettings& helper.setWindowIcon(settings.icon); mWindow = helper.getWindow(); + SDL_GetWindowGammaRamp(mSDLWindow, mOldSystemGammaRamp, &mOldSystemGammaRamp[256], &mOldSystemGammaRamp[512]); + setWindowGammaContrast(settings.gamma, settings.contrast); // create the semi-transparent black background texture used by the GUI. // has to be created in code with TU_DYNAMIC_WRITE_ONLY param @@ -161,6 +169,24 @@ void OgreRenderer::createWindow(const std::string &title, const WindowSettings& mCamera->setAspectRatio(Real(mView->getActualWidth()) / Real(mView->getActualHeight())); } +void OgreRenderer::setWindowGammaContrast(float gamma, float contrast) +{ + Uint16 red[256], green[256], blue[256]; + for (int i = 0; i < 256; i++) + { + float k = i/256.0f; + k = (k - 0.5f) * contrast + 0.5f; + k = pow(k, 1.f/gamma); + k *= 256; + float value = k*256; + if (value > 65535) value = 65535; + else if (value < 0) value = 0; + + red[i] = green[i] = blue[i] = value; + } + SDL_SetWindowGammaRamp(mSDLWindow, red, green, blue); +} + void OgreRenderer::adjustCamera(float fov, float nearClip) { mCamera->setNearClipDistance(nearClip); diff --git a/libs/openengine/ogre/renderer.hpp b/libs/openengine/ogre/renderer.hpp index 70cc3db60..6f2891e6a 100644 --- a/libs/openengine/ogre/renderer.hpp +++ b/libs/openengine/ogre/renderer.hpp @@ -42,6 +42,8 @@ namespace OEngine int screen; std::string fsaa; std::string icon; + float gamma; + float contrast; }; class WindowSizeListener @@ -67,6 +69,9 @@ namespace OEngine int mWindowHeight; bool mOutstandingResize; + // Store system gamma ramp on window creation. Restore system gamma ramp on exit + uint16_t mOldSystemGammaRamp[256*3]; + public: OgreRenderer() : mRoot(NULL) @@ -83,7 +88,7 @@ namespace OEngine { } - ~OgreRenderer() { cleanup(); } + ~OgreRenderer(); /** Configure the renderer. This will load configuration files and set up the Root and logging classes. */ @@ -95,6 +100,8 @@ namespace OEngine /// Create a window with the given title void createWindow(const std::string &title, const WindowSettings& settings); + void setWindowGammaContrast(float gamma, float contrast); + /// Set up the scene manager, camera and viewport void adjustCamera( float fov=55, // Field of view angle From 5b2633588c0a1f6e9dcdd530726d1f9915408d48 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 30 Dec 2014 19:14:06 +0100 Subject: [PATCH 0151/3725] Add error handling for SDL_CreateWindow --- libs/openengine/ogre/renderer.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libs/openengine/ogre/renderer.cpp b/libs/openengine/ogre/renderer.cpp index eb33d5876..2c81b1b9d 100644 --- a/libs/openengine/ogre/renderer.cpp +++ b/libs/openengine/ogre/renderer.cpp @@ -130,6 +130,8 @@ void OgreRenderer::createWindow(const std::string &title, const WindowSettings& SDL_WINDOW_SHOWN | (settings.fullscreen ? SDL_WINDOW_FULLSCREEN : 0) | SDL_WINDOW_RESIZABLE ); + if (mSDLWindow == 0) + throw std::runtime_error("Failed to create window: " + std::string(SDL_GetError())); SFO::SDLWindowHelper helper(mSDLWindow, settings.window_x, settings.window_y, title, settings.fullscreen, params); if (settings.icon != "") From 3024c67995db4d7f2cbe5ac51ce3db5d9e40b872 Mon Sep 17 00:00:00 2001 From: Marco Schulze Date: Tue, 30 Dec 2014 18:37:33 -0300 Subject: [PATCH 0152/3725] Regenerate components/version/version.hpp as HEAD moves on a git checkout Pull request #416 introduced a common bug where version.hpp wouldn't be regenerated every build, poteantially leading to stale version data. This commit adds a custom build target, git-version, which updates version.hpp before the components library is built. --- CMakeLists.txt | 25 ++----------------------- cmake/GitVersion.cmake | 24 ++++++++++++++++++++++++ components/CMakeLists.txt | 23 ++++++++++++++++++++++- 3 files changed, 48 insertions(+), 24 deletions(-) create mode 100644 cmake/GitVersion.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index d7c85818e..323b743bc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,33 +20,13 @@ set(OPENMW_VERSION_TAGHASH "") set(OPENMW_VERSION "${OPENMW_VERSION_MAJOR}.${OPENMW_VERSION_MINOR}.${OPENMW_VERSION_RELEASE}") +set(GIT_CHECKOUT FALSE) if(EXISTS ${PROJECT_SOURCE_DIR}/.git) if(NOT EXISTS ${PROJECT_SOURCE_DIR}/.git/shallow) find_package(Git) if(GIT_FOUND) - execute_process ( - COMMAND "${GIT_EXECUTABLE}" rev-list --tags --max-count=1 - WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}" - RESULT_VARIABLE EXITCODE1 - OUTPUT_VARIABLE TAGHASH - OUTPUT_STRIP_TRAILING_WHITESPACE) - - execute_process ( - COMMAND "${GIT_EXECUTABLE}" rev-parse HEAD - WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}" - RESULT_VARIABLE EXITCODE2 - OUTPUT_VARIABLE COMMITHASH - OUTPUT_STRIP_TRAILING_WHITESPACE) - - string (COMPARE EQUAL "${EXITCODE1}:${EXITCODE2}" "0:0" SUCCESS) - if (SUCCESS) - set(OPENMW_VERSION_COMMITHASH "${COMMITHASH}") - set(OPENMW_VERSION_TAGHASH "${TAGHASH}") - message(STATUS "OpenMW version ${OPENMW_VERSION}") - else (SUCCESS) - message(WARNING "Failed to get valid version information from Git") - endif (SUCCESS) + set(GIT_CHECKOUT TRUE) else(GIT_FOUND) message(WARNING "Git executable not found") endif(GIT_FOUND) @@ -874,4 +854,3 @@ if (DOXYGEN_FOUND) WORKING_DIRECTORY ${OpenMW_BINARY_DIR} COMMENT "Generating documentation for the github-pages at ${DOXYGEN_PAGES_OUTPUT_DIR}" VERBATIM) endif () - diff --git a/cmake/GitVersion.cmake b/cmake/GitVersion.cmake new file mode 100644 index 000000000..0087461a1 --- /dev/null +++ b/cmake/GitVersion.cmake @@ -0,0 +1,24 @@ +execute_process ( + COMMAND ${GIT_EXECUTABLE} rev-list --tags --max-count=1 + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} + RESULT_VARIABLE EXITCODE1 + OUTPUT_VARIABLE TAGHASH + OUTPUT_STRIP_TRAILING_WHITESPACE) + +execute_process ( + COMMAND ${GIT_EXECUTABLE} rev-parse HEAD + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} + RESULT_VARIABLE EXITCODE2 + OUTPUT_VARIABLE COMMITHASH + OUTPUT_STRIP_TRAILING_WHITESPACE) + +string (COMPARE EQUAL "${EXITCODE1}:${EXITCODE2}" "0:0" SUCCESS) +if (SUCCESS) + set(OPENMW_VERSION_COMMITHASH "${COMMITHASH}") + set(OPENMW_VERSION_TAGHASH "${TAGHASH}") + message(STATUS "OpenMW version ${OPENMW_VERSION}") +else (SUCCESS) + message(WARNING "Failed to get valid version information from Git") +endif (SUCCESS) + +configure_file(${VERSION_HPP_IN} ${VERSION_HPP}) diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 6918b87a7..1e400f779 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -2,7 +2,24 @@ project (Components) set (CMAKE_BUILD_TYPE DEBUG) # Version file -configure_file("${CMAKE_CURRENT_SOURCE_DIR}/version/version.hpp.cmake" "${CMAKE_CURRENT_SOURCE_DIR}/version/version.hpp") +set (VERSION_HPP_IN ${CMAKE_CURRENT_SOURCE_DIR}/version/version.hpp.cmake) +set (VERSION_HPP ${CMAKE_CURRENT_SOURCE_DIR}/version/version.hpp) +if (GIT_CHECKOUT) + add_custom_target (git-version + COMMAND ${CMAKE_COMMAND} + -DGIT_EXECUTABLE=${GIT_EXECUTABLE} + -DPROJECT_SOURCE_DIR=${PROJECT_SOURCE_DIR} + -DVERSION_HPP_IN=${VERSION_HPP_IN} + -DVERSION_HPP=${VERSION_HPP} + -DOPENMW_VERSION_MAJOR=${OPENMW_VERSION_MAJOR} + -DOPENMW_VERSION_MINOR=${OPENMW_VERSION_MINOR} + -DOPENMW_VERSION_RELEASE=${OPENMW_VERSION_RELEASE} + -DOPENMW_VERSION=${OPENMW_VERSION} + -P ${CMAKE_CURRENT_SOURCE_DIR}/../cmake/GitVersion.cmake + VERBATIM) +else (GIT_CHECKOUT) + configure_file(${VERSION_HPP_IN} ${VERSION_HPP}) +endif (GIT_CHECKOUT) # source files @@ -145,6 +162,10 @@ add_library(components STATIC ${COMPONENT_FILES} ${MOC_SRCS} ${ESM_UI_HDR}) target_link_libraries(components ${Boost_LIBRARIES} ${OGRE_LIBRARIES}) +if (GIT_CHECKOUT) + add_dependencies (components git-version) +endif (GIT_CHECKOUT) + # Fix for not visible pthreads functions for linker with glibc 2.15 if (UNIX AND NOT APPLE) target_link_libraries(components ${CMAKE_THREAD_LIBS_INIT}) From dfbd470613045f19a7628de5ad600cf3296bc8da Mon Sep 17 00:00:00 2001 From: dteviot Date: Wed, 31 Dec 2014 19:19:54 +1300 Subject: [PATCH 0153/3725] Adjust plug-in order to match profile loading. Also marks plug-ins with load order problems in red and changes tool tip to describe error. --- components/CMakeLists.txt | 1 + .../contentselector/model/contentmodel.cpp | 93 ++++++++++++++++++- .../contentselector/model/contentmodel.hpp | 11 ++- .../contentselector/model/loadordererror.cpp | 22 +++++ .../contentselector/model/loadordererror.hpp | 41 ++++++++ .../contentselector/view/contentselector.cpp | 6 +- .../contentselector/view/contentselector.hpp | 2 +- 7 files changed, 167 insertions(+), 9 deletions(-) create mode 100644 components/contentselector/model/loadordererror.cpp create mode 100644 components/contentselector/model/loadordererror.hpp diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 6918b87a7..fbad61bfd 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -116,6 +116,7 @@ if(QT_QTGUI_LIBRARY AND QT_QTCORE_LIBRARY) add_component_qt_dir (contentselector model/modelitem model/esmfile model/naturalsort model/contentmodel + model/loadordererror view/combobox view/contentselector ) add_component_qt_dir (config diff --git a/components/contentselector/model/contentmodel.cpp b/components/contentselector/model/contentmodel.cpp index 0d4f2365a..72bca2244 100644 --- a/components/contentselector/model/contentmodel.cpp +++ b/components/contentselector/model/contentmodel.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "components/esm/esmreader.hpp" @@ -170,6 +171,16 @@ QVariant ContentSelectorModel::ContentModel::data(const QModelIndex &index, int switch (role) { + case Qt::ForegroundRole: + { + if (isLoadOrderError(file->filePath())) + { + QBrush redBackground(Qt::red, Qt::SolidPattern); + return redBackground; + } + break; + } + case Qt::EditRole: case Qt::DisplayRole: { @@ -202,7 +213,7 @@ QVariant ContentSelectorModel::ContentModel::data(const QModelIndex &index, int if (column != 0) return QVariant(); - return file->toolTip(); + return isLoadOrderError(file->filePath()) ? getLoadOrderError(file->filePath()).toolTip() : file->toolTip(); break; } @@ -341,6 +352,8 @@ bool ContentSelectorModel::ContentModel::removeRows(int position, int rows, cons } endRemoveRows(); + // at this point we know that drag and drop has finished. + checkForLoadOrderErrors(); return true; } @@ -530,11 +543,83 @@ bool ContentSelectorModel::ContentModel::isEnabled (QModelIndex index) const return (flags(index) & Qt::ItemIsEnabled); } -void ContentSelectorModel::ContentModel::setCheckStates (const QStringList &fileList, bool isChecked) +bool ContentSelectorModel::ContentModel::isLoadOrderError(const QString& filepath) const +{ + return !(getLoadOrderError(filepath) == LoadOrderError::sNoError); +} + +ContentSelectorModel::LoadOrderError ContentSelectorModel::ContentModel::getLoadOrderError(const QString& filepath) const +{ + return mLoadOrderErrors.contains(filepath) ? mLoadOrderErrors[filepath] : ContentSelectorModel::LoadOrderError::sNoError; +} + +void ContentSelectorModel::ContentModel::setLoadOrderError(const QString& filepath, const ContentSelectorModel::LoadOrderError& loadOrderError) +{ + mLoadOrderErrors[filepath] = loadOrderError; + int filePosition = indexFromItem(item(filepath)).row(); + emit dataChanged(index(filePosition, 0, QModelIndex()), index(filePosition, 0, QModelIndex())); +} + +void ContentSelectorModel::ContentModel::setContentList(const QStringList &fileList, bool isChecked) { - foreach (const QString &file, fileList) + mLoadOrderErrors.clear(); + int previousPosition = -1; + foreach (const QString &filepath, fileList) { - setCheckState (file, isChecked); + if (setCheckState(filepath, isChecked)) + { + // as necessary, move plug-ins in visible list to match sequence of supplied filelist + const EsmFile* file = item(filepath); + int filePosition = indexFromItem(file).row(); + if (filePosition < previousPosition) + { + mFiles.move(filePosition, previousPosition); + emit dataChanged(index(filePosition, 0, QModelIndex()), index(previousPosition, 0, QModelIndex())); + } + else + { + previousPosition = filePosition; + } + } + } + checkForLoadOrderErrors(); +} + +void ContentSelectorModel::ContentModel::checkForLoadOrderErrors() +{ + for (int row = 0; row < mFiles.count(); ++row) + { + EsmFile* file = item(row); + bool isRowInError = isLoadOrderError(file->filePath()); + LoadOrderError::ErrorCode error = LoadOrderError::ErrorCode_None; + foreach(QString dependantfileName, file->gameFiles()) + { + const EsmFile* dependentFile = item(dependantfileName); + + if (!dependentFile) + { + error = LoadOrderError::ErrorCode_MissingDependency; + } + else if (!isChecked(dependentFile->filePath())) + { + error = LoadOrderError::ErrorCode_InactiveDependency; + } + else if (row < indexFromItem(dependentFile).row()) + { + error = LoadOrderError::ErrorCode_LoadOrder; + } + + if (!isRowInError && (error != LoadOrderError::ErrorCode_None)) + { + setLoadOrderError(file->filePath(), LoadOrderError(error, dependantfileName)); + break; + } + } + + if (isRowInError && (error == LoadOrderError::ErrorCode_None)) + { + setLoadOrderError(file->filePath(), LoadOrderError::sNoError); + } } } diff --git a/components/contentselector/model/contentmodel.hpp b/components/contentselector/model/contentmodel.hpp index 7b2000b51..fc50eeb85 100644 --- a/components/contentselector/model/contentmodel.hpp +++ b/components/contentselector/model/contentmodel.hpp @@ -4,6 +4,8 @@ #include #include +#include "loadordererror.hpp" + namespace ContentSelectorModel { class EsmFile; @@ -47,10 +49,14 @@ namespace ContentSelectorModel bool isEnabled (QModelIndex index) const; bool isChecked(const QString &filepath) const; bool setCheckState(const QString &filepath, bool isChecked); - void setCheckStates (const QStringList &fileList, bool isChecked); + void setContentList(const QStringList &fileList, bool isChecked); ContentFileList checkedItems() const; void uncheckAll(); + bool isLoadOrderError(const QString& filepath) const; + ContentSelectorModel::LoadOrderError ContentSelectorModel::ContentModel::getLoadOrderError(const QString& filepath) const; + void ContentSelectorModel::ContentModel::setLoadOrderError(const QString& filepath, const ContentSelectorModel::LoadOrderError& loadOrderError); + void refreshModel(); private: @@ -60,9 +66,12 @@ namespace ContentSelectorModel EsmFile *item(int row); void sortFiles(); + void checkForLoadOrderErrors(); + ContentFileList mFiles; QHash mCheckStates; + QHash mLoadOrderErrors; QTextCodec *mCodec; QString mEncoding; diff --git a/components/contentselector/model/loadordererror.cpp b/components/contentselector/model/loadordererror.cpp new file mode 100644 index 000000000..c8b258e98 --- /dev/null +++ b/components/contentselector/model/loadordererror.cpp @@ -0,0 +1,22 @@ +#include "loadordererror.hpp" +#include + +QString ContentSelectorModel::LoadOrderError::sErrorToolTips[ErrorCode_LoadOrder] = +{ + QString("Unable to find dependant file: %1"), + QString("Dependent file needs to be active: %1"), + QString("This file needs to load after %1"), +}; + +ContentSelectorModel::LoadOrderError ContentSelectorModel::LoadOrderError::sNoError = ContentSelectorModel::LoadOrderError(); + +QString ContentSelectorModel::LoadOrderError::toolTip() const +{ + assert(mErrorCode); + return sErrorToolTips[mErrorCode - 1].arg(mFileName); +} + +bool ContentSelectorModel::LoadOrderError::operator== (const ContentSelectorModel::LoadOrderError& rhs) const +{ + return (mErrorCode == rhs.mErrorCode) && ((mErrorCode == ErrorCode_None) || (mFileName == rhs.mFileName)); +} \ No newline at end of file diff --git a/components/contentselector/model/loadordererror.hpp b/components/contentselector/model/loadordererror.hpp new file mode 100644 index 000000000..75ec2ad92 --- /dev/null +++ b/components/contentselector/model/loadordererror.hpp @@ -0,0 +1,41 @@ +#ifndef LOADORDERERROR_HPP +#define LOADORDERERROR_HPP + +#include + +namespace ContentSelectorModel +{ + /// \Details of a suspected Load Order problem a plug-in will have. This is basically a POD + class LoadOrderError + { + public: + enum ErrorCode + { + ErrorCode_None = 0, + ErrorCode_MissingDependency = 1, + ErrorCode_InactiveDependency = 2, + ErrorCode_LoadOrder = 3, + }; + + inline LoadOrderError() : mErrorCode(ErrorCode_None) {}; + inline LoadOrderError(ErrorCode errorCode, QString fileName) + { + mErrorCode = errorCode; + mFileName = fileName; + } + inline ErrorCode errorCode() const { return mErrorCode; } + inline QString fileName() const { return mFileName; } + bool operator==(const LoadOrderError& rhs) const; + QString toolTip() const; + + /// \Sentinal to represent a "No Load Order Error" condition + static LoadOrderError sNoError; + + private: + ErrorCode mErrorCode; + QString mFileName; + static QString sErrorToolTips[ErrorCode_LoadOrder]; + }; +} + +#endif // LOADORDERERROR_HPP diff --git a/components/contentselector/view/contentselector.cpp b/components/contentselector/view/contentselector.cpp index b12d4147a..a5e250840 100644 --- a/components/contentselector/view/contentselector.cpp +++ b/components/contentselector/view/contentselector.cpp @@ -75,7 +75,7 @@ void ContentSelectorView::ContentSelector::setProfileContent(const QStringList & } } - setCheckStates (fileList); + setContentList(fileList); } void ContentSelectorView::ContentSelector::setGameFile(const QString &filename) @@ -103,14 +103,14 @@ void ContentSelectorView::ContentSelector::clearCheckStates() mContentModel->uncheckAll(); } -void ContentSelectorView::ContentSelector::setCheckStates(const QStringList &list) +void ContentSelectorView::ContentSelector::setContentList(const QStringList &list) { if (list.isEmpty()) { slotCurrentGameFileIndexChanged (ui.gameFileView->currentIndex()); } else - mContentModel->setCheckStates (list, true); + mContentModel->setContentList(list, true); } ContentSelectorModel::ContentFileList diff --git a/components/contentselector/view/contentselector.hpp b/components/contentselector/view/contentselector.hpp index a25eb20ae..a4da38727 100644 --- a/components/contentselector/view/contentselector.hpp +++ b/components/contentselector/view/contentselector.hpp @@ -32,7 +32,7 @@ namespace ContentSelectorView void setProfileContent (const QStringList &fileList); void clearCheckStates(); - void setCheckStates (const QStringList &list); + void setContentList(const QStringList &list); ContentSelectorModel::ContentFileList selectedFiles() const; From 60a74d5eb8f5f673d6fecc626e789ecf37c31b40 Mon Sep 17 00:00:00 2001 From: mrcheko Date: Wed, 31 Dec 2014 18:40:01 +0300 Subject: [PATCH 0154/3725] increase robustness for gamma to persist in the system; use GMST strings for gamma interface --- apps/openmw/engine.cpp | 5 +++-- files/mygui/openmw_settings_window.layout | 22 +++++++++++++++------- libs/openengine/ogre/renderer.cpp | 17 +++++++++++++---- libs/openengine/ogre/renderer.hpp | 3 +-- 4 files changed, 32 insertions(+), 15 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 8912cb19e..c5ecfee2d 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -208,6 +208,7 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) OMW::Engine::~Engine() { + mOgre->restoreWindowGammaRamp(); mEnvironment.cleanup(); delete mScriptContext; delete mOgre; @@ -358,8 +359,6 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) windowSettings.icon = "openmw.png"; std::string aa = settings.getString("antialiasing", "Video"); windowSettings.fsaa = (aa.substr(0, 4) == "MSAA") ? aa.substr(5, aa.size()-5) : "0"; - windowSettings.gamma = Settings::Manager::getFloat("gamma", "General"); - windowSettings.contrast = Settings::Manager::getFloat("contrast", "General"); SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, settings.getBool("minimize on focus loss", "Video") ? "1" : "0"); @@ -384,6 +383,8 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) // Create sound system mEnvironment.setSoundManager (new MWSound::SoundManager(mUseSound)); + mOgre->setWindowGammaContrast(Settings::Manager::getFloat("gamma", "General"), Settings::Manager::getFloat("contrast", "General")); + if (!mSkipMenu) { std::string logo = mFallbackMap["Movies_Company_Logo"]; diff --git a/files/mygui/openmw_settings_window.layout b/files/mygui/openmw_settings_window.layout index b3da0b9f6..8fd3d8af1 100644 --- a/files/mygui/openmw_settings_window.layout +++ b/files/mygui/openmw_settings_window.layout @@ -1,8 +1,8 @@  - + - + @@ -214,7 +214,7 @@ - + @@ -293,7 +293,7 @@ - + @@ -305,10 +305,18 @@ - + + + + + + + + + - + @@ -496,7 +504,7 @@ - + diff --git a/libs/openengine/ogre/renderer.cpp b/libs/openengine/ogre/renderer.cpp index e20d72190..022c6473f 100644 --- a/libs/openengine/ogre/renderer.cpp +++ b/libs/openengine/ogre/renderer.cpp @@ -26,8 +26,7 @@ using namespace OEngine::Render; OgreRenderer::~OgreRenderer() { cleanup(); - // restore system gamma ramp - SDL_SetWindowGammaRamp(mSDLWindow, mOldSystemGammaRamp, &mOldSystemGammaRamp[256], &mOldSystemGammaRamp[512]); + restoreWindowGammaRamp(); } void OgreRenderer::cleanup() @@ -145,7 +144,6 @@ void OgreRenderer::createWindow(const std::string &title, const WindowSettings& mWindow = helper.getWindow(); SDL_GetWindowGammaRamp(mSDLWindow, mOldSystemGammaRamp, &mOldSystemGammaRamp[256], &mOldSystemGammaRamp[512]); - setWindowGammaContrast(settings.gamma, settings.contrast); // create the semi-transparent black background texture used by the GUI. // has to be created in code with TU_DYNAMIC_WRITE_ONLY param @@ -171,6 +169,8 @@ void OgreRenderer::createWindow(const std::string &title, const WindowSettings& void OgreRenderer::setWindowGammaContrast(float gamma, float contrast) { + if (mSDLWindow == NULL) return; + Uint16 red[256], green[256], blue[256]; for (int i = 0; i < 256; i++) { @@ -184,7 +184,16 @@ void OgreRenderer::setWindowGammaContrast(float gamma, float contrast) red[i] = green[i] = blue[i] = value; } - SDL_SetWindowGammaRamp(mSDLWindow, red, green, blue); + if (SDL_SetWindowGammaRamp(mSDLWindow, red, green, blue) < 0) + std::cout << "Couldn't set gamma: " << SDL_GetError() << std::endl; +} + +void OgreRenderer::restoreWindowGammaRamp() +{ + if (mSDLWindow != NULL) + { + SDL_SetWindowGammaRamp(mSDLWindow, mOldSystemGammaRamp, &mOldSystemGammaRamp[256], &mOldSystemGammaRamp[512]); + } } void OgreRenderer::adjustCamera(float fov, float nearClip) diff --git a/libs/openengine/ogre/renderer.hpp b/libs/openengine/ogre/renderer.hpp index 6f2891e6a..1b18a7b0b 100644 --- a/libs/openengine/ogre/renderer.hpp +++ b/libs/openengine/ogre/renderer.hpp @@ -42,8 +42,6 @@ namespace OEngine int screen; std::string fsaa; std::string icon; - float gamma; - float contrast; }; class WindowSizeListener @@ -101,6 +99,7 @@ namespace OEngine void createWindow(const std::string &title, const WindowSettings& settings); void setWindowGammaContrast(float gamma, float contrast); + void restoreWindowGammaRamp(); /// Set up the scene manager, camera and viewport void adjustCamera( From d1a29300f0c6bad8671ce64fc10755c7af4e84c8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 31 Dec 2014 16:59:21 +0100 Subject: [PATCH 0155/3725] Handle bipedal creatures not using weapons (Fixes #2238) --- apps/openmw/mwmechanics/character.cpp | 131 +++++++++++++++----------- 1 file changed, 78 insertions(+), 53 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 23ff9afff..9f88d1573 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -296,7 +296,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat } const WeaponInfo *weap = std::find_if(sWeaponTypeList, sWeaponTypeListEnd, FindWeaponType(mWeaponType)); - if (!mPtr.getClass().hasInventoryStore(mPtr)) + if (!mPtr.getClass().isBipedal(mPtr)) weap = sWeaponTypeListEnd; if(force || idle != mIdleState) @@ -870,10 +870,26 @@ bool CharacterController::updateWeaponState() const MWWorld::Class &cls = mPtr.getClass(); CreatureStats &stats = cls.getCreatureStats(mPtr); WeaponType weaptype = WeapType_None; - MWWorld::InventoryStore &inv = cls.getInventoryStore(mPtr); - MWWorld::ContainerStoreIterator weapon = getActiveWeapon(stats, inv, &weaptype); + if(stats.getDrawState() == DrawState_Weapon) + weaptype = WeapType_HandToHand; + else if (stats.getDrawState() == DrawState_Spell) + weaptype = WeapType_Spell; + const bool isWerewolf = cls.isNpc() && cls.getNpcStats(mPtr).isWerewolf(); + std::string soundid; + if (mPtr.getClass().hasInventoryStore(mPtr)) + { + MWWorld::InventoryStore &inv = cls.getInventoryStore(mPtr); + MWWorld::ContainerStoreIterator weapon = getActiveWeapon(stats, inv, &weaptype); + if(weapon != inv.end() && !(weaptype == WeapType_None && mWeaponType == WeapType_Spell)) + { + soundid = (weaptype == WeapType_None) ? + weapon->getClass().getDownSoundId(*weapon) : + weapon->getClass().getUpSoundId(*weapon); + } + } + bool forcestateupdate = false; if(weaptype != mWeaponType && mHitState != CharState_KnockDown) { @@ -913,16 +929,10 @@ bool CharacterController::updateWeaponState() } } - if(weapon != inv.end() && !(weaptype == WeapType_None && mWeaponType == WeapType_Spell)) + if(!soundid.empty()) { - std::string soundid = (weaptype == WeapType_None) ? - weapon->getClass().getDownSoundId(*weapon) : - weapon->getClass().getUpSoundId(*weapon); - if(!soundid.empty()) - { - MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); - sndMgr->playSound3D(mPtr, soundid, 1.0f, 1.0f); - } + MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); + sndMgr->playSound3D(mPtr, soundid, 1.0f, 1.0f); } mWeaponType = weaptype; @@ -945,22 +955,28 @@ bool CharacterController::updateWeaponState() sndMgr->stopSound3D(mPtr, "WolfRun"); } - bool isWeapon = (weapon != inv.end() && weapon->getTypeName() == typeid(ESM::Weapon).name()); - float weapSpeed = 1.0f; - if(isWeapon) - weapSpeed = weapon->get()->mBase->mData.mSpeed; - // Cancel attack if we no longer have ammunition bool ammunition = true; - MWWorld::ContainerStoreIterator ammo = inv.getSlot(MWWorld::InventoryStore::Slot_Ammunition); - if (mWeaponType == WeapType_Crossbow) - ammunition = (ammo != inv.end() && ammo->get()->mBase->mData.mType == ESM::Weapon::Bolt); - else if (mWeaponType == WeapType_BowAndArrow) - ammunition = (ammo != inv.end() && ammo->get()->mBase->mData.mType == ESM::Weapon::Arrow); - if (!ammunition && mUpperBodyState > UpperCharState_WeapEquiped) + bool isWeapon = false; + float weapSpeed = 1.f; + if (mPtr.getClass().hasInventoryStore(mPtr)) { - mAnimation->disable(mCurrentWeapon); - mUpperBodyState = UpperCharState_WeapEquiped; + MWWorld::InventoryStore &inv = cls.getInventoryStore(mPtr); + MWWorld::ContainerStoreIterator weapon = getActiveWeapon(stats, inv, &weaptype); + isWeapon = (weapon != inv.end() && weapon->getTypeName() == typeid(ESM::Weapon).name()); + if(isWeapon) + weapSpeed = weapon->get()->mBase->mData.mSpeed; + + MWWorld::ContainerStoreIterator ammo = inv.getSlot(MWWorld::InventoryStore::Slot_Ammunition); + if (mWeaponType == WeapType_Crossbow) + ammunition = (ammo != inv.end() && ammo->get()->mBase->mData.mType == ESM::Weapon::Bolt); + else if (mWeaponType == WeapType_BowAndArrow) + ammunition = (ammo != inv.end() && ammo->get()->mBase->mData.mType == ESM::Weapon::Arrow); + if (!ammunition && mUpperBodyState > UpperCharState_WeapEquiped) + { + mAnimation->disable(mCurrentWeapon); + mUpperBodyState = UpperCharState_WeapEquiped; + } } float complete; @@ -1001,15 +1017,14 @@ bool CharacterController::updateWeaponState() const ESM::Static* castStatic = MWBase::Environment::get().getWorld()->getStore().get().find ("VFX_Hands"); if (mAnimation->getNode("Left Hand")) - { mAnimation->addEffect("meshes\\" + castStatic->mModel, -1, false, "Left Hand", effect->mParticle); - mAnimation->addEffect("meshes\\" + castStatic->mModel, -1, false, "Right Hand", effect->mParticle); - } else - { mAnimation->addEffect("meshes\\" + castStatic->mModel, -1, false, "Bip01 L Hand", effect->mParticle); + + if (mAnimation->getNode("Right Hand")) + mAnimation->addEffect("meshes\\" + castStatic->mModel, -1, false, "Right Hand", effect->mParticle); + else mAnimation->addEffect("meshes\\" + castStatic->mModel, -1, false, "Bip01 R Hand", effect->mParticle); - } switch(effectentry.mRange) { @@ -1024,14 +1039,20 @@ bool CharacterController::updateWeaponState() 0.0f, 0); mUpperBodyState = UpperCharState_CastingSpell; } - if (inv.getSelectedEnchantItem() != inv.end()) + if (mPtr.getClass().hasInventoryStore(mPtr)) { - // Enchanted items cast immediately (no animation) - MWBase::Environment::get().getWorld()->castSpell(mPtr); + MWWorld::InventoryStore& inv = mPtr.getClass().getInventoryStore(mPtr); + if (inv.getSelectedEnchantItem() != inv.end()) + { + // Enchanted items cast immediately (no animation) + MWBase::Environment::get().getWorld()->castSpell(mPtr); + } } + } else if(mWeaponType == WeapType_PickProbe) { + MWWorld::ContainerStoreIterator weapon = mPtr.getClass().getInventoryStore(mPtr).getSlot(MWWorld::InventoryStore::Slot_CarriedRight); MWWorld::Ptr item = *weapon; // TODO: this will only work for the player, and needs to be fixed if NPCs should ever use lockpicks/probes. MWWorld::Ptr target = MWBase::Environment::get().getWorld()->getFacedObject(); @@ -1063,7 +1084,10 @@ bool CharacterController::updateWeaponState() { if(isWeapon && mPtr.getRefData().getHandle() == "player" && Settings::Manager::getBool("best attack", "Game")) + { + MWWorld::ContainerStoreIterator weapon = mPtr.getClass().getInventoryStore(mPtr).getSlot(MWWorld::InventoryStore::Slot_CarriedRight); mAttackType = getBestAttack(weapon->get()->mBase); + } else determineAttackType(); } @@ -1283,17 +1307,21 @@ bool CharacterController::updateWeaponState() } } - MWWorld::ContainerStoreIterator torch = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft); - if(torch != inv.end() && torch->getTypeName() == typeid(ESM::Light).name() - && updateCarriedLeftVisible(mWeaponType)) - + if (mPtr.getClass().hasInventoryStore(mPtr)) { - mAnimation->play("torch", Priority_Torch, MWRender::Animation::Group_LeftArm, - false, 1.0f, "start", "stop", 0.0f, (~(size_t)0), true); - } - else if (mAnimation->isPlaying("torch")) - { - mAnimation->disable("torch"); + MWWorld::InventoryStore& inv = mPtr.getClass().getInventoryStore(mPtr); + MWWorld::ContainerStoreIterator torch = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft); + if(torch != inv.end() && torch->getTypeName() == typeid(ESM::Light).name() + && updateCarriedLeftVisible(mWeaponType)) + + { + mAnimation->play("torch", Priority_Torch, MWRender::Animation::Group_LeftArm, + false, 1.0f, "start", "stop", 0.0f, (~(size_t)0), true); + } + else if (mAnimation->isPlaying("torch")) + { + mAnimation->disable("torch"); + } } return forcestateupdate; @@ -1607,7 +1635,7 @@ void CharacterController::update(float duration) } } - if(cls.hasInventoryStore(mPtr)) + if(cls.isBipedal(mPtr)) forcestateupdate = updateWeaponState() || forcestateupdate; else forcestateupdate = updateCreatureState() || forcestateupdate; @@ -1839,15 +1867,12 @@ void CharacterController::determineAttackType() { float *move = mPtr.getClass().getMovementSettings(mPtr).mPosition; - if(mPtr.getClass().hasInventoryStore(mPtr)) - { - if (move[1] && !move[0]) // forward-backward - mAttackType = "thrust"; - else if (move[0] && !move[1]) //sideway - mAttackType = "slash"; - else - mAttackType = "chop"; - } + if (move[1] && !move[0]) // forward-backward + mAttackType = "thrust"; + else if (move[0] && !move[1]) //sideway + mAttackType = "slash"; + else + mAttackType = "chop"; } bool CharacterController::isReadyToBlock() const From d26d5f6c26ed1d0044654fe3e0c0a3e0c1524ed6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 31 Dec 2014 17:25:06 +0100 Subject: [PATCH 0156/3725] Fix outdated bone locations when camera view is changed while paralyzed --- apps/openmw/mwmechanics/character.cpp | 69 ++++++++++++++------------- 1 file changed, 36 insertions(+), 33 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 9f88d1573..21dbc15b9 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1640,7 +1640,8 @@ void CharacterController::update(float duration) else forcestateupdate = updateCreatureState() || forcestateupdate; - refreshCurrentAnims(idlestate, movestate, forcestateupdate); + if (!mSkipAnim) + refreshCurrentAnims(idlestate, movestate, forcestateupdate); if (inJump) mMovementAnimationControlled = false; @@ -1672,47 +1673,47 @@ void CharacterController::update(float duration) // Can't reset jump state (mPosition[2]) here; we don't know for sure whether the PhysicSystem will actually handle it in this frame // due to the fixed minimum timestep used for the physics update. It will be reset in PhysicSystem::move once the jump is handled. - updateHeadTracking(duration); + if (!mSkipAnim) + updateHeadTracking(duration); } else if(cls.getCreatureStats(mPtr).isDead()) { world->queueMovement(mPtr, Ogre::Vector3(0.0f)); } - if(!mSkipAnim) - { - Ogre::Vector3 moved = mAnimation->runAnimation(duration); - if(duration > 0.0f) - moved /= duration; - else - moved = Ogre::Vector3(0.0f); - - // Ensure we're moving in generally the right direction... - if(mMovementSpeed > 0.f) - { - float l = moved.length(); - - if((movement.x < 0.0f && movement.x < moved.x*2.0f) || - (movement.x > 0.0f && movement.x > moved.x*2.0f)) - moved.x = movement.x; - if((movement.y < 0.0f && movement.y < moved.y*2.0f) || - (movement.y > 0.0f && movement.y > moved.y*2.0f)) - moved.y = movement.y; - if((movement.z < 0.0f && movement.z < moved.z*2.0f) || - (movement.z > 0.0f && movement.z > moved.z*2.0f)) - moved.z = movement.z; - // but keep the original speed - float newLength = moved.length(); - if (newLength > 0) - moved *= (l / newLength); - } + Ogre::Vector3 moved = mAnimation->runAnimation(mSkipAnim ? 0.f : duration); + if(duration > 0.0f) + moved /= duration; + else + moved = Ogre::Vector3(0.0f); - // Update movement - if(mMovementAnimationControlled && mPtr.getClass().isActor()) - world->queueMovement(mPtr, moved); + // Ensure we're moving in generally the right direction... + if(mMovementSpeed > 0.f) + { + float l = moved.length(); + + if((movement.x < 0.0f && movement.x < moved.x*2.0f) || + (movement.x > 0.0f && movement.x > moved.x*2.0f)) + moved.x = movement.x; + if((movement.y < 0.0f && movement.y < moved.y*2.0f) || + (movement.y > 0.0f && movement.y > moved.y*2.0f)) + moved.y = movement.y; + if((movement.z < 0.0f && movement.z < moved.z*2.0f) || + (movement.z > 0.0f && movement.z > moved.z*2.0f)) + moved.z = movement.z; + // but keep the original speed + float newLength = moved.length(); + if (newLength > 0) + moved *= (l / newLength); } - else + + if (mSkipAnim) mAnimation->updateEffects(duration); + + // Update movement + if(mMovementAnimationControlled && mPtr.getClass().isActor()) + world->queueMovement(mPtr, moved); + mSkipAnim = false; mAnimation->enableHeadAnimation(cls.isActor() && !cls.getCreatureStats(mPtr).isDead()); @@ -1781,6 +1782,8 @@ void CharacterController::forceStateUpdate() { playRandomDeath(); } + + mAnimation->runAnimation(0.f); } bool CharacterController::kill() From a8ae0dec522914f801eec9869fae57506bb166f9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 31 Dec 2014 18:41:57 +0100 Subject: [PATCH 0157/3725] Implement AiWander fast-forward (Feature #1125) --- apps/openmw/mwmechanics/actors.cpp | 14 ++ apps/openmw/mwmechanics/actors.hpp | 3 + apps/openmw/mwmechanics/aipackage.hpp | 3 + apps/openmw/mwmechanics/aisequence.cpp | 9 + apps/openmw/mwmechanics/aisequence.hpp | 3 + apps/openmw/mwmechanics/aistate.hpp | 20 +- apps/openmw/mwmechanics/aitravel.cpp | 5 + apps/openmw/mwmechanics/aitravel.hpp | 3 + apps/openmw/mwmechanics/aiwander.cpp | 183 +++++++++--------- apps/openmw/mwmechanics/aiwander.hpp | 5 +- .../mwmechanics/mechanicsmanagerimp.cpp | 1 + 11 files changed, 141 insertions(+), 108 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 1a1d8c154..ca06b57d3 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1641,4 +1641,18 @@ namespace MWMechanics return it->second->getCharacterController()->isReadyToBlock(); } + + void Actors::fastForwardAi() + { + if (!MWBase::Environment::get().getMechanicsManager()->isAIActive()) + return; + for (PtrActorMap::iterator it = mActors.begin(); it != mActors.end(); ++it) + { + MWWorld::Ptr ptr = it->first; + if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + continue; + MWMechanics::AiSequence& seq = ptr.getClass().getCreatureStats(ptr).getAiSequence(); + seq.fastForward(ptr, it->second->getAiState()); + } + } } diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index 91bfad170..39fe38208 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -101,6 +101,9 @@ namespace MWMechanics int getHoursToRest(const MWWorld::Ptr& ptr) const; ///< Calculate how many hours the given actor needs to rest in order to be fully healed + void fastForwardAi(); + ///< Simulate the passing of time + int countDeaths (const std::string& id) const; ///< Return the number of deaths for actors with the given ID. diff --git a/apps/openmw/mwmechanics/aipackage.hpp b/apps/openmw/mwmechanics/aipackage.hpp index ca08de072..80b48fc37 100644 --- a/apps/openmw/mwmechanics/aipackage.hpp +++ b/apps/openmw/mwmechanics/aipackage.hpp @@ -63,6 +63,9 @@ namespace MWMechanics virtual void writeState (ESM::AiSequence::AiSequence& sequence) const {} + /// Simulates the passing of time + virtual void fastForward(const MWWorld::Ptr& actor, AiState& state) {} + protected: /// Causes the actor to attempt to walk to the specified location /** \return If the actor has arrived at his destination **/ diff --git a/apps/openmw/mwmechanics/aisequence.cpp b/apps/openmw/mwmechanics/aisequence.cpp index 2ee898405..ea59708c2 100644 --- a/apps/openmw/mwmechanics/aisequence.cpp +++ b/apps/openmw/mwmechanics/aisequence.cpp @@ -390,4 +390,13 @@ void AiSequence::readState(const ESM::AiSequence::AiSequence &sequence) } } +void AiSequence::fastForward(const MWWorld::Ptr& actor, AiState& state) +{ + if (!mPackages.empty()) + { + MWMechanics::AiPackage* package = mPackages.front(); + package->fastForward(actor, state); + } +} + } // namespace MWMechanics diff --git a/apps/openmw/mwmechanics/aisequence.hpp b/apps/openmw/mwmechanics/aisequence.hpp index 460a411ba..e43ce72f1 100644 --- a/apps/openmw/mwmechanics/aisequence.hpp +++ b/apps/openmw/mwmechanics/aisequence.hpp @@ -97,6 +97,9 @@ namespace MWMechanics /// Execute current package, switching if needed. void execute (const MWWorld::Ptr& actor, MWMechanics::AiState& state, float duration); + /// Simulate the passing of time using the currently active AI package + void fastForward(const MWWorld::Ptr &actor, AiState &state); + /// Remove all packages. void clear(); diff --git a/apps/openmw/mwmechanics/aistate.hpp b/apps/openmw/mwmechanics/aistate.hpp index 7b670ad47..581f45d07 100644 --- a/apps/openmw/mwmechanics/aistate.hpp +++ b/apps/openmw/mwmechanics/aistate.hpp @@ -76,24 +76,6 @@ namespace MWMechanics mStorage = p; } - /// \brief gives away ownership of object. Throws exception if storage does not contain Derived or is empty. - template< class Derived > - Derived* moveOut() - { - assert_derived(); - - - if(!mStorage) - throw std::runtime_error("Cant move out: empty storage."); - - Derived* result = dynamic_cast(mStorage); - - if(!mStorage) - throw std::runtime_error("Cant move out: wrong type requested."); - - return result; - } - bool empty() const { return mStorage == NULL; @@ -120,7 +102,7 @@ namespace MWMechanics /// \brief base class for the temporary storage of AiPackages. /** * Each AI package with temporary values needs a AiPackageStorage class - * which is derived from AiTemporaryBase. The CharacterController holds a container + * which is derived from AiTemporaryBase. The Actor holds a container * AiState where one of these storages can be stored at a time. * The execute(...) member function takes this container as an argument. * */ diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index 959784983..64bf8a61b 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -113,6 +113,11 @@ namespace MWMechanics return TypeIdTravel; } + void AiTravel::fastForward(const MWWorld::Ptr& actor, AiState& state) + { + + } + void AiTravel::writeState(ESM::AiSequence::AiSequence &sequence) const { std::auto_ptr travel(new ESM::AiSequence::AiTravel()); diff --git a/apps/openmw/mwmechanics/aitravel.hpp b/apps/openmw/mwmechanics/aitravel.hpp index c2c33c2cf..c2732e3aa 100644 --- a/apps/openmw/mwmechanics/aitravel.hpp +++ b/apps/openmw/mwmechanics/aitravel.hpp @@ -23,6 +23,9 @@ namespace MWMechanics AiTravel(float x, float y, float z); AiTravel(const ESM::AiSequence::AiTravel* travel); + /// Simulates the passing of time + virtual void fastForward(const MWWorld::Ptr& actor, AiState& state); + void writeState(ESM::AiSequence::AiSequence &sequence) const; virtual AiTravel *clone() const; diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index c8a0c85d5..20588e5c3 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -40,16 +40,9 @@ namespace MWMechanics AiWander::GreetingState mSaidGreeting; int mGreetingTimer; - - // Cached current cell location - int mCellX; - int mCellY; - // Cell location multiplied by ESM::Land::REAL_SIZE - float mXCell; - float mYCell; - + const MWWorld::CellStore* mCell; // for detecting cell change - + // AiWander states bool mChooseAction; bool mIdleNow; @@ -66,10 +59,6 @@ namespace MWMechanics mReaction(0), mSaidGreeting(AiWander::Greet_None), mGreetingTimer(0), - mCellX(std::numeric_limits::max()), - mCellY(std::numeric_limits::max()), - mXCell(0), - mYCell(0), mCell(NULL), mChooseAction(true), mIdleNow(false), @@ -183,7 +172,6 @@ namespace MWMechanics currentCell = actor.getCell(); mStoredAvailableNodes = false; // prob. not needed since mDistance = 0 } - const ESM::Cell *cell = currentCell->getCell(); cStats.setDrawState(DrawState_Nothing); cStats.setMovementFlag(CreatureStats::Flag_Run, false); @@ -371,81 +359,10 @@ namespace MWMechanics } } - - - int& cachedCellX = storage.mCellX; - int& cachedCellY = storage.mCellY; - float& cachedCellXposition = storage.mXCell; - float& cachedCellYposition = storage.mYCell; // Initialization to discover & store allowed node points for this actor. if(!mStoredAvailableNodes) { - // infrequently used, therefore no benefit in caching it as a member - const ESM::Pathgrid * - pathgrid = world->getStore().get().search(*cell); - - // cache the current cell location - cachedCellX = cell->mData.mX; - cachedCellY = cell->mData.mY; - - // If there is no path this actor doesn't go anywhere. See: - // https://forum.openmw.org/viewtopic.php?t=1556 - // http://www.fliggerty.com/phpBB3/viewtopic.php?f=30&t=5833 - if(!pathgrid || pathgrid->mPoints.empty()) - mDistance = 0; - - // A distance value passed into the constructor indicates how far the - // actor can wander from the spawn position. AiWander assumes that - // pathgrid points are available, and uses them to randomly select wander - // destinations within the allowed set of pathgrid points (nodes). - if(mDistance) - { - cachedCellXposition = 0; - cachedCellYposition = 0; - if(cell->isExterior()) - { - cachedCellXposition = cachedCellX * ESM::Land::REAL_SIZE; - cachedCellYposition = cachedCellY * ESM::Land::REAL_SIZE; - } - - // FIXME: There might be a bug here. The allowed node points are - // based on the actor's current position rather than the actor's - // spawn point. As a result the allowed nodes for wander can change - // between saves, for example. - // - // convert npcPos to local (i.e. cell) co-ordinates - Ogre::Vector3 npcPos(pos.pos); - npcPos[0] = npcPos[0] - cachedCellXposition; - npcPos[1] = npcPos[1] - cachedCellYposition; - - // mAllowedNodes for this actor with pathgrid point indexes based on mDistance - // NOTE: mPoints and mAllowedNodes are in local co-ordinates - for(unsigned int counter = 0; counter < pathgrid->mPoints.size(); counter++) - { - Ogre::Vector3 nodePos(pathgrid->mPoints[counter].mX, pathgrid->mPoints[counter].mY, - pathgrid->mPoints[counter].mZ); - if(npcPos.squaredDistance(nodePos) <= mDistance * mDistance) - mAllowedNodes.push_back(pathgrid->mPoints[counter]); - } - if(!mAllowedNodes.empty()) - { - Ogre::Vector3 firstNodePos(mAllowedNodes[0].mX, mAllowedNodes[0].mY, mAllowedNodes[0].mZ); - float closestNode = npcPos.squaredDistance(firstNodePos); - unsigned int index = 0; - for(unsigned int counterThree = 1; counterThree < mAllowedNodes.size(); counterThree++) - { - Ogre::Vector3 nodePos(mAllowedNodes[counterThree].mX, mAllowedNodes[counterThree].mY, - mAllowedNodes[counterThree].mZ); - float tempDist = npcPos.squaredDistance(nodePos); - if(tempDist < closestNode) - index = counterThree; - } - mCurrentNode = mAllowedNodes[index]; - mAllowedNodes.erase(mAllowedNodes.begin() + index); - - mStoredAvailableNodes = true; // set only if successful in finding allowed nodes - } - } + getAllowedNodes(actor, currentCell->getCell()); } // Actor becomes stationary - see above URL's for previous research @@ -581,8 +498,8 @@ namespace MWMechanics // convert dest to use world co-ordinates ESM::Pathgrid::Point dest; - dest.mX = destNodePos[0] + cachedCellXposition; - dest.mY = destNodePos[1] + cachedCellYposition; + dest.mX = destNodePos[0] + currentCell->getCell()->mData.mX * ESM::Land::REAL_SIZE; + dest.mY = destNodePos[1] + currentCell->getCell()->mData.mY * ESM::Land::REAL_SIZE; dest.mZ = destNodePos[2]; // actor position is already in world co-ordinates @@ -732,6 +649,96 @@ namespace MWMechanics } } + void AiWander::fastForward(const MWWorld::Ptr& actor, AiState &state) + { + if (mDistance == 0) + return; + + if (!mStoredAvailableNodes) + getAllowedNodes(actor, actor.getCell()->getCell()); + + if (mAllowedNodes.empty()) + return; + + state.moveIn(new AiWanderStorage()); + + int index = std::rand() / (static_cast (RAND_MAX) + 1) * mAllowedNodes.size(); + ESM::Pathgrid::Point dest = mAllowedNodes[index]; + + // apply a slight offset to prevent overcrowding + dest.mX += Ogre::Math::RangeRandom(-64, 64); + dest.mY += Ogre::Math::RangeRandom(-64, 64); + + MWBase::Environment::get().getWorld()->moveObject(actor, dest.mX, dest.mY, dest.mZ); + actor.getClass().adjustPosition(actor, false); + } + + void AiWander::getAllowedNodes(const MWWorld::Ptr& actor, const ESM::Cell* cell) + { + // infrequently used, therefore no benefit in caching it as a member + const ESM::Pathgrid * + pathgrid = MWBase::Environment::get().getWorld()->getStore().get().search(*cell); + + // If there is no path this actor doesn't go anywhere. See: + // https://forum.openmw.org/viewtopic.php?t=1556 + // http://www.fliggerty.com/phpBB3/viewtopic.php?f=30&t=5833 + if(!pathgrid || pathgrid->mPoints.empty()) + mDistance = 0; + + // A distance value passed into the constructor indicates how far the + // actor can wander from the spawn position. AiWander assumes that + // pathgrid points are available, and uses them to randomly select wander + // destinations within the allowed set of pathgrid points (nodes). + if(mDistance) + { + float cellXOffset = 0; + float cellYOffset = 0; + if(cell->isExterior()) + { + cellXOffset = cell->mData.mX * ESM::Land::REAL_SIZE; + cellYOffset = cell->mData.mY * ESM::Land::REAL_SIZE; + } + + // FIXME: There might be a bug here. The allowed node points are + // based on the actor's current position rather than the actor's + // spawn point. As a result the allowed nodes for wander can change + // between saves, for example. + // + // convert npcPos to local (i.e. cell) co-ordinates + Ogre::Vector3 npcPos(actor.getRefData().getPosition().pos); + npcPos[0] = npcPos[0] - cellXOffset; + npcPos[1] = npcPos[1] - cellYOffset; + + // mAllowedNodes for this actor with pathgrid point indexes based on mDistance + // NOTE: mPoints and mAllowedNodes are in local co-ordinates + for(unsigned int counter = 0; counter < pathgrid->mPoints.size(); counter++) + { + Ogre::Vector3 nodePos(pathgrid->mPoints[counter].mX, pathgrid->mPoints[counter].mY, + pathgrid->mPoints[counter].mZ); + if(npcPos.squaredDistance(nodePos) <= mDistance * mDistance) + mAllowedNodes.push_back(pathgrid->mPoints[counter]); + } + if(!mAllowedNodes.empty()) + { + Ogre::Vector3 firstNodePos(mAllowedNodes[0].mX, mAllowedNodes[0].mY, mAllowedNodes[0].mZ); + float closestNode = npcPos.squaredDistance(firstNodePos); + unsigned int index = 0; + for(unsigned int counterThree = 1; counterThree < mAllowedNodes.size(); counterThree++) + { + Ogre::Vector3 nodePos(mAllowedNodes[counterThree].mX, mAllowedNodes[counterThree].mY, + mAllowedNodes[counterThree].mZ); + float tempDist = npcPos.squaredDistance(nodePos); + if(tempDist < closestNode) + index = counterThree; + } + mCurrentNode = mAllowedNodes[index]; + mAllowedNodes.erase(mAllowedNodes.begin() + index); + + mStoredAvailableNodes = true; // set only if successful in finding allowed nodes + } + } + } + void AiWander::writeState(ESM::AiSequence::AiSequence &sequence) const { std::auto_ptr wander(new ESM::AiSequence::AiWander()); diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index b9b394a26..cd0f6533e 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -57,6 +57,7 @@ namespace MWMechanics virtual void writeState(ESM::AiSequence::AiSequence &sequence) const; + virtual void fastForward(const MWWorld::Ptr& actor, AiState& state); enum GreetingState { Greet_None, @@ -77,7 +78,6 @@ namespace MWMechanics int mTimeOfDay; std::vector mIdle; bool mRepeat; - bool mHasReturnPosition; // NOTE: Could be removed if mReturnPosition was initialized to actor position, @@ -98,6 +98,9 @@ namespace MWMechanics // allowed pathgrid nodes based on mDistance from the spawn point std::vector mAllowedNodes; + + void getAllowedNodes(const MWWorld::Ptr& actor, const ESM::Cell* cell); + ESM::Pathgrid::Point mCurrentNode; bool mTrimCurrentNode; void trimAllowedNodes(std::vector& nodes, diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 8c6833497..42728290b 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -472,6 +472,7 @@ namespace MWMechanics void MechanicsManager::rest(bool sleep) { mActors.restoreDynamicStats (sleep); + mActors.fastForwardAi(); } int MechanicsManager::getHoursToRest() const From 99ae0f901bf66729045aade887927419fcef67f0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 31 Dec 2014 18:55:07 +0100 Subject: [PATCH 0158/3725] Implement AiTravel fast-forward (Fixes #1125) --- apps/openmw/mwmechanics/aitravel.cpp | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index 64bf8a61b..7124a1102 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -14,6 +14,19 @@ #include "movement.hpp" #include "creaturestats.hpp" +namespace +{ + +bool isWithinMaxRange(const Ogre::Vector3& pos1, const Ogre::Vector3& pos2) +{ + // Maximum travel distance for vanilla compatibility. + // Was likely meant to prevent NPCs walking into non-loaded exterior cells, but for some reason is used in interior cells as well. + // We can make this configurable at some point, but the default *must* be the below value. Anything else will break shoddily-written content (*cough* MW *cough*) in bizarre ways. + return (pos1.squaredDistance(pos2) <= 7168*7168); +} + +} + namespace MWMechanics { AiTravel::AiTravel(float x, float y, float z) @@ -71,10 +84,7 @@ namespace MWMechanics } } - // Maximum travel distance for vanilla compatibility. - // Was likely meant to prevent NPCs walking into non-loaded exterior cells, but for some reason is used in interior cells as well. - // We can make this configurable at some point, but the default *must* be the below value. Anything else will break shoddily-written content (*cough* MW *cough*) in bizarre ways. - if (Ogre::Vector3(mX, mY, mZ).squaredDistance(Ogre::Vector3(pos.pos)) > 7168*7168) + if (!isWithinMaxRange(Ogre::Vector3(mX, mY, mZ), Ogre::Vector3(pos.pos))) return false; bool cellChange = cell->mData.mX != mCellX || cell->mData.mY != mCellY; @@ -115,7 +125,12 @@ namespace MWMechanics void AiTravel::fastForward(const MWWorld::Ptr& actor, AiState& state) { - + if (!isWithinMaxRange(Ogre::Vector3(mX, mY, mZ), Ogre::Vector3(actor.getRefData().getPosition().pos))) + return; + // does not do any validation on the travel target (whether it's in air, inside collision geometry, etc), + // that is the user's responsibility + MWBase::Environment::get().getWorld()->moveObject(actor, mX, mY, mZ); + actor.getClass().adjustPosition(actor, false); } void AiTravel::writeState(ESM::AiSequence::AiSequence &sequence) const From 5d7eb11596be16f9426f40535b4e422774b0e36c Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 31 Dec 2014 21:04:13 +0100 Subject: [PATCH 0159/3725] Fix lights being rendered on the map (broken by d55fe43fc95bf) --- apps/openmw/mwrender/actors.cpp | 14 ++++++++++++++ apps/openmw/mwrender/actors.hpp | 5 ++++- apps/openmw/mwrender/objects.cpp | 14 -------------- apps/openmw/mwrender/objects.hpp | 3 --- apps/openmw/mwrender/renderingmanager.cpp | 4 ++-- 5 files changed, 20 insertions(+), 20 deletions(-) diff --git a/apps/openmw/mwrender/actors.cpp b/apps/openmw/mwrender/actors.cpp index 06acf4b3c..db666e890 100644 --- a/apps/openmw/mwrender/actors.cpp +++ b/apps/openmw/mwrender/actors.cpp @@ -198,4 +198,18 @@ void Actors::updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur) mRendering->updateWaterRippleEmitterPtr (old, cur); } +void Actors::enableLights() +{ + PtrAnimationMap::const_iterator it = mAllActors.begin(); + for(;it != mAllActors.end();++it) + it->second->enableLights(true); +} + +void Actors::disableLights() +{ + PtrAnimationMap::const_iterator it = mAllActors.begin(); + for(;it != mAllActors.end();++it) + it->second->enableLights(false); +} + } diff --git a/apps/openmw/mwrender/actors.hpp b/apps/openmw/mwrender/actors.hpp index 177c8a732..f81082e41 100644 --- a/apps/openmw/mwrender/actors.hpp +++ b/apps/openmw/mwrender/actors.hpp @@ -42,9 +42,12 @@ namespace MWRender void insertNPC(const MWWorld::Ptr& ptr); void insertCreature (const MWWorld::Ptr& ptr, bool weaponsShields); void insertActivator (const MWWorld::Ptr& ptr, bool addLight=false); - bool deleteObject (const MWWorld::Ptr& ptr); + bool deleteObject (const MWWorld::Ptr& ptr); ///< \return found? + void enableLights(); + void disableLights(); + void removeCell(MWWorld::CellStore* store); void update (Ogre::Camera* camera); diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 96cce178e..965083019 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -237,20 +237,6 @@ Ogre::AxisAlignedBox Objects::getDimensions(MWWorld::CellStore* cell) return mBounds[cell]; } -void Objects::enableLights() -{ - PtrAnimationMap::const_iterator it = mObjects.begin(); - for(;it != mObjects.end();++it) - it->second->enableLights(true); -} - -void Objects::disableLights() -{ - PtrAnimationMap::const_iterator it = mObjects.begin(); - for(;it != mObjects.end();++it) - it->second->enableLights(false); -} - void Objects::update(float dt, Ogre::Camera* camera) { PtrAnimationMap::const_iterator it = mObjects.begin(); diff --git a/apps/openmw/mwrender/objects.hpp b/apps/openmw/mwrender/objects.hpp index 02e974e2d..adfe5ca26 100644 --- a/apps/openmw/mwrender/objects.hpp +++ b/apps/openmw/mwrender/objects.hpp @@ -45,9 +45,6 @@ public: ObjectAnimation* getAnimation(const MWWorld::Ptr &ptr); - void enableLights(); - void disableLights(); - void update (float dt, Ogre::Camera* camera); ///< per-frame update diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 2cddbce75..33649ea7c 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -677,13 +677,13 @@ void RenderingManager::writeFog(MWWorld::CellStore* cell) void RenderingManager::disableLights(bool sun) { - mObjects->disableLights(); + mActors->disableLights(); sunDisable(sun); } void RenderingManager::enableLights(bool sun) { - mObjects->enableLights(); + mActors->enableLights(); sunEnable(sun); } From 93bbd7463ad1c0b9e97c1e9794f916b2ce1823c6 Mon Sep 17 00:00:00 2001 From: dteviot Date: Thu, 1 Jan 2015 09:40:42 +1300 Subject: [PATCH 0160/3725] Fixed errors and warnings from Travis CI. --- components/contentselector/model/contentmodel.cpp | 2 +- components/contentselector/model/loadordererror.cpp | 2 +- components/contentselector/model/loadordererror.hpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/components/contentselector/model/contentmodel.cpp b/components/contentselector/model/contentmodel.cpp index 72bca2244..b74960dc8 100644 --- a/components/contentselector/model/contentmodel.cpp +++ b/components/contentselector/model/contentmodel.cpp @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include "components/esm/esmreader.hpp" diff --git a/components/contentselector/model/loadordererror.cpp b/components/contentselector/model/loadordererror.cpp index c8b258e98..593c53abb 100644 --- a/components/contentselector/model/loadordererror.cpp +++ b/components/contentselector/model/loadordererror.cpp @@ -5,7 +5,7 @@ QString ContentSelectorModel::LoadOrderError::sErrorToolTips[ErrorCode_LoadOrder { QString("Unable to find dependant file: %1"), QString("Dependent file needs to be active: %1"), - QString("This file needs to load after %1"), + QString("This file needs to load after %1") }; ContentSelectorModel::LoadOrderError ContentSelectorModel::LoadOrderError::sNoError = ContentSelectorModel::LoadOrderError(); diff --git a/components/contentselector/model/loadordererror.hpp b/components/contentselector/model/loadordererror.hpp index 75ec2ad92..f7a58c25f 100644 --- a/components/contentselector/model/loadordererror.hpp +++ b/components/contentselector/model/loadordererror.hpp @@ -14,7 +14,7 @@ namespace ContentSelectorModel ErrorCode_None = 0, ErrorCode_MissingDependency = 1, ErrorCode_InactiveDependency = 2, - ErrorCode_LoadOrder = 3, + ErrorCode_LoadOrder = 3 }; inline LoadOrderError() : mErrorCode(ErrorCode_None) {}; From 43dd9aee94c70230181eea114e1165210fb5d510 Mon Sep 17 00:00:00 2001 From: dteviot Date: Thu, 1 Jan 2015 10:13:27 +1300 Subject: [PATCH 0161/3725] Fix for more errors found by Travis CI. --- components/contentselector/model/contentmodel.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/contentselector/model/contentmodel.hpp b/components/contentselector/model/contentmodel.hpp index fc50eeb85..2a9f2c93b 100644 --- a/components/contentselector/model/contentmodel.hpp +++ b/components/contentselector/model/contentmodel.hpp @@ -54,8 +54,8 @@ namespace ContentSelectorModel void uncheckAll(); bool isLoadOrderError(const QString& filepath) const; - ContentSelectorModel::LoadOrderError ContentSelectorModel::ContentModel::getLoadOrderError(const QString& filepath) const; - void ContentSelectorModel::ContentModel::setLoadOrderError(const QString& filepath, const ContentSelectorModel::LoadOrderError& loadOrderError); + LoadOrderError getLoadOrderError(const QString& filepath) const; + void setLoadOrderError(const QString& filepath, const LoadOrderError& loadOrderError); void refreshModel(); From 01652bbcc5d8c80868781a1e949eee5901870e8a Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 31 Dec 2014 21:27:19 +0100 Subject: [PATCH 0162/3725] Store original actor position in AiWander package (Fixes #2200) --- apps/openmw/mwmechanics/aiwander.cpp | 18 ++++++---- apps/openmw/mwmechanics/aiwander.hpp | 3 +- components/CMakeLists.txt | 2 +- components/esm/aisequence.cpp | 8 +++++ components/esm/aisequence.hpp | 5 +++ components/esm/projectilestate.hpp | 39 ++------------------- components/esm/util.hpp | 51 ++++++++++++++++++++++++++++ 7 files changed, 81 insertions(+), 45 deletions(-) create mode 100644 components/esm/util.hpp diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 20588e5c3..95b597def 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -70,6 +70,7 @@ namespace MWMechanics AiWander::AiWander(int distance, int duration, int timeOfDay, const std::vector& idle, bool repeat): mDistance(distance), mDuration(duration), mTimeOfDay(timeOfDay), mIdle(idle), mRepeat(repeat) + , mStoredInitialActorPosition(false) { mIdle.resize(8, 0); init(); @@ -675,6 +676,12 @@ namespace MWMechanics void AiWander::getAllowedNodes(const MWWorld::Ptr& actor, const ESM::Cell* cell) { + if (!mStoredInitialActorPosition) + { + mInitialActorPosition = Ogre::Vector3(actor.getRefData().getPosition().pos); + mStoredInitialActorPosition = true; + } + // infrequently used, therefore no benefit in caching it as a member const ESM::Pathgrid * pathgrid = MWBase::Environment::get().getWorld()->getStore().get().search(*cell); @@ -699,13 +706,8 @@ namespace MWMechanics cellYOffset = cell->mData.mY * ESM::Land::REAL_SIZE; } - // FIXME: There might be a bug here. The allowed node points are - // based on the actor's current position rather than the actor's - // spawn point. As a result the allowed nodes for wander can change - // between saves, for example. - // // convert npcPos to local (i.e. cell) co-ordinates - Ogre::Vector3 npcPos(actor.getRefData().getPosition().pos); + Ogre::Vector3 npcPos(mInitialActorPosition); npcPos[0] = npcPos[0] - cellXOffset; npcPos[1] = npcPos[1] - cellYOffset; @@ -750,6 +752,9 @@ namespace MWMechanics for (int i=0; i<8; ++i) wander->mData.mIdle[i] = mIdle[i]; wander->mData.mShouldRepeat = mRepeat; + wander->mStoredInitialActorPosition = mStoredInitialActorPosition; + if (mStoredInitialActorPosition) + wander->mInitialActorPosition = mInitialActorPosition; ESM::AiSequence::AiPackageContainer package; package.mType = ESM::AiSequence::Ai_Wander; @@ -763,6 +768,7 @@ namespace MWMechanics , mStartTime(MWWorld::TimeStamp(wander->mStartTime)) , mTimeOfDay(wander->mData.mTimeOfDay) , mRepeat(wander->mData.mShouldRepeat) + , mStoredInitialActorPosition(wander->mStoredInitialActorPosition) { for (int i=0; i<8; ++i) mIdle.push_back(wander->mData.mIdle[i]); diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index cd0f6533e..975ebfb81 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -84,7 +84,8 @@ namespace MWMechanics // if we had the actor in the AiWander constructor... Ogre::Vector3 mReturnPosition; - + Ogre::Vector3 mInitialActorPosition; + bool mStoredInitialActorPosition; diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 6918b87a7..b36b89814 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -46,7 +46,7 @@ add_component_dir (esm loadweap records aipackage effectlist spelllist variant variantimp loadtes3 cellref filter savedgame journalentry queststate locals globalscript player objectstate cellid cellstate globalmap lightstate inventorystate containerstate npcstate creaturestate dialoguestate statstate npcstats creaturestats weatherstate quickkeys fogstate spellstate activespells creaturelevliststate doorstate projectilestate debugprofile - aisequence magiceffects + aisequence magiceffects util ) add_component_dir (esmterrain diff --git a/components/esm/aisequence.cpp b/components/esm/aisequence.cpp index 339b390d7..5b36f9a4c 100644 --- a/components/esm/aisequence.cpp +++ b/components/esm/aisequence.cpp @@ -16,12 +16,20 @@ namespace AiSequence { esm.getHNT (mData, "DATA"); esm.getHNT(mStartTime, "STAR"); + mStoredInitialActorPosition = false; + if (esm.isNextSub("POS_")) + { + mStoredInitialActorPosition = true; + esm.getHT(mInitialActorPosition); + } } void AiWander::save(ESMWriter &esm) const { esm.writeHNT ("DATA", mData); esm.writeHNT ("STAR", mStartTime); + if (mStoredInitialActorPosition) + esm.writeHNT ("POS_", mInitialActorPosition); } void AiTravel::load(ESMReader &esm) diff --git a/components/esm/aisequence.hpp b/components/esm/aisequence.hpp index fbf83c245..2560fbe7d 100644 --- a/components/esm/aisequence.hpp +++ b/components/esm/aisequence.hpp @@ -6,6 +6,8 @@ #include "defs.hpp" +#include "util.hpp" + namespace ESM { class ESMReader; @@ -61,6 +63,9 @@ namespace ESM AiWanderData mData; ESM::TimeStamp mStartTime; + bool mStoredInitialActorPosition; + ESM::Vector3 mInitialActorPosition; + /// \todo add more AiWander state void load(ESMReader &esm); diff --git a/components/esm/projectilestate.hpp b/components/esm/projectilestate.hpp index 6e36efb5b..51cd5d8c4 100644 --- a/components/esm/projectilestate.hpp +++ b/components/esm/projectilestate.hpp @@ -8,48 +8,13 @@ #include "effectlist.hpp" +#include "util.hpp" + namespace ESM { // format 0, savegames only - struct Quaternion - { - float mValues[4]; - - Quaternion() {} - Quaternion (Ogre::Quaternion q) - { - mValues[0] = q.w; - mValues[1] = q.x; - mValues[2] = q.y; - mValues[3] = q.z; - } - - operator Ogre::Quaternion () const - { - return Ogre::Quaternion(mValues[0], mValues[1], mValues[2], mValues[3]); - } - }; - - struct Vector3 - { - float mValues[3]; - - Vector3() {} - Vector3 (Ogre::Vector3 v) - { - mValues[0] = v.x; - mValues[1] = v.y; - mValues[2] = v.z; - } - - operator Ogre::Vector3 () const - { - return Ogre::Vector3(&mValues[0]); - } - }; - struct BaseProjectileState { std::string mId; diff --git a/components/esm/util.hpp b/components/esm/util.hpp new file mode 100644 index 000000000..bb7f3cf7c --- /dev/null +++ b/components/esm/util.hpp @@ -0,0 +1,51 @@ +#ifndef OPENMW_ESM_UTIL_H +#define OPENMW_ESM_UTIL_H + +#include +#include + +namespace ESM +{ + +// format 0, savegames only + +struct Quaternion +{ + float mValues[4]; + + Quaternion() {} + Quaternion (Ogre::Quaternion q) + { + mValues[0] = q.w; + mValues[1] = q.x; + mValues[2] = q.y; + mValues[3] = q.z; + } + + operator Ogre::Quaternion () const + { + return Ogre::Quaternion(mValues[0], mValues[1], mValues[2], mValues[3]); + } +}; + +struct Vector3 +{ + float mValues[3]; + + Vector3() {} + Vector3 (Ogre::Vector3 v) + { + mValues[0] = v.x; + mValues[1] = v.y; + mValues[2] = v.z; + } + + operator Ogre::Vector3 () const + { + return Ogre::Vector3(&mValues[0]); + } +}; + +} + +#endif From 70d3bfc6ed02f51a126314448d14614e619354d9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 31 Dec 2014 23:01:31 +0100 Subject: [PATCH 0163/3725] Fix idle animation not restarting immediately for creatures --- apps/openmw/mwmechanics/character.cpp | 74 ++++++++++++++------------- 1 file changed, 38 insertions(+), 36 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 21dbc15b9..3136ae676 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -299,37 +299,6 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat if (!mPtr.getClass().isBipedal(mPtr)) weap = sWeaponTypeListEnd; - if(force || idle != mIdleState) - { - mIdleState = idle; - - std::string idle; - // Only play "idleswim" or "idlesneak" if they exist. Otherwise, fallback to - // "idle"+weapon or "idle". - if(mIdleState == CharState_IdleSwim && mAnimation->hasAnimation("idleswim")) - idle = "idleswim"; - else if(mIdleState == CharState_IdleSneak && mAnimation->hasAnimation("idlesneak")) - idle = "idlesneak"; - else if(mIdleState != CharState_None) - { - idle = "idle"; - if(weap != sWeaponTypeListEnd) - { - idle += weap->shortgroup; - if(!mAnimation->hasAnimation(idle)) - idle = "idle"; - } - } - - mAnimation->disable(mCurrentIdle); - mCurrentIdle = idle; - if(!mCurrentIdle.empty()) - mAnimation->play(mCurrentIdle, Priority_Default, MWRender::Animation::Group_All, false, - 1.0f, "start", "stop", 0.0f, ~0ul, true); - } - - updateIdleStormState(); - if(force && mJumpState != JumpState_None) { std::string jump; @@ -470,6 +439,44 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat speedmult, ((mode!=2)?"start":"loop start"), "stop", 0.0f, ~0ul); } } + + // idle handled last as it can depend on the other states + if ((mUpperBodyState != UpperCharState_Nothing + || mMovementState != CharState_None + || mHitState != CharState_None) + && !mPtr.getClass().isBipedal(mPtr)) + idle = CharState_None; + + if(force || idle != mIdleState) + { + mIdleState = idle; + + std::string idle; + // Only play "idleswim" or "idlesneak" if they exist. Otherwise, fallback to + // "idle"+weapon or "idle". + if(mIdleState == CharState_IdleSwim && mAnimation->hasAnimation("idleswim")) + idle = "idleswim"; + else if(mIdleState == CharState_IdleSneak && mAnimation->hasAnimation("idlesneak")) + idle = "idlesneak"; + else if(mIdleState != CharState_None) + { + idle = "idle"; + if(weap != sWeaponTypeListEnd) + { + idle += weap->shortgroup; + if(!mAnimation->hasAnimation(idle)) + idle = "idle"; + } + } + + mAnimation->disable(mCurrentIdle); + mCurrentIdle = idle; + if(!mCurrentIdle.empty()) + mAnimation->play(mCurrentIdle, Priority_Default, MWRender::Animation::Group_All, false, + 1.0f, "start", "stop", 0.0f, ~0ul, true); + } + + updateIdleStormState(); } @@ -1616,11 +1623,6 @@ void CharacterController::update(float duration) if(mAnimQueue.empty()) { idlestate = (inwater ? CharState_IdleSwim : (sneak ? CharState_IdleSneak : CharState_Idle)); - if ((mUpperBodyState != UpperCharState_Nothing - || mMovementState != CharState_None - || mHitState != CharState_None) - && !mPtr.getClass().isBipedal(mPtr)) - idlestate = CharState_None; } else if(mAnimQueue.size() > 1) { From e0d083f702342f00df07d4d58cd7d43597e23ceb Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 31 Dec 2014 23:13:36 +0100 Subject: [PATCH 0164/3725] Add hand-to-hand combat mechanics for bipedal creatures You can now have a fistfight with vivec, if you so desire. --- apps/openmw/mwclass/creature.cpp | 8 +++++-- apps/openmw/mwclass/npc.cpp | 29 +------------------------ apps/openmw/mwmechanics/combat.cpp | 35 ++++++++++++++++++++++++++++++ apps/openmw/mwmechanics/combat.hpp | 2 ++ 4 files changed, 44 insertions(+), 30 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 59ab9dc90..2146fdfde 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -288,7 +288,7 @@ namespace MWClass } float damage = min + (max - min) * stats.getAttackStrength(); - + bool healthdmg = true; if (!weapon.isEmpty()) { const unsigned char *attack = NULL; @@ -321,6 +321,10 @@ namespace MWClass } } } + else if (isBipedal(ptr)) + { + MWMechanics::getHandToHandDamage(ptr, victim, damage, healthdmg); + } MWMechanics::applyElementalShields(ptr, victim); @@ -332,7 +336,7 @@ namespace MWClass MWMechanics::diseaseContact(victim, ptr); - victim.getClass().onHit(victim, damage, true, weapon, ptr, true); + victim.getClass().onHit(victim, damage, healthdmg, weapon, ptr, true); } void Creature::onHit(const MWWorld::Ptr &ptr, float damage, bool ishealth, const MWWorld::Ptr &object, const MWWorld::Ptr &attacker, bool successful) const diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 30445612a..22263d820 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -577,34 +577,7 @@ namespace MWClass } else { - // Note: MCP contains an option to include Strength in hand-to-hand damage - // calculations. Some mods recommend using it, so we may want to include am - // option for it. - float minstrike = store.find("fMinHandToHandMult")->getFloat(); - float maxstrike = store.find("fMaxHandToHandMult")->getFloat(); - damage = stats.getSkill(weapskill).getModified(); - damage *= minstrike + ((maxstrike-minstrike)*stats.getAttackStrength()); - - healthdmg = (otherstats.getMagicEffects().get(ESM::MagicEffect::Paralyze).getMagnitude() > 0) - || otherstats.getKnockedDown(); - if(stats.isWerewolf()) - { - healthdmg = true; - // GLOB instead of GMST because it gets updated during a quest - damage *= world->getGlobalFloat("werewolfclawmult"); - } - if(healthdmg) - damage *= store.find("fHandtoHandHealthPer")->getFloat(); - - MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); - if(stats.isWerewolf()) - { - const ESM::Sound *sound = world->getStore().get().searchRandom("WolfHit"); - if(sound) - sndMgr->playSound3D(victim, sound->mId, 1.0f, 1.0f); - } - else - sndMgr->playSound3D(victim, "Hand To Hand Hit", 1.0f, 1.0f); + MWMechanics::getHandToHandDamage(ptr, victim, damage, healthdmg); } if(ptr.getRefData().getHandle() == "player") { diff --git a/apps/openmw/mwmechanics/combat.cpp b/apps/openmw/mwmechanics/combat.cpp index e52dbdde7..459ff8aef 100644 --- a/apps/openmw/mwmechanics/combat.cpp +++ b/apps/openmw/mwmechanics/combat.cpp @@ -332,4 +332,39 @@ namespace MWMechanics damage *= (float(weaphealth) / weapmaxhealth); } } + + void getHandToHandDamage(const MWWorld::Ptr &attacker, const MWWorld::Ptr &victim, float &damage, bool &healthdmg) + { + // Note: MCP contains an option to include Strength in hand-to-hand damage + // calculations. Some mods recommend using it, so we may want to include an + // option for it. + const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); + float minstrike = store.get().find("fMinHandToHandMult")->getFloat(); + float maxstrike = store.get().find("fMaxHandToHandMult")->getFloat(); + damage = attacker.getClass().getSkill(attacker, ESM::Skill::HandToHand); + damage *= minstrike + ((maxstrike-minstrike)*attacker.getClass().getCreatureStats(attacker).getAttackStrength()); + + MWMechanics::CreatureStats& otherstats = victim.getClass().getCreatureStats(victim); + healthdmg = (otherstats.getMagicEffects().get(ESM::MagicEffect::Paralyze).getMagnitude() > 0) + || otherstats.getKnockedDown(); + bool isWerewolf = (attacker.getClass().isNpc() && attacker.getClass().getNpcStats(attacker).isWerewolf()); + if(isWerewolf) + { + healthdmg = true; + // GLOB instead of GMST because it gets updated during a quest + damage *= MWBase::Environment::get().getWorld()->getGlobalFloat("werewolfclawmult"); + } + if(healthdmg) + damage *= store.get().find("fHandtoHandHealthPer")->getFloat(); + + MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); + if(isWerewolf) + { + const ESM::Sound *sound = store.get().searchRandom("WolfHit"); + if(sound) + sndMgr->playSound3D(victim, sound->mId, 1.0f, 1.0f); + } + else + sndMgr->playSound3D(victim, "Hand To Hand Hit", 1.0f, 1.0f); + } } diff --git a/apps/openmw/mwmechanics/combat.hpp b/apps/openmw/mwmechanics/combat.hpp index 0d3009510..c6fc9ff92 100644 --- a/apps/openmw/mwmechanics/combat.hpp +++ b/apps/openmw/mwmechanics/combat.hpp @@ -32,6 +32,8 @@ void reduceWeaponCondition (float damage, bool hit, MWWorld::Ptr& weapon, const /// Adjust weapon damage based on its condition. A used weapon will be less effective. void adjustWeaponDamage (float& damage, const MWWorld::Ptr& weapon); +void getHandToHandDamage (const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim, float& damage, bool& healthdmg); + } #endif From dc1c52bda7b850ac0905c376579efa7d03489c64 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 1 Jan 2015 02:46:18 +0100 Subject: [PATCH 0165/3725] Add some todo comments --- apps/openmw/mwmechanics/actors.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index ca06b57d3..753c4da88 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -73,6 +73,8 @@ bool disintegrateSlot (MWWorld::Ptr ptr, int slot, float disintegrate) if (charge == 0) return false; + // FIXME: charge should be a float, not int so that damage < 1 per frame can be applied. + // This was also a bug in the original engine. charge -= std::min(disintegrate, static_cast(charge)); @@ -522,6 +524,9 @@ namespace MWMechanics bool wasDead = creatureStats.isDead(); + // FIXME: effect ticks should go into separate functions so they can be used with either + // magnitude (instant effect) or magnitude*duration + // attributes for(int i = 0;i < ESM::Attribute::Length;++i) { @@ -731,6 +736,8 @@ namespace MWMechanics } // Update bound effects + // Note: in vanilla MW multiple bound items of the same type can be created by different spells. + // As these extra copies are kinda useless this may or may not be important. static std::map boundItemsMap; if (boundItemsMap.empty()) { From fb671fed20eb7e254665ddaab865690db3a761aa Mon Sep 17 00:00:00 2001 From: dteviot Date: Thu, 1 Jan 2015 15:53:35 +1300 Subject: [PATCH 0166/3725] Corrected issues found by Scrawl. --- components/contentselector/model/contentmodel.cpp | 6 +++--- components/contentselector/model/loadordererror.cpp | 2 +- components/contentselector/model/loadordererror.hpp | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/components/contentselector/model/contentmodel.cpp b/components/contentselector/model/contentmodel.cpp index b74960dc8..6366d7f54 100644 --- a/components/contentselector/model/contentmodel.cpp +++ b/components/contentselector/model/contentmodel.cpp @@ -592,9 +592,9 @@ void ContentSelectorModel::ContentModel::checkForLoadOrderErrors() EsmFile* file = item(row); bool isRowInError = isLoadOrderError(file->filePath()); LoadOrderError::ErrorCode error = LoadOrderError::ErrorCode_None; - foreach(QString dependantfileName, file->gameFiles()) + foreach(QString dependentfileName, file->gameFiles()) { - const EsmFile* dependentFile = item(dependantfileName); + const EsmFile* dependentFile = item(dependentfileName); if (!dependentFile) { @@ -611,7 +611,7 @@ void ContentSelectorModel::ContentModel::checkForLoadOrderErrors() if (!isRowInError && (error != LoadOrderError::ErrorCode_None)) { - setLoadOrderError(file->filePath(), LoadOrderError(error, dependantfileName)); + setLoadOrderError(file->filePath(), LoadOrderError(error, dependentfileName)); break; } } diff --git a/components/contentselector/model/loadordererror.cpp b/components/contentselector/model/loadordererror.cpp index 593c53abb..0d02efbeb 100644 --- a/components/contentselector/model/loadordererror.cpp +++ b/components/contentselector/model/loadordererror.cpp @@ -3,7 +3,7 @@ QString ContentSelectorModel::LoadOrderError::sErrorToolTips[ErrorCode_LoadOrder] = { - QString("Unable to find dependant file: %1"), + QString("Unable to find dependent file: %1"), QString("Dependent file needs to be active: %1"), QString("This file needs to load after %1") }; diff --git a/components/contentselector/model/loadordererror.hpp b/components/contentselector/model/loadordererror.hpp index f7a58c25f..f3d3b0f8a 100644 --- a/components/contentselector/model/loadordererror.hpp +++ b/components/contentselector/model/loadordererror.hpp @@ -5,7 +5,7 @@ namespace ContentSelectorModel { - /// \Details of a suspected Load Order problem a plug-in will have. This is basically a POD + /// \brief Details of a suspected Load Order problem a plug-in will have. This is basically a POD. class LoadOrderError { public: @@ -28,7 +28,7 @@ namespace ContentSelectorModel bool operator==(const LoadOrderError& rhs) const; QString toolTip() const; - /// \Sentinal to represent a "No Load Order Error" condition + /// Sentinel to represent a "No Load Order Error" condition static LoadOrderError sNoError; private: From a7a3ab0c78aef3f601e5e7006fa664a8abdf6a7e Mon Sep 17 00:00:00 2001 From: Internecine Date: Thu, 1 Jan 2015 21:26:09 +1300 Subject: [PATCH 0167/3725] Fixed instant negative dynamic stat changes being applied as positive --- apps/openmw/mwmechanics/spellcasting.cpp | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 352db88b4..71064d9b0 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -578,15 +578,27 @@ namespace MWMechanics value.restore(magnitude); target.getClass().getCreatureStats(target).setAttribute(attribute, value); } - else if (effectId == ESM::MagicEffect::DamageHealth || effectId == ESM::MagicEffect::RestoreHealth) + else if (effectId == ESM::MagicEffect::DamageHealth) { - applyDynamicStatsEffect(0, target, magnitude); + applyDynamicStatsEffect(0, target, magnitude * -1); } - else if (effectId == ESM::MagicEffect::DamageFatigue || effectId == ESM::MagicEffect::RestoreFatigue) + else if (effectId == ESM::MagicEffect::RestoreHealth) { applyDynamicStatsEffect(2, target, magnitude); } - else if (effectId == ESM::MagicEffect::DamageMagicka || effectId == ESM::MagicEffect::RestoreMagicka) + else if (effectId == ESM::MagicEffect::DamageFatigue) + { + applyDynamicStatsEffect(2, target, magnitude * -1); + } + else if (effectId == ESM::MagicEffect::RestoreFatigue) + { + applyDynamicStatsEffect(2, target, magnitude); + } + else if (effectId == ESM::MagicEffect::DamageMagicka) + { + applyDynamicStatsEffect(1, target, magnitude * -1); + } + else if (effectId == ESM::MagicEffect::RestoreMagicka) { applyDynamicStatsEffect(1, target, magnitude); } From 6cd5b78ca79212ca962fc3f69c0ea285f2aa32bd Mon Sep 17 00:00:00 2001 From: Marco Schulze Date: Thu, 1 Jan 2015 14:15:05 -0300 Subject: [PATCH 0168/3725] Fix missing include in apps/launcher/main.cpp --- apps/launcher/main.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/launcher/main.cpp b/apps/launcher/main.cpp index 3dc82bc54..e4fae74f4 100644 --- a/apps/launcher/main.cpp +++ b/apps/launcher/main.cpp @@ -1,3 +1,5 @@ +#include + #include #include #include From 559ddbb480f1d4a322585fe15a8c57fdb50c46d5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 1 Jan 2015 18:11:37 +0100 Subject: [PATCH 0169/3725] Quick fix for Ai fast-forward crash in exteriors (Fixes #2241) --- apps/openmw/mwmechanics/actors.cpp | 5 ++++- apps/openmw/mwmechanics/aiwander.cpp | 15 +++++++++++++-- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 753c4da88..1055e0f4a 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1653,7 +1653,10 @@ namespace MWMechanics { if (!MWBase::Environment::get().getMechanicsManager()->isAIActive()) return; - for (PtrActorMap::iterator it = mActors.begin(); it != mActors.end(); ++it) + + // making a copy since fast-forward could move actor to a different cell and invalidate the mActors iterator + PtrActorMap map = mActors; + for (PtrActorMap::iterator it = map.begin(); it != map.end(); ++it) { MWWorld::Ptr ptr = it->first; if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 95b597def..8ca78b6ed 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -499,9 +499,14 @@ namespace MWMechanics // convert dest to use world co-ordinates ESM::Pathgrid::Point dest; - dest.mX = destNodePos[0] + currentCell->getCell()->mData.mX * ESM::Land::REAL_SIZE; - dest.mY = destNodePos[1] + currentCell->getCell()->mData.mY * ESM::Land::REAL_SIZE; + dest.mX = destNodePos[0]; + dest.mY = destNodePos[1]; dest.mZ = destNodePos[2]; + if (currentCell->getCell()->isExterior()) + { + dest.mX += currentCell->getCell()->mData.mX * ESM::Land::REAL_SIZE; + dest.mY += currentCell->getCell()->mData.mY * ESM::Land::REAL_SIZE; + } // actor position is already in world co-ordinates ESM::Pathgrid::Point start; @@ -670,6 +675,12 @@ namespace MWMechanics dest.mX += Ogre::Math::RangeRandom(-64, 64); dest.mY += Ogre::Math::RangeRandom(-64, 64); + if (actor.getCell()->isExterior()) + { + dest.mX += actor.getCell()->getCell()->mData.mX * ESM::Land::REAL_SIZE; + dest.mY += actor.getCell()->getCell()->mData.mY * ESM::Land::REAL_SIZE; + } + MWBase::Environment::get().getWorld()->moveObject(actor, dest.mX, dest.mY, dest.mZ); actor.getClass().adjustPosition(actor, false); } From 92e4a0669c841733e3a8ae6a3cbab707ec350b9e Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 1 Jan 2015 18:58:17 +0100 Subject: [PATCH 0170/3725] Fix for AiWander state loading --- apps/openmw/mwmechanics/aiwander.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 8ca78b6ed..2df3762ab 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -781,6 +781,8 @@ namespace MWMechanics , mRepeat(wander->mData.mShouldRepeat) , mStoredInitialActorPosition(wander->mStoredInitialActorPosition) { + if (mStoredInitialActorPosition) + mInitialActorPosition = wander->mInitialActorPosition; for (int i=0; i<8; ++i) mIdle.push_back(wander->mData.mIdle[i]); From 326d0d3ebf13244659dbae72dfb528e7df0a5963 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 1 Jan 2015 22:54:39 +0100 Subject: [PATCH 0171/3725] Add default values for fNPCHealthBarTime and fNPCHealthBarFade (Fixes #2243) These GMSTs are missing in unpatched versions of the game. --- apps/openmw/mwworld/worldimp.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index fdfa19af4..1c9b8b996 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -393,6 +393,8 @@ namespace MWWorld gmst["sTauntFail"] = ESM::Variant("Taunt Fail"); gmst["sBribeSuccess"] = ESM::Variant("Bribe Success"); gmst["sBribeFail"] = ESM::Variant("Bribe Fail"); + gmst["fNPCHealthBarTime"] = ESM::Variant(5.f); + gmst["fNPCHealthBarFade"] = ESM::Variant(1.f); // Werewolf (BM) gmst["fWereWolfRunMult"] = ESM::Variant(1.f); From 17fb7aa5982207f4c918fadd8b582e5d65538e2c Mon Sep 17 00:00:00 2001 From: Thoronador Date: Sun, 26 Oct 2014 17:51:08 +0100 Subject: [PATCH 0172/3725] uninitialized stuff --- apps/opencs/model/world/refidadapterimp.cpp | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index d9a691abd..27406569b 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -223,7 +223,14 @@ void CSMWorld::ContainerRefIdAdapter::setData (const RefIdColumn *column, RefIdD } CSMWorld::CreatureColumns::CreatureColumns (const ActorColumns& actorColumns) -: ActorColumns (actorColumns) +: ActorColumns (actorColumns), + mType(NULL), + mSoul(NULL), + mScale(NULL), + mOriginal(NULL), + mCombat(NULL), + mMagic(NULL), + mStealth(NULL) {} CSMWorld::CreatureRefIdAdapter::CreatureRefIdAdapter (const CreatureColumns& columns) @@ -431,7 +438,15 @@ void CSMWorld::MiscRefIdAdapter::setData (const RefIdColumn *column, RefIdData& InventoryRefIdAdapter::setData (column, data, index, value); } -CSMWorld::NpcColumns::NpcColumns (const ActorColumns& actorColumns) : ActorColumns (actorColumns) {} +CSMWorld::NpcColumns::NpcColumns (const ActorColumns& actorColumns) +: ActorColumns (actorColumns), + mFlags(std::map()), + mRace(NULL), + mClass(NULL), + mFaction(NULL), + mHair(NULL), + mHead(NULL) +{} CSMWorld::NpcRefIdAdapter::NpcRefIdAdapter (const NpcColumns& columns) : ActorRefIdAdapter (UniversalId::Type_Npc, columns), mColumns (columns) @@ -587,4 +602,4 @@ void CSMWorld::WeaponRefIdAdapter::setData (const RefIdColumn *column, RefIdData else EnchantableRefIdAdapter::setData (column, data, index, value); } -} \ No newline at end of file +} From 91ff5364602f1aedc5e7ef49e4bf91f9d8bc2b42 Mon Sep 17 00:00:00 2001 From: Thoronador Date: Sun, 26 Oct 2014 18:18:54 +0100 Subject: [PATCH 0173/3725] fix uninit, #2 --- apps/opencs/model/world/universalid.cpp | 1 + apps/opencs/view/doc/loader.cpp | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index 190ea87d8..d19959d44 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -131,6 +131,7 @@ namespace } CSMWorld::UniversalId::UniversalId (const std::string& universalId) +: mIndex(0) { std::string::size_type index = universalId.find (':'); diff --git a/apps/opencs/view/doc/loader.cpp b/apps/opencs/view/doc/loader.cpp index ca7c93f9d..27dfd59e5 100644 --- a/apps/opencs/view/doc/loader.cpp +++ b/apps/opencs/view/doc/loader.cpp @@ -18,7 +18,7 @@ void CSVDoc::LoadingDocument::closeEvent (QCloseEvent *event) } CSVDoc::LoadingDocument::LoadingDocument (CSMDoc::Document *document) -: mDocument (document), mAborted (false), mMessages (0) +: mDocument (document), mAborted (false), mMessages (0), mTotalRecords (0) { setWindowTitle (("Opening " + document->getSavePath().filename().string()).c_str()); @@ -199,4 +199,4 @@ void CSVDoc::Loader::loadMessage (CSMDoc::Document *document, const std::string& if (iter!=mDocuments.end()) iter->second->addMessage (message); -} \ No newline at end of file +} From 526fb1b37b8f19d472744927bc8a2b8ebf51b20d Mon Sep 17 00:00:00 2001 From: Thoronador Date: Fri, 2 Jan 2015 00:45:50 +0100 Subject: [PATCH 0174/3725] fix uninitialized value in BillboardObject --- apps/openmw/mwrender/sky.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 131e12a5c..385e7d8c5 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -74,6 +74,7 @@ BillboardObject::BillboardObject( const String& textureName, const Vector3& position, SceneNode* rootNode, const std::string& material) +: mVisibility(1.0f) { SceneManager* sceneMgr = rootNode->getCreator(); From 87fac78823149c9fcc6c2c25e3e8be145593d254 Mon Sep 17 00:00:00 2001 From: Thoronador Date: Fri, 2 Jan 2015 01:01:37 +0100 Subject: [PATCH 0175/3725] fix uninitialized members in Cell and structures --- components/esm/loadcell.hpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/components/esm/loadcell.hpp b/components/esm/loadcell.hpp index a24b106d4..33e4ce61e 100644 --- a/components/esm/loadcell.hpp +++ b/components/esm/loadcell.hpp @@ -70,15 +70,27 @@ struct Cell { int mFlags; int mX, mY; + + DATAstruct() : mFlags(0), mX(0), mY(0) {} }; struct AMBIstruct { Color mAmbient, mSunlight, mFog; float mFogDensity; + + AMBIstruct() : mAmbient(0), mSunlight(0), mFog(0), mFogDensity(0) {} }; - Cell() : mWater(0) {} + Cell() : mWater(0), + mName(""), + mRegion(""), + mData(DATAstruct()), + mAmbi(AMBIstruct()), + mWaterInt(false), + mMapColor(0), + mRefNumCounter(0) + {} // Interior cells are indexed by this (it's the 'id'), for exterior // cells it is optional. From 9cc219ff762e383425f474d9a8782e84d4cc753a Mon Sep 17 00:00:00 2001 From: Thoronador Date: Fri, 2 Jan 2015 01:11:31 +0100 Subject: [PATCH 0176/3725] fix uninitialized members in Pathgrid::Point --- components/esm/loadpgrd.cpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/components/esm/loadpgrd.cpp b/components/esm/loadpgrd.cpp index 7fdc9a43c..61f56b511 100644 --- a/components/esm/loadpgrd.cpp +++ b/components/esm/loadpgrd.cpp @@ -8,18 +8,28 @@ namespace ESM { unsigned int Pathgrid::sRecordId = REC_PGRD; - Pathgrid::Point& Pathgrid::Point::operator=(const float rhs[3]) { + Pathgrid::Point& Pathgrid::Point::operator=(const float rhs[3]) + { mX = rhs[0]; mY = rhs[1]; mZ = rhs[2]; + mAutogenerated = 0; + mConnectionNum = 0; + mUnknown = 0; return *this; } - Pathgrid::Point::Point(const float rhs[3]) { + Pathgrid::Point::Point(const float rhs[3]) + : mAutogenerated(0), + mConnectionNum(0), + mUnknown(0) + { mX = rhs[0]; mY = rhs[1]; mZ = rhs[2]; } - Pathgrid::Point::Point():mX(0),mY(0),mZ(0) { + Pathgrid::Point::Point():mX(0),mY(0),mZ(0),mAutogenerated(0), + mConnectionNum(0),mUnknown(0) + { } void Pathgrid::load(ESMReader &esm) From 3b00a24f3fc0bdbe927944b258acb1c518524747 Mon Sep 17 00:00:00 2001 From: Thoronador Date: Fri, 2 Jan 2015 01:33:40 +0100 Subject: [PATCH 0177/3725] fix some uninitialized stuff in ShaderBasedRenderManager --- libs/openengine/gui/manager.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libs/openengine/gui/manager.cpp b/libs/openengine/gui/manager.cpp index 30a5b938c..512c7f069 100644 --- a/libs/openengine/gui/manager.cpp +++ b/libs/openengine/gui/manager.cpp @@ -103,6 +103,9 @@ public: mVertexProgramOneTexture(NULL), mFragmentProgramOneTexture(NULL) { + mTextureAddressMode.u = Ogre::TextureUnitState::TAM_CLAMP; + mTextureAddressMode.v = Ogre::TextureUnitState::TAM_CLAMP; + mTextureAddressMode.w = Ogre::TextureUnitState::TAM_CLAMP; } void initialise(Ogre::RenderWindow* _window, Ogre::SceneManager* _scene) From 44e01d0eaaad984e3a8014bbe7f7b4e6b19c6d12 Mon Sep 17 00:00:00 2001 From: Thoronador Date: Fri, 2 Jan 2015 02:23:10 +0100 Subject: [PATCH 0178/3725] remove redundant initialization statement See https://github.com/OpenMW/openmw/pull/423#discussion_r22403388 --- apps/opencs/model/world/refidadapterimp.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index 27406569b..47caa8d71 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -440,7 +440,6 @@ void CSMWorld::MiscRefIdAdapter::setData (const RefIdColumn *column, RefIdData& CSMWorld::NpcColumns::NpcColumns (const ActorColumns& actorColumns) : ActorColumns (actorColumns), - mFlags(std::map()), mRace(NULL), mClass(NULL), mFaction(NULL), From 4edc4142f3b4f1cde4d99392045d5d25858e6bf7 Mon Sep 17 00:00:00 2001 From: Arthur Moore Date: Tue, 28 Oct 2014 04:03:00 -0400 Subject: [PATCH 0179/3725] Made NIFStream getters templated --- components/nif/nifstream.cpp | 29 +++++++++++++++++++++++++++++ components/nif/nifstream.hpp | 4 ++++ 2 files changed, 33 insertions(+) diff --git a/components/nif/nifstream.cpp b/components/nif/nifstream.cpp index e5699db7b..4464c8af5 100644 --- a/components/nif/nifstream.cpp +++ b/components/nif/nifstream.cpp @@ -143,4 +143,33 @@ void NIFStream::getQuaternions(std::vector &quat, size_t size) quat[i] = getQuaternion(); } +template <> +char NIFStream::get(){ return getChar(); } +template <> +short NIFStream::get(){ return getShort(); } +template <> +unsigned short NIFStream::get(){ return getUShort(); } +template <> +int NIFStream::get(){ return getInt(); } +template <> +unsigned int NIFStream::get(){ return getUInt(); } +template <> +float NIFStream::get(){ return getFloat(); } + +template <> +Ogre::Vector2 NIFStream::get(){ return getVector2(); } +template <> +Ogre::Vector3 NIFStream::get(){ return getVector3(); } +template <> +Ogre::Vector4 NIFStream::get(){ return getVector4(); } +template <> +Ogre::Matrix3 NIFStream::get(){ return getMatrix3(); } +template <> +Ogre::Quaternion NIFStream::get(){ return getQuaternion(); } +template <> +Transformation NIFStream::get(){ return getTrafo(); } + +template <> +std::string NIFStream::get(){ return getString(); } + } diff --git a/components/nif/nifstream.hpp b/components/nif/nifstream.hpp index cc14971fd..f32d233b1 100644 --- a/components/nif/nifstream.hpp +++ b/components/nif/nifstream.hpp @@ -84,6 +84,10 @@ public: ///This is special since the version string doesn't start with a number, and ends with "\n" std::string getVersionString(); + //Templated functions to handle reads + template + T get(){throw std::runtime_error("Can not get this type of data from a NIF File!");} + void getShorts(std::vector &vec, size_t size); void getFloats(std::vector &vec, size_t size); void getVector2s(std::vector &vec, size_t size); From ce7cef924e80ab551066e779446dcb86c25cb4c9 Mon Sep 17 00:00:00 2001 From: Scott Howard Date: Thu, 1 Jan 2015 22:27:08 -0500 Subject: [PATCH 0180/3725] when loading a file fails, pop-up critical window and highlight error text --- apps/opencs/view/doc/loader.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/doc/loader.cpp b/apps/opencs/view/doc/loader.cpp index ca7c93f9d..3f3163f26 100644 --- a/apps/opencs/view/doc/loader.cpp +++ b/apps/opencs/view/doc/loader.cpp @@ -8,6 +8,8 @@ #include #include #include +#include +#include #include "../../model/doc/document.hpp" @@ -104,8 +106,10 @@ void CSVDoc::LoadingDocument::nextRecord (int records) void CSVDoc::LoadingDocument::abort (const std::string& error) { mAborted = true; - mError->setText (QString::fromUtf8 (("Loading failed: " + error).c_str())); + mError->setText (QString::fromUtf8 (("Loading failed: " + error + "").c_str())); mButtons->setStandardButtons (QDialogButtonBox::Close); + QMessageBox::critical(this, tr("OpenCS Loading Failed"), + QString::fromUtf8 (("Loading failed:\n" + error).c_str())); } void CSVDoc::LoadingDocument::addMessage (const std::string& message) @@ -199,4 +203,4 @@ void CSVDoc::Loader::loadMessage (CSMDoc::Document *document, const std::string& if (iter!=mDocuments.end()) iter->second->addMessage (message); -} \ No newline at end of file +} From f318ee0b8c68a46d53a0fdd216ae8d6b371eedc2 Mon Sep 17 00:00:00 2001 From: Arthur Moore Date: Tue, 28 Oct 2014 04:13:27 -0400 Subject: [PATCH 0181/3725] Add a templated option for getting vectors to NIFStream --- components/nif/nifstream.hpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/components/nif/nifstream.hpp b/components/nif/nifstream.hpp index f32d233b1..083147867 100644 --- a/components/nif/nifstream.hpp +++ b/components/nif/nifstream.hpp @@ -94,6 +94,20 @@ public: void getVector3s(std::vector &vec, size_t size); void getVector4s(std::vector &vec, size_t size); void getQuaternions(std::vector &quat, size_t size); + + ///Return a vector of whatever object is needed + template + std::vector getItems(size_t number_of_items) + { + std::vector items; + items.reserve(number_of_items); + for(size_t i=0; i < number_of_items; ++i) + { + items.push_back(get()); + } + return items; + } + }; } From 2619d57bb6afc5c31bf1a90b8c033d66f29a9a58 Mon Sep 17 00:00:00 2001 From: Arthur Moore Date: Tue, 28 Oct 2014 04:50:28 -0400 Subject: [PATCH 0182/3725] Converted most nifstream "get multiple" functions to the templated version --- components/nif/data.hpp | 16 ++++++++-------- components/nif/nifstream.cpp | 37 ------------------------------------ components/nif/nifstream.hpp | 7 ------- 3 files changed, 8 insertions(+), 52 deletions(-) diff --git a/components/nif/data.hpp b/components/nif/data.hpp index d9de12fb5..e6d3370be 100644 --- a/components/nif/data.hpp +++ b/components/nif/data.hpp @@ -44,16 +44,16 @@ public: int verts = nif->getUShort(); if(nif->getInt()) - nif->getVector3s(vertices, verts); + vertices = nif->getItems(verts); if(nif->getInt()) - nif->getVector3s(normals, verts); + normals = nif->getItems(verts); center = nif->getVector3(); radius = nif->getFloat(); if(nif->getInt()) - nif->getVector4s(colors, verts); + colors = nif->getItems(verts); // Only the first 6 bits are used as a count. I think the rest are // flags of some sort. @@ -64,7 +64,7 @@ public: { uvlist.resize(uvs); for(int i = 0;i < uvs;i++) - nif->getVector2s(uvlist[i], verts); + uvlist[i] = nif->getItems(verts); } } }; @@ -84,7 +84,7 @@ public: // We have three times as many vertices as triangles, so this // is always equal to tris*3. int cnt = nif->getInt(); - nif->getShorts(triangles, cnt); + triangles = nif->getItems(cnt); // Read the match list, which lists the vertices that are equal to // vertices. We don't actually need need this for anything, so @@ -123,7 +123,7 @@ public: if(nif->getInt()) { // Particle sizes - nif->getFloats(sizes, vertices.size()); + sizes = nif->getItems(vertices.size()); } } }; @@ -140,7 +140,7 @@ public: if(nif->getInt()) { // Rotation quaternions. - nif->getQuaternions(rotations, vertices.size()); + rotations = nif->getItems(vertices.size()); } } }; @@ -341,7 +341,7 @@ struct NiMorphData : public Record for(int i = 0;i < morphCount;i++) { mMorphs[i].mData.read(nif, true); - nif->getVector3s(mMorphs[i].mVertices, vertCount); + mMorphs[i].mVertices = nif->getItems(vertCount); } } }; diff --git a/components/nif/nifstream.cpp b/components/nif/nifstream.cpp index 4464c8af5..9eeee6a12 100644 --- a/components/nif/nifstream.cpp +++ b/components/nif/nifstream.cpp @@ -106,43 +106,6 @@ std::string NIFStream::getVersionString() return inp->getLine(); } -void NIFStream::getShorts(std::vector &vec, size_t size) -{ - vec.resize(size); - for(size_t i = 0;i < vec.size();i++) - vec[i] = getShort(); -} -void NIFStream::getFloats(std::vector &vec, size_t size) -{ - vec.resize(size); - for(size_t i = 0;i < vec.size();i++) - vec[i] = getFloat(); -} -void NIFStream::getVector2s(std::vector &vec, size_t size) -{ - vec.resize(size); - for(size_t i = 0;i < vec.size();i++) - vec[i] = getVector2(); -} -void NIFStream::getVector3s(std::vector &vec, size_t size) -{ - vec.resize(size); - for(size_t i = 0;i < vec.size();i++) - vec[i] = getVector3(); -} -void NIFStream::getVector4s(std::vector &vec, size_t size) -{ - vec.resize(size); - for(size_t i = 0;i < vec.size();i++) - vec[i] = getVector4(); -} -void NIFStream::getQuaternions(std::vector &quat, size_t size) -{ - quat.resize(size); - for(size_t i = 0;i < quat.size();i++) - quat[i] = getQuaternion(); -} - template <> char NIFStream::get(){ return getChar(); } template <> diff --git a/components/nif/nifstream.hpp b/components/nif/nifstream.hpp index 083147867..b9caa1536 100644 --- a/components/nif/nifstream.hpp +++ b/components/nif/nifstream.hpp @@ -88,13 +88,6 @@ public: template T get(){throw std::runtime_error("Can not get this type of data from a NIF File!");} - void getShorts(std::vector &vec, size_t size); - void getFloats(std::vector &vec, size_t size); - void getVector2s(std::vector &vec, size_t size); - void getVector3s(std::vector &vec, size_t size); - void getVector4s(std::vector &vec, size_t size); - void getQuaternions(std::vector &quat, size_t size); - ///Return a vector of whatever object is needed template std::vector getItems(size_t number_of_items) From c1315ed90c87a457f17e6076c149465da3fa6c3a Mon Sep 17 00:00:00 2001 From: Arthur Moore Date: Thu, 1 Jan 2015 21:51:54 -0500 Subject: [PATCH 0183/3725] Build the nif file tester by default It's extremely useful in determining if a nif file is bad without having to load up openmw or opencs. Also updated the nif testing script to run at a low priority. --- CMakeLists.txt | 2 +- components/nif/tests/test.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d7c85818e..fb89f4e91 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -82,7 +82,7 @@ option(BUILD_OPENCS "build OpenMW Construction Set" ON) option(BUILD_WIZARD "build Installation Wizard" ON) option(BUILD_WITH_CODE_COVERAGE "Enable code coverage with gconv" OFF) option(BUILD_UNITTESTS "Enable Unittests with Google C++ Unittest and GMock frameworks" OFF) -option(BUILD_NIFTEST "build nif file tester" OFF) +option(BUILD_NIFTEST "build nif file tester" ON) option(BUILD_MYGUI_PLUGIN "build MyGUI plugin for OpenMW resources, to use with MyGUI tools" ON) # OS X deployment diff --git a/components/nif/tests/test.sh b/components/nif/tests/test.sh index 95ecdbfba..424e27b07 100755 --- a/components/nif/tests/test.sh +++ b/components/nif/tests/test.sh @@ -9,7 +9,7 @@ find "$DATAFILESDIR" -iname *nif >> nifs.txt sed -e 's/.*/\"&\"/' nifs.txt > quoted_nifs.txt -xargs --arg-file=quoted_nifs.txt ../../../niftest +nice -n 10 xargs --arg-file=quoted_nifs.txt ../../../niftest rm nifs.txt rm quoted_nifs.txt From 03b39435f8d6e4ce7d70492f8f784d8286028968 Mon Sep 17 00:00:00 2001 From: Scott Howard Date: Thu, 1 Jan 2015 22:50:35 -0500 Subject: [PATCH 0184/3725] place user settings window at same location as mouse pointer --- apps/opencs/editor.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index f609b80b7..826619b5d 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -236,6 +236,7 @@ void CS::Editor::showSettings() if (mSettings.isHidden()) mSettings.show(); + mSettings.move (QCursor::pos()); mSettings.raise(); mSettings.activateWindow(); } From dece4e2640f2180ae61a8280acf79ab2f8179866 Mon Sep 17 00:00:00 2001 From: Scott Howard Date: Thu, 1 Jan 2015 22:54:32 -0500 Subject: [PATCH 0185/3725] remove unneeded includes --- apps/opencs/view/doc/loader.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/opencs/view/doc/loader.cpp b/apps/opencs/view/doc/loader.cpp index 3f3163f26..b062a42b8 100644 --- a/apps/opencs/view/doc/loader.cpp +++ b/apps/opencs/view/doc/loader.cpp @@ -9,7 +9,6 @@ #include #include #include -#include #include "../../model/doc/document.hpp" From 9909c4abadbe4c0aedc24a50155908c5e7e39b13 Mon Sep 17 00:00:00 2001 From: Arthur Moore Date: Fri, 2 Jan 2015 01:16:47 -0500 Subject: [PATCH 0186/3725] Made incorrect nif get error message more informative. --- components/nif/nifstream.hpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/components/nif/nifstream.hpp b/components/nif/nifstream.hpp index b9caa1536..0f9ec9085 100644 --- a/components/nif/nifstream.hpp +++ b/components/nif/nifstream.hpp @@ -5,6 +5,8 @@ #include #include +#include +#include #include #include @@ -86,7 +88,7 @@ public: //Templated functions to handle reads template - T get(){throw std::runtime_error("Can not get this type of data from a NIF File!");} + T get(){throw std::runtime_error("Can not read a <"+std::string(typeid(T).name())+"> from a NIF File! The get() function was called with the wrong template!");} ///Return a vector of whatever object is needed template From ad609bff7822abffc76de9ae01b50cb9df97b093 Mon Sep 17 00:00:00 2001 From: Arthur Moore Date: Fri, 2 Jan 2015 01:19:34 -0500 Subject: [PATCH 0187/3725] components/nif/base.hpp now uses the templated get() function --- components/nif/base.hpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/components/nif/base.hpp b/components/nif/base.hpp index 30c652b64..031000bcc 100644 --- a/components/nif/base.hpp +++ b/components/nif/base.hpp @@ -36,12 +36,12 @@ public: { next.read(nif); - flags = nif->getUShort(); + flags = nif->get(); - frequency = nif->getFloat(); - phase = nif->getFloat(); - timeStart = nif->getFloat(); - timeStop = nif->getFloat(); + frequency = nif->get(); + phase = nif->get(); + timeStart = nif->get(); + timeStop = nif->get(); target.read(nif); } @@ -81,7 +81,7 @@ public: void read(NIFStream *nif) { - name = nif->getString(); + name = nif->get(); Controlled::read(nif); } }; From a8621e62308abafae018e30c76f3f2feddd5edcb Mon Sep 17 00:00:00 2001 From: mrcheko Date: Fri, 2 Jan 2015 16:49:22 +0300 Subject: [PATCH 0188/3725] defaults are set to 1.0; remove contrast setting (can be changed in config though); disable gamma control for not Windows OSs --- apps/openmw/mwgui/settingswindow.cpp | 14 +++++++++++++ apps/openmw/mwrender/renderingmanager.cpp | 2 +- files/mygui/openmw_settings_window.layout | 25 ++++++----------------- files/settings-default.cfg | 4 ++-- 4 files changed, 23 insertions(+), 22 deletions(-) diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index ce2a20d8b..05664386b 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -182,6 +182,20 @@ namespace MWGui getWidget(mRefractionButton, "RefractionButton"); getWidget(mDifficultySlider, "DifficultySlider"); +#ifndef WIN32 + // hide gamma controls since it currently does not work under Linux + MyGUI::ScrollBar *gammaSlider; + getWidget(gammaSlider, "GammaSlider"); + gammaSlider->setVisible(false); + MyGUI::TextBox *textBox; + getWidget(textBox, "GammaText"); + textBox->setVisible(false); + getWidget(textBox, "GammaTextDark"); + textBox->setVisible(false); + getWidget(textBox, "GammaTextLight"); + textBox->setVisible(false); +#endif + mMainWidget->castType()->eventWindowChangeCoord += MyGUI::newDelegate(this, &SettingsWindow::onWindowResize); mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onOkButtonClicked); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 44edcf03b..3aff46d43 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -757,7 +757,7 @@ void RenderingManager::processChangedSettings(const Settings::CategorySettingVec changeRes = true; else if (it->second == "field of view" && it->first == "General") mRendering.setFov(Settings::Manager::getFloat("field of view", "General")); - else if ((it->second == "gamma" || it->second == "contrast") && it->first == "General") + else if (it->second == "gamma" && it->first == "General") { mRendering.setWindowGammaContrast(Settings::Manager::getFloat("gamma", "General"), Settings::Manager::getFloat("contrast", "General")); } diff --git a/files/mygui/openmw_settings_window.layout b/files/mygui/openmw_settings_window.layout index 8fd3d8af1..4a993e140 100644 --- a/files/mygui/openmw_settings_window.layout +++ b/files/mygui/openmw_settings_window.layout @@ -1,8 +1,8 @@  - + - + @@ -214,7 +214,7 @@ - + @@ -305,27 +305,14 @@ - + - + - - - - - - - - - - - - - @@ -504,7 +491,7 @@ - + diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 6bd10dc21..0a55a286b 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -48,8 +48,8 @@ werewolf overlay = true [General] # Camera field of view field of view = 55 -gamma = 1.34 -contrast = 0.98 +gamma = 1.00 +contrast = 1.00 # Texture filtering mode. valid values: # none From 773669952b5baaba0cd8b1faae059a9f5a0b5314 Mon Sep 17 00:00:00 2001 From: Thoronador Date: Fri, 2 Jan 2015 16:30:14 +0100 Subject: [PATCH 0189/3725] remove initializing constructors from "dumb structs" As suggested by Marc Zinnschlag: https://github.com/OpenMW/openmw/pull/423#issuecomment-68526701 --- components/esm/loadcell.hpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/components/esm/loadcell.hpp b/components/esm/loadcell.hpp index 33e4ce61e..e1a6eee1a 100644 --- a/components/esm/loadcell.hpp +++ b/components/esm/loadcell.hpp @@ -70,23 +70,17 @@ struct Cell { int mFlags; int mX, mY; - - DATAstruct() : mFlags(0), mX(0), mY(0) {} }; struct AMBIstruct { Color mAmbient, mSunlight, mFog; float mFogDensity; - - AMBIstruct() : mAmbient(0), mSunlight(0), mFog(0), mFogDensity(0) {} }; Cell() : mWater(0), mName(""), mRegion(""), - mData(DATAstruct()), - mAmbi(AMBIstruct()), mWaterInt(false), mMapColor(0), mRefNumCounter(0) From f24c1845b6f754f8817ae6bc6a2564ff99ae9f29 Mon Sep 17 00:00:00 2001 From: Scott Howard Date: Fri, 2 Jan 2015 10:42:09 -0500 Subject: [PATCH 0190/3725] remove pop-up message on load failure --- apps/opencs/view/doc/loader.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/apps/opencs/view/doc/loader.cpp b/apps/opencs/view/doc/loader.cpp index b062a42b8..f2b897a3e 100644 --- a/apps/opencs/view/doc/loader.cpp +++ b/apps/opencs/view/doc/loader.cpp @@ -8,7 +8,6 @@ #include #include #include -#include #include "../../model/doc/document.hpp" @@ -107,8 +106,6 @@ void CSVDoc::LoadingDocument::abort (const std::string& error) mAborted = true; mError->setText (QString::fromUtf8 (("Loading failed: " + error + "").c_str())); mButtons->setStandardButtons (QDialogButtonBox::Close); - QMessageBox::critical(this, tr("OpenCS Loading Failed"), - QString::fromUtf8 (("Loading failed:\n" + error).c_str())); } void CSVDoc::LoadingDocument::addMessage (const std::string& message) From bbbf431ae377fcbd442592ad29c7b79548ac8346 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 3 Jan 2015 13:54:46 +0100 Subject: [PATCH 0191/3725] double bug in script name handling workaround (Fixes #1730) --- components/compiler/fileparser.cpp | 1 + components/compiler/quickfileparser.cpp | 6 ++++++ components/compiler/scanner.cpp | 8 +------- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/components/compiler/fileparser.cpp b/components/compiler/fileparser.cpp index 37ad1f258..423841ac3 100644 --- a/components/compiler/fileparser.cpp +++ b/components/compiler/fileparser.cpp @@ -112,6 +112,7 @@ namespace Compiler scanner.scan (mScriptParser); mState = EndNameState; + scanner.allowNameStartingwithDigit(); return true; } diff --git a/components/compiler/quickfileparser.cpp b/components/compiler/quickfileparser.cpp index f3d8063b2..895b7ce65 100644 --- a/components/compiler/quickfileparser.cpp +++ b/components/compiler/quickfileparser.cpp @@ -19,6 +19,12 @@ bool Compiler::QuickFileParser::parseName (const std::string& name, const TokenL bool Compiler::QuickFileParser::parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner) { + if (keyword==Scanner::K_begin) + { + scanner.allowNameStartingwithDigit(); + return true; + } + if (keyword==Scanner::K_end) return false; diff --git a/components/compiler/scanner.cpp b/components/compiler/scanner.cpp index 3fdbdb9f0..705e90eb3 100644 --- a/components/compiler/scanner.cpp +++ b/components/compiler/scanner.cpp @@ -314,12 +314,10 @@ namespace Compiler bool Scanner::scanName (char c, std::string& name) { - bool first = true; bool error = false; name.clear(); - - putback (c); + name += c; while (get (c)) { @@ -352,13 +350,9 @@ namespace Compiler putback (c); break; } - - if (first && (std::isdigit (c) || c=='`' || c=='-')) - error = true; } name += c; - first = false; } return !error; From ac7c2a1473d931adf9bc5d66c7a6cf424b1bfd3f Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 3 Jan 2015 13:59:59 +0100 Subject: [PATCH 0192/3725] some cleanup --- components/compiler/scanner.cpp | 11 ++++++----- components/compiler/scanner.hpp | 3 ++- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/components/compiler/scanner.cpp b/components/compiler/scanner.cpp index 705e90eb3..14ab99c21 100644 --- a/components/compiler/scanner.cpp +++ b/components/compiler/scanner.cpp @@ -270,8 +270,9 @@ namespace Compiler bool Scanner::scanName (char c, Parser& parser, bool& cont) { std::string name; + name += c; - if (!scanName (c, name)) + if (!scanName (name)) return false; TokenLoc loc (mLoc); @@ -312,13 +313,11 @@ namespace Compiler return true; } - bool Scanner::scanName (char c, std::string& name) + bool Scanner::scanName (std::string& name) { + char c; bool error = false; - name.clear(); - name += c; - while (get (c)) { if (!name.empty() && name[0]=='"') @@ -333,12 +332,14 @@ namespace Compiler // { // if (!get (c)) // { +// error = true; // mErrorHandler.error ("incomplete escape sequence", mLoc); // break; // } // } else if (c=='\n') { + error = true; mErrorHandler.error ("incomplete string or name", mLoc); break; } diff --git a/components/compiler/scanner.hpp b/components/compiler/scanner.hpp index 349a8afb6..ed01bbe44 100644 --- a/components/compiler/scanner.hpp +++ b/components/compiler/scanner.hpp @@ -89,7 +89,8 @@ namespace Compiler bool scanName (char c, Parser& parser, bool& cont); - bool scanName (char c, std::string& name); + /// \param name May contain the start of the name (one or more characters) + bool scanName (std::string& name); bool scanSpecial (char c, Parser& parser, bool& cont); From 4a734f5cd3750ba3c781290d6c8fc3c945f11eb4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 2 Jan 2015 00:17:51 +0100 Subject: [PATCH 0193/3725] Fall back to top-level directory when looking for resources (Fixes #2169) --- components/misc/resourcehelpers.cpp | 47 ++++++++++++++++++++++++----- 1 file changed, 40 insertions(+), 7 deletions(-) diff --git a/components/misc/resourcehelpers.cpp b/components/misc/resourcehelpers.cpp index 9eaf441ef..ee911c566 100644 --- a/components/misc/resourcehelpers.cpp +++ b/components/misc/resourcehelpers.cpp @@ -4,6 +4,29 @@ #include +namespace +{ + + + struct MatchPathSeparator + { + bool operator()( char ch ) const + { + return ch == '\\' || ch == '/'; + } + }; + + std::string + getBasename( std::string const& pathname ) + { + return std::string( + std::find_if( pathname.rbegin(), pathname.rend(), + MatchPathSeparator() ).base(), + pathname.end() ); + } + +} + bool Misc::ResourceHelpers::changeExtensionToDds(std::string &path) { Ogre::String::size_type pos = path.rfind('.'); @@ -40,14 +63,24 @@ std::string Misc::ResourceHelpers::correctResourcePath(const std::string &topLev // since we know all (GOTY edition or less) textures end // in .dds, we change the extension - if (changeExtensionToDds(correctedPath)) + bool changedToDds = changeExtensionToDds(correctedPath); + if (Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(correctedPath)) + return correctedPath; + // if it turns out that the above wasn't true in all cases (not for vanilla, but maybe mods) + // verify, and revert if false (this call succeeds quickly, but fails slowly) + if (changedToDds && Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(origExt)) + return origExt; + + // fall back to a resource in the top level directory if it exists + std::string fallback = topLevelDirectory + "\\" + getBasename(correctedPath); + if (Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(fallback)) + return fallback; + + if (changedToDds) { - // if it turns out that the above wasn't true in all cases (not for vanilla, but maybe mods) - // verify, and revert if false (this call succeeds quickly, but fails slowly) - if(!Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(correctedPath)) - { - return origExt; - } + fallback = topLevelDirectory + "\\" + getBasename(origExt); + if (Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(fallback)) + return fallback; } return correctedPath; From 593ca6bd48dc2904d6bab232a4c4028ae049ae65 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 2 Jan 2015 00:34:16 +0100 Subject: [PATCH 0194/3725] Fix for framerate-dependent maximum stepping distance (Bug #1638) --- apps/openmw/mwworld/physicssystem.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 1374dc37a..3a7aa0490 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -108,7 +108,7 @@ namespace MWWorld } static bool stepMove(btCollisionObject *colobj, Ogre::Vector3 &position, - const Ogre::Vector3 &velocity, float &remainingTime, + const Ogre::Vector3 &toMove, float &remainingTime, OEngine::Physic::PhysicEngine *engine) { /* @@ -124,7 +124,7 @@ namespace MWWorld * If not successful return 'false'. May fail for these reasons: * - can't move directly up from current position * - having moved up by between epsilon() and sStepSize, can't move forward - * - having moved forward by between epsilon() and velocity*remainingTime, + * - having moved forward by between epsilon() and toMove, * = moved down between 0 and just under sStepSize but slope was too steep, or * = moved the full sStepSize down (FIXME: this could be a bug) * @@ -133,7 +133,7 @@ namespace MWWorld * Starting position. Obstacle or stairs with height upto sStepSize in front. * * +--+ +--+ |XX - * | | -------> velocity | | +--+XX + * | | -------> toMove | | +--+XX * | | | | |XXXXX * | | +--+ | | +--+XXXXX * | | |XX| | | |XXXXXXXX @@ -171,11 +171,11 @@ namespace MWWorld * | | * <------------------->| | * +--+ +--+ - * |XX| the moved amount is velocity*remainingTime*tracer.mFraction + * |XX| the moved amount is toMove*tracer.mFraction * +--+ * ============================================== */ - tracer.doTrace(colobj, stepper.mEndPos, stepper.mEndPos + velocity*remainingTime, engine); + tracer.doTrace(colobj, stepper.mEndPos, stepper.mEndPos + toMove, engine); if(tracer.mFraction < std::numeric_limits::epsilon()) return false; // didn't even move the smallest representable amount @@ -428,9 +428,9 @@ namespace MWWorld Ogre::Vector3 oldPosition = newPosition; // We hit something. Try to step up onto it. (NOTE: stepMove does not allow stepping over) // NOTE: stepMove modifies newPosition if successful - bool result = stepMove(colobj, newPosition, velocity, remainingTime, engine); - if (!result) - result = stepMove(colobj, newPosition, velocity.normalisedCopy()*300.f, remainingTime, engine); + bool result = stepMove(colobj, newPosition, velocity*remainingTime, remainingTime, engine); + if (!result) // to make sure the maximum stepping distance isn't framerate-dependent or movement-speed dependent + result = stepMove(colobj, newPosition, velocity.normalisedCopy()*10.f, remainingTime, engine); if(result) { // don't let pure water creatures move out of water after stepMove From 6f747df7133284ea8146b70595e82951265704e5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 2 Jan 2015 02:10:40 +0100 Subject: [PATCH 0195/3725] Remove an unused constructor --- apps/openmw/mwrender/sky.cpp | 5 ----- apps/openmw/mwrender/sky.hpp | 1 - 2 files changed, 6 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 385e7d8c5..761d3fd96 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -104,11 +104,6 @@ BillboardObject::BillboardObject( const String& textureName, bodyCount++; } -BillboardObject::BillboardObject() -: mNode(NULL), mMaterial(NULL), mEntity(NULL), mVisibility(1.f) -{ -} - void BillboardObject::requestedConfiguration (sh::MaterialInstance* m, const std::string& configuration) { } diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index 0544f17ef..70251f490 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -39,7 +39,6 @@ namespace MWRender Ogre::SceneNode* rootNode, const std::string& material ); - BillboardObject(); void requestedConfiguration (sh::MaterialInstance* m, const std::string& configuration); void createdConfiguration (sh::MaterialInstance* m, const std::string& configuration); From d56906acf714c8decf35336ecf104647dd954e45 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 2 Jan 2015 02:27:05 +0100 Subject: [PATCH 0196/3725] Fix the creature position glitch --- apps/openmw/mwmechanics/character.cpp | 2 ++ apps/openmw/mwrender/animation.cpp | 7 ++++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 3136ae676..21683d3cc 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -441,6 +441,8 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat } // idle handled last as it can depend on the other states + // FIXME: if one of the below states is close to their last animation frame (i.e. will be disabled in the coming update), + // the idle animation should be displayed if ((mUpperBodyState != UpperCharState_Nothing || mMovementState != CharState_None || mHitState != CharState_None) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index a922fa170..1ef7a3533 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -988,7 +988,11 @@ void Animation::resetActiveGroups() AnimStateMap::const_iterator state = mStates.find(mAnimationTimePtr[0]->getAnimName()); if(state == mStates.end()) + { + if (mAccumRoot && mNonAccumRoot) + mAccumRoot->setPosition(-mNonAccumRoot->getPosition()*mAccumulate); return; + } const Ogre::SharedPtr &animsrc = state->second.mSource; const std::vector >&ctrls = animsrc->mControllers[0]; @@ -1142,9 +1146,6 @@ Ogre::Vector3 Animation::runAnimation(float duration) if(!state.mPlaying && state.mAutoDisable) { - if(mNonAccumCtrl && stateiter->first == mAnimationTimePtr[0]->getAnimName()) - mAccumRoot->setPosition(0.f,0.f,0.f); - mStates.erase(stateiter++); resetActiveGroups(); From 398fe6e780314bd94bee591a9d59b608b48aee56 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 4 Jan 2015 01:33:36 +0100 Subject: [PATCH 0197/3725] Thrown weapon fix (Fixes #2248) --- apps/openmw/mwrender/weaponanimation.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/weaponanimation.cpp b/apps/openmw/mwrender/weaponanimation.cpp index 8a9feef03..8af4d637a 100644 --- a/apps/openmw/mwrender/weaponanimation.cpp +++ b/apps/openmw/mwrender/weaponanimation.cpp @@ -68,9 +68,6 @@ void WeaponAnimation::attachArrow(MWWorld::Ptr actor) void WeaponAnimation::releaseArrow(MWWorld::Ptr actor) { - if (!mAmmunition.get()) - return; - MWWorld::InventoryStore& inv = actor.getClass().getInventoryStore(actor); MWWorld::ContainerStoreIterator weapon = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); if (weapon == inv.end()) @@ -131,6 +128,9 @@ void WeaponAnimation::releaseArrow(MWWorld::Ptr actor) if (ammo == inv.end()) return; + if (!mAmmunition.get()) + return; + Ogre::Vector3 launchPos(0,0,0); if (mAmmunition->mSkelBase) { From bc686c93b50485bc6e3bb4e94d83c7b46def6dca Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 4 Jan 2015 01:36:57 +0100 Subject: [PATCH 0198/3725] Potential fix for thrown weapons being regarded as broken --- apps/openmw/mwclass/weapon.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index f1f0386c6..8456c72e6 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -386,7 +386,7 @@ namespace MWClass std::pair Weapon::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const { - if (ptr.getCellRef().getCharge() == 0) + if (hasItemHealth(ptr) && ptr.getCellRef().getCharge() == 0) return std::make_pair(0, "#{sInventoryMessage1}"); std::pair, bool> slots_ = ptr.getClass().getEquipmentSlots(ptr); From de12c96a460815da6acff2828ce745581e9f01ca Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 4 Jan 2015 19:23:31 +0100 Subject: [PATCH 0199/3725] Fix crash on exit if the window wasn't created (Fixes #2249) --- apps/openmw/engine.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 3473d0b29..24e1388d0 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -208,7 +208,8 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) OMW::Engine::~Engine() { - mOgre->restoreWindowGammaRamp(); + if (mOgre) + mOgre->restoreWindowGammaRamp(); mEnvironment.cleanup(); delete mScriptContext; delete mOgre; From 5e7e40aac90af0d55e51e7113203f3e96d517585 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 4 Jan 2015 19:50:46 +0100 Subject: [PATCH 0200/3725] Fix being able to switch weapons while knocked out --- apps/openmw/mwmechanics/character.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 21683d3cc..6632f0275 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -900,7 +900,8 @@ bool CharacterController::updateWeaponState() } bool forcestateupdate = false; - if(weaptype != mWeaponType && mHitState != CharState_KnockDown) + if(weaptype != mWeaponType && mHitState != CharState_KnockDown && mHitState != CharState_KnockOut + && mHitState != CharState_Hit) { forcestateupdate = true; From 3b534326ff0c01de98deb9a3220e74c2049073ad Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 5 Jan 2015 15:04:11 +0100 Subject: [PATCH 0201/3725] forbid manual editing of the cell field in reference records --- apps/opencs/model/world/columnimp.hpp | 10 ++++++++-- apps/opencs/model/world/data.cpp | 2 +- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index eba73cf0b..95023f49d 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -870,7 +870,13 @@ namespace CSMWorld template struct CellColumn : public Column { - CellColumn() : Column (Columns::ColumnId_Cell, ColumnBase::Display_Cell) {} + bool mBlocked; + + /// \param blocked Do not allow user-modification + CellColumn (bool blocked = false) + : Column (Columns::ColumnId_Cell, ColumnBase::Display_Cell), + mBlocked (blocked) + {} virtual QVariant get (const Record& record) const { @@ -893,7 +899,7 @@ namespace CSMWorld virtual bool isUserEditable() const { - return true; + return !mBlocked; } }; diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 67f6822c7..b925a66b3 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -257,7 +257,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mRefs.addColumn (new StringIdColumn (true)); mRefs.addColumn (new RecordStateColumn); mRefs.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Reference)); - mRefs.addColumn (new CellColumn); + mRefs.addColumn (new CellColumn (true)); mRefs.addColumn (new IdColumn); mRefs.addColumn (new PosColumn (&CellRef::mPos, 0, false)); mRefs.addColumn (new PosColumn (&CellRef::mPos, 1, false)); From ba7b74217b9b821f2d354f5ee131b90bc333fd50 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 5 Jan 2015 15:20:47 +0100 Subject: [PATCH 0202/3725] added original cell column to reference table --- apps/opencs/model/world/columnimp.hpp | 32 +++++++++++++++++++++++ apps/opencs/model/world/columns.cpp | 1 + apps/opencs/model/world/columns.hpp | 1 + apps/opencs/model/world/data.cpp | 1 + apps/opencs/model/world/ref.hpp | 1 + apps/opencs/model/world/refcollection.cpp | 1 + 6 files changed, 37 insertions(+) diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index 95023f49d..ed2cfc310 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -903,6 +903,38 @@ namespace CSMWorld } }; + template + struct OriginalCellColumn : public Column + { + OriginalCellColumn() + : Column (Columns::ColumnId_OriginalCell, ColumnBase::Display_Cell) + {} + + virtual QVariant get (const Record& record) const + { + return QString::fromUtf8 (record.get().mOriginalCell.c_str()); + } + + virtual void set (Record& record, const QVariant& data) + { + ESXRecordT record2 = record.get(); + + record2.mOriginalCell = data.toString().toUtf8().constData(); + + record.setModified (record2); + } + + virtual bool isEditable() const + { + return true; + } + + virtual bool isUserEditable() const + { + return false; + } + }; + template struct IdColumn : public Column { diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 8349eb515..d85125bd5 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -201,6 +201,7 @@ namespace CSMWorld { ColumnId_HitSound, "Hit Sound" }, { ColumnId_AreaSound, "Area Sound" }, { ColumnId_BoltSound, "Bolt Sound" }, + { ColumnId_OriginalCell, "Original Cell" }, { ColumnId_UseValue1, "Use value 1" }, { ColumnId_UseValue2, "Use value 2" }, diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index ca0326655..d3476f7b2 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -194,6 +194,7 @@ namespace CSMWorld ColumnId_HitSound = 178, ColumnId_AreaSound = 179, ColumnId_BoltSound = 180, + ColumnId_OriginalCell = 181, // Allocated to a separate value range, so we don't get a collision should we ever need // to extend the number of use values. ColumnId_UseValue1 = 0x10000, diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index b925a66b3..e8905b925 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -258,6 +258,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mRefs.addColumn (new RecordStateColumn); mRefs.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Reference)); mRefs.addColumn (new CellColumn (true)); + mRefs.addColumn (new OriginalCellColumn); mRefs.addColumn (new IdColumn); mRefs.addColumn (new PosColumn (&CellRef::mPos, 0, false)); mRefs.addColumn (new PosColumn (&CellRef::mPos, 1, false)); diff --git a/apps/opencs/model/world/ref.hpp b/apps/opencs/model/world/ref.hpp index eb62434cf..411024691 100644 --- a/apps/opencs/model/world/ref.hpp +++ b/apps/opencs/model/world/ref.hpp @@ -12,6 +12,7 @@ namespace CSMWorld { std::string mId; std::string mCell; + std::string mOriginalCell; CellRef(); }; diff --git a/apps/opencs/model/world/refcollection.cpp b/apps/opencs/model/world/refcollection.cpp index 47f0276c6..1a0dd1e5b 100644 --- a/apps/opencs/model/world/refcollection.cpp +++ b/apps/opencs/model/world/refcollection.cpp @@ -23,6 +23,7 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool while (ESM::Cell::getNextRef (reader, ref, deleted)) { + ref.mOriginalCell = cell2.mId; ref.mCell = cell2.mId; /// \todo handle moved references From d919a0186e9f50999f9d10962333f8d60536433f Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 5 Jan 2015 18:54:52 +0100 Subject: [PATCH 0203/3725] Comment out unused opSkipOnZero --- components/compiler/generator.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/components/compiler/generator.cpp b/components/compiler/generator.cpp index 2efa2477e..ead0c7290 100644 --- a/components/compiler/generator.cpp +++ b/components/compiler/generator.cpp @@ -150,10 +150,13 @@ namespace code.push_back (Compiler::Generator::segment0 (2, offset)); } + /* + Currently unused void opSkipOnZero (Compiler::Generator::CodeContainer& code) { code.push_back (Compiler::Generator::segment5 (24)); } + */ void opSkipOnNonZero (Compiler::Generator::CodeContainer& code) { From c1955ef7fa983b9f9bf72e2cd0ee64af1f03320f Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 5 Jan 2015 05:33:51 +0100 Subject: [PATCH 0204/3725] Fix enchanting dialog effect labels showing a duration for constant effects --- apps/openmw/mwgui/enchantingdialog.cpp | 9 ++++---- apps/openmw/mwgui/spellcreationdialog.cpp | 25 +++++++++++++++++------ apps/openmw/mwgui/spellcreationdialog.hpp | 9 +++++++- 3 files changed, 32 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 224f8a4d8..4744fd1a1 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -120,19 +120,19 @@ namespace MWGui { case ESM::Enchantment::CastOnce: mTypeButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sItemCastOnce","Cast Once")); - mAddEffectDialog.constantEffect=false; + setConstantEffect(false); break; case ESM::Enchantment::WhenStrikes: mTypeButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sItemCastWhenStrikes", "When Strikes")); - mAddEffectDialog.constantEffect=false; + setConstantEffect(false); break; case ESM::Enchantment::WhenUsed: mTypeButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sItemCastWhenUsed", "When Used")); - mAddEffectDialog.constantEffect=false; + setConstantEffect(false); break; case ESM::Enchantment::ConstantEffect: mTypeButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sItemCastConstant", "Cast Constant")); - mAddEffectDialog.constantEffect=true; + setConstantEffect(true); break; } } @@ -283,6 +283,7 @@ namespace MWGui { mEnchanting.nextCastStyle(); updateLabels(); + updateEffectsView(); } void EnchantingDialog::onBuyButtonClicked(MyGUI::Widget* sender) diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index 6716f87da..0db2e30ce 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -42,6 +42,7 @@ namespace MWGui : WindowModal("openmw_edit_effect.layout") , mEditing(false) , mMagicEffect(NULL) + , mConstantEffect(false) { getWidget(mCancelButton, "CancelButton"); getWidget(mOkButton, "OkButton"); @@ -71,7 +72,11 @@ namespace MWGui mMagnitudeMaxSlider->eventScrollChangePosition += MyGUI::newDelegate(this, &EditEffectDialog::onMagnitudeMaxChanged); mDurationSlider->eventScrollChangePosition += MyGUI::newDelegate(this, &EditEffectDialog::onDurationChanged); mAreaSlider->eventScrollChangePosition += MyGUI::newDelegate(this, &EditEffectDialog::onAreaChanged); - constantEffect=false; + } + + void EditEffectDialog::setConstantEffect(bool constant) + { + mConstantEffect = constant; } void EditEffectDialog::open() @@ -92,8 +97,8 @@ namespace MWGui void EditEffectDialog::newEffect (const ESM::MagicEffect *effect) { bool allowSelf = effect->mData.mFlags & ESM::MagicEffect::CastSelf; - bool allowTouch = (effect->mData.mFlags & ESM::MagicEffect::CastTouch) && !constantEffect; - bool allowTarget = (effect->mData.mFlags & ESM::MagicEffect::CastTarget) && !constantEffect; + bool allowTouch = (effect->mData.mFlags & ESM::MagicEffect::CastTouch) && !mConstantEffect; + bool allowTarget = (effect->mData.mFlags & ESM::MagicEffect::CastTarget) && !mConstantEffect; if (!allowSelf && !allowTouch && !allowTarget) return; // TODO: Show an error message popup? @@ -183,7 +188,7 @@ namespace MWGui mMagnitudeBox->setVisible (true); curY += mMagnitudeBox->getSize().height; } - if (!(mMagicEffect->mData.mFlags & ESM::MagicEffect::NoDuration)&&constantEffect==false) + if (!(mMagicEffect->mData.mFlags & ESM::MagicEffect::NoDuration)&&mConstantEffect==false) { mDurationBox->setPosition(mDurationBox->getPosition().left, curY); mDurationBox->setVisible (true); @@ -204,8 +209,8 @@ namespace MWGui // cycle through range types until we find something that's allowed // does not handle the case where nothing is allowed (this should be prevented before opening the Add Effect dialog) bool allowSelf = mMagicEffect->mData.mFlags & ESM::MagicEffect::CastSelf; - bool allowTouch = (mMagicEffect->mData.mFlags & ESM::MagicEffect::CastTouch) && !constantEffect; - bool allowTarget = (mMagicEffect->mData.mFlags & ESM::MagicEffect::CastTarget) && !constantEffect; + bool allowTouch = (mMagicEffect->mData.mFlags & ESM::MagicEffect::CastTouch) && !mConstantEffect; + bool allowTarget = (mMagicEffect->mData.mFlags & ESM::MagicEffect::CastTarget) && !mConstantEffect; if (mEffect.mRange == ESM::RT_Self && !allowSelf) mEffect.mRange = (mEffect.mRange+1)%3; if (mEffect.mRange == ESM::RT_Touch && !allowTouch) @@ -468,6 +473,7 @@ namespace MWGui , mSelectedEffect(0) , mSelectedKnownEffectId(0) , mType(type) + , mConstantEffect(false) { mAddEffectDialog.eventEffectAdded += MyGUI::newDelegate(this, &EffectEditorBase::onEffectAdded); mAddEffectDialog.eventEffectModified += MyGUI::newDelegate(this, &EffectEditorBase::onEffectModified); @@ -659,6 +665,7 @@ namespace MWGui params.mMagnMax = it->mMagnMax; params.mRange = it->mRange; params.mArea = it->mArea; + params.mIsConstant = mConstantEffect; MyGUI::Button* button = mUsedEffectsView->createWidget("", MyGUI::IntCoord(0, size.height, 0, 24), MyGUI::Align::Default); button->setUserData(i); @@ -703,4 +710,10 @@ namespace MWGui mAddEffectDialog.editEffect (mEffects[id]); mAddEffectDialog.setVisible (true); } + + void EffectEditorBase::setConstantEffect(bool constant) + { + mAddEffectDialog.setConstantEffect(constant); + mConstantEffect = constant; + } } diff --git a/apps/openmw/mwgui/spellcreationdialog.hpp b/apps/openmw/mwgui/spellcreationdialog.hpp index a94289bfd..72e581c87 100644 --- a/apps/openmw/mwgui/spellcreationdialog.hpp +++ b/apps/openmw/mwgui/spellcreationdialog.hpp @@ -23,12 +23,13 @@ namespace MWGui virtual void open(); virtual void exit(); + void setConstantEffect(bool constant); + void setSkill(int skill); void setAttribute(int attribute); void newEffect (const ESM::MagicEffect* effect); void editEffect (ESM::ENAMstruct effect); - bool constantEffect; typedef MyGUI::delegates::CMultiDelegate1 EventHandle_Effect; EventHandle_Effect eventEffectAdded; @@ -82,6 +83,8 @@ namespace MWGui ESM::ENAMstruct mOldEffect; const ESM::MagicEffect* mMagicEffect; + + bool mConstantEffect; }; @@ -97,6 +100,8 @@ namespace MWGui EffectEditorBase(Type type); virtual ~EffectEditorBase(); + void setConstantEffect(bool constant); + protected: std::map mButtonMapping; // maps button ID to effect ID @@ -110,6 +115,8 @@ namespace MWGui int mSelectedEffect; short mSelectedKnownEffectId; + bool mConstantEffect; + std::vector mEffects; void onEffectAdded(ESM::ENAMstruct effect); From e6be979350102155e281a628027ea887131e74c0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 5 Jan 2015 06:29:33 +0100 Subject: [PATCH 0205/3725] Fix default position for spell window --- files/settings-default.cfg | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 39232c95c..6ec9b03e9 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -251,10 +251,10 @@ stats y = 0 stats w = 0.375 stats h = 0.4275 -spells x = 0.3775 -spells y = 0.4275 +spells x = 0.625 +spells y = 0.5725 spells w = 0.375 -spells h = 0.5725 +spells h = 0.4275 console x = 0 console y = 0 From c343a5c803b047fdbddbc42cdfe9a15b41b43977 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 5 Jan 2015 19:33:51 +0100 Subject: [PATCH 0206/3725] stopCombat fix --- apps/openmw/mwmechanics/aisequence.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwmechanics/aisequence.cpp b/apps/openmw/mwmechanics/aisequence.cpp index ea59708c2..13d09af7e 100644 --- a/apps/openmw/mwmechanics/aisequence.cpp +++ b/apps/openmw/mwmechanics/aisequence.cpp @@ -125,19 +125,23 @@ bool AiSequence::isInCombat(const MWWorld::Ptr &actor) const void AiSequence::stopCombat() { - while (getTypeId() == AiPackage::TypeIdCombat) + for(std::list::iterator it = mPackages.begin(); it != mPackages.end(); ) { - delete *mPackages.begin(); - mPackages.erase (mPackages.begin()); + if ((*it)->getTypeId() == AiPackage::TypeIdCombat) + it = mPackages.erase(it); + else + ++it; } } void AiSequence::stopPursuit() { - while (getTypeId() == AiPackage::TypeIdPursue) + for(std::list::iterator it = mPackages.begin(); it != mPackages.end(); ) { - delete *mPackages.begin(); - mPackages.erase (mPackages.begin()); + if ((*it)->getTypeId() == AiPackage::TypeIdPursue) + it = mPackages.erase(it); + else + ++it; } } From 708dbc2518c127ac692e18fcf80cc154b5ca8716 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 5 Jan 2015 19:59:47 +0100 Subject: [PATCH 0207/3725] Crime fix --- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 42728290b..3d757bde6 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1164,6 +1164,19 @@ namespace MWMechanics player.getClass().getNpcStats(player).expell(factionID); } } + + if (type == OT_Assault && !victim.isEmpty() + && !victim.getClass().getCreatureStats(victim).getAiSequence().isInCombat(player) + && victim.getClass().isNpc()) + { + // Attacker is in combat with us, but we are not in combat with the attacker yet. Time to fight back. + // Note: accidental or collateral damage attacks are ignored. + startCombat(victim, player); + + // Set the crime ID, which we will use to calm down participants + // once the bounty has been paid. + victim.getClass().getNpcStats(victim).setCrimeId(id); + } } } From afc961d19c0618c58ae9343a194003ae13b37987 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 5 Jan 2015 20:15:30 +0100 Subject: [PATCH 0208/3725] Workaround for random AABB assertion due to zero-sized particles (Fixes #1663) --- components/nifogre/ogrenifloader.cpp | 5 ++++- components/nifogre/particles.cpp | 8 ++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index b55248784..9c5f4a016 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -973,7 +973,10 @@ class NIFObjectLoader { const Nif::NiParticleSystemController *partctrl = static_cast(ctrl.getPtr()); - partsys->setDefaultDimensions(partctrl->size*2, partctrl->size*2); + float size = partctrl->size*2; + // HACK: don't allow zero-sized particles which can rarely cause an AABB assertion in Ogre to fail + size = std::max(size, 0.00001f); + partsys->setDefaultDimensions(size, size); if(!partctrl->emitter.empty()) { diff --git a/components/nifogre/particles.cpp b/components/nifogre/particles.cpp index 316e4edc2..4fec2d29e 100644 --- a/components/nifogre/particles.cpp +++ b/components/nifogre/particles.cpp @@ -452,6 +452,8 @@ public: { Ogre::Real scale = (life_time-particle_time) / mGrowTime; assert (scale >= 0); + // HACK: don't allow zero-sized particles which can rarely cause an AABB assertion in Ogre to fail + scale = std::max(scale, 0.00001f); width *= scale; height *= scale; } @@ -459,6 +461,8 @@ public: { Ogre::Real scale = particle_time / mFadeTime; assert (scale >= 0); + // HACK: don't allow zero-sized particles which can rarely cause an AABB assertion in Ogre to fail + scale = std::max(scale, 0.00001f); width *= scale; height *= scale; } @@ -485,6 +489,8 @@ public: { Ogre::Real scale = (life_time-particle_time) / mGrowTime; assert (scale >= 0); + // HACK: don't allow zero-sized particles which can rarely cause an AABB assertion in Ogre to fail + scale = std::max(scale, 0.00001f); width *= scale; height *= scale; } @@ -492,6 +498,8 @@ public: { Ogre::Real scale = particle_time / mFadeTime; assert (scale >= 0); + // HACK: don't allow zero-sized particles which can rarely cause an AABB assertion in Ogre to fail + scale = std::max(scale, 0.00001f); width *= scale; height *= scale; } From 464f8abb3f954a2798e8d312f938ccd6fef5ef26 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 6 Jan 2015 01:10:09 +0100 Subject: [PATCH 0209/3725] List exterior cell names in tab completion (Fixes #2252) --- apps/openmw/mwgui/console.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/apps/openmw/mwgui/console.cpp b/apps/openmw/mwgui/console.cpp index c922b625d..97f11f4f3 100644 --- a/apps/openmw/mwgui/console.cpp +++ b/apps/openmw/mwgui/console.cpp @@ -102,8 +102,20 @@ namespace MWGui it->second->listIdentifier (mNames); } + // exterior cell names aren't technically identifiers, but since the COC function accepts them, + // we should list them too + for (MWWorld::Store::iterator it = store.get().extBegin(); + it != store.get().extEnd(); ++it) + { + if (!it->mName.empty()) + mNames.push_back(it->mName); + } + // sort std::sort (mNames.begin(), mNames.end()); + + // remove duplicates + mNames.erase( std::unique( mNames.begin(), mNames.end() ), mNames.end() ); } } From e1fdcb608eaa0bff2e491a4f4b063b02bf4d41b7 Mon Sep 17 00:00:00 2001 From: Internecine Date: Tue, 6 Jan 2015 15:00:24 +1300 Subject: [PATCH 0210/3725] Fixed incorrect index --- apps/openmw/mwmechanics/spellcasting.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 71064d9b0..8e4e80d9c 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -584,7 +584,7 @@ namespace MWMechanics } else if (effectId == ESM::MagicEffect::RestoreHealth) { - applyDynamicStatsEffect(2, target, magnitude); + applyDynamicStatsEffect(0, target, magnitude); } else if (effectId == ESM::MagicEffect::DamageFatigue) { From f267497c0316f1163c4202451babf768274a6440 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 5 Jan 2015 18:52:37 +0100 Subject: [PATCH 0211/3725] Allow separate summoned creature instances for each spell ID (Fixes #2194) --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwgui/spellicons.cpp | 2 +- apps/openmw/mwgui/spellicons.hpp | 2 +- apps/openmw/mwmechanics/activespells.cpp | 18 +- apps/openmw/mwmechanics/activespells.hpp | 3 + apps/openmw/mwmechanics/actors.cpp | 159 +----------------- apps/openmw/mwmechanics/creaturestats.cpp | 2 +- apps/openmw/mwmechanics/creaturestats.hpp | 11 +- apps/openmw/mwmechanics/magiceffects.hpp | 2 +- apps/openmw/mwmechanics/spellcasting.cpp | 1 + apps/openmw/mwmechanics/spells.cpp | 2 +- apps/openmw/mwmechanics/summoning.cpp | 195 ++++++++++++++++++++++ apps/openmw/mwmechanics/summoning.hpp | 35 ++++ apps/openmw/mwworld/inventorystore.cpp | 49 +++++- apps/openmw/mwworld/inventorystore.hpp | 3 + components/esm/creaturestats.cpp | 8 +- components/esm/creaturestats.hpp | 2 +- 17 files changed, 329 insertions(+), 167 deletions(-) create mode 100644 apps/openmw/mwmechanics/summoning.cpp create mode 100644 apps/openmw/mwmechanics/summoning.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index c645e1a0a..97ab13012 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -76,7 +76,7 @@ add_openmw_dir (mwmechanics mechanicsmanagerimp stat character creaturestats magiceffects movement actors objects drawstate spells activespells npcstats aipackage aisequence aipursue alchemy aiwander aitravel aifollow aiavoiddoor aiescort aiactivate aicombat repair enchanting pathfinding pathgrid security spellsuccess spellcasting - disease pickpocket levelledlist combat steering obstacle autocalcspell difficultyscaling aicombataction actor + disease pickpocket levelledlist combat steering obstacle autocalcspell difficultyscaling aicombataction actor summoning ) add_openmw_dir (mwstate diff --git a/apps/openmw/mwgui/spellicons.cpp b/apps/openmw/mwgui/spellicons.cpp index 8ea9cfd7f..d23f1a235 100644 --- a/apps/openmw/mwgui/spellicons.cpp +++ b/apps/openmw/mwgui/spellicons.cpp @@ -25,7 +25,7 @@ namespace MWGui { void EffectSourceVisitor::visit (MWMechanics::EffectKey key, - const std::string& sourceName, int casterActorId, + const std::string& sourceName, const std::string& sourceId, int casterActorId, float magnitude, float remainingTime, float totalTime) { MagicEffectInfo newEffectSource; diff --git a/apps/openmw/mwgui/spellicons.hpp b/apps/openmw/mwgui/spellicons.hpp index e9d9967ea..5099fc4d6 100644 --- a/apps/openmw/mwgui/spellicons.hpp +++ b/apps/openmw/mwgui/spellicons.hpp @@ -47,7 +47,7 @@ namespace MWGui virtual ~EffectSourceVisitor() {} virtual void visit (MWMechanics::EffectKey key, - const std::string& sourceName, int casterActorId, + const std::string& sourceName, const std::string& sourceId, int casterActorId, float magnitude, float remainingTime = -1, float totalTime = -1); }; diff --git a/apps/openmw/mwmechanics/activespells.cpp b/apps/openmw/mwmechanics/activespells.cpp index 717a63be8..6e15449e1 100644 --- a/apps/openmw/mwmechanics/activespells.cpp +++ b/apps/openmw/mwmechanics/activespells.cpp @@ -195,7 +195,7 @@ namespace MWMechanics float magnitude = effectIt->mMagnitude; if (magnitude) - visitor.visit(MWMechanics::EffectKey(effectIt->mEffectId, effectIt->mArg), name, it->second.mCasterActorId, magnitude, remainingTime, effectIt->mDuration); + visitor.visit(MWMechanics::EffectKey(effectIt->mEffectId, effectIt->mArg), name, it->first, it->second.mCasterActorId, magnitude, remainingTime, effectIt->mDuration); } } } @@ -229,6 +229,22 @@ namespace MWMechanics mSpellsChanged = true; } + void ActiveSpells::purgeEffect(short effectId, const std::string& sourceId) + { + for (TContainer::iterator it = mSpells.begin(); it != mSpells.end(); ++it) + { + for (std::vector::iterator effectIt = it->second.mEffects.begin(); + effectIt != it->second.mEffects.end();) + { + if (effectIt->mEffectId == effectId && it->first == sourceId) + effectIt = it->second.mEffects.erase(effectIt); + else + ++effectIt; + } + } + mSpellsChanged = true; + } + void ActiveSpells::purge(int casterActorId) { for (TContainer::iterator it = mSpells.begin(); it != mSpells.end(); ++it) diff --git a/apps/openmw/mwmechanics/activespells.hpp b/apps/openmw/mwmechanics/activespells.hpp index 9c1a5e613..4f9d15d8c 100644 --- a/apps/openmw/mwmechanics/activespells.hpp +++ b/apps/openmw/mwmechanics/activespells.hpp @@ -82,6 +82,9 @@ namespace MWMechanics /// Remove all active effects with this effect id void purgeEffect (short effectId); + /// Remove all active effects with this effect id and source id + void purgeEffect (short effectId, const std::string& sourceId); + /// Remove all active effects, if roll succeeds (for each effect) void purgeAll (float chance); diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 1055e0f4a..c0fc80692 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -36,6 +36,7 @@ #include "aipursue.hpp" #include "actor.hpp" +#include "summoning.hpp" namespace { @@ -105,7 +106,7 @@ public: , mCommanded(false){} virtual void visit (MWMechanics::EffectKey key, - const std::string& sourceName, int casterActorId, + const std::string& sourceName, const std::string& sourceId, int casterActorId, float magnitude, float remainingTime = -1, float totalTime = -1) { MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); @@ -165,30 +166,6 @@ void getRestorationPerHourOfSleep (const MWWorld::Ptr& ptr, float& health, float } } -void cleanupSummonedCreature (MWMechanics::CreatureStats& casterStats, int creatureActorId) -{ - MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->searchPtrViaActorId(creatureActorId); - if (!ptr.isEmpty()) - { - // TODO: Show death animation before deleting? We shouldn't allow looting the corpse while the animation - // plays though, which is a rather lame exploit in vanilla. - MWBase::Environment::get().getWorld()->deleteObject(ptr); - - const ESM::Static* fx = MWBase::Environment::get().getWorld()->getStore().get() - .search("VFX_Summon_End"); - if (fx) - MWBase::Environment::get().getWorld()->spawnEffect("meshes\\" + fx->mModel, - "", Ogre::Vector3(ptr.getRefData().getPosition().pos)); - } - else - { - // We didn't find the creature. It's probably in an inactive cell. - // Add to graveyard so we can delete it when the cell becomes active. - std::vector& graveyard = casterStats.getSummonedCreatureGraveyard(); - graveyard.push_back(creatureActorId); - } -} - } namespace MWMechanics @@ -203,7 +180,7 @@ namespace MWMechanics : mCreature(trappedCreature) {} virtual void visit (MWMechanics::EffectKey key, - const std::string& sourceName, int casterActorId, + const std::string& sourceName, const std::string& sourceId, int casterActorId, float magnitude, float remainingTime = -1, float totalTime = -1) { if (key.mId != ESM::MagicEffect::Soultrap) @@ -782,131 +759,11 @@ namespace MWMechanics } } - // Update summon effects - static std::map summonMap; - if (summonMap.empty()) - { - summonMap[ESM::MagicEffect::SummonAncestralGhost] = "sMagicAncestralGhostID"; - summonMap[ESM::MagicEffect::SummonBonelord] = "sMagicBonelordID"; - summonMap[ESM::MagicEffect::SummonBonewalker] = "sMagicLeastBonewalkerID"; - summonMap[ESM::MagicEffect::SummonCenturionSphere] = "sMagicCenturionSphereID"; - summonMap[ESM::MagicEffect::SummonClannfear] = "sMagicClannfearID"; - summonMap[ESM::MagicEffect::SummonDaedroth] = "sMagicDaedrothID"; - summonMap[ESM::MagicEffect::SummonDremora] = "sMagicDremoraID"; - summonMap[ESM::MagicEffect::SummonFabricant] = "sMagicFabricantID"; - summonMap[ESM::MagicEffect::SummonFlameAtronach] = "sMagicFlameAtronachID"; - summonMap[ESM::MagicEffect::SummonFrostAtronach] = "sMagicFrostAtronachID"; - summonMap[ESM::MagicEffect::SummonGoldenSaint] = "sMagicGoldenSaintID"; - summonMap[ESM::MagicEffect::SummonGreaterBonewalker] = "sMagicGreaterBonewalkerID"; - summonMap[ESM::MagicEffect::SummonHunger] = "sMagicHungerID"; - summonMap[ESM::MagicEffect::SummonScamp] = "sMagicScampID"; - summonMap[ESM::MagicEffect::SummonSkeletalMinion] = "sMagicSkeletalMinionID"; - summonMap[ESM::MagicEffect::SummonStormAtronach] = "sMagicStormAtronachID"; - summonMap[ESM::MagicEffect::SummonWingedTwilight] = "sMagicWingedTwilightID"; - summonMap[ESM::MagicEffect::SummonWolf] = "sMagicCreature01ID"; - summonMap[ESM::MagicEffect::SummonBear] = "sMagicCreature02ID"; - summonMap[ESM::MagicEffect::SummonBonewolf] = "sMagicCreature03ID"; - summonMap[ESM::MagicEffect::SummonCreature04] = "sMagicCreature04ID"; - summonMap[ESM::MagicEffect::SummonCreature05] = "sMagicCreature05ID"; - } - - std::map& creatureMap = creatureStats.getSummonedCreatureMap(); - for (std::map::iterator it = summonMap.begin(); it != summonMap.end(); ++it) - { - bool found = creatureMap.find(it->first) != creatureMap.end(); - int magnitude = creatureStats.getMagicEffects().get(it->first).getMagnitude(); - if (found != (magnitude > 0)) - { - if (magnitude > 0) - { - ESM::Position ipos = ptr.getRefData().getPosition(); - Ogre::Vector3 pos(ipos.pos); - Ogre::Quaternion rot(Ogre::Radian(-ipos.rot[2]), Ogre::Vector3::UNIT_Z); - const float distance = 50; - pos = pos + distance*rot.yAxis(); - ipos.pos[0] = pos.x; - ipos.pos[1] = pos.y; - ipos.pos[2] = pos.z; - ipos.rot[0] = 0; - ipos.rot[1] = 0; - ipos.rot[2] = 0; - - std::string creatureID = - MWBase::Environment::get().getWorld()->getStore().get().find(it->second)->getString(); - - if (!creatureID.empty()) - { - MWWorld::CellStore* store = ptr.getCell(); - MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), creatureID, 1); - ref.getPtr().getCellRef().setPosition(ipos); - - MWMechanics::CreatureStats& summonedCreatureStats = ref.getPtr().getClass().getCreatureStats(ref.getPtr()); - - // Make the summoned creature follow its master and help in fights - AiFollow package(ptr.getCellRef().getRefId()); - summonedCreatureStats.getAiSequence().stack(package, ref.getPtr()); - int creatureActorId = summonedCreatureStats.getActorId(); - - MWWorld::Ptr placed = MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),store,ipos); - - MWRender::Animation* anim = MWBase::Environment::get().getWorld()->getAnimation(placed); - if (anim) - { - const ESM::Static* fx = MWBase::Environment::get().getWorld()->getStore().get() - .search("VFX_Summon_Start"); - if (fx) - anim->addEffect("meshes\\" + fx->mModel, -1, false); - } - - creatureMap.insert(std::make_pair(it->first, creatureActorId)); - } - } - else - { - // Effect has ended - std::map::iterator foundCreature = creatureMap.find(it->first); - cleanupSummonedCreature(creatureStats, foundCreature->second); - creatureMap.erase(foundCreature); - } - } - } - - for (std::map::iterator it = creatureMap.begin(); it != creatureMap.end(); ) - { - MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->searchPtrViaActorId(it->second); - if (!ptr.isEmpty() && ptr.getClass().getCreatureStats(ptr).isDead()) - { - // Purge the magic effect so a new creature can be summoned if desired - creatureStats.getActiveSpells().purgeEffect(it->first); - if (ptr.getClass().hasInventoryStore(ptr)) - ptr.getClass().getInventoryStore(ptr).purgeEffect(it->first); - - cleanupSummonedCreature(creatureStats, it->second); - creatureMap.erase(it++); - } - else - ++it; - } - - std::vector& graveyard = creatureStats.getSummonedCreatureGraveyard(); - for (std::vector::iterator it = graveyard.begin(); it != graveyard.end(); ) - { - MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->searchPtrViaActorId(*it); - if (!ptr.isEmpty()) - { - it = graveyard.erase(it); - - const ESM::Static* fx = MWBase::Environment::get().getWorld()->getStore().get() - .search("VFX_Summon_End"); - if (fx) - MWBase::Environment::get().getWorld()->spawnEffect("meshes\\" + fx->mModel, - "", Ogre::Vector3(ptr.getRefData().getPosition().pos)); - - MWBase::Environment::get().getWorld()->deleteObject(ptr); - } - else - ++it; - } + UpdateSummonedCreatures updateSummonedCreatures(ptr); + creatureStats.getActiveSpells().visitEffectSources(updateSummonedCreatures); + if (ptr.getClass().hasInventoryStore(ptr)) + ptr.getClass().getInventoryStore(ptr).visitEffectSources(updateSummonedCreatures); + updateSummonedCreatures.finish(); } void Actors::calculateNpcStatModifiers (const MWWorld::Ptr& ptr, float duration) diff --git a/apps/openmw/mwmechanics/creaturestats.cpp b/apps/openmw/mwmechanics/creaturestats.cpp index ac6f88d44..c61cc9697 100644 --- a/apps/openmw/mwmechanics/creaturestats.cpp +++ b/apps/openmw/mwmechanics/creaturestats.cpp @@ -638,7 +638,7 @@ namespace MWMechanics mDeathAnimation = index; } - std::map& CreatureStats::getSummonedCreatureMap() + std::map& CreatureStats::getSummonedCreatureMap() { return mSummonedCreatures; } diff --git a/apps/openmw/mwmechanics/creaturestats.hpp b/apps/openmw/mwmechanics/creaturestats.hpp index 9a08b58c9..145eb8a5b 100644 --- a/apps/openmw/mwmechanics/creaturestats.hpp +++ b/apps/openmw/mwmechanics/creaturestats.hpp @@ -67,8 +67,11 @@ namespace MWMechanics // The index of the death animation that was played unsigned char mDeathAnimation; - // - std::map mSummonedCreatures; + public: + typedef std::pair SummonKey; // + private: + std::map mSummonedCreatures; // + // Contains ActorIds of summoned creatures with an expired lifetime that have not been deleted yet. // This may be necessary when the creature is in an inactive cell. std::vector mSummonGraveyard; @@ -216,8 +219,8 @@ namespace MWMechanics void setBlock(bool value); bool getBlock() const; - std::map& getSummonedCreatureMap(); - std::vector& getSummonedCreatureGraveyard(); + std::map& getSummonedCreatureMap(); // + std::vector& getSummonedCreatureGraveyard(); // ActorIds enum Flag { diff --git a/apps/openmw/mwmechanics/magiceffects.hpp b/apps/openmw/mwmechanics/magiceffects.hpp index 88d8d988f..c384d0857 100644 --- a/apps/openmw/mwmechanics/magiceffects.hpp +++ b/apps/openmw/mwmechanics/magiceffects.hpp @@ -73,7 +73,7 @@ namespace MWMechanics struct EffectSourceVisitor { virtual void visit (MWMechanics::EffectKey key, - const std::string& sourceName, int casterActorId, + const std::string& sourceName, const std::string& sourceId, int casterActorId, float magnitude, float remainingTime = -1, float totalTime = -1) = 0; }; diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 58ccd389a..9cfcdda18 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -21,6 +21,7 @@ #include "magiceffects.hpp" #include "npcstats.hpp" +#include "summoning.hpp" namespace { diff --git a/apps/openmw/mwmechanics/spells.cpp b/apps/openmw/mwmechanics/spells.cpp index 5953be523..1f8ada06d 100644 --- a/apps/openmw/mwmechanics/spells.cpp +++ b/apps/openmw/mwmechanics/spells.cpp @@ -249,7 +249,7 @@ namespace MWMechanics random = it->second.at(i); float magnitude = effectIt->mMagnMin + (effectIt->mMagnMax - effectIt->mMagnMin) * random; - visitor.visit(MWMechanics::EffectKey(*effectIt), spell->mName, -1, magnitude); + visitor.visit(MWMechanics::EffectKey(*effectIt), spell->mName, spell->mId, -1, magnitude); } } } diff --git a/apps/openmw/mwmechanics/summoning.cpp b/apps/openmw/mwmechanics/summoning.cpp new file mode 100644 index 000000000..356cb422f --- /dev/null +++ b/apps/openmw/mwmechanics/summoning.cpp @@ -0,0 +1,195 @@ +#include "summoning.hpp" + +#include + +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" + +#include "../mwworld/esmstore.hpp" +#include "../mwworld/class.hpp" +#include "../mwworld/manualref.hpp" +#include "../mwworld/inventorystore.hpp" + +#include "../mwrender/animation.hpp" + +#include "creaturestats.hpp" +#include "aifollow.hpp" + + +namespace MWMechanics +{ + + void cleanupSummonedCreature (MWMechanics::CreatureStats& casterStats, int creatureActorId) + { + MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->searchPtrViaActorId(creatureActorId); + if (!ptr.isEmpty()) + { + // TODO: Show death animation before deleting? We shouldn't allow looting the corpse while the animation + // plays though, which is a rather lame exploit in vanilla. + MWBase::Environment::get().getWorld()->deleteObject(ptr); + + const ESM::Static* fx = MWBase::Environment::get().getWorld()->getStore().get() + .search("VFX_Summon_End"); + if (fx) + MWBase::Environment::get().getWorld()->spawnEffect("meshes\\" + fx->mModel, + "", Ogre::Vector3(ptr.getRefData().getPosition().pos)); + } + else + { + // We didn't find the creature. It's probably in an inactive cell. + // Add to graveyard so we can delete it when the cell becomes active. + std::vector& graveyard = casterStats.getSummonedCreatureGraveyard(); + graveyard.push_back(creatureActorId); + } + } + + UpdateSummonedCreatures::UpdateSummonedCreatures(const MWWorld::Ptr &actor) + : mActor(actor) + { + + } + + void UpdateSummonedCreatures::visit(EffectKey key, const std::string &sourceName, const std::string &sourceId, int casterActorId, float magnitude, float remainingTime, float totalTime) + { + if (key.mId >= ESM::MagicEffect::SummonScamp + && key.mId <= ESM::MagicEffect::SummonStormAtronach && magnitude > 0) + { + mActiveEffects.insert(std::make_pair(key.mId, sourceId)); + } + } + + void UpdateSummonedCreatures::finish() + { + static std::map summonMap; + if (summonMap.empty()) + { + summonMap[ESM::MagicEffect::SummonAncestralGhost] = "sMagicAncestralGhostID"; + summonMap[ESM::MagicEffect::SummonBonelord] = "sMagicBonelordID"; + summonMap[ESM::MagicEffect::SummonBonewalker] = "sMagicLeastBonewalkerID"; + summonMap[ESM::MagicEffect::SummonCenturionSphere] = "sMagicCenturionSphereID"; + summonMap[ESM::MagicEffect::SummonClannfear] = "sMagicClannfearID"; + summonMap[ESM::MagicEffect::SummonDaedroth] = "sMagicDaedrothID"; + summonMap[ESM::MagicEffect::SummonDremora] = "sMagicDremoraID"; + summonMap[ESM::MagicEffect::SummonFabricant] = "sMagicFabricantID"; + summonMap[ESM::MagicEffect::SummonFlameAtronach] = "sMagicFlameAtronachID"; + summonMap[ESM::MagicEffect::SummonFrostAtronach] = "sMagicFrostAtronachID"; + summonMap[ESM::MagicEffect::SummonGoldenSaint] = "sMagicGoldenSaintID"; + summonMap[ESM::MagicEffect::SummonGreaterBonewalker] = "sMagicGreaterBonewalkerID"; + summonMap[ESM::MagicEffect::SummonHunger] = "sMagicHungerID"; + summonMap[ESM::MagicEffect::SummonScamp] = "sMagicScampID"; + summonMap[ESM::MagicEffect::SummonSkeletalMinion] = "sMagicSkeletalMinionID"; + summonMap[ESM::MagicEffect::SummonStormAtronach] = "sMagicStormAtronachID"; + summonMap[ESM::MagicEffect::SummonWingedTwilight] = "sMagicWingedTwilightID"; + summonMap[ESM::MagicEffect::SummonWolf] = "sMagicCreature01ID"; + summonMap[ESM::MagicEffect::SummonBear] = "sMagicCreature02ID"; + summonMap[ESM::MagicEffect::SummonBonewolf] = "sMagicCreature03ID"; + summonMap[ESM::MagicEffect::SummonCreature04] = "sMagicCreature04ID"; + summonMap[ESM::MagicEffect::SummonCreature05] = "sMagicCreature05ID"; + } + + MWMechanics::CreatureStats& creatureStats = mActor.getClass().getCreatureStats(mActor); + + // Update summon effects + std::map& creatureMap = creatureStats.getSummonedCreatureMap(); + for (std::map::iterator it = creatureMap.begin(); it != creatureMap.end(); ) + { + bool found = mActiveEffects.find(it->first) != mActiveEffects.end(); + if (!found) + { + // Effect has ended + cleanupSummonedCreature(creatureStats, it->second); + creatureMap.erase(it++); + continue; + } + ++it; + } + + for (std::set >::iterator it = mActiveEffects.begin(); it != mActiveEffects.end(); ++it) + { + bool found = creatureMap.find(std::make_pair(it->first, it->second)) != creatureMap.end(); + if (!found) + { + ESM::Position ipos = mActor.getRefData().getPosition(); + Ogre::Vector3 pos(ipos.pos); + Ogre::Quaternion rot(Ogre::Radian(-ipos.rot[2]), Ogre::Vector3::UNIT_Z); + const float distance = 50; + pos = pos + distance*rot.yAxis(); + ipos.pos[0] = pos.x; + ipos.pos[1] = pos.y; + ipos.pos[2] = pos.z; + ipos.rot[0] = 0; + ipos.rot[1] = 0; + ipos.rot[2] = 0; + + const std::string& creatureGmst = summonMap[it->first]; + std::string creatureID = + MWBase::Environment::get().getWorld()->getStore().get().find(creatureGmst)->getString(); + + if (!creatureID.empty()) + { + MWWorld::CellStore* store = mActor.getCell(); + MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), creatureID, 1); + ref.getPtr().getCellRef().setPosition(ipos); + + MWMechanics::CreatureStats& summonedCreatureStats = ref.getPtr().getClass().getCreatureStats(ref.getPtr()); + + // Make the summoned creature follow its master and help in fights + AiFollow package(mActor.getCellRef().getRefId()); + summonedCreatureStats.getAiSequence().stack(package, ref.getPtr()); + int creatureActorId = summonedCreatureStats.getActorId(); + + MWWorld::Ptr placed = MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),store,ipos); + + MWRender::Animation* anim = MWBase::Environment::get().getWorld()->getAnimation(placed); + if (anim) + { + const ESM::Static* fx = MWBase::Environment::get().getWorld()->getStore().get() + .search("VFX_Summon_Start"); + if (fx) + anim->addEffect("meshes\\" + fx->mModel, -1, false); + } + + creatureMap.insert(std::make_pair(*it, creatureActorId)); + } + } + } + + for (std::map::iterator it = creatureMap.begin(); it != creatureMap.end(); ) + { + MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->searchPtrViaActorId(it->second); + if (!ptr.isEmpty() && ptr.getClass().getCreatureStats(ptr).isDead()) + { + // Purge the magic effect so a new creature can be summoned if desired + creatureStats.getActiveSpells().purgeEffect(it->first.first, it->first.second); + if (mActor.getClass().hasInventoryStore(ptr)) + mActor.getClass().getInventoryStore(mActor).purgeEffect(it->first.first, it->first.second); + + cleanupSummonedCreature(creatureStats, it->second); + creatureMap.erase(it++); + } + else + ++it; + } + + std::vector& graveyard = creatureStats.getSummonedCreatureGraveyard(); + for (std::vector::iterator it = graveyard.begin(); it != graveyard.end(); ) + { + MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->searchPtrViaActorId(*it); + if (!ptr.isEmpty()) + { + it = graveyard.erase(it); + + const ESM::Static* fx = MWBase::Environment::get().getWorld()->getStore().get() + .search("VFX_Summon_End"); + if (fx) + MWBase::Environment::get().getWorld()->spawnEffect("meshes\\" + fx->mModel, + "", Ogre::Vector3(ptr.getRefData().getPosition().pos)); + + MWBase::Environment::get().getWorld()->deleteObject(ptr); + } + else + ++it; + } + } + +} diff --git a/apps/openmw/mwmechanics/summoning.hpp b/apps/openmw/mwmechanics/summoning.hpp new file mode 100644 index 000000000..b8fe37783 --- /dev/null +++ b/apps/openmw/mwmechanics/summoning.hpp @@ -0,0 +1,35 @@ +#ifndef OPENMW_MECHANICS_SUMMONING_H +#define OPENMW_MECHANICS_SUMMONING_H + +#include + +#include "magiceffects.hpp" +#include "../mwworld/ptr.hpp" + +namespace MWMechanics +{ + + class CreatureStats; + + struct UpdateSummonedCreatures : public EffectSourceVisitor + { + UpdateSummonedCreatures(const MWWorld::Ptr& actor); + + virtual void visit (MWMechanics::EffectKey key, + const std::string& sourceName, const std::string& sourceId, int casterActorId, + float magnitude, float remainingTime = -1, float totalTime = -1); + + /// To call after all effect sources have been visited + void finish(); + + private: + MWWorld::Ptr mActor; + + std::set > mActiveEffects; + }; + + void cleanupSummonedCreature (MWMechanics::CreatureStats& casterStats, int creatureActorId); + +} + +#endif diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 9c329ce72..445b42d8d 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -583,7 +583,8 @@ void MWWorld::InventoryStore::visitEffectSources(MWMechanics::EffectSourceVisito const EffectParams& params = mPermanentMagicEffectMagnitudes[(**iter).getCellRef().getRefId()][i]; float magnitude = effectIt->mMagnMin + (effectIt->mMagnMax - effectIt->mMagnMin) * params.mRandom; magnitude *= params.mMultiplier; - visitor.visit(MWMechanics::EffectKey(*effectIt), (**iter).getClass().getName(**iter), -1, magnitude); + if (magnitude > 0) + visitor.visit(MWMechanics::EffectKey(*effectIt), (**iter).getClass().getName(**iter), (**iter).getCellRef().getRefId(), -1, magnitude); ++i; } @@ -639,6 +640,52 @@ void MWWorld::InventoryStore::purgeEffect(short effectId) mMagicEffects.remove(MWMechanics::EffectKey(effectId)); } +void MWWorld::InventoryStore::purgeEffect(short effectId, const std::string &sourceId) +{ + TEffectMagnitudes::iterator effectMagnitudeIt = mPermanentMagicEffectMagnitudes.find(sourceId); + if (effectMagnitudeIt == mPermanentMagicEffectMagnitudes.end()) + return; + + for (TSlots::const_iterator iter (mSlots.begin()); iter!=mSlots.end(); ++iter) + { + if (*iter==end()) + continue; + + if ((*iter)->getClass().getId(**iter) != sourceId) + continue; + + std::string enchantmentId = (*iter)->getClass().getEnchantment (**iter); + + if (!enchantmentId.empty()) + { + const ESM::Enchantment& enchantment = + *MWBase::Environment::get().getWorld()->getStore().get().find (enchantmentId); + + if (enchantment.mData.mType != ESM::Enchantment::ConstantEffect) + continue; + + std::vector& params = effectMagnitudeIt->second; + + int i=0; + for (std::vector::const_iterator effectIt (enchantment.mEffects.mList.begin()); + effectIt!=enchantment.mEffects.mList.end(); ++effectIt, ++i) + { + if (effectIt->mEffectID != effectId) + continue; + + float magnitude = effectIt->mMagnMin + (effectIt->mMagnMax - effectIt->mMagnMin) * params[i].mRandom; + magnitude *= params[i].mMultiplier; + + if (magnitude) + mMagicEffects.add (*effectIt, -magnitude); + + params[i].mMultiplier = 0; + break; + } + } + } +} + void MWWorld::InventoryStore::clear() { mSlots.clear(); diff --git a/apps/openmw/mwworld/inventorystore.hpp b/apps/openmw/mwworld/inventorystore.hpp index 48742b557..9fd18c54b 100644 --- a/apps/openmw/mwworld/inventorystore.hpp +++ b/apps/openmw/mwworld/inventorystore.hpp @@ -203,6 +203,9 @@ namespace MWWorld void purgeEffect (short effectId); ///< Remove a magic effect + void purgeEffect (short effectId, const std::string& sourceId); + ///< Remove a magic effect + virtual void clear(); ///< Empty container. diff --git a/components/esm/creaturestats.cpp b/components/esm/creaturestats.cpp index cc76ef0df..1fdce703c 100644 --- a/components/esm/creaturestats.cpp +++ b/components/esm/creaturestats.cpp @@ -94,9 +94,10 @@ void ESM::CreatureStats::load (ESMReader &esm) { int magicEffect; esm.getHT(magicEffect); + std::string source = esm.getHNOString("SOUR"); int actorId; esm.getHNT (actorId, "ACID"); - mSummonedCreatureMap[magicEffect] = actorId; + mSummonedCreatureMap[std::make_pair(magicEffect, source)] = actorId; } while (esm.isNextSub("GRAV")) @@ -204,9 +205,10 @@ void ESM::CreatureStats::save (ESMWriter &esm) const mAiSequence.save(esm); mMagicEffects.save(esm); - for (std::map::const_iterator it = mSummonedCreatureMap.begin(); it != mSummonedCreatureMap.end(); ++it) + for (std::map, int>::const_iterator it = mSummonedCreatureMap.begin(); it != mSummonedCreatureMap.end(); ++it) { - esm.writeHNT ("SUMM", it->first); + esm.writeHNT ("SUMM", it->first.first); + esm.writeHNString ("SOUR", it->first.second); esm.writeHNT ("ACID", it->second); } diff --git a/components/esm/creaturestats.hpp b/components/esm/creaturestats.hpp index 7946d0e45..680577f93 100644 --- a/components/esm/creaturestats.hpp +++ b/components/esm/creaturestats.hpp @@ -32,7 +32,7 @@ namespace ESM bool mHasAiSettings; StatState mAiSettings[4]; - std::map mSummonedCreatureMap; + std::map, int> mSummonedCreatureMap; std::vector mSummonGraveyard; ESM::TimeStamp mTradeTime; From 992b87ea441de3be8c673f300532f902330c0dda Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 6 Jan 2015 16:08:23 +0100 Subject: [PATCH 0212/3725] Reset existing summons when the spell is re-casted (Fixes #2135) --- apps/openmw/mwmechanics/spellcasting.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 9cfcdda18..b7c7e00a1 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -471,6 +471,20 @@ namespace MWMechanics else applyInstantEffect(target, caster, EffectKey(*effectIt), magnitude); + // Re-casting a summon effect will remove the creature from previous castings of that effect. + if (effectIt->mEffectID >= ESM::MagicEffect::SummonScamp + && effectIt->mEffectID <= ESM::MagicEffect::SummonStormAtronach + && !target.isEmpty() && target.getClass().isActor()) + { + CreatureStats& targetStats = target.getClass().getCreatureStats(target); + std::map::iterator found = targetStats.getSummonedCreatureMap().find(std::make_pair(effectIt->mEffectID, mId)); + if (found != targetStats.getSummonedCreatureMap().end()) + { + cleanupSummonedCreature(targetStats, found->second); + targetStats.getSummonedCreatureMap().erase(found); + } + } + // HACK: Damage attribute/skill actually has a duration, even though the actual effect is instant and permanent. // This was probably just done to have the effect visible in the magic menu for a while // to notify the player they've been damaged? From c6c7d102d0171c1f0daedc8fa0435cb913bc7b13 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 6 Jan 2015 23:35:40 +0100 Subject: [PATCH 0213/3725] Revert "components/nif/base.hpp now uses the templated get() function" This reverts commit ad609bff7822abffc76de9ae01b50cb9df97b093. Revert "Made incorrect nif get error message more informative." This reverts commit 9909c4abadbe4c0aedc24a50155908c5e7e39b13. Revert "Build the nif file tester by default" This reverts commit c1315ed90c87a457f17e6076c149465da3fa6c3a. Revert "Converted most nifstream "get multiple" functions to the templated version" This reverts commit 2619d57bb6afc5c31bf1a90b8c033d66f29a9a58. Revert "Add a templated option for getting vectors to NIFStream" This reverts commit f318ee0b8c68a46d53a0fdd216ae8d6b371eedc2. Revert "Made NIFStream getters templated" This reverts commit 4edc4142f3b4f1cde4d99392045d5d25858e6bf7. --- CMakeLists.txt | 2 +- components/nif/base.hpp | 12 +++---- components/nif/data.hpp | 16 ++++----- components/nif/nifstream.cpp | 64 ++++++++++++++++++++---------------- components/nif/nifstream.hpp | 25 ++++---------- components/nif/tests/test.sh | 2 +- 6 files changed, 58 insertions(+), 63 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index fb89f4e91..d7c85818e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -82,7 +82,7 @@ option(BUILD_OPENCS "build OpenMW Construction Set" ON) option(BUILD_WIZARD "build Installation Wizard" ON) option(BUILD_WITH_CODE_COVERAGE "Enable code coverage with gconv" OFF) option(BUILD_UNITTESTS "Enable Unittests with Google C++ Unittest and GMock frameworks" OFF) -option(BUILD_NIFTEST "build nif file tester" ON) +option(BUILD_NIFTEST "build nif file tester" OFF) option(BUILD_MYGUI_PLUGIN "build MyGUI plugin for OpenMW resources, to use with MyGUI tools" ON) # OS X deployment diff --git a/components/nif/base.hpp b/components/nif/base.hpp index 031000bcc..30c652b64 100644 --- a/components/nif/base.hpp +++ b/components/nif/base.hpp @@ -36,12 +36,12 @@ public: { next.read(nif); - flags = nif->get(); + flags = nif->getUShort(); - frequency = nif->get(); - phase = nif->get(); - timeStart = nif->get(); - timeStop = nif->get(); + frequency = nif->getFloat(); + phase = nif->getFloat(); + timeStart = nif->getFloat(); + timeStop = nif->getFloat(); target.read(nif); } @@ -81,7 +81,7 @@ public: void read(NIFStream *nif) { - name = nif->get(); + name = nif->getString(); Controlled::read(nif); } }; diff --git a/components/nif/data.hpp b/components/nif/data.hpp index e6d3370be..d9de12fb5 100644 --- a/components/nif/data.hpp +++ b/components/nif/data.hpp @@ -44,16 +44,16 @@ public: int verts = nif->getUShort(); if(nif->getInt()) - vertices = nif->getItems(verts); + nif->getVector3s(vertices, verts); if(nif->getInt()) - normals = nif->getItems(verts); + nif->getVector3s(normals, verts); center = nif->getVector3(); radius = nif->getFloat(); if(nif->getInt()) - colors = nif->getItems(verts); + nif->getVector4s(colors, verts); // Only the first 6 bits are used as a count. I think the rest are // flags of some sort. @@ -64,7 +64,7 @@ public: { uvlist.resize(uvs); for(int i = 0;i < uvs;i++) - uvlist[i] = nif->getItems(verts); + nif->getVector2s(uvlist[i], verts); } } }; @@ -84,7 +84,7 @@ public: // We have three times as many vertices as triangles, so this // is always equal to tris*3. int cnt = nif->getInt(); - triangles = nif->getItems(cnt); + nif->getShorts(triangles, cnt); // Read the match list, which lists the vertices that are equal to // vertices. We don't actually need need this for anything, so @@ -123,7 +123,7 @@ public: if(nif->getInt()) { // Particle sizes - sizes = nif->getItems(vertices.size()); + nif->getFloats(sizes, vertices.size()); } } }; @@ -140,7 +140,7 @@ public: if(nif->getInt()) { // Rotation quaternions. - rotations = nif->getItems(vertices.size()); + nif->getQuaternions(rotations, vertices.size()); } } }; @@ -341,7 +341,7 @@ struct NiMorphData : public Record for(int i = 0;i < morphCount;i++) { mMorphs[i].mData.read(nif, true); - mMorphs[i].mVertices = nif->getItems(vertCount); + nif->getVector3s(mMorphs[i].mVertices, vertCount); } } }; diff --git a/components/nif/nifstream.cpp b/components/nif/nifstream.cpp index 9eeee6a12..e5699db7b 100644 --- a/components/nif/nifstream.cpp +++ b/components/nif/nifstream.cpp @@ -106,33 +106,41 @@ std::string NIFStream::getVersionString() return inp->getLine(); } -template <> -char NIFStream::get(){ return getChar(); } -template <> -short NIFStream::get(){ return getShort(); } -template <> -unsigned short NIFStream::get(){ return getUShort(); } -template <> -int NIFStream::get(){ return getInt(); } -template <> -unsigned int NIFStream::get(){ return getUInt(); } -template <> -float NIFStream::get(){ return getFloat(); } - -template <> -Ogre::Vector2 NIFStream::get(){ return getVector2(); } -template <> -Ogre::Vector3 NIFStream::get(){ return getVector3(); } -template <> -Ogre::Vector4 NIFStream::get(){ return getVector4(); } -template <> -Ogre::Matrix3 NIFStream::get(){ return getMatrix3(); } -template <> -Ogre::Quaternion NIFStream::get(){ return getQuaternion(); } -template <> -Transformation NIFStream::get(){ return getTrafo(); } - -template <> -std::string NIFStream::get(){ return getString(); } +void NIFStream::getShorts(std::vector &vec, size_t size) +{ + vec.resize(size); + for(size_t i = 0;i < vec.size();i++) + vec[i] = getShort(); +} +void NIFStream::getFloats(std::vector &vec, size_t size) +{ + vec.resize(size); + for(size_t i = 0;i < vec.size();i++) + vec[i] = getFloat(); +} +void NIFStream::getVector2s(std::vector &vec, size_t size) +{ + vec.resize(size); + for(size_t i = 0;i < vec.size();i++) + vec[i] = getVector2(); +} +void NIFStream::getVector3s(std::vector &vec, size_t size) +{ + vec.resize(size); + for(size_t i = 0;i < vec.size();i++) + vec[i] = getVector3(); +} +void NIFStream::getVector4s(std::vector &vec, size_t size) +{ + vec.resize(size); + for(size_t i = 0;i < vec.size();i++) + vec[i] = getVector4(); +} +void NIFStream::getQuaternions(std::vector &quat, size_t size) +{ + quat.resize(size); + for(size_t i = 0;i < quat.size();i++) + quat[i] = getQuaternion(); +} } diff --git a/components/nif/nifstream.hpp b/components/nif/nifstream.hpp index 0f9ec9085..cc14971fd 100644 --- a/components/nif/nifstream.hpp +++ b/components/nif/nifstream.hpp @@ -5,8 +5,6 @@ #include #include -#include -#include #include #include @@ -86,23 +84,12 @@ public: ///This is special since the version string doesn't start with a number, and ends with "\n" std::string getVersionString(); - //Templated functions to handle reads - template - T get(){throw std::runtime_error("Can not read a <"+std::string(typeid(T).name())+"> from a NIF File! The get() function was called with the wrong template!");} - - ///Return a vector of whatever object is needed - template - std::vector getItems(size_t number_of_items) - { - std::vector items; - items.reserve(number_of_items); - for(size_t i=0; i < number_of_items; ++i) - { - items.push_back(get()); - } - return items; - } - + void getShorts(std::vector &vec, size_t size); + void getFloats(std::vector &vec, size_t size); + void getVector2s(std::vector &vec, size_t size); + void getVector3s(std::vector &vec, size_t size); + void getVector4s(std::vector &vec, size_t size); + void getQuaternions(std::vector &quat, size_t size); }; } diff --git a/components/nif/tests/test.sh b/components/nif/tests/test.sh index 424e27b07..95ecdbfba 100755 --- a/components/nif/tests/test.sh +++ b/components/nif/tests/test.sh @@ -9,7 +9,7 @@ find "$DATAFILESDIR" -iname *nif >> nifs.txt sed -e 's/.*/\"&\"/' nifs.txt > quoted_nifs.txt -nice -n 10 xargs --arg-file=quoted_nifs.txt ../../../niftest +xargs --arg-file=quoted_nifs.txt ../../../niftest rm nifs.txt rm quoted_nifs.txt From e19ab77d00301108d06307142e201b4f6edbd813 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 6 Jan 2015 19:29:33 +0100 Subject: [PATCH 0214/3725] Store camera first person state in savegame (Fixes #2255) --- apps/openmw/mwstate/statemanagerimp.cpp | 3 +++ apps/openmw/mwworld/worldimp.cpp | 16 ++++++++++++++-- components/esm/defs.hpp | 1 + 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index f77a90d8e..30dba2aaa 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -355,6 +355,7 @@ void MWState::StateManager::loadGame (const Character *character, const Slot *sl case ESM::REC_ENAB: case ESM::REC_LEVC: case ESM::REC_LEVI: + case ESM::REC_CAM_: MWBase::Environment::get().getWorld()->readRecord (reader, n.val, contentFileMap); break; @@ -406,6 +407,8 @@ void MWState::StateManager::loadGame (const Character *character, const Slot *sl // Use detectWorldSpaceChange=false, otherwise some of the data we just loaded would be cleared again MWBase::Environment::get().getWorld()->changeToCell (cellId, ptr.getRefData().getPosition(), false); + // Vanilla MW will restart startup scripts when a save game is loaded. This is unintuive, + // but some mods may be using it as a reload detector. MWBase::Environment::get().getScriptManager()->getGlobalScripts().addStartup(); // Do not trigger erroneous cellChanged events diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 1c9b8b996..a939a6db9 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -201,6 +201,7 @@ namespace MWWorld setupPlayer(); renderPlayer(); + mRendering->resetCamera(); MWBase::Environment::get().getWindowManager()->updatePlayer(); @@ -304,7 +305,8 @@ namespace MWWorld +1 // player record +1 // weather record +1 // actorId counter - +1; // levitation/teleport enabled state + +1 // levitation/teleport enabled state + +1; // camera } void World::write (ESM::ESMWriter& writer, Loading::Listener& progress) const @@ -333,6 +335,11 @@ namespace MWWorld writer.writeHNT("LEVT", mLevitationEnabled); writer.endRecord(ESM::REC_ENAB); progress.increaseProgress(); + + writer.startRecord(ESM::REC_CAM_); + writer.writeHNT("FIRS", isFirstPerson()); + writer.endRecord(ESM::REC_CAM_); + progress.increaseProgress(); } void World::readRecord (ESM::ESMReader& reader, int32_t type, @@ -347,6 +354,12 @@ namespace MWWorld reader.getHNT(mTeleportEnabled, "TELE"); reader.getHNT(mLevitationEnabled, "LEVT"); return; + case ESM::REC_CAM_: + bool firstperson; + reader.getHNT(firstperson, "FIRS"); + if (firstperson != isFirstPerson()) + togglePOV(); + break; default: if (!mStore.readRecord (reader, type) && !mGlobalVariables.readRecord (reader, type) && @@ -2073,7 +2086,6 @@ namespace MWWorld MWBase::Environment::get().getMechanicsManager()->add(mPlayer->getPlayer()); mPhysics->addActor(mPlayer->getPlayer()); - mRendering->resetCamera(); } int World::canRest () diff --git a/components/esm/defs.hpp b/components/esm/defs.hpp index d5ba919b0..fe45d6914 100644 --- a/components/esm/defs.hpp +++ b/components/esm/defs.hpp @@ -114,6 +114,7 @@ enum RecNameInts REC_DCOU = FourCC<'D','C','O','U'>::value, REC_MARK = FourCC<'M','A','R','K'>::value, REC_ENAB = FourCC<'E','N','A','B'>::value, + REC_CAM_ = FourCC<'C','A','M','_'>::value, // format 1 REC_FILT = 0x544C4946, From 4d9100091d3356dfadef0b55e83970da689ba406 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 6 Jan 2015 22:19:04 +0100 Subject: [PATCH 0215/3725] Reduce default pathing arrival tolerance to 32 units (Fixes #1605) --- apps/openmw/mwmechanics/aiwander.cpp | 2 +- apps/openmw/mwmechanics/pathfinding.cpp | 4 ++-- apps/openmw/mwmechanics/pathfinding.hpp | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 2df3762ab..94c4542f8 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -202,7 +202,7 @@ namespace MWMechanics // Are we there yet? bool& chooseAction = storage.mChooseAction; if(walking && - storage.mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], pos.pos[2])) + storage.mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], pos.pos[2], 64.f)) { stopWalking(actor, storage); moveNow = false; diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index f1279c415..f59167df7 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -297,13 +297,13 @@ namespace MWMechanics return false; } - bool PathFinder::checkPathCompleted(float x, float y, float z) + bool PathFinder::checkPathCompleted(float x, float y, float z, float tolerance) { if(mPath.empty()) return true; ESM::Pathgrid::Point nextPoint = *mPath.begin(); - if(sqrDistanceZCorrected(nextPoint, x, y, z) < 64*64) + if(sqrDistanceZCorrected(nextPoint, x, y, z) < tolerance*tolerance) { mPath.pop_front(); if(mPath.empty()) diff --git a/apps/openmw/mwmechanics/pathfinding.hpp b/apps/openmw/mwmechanics/pathfinding.hpp index 482808dac..61008577c 100644 --- a/apps/openmw/mwmechanics/pathfinding.hpp +++ b/apps/openmw/mwmechanics/pathfinding.hpp @@ -39,8 +39,8 @@ namespace MWMechanics void buildPath(const ESM::Pathgrid::Point &startPoint, const ESM::Pathgrid::Point &endPoint, const MWWorld::CellStore* cell, bool allowShortcuts = true); - bool checkPathCompleted(float x, float y, float z); - ///< \Returns true if the last point of the path has been reached. + bool checkPathCompleted(float x, float y, float z, float tolerance=32.f); + ///< \Returns true if we are within \a tolerance units of the last path point. bool checkWaypoint(float x, float y, float z); ///< \Returns true if a way point was reached From a17252eab3415d2b1d987ccc8c3a3ef3c1481b32 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 6 Jan 2015 23:23:58 +0100 Subject: [PATCH 0216/3725] Remove unused checkWaypoint function It was an almost exact copy of the checkPathCompleted function anyway. --- apps/openmw/mwmechanics/aicombat.cpp | 2 +- apps/openmw/mwmechanics/pathfinding.cpp | 15 --------------- apps/openmw/mwmechanics/pathfinding.hpp | 3 --- 3 files changed, 1 insertion(+), 19 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index a23634ea3..5d0470554 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -580,7 +580,7 @@ namespace MWMechanics buildNewPath(actor, target); //may fail to build a path, check before use //delete visited path node - mPathFinder.checkWaypoint(pos.pos[0],pos.pos[1],pos.pos[2]); + mPathFinder.checkPathCompleted(pos.pos[0],pos.pos[1],pos.pos[2]); // This works on the borders between the path grid and areas with no waypoints. if(inLOS && mPathFinder.getPath().size() > 1) diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index f59167df7..0634725a8 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -282,21 +282,6 @@ namespace MWMechanics return Ogre::Math::ATan2(directionX,directionY).valueDegrees(); } - bool PathFinder::checkWaypoint(float x, float y, float z) - { - if(mPath.empty()) - return true; - - ESM::Pathgrid::Point nextPoint = *mPath.begin(); - if(sqrDistanceZCorrected(nextPoint, x, y, z) < 64*64) - { - mPath.pop_front(); - if(mPath.empty()) mIsPathConstructed = false; - return true; - } - return false; - } - bool PathFinder::checkPathCompleted(float x, float y, float z, float tolerance) { if(mPath.empty()) diff --git a/apps/openmw/mwmechanics/pathfinding.hpp b/apps/openmw/mwmechanics/pathfinding.hpp index 61008577c..7ba2d22ba 100644 --- a/apps/openmw/mwmechanics/pathfinding.hpp +++ b/apps/openmw/mwmechanics/pathfinding.hpp @@ -42,9 +42,6 @@ namespace MWMechanics bool checkPathCompleted(float x, float y, float z, float tolerance=32.f); ///< \Returns true if we are within \a tolerance units of the last path point. - bool checkWaypoint(float x, float y, float z); - ///< \Returns true if a way point was reached - float getZAngleToNext(float x, float y) const; bool isPathConstructed() const From d02e075bab885d805e8c6d7b994da75c69f69154 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 6 Jan 2015 23:54:53 +0100 Subject: [PATCH 0217/3725] Add setting for exterior cell grid size (Fixes #1537) --- apps/openmw/mwworld/scene.cpp | 16 +++++++++------- files/settings-default.cfg | 3 +++ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 02c9db9ea..efe88c406 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -296,15 +296,17 @@ namespace MWWorld std::string loadingExteriorText = "#{sLoadingMessage3}"; loadingListener->setLabel(loadingExteriorText); + const int halfGridSize = Settings::Manager::getInt("exterior grid size", "Cells")/2; + CellStoreCollection::iterator active = mActiveCells.begin(); while (active!=mActiveCells.end()) { if ((*active)->getCell()->isExterior()) { - if (std::abs (X-(*active)->getCell()->getGridX())<=1 && - std::abs (Y-(*active)->getCell()->getGridY())<=1) + if (std::abs (X-(*active)->getCell()->getGridX())<=halfGridSize && + std::abs (Y-(*active)->getCell()->getGridY())<=halfGridSize) { - // keep cells within the new 3x3 grid + // keep cells within the new grid ++active; continue; } @@ -314,9 +316,9 @@ namespace MWWorld int refsToLoad = 0; // get the number of refs to load - for (int x=X-1; x<=X+1; ++x) + for (int x=X-halfGridSize; x<=X+halfGridSize; ++x) { - for (int y=Y-1; y<=Y+1; ++y) + for (int y=Y-halfGridSize; y<=Y+halfGridSize; ++y) { CellStoreCollection::iterator iter = mActiveCells.begin(); @@ -339,9 +341,9 @@ namespace MWWorld loadingListener->setProgressRange(refsToLoad); // Load cells - for (int x=X-1; x<=X+1; ++x) + for (int x=X-halfGridSize; x<=X+halfGridSize; ++x) { - for (int y=Y-1; y<=Y+1; ++y) + for (int y=Y-halfGridSize; y<=Y+halfGridSize; ++y) { CellStoreCollection::iterator iter = mActiveCells.begin(); diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 6ec9b03e9..f91299a1f 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -123,6 +123,9 @@ local map resolution = 256 local map widget size = 512 local map hud widget size = 256 +[Cells] +exterior grid size = 3 + [Viewing distance] # Limit the rendering distance of small objects limit small object distance = false From dc5ed5b8613b9074ecc6a25e4a41b1825909abb6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 7 Jan 2015 01:11:39 +0100 Subject: [PATCH 0218/3725] Remove weather particles underwater (Fixes #2010) --- apps/openmw/mwrender/sky.cpp | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 761d3fd96..0b9dc091e 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -431,7 +432,10 @@ void SkyManager::updateRain(float dt) Ogre::Vector3 pos = it->first->getPosition(); pos.z -= mRainSpeed * dt; it->first->setPosition(pos); - if (pos.z < -minHeight) + if (pos.z < -minHeight + // Here we might want to add a "splash" effect later + || MWBase::Environment::get().getWorld()->isUnderwater( + MWBase::Environment::get().getWorld()->getPlayerPtr().getCell(), it->first->_getDerivedPosition())) { it->second.setNull(); mSceneMgr->destroySceneNode(it->first); @@ -458,6 +462,12 @@ void SkyManager::updateRain(float dt) // Create a separate node to control the offset, since a node with setInheritOrientation(false) will still // consider the orientation of the parent node for its position, just not for its orientation float startHeight = 700; + Ogre::Vector3 worldPos = mParticleNode->_getDerivedPosition(); + worldPos += Ogre::Vector3(xOffs, yOffs, startHeight); + if (MWBase::Environment::get().getWorld()->isUnderwater( + MWBase::Environment::get().getWorld()->getPlayerPtr().getCell(), worldPos)) + return; + Ogre::SceneNode* offsetNode = mParticleNode->createChildSceneNode(Ogre::Vector3(xOffs,yOffs,startHeight)); // Spawn a new rain object for each instance. @@ -490,6 +500,30 @@ void SkyManager::update(float duration) for (unsigned int i=0; imControllers.size(); ++i) mParticle->mControllers[i].update(); + for (unsigned int i=0; imParticles.size(); ++i) + { + Ogre::ParticleSystem* psys = mParticle->mParticles[i]; + Ogre::ParticleIterator pi = psys->_getIterator(); + while (!pi.end()) + { + Ogre::Particle *p = pi.getNext(); + #if OGRE_VERSION >= (1 << 16 | 10 << 8 | 0) + Ogre::Vector3 pos = p->mPosition; + Ogre::Real& timeToLive = p->mTimeToLive; + #else + Ogre::Vector3 pos = p->position; + Ogre::Real& timeToLive = p->timeToLive; + #endif + + if (psys->getKeepParticlesInLocalSpace() && psys->getParentNode()) + pos = psys->getParentNode()->convertLocalToWorldPosition(pos); + + if (MWBase::Environment::get().getWorld()->isUnderwater( + MWBase::Environment::get().getWorld()->getPlayerPtr().getCell(), pos)) + timeToLive = 0; + } + } + if (mIsStorm) mParticleNode->setOrientation(Ogre::Vector3::UNIT_Y.getRotationTo(mStormDirection)); } From 157438460b1500ec2277d4f809b3fc383cba36d0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 7 Jan 2015 01:30:59 +0100 Subject: [PATCH 0219/3725] Fix being able to activate objects when paralyzed --- apps/openmw/engine.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 24e1388d0..c48f509b5 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -514,7 +514,8 @@ void OMW::Engine::activate() return; MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); - if (player.getClass().getCreatureStats(player).getKnockedDown()) + if (player.getClass().getCreatureStats(player).getMagicEffects().get(ESM::MagicEffect::Paralyze).getMagnitude() > 0 + || player.getClass().getCreatureStats(player).getKnockedDown()) return; MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getFacedObject(); From 4e92f6ab48c5cefb5c4dc60d6ef8ee04fc2e6e70 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 7 Jan 2015 03:03:56 +0100 Subject: [PATCH 0220/3725] Add commandline option to load a save game on startup --- apps/openmw/engine.cpp | 13 +++++- apps/openmw/engine.hpp | 4 ++ apps/openmw/main.cpp | 4 ++ apps/openmw/mwbase/statemanager.hpp | 11 +++-- apps/openmw/mwgui/savegamedialog.cpp | 2 +- apps/openmw/mwstate/character.cpp | 5 +++ apps/openmw/mwstate/character.hpp | 6 +-- apps/openmw/mwstate/statemanagerimp.cpp | 53 ++++++++++++++++++++----- apps/openmw/mwstate/statemanagerimp.hpp | 11 +++-- 9 files changed, 85 insertions(+), 24 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 24e1388d0..43adedcee 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -472,9 +472,13 @@ void OMW::Engine::go() // Play some good 'ol tunes MWBase::Environment::get().getSoundManager()->playPlaylist(std::string("Explore")); - // start in main menu - if (!mSkipMenu) + if (!mSaveGameFile.empty()) + { + MWBase::Environment::get().getStateManager()->loadGame(mSaveGameFile); + } + else if (!mSkipMenu) { + // start in main menu MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_MainMenu); try { @@ -622,3 +626,8 @@ void OMW::Engine::enableFontExport(bool exportFonts) { mExportFonts = exportFonts; } + +void OMW::Engine::setSaveGameFile(const std::string &savegame) +{ + mSaveGameFile = savegame; +} diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index 6cf31cba8..079dd922c 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -83,6 +83,7 @@ namespace OMW bool mScriptConsoleMode; std::string mStartupScript; int mActivationDistanceOverride; + std::string mSaveGameFile; // Grab mouse? bool mGrab; @@ -204,6 +205,9 @@ namespace OMW void enableFontExport(bool exportFonts); + /// Set the save game file to load after initialising the engine. + void setSaveGameFile(const std::string& savegame); + private: Files::ConfigurationManager& mCfgMgr; }; diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 9382e2516..74d434f63 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -152,6 +152,9 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat ("script-blacklist-use", bpo::value()->implicit_value(true) ->default_value(true), "enable script blacklisting") + ("load-savegame", bpo::value()->default_value(""), + "load a save game file on game startup") + ("skip-menu", bpo::value()->implicit_value(true) ->default_value(false), "skip main menu on game startup") @@ -274,6 +277,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat engine.setWarningsMode (variables["script-warn"].as()); engine.setScriptBlacklist (variables["script-blacklist"].as()); engine.setScriptBlacklistUse (variables["script-blacklist-use"].as()); + engine.setSaveGameFile (variables["load-savegame"].as()); // other settings engine.setSoundUsage(!variables["no-sound"].as()); diff --git a/apps/openmw/mwbase/statemanager.hpp b/apps/openmw/mwbase/statemanager.hpp index 006be921b..79ddbfa2a 100644 --- a/apps/openmw/mwbase/statemanager.hpp +++ b/apps/openmw/mwbase/statemanager.hpp @@ -62,10 +62,13 @@ namespace MWBase /// /// \note Slot must belong to the current character. - virtual void loadGame (const MWState::Character *character, const MWState::Slot *slot) = 0; - ///< Load a saved game file from \a slot. - /// - /// \note \a slot must belong to \a character. + virtual void loadGame (const std::string& filepath) = 0; + ///< Load a saved game directly from the given file path. This will search the CharacterManager + /// for a Character containing this save file, and set this Character current if one was found. + /// Otherwise, a new Character will be created. + + virtual void loadGame (const MWState::Character *character, const std::string& filepath) = 0; + ///< Load a saved game file belonging to the given character. ///Simple saver, writes over the file if already existing /** Used for quick save and autosave **/ diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index 7b9777c81..3775f53dd 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -246,7 +246,7 @@ namespace MWGui else { assert (mCurrentCharacter && mCurrentSlot); - MWBase::Environment::get().getStateManager()->loadGame (mCurrentCharacter, mCurrentSlot); + MWBase::Environment::get().getStateManager()->loadGame (mCurrentCharacter, mCurrentSlot->mPath.string()); } } diff --git a/apps/openmw/mwstate/character.cpp b/apps/openmw/mwstate/character.cpp index f8fcfceec..c2ca5e095 100644 --- a/apps/openmw/mwstate/character.cpp +++ b/apps/openmw/mwstate/character.cpp @@ -190,3 +190,8 @@ ESM::SavedGame MWState::Character::getSignature() const return slot.mProfile; } + +const boost::filesystem::path& MWState::Character::getPath() const +{ + return mPath; +} diff --git a/apps/openmw/mwstate/character.hpp b/apps/openmw/mwstate/character.hpp index 4703f0cca..32c79a183 100644 --- a/apps/openmw/mwstate/character.hpp +++ b/apps/openmw/mwstate/character.hpp @@ -54,12 +54,12 @@ namespace MWState /// \attention The \a slot pointer will be invalidated by this call. SlotIterator begin() const; - ///< First slot is the most recent. Other slots follow in descending order of save date. - /// - /// Any call to createSlot and updateSlot can invalidate the returned iterator. + ///< Any call to createSlot and updateSlot can invalidate the returned iterator. SlotIterator end() const; + const boost::filesystem::path& getPath() const; + ESM::SavedGame getSignature() const; ///< Return signature information for this character. /// diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index f77a90d8e..03cb5d921 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -291,16 +291,47 @@ void MWState::StateManager::quickSave (std::string name) saveGame(name, slot); } -void MWState::StateManager::loadGame (const Character *character, const Slot *slot) +void MWState::StateManager::loadGame(const std::string& filepath) +{ + for (CharacterIterator it = mCharacterManager.begin(); it != mCharacterManager.end(); ++it) + { + const MWState::Character& character = *it; + for (MWState::Character::SlotIterator slotIt = character.begin(); slotIt != character.end(); ++slotIt) + { + const MWState::Slot& slot = *slotIt; + if (slot.mPath == boost::filesystem::path(filepath)) + { + loadGame(&character, slot.mPath.string()); + return; + } + } + } + + // have to peek into the save file to get the player name + ESM::ESMReader reader; + reader.open (filepath); + if (reader.getFormat()>ESM::Header::CurrentFormat) + return; // format is too new -> ignore + if (reader.getRecName()!=ESM::REC_SAVE) + return; // invalid save file -> ignore + reader.getRecHeader(); + ESM::SavedGame profile; + profile.load (reader); + reader.close(); + + MWState::Character* character = mCharacterManager.getCurrentCharacter(true, profile.mPlayerName); + loadGame(character, filepath); + mTimePlayed = profile.mTimePlayed; +} + +void MWState::StateManager::loadGame (const Character *character, const std::string& filepath) { try { cleanup(); - mTimePlayed = slot->mProfile.mTimePlayed; - ESM::ESMReader reader; - reader.open (slot->mPath.string()); + reader.open (filepath); std::map contentFileMap = buildContentFileIndexMap (reader); @@ -319,9 +350,11 @@ void MWState::StateManager::loadGame (const Character *character, const Slot *sl switch (n.val) { case ESM::REC_SAVE: - - // don't need to read that here - reader.skipRecord(); + { + ESM::SavedGame profile; + profile.load(reader); + mTimePlayed = profile.mTimePlayed; + } break; case ESM::REC_JOUR: @@ -391,7 +424,7 @@ void MWState::StateManager::loadGame (const Character *character, const Slot *sl mState = State_Running; Settings::Manager::setString ("character", "Saves", - slot->mPath.parent_path().filename().string()); + character->getPath().filename().string()); MWBase::Environment::get().getWindowManager()->setNewGame(false); MWBase::Environment::get().getWorld()->setupPlayer(); @@ -431,7 +464,7 @@ void MWState::StateManager::quickLoad() { if (Character* mCurrentCharacter = getCurrentCharacter (false)) if (const MWState::Slot* slot = &*mCurrentCharacter->begin()) //Get newest save - loadGame (mCurrentCharacter, slot); + loadGame (mCurrentCharacter, slot->mPath.string()); } void MWState::StateManager::deleteGame(const MWState::Character *character, const MWState::Slot *slot) @@ -472,7 +505,7 @@ void MWState::StateManager::update (float duration) //Load last saved game for current character MWState::Slot lastSave = *curCharacter->begin(); - loadGame(curCharacter, &lastSave); + loadGame(curCharacter, lastSave.mPath.string()); } else if(iButton==1) { diff --git a/apps/openmw/mwstate/statemanagerimp.hpp b/apps/openmw/mwstate/statemanagerimp.hpp index 40c36deb5..956a2d73c 100644 --- a/apps/openmw/mwstate/statemanagerimp.hpp +++ b/apps/openmw/mwstate/statemanagerimp.hpp @@ -61,10 +61,13 @@ namespace MWState /** Used for quickload **/ virtual void quickLoad(); - virtual void loadGame (const Character *character, const Slot *slot); - ///< Load a saved game file from \a slot. - /// - /// \note \a slot must belong to \a character. + virtual void loadGame (const std::string& filepath); + ///< Load a saved game directly from the given file path. This will search the CharacterManager + /// for a Character containing this save file, and set this Character current if one was found. + /// Otherwise, a new Character will be created. + + virtual void loadGame (const Character *character, const std::string &filepath); + ///< Load a saved game file belonging to the given character. virtual Character *getCurrentCharacter (bool create = true); ///< \param create Create a new character, if there is no current character. From ef1b0a191b0370a711377093b84ccbbbe676955b Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 7 Jan 2015 03:48:16 +0100 Subject: [PATCH 0221/3725] Revert "Enchanting: fix inverted self-enchant success chance" It wasn't inverted to begin with. The author of this commit is an idiot. --- apps/openmw/mwmechanics/enchanting.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp index 8c85e5eef..08df95fd9 100644 --- a/apps/openmw/mwmechanics/enchanting.cpp +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -65,7 +65,7 @@ namespace MWMechanics if(mSelfEnchanting) { - if(std::rand()/static_cast (RAND_MAX)*100 < getEnchantChance()) + if(getEnchantChance() (RAND_MAX)*100) return false; mEnchanter.getClass().skillUsageSucceeded (mEnchanter, ESM::Skill::Enchant, 2); From 13c5bd5cc27cde385285776d48cd9e1aff7b42eb Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 7 Jan 2015 04:28:56 +0100 Subject: [PATCH 0222/3725] Enchanting: fix skill-based cast cost bonus being applied twice --- apps/openmw/mwgui/enchantingdialog.cpp | 2 +- apps/openmw/mwgui/spellmodel.cpp | 4 +--- apps/openmw/mwmechanics/enchanting.cpp | 23 ++++++++++------------- apps/openmw/mwmechanics/enchanting.hpp | 3 ++- apps/openmw/mwmechanics/spellcasting.cpp | 16 +++++++++++++--- apps/openmw/mwmechanics/spellcasting.hpp | 2 ++ 6 files changed, 29 insertions(+), 21 deletions(-) diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 4744fd1a1..d2315be38 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -111,7 +111,7 @@ namespace MWGui mCharge->setCaption(boost::lexical_cast(mEnchanting.getGemCharge())); std::stringstream castCost; - castCost << mEnchanting.getCastCost(); + castCost << mEnchanting.getEffectiveCastCost(); mCastCost->setCaption(castCost.str()); mPrice->setCaption(boost::lexical_cast(mEnchanting.getEnchantPrice())); diff --git a/apps/openmw/mwgui/spellmodel.cpp b/apps/openmw/mwgui/spellmodel.cpp index ad9a913fa..4713720cd 100644 --- a/apps/openmw/mwgui/spellmodel.cpp +++ b/apps/openmw/mwgui/spellmodel.cpp @@ -103,9 +103,7 @@ namespace MWGui && item.getClass().canBeEquipped(item, mActor).first == 0) continue; - float enchantCost = enchant->mData.mCost; - int eSkill = mActor.getClass().getSkill(mActor, ESM::Skill::Enchant); - int castCost = std::max(1.f, enchantCost - (enchantCost / 100) * (eSkill - 10)); + int castCost = MWMechanics::getEffectiveEnchantmentCastCost(enchant->mData.mCost, mActor); std::string cost = boost::lexical_cast(castCost); int currentCharge = int(item.getCellRef().getEnchantmentCharge()); diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp index 08df95fd9..96afe2e2a 100644 --- a/apps/openmw/mwmechanics/enchanting.cpp +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -6,6 +6,7 @@ #include "creaturestats.hpp" #include "npcstats.hpp" +#include "spellcasting.hpp" namespace MWMechanics { @@ -55,7 +56,7 @@ namespace MWMechanics enchantment.mData.mCharge = getGemCharge(); enchantment.mData.mAutocalc = 0; enchantment.mData.mType = mCastStyle; - enchantment.mData.mCost = getCastCost(); + enchantment.mData.mCost = getBaseCastCost(); store.remove(mSoulGemPtr, 1, player); @@ -199,23 +200,19 @@ namespace MWMechanics } - int Enchanting::getCastCost() const + int Enchanting::getBaseCastCost() const { if (mCastStyle == ESM::Enchantment::ConstantEffect) return 0; - const float enchantCost = getEnchantPoints(); - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); - MWMechanics::NpcStats &stats = player.getClass().getNpcStats(player); - int eSkill = stats.getSkill(ESM::Skill::Enchant).getModified(); - - /* - * Each point of enchant skill above/under 10 subtracts/adds - * one percent of enchantment cost while minimum is 1. - */ - const float castCost = enchantCost - (enchantCost / 100) * (eSkill - 10); + return getEnchantPoints(); + } - return static_cast((castCost < 1) ? 1 : castCost); + int Enchanting::getEffectiveCastCost() const + { + int baseCost = getBaseCastCost(); + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + return getEffectiveEnchantmentCastCost(baseCost, player); } diff --git a/apps/openmw/mwmechanics/enchanting.hpp b/apps/openmw/mwmechanics/enchanting.hpp index 2ee5ccce4..2c05d2d2e 100644 --- a/apps/openmw/mwmechanics/enchanting.hpp +++ b/apps/openmw/mwmechanics/enchanting.hpp @@ -36,7 +36,8 @@ namespace MWMechanics void nextCastStyle(); //Set enchant type to next possible type (for mOldItemPtr object) int getCastStyle() const; int getEnchantPoints() const; - int getCastCost() const; + int getBaseCastCost() const; // To be saved in the enchantment's record + int getEffectiveCastCost() const; // Effective cost taking player Enchant skill into account, used for preview purposes in the UI int getEnchantPrice() const; int getMaxEnchantValue() const; int getGemCharge() const; diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index b7c7e00a1..d9df1d00e 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -689,9 +689,7 @@ namespace MWMechanics // Check if there's enough charge left if (enchantment->mData.mType == ESM::Enchantment::WhenUsed || enchantment->mData.mType == ESM::Enchantment::WhenStrikes) { - const float enchantCost = enchantment->mData.mCost; - int eSkill = mCaster.getClass().getSkill(mCaster, ESM::Skill::Enchant); - const int castCost = std::max(1.f, enchantCost - (enchantCost / 100) * (eSkill - 10)); + const int castCost = getEffectiveEnchantmentCastCost(enchantment->mData.mCost, mCaster); if (item.getCellRef().getEnchantmentCharge() == -1) item.getCellRef().setEnchantmentCharge(enchantment->mData.mCharge); @@ -915,4 +913,16 @@ namespace MWMechanics return true; } + + int getEffectiveEnchantmentCastCost(float castCost, const MWWorld::Ptr &actor) + { + /* + * Each point of enchant skill above/under 10 subtracts/adds + * one percent of enchantment cost while minimum is 1. + */ + int eSkill = actor.getClass().getSkill(actor, ESM::Skill::Enchant); + const float result = castCost - (castCost / 100) * (eSkill - 10); + + return static_cast((result < 1) ? 1 : result); + } } diff --git a/apps/openmw/mwmechanics/spellcasting.hpp b/apps/openmw/mwmechanics/spellcasting.hpp index 395ae043b..a79eeec6b 100644 --- a/apps/openmw/mwmechanics/spellcasting.hpp +++ b/apps/openmw/mwmechanics/spellcasting.hpp @@ -58,6 +58,8 @@ namespace MWMechanics float getEffectMultiplier(short effectId, const MWWorld::Ptr& actor, const MWWorld::Ptr& caster, const ESM::Spell* spell = NULL, const MagicEffects* effects = NULL); + int getEffectiveEnchantmentCastCost (float castCost, const MWWorld::Ptr& actor); + class CastSpell { private: From 4684014a83d1c8fef28cb7a25bb6528b03e4978a Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 7 Jan 2015 15:06:39 +0100 Subject: [PATCH 0223/3725] Use .omwsave extension for save game files --- apps/openmw/mwstate/character.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwstate/character.cpp b/apps/openmw/mwstate/character.cpp index c2ca5e095..f190565da 100644 --- a/apps/openmw/mwstate/character.cpp +++ b/apps/openmw/mwstate/character.cpp @@ -61,7 +61,8 @@ void MWState::Character::addSlot (const ESM::SavedGame& profile) stream << "_"; } - slot.mPath = mPath / stream.str(); + const std::string ext = ".omwsave"; + slot.mPath = mPath / (stream.str() + ext); // Append an index if necessary to ensure a unique file int i=0; @@ -70,7 +71,7 @@ void MWState::Character::addSlot (const ESM::SavedGame& profile) std::ostringstream test; test << stream.str(); test << " - " << ++i; - slot.mPath = mPath / test.str(); + slot.mPath = mPath / (test.str() + ext); } slot.mProfile = profile; From 94002b0758a8825215074b5341b6ec6b0cd28660 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 7 Jan 2015 15:07:08 +0100 Subject: [PATCH 0224/3725] Add freedesktop.org mimeinfo for OpenMW save game files This allows us to launch OpenMW when the user opens a save game file through the file manager. --- CMakeLists.txt | 3 +++ files/openmw-mimeinfo.xml | 11 +++++++++++ files/openmw.desktop | 13 +++++++++++++ 3 files changed, 27 insertions(+) create mode 100644 files/openmw-mimeinfo.xml diff --git a/CMakeLists.txt b/CMakeLists.txt index fb89f4e91..0edf8cacd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -386,6 +386,8 @@ configure_file(${OpenMW_SOURCE_DIR}/files/opencs/defaultfilters if (NOT WIN32 AND NOT APPLE) configure_file(${OpenMW_SOURCE_DIR}/files/openmw.desktop "${OpenMW_BINARY_DIR}/openmw.desktop") + configure_file(${OpenMW_SOURCE_DIR}/files/openmw-mimeinfo.xml + "${OpenMW_BINARY_DIR}/openmw-mimeinfo.xml") configure_file(${OpenMW_SOURCE_DIR}/files/opencs.desktop "${OpenMW_BINARY_DIR}/opencs.desktop") endif() @@ -451,6 +453,7 @@ IF(NOT WIN32 AND NOT APPLE) # Install icon and desktop file INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.desktop" DESTINATION "${DATAROOTDIR}/applications" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") + INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw-mimeinfo.xml" DESTINATION "${DATAROOTDIR}/mime/packages" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") INSTALL(FILES "${OpenMW_SOURCE_DIR}/files/launcher/images/openmw.png" DESTINATION "${ICONDIR}" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") IF(BUILD_OPENCS) INSTALL(FILES "${OpenMW_BINARY_DIR}/opencs.desktop" DESTINATION "${DATAROOTDIR}/applications" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "opencs") diff --git a/files/openmw-mimeinfo.xml b/files/openmw-mimeinfo.xml new file mode 100644 index 000000000..1355383a5 --- /dev/null +++ b/files/openmw-mimeinfo.xml @@ -0,0 +1,11 @@ + + + + + + + OpenMW Savegame + + + + diff --git a/files/openmw.desktop b/files/openmw.desktop index 4a3a76f52..709304cb9 100644 --- a/files/openmw.desktop +++ b/files/openmw.desktop @@ -8,3 +8,16 @@ TryExec=omwlauncher Exec=omwlauncher Icon=openmw Categories=Game;RolePlaying; + +[Desktop Entry] +Type=Application +Name=OpenMW +GenericName=Role Playing Game +Comment=An engine replacement for The Elder Scrolls III: Morrowind +Keywords=Morrowind;Reimplementation Mods;esm;bsa; +Exec=openmw --load-savegame=%f +Icon=openmw +Categories=Game;RolePlaying; +Terminal=false +NoDisplay=true +MimeType=application/x-openmw-savegame; From 083de62be59ad0fe701af233eff2e8d0411ebb18 Mon Sep 17 00:00:00 2001 From: dteviot Date: Thu, 8 Jan 2015 11:18:42 +1300 Subject: [PATCH 0225/3725] Fixed issues found by Zinnschlag. 1. Errors found are added to default tool tip text. (Instead of replacing it.) 2. If multiple errors are found, all are shown in tool tip text, not just first one. 3. Load Order Errors are updated when files are activated/deactivated, not just when the files have their position in list changed. --- .../contentselector/model/contentmodel.cpp | 94 +++++++++++-------- .../contentselector/model/contentmodel.hpp | 17 +++- .../contentselector/model/loadordererror.cpp | 7 -- .../contentselector/model/loadordererror.hpp | 4 - 4 files changed, 65 insertions(+), 57 deletions(-) diff --git a/components/contentselector/model/contentmodel.cpp b/components/contentselector/model/contentmodel.cpp index 6366d7f54..57b231357 100644 --- a/components/contentselector/model/contentmodel.cpp +++ b/components/contentselector/model/contentmodel.cpp @@ -173,7 +173,7 @@ QVariant ContentSelectorModel::ContentModel::data(const QModelIndex &index, int { case Qt::ForegroundRole: { - if (isLoadOrderError(file->filePath())) + if (isLoadOrderError(file)) { QBrush redBackground(Qt::red, Qt::SolidPattern); return redBackground; @@ -213,7 +213,7 @@ QVariant ContentSelectorModel::ContentModel::data(const QModelIndex &index, int if (column != 0) return QVariant(); - return isLoadOrderError(file->filePath()) ? getLoadOrderError(file->filePath()).toolTip() : file->toolTip(); + return toolTip(file); break; } @@ -302,7 +302,7 @@ bool ContentSelectorModel::ContentModel::setData(const QModelIndex &index, const { setCheckState(file->filePath(), success); emit dataChanged(index, index); - + checkForLoadOrderErrors(); } else return success; @@ -543,26 +543,14 @@ bool ContentSelectorModel::ContentModel::isEnabled (QModelIndex index) const return (flags(index) & Qt::ItemIsEnabled); } -bool ContentSelectorModel::ContentModel::isLoadOrderError(const QString& filepath) const +bool ContentSelectorModel::ContentModel::isLoadOrderError(const EsmFile *file) const { - return !(getLoadOrderError(filepath) == LoadOrderError::sNoError); -} - -ContentSelectorModel::LoadOrderError ContentSelectorModel::ContentModel::getLoadOrderError(const QString& filepath) const -{ - return mLoadOrderErrors.contains(filepath) ? mLoadOrderErrors[filepath] : ContentSelectorModel::LoadOrderError::sNoError; -} - -void ContentSelectorModel::ContentModel::setLoadOrderError(const QString& filepath, const ContentSelectorModel::LoadOrderError& loadOrderError) -{ - mLoadOrderErrors[filepath] = loadOrderError; - int filePosition = indexFromItem(item(filepath)).row(); - emit dataChanged(index(filePosition, 0, QModelIndex()), index(filePosition, 0, QModelIndex())); + return mPluginsWithLoadOrderError.contains(file->filePath()); } void ContentSelectorModel::ContentModel::setContentList(const QStringList &fileList, bool isChecked) { - mLoadOrderErrors.clear(); + mPluginsWithLoadOrderError.clear(); int previousPosition = -1; foreach (const QString &filepath, fileList) { @@ -590,36 +578,60 @@ void ContentSelectorModel::ContentModel::checkForLoadOrderErrors() for (int row = 0; row < mFiles.count(); ++row) { EsmFile* file = item(row); - bool isRowInError = isLoadOrderError(file->filePath()); - LoadOrderError::ErrorCode error = LoadOrderError::ErrorCode_None; - foreach(QString dependentfileName, file->gameFiles()) + bool isRowInError = checkForLoadOrderErrors(file, row).count() != 0; + if (isRowInError) + { + mPluginsWithLoadOrderError.insert(file->filePath()); + } + else { - const EsmFile* dependentFile = item(dependentfileName); + mPluginsWithLoadOrderError.remove(file->filePath()); + } + } +} - if (!dependentFile) - { - error = LoadOrderError::ErrorCode_MissingDependency; - } - else if (!isChecked(dependentFile->filePath())) - { - error = LoadOrderError::ErrorCode_InactiveDependency; - } - else if (row < indexFromItem(dependentFile).row()) - { - error = LoadOrderError::ErrorCode_LoadOrder; - } +QList ContentSelectorModel::ContentModel::checkForLoadOrderErrors(const EsmFile *file, int row) const +{ + QList errors = QList(); + foreach(QString dependentfileName, file->gameFiles()) + { + const EsmFile* dependentFile = item(dependentfileName); - if (!isRowInError && (error != LoadOrderError::ErrorCode_None)) - { - setLoadOrderError(file->filePath(), LoadOrderError(error, dependentfileName)); - break; - } + if (!dependentFile) + { + errors.append(LoadOrderError(LoadOrderError::ErrorCode_MissingDependency, dependentfileName)); + } + if (!isChecked(dependentFile->filePath())) + { + errors.append(LoadOrderError(LoadOrderError::ErrorCode_InactiveDependency, dependentfileName)); } + if (row < indexFromItem(dependentFile).row()) + { + errors.append(LoadOrderError(LoadOrderError::ErrorCode_LoadOrder, dependentfileName)); + } + } + return errors; +} - if (isRowInError && (error == LoadOrderError::ErrorCode_None)) +QString ContentSelectorModel::ContentModel::toolTip(const EsmFile *file) const +{ + if (isLoadOrderError(file)) + { + QString text(""); + int index = indexFromItem(item(file->filePath())).row(); + foreach(const LoadOrderError& error, checkForLoadOrderErrors(file, index)) { - setLoadOrderError(file->filePath(), LoadOrderError::sNoError); + text += "

"; + text += error.toolTip(); + text += "

"; } + text += ("
"); + text += file->toolTip(); + return text; + } + else + { + return file->toolTip(); } } diff --git a/components/contentselector/model/contentmodel.hpp b/components/contentselector/model/contentmodel.hpp index 2a9f2c93b..f6e3d62bd 100644 --- a/components/contentselector/model/contentmodel.hpp +++ b/components/contentselector/model/contentmodel.hpp @@ -3,6 +3,7 @@ #include #include +#include #include "loadordererror.hpp" @@ -53,10 +54,6 @@ namespace ContentSelectorModel ContentFileList checkedItems() const; void uncheckAll(); - bool isLoadOrderError(const QString& filepath) const; - LoadOrderError getLoadOrderError(const QString& filepath) const; - void setLoadOrderError(const QString& filepath, const LoadOrderError& loadOrderError); - void refreshModel(); private: @@ -66,12 +63,22 @@ namespace ContentSelectorModel EsmFile *item(int row); void sortFiles(); + + /// Checks all plug-ins for load order errors and updates mPluginsWithLoadOrderError with plug-ins with issues void checkForLoadOrderErrors(); + /// Checks a specific plug-in for load order errors + /// \return all errors found for specific plug-in + QList checkForLoadOrderErrors(const EsmFile *file, int row) const; + + /// \return true if plug-in has a Load Order error + bool isLoadOrderError(const EsmFile *file) const; + + QString toolTip(const EsmFile *file) const; ContentFileList mFiles; QHash mCheckStates; - QHash mLoadOrderErrors; + QSet mPluginsWithLoadOrderError; QTextCodec *mCodec; QString mEncoding; diff --git a/components/contentselector/model/loadordererror.cpp b/components/contentselector/model/loadordererror.cpp index 0d02efbeb..aa69f330e 100644 --- a/components/contentselector/model/loadordererror.cpp +++ b/components/contentselector/model/loadordererror.cpp @@ -8,15 +8,8 @@ QString ContentSelectorModel::LoadOrderError::sErrorToolTips[ErrorCode_LoadOrder QString("This file needs to load after %1") }; -ContentSelectorModel::LoadOrderError ContentSelectorModel::LoadOrderError::sNoError = ContentSelectorModel::LoadOrderError(); - QString ContentSelectorModel::LoadOrderError::toolTip() const { assert(mErrorCode); return sErrorToolTips[mErrorCode - 1].arg(mFileName); } - -bool ContentSelectorModel::LoadOrderError::operator== (const ContentSelectorModel::LoadOrderError& rhs) const -{ - return (mErrorCode == rhs.mErrorCode) && ((mErrorCode == ErrorCode_None) || (mFileName == rhs.mFileName)); -} \ No newline at end of file diff --git a/components/contentselector/model/loadordererror.hpp b/components/contentselector/model/loadordererror.hpp index f3d3b0f8a..2b840cf69 100644 --- a/components/contentselector/model/loadordererror.hpp +++ b/components/contentselector/model/loadordererror.hpp @@ -25,12 +25,8 @@ namespace ContentSelectorModel } inline ErrorCode errorCode() const { return mErrorCode; } inline QString fileName() const { return mFileName; } - bool operator==(const LoadOrderError& rhs) const; QString toolTip() const; - /// Sentinel to represent a "No Load Order Error" condition - static LoadOrderError sNoError; - private: ErrorCode mErrorCode; QString mFileName; From 4b88ef58910c63cfef0fe6a1dac471980813f00c Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 8 Jan 2015 13:59:03 +0100 Subject: [PATCH 0226/3725] fixed QuickFileParser handling of begin line (skip it instead of trying to make sense of it) --- components/compiler/quickfileparser.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/components/compiler/quickfileparser.cpp b/components/compiler/quickfileparser.cpp index 895b7ce65..f3d8063b2 100644 --- a/components/compiler/quickfileparser.cpp +++ b/components/compiler/quickfileparser.cpp @@ -19,12 +19,6 @@ bool Compiler::QuickFileParser::parseName (const std::string& name, const TokenL bool Compiler::QuickFileParser::parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner) { - if (keyword==Scanner::K_begin) - { - scanner.allowNameStartingwithDigit(); - return true; - } - if (keyword==Scanner::K_end) return false; From ef7e0070a62f1c90c9a9150c397d3666c61a0b0a Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 8 Jan 2015 02:34:37 +0100 Subject: [PATCH 0227/3725] Don't right-shift signed integers which is implementation-defined --- apps/openmw/mwgui/formatting.cpp | 2 +- apps/openmw/mwrender/animation.cpp | 2 +- components/esm/loadligh.hpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwgui/formatting.cpp b/apps/openmw/mwgui/formatting.cpp index 583116003..765402a01 100644 --- a/apps/openmw/mwgui/formatting.cpp +++ b/apps/openmw/mwgui/formatting.cpp @@ -340,7 +340,7 @@ namespace MWGui { if (attr.find("color") != attr.end()) { - int color; + unsigned int color; std::stringstream ss; ss << attr.at("color"); ss >> std::hex >> color; diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 1ef7a3533..ea40721cb 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -336,7 +336,7 @@ void Animation::addExtraLight(Ogre::SceneManager *sceneMgr, NifOgre::ObjectScene { const MWWorld::Fallback *fallback = MWBase::Environment::get().getWorld()->getFallback(); - const int clr = light->mData.mColor; + const unsigned int clr = light->mData.mColor; Ogre::ColourValue color(((clr >> 0) & 0xFF) / 255.0f, ((clr >> 8) & 0xFF) / 255.0f, ((clr >> 16) & 0xFF) / 255.0f); diff --git a/components/esm/loadligh.hpp b/components/esm/loadligh.hpp index ffc291609..2c83248f8 100644 --- a/components/esm/loadligh.hpp +++ b/components/esm/loadligh.hpp @@ -37,7 +37,7 @@ struct Light int mValue; int mTime; // Duration int mRadius; - int mColor; // 4-byte rgba value + unsigned int mColor; // 4-byte rgba value int mFlags; }; // Size = 24 bytes From 928b9ee41b2f3296426102d4df1fc9bf85d8ed91 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 8 Jan 2015 03:29:13 +0100 Subject: [PATCH 0228/3725] Fix missing GUI mode update when showing soulgem dialog --- apps/openmw/mwgui/windowmanagerimp.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 72805dd31..5546480ec 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1455,6 +1455,8 @@ namespace MWGui void WindowManager::showSoulgemDialog(MWWorld::Ptr item) { mSoulgemDialog->show(item); + MWBase::Environment::get().getInputManager()->changeInputMode(isGuiMode()); + updateVisible(); } void WindowManager::frameStarted (float dt) From d31ae2b345e0058696a41308d370cb6e851f55a2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 8 Jan 2015 16:17:13 +0100 Subject: [PATCH 0229/3725] Fix mIds mapping for dynamic records being lost on save/reload --- apps/openmw/mwworld/esmstore.cpp | 10 +++++++++- apps/openmw/mwworld/store.hpp | 6 +++--- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index 2a3fd9179..8e0f58a6b 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -192,7 +192,15 @@ void ESMStore::setUp() case ESM::REC_LEVI: case ESM::REC_LEVC: - mStores[type]->read (reader); + { + std::string id = reader.getHNString ("NAME"); + mStores[type]->read (reader, id); + + // FIXME: there might be stale dynamic IDs in mIds from an earlier savegame + // that really should be cleared instead of just overwritten + + mIds[id] = type; + } if (type==ESM::REC_NPC_) { diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index dcfbb4eb1..97ba4652f 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -30,7 +30,7 @@ namespace MWWorld virtual void write (ESM::ESMWriter& writer) const {} - virtual void read (ESM::ESMReader& reader) {} + virtual void read (ESM::ESMReader& reader, const std::string& id) {} ///< Read into dynamic storage }; @@ -329,10 +329,10 @@ namespace MWWorld } } - void read (ESM::ESMReader& reader) + void read (ESM::ESMReader& reader, const std::string& id) { T record; - record.mId = reader.getHNString ("NAME"); + record.mId = id; record.load (reader); insert (record); } From 2ddbe22da311b5f740a53fa1c4eecc39cbde4b9d Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 9 Jan 2015 00:44:22 +0100 Subject: [PATCH 0230/3725] Fix for NPC store clearDynamic bug It was clearing the whole mShared vector, instead of only the dynamic part. Actually, that whole overload was pointless to begin with. All it does is making sure the Player record isn't cleared, but ESMStore::clearDynamic re-inserts the player record anyway after clearing. --- apps/openmw/mwworld/store.hpp | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index 97ba4652f..e94624ade 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -140,7 +140,8 @@ namespace MWWorld virtual void clearDynamic() { // remove the dynamic part of mShared - mShared.erase(mShared.begin() + mStatic.size(), mShared.end()); + if (mShared.size() > mStatic.size()) + mShared.erase(mShared.begin() + mStatic.size(), mShared.end()); mDynamic.clear(); } @@ -217,7 +218,8 @@ namespace MWWorld void setUp() { // remove the dynamic part of mShared - mShared.erase(mShared.begin() + mStatic.size(), mShared.end()); + if (mShared.size() > mStatic.size()) + mShared.erase(mShared.begin() + mStatic.size(), mShared.end()); } iterator begin() const { @@ -305,7 +307,8 @@ namespace MWWorld mDynamic.erase(it); // have to reinit the whole shared part - mShared.erase(mShared.begin() + mStatic.size(), mShared.end()); + if (mShared.size() > mStatic.size()) + mShared.erase(mShared.begin() + mStatic.size(), mShared.end()); for (it = mDynamic.begin(); it != mDynamic.end(); ++it) { mShared.push_back(&it->second); } @@ -338,20 +341,6 @@ namespace MWWorld } }; - template <> - inline void Store::clearDynamic() - { - std::map::iterator iter = mDynamic.begin(); - - while (iter!=mDynamic.end()) - if (iter->first=="player") - ++iter; - else - mDynamic.erase (iter++); - - mShared.clear(); - } - template <> inline void Store::load(ESM::ESMReader &esm, const std::string &id) { std::string idLower = Misc::StringUtils::lowerCase(id); From c77660ba206168cd186c26d03f170e3cee3d31a8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 9 Jan 2015 01:01:55 +0100 Subject: [PATCH 0231/3725] Remove some nonsense code --- apps/openmw/mwworld/esmstore.hpp | 3 --- apps/openmw/mwworld/store.cpp | 3 +-- apps/openmw/mwworld/store.hpp | 6 ------ 3 files changed, 1 insertion(+), 11 deletions(-) diff --git a/apps/openmw/mwworld/esmstore.hpp b/apps/openmw/mwworld/esmstore.hpp index 5d794db89..01770e6b3 100644 --- a/apps/openmw/mwworld/esmstore.hpp +++ b/apps/openmw/mwworld/esmstore.hpp @@ -99,9 +99,6 @@ namespace MWWorld ESMStore() : mDynamicCount(0) { - // Cell store needs access to this for tracking moved references - mCells.mEsmStore = this; - mStores[ESM::REC_ACTI] = &mActivators; mStores[ESM::REC_ALCH] = &mPotions; mStores[ESM::REC_APPA] = &mAppas; diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index caf4083fe..7d58013e7 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -11,8 +11,7 @@ void Store::handleMovedCellRefs(ESM::ESMReader& esm, ESM::Cell* cell) ESM::MovedCellRef cMRef; cell->getNextMVRF(esm, cMRef); - MWWorld::Store &cStore = const_cast&>(mEsmStore->get()); - ESM::Cell *cellAlt = const_cast(cStore.searchOrCreate(cMRef.mTarget[0], cMRef.mTarget[1])); + ESM::Cell *cellAlt = const_cast(searchOrCreate(cMRef.mTarget[0], cMRef.mTarget[1])); // Get regular moved reference data. Adapted from CellStore::loadRefs. Maybe we can optimize the following // implementation when the oher implementation works as well. diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index e94624ade..71e77d0c7 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -582,14 +582,8 @@ namespace MWWorld void handleMovedCellRefs(ESM::ESMReader& esm, ESM::Cell* cell); public: - ESMStore *mEsmStore; - typedef SharedIterator iterator; - Store() - : mEsmStore(NULL) - {} - const ESM::Cell *search(const std::string &id) const { ESM::Cell cell; cell.mName = Misc::StringUtils::lowerCase(id); From ddd6e682bcf2bae8b8447b1203a2f5b8792ee3fc Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 9 Jan 2015 04:19:38 +0100 Subject: [PATCH 0232/3725] Dialogue: add conflict resolution for overlapping keywords (Fixes #2245) --- apps/openmw/mwdialogue/hypertextparser.cpp | 10 +++-- apps/openmw/mwdialogue/keywordsearch.hpp | 47 ++++++++++++++++++---- apps/openmw/mwgui/dialogue.cpp | 9 +++-- apps/openmw/mwgui/journalviewmodel.cpp | 10 +++-- 4 files changed, 58 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwdialogue/hypertextparser.cpp b/apps/openmw/mwdialogue/hypertextparser.cpp index 776edac94..aa748e772 100644 --- a/apps/openmw/mwdialogue/hypertextparser.cpp +++ b/apps/openmw/mwdialogue/hypertextparser.cpp @@ -56,13 +56,17 @@ namespace MWDialogue keywordList.sort(Misc::StringUtils::ciLess); KeywordSearch keywordSearch; - KeywordSearch::Match match; for (std::list::const_iterator it = keywordList.begin(); it != keywordList.end(); ++it) keywordSearch.seed(*it, 0 /*unused*/); - for (std::string::const_iterator it = text.begin(); it != text.end() && keywordSearch.search(it, text.end(), match, text.begin()); it = match.mEnd) - tokens.push_back(Token(std::string(match.mBeg, match.mEnd), Token::ImplicitKeyword)); + std::vector::Match> matches; + keywordSearch.highlightKeywords(text.begin(), text.end(), matches); + + for (std::vector::Match>::const_iterator it = matches.begin(); it != matches.end(); ++it) + { + tokens.push_back(Token(std::string(it->mBeg, it->mEnd), Token::ImplicitKeyword)); + } } size_t removePseudoAsterisks(std::string & phrase) diff --git a/apps/openmw/mwdialogue/keywordsearch.hpp b/apps/openmw/mwdialogue/keywordsearch.hpp index 51508890c..5ce492441 100644 --- a/apps/openmw/mwdialogue/keywordsearch.hpp +++ b/apps/openmw/mwdialogue/keywordsearch.hpp @@ -66,19 +66,20 @@ public: return false; } - bool search (Point beg, Point end, Match & match, Point start) + void highlightKeywords (Point beg, Point end, std::vector& out) { for (Point i = beg; i != end; ++i) { // check if previous character marked start of new word - if (i != start) + if (i != beg) { Point prev = i; - --prev; + --prev; if(isalpha(*prev)) continue; } + // check first character typename Entry::childen_t::iterator candidate = mRoot.mChildren.find (std::tolower (*i, mLocale)); @@ -137,16 +138,48 @@ public: if (t != candidate->second.mKeyword.end ()) continue; - // we did it, report the good news + // found a keyword, but there might still be longer keywords that start somewhere _within_ this keyword + // we will resolve these overlapping keywords later, choosing the longest one in case of conflict + Match match; match.mValue = candidate->second.mValue; match.mBeg = i; match.mEnd = k; - return true; + out.push_back(match); + break; } } - // no match in range, report the bad news - return false; + // resolve overlapping keywords + for (typename std::vector::iterator it = out.begin(); it != out.end();) + { + typename std::vector::iterator next = it; + ++next; + + if (next == out.end()) + break; + + if (it->mEnd <= next->mBeg) + { + ++it; + continue; // no overlap + } + else + { + // prefer the longer keyword + int size = it->mEnd - it->mBeg; + int nextSize = next->mEnd - next->mBeg; + if (size >= nextSize) // if both are the same length, then prefer the first keyword + { + out.erase(next); + continue; + } + else + { + it = out.erase(it); + continue; + } + } + } } private: diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index e1e016714..db9fa9f6b 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -177,11 +177,13 @@ namespace MWGui } else { - std::string::const_iterator i = text.begin (); - KeywordSearchT::Match match; + std::vector matches; + keywordSearch->highlightKeywords(text.begin(), text.end(), matches); - while (i != text.end () && keywordSearch->search (i, text.end (), match, text.begin ())) + std::string::const_iterator i = text.begin (); + for (std::vector::iterator it = matches.begin(); it != matches.end(); ++it) { + KeywordSearchT::Match match = *it; if (i != match.mBeg) addTopicLink (typesetter, 0, i - text.begin (), match.mBeg - text.begin ()); @@ -189,7 +191,6 @@ namespace MWGui i = match.mEnd; } - if (i != text.end ()) addTopicLink (typesetter, 0, i - text.begin (), text.size ()); } diff --git a/apps/openmw/mwgui/journalviewmodel.cpp b/apps/openmw/mwgui/journalviewmodel.cpp index 059af463f..add2ac62c 100644 --- a/apps/openmw/mwgui/journalviewmodel.cpp +++ b/apps/openmw/mwgui/journalviewmodel.cpp @@ -174,12 +174,14 @@ struct JournalViewModelImpl : JournalViewModel } else { - std::string::const_iterator i = utf8text.begin (); - - KeywordSearchT::Match match; + std::vector matches; + mModel->mKeywordSearch.highlightKeywords(utf8text.begin(), utf8text.end(), matches); - while (i != utf8text.end () && mModel->mKeywordSearch.search (i, utf8text.end (), match, utf8text.begin())) + std::string::const_iterator i = utf8text.begin (); + for (std::vector::const_iterator it = matches.begin(); it != matches.end(); ++it) { + const KeywordSearchT::Match& match = *it; + if (i != match.mBeg) visitor (0, i - utf8text.begin (), match.mBeg - utf8text.begin ()); From 65ab31eae6d069a9f835f637dc507780116e83b8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 9 Jan 2015 04:31:02 +0100 Subject: [PATCH 0233/3725] Remove now redundant Store::setUp implementation --- apps/openmw/mwworld/store.hpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index 71e77d0c7..f3a5aad11 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -217,9 +217,6 @@ namespace MWWorld } void setUp() { - // remove the dynamic part of mShared - if (mShared.size() > mStatic.size()) - mShared.erase(mShared.begin() + mStatic.size(), mShared.end()); } iterator begin() const { From 7fe2f86d06237a6f9d8f4c4289cec8e0143fc6b7 Mon Sep 17 00:00:00 2001 From: dteviot Date: Fri, 9 Jan 2015 21:40:53 +1300 Subject: [PATCH 0234/3725] Slaughter fish attacks when player only knee deep in water (Fixes #2076) --- apps/openmw/mwbase/world.hpp | 1 + apps/openmw/mwclass/creature.cpp | 6 +++--- apps/openmw/mwmechanics/actors.cpp | 4 ++-- apps/openmw/mwmechanics/aicombat.cpp | 2 +- apps/openmw/mwworld/class.cpp | 10 ++++++++++ apps/openmw/mwworld/class.hpp | 2 ++ apps/openmw/mwworld/physicssystem.cpp | 4 ++-- apps/openmw/mwworld/worldimp.cpp | 27 ++++++++++++++++++--------- apps/openmw/mwworld/worldimp.hpp | 4 ++++ 9 files changed, 43 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index cdfdfc358..7432db734 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -392,6 +392,7 @@ namespace MWBase virtual bool isFlying(const MWWorld::Ptr &ptr) const = 0; virtual bool isSlowFalling(const MWWorld::Ptr &ptr) const = 0; virtual bool isSwimming(const MWWorld::Ptr &object) const = 0; + virtual bool isWading(const MWWorld::Ptr &object) const = 0; ///Is the head of the creature underwater? virtual bool isSubmerged(const MWWorld::Ptr &object) const = 0; virtual bool isUnderwater(const MWWorld::CellStore* cell, const Ogre::Vector3 &pos) const = 0; diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 2146fdfde..e21676f10 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -348,9 +348,9 @@ namespace MWClass // Self defense bool setOnPcHitMe = true; // Note OnPcHitMe is not set for friendly hits. - if ((canWalk(ptr) || canFly(ptr) || canSwim(ptr)) // No retaliation for totally static creatures - // (they have no movement or attacks anyway) - && !attacker.isEmpty()) + + // No retaliation for totally static creatures (they have no movement or attacks anyway) + if (isMobile(ptr) && !attacker.isEmpty()) { setOnPcHitMe = MWBase::Environment::get().getMechanicsManager()->actorAttacked(ptr, attacker); } diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index c0fc80692..0a25ddd42 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -309,8 +309,8 @@ namespace MWMechanics // pure water creatures won't try to fight with the target on the ground // except that creature is already hostile if ((againstPlayer || !creatureStats.getAiSequence().isInCombat()) - && ((actor1.getClass().canSwim(actor1) && !actor1.getClass().canWalk(actor1) // pure water creature - && !MWBase::Environment::get().getWorld()->isSwimming(actor2)) + && ((actor1.getClass().isPureWaterCreature(actor1) + && !MWBase::Environment::get().getWorld()->isWading(actor2)) || (!actor1.getClass().canSwim(actor1) && MWBase::Environment::get().getWorld()->isSwimming(actor2)))) // creature can't swim to target return; diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 5d0470554..ce5963a91 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -209,7 +209,7 @@ namespace MWMechanics if (!actorClass.isNpc() && // 1. pure water creature and Player moved out of water ((target == world->getPlayerPtr() && - actorClass.canSwim(actor) && !actor.getClass().canWalk(actor) && !world->isSwimming(target)) + actorClass.isPureWaterCreature(actor) && !world->isWading(target)) // 2. creature can't swim to target || (!actorClass.canSwim(actor) && world->isSwimming(target)))) { diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 61c597517..939b72ddb 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -383,6 +383,16 @@ namespace MWWorld return false; } + bool Class::isPureWaterCreature(const MWWorld::Ptr& ptr) const + { + return canSwim(ptr) && !canWalk(ptr); + } + + bool Class::isMobile(const MWWorld::Ptr& ptr) const + { + return canSwim(ptr) || canWalk(ptr) || canFly(ptr); + } + int Class::getSkill(const MWWorld::Ptr& ptr, int skill) const { throw std::runtime_error("class does not support skills"); diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index cc18d830c..b738cdd44 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -308,6 +308,8 @@ namespace MWWorld virtual bool canFly(const MWWorld::Ptr& ptr) const; virtual bool canSwim(const MWWorld::Ptr& ptr) const; virtual bool canWalk(const MWWorld::Ptr& ptr) const; + bool isPureWaterCreature(const MWWorld::Ptr& ptr) const; + bool isMobile(const MWWorld::Ptr& ptr) const; virtual int getSkill(const MWWorld::Ptr& ptr, int skill) const; diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 3a7aa0490..5b712648c 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -281,7 +281,7 @@ namespace MWWorld // Early-out for totally static creatures // (Not sure if gravity should still apply?) - if (!ptr.getClass().canWalk(ptr) && !ptr.getClass().canFly(ptr) && !ptr.getClass().canSwim(ptr)) + if (!ptr.getClass().isMobile(ptr)) return position; OEngine::Physic::PhysicActor *physicActor = engine->getCharacter(ptr.getRefData().getHandle()); @@ -434,7 +434,7 @@ namespace MWWorld if(result) { // don't let pure water creatures move out of water after stepMove - if((ptr.getClass().canSwim(ptr) && !ptr.getClass().canWalk(ptr)) + if (ptr.getClass().isPureWaterCreature(ptr) && newPosition.z > (waterlevel - halfExtents.z * 0.5)) newPosition = oldPosition; } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index a939a6db9..b99b4ff24 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1978,25 +1978,34 @@ namespace MWWorld bool World::isSubmerged(const MWWorld::Ptr &object) const { - const float *fpos = object.getRefData().getPosition().pos; - Ogre::Vector3 pos(fpos[0], fpos[1], fpos[2]); - - const OEngine::Physic::PhysicActor *actor = mPhysEngine->getCharacter(object.getRefData().getHandle()); - if(actor) pos.z += 1.85*actor->getHalfExtents().z; - - return isUnderwater(object.getCell(), pos); + return isUnderwater(object, 1.85f); } bool World::isSwimming(const MWWorld::Ptr &object) const { /// \todo add check ifActor() - only actors can swim + /// \fixme 3/4ths submerged? + return isUnderwater(object, 1.5f); + } + + bool + World::isWading(const MWWorld::Ptr &object) const + { + return isUnderwater(object, 0.5f); + } + + bool + World::isUnderwater(const MWWorld::Ptr &object, const float hightRatio) const + { const float *fpos = object.getRefData().getPosition().pos; Ogre::Vector3 pos(fpos[0], fpos[1], fpos[2]); - /// \fixme 3/4ths submerged? const OEngine::Physic::PhysicActor *actor = mPhysEngine->getCharacter(object.getRefData().getHandle()); - if(actor) pos.z += actor->getHalfExtents().z * 1.5; + if (actor) + { + pos.z += hightRatio*actor->getHalfExtents().z; + } return isUnderwater(object.getCell(), pos); } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 5810fe42f..708a9abc3 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -139,6 +139,9 @@ namespace MWWorld void loadContentFiles(const Files::Collections& fileCollections, const std::vector& content, ContentLoader& contentLoader); + bool isUnderwater(const MWWorld::Ptr &object, const float hightRatio) const; + ///< helper function for implementing isSwimming(), isSubmerged(), isWading() + bool mTeleportEnabled; bool mLevitationEnabled; bool mGoToJail; @@ -454,6 +457,7 @@ namespace MWWorld virtual bool isSubmerged(const MWWorld::Ptr &object) const; virtual bool isSwimming(const MWWorld::Ptr &object) const; virtual bool isUnderwater(const MWWorld::CellStore* cell, const Ogre::Vector3 &pos) const; + virtual bool isWading(const MWWorld::Ptr &object) const; virtual bool isOnGround(const MWWorld::Ptr &ptr) const; virtual void togglePOV() { From 64cd1396ac0fcd9f18143dbdf142379b907a4e1f Mon Sep 17 00:00:00 2001 From: dteviot Date: Fri, 9 Jan 2015 22:17:53 +1300 Subject: [PATCH 0235/3725] Fixed minor issues. 1. Renamed "hightRatio" to "heightRatio". 2. Replaced magic numbers with named constants. --- apps/openmw/mwworld/worldimp.cpp | 10 ++++++---- apps/openmw/mwworld/worldimp.hpp | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index b99b4ff24..f9642226b 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1978,7 +1978,8 @@ namespace MWWorld bool World::isSubmerged(const MWWorld::Ptr &object) const { - return isUnderwater(object, 1.85f); + const float neckDeep = 1.85f; + return isUnderwater(object, neckDeep); } bool @@ -1992,11 +1993,12 @@ namespace MWWorld bool World::isWading(const MWWorld::Ptr &object) const { - return isUnderwater(object, 0.5f); + const float kneeDeep = 0.5f; + return isUnderwater(object, kneeDeep); } bool - World::isUnderwater(const MWWorld::Ptr &object, const float hightRatio) const + World::isUnderwater(const MWWorld::Ptr &object, const float heightRatio) const { const float *fpos = object.getRefData().getPosition().pos; Ogre::Vector3 pos(fpos[0], fpos[1], fpos[2]); @@ -2004,7 +2006,7 @@ namespace MWWorld const OEngine::Physic::PhysicActor *actor = mPhysEngine->getCharacter(object.getRefData().getHandle()); if (actor) { - pos.z += hightRatio*actor->getHalfExtents().z; + pos.z += heightRatio*actor->getHalfExtents().z; } return isUnderwater(object.getCell(), pos); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 708a9abc3..dfaa9f789 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -139,7 +139,7 @@ namespace MWWorld void loadContentFiles(const Files::Collections& fileCollections, const std::vector& content, ContentLoader& contentLoader); - bool isUnderwater(const MWWorld::Ptr &object, const float hightRatio) const; + bool isUnderwater(const MWWorld::Ptr &object, const float heightRatio) const; ///< helper function for implementing isSwimming(), isSubmerged(), isWading() bool mTeleportEnabled; From e32402a0402be2bb36754fe2b718aa384df54726 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 9 Jan 2015 12:05:16 +0100 Subject: [PATCH 0236/3725] handle moved references on load --- apps/opencs/model/world/ref.cpp | 10 ++++++++++ apps/opencs/model/world/ref.hpp | 5 +++++ apps/opencs/model/world/refcollection.cpp | 14 ++++++++++++-- 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/world/ref.cpp b/apps/opencs/model/world/ref.cpp index f3c1b0b73..63594acc8 100644 --- a/apps/opencs/model/world/ref.cpp +++ b/apps/opencs/model/world/ref.cpp @@ -1,8 +1,18 @@ #include "ref.hpp" +#include + CSMWorld::CellRef::CellRef() { mRefNum.mIndex = 0; mRefNum.mContentFile = 0; +} + +std::pair CSMWorld::CellRef::getCellIndex() const +{ + const int cellSize = 8192; + + return std::make_pair ( + std::floor (mPos.pos[0]/cellSize), std::floor (mPos.pos[1]/cellSize)); } \ No newline at end of file diff --git a/apps/opencs/model/world/ref.hpp b/apps/opencs/model/world/ref.hpp index 411024691..dae9488f0 100644 --- a/apps/opencs/model/world/ref.hpp +++ b/apps/opencs/model/world/ref.hpp @@ -1,6 +1,8 @@ #ifndef CSM_WOLRD_REF_H #define CSM_WOLRD_REF_H +#include + #include namespace CSMWorld @@ -15,6 +17,9 @@ namespace CSMWorld std::string mOriginalCell; CellRef(); + + /// Calculate cell index based on coordinates (x and y) + std::pair getCellIndex() const; }; } diff --git a/apps/opencs/model/world/refcollection.cpp b/apps/opencs/model/world/refcollection.cpp index 1a0dd1e5b..19dfae57d 100644 --- a/apps/opencs/model/world/refcollection.cpp +++ b/apps/opencs/model/world/refcollection.cpp @@ -24,9 +24,19 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool while (ESM::Cell::getNextRef (reader, ref, deleted)) { ref.mOriginalCell = cell2.mId; - ref.mCell = cell2.mId; - /// \todo handle moved references + if (cell.get().isExterior()) + { + // ignoring moved references sub-record; instead calculate cell from coordinates + std::pair index = ref.getCellIndex(); + + std::ostringstream stream; + stream << "#" << index.first << " " << index.second; + + ref.mCell = stream.str(); + } + else + ref.mCell = cell2.mId; std::map::iterator iter = cache.find (ref.mRefNum); From ce2cbab4025204ccf643d6ef1ecd4dc4e18bad35 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 9 Jan 2015 20:08:52 +0100 Subject: [PATCH 0237/3725] Dialogue: improve conflict resolution for chains of overlapping keywords (unit test for such a case will follow) --- apps/openmw/mwdialogue/keywordsearch.hpp | 59 +++++++++++++++--------- 1 file changed, 37 insertions(+), 22 deletions(-) diff --git a/apps/openmw/mwdialogue/keywordsearch.hpp b/apps/openmw/mwdialogue/keywordsearch.hpp index 5ce492441..c44139f32 100644 --- a/apps/openmw/mwdialogue/keywordsearch.hpp +++ b/apps/openmw/mwdialogue/keywordsearch.hpp @@ -66,8 +66,14 @@ public: return false; } + static bool sortMatches(const Match& left, const Match& right) + { + return left.mBeg < right.mBeg; + } + void highlightKeywords (Point beg, Point end, std::vector& out) { + std::vector matches; for (Point i = beg; i != end; ++i) { // check if previous character marked start of new word @@ -144,42 +150,51 @@ public: match.mValue = candidate->second.mValue; match.mBeg = i; match.mEnd = k; - out.push_back(match); + matches.push_back(match); break; } } // resolve overlapping keywords - for (typename std::vector::iterator it = out.begin(); it != out.end();) + while (matches.size()) { - typename std::vector::iterator next = it; - ++next; - - if (next == out.end()) - break; - - if (it->mEnd <= next->mBeg) - { - ++it; - continue; // no overlap - } - else + int longestKeywordSize = 0; + typename std::vector::iterator longestKeyword; + for (typename std::vector::iterator it = matches.begin(); it != matches.end(); ++it) { - // prefer the longer keyword int size = it->mEnd - it->mBeg; - int nextSize = next->mEnd - next->mBeg; - if (size >= nextSize) // if both are the same length, then prefer the first keyword + if (size > longestKeywordSize) { - out.erase(next); - continue; + longestKeywordSize = size; + longestKeyword = it; } - else + + typename std::vector::iterator next = it; + ++next; + + if (next == matches.end()) + break; + + if (it->mEnd <= next->mBeg) { - it = out.erase(it); - continue; + break; // no overlap } } + + Match keyword = *longestKeyword; + matches.erase(longestKeyword); + out.push_back(keyword); + // erase anything that overlaps with the keyword we just added to the output + for (typename std::vector::iterator it = matches.begin(); it != matches.end();) + { + if (it->mBeg < keyword.mEnd && it->mEnd > keyword.mBeg) + it = matches.erase(it); + else + ++it; + } } + + std::sort(out.begin(), out.end(), sortMatches); } private: From 9d07edda1394b479a5bf6bf6b751fc4ba073622c Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 9 Jan 2015 20:48:36 +0100 Subject: [PATCH 0238/3725] UnitTests: remove GMock which wasn't used anyway, and the gmock headers fail to compile together with gtest on ubuntu 14.04 --- CMakeLists.txt | 2 +- apps/openmw_test_suite/CMakeLists.txt | 11 +-- apps/openmw_test_suite/openmw_test_suite.cpp | 12 +-- cmake/FindGMock.cmake | 91 -------------------- 4 files changed, 6 insertions(+), 110 deletions(-) delete mode 100644 cmake/FindGMock.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 323b743bc..60c37d0f5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -61,7 +61,7 @@ option(BUILD_MWINIIMPORTER "build MWiniImporter" ON) option(BUILD_OPENCS "build OpenMW Construction Set" ON) option(BUILD_WIZARD "build Installation Wizard" ON) option(BUILD_WITH_CODE_COVERAGE "Enable code coverage with gconv" OFF) -option(BUILD_UNITTESTS "Enable Unittests with Google C++ Unittest and GMock frameworks" OFF) +option(BUILD_UNITTESTS "Enable Unittests with Google C++ Unittest" OFF) option(BUILD_NIFTEST "build nif file tester" OFF) option(BUILD_MYGUI_PLUGIN "build MyGUI plugin for OpenMW resources, to use with MyGUI tools" ON) diff --git a/apps/openmw_test_suite/CMakeLists.txt b/apps/openmw_test_suite/CMakeLists.txt index 9fe7890ac..44354eac8 100644 --- a/apps/openmw_test_suite/CMakeLists.txt +++ b/apps/openmw_test_suite/CMakeLists.txt @@ -1,14 +1,7 @@ -# TODO: This should not be needed, check how it was done in FindGTEST -set(GMOCK_ROOT "/usr/include") -set(GMOCK_BUILD "/usr/lib") - find_package(GTest REQUIRED) -find_package(GMock REQUIRED) - -if (GTEST_FOUND AND GMOCK_FOUND) +if (GTEST_FOUND) include_directories(${GTEST_INCLUDE_DIRS}) - include_directories(${GMOCK_INCLUDE_DIRS}) file(GLOB UNITTEST_SRC_FILES components/misc/test_*.cpp @@ -18,7 +11,7 @@ if (GTEST_FOUND AND GMOCK_FOUND) add_executable(openmw_test_suite openmw_test_suite.cpp ${UNITTEST_SRC_FILES}) - target_link_libraries(openmw_test_suite ${GMOCK_BOTH_LIBRARIES} ${GTEST_BOTH_LIBRARIES} components) + target_link_libraries(openmw_test_suite ${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/openmw_test_suite.cpp b/apps/openmw_test_suite/openmw_test_suite.cpp index 81476325e..7cc76b25b 100644 --- a/apps/openmw_test_suite/openmw_test_suite.cpp +++ b/apps/openmw_test_suite/openmw_test_suite.cpp @@ -1,12 +1,6 @@ -#include #include - -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) = false; - ::testing::InitGoogleMock(&argc, argv); - - return RUN_ALL_TESTS(); +GTEST_API_ int main(int argc, char **argv) { + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); } diff --git a/cmake/FindGMock.cmake b/cmake/FindGMock.cmake deleted file mode 100644 index eda7d4d72..000000000 --- a/cmake/FindGMock.cmake +++ /dev/null @@ -1,91 +0,0 @@ -# Locate the Google C++ Mocking Framework. -# -# Defines the following variables: -# -# GMOCK_FOUND - Found the Google Mocking framework -# GMOCK_INCLUDE_DIRS - Include directories -# -# Also defines the library variables below as normal -# variables. These contain debug/optimized keywords when -# a debugging library is found. -# -# GMOCK_BOTH_LIBRARIES - Both libgmock & libgmock-main -# GMOCK_LIBRARIES - libgmock -# GMOCK_MAIN_LIBRARIES - libgmock-main -# -# Accepts the following variables as input: -# -# GMOCK_ROOT - (as CMake or env. variable) -# The root directory of the gmock install prefix -# -#----------------------- -# Example Usage: -# -# enable_testing(true) -# find_package(GMock REQUIRED) -# include_directories(${GMOCK_INCLUDE_DIRS}) -# -# add_executable(foo foo.cc) -# target_link_libraries(foo ${GMOCK_BOTH_LIBRARIES}) -# -# add_test(AllTestsInFoo foo) -# - -#set (GMOCK_FOUND FALSE) - - -#set (GMOCK_ROOT $ENV{GMOCK_ROOT} CACHE PATH "Path to the gmock root directory.") -if (NOT EXISTS ${GMOCK_ROOT}) - message (FATAL_ERROR "GMOCK_ROOT does not exist.") -endif () - -#set (GMOCK_BUILD ${GMOCK_ROOT}/build CACHE PATH "Path to the gmock build directory.") -if (NOT EXISTS ${GMOCK_BUILD}) - message (FATAL_ERROR "GMOCK_BUILD does not exist.") -endif () - -# Find the include directory -find_path(GMOCK_INCLUDE_DIRS gmock/gmock.h - HINTS - $ENV{GMOCK_ROOT}/include - ${GMOCK_ROOT}/include -) -mark_as_advanced(GMOCK_INCLUDE_DIRS) - -function(_gmock_find_library _name) - find_library(${_name} - NAMES ${ARGN} - HINTS - $ENV{GMOCK_BUILD} - ${GMOCK_BUILD} - ) - mark_as_advanced(${_name}) -endfunction() - -# Find the gmock libraries -if (MSVC) - _gmock_find_library (GMOCK_LIBRARIES_DEBUG gmock ${GMOCK_BUILD}/Debug) - _gmock_find_library (GMOCK_LIBRARIES_RELEASE gmock ${GMOCK_BUILD}/Release) - _gmock_find_library (GMOCK_MAIN_LIBRARIES_DEBUG gmock_main ${GMOCK_BUILD}/Debug) - _gmock_find_library (GMOCK_MAIN_LIBRARIES_RELEASE gmock_main ${GMOCK_BUILD}/Release) - set (GMOCK_LIBRARIES - debug ${GMOCK_LIBRARIES_DEBUG} - optimized ${GMOCK_LIBRARIES_RELEASE} - ) - set (GMOCK_MAIN_LIBRARIES - debug ${GMOCK_MAIN_LIBRARIES_DEBUG} - optimized ${GMOCK_MAIN_LIBRARIES_RELEASE} - ) -else () - _gmock_find_library (GMOCK_LIBRARIES gmock ${GMOCK_BUILD}) - _gmock_find_library (GMOCK_MAIN_LIBRARIES gmock_main ${GMOCK_BUILD} ${GMOCK_BUILD}/Debug) -endif () - -FIND_PACKAGE_HANDLE_STANDARD_ARGS(GMock DEFAULT_MSG GMOCK_LIBRARIES GMOCK_INCLUDE_DIRS GMOCK_MAIN_LIBRARIES) - -if(GMOCK_FOUND) - set(GMOCK_INCLUDE_DIRS ${GMOCK_INCLUDE_DIR}) - set(GMOCK_BOTH_LIBRARIES ${GMOCK_LIBRARIES} ${GMOCK_MAIN_LIBRARIES}) -endif() - - From 1b302b750cca4b6f88cb4794b97739acc140480c Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 9 Jan 2015 20:52:31 +0100 Subject: [PATCH 0239/3725] UnitTests: add tests for KeywordSearch conflict resolution --- apps/openmw_test_suite/CMakeLists.txt | 1 + .../mwdialogue/test_keywordsearch.cpp | 48 +++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 apps/openmw_test_suite/mwdialogue/test_keywordsearch.cpp diff --git a/apps/openmw_test_suite/CMakeLists.txt b/apps/openmw_test_suite/CMakeLists.txt index 44354eac8..2ffb7ffa0 100644 --- a/apps/openmw_test_suite/CMakeLists.txt +++ b/apps/openmw_test_suite/CMakeLists.txt @@ -5,6 +5,7 @@ if (GTEST_FOUND) file(GLOB UNITTEST_SRC_FILES components/misc/test_*.cpp + mwdialogue/test_*.cpp ) source_group(apps\\openmw_test_suite FILES openmw_test_suite.cpp ${UNITTEST_SRC_FILES}) diff --git a/apps/openmw_test_suite/mwdialogue/test_keywordsearch.cpp b/apps/openmw_test_suite/mwdialogue/test_keywordsearch.cpp new file mode 100644 index 000000000..c8ea9d01c --- /dev/null +++ b/apps/openmw_test_suite/mwdialogue/test_keywordsearch.cpp @@ -0,0 +1,48 @@ +#include +#include "apps/openmw/mwdialogue/keywordsearch.hpp" + +struct KeywordSearchTest : public ::testing::Test +{ + protected: + virtual void SetUp() + { + } + + virtual void TearDown() + { + } +}; + +TEST_F(KeywordSearchTest, keyword_test_conflict_resolution) +{ + // test to make sure the longest keyword in a chain of conflicting keywords gets chosen + MWDialogue::KeywordSearch search; + search.seed("foo bar", 0); + search.seed("bar lock", 0); + search.seed("lock switch", 0); + + std::string text = "foo bar lock switch"; + + std::vector::Match> matches; + search.highlightKeywords(text.begin(), text.end(), matches); + + // Should contain: "foo bar", "lock switch" + ASSERT_TRUE (matches.size() == 2); + ASSERT_TRUE (std::string(matches.front().mBeg, matches.front().mEnd) == "foo bar"); + ASSERT_TRUE (std::string(matches.rbegin()->mBeg, matches.rbegin()->mEnd) == "lock switch"); +} + +TEST_F(KeywordSearchTest, keyword_test_conflict_resolution2) +{ + MWDialogue::KeywordSearch search; + search.seed("the dwemer", 0); + search.seed("dwemer language", 0); + + std::string text = "the dwemer language"; + + std::vector::Match> matches; + search.highlightKeywords(text.begin(), text.end(), matches); + + ASSERT_TRUE (matches.size() == 1); + ASSERT_TRUE (std::string(matches.front().mBeg, matches.front().mEnd) == "dwemer language"); +} From dfdf26e95e93981f4fa6ff0b3a0de0215d89266e Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 9 Jan 2015 20:58:53 +0100 Subject: [PATCH 0240/3725] Add assertion to Store --- apps/openmw/mwworld/store.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index f3a5aad11..d9e4285fe 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -140,8 +140,8 @@ namespace MWWorld virtual void clearDynamic() { // remove the dynamic part of mShared - if (mShared.size() > mStatic.size()) - mShared.erase(mShared.begin() + mStatic.size(), mShared.end()); + assert(mShared.size() >= mStatic.size()); + mShared.erase(mShared.begin() + mStatic.size(), mShared.end()); mDynamic.clear(); } @@ -304,8 +304,8 @@ namespace MWWorld mDynamic.erase(it); // have to reinit the whole shared part - if (mShared.size() > mStatic.size()) - mShared.erase(mShared.begin() + mStatic.size(), mShared.end()); + assert(mShared.size() >= mStatic.size()); + mShared.erase(mShared.begin() + mStatic.size(), mShared.end()); for (it = mDynamic.begin(); it != mDynamic.end(); ++it) { mShared.push_back(&it->second); } From efbc8742a03b9037f465ce6bb350f9a4675bb34a Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 9 Jan 2015 21:13:57 +0100 Subject: [PATCH 0241/3725] Remove some unnecessary includes --- components/misc/stringops.cpp | 9 --------- 1 file changed, 9 deletions(-) diff --git a/components/misc/stringops.cpp b/components/misc/stringops.cpp index 0f801e554..723c1c1e0 100644 --- a/components/misc/stringops.cpp +++ b/components/misc/stringops.cpp @@ -1,14 +1,5 @@ #include "stringops.hpp" -#include -#include -#include - -#include -#include - - - namespace Misc { From 2ac23008f5eec975f444a2cd72cba49745d1c579 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 10 Jan 2015 00:07:40 +0100 Subject: [PATCH 0242/3725] Remove an old workaround (Fixes #2263) The workaround was added when we were still using OIS for input. It doesn't seem to be needed with SDL. --- apps/openmw/mwinput/inputmanagerimp.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 2f6149f09..ece189c75 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -409,8 +409,7 @@ namespace MWInput if (mControlSwitch["playerviewswitch"]) { - // work around preview mode toggle when pressing Alt+Tab - if (actionIsActive(A_TogglePOV) && !mInputManager->isModifierHeld(SDL_Keymod(KMOD_ALT))) { + if (actionIsActive(A_TogglePOV)) { if (mPreviewPOVDelay <= 0.5 && (mPreviewPOVDelay += dt) > 0.5) { From 66e7e0480717164fabbd4aae1e5190771db85d0c Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 10 Jan 2015 00:26:13 +0100 Subject: [PATCH 0243/3725] UnitTests: add another dialogue keyword test --- .../mwdialogue/test_keywordsearch.cpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/apps/openmw_test_suite/mwdialogue/test_keywordsearch.cpp b/apps/openmw_test_suite/mwdialogue/test_keywordsearch.cpp index c8ea9d01c..e0e1871d2 100644 --- a/apps/openmw_test_suite/mwdialogue/test_keywordsearch.cpp +++ b/apps/openmw_test_suite/mwdialogue/test_keywordsearch.cpp @@ -46,3 +46,22 @@ TEST_F(KeywordSearchTest, keyword_test_conflict_resolution2) ASSERT_TRUE (matches.size() == 1); ASSERT_TRUE (std::string(matches.front().mBeg, matches.front().mEnd) == "dwemer language"); } + + +TEST_F(KeywordSearchTest, keyword_test_conflict_resolution3) +{ + // testing that the longest keyword is chosen, rather than maximizing the + // amount of highlighted characters by highlighting the first and last keyword + MWDialogue::KeywordSearch search; + search.seed("foo bar", 0); + search.seed("bar lock", 0); + search.seed("lock so", 0); + + std::string text = "foo bar lock so"; + + std::vector::Match> matches; + search.highlightKeywords(text.begin(), text.end(), matches); + + ASSERT_TRUE (matches.size() == 1); + ASSERT_TRUE (std::string(matches.front().mBeg, matches.front().mEnd) == "bar lock"); +} From eb99ed697b0029f0e54ce915428c966478b4f92f Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 10 Jan 2015 01:00:52 +0100 Subject: [PATCH 0244/3725] Reduce includes --- apps/openmw/mwgui/alchemywindow.cpp | 27 +++++++++++++------------ apps/openmw/mwgui/alchemywindow.hpp | 9 ++++++--- apps/openmw/mwgui/charactercreation.cpp | 18 +++++++++++------ apps/openmw/mwgui/charactercreation.hpp | 5 +++-- apps/openmw/mwgui/travelwindow.hpp | 4 +++- apps/openmw/mwgui/videowidget.cpp | 19 +++++++++-------- apps/openmw/mwgui/videowidget.hpp | 7 +++++-- apps/openmw/mwworld/class.hpp | 1 - apps/openmw/mwworld/containerstore.hpp | 1 + apps/openmw/mwworld/esmloader.hpp | 6 +++++- apps/openmw/mwworld/ptr.hpp | 2 +- 11 files changed, 61 insertions(+), 38 deletions(-) diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index bb201e2dd..1715c49f8 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -1,7 +1,6 @@ #include "alchemywindow.hpp" #include -#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -9,6 +8,7 @@ #include "../mwbase/windowmanager.hpp" #include "../mwmechanics/magiceffects.hpp" +#include "../mwmechanics/alchemy.hpp" #include "../mwworld/class.hpp" #include "../mwworld/esmstore.hpp" @@ -27,6 +27,7 @@ namespace MWGui , mApparatus (4) , mIngredients (4) , mSortModel(NULL) + , mAlchemy(new MWMechanics::Alchemy()) { getWidget(mCreateButton, "CreateButton"); getWidget(mCancelButton, "CancelButton"); @@ -66,7 +67,7 @@ namespace MWGui std::string name = mNameEdit->getCaption(); boost::algorithm::trim(name); - MWMechanics::Alchemy::Result result = mAlchemy.create (mNameEdit->getCaption ()); + MWMechanics::Alchemy::Result result = mAlchemy->create (mNameEdit->getCaption ()); if (result == MWMechanics::Alchemy::Result_NoName) { @@ -121,7 +122,7 @@ namespace MWGui void AlchemyWindow::open() { - mAlchemy.setAlchemist (MWBase::Environment::get().getWorld()->getPlayerPtr()); + mAlchemy->setAlchemist (MWBase::Environment::get().getWorld()->getPlayerPtr()); InventoryItemModel* model = new InventoryItemModel(MWBase::Environment::get().getWorld()->getPlayerPtr()); mSortModel = new SortFilterItemModel(model); @@ -132,10 +133,10 @@ namespace MWGui int index = 0; - mAlchemy.setAlchemist (MWBase::Environment::get().getWorld()->getPlayerPtr()); + mAlchemy->setAlchemist (MWBase::Environment::get().getWorld()->getPlayerPtr()); - for (MWMechanics::Alchemy::TToolsIterator iter (mAlchemy.beginTools()); - iter!=mAlchemy.endTools() && index (mApparatus.size()); ++iter, ++index) + for (MWMechanics::Alchemy::TToolsIterator iter (mAlchemy->beginTools()); + iter!=mAlchemy->endTools() && index (mApparatus.size()); ++iter, ++index) { mApparatus.at (index)->setItem(*iter); mApparatus.at (index)->clearUserStrings(); @@ -150,7 +151,7 @@ namespace MWGui } void AlchemyWindow::exit() { - mAlchemy.clear(); + mAlchemy->clear(); MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Alchemy); MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Inventory); } @@ -164,7 +165,7 @@ namespace MWGui void AlchemyWindow::onSelectedItem(int index) { MWWorld::Ptr item = mSortModel->getItem(index).mBase; - int res = mAlchemy.addIngredient(item); + int res = mAlchemy->addIngredient(item); if (res != -1) { @@ -177,20 +178,20 @@ namespace MWGui void AlchemyWindow::update() { - std::string suggestedName = mAlchemy.suggestPotionName(); + std::string suggestedName = mAlchemy->suggestPotionName(); if (suggestedName != mSuggestedPotionName) mNameEdit->setCaptionWithReplacing(suggestedName); mSuggestedPotionName = suggestedName; mSortModel->clearDragItems(); - MWMechanics::Alchemy::TIngredientsIterator it = mAlchemy.beginIngredients (); + MWMechanics::Alchemy::TIngredientsIterator it = mAlchemy->beginIngredients (); for (int i=0; i<4; ++i) { ItemWidget* ingredient = mIngredients[i]; MWWorld::Ptr item; - if (it != mAlchemy.endIngredients ()) + if (it != mAlchemy->endIngredients ()) { item = *it; ++it; @@ -217,7 +218,7 @@ namespace MWGui mItemView->update(); - std::set effectIds = mAlchemy.listEffects(); + std::set effectIds = mAlchemy->listEffects(); Widgets::SpellEffectList list; for (std::set::iterator it = effectIds.begin(); it != effectIds.end(); ++it) { @@ -252,7 +253,7 @@ namespace MWGui { for (int i=0; i<4; ++i) if (mIngredients[i] == ingredient) - mAlchemy.removeIngredient (i); + mAlchemy->removeIngredient (i); update(); } diff --git a/apps/openmw/mwgui/alchemywindow.hpp b/apps/openmw/mwgui/alchemywindow.hpp index 36f540c1b..69fff8c67 100644 --- a/apps/openmw/mwgui/alchemywindow.hpp +++ b/apps/openmw/mwgui/alchemywindow.hpp @@ -3,11 +3,14 @@ #include -#include "../mwmechanics/alchemy.hpp" - #include "widgets.hpp" #include "windowbase.hpp" +namespace MWMechanics +{ + class Alchemy; +} + namespace MWGui { class ItemView; @@ -45,7 +48,7 @@ namespace MWGui void update(); - MWMechanics::Alchemy mAlchemy; + std::auto_ptr mAlchemy; std::vector mApparatus; std::vector mIngredients; diff --git a/apps/openmw/mwgui/charactercreation.cpp b/apps/openmw/mwgui/charactercreation.cpp index 33d0c4907..3df8da942 100644 --- a/apps/openmw/mwgui/charactercreation.cpp +++ b/apps/openmw/mwgui/charactercreation.cpp @@ -1,20 +1,26 @@ #include "charactercreation.hpp" -#include "textinput.hpp" -#include "race.hpp" -#include "class.hpp" -#include "birth.hpp" -#include "review.hpp" -#include "inventorywindow.hpp" #include + #include "../mwbase/environment.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" +#include "../mwbase/world.hpp" +#include "../mwbase/windowmanager.hpp" + #include "../mwmechanics/npcstats.hpp" + #include "../mwworld/class.hpp" #include "../mwworld/fallback.hpp" #include "../mwworld/esmstore.hpp" +#include "textinput.hpp" +#include "race.hpp" +#include "class.hpp" +#include "birth.hpp" +#include "review.hpp" +#include "inventorywindow.hpp" + namespace { struct Step diff --git a/apps/openmw/mwgui/charactercreation.hpp b/apps/openmw/mwgui/charactercreation.hpp index 03898093d..c2486c7f0 100644 --- a/apps/openmw/mwgui/charactercreation.hpp +++ b/apps/openmw/mwgui/charactercreation.hpp @@ -4,8 +4,9 @@ #include #include -#include "../mwbase/world.hpp" -#include "../mwbase/windowmanager.hpp" +#include + +#include "../mwmechanics/stat.hpp" namespace MWGui { diff --git a/apps/openmw/mwgui/travelwindow.hpp b/apps/openmw/mwgui/travelwindow.hpp index 3f1949256..3230f897f 100644 --- a/apps/openmw/mwgui/travelwindow.hpp +++ b/apps/openmw/mwgui/travelwindow.hpp @@ -1,7 +1,9 @@ #ifndef MWGUI_TravelWINDOW_H #define MWGUI_TravelWINDOW_H -#include "container.hpp" + +#include "windowbase.hpp" +#include "referenceinterface.hpp" namespace MyGUI { diff --git a/apps/openmw/mwgui/videowidget.cpp b/apps/openmw/mwgui/videowidget.cpp index f8054925b..2ade0f4c5 100644 --- a/apps/openmw/mwgui/videowidget.cpp +++ b/apps/openmw/mwgui/videowidget.cpp @@ -1,5 +1,7 @@ #include "videowidget.hpp" +#include + #include "../mwsound/movieaudiofactory.hpp" namespace MWGui @@ -7,40 +9,41 @@ namespace MWGui VideoWidget::VideoWidget() { + mPlayer.reset(new Video::VideoPlayer()); setNeedKeyFocus(true); } void VideoWidget::playVideo(const std::string &video) { - mPlayer.setAudioFactory(new MWSound::MovieAudioFactory()); - mPlayer.playVideo(video); + mPlayer->setAudioFactory(new MWSound::MovieAudioFactory()); + mPlayer->playVideo(video); - setImageTexture(mPlayer.getTextureName()); + setImageTexture(mPlayer->getTextureName()); } int VideoWidget::getVideoWidth() { - return mPlayer.getVideoWidth(); + return mPlayer->getVideoWidth(); } int VideoWidget::getVideoHeight() { - return mPlayer.getVideoHeight(); + return mPlayer->getVideoHeight(); } bool VideoWidget::update() { - return mPlayer.update(); + return mPlayer->update(); } void VideoWidget::stop() { - mPlayer.close(); + mPlayer->close(); } bool VideoWidget::hasAudioStream() { - return mPlayer.hasAudioStream(); + return mPlayer->hasAudioStream(); } } diff --git a/apps/openmw/mwgui/videowidget.hpp b/apps/openmw/mwgui/videowidget.hpp index 79e1c26bb..e350573c4 100644 --- a/apps/openmw/mwgui/videowidget.hpp +++ b/apps/openmw/mwgui/videowidget.hpp @@ -3,7 +3,10 @@ #include -#include +namespace Video +{ + class VideoPlayer; +} namespace MWGui { @@ -33,7 +36,7 @@ namespace MWGui void stop(); private: - Video::VideoPlayer mPlayer; + std::auto_ptr mPlayer; }; } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index cc18d830c..df9ca6a36 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -43,7 +43,6 @@ namespace ESM namespace MWWorld { - class Ptr; class ContainerStore; class InventoryStore; class PhysicsSystem; diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index 1863984b2..2849463c9 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -18,6 +18,7 @@ #include #include "ptr.hpp" +#include "cellreflist.hpp" namespace ESM { diff --git a/apps/openmw/mwworld/esmloader.hpp b/apps/openmw/mwworld/esmloader.hpp index d799c3f15..b96af707c 100644 --- a/apps/openmw/mwworld/esmloader.hpp +++ b/apps/openmw/mwworld/esmloader.hpp @@ -4,13 +4,17 @@ #include #include "contentloader.hpp" -#include "components/esm/esmreader.hpp" namespace ToUTF8 { class Utf8Encoder; } +namespace ESM +{ + class ESMReader; +} + namespace MWWorld { diff --git a/apps/openmw/mwworld/ptr.hpp b/apps/openmw/mwworld/ptr.hpp index 2f37a1cfd..4d928dacf 100644 --- a/apps/openmw/mwworld/ptr.hpp +++ b/apps/openmw/mwworld/ptr.hpp @@ -6,7 +6,7 @@ #include #include -#include "cellreflist.hpp" +#include "livecellref.hpp" namespace MWWorld { From 4b704f665fc33f1dbdc26138146d7bc3e377942b Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 10 Jan 2015 01:21:17 +0100 Subject: [PATCH 0245/3725] Reduce includes, move DragAndDrop to separate file --- apps/openmw/CMakeLists.txt | 1 + apps/openmw/mwgui/companionwindow.cpp | 2 +- apps/openmw/mwgui/container.cpp | 114 +--------------------- apps/openmw/mwgui/container.hpp | 19 ---- apps/openmw/mwgui/draganddrop.cpp | 130 +++++++++++++++++++++++++ apps/openmw/mwgui/draganddrop.hpp | 38 ++++++++ apps/openmw/mwgui/enchantingdialog.cpp | 1 - apps/openmw/mwgui/hud.cpp | 2 +- apps/openmw/mwgui/inventorywindow.cpp | 2 +- apps/openmw/mwgui/itemselection.hpp | 9 +- apps/openmw/mwgui/tradewindow.hpp | 3 +- apps/openmw/mwgui/windowbase.cpp | 4 +- apps/openmw/mwgui/windowmanagerimp.cpp | 2 + 13 files changed, 187 insertions(+), 140 deletions(-) create mode 100644 apps/openmw/mwgui/draganddrop.cpp create mode 100644 apps/openmw/mwgui/draganddrop.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 97ab13012..cb6cc301b 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -41,6 +41,7 @@ add_openmw_dir (mwgui itemmodel containeritemmodel inventoryitemmodel sortfilteritemmodel itemview tradeitemmodel companionitemmodel pickpocketitemmodel controllers savegamedialog recharge mode videowidget backgroundimage itemwidget screenfader debugwindow spellmodel spellview + draganddrop ) add_openmw_dir (mwdialogue diff --git a/apps/openmw/mwgui/companionwindow.cpp b/apps/openmw/mwgui/companionwindow.cpp index 2dd130b0d..c53e1697e 100644 --- a/apps/openmw/mwgui/companionwindow.cpp +++ b/apps/openmw/mwgui/companionwindow.cpp @@ -13,7 +13,7 @@ #include "itemview.hpp" #include "sortfilteritemmodel.hpp" #include "companionitemmodel.hpp" -#include "container.hpp" +#include "draganddrop.hpp" #include "countdialog.hpp" namespace MWGui diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index ee1d28592..85882ec13 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -24,123 +24,11 @@ #include "inventoryitemmodel.hpp" #include "sortfilteritemmodel.hpp" #include "pickpocketitemmodel.hpp" +#include "draganddrop.hpp" namespace MWGui { - DragAndDrop::DragAndDrop() - : mDraggedWidget(NULL) - , mDraggedCount(0) - , mSourceModel(NULL) - , mSourceView(NULL) - , mSourceSortModel(NULL) - , mIsOnDragAndDrop(false) - { - } - - void DragAndDrop::startDrag (int index, SortFilterItemModel* sortModel, ItemModel* sourceModel, ItemView* sourceView, int count) - { - mItem = sourceModel->getItem(index); - mDraggedCount = count; - mSourceModel = sourceModel; - mSourceView = sourceView; - mSourceSortModel = sortModel; - mIsOnDragAndDrop = true; - - // If picking up an item that isn't from the player's inventory, the item gets added to player inventory backend - // immediately, even though it's still floating beneath the mouse cursor. A bit counterintuitive, - // but this is how it works in vanilla, and not doing so would break quests (BM_beasts for instance). - ItemModel* playerModel = MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getModel(); - if (mSourceModel != playerModel) - { - MWWorld::Ptr item = mSourceModel->moveItem(mItem, mDraggedCount, playerModel); - - playerModel->update(); - - ItemModel::ModelIndex newIndex = -1; - for (unsigned int i=0; igetItemCount(); ++i) - { - if (playerModel->getItem(i).mBase == item) - { - newIndex = i; - break; - } - } - mItem = playerModel->getItem(newIndex); - mSourceModel = playerModel; - - SortFilterItemModel* playerFilterModel = MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getSortFilterModel(); - mSourceSortModel = playerFilterModel; - } - - std::string sound = mItem.mBase.getClass().getUpSoundId(mItem.mBase); - MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); - - if (mSourceSortModel) - { - mSourceSortModel->clearDragItems(); - mSourceSortModel->addDragItem(mItem.mBase, count); - } - - ItemWidget* baseWidget = MyGUI::Gui::getInstance().createWidget("MW_ItemIcon", 0, 0, 42, 42, MyGUI::Align::Default, "DragAndDrop"); - - Controllers::ControllerFollowMouse* controller = - MyGUI::ControllerManager::getInstance().createItem(Controllers::ControllerFollowMouse::getClassTypeName()) - ->castType(); - MyGUI::ControllerManager::getInstance().addItem(baseWidget, controller); - - mDraggedWidget = baseWidget; - baseWidget->setItem(mItem.mBase); - baseWidget->setNeedMouseFocus(false); - baseWidget->setCount(count); - - sourceView->update(); - - MWBase::Environment::get().getWindowManager()->setDragDrop(true); - } - - void DragAndDrop::drop(ItemModel *targetModel, ItemView *targetView) - { - std::string sound = mItem.mBase.getClass().getDownSoundId(mItem.mBase); - MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); - - // We can't drop a conjured item to the ground; the target container should always be the source container - if (mItem.mFlags & ItemStack::Flag_Bound && targetModel != mSourceModel) - { - MWBase::Environment::get().getWindowManager()->messageBox("#{sBarterDialog12}"); - return; - } - - // If item is dropped where it was taken from, we don't need to do anything - - // otherwise, do the transfer - if (targetModel != mSourceModel) - { - mSourceModel->moveItem(mItem, mDraggedCount, targetModel); - } - - mSourceModel->update(); - - finish(); - if (targetView) - targetView->update(); - - MWBase::Environment::get().getWindowManager()->getInventoryWindow()->updateItemView(); - - // We need to update the view since an other item could be auto-equipped. - mSourceView->update(); - } - - void DragAndDrop::finish() - { - mIsOnDragAndDrop = false; - mSourceSortModel->clearDragItems(); - - MyGUI::Gui::getInstance().destroyWidget(mDraggedWidget); - mDraggedWidget = 0; - MWBase::Environment::get().getWindowManager()->setDragDrop(false); - } - - ContainerWindow::ContainerWindow(DragAndDrop* dragAndDrop) : WindowBase("openmw_container_window.layout") , mDragAndDrop(dragAndDrop) diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index e32c6efaf..87ae993a5 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -28,25 +28,6 @@ namespace MWGui namespace MWGui { - class DragAndDrop - { - public: - bool mIsOnDragAndDrop; - MyGUI::Widget* mDraggedWidget; - ItemModel* mSourceModel; - ItemView* mSourceView; - SortFilterItemModel* mSourceSortModel; - ItemStack mItem; - int mDraggedCount; - - DragAndDrop(); - - void startDrag (int index, SortFilterItemModel* sortModel, ItemModel* sourceModel, ItemView* sourceView, int count); - void drop (ItemModel* targetModel, ItemView* targetView); - - void finish(); - }; - class ContainerWindow : public WindowBase, public ReferenceInterface { public: diff --git a/apps/openmw/mwgui/draganddrop.cpp b/apps/openmw/mwgui/draganddrop.cpp new file mode 100644 index 000000000..452d862f0 --- /dev/null +++ b/apps/openmw/mwgui/draganddrop.cpp @@ -0,0 +1,130 @@ +#include "draganddrop.hpp" + +#include "../mwbase/windowmanager.hpp" +#include "../mwbase/environment.hpp" +#include "../mwbase/soundmanager.hpp" + +#include "../mwworld/class.hpp" + +#include "sortfilteritemmodel.hpp" +#include "inventorywindow.hpp" +#include "itemwidget.hpp" +#include "itemview.hpp" + +namespace MWGui +{ + + +DragAndDrop::DragAndDrop() + : mDraggedWidget(NULL) + , mDraggedCount(0) + , mSourceModel(NULL) + , mSourceView(NULL) + , mSourceSortModel(NULL) + , mIsOnDragAndDrop(false) +{ +} + +void DragAndDrop::startDrag (int index, SortFilterItemModel* sortModel, ItemModel* sourceModel, ItemView* sourceView, int count) +{ + mItem = sourceModel->getItem(index); + mDraggedCount = count; + mSourceModel = sourceModel; + mSourceView = sourceView; + mSourceSortModel = sortModel; + mIsOnDragAndDrop = true; + + // If picking up an item that isn't from the player's inventory, the item gets added to player inventory backend + // immediately, even though it's still floating beneath the mouse cursor. A bit counterintuitive, + // but this is how it works in vanilla, and not doing so would break quests (BM_beasts for instance). + ItemModel* playerModel = MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getModel(); + if (mSourceModel != playerModel) + { + MWWorld::Ptr item = mSourceModel->moveItem(mItem, mDraggedCount, playerModel); + + playerModel->update(); + + ItemModel::ModelIndex newIndex = -1; + for (unsigned int i=0; igetItemCount(); ++i) + { + if (playerModel->getItem(i).mBase == item) + { + newIndex = i; + break; + } + } + mItem = playerModel->getItem(newIndex); + mSourceModel = playerModel; + + SortFilterItemModel* playerFilterModel = MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getSortFilterModel(); + mSourceSortModel = playerFilterModel; + } + + std::string sound = mItem.mBase.getClass().getUpSoundId(mItem.mBase); + MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); + + if (mSourceSortModel) + { + mSourceSortModel->clearDragItems(); + mSourceSortModel->addDragItem(mItem.mBase, count); + } + + ItemWidget* baseWidget = MyGUI::Gui::getInstance().createWidget("MW_ItemIcon", 0, 0, 42, 42, MyGUI::Align::Default, "DragAndDrop"); + + Controllers::ControllerFollowMouse* controller = + MyGUI::ControllerManager::getInstance().createItem(Controllers::ControllerFollowMouse::getClassTypeName()) + ->castType(); + MyGUI::ControllerManager::getInstance().addItem(baseWidget, controller); + + mDraggedWidget = baseWidget; + baseWidget->setItem(mItem.mBase); + baseWidget->setNeedMouseFocus(false); + baseWidget->setCount(count); + + sourceView->update(); + + MWBase::Environment::get().getWindowManager()->setDragDrop(true); +} + +void DragAndDrop::drop(ItemModel *targetModel, ItemView *targetView) +{ + std::string sound = mItem.mBase.getClass().getDownSoundId(mItem.mBase); + MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); + + // We can't drop a conjured item to the ground; the target container should always be the source container + if (mItem.mFlags & ItemStack::Flag_Bound && targetModel != mSourceModel) + { + MWBase::Environment::get().getWindowManager()->messageBox("#{sBarterDialog12}"); + return; + } + + // If item is dropped where it was taken from, we don't need to do anything - + // otherwise, do the transfer + if (targetModel != mSourceModel) + { + mSourceModel->moveItem(mItem, mDraggedCount, targetModel); + } + + mSourceModel->update(); + + finish(); + if (targetView) + targetView->update(); + + MWBase::Environment::get().getWindowManager()->getInventoryWindow()->updateItemView(); + + // We need to update the view since an other item could be auto-equipped. + mSourceView->update(); +} + +void DragAndDrop::finish() +{ + mIsOnDragAndDrop = false; + mSourceSortModel->clearDragItems(); + + MyGUI::Gui::getInstance().destroyWidget(mDraggedWidget); + mDraggedWidget = 0; + MWBase::Environment::get().getWindowManager()->setDragDrop(false); +} + +} diff --git a/apps/openmw/mwgui/draganddrop.hpp b/apps/openmw/mwgui/draganddrop.hpp new file mode 100644 index 000000000..a356fe4e2 --- /dev/null +++ b/apps/openmw/mwgui/draganddrop.hpp @@ -0,0 +1,38 @@ +#ifndef OPENMW_MWGUI_DRAGANDDROP_H +#define OPENMW_MWGUI_DRAGANDDROP_H + +#include "itemmodel.hpp" + +namespace MyGUI +{ + class Widget; +} + +namespace MWGui +{ + + class ItemView; + class SortFilterItemModel; + + class DragAndDrop + { + public: + bool mIsOnDragAndDrop; + MyGUI::Widget* mDraggedWidget; + ItemModel* mSourceModel; + ItemView* mSourceView; + SortFilterItemModel* mSourceSortModel; + ItemStack mItem; + int mDraggedCount; + + DragAndDrop(); + + void startDrag (int index, SortFilterItemModel* sortModel, ItemModel* sourceModel, ItemView* sourceView, int count); + void drop (ItemModel* targetModel, ItemView* targetView); + + void finish(); + }; + +} + +#endif diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index d2315be38..5bd799dac 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -15,7 +15,6 @@ #include "../mwworld/esmstore.hpp" #include "itemselection.hpp" -#include "container.hpp" #include "itemwidget.hpp" #include "sortfilteritemmodel.hpp" diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index f4c1f524a..b7035ee35 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -19,7 +19,7 @@ #include "console.hpp" #include "spellicons.hpp" #include "itemmodel.hpp" -#include "container.hpp" +#include "draganddrop.hpp" #include "itemmodel.hpp" #include "itemwidget.hpp" diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 60f40e6fb..0588d5002 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -25,7 +25,7 @@ #include "tradeitemmodel.hpp" #include "countdialog.hpp" #include "tradewindow.hpp" -#include "container.hpp" +#include "draganddrop.hpp" namespace { diff --git a/apps/openmw/mwgui/itemselection.hpp b/apps/openmw/mwgui/itemselection.hpp index 28c45c605..50e15a3fe 100644 --- a/apps/openmw/mwgui/itemselection.hpp +++ b/apps/openmw/mwgui/itemselection.hpp @@ -1,7 +1,14 @@ #ifndef OPENMW_GAME_MWGUI_ITEMSELECTION_H #define OPENMW_GAME_MWGUI_ITEMSELECTION_H -#include "container.hpp" +#include + +#include "windowbase.hpp" + +namespace MWWorld +{ + class Ptr; +} namespace MWGui { diff --git a/apps/openmw/mwgui/tradewindow.hpp b/apps/openmw/mwgui/tradewindow.hpp index b8bdfe648..61587e3df 100644 --- a/apps/openmw/mwgui/tradewindow.hpp +++ b/apps/openmw/mwgui/tradewindow.hpp @@ -1,7 +1,8 @@ #ifndef MWGUI_TRADEWINDOW_H #define MWGUI_TRADEWINDOW_H -#include "container.hpp" +#include "referenceinterface.hpp" +#include "windowbase.hpp" namespace Gui { diff --git a/apps/openmw/mwgui/windowbase.cpp b/apps/openmw/mwgui/windowbase.cpp index 9c12b04ef..d164320dd 100644 --- a/apps/openmw/mwgui/windowbase.cpp +++ b/apps/openmw/mwgui/windowbase.cpp @@ -1,9 +1,9 @@ #include "windowbase.hpp" #include "../mwbase/windowmanager.hpp" -#include "container.hpp" #include "../mwbase/environment.hpp" -#include "../mwgui/windowmanagerimp.hpp" + +#include "draganddrop.hpp" using namespace MWGui; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 5546480ec..5531a4980 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -74,6 +74,8 @@ #include "screenfader.hpp" #include "debugwindow.hpp" #include "spellview.hpp" +#include "draganddrop.hpp" +#include "container.hpp" namespace MWGui { From eecea4131f18cb400fc74afba2b9d6e20a62b714 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 10 Jan 2015 02:50:43 +0100 Subject: [PATCH 0246/3725] Reduce MyGUI includes --- CMakeLists.txt | 2 +- apps/openmw/mwgui/alchemywindow.cpp | 2 + apps/openmw/mwgui/birth.cpp | 4 + apps/openmw/mwgui/bookwindow.cpp | 2 + apps/openmw/mwgui/class.cpp | 4 + apps/openmw/mwgui/companionwindow.cpp | 2 + apps/openmw/mwgui/confirmationdialog.cpp | 3 + apps/openmw/mwgui/console.cpp | 2 + apps/openmw/mwgui/container.cpp | 3 + apps/openmw/mwgui/controllers.cpp | 1 + apps/openmw/mwgui/controllers.hpp | 6 +- apps/openmw/mwgui/countdialog.cpp | 4 +- apps/openmw/mwgui/debugwindow.cpp | 4 + apps/openmw/mwgui/dialogue.cpp | 4 + apps/openmw/mwgui/dialogue.hpp | 2 +- apps/openmw/mwgui/draganddrop.cpp | 4 + apps/openmw/mwgui/formatting.cpp | 18 ++-- apps/openmw/mwgui/formatting.hpp | 2 +- apps/openmw/mwgui/hud.cpp | 9 ++ apps/openmw/mwgui/inventorywindow.cpp | 13 +++ apps/openmw/mwgui/inventorywindow.hpp | 19 ++-- apps/openmw/mwgui/itemselection.cpp | 3 + apps/openmw/mwgui/journalwindow.cpp | 15 +-- apps/openmw/mwgui/levelupdialog.cpp | 18 ++-- apps/openmw/mwgui/loadingscreen.cpp | 5 + apps/openmw/mwgui/mainmenu.cpp | 4 + apps/openmw/mwgui/mapwindow.cpp | 11 +- apps/openmw/mwgui/merchantrepair.cpp | 4 + apps/openmw/mwgui/messagebox.cpp | 8 +- apps/openmw/mwgui/quickkeysmenu.cpp | 4 + apps/openmw/mwgui/race.cpp | 5 + apps/openmw/mwgui/recharge.cpp | 3 + apps/openmw/mwgui/repair.cpp | 3 + apps/openmw/mwgui/review.cpp | 14 +++ apps/openmw/mwgui/savegamedialog.cpp | 5 + apps/openmw/mwgui/screenfader.cpp | 2 + apps/openmw/mwgui/scrollwindow.cpp | 2 + apps/openmw/mwgui/settingswindow.cpp | 8 +- apps/openmw/mwgui/spellbuyingwindow.cpp | 4 + apps/openmw/mwgui/spellcreationdialog.cpp | 3 + apps/openmw/mwgui/spellicons.cpp | 6 +- apps/openmw/mwgui/spellwindow.cpp | 2 + apps/openmw/mwgui/statswindow.cpp | 6 ++ apps/openmw/mwgui/textinput.cpp | 14 +++ apps/openmw/mwgui/textinput.hpp | 4 +- apps/openmw/mwgui/tooltips.cpp | 5 + apps/openmw/mwgui/tradewindow.cpp | 8 +- apps/openmw/mwgui/tradewindow.hpp | 5 +- apps/openmw/mwgui/trainingwindow.cpp | 2 + apps/openmw/mwgui/travelwindow.cpp | 4 + apps/openmw/mwgui/waitdialog.cpp | 2 + apps/openmw/mwgui/widgets.cpp | 11 +- apps/openmw/mwgui/widgets.hpp | 2 +- apps/openmw/mwgui/windowbase.cpp | 2 + apps/openmw/mwgui/windowmanagerimp.cpp | 16 ++- apps/openmw/mwgui/windowpinnablebase.cpp | 2 + libs/openengine/gui/layout.cpp | 103 ++++++++++++++++++ libs/openengine/gui/layout.hpp | 121 +++++----------------- 58 files changed, 395 insertions(+), 151 deletions(-) create mode 100644 libs/openengine/gui/layout.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 60c37d0f5..79fc7471f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -101,7 +101,7 @@ set(OENGINE_OGRE set(OENGINE_GUI ${LIBS_DIR}/openengine/gui/loglistener.cpp ${LIBS_DIR}/openengine/gui/manager.cpp - ${LIBS_DIR}/openengine/gui/layout.hpp + ${LIBS_DIR}/openengine/gui/layout.cpp ) set(OENGINE_BULLET diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index 1715c49f8..b28e4de09 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -2,6 +2,8 @@ #include +#include + #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/soundmanager.hpp" diff --git a/apps/openmw/mwgui/birth.cpp b/apps/openmw/mwgui/birth.cpp index 50c6639dd..f6e8ec0a8 100644 --- a/apps/openmw/mwgui/birth.cpp +++ b/apps/openmw/mwgui/birth.cpp @@ -1,5 +1,9 @@ #include "birth.hpp" +#include +#include +#include + #include #include diff --git a/apps/openmw/mwgui/bookwindow.cpp b/apps/openmw/mwgui/bookwindow.cpp index 92e876708..69d4a7288 100644 --- a/apps/openmw/mwgui/bookwindow.cpp +++ b/apps/openmw/mwgui/bookwindow.cpp @@ -1,5 +1,7 @@ #include "bookwindow.hpp" +#include + #include #include diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index 4e72a3f59..3e8734c71 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -1,5 +1,9 @@ #include "class.hpp" +#include +#include +#include + #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" diff --git a/apps/openmw/mwgui/companionwindow.cpp b/apps/openmw/mwgui/companionwindow.cpp index c53e1697e..a863000ff 100644 --- a/apps/openmw/mwgui/companionwindow.cpp +++ b/apps/openmw/mwgui/companionwindow.cpp @@ -2,6 +2,8 @@ #include +#include + #include "../mwbase/environment.hpp" #include "../mwbase/dialoguemanager.hpp" diff --git a/apps/openmw/mwgui/confirmationdialog.cpp b/apps/openmw/mwgui/confirmationdialog.cpp index a4e10749a..83650b195 100644 --- a/apps/openmw/mwgui/confirmationdialog.cpp +++ b/apps/openmw/mwgui/confirmationdialog.cpp @@ -1,5 +1,8 @@ #include "confirmationdialog.hpp" +#include +#include + namespace MWGui { ConfirmationDialog::ConfirmationDialog() : diff --git a/apps/openmw/mwgui/console.cpp b/apps/openmw/mwgui/console.cpp index 97f11f4f3..5629c25f1 100644 --- a/apps/openmw/mwgui/console.cpp +++ b/apps/openmw/mwgui/console.cpp @@ -1,5 +1,7 @@ #include "console.hpp" +#include + #include #include diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 85882ec13..cb256e0fd 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -2,6 +2,9 @@ #include +#include +#include + #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/soundmanager.hpp" diff --git a/apps/openmw/mwgui/controllers.cpp b/apps/openmw/mwgui/controllers.cpp index 5ebd2b1e7..ad804997a 100644 --- a/apps/openmw/mwgui/controllers.cpp +++ b/apps/openmw/mwgui/controllers.cpp @@ -1,6 +1,7 @@ #include "controllers.hpp" #include +#include namespace MWGui { diff --git a/apps/openmw/mwgui/controllers.hpp b/apps/openmw/mwgui/controllers.hpp index 003027a46..4208f048c 100644 --- a/apps/openmw/mwgui/controllers.hpp +++ b/apps/openmw/mwgui/controllers.hpp @@ -1,9 +1,13 @@ #ifndef MWGUI_CONTROLLERS_H #define MWGUI_CONTROLLERS_H -#include +#include #include +namespace MyGUI +{ + class Widget; +} namespace MWGui { diff --git a/apps/openmw/mwgui/countdialog.cpp b/apps/openmw/mwgui/countdialog.cpp index 24d0af0d7..c6f2180c9 100644 --- a/apps/openmw/mwgui/countdialog.cpp +++ b/apps/openmw/mwgui/countdialog.cpp @@ -1,6 +1,8 @@ #include "countdialog.hpp" -#include +#include +#include +#include #include diff --git a/apps/openmw/mwgui/debugwindow.cpp b/apps/openmw/mwgui/debugwindow.cpp index fab386bda..a6dab66c1 100644 --- a/apps/openmw/mwgui/debugwindow.cpp +++ b/apps/openmw/mwgui/debugwindow.cpp @@ -1,5 +1,9 @@ #include "debugwindow.hpp" +#include +#include +#include +#include #include diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index db9fa9f6b..1e8e06dc0 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -3,6 +3,10 @@ #include #include +#include +#include +#include + #include #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index 23709e8fe..4ab88c06f 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -171,7 +171,7 @@ namespace MWGui BookPage* mHistory; Gui::MWList* mTopicsList; MyGUI::ScrollBar* mScrollBar; - MyGUI::Progress* mDispositionBar; + MyGUI::ProgressBar* mDispositionBar; MyGUI::EditBox* mDispositionText; PersuasionDialog mPersuasionDialog; diff --git a/apps/openmw/mwgui/draganddrop.cpp b/apps/openmw/mwgui/draganddrop.cpp index 452d862f0..fcb381b95 100644 --- a/apps/openmw/mwgui/draganddrop.cpp +++ b/apps/openmw/mwgui/draganddrop.cpp @@ -1,5 +1,8 @@ #include "draganddrop.hpp" +#include +#include + #include "../mwbase/windowmanager.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/soundmanager.hpp" @@ -10,6 +13,7 @@ #include "inventorywindow.hpp" #include "itemwidget.hpp" #include "itemview.hpp" +#include "controllers.hpp" namespace MWGui { diff --git a/apps/openmw/mwgui/formatting.cpp b/apps/openmw/mwgui/formatting.cpp index 765402a01..3f2b7d228 100644 --- a/apps/openmw/mwgui/formatting.cpp +++ b/apps/openmw/mwgui/formatting.cpp @@ -1,19 +1,23 @@ #include "formatting.hpp" -#include -#include -#include +#include +#include -#include "../mwscript/interpretercontext.hpp" +#include +#include +#include +#include +#include #include #include #include -#include -#include +#include +#include +#include -#include +#include "../mwscript/interpretercontext.hpp" namespace MWGui { diff --git a/apps/openmw/mwgui/formatting.hpp b/apps/openmw/mwgui/formatting.hpp index 0d0f74b72..d525baace 100644 --- a/apps/openmw/mwgui/formatting.hpp +++ b/apps/openmw/mwgui/formatting.hpp @@ -1,7 +1,7 @@ #ifndef MWGUI_FORMATTING_H #define MWGUI_FORMATTING_H -#include +#include #include namespace MWGui diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index b7035ee35..053106043 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -2,6 +2,15 @@ #include +#include + +#include +#include +#include +#include +#include +#include + #include #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 0588d5002..bc39c36d2 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -2,6 +2,12 @@ #include +#include +#include +#include +#include +#include + #include #include "../mwbase/world.hpp" @@ -15,6 +21,7 @@ #include "../mwworld/action.hpp" #include "../mwscript/interpretercontext.hpp" #include "../mwbase/scriptmanager.hpp" +#include "../mwrender/characterpreview.hpp" #include "bookwindow.hpp" #include "scrollwindow.hpp" @@ -26,6 +33,7 @@ #include "countdialog.hpp" #include "tradewindow.hpp" #include "draganddrop.hpp" +#include "widgets.hpp" namespace { @@ -667,4 +675,9 @@ namespace MWGui useItem(model.getItem(cycled).mBase); } + + void InventoryWindow::rebuildAvatar() + { + mPreview->rebuild(); + } } diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index 4f53a1e24..ee71d9b04 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -1,14 +1,23 @@ #ifndef MGUI_Inventory_H #define MGUI_Inventory_H -#include "../mwrender/characterpreview.hpp" - #include "windowpinnablebase.hpp" -#include "widgets.hpp" #include "mode.hpp" +#include "../mwworld/ptr.hpp" + +namespace MWRender +{ + class InventoryPreview; +} + namespace MWGui { + namespace Widgets + { + class MWDynamicStat; + } + class ItemView; class SortFilterItemModel; class TradeItemModel; @@ -33,9 +42,7 @@ namespace MWGui MWWorld::Ptr getAvatarSelectedItem(int x, int y); - void rebuildAvatar() { - mPreview->rebuild(); - } + void rebuildAvatar(); SortFilterItemModel* getSortFilterModel(); TradeItemModel* getTradeModel(); diff --git a/apps/openmw/mwgui/itemselection.cpp b/apps/openmw/mwgui/itemselection.cpp index 1b197f6d8..916f13360 100644 --- a/apps/openmw/mwgui/itemselection.cpp +++ b/apps/openmw/mwgui/itemselection.cpp @@ -1,5 +1,8 @@ #include "itemselection.hpp" +#include +#include + #include "itemview.hpp" #include "inventoryitemmodel.hpp" #include "sortfilteritemmodel.hpp" diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index 0bcd5062d..c4b80b5fe 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -1,22 +1,25 @@ #include "journalwindow.hpp" -#include "../mwbase/environment.hpp" -#include "../mwbase/soundmanager.hpp" -#include "../mwbase/windowmanager.hpp" -#include "../mwbase/journal.hpp" - #include #include #include #include #include + +#include + #include #include -#include "boost/lexical_cast.hpp" +#include #include #include +#include "../mwbase/environment.hpp" +#include "../mwbase/soundmanager.hpp" +#include "../mwbase/windowmanager.hpp" +#include "../mwbase/journal.hpp" + #include "bookpage.hpp" #include "windowbase.hpp" #include "journalviewmodel.hpp" diff --git a/apps/openmw/mwgui/levelupdialog.cpp b/apps/openmw/mwgui/levelupdialog.cpp index 56a231947..8553811aa 100644 --- a/apps/openmw/mwgui/levelupdialog.cpp +++ b/apps/openmw/mwgui/levelupdialog.cpp @@ -1,6 +1,8 @@ #include "levelupdialog.hpp" -#include +#include +#include +#include #include "../mwbase/windowmanager.hpp" #include "../mwbase/environment.hpp" @@ -34,17 +36,17 @@ namespace MWGui for (int i=1; i<9; ++i) { MyGUI::TextBox* t; - getWidget(t, "AttribVal" + boost::lexical_cast(i)); + getWidget(t, "AttribVal" + MyGUI::utility::toString(i)); MyGUI::Button* b; - getWidget(b, "Attrib" + boost::lexical_cast(i)); + getWidget(b, "Attrib" + MyGUI::utility::toString(i)); b->setUserData (i-1); b->eventMouseButtonClick += MyGUI::newDelegate(this, &LevelupDialog::onAttributeClicked); mAttributes.push_back(b); mAttributeValues.push_back(t); - getWidget(t, "AttribMultiplier" + boost::lexical_cast(i)); + getWidget(t, "AttribMultiplier" + MyGUI::utility::toString(i)); mAttributeMultipliers.push_back(t); } @@ -76,7 +78,7 @@ namespace MWGui if (val >= 100) val = 100; - mAttributeValues[i]->setCaption(boost::lexical_cast(val)); + mAttributeValues[i]->setCaption(MyGUI::utility::toString(val)); } } @@ -154,13 +156,13 @@ namespace MWGui mClassImage->setImageTexture ("textures\\levelup\\" + cls->mId + ".dds"); int level = creatureStats.getLevel ()+1; - mLevelText->setCaptionWithReplacing("#{sLevelUpMenu1} " + boost::lexical_cast(level)); + mLevelText->setCaptionWithReplacing("#{sLevelUpMenu1} " + MyGUI::utility::toString(level)); std::string levelupdescription; if(level > 20) levelupdescription=world->getFallback()->getFallbackString("Level_Up_Default"); else - levelupdescription=world->getFallback()->getFallbackString("Level_Up_Level"+boost::lexical_cast(level)); + levelupdescription=world->getFallback()->getFallbackString("Level_Up_Level"+MyGUI::utility::toString(level)); mLevelDescription->setCaption (levelupdescription); @@ -174,7 +176,7 @@ namespace MWGui availableAttributes++; int mult = pcStats.getLevelupAttributeMultiplier (i); - text->setCaption(mult <= 1 ? "" : "x" + boost::lexical_cast(mult)); + text->setCaption(mult <= 1 ? "" : "x" + MyGUI::utility::toString(mult)); } else { diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index 4ff6b0c89..855a6fc84 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -9,6 +9,11 @@ #include #include +#include +#include +#include +#include + #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/statemanager.hpp" diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index f1e7b4fc5..c7855b367 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -2,6 +2,10 @@ #include +#include +#include +#include + #include #include diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 729ee9277..cf8326b5c 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -5,6 +5,15 @@ #include #include +#include +#include +#include +#include +#include +#include +#include +#include + #include "../mwbase/windowmanager.hpp" #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" @@ -15,7 +24,7 @@ #include "../mwrender/globalmap.hpp" -#include "../components/esm/globalmap.hpp" +#include #include "widgets.hpp" #include "confirmationdialog.hpp" diff --git a/apps/openmw/mwgui/merchantrepair.cpp b/apps/openmw/mwgui/merchantrepair.cpp index e85681c04..3f2f2ba02 100644 --- a/apps/openmw/mwgui/merchantrepair.cpp +++ b/apps/openmw/mwgui/merchantrepair.cpp @@ -4,6 +4,10 @@ #include +#include +#include +#include + #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/mechanicsmanager.hpp" diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index d4520aad7..43debd0e5 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -1,6 +1,12 @@ +#include "messagebox.hpp" + +#include +#include +#include +#include + #include -#include "messagebox.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwbase/inputmanager.hpp" diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index d59b29f0f..6e10e4a97 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -2,6 +2,10 @@ #include +#include +#include +#include + #include #include diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index 62bdd7f6b..9c5091b2b 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -1,5 +1,10 @@ #include "race.hpp" +#include +#include +#include +#include + #include #include diff --git a/apps/openmw/mwgui/recharge.cpp b/apps/openmw/mwgui/recharge.cpp index 7458a6eff..81e36c958 100644 --- a/apps/openmw/mwgui/recharge.cpp +++ b/apps/openmw/mwgui/recharge.cpp @@ -3,6 +3,9 @@ #include #include +#include +#include + #include #include "../mwbase/world.hpp" diff --git a/apps/openmw/mwgui/repair.cpp b/apps/openmw/mwgui/repair.cpp index 019f341b5..56ce09c84 100644 --- a/apps/openmw/mwgui/repair.cpp +++ b/apps/openmw/mwgui/repair.cpp @@ -4,6 +4,9 @@ #include +#include +#include + #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" diff --git a/apps/openmw/mwgui/review.cpp b/apps/openmw/mwgui/review.cpp index ca1b6ed5d..2f52aae85 100644 --- a/apps/openmw/mwgui/review.cpp +++ b/apps/openmw/mwgui/review.cpp @@ -1,5 +1,9 @@ #include "review.hpp" +#include +#include +#include + #include #include "../mwbase/environment.hpp" @@ -12,6 +16,16 @@ #undef min #undef max +namespace +{ + void adjustButtonSize(MyGUI::Button *button) + { + // adjust size of button to fit its text + MyGUI::IntSize size = button->getTextSize(); + button->setSize(size.width + 24, button->getSize().height); + } +} + namespace MWGui { diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index 3775f53dd..d022c8e25 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -4,6 +4,11 @@ #include #include +#include +#include +#include +#include + #include #include diff --git a/apps/openmw/mwgui/screenfader.cpp b/apps/openmw/mwgui/screenfader.cpp index a0421ec28..473776a82 100644 --- a/apps/openmw/mwgui/screenfader.cpp +++ b/apps/openmw/mwgui/screenfader.cpp @@ -1,5 +1,7 @@ #include "screenfader.hpp" +#include + namespace MWGui { diff --git a/apps/openmw/mwgui/scrollwindow.cpp b/apps/openmw/mwgui/scrollwindow.cpp index 038d91ca9..d49d5ad5f 100644 --- a/apps/openmw/mwgui/scrollwindow.cpp +++ b/apps/openmw/mwgui/scrollwindow.cpp @@ -1,5 +1,7 @@ #include "scrollwindow.hpp" +#include + #include #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 05664386b..f170559b0 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -1,7 +1,13 @@ #include "settingswindow.hpp" #include -#include + +#include +#include +#include +#include +#include +#include #include #include diff --git a/apps/openmw/mwgui/spellbuyingwindow.cpp b/apps/openmw/mwgui/spellbuyingwindow.cpp index 38b1bce7b..9c3534d4a 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.cpp +++ b/apps/openmw/mwgui/spellbuyingwindow.cpp @@ -2,6 +2,10 @@ #include +#include +#include +#include + #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/soundmanager.hpp" diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index 0db2e30ce..275762d15 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -2,6 +2,9 @@ #include +#include +#include + #include #include diff --git a/apps/openmw/mwgui/spellicons.cpp b/apps/openmw/mwgui/spellicons.cpp index d23f1a235..7edc6c8da 100644 --- a/apps/openmw/mwgui/spellicons.cpp +++ b/apps/openmw/mwgui/spellicons.cpp @@ -1,10 +1,12 @@ #include "spellicons.hpp" -#include - #include #include +#include + +#include + #include #include diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index 98ee588b1..6d3c79b34 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -2,6 +2,8 @@ #include +#include + #include "../mwbase/windowmanager.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" diff --git a/apps/openmw/mwgui/statswindow.cpp b/apps/openmw/mwgui/statswindow.cpp index dcf85ddb7..e565b6f0e 100644 --- a/apps/openmw/mwgui/statswindow.cpp +++ b/apps/openmw/mwgui/statswindow.cpp @@ -1,5 +1,11 @@ #include "statswindow.hpp" +#include +#include +#include +#include +#include + #include #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwgui/textinput.cpp b/apps/openmw/mwgui/textinput.cpp index 80652b430..958b52dc0 100644 --- a/apps/openmw/mwgui/textinput.cpp +++ b/apps/openmw/mwgui/textinput.cpp @@ -3,6 +3,9 @@ #include "../mwbase/windowmanager.hpp" #include "../mwbase/environment.hpp" +#include +#include + namespace MWGui { @@ -64,4 +67,15 @@ namespace MWGui onOkClicked(_sender); } + std::string TextInputDialog::getTextInput() const + { + return mTextEdit->getCaption(); + } + + void TextInputDialog::setTextInput(const std::string &text) + { + mTextEdit->setCaption(text); + } + + } diff --git a/apps/openmw/mwgui/textinput.hpp b/apps/openmw/mwgui/textinput.hpp index c83e3ffa9..57dd34dd6 100644 --- a/apps/openmw/mwgui/textinput.hpp +++ b/apps/openmw/mwgui/textinput.hpp @@ -15,8 +15,8 @@ namespace MWGui public: TextInputDialog(); - std::string getTextInput() const { return mTextEdit->getCaption(); } - void setTextInput(const std::string &text) { mTextEdit->setCaption(text); } + std::string getTextInput() const; + void setTextInput(const std::string &text); void setNextButtonShow(bool shown); void setTextLabel(const std::string &label); diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index aafea1178..3f3540a21 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -2,6 +2,11 @@ #include +#include +#include +#include +#include + #include #include diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 6f0074e7e..bafa89d5b 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -1,6 +1,8 @@ #include "tradewindow.hpp" -#include +#include +#include +#include #include @@ -484,7 +486,7 @@ namespace MWGui MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); int playerGold = player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId); - mPlayerGold->setCaptionWithReplacing("#{sYourGold} " + boost::lexical_cast(playerGold)); + mPlayerGold->setCaptionWithReplacing("#{sYourGold} " + MyGUI::utility::toString(playerGold)); if (mCurrentBalance > 0) { @@ -497,7 +499,7 @@ namespace MWGui mTotalBalance->setValue(std::abs(mCurrentBalance)); - mMerchantGold->setCaptionWithReplacing("#{sSellerGold} " + boost::lexical_cast(getMerchantGold())); + mMerchantGold->setCaptionWithReplacing("#{sSellerGold} " + MyGUI::utility::toString(getMerchantGold())); } void TradeWindow::updateOffer() diff --git a/apps/openmw/mwgui/tradewindow.hpp b/apps/openmw/mwgui/tradewindow.hpp index 61587e3df..a23196d70 100644 --- a/apps/openmw/mwgui/tradewindow.hpp +++ b/apps/openmw/mwgui/tradewindow.hpp @@ -9,12 +9,11 @@ namespace Gui class NumericEditBox; } -namespace MWGui +namespace MyGUI { - class WindowManager; + class ControllerItem; } - namespace MWGui { class ItemView; diff --git a/apps/openmw/mwgui/trainingwindow.cpp b/apps/openmw/mwgui/trainingwindow.cpp index 56c9dff98..fc9167f3c 100644 --- a/apps/openmw/mwgui/trainingwindow.cpp +++ b/apps/openmw/mwgui/trainingwindow.cpp @@ -2,6 +2,8 @@ #include +#include + #include "../mwbase/windowmanager.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index 6a0c99b8a..3d37d0ab0 100644 --- a/apps/openmw/mwgui/travelwindow.cpp +++ b/apps/openmw/mwgui/travelwindow.cpp @@ -2,6 +2,10 @@ #include +#include +#include +#include + #include #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index f2f4a1f91..6f87bffe0 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -2,6 +2,8 @@ #include +#include + #include #include "../mwbase/windowmanager.hpp" diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index 6af7714cb..381fc301e 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -1,21 +1,24 @@ #include "widgets.hpp" -#include "../mwworld/esmstore.hpp" - -#include #include #include -#include +#include #include #include #include +#include + #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwworld/esmstore.hpp" + +#include "controllers.hpp" + #undef min #undef max diff --git a/apps/openmw/mwgui/widgets.hpp b/apps/openmw/mwgui/widgets.hpp index 6ce114131..09a3c11ac 100644 --- a/apps/openmw/mwgui/widgets.hpp +++ b/apps/openmw/mwgui/widgets.hpp @@ -2,7 +2,6 @@ #define MWGUI_WIDGETS_H #include "../mwmechanics/stat.hpp" -#include "controllers.hpp" #include #include @@ -14,6 +13,7 @@ namespace MyGUI { class ImageBox; + class ControllerItem; } namespace MWBase diff --git a/apps/openmw/mwgui/windowbase.cpp b/apps/openmw/mwgui/windowbase.cpp index d164320dd..7f2eaec2e 100644 --- a/apps/openmw/mwgui/windowbase.cpp +++ b/apps/openmw/mwgui/windowbase.cpp @@ -1,5 +1,7 @@ #include "windowbase.hpp" +#include + #include "../mwbase/windowmanager.hpp" #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 5531a4980..aa80e69fc 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -6,10 +6,17 @@ #include #include -#include "MyGUI_UString.h" -#include "MyGUI_IPointer.h" -#include "MyGUI_ResourceImageSetPointer.h" -#include "MyGUI_TextureUtility.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include @@ -76,6 +83,7 @@ #include "spellview.hpp" #include "draganddrop.hpp" #include "container.hpp" +#include "controllers.hpp" namespace MWGui { diff --git a/apps/openmw/mwgui/windowpinnablebase.cpp b/apps/openmw/mwgui/windowpinnablebase.cpp index f9bbca665..7307ece2d 100644 --- a/apps/openmw/mwgui/windowpinnablebase.cpp +++ b/apps/openmw/mwgui/windowpinnablebase.cpp @@ -1,5 +1,7 @@ #include "windowpinnablebase.hpp" +#include + #include "exposedwindow.hpp" namespace MWGui diff --git a/libs/openengine/gui/layout.cpp b/libs/openengine/gui/layout.cpp new file mode 100644 index 000000000..238c4232b --- /dev/null +++ b/libs/openengine/gui/layout.cpp @@ -0,0 +1,103 @@ +#include "layout.hpp" + +#include +#include +#include +#include +#include + +namespace OEngine +{ +namespace GUI +{ + void Layout::initialise(const std::string& _layout, MyGUI::Widget* _parent) + { + const std::string MAIN_WINDOW = "_Main"; + mLayoutName = _layout; + + if (mLayoutName.empty()) + mMainWidget = _parent; + else + { + mPrefix = MyGUI::utility::toString(this, "_"); + mListWindowRoot = MyGUI::LayoutManager::getInstance().loadLayout(mLayoutName, mPrefix, _parent); + + const std::string main_name = mPrefix + MAIN_WINDOW; + for (MyGUI::VectorWidgetPtr::iterator iter=mListWindowRoot.begin(); iter!=mListWindowRoot.end(); ++iter) + { + if ((*iter)->getName() == main_name) + { + mMainWidget = (*iter); + break; + } + } + MYGUI_ASSERT(mMainWidget, "root widget name '" << MAIN_WINDOW << "' in layout '" << mLayoutName << "' not found."); + } + } + + void Layout::shutdown() + { + MyGUI::Gui::getInstance().destroyWidget(mMainWidget); + mListWindowRoot.clear(); + } + + void Layout::setCoord(int x, int y, int w, int h) + { + mMainWidget->setCoord(x,y,w,h); + } + + void Layout::adjustWindowCaption() + { + MyGUI::TextBox* box = mMainWidget->castType(mMainWidget)->getCaptionWidget(); + box->setSize(box->getTextSize().width + 24, box->getSize().height); + + // in order to trigger alignment updates, we need to update the parent + // mygui doesn't provide a proper way of doing this, so we are just changing size + box->getParent()->setCoord(MyGUI::IntCoord( + box->getParent()->getCoord().left, + box->getParent()->getCoord().top, + box->getParent()->getCoord().width, + box->getParent()->getCoord().height+1 + )); + box->getParent()->setCoord(MyGUI::IntCoord( + box->getParent()->getCoord().left, + box->getParent()->getCoord().top, + box->getParent()->getCoord().width, + box->getParent()->getCoord().height-1 + )); + } + + void Layout::setVisible(bool b) + { + mMainWidget->setVisible(b); + } + + void Layout::setText(const std::string &name, const std::string &caption) + { + MyGUI::Widget* pt; + getWidget(pt, name); + static_cast(pt)->setCaption(caption); + } + + void Layout::setTitle(const std::string& title) + { + static_cast(mMainWidget)->setCaptionWithReplacing(title); + adjustWindowCaption(); + } + + MyGUI::Widget* Layout::getWidget(const std::string &_name) + { + for (MyGUI::VectorWidgetPtr::iterator iter=mListWindowRoot.begin(); + iter!=mListWindowRoot.end(); ++iter) + { + MyGUI::Widget* find = (*iter)->findWidget(mPrefix + _name); + if (nullptr != find) + { + return find; + } + } + MYGUI_EXCEPT("widget name '" << _name << "' in layout '" << mLayoutName << "' not found."); + } + +} +} diff --git a/libs/openengine/gui/layout.hpp b/libs/openengine/gui/layout.hpp index cd530a1d9..eb9205b82 100644 --- a/libs/openengine/gui/layout.hpp +++ b/libs/openengine/gui/layout.hpp @@ -1,7 +1,9 @@ #ifndef OENGINE_MYGUI_LAYOUT_H #define OENGINE_MYGUI_LAYOUT_H -#include +#include +#include +#include namespace OEngine { namespace GUI @@ -17,118 +19,43 @@ namespace GUI { initialise(_layout, _parent); } virtual ~Layout() { shutdown(); } + MyGUI::Widget* getWidget(const std::string& _name); + template - void getWidget(T * & _widget, const std::string & _name, bool _throw = true) + void getWidget(T * & _widget, const std::string & _name) { - _widget = nullptr; - for (MyGUI::VectorWidgetPtr::iterator iter=mListWindowRoot.begin(); - iter!=mListWindowRoot.end(); ++iter) + MyGUI::Widget* w = getWidget(_name); + T* cast = w->castType(false); + if (!cast) { - MyGUI::Widget* find = (*iter)->findWidget(mPrefix + _name); - if (nullptr != find) - { - T * cast = find->castType(false); - if (nullptr != cast) - _widget = cast; - else if (_throw) - { - MYGUI_EXCEPT("Error cast : dest type = '" << T::getClassTypeName() - << "' source name = '" << find->getName() - << "' source type = '" << find->getTypeName() << "' in layout '" << mLayoutName << "'"); - } - return; - } + MYGUI_EXCEPT("Error cast : dest type = '" << T::getClassTypeName() + << "' source name = '" << w->getName() + << "' source type = '" << w->getTypeName() << "' in layout '" << mLayoutName << "'"); } - MYGUI_ASSERT( ! _throw, "widget name '" << _name << "' in layout '" << mLayoutName << "' not found."); + else + _widget = cast; } private: void initialise(const std::string & _layout, - MyGUI::Widget* _parent = nullptr) - { - const std::string MAIN_WINDOW = "_Main"; - mLayoutName = _layout; - - if (mLayoutName.empty()) - mMainWidget = _parent; - else - { - mPrefix = MyGUI::utility::toString(this, "_"); - mListWindowRoot = MyGUI::LayoutManager::getInstance().loadLayout(mLayoutName, mPrefix, _parent); + MyGUI::Widget* _parent = nullptr); - const std::string main_name = mPrefix + MAIN_WINDOW; - for (MyGUI::VectorWidgetPtr::iterator iter=mListWindowRoot.begin(); iter!=mListWindowRoot.end(); ++iter) - { - if ((*iter)->getName() == main_name) - { - mMainWidget = (*iter); - break; - } - } - MYGUI_ASSERT(mMainWidget, "root widget name '" << MAIN_WINDOW << "' in layout '" << mLayoutName << "' not found."); - } - } - - void shutdown() - { - MyGUI::Gui::getInstance().destroyWidget(mMainWidget); - mListWindowRoot.clear(); - } + void shutdown(); public: - void setCoord(int x, int y, int w, int h) - { - mMainWidget->setCoord(x,y,w,h); - } + void setCoord(int x, int y, int w, int h); - void adjustWindowCaption() - { - // adjust the size of the window caption so that all text is visible - // NOTE: this assumes that mMainWidget is of type Window. - MyGUI::TextBox* box = static_cast(mMainWidget)->getCaptionWidget(); - box->setSize(box->getTextSize().width + 24, box->getSize().height); + // adjust the size of the window caption so that all text is visible + // NOTE: this assumes that mMainWidget is of type Window. + void adjustWindowCaption(); - // in order to trigger alignment updates, we need to update the parent - // mygui doesn't provide a proper way of doing this, so we are just changing size - box->getParent()->setCoord(MyGUI::IntCoord( - box->getParent()->getCoord().left, - box->getParent()->getCoord().top, - box->getParent()->getCoord().width, - box->getParent()->getCoord().height+1 - )); - box->getParent()->setCoord(MyGUI::IntCoord( - box->getParent()->getCoord().left, - box->getParent()->getCoord().top, - box->getParent()->getCoord().width, - box->getParent()->getCoord().height-1 - )); - } + virtual void setVisible(bool b); - virtual void setVisible(bool b) - { - mMainWidget->setVisible(b); - } + void setText(const std::string& name, const std::string& caption); - void setText(const std::string& name, const std::string& caption) - { - MyGUI::Widget* pt; - getWidget(pt, name); - static_cast(pt)->setCaption(caption); - } + // NOTE: this assume that mMainWidget is of type Window. + void setTitle(const std::string& title); - void setTitle(const std::string& title) - { - // NOTE: this assume that mMainWidget is of type Window. - static_cast(mMainWidget)->setCaptionWithReplacing(title); - adjustWindowCaption(); - } - - void adjustButtonSize(MyGUI::Button* button) - { - // adjust size of button to fit its text - MyGUI::IntSize size = button->getTextSize(); - button->setSize(size.width + 24, button->getSize().height); - } MyGUI::Widget* mMainWidget; protected: From 728b842e72c748afd9fe4a173ba924d378edbe97 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 10 Jan 2015 03:01:01 +0100 Subject: [PATCH 0247/3725] Use MyGUI::utility in favor of boost lexical_cast --- apps/openmw/mwgui/birth.cpp | 4 +-- apps/openmw/mwgui/bookwindow.cpp | 6 ++--- apps/openmw/mwgui/charactercreation.cpp | 12 ++++----- apps/openmw/mwgui/companionwindow.cpp | 4 +-- apps/openmw/mwgui/container.cpp | 2 -- apps/openmw/mwgui/dialogue.cpp | 7 +++-- apps/openmw/mwgui/enchantingdialog.cpp | 6 ++--- apps/openmw/mwgui/formatting.cpp | 9 +++---- apps/openmw/mwgui/hud.cpp | 10 +++---- apps/openmw/mwgui/inventorywindow.cpp | 6 ++--- apps/openmw/mwgui/itemview.cpp | 2 -- apps/openmw/mwgui/itemwidget.cpp | 6 ++--- apps/openmw/mwgui/journalwindow.cpp | 3 +-- apps/openmw/mwgui/mapwindow.cpp | 10 +++---- apps/openmw/mwgui/merchantrepair.cpp | 10 +++---- apps/openmw/mwgui/quickkeysmenu.cpp | 6 ++--- apps/openmw/mwgui/race.cpp | 5 ++-- apps/openmw/mwgui/recharge.cpp | 3 +-- apps/openmw/mwgui/repair.cpp | 4 +-- apps/openmw/mwgui/review.cpp | 14 +++++----- apps/openmw/mwgui/settingswindow.cpp | 25 +++++++++--------- apps/openmw/mwgui/spellbuyingwindow.cpp | 6 ++--- apps/openmw/mwgui/spellcreationdialog.cpp | 20 +++++++------- apps/openmw/mwgui/spellicons.cpp | 4 +-- apps/openmw/mwgui/statswindow.cpp | 32 +++++++++++------------ apps/openmw/mwgui/tooltips.cpp | 4 +-- apps/openmw/mwgui/trainingwindow.cpp | 6 ++--- apps/openmw/mwgui/travelwindow.cpp | 6 ++--- apps/openmw/mwgui/waitdialog.cpp | 12 ++++----- apps/openmw/mwgui/widgets.cpp | 14 +++++----- 30 files changed, 103 insertions(+), 155 deletions(-) diff --git a/apps/openmw/mwgui/birth.cpp b/apps/openmw/mwgui/birth.cpp index f6e8ec0a8..668253712 100644 --- a/apps/openmw/mwgui/birth.cpp +++ b/apps/openmw/mwgui/birth.cpp @@ -4,8 +4,6 @@ #include #include -#include - #include #include @@ -234,7 +232,7 @@ namespace MWGui for (std::vector::const_iterator it = categories[category].spells.begin(); it != end; ++it) { const std::string &spellId = *it; - spellWidget = mSpellArea->createWidget("MW_StatName", coord, MyGUI::Align::Default, std::string("Spell") + boost::lexical_cast(i)); + spellWidget = mSpellArea->createWidget("MW_StatName", coord, MyGUI::Align::Default, std::string("Spell") + MyGUI::utility::toString(i)); spellWidget->setSpellId(spellId); mSpellItems.push_back(spellWidget); diff --git a/apps/openmw/mwgui/bookwindow.cpp b/apps/openmw/mwgui/bookwindow.cpp index 69d4a7288..da0d1950e 100644 --- a/apps/openmw/mwgui/bookwindow.cpp +++ b/apps/openmw/mwgui/bookwindow.cpp @@ -2,8 +2,6 @@ #include -#include - #include #include "../mwbase/environment.hpp" @@ -142,8 +140,8 @@ namespace MWGui void BookWindow::updatePages() { - mLeftPageNumber->setCaption( boost::lexical_cast(mCurrentPage*2 + 1) ); - mRightPageNumber->setCaption( boost::lexical_cast(mCurrentPage*2 + 2) ); + mLeftPageNumber->setCaption( MyGUI::utility::toString(mCurrentPage*2 + 1) ); + mRightPageNumber->setCaption( MyGUI::utility::toString(mCurrentPage*2 + 2) ); //If it is the last page, hide the button "Next Page" if ( (mCurrentPage+1)*2 == mPages.size() diff --git a/apps/openmw/mwgui/charactercreation.cpp b/apps/openmw/mwgui/charactercreation.cpp index 3df8da942..ab412f63b 100644 --- a/apps/openmw/mwgui/charactercreation.cpp +++ b/apps/openmw/mwgui/charactercreation.cpp @@ -1,7 +1,5 @@ #include "charactercreation.hpp" -#include - #include "../mwbase/environment.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" @@ -34,11 +32,11 @@ namespace Step sGenerateClassSteps(int number) { number++; const MWWorld::Fallback* fallback=MWBase::Environment::get().getWorld()->getFallback(); - Step step = {fallback->getFallbackString("Question_"+boost::lexical_cast(number)+"_Question"), - {fallback->getFallbackString("Question_"+boost::lexical_cast(number)+"_AnswerOne"), - fallback->getFallbackString("Question_"+boost::lexical_cast(number)+"_AnswerTwo"), - fallback->getFallbackString("Question_"+boost::lexical_cast(number)+"_AnswerThree")}, - "vo\\misc\\chargen qa"+boost::lexical_cast(number)+".wav" + Step step = {fallback->getFallbackString("Question_"+MyGUI::utility::toString(number)+"_Question"), + {fallback->getFallbackString("Question_"+MyGUI::utility::toString(number)+"_AnswerOne"), + fallback->getFallbackString("Question_"+MyGUI::utility::toString(number)+"_AnswerTwo"), + fallback->getFallbackString("Question_"+MyGUI::utility::toString(number)+"_AnswerThree")}, + "vo\\misc\\chargen qa"+MyGUI::utility::toString(number)+".wav" }; return step; } diff --git a/apps/openmw/mwgui/companionwindow.cpp b/apps/openmw/mwgui/companionwindow.cpp index a863000ff..758316030 100644 --- a/apps/openmw/mwgui/companionwindow.cpp +++ b/apps/openmw/mwgui/companionwindow.cpp @@ -1,7 +1,5 @@ #include "companionwindow.hpp" -#include - #include #include "../mwbase/environment.hpp" @@ -122,7 +120,7 @@ void CompanionWindow::updateEncumbranceBar() else { MWMechanics::NpcStats& stats = mPtr.getClass().getNpcStats(mPtr); - mProfitLabel->setCaptionWithReplacing("#{sProfitValue} " + boost::lexical_cast(stats.getProfit())); + mProfitLabel->setCaptionWithReplacing("#{sProfitValue} " + MyGUI::utility::toString(stats.getProfit())); } } diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index cb256e0fd..49e641aed 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -1,7 +1,5 @@ #include "container.hpp" -#include - #include #include diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 1e8e06dc0..eee86c6d2 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -1,7 +1,6 @@ #include "dialogue.hpp" #include -#include #include #include @@ -100,7 +99,7 @@ namespace MWGui mBribe100Button->setEnabled (playerGold >= 100); mBribe1000Button->setEnabled (playerGold >= 1000); - mGoldLabel->setCaptionWithReplacing("#{sGold}: " + boost::lexical_cast(playerGold)); + mGoldLabel->setCaptionWithReplacing("#{sGold}: " + MyGUI::utility::toString(playerGold)); } void PersuasionDialog::exit() @@ -630,7 +629,7 @@ namespace MWGui dispositionVisible = true; mDispositionBar->setProgressRange(100); mDispositionBar->setProgressPosition(MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mPtr)); - mDispositionText->setCaption(boost::lexical_cast(MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mPtr))+std::string("/100")); + mDispositionText->setCaption(MyGUI::utility::toString(MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mPtr))+std::string("/100")); } bool dispositionWasVisible = mDispositionBar->getVisible(); @@ -672,7 +671,7 @@ namespace MWGui + MWBase::Environment::get().getDialogueManager()->getTemporaryDispositionChange())); mDispositionBar->setProgressRange(100); mDispositionBar->setProgressPosition(disp); - mDispositionText->setCaption(boost::lexical_cast(disp)+std::string("/100")); + mDispositionText->setCaption(MyGUI::utility::toString(disp)+std::string("/100")); } } } diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 5bd799dac..a17c0d0e6 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -105,15 +105,15 @@ namespace MWGui { std::stringstream enchantCost; enchantCost << std::setprecision(1) << std::fixed << mEnchanting.getEnchantPoints(); - mEnchantmentPoints->setCaption(enchantCost.str() + " / " + boost::lexical_cast(mEnchanting.getMaxEnchantValue())); + mEnchantmentPoints->setCaption(enchantCost.str() + " / " + MyGUI::utility::toString(mEnchanting.getMaxEnchantValue())); - mCharge->setCaption(boost::lexical_cast(mEnchanting.getGemCharge())); + mCharge->setCaption(MyGUI::utility::toString(mEnchanting.getGemCharge())); std::stringstream castCost; castCost << mEnchanting.getEffectiveCastCost(); mCastCost->setCaption(castCost.str()); - mPrice->setCaption(boost::lexical_cast(mEnchanting.getEnchantPrice())); + mPrice->setCaption(MyGUI::utility::toString(mEnchanting.getEnchantPrice())); switch(mEnchanting.getCastStyle()) { diff --git a/apps/openmw/mwgui/formatting.cpp b/apps/openmw/mwgui/formatting.cpp index 3f2b7d228..761a89ca6 100644 --- a/apps/openmw/mwgui/formatting.cpp +++ b/apps/openmw/mwgui/formatting.cpp @@ -11,7 +11,6 @@ #include #include -#include #include #include @@ -284,8 +283,8 @@ namespace MWGui continue; std::string src = attr.at("src"); - int width = boost::lexical_cast(attr.at("width")); - int height = boost::lexical_cast(attr.at("height")); + int width = MyGUI::utility::parseInt(attr.at("width")); + int height = MyGUI::utility::parseInt(attr.at("height")); ImageElement elem(paper, pag, mBlockStyle, src, width, height); @@ -397,7 +396,7 @@ namespace MWGui { MyGUI::EditBox* box = parent->createWidget("NormalText", MyGUI::IntCoord(0, pag.getCurrentTop(), pag.getPageWidth(), 0), MyGUI::Align::Left | MyGUI::Align::Top, - parent->getName() + boost::lexical_cast(parent->getChildCount())); + parent->getName() + MyGUI::utility::toString(parent->getChildCount())); box->setProperty("Static", "true"); box->setProperty("MultiLine", "true"); box->setProperty("WordWrap", "true"); @@ -465,7 +464,7 @@ namespace MWGui mImageBox = parent->createWidget ("ImageBox", MyGUI::IntCoord(left, pag.getCurrentTop(), width, mImageHeight), MyGUI::Align::Left | MyGUI::Align::Top, - parent->getName() + boost::lexical_cast(parent->getChildCount())); + parent->getName() + MyGUI::utility::toString(parent->getChildCount())); std::string image = Misc::ResourceHelpers::correctBookartPath(src, width, mImageHeight); mImageBox->setImageTexture(image); diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 053106043..b4312dc40 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -1,7 +1,5 @@ #include "hud.hpp" -#include - #include #include @@ -214,17 +212,17 @@ namespace MWGui void HUD::setFPS(float fps) { if (mFpsCounter) - mFpsCounter->setCaption(boost::lexical_cast((int)fps)); + mFpsCounter->setCaption(MyGUI::utility::toString((int)fps)); } void HUD::setTriangleCount(unsigned int count) { - mTriangleCounter->setCaption(boost::lexical_cast(count)); + mTriangleCounter->setCaption(MyGUI::utility::toString(count)); } void HUD::setBatchCount(unsigned int count) { - mBatchCounter->setCaption(boost::lexical_cast(count)); + mBatchCounter->setCaption(MyGUI::utility::toString(count)); } void HUD::setValue(const std::string& id, const MWMechanics::DynamicStat& value) @@ -233,7 +231,7 @@ namespace MWGui int modified = static_cast(value.getModified()); MyGUI::Widget* w; - std::string valStr = boost::lexical_cast(current) + "/" + boost::lexical_cast(modified); + std::string valStr = MyGUI::utility::toString(current) + "/" + MyGUI::utility::toString(modified); if (id == "HBar") { mHealth->setProgressRange(modified); diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index bc39c36d2..ed0f505f5 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -8,8 +8,6 @@ #include #include -#include - #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/soundmanager.hpp" @@ -542,9 +540,9 @@ namespace MWGui if (mPreviewResize || mPreviewDirty) { mArmorRating->setCaptionWithReplacing ("#{sArmor}: " - + boost::lexical_cast(static_cast(mPtr.getClass().getArmorRating(mPtr)))); + + MyGUI::utility::toString(static_cast(mPtr.getClass().getArmorRating(mPtr)))); if (mArmorRating->getTextSize().width > mArmorRating->getSize().width) - mArmorRating->setCaptionWithReplacing (boost::lexical_cast(static_cast(mPtr.getClass().getArmorRating(mPtr)))); + mArmorRating->setCaptionWithReplacing (MyGUI::utility::toString(static_cast(mPtr.getClass().getArmorRating(mPtr)))); } if (mPreviewResize) { diff --git a/apps/openmw/mwgui/itemview.cpp b/apps/openmw/mwgui/itemview.cpp index bf8bf1adf..41c3604b4 100644 --- a/apps/openmw/mwgui/itemview.cpp +++ b/apps/openmw/mwgui/itemview.cpp @@ -2,8 +2,6 @@ #include -#include - #include #include #include diff --git a/apps/openmw/mwgui/itemwidget.cpp b/apps/openmw/mwgui/itemwidget.cpp index b6a288078..36940113e 100644 --- a/apps/openmw/mwgui/itemwidget.cpp +++ b/apps/openmw/mwgui/itemwidget.cpp @@ -4,8 +4,6 @@ #include #include -#include - #include #include "../mwworld/class.hpp" @@ -17,9 +15,9 @@ namespace if (count == 1) return ""; if (count > 9999) - return boost::lexical_cast(int(count/1000.f)) + "k"; + return MyGUI::utility::toString(int(count/1000.f)) + "k"; else - return boost::lexical_cast(count); + return MyGUI::utility::toString(count); } } diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index c4b80b5fe..afff5601a 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -10,7 +10,6 @@ #include #include -#include #include #include @@ -74,7 +73,7 @@ namespace void setText (char const * name, value_type const & value) { getWidget (name) -> - setCaption (boost::lexical_cast (value)); + setCaption (MyGUI::utility::toString (value)); } void setVisible (char const * name, bool visible) diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index cf8326b5c..0f9fa2775 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -1,7 +1,5 @@ #include "mapwindow.hpp" -#include - #include #include @@ -235,8 +233,8 @@ namespace MWGui { for (int my=0; my<3; ++my) { - std::string image = mPrefix+"_"+ boost::lexical_cast(mCurX + (mx-1)) + "_" - + boost::lexical_cast(mCurY + (-1*(my-1))); + std::string image = mPrefix+"_"+ MyGUI::utility::toString(mCurX + (mx-1)) + "_" + + MyGUI::utility::toString(mCurY + (-1*(my-1))); MyGUI::ImageBox* fog = mFogWidgets[my + 3*mx]; fog->setImageTexture(mFogOfWar ? ((MyGUI::RenderManager::getInstance().getTexture(image+"_fog") != 0) ? image+"_fog" @@ -362,8 +360,8 @@ namespace MWGui for (int my=0; my<3; ++my) { // map - std::string image = mPrefix+"_"+ boost::lexical_cast(x + (mx-1)) + "_" - + boost::lexical_cast(y + (-1*(my-1))); + std::string image = mPrefix+"_"+ MyGUI::utility::toString(x + (mx-1)) + "_" + + MyGUI::utility::toString(y + (-1*(my-1))); MyGUI::ImageBox* box = mMapWidgets[my + 3*mx]; diff --git a/apps/openmw/mwgui/merchantrepair.cpp b/apps/openmw/mwgui/merchantrepair.cpp index 3f2f2ba02..907c664b1 100644 --- a/apps/openmw/mwgui/merchantrepair.cpp +++ b/apps/openmw/mwgui/merchantrepair.cpp @@ -2,8 +2,6 @@ #include -#include - #include #include #include @@ -71,7 +69,7 @@ void MerchantRepair::startRepair(const MWWorld::Ptr &actor) std::string name = iter->getClass().getName(*iter) - + " - " + boost::lexical_cast(price) + + " - " + MyGUI::utility::toString(price) + MWBase::Environment::get().getWorld()->getStore().get() .find("sgp")->getString(); @@ -87,7 +85,7 @@ void MerchantRepair::startRepair(const MWWorld::Ptr &actor) currentY += 18; - button->setUserString("Price", boost::lexical_cast(price)); + button->setUserString("Price", MyGUI::utility::toString(price)); button->setUserData(*iter); button->setCaptionWithReplacing(name); button->setSize(button->getTextSize().width,18); @@ -102,7 +100,7 @@ void MerchantRepair::startRepair(const MWWorld::Ptr &actor) mList->setVisibleVScroll(true); mGoldLabel->setCaptionWithReplacing("#{sGold}: " - + boost::lexical_cast(playerGold)); + + MyGUI::utility::toString(playerGold)); } void MerchantRepair::onMouseWheel(MyGUI::Widget* _sender, int _rel) @@ -127,7 +125,7 @@ void MerchantRepair::onRepairButtonClick(MyGUI::Widget *sender) { MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); - int price = boost::lexical_cast(sender->getUserString("Price")); + int price = MyGUI::utility::parseInt(sender->getUserString("Price")); if (price > player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId)) return; diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index 6e10e4a97..deba64434 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -1,7 +1,5 @@ #include "quickkeysmenu.hpp" -#include - #include #include #include @@ -57,7 +55,7 @@ namespace MWGui for (int i = 0; i < 10; ++i) { ItemWidget* button; - getWidget(button, "QuickKey" + boost::lexical_cast(i+1)); + getWidget(button, "QuickKey" + MyGUI::utility::toString(i+1)); button->eventMouseButtonClick += MyGUI::newDelegate(this, &QuickKeysMenu::onQuickKeyButtonClicked); @@ -100,7 +98,7 @@ namespace MWGui MyGUI::TextBox* textBox = key->createWidgetReal("SandText", MyGUI::FloatCoord(0,0,1,1), MyGUI::Align::Default); textBox->setTextAlign (MyGUI::Align::Center); - textBox->setCaption (boost::lexical_cast(index+1)); + textBox->setCaption (MyGUI::utility::toString(index+1)); textBox->setNeedMouseFocus (false); } diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index 9c5091b2b..f6aa8ee4c 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -5,7 +5,6 @@ #include #include -#include #include #include "../mwworld/esmstore.hpp" @@ -402,7 +401,7 @@ namespace MWGui continue; skillWidget = mSkillList->createWidget("MW_StatNameValue", coord1, MyGUI::Align::Default, - std::string("Skill") + boost::lexical_cast(i)); + std::string("Skill") + MyGUI::utility::toString(i)); skillWidget->setSkillNumber(skillId); skillWidget->setSkillValue(Widgets::MWSkill::SkillValue(race->mData.mBonus[i].mBonus)); ToolTips::createSkillToolTip(skillWidget, skillId); @@ -436,7 +435,7 @@ namespace MWGui for (int i = 0; it != end; ++it) { const std::string &spellpower = *it; - Widgets::MWSpellPtr spellPowerWidget = mSpellPowerList->createWidget("MW_StatName", coord, MyGUI::Align::Default, std::string("SpellPower") + boost::lexical_cast(i)); + Widgets::MWSpellPtr spellPowerWidget = mSpellPowerList->createWidget("MW_StatName", coord, MyGUI::Align::Default, std::string("SpellPower") + MyGUI::utility::toString(i)); spellPowerWidget->setSpellId(spellpower); spellPowerWidget->setUserString("ToolTipType", "Spell"); spellPowerWidget->setUserString("Spell", spellpower); diff --git a/apps/openmw/mwgui/recharge.cpp b/apps/openmw/mwgui/recharge.cpp index 81e36c958..2c854a8f5 100644 --- a/apps/openmw/mwgui/recharge.cpp +++ b/apps/openmw/mwgui/recharge.cpp @@ -1,6 +1,5 @@ #include "recharge.hpp" -#include #include #include @@ -66,7 +65,7 @@ void Recharge::updateView() std::string soul = gem.getCellRef().getSoul(); const ESM::Creature *creature = MWBase::Environment::get().getWorld()->getStore().get().find(soul); - mChargeLabel->setCaptionWithReplacing("#{sCharges} " + boost::lexical_cast(creature->mData.mSoul)); + mChargeLabel->setCaptionWithReplacing("#{sCharges} " + MyGUI::utility::toString(creature->mData.mSoul)); bool toolBoxVisible = (gem.getRefData().getCount() != 0); mGemBox->setVisible(toolBoxVisible); diff --git a/apps/openmw/mwgui/repair.cpp b/apps/openmw/mwgui/repair.cpp index 56ce09c84..c3c971400 100644 --- a/apps/openmw/mwgui/repair.cpp +++ b/apps/openmw/mwgui/repair.cpp @@ -2,8 +2,6 @@ #include -#include - #include #include @@ -68,7 +66,7 @@ void Repair::updateRepairView() std::stringstream qualityStr; qualityStr << std::setprecision(3) << quality; - mUsesLabel->setCaptionWithReplacing("#{sUses} " + boost::lexical_cast(uses)); + mUsesLabel->setCaptionWithReplacing("#{sUses} " + MyGUI::utility::toString(uses)); mQualityLabel->setCaptionWithReplacing("#{sQuality} " + qualityStr.str()); bool toolBoxVisible = (mRepair.getTool().getRefData().getCount() != 0); diff --git a/apps/openmw/mwgui/review.cpp b/apps/openmw/mwgui/review.cpp index 2f52aae85..1bcd2d31a 100644 --- a/apps/openmw/mwgui/review.cpp +++ b/apps/openmw/mwgui/review.cpp @@ -4,8 +4,6 @@ #include #include -#include - #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" @@ -77,7 +75,7 @@ namespace MWGui Widgets::MWAttributePtr attribute; for (int idx = 0; idx < ESM::Attribute::Length; ++idx) { - getWidget(attribute, std::string("Attribute") + boost::lexical_cast(idx)); + getWidget(attribute, std::string("Attribute") + MyGUI::utility::toString(idx)); mAttributeWidgets.insert(std::make_pair(static_cast(ESM::Attribute::sAttributeIds[idx]), attribute)); attribute->setAttributeId(ESM::Attribute::sAttributeIds[idx]); attribute->setAttributeValue(Widgets::MWAttribute::AttributeValue()); @@ -149,21 +147,21 @@ namespace MWGui void ReviewDialog::setHealth(const MWMechanics::DynamicStat& value) { mHealth->setValue(value.getCurrent(), value.getModified()); - std::string valStr = boost::lexical_cast(value.getCurrent()) + "/" + boost::lexical_cast(value.getModified()); + std::string valStr = MyGUI::utility::toString(value.getCurrent()) + "/" + MyGUI::utility::toString(value.getModified()); mHealth->setUserString("Caption_HealthDescription", "#{sHealthDesc}\n" + valStr); } void ReviewDialog::setMagicka(const MWMechanics::DynamicStat& value) { mMagicka->setValue(value.getCurrent(), value.getModified()); - std::string valStr = boost::lexical_cast(value.getCurrent()) + "/" + boost::lexical_cast(value.getModified()); + std::string valStr = MyGUI::utility::toString(value.getCurrent()) + "/" + MyGUI::utility::toString(value.getModified()); mMagicka->setUserString("Caption_HealthDescription", "#{sIntDesc}\n" + valStr); } void ReviewDialog::setFatigue(const MWMechanics::DynamicStat& value) { mFatigue->setValue(value.getCurrent(), value.getModified()); - std::string valStr = boost::lexical_cast(value.getCurrent()) + "/" + boost::lexical_cast(value.getModified()); + std::string valStr = MyGUI::utility::toString(value.getCurrent()) + "/" + MyGUI::utility::toString(value.getModified()); mFatigue->setUserString("Caption_HealthDescription", "#{sFatDesc}\n" + valStr); } @@ -183,7 +181,7 @@ namespace MWGui if (widget) { float modified = value.getModified(), base = value.getBase(); - std::string text = boost::lexical_cast(std::floor(modified)); + std::string text = MyGUI::utility::toString(std::floor(modified)); std::string state = "normal"; if (modified > base) state = "increased"; @@ -303,7 +301,7 @@ namespace MWGui state = "increased"; else if (modified < base) state = "decreased"; - MyGUI::TextBox* widget = addValueItem(MWBase::Environment::get().getWindowManager()->getGameSettingString(skillNameId, skillNameId), boost::lexical_cast(static_cast(modified)), state, coord1, coord2); + MyGUI::TextBox* widget = addValueItem(MWBase::Environment::get().getWindowManager()->getGameSettingString(skillNameId, skillNameId), MyGUI::utility::toString(static_cast(modified)), state, coord1, coord2); for (int i=0; i<2; ++i) { diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index f170559b0..f8741a67a 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -9,7 +9,6 @@ #include #include -#include #include #include @@ -54,8 +53,8 @@ namespace assert (split.size() >= 2); boost::trim(split[0]); boost::trim(split[1]); - x = boost::lexical_cast (split[0]); - y = boost::lexical_cast (split[1]); + x = MyGUI::utility::parseInt (split[0]); + y = MyGUI::utility::parseInt (split[1]); } bool sortResolutions (std::pair left, std::pair right) @@ -73,7 +72,7 @@ namespace // special case: 8 : 5 is usually referred to as 16:10 if (xaspect == 8 && yaspect == 5) return "16 : 10"; - return boost::lexical_cast(xaspect) + " : " + boost::lexical_cast(yaspect); + return MyGUI::utility::toString(xaspect) + " : " + MyGUI::utility::toString(yaspect); } std::string hlslGlsl () @@ -111,9 +110,9 @@ namespace min = 0.f; max = 1.f; if (!widget->getUserString(settingMin).empty()) - min = boost::lexical_cast(widget->getUserString(settingMin)); + min = MyGUI::utility::parseFloat(widget->getUserString(settingMin)); if (!widget->getUserString(settingMax).empty()) - max = boost::lexical_cast(widget->getUserString(settingMax)); + max = MyGUI::utility::parseFloat(widget->getUserString(settingMax)); } } @@ -230,7 +229,7 @@ namespace MWGui for (std::vector < std::pair >::const_iterator it=resolutions.begin(); it!=resolutions.end(); ++it) { - std::string str = boost::lexical_cast(it->first) + " x " + boost::lexical_cast(it->second) + std::string str = MyGUI::utility::toString(it->first) + " x " + MyGUI::utility::toString(it->second) + " (" + getAspect(it->first,it->second) + ")"; if (mResolutionList->findItemIndexWith(str) == MyGUI::ITEM_NONE) @@ -239,7 +238,7 @@ namespace MWGui std::string tf = Settings::Manager::getString("texture filtering", "General"); mTextureFilteringButton->setCaption(textureFilteringToStr(tf)); - mAnisotropyLabel->setCaption("Anisotropy (" + boost::lexical_cast(Settings::Manager::getInt("anisotropy", "General")) + ")"); + mAnisotropyLabel->setCaption("Anisotropy (" + MyGUI::utility::toString(Settings::Manager::getInt("anisotropy", "General")) + ")"); mShadowsTextureSize->setCaption (Settings::Manager::getString ("texture size", "Shadows")); @@ -255,11 +254,11 @@ namespace MWGui MyGUI::TextBox* fovText; getWidget(fovText, "FovText"); - fovText->setCaption("Field of View (" + boost::lexical_cast(int(Settings::Manager::getInt("field of view", "General"))) + ")"); + fovText->setCaption("Field of View (" + MyGUI::utility::toString(int(Settings::Manager::getInt("field of view", "General"))) + ")"); MyGUI::TextBox* diffText; getWidget(diffText, "DifficultyText"); - diffText->setCaptionWithReplacing("#{sDifficulty} (" + boost::lexical_cast(int(Settings::Manager::getInt("difficulty", "Game"))) + ")"); + diffText->setCaptionWithReplacing("#{sDifficulty} (" + MyGUI::utility::toString(int(Settings::Manager::getInt("difficulty", "Game"))) + ")"); mWindowBorderButton->setEnabled(!Settings::Manager::getBool("fullscreen", "Video")); } @@ -431,13 +430,13 @@ namespace MWGui { MyGUI::TextBox* fovText; getWidget(fovText, "FovText"); - fovText->setCaption("Field of View (" + boost::lexical_cast(int(value)) + ")"); + fovText->setCaption("Field of View (" + MyGUI::utility::toString(int(value)) + ")"); } if (scroller == mDifficultySlider) { MyGUI::TextBox* diffText; getWidget(diffText, "DifficultyText"); - diffText->setCaptionWithReplacing("#{sDifficulty} (" + boost::lexical_cast(int(value)) + ")"); + diffText->setCaptionWithReplacing("#{sDifficulty} (" + MyGUI::utility::toString(int(value)) + ")"); } } else @@ -445,7 +444,7 @@ namespace MWGui Settings::Manager::setInt(getSettingName(scroller), getSettingCategory(scroller), pos); if (scroller == mAnisotropySlider) { - mAnisotropyLabel->setCaption("Anisotropy (" + boost::lexical_cast(pos) + ")"); + mAnisotropyLabel->setCaption("Anisotropy (" + MyGUI::utility::toString(pos) + ")"); } } apply(); diff --git a/apps/openmw/mwgui/spellbuyingwindow.cpp b/apps/openmw/mwgui/spellbuyingwindow.cpp index 9c3534d4a..54094b606 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.cpp +++ b/apps/openmw/mwgui/spellbuyingwindow.cpp @@ -1,7 +1,5 @@ #include "spellbuyingwindow.hpp" -#include - #include #include #include @@ -69,7 +67,7 @@ namespace MWGui mCurrentY += sLineHeight; toAdd->setUserData(price); - toAdd->setCaptionWithReplacing(spell->mName+" - "+boost::lexical_cast(price)+"#{sgp}"); + toAdd->setCaptionWithReplacing(spell->mName+" - "+MyGUI::utility::toString(price)+"#{sgp}"); toAdd->setSize(toAdd->getTextSize().width,sLineHeight); toAdd->eventMouseWheel += MyGUI::newDelegate(this, &SpellBuyingWindow::onMouseWheel); toAdd->setUserString("ToolTipType", "Spell"); @@ -170,7 +168,7 @@ namespace MWGui MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); int playerGold = player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId); - mPlayerGold->setCaptionWithReplacing("#{sGold}: " + boost::lexical_cast(playerGold)); + mPlayerGold->setCaptionWithReplacing("#{sGold}: " + MyGUI::utility::toString(playerGold)); mPlayerGold->setCoord(8, mPlayerGold->getTop(), mPlayerGold->getTextSize().width, diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index 275762d15..1ff379c0b 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -1,7 +1,5 @@ #include "spellcreationdialog.hpp" -#include - #include #include @@ -269,7 +267,7 @@ namespace MWGui void EditEffectDialog::onMagnitudeMinChanged (MyGUI::ScrollBar* sender, size_t pos) { - mMagnitudeMinValue->setCaption(boost::lexical_cast(pos+1)); + mMagnitudeMinValue->setCaption(MyGUI::utility::toString(pos+1)); mEffect.mMagnMin = pos+1; // trigger the check again (see below) @@ -289,21 +287,21 @@ namespace MWGui mEffect.mMagnMax = pos+1; - mMagnitudeMaxValue->setCaption("- " + boost::lexical_cast(pos+1)); + mMagnitudeMaxValue->setCaption("- " + MyGUI::utility::toString(pos+1)); eventEffectModified(mEffect); } void EditEffectDialog::onDurationChanged (MyGUI::ScrollBar* sender, size_t pos) { - mDurationValue->setCaption(boost::lexical_cast(pos+1)); + mDurationValue->setCaption(MyGUI::utility::toString(pos+1)); mEffect.mDuration = pos+1; eventEffectModified(mEffect); } void EditEffectDialog::onAreaChanged (MyGUI::ScrollBar* sender, size_t pos) { - mAreaValue->setCaption(boost::lexical_cast(pos)); + mAreaValue->setCaption(MyGUI::utility::toString(pos)); mEffect.mArea = pos; eventEffectModified(mEffect); } @@ -365,7 +363,7 @@ namespace MWGui MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); int playerGold = player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId); - if (boost::lexical_cast(mPriceLabel->getCaption()) > playerGold) + if (MyGUI::utility::parseInt(mPriceLabel->getCaption()) > playerGold) { MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage18}"); return; @@ -373,7 +371,7 @@ namespace MWGui mSpell.mName = mNameEdit->getCaption(); - int price = boost::lexical_cast(mPriceLabel->getCaption()); + int price = MyGUI::utility::parseInt(mPriceLabel->getCaption()); player.getClass().getContainerStore(player).remove(MWWorld::ContainerStore::sGoldId, price, player); @@ -451,17 +449,17 @@ namespace MWGui mSpell.mData.mType = ESM::Spell::ST_Spell; mSpell.mData.mFlags = 0; - mMagickaCost->setCaption(boost::lexical_cast(int(y))); + mMagickaCost->setCaption(MyGUI::utility::toString(int(y))); float fSpellMakingValueMult = store.get().find("fSpellMakingValueMult")->getFloat(); int price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr,int(y) * fSpellMakingValueMult,true); - mPriceLabel->setCaption(boost::lexical_cast(int(price))); + mPriceLabel->setCaption(MyGUI::utility::toString(int(price))); float chance = MWMechanics::getSpellSuccessChance(&mSpell, MWBase::Environment::get().getWorld()->getPlayerPtr()); - mSuccessChance->setCaption(boost::lexical_cast(int(chance))); + mSuccessChance->setCaption(MyGUI::utility::toString(int(chance))); } // ------------------------------------------------------------------------------------------------ diff --git a/apps/openmw/mwgui/spellicons.cpp b/apps/openmw/mwgui/spellicons.cpp index 7edc6c8da..20c6f3ba8 100644 --- a/apps/openmw/mwgui/spellicons.cpp +++ b/apps/openmw/mwgui/spellicons.cpp @@ -3,8 +3,6 @@ #include #include -#include - #include #include @@ -117,7 +115,7 @@ namespace MWGui } else if ( displayType != ESM::MagicEffect::MDT_None ) { - sourcesDescription += ": " + boost::lexical_cast(effectIt->mMagnitude); + sourcesDescription += ": " + MyGUI::utility::toString(effectIt->mMagnitude); if ( displayType == ESM::MagicEffect::MDT_Percentage ) sourcesDescription += MWBase::Environment::get().getWindowManager()->getGameSettingString("spercent", ""); diff --git a/apps/openmw/mwgui/statswindow.cpp b/apps/openmw/mwgui/statswindow.cpp index e565b6f0e..b5abf91fd 100644 --- a/apps/openmw/mwgui/statswindow.cpp +++ b/apps/openmw/mwgui/statswindow.cpp @@ -6,8 +6,6 @@ #include #include -#include - #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" @@ -151,7 +149,7 @@ namespace MWGui // health, magicka, fatigue tooltip MyGUI::Widget* w; - std::string valStr = boost::lexical_cast(current) + "/" + boost::lexical_cast(modified); + std::string valStr = MyGUI::utility::toString(current) + "/" + MyGUI::utility::toString(modified); if (id == "HBar") { getWidget(w, "Health"); @@ -196,7 +194,7 @@ namespace MWGui if (widget) { int modified = value.getModified(), base = value.getBase(); - std::string text = boost::lexical_cast(modified); + std::string text = MyGUI::utility::toString(modified); std::string state = "normal"; if (modified > base) state = "increased"; @@ -245,10 +243,10 @@ namespace MWGui { int max = MWBase::Environment::get().getWorld()->getStore().get().find("iLevelUpTotal")->getInt(); getWidget(levelWidget, i==0 ? "Level_str" : "LevelText"); - levelWidget->setUserString("RangePosition_LevelProgress", boost::lexical_cast(PCstats.getLevelProgress())); - levelWidget->setUserString("Range_LevelProgress", boost::lexical_cast(max)); - levelWidget->setUserString("Caption_LevelProgressText", boost::lexical_cast(PCstats.getLevelProgress()) + "/" - + boost::lexical_cast(max)); + levelWidget->setUserString("RangePosition_LevelProgress", MyGUI::utility::toString(PCstats.getLevelProgress())); + levelWidget->setUserString("Range_LevelProgress", MyGUI::utility::toString(max)); + levelWidget->setUserString("Caption_LevelProgressText", MyGUI::utility::toString(PCstats.getLevelProgress()) + "/" + + MyGUI::utility::toString(max)); } setFactions(PCstats.getFactionRanks()); @@ -403,7 +401,7 @@ namespace MWGui else if (modified < base) state = "decreased"; MyGUI::TextBox* widget = addValueItem(MWBase::Environment::get().getWindowManager()->getGameSettingString(skillNameId, skillNameId), - boost::lexical_cast(static_cast(modified)), state, coord1, coord2); + MyGUI::utility::toString(static_cast(modified)), state, coord1, coord2); for (int i=0; i<2; ++i) { @@ -421,9 +419,9 @@ namespace MWGui mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Visible_SkillProgressVBox", "true"); mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("UserData^Hidden_SkillProgressVBox", "false"); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_SkillProgressText", boost::lexical_cast(progressPercent)+"/100"); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_SkillProgressText", MyGUI::utility::toString(progressPercent)+"/100"); mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Range_SkillProgress", "100"); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("RangePosition_SkillProgress", boost::lexical_cast(progressPercent)); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("RangePosition_SkillProgress", MyGUI::utility::toString(progressPercent)); } else { mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Visible_SkillMaxed", "true"); mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("UserData^Hidden_SkillMaxed", "false"); @@ -534,8 +532,8 @@ namespace MWGui const ESM::Attribute* attr1 = store.get().find(faction->mData.mAttribute[0]); const ESM::Attribute* attr2 = store.get().find(faction->mData.mAttribute[1]); - text += "\n#{fontcolourhtml=normal}#{" + attr1->mName + "}: " + boost::lexical_cast(rankData.mAttribute1) - + ", #{" + attr2->mName + "}: " + boost::lexical_cast(rankData.mAttribute2); + text += "\n#{fontcolourhtml=normal}#{" + attr1->mName + "}: " + MyGUI::utility::toString(rankData.mAttribute1) + + ", #{" + attr2->mName + "}: " + MyGUI::utility::toString(rankData.mAttribute2); text += "\n\n#{fontcolourhtml=header}#{sFavoriteSkills}"; text += "\n#{fontcolourhtml=normal}"; @@ -556,9 +554,9 @@ namespace MWGui text += "\n"; if (rankData.mSkill1 > 0) - text += "\n#{sNeedOneSkill} " + boost::lexical_cast(rankData.mSkill1); + text += "\n#{sNeedOneSkill} " + MyGUI::utility::toString(rankData.mSkill1); if (rankData.mSkill2 > 0) - text += "\n#{sNeedTwoSkills} " + boost::lexical_cast(rankData.mSkill2); + text += "\n#{sNeedTwoSkills} " + MyGUI::utility::toString(rankData.mSkill2); } } @@ -587,7 +585,7 @@ namespace MWGui addSeparator(coord1, coord2); addValueItem(MWBase::Environment::get().getWindowManager()->getGameSettingString("sReputation", "Reputation"), - boost::lexical_cast(static_cast(mReputation)), "normal", coord1, coord2); + MyGUI::utility::toString(static_cast(mReputation)), "normal", coord1, coord2); for (int i=0; i<2; ++i) { @@ -597,7 +595,7 @@ namespace MWGui } addValueItem(MWBase::Environment::get().getWindowManager()->getGameSettingString("sBounty", "Bounty"), - boost::lexical_cast(static_cast(mBounty)), "normal", coord1, coord2); + MyGUI::utility::toString(static_cast(mBounty)), "normal", coord1, coord2); for (int i=0; i<2; ++i) { diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 3f3540a21..303b8819f 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -7,8 +7,6 @@ #include #include -#include - #include #include "../mwbase/world.hpp" @@ -556,7 +554,7 @@ namespace MWGui if (value == 1) return ""; else - return " (" + boost::lexical_cast(value) + ")"; + return " (" + MyGUI::utility::toString(value) + ")"; } std::string ToolTips::getCellRefString(const MWWorld::CellRef& cellref) diff --git a/apps/openmw/mwgui/trainingwindow.cpp b/apps/openmw/mwgui/trainingwindow.cpp index fc9167f3c..88ba62cc1 100644 --- a/apps/openmw/mwgui/trainingwindow.cpp +++ b/apps/openmw/mwgui/trainingwindow.cpp @@ -1,7 +1,5 @@ #include "trainingwindow.hpp" -#include - #include #include "../mwbase/windowmanager.hpp" @@ -67,7 +65,7 @@ namespace MWGui MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); int playerGold = player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId); - mPlayerGold->setCaptionWithReplacing("#{sGold}: " + boost::lexical_cast(playerGold)); + mPlayerGold->setCaptionWithReplacing("#{sGold}: " + MyGUI::utility::toString(playerGold)); MWMechanics::NpcStats& npcStats = actor.getClass().getNpcStats (actor); @@ -102,7 +100,7 @@ namespace MWGui button->setUserData(skills[i].first); button->eventMouseButtonClick += MyGUI::newDelegate(this, &TrainingWindow::onTrainingSelected); - button->setCaptionWithReplacing("#{" + ESM::Skill::sSkillNameIds[skills[i].first] + "} - " + boost::lexical_cast(price)); + button->setCaptionWithReplacing("#{" + ESM::Skill::sSkillNameIds[skills[i].first] + "} - " + MyGUI::utility::toString(price)); button->setSize(button->getTextSize ().width+12, button->getSize().height); diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index 3d37d0ab0..50e08223e 100644 --- a/apps/openmw/mwgui/travelwindow.cpp +++ b/apps/openmw/mwgui/travelwindow.cpp @@ -1,7 +1,5 @@ #include "travelwindow.hpp" -#include - #include #include #include @@ -91,7 +89,7 @@ namespace MWGui oss << price; toAdd->setUserString("price",oss.str()); - toAdd->setCaptionWithReplacing("#{sCell=" + name + "} - " + boost::lexical_cast(price)+"#{sgp}"); + toAdd->setCaptionWithReplacing("#{sCell=" + name + "} - " + MyGUI::utility::toString(price)+"#{sgp}"); toAdd->setSize(toAdd->getTextSize().width,sLineHeight); toAdd->eventMouseWheel += MyGUI::newDelegate(this, &TravelWindow::onMouseWheel); toAdd->setUserString("Destination", name); @@ -196,7 +194,7 @@ namespace MWGui MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayerPtr(); int playerGold = player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId); - mPlayerGold->setCaptionWithReplacing("#{sGold}: " + boost::lexical_cast(playerGold)); + mPlayerGold->setCaptionWithReplacing("#{sGold}: " + MyGUI::utility::toString(playerGold)); mPlayerGold->setCoord(8, mPlayerGold->getTop(), mPlayerGold->getTextSize().width, diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index 6f87bffe0..c53a887c9 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -1,7 +1,5 @@ #include "waitdialog.hpp" -#include - #include #include @@ -40,7 +38,7 @@ namespace MWGui { mProgressBar->setProgressRange (total); mProgressBar->setProgressPosition (cur); - mProgressText->setCaption(boost::lexical_cast(cur) + "/" + boost::lexical_cast(total)); + mProgressText->setCaption(MyGUI::utility::toString(cur) + "/" + MyGUI::utility::toString(total)); } // --------------------------------------------------------------------------------------------------------- @@ -106,9 +104,9 @@ namespace MWGui if (hour == 0) hour = 12; std::string dateTimeText = - boost::lexical_cast(MWBase::Environment::get().getWorld ()->getDay ()) + " " - + month + " (#{sDay} " + boost::lexical_cast(MWBase::Environment::get().getWorld ()->getTimeStamp ().getDay()) - + ") " + boost::lexical_cast(hour) + " " + (pm ? "#{sSaveMenuHelp05}" : "#{sSaveMenuHelp04}"); + MyGUI::utility::toString(MWBase::Environment::get().getWorld ()->getDay ()) + " " + + month + " (#{sDay} " + MyGUI::utility::toString(MWBase::Environment::get().getWorld ()->getTimeStamp ().getDay()) + + ") " + MyGUI::utility::toString(hour) + " " + (pm ? "#{sSaveMenuHelp05}" : "#{sSaveMenuHelp04}"); mDateTimeText->setCaptionWithReplacing (dateTimeText); } @@ -174,7 +172,7 @@ namespace MWGui void WaitDialog::onHourSliderChangedPosition(MyGUI::ScrollBar* sender, size_t position) { - mHourText->setCaptionWithReplacing (boost::lexical_cast(position+1) + " #{sRestMenu2}"); + mHourText->setCaptionWithReplacing (MyGUI::utility::toString(position+1) + " #{sRestMenu2}"); mManualHours = position+1; } diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index 381fc301e..26fe31567 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -3,8 +3,6 @@ #include #include -#include - #include #include #include @@ -74,7 +72,7 @@ namespace MWGui if (mSkillValueWidget) { SkillValue::Type modified = mValue.getModified(), base = mValue.getBase(); - mSkillValueWidget->setCaption(boost::lexical_cast(modified)); + mSkillValueWidget->setCaption(MyGUI::utility::toString(modified)); if (modified > base) mSkillValueWidget->_setWidgetState("increased"); else if (modified < base) @@ -170,7 +168,7 @@ namespace MWGui if (mAttributeValueWidget) { int modified = mValue.getModified(), base = mValue.getBase(); - mAttributeValueWidget->setCaption(boost::lexical_cast(modified)); + mAttributeValueWidget->setCaption(MyGUI::utility::toString(modified)); if (modified > base) mAttributeValueWidget->_setWidgetState("increased"); else if (modified < base) @@ -432,9 +430,9 @@ namespace MWGui spellLine += formatter.str(); } else if ( displayType != ESM::MagicEffect::MDT_None ) { - spellLine += " " + boost::lexical_cast(mEffectParams.mMagnMin); + spellLine += " " + MyGUI::utility::toString(mEffectParams.mMagnMin); if (mEffectParams.mMagnMin != mEffectParams.mMagnMax) - spellLine += to + boost::lexical_cast(mEffectParams.mMagnMax); + spellLine += to + MyGUI::utility::toString(mEffectParams.mMagnMax); if ( displayType == ESM::MagicEffect::MDT_Percentage ) spellLine += pct; @@ -452,12 +450,12 @@ namespace MWGui { if (mEffectParams.mDuration > 0 && !(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration)) { - spellLine += " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("sfor", "") + " " + boost::lexical_cast(mEffectParams.mDuration) + ((mEffectParams.mDuration == 1) ? sec : secs); + spellLine += " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("sfor", "") + " " + MyGUI::utility::toString(mEffectParams.mDuration) + ((mEffectParams.mDuration == 1) ? sec : secs); } if (mEffectParams.mArea > 0) { - spellLine += " #{sin} " + boost::lexical_cast(mEffectParams.mArea) + " #{sfootarea}"; + spellLine += " #{sin} " + MyGUI::utility::toString(mEffectParams.mArea) + " #{sfootarea}"; } // potions have no target From 063388e0eb6113d617a437ec5ef0f52fb601cdc1 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sat, 10 Jan 2015 15:04:45 +1300 Subject: [PATCH 0248/3725] Change "Profile" to "Content List" in user visible strings in Launcher. (Fixes #810) --- apps/launcher/datafilespage.cpp | 10 +++++----- apps/launcher/settingspage.cpp | 2 +- files/ui/datafilespage.ui | 18 +++++++++--------- files/ui/playpage.ui | 2 +- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index a0ef97ff9..8fca73c89 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -30,7 +30,7 @@ Launcher::DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, Config: setObjectName ("DataFilesPage"); mSelector = new ContentSelectorView::ContentSelector (ui.contentSelectorWidget); - mProfileDialog = new TextInputDialog(tr("New Profile"), tr("Profile name:"), this); + mProfileDialog = new TextInputDialog(tr("New Content List"), tr("Content List name:"), this); connect(mProfileDialog->lineEdit(), SIGNAL(textChanged(QString)), this, SLOT(updateOkButton(QString))); @@ -44,12 +44,12 @@ void Launcher::DataFilesPage::buildView() ui.verticalLayout->insertWidget (0, mSelector->uiWidget()); //tool buttons - ui.newProfileButton->setToolTip ("Create a new profile"); - ui.deleteProfileButton->setToolTip ("Delete an existing profile"); + ui.newProfileButton->setToolTip ("Create a new Content List"); + ui.deleteProfileButton->setToolTip ("Delete an existing Content List"); //combo box ui.profilesComboBox->addItem ("Default"); - ui.profilesComboBox->setPlaceholderText (QString("Select a profile...")); + ui.profilesComboBox->setPlaceholderText (QString("Select a Content List...")); ui.profilesComboBox->setCurrentIndex(ui.profilesComboBox->findText(QLatin1String("Default"))); // Add the actions to the toolbuttons @@ -306,7 +306,7 @@ void Launcher::DataFilesPage::checkForDefaultProfile() bool Launcher::DataFilesPage::showDeleteMessageBox (const QString &text) { QMessageBox msgBox(this); - msgBox.setWindowTitle(tr("Delete Profile")); + msgBox.setWindowTitle(tr("Delete Content List")); msgBox.setIcon(QMessageBox::Warning); msgBox.setStandardButtons(QMessageBox::Cancel); msgBox.setText(tr("Are you sure you want to delete %0?").arg(text)); diff --git a/apps/launcher/settingspage.cpp b/apps/launcher/settingspage.cpp index 5422e7957..26908746b 100644 --- a/apps/launcher/settingspage.cpp +++ b/apps/launcher/settingspage.cpp @@ -51,7 +51,7 @@ Launcher::SettingsPage::SettingsPage(Files::ConfigurationManager &cfg, connect(mImporterInvoker->getProcess(), SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(importerFinished(int,QProcess::ExitStatus))); - mProfileDialog = new TextInputDialog(tr("New Profile"), tr("Profile name:"), this); + mProfileDialog = new TextInputDialog(tr("New Content List"), tr("Content List name:"), this); connect(mProfileDialog->lineEdit(), SIGNAL(textChanged(QString)), this, SLOT(updateOkButton(QString))); diff --git a/files/ui/datafilespage.ui b/files/ui/datafilespage.ui index eb5ebc61d..5a6b7265a 100644 --- a/files/ui/datafilespage.ui +++ b/files/ui/datafilespage.ui @@ -29,7 +29,7 @@ Qt::NoFocus
- Profile + Content List false @@ -69,10 +69,10 @@ - New Profile + New Content List - &New Profile + &New Content List true @@ -82,10 +82,10 @@ - Delete Profile + Delete Content List - Delete Profile + Delete Content List Ctrl+D @@ -106,10 +106,10 @@ - New Profile + New Content List - New Profile + New Content List Ctrl+N @@ -125,10 +125,10 @@ - Delete Profile + Delete Content List - Delete Profile + Delete Content List diff --git a/files/ui/playpage.ui b/files/ui/playpage.ui index bf883b96e..1d529e2d7 100644 --- a/files/ui/playpage.ui +++ b/files/ui/playpage.ui @@ -101,7 +101,7 @@
- Current Profile: + Current Content List:
From 5b9d10f85156a41581ea29bbcbc9e5ce2f3e48b5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 10 Jan 2015 03:56:06 +0100 Subject: [PATCH 0249/3725] Reduce includes in MWGui --- apps/openmw/mwgui/birth.hpp | 5 ----- apps/openmw/mwgui/class.hpp | 5 ----- apps/openmw/mwgui/companionwindow.cpp | 1 + apps/openmw/mwgui/dialogue.hpp | 5 ----- apps/openmw/mwgui/enchantingdialog.cpp | 5 +++++ apps/openmw/mwgui/hud.hpp | 6 +++++- apps/openmw/mwgui/journalwindow.hpp | 1 - apps/openmw/mwgui/loadingscreen.cpp | 1 + apps/openmw/mwgui/loadingscreen.hpp | 7 ++++++- apps/openmw/mwgui/merchantrepair.hpp | 2 -- apps/openmw/mwgui/messagebox.cpp | 1 + apps/openmw/mwgui/messagebox.hpp | 2 -- apps/openmw/mwgui/race.cpp | 6 ++++++ apps/openmw/mwgui/race.hpp | 17 ++++++++++------- apps/openmw/mwgui/recharge.hpp | 5 ++++- apps/openmw/mwgui/review.hpp | 5 ----- apps/openmw/mwgui/scrollwindow.cpp | 1 + apps/openmw/mwgui/scrollwindow.hpp | 7 +++++-- apps/openmw/mwgui/soulgemdialog.cpp | 1 + apps/openmw/mwgui/spellcreationdialog.cpp | 2 ++ apps/openmw/mwgui/spellcreationdialog.hpp | 7 +++++-- apps/openmw/mwgui/statswindow.cpp | 1 + apps/openmw/mwgui/statswindow.hpp | 4 ++-- apps/openmw/mwgui/waitdialog.cpp | 2 ++ apps/openmw/mwgui/waitdialog.hpp | 6 +++++- apps/openmw/mwgui/windowmanagerimp.cpp | 2 ++ 26 files changed, 65 insertions(+), 42 deletions(-) diff --git a/apps/openmw/mwgui/birth.hpp b/apps/openmw/mwgui/birth.hpp index 257dc6fef..0a84bb4e9 100644 --- a/apps/openmw/mwgui/birth.hpp +++ b/apps/openmw/mwgui/birth.hpp @@ -3,11 +3,6 @@ #include "windowbase.hpp" -/* - This file contains the dialog for choosing a birth sign. - Layout is defined by resources/mygui/openmw_chargen_race.layout. - */ - namespace MWGui { class BirthDialog : public WindowModal diff --git a/apps/openmw/mwgui/class.hpp b/apps/openmw/mwgui/class.hpp index 9d529ece0..e36a9a98b 100644 --- a/apps/openmw/mwgui/class.hpp +++ b/apps/openmw/mwgui/class.hpp @@ -6,11 +6,6 @@ #include "widgets.hpp" #include "windowbase.hpp" -/* - This file contains the dialogs for choosing a class. - Layout is defined by resources/mygui/openmw_chargen_class.layout. - */ - namespace MWGui { class InfoBoxDialog : public WindowModal diff --git a/apps/openmw/mwgui/companionwindow.cpp b/apps/openmw/mwgui/companionwindow.cpp index 758316030..53b14691b 100644 --- a/apps/openmw/mwgui/companionwindow.cpp +++ b/apps/openmw/mwgui/companionwindow.cpp @@ -4,6 +4,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/dialoguemanager.hpp" +#include "../mwbase/windowmanager.hpp" #include "../mwmechanics/npcstats.hpp" diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index 4ab88c06f..769c32af7 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -18,11 +18,6 @@ namespace MWGui class WindowManager; } -/* - This file contains the dialouge window - Layout is defined by resources/mygui/openmw_dialogue_window.layout. - */ - namespace MWGui { class DialogueHistoryViewModel; diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index a17c0d0e6..3376858c1 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -3,7 +3,12 @@ #include #include + +#include +#include + #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" diff --git a/apps/openmw/mwgui/hud.hpp b/apps/openmw/mwgui/hud.hpp index ca68d907a..41a535a08 100644 --- a/apps/openmw/mwgui/hud.hpp +++ b/apps/openmw/mwgui/hud.hpp @@ -4,7 +4,11 @@ #include "mapwindow.hpp" #include "../mwmechanics/stat.hpp" -#include "../mwworld/ptr.hpp" + +namespace MWWorld +{ + class Ptr; +} namespace MWGui { diff --git a/apps/openmw/mwgui/journalwindow.hpp b/apps/openmw/mwgui/journalwindow.hpp index 63770ec1a..5d2a5318a 100644 --- a/apps/openmw/mwgui/journalwindow.hpp +++ b/apps/openmw/mwgui/journalwindow.hpp @@ -1,7 +1,6 @@ #ifndef MWGUI_JOURNAL_H #define MWGUI_JOURNAL_H -#include #include namespace MWBase { class WindowManager; } diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index 855a6fc84..d10a295c1 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include diff --git a/apps/openmw/mwgui/loadingscreen.hpp b/apps/openmw/mwgui/loadingscreen.hpp index 892710433..0d3ffbbec 100644 --- a/apps/openmw/mwgui/loadingscreen.hpp +++ b/apps/openmw/mwgui/loadingscreen.hpp @@ -1,13 +1,18 @@ #ifndef MWGUI_LOADINGSCREEN_H #define MWGUI_LOADINGSCREEN_H -#include #include +#include #include "windowbase.hpp" #include +namespace Ogre +{ + class SceneManager; +} + namespace MWGui { class BackgroundImage; diff --git a/apps/openmw/mwgui/merchantrepair.hpp b/apps/openmw/mwgui/merchantrepair.hpp index 2f1387365..231d11089 100644 --- a/apps/openmw/mwgui/merchantrepair.hpp +++ b/apps/openmw/mwgui/merchantrepair.hpp @@ -4,8 +4,6 @@ #include "windowbase.hpp" #include "../mwworld/ptr.hpp" - - namespace MWGui { diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index 43debd0e5..c45136eb3 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -10,6 +10,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwbase/inputmanager.hpp" +#include "../mwbase/windowmanager.hpp" namespace MWGui { diff --git a/apps/openmw/mwgui/messagebox.hpp b/apps/openmw/mwgui/messagebox.hpp index 5f180df20..59804e097 100644 --- a/apps/openmw/mwgui/messagebox.hpp +++ b/apps/openmw/mwgui/messagebox.hpp @@ -3,8 +3,6 @@ #include "windowbase.hpp" -#include "../mwbase/windowmanager.hpp" - #undef MessageBox namespace MyGUI diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index f6aa8ee4c..b03bf758a 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -11,6 +11,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwrender/characterpreview.hpp" #include "tooltips.hpp" @@ -446,4 +447,9 @@ namespace MWGui ++i; } } + + const ESM::NPC& RaceDialog::getResult() const + { + return mPreview->getPrototype(); + } } diff --git a/apps/openmw/mwgui/race.hpp b/apps/openmw/mwgui/race.hpp index 454c1d0b6..be16af5d1 100644 --- a/apps/openmw/mwgui/race.hpp +++ b/apps/openmw/mwgui/race.hpp @@ -1,8 +1,6 @@ #ifndef MWGUI_RACE_H #define MWGUI_RACE_H -#include "../mwrender/characterpreview.hpp" - #include "windowbase.hpp" @@ -11,10 +9,15 @@ namespace MWGui class WindowManager; } -/* - This file contains the dialog for choosing a race. - Layout is defined by resources/mygui/openmw_chargen_race.layout. - */ +namespace MWRender +{ + class RaceSelectionPreview; +} + +namespace ESM +{ + struct NPC; +} namespace MWGui { @@ -29,7 +32,7 @@ namespace MWGui GM_Female }; - const ESM::NPC &getResult() const { return mPreview->getPrototype(); } + const ESM::NPC &getResult() const; const std::string &getRaceId() const { return mCurrentRaceId; } Gender getGender() const { return mGenderIndex == 0 ? GM_Male : GM_Female; } // getFace() diff --git a/apps/openmw/mwgui/recharge.hpp b/apps/openmw/mwgui/recharge.hpp index 17d700649..3e8e1269e 100644 --- a/apps/openmw/mwgui/recharge.hpp +++ b/apps/openmw/mwgui/recharge.hpp @@ -3,7 +3,10 @@ #include "windowbase.hpp" -#include "../mwworld/ptr.hpp" +namespace MWWorld +{ + class Ptr; +} namespace MWGui { diff --git a/apps/openmw/mwgui/review.hpp b/apps/openmw/mwgui/review.hpp index 1419925b5..111d7de1d 100644 --- a/apps/openmw/mwgui/review.hpp +++ b/apps/openmw/mwgui/review.hpp @@ -11,11 +11,6 @@ namespace MWGui class WindowManager; } -/* -This file contains the dialog for reviewing the generated character. -Layout is defined by resources/mygui/openmw_chargen_review.layout. -*/ - namespace MWGui { class ReviewDialog : public WindowModal diff --git a/apps/openmw/mwgui/scrollwindow.cpp b/apps/openmw/mwgui/scrollwindow.cpp index d49d5ad5f..d61693d39 100644 --- a/apps/openmw/mwgui/scrollwindow.cpp +++ b/apps/openmw/mwgui/scrollwindow.cpp @@ -3,6 +3,7 @@ #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" diff --git a/apps/openmw/mwgui/scrollwindow.hpp b/apps/openmw/mwgui/scrollwindow.hpp index 08ce6a905..e1f86529a 100644 --- a/apps/openmw/mwgui/scrollwindow.hpp +++ b/apps/openmw/mwgui/scrollwindow.hpp @@ -3,10 +3,13 @@ #include "windowbase.hpp" -#include - #include "../mwworld/ptr.hpp" +namespace Gui +{ + class ImageButton; +} + namespace MWGui { class ScrollWindow : public WindowBase diff --git a/apps/openmw/mwgui/soulgemdialog.cpp b/apps/openmw/mwgui/soulgemdialog.cpp index 6d70c85d9..0232eb7b3 100644 --- a/apps/openmw/mwgui/soulgemdialog.cpp +++ b/apps/openmw/mwgui/soulgemdialog.cpp @@ -1,6 +1,7 @@ #include "soulgemdialog.hpp" #include "../mwbase/environment.hpp" +#include "../mwbase/windowmanager.hpp" #include "messagebox.hpp" diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index 1ff379c0b..a00afdab8 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -5,6 +5,7 @@ #include #include +#include #include "../mwbase/windowmanager.hpp" #include "../mwbase/soundmanager.hpp" @@ -22,6 +23,7 @@ #include "tooltips.hpp" #include "class.hpp" +#include "widgets.hpp" namespace { diff --git a/apps/openmw/mwgui/spellcreationdialog.hpp b/apps/openmw/mwgui/spellcreationdialog.hpp index 72e581c87..6cdf74d10 100644 --- a/apps/openmw/mwgui/spellcreationdialog.hpp +++ b/apps/openmw/mwgui/spellcreationdialog.hpp @@ -3,11 +3,14 @@ #include #include -#include #include "windowbase.hpp" #include "referenceinterface.hpp" -#include "widgets.hpp" + +namespace Gui +{ + class MWList; +} namespace MWGui { diff --git a/apps/openmw/mwgui/statswindow.cpp b/apps/openmw/mwgui/statswindow.cpp index b5abf91fd..19f9c749c 100644 --- a/apps/openmw/mwgui/statswindow.cpp +++ b/apps/openmw/mwgui/statswindow.cpp @@ -12,6 +12,7 @@ #include "../mwworld/class.hpp" #include "../mwworld/player.hpp" +#include "../mwworld/esmstore.hpp" #include "../mwmechanics/npcstats.hpp" diff --git a/apps/openmw/mwgui/statswindow.hpp b/apps/openmw/mwgui/statswindow.hpp index f41995ac0..2cf4ca819 100644 --- a/apps/openmw/mwgui/statswindow.hpp +++ b/apps/openmw/mwgui/statswindow.hpp @@ -1,11 +1,11 @@ #ifndef MWGUI_STATS_WINDOW_H #define MWGUI_STATS_WINDOW_H -#include "../mwworld/esmstore.hpp" - #include "../mwmechanics/stat.hpp" #include "windowpinnablebase.hpp" +#include + namespace MWGui { class WindowManager; diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index c53a887c9..718e04e52 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -19,6 +19,8 @@ #include "../mwstate/charactermanager.hpp" +#include "widgets.hpp" + namespace MWGui { diff --git a/apps/openmw/mwgui/waitdialog.hpp b/apps/openmw/mwgui/waitdialog.hpp index 1cf05bb06..435c1cb54 100644 --- a/apps/openmw/mwgui/waitdialog.hpp +++ b/apps/openmw/mwgui/waitdialog.hpp @@ -2,11 +2,15 @@ #define MWGUI_WAIT_DIALOG_H #include "windowbase.hpp" -#include "widgets.hpp" namespace MWGui { + namespace Widgets + { + class MWScrollBar; + } + class WaitDialogProgressBar : public WindowBase { public: diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index aa80e69fc..5d737ec41 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include @@ -34,6 +35,7 @@ #include "../mwworld/class.hpp" #include "../mwworld/player.hpp" #include "../mwworld/cellstore.hpp" +#include "../mwworld/esmstore.hpp" #include "../mwmechanics/npcstats.hpp" From 05b89be8bfc19a653287a90b05eb54f63b8a5609 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sat, 10 Jan 2015 18:46:47 +1300 Subject: [PATCH 0250/3725] Launcher sets content list to match values in openmw.cfg (Fixes #811) I took the liberty to add accessor & mutator functions for classes ContentListsGameSettings and LauncherSettings , as existing code can reverse order of entries. Also replaced some "magic strings" with named constants. --- apps/launcher/datafilespage.cpp | 31 +++--- apps/launcher/maindialog.cpp | 10 +- apps/launcher/settingspage.cpp | 17 +--- apps/wizard/mainwizard.cpp | 4 +- components/config/gamesettings.cpp | 30 ++++-- components/config/gamesettings.hpp | 7 +- components/config/launchersettings.cpp | 134 +++++++++++++++++++++---- components/config/launchersettings.hpp | 43 +++++++- components/config/settingsbase.hpp | 4 +- 9 files changed, 207 insertions(+), 73 deletions(-) diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index 8fca73c89..8429aaadc 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -82,8 +82,8 @@ bool Launcher::DataFilesPage::loadSettings() paths.insert (0, mDataLocal); PathIterator pathIterator (paths); - QStringList profiles = mLauncherSettings.subKeys(QString("Profiles/")); - QString currentProfile = mLauncherSettings.getSettings().value("Profiles/currentprofile"); + QStringList profiles = mLauncherSettings.getContentLists(); + QString currentProfile = mLauncherSettings.getCurrentContentListName(); qDebug() << "current profile is: " << currentProfile; @@ -101,15 +101,12 @@ bool Launcher::DataFilesPage::loadSettings() QStringList Launcher::DataFilesPage::filesInProfile(const QString& profileName, PathIterator& pathIterator) { - QStringList files = mLauncherSettings.values(QString("Profiles/") + profileName + QString("/content"), Qt::MatchExactly); + QStringList files = mLauncherSettings.getContentListFiles(profileName); QStringList filepaths; - // mLauncherSettings.values() returns the files in reverse load order - QListIterator i(files); - i.toBack(); - while (i.hasPrevious()) + foreach(const QString& file, files) { - QString filepath = pathIterator.findFirstPath(i.previous()); + QString filepath = pathIterator.findFirstPath(file); if (!filepath.isEmpty()) filepaths << filepath; @@ -128,24 +125,20 @@ void Launcher::DataFilesPage::saveSettings(const QString &profile) //retrieve the files selected for the profile ContentSelectorModel::ContentFileList items = mSelector->selectedFiles(); - removeProfile (profileName); - - mGameSettings.remove(QString("content")); - //set the value of the current profile (not necessarily the profile being saved!) - mLauncherSettings.setValue(QString("Profiles/currentprofile"), ui.profilesComboBox->currentText()); + mLauncherSettings.setCurrentContentListName(ui.profilesComboBox->currentText()); + QStringList fileNames; foreach(const ContentSelectorModel::EsmFile *item, items) { - mLauncherSettings.setMultiValue(QString("Profiles/") + profileName + QString("/content"), item->fileName()); - mGameSettings.setMultiValue(QString("content"), item->fileName()); + fileNames.append(item->fileName()); } - + mLauncherSettings.setContentList(profileName, fileNames); + mGameSettings.setContentList(fileNames); } void Launcher::DataFilesPage::removeProfile(const QString &profile) { - mLauncherSettings.remove(QString("Profiles/") + profile); - mLauncherSettings.remove(QString("Profiles/") + profile + QString("/content")); + mLauncherSettings.removeContentList(profile); } QAbstractItemModel *Launcher::DataFilesPage::profilesModel() const @@ -233,7 +226,7 @@ void Launcher::DataFilesPage::on_newProfileAction_triggered() saveSettings(); - mLauncherSettings.setValue(QString("Profiles/currentprofile"), profile); + mLauncherSettings.setCurrentContentListName(profile); addProfile(profile, true); mSelector->clearCheckStates(); diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index 975958d7a..00c549969 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -209,6 +209,8 @@ bool Launcher::MainDialog::setup() if (!setupGameSettings()) return false; + mLauncherSettings.setContentList(mGameSettings); + if (!setupGraphicsSettings()) return false; @@ -232,6 +234,8 @@ bool Launcher::MainDialog::reloadSettings() if (!setupGameSettings()) return false; + mLauncherSettings.setContentList(mGameSettings); + if (!setupGraphicsSettings()) return false; @@ -280,8 +284,8 @@ bool Launcher::MainDialog::setupLauncherSettings() QString userPath = QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str()); QStringList paths; - paths.append(QString("launcher.cfg")); - paths.append(userPath + QString("launcher.cfg")); + paths.append(QString(Config::LauncherSettings::sLauncherConfigFileName)); + paths.append(userPath + QString(Config::LauncherSettings::sLauncherConfigFileName)); foreach (const QString &path, paths) { qDebug() << "Loading config file:" << qPrintable(path); @@ -562,7 +566,7 @@ bool Launcher::MainDialog::writeSettings() file.close(); // Launcher settings - file.setFileName(userPath + QString("launcher.cfg")); + file.setFileName(userPath + QString(Config::LauncherSettings::sLauncherConfigFileName)); if (!file.open(QIODevice::ReadWrite | QIODevice::Text | QIODevice::Truncate)) { // File cannot be opened or created diff --git a/apps/launcher/settingspage.cpp b/apps/launcher/settingspage.cpp index 26908746b..ace8f4310 100644 --- a/apps/launcher/settingspage.cpp +++ b/apps/launcher/settingspage.cpp @@ -207,18 +207,9 @@ void Launcher::SettingsPage::importerFinished(int exitCode, QProcess::ExitStatus if (mProfileDialog->exec() == QDialog::Accepted) { const QString profile(mProfileDialog->lineEdit()->text()); - const QStringList files(mGameSettings.values(QLatin1String("content"))); - - qDebug() << "Profile " << profile << files; - - // Doesn't quite work right now - mLauncherSettings.setValue(QLatin1String("Profiles/currentprofile"), profile); - - foreach (const QString &file, files) { - mLauncherSettings.setMultiValue(QLatin1String("Profiles/") + profile + QLatin1String("/content"), file); - } - - mGameSettings.remove(QLatin1String("content")); + const QStringList files(mGameSettings.getContentList()); + mLauncherSettings.setCurrentContentListName(profile); + mLauncherSettings.setContentList(profile, files); } } @@ -234,7 +225,7 @@ void Launcher::SettingsPage::updateOkButton(const QString &text) return; } - const QStringList profiles(mLauncherSettings.subKeys(QString("Profiles/"))); + const QStringList profiles(mLauncherSettings.getContentLists()); (profiles.contains(text)) ? mProfileDialog->setOkButtonEnabled(false) diff --git a/apps/wizard/mainwizard.cpp b/apps/wizard/mainwizard.cpp index e68070c4d..9a8ec2056 100644 --- a/apps/wizard/mainwizard.cpp +++ b/apps/wizard/mainwizard.cpp @@ -182,7 +182,7 @@ void Wizard::MainWizard::setupGameSettings() void Wizard::MainWizard::setupLauncherSettings() { QString path(QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str())); - path.append(QLatin1String("launcher.cfg")); + path.append(QLatin1String(Config::LauncherSettings::sLauncherConfigFileName)); QString message(tr("

Could not open %1 for reading

\

Please make sure you have the right permissions \ @@ -427,7 +427,7 @@ void Wizard::MainWizard::writeSettings() file.close(); // Launcher settings - file.setFileName(userPath + QLatin1String("launcher.cfg")); + file.setFileName(userPath + QLatin1String(Config::LauncherSettings::sLauncherConfigFileName)); if (!file.open(QIODevice::ReadWrite | QIODevice::Text | QIODevice::Truncate)) { // File cannot be opened or created diff --git a/components/config/gamesettings.cpp b/components/config/gamesettings.cpp index 1e7f716e2..0481235c7 100644 --- a/components/config/gamesettings.cpp +++ b/components/config/gamesettings.cpp @@ -1,4 +1,5 @@ #include "gamesettings.hpp" +#include "launchersettings.hpp" #include #include @@ -26,6 +27,7 @@ namespace boost } /* namespace boost */ #endif /* (BOOST_VERSION <= 104600) */ +const char Config::GameSettings::sContentKey[] = "content"; Config::GameSettings::GameSettings(Files::ConfigurationManager &cfg) : mCfgMgr(cfg) @@ -81,7 +83,7 @@ void Config::GameSettings::validatePaths() } } -QStringList Config::GameSettings::values(const QString &key, const QStringList &defaultValues) +QStringList Config::GameSettings::values(const QString &key, const QStringList &defaultValues) const { if (!mSettings.values(key).isEmpty()) return mSettings.values(key); @@ -149,9 +151,6 @@ bool Config::GameSettings::writeFile(QTextStream &stream) while (i.hasPrevious()) { i.previous(); - if (i.key() == QLatin1String("content")) - continue; - // Quote paths with spaces if (i.key() == QLatin1String("data") || i.key() == QLatin1String("data-local") @@ -171,18 +170,13 @@ bool Config::GameSettings::writeFile(QTextStream &stream) } - QStringList content = mUserSettings.values(QString("content")); - for (int i = content.count(); i--;) { - stream << "content=" << content.at(i) << "\n"; - } - return true; } bool Config::GameSettings::hasMaster() { bool result = false; - QStringList content = mSettings.values(QString("content")); + QStringList content = mSettings.values(QString(Config::GameSettings::sContentKey)); for (int i = 0; i < content.count(); ++i) { if (content.at(i).contains(".omwgame") || content.at(i).contains(".esm")) { result = true; @@ -192,3 +186,19 @@ bool Config::GameSettings::hasMaster() return result; } + +void Config::GameSettings::setContentList(const QStringList& fileNames) +{ + remove(sContentKey); + foreach(const QString& fileName, fileNames) + { + setMultiValue(sContentKey, fileName); + } +} + +QStringList Config::GameSettings::getContentList() const +{ + // QMap returns multiple rows in LIFO order, so need to reverse + return Config::LauncherSettings::reverse(values(sContentKey)); +} + diff --git a/components/config/gamesettings.hpp b/components/config/gamesettings.hpp index c4a6ead79..cc5033f35 100644 --- a/components/config/gamesettings.hpp +++ b/components/config/gamesettings.hpp @@ -59,7 +59,7 @@ namespace Config bool hasMaster(); - QStringList values(const QString &key, const QStringList &defaultValues = QStringList()); + QStringList values(const QString &key, const QStringList &defaultValues = QStringList()) const; bool readFile(QTextStream &stream); bool readFile(QTextStream &stream, QMap &settings); @@ -67,6 +67,9 @@ namespace Config bool writeFile(QTextStream &stream); + void setContentList(const QStringList& fileNames); + QStringList getContentList() const; + private: Files::ConfigurationManager &mCfgMgr; @@ -76,6 +79,8 @@ namespace Config QStringList mDataDirs; QString mDataLocal; + + static const char sContentKey[]; }; } #endif // GAMESETTINGS_HPP diff --git a/components/config/launchersettings.cpp b/components/config/launchersettings.cpp index c014579dc..66f05f691 100644 --- a/components/config/launchersettings.cpp +++ b/components/config/launchersettings.cpp @@ -7,6 +7,11 @@ #include +const char Config::LauncherSettings::sCurrentContentListKey[] = "Profiles/currentprofile"; +const char Config::LauncherSettings::sLauncherConfigFileName[] = "launcher.cfg"; +const char Config::LauncherSettings::sContentListsSectionPrefix[] = "Profiles/"; +const char Config::LauncherSettings::sContentListSuffix[] = "/content"; + Config::LauncherSettings::LauncherSettings() { } @@ -15,27 +20,6 @@ Config::LauncherSettings::~LauncherSettings() { } -QStringList Config::LauncherSettings::values(const QString &key, Qt::MatchFlags flags) -{ - QMap settings = SettingsBase::getSettings(); - - if (flags == Qt::MatchExactly) - return settings.values(key); - - QStringList result; - - if (flags == Qt::MatchStartsWith) { - QStringList keys = settings.keys(); - - foreach (const QString ¤tKey, keys) { - if (currentKey.startsWith(key)) - result.append(settings.value(currentKey)); - } - } - - return result; -} - QStringList Config::LauncherSettings::subKeys(const QString &key) { QMap settings = SettingsBase::getSettings(); @@ -66,6 +50,7 @@ QStringList Config::LauncherSettings::subKeys(const QString &key) return result; } + bool Config::LauncherSettings::writeFile(QTextStream &stream) { QString sectionPrefix; @@ -104,3 +89,110 @@ bool Config::LauncherSettings::writeFile(QTextStream &stream) return true; } + +QStringList Config::LauncherSettings::getContentLists() +{ + return subKeys(QString(sContentListsSectionPrefix)); +} + +QString Config::LauncherSettings::makeContentListKey(const QString& contentListName) +{ + return QString(sContentListsSectionPrefix) + contentListName + QString(sContentListSuffix); +} + +void Config::LauncherSettings::setContentList(const GameSettings& gameSettings) +{ + // obtain content list from game settings (if present) + const QStringList files(gameSettings.getContentList()); + + // if any existing profile in launcher matches the content list, make that profile the default + foreach(const QString &listName, getContentLists()) + { + if (isEqual(files, getContentListFiles(listName))) + { + setCurrentContentListName(listName); + return; + } + } + + // otherwise, add content list + QString newContentListName(makeNewContentListName()); + setCurrentContentListName(newContentListName); + setContentList(newContentListName, files); +} + +void Config::LauncherSettings::removeContentList(const QString &contentListName) +{ + remove(makeContentListKey(contentListName)); +} + +void Config::LauncherSettings::setCurrentContentListName(const QString &contentListName) +{ + remove(QString(sCurrentContentListKey)); + setValue(QString(sCurrentContentListKey), contentListName); +} + +void Config::LauncherSettings::setContentList(const QString& contentListName, const QStringList& fileNames) +{ + removeContentList(contentListName); + QString key = makeContentListKey(contentListName); + foreach(const QString& fileName, fileNames) + { + setMultiValue(key, fileName); + } +} + +QString Config::LauncherSettings::getCurrentContentListName() const +{ + return value(QString(sCurrentContentListKey)); +} + +QStringList Config::LauncherSettings::getContentListFiles(const QString& contentListName) const +{ + // QMap returns multiple rows in LIFO order, so need to reverse + return reverse(getSettings().values(makeContentListKey(contentListName))); +} + +QStringList Config::LauncherSettings::reverse(const QStringList& toReverse) +{ + QStringList result; + result.reserve(toReverse.size()); + std::reverse_copy(toReverse.begin(), toReverse.end(), std::back_inserter(result)); + return result; +} + +bool Config::LauncherSettings::isEqual(const QStringList& list1, const QStringList& list2) +{ + if (list1.count() != list2.count()) + { + return false; + } + + for (int i = 0; i < list1.count(); ++i) + { + if (list1.at(i) != list2.at(i)) + { + return false; + } + } + + // if get here, lists are same + return true; +} + +QString Config::LauncherSettings::makeNewContentListName() +{ + // basically, use date and time as the name e.g. YYYY-MM-DDThh:mm:ss + time_t rawtime; + struct tm * timeinfo; + + time(&rawtime); + timeinfo = localtime(&rawtime); + int base = 10; + QChar zeroPad('0'); + return QString("%1-%2-%3T%4:%5:%6") + .arg(timeinfo->tm_year + 1900, 4).arg(timeinfo->tm_mon + 1, 2, base, zeroPad).arg(timeinfo->tm_mday, 2, base, zeroPad) + .arg(timeinfo->tm_hour, 2, base, zeroPad).arg(timeinfo->tm_min, 2, base, zeroPad).arg(timeinfo->tm_sec, 2, base, zeroPad); +} + + diff --git a/components/config/launchersettings.hpp b/components/config/launchersettings.hpp index 042823ca9..cbe21c54a 100644 --- a/components/config/launchersettings.hpp +++ b/components/config/launchersettings.hpp @@ -2,6 +2,7 @@ #define LAUNCHERSETTINGS_HPP #include "settingsbase.hpp" +#include "gamesettings.hpp" namespace Config { @@ -11,11 +12,49 @@ namespace Config LauncherSettings(); ~LauncherSettings(); + bool writeFile(QTextStream &stream); + + /// \return names of all Content Lists in the launcher's .cfg file. + QStringList getContentLists(); + + /// Set initally selected content list to match values from openmw.cfg, creating if necessary + void setContentList(const GameSettings& gameSettings); + + /// Create a Content List (or replace if it already exists) + void setContentList(const QString& contentListName, const QStringList& fileNames); + + void removeContentList(const QString &contentListName); + + void setCurrentContentListName(const QString &contentListName); + + QString getCurrentContentListName() const; + + QStringList getContentListFiles(const QString& contentListName) const; + + /// \return new list that is reversed order of input + static QStringList reverse(const QStringList& toReverse); + + static const char sLauncherConfigFileName[]; + + private: + + /// \return key to use to get/set the files in the specified Content List + static QString makeContentListKey(const QString& contentListName); + + /// \return true if both lists are same + static bool isEqual(const QStringList& list1, const QStringList& list2); + + static QString makeNewContentListName(); + QStringList subKeys(const QString &key); - QStringList values(const QString &key, Qt::MatchFlags flags = Qt::MatchExactly); - bool writeFile(QTextStream &stream); + /// name of entry in launcher.cfg that holds name of currently selected Content List + static const char sCurrentContentListKey[]; + + /// section of launcher.cfg holding the Content Lists + static const char sContentListsSectionPrefix[]; + static const char sContentListSuffix[]; }; } #endif // LAUNCHERSETTINGS_HPP diff --git a/components/config/settingsbase.hpp b/components/config/settingsbase.hpp index e6b0908e0..c798d2893 100644 --- a/components/config/settingsbase.hpp +++ b/components/config/settingsbase.hpp @@ -17,7 +17,7 @@ namespace Config SettingsBase() { mMultiValue = false; } ~SettingsBase() {} - inline QString value(const QString &key, const QString &defaultValue = QString()) + inline QString value(const QString &key, const QString &defaultValue = QString()) const { return mSettings.value(key).isEmpty() ? defaultValue : mSettings.value(key); } @@ -46,7 +46,7 @@ namespace Config mSettings.remove(key); } - Map getSettings() {return mSettings;} + Map getSettings() const {return mSettings;} bool readFile(QTextStream &stream) { From 320b994aef7ed7f0df3987c4ffc909aa287e9059 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 10 Jan 2015 12:35:59 +0100 Subject: [PATCH 0251/3725] keep original cell field empty, if reference is in modified --- apps/opencs/model/world/refcollection.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/world/refcollection.cpp b/apps/opencs/model/world/refcollection.cpp index 19dfae57d..dcb295626 100644 --- a/apps/opencs/model/world/refcollection.cpp +++ b/apps/opencs/model/world/refcollection.cpp @@ -23,10 +23,13 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool while (ESM::Cell::getNextRef (reader, ref, deleted)) { - ref.mOriginalCell = cell2.mId; + // Keep mOriginalCell empty when in modified (as an indicator that the + // original cell will always be equal the current cell). + ref.mOriginalCell = base ? cell2.mId : ""; if (cell.get().isExterior()) { + // ignoring moved references sub-record; instead calculate cell from coordinates std::pair index = ref.getCellIndex(); From 37bea9d4dc16bbefc70f66128abff9d6b51d89c8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 10 Jan 2015 15:06:30 +0100 Subject: [PATCH 0252/3725] Fix exception for empty dialog topics (Fixes #2267) --- apps/openmw/mwdialogue/keywordsearch.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwdialogue/keywordsearch.hpp b/apps/openmw/mwdialogue/keywordsearch.hpp index c44139f32..0bb3616d9 100644 --- a/apps/openmw/mwdialogue/keywordsearch.hpp +++ b/apps/openmw/mwdialogue/keywordsearch.hpp @@ -28,6 +28,8 @@ public: void seed (string_t keyword, value_t value) { + if (keyword.empty()) + return; seed_impl (/*std::move*/ (keyword), /*std::move*/ (value), 0, mRoot); } From 412496e28cc1d20f88cbe5eec65380cae44e1253 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 17 Dec 2014 23:19:37 +0100 Subject: [PATCH 0253/3725] Enable coverity scan for Travis CI --- .travis.yml | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 233117718..c5ed43543 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,6 +6,22 @@ branches: only: - master - /openmw-.*$/ +env: + global: + # The next declaration is the encrypted COVERITY_SCAN_TOKEN, created + # via the "travis encrypt" command using the project repo's public key + - secure: "CcQGmzgaBRTPWqPZLoLX4Zkt5pOQb5c6Pr5OFt15C8xQRhWOLrWcdsQEO1UuEJ70/YJgbvN+wQk8B5COBDLxM1roBNBu7zMpK//393Qx3rL2f9PdaZGLaCEtS5DyuXimyUXWzjMt8gsnsBxtomTgHBY4E7F5ag0Ub2z6ZsIQE1A=" + +addons: + coverity_scan: + project: + name: "scrawl/openmw" + description: "" + notification_email: scrawl@baseoftrash.de + build_command_prepend: "cmake ." + build_command: "make -j4" + branch_pattern: coverity_scan + before_install: - if [ "${TRAVIS_OS_NAME}" = "linux" ]; then ./CI/before_install.linux.sh; fi - if [ "${TRAVIS_OS_NAME}" = "osx" ]; then ./CI/before_install.osx.sh; fi @@ -14,7 +30,7 @@ before_script: - if [ "${TRAVIS_OS_NAME}" = "osx" ]; then ./CI/before_script.osx.sh; fi script: - cd ./build - - make -j4 + - if [ "$COVERITY_SCAN_BRANCH" != 1 ]; then make -j4; fi after_script: - if [ "${TRAVIS_OS_NAME}" = "linux" ]; then ./openmw_test_suite; fi notifications: From 3378dece60ef086c2ef5de54302373274fc5d1af Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 17 Dec 2014 23:22:20 +0100 Subject: [PATCH 0254/3725] Add coverity_scan branch to .travis.yml --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index c5ed43543..7acb92554 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,6 +5,7 @@ language: cpp branches: only: - master + - coverity_scan - /openmw-.*$/ env: global: From bf1739ae2cab2c0e3f30e51c74b70dcd4c7f29d7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 10 Jan 2015 15:54:13 +0100 Subject: [PATCH 0255/3725] Adjust COVERITY_SCAN_TOKEN --- .travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7acb92554..1200c6bbc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,8 +11,7 @@ env: global: # The next declaration is the encrypted COVERITY_SCAN_TOKEN, created # via the "travis encrypt" command using the project repo's public key - - secure: "CcQGmzgaBRTPWqPZLoLX4Zkt5pOQb5c6Pr5OFt15C8xQRhWOLrWcdsQEO1UuEJ70/YJgbvN+wQk8B5COBDLxM1roBNBu7zMpK//393Qx3rL2f9PdaZGLaCEtS5DyuXimyUXWzjMt8gsnsBxtomTgHBY4E7F5ag0Ub2z6ZsIQE1A=" - + - secure: "jybGzAdUbqt9vWR/GEnRd96BgAi/7Zd1+2HK68j/i/8+/1YH2XxLOy4Jv/DUBhBlJIkxs/Xv8dRcUlFOclZDHX1d/9Qnsqd3oUVkD7k1y7cTOWy9TBQaE/v/kZo3LpzA3xPwwthrb0BvqIbOfIELi5fS5s8ba85WFRg3AX70wWE=" addons: coverity_scan: project: From 2d51d599ea04f04e949efd248a974cf40fc3e580 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 10 Jan 2015 15:57:13 +0100 Subject: [PATCH 0256/3725] Adjust coverity config to official repo --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 1200c6bbc..d24f5ebd8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,7 +15,7 @@ env: addons: coverity_scan: project: - name: "scrawl/openmw" + name: "openmw/openmw" description: "" notification_email: scrawl@baseoftrash.de build_command_prepend: "cmake ." From c37c071dfe1cb088e778d3e8fb0a9ad518f4d085 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 10 Jan 2015 16:07:12 +0100 Subject: [PATCH 0257/3725] Repository name fix --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index d24f5ebd8..079e84a8e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,7 +15,7 @@ env: addons: coverity_scan: project: - name: "openmw/openmw" + name: "OpenMW/openmw" description: "" notification_email: scrawl@baseoftrash.de build_command_prepend: "cmake ." From 23ffd33d9e6e1f12faf2b7d8e7e4bc3cde49efc8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 10 Jan 2015 16:27:15 +0100 Subject: [PATCH 0258/3725] Convert readme to markdown --- readme.txt => README.md | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) rename readme.txt => README.md (99%) diff --git a/readme.txt b/README.md similarity index 99% rename from readme.txt rename to README.md index 5d344c0b5..304844892 100644 --- a/readme.txt +++ b/README.md @@ -1,18 +1,19 @@ 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.34.0 -License: GPL (see GPL3.txt for more information) -Website: http://www.openmw.org +* Version: 0.34.0 +* License: GPL (see GPL3.txt for more information) +* Website: http://www.openmw.org Font Licenses: DejaVuLGCSansMono.ttf: custom (see DejaVu Font License.txt for more information) - -INSTALLATION +Installation +============ Windows: Run the installer. @@ -28,18 +29,21 @@ https://www.archlinux.org/packages/?sort=&q=openmw OS X: Open DMG file, copy OpenMW folder anywhere, for example in /Applications -BUILD FROM SOURCE +Build from source +================= https://wiki.openmw.org/index.php?title=Development_Environment_Setup -THE DATA PATH +The data path +============= The data path tells OpenMW where to find your Morrowind files. If you run the launcher, OpenMW should be able to pick up the location of these files on its own, if both Morrowind and OpenMW are installed properly (installing Morrowind under WINE is considered a proper install). -COMMAND LINE OPTIONS +Command line options +==================== Syntax: openmw Allowed options: @@ -96,7 +100,8 @@ Allowed options: --no-grab Don't grab mouse cursor --activate-dist arg (=-1) activation distance override -CHANGELOG +Changelog +========= 0.34.0 From 88a562a6481ace71a0569aa07c695437c4ed29fb Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 10 Jan 2015 16:35:03 +0100 Subject: [PATCH 0259/3725] Move changelog to its own file, formatting fixes --- CHANGELOG.md | 1465 +++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 1474 +------------------------------------------------- 2 files changed, 1470 insertions(+), 1469 deletions(-) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 000000000..09f318d9d --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,1465 @@ +

+0.34.0
+
+Bug #904: omwlauncher doesn't allow installing Tribunal and Bloodmoon if only MW is installed
+Bug #986: Launcher: renaming profile names is broken
+Bug #1061: "Browse to CD..." launcher crash
+Bug #1135: Launcher crashes if user does not have write permission
+Bug #1231: Current installer in launcher does not correctly import russian Morrowind.ini settings from setup.inx
+Bug #1288: Fix the Alignment of the Resolution Combobox
+Bug #1343: BIK videos occasionally out of sync with audio
+Bug #1684: Morrowind Grass Mod graphical glitches
+Bug #1734: NPC in fight with invisible/sneaking player
+Bug #1982: Long class names are cut off in the UI
+Bug #2012: Editor: OpenCS script compiler sometimes fails to find IDs
+Bug #2015: Running while levitating does not affect speed but still drains fatigue
+Bug #2018: OpenMW don´t reset modified cells to vanilla when a plugin is deselected and don´t apply changes to cells already visited.
+Bug #2045: ToggleMenus command should close dialogue windows
+Bug #2046: Crash: light_de_streetlight_01_223
+Bug #2047: Buglamp tooltip minor correction
+Bug #2050: Roobrush floating texture bits
+Bug #2053: Slaves react negatively to PC picking up slave's bracers
+Bug #2055: Dremora corpses use the wrong model
+Bug #2056: Mansilamat Vabdas's corpse is floating in the water
+Bug #2057: "Quest: Larius Varro Tells A Little Story": Bounty not completely removed after finishing quest
+Bug #2059: Silenced enemies try to cast spells anyway
+Bug #2060: Editor: Special case implementation for top level window with single sub-window should be optional
+Bug #2061: Editor: SubView closing that is not directly triggered by the user isn't handled properly
+Bug #2063: Tribunal: Quest 'The Warlords' doesn't work
+Bug #2064: Sneak attack on hostiles causes bounty
+Bug #2065: Editor: Qt signal-slot error when closing a dialogue subview
+Bug #2070: Loading ESP in OpenMW works but fails in OpenCS
+Bug #2071: CTD in 0.33
+Bug #2073: Storm atronach animation stops now and then
+Bug #2075: Molag Amur Region, Map shows water on solid ground
+Bug #2080: game won't work with fair magicka regen
+Bug #2082: NPCs appear frozen or switched off after leaving and quickly reentering a cell
+Bug #2088: OpenMW is unable to play OGG files.
+Bug #2093: Darth Gares talks to you in Ilunibi even when he's not there, screwing up the Main Quests
+Bug #2095: Coordinate and rotation editing in the Reference table does not work.
+Bug #2096: Some overflow fun and bartering exploit
+Bug #2098: [D3D] Game crash on maximize
+Bug #2099: Activate, player seems not to work
+Bug #2104: Only labels are sensitive in buttons
+Bug #2107: "Slowfall" effect is too weak
+Bug #2114: OpenCS doesn't load an ESP file full of errors even though Vanilla MW Construction Set can
+Bug #2117: Crash when encountering bandits on opposite side of river from the egg mine south of Balmora
+Bug #2124: [Mod: Baldurians Transparent Glass Amor] Armor above head
+Bug #2125: Unnamed NiNodes in weapons problem in First Person
+Bug #2126: Dirty dialog script in tribunal.esm causing bug in Tribunal MQ
+Bug #2128: Crash when picking character's face
+Bug #2129: Disable the third-person zoom feature by default
+Bug #2130: Ash storm particles shown too long during transition to clear sky
+Bug #2137: Editor: exception caused by following the Creature column of a SoundGen record
+Bug #2139: Mouse movement should be ignored during intro video
+Bug #2143: Editor: Saving is broken
+Bug #2145: OpenMW - crash while exiting x64 debug build
+Bug #2152: You can attack Almalexia during her final monologue
+Bug #2154: Visual effects behave weirdly after loading/taking a screenshot
+Bug #2155: Vivec has too little magicka
+Bug #2156: Azura's spirit fades away too fast
+Bug #2158: [Mod]Julan Ashlander Companion 2.0: Negative magicka
+Bug #2161: Editor: combat/magic/stealth values of creature not displayed correctly
+Bug #2163: OpenMW can't detect death if the NPC die by the post damage effect of a magic weapon.
+Bug #2168: Westly's Master Head Pack X – Some hairs aren't rendered correctly.
+Bug #2170: Mods using conversations to update PC inconsistant
+Bug #2180: Editor: Verifier doesn't handle Windows-specific path issues when dealing with resources
+Bug #2212: Crash or unexpected behavior while closing OpenCS cell render window on OS X
+Feature #238: Add UI to run INI-importer from the launcher
+Feature #854: Editor: Add user setting to show status bar
+Feature #987: Launcher: first launch instructions for CD need to be more explicit
+Feature #1232: There is no way to set the "encoding" option using launcher UI.
+Feature #1281: Editor: Render cell markers
+Feature #1918: Editor: Functionality for Double-Clicking in Tables
+Feature #1966: Editor: User Settings dialogue grouping/labelling/tooltips
+Feature #2097: Editor: Edit position of references in 3D scene
+Feature #2121: Editor: Add edit mode button to scene toolbar
+Task #1965: Editor: Improve layout of user settings dialogue
+
+0.33.1
+
+Bug #2108: OpenCS fails to build
+
+0.33.0
+
+Bug #371: If console assigned to ` (probably to any symbolic key), "`" symbol will be added to console every time it closed
+Bug #1148: Some books'/scrolls' contents are displayed incorrectly
+Bug #1290: Editor: status bar is not updated when record filter is changed
+Bug #1292: Editor: Documents are not removed on closing the last view
+Bug #1301: Editor: File->Exit only checks the document it was issued from.
+Bug #1353: Bluetooth on with no speaker connected results in significantly longer initial load times
+Bug #1436: NPCs react from too far distance
+Bug #1472: PC is placed on top of following NPC when changing cell
+Bug #1487: Tall PC can get stuck in staircases
+Bug #1565: Editor: Subviews are deleted on shutdown instead when they are closed
+Bug #1623: Door marker on Ghorak Manor's balcony makes PC stuck
+Bug #1633: Loaddoor to Sadrith Mora, Telvanni Council House spawns PC in the air
+Bug #1655: Use Appropriate Application Icons on Windows
+Bug #1679: Tribunal expansion, Meryn Othralas the backstage manager in the theatre group in Mournhold in the great bazaar district is floating a good feet above the ground.
+Bug #1705: Rain is broken in third person
+Bug #1706: Thunder and lighting still occurs while the game is paused during the rain
+Bug #1708: No long jumping
+Bug #1710: Editor: ReferenceableID drag to references record filter field creates incorrect filter
+Bug #1712: Rest on Water
+Bug #1715: "Cancel" button is not always on the same side of menu
+Bug #1725: Editor: content file can be opened multiple times from the same dialogue
+Bug #1730: [MOD: Less Generic Nerevarine] Compile failure attempting to enter the Corprusarium.
+Bug #1733: Unhandled ffmpeg sample formats
+Bug #1735: Editor: "Edit Record" context menu button not opening subview for journal infos
+Bug #1750: Editor: record edits result in duplicate entries
+Bug #1789: Editor: Some characters cannot be used in addon name
+Bug #1803: Resizing the map does not keep the pre-resize center at the post-resize center
+Bug #1821: Recovering Cloudcleaver quest: attacking Sosia is considered a crime when you side with Hlormar
+Bug #1838: Editor: Preferences window appears off screen
+Bug #1839: Editor: Record filter title should be moved two pixels to the right
+Bug #1849: Subrecord error in MAO_Containers
+Bug #1854: Knocked-out actors don't fully act knocked out
+Bug #1855: "Soul trapped" sound doesn't play
+Bug #1857: Missing sound effect for enchanted items with empty charge
+Bug #1859: Missing console command: ResetActors (RA)
+Bug #1861: Vendor category "MagicItems" is unhandled
+Bug #1862: Launcher doesn't start if a file listed in launcher.cfg has correct name but wrong capitalization
+Bug #1864: Editor: Region field for cell record in dialogue subview not working
+Bug #1869: Editor: Change label "Musics" to "Music"
+Bug #1870: Goblins killed while knocked down remain in knockdown-pose
+Bug #1874: CellChanged events should not trigger when crossing exterior cell border
+Bug #1877: Spriggans killed instantly if hit while regening
+Bug #1878: Magic Menu text not un-highlighting correctly when going from spell to item as active magic
+Bug #1881: Stuck in ceiling when entering castle karstaags tower
+Bug #1884: Unlit torches still produce a burning sound
+Bug #1885: Can type text in price field in barter window
+Bug #1887: Equipped items do not emit sounds
+Bug #1889: draugr lord aesliip will attack you and remain non-hostile
+Bug #1892: Guard asks player to pay bounty of 0 gold
+Bug #1895: getdistance should only return max float if ref and target are in different worldspaces
+Bug #1896: Crash Report
+Bug #1897: Conjured Equipment cant be re-equipped if removed
+Bug #1898: Only Gidar Verothan follows you during establish the mine quest
+Bug #1900: Black screen when you open the door and breath underwater
+Bug #1904: Crash on casting recall spell
+Bug #1906: Bound item checks should use the GMSTs
+Bug #1907: Bugged door. Mournhold, The Winged Guar
+Bug #1908: Crime reported for attacking Drathas Nerus's henchmen while they attack Dilborn
+Bug #1909: Weird Quest Flow Infidelities quest
+Bug #1910: Follower fighting with gone npc
+Bug #1911: Npcs will drown themselves
+Bug #1912: World map arrow stays static when inside a building
+Bug #1920: Ulyne Henim disappears when game is loaded inside Vas
+Bug #1922: alchemy-> potion of paralyze
+Bug #1923: "levitation magic cannot be used here" shows outside of tribunal
+Bug #1927: AI prefer melee over magic.
+Bug #1929: Tamriel Rebuilt: Named cells that lie within the overlap with Morrowind.esm are not shown
+Bug #1932: BTB - Spells 14.1 magic effects don´t overwrite the Vanilla ones but are added
+Bug #1935: Stacks of items are worth more when sold individually
+Bug #1940: Launcher does not list addon files if base game file is renamed to a different case
+Bug #1946: Mod "Tel Nechim - moved" breaks savegames
+Bug #1947: Buying/Selling price doesn't properly affect the growth of mercantile skill
+Bug #1950: followers from east empire company quest will fight each other if combat happens with anything
+Bug #1958: Journal can be scrolled indefinitely with a mouse wheel
+Bug #1959: Follower not leaving party on quest end
+Bug #1960: Key bindings not always saved correctly
+Bug #1961: Spell merchants selling racial bonus spells
+Bug #1967: segmentation fault on load saves
+Bug #1968: Jump sounds are not controlled by footsteps slider, sound weird compared to footsteps
+Bug #1970: PC suffers silently when taking damage from lava
+Bug #1971: Dwarven Sceptre collision area is not removed after killing one
+Bug #1974: Dalin/Daris Norvayne follows player indefinitely
+Bug #1975: East Empire Company faction rank breaks during Raven Rock questline
+Bug #1979: 0 strength = permanently over encumbered
+Bug #1993: Shrine blessing in Maar Gan doesn't work
+Bug #2008: Enchanted items do not recharge
+Bug #2011: Editor: OpenCS script compiler doesn't handle member variable access properly
+Bug #2016: Dagoth Ur already dead in Facility Cavern
+Bug #2017: Fighters Guild Quest: The Code Book - dialogue loop when UMP is loaded.
+Bug #2019: Animation of 'Correct UV Mudcrabs' broken
+Bug #2022: Alchemy window - Removing ingredient doesn't remove the number of ingredients
+Bug #2025: Missing mouse-over text for non affordable items
+Bug #2028: [MOD: Tamriel Rebuilt] Crashing when trying to enter interior cell "Ruinous Keep, Great Hall"
+Bug #2029: Ienith Brothers Thiev's Guild quest journal entry not adding
+Feature #471: Editor: Special case implementation for top-level window with single sub-window
+Feature #472: Editor: Sub-Window re-use settings
+Feature #704: Font colors import from fallback settings
+Feature #879: Editor: Open sub-views in a new top-level window
+Feature #932: Editor: magic effect table
+Feature #937: Editor: Path Grid table
+Feature #938: Editor: Sound Gen table
+Feature #1117: Death and LevelUp music
+Feature #1226: Editor: Request UniversalId editing from table columns
+Feature #1545: Targeting console on player
+Feature #1597: Editor: Render terrain
+Feature #1695: Editor: add column for CellRef's global variable
+Feature #1696: Editor: use ESM::Cell's RefNum counter
+Feature #1697: Redden player's vision when hit
+Feature #1856: Spellcasting for non-biped creatures
+Feature #1879: Editor: Run OpenMW with the currently edited content list
+Task #1851: Move AI temporary state out of AI packages
+Task #1865: Replace char type in records
+
+0.32.0
+
+Bug #1132: Unable to jump when facing a wall
+Bug #1341: Summoned Creatures do not immediately disappear when killed.
+Bug #1430: CharGen Revamped script does not compile
+Bug #1451: NPCs shouldn't equip weapons prior to fighting
+Bug #1461: Stopped start scripts do not restart on load
+Bug #1473: Dead NPC standing and in 2 pieces
+Bug #1482: Abilities are depleted when interrupted during casting
+Bug #1503: Behaviour of NPCs facing the player
+Bug #1506: Missing character, French edition: three-points
+Bug #1528: Inventory very slow after 2 hours
+Bug #1540: Extra arguments should be ignored for script functions
+Bug #1541: Helseth's Champion: Tribunal
+Bug #1570: Journal cannot be opened while in inventory screen
+Bug #1573: PC joins factions at random
+Bug #1576: NPCs aren't switching their weapons when out of ammo
+Bug #1579: Guards detect creatures in far distance, instead on sight
+Bug #1588: The Siege of the Skaal Village: bloodmoon
+Bug #1593: The script compiler isn't recognising some names that contain a -
+Bug #1606: Books: Question marks instead of quotation marks
+Bug #1608: Dead bodies prevent door from opening/closing.
+Bug #1609: Imperial guards in Sadrith Mora are not using their spears
+Bug #1610: The bounty number is not displayed properly with high numbers
+Bug #1620: Implement correct formula for auto-calculated NPC spells
+Bug #1630: Boats standing vertically in Vivec
+Bug #1635: Arrest dialogue is executed second time after I select "Go to jail"
+Bug #1637: Weird NPC behaviour in Vivec, Hlaalu Ancestral Vaults?
+Bug #1641: Persuasion dialog remains after loading, possibly resulting in crash
+Bug #1644: "Goodbye" and similar options on dialogues prevents escape working properly.
+Bug #1646: PC skill stats are not updated immediately when changing equipment
+Bug #1652: Non-aggressive creature
+Bug #1653: Quickloading while the container window is open crashes the game
+Bug #1654: Priority of checks in organic containers
+Bug #1656: Inventory items merge issue when repairing
+Bug #1657: Attacked state of NPCs is not saved properly
+Bug #1660: Rank dialogue condition ignored
+Bug #1668: Game starts on day 2 instead of day 1
+Bug #1669: Critical Strikes while fighting a target who is currently fighting me
+Bug #1672: OpenCS doesn't save the projects
+Bug #1673: Fatigue decreasing by only one point when running
+Bug #1675: Minimap and localmap graphic glitches
+Bug #1676: Pressing the OK button on the travel menu cancels the travel and exits the menu
+Bug #1677: Sleeping in a rented bed is considered a crime
+Bug #1685: NPCs turn towards player even if invisible/sneaking
+Bug #1686: UI bug: cursor is clicking "world/local" map button while inventory window is closed?
+Bug #1690: Double clicking on a inventory window header doesn't close it.
+Bug #1693: Spell Absorption does not absorb shrine blessings
+Bug #1694: journal displays learned topics as quests
+Bug #1700: Sideways scroll of text boxes
+Bug #1701: Player enchanting requires player hold money, always 100% sucessful.
+Bug #1704: self-made Fortify Intelligence/Drain willpower potions are broken
+Bug #1707: Pausing the game through the esc menu will silence rain, pausing it by opening the inventory will not.
+Bug #1709: Remesa Othril is hostile to Hlaalu members
+Bug #1713: Crash on load after death
+Bug #1719: Blind effect has slight border at the edge of the screen where it is ineffective.
+Bug #1722: Crash after creating enchanted item, reloading saved game
+Bug #1723: Content refs that are stacked share the same index after unstacking
+Bug #1726: Can't finish Aengoth the Jeweler's quest : Retrieve the Scrap Metal
+Bug #1727: Targets almost always resist soultrap scrolls
+Bug #1728: Casting a soultrap spell on invalid target yields no message
+Bug #1729: Chop attack doesn't work if walking diagonally
+Bug #1732: Error handling for missing script function arguments produces weird message
+Bug #1736: Alt-tabbing removes detail from overworld map.
+Bug #1737: Going through doors with (high magnitude?) leviation will put the player high up, possibly even out of bounds.
+Bug #1739: Setting a variable on an NPC from another NPC's dialogue result sets the wrong variable
+Bug #1741: The wait dialogue doesn't black the screen out properly during waiting.
+Bug #1742: ERROR: Object 'sDifficulty' not found (const)
+Bug #1744: Night sky in Skies V.IV (& possibly v3) by SWG rendered incorrectly
+Bug #1746: Bow/marksman weapon condition does not degrade with use
+Bug #1749: Constant Battle Music
+Bug #1752: Alt-Tabbing in the character menus makes the paper doll disappear temporarily
+Bug #1753: Cost of training is not added to merchant's inventory
+Bug #1755: Disposition changes do not persist if the conversation menu is closed by purchasing training.
+Bug #1756: Caught Blight after being cured of Corprus
+Bug #1758: Crash Upon Loading New Cell
+Bug #1760: Player's Magicka is not recalculated upon drained or boosted intelligence
+Bug #1761: Equiped torches lost on reload
+Bug #1762: Your spell did not get a target. Soul trap. Gorenea Andrano
+Bug #1763: Custom Spell Magicka Cost
+Bug #1765: Azuras Star breaks on recharging item
+Bug #1767: GetPCRank did not handle ignored explicit references
+Bug #1772: Dark Brotherhood Assassins never use their Carved Ebony Dart, sticking to their melee weapon.
+Bug #1774: String table overflow also occurs when loading TheGloryRoad.esm
+Bug #1776: dagoth uthol runs in slow motion
+Bug #1778: Incorrect values in spellmaking window
+Bug #1779: Icon of Master Propylon Index is not visible
+Bug #1783: Invisible NPC after looting corpse
+Bug #1787: Health Calculation
+Bug #1788: Skeletons, ghosts etc block doors when we try to open
+Bug #1791: [MOD: LGNPC Foreign Quarter] NPC in completely the wrong place.
+Bug #1792: Potions should show more effects
+Bug #1793: Encumbrance while bartering
+Bug #1794: Fortify attribute not affecting fatigue
+Bug #1795: Too much magicka
+Bug #1796: "Off by default" torch burning
+Bug #1797: Fish too slow
+Bug #1798: Rest until healed shouldn't show with full health and magicka
+Bug #1802: Mark location moved
+Bug #1804: stutter with recent builds
+Bug #1810: attack gothens dremora doesnt agro the others.
+Bug #1811: Regression: Crash Upon Loading New Cell
+Bug #1812: Mod: "QuickChar" weird button placement
+Bug #1815: Keys show value and weight, Vanilla Morrowind's keys dont.
+Bug #1817: Persuasion results do not show using unpatched MW ESM
+Bug #1818: Quest B3_ZainabBride moves to stage 47 upon loading save while Falura Llervu is following
+Bug #1823: AI response to theft incorrect - only guards react, in vanilla everyone does.
+Bug #1829: On-Target Spells Rendered Behind Water Surface Effects
+Bug #1830: Galsa Gindu's house is on fire
+Bug #1832: Fatal Error: OGRE Exception(2:InvalidParametersException)
+Bug #1836: Attacked Guards open "fine/jail/resist"-dialogue after killing you
+Bug #1840: Infinite recursion in ActionTeleport
+Bug #1843: Escorted people change into player's cell after completion of escort stage
+Bug #1845: Typing 'j' into 'Name' fields opens the journal
+Bug #1846: Text pasted into the console still appears twice (Windows)
+Bug #1847: "setfatigue 0" doesn't render NPC unconscious
+Bug #1848: I can talk to unconscious actors
+Bug #1866: Crash when player gets killed by a creature summoned by him
+Bug #1868: Memory leaking when openmw window is minimized
+Feature #47: Magic Effects
+Feature #642: Control NPC mouth movement using current Say sound
+Feature #939: Editor: Resources tables
+Feature #961: AI Combat for magic (spells, potions and enchanted items)
+Feature #1111: Collision script instructions (used e.g. by Lava)
+Feature #1120: Command creature/humanoid magic effects
+Feature #1121: Elemental shield magic effects
+Feature #1122: Light magic effect
+Feature #1139: AI: Friendly hits
+Feature #1141: AI: combat party
+Feature #1326: Editor: Add tooltips to all graphical buttons
+Feature #1489: Magic effect Get/Mod/Set functions
+Feature #1505: Difficulty slider
+Feature #1538: Targeted scripts
+Feature #1571: Allow creating custom markers on the local map
+Feature #1615: Determine local variables from compiled scripts instead of the values in the script record
+Feature #1616: Editor: Body part record verifier
+Feature #1651: Editor: Improved keyboard navigation for scene toolbar
+Feature #1666: Script blacklisting
+Feature #1711: Including the Git revision number from the command line "--version" switch.
+Feature #1721: NPC eye blinking
+Feature #1740: Scene toolbar buttons for selecting which type of elements are rendered
+Feature #1790: Mouse wheel scrolling for the journal
+Feature #1850: NiBSPArrayController
+Task #768: On windows, settings folder should be "OpenMW", not "openmw"
+Task #908: Share keyframe data
+Task #1716: Remove defunct option for building without FFmpeg
+
+0.31.0
+
+Bug #245: Cloud direction and weather systems differ from Morrowind
+Bug #275: Local Map does not always show objects that span multiple cells
+Bug #538: Update CenterOnCell (COC) function behavior
+Bug #618: Local and World Map Textures are sometimes Black
+Bug #640: Water behaviour at night
+Bug #668: OpenMW doesn't support non-latin paths on Windows
+Bug #746: OpenMW doesn't check if the background music was already played
+Bug #747: Door is stuck if cell is left before animation finishes
+Bug #772: Disabled statics are visible on map
+Bug #829: OpenMW uses up all available vram, when playing for extended time
+Bug #869: Dead bodies don't collide with anything
+Bug #894: Various character creation issues
+Bug #897/#1369: opencs Segmentation Fault after "new" or "load"
+Bug #899: Various jumping issues
+Bug #952: Reflection effects are one frame delayed
+Bug #993: Able to interact with world during Wait/Rest dialog
+Bug #995: Dropped items can be placed inside the wall
+Bug #1008: Corpses always face up upon reentering the cell
+Bug #1035: Random colour patterns appearing in automap
+Bug #1037: Footstep volume issues
+Bug #1047: Creation of wrong links in dialogue window
+Bug #1129: Summoned creature time life duration seems infinite
+Bug #1134: Crimes can be committed against hostile NPCs
+Bug #1136: Creature run speed formula is incorrect
+Bug #1150: Weakness to Fire doesn't apply to Fire Damage in the same spell
+Bug #1155: NPCs killing each other
+Bug #1166: Bittercup script still does not work
+Bug #1178: .bsa file names are case sensitive.
+Bug #1179: Crash after trying to load game after being killed
+Bug #1180: Changing footstep sound location
+Bug #1196: Jumping not disabled when showing messageboxes
+Bug #1202: "strange" keys are not shown in binding menu, and are not saved either, but works
+Bug #1216: Broken dialog topics in russian Morrowind
+Bug #1217: Container content changes based on the current position of the mouse
+Bug #1234: Loading/saving issues with dynamic records
+Bug #1277: Text pasted into the console appears twice
+Bug #1284: Crash on New Game
+Bug #1303: It's possible to skip the chargen
+Bug #1304: Slaughterfish should not detect the player unless the player is in the water
+Bug #1311: Editor: deleting Record Filter line does not reset the filter
+Bug #1324: ERROR: ESM Error: String table overflow when loading Animated Morrowind.esp
+Bug #1328: Editor: Bogus Filter created when dragging multiple records to filter bar of non-applicable table
+Bug #1331: Walking/running sound persist after killing NPC`s that are walking/running.
+Bug #1334: Previously equipped items not shown as unequipped after attempting to sell them.
+Bug #1335: Actors ignore vertical axis when deciding to attack
+Bug #1338: Unknown toggle option for shadows
+Bug #1339: "Ashlands Region" is visible when beginning new game during "Loading Area" process
+Bug #1340: Guards prompt Player with punishment options after resisting arrest with another guard.
+Bug #1348: Regression: Bug #1098 has returned with a vengeance
+Bug #1349: [TR] TR_Data mesh tr_ex_imp_gatejamb01 cannot be activated
+Bug #1352: Disabling an ESX file does not disable dependent ESX files
+Bug #1355: CppCat Checks OpenMW
+Bug #1356: Incorrect voice type filtering for sleep interrupts
+Bug #1357: Restarting the game clears saves
+Bug #1360: Seyda Neen silk rider dialog problem
+Bug #1361: Some lights don't work
+Bug #1364: It is difficult to bind "Mouse 1" to an action in the options menu
+Bug #1370: Animation compilation mod does not work properly
+Bug #1371: SL_Pick01.nif from third party fails to load in openmw, but works in Vanilla
+Bug #1373: When stealing in front of Sellus Gravius cannot exit the dialog
+Bug #1378: Installs to /usr/local are not working
+Bug #1380: Loading a save file fail if one of the content files is disabled
+Bug #1382: "getHExact() size mismatch" crash on loading official plugin "Siege at Firemoth.esp"
+Bug #1386: Arkngthand door will not open
+Bug #1388: Segfault when modifying View Distance in Menu options
+Bug #1389: Crash when loading a save after dying
+Bug #1390: Apostrophe characters not displayed [French version]
+Bug #1391: Custom made icon background texture for magical weapons and stuff isn't scaled properly on GUI.
+Bug #1393: Coin icon during the level up dialogue are off of the background
+Bug #1394: Alt+F4 doesn't work on Win version
+Bug #1395: Changing rings switches only the last one put on
+Bug #1396: Pauldron parts aren't showing when the robe is equipped
+Bug #1402: Dialogue of some shrines have wrong button orientation
+Bug #1403: Items are floating in the air when they're dropped onto dead bodies.
+Bug #1404: Forearms are not rendered on Argonian females
+Bug #1407: Alchemy allows making potions from two of the same item
+Bug #1408: "Max sale" button gives you all the items AND all the trader's gold
+Bug #1409: Rest "Until Healed" broken for characters with stunted magicka.
+Bug #1412: Empty travel window opens while playing through start game
+Bug #1413: Save game ignores missing writing permission
+Bug #1414: The Underground 2 ESM Error
+Bug #1416: Not all splash screens in the Splash directory are used
+Bug #1417: Loading saved game does not terminate
+Bug #1419: Skyrim: Home of the Nords error
+Bug #1422: ClearInfoActor
+Bug #1423: ForceGreeting closes existing dialogue windows
+Bug #1425: Cannot load save game
+Bug #1426: Read skill books aren't stored in savegame
+Bug #1427: Useless items can be set under hotkeys
+Bug #1429: Text variables in journal
+Bug #1432: When attacking friendly NPC, the crime is reported and bounty is raised after each swing
+Bug #1435: Stealing priceless items is without punishment
+Bug #1437: Door marker at Jobasha's Rare Books is spawning PC in the air
+Bug #1440: Topic selection menu should be wider
+Bug #1441: Dropping items on the rug makes them inaccessible
+Bug #1442: When dropping and taking some looted items, bystanders consider that as a crime
+Bug #1444: Arrows and bolts are not dropped where the cursor points
+Bug #1445: Security trainers offering acrobatics instead
+Bug #1447: Character dash not displayed, French edition
+Bug #1448: When the player is killed by the guard while having a bounty on his head, the guard dialogue opens over and over instead of loading dialogue
+Bug #1454: Script error in SkipTutorial
+Bug #1456: Bad lighting when using certain Morrowind.ini generated by MGE
+Bug #1457: Heart of Lorkan comes after you when attacking it
+Bug #1458: Modified Keybindings are not remembered
+Bug #1459: Dura Gra-Bol doesn't respond to PC attack
+Bug #1462: Interior cells not loaded with Morrowind Patch active
+Bug #1469: Item tooltip should show the base value, not real value
+Bug #1477: Death count is not stored in savegame
+Bug #1478: AiActivate does not trigger activate scripts
+Bug #1481: Weapon not rendered when partially submerged in water
+Bug #1483: Enemies are attacking even while dying
+Bug #1486: ESM Error: Don't know what to do with INFO
+Bug #1490: Arrows shot at PC can end up in inventory
+Bug #1492: Monsters respawn on top of one another
+Bug #1493: Dialogue box opens with follower NPC even if NPC is dead
+Bug #1494: Paralysed cliffracers remain airbourne
+Bug #1495: Dialogue box opens with follower NPC even the game is paused
+Bug #1496: GUI messages are not cleared when loading another saved game
+Bug #1499: Underwater sound sometimes plays when transitioning from interior.
+Bug #1500: Targetted spells and water.
+Bug #1502: Console error message on info refusal
+Bug #1507: Bloodmoon MQ The Ritual of Beasts: Can't remove the arrow
+Bug #1508: Bloodmoon: Fort Frostmoth, cant talk with Carnius Magius
+Bug #1516: PositionCell doesn't move actors to current cell
+Bug #1518: ForceGreeting broken for explicit references
+Bug #1522: Crash after attempting to play non-music file
+Bug #1523: World map empty after loading interior save
+Bug #1524: Arrows in waiting/resting dialog act like minimum and maximum buttons
+Bug #1525: Werewolf: Killed NPC's don't fill werewolfs hunger for blood
+Bug #1527: Werewolf: Detect life detects wrong type of actor
+Bug #1529: OpenMW crash during "the shrine of the dead" mission (tribunal)
+Bug #1530: Selected text in the console has the same color as the background
+Bug #1539: Barilzar's Mazed Band: Tribunal
+Bug #1542: Looping taunts from NPC`s after death: Tribunal
+Bug #1543: OpenCS crash when using drag&drop in script editor
+Bug #1547: Bamz-Amschend: Centurion Archers combat problem
+Bug #1548: The Missing Hand: Tribunal
+Bug #1549: The Mad God: Tribunal, Dome of Serlyn
+Bug #1557: A bounty is calculated from actual item cost
+Bug #1562: Invisible terrain on top of Red Mountain
+Bug #1564: Cave of the hidden music: Bloodmoon
+Bug #1567: Editor: Deleting of referenceables does not work
+Bug #1568: Picking up a stack of items and holding the enter key and moving your mouse around paints a bunch of garbage on screen.
+Bug #1574: Solstheim: Drauger cant inflict damage on player
+Bug #1578: Solstheim: Bonewolf running animation not working
+Bug #1585: Particle effects on PC are stopped when paralyzed
+Bug #1589: Tribunal: Crimson Plague quest does not update when Gedna Relvel is killed
+Bug #1590: Failed to save game: compile error
+Bug #1598: Segfault when making Drain/Fortify Skill spells
+Bug #1599: Unable to switch to fullscreen
+Bug #1613: Morrowind Rebirth duplicate objects / vanilla objects not removed
+Bug #1618: Death notice fails to show up
+Bug #1628: Alt+Tab Segfault
+Feature #32: Periodic Cleanup/Refill
+Feature #41: Precipitation and weather particles
+Feature #568: Editor: Configuration setup
+Feature #649: Editor: Threaded loading
+Feature #930: Editor: Cell record saving
+Feature #934: Editor: Body part table
+Feature #935: Editor: Enchantment effect table
+Feature #1162: Dialogue merging
+Feature #1174: Saved Game: add missing creature state
+Feature #1177: Saved Game: fog of war state
+Feature #1312: Editor: Combat/Magic/Stealth values for creatures are not displayed
+Feature #1314: Make NPCs and creatures fight each other
+Feature #1315: Crime: Murder
+Feature #1321: Sneak skill enhancements
+Feature #1323: Handle restocking items
+Feature #1332: Saved Game: levelled creatures
+Feature #1347: modFactionReaction script instruction
+Feature #1362: Animated main menu support
+Feature #1433: Store walk/run toggle
+Feature #1449: Use names instead of numbers for saved game files and folders
+Feature #1453: Adding Delete button to the load menu
+Feature #1460: Enable Journal screen while in dialogue
+Feature #1480: Play Battle music when in combat
+Feature #1501: Followers unable to fast travel with you
+Feature #1520: Disposition and distance-based aggression/ShouldAttack
+Feature #1595: Editor: Object rendering in cells
+Task #940: Move license to locations where applicable
+Task #1333: Remove cmake git tag reading
+Task #1566: Editor: Object rendering refactoring
+
+0.30.0
+
+Bug #416: Extreme shaking can occur during cell transitions while moving
+Bug #1003: Province Cyrodiil: Ogre Exception in Stirk
+Bug #1071: Crash when given a non-existent content file
+Bug #1080: OpenMW allows resting/using a bed while in combat
+Bug #1097: Wrong punishment for stealing in Census and Excise Office at the start of a new game
+Bug #1098: Unlocked evidence chests should get locked after new evidence is put into them
+Bug #1099: NPCs that you attacked still fight you after you went to jail/paid your fine
+Bug #1100: Taking items from a corpse is considered stealing
+Bug #1126: Some creatures can't get close enough to attack
+Bug #1144: Killed creatures seem to die again each time player transitions indoors/outdoors
+Bug #1181: loading a saved game does not reset the player control status
+Bug #1185: Collision issues in Addamasartus
+Bug #1187: Athyn Sarethi mission, rescuing varvur sarethi from the doesnt end the mission
+Bug #1189: Crash when entering interior cell "Gnisis, Arvs-Drelen"
+Bug #1191: Picking up papers without inventory in new game
+Bug #1195: NPCs do not equip torches in certain interiors
+Bug #1197: mouse wheel makes things scroll too fast
+Bug #1200: door blocked by monsters
+Bug #1201: item's magical charges are only refreshed when they are used
+Bug #1203: Scribs do not defend themselves
+Bug #1204: creatures life is not empty when they are dead
+Bug #1205: armor experience does not progress when hits are taken
+Bug #1206: blood particules always red. Undeads and mechanicals should have a different one.
+Bug #1209: Tarhiel never falls
+Bug #1210: journal adding script is ran again after having saved/loaded
+Bug #1224: Names of custom classes are not properly handled in save games
+Bug #1227: Editor: Fixed case handling for broken localised versions of Morrowind.esm
+Bug #1235: Indoors walk stutter
+Bug #1236: Aborting intro movie brings up the menu
+Bug #1239: NPCs get stuck when walking past each other
+Bug #1240: BTB - Settings 14.1 and Health Bar.
+Bug #1241: BTB - Character and Khajiit Prejudice
+Bug #1248: GUI Weapon icon is changed to hand-to-hand after save load
+Bug #1254: Guild ranks do not show in dialogue
+Bug #1255: When opening a container and selecting "Take All", the screen flashes blue
+Bug #1260: Level Up menu doesn't show image when using a custom class
+Bug #1265: Quit Menu Has Misaligned Buttons
+Bug #1270: Active weapon icon is not updated when weapon is repaired
+Bug #1271: NPC Stuck in hovering "Jumping" animation
+Bug #1272: Crash when attempting to load Big City esm file.
+Bug #1276: Editor: Dropping a region into the filter of a cell subview fails
+Bug #1286: Dialogue topic list clips with window frame
+Bug #1291: Saved game: store faction membership
+Bug #1293: Pluginless Khajiit Head Pack by ashiraniir makes OpenMW close.
+Bug #1294: Pasting in console adds text to end, not at cursor
+Bug #1295: Conversation loop when asking about "specific place" in Vivec
+Bug #1296: Caius doesn't leave at start of quest "Mehra Milo and the Lost Prophecies"
+Bug #1297: Saved game: map markers
+Bug #1302: ring_keley script causes vector::_M_range_check exception
+Bug #1309: Bug on "You violated the law" dialog
+Bug #1319: Creatures sometimes rendered incorrectly
+Feature #50: Ranged Combat
+Feature #58: Sneaking Skill
+Feature #73: Crime and Punishment
+Feature #135: Editor: OGRE integration
+Feature #541: Editor: Dialogue Sub-Views
+Feature #853: Editor: Rework User Settings
+Feature #944: Editor: lighting modes
+Feature #945: Editor: Camera navigation mode
+Feature #953: Trader gold
+Feature #1140: AI: summoned creatures
+Feature #1142: AI follow: Run stance
+Feature #1154: Not all NPCs get aggressive when one is attacked
+Feature #1169: Terrain threading
+Feature #1172: Loading screen and progress bars during saved/loading game
+Feature #1173: Saved Game: include weather state
+Feature #1207: Class creation form does not remember
+Feature #1220: Editor: Preview Subview
+Feature #1223: Saved Game: Local Variables
+Feature #1229: Quicksave, quickload, autosave
+Feature #1230: Deleting saves
+Feature #1233: Bribe gold is placed into NPCs inventory
+Feature #1252: Saved Game: quick key bindings
+Feature #1273: Editor: Region Map context menu
+Feature #1274: Editor: Region Map drag & drop
+Feature #1275: Editor: Scene subview drop
+Feature #1282: Non-faction member crime recognition.
+Feature #1289: NPCs return to default position
+Task #941: Remove unused cmake files
+
+0.29.0
+
+Bug #556: Video soundtrack not played when music volume is set to zero
+Bug #829: OpenMW uses up all available vram, when playing for extended time
+Bug #848: Wrong amount of footsteps playing in 1st person
+Bug #888: Ascended Sleepers have movement issues
+Bug #892: Explicit references are allowed on all script functions
+Bug #999: Graphic Herbalism (mod): sometimes doesn't activate properly
+Bug #1009: Lake Fjalding AI related slowdown.
+Bug #1041: Music playback issues on OS X >= 10.9
+Bug #1043: No message box when advancing skill "Speechcraft" while in dialog window
+Bug #1060: Some message boxes are cut off at the bottom
+Bug #1062: Bittercup script does not work ('end' variable)
+Bug #1074: Inventory paperdoll obscures armour rating
+Bug #1077: Message after killing an essential NPC disappears too fast
+Bug #1078: "Clutterbane" shows empty charge bar
+Bug #1083: UndoWerewolf fails
+Bug #1088: Better Clothes Bloodmoon Plus 1.5 by Spirited Treasure pants are not rendered
+Bug #1090: Start scripts fail when going to a non-predefined cell
+Bug #1091: Crash: Assertion `!q.isNaN() && "Invalid orientation supplied as parameter"' failed.
+Bug #1093: Weapons of aggressive NPCs are invisible after you exit and re-enter interior
+Bug #1105: Magicka is depleted when using uncastable spells
+Bug #1106: Creatures should be able to run
+Bug #1107: TR cliffs have way too huge collision boxes in OpenMW
+Bug #1109: Cleaning True Light and Darkness with Tes3cmd makes Addamasartus , Zenarbael and Yasamsi flooded.
+Bug #1114: Bad output for desktop-file-validate on openmw.desktop (and opencs.desktop)
+Bug #1115: Memory leak when spying on Fargoth
+Bug #1137: Script execution fails (drenSlaveOwners script)
+Bug #1143: Mehra Milo quest (vivec informants) is broken
+Bug #1145: Issues with moving gold between inventory and containers
+Bug #1146: Issues with picking up stacks of gold
+Bug #1147: Dwemer Crossbows are held incorrectly
+Bug #1158: Armor rating should always stay below inventory mannequin
+Bug #1159: Quick keys can be set during character generation
+Bug #1160: Crash on equip lockpick when
+Bug #1167: Editor: Referenceables are not correctly loaded when dealing with more than one content file
+Bug #1184: Game Save: overwriting an existing save does not actually overwrites the file
+Feature #30: Loading/Saving (still missing a few parts)
+Feature #101: AI Package: Activate
+Feature #103: AI Package: Follow, FollowCell
+Feature #138: Editor: Drag & Drop
+Feature #428: Player death
+Feature #505: Editor: Record Cloning
+Feature #701: Levelled creatures
+Feature #708: Improved Local Variable handling
+Feature #709: Editor: Script verifier
+Feature #764: Missing journal backend features
+Feature #777: Creature weapons/shields
+Feature #789: Editor: Referenceable record verifier
+Feature #924: Load/Save GUI (still missing loading screen and progress bars)
+Feature #946: Knockdown
+Feature #947: Decrease fatigue when running, swimming and attacking
+Feature #956: Melee Combat: Blocking
+Feature #957: Area magic
+Feature #960: Combat/AI combat for creatures
+Feature #962: Combat-Related AI instructions
+Feature #1075: Damage/Restore skill/attribute magic effects
+Feature #1076: Soultrap magic effect
+Feature #1081: Disease contraction
+Feature #1086: Blood particles
+Feature #1092: Interrupt resting
+Feature #1101: Inventory equip scripts
+Feature #1116: Version/Build number in Launcher window
+Feature #1119: Resistance/weakness to normal weapons magic effect
+Feature #1123: Slow Fall magic effect
+Feature #1130: Auto-calculate spells
+Feature #1164: Editor: Case-insensitive sorting in tables
+
+0.28.0
+
+Bug #399: Inventory changes are not visible immediately
+Bug #417: Apply weather instantly when teleporting
+Bug #566: Global Map position marker not updated for interior cells
+Bug #712: Looting corpse delay
+Bug #716: Problem with the "Vurt's Ascadian Isles Mod" mod
+Bug #805: Two TR meshes appear black (v0.24RC)
+Bug #841: Third-person activation distance taken from camera rather than head
+Bug #845: NPCs hold torches during the day
+Bug #855: Vvardenfell Visages Volume I some hairs don´t appear since 0,24
+Bug #856: Maormer race by Mac Kom - The heads are way up
+Bug #864: Walk locks during loading in 3rd person
+Bug #871: active weapon/magic item icon is not immediately made blank if item is removed during dialog
+Bug #882: Hircine's Ring doesn't always work
+Bug #909: [Tamriel Rebuilt] crashes in Akamora
+Bug #922: Launcher writing merged openmw.cfg files
+Bug #943: Random magnitude should be calculated per effect
+Bug #948: Negative fatigue level should be allowed
+Bug #949: Particles in world space
+Bug #950: Hard crash on x64 Linux running --new-game (on startup)
+Bug #951: setMagicka and setFatigue have no effect
+Bug #954: Problem with equipping inventory items when using a keyboard shortcut
+Bug #955: Issues with equipping torches
+Bug #966: Shield is visible when casting spell
+Bug #967: Game crashes when equipping silver candlestick
+Bug #970: Segmentation fault when starting at Bal Isra
+Bug #977: Pressing down key in console doesn't go forward in history
+Bug #979: Tooltip disappears when changing inventory
+Bug #980: Barter: item category is remembered, but not shown
+Bug #981: Mod: replacing model has wrong position/orientation
+Bug #982: Launcher: Addon unchecking is not saved
+Bug #983: Fix controllers to affect objects attached to the base node
+Bug #985: Player can talk to NPCs who are in combat
+Bug #989: OpenMW crashes when trying to include mod with capital .ESP
+Bug #991: Merchants equip items with harmful constant effect enchantments
+Bug #994: Don't cap skills/attributes when set via console
+Bug #998: Setting the max health should also set the current health
+Bug #1005: Torches are visible when casting spells and during hand to hand combat.
+Bug #1006: Many NPCs have 0 skill
+Bug #1007: Console fills up with text
+Bug #1013: Player randomly loses health or dies
+Bug #1014: Persuasion window is not centered in maximized window
+Bug #1015: Player status window scroll state resets on status change
+Bug #1016: Notification window not big enough for all skill level ups
+Bug #1020: Saved window positions are not rescaled appropriately on resolution change
+Bug #1022: Messages stuck permanently on screen when they pile up
+Bug #1023: Journals doesn't open
+Bug #1026: Game loses track of torch usage.
+Bug #1028: Crash on pickup of jug in Unexplored Shipwreck, Upper level
+Bug #1029: Quick keys menu: Select compatible replacement when tool used up
+Bug #1042: TES3 header data wrong encoding
+Bug #1045: OS X: deployed OpenCS won't launch
+Bug #1046: All damaged weaponry is worth 1 gold
+Bug #1048: Links in "locked" dialogue are still clickable
+Bug #1052: Using color codes when naming your character actually changes the name's color
+Bug #1054: Spell effects not visible in front of water
+Bug #1055: Power-Spell animation starts even though you already casted it that day
+Bug #1059: Cure disease potion removes all effects from player, even your race bonus and race ability
+Bug #1063: Crash upon checking out game start ship area in Seyda Neen
+Bug #1064: openmw binaries link to unnecessary libraries
+Bug #1065: Landing from a high place in water still causes fall damage
+Bug #1072: Drawing weapon increases torch brightness
+Bug #1073: Merchants sell stacks of gold
+Feature #43: Visuals for Magic Effects
+Feature #51: Ranged Magic
+Feature #52: Touch Range Magic
+Feature #53: Self Range Magic
+Feature #54: Spell Casting
+Feature #70: Vampirism
+Feature #100: Combat AI
+Feature #171: Implement NIF record NiFlipController
+Feature #410: Window to restore enchanted item charge
+Feature #647: Enchanted item glow
+Feature #723: Invisibility/Chameleon magic effects
+Feature #737: Resist Magicka magic effect
+Feature #758: GetLOS
+Feature #926: Editor: Info-Record tables
+Feature #958: Material controllers
+Feature #959: Terrain bump, specular, & parallax mapping
+Feature #990: Request: unlock mouse when in any menu
+Feature #1018: Do not allow view mode switching while performing an action
+Feature #1027: Vertex morph animation (NiGeomMorpherController)
+Feature #1031: Handle NiBillboardNode
+Feature #1051: Implement NIF texture slot DarkTexture
+Task #873: Unify OGRE initialisation
+
+0.27.0
+
+Bug #597: Assertion `dialogue->mId == id' failed in esmstore.cpp
+Bug #794: incorrect display of decimal numbers
+Bug #840: First-person sneaking camera height
+Bug #887: Ambient sounds playing while paused
+Bug #902: Problems with Polish character encoding
+Bug #907: Entering third person using the mousewheel is possible even if it's impossible using the key
+Bug #910: Some CDs not working correctly with Unshield installer
+Bug #917: Quick character creation plugin does not work
+Bug #918: Fatigue does not refill
+Bug #919: The PC falls dead in Beshara - OpenMW nightly Win64 (708CDE2)
+Feature #57: Acrobatics Skill
+Feature #462: Editor: Start Dialogue
+Feature #546: Modify ESX selector to handle new content file scheme
+Feature #588: Editor: Adjust name/path of edited content files
+Feature #644: Editor: Save
+Feature #710: Editor: Configure script compiler context
+Feature #790: God Mode
+Feature #881: Editor: Allow only one instance of OpenCS
+Feature #889: Editor: Record filtering
+Feature #895: Extinguish torches
+Feature #898: Breath meter enhancements
+Feature #901: Editor: Default record filter
+Feature #913: Merge --master and --plugin switches
+
+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
+Bug #604: Terrible performance drop in the Census and Excise Office.
+Bug #676: Start Scripts fail to load
+Bug #677: OpenMW does not accept script names with -
+Bug #766: Extra space in front of topic links
+Bug #793: AIWander Isn't Being Passed The Repeat Parameter
+Bug #795: Sound playing with drawn weapon and crossing cell-border
+Bug #800: can't select weapon for enchantment
+Bug #801: Player can move while over-encumbered
+Bug #802: Dead Keys not working
+Bug #808: mouse capture
+Bug #809: ini Importer does not work without an existing cfg file
+Bug #812: Launcher will run OpenMW with no ESM or ESP selected
+Bug #813: OpenMW defaults to Morrowind.ESM with no ESM or ESP selected
+Bug #817: Dead NPCs and Creatures still have collision boxes
+Bug #820: Incorrect sorting of answers (Dialogue)
+Bug #826: mwinimport dumps core when given an unknown parameter
+Bug #833: getting stuck in door
+Bug #835: Journals/books not showing up properly.
+Feature #38: SoundGen
+Feature #105: AI Package: Wander
+Feature #230: 64-bit compatibility for OS X
+Feature #263: Hardware mouse cursors
+Feature #449: Allow mouse outside of window while paused
+Feature #736: First person animations
+Feature #750: Using mouse wheel in third person mode
+Feature #822: Autorepeat for slider buttons
+
+0.24.0
+
+Bug #284: Book's text misalignment
+Bug #445: Camera able to get slightly below floor / terrain
+Bug #582: Seam issue in Red Mountain
+Bug #632: Journal Next Button shows white square
+Bug #653: IndexedStore ignores index
+Bug #694: Parser does not recognize float values starting with .
+Bug #699: Resource handling broken with Ogre 1.9 trunk
+Bug #718: components/esm/loadcell is using the mwworld subsystem
+Bug #729: Levelled item list tries to add nonexistent item
+Bug #730: Arrow buttons in the settings menu do not work.
+Bug #732: Erroneous behavior when binding keys
+Bug #733: Unclickable dialogue topic
+Bug #734: Book empty line problem
+Bug #738: OnDeath only works with implicit references
+Bug #740: Script compiler fails on scripts with special names
+Bug #742: Wait while no clipping
+Bug #743: Problem with changeweather console command
+Bug #744: No wait dialogue after starting a new game
+Bug #748: Player is not able to unselect objects with the console
+Bug #751: AddItem should only spawn a message box when called from dialogue
+Bug #752: The enter button has several functions in trade and looting that is not impelemted.
+Bug #753: Fargoth's Ring Quest Strange Behavior
+Bug #755: Launcher writes duplicate lines into settings.cfg
+Bug #759: Second quest in mages guild does not work
+Bug #763: Enchantment cast cost is wrong
+Bug #770: The "Take" and "Close" buttons in the scroll GUI are stretched incorrectly
+Bug #773: AIWander Isn't Being Passed The Correct idle Values
+Bug #778: The journal can be opened at the start of a new game
+Bug #779: Divayth Fyr starts as dead
+Bug #787: "Batch count" on detailed FPS counter gets cut-off
+Bug #788: chargen scroll layout does not match vanilla
+Feature #60: Atlethics Skill
+Feature #65: Security Skill
+Feature #74: Interaction with non-load-doors
+Feature #98: Render Weapon and Shield
+Feature #102: AI Package: Escort, EscortCell
+Feature #182: Advanced Journal GUI
+Feature #288: Trading enhancements
+Feature #405: Integrate "new game" into the menu
+Feature #537: Highlight dialogue topic links
+Feature #658: Rotate, RotateWorld script instructions and local rotations
+Feature #690: Animation Layering
+Feature #722: Night Eye/Blind magic effects
+Feature #735: Move, MoveWorld script instructions.
+Feature #760: Non-removable corpses
+
+0.23.0
+
+Bug #522: Player collides with placeable items
+Bug #553: Open/Close sounds played when accessing main menu w/ Journal Open
+Bug #561: Tooltip word wrapping delay
+Bug #578: Bribing works incorrectly
+Bug #601: PositionCell fails on negative coordinates
+Bug #606: Some NPCs hairs not rendered with Better Heads addon
+Bug #609: Bad rendering of bone boots
+Bug #613: Messagebox causing assert to fail
+Bug #631: Segfault on shutdown
+Bug #634: Exception when talking to Calvus Horatius in Mournhold, royal palace courtyard
+Bug #635: Scale NPCs depending on race
+Bug #643: Dialogue Race select function is inverted
+Bug #646: Twohanded weapons don't work properly
+Bug #654: Crash when dropping objects without a collision shape
+Bug #655/656: Objects that were disabled or deleted (but not both) were added to the scene when re-entering a cell
+Bug #660: "g" in "change" cut off in Race Menu
+Bug #661: Arrille sells me the key to his upstairs room
+Bug #662: Day counter starts at 2 instead of 1
+Bug #663: Cannot select "come unprepared" topic in dialog with Dagoth Ur
+Bug #665: Pickpocket -> "Grab all" grabs all NPC inventory, even not listed in container window.
+Bug #666: Looking up/down problem
+Bug #667: Active effects border visible during loading
+Bug #669: incorrect player position at new game start
+Bug #670: race selection menu: sex, face and hair left button not totally clickable
+Bug #671: new game: player is naked
+Bug #674: buying or selling items doesn't change amount of gold
+Bug #675: fatigue is not set to its maximum when starting a new game
+Bug #678: Wrong rotation order causes RefData's rotation to be stored incorrectly
+Bug #680: different gold coins in Tel Mara
+Bug #682: Race menu ignores playable flag for some hairs and faces
+Bug #685: Script compiler does not accept ":" after a function name
+Bug #688: dispose corpse makes cross-hair to disappear
+Bug #691: Auto equipping ignores equipment conditions
+Bug #692: OpenMW doesnt load "loose file" texture packs that places resources directly in data folder
+Bug #696: Draugr incorrect head offset
+Bug #697: Sail transparency issue
+Bug #700: "On the rocks" mod does not load its UV coordinates correctly.
+Bug #702: Some race mods don't work
+Bug #711: Crash during character creation
+Bug #715: Growing Tauryon
+Bug #725: Auto calculate stats
+Bug #728: Failure to open container and talk dialogue
+Bug #731: Crash with Mush-Mere's "background" topic
+Feature #55/657: Item Repairing
+Feature #62/87: Enchanting
+Feature #99: Pathfinding
+Feature #104: AI Package: Travel
+Feature #129: Levelled items
+Feature #204: Texture animations
+Feature #239: Fallback-Settings
+Feature #535: Console object selection improvements
+Feature #629: Add levelup description in levelup layout dialog
+Feature #630: Optional format subrecord in (tes3) header
+Feature #641: Armor rating
+Feature #645: OnDeath script function
+Feature #683: Companion item UI
+Feature #698: Basic Particles
+Task #648: Split up components/esm/loadlocks
+Task #695: mwgui cleanup
+
+0.22.0
+
+Bug #311: Potential infinite recursion in script compiler
+Bug #355: Keyboard repeat rate (in Xorg) are left disabled after game exit.
+Bug #382: Weird effect in 3rd person on water
+Bug #387: Always use detailed shape for physics raycasts
+Bug #420: Potion/ingredient effects do not stack
+Bug #429: Parts of dwemer door not picked up correctly for activation/tooltips
+Bug #434/Bug #605: Object movement between cells not properly implemented
+Bug #502: Duplicate player collision model at origin
+Bug #509: Dialogue topic list shifts inappropriately
+Bug #513: Sliding stairs
+Bug #515: Launcher does not support non-latin strings
+Bug #525: Race selection preview camera wrong position
+Bug #526: Attributes / skills should not go below zero
+Bug #529: Class and Birthsign menus options should be preselected
+Bug #530: Lock window button graphic missing
+Bug #532: Missing map menu graphics
+Bug #545: ESX selector does not list ESM files properly
+Bug #547: Global variables of type short are read incorrectly
+Bug #550: Invisible meshes collision and tooltip
+Bug #551: Performance drop when loading multiple ESM files
+Bug #552: Don't list CG in options if it is not available
+Bug #555: Character creation windows "OK" button broken
+Bug #558: Segmentation fault when Alt-tabbing with console opened
+Bug #559: Dialog window should not be available before character creation is finished
+Bug #560: Tooltip borders should be stretched
+Bug #562: Sound should not be played when an object cannot be picked up
+Bug #565: Water animation speed + timescale
+Bug #572: Better Bodies' textures don't work
+Bug #573: OpenMW doesn't load if TR_Mainland.esm is enabled (Tamriel Rebuilt mod)
+Bug #574: Moving left/right should not cancel auto-run
+Bug #575: Crash entering the Chamber of Song
+Bug #576: Missing includes
+Bug #577: Left Gloves Addon causes ESMReader exception
+Bug #579: Unable to open container "Kvama Egg Sack"
+Bug #581: Mimicking vanilla Morrowind water
+Bug #583: Gender not recognized
+Bug #586: Wrong char gen behaviour
+Bug #587: "End" script statements with spaces don't work
+Bug #589: Closing message boxes by pressing the activation key
+Bug #590: Ugly Dagoth Ur rendering
+Bug #591: Race selection issues
+Bug #593: Persuasion response should be random
+Bug #595: Footless guard
+Bug #599: Waterfalls are invisible from a certain distance
+Bug #600: Waterfalls rendered incorrectly, cut off by water
+Bug #607: New beast bodies mod crashes
+Bug #608: Crash in cell "Mournhold, Royal Palace"
+Bug #611: OpenMW doesn't find some of textures used in Tamriel Rebuilt
+Bug #613: Messagebox causing assert to fail
+Bug #615: Meshes invisible from above water
+Bug #617: Potion effects should be hidden until discovered
+Bug #619: certain moss hanging from tree has rendering bug
+Bug #621: Batching bloodmoon's trees
+Bug #623: NiMaterialProperty alpha unhandled
+Bug #628: Launcher in latest master crashes the game
+Bug #633: Crash on startup: Better Heads
+Bug #636: Incorrect Char Gen Menu Behavior
+Feature #29: Allow ESPs and multiple ESMs
+Feature #94: Finish class selection-dialogue
+Feature #149: Texture Alphas
+Feature #237: Run Morrowind-ini importer from launcher
+Feature #286: Update Active Spell Icons
+Feature #334: Swimming animation
+Feature #335: Walking animation
+Feature #360: Proper collision shapes for NPCs and creatures
+Feature #367: Lights that behave more like original morrowind implementation
+Feature #477: Special local scripting variables
+Feature #528: Message boxes should close when enter is pressed under certain conditions.
+Feature #543: Add bsa files to the settings imported by the ini importer
+Feature #594: coordinate space and utility functions
+Feature #625: Zoom in vanity mode
+Task #464: Refactor launcher ESX selector into a re-usable component
+Task #624: Unified implementation of type-variable sub-records
+
+0.21.0
+
+Bug #253: Dialogs don't work for Russian version of Morrowind
+Bug #267: Activating creatures without dialogue can still activate the dialogue GUI
+Bug #354: True flickering lights
+Bug #386: The main menu's first entry is wrong (in french)
+Bug #479: Adding the spell "Ash Woe Blight" to the player causes strange attribute oscillations
+Bug #495: Activation Range
+Bug #497: Failed Disposition check doesn't stop a dialogue entry from being returned
+Bug #498: Failing a disposition check shouldn't eliminate topics from the the list of those available
+Bug #500: Disposition for most NPCs is 0/100
+Bug #501: Getdisposition command wrongly returns base disposition
+Bug #506: Journal UI doesn't update anymore
+Bug #507: EnableRestMenu is not a valid command - change it to EnableRest
+Bug #508: Crash in Ald Daedroth Shrine
+Bug #517: Wrong price calculation when untrading an item
+Bug #521: MWGui::InventoryWindow creates a duplicate player actor at the origin
+Bug #524: Beast races are able to wear shoes
+Bug #527: Background music fails to play
+Bug #533: The arch at Gnisis entrance is not displayed
+Bug #534: Terrain gets its correct shape only some time after the cell is loaded
+Bug #536: The same entry can be added multiple times to the journal
+Bug #539: Race selection is broken
+Bug #544: Terrain normal map corrupt when the map is rendered
+Feature #39: Video Playback
+Feature #151: ^-escape sequences in text output
+Feature #392: Add AI related script functions
+Feature #456: Determine required ini fallback values and adjust the ini importer accordingly
+Feature #460: Experimental DirArchives improvements
+Feature #540: Execute scripts of objects in containers/inventories in active cells
+Task #401: Review GMST fixing
+Task #453: Unify case smashing/folding
+Task #512: Rewrite utf8 component
+
+0.20.0
+
+Bug #366: Changing the player's race during character creation does not change the look of the player character
+Bug #430: Teleporting and using loading doors linking within the same cell reloads the cell
+Bug #437: Stop animations when paused
+Bug #438: Time displays as "0 a.m." when it should be "12 a.m."
+Bug #439: Text in "name" field of potion/spell creation window is persistent
+Bug #440: Starting date at a new game is off by one day
+Bug #442: Console window doesn't close properly sometimes
+Bug #448: Do not break container window formatting when item names are very long
+Bug #458: Topics sometimes not automatically added to known topic list
+Bug #476: Auto-Moving allows player movement after using DisablePlayerControls
+Bug #478: After sleeping in a bed the rest dialogue window opens automtically again
+Bug #492: On creating potions the ingredients are removed twice
+Feature #63: Mercantile skill
+Feature #82: Persuasion Dialogue
+Feature #219: Missing dialogue filters/functions
+Feature #369: Add a FailedAction
+Feature #377: Select head/hair on character creation
+Feature #391: Dummy AI package classes
+Feature #435: Global Map, 2nd Layer
+Feature #450: Persuasion
+Feature #457: Add more script instructions
+Feature #474: update the global variable pcrace when the player's race is changed
+Task #158: Move dynamically generated classes from Player class to World Class
+Task #159: ESMStore rework and cleanup
+Task #163: More Component Namespace Cleanup
+Task #402: Move player data from MWWorld::Player to the player's NPC record
+Task #446: Fix no namespace in BulletShapeLoader
+
+0.19.0
+
+Bug #374: Character shakes in 3rd person mode near the origin
+Bug #404: Gamma correct rendering
+Bug #407: Shoes of St. Rilm do not work
+Bug #408: Rugs has collision even if they are not supposed to
+Bug #412: Birthsign menu sorted incorrectly
+Bug #413: Resolutions presented multiple times in launcher
+Bug #414: launcher.cfg file stored in wrong directory
+Bug #415: Wrong esm order in openmw.cfg
+Bug #418: Sound listener position updates incorrectly
+Bug #423: wrong usage of "Version" entry in openmw.desktop
+Bug #426: Do not use hardcoded splash images
+Bug #431: Don't use markers for raycast
+Bug #432: Crash after picking up items from an NPC
+Feature #21/#95: Sleeping/resting
+Feature #61: Alchemy Skill
+Feature #68: Death
+Feature #69/#86: Spell Creation
+Feature #72/#84: Travel
+Feature #76: Global Map, 1st Layer
+Feature #120: Trainer Window
+Feature #152: Skill Increase from Skill Books
+Feature #160: Record Saving
+Task #400: Review GMST access
+
+0.18.0
+
+Bug #310: Button of the "preferences menu" are too small
+Bug #361: Hand-to-hand skill is always 100
+Bug #365: NPC and creature animation is jerky; Characters float around when they are not supposed to
+Bug #372: playSound3D uses original coordinates instead of current coordinates.
+Bug #373: Static OGRE build faulty
+Bug #375: Alt-tab toggle view
+Bug #376: Screenshots are disable
+Bug #378: Exception when drinking self-made potions
+Bug #380: Cloth visibility problem
+Bug #384: Weird character on doors tooltip.
+Bug #398: Some objects do not collide in MW, but do so in OpenMW
+Feature #22: Implement level-up
+Feature #36: Hide Marker
+Feature #88: Hotkey Window
+Feature #91: Level-Up Dialogue
+Feature #118: Keyboard and Mouse-Button bindings
+Feature #119: Spell Buying Window
+Feature #133: Handle resources across multiple data directories
+Feature #134: Generate a suitable default-value for --data-local
+Feature #292: Object Movement/Creation Script Instructions
+Feature #340: AIPackage data structures
+Feature #356: Ingredients use
+Feature #358: Input system rewrite
+Feature #370: Target handling in actions
+Feature #379: Door markers on the local map
+Feature #389: AI framework
+Feature #395: Using keys to open doors / containers
+Feature #396: Loading screens
+Feature #397: Inventory avatar image and race selection head preview
+Task #339: Move sounds into Action
+
+0.17.0
+
+Bug #225: Valgrind reports about 40MB of leaked memory
+Bug #241: Some physics meshes still don't match
+Bug #248: Some textures are too dark
+Bug #300: Dependency on proprietary CG toolkit
+Bug #302: Some objects don't collide although they should
+Bug #308: Freeze in Balmora, Meldor: Armorer
+Bug #313: openmw without a ~/.config/openmw folder segfault.
+Bug #317: adding non-existing spell via console locks game
+Bug #318: Wrong character normals
+Bug #341: Building with Ogre Debug libraries does not use debug version of plugins
+Bug #347: Crash when running openmw with --start="XYZ"
+Bug #353: FindMyGUI.cmake breaks path on Windows
+Bug #359: WindowManager throws exception at destruction
+Bug #364: Laggy input on OS X due to bug in Ogre's event pump implementation
+Feature #33: Allow objects to cross cell-borders
+Feature #59: Dropping Items (replaced stopgap implementation with a proper one)
+Feature #93: Main Menu
+Feature #96/329/330/331/332/333: Player Control
+Feature #180: Object rotation and scaling.
+Feature #272: Incorrect NIF material sharing
+Feature #314: Potion usage
+Feature #324: Skill Gain
+Feature #342: Drain/fortify dynamic stats/attributes magic effects
+Feature #350: Allow console only script instructions
+Feature #352: Run scripts in console on startup
+Task #107: Refactor mw*-subsystems
+Task #325: Make CreatureStats into a class
+Task #345: Use Ogre's animation system
+Task #351: Rewrite Action class to support automatic sound playing
+
+0.16.0
+
+Bug #250: OpenMW launcher erratic behaviour
+Bug #270: Crash because of underwater effect on OS X
+Bug #277: Auto-equipping in some cells not working
+Bug #294: Container GUI ignores disabled inventory menu
+Bug #297: Stats review dialog shows all skills and attribute values as 0
+Bug #298: MechanicsManager::buildPlayer does not remove previous bonuses
+Bug #299: Crash in World::disable
+Bug #306: Non-existent ~/.config/openmw "crash" the launcher.
+Bug #307: False "Data Files" location make the launcher "crash"
+Feature #81: Spell Window
+Feature #85: Alchemy Window
+Feature #181: Support for x.y script syntax
+Feature #242: Weapon and Spell icons
+Feature #254: Ingame settings window
+Feature #293: Allow "stacking" game modes
+Feature #295: Class creation dialog tooltips
+Feature #296: Clicking on the HUD elements should show/hide the respective window
+Feature #301: Direction after using a Teleport Door
+Feature #303: Allow object selection in the console
+Feature #305: Allow the use of = as a synonym for ==
+Feature #312: Compensation for slow object access in poorly written Morrowind.esm scripts
+Task #176: Restructure enabling/disabling of MW-references
+Task #283: Integrate ogre.cfg file in settings file
+Task #290: Auto-Close MW-reference related GUI windows
+
+0.15.0
+
+Bug #5: Physics reimplementation (fixes various issues)
+Bug #258: Resizing arrow's background is not transparent
+Bug #268: Widening the stats window in X direction causes layout problems
+Bug #269: Topic pane in dialgoue window is too small for some longer topics
+Bug #271: Dialog choices are sorted incorrectly
+Bug #281: The single quote character is not rendered on dialog windows
+Bug #285: Terrain not handled properly in cells that are not predefined
+Bug #289: Dialogue filter isn't doing case smashing/folding for item IDs
+Feature #15: Collision with Terrain
+Feature #17: Inventory-, Container- and Trade-Windows
+Feature #44: Floating Labels above Focussed Objects
+Feature #80: Tooltips
+Feature #83: Barter Dialogue
+Feature #90: Book and Scroll Windows
+Feature #156: Item Stacking in Containers
+Feature #213: Pulsating lights
+Feature #218: Feather & Burden
+Feature #256: Implement magic effect bookkeeping
+Feature #259: Add missing information to Stats window
+Feature #260: Correct case for dialogue topics
+Feature #280: GUI texture atlasing
+Feature #291: Ability to use GMST strings from GUI layout files
+Task #255: Make MWWorld::Environment into a singleton
+
+0.14.0
+
+Bug #1: Meshes rendered with wrong orientation
+Bug #6/Task #220: Picking up small objects doesn't always work
+Bug #127: tcg doesn't work
+Bug #178: Compablity problems with Ogre 1.8.0 RC 1
+Bug #211: Wireframe mode (toggleWireframe command) should not apply to Console & other UI
+Bug #227: Terrain crashes when moving away from predefined cells
+Bug #229: On OS X Launcher cannot launch game if path to binary contains spaces
+Bug #235: TGA texture loading problem
+Bug #246: wireframe mode does not work in water
+Feature #8/#232: Water Rendering
+Feature #13: Terrain Rendering
+Feature #37: Render Path Grid
+Feature #66: Factions
+Feature #77: Local Map
+Feature #78: Compass/Mini-Map
+Feature #97: Render Clothing/Armour
+Feature #121: Window Pinning
+Feature #205: Auto equip
+Feature #217: Contiainer should track changes to its content
+Feature #221: NPC Dialogue Window Enhancements
+Feature #233: Game settings manager
+Feature #240: Spell List and selected spell (no GUI yet)
+Feature #243: Draw State
+Task #113: Morrowind.ini Importer
+Task #215: Refactor the sound code
+Task #216: Update MyGUI
+
+0.13.0
+
+Bug #145: Fixed sound problems after cell change
+Bug #179: Pressing space in console triggers activation
+Bug #186: CMake doesn't use the debug versions of Ogre libraries on Linux
+Bug #189: ASCII 16 character added to console on it's activation on Mac OS X
+Bug #190: Case Folding fails with music files
+Bug #192: Keypresses write Text into Console no matter which gui element is active
+Bug #196: Collision shapes out of place
+Bug #202: ESMTool doesn't not work with localised ESM files anymore
+Bug #203: Torch lights only visible on short distance
+Bug #207: Ogre.log not written
+Bug #209: Sounds do not play
+Bug #210: Ogre crash at Dren plantation
+Bug #214: Unsupported file format version
+Bug #222: Launcher is writing openmw.cfg file to wrong location
+Feature #9: NPC Dialogue Window
+Feature #16/42: New sky/weather implementation
+Feature #40: Fading
+Feature #48: NPC Dialogue System
+Feature #117: Equipping Items (backend only, no GUI yet, no rendering of equipped items yet)
+Feature #161: Load REC_PGRD records
+Feature #195: Wireframe-mode
+Feature #198/199: Various sound effects
+Feature #206: Allow picking data path from launcher if non is set
+Task #108: Refactor window manager class
+Task #172: Sound Manager Cleanup
+Task #173: Create OpenEngine systems in the appropriate manager classes
+Task #184: Adjust MSVC and gcc warning levels
+Task #185: RefData rewrite
+Task #201: Workaround for transparency issues
+Task #208: silenced esm_reader.hpp warning
+
+0.12.0
+
+Bug #154: FPS Drop
+Bug #169: Local scripts continue running if associated object is deleted
+Bug #174: OpenMW fails to start if the config directory doesn't exist
+Bug #187: Missing lighting
+Bug #188: Lights without a mesh are not rendered
+Bug #191: Taking screenshot causes crash when running installed
+Feature #28: Sort out the cell load problem
+Feature #31: Allow the player to move away from pre-defined cells
+Feature #35: Use alternate storage location for modified object position
+Feature #45: NPC animations
+Feature #46: Creature Animation
+Feature #89: Basic Journal Window
+Feature #110: Automatically pick up the path of existing MW-installations
+Feature #183: More FPS display settings
+Task #19: Refactor engine class
+Task #109/Feature #162: Automate Packaging
+Task #112: Catch exceptions thrown in input handling functions
+Task #128/#168: Cleanup Configuration File Handling
+Task #131: NPC Activation doesn't work properly
+Task #144: MWRender cleanup
+Task #155: cmake cleanup
+
+0.11.1
+
+Bug #2: Resources loading doesn't work outside of bsa files
+Bug #3: GUI does not render non-English characters
+Bug #7: openmw.cfg location doesn't match
+Bug #124: The TCL alias for ToggleCollision is missing.
+Bug #125: Some command line options can't be used from a .cfg file
+Bug #126: Toggle-type script instructions are less verbose compared with original MW
+Bug #130: NPC-Record Loading fails for some NPCs
+Bug #167: Launcher sets invalid parameters in ogre config
+Feature #10: Journal
+Feature #12: Rendering Optimisations
+Feature #23: Change Launcher GUI to a tabbed interface
+Feature #24: Integrate the OGRE settings window into the launcher
+Feature #25: Determine openmw.cfg location (Launcher)
+Feature #26: Launcher Profiles
+Feature #79: MessageBox
+Feature #116: Tab-Completion in Console
+Feature #132: --data-local and multiple --data
+Feature #143: Non-Rendering Performance-Optimisations
+Feature #150: Accessing objects in cells via ID does only work for objects with all lower case IDs
+Feature #157: Version Handling
+Task #14: Replace tabs with 4 spaces
+Task #18: Move components from global namespace into their own namespace
+Task #123: refactor header files in components/esm
+
+0.10.0
+
+* NPC dialogue window (not functional yet)
+* Collisions with objects
+* Refactor the PlayerPos class
+* Adjust file locations
+* CMake files and test linking for Bullet
+* Replace Ogre raycasting test for activation with something more precise
+* Adjust player movement according to collision results
+* FPS display
+* Various Portability Improvements
+* Mac OS X support is back!
+
+0.9.0
+
+* Exterior cells loading, unloading and management
+* Character Creation GUI
+* Character creation
+* Make cell names case insensitive when doing internal lookups
+* Music player
+* NPCs rendering
+
+0.8.0
+
+* GUI
+* Complete and working script engine
+* In game console
+* Sky rendering
+* Sound and music
+* Tons of smaller stuff
+
+0.7.0
+
+* This release is a complete rewrite in C++.
+* All D code has been culled, and all modules have been rewritten.
+* The game is now back up to the level of rendering interior cells and moving around, but physics, sound, GUI, and scripting still remain to be ported from the old codebase.
+
+0.6.0
+
+* Coded a GUI system using MyGUI
+* Skinned MyGUI to look like Morrowind (work in progress)
+* Integrated the Monster script engine
+* Rewrote some functions into script code
+* Very early MyGUI < > Monster binding
+* Fixed Windows sound problems (replaced old openal32.dll)
+
+0.5.0
+
+* Collision detection with Bullet
+* Experimental walk & fall character physics
+* New key bindings:
+  * t toggle physics mode (walking, flying, ghost),
+  * n night eye, brightens the scene
+* Fixed incompatability with DMD 1.032 and newer compilers
+* * (thanks to tomqyp)
+* Various minor changes and updates
+
+0.4.0
+
+* Switched from Audiere to OpenAL
+* * (BIG thanks to Chris Robinson)
+* Added complete Makefile (again) as a alternative build tool
+* More realistic lighting (thanks again to Chris Robinson)
+* Various localization fixes tested with Russian and French versions
+* Temporary workaround for the Unicode issue: invalid UTF displayed as '?'
+* Added ns option to disable sound, for debugging
+* Various bug fixes
+* Cosmetic changes to placate gdc Wall
+
+0.3.0
+
+* Built and tested on Windows XP
+* Partial support for FreeBSD (exceptions do not work)
+* You no longer have to download Monster separately
+* Made an alternative for building without DSSS (but DSSS still works)
+* Renamed main program from 'morro' to 'openmw'
+* Made the config system more robust
+* Added oc switch for showing Ogre config window on startup
+* Removed some config files, these are auto generated when missing.
+* Separated plugins.cfg into linux and windows versions.
+* Updated Makefile and sources for increased portability
+* confirmed to work against OIS 1.0.0 (Ubuntu repository package)
+
+0.2.0
+
+* Compiles with gdc
+* Switched to DSSS for building D code
+* Includes the program esmtool
+
+0.1.0
+
+first release
+
diff --git a/README.md b/README.md index 304844892..862ae16c7 100644 --- a/README.md +++ b/README.md @@ -9,8 +9,7 @@ Morrowind by Bethesda Softworks. You need to own and install the original game f * Website: http://www.openmw.org Font Licenses: -DejaVuLGCSansMono.ttf: custom (see DejaVu Font License.txt for more information) - +* DejaVuLGCSansMono.ttf: custom (see DejaVu Font License.txt for more information) Installation ============ @@ -34,17 +33,15 @@ Build from source https://wiki.openmw.org/index.php?title=Development_Environment_Setup - The data path ============= -The data path tells OpenMW where to find your Morrowind files. If you run the launcher, OpenMW should be able to -pick up the location of these files on its own, if both Morrowind and OpenMW are installed properly -(installing Morrowind under WINE is considered a proper install). +The data path tells OpenMW where to find your Morrowind files. If you run the launcher, OpenMW should be able to pick up the location of these files on its own, if both Morrowind and OpenMW are installed properly (installing Morrowind under WINE is considered a proper install). Command line options ==================== +
 Syntax: openmw 
 Allowed options:
   --help                                print help message
@@ -99,1470 +96,9 @@ Allowed options:
   --fallback arg                        fallback values
   --no-grab                             Don't grab mouse cursor
   --activate-dist arg (=-1)             activation distance override
+
Changelog ========= -0.34.0 - -Bug #904: omwlauncher doesn't allow installing Tribunal and Bloodmoon if only MW is installed -Bug #986: Launcher: renaming profile names is broken -Bug #1061: "Browse to CD..." launcher crash -Bug #1135: Launcher crashes if user does not have write permission -Bug #1231: Current installer in launcher does not correctly import russian Morrowind.ini settings from setup.inx -Bug #1288: Fix the Alignment of the Resolution Combobox -Bug #1343: BIK videos occasionally out of sync with audio -Bug #1684: Morrowind Grass Mod graphical glitches -Bug #1734: NPC in fight with invisible/sneaking player -Bug #1982: Long class names are cut off in the UI -Bug #2012: Editor: OpenCS script compiler sometimes fails to find IDs -Bug #2015: Running while levitating does not affect speed but still drains fatigue -Bug #2018: OpenMW don´t reset modified cells to vanilla when a plugin is deselected and don´t apply changes to cells already visited. -Bug #2045: ToggleMenus command should close dialogue windows -Bug #2046: Crash: light_de_streetlight_01_223 -Bug #2047: Buglamp tooltip minor correction -Bug #2050: Roobrush floating texture bits -Bug #2053: Slaves react negatively to PC picking up slave's bracers -Bug #2055: Dremora corpses use the wrong model -Bug #2056: Mansilamat Vabdas's corpse is floating in the water -Bug #2057: "Quest: Larius Varro Tells A Little Story": Bounty not completely removed after finishing quest -Bug #2059: Silenced enemies try to cast spells anyway -Bug #2060: Editor: Special case implementation for top level window with single sub-window should be optional -Bug #2061: Editor: SubView closing that is not directly triggered by the user isn't handled properly -Bug #2063: Tribunal: Quest 'The Warlords' doesn't work -Bug #2064: Sneak attack on hostiles causes bounty -Bug #2065: Editor: Qt signal-slot error when closing a dialogue subview -Bug #2070: Loading ESP in OpenMW works but fails in OpenCS -Bug #2071: CTD in 0.33 -Bug #2073: Storm atronach animation stops now and then -Bug #2075: Molag Amur Region, Map shows water on solid ground -Bug #2080: game won't work with fair magicka regen -Bug #2082: NPCs appear frozen or switched off after leaving and quickly reentering a cell -Bug #2088: OpenMW is unable to play OGG files. -Bug #2093: Darth Gares talks to you in Ilunibi even when he's not there, screwing up the Main Quests -Bug #2095: Coordinate and rotation editing in the Reference table does not work. -Bug #2096: Some overflow fun and bartering exploit -Bug #2098: [D3D] Game crash on maximize -Bug #2099: Activate, player seems not to work -Bug #2104: Only labels are sensitive in buttons -Bug #2107: "Slowfall" effect is too weak -Bug #2114: OpenCS doesn't load an ESP file full of errors even though Vanilla MW Construction Set can -Bug #2117: Crash when encountering bandits on opposite side of river from the egg mine south of Balmora -Bug #2124: [Mod: Baldurians Transparent Glass Amor] Armor above head -Bug #2125: Unnamed NiNodes in weapons problem in First Person -Bug #2126: Dirty dialog script in tribunal.esm causing bug in Tribunal MQ -Bug #2128: Crash when picking character's face -Bug #2129: Disable the third-person zoom feature by default -Bug #2130: Ash storm particles shown too long during transition to clear sky -Bug #2137: Editor: exception caused by following the Creature column of a SoundGen record -Bug #2139: Mouse movement should be ignored during intro video -Bug #2143: Editor: Saving is broken -Bug #2145: OpenMW - crash while exiting x64 debug build -Bug #2152: You can attack Almalexia during her final monologue -Bug #2154: Visual effects behave weirdly after loading/taking a screenshot -Bug #2155: Vivec has too little magicka -Bug #2156: Azura's spirit fades away too fast -Bug #2158: [Mod]Julan Ashlander Companion 2.0: Negative magicka -Bug #2161: Editor: combat/magic/stealth values of creature not displayed correctly -Bug #2163: OpenMW can't detect death if the NPC die by the post damage effect of a magic weapon. -Bug #2168: Westly's Master Head Pack X – Some hairs aren't rendered correctly. -Bug #2170: Mods using conversations to update PC inconsistant -Bug #2180: Editor: Verifier doesn't handle Windows-specific path issues when dealing with resources -Bug #2212: Crash or unexpected behavior while closing OpenCS cell render window on OS X -Feature #238: Add UI to run INI-importer from the launcher -Feature #854: Editor: Add user setting to show status bar -Feature #987: Launcher: first launch instructions for CD need to be more explicit -Feature #1232: There is no way to set the "encoding" option using launcher UI. -Feature #1281: Editor: Render cell markers -Feature #1918: Editor: Functionality for Double-Clicking in Tables -Feature #1966: Editor: User Settings dialogue grouping/labelling/tooltips -Feature #2097: Editor: Edit position of references in 3D scene -Feature #2121: Editor: Add edit mode button to scene toolbar -Task #1965: Editor: Improve layout of user settings dialogue - -0.33.1 - -Bug #2108: OpenCS fails to build - -0.33.0 - -Bug #371: If console assigned to ` (probably to any symbolic key), "`" symbol will be added to console every time it closed -Bug #1148: Some books'/scrolls' contents are displayed incorrectly -Bug #1290: Editor: status bar is not updated when record filter is changed -Bug #1292: Editor: Documents are not removed on closing the last view -Bug #1301: Editor: File->Exit only checks the document it was issued from. -Bug #1353: Bluetooth on with no speaker connected results in significantly longer initial load times -Bug #1436: NPCs react from too far distance -Bug #1472: PC is placed on top of following NPC when changing cell -Bug #1487: Tall PC can get stuck in staircases -Bug #1565: Editor: Subviews are deleted on shutdown instead when they are closed -Bug #1623: Door marker on Ghorak Manor's balcony makes PC stuck -Bug #1633: Loaddoor to Sadrith Mora, Telvanni Council House spawns PC in the air -Bug #1655: Use Appropriate Application Icons on Windows -Bug #1679: Tribunal expansion, Meryn Othralas the backstage manager in the theatre group in Mournhold in the great bazaar district is floating a good feet above the ground. -Bug #1705: Rain is broken in third person -Bug #1706: Thunder and lighting still occurs while the game is paused during the rain -Bug #1708: No long jumping -Bug #1710: Editor: ReferenceableID drag to references record filter field creates incorrect filter -Bug #1712: Rest on Water -Bug #1715: "Cancel" button is not always on the same side of menu -Bug #1725: Editor: content file can be opened multiple times from the same dialogue -Bug #1730: [MOD: Less Generic Nerevarine] Compile failure attempting to enter the Corprusarium. -Bug #1733: Unhandled ffmpeg sample formats -Bug #1735: Editor: "Edit Record" context menu button not opening subview for journal infos -Bug #1750: Editor: record edits result in duplicate entries -Bug #1789: Editor: Some characters cannot be used in addon name -Bug #1803: Resizing the map does not keep the pre-resize center at the post-resize center -Bug #1821: Recovering Cloudcleaver quest: attacking Sosia is considered a crime when you side with Hlormar -Bug #1838: Editor: Preferences window appears off screen -Bug #1839: Editor: Record filter title should be moved two pixels to the right -Bug #1849: Subrecord error in MAO_Containers -Bug #1854: Knocked-out actors don't fully act knocked out -Bug #1855: "Soul trapped" sound doesn't play -Bug #1857: Missing sound effect for enchanted items with empty charge -Bug #1859: Missing console command: ResetActors (RA) -Bug #1861: Vendor category "MagicItems" is unhandled -Bug #1862: Launcher doesn't start if a file listed in launcher.cfg has correct name but wrong capitalization -Bug #1864: Editor: Region field for cell record in dialogue subview not working -Bug #1869: Editor: Change label "Musics" to "Music" -Bug #1870: Goblins killed while knocked down remain in knockdown-pose -Bug #1874: CellChanged events should not trigger when crossing exterior cell border -Bug #1877: Spriggans killed instantly if hit while regening -Bug #1878: Magic Menu text not un-highlighting correctly when going from spell to item as active magic -Bug #1881: Stuck in ceiling when entering castle karstaags tower -Bug #1884: Unlit torches still produce a burning sound -Bug #1885: Can type text in price field in barter window -Bug #1887: Equipped items do not emit sounds -Bug #1889: draugr lord aesliip will attack you and remain non-hostile -Bug #1892: Guard asks player to pay bounty of 0 gold -Bug #1895: getdistance should only return max float if ref and target are in different worldspaces -Bug #1896: Crash Report -Bug #1897: Conjured Equipment cant be re-equipped if removed -Bug #1898: Only Gidar Verothan follows you during establish the mine quest -Bug #1900: Black screen when you open the door and breath underwater -Bug #1904: Crash on casting recall spell -Bug #1906: Bound item checks should use the GMSTs -Bug #1907: Bugged door. Mournhold, The Winged Guar -Bug #1908: Crime reported for attacking Drathas Nerus's henchmen while they attack Dilborn -Bug #1909: Weird Quest Flow Infidelities quest -Bug #1910: Follower fighting with gone npc -Bug #1911: Npcs will drown themselves -Bug #1912: World map arrow stays static when inside a building -Bug #1920: Ulyne Henim disappears when game is loaded inside Vas -Bug #1922: alchemy-> potion of paralyze -Bug #1923: "levitation magic cannot be used here" shows outside of tribunal -Bug #1927: AI prefer melee over magic. -Bug #1929: Tamriel Rebuilt: Named cells that lie within the overlap with Morrowind.esm are not shown -Bug #1932: BTB - Spells 14.1 magic effects don´t overwrite the Vanilla ones but are added -Bug #1935: Stacks of items are worth more when sold individually -Bug #1940: Launcher does not list addon files if base game file is renamed to a different case -Bug #1946: Mod "Tel Nechim - moved" breaks savegames -Bug #1947: Buying/Selling price doesn't properly affect the growth of mercantile skill -Bug #1950: followers from east empire company quest will fight each other if combat happens with anything -Bug #1958: Journal can be scrolled indefinitely with a mouse wheel -Bug #1959: Follower not leaving party on quest end -Bug #1960: Key bindings not always saved correctly -Bug #1961: Spell merchants selling racial bonus spells -Bug #1967: segmentation fault on load saves -Bug #1968: Jump sounds are not controlled by footsteps slider, sound weird compared to footsteps -Bug #1970: PC suffers silently when taking damage from lava -Bug #1971: Dwarven Sceptre collision area is not removed after killing one -Bug #1974: Dalin/Daris Norvayne follows player indefinitely -Bug #1975: East Empire Company faction rank breaks during Raven Rock questline -Bug #1979: 0 strength = permanently over encumbered -Bug #1993: Shrine blessing in Maar Gan doesn't work -Bug #2008: Enchanted items do not recharge -Bug #2011: Editor: OpenCS script compiler doesn't handle member variable access properly -Bug #2016: Dagoth Ur already dead in Facility Cavern -Bug #2017: Fighters Guild Quest: The Code Book - dialogue loop when UMP is loaded. -Bug #2019: Animation of 'Correct UV Mudcrabs' broken -Bug #2022: Alchemy window - Removing ingredient doesn't remove the number of ingredients -Bug #2025: Missing mouse-over text for non affordable items -Bug #2028: [MOD: Tamriel Rebuilt] Crashing when trying to enter interior cell "Ruinous Keep, Great Hall" -Bug #2029: Ienith Brothers Thiev's Guild quest journal entry not adding -Feature #471: Editor: Special case implementation for top-level window with single sub-window -Feature #472: Editor: Sub-Window re-use settings -Feature #704: Font colors import from fallback settings -Feature #879: Editor: Open sub-views in a new top-level window -Feature #932: Editor: magic effect table -Feature #937: Editor: Path Grid table -Feature #938: Editor: Sound Gen table -Feature #1117: Death and LevelUp music -Feature #1226: Editor: Request UniversalId editing from table columns -Feature #1545: Targeting console on player -Feature #1597: Editor: Render terrain -Feature #1695: Editor: add column for CellRef's global variable -Feature #1696: Editor: use ESM::Cell's RefNum counter -Feature #1697: Redden player's vision when hit -Feature #1856: Spellcasting for non-biped creatures -Feature #1879: Editor: Run OpenMW with the currently edited content list -Task #1851: Move AI temporary state out of AI packages -Task #1865: Replace char type in records - -0.32.0 - -Bug #1132: Unable to jump when facing a wall -Bug #1341: Summoned Creatures do not immediately disappear when killed. -Bug #1430: CharGen Revamped script does not compile -Bug #1451: NPCs shouldn't equip weapons prior to fighting -Bug #1461: Stopped start scripts do not restart on load -Bug #1473: Dead NPC standing and in 2 pieces -Bug #1482: Abilities are depleted when interrupted during casting -Bug #1503: Behaviour of NPCs facing the player -Bug #1506: Missing character, French edition: three-points -Bug #1528: Inventory very slow after 2 hours -Bug #1540: Extra arguments should be ignored for script functions -Bug #1541: Helseth's Champion: Tribunal -Bug #1570: Journal cannot be opened while in inventory screen -Bug #1573: PC joins factions at random -Bug #1576: NPCs aren't switching their weapons when out of ammo -Bug #1579: Guards detect creatures in far distance, instead on sight -Bug #1588: The Siege of the Skaal Village: bloodmoon -Bug #1593: The script compiler isn't recognising some names that contain a - -Bug #1606: Books: Question marks instead of quotation marks -Bug #1608: Dead bodies prevent door from opening/closing. -Bug #1609: Imperial guards in Sadrith Mora are not using their spears -Bug #1610: The bounty number is not displayed properly with high numbers -Bug #1620: Implement correct formula for auto-calculated NPC spells -Bug #1630: Boats standing vertically in Vivec -Bug #1635: Arrest dialogue is executed second time after I select "Go to jail" -Bug #1637: Weird NPC behaviour in Vivec, Hlaalu Ancestral Vaults? -Bug #1641: Persuasion dialog remains after loading, possibly resulting in crash -Bug #1644: "Goodbye" and similar options on dialogues prevents escape working properly. -Bug #1646: PC skill stats are not updated immediately when changing equipment -Bug #1652: Non-aggressive creature -Bug #1653: Quickloading while the container window is open crashes the game -Bug #1654: Priority of checks in organic containers -Bug #1656: Inventory items merge issue when repairing -Bug #1657: Attacked state of NPCs is not saved properly -Bug #1660: Rank dialogue condition ignored -Bug #1668: Game starts on day 2 instead of day 1 -Bug #1669: Critical Strikes while fighting a target who is currently fighting me -Bug #1672: OpenCS doesn't save the projects -Bug #1673: Fatigue decreasing by only one point when running -Bug #1675: Minimap and localmap graphic glitches -Bug #1676: Pressing the OK button on the travel menu cancels the travel and exits the menu -Bug #1677: Sleeping in a rented bed is considered a crime -Bug #1685: NPCs turn towards player even if invisible/sneaking -Bug #1686: UI bug: cursor is clicking "world/local" map button while inventory window is closed? -Bug #1690: Double clicking on a inventory window header doesn't close it. -Bug #1693: Spell Absorption does not absorb shrine blessings -Bug #1694: journal displays learned topics as quests -Bug #1700: Sideways scroll of text boxes -Bug #1701: Player enchanting requires player hold money, always 100% sucessful. -Bug #1704: self-made Fortify Intelligence/Drain willpower potions are broken -Bug #1707: Pausing the game through the esc menu will silence rain, pausing it by opening the inventory will not. -Bug #1709: Remesa Othril is hostile to Hlaalu members -Bug #1713: Crash on load after death -Bug #1719: Blind effect has slight border at the edge of the screen where it is ineffective. -Bug #1722: Crash after creating enchanted item, reloading saved game -Bug #1723: Content refs that are stacked share the same index after unstacking -Bug #1726: Can't finish Aengoth the Jeweler's quest : Retrieve the Scrap Metal -Bug #1727: Targets almost always resist soultrap scrolls -Bug #1728: Casting a soultrap spell on invalid target yields no message -Bug #1729: Chop attack doesn't work if walking diagonally -Bug #1732: Error handling for missing script function arguments produces weird message -Bug #1736: Alt-tabbing removes detail from overworld map. -Bug #1737: Going through doors with (high magnitude?) leviation will put the player high up, possibly even out of bounds. -Bug #1739: Setting a variable on an NPC from another NPC's dialogue result sets the wrong variable -Bug #1741: The wait dialogue doesn't black the screen out properly during waiting. -Bug #1742: ERROR: Object 'sDifficulty' not found (const) -Bug #1744: Night sky in Skies V.IV (& possibly v3) by SWG rendered incorrectly -Bug #1746: Bow/marksman weapon condition does not degrade with use -Bug #1749: Constant Battle Music -Bug #1752: Alt-Tabbing in the character menus makes the paper doll disappear temporarily -Bug #1753: Cost of training is not added to merchant's inventory -Bug #1755: Disposition changes do not persist if the conversation menu is closed by purchasing training. -Bug #1756: Caught Blight after being cured of Corprus -Bug #1758: Crash Upon Loading New Cell -Bug #1760: Player's Magicka is not recalculated upon drained or boosted intelligence -Bug #1761: Equiped torches lost on reload -Bug #1762: Your spell did not get a target. Soul trap. Gorenea Andrano -Bug #1763: Custom Spell Magicka Cost -Bug #1765: Azuras Star breaks on recharging item -Bug #1767: GetPCRank did not handle ignored explicit references -Bug #1772: Dark Brotherhood Assassins never use their Carved Ebony Dart, sticking to their melee weapon. -Bug #1774: String table overflow also occurs when loading TheGloryRoad.esm -Bug #1776: dagoth uthol runs in slow motion -Bug #1778: Incorrect values in spellmaking window -Bug #1779: Icon of Master Propylon Index is not visible -Bug #1783: Invisible NPC after looting corpse -Bug #1787: Health Calculation -Bug #1788: Skeletons, ghosts etc block doors when we try to open -Bug #1791: [MOD: LGNPC Foreign Quarter] NPC in completely the wrong place. -Bug #1792: Potions should show more effects -Bug #1793: Encumbrance while bartering -Bug #1794: Fortify attribute not affecting fatigue -Bug #1795: Too much magicka -Bug #1796: "Off by default" torch burning -Bug #1797: Fish too slow -Bug #1798: Rest until healed shouldn't show with full health and magicka -Bug #1802: Mark location moved -Bug #1804: stutter with recent builds -Bug #1810: attack gothens dremora doesnt agro the others. -Bug #1811: Regression: Crash Upon Loading New Cell -Bug #1812: Mod: "QuickChar" weird button placement -Bug #1815: Keys show value and weight, Vanilla Morrowind's keys dont. -Bug #1817: Persuasion results do not show using unpatched MW ESM -Bug #1818: Quest B3_ZainabBride moves to stage 47 upon loading save while Falura Llervu is following -Bug #1823: AI response to theft incorrect - only guards react, in vanilla everyone does. -Bug #1829: On-Target Spells Rendered Behind Water Surface Effects -Bug #1830: Galsa Gindu's house is on fire -Bug #1832: Fatal Error: OGRE Exception(2:InvalidParametersException) -Bug #1836: Attacked Guards open "fine/jail/resist"-dialogue after killing you -Bug #1840: Infinite recursion in ActionTeleport -Bug #1843: Escorted people change into player's cell after completion of escort stage -Bug #1845: Typing 'j' into 'Name' fields opens the journal -Bug #1846: Text pasted into the console still appears twice (Windows) -Bug #1847: "setfatigue 0" doesn't render NPC unconscious -Bug #1848: I can talk to unconscious actors -Bug #1866: Crash when player gets killed by a creature summoned by him -Bug #1868: Memory leaking when openmw window is minimized -Feature #47: Magic Effects -Feature #642: Control NPC mouth movement using current Say sound -Feature #939: Editor: Resources tables -Feature #961: AI Combat for magic (spells, potions and enchanted items) -Feature #1111: Collision script instructions (used e.g. by Lava) -Feature #1120: Command creature/humanoid magic effects -Feature #1121: Elemental shield magic effects -Feature #1122: Light magic effect -Feature #1139: AI: Friendly hits -Feature #1141: AI: combat party -Feature #1326: Editor: Add tooltips to all graphical buttons -Feature #1489: Magic effect Get/Mod/Set functions -Feature #1505: Difficulty slider -Feature #1538: Targeted scripts -Feature #1571: Allow creating custom markers on the local map -Feature #1615: Determine local variables from compiled scripts instead of the values in the script record -Feature #1616: Editor: Body part record verifier -Feature #1651: Editor: Improved keyboard navigation for scene toolbar -Feature #1666: Script blacklisting -Feature #1711: Including the Git revision number from the command line "--version" switch. -Feature #1721: NPC eye blinking -Feature #1740: Scene toolbar buttons for selecting which type of elements are rendered -Feature #1790: Mouse wheel scrolling for the journal -Feature #1850: NiBSPArrayController -Task #768: On windows, settings folder should be "OpenMW", not "openmw" -Task #908: Share keyframe data -Task #1716: Remove defunct option for building without FFmpeg - -0.31.0 - -Bug #245: Cloud direction and weather systems differ from Morrowind -Bug #275: Local Map does not always show objects that span multiple cells -Bug #538: Update CenterOnCell (COC) function behavior -Bug #618: Local and World Map Textures are sometimes Black -Bug #640: Water behaviour at night -Bug #668: OpenMW doesn't support non-latin paths on Windows -Bug #746: OpenMW doesn't check if the background music was already played -Bug #747: Door is stuck if cell is left before animation finishes -Bug #772: Disabled statics are visible on map -Bug #829: OpenMW uses up all available vram, when playing for extended time -Bug #869: Dead bodies don't collide with anything -Bug #894: Various character creation issues -Bug #897/#1369: opencs Segmentation Fault after "new" or "load" -Bug #899: Various jumping issues -Bug #952: Reflection effects are one frame delayed -Bug #993: Able to interact with world during Wait/Rest dialog -Bug #995: Dropped items can be placed inside the wall -Bug #1008: Corpses always face up upon reentering the cell -Bug #1035: Random colour patterns appearing in automap -Bug #1037: Footstep volume issues -Bug #1047: Creation of wrong links in dialogue window -Bug #1129: Summoned creature time life duration seems infinite -Bug #1134: Crimes can be committed against hostile NPCs -Bug #1136: Creature run speed formula is incorrect -Bug #1150: Weakness to Fire doesn't apply to Fire Damage in the same spell -Bug #1155: NPCs killing each other -Bug #1166: Bittercup script still does not work -Bug #1178: .bsa file names are case sensitive. -Bug #1179: Crash after trying to load game after being killed -Bug #1180: Changing footstep sound location -Bug #1196: Jumping not disabled when showing messageboxes -Bug #1202: "strange" keys are not shown in binding menu, and are not saved either, but works -Bug #1216: Broken dialog topics in russian Morrowind -Bug #1217: Container content changes based on the current position of the mouse -Bug #1234: Loading/saving issues with dynamic records -Bug #1277: Text pasted into the console appears twice -Bug #1284: Crash on New Game -Bug #1303: It's possible to skip the chargen -Bug #1304: Slaughterfish should not detect the player unless the player is in the water -Bug #1311: Editor: deleting Record Filter line does not reset the filter -Bug #1324: ERROR: ESM Error: String table overflow when loading Animated Morrowind.esp -Bug #1328: Editor: Bogus Filter created when dragging multiple records to filter bar of non-applicable table -Bug #1331: Walking/running sound persist after killing NPC`s that are walking/running. -Bug #1334: Previously equipped items not shown as unequipped after attempting to sell them. -Bug #1335: Actors ignore vertical axis when deciding to attack -Bug #1338: Unknown toggle option for shadows -Bug #1339: "Ashlands Region" is visible when beginning new game during "Loading Area" process -Bug #1340: Guards prompt Player with punishment options after resisting arrest with another guard. -Bug #1348: Regression: Bug #1098 has returned with a vengeance -Bug #1349: [TR] TR_Data mesh tr_ex_imp_gatejamb01 cannot be activated -Bug #1352: Disabling an ESX file does not disable dependent ESX files -Bug #1355: CppCat Checks OpenMW -Bug #1356: Incorrect voice type filtering for sleep interrupts -Bug #1357: Restarting the game clears saves -Bug #1360: Seyda Neen silk rider dialog problem -Bug #1361: Some lights don't work -Bug #1364: It is difficult to bind "Mouse 1" to an action in the options menu -Bug #1370: Animation compilation mod does not work properly -Bug #1371: SL_Pick01.nif from third party fails to load in openmw, but works in Vanilla -Bug #1373: When stealing in front of Sellus Gravius cannot exit the dialog -Bug #1378: Installs to /usr/local are not working -Bug #1380: Loading a save file fail if one of the content files is disabled -Bug #1382: "getHExact() size mismatch" crash on loading official plugin "Siege at Firemoth.esp" -Bug #1386: Arkngthand door will not open -Bug #1388: Segfault when modifying View Distance in Menu options -Bug #1389: Crash when loading a save after dying -Bug #1390: Apostrophe characters not displayed [French version] -Bug #1391: Custom made icon background texture for magical weapons and stuff isn't scaled properly on GUI. -Bug #1393: Coin icon during the level up dialogue are off of the background -Bug #1394: Alt+F4 doesn't work on Win version -Bug #1395: Changing rings switches only the last one put on -Bug #1396: Pauldron parts aren't showing when the robe is equipped -Bug #1402: Dialogue of some shrines have wrong button orientation -Bug #1403: Items are floating in the air when they're dropped onto dead bodies. -Bug #1404: Forearms are not rendered on Argonian females -Bug #1407: Alchemy allows making potions from two of the same item -Bug #1408: "Max sale" button gives you all the items AND all the trader's gold -Bug #1409: Rest "Until Healed" broken for characters with stunted magicka. -Bug #1412: Empty travel window opens while playing through start game -Bug #1413: Save game ignores missing writing permission -Bug #1414: The Underground 2 ESM Error -Bug #1416: Not all splash screens in the Splash directory are used -Bug #1417: Loading saved game does not terminate -Bug #1419: Skyrim: Home of the Nords error -Bug #1422: ClearInfoActor -Bug #1423: ForceGreeting closes existing dialogue windows -Bug #1425: Cannot load save game -Bug #1426: Read skill books aren't stored in savegame -Bug #1427: Useless items can be set under hotkeys -Bug #1429: Text variables in journal -Bug #1432: When attacking friendly NPC, the crime is reported and bounty is raised after each swing -Bug #1435: Stealing priceless items is without punishment -Bug #1437: Door marker at Jobasha's Rare Books is spawning PC in the air -Bug #1440: Topic selection menu should be wider -Bug #1441: Dropping items on the rug makes them inaccessible -Bug #1442: When dropping and taking some looted items, bystanders consider that as a crime -Bug #1444: Arrows and bolts are not dropped where the cursor points -Bug #1445: Security trainers offering acrobatics instead -Bug #1447: Character dash not displayed, French edition -Bug #1448: When the player is killed by the guard while having a bounty on his head, the guard dialogue opens over and over instead of loading dialogue -Bug #1454: Script error in SkipTutorial -Bug #1456: Bad lighting when using certain Morrowind.ini generated by MGE -Bug #1457: Heart of Lorkan comes after you when attacking it -Bug #1458: Modified Keybindings are not remembered -Bug #1459: Dura Gra-Bol doesn't respond to PC attack -Bug #1462: Interior cells not loaded with Morrowind Patch active -Bug #1469: Item tooltip should show the base value, not real value -Bug #1477: Death count is not stored in savegame -Bug #1478: AiActivate does not trigger activate scripts -Bug #1481: Weapon not rendered when partially submerged in water -Bug #1483: Enemies are attacking even while dying -Bug #1486: ESM Error: Don't know what to do with INFO -Bug #1490: Arrows shot at PC can end up in inventory -Bug #1492: Monsters respawn on top of one another -Bug #1493: Dialogue box opens with follower NPC even if NPC is dead -Bug #1494: Paralysed cliffracers remain airbourne -Bug #1495: Dialogue box opens with follower NPC even the game is paused -Bug #1496: GUI messages are not cleared when loading another saved game -Bug #1499: Underwater sound sometimes plays when transitioning from interior. -Bug #1500: Targetted spells and water. -Bug #1502: Console error message on info refusal -Bug #1507: Bloodmoon MQ The Ritual of Beasts: Can't remove the arrow -Bug #1508: Bloodmoon: Fort Frostmoth, cant talk with Carnius Magius -Bug #1516: PositionCell doesn't move actors to current cell -Bug #1518: ForceGreeting broken for explicit references -Bug #1522: Crash after attempting to play non-music file -Bug #1523: World map empty after loading interior save -Bug #1524: Arrows in waiting/resting dialog act like minimum and maximum buttons -Bug #1525: Werewolf: Killed NPC's don't fill werewolfs hunger for blood -Bug #1527: Werewolf: Detect life detects wrong type of actor -Bug #1529: OpenMW crash during "the shrine of the dead" mission (tribunal) -Bug #1530: Selected text in the console has the same color as the background -Bug #1539: Barilzar's Mazed Band: Tribunal -Bug #1542: Looping taunts from NPC`s after death: Tribunal -Bug #1543: OpenCS crash when using drag&drop in script editor -Bug #1547: Bamz-Amschend: Centurion Archers combat problem -Bug #1548: The Missing Hand: Tribunal -Bug #1549: The Mad God: Tribunal, Dome of Serlyn -Bug #1557: A bounty is calculated from actual item cost -Bug #1562: Invisible terrain on top of Red Mountain -Bug #1564: Cave of the hidden music: Bloodmoon -Bug #1567: Editor: Deleting of referenceables does not work -Bug #1568: Picking up a stack of items and holding the enter key and moving your mouse around paints a bunch of garbage on screen. -Bug #1574: Solstheim: Drauger cant inflict damage on player -Bug #1578: Solstheim: Bonewolf running animation not working -Bug #1585: Particle effects on PC are stopped when paralyzed -Bug #1589: Tribunal: Crimson Plague quest does not update when Gedna Relvel is killed -Bug #1590: Failed to save game: compile error -Bug #1598: Segfault when making Drain/Fortify Skill spells -Bug #1599: Unable to switch to fullscreen -Bug #1613: Morrowind Rebirth duplicate objects / vanilla objects not removed -Bug #1618: Death notice fails to show up -Bug #1628: Alt+Tab Segfault -Feature #32: Periodic Cleanup/Refill -Feature #41: Precipitation and weather particles -Feature #568: Editor: Configuration setup -Feature #649: Editor: Threaded loading -Feature #930: Editor: Cell record saving -Feature #934: Editor: Body part table -Feature #935: Editor: Enchantment effect table -Feature #1162: Dialogue merging -Feature #1174: Saved Game: add missing creature state -Feature #1177: Saved Game: fog of war state -Feature #1312: Editor: Combat/Magic/Stealth values for creatures are not displayed -Feature #1314: Make NPCs and creatures fight each other -Feature #1315: Crime: Murder -Feature #1321: Sneak skill enhancements -Feature #1323: Handle restocking items -Feature #1332: Saved Game: levelled creatures -Feature #1347: modFactionReaction script instruction -Feature #1362: Animated main menu support -Feature #1433: Store walk/run toggle -Feature #1449: Use names instead of numbers for saved game files and folders -Feature #1453: Adding Delete button to the load menu -Feature #1460: Enable Journal screen while in dialogue -Feature #1480: Play Battle music when in combat -Feature #1501: Followers unable to fast travel with you -Feature #1520: Disposition and distance-based aggression/ShouldAttack -Feature #1595: Editor: Object rendering in cells -Task #940: Move license to locations where applicable -Task #1333: Remove cmake git tag reading -Task #1566: Editor: Object rendering refactoring - -0.30.0 - -Bug #416: Extreme shaking can occur during cell transitions while moving -Bug #1003: Province Cyrodiil: Ogre Exception in Stirk -Bug #1071: Crash when given a non-existent content file -Bug #1080: OpenMW allows resting/using a bed while in combat -Bug #1097: Wrong punishment for stealing in Census and Excise Office at the start of a new game -Bug #1098: Unlocked evidence chests should get locked after new evidence is put into them -Bug #1099: NPCs that you attacked still fight you after you went to jail/paid your fine -Bug #1100: Taking items from a corpse is considered stealing -Bug #1126: Some creatures can't get close enough to attack -Bug #1144: Killed creatures seem to die again each time player transitions indoors/outdoors -Bug #1181: loading a saved game does not reset the player control status -Bug #1185: Collision issues in Addamasartus -Bug #1187: Athyn Sarethi mission, rescuing varvur sarethi from the doesnt end the mission -Bug #1189: Crash when entering interior cell "Gnisis, Arvs-Drelen" -Bug #1191: Picking up papers without inventory in new game -Bug #1195: NPCs do not equip torches in certain interiors -Bug #1197: mouse wheel makes things scroll too fast -Bug #1200: door blocked by monsters -Bug #1201: item's magical charges are only refreshed when they are used -Bug #1203: Scribs do not defend themselves -Bug #1204: creatures life is not empty when they are dead -Bug #1205: armor experience does not progress when hits are taken -Bug #1206: blood particules always red. Undeads and mechanicals should have a different one. -Bug #1209: Tarhiel never falls -Bug #1210: journal adding script is ran again after having saved/loaded -Bug #1224: Names of custom classes are not properly handled in save games -Bug #1227: Editor: Fixed case handling for broken localised versions of Morrowind.esm -Bug #1235: Indoors walk stutter -Bug #1236: Aborting intro movie brings up the menu -Bug #1239: NPCs get stuck when walking past each other -Bug #1240: BTB - Settings 14.1 and Health Bar. -Bug #1241: BTB - Character and Khajiit Prejudice -Bug #1248: GUI Weapon icon is changed to hand-to-hand after save load -Bug #1254: Guild ranks do not show in dialogue -Bug #1255: When opening a container and selecting "Take All", the screen flashes blue -Bug #1260: Level Up menu doesn't show image when using a custom class -Bug #1265: Quit Menu Has Misaligned Buttons -Bug #1270: Active weapon icon is not updated when weapon is repaired -Bug #1271: NPC Stuck in hovering "Jumping" animation -Bug #1272: Crash when attempting to load Big City esm file. -Bug #1276: Editor: Dropping a region into the filter of a cell subview fails -Bug #1286: Dialogue topic list clips with window frame -Bug #1291: Saved game: store faction membership -Bug #1293: Pluginless Khajiit Head Pack by ashiraniir makes OpenMW close. -Bug #1294: Pasting in console adds text to end, not at cursor -Bug #1295: Conversation loop when asking about "specific place" in Vivec -Bug #1296: Caius doesn't leave at start of quest "Mehra Milo and the Lost Prophecies" -Bug #1297: Saved game: map markers -Bug #1302: ring_keley script causes vector::_M_range_check exception -Bug #1309: Bug on "You violated the law" dialog -Bug #1319: Creatures sometimes rendered incorrectly -Feature #50: Ranged Combat -Feature #58: Sneaking Skill -Feature #73: Crime and Punishment -Feature #135: Editor: OGRE integration -Feature #541: Editor: Dialogue Sub-Views -Feature #853: Editor: Rework User Settings -Feature #944: Editor: lighting modes -Feature #945: Editor: Camera navigation mode -Feature #953: Trader gold -Feature #1140: AI: summoned creatures -Feature #1142: AI follow: Run stance -Feature #1154: Not all NPCs get aggressive when one is attacked -Feature #1169: Terrain threading -Feature #1172: Loading screen and progress bars during saved/loading game -Feature #1173: Saved Game: include weather state -Feature #1207: Class creation form does not remember -Feature #1220: Editor: Preview Subview -Feature #1223: Saved Game: Local Variables -Feature #1229: Quicksave, quickload, autosave -Feature #1230: Deleting saves -Feature #1233: Bribe gold is placed into NPCs inventory -Feature #1252: Saved Game: quick key bindings -Feature #1273: Editor: Region Map context menu -Feature #1274: Editor: Region Map drag & drop -Feature #1275: Editor: Scene subview drop -Feature #1282: Non-faction member crime recognition. -Feature #1289: NPCs return to default position -Task #941: Remove unused cmake files - -0.29.0 - -Bug #556: Video soundtrack not played when music volume is set to zero -Bug #829: OpenMW uses up all available vram, when playing for extended time -Bug #848: Wrong amount of footsteps playing in 1st person -Bug #888: Ascended Sleepers have movement issues -Bug #892: Explicit references are allowed on all script functions -Bug #999: Graphic Herbalism (mod): sometimes doesn't activate properly -Bug #1009: Lake Fjalding AI related slowdown. -Bug #1041: Music playback issues on OS X >= 10.9 -Bug #1043: No message box when advancing skill "Speechcraft" while in dialog window -Bug #1060: Some message boxes are cut off at the bottom -Bug #1062: Bittercup script does not work ('end' variable) -Bug #1074: Inventory paperdoll obscures armour rating -Bug #1077: Message after killing an essential NPC disappears too fast -Bug #1078: "Clutterbane" shows empty charge bar -Bug #1083: UndoWerewolf fails -Bug #1088: Better Clothes Bloodmoon Plus 1.5 by Spirited Treasure pants are not rendered -Bug #1090: Start scripts fail when going to a non-predefined cell -Bug #1091: Crash: Assertion `!q.isNaN() && "Invalid orientation supplied as parameter"' failed. -Bug #1093: Weapons of aggressive NPCs are invisible after you exit and re-enter interior -Bug #1105: Magicka is depleted when using uncastable spells -Bug #1106: Creatures should be able to run -Bug #1107: TR cliffs have way too huge collision boxes in OpenMW -Bug #1109: Cleaning True Light and Darkness with Tes3cmd makes Addamasartus , Zenarbael and Yasamsi flooded. -Bug #1114: Bad output for desktop-file-validate on openmw.desktop (and opencs.desktop) -Bug #1115: Memory leak when spying on Fargoth -Bug #1137: Script execution fails (drenSlaveOwners script) -Bug #1143: Mehra Milo quest (vivec informants) is broken -Bug #1145: Issues with moving gold between inventory and containers -Bug #1146: Issues with picking up stacks of gold -Bug #1147: Dwemer Crossbows are held incorrectly -Bug #1158: Armor rating should always stay below inventory mannequin -Bug #1159: Quick keys can be set during character generation -Bug #1160: Crash on equip lockpick when -Bug #1167: Editor: Referenceables are not correctly loaded when dealing with more than one content file -Bug #1184: Game Save: overwriting an existing save does not actually overwrites the file -Feature #30: Loading/Saving (still missing a few parts) -Feature #101: AI Package: Activate -Feature #103: AI Package: Follow, FollowCell -Feature #138: Editor: Drag & Drop -Feature #428: Player death -Feature #505: Editor: Record Cloning -Feature #701: Levelled creatures -Feature #708: Improved Local Variable handling -Feature #709: Editor: Script verifier -Feature #764: Missing journal backend features -Feature #777: Creature weapons/shields -Feature #789: Editor: Referenceable record verifier -Feature #924: Load/Save GUI (still missing loading screen and progress bars) -Feature #946: Knockdown -Feature #947: Decrease fatigue when running, swimming and attacking -Feature #956: Melee Combat: Blocking -Feature #957: Area magic -Feature #960: Combat/AI combat for creatures -Feature #962: Combat-Related AI instructions -Feature #1075: Damage/Restore skill/attribute magic effects -Feature #1076: Soultrap magic effect -Feature #1081: Disease contraction -Feature #1086: Blood particles -Feature #1092: Interrupt resting -Feature #1101: Inventory equip scripts -Feature #1116: Version/Build number in Launcher window -Feature #1119: Resistance/weakness to normal weapons magic effect -Feature #1123: Slow Fall magic effect -Feature #1130: Auto-calculate spells -Feature #1164: Editor: Case-insensitive sorting in tables - -0.28.0 - -Bug #399: Inventory changes are not visible immediately -Bug #417: Apply weather instantly when teleporting -Bug #566: Global Map position marker not updated for interior cells -Bug #712: Looting corpse delay -Bug #716: Problem with the "Vurt's Ascadian Isles Mod" mod -Bug #805: Two TR meshes appear black (v0.24RC) -Bug #841: Third-person activation distance taken from camera rather than head -Bug #845: NPCs hold torches during the day -Bug #855: Vvardenfell Visages Volume I some hairs don´t appear since 0,24 -Bug #856: Maormer race by Mac Kom - The heads are way up -Bug #864: Walk locks during loading in 3rd person -Bug #871: active weapon/magic item icon is not immediately made blank if item is removed during dialog -Bug #882: Hircine's Ring doesn't always work -Bug #909: [Tamriel Rebuilt] crashes in Akamora -Bug #922: Launcher writing merged openmw.cfg files -Bug #943: Random magnitude should be calculated per effect -Bug #948: Negative fatigue level should be allowed -Bug #949: Particles in world space -Bug #950: Hard crash on x64 Linux running --new-game (on startup) -Bug #951: setMagicka and setFatigue have no effect -Bug #954: Problem with equipping inventory items when using a keyboard shortcut -Bug #955: Issues with equipping torches -Bug #966: Shield is visible when casting spell -Bug #967: Game crashes when equipping silver candlestick -Bug #970: Segmentation fault when starting at Bal Isra -Bug #977: Pressing down key in console doesn't go forward in history -Bug #979: Tooltip disappears when changing inventory -Bug #980: Barter: item category is remembered, but not shown -Bug #981: Mod: replacing model has wrong position/orientation -Bug #982: Launcher: Addon unchecking is not saved -Bug #983: Fix controllers to affect objects attached to the base node -Bug #985: Player can talk to NPCs who are in combat -Bug #989: OpenMW crashes when trying to include mod with capital .ESP -Bug #991: Merchants equip items with harmful constant effect enchantments -Bug #994: Don't cap skills/attributes when set via console -Bug #998: Setting the max health should also set the current health -Bug #1005: Torches are visible when casting spells and during hand to hand combat. -Bug #1006: Many NPCs have 0 skill -Bug #1007: Console fills up with text -Bug #1013: Player randomly loses health or dies -Bug #1014: Persuasion window is not centered in maximized window -Bug #1015: Player status window scroll state resets on status change -Bug #1016: Notification window not big enough for all skill level ups -Bug #1020: Saved window positions are not rescaled appropriately on resolution change -Bug #1022: Messages stuck permanently on screen when they pile up -Bug #1023: Journals doesn't open -Bug #1026: Game loses track of torch usage. -Bug #1028: Crash on pickup of jug in Unexplored Shipwreck, Upper level -Bug #1029: Quick keys menu: Select compatible replacement when tool used up -Bug #1042: TES3 header data wrong encoding -Bug #1045: OS X: deployed OpenCS won't launch -Bug #1046: All damaged weaponry is worth 1 gold -Bug #1048: Links in "locked" dialogue are still clickable -Bug #1052: Using color codes when naming your character actually changes the name's color -Bug #1054: Spell effects not visible in front of water -Bug #1055: Power-Spell animation starts even though you already casted it that day -Bug #1059: Cure disease potion removes all effects from player, even your race bonus and race ability -Bug #1063: Crash upon checking out game start ship area in Seyda Neen -Bug #1064: openmw binaries link to unnecessary libraries -Bug #1065: Landing from a high place in water still causes fall damage -Bug #1072: Drawing weapon increases torch brightness -Bug #1073: Merchants sell stacks of gold -Feature #43: Visuals for Magic Effects -Feature #51: Ranged Magic -Feature #52: Touch Range Magic -Feature #53: Self Range Magic -Feature #54: Spell Casting -Feature #70: Vampirism -Feature #100: Combat AI -Feature #171: Implement NIF record NiFlipController -Feature #410: Window to restore enchanted item charge -Feature #647: Enchanted item glow -Feature #723: Invisibility/Chameleon magic effects -Feature #737: Resist Magicka magic effect -Feature #758: GetLOS -Feature #926: Editor: Info-Record tables -Feature #958: Material controllers -Feature #959: Terrain bump, specular, & parallax mapping -Feature #990: Request: unlock mouse when in any menu -Feature #1018: Do not allow view mode switching while performing an action -Feature #1027: Vertex morph animation (NiGeomMorpherController) -Feature #1031: Handle NiBillboardNode -Feature #1051: Implement NIF texture slot DarkTexture -Task #873: Unify OGRE initialisation - -0.27.0 - -Bug #597: Assertion `dialogue->mId == id' failed in esmstore.cpp -Bug #794: incorrect display of decimal numbers -Bug #840: First-person sneaking camera height -Bug #887: Ambient sounds playing while paused -Bug #902: Problems with Polish character encoding -Bug #907: Entering third person using the mousewheel is possible even if it's impossible using the key -Bug #910: Some CDs not working correctly with Unshield installer -Bug #917: Quick character creation plugin does not work -Bug #918: Fatigue does not refill -Bug #919: The PC falls dead in Beshara - OpenMW nightly Win64 (708CDE2) -Feature #57: Acrobatics Skill -Feature #462: Editor: Start Dialogue -Feature #546: Modify ESX selector to handle new content file scheme -Feature #588: Editor: Adjust name/path of edited content files -Feature #644: Editor: Save -Feature #710: Editor: Configure script compiler context -Feature #790: God Mode -Feature #881: Editor: Allow only one instance of OpenCS -Feature #889: Editor: Record filtering -Feature #895: Extinguish torches -Feature #898: Breath meter enhancements -Feature #901: Editor: Default record filter -Feature #913: Merge --master and --plugin switches - -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 -Bug #604: Terrible performance drop in the Census and Excise Office. -Bug #676: Start Scripts fail to load -Bug #677: OpenMW does not accept script names with - -Bug #766: Extra space in front of topic links -Bug #793: AIWander Isn't Being Passed The Repeat Parameter -Bug #795: Sound playing with drawn weapon and crossing cell-border -Bug #800: can't select weapon for enchantment -Bug #801: Player can move while over-encumbered -Bug #802: Dead Keys not working -Bug #808: mouse capture -Bug #809: ini Importer does not work without an existing cfg file -Bug #812: Launcher will run OpenMW with no ESM or ESP selected -Bug #813: OpenMW defaults to Morrowind.ESM with no ESM or ESP selected -Bug #817: Dead NPCs and Creatures still have collision boxes -Bug #820: Incorrect sorting of answers (Dialogue) -Bug #826: mwinimport dumps core when given an unknown parameter -Bug #833: getting stuck in door -Bug #835: Journals/books not showing up properly. -Feature #38: SoundGen -Feature #105: AI Package: Wander -Feature #230: 64-bit compatibility for OS X -Feature #263: Hardware mouse cursors -Feature #449: Allow mouse outside of window while paused -Feature #736: First person animations -Feature #750: Using mouse wheel in third person mode -Feature #822: Autorepeat for slider buttons - -0.24.0 - -Bug #284: Book's text misalignment -Bug #445: Camera able to get slightly below floor / terrain -Bug #582: Seam issue in Red Mountain -Bug #632: Journal Next Button shows white square -Bug #653: IndexedStore ignores index -Bug #694: Parser does not recognize float values starting with . -Bug #699: Resource handling broken with Ogre 1.9 trunk -Bug #718: components/esm/loadcell is using the mwworld subsystem -Bug #729: Levelled item list tries to add nonexistent item -Bug #730: Arrow buttons in the settings menu do not work. -Bug #732: Erroneous behavior when binding keys -Bug #733: Unclickable dialogue topic -Bug #734: Book empty line problem -Bug #738: OnDeath only works with implicit references -Bug #740: Script compiler fails on scripts with special names -Bug #742: Wait while no clipping -Bug #743: Problem with changeweather console command -Bug #744: No wait dialogue after starting a new game -Bug #748: Player is not able to unselect objects with the console -Bug #751: AddItem should only spawn a message box when called from dialogue -Bug #752: The enter button has several functions in trade and looting that is not impelemted. -Bug #753: Fargoth's Ring Quest Strange Behavior -Bug #755: Launcher writes duplicate lines into settings.cfg -Bug #759: Second quest in mages guild does not work -Bug #763: Enchantment cast cost is wrong -Bug #770: The "Take" and "Close" buttons in the scroll GUI are stretched incorrectly -Bug #773: AIWander Isn't Being Passed The Correct idle Values -Bug #778: The journal can be opened at the start of a new game -Bug #779: Divayth Fyr starts as dead -Bug #787: "Batch count" on detailed FPS counter gets cut-off -Bug #788: chargen scroll layout does not match vanilla -Feature #60: Atlethics Skill -Feature #65: Security Skill -Feature #74: Interaction with non-load-doors -Feature #98: Render Weapon and Shield -Feature #102: AI Package: Escort, EscortCell -Feature #182: Advanced Journal GUI -Feature #288: Trading enhancements -Feature #405: Integrate "new game" into the menu -Feature #537: Highlight dialogue topic links -Feature #658: Rotate, RotateWorld script instructions and local rotations -Feature #690: Animation Layering -Feature #722: Night Eye/Blind magic effects -Feature #735: Move, MoveWorld script instructions. -Feature #760: Non-removable corpses - -0.23.0 - -Bug #522: Player collides with placeable items -Bug #553: Open/Close sounds played when accessing main menu w/ Journal Open -Bug #561: Tooltip word wrapping delay -Bug #578: Bribing works incorrectly -Bug #601: PositionCell fails on negative coordinates -Bug #606: Some NPCs hairs not rendered with Better Heads addon -Bug #609: Bad rendering of bone boots -Bug #613: Messagebox causing assert to fail -Bug #631: Segfault on shutdown -Bug #634: Exception when talking to Calvus Horatius in Mournhold, royal palace courtyard -Bug #635: Scale NPCs depending on race -Bug #643: Dialogue Race select function is inverted -Bug #646: Twohanded weapons don't work properly -Bug #654: Crash when dropping objects without a collision shape -Bug #655/656: Objects that were disabled or deleted (but not both) were added to the scene when re-entering a cell -Bug #660: "g" in "change" cut off in Race Menu -Bug #661: Arrille sells me the key to his upstairs room -Bug #662: Day counter starts at 2 instead of 1 -Bug #663: Cannot select "come unprepared" topic in dialog with Dagoth Ur -Bug #665: Pickpocket -> "Grab all" grabs all NPC inventory, even not listed in container window. -Bug #666: Looking up/down problem -Bug #667: Active effects border visible during loading -Bug #669: incorrect player position at new game start -Bug #670: race selection menu: sex, face and hair left button not totally clickable -Bug #671: new game: player is naked -Bug #674: buying or selling items doesn't change amount of gold -Bug #675: fatigue is not set to its maximum when starting a new game -Bug #678: Wrong rotation order causes RefData's rotation to be stored incorrectly -Bug #680: different gold coins in Tel Mara -Bug #682: Race menu ignores playable flag for some hairs and faces -Bug #685: Script compiler does not accept ":" after a function name -Bug #688: dispose corpse makes cross-hair to disappear -Bug #691: Auto equipping ignores equipment conditions -Bug #692: OpenMW doesnt load "loose file" texture packs that places resources directly in data folder -Bug #696: Draugr incorrect head offset -Bug #697: Sail transparency issue -Bug #700: "On the rocks" mod does not load its UV coordinates correctly. -Bug #702: Some race mods don't work -Bug #711: Crash during character creation -Bug #715: Growing Tauryon -Bug #725: Auto calculate stats -Bug #728: Failure to open container and talk dialogue -Bug #731: Crash with Mush-Mere's "background" topic -Feature #55/657: Item Repairing -Feature #62/87: Enchanting -Feature #99: Pathfinding -Feature #104: AI Package: Travel -Feature #129: Levelled items -Feature #204: Texture animations -Feature #239: Fallback-Settings -Feature #535: Console object selection improvements -Feature #629: Add levelup description in levelup layout dialog -Feature #630: Optional format subrecord in (tes3) header -Feature #641: Armor rating -Feature #645: OnDeath script function -Feature #683: Companion item UI -Feature #698: Basic Particles -Task #648: Split up components/esm/loadlocks -Task #695: mwgui cleanup - -0.22.0 - -Bug #311: Potential infinite recursion in script compiler -Bug #355: Keyboard repeat rate (in Xorg) are left disabled after game exit. -Bug #382: Weird effect in 3rd person on water -Bug #387: Always use detailed shape for physics raycasts -Bug #420: Potion/ingredient effects do not stack -Bug #429: Parts of dwemer door not picked up correctly for activation/tooltips -Bug #434/Bug #605: Object movement between cells not properly implemented -Bug #502: Duplicate player collision model at origin -Bug #509: Dialogue topic list shifts inappropriately -Bug #513: Sliding stairs -Bug #515: Launcher does not support non-latin strings -Bug #525: Race selection preview camera wrong position -Bug #526: Attributes / skills should not go below zero -Bug #529: Class and Birthsign menus options should be preselected -Bug #530: Lock window button graphic missing -Bug #532: Missing map menu graphics -Bug #545: ESX selector does not list ESM files properly -Bug #547: Global variables of type short are read incorrectly -Bug #550: Invisible meshes collision and tooltip -Bug #551: Performance drop when loading multiple ESM files -Bug #552: Don't list CG in options if it is not available -Bug #555: Character creation windows "OK" button broken -Bug #558: Segmentation fault when Alt-tabbing with console opened -Bug #559: Dialog window should not be available before character creation is finished -Bug #560: Tooltip borders should be stretched -Bug #562: Sound should not be played when an object cannot be picked up -Bug #565: Water animation speed + timescale -Bug #572: Better Bodies' textures don't work -Bug #573: OpenMW doesn't load if TR_Mainland.esm is enabled (Tamriel Rebuilt mod) -Bug #574: Moving left/right should not cancel auto-run -Bug #575: Crash entering the Chamber of Song -Bug #576: Missing includes -Bug #577: Left Gloves Addon causes ESMReader exception -Bug #579: Unable to open container "Kvama Egg Sack" -Bug #581: Mimicking vanilla Morrowind water -Bug #583: Gender not recognized -Bug #586: Wrong char gen behaviour -Bug #587: "End" script statements with spaces don't work -Bug #589: Closing message boxes by pressing the activation key -Bug #590: Ugly Dagoth Ur rendering -Bug #591: Race selection issues -Bug #593: Persuasion response should be random -Bug #595: Footless guard -Bug #599: Waterfalls are invisible from a certain distance -Bug #600: Waterfalls rendered incorrectly, cut off by water -Bug #607: New beast bodies mod crashes -Bug #608: Crash in cell "Mournhold, Royal Palace" -Bug #611: OpenMW doesn't find some of textures used in Tamriel Rebuilt -Bug #613: Messagebox causing assert to fail -Bug #615: Meshes invisible from above water -Bug #617: Potion effects should be hidden until discovered -Bug #619: certain moss hanging from tree has rendering bug -Bug #621: Batching bloodmoon's trees -Bug #623: NiMaterialProperty alpha unhandled -Bug #628: Launcher in latest master crashes the game -Bug #633: Crash on startup: Better Heads -Bug #636: Incorrect Char Gen Menu Behavior -Feature #29: Allow ESPs and multiple ESMs -Feature #94: Finish class selection-dialogue -Feature #149: Texture Alphas -Feature #237: Run Morrowind-ini importer from launcher -Feature #286: Update Active Spell Icons -Feature #334: Swimming animation -Feature #335: Walking animation -Feature #360: Proper collision shapes for NPCs and creatures -Feature #367: Lights that behave more like original morrowind implementation -Feature #477: Special local scripting variables -Feature #528: Message boxes should close when enter is pressed under certain conditions. -Feature #543: Add bsa files to the settings imported by the ini importer -Feature #594: coordinate space and utility functions -Feature #625: Zoom in vanity mode -Task #464: Refactor launcher ESX selector into a re-usable component -Task #624: Unified implementation of type-variable sub-records - -0.21.0 - -Bug #253: Dialogs don't work for Russian version of Morrowind -Bug #267: Activating creatures without dialogue can still activate the dialogue GUI -Bug #354: True flickering lights -Bug #386: The main menu's first entry is wrong (in french) -Bug #479: Adding the spell "Ash Woe Blight" to the player causes strange attribute oscillations -Bug #495: Activation Range -Bug #497: Failed Disposition check doesn't stop a dialogue entry from being returned -Bug #498: Failing a disposition check shouldn't eliminate topics from the the list of those available -Bug #500: Disposition for most NPCs is 0/100 -Bug #501: Getdisposition command wrongly returns base disposition -Bug #506: Journal UI doesn't update anymore -Bug #507: EnableRestMenu is not a valid command - change it to EnableRest -Bug #508: Crash in Ald Daedroth Shrine -Bug #517: Wrong price calculation when untrading an item -Bug #521: MWGui::InventoryWindow creates a duplicate player actor at the origin -Bug #524: Beast races are able to wear shoes -Bug #527: Background music fails to play -Bug #533: The arch at Gnisis entrance is not displayed -Bug #534: Terrain gets its correct shape only some time after the cell is loaded -Bug #536: The same entry can be added multiple times to the journal -Bug #539: Race selection is broken -Bug #544: Terrain normal map corrupt when the map is rendered -Feature #39: Video Playback -Feature #151: ^-escape sequences in text output -Feature #392: Add AI related script functions -Feature #456: Determine required ini fallback values and adjust the ini importer accordingly -Feature #460: Experimental DirArchives improvements -Feature #540: Execute scripts of objects in containers/inventories in active cells -Task #401: Review GMST fixing -Task #453: Unify case smashing/folding -Task #512: Rewrite utf8 component - -0.20.0 - -Bug #366: Changing the player's race during character creation does not change the look of the player character -Bug #430: Teleporting and using loading doors linking within the same cell reloads the cell -Bug #437: Stop animations when paused -Bug #438: Time displays as "0 a.m." when it should be "12 a.m." -Bug #439: Text in "name" field of potion/spell creation window is persistent -Bug #440: Starting date at a new game is off by one day -Bug #442: Console window doesn't close properly sometimes -Bug #448: Do not break container window formatting when item names are very long -Bug #458: Topics sometimes not automatically added to known topic list -Bug #476: Auto-Moving allows player movement after using DisablePlayerControls -Bug #478: After sleeping in a bed the rest dialogue window opens automtically again -Bug #492: On creating potions the ingredients are removed twice -Feature #63: Mercantile skill -Feature #82: Persuasion Dialogue -Feature #219: Missing dialogue filters/functions -Feature #369: Add a FailedAction -Feature #377: Select head/hair on character creation -Feature #391: Dummy AI package classes -Feature #435: Global Map, 2nd Layer -Feature #450: Persuasion -Feature #457: Add more script instructions -Feature #474: update the global variable pcrace when the player's race is changed -Task #158: Move dynamically generated classes from Player class to World Class -Task #159: ESMStore rework and cleanup -Task #163: More Component Namespace Cleanup -Task #402: Move player data from MWWorld::Player to the player's NPC record -Task #446: Fix no namespace in BulletShapeLoader - -0.19.0 - -Bug #374: Character shakes in 3rd person mode near the origin -Bug #404: Gamma correct rendering -Bug #407: Shoes of St. Rilm do not work -Bug #408: Rugs has collision even if they are not supposed to -Bug #412: Birthsign menu sorted incorrectly -Bug #413: Resolutions presented multiple times in launcher -Bug #414: launcher.cfg file stored in wrong directory -Bug #415: Wrong esm order in openmw.cfg -Bug #418: Sound listener position updates incorrectly -Bug #423: wrong usage of "Version" entry in openmw.desktop -Bug #426: Do not use hardcoded splash images -Bug #431: Don't use markers for raycast -Bug #432: Crash after picking up items from an NPC -Feature #21/#95: Sleeping/resting -Feature #61: Alchemy Skill -Feature #68: Death -Feature #69/#86: Spell Creation -Feature #72/#84: Travel -Feature #76: Global Map, 1st Layer -Feature #120: Trainer Window -Feature #152: Skill Increase from Skill Books -Feature #160: Record Saving -Task #400: Review GMST access - -0.18.0 - -Bug #310: Button of the "preferences menu" are too small -Bug #361: Hand-to-hand skill is always 100 -Bug #365: NPC and creature animation is jerky; Characters float around when they are not supposed to -Bug #372: playSound3D uses original coordinates instead of current coordinates. -Bug #373: Static OGRE build faulty -Bug #375: Alt-tab toggle view -Bug #376: Screenshots are disable -Bug #378: Exception when drinking self-made potions -Bug #380: Cloth visibility problem -Bug #384: Weird character on doors tooltip. -Bug #398: Some objects do not collide in MW, but do so in OpenMW -Feature #22: Implement level-up -Feature #36: Hide Marker -Feature #88: Hotkey Window -Feature #91: Level-Up Dialogue -Feature #118: Keyboard and Mouse-Button bindings -Feature #119: Spell Buying Window -Feature #133: Handle resources across multiple data directories -Feature #134: Generate a suitable default-value for --data-local -Feature #292: Object Movement/Creation Script Instructions -Feature #340: AIPackage data structures -Feature #356: Ingredients use -Feature #358: Input system rewrite -Feature #370: Target handling in actions -Feature #379: Door markers on the local map -Feature #389: AI framework -Feature #395: Using keys to open doors / containers -Feature #396: Loading screens -Feature #397: Inventory avatar image and race selection head preview -Task #339: Move sounds into Action - -0.17.0 - -Bug #225: Valgrind reports about 40MB of leaked memory -Bug #241: Some physics meshes still don't match -Bug #248: Some textures are too dark -Bug #300: Dependency on proprietary CG toolkit -Bug #302: Some objects don't collide although they should -Bug #308: Freeze in Balmora, Meldor: Armorer -Bug #313: openmw without a ~/.config/openmw folder segfault. -Bug #317: adding non-existing spell via console locks game -Bug #318: Wrong character normals -Bug #341: Building with Ogre Debug libraries does not use debug version of plugins -Bug #347: Crash when running openmw with --start="XYZ" -Bug #353: FindMyGUI.cmake breaks path on Windows -Bug #359: WindowManager throws exception at destruction -Bug #364: Laggy input on OS X due to bug in Ogre's event pump implementation -Feature #33: Allow objects to cross cell-borders -Feature #59: Dropping Items (replaced stopgap implementation with a proper one) -Feature #93: Main Menu -Feature #96/329/330/331/332/333: Player Control -Feature #180: Object rotation and scaling. -Feature #272: Incorrect NIF material sharing -Feature #314: Potion usage -Feature #324: Skill Gain -Feature #342: Drain/fortify dynamic stats/attributes magic effects -Feature #350: Allow console only script instructions -Feature #352: Run scripts in console on startup -Task #107: Refactor mw*-subsystems -Task #325: Make CreatureStats into a class -Task #345: Use Ogre's animation system -Task #351: Rewrite Action class to support automatic sound playing - -0.16.0 - -Bug #250: OpenMW launcher erratic behaviour -Bug #270: Crash because of underwater effect on OS X -Bug #277: Auto-equipping in some cells not working -Bug #294: Container GUI ignores disabled inventory menu -Bug #297: Stats review dialog shows all skills and attribute values as 0 -Bug #298: MechanicsManager::buildPlayer does not remove previous bonuses -Bug #299: Crash in World::disable -Bug #306: Non-existent ~/.config/openmw "crash" the launcher. -Bug #307: False "Data Files" location make the launcher "crash" -Feature #81: Spell Window -Feature #85: Alchemy Window -Feature #181: Support for x.y script syntax -Feature #242: Weapon and Spell icons -Feature #254: Ingame settings window -Feature #293: Allow "stacking" game modes -Feature #295: Class creation dialog tooltips -Feature #296: Clicking on the HUD elements should show/hide the respective window -Feature #301: Direction after using a Teleport Door -Feature #303: Allow object selection in the console -Feature #305: Allow the use of = as a synonym for == -Feature #312: Compensation for slow object access in poorly written Morrowind.esm scripts -Task #176: Restructure enabling/disabling of MW-references -Task #283: Integrate ogre.cfg file in settings file -Task #290: Auto-Close MW-reference related GUI windows - -0.15.0 - -Bug #5: Physics reimplementation (fixes various issues) -Bug #258: Resizing arrow's background is not transparent -Bug #268: Widening the stats window in X direction causes layout problems -Bug #269: Topic pane in dialgoue window is too small for some longer topics -Bug #271: Dialog choices are sorted incorrectly -Bug #281: The single quote character is not rendered on dialog windows -Bug #285: Terrain not handled properly in cells that are not predefined -Bug #289: Dialogue filter isn't doing case smashing/folding for item IDs -Feature #15: Collision with Terrain -Feature #17: Inventory-, Container- and Trade-Windows -Feature #44: Floating Labels above Focussed Objects -Feature #80: Tooltips -Feature #83: Barter Dialogue -Feature #90: Book and Scroll Windows -Feature #156: Item Stacking in Containers -Feature #213: Pulsating lights -Feature #218: Feather & Burden -Feature #256: Implement magic effect bookkeeping -Feature #259: Add missing information to Stats window -Feature #260: Correct case for dialogue topics -Feature #280: GUI texture atlasing -Feature #291: Ability to use GMST strings from GUI layout files -Task #255: Make MWWorld::Environment into a singleton - -0.14.0 - -Bug #1: Meshes rendered with wrong orientation -Bug #6/Task #220: Picking up small objects doesn't always work -Bug #127: tcg doesn't work -Bug #178: Compablity problems with Ogre 1.8.0 RC 1 -Bug #211: Wireframe mode (toggleWireframe command) should not apply to Console & other UI -Bug #227: Terrain crashes when moving away from predefined cells -Bug #229: On OS X Launcher cannot launch game if path to binary contains spaces -Bug #235: TGA texture loading problem -Bug #246: wireframe mode does not work in water -Feature #8/#232: Water Rendering -Feature #13: Terrain Rendering -Feature #37: Render Path Grid -Feature #66: Factions -Feature #77: Local Map -Feature #78: Compass/Mini-Map -Feature #97: Render Clothing/Armour -Feature #121: Window Pinning -Feature #205: Auto equip -Feature #217: Contiainer should track changes to its content -Feature #221: NPC Dialogue Window Enhancements -Feature #233: Game settings manager -Feature #240: Spell List and selected spell (no GUI yet) -Feature #243: Draw State -Task #113: Morrowind.ini Importer -Task #215: Refactor the sound code -Task #216: Update MyGUI - -0.13.0 - -Bug #145: Fixed sound problems after cell change -Bug #179: Pressing space in console triggers activation -Bug #186: CMake doesn't use the debug versions of Ogre libraries on Linux -Bug #189: ASCII 16 character added to console on it's activation on Mac OS X -Bug #190: Case Folding fails with music files -Bug #192: Keypresses write Text into Console no matter which gui element is active -Bug #196: Collision shapes out of place -Bug #202: ESMTool doesn't not work with localised ESM files anymore -Bug #203: Torch lights only visible on short distance -Bug #207: Ogre.log not written -Bug #209: Sounds do not play -Bug #210: Ogre crash at Dren plantation -Bug #214: Unsupported file format version -Bug #222: Launcher is writing openmw.cfg file to wrong location -Feature #9: NPC Dialogue Window -Feature #16/42: New sky/weather implementation -Feature #40: Fading -Feature #48: NPC Dialogue System -Feature #117: Equipping Items (backend only, no GUI yet, no rendering of equipped items yet) -Feature #161: Load REC_PGRD records -Feature #195: Wireframe-mode -Feature #198/199: Various sound effects -Feature #206: Allow picking data path from launcher if non is set -Task #108: Refactor window manager class -Task #172: Sound Manager Cleanup -Task #173: Create OpenEngine systems in the appropriate manager classes -Task #184: Adjust MSVC and gcc warning levels -Task #185: RefData rewrite -Task #201: Workaround for transparency issues -Task #208: silenced esm_reader.hpp warning - -0.12.0 - -Bug #154: FPS Drop -Bug #169: Local scripts continue running if associated object is deleted -Bug #174: OpenMW fails to start if the config directory doesn't exist -Bug #187: Missing lighting -Bug #188: Lights without a mesh are not rendered -Bug #191: Taking screenshot causes crash when running installed -Feature #28: Sort out the cell load problem -Feature #31: Allow the player to move away from pre-defined cells -Feature #35: Use alternate storage location for modified object position -Feature #45: NPC animations -Feature #46: Creature Animation -Feature #89: Basic Journal Window -Feature #110: Automatically pick up the path of existing MW-installations -Feature #183: More FPS display settings -Task #19: Refactor engine class -Task #109/Feature #162: Automate Packaging -Task #112: Catch exceptions thrown in input handling functions -Task #128/#168: Cleanup Configuration File Handling -Task #131: NPC Activation doesn't work properly -Task #144: MWRender cleanup -Task #155: cmake cleanup - -0.11.1 - -Bug #2: Resources loading doesn't work outside of bsa files -Bug #3: GUI does not render non-English characters -Bug #7: openmw.cfg location doesn't match -Bug #124: The TCL alias for ToggleCollision is missing. -Bug #125: Some command line options can't be used from a .cfg file -Bug #126: Toggle-type script instructions are less verbose compared with original MW -Bug #130: NPC-Record Loading fails for some NPCs -Bug #167: Launcher sets invalid parameters in ogre config -Feature #10: Journal -Feature #12: Rendering Optimisations -Feature #23: Change Launcher GUI to a tabbed interface -Feature #24: Integrate the OGRE settings window into the launcher -Feature #25: Determine openmw.cfg location (Launcher) -Feature #26: Launcher Profiles -Feature #79: MessageBox -Feature #116: Tab-Completion in Console -Feature #132: --data-local and multiple --data -Feature #143: Non-Rendering Performance-Optimisations -Feature #150: Accessing objects in cells via ID does only work for objects with all lower case IDs -Feature #157: Version Handling -Task #14: Replace tabs with 4 spaces -Task #18: Move components from global namespace into their own namespace -Task #123: refactor header files in components/esm - -0.10.0 - -* NPC dialogue window (not functional yet) -* Collisions with objects -* Refactor the PlayerPos class -* Adjust file locations -* CMake files and test linking for Bullet -* Replace Ogre raycasting test for activation with something more precise -* Adjust player movement according to collision results -* FPS display -* Various Portability Improvements -* Mac OS X support is back! - -0.9.0 - -* Exterior cells loading, unloading and management -* Character Creation GUI -* Character creation -* Make cell names case insensitive when doing internal lookups -* Music player -* NPCs rendering - -0.8.0 - -* GUI -* Complete and working script engine -* In game console -* Sky rendering -* Sound and music -* Tons of smaller stuff - -0.7.0 - -* This release is a complete rewrite in C++. -* All D code has been culled, and all modules have been rewritten. -* The game is now back up to the level of rendering interior cells and moving around, but physics, sound, GUI, and scripting still remain to be ported from the old codebase. - -0.6.0 - -* Coded a GUI system using MyGUI -* Skinned MyGUI to look like Morrowind (work in progress) -* Integrated the Monster script engine -* Rewrote some functions into script code -* Very early MyGUI < > Monster binding -* Fixed Windows sound problems (replaced old openal32.dll) - -0.5.0 - -* Collision detection with Bullet -* Experimental walk & fall character physics -* New key bindings: - * t toggle physics mode (walking, flying, ghost), - * n night eye, brightens the scene -* Fixed incompatability with DMD 1.032 and newer compilers -* * (thanks to tomqyp) -* Various minor changes and updates - -0.4.0 - -* Switched from Audiere to OpenAL -* * (BIG thanks to Chris Robinson) -* Added complete Makefile (again) as a alternative build tool -* More realistic lighting (thanks again to Chris Robinson) -* Various localization fixes tested with Russian and French versions -* Temporary workaround for the Unicode issue: invalid UTF displayed as '?' -* Added ns option to disable sound, for debugging -* Various bug fixes -* Cosmetic changes to placate gdc Wall - -0.3.0 - -* Built and tested on Windows XP -* Partial support for FreeBSD (exceptions do not work) -* You no longer have to download Monster separately -* Made an alternative for building without DSSS (but DSSS still works) -* Renamed main program from 'morro' to 'openmw' -* Made the config system more robust -* Added oc switch for showing Ogre config window on startup -* Removed some config files, these are auto generated when missing. -* Separated plugins.cfg into linux and windows versions. -* Updated Makefile and sources for increased portability -* confirmed to work against OIS 1.0.0 (Ubuntu repository package) - -0.2.0 - -* Compiles with gdc -* Switched to DSSS for building D code -* Includes the program esmtool - -0.1.0 - -first release +See CHANGELOG.md From c8373198a1b8c714ead2db7d38641d4f30a5db3e Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 10 Jan 2015 16:36:59 +0100 Subject: [PATCH 0260/3725] Add Travis-CI build status image to Readme --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 862ae16c7..63bf1bcf3 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ OpenMW: A reimplementation of The Elder Scrolls III: Morrowind ============================================================== +[![Build Status](https://travis-ci.org/OpenMW/openmw.svg?branch=coverity_scan)](https://travis-ci.org/OpenMW/openmw) + 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. From 32ad1ae1761e1961ccb2acf25669f3e97fb2799c Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 10 Jan 2015 16:39:00 +0100 Subject: [PATCH 0261/3725] Add coverity scan build status image to Readme --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 63bf1bcf3..bc1efa562 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,8 @@ OpenMW: A reimplementation of The Elder Scrolls III: Morrowind [![Build Status](https://travis-ci.org/OpenMW/openmw.svg?branch=coverity_scan)](https://travis-ci.org/OpenMW/openmw) +[![Coverity Scan Build Status](https://scan.coverity.com/projects/3740/badge.svg)](https://scan.coverity.com/projects/3740) + 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. From 5ee78602e98326601a7058183677497c22552ced Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 10 Jan 2015 16:44:28 +0100 Subject: [PATCH 0262/3725] Improve readme formatting --- README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index bc1efa562..754e4d5f7 100644 --- a/README.md +++ b/README.md @@ -18,18 +18,18 @@ Font Licenses: Installation ============ -Windows: +Windows +------- Run the installer. -Linux: -Ubuntu (and most others) -Download the .deb file and install it in the usual way. +Linux +----- +* Ubuntu (and most others): Download the .deb file and install it in the usual way. -Arch Linux -There's an OpenMW package available in the [community] Repository: -https://www.archlinux.org/packages/?sort=&q=openmw +* Arch Linux: There's an OpenMW package available in the [community] Repository: https://www.archlinux.org/packages/?sort=&q=openmw -OS X: +OS X +---- Open DMG file, copy OpenMW folder anywhere, for example in /Applications Build from source From 3c74c554f811fe8e71d50fe6ab4ac0f8857385f0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 10 Jan 2015 16:45:20 +0100 Subject: [PATCH 0263/3725] Add IRC channel to readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 754e4d5f7..de06554c1 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ Morrowind by Bethesda Softworks. You need to own and install the original game f * Version: 0.34.0 * License: GPL (see GPL3.txt for more information) * Website: http://www.openmw.org +* IRC: #openmw on irc.freenode.net Font Licenses: * DejaVuLGCSansMono.ttf: custom (see DejaVu Font License.txt for more information) From d1b07faa5678999f04e3d6e06162cef49115cf7d Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 10 Jan 2015 16:49:59 +0100 Subject: [PATCH 0264/3725] Replace outdated Installation section with link --- README.md | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/README.md b/README.md index de06554c1..279d1d6d7 100644 --- a/README.md +++ b/README.md @@ -19,19 +19,7 @@ Font Licenses: Installation ============ -Windows -------- -Run the installer. - -Linux ------ -* Ubuntu (and most others): Download the .deb file and install it in the usual way. - -* Arch Linux: There's an OpenMW package available in the [community] Repository: https://www.archlinux.org/packages/?sort=&q=openmw - -OS X ----- -Open DMG file, copy OpenMW folder anywhere, for example in /Applications +Head to [Downloads](http://openmw.org/downloads/) to find a packaged release for your platform of choice. Build from source ================= From bcddfabea135be3ff034ee11a0d0f79736272a57 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 10 Jan 2015 16:54:55 +0100 Subject: [PATCH 0265/3725] Fix license file names in readme --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 279d1d6d7..ff5185b5d 100644 --- a/README.md +++ b/README.md @@ -9,12 +9,12 @@ 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.34.0 -* License: GPL (see GPL3.txt for more information) +* License: GPL (see docs/license/GPL3.txt for more information) * Website: http://www.openmw.org * IRC: #openmw on irc.freenode.net Font Licenses: -* DejaVuLGCSansMono.ttf: custom (see DejaVu Font License.txt for more information) +* DejaVuLGCSansMono.ttf: custom (see docs/license/DejaVu Font License.txt for more information) Installation ============ From 36a2c11da4e0f59c871673e482f3ab4c80f28f90 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 10 Jan 2015 16:59:21 +0100 Subject: [PATCH 0266/3725] Move credits.txt to AUTHORS.md to make it consistent with most other github projects --- credits.txt => AUTHORS.md | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) rename credits.txt => AUTHORS.md (93%) diff --git a/credits.txt b/AUTHORS.md similarity index 93% rename from credits.txt rename to AUTHORS.md index dfdf87565..b6aec55f5 100644 --- a/credits.txt +++ b/AUTHORS.md @@ -1,4 +1,5 @@ Contributors +============ The OpenMW project was started in 2008 by Nicolay Korslund. In the course of years many people have contributed to the project. @@ -7,7 +8,9 @@ If you feel your name is missing from this list, please notify a developer. -Programmers: +Programmers +----------- + Marc Zinnschlag (Zini) - Lead Programmer/Project Manager Adam Hogan (aurix) @@ -103,7 +106,8 @@ viadanna Vincent Heuken vocollapse -Packagers: +Packagers +--------- Alexander Olofsson (Ace) - Windows Bret Curtis (psi29a) - Ubuntu Linux Edmondo Tommasina (edmondo) - Gentoo Linux @@ -113,7 +117,8 @@ Kenny Armstrong (artorius) - Fedora Linux Nikolay Kasyanov (corristo) - Mac OS X Sandy Carter (bwrsandman) - Arch Linux -Public Relations and Translations: +Public Relations and Translations +--------------------------------- Alex McKibben (WeirdSexy) - Podcaster Artem Kotsynyak (greye) - Russian News Writer Jim Clauwaert (Zedd) - Public Outreach @@ -125,12 +130,14 @@ Pithorn - Chinese News Writer sir_herrbatka - Polish News Writer Dawid Lakomy (Vedyimyn) - Polish News Writer -Website: +Website +------- Lukasz Gromanowski (Lgro) - Website Administrator Ryan Sardonic (Wry) - Wiki Editor sir_herrbatka - Forum Administrator -Formula Research: +Formula Research +---------------- Hrnchamd Epsilon fragonard @@ -141,12 +148,14 @@ Myckel natirips Sadler -Artwork: +Artwork +------- Necrod - OpenMW Logo Mickey Lyle (raevol) - Wordpress Theme Tom Koenderink (Okulo), SirHerrbatka, crysthala, Shnatsel - OpenMW Editor Icons -Inactive Contributors: +Inactive Contributors +--------------------- Ardekantur Armin Preiml Berulacks @@ -174,7 +183,8 @@ Thoronador Yuri Krupenin -Additional Credits: +Additional Credits +------------------ In this section we would like to thank people not part of OpenMW for their work. Thanks to Maxim Nikolaev, From 6079bcad245e22a9c778571a4b4387e367e804f0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 10 Jan 2015 17:03:41 +0100 Subject: [PATCH 0267/3725] Formatting fix --- AUTHORS.md | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/AUTHORS.md b/AUTHORS.md index b6aec55f5..dddc61a13 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -4,13 +4,12 @@ Contributors The OpenMW project was started in 2008 by Nicolay Korslund. In the course of years many people have contributed to the project. -If you feel your name is missing from this list, -please notify a developer. +If you feel your name is missing from this list, please notify a developer. Programmers ----------- - +
 Marc Zinnschlag (Zini) - Lead Programmer/Project Manager
 
 Adam Hogan (aurix)
@@ -105,9 +104,10 @@ Torben Leif Carrington (TorbenC)
 viadanna
 Vincent Heuken
 vocollapse
-
+
Packagers --------- +
 Alexander Olofsson (Ace) - Windows
 Bret Curtis (psi29a) - Ubuntu Linux
 Edmondo Tommasina (edmondo) - Gentoo Linux
@@ -116,9 +116,10 @@ Karl-Felix Glatzer (k1ll) - Linux Binaries
 Kenny Armstrong (artorius) - Fedora Linux
 Nikolay Kasyanov (corristo) - Mac OS X
 Sandy Carter (bwrsandman) - Arch Linux
-
+
Public Relations and Translations --------------------------------- +
 Alex McKibben (WeirdSexy) - Podcaster
 Artem Kotsynyak (greye) - Russian News Writer
 Jim Clauwaert (Zedd) - Public Outreach
@@ -129,15 +130,17 @@ Mickey Lyle (raevol) - Release Manager
 Pithorn - Chinese News Writer
 sir_herrbatka - Polish News Writer
 Dawid Lakomy (Vedyimyn) - Polish News Writer
-
+
Website ------- +
 Lukasz Gromanowski (Lgro) - Website Administrator
 Ryan Sardonic (Wry) - Wiki Editor
 sir_herrbatka - Forum Administrator
-
+
Formula Research ---------------- +
 Hrnchamd
 Epsilon
 fragonard
@@ -147,15 +150,17 @@ modred11
 Myckel
 natirips
 Sadler
-
+
Artwork ------- +
 Necrod - OpenMW Logo
 Mickey Lyle (raevol) - Wordpress Theme
 Tom Koenderink (Okulo), SirHerrbatka, crysthala, Shnatsel - OpenMW Editor Icons
-
+
Inactive Contributors --------------------- +
 Ardekantur
 Armin Preiml
 Berulacks
@@ -181,7 +186,7 @@ spyboot
 Star-Demon
 Thoronador
 Yuri Krupenin
-
+
Additional Credits ------------------ From 529fd353fe0724a179595854f0f92f137cd39fca Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 10 Jan 2015 17:05:24 +0100 Subject: [PATCH 0268/3725] EB Garamond and Daedric Fontface are no longer used --- AUTHORS.md | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/AUTHORS.md b/AUTHORS.md index dddc61a13..f6da26e77 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -196,17 +196,10 @@ Thanks to Maxim Nikolaev, for allowing us to use his excellent Morrowind fan-art on our website and in other places. Thanks to DokterDume, -for kindly providing us with the Moon and Star logo, -used as the application icon and project logo. +for kindly providing us with the Moon and Star logo, used as the application icon and project logo. Thanks to Kevin Ryan, for creating the icon used for the Data Files tab of the OpenMW Launcher. -Thanks to Georg Duffner, -for his EB Garamond fontface, see OFL.txt for his license terms. - -Thanks to Dongle, -for his Daedric fontface, see Daedric Font License.txt for his license terms. - Thanks to DejaVu team, for their DejaVuLGCSansMono fontface, see DejaVu Font License.txt for their license terms. From 3684f586cd6cad55cc5fb1d49db18d12a1ff8308 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 10 Jan 2015 17:18:33 +0100 Subject: [PATCH 0269/3725] Changelog formatting --- CHANGELOG.md | 2677 +++++++++++++++++++++++++------------------------- 1 file changed, 1355 insertions(+), 1322 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 09f318d9d..750cb5476 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,1376 +1,1401 @@ -
 0.34.0
-
-Bug #904: omwlauncher doesn't allow installing Tribunal and Bloodmoon if only MW is installed
-Bug #986: Launcher: renaming profile names is broken
-Bug #1061: "Browse to CD..." launcher crash
-Bug #1135: Launcher crashes if user does not have write permission
-Bug #1231: Current installer in launcher does not correctly import russian Morrowind.ini settings from setup.inx
-Bug #1288: Fix the Alignment of the Resolution Combobox
-Bug #1343: BIK videos occasionally out of sync with audio
-Bug #1684: Morrowind Grass Mod graphical glitches
-Bug #1734: NPC in fight with invisible/sneaking player
-Bug #1982: Long class names are cut off in the UI
-Bug #2012: Editor: OpenCS script compiler sometimes fails to find IDs
-Bug #2015: Running while levitating does not affect speed but still drains fatigue
-Bug #2018: OpenMW don´t reset modified cells to vanilla when a plugin is deselected and don´t apply changes to cells already visited.
-Bug #2045: ToggleMenus command should close dialogue windows
-Bug #2046: Crash: light_de_streetlight_01_223
-Bug #2047: Buglamp tooltip minor correction
-Bug #2050: Roobrush floating texture bits
-Bug #2053: Slaves react negatively to PC picking up slave's bracers
-Bug #2055: Dremora corpses use the wrong model
-Bug #2056: Mansilamat Vabdas's corpse is floating in the water
-Bug #2057: "Quest: Larius Varro Tells A Little Story": Bounty not completely removed after finishing quest
-Bug #2059: Silenced enemies try to cast spells anyway
-Bug #2060: Editor: Special case implementation for top level window with single sub-window should be optional
-Bug #2061: Editor: SubView closing that is not directly triggered by the user isn't handled properly
-Bug #2063: Tribunal: Quest 'The Warlords' doesn't work
-Bug #2064: Sneak attack on hostiles causes bounty
-Bug #2065: Editor: Qt signal-slot error when closing a dialogue subview
-Bug #2070: Loading ESP in OpenMW works but fails in OpenCS
-Bug #2071: CTD in 0.33
-Bug #2073: Storm atronach animation stops now and then
-Bug #2075: Molag Amur Region, Map shows water on solid ground
-Bug #2080: game won't work with fair magicka regen
-Bug #2082: NPCs appear frozen or switched off after leaving and quickly reentering a cell
-Bug #2088: OpenMW is unable to play OGG files.
-Bug #2093: Darth Gares talks to you in Ilunibi even when he's not there, screwing up the Main Quests
-Bug #2095: Coordinate and rotation editing in the Reference table does not work.
-Bug #2096: Some overflow fun and bartering exploit
-Bug #2098: [D3D] Game crash on maximize
-Bug #2099: Activate, player seems not to work
-Bug #2104: Only labels are sensitive in buttons
-Bug #2107: "Slowfall" effect is too weak
-Bug #2114: OpenCS doesn't load an ESP file full of errors even though Vanilla MW Construction Set can
-Bug #2117: Crash when encountering bandits on opposite side of river from the egg mine south of Balmora
-Bug #2124: [Mod: Baldurians Transparent Glass Amor] Armor above head
-Bug #2125: Unnamed NiNodes in weapons problem in First Person
-Bug #2126: Dirty dialog script in tribunal.esm causing bug in Tribunal MQ
-Bug #2128: Crash when picking character's face
-Bug #2129: Disable the third-person zoom feature by default
-Bug #2130: Ash storm particles shown too long during transition to clear sky
-Bug #2137: Editor: exception caused by following the Creature column of a SoundGen record
-Bug #2139: Mouse movement should be ignored during intro video
-Bug #2143: Editor: Saving is broken
-Bug #2145: OpenMW - crash while exiting x64 debug build
-Bug #2152: You can attack Almalexia during her final monologue
-Bug #2154: Visual effects behave weirdly after loading/taking a screenshot
-Bug #2155: Vivec has too little magicka
-Bug #2156: Azura's spirit fades away too fast
-Bug #2158: [Mod]Julan Ashlander Companion 2.0: Negative magicka
-Bug #2161: Editor: combat/magic/stealth values of creature not displayed correctly
-Bug #2163: OpenMW can't detect death if the NPC die by the post damage effect of a magic weapon.
-Bug #2168: Westly's Master Head Pack X – Some hairs aren't rendered correctly.
-Bug #2170: Mods using conversations to update PC inconsistant
-Bug #2180: Editor: Verifier doesn't handle Windows-specific path issues when dealing with resources
-Bug #2212: Crash or unexpected behavior while closing OpenCS cell render window on OS X
-Feature #238: Add UI to run INI-importer from the launcher
-Feature #854: Editor: Add user setting to show status bar
-Feature #987: Launcher: first launch instructions for CD need to be more explicit
-Feature #1232: There is no way to set the "encoding" option using launcher UI.
-Feature #1281: Editor: Render cell markers
-Feature #1918: Editor: Functionality for Double-Clicking in Tables
-Feature #1966: Editor: User Settings dialogue grouping/labelling/tooltips
-Feature #2097: Editor: Edit position of references in 3D scene
-Feature #2121: Editor: Add edit mode button to scene toolbar
-Task #1965: Editor: Improve layout of user settings dialogue
+------
+
+    Bug #904: omwlauncher doesn't allow installing Tribunal and Bloodmoon if only MW is installed
+    Bug #986: Launcher: renaming profile names is broken
+    Bug #1061: "Browse to CD..." launcher crash
+    Bug #1135: Launcher crashes if user does not have write permission
+    Bug #1231: Current installer in launcher does not correctly import russian Morrowind.ini settings from setup.inx
+    Bug #1288: Fix the Alignment of the Resolution Combobox
+    Bug #1343: BIK videos occasionally out of sync with audio
+    Bug #1684: Morrowind Grass Mod graphical glitches
+    Bug #1734: NPC in fight with invisible/sneaking player
+    Bug #1982: Long class names are cut off in the UI
+    Bug #2012: Editor: OpenCS script compiler sometimes fails to find IDs
+    Bug #2015: Running while levitating does not affect speed but still drains fatigue
+    Bug #2018: OpenMW don´t reset modified cells to vanilla when a plugin is deselected and don´t apply changes to cells already visited.
+    Bug #2045: ToggleMenus command should close dialogue windows
+    Bug #2046: Crash: light_de_streetlight_01_223
+    Bug #2047: Buglamp tooltip minor correction
+    Bug #2050: Roobrush floating texture bits
+    Bug #2053: Slaves react negatively to PC picking up slave's bracers
+    Bug #2055: Dremora corpses use the wrong model
+    Bug #2056: Mansilamat Vabdas's corpse is floating in the water
+    Bug #2057: "Quest: Larius Varro Tells A Little Story": Bounty not completely removed after finishing quest
+    Bug #2059: Silenced enemies try to cast spells anyway
+    Bug #2060: Editor: Special case implementation for top level window with single sub-window should be optional
+    Bug #2061: Editor: SubView closing that is not directly triggered by the user isn't handled properly
+    Bug #2063: Tribunal: Quest 'The Warlords' doesn't work
+    Bug #2064: Sneak attack on hostiles causes bounty
+    Bug #2065: Editor: Qt signal-slot error when closing a dialogue subview
+    Bug #2070: Loading ESP in OpenMW works but fails in OpenCS
+    Bug #2071: CTD in 0.33
+    Bug #2073: Storm atronach animation stops now and then
+    Bug #2075: Molag Amur Region, Map shows water on solid ground
+    Bug #2080: game won't work with fair magicka regen
+    Bug #2082: NPCs appear frozen or switched off after leaving and quickly reentering a cell
+    Bug #2088: OpenMW is unable to play OGG files.
+    Bug #2093: Darth Gares talks to you in Ilunibi even when he's not there, screwing up the Main Quests
+    Bug #2095: Coordinate and rotation editing in the Reference table does not work.
+    Bug #2096: Some overflow fun and bartering exploit
+    Bug #2098: [D3D] Game crash on maximize
+    Bug #2099: Activate, player seems not to work
+    Bug #2104: Only labels are sensitive in buttons
+    Bug #2107: "Slowfall" effect is too weak
+    Bug #2114: OpenCS doesn't load an ESP file full of errors even though Vanilla MW Construction Set can
+    Bug #2117: Crash when encountering bandits on opposite side of river from the egg mine south of Balmora
+    Bug #2124: [Mod: Baldurians Transparent Glass Amor] Armor above head
+    Bug #2125: Unnamed NiNodes in weapons problem in First Person
+    Bug #2126: Dirty dialog script in tribunal.esm causing bug in Tribunal MQ
+    Bug #2128: Crash when picking character's face
+    Bug #2129: Disable the third-person zoom feature by default
+    Bug #2130: Ash storm particles shown too long during transition to clear sky
+    Bug #2137: Editor: exception caused by following the Creature column of a SoundGen record
+    Bug #2139: Mouse movement should be ignored during intro video
+    Bug #2143: Editor: Saving is broken
+    Bug #2145: OpenMW - crash while exiting x64 debug build
+    Bug #2152: You can attack Almalexia during her final monologue
+    Bug #2154: Visual effects behave weirdly after loading/taking a screenshot
+    Bug #2155: Vivec has too little magicka
+    Bug #2156: Azura's spirit fades away too fast
+    Bug #2158: [Mod]Julan Ashlander Companion 2.0: Negative magicka
+    Bug #2161: Editor: combat/magic/stealth values of creature not displayed correctly
+    Bug #2163: OpenMW can't detect death if the NPC die by the post damage effect of a magic weapon.
+    Bug #2168: Westly's Master Head Pack X – Some hairs aren't rendered correctly.
+    Bug #2170: Mods using conversations to update PC inconsistant
+    Bug #2180: Editor: Verifier doesn't handle Windows-specific path issues when dealing with resources
+    Bug #2212: Crash or unexpected behavior while closing OpenCS cell render window on OS X
+    Feature #238: Add UI to run INI-importer from the launcher
+    Feature #854: Editor: Add user setting to show status bar
+    Feature #987: Launcher: first launch instructions for CD need to be more explicit
+    Feature #1232: There is no way to set the "encoding" option using launcher UI.
+    Feature #1281: Editor: Render cell markers
+    Feature #1918: Editor: Functionality for Double-Clicking in Tables
+    Feature #1966: Editor: User Settings dialogue grouping/labelling/tooltips
+    Feature #2097: Editor: Edit position of references in 3D scene
+    Feature #2121: Editor: Add edit mode button to scene toolbar
+    Task #1965: Editor: Improve layout of user settings dialogue
 
 0.33.1
+------
 
-Bug #2108: OpenCS fails to build
+    Bug #2108: OpenCS fails to build
 
 0.33.0
-
-Bug #371: If console assigned to ` (probably to any symbolic key), "`" symbol will be added to console every time it closed
-Bug #1148: Some books'/scrolls' contents are displayed incorrectly
-Bug #1290: Editor: status bar is not updated when record filter is changed
-Bug #1292: Editor: Documents are not removed on closing the last view
-Bug #1301: Editor: File->Exit only checks the document it was issued from.
-Bug #1353: Bluetooth on with no speaker connected results in significantly longer initial load times
-Bug #1436: NPCs react from too far distance
-Bug #1472: PC is placed on top of following NPC when changing cell
-Bug #1487: Tall PC can get stuck in staircases
-Bug #1565: Editor: Subviews are deleted on shutdown instead when they are closed
-Bug #1623: Door marker on Ghorak Manor's balcony makes PC stuck
-Bug #1633: Loaddoor to Sadrith Mora, Telvanni Council House spawns PC in the air
-Bug #1655: Use Appropriate Application Icons on Windows
-Bug #1679: Tribunal expansion, Meryn Othralas the backstage manager in the theatre group in Mournhold in the great bazaar district is floating a good feet above the ground.
-Bug #1705: Rain is broken in third person
-Bug #1706: Thunder and lighting still occurs while the game is paused during the rain
-Bug #1708: No long jumping
-Bug #1710: Editor: ReferenceableID drag to references record filter field creates incorrect filter
-Bug #1712: Rest on Water
-Bug #1715: "Cancel" button is not always on the same side of menu
-Bug #1725: Editor: content file can be opened multiple times from the same dialogue
-Bug #1730: [MOD: Less Generic Nerevarine] Compile failure attempting to enter the Corprusarium.
-Bug #1733: Unhandled ffmpeg sample formats
-Bug #1735: Editor: "Edit Record" context menu button not opening subview for journal infos
-Bug #1750: Editor: record edits result in duplicate entries
-Bug #1789: Editor: Some characters cannot be used in addon name
-Bug #1803: Resizing the map does not keep the pre-resize center at the post-resize center
-Bug #1821: Recovering Cloudcleaver quest: attacking Sosia is considered a crime when you side with Hlormar
-Bug #1838: Editor: Preferences window appears off screen
-Bug #1839: Editor: Record filter title should be moved two pixels to the right
-Bug #1849: Subrecord error in MAO_Containers
-Bug #1854: Knocked-out actors don't fully act knocked out
-Bug #1855: "Soul trapped" sound doesn't play
-Bug #1857: Missing sound effect for enchanted items with empty charge
-Bug #1859: Missing console command: ResetActors (RA)
-Bug #1861: Vendor category "MagicItems" is unhandled
-Bug #1862: Launcher doesn't start if a file listed in launcher.cfg has correct name but wrong capitalization
-Bug #1864: Editor: Region field for cell record in dialogue subview not working
-Bug #1869: Editor: Change label "Musics" to "Music"
-Bug #1870: Goblins killed while knocked down remain in knockdown-pose
-Bug #1874: CellChanged events should not trigger when crossing exterior cell border
-Bug #1877: Spriggans killed instantly if hit while regening
-Bug #1878: Magic Menu text not un-highlighting correctly when going from spell to item as active magic
-Bug #1881: Stuck in ceiling when entering castle karstaags tower
-Bug #1884: Unlit torches still produce a burning sound
-Bug #1885: Can type text in price field in barter window
-Bug #1887: Equipped items do not emit sounds
-Bug #1889: draugr lord aesliip will attack you and remain non-hostile
-Bug #1892: Guard asks player to pay bounty of 0 gold
-Bug #1895: getdistance should only return max float if ref and target are in different worldspaces
-Bug #1896: Crash Report
-Bug #1897: Conjured Equipment cant be re-equipped if removed
-Bug #1898: Only Gidar Verothan follows you during establish the mine quest
-Bug #1900: Black screen when you open the door and breath underwater
-Bug #1904: Crash on casting recall spell
-Bug #1906: Bound item checks should use the GMSTs
-Bug #1907: Bugged door. Mournhold, The Winged Guar
-Bug #1908: Crime reported for attacking Drathas Nerus's henchmen while they attack Dilborn
-Bug #1909: Weird Quest Flow Infidelities quest
-Bug #1910: Follower fighting with gone npc
-Bug #1911: Npcs will drown themselves
-Bug #1912: World map arrow stays static when inside a building
-Bug #1920: Ulyne Henim disappears when game is loaded inside Vas
-Bug #1922: alchemy-> potion of paralyze
-Bug #1923: "levitation magic cannot be used here" shows outside of tribunal
-Bug #1927: AI prefer melee over magic.
-Bug #1929: Tamriel Rebuilt: Named cells that lie within the overlap with Morrowind.esm are not shown
-Bug #1932: BTB - Spells 14.1 magic effects don´t overwrite the Vanilla ones but are added
-Bug #1935: Stacks of items are worth more when sold individually
-Bug #1940: Launcher does not list addon files if base game file is renamed to a different case
-Bug #1946: Mod "Tel Nechim - moved" breaks savegames
-Bug #1947: Buying/Selling price doesn't properly affect the growth of mercantile skill
-Bug #1950: followers from east empire company quest will fight each other if combat happens with anything
-Bug #1958: Journal can be scrolled indefinitely with a mouse wheel
-Bug #1959: Follower not leaving party on quest end
-Bug #1960: Key bindings not always saved correctly
-Bug #1961: Spell merchants selling racial bonus spells
-Bug #1967: segmentation fault on load saves
-Bug #1968: Jump sounds are not controlled by footsteps slider, sound weird compared to footsteps
-Bug #1970: PC suffers silently when taking damage from lava
-Bug #1971: Dwarven Sceptre collision area is not removed after killing one
-Bug #1974: Dalin/Daris Norvayne follows player indefinitely
-Bug #1975: East Empire Company faction rank breaks during Raven Rock questline
-Bug #1979: 0 strength = permanently over encumbered
-Bug #1993: Shrine blessing in Maar Gan doesn't work
-Bug #2008: Enchanted items do not recharge
-Bug #2011: Editor: OpenCS script compiler doesn't handle member variable access properly
-Bug #2016: Dagoth Ur already dead in Facility Cavern
-Bug #2017: Fighters Guild Quest: The Code Book - dialogue loop when UMP is loaded.
-Bug #2019: Animation of 'Correct UV Mudcrabs' broken
-Bug #2022: Alchemy window - Removing ingredient doesn't remove the number of ingredients
-Bug #2025: Missing mouse-over text for non affordable items
-Bug #2028: [MOD: Tamriel Rebuilt] Crashing when trying to enter interior cell "Ruinous Keep, Great Hall"
-Bug #2029: Ienith Brothers Thiev's Guild quest journal entry not adding
-Feature #471: Editor: Special case implementation for top-level window with single sub-window
-Feature #472: Editor: Sub-Window re-use settings
-Feature #704: Font colors import from fallback settings
-Feature #879: Editor: Open sub-views in a new top-level window
-Feature #932: Editor: magic effect table
-Feature #937: Editor: Path Grid table
-Feature #938: Editor: Sound Gen table
-Feature #1117: Death and LevelUp music
-Feature #1226: Editor: Request UniversalId editing from table columns
-Feature #1545: Targeting console on player
-Feature #1597: Editor: Render terrain
-Feature #1695: Editor: add column for CellRef's global variable
-Feature #1696: Editor: use ESM::Cell's RefNum counter
-Feature #1697: Redden player's vision when hit
-Feature #1856: Spellcasting for non-biped creatures
-Feature #1879: Editor: Run OpenMW with the currently edited content list
-Task #1851: Move AI temporary state out of AI packages
-Task #1865: Replace char type in records
+------
+
+    Bug #371: If console assigned to ` (probably to any symbolic key), "`" symbol will be added to console every time it closed
+    Bug #1148: Some books'/scrolls' contents are displayed incorrectly
+    Bug #1290: Editor: status bar is not updated when record filter is changed
+    Bug #1292: Editor: Documents are not removed on closing the last view
+    Bug #1301: Editor: File->Exit only checks the document it was issued from.
+    Bug #1353: Bluetooth on with no speaker connected results in significantly longer initial load times
+    Bug #1436: NPCs react from too far distance
+    Bug #1472: PC is placed on top of following NPC when changing cell
+    Bug #1487: Tall PC can get stuck in staircases
+    Bug #1565: Editor: Subviews are deleted on shutdown instead when they are closed
+    Bug #1623: Door marker on Ghorak Manor's balcony makes PC stuck
+    Bug #1633: Loaddoor to Sadrith Mora, Telvanni Council House spawns PC in the air
+    Bug #1655: Use Appropriate Application Icons on Windows
+    Bug #1679: Tribunal expansion, Meryn Othralas the backstage manager in the theatre group in Mournhold in the great bazaar district is floating a good feet above the ground.
+    Bug #1705: Rain is broken in third person
+    Bug #1706: Thunder and lighting still occurs while the game is paused during the rain
+    Bug #1708: No long jumping
+    Bug #1710: Editor: ReferenceableID drag to references record filter field creates incorrect filter
+    Bug #1712: Rest on Water
+    Bug #1715: "Cancel" button is not always on the same side of menu
+    Bug #1725: Editor: content file can be opened multiple times from the same dialogue
+    Bug #1730: [MOD: Less Generic Nerevarine] Compile failure attempting to enter the Corprusarium.
+    Bug #1733: Unhandled ffmpeg sample formats
+    Bug #1735: Editor: "Edit Record" context menu button not opening subview for journal infos
+    Bug #1750: Editor: record edits result in duplicate entries
+    Bug #1789: Editor: Some characters cannot be used in addon name
+    Bug #1803: Resizing the map does not keep the pre-resize center at the post-resize center
+    Bug #1821: Recovering Cloudcleaver quest: attacking Sosia is considered a crime when you side with Hlormar
+    Bug #1838: Editor: Preferences window appears off screen
+    Bug #1839: Editor: Record filter title should be moved two pixels to the right
+    Bug #1849: Subrecord error in MAO_Containers
+    Bug #1854: Knocked-out actors don't fully act knocked out
+    Bug #1855: "Soul trapped" sound doesn't play
+    Bug #1857: Missing sound effect for enchanted items with empty charge
+    Bug #1859: Missing console command: ResetActors (RA)
+    Bug #1861: Vendor category "MagicItems" is unhandled
+    Bug #1862: Launcher doesn't start if a file listed in launcher.cfg has correct name but wrong capitalization
+    Bug #1864: Editor: Region field for cell record in dialogue subview not working
+    Bug #1869: Editor: Change label "Musics" to "Music"
+    Bug #1870: Goblins killed while knocked down remain in knockdown-pose
+    Bug #1874: CellChanged events should not trigger when crossing exterior cell border
+    Bug #1877: Spriggans killed instantly if hit while regening
+    Bug #1878: Magic Menu text not un-highlighting correctly when going from spell to item as active magic
+    Bug #1881: Stuck in ceiling when entering castle karstaags tower
+    Bug #1884: Unlit torches still produce a burning sound
+    Bug #1885: Can type text in price field in barter window
+    Bug #1887: Equipped items do not emit sounds
+    Bug #1889: draugr lord aesliip will attack you and remain non-hostile
+    Bug #1892: Guard asks player to pay bounty of 0 gold
+    Bug #1895: getdistance should only return max float if ref and target are in different worldspaces
+    Bug #1896: Crash Report
+    Bug #1897: Conjured Equipment cant be re-equipped if removed
+    Bug #1898: Only Gidar Verothan follows you during establish the mine quest
+    Bug #1900: Black screen when you open the door and breath underwater
+    Bug #1904: Crash on casting recall spell
+    Bug #1906: Bound item checks should use the GMSTs
+    Bug #1907: Bugged door. Mournhold, The Winged Guar
+    Bug #1908: Crime reported for attacking Drathas Nerus's henchmen while they attack Dilborn
+    Bug #1909: Weird Quest Flow Infidelities quest
+    Bug #1910: Follower fighting with gone npc
+    Bug #1911: Npcs will drown themselves
+    Bug #1912: World map arrow stays static when inside a building
+    Bug #1920: Ulyne Henim disappears when game is loaded inside Vas
+    Bug #1922: alchemy-> potion of paralyze
+    Bug #1923: "levitation magic cannot be used here" shows outside of tribunal
+    Bug #1927: AI prefer melee over magic.
+    Bug #1929: Tamriel Rebuilt: Named cells that lie within the overlap with Morrowind.esm are not shown
+    Bug #1932: BTB - Spells 14.1 magic effects don´t overwrite the Vanilla ones but are added
+    Bug #1935: Stacks of items are worth more when sold individually
+    Bug #1940: Launcher does not list addon files if base game file is renamed to a different case
+    Bug #1946: Mod "Tel Nechim - moved" breaks savegames
+    Bug #1947: Buying/Selling price doesn't properly affect the growth of mercantile skill
+    Bug #1950: followers from east empire company quest will fight each other if combat happens with anything
+    Bug #1958: Journal can be scrolled indefinitely with a mouse wheel
+    Bug #1959: Follower not leaving party on quest end
+    Bug #1960: Key bindings not always saved correctly
+    Bug #1961: Spell merchants selling racial bonus spells
+    Bug #1967: segmentation fault on load saves
+    Bug #1968: Jump sounds are not controlled by footsteps slider, sound weird compared to footsteps
+    Bug #1970: PC suffers silently when taking damage from lava
+    Bug #1971: Dwarven Sceptre collision area is not removed after killing one
+    Bug #1974: Dalin/Daris Norvayne follows player indefinitely
+    Bug #1975: East Empire Company faction rank breaks during Raven Rock questline
+    Bug #1979: 0 strength = permanently over encumbered
+    Bug #1993: Shrine blessing in Maar Gan doesn't work
+    Bug #2008: Enchanted items do not recharge
+    Bug #2011: Editor: OpenCS script compiler doesn't handle member variable access properly
+    Bug #2016: Dagoth Ur already dead in Facility Cavern
+    Bug #2017: Fighters Guild Quest: The Code Book - dialogue loop when UMP is loaded.
+    Bug #2019: Animation of 'Correct UV Mudcrabs' broken
+    Bug #2022: Alchemy window - Removing ingredient doesn't remove the number of ingredients
+    Bug #2025: Missing mouse-over text for non affordable items
+    Bug #2028: [MOD: Tamriel Rebuilt] Crashing when trying to enter interior cell "Ruinous Keep, Great Hall"
+    Bug #2029: Ienith Brothers Thiev's Guild quest journal entry not adding
+    Feature #471: Editor: Special case implementation for top-level window with single sub-window
+    Feature #472: Editor: Sub-Window re-use settings
+    Feature #704: Font colors import from fallback settings
+    Feature #879: Editor: Open sub-views in a new top-level window
+    Feature #932: Editor: magic effect table
+    Feature #937: Editor: Path Grid table
+    Feature #938: Editor: Sound Gen table
+    Feature #1117: Death and LevelUp music
+    Feature #1226: Editor: Request UniversalId editing from table columns
+    Feature #1545: Targeting console on player
+    Feature #1597: Editor: Render terrain
+    Feature #1695: Editor: add column for CellRef's global variable
+    Feature #1696: Editor: use ESM::Cell's RefNum counter
+    Feature #1697: Redden player's vision when hit
+    Feature #1856: Spellcasting for non-biped creatures
+    Feature #1879: Editor: Run OpenMW with the currently edited content list
+    Task #1851: Move AI temporary state out of AI packages
+    Task #1865: Replace char type in records
 
 0.32.0
-
-Bug #1132: Unable to jump when facing a wall
-Bug #1341: Summoned Creatures do not immediately disappear when killed.
-Bug #1430: CharGen Revamped script does not compile
-Bug #1451: NPCs shouldn't equip weapons prior to fighting
-Bug #1461: Stopped start scripts do not restart on load
-Bug #1473: Dead NPC standing and in 2 pieces
-Bug #1482: Abilities are depleted when interrupted during casting
-Bug #1503: Behaviour of NPCs facing the player
-Bug #1506: Missing character, French edition: three-points
-Bug #1528: Inventory very slow after 2 hours
-Bug #1540: Extra arguments should be ignored for script functions
-Bug #1541: Helseth's Champion: Tribunal
-Bug #1570: Journal cannot be opened while in inventory screen
-Bug #1573: PC joins factions at random
-Bug #1576: NPCs aren't switching their weapons when out of ammo
-Bug #1579: Guards detect creatures in far distance, instead on sight
-Bug #1588: The Siege of the Skaal Village: bloodmoon
-Bug #1593: The script compiler isn't recognising some names that contain a -
-Bug #1606: Books: Question marks instead of quotation marks
-Bug #1608: Dead bodies prevent door from opening/closing.
-Bug #1609: Imperial guards in Sadrith Mora are not using their spears
-Bug #1610: The bounty number is not displayed properly with high numbers
-Bug #1620: Implement correct formula for auto-calculated NPC spells
-Bug #1630: Boats standing vertically in Vivec
-Bug #1635: Arrest dialogue is executed second time after I select "Go to jail"
-Bug #1637: Weird NPC behaviour in Vivec, Hlaalu Ancestral Vaults?
-Bug #1641: Persuasion dialog remains after loading, possibly resulting in crash
-Bug #1644: "Goodbye" and similar options on dialogues prevents escape working properly.
-Bug #1646: PC skill stats are not updated immediately when changing equipment
-Bug #1652: Non-aggressive creature
-Bug #1653: Quickloading while the container window is open crashes the game
-Bug #1654: Priority of checks in organic containers
-Bug #1656: Inventory items merge issue when repairing
-Bug #1657: Attacked state of NPCs is not saved properly
-Bug #1660: Rank dialogue condition ignored
-Bug #1668: Game starts on day 2 instead of day 1
-Bug #1669: Critical Strikes while fighting a target who is currently fighting me
-Bug #1672: OpenCS doesn't save the projects
-Bug #1673: Fatigue decreasing by only one point when running
-Bug #1675: Minimap and localmap graphic glitches
-Bug #1676: Pressing the OK button on the travel menu cancels the travel and exits the menu
-Bug #1677: Sleeping in a rented bed is considered a crime
-Bug #1685: NPCs turn towards player even if invisible/sneaking
-Bug #1686: UI bug: cursor is clicking "world/local" map button while inventory window is closed?
-Bug #1690: Double clicking on a inventory window header doesn't close it.
-Bug #1693: Spell Absorption does not absorb shrine blessings
-Bug #1694: journal displays learned topics as quests
-Bug #1700: Sideways scroll of text boxes
-Bug #1701: Player enchanting requires player hold money, always 100% sucessful.
-Bug #1704: self-made Fortify Intelligence/Drain willpower potions are broken
-Bug #1707: Pausing the game through the esc menu will silence rain, pausing it by opening the inventory will not.
-Bug #1709: Remesa Othril is hostile to Hlaalu members
-Bug #1713: Crash on load after death
-Bug #1719: Blind effect has slight border at the edge of the screen where it is ineffective.
-Bug #1722: Crash after creating enchanted item, reloading saved game
-Bug #1723: Content refs that are stacked share the same index after unstacking
-Bug #1726: Can't finish Aengoth the Jeweler's quest : Retrieve the Scrap Metal
-Bug #1727: Targets almost always resist soultrap scrolls
-Bug #1728: Casting a soultrap spell on invalid target yields no message
-Bug #1729: Chop attack doesn't work if walking diagonally
-Bug #1732: Error handling for missing script function arguments produces weird message
-Bug #1736: Alt-tabbing removes detail from overworld map.
-Bug #1737: Going through doors with (high magnitude?) leviation will put the player high up, possibly even out of bounds.
-Bug #1739: Setting a variable on an NPC from another NPC's dialogue result sets the wrong variable
-Bug #1741: The wait dialogue doesn't black the screen out properly during waiting.
-Bug #1742: ERROR: Object 'sDifficulty' not found (const)
-Bug #1744: Night sky in Skies V.IV (& possibly v3) by SWG rendered incorrectly
-Bug #1746: Bow/marksman weapon condition does not degrade with use
-Bug #1749: Constant Battle Music
-Bug #1752: Alt-Tabbing in the character menus makes the paper doll disappear temporarily
-Bug #1753: Cost of training is not added to merchant's inventory
-Bug #1755: Disposition changes do not persist if the conversation menu is closed by purchasing training.
-Bug #1756: Caught Blight after being cured of Corprus
-Bug #1758: Crash Upon Loading New Cell
-Bug #1760: Player's Magicka is not recalculated upon drained or boosted intelligence
-Bug #1761: Equiped torches lost on reload
-Bug #1762: Your spell did not get a target. Soul trap. Gorenea Andrano
-Bug #1763: Custom Spell Magicka Cost
-Bug #1765: Azuras Star breaks on recharging item
-Bug #1767: GetPCRank did not handle ignored explicit references
-Bug #1772: Dark Brotherhood Assassins never use their Carved Ebony Dart, sticking to their melee weapon.
-Bug #1774: String table overflow also occurs when loading TheGloryRoad.esm
-Bug #1776: dagoth uthol runs in slow motion
-Bug #1778: Incorrect values in spellmaking window
-Bug #1779: Icon of Master Propylon Index is not visible
-Bug #1783: Invisible NPC after looting corpse
-Bug #1787: Health Calculation
-Bug #1788: Skeletons, ghosts etc block doors when we try to open
-Bug #1791: [MOD: LGNPC Foreign Quarter] NPC in completely the wrong place.
-Bug #1792: Potions should show more effects
-Bug #1793: Encumbrance while bartering
-Bug #1794: Fortify attribute not affecting fatigue
-Bug #1795: Too much magicka
-Bug #1796: "Off by default" torch burning
-Bug #1797: Fish too slow
-Bug #1798: Rest until healed shouldn't show with full health and magicka
-Bug #1802: Mark location moved
-Bug #1804: stutter with recent builds
-Bug #1810: attack gothens dremora doesnt agro the others.
-Bug #1811: Regression: Crash Upon Loading New Cell
-Bug #1812: Mod: "QuickChar" weird button placement
-Bug #1815: Keys show value and weight, Vanilla Morrowind's keys dont.
-Bug #1817: Persuasion results do not show using unpatched MW ESM
-Bug #1818: Quest B3_ZainabBride moves to stage 47 upon loading save while Falura Llervu is following
-Bug #1823: AI response to theft incorrect - only guards react, in vanilla everyone does.
-Bug #1829: On-Target Spells Rendered Behind Water Surface Effects
-Bug #1830: Galsa Gindu's house is on fire
-Bug #1832: Fatal Error: OGRE Exception(2:InvalidParametersException)
-Bug #1836: Attacked Guards open "fine/jail/resist"-dialogue after killing you
-Bug #1840: Infinite recursion in ActionTeleport
-Bug #1843: Escorted people change into player's cell after completion of escort stage
-Bug #1845: Typing 'j' into 'Name' fields opens the journal
-Bug #1846: Text pasted into the console still appears twice (Windows)
-Bug #1847: "setfatigue 0" doesn't render NPC unconscious
-Bug #1848: I can talk to unconscious actors
-Bug #1866: Crash when player gets killed by a creature summoned by him
-Bug #1868: Memory leaking when openmw window is minimized
-Feature #47: Magic Effects
-Feature #642: Control NPC mouth movement using current Say sound
-Feature #939: Editor: Resources tables
-Feature #961: AI Combat for magic (spells, potions and enchanted items)
-Feature #1111: Collision script instructions (used e.g. by Lava)
-Feature #1120: Command creature/humanoid magic effects
-Feature #1121: Elemental shield magic effects
-Feature #1122: Light magic effect
-Feature #1139: AI: Friendly hits
-Feature #1141: AI: combat party
-Feature #1326: Editor: Add tooltips to all graphical buttons
-Feature #1489: Magic effect Get/Mod/Set functions
-Feature #1505: Difficulty slider
-Feature #1538: Targeted scripts
-Feature #1571: Allow creating custom markers on the local map
-Feature #1615: Determine local variables from compiled scripts instead of the values in the script record
-Feature #1616: Editor: Body part record verifier
-Feature #1651: Editor: Improved keyboard navigation for scene toolbar
-Feature #1666: Script blacklisting
-Feature #1711: Including the Git revision number from the command line "--version" switch.
-Feature #1721: NPC eye blinking
-Feature #1740: Scene toolbar buttons for selecting which type of elements are rendered
-Feature #1790: Mouse wheel scrolling for the journal
-Feature #1850: NiBSPArrayController
-Task #768: On windows, settings folder should be "OpenMW", not "openmw"
-Task #908: Share keyframe data
-Task #1716: Remove defunct option for building without FFmpeg
+------
+
+    Bug #1132: Unable to jump when facing a wall
+    Bug #1341: Summoned Creatures do not immediately disappear when killed.
+    Bug #1430: CharGen Revamped script does not compile
+    Bug #1451: NPCs shouldn't equip weapons prior to fighting
+    Bug #1461: Stopped start scripts do not restart on load
+    Bug #1473: Dead NPC standing and in 2 pieces
+    Bug #1482: Abilities are depleted when interrupted during casting
+    Bug #1503: Behaviour of NPCs facing the player
+    Bug #1506: Missing character, French edition: three-points
+    Bug #1528: Inventory very slow after 2 hours
+    Bug #1540: Extra arguments should be ignored for script functions
+    Bug #1541: Helseth's Champion: Tribunal
+    Bug #1570: Journal cannot be opened while in inventory screen
+    Bug #1573: PC joins factions at random
+    Bug #1576: NPCs aren't switching their weapons when out of ammo
+    Bug #1579: Guards detect creatures in far distance, instead on sight
+    Bug #1588: The Siege of the Skaal Village: bloodmoon
+    Bug #1593: The script compiler isn't recognising some names that contain a -
+    Bug #1606: Books: Question marks instead of quotation marks
+    Bug #1608: Dead bodies prevent door from opening/closing.
+    Bug #1609: Imperial guards in Sadrith Mora are not using their spears
+    Bug #1610: The bounty number is not displayed properly with high numbers
+    Bug #1620: Implement correct formula for auto-calculated NPC spells
+    Bug #1630: Boats standing vertically in Vivec
+    Bug #1635: Arrest dialogue is executed second time after I select "Go to jail"
+    Bug #1637: Weird NPC behaviour in Vivec, Hlaalu Ancestral Vaults?
+    Bug #1641: Persuasion dialog remains after loading, possibly resulting in crash
+    Bug #1644: "Goodbye" and similar options on dialogues prevents escape working properly.
+    Bug #1646: PC skill stats are not updated immediately when changing equipment
+    Bug #1652: Non-aggressive creature
+    Bug #1653: Quickloading while the container window is open crashes the game
+    Bug #1654: Priority of checks in organic containers
+    Bug #1656: Inventory items merge issue when repairing
+    Bug #1657: Attacked state of NPCs is not saved properly
+    Bug #1660: Rank dialogue condition ignored
+    Bug #1668: Game starts on day 2 instead of day 1
+    Bug #1669: Critical Strikes while fighting a target who is currently fighting me
+    Bug #1672: OpenCS doesn't save the projects
+    Bug #1673: Fatigue decreasing by only one point when running
+    Bug #1675: Minimap and localmap graphic glitches
+    Bug #1676: Pressing the OK button on the travel menu cancels the travel and exits the menu
+    Bug #1677: Sleeping in a rented bed is considered a crime
+    Bug #1685: NPCs turn towards player even if invisible/sneaking
+    Bug #1686: UI bug: cursor is clicking "world/local" map button while inventory window is closed?
+    Bug #1690: Double clicking on a inventory window header doesn't close it.
+    Bug #1693: Spell Absorption does not absorb shrine blessings
+    Bug #1694: journal displays learned topics as quests
+    Bug #1700: Sideways scroll of text boxes
+    Bug #1701: Player enchanting requires player hold money, always 100% sucessful.
+    Bug #1704: self-made Fortify Intelligence/Drain willpower potions are broken
+    Bug #1707: Pausing the game through the esc menu will silence rain, pausing it by opening the inventory will not.
+    Bug #1709: Remesa Othril is hostile to Hlaalu members
+    Bug #1713: Crash on load after death
+    Bug #1719: Blind effect has slight border at the edge of the screen where it is ineffective.
+    Bug #1722: Crash after creating enchanted item, reloading saved game
+    Bug #1723: Content refs that are stacked share the same index after unstacking
+    Bug #1726: Can't finish Aengoth the Jeweler's quest : Retrieve the Scrap Metal
+    Bug #1727: Targets almost always resist soultrap scrolls
+    Bug #1728: Casting a soultrap spell on invalid target yields no message
+    Bug #1729: Chop attack doesn't work if walking diagonally
+    Bug #1732: Error handling for missing script function arguments produces weird message
+    Bug #1736: Alt-tabbing removes detail from overworld map.
+    Bug #1737: Going through doors with (high magnitude?) leviation will put the player high up, possibly even out of bounds.
+    Bug #1739: Setting a variable on an NPC from another NPC's dialogue result sets the wrong variable
+    Bug #1741: The wait dialogue doesn't black the screen out properly during waiting.
+    Bug #1742: ERROR: Object 'sDifficulty' not found (const)
+    Bug #1744: Night sky in Skies V.IV (& possibly v3) by SWG rendered incorrectly
+    Bug #1746: Bow/marksman weapon condition does not degrade with use
+    Bug #1749: Constant Battle Music
+    Bug #1752: Alt-Tabbing in the character menus makes the paper doll disappear temporarily
+    Bug #1753: Cost of training is not added to merchant's inventory
+    Bug #1755: Disposition changes do not persist if the conversation menu is closed by purchasing training.
+    Bug #1756: Caught Blight after being cured of Corprus
+    Bug #1758: Crash Upon Loading New Cell
+    Bug #1760: Player's Magicka is not recalculated upon drained or boosted intelligence
+    Bug #1761: Equiped torches lost on reload
+    Bug #1762: Your spell did not get a target. Soul trap. Gorenea Andrano
+    Bug #1763: Custom Spell Magicka Cost
+    Bug #1765: Azuras Star breaks on recharging item
+    Bug #1767: GetPCRank did not handle ignored explicit references
+    Bug #1772: Dark Brotherhood Assassins never use their Carved Ebony Dart, sticking to their melee weapon.
+    Bug #1774: String table overflow also occurs when loading TheGloryRoad.esm
+    Bug #1776: dagoth uthol runs in slow motion
+    Bug #1778: Incorrect values in spellmaking window
+    Bug #1779: Icon of Master Propylon Index is not visible
+    Bug #1783: Invisible NPC after looting corpse
+    Bug #1787: Health Calculation
+    Bug #1788: Skeletons, ghosts etc block doors when we try to open
+    Bug #1791: [MOD: LGNPC Foreign Quarter] NPC in completely the wrong place.
+    Bug #1792: Potions should show more effects
+    Bug #1793: Encumbrance while bartering
+    Bug #1794: Fortify attribute not affecting fatigue
+    Bug #1795: Too much magicka
+    Bug #1796: "Off by default" torch burning
+    Bug #1797: Fish too slow
+    Bug #1798: Rest until healed shouldn't show with full health and magicka
+    Bug #1802: Mark location moved
+    Bug #1804: stutter with recent builds
+    Bug #1810: attack gothens dremora doesnt agro the others.
+    Bug #1811: Regression: Crash Upon Loading New Cell
+    Bug #1812: Mod: "QuickChar" weird button placement
+    Bug #1815: Keys show value and weight, Vanilla Morrowind's keys dont.
+    Bug #1817: Persuasion results do not show using unpatched MW ESM
+    Bug #1818: Quest B3_ZainabBride moves to stage 47 upon loading save while Falura Llervu is following
+    Bug #1823: AI response to theft incorrect - only guards react, in vanilla everyone does.
+    Bug #1829: On-Target Spells Rendered Behind Water Surface Effects
+    Bug #1830: Galsa Gindu's house is on fire
+    Bug #1832: Fatal Error: OGRE Exception(2:InvalidParametersException)
+    Bug #1836: Attacked Guards open "fine/jail/resist"-dialogue after killing you
+    Bug #1840: Infinite recursion in ActionTeleport
+    Bug #1843: Escorted people change into player's cell after completion of escort stage
+    Bug #1845: Typing 'j' into 'Name' fields opens the journal
+    Bug #1846: Text pasted into the console still appears twice (Windows)
+    Bug #1847: "setfatigue 0" doesn't render NPC unconscious
+    Bug #1848: I can talk to unconscious actors
+    Bug #1866: Crash when player gets killed by a creature summoned by him
+    Bug #1868: Memory leaking when openmw window is minimized
+    Feature #47: Magic Effects
+    Feature #642: Control NPC mouth movement using current Say sound
+    Feature #939: Editor: Resources tables
+    Feature #961: AI Combat for magic (spells, potions and enchanted items)
+    Feature #1111: Collision script instructions (used e.g. by Lava)
+    Feature #1120: Command creature/humanoid magic effects
+    Feature #1121: Elemental shield magic effects
+    Feature #1122: Light magic effect
+    Feature #1139: AI: Friendly hits
+    Feature #1141: AI: combat party
+    Feature #1326: Editor: Add tooltips to all graphical buttons
+    Feature #1489: Magic effect Get/Mod/Set functions
+    Feature #1505: Difficulty slider
+    Feature #1538: Targeted scripts
+    Feature #1571: Allow creating custom markers on the local map
+    Feature #1615: Determine local variables from compiled scripts instead of the values in the script record
+    Feature #1616: Editor: Body part record verifier
+    Feature #1651: Editor: Improved keyboard navigation for scene toolbar
+    Feature #1666: Script blacklisting
+    Feature #1711: Including the Git revision number from the command line "--version" switch.
+    Feature #1721: NPC eye blinking
+    Feature #1740: Scene toolbar buttons for selecting which type of elements are rendered
+    Feature #1790: Mouse wheel scrolling for the journal
+    Feature #1850: NiBSPArrayController
+    Task #768: On windows, settings folder should be "OpenMW", not "openmw"
+    Task #908: Share keyframe data
+    Task #1716: Remove defunct option for building without FFmpeg
 
 0.31.0
-
-Bug #245: Cloud direction and weather systems differ from Morrowind
-Bug #275: Local Map does not always show objects that span multiple cells
-Bug #538: Update CenterOnCell (COC) function behavior
-Bug #618: Local and World Map Textures are sometimes Black
-Bug #640: Water behaviour at night
-Bug #668: OpenMW doesn't support non-latin paths on Windows
-Bug #746: OpenMW doesn't check if the background music was already played
-Bug #747: Door is stuck if cell is left before animation finishes
-Bug #772: Disabled statics are visible on map
-Bug #829: OpenMW uses up all available vram, when playing for extended time
-Bug #869: Dead bodies don't collide with anything
-Bug #894: Various character creation issues
-Bug #897/#1369: opencs Segmentation Fault after "new" or "load"
-Bug #899: Various jumping issues
-Bug #952: Reflection effects are one frame delayed
-Bug #993: Able to interact with world during Wait/Rest dialog
-Bug #995: Dropped items can be placed inside the wall
-Bug #1008: Corpses always face up upon reentering the cell
-Bug #1035: Random colour patterns appearing in automap
-Bug #1037: Footstep volume issues
-Bug #1047: Creation of wrong links in dialogue window
-Bug #1129: Summoned creature time life duration seems infinite
-Bug #1134: Crimes can be committed against hostile NPCs
-Bug #1136: Creature run speed formula is incorrect
-Bug #1150: Weakness to Fire doesn't apply to Fire Damage in the same spell
-Bug #1155: NPCs killing each other
-Bug #1166: Bittercup script still does not work
-Bug #1178: .bsa file names are case sensitive.
-Bug #1179: Crash after trying to load game after being killed
-Bug #1180: Changing footstep sound location
-Bug #1196: Jumping not disabled when showing messageboxes
-Bug #1202: "strange" keys are not shown in binding menu, and are not saved either, but works
-Bug #1216: Broken dialog topics in russian Morrowind
-Bug #1217: Container content changes based on the current position of the mouse
-Bug #1234: Loading/saving issues with dynamic records
-Bug #1277: Text pasted into the console appears twice
-Bug #1284: Crash on New Game
-Bug #1303: It's possible to skip the chargen
-Bug #1304: Slaughterfish should not detect the player unless the player is in the water
-Bug #1311: Editor: deleting Record Filter line does not reset the filter
-Bug #1324: ERROR: ESM Error: String table overflow when loading Animated Morrowind.esp
-Bug #1328: Editor: Bogus Filter created when dragging multiple records to filter bar of non-applicable table
-Bug #1331: Walking/running sound persist after killing NPC`s that are walking/running.
-Bug #1334: Previously equipped items not shown as unequipped after attempting to sell them.
-Bug #1335: Actors ignore vertical axis when deciding to attack
-Bug #1338: Unknown toggle option for shadows
-Bug #1339: "Ashlands Region" is visible when beginning new game during "Loading Area" process
-Bug #1340: Guards prompt Player with punishment options after resisting arrest with another guard.
-Bug #1348: Regression: Bug #1098 has returned with a vengeance
-Bug #1349: [TR] TR_Data mesh tr_ex_imp_gatejamb01 cannot be activated
-Bug #1352: Disabling an ESX file does not disable dependent ESX files
-Bug #1355: CppCat Checks OpenMW
-Bug #1356: Incorrect voice type filtering for sleep interrupts
-Bug #1357: Restarting the game clears saves
-Bug #1360: Seyda Neen silk rider dialog problem
-Bug #1361: Some lights don't work
-Bug #1364: It is difficult to bind "Mouse 1" to an action in the options menu
-Bug #1370: Animation compilation mod does not work properly
-Bug #1371: SL_Pick01.nif from third party fails to load in openmw, but works in Vanilla
-Bug #1373: When stealing in front of Sellus Gravius cannot exit the dialog
-Bug #1378: Installs to /usr/local are not working
-Bug #1380: Loading a save file fail if one of the content files is disabled
-Bug #1382: "getHExact() size mismatch" crash on loading official plugin "Siege at Firemoth.esp"
-Bug #1386: Arkngthand door will not open
-Bug #1388: Segfault when modifying View Distance in Menu options
-Bug #1389: Crash when loading a save after dying
-Bug #1390: Apostrophe characters not displayed [French version]
-Bug #1391: Custom made icon background texture for magical weapons and stuff isn't scaled properly on GUI.
-Bug #1393: Coin icon during the level up dialogue are off of the background
-Bug #1394: Alt+F4 doesn't work on Win version
-Bug #1395: Changing rings switches only the last one put on
-Bug #1396: Pauldron parts aren't showing when the robe is equipped
-Bug #1402: Dialogue of some shrines have wrong button orientation
-Bug #1403: Items are floating in the air when they're dropped onto dead bodies.
-Bug #1404: Forearms are not rendered on Argonian females
-Bug #1407: Alchemy allows making potions from two of the same item
-Bug #1408: "Max sale" button gives you all the items AND all the trader's gold
-Bug #1409: Rest "Until Healed" broken for characters with stunted magicka.
-Bug #1412: Empty travel window opens while playing through start game
-Bug #1413: Save game ignores missing writing permission
-Bug #1414: The Underground 2 ESM Error
-Bug #1416: Not all splash screens in the Splash directory are used
-Bug #1417: Loading saved game does not terminate
-Bug #1419: Skyrim: Home of the Nords error
-Bug #1422: ClearInfoActor
-Bug #1423: ForceGreeting closes existing dialogue windows
-Bug #1425: Cannot load save game
-Bug #1426: Read skill books aren't stored in savegame
-Bug #1427: Useless items can be set under hotkeys
-Bug #1429: Text variables in journal
-Bug #1432: When attacking friendly NPC, the crime is reported and bounty is raised after each swing
-Bug #1435: Stealing priceless items is without punishment
-Bug #1437: Door marker at Jobasha's Rare Books is spawning PC in the air
-Bug #1440: Topic selection menu should be wider
-Bug #1441: Dropping items on the rug makes them inaccessible
-Bug #1442: When dropping and taking some looted items, bystanders consider that as a crime
-Bug #1444: Arrows and bolts are not dropped where the cursor points
-Bug #1445: Security trainers offering acrobatics instead
-Bug #1447: Character dash not displayed, French edition
-Bug #1448: When the player is killed by the guard while having a bounty on his head, the guard dialogue opens over and over instead of loading dialogue
-Bug #1454: Script error in SkipTutorial
-Bug #1456: Bad lighting when using certain Morrowind.ini generated by MGE
-Bug #1457: Heart of Lorkan comes after you when attacking it
-Bug #1458: Modified Keybindings are not remembered
-Bug #1459: Dura Gra-Bol doesn't respond to PC attack
-Bug #1462: Interior cells not loaded with Morrowind Patch active
-Bug #1469: Item tooltip should show the base value, not real value
-Bug #1477: Death count is not stored in savegame
-Bug #1478: AiActivate does not trigger activate scripts
-Bug #1481: Weapon not rendered when partially submerged in water
-Bug #1483: Enemies are attacking even while dying
-Bug #1486: ESM Error: Don't know what to do with INFO
-Bug #1490: Arrows shot at PC can end up in inventory
-Bug #1492: Monsters respawn on top of one another
-Bug #1493: Dialogue box opens with follower NPC even if NPC is dead
-Bug #1494: Paralysed cliffracers remain airbourne
-Bug #1495: Dialogue box opens with follower NPC even the game is paused
-Bug #1496: GUI messages are not cleared when loading another saved game
-Bug #1499: Underwater sound sometimes plays when transitioning from interior.
-Bug #1500: Targetted spells and water.
-Bug #1502: Console error message on info refusal
-Bug #1507: Bloodmoon MQ The Ritual of Beasts: Can't remove the arrow
-Bug #1508: Bloodmoon: Fort Frostmoth, cant talk with Carnius Magius
-Bug #1516: PositionCell doesn't move actors to current cell
-Bug #1518: ForceGreeting broken for explicit references
-Bug #1522: Crash after attempting to play non-music file
-Bug #1523: World map empty after loading interior save
-Bug #1524: Arrows in waiting/resting dialog act like minimum and maximum buttons
-Bug #1525: Werewolf: Killed NPC's don't fill werewolfs hunger for blood
-Bug #1527: Werewolf: Detect life detects wrong type of actor
-Bug #1529: OpenMW crash during "the shrine of the dead" mission (tribunal)
-Bug #1530: Selected text in the console has the same color as the background
-Bug #1539: Barilzar's Mazed Band: Tribunal
-Bug #1542: Looping taunts from NPC`s after death: Tribunal
-Bug #1543: OpenCS crash when using drag&drop in script editor
-Bug #1547: Bamz-Amschend: Centurion Archers combat problem
-Bug #1548: The Missing Hand: Tribunal
-Bug #1549: The Mad God: Tribunal, Dome of Serlyn
-Bug #1557: A bounty is calculated from actual item cost
-Bug #1562: Invisible terrain on top of Red Mountain
-Bug #1564: Cave of the hidden music: Bloodmoon
-Bug #1567: Editor: Deleting of referenceables does not work
-Bug #1568: Picking up a stack of items and holding the enter key and moving your mouse around paints a bunch of garbage on screen.
-Bug #1574: Solstheim: Drauger cant inflict damage on player
-Bug #1578: Solstheim: Bonewolf running animation not working
-Bug #1585: Particle effects on PC are stopped when paralyzed
-Bug #1589: Tribunal: Crimson Plague quest does not update when Gedna Relvel is killed
-Bug #1590: Failed to save game: compile error
-Bug #1598: Segfault when making Drain/Fortify Skill spells
-Bug #1599: Unable to switch to fullscreen
-Bug #1613: Morrowind Rebirth duplicate objects / vanilla objects not removed
-Bug #1618: Death notice fails to show up
-Bug #1628: Alt+Tab Segfault
-Feature #32: Periodic Cleanup/Refill
-Feature #41: Precipitation and weather particles
-Feature #568: Editor: Configuration setup
-Feature #649: Editor: Threaded loading
-Feature #930: Editor: Cell record saving
-Feature #934: Editor: Body part table
-Feature #935: Editor: Enchantment effect table
-Feature #1162: Dialogue merging
-Feature #1174: Saved Game: add missing creature state
-Feature #1177: Saved Game: fog of war state
-Feature #1312: Editor: Combat/Magic/Stealth values for creatures are not displayed
-Feature #1314: Make NPCs and creatures fight each other
-Feature #1315: Crime: Murder
-Feature #1321: Sneak skill enhancements
-Feature #1323: Handle restocking items
-Feature #1332: Saved Game: levelled creatures
-Feature #1347: modFactionReaction script instruction
-Feature #1362: Animated main menu support
-Feature #1433: Store walk/run toggle
-Feature #1449: Use names instead of numbers for saved game files and folders
-Feature #1453: Adding Delete button to the load menu
-Feature #1460: Enable Journal screen while in dialogue
-Feature #1480: Play Battle music when in combat
-Feature #1501: Followers unable to fast travel with you
-Feature #1520: Disposition and distance-based aggression/ShouldAttack
-Feature #1595: Editor: Object rendering in cells
-Task #940: Move license to locations where applicable
-Task #1333: Remove cmake git tag reading
-Task #1566: Editor: Object rendering refactoring
+------
+
+    Bug #245: Cloud direction and weather systems differ from Morrowind
+    Bug #275: Local Map does not always show objects that span multiple cells
+    Bug #538: Update CenterOnCell (COC) function behavior
+    Bug #618: Local and World Map Textures are sometimes Black
+    Bug #640: Water behaviour at night
+    Bug #668: OpenMW doesn't support non-latin paths on Windows
+    Bug #746: OpenMW doesn't check if the background music was already played
+    Bug #747: Door is stuck if cell is left before animation finishes
+    Bug #772: Disabled statics are visible on map
+    Bug #829: OpenMW uses up all available vram, when playing for extended time
+    Bug #869: Dead bodies don't collide with anything
+    Bug #894: Various character creation issues
+    Bug #897/#1369: opencs Segmentation Fault after "new" or "load"
+    Bug #899: Various jumping issues
+    Bug #952: Reflection effects are one frame delayed
+    Bug #993: Able to interact with world during Wait/Rest dialog
+    Bug #995: Dropped items can be placed inside the wall
+    Bug #1008: Corpses always face up upon reentering the cell
+    Bug #1035: Random colour patterns appearing in automap
+    Bug #1037: Footstep volume issues
+    Bug #1047: Creation of wrong links in dialogue window
+    Bug #1129: Summoned creature time life duration seems infinite
+    Bug #1134: Crimes can be committed against hostile NPCs
+    Bug #1136: Creature run speed formula is incorrect
+    Bug #1150: Weakness to Fire doesn't apply to Fire Damage in the same spell
+    Bug #1155: NPCs killing each other
+    Bug #1166: Bittercup script still does not work
+    Bug #1178: .bsa file names are case sensitive.
+    Bug #1179: Crash after trying to load game after being killed
+    Bug #1180: Changing footstep sound location
+    Bug #1196: Jumping not disabled when showing messageboxes
+    Bug #1202: "strange" keys are not shown in binding menu, and are not saved either, but works
+    Bug #1216: Broken dialog topics in russian Morrowind
+    Bug #1217: Container content changes based on the current position of the mouse
+    Bug #1234: Loading/saving issues with dynamic records
+    Bug #1277: Text pasted into the console appears twice
+    Bug #1284: Crash on New Game
+    Bug #1303: It's possible to skip the chargen
+    Bug #1304: Slaughterfish should not detect the player unless the player is in the water
+    Bug #1311: Editor: deleting Record Filter line does not reset the filter
+    Bug #1324: ERROR: ESM Error: String table overflow when loading Animated Morrowind.esp
+    Bug #1328: Editor: Bogus Filter created when dragging multiple records to filter bar of non-applicable table
+    Bug #1331: Walking/running sound persist after killing NPC`s that are walking/running.
+    Bug #1334: Previously equipped items not shown as unequipped after attempting to sell them.
+    Bug #1335: Actors ignore vertical axis when deciding to attack
+    Bug #1338: Unknown toggle option for shadows
+    Bug #1339: "Ashlands Region" is visible when beginning new game during "Loading Area" process
+    Bug #1340: Guards prompt Player with punishment options after resisting arrest with another guard.
+    Bug #1348: Regression: Bug #1098 has returned with a vengeance
+    Bug #1349: [TR] TR_Data mesh tr_ex_imp_gatejamb01 cannot be activated
+    Bug #1352: Disabling an ESX file does not disable dependent ESX files
+    Bug #1355: CppCat Checks OpenMW
+    Bug #1356: Incorrect voice type filtering for sleep interrupts
+    Bug #1357: Restarting the game clears saves
+    Bug #1360: Seyda Neen silk rider dialog problem
+    Bug #1361: Some lights don't work
+    Bug #1364: It is difficult to bind "Mouse 1" to an action in the options menu
+    Bug #1370: Animation compilation mod does not work properly
+    Bug #1371: SL_Pick01.nif from third party fails to load in openmw, but works in Vanilla
+    Bug #1373: When stealing in front of Sellus Gravius cannot exit the dialog
+    Bug #1378: Installs to /usr/local are not working
+    Bug #1380: Loading a save file fail if one of the content files is disabled
+    Bug #1382: "getHExact() size mismatch" crash on loading official plugin "Siege at Firemoth.esp"
+    Bug #1386: Arkngthand door will not open
+    Bug #1388: Segfault when modifying View Distance in Menu options
+    Bug #1389: Crash when loading a save after dying
+    Bug #1390: Apostrophe characters not displayed [French version]
+    Bug #1391: Custom made icon background texture for magical weapons and stuff isn't scaled properly on GUI.
+    Bug #1393: Coin icon during the level up dialogue are off of the background
+    Bug #1394: Alt+F4 doesn't work on Win version
+    Bug #1395: Changing rings switches only the last one put on
+    Bug #1396: Pauldron parts aren't showing when the robe is equipped
+    Bug #1402: Dialogue of some shrines have wrong button orientation
+    Bug #1403: Items are floating in the air when they're dropped onto dead bodies.
+    Bug #1404: Forearms are not rendered on Argonian females
+    Bug #1407: Alchemy allows making potions from two of the same item
+    Bug #1408: "Max sale" button gives you all the items AND all the trader's gold
+    Bug #1409: Rest "Until Healed" broken for characters with stunted magicka.
+    Bug #1412: Empty travel window opens while playing through start game
+    Bug #1413: Save game ignores missing writing permission
+    Bug #1414: The Underground 2 ESM Error
+    Bug #1416: Not all splash screens in the Splash directory are used
+    Bug #1417: Loading saved game does not terminate
+    Bug #1419: Skyrim: Home of the Nords error
+    Bug #1422: ClearInfoActor
+    Bug #1423: ForceGreeting closes existing dialogue windows
+    Bug #1425: Cannot load save game
+    Bug #1426: Read skill books aren't stored in savegame
+    Bug #1427: Useless items can be set under hotkeys
+    Bug #1429: Text variables in journal
+    Bug #1432: When attacking friendly NPC, the crime is reported and bounty is raised after each swing
+    Bug #1435: Stealing priceless items is without punishment
+    Bug #1437: Door marker at Jobasha's Rare Books is spawning PC in the air
+    Bug #1440: Topic selection menu should be wider
+    Bug #1441: Dropping items on the rug makes them inaccessible
+    Bug #1442: When dropping and taking some looted items, bystanders consider that as a crime
+    Bug #1444: Arrows and bolts are not dropped where the cursor points
+    Bug #1445: Security trainers offering acrobatics instead
+    Bug #1447: Character dash not displayed, French edition
+    Bug #1448: When the player is killed by the guard while having a bounty on his head, the guard dialogue opens over and over instead of loading dialogue
+    Bug #1454: Script error in SkipTutorial
+    Bug #1456: Bad lighting when using certain Morrowind.ini generated by MGE
+    Bug #1457: Heart of Lorkan comes after you when attacking it
+    Bug #1458: Modified Keybindings are not remembered
+    Bug #1459: Dura Gra-Bol doesn't respond to PC attack
+    Bug #1462: Interior cells not loaded with Morrowind Patch active
+    Bug #1469: Item tooltip should show the base value, not real value
+    Bug #1477: Death count is not stored in savegame
+    Bug #1478: AiActivate does not trigger activate scripts
+    Bug #1481: Weapon not rendered when partially submerged in water
+    Bug #1483: Enemies are attacking even while dying
+    Bug #1486: ESM Error: Don't know what to do with INFO
+    Bug #1490: Arrows shot at PC can end up in inventory
+    Bug #1492: Monsters respawn on top of one another
+    Bug #1493: Dialogue box opens with follower NPC even if NPC is dead
+    Bug #1494: Paralysed cliffracers remain airbourne
+    Bug #1495: Dialogue box opens with follower NPC even the game is paused
+    Bug #1496: GUI messages are not cleared when loading another saved game
+    Bug #1499: Underwater sound sometimes plays when transitioning from interior.
+    Bug #1500: Targetted spells and water.
+    Bug #1502: Console error message on info refusal
+    Bug #1507: Bloodmoon MQ The Ritual of Beasts: Can't remove the arrow
+    Bug #1508: Bloodmoon: Fort Frostmoth, cant talk with Carnius Magius
+    Bug #1516: PositionCell doesn't move actors to current cell
+    Bug #1518: ForceGreeting broken for explicit references
+    Bug #1522: Crash after attempting to play non-music file
+    Bug #1523: World map empty after loading interior save
+    Bug #1524: Arrows in waiting/resting dialog act like minimum and maximum buttons
+    Bug #1525: Werewolf: Killed NPC's don't fill werewolfs hunger for blood
+    Bug #1527: Werewolf: Detect life detects wrong type of actor
+    Bug #1529: OpenMW crash during "the shrine of the dead" mission (tribunal)
+    Bug #1530: Selected text in the console has the same color as the background
+    Bug #1539: Barilzar's Mazed Band: Tribunal
+    Bug #1542: Looping taunts from NPC`s after death: Tribunal
+    Bug #1543: OpenCS crash when using drag&drop in script editor
+    Bug #1547: Bamz-Amschend: Centurion Archers combat problem
+    Bug #1548: The Missing Hand: Tribunal
+    Bug #1549: The Mad God: Tribunal, Dome of Serlyn
+    Bug #1557: A bounty is calculated from actual item cost
+    Bug #1562: Invisible terrain on top of Red Mountain
+    Bug #1564: Cave of the hidden music: Bloodmoon
+    Bug #1567: Editor: Deleting of referenceables does not work
+    Bug #1568: Picking up a stack of items and holding the enter key and moving your mouse around paints a bunch of garbage on screen.
+    Bug #1574: Solstheim: Drauger cant inflict damage on player
+    Bug #1578: Solstheim: Bonewolf running animation not working
+    Bug #1585: Particle effects on PC are stopped when paralyzed
+    Bug #1589: Tribunal: Crimson Plague quest does not update when Gedna Relvel is killed
+    Bug #1590: Failed to save game: compile error
+    Bug #1598: Segfault when making Drain/Fortify Skill spells
+    Bug #1599: Unable to switch to fullscreen
+    Bug #1613: Morrowind Rebirth duplicate objects / vanilla objects not removed
+    Bug #1618: Death notice fails to show up
+    Bug #1628: Alt+Tab Segfault
+    Feature #32: Periodic Cleanup/Refill
+    Feature #41: Precipitation and weather particles
+    Feature #568: Editor: Configuration setup
+    Feature #649: Editor: Threaded loading
+    Feature #930: Editor: Cell record saving
+    Feature #934: Editor: Body part table
+    Feature #935: Editor: Enchantment effect table
+    Feature #1162: Dialogue merging
+    Feature #1174: Saved Game: add missing creature state
+    Feature #1177: Saved Game: fog of war state
+    Feature #1312: Editor: Combat/Magic/Stealth values for creatures are not displayed
+    Feature #1314: Make NPCs and creatures fight each other
+    Feature #1315: Crime: Murder
+    Feature #1321: Sneak skill enhancements
+    Feature #1323: Handle restocking items
+    Feature #1332: Saved Game: levelled creatures
+    Feature #1347: modFactionReaction script instruction
+    Feature #1362: Animated main menu support
+    Feature #1433: Store walk/run toggle
+    Feature #1449: Use names instead of numbers for saved game files and folders
+    Feature #1453: Adding Delete button to the load menu
+    Feature #1460: Enable Journal screen while in dialogue
+    Feature #1480: Play Battle music when in combat
+    Feature #1501: Followers unable to fast travel with you
+    Feature #1520: Disposition and distance-based aggression/ShouldAttack
+    Feature #1595: Editor: Object rendering in cells
+    Task #940: Move license to locations where applicable
+    Task #1333: Remove cmake git tag reading
+    Task #1566: Editor: Object rendering refactoring
 
 0.30.0
-
-Bug #416: Extreme shaking can occur during cell transitions while moving
-Bug #1003: Province Cyrodiil: Ogre Exception in Stirk
-Bug #1071: Crash when given a non-existent content file
-Bug #1080: OpenMW allows resting/using a bed while in combat
-Bug #1097: Wrong punishment for stealing in Census and Excise Office at the start of a new game
-Bug #1098: Unlocked evidence chests should get locked after new evidence is put into them
-Bug #1099: NPCs that you attacked still fight you after you went to jail/paid your fine
-Bug #1100: Taking items from a corpse is considered stealing
-Bug #1126: Some creatures can't get close enough to attack
-Bug #1144: Killed creatures seem to die again each time player transitions indoors/outdoors
-Bug #1181: loading a saved game does not reset the player control status
-Bug #1185: Collision issues in Addamasartus
-Bug #1187: Athyn Sarethi mission, rescuing varvur sarethi from the doesnt end the mission
-Bug #1189: Crash when entering interior cell "Gnisis, Arvs-Drelen"
-Bug #1191: Picking up papers without inventory in new game
-Bug #1195: NPCs do not equip torches in certain interiors
-Bug #1197: mouse wheel makes things scroll too fast
-Bug #1200: door blocked by monsters
-Bug #1201: item's magical charges are only refreshed when they are used
-Bug #1203: Scribs do not defend themselves
-Bug #1204: creatures life is not empty when they are dead
-Bug #1205: armor experience does not progress when hits are taken
-Bug #1206: blood particules always red. Undeads and mechanicals should have a different one.
-Bug #1209: Tarhiel never falls
-Bug #1210: journal adding script is ran again after having saved/loaded
-Bug #1224: Names of custom classes are not properly handled in save games
-Bug #1227: Editor: Fixed case handling for broken localised versions of Morrowind.esm
-Bug #1235: Indoors walk stutter
-Bug #1236: Aborting intro movie brings up the menu
-Bug #1239: NPCs get stuck when walking past each other
-Bug #1240: BTB - Settings 14.1 and Health Bar.
-Bug #1241: BTB - Character and Khajiit Prejudice
-Bug #1248: GUI Weapon icon is changed to hand-to-hand after save load
-Bug #1254: Guild ranks do not show in dialogue
-Bug #1255: When opening a container and selecting "Take All", the screen flashes blue
-Bug #1260: Level Up menu doesn't show image when using a custom class
-Bug #1265: Quit Menu Has Misaligned Buttons
-Bug #1270: Active weapon icon is not updated when weapon is repaired
-Bug #1271: NPC Stuck in hovering "Jumping" animation
-Bug #1272: Crash when attempting to load Big City esm file.
-Bug #1276: Editor: Dropping a region into the filter of a cell subview fails
-Bug #1286: Dialogue topic list clips with window frame
-Bug #1291: Saved game: store faction membership
-Bug #1293: Pluginless Khajiit Head Pack by ashiraniir makes OpenMW close.
-Bug #1294: Pasting in console adds text to end, not at cursor
-Bug #1295: Conversation loop when asking about "specific place" in Vivec
-Bug #1296: Caius doesn't leave at start of quest "Mehra Milo and the Lost Prophecies"
-Bug #1297: Saved game: map markers
-Bug #1302: ring_keley script causes vector::_M_range_check exception
-Bug #1309: Bug on "You violated the law" dialog
-Bug #1319: Creatures sometimes rendered incorrectly
-Feature #50: Ranged Combat
-Feature #58: Sneaking Skill
-Feature #73: Crime and Punishment
-Feature #135: Editor: OGRE integration
-Feature #541: Editor: Dialogue Sub-Views
-Feature #853: Editor: Rework User Settings
-Feature #944: Editor: lighting modes
-Feature #945: Editor: Camera navigation mode
-Feature #953: Trader gold
-Feature #1140: AI: summoned creatures
-Feature #1142: AI follow: Run stance
-Feature #1154: Not all NPCs get aggressive when one is attacked
-Feature #1169: Terrain threading
-Feature #1172: Loading screen and progress bars during saved/loading game
-Feature #1173: Saved Game: include weather state
-Feature #1207: Class creation form does not remember
-Feature #1220: Editor: Preview Subview
-Feature #1223: Saved Game: Local Variables
-Feature #1229: Quicksave, quickload, autosave
-Feature #1230: Deleting saves
-Feature #1233: Bribe gold is placed into NPCs inventory
-Feature #1252: Saved Game: quick key bindings
-Feature #1273: Editor: Region Map context menu
-Feature #1274: Editor: Region Map drag & drop
-Feature #1275: Editor: Scene subview drop
-Feature #1282: Non-faction member crime recognition.
-Feature #1289: NPCs return to default position
-Task #941: Remove unused cmake files
+------
+
+    Bug #416: Extreme shaking can occur during cell transitions while moving
+    Bug #1003: Province Cyrodiil: Ogre Exception in Stirk
+    Bug #1071: Crash when given a non-existent content file
+    Bug #1080: OpenMW allows resting/using a bed while in combat
+    Bug #1097: Wrong punishment for stealing in Census and Excise Office at the start of a new game
+    Bug #1098: Unlocked evidence chests should get locked after new evidence is put into them
+    Bug #1099: NPCs that you attacked still fight you after you went to jail/paid your fine
+    Bug #1100: Taking items from a corpse is considered stealing
+    Bug #1126: Some creatures can't get close enough to attack
+    Bug #1144: Killed creatures seem to die again each time player transitions indoors/outdoors
+    Bug #1181: loading a saved game does not reset the player control status
+    Bug #1185: Collision issues in Addamasartus
+    Bug #1187: Athyn Sarethi mission, rescuing varvur sarethi from the doesnt end the mission
+    Bug #1189: Crash when entering interior cell "Gnisis, Arvs-Drelen"
+    Bug #1191: Picking up papers without inventory in new game
+    Bug #1195: NPCs do not equip torches in certain interiors
+    Bug #1197: mouse wheel makes things scroll too fast
+    Bug #1200: door blocked by monsters
+    Bug #1201: item's magical charges are only refreshed when they are used
+    Bug #1203: Scribs do not defend themselves
+    Bug #1204: creatures life is not empty when they are dead
+    Bug #1205: armor experience does not progress when hits are taken
+    Bug #1206: blood particules always red. Undeads and mechanicals should have a different one.
+    Bug #1209: Tarhiel never falls
+    Bug #1210: journal adding script is ran again after having saved/loaded
+    Bug #1224: Names of custom classes are not properly handled in save games
+    Bug #1227: Editor: Fixed case handling for broken localised versions of Morrowind.esm
+    Bug #1235: Indoors walk stutter
+    Bug #1236: Aborting intro movie brings up the menu
+    Bug #1239: NPCs get stuck when walking past each other
+    Bug #1240: BTB - Settings 14.1 and Health Bar.
+    Bug #1241: BTB - Character and Khajiit Prejudice
+    Bug #1248: GUI Weapon icon is changed to hand-to-hand after save load
+    Bug #1254: Guild ranks do not show in dialogue
+    Bug #1255: When opening a container and selecting "Take All", the screen flashes blue
+    Bug #1260: Level Up menu doesn't show image when using a custom class
+    Bug #1265: Quit Menu Has Misaligned Buttons
+    Bug #1270: Active weapon icon is not updated when weapon is repaired
+    Bug #1271: NPC Stuck in hovering "Jumping" animation
+    Bug #1272: Crash when attempting to load Big City esm file.
+    Bug #1276: Editor: Dropping a region into the filter of a cell subview fails
+    Bug #1286: Dialogue topic list clips with window frame
+    Bug #1291: Saved game: store faction membership
+    Bug #1293: Pluginless Khajiit Head Pack by ashiraniir makes OpenMW close.
+    Bug #1294: Pasting in console adds text to end, not at cursor
+    Bug #1295: Conversation loop when asking about "specific place" in Vivec
+    Bug #1296: Caius doesn't leave at start of quest "Mehra Milo and the Lost Prophecies"
+    Bug #1297: Saved game: map markers
+    Bug #1302: ring_keley script causes vector::_M_range_check exception
+    Bug #1309: Bug on "You violated the law" dialog
+    Bug #1319: Creatures sometimes rendered incorrectly
+    Feature #50: Ranged Combat
+    Feature #58: Sneaking Skill
+    Feature #73: Crime and Punishment
+    Feature #135: Editor: OGRE integration
+    Feature #541: Editor: Dialogue Sub-Views
+    Feature #853: Editor: Rework User Settings
+    Feature #944: Editor: lighting modes
+    Feature #945: Editor: Camera navigation mode
+    Feature #953: Trader gold
+    Feature #1140: AI: summoned creatures
+    Feature #1142: AI follow: Run stance
+    Feature #1154: Not all NPCs get aggressive when one is attacked
+    Feature #1169: Terrain threading
+    Feature #1172: Loading screen and progress bars during saved/loading game
+    Feature #1173: Saved Game: include weather state
+    Feature #1207: Class creation form does not remember
+    Feature #1220: Editor: Preview Subview
+    Feature #1223: Saved Game: Local Variables
+    Feature #1229: Quicksave, quickload, autosave
+    Feature #1230: Deleting saves
+    Feature #1233: Bribe gold is placed into NPCs inventory
+    Feature #1252: Saved Game: quick key bindings
+    Feature #1273: Editor: Region Map context menu
+    Feature #1274: Editor: Region Map drag & drop
+    Feature #1275: Editor: Scene subview drop
+    Feature #1282: Non-faction member crime recognition.
+    Feature #1289: NPCs return to default position
+    Task #941: Remove unused cmake files
 
 0.29.0
-
-Bug #556: Video soundtrack not played when music volume is set to zero
-Bug #829: OpenMW uses up all available vram, when playing for extended time
-Bug #848: Wrong amount of footsteps playing in 1st person
-Bug #888: Ascended Sleepers have movement issues
-Bug #892: Explicit references are allowed on all script functions
-Bug #999: Graphic Herbalism (mod): sometimes doesn't activate properly
-Bug #1009: Lake Fjalding AI related slowdown.
-Bug #1041: Music playback issues on OS X >= 10.9
-Bug #1043: No message box when advancing skill "Speechcraft" while in dialog window
-Bug #1060: Some message boxes are cut off at the bottom
-Bug #1062: Bittercup script does not work ('end' variable)
-Bug #1074: Inventory paperdoll obscures armour rating
-Bug #1077: Message after killing an essential NPC disappears too fast
-Bug #1078: "Clutterbane" shows empty charge bar
-Bug #1083: UndoWerewolf fails
-Bug #1088: Better Clothes Bloodmoon Plus 1.5 by Spirited Treasure pants are not rendered
-Bug #1090: Start scripts fail when going to a non-predefined cell
-Bug #1091: Crash: Assertion `!q.isNaN() && "Invalid orientation supplied as parameter"' failed.
-Bug #1093: Weapons of aggressive NPCs are invisible after you exit and re-enter interior
-Bug #1105: Magicka is depleted when using uncastable spells
-Bug #1106: Creatures should be able to run
-Bug #1107: TR cliffs have way too huge collision boxes in OpenMW
-Bug #1109: Cleaning True Light and Darkness with Tes3cmd makes Addamasartus , Zenarbael and Yasamsi flooded.
-Bug #1114: Bad output for desktop-file-validate on openmw.desktop (and opencs.desktop)
-Bug #1115: Memory leak when spying on Fargoth
-Bug #1137: Script execution fails (drenSlaveOwners script)
-Bug #1143: Mehra Milo quest (vivec informants) is broken
-Bug #1145: Issues with moving gold between inventory and containers
-Bug #1146: Issues with picking up stacks of gold
-Bug #1147: Dwemer Crossbows are held incorrectly
-Bug #1158: Armor rating should always stay below inventory mannequin
-Bug #1159: Quick keys can be set during character generation
-Bug #1160: Crash on equip lockpick when
-Bug #1167: Editor: Referenceables are not correctly loaded when dealing with more than one content file
-Bug #1184: Game Save: overwriting an existing save does not actually overwrites the file
-Feature #30: Loading/Saving (still missing a few parts)
-Feature #101: AI Package: Activate
-Feature #103: AI Package: Follow, FollowCell
-Feature #138: Editor: Drag & Drop
-Feature #428: Player death
-Feature #505: Editor: Record Cloning
-Feature #701: Levelled creatures
-Feature #708: Improved Local Variable handling
-Feature #709: Editor: Script verifier
-Feature #764: Missing journal backend features
-Feature #777: Creature weapons/shields
-Feature #789: Editor: Referenceable record verifier
-Feature #924: Load/Save GUI (still missing loading screen and progress bars)
-Feature #946: Knockdown
-Feature #947: Decrease fatigue when running, swimming and attacking
-Feature #956: Melee Combat: Blocking
-Feature #957: Area magic
-Feature #960: Combat/AI combat for creatures
-Feature #962: Combat-Related AI instructions
-Feature #1075: Damage/Restore skill/attribute magic effects
-Feature #1076: Soultrap magic effect
-Feature #1081: Disease contraction
-Feature #1086: Blood particles
-Feature #1092: Interrupt resting
-Feature #1101: Inventory equip scripts
-Feature #1116: Version/Build number in Launcher window
-Feature #1119: Resistance/weakness to normal weapons magic effect
-Feature #1123: Slow Fall magic effect
-Feature #1130: Auto-calculate spells
-Feature #1164: Editor: Case-insensitive sorting in tables
+------
+
+    Bug #556: Video soundtrack not played when music volume is set to zero
+    Bug #829: OpenMW uses up all available vram, when playing for extended time
+    Bug #848: Wrong amount of footsteps playing in 1st person
+    Bug #888: Ascended Sleepers have movement issues
+    Bug #892: Explicit references are allowed on all script functions
+    Bug #999: Graphic Herbalism (mod): sometimes doesn't activate properly
+    Bug #1009: Lake Fjalding AI related slowdown.
+    Bug #1041: Music playback issues on OS X >= 10.9
+    Bug #1043: No message box when advancing skill "Speechcraft" while in dialog window
+    Bug #1060: Some message boxes are cut off at the bottom
+    Bug #1062: Bittercup script does not work ('end' variable)
+    Bug #1074: Inventory paperdoll obscures armour rating
+    Bug #1077: Message after killing an essential NPC disappears too fast
+    Bug #1078: "Clutterbane" shows empty charge bar
+    Bug #1083: UndoWerewolf fails
+    Bug #1088: Better Clothes Bloodmoon Plus 1.5 by Spirited Treasure pants are not rendered
+    Bug #1090: Start scripts fail when going to a non-predefined cell
+    Bug #1091: Crash: Assertion `!q.isNaN() && "Invalid orientation supplied as parameter"' failed.
+    Bug #1093: Weapons of aggressive NPCs are invisible after you exit and re-enter interior
+    Bug #1105: Magicka is depleted when using uncastable spells
+    Bug #1106: Creatures should be able to run
+    Bug #1107: TR cliffs have way too huge collision boxes in OpenMW
+    Bug #1109: Cleaning True Light and Darkness with Tes3cmd makes Addamasartus , Zenarbael and Yasamsi flooded.
+    Bug #1114: Bad output for desktop-file-validate on openmw.desktop (and opencs.desktop)
+    Bug #1115: Memory leak when spying on Fargoth
+    Bug #1137: Script execution fails (drenSlaveOwners script)
+    Bug #1143: Mehra Milo quest (vivec informants) is broken
+    Bug #1145: Issues with moving gold between inventory and containers
+    Bug #1146: Issues with picking up stacks of gold
+    Bug #1147: Dwemer Crossbows are held incorrectly
+    Bug #1158: Armor rating should always stay below inventory mannequin
+    Bug #1159: Quick keys can be set during character generation
+    Bug #1160: Crash on equip lockpick when
+    Bug #1167: Editor: Referenceables are not correctly loaded when dealing with more than one content file
+    Bug #1184: Game Save: overwriting an existing save does not actually overwrites the file
+    Feature #30: Loading/Saving (still missing a few parts)
+    Feature #101: AI Package: Activate
+    Feature #103: AI Package: Follow, FollowCell
+    Feature #138: Editor: Drag & Drop
+    Feature #428: Player death
+    Feature #505: Editor: Record Cloning
+    Feature #701: Levelled creatures
+    Feature #708: Improved Local Variable handling
+    Feature #709: Editor: Script verifier
+    Feature #764: Missing journal backend features
+    Feature #777: Creature weapons/shields
+    Feature #789: Editor: Referenceable record verifier
+    Feature #924: Load/Save GUI (still missing loading screen and progress bars)
+    Feature #946: Knockdown
+    Feature #947: Decrease fatigue when running, swimming and attacking
+    Feature #956: Melee Combat: Blocking
+    Feature #957: Area magic
+    Feature #960: Combat/AI combat for creatures
+    Feature #962: Combat-Related AI instructions
+    Feature #1075: Damage/Restore skill/attribute magic effects
+    Feature #1076: Soultrap magic effect
+    Feature #1081: Disease contraction
+    Feature #1086: Blood particles
+    Feature #1092: Interrupt resting
+    Feature #1101: Inventory equip scripts
+    Feature #1116: Version/Build number in Launcher window
+    Feature #1119: Resistance/weakness to normal weapons magic effect
+    Feature #1123: Slow Fall magic effect
+    Feature #1130: Auto-calculate spells
+    Feature #1164: Editor: Case-insensitive sorting in tables
 
 0.28.0
-
-Bug #399: Inventory changes are not visible immediately
-Bug #417: Apply weather instantly when teleporting
-Bug #566: Global Map position marker not updated for interior cells
-Bug #712: Looting corpse delay
-Bug #716: Problem with the "Vurt's Ascadian Isles Mod" mod
-Bug #805: Two TR meshes appear black (v0.24RC)
-Bug #841: Third-person activation distance taken from camera rather than head
-Bug #845: NPCs hold torches during the day
-Bug #855: Vvardenfell Visages Volume I some hairs don´t appear since 0,24
-Bug #856: Maormer race by Mac Kom - The heads are way up
-Bug #864: Walk locks during loading in 3rd person
-Bug #871: active weapon/magic item icon is not immediately made blank if item is removed during dialog
-Bug #882: Hircine's Ring doesn't always work
-Bug #909: [Tamriel Rebuilt] crashes in Akamora
-Bug #922: Launcher writing merged openmw.cfg files
-Bug #943: Random magnitude should be calculated per effect
-Bug #948: Negative fatigue level should be allowed
-Bug #949: Particles in world space
-Bug #950: Hard crash on x64 Linux running --new-game (on startup)
-Bug #951: setMagicka and setFatigue have no effect
-Bug #954: Problem with equipping inventory items when using a keyboard shortcut
-Bug #955: Issues with equipping torches
-Bug #966: Shield is visible when casting spell
-Bug #967: Game crashes when equipping silver candlestick
-Bug #970: Segmentation fault when starting at Bal Isra
-Bug #977: Pressing down key in console doesn't go forward in history
-Bug #979: Tooltip disappears when changing inventory
-Bug #980: Barter: item category is remembered, but not shown
-Bug #981: Mod: replacing model has wrong position/orientation
-Bug #982: Launcher: Addon unchecking is not saved
-Bug #983: Fix controllers to affect objects attached to the base node
-Bug #985: Player can talk to NPCs who are in combat
-Bug #989: OpenMW crashes when trying to include mod with capital .ESP
-Bug #991: Merchants equip items with harmful constant effect enchantments
-Bug #994: Don't cap skills/attributes when set via console
-Bug #998: Setting the max health should also set the current health
-Bug #1005: Torches are visible when casting spells and during hand to hand combat.
-Bug #1006: Many NPCs have 0 skill
-Bug #1007: Console fills up with text
-Bug #1013: Player randomly loses health or dies
-Bug #1014: Persuasion window is not centered in maximized window
-Bug #1015: Player status window scroll state resets on status change
-Bug #1016: Notification window not big enough for all skill level ups
-Bug #1020: Saved window positions are not rescaled appropriately on resolution change
-Bug #1022: Messages stuck permanently on screen when they pile up
-Bug #1023: Journals doesn't open
-Bug #1026: Game loses track of torch usage.
-Bug #1028: Crash on pickup of jug in Unexplored Shipwreck, Upper level
-Bug #1029: Quick keys menu: Select compatible replacement when tool used up
-Bug #1042: TES3 header data wrong encoding
-Bug #1045: OS X: deployed OpenCS won't launch
-Bug #1046: All damaged weaponry is worth 1 gold
-Bug #1048: Links in "locked" dialogue are still clickable
-Bug #1052: Using color codes when naming your character actually changes the name's color
-Bug #1054: Spell effects not visible in front of water
-Bug #1055: Power-Spell animation starts even though you already casted it that day
-Bug #1059: Cure disease potion removes all effects from player, even your race bonus and race ability
-Bug #1063: Crash upon checking out game start ship area in Seyda Neen
-Bug #1064: openmw binaries link to unnecessary libraries
-Bug #1065: Landing from a high place in water still causes fall damage
-Bug #1072: Drawing weapon increases torch brightness
-Bug #1073: Merchants sell stacks of gold
-Feature #43: Visuals for Magic Effects
-Feature #51: Ranged Magic
-Feature #52: Touch Range Magic
-Feature #53: Self Range Magic
-Feature #54: Spell Casting
-Feature #70: Vampirism
-Feature #100: Combat AI
-Feature #171: Implement NIF record NiFlipController
-Feature #410: Window to restore enchanted item charge
-Feature #647: Enchanted item glow
-Feature #723: Invisibility/Chameleon magic effects
-Feature #737: Resist Magicka magic effect
-Feature #758: GetLOS
-Feature #926: Editor: Info-Record tables
-Feature #958: Material controllers
-Feature #959: Terrain bump, specular, & parallax mapping
-Feature #990: Request: unlock mouse when in any menu
-Feature #1018: Do not allow view mode switching while performing an action
-Feature #1027: Vertex morph animation (NiGeomMorpherController)
-Feature #1031: Handle NiBillboardNode
-Feature #1051: Implement NIF texture slot DarkTexture
-Task #873: Unify OGRE initialisation
+------
+
+    Bug #399: Inventory changes are not visible immediately
+    Bug #417: Apply weather instantly when teleporting
+    Bug #566: Global Map position marker not updated for interior cells
+    Bug #712: Looting corpse delay
+    Bug #716: Problem with the "Vurt's Ascadian Isles Mod" mod
+    Bug #805: Two TR meshes appear black (v0.24RC)
+    Bug #841: Third-person activation distance taken from camera rather than head
+    Bug #845: NPCs hold torches during the day
+    Bug #855: Vvardenfell Visages Volume I some hairs don´t appear since 0,24
+    Bug #856: Maormer race by Mac Kom - The heads are way up
+    Bug #864: Walk locks during loading in 3rd person
+    Bug #871: active weapon/magic item icon is not immediately made blank if item is removed during dialog
+    Bug #882: Hircine's Ring doesn't always work
+    Bug #909: [Tamriel Rebuilt] crashes in Akamora
+    Bug #922: Launcher writing merged openmw.cfg files
+    Bug #943: Random magnitude should be calculated per effect
+    Bug #948: Negative fatigue level should be allowed
+    Bug #949: Particles in world space
+    Bug #950: Hard crash on x64 Linux running --new-game (on startup)
+    Bug #951: setMagicka and setFatigue have no effect
+    Bug #954: Problem with equipping inventory items when using a keyboard shortcut
+    Bug #955: Issues with equipping torches
+    Bug #966: Shield is visible when casting spell
+    Bug #967: Game crashes when equipping silver candlestick
+    Bug #970: Segmentation fault when starting at Bal Isra
+    Bug #977: Pressing down key in console doesn't go forward in history
+    Bug #979: Tooltip disappears when changing inventory
+    Bug #980: Barter: item category is remembered, but not shown
+    Bug #981: Mod: replacing model has wrong position/orientation
+    Bug #982: Launcher: Addon unchecking is not saved
+    Bug #983: Fix controllers to affect objects attached to the base node
+    Bug #985: Player can talk to NPCs who are in combat
+    Bug #989: OpenMW crashes when trying to include mod with capital .ESP
+    Bug #991: Merchants equip items with harmful constant effect enchantments
+    Bug #994: Don't cap skills/attributes when set via console
+    Bug #998: Setting the max health should also set the current health
+    Bug #1005: Torches are visible when casting spells and during hand to hand combat.
+    Bug #1006: Many NPCs have 0 skill
+    Bug #1007: Console fills up with text
+    Bug #1013: Player randomly loses health or dies
+    Bug #1014: Persuasion window is not centered in maximized window
+    Bug #1015: Player status window scroll state resets on status change
+    Bug #1016: Notification window not big enough for all skill level ups
+    Bug #1020: Saved window positions are not rescaled appropriately on resolution change
+    Bug #1022: Messages stuck permanently on screen when they pile up
+    Bug #1023: Journals doesn't open
+    Bug #1026: Game loses track of torch usage.
+    Bug #1028: Crash on pickup of jug in Unexplored Shipwreck, Upper level
+    Bug #1029: Quick keys menu: Select compatible replacement when tool used up
+    Bug #1042: TES3 header data wrong encoding
+    Bug #1045: OS X: deployed OpenCS won't launch
+    Bug #1046: All damaged weaponry is worth 1 gold
+    Bug #1048: Links in "locked" dialogue are still clickable
+    Bug #1052: Using color codes when naming your character actually changes the name's color
+    Bug #1054: Spell effects not visible in front of water
+    Bug #1055: Power-Spell animation starts even though you already casted it that day
+    Bug #1059: Cure disease potion removes all effects from player, even your race bonus and race ability
+    Bug #1063: Crash upon checking out game start ship area in Seyda Neen
+    Bug #1064: openmw binaries link to unnecessary libraries
+    Bug #1065: Landing from a high place in water still causes fall damage
+    Bug #1072: Drawing weapon increases torch brightness
+    Bug #1073: Merchants sell stacks of gold
+    Feature #43: Visuals for Magic Effects
+    Feature #51: Ranged Magic
+    Feature #52: Touch Range Magic
+    Feature #53: Self Range Magic
+    Feature #54: Spell Casting
+    Feature #70: Vampirism
+    Feature #100: Combat AI
+    Feature #171: Implement NIF record NiFlipController
+    Feature #410: Window to restore enchanted item charge
+    Feature #647: Enchanted item glow
+    Feature #723: Invisibility/Chameleon magic effects
+    Feature #737: Resist Magicka magic effect
+    Feature #758: GetLOS
+    Feature #926: Editor: Info-Record tables
+    Feature #958: Material controllers
+    Feature #959: Terrain bump, specular, & parallax mapping
+    Feature #990: Request: unlock mouse when in any menu
+    Feature #1018: Do not allow view mode switching while performing an action
+    Feature #1027: Vertex morph animation (NiGeomMorpherController)
+    Feature #1031: Handle NiBillboardNode
+    Feature #1051: Implement NIF texture slot DarkTexture
+    Task #873: Unify OGRE initialisation
 
 0.27.0
-
-Bug #597: Assertion `dialogue->mId == id' failed in esmstore.cpp
-Bug #794: incorrect display of decimal numbers
-Bug #840: First-person sneaking camera height
-Bug #887: Ambient sounds playing while paused
-Bug #902: Problems with Polish character encoding
-Bug #907: Entering third person using the mousewheel is possible even if it's impossible using the key
-Bug #910: Some CDs not working correctly with Unshield installer
-Bug #917: Quick character creation plugin does not work
-Bug #918: Fatigue does not refill
-Bug #919: The PC falls dead in Beshara - OpenMW nightly Win64 (708CDE2)
-Feature #57: Acrobatics Skill
-Feature #462: Editor: Start Dialogue
-Feature #546: Modify ESX selector to handle new content file scheme
-Feature #588: Editor: Adjust name/path of edited content files
-Feature #644: Editor: Save
-Feature #710: Editor: Configure script compiler context
-Feature #790: God Mode
-Feature #881: Editor: Allow only one instance of OpenCS
-Feature #889: Editor: Record filtering
-Feature #895: Extinguish torches
-Feature #898: Breath meter enhancements
-Feature #901: Editor: Default record filter
-Feature #913: Merge --master and --plugin switches
+------
+
+    Bug #597: Assertion `dialogue->mId == id' failed in esmstore.cpp
+    Bug #794: incorrect display of decimal numbers
+    Bug #840: First-person sneaking camera height
+    Bug #887: Ambient sounds playing while paused
+    Bug #902: Problems with Polish character encoding
+    Bug #907: Entering third person using the mousewheel is possible even if it's impossible using the key
+    Bug #910: Some CDs not working correctly with Unshield installer
+    Bug #917: Quick character creation plugin does not work
+    Bug #918: Fatigue does not refill
+    Bug #919: The PC falls dead in Beshara - OpenMW nightly Win64 (708CDE2)
+    Feature #57: Acrobatics Skill
+    Feature #462: Editor: Start Dialogue
+    Feature #546: Modify ESX selector to handle new content file scheme
+    Feature #588: Editor: Adjust name/path of edited content files
+    Feature #644: Editor: Save
+    Feature #710: Editor: Configure script compiler context
+    Feature #790: God Mode
+    Feature #881: Editor: Allow only one instance of OpenCS
+    Feature #889: Editor: Record filtering
+    Feature #895: Extinguish torches
+    Feature #898: Breath meter enhancements
+    Feature #901: Editor: Default record filter
+    Feature #913: Merge --master and --plugin switches
 
 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
+------
+
+    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
-Bug #604: Terrible performance drop in the Census and Excise Office.
-Bug #676: Start Scripts fail to load
-Bug #677: OpenMW does not accept script names with -
-Bug #766: Extra space in front of topic links
-Bug #793: AIWander Isn't Being Passed The Repeat Parameter
-Bug #795: Sound playing with drawn weapon and crossing cell-border
-Bug #800: can't select weapon for enchantment
-Bug #801: Player can move while over-encumbered
-Bug #802: Dead Keys not working
-Bug #808: mouse capture
-Bug #809: ini Importer does not work without an existing cfg file
-Bug #812: Launcher will run OpenMW with no ESM or ESP selected
-Bug #813: OpenMW defaults to Morrowind.ESM with no ESM or ESP selected
-Bug #817: Dead NPCs and Creatures still have collision boxes
-Bug #820: Incorrect sorting of answers (Dialogue)
-Bug #826: mwinimport dumps core when given an unknown parameter
-Bug #833: getting stuck in door
-Bug #835: Journals/books not showing up properly.
-Feature #38: SoundGen
-Feature #105: AI Package: Wander
-Feature #230: 64-bit compatibility for OS X
-Feature #263: Hardware mouse cursors
-Feature #449: Allow mouse outside of window while paused
-Feature #736: First person animations
-Feature #750: Using mouse wheel in third person mode
-Feature #822: Autorepeat for slider buttons
+------
+
+    Bug #411: Launcher crash on OS X < 10.8
+    Bug #604: Terrible performance drop in the Census and Excise Office.
+    Bug #676: Start Scripts fail to load
+    Bug #677: OpenMW does not accept script names with -
+    Bug #766: Extra space in front of topic links
+    Bug #793: AIWander Isn't Being Passed The Repeat Parameter
+    Bug #795: Sound playing with drawn weapon and crossing cell-border
+    Bug #800: can't select weapon for enchantment
+    Bug #801: Player can move while over-encumbered
+    Bug #802: Dead Keys not working
+    Bug #808: mouse capture
+    Bug #809: ini Importer does not work without an existing cfg file
+    Bug #812: Launcher will run OpenMW with no ESM or ESP selected
+    Bug #813: OpenMW defaults to Morrowind.ESM with no ESM or ESP selected
+    Bug #817: Dead NPCs and Creatures still have collision boxes
+    Bug #820: Incorrect sorting of answers (Dialogue)
+    Bug #826: mwinimport dumps core when given an unknown parameter
+    Bug #833: getting stuck in door
+    Bug #835: Journals/books not showing up properly.
+    Feature #38: SoundGen
+    Feature #105: AI Package: Wander
+    Feature #230: 64-bit compatibility for OS X
+    Feature #263: Hardware mouse cursors
+    Feature #449: Allow mouse outside of window while paused
+    Feature #736: First person animations
+    Feature #750: Using mouse wheel in third person mode
+    Feature #822: Autorepeat for slider buttons
 
 0.24.0
-
-Bug #284: Book's text misalignment
-Bug #445: Camera able to get slightly below floor / terrain
-Bug #582: Seam issue in Red Mountain
-Bug #632: Journal Next Button shows white square
-Bug #653: IndexedStore ignores index
-Bug #694: Parser does not recognize float values starting with .
-Bug #699: Resource handling broken with Ogre 1.9 trunk
-Bug #718: components/esm/loadcell is using the mwworld subsystem
-Bug #729: Levelled item list tries to add nonexistent item
-Bug #730: Arrow buttons in the settings menu do not work.
-Bug #732: Erroneous behavior when binding keys
-Bug #733: Unclickable dialogue topic
-Bug #734: Book empty line problem
-Bug #738: OnDeath only works with implicit references
-Bug #740: Script compiler fails on scripts with special names
-Bug #742: Wait while no clipping
-Bug #743: Problem with changeweather console command
-Bug #744: No wait dialogue after starting a new game
-Bug #748: Player is not able to unselect objects with the console
-Bug #751: AddItem should only spawn a message box when called from dialogue
-Bug #752: The enter button has several functions in trade and looting that is not impelemted.
-Bug #753: Fargoth's Ring Quest Strange Behavior
-Bug #755: Launcher writes duplicate lines into settings.cfg
-Bug #759: Second quest in mages guild does not work
-Bug #763: Enchantment cast cost is wrong
-Bug #770: The "Take" and "Close" buttons in the scroll GUI are stretched incorrectly
-Bug #773: AIWander Isn't Being Passed The Correct idle Values
-Bug #778: The journal can be opened at the start of a new game
-Bug #779: Divayth Fyr starts as dead
-Bug #787: "Batch count" on detailed FPS counter gets cut-off
-Bug #788: chargen scroll layout does not match vanilla
-Feature #60: Atlethics Skill
-Feature #65: Security Skill
-Feature #74: Interaction with non-load-doors
-Feature #98: Render Weapon and Shield
-Feature #102: AI Package: Escort, EscortCell
-Feature #182: Advanced Journal GUI
-Feature #288: Trading enhancements
-Feature #405: Integrate "new game" into the menu
-Feature #537: Highlight dialogue topic links
-Feature #658: Rotate, RotateWorld script instructions and local rotations
-Feature #690: Animation Layering
-Feature #722: Night Eye/Blind magic effects
-Feature #735: Move, MoveWorld script instructions.
-Feature #760: Non-removable corpses
+------
+
+    Bug #284: Book's text misalignment
+    Bug #445: Camera able to get slightly below floor / terrain
+    Bug #582: Seam issue in Red Mountain
+    Bug #632: Journal Next Button shows white square
+    Bug #653: IndexedStore ignores index
+    Bug #694: Parser does not recognize float values starting with .
+    Bug #699: Resource handling broken with Ogre 1.9 trunk
+    Bug #718: components/esm/loadcell is using the mwworld subsystem
+    Bug #729: Levelled item list tries to add nonexistent item
+    Bug #730: Arrow buttons in the settings menu do not work.
+    Bug #732: Erroneous behavior when binding keys
+    Bug #733: Unclickable dialogue topic
+    Bug #734: Book empty line problem
+    Bug #738: OnDeath only works with implicit references
+    Bug #740: Script compiler fails on scripts with special names
+    Bug #742: Wait while no clipping
+    Bug #743: Problem with changeweather console command
+    Bug #744: No wait dialogue after starting a new game
+    Bug #748: Player is not able to unselect objects with the console
+    Bug #751: AddItem should only spawn a message box when called from dialogue
+    Bug #752: The enter button has several functions in trade and looting that is not impelemted.
+    Bug #753: Fargoth's Ring Quest Strange Behavior
+    Bug #755: Launcher writes duplicate lines into settings.cfg
+    Bug #759: Second quest in mages guild does not work
+    Bug #763: Enchantment cast cost is wrong
+    Bug #770: The "Take" and "Close" buttons in the scroll GUI are stretched incorrectly
+    Bug #773: AIWander Isn't Being Passed The Correct idle Values
+    Bug #778: The journal can be opened at the start of a new game
+    Bug #779: Divayth Fyr starts as dead
+    Bug #787: "Batch count" on detailed FPS counter gets cut-off
+    Bug #788: chargen scroll layout does not match vanilla
+    Feature #60: Atlethics Skill
+    Feature #65: Security Skill
+    Feature #74: Interaction with non-load-doors
+    Feature #98: Render Weapon and Shield
+    Feature #102: AI Package: Escort, EscortCell
+    Feature #182: Advanced Journal GUI
+    Feature #288: Trading enhancements
+    Feature #405: Integrate "new game" into the menu
+    Feature #537: Highlight dialogue topic links
+    Feature #658: Rotate, RotateWorld script instructions and local rotations
+    Feature #690: Animation Layering
+    Feature #722: Night Eye/Blind magic effects
+    Feature #735: Move, MoveWorld script instructions.
+    Feature #760: Non-removable corpses
 
 0.23.0
-
-Bug #522: Player collides with placeable items
-Bug #553: Open/Close sounds played when accessing main menu w/ Journal Open
-Bug #561: Tooltip word wrapping delay
-Bug #578: Bribing works incorrectly
-Bug #601: PositionCell fails on negative coordinates
-Bug #606: Some NPCs hairs not rendered with Better Heads addon
-Bug #609: Bad rendering of bone boots
-Bug #613: Messagebox causing assert to fail
-Bug #631: Segfault on shutdown
-Bug #634: Exception when talking to Calvus Horatius in Mournhold, royal palace courtyard
-Bug #635: Scale NPCs depending on race
-Bug #643: Dialogue Race select function is inverted
-Bug #646: Twohanded weapons don't work properly
-Bug #654: Crash when dropping objects without a collision shape
-Bug #655/656: Objects that were disabled or deleted (but not both) were added to the scene when re-entering a cell
-Bug #660: "g" in "change" cut off in Race Menu
-Bug #661: Arrille sells me the key to his upstairs room
-Bug #662: Day counter starts at 2 instead of 1
-Bug #663: Cannot select "come unprepared" topic in dialog with Dagoth Ur
-Bug #665: Pickpocket -> "Grab all" grabs all NPC inventory, even not listed in container window.
-Bug #666: Looking up/down problem
-Bug #667: Active effects border visible during loading
-Bug #669: incorrect player position at new game start
-Bug #670: race selection menu: sex, face and hair left button not totally clickable
-Bug #671: new game: player is naked
-Bug #674: buying or selling items doesn't change amount of gold
-Bug #675: fatigue is not set to its maximum when starting a new game
-Bug #678: Wrong rotation order causes RefData's rotation to be stored incorrectly
-Bug #680: different gold coins in Tel Mara
-Bug #682: Race menu ignores playable flag for some hairs and faces
-Bug #685: Script compiler does not accept ":" after a function name
-Bug #688: dispose corpse makes cross-hair to disappear
-Bug #691: Auto equipping ignores equipment conditions
-Bug #692: OpenMW doesnt load "loose file" texture packs that places resources directly in data folder
-Bug #696: Draugr incorrect head offset
-Bug #697: Sail transparency issue
-Bug #700: "On the rocks" mod does not load its UV coordinates correctly.
-Bug #702: Some race mods don't work
-Bug #711: Crash during character creation
-Bug #715: Growing Tauryon
-Bug #725: Auto calculate stats
-Bug #728: Failure to open container and talk dialogue
-Bug #731: Crash with Mush-Mere's "background" topic
-Feature #55/657: Item Repairing
-Feature #62/87: Enchanting
-Feature #99: Pathfinding
-Feature #104: AI Package: Travel
-Feature #129: Levelled items
-Feature #204: Texture animations
-Feature #239: Fallback-Settings
-Feature #535: Console object selection improvements
-Feature #629: Add levelup description in levelup layout dialog
-Feature #630: Optional format subrecord in (tes3) header
-Feature #641: Armor rating
-Feature #645: OnDeath script function
-Feature #683: Companion item UI
-Feature #698: Basic Particles
-Task #648: Split up components/esm/loadlocks
-Task #695: mwgui cleanup
+------
+
+    Bug #522: Player collides with placeable items
+    Bug #553: Open/Close sounds played when accessing main menu w/ Journal Open
+    Bug #561: Tooltip word wrapping delay
+    Bug #578: Bribing works incorrectly
+    Bug #601: PositionCell fails on negative coordinates
+    Bug #606: Some NPCs hairs not rendered with Better Heads addon
+    Bug #609: Bad rendering of bone boots
+    Bug #613: Messagebox causing assert to fail
+    Bug #631: Segfault on shutdown
+    Bug #634: Exception when talking to Calvus Horatius in Mournhold, royal palace courtyard
+    Bug #635: Scale NPCs depending on race
+    Bug #643: Dialogue Race select function is inverted
+    Bug #646: Twohanded weapons don't work properly
+    Bug #654: Crash when dropping objects without a collision shape
+    Bug #655/656: Objects that were disabled or deleted (but not both) were added to the scene when re-entering a cell
+    Bug #660: "g" in "change" cut off in Race Menu
+    Bug #661: Arrille sells me the key to his upstairs room
+    Bug #662: Day counter starts at 2 instead of 1
+    Bug #663: Cannot select "come unprepared" topic in dialog with Dagoth Ur
+    Bug #665: Pickpocket -> "Grab all" grabs all NPC inventory, even not listed in container window.
+    Bug #666: Looking up/down problem
+    Bug #667: Active effects border visible during loading
+    Bug #669: incorrect player position at new game start
+    Bug #670: race selection menu: sex, face and hair left button not totally clickable
+    Bug #671: new game: player is naked
+    Bug #674: buying or selling items doesn't change amount of gold
+    Bug #675: fatigue is not set to its maximum when starting a new game
+    Bug #678: Wrong rotation order causes RefData's rotation to be stored incorrectly
+    Bug #680: different gold coins in Tel Mara
+    Bug #682: Race menu ignores playable flag for some hairs and faces
+    Bug #685: Script compiler does not accept ":" after a function name
+    Bug #688: dispose corpse makes cross-hair to disappear
+    Bug #691: Auto equipping ignores equipment conditions
+    Bug #692: OpenMW doesnt load "loose file" texture packs that places resources directly in data folder
+    Bug #696: Draugr incorrect head offset
+    Bug #697: Sail transparency issue
+    Bug #700: "On the rocks" mod does not load its UV coordinates correctly.
+    Bug #702: Some race mods don't work
+    Bug #711: Crash during character creation
+    Bug #715: Growing Tauryon
+    Bug #725: Auto calculate stats
+    Bug #728: Failure to open container and talk dialogue
+    Bug #731: Crash with Mush-Mere's "background" topic
+    Feature #55/657: Item Repairing
+    Feature #62/87: Enchanting
+    Feature #99: Pathfinding
+    Feature #104: AI Package: Travel
+    Feature #129: Levelled items
+    Feature #204: Texture animations
+    Feature #239: Fallback-Settings
+    Feature #535: Console object selection improvements
+    Feature #629: Add levelup description in levelup layout dialog
+    Feature #630: Optional format subrecord in (tes3) header
+    Feature #641: Armor rating
+    Feature #645: OnDeath script function
+    Feature #683: Companion item UI
+    Feature #698: Basic Particles
+    Task #648: Split up components/esm/loadlocks
+    Task #695: mwgui cleanup
 
 0.22.0
-
-Bug #311: Potential infinite recursion in script compiler
-Bug #355: Keyboard repeat rate (in Xorg) are left disabled after game exit.
-Bug #382: Weird effect in 3rd person on water
-Bug #387: Always use detailed shape for physics raycasts
-Bug #420: Potion/ingredient effects do not stack
-Bug #429: Parts of dwemer door not picked up correctly for activation/tooltips
-Bug #434/Bug #605: Object movement between cells not properly implemented
-Bug #502: Duplicate player collision model at origin
-Bug #509: Dialogue topic list shifts inappropriately
-Bug #513: Sliding stairs
-Bug #515: Launcher does not support non-latin strings
-Bug #525: Race selection preview camera wrong position
-Bug #526: Attributes / skills should not go below zero
-Bug #529: Class and Birthsign menus options should be preselected
-Bug #530: Lock window button graphic missing
-Bug #532: Missing map menu graphics
-Bug #545: ESX selector does not list ESM files properly
-Bug #547: Global variables of type short are read incorrectly
-Bug #550: Invisible meshes collision and tooltip
-Bug #551: Performance drop when loading multiple ESM files
-Bug #552: Don't list CG in options if it is not available
-Bug #555: Character creation windows "OK" button broken
-Bug #558: Segmentation fault when Alt-tabbing with console opened
-Bug #559: Dialog window should not be available before character creation is finished
-Bug #560: Tooltip borders should be stretched
-Bug #562: Sound should not be played when an object cannot be picked up
-Bug #565: Water animation speed + timescale
-Bug #572: Better Bodies' textures don't work
-Bug #573: OpenMW doesn't load if TR_Mainland.esm is enabled (Tamriel Rebuilt mod)
-Bug #574: Moving left/right should not cancel auto-run
-Bug #575: Crash entering the Chamber of Song
-Bug #576: Missing includes
-Bug #577: Left Gloves Addon causes ESMReader exception
-Bug #579: Unable to open container "Kvama Egg Sack"
-Bug #581: Mimicking vanilla Morrowind water
-Bug #583: Gender not recognized
-Bug #586: Wrong char gen behaviour
-Bug #587: "End" script statements with spaces don't work
-Bug #589: Closing message boxes by pressing the activation key
-Bug #590: Ugly Dagoth Ur rendering
-Bug #591: Race selection issues
-Bug #593: Persuasion response should be random
-Bug #595: Footless guard
-Bug #599: Waterfalls are invisible from a certain distance
-Bug #600: Waterfalls rendered incorrectly, cut off by water
-Bug #607: New beast bodies mod crashes
-Bug #608: Crash in cell "Mournhold, Royal Palace"
-Bug #611: OpenMW doesn't find some of textures used in Tamriel Rebuilt
-Bug #613: Messagebox causing assert to fail
-Bug #615: Meshes invisible from above water
-Bug #617: Potion effects should be hidden until discovered
-Bug #619: certain moss hanging from tree has rendering bug
-Bug #621: Batching bloodmoon's trees
-Bug #623: NiMaterialProperty alpha unhandled
-Bug #628: Launcher in latest master crashes the game
-Bug #633: Crash on startup: Better Heads
-Bug #636: Incorrect Char Gen Menu Behavior
-Feature #29: Allow ESPs and multiple ESMs
-Feature #94: Finish class selection-dialogue
-Feature #149: Texture Alphas
-Feature #237: Run Morrowind-ini importer from launcher
-Feature #286: Update Active Spell Icons
-Feature #334: Swimming animation
-Feature #335: Walking animation
-Feature #360: Proper collision shapes for NPCs and creatures
-Feature #367: Lights that behave more like original morrowind implementation
-Feature #477: Special local scripting variables
-Feature #528: Message boxes should close when enter is pressed under certain conditions.
-Feature #543: Add bsa files to the settings imported by the ini importer
-Feature #594: coordinate space and utility functions
-Feature #625: Zoom in vanity mode
-Task #464: Refactor launcher ESX selector into a re-usable component
-Task #624: Unified implementation of type-variable sub-records
+------
+
+    Bug #311: Potential infinite recursion in script compiler
+    Bug #355: Keyboard repeat rate (in Xorg) are left disabled after game exit.
+    Bug #382: Weird effect in 3rd person on water
+    Bug #387: Always use detailed shape for physics raycasts
+    Bug #420: Potion/ingredient effects do not stack
+    Bug #429: Parts of dwemer door not picked up correctly for activation/tooltips
+    Bug #434/Bug #605: Object movement between cells not properly implemented
+    Bug #502: Duplicate player collision model at origin
+    Bug #509: Dialogue topic list shifts inappropriately
+    Bug #513: Sliding stairs
+    Bug #515: Launcher does not support non-latin strings
+    Bug #525: Race selection preview camera wrong position
+    Bug #526: Attributes / skills should not go below zero
+    Bug #529: Class and Birthsign menus options should be preselected
+    Bug #530: Lock window button graphic missing
+    Bug #532: Missing map menu graphics
+    Bug #545: ESX selector does not list ESM files properly
+    Bug #547: Global variables of type short are read incorrectly
+    Bug #550: Invisible meshes collision and tooltip
+    Bug #551: Performance drop when loading multiple ESM files
+    Bug #552: Don't list CG in options if it is not available
+    Bug #555: Character creation windows "OK" button broken
+    Bug #558: Segmentation fault when Alt-tabbing with console opened
+    Bug #559: Dialog window should not be available before character creation is finished
+    Bug #560: Tooltip borders should be stretched
+    Bug #562: Sound should not be played when an object cannot be picked up
+    Bug #565: Water animation speed + timescale
+    Bug #572: Better Bodies' textures don't work
+    Bug #573: OpenMW doesn't load if TR_Mainland.esm is enabled (Tamriel Rebuilt mod)
+    Bug #574: Moving left/right should not cancel auto-run
+    Bug #575: Crash entering the Chamber of Song
+    Bug #576: Missing includes
+    Bug #577: Left Gloves Addon causes ESMReader exception
+    Bug #579: Unable to open container "Kvama Egg Sack"
+    Bug #581: Mimicking vanilla Morrowind water
+    Bug #583: Gender not recognized
+    Bug #586: Wrong char gen behaviour
+    Bug #587: "End" script statements with spaces don't work
+    Bug #589: Closing message boxes by pressing the activation key
+    Bug #590: Ugly Dagoth Ur rendering
+    Bug #591: Race selection issues
+    Bug #593: Persuasion response should be random
+    Bug #595: Footless guard
+    Bug #599: Waterfalls are invisible from a certain distance
+    Bug #600: Waterfalls rendered incorrectly, cut off by water
+    Bug #607: New beast bodies mod crashes
+    Bug #608: Crash in cell "Mournhold, Royal Palace"
+    Bug #611: OpenMW doesn't find some of textures used in Tamriel Rebuilt
+    Bug #613: Messagebox causing assert to fail
+    Bug #615: Meshes invisible from above water
+    Bug #617: Potion effects should be hidden until discovered
+    Bug #619: certain moss hanging from tree has rendering bug
+    Bug #621: Batching bloodmoon's trees
+    Bug #623: NiMaterialProperty alpha unhandled
+    Bug #628: Launcher in latest master crashes the game
+    Bug #633: Crash on startup: Better Heads
+    Bug #636: Incorrect Char Gen Menu Behavior
+    Feature #29: Allow ESPs and multiple ESMs
+    Feature #94: Finish class selection-dialogue
+    Feature #149: Texture Alphas
+    Feature #237: Run Morrowind-ini importer from launcher
+    Feature #286: Update Active Spell Icons
+    Feature #334: Swimming animation
+    Feature #335: Walking animation
+    Feature #360: Proper collision shapes for NPCs and creatures
+    Feature #367: Lights that behave more like original morrowind implementation
+    Feature #477: Special local scripting variables
+    Feature #528: Message boxes should close when enter is pressed under certain conditions.
+    Feature #543: Add bsa files to the settings imported by the ini importer
+    Feature #594: coordinate space and utility functions
+    Feature #625: Zoom in vanity mode
+    Task #464: Refactor launcher ESX selector into a re-usable component
+    Task #624: Unified implementation of type-variable sub-records
 
 0.21.0
-
-Bug #253: Dialogs don't work for Russian version of Morrowind
-Bug #267: Activating creatures without dialogue can still activate the dialogue GUI
-Bug #354: True flickering lights
-Bug #386: The main menu's first entry is wrong (in french)
-Bug #479: Adding the spell "Ash Woe Blight" to the player causes strange attribute oscillations
-Bug #495: Activation Range
-Bug #497: Failed Disposition check doesn't stop a dialogue entry from being returned
-Bug #498: Failing a disposition check shouldn't eliminate topics from the the list of those available
-Bug #500: Disposition for most NPCs is 0/100
-Bug #501: Getdisposition command wrongly returns base disposition
-Bug #506: Journal UI doesn't update anymore
-Bug #507: EnableRestMenu is not a valid command - change it to EnableRest
-Bug #508: Crash in Ald Daedroth Shrine
-Bug #517: Wrong price calculation when untrading an item
-Bug #521: MWGui::InventoryWindow creates a duplicate player actor at the origin
-Bug #524: Beast races are able to wear shoes
-Bug #527: Background music fails to play
-Bug #533: The arch at Gnisis entrance is not displayed
-Bug #534: Terrain gets its correct shape only some time after the cell is loaded
-Bug #536: The same entry can be added multiple times to the journal
-Bug #539: Race selection is broken
-Bug #544: Terrain normal map corrupt when the map is rendered
-Feature #39: Video Playback
-Feature #151: ^-escape sequences in text output
-Feature #392: Add AI related script functions
-Feature #456: Determine required ini fallback values and adjust the ini importer accordingly
-Feature #460: Experimental DirArchives improvements
-Feature #540: Execute scripts of objects in containers/inventories in active cells
-Task #401: Review GMST fixing
-Task #453: Unify case smashing/folding
-Task #512: Rewrite utf8 component
+------
+
+    Bug #253: Dialogs don't work for Russian version of Morrowind
+    Bug #267: Activating creatures without dialogue can still activate the dialogue GUI
+    Bug #354: True flickering lights
+    Bug #386: The main menu's first entry is wrong (in french)
+    Bug #479: Adding the spell "Ash Woe Blight" to the player causes strange attribute oscillations
+    Bug #495: Activation Range
+    Bug #497: Failed Disposition check doesn't stop a dialogue entry from being returned
+    Bug #498: Failing a disposition check shouldn't eliminate topics from the the list of those available
+    Bug #500: Disposition for most NPCs is 0/100
+    Bug #501: Getdisposition command wrongly returns base disposition
+    Bug #506: Journal UI doesn't update anymore
+    Bug #507: EnableRestMenu is not a valid command - change it to EnableRest
+    Bug #508: Crash in Ald Daedroth Shrine
+    Bug #517: Wrong price calculation when untrading an item
+    Bug #521: MWGui::InventoryWindow creates a duplicate player actor at the origin
+    Bug #524: Beast races are able to wear shoes
+    Bug #527: Background music fails to play
+    Bug #533: The arch at Gnisis entrance is not displayed
+    Bug #534: Terrain gets its correct shape only some time after the cell is loaded
+    Bug #536: The same entry can be added multiple times to the journal
+    Bug #539: Race selection is broken
+    Bug #544: Terrain normal map corrupt when the map is rendered
+    Feature #39: Video Playback
+    Feature #151: ^-escape sequences in text output
+    Feature #392: Add AI related script functions
+    Feature #456: Determine required ini fallback values and adjust the ini importer accordingly
+    Feature #460: Experimental DirArchives improvements
+    Feature #540: Execute scripts of objects in containers/inventories in active cells
+    Task #401: Review GMST fixing
+    Task #453: Unify case smashing/folding
+    Task #512: Rewrite utf8 component
 
 0.20.0
-
-Bug #366: Changing the player's race during character creation does not change the look of the player character
-Bug #430: Teleporting and using loading doors linking within the same cell reloads the cell
-Bug #437: Stop animations when paused
-Bug #438: Time displays as "0 a.m." when it should be "12 a.m."
-Bug #439: Text in "name" field of potion/spell creation window is persistent
-Bug #440: Starting date at a new game is off by one day
-Bug #442: Console window doesn't close properly sometimes
-Bug #448: Do not break container window formatting when item names are very long
-Bug #458: Topics sometimes not automatically added to known topic list
-Bug #476: Auto-Moving allows player movement after using DisablePlayerControls
-Bug #478: After sleeping in a bed the rest dialogue window opens automtically again
-Bug #492: On creating potions the ingredients are removed twice
-Feature #63: Mercantile skill
-Feature #82: Persuasion Dialogue
-Feature #219: Missing dialogue filters/functions
-Feature #369: Add a FailedAction
-Feature #377: Select head/hair on character creation
-Feature #391: Dummy AI package classes
-Feature #435: Global Map, 2nd Layer
-Feature #450: Persuasion
-Feature #457: Add more script instructions
-Feature #474: update the global variable pcrace when the player's race is changed
-Task #158: Move dynamically generated classes from Player class to World Class
-Task #159: ESMStore rework and cleanup
-Task #163: More Component Namespace Cleanup
-Task #402: Move player data from MWWorld::Player to the player's NPC record
-Task #446: Fix no namespace in BulletShapeLoader
+------
+
+    Bug #366: Changing the player's race during character creation does not change the look of the player character
+    Bug #430: Teleporting and using loading doors linking within the same cell reloads the cell
+    Bug #437: Stop animations when paused
+    Bug #438: Time displays as "0 a.m." when it should be "12 a.m."
+    Bug #439: Text in "name" field of potion/spell creation window is persistent
+    Bug #440: Starting date at a new game is off by one day
+    Bug #442: Console window doesn't close properly sometimes
+    Bug #448: Do not break container window formatting when item names are very long
+    Bug #458: Topics sometimes not automatically added to known topic list
+    Bug #476: Auto-Moving allows player movement after using DisablePlayerControls
+    Bug #478: After sleeping in a bed the rest dialogue window opens automtically again
+    Bug #492: On creating potions the ingredients are removed twice
+    Feature #63: Mercantile skill
+    Feature #82: Persuasion Dialogue
+    Feature #219: Missing dialogue filters/functions
+    Feature #369: Add a FailedAction
+    Feature #377: Select head/hair on character creation
+    Feature #391: Dummy AI package classes
+    Feature #435: Global Map, 2nd Layer
+    Feature #450: Persuasion
+    Feature #457: Add more script instructions
+    Feature #474: update the global variable pcrace when the player's race is changed
+    Task #158: Move dynamically generated classes from Player class to World Class
+    Task #159: ESMStore rework and cleanup
+    Task #163: More Component Namespace Cleanup
+    Task #402: Move player data from MWWorld::Player to the player's NPC record
+    Task #446: Fix no namespace in BulletShapeLoader
 
 0.19.0
-
-Bug #374: Character shakes in 3rd person mode near the origin
-Bug #404: Gamma correct rendering
-Bug #407: Shoes of St. Rilm do not work
-Bug #408: Rugs has collision even if they are not supposed to
-Bug #412: Birthsign menu sorted incorrectly
-Bug #413: Resolutions presented multiple times in launcher
-Bug #414: launcher.cfg file stored in wrong directory
-Bug #415: Wrong esm order in openmw.cfg
-Bug #418: Sound listener position updates incorrectly
-Bug #423: wrong usage of "Version" entry in openmw.desktop
-Bug #426: Do not use hardcoded splash images
-Bug #431: Don't use markers for raycast
-Bug #432: Crash after picking up items from an NPC
-Feature #21/#95: Sleeping/resting
-Feature #61: Alchemy Skill
-Feature #68: Death
-Feature #69/#86: Spell Creation
-Feature #72/#84: Travel
-Feature #76: Global Map, 1st Layer
-Feature #120: Trainer Window
-Feature #152: Skill Increase from Skill Books
-Feature #160: Record Saving
-Task #400: Review GMST access
+------
+
+    Bug #374: Character shakes in 3rd person mode near the origin
+    Bug #404: Gamma correct rendering
+    Bug #407: Shoes of St. Rilm do not work
+    Bug #408: Rugs has collision even if they are not supposed to
+    Bug #412: Birthsign menu sorted incorrectly
+    Bug #413: Resolutions presented multiple times in launcher
+    Bug #414: launcher.cfg file stored in wrong directory
+    Bug #415: Wrong esm order in openmw.cfg
+    Bug #418: Sound listener position updates incorrectly
+    Bug #423: wrong usage of "Version" entry in openmw.desktop
+    Bug #426: Do not use hardcoded splash images
+    Bug #431: Don't use markers for raycast
+    Bug #432: Crash after picking up items from an NPC
+    Feature #21/#95: Sleeping/resting
+    Feature #61: Alchemy Skill
+    Feature #68: Death
+    Feature #69/#86: Spell Creation
+    Feature #72/#84: Travel
+    Feature #76: Global Map, 1st Layer
+    Feature #120: Trainer Window
+    Feature #152: Skill Increase from Skill Books
+    Feature #160: Record Saving
+    Task #400: Review GMST access
 
 0.18.0
-
-Bug #310: Button of the "preferences menu" are too small
-Bug #361: Hand-to-hand skill is always 100
-Bug #365: NPC and creature animation is jerky; Characters float around when they are not supposed to
-Bug #372: playSound3D uses original coordinates instead of current coordinates.
-Bug #373: Static OGRE build faulty
-Bug #375: Alt-tab toggle view
-Bug #376: Screenshots are disable
-Bug #378: Exception when drinking self-made potions
-Bug #380: Cloth visibility problem
-Bug #384: Weird character on doors tooltip.
-Bug #398: Some objects do not collide in MW, but do so in OpenMW
-Feature #22: Implement level-up
-Feature #36: Hide Marker
-Feature #88: Hotkey Window
-Feature #91: Level-Up Dialogue
-Feature #118: Keyboard and Mouse-Button bindings
-Feature #119: Spell Buying Window
-Feature #133: Handle resources across multiple data directories
-Feature #134: Generate a suitable default-value for --data-local
-Feature #292: Object Movement/Creation Script Instructions
-Feature #340: AIPackage data structures
-Feature #356: Ingredients use
-Feature #358: Input system rewrite
-Feature #370: Target handling in actions
-Feature #379: Door markers on the local map
-Feature #389: AI framework
-Feature #395: Using keys to open doors / containers
-Feature #396: Loading screens
-Feature #397: Inventory avatar image and race selection head preview
-Task #339: Move sounds into Action
+------
+
+    Bug #310: Button of the "preferences menu" are too small
+    Bug #361: Hand-to-hand skill is always 100
+    Bug #365: NPC and creature animation is jerky; Characters float around when they are not supposed to
+    Bug #372: playSound3D uses original coordinates instead of current coordinates.
+    Bug #373: Static OGRE build faulty
+    Bug #375: Alt-tab toggle view
+    Bug #376: Screenshots are disable
+    Bug #378: Exception when drinking self-made potions
+    Bug #380: Cloth visibility problem
+    Bug #384: Weird character on doors tooltip.
+    Bug #398: Some objects do not collide in MW, but do so in OpenMW
+    Feature #22: Implement level-up
+    Feature #36: Hide Marker
+    Feature #88: Hotkey Window
+    Feature #91: Level-Up Dialogue
+    Feature #118: Keyboard and Mouse-Button bindings
+    Feature #119: Spell Buying Window
+    Feature #133: Handle resources across multiple data directories
+    Feature #134: Generate a suitable default-value for --data-local
+    Feature #292: Object Movement/Creation Script Instructions
+    Feature #340: AIPackage data structures
+    Feature #356: Ingredients use
+    Feature #358: Input system rewrite
+    Feature #370: Target handling in actions
+    Feature #379: Door markers on the local map
+    Feature #389: AI framework
+    Feature #395: Using keys to open doors / containers
+    Feature #396: Loading screens
+    Feature #397: Inventory avatar image and race selection head preview
+    Task #339: Move sounds into Action
 
 0.17.0
-
-Bug #225: Valgrind reports about 40MB of leaked memory
-Bug #241: Some physics meshes still don't match
-Bug #248: Some textures are too dark
-Bug #300: Dependency on proprietary CG toolkit
-Bug #302: Some objects don't collide although they should
-Bug #308: Freeze in Balmora, Meldor: Armorer
-Bug #313: openmw without a ~/.config/openmw folder segfault.
-Bug #317: adding non-existing spell via console locks game
-Bug #318: Wrong character normals
-Bug #341: Building with Ogre Debug libraries does not use debug version of plugins
-Bug #347: Crash when running openmw with --start="XYZ"
-Bug #353: FindMyGUI.cmake breaks path on Windows
-Bug #359: WindowManager throws exception at destruction
-Bug #364: Laggy input on OS X due to bug in Ogre's event pump implementation
-Feature #33: Allow objects to cross cell-borders
-Feature #59: Dropping Items (replaced stopgap implementation with a proper one)
-Feature #93: Main Menu
-Feature #96/329/330/331/332/333: Player Control
-Feature #180: Object rotation and scaling.
-Feature #272: Incorrect NIF material sharing
-Feature #314: Potion usage
-Feature #324: Skill Gain
-Feature #342: Drain/fortify dynamic stats/attributes magic effects
-Feature #350: Allow console only script instructions
-Feature #352: Run scripts in console on startup
-Task #107: Refactor mw*-subsystems
-Task #325: Make CreatureStats into a class
-Task #345: Use Ogre's animation system
-Task #351: Rewrite Action class to support automatic sound playing
+------
+
+    Bug #225: Valgrind reports about 40MB of leaked memory
+    Bug #241: Some physics meshes still don't match
+    Bug #248: Some textures are too dark
+    Bug #300: Dependency on proprietary CG toolkit
+    Bug #302: Some objects don't collide although they should
+    Bug #308: Freeze in Balmora, Meldor: Armorer
+    Bug #313: openmw without a ~/.config/openmw folder segfault.
+    Bug #317: adding non-existing spell via console locks game
+    Bug #318: Wrong character normals
+    Bug #341: Building with Ogre Debug libraries does not use debug version of plugins
+    Bug #347: Crash when running openmw with --start="XYZ"
+    Bug #353: FindMyGUI.cmake breaks path on Windows
+    Bug #359: WindowManager throws exception at destruction
+    Bug #364: Laggy input on OS X due to bug in Ogre's event pump implementation
+    Feature #33: Allow objects to cross cell-borders
+    Feature #59: Dropping Items (replaced stopgap implementation with a proper one)
+    Feature #93: Main Menu
+    Feature #96/329/330/331/332/333: Player Control
+    Feature #180: Object rotation and scaling.
+    Feature #272: Incorrect NIF material sharing
+    Feature #314: Potion usage
+    Feature #324: Skill Gain
+    Feature #342: Drain/fortify dynamic stats/attributes magic effects
+    Feature #350: Allow console only script instructions
+    Feature #352: Run scripts in console on startup
+    Task #107: Refactor mw*-subsystems
+    Task #325: Make CreatureStats into a class
+    Task #345: Use Ogre's animation system
+    Task #351: Rewrite Action class to support automatic sound playing
 
 0.16.0
-
-Bug #250: OpenMW launcher erratic behaviour
-Bug #270: Crash because of underwater effect on OS X
-Bug #277: Auto-equipping in some cells not working
-Bug #294: Container GUI ignores disabled inventory menu
-Bug #297: Stats review dialog shows all skills and attribute values as 0
-Bug #298: MechanicsManager::buildPlayer does not remove previous bonuses
-Bug #299: Crash in World::disable
-Bug #306: Non-existent ~/.config/openmw "crash" the launcher.
-Bug #307: False "Data Files" location make the launcher "crash"
-Feature #81: Spell Window
-Feature #85: Alchemy Window
-Feature #181: Support for x.y script syntax
-Feature #242: Weapon and Spell icons
-Feature #254: Ingame settings window
-Feature #293: Allow "stacking" game modes
-Feature #295: Class creation dialog tooltips
-Feature #296: Clicking on the HUD elements should show/hide the respective window
-Feature #301: Direction after using a Teleport Door
-Feature #303: Allow object selection in the console
-Feature #305: Allow the use of = as a synonym for ==
-Feature #312: Compensation for slow object access in poorly written Morrowind.esm scripts
-Task #176: Restructure enabling/disabling of MW-references
-Task #283: Integrate ogre.cfg file in settings file
-Task #290: Auto-Close MW-reference related GUI windows
+------
+
+    Bug #250: OpenMW launcher erratic behaviour
+    Bug #270: Crash because of underwater effect on OS X
+    Bug #277: Auto-equipping in some cells not working
+    Bug #294: Container GUI ignores disabled inventory menu
+    Bug #297: Stats review dialog shows all skills and attribute values as 0
+    Bug #298: MechanicsManager::buildPlayer does not remove previous bonuses
+    Bug #299: Crash in World::disable
+    Bug #306: Non-existent ~/.config/openmw "crash" the launcher.
+    Bug #307: False "Data Files" location make the launcher "crash"
+    Feature #81: Spell Window
+    Feature #85: Alchemy Window
+    Feature #181: Support for x.y script syntax
+    Feature #242: Weapon and Spell icons
+    Feature #254: Ingame settings window
+    Feature #293: Allow "stacking" game modes
+    Feature #295: Class creation dialog tooltips
+    Feature #296: Clicking on the HUD elements should show/hide the respective window
+    Feature #301: Direction after using a Teleport Door
+    Feature #303: Allow object selection in the console
+    Feature #305: Allow the use of = as a synonym for ==
+    Feature #312: Compensation for slow object access in poorly written Morrowind.esm scripts
+    Task #176: Restructure enabling/disabling of MW-references
+    Task #283: Integrate ogre.cfg file in settings file
+    Task #290: Auto-Close MW-reference related GUI windows
 
 0.15.0
-
-Bug #5: Physics reimplementation (fixes various issues)
-Bug #258: Resizing arrow's background is not transparent
-Bug #268: Widening the stats window in X direction causes layout problems
-Bug #269: Topic pane in dialgoue window is too small for some longer topics
-Bug #271: Dialog choices are sorted incorrectly
-Bug #281: The single quote character is not rendered on dialog windows
-Bug #285: Terrain not handled properly in cells that are not predefined
-Bug #289: Dialogue filter isn't doing case smashing/folding for item IDs
-Feature #15: Collision with Terrain
-Feature #17: Inventory-, Container- and Trade-Windows
-Feature #44: Floating Labels above Focussed Objects
-Feature #80: Tooltips
-Feature #83: Barter Dialogue
-Feature #90: Book and Scroll Windows
-Feature #156: Item Stacking in Containers
-Feature #213: Pulsating lights
-Feature #218: Feather & Burden
-Feature #256: Implement magic effect bookkeeping
-Feature #259: Add missing information to Stats window
-Feature #260: Correct case for dialogue topics
-Feature #280: GUI texture atlasing
-Feature #291: Ability to use GMST strings from GUI layout files
-Task #255: Make MWWorld::Environment into a singleton
+------
+
+    Bug #5: Physics reimplementation (fixes various issues)
+    Bug #258: Resizing arrow's background is not transparent
+    Bug #268: Widening the stats window in X direction causes layout problems
+    Bug #269: Topic pane in dialgoue window is too small for some longer topics
+    Bug #271: Dialog choices are sorted incorrectly
+    Bug #281: The single quote character is not rendered on dialog windows
+    Bug #285: Terrain not handled properly in cells that are not predefined
+    Bug #289: Dialogue filter isn't doing case smashing/folding for item IDs
+    Feature #15: Collision with Terrain
+    Feature #17: Inventory-, Container- and Trade-Windows
+    Feature #44: Floating Labels above Focussed Objects
+    Feature #80: Tooltips
+    Feature #83: Barter Dialogue
+    Feature #90: Book and Scroll Windows
+    Feature #156: Item Stacking in Containers
+    Feature #213: Pulsating lights
+    Feature #218: Feather & Burden
+    Feature #256: Implement magic effect bookkeeping
+    Feature #259: Add missing information to Stats window
+    Feature #260: Correct case for dialogue topics
+    Feature #280: GUI texture atlasing
+    Feature #291: Ability to use GMST strings from GUI layout files
+    Task #255: Make MWWorld::Environment into a singleton
 
 0.14.0
-
-Bug #1: Meshes rendered with wrong orientation
-Bug #6/Task #220: Picking up small objects doesn't always work
-Bug #127: tcg doesn't work
-Bug #178: Compablity problems with Ogre 1.8.0 RC 1
-Bug #211: Wireframe mode (toggleWireframe command) should not apply to Console & other UI
-Bug #227: Terrain crashes when moving away from predefined cells
-Bug #229: On OS X Launcher cannot launch game if path to binary contains spaces
-Bug #235: TGA texture loading problem
-Bug #246: wireframe mode does not work in water
-Feature #8/#232: Water Rendering
-Feature #13: Terrain Rendering
-Feature #37: Render Path Grid
-Feature #66: Factions
-Feature #77: Local Map
-Feature #78: Compass/Mini-Map
-Feature #97: Render Clothing/Armour
-Feature #121: Window Pinning
-Feature #205: Auto equip
-Feature #217: Contiainer should track changes to its content
-Feature #221: NPC Dialogue Window Enhancements
-Feature #233: Game settings manager
-Feature #240: Spell List and selected spell (no GUI yet)
-Feature #243: Draw State
-Task #113: Morrowind.ini Importer
-Task #215: Refactor the sound code
-Task #216: Update MyGUI
+------
+
+    Bug #1: Meshes rendered with wrong orientation
+    Bug #6/Task #220: Picking up small objects doesn't always work
+    Bug #127: tcg doesn't work
+    Bug #178: Compablity problems with Ogre 1.8.0 RC 1
+    Bug #211: Wireframe mode (toggleWireframe command) should not apply to Console & other UI
+    Bug #227: Terrain crashes when moving away from predefined cells
+    Bug #229: On OS X Launcher cannot launch game if path to binary contains spaces
+    Bug #235: TGA texture loading problem
+    Bug #246: wireframe mode does not work in water
+    Feature #8/#232: Water Rendering
+    Feature #13: Terrain Rendering
+    Feature #37: Render Path Grid
+    Feature #66: Factions
+    Feature #77: Local Map
+    Feature #78: Compass/Mini-Map
+    Feature #97: Render Clothing/Armour
+    Feature #121: Window Pinning
+    Feature #205: Auto equip
+    Feature #217: Contiainer should track changes to its content
+    Feature #221: NPC Dialogue Window Enhancements
+    Feature #233: Game settings manager
+    Feature #240: Spell List and selected spell (no GUI yet)
+    Feature #243: Draw State
+    Task #113: Morrowind.ini Importer
+    Task #215: Refactor the sound code
+    Task #216: Update MyGUI
 
 0.13.0
-
-Bug #145: Fixed sound problems after cell change
-Bug #179: Pressing space in console triggers activation
-Bug #186: CMake doesn't use the debug versions of Ogre libraries on Linux
-Bug #189: ASCII 16 character added to console on it's activation on Mac OS X
-Bug #190: Case Folding fails with music files
-Bug #192: Keypresses write Text into Console no matter which gui element is active
-Bug #196: Collision shapes out of place
-Bug #202: ESMTool doesn't not work with localised ESM files anymore
-Bug #203: Torch lights only visible on short distance
-Bug #207: Ogre.log not written
-Bug #209: Sounds do not play
-Bug #210: Ogre crash at Dren plantation
-Bug #214: Unsupported file format version
-Bug #222: Launcher is writing openmw.cfg file to wrong location
-Feature #9: NPC Dialogue Window
-Feature #16/42: New sky/weather implementation
-Feature #40: Fading
-Feature #48: NPC Dialogue System
-Feature #117: Equipping Items (backend only, no GUI yet, no rendering of equipped items yet)
-Feature #161: Load REC_PGRD records
-Feature #195: Wireframe-mode
-Feature #198/199: Various sound effects
-Feature #206: Allow picking data path from launcher if non is set
-Task #108: Refactor window manager class
-Task #172: Sound Manager Cleanup
-Task #173: Create OpenEngine systems in the appropriate manager classes
-Task #184: Adjust MSVC and gcc warning levels
-Task #185: RefData rewrite
-Task #201: Workaround for transparency issues
-Task #208: silenced esm_reader.hpp warning
+------
+
+    Bug #145: Fixed sound problems after cell change
+    Bug #179: Pressing space in console triggers activation
+    Bug #186: CMake doesn't use the debug versions of Ogre libraries on Linux
+    Bug #189: ASCII 16 character added to console on it's activation on Mac OS X
+    Bug #190: Case Folding fails with music files
+    Bug #192: Keypresses write Text into Console no matter which gui element is active
+    Bug #196: Collision shapes out of place
+    Bug #202: ESMTool doesn't not work with localised ESM files anymore
+    Bug #203: Torch lights only visible on short distance
+    Bug #207: Ogre.log not written
+    Bug #209: Sounds do not play
+    Bug #210: Ogre crash at Dren plantation
+    Bug #214: Unsupported file format version
+    Bug #222: Launcher is writing openmw.cfg file to wrong location
+    Feature #9: NPC Dialogue Window
+    Feature #16/42: New sky/weather implementation
+    Feature #40: Fading
+    Feature #48: NPC Dialogue System
+    Feature #117: Equipping Items (backend only, no GUI yet, no rendering of equipped items yet)
+    Feature #161: Load REC_PGRD records
+    Feature #195: Wireframe-mode
+    Feature #198/199: Various sound effects
+    Feature #206: Allow picking data path from launcher if non is set
+    Task #108: Refactor window manager class
+    Task #172: Sound Manager Cleanup
+    Task #173: Create OpenEngine systems in the appropriate manager classes
+    Task #184: Adjust MSVC and gcc warning levels
+    Task #185: RefData rewrite
+    Task #201: Workaround for transparency issues
+    Task #208: silenced esm_reader.hpp warning
 
 0.12.0
-
-Bug #154: FPS Drop
-Bug #169: Local scripts continue running if associated object is deleted
-Bug #174: OpenMW fails to start if the config directory doesn't exist
-Bug #187: Missing lighting
-Bug #188: Lights without a mesh are not rendered
-Bug #191: Taking screenshot causes crash when running installed
-Feature #28: Sort out the cell load problem
-Feature #31: Allow the player to move away from pre-defined cells
-Feature #35: Use alternate storage location for modified object position
-Feature #45: NPC animations
-Feature #46: Creature Animation
-Feature #89: Basic Journal Window
-Feature #110: Automatically pick up the path of existing MW-installations
-Feature #183: More FPS display settings
-Task #19: Refactor engine class
-Task #109/Feature #162: Automate Packaging
-Task #112: Catch exceptions thrown in input handling functions
-Task #128/#168: Cleanup Configuration File Handling
-Task #131: NPC Activation doesn't work properly
-Task #144: MWRender cleanup
-Task #155: cmake cleanup
+------
+
+    Bug #154: FPS Drop
+    Bug #169: Local scripts continue running if associated object is deleted
+    Bug #174: OpenMW fails to start if the config directory doesn't exist
+    Bug #187: Missing lighting
+    Bug #188: Lights without a mesh are not rendered
+    Bug #191: Taking screenshot causes crash when running installed
+    Feature #28: Sort out the cell load problem
+    Feature #31: Allow the player to move away from pre-defined cells
+    Feature #35: Use alternate storage location for modified object position
+    Feature #45: NPC animations
+    Feature #46: Creature Animation
+    Feature #89: Basic Journal Window
+    Feature #110: Automatically pick up the path of existing MW-installations
+    Feature #183: More FPS display settings
+    Task #19: Refactor engine class
+    Task #109/Feature #162: Automate Packaging
+    Task #112: Catch exceptions thrown in input handling functions
+    Task #128/#168: Cleanup Configuration File Handling
+    Task #131: NPC Activation doesn't work properly
+    Task #144: MWRender cleanup
+    Task #155: cmake cleanup
 
 0.11.1
-
-Bug #2: Resources loading doesn't work outside of bsa files
-Bug #3: GUI does not render non-English characters
-Bug #7: openmw.cfg location doesn't match
-Bug #124: The TCL alias for ToggleCollision is missing.
-Bug #125: Some command line options can't be used from a .cfg file
-Bug #126: Toggle-type script instructions are less verbose compared with original MW
-Bug #130: NPC-Record Loading fails for some NPCs
-Bug #167: Launcher sets invalid parameters in ogre config
-Feature #10: Journal
-Feature #12: Rendering Optimisations
-Feature #23: Change Launcher GUI to a tabbed interface
-Feature #24: Integrate the OGRE settings window into the launcher
-Feature #25: Determine openmw.cfg location (Launcher)
-Feature #26: Launcher Profiles
-Feature #79: MessageBox
-Feature #116: Tab-Completion in Console
-Feature #132: --data-local and multiple --data
-Feature #143: Non-Rendering Performance-Optimisations
-Feature #150: Accessing objects in cells via ID does only work for objects with all lower case IDs
-Feature #157: Version Handling
-Task #14: Replace tabs with 4 spaces
-Task #18: Move components from global namespace into their own namespace
-Task #123: refactor header files in components/esm
+------
+
+    Bug #2: Resources loading doesn't work outside of bsa files
+    Bug #3: GUI does not render non-English characters
+    Bug #7: openmw.cfg location doesn't match
+    Bug #124: The TCL alias for ToggleCollision is missing.
+    Bug #125: Some command line options can't be used from a .cfg file
+    Bug #126: Toggle-type script instructions are less verbose compared with original MW
+    Bug #130: NPC-Record Loading fails for some NPCs
+    Bug #167: Launcher sets invalid parameters in ogre config
+    Feature #10: Journal
+    Feature #12: Rendering Optimisations
+    Feature #23: Change Launcher GUI to a tabbed interface
+    Feature #24: Integrate the OGRE settings window into the launcher
+    Feature #25: Determine openmw.cfg location (Launcher)
+    Feature #26: Launcher Profiles
+    Feature #79: MessageBox
+    Feature #116: Tab-Completion in Console
+    Feature #132: --data-local and multiple --data
+    Feature #143: Non-Rendering Performance-Optimisations
+    Feature #150: Accessing objects in cells via ID does only work for objects with all lower case IDs
+    Feature #157: Version Handling
+    Task #14: Replace tabs with 4 spaces
+    Task #18: Move components from global namespace into their own namespace
+    Task #123: refactor header files in components/esm
 
 0.10.0
+------
 
 * NPC dialogue window (not functional yet)
 * Collisions with objects
@@ -1384,6 +1409,7 @@ Task #123: refactor header files in components/esm
 * Mac OS X support is back!
 
 0.9.0
+-----
 
 * Exterior cells loading, unloading and management
 * Character Creation GUI
@@ -1393,6 +1419,7 @@ Task #123: refactor header files in components/esm
 * NPCs rendering
 
 0.8.0
+-----
 
 * GUI
 * Complete and working script engine
@@ -1402,12 +1429,14 @@ Task #123: refactor header files in components/esm
 * Tons of smaller stuff
 
 0.7.0
+-----
 
 * This release is a complete rewrite in C++.
 * All D code has been culled, and all modules have been rewritten.
 * The game is now back up to the level of rendering interior cells and moving around, but physics, sound, GUI, and scripting still remain to be ported from the old codebase.
 
 0.6.0
+-----
 
 * Coded a GUI system using MyGUI
 * Skinned MyGUI to look like Morrowind (work in progress)
@@ -1417,6 +1446,7 @@ Task #123: refactor header files in components/esm
 * Fixed Windows sound problems (replaced old openal32.dll)
 
 0.5.0
+-----
 
 * Collision detection with Bullet
 * Experimental walk & fall character physics
@@ -1428,6 +1458,7 @@ Task #123: refactor header files in components/esm
 * Various minor changes and updates
 
 0.4.0
+-----
 
 * Switched from Audiere to OpenAL
 * * (BIG thanks to Chris Robinson)
@@ -1440,6 +1471,7 @@ Task #123: refactor header files in components/esm
 * Cosmetic changes to placate gdc Wall
 
 0.3.0
+-----
 
 * Built and tested on Windows XP
 * Partial support for FreeBSD (exceptions do not work)
@@ -1454,12 +1486,13 @@ Task #123: refactor header files in components/esm
 * confirmed to work against OIS 1.0.0 (Ubuntu repository package)
 
 0.2.0
+-----
 
 * Compiles with gdc
 * Switched to DSSS for building D code
 * Includes the program esmtool
 
 0.1.0
+-----
 
 first release
-
From bc51fe4ec2a3db5df1d78f51364bdbf7ece02e86 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 10 Jan 2015 17:22:12 +0100 Subject: [PATCH 0270/3725] Use indent instead of
 in AUTHORS.md (looks
 nicer in plaintext mode)

---
 AUTHORS.md | 331 ++++++++++++++++++++++++++---------------------------
 1 file changed, 165 insertions(+), 166 deletions(-)

diff --git a/AUTHORS.md b/AUTHORS.md
index f6da26e77..d2c5cdc04 100644
--- a/AUTHORS.md
+++ b/AUTHORS.md
@@ -9,184 +9,183 @@ If you feel your name is missing from this list, please notify a developer.
 
 Programmers
 -----------
-
-Marc Zinnschlag (Zini) - Lead Programmer/Project Manager
-
-Adam Hogan (aurix)
-Aleksandar Jovanov
-Alex Haddad (rainChu)
-Alex McKibben (WeirdSexy)
-Alexander Nadeau (wareya)
-Alexander Olofsson (Ace)
-Artem Kotsynyak (greye)
-Arthur Moore (EmperorArthur)
-athile
-Bret Curtis (psi29a)
-Britt Mathis (galdor557)
-cc9cii
-Chris Boyce (slothlife)
-Chris Robinson (KittyCat)
-Cory F. Cohen (cfcohen)
-Cris Mihalache (Mirceam)
-darkf
-Dmitry Shkurskiy (endorph)
-Douglas Diniz (Dgdiniz)
-Douglas Mencken (dougmencken)
-dreamer-dead
-dteviot
-Edmondo Tommasina (edmondo)
-Eduard Cot (trombonecot)
-Eli2
-Emanuel Guével (potatoesmaster)
-eroen
-Fil Krynicki (filkry)
-Gašper Sedej
-gugus/gus
-Hallfaer Tuilinn
-Internecine
-Jacob Essex (Yacoby)
-Jannik Heller (scrawl)
-Jason Hooks (jhooks)
-jeaye
-Jeffrey Haines (Jyby)
-Jengerer
-Joel Graff (graffy)
-John Blomberg (fstp)
-Jordan Ayers
-Jordan Milne
-Julien Voisin (jvoisin/ap0)
-Karl-Felix Glatzer (k1ll)
-Kevin Poitra (PuppyKevin)
-Lars Söderberg (Lazaroth)
-lazydev
-Leon Saunders (emoose)
-Lukasz Gromanowski (lgro)
-Manuel Edelmann (vorenon)
-Marc Bouvier (CramitDeFrog)
-Marcin Hulist (Gohan)
-Mark Siewert (mark76)
-Marco Melletti (mellotanica)
-Marco Schulze
-Mateusz Kołaczek (PL_kolek)
-megaton
-Michael Hogan (Xethik)
-Michael Mc Donnell
-Michael Papageorgiou (werdanith)
-Michał Bień (Glorf)
-Miroslav Puda (pakanek)
-MiroslavR
-Narmo
-Nathan Jeffords (blunted2night)
-Nikolay Kasyanov (corristo)
-nobrakal
-Nolan Poe (nopoe)
-Paul McElroy (Greendogo)
-Pieter van der Kloet (pvdk)
-Radu-Marius Popovici (rpopovici)
-riothamus
-Robert MacGregor (Ragora)
-Rohit Nirmal
-Roman Melnik (Kromgart)
-Roman Proskuryakov (humbug)
-sandstranger
-Sandy Carter (bwrsandman)
-Scott Howard
-Sebastian Wick (swick)
-Sergey Shambir
-sir_herrbatka
-Stefan Galowicz (bogglez)
-Stanislav Bobrov (Jiub)
-Sylvain Thesnieres (Garvek)
-terrorfisch
-Thomas Luppi (Digmaster)
-Tom Mason (wheybags)
-Torben Leif Carrington (TorbenC)
-viadanna
-Vincent Heuken
-vocollapse
-
+ + Marc Zinnschlag (Zini) - Lead Programmer/Project Manager + + Adam Hogan (aurix) + Aleksandar Jovanov + Alex Haddad (rainChu) + Alex McKibben (WeirdSexy) + Alexander Nadeau (wareya) + Alexander Olofsson (Ace) + Artem Kotsynyak (greye) + Arthur Moore (EmperorArthur) + athile + Bret Curtis (psi29a) + Britt Mathis (galdor557) + cc9cii + Chris Boyce (slothlife) + Chris Robinson (KittyCat) + Cory F. Cohen (cfcohen) + Cris Mihalache (Mirceam) + darkf + Dmitry Shkurskiy (endorph) + Douglas Diniz (Dgdiniz) + Douglas Mencken (dougmencken) + dreamer-dead + dteviot + Edmondo Tommasina (edmondo) + Eduard Cot (trombonecot) + Eli2 + Emanuel Guével (potatoesmaster) + eroen + Fil Krynicki (filkry) + Gašper Sedej + gugus/gus + Hallfaer Tuilinn + Internecine + Jacob Essex (Yacoby) + Jannik Heller (scrawl) + Jason Hooks (jhooks) + jeaye + Jeffrey Haines (Jyby) + Jengerer + Joel Graff (graffy) + John Blomberg (fstp) + Jordan Ayers + Jordan Milne + Julien Voisin (jvoisin/ap0) + Karl-Felix Glatzer (k1ll) + Kevin Poitra (PuppyKevin) + Lars Söderberg (Lazaroth) + lazydev + Leon Saunders (emoose) + Lukasz Gromanowski (lgro) + Manuel Edelmann (vorenon) + Marc Bouvier (CramitDeFrog) + Marcin Hulist (Gohan) + Mark Siewert (mark76) + Marco Melletti (mellotanica) + Marco Schulze + Mateusz Kołaczek (PL_kolek) + megaton + Michael Hogan (Xethik) + Michael Mc Donnell + Michael Papageorgiou (werdanith) + Michał Bień (Glorf) + Miroslav Puda (pakanek) + MiroslavR + Narmo + Nathan Jeffords (blunted2night) + Nikolay Kasyanov (corristo) + nobrakal + Nolan Poe (nopoe) + Paul McElroy (Greendogo) + Pieter van der Kloet (pvdk) + Radu-Marius Popovici (rpopovici) + riothamus + Robert MacGregor (Ragora) + Rohit Nirmal + Roman Melnik (Kromgart) + Roman Proskuryakov (humbug) + sandstranger + Sandy Carter (bwrsandman) + Scott Howard + Sebastian Wick (swick) + Sergey Shambir + sir_herrbatka + Stefan Galowicz (bogglez) + Stanislav Bobrov (Jiub) + Sylvain Thesnieres (Garvek) + terrorfisch + Thomas Luppi (Digmaster) + Tom Mason (wheybags) + Torben Leif Carrington (TorbenC) + viadanna + Vincent Heuken + vocollapse + Packagers --------- -
-Alexander Olofsson (Ace) - Windows
-Bret Curtis (psi29a) - Ubuntu Linux
-Edmondo Tommasina (edmondo) - Gentoo Linux
-Julian Ospald (hasufell) - Gentoo Linux
-Karl-Felix Glatzer (k1ll) - Linux Binaries
-Kenny Armstrong (artorius) - Fedora Linux
-Nikolay Kasyanov (corristo) - Mac OS X
-Sandy Carter (bwrsandman) - Arch Linux
-
+ + Alexander Olofsson (Ace) - Windows + Bret Curtis (psi29a) - Ubuntu Linux + Edmondo Tommasina (edmondo) - Gentoo Linux + Julian Ospald (hasufell) - Gentoo Linux + Karl-Felix Glatzer (k1ll) - Linux Binaries + Kenny Armstrong (artorius) - Fedora Linux + Nikolay Kasyanov (corristo) - Mac OS X + Sandy Carter (bwrsandman) - Arch Linux + Public Relations and Translations --------------------------------- -
-Alex McKibben (WeirdSexy) - Podcaster
-Artem Kotsynyak (greye) - Russian News Writer
-Jim Clauwaert (Zedd) - Public Outreach
-Julien Voisin (jvoisin/ap0) - French News Writer
-Tom Koenderink (Okulo) - English News Writer
-Lukasz Gromanowski (lgro) - English News Writer
-Mickey Lyle (raevol) - Release Manager
-Pithorn - Chinese News Writer
-sir_herrbatka - Polish News Writer
-Dawid Lakomy (Vedyimyn) - Polish News Writer
-
+ + Alex McKibben (WeirdSexy) - Podcaster + Artem Kotsynyak (greye) - Russian News Writer + Jim Clauwaert (Zedd) - Public Outreach + Julien Voisin (jvoisin/ap0) - French News Writer + Tom Koenderink (Okulo) - English News Writer + Lukasz Gromanowski (lgro) - English News Writer + Mickey Lyle (raevol) - Release Manager + Pithorn - Chinese News Writer + sir_herrbatka - Polish News Writer + Dawid Lakomy (Vedyimyn) - Polish News Writer + Website ------- -
-Lukasz Gromanowski (Lgro) - Website Administrator
-Ryan Sardonic (Wry) - Wiki Editor
-sir_herrbatka - Forum Administrator
-
+ + Lukasz Gromanowski (Lgro) - Website Administrator + Ryan Sardonic (Wry) - Wiki Editor + sir_herrbatka - Forum Administrator + Formula Research ---------------- -
-Hrnchamd
-Epsilon
-fragonard
-Greendogo
-HiPhish
-modred11
-Myckel
-natirips
-Sadler
-
+ + Hrnchamd + Epsilon + fragonard + Greendogo + HiPhish + modred11 + Myckel + natirips + Sadler + Artwork ------- -
-Necrod - OpenMW Logo
-Mickey Lyle (raevol) - Wordpress Theme
-Tom Koenderink (Okulo), SirHerrbatka, crysthala, Shnatsel - OpenMW Editor Icons
-
+ + Necrod - OpenMW Logo + Mickey Lyle (raevol) - Wordpress Theme + Tom Koenderink (Okulo), SirHerrbatka, crysthala, Shnatsel - OpenMW Editor Icons + Inactive Contributors --------------------- -
-Ardekantur
-Armin Preiml
-Berulacks
-Carl Maxwell
-Diggory Hardy
-Dmitry Marakasov (AMDmi3)
-ElderTroll
-guidoj
-Jan-Peter Nilsson (peppe)
-Jan Borsodi
-Josua Grawitter
-juanmnzsk8
-Kingpix
-Lordrea
-Michal Sciubidlo
-Nicolay Korslund
-Nekochan
-pchan3
-penguinroad
-psi29a
-sergoz
-spyboot
-Star-Demon
-Thoronador
-Yuri Krupenin
-
+ + Ardekantur + Armin Preiml + Berulacks + Carl Maxwell + Diggory Hardy + Dmitry Marakasov (AMDmi3) + ElderTroll + guidoj + Jan-Peter Nilsson (peppe) + Jan Borsodi + Josua Grawitter + juanmnzsk8 + Kingpix + Lordrea + Michal Sciubidlo + Nicolay Korslund + Nekochan + pchan3 + penguinroad + psi29a + sergoz + spyboot + Star-Demon + Thoronador + Yuri Krupenin Additional Credits ------------------ From 38c6859281ede92eb33fb5254f68b4b2c0386788 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 10 Jan 2015 17:27:38 +0100 Subject: [PATCH 0271/3725] Add some Getting Started links from the wiki to Readme --- README.md | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index ff5185b5d..8bc3c0280 100644 --- a/README.md +++ b/README.md @@ -16,15 +16,16 @@ Morrowind by Bethesda Softworks. You need to own and install the original game f Font Licenses: * DejaVuLGCSansMono.ttf: custom (see docs/license/DejaVu Font License.txt for more information) -Installation -============ - -Head to [Downloads](http://openmw.org/downloads/) to find a packaged release for your platform of choice. - -Build from source -================= - -https://wiki.openmw.org/index.php?title=Development_Environment_Setup +Getting Started +=============== + +* [Official forums](https://forum.openmw.org/) +* [Installation instructions](https://wiki.openmw.org/index.php?title=Installation_Instructions) +* [Build from source](https://wiki.openmw.org/index.php?title=Development_Environment_Setup) +* [Testing the game](https://wiki.openmw.org/index.php?title=Testing) +* [How to contribute](https://wiki.openmw.org/index.php?title=Contribution_Wanted) +* [Report a bug](http://bugs.openmw.org/projects/openmw) - read the [guidelines](before submitting your first bug!) +* [Known issues] (http://bugs.openmw.org/projects/openmw/issues?utf8=%E2%9C%93&set_filter=1&f%5B%5D=status_id&op%5Bstatus_id%5D=%3D&v%5Bstatus_id%5D%5B%5D=7&f%5B%5D=tracker_id&op%5Btracker_id%5D=%3D&v%5Btracker_id%5D%5B%5D=1&f%5B%5D=&c%5B%5D=project&c%5B%5D=tracker&c%5B%5D=status&c%5B%5D=priority&c%5B%5D=subject&c%5B%5D=assigned_to&c%5B%5D=updated_on&group_by=tracker) The data path ============= From d4740b7533fe06bad16db365cd1e63be51e7ca3e Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 10 Jan 2015 17:36:36 +0100 Subject: [PATCH 0272/3725] Formatting, link fix --- README.md | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 8bc3c0280..168684e8d 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -OpenMW: A reimplementation of The Elder Scrolls III: Morrowind -============================================================== +OpenMW +====== [![Build Status](https://travis-ci.org/OpenMW/openmw.svg?branch=coverity_scan)](https://travis-ci.org/OpenMW/openmw) @@ -17,23 +17,23 @@ Font Licenses: * DejaVuLGCSansMono.ttf: custom (see docs/license/DejaVu Font License.txt for more information) Getting Started -=============== +--------------- * [Official forums](https://forum.openmw.org/) * [Installation instructions](https://wiki.openmw.org/index.php?title=Installation_Instructions) * [Build from source](https://wiki.openmw.org/index.php?title=Development_Environment_Setup) * [Testing the game](https://wiki.openmw.org/index.php?title=Testing) * [How to contribute](https://wiki.openmw.org/index.php?title=Contribution_Wanted) -* [Report a bug](http://bugs.openmw.org/projects/openmw) - read the [guidelines](before submitting your first bug!) +* [Report a bug](http://bugs.openmw.org/projects/openmw) - read the [guidelines](https://wiki.openmw.org/index.php?title=Bug_Reporting_Guidelines) before submitting your first bug! * [Known issues] (http://bugs.openmw.org/projects/openmw/issues?utf8=%E2%9C%93&set_filter=1&f%5B%5D=status_id&op%5Bstatus_id%5D=%3D&v%5Bstatus_id%5D%5B%5D=7&f%5B%5D=tracker_id&op%5Btracker_id%5D=%3D&v%5Btracker_id%5D%5B%5D=1&f%5B%5D=&c%5B%5D=project&c%5B%5D=tracker&c%5B%5D=status&c%5B%5D=priority&c%5B%5D=subject&c%5B%5D=assigned_to&c%5B%5D=updated_on&group_by=tracker) The data path -============= +------------- The data path tells OpenMW where to find your Morrowind files. If you run the launcher, OpenMW should be able to pick up the location of these files on its own, if both Morrowind and OpenMW are installed properly (installing Morrowind under WINE is considered a proper install). Command line options -==================== +--------------------
 Syntax: openmw 
@@ -91,8 +91,3 @@ Allowed options:
   --no-grab                             Don't grab mouse cursor
   --activate-dist arg (=-1)             activation distance override
 
- -Changelog -========= - -See CHANGELOG.md From fcbf7d7deb602456f7140ebe68be428903d9371f Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 11 Jan 2015 08:33:33 +1300 Subject: [PATCH 0273/3725] Fixed string formatting minor error found by Mingun. --- apps/launcher/datafilespage.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index 8429aaadc..245665421 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -302,7 +302,7 @@ bool Launcher::DataFilesPage::showDeleteMessageBox (const QString &text) msgBox.setWindowTitle(tr("Delete Content List")); msgBox.setIcon(QMessageBox::Warning); msgBox.setStandardButtons(QMessageBox::Cancel); - msgBox.setText(tr("Are you sure you want to delete %0?").arg(text)); + msgBox.setText(tr("Are you sure you want to delete %1?").arg(text)); QAbstractButton *deleteButton = msgBox.addButton(tr("Delete"), QMessageBox::ActionRole); From 91571f51be4f6ecc339ffb2354e44cb35b55b5c3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 10 Jan 2015 15:27:03 +0100 Subject: [PATCH 0274/3725] Ogre crash workaround (Fixes #1745) --- apps/openmw/mwrender/animation.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index ea40721cb..bf161442e 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -169,6 +169,9 @@ struct AddGlow instance->setProperty("env_map", sh::makeProperty(new sh::BooleanValue(true))); instance->setProperty("env_map_color", sh::makeProperty(new sh::Vector3(mColor->x, mColor->y, mColor->z))); + // Workaround for crash in Ogre (https://bitbucket.org/sinbad/ogre/pull-request/447/fix-shadows-crash-for-textureunitstates/diff) + // Remove when the fix is merged + instance->getMaterial()->setShadowCasterMaterial("openmw_shadowcaster_noalpha"); } }; From 579f5d232f5ea87716f3bfb44272052325a7ba75 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 10 Jan 2015 23:21:39 +0100 Subject: [PATCH 0275/3725] Move interactive messageBox to separate function --- apps/openmw/mwbase/windowmanager.hpp | 4 ++- apps/openmw/mwdialogue/journalimp.cpp | 4 +-- apps/openmw/mwgui/windowmanagerimp.cpp | 35 +++++++++++++------- apps/openmw/mwgui/windowmanagerimp.hpp | 5 ++- apps/openmw/mwinput/inputmanagerimp.cpp | 3 +- apps/openmw/mwmechanics/npcstats.cpp | 6 ++-- apps/openmw/mwscript/containerextensions.cpp | 6 ++-- apps/openmw/mwscript/interpretercontext.cpp | 5 ++- apps/openmw/mwstate/statemanagerimp.cpp | 6 ++-- apps/openmw/mwworld/worldimp.cpp | 2 +- 10 files changed, 44 insertions(+), 32 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index fb35157e8..3e957ef14 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -240,9 +240,11 @@ namespace MWBase /** No guarentee of actually closing the window **/ virtual void exitCurrentGuiMode() = 0; - virtual void messageBox (const std::string& message, const std::vector& buttons = std::vector(), enum MWGui::ShowInDialogueMode showInDialogueMode = MWGui::ShowInDialogueMode_IfPossible) = 0; + virtual void messageBox (const std::string& message, enum MWGui::ShowInDialogueMode showInDialogueMode = MWGui::ShowInDialogueMode_IfPossible) = 0; virtual void staticMessageBox(const std::string& message) = 0; virtual void removeStaticMessageBox() = 0; + virtual void interactiveMessageBox (const std::string& message, + const std::vector& buttons = std::vector(), bool block=false) = 0; /// returns the index of the pressed button or -1 if no button was pressed (->MessageBoxmanager->InteractiveMessageBox) virtual int readPressedButton() = 0; diff --git a/apps/openmw/mwdialogue/journalimp.cpp b/apps/openmw/mwdialogue/journalimp.cpp index 9497347e3..e8d5375e1 100644 --- a/apps/openmw/mwdialogue/journalimp.cpp +++ b/apps/openmw/mwdialogue/journalimp.cpp @@ -92,9 +92,7 @@ namespace MWDialogue quest.addEntry (entry); // we are doing slicing on purpose here - std::vector empty; - std::string notification = "#{sJournalEntry}"; - MWBase::Environment::get().getWindowManager()->messageBox (notification, empty); + MWBase::Environment::get().getWindowManager()->messageBox ("#{sJournalEntry}"); } void Journal::setJournalIndex (const std::string& id, int index) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 5d737ec41..7d9e10d8f 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -805,19 +805,30 @@ namespace MWGui } } - void WindowManager::messageBox (const std::string& message, const std::vector& buttons, enum MWGui::ShowInDialogueMode showInDialogueMode) - { - if (buttons.empty()) { - /* If there are no buttons, and there is a dialogue window open, messagebox goes to the dialogue window */ - if (getMode() == GM_Dialogue && showInDialogueMode != MWGui::ShowInDialogueMode_Never) { - mDialogueWindow->addMessageBox(MyGUI::LanguageManager::getInstance().replaceTags(message)); - } else if (showInDialogueMode != MWGui::ShowInDialogueMode_Only) { - mMessageBoxManager->createMessageBox(message); + void WindowManager::interactiveMessageBox(const std::string &message, const std::vector &buttons, bool block) + { + mMessageBoxManager->createInteractiveMessageBox(message, buttons); + MWBase::Environment::get().getInputManager()->changeInputMode(isGuiMode()); + updateVisible(); + + if (block) + { + while (mMessageBoxManager->readPressedButton() == -1 + && !MWBase::Environment::get().getStateManager()->hasQuitRequest()) + { + MWBase::Environment::get().getInputManager()->update(0, true, false); + + mRendering->getWindow()->update(); } - } else { - mMessageBoxManager->createInteractiveMessageBox(message, buttons); - MWBase::Environment::get().getInputManager()->changeInputMode(isGuiMode()); - updateVisible(); + } + } + + void WindowManager::messageBox (const std::string& message, enum MWGui::ShowInDialogueMode showInDialogueMode) + { + if (getMode() == GM_Dialogue && showInDialogueMode != MWGui::ShowInDialogueMode_Never) { + mDialogueWindow->addMessageBox(MyGUI::LanguageManager::getInstance().replaceTags(message)); + } else if (showInDialogueMode != MWGui::ShowInDialogueMode_Only) { + mMessageBoxManager->createMessageBox(message); } } diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 015f200d5..44d5819c2 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -238,9 +238,12 @@ namespace MWGui ///Gracefully attempts to exit the topmost GUI mode virtual void exitCurrentGuiMode(); - virtual void messageBox (const std::string& message, const std::vector& buttons = std::vector(), enum MWGui::ShowInDialogueMode showInDialogueMode = MWGui::ShowInDialogueMode_IfPossible); + virtual void messageBox (const std::string& message, enum MWGui::ShowInDialogueMode showInDialogueMode = MWGui::ShowInDialogueMode_IfPossible); virtual void staticMessageBox(const std::string& message); virtual void removeStaticMessageBox(); + virtual void interactiveMessageBox (const std::string& message, + const std::vector& buttons = std::vector(), bool block=false); + virtual int readPressedButton (); ///< returns the index of the pressed button or -1 if no button was pressed (->MessageBoxmanager->InteractiveMessageBox) virtual void onFrame (float frameDuration); diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index ece189c75..846cce6a2 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -743,8 +743,7 @@ namespace MWInput { mEngine.screenshot(); - std::vector empty; - MWBase::Environment::get().getWindowManager()->messageBox ("Screenshot saved", empty); + MWBase::Environment::get().getWindowManager()->messageBox ("Screenshot saved"); } void InputManager::toggleInventory() diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index ec7b232a2..ba01caf95 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -257,18 +257,16 @@ void MWMechanics::NpcStats::increaseSkill(int skillIndex, const ESM::Class &clas /// \todo check if character is the player, if levelling is ever implemented for NPCs MWBase::Environment::get().getSoundManager ()->playSound ("skillraise", 1, 1); - std::vector noButtons; - std::stringstream message; message << boost::format(MWBase::Environment::get().getWindowManager ()->getGameSettingString ("sNotifyMessage39", "")) % std::string("#{" + ESM::Skill::sSkillNameIds[skillIndex] + "}") % static_cast (base); - MWBase::Environment::get().getWindowManager ()->messageBox(message.str(), noButtons, MWGui::ShowInDialogueMode_Never); + MWBase::Environment::get().getWindowManager ()->messageBox(message.str(), MWGui::ShowInDialogueMode_Never); if (mLevelProgress >= gmst.find("iLevelUpTotal")->getInt()) { // levelup is possible now - MWBase::Environment::get().getWindowManager ()->messageBox ("#{sLevelUpMsg}", noButtons, MWGui::ShowInDialogueMode_Never); + MWBase::Environment::get().getWindowManager ()->messageBox ("#{sLevelUpMsg}", MWGui::ShowInDialogueMode_Never); } getSkill (skillIndex).setBase (base); diff --git a/apps/openmw/mwscript/containerextensions.cpp b/apps/openmw/mwscript/containerextensions.cpp index 96e30e396..58b1b375b 100644 --- a/apps/openmw/mwscript/containerextensions.cpp +++ b/apps/openmw/mwscript/containerextensions.cpp @@ -71,8 +71,7 @@ namespace MWScript msgBox = MyGUI::LanguageManager::getInstance().replaceTags("#{sNotifyMessage61}"); msgBox = boost::str(boost::format(msgBox) % count % itemName); } - std::vector noButtons; - MWBase::Environment::get().getWindowManager()->messageBox(msgBox, noButtons, MWGui::ShowInDialogueMode_Only); + MWBase::Environment::get().getWindowManager()->messageBox(msgBox, MWGui::ShowInDialogueMode_Only); } } }; @@ -143,8 +142,7 @@ namespace MWScript msgBox = MyGUI::LanguageManager::getInstance().replaceTags("#{sNotifyMessage62}"); msgBox = boost::str (boost::format(msgBox) % itemName); } - std::vector noButtons; - MWBase::Environment::get().getWindowManager()->messageBox(msgBox, noButtons, MWGui::ShowInDialogueMode_Only); + MWBase::Environment::get().getWindowManager()->messageBox(msgBox, MWGui::ShowInDialogueMode_Only); } } }; diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index 5d52033a8..5cc4d69b6 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -200,7 +200,10 @@ namespace MWScript void InterpreterContext::messageBox (const std::string& message, const std::vector& buttons) { - MWBase::Environment::get().getWindowManager()->messageBox (message, buttons); + if (buttons.empty()) + MWBase::Environment::get().getWindowManager()->messageBox (message); + else + MWBase::Environment::get().getWindowManager()->interactiveMessageBox(message, buttons); } void InterpreterContext::report (const std::string& message) diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 94b1ab4dc..8ae7fb355 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -118,7 +118,7 @@ void MWState::StateManager::askLoadRecent() std::string message = MWBase::Environment::get().getWindowManager()->getGameSettingString("sLoadLastSaveMsg", tag); size_t pos = message.find(tag); message.replace(pos, tag.length(), lastSave.mProfile.mDescription); - MWBase::Environment::get().getWindowManager()->messageBox(message, buttons); + MWBase::Environment::get().getWindowManager()->interactiveMessageBox(message, buttons); mAskLoadRecent = true; } } @@ -259,7 +259,7 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot std::vector buttons; buttons.push_back("#{sOk}"); - MWBase::Environment::get().getWindowManager()->messageBox(error.str(), buttons); + MWBase::Environment::get().getWindowManager()->interactiveMessageBox(error.str(), buttons); // If no file was written, clean up the slot if (slot && !boost::filesystem::exists(slot->mPath)) @@ -459,7 +459,7 @@ void MWState::StateManager::loadGame (const Character *character, const std::str std::vector buttons; buttons.push_back("#{sOk}"); - MWBase::Environment::get().getWindowManager()->messageBox(error.str(), buttons); + MWBase::Environment::get().getWindowManager()->interactiveMessageBox(error.str(), buttons); } } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index f9642226b..810b7f80d 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -3047,7 +3047,7 @@ namespace MWWorld std::vector buttons; buttons.push_back("#{sOk}"); - MWBase::Environment::get().getWindowManager()->messageBox(message, buttons); + MWBase::Environment::get().getWindowManager()->interactiveMessageBox(message, buttons); } } From f9227beedd787e2386ce85310b11c663b07c6770 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 10 Jan 2015 23:58:55 +0100 Subject: [PATCH 0276/3725] Add warning when loading a savegame that depends on non-existing content files (Fixes #2261) --- apps/openmw/mwgui/messagebox.cpp | 5 +-- apps/openmw/mwgui/messagebox.hpp | 3 +- apps/openmw/mwgui/windowmanagerimp.cpp | 5 +-- apps/openmw/mwstate/statemanagerimp.cpp | 33 +++++++++++++++++++ apps/openmw/mwstate/statemanagerimp.hpp | 2 ++ .../openmw_interactive_messagebox.layout | 2 +- files/mygui/openmw_layers.xml | 1 + 7 files changed, 45 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index c45136eb3..9cb778ea2 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -146,10 +146,11 @@ namespace MWGui return false; } - int MessageBoxManager::readPressedButton () + int MessageBoxManager::readPressedButton (bool reset) { int pressed = mLastButtonPressed; - mLastButtonPressed = -1; + if (reset) + mLastButtonPressed = -1; return pressed; } diff --git a/apps/openmw/mwgui/messagebox.hpp b/apps/openmw/mwgui/messagebox.hpp index 59804e097..48a92c844 100644 --- a/apps/openmw/mwgui/messagebox.hpp +++ b/apps/openmw/mwgui/messagebox.hpp @@ -33,7 +33,8 @@ namespace MWGui bool removeMessageBox (MessageBox *msgbox); - int readPressedButton (); + /// @param reset Reset the pressed button to -1 after reading it. + int readPressedButton (bool reset=true); typedef MyGUI::delegates::CMultiDelegate1 EventHandle_Int; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 7d9e10d8f..077ca4fe3 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -607,7 +607,7 @@ namespace MWGui // GM_Loading uses a texture of the last rendered frame so everything previously visible will be rendered. mHud->setVisible(false); mToolTips->setVisible(false); - setCursorVisible(false); + setCursorVisible(mMessageBoxManager && mMessageBoxManager->isInteractiveMessageBox()); break; default: // Unsupported mode, switch back to game @@ -813,9 +813,10 @@ namespace MWGui if (block) { - while (mMessageBoxManager->readPressedButton() == -1 + while (mMessageBoxManager->readPressedButton(false) == -1 && !MWBase::Environment::get().getStateManager()->hasQuitRequest()) { + mMessageBoxManager->onFrame(0.f); MWBase::Environment::get().getInputManager()->update(0, true, false); mRendering->getWindow()->update(); diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 8ae7fb355..f756ee42a 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -353,6 +353,12 @@ void MWState::StateManager::loadGame (const Character *character, const std::str { ESM::SavedGame profile; profile.load(reader); + if (!verifyProfile(profile)) + { + cleanup (true); + MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_MainMenu); + return; + } mTimePlayed = profile.mTimePlayed; } break; @@ -517,3 +523,30 @@ void MWState::StateManager::update (float duration) } } } + +bool MWState::StateManager::verifyProfile(const ESM::SavedGame& profile) const +{ + const std::vector& selectedContentFiles = MWBase::Environment::get().getWorld()->getContentFiles(); + bool notFound = false; + for (std::vector::const_iterator it = profile.mContentFiles.begin(); + it != profile.mContentFiles.end(); ++it) + { + if (std::find(selectedContentFiles.begin(), selectedContentFiles.end(), *it) + == selectedContentFiles.end()) + { + notFound = true; + break; + } + } + if (notFound) + { + std::vector buttons; + buttons.push_back("#{sYes}"); + buttons.push_back("#{sNo}"); + MWBase::Environment::get().getWindowManager()->interactiveMessageBox("#{sMissingMastersMsg}", buttons, true); + int selectedButton = MWBase::Environment::get().getWindowManager()->readPressedButton(); + if (selectedButton == 1 || selectedButton == -1) + return false; + } + return true; +} diff --git a/apps/openmw/mwstate/statemanagerimp.hpp b/apps/openmw/mwstate/statemanagerimp.hpp index 956a2d73c..37f38f8df 100644 --- a/apps/openmw/mwstate/statemanagerimp.hpp +++ b/apps/openmw/mwstate/statemanagerimp.hpp @@ -23,6 +23,8 @@ namespace MWState void cleanup (bool force = false); + bool verifyProfile (const ESM::SavedGame& profile) const; + std::map buildContentFileIndexMap (const ESM::ESMReader& reader) const; public: diff --git a/files/mygui/openmw_interactive_messagebox.layout b/files/mygui/openmw_interactive_messagebox.layout index a1dbc5aa8..a72bebf3a 100644 --- a/files/mygui/openmw_interactive_messagebox.layout +++ b/files/mygui/openmw_interactive_messagebox.layout @@ -1,7 +1,7 @@ - + diff --git a/files/mygui/openmw_layers.xml b/files/mygui/openmw_layers.xml index 38a98d133..50f83aaa2 100644 --- a/files/mygui/openmw_layers.xml +++ b/files/mygui/openmw_layers.xml @@ -11,6 +11,7 @@ + From 7aa0f887c0d992c96fa260e06b40234a50ca76b8 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 11 Jan 2015 12:20:22 +1300 Subject: [PATCH 0277/3725] Minor changes to ESM::RefNum 1. Changed mIndex to unsigned, to solve potential implementation defined behavior with right shift. 2. Refactoring to minimize use of magic number -1 to indicate "no Content File". --- apps/openmw/mwclass/creature.cpp | 2 +- apps/openmw/mwclass/npc.cpp | 2 +- apps/openmw/mwscript/miscextensions.cpp | 2 +- apps/openmw/mwworld/cellref.cpp | 8 ++++++-- apps/openmw/mwworld/cellref.hpp | 3 +++ apps/openmw/mwworld/cellreflist.hpp | 2 +- apps/openmw/mwworld/cellstore.cpp | 10 +++++----- apps/openmw/mwworld/manualref.hpp | 3 +-- apps/openmw/mwworld/worldimp.cpp | 4 ++-- components/esm/cellref.cpp | 3 +-- components/esm/cellref.hpp | 8 ++++++-- 11 files changed, 28 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index e21676f10..9eb5b1b69 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -872,7 +872,7 @@ namespace MWClass { // Note we do not respawn moved references in the cell they were moved to. Instead they are respawned in the original cell. // This also means we cannot respawn dynamically placed references with no content file connection. - if (ptr.getCellRef().getRefNum().mContentFile != -1) + if (ptr.getCellRef().hasContentFile()) { if (ptr.getRefData().getCount() == 0) ptr.getRefData().setCount(1); diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 22263d820..596b56acd 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -1331,7 +1331,7 @@ namespace MWClass { // Note we do not respawn moved references in the cell they were moved to. Instead they are respawned in the original cell. // This also means we cannot respawn dynamically placed references with no content file connection. - if (ptr.getCellRef().getRefNum().mContentFile != -1) + if (ptr.getCellRef().hasContentFile()) { if (ptr.getRefData().getCount() == 0) ptr.getRefData().setCount(1); diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index f20c9967d..d4431016a 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -1035,7 +1035,7 @@ namespace MWScript msg << "Content file: "; - if (ptr.getCellRef().getRefNum().mContentFile == -1) + if (!ptr.getCellRef().hasContentFile()) msg << "[None]" << std::endl; else { diff --git a/apps/openmw/mwworld/cellref.cpp b/apps/openmw/mwworld/cellref.cpp index 3ea3ed8bf..aa6627de5 100644 --- a/apps/openmw/mwworld/cellref.cpp +++ b/apps/openmw/mwworld/cellref.cpp @@ -10,10 +10,14 @@ namespace MWWorld return mCellRef.mRefNum; } + bool CellRef::hasContentFile() const + { + return getRefNum().hasContentFile(); + } + void CellRef::unsetRefNum() { - mCellRef.mRefNum.mContentFile = -1; - mCellRef.mRefNum.mIndex = 0; + getRefNum().unset(); } std::string CellRef::getRefId() const diff --git a/apps/openmw/mwworld/cellref.hpp b/apps/openmw/mwworld/cellref.hpp index d7c0ce221..a7ffbe08b 100644 --- a/apps/openmw/mwworld/cellref.hpp +++ b/apps/openmw/mwworld/cellref.hpp @@ -28,6 +28,9 @@ namespace MWWorld // Set RefNum to its default state. void unsetRefNum(); + /// Does the RefNum have a content file? + bool hasContentFile() const; + // Id of object being referenced std::string getRefId() const; diff --git a/apps/openmw/mwworld/cellreflist.hpp b/apps/openmw/mwworld/cellreflist.hpp index 037de8645..2c5e01aaa 100644 --- a/apps/openmw/mwworld/cellreflist.hpp +++ b/apps/openmw/mwworld/cellreflist.hpp @@ -28,7 +28,7 @@ namespace MWWorld { for (typename List::iterator iter (mList.begin()); iter!=mList.end(); ++iter) if (!iter->mData.isDeletedByContentFile() - && (iter->mRef.getRefNum().mContentFile != -1 || iter->mData.getCount() > 0) + && (iter->mRef.hasContentFile() || iter->mData.getCount() > 0) && iter->mRef.getRefId() == name) return &*iter; diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index f1a8451ea..1c0e7e385 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -72,12 +72,12 @@ namespace iter (collection.mList.begin()); iter!=collection.mList.end(); ++iter) { - if (!iter->mData.hasChanged() && !iter->mRef.hasChanged() && iter->mRef.getRefNum().mContentFile != -1) + if (!iter->mData.hasChanged() && !iter->mRef.hasChanged() && iter->mRef.hasContentFile()) { // Reference that came from a content file and has not been changed -> ignore continue; } - if (iter->mData.getCount()==0 && iter->mRef.getRefNum().mContentFile==-1) + if (iter->mData.getCount()==0 && !iter->mRef.hasContentFile()) { // Deleted reference that did not come from a content file -> ignore continue; @@ -102,7 +102,7 @@ namespace state.load (reader); // If the reference came from a content file, make sure this content file is loaded - if (state.mRef.mRefNum.mContentFile != -1) + if (state.mRef.mRefNum.hasContentFile()) { std::map::const_iterator iter = contentFileMap.find (state.mRef.mRefNum.mContentFile); @@ -121,7 +121,7 @@ namespace if (!record) return; - if (state.mRef.mRefNum.mContentFile != -1) + if (state.mRef.mRefNum.hasContentFile()) { for (typename MWWorld::CellRefList::List::iterator iter (collection.mList.begin()); iter!=collection.mList.end(); ++iter) @@ -487,7 +487,7 @@ namespace MWWorld mCell->restore (esm[index], i); ESM::CellRef ref; - ref.mRefNum.mContentFile = -1; + ref.mRefNum.mContentFile = ESM::RefNum::RefNum_NoContentFile; // Get each reference in turn bool deleted = false; diff --git a/apps/openmw/mwworld/manualref.hpp b/apps/openmw/mwworld/manualref.hpp index 0becd7524..4eb93543b 100644 --- a/apps/openmw/mwworld/manualref.hpp +++ b/apps/openmw/mwworld/manualref.hpp @@ -24,8 +24,7 @@ namespace MWWorld const T* base = list.find(name); ESM::CellRef cellRef; - cellRef.mRefNum.mIndex = 0; - cellRef.mRefNum.mContentFile = -1; + cellRef.mRefNum.unset(); cellRef.mRefID = name; cellRef.mScale = 1; cellRef.mFactionRank = 0; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index f9642226b..7dfd41408 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1089,7 +1089,7 @@ namespace MWWorld void World::undeleteObject(const Ptr& ptr) { - if (ptr.getCellRef().getRefNum().mContentFile == -1) + if (!ptr.getCellRef().hasContentFile()) return; if (ptr.getRefData().isDeleted()) { @@ -3206,7 +3206,7 @@ namespace MWWorld { // Can't reset actors that were moved to a different cell, because we don't know what cell they came from. // This could be fixed once we properly track actor cell changes, but may not be desirable behaviour anyhow. - if (ptr.getClass().isActor() && ptr.getCellRef().getRefNum().mContentFile != -1) + if (ptr.getClass().isActor() && ptr.getCellRef().hasContentFile()) { const ESM::Position& origPos = ptr.getCellRef().getPosition(); MWBase::Environment::get().getWorld()->moveObject(ptr, origPos.pos[0], origPos.pos[1], origPos.pos[2]); diff --git a/components/esm/cellref.cpp b/components/esm/cellref.cpp index 29d26d013..f93fe1535 100644 --- a/components/esm/cellref.cpp +++ b/components/esm/cellref.cpp @@ -129,8 +129,7 @@ void ESM::CellRef::save (ESMWriter &esm, bool wideRefNum, bool inInventory) cons void ESM::CellRef::blank() { - mRefNum.mIndex = 0; - mRefNum.mContentFile = -1; + mRefNum.unset(); mRefID.clear(); mScale = 1; mOwner.clear(); diff --git a/components/esm/cellref.hpp b/components/esm/cellref.hpp index 9c57061b0..f3986ccf3 100644 --- a/components/esm/cellref.hpp +++ b/components/esm/cellref.hpp @@ -13,8 +13,12 @@ namespace ESM struct RefNum { - int mIndex; - int mContentFile; // -1 no content file + unsigned int mIndex; + int mContentFile; + + enum { RefNum_NoContentFile = -1 }; + inline bool hasContentFile() const { return mContentFile != RefNum_NoContentFile; } + inline void unset() { mIndex = 0; mContentFile = RefNum_NoContentFile; } }; /* Cell reference. This represents ONE object (of many) inside the From 458b82c308ec62156e0c250f75dce75f3760901a Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 11 Jan 2015 14:25:46 +1300 Subject: [PATCH 0278/3725] Centralized "fish can't attack non-swimmer" logic. --- apps/openmw/mwmechanics/actors.cpp | 7 ++++--- apps/openmw/mwmechanics/aicombat.cpp | 9 +++------ apps/openmw/mwmechanics/combat.cpp | 20 ++++++++++++++++++++ apps/openmw/mwmechanics/combat.hpp | 4 ++++ 4 files changed, 31 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 0a25ddd42..a90277160 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -37,6 +37,7 @@ #include "actor.hpp" #include "summoning.hpp" +#include "combat.hpp" namespace { @@ -309,10 +310,10 @@ namespace MWMechanics // pure water creatures won't try to fight with the target on the ground // except that creature is already hostile if ((againstPlayer || !creatureStats.getAiSequence().isInCombat()) - && ((actor1.getClass().isPureWaterCreature(actor1) - && !MWBase::Environment::get().getWorld()->isWading(actor2)) - || (!actor1.getClass().canSwim(actor1) && MWBase::Environment::get().getWorld()->isSwimming(actor2)))) // creature can't swim to target + && !MWMechanics::isEnvironmentCompatible(actor1, actor2)) // creature can't swim to target + { return; + } bool aggressive; diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index ce5963a91..f7e285ff5 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -23,6 +23,7 @@ #include "character.hpp" // fixme: for getActiveWeapon #include "aicombataction.hpp" +#include "combat.hpp" namespace { @@ -206,12 +207,8 @@ namespace MWMechanics const MWWorld::Class& actorClass = actor.getClass(); MWBase::World* world = MWBase::Environment::get().getWorld(); - if (!actorClass.isNpc() && - // 1. pure water creature and Player moved out of water - ((target == world->getPlayerPtr() && - actorClass.isPureWaterCreature(actor) && !world->isWading(target)) - // 2. creature can't swim to target - || (!actorClass.canSwim(actor) && world->isSwimming(target)))) + // can't fight if attacker can't go where target is. E.g. A fish can't attack person on land. + if (!actorClass.isNpc() && !MWMechanics::isEnvironmentCompatible(actor, target)) { actorClass.getCreatureStats(actor).setAttackingOrSpell(false); return true; diff --git a/apps/openmw/mwmechanics/combat.cpp b/apps/openmw/mwmechanics/combat.cpp index 459ff8aef..ad4d3aabf 100644 --- a/apps/openmw/mwmechanics/combat.cpp +++ b/apps/openmw/mwmechanics/combat.cpp @@ -367,4 +367,24 @@ namespace MWMechanics else sndMgr->playSound3D(victim, "Hand To Hand Hit", 1.0f, 1.0f); } + + bool isEnvironmentCompatible(const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim) + { + const MWWorld::Class& attackerClass = attacker.getClass(); + MWBase::World* world = MWBase::Environment::get().getWorld(); + + // If attacker is fish, victim must be in water + if (attackerClass.isPureWaterCreature(attacker)) + { + return world->isWading(victim); + } + + // If attacker can't swim, victim must not be in water + if (!attackerClass.canSwim(attacker)) + { + return !world->isSwimming(victim); + } + + return true; + } } diff --git a/apps/openmw/mwmechanics/combat.hpp b/apps/openmw/mwmechanics/combat.hpp index c6fc9ff92..41dd2d1a4 100644 --- a/apps/openmw/mwmechanics/combat.hpp +++ b/apps/openmw/mwmechanics/combat.hpp @@ -34,6 +34,10 @@ void adjustWeaponDamage (float& damage, const MWWorld::Ptr& weapon); void getHandToHandDamage (const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim, float& damage, bool& healthdmg); +/// Can attacker operate in victim's environment? +/// e.g. If attacker is a fish, is victim in water? Or, if attacker can't swim, is victim on land? +bool isEnvironmentCompatible(const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim); + } #endif From 1795fdaf034928b9e995eb64b98c6e0be8be3dd8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 11 Jan 2015 13:50:50 +0100 Subject: [PATCH 0279/3725] Command line options readme fix --- README.md | 104 ++++++++++++++++++++++++++---------------------------- 1 file changed, 51 insertions(+), 53 deletions(-) diff --git a/README.md b/README.md index 168684e8d..bb59b7e02 100644 --- a/README.md +++ b/README.md @@ -35,59 +35,57 @@ The data path tells OpenMW where to find your Morrowind files. If you run the la Command line options -------------------- -
-Syntax: openmw 
-Allowed options:
-  --help                                print help message
-  --version                             print version information and quit
-  --data arg (=data)                    set data directories (later directories
-                                        have higher priority)
-  --data-local arg                      set local data directory (highest
-                                        priority)
-  --fallback-archive arg (=fallback-archive)
-                                        set fallback BSA archives (later
-                                        archives have higher priority)
-  --resources arg (=resources)          set resources directory
-  --start arg (=Beshara)                set initial cell
-  --content arg                         content file(s): esm/esp, or
-                                        omwgame/omwaddon
-  --anim-verbose [=arg(=1)] (=0)        output animation indices files
-  --no-sound [=arg(=1)] (=0)            disable all sounds
-  --script-verbose [=arg(=1)] (=0)      verbose script output
-  --script-all [=arg(=1)] (=0)          compile all scripts (excluding dialogue
-                                        scripts) at startup
-  --script-console [=arg(=1)] (=0)      enable console-only script
-                                        functionality
-  --script-run arg                      select a file containing a list of
-                                        console commands that is executed on
-                                        startup
-   --script-warn [=arg(=1)] (=1)        handling of warnings when compiling
-                                        scripts
-                                        0 - ignore warning
-                                        1 - show warning but consider script as
-                                        correctly compiled anyway
-                                        2 - treat warnings as errors
-  --skip-menu [=arg(=1)] (=0)           skip main menu on game startup
-  --new-game [=arg(=1)] (=0)            run new game sequence (ignored if
-                                        skip-menu=0)
-  --fs-strict [=arg(=1)] (=0)           strict file system handling (no case
-                                        folding)
-  --encoding arg (=win1252)             Character encoding used in OpenMW game
-                                        messages:
+    Syntax: openmw 
+    Allowed options:
+      --help                                print help message
+      --version                             print version information and quit
+      --data arg (=data)                    set data directories (later directories
+                                            have higher priority)
+      --data-local arg                      set local data directory (highest
+                                            priority)
+      --fallback-archive arg (=fallback-archive)
+                                            set fallback BSA archives (later
+                                            archives have higher priority)
+      --resources arg (=resources)          set resources directory
+      --start arg (=Beshara)                set initial cell
+      --content arg                         content file(s): esm/esp, or
+                                            omwgame/omwaddon
+      --anim-verbose [=arg(=1)] (=0)        output animation indices files
+      --no-sound [=arg(=1)] (=0)            disable all sounds
+      --script-verbose [=arg(=1)] (=0)      verbose script output
+      --script-all [=arg(=1)] (=0)          compile all scripts (excluding dialogue
+                                            scripts) at startup
+      --script-console [=arg(=1)] (=0)      enable console-only script
+                                            functionality
+      --script-run arg                      select a file containing a list of
+                                            console commands that is executed on
+                                            startup
+       --script-warn [=arg(=1)] (=1)        handling of warnings when compiling
+                                            scripts
+                                            0 - ignore warning
+                                            1 - show warning but consider script as
+                                            correctly compiled anyway
+                                            2 - treat warnings as errors
+      --skip-menu [=arg(=1)] (=0)           skip main menu on game startup
+      --new-game [=arg(=1)] (=0)            run new game sequence (ignored if
+                                            skip-menu=0)
+      --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
+                                            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
+                                            win1251 - Cyrillic alphabet such as
+                                            Russian, Bulgarian, Serbian Cyrillic
+                                            and other languages
 
-                                        win1252 - Western European (Latin)
-                                        alphabet, used by default
-  --fallback arg                        fallback values
-  --no-grab                             Don't grab mouse cursor
-  --activate-dist arg (=-1)             activation distance override
-
+ win1252 - Western European (Latin) + alphabet, used by default + --fallback arg fallback values + --no-grab Don't grab mouse cursor + --activate-dist arg (=-1) activation distance override From e2fe9693f3a9be047eb785fae49aa4e5c06ece93 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 11 Jan 2015 00:17:55 +0100 Subject: [PATCH 0280/3725] Add missing tooltips in edit effect dialog --- files/mygui/openmw_edit_effect.layout | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/files/mygui/openmw_edit_effect.layout b/files/mygui/openmw_edit_effect.layout index 5dc53e505..6123f90a7 100644 --- a/files/mygui/openmw_edit_effect.layout +++ b/files/mygui/openmw_edit_effect.layout @@ -12,9 +12,12 @@ - + + + + @@ -22,9 +25,12 @@ - + + + + @@ -49,9 +55,12 @@ - + + + + @@ -66,9 +75,12 @@ - + + + + From 716e14a37a8cd86d8711bd2ba5e1ac8e597d0d66 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 11 Jan 2015 15:12:47 +0100 Subject: [PATCH 0281/3725] Print missing savegame dependencies on the console --- apps/openmw/mwstate/statemanagerimp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index f756ee42a..77e3452e3 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -534,8 +534,8 @@ bool MWState::StateManager::verifyProfile(const ESM::SavedGame& profile) const if (std::find(selectedContentFiles.begin(), selectedContentFiles.end(), *it) == selectedContentFiles.end()) { + std::cerr << "Savegame dependency " << *it << " is missing." << std::endl; notFound = true; - break; } } if (notFound) From b108fbe9866d97c853489defff91b41996cb39e0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 11 Jan 2015 15:47:56 +0100 Subject: [PATCH 0282/3725] Remove incorrect implementation of fGreetDistanceReset This can't be right. A reset distance of 512 is smaller than the maximum greeting distance for certain NPCs, which would then say greetings non-stop. --- apps/openmw/mwmechanics/aiwander.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 94c4542f8..30e17c7f4 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -477,10 +477,8 @@ namespace MWMechanics if (greetingState == MWMechanics::AiWander::Greet_Done) { - static float fGreetDistanceReset = MWBase::Environment::get().getWorld()->getStore() - .get().find("fGreetDistanceReset")->getFloat(); - - if (playerDistSqr >= fGreetDistanceReset*fGreetDistanceReset) + float resetDist = 2*helloDistance; + if (playerDistSqr >= resetDist*resetDist) greetingState = Greet_None; } } From 4d4f2fc475a2f42bd07bf6d235debb7a09c83375 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 11 Jan 2015 16:51:24 +0100 Subject: [PATCH 0283/3725] Add maximum distance for teleporting followers on using a door --- apps/openmw/mwworld/actionteleport.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/actionteleport.cpp b/apps/openmw/mwworld/actionteleport.cpp index 7fd6ba024..8bbb08008 100644 --- a/apps/openmw/mwworld/actionteleport.cpp +++ b/apps/openmw/mwworld/actionteleport.cpp @@ -37,7 +37,11 @@ namespace MWWorld getFollowers(actor, followers); for(std::set::iterator it = followers.begin();it != followers.end();++it) { - teleport(*it); + MWWorld::Ptr follower = *it; + if (Ogre::Vector3(follower.getRefData().getPosition().pos).squaredDistance( + Ogre::Vector3( actor.getRefData().getPosition().pos)) + <= 800*800) + teleport(*it); } teleport(actor); From 1780bcc238e06230815f4090cca3e96cdd88d036 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 11 Jan 2015 16:52:04 +0100 Subject: [PATCH 0284/3725] Print RefNum in BetaComment --- apps/openmw/mwscript/miscextensions.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index d4431016a..37bb4235e 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -1042,6 +1042,7 @@ namespace MWScript std::vector contentFiles = MWBase::Environment::get().getWorld()->getContentFiles(); msg << contentFiles.at (ptr.getCellRef().getRefNum().mContentFile) << std::endl; + msg << "RefNum: " << ptr.getCellRef().getRefNum().mIndex << std::endl; } msg << "RefID: " << ptr.getCellRef().getRefId() << std::endl; From 0ec018f7f1f77c22750bb7f6a6649808c4ec1e1a Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 11 Jan 2015 17:54:15 +0100 Subject: [PATCH 0285/3725] More accurate savegame loading progress bar, uses position in the file (Bug #2259) --- apps/openmw/mwstate/statemanagerimp.cpp | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 77e3452e3..e9b549dc9 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -337,11 +337,13 @@ void MWState::StateManager::loadGame (const Character *character, const std::str Loading::Listener& listener = *MWBase::Environment::get().getWindowManager()->getLoadingScreen(); - listener.setProgressRange(reader.getRecordCount()); + listener.setProgressRange(100); listener.setLabel("#{sLoadingMessage14}"); Loading::ScopedLoad load(&listener); + size_t total = reader.getFileSize(); + int currentPercent = 0; while (reader.hasMoreRecs()) { ESM::NAME n = reader.getRecName(); @@ -423,7 +425,12 @@ void MWState::StateManager::loadGame (const Character *character, const std::str std::cerr << "Ignoring unknown record: " << n.name << std::endl; reader.skipRecord(); } - listener.increaseProgress(); + int progressPercent = static_cast(float(reader.getFileOffset())/total*100); + if (progressPercent > currentPercent) + { + listener.increaseProgress(progressPercent-currentPercent); + currentPercent = progressPercent; + } } mCharacterManager.setCurrentCharacter(character); @@ -446,7 +453,7 @@ void MWState::StateManager::loadGame (const Character *character, const std::str // Use detectWorldSpaceChange=false, otherwise some of the data we just loaded would be cleared again MWBase::Environment::get().getWorld()->changeToCell (cellId, ptr.getRefData().getPosition(), false); - // Vanilla MW will restart startup scripts when a save game is loaded. This is unintuive, + // Vanilla MW will restart startup scripts when a save game is loaded. This is unintuitive, // but some mods may be using it as a reload detector. MWBase::Environment::get().getScriptManager()->getGlobalScripts().addStartup(); @@ -472,8 +479,11 @@ void MWState::StateManager::loadGame (const Character *character, const std::str void MWState::StateManager::quickLoad() { if (Character* mCurrentCharacter = getCurrentCharacter (false)) - if (const MWState::Slot* slot = &*mCurrentCharacter->begin()) //Get newest save - loadGame (mCurrentCharacter, slot->mPath.string()); + { + if (mCurrentCharacter->begin() == mCurrentCharacter->end()) + return; + loadGame (mCurrentCharacter, mCurrentCharacter->begin()->mPath.string()); //Get newest save + } } void MWState::StateManager::deleteGame(const MWState::Character *character, const MWState::Slot *slot) From c3f3f8b3d0fd4f8845c54fa0666d4b208fb33ee2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 11 Jan 2015 18:01:06 +0100 Subject: [PATCH 0286/3725] Use only Cell records for saving progress bar (Fixes #2259) --- apps/openmw/mwbase/world.hpp | 1 + apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 1 - apps/openmw/mwdialogue/journalimp.cpp | 4 ---- apps/openmw/mwgui/mapwindow.cpp | 1 - apps/openmw/mwgui/windowmanagerimp.cpp | 3 --- apps/openmw/mwmechanics/actors.cpp | 2 -- apps/openmw/mwrender/globalmap.cpp | 1 - apps/openmw/mwscript/globalscripts.cpp | 1 - apps/openmw/mwstate/statemanagerimp.cpp | 4 ++-- apps/openmw/mwworld/cells.cpp | 4 ++-- apps/openmw/mwworld/esmstore.cpp | 1 - apps/openmw/mwworld/globals.cpp | 1 - apps/openmw/mwworld/player.cpp | 2 -- apps/openmw/mwworld/projectilemanager.cpp | 4 ---- apps/openmw/mwworld/store.hpp | 1 - apps/openmw/mwworld/weather.cpp | 1 - apps/openmw/mwworld/worldimp.cpp | 8 +++++--- apps/openmw/mwworld/worldimp.hpp | 1 + 18 files changed, 11 insertions(+), 30 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 7432db734..db0f0a763 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -104,6 +104,7 @@ namespace MWBase virtual void clear() = 0; virtual int countSavedGameRecords() const = 0; + virtual int countSavedGameCells() const = 0; virtual void write (ESM::ESMWriter& writer, Loading::Listener& listener) const = 0; diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index a42a48696..dd0fa21fa 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -645,7 +645,6 @@ namespace MWDialogue writer.startRecord (ESM::REC_DIAS); state.save (writer); writer.endRecord (ESM::REC_DIAS); - progress.increaseProgress(); } void DialogueManager::readRecord (ESM::ESMReader& reader, int32_t type) diff --git a/apps/openmw/mwdialogue/journalimp.cpp b/apps/openmw/mwdialogue/journalimp.cpp index e8d5375e1..1d17134df 100644 --- a/apps/openmw/mwdialogue/journalimp.cpp +++ b/apps/openmw/mwdialogue/journalimp.cpp @@ -187,7 +187,6 @@ namespace MWDialogue writer.startRecord (ESM::REC_QUES); state.save (writer); writer.endRecord (ESM::REC_QUES); - progress.increaseProgress(); for (Topic::TEntryIter iter (quest.begin()); iter!=quest.end(); ++iter) { @@ -198,7 +197,6 @@ namespace MWDialogue writer.startRecord (ESM::REC_JOUR); entry.save (writer); writer.endRecord (ESM::REC_JOUR); - progress.increaseProgress(); } } @@ -210,7 +208,6 @@ namespace MWDialogue writer.startRecord (ESM::REC_JOUR); entry.save (writer); writer.endRecord (ESM::REC_JOUR); - progress.increaseProgress(); } for (TTopicIter iter (mTopics.begin()); iter!=mTopics.end(); ++iter) @@ -226,7 +223,6 @@ namespace MWDialogue writer.startRecord (ESM::REC_JOUR); entry.save (writer); writer.endRecord (ESM::REC_JOUR); - progress.increaseProgress(); } } } diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 0f9fa2775..4de9af108 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -903,7 +903,6 @@ namespace MWGui writer.startRecord(ESM::REC_GMAP); map.save(writer); writer.endRecord(ESM::REC_GMAP); - progress.increaseProgress(); } void MapWindow::readRecord(ESM::ESMReader &reader, int32_t type) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 077ca4fe3..d5a71bc77 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1604,14 +1604,12 @@ namespace MWGui mMap->write(writer, progress); mQuickKeysMenu->write(writer); - progress.increaseProgress(); if (!mSelectedSpell.empty()) { writer.startRecord(ESM::REC_ASPL); writer.writeHNString("ID__", mSelectedSpell); writer.endRecord(ESM::REC_ASPL); - progress.increaseProgress(); } for (std::vector::const_iterator it = mCustomMarkers.begin(); it != mCustomMarkers.end(); ++it) @@ -1619,7 +1617,6 @@ namespace MWGui writer.startRecord(ESM::REC_MARK); (*it).save(writer); writer.endRecord(ESM::REC_MARK); - progress.increaseProgress(); } } diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index a90277160..adabff092 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1460,8 +1460,6 @@ namespace MWMechanics writer.writeHNT ("COUN", it->second); } writer.endRecord(ESM::REC_DCOU); - - listener.increaseProgress(1); } void Actors::readRecord (ESM::ESMReader& reader, int32_t type) diff --git a/apps/openmw/mwrender/globalmap.cpp b/apps/openmw/mwrender/globalmap.cpp index 5546c401b..9816b0f41 100644 --- a/apps/openmw/mwrender/globalmap.cpp +++ b/apps/openmw/mwrender/globalmap.cpp @@ -157,7 +157,6 @@ namespace MWRender data[texelY * mWidth * 3 + texelX * 3+2] = b; } } - loadingListener->increaseProgress(1); } } diff --git a/apps/openmw/mwscript/globalscripts.cpp b/apps/openmw/mwscript/globalscripts.cpp index b409a304c..c7371100f 100644 --- a/apps/openmw/mwscript/globalscripts.cpp +++ b/apps/openmw/mwscript/globalscripts.cpp @@ -142,7 +142,6 @@ namespace MWScript writer.startRecord (ESM::REC_GSCR); script.save (writer); writer.endRecord (ESM::REC_GSCR); - progress.increaseProgress(); } } diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index e9b549dc9..9bd2dbd3e 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -221,7 +221,8 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot writer.save (stream); Loading::Listener& listener = *MWBase::Environment::get().getWindowManager()->getLoadingScreen(); - listener.setProgressRange(recordCount); + // Using only Cells for progress information, since they typically have the largest records by far + listener.setProgressRange(MWBase::Environment::get().getWorld()->countSavedGameCells()); listener.setLabel("#{sNotifyMessage4}"); Loading::ScopedLoad load(&listener); @@ -229,7 +230,6 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot writer.startRecord (ESM::REC_SAVE); slot->mProfile.save (writer); writer.endRecord (ESM::REC_SAVE); - listener.increaseProgress(); MWBase::Environment::get().getJournal()->write (writer, listener); MWBase::Environment::get().getDialogueManager()->write (writer, listener); diff --git a/apps/openmw/mwworld/cells.cpp b/apps/openmw/mwworld/cells.cpp index ef3d299a9..3a8b7d5c4 100644 --- a/apps/openmw/mwworld/cells.cpp +++ b/apps/openmw/mwworld/cells.cpp @@ -287,7 +287,7 @@ void MWWorld::Cells::write (ESM::ESMWriter& writer, Loading::Listener& progress) if (iter->second.hasState()) { writeCell (writer, iter->second); - progress.increaseProgress(); // Assumes that each cell writes one record + progress.increaseProgress(); } for (std::map::iterator iter (mInteriors.begin()); @@ -295,7 +295,7 @@ void MWWorld::Cells::write (ESM::ESMWriter& writer, Loading::Listener& progress) if (iter->second.hasState()) { writeCell (writer, iter->second); - progress.increaseProgress(); // Assumes that each cell writes one record + progress.increaseProgress(); } } diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index 8e0f58a6b..b096f4b90 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -161,7 +161,6 @@ void ESMStore::setUp() writer.writeT(mDynamicCount); writer.endRecord("COUN"); writer.endRecord(ESM::REC_DYNA); - progress.increaseProgress(); mPotions.write (writer, progress); mArmors.write (writer, progress); diff --git a/apps/openmw/mwworld/globals.cpp b/apps/openmw/mwworld/globals.cpp index 15ba27498..302a05824 100644 --- a/apps/openmw/mwworld/globals.cpp +++ b/apps/openmw/mwworld/globals.cpp @@ -85,7 +85,6 @@ namespace MWWorld writer.writeHNString ("NAME", iter->first); iter->second.write (writer, ESM::Variant::Format_Global); writer.endRecord (ESM::REC_GLOB); - progress.increaseProgress(); } } diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index b3996f756..a57934bd3 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -225,8 +225,6 @@ namespace MWWorld writer.startRecord (ESM::REC_PLAY); player.save (writer); writer.endRecord (ESM::REC_PLAY); - - progress.increaseProgress(); } bool Player::readRecord (ESM::ESMReader& reader, int32_t type) diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 100ff0ba9..e4b2d5a1e 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -318,8 +318,6 @@ namespace MWWorld state.save(writer); writer.endRecord(ESM::REC_PROJ); - - progress.increaseProgress(); } for (std::vector::const_iterator it = mMagicBolts.begin(); it != mMagicBolts.end(); ++it) @@ -342,8 +340,6 @@ namespace MWWorld state.save(writer); writer.endRecord(ESM::REC_MPRJ); - - progress.increaseProgress(); } } diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index d9e4285fe..adca81adc 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -325,7 +325,6 @@ namespace MWWorld writer.writeHNString ("NAME", iter->second.mId); iter->second.save (writer); writer.endRecord (T::sRecordId); - progress.increaseProgress(); } } diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 3f9b7d562..cd05cb798 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -760,7 +760,6 @@ void WeatherManager::write(ESM::ESMWriter& writer, Loading::Listener& progress) writer.startRecord(ESM::REC_WTHR); state.save(writer); writer.endRecord(ESM::REC_WTHR); - progress.increaseProgress(); } bool WeatherManager::readRecord(ESM::ESMReader& reader, int32_t type) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 5461e8405..4c34f2a04 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -309,6 +309,11 @@ namespace MWWorld +1; // camera } + int World::countSavedGameCells() const + { + return mCells.countSavedGameRecords(); + } + void World::write (ESM::ESMWriter& writer, Loading::Listener& progress) const { // Active cells could have a dirty fog of war, sync it to the CellStore first @@ -320,7 +325,6 @@ namespace MWWorld } MWMechanics::CreatureStats::writeActorIdCounter(writer); - progress.increaseProgress(); mStore.write (writer, progress); // dynamic Store must be written (and read) before Cells, so that // references to custom made records will be recognized @@ -334,12 +338,10 @@ namespace MWWorld writer.writeHNT("TELE", mTeleportEnabled); writer.writeHNT("LEVT", mLevitationEnabled); writer.endRecord(ESM::REC_ENAB); - progress.increaseProgress(); writer.startRecord(ESM::REC_CAM_); writer.writeHNT("FIRS", isFirstPerson()); writer.endRecord(ESM::REC_CAM_); - progress.increaseProgress(); } void World::readRecord (ESM::ESMReader& reader, int32_t type, diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index dfaa9f789..f050c498d 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -166,6 +166,7 @@ namespace MWWorld virtual void clear(); virtual int countSavedGameRecords() const; + virtual int countSavedGameCells() const; virtual void write (ESM::ESMWriter& writer, Loading::Listener& progress) const; From e95b513cfcdbe1dedb95fffaa12a0ba736b6761f Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 11 Jan 2015 16:33:03 +1300 Subject: [PATCH 0287/3725] Use icon to show files with problem (Fixes #2268) Launcher now indicates files with problem using an icon. Using red text for files with load order issue removed because it doesn't work well with dark themes. --- components/contentselector/model/contentmodel.cpp | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/components/contentselector/model/contentmodel.cpp b/components/contentselector/model/contentmodel.cpp index 6c5614f13..5760a327e 100644 --- a/components/contentselector/model/contentmodel.cpp +++ b/components/contentselector/model/contentmodel.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include "components/esm/esmreader.hpp" @@ -177,14 +178,9 @@ QVariant ContentSelectorModel::ContentModel::data(const QModelIndex &index, int switch (role) { - case Qt::ForegroundRole: + case Qt::DecorationRole: { - if (isLoadOrderError(file)) - { - QBrush redBackground(Qt::red, Qt::SolidPattern); - return redBackground; - } - break; + return isLoadOrderError(file) ? QIcon::fromTheme("edit-delete") : QVariant(); } case Qt::EditRole: @@ -618,7 +614,7 @@ QString ContentSelectorModel::ContentModel::toolTip(const EsmFile *file) const { if (isLoadOrderError(file)) { - QString text(""); + QString text(""); int index = indexFromItem(item(file->filePath())).row(); foreach(const LoadOrderError& error, checkForLoadOrderErrors(file, index)) { @@ -626,7 +622,7 @@ QString ContentSelectorModel::ContentModel::toolTip(const EsmFile *file) const text += error.toolTip(); text += "

"; } - text += ("
"); + text += (""); text += file->toolTip(); return text; } From 82eaa9f1bc7af41be5193db065e67dbd26d4132a Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 11 Jan 2015 20:07:17 +0100 Subject: [PATCH 0288/3725] Fix loading crash (don't apply viewmode before player is set up) (Fixes #2272) --- apps/openmw/mwstate/statemanagerimp.cpp | 11 +++++++++-- apps/openmw/mwworld/worldimp.cpp | 6 ------ 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 9bd2dbd3e..54c3726bd 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -342,6 +342,8 @@ void MWState::StateManager::loadGame (const Character *character, const std::str Loading::ScopedLoad load(&listener); + bool firstPersonCam = false; + size_t total = reader.getFileSize(); int currentPercent = 0; while (reader.hasMoreRecs()) @@ -396,9 +398,11 @@ void MWState::StateManager::loadGame (const Character *character, const std::str case ESM::REC_ENAB: case ESM::REC_LEVC: case ESM::REC_LEVI: - case ESM::REC_CAM_: + MWBase::Environment::get().getWorld()->readRecord(reader, n.val, contentFileMap); + break; - MWBase::Environment::get().getWorld()->readRecord (reader, n.val, contentFileMap); + case ESM::REC_CAM_: + reader.getHNT(firstPersonCam, "FIRS"); break; case ESM::REC_GSCR: @@ -446,6 +450,9 @@ void MWState::StateManager::loadGame (const Character *character, const std::str MWBase::Environment::get().getWindowManager()->updatePlayer(); MWBase::Environment::get().getMechanicsManager()->playerLoaded(); + if (firstPersonCam != MWBase::Environment::get().getWorld()->isFirstPerson()) + MWBase::Environment::get().getWorld()->togglePOV(); + MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr(); ESM::CellId cellId = ptr.getCell()->getCell()->getCellId(); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 4c34f2a04..5e773f5d3 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -356,12 +356,6 @@ namespace MWWorld reader.getHNT(mTeleportEnabled, "TELE"); reader.getHNT(mLevitationEnabled, "LEVT"); return; - case ESM::REC_CAM_: - bool firstperson; - reader.getHNT(firstperson, "FIRS"); - if (firstperson != isFirstPerson()) - togglePOV(); - break; default: if (!mStore.readRecord (reader, type) && !mGlobalVariables.readRecord (reader, type) && From 04d6cead3b3738fbf4aeebb355a71592797f043d Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 11 Jan 2015 20:34:26 +0100 Subject: [PATCH 0289/3725] Autogenerated collision should only be disabled if RootCollisionNode is a child of the root node (Fixes #2133) --- components/nifbullet/bulletnifloader.cpp | 20 ++++++++------------ components/nifbullet/bulletnifloader.hpp | 2 +- libs/openengine/bullet/BulletShapeLoader.cpp | 2 +- libs/openengine/bullet/BulletShapeLoader.h | 5 ++--- libs/openengine/bullet/physic.cpp | 2 +- 5 files changed, 13 insertions(+), 18 deletions(-) diff --git a/components/nifbullet/bulletnifloader.cpp b/components/nifbullet/bulletnifloader.cpp index 3abe0c171..6c56fbba8 100644 --- a/components/nifbullet/bulletnifloader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -95,7 +95,7 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource) return; } - mShape->mHasCollisionNode = hasRootCollisionNode(node); + mShape->mAutogenerated = hasAutoGeneratedCollision(node); //do a first pass handleNode(node,0,false,false,false); @@ -152,12 +152,9 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource) mShape->mRaycastingShape = new TriangleMeshShape(mStaticMesh,true); } -bool ManualBulletShapeLoader::hasRootCollisionNode(Nif::Node const * node) +bool ManualBulletShapeLoader::hasAutoGeneratedCollision(Nif::Node const * rootNode) { - if(node->recType == Nif::RC_RootCollisionNode) - return true; - - const Nif::NiNode *ninode = dynamic_cast(node); + const Nif::NiNode *ninode = dynamic_cast(rootNode); if(ninode) { const Nif::NodeList &list = ninode->children; @@ -165,13 +162,12 @@ bool ManualBulletShapeLoader::hasRootCollisionNode(Nif::Node const * node) { if(!list[i].empty()) { - if(hasRootCollisionNode(list[i].getPtr())) - return true; + if(list[i].getPtr()->recType == Nif::RC_RootCollisionNode) + return false; } } } - - return false; + return true; } void ManualBulletShapeLoader::handleNode(const Nif::Node *node, int flags, @@ -230,8 +226,8 @@ void ManualBulletShapeLoader::handleNode(const Nif::Node *node, int flags, } } - if ( (isCollisionNode || (!mShape->mHasCollisionNode && !raycasting)) - && (!isMarker || (mShape->mHasCollisionNode && !raycasting))) + if ( (isCollisionNode || (mShape->mAutogenerated && !raycasting)) + && (!isMarker || (!mShape->mAutogenerated && !raycasting))) { // NOTE: a trishape with hasBounds=true, but no BBoxCollision flag should NOT go through handleNiTriShape! // It must be ignored completely. diff --git a/components/nifbullet/bulletnifloader.hpp b/components/nifbullet/bulletnifloader.hpp index a9ee968b9..8a77e9e9e 100644 --- a/components/nifbullet/bulletnifloader.hpp +++ b/components/nifbullet/bulletnifloader.hpp @@ -112,7 +112,7 @@ private: /** *Helper function */ - bool hasRootCollisionNode(const Nif::Node *node); + bool hasAutoGeneratedCollision(const Nif::Node *rootNode); /** *convert a NiTriShape to a bullet trishape. diff --git a/libs/openengine/bullet/BulletShapeLoader.cpp b/libs/openengine/bullet/BulletShapeLoader.cpp index 5e3eeec96..fd9204b44 100644 --- a/libs/openengine/bullet/BulletShapeLoader.cpp +++ b/libs/openengine/bullet/BulletShapeLoader.cpp @@ -19,7 +19,7 @@ Ogre::Resource(creator, name, handle, group, isManual, loader) */ mCollisionShape = NULL; mRaycastingShape = NULL; - mHasCollisionNode = false; + mAutogenerated = true; mCollide = true; createParamDictionary("BulletShape"); } diff --git a/libs/openengine/bullet/BulletShapeLoader.h b/libs/openengine/bullet/BulletShapeLoader.h index a95640cf1..472a9861f 100644 --- a/libs/openengine/bullet/BulletShapeLoader.h +++ b/libs/openengine/bullet/BulletShapeLoader.h @@ -41,9 +41,8 @@ public: btCollisionShape* mCollisionShape; btCollisionShape* mRaycastingShape; - // Whether or not a NiRootCollisionNode was present in the .nif. If there is none, the collision behaviour - // depends on object type, so we need to expose this variable. - bool mHasCollisionNode; + // Does this .nif have an autogenerated collision mesh? + bool mAutogenerated; Ogre::Vector3 mBoxTranslation; Ogre::Quaternion mBoxRotation; diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index 0b08e28d9..94bd39788 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -456,7 +456,7 @@ namespace Physic BulletShapeManager::getSingletonPtr()->load(outputstring,"General"); BulletShapePtr shape = BulletShapeManager::getSingleton().getByName(outputstring,"General"); - if (placeable && !raycasting && shape->mCollisionShape && !shape->mHasCollisionNode) + if (placeable && !raycasting && shape->mCollisionShape && shape->mAutogenerated) return NULL; if (!shape->mCollisionShape && !raycasting) From 871d59de6ce9f910c5792aacb00e0cbd546b45e5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 12 Jan 2015 12:09:26 +0100 Subject: [PATCH 0290/3725] Reduce Idle voice chance (Fixes #1964) --- apps/openmw/mwmechanics/aiwander.cpp | 43 ++++++++++++++++------------ 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 30e17c7f4..c3278a5ad 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -9,6 +9,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/dialoguemanager.hpp" +#include "../mwbase/soundmanager.hpp" #include "../mwworld/class.hpp" #include "../mwworld/esmstore.hpp" @@ -301,28 +302,32 @@ namespace MWMechanics playIdle(actor, playedIdle); chooseAction = false; idleNow = true; - - // Play idle voiced dialogue entries randomly - int hello = cStats.getAiSetting(CreatureStats::AI_Hello).getModified(); - if (hello > 0) - { - int roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 100; // [0, 99] - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); - - // Don't bother if the player is out of hearing range - static float fVoiceIdleOdds = MWBase::Environment::get().getWorld()->getStore() - .get().find("fVoiceIdleOdds")->getFloat(); - - // Only say Idle voices when player is in LOS - // A bit counterintuitive, likely vanilla did this to reduce the appearance of - // voices going through walls? - if (roll < fVoiceIdleOdds && Ogre::Vector3(player.getRefData().getPosition().pos).squaredDistance(Ogre::Vector3(pos.pos)) < 1500*1500 - && MWBase::Environment::get().getWorld()->getLOS(player, actor)) - MWBase::Environment::get().getDialogueManager()->say(actor, "idle"); - } } } + // Play idle voiced dialogue entries randomly + int hello = cStats.getAiSetting(CreatureStats::AI_Hello).getModified(); + if (hello > 0 && !MWBase::Environment::get().getWorld()->isSwimming(actor) + && actor.getRefData().getPosition().pos[2] < 3000 && + MWBase::Environment::get().getSoundManager()->sayDone(actor)) + { + float roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 10000; // [0, 9999] + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + + // Don't bother if the player is out of hearing range + static float fVoiceIdleOdds = MWBase::Environment::get().getWorld()->getStore() + .get().find("fVoiceIdleOdds")->getFloat(); + + float x = fVoiceIdleOdds * MWBase::Environment::get().getFrameDuration(); + + // Only say Idle voices when player is in LOS + // A bit counterintuitive, likely vanilla did this to reduce the appearance of + // voices going through walls? + if (roll < x && Ogre::Vector3(player.getRefData().getPosition().pos).squaredDistance(Ogre::Vector3(pos.pos)) < 1500*1500 + && MWBase::Environment::get().getWorld()->getLOS(player, actor)) + MWBase::Environment::get().getDialogueManager()->say(actor, "idle"); + } + float& lastReaction = storage.mReaction; lastReaction += duration; if(lastReaction < REACTION_INTERVAL) From cda2eea906531709599a7a0768db87bb7ee975ed Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 12 Jan 2015 19:51:05 +0100 Subject: [PATCH 0291/3725] Enchanting: use fEnchantmentConstantDurationMult and fEffectCostMult --- apps/openmw/mwmechanics/enchanting.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp index 96afe2e2a..31ad4a01a 100644 --- a/apps/openmw/mwmechanics/enchanting.cpp +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -176,23 +176,25 @@ namespace MWMechanics int magMax = (it->mMagnMax == 0) ? 1 : it->mMagnMax; int area = (it->mArea == 0) ? 1 : it->mArea; - float magnitudeCost = 0; + float magnitudeCost = (magMin + magMax) * baseCost * 0.05; if (mCastStyle == ESM::Enchantment::ConstantEffect) { - magnitudeCost = (magMin + magMax) * baseCost * 2.5; + magnitudeCost *= store.get().find("fEnchantmentConstantDurationMult")->getFloat(); } else { - magnitudeCost = (magMin + magMax) * it->mDuration * baseCost * 0.025; + magnitudeCost *= it->mDuration; if(it->mRange == ESM::RT_Target) magnitudeCost *= 1.5; } - float areaCost = area * 0.025 * baseCost; + float areaCost = area * 0.05 * baseCost; if (it->mRange == ESM::RT_Target) areaCost *= 1.5; - enchantmentCost += (magnitudeCost + areaCost) * effectsLeftCnt; + const float fEffectCostMult = store.get().find("fEffectCostMult")->getFloat(); + + enchantmentCost += (magnitudeCost + areaCost) * fEffectCostMult * effectsLeftCnt; --effectsLeftCnt; } From de23ad5c8d6ef3440ef9a7b4fe3a86dacf4e0b34 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 12 Jan 2015 19:57:54 +0100 Subject: [PATCH 0292/3725] Change dynamic_cast to static_cast to make coverity happy --- apps/openmw/mwgui/bookpage.cpp | 6 +++--- apps/openmw/mwmechanics/actors.cpp | 10 +++++----- apps/openmw/mwmechanics/aisequence.cpp | 14 +++++++------- apps/openmw/mwrender/globalmap.cpp | 2 +- apps/openmw/mwrender/localmap.cpp | 2 +- components/nifogre/mesh.cpp | 4 ++-- components/nifogre/ogrenifloader.cpp | 6 +++--- libs/openengine/bullet/physic.cpp | 2 +- 8 files changed, 23 insertions(+), 23 deletions(-) diff --git a/apps/openmw/mwgui/bookpage.cpp b/apps/openmw/mwgui/bookpage.cpp index 0f2df494a..3b1d40fc3 100644 --- a/apps/openmw/mwgui/bookpage.cpp +++ b/apps/openmw/mwgui/bookpage.cpp @@ -246,7 +246,7 @@ struct TypesetBookImpl::Typesetter : BookTypesetter Style* createHotStyle (Style* baseStyle, Colour normalColour, Colour hoverColour, Colour activeColour, InteractiveId id, bool unique) { - StyleImpl* BaseStyle = dynamic_cast (baseStyle); + StyleImpl* BaseStyle = static_cast (baseStyle); if (!unique) for (Styles::iterator i = mBook->mStyles.begin (); i != mBook->mStyles.end (); ++i) @@ -268,7 +268,7 @@ struct TypesetBookImpl::Typesetter : BookTypesetter { Range range = mBook->addContent (text); - writeImpl (dynamic_cast (style), range.first, range.second); + writeImpl (static_cast (style), range.first, range.second); } intptr_t addContent (Utf8Span text, bool select) @@ -295,7 +295,7 @@ struct TypesetBookImpl::Typesetter : BookTypesetter Utf8Point begin_ = &mCurrentContent->front () + begin; Utf8Point end_ = &mCurrentContent->front () + end ; - writeImpl (dynamic_cast (style), begin_, end_); + writeImpl (static_cast (style), begin_, end_); } void lineBreak (float margin) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index adabff092..a454d816a 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -131,7 +131,7 @@ void adjustCommandedActor (const MWWorld::Ptr& actor) for (it = stats.getAiSequence().begin(); it != stats.getAiSequence().end(); ++it) { if ((*it)->getTypeId() == MWMechanics::AiPackage::TypeIdFollow && - dynamic_cast(*it)->isCommanded()) + static_cast(*it)->isCommanded()) { hasCommandPackage = true; break; @@ -355,7 +355,7 @@ namespace MWMechanics { if ((*it)->getTypeId() == MWMechanics::AiPackage::TypeIdFollow) { - MWWorld::Ptr followTarget = dynamic_cast(*it)->getTarget(); + MWWorld::Ptr followTarget = static_cast(*it)->getTarget(); if (followTarget.isEmpty()) continue; @@ -1389,7 +1389,7 @@ namespace MWMechanics { if ((*it)->getTypeId() == MWMechanics::AiPackage::TypeIdFollow) { - MWWorld::Ptr followTarget = dynamic_cast(*it)->getTarget(); + MWWorld::Ptr followTarget = static_cast(*it)->getTarget(); if (followTarget.isEmpty()) continue; if (followTarget == actor) @@ -1419,11 +1419,11 @@ namespace MWMechanics { if ((*it)->getTypeId() == MWMechanics::AiPackage::TypeIdFollow) { - MWWorld::Ptr followTarget = dynamic_cast(*it)->getTarget(); + MWWorld::Ptr followTarget = static_cast(*it)->getTarget(); if (followTarget.isEmpty()) continue; if (followTarget == actor) - list.push_back(dynamic_cast(*it)->getFollowIndex()); + list.push_back(static_cast(*it)->getFollowIndex()); else break; } diff --git a/apps/openmw/mwmechanics/aisequence.cpp b/apps/openmw/mwmechanics/aisequence.cpp index 13d09af7e..364e6effe 100644 --- a/apps/openmw/mwmechanics/aisequence.cpp +++ b/apps/openmw/mwmechanics/aisequence.cpp @@ -342,49 +342,49 @@ void AiSequence::readState(const ESM::AiSequence::AiSequence &sequence) case ESM::AiSequence::Ai_Wander: { MWMechanics::AiWander* wander = new AiWander( - dynamic_cast(it->mPackage)); + static_cast(it->mPackage)); mPackages.push_back(wander); break; } case ESM::AiSequence::Ai_Travel: { MWMechanics::AiTravel* travel = new AiTravel( - dynamic_cast(it->mPackage)); + static_cast(it->mPackage)); mPackages.push_back(travel); break; } case ESM::AiSequence::Ai_Escort: { MWMechanics::AiEscort* escort = new AiEscort( - dynamic_cast(it->mPackage)); + static_cast(it->mPackage)); mPackages.push_back(escort); break; } case ESM::AiSequence::Ai_Follow: { MWMechanics::AiFollow* follow = new AiFollow( - dynamic_cast(it->mPackage)); + static_cast(it->mPackage)); mPackages.push_back(follow); break; } case ESM::AiSequence::Ai_Activate: { MWMechanics::AiActivate* activate = new AiActivate( - dynamic_cast(it->mPackage)); + static_cast(it->mPackage)); mPackages.push_back(activate); break; } case ESM::AiSequence::Ai_Combat: { MWMechanics::AiCombat* combat = new AiCombat( - dynamic_cast(it->mPackage)); + static_cast(it->mPackage)); mPackages.push_back(combat); break; } case ESM::AiSequence::Ai_Pursue: { MWMechanics::AiPursue* pursue = new AiPursue( - dynamic_cast(it->mPackage)); + static_cast(it->mPackage)); mPackages.push_back(pursue); break; } diff --git a/apps/openmw/mwrender/globalmap.cpp b/apps/openmw/mwrender/globalmap.cpp index 9816b0f41..a4460c59d 100644 --- a/apps/openmw/mwrender/globalmap.cpp +++ b/apps/openmw/mwrender/globalmap.cpp @@ -245,7 +245,7 @@ namespace MWRender void GlobalMap::loadResource(Ogre::Resource *resource) { - Ogre::Texture* tex = dynamic_cast(resource); + Ogre::Texture* tex = static_cast(resource); Ogre::ConstImagePtrList list; list.push_back(&mOverlayImage); tex->_loadImages(list); diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 059d83e79..c152d1513 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -494,7 +494,7 @@ void LocalMap::loadResource(Ogre::Resource* resource) std::vector& buffer = mBuffers[resourceName]; - Ogre::Texture* tex = dynamic_cast(resource); + Ogre::Texture* tex = static_cast(resource); tex->createInternalResources(); memcpy(tex->getBuffer()->lock(HardwareBuffer::HBL_DISCARD), &buffer[0], sFogOfWarResolution*sFogOfWarResolution*4); tex->getBuffer()->unlock(); diff --git a/components/nifogre/mesh.cpp b/components/nifogre/mesh.cpp index 4932dd009..85c3a7b65 100644 --- a/components/nifogre/mesh.cpp +++ b/components/nifogre/mesh.cpp @@ -382,7 +382,7 @@ NIFMeshLoader::NIFMeshLoader(const std::string &name, const std::string &group, void NIFMeshLoader::loadResource(Ogre::Resource *resource) { - Ogre::Mesh *mesh = dynamic_cast(resource); + Ogre::Mesh *mesh = static_cast(resource); OgreAssert(mesh, "Attempting to load a mesh into a non-mesh resource!"); Nif::NIFFilePtr nif = Nif::Cache::getInstance().load(mName); @@ -395,7 +395,7 @@ void NIFMeshLoader::loadResource(Ogre::Resource *resource) } const Nif::Record *record = nif->getRecord(mShapeIndex); - createSubMesh(mesh, dynamic_cast(record)); + createSubMesh(mesh, static_cast(record)); } diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 9c5f4a016..7ec2c2c24 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -799,7 +799,7 @@ class NIFObjectLoader { if (ctrls->recType == Nif::RC_NiAlphaController) { - const Nif::NiAlphaController *alphaCtrl = dynamic_cast(ctrls.getPtr()); + const Nif::NiAlphaController *alphaCtrl = static_cast(ctrls.getPtr()); Ogre::ControllerValueRealPtr dstval(OGRE_NEW AlphaController::Value(movable, alphaCtrl->data.getPtr(), &scene->mMaterialControllerMgr)); AlphaController::Function* function = OGRE_NEW AlphaController::Function(alphaCtrl, (animflags&Nif::NiNode::AnimFlag_AutoPlay)); scene->mMaxControllerLength = std::max(function->mStopTime, scene->mMaxControllerLength); @@ -808,7 +808,7 @@ class NIFObjectLoader } else if (ctrls->recType == Nif::RC_NiMaterialColorController) { - const Nif::NiMaterialColorController *matCtrl = dynamic_cast(ctrls.getPtr()); + const Nif::NiMaterialColorController *matCtrl = static_cast(ctrls.getPtr()); Ogre::ControllerValueRealPtr dstval(OGRE_NEW MaterialColorController::Value(movable, matCtrl->data.getPtr(), &scene->mMaterialControllerMgr)); MaterialColorController::Function* function = OGRE_NEW MaterialColorController::Function(matCtrl, (animflags&Nif::NiNode::AnimFlag_AutoPlay)); scene->mMaxControllerLength = std::max(function->mStopTime, scene->mMaxControllerLength); @@ -826,7 +826,7 @@ class NIFObjectLoader { if (ctrls->recType == Nif::RC_NiFlipController) { - const Nif::NiFlipController *flipCtrl = dynamic_cast(ctrls.getPtr()); + const Nif::NiFlipController *flipCtrl = static_cast(ctrls.getPtr()); Ogre::ControllerValueRealPtr dstval(OGRE_NEW FlipController::Value( diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index 94bd39788..ed6d74b9b 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -35,7 +35,7 @@ btCollisionShape *duplicateCollisionShape(btCollisionShape *shape) if(btBvhTriangleMeshShape *trishape = dynamic_cast(shape)) { - btTriangleMesh* oldMesh = dynamic_cast(trishape->getMeshInterface()); + btTriangleMesh* oldMesh = static_cast(trishape->getMeshInterface()); btTriangleMesh* newMesh = new btTriangleMesh(*oldMesh); NifBullet::TriangleMeshShape *newShape = new NifBullet::TriangleMeshShape(newMesh, true); From 08d8dd287cb59b4759764b34c06dbba672015dc0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 12 Jan 2015 20:25:06 +0100 Subject: [PATCH 0293/3725] I think this was committed by accident --- apps/openmw/mwrender/localmap.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index c152d1513..638a08623 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -200,7 +200,7 @@ void LocalMap::requestMap(MWWorld::CellStore* cell, // Get the cell's NorthMarker rotation. This is used to rotate the entire map. const Vector2& north = MWBase::Environment::get().getWorld()->getNorthVector(cell); - Radian angle = Ogre::Math::ATan2 (north.x, north.y) + Ogre::Degree(2); + Radian angle = Ogre::Math::ATan2 (north.x, north.y); mAngle = angle.valueRadians(); // Rotate the cell and merge the rotated corners to the bounding box From bb718f216db6216ed886172bd23bf7a0b6d5ef4b Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 12 Jan 2015 20:25:25 +0100 Subject: [PATCH 0294/3725] Initialize ENAMstruct in SpellCreationDialog (Coverity) --- apps/openmw/mwgui/spellcreationdialog.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index a00afdab8..f4c9d021a 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -36,6 +36,18 @@ namespace return gmst.find(ESM::MagicEffect::effectIdToString (id1))->getString() < gmst.find(ESM::MagicEffect::effectIdToString (id2))->getString(); } + + void init(ESM::ENAMstruct& effect) + { + effect.mArea = 0; + effect.mDuration = 0; + effect.mEffectID = -1; + effect.mMagnMax = 0; + effect.mMagnMin = 0; + effect.mRange = 0; + effect.mSkill = -1; + effect.mAttribute = -1; + } } namespace MWGui @@ -47,6 +59,9 @@ namespace MWGui , mMagicEffect(NULL) , mConstantEffect(false) { + init(mEffect); + init(mOldEffect); + getWidget(mCancelButton, "CancelButton"); getWidget(mOkButton, "OkButton"); getWidget(mDeleteButton, "DeleteButton"); From 4ed3e7bbb7714d93771689114d6867494385b30a Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 12 Jan 2015 23:28:52 +0100 Subject: [PATCH 0295/3725] Enchanting code cleanup --- apps/openmw/mwmechanics/enchanting.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp index 31ad4a01a..002831acc 100644 --- a/apps/openmw/mwmechanics/enchanting.cpp +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -171,7 +171,6 @@ namespace MWMechanics for (std::vector::const_iterator it = mEffects.begin(); it != mEffects.end(); ++it) { float baseCost = (store.get().find(it->mEffectID))->mData.mBaseCost; - // To reflect vanilla behavior int magMin = (it->mMagnMin == 0) ? 1 : it->mMagnMin; int magMax = (it->mMagnMax == 0) ? 1 : it->mMagnMax; int area = (it->mArea == 0) ? 1 : it->mArea; @@ -184,17 +183,18 @@ namespace MWMechanics else { magnitudeCost *= it->mDuration; - if(it->mRange == ESM::RT_Target) - magnitudeCost *= 1.5; } float areaCost = area * 0.05 * baseCost; - if (it->mRange == ESM::RT_Target) - areaCost *= 1.5; const float fEffectCostMult = store.get().find("fEffectCostMult")->getFloat(); - enchantmentCost += (magnitudeCost + areaCost) * fEffectCostMult * effectsLeftCnt; + float cost = (magnitudeCost + areaCost) * fEffectCostMult; + if (it->mRange == ESM::RT_Target) + cost *= 1.5; + + enchantmentCost += cost * effectsLeftCnt; + enchantmentCost = std::max(1.f, enchantmentCost); --effectsLeftCnt; } From 41b3a9dba9206d24778140d668c7a4290273a4a7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 12 Jan 2015 11:29:56 +0100 Subject: [PATCH 0296/3725] Rewrite animated collision shape support (Fixes #2123) --- apps/openmw/mwclass/activator.cpp | 10 ++- apps/openmw/mwclass/activator.hpp | 4 +- apps/openmw/mwclass/apparatus.cpp | 8 +-- apps/openmw/mwclass/apparatus.hpp | 4 +- apps/openmw/mwclass/armor.cpp | 8 +-- apps/openmw/mwclass/armor.hpp | 4 +- apps/openmw/mwclass/book.cpp | 8 +-- apps/openmw/mwclass/book.hpp | 4 +- apps/openmw/mwclass/clothing.cpp | 8 +-- apps/openmw/mwclass/clothing.hpp | 4 +- apps/openmw/mwclass/container.cpp | 10 ++- apps/openmw/mwclass/container.hpp | 4 +- apps/openmw/mwclass/creature.cpp | 9 ++- apps/openmw/mwclass/creature.hpp | 4 +- apps/openmw/mwclass/door.cpp | 10 ++- apps/openmw/mwclass/door.hpp | 4 +- apps/openmw/mwclass/ingredient.cpp | 8 +-- apps/openmw/mwclass/ingredient.hpp | 4 +- apps/openmw/mwclass/light.cpp | 10 ++- apps/openmw/mwclass/light.hpp | 4 +- apps/openmw/mwclass/lockpick.cpp | 8 +-- apps/openmw/mwclass/lockpick.hpp | 4 +- apps/openmw/mwclass/misc.cpp | 8 +-- apps/openmw/mwclass/misc.hpp | 4 +- apps/openmw/mwclass/npc.cpp | 6 +- apps/openmw/mwclass/npc.hpp | 4 +- apps/openmw/mwclass/potion.cpp | 8 +-- apps/openmw/mwclass/potion.hpp | 4 +- apps/openmw/mwclass/probe.cpp | 8 +-- apps/openmw/mwclass/probe.hpp | 4 +- apps/openmw/mwclass/repair.cpp | 8 +-- apps/openmw/mwclass/repair.hpp | 4 +- apps/openmw/mwclass/static.cpp | 8 +-- apps/openmw/mwclass/static.hpp | 4 +- apps/openmw/mwclass/weapon.cpp | 8 +-- apps/openmw/mwclass/weapon.hpp | 4 +- apps/openmw/mwrender/activatoranimation.cpp | 8 +-- apps/openmw/mwrender/activatoranimation.hpp | 2 +- apps/openmw/mwrender/actors.cpp | 10 +-- apps/openmw/mwrender/actors.hpp | 4 +- apps/openmw/mwrender/animation.cpp | 46 ++++++------- apps/openmw/mwrender/animation.hpp | 4 ++ apps/openmw/mwrender/creatureanimation.cpp | 10 ++- apps/openmw/mwrender/creatureanimation.hpp | 4 +- apps/openmw/mwrender/npcanimation.cpp | 15 +++-- apps/openmw/mwrender/renderingmanager.cpp | 4 +- apps/openmw/mwrender/renderingmanager.hpp | 2 +- apps/openmw/mwworld/class.cpp | 4 +- apps/openmw/mwworld/class.hpp | 4 +- apps/openmw/mwworld/physicssystem.cpp | 33 ++++----- apps/openmw/mwworld/physicssystem.hpp | 4 +- apps/openmw/mwworld/scene.cpp | 14 ++-- apps/openmw/mwworld/worldimp.cpp | 5 +- components/misc/resourcehelpers.cpp | 17 +++++ components/misc/resourcehelpers.hpp | 2 + components/nifbullet/bulletnifloader.cpp | 75 +++++++++++++++++++-- components/nifbullet/bulletnifloader.hpp | 2 + libs/openengine/bullet/BulletShapeLoader.h | 6 +- libs/openengine/bullet/physic.cpp | 13 ++-- libs/openengine/bullet/physic.hpp | 4 +- 60 files changed, 286 insertions(+), 229 deletions(-) diff --git a/apps/openmw/mwclass/activator.cpp b/apps/openmw/mwclass/activator.cpp index 46b23e942..457b0cec1 100644 --- a/apps/openmw/mwclass/activator.cpp +++ b/apps/openmw/mwclass/activator.cpp @@ -31,20 +31,18 @@ namespace MWClass return ptr.get()->mBase->mId; } - void Activator::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const + void Activator::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { - const std::string model = getModel(ptr); if (!model.empty()) { MWRender::Actors& actors = renderingInterface.getActors(); - actors.insertActivator(ptr); + actors.insertActivator(ptr, model); } } - void Activator::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const + void Activator::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const { - const std::string model = getModel(ptr); if(!model.empty()) - physics.addObject(ptr); + physics.addObject(ptr, model); MWBase::Environment::get().getMechanicsManager()->add(ptr); } diff --git a/apps/openmw/mwclass/activator.hpp b/apps/openmw/mwclass/activator.hpp index 3e4bc3de4..e79318a55 100644 --- a/apps/openmw/mwclass/activator.hpp +++ b/apps/openmw/mwclass/activator.hpp @@ -16,10 +16,10 @@ namespace MWClass /// Return ID of \a ptr virtual std::string getId (const MWWorld::Ptr& ptr) const; - virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; + virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const; + virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); diff --git a/apps/openmw/mwclass/apparatus.cpp b/apps/openmw/mwclass/apparatus.cpp index c466cbc33..316ba3ab6 100644 --- a/apps/openmw/mwclass/apparatus.cpp +++ b/apps/openmw/mwclass/apparatus.cpp @@ -26,19 +26,17 @@ namespace MWClass return ptr.get()->mBase->mId; } - void Apparatus::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const + void Apparatus::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { - const std::string model = getModel(ptr); if (!model.empty()) { renderingInterface.getObjects().insertModel(ptr, model); } } - void Apparatus::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const + void Apparatus::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const { - const std::string model = getModel(ptr); if(!model.empty()) - physics.addObject(ptr,true); + physics.addObject(ptr, model, true); } std::string Apparatus::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/apparatus.hpp b/apps/openmw/mwclass/apparatus.hpp index 5cdda8f26..2ab0a47e3 100644 --- a/apps/openmw/mwclass/apparatus.hpp +++ b/apps/openmw/mwclass/apparatus.hpp @@ -18,10 +18,10 @@ namespace MWClass virtual float getWeight (const MWWorld::Ptr& ptr) const; - virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; + virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const; + virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index 2fa6602c4..64043157d 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -31,19 +31,17 @@ namespace MWClass return ptr.get()->mBase->mId; } - void Armor::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const + void Armor::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { - const std::string model = getModel(ptr); if (!model.empty()) { renderingInterface.getObjects().insertModel(ptr, model); } } - void Armor::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const + void Armor::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const { - const std::string model = getModel(ptr); if(!model.empty()) - physics.addObject(ptr,true); + physics.addObject(ptr, model, true); } std::string Armor::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index 8b7804c63..8c8e74cf4 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -17,10 +17,10 @@ namespace MWClass virtual float getWeight (const MWWorld::Ptr& ptr) const; - virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; + virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const; + virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index b99d71a06..a9c96e7c7 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -28,19 +28,17 @@ namespace MWClass return ptr.get()->mBase->mId; } - void Book::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const + void Book::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { - const std::string model = getModel(ptr); if (!model.empty()) { renderingInterface.getObjects().insertModel(ptr, model); } } - void Book::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const + void Book::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const { - const std::string model = getModel(ptr); if(!model.empty()) - physics.addObject(ptr,true); + physics.addObject(ptr, model, true); } std::string Book::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/book.hpp b/apps/openmw/mwclass/book.hpp index 49d21e8bf..05ff88bb2 100644 --- a/apps/openmw/mwclass/book.hpp +++ b/apps/openmw/mwclass/book.hpp @@ -15,10 +15,10 @@ namespace MWClass /// Return ID of \a ptr virtual std::string getId (const MWWorld::Ptr& ptr) const; - virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; + virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const; + virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index eb2dec0ab..0fa686dda 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -28,19 +28,17 @@ namespace MWClass return ptr.get()->mBase->mId; } - void Clothing::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const + void Clothing::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { - const std::string model = getModel(ptr); if (!model.empty()) { renderingInterface.getObjects().insertModel(ptr, model); } } - void Clothing::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const + void Clothing::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const { - const std::string model = getModel(ptr); if(!model.empty()) - physics.addObject(ptr,true); + physics.addObject(ptr, model, true); } std::string Clothing::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index 99ce61ece..570054348 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -15,10 +15,10 @@ namespace MWClass /// Return ID of \a ptr virtual std::string getId (const MWWorld::Ptr& ptr) const; - virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; + virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const; + virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index b05837cb6..c6a7bbf74 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -85,20 +85,18 @@ namespace MWClass store.restock(list, ptr, ptr.getCellRef().getOwner(), ptr.getCellRef().getFaction(), ptr.getCellRef().getFactionRank()); } - void Container::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const + void Container::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { - const std::string model = getModel(ptr); if (!model.empty()) { MWRender::Actors& actors = renderingInterface.getActors(); - actors.insertActivator(ptr); + actors.insertActivator(ptr, model); } } - void Container::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const + void Container::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const { - const std::string model = getModel(ptr); if(!model.empty()) - physics.addObject(ptr); + physics.addObject(ptr, model); MWBase::Environment::get().getMechanicsManager()->add(ptr); } diff --git a/apps/openmw/mwclass/container.hpp b/apps/openmw/mwclass/container.hpp index e926a71fe..52873374e 100644 --- a/apps/openmw/mwclass/container.hpp +++ b/apps/openmw/mwclass/container.hpp @@ -18,10 +18,10 @@ namespace MWClass /// Return ID of \a ptr virtual std::string getId (const MWWorld::Ptr& ptr) const; - virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; + virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const; + virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 9eb5b1b69..a3614af96 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -160,20 +160,19 @@ namespace MWClass MWBase::Environment::get().getWorld()->adjustPosition(ptr, force); } - void Creature::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const + void Creature::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { MWWorld::LiveCellRef *ref = ptr.get(); MWRender::Actors& actors = renderingInterface.getActors(); - actors.insertCreature(ptr, ref->mBase->mFlags & ESM::Creature::Weapon); + actors.insertCreature(ptr, model, ref->mBase->mFlags & ESM::Creature::Weapon); } - void Creature::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const + void Creature::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const { - const std::string model = getModel(ptr); if(!model.empty()) { - physics.addActor(ptr); + physics.addActor(ptr, model); if (getCreatureStats(ptr).isDead()) MWBase::Environment::get().getWorld()->enableActorCollision(ptr, false); } diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index 4b5886448..e11529b2e 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -44,10 +44,10 @@ namespace MWClass virtual std::string getId (const MWWorld::Ptr& ptr) const; ///< Return ID of \a ptr - virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; + virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const; + virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const; virtual void adjustPosition(const MWWorld::Ptr& ptr, bool force) const; ///< Adjust position to stand on ground. Must be called post model load diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index ee3993fc5..84c6c66fd 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -49,20 +49,18 @@ namespace MWClass return ptr.get()->mBase->mId; } - void Door::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const + void Door::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { - const std::string model = getModel(ptr); if (!model.empty()) { MWRender::Actors& actors = renderingInterface.getActors(); - actors.insertActivator(ptr); + actors.insertActivator(ptr, model); } } - void Door::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const + void Door::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const { - const std::string model = getModel(ptr); if(!model.empty()) - physics.addObject(ptr); + physics.addObject(ptr, model); // Resume the door's opening/closing animation if it wasn't finished if (ptr.getRefData().getCustomData()) diff --git a/apps/openmw/mwclass/door.hpp b/apps/openmw/mwclass/door.hpp index 23e11d336..c5f258d3e 100644 --- a/apps/openmw/mwclass/door.hpp +++ b/apps/openmw/mwclass/door.hpp @@ -19,10 +19,10 @@ namespace MWClass /// Return ID of \a ptr virtual std::string getId (const MWWorld::Ptr& ptr) const; - virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; + virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const; + virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); diff --git a/apps/openmw/mwclass/ingredient.cpp b/apps/openmw/mwclass/ingredient.cpp index 610a0b478..9f662a60e 100644 --- a/apps/openmw/mwclass/ingredient.cpp +++ b/apps/openmw/mwclass/ingredient.cpp @@ -32,19 +32,17 @@ namespace MWClass return ref->mBase->mId; } - void Ingredient::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const + void Ingredient::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { - const std::string model = getModel(ptr); if (!model.empty()) { renderingInterface.getObjects().insertModel(ptr, model); } } - void Ingredient::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const + void Ingredient::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const { - const std::string model = getModel(ptr); if(!model.empty()) - physics.addObject(ptr,true); + physics.addObject(ptr, model, true); } std::string Ingredient::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/ingredient.hpp b/apps/openmw/mwclass/ingredient.hpp index 690dd601a..a4681f462 100644 --- a/apps/openmw/mwclass/ingredient.hpp +++ b/apps/openmw/mwclass/ingredient.hpp @@ -15,10 +15,10 @@ namespace MWClass virtual std::string getId (const MWWorld::Ptr& ptr) const; ///< Return ID of \a ptr - virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; + virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const; + virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 7ad81232d..669b8187c 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -54,26 +54,24 @@ namespace MWClass return ptr.get()->mBase->mId; } - void Light::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const + void Light::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { MWWorld::LiveCellRef *ref = ptr.get(); // Insert even if model is empty, so that the light is added MWRender::Actors& actors = renderingInterface.getActors(); - actors.insertActivator(ptr, !(ref->mBase->mData.mFlags & ESM::Light::OffDefault)); + actors.insertActivator(ptr, model, !(ref->mBase->mData.mFlags & ESM::Light::OffDefault)); } - void Light::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const + void Light::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const { MWWorld::LiveCellRef *ref = ptr.get(); assert (ref->mBase != NULL); - const std::string &model = ref->mBase->mModel; - if(!model.empty()) - physics.addObject(ptr,ref->mBase->mData.mFlags & ESM::Light::Carry); + physics.addObject(ptr, model, ref->mBase->mData.mFlags & ESM::Light::Carry); if (!ref->mBase->mSound.empty() && !(ref->mBase->mData.mFlags & ESM::Light::OffDefault)) MWBase::Environment::get().getSoundManager()->playSound3D(ptr, ref->mBase->mSound, 1.0, 1.0, diff --git a/apps/openmw/mwclass/light.hpp b/apps/openmw/mwclass/light.hpp index a3b841261..bbca30113 100644 --- a/apps/openmw/mwclass/light.hpp +++ b/apps/openmw/mwclass/light.hpp @@ -17,10 +17,10 @@ namespace MWClass /// Return ID of \a ptr virtual std::string getId (const MWWorld::Ptr& ptr) const; - virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; + virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const; + virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index 9df587024..e78c43eee 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -27,19 +27,17 @@ namespace MWClass return ptr.get()->mBase->mId; } - void Lockpick::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const + void Lockpick::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { - const std::string model = getModel(ptr); if (!model.empty()) { renderingInterface.getObjects().insertModel(ptr, model); } } - void Lockpick::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const + void Lockpick::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const { - const std::string model = getModel(ptr); if(!model.empty()) - physics.addObject(ptr,true); + physics.addObject(ptr, model, true); } std::string Lockpick::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/lockpick.hpp b/apps/openmw/mwclass/lockpick.hpp index d4bdf3fa6..293a40be1 100644 --- a/apps/openmw/mwclass/lockpick.hpp +++ b/apps/openmw/mwclass/lockpick.hpp @@ -15,10 +15,10 @@ namespace MWClass /// Return ID of \a ptr virtual std::string getId (const MWWorld::Ptr& ptr) const; - virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; + virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const; + virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index 1b4719c6e..271a7510e 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -43,19 +43,17 @@ namespace MWClass return ptr.get()->mBase->mId; } - void Miscellaneous::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const + void Miscellaneous::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { - const std::string model = getModel(ptr); if (!model.empty()) { renderingInterface.getObjects().insertModel(ptr, model); } } - void Miscellaneous::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const + void Miscellaneous::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const { - const std::string model = getModel(ptr); if(!model.empty()) - physics.addObject(ptr,true); + physics.addObject(ptr, model, true); } std::string Miscellaneous::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/misc.hpp b/apps/openmw/mwclass/misc.hpp index 53a8e050b..23160d41c 100644 --- a/apps/openmw/mwclass/misc.hpp +++ b/apps/openmw/mwclass/misc.hpp @@ -15,10 +15,10 @@ namespace MWClass /// Return ID of \a ptr virtual std::string getId (const MWWorld::Ptr& ptr) const; - virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; + virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const; + virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 596b56acd..ac4182734 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -428,14 +428,14 @@ namespace MWClass MWBase::Environment::get().getWorld()->adjustPosition(ptr, force); } - void Npc::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const + void Npc::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { renderingInterface.getActors().insertNPC(ptr); } - void Npc::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const + void Npc::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const { - physics.addActor(ptr); + physics.addActor(ptr, model); MWBase::Environment::get().getMechanicsManager()->add(ptr); if (getCreatureStats(ptr).isDead()) MWBase::Environment::get().getWorld()->enableActorCollision(ptr, false); diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index 8c89686af..56931a419 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -50,10 +50,10 @@ namespace MWClass virtual std::string getId (const MWWorld::Ptr& ptr) const; ///< Return ID of \a ptr - virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; + virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const; + virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const; virtual void adjustPosition(const MWWorld::Ptr& ptr, bool force) const; ///< Adjust position to stand on ground. Must be called post model load diff --git a/apps/openmw/mwclass/potion.cpp b/apps/openmw/mwclass/potion.cpp index 814d903ff..bd06f89fc 100644 --- a/apps/openmw/mwclass/potion.cpp +++ b/apps/openmw/mwclass/potion.cpp @@ -30,19 +30,17 @@ namespace MWClass return ptr.get()->mBase->mId; } - void Potion::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const + void Potion::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { - const std::string model = getModel(ptr); if (!model.empty()) { renderingInterface.getObjects().insertModel(ptr, model); } } - void Potion::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const + void Potion::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const { - const std::string model = getModel(ptr); if(!model.empty()) - physics.addObject(ptr,true); + physics.addObject(ptr, model, true); } std::string Potion::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/potion.hpp b/apps/openmw/mwclass/potion.hpp index 4c407d161..32e390115 100644 --- a/apps/openmw/mwclass/potion.hpp +++ b/apps/openmw/mwclass/potion.hpp @@ -15,10 +15,10 @@ namespace MWClass /// Return ID of \a ptr virtual std::string getId (const MWWorld::Ptr& ptr) const; - virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; + virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const; + virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index 82f487986..a11725f26 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -27,19 +27,17 @@ namespace MWClass return ptr.get()->mBase->mId; } - void Probe::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const + void Probe::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { - const std::string model = getModel(ptr); if (!model.empty()) { renderingInterface.getObjects().insertModel(ptr, model); } } - void Probe::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const + void Probe::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const { - const std::string model = getModel(ptr); if(!model.empty()) - physics.addObject(ptr,true); + physics.addObject(ptr, model, true); } std::string Probe::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/probe.hpp b/apps/openmw/mwclass/probe.hpp index 047cb8ed4..bb90ac153 100644 --- a/apps/openmw/mwclass/probe.hpp +++ b/apps/openmw/mwclass/probe.hpp @@ -15,10 +15,10 @@ namespace MWClass /// Return ID of \a ptr virtual std::string getId (const MWWorld::Ptr& ptr) const; - virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; + virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const; + virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); diff --git a/apps/openmw/mwclass/repair.cpp b/apps/openmw/mwclass/repair.cpp index 4b18aced0..e9c4ac9b1 100644 --- a/apps/openmw/mwclass/repair.cpp +++ b/apps/openmw/mwclass/repair.cpp @@ -26,19 +26,17 @@ namespace MWClass return ptr.get()->mBase->mId; } - void Repair::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const + void Repair::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { - const std::string model = getModel(ptr); if (!model.empty()) { renderingInterface.getObjects().insertModel(ptr, model); } } - void Repair::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const + void Repair::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const { - const std::string model = getModel(ptr); if(!model.empty()) - physics.addObject(ptr,true); + physics.addObject(ptr, model, true); } std::string Repair::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/repair.hpp b/apps/openmw/mwclass/repair.hpp index f89258234..2589a4af3 100644 --- a/apps/openmw/mwclass/repair.hpp +++ b/apps/openmw/mwclass/repair.hpp @@ -15,10 +15,10 @@ namespace MWClass /// Return ID of \a ptr virtual std::string getId (const MWWorld::Ptr& ptr) const; - virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; + virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const; + virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); diff --git a/apps/openmw/mwclass/static.cpp b/apps/openmw/mwclass/static.cpp index c241935ab..dbbe7e43a 100644 --- a/apps/openmw/mwclass/static.cpp +++ b/apps/openmw/mwclass/static.cpp @@ -17,22 +17,20 @@ namespace MWClass return ptr.get()->mBase->mId; } - void Static::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const + void Static::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { MWWorld::LiveCellRef *ref = ptr.get(); - const std::string model = getModel(ptr); if (!model.empty()) { renderingInterface.getObjects().insertModel(ptr, model, !ref->mBase->mPersistent); } } - void Static::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const + void Static::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const { - const std::string model = getModel(ptr); if(!model.empty()) - physics.addObject(ptr); + physics.addObject(ptr, model); } std::string Static::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/static.hpp b/apps/openmw/mwclass/static.hpp index 2ac2e8682..a94dff394 100644 --- a/apps/openmw/mwclass/static.hpp +++ b/apps/openmw/mwclass/static.hpp @@ -15,10 +15,10 @@ namespace MWClass /// Return ID of \a ptr virtual std::string getId (const MWWorld::Ptr& ptr) const; - virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; + virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const; + virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index 8456c72e6..122c8eeae 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -30,19 +30,17 @@ namespace MWClass return ref->mBase->mId; } - void Weapon::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const + void Weapon::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { - const std::string model = getModel(ptr); if (!model.empty()) { renderingInterface.getObjects().insertModel(ptr, model); } } - void Weapon::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const + void Weapon::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const { - const std::string model = getModel(ptr); if(!model.empty()) - physics.addObject(ptr,true); + physics.addObject(ptr, model, true); } std::string Weapon::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index 97ee10291..47f1c5251 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -15,10 +15,10 @@ namespace MWClass virtual std::string getId (const MWWorld::Ptr& ptr) const; ///< Return ID of \a ptr - virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; + virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const; + virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); diff --git a/apps/openmw/mwrender/activatoranimation.cpp b/apps/openmw/mwrender/activatoranimation.cpp index 4c63e2cf2..1ef68f619 100644 --- a/apps/openmw/mwrender/activatoranimation.cpp +++ b/apps/openmw/mwrender/activatoranimation.cpp @@ -5,10 +5,6 @@ #include -#include "../mwbase/world.hpp" - -#include "../mwworld/class.hpp" - #include "renderconst.hpp" namespace MWRender @@ -18,11 +14,9 @@ ActivatorAnimation::~ActivatorAnimation() { } -ActivatorAnimation::ActivatorAnimation(const MWWorld::Ptr &ptr) +ActivatorAnimation::ActivatorAnimation(const MWWorld::Ptr &ptr, const std::string& model) : Animation(ptr, ptr.getRefData().getBaseNode()) { - const std::string& model = mPtr.getClass().getModel(mPtr); - if(!model.empty()) { setObjectRoot(model, false); diff --git a/apps/openmw/mwrender/activatoranimation.hpp b/apps/openmw/mwrender/activatoranimation.hpp index ec0114ccd..a234defe7 100644 --- a/apps/openmw/mwrender/activatoranimation.hpp +++ b/apps/openmw/mwrender/activatoranimation.hpp @@ -13,7 +13,7 @@ namespace MWRender class ActivatorAnimation : public Animation { public: - ActivatorAnimation(const MWWorld::Ptr& ptr); + ActivatorAnimation(const MWWorld::Ptr& ptr, const std::string &model); virtual ~ActivatorAnimation(); void addLight(const ESM::Light *light); diff --git a/apps/openmw/mwrender/actors.cpp b/apps/openmw/mwrender/actors.cpp index db666e890..3da6c40c8 100644 --- a/apps/openmw/mwrender/actors.cpp +++ b/apps/openmw/mwrender/actors.cpp @@ -71,22 +71,22 @@ void Actors::insertNPC(const MWWorld::Ptr& ptr) mAllActors[ptr] = anim; mRendering->addWaterRippleEmitter (ptr); } -void Actors::insertCreature (const MWWorld::Ptr& ptr, bool weaponsShields) +void Actors::insertCreature (const MWWorld::Ptr& ptr, const std::string &model, bool weaponsShields) { insertBegin(ptr); Animation* anim = NULL; if (weaponsShields) - anim = new CreatureWeaponAnimation(ptr); + anim = new CreatureWeaponAnimation(ptr, model); else - anim = new CreatureAnimation(ptr); + anim = new CreatureAnimation(ptr, model); delete mAllActors[ptr]; mAllActors[ptr] = anim; mRendering->addWaterRippleEmitter (ptr); } -void Actors::insertActivator (const MWWorld::Ptr& ptr, bool addLight) +void Actors::insertActivator (const MWWorld::Ptr& ptr, const std::string &model, bool addLight) { insertBegin(ptr); - ActivatorAnimation* anim = new ActivatorAnimation(ptr); + ActivatorAnimation* anim = new ActivatorAnimation(ptr, model); if(ptr.getTypeName() == typeid(ESM::Light).name()) { diff --git a/apps/openmw/mwrender/actors.hpp b/apps/openmw/mwrender/actors.hpp index f81082e41..4f6c1bec2 100644 --- a/apps/openmw/mwrender/actors.hpp +++ b/apps/openmw/mwrender/actors.hpp @@ -40,8 +40,8 @@ namespace MWRender void setRootNode(Ogre::SceneNode* root); void insertNPC(const MWWorld::Ptr& ptr); - void insertCreature (const MWWorld::Ptr& ptr, bool weaponsShields); - void insertActivator (const MWWorld::Ptr& ptr, bool addLight=false); + void insertCreature (const MWWorld::Ptr& ptr, const std::string& model, bool weaponsShields); + void insertActivator (const MWWorld::Ptr& ptr, const std::string& model, bool addLight=false); bool deleteObject (const MWWorld::Ptr& ptr); ///< \return found? diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index bf161442e..117830c09 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -86,6 +86,12 @@ Animation::~Animation() mAnimSources.clear(); } +std::string Animation::getObjectRootName() const +{ + if (mSkelBase) + return mSkelBase->getMesh()->getName(); + return std::string(); +} void Animation::setObjectRoot(const std::string &model, bool baseonly) { @@ -97,22 +103,8 @@ void Animation::setObjectRoot(const std::string &model, bool baseonly) if(model.empty()) return; - std::string mdlname = Misc::StringUtils::lowerCase(model); - std::string::size_type p = mdlname.rfind('\\'); - if(p == std::string::npos) - p = mdlname.rfind('/'); - if(p != std::string::npos) - mdlname.insert(mdlname.begin()+p+1, 'x'); - else - mdlname.insert(mdlname.begin(), 'x'); - if(!Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(mdlname)) - { - mdlname = model; - Misc::StringUtils::toLower(mdlname); - } - - mObjectRoot = (!baseonly ? NifOgre::Loader::createObjects(mInsert, mdlname) : - NifOgre::Loader::createObjectBase(mInsert, mdlname)); + mObjectRoot = (!baseonly ? NifOgre::Loader::createObjects(mInsert, model) : + NifOgre::Loader::createObjectBase(mInsert, model)); if(mObjectRoot->mSkelBase) { @@ -255,14 +247,8 @@ void Animation::addAnimSource(const std::string &model) if(!mSkelBase) return; - std::string kfname = Misc::StringUtils::lowerCase(model); - std::string::size_type p = kfname.rfind('\\'); - if(p == std::string::npos) - p = kfname.rfind('/'); - if(p != std::string::npos) - kfname.insert(kfname.begin()+p+1, 'x'); - else - kfname.insert(kfname.begin(), 'x'); + std::string kfname = model; + Misc::StringUtils::toLower(kfname); if(kfname.size() > 4 && kfname.compare(kfname.size()-4, 4, ".nif") == 0) kfname.replace(kfname.size()-4, 4, ".kf"); @@ -417,7 +403,7 @@ void Animation::addExtraLight(Ogre::SceneManager *sceneMgr, NifOgre::ObjectScene } -Ogre::Node *Animation::getNode(const std::string &name) +Ogre::Node* Animation::getNode(const std::string &name) { if(mSkelBase) { @@ -428,6 +414,16 @@ Ogre::Node *Animation::getNode(const std::string &name) return NULL; } +Ogre::Node* Animation::getNode(int handle) +{ + if (mSkelBase) + { + Ogre::SkeletonInstance *skel = mSkelBase->getSkeleton(); + return skel->getBone(handle); + } + return NULL; +} + NifOgre::TextKeyMap::const_iterator Animation::findGroupStart(const NifOgre::TextKeyMap &keys, const std::string &groupname) { NifOgre::TextKeyMap::const_iterator iter(keys.begin()); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 73d10fd06..dab8cfebb 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -206,6 +206,9 @@ public: Ogre::uint8 transqueue, Ogre::Real dist=0.0f, bool enchantedGlow=false, Ogre::Vector3* glowColor=NULL); + /// Returns the name of the .nif file that makes up this animation's base skeleton. + /// If there is no skeleton, returns "". + std::string getObjectRootName() const; Animation(const MWWorld::Ptr &ptr, Ogre::SceneNode *node); virtual ~Animation(); @@ -334,6 +337,7 @@ public: Ogre::AxisAlignedBox getWorldBounds(); Ogre::Node *getNode(const std::string &name); + Ogre::Node *getNode(int handle); // Attaches the given object to a bone on this object's base skeleton. If the bone doesn't // exist, the object isn't attached and NULL is returned. The returned TagPoint is only diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index c1957d7a8..2bdf8a499 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -16,39 +16,37 @@ namespace MWRender { -CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr) +CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr, const std::string& model) : Animation(ptr, ptr.getRefData().getBaseNode()) { MWWorld::LiveCellRef *ref = mPtr.get(); - std::string model = ptr.getClass().getModel(ptr); if(!model.empty()) { setObjectRoot(model, false); setRenderProperties(mObjectRoot, RV_Actors, RQG_Main, RQG_Alpha); if((ref->mBase->mFlags&ESM::Creature::Bipedal)) - addAnimSource("meshes\\base_anim.nif"); + addAnimSource("meshes\\xbase_anim.nif"); addAnimSource(model); } } -CreatureWeaponAnimation::CreatureWeaponAnimation(const MWWorld::Ptr &ptr) +CreatureWeaponAnimation::CreatureWeaponAnimation(const MWWorld::Ptr &ptr, const std::string& model) : Animation(ptr, ptr.getRefData().getBaseNode()) , mShowWeapons(false) , mShowCarriedLeft(false) { MWWorld::LiveCellRef *ref = mPtr.get(); - std::string model = ptr.getClass().getModel(ptr); if(!model.empty()) { setObjectRoot(model, false); setRenderProperties(mObjectRoot, RV_Actors, RQG_Main, RQG_Alpha); if((ref->mBase->mFlags&ESM::Creature::Bipedal)) - addAnimSource("meshes\\base_anim.nif"); + addAnimSource("meshes\\xbase_anim.nif"); addAnimSource(model); mPtr.getClass().getInventoryStore(mPtr).setListener(this, mPtr); diff --git a/apps/openmw/mwrender/creatureanimation.hpp b/apps/openmw/mwrender/creatureanimation.hpp index d6cd8a517..6201c7af4 100644 --- a/apps/openmw/mwrender/creatureanimation.hpp +++ b/apps/openmw/mwrender/creatureanimation.hpp @@ -15,7 +15,7 @@ namespace MWRender class CreatureAnimation : public Animation { public: - CreatureAnimation(const MWWorld::Ptr& ptr); + CreatureAnimation(const MWWorld::Ptr& ptr, const std::string &model); virtual ~CreatureAnimation() {} }; @@ -25,7 +25,7 @@ namespace MWRender class CreatureWeaponAnimation : public Animation, public WeaponAnimation, public MWWorld::InventoryStoreListener { public: - CreatureWeaponAnimation(const MWWorld::Ptr& ptr); + CreatureWeaponAnimation(const MWWorld::Ptr& ptr, const std::string &model); virtual ~CreatureWeaponAnimation() {} virtual void equipmentChanged() { updateParts(); } diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 32c1e7e05..5e73a95f2 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -12,6 +12,8 @@ #include +#include + #include "../mwworld/esmstore.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwworld/class.hpp" @@ -282,6 +284,7 @@ void NpcAnimation::updateNpcBase() (!isWerewolf ? !isBeast ? "meshes\\base_anim.1st.nif" : "meshes\\base_animkna.1st.nif" : "meshes\\wolf\\skin.1st.nif"); + smodel = Misc::ResourceHelpers::correctActorModelPath(smodel); setObjectRoot(smodel, true); if(mViewMode != VM_FirstPerson) @@ -290,11 +293,11 @@ void NpcAnimation::updateNpcBase() if(!isWerewolf) { if(Misc::StringUtils::lowerCase(mNpc->mRace).find("argonian") != std::string::npos) - addAnimSource("meshes\\argonian_swimkna.nif"); + addAnimSource("meshes\\xargonian_swimkna.nif"); else if(!mNpc->isMale() && !isBeast) - addAnimSource("meshes\\base_anim_female.nif"); + addAnimSource("meshes\\xbase_anim_female.nif"); if(mNpc->mModel.length() > 0) - addAnimSource("meshes\\"+mNpc->mModel); + addAnimSource("meshes\\x"+mNpc->mModel); } } else @@ -306,11 +309,11 @@ void NpcAnimation::updateNpcBase() /* A bit counter-intuitive, but unlike third-person anims, it seems * beast races get both base_anim.1st.nif and base_animkna.1st.nif. */ - addAnimSource("meshes\\base_anim.1st.nif"); + addAnimSource("meshes\\xbase_anim.1st.nif"); if(isBeast) - addAnimSource("meshes\\base_animkna.1st.nif"); + addAnimSource("meshes\\xbase_animkna.1st.nif"); if(!mNpc->isMale() && !isBeast) - addAnimSource("meshes\\base_anim_female.1st.nif"); + addAnimSource("meshes\\xbase_anim_female.1st.nif"); } } diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 4a87104ad..8e8b18cd1 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -256,10 +256,10 @@ void RenderingManager::cellAdded (MWWorld::CellStore *store) mDebugging->cellAdded(store); } -void RenderingManager::addObject (const MWWorld::Ptr& ptr){ +void RenderingManager::addObject (const MWWorld::Ptr& ptr, const std::string& model){ const MWWorld::Class& class_ = ptr.getClass(); - class_.insertObjectRendering(ptr, *this); + class_.insertObjectRendering(ptr, model, *this); } void RenderingManager::removeObject (const MWWorld::Ptr& ptr) diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index c3eedce7b..d4b85133d 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -111,7 +111,7 @@ public: /// Write current fog of war for this cell to the CellStore void writeFog (MWWorld::CellStore* store); - void addObject (const MWWorld::Ptr& ptr); + void addObject (const MWWorld::Ptr& ptr, const std::string& model); void removeObject (const MWWorld::Ptr& ptr); void moveObject (const MWWorld::Ptr& ptr, const Ogre::Vector3& position); diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 939b72ddb..edb3f3788 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -38,12 +38,12 @@ namespace MWWorld throw std::runtime_error ("class does not support ID retrieval"); } - void Class::insertObjectRendering (const Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const + void Class::insertObjectRendering (const Ptr& ptr, const std::string& mesh, MWRender::RenderingInterface& renderingInterface) const { } - void Class::insertObject(const Ptr& ptr, MWWorld::PhysicsSystem& physics) const + void Class::insertObject(const Ptr& ptr, const std::string& mesh, MWWorld::PhysicsSystem& physics) const { } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 7e605d6a2..3c44abe66 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -81,8 +81,8 @@ namespace MWWorld ///< Return ID of \a ptr or throw an exception, if class does not support ID retrieval /// (default implementation: throw an exception) - virtual void insertObjectRendering (const Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; - virtual void insertObject(const Ptr& ptr, MWWorld::PhysicsSystem& physics) const; + virtual void insertObjectRendering (const Ptr& ptr, const std::string& mesh, MWRender::RenderingInterface& renderingInterface) const; + virtual void insertObject(const Ptr& ptr, const std::string& mesh, MWWorld::PhysicsSystem& physics) const; ///< Add reference into a cell for rendering (default implementation: don't render anything). virtual std::string getName (const Ptr& ptr) const = 0; diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 5b712648c..7375fa4f8 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -17,6 +17,8 @@ #include #include +#include +#include #include @@ -51,25 +53,22 @@ void animateCollisionShapes (std::mapgetAnimation(ptr); - if (!animation) // Shouldn't happen either, since keyframe-controlled objects are not batched in StaticGeometry - throw std::runtime_error("can't find Animation for " + ptr.getCellRef().getRefId()); + if (!animation) + continue; OEngine::Physic::AnimatedShapeInstance& instance = it->second; - std::map& shapes = instance.mAnimatedShapes; - for (std::map::iterator shapeIt = shapes.begin(); + std::map& shapes = instance.mAnimatedShapes; + for (std::map::iterator shapeIt = shapes.begin(); shapeIt != shapes.end(); ++shapeIt) { - Ogre::Node* bone; - if (shapeIt->first.empty()) - // HACK: see NifSkeletonLoader::buildBones - bone = animation->getNode(" "); - else - bone = animation->getNode(shapeIt->first); + const std::string& mesh = animation->getObjectRootName(); + int boneHandle = NifOgre::NIFSkeletonLoader::lookupOgreBoneHandle(mesh, shapeIt->first); + Ogre::Node* bone = animation->getNode(boneHandle); if (bone == NULL) - throw std::runtime_error("can't find bone"); + continue; btCompoundShape* compound = dynamic_cast(instance.mCompound); @@ -689,9 +688,8 @@ namespace MWWorld mEngine->removeHeightField(x, y); } - void PhysicsSystem::addObject (const Ptr& ptr, bool placeable) + void PhysicsSystem::addObject (const Ptr& ptr, const std::string& mesh, bool placeable) { - std::string mesh = ptr.getClass().getModel(ptr); Ogre::SceneNode* node = ptr.getRefData().getBaseNode(); handleToMesh[node->getName()] = mesh; mEngine->createAndAdjustRigidBody( @@ -700,9 +698,8 @@ namespace MWWorld mesh, node->getName(), ptr.getCellRef().getScale(), node->getPosition(), node->getOrientation(), 0, 0, true, placeable); } - void PhysicsSystem::addActor (const Ptr& ptr) + void PhysicsSystem::addActor (const Ptr& ptr, const std::string& mesh) { - std::string mesh = ptr.getClass().getModel(ptr); Ogre::SceneNode* node = ptr.getRefData().getBaseNode(); //TODO:optimize this. Searching the std::map isn't very efficient i think. mEngine->addCharacter(node->getName(), mesh, node->getPosition(), node->getScale().x, node->getOrientation()); @@ -773,13 +770,16 @@ namespace MWWorld const std::string &handle = node->getName(); if(handleToMesh.find(handle) != handleToMesh.end()) { + std::string model = ptr.getClass().getModel(ptr); + model = Misc::ResourceHelpers::correctActorModelPath(model); // FIXME: scaling shouldn't require model + bool placeable = false; if (OEngine::Physic::RigidBody* body = mEngine->getRigidBody(handle,true)) placeable = body->mPlaceable; else if (OEngine::Physic::RigidBody* body = mEngine->getRigidBody(handle,false)) placeable = body->mPlaceable; removeObject(handle); - addObject(ptr, placeable); + addObject(ptr, model, placeable); } if (OEngine::Physic::PhysicActor* act = mEngine->getCharacter(handle)) @@ -820,6 +820,7 @@ namespace MWWorld bool PhysicsSystem::getObjectAABB(const MWWorld::Ptr &ptr, Ogre::Vector3 &min, Ogre::Vector3 &max) { std::string model = ptr.getClass().getModel(ptr); + model = Misc::ResourceHelpers::correctActorModelPath(model); if (model.empty()) { return false; } diff --git a/apps/openmw/mwworld/physicssystem.hpp b/apps/openmw/mwworld/physicssystem.hpp index 7dc8acaa1..c1046aacb 100644 --- a/apps/openmw/mwworld/physicssystem.hpp +++ b/apps/openmw/mwworld/physicssystem.hpp @@ -38,9 +38,9 @@ namespace MWWorld void setWaterHeight(float height); void disableWater(); - void addObject (const MWWorld::Ptr& ptr, bool placeable=false); + void addObject (const MWWorld::Ptr& ptr, const std::string& mesh, bool placeable=false); - void addActor (const MWWorld::Ptr& ptr); + void addActor (const MWWorld::Ptr& ptr, const std::string& mesh); void addHeightField (float* heights, int x, int y, float yoffset, diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index efe88c406..d7548018f 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -3,6 +3,7 @@ #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -79,8 +80,9 @@ namespace { try { - mRendering.addObject (ptr); - ptr.getClass().insertObject (ptr, mPhysics); + const std::string& model = Misc::ResourceHelpers::correctActorModelPath(ptr.getClass().getModel(ptr)); + mRendering.addObject(ptr, model); + ptr.getClass().insertObject (ptr, model, mPhysics); updateObjectLocalRotation(ptr, mPhysics, mRendering); if (ptr.getRefData().getBaseNode()) @@ -486,8 +488,7 @@ namespace MWWorld // Sky system MWBase::Environment::get().getWorld()->adjustSky(); - mCellChanged = true; - MWBase::Environment::get().getWindowManager()->fadeScreenIn(0.5); + mCellChanged = true; MWBase::Environment::get().getWindowManager()->fadeScreenIn(0.5); MWBase::Environment::get().getWindowManager()->changeCell(mCurrentCell); @@ -529,8 +530,9 @@ namespace MWWorld void Scene::addObjectToScene (const Ptr& ptr) { - mRendering.addObject(ptr); - ptr.getClass().insertObject(ptr, *mPhysics); + const std::string& model = Misc::ResourceHelpers::correctActorModelPath(ptr.getClass().getModel(ptr)); + mRendering.addObject(ptr, model); + ptr.getClass().insertObject (ptr, model, *mPhysics); MWBase::Environment::get().getWorld()->rotateObject(ptr, 0, 0, 0, true); MWBase::Environment::get().getWorld()->scaleObject(ptr, ptr.getCellRef().getScale()); } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 5e773f5d3..011f6c330 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include @@ -2092,7 +2093,9 @@ namespace MWWorld // so we should make sure not to use a "stale" controller for that. MWBase::Environment::get().getMechanicsManager()->add(mPlayer->getPlayer()); - mPhysics->addActor(mPlayer->getPlayer()); + std::string model = getPlayerPtr().getClass().getModel(getPlayerPtr()); + model = Misc::ResourceHelpers::correctActorModelPath(model); + mPhysics->addActor(mPlayer->getPlayer(), model); } int World::canRest () diff --git a/components/misc/resourcehelpers.cpp b/components/misc/resourcehelpers.cpp index ee911c566..dc08b352a 100644 --- a/components/misc/resourcehelpers.cpp +++ b/components/misc/resourcehelpers.cpp @@ -121,3 +121,20 @@ std::string Misc::ResourceHelpers::correctBookartPath(const std::string &resPath return image; } + +std::string Misc::ResourceHelpers::correctActorModelPath(const std::string &resPath) +{ + std::string mdlname = resPath; + std::string::size_type p = mdlname.rfind('\\'); + if(p == std::string::npos) + p = mdlname.rfind('/'); + if(p != std::string::npos) + mdlname.insert(mdlname.begin()+p+1, 'x'); + else + mdlname.insert(mdlname.begin(), 'x'); + if(!Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(mdlname)) + { + return resPath; + } + return mdlname; +} diff --git a/components/misc/resourcehelpers.hpp b/components/misc/resourcehelpers.hpp index 3cf0f4c27..2ce3dce1e 100644 --- a/components/misc/resourcehelpers.hpp +++ b/components/misc/resourcehelpers.hpp @@ -13,6 +13,8 @@ namespace Misc std::string correctIconPath(const std::string &resPath); std::string correctBookartPath(const std::string &resPath); std::string correctBookartPath(const std::string &resPath, int width, int height); + /// Uses "xfoo.nif" instead of "foo.nif" if available + std::string correctActorModelPath(const std::string &resPath); } } diff --git a/components/nifbullet/bulletnifloader.cpp b/components/nifbullet/bulletnifloader.cpp index 6c56fbba8..130787797 100644 --- a/components/nifbullet/bulletnifloader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -48,6 +48,57 @@ http://www.gnu.org/licenses/ . typedef unsigned char ubyte; +// Extract a list of keyframe-controlled nodes from a .kf file +// FIXME: this is a similar copy of OgreNifLoader::loadKf +void extractControlledNodes(Nif::NIFFilePtr kfFile, std::set& controlled) +{ + if(kfFile->numRoots() < 1) + { + kfFile->warn("Found no root nodes in "+kfFile->getFilename()+"."); + return; + } + + const Nif::Record *r = kfFile->getRoot(0); + assert(r != NULL); + + if(r->recType != Nif::RC_NiSequenceStreamHelper) + { + kfFile->warn("First root was not a NiSequenceStreamHelper, but a "+ + r->recName+"."); + return; + } + const Nif::NiSequenceStreamHelper *seq = static_cast(r); + + Nif::ExtraPtr extra = seq->extra; + if(extra.empty() || extra->recType != Nif::RC_NiTextKeyExtraData) + { + kfFile->warn("First extra data was not a NiTextKeyExtraData, but a "+ + (extra.empty() ? std::string("nil") : extra->recName)+"."); + return; + } + + extra = extra->extra; + Nif::ControllerPtr ctrl = seq->controller; + for(;!extra.empty() && !ctrl.empty();(extra=extra->extra),(ctrl=ctrl->next)) + { + if(extra->recType != Nif::RC_NiStringExtraData || ctrl->recType != Nif::RC_NiKeyframeController) + { + kfFile->warn("Unexpected extra data "+extra->recName+" with controller "+ctrl->recName); + continue; + } + + if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active)) + continue; + + const Nif::NiStringExtraData *strdata = static_cast(extra.getPtr()); + const Nif::NiKeyframeController *key = static_cast(ctrl.getPtr()); + + if(key->data.empty()) + continue; + controlled.insert(strdata->string); + } +} + namespace NifBullet { @@ -72,10 +123,6 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource) mCompoundShape = NULL; mStaticMesh = NULL; - // Load the NIF. TODO: Wrap this in a try-catch block once we're out - // of the early stages of development. Right now we WANT to catch - // every error as early and intrusively as possible, as it's most - // likely a sign of incomplete code rather than faulty input. Nif::NIFFilePtr pnif (Nif::Cache::getInstance().load(mResourceName.substr(0, mResourceName.length()-7))); Nif::NIFFile & nif = *pnif.get (); if (nif.numRoots() < 1) @@ -84,6 +131,19 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource) return; } + // Have to load controlled nodes from the .kf + // FIXME: the .kf has to be loaded both for rendering and physics, ideally it should be opened once and then reused + mControlledNodes.clear(); + std::string kfname = mResourceName.substr(0, mResourceName.length()-7); + Misc::StringUtils::toLower(kfname); + if(kfname.size() > 4 && kfname.compare(kfname.size()-4, 4, ".nif") == 0) + kfname.replace(kfname.size()-4, 4, ".kf"); + if (Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(kfname)) + { + Nif::NIFFilePtr kf (Nif::Cache::getInstance().load(kfname)); + extractControlledNodes(kf, mControlledNodes); + } + Nif::Record *r = nif.getRoot(0); assert(r != NULL); @@ -182,6 +242,9 @@ void ManualBulletShapeLoader::handleNode(const Nif::Node *node, int flags, && (node->controller->flags & Nif::NiNode::ControllerFlag_Active)) isAnimated = true; + if (mControlledNodes.find(node->name) != mControlledNodes.end()) + isAnimated = true; + if (!raycasting) isCollisionNode = isCollisionNode || (node->recType == Nif::RC_RootCollisionNode); else @@ -318,9 +381,9 @@ void ManualBulletShapeLoader::handleNiTriShape(const Nif::NiTriShape *shape, int btTransform trans(btQuaternion(q.x, q.y, q.z, q.w), btVector3(v.x, v.y, v.z)); if (raycasting) - mShape->mAnimatedRaycastingShapes.insert(std::make_pair(shape->name, mCompoundShape->getNumChildShapes())); + mShape->mAnimatedRaycastingShapes.insert(std::make_pair(shape->recIndex, mCompoundShape->getNumChildShapes())); else - mShape->mAnimatedShapes.insert(std::make_pair(shape->name, mCompoundShape->getNumChildShapes())); + mShape->mAnimatedShapes.insert(std::make_pair(shape->recIndex, mCompoundShape->getNumChildShapes())); mCompoundShape->addChildShape(trans, childShape); } diff --git a/components/nifbullet/bulletnifloader.hpp b/components/nifbullet/bulletnifloader.hpp index 8a77e9e9e..f95bdfccf 100644 --- a/components/nifbullet/bulletnifloader.hpp +++ b/components/nifbullet/bulletnifloader.hpp @@ -128,6 +128,8 @@ private: btTriangleMesh* mStaticMesh; btBoxShape *mBoundingBox; + + std::set mControlledNodes; }; diff --git a/libs/openengine/bullet/BulletShapeLoader.h b/libs/openengine/bullet/BulletShapeLoader.h index 472a9861f..31ee3cc7d 100644 --- a/libs/openengine/bullet/BulletShapeLoader.h +++ b/libs/openengine/bullet/BulletShapeLoader.h @@ -33,10 +33,10 @@ public: // Stores animated collision shapes. If any collision nodes in the NIF are animated, then mCollisionShape // will be a btCompoundShape (which consists of one or more child shapes). // In this map, for each animated collision shape, - // we store the bone name mapped to the child index of the shape in the btCompoundShape. - std::map mAnimatedShapes; + // we store the node's record index mapped to the child index of the shape in the btCompoundShape. + std::map mAnimatedShapes; - std::map mAnimatedRaycastingShapes; + std::map mAnimatedRaycastingShapes; btCollisionShape* mCollisionShape; btCollisionShape* mRaycastingShape; diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index ed6d74b9b..a3ec25e22 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -1,16 +1,21 @@ #include "physic.hpp" + #include #include #include + +#include +#include + +#include + #include -#include "OgreRoot.h" +#include + #include "BtOgrePG.h" #include "BtOgreGP.h" #include "BtOgreExtras.h" -#include -#include - namespace { diff --git a/libs/openengine/bullet/physic.hpp b/libs/openengine/bullet/physic.hpp index fb6ae0ceb..f497150f9 100644 --- a/libs/openengine/bullet/physic.hpp +++ b/libs/openengine/bullet/physic.hpp @@ -182,8 +182,8 @@ namespace Physic { btCollisionShape* mCompound; - // Maps bone name to child index in the compound shape - std::map mAnimatedShapes; + // Maps node record index to child index in the compound shape + std::map mAnimatedShapes; }; /** From f7bac58b39125c6466cb187578291cb75cf20a52 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 13 Jan 2015 01:00:33 +0100 Subject: [PATCH 0297/3725] Terrain: change index buffer flags to unsigned --- components/terrain/buffercache.cpp | 2 +- components/terrain/buffercache.hpp | 2 +- components/terrain/quadtreenode.cpp | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/components/terrain/buffercache.cpp b/components/terrain/buffercache.cpp index a3e67af5b..c26e47553 100644 --- a/components/terrain/buffercache.cpp +++ b/components/terrain/buffercache.cpp @@ -39,7 +39,7 @@ namespace Terrain return buffer; } - Ogre::HardwareIndexBufferSharedPtr BufferCache::getIndexBuffer(int flags) + Ogre::HardwareIndexBufferSharedPtr BufferCache::getIndexBuffer(unsigned int flags) { unsigned int verts = mNumVerts; diff --git a/components/terrain/buffercache.hpp b/components/terrain/buffercache.hpp index f0aea9bfd..51c0a61af 100644 --- a/components/terrain/buffercache.hpp +++ b/components/terrain/buffercache.hpp @@ -17,7 +17,7 @@ namespace Terrain /// @param flags first 4*4 bits are LOD deltas on each edge, respectively (4 bits each) /// next 4 bits are LOD level of the index buffer (LOD 0 = don't omit any vertices) - Ogre::HardwareIndexBufferSharedPtr getIndexBuffer (int flags); + Ogre::HardwareIndexBufferSharedPtr getIndexBuffer (unsigned int flags); Ogre::HardwareVertexBufferSharedPtr getUVBuffer (); diff --git a/components/terrain/quadtreenode.cpp b/components/terrain/quadtreenode.cpp index 57379a334..755c45c21 100644 --- a/components/terrain/quadtreenode.cpp +++ b/components/terrain/quadtreenode.cpp @@ -415,7 +415,7 @@ void QuadTreeNode::updateIndexBuffers() // Fetch a suitable index buffer (which may be shared) size_t ourLod = getActualLodLevel(); - int flags = 0; + unsigned int flags = 0; for (int i=0; i<4; ++i) { @@ -436,7 +436,7 @@ void QuadTreeNode::updateIndexBuffers() if (lod > 0) { assert (lod - ourLod < (1 << 4)); - flags |= int(lod - ourLod) << (4*i); + flags |= static_cast(lod - ourLod) << (4*i); } } flags |= 0 /*((int)mAdditionalLod)*/ << (4*4); From 261da8dd0ac6ddb64aa4154a863c950087a1e05a Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 13 Jan 2015 01:47:42 +0100 Subject: [PATCH 0298/3725] Terrain: use 32-bit indices if necessary --- components/terrain/buffercache.cpp | 305 +++++++++++++++-------------- 1 file changed, 161 insertions(+), 144 deletions(-) diff --git a/components/terrain/buffercache.cpp b/components/terrain/buffercache.cpp index c26e47553..3d0b35910 100644 --- a/components/terrain/buffercache.cpp +++ b/components/terrain/buffercache.cpp @@ -4,6 +4,162 @@ #include "defs.hpp" +namespace +{ + +template +Ogre::HardwareIndexBufferSharedPtr createIndexBuffer(unsigned int flags, unsigned int verts, Ogre::HardwareIndexBuffer::IndexType type) +{ + // LOD level n means every 2^n-th vertex is kept + size_t lodLevel = (flags >> (4*4)); + + size_t lodDeltas[4]; + for (int i=0; i<4; ++i) + lodDeltas[i] = (flags >> (4*i)) & (0xf); + + bool anyDeltas = (lodDeltas[Terrain::North] || lodDeltas[Terrain::South] || lodDeltas[Terrain::West] || lodDeltas[Terrain::East]); + + size_t increment = 1 << lodLevel; + assert(increment < verts); + std::vector indices; + indices.reserve((verts-1)*(verts-1)*2*3 / increment); + + size_t rowStart = 0, colStart = 0, rowEnd = verts-1, colEnd = verts-1; + // If any edge needs stitching we'll skip all edges at this point, + // mainly because stitching one edge would have an effect on corners and on the adjacent edges + if (anyDeltas) + { + colStart += increment; + colEnd -= increment; + rowEnd -= increment; + rowStart += increment; + } + for (size_t row = rowStart; row < rowEnd; row += increment) + { + for (size_t col = colStart; col < colEnd; col += increment) + { + indices.push_back(verts*col+row); + indices.push_back(verts*(col+increment)+row+increment); + indices.push_back(verts*col+row+increment); + + indices.push_back(verts*col+row); + indices.push_back(verts*(col+increment)+row); + indices.push_back(verts*(col+increment)+row+increment); + } + } + + size_t innerStep = increment; + if (anyDeltas) + { + // Now configure LOD transitions at the edges - this is pretty tedious, + // and some very long and boring code, but it works great + + // South + size_t row = 0; + size_t outerStep = 1 << (lodDeltas[Terrain::South] + lodLevel); + for (size_t col = 0; col < verts-1; col += outerStep) + { + indices.push_back(verts*col+row); + indices.push_back(verts*(col+outerStep)+row); + // Make sure not to touch the right edge + if (col+outerStep == verts-1) + indices.push_back(verts*(col+outerStep-innerStep)+row+innerStep); + else + indices.push_back(verts*(col+outerStep)+row+innerStep); + + for (size_t i = 0; i < outerStep; i += innerStep) + { + // Make sure not to touch the left or right edges + if (col+i == 0 || col+i == verts-1-innerStep) + continue; + indices.push_back(verts*(col)+row); + indices.push_back(verts*(col+i+innerStep)+row+innerStep); + indices.push_back(verts*(col+i)+row+innerStep); + } + } + + // North + row = verts-1; + outerStep = size_t(1) << (lodDeltas[Terrain::North] + lodLevel); + for (size_t col = 0; col < verts-1; col += outerStep) + { + indices.push_back(verts*(col+outerStep)+row); + indices.push_back(verts*col+row); + // Make sure not to touch the left edge + if (col == 0) + indices.push_back(verts*(col+innerStep)+row-innerStep); + else + indices.push_back(verts*col+row-innerStep); + + for (size_t i = 0; i < outerStep; i += innerStep) + { + // Make sure not to touch the left or right edges + if (col+i == 0 || col+i == verts-1-innerStep) + continue; + indices.push_back(verts*(col+i)+row-innerStep); + indices.push_back(verts*(col+i+innerStep)+row-innerStep); + indices.push_back(verts*(col+outerStep)+row); + } + } + + // West + size_t col = 0; + outerStep = size_t(1) << (lodDeltas[Terrain::West] + lodLevel); + for (size_t row = 0; row < verts-1; row += outerStep) + { + indices.push_back(verts*col+row+outerStep); + indices.push_back(verts*col+row); + // Make sure not to touch the top edge + if (row+outerStep == verts-1) + indices.push_back(verts*(col+innerStep)+row+outerStep-innerStep); + else + indices.push_back(verts*(col+innerStep)+row+outerStep); + + for (size_t i = 0; i < outerStep; i += innerStep) + { + // Make sure not to touch the top or bottom edges + if (row+i == 0 || row+i == verts-1-innerStep) + continue; + indices.push_back(verts*col+row); + indices.push_back(verts*(col+innerStep)+row+i); + indices.push_back(verts*(col+innerStep)+row+i+innerStep); + } + } + + // East + col = verts-1; + outerStep = size_t(1) << (lodDeltas[Terrain::East] + lodLevel); + for (size_t row = 0; row < verts-1; row += outerStep) + { + indices.push_back(verts*col+row); + indices.push_back(verts*col+row+outerStep); + // Make sure not to touch the bottom edge + if (row == 0) + indices.push_back(verts*(col-innerStep)+row+innerStep); + else + indices.push_back(verts*(col-innerStep)+row); + + for (size_t i = 0; i < outerStep; i += innerStep) + { + // Make sure not to touch the top or bottom edges + if (row+i == 0 || row+i == verts-1-innerStep) + continue; + indices.push_back(verts*col+row+outerStep); + indices.push_back(verts*(col-innerStep)+row+i+innerStep); + indices.push_back(verts*(col-innerStep)+row+i); + } + } + } + + Ogre::HardwareBufferManager* mgr = Ogre::HardwareBufferManager::getSingletonPtr(); + Ogre::HardwareIndexBufferSharedPtr buffer = mgr->createIndexBuffer(type, + indices.size(), Ogre::HardwareBuffer::HBU_STATIC); + buffer->writeData(0, buffer->getSizeInBytes(), &indices[0], true); + return buffer; +} + +} + namespace Terrain { @@ -48,151 +204,12 @@ namespace Terrain return mIndexBufferMap[flags]; } - // LOD level n means every 2^n-th vertex is kept - size_t lodLevel = (flags >> (4*4)); - - size_t lodDeltas[4]; - for (int i=0; i<4; ++i) - lodDeltas[i] = (flags >> (4*i)) & (0xf); - - bool anyDeltas = (lodDeltas[North] || lodDeltas[South] || lodDeltas[West] || lodDeltas[East]); + Ogre::HardwareIndexBufferSharedPtr buffer; + if (verts*verts > (0xffffu)) + buffer = createIndexBuffer(flags, verts, Ogre::HardwareIndexBuffer::IT_32BIT); + else + buffer = createIndexBuffer(flags, verts, Ogre::HardwareIndexBuffer::IT_16BIT); - size_t increment = 1 << lodLevel; - assert(increment < verts); - std::vector indices; - indices.reserve((verts-1)*(verts-1)*2*3 / increment); - - size_t rowStart = 0, colStart = 0, rowEnd = verts-1, colEnd = verts-1; - // If any edge needs stitching we'll skip all edges at this point, - // mainly because stitching one edge would have an effect on corners and on the adjacent edges - if (anyDeltas) - { - colStart += increment; - colEnd -= increment; - rowEnd -= increment; - rowStart += increment; - } - for (size_t row = rowStart; row < rowEnd; row += increment) - { - for (size_t col = colStart; col < colEnd; col += increment) - { - indices.push_back(verts*col+row); - indices.push_back(verts*(col+increment)+row+increment); - indices.push_back(verts*col+row+increment); - - indices.push_back(verts*col+row); - indices.push_back(verts*(col+increment)+row); - indices.push_back(verts*(col+increment)+row+increment); - } - } - - size_t innerStep = increment; - if (anyDeltas) - { - // Now configure LOD transitions at the edges - this is pretty tedious, - // and some very long and boring code, but it works great - - // South - size_t row = 0; - size_t outerStep = 1 << (lodDeltas[South] + lodLevel); - for (size_t col = 0; col < verts-1; col += outerStep) - { - indices.push_back(verts*col+row); - indices.push_back(verts*(col+outerStep)+row); - // Make sure not to touch the right edge - if (col+outerStep == verts-1) - indices.push_back(verts*(col+outerStep-innerStep)+row+innerStep); - else - indices.push_back(verts*(col+outerStep)+row+innerStep); - - for (size_t i = 0; i < outerStep; i += innerStep) - { - // Make sure not to touch the left or right edges - if (col+i == 0 || col+i == verts-1-innerStep) - continue; - indices.push_back(verts*(col)+row); - indices.push_back(verts*(col+i+innerStep)+row+innerStep); - indices.push_back(verts*(col+i)+row+innerStep); - } - } - - // North - row = verts-1; - outerStep = size_t(1) << (lodDeltas[North] + lodLevel); - for (size_t col = 0; col < verts-1; col += outerStep) - { - indices.push_back(verts*(col+outerStep)+row); - indices.push_back(verts*col+row); - // Make sure not to touch the left edge - if (col == 0) - indices.push_back(verts*(col+innerStep)+row-innerStep); - else - indices.push_back(verts*col+row-innerStep); - - for (size_t i = 0; i < outerStep; i += innerStep) - { - // Make sure not to touch the left or right edges - if (col+i == 0 || col+i == verts-1-innerStep) - continue; - indices.push_back(verts*(col+i)+row-innerStep); - indices.push_back(verts*(col+i+innerStep)+row-innerStep); - indices.push_back(verts*(col+outerStep)+row); - } - } - - // West - size_t col = 0; - outerStep = size_t(1) << (lodDeltas[West] + lodLevel); - for (size_t row = 0; row < verts-1; row += outerStep) - { - indices.push_back(verts*col+row+outerStep); - indices.push_back(verts*col+row); - // Make sure not to touch the top edge - if (row+outerStep == verts-1) - indices.push_back(verts*(col+innerStep)+row+outerStep-innerStep); - else - indices.push_back(verts*(col+innerStep)+row+outerStep); - - for (size_t i = 0; i < outerStep; i += innerStep) - { - // Make sure not to touch the top or bottom edges - if (row+i == 0 || row+i == verts-1-innerStep) - continue; - indices.push_back(verts*col+row); - indices.push_back(verts*(col+innerStep)+row+i); - indices.push_back(verts*(col+innerStep)+row+i+innerStep); - } - } - - // East - col = verts-1; - outerStep = size_t(1) << (lodDeltas[East] + lodLevel); - for (size_t row = 0; row < verts-1; row += outerStep) - { - indices.push_back(verts*col+row); - indices.push_back(verts*col+row+outerStep); - // Make sure not to touch the bottom edge - if (row == 0) - indices.push_back(verts*(col-innerStep)+row+innerStep); - else - indices.push_back(verts*(col-innerStep)+row); - - for (size_t i = 0; i < outerStep; i += innerStep) - { - // Make sure not to touch the top or bottom edges - if (row+i == 0 || row+i == verts-1-innerStep) - continue; - indices.push_back(verts*col+row+outerStep); - indices.push_back(verts*(col-innerStep)+row+i+innerStep); - indices.push_back(verts*(col-innerStep)+row+i); - } - } - } - - Ogre::HardwareBufferManager* mgr = Ogre::HardwareBufferManager::getSingletonPtr(); - Ogre::HardwareIndexBufferSharedPtr buffer = mgr->createIndexBuffer(Ogre::HardwareIndexBuffer::IT_16BIT, - indices.size(), Ogre::HardwareBuffer::HBU_STATIC); - buffer->writeData(0, buffer->getSizeInBytes(), &indices[0], true); mIndexBufferMap[flags] = buffer; return buffer; } From fafc14d5a08f9a38ab4e3924e6d44f0aa2064b02 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 13 Jan 2015 03:11:29 +0100 Subject: [PATCH 0299/3725] Add proper air movement mechanics (Fixes #2077) --- apps/openmw/mwmechanics/character.cpp | 10 ++++---- apps/openmw/mwworld/physicssystem.cpp | 33 ++++++++------------------- 2 files changed, 14 insertions(+), 29 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 6632f0275..fa7e52af2 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1496,12 +1496,12 @@ void CharacterController::update(float duration) forcestateupdate = (mJumpState != JumpState_InAir); mJumpState = JumpState_InAir; - // This is a guess. All that seems to be known is that "While the player is in the - // air, fJumpMoveBase and fJumpMoveMult governs air control". What does fJumpMoveMult do? static const float fJumpMoveBase = gmst.find("fJumpMoveBase")->getFloat(); - - vec.x *= fJumpMoveBase; - vec.y *= fJumpMoveBase; + static const float fJumpMoveMult = gmst.find("fJumpMoveMult")->getFloat(); + float factor = fJumpMoveBase + fJumpMoveMult * mPtr.getClass().getSkill(mPtr, ESM::Skill::Acrobatics)/100.f; + factor = std::min(1.f, factor); + vec.x *= factor; + vec.y *= factor; vec.z = 0.0f; } else if(vec.z > 0.0f && mJumpState == JumpState_None) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 7375fa4f8..77c5b4460 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -289,7 +289,7 @@ namespace MWWorld // Reset per-frame data physicActor->setWalkingOnWater(false); - /* Anything to collide with? */ + // Anything to collide with? if(!physicActor->getCollisionMode()) { return position + (Ogre::Quaternion(Ogre::Radian(refpos.rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z) * @@ -317,12 +317,11 @@ namespace MWWorld */ OEngine::Physic::ActorTracer tracer; - Ogre::Vector3 inertia(0.0f); + Ogre::Vector3 inertia = physicActor->getInertialForce(); Ogre::Vector3 velocity; - if(position.z < waterlevel || isFlying) // under water by 3/4 or can fly + if(position.z < waterlevel || isFlying) { - // TODO: Shouldn't water have higher drag in calculating velocity? velocity = (Ogre::Quaternion(Ogre::Radian(refpos.rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z)* Ogre::Quaternion(Ogre::Radian(refpos.rot[0]), Ogre::Vector3::NEGATIVE_UNIT_X)) * movement; } @@ -330,25 +329,12 @@ namespace MWWorld { velocity = Ogre::Quaternion(Ogre::Radian(refpos.rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z) * movement; - // not in water nor can fly, so need to deal with gravity - if(!physicActor->getOnGround()) // if current OnGround status is false, must be falling or jumping + if (velocity.z > 0.f) + inertia = velocity; + if(!physicActor->getOnGround()) { - // If falling or jumping up, add part of the incoming velocity with the current inertia, - // but don't allow increasing inertia beyond actor's speed (except on the initial jump impulse) - float actorSpeed = ptr.getClass().getSpeed(ptr); - float cap = std::max(actorSpeed, Ogre::Vector2(physicActor->getInertialForce().x, physicActor->getInertialForce().y).length()); - Ogre::Vector3 newVelocity = velocity + physicActor->getInertialForce(); - if (Ogre::Vector2(newVelocity.x, newVelocity.y).squaredLength() > cap*cap) - { - velocity = newVelocity; - float speedXY = Ogre::Vector2(velocity.x, velocity.y).length(); - velocity.x *= cap / speedXY; - velocity.y *= cap / speedXY; - } - else - velocity = newVelocity; + velocity = velocity + physicActor->getInertialForce(); } - inertia = velocity; // NOTE: velocity is for z axis only in this code block } ptr.getClass().getMovementSettings(ptr).mPosition[2] = 0; @@ -371,7 +357,6 @@ namespace MWWorld float remainingTime = time; for(int iterations = 0; iterations < sMaxIterations && remainingTime > 0.01f; ++iterations) { - // NOTE: velocity is either z axis only or x & z axis Ogre::Vector3 nextpos = newPosition + velocity * remainingTime; // If not able to fly, don't allow to swim up into the air @@ -482,7 +467,7 @@ namespace MWWorld // so that we do not stay suspended in air indefinitely. if (tracer.mFraction < 1.0f && tracer.mHitObject->getBroadphaseHandle()->m_collisionFilterGroup == OEngine::Physic::CollisionType_Actor) { - if (Ogre::Vector3(inertia.x, inertia.y, 0).squaredLength() < 100.f*100.f) + if (Ogre::Vector3(velocity.x, velocity.y, 0).squaredLength() < 100.f*100.f) { btVector3 aabbMin, aabbMax; tracer.mHitObject->getCollisionShape()->getAabb(tracer.mHitObject->getWorldTransform(), aabbMin, aabbMax); @@ -508,7 +493,7 @@ namespace MWWorld } physicActor->setOnGround(isOnGround); - newPosition.z -= halfExtents.z; // remove what was added at the beggining + newPosition.z -= halfExtents.z; // remove what was added at the beginning return newPosition; } }; From 7b4665c6234f7190e085396a524c40220a50a3ed Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 13 Jan 2015 03:30:14 +0100 Subject: [PATCH 0300/3725] Terrain: documentation update --- components/esmterrain/storage.hpp | 2 ++ components/terrain/storage.hpp | 2 ++ 2 files changed, 4 insertions(+) diff --git a/components/esmterrain/storage.hpp b/components/esmterrain/storage.hpp index d25f7552b..e184cbc4c 100644 --- a/components/esmterrain/storage.hpp +++ b/components/esmterrain/storage.hpp @@ -38,6 +38,8 @@ namespace ESMTerrain /// Fill vertex buffers for a terrain chunk. /// @note May be called from background threads. Make sure to only call thread-safe functions from here! /// @note returned colors need to be in render-system specific format! Use RenderSystem::convertColourValue. + /// @note Vertices should be written in row-major order (a row is defined as parallel to the x-axis). + /// The specified positions should be in local space, i.e. relative to the center of the terrain chunk. /// @param lodLevel LOD level, 0 = most detailed /// @param size size of the terrain chunk in cell units /// @param center center of the chunk in cell units diff --git a/components/terrain/storage.hpp b/components/terrain/storage.hpp index d3770ea57..aa52ffc4b 100644 --- a/components/terrain/storage.hpp +++ b/components/terrain/storage.hpp @@ -30,6 +30,8 @@ namespace Terrain /// Fill vertex buffers for a terrain chunk. /// @note May be called from background threads. Make sure to only call thread-safe functions from here! /// @note returned colors need to be in render-system specific format! Use RenderSystem::convertColourValue. + /// @note Vertices should be written in row-major order (a row is defined as parallel to the x-axis). + /// The specified positions should be in local space, i.e. relative to the center of the terrain chunk. /// @param lodLevel LOD level, 0 = most detailed /// @param size size of the terrain chunk in cell units /// @param center center of the chunk in cell units From 3ce22d31d807447860234ee5580db398321884ba Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 13 Jan 2015 04:53:49 +0100 Subject: [PATCH 0301/3725] Fix cursor issue when loading savegame from within mouselook-mode and a warning pops up --- apps/openmw/mwinput/inputmanagerimp.cpp | 38 +++++++++++++++---------- apps/openmw/mwinput/inputmanagerimp.hpp | 2 ++ 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 846cce6a2..fed864dfc 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -302,22 +302,8 @@ namespace MWInput } } - void InputManager::update(float dt, bool disableControls, bool disableEvents) + void InputManager::updateCursorMode() { - mControlsDisabled = disableControls; - - mInputManager->setMouseVisible(MWBase::Environment::get().getWindowManager()->getCursorVisible()); - - mInputManager->capture(disableEvents); - // inject some fake mouse movement to force updating MyGUI's widget states - MyGUI::InputManager::getInstance().injectMouseMove( int(mMouseX), int(mMouseY), mMouseWheel); - - if (mControlsDisabled) - return; - - // update values of channels (as a result of pressed keys) - mInputBinder->update(dt); - bool grab = !MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_MainMenu) && MWBase::Environment::get().getWindowManager()->getMode() != MWGui::GM_Console; @@ -337,6 +323,28 @@ namespace MWInput { mInputManager->warpMouse(mMouseX, mMouseY); } + } + + void InputManager::update(float dt, bool disableControls, bool disableEvents) + { + mControlsDisabled = disableControls; + + mInputManager->setMouseVisible(MWBase::Environment::get().getWindowManager()->getCursorVisible()); + + mInputManager->capture(disableEvents); + // inject some fake mouse movement to force updating MyGUI's widget states + MyGUI::InputManager::getInstance().injectMouseMove( int(mMouseX), int(mMouseY), mMouseWheel); + + if (mControlsDisabled) + { + updateCursorMode(); + return; + } + + // update values of channels (as a result of pressed keys) + mInputBinder->update(dt); + + updateCursorMode(); // Disable movement in Gui mode if (!(MWBase::Environment::get().getWindowManager()->isGuiMode() diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 346e02ff9..851f24971 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -176,6 +176,8 @@ namespace MWInput void setPlayerControlsEnabled(bool enabled); + void updateCursorMode(); + private: void toggleMainMenu(); void toggleSpell(); From 883f7ec7ce0b62c2b04019898f4419f176433169 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 13 Jan 2015 17:14:54 +0100 Subject: [PATCH 0302/3725] Move workaround for hiding markers from NIF loader to Scene --- apps/openmw/mwworld/scene.cpp | 21 ++++++++++++++------- components/nifbullet/bulletnifloader.cpp | 18 +++++------------- components/nifbullet/bulletnifloader.hpp | 2 +- components/nifogre/ogrenifloader.cpp | 5 ----- 4 files changed, 20 insertions(+), 26 deletions(-) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index d7548018f..d054cd560 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -21,6 +21,18 @@ namespace { + + void addObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics, + MWRender::RenderingManager& rendering) + { + std::string model = Misc::ResourceHelpers::correctActorModelPath(ptr.getClass().getModel(ptr)); + std::string id = ptr.getClass().getId(ptr); + if (id == "prisonmarker" || id == "divinemarker" || id == "templemarker" || id == "northmarker") + model = ""; + rendering.addObject(ptr, model); + ptr.getClass().insertObject (ptr, model, physics); + } + void updateObjectLocalRotation (const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics, MWRender::RenderingManager& rendering) { @@ -80,10 +92,7 @@ namespace { try { - const std::string& model = Misc::ResourceHelpers::correctActorModelPath(ptr.getClass().getModel(ptr)); - mRendering.addObject(ptr, model); - ptr.getClass().insertObject (ptr, model, mPhysics); - + addObject(ptr, mPhysics, mRendering); updateObjectLocalRotation(ptr, mPhysics, mRendering); if (ptr.getRefData().getBaseNode()) { @@ -530,9 +539,7 @@ namespace MWWorld void Scene::addObjectToScene (const Ptr& ptr) { - const std::string& model = Misc::ResourceHelpers::correctActorModelPath(ptr.getClass().getModel(ptr)); - mRendering.addObject(ptr, model); - ptr.getClass().insertObject (ptr, model, *mPhysics); + addObject(ptr, *mPhysics, mRendering); MWBase::Environment::get().getWorld()->rotateObject(ptr, 0, 0, 0, true); MWBase::Environment::get().getWorld()->scaleObject(ptr, ptr.getCellRef().getScale()); } diff --git a/components/nifbullet/bulletnifloader.cpp b/components/nifbullet/bulletnifloader.cpp index 130787797..8cb531f55 100644 --- a/components/nifbullet/bulletnifloader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -158,7 +158,7 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource) mShape->mAutogenerated = hasAutoGeneratedCollision(node); //do a first pass - handleNode(node,0,false,false,false); + handleNode(node,0,false,false); if(mBoundingBox != NULL) { @@ -232,7 +232,7 @@ bool ManualBulletShapeLoader::hasAutoGeneratedCollision(Nif::Node const * rootNo void ManualBulletShapeLoader::handleNode(const Nif::Node *node, int flags, bool isCollisionNode, - bool raycasting, bool isMarker, bool isAnimated) + bool raycasting, bool isAnimated) { // Accumulate the flags from all the child nodes. This works for all // the flags we currently use, at least. @@ -254,13 +254,6 @@ void ManualBulletShapeLoader::handleNode(const Nif::Node *node, int flags, if(node->recType == Nif::RC_AvoidNode) flags |= 0x800; - // Marker objects - /// \todo don't do this in the editor - std::string nodename = node->name; - Misc::StringUtils::toLower(nodename); - if (nodename.find("marker") != std::string::npos) - isMarker = true; - // Check for extra data Nif::Extra const *e = node; while (!e->extra.empty()) @@ -285,12 +278,11 @@ void ManualBulletShapeLoader::handleNode(const Nif::Node *node, int flags, // Marker objects. These are only visible in the // editor. Until and unless we add an editor component to // the engine, just skip this entire node. - isMarker = true; + return; } } - if ( (isCollisionNode || (mShape->mAutogenerated && !raycasting)) - && (!isMarker || (!mShape->mAutogenerated && !raycasting))) + if (isCollisionNode || (mShape->mAutogenerated && !raycasting)) { // NOTE: a trishape with hasBounds=true, but no BBoxCollision flag should NOT go through handleNiTriShape! // It must be ignored completely. @@ -319,7 +311,7 @@ void ManualBulletShapeLoader::handleNode(const Nif::Node *node, int flags, for(size_t i = 0;i < list.length();i++) { if(!list[i].empty()) - handleNode(list[i].getPtr(), flags, isCollisionNode, raycasting, isMarker, isAnimated); + handleNode(list[i].getPtr(), flags, isCollisionNode, raycasting, isAnimated); } } } diff --git a/components/nifbullet/bulletnifloader.hpp b/components/nifbullet/bulletnifloader.hpp index f95bdfccf..889599719 100644 --- a/components/nifbullet/bulletnifloader.hpp +++ b/components/nifbullet/bulletnifloader.hpp @@ -107,7 +107,7 @@ private: *Parse a node. */ void handleNode(Nif::Node const *node, int flags, bool isCollisionNode, - bool raycasting, bool isMarker, bool isAnimated=false); + bool raycasting, bool isAnimated=false); /** *Helper function diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 7ec2c2c24..51e5d10da 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -1176,11 +1176,6 @@ class NIFObjectLoader if(node->recType == Nif::RC_RootCollisionNode) isRootCollisionNode = true; - // Marker objects: just skip the entire node branch - /// \todo don't do this in the editor - if (node->name.find("marker") != std::string::npos) - return; - if(node->recType == Nif::RC_NiBSAnimationNode) animflags |= node->flags; else if(node->recType == Nif::RC_NiBSParticleNode) From f11ec653d0f2ab00431f1af6abc9435d7a93ae9a Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 13 Jan 2015 17:29:25 +0100 Subject: [PATCH 0303/3725] Add setting for showing MRK nodes to NIF loaders This makes marker objects show up in OpenCS. --- apps/opencs/editor.cpp | 4 +++- apps/opencs/view/world/physicssystem.cpp | 2 +- components/nifbullet/bulletnifloader.cpp | 5 ++--- components/nifbullet/bulletnifloader.hpp | 5 ++++- components/nifogre/ogrenifloader.cpp | 19 ++++++++++++++++++- components/nifogre/ogrenifloader.hpp | 8 ++++++++ 6 files changed, 36 insertions(+), 7 deletions(-) diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 826619b5d..77644665f 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -15,7 +15,7 @@ #include #include - +#include #include #include "model/doc/document.hpp" @@ -35,6 +35,8 @@ CS::Editor::Editor (OgreInit::OgreInit& ogreInit) ogreInit.init ((mCfgMgr.getUserConfigPath() / "opencsOgre.log").string()); + NifOgre::Loader::setShowMarkers(true); + mOverlaySystem.reset (new CSVRender::OverlaySystem); Bsa::registerResources (Files::Collections (config.first, !mFsStrict), config.second, true, diff --git a/apps/opencs/view/world/physicssystem.cpp b/apps/opencs/view/world/physicssystem.cpp index 57909f4d3..2cbe17dcf 100644 --- a/apps/opencs/view/world/physicssystem.cpp +++ b/apps/opencs/view/world/physicssystem.cpp @@ -16,7 +16,7 @@ namespace CSVWorld PhysicsSystem::PhysicsSystem() { // Create physics. shapeLoader is deleted by the physic engine - NifBullet::ManualBulletShapeLoader* shapeLoader = new NifBullet::ManualBulletShapeLoader(); + NifBullet::ManualBulletShapeLoader* shapeLoader = new NifBullet::ManualBulletShapeLoader(true); mEngine = new OEngine::Physic::PhysicEngine(shapeLoader); } diff --git a/components/nifbullet/bulletnifloader.cpp b/components/nifbullet/bulletnifloader.cpp index 8cb531f55..372716b68 100644 --- a/components/nifbullet/bulletnifloader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -274,10 +274,9 @@ void ManualBulletShapeLoader::handleNode(const Nif::Node *node, int flags, // No collision. Use an internal flag setting to mark this. flags |= 0x800; } - else if (sd->string == "MRK") + else if (sd->string == "MRK" && !mShowMarkers) // Marker objects. These are only visible in the - // editor. Until and unless we add an editor component to - // the engine, just skip this entire node. + // editor. return; } } diff --git a/components/nifbullet/bulletnifloader.hpp b/components/nifbullet/bulletnifloader.hpp index 889599719..56d98834d 100644 --- a/components/nifbullet/bulletnifloader.hpp +++ b/components/nifbullet/bulletnifloader.hpp @@ -67,11 +67,12 @@ struct TriangleMeshShape : public btBvhTriangleMeshShape class ManualBulletShapeLoader : public OEngine::Physic::BulletShapeLoader { public: - ManualBulletShapeLoader() + ManualBulletShapeLoader(bool showMarkers=false) : mShape(NULL) , mStaticMesh(NULL) , mCompoundShape(NULL) , mBoundingBox(NULL) + , mShowMarkers(showMarkers) { } @@ -130,6 +131,8 @@ private: btBoxShape *mBoundingBox; std::set mControlledNodes; + + bool mShowMarkers; }; diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 51e5d10da..17df7a3cd 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -689,6 +689,14 @@ public: */ class NIFObjectLoader { + static bool sShowMarkers; +public: + static void setShowMarkers(bool show) + { + sShowMarkers = show; + } +private: + static void warn(const std::string &msg) { std::cerr << "NIFObjectLoader: Warn: " << msg << std::endl; @@ -1208,7 +1216,7 @@ class NIFObjectLoader const Nif::NiStringExtraData *sd = static_cast(e.getPtr()); // String markers may contain important information // affecting the entire subtree of this obj - if(sd->string == "MRK") + if(sd->string == "MRK" && !sShowMarkers) { // Marker objects. These meshes are only visible in the // editor. @@ -1471,5 +1479,14 @@ void Loader::createKfControllers(Ogre::Entity *skelBase, NIFObjectLoader::loadKf(skelBase->getSkeleton(), name, textKeys, ctrls); } +bool Loader::sShowMarkers = false; +bool NIFObjectLoader::sShowMarkers = false; + +void Loader::setShowMarkers(bool show) +{ + sShowMarkers = show; + NIFObjectLoader::setShowMarkers(show); +} + } // namespace NifOgre diff --git a/components/nifogre/ogrenifloader.hpp b/components/nifogre/ogrenifloader.hpp index fd5ddca7d..c13532644 100644 --- a/components/nifogre/ogrenifloader.hpp +++ b/components/nifogre/ogrenifloader.hpp @@ -110,10 +110,18 @@ public: std::string name, const std::string &group="General"); + /// Set whether or not nodes marked as "MRK" should be shown. + /// These should be hidden ingame, but visible in the editior. + /// Default: false. + static void setShowMarkers(bool show); + static void createKfControllers(Ogre::Entity *skelBase, const std::string &name, TextKeyMap &textKeys, std::vector > &ctrls); + +private: + static bool sShowMarkers; }; // FIXME: Should be with other general Ogre extensions. From 2ac4a74a34d150cb135d8c9545fe117734f21b9c Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 13 Jan 2015 18:09:10 +0100 Subject: [PATCH 0304/3725] Fix running AI for dead actors --- apps/openmw/mwmechanics/actors.cpp | 20 ++++++++++++++------ apps/openmw/mwmechanics/aisequence.cpp | 3 +-- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index a454d816a..64434a304 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -42,6 +42,12 @@ namespace { +bool isConscious(const MWWorld::Ptr& ptr) +{ + const MWMechanics::CreatureStats& stats = ptr.getClass().getCreatureStats(ptr); + return !stats.isDead() && !stats.getKnockedDown(); +} + void adjustBoundItem (const std::string& item, bool bound, const MWWorld::Ptr& actor) { if (bound) @@ -1101,12 +1107,12 @@ namespace MWMechanics updateCrimePersuit(iter->first, duration); if (iter->first != player) - iter->first.getClass().getCreatureStats(iter->first).getAiSequence().execute(iter->first,iter->second->getAiState(), duration); - - CreatureStats &stats = iter->first.getClass().getCreatureStats(iter->first); - if(!stats.isDead()) { - if (stats.getAiSequence().isInCombat()) hostilesCount++; + CreatureStats &stats = iter->first.getClass().getCreatureStats(iter->first); + if (isConscious(iter->first)) + stats.getAiSequence().execute(iter->first,iter->second->getAiState(), duration); + + if (stats.getAiSequence().isInCombat() && !stats.isDead()) hostilesCount++; } } @@ -1515,7 +1521,9 @@ namespace MWMechanics for (PtrActorMap::iterator it = map.begin(); it != map.end(); ++it) { MWWorld::Ptr ptr = it->first; - if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr() + || !isConscious(ptr) + || ptr.getClass().getCreatureStats(ptr).getMagicEffects().get(ESM::MagicEffect::Paralyze).getMagnitude() > 0) continue; MWMechanics::AiSequence& seq = ptr.getClass().getCreatureStats(ptr).getAiSequence(); seq.fastForward(ptr, it->second->getAiState()); diff --git a/apps/openmw/mwmechanics/aisequence.cpp b/apps/openmw/mwmechanics/aisequence.cpp index 364e6effe..533bcd17c 100644 --- a/apps/openmw/mwmechanics/aisequence.cpp +++ b/apps/openmw/mwmechanics/aisequence.cpp @@ -152,8 +152,7 @@ bool AiSequence::isPackageDone() const void AiSequence::execute (const MWWorld::Ptr& actor, AiState& state,float duration) { - if(actor != MWBase::Environment::get().getWorld()->getPlayerPtr() - && !actor.getClass().getCreatureStats(actor).getKnockedDown()) + if(actor != MWBase::Environment::get().getWorld()->getPlayerPtr()) { if (!mPackages.empty()) { From a3c861b7fa1c68b20a20ff9edc927dc406956e80 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 14 Jan 2015 00:07:14 +0100 Subject: [PATCH 0305/3725] Idle voice fix --- apps/openmw/mwmechanics/aiwander.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index c3278a5ad..73f066140 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -311,14 +311,18 @@ namespace MWMechanics && actor.getRefData().getPosition().pos[2] < 3000 && MWBase::Environment::get().getSoundManager()->sayDone(actor)) { - float roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 10000; // [0, 9999] MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); - // Don't bother if the player is out of hearing range static float fVoiceIdleOdds = MWBase::Environment::get().getWorld()->getStore() .get().find("fVoiceIdleOdds")->getFloat(); - float x = fVoiceIdleOdds * MWBase::Environment::get().getFrameDuration(); + float roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 10000; + + // In vanilla MW the chance was FPS dependent, and did not allow proper changing of fVoiceIdleOdds + // due to the roll being an integer. + // Our implementation does not have these issues, so needs to be recalibrated. We chose to + // use the chance MW would have when run at 60 FPS with the default value of the GMST for calibration. + float x = fVoiceIdleOdds * 0.6 * (MWBase::Environment::get().getFrameDuration() / 0.1); // Only say Idle voices when player is in LOS // A bit counterintuitive, likely vanilla did this to reduce the appearance of From 52ed3d92a8c86224bc4ab0dc24aeb7ad797a8c96 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 14 Jan 2015 17:59:04 +0100 Subject: [PATCH 0306/3725] Fix btCompoundShape scaling (Fixes #1683) --- apps/openmw/mwworld/physicssystem.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 77c5b4460..993e1aa25 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -73,10 +73,12 @@ void animateCollisionShapes (std::map(instance.mCompound); btTransform trans; - trans.setOrigin(BtOgre::Convert::toBullet(bone->_getDerivedPosition())); + trans.setOrigin(BtOgre::Convert::toBullet(bone->_getDerivedPosition()) * compound->getLocalScaling()); trans.setRotation(BtOgre::Convert::toBullet(bone->_getDerivedOrientation())); - compound->getChildShape(shapeIt->second)->setLocalScaling(BtOgre::Convert::toBullet(bone->_getDerivedScale())); + compound->getChildShape(shapeIt->second)->setLocalScaling( + compound->getLocalScaling() * + BtOgre::Convert::toBullet(bone->_getDerivedScale())); compound->updateChildTransform(shapeIt->second, trans); } From d387c207d19aa4b0685207e9b0a48d841ac68899 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 14 Jan 2015 18:43:42 +0100 Subject: [PATCH 0307/3725] Fix initial scaling for btCompoundShape children (Fixes #2234) --- components/nifbullet/bulletnifloader.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/components/nifbullet/bulletnifloader.cpp b/components/nifbullet/bulletnifloader.cpp index 372716b68..35d552726 100644 --- a/components/nifbullet/bulletnifloader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -365,10 +365,17 @@ void ManualBulletShapeLoader::handleNiTriShape(const Nif::NiTriShape *shape, int TriangleMeshShape* childShape = new TriangleMeshShape(childMesh,true); - childShape->setLocalScaling(btVector3(transform[0][0], transform[1][1], transform[2][2])); - + float scale = shape->trafo.scale; + const Nif::Node* parent = shape; + while (parent->parent) + { + parent = parent->parent; + scale *= parent->trafo.scale; + } Ogre::Quaternion q = transform.extractQuaternion(); Ogre::Vector3 v = transform.getTrans(); + childShape->setLocalScaling(btVector3(scale, scale, scale)); + btTransform trans(btQuaternion(q.x, q.y, q.z, q.w), btVector3(v.x, v.y, v.z)); if (raycasting) From fb6dd736cfae19269ac2a98e82c2c7d2339697d2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 14 Jan 2015 20:43:15 +0100 Subject: [PATCH 0308/3725] Reducing number of jobs in .travis.yml to see if this fixes out of memory issues with coverity build --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 079e84a8e..9e302b144 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,7 +19,7 @@ addons: description: "" notification_email: scrawl@baseoftrash.de build_command_prepend: "cmake ." - build_command: "make -j4" + build_command: "make -j2" branch_pattern: coverity_scan before_install: From 03c3e3e1fffcea07b970d448c91e83fcb968fa47 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 15 Jan 2015 00:33:20 +0100 Subject: [PATCH 0309/3725] 3 jobs --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 9e302b144..f9c917bbb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,7 +19,7 @@ addons: description: "" notification_email: scrawl@baseoftrash.de build_command_prepend: "cmake ." - build_command: "make -j2" + build_command: "make -j3" branch_pattern: coverity_scan before_install: From cef72385d4f8bfeea46bdc986abf9a37ed7799d2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 15 Jan 2015 00:58:12 +0100 Subject: [PATCH 0310/3725] Fix extreme frame drop when running into certain corners (Fixes #2023) --- apps/openmw/mwworld/physicssystem.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 993e1aa25..d17d5e089 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -350,6 +350,8 @@ namespace MWWorld velocity *= 1.f-(fStromWalkMult * (angle.valueDegrees()/180.f)); } + Ogre::Vector3 origVelocity = velocity; + Ogre::Vector3 newPosition = position; /* * A loop to find newPosition using tracer, if successful different from the starting position. @@ -427,10 +429,18 @@ namespace MWWorld else { // Can't move this way, try to find another spot along the plane - Ogre::Real movelen = velocity.normalise(); + Ogre::Vector3 direction = velocity; + Ogre::Real movelen = direction.normalise(); Ogre::Vector3 reflectdir = velocity.reflect(tracer.mPlaneNormal); reflectdir.normalise(); - velocity = slide(reflectdir, tracer.mPlaneNormal)*movelen; + + Ogre::Vector3 newVelocity = slide(reflectdir, tracer.mPlaneNormal)*movelen; + if ((newVelocity-velocity).squaredLength() < 0.01) + break; + if (velocity.dotProduct(origVelocity) <= 0.f) + break; + + velocity = newVelocity; // Do not allow sliding upward if there is gravity. Stepping will have taken // care of that. From edbac30a57e20d5d742640f38ee7226aa1af4554 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 15 Jan 2015 01:23:58 +0100 Subject: [PATCH 0311/3725] Change another dynamic_cast to static_cast (coverity) --- apps/openmw/mwworld/physicssystem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index d17d5e089..0090ca010 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -70,7 +70,7 @@ void animateCollisionShapes (std::map(instance.mCompound); + btCompoundShape* compound = static_cast(instance.mCompound); btTransform trans; trans.setOrigin(BtOgre::Convert::toBullet(bone->_getDerivedPosition()) * compound->getLocalScaling()); From 6b2df951677802b138e662b606c83a01105de051 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 15 Jan 2015 02:03:27 +0100 Subject: [PATCH 0312/3725] Fix for some coverity defects --- apps/openmw/mwworld/worldimp.cpp | 13 +++++++++++-- extern/oics/ICSInputControlSystem.cpp | 3 +++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 011f6c330..fbb0b5869 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2107,6 +2107,9 @@ namespace MWWorld Ogre::Vector3 playerPos(refdata.getPosition().pos); const OEngine::Physic::PhysicActor *physactor = mPhysEngine->getCharacter(refdata.getHandle()); + if (!physactor) + return 0; // shouldn't happen + if((!physactor->getOnGround()&&physactor->getCollisionMode()) || isUnderwater(currentCell, playerPos) || isWalkingOnWater(player)) return 2; if((currentCell->getCell()->mData.mFlags&ESM::Cell::NoSleep) || @@ -2326,9 +2329,15 @@ namespace MWWorld if (!targetActor.getRefData().getBaseNode() || !targetActor.getRefData().getBaseNode()) return false; // not in active cell - Ogre::Vector3 halfExt1 = mPhysEngine->getCharacter(actor.getRefData().getHandle())->getHalfExtents(); + OEngine::Physic::PhysicActor* actor1 = mPhysEngine->getCharacter(actor.getRefData().getHandle()); + OEngine::Physic::PhysicActor* actor2 = mPhysEngine->getCharacter(targetActor.getRefData().getHandle()); + + if (!actor1 || !actor2) + return false; + + Ogre::Vector3 halfExt1 = actor1->getHalfExtents(); const float* pos1 = actor.getRefData().getPosition().pos; - Ogre::Vector3 halfExt2 = mPhysEngine->getCharacter(targetActor.getRefData().getHandle())->getHalfExtents(); + Ogre::Vector3 halfExt2 = actor2->getHalfExtents(); const float* pos2 = targetActor.getRefData().getPosition().pos; btVector3 from(pos1[0],pos1[1],pos1[2]+halfExt1.z*2*0.9); // eye level diff --git a/extern/oics/ICSInputControlSystem.cpp b/extern/oics/ICSInputControlSystem.cpp index 7dc026c7e..e1bd58728 100644 --- a/extern/oics/ICSInputControlSystem.cpp +++ b/extern/oics/ICSInputControlSystem.cpp @@ -36,6 +36,9 @@ namespace ICS , mDetectingBindingControl(NULL) , mLog(log) , mXmouseAxisBinded(false), mYmouseAxisBinded(false) + , mClientHeight(1) + , mClientWidth(1) + , mDetectingBindingDirection(Control::STOP) { ICS_LOG(" - Creating InputControlSystem - "); From b39cc0c8c837f4c01e2d98dc13721f72f52d0de7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 15 Jan 2015 02:49:54 +0100 Subject: [PATCH 0313/3725] Fix OpenCS window opening issue when config file doesn't exist It would attempt to create a zero-sized window (or even negative-sized, after subtracting the frame dimensions). --- apps/opencs/view/doc/view.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 0d2b6060e..9117a6d03 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -375,17 +375,20 @@ CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int to : mViewManager (viewManager), mDocument (document), mViewIndex (totalViews-1), mViewTotal (totalViews) { - QString width = CSMSettings::UserSettings::instance().settingValue - ("window/default-width"); + int width = CSMSettings::UserSettings::instance().settingValue + ("window/default-width").toInt(); - QString height = CSMSettings::UserSettings::instance().settingValue - ("window/default-height"); + int height = CSMSettings::UserSettings::instance().settingValue + ("window/default-height").toInt(); + + width = std::max(width, 300); + height = std::max(height, 300); // trick to get the window decorations and their sizes show(); hide(); - resize (width.toInt() - (frameGeometry().width() - geometry().width()), - height.toInt() - (frameGeometry().height() - geometry().height())); + resize (width - (frameGeometry().width() - geometry().width()), + height - (frameGeometry().height() - geometry().height())); mSubViewWindow.setDockOptions (QMainWindow::AllowNestedDocks); From bf915d929a3fcc8a5cb06c88c1e8986b4c4ef7b8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 15 Jan 2015 03:35:46 +0100 Subject: [PATCH 0314/3725] Update idle voices according to research --- apps/openmw/mwmechanics/aiwander.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 73f066140..fbb147b34 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -308,8 +308,7 @@ namespace MWMechanics // Play idle voiced dialogue entries randomly int hello = cStats.getAiSetting(CreatureStats::AI_Hello).getModified(); if (hello > 0 && !MWBase::Environment::get().getWorld()->isSwimming(actor) - && actor.getRefData().getPosition().pos[2] < 3000 && - MWBase::Environment::get().getSoundManager()->sayDone(actor)) + && MWBase::Environment::get().getSoundManager()->sayDone(actor)) { MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); @@ -327,7 +326,8 @@ namespace MWMechanics // Only say Idle voices when player is in LOS // A bit counterintuitive, likely vanilla did this to reduce the appearance of // voices going through walls? - if (roll < x && Ogre::Vector3(player.getRefData().getPosition().pos).squaredDistance(Ogre::Vector3(pos.pos)) < 1500*1500 + if (roll < x && Ogre::Vector3(player.getRefData().getPosition().pos).squaredDistance(Ogre::Vector3(pos.pos)) + < 3000*3000 // maybe should be fAudioVoiceDefaultMaxDistance*fAudioMaxDistanceMult instead && MWBase::Environment::get().getWorld()->getLOS(player, actor)) MWBase::Environment::get().getDialogueManager()->say(actor, "idle"); } From 375d426dd0e87173c668b9abea0f5f958ebc3989 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 15 Jan 2015 11:35:17 +0100 Subject: [PATCH 0315/3725] check for premature end of scripts more consistently --- components/compiler/scanner.cpp | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/components/compiler/scanner.cpp b/components/compiler/scanner.cpp index 14ab99c21..83d435962 100644 --- a/components/compiler/scanner.cpp +++ b/components/compiler/scanner.cpp @@ -387,10 +387,9 @@ namespace Compiler if (get (c)) { /// \todo hack to allow a space in comparison operators (add option to disable) - if (c==' ') - get (c); - - if (c=='=') + if (c==' ' && !get (c)) + special = S_cmpEQ; + else if (c=='=') special = S_cmpEQ; else { @@ -471,10 +470,9 @@ namespace Compiler if (get (c)) { /// \todo hack to allow a space in comparison operators (add option to disable) - if (c==' ') - get (c); - - if (c=='=') + if (c==' ' && !get (c)) + special = S_cmpLT; + else if (c=='=') { special = S_cmpLE; @@ -495,10 +493,9 @@ namespace Compiler if (get (c)) { /// \todo hack to allow a space in comparison operators (add option to disable) - if (c==' ') - get (c); - - if (c=='=') + if (c==' ' && !get (c)) + special = S_cmpGT; + else if (c=='=') { special = S_cmpGE; From f3c7532660c0d7f5bd806366802be4a61c0b730c Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 15 Jan 2015 12:01:59 +0100 Subject: [PATCH 0316/3725] cleaned up some enum confusion --- apps/opencs/model/filter/valuenode.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/filter/valuenode.cpp b/apps/opencs/model/filter/valuenode.cpp index 66b6282d7..26b982441 100644 --- a/apps/opencs/model/filter/valuenode.cpp +++ b/apps/opencs/model/filter/valuenode.cpp @@ -27,7 +27,7 @@ bool CSMFilter::ValueNode::test (const CSMWorld::IdTableBase& table, int row, QVariant data = table.data (index); if (data.type()!=QVariant::Double && data.type()!=QVariant::Bool && data.type()!=QVariant::Int && - data.type()!=QVariant::UInt && data.type()!=static_cast (QMetaType::Float)) + data.type()!=QVariant::UInt) return false; double value = data.toDouble(); From 7b8e6f9dda0e278ec8961d02f42f0ad615a95ec5 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 15 Jan 2015 12:04:23 +0100 Subject: [PATCH 0317/3725] addressed potential 0-pointer issue --- apps/opencs/view/render/object.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index d92b4aaa2..3cf256e11 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -156,11 +156,13 @@ CSVRender::Object::~Object() { clear(); - if(mPhysics) // preview may not have physics enabled - mPhysics->removeObject(mBase->getName()); - if (mBase) + { + if(mPhysics) // preview may not have physics enabled + mPhysics->removeObject(mBase->getName()); + mBase->getCreator()->destroySceneNode (mBase); + } } bool CSVRender::Object::referenceableDataChanged (const QModelIndex& topLeft, From 706df3f881ed974e3372e4e5644a39f1c8adcd58 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 15 Jan 2015 12:13:53 +0100 Subject: [PATCH 0318/3725] silenced a coverity warning --- apps/opencs/editor.cpp | 3 ++- apps/opencs/view/world/tablesubview.cpp | 20 +++++++++++--------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 826619b5d..21e1270f3 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -75,7 +75,8 @@ CS::Editor::~Editor () mPidFile.close(); if(mServer && boost::filesystem::exists(mPid)) - remove(mPid.string().c_str()); // ignore any error + static_cast ( // silence coverity warning + remove(mPid.string().c_str())); // ignore any error // cleanup global resources used by OEngine delete OEngine::Physic::BulletShapeManager::getSingletonPtr(); diff --git a/apps/opencs/view/world/tablesubview.cpp b/apps/opencs/view/world/tablesubview.cpp index 54518023b..729b6b8d7 100644 --- a/apps/opencs/view/world/tablesubview.cpp +++ b/apps/opencs/view/world/tablesubview.cpp @@ -138,17 +138,19 @@ bool CSVWorld::TableSubView::eventFilter (QObject* object, QEvent* event) { if (event->type() == QEvent::Drop) { - QDropEvent* drop = dynamic_cast(event); - const CSMWorld::TableMimeData* data = dynamic_cast(drop->mimeData()); - if (!data) // May happen when non-records (e.g. plain text) are dragged and dropped - return false; - - bool handled = data->holdsType(CSMWorld::UniversalId::Type_Filter); - if (handled) + if (QDropEvent* drop = dynamic_cast(event)) { - mFilterBox->setRecordFilter(data->returnMatching(CSMWorld::UniversalId::Type_Filter).getId()); + const CSMWorld::TableMimeData* data = dynamic_cast(drop->mimeData()); + if (!data) // May happen when non-records (e.g. plain text) are dragged and dropped + return false; + + bool handled = data->holdsType(CSMWorld::UniversalId::Type_Filter); + if (handled) + { + mFilterBox->setRecordFilter(data->returnMatching(CSMWorld::UniversalId::Type_Filter).getId()); + } + return handled; } - return handled; } return false; } From 7615cbafcee43007b60da8de8f7e1a5795b1471b Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 15 Jan 2015 14:24:33 +0100 Subject: [PATCH 0319/3725] create modify commands through command dispatcher --- apps/opencs/model/world/commanddispatcher.cpp | 8 ++++++++ apps/opencs/model/world/commanddispatcher.hpp | 9 +++++++++ apps/opencs/view/tools/reporttable.cpp | 4 ++-- apps/opencs/view/world/datadisplaydelegate.cpp | 7 ++++--- apps/opencs/view/world/datadisplaydelegate.hpp | 11 ++++------- apps/opencs/view/world/dialoguesubview.cpp | 14 +++++++------- apps/opencs/view/world/dialoguesubview.hpp | 10 ++++++---- apps/opencs/view/world/enumdelegate.cpp | 8 ++++---- apps/opencs/view/world/enumdelegate.hpp | 4 ++-- apps/opencs/view/world/idtypedelegate.cpp | 8 ++++---- apps/opencs/view/world/idtypedelegate.hpp | 4 ++-- .../opencs/view/world/recordstatusdelegate.cpp | 8 ++++---- .../opencs/view/world/recordstatusdelegate.hpp | 8 ++++---- apps/opencs/view/world/table.cpp | 2 +- apps/opencs/view/world/util.cpp | 18 ++++++++++++------ apps/opencs/view/world/util.hpp | 14 ++++++++++---- apps/opencs/view/world/vartypedelegate.cpp | 8 ++++---- apps/opencs/view/world/vartypedelegate.hpp | 5 +++-- 18 files changed, 90 insertions(+), 60 deletions(-) diff --git a/apps/opencs/model/world/commanddispatcher.cpp b/apps/opencs/model/world/commanddispatcher.cpp index 4e146d87c..a0b7a9fa0 100644 --- a/apps/opencs/model/world/commanddispatcher.cpp +++ b/apps/opencs/model/world/commanddispatcher.cpp @@ -131,6 +131,14 @@ std::vector CSMWorld::CommandDispatcher::getExtendedTypes return tables; } +void CSMWorld::CommandDispatcher::executeModify (QAbstractItemModel *model, const QModelIndex& index, const QVariant& new_) +{ + if (mLocked) + return; + + mDocument.getUndoStack().push (new CSMWorld::ModifyCommand (*model, index, new_)); +} + void CSMWorld::CommandDispatcher::executeDelete() { if (mLocked) diff --git a/apps/opencs/model/world/commanddispatcher.hpp b/apps/opencs/model/world/commanddispatcher.hpp index 50085b1a1..1d29e48c1 100644 --- a/apps/opencs/model/world/commanddispatcher.hpp +++ b/apps/opencs/model/world/commanddispatcher.hpp @@ -7,6 +7,9 @@ #include "universalid.hpp" +class QModelIndex; +class QAbstractItemModel; + namespace CSMDoc { class Document; @@ -53,6 +56,12 @@ namespace CSMWorld /// the extended mode, the returned vector will be empty instead. std::vector getExtendedTypes() const; + /// Add a modify command to the undo stack. + /// + /// \attention model must either be a model for the table operated on by this + /// dispatcher or a proxy of it. + void executeModify (QAbstractItemModel *model, const QModelIndex& index, const QVariant& new_); + public slots: void executeDelete(); diff --git a/apps/opencs/view/tools/reporttable.cpp b/apps/opencs/view/tools/reporttable.cpp index 4cd11925e..6ab470a02 100644 --- a/apps/opencs/view/tools/reporttable.cpp +++ b/apps/opencs/view/tools/reporttable.cpp @@ -79,8 +79,8 @@ CSVTools::ReportTable::ReportTable (CSMDoc::Document& document, setModel (mModel); setColumnHidden (2, true); - mIdTypeDelegate = CSVWorld::IdTypeDelegateFactory().makeDelegate ( - document, this); + mIdTypeDelegate = CSVWorld::IdTypeDelegateFactory().makeDelegate (0, + mDocument, this); setItemDelegateForColumn (0, mIdTypeDelegate); diff --git a/apps/opencs/view/world/datadisplaydelegate.cpp b/apps/opencs/view/world/datadisplaydelegate.cpp index 46ca17a29..b9df52bf7 100644 --- a/apps/opencs/view/world/datadisplaydelegate.cpp +++ b/apps/opencs/view/world/datadisplaydelegate.cpp @@ -6,11 +6,12 @@ CSVWorld::DataDisplayDelegate::DataDisplayDelegate(const ValueList &values, const IconList &icons, + CSMWorld::CommandDispatcher *dispatcher, CSMDoc::Document& document, const QString &pageName, const QString &settingName, QObject *parent) - : EnumDelegate (values, document, parent), mDisplayMode (Mode_TextOnly), + : EnumDelegate (values, dispatcher, document, parent), mDisplayMode (Mode_TextOnly), mIcons (icons), mIconSize (QSize(16, 16)), mIconLeftOffset(3), mTextLeftOffset(8), mSettingKey (pageName + '/' + settingName) { @@ -136,9 +137,9 @@ void CSVWorld::DataDisplayDelegateFactory::add (int enumValue, QString enumName, } CSVWorld::CommandDelegate *CSVWorld::DataDisplayDelegateFactory::makeDelegate ( - CSMDoc::Document& document, QObject *parent) const + CSMWorld::CommandDispatcher *dispatcher, CSMDoc::Document& document, QObject *parent) const { - return new DataDisplayDelegate (mValues, mIcons, document, "", "", parent); + return new DataDisplayDelegate (mValues, mIcons, dispatcher, document, "", "", parent); } diff --git a/apps/opencs/view/world/datadisplaydelegate.hpp b/apps/opencs/view/world/datadisplaydelegate.hpp index 73790e3c6..f6e4c2688 100755 --- a/apps/opencs/view/world/datadisplaydelegate.hpp +++ b/apps/opencs/view/world/datadisplaydelegate.hpp @@ -38,12 +38,9 @@ namespace CSVWorld QString mSettingKey; public: - explicit DataDisplayDelegate (const ValueList & values, - const IconList & icons, - CSMDoc::Document& document, - const QString &pageName, - const QString &settingName, - QObject *parent); + DataDisplayDelegate (const ValueList & values, const IconList & icons, + CSMWorld::CommandDispatcher *dispatcher, CSMDoc::Document& document, + const QString &pageName, const QString &settingName, QObject *parent); ~DataDisplayDelegate(); @@ -82,7 +79,7 @@ namespace CSVWorld public: - virtual CommandDelegate *makeDelegate (CSMDoc::Document& document, QObject *parent) const; + virtual CommandDelegate *makeDelegate (CSMWorld::CommandDispatcher *dispatcher, CSMDoc::Document& document, QObject *parent) const; ///< The ownership of the returned CommandDelegate is transferred to the caller. protected: diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 8790601ea..497ce7acd 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -167,10 +167,10 @@ void CSVWorld::DialogueDelegateDispatcherProxy::tableMimeDataDropped(const std:: ==============================DialogueDelegateDispatcher========================================== */ -CSVWorld::DialogueDelegateDispatcher::DialogueDelegateDispatcher(QObject* parent, CSMWorld::IdTable* table, CSMDoc::Document& document) : +CSVWorld::DialogueDelegateDispatcher::DialogueDelegateDispatcher(QObject* parent, CSMWorld::IdTable* table, CSMWorld::CommandDispatcher& commandDispatcher, CSMDoc::Document& document) : mParent(parent), mTable(table), -mDocument (document), +mCommandDispatcher (commandDispatcher), mDocument (document), mNotEditableDelegate(table, parent) { } @@ -182,7 +182,7 @@ CSVWorld::CommandDelegate* CSVWorld::DialogueDelegateDispatcher::makeDelegate(CS if (delegateIt == mDelegates.end()) { delegate = CommandDelegateFactoryCollection::get().makeDelegate ( - display, mDocument, mParent); + display, &mCommandDispatcher, mDocument, mParent); mDelegates.insert(std::make_pair(display, delegate)); } else { @@ -309,12 +309,12 @@ CSVWorld::DialogueDelegateDispatcher::~DialogueDelegateDispatcher() =============================================================EditWidget===================================================== */ -CSVWorld::EditWidget::EditWidget(QWidget *parent, int row, CSMWorld::IdTable* table, CSMDoc::Document& document, bool createAndDelete) : -mDispatcher(this, table, document), +CSVWorld::EditWidget::EditWidget(QWidget *parent, int row, CSMWorld::IdTable* table, CSMWorld::CommandDispatcher& commandDispatcher, CSMDoc::Document& document, bool createAndDelete) : +mDispatcher(this, table, commandDispatcher, document), QScrollArea(parent), mWidgetMapper(NULL), mMainWidget(NULL), -mDocument (document), +mCommandDispatcher (commandDispatcher), mTable(table) { remake (row); @@ -471,7 +471,7 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSM mMainLayout = new QVBoxLayout(mainWidget); - mEditWidget = new EditWidget(mainWidget, mRow, mTable, document, false); + mEditWidget = new EditWidget(mainWidget, mRow, mTable, mCommandDispatcher, document, false); connect(mEditWidget, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*)), this, SLOT(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*))); diff --git a/apps/opencs/view/world/dialoguesubview.hpp b/apps/opencs/view/world/dialoguesubview.hpp index 4c260170f..f45ed40c4 100644 --- a/apps/opencs/view/world/dialoguesubview.hpp +++ b/apps/opencs/view/world/dialoguesubview.hpp @@ -101,14 +101,16 @@ namespace CSVWorld CSMWorld::IdTable* mTable; - CSMDoc::Document& mDocument; + CSMWorld::CommandDispatcher& mCommandDispatcher; + CSMDoc::Document& mDocument; NotEditableSubDelegate mNotEditableDelegate; std::vector mProxys; //once we move to the C++11 we should use unique_ptr public: - DialogueDelegateDispatcher(QObject* parent, CSMWorld::IdTable* table, CSMDoc::Document& document); + DialogueDelegateDispatcher(QObject* parent, CSMWorld::IdTable* table, + CSMWorld::CommandDispatcher& commandDispatcher, CSMDoc::Document& document); ~DialogueDelegateDispatcher(); @@ -145,11 +147,11 @@ namespace CSVWorld DialogueDelegateDispatcher mDispatcher; QWidget* mMainWidget; CSMWorld::IdTable* mTable; - CSMDoc::Document& mDocument; + CSMWorld::CommandDispatcher& mCommandDispatcher; public: - EditWidget (QWidget *parent, int row, CSMWorld::IdTable* table, CSMDoc::Document& document, bool createAndDelete = false); + EditWidget (QWidget *parent, int row, CSMWorld::IdTable* table, CSMWorld::CommandDispatcher& commandDispatcher, CSMDoc::Document& document, bool createAndDelete = false); void remake(int row); diff --git a/apps/opencs/view/world/enumdelegate.cpp b/apps/opencs/view/world/enumdelegate.cpp index 168e5cb0a..95b120e9a 100644 --- a/apps/opencs/view/world/enumdelegate.cpp +++ b/apps/opencs/view/world/enumdelegate.cpp @@ -35,8 +35,8 @@ void CSVWorld::EnumDelegate::addCommands (QAbstractItemModel *model, CSVWorld::EnumDelegate::EnumDelegate (const std::vector >& values, - CSMDoc::Document& document, QObject *parent) -: CommandDelegate (document, parent), mValues (values) + CSMWorld::CommandDispatcher *dispatcher, CSMDoc::Document& document, QObject *parent) +: CommandDelegate (dispatcher, document, parent), mValues (values) { } @@ -141,9 +141,9 @@ CSVWorld::EnumDelegateFactory::EnumDelegateFactory (const std::vector >& values, - CSMDoc::Document& document, QObject *parent); + CSMWorld::CommandDispatcher *dispatcher, CSMDoc::Document& document, QObject *parent); virtual QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem& option, @@ -64,7 +64,7 @@ namespace CSVWorld EnumDelegateFactory (const std::vector& names, bool allowNone = false); /// \param allowNone Use value of -1 for "none selected" (empty string) - virtual CommandDelegate *makeDelegate (CSMDoc::Document& document, QObject *parent) const; + virtual CommandDelegate *makeDelegate (CSMWorld::CommandDispatcher *dispatcher, CSMDoc::Document& document, QObject *parent) const; ///< The ownership of the returned CommandDelegate is transferred to the caller. void add (int value, const QString& name); diff --git a/apps/opencs/view/world/idtypedelegate.cpp b/apps/opencs/view/world/idtypedelegate.cpp index 3b440ff71..34c8d12cd 100755 --- a/apps/opencs/view/world/idtypedelegate.cpp +++ b/apps/opencs/view/world/idtypedelegate.cpp @@ -3,8 +3,8 @@ #include "../../model/world/universalid.hpp" CSVWorld::IdTypeDelegate::IdTypeDelegate - (const ValueList &values, const IconList &icons, CSMDoc::Document& document, QObject *parent) - : DataDisplayDelegate (values, icons, document, + (const ValueList &values, const IconList &icons, CSMWorld::CommandDispatcher *dispatcher, CSMDoc::Document& document, QObject *parent) + : DataDisplayDelegate (values, icons, dispatcher, document, "records", "type-format", parent) {} @@ -21,7 +21,7 @@ CSVWorld::IdTypeDelegateFactory::IdTypeDelegateFactory() } CSVWorld::CommandDelegate *CSVWorld::IdTypeDelegateFactory::makeDelegate ( - CSMDoc::Document& document, QObject *parent) const + CSMWorld::CommandDispatcher *dispatcher, CSMDoc::Document& document, QObject *parent) const { - return new IdTypeDelegate (mValues, mIcons, document, parent); + return new IdTypeDelegate (mValues, mIcons, dispatcher, document, parent); } diff --git a/apps/opencs/view/world/idtypedelegate.hpp b/apps/opencs/view/world/idtypedelegate.hpp index e9a0af68c..d0ed6997b 100755 --- a/apps/opencs/view/world/idtypedelegate.hpp +++ b/apps/opencs/view/world/idtypedelegate.hpp @@ -11,7 +11,7 @@ namespace CSVWorld class IdTypeDelegate : public DataDisplayDelegate { public: - IdTypeDelegate (const ValueList &mValues, const IconList &icons, CSMDoc::Document& document, QObject *parent); + IdTypeDelegate (const ValueList &mValues, const IconList &icons, CSMWorld::CommandDispatcher *dispatcher, CSMDoc::Document& document, QObject *parent); }; class IdTypeDelegateFactory : public DataDisplayDelegateFactory @@ -20,7 +20,7 @@ namespace CSVWorld IdTypeDelegateFactory(); - virtual CommandDelegate *makeDelegate (CSMDoc::Document& document, QObject *parent) const; + virtual CommandDelegate *makeDelegate (CSMWorld::CommandDispatcher *dispatcher, CSMDoc::Document& document, 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 708a78015..58a5c0177 100644 --- a/apps/opencs/view/world/recordstatusdelegate.cpp +++ b/apps/opencs/view/world/recordstatusdelegate.cpp @@ -9,16 +9,16 @@ CSVWorld::RecordStatusDelegate::RecordStatusDelegate(const ValueList& values, const IconList & icons, - CSMDoc::Document& document, QObject *parent) - : DataDisplayDelegate (values, icons, document, + CSMWorld::CommandDispatcher *dispatcher, CSMDoc::Document& document, QObject *parent) + : DataDisplayDelegate (values, icons, dispatcher, document, "records", "status-format", parent) {} CSVWorld::CommandDelegate *CSVWorld::RecordStatusDelegateFactory::makeDelegate ( - CSMDoc::Document& document, QObject *parent) const + CSMWorld::CommandDispatcher *dispatcher, CSMDoc::Document& document, QObject *parent) const { - return new RecordStatusDelegate (mValues, mIcons, document, parent); + return new RecordStatusDelegate (mValues, mIcons, dispatcher, document, parent); } CSVWorld::RecordStatusDelegateFactory::RecordStatusDelegateFactory() diff --git a/apps/opencs/view/world/recordstatusdelegate.hpp b/apps/opencs/view/world/recordstatusdelegate.hpp index fbdaed538..acaf872a6 100644 --- a/apps/opencs/view/world/recordstatusdelegate.hpp +++ b/apps/opencs/view/world/recordstatusdelegate.hpp @@ -17,9 +17,9 @@ namespace CSVWorld { public: - explicit RecordStatusDelegate(const ValueList& values, - const IconList& icons, - CSMDoc::Document& document, QObject *parent = 0); + RecordStatusDelegate (const ValueList& values, const IconList& icons, + CSMWorld::CommandDispatcher *dispatcher, CSMDoc::Document& document, + QObject *parent = 0); }; class RecordStatusDelegateFactory : public DataDisplayDelegateFactory @@ -28,7 +28,7 @@ namespace CSVWorld RecordStatusDelegateFactory(); - virtual CommandDelegate *makeDelegate (CSMDoc::Document& document, QObject *parent) const; + virtual CommandDelegate *makeDelegate (CSMWorld::CommandDispatcher *dispatcher, CSMDoc::Document& document, QObject *parent) const; ///< The ownership of the returned CommandDelegate is transferred to the caller. }; diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index e864e4ed2..794510f42 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -281,7 +281,7 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id, mModel->headerData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Display).toInt()); CommandDelegate *delegate = CommandDelegateFactoryCollection::get().makeDelegate (display, - mDocument, this); + mDispatcher, document, this); mDelegates.push_back (delegate); setItemDelegateForColumn (i, delegate); diff --git a/apps/opencs/view/world/util.cpp b/apps/opencs/view/world/util.cpp index c65e12c60..8039034a2 100644 --- a/apps/opencs/view/world/util.cpp +++ b/apps/opencs/view/world/util.cpp @@ -18,6 +18,7 @@ #include "../../model/world/commands.hpp" #include "../../model/world/tablemimedata.hpp" +#include "../../model/world/commanddispatcher.hpp" #include "scriptedit.hpp" @@ -82,15 +83,15 @@ void CSVWorld::CommandDelegateFactoryCollection::add (CSMWorld::ColumnBase::Disp } CSVWorld::CommandDelegate *CSVWorld::CommandDelegateFactoryCollection::makeDelegate ( - CSMWorld::ColumnBase::Display display, CSMDoc::Document& document, QObject *parent) const + CSMWorld::ColumnBase::Display display, CSMWorld::CommandDispatcher *dispatcher, CSMDoc::Document& document, QObject *parent) const { std::map::const_iterator iter = mFactories.find (display); if (iter!=mFactories.end()) - return iter->second->makeDelegate (document, parent); + return iter->second->makeDelegate (dispatcher, document, parent); - return new CommandDelegate (document, parent); + return new CommandDelegate (dispatcher, document, parent); } const CSVWorld::CommandDelegateFactoryCollection& CSVWorld::CommandDelegateFactoryCollection::get() @@ -115,17 +116,22 @@ CSMDoc::Document& CSVWorld::CommandDelegate::getDocument() const void CSVWorld::CommandDelegate::setModelDataImp (QWidget *editor, QAbstractItemModel *model, const QModelIndex& index) const { + if (!mCommandDispatcher) + return; + NastyTableModelHack hack (*model); QStyledItemDelegate::setModelData (editor, &hack, index); QVariant new_ = hack.getData(); if (model->data (index)!=new_) - getUndoStack().push (new CSMWorld::ModifyCommand (*model, index, new_)); + mCommandDispatcher->executeModify (model, index, new_); } -CSVWorld::CommandDelegate::CommandDelegate (CSMDoc::Document& document, QObject *parent) -: QStyledItemDelegate (parent), mDocument (document), mEditLock (false) +CSVWorld::CommandDelegate::CommandDelegate (CSMWorld::CommandDispatcher *commandDispatcher, + CSMDoc::Document& document, QObject *parent) +: QStyledItemDelegate (parent), mEditLock (false), + mCommandDispatcher (commandDispatcher), mDocument (document) {} void CSVWorld::CommandDelegate::setModelData (QWidget *editor, QAbstractItemModel *model, diff --git a/apps/opencs/view/world/util.hpp b/apps/opencs/view/world/util.hpp index b4d972bf3..df9d61dad 100644 --- a/apps/opencs/view/world/util.hpp +++ b/apps/opencs/view/world/util.hpp @@ -16,6 +16,7 @@ namespace CSMWorld { class TableMimeData; class UniversalId; + class CommandDispatcher; } namespace CSVWorld @@ -51,7 +52,8 @@ namespace CSVWorld virtual ~CommandDelegateFactory(); - virtual CommandDelegate *makeDelegate (CSMDoc::Document& document, QObject *parent) + virtual CommandDelegate *makeDelegate (CSMWorld::CommandDispatcher *dispatcher, + CSMDoc::Document& document, QObject *parent) const = 0; ///< The ownership of the returned CommandDelegate is transferred to the caller. }; @@ -78,7 +80,8 @@ namespace CSVWorld /// /// This function must not be called more than once per value of \a display. - CommandDelegate *makeDelegate (CSMWorld::ColumnBase::Display display, CSMDoc::Document& document, + CommandDelegate *makeDelegate (CSMWorld::ColumnBase::Display display, + CSMWorld::CommandDispatcher *dispatcher, CSMDoc::Document& document, QObject *parent) const; ///< The ownership of the returned CommandDelegate is transferred to the caller. /// @@ -111,8 +114,9 @@ namespace CSVWorld { Q_OBJECT - CSMDoc::Document& mDocument; bool mEditLock; + CSMWorld::CommandDispatcher *mCommandDispatcher; + CSMDoc::Document& mDocument; protected: @@ -125,7 +129,9 @@ namespace CSVWorld public: - CommandDelegate (CSMDoc::Document& document, QObject *parent); + /// \param commandDispatcher If CommandDelegate will be only be used on read-only + /// cells, a 0-pointer can be passed here. + CommandDelegate (CSMWorld::CommandDispatcher *commandDispatcher, CSMDoc::Document& document, QObject *parent); virtual void setModelData (QWidget *editor, QAbstractItemModel *model, const QModelIndex& index) const; diff --git a/apps/opencs/view/world/vartypedelegate.cpp b/apps/opencs/view/world/vartypedelegate.cpp index c3c98b800..90a686a67 100644 --- a/apps/opencs/view/world/vartypedelegate.cpp +++ b/apps/opencs/view/world/vartypedelegate.cpp @@ -47,8 +47,8 @@ void CSVWorld::VarTypeDelegate::addCommands (QAbstractItemModel *model, const QM } CSVWorld::VarTypeDelegate::VarTypeDelegate (const std::vector >& values, - CSMDoc::Document& document, QObject *parent) -: EnumDelegate (values, document, parent) + CSMWorld::CommandDispatcher *dispatcher, CSMDoc::Document& document, QObject *parent) +: EnumDelegate (values, dispatcher, document, parent) {} @@ -69,9 +69,9 @@ CSVWorld::VarTypeDelegateFactory::VarTypeDelegateFactory (ESM::VarType type0, } CSVWorld::CommandDelegate *CSVWorld::VarTypeDelegateFactory::makeDelegate ( - CSMDoc::Document& document, QObject *parent) const + CSMWorld::CommandDispatcher *dispatcher, CSMDoc::Document& document, QObject *parent) const { - return new VarTypeDelegate (mValues, document, parent); + return new VarTypeDelegate (mValues, dispatcher, document, parent); } void CSVWorld::VarTypeDelegateFactory::add (ESM::VarType type) diff --git a/apps/opencs/view/world/vartypedelegate.hpp b/apps/opencs/view/world/vartypedelegate.hpp index c86b936f6..a8f39c318 100644 --- a/apps/opencs/view/world/vartypedelegate.hpp +++ b/apps/opencs/view/world/vartypedelegate.hpp @@ -17,7 +17,7 @@ namespace CSVWorld public: VarTypeDelegate (const std::vector >& values, - CSMDoc::Document& document, QObject *parent); + CSMWorld::CommandDispatcher *dispatcher, CSMDoc::Document& document, QObject *parent); }; class VarTypeDelegateFactory : public CommandDelegateFactory @@ -30,7 +30,8 @@ namespace CSVWorld ESM::VarType type1 = ESM::VT_Unknown, ESM::VarType type2 = ESM::VT_Unknown, ESM::VarType type3 = ESM::VT_Unknown); - virtual CommandDelegate *makeDelegate (CSMDoc::Document& document, QObject *parent) const; + virtual CommandDelegate *makeDelegate (CSMWorld::CommandDispatcher *dispatcher, + CSMDoc::Document& document, QObject *parent) const; ///< The ownership of the returned CommandDelegate is transferred to the caller. void add (ESM::VarType type); From c55e9b9c586b4687c16fab04cc91a4f9061f3ae4 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 15 Jan 2015 15:00:16 +0100 Subject: [PATCH 0320/3725] one more potential 0-pointer fix --- apps/opencs/view/render/object.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index 3cf256e11..3607fb415 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -35,7 +35,8 @@ void CSVRender::Object::clear() { mObject.setNull(); - clearSceneNode (mBase); + if (mBase) + clearSceneNode (mBase); } void CSVRender::Object::update() From fc6aa256bfd1118496db8f6f09dc6397824ecea1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 15 Jan 2015 16:05:25 +0100 Subject: [PATCH 0321/3725] Add comment --- apps/openmw/mwworld/scene.cpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index d054cd560..286721df4 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -28,7 +28,7 @@ namespace std::string model = Misc::ResourceHelpers::correctActorModelPath(ptr.getClass().getModel(ptr)); std::string id = ptr.getClass().getId(ptr); if (id == "prisonmarker" || id == "divinemarker" || id == "templemarker" || id == "northmarker") - model = ""; + model = ""; // marker objects that have a hardcoded function in the game logic, should be hidden from the player rendering.addObject(ptr, model); ptr.getClass().insertObject (ptr, model, physics); } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index fbb0b5869..104605e65 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2108,7 +2108,7 @@ namespace MWWorld const OEngine::Physic::PhysicActor *physactor = mPhysEngine->getCharacter(refdata.getHandle()); if (!physactor) - return 0; // shouldn't happen + throw std::runtime_error("can't find player"); if((!physactor->getOnGround()&&physactor->getCollisionMode()) || isUnderwater(currentCell, playerPos) || isWalkingOnWater(player)) return 2; From 714b19015cb43e5a5829020730de145b15d3c7f7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 15 Jan 2015 20:31:08 +0100 Subject: [PATCH 0322/3725] Fix unknown record error message --- apps/openmw/mwstate/statemanagerimp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 54c3726bd..87b303b6f 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -426,7 +426,7 @@ void MWState::StateManager::loadGame (const Character *character, const std::str default: // ignore invalid records - std::cerr << "Ignoring unknown record: " << n.name << std::endl; + std::cerr << "Ignoring unknown record: " << n.toString() << std::endl; reader.skipRecord(); } int progressPercent = static_cast(float(reader.getFileOffset())/total*100); From 561ddfa0c59bdea8cb717658b56f6b4701c4cef7 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 16 Jan 2015 11:27:17 +0100 Subject: [PATCH 0323/3725] make column type accessable via the regular table model --- apps/opencs/model/world/columnbase.hpp | 3 ++- apps/opencs/model/world/idtable.cpp | 13 +++++++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index db9b8b3c6..03e373904 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -15,7 +15,8 @@ namespace CSMWorld enum Roles { Role_Flags = Qt::UserRole, - Role_Display = Qt::UserRole+1 + Role_Display = Qt::UserRole+1, + Role_ColumnId = Qt::UserRole+1 }; enum Flags diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index c68b71789..773326490 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -27,9 +27,15 @@ int CSMWorld::IdTable::columnCount (const QModelIndex & parent) const return mIdCollection->getColumns(); } -QVariant CSMWorld::IdTable::data (const QModelIndex & index, int role) const +QVariant CSMWorld::IdTable::data (const QModelIndex & index, int role) const { - if ((role!=Qt::DisplayRole && role!=Qt::EditRole) || index.row() < 0 || index.column() < 0) + if (index.row() < 0 || index.column() < 0) + return QVariant(); + + if (role==ColumnBase::Role_ColumnId) + return QVariant (getColumnId (index.column())); + + if ((role!=Qt::DisplayRole && role!=Qt::EditRole)) return QVariant(); if (role==Qt::EditRole && !mIdCollection->getColumn (index.column()).isEditable()) @@ -52,6 +58,9 @@ QVariant CSMWorld::IdTable::headerData (int section, Qt::Orientation orientation if (role==ColumnBase::Role_Display) return mIdCollection->getColumn (section).mDisplayType; + if (role==ColumnBase::Role_ColumnId) + return getColumnId (section); + return QVariant(); } From 9670e0881dd74c83e2ce40d7b5495d99bc525603 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 16 Jan 2015 15:17:52 +0100 Subject: [PATCH 0324/3725] update reference's current cell when x/y-coordinates are modified --- apps/opencs/model/world/commanddispatcher.cpp | 44 ++++++++++++++++- apps/opencs/model/world/commands.cpp | 47 ++++++++++++++++++- apps/opencs/model/world/commands.hpp | 23 ++++++++- 3 files changed, 111 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/world/commanddispatcher.cpp b/apps/opencs/model/world/commanddispatcher.cpp index a0b7a9fa0..cda4f3a74 100644 --- a/apps/opencs/model/world/commanddispatcher.cpp +++ b/apps/opencs/model/world/commanddispatcher.cpp @@ -2,6 +2,7 @@ #include "commanddispatcher.hpp" #include +#include #include @@ -10,6 +11,7 @@ #include "idtable.hpp" #include "record.hpp" #include "commands.hpp" +#include "idtableproxymodel.hpp" std::vector CSMWorld::CommandDispatcher::getDeletableRecords() const { @@ -136,7 +138,47 @@ void CSMWorld::CommandDispatcher::executeModify (QAbstractItemModel *model, cons if (mLocked) return; - mDocument.getUndoStack().push (new CSMWorld::ModifyCommand (*model, index, new_)); + std::auto_ptr modifyCell; + + int columnId = model->data (index, ColumnBase::Role_ColumnId).toInt(); + + if (columnId==Columns::ColumnId_PositionXPos || columnId==Columns::ColumnId_PositionYPos) + { + IdTableProxyModel *proxy = dynamic_cast (model); + + int row = proxy ? proxy->mapToSource (index).row() : index.row(); + + // This is not guaranteed to be the same as \a model, since a proxy could be used. + IdTable& model2 = dynamic_cast (*mDocument.getData().getTableModel (mId)); + + int cellColumn = model2.searchColumnIndex (Columns::ColumnId_Cell); + + if (cellColumn!=-1) + { + QModelIndex cellIndex = model2.index (row, cellColumn); + + std::string cellId = model2.data (cellIndex).toString().toUtf8().data(); + + if (cellId.find ('#')!=std::string::npos) + { + // Need to recalculate the cell + modifyCell.reset (new UpdateCellCommand (model2, row)); + } + } + } + + std::auto_ptr modifyData ( + new CSMWorld::ModifyCommand (*model, index, new_)); + + if (modifyCell.get()) + { + mDocument.getUndoStack().beginMacro (modifyData->text()); + mDocument.getUndoStack().push (modifyData.release()); + mDocument.getUndoStack().push (modifyCell.release()); + mDocument.getUndoStack().endMacro(); + } + else + mDocument.getUndoStack().push (modifyData.release()); } void CSMWorld::CommandDispatcher::executeDelete() diff --git a/apps/opencs/model/world/commands.cpp b/apps/opencs/model/world/commands.cpp index de0e9a4e5..bd667e40b 100644 --- a/apps/opencs/model/world/commands.cpp +++ b/apps/opencs/model/world/commands.cpp @@ -1,11 +1,16 @@ #include "commands.hpp" +#include + +#include + #include -#include "idtable.hpp" #include +#include "idtable.hpp" + CSMWorld::ModifyCommand::ModifyCommand (QAbstractItemModel& model, const QModelIndex& index, const QVariant& new_, QUndoCommand* parent) : QUndoCommand (parent), mModel (model), mIndex (index), mNew (new_) @@ -170,4 +175,44 @@ void CSMWorld::CloneCommand::redo() void CSMWorld::CloneCommand::undo() { mModel.removeRow (mModel.getModelIndex (mId, 0).row()); +} + + +CSMWorld::UpdateCellCommand::UpdateCellCommand (IdTable& model, int row, QUndoCommand *parent) +: QUndoCommand (parent), mModel (model), mRow (row) +{ + setText ("Update cell ID"); +} + +void CSMWorld::UpdateCellCommand::redo() +{ + if (!mNew.isValid()) + { + int cellColumn = mModel.searchColumnIndex (Columns::ColumnId_Cell); + mIndex = mModel.index (mRow, cellColumn); + + const int cellSize = 8192; + + QModelIndex xIndex = mModel.index ( + mRow, mModel.findColumnIndex (Columns::ColumnId_PositionXPos)); + + QModelIndex yIndex = mModel.index ( + mRow, mModel.findColumnIndex (Columns::ColumnId_PositionYPos)); + + int x = std::floor (mModel.data (xIndex).toFloat() / cellSize); + int y = std::floor (mModel.data (yIndex).toFloat() / cellSize); + + std::ostringstream stream; + + stream << "#" << x << " " << y; + + mNew = QString::fromUtf8 (stream.str().c_str()); + } + + mModel.setData (mIndex, mNew); +} + +void CSMWorld::UpdateCellCommand::undo() +{ + mModel.setData (mIndex, mOld); } \ No newline at end of file diff --git a/apps/opencs/model/world/commands.hpp b/apps/opencs/model/world/commands.hpp index a15c071a8..26e1da828 100644 --- a/apps/opencs/model/world/commands.hpp +++ b/apps/opencs/model/world/commands.hpp @@ -18,7 +18,6 @@ class QAbstractItemModel; namespace CSMWorld { - class IdTable; class IdTable; class RecordBase; @@ -139,6 +138,28 @@ namespace CSMWorld virtual void undo(); }; + + /// \brief Update cell ID according to x/y-coordinates + /// + /// \note The new value will be calculated in the first call to redo instead of the + /// constructor to accommodate multiple coordinate-affecting commands being executed + /// in a macro. + class UpdateCellCommand : public QUndoCommand + { + IdTable& mModel; + int mRow; + QModelIndex mIndex; + QVariant mNew; // invalid, if new cell ID has not been calculated yet + QVariant mOld; + + public: + + UpdateCellCommand (IdTable& model, int row, QUndoCommand *parent = 0); + + virtual void redo(); + + virtual void undo(); + }; } #endif \ No newline at end of file From 1869d37cfc3b1dfb786f51a7995818d3225a4f15 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 16 Jan 2015 04:55:42 +0100 Subject: [PATCH 0325/3725] Remove unused mLastDrowningHit --- apps/openmw/mwmechanics/npcstats.cpp | 3 --- apps/openmw/mwmechanics/npcstats.hpp | 2 -- components/esm/npcstats.cpp | 8 +++----- components/esm/npcstats.hpp | 1 - 4 files changed, 3 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index ba01caf95..6d9388408 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -33,7 +33,6 @@ MWMechanics::NpcStats::NpcStats() , mWerewolfKills (0) , mProfit(0) , mTimeToStartDrowning(20.0) -, mLastDrowningHit(0) { mSkillIncreases.resize (ESM::Attribute::Length, 0); } @@ -522,7 +521,6 @@ void MWMechanics::NpcStats::writeState (ESM::NpcStats& state) const std::copy (mUsedIds.begin(), mUsedIds.end(), std::back_inserter (state.mUsedIds)); state.mTimeToStartDrowning = mTimeToStartDrowning; - state.mLastDrowningHit = mLastDrowningHit; } void MWMechanics::NpcStats::readState (const ESM::NpcStats& state) @@ -573,5 +571,4 @@ void MWMechanics::NpcStats::readState (const ESM::NpcStats& state) mUsedIds.insert (*iter); mTimeToStartDrowning = state.mTimeToStartDrowning; - mLastDrowningHit = state.mLastDrowningHit; } diff --git a/apps/openmw/mwmechanics/npcstats.hpp b/apps/openmw/mwmechanics/npcstats.hpp index ee897033b..579455a75 100644 --- a/apps/openmw/mwmechanics/npcstats.hpp +++ b/apps/openmw/mwmechanics/npcstats.hpp @@ -46,8 +46,6 @@ namespace MWMechanics /// Countdown to getting damage while underwater float mTimeToStartDrowning; - /// time since last hit from drowning - float mLastDrowningHit; public: diff --git a/components/esm/npcstats.cpp b/components/esm/npcstats.cpp index 3e6aed99d..4ba0ce7e3 100644 --- a/components/esm/npcstats.cpp +++ b/components/esm/npcstats.cpp @@ -75,8 +75,9 @@ void ESM::NpcStats::load (ESMReader &esm) mTimeToStartDrowning = 0; esm.getHNOT (mTimeToStartDrowning, "DRTI"); - mLastDrowningHit = 0; - esm.getHNOT (mLastDrowningHit, "DRLH"); + // No longer used + float lastDrowningHit = 0; + esm.getHNOT (lastDrowningHit, "DRLH"); // No longer used float levelHealthBonus = 0; @@ -146,9 +147,6 @@ void ESM::NpcStats::save (ESMWriter &esm) const if (mTimeToStartDrowning) esm.writeHNT ("DRTI", mTimeToStartDrowning); - if (mLastDrowningHit) - esm.writeHNT ("DRLH", mLastDrowningHit); - if (mCrimeId != -1) esm.writeHNT ("CRID", mCrimeId); } diff --git a/components/esm/npcstats.hpp b/components/esm/npcstats.hpp index 0061fc05f..f6e9c1e58 100644 --- a/components/esm/npcstats.hpp +++ b/components/esm/npcstats.hpp @@ -45,7 +45,6 @@ namespace ESM int mSkillIncrease[8]; std::vector mUsedIds; float mTimeToStartDrowning; - float mLastDrowningHit; int mCrimeId; void load (ESMReader &esm); From b77558726a99427b62d59256db75ace243d4bef7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 16 Jan 2015 14:59:42 +0100 Subject: [PATCH 0326/3725] Disable collision for placeable objects (Fixes #1634) --- libs/openengine/bullet/physic.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index a3ec25e22..1ef00a0e1 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -461,7 +461,9 @@ namespace Physic BulletShapeManager::getSingletonPtr()->load(outputstring,"General"); BulletShapePtr shape = BulletShapeManager::getSingleton().getByName(outputstring,"General"); - if (placeable && !raycasting && shape->mCollisionShape && shape->mAutogenerated) + // TODO: add option somewhere to enable collision for placeable meshes + + if (placeable && !raycasting && shape->mCollisionShape) return NULL; if (!shape->mCollisionShape && !raycasting) From 14aacf9a726e2b1d94b3339d1403af1ecabab13c Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 16 Jan 2015 17:56:19 +0100 Subject: [PATCH 0327/3725] Add comment --- apps/openmw/mwmechanics/npcstats.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwmechanics/npcstats.hpp b/apps/openmw/mwmechanics/npcstats.hpp index 579455a75..4594492e1 100644 --- a/apps/openmw/mwmechanics/npcstats.hpp +++ b/apps/openmw/mwmechanics/npcstats.hpp @@ -108,8 +108,10 @@ namespace MWMechanics /// Called at character creation. void flagAsUsed (const std::string& id); + ///< @note Id must be lower-case bool hasBeenUsed (const std::string& id) const; + ///< @note Id must be lower-case int getBounty() const; From fc663addfa336032dab9f02a026474f91e3c80c7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 16 Jan 2015 23:10:57 +0100 Subject: [PATCH 0328/3725] Fix null character issue in ESMReader::getString --- components/esm/esmreader.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/components/esm/esmreader.cpp b/components/esm/esmreader.cpp index 6facee381..7cf0de1a9 100644 --- a/components/esm/esmreader.cpp +++ b/components/esm/esmreader.cpp @@ -299,8 +299,7 @@ std::string ESMReader::getString(int size) char *ptr = &mBuffer[0]; getExact(ptr, size); - if (size>0 && ptr[size-1]==0) - --size; + size = strnlen(ptr, size); // Convert to UTF8 and return if (mEncoder) From 031eec45509c3b157dd4fce9e366ac4fcfffe571 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 17 Jan 2015 00:11:36 +0100 Subject: [PATCH 0329/3725] Starting ESS importer for Morrowind save files --- CMakeLists.txt | 11 + apps/essimporter/CMakeLists.txt | 25 +++ apps/essimporter/converter.cpp | 40 ++++ apps/essimporter/converter.hpp | 262 +++++++++++++++++++++++ apps/essimporter/importacdt.hpp | 25 +++ apps/essimporter/importcellref.cpp | 28 +++ apps/essimporter/importcellref.hpp | 33 +++ apps/essimporter/importcrec.cpp | 13 ++ apps/essimporter/importcrec.hpp | 22 ++ apps/essimporter/importer.cpp | 306 +++++++++++++++++++++++++++ apps/essimporter/importer.hpp | 25 +++ apps/essimporter/importercontext.cpp | 0 apps/essimporter/importercontext.hpp | 65 ++++++ apps/essimporter/importnpcc.cpp | 18 ++ apps/essimporter/importnpcc.hpp | 29 +++ apps/essimporter/importplayer.cpp | 59 ++++++ apps/essimporter/importplayer.hpp | 58 +++++ apps/essimporter/main.cpp | 60 ++++++ components/esm/esmreader.hpp | 1 + components/esm/loadcell.cpp | 5 + components/esm/loadnpcc.hpp | 29 +-- components/esm/loadscpt.cpp | 26 +++ components/esm/loadtes3.cpp | 19 ++ components/esm/loadtes3.hpp | 14 ++ 24 files changed, 1161 insertions(+), 12 deletions(-) create mode 100644 apps/essimporter/CMakeLists.txt create mode 100644 apps/essimporter/converter.cpp create mode 100644 apps/essimporter/converter.hpp create mode 100644 apps/essimporter/importacdt.hpp create mode 100644 apps/essimporter/importcellref.cpp create mode 100644 apps/essimporter/importcellref.hpp create mode 100644 apps/essimporter/importcrec.cpp create mode 100644 apps/essimporter/importcrec.hpp create mode 100644 apps/essimporter/importer.cpp create mode 100644 apps/essimporter/importer.hpp create mode 100644 apps/essimporter/importercontext.cpp create mode 100644 apps/essimporter/importercontext.hpp create mode 100644 apps/essimporter/importnpcc.cpp create mode 100644 apps/essimporter/importnpcc.hpp create mode 100644 apps/essimporter/importplayer.cpp create mode 100644 apps/essimporter/importplayer.hpp create mode 100644 apps/essimporter/main.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 0bbce7ad4..6e971b8fb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -58,6 +58,7 @@ option(BUILD_BSATOOL "build BSA extractor" ON) option(BUILD_ESMTOOL "build ESM inspector" ON) option(BUILD_LAUNCHER "build Launcher" ON) option(BUILD_MWINIIMPORTER "build MWiniImporter" ON) +option(BUILD_ESSIMPORTER "build ESS (Morrowind save game) importer" ON) option(BUILD_OPENCS "build OpenMW Construction Set" ON) option(BUILD_WIZARD "build Installation Wizard" ON) option(BUILD_WITH_CODE_COVERAGE "Enable code coverage with gconv" OFF) @@ -414,6 +415,9 @@ IF(NOT WIN32 AND NOT APPLE) IF(BUILD_MWINIIMPORTER) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/mwiniimport" DESTINATION "${BINDIR}" ) ENDIF(BUILD_MWINIIMPORTER) + IF(BUILD_ESSIMPORTER) + INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/openmw-essimporter" DESTINATION "${BINDIR}" ) + ENDIF(BUILD_ESSIMPORTER) IF(BUILD_OPENCS) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/opencs" DESTINATION "${BINDIR}" ) ENDIF(BUILD_OPENCS) @@ -472,6 +476,9 @@ if(WIN32) IF(BUILD_MWINIIMPORTER) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/mwiniimport.exe" DESTINATION ".") ENDIF(BUILD_MWINIIMPORTER) + IF(BUILD_ESSIMPORTER) + INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/openmw-essimporter.exe" DESTINATION ".") + ENDIF(BUILD_ESSIMPORTER) IF(BUILD_OPENCS) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/opencs.exe" DESTINATION ".") INSTALL(FILES "${OpenMW_BINARY_DIR}/opencs.ini" DESTINATION ".") @@ -582,6 +589,10 @@ if (BUILD_MWINIIMPORTER) add_subdirectory( apps/mwiniimporter ) endif() +if (BUILD_ESSIMPORTER) + add_subdirectory (apps/essimporter ) +endif() + if (BUILD_OPENCS) add_subdirectory (apps/opencs) endif() diff --git a/apps/essimporter/CMakeLists.txt b/apps/essimporter/CMakeLists.txt new file mode 100644 index 000000000..231e31fd8 --- /dev/null +++ b/apps/essimporter/CMakeLists.txt @@ -0,0 +1,25 @@ +set(ESSIMPORTER_FILES + main.cpp + importer.cpp + importplayer.cpp + importnpcc.cpp + importcrec.cpp + importcellref.cpp + importacdt.hpp + importercontext.cpp + converter.cpp +) + +add_executable(openmw-essimporter + ${ESSIMPORTER_FILES} +) + +target_link_libraries(openmw-essimporter + ${Boost_LIBRARIES} + components +) + +if (BUILD_WITH_CODE_COVERAGE) + add_definitions (--coverage) + target_link_libraries(openmw-essimporter gcov) +endif() diff --git a/apps/essimporter/converter.cpp b/apps/essimporter/converter.cpp new file mode 100644 index 000000000..4f36f13ee --- /dev/null +++ b/apps/essimporter/converter.cpp @@ -0,0 +1,40 @@ +#include "converter.hpp" + +#include + +namespace +{ + + void convertImage(char* data, int size, int width, int height, Ogre::PixelFormat pf, const std::string& out) + { + Ogre::Image screenshot; + Ogre::DataStreamPtr stream (new Ogre::MemoryDataStream(data, size)); + screenshot.loadRawData(stream, width, height, 1, pf); + screenshot.save(out); + } + +} + +namespace ESSImport +{ + + + struct MAPH + { + unsigned int size; + unsigned int value; + }; + + void ConvertFMAP::read(ESM::ESMReader &esm) + { + MAPH maph; + esm.getHNT(maph, "MAPH"); + std::vector data; + esm.getSubNameIs("MAPD"); + esm.getSubHeader(); + data.resize(esm.getSubSize()); + esm.getExact(&data[0], data.size()); + convertImage(&data[0], data.size(), maph.size, maph.size, Ogre::PF_BYTE_RGB, "map.tga"); + } + +} diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp new file mode 100644 index 000000000..2662f8c75 --- /dev/null +++ b/apps/essimporter/converter.hpp @@ -0,0 +1,262 @@ +#ifndef OPENMW_ESSIMPORT_CONVERTER_H +#define OPENMW_ESSIMPORT_CONVERTER_H + +#include +#include + +#include +#include +#include +#include +#include "importcrec.hpp" + +#include "importercontext.hpp" +#include "importcellref.hpp" + +namespace ESSImport +{ + +class Converter +{ +public: + /// @return the order for writing this converter's records to the output file, in relation to other converters + virtual int getStage() { return 1; } + + virtual ~Converter() {} + + void setContext(Context& context) { mContext = &context; } + + virtual void read(ESM::ESMReader& esm) + { + } + + /// Called after the input file has been read in completely, which may be necessary + /// if the conversion process relies on information in other records + virtual void write(ESM::ESMWriter& esm) + { + + } + +protected: + Context* mContext; +}; + +/// Default converter: simply reads the record and writes it unmodified to the output +template +class DefaultConverter : public Converter +{ +public: + virtual int getStage() { return 0; } + + virtual void read(ESM::ESMReader& esm) + { + std::string id = esm.getHNString("NAME"); + T record; + record.load(esm); + mRecords[id] = record; + } + + virtual void write(ESM::ESMWriter& esm) + { + for (typename std::map::const_iterator it = mRecords.begin(); it != mRecords.end(); ++it) + { + esm.startRecord(T::sRecordId); + esm.writeHNString("NAME", it->first); + it->second.save(esm); + esm.endRecord(T::sRecordId); + } + } + +protected: + std::map mRecords; +}; + +class ConvertNPC : public Converter +{ +public: + virtual void read(ESM::ESMReader &esm) + { + // this is always the player + ESM::NPC npc; + std::string id = esm.getHNString("NAME"); + assert (id == "player"); + npc.load(esm); + mContext->mPlayer.mObject.mCreatureStats.mLevel = npc.mNpdt52.mLevel; + mContext->mPlayerBase = npc; + std::map empty; + for (std::vector::const_iterator it = npc.mSpells.mList.begin(); it != npc.mSpells.mList.end(); ++it) + mContext->mPlayer.mObject.mCreatureStats.mSpells.mSpells[*it] = empty; + } +}; + +class ConvertGlobal : public DefaultConverter +{ +public: + virtual void read(ESM::ESMReader &esm) + { + std::string id = esm.getHNString("NAME"); + ESM::Global global; + global.load(esm); + if (Misc::StringUtils::ciEqual(id, "gamehour")) + mContext->mHour = global.mValue.getFloat(); + if (Misc::StringUtils::ciEqual(id, "day")) + mContext->mDay = global.mValue.getInteger(); + if (Misc::StringUtils::ciEqual(id, "month")) + mContext->mMonth = global.mValue.getInteger(); + if (Misc::StringUtils::ciEqual(id, "year")) + mContext->mYear = global.mValue.getInteger(); + mRecords[id] = global; + } +}; + +class ConvertClass : public DefaultConverter +{ +public: + virtual void read(ESM::ESMReader &esm) + { + std::string id = esm.getHNString("NAME"); + ESM::Class class_; + class_.load(esm); + + if (id == "NEWCLASSID_CHARGEN") + mContext->mCustomPlayerClassName = class_.mName; + + mRecords[id] = class_; + } +}; + +class ConvertBook : public DefaultConverter +{ +public: + virtual void read(ESM::ESMReader &esm) + { + std::string id = esm.getHNString("NAME"); + ESM::Book book; + book.load(esm); + if (book.mData.mSkillID == -1) + mContext->mPlayer.mObject.mNpcStats.mUsedIds.push_back(Misc::StringUtils::lowerCase(id)); + + mRecords[id] = book; + } +}; + +class ConvertNPCC : public Converter +{ +public: + virtual void read(ESM::ESMReader &esm) + { + std::string id = esm.getHNString("NAME"); + NPCC npcc; + npcc.load(esm); + if (id == "PlayerSaveGame") + { + mContext->mPlayer.mObject.mNpcStats.mReputation = npcc.mNPDT.mReputation; + } + } +}; + +class ConvertREFR : public Converter +{ +public: + virtual void read(ESM::ESMReader &esm) + { + REFR refr; + refr.load(esm); + assert(refr.mRefID == "PlayerSaveGame"); + mContext->mPlayer.mObject.mPosition = refr.mPos; + + ESM::CreatureStats& cStats = mContext->mPlayer.mObject.mCreatureStats; + for (int i=0; i<3; ++i) + { + int writeIndex = translateDynamicIndex(i); + cStats.mDynamic[writeIndex].mBase = refr.mACDT.mDynamic[i][1]; + cStats.mDynamic[writeIndex].mMod = refr.mACDT.mDynamic[i][1]; + cStats.mDynamic[writeIndex].mCurrent = refr.mACDT.mDynamic[i][0]; + } + for (int i=0; i<8; ++i) + { + cStats.mAttributes[i].mBase = refr.mACDT.mAttributes[i][1]; + cStats.mAttributes[i].mMod = refr.mACDT.mAttributes[i][0]; + cStats.mAttributes[i].mCurrent = refr.mACDT.mAttributes[i][0]; + } + ESM::NpcStats& npcStats = mContext->mPlayer.mObject.mNpcStats; + for (int i=0; imPlayer.mBirthsign = pcdt.mBirthsign; + mContext->mPlayer.mObject.mNpcStats.mBounty = pcdt.mBounty; + for (std::vector::const_iterator it = pcdt.mFactions.begin(); it != pcdt.mFactions.end(); ++it) + { + ESM::NpcStats::Faction faction; + faction.mExpelled = it->mFlags & 0x2; + faction.mRank = it->mRank; + faction.mReputation = it->mReputation; + mContext->mPlayer.mObject.mNpcStats.mFactions[it->mFactionName.toString()] = faction; + } + + } +}; + +class ConvertCREC : public Converter +{ +public: + virtual void read(ESM::ESMReader &esm) + { + std::string id = esm.getHNString("NAME"); + CREC crec; + crec.load(esm); + } +}; + +class ConvertFMAP : public Converter +{ +public: + virtual void read(ESM::ESMReader &esm); +}; + +class ConvertCell : public Converter +{ +public: + virtual void read(ESM::ESMReader& esm) + { + ESM::Cell cell; + std::string id = esm.getHNString("NAME"); + cell.load(esm, false); + CellRef ref; + while (esm.hasMoreSubs()) + { + ref.load (esm); + if (esm.isNextSub("DELE")) + std::cout << "deleted ref " << ref.mIndexedRefId << std::endl; + } + } + +}; + +} + +#endif diff --git a/apps/essimporter/importacdt.hpp b/apps/essimporter/importacdt.hpp new file mode 100644 index 000000000..1d79f899e --- /dev/null +++ b/apps/essimporter/importacdt.hpp @@ -0,0 +1,25 @@ +#ifndef OPENMW_ESSIMPORT_ACDT_H +#define OPENMW_ESSIMPORT_ACDT_H + +namespace ESSImport +{ + + /// Actor data, shared by (at least) REFR and CellRef + struct ACDT + { + unsigned char mUnknown1[40]; + float mDynamic[3][2]; + unsigned char mUnknown2[16]; + float mAttributes[8][2]; + unsigned char mUnknown3[120]; + }; + + /// Unknown, shared by (at least) REFR and CellRef + struct ACSC + { + unsigned char unknown[112]; + }; + +} + +#endif diff --git a/apps/essimporter/importcellref.cpp b/apps/essimporter/importcellref.cpp new file mode 100644 index 000000000..f59358d8b --- /dev/null +++ b/apps/essimporter/importcellref.cpp @@ -0,0 +1,28 @@ +#include "importcellref.hpp" + +#include + +namespace ESSImport +{ + + void CellRef::load(ESM::ESMReader &esm) + { + esm.getHNT(mRefNum.mIndex, "FRMR"); // TODO: adjust RefNum + + mIndexedRefId = esm.getHNString("NAME"); + + esm.getHNT(mACDT, "ACDT"); + + ACSC acsc; + esm.getHNOT(acsc, "ACSC"); + esm.getHNOT(acsc, "ACSL"); + + if (esm.isNextSub("CRED")) + esm.skipHSub(); + + if (esm.isNextSub("ND3D")) + esm.skipHSub(); + esm.getHNOT(mPos, "DATA", 24); + } + +} diff --git a/apps/essimporter/importcellref.hpp b/apps/essimporter/importcellref.hpp new file mode 100644 index 000000000..f06278ba5 --- /dev/null +++ b/apps/essimporter/importcellref.hpp @@ -0,0 +1,33 @@ +#ifndef OPENMW_ESSIMPORT_CELLREF_H +#define OPENMW_ESSIMPORT_CELLREF_H + +#include + +#include + +#include "importacdt.hpp" + +namespace ESM +{ + class ESMReader; +} + +namespace ESSImport +{ + + // Not sure if we can share any code with ESM::CellRef here + struct CellRef + { + std::string mIndexedRefId; + ESM::RefNum mRefNum; + + ACDT mACDT; + + ESM::Position mPos; + + void load(ESM::ESMReader& esm); + }; + +} + +#endif diff --git a/apps/essimporter/importcrec.cpp b/apps/essimporter/importcrec.cpp new file mode 100644 index 000000000..c770b2386 --- /dev/null +++ b/apps/essimporter/importcrec.cpp @@ -0,0 +1,13 @@ +#include "importcrec.hpp" + +#include + +namespace ESSImport +{ + + void CREC::load(ESM::ESMReader &esm) + { + esm.getHNT(mIndex, "INDX"); + } + +} diff --git a/apps/essimporter/importcrec.hpp b/apps/essimporter/importcrec.hpp new file mode 100644 index 000000000..62881c582 --- /dev/null +++ b/apps/essimporter/importcrec.hpp @@ -0,0 +1,22 @@ +#ifndef OPENMW_ESSIMPORT_CREC_H +#define OPENMW_ESSIMPORT_CREC_H + +namespace ESM +{ + class ESMReader; +} + +namespace ESSImport +{ + + /// Creature changes + struct CREC + { + int mIndex; + + void load(ESM::ESMReader& esm); + }; + +} + +#endif diff --git a/apps/essimporter/importer.cpp b/apps/essimporter/importer.cpp new file mode 100644 index 000000000..96b79e029 --- /dev/null +++ b/apps/essimporter/importer.cpp @@ -0,0 +1,306 @@ +#include "importer.hpp" + +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "importercontext.hpp" + +#include "converter.hpp" + +namespace +{ + + void writeScreenshot(const ESM::Header& fileHeader, ESM::SavedGame& out) + { + Ogre::Image screenshot; + std::vector screenshotData = fileHeader.mSCRS; // MemoryDataStream doesn't work with const data :( + Ogre::DataStreamPtr screenshotStream (new Ogre::MemoryDataStream(&screenshotData[0], screenshotData.size())); + screenshot.loadRawData(screenshotStream, 128, 128, 1, Ogre::PF_BYTE_BGRA); + Ogre::DataStreamPtr encoded = screenshot.encode("jpg"); + out.mScreenshot.resize(encoded->size()); + encoded->read(&out.mScreenshot[0], encoded->size()); + } + +} + +namespace ESSImport +{ + + Importer::Importer(const std::string &essfile, const std::string &outfile) + : mEssFile(essfile) + , mOutFile(outfile) + { + + } + + struct File + { + struct Subrecord + { + std::string mName; + size_t mFileOffset; + std::vector mData; + }; + + struct Record + { + std::string mName; + size_t mFileOffset; + std::vector mSubrecords; + }; + + std::vector mRecords; + }; + + void read(const std::string& filename, File& file) + { + ESM::ESMReader esm; + esm.open(filename); + + while (esm.hasMoreRecs()) + { + ESM::NAME n = esm.getRecName(); + esm.getRecHeader(); + + File::Record rec; + rec.mName = n.toString(); + rec.mFileOffset = esm.getFileOffset(); + while (esm.hasMoreSubs()) + { + File::Subrecord sub; + esm.getSubName(); + esm.getSubHeader(); + sub.mFileOffset = esm.getFileOffset(); + sub.mName = esm.retSubName().toString(); + sub.mData.resize(esm.getSubSize()); + esm.getExact(&sub.mData[0], sub.mData.size()); + rec.mSubrecords.push_back(sub); + } + file.mRecords.push_back(rec); + } + } + + void Importer::compare() + { + // data that always changes should be blacklisted + std::set > blacklist; + blacklist.insert(std::make_pair("GLOB", "FLTV")); // gamehour + blacklist.insert(std::make_pair("REFR", "DATA")); // player position + + File file1; + read(mEssFile, file1); + File file2; + read(mOutFile, file2); // todo rename variable + + for (unsigned int i=0; i= file2.mRecords.size()) + { + std::cout << "Record in file1 not present in file2: (1) 0x" << std::hex << rec.mFileOffset; + return; + } + + File::Record rec2 = file2.mRecords[i]; + + if (rec.mName != rec2.mName) + { + std::cout << "Different record name at (2) 0x" << std::hex << rec2.mFileOffset << std::endl; + return; // TODO: try to recover + } + + // FIXME: use max(size1, size2) + for (unsigned int j=0; j= rec2.mSubrecords.size()) + { + std::cout << "Subrecord in file1 not present in file2: (1) 0x" << std::hex << sub.mFileOffset; + return; + } + + File::Subrecord sub2 = rec2.mSubrecords[j]; + + if (sub.mName != sub2.mName) + { + std::cout << "Different subrecord name (" << rec.mName << "." << sub.mName << " vs. " << sub2.mName << ") at (1) 0x" << std::hex << sub.mFileOffset + << " (2) 0x" << sub2.mFileOffset << std::endl; + return; // TODO: try to recover + } + + if (sub.mData != sub2.mData) + { + if (blacklist.find(std::make_pair(rec.mName, sub.mName)) != blacklist.end()) + continue; + + std::cout << "Different subrecord data for " << rec.mName << "." << sub.mName << " at (1) 0x" << std::hex << sub.mFileOffset + << " (2) 0x" << sub2.mFileOffset << std::endl; + + std::cout << "Data 1:" << std::endl; + for (unsigned int k=0; k globals; + + const unsigned int recREFR = ESM::FourCC<'R','E','F','R'>::value; + const unsigned int recPCDT = ESM::FourCC<'P','C','D','T'>::value; + const unsigned int recFMAP = ESM::FourCC<'F','M','A','P'>::value; + + std::map > converters; + converters[ESM::REC_GLOB] = boost::shared_ptr(new ConvertGlobal()); + converters[ESM::REC_BOOK] = boost::shared_ptr(new ConvertBook()); + converters[ESM::REC_NPC_] = boost::shared_ptr(new ConvertNPC()); + converters[ESM::REC_NPCC] = boost::shared_ptr(new ConvertNPCC()); + converters[ESM::REC_CREC] = boost::shared_ptr(new ConvertCREC()); + converters[recREFR] = boost::shared_ptr(new ConvertREFR()); + converters[recPCDT] = boost::shared_ptr(new ConvertPCDT()); + converters[recFMAP] = boost::shared_ptr(new ConvertFMAP()); + converters[ESM::REC_CELL] = boost::shared_ptr(new ConvertCell()); + converters[ESM::REC_ALCH] = boost::shared_ptr(new DefaultConverter()); + converters[ESM::REC_CLAS] = boost::shared_ptr(new ConvertClass()); + converters[ESM::REC_SPEL] = boost::shared_ptr(new DefaultConverter()); + converters[ESM::REC_ARMO] = boost::shared_ptr(new DefaultConverter()); + converters[ESM::REC_WEAP] = boost::shared_ptr(new DefaultConverter()); + converters[ESM::REC_CLOT] = boost::shared_ptr(new DefaultConverter()); + converters[ESM::REC_ENCH] = boost::shared_ptr(new DefaultConverter()); + converters[ESM::REC_WEAP] = boost::shared_ptr(new DefaultConverter()); + converters[ESM::REC_LEVC] = boost::shared_ptr(new DefaultConverter()); + converters[ESM::REC_LEVI] = boost::shared_ptr(new DefaultConverter()); + + + for (std::map >::const_iterator it = converters.begin(); + it != converters.end(); ++it) + { + it->second->setContext(context); + } + + while (esm.hasMoreRecs()) + { + ESM::NAME n = esm.getRecName(); + esm.getRecHeader(); + + std::map >::iterator it = converters.find(n.val); + if (it != converters.end()) + { + it->second->read(esm); + } + else + { + std::cerr << "unknown record " << n.toString() << std::endl; + esm.skipRecord(); + } + } + + const ESM::Header& header = esm.getHeader(); + + ESM::ESMWriter writer; + + writer.setFormat (ESM::Header::CurrentFormat); + + std::ofstream stream(mOutFile.c_str(), std::ios::binary); + // all unused + writer.setVersion(0); + writer.setType(0); + writer.setAuthor(""); + writer.setDescription(""); + writer.setRecordCount (0); + writer.save (stream); + + ESM::SavedGame profile; + for (std::vector::const_iterator it = header.mMaster.begin(); + it != header.mMaster.end(); ++it) + { + profile.mContentFiles.push_back(it->name); + } + profile.mDescription = esm.getDesc(); + profile.mInGameTime.mDay = context.mDay; + profile.mInGameTime.mGameHour = context.mHour; + profile.mInGameTime.mMonth = context.mMonth; + profile.mInGameTime.mYear = context.mYear; + profile.mPlayerCell = header.mGameData.mCurrentCell.toString(); + if (context.mPlayerBase.mClass == "NEWCLASSID_CHARGEN") + profile.mPlayerClassName = context.mCustomPlayerClassName; + else + profile.mPlayerClassId = context.mPlayerBase.mClass; + profile.mPlayerLevel = context.mPlayerBase.mNpdt52.mLevel; + profile.mPlayerName = header.mGameData.mPlayerName.toString(); + + writeScreenshot(header, profile); + + writer.startRecord (ESM::REC_SAVE); + profile.save (writer); + writer.endRecord (ESM::REC_SAVE); + + // Writing order should be Dynamic Store -> Cells -> Player, + // so that references to dynamic records can be recognized when loading + for (std::map >::const_iterator it = converters.begin(); + it != converters.end(); ++it) + { + if (it->second->getStage() != 0) + continue; + it->second->write(writer); + } + + writer.startRecord(ESM::REC_NPC_); + writer.writeHNString("NAME", "player"); + context.mPlayerBase.save(writer); + writer.endRecord(ESM::REC_NPC_); + + for (std::map >::const_iterator it = converters.begin(); + it != converters.end(); ++it) + { + if (it->second->getStage() != 1) + continue; + it->second->write(writer); + } + + writer.startRecord(ESM::REC_PLAY); + context.mPlayer.save(writer); + writer.endRecord(ESM::REC_PLAY); + } + + +} diff --git a/apps/essimporter/importer.hpp b/apps/essimporter/importer.hpp new file mode 100644 index 000000000..eb199b6df --- /dev/null +++ b/apps/essimporter/importer.hpp @@ -0,0 +1,25 @@ +#ifndef OPENMW_ESSIMPORTER_IMPORTER_H +#define OPENMW_ESSIMPORTER_IMPORTER_H + +#include + +namespace ESSImport +{ + + class Importer + { + public: + Importer(const std::string& essfile, const std::string& outfile); + + void run(); + + void compare(); + + private: + std::string mEssFile; + std::string mOutFile; + }; + +} + +#endif diff --git a/apps/essimporter/importercontext.cpp b/apps/essimporter/importercontext.cpp new file mode 100644 index 000000000..e69de29bb diff --git a/apps/essimporter/importercontext.hpp b/apps/essimporter/importercontext.hpp new file mode 100644 index 000000000..e9af77678 --- /dev/null +++ b/apps/essimporter/importercontext.hpp @@ -0,0 +1,65 @@ +#ifndef OPENMW_ESSIMPORT_CONTEXT_H +#define OPENMW_ESSIMPORT_CONTEXT_H + +#include + +#include "importnpcc.hpp" +#include "importplayer.hpp" + +#include + +namespace ESSImport +{ + + struct Context + { + ESM::Player mPlayer; + ESM::NPC mPlayerBase; + std::string mCustomPlayerClassName; + + int mDay, mMonth, mYear; + float mHour; + + Context() + { + mPlayer.mAutoMove = 0; + ESM::CellId playerCellId; + playerCellId.mPaged = true; + playerCellId.mIndex.mX = playerCellId.mIndex.mY = 0; + mPlayer.mCellId = playerCellId; + //mPlayer.mLastKnownExteriorPosition + mPlayer.mHasMark = 0; // TODO + mPlayer.mCurrentCrimeId = 0; // TODO + mPlayer.mObject.mCount = 1; + mPlayer.mObject.mEnabled = 1; + mPlayer.mObject.mHasLocals = false; + mPlayer.mObject.mRef.mRefID = "player"; // REFR.mRefID would be PlayerSaveGame + mPlayer.mObject.mCreatureStats.mHasAiSettings = true; + mPlayer.mObject.mCreatureStats.mDead = false; + mPlayer.mObject.mCreatureStats.mDied = false; + mPlayer.mObject.mCreatureStats.mKnockdown = false; + mPlayer.mObject.mCreatureStats.mKnockdownOneFrame = false; + mPlayer.mObject.mCreatureStats.mKnockdownOverOneFrame = false; + mPlayer.mObject.mCreatureStats.mHitRecovery = false; + mPlayer.mObject.mCreatureStats.mBlock = false; + mPlayer.mObject.mCreatureStats.mMovementFlags = 0; + mPlayer.mObject.mCreatureStats.mAttackStrength = 0.f; + mPlayer.mObject.mCreatureStats.mFallHeight = 0.f; + mPlayer.mObject.mCreatureStats.mRecalcDynamicStats = false; + mPlayer.mObject.mCreatureStats.mDrawState = 0; + mPlayer.mObject.mCreatureStats.mDeathAnimation = 0; + mPlayer.mObject.mNpcStats.mIsWerewolf = false; + mPlayer.mObject.mNpcStats.mTimeToStartDrowning = 20; + mPlayer.mObject.mNpcStats.mLevelProgress = 0; + mPlayer.mObject.mNpcStats.mDisposition = 0; + mPlayer.mObject.mNpcStats.mTimeToStartDrowning = 20; + mPlayer.mObject.mNpcStats.mReputation = 0; + mPlayer.mObject.mNpcStats.mCrimeId = -1; + mPlayer.mObject.mNpcStats.mWerewolfKills = 0; + mPlayer.mObject.mNpcStats.mProfit = 0; + } + }; + +} + +#endif diff --git a/apps/essimporter/importnpcc.cpp b/apps/essimporter/importnpcc.cpp new file mode 100644 index 000000000..192fe5da4 --- /dev/null +++ b/apps/essimporter/importnpcc.cpp @@ -0,0 +1,18 @@ +#include "importnpcc.hpp" + +#include + +namespace ESSImport +{ + + void NPCC::load(ESM::ESMReader &esm) + { + esm.getHNT(mNPDT, "NPDT"); + + // container: + // XIDX + // XHLT - condition + // WIDX - equipping? + } + +} diff --git a/apps/essimporter/importnpcc.hpp b/apps/essimporter/importnpcc.hpp new file mode 100644 index 000000000..12135850f --- /dev/null +++ b/apps/essimporter/importnpcc.hpp @@ -0,0 +1,29 @@ +#ifndef OPENMW_ESSIMPORT_NPCC_H +#define OPENMW_ESSIMPORT_NPCC_H + +#include +#include + +namespace ESM +{ + class ESMReader; +} + +namespace ESSImport +{ + + struct NPCC : public ESM::NPC + { + struct NPDT + { + unsigned char unknown[2]; + unsigned char mReputation; + unsigned char unknown2[5]; + } mNPDT; + + void load(ESM::ESMReader &esm); + }; + +} + +#endif diff --git a/apps/essimporter/importplayer.cpp b/apps/essimporter/importplayer.cpp new file mode 100644 index 000000000..81f81e764 --- /dev/null +++ b/apps/essimporter/importplayer.cpp @@ -0,0 +1,59 @@ +#include "importplayer.hpp" + +#include + +namespace ESSImport +{ + + void REFR::load(ESM::ESMReader &esm) + { + esm.getHNT(mRefNum.mIndex, "FRMR"); + + mRefID = esm.getHNString("NAME"); + + if (esm.isNextSub("STPR")) + esm.skipHSub(); // ESS TODO + + esm.getHNT(mACDT, "ACDT"); + + ACSC acsc; + esm.getHNOT(acsc, "ACSC"); + esm.getHNOT(acsc, "ACSL"); + + esm.getHNExact(mSkills, 27*2*sizeof(int), "CHRD"); + + if (esm.isNextSub("ND3D")) + esm.skipHSub(); // ESS TODO (1 byte) + + esm.getHNOT(mPos, "DATA", 24); + } + + void PCDT::load(ESM::ESMReader &esm) + { + if (esm.isNextSub("PNAM")) + esm.skipHSub(); + if (esm.isNextSub("SNAM")) + esm.skipHSub(); + if (esm.isNextSub("NAM9")) + esm.skipHSub(); + + mBounty = 0; + esm.getHNOT(mBounty, "CNAM"); + + mBirthsign = esm.getHNOString("BNAM"); + + if (esm.isNextSub("ENAM")) + esm.skipHSub(); + + while (esm.isNextSub("FNAM")) + { + FNAM fnam; + esm.getHT(fnam); + mFactions.push_back(fnam); + } + + if (esm.isNextSub("KNAM")) + esm.skipHSub(); + } + +} diff --git a/apps/essimporter/importplayer.hpp b/apps/essimporter/importplayer.hpp new file mode 100644 index 000000000..8a0a087a5 --- /dev/null +++ b/apps/essimporter/importplayer.hpp @@ -0,0 +1,58 @@ +#ifndef OPENMW_ESSIMPORT_PLAYER_H +#define OPENMW_ESSIMPORT_PLAYER_H + +#include +#include + +#include +#include +#include + +#include "importacdt.hpp" + +namespace ESM +{ + class ESMReader; +} + +namespace ESSImport +{ + +/// Player-agnostic player data +struct REFR +{ + ACDT mACDT; + + std::string mRefID; + ESM::Position mPos; + ESM::RefNum mRefNum; + + int mSkills[27][2]; + float mAttributes[8][2]; + + void load(ESM::ESMReader& esm); +}; + +/// Other player data +struct PCDT +{ + int mBounty; + std::string mBirthsign; + + struct FNAM + { + unsigned char mRank; + unsigned char mUnknown1[3]; + int mReputation; + unsigned char mFlags; // 0x1: unknown, 0x2: expelled + unsigned char mUnknown2[3]; + ESM::NAME32 mFactionName; + }; + std::vector mFactions; + + void load(ESM::ESMReader& esm); +}; + +} + +#endif diff --git a/apps/essimporter/main.cpp b/apps/essimporter/main.cpp new file mode 100644 index 000000000..0e5c65e95 --- /dev/null +++ b/apps/essimporter/main.cpp @@ -0,0 +1,60 @@ +#include +#include +#include +#include + +#include "importer.hpp" + +namespace bpo = boost::program_options; +namespace bfs = boost::filesystem; + + + +int main(int argc, const char** argv) +{ + try + { + bpo::options_description desc("Syntax: openmw-essimporter infile.ess outfile.omwsave\nAllowed options"); + bpo::positional_options_description p_desc; + desc.add_options() + ("help,h", "produce help message") + ("mwsave,m", bpo::value(), "morrowind .ess save file") + ("output,o", bpo::value(), "output file (.omwsave)") + ("compare,c", "compare two .ess files") + ; + p_desc.add("mwsave", 1).add("output", 1); + + bpo::variables_map vm; + + bpo::parsed_options parsed = bpo::command_line_parser(argc, argv) + .options(desc) + .positional(p_desc) + .run(); + + bpo::store(parsed, vm); + + if(vm.count("help") || !vm.count("mwsave") || !vm.count("output")) { + std::cout << desc; + return 0; + } + + bpo::notify(vm); + + std::string essFile = vm["mwsave"].as(); + std::string outputFile = vm["output"].as(); + + ESSImport::Importer importer(essFile, outputFile); + + if (vm.count("compare")) + importer.compare(); + else + importer.run(); + } + catch (std::exception& e) + { + std::cerr << "Error: " << e.what() << std::endl; + return 1; + } + + return 0; +} diff --git a/components/esm/esmreader.hpp b/components/esm/esmreader.hpp index 1549e15f5..642ec4168 100644 --- a/components/esm/esmreader.hpp +++ b/components/esm/esmreader.hpp @@ -36,6 +36,7 @@ public: const std::string getAuthor() const { return mHeader.mData.author.toString(); } const std::string getDesc() const { return mHeader.mData.desc.toString(); } const std::vector &getGameFiles() const { return mHeader.mMaster; } + const Header& getHeader() const { return mHeader; } int getFormat() const; const NAME &retSubName() const { return mCtx.subName; } uint32_t getSubSize() const { return mCtx.leftSub; } diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index e4f847dec..f6649d94a 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -111,6 +111,11 @@ void Cell::loadData(ESMReader &esm) } esm.getHNT(mData, "DATA", 12); + + // ess only, unknown + char nam8[32]; + if (esm.isNextSub("NAM8")) + esm.getHExact(nam8, 32); } void Cell::postLoad(ESMReader &esm) diff --git a/components/esm/loadnpcc.hpp b/components/esm/loadnpcc.hpp index c87c2545f..6c087fd01 100644 --- a/components/esm/loadnpcc.hpp +++ b/components/esm/loadnpcc.hpp @@ -17,26 +17,29 @@ class ESMWriter; * * Some general observations about savegames: * - * Magical items/potions/spells/etc are added normally as new ALCH, - * SPEL, etc. records, with unique numeric identifiers. - * - * Books with ability enhancements are listed in the save if they have - * been read. - * - * GLOB records set global variables. - * * SCPT records do not define new scripts, but assign values to the * variables of existing ones. * * STLN - stolen items, ONAM is the owner * - * GAME - contains a GMDT (game data) of unknown format - * - * VFXM, SPLM, KLST - no clue + * GAME - weather data + * struct GMDT + { + char mCellName[64]; + int mFogColour; + float mFogDensity; + int mCurrentWeather, mNextWeather; + int mWeatherTransition; // 0-100 transition between weathers, top 3 bytes may be garbage + float mTimeOfNextTransition; // weather changes when gamehour == timeOfNextTransition + int masserPhase, secundaPhase; // top 3 bytes may be garbage + }; + * + * VFXM, SPLM - no clue + * KLST - kill counter * * PCDT - seems to contain a lot of DNAMs, strings? * - * FMAP - MAPH and MAPD, probably map data. + * FMAP - MAPH and MAPD, global map image. * * JOUR - the entire journal in html * @@ -44,6 +47,8 @@ class ESMWriter; * ones you have done or begun. * * REGN - lists all regions in the game, even unvisited ones. + * notable differences to Regions in ESM files: mMapColor may be missing, and includes an unknown WNAM subrecord. + * * * The DIAL/INFO blocks contain changes to characters' dialog status. * diff --git a/components/esm/loadscpt.cpp b/components/esm/loadscpt.cpp index 07561c2ea..f2f13d086 100644 --- a/components/esm/loadscpt.cpp +++ b/components/esm/loadscpt.cpp @@ -92,6 +92,32 @@ void Script::load(ESMReader &esm) if (esm.isNextSub("SCVR")) { esm.skipHSub(); } + + // ESS only, TODO: move + if (esm.isNextSub("SLCS")) + { + esm.getSubHeader(); + char unknown[12]; + esm.getExact(unknown, 12); + } + if (esm.isNextSub("SLSD")) + { + float read; + esm.getSubHeader(); + // values of variables? + for (int i=0; i mSCRD; // Used in .ess savegames only, screenshot? + std::vector mSCRS; // Used in .ess savegames only, screenshot? + Data mData; int mFormat; std::vector mMaster; From cbf56dbb4750822650dfc5335e78cc577a596c31 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 17 Jan 2015 03:07:24 +0100 Subject: [PATCH 0330/3725] ESSImport: work on cell fog of war --- apps/essimporter/converter.cpp | 50 ++++++++++++++++++++++++++++++++++ apps/essimporter/converter.hpp | 35 ++++++++++++++++++------ apps/essimporter/importer.cpp | 6 ++-- components/esm/loadcell.cpp | 5 ---- 4 files changed, 79 insertions(+), 17 deletions(-) diff --git a/apps/essimporter/converter.cpp b/apps/essimporter/converter.cpp index 4f36f13ee..5f7366625 100644 --- a/apps/essimporter/converter.cpp +++ b/apps/essimporter/converter.cpp @@ -37,4 +37,54 @@ namespace ESSImport convertImage(&data[0], data.size(), maph.size, maph.size, Ogre::PF_BYTE_RGB, "map.tga"); } + void ConvertCell::read(ESM::ESMReader &esm) + { + ESM::Cell cell; + std::string id = esm.getHNString("NAME"); + cell.load(esm, false); + + Cell newcell; + newcell.mCell = cell; + + // fog of war + // seems to be a 1-bit pixel format, 16*16 pixels + // TODO: add bleeding of FOW into neighbouring cells (openmw handles this by writing to the textures, + // MW handles it when rendering only) + unsigned char nam8[32]; + if (esm.isNextSub("NAM8")) + { + esm.getHExact(nam8, 32); + + newcell.mFogOfWar.reserve(16*16); + for (int x=0; x<16; ++x) + { + for (int y=0; y<16; ++y) + { + size_t pos = x*16+y; + size_t bytepos = pos/8; + assert(bytepos<32); + int bit = pos%8; + newcell.mFogOfWar.push_back(((nam8[bytepos] >> bit) & (0x1)) ? 0xffffffff : 0x000000ff); + } + } + + std::ostringstream filename; + filename << "fog_" << cell.mData.mX << "_" << cell.mData.mY << ".tga"; + + convertImage((char*)&newcell.mFogOfWar[0], newcell.mFogOfWar.size()*4, 16, 16, Ogre::PF_BYTE_RGBA, filename.str()); + } + + std::vector cellrefs; + while (esm.hasMoreSubs()) + { + CellRef ref; + ref.load (esm); + if (esm.isNextSub("DELE")) + std::cout << "deleted ref " << ref.mIndexedRefId << std::endl; + } + + newcell.mRefs = cellrefs; + mCells[id] = newcell; + } + } diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index 2662f8c75..011508f36 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -8,6 +8,7 @@ #include #include #include +#include #include "importcrec.hpp" #include "importercontext.hpp" @@ -241,20 +242,36 @@ public: class ConvertCell : public Converter { public: - virtual void read(ESM::ESMReader& esm) + virtual void read(ESM::ESMReader& esm); + + virtual void write(ESM::ESMWriter& esm) { - ESM::Cell cell; - std::string id = esm.getHNString("NAME"); - cell.load(esm, false); - CellRef ref; - while (esm.hasMoreSubs()) + for (std::map::const_iterator it = mCells.begin(); it != mCells.end(); ++it) { - ref.load (esm); - if (esm.isNextSub("DELE")) - std::cout << "deleted ref " << ref.mIndexedRefId << std::endl; + const ESM::Cell& cell = it->second.mCell; + esm.startRecord(ESM::REC_CSTA); + ESM::CellState csta; + csta.mHasFogOfWar = 0; + csta.mId = cell.getCellId(); + csta.mId.save(esm); + // TODO csta.mLastRespawn; + // shouldn't be needed if we respawn on global schedule like in original MW + csta.mWaterLevel = cell.mWater; + csta.save(esm); + esm.endRecord(ESM::REC_CSTA); } } +private: + struct Cell + { + ESM::Cell mCell; + std::vector mRefs; + std::vector mFogOfWar; + }; + + std::map mCells; + }; } diff --git a/apps/essimporter/importer.cpp b/apps/essimporter/importer.cpp index 96b79e029..b511dfe5e 100644 --- a/apps/essimporter/importer.cpp +++ b/apps/essimporter/importer.cpp @@ -99,16 +99,18 @@ namespace ESSImport void Importer::compare() { - // data that always changes should be blacklisted + // data that always changes (and/or is already fully decoded) should be blacklisted std::set > blacklist; blacklist.insert(std::make_pair("GLOB", "FLTV")); // gamehour blacklist.insert(std::make_pair("REFR", "DATA")); // player position + blacklist.insert(std::make_pair("CELL", "NAM8")); // fog of war File file1; read(mEssFile, file1); File file2; read(mOutFile, file2); // todo rename variable + // FIXME: use max(size1, size2) for (unsigned int i=0; i globals; - const unsigned int recREFR = ESM::FourCC<'R','E','F','R'>::value; const unsigned int recPCDT = ESM::FourCC<'P','C','D','T'>::value; const unsigned int recFMAP = ESM::FourCC<'F','M','A','P'>::value; diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index f6649d94a..e4f847dec 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -111,11 +111,6 @@ void Cell::loadData(ESMReader &esm) } esm.getHNT(mData, "DATA", 12); - - // ess only, unknown - char nam8[32]; - if (esm.isNextSub("NAM8")) - esm.getHExact(nam8, 32); } void Cell::postLoad(ESMReader &esm) From b66937d6307d07823f890c5a78a6c5c567221be0 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sat, 17 Jan 2015 15:35:58 +1300 Subject: [PATCH 0331/3725] add #include Required to get build to work on my configuration. --- libs/openengine/ogre/renderer.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libs/openengine/ogre/renderer.hpp b/libs/openengine/ogre/renderer.hpp index 1b18a7b0b..33a42f8cd 100644 --- a/libs/openengine/ogre/renderer.hpp +++ b/libs/openengine/ogre/renderer.hpp @@ -6,6 +6,7 @@ */ #include +#include #include From 017e4cd4effb26b0b1a4a9c64b47c17f4d4e0633 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sat, 17 Jan 2015 18:11:03 +1300 Subject: [PATCH 0332/3725] OpenCS shows plug-ins with load order issues. 1. FileDiaog in OpenCS now shows warning icon beside .esm./.esp files with load order problems. 2. omwlaucher -> replaced "stop" icon with "warning" icon for files with load order problems. --- components/contentselector/model/contentmodel.cpp | 7 +++---- components/contentselector/model/contentmodel.hpp | 11 ++++++----- components/contentselector/view/contentselector.cpp | 4 +++- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/components/contentselector/model/contentmodel.cpp b/components/contentselector/model/contentmodel.cpp index 5760a327e..4a1a69169 100644 --- a/components/contentselector/model/contentmodel.cpp +++ b/components/contentselector/model/contentmodel.cpp @@ -6,13 +6,12 @@ #include #include #include -#include -#include #include "components/esm/esmreader.hpp" -ContentSelectorModel::ContentModel::ContentModel(QObject *parent) : +ContentSelectorModel::ContentModel::ContentModel(QObject *parent, QIcon warningIcon) : QAbstractTableModel(parent), + mWarningIcon(warningIcon), mMimeType ("application/omwcontent"), mMimeTypes (QStringList() << mMimeType), mColumnCount (1), @@ -180,7 +179,7 @@ QVariant ContentSelectorModel::ContentModel::data(const QModelIndex &index, int { case Qt::DecorationRole: { - return isLoadOrderError(file) ? QIcon::fromTheme("edit-delete") : QVariant(); + return isLoadOrderError(file) ? mWarningIcon : QVariant(); } case Qt::EditRole: diff --git a/components/contentselector/model/contentmodel.hpp b/components/contentselector/model/contentmodel.hpp index 153800dca..2ced40f04 100644 --- a/components/contentselector/model/contentmodel.hpp +++ b/components/contentselector/model/contentmodel.hpp @@ -4,7 +4,7 @@ #include #include #include - +#include #include "loadordererror.hpp" namespace ContentSelectorModel @@ -23,7 +23,7 @@ namespace ContentSelectorModel { Q_OBJECT public: - explicit ContentModel(QObject *parent = 0); + explicit ContentModel(QObject *parent, QIcon warningIcon); ~ContentModel(); void setEncoding(const QString &encoding); @@ -57,6 +57,9 @@ namespace ContentSelectorModel void refreshModel(); + /// Checks all plug-ins for load order errors and updates mPluginsWithLoadOrderError with plug-ins with issues + void checkForLoadOrderErrors(); + private: void addFile(EsmFile *file); @@ -65,9 +68,6 @@ namespace ContentSelectorModel void sortFiles(); - /// Checks all plug-ins for load order errors and updates mPluginsWithLoadOrderError with plug-ins with issues - void checkForLoadOrderErrors(); - /// Checks a specific plug-in for load order errors /// \return all errors found for specific plug-in QList checkForLoadOrderErrors(const EsmFile *file, int row) const; @@ -82,6 +82,7 @@ namespace ContentSelectorModel QSet mPluginsWithLoadOrderError; QTextCodec *mCodec; QString mEncoding; + QIcon mWarningIcon; public: diff --git a/components/contentselector/view/contentselector.cpp b/components/contentselector/view/contentselector.cpp index 770d45c86..521462d92 100644 --- a/components/contentselector/view/contentselector.cpp +++ b/components/contentselector/view/contentselector.cpp @@ -24,7 +24,8 @@ ContentSelectorView::ContentSelector::ContentSelector(QWidget *parent) : void ContentSelectorView::ContentSelector::buildContentModel() { - mContentModel = new ContentSelectorModel::ContentModel(this); + QIcon warningIcon(ui.addonView->style()->standardIcon(QStyle::SP_MessageBoxWarning).pixmap(QSize(16, 15))); + mContentModel = new ContentSelectorModel::ContentModel(this, warningIcon); } void ContentSelectorView::ContentSelector::buildGameFileView() @@ -161,6 +162,7 @@ void ContentSelectorView::ContentSelector::slotCurrentGameFileIndexChanged(int i oldIndex = index; model->setData(model->index(index, 0), true, Qt::UserRole + 1); + mContentModel->checkForLoadOrderErrors(); } if (proxy) From 71700d2cb119934122dc7fc9f8ffae725cb2fce1 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 18 Jan 2015 11:55:58 +1300 Subject: [PATCH 0333/3725] Bugfix: OpenCS segfault when plug-in dependency not found. When a file that a plug-in depends on cannot be found, the OpenCS file dialog crashes. Similar problem exists in omwlauncher's "Data Files" dialog. --- components/contentselector/model/contentmodel.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/components/contentselector/model/contentmodel.cpp b/components/contentselector/model/contentmodel.cpp index 4a1a69169..3f1feac61 100644 --- a/components/contentselector/model/contentmodel.cpp +++ b/components/contentselector/model/contentmodel.cpp @@ -597,13 +597,16 @@ QList ContentSelectorModel::ContentModel:: { errors.append(LoadOrderError(LoadOrderError::ErrorCode_MissingDependency, dependentfileName)); } - if (!isChecked(dependentFile->filePath())) - { - errors.append(LoadOrderError(LoadOrderError::ErrorCode_InactiveDependency, dependentfileName)); - } - if (row < indexFromItem(dependentFile).row()) + else { - errors.append(LoadOrderError(LoadOrderError::ErrorCode_LoadOrder, dependentfileName)); + if (!isChecked(dependentFile->filePath())) + { + errors.append(LoadOrderError(LoadOrderError::ErrorCode_InactiveDependency, dependentfileName)); + } + if (row < indexFromItem(dependentFile).row()) + { + errors.append(LoadOrderError(LoadOrderError::ErrorCode_LoadOrder, dependentfileName)); + } } } return errors; From c8ed24cc84f5112d7784d957afd1f6e745225c87 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 18 Jan 2015 16:13:52 +0100 Subject: [PATCH 0334/3725] ESSImport: creature CellRefs work, need probing to find ref type --- apps/essimporter/converter.cpp | 60 ++++++++++++++++++++++++++++ apps/essimporter/converter.hpp | 22 ++-------- apps/essimporter/importcellref.cpp | 9 +++++ apps/essimporter/importcellref.hpp | 2 + apps/essimporter/importercontext.hpp | 10 ++++- 5 files changed, 84 insertions(+), 19 deletions(-) diff --git a/apps/essimporter/converter.cpp b/apps/essimporter/converter.cpp index 5f7366625..1ad60d7ba 100644 --- a/apps/essimporter/converter.cpp +++ b/apps/essimporter/converter.cpp @@ -2,6 +2,8 @@ #include +#include + namespace { @@ -81,10 +83,68 @@ namespace ESSImport ref.load (esm); if (esm.isNextSub("DELE")) std::cout << "deleted ref " << ref.mIndexedRefId << std::endl; + cellrefs.push_back(ref); } newcell.mRefs = cellrefs; mCells[id] = newcell; } + void ConvertCell::write(ESM::ESMWriter &esm) + { + for (std::map::const_iterator it = mCells.begin(); it != mCells.end(); ++it) + { + const ESM::Cell& cell = it->second.mCell; + esm.startRecord(ESM::REC_CSTA); + ESM::CellState csta; + csta.mHasFogOfWar = 0; + csta.mId = cell.getCellId(); + csta.mId.save(esm); + // TODO csta.mLastRespawn; + // shouldn't be needed if we respawn on global schedule like in original MW + csta.mWaterLevel = cell.mWater; + csta.save(esm); + + for (std::vector::const_iterator refIt = it->second.mRefs.begin(); refIt != it->second.mRefs.end(); ++refIt) + { + const CellRef& cellref = *refIt; + ESM::CellRef out; + out.blank(); + + if (cellref.mIndexedRefId.size() < 8) + { + std::cerr << "CellRef with no index?" << std::endl; + continue; + } + std::stringstream stream; + stream << cellref.mIndexedRefId.substr(cellref.mIndexedRefId.size()-8,8); + int refIndex; + stream >> refIndex; + + out.mRefID = cellref.mIndexedRefId.substr(0,cellref.mIndexedRefId.size()-8); + + std::map, CREC>::const_iterator crecIt = mContext->mCreatureChanges.find( + std::make_pair(refIndex, out.mRefID)); + if (crecIt != mContext->mCreatureChanges.end()) + { + std::cerr << "Can't' find CREC for " << refIndex << " " << out.mRefID << std::endl; + continue; + } + + ESM::CreatureState objstate; + objstate.mCount = 1; + objstate.mEnabled = cellref.mEnabled; + objstate.mHasLocals = 0; + objstate.mLocalRotation[0] = objstate.mLocalRotation[1] = objstate.mLocalRotation[2] = 0; + objstate.mPosition = cellref.mPos; + objstate.mRef = out; + objstate.mRef.mRefNum = cellref.mRefNum; + esm.writeHNT ("OBJE", ESM::REC_CREA); + objstate.save(esm); + } + + esm.endRecord(ESM::REC_CSTA); + } + } + } diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index 011508f36..71eb3ab9f 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -153,6 +153,7 @@ public: { mContext->mPlayer.mObject.mNpcStats.mReputation = npcc.mNPDT.mReputation; } + //mContext->mNpcChanges.insert(std::make_pair(std::make_pair(npcc.mIndex,id), crec)); } }; @@ -230,6 +231,8 @@ public: std::string id = esm.getHNString("NAME"); CREC crec; crec.load(esm); + + mContext->mCreatureChanges.insert(std::make_pair(std::make_pair(crec.mIndex,id), crec)); } }; @@ -243,24 +246,7 @@ class ConvertCell : public Converter { public: virtual void read(ESM::ESMReader& esm); - - virtual void write(ESM::ESMWriter& esm) - { - for (std::map::const_iterator it = mCells.begin(); it != mCells.end(); ++it) - { - const ESM::Cell& cell = it->second.mCell; - esm.startRecord(ESM::REC_CSTA); - ESM::CellState csta; - csta.mHasFogOfWar = 0; - csta.mId = cell.getCellId(); - csta.mId.save(esm); - // TODO csta.mLastRespawn; - // shouldn't be needed if we respawn on global schedule like in original MW - csta.mWaterLevel = cell.mWater; - csta.save(esm); - esm.endRecord(ESM::REC_CSTA); - } - } + virtual void write(ESM::ESMWriter& esm); private: struct Cell diff --git a/apps/essimporter/importcellref.cpp b/apps/essimporter/importcellref.cpp index f59358d8b..51e771081 100644 --- a/apps/essimporter/importcellref.cpp +++ b/apps/essimporter/importcellref.cpp @@ -9,6 +9,11 @@ namespace ESSImport { esm.getHNT(mRefNum.mIndex, "FRMR"); // TODO: adjust RefNum + // this is required since openmw supports more than 255 content files + int pluginIndex = (mRefNum.mIndex & 0xff000000) >> 24; + mRefNum.mContentFile = pluginIndex-1; + mRefNum.mIndex &= 0x00ffffff; + mIndexedRefId = esm.getHNString("NAME"); esm.getHNT(mACDT, "ACDT"); @@ -22,6 +27,10 @@ namespace ESSImport if (esm.isNextSub("ND3D")) esm.skipHSub(); + + mEnabled = true; + esm.getHNOT(mEnabled, "ZNAM"); + esm.getHNOT(mPos, "DATA", 24); } diff --git a/apps/essimporter/importcellref.hpp b/apps/essimporter/importcellref.hpp index f06278ba5..72c5af257 100644 --- a/apps/essimporter/importcellref.hpp +++ b/apps/essimporter/importcellref.hpp @@ -25,6 +25,8 @@ namespace ESSImport ESM::Position mPos; + bool mEnabled; + void load(ESM::ESMReader& esm); }; diff --git a/apps/essimporter/importercontext.hpp b/apps/essimporter/importercontext.hpp index e9af77678..6f26e8329 100644 --- a/apps/essimporter/importercontext.hpp +++ b/apps/essimporter/importercontext.hpp @@ -1,12 +1,16 @@ #ifndef OPENMW_ESSIMPORT_CONTEXT_H #define OPENMW_ESSIMPORT_CONTEXT_H +#include + #include +#include #include "importnpcc.hpp" +#include "importcrec.hpp" #include "importplayer.hpp" -#include + namespace ESSImport { @@ -20,6 +24,10 @@ namespace ESSImport int mDay, mMonth, mYear; float mHour; + // key + std::map, CREC> mCreatureChanges; + std::map, NPCC> mNpcChanges; + Context() { mPlayer.mAutoMove = 0; From 08ad4d73bbf9873887a8c6716c37b641e2603026 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 18 Jan 2015 19:59:29 +0100 Subject: [PATCH 0335/3725] ESSImport: player is placed in correct cell, npc cellrefs work --- apps/essimporter/CMakeLists.txt | 4 ++- apps/essimporter/convertacdt.cpp | 42 ++++++++++++++++++++++ apps/essimporter/convertacdt.hpp | 22 ++++++++++++ apps/essimporter/converter.cpp | 54 +++++++++++++++++++++------- apps/essimporter/converter.hpp | 40 +++++---------------- apps/essimporter/convertnpcc.cpp | 22 ++++++++++++ apps/essimporter/convertnpcc.hpp | 15 ++++++++ apps/essimporter/importacdt.cpp | 28 +++++++++++++++ apps/essimporter/importacdt.hpp | 24 +++++++++++++ apps/essimporter/importcellref.cpp | 19 +++++----- apps/essimporter/importcellref.hpp | 4 ++- apps/essimporter/importer.cpp | 19 ++++++++-- apps/essimporter/importercontext.hpp | 30 +++------------- apps/essimporter/importnpcc.cpp | 25 ++++++++++--- apps/essimporter/importnpcc.hpp | 12 +++++-- apps/essimporter/importplayer.cpp | 14 +++----- apps/essimporter/importplayer.hpp | 5 +-- components/esm/creaturestate.cpp | 8 ++++- components/esm/creaturestate.hpp | 3 ++ components/esm/creaturestats.cpp | 36 +++++++++++++++++-- components/esm/creaturestats.hpp | 3 ++ components/esm/npcstate.cpp | 9 ++++- components/esm/npcstate.hpp | 3 ++ components/esm/npcstats.cpp | 15 ++++++++ components/esm/npcstats.hpp | 3 ++ components/esm/objectstate.cpp | 16 ++++++++- components/esm/objectstate.hpp | 5 ++- 27 files changed, 370 insertions(+), 110 deletions(-) create mode 100644 apps/essimporter/convertacdt.cpp create mode 100644 apps/essimporter/convertacdt.hpp create mode 100644 apps/essimporter/convertnpcc.cpp create mode 100644 apps/essimporter/convertnpcc.hpp create mode 100644 apps/essimporter/importacdt.cpp diff --git a/apps/essimporter/CMakeLists.txt b/apps/essimporter/CMakeLists.txt index 231e31fd8..257a466ee 100644 --- a/apps/essimporter/CMakeLists.txt +++ b/apps/essimporter/CMakeLists.txt @@ -5,9 +5,11 @@ set(ESSIMPORTER_FILES importnpcc.cpp importcrec.cpp importcellref.cpp - importacdt.hpp + importacdt.cpp importercontext.cpp converter.cpp + convertacdt.cpp + convertnpcc.cpp ) add_executable(openmw-essimporter diff --git a/apps/essimporter/convertacdt.cpp b/apps/essimporter/convertacdt.cpp new file mode 100644 index 000000000..81ab61084 --- /dev/null +++ b/apps/essimporter/convertacdt.cpp @@ -0,0 +1,42 @@ +#include "convertacdt.hpp" + +namespace ESSImport +{ + + int translateDynamicIndex(int mwIndex) + { + if (mwIndex == 1) + return 2; + else if (mwIndex == 2) + return 1; + return mwIndex; + } + + void convertACDT (const ACDT& acdt, ESM::CreatureStats& cStats) + { + for (int i=0; i<3; ++i) + { + int writeIndex = translateDynamicIndex(i); + cStats.mDynamic[writeIndex].mBase = acdt.mDynamic[i][1]; + cStats.mDynamic[writeIndex].mMod = acdt.mDynamic[i][1]; + cStats.mDynamic[writeIndex].mCurrent = acdt.mDynamic[i][0]; + } + for (int i=0; i<8; ++i) + { + cStats.mAttributes[i].mBase = acdt.mAttributes[i][1]; + cStats.mAttributes[i].mMod = acdt.mAttributes[i][0]; + cStats.mAttributes[i].mCurrent = acdt.mAttributes[i][0]; + } + } + + void convertNpcData (const ActorData& actorData, ESM::NpcStats& npcStats) + { + for (int i=0; i +#include +#include + +#include "importacdt.hpp" + +namespace ESSImport +{ + + // OpenMW uses Health,Magicka,Fatigue, MW uses Health,Fatigue,Magicka + int translateDynamicIndex(int mwIndex); + + + void convertACDT (const ACDT& acdt, ESM::CreatureStats& cStats); + + void convertNpcData (const ActorData& actorData, ESM::NpcStats& npcStats); +} + +#endif diff --git a/apps/essimporter/converter.cpp b/apps/essimporter/converter.cpp index 1ad60d7ba..2e7a954e0 100644 --- a/apps/essimporter/converter.cpp +++ b/apps/essimporter/converter.cpp @@ -43,8 +43,15 @@ namespace ESSImport { ESM::Cell cell; std::string id = esm.getHNString("NAME"); + cell.mName = id; cell.load(esm, false); + // note if the player is in a nameless exterior cell, we will assign the cellId later based on player position + if (id == mContext->mPlayerCellName) + { + mContext->mPlayer.mCellId = cell.getCellId(); + } + Cell newcell; newcell.mCell = cell; @@ -55,7 +62,12 @@ namespace ESSImport unsigned char nam8[32]; if (esm.isNextSub("NAM8")) { - esm.getHExact(nam8, 32); + esm.getSubHeader(); + // FIXME: different size in interior cells for some reason + if (esm.getSubSize() == 36) + esm.skip(4); + + esm.getExact(nam8, 32); newcell.mFogOfWar.reserve(16*16); for (int x=0; x<16; ++x) @@ -87,6 +99,8 @@ namespace ESSImport } newcell.mRefs = cellrefs; + + // FIXME: map by ID for exterior cells mCells[id] = newcell; } @@ -127,20 +141,36 @@ namespace ESSImport std::make_pair(refIndex, out.mRefID)); if (crecIt != mContext->mCreatureChanges.end()) { - std::cerr << "Can't' find CREC for " << refIndex << " " << out.mRefID << std::endl; + ESM::CreatureState objstate; + objstate.blank(); + convertACDT(cellref.mActorData.mACDT, objstate.mCreatureStats); + objstate.mEnabled = cellref.mEnabled; + objstate.mPosition = cellref.mPos; + objstate.mRef = out; + objstate.mRef.mRefNum = cellref.mRefNum; + esm.writeHNT ("OBJE", ESM::REC_CREA); + objstate.save(esm); + continue; + } + + std::map, NPCC>::const_iterator npccIt = mContext->mNpcChanges.find( + std::make_pair(refIndex, out.mRefID)); + if (npccIt != mContext->mNpcChanges.end()) + { + ESM::NpcState objstate; + objstate.blank(); + convertACDT(cellref.mActorData.mACDT, objstate.mCreatureStats); + convertNpcData(cellref.mActorData, objstate.mNpcStats); + objstate.mEnabled = cellref.mEnabled; + objstate.mPosition = cellref.mPos; + objstate.mRef = out; + objstate.mRef.mRefNum = cellref.mRefNum; + esm.writeHNT ("OBJE", ESM::REC_NPC_); + objstate.save(esm); continue; } - ESM::CreatureState objstate; - objstate.mCount = 1; - objstate.mEnabled = cellref.mEnabled; - objstate.mHasLocals = 0; - objstate.mLocalRotation[0] = objstate.mLocalRotation[1] = objstate.mLocalRotation[2] = 0; - objstate.mPosition = cellref.mPos; - objstate.mRef = out; - objstate.mRef.mRefNum = cellref.mRefNum; - esm.writeHNT ("OBJE", ESM::REC_CREA); - objstate.save(esm); + std::cerr << "Can't find type for " << refIndex << " " << out.mRefID << std::endl; } esm.endRecord(ESM::REC_CSTA); diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index 71eb3ab9f..7e9166902 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -14,6 +14,9 @@ #include "importercontext.hpp" #include "importcellref.hpp" +#include "convertacdt.hpp" +#include "convertnpcc.hpp" + namespace ESSImport { @@ -151,9 +154,10 @@ public: npcc.load(esm); if (id == "PlayerSaveGame") { - mContext->mPlayer.mObject.mNpcStats.mReputation = npcc.mNPDT.mReputation; + convertNPCC(npcc, mContext->mPlayer.mObject); } - //mContext->mNpcChanges.insert(std::make_pair(std::make_pair(npcc.mIndex,id), crec)); + else + mContext->mNpcChanges.insert(std::make_pair(std::make_pair(npcc.mIndex,id), npcc)); } }; @@ -168,36 +172,10 @@ public: mContext->mPlayer.mObject.mPosition = refr.mPos; ESM::CreatureStats& cStats = mContext->mPlayer.mObject.mCreatureStats; - for (int i=0; i<3; ++i) - { - int writeIndex = translateDynamicIndex(i); - cStats.mDynamic[writeIndex].mBase = refr.mACDT.mDynamic[i][1]; - cStats.mDynamic[writeIndex].mMod = refr.mACDT.mDynamic[i][1]; - cStats.mDynamic[writeIndex].mCurrent = refr.mACDT.mDynamic[i][0]; - } - for (int i=0; i<8; ++i) - { - cStats.mAttributes[i].mBase = refr.mACDT.mAttributes[i][1]; - cStats.mAttributes[i].mMod = refr.mACDT.mAttributes[i][0]; - cStats.mAttributes[i].mCurrent = refr.mACDT.mAttributes[i][0]; - } - ESM::NpcStats& npcStats = mContext->mPlayer.mObject.mNpcStats; - for (int i=0; imPlayer.mObject.mNpcStats; + convertNpcData(refr.mActorData, npcStats); } }; diff --git a/apps/essimporter/convertnpcc.cpp b/apps/essimporter/convertnpcc.cpp new file mode 100644 index 000000000..11e665bfd --- /dev/null +++ b/apps/essimporter/convertnpcc.cpp @@ -0,0 +1,22 @@ +#include "convertnpcc.hpp" + +namespace ESSImport +{ + + void convertNPCC(const NPCC &npcc, ESM::NpcState &npcState) + { + npcState.mNpcStats.mReputation = npcc.mNPDT.mReputation; + + for (std::vector::const_iterator it = npcc.mInventory.begin(); + it != npcc.mInventory.end(); ++it) + { + ESM::ObjectState obj; + obj.blank(); + obj.mRef.mRefID = it->mId; + obj.mRef.mCharge = it->mCondition; + + // Don't know type of object :( change save format? + // npcState.mInventory.mItems.push_back(std::make_pair(obj, std::make_pair(0,0))); + } + } +} diff --git a/apps/essimporter/convertnpcc.hpp b/apps/essimporter/convertnpcc.hpp new file mode 100644 index 000000000..eb12d8f3b --- /dev/null +++ b/apps/essimporter/convertnpcc.hpp @@ -0,0 +1,15 @@ +#ifndef OPENMW_ESSIMPORT_CONVERTNPCC_H +#define OPENMW_ESSIMPORT_CONVERTNPCC_H + +#include "importnpcc.hpp" + +#include + +namespace ESSImport +{ + + void convertNPCC (const NPCC& npcc, ESM::NpcState& npcState); + +} + +#endif diff --git a/apps/essimporter/importacdt.cpp b/apps/essimporter/importacdt.cpp new file mode 100644 index 000000000..b3e399f9f --- /dev/null +++ b/apps/essimporter/importacdt.cpp @@ -0,0 +1,28 @@ +#include "importacdt.hpp" + +#include + +namespace ESSImport +{ + + void ActorData::load(ESM::ESMReader &esm) + { + esm.getHNT(mACDT, "ACDT"); + + ACSC acsc; + esm.getHNOT(acsc, "ACSC"); + esm.getHNOT(acsc, "ACSL"); + + if (esm.isNextSub("CHRD")) // npc only + esm.getHExact(mSkills, 27*2*sizeof(int)); + + if (esm.isNextSub("CRED")) // creature only + esm.getHExact(mCombatStats, 3*2*sizeof(int)); + + mScript = esm.getHNOString("SCRI"); + + if (esm.isNextSub("ND3D")) + esm.skipHSub(); + } + +} diff --git a/apps/essimporter/importacdt.hpp b/apps/essimporter/importacdt.hpp index 1d79f899e..6efae9dc5 100644 --- a/apps/essimporter/importacdt.hpp +++ b/apps/essimporter/importacdt.hpp @@ -1,9 +1,17 @@ #ifndef OPENMW_ESSIMPORT_ACDT_H #define OPENMW_ESSIMPORT_ACDT_H +#include + +namespace ESM +{ + struct ESMReader; +} + namespace ESSImport { + /// Actor data, shared by (at least) REFR and CellRef struct ACDT { @@ -14,6 +22,22 @@ namespace ESSImport unsigned char mUnknown3[120]; }; + struct ActorData + { + ACDT mACDT; + + int mSkills[27][2]; + + // creature combat stats, base and modified + // I think these can be ignored in the conversion, because it is not possible + // to change them ingame + int mCombatStats[3][2]; + + std::string mScript; + + void load(ESM::ESMReader& esm); + }; + /// Unknown, shared by (at least) REFR and CellRef struct ACSC { diff --git a/apps/essimporter/importcellref.cpp b/apps/essimporter/importcellref.cpp index 51e771081..76356769a 100644 --- a/apps/essimporter/importcellref.cpp +++ b/apps/essimporter/importcellref.cpp @@ -16,22 +16,19 @@ namespace ESSImport mIndexedRefId = esm.getHNString("NAME"); - esm.getHNT(mACDT, "ACDT"); + // the following two occur in ESM::CellRef too (Charge and Gold), + // but may have entirely different meanings here + int intv; + esm.getHNOT(intv, "INTV"); + int nam9; + esm.getHNOT(nam9, "NAM9"); - ACSC acsc; - esm.getHNOT(acsc, "ACSC"); - esm.getHNOT(acsc, "ACSL"); - - if (esm.isNextSub("CRED")) - esm.skipHSub(); - - if (esm.isNextSub("ND3D")) - esm.skipHSub(); + mActorData.load(esm); mEnabled = true; esm.getHNOT(mEnabled, "ZNAM"); - esm.getHNOT(mPos, "DATA", 24); + esm.getHNT(mPos, "DATA", 24); } } diff --git a/apps/essimporter/importcellref.hpp b/apps/essimporter/importcellref.hpp index 72c5af257..77763d434 100644 --- a/apps/essimporter/importcellref.hpp +++ b/apps/essimporter/importcellref.hpp @@ -21,10 +21,12 @@ namespace ESSImport std::string mIndexedRefId; ESM::RefNum mRefNum; - ACDT mACDT; + ActorData mActorData; ESM::Position mPos; + std::string mScript; + bool mEnabled; void load(ESM::ESMReader& esm); diff --git a/apps/essimporter/importer.cpp b/apps/essimporter/importer.cpp index b511dfe5e..572489d9a 100644 --- a/apps/essimporter/importer.cpp +++ b/apps/essimporter/importer.cpp @@ -185,6 +185,9 @@ namespace ESSImport Context context; + const ESM::Header& header = esm.getHeader(); + context.mPlayerCellName = header.mGameData.mCurrentCell.toString(); + const unsigned int recREFR = ESM::FourCC<'R','E','F','R'>::value; const unsigned int recPCDT = ESM::FourCC<'P','C','D','T'>::value; const unsigned int recFMAP = ESM::FourCC<'F','M','A','P'>::value; @@ -234,8 +237,6 @@ namespace ESSImport } } - const ESM::Header& header = esm.getHeader(); - ESM::ESMWriter writer; writer.setFormat (ESM::Header::CurrentFormat); @@ -247,6 +248,11 @@ namespace ESSImport writer.setAuthor(""); writer.setDescription(""); writer.setRecordCount (0); + + for (std::vector::const_iterator it = header.mMaster.begin(); + it != header.mMaster.end(); ++it) + writer.addMaster (it->name, 0); // not using the size information anyway -> use value of 0 + writer.save (stream); ESM::SavedGame profile; @@ -298,6 +304,15 @@ namespace ESSImport } writer.startRecord(ESM::REC_PLAY); + if (context.mPlayer.mCellId.mPaged) + { + // exterior cell -> determine cell coordinates based on position + const int cellSize = 8192; + int cellX = std::floor(context.mPlayer.mObject.mPosition.pos[0]/cellSize); + int cellY = std::floor(context.mPlayer.mObject.mPosition.pos[1]/cellSize); + context.mPlayer.mCellId.mIndex.mX = cellX; + context.mPlayer.mCellId.mIndex.mY = cellY; + } context.mPlayer.save(writer); writer.endRecord(ESM::REC_PLAY); } diff --git a/apps/essimporter/importercontext.hpp b/apps/essimporter/importercontext.hpp index 6f26e8329..9183e6179 100644 --- a/apps/essimporter/importercontext.hpp +++ b/apps/essimporter/importercontext.hpp @@ -17,6 +17,9 @@ namespace ESSImport struct Context { + // set from the TES3 header + std::string mPlayerCellName; + ESM::Player mPlayer; ESM::NPC mPlayerBase; std::string mCustomPlayerClassName; @@ -38,33 +41,8 @@ namespace ESSImport //mPlayer.mLastKnownExteriorPosition mPlayer.mHasMark = 0; // TODO mPlayer.mCurrentCrimeId = 0; // TODO - mPlayer.mObject.mCount = 1; - mPlayer.mObject.mEnabled = 1; - mPlayer.mObject.mHasLocals = false; + mPlayer.mObject.blank(); mPlayer.mObject.mRef.mRefID = "player"; // REFR.mRefID would be PlayerSaveGame - mPlayer.mObject.mCreatureStats.mHasAiSettings = true; - mPlayer.mObject.mCreatureStats.mDead = false; - mPlayer.mObject.mCreatureStats.mDied = false; - mPlayer.mObject.mCreatureStats.mKnockdown = false; - mPlayer.mObject.mCreatureStats.mKnockdownOneFrame = false; - mPlayer.mObject.mCreatureStats.mKnockdownOverOneFrame = false; - mPlayer.mObject.mCreatureStats.mHitRecovery = false; - mPlayer.mObject.mCreatureStats.mBlock = false; - mPlayer.mObject.mCreatureStats.mMovementFlags = 0; - mPlayer.mObject.mCreatureStats.mAttackStrength = 0.f; - mPlayer.mObject.mCreatureStats.mFallHeight = 0.f; - mPlayer.mObject.mCreatureStats.mRecalcDynamicStats = false; - mPlayer.mObject.mCreatureStats.mDrawState = 0; - mPlayer.mObject.mCreatureStats.mDeathAnimation = 0; - mPlayer.mObject.mNpcStats.mIsWerewolf = false; - mPlayer.mObject.mNpcStats.mTimeToStartDrowning = 20; - mPlayer.mObject.mNpcStats.mLevelProgress = 0; - mPlayer.mObject.mNpcStats.mDisposition = 0; - mPlayer.mObject.mNpcStats.mTimeToStartDrowning = 20; - mPlayer.mObject.mNpcStats.mReputation = 0; - mPlayer.mObject.mNpcStats.mCrimeId = -1; - mPlayer.mObject.mNpcStats.mWerewolfKills = 0; - mPlayer.mObject.mNpcStats.mProfit = 0; } }; diff --git a/apps/essimporter/importnpcc.cpp b/apps/essimporter/importnpcc.cpp index 192fe5da4..4cfc816c9 100644 --- a/apps/essimporter/importnpcc.cpp +++ b/apps/essimporter/importnpcc.cpp @@ -7,12 +7,29 @@ namespace ESSImport void NPCC::load(ESM::ESMReader &esm) { + mIndex = 0; + esm.getHNOT(mIndex, "INDX"); + esm.getHNT(mNPDT, "NPDT"); - // container: - // XIDX - // XHLT - condition - // WIDX - equipping? + while (esm.isNextSub("NPCO")) + { + InventoryItem item; + item.mId = esm.getHString(); + + if (esm.isNextSub("XIDX")) + esm.skipHSub(); + + item.mCondition = -1; + esm.getHNOT(item.mCondition, "XHLT"); + mInventory.push_back(item); + } + + while (esm.isNextSub("WIDX")) + { + // equipping? + esm.skipHSub(); + } } } diff --git a/apps/essimporter/importnpcc.hpp b/apps/essimporter/importnpcc.hpp index 12135850f..d10048fe0 100644 --- a/apps/essimporter/importnpcc.hpp +++ b/apps/essimporter/importnpcc.hpp @@ -1,7 +1,6 @@ #ifndef OPENMW_ESSIMPORT_NPCC_H #define OPENMW_ESSIMPORT_NPCC_H -#include #include namespace ESM @@ -12,7 +11,7 @@ namespace ESM namespace ESSImport { - struct NPCC : public ESM::NPC + struct NPCC { struct NPDT { @@ -21,6 +20,15 @@ namespace ESSImport unsigned char unknown2[5]; } mNPDT; + struct InventoryItem + { + std::string mId; + int mCondition; + }; + std::vector mInventory; + + int mIndex; + void load(ESM::ESMReader &esm); }; diff --git a/apps/essimporter/importplayer.cpp b/apps/essimporter/importplayer.cpp index 81f81e764..f8c78dab0 100644 --- a/apps/essimporter/importplayer.cpp +++ b/apps/essimporter/importplayer.cpp @@ -14,16 +14,7 @@ namespace ESSImport if (esm.isNextSub("STPR")) esm.skipHSub(); // ESS TODO - esm.getHNT(mACDT, "ACDT"); - - ACSC acsc; - esm.getHNOT(acsc, "ACSC"); - esm.getHNOT(acsc, "ACSL"); - - esm.getHNExact(mSkills, 27*2*sizeof(int), "CHRD"); - - if (esm.isNextSub("ND3D")) - esm.skipHSub(); // ESS TODO (1 byte) + mActorData.load(esm); esm.getHNOT(mPos, "DATA", 24); } @@ -45,6 +36,9 @@ namespace ESSImport if (esm.isNextSub("ENAM")) esm.skipHSub(); + if (esm.isNextSub("LNAM")) + esm.skipHSub(); + while (esm.isNextSub("FNAM")) { FNAM fnam; diff --git a/apps/essimporter/importplayer.hpp b/apps/essimporter/importplayer.hpp index 8a0a087a5..2493fcdad 100644 --- a/apps/essimporter/importplayer.hpp +++ b/apps/essimporter/importplayer.hpp @@ -21,15 +21,12 @@ namespace ESSImport /// Player-agnostic player data struct REFR { - ACDT mACDT; + ActorData mActorData; std::string mRefID; ESM::Position mPos; ESM::RefNum mRefNum; - int mSkills[27][2]; - float mAttributes[8][2]; - void load(ESM::ESMReader& esm); }; diff --git a/components/esm/creaturestate.cpp b/components/esm/creaturestate.cpp index 9e9b56102..c2838f78d 100644 --- a/components/esm/creaturestate.cpp +++ b/components/esm/creaturestate.cpp @@ -17,4 +17,10 @@ void ESM::CreatureState::save (ESMWriter &esm, bool inInventory) const mInventory.save (esm); mCreatureStats.save (esm); -} \ No newline at end of file +} + +void ESM::CreatureState::blank() +{ + ObjectState::blank(); + mCreatureStats.blank(); +} diff --git a/components/esm/creaturestate.hpp b/components/esm/creaturestate.hpp index 604c2f3a7..9a3d41daa 100644 --- a/components/esm/creaturestate.hpp +++ b/components/esm/creaturestate.hpp @@ -14,6 +14,9 @@ namespace ESM InventoryState mInventory; CreatureStats mCreatureStats; + /// Initialize to default state + void blank(); + virtual void load (ESMReader &esm); virtual void save (ESMWriter &esm, bool inInventory = false) const; }; diff --git a/components/esm/creaturestats.cpp b/components/esm/creaturestats.cpp index 1fdce703c..a1ef7eb0e 100644 --- a/components/esm/creaturestats.cpp +++ b/components/esm/creaturestats.cpp @@ -218,6 +218,38 @@ void ESM::CreatureStats::save (ESMWriter &esm) const } esm.writeHNT("AISE", mHasAiSettings); - for (int i=0; i<4; ++i) - mAiSettings[i].save(esm); + if (mHasAiSettings) + { + for (int i=0; i<4; ++i) + mAiSettings[i].save(esm); + } +} + +void ESM::CreatureStats::blank() +{ + mTradeTime.mHour = 0; + mTradeTime.mDay = 0; + mGoldPool = 0; + mActorId = 0; + mHasAiSettings = false; + mDead = false; + mDied = false; + mMurdered = false; + mFriendlyHits = 0; + mTalkedTo = false; + mAlarmed = false; + mAttacked = false; + mAttackingOrSpell = false; + mKnockdown = false; + mKnockdownOneFrame = false; + mKnockdownOverOneFrame = false; + mHitRecovery = false; + mBlock = false; + mMovementFlags = 0; + mAttackStrength = 0.f; + mFallHeight = 0.f; + mRecalcDynamicStats = false; + mDrawState = 0; + mDeathAnimation = 0; + mLevel = 1; } diff --git a/components/esm/creaturestats.hpp b/components/esm/creaturestats.hpp index 680577f93..91ee98333 100644 --- a/components/esm/creaturestats.hpp +++ b/components/esm/creaturestats.hpp @@ -66,6 +66,9 @@ namespace ESM SpellState mSpells; ActiveSpells mActiveSpells; + /// Initialize to default state + void blank(); + void load (ESMReader &esm); void save (ESMWriter &esm) const; }; diff --git a/components/esm/npcstate.cpp b/components/esm/npcstate.cpp index e59ec3e26..6134193c2 100644 --- a/components/esm/npcstate.cpp +++ b/components/esm/npcstate.cpp @@ -21,4 +21,11 @@ void ESM::NpcState::save (ESMWriter &esm, bool inInventory) const mNpcStats.save (esm); mCreatureStats.save (esm); -} \ No newline at end of file +} + +void ESM::NpcState::blank() +{ + ObjectState::blank(); + mNpcStats.blank(); + mCreatureStats.blank(); +} diff --git a/components/esm/npcstate.hpp b/components/esm/npcstate.hpp index 39858d553..b90cd85e6 100644 --- a/components/esm/npcstate.hpp +++ b/components/esm/npcstate.hpp @@ -16,6 +16,9 @@ namespace ESM NpcStats mNpcStats; CreatureStats mCreatureStats; + /// Initialize to default state + void blank(); + virtual void load (ESMReader &esm); virtual void save (ESMWriter &esm, bool inInventory = false) const; }; diff --git a/components/esm/npcstats.cpp b/components/esm/npcstats.cpp index 4ba0ce7e3..e305ddab0 100644 --- a/components/esm/npcstats.cpp +++ b/components/esm/npcstats.cpp @@ -150,3 +150,18 @@ void ESM::NpcStats::save (ESMWriter &esm) const if (mCrimeId != -1) esm.writeHNT ("CRID", mCrimeId); } + +void ESM::NpcStats::blank() +{ + mIsWerewolf = false; + mDisposition = 0; + mBounty = 0; + mReputation = 0; + mWerewolfKills = 0; + mProfit = 0; + mLevelProgress = 0; + for (int i=0; i<8; ++i) + mSkillIncrease[i] = 0; + mTimeToStartDrowning = 20; + mCrimeId = -1; +} diff --git a/components/esm/npcstats.hpp b/components/esm/npcstats.hpp index f6e9c1e58..a8ec4cf44 100644 --- a/components/esm/npcstats.hpp +++ b/components/esm/npcstats.hpp @@ -47,6 +47,9 @@ namespace ESM float mTimeToStartDrowning; int mCrimeId; + /// Initialize to default state + void blank(); + void load (ESMReader &esm); void save (ESMWriter &esm) const; }; diff --git a/components/esm/objectstate.cpp b/components/esm/objectstate.cpp index be00f3ef6..f7755f8cb 100644 --- a/components/esm/objectstate.cpp +++ b/components/esm/objectstate.cpp @@ -48,4 +48,18 @@ void ESM::ObjectState::save (ESMWriter &esm, bool inInventory) const } } -ESM::ObjectState::~ObjectState() {} \ No newline at end of file +void ESM::ObjectState::blank() +{ + mRef.blank(); + mHasLocals = 0; + mEnabled = false; + mCount = 1; + for (int i=0;i<3;++i) + { + mPosition.pos[i] = 0; + mPosition.rot[i] = 0; + mLocalRotation[i] = 0; + } +} + +ESM::ObjectState::~ObjectState() {} diff --git a/components/esm/objectstate.hpp b/components/esm/objectstate.hpp index 9c9ca5f2e..5b05e0949 100644 --- a/components/esm/objectstate.hpp +++ b/components/esm/objectstate.hpp @@ -29,8 +29,11 @@ namespace ESM virtual void load (ESMReader &esm); virtual void save (ESMWriter &esm, bool inInventory = false) const; + /// Initialize to default state + void blank(); + virtual ~ObjectState(); }; } -#endif \ No newline at end of file +#endif From 19ed047dec4763362556141e876b12945a4894b6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 18 Jan 2015 22:52:11 +0100 Subject: [PATCH 0336/3725] ESSImport: add some subrecords to CellRef and others, most files should load now, importacdt/cellref class structure need some refactoring --- apps/essimporter/CMakeLists.txt | 1 + apps/essimporter/converter.cpp | 34 +++++++++++-- apps/essimporter/converter.hpp | 16 ++++--- apps/essimporter/convertnpcc.cpp | 12 ----- apps/essimporter/importacdt.cpp | 71 +++++++++++++++++++++++++++- apps/essimporter/importcellref.cpp | 24 ++++++---- apps/essimporter/importcrec.cpp | 7 +++ apps/essimporter/importcrec.hpp | 4 ++ apps/essimporter/importinventory.cpp | 46 ++++++++++++++++++ apps/essimporter/importinventory.hpp | 31 ++++++++++++ apps/essimporter/importnpcc.cpp | 24 +++------- apps/essimporter/importnpcc.hpp | 11 ++--- apps/essimporter/importplayer.cpp | 28 +++++++++-- apps/essimporter/importplayer.hpp | 2 + components/esm/cellref.cpp | 5 ++ components/esm/cellref.hpp | 3 ++ 16 files changed, 261 insertions(+), 58 deletions(-) create mode 100644 apps/essimporter/importinventory.cpp create mode 100644 apps/essimporter/importinventory.hpp diff --git a/apps/essimporter/CMakeLists.txt b/apps/essimporter/CMakeLists.txt index 257a466ee..3d3e0860c 100644 --- a/apps/essimporter/CMakeLists.txt +++ b/apps/essimporter/CMakeLists.txt @@ -6,6 +6,7 @@ set(ESSIMPORTER_FILES importcrec.cpp importcellref.cpp importacdt.cpp + importinventory.cpp importercontext.cpp converter.cpp convertacdt.cpp diff --git a/apps/essimporter/converter.cpp b/apps/essimporter/converter.cpp index 2e7a954e0..c51e91ed7 100644 --- a/apps/essimporter/converter.cpp +++ b/apps/essimporter/converter.cpp @@ -60,12 +60,17 @@ namespace ESSImport // TODO: add bleeding of FOW into neighbouring cells (openmw handles this by writing to the textures, // MW handles it when rendering only) unsigned char nam8[32]; - if (esm.isNextSub("NAM8")) + // exterior has 1 NAM8, interior can have multiple ones, and have an extra 4 byte flag at the start + // (probably offset of that specific fog texture?) + while (esm.isNextSub("NAM8")) { esm.getSubHeader(); - // FIXME: different size in interior cells for some reason + if (esm.getSubSize() == 36) + { + // flag on interiors esm.skip(4); + } esm.getExact(nam8, 32); @@ -82,10 +87,24 @@ namespace ESSImport } } - std::ostringstream filename; - filename << "fog_" << cell.mData.mX << "_" << cell.mData.mY << ".tga"; + if (cell.isExterior()) + { + std::ostringstream filename; + filename << "fog_" << cell.mData.mX << "_" << cell.mData.mY << ".tga"; + + convertImage((char*)&newcell.mFogOfWar[0], newcell.mFogOfWar.size()*4, 16, 16, Ogre::PF_BYTE_RGBA, filename.str()); + } + } - convertImage((char*)&newcell.mFogOfWar[0], newcell.mFogOfWar.size()*4, 16, 16, Ogre::PF_BYTE_RGBA, filename.str()); + // moved reference, not handled yet + // NOTE: MVRF can also occur in within normal references (importcellref.cpp)? + // this does not match the ESM file implementation, + // verify if that can happen with ESM files too + while (esm.isNextSub("MVRF")) + { + esm.skipHSub(); // skip MVRF + esm.getSubName(); + esm.skipHSub(); // skip CNDT } std::vector cellrefs; @@ -94,7 +113,11 @@ namespace ESSImport CellRef ref; ref.load (esm); if (esm.isNextSub("DELE")) + { + // strangely this can be e.g. 52 instead of just 1, std::cout << "deleted ref " << ref.mIndexedRefId << std::endl; + esm.skipHSub(); + } cellrefs.push_back(ref); } @@ -148,6 +171,7 @@ namespace ESSImport objstate.mPosition = cellref.mPos; objstate.mRef = out; objstate.mRef.mRefNum = cellref.mRefNum; + // FIXME: change save format to not require object type, instead look up it up using the RefId esm.writeHNT ("OBJE", ESM::REC_CREA); objstate.save(esm); continue; diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index 7e9166902..3f8b4cbbe 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -83,13 +83,17 @@ public: // this is always the player ESM::NPC npc; std::string id = esm.getHNString("NAME"); - assert (id == "player"); npc.load(esm); - mContext->mPlayer.mObject.mCreatureStats.mLevel = npc.mNpdt52.mLevel; - mContext->mPlayerBase = npc; - std::map empty; - for (std::vector::const_iterator it = npc.mSpells.mList.begin(); it != npc.mSpells.mList.end(); ++it) - mContext->mPlayer.mObject.mCreatureStats.mSpells.mSpells[*it] = empty; + if (id != "player") // seems to occur sometimes, with "chargen X" names + std::cerr << "non-player NPC record: " << id << std::endl; + else + { + mContext->mPlayer.mObject.mCreatureStats.mLevel = npc.mNpdt52.mLevel; + mContext->mPlayerBase = npc; + std::map empty; + for (std::vector::const_iterator it = npc.mSpells.mList.begin(); it != npc.mSpells.mList.end(); ++it) + mContext->mPlayer.mObject.mCreatureStats.mSpells.mSpells[*it] = empty; + } } }; diff --git a/apps/essimporter/convertnpcc.cpp b/apps/essimporter/convertnpcc.cpp index 11e665bfd..fdf96c15a 100644 --- a/apps/essimporter/convertnpcc.cpp +++ b/apps/essimporter/convertnpcc.cpp @@ -6,17 +6,5 @@ namespace ESSImport void convertNPCC(const NPCC &npcc, ESM::NpcState &npcState) { npcState.mNpcStats.mReputation = npcc.mNPDT.mReputation; - - for (std::vector::const_iterator it = npcc.mInventory.begin(); - it != npcc.mInventory.end(); ++it) - { - ESM::ObjectState obj; - obj.blank(); - obj.mRef.mRefID = it->mId; - obj.mRef.mCharge = it->mCondition; - - // Don't know type of object :( change save format? - // npcState.mInventory.mItems.push_back(std::make_pair(obj, std::make_pair(0,0))); - } } } diff --git a/apps/essimporter/importacdt.cpp b/apps/essimporter/importacdt.cpp index b3e399f9f..5bec5bd82 100644 --- a/apps/essimporter/importacdt.cpp +++ b/apps/essimporter/importacdt.cpp @@ -2,17 +2,73 @@ #include +#include + namespace ESSImport { void ActorData::load(ESM::ESMReader &esm) { - esm.getHNT(mACDT, "ACDT"); + // unsure at which point between NAME and ESM::CellRef + if (esm.isNextSub("MNAM")) + esm.skipHSub(); + + if (esm.isNextSub("ACTN")) + esm.skipHSub(); + + if (esm.isNextSub("STPR")) + esm.skipHSub(); + + ESM::CellRef bla; + bla.ESM::CellRef::loadData(esm); + + // FIXME: actually should be required for all actors?, but ActorData is currently in base CellRef + esm.getHNOT(mACDT, "ACDT"); ACSC acsc; esm.getHNOT(acsc, "ACSC"); esm.getHNOT(acsc, "ACSL"); + if (esm.isNextSub("CSTN")) + esm.skipHSub(); // "PlayerSaveGame", link to some object? + + if (esm.isNextSub("LSTN")) + esm.skipHSub(); // "PlayerSaveGame", link to some object? + + // unsure at which point between LSTN and TGTN + if (esm.isNextSub("CSHN")) + esm.skipHSub(); // "PlayerSaveGame", link to some object? + + // unsure if before or after CSTN/LSTN + if (esm.isNextSub("LSHN")) + esm.skipHSub(); // "PlayerSaveGame", link to some object? + + while (esm.isNextSub("TGTN")) + esm.skipHSub(); // "PlayerSaveGame", link to some object? + + while (esm.isNextSub("FGTN")) + esm.getHString(); // fight target? + + // unsure at which point between FGTN and CHRD + if (esm.isNextSub("PWPC")) + esm.skipHSub(); + if (esm.isNextSub("PWPS")) + esm.skipHSub(); + + if (esm.isNextSub("WNAM")) + { + esm.skipHSub(); // seen values: "ancestor guardian", "bound dagger_en". Summoned creature / bound weapons? + + if (esm.isNextSub("XNAM")) + { + // "demon tanto", probably the ID of spell/item that created the bound weapon/crature? + esm.skipHSub(); + } + + if (esm.isNextSub("YNAM")) + esm.skipHSub(); // 4 byte, 0 + } + if (esm.isNextSub("CHRD")) // npc only esm.getHExact(mSkills, 27*2*sizeof(int)); @@ -21,8 +77,21 @@ namespace ESSImport mScript = esm.getHNOString("SCRI"); + // script variables? + if (!mScript.empty()) + { + if (esm.isNextSub("SLCS")) + esm.skipHSub(); + if (esm.isNextSub("SLSD")) // Short Data? + esm.skipHSub(); + if (esm.isNextSub("SLFD")) // Float Data? + esm.skipHSub(); + } + if (esm.isNextSub("ND3D")) esm.skipHSub(); + if (esm.isNextSub("ANIS")) + esm.skipHSub(); } } diff --git a/apps/essimporter/importcellref.cpp b/apps/essimporter/importcellref.cpp index 76356769a..454690adc 100644 --- a/apps/essimporter/importcellref.cpp +++ b/apps/essimporter/importcellref.cpp @@ -7,7 +7,7 @@ namespace ESSImport void CellRef::load(ESM::ESMReader &esm) { - esm.getHNT(mRefNum.mIndex, "FRMR"); // TODO: adjust RefNum + esm.getHNT(mRefNum.mIndex, "FRMR"); // this is required since openmw supports more than 255 content files int pluginIndex = (mRefNum.mIndex & 0xff000000) >> 24; @@ -16,19 +16,27 @@ namespace ESSImport mIndexedRefId = esm.getHNString("NAME"); - // the following two occur in ESM::CellRef too (Charge and Gold), - // but may have entirely different meanings here - int intv; - esm.getHNOT(intv, "INTV"); - int nam9; - esm.getHNOT(nam9, "NAM9"); + if (esm.isNextSub("LVCR")) + esm.skipHSub(); mActorData.load(esm); mEnabled = true; esm.getHNOT(mEnabled, "ZNAM"); - esm.getHNT(mPos, "DATA", 24); + // should occur for all references but not levelled creature spawners + esm.getHNOT(mPos, "DATA", 24); + + // i've seen DATA record TWICE on a creature record - and with the exact same content too! weird + // alarmvoi0000.ess + esm.getHNOT(mPos, "DATA", 24); + + if (esm.isNextSub("MVRF")) + { + esm.skipHSub(); + esm.getSubName(); + esm.skipHSub(); + } } } diff --git a/apps/essimporter/importcrec.cpp b/apps/essimporter/importcrec.cpp index c770b2386..9cf455588 100644 --- a/apps/essimporter/importcrec.cpp +++ b/apps/essimporter/importcrec.cpp @@ -8,6 +8,13 @@ namespace ESSImport void CREC::load(ESM::ESMReader &esm) { esm.getHNT(mIndex, "INDX"); + + // equivalent of ESM::Creature XSCL? probably don't have to convert this, + // since the value can't be changed + float scale; + esm.getHNOT(scale, "XSCL"); + + mInventory.load(esm); } } diff --git a/apps/essimporter/importcrec.hpp b/apps/essimporter/importcrec.hpp index 62881c582..16b752807 100644 --- a/apps/essimporter/importcrec.hpp +++ b/apps/essimporter/importcrec.hpp @@ -1,6 +1,8 @@ #ifndef OPENMW_ESSIMPORT_CREC_H #define OPENMW_ESSIMPORT_CREC_H +#include "importinventory.hpp" + namespace ESM { class ESMReader; @@ -14,6 +16,8 @@ namespace ESSImport { int mIndex; + Inventory mInventory; + void load(ESM::ESMReader& esm); }; diff --git a/apps/essimporter/importinventory.cpp b/apps/essimporter/importinventory.cpp new file mode 100644 index 000000000..d132fd76d --- /dev/null +++ b/apps/essimporter/importinventory.cpp @@ -0,0 +1,46 @@ +#include "importinventory.hpp" + +#include + +namespace ESSImport +{ + + void Inventory::load(ESM::ESMReader &esm) + { + while (esm.isNextSub("NPCO")) + { + InventoryItem item; + item.mId = esm.getHString(); + + if (esm.isNextSub("XIDX")) + esm.skipHSub(); + + std::string script = esm.getHNOString("SCRI"); + // script variables? + // unsure if before or after ESM::CellRef + if (!script.empty()) + { + if (esm.isNextSub("SLCS")) + esm.skipHSub(); + if (esm.isNextSub("SLSD")) // Short Data? + esm.skipHSub(); + if (esm.isNextSub("SLFD")) // Float Data? + esm.skipHSub(); + } + + // for XSOL and XCHG seen so far, but probably others too + item.ESM::CellRef::loadData(esm); + + item.mCondition = -1; + esm.getHNOT(item.mCondition, "XHLT"); + mItems.push_back(item); + } + + while (esm.isNextSub("WIDX")) + { + // equipping? + esm.skipHSub(); + } + } + +} diff --git a/apps/essimporter/importinventory.hpp b/apps/essimporter/importinventory.hpp new file mode 100644 index 000000000..e31cab76a --- /dev/null +++ b/apps/essimporter/importinventory.hpp @@ -0,0 +1,31 @@ +#ifndef OPENMW_ESSIMPORT_IMPORTINVENTORY_H +#define OPENMW_ESSIMPORT_IMPORTINVENTORY_H + +#include +#include + +#include + +namespace ESM +{ + class ESMReader; +} + +namespace ESSImport +{ + + struct Inventory + { + struct InventoryItem : public ESM::CellRef + { + std::string mId; + int mCondition; + }; + std::vector mItems; + + void load(ESM::ESMReader& esm); + }; + +} + +#endif diff --git a/apps/essimporter/importnpcc.cpp b/apps/essimporter/importnpcc.cpp index 4cfc816c9..8400a9e4a 100644 --- a/apps/essimporter/importnpcc.cpp +++ b/apps/essimporter/importnpcc.cpp @@ -12,24 +12,14 @@ namespace ESSImport esm.getHNT(mNPDT, "NPDT"); - while (esm.isNextSub("NPCO")) - { - InventoryItem item; - item.mId = esm.getHString(); - - if (esm.isNextSub("XIDX")) - esm.skipHSub(); - - item.mCondition = -1; - esm.getHNOT(item.mCondition, "XHLT"); - mInventory.push_back(item); - } - - while (esm.isNextSub("WIDX")) - { - // equipping? + if (esm.isNextSub("AI_E")) esm.skipHSub(); - } + if (esm.isNextSub("AI_T")) + esm.skipHSub(); + if (esm.isNextSub("AI_F")) + esm.skipHSub(); + + mInventory.load(esm); } } diff --git a/apps/essimporter/importnpcc.hpp b/apps/essimporter/importnpcc.hpp index d10048fe0..f3c4e24c7 100644 --- a/apps/essimporter/importnpcc.hpp +++ b/apps/essimporter/importnpcc.hpp @@ -3,6 +3,10 @@ #include +#include + +#include "importinventory.hpp" + namespace ESM { class ESMReader; @@ -20,12 +24,7 @@ namespace ESSImport unsigned char unknown2[5]; } mNPDT; - struct InventoryItem - { - std::string mId; - int mCondition; - }; - std::vector mInventory; + Inventory mInventory; int mIndex; diff --git a/apps/essimporter/importplayer.cpp b/apps/essimporter/importplayer.cpp index f8c78dab0..8a57ae588 100644 --- a/apps/essimporter/importplayer.cpp +++ b/apps/essimporter/importplayer.cpp @@ -11,9 +11,6 @@ namespace ESSImport mRefID = esm.getHNString("NAME"); - if (esm.isNextSub("STPR")) - esm.skipHSub(); // ESS TODO - mActorData.load(esm); esm.getHNOT(mPos, "DATA", 24); @@ -21,6 +18,12 @@ namespace ESSImport void PCDT::load(ESM::ESMReader &esm) { + while (esm.isNextSub("DNAM")) + { + // TODO: deal with encoding? + mKnownDialogueTopics.push_back(esm.getHString()); + } + if (esm.isNextSub("PNAM")) esm.skipHSub(); if (esm.isNextSub("SNAM")) @@ -33,6 +36,17 @@ namespace ESSImport mBirthsign = esm.getHNOString("BNAM"); + // Holds the names of the last used Alchemy apparatus. Don't need to import this ATM, + // because our GUI auto-selects the best apparatus. + if (esm.isNextSub("NAM0")) + esm.skipHSub(); + if (esm.isNextSub("NAM1")) + esm.skipHSub(); + if (esm.isNextSub("NAM2")) + esm.skipHSub(); + if (esm.isNextSub("NAM3")) + esm.skipHSub(); + if (esm.isNextSub("ENAM")) esm.skipHSub(); @@ -48,6 +62,14 @@ namespace ESSImport if (esm.isNextSub("KNAM")) esm.skipHSub(); + + if (esm.isNextSub("WERE")) + { + // some werewolf data, 152 bytes + // maybe current skills and attributes for werewolf form + esm.getSubHeader(); + esm.skip(152); + } } } diff --git a/apps/essimporter/importplayer.hpp b/apps/essimporter/importplayer.hpp index 2493fcdad..af8625fa6 100644 --- a/apps/essimporter/importplayer.hpp +++ b/apps/essimporter/importplayer.hpp @@ -36,6 +36,8 @@ struct PCDT int mBounty; std::string mBirthsign; + std::vector mKnownDialogueTopics; + struct FNAM { unsigned char mRank; diff --git a/components/esm/cellref.cpp b/components/esm/cellref.cpp index f93fe1535..43b1f4d29 100644 --- a/components/esm/cellref.cpp +++ b/components/esm/cellref.cpp @@ -20,6 +20,11 @@ void ESM::CellRef::load (ESMReader& esm, bool wideRefNum) mRefID = esm.getHNString ("NAME"); + loadData(esm); +} + +void ESM::CellRef::loadData(ESMReader &esm) +{ // Again, UNAM sometimes appears after NAME and sometimes later. // Or perhaps this UNAM means something different? mReferenceBlocked = -1; diff --git a/components/esm/cellref.hpp b/components/esm/cellref.hpp index f3986ccf3..b7b00a654 100644 --- a/components/esm/cellref.hpp +++ b/components/esm/cellref.hpp @@ -91,6 +91,9 @@ namespace ESM void load (ESMReader& esm, bool wideRefNum = false); + /// Implicitly called by load + void loadData (ESMReader& esm); + void save (ESMWriter &esm, bool wideRefNum = false, bool inInventory = false) const; void blank(); From f9cf31fcd5319dca02dddf89dead998cff3e9955 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 19 Jan 2015 00:35:19 +0100 Subject: [PATCH 0337/3725] ESSImport: convert custom map markers, not working for interiors yet --- apps/essimporter/converter.cpp | 39 +++++++++++++++++++++++++- apps/essimporter/converter.hpp | 3 ++ apps/essimporter/importacdt.cpp | 7 +++++ apps/essimporter/importcellref.cpp | 3 +- apps/essimporter/importer.cpp | 5 +++- apps/openmw/mwgui/mapwindow.cpp | 39 +++++++------------------- apps/openmw/mwgui/mapwindow.hpp | 34 ++++++---------------- apps/openmw/mwgui/windowmanagerimp.cpp | 4 +-- components/CMakeLists.txt | 2 +- components/esm/custommarkerstate.cpp | 26 +++++++++++++++++ components/esm/custommarkerstate.hpp | 30 ++++++++++++++++++++ 11 files changed, 132 insertions(+), 60 deletions(-) create mode 100644 components/esm/custommarkerstate.cpp create mode 100644 components/esm/custommarkerstate.hpp diff --git a/apps/essimporter/converter.cpp b/apps/essimporter/converter.cpp index c51e91ed7..ce3cea675 100644 --- a/apps/essimporter/converter.cpp +++ b/apps/essimporter/converter.cpp @@ -108,7 +108,7 @@ namespace ESSImport } std::vector cellrefs; - while (esm.hasMoreSubs()) + while (esm.hasMoreSubs() && esm.isNextSub("FRMR")) { CellRef ref; ref.load (esm); @@ -121,6 +121,36 @@ namespace ESSImport cellrefs.push_back(ref); } + while (esm.isNextSub("MPCD")) + { + float notepos[3]; + esm.getHT(notepos, 3*sizeof(float)); + + // Markers seem to be arranged in a 32*32 grid, notepos has grid-indices. + // This seems to be the reason markers can't be placed everywhere in interior cells, + // i.e. when the grid is exceeded. + // Converting the interior markers correctly could be rather tricky, but is probably similar logic + // as used for the FoW texture placement, which we need to figure out anyway + notepos[1] += 31.f; + notepos[0] += 0.5; + notepos[1] += 0.5; + notepos[0] = 8192 * notepos[0] / 32.f; + notepos[1] = 8192 * notepos[1] / 32.f; + if (cell.isExterior()) + { + notepos[0] += 8192 * cell.mData.mX; + notepos[1] += 8192 * cell.mData.mY; + } + // TODO: what encoding is this in? + std::string note = esm.getHNString("MPNT"); + ESM::CustomMarker marker; + marker.mWorldX = notepos[0]; + marker.mWorldY = notepos[1]; + marker.mNote = note; + marker.mCell = cell.getCellId(); + mMarkers.push_back(marker); + } + newcell.mRefs = cellrefs; // FIXME: map by ID for exterior cells @@ -199,6 +229,13 @@ namespace ESSImport esm.endRecord(ESM::REC_CSTA); } + + for (std::vector::const_iterator it = mMarkers.begin(); it != mMarkers.end(); ++it) + { + esm.startRecord(ESM::REC_MARK); + it->save(esm); + esm.endRecord(ESM::REC_MARK); + } } } diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index 3f8b4cbbe..5f1961717 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -9,6 +9,8 @@ #include #include #include +#include + #include "importcrec.hpp" #include "importercontext.hpp" @@ -240,6 +242,7 @@ private: std::map mCells; + std::vector mMarkers; }; } diff --git a/apps/essimporter/importacdt.cpp b/apps/essimporter/importacdt.cpp index 5bec5bd82..d961720a7 100644 --- a/apps/essimporter/importacdt.cpp +++ b/apps/essimporter/importacdt.cpp @@ -49,6 +49,13 @@ namespace ESSImport while (esm.isNextSub("FGTN")) esm.getHString(); // fight target? + // unsure at which point between TGTN and CRED + if (esm.isNextSub("AADT")) + { + // occured when a creature was in the middle of its attack, 44 bytes + esm.skipHSub(); + } + // unsure at which point between FGTN and CHRD if (esm.isNextSub("PWPC")) esm.skipHSub(); diff --git a/apps/essimporter/importcellref.cpp b/apps/essimporter/importcellref.cpp index 454690adc..8c2b8f36d 100644 --- a/apps/essimporter/importcellref.cpp +++ b/apps/essimporter/importcellref.cpp @@ -7,7 +7,8 @@ namespace ESSImport void CellRef::load(ESM::ESMReader &esm) { - esm.getHNT(mRefNum.mIndex, "FRMR"); + // (FRMR subrecord name is already read by the loop in ConvertCell) + esm.getHT(mRefNum.mIndex); // FRMR // this is required since openmw supports more than 255 content files int pluginIndex = (mRefNum.mIndex & 0xff000000) >> 24; diff --git a/apps/essimporter/importer.cpp b/apps/essimporter/importer.cpp index 572489d9a..12136cdea 100644 --- a/apps/essimporter/importer.cpp +++ b/apps/essimporter/importer.cpp @@ -213,6 +213,7 @@ namespace ESSImport converters[ESM::REC_LEVC] = boost::shared_ptr(new DefaultConverter()); converters[ESM::REC_LEVI] = boost::shared_ptr(new DefaultConverter()); + std::set unknownRecords; for (std::map >::const_iterator it = converters.begin(); it != converters.end(); ++it) @@ -232,7 +233,9 @@ namespace ESSImport } else { - std::cerr << "unknown record " << n.toString() << std::endl; + if (unknownRecords.insert(n.val).second) + std::cerr << "unknown record " << n.toString() << std::endl; + esm.skipRecord(); } } diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 4de9af108..abd1256d7 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -86,35 +86,16 @@ namespace namespace MWGui { - void CustomMarker::save(ESM::ESMWriter &esm) const - { - esm.writeHNT("POSX", mWorldX); - esm.writeHNT("POSY", mWorldY); - mCell.save(esm); - if (!mNote.empty()) - esm.writeHNString("NOTE", mNote); - } - - void CustomMarker::load(ESM::ESMReader &esm) - { - esm.getHNT(mWorldX, "POSX"); - esm.getHNT(mWorldY, "POSY"); - mCell.load(esm); - mNote = esm.getHNOString("NOTE"); - } - - // ------------------------------------------------------ - - void CustomMarkerCollection::addMarker(const CustomMarker &marker, bool triggerEvent) + void CustomMarkerCollection::addMarker(const ESM::CustomMarker &marker, bool triggerEvent) { mMarkers.push_back(marker); if (triggerEvent) eventMarkersChanged(); } - void CustomMarkerCollection::deleteMarker(const CustomMarker &marker) + void CustomMarkerCollection::deleteMarker(const ESM::CustomMarker &marker) { - std::vector::iterator it = std::find(mMarkers.begin(), mMarkers.end(), marker); + std::vector::iterator it = std::find(mMarkers.begin(), mMarkers.end(), marker); if (it != mMarkers.end()) mMarkers.erase(it); else @@ -123,9 +104,9 @@ namespace MWGui eventMarkersChanged(); } - void CustomMarkerCollection::updateMarker(const CustomMarker &marker, const std::string &newNote) + void CustomMarkerCollection::updateMarker(const ESM::CustomMarker &marker, const std::string &newNote) { - std::vector::iterator it = std::find(mMarkers.begin(), mMarkers.end(), marker); + std::vector::iterator it = std::find(mMarkers.begin(), mMarkers.end(), marker); if (it != mMarkers.end()) it->mNote = newNote; else @@ -140,12 +121,12 @@ namespace MWGui eventMarkersChanged(); } - std::vector::const_iterator CustomMarkerCollection::begin() const + std::vector::const_iterator CustomMarkerCollection::begin() const { return mMarkers.begin(); } - std::vector::const_iterator CustomMarkerCollection::end() const + std::vector::const_iterator CustomMarkerCollection::end() const { return mMarkers.end(); } @@ -295,9 +276,9 @@ namespace MWGui MyGUI::Gui::getInstance().destroyWidget(*it); mCustomMarkerWidgets.clear(); - for (std::vector::const_iterator it = mCustomMarkers.begin(); it != mCustomMarkers.end(); ++it) + for (std::vector::const_iterator it = mCustomMarkers.begin(); it != mCustomMarkers.end(); ++it) { - const CustomMarker& marker = *it; + const ESM::CustomMarker& marker = *it; if (marker.mCell.mPaged != !mInterior) continue; @@ -654,7 +635,7 @@ namespace MWGui void MapWindow::onCustomMarkerDoubleClicked(MyGUI::Widget *sender) { - mEditingMarker = *sender->getUserData(); + mEditingMarker = *sender->getUserData(); mEditNoteDialog.setText(mEditingMarker.mNote); mEditNoteDialog.showDeleteButton(true); mEditNoteDialog.setVisible(true); diff --git a/apps/openmw/mwgui/mapwindow.hpp b/apps/openmw/mwgui/mapwindow.hpp index 118fee0f6..684069467 100644 --- a/apps/openmw/mwgui/mapwindow.hpp +++ b/apps/openmw/mwgui/mapwindow.hpp @@ -7,6 +7,8 @@ #include +#include + namespace MWRender { class GlobalMap; @@ -26,43 +28,25 @@ namespace Loading namespace MWGui { - struct CustomMarker - { - float mWorldX; - float mWorldY; - - ESM::CellId mCell; - - std::string mNote; - - bool operator == (const CustomMarker& other) - { - return mNote == other.mNote && mCell == other.mCell && mWorldX == other.mWorldX && mWorldY == other.mWorldY; - } - - void load (ESM::ESMReader& reader); - void save (ESM::ESMWriter& writer) const; - }; - class CustomMarkerCollection { public: - void addMarker(const CustomMarker& marker, bool triggerEvent=true); - void deleteMarker (const CustomMarker& marker); - void updateMarker(const CustomMarker& marker, const std::string& newNote); + void addMarker(const ESM::CustomMarker& marker, bool triggerEvent=true); + void deleteMarker (const ESM::CustomMarker& marker); + void updateMarker(const ESM::CustomMarker& marker, const std::string& newNote); void clear(); size_t size() const; - std::vector::const_iterator begin() const; - std::vector::const_iterator end() const; + std::vector::const_iterator begin() const; + std::vector::const_iterator end() const; typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void; EventHandle_Void eventMarkersChanged; private: - std::vector mMarkers; + std::vector mMarkers; }; class LocalMapBase @@ -233,7 +217,7 @@ namespace MWGui MWRender::GlobalMap* mGlobalMapRender; EditNoteDialog mEditNoteDialog; - CustomMarker mEditingMarker; + ESM::CustomMarker mEditingMarker; virtual void onPinToggled(); virtual void onTitleDoubleClicked(); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index d5a71bc77..5b2bbee90 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1612,7 +1612,7 @@ namespace MWGui writer.endRecord(ESM::REC_ASPL); } - for (std::vector::const_iterator it = mCustomMarkers.begin(); it != mCustomMarkers.end(); ++it) + for (std::vector::const_iterator it = mCustomMarkers.begin(); it != mCustomMarkers.end(); ++it) { writer.startRecord(ESM::REC_MARK); (*it).save(writer); @@ -1633,7 +1633,7 @@ namespace MWGui } else if (type == ESM::REC_MARK) { - CustomMarker marker; + ESM::CustomMarker marker; marker.load(reader); mCustomMarkers.addMarker(marker, false); } diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index a3e79758f..0578a44b0 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -63,7 +63,7 @@ add_component_dir (esm loadweap records aipackage effectlist spelllist variant variantimp loadtes3 cellref filter savedgame journalentry queststate locals globalscript player objectstate cellid cellstate globalmap lightstate inventorystate containerstate npcstate creaturestate dialoguestate statstate npcstats creaturestats weatherstate quickkeys fogstate spellstate activespells creaturelevliststate doorstate projectilestate debugprofile - aisequence magiceffects util + aisequence magiceffects util custommarkerstate ) add_component_dir (esmterrain diff --git a/components/esm/custommarkerstate.cpp b/components/esm/custommarkerstate.cpp new file mode 100644 index 000000000..dc81c123d --- /dev/null +++ b/components/esm/custommarkerstate.cpp @@ -0,0 +1,26 @@ +#include "custommarkerstate.hpp" + +#include "esmwriter.hpp" +#include "esmreader.hpp" + +namespace ESM +{ + +void CustomMarker::save(ESM::ESMWriter &esm) const +{ + esm.writeHNT("POSX", mWorldX); + esm.writeHNT("POSY", mWorldY); + mCell.save(esm); + if (!mNote.empty()) + esm.writeHNString("NOTE", mNote); +} + +void CustomMarker::load(ESM::ESMReader &esm) +{ + esm.getHNT(mWorldX, "POSX"); + esm.getHNT(mWorldY, "POSY"); + mCell.load(esm); + mNote = esm.getHNOString("NOTE"); +} + +} diff --git a/components/esm/custommarkerstate.hpp b/components/esm/custommarkerstate.hpp new file mode 100644 index 000000000..fc9286bfe --- /dev/null +++ b/components/esm/custommarkerstate.hpp @@ -0,0 +1,30 @@ +#ifndef OPENMW_ESM_CUSTOMMARKERSTATE_H +#define OPENMW_ESM_CUSTOMMARKERSTATE_H + +#include "cellid.hpp" + +namespace ESM +{ + +// format 0, saved games only +struct CustomMarker +{ + float mWorldX; + float mWorldY; + + ESM::CellId mCell; + + std::string mNote; + + bool operator == (const CustomMarker& other) + { + return mNote == other.mNote && mCell == other.mCell && mWorldX == other.mWorldX && mWorldY == other.mWorldY; + } + + void load (ESM::ESMReader& reader); + void save (ESM::ESMWriter& writer) const; +}; + +} + +#endif From ad398f0c65d2df8299d22bdb7182c5deb89e71ca Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 19 Jan 2015 01:06:45 +0100 Subject: [PATCH 0338/3725] ESSImport: convert kill counter --- apps/essimporter/CMakeLists.txt | 1 + apps/essimporter/converter.hpp | 29 +++++++++++++++++++++++++++++ apps/essimporter/importer.cpp | 5 ++++- apps/essimporter/importklst.cpp | 22 ++++++++++++++++++++++ apps/essimporter/importklst.hpp | 28 ++++++++++++++++++++++++++++ 5 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 apps/essimporter/importklst.cpp create mode 100644 apps/essimporter/importklst.hpp diff --git a/apps/essimporter/CMakeLists.txt b/apps/essimporter/CMakeLists.txt index 3d3e0860c..cf3218454 100644 --- a/apps/essimporter/CMakeLists.txt +++ b/apps/essimporter/CMakeLists.txt @@ -7,6 +7,7 @@ set(ESSIMPORTER_FILES importcellref.cpp importacdt.cpp importinventory.cpp + importklst.cpp importercontext.cpp converter.cpp convertacdt.cpp diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index 5f1961717..aee60f2e7 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -15,6 +15,7 @@ #include "importercontext.hpp" #include "importcellref.hpp" +#include "importklst.hpp" #include "convertacdt.hpp" #include "convertnpcc.hpp" @@ -93,6 +94,7 @@ public: mContext->mPlayer.mObject.mCreatureStats.mLevel = npc.mNpdt52.mLevel; mContext->mPlayerBase = npc; std::map empty; + // FIXME: not working? for (std::vector::const_iterator it = npc.mSpells.mList.begin(); it != npc.mSpells.mList.end(); ++it) mContext->mPlayer.mObject.mCreatureStats.mSpells.mSpells[*it] = empty; } @@ -245,6 +247,33 @@ private: std::vector mMarkers; }; +class ConvertKLST : public Converter +{ +public: + virtual void read(ESM::ESMReader& esm) + { + KLST klst; + klst.load(esm); + mKillCounter = klst.mKillCounter; + + mContext->mPlayer.mObject.mNpcStats.mWerewolfKills = klst.mWerewolfKills; + } + + virtual void write(ESM::ESMWriter &esm) + { + esm.startRecord(ESM::REC_DCOU); + for (std::map::const_iterator it = mKillCounter.begin(); it != mKillCounter.end(); ++it) + { + esm.writeHNString("ID__", it->first); + esm.writeHNT ("COUN", it->second); + } + esm.endRecord(ESM::REC_DCOU); + } + +private: + std::map mKillCounter; +}; + } #endif diff --git a/apps/essimporter/importer.cpp b/apps/essimporter/importer.cpp index 12136cdea..4cf41a861 100644 --- a/apps/essimporter/importer.cpp +++ b/apps/essimporter/importer.cpp @@ -146,7 +146,7 @@ namespace ESSImport { std::cout << "Different subrecord name (" << rec.mName << "." << sub.mName << " vs. " << sub2.mName << ") at (1) 0x" << std::hex << sub.mFileOffset << " (2) 0x" << sub2.mFileOffset << std::endl; - return; // TODO: try to recover + break; // TODO: try to recover } if (sub.mData != sub2.mData) @@ -177,6 +177,7 @@ namespace ESSImport void Importer::run() { + // construct Ogre::Root to gain access to image codecs Ogre::LogManager logman; Ogre::Root root; @@ -191,6 +192,7 @@ namespace ESSImport const unsigned int recREFR = ESM::FourCC<'R','E','F','R'>::value; const unsigned int recPCDT = ESM::FourCC<'P','C','D','T'>::value; const unsigned int recFMAP = ESM::FourCC<'F','M','A','P'>::value; + const unsigned int recKLST = ESM::FourCC<'K','L','S','T'>::value; std::map > converters; converters[ESM::REC_GLOB] = boost::shared_ptr(new ConvertGlobal()); @@ -201,6 +203,7 @@ namespace ESSImport converters[recREFR] = boost::shared_ptr(new ConvertREFR()); converters[recPCDT] = boost::shared_ptr(new ConvertPCDT()); converters[recFMAP] = boost::shared_ptr(new ConvertFMAP()); + converters[recKLST] = boost::shared_ptr(new ConvertKLST()); converters[ESM::REC_CELL] = boost::shared_ptr(new ConvertCell()); converters[ESM::REC_ALCH] = boost::shared_ptr(new DefaultConverter()); converters[ESM::REC_CLAS] = boost::shared_ptr(new ConvertClass()); diff --git a/apps/essimporter/importklst.cpp b/apps/essimporter/importklst.cpp new file mode 100644 index 000000000..daa1ab077 --- /dev/null +++ b/apps/essimporter/importklst.cpp @@ -0,0 +1,22 @@ +#include "importklst.hpp" + +#include + +namespace ESSImport +{ + + void KLST::load(ESM::ESMReader &esm) + { + while (esm.isNextSub("KNAM")) + { + std::string refId = esm.getHString(); + int count; + esm.getHNT(count, "CNAM"); + mKillCounter[refId] = count; + } + + mWerewolfKills = 0; + esm.getHNOT(mWerewolfKills, "INTV"); + } + +} diff --git a/apps/essimporter/importklst.hpp b/apps/essimporter/importklst.hpp new file mode 100644 index 000000000..e333e7150 --- /dev/null +++ b/apps/essimporter/importklst.hpp @@ -0,0 +1,28 @@ +#ifndef OPENMW_ESSIMPORT_KLST_H +#define OPENMW_ESSIMPORT_KLST_H + +#include +#include + +namespace ESM +{ + struct ESMReader; +} + +namespace ESSImport +{ + + /// Kill Stats + struct KLST + { + void load(ESM::ESMReader& esm); + + /// RefId, kill count + std::map mKillCounter; + + int mWerewolfKills; + }; + +} + +#endif From 235683e44943bc68528527f9da14953749126b21 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 19 Jan 2015 10:34:49 +0100 Subject: [PATCH 0339/3725] Remove LightState from openmw save format to streamline inventory loading --- apps/openmw/mwclass/light.cpp | 10 ++---- apps/openmw/mwworld/cellstore.cpp | 5 ++- apps/openmw/mwworld/containerstore.cpp | 36 ++++++++------------- apps/openmw/mwworld/containerstore.hpp | 2 +- components/CMakeLists.txt | 2 +- components/esm/inventorystate.cpp | 43 +++++++++----------------- components/esm/inventorystate.hpp | 7 +---- components/esm/lightstate.cpp | 21 ------------- components/esm/lightstate.hpp | 19 ------------ components/esm/objectstate.cpp | 8 +++++ components/esm/objectstate.hpp | 2 ++ 11 files changed, 45 insertions(+), 110 deletions(-) delete mode 100644 components/esm/lightstate.cpp delete mode 100644 components/esm/lightstate.hpp diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 669b8187c..c50ad52d8 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -2,7 +2,7 @@ #include "light.hpp" #include -#include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -285,21 +285,17 @@ namespace MWClass void Light::readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state) const { - const ESM::LightState& state2 = dynamic_cast (state); - ensureCustomData (ptr); - dynamic_cast (*ptr.getRefData().getCustomData()).mTime = state2.mTime; + dynamic_cast (*ptr.getRefData().getCustomData()).mTime = state.mTime; } void Light::writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state) const { - ESM::LightState& state2 = dynamic_cast (state); - ensureCustomData (ptr); - state2.mTime = dynamic_cast (*ptr.getRefData().getCustomData()).mTime; + state.mTime = dynamic_cast (*ptr.getRefData().getCustomData()).mTime; } std::string Light::getSound(const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 1c0e7e385..4cf99fdb7 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include @@ -624,7 +623,7 @@ namespace MWWorld writeReferenceCollection (writer, mIngreds); writeReferenceCollection (writer, mCreatureLists); writeReferenceCollection (writer, mItemLists); - writeReferenceCollection (writer, mLights); + writeReferenceCollection (writer, mLights); writeReferenceCollection (writer, mLockpicks); writeReferenceCollection (writer, mMiscItems); writeReferenceCollection (writer, mNpcs); @@ -708,7 +707,7 @@ namespace MWWorld case ESM::REC_LIGH: - readReferenceCollection (reader, mLights, contentFileMap); + readReferenceCollection (reader, mLights, contentFileMap); break; case ESM::REC_LOCK: diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index e9c968a07..bd14720f7 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -87,7 +87,7 @@ void MWWorld::ContainerStore::storeState (const LiveCellRef& ref, ESM::Object template void MWWorld::ContainerStore::storeStates (const CellRefList& collection, - std::vector > >& states, bool equipable) const + std::vector >& states, bool equipable) const { for (typename CellRefList::List::const_iterator iter (collection.mList.begin()); iter!=collection.mList.end(); ++iter) @@ -97,7 +97,7 @@ void MWWorld::ContainerStore::storeStates (const CellRefList& collection, ESM::ObjectState state; storeState (*iter, state); int slot = equipable ? getSlot (*iter) : -1; - states.push_back (std::make_pair (state, std::make_pair (T::sRecordId, slot))); + states.push_back (std::make_pair (state, slot)); } } @@ -656,30 +656,25 @@ void MWWorld::ContainerStore::writeState (ESM::InventoryState& state) const storeStates (probes, state.mItems, true); storeStates (repairs, state.mItems); storeStates (weapons, state.mItems, true); - - state.mLights.clear(); + storeStates (lights, state.mItems, true); state.mLevelledItemMap = mLevelledItemMap; - - for (MWWorld::CellRefList::List::const_iterator iter (lights.mList.begin()); - iter!=lights.mList.end(); ++iter) - { - ESM::LightState objectState; - storeState (*iter, objectState); - state.mLights.push_back (std::make_pair (objectState, getSlot (*iter))); - } } void MWWorld::ContainerStore::readState (const ESM::InventoryState& state) { clear(); - for (std::vector > >::const_iterator + for (std::vector >::const_iterator iter (state.mItems.begin()); iter!=state.mItems.end(); ++iter) { - int slot = iter->second.second; + int slot = iter->second; + + const ESM::ObjectState& state = iter->first; - switch (iter->second.first) + int type = MWBase::Environment::get().getWorld()->getStore().find(state.mRef.mRefID); + + switch (type) { case ESM::REC_ALCH: getState (potions, iter->first); break; case ESM::REC_APPA: getState (appas, iter->first); break; @@ -692,19 +687,14 @@ void MWWorld::ContainerStore::readState (const ESM::InventoryState& state) case ESM::REC_PROB: setSlot (getState (probes, iter->first), slot); break; case ESM::REC_REPA: getState (repairs, iter->first); break; case ESM::REC_WEAP: setSlot (getState (weapons, iter->first), slot); break; + case ESM::REC_LIGH: setSlot (getState (lights, iter->first), slot); break; default: - - std::cerr << "invalid item type in inventory state" << std::endl; + std::cerr << "invalid item type in inventory state, refid " << state.mRef.mRefID << std::endl; + break; } } - for (std::vector >::const_iterator iter (state.mLights.begin()); - iter!=state.mLights.end(); ++iter) - { - int slot = iter->second; - setSlot (getState (lights, iter->first), slot); - } mLevelledItemMap = state.mLevelledItemMap; } diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index 2849463c9..68ee41a1d 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -86,7 +86,7 @@ namespace MWWorld template void storeStates (const CellRefList& collection, - std::vector > >& states, + std::vector >& states, bool equipable = false) const; virtual int getSlot (const MWWorld::LiveCellRefBase& ref) const; diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 0578a44b0..93228f87a 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -61,7 +61,7 @@ add_component_dir (esm loadinfo loadingr loadland loadlevlist loadligh loadlock loadprob loadrepa loadltex loadmgef loadmisc loadnpcc loadnpc loadpgrd loadrace loadregn loadscpt loadskil loadsndg loadsoun loadspel loadsscr loadstat loadweap records aipackage effectlist spelllist variant variantimp loadtes3 cellref filter - savedgame journalentry queststate locals globalscript player objectstate cellid cellstate globalmap lightstate inventorystate containerstate npcstate creaturestate dialoguestate statstate + savedgame journalentry queststate locals globalscript player objectstate cellid cellstate globalmap inventorystate containerstate npcstate creaturestate dialoguestate statstate npcstats creaturestats weatherstate quickkeys fogstate spellstate activespells creaturelevliststate doorstate projectilestate debugprofile aisequence magiceffects util custommarkerstate ) diff --git a/components/esm/inventorystate.cpp b/components/esm/inventorystate.cpp index a2d49b144..fdaba3322 100644 --- a/components/esm/inventorystate.cpp +++ b/components/esm/inventorystate.cpp @@ -14,9 +14,10 @@ namespace state.load (esm); } - void write (ESM::ESMWriter &esm, const ESM::ObjectState& state, unsigned int type, int slot) + void write (ESM::ESMWriter &esm, const ESM::ObjectState& state, int slot) { - esm.writeHNT ("IOBJ", type); + int unused = 0; + esm.writeHNT ("IOBJ", unused); if (slot!=-1) esm.writeHNT ("SLOT", slot); @@ -29,27 +30,15 @@ void ESM::InventoryState::load (ESMReader &esm) { while (esm.isNextSub ("IOBJ")) { - unsigned int id = 0; - esm.getHT (id); - - if (id==ESM::REC_LIGH) - { - LightState state; - int slot; - read (esm, state, slot); - if (state.mCount == 0) - continue; - mLights.push_back (std::make_pair (state, slot)); - } - else - { - ObjectState state; - int slot; - read (esm, state, slot); - if (state.mCount == 0) - continue; - mItems.push_back (std::make_pair (state, std::make_pair (id, slot))); - } + int unused; // no longer used + esm.getHT(unused); + + ObjectState state; + int slot; + read (esm, state, slot); + if (state.mCount == 0) + continue; + mItems.push_back (std::make_pair (state, slot)); } while (esm.isNextSub("LEVM")) @@ -78,12 +67,8 @@ void ESM::InventoryState::load (ESMReader &esm) void ESM::InventoryState::save (ESMWriter &esm) const { - for (std::vector > >::const_iterator iter (mItems.begin()); iter!=mItems.end(); ++iter) - write (esm, iter->first, iter->second.first, iter->second.second); - - for (std::vector >::const_iterator iter (mLights.begin()); - iter!=mLights.end(); ++iter) - write (esm, iter->first, ESM::REC_LIGH, iter->second); + for (std::vector >::const_iterator iter (mItems.begin()); iter!=mItems.end(); ++iter) + write (esm, iter->first, iter->second); for (std::map::const_iterator it = mLevelledItemMap.begin(); it != mLevelledItemMap.end(); ++it) { diff --git a/components/esm/inventorystate.hpp b/components/esm/inventorystate.hpp index bd0b46a22..3d4407e7b 100644 --- a/components/esm/inventorystate.hpp +++ b/components/esm/inventorystate.hpp @@ -4,7 +4,6 @@ #include #include "objectstate.hpp" -#include "lightstate.hpp" namespace ESM { @@ -16,11 +15,7 @@ namespace ESM /// \brief State for inventories and containers struct InventoryState { - // anything but lights (type, slot) - std::vector > > mItems; - - // lights (slot) - std::vector > mLights; + std::vector > mItems; std::map mLevelledItemMap; diff --git a/components/esm/lightstate.cpp b/components/esm/lightstate.cpp deleted file mode 100644 index 1ef040823..000000000 --- a/components/esm/lightstate.cpp +++ /dev/null @@ -1,21 +0,0 @@ - -#include "lightstate.hpp" - -#include "esmreader.hpp" -#include "esmwriter.hpp" - -void ESM::LightState::load (ESMReader &esm) -{ - ObjectState::load (esm); - - mTime = 0; - esm.getHNOT (mTime, "LTIM"); -} - -void ESM::LightState::save (ESMWriter &esm, bool inInventory) const -{ - ObjectState::save (esm, inInventory); - - if (mTime) - esm.writeHNT ("LTIM", mTime); -} \ No newline at end of file diff --git a/components/esm/lightstate.hpp b/components/esm/lightstate.hpp deleted file mode 100644 index a22735e07..000000000 --- a/components/esm/lightstate.hpp +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef OPENMW_ESM_LIGHTSTATE_H -#define OPENMW_ESM_LIGHTSTATE_H - -#include "objectstate.hpp" - -namespace ESM -{ - // format 0, saved games only - - struct LightState : public ObjectState - { - float mTime; - - virtual void load (ESMReader &esm); - virtual void save (ESMWriter &esm, bool inInventory = false) const; - }; -} - -#endif diff --git a/components/esm/objectstate.cpp b/components/esm/objectstate.cpp index f7755f8cb..98cf3eba6 100644 --- a/components/esm/objectstate.cpp +++ b/components/esm/objectstate.cpp @@ -23,6 +23,10 @@ void ESM::ObjectState::load (ESMReader &esm) esm.getHNOT (mPosition, "POS_", 24); esm.getHNOT (mLocalRotation, "LROT", 12); + + // used for lights only + mTime = 0; + esm.getHNOT (mTime, "LTIM"); } void ESM::ObjectState::save (ESMWriter &esm, bool inInventory) const @@ -46,6 +50,9 @@ void ESM::ObjectState::save (ESMWriter &esm, bool inInventory) const esm.writeHNT ("POS_", mPosition, 24); esm.writeHNT ("LROT", mLocalRotation, 12); } + + if (mTime) + esm.writeHNT ("LTIM", mTime); } void ESM::ObjectState::blank() @@ -60,6 +67,7 @@ void ESM::ObjectState::blank() mPosition.rot[i] = 0; mLocalRotation[i] = 0; } + mTime = 0; } ESM::ObjectState::~ObjectState() {} diff --git a/components/esm/objectstate.hpp b/components/esm/objectstate.hpp index 5b05e0949..6b536bd01 100644 --- a/components/esm/objectstate.hpp +++ b/components/esm/objectstate.hpp @@ -26,6 +26,8 @@ namespace ESM ESM::Position mPosition; float mLocalRotation[3]; + float mTime; // Used for lights only. Overhead should not be so awful, besides CellRef isn't OO either + virtual void load (ESMReader &esm); virtual void save (ESMWriter &esm, bool inInventory = false) const; From f7e32a24c9f8550c018495860a2f9e0b4dc36194 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 19 Jan 2015 12:03:30 +0100 Subject: [PATCH 0340/3725] Fix terrain assertion --- components/esmterrain/storage.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/esmterrain/storage.cpp b/components/esmterrain/storage.cpp index 3c76cc3b4..a66193f97 100644 --- a/components/esmterrain/storage.cpp +++ b/components/esmterrain/storage.cpp @@ -402,8 +402,8 @@ namespace ESMTerrain int endX = startX + 1; int endY = startY + 1; - assert(endX < ESM::Land::LAND_SIZE); - assert(endY < ESM::Land::LAND_SIZE); + endX = std::min(endX, ESM::Land::LAND_SIZE-1); + endY = std::min(endY, ESM::Land::LAND_SIZE-1); // now get points in terrain space (effectively rounding them to boundaries) float startXTS = startX * invFactor; From a7b82e5107caed0fceb407abfa364071d0338053 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 19 Jan 2015 12:22:51 +0100 Subject: [PATCH 0341/3725] ESSImport: inventory loading works, equipment slots need more work --- apps/essimporter/CMakeLists.txt | 2 ++ apps/essimporter/convertcrec.cpp | 13 +++++++++++++ apps/essimporter/convertcrec.hpp | 15 +++++++++++++++ apps/essimporter/converter.cpp | 4 ++++ apps/essimporter/convertinventory.cpp | 23 +++++++++++++++++++++++ apps/essimporter/convertinventory.hpp | 15 +++++++++++++++ apps/essimporter/convertnpcc.cpp | 4 ++++ apps/essimporter/importinventory.cpp | 22 +++++++++++++++++++--- apps/essimporter/importinventory.hpp | 1 + components/esm/cellref.cpp | 4 ++-- 10 files changed, 98 insertions(+), 5 deletions(-) create mode 100644 apps/essimporter/convertcrec.cpp create mode 100644 apps/essimporter/convertcrec.hpp create mode 100644 apps/essimporter/convertinventory.cpp create mode 100644 apps/essimporter/convertinventory.hpp diff --git a/apps/essimporter/CMakeLists.txt b/apps/essimporter/CMakeLists.txt index cf3218454..1af55de9b 100644 --- a/apps/essimporter/CMakeLists.txt +++ b/apps/essimporter/CMakeLists.txt @@ -12,6 +12,8 @@ set(ESSIMPORTER_FILES converter.cpp convertacdt.cpp convertnpcc.cpp + convertinventory.cpp + convertcrec.cpp ) add_executable(openmw-essimporter diff --git a/apps/essimporter/convertcrec.cpp b/apps/essimporter/convertcrec.cpp new file mode 100644 index 000000000..34e1c0070 --- /dev/null +++ b/apps/essimporter/convertcrec.cpp @@ -0,0 +1,13 @@ +#include "convertcrec.hpp" + +#include "convertinventory.hpp" + +namespace ESSImport +{ + + void convertCREC(const CREC &crec, ESM::CreatureState &state) + { + convertInventory(crec.mInventory, state.mInventory); + } + +} diff --git a/apps/essimporter/convertcrec.hpp b/apps/essimporter/convertcrec.hpp new file mode 100644 index 000000000..7d317f03e --- /dev/null +++ b/apps/essimporter/convertcrec.hpp @@ -0,0 +1,15 @@ +#ifndef OPENMW_ESSIMPORT_CONVERTCREC_H +#define OPENMW_ESSIMPORT_CONVERTCREC_H + +#include "importcrec.hpp" + +#include + +namespace ESSImport +{ + + void convertCREC(const CREC& crec, ESM::CreatureState& state); + +} + +#endif diff --git a/apps/essimporter/converter.cpp b/apps/essimporter/converter.cpp index ce3cea675..22d6d8282 100644 --- a/apps/essimporter/converter.cpp +++ b/apps/essimporter/converter.cpp @@ -4,6 +4,8 @@ #include +#include "convertcrec.hpp" + namespace { @@ -197,6 +199,7 @@ namespace ESSImport ESM::CreatureState objstate; objstate.blank(); convertACDT(cellref.mActorData.mACDT, objstate.mCreatureStats); + convertCREC(crecIt->second, objstate); objstate.mEnabled = cellref.mEnabled; objstate.mPosition = cellref.mPos; objstate.mRef = out; @@ -215,6 +218,7 @@ namespace ESSImport objstate.blank(); convertACDT(cellref.mActorData.mACDT, objstate.mCreatureStats); convertNpcData(cellref.mActorData, objstate.mNpcStats); + convertNPCC(npccIt->second, objstate); objstate.mEnabled = cellref.mEnabled; objstate.mPosition = cellref.mPos; objstate.mRef = out; diff --git a/apps/essimporter/convertinventory.cpp b/apps/essimporter/convertinventory.cpp new file mode 100644 index 000000000..42535d946 --- /dev/null +++ b/apps/essimporter/convertinventory.cpp @@ -0,0 +1,23 @@ +#include "convertinventory.hpp" + +#include + +namespace ESSImport +{ + + void convertInventory(const Inventory &inventory, ESM::InventoryState &state) + { + for (std::vector::const_iterator it = inventory.mItems.begin(); + it != inventory.mItems.end(); ++it) + { + ESM::ObjectState objstate; + objstate.blank(); + objstate.mRef.mRefID = Misc::StringUtils::lowerCase(it->mId); + objstate.mCount = std::abs(it->mCount); // restocking items have negative count in the savefile + // openmw handles them differently, so no need to set any flags + objstate.mRef.mCharge = it->mCondition; + state.mItems.push_back(std::make_pair(objstate, -1)); + } + } + +} diff --git a/apps/essimporter/convertinventory.hpp b/apps/essimporter/convertinventory.hpp new file mode 100644 index 000000000..8abe85a44 --- /dev/null +++ b/apps/essimporter/convertinventory.hpp @@ -0,0 +1,15 @@ +#ifndef OPENMW_ESSIMPORT_CONVERTINVENTORY_H +#define OPENMW_ESSIMPORT_CONVERTINVENTORY_H + +#include "importinventory.hpp" + +#include + +namespace ESSImport +{ + + void convertInventory (const Inventory& inventory, ESM::InventoryState& state); + +} + +#endif diff --git a/apps/essimporter/convertnpcc.cpp b/apps/essimporter/convertnpcc.cpp index fdf96c15a..2155f46fb 100644 --- a/apps/essimporter/convertnpcc.cpp +++ b/apps/essimporter/convertnpcc.cpp @@ -1,10 +1,14 @@ #include "convertnpcc.hpp" +#include "convertinventory.hpp" + namespace ESSImport { void convertNPCC(const NPCC &npcc, ESM::NpcState &npcState) { npcState.mNpcStats.mReputation = npcc.mNPDT.mReputation; + + convertInventory(npcc.mInventory, npcState.mInventory); } } diff --git a/apps/essimporter/importinventory.cpp b/apps/essimporter/importinventory.cpp index d132fd76d..b3bd4a86b 100644 --- a/apps/essimporter/importinventory.cpp +++ b/apps/essimporter/importinventory.cpp @@ -2,6 +2,8 @@ #include +#include + namespace ESSImport { @@ -9,8 +11,12 @@ namespace ESSImport { while (esm.isNextSub("NPCO")) { + ESM::ContItem contItem; + esm.getHT(contItem); + InventoryItem item; - item.mId = esm.getHString(); + item.mId = contItem.mItem.toString(); + item.mCount = contItem.mCount; if (esm.isNextSub("XIDX")) esm.skipHSub(); @@ -32,14 +38,24 @@ namespace ESSImport item.ESM::CellRef::loadData(esm); item.mCondition = -1; + // FIXME: for Lights, this is actually a float esm.getHNOT(item.mCondition, "XHLT"); mItems.push_back(item); } + // equipped items while (esm.isNextSub("WIDX")) { - // equipping? - esm.skipHSub(); + // note: same item can be equipped 2 items (e.g. 2 rings) + // and will be *stacked* in the NPCO list, unlike openmw! + esm.getSubHeader(); + int itemIndex; // index of the item in the NPCO list + esm.getT(itemIndex); + + // appears to be a relative index for only the *possible* slots this item can be equipped in, + // i.e. 0 most of the time, unlike openmw slot enum index + int slotIndex; + esm.getT(slotIndex); } } diff --git a/apps/essimporter/importinventory.hpp b/apps/essimporter/importinventory.hpp index e31cab76a..359e43fa6 100644 --- a/apps/essimporter/importinventory.hpp +++ b/apps/essimporter/importinventory.hpp @@ -19,6 +19,7 @@ namespace ESSImport struct InventoryItem : public ESM::CellRef { std::string mId; + int mCount; int mCondition; }; std::vector mItems; diff --git a/components/esm/cellref.cpp b/components/esm/cellref.cpp index 43b1f4d29..0c2dfd5db 100644 --- a/components/esm/cellref.cpp +++ b/components/esm/cellref.cpp @@ -142,8 +142,8 @@ void ESM::CellRef::blank() mSoul.clear(); mFaction.clear(); mFactionRank = -2; - mCharge = 0; - mEnchantmentCharge = 0; + mCharge = -1; + mEnchantmentCharge = -1; mGoldValue = 0; mDestCell.clear(); mLockLevel = 0; From 8e1eeccbe190f3ec04fc60283313683e7ea7dac2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 19 Jan 2015 13:16:12 +0100 Subject: [PATCH 0342/3725] ESSImport: container state --- apps/essimporter/CMakeLists.txt | 2 + apps/essimporter/convertcntc.cpp | 13 +++ apps/essimporter/convertcntc.hpp | 15 +++ apps/essimporter/converter.cpp | 163 ++++++++++++++++----------- apps/essimporter/converter.hpp | 20 +++- apps/essimporter/importcntc.cpp | 16 +++ apps/essimporter/importcntc.hpp | 25 ++++ apps/essimporter/importer.cpp | 1 + apps/essimporter/importercontext.hpp | 2 + components/CMakeLists.txt | 2 +- components/esm/loadcrec.hpp | 49 -------- components/esm/records.hpp | 1 - 12 files changed, 189 insertions(+), 120 deletions(-) create mode 100644 apps/essimporter/convertcntc.cpp create mode 100644 apps/essimporter/convertcntc.hpp create mode 100644 apps/essimporter/importcntc.cpp create mode 100644 apps/essimporter/importcntc.hpp delete mode 100644 components/esm/loadcrec.hpp diff --git a/apps/essimporter/CMakeLists.txt b/apps/essimporter/CMakeLists.txt index 1af55de9b..8d1af714d 100644 --- a/apps/essimporter/CMakeLists.txt +++ b/apps/essimporter/CMakeLists.txt @@ -8,12 +8,14 @@ set(ESSIMPORTER_FILES importacdt.cpp importinventory.cpp importklst.cpp + importcntc.cpp importercontext.cpp converter.cpp convertacdt.cpp convertnpcc.cpp convertinventory.cpp convertcrec.cpp + convertcntc.cpp ) add_executable(openmw-essimporter diff --git a/apps/essimporter/convertcntc.cpp b/apps/essimporter/convertcntc.cpp new file mode 100644 index 000000000..426ef4496 --- /dev/null +++ b/apps/essimporter/convertcntc.cpp @@ -0,0 +1,13 @@ +#include "convertcntc.hpp" + +#include "convertinventory.hpp" + +namespace ESSImport +{ + + void convertCNTC(const CNTC &cntc, ESM::ContainerState &state) + { + convertInventory(cntc.mInventory, state.mInventory); + } + +} diff --git a/apps/essimporter/convertcntc.hpp b/apps/essimporter/convertcntc.hpp new file mode 100644 index 000000000..c299d87a1 --- /dev/null +++ b/apps/essimporter/convertcntc.hpp @@ -0,0 +1,15 @@ +#ifndef OPENMW_ESSIMPORT_CONVERTCNTC_H +#define OPENMW_ESSIMPORT_CONVERTCNTC_H + +#include "importcntc.hpp" + +#include + +namespace ESSImport +{ + + void convertCNTC(const CNTC& cntc, ESM::ContainerState& state); + +} + +#endif diff --git a/apps/essimporter/converter.cpp b/apps/essimporter/converter.cpp index 22d6d8282..293c48624 100644 --- a/apps/essimporter/converter.cpp +++ b/apps/essimporter/converter.cpp @@ -3,8 +3,10 @@ #include #include +#include #include "convertcrec.hpp" +#include "convertcntc.hpp" namespace { @@ -17,6 +19,13 @@ namespace screenshot.save(out); } + + void convertCellRef(const ESSImport::CellRef& cellref, ESM::ObjectState& objstate) + { + objstate.mEnabled = cellref.mEnabled; + objstate.mPosition = cellref.mPos; + objstate.mRef.mRefNum = cellref.mRefNum; + } } namespace ESSImport @@ -116,8 +125,9 @@ namespace ESSImport ref.load (esm); if (esm.isNextSub("DELE")) { + // TODO // strangely this can be e.g. 52 instead of just 1, - std::cout << "deleted ref " << ref.mIndexedRefId << std::endl; + //std::cout << "deleted ref " << ref.mIndexedRefId << std::endl; esm.skipHSub(); } cellrefs.push_back(ref); @@ -155,85 +165,104 @@ namespace ESSImport newcell.mRefs = cellrefs; - // FIXME: map by ID for exterior cells - mCells[id] = newcell; + + if (cell.isExterior()) + mExtCells[std::make_pair(cell.mData.mX, cell.mData.mY)] = newcell; + else + mIntCells[id] = newcell; } - void ConvertCell::write(ESM::ESMWriter &esm) + void ConvertCell::writeCell(const Cell &cell, ESM::ESMWriter& esm) { - for (std::map::const_iterator it = mCells.begin(); it != mCells.end(); ++it) + ESM::Cell esmcell = cell.mCell; + esm.startRecord(ESM::REC_CSTA); + ESM::CellState csta; + csta.mHasFogOfWar = 0; + csta.mId = esmcell.getCellId(); + csta.mId.save(esm); + // TODO csta.mLastRespawn; + // shouldn't be needed if we respawn on global schedule like in original MW + csta.mWaterLevel = esmcell.mWater; + csta.save(esm); + + for (std::vector::const_iterator refIt = cell.mRefs.begin(); refIt != cell.mRefs.end(); ++refIt) { - const ESM::Cell& cell = it->second.mCell; - esm.startRecord(ESM::REC_CSTA); - ESM::CellState csta; - csta.mHasFogOfWar = 0; - csta.mId = cell.getCellId(); - csta.mId.save(esm); - // TODO csta.mLastRespawn; - // shouldn't be needed if we respawn on global schedule like in original MW - csta.mWaterLevel = cell.mWater; - csta.save(esm); - - for (std::vector::const_iterator refIt = it->second.mRefs.begin(); refIt != it->second.mRefs.end(); ++refIt) - { - const CellRef& cellref = *refIt; - ESM::CellRef out; - out.blank(); + const CellRef& cellref = *refIt; + ESM::CellRef out; + out.blank(); - if (cellref.mIndexedRefId.size() < 8) - { - std::cerr << "CellRef with no index?" << std::endl; - continue; - } - std::stringstream stream; - stream << cellref.mIndexedRefId.substr(cellref.mIndexedRefId.size()-8,8); - int refIndex; - stream >> refIndex; + if (cellref.mIndexedRefId.size() < 8) + { + std::cerr << "CellRef with no index?" << std::endl; + continue; + } + std::stringstream stream; + stream << cellref.mIndexedRefId.substr(cellref.mIndexedRefId.size()-8,8); + int refIndex; + stream >> refIndex; - out.mRefID = cellref.mIndexedRefId.substr(0,cellref.mIndexedRefId.size()-8); + out.mRefID = cellref.mIndexedRefId.substr(0,cellref.mIndexedRefId.size()-8); - std::map, CREC>::const_iterator crecIt = mContext->mCreatureChanges.find( - std::make_pair(refIndex, out.mRefID)); - if (crecIt != mContext->mCreatureChanges.end()) - { - ESM::CreatureState objstate; - objstate.blank(); - convertACDT(cellref.mActorData.mACDT, objstate.mCreatureStats); - convertCREC(crecIt->second, objstate); - objstate.mEnabled = cellref.mEnabled; - objstate.mPosition = cellref.mPos; - objstate.mRef = out; - objstate.mRef.mRefNum = cellref.mRefNum; - // FIXME: change save format to not require object type, instead look up it up using the RefId - esm.writeHNT ("OBJE", ESM::REC_CREA); - objstate.save(esm); - continue; - } + std::map, CREC>::const_iterator crecIt = mContext->mCreatureChanges.find( + std::make_pair(refIndex, out.mRefID)); + if (crecIt != mContext->mCreatureChanges.end()) + { + ESM::CreatureState objstate; + objstate.blank(); + objstate.mRef = out; + convertACDT(cellref.mActorData.mACDT, objstate.mCreatureStats); + convertCREC(crecIt->second, objstate); + convertCellRef(cellref, objstate); + // FIXME: change save format to not require object type, instead look up it up using the RefId + esm.writeHNT ("OBJE", ESM::REC_CREA); + objstate.save(esm); + continue; + } - std::map, NPCC>::const_iterator npccIt = mContext->mNpcChanges.find( - std::make_pair(refIndex, out.mRefID)); - if (npccIt != mContext->mNpcChanges.end()) - { - ESM::NpcState objstate; - objstate.blank(); - convertACDT(cellref.mActorData.mACDT, objstate.mCreatureStats); - convertNpcData(cellref.mActorData, objstate.mNpcStats); - convertNPCC(npccIt->second, objstate); - objstate.mEnabled = cellref.mEnabled; - objstate.mPosition = cellref.mPos; - objstate.mRef = out; - objstate.mRef.mRefNum = cellref.mRefNum; - esm.writeHNT ("OBJE", ESM::REC_NPC_); - objstate.save(esm); - continue; - } + std::map, NPCC>::const_iterator npccIt = mContext->mNpcChanges.find( + std::make_pair(refIndex, out.mRefID)); + if (npccIt != mContext->mNpcChanges.end()) + { + ESM::NpcState objstate; + objstate.blank(); + objstate.mRef = out; + convertACDT(cellref.mActorData.mACDT, objstate.mCreatureStats); + convertNpcData(cellref.mActorData, objstate.mNpcStats); + convertNPCC(npccIt->second, objstate); + convertCellRef(cellref, objstate); + esm.writeHNT ("OBJE", ESM::REC_NPC_); + objstate.save(esm); + continue; + } - std::cerr << "Can't find type for " << refIndex << " " << out.mRefID << std::endl; + std::map, CNTC>::const_iterator cntcIt = mContext->mContainerChanges.find( + std::make_pair(refIndex, out.mRefID)); + if (cntcIt != mContext->mContainerChanges.end()) + { + ESM::ContainerState objstate; + objstate.blank(); + objstate.mRef = out; + convertCNTC(cntcIt->second, objstate); + convertCellRef(cellref, objstate); + esm.writeHNT ("OBJE", ESM::REC_CONT); + objstate.save(esm); + continue; } - esm.endRecord(ESM::REC_CSTA); + std::cerr << "Can't find type for " << refIndex << " " << out.mRefID << std::endl; } + esm.endRecord(ESM::REC_CSTA); + } + + void ConvertCell::write(ESM::ESMWriter &esm) + { + for (std::map::const_iterator it = mIntCells.begin(); it != mIntCells.end(); ++it) + writeCell(it->second, esm); + + for (std::map, Cell>::const_iterator it = mExtCells.begin(); it != mExtCells.end(); ++it) + writeCell(it->second, esm); + for (std::vector::const_iterator it = mMarkers.begin(); it != mMarkers.end(); ++it) { esm.startRecord(ESM::REC_MARK); diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index aee60f2e7..e758db964 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -12,6 +12,7 @@ #include #include "importcrec.hpp" +#include "importcntc.hpp" #include "importercontext.hpp" #include "importcellref.hpp" @@ -94,7 +95,8 @@ public: mContext->mPlayer.mObject.mCreatureStats.mLevel = npc.mNpdt52.mLevel; mContext->mPlayerBase = npc; std::map empty; - // FIXME: not working? + // FIXME: player start spells, racial spells and birthsign spells aren't listed here, + // need to fix openmw to account for this for (std::vector::const_iterator it = npc.mSpells.mList.begin(); it != npc.mSpells.mList.end(); ++it) mContext->mPlayer.mObject.mCreatureStats.mSpells.mSpells[*it] = empty; } @@ -209,6 +211,17 @@ public: } }; +class ConvertCNTC : public Converter +{ + virtual void read(ESM::ESMReader &esm) + { + std::string id = esm.getHNString("NAME"); + CNTC cntc; + cntc.load(esm); + mContext->mContainerChanges.insert(std::make_pair(std::make_pair(cntc.mIndex,id), cntc)); + } +}; + class ConvertCREC : public Converter { public: @@ -242,9 +255,12 @@ private: std::vector mFogOfWar; }; - std::map mCells; + std::map mIntCells; + std::map, Cell> mExtCells; std::vector mMarkers; + + void writeCell(const Cell& cell, ESM::ESMWriter &esm); }; class ConvertKLST : public Converter diff --git a/apps/essimporter/importcntc.cpp b/apps/essimporter/importcntc.cpp new file mode 100644 index 000000000..a492aef5a --- /dev/null +++ b/apps/essimporter/importcntc.cpp @@ -0,0 +1,16 @@ +#include "importcntc.hpp" + +#include + +namespace ESSImport +{ + + void CNTC::load(ESM::ESMReader &esm) + { + mIndex = 0; + esm.getHNT(mIndex, "INDX"); + + mInventory.load(esm); + } + +} diff --git a/apps/essimporter/importcntc.hpp b/apps/essimporter/importcntc.hpp new file mode 100644 index 000000000..1bc7d94bd --- /dev/null +++ b/apps/essimporter/importcntc.hpp @@ -0,0 +1,25 @@ +#ifndef OPENMW_ESSIMPORT_IMPORTCNTC_H +#define OPENMW_ESSIMPORT_IMPORTCNTC_H + +#include "importinventory.hpp" + +namespace ESM +{ + class ESMReader; +} + +namespace ESSImport +{ + + /// Changed container contents + struct CNTC + { + int mIndex; + + Inventory mInventory; + + void load(ESM::ESMReader& esm); + }; + +} +#endif diff --git a/apps/essimporter/importer.cpp b/apps/essimporter/importer.cpp index 4cf41a861..9075db404 100644 --- a/apps/essimporter/importer.cpp +++ b/apps/essimporter/importer.cpp @@ -215,6 +215,7 @@ namespace ESSImport converters[ESM::REC_WEAP] = boost::shared_ptr(new DefaultConverter()); converters[ESM::REC_LEVC] = boost::shared_ptr(new DefaultConverter()); converters[ESM::REC_LEVI] = boost::shared_ptr(new DefaultConverter()); + converters[ESM::REC_CNTC] = boost::shared_ptr(new ConvertCNTC()); std::set unknownRecords; diff --git a/apps/essimporter/importercontext.hpp b/apps/essimporter/importercontext.hpp index 9183e6179..a921b81ef 100644 --- a/apps/essimporter/importercontext.hpp +++ b/apps/essimporter/importercontext.hpp @@ -8,6 +8,7 @@ #include "importnpcc.hpp" #include "importcrec.hpp" +#include "importcntc.hpp" #include "importplayer.hpp" @@ -30,6 +31,7 @@ namespace ESSImport // key std::map, CREC> mCreatureChanges; std::map, NPCC> mNpcChanges; + std::map, CNTC> mContainerChanges; Context() { diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 93228f87a..a0500127c 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -57,7 +57,7 @@ add_component_dir (to_utf8 add_component_dir (esm attr defs esmcommon esmreader esmwriter loadacti loadalch loadappa loadarmo loadbody loadbook loadbsgn loadcell - loadclas loadclot loadcont loadcrea loadcrec loaddial loaddoor loadench loadfact loadglob loadgmst + loadclas loadclot loadcont loadcrea loaddial loaddoor loadench loadfact loadglob loadgmst loadinfo loadingr loadland loadlevlist loadligh loadlock loadprob loadrepa loadltex loadmgef loadmisc loadnpcc loadnpc loadpgrd loadrace loadregn loadscpt loadskil loadsndg loadsoun loadspel loadsscr loadstat loadweap records aipackage effectlist spelllist variant variantimp loadtes3 cellref filter diff --git a/components/esm/loadcrec.hpp b/components/esm/loadcrec.hpp deleted file mode 100644 index 280739aca..000000000 --- a/components/esm/loadcrec.hpp +++ /dev/null @@ -1,49 +0,0 @@ -#ifndef OPENMW_ESM_CREC_H -#define OPENMW_ESM_CREC_H - -#include - -// TODO create implementation files and remove this one -#include "esmreader.hpp" - -namespace ESM { - -class ESMReader; -class ESMWriter; - -/* These two are only used in save games. They are not decoded yet. - */ - -/// Changes a creature -struct LoadCREC -{ - static unsigned int sRecordId; - - std::string mId; - - void load(ESMReader &esm) - { - esm.skipRecord(); - } - - void save(ESMWriter &esm) const - { - } -}; - -/// Changes an item list / container -struct LoadCNTC -{ - std::string mId; - - void load(ESMReader &esm) - { - esm.skipRecord(); - } - - void save(ESMWriter &esm) const - { - } -}; -} -#endif diff --git a/components/esm/records.hpp b/components/esm/records.hpp index 7a0452eb3..c01c89d57 100644 --- a/components/esm/records.hpp +++ b/components/esm/records.hpp @@ -14,7 +14,6 @@ #include "loadclot.hpp" #include "loadcont.hpp" #include "loadcrea.hpp" -#include "loadcrec.hpp" #include "loadinfo.hpp" #include "loaddial.hpp" #include "loaddoor.hpp" From 9014dc48ee166ff9d3e5750971787056a318356e Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 19 Jan 2015 23:29:06 +0100 Subject: [PATCH 0343/3725] Don't require the object type id for reading references from savegames This is redundant, since we can look it up from the RefID. --- apps/openmw/mwclass/creature.cpp | 10 ++++- apps/openmw/mwclass/npc.cpp | 9 +++++ apps/openmw/mwworld/cellstore.cpp | 65 +++++++++++++++++++------------ components/esm/cellref.cpp | 8 +++- components/esm/cellref.hpp | 3 ++ components/esm/creaturestate.cpp | 14 +++++-- components/esm/esmreader.cpp | 11 ++++++ components/esm/esmreader.hpp | 3 ++ components/esm/inventorystate.cpp | 1 + components/esm/npcstate.cpp | 19 ++++++--- components/esm/objectstate.cpp | 10 ++++- components/esm/objectstate.hpp | 8 ++++ components/esm/player.cpp | 1 + 13 files changed, 123 insertions(+), 39 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index a3614af96..2e53fe802 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -816,6 +816,9 @@ namespace MWClass void Creature::readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state) const { + if (!state.mHasCustomState) + return; + const ESM::CreatureState& state2 = dynamic_cast (state); ensureCustomData(ptr); @@ -844,7 +847,6 @@ namespace MWClass customData.mContainerStore->readState (state2.mInventory); customData.mCreatureStats.readState (state2.mCreatureStats); - } void Creature::writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state) @@ -852,6 +854,12 @@ namespace MWClass { ESM::CreatureState& state2 = dynamic_cast (state); + if (!ptr.getRefData().getCustomData()) + { + state.mHasCustomState = false; + return; + } + ensureCustomData (ptr); CreatureCustomData& customData = dynamic_cast (*ptr.getRefData().getCustomData()); diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index ac4182734..8f62cc1e8 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -1275,6 +1275,9 @@ namespace MWClass void Npc::readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state) const { + if (!state.mHasCustomState) + return; + const ESM::NpcState& state2 = dynamic_cast (state); ensureCustomData(ptr); @@ -1302,6 +1305,12 @@ namespace MWClass { ESM::NpcState& state2 = dynamic_cast (state); + if (!ptr.getRefData().getCustomData()) + { + state.mHasCustomState = false; + return; + } + ensureCustomData (ptr); NpcCustomData& customData = dynamic_cast (*ptr.getRefData().getCustomData()); diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 4cf99fdb7..605c8f9d2 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -85,7 +85,9 @@ namespace RecordType state; iter->save (state); + // recordId currently unused writer.writeHNT ("OBJE", collection.mList.front().mBase->sRecordId); + state.save (writer); } } @@ -93,12 +95,13 @@ namespace template void readReferenceCollection (ESM::ESMReader& reader, - MWWorld::CellRefList& collection, const std::map& contentFileMap) + MWWorld::CellRefList& collection, const ESM::CellRef& cref, const std::map& contentFileMap) { const MWWorld::ESMStore& esmStore = MWBase::Environment::get().getWorld()->getStore(); RecordType state; - state.load (reader); + state.mRef = cref; + state.load(reader); // If the reference came from a content file, make sure this content file is loaded if (state.mRef.mRefNum.hasContentFile()) @@ -640,109 +643,121 @@ namespace MWWorld while (reader.isNextSub ("OBJE")) { - unsigned int id = 0; - reader.getHT (id); + unsigned int unused; + reader.getHT (unused); + + // load the RefID first so we know what type of object it is + ESM::CellRef cref; + cref.loadId(reader, true); + + int type = MWBase::Environment::get().getWorld()->getStore().find(cref.mRefID); + if (type == 0) + { + std::cerr << "Dropping reference to '" << cref.mRefID << "' (object no longer exists)" << std::endl; + reader.skipHSubUntil("OBJE"); + continue; + } - switch (id) + switch (type) { case ESM::REC_ACTI: - readReferenceCollection (reader, mActivators, contentFileMap); + readReferenceCollection (reader, mActivators, cref, contentFileMap); break; case ESM::REC_ALCH: - readReferenceCollection (reader, mPotions, contentFileMap); + readReferenceCollection (reader, mPotions, cref, contentFileMap); break; case ESM::REC_APPA: - readReferenceCollection (reader, mAppas, contentFileMap); + readReferenceCollection (reader, mAppas, cref, contentFileMap); break; case ESM::REC_ARMO: - readReferenceCollection (reader, mArmors, contentFileMap); + readReferenceCollection (reader, mArmors, cref, contentFileMap); break; case ESM::REC_BOOK: - readReferenceCollection (reader, mBooks, contentFileMap); + readReferenceCollection (reader, mBooks, cref, contentFileMap); break; case ESM::REC_CLOT: - readReferenceCollection (reader, mClothes, contentFileMap); + readReferenceCollection (reader, mClothes, cref, contentFileMap); break; case ESM::REC_CONT: - readReferenceCollection (reader, mContainers, contentFileMap); + readReferenceCollection (reader, mContainers, cref, contentFileMap); break; case ESM::REC_CREA: - readReferenceCollection (reader, mCreatures, contentFileMap); + readReferenceCollection (reader, mCreatures, cref, contentFileMap); break; case ESM::REC_DOOR: - readReferenceCollection (reader, mDoors, contentFileMap); + readReferenceCollection (reader, mDoors, cref, contentFileMap); break; case ESM::REC_INGR: - readReferenceCollection (reader, mIngreds, contentFileMap); + readReferenceCollection (reader, mIngreds, cref, contentFileMap); break; case ESM::REC_LEVC: - readReferenceCollection (reader, mCreatureLists, contentFileMap); + readReferenceCollection (reader, mCreatureLists, cref, contentFileMap); break; case ESM::REC_LEVI: - readReferenceCollection (reader, mItemLists, contentFileMap); + readReferenceCollection (reader, mItemLists, cref, contentFileMap); break; case ESM::REC_LIGH: - readReferenceCollection (reader, mLights, contentFileMap); + readReferenceCollection (reader, mLights, cref, contentFileMap); break; case ESM::REC_LOCK: - readReferenceCollection (reader, mLockpicks, contentFileMap); + readReferenceCollection (reader, mLockpicks, cref, contentFileMap); break; case ESM::REC_MISC: - readReferenceCollection (reader, mMiscItems, contentFileMap); + readReferenceCollection (reader, mMiscItems, cref, contentFileMap); break; case ESM::REC_NPC_: - readReferenceCollection (reader, mNpcs, contentFileMap); + readReferenceCollection (reader, mNpcs, cref, contentFileMap); break; case ESM::REC_PROB: - readReferenceCollection (reader, mProbes, contentFileMap); + readReferenceCollection (reader, mProbes, cref, contentFileMap); break; case ESM::REC_REPA: - readReferenceCollection (reader, mRepairs, contentFileMap); + readReferenceCollection (reader, mRepairs, cref, contentFileMap); break; case ESM::REC_STAT: - readReferenceCollection (reader, mStatics, contentFileMap); + readReferenceCollection (reader, mStatics, cref, contentFileMap); break; case ESM::REC_WEAP: - readReferenceCollection (reader, mWeapons, contentFileMap); + readReferenceCollection (reader, mWeapons, cref, contentFileMap); break; default: diff --git a/components/esm/cellref.cpp b/components/esm/cellref.cpp index 0c2dfd5db..cd9fe8570 100644 --- a/components/esm/cellref.cpp +++ b/components/esm/cellref.cpp @@ -5,6 +5,12 @@ #include "esmwriter.hpp" void ESM::CellRef::load (ESMReader& esm, bool wideRefNum) +{ + loadId(esm, wideRefNum); + loadData(esm); +} + +void ESM::CellRef::loadId(ESMReader &esm, bool wideRefNum) { // According to Hrnchamd, this does not belong to the actual ref. Instead, it is a marker indicating that // the following refs are part of a "temp refs" section. A temp ref is not being tracked by the moved references system. @@ -19,8 +25,6 @@ void ESM::CellRef::load (ESMReader& esm, bool wideRefNum) esm.getHNT (mRefNum.mIndex, "FRMR"); mRefID = esm.getHNString ("NAME"); - - loadData(esm); } void ESM::CellRef::loadData(ESMReader &esm) diff --git a/components/esm/cellref.hpp b/components/esm/cellref.hpp index b7b00a654..7aa0e4d44 100644 --- a/components/esm/cellref.hpp +++ b/components/esm/cellref.hpp @@ -89,8 +89,11 @@ namespace ESM // Position and rotation of this object within the cell Position mPos; + /// Calls loadId and loadData void load (ESMReader& esm, bool wideRefNum = false); + void loadId (ESMReader& esm, bool wideRefNum = false); + /// Implicitly called by load void loadData (ESMReader& esm); diff --git a/components/esm/creaturestate.cpp b/components/esm/creaturestate.cpp index c2838f78d..c15becd98 100644 --- a/components/esm/creaturestate.cpp +++ b/components/esm/creaturestate.cpp @@ -5,18 +5,24 @@ void ESM::CreatureState::load (ESMReader &esm) { ObjectState::load (esm); - mInventory.load (esm); + if (mHasCustomState) + { + mInventory.load (esm); - mCreatureStats.load (esm); + mCreatureStats.load (esm); + } } void ESM::CreatureState::save (ESMWriter &esm, bool inInventory) const { ObjectState::save (esm, inInventory); - mInventory.save (esm); + if (mHasCustomState) + { + mInventory.save (esm); - mCreatureStats.save (esm); + mCreatureStats.save (esm); + } } void ESM::CreatureState::blank() diff --git a/components/esm/esmreader.cpp b/components/esm/esmreader.cpp index 7cf0de1a9..de110dd18 100644 --- a/components/esm/esmreader.cpp +++ b/components/esm/esmreader.cpp @@ -210,6 +210,17 @@ void ESMReader::skipHSubSize(int size) fail("skipHSubSize() mismatch"); } +void ESMReader::skipHSubUntil(const char *name) +{ + while (hasMoreSubs() && !isNextSub(name)) + { + mCtx.subCached = false; + skipHSub(); + } + if (hasMoreSubs()) + mCtx.subCached = true; +} + void ESMReader::getSubHeader() { if (mCtx.leftRec < 4) diff --git a/components/esm/esmreader.hpp b/components/esm/esmreader.hpp index 642ec4168..bb615af11 100644 --- a/components/esm/esmreader.hpp +++ b/components/esm/esmreader.hpp @@ -195,6 +195,9 @@ public: // Skip sub record and check its size void skipHSubSize(int size); + // Skip all subrecords until the given subrecord or no more subrecords remaining + void skipHSubUntil(const char* name); + /* Sub-record header. This updates leftRec beyond the current sub-record as well. leftSub contains size of current sub-record. */ diff --git a/components/esm/inventorystate.cpp b/components/esm/inventorystate.cpp index fdaba3322..b946f9501 100644 --- a/components/esm/inventorystate.cpp +++ b/components/esm/inventorystate.cpp @@ -11,6 +11,7 @@ namespace slot = -1; esm.getHNOT (slot, "SLOT"); + state.mRef.loadId(esm, true); state.load (esm); } diff --git a/components/esm/npcstate.cpp b/components/esm/npcstate.cpp index 6134193c2..724d67326 100644 --- a/components/esm/npcstate.cpp +++ b/components/esm/npcstate.cpp @@ -5,22 +5,28 @@ void ESM::NpcState::load (ESMReader &esm) { ObjectState::load (esm); - mInventory.load (esm); + if (mHasCustomState) + { + mInventory.load (esm); - mNpcStats.load (esm); + mNpcStats.load (esm); - mCreatureStats.load (esm); + mCreatureStats.load (esm); + } } void ESM::NpcState::save (ESMWriter &esm, bool inInventory) const { ObjectState::save (esm, inInventory); - mInventory.save (esm); + if (mHasCustomState) + { + mInventory.save (esm); - mNpcStats.save (esm); + mNpcStats.save (esm); - mCreatureStats.save (esm); + mCreatureStats.save (esm); + } } void ESM::NpcState::blank() @@ -28,4 +34,5 @@ void ESM::NpcState::blank() ObjectState::blank(); mNpcStats.blank(); mCreatureStats.blank(); + mHasCustomState = true; } diff --git a/components/esm/objectstate.cpp b/components/esm/objectstate.cpp index 98cf3eba6..66fd49663 100644 --- a/components/esm/objectstate.cpp +++ b/components/esm/objectstate.cpp @@ -6,7 +6,7 @@ void ESM::ObjectState::load (ESMReader &esm) { - mRef.load (esm, true); + mRef.loadData(esm); mHasLocals = 0; esm.getHNOT (mHasLocals, "HLOC"); @@ -27,6 +27,10 @@ void ESM::ObjectState::load (ESMReader &esm) // used for lights only mTime = 0; esm.getHNOT (mTime, "LTIM"); + + // FIXME: assuming "false" as default would make more sense, but also break compatibility with older save files + mHasCustomState = true; + esm.getHNOT (mHasCustomState, "HCUS"); } void ESM::ObjectState::save (ESMWriter &esm, bool inInventory) const @@ -53,6 +57,9 @@ void ESM::ObjectState::save (ESMWriter &esm, bool inInventory) const if (mTime) esm.writeHNT ("LTIM", mTime); + + if (!mHasCustomState) + esm.writeHNT ("HCUS", false); } void ESM::ObjectState::blank() @@ -68,6 +75,7 @@ void ESM::ObjectState::blank() mLocalRotation[i] = 0; } mTime = 0; + mHasCustomState = true; } ESM::ObjectState::~ObjectState() {} diff --git a/components/esm/objectstate.hpp b/components/esm/objectstate.hpp index 6b536bd01..b03689653 100644 --- a/components/esm/objectstate.hpp +++ b/components/esm/objectstate.hpp @@ -28,7 +28,15 @@ namespace ESM float mTime; // Used for lights only. Overhead should not be so awful, besides CellRef isn't OO either + // Is there any class-specific state following the ObjectState + bool mHasCustomState; + + ObjectState() : mHasCustomState(true) + {} + + /// @note Does not load the CellRef ID, it should already be loaded before calling this method virtual void load (ESMReader &esm); + virtual void save (ESMWriter &esm, bool inInventory = false) const; /// Initialize to default state diff --git a/components/esm/player.cpp b/components/esm/player.cpp index 52b44c945..70c4b79e2 100644 --- a/components/esm/player.cpp +++ b/components/esm/player.cpp @@ -6,6 +6,7 @@ void ESM::Player::load (ESMReader &esm) { + mObject.mRef.loadId(esm, true); mObject.load (esm); mCellId.load (esm); From 40c29abe20445d8cdd61b3dc63ce8e63891757c4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 19 Jan 2015 23:51:43 +0100 Subject: [PATCH 0344/3725] ESSImport: convert other references (non-creature/npc/container) --- apps/essimporter/converter.cpp | 129 ++++++++++++++++++----------- apps/essimporter/converter.hpp | 9 +- apps/essimporter/importcellref.cpp | 9 +- apps/essimporter/importnpcc.cpp | 3 - apps/essimporter/importnpcc.hpp | 2 - 5 files changed, 95 insertions(+), 57 deletions(-) diff --git a/apps/essimporter/converter.cpp b/apps/essimporter/converter.cpp index 293c48624..83ea077ea 100644 --- a/apps/essimporter/converter.cpp +++ b/apps/essimporter/converter.cpp @@ -26,6 +26,17 @@ namespace objstate.mPosition = cellref.mPos; objstate.mRef.mRefNum = cellref.mRefNum; } + + bool isIndexedRefId(const std::string& indexedRefId) + { + if (indexedRefId.size() <= 8) + return false; + + std::string index = indexedRefId.substr(indexedRefId.size()-8); + if(index.find_first_not_of("0123456789ABCDEF") == std::string::npos ) + return true; + return false; + } } namespace ESSImport @@ -191,65 +202,87 @@ namespace ESSImport ESM::CellRef out; out.blank(); - if (cellref.mIndexedRefId.size() < 8) + if (!isIndexedRefId(cellref.mIndexedRefId)) { - std::cerr << "CellRef with no index?" << std::endl; - continue; - } - std::stringstream stream; - stream << cellref.mIndexedRefId.substr(cellref.mIndexedRefId.size()-8,8); - int refIndex; - stream >> refIndex; + // non-indexed RefNum, i.e. no CREC/NPCC/CNTC record associated with it + // this could be any type of object really (even creatures/npcs too) + out.mRefID = cellref.mIndexedRefId; + std::string idLower = Misc::StringUtils::lowerCase(out.mRefID); - out.mRefID = cellref.mIndexedRefId.substr(0,cellref.mIndexedRefId.size()-8); - - std::map, CREC>::const_iterator crecIt = mContext->mCreatureChanges.find( - std::make_pair(refIndex, out.mRefID)); - if (crecIt != mContext->mCreatureChanges.end()) - { - ESM::CreatureState objstate; + ESM::ObjectState objstate; objstate.blank(); objstate.mRef = out; - convertACDT(cellref.mActorData.mACDT, objstate.mCreatureStats); - convertCREC(crecIt->second, objstate); + objstate.mRef.mRefID = idLower; + objstate.mHasCustomState = false; convertCellRef(cellref, objstate); - // FIXME: change save format to not require object type, instead look up it up using the RefId - esm.writeHNT ("OBJE", ESM::REC_CREA); + esm.writeHNT ("OBJE", 0); objstate.save(esm); continue; } - - std::map, NPCC>::const_iterator npccIt = mContext->mNpcChanges.find( - std::make_pair(refIndex, out.mRefID)); - if (npccIt != mContext->mNpcChanges.end()) + else { - ESM::NpcState objstate; - objstate.blank(); - objstate.mRef = out; - convertACDT(cellref.mActorData.mACDT, objstate.mCreatureStats); - convertNpcData(cellref.mActorData, objstate.mNpcStats); - convertNPCC(npccIt->second, objstate); - convertCellRef(cellref, objstate); - esm.writeHNT ("OBJE", ESM::REC_NPC_); - objstate.save(esm); - continue; - } + std::stringstream stream; + stream << std::hex << cellref.mIndexedRefId.substr(cellref.mIndexedRefId.size()-8,8); + int refIndex; + stream >> refIndex; - std::map, CNTC>::const_iterator cntcIt = mContext->mContainerChanges.find( - std::make_pair(refIndex, out.mRefID)); - if (cntcIt != mContext->mContainerChanges.end()) - { - ESM::ContainerState objstate; - objstate.blank(); - objstate.mRef = out; - convertCNTC(cntcIt->second, objstate); - convertCellRef(cellref, objstate); - esm.writeHNT ("OBJE", ESM::REC_CONT); - objstate.save(esm); - continue; - } + out.mRefID = cellref.mIndexedRefId.substr(0,cellref.mIndexedRefId.size()-8); + std::string idLower = Misc::StringUtils::lowerCase(out.mRefID); + + std::map, NPCC>::const_iterator npccIt = mContext->mNpcChanges.find( + std::make_pair(refIndex, out.mRefID)); + if (npccIt != mContext->mNpcChanges.end()) + { + ESM::NpcState objstate; + objstate.blank(); + objstate.mRef = out; + objstate.mRef.mRefID = idLower; + // probably need more micromanagement here so we don't overwrite values + // from the ESM with default values + convertACDT(cellref.mActorData.mACDT, objstate.mCreatureStats); + convertNpcData(cellref.mActorData, objstate.mNpcStats); + convertNPCC(npccIt->second, objstate); + convertCellRef(cellref, objstate); + esm.writeHNT ("OBJE", ESM::REC_NPC_); + objstate.save(esm); + continue; + } + + std::map, CNTC>::const_iterator cntcIt = mContext->mContainerChanges.find( + std::make_pair(refIndex, out.mRefID)); + if (cntcIt != mContext->mContainerChanges.end()) + { + ESM::ContainerState objstate; + objstate.blank(); + objstate.mRef = out; + objstate.mRef.mRefID = idLower; + convertCNTC(cntcIt->second, objstate); + convertCellRef(cellref, objstate); + esm.writeHNT ("OBJE", ESM::REC_CONT); + objstate.save(esm); + continue; + } - std::cerr << "Can't find type for " << refIndex << " " << out.mRefID << std::endl; + std::map, CREC>::const_iterator crecIt = mContext->mCreatureChanges.find( + std::make_pair(refIndex, out.mRefID)); + if (crecIt != mContext->mCreatureChanges.end()) + { + ESM::CreatureState objstate; + objstate.blank(); + objstate.mRef = out; + objstate.mRef.mRefID = idLower; + convertACDT(cellref.mActorData.mACDT, objstate.mCreatureStats); + // probably need more micromanagement here so we don't overwrite values + // from the ESM with default values + convertCREC(crecIt->second, objstate); + convertCellRef(cellref, objstate); + esm.writeHNT ("OBJE", ESM::REC_CREA); + objstate.save(esm); + continue; + } + + std::cerr << "Can't find type for " << cellref.mIndexedRefId << std::endl; + } } esm.endRecord(ESM::REC_CSTA); diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index e758db964..187386b9d 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -167,8 +167,14 @@ public: convertNPCC(npcc, mContext->mPlayer.mObject); } else - mContext->mNpcChanges.insert(std::make_pair(std::make_pair(npcc.mIndex,id), npcc)); + { + int index = mIndexCounter[id]++; + mContext->mNpcChanges.insert(std::make_pair(std::make_pair(index,id), npcc)).second; + } } + +private: + std::map mIndexCounter; }; class ConvertREFR : public Converter @@ -230,7 +236,6 @@ public: std::string id = esm.getHNString("NAME"); CREC crec; crec.load(esm); - mContext->mCreatureChanges.insert(std::make_pair(std::make_pair(crec.mIndex,id), crec)); } }; diff --git a/apps/essimporter/importcellref.cpp b/apps/essimporter/importcellref.cpp index 8c2b8f36d..fd58d5bc1 100644 --- a/apps/essimporter/importcellref.cpp +++ b/apps/essimporter/importcellref.cpp @@ -18,8 +18,13 @@ namespace ESSImport mIndexedRefId = esm.getHNString("NAME"); if (esm.isNextSub("LVCR")) - esm.skipHSub(); - + { + // occurs on leveled creature spawner references + // probably some identifier for the the creature that has been spawned? + unsigned char lvcr; + esm.getHT(lvcr); + //std::cout << "LVCR: " << (int)lvcr << std::endl; + } mActorData.load(esm); mEnabled = true; diff --git a/apps/essimporter/importnpcc.cpp b/apps/essimporter/importnpcc.cpp index 8400a9e4a..c389ede7f 100644 --- a/apps/essimporter/importnpcc.cpp +++ b/apps/essimporter/importnpcc.cpp @@ -7,9 +7,6 @@ namespace ESSImport void NPCC::load(ESM::ESMReader &esm) { - mIndex = 0; - esm.getHNOT(mIndex, "INDX"); - esm.getHNT(mNPDT, "NPDT"); if (esm.isNextSub("AI_E")) diff --git a/apps/essimporter/importnpcc.hpp b/apps/essimporter/importnpcc.hpp index f3c4e24c7..2f474aba0 100644 --- a/apps/essimporter/importnpcc.hpp +++ b/apps/essimporter/importnpcc.hpp @@ -26,8 +26,6 @@ namespace ESSImport Inventory mInventory; - int mIndex; - void load(ESM::ESMReader &esm); }; From 5104a5a0235061454c8aae984e88dce6b928be8c Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 19 Jan 2015 23:55:17 +0100 Subject: [PATCH 0345/3725] Add missing setFactionReaction instruction, use absolute storage instead of difference Seems to be closer to how MW is storing it (it has the complete FACT record in the savegame, actually). This (somewhat) breaks OMW savegame compatibility in that old changes are discarded, but I don't think the faction reactions are quest relevant anywhere. --- apps/openmw/mwbase/dialoguemanager.hpp | 2 ++ apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 36 ++++++++++++------- apps/openmw/mwdialogue/dialoguemanagerimp.hpp | 4 ++- apps/openmw/mwscript/dialogueextensions.cpp | 20 +++++++++++ apps/openmw/mwscript/docs/vmformat.txt | 3 +- components/compiler/extensions0.cpp | 1 + components/compiler/opcodes.hpp | 1 + components/esm/dialoguestate.cpp | 17 ++++++--- components/esm/dialoguestate.hpp | 2 +- 9 files changed, 66 insertions(+), 20 deletions(-) diff --git a/apps/openmw/mwbase/dialoguemanager.hpp b/apps/openmw/mwbase/dialoguemanager.hpp index d0e64b23c..d35b5950f 100644 --- a/apps/openmw/mwbase/dialoguemanager.hpp +++ b/apps/openmw/mwbase/dialoguemanager.hpp @@ -74,6 +74,8 @@ namespace MWBase /// Changes faction1's opinion of faction2 by \a diff. virtual void modFactionReaction (const std::string& faction1, const std::string& faction2, int diff) = 0; + virtual void setFactionReaction (const std::string& faction1, const std::string& faction2, int absolute) = 0; + /// @return faction1's opinion of faction2 virtual int getFactionReaction (const std::string& faction1, const std::string& faction2) const = 0; diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index dd0fa21fa..0ee7dfe94 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -640,7 +640,7 @@ namespace MWDialogue if (iter->second) state.mKnownTopics.push_back (iter->first); - state.mModFactionReaction = mModFactionReaction; + state.mChangedFactionReaction = mChangedFactionReaction; writer.startRecord (ESM::REC_DIAS); state.save (writer); @@ -661,7 +661,7 @@ namespace MWDialogue if (store.get().search (*iter)) mKnownTopics.insert (std::make_pair (*iter, true)); - mModFactionReaction = state.mModFactionReaction; + mChangedFactionReaction = state.mChangedFactionReaction; } } @@ -674,10 +674,23 @@ namespace MWDialogue MWBase::Environment::get().getWorld()->getStore().get().find(fact1); MWBase::Environment::get().getWorld()->getStore().get().find(fact2); - std::map& map = mModFactionReaction[fact1]; - if (map.find(fact2) == map.end()) - map[fact2] = 0; - map[fact2] += diff; + int newValue = getFactionReaction(faction1, faction2) + diff; + + std::map& map = mChangedFactionReaction[fact1]; + map[fact2] = newValue; + } + + void DialogueManager::setFactionReaction(const std::string &faction1, const std::string &faction2, int absolute) + { + std::string fact1 = Misc::StringUtils::lowerCase(faction1); + std::string fact2 = Misc::StringUtils::lowerCase(faction2); + + // Make sure the factions exist + MWBase::Environment::get().getWorld()->getStore().get().find(fact1); + MWBase::Environment::get().getWorld()->getStore().get().find(fact2); + + std::map& map = mChangedFactionReaction[fact1]; + map[fact2] = absolute; } int DialogueManager::getFactionReaction(const std::string &faction1, const std::string &faction2) const @@ -685,10 +698,9 @@ namespace MWDialogue std::string fact1 = Misc::StringUtils::lowerCase(faction1); std::string fact2 = Misc::StringUtils::lowerCase(faction2); - ModFactionReactionMap::const_iterator map = mModFactionReaction.find(fact1); - int diff = 0; - if (map != mModFactionReaction.end() && map->second.find(fact2) != map->second.end()) - diff = map->second.at(fact2); + ModFactionReactionMap::const_iterator map = mChangedFactionReaction.find(fact1); + if (map != mChangedFactionReaction.end() && map->second.find(fact2) != map->second.end()) + return map->second.at(fact2); const ESM::Faction* faction = MWBase::Environment::get().getWorld()->getStore().get().find(fact1); @@ -696,9 +708,9 @@ namespace MWDialogue for (; it != faction->mReactions.end(); ++it) { if (Misc::StringUtils::ciEqual(it->first, fact2)) - return it->second + diff; + return it->second; } - return diff; + return 0; } void DialogueManager::clearInfoActor(const MWWorld::Ptr &actor) const diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp index 9c3d0d54b..c06299736 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp @@ -27,7 +27,7 @@ namespace MWDialogue // Modified faction reactions. > typedef std::map > ModFactionReactionMap; - ModFactionReactionMap mModFactionReaction; + ModFactionReactionMap mChangedFactionReaction; std::list mActorKnownTopics; @@ -97,6 +97,8 @@ namespace MWDialogue /// Changes faction1's opinion of faction2 by \a diff. virtual void modFactionReaction (const std::string& faction1, const std::string& faction2, int diff); + virtual void setFactionReaction (const std::string& faction1, const std::string& faction2, int absolute); + /// @return faction1's opinion of faction2 virtual int getFactionReaction (const std::string& faction1, const std::string& faction2) const; diff --git a/apps/openmw/mwscript/dialogueextensions.cpp b/apps/openmw/mwscript/dialogueextensions.cpp index 563a9dde3..1d82b8418 100644 --- a/apps/openmw/mwscript/dialogueextensions.cpp +++ b/apps/openmw/mwscript/dialogueextensions.cpp @@ -236,6 +236,25 @@ namespace MWScript } }; + class OpSetFactionReaction : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + std::string faction1 = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + std::string faction2 = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + int newValue = runtime[0].mInteger; + runtime.pop(); + + MWBase::Environment::get().getDialogueManager()->setFactionReaction(faction1, faction2, newValue); + } + }; + template class OpClearInfoActor : public Interpreter::Opcode0 { @@ -268,6 +287,7 @@ namespace MWScript interpreter.installSegment5 (Compiler::Dialogue::opcodeSameFaction, new OpSameFaction); interpreter.installSegment5 (Compiler::Dialogue::opcodeSameFactionExplicit, new OpSameFaction); interpreter.installSegment5 (Compiler::Dialogue::opcodeModFactionReaction, new OpModFactionReaction); + interpreter.installSegment5 (Compiler::Dialogue::opcodeSetFactionReaction, new OpSetFactionReaction); interpreter.installSegment5 (Compiler::Dialogue::opcodeGetFactionReaction, new OpGetFactionReaction); interpreter.installSegment5 (Compiler::Dialogue::opcodeClearInfoActor, new OpClearInfoActor); interpreter.installSegment5 (Compiler::Dialogue::opcodeClearInfoActorExplicit, new OpClearInfoActor); diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index 172e1b528..b139d6138 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -442,5 +442,6 @@ op 0x20002fb: AddToLevCreature op 0x20002fc: RemoveFromLevCreature op 0x20002fd: AddToLevItem op 0x20002fe: RemoveFromLevItem +op 0x20002ff: SetFactionReaction -opcodes 0x20002ff-0x3ffffff unused +opcodes 0x2000300-0x3ffffff unused diff --git a/components/compiler/extensions0.cpp b/components/compiler/extensions0.cpp index 234c5b12d..a5cc0da62 100644 --- a/components/compiler/extensions0.cpp +++ b/components/compiler/extensions0.cpp @@ -192,6 +192,7 @@ namespace Compiler extensions.registerFunction("samefaction", 'l', "", opcodeSameFaction, opcodeSameFactionExplicit); extensions.registerInstruction("modfactionreaction", "ccl", opcodeModFactionReaction); + extensions.registerInstruction("setfactionreaction", "ccl", opcodeSetFactionReaction); extensions.registerFunction("getfactionreaction", 'l', "ccX", opcodeGetFactionReaction); extensions.registerInstruction("clearinfoactor", "", opcodeClearInfoActor, opcodeClearInfoActorExplicit); } diff --git a/components/compiler/opcodes.hpp b/components/compiler/opcodes.hpp index bbafd6b13..04666e976 100644 --- a/components/compiler/opcodes.hpp +++ b/components/compiler/opcodes.hpp @@ -167,6 +167,7 @@ namespace Compiler const int opcodeSameFaction = 0x20001b5; const int opcodeSameFactionExplicit = 0x20001b6; const int opcodeModFactionReaction = 0x2000242; + const int opcodeSetFactionReaction = 0x20002ff; const int opcodeGetFactionReaction = 0x2000243; const int opcodeClearInfoActor = 0x2000245; const int opcodeClearInfoActorExplicit = 0x2000246; diff --git a/components/esm/dialoguestate.cpp b/components/esm/dialoguestate.cpp index 14301ac19..f546462a3 100644 --- a/components/esm/dialoguestate.cpp +++ b/components/esm/dialoguestate.cpp @@ -13,13 +13,20 @@ void ESM::DialogueState::load (ESMReader &esm) { std::string faction = esm.getHString(); - while (esm.isNextSub ("REAC")) + while (esm.isNextSub("REA2")) { std::string faction2 = esm.getHString(); int reaction; esm.getHNT(reaction, "INTV"); + mChangedFactionReaction[faction][faction2] = reaction; + } - mModFactionReaction[faction][faction2] = reaction; + // no longer used + while (esm.isNextSub ("REAC")) + { + esm.skipHSub(); + esm.getSubHeader(); + esm.skipHSub(); } } } @@ -32,15 +39,15 @@ void ESM::DialogueState::save (ESMWriter &esm) const esm.writeHNString ("TOPI", *iter); } - for (std::map >::const_iterator iter = mModFactionReaction.begin(); - iter != mModFactionReaction.end(); ++iter) + for (std::map >::const_iterator iter = mChangedFactionReaction.begin(); + iter != mChangedFactionReaction.end(); ++iter) { esm.writeHNString ("FACT", iter->first); for (std::map::const_iterator reactIter = iter->second.begin(); reactIter != iter->second.end(); ++reactIter) { - esm.writeHNString ("REAC", reactIter->first); + esm.writeHNString ("REA2", reactIter->first); esm.writeHNT ("INTV", reactIter->second); } } diff --git a/components/esm/dialoguestate.hpp b/components/esm/dialoguestate.hpp index 5e5f602a3..1adade5a0 100644 --- a/components/esm/dialoguestate.hpp +++ b/components/esm/dialoguestate.hpp @@ -16,7 +16,7 @@ namespace ESM { std::vector mKnownTopics; - std::map > mModFactionReaction; + std::map > mChangedFactionReaction; void load (ESMReader &esm); void save (ESMWriter &esm) const; From 6d5bb57e00ea23f573731f7ed15f31f928a76576 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 20 Jan 2015 01:21:44 +0100 Subject: [PATCH 0346/3725] ESSImport: fix loading item stacks in containers --- apps/essimporter/importinventory.cpp | 43 ++++++++++++++++------------ 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/apps/essimporter/importinventory.cpp b/apps/essimporter/importinventory.cpp index b3bd4a86b..b4d193540 100644 --- a/apps/essimporter/importinventory.cpp +++ b/apps/essimporter/importinventory.cpp @@ -18,28 +18,35 @@ namespace ESSImport item.mId = contItem.mItem.toString(); item.mCount = contItem.mCount; - if (esm.isNextSub("XIDX")) - esm.skipHSub(); - - std::string script = esm.getHNOString("SCRI"); - // script variables? - // unsure if before or after ESM::CellRef - if (!script.empty()) + // seems that a stack of items can have a set of subrecords for each item? rings0000.ess + // doesn't make any sense to me, if the values were different then the items shouldn't stack in the first place? + // I guess we should double check the stacking logic in OpenMW + for (int i=0;i Date: Tue, 20 Jan 2015 15:24:33 +0100 Subject: [PATCH 0347/3725] Fix broken windows builds due to README change --- CMakeLists.txt | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0bbce7ad4..938162b01 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -457,8 +457,9 @@ if(WIN32) FILE(GLOB dll_files "${OpenMW_BINARY_DIR}/Release/*.dll") INSTALL(FILES ${dll_files} DESTINATION ".") INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" DESTINATION "." RENAME "openmw.cfg") + INSTALL(FILES "${OpenMW_SOURCE_DIR}/CHANGELOG.md" DESTINATION "." RENAME "CHANGELOG.txt") + INSTALL(FILES "${OpenMW_SOURCE_DIR}/README.md" DESTINATION "." RENAME "README.txt") INSTALL(FILES - "${OpenMW_SOURCE_DIR}/readme.txt" "${OpenMW_SOURCE_DIR}/Docs/license/GPL3.txt" "${OpenMW_SOURCE_DIR}/Docs/license/DejaVu Font License.txt" "${OpenMW_BINARY_DIR}/settings-default.cfg" @@ -502,13 +503,13 @@ if(WIN32) IF(BUILD_WIZARD) SET(CPACK_PACKAGE_EXECUTABLES "${CPACK_PACKAGE_EXECUTABLES};openmw-wizard;OpenMW Wizard") ENDIF(BUILD_WIZARD) - SET(CPACK_NSIS_CREATE_ICONS_EXTRA "CreateShortCut '\$SMPROGRAMS\\\\$STARTMENU_FOLDER\\\\Readme.lnk' '\$INSTDIR\\\\readme.txt'") + SET(CPACK_NSIS_CREATE_ICONS_EXTRA "CreateShortCut '\$SMPROGRAMS\\\\$STARTMENU_FOLDER\\\\Readme.lnk' '\$INSTDIR\\\\README.txt'") SET(CPACK_NSIS_DELETE_ICONS_EXTRA " !insertmacro MUI_STARTMENU_GETFOLDER Application $MUI_TEMP Delete \\\"$SMPROGRAMS\\\\$MUI_TEMP\\\\Readme.lnk\\\" ") - SET(CPACK_RESOURCE_FILE_README "${OpenMW_SOURCE_DIR}/readme.txt") - SET(CPACK_PACKAGE_DESCRIPTION_FILE "${OpenMW_SOURCE_DIR}/readme.txt") + SET(CPACK_RESOURCE_FILE_README "${OpenMW_SOURCE_DIR}/README.md") + SET(CPACK_PACKAGE_DESCRIPTION_FILE "${OpenMW_SOURCE_DIR}/README.md") SET(CPACK_NSIS_EXECUTABLES_DIRECTORY ".") SET(CPACK_NSIS_DISPLAY_NAME "OpenMW ${OPENMW_VERSION}") SET(CPACK_NSIS_HELP_LINK "http:\\\\\\\\www.openmw.org") From 06736e9e0317037c0095971caff2213a9a94fa29 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 20 Jan 2015 01:28:34 +0100 Subject: [PATCH 0348/3725] ESSImport: convert faction reactions and known dialogue topics --- apps/essimporter/converter.hpp | 26 ++++++++++++++++++++++++++ apps/essimporter/importer.cpp | 7 +++++++ apps/essimporter/importercontext.hpp | 3 +++ apps/essimporter/importplayer.cpp | 1 - components/esm/dialoguestate.hpp | 2 ++ 5 files changed, 38 insertions(+), 1 deletion(-) diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index 187386b9d..62729cd03 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -9,6 +9,8 @@ #include #include #include +#include +#include #include #include "importcrec.hpp" @@ -214,6 +216,12 @@ public: mContext->mPlayer.mObject.mNpcStats.mFactions[it->mFactionName.toString()] = faction; } + for (std::vector::const_iterator it = pcdt.mKnownDialogueTopics.begin(); + it != pcdt.mKnownDialogueTopics.end(); ++it) + { + mContext->mDialogueState.mKnownTopics.push_back(Misc::StringUtils::lowerCase(*it)); + } + } }; @@ -295,6 +303,24 @@ private: std::map mKillCounter; }; +class ConvertFACT : public Converter +{ +public: + virtual void read(ESM::ESMReader& esm) + { + std::string id = esm.getHNString("NAME"); + ESM::Faction faction; + faction.load(esm); + + Misc::StringUtils::toLower(id); + for (std::map::const_iterator it = faction.mReactions.begin(); it != faction.mReactions.end(); ++it) + { + std::string faction2 = Misc::StringUtils::lowerCase(it->first); + mContext->mDialogueState.mChangedFactionReaction[id].insert(std::make_pair(faction2, it->second)); + } + } +}; + } #endif diff --git a/apps/essimporter/importer.cpp b/apps/essimporter/importer.cpp index 9075db404..e73aaafae 100644 --- a/apps/essimporter/importer.cpp +++ b/apps/essimporter/importer.cpp @@ -181,6 +181,8 @@ namespace ESSImport Ogre::LogManager logman; Ogre::Root root; + // TODO: set up encoding on ESMReader based on openmw.cfg / --encoding switch + ESM::ESMReader esm; esm.open(mEssFile); @@ -216,6 +218,7 @@ namespace ESSImport converters[ESM::REC_LEVC] = boost::shared_ptr(new DefaultConverter()); converters[ESM::REC_LEVI] = boost::shared_ptr(new DefaultConverter()); converters[ESM::REC_CNTC] = boost::shared_ptr(new ConvertCNTC()); + converters[ESM::REC_FACT] = boost::shared_ptr(new ConvertFACT()); std::set unknownRecords; @@ -322,6 +325,10 @@ namespace ESSImport } context.mPlayer.save(writer); writer.endRecord(ESM::REC_PLAY); + + writer.startRecord (ESM::REC_DIAS); + context.mDialogueState.save(writer); + writer.endRecord(ESM::REC_DIAS); } diff --git a/apps/essimporter/importercontext.hpp b/apps/essimporter/importercontext.hpp index a921b81ef..02585799a 100644 --- a/apps/essimporter/importercontext.hpp +++ b/apps/essimporter/importercontext.hpp @@ -5,6 +5,7 @@ #include #include +#include #include "importnpcc.hpp" #include "importcrec.hpp" @@ -25,6 +26,8 @@ namespace ESSImport ESM::NPC mPlayerBase; std::string mCustomPlayerClassName; + ESM::DialogueState mDialogueState; + int mDay, mMonth, mYear; float mHour; diff --git a/apps/essimporter/importplayer.cpp b/apps/essimporter/importplayer.cpp index 8a57ae588..f94d3aacc 100644 --- a/apps/essimporter/importplayer.cpp +++ b/apps/essimporter/importplayer.cpp @@ -20,7 +20,6 @@ namespace ESSImport { while (esm.isNextSub("DNAM")) { - // TODO: deal with encoding? mKnownDialogueTopics.push_back(esm.getHString()); } diff --git a/components/esm/dialoguestate.hpp b/components/esm/dialoguestate.hpp index 1adade5a0..d7cdb941c 100644 --- a/components/esm/dialoguestate.hpp +++ b/components/esm/dialoguestate.hpp @@ -14,8 +14,10 @@ namespace ESM struct DialogueState { + // must be lower case topic IDs std::vector mKnownTopics; + // must be lower case faction IDs std::map > mChangedFactionReaction; void load (ESMReader &esm); From 25ff45d819290feaa25a344ffdd491509a25083c Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 20 Jan 2015 15:44:47 +0100 Subject: [PATCH 0349/3725] Update command line options in Readme --- README.md | 51 +++++++++++++++++++++++++++++---------------------- 1 file changed, 29 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index bb59b7e02..7c24a4c81 100644 --- a/README.md +++ b/README.md @@ -41,51 +41,58 @@ Command line options --version print version information and quit --data arg (=data) set data directories (later directories have higher priority) - --data-local arg set local data directory (highest + --data-local arg set local data directory (highest priority) --fallback-archive arg (=fallback-archive) - set fallback BSA archives (later + set fallback BSA archives (later archives have higher priority) --resources arg (=resources) set resources directory - --start arg (=Beshara) set initial cell - --content arg content file(s): esm/esp, or + --start arg set initial cell + --content arg content file(s): esm/esp, or omwgame/omwaddon - --anim-verbose [=arg(=1)] (=0) output animation indices files --no-sound [=arg(=1)] (=0) disable all sounds --script-verbose [=arg(=1)] (=0) verbose script output --script-all [=arg(=1)] (=0) compile all scripts (excluding dialogue scripts) at startup - --script-console [=arg(=1)] (=0) enable console-only script + --script-all-dialogue [=arg(=1)] (=0) compile all dialogue scripts at startup + --script-console [=arg(=1)] (=0) enable console-only script functionality - --script-run arg select a file containing a list of - console commands that is executed on + --script-run arg select a file containing a list of + console commands that is executed on startup - --script-warn [=arg(=1)] (=1) handling of warnings when compiling + --script-warn [=arg(=1)] (=1) handling of warnings when compiling scripts 0 - ignore warning 1 - show warning but consider script as correctly compiled anyway 2 - treat warnings as errors + --script-blacklist arg ignore the specified script (if the use + of the blacklist is enabled) + --script-blacklist-use [=arg(=1)] (=1) + enable script blacklisting + --load-savegame arg load a save game file on game startup --skip-menu [=arg(=1)] (=0) skip main menu on game startup - --new-game [=arg(=1)] (=0) run new game sequence (ignored if + --new-game [=arg(=1)] (=0) run new game sequence (ignored if skip-menu=0) - --fs-strict [=arg(=1)] (=0) strict file system handling (no case + --fs-strict [=arg(=1)] (=0) strict file system handling (no case folding) - --encoding arg (=win1252) Character encoding used in OpenMW game + --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 + + 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 + + win1251 - Cyrillic alphabet such as + Russian, Bulgarian, Serbian Cyrillic and other languages - - win1252 - Western European (Latin) + + win1252 - Western European (Latin) alphabet, used by default --fallback arg fallback values --no-grab Don't grab mouse cursor + --export-fonts [=arg(=1)] (=0) Export Morrowind .fnt fonts to PNG + image and XML file in current directory --activate-dist arg (=-1) activation distance override From 3a88f4ebd5fbaadae05b74a604399d78157392da Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Tue, 20 Jan 2015 17:07:26 +0100 Subject: [PATCH 0350/3725] Fix windows build, MessageBox is a defined symbol Windows and its stupid defines... --- apps/openmw/mwgui/messagebox.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index 9cb778ea2..cdbcf784d 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -12,6 +12,8 @@ #include "../mwbase/inputmanager.hpp" #include "../mwbase/windowmanager.hpp" +#undef MessageBox + namespace MWGui { From 1375a4e4bb36ac144ba9511451feb1669783b1a3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 20 Jan 2015 16:06:15 +0100 Subject: [PATCH 0351/3725] ESSImport: read stolen items (not converted yet) --- apps/essimporter/converter.hpp | 24 ++++++++++++++++++++++++ apps/essimporter/importer.cpp | 10 ++++++---- 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index 62729cd03..716ddc9c7 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -321,6 +321,30 @@ public: } }; +/// Stolen items +class ConvertSTLN : public Converter +{ +public: + virtual void read(ESM::ESMReader &esm) + { + std::string itemid = esm.getHNString("NAME"); + + while (esm.isNextSub("ONAM")) + { + std::string ownerid = esm.getHString(); + mStolenItems.insert(std::make_pair(itemid, ownerid)); + } + while (esm.isNextSub("FNAM")) + { + std::string factionid = esm.getHString(); + mFactionStolenItems.insert(std::make_pair(itemid, factionid)); + } + } +private: + std::multimap mStolenItems; + std::multimap mFactionStolenItems; +}; + } #endif diff --git a/apps/essimporter/importer.cpp b/apps/essimporter/importer.cpp index e73aaafae..699725d67 100644 --- a/apps/essimporter/importer.cpp +++ b/apps/essimporter/importer.cpp @@ -195,6 +195,7 @@ namespace ESSImport const unsigned int recPCDT = ESM::FourCC<'P','C','D','T'>::value; const unsigned int recFMAP = ESM::FourCC<'F','M','A','P'>::value; const unsigned int recKLST = ESM::FourCC<'K','L','S','T'>::value; + const unsigned int recSTLN = ESM::FourCC<'S','T','L','N'>::value; std::map > converters; converters[ESM::REC_GLOB] = boost::shared_ptr(new ConvertGlobal()); @@ -202,10 +203,11 @@ namespace ESSImport converters[ESM::REC_NPC_] = boost::shared_ptr(new ConvertNPC()); converters[ESM::REC_NPCC] = boost::shared_ptr(new ConvertNPCC()); converters[ESM::REC_CREC] = boost::shared_ptr(new ConvertCREC()); - converters[recREFR] = boost::shared_ptr(new ConvertREFR()); - converters[recPCDT] = boost::shared_ptr(new ConvertPCDT()); - converters[recFMAP] = boost::shared_ptr(new ConvertFMAP()); - converters[recKLST] = boost::shared_ptr(new ConvertKLST()); + converters[recREFR ] = boost::shared_ptr(new ConvertREFR()); + converters[recPCDT ] = boost::shared_ptr(new ConvertPCDT()); + converters[recFMAP ] = boost::shared_ptr(new ConvertFMAP()); + converters[recKLST ] = boost::shared_ptr(new ConvertKLST()); + converters[recSTLN ] = boost::shared_ptr(new ConvertSTLN()); converters[ESM::REC_CELL] = boost::shared_ptr(new ConvertCell()); converters[ESM::REC_ALCH] = boost::shared_ptr(new DefaultConverter()); converters[ESM::REC_CLAS] = boost::shared_ptr(new ConvertClass()); From 0fc9221eb36058ccb31e4fb57f09cc1a1a3bc2fb Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 20 Jan 2015 18:22:02 +0100 Subject: [PATCH 0352/3725] ESSImport: convert NPC disposition --- apps/essimporter/convertnpcc.cpp | 1 + apps/essimporter/importnpcc.hpp | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/essimporter/convertnpcc.cpp b/apps/essimporter/convertnpcc.cpp index 2155f46fb..48d3d9232 100644 --- a/apps/essimporter/convertnpcc.cpp +++ b/apps/essimporter/convertnpcc.cpp @@ -7,6 +7,7 @@ namespace ESSImport void convertNPCC(const NPCC &npcc, ESM::NpcState &npcState) { + npcState.mNpcStats.mDisposition = npcc.mNPDT.mDisposition; npcState.mNpcStats.mReputation = npcc.mNPDT.mReputation; convertInventory(npcc.mInventory, npcState.mInventory); diff --git a/apps/essimporter/importnpcc.hpp b/apps/essimporter/importnpcc.hpp index 2f474aba0..ee8eccda2 100644 --- a/apps/essimporter/importnpcc.hpp +++ b/apps/essimporter/importnpcc.hpp @@ -19,7 +19,8 @@ namespace ESSImport { struct NPDT { - unsigned char unknown[2]; + unsigned char mDisposition; + unsigned char unknown; unsigned char mReputation; unsigned char unknown2[5]; } mNPDT; From d473629dcd6aa6e04d53accc2e7a69314b8fa79c Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 20 Jan 2015 19:12:07 +0100 Subject: [PATCH 0353/3725] Improve ESMReader error messages --- components/esm/esmreader.cpp | 6 +++++- components/esm/esmreader.hpp | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/components/esm/esmreader.cpp b/components/esm/esmreader.cpp index de110dd18..3c43d067f 100644 --- a/components/esm/esmreader.cpp +++ b/components/esm/esmreader.cpp @@ -134,7 +134,11 @@ void ESMReader::getHExact(void*p, int size) { getSubHeader(); if (size != static_cast (mCtx.leftSub)) - fail("getHExact() size mismatch"); + { + std::stringstream error; + error << "getHExact(): size mismatch (requested " << size << ", got " << mCtx.leftSub << ")"; + fail(error.str()); + } getExact(p, size); } diff --git a/components/esm/esmreader.hpp b/components/esm/esmreader.hpp index bb615af11..e7721bb8f 100644 --- a/components/esm/esmreader.hpp +++ b/components/esm/esmreader.hpp @@ -137,7 +137,11 @@ public: { getSubHeader(); if (mCtx.leftSub != sizeof(X)) - fail("getHT(): subrecord size mismatch"); + { + std::stringstream error; + error << "getHT(): subrecord size mismatch (requested " << sizeof(X) << ", got " << mCtx.leftSub << ")"; + fail(error.str()); + } getT(x); } From eede2c8e55fe9579dd8e746385be2a794ce969bb Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 20 Jan 2015 19:30:39 +0100 Subject: [PATCH 0354/3725] ESSImport: convert breath meter and skill increases --- apps/essimporter/convertacdt.cpp | 2 ++ apps/essimporter/converter.hpp | 2 ++ apps/essimporter/importacdt.hpp | 16 +++++++++++++--- apps/essimporter/importer.cpp | 5 +++++ apps/essimporter/importplayer.cpp | 4 ++-- apps/essimporter/importplayer.hpp | 11 +++++++++++ apps/openmw/mwmechanics/npcstats.hpp | 22 +++++++++++----------- 7 files changed, 46 insertions(+), 16 deletions(-) diff --git a/apps/essimporter/convertacdt.cpp b/apps/essimporter/convertacdt.cpp index 81ab61084..af66ec272 100644 --- a/apps/essimporter/convertacdt.cpp +++ b/apps/essimporter/convertacdt.cpp @@ -37,6 +37,8 @@ namespace ESSImport npcStats.mSkills[i].mRegular.mCurrent = actorData.mSkills[i][1]; npcStats.mSkills[i].mRegular.mBase = actorData.mSkills[i][0]; } + + npcStats.mTimeToStartDrowning = actorData.mACDT.mBreathMeter; } } diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index 716ddc9c7..23b0434b1 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -215,6 +215,8 @@ public: faction.mReputation = it->mReputation; mContext->mPlayer.mObject.mNpcStats.mFactions[it->mFactionName.toString()] = faction; } + for (int i=0; i<8; ++i) + mContext->mPlayer.mObject.mNpcStats.mSkillIncrease[i] = pcdt.mPNAM.mSkillIncreases[i]; for (std::vector::const_iterator it = pcdt.mKnownDialogueTopics.begin(); it != pcdt.mKnownDialogueTopics.end(); ++it) diff --git a/apps/essimporter/importacdt.hpp b/apps/essimporter/importacdt.hpp index 6efae9dc5..cf72b5cf7 100644 --- a/apps/essimporter/importacdt.hpp +++ b/apps/essimporter/importacdt.hpp @@ -13,14 +13,24 @@ namespace ESSImport /// Actor data, shared by (at least) REFR and CellRef +#pragma pack(push) +#pragma pack(1) struct ACDT { - unsigned char mUnknown1[40]; + // Note, not stored at *all*: + // - Level changes are lost on reload, except for the player (there it's in the NPC record). + unsigned char mUnknown1[16]; + float mBreathMeter; // Seconds left before drowning + unsigned char mUnknown2[20]; float mDynamic[3][2]; - unsigned char mUnknown2[16]; + unsigned char mUnknown3[16]; float mAttributes[8][2]; - unsigned char mUnknown3[120]; + unsigned char mUnknown4[109]; + // This seems to increase when purchasing training, though I don't see it anywhere ingame. + int mGold; + unsigned char mUnknown5[7]; }; +#pragma pack(pop) struct ActorData { diff --git a/apps/essimporter/importer.cpp b/apps/essimporter/importer.cpp index 699725d67..c2092ea4d 100644 --- a/apps/essimporter/importer.cpp +++ b/apps/essimporter/importer.cpp @@ -104,6 +104,11 @@ namespace ESSImport blacklist.insert(std::make_pair("GLOB", "FLTV")); // gamehour blacklist.insert(std::make_pair("REFR", "DATA")); // player position blacklist.insert(std::make_pair("CELL", "NAM8")); // fog of war + blacklist.insert(std::make_pair("GAME", "GMDT")); // weather data, current time always changes + + // this changes way too often, name suggests some renderer internal data? + blacklist.insert(std::make_pair("CELL", "ND3D")); + blacklist.insert(std::make_pair("REFR", "ND3D")); File file1; read(mEssFile, file1); diff --git a/apps/essimporter/importplayer.cpp b/apps/essimporter/importplayer.cpp index f94d3aacc..285605068 100644 --- a/apps/essimporter/importplayer.cpp +++ b/apps/essimporter/importplayer.cpp @@ -23,8 +23,8 @@ namespace ESSImport mKnownDialogueTopics.push_back(esm.getHString()); } - if (esm.isNextSub("PNAM")) - esm.skipHSub(); + esm.getHNT(mPNAM, "PNAM"); + if (esm.isNextSub("SNAM")) esm.skipHSub(); if (esm.isNextSub("NAM9")) diff --git a/apps/essimporter/importplayer.hpp b/apps/essimporter/importplayer.hpp index af8625fa6..2bd55ef73 100644 --- a/apps/essimporter/importplayer.hpp +++ b/apps/essimporter/importplayer.hpp @@ -38,6 +38,8 @@ struct PCDT std::vector mKnownDialogueTopics; +#pragma pack(push) +#pragma pack(1) struct FNAM { unsigned char mRank; @@ -47,7 +49,16 @@ struct PCDT unsigned char mUnknown2[3]; ESM::NAME32 mFactionName; }; + struct PNAM + { + unsigned char mUnknown1[116]; + unsigned char mSkillIncreases[8]; // number of skill increases for each attribute + unsigned char mUnknown2[88]; + }; +#pragma pack(pop) + std::vector mFactions; + PNAM mPNAM; void load(ESM::ESMReader& esm); }; diff --git a/apps/openmw/mwmechanics/npcstats.hpp b/apps/openmw/mwmechanics/npcstats.hpp index 4594492e1..9e543bb79 100644 --- a/apps/openmw/mwmechanics/npcstats.hpp +++ b/apps/openmw/mwmechanics/npcstats.hpp @@ -22,27 +22,27 @@ namespace MWMechanics class NpcStats : public CreatureStats { - /// NPCs other than the player can only have one faction. But for the sake of consistency - /// we use the same data structure for the PC and the NPCs. - /// \note the faction key must be in lowercase - std::map mFactionRank; - int mDisposition; SkillValue mSkill[ESM::Skill::Length]; SkillValue mWerewolfSkill[ESM::Skill::Length]; - int mBounty; - std::set mExpelled; - std::map mFactionReputation; int mReputation; int mCrimeId; - int mWerewolfKills; + int mProfit; + // ----- used by the player only, maybe should be moved at some point ------- + int mBounty; + int mWerewolfKills; + /// NPCs other than the player can only have one faction. But for the sake of consistency + /// we use the same data structure for the PC and the NPCs. + /// \note the faction key must be in lowercase + std::map mFactionRank; + std::set mExpelled; + std::map mFactionReputation; int mLevelProgress; // 0-10 - std::vector mSkillIncreases; // number of skill increases for each attribute - std::set mUsedIds; + // --------------------------------------------------------------------------- /// Countdown to getting damage while underwater float mTimeToStartDrowning; From 5b705196bc11acb9e471ad96c6eb928bbe5bad3e Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 20 Jan 2015 19:47:54 +0100 Subject: [PATCH 0355/3725] ESSImport: convert level progress --- apps/essimporter/converter.hpp | 1 + apps/essimporter/importplayer.hpp | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index 23b0434b1..920e6eead 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -217,6 +217,7 @@ public: } for (int i=0; i<8; ++i) mContext->mPlayer.mObject.mNpcStats.mSkillIncrease[i] = pcdt.mPNAM.mSkillIncreases[i]; + mContext->mPlayer.mObject.mNpcStats.mLevelProgress = pcdt.mPNAM.mLevelProgress; for (std::vector::const_iterator it = pcdt.mKnownDialogueTopics.begin(); it != pcdt.mKnownDialogueTopics.end(); ++it) diff --git a/apps/essimporter/importplayer.hpp b/apps/essimporter/importplayer.hpp index 2bd55ef73..64ceddfd7 100644 --- a/apps/essimporter/importplayer.hpp +++ b/apps/essimporter/importplayer.hpp @@ -51,9 +51,11 @@ struct PCDT }; struct PNAM { - unsigned char mUnknown1[116]; + unsigned char mUnknown1[4]; + unsigned char mLevelProgress; + unsigned char mUnknown2[111]; unsigned char mSkillIncreases[8]; // number of skill increases for each attribute - unsigned char mUnknown2[88]; + unsigned char mUnknown3[88]; }; #pragma pack(pop) From e38d75634505ea77173d492ee90fff5e0a347128 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 20 Jan 2015 20:18:30 +0100 Subject: [PATCH 0356/3725] ESSImport: fix NPCC indices --- apps/essimporter/converter.cpp | 6 +++++- apps/essimporter/converter.hpp | 5 +---- apps/essimporter/importnpcc.hpp | 3 ++- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/apps/essimporter/converter.cpp b/apps/essimporter/converter.cpp index 83ea077ea..099987762 100644 --- a/apps/essimporter/converter.cpp +++ b/apps/essimporter/converter.cpp @@ -1,5 +1,7 @@ #include "converter.hpp" +#include + #include #include @@ -281,7 +283,9 @@ namespace ESSImport continue; } - std::cerr << "Can't find type for " << cellref.mIndexedRefId << std::endl; + std::stringstream error; + error << "Can't find type for " << cellref.mIndexedRefId << std::endl; + throw std::runtime_error(error.str()); } } diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index 920e6eead..b68f9a218 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -170,13 +170,10 @@ public: } else { - int index = mIndexCounter[id]++; + int index = npcc.mNPDT.mIndex; mContext->mNpcChanges.insert(std::make_pair(std::make_pair(index,id), npcc)).second; } } - -private: - std::map mIndexCounter; }; class ConvertREFR : public Converter diff --git a/apps/essimporter/importnpcc.hpp b/apps/essimporter/importnpcc.hpp index ee8eccda2..c69fa3e03 100644 --- a/apps/essimporter/importnpcc.hpp +++ b/apps/essimporter/importnpcc.hpp @@ -22,7 +22,8 @@ namespace ESSImport unsigned char mDisposition; unsigned char unknown; unsigned char mReputation; - unsigned char unknown2[5]; + unsigned char unknown2; + int mIndex; } mNPDT; Inventory mInventory; From 142a138b75e3391963ce109b216c7eb625a441b7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 20 Jan 2015 20:19:08 +0100 Subject: [PATCH 0357/3725] ESSImport: convert TalkedTo flag and gold pool --- apps/essimporter/convertacdt.cpp | 2 ++ apps/essimporter/importacdt.cpp | 3 ++- apps/essimporter/importacdt.hpp | 15 ++++++++++----- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/apps/essimporter/convertacdt.cpp b/apps/essimporter/convertacdt.cpp index af66ec272..496eab9e9 100644 --- a/apps/essimporter/convertacdt.cpp +++ b/apps/essimporter/convertacdt.cpp @@ -27,6 +27,8 @@ namespace ESSImport cStats.mAttributes[i].mMod = acdt.mAttributes[i][0]; cStats.mAttributes[i].mCurrent = acdt.mAttributes[i][0]; } + cStats.mGoldPool = acdt.mGoldPool; + cStats.mTalkedTo = acdt.mFlags & TalkedToPlayer; } void convertNpcData (const ActorData& actorData, ESM::NpcStats& npcStats) diff --git a/apps/essimporter/importacdt.cpp b/apps/essimporter/importacdt.cpp index d961720a7..84c800897 100644 --- a/apps/essimporter/importacdt.cpp +++ b/apps/essimporter/importacdt.cpp @@ -22,7 +22,7 @@ namespace ESSImport ESM::CellRef bla; bla.ESM::CellRef::loadData(esm); - // FIXME: actually should be required for all actors?, but ActorData is currently in base CellRef + // FIXME: not all actors have this, add flag esm.getHNOT(mACDT, "ACDT"); ACSC acsc; @@ -76,6 +76,7 @@ namespace ESSImport esm.skipHSub(); // 4 byte, 0 } + // FIXME: not all actors have this, add flag if (esm.isNextSub("CHRD")) // npc only esm.getHExact(mSkills, 27*2*sizeof(int)); diff --git a/apps/essimporter/importacdt.hpp b/apps/essimporter/importacdt.hpp index cf72b5cf7..79f67d2c2 100644 --- a/apps/essimporter/importacdt.hpp +++ b/apps/essimporter/importacdt.hpp @@ -11,6 +11,10 @@ namespace ESM namespace ESSImport { + enum ACDTFlags + { + TalkedToPlayer = 0x4 + }; /// Actor data, shared by (at least) REFR and CellRef #pragma pack(push) @@ -19,16 +23,17 @@ namespace ESSImport { // Note, not stored at *all*: // - Level changes are lost on reload, except for the player (there it's in the NPC record). - unsigned char mUnknown1[16]; + unsigned char mUnknown[12]; + unsigned char mFlags; // ACDTFlags + unsigned char mUnknown1[3]; float mBreathMeter; // Seconds left before drowning unsigned char mUnknown2[20]; float mDynamic[3][2]; unsigned char mUnknown3[16]; float mAttributes[8][2]; - unsigned char mUnknown4[109]; - // This seems to increase when purchasing training, though I don't see it anywhere ingame. - int mGold; - unsigned char mUnknown5[7]; + unsigned char mUnknown4[112]; + unsigned int mGoldPool; + unsigned char mUnknown5[4]; }; #pragma pack(pop) From 89d9649b50b2b6e102b90517a5b136cc74415ba0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 20 Jan 2015 23:55:26 +0100 Subject: [PATCH 0358/3725] Change save format to store relative equipment index Store the index for the allowedSlots vector instead of the absolute slot index. This will more gracefully handle edge cases like the available slots for an item having changed when loading the game, or the "allows stacking" property having changed. However the main reason this was done is to ease work on the essimporter. --- apps/openmw/mwworld/cellstore.cpp | 2 +- apps/openmw/mwworld/containerstore.cpp | 27 ++++++++++---------- apps/openmw/mwworld/containerstore.hpp | 12 +++++---- apps/openmw/mwworld/inventorystore.cpp | 35 ++++++++++++++++++++------ apps/openmw/mwworld/inventorystore.hpp | 6 ++--- apps/openmw/mwworld/worldimp.cpp | 4 +-- components/esm/inventorystate.hpp | 1 + 7 files changed, 56 insertions(+), 31 deletions(-) diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 605c8f9d2..545bbd4b3 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -466,7 +466,7 @@ namespace MWWorld // List moved references, from separately tracked list. for (ESM::CellRefTracker::const_iterator it = mCell->mLeasedRefs.begin(); it != mCell->mLeasedRefs.end(); ++it) { - ESM::CellRef &ref = const_cast(*it); + const ESM::CellRef &ref = *it; mIds.push_back(Misc::StringUtils::lowerCase(ref.mRefID)); } diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index bd14720f7..5911b45f7 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -85,28 +85,29 @@ void MWWorld::ContainerStore::storeState (const LiveCellRef& ref, ESM::Object ref.save (state); } +/// \todo make this method const once const-correct ContainerStoreIterators are available template -void MWWorld::ContainerStore::storeStates (const CellRefList& collection, - std::vector >& states, bool equipable) const +void MWWorld::ContainerStore::storeStates (CellRefList& collection, + std::vector >& states, bool equipable) { - for (typename CellRefList::List::const_iterator iter (collection.mList.begin()); + for (typename CellRefList::List::iterator iter (collection.mList.begin()); iter!=collection.mList.end(); ++iter) { if (iter->mData.getCount() == 0) continue; ESM::ObjectState state; storeState (*iter, state); - int slot = equipable ? getSlot (*iter) : -1; + int slot = equipable ? getRelativeSlot (MWWorld::ContainerStoreIterator(this, iter)) : -1; states.push_back (std::make_pair (state, slot)); } } -int MWWorld::ContainerStore::getSlot (const MWWorld::LiveCellRefBase& ref) const +int MWWorld::ContainerStore::getRelativeSlot (const MWWorld::ContainerStoreIterator& iter) const { return -1; } -void MWWorld::ContainerStore::setSlot (const MWWorld::ContainerStoreIterator& iter, int slot) {} +void MWWorld::ContainerStore::setRelativeSlot (const MWWorld::ContainerStoreIterator& iter, int slot) {} const std::string MWWorld::ContainerStore::sGoldId = "gold_001"; @@ -641,7 +642,7 @@ MWWorld::Ptr MWWorld::ContainerStore::search (const std::string& id) return Ptr(); } -void MWWorld::ContainerStore::writeState (ESM::InventoryState& state) const +void MWWorld::ContainerStore::writeState (ESM::InventoryState& state) { state.mItems.clear(); @@ -678,16 +679,16 @@ void MWWorld::ContainerStore::readState (const ESM::InventoryState& state) { case ESM::REC_ALCH: getState (potions, iter->first); break; case ESM::REC_APPA: getState (appas, iter->first); break; - case ESM::REC_ARMO: setSlot (getState (armors, iter->first), slot); break; + case ESM::REC_ARMO: setRelativeSlot (getState (armors, iter->first), slot); break; case ESM::REC_BOOK: getState (books, iter->first); break; - case ESM::REC_CLOT: setSlot (getState (clothes, iter->first), slot); break; + case ESM::REC_CLOT: setRelativeSlot (getState (clothes, iter->first), slot); break; case ESM::REC_INGR: getState (ingreds, iter->first); break; - case ESM::REC_LOCK: setSlot (getState (lockpicks, iter->first), slot); break; + case ESM::REC_LOCK: setRelativeSlot (getState (lockpicks, iter->first), slot); break; case ESM::REC_MISC: getState (miscItems, iter->first); break; - case ESM::REC_PROB: setSlot (getState (probes, iter->first), slot); break; + case ESM::REC_PROB: setRelativeSlot (getState (probes, iter->first), slot); break; case ESM::REC_REPA: getState (repairs, iter->first); break; - case ESM::REC_WEAP: setSlot (getState (weapons, iter->first), slot); break; - case ESM::REC_LIGH: setSlot (getState (lights, iter->first), slot); break; + case ESM::REC_WEAP: setRelativeSlot (getState (weapons, iter->first), slot); break; + case ESM::REC_LIGH: setRelativeSlot (getState (lights, iter->first), slot); break; default: std::cerr << "invalid item type in inventory state, refid " << state.mRef.mRefID << std::endl; diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index 68ee41a1d..4a95606f7 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -84,15 +84,16 @@ namespace MWWorld template void storeState (const LiveCellRef& ref, ESM::ObjectState& state) const; + /// \todo make this method const once const-correct ContainerStoreIterators are available template - void storeStates (const CellRefList& collection, + void storeStates (CellRefList& collection, std::vector >& states, - bool equipable = false) const; + bool equipable = false); - virtual int getSlot (const MWWorld::LiveCellRefBase& ref) const; + virtual int getRelativeSlot (const MWWorld::ContainerStoreIterator& iter) const; ///< Return inventory slot that \a ref is in or -1 (if \a ref is not in a slot). - virtual void setSlot (const MWWorld::ContainerStoreIterator& iter, int slot); + virtual void setRelativeSlot (const MWWorld::ContainerStoreIterator& iter, int slot); ///< Set slot for \a iter. Ignored if \a iter is an end iterator or if slot==-1. public: @@ -171,7 +172,8 @@ namespace MWWorld Ptr search (const std::string& id); - virtual void writeState (ESM::InventoryState& state) const; + /// \todo make this method const once const-correct ContainerStoreIterators are available + virtual void writeState (ESM::InventoryState& state); virtual void readState (const ESM::InventoryState& state); diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 445b42d8d..8f272ca49 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -49,19 +49,40 @@ void MWWorld::InventoryStore::initSlots (TSlots& slots_) slots_.push_back (end()); } -int MWWorld::InventoryStore::getSlot (const MWWorld::LiveCellRefBase& ref) const +int MWWorld::InventoryStore::getRelativeSlot (const MWWorld::ContainerStoreIterator& iter) { for (int i = 0; i (mSlots.size()); ++i) - if (mSlots[i].getType()!=-1 && mSlots[i]->getBase()==&ref) - return i; + if (mSlots[i].getType()!=-1 && mSlots[i] == iter) + { + // linear complexity, but allowedSlots is most of the time just 1 anyway + std::vector allowedSlots = iter->getClass().getEquipmentSlots(*iter).first; + std::vector::iterator found = std::find(allowedSlots.begin(),allowedSlots.end(),i); + if (found == allowedSlots.end()) + return -1; + else + return std::distance(allowedSlots.begin(), found); + } return -1; } -void MWWorld::InventoryStore::setSlot (const MWWorld::ContainerStoreIterator& iter, int slot) +void MWWorld::InventoryStore::setRelativeSlot (const MWWorld::ContainerStoreIterator& iter, int relativeSlot) { - if (iter!=end() && slot>=0 && slot, bool> allowedSlots = iter->getClass().getEquipmentSlots(*iter); + relativeSlot = std::min(int(allowedSlots.first.size()-1), relativeSlot); + + // unstack if required + if (!allowedSlots.second && iter->getRefData().getCount() > 1) + { + MWWorld::ContainerStoreIterator newIter = addNewStack(*iter, 1); + iter->getRefData().setCount(iter->getRefData().getCount()-1); + mSlots[allowedSlots.first[relativeSlot]] = newIter; + } + else + mSlots[allowedSlots.first[relativeSlot]] = iter; } MWWorld::InventoryStore::InventoryStore() @@ -703,7 +724,7 @@ bool MWWorld::InventoryStore::isEquipped(const MWWorld::Ptr &item) return false; } -void MWWorld::InventoryStore::writeState(ESM::InventoryState &state) const +void MWWorld::InventoryStore::writeState(ESM::InventoryState &state) { MWWorld::ContainerStore::writeState(state); diff --git a/apps/openmw/mwworld/inventorystore.hpp b/apps/openmw/mwworld/inventorystore.hpp index 9fd18c54b..ae2ced2b8 100644 --- a/apps/openmw/mwworld/inventorystore.hpp +++ b/apps/openmw/mwworld/inventorystore.hpp @@ -113,10 +113,10 @@ namespace MWWorld void fireEquipmentChangedEvent(); - virtual int getSlot (const MWWorld::LiveCellRefBase& ref) const; + virtual int getRelativeSlot (const MWWorld::ContainerStoreIterator& iter); ///< Return inventory slot that \a ref is in or -1 (if \a ref is not in a slot). - virtual void setSlot (const MWWorld::ContainerStoreIterator& iter, int slot); + virtual void setRelativeSlot (const MWWorld::ContainerStoreIterator& iter, int relativeSlot); ///< Set slot for \a iter. Ignored if \a iter is an end iterator or if slot==-1. public: @@ -209,7 +209,7 @@ namespace MWWorld virtual void clear(); ///< Empty container. - virtual void writeState (ESM::InventoryState& state) const; + virtual void writeState (ESM::InventoryState& state); virtual void readState (const ESM::InventoryState& state); }; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 104605e65..f7d5d9616 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2031,7 +2031,7 @@ namespace MWWorld bool World::isOnGround(const MWWorld::Ptr &ptr) const { RefData &refdata = ptr.getRefData(); - const OEngine::Physic::PhysicActor *physactor = mPhysEngine->getCharacter(refdata.getHandle()); + OEngine::Physic::PhysicActor *physactor = mPhysEngine->getCharacter(refdata.getHandle()); if(!physactor) return false; @@ -2049,7 +2049,7 @@ namespace MWWorld mPhysEngine); if(tracer.mFraction < 1.0f) // collision, must be close to something below { - const_cast (physactor)->setOnGround(true); + physactor->setOnGround(true); return true; } else diff --git a/components/esm/inventorystate.hpp b/components/esm/inventorystate.hpp index 3d4407e7b..13af28e30 100644 --- a/components/esm/inventorystate.hpp +++ b/components/esm/inventorystate.hpp @@ -15,6 +15,7 @@ namespace ESM /// \brief State for inventories and containers struct InventoryState { + /// std::vector > mItems; std::map mLevelledItemMap; From 03df659e7d60c1047dd51b8d293cdd26f1cb9e2d Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 20 Jan 2015 23:58:24 +0100 Subject: [PATCH 0359/3725] ESSImport: convert inventory equipment slots --- apps/essimporter/convertinventory.cpp | 2 +- apps/essimporter/importinventory.cpp | 12 +++++++++++- apps/essimporter/importinventory.hpp | 1 + 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/apps/essimporter/convertinventory.cpp b/apps/essimporter/convertinventory.cpp index 42535d946..6a31be6a3 100644 --- a/apps/essimporter/convertinventory.cpp +++ b/apps/essimporter/convertinventory.cpp @@ -16,7 +16,7 @@ namespace ESSImport objstate.mCount = std::abs(it->mCount); // restocking items have negative count in the savefile // openmw handles them differently, so no need to set any flags objstate.mRef.mCharge = it->mCondition; - state.mItems.push_back(std::make_pair(objstate, -1)); + state.mItems.push_back(std::make_pair(objstate, it->mRelativeEquipmentSlot)); } } diff --git a/apps/essimporter/importinventory.cpp b/apps/essimporter/importinventory.cpp index b4d193540..2f5c3c054 100644 --- a/apps/essimporter/importinventory.cpp +++ b/apps/essimporter/importinventory.cpp @@ -1,5 +1,7 @@ #include "importinventory.hpp" +#include + #include #include @@ -17,6 +19,7 @@ namespace ESSImport InventoryItem item; item.mId = contItem.mItem.toString(); item.mCount = contItem.mCount; + item.mRelativeEquipmentSlot = -1; // seems that a stack of items can have a set of subrecords for each item? rings0000.ess // doesn't make any sense to me, if the values were different then the items shouldn't stack in the first place? @@ -55,14 +58,21 @@ namespace ESSImport { // note: same item can be equipped 2 items (e.g. 2 rings) // and will be *stacked* in the NPCO list, unlike openmw! + // this is currently not handled properly. + esm.getSubHeader(); int itemIndex; // index of the item in the NPCO list esm.getT(itemIndex); + if (itemIndex < 0 || itemIndex >= int(mItems.size())) + esm.fail("equipment item index out of range"); + // appears to be a relative index for only the *possible* slots this item can be equipped in, - // i.e. 0 most of the time, unlike openmw slot enum index + // i.e. 0 most of the time int slotIndex; esm.getT(slotIndex); + + mItems[itemIndex].mRelativeEquipmentSlot = slotIndex; } } diff --git a/apps/essimporter/importinventory.hpp b/apps/essimporter/importinventory.hpp index 359e43fa6..8a1594465 100644 --- a/apps/essimporter/importinventory.hpp +++ b/apps/essimporter/importinventory.hpp @@ -21,6 +21,7 @@ namespace ESSImport std::string mId; int mCount; int mCondition; + int mRelativeEquipmentSlot; }; std::vector mItems; From 8c32b7e304ae5ce07209849a0f772ecbdb097aab Mon Sep 17 00:00:00 2001 From: Scott Howard Date: Tue, 20 Jan 2015 17:59:11 -0500 Subject: [PATCH 0360/3725] missing include in essimporter/main.cpp error: 'cout' is not a member of 'std' error: 'cerr' is not a member of 'std' https://launchpadlibrarian.net/195402684/buildlog_ubuntu-trusty-amd64.openmw_0.34.0%2Bgit20150120.442-0~ubuntu14.04.1_FAILEDTOBUILD.txt.gz --- apps/essimporter/main.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/essimporter/main.cpp b/apps/essimporter/main.cpp index 0e5c65e95..1c7d51116 100644 --- a/apps/essimporter/main.cpp +++ b/apps/essimporter/main.cpp @@ -1,3 +1,5 @@ +#include + #include #include #include From db64ff66453245ecf0b273354bee3ec1af7a0810 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 21 Jan 2015 01:33:48 +0100 Subject: [PATCH 0361/3725] Fix actorId initialization --- components/esm/creaturestats.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esm/creaturestats.cpp b/components/esm/creaturestats.cpp index a1ef7eb0e..cac5cc0a6 100644 --- a/components/esm/creaturestats.cpp +++ b/components/esm/creaturestats.cpp @@ -230,7 +230,7 @@ void ESM::CreatureStats::blank() mTradeTime.mHour = 0; mTradeTime.mDay = 0; mGoldPool = 0; - mActorId = 0; + mActorId = -1; mHasAiSettings = false; mDead = false; mDied = false; From 5e0428243b38d18c55b80e7675ea74a0563f5e44 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 21 Jan 2015 01:59:45 +0100 Subject: [PATCH 0362/3725] Light charge handling fix --- apps/esmtool/esmtool.cpp | 2 +- apps/essimporter/convertinventory.cpp | 2 +- apps/essimporter/importinventory.cpp | 6 +-- apps/essimporter/importinventory.hpp | 1 - apps/opencs/model/world/columnimp.hpp | 4 +- apps/openmw/mwclass/light.cpp | 56 +++------------------------ apps/openmw/mwclass/light.hpp | 10 ----- apps/openmw/mwworld/cellref.cpp | 20 ++++++++-- apps/openmw/mwworld/cellref.hpp | 3 ++ apps/openmw/mwworld/manualref.hpp | 2 +- components/esm/cellref.cpp | 10 ++--- components/esm/cellref.hpp | 6 ++- components/esm/objectstate.cpp | 10 ++--- components/esm/objectstate.hpp | 2 - 14 files changed, 47 insertions(+), 87 deletions(-) diff --git a/apps/esmtool/esmtool.cpp b/apps/esmtool/esmtool.cpp index a18736bf2..b23ba72f9 100644 --- a/apps/esmtool/esmtool.cpp +++ b/apps/esmtool/esmtool.cpp @@ -261,7 +261,7 @@ void loadCell(ESM::Cell &cell, ESM::ESMReader &esm, Arguments& info) std::cout << " Faction: '" << ref.mFaction << "'" << std::endl; std::cout << " Faction rank: '" << ref.mFactionRank << "'" << std::endl; std::cout << " Enchantment charge: '" << ref.mEnchantmentCharge << "'\n"; - std::cout << " Uses/health: '" << ref.mCharge << "'\n"; + std::cout << " Uses/health: '" << ref.mChargeInt << "'\n"; std::cout << " Gold value: '" << ref.mGoldValue << "'\n"; std::cout << " Blocked: '" << static_cast(ref.mReferenceBlocked) << "'" << std::endl; std::cout << " Deleted: " << deleted << std::endl; diff --git a/apps/essimporter/convertinventory.cpp b/apps/essimporter/convertinventory.cpp index 6a31be6a3..31272bf5a 100644 --- a/apps/essimporter/convertinventory.cpp +++ b/apps/essimporter/convertinventory.cpp @@ -12,10 +12,10 @@ namespace ESSImport { ESM::ObjectState objstate; objstate.blank(); + objstate.mRef = *it; objstate.mRef.mRefID = Misc::StringUtils::lowerCase(it->mId); objstate.mCount = std::abs(it->mCount); // restocking items have negative count in the savefile // openmw handles them differently, so no need to set any flags - objstate.mRef.mCharge = it->mCondition; state.mItems.push_back(std::make_pair(objstate, it->mRelativeEquipmentSlot)); } } diff --git a/apps/essimporter/importinventory.cpp b/apps/essimporter/importinventory.cpp index 2f5c3c054..a20584ff5 100644 --- a/apps/essimporter/importinventory.cpp +++ b/apps/essimporter/importinventory.cpp @@ -45,9 +45,9 @@ namespace ESSImport // for XSOL and XCHG seen so far, but probably others too item.ESM::CellRef::loadData(esm); - item.mCondition = -1; - // FIXME: for Lights, this is actually a float - esm.getHNOT(item.mCondition, "XHLT"); + int charge=-1; + esm.getHNOT(charge, "XHLT"); + item.mChargeInt = charge; } mItems.push_back(item); diff --git a/apps/essimporter/importinventory.hpp b/apps/essimporter/importinventory.hpp index 8a1594465..99fed9b20 100644 --- a/apps/essimporter/importinventory.hpp +++ b/apps/essimporter/importinventory.hpp @@ -20,7 +20,6 @@ namespace ESSImport { std::string mId; int mCount; - int mCondition; int mRelativeEquipmentSlot; }; std::vector mItems; diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index eba73cf0b..da14bb495 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -1053,13 +1053,13 @@ namespace CSMWorld virtual QVariant get (const Record& record) const { - return record.get().mCharge; + return record.get().mChargeInt; } virtual void set (Record& record, const QVariant& data) { ESXRecordT record2 = record.get(); - record2.mCharge = data.toInt(); + record2.mChargeInt = data.toInt(); record.setModified (record2); } diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index c50ad52d8..35a21b63e 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -26,27 +26,6 @@ #include "../mwrender/actors.hpp" #include "../mwrender/renderinginterface.hpp" -namespace -{ - struct LightCustomData : public MWWorld::CustomData - { - float mTime; - ///< Time remaining - - LightCustomData(MWWorld::Ptr ptr) - { - MWWorld::LiveCellRef *ref = ptr.get(); - mTime = ref->mBase->mData.mTime; - } - ///< Constructs this CustomData from the base values for Ptr. - - virtual MWWorld::CustomData *clone() const - { - return new LightCustomData (*this); - } - }; -} - namespace MWClass { std::string Light::getId (const MWWorld::Ptr& ptr) const @@ -219,17 +198,16 @@ namespace MWClass void Light::setRemainingUsageTime (const MWWorld::Ptr& ptr, float duration) const { - ensureCustomData(ptr); - - float &timeRemaining = dynamic_cast (*ptr.getRefData().getCustomData()).mTime; - timeRemaining = duration; + ptr.getCellRef().setChargeFloat(duration); } float Light::getRemainingUsageTime (const MWWorld::Ptr& ptr) const { - ensureCustomData(ptr); - - return dynamic_cast (*ptr.getRefData().getCustomData()).mTime; + MWWorld::LiveCellRef *ref = ptr.get(); + if (ptr.getCellRef().getCharge() == -1) + return ref->mBase->mData.mTime; + else + return ptr.getCellRef().getChargeFloat(); } MWWorld::Ptr @@ -241,12 +219,6 @@ namespace MWClass return MWWorld::Ptr(&cell.get().insert(*ref), &cell); } - void Light::ensureCustomData (const MWWorld::Ptr& ptr) const - { - if (!ptr.getRefData().getCustomData()) - ptr.getRefData().setCustomData(new LightCustomData(ptr)); - } - bool Light::canSell (const MWWorld::Ptr& item, int npcServices) const { return npcServices & ESM::NPC::Lights; @@ -282,22 +254,6 @@ namespace MWClass return std::make_pair(1,""); } - void Light::readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state) - const - { - ensureCustomData (ptr); - - dynamic_cast (*ptr.getRefData().getCustomData()).mTime = state.mTime; - } - - void Light::writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state) - const - { - ensureCustomData (ptr); - - state.mTime = dynamic_cast (*ptr.getRefData().getCustomData()).mTime; - } - std::string Light::getSound(const MWWorld::Ptr& ptr) const { return ptr.get()->mBase->mSound; diff --git a/apps/openmw/mwclass/light.hpp b/apps/openmw/mwclass/light.hpp index bbca30113..8658375b7 100644 --- a/apps/openmw/mwclass/light.hpp +++ b/apps/openmw/mwclass/light.hpp @@ -10,8 +10,6 @@ namespace MWClass virtual MWWorld::Ptr copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const; - void ensureCustomData (const MWWorld::Ptr& ptr) const; - public: /// Return ID of \a ptr @@ -75,14 +73,6 @@ namespace MWClass std::pair canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const; - virtual void readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state) - const; - ///< Read additional state from \a state into \a ptr. - - virtual void writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state) - const; - ///< Write additional state from \a ptr into \a state. - virtual std::string getSound(const MWWorld::Ptr& ptr) const; }; } diff --git a/apps/openmw/mwworld/cellref.cpp b/apps/openmw/mwworld/cellref.cpp index aa6627de5..744e0e27a 100644 --- a/apps/openmw/mwworld/cellref.cpp +++ b/apps/openmw/mwworld/cellref.cpp @@ -81,15 +81,29 @@ namespace MWWorld int CellRef::getCharge() const { - return mCellRef.mCharge; + return mCellRef.mChargeInt; } void CellRef::setCharge(int charge) { - if (charge != mCellRef.mCharge) + if (charge != mCellRef.mChargeInt) { mChanged = true; - mCellRef.mCharge = charge; + mCellRef.mChargeInt = charge; + } + } + + float CellRef::getChargeFloat() const + { + return mCellRef.mChargeFloat; + } + + void CellRef::setChargeFloat(float charge) + { + if (charge != mCellRef.mChargeFloat) + { + mChanged = true; + mCellRef.mChargeFloat = charge; } } diff --git a/apps/openmw/mwworld/cellref.hpp b/apps/openmw/mwworld/cellref.hpp index a7ffbe08b..054fd7fc6 100644 --- a/apps/openmw/mwworld/cellref.hpp +++ b/apps/openmw/mwworld/cellref.hpp @@ -60,8 +60,11 @@ namespace MWWorld // For weapon or armor, this is the remaining item health. // For tools (lockpicks, probes, repair hammer) it is the remaining uses. + // If this returns int(-1) it means full health. int getCharge() const; + float getChargeFloat() const; // Implemented as union with int charge void setCharge(int charge); + void setChargeFloat(float charge); // The NPC that owns this object (and will get angry if you steal it) std::string getOwner() const; diff --git a/apps/openmw/mwworld/manualref.hpp b/apps/openmw/mwworld/manualref.hpp index 4eb93543b..f32b07471 100644 --- a/apps/openmw/mwworld/manualref.hpp +++ b/apps/openmw/mwworld/manualref.hpp @@ -28,7 +28,7 @@ namespace MWWorld cellRef.mRefID = name; cellRef.mScale = 1; cellRef.mFactionRank = 0; - cellRef.mCharge = -1; + cellRef.mChargeInt = -1; cellRef.mGoldValue = 1; cellRef.mEnchantmentCharge = -1; cellRef.mTeleport = false; diff --git a/components/esm/cellref.cpp b/components/esm/cellref.cpp index cd9fe8570..dfc3052ee 100644 --- a/components/esm/cellref.cpp +++ b/components/esm/cellref.cpp @@ -46,12 +46,12 @@ void ESM::CellRef::loadData(ESMReader &esm) esm.getHNOT (mFactionRank, "INDX"); mGoldValue = 1; - mCharge = -1; + mChargeInt = -1; mEnchantmentCharge = -1; esm.getHNOT (mEnchantmentCharge, "XCHG"); - esm.getHNOT (mCharge, "INTV"); + esm.getHNOT (mChargeInt, "INTV"); esm.getHNOT (mGoldValue, "NAM9"); @@ -106,8 +106,8 @@ void ESM::CellRef::save (ESMWriter &esm, bool wideRefNum, bool inInventory) cons if (mEnchantmentCharge != -1) esm.writeHNT("XCHG", mEnchantmentCharge); - if (mCharge != -1) - esm.writeHNT("INTV", mCharge); + if (mChargeInt != -1) + esm.writeHNT("INTV", mChargeInt); if (mGoldValue != 1) { esm.writeHNT("NAM9", mGoldValue); @@ -146,7 +146,7 @@ void ESM::CellRef::blank() mSoul.clear(); mFaction.clear(); mFactionRank = -2; - mCharge = -1; + mChargeInt = -1; mEnchantmentCharge = -1; mGoldValue = 0; mDestCell.clear(); diff --git a/components/esm/cellref.hpp b/components/esm/cellref.hpp index 7aa0e4d44..56932aa4d 100644 --- a/components/esm/cellref.hpp +++ b/components/esm/cellref.hpp @@ -59,7 +59,11 @@ namespace ESM // For weapon or armor, this is the remaining item health. // For tools (lockpicks, probes, repair hammer) it is the remaining uses. - int mCharge; + union + { + int mChargeInt; + float mChargeFloat; + }; // Remaining enchantment charge. This could be -1 if the charge was not touched yet (i.e. full). float mEnchantmentCharge; diff --git a/components/esm/objectstate.cpp b/components/esm/objectstate.cpp index 66fd49663..9ef1ccf80 100644 --- a/components/esm/objectstate.cpp +++ b/components/esm/objectstate.cpp @@ -24,9 +24,9 @@ void ESM::ObjectState::load (ESMReader &esm) esm.getHNOT (mLocalRotation, "LROT", 12); - // used for lights only - mTime = 0; - esm.getHNOT (mTime, "LTIM"); + // obsolete + int unused; + esm.getHNOT(unused, "LTIM"); // FIXME: assuming "false" as default would make more sense, but also break compatibility with older save files mHasCustomState = true; @@ -55,9 +55,6 @@ void ESM::ObjectState::save (ESMWriter &esm, bool inInventory) const esm.writeHNT ("LROT", mLocalRotation, 12); } - if (mTime) - esm.writeHNT ("LTIM", mTime); - if (!mHasCustomState) esm.writeHNT ("HCUS", false); } @@ -74,7 +71,6 @@ void ESM::ObjectState::blank() mPosition.rot[i] = 0; mLocalRotation[i] = 0; } - mTime = 0; mHasCustomState = true; } diff --git a/components/esm/objectstate.hpp b/components/esm/objectstate.hpp index b03689653..d1077733a 100644 --- a/components/esm/objectstate.hpp +++ b/components/esm/objectstate.hpp @@ -26,8 +26,6 @@ namespace ESM ESM::Position mPosition; float mLocalRotation[3]; - float mTime; // Used for lights only. Overhead should not be so awful, besides CellRef isn't OO either - // Is there any class-specific state following the ObjectState bool mHasCustomState; From 764c155cece395e7e05de885dd26a0ad62b5c6f4 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 22 Jan 2015 13:33:23 +0100 Subject: [PATCH 0363/3725] moved code for writing/reading ref nums into RefNum struct --- components/esm/cellref.cpp | 27 +++++++++++++++++++-------- components/esm/cellref.hpp | 4 ++++ 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/components/esm/cellref.cpp b/components/esm/cellref.cpp index 29d26d013..a14f977d6 100644 --- a/components/esm/cellref.cpp +++ b/components/esm/cellref.cpp @@ -4,6 +4,23 @@ #include "esmreader.hpp" #include "esmwriter.hpp" +void ESM::RefNum::load (ESMReader& esm, bool wide) +{ + if (wide) + esm.getHNT (*this, "FRMR", 8); + else + esm.getHNT (mIndex, "FRMR"); +} + +void ESM::RefNum::save (ESMWriter &esm, bool wide) const +{ + if (wide) + esm.writeHNT ("FRMR", *this, 8); + else + esm.writeHNT ("FRMR", mIndex, 4); +} + + void ESM::CellRef::load (ESMReader& esm, bool wideRefNum) { // According to Hrnchamd, this does not belong to the actual ref. Instead, it is a marker indicating that @@ -13,10 +30,7 @@ void ESM::CellRef::load (ESMReader& esm, bool wideRefNum) if (esm.isNextSub ("NAM0")) esm.skipHSub(); - if (wideRefNum) - esm.getHNT (mRefNum, "FRMR", 8); - else - esm.getHNT (mRefNum.mIndex, "FRMR"); + mRefNum.load (esm, wideRefNum); mRefID = esm.getHNString ("NAME"); @@ -74,10 +88,7 @@ void ESM::CellRef::load (ESMReader& esm, bool wideRefNum) void ESM::CellRef::save (ESMWriter &esm, bool wideRefNum, bool inInventory) const { - if (wideRefNum) - esm.writeHNT ("FRMR", mRefNum, 8); - else - esm.writeHNT ("FRMR", mRefNum.mIndex, 4); + mRefNum.save (esm, wideRefNum); esm.writeHNCString("NAME", mRefID); diff --git a/components/esm/cellref.hpp b/components/esm/cellref.hpp index 9c57061b0..505f676b1 100644 --- a/components/esm/cellref.hpp +++ b/components/esm/cellref.hpp @@ -15,6 +15,10 @@ namespace ESM { int mIndex; int mContentFile; // -1 no content file + + void load (ESMReader& esm, bool wide = false); + + void save (ESMWriter &esm, bool wide = false) const; }; /* Cell reference. This represents ONE object (of many) inside the From a97f599e6529ebdf87188c110839baa40f0c6f7c Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 22 Jan 2015 13:41:09 +0100 Subject: [PATCH 0364/3725] fixed ref num saving in non-wide format --- apps/opencs/model/doc/savingstages.cpp | 36 +++++++++++++++++++++++--- apps/opencs/model/doc/savingstate.cpp | 2 +- apps/opencs/model/doc/savingstate.hpp | 5 ++-- components/esm/cellref.cpp | 6 ++++- 4 files changed, 41 insertions(+), 8 deletions(-) diff --git a/apps/opencs/model/doc/savingstages.cpp b/apps/opencs/model/doc/savingstages.cpp index 08f8c9eaa..6b8750b44 100644 --- a/apps/opencs/model/doc/savingstages.cpp +++ b/apps/opencs/model/doc/savingstages.cpp @@ -231,8 +231,18 @@ void CSMDoc::CollectionReferencesStage::perform (int stage, Messages& messages) record.mState==CSMWorld::RecordBase::State_Modified || record.mState==CSMWorld::RecordBase::State_ModifiedOnly) { - mState.getSubRecords()[Misc::StringUtils::lowerCase (record.get().mCell)] - .push_back (i); + std::string cellId = record.get().mOriginalCell.empty() ? + record.get().mCell : record.get().mOriginalCell; + + std::deque& indices = + mState.getSubRecords()[Misc::StringUtils::lowerCase (cellId)]; + + // collect moved references at the end of the container + if (!record.get().mOriginalCell.empty() && + record.get().mOriginalCell!=record.get().mCell) + indices.push_back (i); + else + indices.push_front (i); } } } @@ -253,7 +263,7 @@ void CSMDoc::WriteCellCollectionStage::perform (int stage, Messages& messages) const CSMWorld::Record& cell = mDocument.getData().getCells().getRecord (stage); - std::map >::const_iterator references = + std::map >::const_iterator references = mState.getSubRecords().find (Misc::StringUtils::lowerCase (cell.get().mId)); if (cell.mState==CSMWorld::RecordBase::State_Modified || @@ -284,7 +294,7 @@ void CSMDoc::WriteCellCollectionStage::perform (int stage, Messages& messages) // write references if (references!=mState.getSubRecords().end()) { - for (std::vector::const_iterator iter (references->second.begin()); + for (std::deque::const_iterator iter (references->second.begin()); iter!=references->second.end(); ++iter) { const CSMWorld::Record& ref = @@ -293,6 +303,24 @@ void CSMDoc::WriteCellCollectionStage::perform (int stage, Messages& messages) if (ref.mState==CSMWorld::RecordBase::State_Modified || ref.mState==CSMWorld::RecordBase::State_ModifiedOnly) { + if (!ref.get().mOriginalCell.empty() && + ref.get().mOriginalCell!=ref.get().mCell) + { + ESM::MovedCellRef moved; + moved.mRefNum = ref.get().mRefNum; + + std::istringstream stream (ref.get().mCell.c_str()); + + char ignore; + stream >> ignore >> moved.mTarget[0] >> moved.mTarget[1]; + + mState.getWriter().startSubRecord ("MVRF"); + + mState.getWriter().endRecord ("MVRF"); + mState.getWriter().writeHNT ("FRMR", moved.mRefNum.mIndex, 4); + mState.getWriter().writeHNT ("CNDT", moved.mTarget, 8); + } + ref.get().save (mState.getWriter()); } else if (ref.mState==CSMWorld::RecordBase::State_Deleted) diff --git a/apps/opencs/model/doc/savingstate.cpp b/apps/opencs/model/doc/savingstate.cpp index 84bca1e95..e7ad551b2 100644 --- a/apps/opencs/model/doc/savingstate.cpp +++ b/apps/opencs/model/doc/savingstate.cpp @@ -64,7 +64,7 @@ bool CSMDoc::SavingState::isProjectFile() const return mProjectFile; } -std::map >& CSMDoc::SavingState::getSubRecords() +std::map >& CSMDoc::SavingState::getSubRecords() { return mSubRecords; } diff --git a/apps/opencs/model/doc/savingstate.hpp b/apps/opencs/model/doc/savingstate.hpp index 577fc734d..e6c8c545a 100644 --- a/apps/opencs/model/doc/savingstate.hpp +++ b/apps/opencs/model/doc/savingstate.hpp @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -26,7 +27,7 @@ namespace CSMDoc ESM::ESMWriter mWriter; boost::filesystem::path mProjectPath; bool mProjectFile; - std::map > mSubRecords; // record ID, list of subrecords + std::map > mSubRecords; // record ID, list of subrecords public: @@ -49,7 +50,7 @@ namespace CSMDoc bool isProjectFile() const; ///< Currently saving project file? (instead of content file) - std::map >& getSubRecords(); + std::map >& getSubRecords(); }; diff --git a/components/esm/cellref.cpp b/components/esm/cellref.cpp index a14f977d6..0e258571f 100644 --- a/components/esm/cellref.cpp +++ b/components/esm/cellref.cpp @@ -17,7 +17,11 @@ void ESM::RefNum::save (ESMWriter &esm, bool wide) const if (wide) esm.writeHNT ("FRMR", *this, 8); else - esm.writeHNT ("FRMR", mIndex, 4); + { + int refNum = (mIndex & 0xffffff) | ((mContentFile==-1 ? 0xff : mContentFile)<<24); + + esm.writeHNT ("FRMR", refNum, 4); + } } From b95748d044a421c2e02fa54cdc7e8aa902039e6c Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 23 Jan 2015 02:32:38 +0100 Subject: [PATCH 0365/3725] Revert "Light charge handling fix" This reverts commit 5e0428243b38d18c55b80e7675ea74a0563f5e44. --- apps/esmtool/esmtool.cpp | 2 +- apps/essimporter/convertinventory.cpp | 2 +- apps/essimporter/importinventory.cpp | 6 +-- apps/essimporter/importinventory.hpp | 1 + apps/opencs/model/world/columnimp.hpp | 4 +- apps/openmw/mwclass/light.cpp | 56 ++++++++++++++++++++++++--- apps/openmw/mwclass/light.hpp | 10 +++++ apps/openmw/mwworld/cellref.cpp | 20 ++-------- apps/openmw/mwworld/cellref.hpp | 3 -- apps/openmw/mwworld/manualref.hpp | 2 +- components/esm/cellref.cpp | 10 ++--- components/esm/cellref.hpp | 6 +-- components/esm/objectstate.cpp | 10 +++-- components/esm/objectstate.hpp | 2 + 14 files changed, 87 insertions(+), 47 deletions(-) diff --git a/apps/esmtool/esmtool.cpp b/apps/esmtool/esmtool.cpp index b23ba72f9..a18736bf2 100644 --- a/apps/esmtool/esmtool.cpp +++ b/apps/esmtool/esmtool.cpp @@ -261,7 +261,7 @@ void loadCell(ESM::Cell &cell, ESM::ESMReader &esm, Arguments& info) std::cout << " Faction: '" << ref.mFaction << "'" << std::endl; std::cout << " Faction rank: '" << ref.mFactionRank << "'" << std::endl; std::cout << " Enchantment charge: '" << ref.mEnchantmentCharge << "'\n"; - std::cout << " Uses/health: '" << ref.mChargeInt << "'\n"; + std::cout << " Uses/health: '" << ref.mCharge << "'\n"; std::cout << " Gold value: '" << ref.mGoldValue << "'\n"; std::cout << " Blocked: '" << static_cast(ref.mReferenceBlocked) << "'" << std::endl; std::cout << " Deleted: " << deleted << std::endl; diff --git a/apps/essimporter/convertinventory.cpp b/apps/essimporter/convertinventory.cpp index 31272bf5a..6a31be6a3 100644 --- a/apps/essimporter/convertinventory.cpp +++ b/apps/essimporter/convertinventory.cpp @@ -12,10 +12,10 @@ namespace ESSImport { ESM::ObjectState objstate; objstate.blank(); - objstate.mRef = *it; objstate.mRef.mRefID = Misc::StringUtils::lowerCase(it->mId); objstate.mCount = std::abs(it->mCount); // restocking items have negative count in the savefile // openmw handles them differently, so no need to set any flags + objstate.mRef.mCharge = it->mCondition; state.mItems.push_back(std::make_pair(objstate, it->mRelativeEquipmentSlot)); } } diff --git a/apps/essimporter/importinventory.cpp b/apps/essimporter/importinventory.cpp index a20584ff5..2f5c3c054 100644 --- a/apps/essimporter/importinventory.cpp +++ b/apps/essimporter/importinventory.cpp @@ -45,9 +45,9 @@ namespace ESSImport // for XSOL and XCHG seen so far, but probably others too item.ESM::CellRef::loadData(esm); - int charge=-1; - esm.getHNOT(charge, "XHLT"); - item.mChargeInt = charge; + item.mCondition = -1; + // FIXME: for Lights, this is actually a float + esm.getHNOT(item.mCondition, "XHLT"); } mItems.push_back(item); diff --git a/apps/essimporter/importinventory.hpp b/apps/essimporter/importinventory.hpp index 99fed9b20..8a1594465 100644 --- a/apps/essimporter/importinventory.hpp +++ b/apps/essimporter/importinventory.hpp @@ -20,6 +20,7 @@ namespace ESSImport { std::string mId; int mCount; + int mCondition; int mRelativeEquipmentSlot; }; std::vector mItems; diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index da14bb495..eba73cf0b 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -1053,13 +1053,13 @@ namespace CSMWorld virtual QVariant get (const Record& record) const { - return record.get().mChargeInt; + return record.get().mCharge; } virtual void set (Record& record, const QVariant& data) { ESXRecordT record2 = record.get(); - record2.mChargeInt = data.toInt(); + record2.mCharge = data.toInt(); record.setModified (record2); } diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 35a21b63e..c50ad52d8 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -26,6 +26,27 @@ #include "../mwrender/actors.hpp" #include "../mwrender/renderinginterface.hpp" +namespace +{ + struct LightCustomData : public MWWorld::CustomData + { + float mTime; + ///< Time remaining + + LightCustomData(MWWorld::Ptr ptr) + { + MWWorld::LiveCellRef *ref = ptr.get(); + mTime = ref->mBase->mData.mTime; + } + ///< Constructs this CustomData from the base values for Ptr. + + virtual MWWorld::CustomData *clone() const + { + return new LightCustomData (*this); + } + }; +} + namespace MWClass { std::string Light::getId (const MWWorld::Ptr& ptr) const @@ -198,16 +219,17 @@ namespace MWClass void Light::setRemainingUsageTime (const MWWorld::Ptr& ptr, float duration) const { - ptr.getCellRef().setChargeFloat(duration); + ensureCustomData(ptr); + + float &timeRemaining = dynamic_cast (*ptr.getRefData().getCustomData()).mTime; + timeRemaining = duration; } float Light::getRemainingUsageTime (const MWWorld::Ptr& ptr) const { - MWWorld::LiveCellRef *ref = ptr.get(); - if (ptr.getCellRef().getCharge() == -1) - return ref->mBase->mData.mTime; - else - return ptr.getCellRef().getChargeFloat(); + ensureCustomData(ptr); + + return dynamic_cast (*ptr.getRefData().getCustomData()).mTime; } MWWorld::Ptr @@ -219,6 +241,12 @@ namespace MWClass return MWWorld::Ptr(&cell.get().insert(*ref), &cell); } + void Light::ensureCustomData (const MWWorld::Ptr& ptr) const + { + if (!ptr.getRefData().getCustomData()) + ptr.getRefData().setCustomData(new LightCustomData(ptr)); + } + bool Light::canSell (const MWWorld::Ptr& item, int npcServices) const { return npcServices & ESM::NPC::Lights; @@ -254,6 +282,22 @@ namespace MWClass return std::make_pair(1,""); } + void Light::readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state) + const + { + ensureCustomData (ptr); + + dynamic_cast (*ptr.getRefData().getCustomData()).mTime = state.mTime; + } + + void Light::writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state) + const + { + ensureCustomData (ptr); + + state.mTime = dynamic_cast (*ptr.getRefData().getCustomData()).mTime; + } + std::string Light::getSound(const MWWorld::Ptr& ptr) const { return ptr.get()->mBase->mSound; diff --git a/apps/openmw/mwclass/light.hpp b/apps/openmw/mwclass/light.hpp index 8658375b7..bbca30113 100644 --- a/apps/openmw/mwclass/light.hpp +++ b/apps/openmw/mwclass/light.hpp @@ -10,6 +10,8 @@ namespace MWClass virtual MWWorld::Ptr copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const; + void ensureCustomData (const MWWorld::Ptr& ptr) const; + public: /// Return ID of \a ptr @@ -73,6 +75,14 @@ namespace MWClass std::pair canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const; + virtual void readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state) + const; + ///< Read additional state from \a state into \a ptr. + + virtual void writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state) + const; + ///< Write additional state from \a ptr into \a state. + virtual std::string getSound(const MWWorld::Ptr& ptr) const; }; } diff --git a/apps/openmw/mwworld/cellref.cpp b/apps/openmw/mwworld/cellref.cpp index 744e0e27a..aa6627de5 100644 --- a/apps/openmw/mwworld/cellref.cpp +++ b/apps/openmw/mwworld/cellref.cpp @@ -81,29 +81,15 @@ namespace MWWorld int CellRef::getCharge() const { - return mCellRef.mChargeInt; + return mCellRef.mCharge; } void CellRef::setCharge(int charge) { - if (charge != mCellRef.mChargeInt) + if (charge != mCellRef.mCharge) { mChanged = true; - mCellRef.mChargeInt = charge; - } - } - - float CellRef::getChargeFloat() const - { - return mCellRef.mChargeFloat; - } - - void CellRef::setChargeFloat(float charge) - { - if (charge != mCellRef.mChargeFloat) - { - mChanged = true; - mCellRef.mChargeFloat = charge; + mCellRef.mCharge = charge; } } diff --git a/apps/openmw/mwworld/cellref.hpp b/apps/openmw/mwworld/cellref.hpp index 054fd7fc6..a7ffbe08b 100644 --- a/apps/openmw/mwworld/cellref.hpp +++ b/apps/openmw/mwworld/cellref.hpp @@ -60,11 +60,8 @@ namespace MWWorld // For weapon or armor, this is the remaining item health. // For tools (lockpicks, probes, repair hammer) it is the remaining uses. - // If this returns int(-1) it means full health. int getCharge() const; - float getChargeFloat() const; // Implemented as union with int charge void setCharge(int charge); - void setChargeFloat(float charge); // The NPC that owns this object (and will get angry if you steal it) std::string getOwner() const; diff --git a/apps/openmw/mwworld/manualref.hpp b/apps/openmw/mwworld/manualref.hpp index f32b07471..4eb93543b 100644 --- a/apps/openmw/mwworld/manualref.hpp +++ b/apps/openmw/mwworld/manualref.hpp @@ -28,7 +28,7 @@ namespace MWWorld cellRef.mRefID = name; cellRef.mScale = 1; cellRef.mFactionRank = 0; - cellRef.mChargeInt = -1; + cellRef.mCharge = -1; cellRef.mGoldValue = 1; cellRef.mEnchantmentCharge = -1; cellRef.mTeleport = false; diff --git a/components/esm/cellref.cpp b/components/esm/cellref.cpp index dfc3052ee..cd9fe8570 100644 --- a/components/esm/cellref.cpp +++ b/components/esm/cellref.cpp @@ -46,12 +46,12 @@ void ESM::CellRef::loadData(ESMReader &esm) esm.getHNOT (mFactionRank, "INDX"); mGoldValue = 1; - mChargeInt = -1; + mCharge = -1; mEnchantmentCharge = -1; esm.getHNOT (mEnchantmentCharge, "XCHG"); - esm.getHNOT (mChargeInt, "INTV"); + esm.getHNOT (mCharge, "INTV"); esm.getHNOT (mGoldValue, "NAM9"); @@ -106,8 +106,8 @@ void ESM::CellRef::save (ESMWriter &esm, bool wideRefNum, bool inInventory) cons if (mEnchantmentCharge != -1) esm.writeHNT("XCHG", mEnchantmentCharge); - if (mChargeInt != -1) - esm.writeHNT("INTV", mChargeInt); + if (mCharge != -1) + esm.writeHNT("INTV", mCharge); if (mGoldValue != 1) { esm.writeHNT("NAM9", mGoldValue); @@ -146,7 +146,7 @@ void ESM::CellRef::blank() mSoul.clear(); mFaction.clear(); mFactionRank = -2; - mChargeInt = -1; + mCharge = -1; mEnchantmentCharge = -1; mGoldValue = 0; mDestCell.clear(); diff --git a/components/esm/cellref.hpp b/components/esm/cellref.hpp index 56932aa4d..7aa0e4d44 100644 --- a/components/esm/cellref.hpp +++ b/components/esm/cellref.hpp @@ -59,11 +59,7 @@ namespace ESM // For weapon or armor, this is the remaining item health. // For tools (lockpicks, probes, repair hammer) it is the remaining uses. - union - { - int mChargeInt; - float mChargeFloat; - }; + int mCharge; // Remaining enchantment charge. This could be -1 if the charge was not touched yet (i.e. full). float mEnchantmentCharge; diff --git a/components/esm/objectstate.cpp b/components/esm/objectstate.cpp index 9ef1ccf80..66fd49663 100644 --- a/components/esm/objectstate.cpp +++ b/components/esm/objectstate.cpp @@ -24,9 +24,9 @@ void ESM::ObjectState::load (ESMReader &esm) esm.getHNOT (mLocalRotation, "LROT", 12); - // obsolete - int unused; - esm.getHNOT(unused, "LTIM"); + // used for lights only + mTime = 0; + esm.getHNOT (mTime, "LTIM"); // FIXME: assuming "false" as default would make more sense, but also break compatibility with older save files mHasCustomState = true; @@ -55,6 +55,9 @@ void ESM::ObjectState::save (ESMWriter &esm, bool inInventory) const esm.writeHNT ("LROT", mLocalRotation, 12); } + if (mTime) + esm.writeHNT ("LTIM", mTime); + if (!mHasCustomState) esm.writeHNT ("HCUS", false); } @@ -71,6 +74,7 @@ void ESM::ObjectState::blank() mPosition.rot[i] = 0; mLocalRotation[i] = 0; } + mTime = 0; mHasCustomState = true; } diff --git a/components/esm/objectstate.hpp b/components/esm/objectstate.hpp index d1077733a..b03689653 100644 --- a/components/esm/objectstate.hpp +++ b/components/esm/objectstate.hpp @@ -26,6 +26,8 @@ namespace ESM ESM::Position mPosition; float mLocalRotation[3]; + float mTime; // Used for lights only. Overhead should not be so awful, besides CellRef isn't OO either + // Is there any class-specific state following the ObjectState bool mHasCustomState; From fe31ca0ac0649a0e34617a5821454e04863531ca Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 23 Jan 2015 02:32:42 +0100 Subject: [PATCH 0366/3725] Revert "ESSImport: convert inventory equipment slots" This reverts commit 03df659e7d60c1047dd51b8d293cdd26f1cb9e2d. --- apps/essimporter/convertinventory.cpp | 2 +- apps/essimporter/importinventory.cpp | 12 +----------- apps/essimporter/importinventory.hpp | 1 - 3 files changed, 2 insertions(+), 13 deletions(-) diff --git a/apps/essimporter/convertinventory.cpp b/apps/essimporter/convertinventory.cpp index 6a31be6a3..42535d946 100644 --- a/apps/essimporter/convertinventory.cpp +++ b/apps/essimporter/convertinventory.cpp @@ -16,7 +16,7 @@ namespace ESSImport objstate.mCount = std::abs(it->mCount); // restocking items have negative count in the savefile // openmw handles them differently, so no need to set any flags objstate.mRef.mCharge = it->mCondition; - state.mItems.push_back(std::make_pair(objstate, it->mRelativeEquipmentSlot)); + state.mItems.push_back(std::make_pair(objstate, -1)); } } diff --git a/apps/essimporter/importinventory.cpp b/apps/essimporter/importinventory.cpp index 2f5c3c054..b4d193540 100644 --- a/apps/essimporter/importinventory.cpp +++ b/apps/essimporter/importinventory.cpp @@ -1,7 +1,5 @@ #include "importinventory.hpp" -#include - #include #include @@ -19,7 +17,6 @@ namespace ESSImport InventoryItem item; item.mId = contItem.mItem.toString(); item.mCount = contItem.mCount; - item.mRelativeEquipmentSlot = -1; // seems that a stack of items can have a set of subrecords for each item? rings0000.ess // doesn't make any sense to me, if the values were different then the items shouldn't stack in the first place? @@ -58,21 +55,14 @@ namespace ESSImport { // note: same item can be equipped 2 items (e.g. 2 rings) // and will be *stacked* in the NPCO list, unlike openmw! - // this is currently not handled properly. - esm.getSubHeader(); int itemIndex; // index of the item in the NPCO list esm.getT(itemIndex); - if (itemIndex < 0 || itemIndex >= int(mItems.size())) - esm.fail("equipment item index out of range"); - // appears to be a relative index for only the *possible* slots this item can be equipped in, - // i.e. 0 most of the time + // i.e. 0 most of the time, unlike openmw slot enum index int slotIndex; esm.getT(slotIndex); - - mItems[itemIndex].mRelativeEquipmentSlot = slotIndex; } } diff --git a/apps/essimporter/importinventory.hpp b/apps/essimporter/importinventory.hpp index 8a1594465..359e43fa6 100644 --- a/apps/essimporter/importinventory.hpp +++ b/apps/essimporter/importinventory.hpp @@ -21,7 +21,6 @@ namespace ESSImport std::string mId; int mCount; int mCondition; - int mRelativeEquipmentSlot; }; std::vector mItems; From c65f9cb3c0fa39f6f5664f68852ee5109663bf30 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 23 Jan 2015 02:32:43 +0100 Subject: [PATCH 0367/3725] Revert "Change save format to store relative equipment index" This reverts commit 89d9649b50b2b6e102b90517a5b136cc74415ba0. --- apps/openmw/mwworld/cellstore.cpp | 2 +- apps/openmw/mwworld/containerstore.cpp | 27 ++++++++++---------- apps/openmw/mwworld/containerstore.hpp | 12 ++++----- apps/openmw/mwworld/inventorystore.cpp | 35 ++++++-------------------- apps/openmw/mwworld/inventorystore.hpp | 6 ++--- apps/openmw/mwworld/worldimp.cpp | 4 +-- components/esm/inventorystate.hpp | 1 - 7 files changed, 31 insertions(+), 56 deletions(-) diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 545bbd4b3..605c8f9d2 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -466,7 +466,7 @@ namespace MWWorld // List moved references, from separately tracked list. for (ESM::CellRefTracker::const_iterator it = mCell->mLeasedRefs.begin(); it != mCell->mLeasedRefs.end(); ++it) { - const ESM::CellRef &ref = *it; + ESM::CellRef &ref = const_cast(*it); mIds.push_back(Misc::StringUtils::lowerCase(ref.mRefID)); } diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 5911b45f7..bd14720f7 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -85,29 +85,28 @@ void MWWorld::ContainerStore::storeState (const LiveCellRef& ref, ESM::Object ref.save (state); } -/// \todo make this method const once const-correct ContainerStoreIterators are available template -void MWWorld::ContainerStore::storeStates (CellRefList& collection, - std::vector >& states, bool equipable) +void MWWorld::ContainerStore::storeStates (const CellRefList& collection, + std::vector >& states, bool equipable) const { - for (typename CellRefList::List::iterator iter (collection.mList.begin()); + for (typename CellRefList::List::const_iterator iter (collection.mList.begin()); iter!=collection.mList.end(); ++iter) { if (iter->mData.getCount() == 0) continue; ESM::ObjectState state; storeState (*iter, state); - int slot = equipable ? getRelativeSlot (MWWorld::ContainerStoreIterator(this, iter)) : -1; + int slot = equipable ? getSlot (*iter) : -1; states.push_back (std::make_pair (state, slot)); } } -int MWWorld::ContainerStore::getRelativeSlot (const MWWorld::ContainerStoreIterator& iter) const +int MWWorld::ContainerStore::getSlot (const MWWorld::LiveCellRefBase& ref) const { return -1; } -void MWWorld::ContainerStore::setRelativeSlot (const MWWorld::ContainerStoreIterator& iter, int slot) {} +void MWWorld::ContainerStore::setSlot (const MWWorld::ContainerStoreIterator& iter, int slot) {} const std::string MWWorld::ContainerStore::sGoldId = "gold_001"; @@ -642,7 +641,7 @@ MWWorld::Ptr MWWorld::ContainerStore::search (const std::string& id) return Ptr(); } -void MWWorld::ContainerStore::writeState (ESM::InventoryState& state) +void MWWorld::ContainerStore::writeState (ESM::InventoryState& state) const { state.mItems.clear(); @@ -679,16 +678,16 @@ void MWWorld::ContainerStore::readState (const ESM::InventoryState& state) { case ESM::REC_ALCH: getState (potions, iter->first); break; case ESM::REC_APPA: getState (appas, iter->first); break; - case ESM::REC_ARMO: setRelativeSlot (getState (armors, iter->first), slot); break; + case ESM::REC_ARMO: setSlot (getState (armors, iter->first), slot); break; case ESM::REC_BOOK: getState (books, iter->first); break; - case ESM::REC_CLOT: setRelativeSlot (getState (clothes, iter->first), slot); break; + case ESM::REC_CLOT: setSlot (getState (clothes, iter->first), slot); break; case ESM::REC_INGR: getState (ingreds, iter->first); break; - case ESM::REC_LOCK: setRelativeSlot (getState (lockpicks, iter->first), slot); break; + case ESM::REC_LOCK: setSlot (getState (lockpicks, iter->first), slot); break; case ESM::REC_MISC: getState (miscItems, iter->first); break; - case ESM::REC_PROB: setRelativeSlot (getState (probes, iter->first), slot); break; + case ESM::REC_PROB: setSlot (getState (probes, iter->first), slot); break; case ESM::REC_REPA: getState (repairs, iter->first); break; - case ESM::REC_WEAP: setRelativeSlot (getState (weapons, iter->first), slot); break; - case ESM::REC_LIGH: setRelativeSlot (getState (lights, iter->first), slot); break; + case ESM::REC_WEAP: setSlot (getState (weapons, iter->first), slot); break; + case ESM::REC_LIGH: setSlot (getState (lights, iter->first), slot); break; default: std::cerr << "invalid item type in inventory state, refid " << state.mRef.mRefID << std::endl; diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index 4a95606f7..68ee41a1d 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -84,16 +84,15 @@ namespace MWWorld template void storeState (const LiveCellRef& ref, ESM::ObjectState& state) const; - /// \todo make this method const once const-correct ContainerStoreIterators are available template - void storeStates (CellRefList& collection, + void storeStates (const CellRefList& collection, std::vector >& states, - bool equipable = false); + bool equipable = false) const; - virtual int getRelativeSlot (const MWWorld::ContainerStoreIterator& iter) const; + virtual int getSlot (const MWWorld::LiveCellRefBase& ref) const; ///< Return inventory slot that \a ref is in or -1 (if \a ref is not in a slot). - virtual void setRelativeSlot (const MWWorld::ContainerStoreIterator& iter, int slot); + virtual void setSlot (const MWWorld::ContainerStoreIterator& iter, int slot); ///< Set slot for \a iter. Ignored if \a iter is an end iterator or if slot==-1. public: @@ -172,8 +171,7 @@ namespace MWWorld Ptr search (const std::string& id); - /// \todo make this method const once const-correct ContainerStoreIterators are available - virtual void writeState (ESM::InventoryState& state); + virtual void writeState (ESM::InventoryState& state) const; virtual void readState (const ESM::InventoryState& state); diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 8f272ca49..445b42d8d 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -49,40 +49,19 @@ void MWWorld::InventoryStore::initSlots (TSlots& slots_) slots_.push_back (end()); } -int MWWorld::InventoryStore::getRelativeSlot (const MWWorld::ContainerStoreIterator& iter) +int MWWorld::InventoryStore::getSlot (const MWWorld::LiveCellRefBase& ref) const { for (int i = 0; i (mSlots.size()); ++i) - if (mSlots[i].getType()!=-1 && mSlots[i] == iter) - { - // linear complexity, but allowedSlots is most of the time just 1 anyway - std::vector allowedSlots = iter->getClass().getEquipmentSlots(*iter).first; - std::vector::iterator found = std::find(allowedSlots.begin(),allowedSlots.end(),i); - if (found == allowedSlots.end()) - return -1; - else - return std::distance(allowedSlots.begin(), found); - } + if (mSlots[i].getType()!=-1 && mSlots[i]->getBase()==&ref) + return i; return -1; } -void MWWorld::InventoryStore::setRelativeSlot (const MWWorld::ContainerStoreIterator& iter, int relativeSlot) +void MWWorld::InventoryStore::setSlot (const MWWorld::ContainerStoreIterator& iter, int slot) { - if (relativeSlot < 0 || iter == end()) - return; - - std::pair, bool> allowedSlots = iter->getClass().getEquipmentSlots(*iter); - relativeSlot = std::min(int(allowedSlots.first.size()-1), relativeSlot); - - // unstack if required - if (!allowedSlots.second && iter->getRefData().getCount() > 1) - { - MWWorld::ContainerStoreIterator newIter = addNewStack(*iter, 1); - iter->getRefData().setCount(iter->getRefData().getCount()-1); - mSlots[allowedSlots.first[relativeSlot]] = newIter; - } - else - mSlots[allowedSlots.first[relativeSlot]] = iter; + if (iter!=end() && slot>=0 && slotgetCharacter(refdata.getHandle()); + const OEngine::Physic::PhysicActor *physactor = mPhysEngine->getCharacter(refdata.getHandle()); if(!physactor) return false; @@ -2049,7 +2049,7 @@ namespace MWWorld mPhysEngine); if(tracer.mFraction < 1.0f) // collision, must be close to something below { - physactor->setOnGround(true); + const_cast (physactor)->setOnGround(true); return true; } else diff --git a/components/esm/inventorystate.hpp b/components/esm/inventorystate.hpp index 13af28e30..3d4407e7b 100644 --- a/components/esm/inventorystate.hpp +++ b/components/esm/inventorystate.hpp @@ -15,7 +15,6 @@ namespace ESM /// \brief State for inventories and containers struct InventoryState { - /// std::vector > mItems; std::map mLevelledItemMap; From d13335ba40f10203cd9e9f86a198eab98c93c168 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 23 Jan 2015 15:31:44 +0100 Subject: [PATCH 0368/3725] Ensure the item can be equipped in the given slot when loading inventory --- apps/openmw/mwworld/cellstore.cpp | 2 +- apps/openmw/mwworld/containerstore.cpp | 5 ++--- apps/openmw/mwworld/containerstore.hpp | 5 +++-- apps/openmw/mwworld/inventorystore.cpp | 22 ++++++++++++++++++---- apps/openmw/mwworld/inventorystore.hpp | 4 ++-- apps/openmw/mwworld/worldimp.cpp | 4 ++-- components/esm/inventorystate.hpp | 1 + 7 files changed, 29 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 605c8f9d2..545bbd4b3 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -466,7 +466,7 @@ namespace MWWorld // List moved references, from separately tracked list. for (ESM::CellRefTracker::const_iterator it = mCell->mLeasedRefs.begin(); it != mCell->mLeasedRefs.end(); ++it) { - ESM::CellRef &ref = const_cast(*it); + const ESM::CellRef &ref = *it; mIds.push_back(Misc::StringUtils::lowerCase(ref.mRefID)); } diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index bd14720f7..ba70e2f8f 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -86,7 +86,7 @@ void MWWorld::ContainerStore::storeState (const LiveCellRef& ref, ESM::Object } template -void MWWorld::ContainerStore::storeStates (const CellRefList& collection, +void MWWorld::ContainerStore::storeStates (CellRefList& collection, std::vector >& states, bool equipable) const { for (typename CellRefList::List::const_iterator iter (collection.mList.begin()); @@ -641,7 +641,7 @@ MWWorld::Ptr MWWorld::ContainerStore::search (const std::string& id) return Ptr(); } -void MWWorld::ContainerStore::writeState (ESM::InventoryState& state) const +void MWWorld::ContainerStore::writeState (ESM::InventoryState& state) { state.mItems.clear(); @@ -688,7 +688,6 @@ void MWWorld::ContainerStore::readState (const ESM::InventoryState& state) case ESM::REC_REPA: getState (repairs, iter->first); break; case ESM::REC_WEAP: setSlot (getState (weapons, iter->first), slot); break; case ESM::REC_LIGH: setSlot (getState (lights, iter->first), slot); break; - default: std::cerr << "invalid item type in inventory state, refid " << state.mRef.mRefID << std::endl; break; diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index 68ee41a1d..f7c8a369c 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -85,7 +85,7 @@ namespace MWWorld void storeState (const LiveCellRef& ref, ESM::ObjectState& state) const; template - void storeStates (const CellRefList& collection, + void storeStates (CellRefList& collection, std::vector >& states, bool equipable = false) const; @@ -171,7 +171,8 @@ namespace MWWorld Ptr search (const std::string& id); - virtual void writeState (ESM::InventoryState& state) const; + /// \todo make this method const once const-correct ContainerStoreIterators are available + virtual void writeState (ESM::InventoryState& state); virtual void readState (const ESM::InventoryState& state); diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 445b42d8d..be93824e5 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -58,10 +58,24 @@ int MWWorld::InventoryStore::getSlot (const MWWorld::LiveCellRefBase& ref) const return -1; } -void MWWorld::InventoryStore::setSlot (const MWWorld::ContainerStoreIterator& iter, int slot) +void MWWorld::InventoryStore::setSlot (const MWWorld::ContainerStoreIterator& iter, int relativeSlot) { - if (iter!=end() && slot>=0 && slot, bool> allowedSlots = iter->getClass().getEquipmentSlots(*iter); + relativeSlot = std::min(int(allowedSlots.first.size()-1), relativeSlot); + + // unstack if required + if (!allowedSlots.second && iter->getRefData().getCount() > 1) + { + MWWorld::ContainerStoreIterator newIter = addNewStack(*iter, 1); + iter->getRefData().setCount(iter->getRefData().getCount()-1); + mSlots[allowedSlots.first[relativeSlot]] = newIter; + } + else + mSlots[allowedSlots.first[relativeSlot]] = iter; } MWWorld::InventoryStore::InventoryStore() @@ -703,7 +717,7 @@ bool MWWorld::InventoryStore::isEquipped(const MWWorld::Ptr &item) return false; } -void MWWorld::InventoryStore::writeState(ESM::InventoryState &state) const +void MWWorld::InventoryStore::writeState(ESM::InventoryState &state) { MWWorld::ContainerStore::writeState(state); diff --git a/apps/openmw/mwworld/inventorystore.hpp b/apps/openmw/mwworld/inventorystore.hpp index 9fd18c54b..7bd977e39 100644 --- a/apps/openmw/mwworld/inventorystore.hpp +++ b/apps/openmw/mwworld/inventorystore.hpp @@ -116,7 +116,7 @@ namespace MWWorld virtual int getSlot (const MWWorld::LiveCellRefBase& ref) const; ///< Return inventory slot that \a ref is in or -1 (if \a ref is not in a slot). - virtual void setSlot (const MWWorld::ContainerStoreIterator& iter, int slot); + virtual void setSlot (const MWWorld::ContainerStoreIterator& iter, int relativeSlot); ///< Set slot for \a iter. Ignored if \a iter is an end iterator or if slot==-1. public: @@ -209,7 +209,7 @@ namespace MWWorld virtual void clear(); ///< Empty container. - virtual void writeState (ESM::InventoryState& state) const; + virtual void writeState (ESM::InventoryState& state); virtual void readState (const ESM::InventoryState& state); }; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 104605e65..f7d5d9616 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2031,7 +2031,7 @@ namespace MWWorld bool World::isOnGround(const MWWorld::Ptr &ptr) const { RefData &refdata = ptr.getRefData(); - const OEngine::Physic::PhysicActor *physactor = mPhysEngine->getCharacter(refdata.getHandle()); + OEngine::Physic::PhysicActor *physactor = mPhysEngine->getCharacter(refdata.getHandle()); if(!physactor) return false; @@ -2049,7 +2049,7 @@ namespace MWWorld mPhysEngine); if(tracer.mFraction < 1.0f) // collision, must be close to something below { - const_cast (physactor)->setOnGround(true); + physactor->setOnGround(true); return true; } else diff --git a/components/esm/inventorystate.hpp b/components/esm/inventorystate.hpp index 3d4407e7b..13af28e30 100644 --- a/components/esm/inventorystate.hpp +++ b/components/esm/inventorystate.hpp @@ -15,6 +15,7 @@ namespace ESM /// \brief State for inventories and containers struct InventoryState { + /// std::vector > mItems; std::map mLevelledItemMap; From 7ead963075c0ef0ff036dec10531367548ae4a56 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 23 Jan 2015 15:33:30 +0100 Subject: [PATCH 0369/3725] Revert "Revert "ESSImport: convert inventory equipment slots"" This reverts commit fe31ca0ac0649a0e34617a5821454e04863531ca. --- apps/essimporter/convertinventory.cpp | 2 +- apps/essimporter/importinventory.cpp | 12 +++++++++++- apps/essimporter/importinventory.hpp | 1 + 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/apps/essimporter/convertinventory.cpp b/apps/essimporter/convertinventory.cpp index 42535d946..6a31be6a3 100644 --- a/apps/essimporter/convertinventory.cpp +++ b/apps/essimporter/convertinventory.cpp @@ -16,7 +16,7 @@ namespace ESSImport objstate.mCount = std::abs(it->mCount); // restocking items have negative count in the savefile // openmw handles them differently, so no need to set any flags objstate.mRef.mCharge = it->mCondition; - state.mItems.push_back(std::make_pair(objstate, -1)); + state.mItems.push_back(std::make_pair(objstate, it->mRelativeEquipmentSlot)); } } diff --git a/apps/essimporter/importinventory.cpp b/apps/essimporter/importinventory.cpp index b4d193540..2f5c3c054 100644 --- a/apps/essimporter/importinventory.cpp +++ b/apps/essimporter/importinventory.cpp @@ -1,5 +1,7 @@ #include "importinventory.hpp" +#include + #include #include @@ -17,6 +19,7 @@ namespace ESSImport InventoryItem item; item.mId = contItem.mItem.toString(); item.mCount = contItem.mCount; + item.mRelativeEquipmentSlot = -1; // seems that a stack of items can have a set of subrecords for each item? rings0000.ess // doesn't make any sense to me, if the values were different then the items shouldn't stack in the first place? @@ -55,14 +58,21 @@ namespace ESSImport { // note: same item can be equipped 2 items (e.g. 2 rings) // and will be *stacked* in the NPCO list, unlike openmw! + // this is currently not handled properly. + esm.getSubHeader(); int itemIndex; // index of the item in the NPCO list esm.getT(itemIndex); + if (itemIndex < 0 || itemIndex >= int(mItems.size())) + esm.fail("equipment item index out of range"); + // appears to be a relative index for only the *possible* slots this item can be equipped in, - // i.e. 0 most of the time, unlike openmw slot enum index + // i.e. 0 most of the time int slotIndex; esm.getT(slotIndex); + + mItems[itemIndex].mRelativeEquipmentSlot = slotIndex; } } diff --git a/apps/essimporter/importinventory.hpp b/apps/essimporter/importinventory.hpp index 359e43fa6..8a1594465 100644 --- a/apps/essimporter/importinventory.hpp +++ b/apps/essimporter/importinventory.hpp @@ -21,6 +21,7 @@ namespace ESSImport std::string mId; int mCount; int mCondition; + int mRelativeEquipmentSlot; }; std::vector mItems; From c7d15e6f74a81e007b48ddeb5f3a077ac4812312 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 23 Jan 2015 15:33:39 +0100 Subject: [PATCH 0370/3725] Revert "Revert "Light charge handling fix"" This reverts commit b95748d044a421c2e02fa54cdc7e8aa902039e6c. --- apps/esmtool/esmtool.cpp | 2 +- apps/essimporter/convertinventory.cpp | 2 +- apps/essimporter/importinventory.cpp | 6 +-- apps/essimporter/importinventory.hpp | 1 - apps/opencs/model/world/columnimp.hpp | 4 +- apps/openmw/mwclass/light.cpp | 56 +++------------------------ apps/openmw/mwclass/light.hpp | 10 ----- apps/openmw/mwworld/cellref.cpp | 20 ++++++++-- apps/openmw/mwworld/cellref.hpp | 3 ++ apps/openmw/mwworld/manualref.hpp | 2 +- components/esm/cellref.cpp | 10 ++--- components/esm/cellref.hpp | 6 ++- components/esm/objectstate.cpp | 10 ++--- components/esm/objectstate.hpp | 2 - 14 files changed, 47 insertions(+), 87 deletions(-) diff --git a/apps/esmtool/esmtool.cpp b/apps/esmtool/esmtool.cpp index a18736bf2..b23ba72f9 100644 --- a/apps/esmtool/esmtool.cpp +++ b/apps/esmtool/esmtool.cpp @@ -261,7 +261,7 @@ void loadCell(ESM::Cell &cell, ESM::ESMReader &esm, Arguments& info) std::cout << " Faction: '" << ref.mFaction << "'" << std::endl; std::cout << " Faction rank: '" << ref.mFactionRank << "'" << std::endl; std::cout << " Enchantment charge: '" << ref.mEnchantmentCharge << "'\n"; - std::cout << " Uses/health: '" << ref.mCharge << "'\n"; + std::cout << " Uses/health: '" << ref.mChargeInt << "'\n"; std::cout << " Gold value: '" << ref.mGoldValue << "'\n"; std::cout << " Blocked: '" << static_cast(ref.mReferenceBlocked) << "'" << std::endl; std::cout << " Deleted: " << deleted << std::endl; diff --git a/apps/essimporter/convertinventory.cpp b/apps/essimporter/convertinventory.cpp index 6a31be6a3..31272bf5a 100644 --- a/apps/essimporter/convertinventory.cpp +++ b/apps/essimporter/convertinventory.cpp @@ -12,10 +12,10 @@ namespace ESSImport { ESM::ObjectState objstate; objstate.blank(); + objstate.mRef = *it; objstate.mRef.mRefID = Misc::StringUtils::lowerCase(it->mId); objstate.mCount = std::abs(it->mCount); // restocking items have negative count in the savefile // openmw handles them differently, so no need to set any flags - objstate.mRef.mCharge = it->mCondition; state.mItems.push_back(std::make_pair(objstate, it->mRelativeEquipmentSlot)); } } diff --git a/apps/essimporter/importinventory.cpp b/apps/essimporter/importinventory.cpp index 2f5c3c054..a20584ff5 100644 --- a/apps/essimporter/importinventory.cpp +++ b/apps/essimporter/importinventory.cpp @@ -45,9 +45,9 @@ namespace ESSImport // for XSOL and XCHG seen so far, but probably others too item.ESM::CellRef::loadData(esm); - item.mCondition = -1; - // FIXME: for Lights, this is actually a float - esm.getHNOT(item.mCondition, "XHLT"); + int charge=-1; + esm.getHNOT(charge, "XHLT"); + item.mChargeInt = charge; } mItems.push_back(item); diff --git a/apps/essimporter/importinventory.hpp b/apps/essimporter/importinventory.hpp index 8a1594465..99fed9b20 100644 --- a/apps/essimporter/importinventory.hpp +++ b/apps/essimporter/importinventory.hpp @@ -20,7 +20,6 @@ namespace ESSImport { std::string mId; int mCount; - int mCondition; int mRelativeEquipmentSlot; }; std::vector mItems; diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index eba73cf0b..da14bb495 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -1053,13 +1053,13 @@ namespace CSMWorld virtual QVariant get (const Record& record) const { - return record.get().mCharge; + return record.get().mChargeInt; } virtual void set (Record& record, const QVariant& data) { ESXRecordT record2 = record.get(); - record2.mCharge = data.toInt(); + record2.mChargeInt = data.toInt(); record.setModified (record2); } diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index c50ad52d8..35a21b63e 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -26,27 +26,6 @@ #include "../mwrender/actors.hpp" #include "../mwrender/renderinginterface.hpp" -namespace -{ - struct LightCustomData : public MWWorld::CustomData - { - float mTime; - ///< Time remaining - - LightCustomData(MWWorld::Ptr ptr) - { - MWWorld::LiveCellRef *ref = ptr.get(); - mTime = ref->mBase->mData.mTime; - } - ///< Constructs this CustomData from the base values for Ptr. - - virtual MWWorld::CustomData *clone() const - { - return new LightCustomData (*this); - } - }; -} - namespace MWClass { std::string Light::getId (const MWWorld::Ptr& ptr) const @@ -219,17 +198,16 @@ namespace MWClass void Light::setRemainingUsageTime (const MWWorld::Ptr& ptr, float duration) const { - ensureCustomData(ptr); - - float &timeRemaining = dynamic_cast (*ptr.getRefData().getCustomData()).mTime; - timeRemaining = duration; + ptr.getCellRef().setChargeFloat(duration); } float Light::getRemainingUsageTime (const MWWorld::Ptr& ptr) const { - ensureCustomData(ptr); - - return dynamic_cast (*ptr.getRefData().getCustomData()).mTime; + MWWorld::LiveCellRef *ref = ptr.get(); + if (ptr.getCellRef().getCharge() == -1) + return ref->mBase->mData.mTime; + else + return ptr.getCellRef().getChargeFloat(); } MWWorld::Ptr @@ -241,12 +219,6 @@ namespace MWClass return MWWorld::Ptr(&cell.get().insert(*ref), &cell); } - void Light::ensureCustomData (const MWWorld::Ptr& ptr) const - { - if (!ptr.getRefData().getCustomData()) - ptr.getRefData().setCustomData(new LightCustomData(ptr)); - } - bool Light::canSell (const MWWorld::Ptr& item, int npcServices) const { return npcServices & ESM::NPC::Lights; @@ -282,22 +254,6 @@ namespace MWClass return std::make_pair(1,""); } - void Light::readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state) - const - { - ensureCustomData (ptr); - - dynamic_cast (*ptr.getRefData().getCustomData()).mTime = state.mTime; - } - - void Light::writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state) - const - { - ensureCustomData (ptr); - - state.mTime = dynamic_cast (*ptr.getRefData().getCustomData()).mTime; - } - std::string Light::getSound(const MWWorld::Ptr& ptr) const { return ptr.get()->mBase->mSound; diff --git a/apps/openmw/mwclass/light.hpp b/apps/openmw/mwclass/light.hpp index bbca30113..8658375b7 100644 --- a/apps/openmw/mwclass/light.hpp +++ b/apps/openmw/mwclass/light.hpp @@ -10,8 +10,6 @@ namespace MWClass virtual MWWorld::Ptr copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const; - void ensureCustomData (const MWWorld::Ptr& ptr) const; - public: /// Return ID of \a ptr @@ -75,14 +73,6 @@ namespace MWClass std::pair canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const; - virtual void readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state) - const; - ///< Read additional state from \a state into \a ptr. - - virtual void writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state) - const; - ///< Write additional state from \a ptr into \a state. - virtual std::string getSound(const MWWorld::Ptr& ptr) const; }; } diff --git a/apps/openmw/mwworld/cellref.cpp b/apps/openmw/mwworld/cellref.cpp index aa6627de5..744e0e27a 100644 --- a/apps/openmw/mwworld/cellref.cpp +++ b/apps/openmw/mwworld/cellref.cpp @@ -81,15 +81,29 @@ namespace MWWorld int CellRef::getCharge() const { - return mCellRef.mCharge; + return mCellRef.mChargeInt; } void CellRef::setCharge(int charge) { - if (charge != mCellRef.mCharge) + if (charge != mCellRef.mChargeInt) { mChanged = true; - mCellRef.mCharge = charge; + mCellRef.mChargeInt = charge; + } + } + + float CellRef::getChargeFloat() const + { + return mCellRef.mChargeFloat; + } + + void CellRef::setChargeFloat(float charge) + { + if (charge != mCellRef.mChargeFloat) + { + mChanged = true; + mCellRef.mChargeFloat = charge; } } diff --git a/apps/openmw/mwworld/cellref.hpp b/apps/openmw/mwworld/cellref.hpp index a7ffbe08b..054fd7fc6 100644 --- a/apps/openmw/mwworld/cellref.hpp +++ b/apps/openmw/mwworld/cellref.hpp @@ -60,8 +60,11 @@ namespace MWWorld // For weapon or armor, this is the remaining item health. // For tools (lockpicks, probes, repair hammer) it is the remaining uses. + // If this returns int(-1) it means full health. int getCharge() const; + float getChargeFloat() const; // Implemented as union with int charge void setCharge(int charge); + void setChargeFloat(float charge); // The NPC that owns this object (and will get angry if you steal it) std::string getOwner() const; diff --git a/apps/openmw/mwworld/manualref.hpp b/apps/openmw/mwworld/manualref.hpp index 4eb93543b..f32b07471 100644 --- a/apps/openmw/mwworld/manualref.hpp +++ b/apps/openmw/mwworld/manualref.hpp @@ -28,7 +28,7 @@ namespace MWWorld cellRef.mRefID = name; cellRef.mScale = 1; cellRef.mFactionRank = 0; - cellRef.mCharge = -1; + cellRef.mChargeInt = -1; cellRef.mGoldValue = 1; cellRef.mEnchantmentCharge = -1; cellRef.mTeleport = false; diff --git a/components/esm/cellref.cpp b/components/esm/cellref.cpp index cd9fe8570..dfc3052ee 100644 --- a/components/esm/cellref.cpp +++ b/components/esm/cellref.cpp @@ -46,12 +46,12 @@ void ESM::CellRef::loadData(ESMReader &esm) esm.getHNOT (mFactionRank, "INDX"); mGoldValue = 1; - mCharge = -1; + mChargeInt = -1; mEnchantmentCharge = -1; esm.getHNOT (mEnchantmentCharge, "XCHG"); - esm.getHNOT (mCharge, "INTV"); + esm.getHNOT (mChargeInt, "INTV"); esm.getHNOT (mGoldValue, "NAM9"); @@ -106,8 +106,8 @@ void ESM::CellRef::save (ESMWriter &esm, bool wideRefNum, bool inInventory) cons if (mEnchantmentCharge != -1) esm.writeHNT("XCHG", mEnchantmentCharge); - if (mCharge != -1) - esm.writeHNT("INTV", mCharge); + if (mChargeInt != -1) + esm.writeHNT("INTV", mChargeInt); if (mGoldValue != 1) { esm.writeHNT("NAM9", mGoldValue); @@ -146,7 +146,7 @@ void ESM::CellRef::blank() mSoul.clear(); mFaction.clear(); mFactionRank = -2; - mCharge = -1; + mChargeInt = -1; mEnchantmentCharge = -1; mGoldValue = 0; mDestCell.clear(); diff --git a/components/esm/cellref.hpp b/components/esm/cellref.hpp index 7aa0e4d44..56932aa4d 100644 --- a/components/esm/cellref.hpp +++ b/components/esm/cellref.hpp @@ -59,7 +59,11 @@ namespace ESM // For weapon or armor, this is the remaining item health. // For tools (lockpicks, probes, repair hammer) it is the remaining uses. - int mCharge; + union + { + int mChargeInt; + float mChargeFloat; + }; // Remaining enchantment charge. This could be -1 if the charge was not touched yet (i.e. full). float mEnchantmentCharge; diff --git a/components/esm/objectstate.cpp b/components/esm/objectstate.cpp index 66fd49663..9ef1ccf80 100644 --- a/components/esm/objectstate.cpp +++ b/components/esm/objectstate.cpp @@ -24,9 +24,9 @@ void ESM::ObjectState::load (ESMReader &esm) esm.getHNOT (mLocalRotation, "LROT", 12); - // used for lights only - mTime = 0; - esm.getHNOT (mTime, "LTIM"); + // obsolete + int unused; + esm.getHNOT(unused, "LTIM"); // FIXME: assuming "false" as default would make more sense, but also break compatibility with older save files mHasCustomState = true; @@ -55,9 +55,6 @@ void ESM::ObjectState::save (ESMWriter &esm, bool inInventory) const esm.writeHNT ("LROT", mLocalRotation, 12); } - if (mTime) - esm.writeHNT ("LTIM", mTime); - if (!mHasCustomState) esm.writeHNT ("HCUS", false); } @@ -74,7 +71,6 @@ void ESM::ObjectState::blank() mPosition.rot[i] = 0; mLocalRotation[i] = 0; } - mTime = 0; mHasCustomState = true; } diff --git a/components/esm/objectstate.hpp b/components/esm/objectstate.hpp index b03689653..d1077733a 100644 --- a/components/esm/objectstate.hpp +++ b/components/esm/objectstate.hpp @@ -26,8 +26,6 @@ namespace ESM ESM::Position mPosition; float mLocalRotation[3]; - float mTime; // Used for lights only. Overhead should not be so awful, besides CellRef isn't OO either - // Is there any class-specific state following the ObjectState bool mHasCustomState; From 69676906aef59e4179d8a194425e77a09cb5d812 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 21 Jan 2015 21:24:25 +0100 Subject: [PATCH 0371/3725] Don't clear known spells when reading from the savegame This is needed because the .ess format doesn't include the racial spells in the player's spell list. --- apps/essimporter/importplayer.cpp | 4 ++++ apps/openmw/mwmechanics/spells.cpp | 20 ++++++++------------ components/esm/spellstate.hpp | 1 + 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/apps/essimporter/importplayer.cpp b/apps/essimporter/importplayer.cpp index 285605068..ea9f1932c 100644 --- a/apps/essimporter/importplayer.cpp +++ b/apps/essimporter/importplayer.cpp @@ -23,6 +23,10 @@ namespace ESSImport mKnownDialogueTopics.push_back(esm.getHString()); } + if (esm.isNextSub("MNAM")) + esm.skipHSub(); // If this field is here it seems to specify the interior cell the player is in, + // but it's not always here, so it's kinda useless + esm.getHNT(mPNAM, "PNAM"); if (esm.isNextSub("SNAM")) diff --git a/apps/openmw/mwmechanics/spells.cpp b/apps/openmw/mwmechanics/spells.cpp index 1f8ada06d..dcbd3f09f 100644 --- a/apps/openmw/mwmechanics/spells.cpp +++ b/apps/openmw/mwmechanics/spells.cpp @@ -312,21 +312,17 @@ namespace MWMechanics void Spells::readState(const ESM::SpellState &state) { - mSpells = state.mSpells; - mSelectedSpell = state.mSelectedSpell; - - // Discard spells that are no longer available due to changed content files - for (TContainer::iterator iter = mSpells.begin(); iter!=mSpells.end();) + for (TContainer::const_iterator it = state.mSpells.begin(); it != state.mSpells.end(); ++it) { - const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get().search(iter->first); - if (!spell) + // Discard spells that are no longer available due to changed content files + const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get().search(it->first); + if (spell) { - if (iter->first == mSelectedSpell) - mSelectedSpell = ""; - mSpells.erase(iter++); + mSpells[it->first] = it->second; + + if (it->first == state.mSelectedSpell) + mSelectedSpell = it->first; } - else - ++iter; } // No need to discard spells here (doesn't really matter if non existent ids are kept) diff --git a/components/esm/spellstate.hpp b/components/esm/spellstate.hpp index 2ab27e908..028e6a387 100644 --- a/components/esm/spellstate.hpp +++ b/components/esm/spellstate.hpp @@ -12,6 +12,7 @@ namespace ESM class ESMReader; class ESMWriter; + // NOTE: spell ids must be lower case struct SpellState { struct CorprusStats From acf8461841546f5691f3c2e817af7a0d59116433 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 21 Jan 2015 22:25:37 +0100 Subject: [PATCH 0372/3725] ESSImport: some fixes --- apps/essimporter/converter.cpp | 22 ++++++++++------------ apps/essimporter/converter.hpp | 9 +++++++-- apps/essimporter/importacdt.cpp | 10 ++++------ apps/essimporter/importacdt.hpp | 4 +++- apps/essimporter/importcellref.cpp | 21 ++++++++++++++++----- apps/essimporter/importcellref.hpp | 10 +++------- apps/essimporter/importcrec.cpp | 10 ++++++++++ apps/essimporter/importnpcc.cpp | 3 +++ 8 files changed, 56 insertions(+), 33 deletions(-) diff --git a/apps/essimporter/converter.cpp b/apps/essimporter/converter.cpp index 099987762..81521a028 100644 --- a/apps/essimporter/converter.cpp +++ b/apps/essimporter/converter.cpp @@ -27,6 +27,8 @@ namespace objstate.mEnabled = cellref.mEnabled; objstate.mPosition = cellref.mPos; objstate.mRef.mRefNum = cellref.mRefNum; + if (cellref.mDeleted) + objstate.mCount = 0; } bool isIndexedRefId(const std::string& indexedRefId) @@ -34,6 +36,10 @@ namespace if (indexedRefId.size() <= 8) return false; + if (indexedRefId.find_first_not_of("0123456789") == std::string::npos) + return false; // entirely numeric refid, this is a reference to + // a dynamically created record e.g. player-enchanted weapon + std::string index = indexedRefId.substr(indexedRefId.size()-8); if(index.find_first_not_of("0123456789ABCDEF") == std::string::npos ) return true; @@ -136,13 +142,6 @@ namespace ESSImport { CellRef ref; ref.load (esm); - if (esm.isNextSub("DELE")) - { - // TODO - // strangely this can be e.g. 52 instead of just 1, - //std::cout << "deleted ref " << ref.mIndexedRefId << std::endl; - esm.skipHSub(); - } cellrefs.push_back(ref); } @@ -201,8 +200,7 @@ namespace ESSImport for (std::vector::const_iterator refIt = cell.mRefs.begin(); refIt != cell.mRefs.end(); ++refIt) { const CellRef& cellref = *refIt; - ESM::CellRef out; - out.blank(); + ESM::CellRef out (cellref); if (!isIndexedRefId(cellref.mIndexedRefId)) { @@ -241,8 +239,8 @@ namespace ESSImport objstate.mRef.mRefID = idLower; // probably need more micromanagement here so we don't overwrite values // from the ESM with default values - convertACDT(cellref.mActorData.mACDT, objstate.mCreatureStats); - convertNpcData(cellref.mActorData, objstate.mNpcStats); + convertACDT(cellref.mACDT, objstate.mCreatureStats); + convertNpcData(cellref, objstate.mNpcStats); convertNPCC(npccIt->second, objstate); convertCellRef(cellref, objstate); esm.writeHNT ("OBJE", ESM::REC_NPC_); @@ -273,7 +271,7 @@ namespace ESSImport objstate.blank(); objstate.mRef = out; objstate.mRef.mRefID = idLower; - convertACDT(cellref.mActorData.mACDT, objstate.mCreatureStats); + convertACDT(cellref.mACDT, objstate.mCreatureStats); // probably need more micromanagement here so we don't overwrite values // from the ESM with default values convertCREC(crecIt->second, objstate); diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index b68f9a218..9f6ad49df 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -90,14 +90,19 @@ public: ESM::NPC npc; std::string id = esm.getHNString("NAME"); npc.load(esm); - if (id != "player") // seems to occur sometimes, with "chargen X" names + if (id != "player") + { + // this handles changes to the NPC struct, but since there is no index here + // it will apply to ALL instances of the class. seems to be the reason for the + // "feature" in MW where changing AI settings of one guard will change it for all guards of that refID. std::cerr << "non-player NPC record: " << id << std::endl; + } else { mContext->mPlayer.mObject.mCreatureStats.mLevel = npc.mNpdt52.mLevel; mContext->mPlayerBase = npc; std::map empty; - // FIXME: player start spells, racial spells and birthsign spells aren't listed here, + // FIXME: player start spells and birthsign spells aren't listed here, // need to fix openmw to account for this for (std::vector::const_iterator it = npc.mSpells.mList.begin(); it != npc.mSpells.mList.end(); ++it) mContext->mPlayer.mObject.mCreatureStats.mSpells.mSpells[*it] = empty; diff --git a/apps/essimporter/importacdt.cpp b/apps/essimporter/importacdt.cpp index 84c800897..4d4a87a35 100644 --- a/apps/essimporter/importacdt.cpp +++ b/apps/essimporter/importacdt.cpp @@ -9,18 +9,16 @@ namespace ESSImport void ActorData::load(ESM::ESMReader &esm) { - // unsure at which point between NAME and ESM::CellRef - if (esm.isNextSub("MNAM")) - esm.skipHSub(); - if (esm.isNextSub("ACTN")) esm.skipHSub(); if (esm.isNextSub("STPR")) esm.skipHSub(); - ESM::CellRef bla; - bla.ESM::CellRef::loadData(esm); + if (esm.isNextSub("MNAM")) + esm.skipHSub(); + + ESM::CellRef::loadData(esm); // FIXME: not all actors have this, add flag esm.getHNOT(mACDT, "ACDT"); diff --git a/apps/essimporter/importacdt.hpp b/apps/essimporter/importacdt.hpp index 79f67d2c2..271f6df74 100644 --- a/apps/essimporter/importacdt.hpp +++ b/apps/essimporter/importacdt.hpp @@ -3,6 +3,8 @@ #include +#include + namespace ESM { struct ESMReader; @@ -37,7 +39,7 @@ namespace ESSImport }; #pragma pack(pop) - struct ActorData + struct ActorData : public ESM::CellRef { ACDT mACDT; diff --git a/apps/essimporter/importcellref.cpp b/apps/essimporter/importcellref.cpp index fd58d5bc1..7c4af1e02 100644 --- a/apps/essimporter/importcellref.cpp +++ b/apps/essimporter/importcellref.cpp @@ -7,6 +7,8 @@ namespace ESSImport void CellRef::load(ESM::ESMReader &esm) { + blank(); + // (FRMR subrecord name is already read by the loop in ConvertCell) esm.getHT(mRefNum.mIndex); // FRMR @@ -25,17 +27,26 @@ namespace ESSImport esm.getHT(lvcr); //std::cout << "LVCR: " << (int)lvcr << std::endl; } - mActorData.load(esm); + ActorData::load(esm); mEnabled = true; esm.getHNOT(mEnabled, "ZNAM"); - // should occur for all references but not levelled creature spawners - esm.getHNOT(mPos, "DATA", 24); - - // i've seen DATA record TWICE on a creature record - and with the exact same content too! weird + // DATA should occur for all references, except leveled creature spawners + // I've seen DATA *twice* on a creature record, and with the exact same content too! weird // alarmvoi0000.ess esm.getHNOT(mPos, "DATA", 24); + esm.getHNOT(mPos, "DATA", 24); + + mDeleted = 0; + if (esm.isNextSub("DELE")) + { + int deleted; + esm.getHT(deleted); + // Neither of this seems to work right... + //mDeleted = (deleted != 0); + //mDeleted = (deleted&0x1); + } if (esm.isNextSub("MVRF")) { diff --git a/apps/essimporter/importcellref.hpp b/apps/essimporter/importcellref.hpp index 77763d434..556ed19bf 100644 --- a/apps/essimporter/importcellref.hpp +++ b/apps/essimporter/importcellref.hpp @@ -15,20 +15,16 @@ namespace ESM namespace ESSImport { - // Not sure if we can share any code with ESM::CellRef here - struct CellRef + struct CellRef : public ActorData { std::string mIndexedRefId; - ESM::RefNum mRefNum; - - ActorData mActorData; - - ESM::Position mPos; std::string mScript; bool mEnabled; + bool mDeleted; + void load(ESM::ESMReader& esm); }; diff --git a/apps/essimporter/importcrec.cpp b/apps/essimporter/importcrec.cpp index 9cf455588..28e5ac56f 100644 --- a/apps/essimporter/importcrec.cpp +++ b/apps/essimporter/importcrec.cpp @@ -14,6 +14,16 @@ namespace ESSImport float scale; esm.getHNOT(scale, "XSCL"); + // FIXME: use AiPackageList, need to fix getSubName() + if (esm.isNextSub("AI_W")) + esm.skipHSub(); + if (esm.isNextSub("AI_E")) + esm.skipHSub(); + if (esm.isNextSub("AI_T")) + esm.skipHSub(); + if (esm.isNextSub("AI_F")) + esm.skipHSub(); + mInventory.load(esm); } diff --git a/apps/essimporter/importnpcc.cpp b/apps/essimporter/importnpcc.cpp index c389ede7f..7b8dda371 100644 --- a/apps/essimporter/importnpcc.cpp +++ b/apps/essimporter/importnpcc.cpp @@ -9,6 +9,9 @@ namespace ESSImport { esm.getHNT(mNPDT, "NPDT"); + // FIXME: use AiPackageList, need to fix getSubName() + if (esm.isNextSub("AI_W")) + esm.skipHSub(); if (esm.isNextSub("AI_E")) esm.skipHSub(); if (esm.isNextSub("AI_T")) From 1e92cab3e76b9b258ae813eb43f020ecba2da754 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 21 Jan 2015 23:35:09 +0100 Subject: [PATCH 0373/3725] ESSImport: read dialogue/journal records, not converted yet --- apps/essimporter/CMakeLists.txt | 5 ++ apps/essimporter/converter.hpp | 81 +++++++++++++++++++++++++++++++-- apps/essimporter/importdial.cpp | 13 ++++++ apps/essimporter/importdial.hpp | 20 ++++++++ apps/essimporter/importer.cpp | 10 +++- apps/essimporter/importgame.cpp | 13 ++++++ apps/essimporter/importgame.hpp | 33 ++++++++++++++ apps/essimporter/importinfo.cpp | 14 ++++++ apps/essimporter/importinfo.hpp | 24 ++++++++++ apps/essimporter/importjour.cpp | 13 ++++++ apps/essimporter/importjour.hpp | 25 ++++++++++ apps/essimporter/importques.cpp | 14 ++++++ apps/essimporter/importques.hpp | 28 ++++++++++++ components/esm/defs.hpp | 2 +- components/esm/loadnpcc.hpp | 17 ------- 15 files changed, 290 insertions(+), 22 deletions(-) create mode 100644 apps/essimporter/importdial.cpp create mode 100644 apps/essimporter/importdial.hpp create mode 100644 apps/essimporter/importgame.cpp create mode 100644 apps/essimporter/importgame.hpp create mode 100644 apps/essimporter/importinfo.cpp create mode 100644 apps/essimporter/importinfo.hpp create mode 100644 apps/essimporter/importjour.cpp create mode 100644 apps/essimporter/importjour.hpp create mode 100644 apps/essimporter/importques.cpp create mode 100644 apps/essimporter/importques.hpp diff --git a/apps/essimporter/CMakeLists.txt b/apps/essimporter/CMakeLists.txt index 8d1af714d..70eaefe2c 100644 --- a/apps/essimporter/CMakeLists.txt +++ b/apps/essimporter/CMakeLists.txt @@ -9,6 +9,11 @@ set(ESSIMPORTER_FILES importinventory.cpp importklst.cpp importcntc.cpp + importgame.cpp + importinfo.cpp + importdial.cpp + importques.cpp + importjour.cpp importercontext.cpp converter.cpp convertacdt.cpp diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index 9f6ad49df..4ca0e8386 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -12,6 +12,7 @@ #include #include #include +#include #include "importcrec.hpp" #include "importcntc.hpp" @@ -19,6 +20,11 @@ #include "importercontext.hpp" #include "importcellref.hpp" #include "importklst.hpp" +#include "importgame.hpp" +#include "importinfo.hpp" +#include "importdial.hpp" +#include "importques.hpp" +#include "importjour.hpp" #include "convertacdt.hpp" #include "convertnpcc.hpp" @@ -86,16 +92,15 @@ class ConvertNPC : public Converter public: virtual void read(ESM::ESMReader &esm) { - // this is always the player ESM::NPC npc; std::string id = esm.getHNString("NAME"); npc.load(esm); if (id != "player") { - // this handles changes to the NPC struct, but since there is no index here + // TODO: + // this should handle changes to the NPC struct, but since there is no index here // it will apply to ALL instances of the class. seems to be the reason for the // "feature" in MW where changing AI settings of one guard will change it for all guards of that refID. - std::cerr << "non-player NPC record: " << id << std::endl; } else { @@ -110,6 +115,18 @@ public: } }; +class ConvertCREA : public Converter +{ +public: + virtual void read(ESM::ESMReader &esm) + { + // See comment in ConvertNPC + ESM::Creature creature; + std::string id = esm.getHNString("NAME"); + creature.load(esm); + } +}; + class ConvertGlobal : public DefaultConverter { public: @@ -350,6 +367,64 @@ private: std::multimap mFactionStolenItems; }; +/// Seen responses for a dialogue topic? +/// Each DIAL record is followed by a number of INFO records, I believe, just like in ESMs +/// Dialogue conversion problems (probably have to adjust OpenMW format) - +/// - Journal is stored in one continuous HTML markup rather than each entry separately with associated info ID. +/// - Seen dialogue responses only store the INFO id, rather than the fulltext. +/// - Quest stages only store the INFO id, rather than the journal entry fulltext. +class ConvertINFO : public Converter +{ +public: + virtual void read(ESM::ESMReader& esm) + { + INFO info; + info.load(esm); + } +}; + +class ConvertDIAL : public Converter +{ +public: + virtual void read(ESM::ESMReader& esm) + { + std::string id = esm.getHNString("NAME"); + DIAL dial; + dial.load(esm); + } +}; + +class ConvertQUES : public Converter +{ +public: + virtual void read(ESM::ESMReader& esm) + { + std::string id = esm.getHNString("NAME"); + QUES quest; + quest.load(esm); + } +}; + +class ConvertJOUR : public Converter +{ +public: + virtual void read(ESM::ESMReader& esm) + { + JOUR journal; + journal.load(esm); + } +}; + +class ConvertGAME : public Converter +{ +public: + virtual void read(ESM::ESMReader &esm) + { + GAME game; + game.load(esm); + } +}; + } #endif diff --git a/apps/essimporter/importdial.cpp b/apps/essimporter/importdial.cpp new file mode 100644 index 000000000..228d00a5a --- /dev/null +++ b/apps/essimporter/importdial.cpp @@ -0,0 +1,13 @@ +#include "importdial.hpp" + +#include + +namespace ESSImport +{ + + void DIAL::load(ESM::ESMReader &esm) + { + esm.getHNT(mIndex, "XIDX"); + } + +} diff --git a/apps/essimporter/importdial.hpp b/apps/essimporter/importdial.hpp new file mode 100644 index 000000000..fe4b0c5b4 --- /dev/null +++ b/apps/essimporter/importdial.hpp @@ -0,0 +1,20 @@ +#ifndef OPENMW_ESSIMPORT_IMPORTDIAL_H +#define OPENMW_ESSIMPORT_IMPORTDIAL_H +namespace ESM +{ + struct ESMReader; +} + +namespace ESSImport +{ + + struct DIAL + { + int mIndex; // Journal index + + void load(ESM::ESMReader& esm); + }; + +} + +#endif diff --git a/apps/essimporter/importer.cpp b/apps/essimporter/importer.cpp index c2092ea4d..8603200da 100644 --- a/apps/essimporter/importer.cpp +++ b/apps/essimporter/importer.cpp @@ -201,11 +201,14 @@ namespace ESSImport const unsigned int recFMAP = ESM::FourCC<'F','M','A','P'>::value; const unsigned int recKLST = ESM::FourCC<'K','L','S','T'>::value; const unsigned int recSTLN = ESM::FourCC<'S','T','L','N'>::value; + const unsigned int recGAME = ESM::FourCC<'G','A','M','E'>::value; + const unsigned int recJOUR = ESM::FourCC<'J','O','U','R'>::value; std::map > converters; converters[ESM::REC_GLOB] = boost::shared_ptr(new ConvertGlobal()); converters[ESM::REC_BOOK] = boost::shared_ptr(new ConvertBook()); converters[ESM::REC_NPC_] = boost::shared_ptr(new ConvertNPC()); + converters[ESM::REC_CREA] = boost::shared_ptr(new ConvertCREA()); converters[ESM::REC_NPCC] = boost::shared_ptr(new ConvertNPCC()); converters[ESM::REC_CREC] = boost::shared_ptr(new ConvertCREC()); converters[recREFR ] = boost::shared_ptr(new ConvertREFR()); @@ -213,6 +216,7 @@ namespace ESSImport converters[recFMAP ] = boost::shared_ptr(new ConvertFMAP()); converters[recKLST ] = boost::shared_ptr(new ConvertKLST()); converters[recSTLN ] = boost::shared_ptr(new ConvertSTLN()); + converters[recGAME ] = boost::shared_ptr(new ConvertGAME()); converters[ESM::REC_CELL] = boost::shared_ptr(new ConvertCell()); converters[ESM::REC_ALCH] = boost::shared_ptr(new DefaultConverter()); converters[ESM::REC_CLAS] = boost::shared_ptr(new ConvertClass()); @@ -226,6 +230,10 @@ namespace ESSImport converters[ESM::REC_LEVI] = boost::shared_ptr(new DefaultConverter()); converters[ESM::REC_CNTC] = boost::shared_ptr(new ConvertCNTC()); converters[ESM::REC_FACT] = boost::shared_ptr(new ConvertFACT()); + converters[ESM::REC_INFO] = boost::shared_ptr(new ConvertINFO()); + converters[ESM::REC_DIAL] = boost::shared_ptr(new ConvertDIAL()); + converters[ESM::REC_QUES] = boost::shared_ptr(new ConvertQUES()); + converters[recJOUR ] = boost::shared_ptr(new ConvertJOUR()); std::set unknownRecords; @@ -248,7 +256,7 @@ namespace ESSImport else { if (unknownRecords.insert(n.val).second) - std::cerr << "unknown record " << n.toString() << std::endl; + std::cerr << "unknown record " << n.toString() << " (0x" << std::hex << esm.getFileOffset() << ")" << std::endl; esm.skipRecord(); } diff --git a/apps/essimporter/importgame.cpp b/apps/essimporter/importgame.cpp new file mode 100644 index 000000000..0b3a4f1a7 --- /dev/null +++ b/apps/essimporter/importgame.cpp @@ -0,0 +1,13 @@ +#include "importgame.hpp" + +#include + +namespace ESSImport +{ + +void GAME::load(ESM::ESMReader &esm) +{ + esm.getHNT(mGMDT, "GMDT"); +} + +} diff --git a/apps/essimporter/importgame.hpp b/apps/essimporter/importgame.hpp new file mode 100644 index 000000000..7bb814320 --- /dev/null +++ b/apps/essimporter/importgame.hpp @@ -0,0 +1,33 @@ +#ifndef OPENMW_ESSIMPORT_GAME_H +#define OPENMW_ESSIMPORT_GAME_H + +namespace ESM +{ + class ESMReader; +} + +namespace ESSImport +{ + + /// Weather data + struct GAME + { + struct GMDT + { + char mCellName[64]; + int mFogColour; + float mFogDensity; + int mCurrentWeather, mNextWeather; + int mWeatherTransition; // 0-100 transition between weathers, top 3 bytes may be garbage + float mTimeOfNextTransition; // weather changes when gamehour == timeOfNextTransition + int masserPhase, secundaPhase; // top 3 bytes may be garbage + }; + + GMDT mGMDT; + + void load(ESM::ESMReader& esm); + }; + +} + +#endif diff --git a/apps/essimporter/importinfo.cpp b/apps/essimporter/importinfo.cpp new file mode 100644 index 000000000..113155370 --- /dev/null +++ b/apps/essimporter/importinfo.cpp @@ -0,0 +1,14 @@ +#include "importinfo.hpp" + +#include + +namespace ESSImport +{ + + void INFO::load(ESM::ESMReader &esm) + { + mInfo = esm.getHNString("INAM"); + mActorRefId = esm.getHNString("ACDT"); + } + +} diff --git a/apps/essimporter/importinfo.hpp b/apps/essimporter/importinfo.hpp new file mode 100644 index 000000000..08f588f8d --- /dev/null +++ b/apps/essimporter/importinfo.hpp @@ -0,0 +1,24 @@ +#ifndef OPENMW_ESSIMPORT_IMPORTINFO_H +#define OPENMW_ESSIMPORT_IMPORTINFO_H + +#include + +namespace ESM +{ + struct ESMReader; +} + +namespace ESSImport +{ + + struct INFO + { + std::string mInfo; + std::string mActorRefId; + + void load(ESM::ESMReader& esm); + }; + +} + +#endif diff --git a/apps/essimporter/importjour.cpp b/apps/essimporter/importjour.cpp new file mode 100644 index 000000000..e5d24e113 --- /dev/null +++ b/apps/essimporter/importjour.cpp @@ -0,0 +1,13 @@ +#include "importjour.hpp" + +#include + +namespace ESSImport +{ + + void JOUR::load(ESM::ESMReader &esm) + { + mText = esm.getHNString("NAME"); + } + +} diff --git a/apps/essimporter/importjour.hpp b/apps/essimporter/importjour.hpp new file mode 100644 index 000000000..fe8775a93 --- /dev/null +++ b/apps/essimporter/importjour.hpp @@ -0,0 +1,25 @@ +#ifndef OPENMW_ESSIMPORT_IMPORTJOUR_H +#define OPENMW_ESSIMPORT_IMPORTJOUR_H + +#include + +namespace ESM +{ + struct ESMReader; +} + +namespace ESSImport +{ + + /// Journal + struct JOUR + { + // The entire journal, in HTML + std::string mText; + + void load(ESM::ESMReader& esm); + }; + +} + +#endif diff --git a/apps/essimporter/importques.cpp b/apps/essimporter/importques.cpp new file mode 100644 index 000000000..78b779e43 --- /dev/null +++ b/apps/essimporter/importques.cpp @@ -0,0 +1,14 @@ +#include "importques.hpp" + +#include + +namespace ESSImport +{ + + void QUES::load(ESM::ESMReader &esm) + { + while (esm.isNextSub("DATA")) + mInfo.push_back(esm.getHString()); + } + +} diff --git a/apps/essimporter/importques.hpp b/apps/essimporter/importques.hpp new file mode 100644 index 000000000..d7e718b92 --- /dev/null +++ b/apps/essimporter/importques.hpp @@ -0,0 +1,28 @@ +#ifndef OPENMW_ESSIMPORT_IMPORTQUES_H +#define OPENMW_ESSIMPORT_IMPORTQUES_H + +#include +#include + +namespace ESM +{ + struct ESMReader; +} + +namespace ESSImport +{ + + /// State for a quest + /// Presumably this record only exists when Tribunal is installed, + /// since pre-Tribunal there weren't any quest names in the data files. + struct QUES + { + std::string mName; // NAME, should be assigned from outside as usual + std::vector mInfo; // list of journal entries for the quest + + void load(ESM::ESMReader& esm); + }; + +} + +#endif diff --git a/components/esm/defs.hpp b/components/esm/defs.hpp index fe45d6914..effe9a3f1 100644 --- a/components/esm/defs.hpp +++ b/components/esm/defs.hpp @@ -97,7 +97,7 @@ enum RecNameInts // format 0 - saved games REC_SAVE = 0x45564153, - REC_JOUR = 0x524f55a4, + REC_JOUR = 0x524f55a4, // TODO: this is actually "\nOUR" rather than "JOUR", fix REC_QUES = 0x53455551, REC_GSCR = 0x52435347, REC_PLAY = 0x59414c50, diff --git a/components/esm/loadnpcc.hpp b/components/esm/loadnpcc.hpp index 6c087fd01..6b3cd533f 100644 --- a/components/esm/loadnpcc.hpp +++ b/components/esm/loadnpcc.hpp @@ -20,24 +20,7 @@ class ESMWriter; * SCPT records do not define new scripts, but assign values to the * variables of existing ones. * - * STLN - stolen items, ONAM is the owner - * - * GAME - weather data - * struct GMDT - { - char mCellName[64]; - int mFogColour; - float mFogDensity; - int mCurrentWeather, mNextWeather; - int mWeatherTransition; // 0-100 transition between weathers, top 3 bytes may be garbage - float mTimeOfNextTransition; // weather changes when gamehour == timeOfNextTransition - int masserPhase, secundaPhase; // top 3 bytes may be garbage - }; - * * VFXM, SPLM - no clue - * KLST - kill counter - * - * PCDT - seems to contain a lot of DNAMs, strings? * * FMAP - MAPH and MAPD, global map image. * From 5ce8a931a55fb74041d3690eb1ac4cffe4c73970 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 22 Jan 2015 03:34:44 +0100 Subject: [PATCH 0374/3725] ESSImport: fix a subrecord ordering issue --- apps/essimporter/importcellref.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/essimporter/importcellref.cpp b/apps/essimporter/importcellref.cpp index 7c4af1e02..845c574e4 100644 --- a/apps/essimporter/importcellref.cpp +++ b/apps/essimporter/importcellref.cpp @@ -19,6 +19,7 @@ namespace ESSImport mIndexedRefId = esm.getHNString("NAME"); + ActorData::load(esm); if (esm.isNextSub("LVCR")) { // occurs on leveled creature spawner references @@ -27,7 +28,6 @@ namespace ESSImport esm.getHT(lvcr); //std::cout << "LVCR: " << (int)lvcr << std::endl; } - ActorData::load(esm); mEnabled = true; esm.getHNOT(mEnabled, "ZNAM"); From cc7be1600d7491f8d23081ab6e7a413c943454fc Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 22 Jan 2015 03:36:12 +0100 Subject: [PATCH 0375/3725] Make missing hair/head in NpcAnimation non-fatal for consistency with addOrReplaceIndividualPart --- apps/openmw/mwrender/npcanimation.cpp | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 5e73a95f2..a8ba1abf5 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -263,17 +263,27 @@ void NpcAnimation::updateNpcBase() } else { - if (isVampire) + mHeadModel = ""; + if (isVampire) // FIXME: fall back to regular head when getVampireHead fails? mHeadModel = getVampireHead(mNpc->mRace, mNpc->mFlags & ESM::NPC::Female); else if (!mNpc->mHead.empty()) - mHeadModel = "meshes\\" + store.get().find(mNpc->mHead)->mModel; - else - mHeadModel = ""; + { + const ESM::BodyPart* bp = store.get().search(mNpc->mHead); + if (bp) + mHeadModel = "meshes\\" + bp->mModel; + else + std::cerr << "Failed to load body part '" << mNpc->mHead << "'" << std::endl; + } + mHairModel = ""; if (!mNpc->mHair.empty()) - mHairModel = "meshes\\" + store.get().find(mNpc->mHair)->mModel; - else - mHairModel = ""; + { + const ESM::BodyPart* bp = store.get().search(mNpc->mHair); + if (bp) + mHairModel = "meshes\\" + bp->mModel; + else + std::cerr << "Failed to load body part '" << mNpc->mHair << "'" << std::endl; + } } bool isBeast = (race->mData.mFlags & ESM::Race::Beast) != 0; From 0fd5575efee6495d0fa2eb4322457e543b2d69de Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 22 Jan 2015 03:39:00 +0100 Subject: [PATCH 0376/3725] Improve warning message in ContainerStore::readState --- apps/openmw/mwworld/containerstore.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index ba70e2f8f..57621b7a4 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -688,8 +688,11 @@ void MWWorld::ContainerStore::readState (const ESM::InventoryState& state) case ESM::REC_REPA: getState (repairs, iter->first); break; case ESM::REC_WEAP: setSlot (getState (weapons, iter->first), slot); break; case ESM::REC_LIGH: setSlot (getState (lights, iter->first), slot); break; + case 0: + std::cerr << "Dropping reference to '" << state.mRef.mRefID << "' (object no longer exists)" << std::endl; + break; default: - std::cerr << "invalid item type in inventory state, refid " << state.mRef.mRefID << std::endl; + std::cerr << "Invalid item type in inventory state, refid " << state.mRef.mRefID << std::endl; break; } } From 98402e579de14b6e203e4073481ef0fb689e2553 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 22 Jan 2015 03:39:37 +0100 Subject: [PATCH 0377/3725] ESSImport: fix non-existing items in player record causing load failure in OpenMW --- apps/essimporter/converter.hpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index 4ca0e8386..a88a364d2 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -111,6 +111,14 @@ public: // need to fix openmw to account for this for (std::vector::const_iterator it = npc.mSpells.mList.begin(); it != npc.mSpells.mList.end(); ++it) mContext->mPlayer.mObject.mCreatureStats.mSpells.mSpells[*it] = empty; + + // Clear the list now that we've written it, this prevents issues cropping up with + // ensureCustomData() in OpenMW tripping over no longer existing spells, where an error would be fatal. + mContext->mPlayerBase.mSpells.mList.clear(); + + // Same with inventory. Actually it's strange this would contain something, since there's already an + // inventory list in NPCC. There seems to be a fair amount of redundancy in this format. + mContext->mPlayerBase.mInventory.mList.clear(); } } }; @@ -127,6 +135,10 @@ public: } }; +// Do we need ConvertCONT? +// I've seen a CONT record in a certain save file, but the container contents in it +// were identical to a corresponding CNTC record. See previous comment about redundancy... + class ConvertGlobal : public DefaultConverter { public: From e2031279520aefbe00f053bd9dd75e2f842e2198 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 22 Jan 2015 03:54:33 +0100 Subject: [PATCH 0378/3725] ESSImport: read script variables (not converted yet) --- apps/essimporter/CMakeLists.txt | 2 + apps/essimporter/converter.hpp | 12 ++++++ apps/essimporter/importacdt.cpp | 13 +------ apps/essimporter/importacdt.hpp | 4 +- apps/essimporter/importer.cpp | 1 + apps/essimporter/importinventory.cpp | 13 +------ apps/essimporter/importinventory.hpp | 2 + apps/essimporter/importscpt.cpp | 20 ++++++++++ apps/essimporter/importscpt.hpp | 32 ++++++++++++++++ apps/essimporter/importscri.cpp | 55 ++++++++++++++++++++++++++++ apps/essimporter/importscri.hpp | 30 +++++++++++++++ components/esm/loadscpt.cpp | 32 ---------------- components/esm/loadscpt.hpp | 5 +++ 13 files changed, 164 insertions(+), 57 deletions(-) create mode 100644 apps/essimporter/importscpt.cpp create mode 100644 apps/essimporter/importscpt.hpp create mode 100644 apps/essimporter/importscri.cpp create mode 100644 apps/essimporter/importscri.hpp diff --git a/apps/essimporter/CMakeLists.txt b/apps/essimporter/CMakeLists.txt index 70eaefe2c..5db3a86dc 100644 --- a/apps/essimporter/CMakeLists.txt +++ b/apps/essimporter/CMakeLists.txt @@ -14,6 +14,8 @@ set(ESSIMPORTER_FILES importdial.cpp importques.cpp importjour.cpp + importscri.cpp + importscpt.cpp importercontext.cpp converter.cpp convertacdt.cpp diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index a88a364d2..9894de299 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -25,6 +25,7 @@ #include "importdial.hpp" #include "importques.hpp" #include "importjour.hpp" +#include "importscpt.hpp" #include "convertacdt.hpp" #include "convertnpcc.hpp" @@ -437,6 +438,17 @@ public: } }; +/// Running global script +class ConvertSCPT : public Converter +{ +public: + virtual void read(ESM::ESMReader &esm) + { + SCPT script; + script.load(esm); + } +}; + } #endif diff --git a/apps/essimporter/importacdt.cpp b/apps/essimporter/importacdt.cpp index 4d4a87a35..e590e2826 100644 --- a/apps/essimporter/importacdt.cpp +++ b/apps/essimporter/importacdt.cpp @@ -81,18 +81,7 @@ namespace ESSImport if (esm.isNextSub("CRED")) // creature only esm.getHExact(mCombatStats, 3*2*sizeof(int)); - mScript = esm.getHNOString("SCRI"); - - // script variables? - if (!mScript.empty()) - { - if (esm.isNextSub("SLCS")) - esm.skipHSub(); - if (esm.isNextSub("SLSD")) // Short Data? - esm.skipHSub(); - if (esm.isNextSub("SLFD")) // Float Data? - esm.skipHSub(); - } + mSCRI.load(esm); if (esm.isNextSub("ND3D")) esm.skipHSub(); diff --git a/apps/essimporter/importacdt.hpp b/apps/essimporter/importacdt.hpp index 271f6df74..3e3003f58 100644 --- a/apps/essimporter/importacdt.hpp +++ b/apps/essimporter/importacdt.hpp @@ -5,6 +5,8 @@ #include +#include "importscri.hpp" + namespace ESM { struct ESMReader; @@ -50,7 +52,7 @@ namespace ESSImport // to change them ingame int mCombatStats[3][2]; - std::string mScript; + SCRI mSCRI; void load(ESM::ESMReader& esm); }; diff --git a/apps/essimporter/importer.cpp b/apps/essimporter/importer.cpp index 8603200da..a29d26e2a 100644 --- a/apps/essimporter/importer.cpp +++ b/apps/essimporter/importer.cpp @@ -234,6 +234,7 @@ namespace ESSImport converters[ESM::REC_DIAL] = boost::shared_ptr(new ConvertDIAL()); converters[ESM::REC_QUES] = boost::shared_ptr(new ConvertQUES()); converters[recJOUR ] = boost::shared_ptr(new ConvertJOUR()); + converters[ESM::REC_SCPT] = boost::shared_ptr(new ConvertSCPT()); std::set unknownRecords; diff --git a/apps/essimporter/importinventory.cpp b/apps/essimporter/importinventory.cpp index a20584ff5..d27cd5c8c 100644 --- a/apps/essimporter/importinventory.cpp +++ b/apps/essimporter/importinventory.cpp @@ -29,18 +29,7 @@ namespace ESSImport if (esm.isNextSub("XIDX")) // index in the stack? esm.skipHSub(); - std::string script = esm.getHNOString("SCRI"); - // script variables? - // unsure if before or after ESM::CellRef - if (!script.empty()) - { - if (esm.isNextSub("SLCS")) - esm.skipHSub(); - if (esm.isNextSub("SLSD")) // Short Data? - esm.skipHSub(); - if (esm.isNextSub("SLFD")) // Float Data? - esm.skipHSub(); - } + item.mSCRI.load(esm); // for XSOL and XCHG seen so far, but probably others too item.ESM::CellRef::loadData(esm); diff --git a/apps/essimporter/importinventory.hpp b/apps/essimporter/importinventory.hpp index 99fed9b20..0b5405d96 100644 --- a/apps/essimporter/importinventory.hpp +++ b/apps/essimporter/importinventory.hpp @@ -5,6 +5,7 @@ #include #include +#include "importscri.hpp" namespace ESM { @@ -21,6 +22,7 @@ namespace ESSImport std::string mId; int mCount; int mRelativeEquipmentSlot; + SCRI mSCRI; }; std::vector mItems; diff --git a/apps/essimporter/importscpt.cpp b/apps/essimporter/importscpt.cpp new file mode 100644 index 000000000..374fd05fa --- /dev/null +++ b/apps/essimporter/importscpt.cpp @@ -0,0 +1,20 @@ +#include "importscpt.hpp" + +#include + + + +namespace ESSImport +{ + + void SCPT::load(ESM::ESMReader &esm) + { + esm.getHNT(mSCHD, "SCHD"); + + mSCRI.load(esm); + + mRNAM = -1; + esm.getHNOT(mRNAM, "RNAM"); + } + +} diff --git a/apps/essimporter/importscpt.hpp b/apps/essimporter/importscpt.hpp new file mode 100644 index 000000000..ca2439dda --- /dev/null +++ b/apps/essimporter/importscpt.hpp @@ -0,0 +1,32 @@ +#ifndef OPENMW_ESSIMPORT_IMPORTSCPT_H +#define OPENMW_ESSIMPORT_IMPORTSCPT_H + +#include "importscri.hpp" + +#include + +namespace ESM +{ + class ESMReader; +} + +namespace ESSImport +{ + + // A running global script + // TODO: test how targeted scripts are saved + struct SCPT + { + ESM::Script::SCHD mSCHD; + + // values of local variables + SCRI mSCRI; + + int mRNAM; // unknown, seems to be -1 for some scripts, some huge integer for others + + void load(ESM::ESMReader& esm); + }; + +} + +#endif diff --git a/apps/essimporter/importscri.cpp b/apps/essimporter/importscri.cpp new file mode 100644 index 000000000..de0b35c86 --- /dev/null +++ b/apps/essimporter/importscri.cpp @@ -0,0 +1,55 @@ +#include "importscri.hpp" + +#include + +namespace ESSImport +{ + + void SCRI::load(ESM::ESMReader &esm) + { + mScript = esm.getHNOString("SCRI"); + + int numShorts = 0, numLongs = 0, numFloats = 0; + if (esm.isNextSub("SLCS")) + { + esm.getSubHeader(); + esm.getT(numShorts); + esm.getT(numLongs); + esm.getT(numFloats); + } + + if (esm.isNextSub("SLSD")) + { + esm.getSubHeader(); + for (int i=0; i + +#include + +namespace ESM +{ + class ESMReader; +} + +namespace ESSImport +{ + + /// Local variable assigments for a running script + struct SCRI + { + std::string mScript; + + std::vector mShorts; + std::vector mLongs; + std::vector mFloats; + + void load(ESM::ESMReader& esm); + }; + +} + +#endif diff --git a/components/esm/loadscpt.cpp b/components/esm/loadscpt.cpp index f2f13d086..2df8e66ce 100644 --- a/components/esm/loadscpt.cpp +++ b/components/esm/loadscpt.cpp @@ -7,12 +7,6 @@ namespace ESM { -struct SCHD -{ - NAME32 mName; - Script::SCHDstruct mData; -}; - unsigned int Script::sRecordId = REC_SCPT; void Script::load(ESMReader &esm) @@ -92,32 +86,6 @@ void Script::load(ESMReader &esm) if (esm.isNextSub("SCVR")) { esm.skipHSub(); } - - // ESS only, TODO: move - if (esm.isNextSub("SLCS")) - { - esm.getSubHeader(); - char unknown[12]; - esm.getExact(unknown, 12); - } - if (esm.isNextSub("SLSD")) - { - float read; - esm.getSubHeader(); - // values of variables? - for (int i=0; i Date: Thu, 22 Jan 2015 04:12:08 +0100 Subject: [PATCH 0379/3725] Fix Tribunal/BM summon effects not working --- apps/essimporter/importcellref.cpp | 2 +- apps/openmw/mwmechanics/spellcasting.cpp | 13 ++++++++++--- apps/openmw/mwmechanics/spellcasting.hpp | 2 ++ apps/openmw/mwmechanics/summoning.cpp | 5 +++-- 4 files changed, 16 insertions(+), 6 deletions(-) diff --git a/apps/essimporter/importcellref.cpp b/apps/essimporter/importcellref.cpp index 845c574e4..1894b0023 100644 --- a/apps/essimporter/importcellref.cpp +++ b/apps/essimporter/importcellref.cpp @@ -23,7 +23,7 @@ namespace ESSImport if (esm.isNextSub("LVCR")) { // occurs on leveled creature spawner references - // probably some identifier for the the creature that has been spawned? + // probably some identifier for the creature that has been spawned? unsigned char lvcr; esm.getHT(lvcr); //std::cout << "LVCR: " << (int)lvcr << std::endl; diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index ff27ac5f6..49887e560 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -472,9 +472,7 @@ namespace MWMechanics applyInstantEffect(target, caster, EffectKey(*effectIt), magnitude); // Re-casting a summon effect will remove the creature from previous castings of that effect. - if (effectIt->mEffectID >= ESM::MagicEffect::SummonScamp - && effectIt->mEffectID <= ESM::MagicEffect::SummonStormAtronach - && !target.isEmpty() && target.getClass().isActor()) + if (isSummoningEffect(effectIt->mEffectID) && !target.isEmpty() && target.getClass().isActor()) { CreatureStats& targetStats = target.getClass().getCreatureStats(target); std::map::iterator found = targetStats.getSummonedCreatureMap().find(std::make_pair(effectIt->mEffectID, mId)); @@ -956,4 +954,13 @@ namespace MWMechanics return static_cast((result < 1) ? 1 : result); } + + bool isSummoningEffect(int effectId) + { + return ((effectId >= ESM::MagicEffect::SummonScamp + && effectId <= ESM::MagicEffect::SummonStormAtronach) + || effectId == ESM::MagicEffect::SummonCenturionSphere + || (effectId >= ESM::MagicEffect::SummonFabricant + && effectId <= ESM::MagicEffect::SummonCreature05)); + } } diff --git a/apps/openmw/mwmechanics/spellcasting.hpp b/apps/openmw/mwmechanics/spellcasting.hpp index 00fae847f..2d550e085 100644 --- a/apps/openmw/mwmechanics/spellcasting.hpp +++ b/apps/openmw/mwmechanics/spellcasting.hpp @@ -22,6 +22,8 @@ namespace MWMechanics ESM::Skill::SkillEnum spellSchoolToSkill(int school); + bool isSummoningEffect(int effectId); + /** * @param spell spell to cast * @param actor calculate spell success chance for this actor (depends on actor's skills) diff --git a/apps/openmw/mwmechanics/summoning.cpp b/apps/openmw/mwmechanics/summoning.cpp index 356cb422f..ec9bd0ea0 100644 --- a/apps/openmw/mwmechanics/summoning.cpp +++ b/apps/openmw/mwmechanics/summoning.cpp @@ -5,6 +5,8 @@ #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" +#include "../mwmechanics/spellcasting.hpp" + #include "../mwworld/esmstore.hpp" #include "../mwworld/class.hpp" #include "../mwworld/manualref.hpp" @@ -51,8 +53,7 @@ namespace MWMechanics void UpdateSummonedCreatures::visit(EffectKey key, const std::string &sourceName, const std::string &sourceId, int casterActorId, float magnitude, float remainingTime, float totalTime) { - if (key.mId >= ESM::MagicEffect::SummonScamp - && key.mId <= ESM::MagicEffect::SummonStormAtronach && magnitude > 0) + if (isSummoningEffect(key.mId) && magnitude > 0) { mActiveEffects.insert(std::make_pair(key.mId, sourceId)); } From af0e91c2d348b93d65a8db36582db27dac6de971 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 22 Jan 2015 15:21:03 +0100 Subject: [PATCH 0380/3725] ESSImport: stolen items reading fix --- apps/essimporter/converter.hpp | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index 9894de299..7565b78d4 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -364,15 +364,18 @@ public: { std::string itemid = esm.getHNString("NAME"); - while (esm.isNextSub("ONAM")) + while (esm.isNextSub("FNAM") || esm.isNextSub("ONAM")) { - std::string ownerid = esm.getHString(); - mStolenItems.insert(std::make_pair(itemid, ownerid)); - } - while (esm.isNextSub("FNAM")) - { - std::string factionid = esm.getHString(); - mFactionStolenItems.insert(std::make_pair(itemid, factionid)); + if (esm.retSubName().toString() == "FNAM") + { + std::string factionid = esm.getHString(); + mFactionStolenItems.insert(std::make_pair(itemid, factionid)); + } + else + { + std::string ownerid = esm.getHString(); + mStolenItems.insert(std::make_pair(itemid, ownerid)); + } } } private: From 8b5effe3e06eb628ac3c12f6fec39052ef26a79b Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 22 Jan 2015 17:47:00 +0100 Subject: [PATCH 0381/3725] Fix wrong magic number for JOUR in openmw savegames --- apps/openmw/mwdialogue/journalimp.cpp | 2 +- apps/openmw/mwstate/statemanagerimp.cpp | 1 + components/esm/defs.hpp | 22 ++++++++++++---------- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwdialogue/journalimp.cpp b/apps/openmw/mwdialogue/journalimp.cpp index 1d17134df..597a908e8 100644 --- a/apps/openmw/mwdialogue/journalimp.cpp +++ b/apps/openmw/mwdialogue/journalimp.cpp @@ -229,7 +229,7 @@ namespace MWDialogue void Journal::readRecord (ESM::ESMReader& reader, int32_t type) { - if (type==ESM::REC_JOUR) + if (type==ESM::REC_JOUR || type==ESM::REC_JOUR_LEGACY) { ESM::JournalEntry record; record.load (reader); diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 87b303b6f..a282f152a 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -368,6 +368,7 @@ void MWState::StateManager::loadGame (const Character *character, const std::str break; case ESM::REC_JOUR: + case ESM::REC_JOUR_LEGACY: case ESM::REC_QUES: MWBase::Environment::get().getJournal()->readRecord (reader, n.val); diff --git a/components/esm/defs.hpp b/components/esm/defs.hpp index effe9a3f1..60926d562 100644 --- a/components/esm/defs.hpp +++ b/components/esm/defs.hpp @@ -96,15 +96,17 @@ enum RecNameInts REC_WEAP = 0x50414557, // format 0 - saved games - REC_SAVE = 0x45564153, - REC_JOUR = 0x524f55a4, // TODO: this is actually "\nOUR" rather than "JOUR", fix - REC_QUES = 0x53455551, - REC_GSCR = 0x52435347, - REC_PLAY = 0x59414c50, - REC_CSTA = 0x41545343, - REC_GMAP = 0x50414d47, - REC_DIAS = 0x53414944, - REC_WTHR = 0x52485457, + REC_SAVE = FourCC<'S','A','V','E'>::value, + REC_JOUR_LEGACY = FourCC<0xa4,'U','O','R'>::value, // "\xa4UOR", rather than "JOUR", little oversight when magic numbers were + // calculated by hand, needs to be supported for older files now + REC_JOUR = FourCC<'J','O','U','R'>::value, + REC_QUES = FourCC<'Q','U','E','S'>::value, + REC_GSCR = FourCC<'G','S','C','R'>::value, + REC_PLAY = FourCC<'P','L','A','Y'>::value, + REC_CSTA = FourCC<'C','S','T','A'>::value, + REC_GMAP = FourCC<'G','M','A','P'>::value, + REC_DIAS = FourCC<'D','I','A','S'>::value, + REC_WTHR = FourCC<'W','T','H','R'>::value, REC_KEYS = FourCC<'K','E','Y','S'>::value, REC_DYNA = FourCC<'D','Y','N','A'>::value, REC_ASPL = FourCC<'A','S','P','L'>::value, @@ -117,7 +119,7 @@ enum RecNameInts REC_CAM_ = FourCC<'C','A','M','_'>::value, // format 1 - REC_FILT = 0x544C4946, + REC_FILT = FourCC<'F','I','L','T'>::value, REC_DBGP = FourCC<'D','B','G','P'>::value ///< only used in project files }; From c883a73d30adc988738c6c577f5c4ae67d8da8a0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 22 Jan 2015 19:04:59 +0100 Subject: [PATCH 0382/3725] Several warning fixes --- apps/bsatool/bsatool.cpp | 8 +++---- apps/esmtool/esmtool.cpp | 24 +++++++++---------- apps/esmtool/labels.cpp | 21 ++++++++-------- apps/esmtool/record.cpp | 22 +++++++++-------- apps/esmtool/record.hpp | 10 +++----- apps/essimporter/main.cpp | 2 +- apps/openmw/mwbase/dialoguemanager.hpp | 2 +- apps/openmw/mwbase/journal.hpp | 2 +- apps/openmw/mwbase/mechanicsmanager.hpp | 2 +- apps/openmw/mwbase/windowmanager.hpp | 2 +- apps/openmw/mwbase/world.hpp | 2 +- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 2 +- apps/openmw/mwdialogue/dialoguemanagerimp.hpp | 2 +- apps/openmw/mwdialogue/journalimp.cpp | 2 +- apps/openmw/mwdialogue/journalimp.hpp | 2 +- apps/openmw/mwgui/mapwindow.cpp | 2 +- apps/openmw/mwgui/mapwindow.hpp | 2 +- apps/openmw/mwgui/quickkeysmenu.cpp | 2 +- apps/openmw/mwgui/quickkeysmenu.hpp | 2 +- apps/openmw/mwgui/windowmanagerimp.cpp | 2 +- apps/openmw/mwgui/windowmanagerimp.hpp | 2 +- apps/openmw/mwmechanics/actors.cpp | 2 +- apps/openmw/mwmechanics/actors.hpp | 2 +- .../mwmechanics/mechanicsmanagerimp.cpp | 2 +- .../mwmechanics/mechanicsmanagerimp.hpp | 2 +- apps/openmw/mwscript/globalscripts.cpp | 2 +- apps/openmw/mwscript/globalscripts.hpp | 2 +- apps/openmw/mwworld/cells.cpp | 2 +- apps/openmw/mwworld/cells.hpp | 2 +- apps/openmw/mwworld/esmstore.cpp | 2 +- apps/openmw/mwworld/esmstore.hpp | 2 +- apps/openmw/mwworld/globals.cpp | 2 +- apps/openmw/mwworld/globals.hpp | 2 +- apps/openmw/mwworld/player.cpp | 2 +- apps/openmw/mwworld/player.hpp | 2 +- apps/openmw/mwworld/projectilemanager.cpp | 2 +- apps/openmw/mwworld/projectilemanager.hpp | 2 +- apps/openmw/mwworld/weather.cpp | 2 +- apps/openmw/mwworld/weather.hpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 2 +- apps/openmw/mwworld/worldimp.hpp | 2 +- components/esm/esmcommon.hpp | 2 +- 42 files changed, 78 insertions(+), 81 deletions(-) diff --git a/apps/bsatool/bsatool.cpp b/apps/bsatool/bsatool.cpp index 5b1f7d6bb..c0a6dcc81 100644 --- a/apps/bsatool/bsatool.cpp +++ b/apps/bsatool/bsatool.cpp @@ -27,8 +27,8 @@ struct Arguments void replaceAll(std::string& str, const std::string& needle, const std::string& substitute) { - int pos = str.find(needle); - while(pos != -1) + size_t pos = str.find(needle); + while(pos != std::string::npos) { str.replace(pos, needle.size(), substitute); pos = str.find(needle); @@ -138,8 +138,8 @@ bool parseOptions (int argc, char** argv, Arguments &info) else if (variables["input-file"].as< std::vector >().size() > 1) info.outdir = variables["input-file"].as< std::vector >()[1]; - info.longformat = variables.count("long"); - info.fullpath = variables.count("full-path"); + info.longformat = variables.count("long") != 0; + info.fullpath = variables.count("full-path") != 0; return true; } diff --git a/apps/esmtool/esmtool.cpp b/apps/esmtool/esmtool.cpp index b23ba72f9..9bbf20266 100644 --- a/apps/esmtool/esmtool.cpp +++ b/apps/esmtool/esmtool.cpp @@ -22,7 +22,7 @@ struct ESMData { std::string author; std::string description; - int version; + unsigned int version; std::vector masters; std::deque mRecords; @@ -48,9 +48,9 @@ const std::set ESMData::sLabeledRec = // Based on the legacy struct struct Arguments { - unsigned int raw_given; - unsigned int quiet_given; - unsigned int loadcells_given; + bool raw_given; + bool quiet_given; + bool loadcells_given; bool plain_given; std::string mode; @@ -177,10 +177,10 @@ bool parseOptions (int argc, char** argv, Arguments &info) if (variables["input-file"].as< std::vector >().size() > 1) info.outname = variables["input-file"].as< std::vector >()[1]; - info.raw_given = variables.count ("raw"); - info.quiet_given = variables.count ("quiet"); - info.loadcells_given = variables.count ("loadcells"); - info.plain_given = (variables.count("plain") > 0); + info.raw_given = variables.count ("raw") != 0; + info.quiet_given = variables.count ("quiet") != 0; + info.loadcells_given = variables.count ("loadcells") != 0; + info.plain_given = variables.count("plain") != 0; // Font encoding settings info.encoding = variables["encoding"].as(); @@ -430,7 +430,7 @@ int clone(Arguments& info) return 1; } - int recordCount = info.data.mRecords.size(); + size_t recordCount = info.data.mRecords.size(); int digitCount = 1; // For a nicer output if (recordCount > 9) ++digitCount; @@ -501,9 +501,9 @@ int clone(Arguments& info) if (!info.data.mCellRefs[ptr].empty()) { typedef std::deque RefList; RefList &refs = info.data.mCellRefs[ptr]; - for (RefList::iterator it = refs.begin(); it != refs.end(); ++it) + for (RefList::iterator refIt = refs.begin(); refIt != refs.end(); ++refIt) { - it->save(esm); + refIt->save(esm); } } } @@ -511,7 +511,7 @@ int clone(Arguments& info) esm.endRecord(name.toString()); saved++; - int perc = (saved / (float)recordCount)*100; + int perc = (int)((saved / (float)recordCount)*100); if (perc % 10 == 0) { std::cerr << "\r" << perc << "%"; diff --git a/apps/esmtool/labels.cpp b/apps/esmtool/labels.cpp index 9543628f5..88e188df0 100644 --- a/apps/esmtool/labels.cpp +++ b/apps/esmtool/labels.cpp @@ -13,14 +13,13 @@ #include #include -#include #include std::string bodyPartLabel(int idx) { if (idx >= 0 && idx <= 26) { - const char *bodyPartLabels[] = { + static const char *bodyPartLabels[] = { "Head", "Hair", "Neck", @@ -59,7 +58,7 @@ std::string meshPartLabel(int idx) { if (idx >= 0 && idx <= ESM::BodyPart::MP_Tail) { - const char *meshPartLabels[] = { + static const char *meshPartLabels[] = { "Head", "Hair", "Neck", @@ -86,7 +85,7 @@ std::string meshTypeLabel(int idx) { if (idx >= 0 && idx <= ESM::BodyPart::MT_Armor) { - const char *meshTypeLabels[] = { + static const char *meshTypeLabels[] = { "Skin", "Clothing", "Armor" @@ -101,7 +100,7 @@ std::string clothingTypeLabel(int idx) { if (idx >= 0 && idx <= 9) { - const char *clothingTypeLabels[] = { + static const char *clothingTypeLabels[] = { "Pants", "Shoes", "Shirt", @@ -123,7 +122,7 @@ std::string armorTypeLabel(int idx) { if (idx >= 0 && idx <= 10) { - const char *armorTypeLabels[] = { + static const char *armorTypeLabels[] = { "Helmet", "Cuirass", "Left Pauldron", @@ -146,7 +145,7 @@ std::string dialogTypeLabel(int idx) { if (idx >= 0 && idx <= 4) { - const char *dialogTypeLabels[] = { + static const char *dialogTypeLabels[] = { "Topic", "Voice", "Greeting", @@ -165,7 +164,7 @@ std::string questStatusLabel(int idx) { if (idx >= 0 && idx <= 4) { - const char *questStatusLabels[] = { + static const char *questStatusLabels[] = { "None", "Name", "Finished", @@ -182,7 +181,7 @@ std::string creatureTypeLabel(int idx) { if (idx >= 0 && idx <= 3) { - const char *creatureTypeLabels[] = { + static const char *creatureTypeLabels[] = { "Creature", "Daedra", "Undead", @@ -198,7 +197,7 @@ std::string soundTypeLabel(int idx) { if (idx >= 0 && idx <= 7) { - const char *soundTypeLabels[] = { + static const char *soundTypeLabels[] = { "Left Foot", "Right Foot", "Swim Left", @@ -218,7 +217,7 @@ std::string weaponTypeLabel(int idx) { if (idx >= 0 && idx <= 13) { - const char *weaponTypeLabels[] = { + static const char *weaponTypeLabels[] = { "Short Blade One Hand", "Long Blade One Hand", "Long Blade Two Hand", diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index 3f2ebc2ba..2f07a5f08 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -25,7 +25,7 @@ void printAIPackage(ESM::AIPackage p) { std::cout << " Travel Coordinates: (" << p.mTravel.mX << "," << p.mTravel.mY << "," << p.mTravel.mZ << ")" << std::endl; - std::cout << " Travel Unknown: " << (int)p.mTravel.mUnk << std::endl; + std::cout << " Travel Unknown: " << p.mTravel.mUnk << std::endl; } else if (p.mType == ESM::AI_Follow || p.mType == ESM::AI_Escort) { @@ -33,12 +33,12 @@ void printAIPackage(ESM::AIPackage p) << p.mTarget.mY << "," << p.mTarget.mZ << ")" << std::endl; std::cout << " Duration: " << p.mTarget.mDuration << std::endl; std::cout << " Target ID: " << p.mTarget.mId.toString() << std::endl; - std::cout << " Unknown: " << (int)p.mTarget.mUnk << std::endl; + std::cout << " Unknown: " << p.mTarget.mUnk << std::endl; } else if (p.mType == ESM::AI_Activate) { std::cout << " Name: " << p.mActivate.mName.toString() << std::endl; - std::cout << " Activate Unknown: " << (int)p.mActivate.mUnk << std::endl; + std::cout << " Activate Unknown: " << p.mActivate.mUnk << std::endl; } else { std::cout << " BadPackage: " << boost::format("0x%08x") % p.mType << std::endl; @@ -89,6 +89,7 @@ std::string ruleString(ESM::DialInfo::SelectStruct ss) case 'A': if (indicator == 'R') type_str = "Not Race"; break; case 'B': if (indicator == 'L') type_str = "Not Cell"; break; case 'C': if (indicator == 's') type_str = "Not Local"; break; + default: break; } // Append the variable name to the function string if any. @@ -110,6 +111,7 @@ std::string ruleString(ESM::DialInfo::SelectStruct ss) case '3': oper_str = ">="; break; case '4': oper_str = "< "; break; case '5': oper_str = "<="; break; + default: break; } std::ostringstream stream; @@ -430,7 +432,7 @@ void Record::print() std::cout << " Icon: " << mData.mIcon << std::endl; std::cout << " Script: " << mData.mScript << std::endl; std::cout << " Type: " << apparatusTypeLabel(mData.mData.mType) - << " (" << (int)mData.mData.mType << ")" << std::endl; + << " (" << mData.mData.mType << ")" << std::endl; std::cout << " Weight: " << mData.mData.mWeight << std::endl; std::cout << " Value: " << mData.mData.mValue << std::endl; std::cout << " Quality: " << mData.mData.mQuality << std::endl; @@ -816,7 +818,7 @@ void Record::print() // Seems like this should done with reference counting in the // loader to me. But I'm not really knowledgable about this // record type yet. --Cory - bool wasLoaded = mData.mDataLoaded; + bool wasLoaded = (mData.mDataLoaded != 0); if (mData.mDataTypes) mData.loadData(mData.mDataTypes); if (mData.mDataLoaded) { @@ -999,7 +1001,7 @@ void Record::print() << (unsigned int)((unsigned char)mData.mNpdt12.mUnknown2) << std::endl; std::cout << " Unknown3: " << (unsigned int)((unsigned char)mData.mNpdt12.mUnknown3) << std::endl; - std::cout << " Gold: " << (int)mData.mNpdt12.mGold << std::endl; + std::cout << " Gold: " << mData.mNpdt12.mGold << std::endl; } else { std::cout << " Level: " << mData.mNpdt52.mLevel << std::endl; @@ -1021,7 +1023,7 @@ void Record::print() std::cout << " Skills:" << std::endl; for (int i = 0; i != ESM::Skill::Length; i++) std::cout << " " << skillLabel(i) << ": " - << (int)((unsigned char)mData.mNpdt52.mSkills[i]) << std::endl; + << (int)(mData.mNpdt52.mSkills[i]) << std::endl; std::cout << " Health: " << mData.mNpdt52.mHealth << std::endl; std::cout << " Magicka: " << mData.mNpdt52.mMana << std::endl; @@ -1123,9 +1125,9 @@ void Record::print() std::cout << (male ? " Male:" : " Female:") << std::endl; - for (int i=0; i<8; ++i) - std::cout << " " << sAttributeNames[i] << ": " - << mData.mData.mAttributeValues[i].getValue (male) << std::endl; + for (int j=0; j<8; ++j) + std::cout << " " << sAttributeNames[j] << ": " + << mData.mData.mAttributeValues[j].getValue (male) << std::endl; std::cout << " Height: " << mData.mData.mHeight.getValue (male) << std::endl; std::cout << " Weight: " << mData.mData.mWeight.getValue (male) << std::endl; diff --git a/apps/esmtool/record.hpp b/apps/esmtool/record.hpp index 45b6d0426..c1b90ac2b 100644 --- a/apps/esmtool/record.hpp +++ b/apps/esmtool/record.hpp @@ -19,7 +19,7 @@ namespace EsmTool { protected: std::string mId; - int mFlags; + uint32_t mFlags; ESM::NAME mType; bool mPrintPlain; @@ -40,11 +40,11 @@ namespace EsmTool mId = id; } - int getFlags() const { + uint32_t getFlags() const { return mFlags; } - void setFlags(int flags) { + void setFlags(uint32_t flags) { mFlags = flags; } @@ -52,10 +52,6 @@ namespace EsmTool return mType; } - bool getPrintPlain() const { - return mPrintPlain; - } - void setPrintPlain(bool plain) { mPrintPlain = plain; } diff --git a/apps/essimporter/main.cpp b/apps/essimporter/main.cpp index 1c7d51116..5a9e0c77d 100644 --- a/apps/essimporter/main.cpp +++ b/apps/essimporter/main.cpp @@ -12,7 +12,7 @@ namespace bfs = boost::filesystem; -int main(int argc, const char** argv) +int main(int argc, char** argv) { try { diff --git a/apps/openmw/mwbase/dialoguemanager.hpp b/apps/openmw/mwbase/dialoguemanager.hpp index d35b5950f..1fe63e633 100644 --- a/apps/openmw/mwbase/dialoguemanager.hpp +++ b/apps/openmw/mwbase/dialoguemanager.hpp @@ -69,7 +69,7 @@ namespace MWBase virtual void write (ESM::ESMWriter& writer, Loading::Listener& progress) const = 0; - virtual void readRecord (ESM::ESMReader& reader, int32_t type) = 0; + virtual void readRecord (ESM::ESMReader& reader, uint32_t type) = 0; /// Changes faction1's opinion of faction2 by \a diff. virtual void modFactionReaction (const std::string& faction1, const std::string& faction2, int diff) = 0; diff --git a/apps/openmw/mwbase/journal.hpp b/apps/openmw/mwbase/journal.hpp index 938cec74b..738014ba6 100644 --- a/apps/openmw/mwbase/journal.hpp +++ b/apps/openmw/mwbase/journal.hpp @@ -92,7 +92,7 @@ namespace MWBase virtual void write (ESM::ESMWriter& writer, Loading::Listener& progress) const = 0; - virtual void readRecord (ESM::ESMReader& reader, int32_t type) = 0; + virtual void readRecord (ESM::ESMReader& reader, uint32_t type) = 0; }; } diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index a51e3a301..33a2ef1ea 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -193,7 +193,7 @@ namespace MWBase virtual void write (ESM::ESMWriter& writer, Loading::Listener& listener) const = 0; - virtual void readRecord (ESM::ESMReader& reader, int32_t type) = 0; + virtual void readRecord (ESM::ESMReader& reader, uint32_t type) = 0; virtual void clear() = 0; diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 3e957ef14..02cbc69e9 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -310,7 +310,7 @@ namespace MWBase virtual void clear() = 0; virtual void write (ESM::ESMWriter& writer, Loading::Listener& progress) = 0; - virtual void readRecord (ESM::ESMReader& reader, int32_t type) = 0; + virtual void readRecord (ESM::ESMReader& reader, uint32_t type) = 0; virtual int countSavedGameRecords() const = 0; /// Does the current stack of GUI-windows permit saving? diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index db0f0a763..f58ef0809 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -108,7 +108,7 @@ namespace MWBase virtual void write (ESM::ESMWriter& writer, Loading::Listener& listener) const = 0; - virtual void readRecord (ESM::ESMReader& reader, int32_t type, + virtual void readRecord (ESM::ESMReader& reader, uint32_t type, const std::map& contentFileMap) = 0; virtual MWWorld::CellStore *getExterior (int x, int y) = 0; diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 0ee7dfe94..d2534cd82 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -647,7 +647,7 @@ namespace MWDialogue writer.endRecord (ESM::REC_DIAS); } - void DialogueManager::readRecord (ESM::ESMReader& reader, int32_t type) + void DialogueManager::readRecord (ESM::ESMReader& reader, uint32_t type) { if (type==ESM::REC_DIAS) { diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp index c06299736..77035bc60 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp @@ -92,7 +92,7 @@ namespace MWDialogue virtual void write (ESM::ESMWriter& writer, Loading::Listener& progress) const; - virtual void readRecord (ESM::ESMReader& reader, int32_t type); + virtual void readRecord (ESM::ESMReader& reader, uint32_t type); /// Changes faction1's opinion of faction2 by \a diff. virtual void modFactionReaction (const std::string& faction1, const std::string& faction2, int diff); diff --git a/apps/openmw/mwdialogue/journalimp.cpp b/apps/openmw/mwdialogue/journalimp.cpp index 597a908e8..3b57912da 100644 --- a/apps/openmw/mwdialogue/journalimp.cpp +++ b/apps/openmw/mwdialogue/journalimp.cpp @@ -227,7 +227,7 @@ namespace MWDialogue } } - void Journal::readRecord (ESM::ESMReader& reader, int32_t type) + void Journal::readRecord (ESM::ESMReader& reader, uint32_t type) { if (type==ESM::REC_JOUR || type==ESM::REC_JOUR_LEGACY) { diff --git a/apps/openmw/mwdialogue/journalimp.hpp b/apps/openmw/mwdialogue/journalimp.hpp index d15b909fa..7f26a5bb9 100644 --- a/apps/openmw/mwdialogue/journalimp.hpp +++ b/apps/openmw/mwdialogue/journalimp.hpp @@ -71,7 +71,7 @@ namespace MWDialogue virtual void write (ESM::ESMWriter& writer, Loading::Listener& progress) const; - virtual void readRecord (ESM::ESMReader& reader, int32_t type); + virtual void readRecord (ESM::ESMReader& reader, uint32_t type); }; } diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index abd1256d7..00d60f23b 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -886,7 +886,7 @@ namespace MWGui writer.endRecord(ESM::REC_GMAP); } - void MapWindow::readRecord(ESM::ESMReader &reader, int32_t type) + void MapWindow::readRecord(ESM::ESMReader &reader, uint32_t type) { if (type == ESM::REC_GMAP) { diff --git a/apps/openmw/mwgui/mapwindow.hpp b/apps/openmw/mwgui/mapwindow.hpp index 684069467..7b6c1f205 100644 --- a/apps/openmw/mwgui/mapwindow.hpp +++ b/apps/openmw/mwgui/mapwindow.hpp @@ -177,7 +177,7 @@ namespace MWGui void clear(); void write (ESM::ESMWriter& writer, Loading::Listener& progress); - void readRecord (ESM::ESMReader& reader, int32_t type); + void readRecord (ESM::ESMReader& reader, uint32_t type); private: void onDragStart(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id); diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index deba64434..a102de1e5 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -431,7 +431,7 @@ namespace MWGui writer.endRecord(ESM::REC_KEYS); } - void QuickKeysMenu::readRecord(ESM::ESMReader &reader, int32_t type) + void QuickKeysMenu::readRecord(ESM::ESMReader &reader, uint32_t type) { if (type != ESM::REC_KEYS) return; diff --git a/apps/openmw/mwgui/quickkeysmenu.hpp b/apps/openmw/mwgui/quickkeysmenu.hpp index 30e672891..00afa4561 100644 --- a/apps/openmw/mwgui/quickkeysmenu.hpp +++ b/apps/openmw/mwgui/quickkeysmenu.hpp @@ -47,7 +47,7 @@ namespace MWGui void write (ESM::ESMWriter& writer); - void readRecord (ESM::ESMReader& reader, int32_t type); + void readRecord (ESM::ESMReader& reader, uint32_t type); void clear(); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 5b2bbee90..e976b984f 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1620,7 +1620,7 @@ namespace MWGui } } - void WindowManager::readRecord(ESM::ESMReader &reader, int32_t type) + void WindowManager::readRecord(ESM::ESMReader &reader, uint32_t type) { if (type == ESM::REC_GMAP) mMap->readRecord(reader, type); diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 44d5819c2..a08c59a2f 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -306,7 +306,7 @@ namespace MWGui virtual void clear(); virtual void write (ESM::ESMWriter& writer, Loading::Listener& progress); - virtual void readRecord (ESM::ESMReader& reader, int32_t type); + virtual void readRecord (ESM::ESMReader& reader, uint32_t type); virtual int countSavedGameRecords() const; /// Does the current stack of GUI-windows permit saving? diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 64434a304..f8068e800 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1468,7 +1468,7 @@ namespace MWMechanics writer.endRecord(ESM::REC_DCOU); } - void Actors::readRecord (ESM::ESMReader& reader, int32_t type) + void Actors::readRecord (ESM::ESMReader& reader, uint32_t type) { if (type == ESM::REC_DCOU) { diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index 39fe38208..39598b2a2 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -128,7 +128,7 @@ namespace MWMechanics void write (ESM::ESMWriter& writer, Loading::Listener& listener) const; - void readRecord (ESM::ESMReader& reader, int32_t type); + void readRecord (ESM::ESMReader& reader, uint32_t type); void clear(); // Clear death counter diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 3d757bde6..0a2c3cfff 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1360,7 +1360,7 @@ namespace MWMechanics mActors.write(writer, listener); } - void MechanicsManager::readRecord(ESM::ESMReader &reader, int32_t type) + void MechanicsManager::readRecord(ESM::ESMReader &reader, uint32_t type) { mActors.readRecord(reader, type); } diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index fc9c58974..2f443ad59 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -158,7 +158,7 @@ namespace MWMechanics virtual void write (ESM::ESMWriter& writer, Loading::Listener& listener) const; - virtual void readRecord (ESM::ESMReader& reader, int32_t type); + virtual void readRecord (ESM::ESMReader& reader, uint32_t type); virtual void clear(); diff --git a/apps/openmw/mwscript/globalscripts.cpp b/apps/openmw/mwscript/globalscripts.cpp index c7371100f..6c4bb3be5 100644 --- a/apps/openmw/mwscript/globalscripts.cpp +++ b/apps/openmw/mwscript/globalscripts.cpp @@ -145,7 +145,7 @@ namespace MWScript } } - bool GlobalScripts::readRecord (ESM::ESMReader& reader, int32_t type) + bool GlobalScripts::readRecord (ESM::ESMReader& reader, uint32_t type) { if (type==ESM::REC_GSCR) { diff --git a/apps/openmw/mwscript/globalscripts.hpp b/apps/openmw/mwscript/globalscripts.hpp index 55c2e9321..9f009db98 100644 --- a/apps/openmw/mwscript/globalscripts.hpp +++ b/apps/openmw/mwscript/globalscripts.hpp @@ -62,7 +62,7 @@ namespace MWScript void write (ESM::ESMWriter& writer, Loading::Listener& progress) const; - bool readRecord (ESM::ESMReader& reader, int32_t type); + bool readRecord (ESM::ESMReader& reader, uint32_t type); ///< Records for variables that do not exist are dropped silently. /// /// \return Known type? diff --git a/apps/openmw/mwworld/cells.cpp b/apps/openmw/mwworld/cells.cpp index 3a8b7d5c4..fd5ec20dc 100644 --- a/apps/openmw/mwworld/cells.cpp +++ b/apps/openmw/mwworld/cells.cpp @@ -299,7 +299,7 @@ void MWWorld::Cells::write (ESM::ESMWriter& writer, Loading::Listener& progress) } } -bool MWWorld::Cells::readRecord (ESM::ESMReader& reader, int32_t type, +bool MWWorld::Cells::readRecord (ESM::ESMReader& reader, uint32_t type, const std::map& contentFileMap) { if (type==ESM::REC_CSTA) diff --git a/apps/openmw/mwworld/cells.hpp b/apps/openmw/mwworld/cells.hpp index a9c17fa93..0b7d9444f 100644 --- a/apps/openmw/mwworld/cells.hpp +++ b/apps/openmw/mwworld/cells.hpp @@ -76,7 +76,7 @@ namespace MWWorld void write (ESM::ESMWriter& writer, Loading::Listener& progress) const; - bool readRecord (ESM::ESMReader& reader, int32_t type, + bool readRecord (ESM::ESMReader& reader, uint32_t type, const std::map& contentFileMap); }; } diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index b096f4b90..caa88d751 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -175,7 +175,7 @@ void ESMStore::setUp() mCreatureLists.write (writer, progress); } - bool ESMStore::readRecord (ESM::ESMReader& reader, int32_t type) + bool ESMStore::readRecord (ESM::ESMReader& reader, uint32_t type) { switch (type) { diff --git a/apps/openmw/mwworld/esmstore.hpp b/apps/openmw/mwworld/esmstore.hpp index 01770e6b3..05b633956 100644 --- a/apps/openmw/mwworld/esmstore.hpp +++ b/apps/openmw/mwworld/esmstore.hpp @@ -233,7 +233,7 @@ namespace MWWorld void write (ESM::ESMWriter& writer, Loading::Listener& progress) const; - bool readRecord (ESM::ESMReader& reader, int32_t type); + bool readRecord (ESM::ESMReader& reader, uint32_t type); ///< \return Known type? }; diff --git a/apps/openmw/mwworld/globals.cpp b/apps/openmw/mwworld/globals.cpp index 302a05824..e7cb04590 100644 --- a/apps/openmw/mwworld/globals.cpp +++ b/apps/openmw/mwworld/globals.cpp @@ -88,7 +88,7 @@ namespace MWWorld } } - bool Globals::readRecord (ESM::ESMReader& reader, int32_t type) + bool Globals::readRecord (ESM::ESMReader& reader, uint32_t type) { if (type==ESM::REC_GLOB) { diff --git a/apps/openmw/mwworld/globals.hpp b/apps/openmw/mwworld/globals.hpp index 3ff4a5d6e..bb4ab13d9 100644 --- a/apps/openmw/mwworld/globals.hpp +++ b/apps/openmw/mwworld/globals.hpp @@ -53,7 +53,7 @@ namespace MWWorld void write (ESM::ESMWriter& writer, Loading::Listener& progress) const; - bool readRecord (ESM::ESMReader& reader, int32_t type); + bool readRecord (ESM::ESMReader& reader, uint32_t type); ///< Records for variables that do not exist are dropped silently. /// /// \return Known type? diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index a57934bd3..c1e176b91 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -227,7 +227,7 @@ namespace MWWorld writer.endRecord (ESM::REC_PLAY); } - bool Player::readRecord (ESM::ESMReader& reader, int32_t type) + bool Player::readRecord (ESM::ESMReader& reader, uint32_t type) { if (type==ESM::REC_PLAY) { diff --git a/apps/openmw/mwworld/player.hpp b/apps/openmw/mwworld/player.hpp index d8cde5952..25d8981cd 100644 --- a/apps/openmw/mwworld/player.hpp +++ b/apps/openmw/mwworld/player.hpp @@ -102,7 +102,7 @@ namespace MWWorld void write (ESM::ESMWriter& writer, Loading::Listener& progress) const; - bool readRecord (ESM::ESMReader& reader, int32_t type); + bool readRecord (ESM::ESMReader& reader, uint32_t type); int getNewCrimeId(); // get new id for witnesses void recordCrimeId(); // record the paid crime id when bounty is 0 diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index e4b2d5a1e..41fbfea9f 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -343,7 +343,7 @@ namespace MWWorld } } - bool ProjectileManager::readRecord(ESM::ESMReader &reader, int32_t type) + bool ProjectileManager::readRecord(ESM::ESMReader &reader, uint32_t type) { if (type == ESM::REC_PROJ) { diff --git a/apps/openmw/mwworld/projectilemanager.hpp b/apps/openmw/mwworld/projectilemanager.hpp index 6e84b9efb..93f54c008 100644 --- a/apps/openmw/mwworld/projectilemanager.hpp +++ b/apps/openmw/mwworld/projectilemanager.hpp @@ -53,7 +53,7 @@ namespace MWWorld void clear(); void write (ESM::ESMWriter& writer, Loading::Listener& progress) const; - bool readRecord (ESM::ESMReader& reader, int32_t type); + bool readRecord (ESM::ESMReader& reader, uint32_t type); int countSavedGameRecords() const; private: diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index cd05cb798..6532c5969 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -762,7 +762,7 @@ void WeatherManager::write(ESM::ESMWriter& writer, Loading::Listener& progress) writer.endRecord(ESM::REC_WTHR); } -bool WeatherManager::readRecord(ESM::ESMReader& reader, int32_t type) +bool WeatherManager::readRecord(ESM::ESMReader& reader, uint32_t type) { if(ESM::REC_WTHR == type) { diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index dee9fc52a..830b5c376 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -199,7 +199,7 @@ namespace MWWorld void write(ESM::ESMWriter& writer, Loading::Listener& progress); - bool readRecord(ESM::ESMReader& reader, int32_t type); + bool readRecord(ESM::ESMReader& reader, uint32_t type); private: float mHour; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index f7d5d9616..ceac85bca 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -345,7 +345,7 @@ namespace MWWorld writer.endRecord(ESM::REC_CAM_); } - void World::readRecord (ESM::ESMReader& reader, int32_t type, + void World::readRecord (ESM::ESMReader& reader, uint32_t type, const std::map& contentFileMap) { switch (type) diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index f050c498d..9834015ac 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -170,7 +170,7 @@ namespace MWWorld virtual void write (ESM::ESMWriter& writer, Loading::Listener& progress) const; - virtual void readRecord (ESM::ESMReader& reader, int32_t type, + virtual void readRecord (ESM::ESMReader& reader, uint32_t type, const std::map& contentFileMap); virtual CellStore *getExterior (int x, int y); diff --git a/components/esm/esmcommon.hpp b/components/esm/esmcommon.hpp index d3e6e7fea..1bdadead2 100644 --- a/components/esm/esmcommon.hpp +++ b/components/esm/esmcommon.hpp @@ -23,7 +23,7 @@ template union NAME_T { char name[LEN]; - int32_t val; + uint32_t val; bool operator==(const char *str) const { From a619cff615f011beb2ed89fc2d1900671f3107d3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 22 Jan 2015 21:39:07 +0100 Subject: [PATCH 0383/3725] Implement EnableLevelupMenu to trigger level-up --- apps/openmw/mwscript/docs/vmformat.txt | 3 ++- apps/openmw/mwscript/guiextensions.cpp | 2 ++ components/compiler/extensions0.cpp | 2 +- components/compiler/opcodes.hpp | 1 + 4 files changed, 6 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index b139d6138..41cc6b88a 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -443,5 +443,6 @@ op 0x20002fc: RemoveFromLevCreature op 0x20002fd: AddToLevItem op 0x20002fe: RemoveFromLevItem op 0x20002ff: SetFactionReaction +op 0x2000300: EnableLevelupMenu -opcodes 0x2000300-0x3ffffff unused +opcodes 0x2000301-0x3ffffff unused diff --git a/apps/openmw/mwscript/guiextensions.cpp b/apps/openmw/mwscript/guiextensions.cpp index 1d34adbca..f5549a172 100644 --- a/apps/openmw/mwscript/guiextensions.cpp +++ b/apps/openmw/mwscript/guiextensions.cpp @@ -231,6 +231,8 @@ namespace MWScript new OpShowDialogue (MWGui::GM_Race)); interpreter.installSegment5 (Compiler::Gui::opcodeEnableStatsReviewMenu, new OpShowDialogue (MWGui::GM_Review)); + interpreter.installSegment5 (Compiler::Gui::opcodeEnableLevelupMenu, + new OpShowDialogue (MWGui::GM_Levelup)); interpreter.installSegment5 (Compiler::Gui::opcodeEnableInventoryMenu, new OpEnableWindow (MWGui::GW_Inventory)); diff --git a/components/compiler/extensions0.cpp b/components/compiler/extensions0.cpp index a5cc0da62..70338669e 100644 --- a/components/compiler/extensions0.cpp +++ b/components/compiler/extensions0.cpp @@ -215,7 +215,7 @@ namespace Compiler extensions.registerInstruction ("enablestatsmenu", "", opcodeEnableStatsMenu); extensions.registerInstruction ("enablerest", "", opcodeEnableRest); - extensions.registerInstruction ("enablelevelupmenu", "", opcodeEnableRest); + extensions.registerInstruction ("enablelevelupmenu", "", opcodeEnableLevelupMenu); extensions.registerInstruction ("showrestmenu", "", opcodeShowRestMenu, opcodeShowRestMenuExplicit); diff --git a/components/compiler/opcodes.hpp b/components/compiler/opcodes.hpp index 04666e976..e5cf2e965 100644 --- a/components/compiler/opcodes.hpp +++ b/components/compiler/opcodes.hpp @@ -185,6 +185,7 @@ namespace Compiler const int opcodeEnableMapMenu = 0x2000015; const int opcodeEnableStatsMenu = 0x2000016; const int opcodeEnableRest = 0x2000017; + const int opcodeEnableLevelupMenu = 0x2000300; const int opcodeShowRestMenu = 0x2000018; const int opcodeShowRestMenuExplicit = 0x2000234; const int opcodeGetButtonPressed = 0x2000137; From ba7cd04ff7ac7546ef71ebd999e97dd4ef36028f Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 22 Jan 2015 23:28:31 +0100 Subject: [PATCH 0384/3725] ESSImport: prevent accidental overwriting of file --- apps/essimporter/main.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/apps/essimporter/main.cpp b/apps/essimporter/main.cpp index 5a9e0c77d..d467e053e 100644 --- a/apps/essimporter/main.cpp +++ b/apps/essimporter/main.cpp @@ -50,7 +50,15 @@ int main(int argc, char** argv) if (vm.count("compare")) importer.compare(); else + { + const std::string& ext = ".omwsave"; + if (boost::filesystem::exists(boost::filesystem::path(outputFile)) + && (outputFile.size() < ext.size() || outputFile.substr(outputFile.size()-ext.size()) != ext)) + { + throw std::runtime_error("Output file already exists and does not end in .omwsave. Did you mean to use --compare?"); + } importer.run(); + } } catch (std::exception& e) { From 1d29180e003f00406b5dafef6364534ef84dac07 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 22 Jan 2015 23:28:43 +0100 Subject: [PATCH 0385/3725] ESSImport: handle deleted cell references --- apps/essimporter/importcellref.cpp | 6 ++---- apps/essimporter/importer.cpp | 1 + 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/apps/essimporter/importcellref.cpp b/apps/essimporter/importcellref.cpp index 1894b0023..906b2ed24 100644 --- a/apps/essimporter/importcellref.cpp +++ b/apps/essimporter/importcellref.cpp @@ -41,11 +41,9 @@ namespace ESSImport mDeleted = 0; if (esm.isNextSub("DELE")) { - int deleted; + unsigned int deleted; esm.getHT(deleted); - // Neither of this seems to work right... - //mDeleted = (deleted != 0); - //mDeleted = (deleted&0x1); + mDeleted = (deleted >> 24) & 0x2; // the other 3 bytes seem to be uninitialized garbage } if (esm.isNextSub("MVRF")) diff --git a/apps/essimporter/importer.cpp b/apps/essimporter/importer.cpp index a29d26e2a..9fd2903d8 100644 --- a/apps/essimporter/importer.cpp +++ b/apps/essimporter/importer.cpp @@ -105,6 +105,7 @@ namespace ESSImport blacklist.insert(std::make_pair("REFR", "DATA")); // player position blacklist.insert(std::make_pair("CELL", "NAM8")); // fog of war blacklist.insert(std::make_pair("GAME", "GMDT")); // weather data, current time always changes + blacklist.insert(std::make_pair("CELL", "DELE")); // first 3 bytes are uninitialized // this changes way too often, name suggests some renderer internal data? blacklist.insert(std::make_pair("CELL", "ND3D")); From c354f48a07080a08e713d4114ede4c13ca869996 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 22 Jan 2015 23:42:43 +0100 Subject: [PATCH 0386/3725] ESSImport: some fixes --- apps/essimporter/importcrec.cpp | 9 ++------- apps/essimporter/importdial.cpp | 12 +++++++++++- apps/essimporter/importnpcc.cpp | 9 ++------- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/apps/essimporter/importcrec.cpp b/apps/essimporter/importcrec.cpp index 28e5ac56f..7a8a3eb00 100644 --- a/apps/essimporter/importcrec.cpp +++ b/apps/essimporter/importcrec.cpp @@ -15,13 +15,8 @@ namespace ESSImport esm.getHNOT(scale, "XSCL"); // FIXME: use AiPackageList, need to fix getSubName() - if (esm.isNextSub("AI_W")) - esm.skipHSub(); - if (esm.isNextSub("AI_E")) - esm.skipHSub(); - if (esm.isNextSub("AI_T")) - esm.skipHSub(); - if (esm.isNextSub("AI_F")) + while (esm.isNextSub("AI_W") || esm.isNextSub("AI_E") || esm.isNextSub("AI_T") || esm.isNextSub("AI_F") + || esm.isNextSub("AI_A")) esm.skipHSub(); mInventory.load(esm); diff --git a/apps/essimporter/importdial.cpp b/apps/essimporter/importdial.cpp index 228d00a5a..5797a708a 100644 --- a/apps/essimporter/importdial.cpp +++ b/apps/essimporter/importdial.cpp @@ -7,7 +7,17 @@ namespace ESSImport void DIAL::load(ESM::ESMReader &esm) { - esm.getHNT(mIndex, "XIDX"); + // See ESM::Dialogue::Type enum, not sure why we would need this here though + int type = 0; + esm.getHNOT(type, "DATA"); + + // Deleted dialogue in a savefile. No clue what this means... + int deleted = 0; + esm.getHNOT(deleted, "DELE"); + + mIndex = 0; + // *should* always occur except when the dialogue is deleted, but leaving it optional just in case... + esm.getHNOT(mIndex, "XIDX"); } } diff --git a/apps/essimporter/importnpcc.cpp b/apps/essimporter/importnpcc.cpp index 7b8dda371..547b01441 100644 --- a/apps/essimporter/importnpcc.cpp +++ b/apps/essimporter/importnpcc.cpp @@ -10,13 +10,8 @@ namespace ESSImport esm.getHNT(mNPDT, "NPDT"); // FIXME: use AiPackageList, need to fix getSubName() - if (esm.isNextSub("AI_W")) - esm.skipHSub(); - if (esm.isNextSub("AI_E")) - esm.skipHSub(); - if (esm.isNextSub("AI_T")) - esm.skipHSub(); - if (esm.isNextSub("AI_F")) + while (esm.isNextSub("AI_W") || esm.isNextSub("AI_E") || esm.isNextSub("AI_T") || esm.isNextSub("AI_F") + || esm.isNextSub("AI_A")) esm.skipHSub(); mInventory.load(esm); From e484a91708683c5f6f0d26ea4c46ad73fce2bdd3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 23 Jan 2015 00:15:57 +0100 Subject: [PATCH 0387/3725] ESSImport: convert global map markers --- apps/essimporter/converter.cpp | 10 ++++++++++ apps/essimporter/importer.cpp | 4 ++-- apps/essimporter/importercontext.hpp | 8 ++++++++ 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/apps/essimporter/converter.cpp b/apps/essimporter/converter.cpp index 81521a028..75c2911fd 100644 --- a/apps/essimporter/converter.cpp +++ b/apps/essimporter/converter.cpp @@ -76,6 +76,12 @@ namespace ESSImport cell.mName = id; cell.load(esm, false); + // I wonder what 0x40 does? + if (cell.isExterior() && cell.mData.mFlags & 0x20) + { + mContext->mGlobalMapState.mMarkers.insert(std::make_pair(cell.mData.mX, cell.mData.mY)); + } + // note if the player is in a nameless exterior cell, we will assign the cellId later based on player position if (id == mContext->mPlayerCellName) { @@ -304,6 +310,10 @@ namespace ESSImport it->save(esm); esm.endRecord(ESM::REC_MARK); } + + esm.startRecord(ESM::REC_GMAP); + mContext->mGlobalMapState.save(esm); + esm.endRecord(ESM::REC_GMAP); } } diff --git a/apps/essimporter/importer.cpp b/apps/essimporter/importer.cpp index 9fd2903d8..ed149b023 100644 --- a/apps/essimporter/importer.cpp +++ b/apps/essimporter/importer.cpp @@ -123,7 +123,7 @@ namespace ESSImport if (i >= file2.mRecords.size()) { - std::cout << "Record in file1 not present in file2: (1) 0x" << std::hex << rec.mFileOffset; + std::cout << "Record in file1 not present in file2: (1) 0x" << std::hex << rec.mFileOffset << std::endl; return; } @@ -142,7 +142,7 @@ namespace ESSImport if (j >= rec2.mSubrecords.size()) { - std::cout << "Subrecord in file1 not present in file2: (1) 0x" << std::hex << sub.mFileOffset; + std::cout << "Subrecord in file1 not present in file2: (1) 0x" << std::hex << sub.mFileOffset << std::endl; return; } diff --git a/apps/essimporter/importercontext.hpp b/apps/essimporter/importercontext.hpp index 02585799a..211195d3f 100644 --- a/apps/essimporter/importercontext.hpp +++ b/apps/essimporter/importercontext.hpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "importnpcc.hpp" #include "importcrec.hpp" @@ -28,6 +29,8 @@ namespace ESSImport ESM::DialogueState mDialogueState; + ESM::GlobalMap mGlobalMapState; + int mDay, mMonth, mYear; float mHour; @@ -48,6 +51,11 @@ namespace ESSImport mPlayer.mCurrentCrimeId = 0; // TODO mPlayer.mObject.blank(); mPlayer.mObject.mRef.mRefID = "player"; // REFR.mRefID would be PlayerSaveGame + + mGlobalMapState.mBounds.mMinX = 0; + mGlobalMapState.mBounds.mMaxX = 0; + mGlobalMapState.mBounds.mMinY = 0; + mGlobalMapState.mBounds.mMaxY = 0; } }; From 0c1d76279049155fa9f6d3f1a44fa28585091e2f Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Fri, 23 Jan 2015 15:37:32 +0100 Subject: [PATCH 0388/3725] Fix build when using new boost with Ogre. This fixes a [Parse error at "BOOST_JOIN"] if you're using - for instance - Boost 1.57.0 --- apps/launcher/graphicspage.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/launcher/graphicspage.hpp b/apps/launcher/graphicspage.hpp index da4cb9fb3..a96d9b732 100644 --- a/apps/launcher/graphicspage.hpp +++ b/apps/launcher/graphicspage.hpp @@ -3,8 +3,10 @@ #include +#ifndef Q_MOC_RUN #include #include +#endif #include From 7a903b7100d85838033177a5b15520f9afd146d2 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Fri, 23 Jan 2015 16:05:36 +0100 Subject: [PATCH 0389/3725] Doing forward declaration instead --- apps/launcher/graphicspage.hpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/apps/launcher/graphicspage.hpp b/apps/launcher/graphicspage.hpp index a96d9b732..213b6bccb 100644 --- a/apps/launcher/graphicspage.hpp +++ b/apps/launcher/graphicspage.hpp @@ -3,16 +3,11 @@ #include -#ifndef Q_MOC_RUN -#include -#include -#endif - #include - #include "ui_graphicspage.h" +namespace Ogre { class Root; class RenderSystem; } namespace Files { struct ConfigurationManager; } From 942cf26eeed3b92cb7ee5c7dccee35fc6fe4c8e0 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Fri, 23 Jan 2015 16:06:19 +0100 Subject: [PATCH 0390/3725] And the missing includes --- apps/launcher/graphicspage.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index da707b005..1f85bb5e7 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -12,6 +12,9 @@ #include +#include +#include + #include #include From 79d2eebe5435b9e1e92acbec2c191dc416b12a7b Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 23 Jan 2015 16:45:47 +0100 Subject: [PATCH 0391/3725] Store selected enchant item in savegame (Fixes #1702) --- apps/essimporter/convertinventory.cpp | 9 ++- apps/openmw/mwworld/containerstore.cpp | 87 ++++++++++++++------------ apps/openmw/mwworld/containerstore.hpp | 9 +-- apps/openmw/mwworld/inventorystore.cpp | 48 +++++++++----- apps/openmw/mwworld/inventorystore.hpp | 7 +-- components/esm/inventorystate.cpp | 76 +++++++++++++--------- components/esm/inventorystate.hpp | 9 ++- 7 files changed, 145 insertions(+), 100 deletions(-) diff --git a/apps/essimporter/convertinventory.cpp b/apps/essimporter/convertinventory.cpp index 31272bf5a..f476fe1ee 100644 --- a/apps/essimporter/convertinventory.cpp +++ b/apps/essimporter/convertinventory.cpp @@ -7,6 +7,7 @@ namespace ESSImport void convertInventory(const Inventory &inventory, ESM::InventoryState &state) { + int index = 0; for (std::vector::const_iterator it = inventory.mItems.begin(); it != inventory.mItems.end(); ++it) { @@ -16,7 +17,13 @@ namespace ESSImport objstate.mRef.mRefID = Misc::StringUtils::lowerCase(it->mId); objstate.mCount = std::abs(it->mCount); // restocking items have negative count in the savefile // openmw handles them differently, so no need to set any flags - state.mItems.push_back(std::make_pair(objstate, it->mRelativeEquipmentSlot)); + state.mItems.push_back(objstate); + if (it->mRelativeEquipmentSlot != -1) + // Note we should really write the absolute slot here, which we do not know about + // Not a big deal, OpenMW will auto-correct to a valid slot, the only problem is when + // an item could be equipped in two different slots (e.g. equipped two rings) + state.mEquipmentSlots[index] = it->mRelativeEquipmentSlot; + ++index; } } diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 57621b7a4..b21486c2c 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -79,6 +79,14 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::getState (CellRefList void MWWorld::ContainerStore::storeState (const LiveCellRef& ref, ESM::ObjectState& state) const { @@ -87,7 +95,7 @@ void MWWorld::ContainerStore::storeState (const LiveCellRef& ref, ESM::Object template void MWWorld::ContainerStore::storeStates (CellRefList& collection, - std::vector >& states, bool equipable) const + ESM::InventoryState& inventory, int& index, bool equipable) const { for (typename CellRefList::List::const_iterator iter (collection.mList.begin()); iter!=collection.mList.end(); ++iter) @@ -96,18 +104,13 @@ void MWWorld::ContainerStore::storeStates (CellRefList& collection, continue; ESM::ObjectState state; storeState (*iter, state); - int slot = equipable ? getSlot (*iter) : -1; - states.push_back (std::make_pair (state, slot)); + if (equipable) + storeEquipmentState(*iter, index, inventory); + inventory.mItems.push_back (state); + ++index; } } -int MWWorld::ContainerStore::getSlot (const MWWorld::LiveCellRefBase& ref) const -{ - return -1; -} - -void MWWorld::ContainerStore::setSlot (const MWWorld::ContainerStoreIterator& iter, int slot) {} - const std::string MWWorld::ContainerStore::sGoldId = "gold_001"; MWWorld::ContainerStore::ContainerStore() : mCachedWeight (0), mWeightUpToDate (false) {} @@ -645,49 +648,51 @@ void MWWorld::ContainerStore::writeState (ESM::InventoryState& state) { state.mItems.clear(); - storeStates (potions, state.mItems); - storeStates (appas, state.mItems); - storeStates (armors, state.mItems, true); - storeStates (books, state.mItems); - storeStates (clothes, state.mItems, true); - storeStates (ingreds, state.mItems); - storeStates (lockpicks, state.mItems, true); - storeStates (miscItems, state.mItems); - storeStates (probes, state.mItems, true); - storeStates (repairs, state.mItems); - storeStates (weapons, state.mItems, true); - storeStates (lights, state.mItems, true); + int index = 0; + storeStates (potions, state, index); + storeStates (appas, state, index); + storeStates (armors, state, index, true); + storeStates (books, state, index, true); // not equipable as such, but for selectedEnchantItem + storeStates (clothes, state, index, true); + storeStates (ingreds, state, index); + storeStates (lockpicks, state, index, true); + storeStates (miscItems, state, index); + storeStates (probes, state, index, true); + storeStates (repairs, state, index); + storeStates (weapons, state, index, true); + storeStates (lights, state, index, true); state.mLevelledItemMap = mLevelledItemMap; } -void MWWorld::ContainerStore::readState (const ESM::InventoryState& state) +void MWWorld::ContainerStore::readState (const ESM::InventoryState& inventory) { clear(); - for (std::vector >::const_iterator - iter (state.mItems.begin()); iter!=state.mItems.end(); ++iter) + int index = 0; + for (std::vector::const_iterator + iter (inventory.mItems.begin()); iter!=inventory.mItems.end(); ++iter) { - int slot = iter->second; - - const ESM::ObjectState& state = iter->first; + const ESM::ObjectState& state = *iter; int type = MWBase::Environment::get().getWorld()->getStore().find(state.mRef.mRefID); + int thisIndex = index++; + switch (type) { - case ESM::REC_ALCH: getState (potions, iter->first); break; - case ESM::REC_APPA: getState (appas, iter->first); break; - case ESM::REC_ARMO: setSlot (getState (armors, iter->first), slot); break; - case ESM::REC_BOOK: getState (books, iter->first); break; - case ESM::REC_CLOT: setSlot (getState (clothes, iter->first), slot); break; - case ESM::REC_INGR: getState (ingreds, iter->first); break; - case ESM::REC_LOCK: setSlot (getState (lockpicks, iter->first), slot); break; - case ESM::REC_MISC: getState (miscItems, iter->first); break; - case ESM::REC_PROB: setSlot (getState (probes, iter->first), slot); break; - case ESM::REC_REPA: getState (repairs, iter->first); break; - case ESM::REC_WEAP: setSlot (getState (weapons, iter->first), slot); break; - case ESM::REC_LIGH: setSlot (getState (lights, iter->first), slot); break; + case ESM::REC_ALCH: getState (potions, state); break; + case ESM::REC_APPA: getState (appas, state); break; + case ESM::REC_ARMO: readEquipmentState (getState (armors, state), thisIndex, inventory); break; + case ESM::REC_BOOK: readEquipmentState (getState (books, state), thisIndex, inventory); break; // not equipable as such, but for selectedEnchantItem + case ESM::REC_CLOT: readEquipmentState (getState (clothes, state), thisIndex, inventory); break; + case ESM::REC_INGR: getState (ingreds, state); break; + case ESM::REC_LOCK: readEquipmentState (getState (lockpicks, state), thisIndex, inventory); break; + case ESM::REC_MISC: getState (miscItems, state); break; + case ESM::REC_PROB: readEquipmentState (getState (probes, state), thisIndex, inventory); break; + case ESM::REC_REPA: getState (repairs, state); break; + case ESM::REC_WEAP: readEquipmentState (getState (weapons, state), thisIndex, inventory); break; + case ESM::REC_LIGH: readEquipmentState (getState (lights, state), thisIndex, inventory); break; case 0: std::cerr << "Dropping reference to '" << state.mRef.mRefID << "' (object no longer exists)" << std::endl; break; @@ -698,7 +703,7 @@ void MWWorld::ContainerStore::readState (const ESM::InventoryState& state) } - mLevelledItemMap = state.mLevelledItemMap; + mLevelledItemMap = inventory.mLevelledItemMap; } diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index f7c8a369c..d909a98cc 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -86,15 +86,12 @@ namespace MWWorld template void storeStates (CellRefList& collection, - std::vector >& states, + ESM::InventoryState& inventory, int& index, bool equipable = false) const; - virtual int getSlot (const MWWorld::LiveCellRefBase& ref) const; - ///< Return inventory slot that \a ref is in or -1 (if \a ref is not in a slot). - - virtual void setSlot (const MWWorld::ContainerStoreIterator& iter, int slot); - ///< Set slot for \a iter. Ignored if \a iter is an end iterator or if slot==-1. + virtual void storeEquipmentState (const MWWorld::LiveCellRefBase& ref, int index, ESM::InventoryState& inventory) const; + virtual void readEquipmentState (const MWWorld::ContainerStoreIterator& iter, int index, const ESM::InventoryState& inventory); public: ContainerStore(); diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index be93824e5..4950be912 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -49,33 +49,47 @@ void MWWorld::InventoryStore::initSlots (TSlots& slots_) slots_.push_back (end()); } -int MWWorld::InventoryStore::getSlot (const MWWorld::LiveCellRefBase& ref) const +void MWWorld::InventoryStore::storeEquipmentState(const MWWorld::LiveCellRefBase &ref, int index, ESM::InventoryState &inventory) const { for (int i = 0; i (mSlots.size()); ++i) if (mSlots[i].getType()!=-1 && mSlots[i]->getBase()==&ref) - return i; + { + inventory.mEquipmentSlots[index] = i; + } - return -1; + if (mSelectedEnchantItem.getType()!=-1 && mSelectedEnchantItem->getBase() == &ref) + inventory.mSelectedEnchantItem = index; } -void MWWorld::InventoryStore::setSlot (const MWWorld::ContainerStoreIterator& iter, int relativeSlot) +void MWWorld::InventoryStore::readEquipmentState(const MWWorld::ContainerStoreIterator &iter, int index, const ESM::InventoryState &inventory) { - if (relativeSlot < 0 || iter == end()) - return; - - // make sure the item can actually be equipped in this slot - std::pair, bool> allowedSlots = iter->getClass().getEquipmentSlots(*iter); - relativeSlot = std::min(int(allowedSlots.first.size()-1), relativeSlot); + if (index == inventory.mSelectedEnchantItem) + mSelectedEnchantItem = iter; - // unstack if required - if (!allowedSlots.second && iter->getRefData().getCount() > 1) + std::map::const_iterator found = inventory.mEquipmentSlots.find(index); + if (found != inventory.mEquipmentSlots.end()) { - MWWorld::ContainerStoreIterator newIter = addNewStack(*iter, 1); - iter->getRefData().setCount(iter->getRefData().getCount()-1); - mSlots[allowedSlots.first[relativeSlot]] = newIter; + if (found->second < 0 || found->second >= MWWorld::InventoryStore::Slots) + throw std::runtime_error("Invalid slot index in inventory state"); + + // make sure the item can actually be equipped in this slot + int slot = found->second; + std::pair, bool> allowedSlots = iter->getClass().getEquipmentSlots(*iter); + if (!allowedSlots.first.size()) + return; + if (std::find(allowedSlots.first.begin(), allowedSlots.first.end(), slot) == allowedSlots.first.end()) + slot = allowedSlots.first.front(); + + // unstack if required + if (!allowedSlots.second && iter->getRefData().getCount() > 1) + { + MWWorld::ContainerStoreIterator newIter = addNewStack(*iter, 1); + iter->getRefData().setCount(iter->getRefData().getCount()-1); + mSlots[slot] = newIter; + } + else + mSlots[slot] = iter; } - else - mSlots[allowedSlots.first[relativeSlot]] = iter; } MWWorld::InventoryStore::InventoryStore() diff --git a/apps/openmw/mwworld/inventorystore.hpp b/apps/openmw/mwworld/inventorystore.hpp index 7bd977e39..9a154373a 100644 --- a/apps/openmw/mwworld/inventorystore.hpp +++ b/apps/openmw/mwworld/inventorystore.hpp @@ -113,11 +113,8 @@ namespace MWWorld void fireEquipmentChangedEvent(); - virtual int getSlot (const MWWorld::LiveCellRefBase& ref) const; - ///< Return inventory slot that \a ref is in or -1 (if \a ref is not in a slot). - - virtual void setSlot (const MWWorld::ContainerStoreIterator& iter, int relativeSlot); - ///< Set slot for \a iter. Ignored if \a iter is an end iterator or if slot==-1. + virtual void storeEquipmentState (const MWWorld::LiveCellRefBase& ref, int index, ESM::InventoryState& inventory) const; + virtual void readEquipmentState (const MWWorld::ContainerStoreIterator& iter, int index, const ESM::InventoryState& inventory); public: diff --git a/components/esm/inventorystate.cpp b/components/esm/inventorystate.cpp index b946f9501..4eaaa9f9f 100644 --- a/components/esm/inventorystate.cpp +++ b/components/esm/inventorystate.cpp @@ -4,42 +4,33 @@ #include "esmreader.hpp" #include "esmwriter.hpp" -namespace -{ - void read (ESM::ESMReader &esm, ESM::ObjectState& state, int& slot) - { - slot = -1; - esm.getHNOT (slot, "SLOT"); - - state.mRef.loadId(esm, true); - state.load (esm); - } - - void write (ESM::ESMWriter &esm, const ESM::ObjectState& state, int slot) - { - int unused = 0; - esm.writeHNT ("IOBJ", unused); - - if (slot!=-1) - esm.writeHNT ("SLOT", slot); - - state.save (esm, true); - } -} - void ESM::InventoryState::load (ESMReader &esm) { + int index = 0; while (esm.isNextSub ("IOBJ")) { int unused; // no longer used esm.getHT(unused); ObjectState state; - int slot; - read (esm, state, slot); + + // obsolete + if (esm.isNextSub("SLOT")) + { + int slot; + esm.getHT(slot); + mEquipmentSlots[index] = slot; + } + + state.mRef.loadId(esm, true); + state.load (esm); + if (state.mCount == 0) continue; - mItems.push_back (std::make_pair (state, slot)); + + mItems.push_back (state); + + ++index; } while (esm.isNextSub("LEVM")) @@ -64,12 +55,30 @@ void ESM::InventoryState::load (ESMReader &esm) } mPermanentMagicEffectMagnitudes[id] = params; } + + while (esm.isNextSub("EQUI")) + { + esm.getSubHeader(); + int index; + esm.getT(index); + int slot; + esm.getT(slot); + mEquipmentSlots[index] = slot; + } + + mSelectedEnchantItem = -1; + esm.getHNOT(mSelectedEnchantItem, "SELE"); } void ESM::InventoryState::save (ESMWriter &esm) const { - for (std::vector >::const_iterator iter (mItems.begin()); iter!=mItems.end(); ++iter) - write (esm, iter->first, iter->second); + for (std::vector::const_iterator iter (mItems.begin()); iter!=mItems.end(); ++iter) + { + int unused = 0; + esm.writeHNT ("IOBJ", unused); + + iter->save (esm, true); + } for (std::map::const_iterator it = mLevelledItemMap.begin(); it != mLevelledItemMap.end(); ++it) { @@ -88,4 +97,15 @@ void ESM::InventoryState::save (ESMWriter &esm) const esm.writeHNT ("MULT", pIt->second); } } + + for (std::map::const_iterator it = mEquipmentSlots.begin(); it != mEquipmentSlots.end(); ++it) + { + esm.startSubRecord("EQUI"); + esm.writeT(it->first); + esm.writeT(it->second); + esm.endRecord("EQUI"); + } + + if (mSelectedEnchantItem != -1) + esm.writeHNT ("SELE", mSelectedEnchantItem); } diff --git a/components/esm/inventorystate.hpp b/components/esm/inventorystate.hpp index 13af28e30..d5c317beb 100644 --- a/components/esm/inventorystate.hpp +++ b/components/esm/inventorystate.hpp @@ -15,14 +15,19 @@ namespace ESM /// \brief State for inventories and containers struct InventoryState { - /// - std::vector > mItems; + std::vector mItems; + + // + std::map mEquipmentSlots; std::map mLevelledItemMap; typedef std::map > > TEffectMagnitudes; TEffectMagnitudes mPermanentMagicEffectMagnitudes; + int mSelectedEnchantItem; // For inventories only + + InventoryState() : mSelectedEnchantItem(-1) {} virtual ~InventoryState() {} virtual void load (ESMReader &esm); From b0c2aec374e7faddbcc9927c537457f63de6a6be Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 23 Jan 2015 17:29:03 +0100 Subject: [PATCH 0392/3725] Add warning for missing body parts --- apps/openmw/mwrender/npcanimation.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index a8ba1abf5..9b05ce0a2 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -811,6 +811,8 @@ void NpcAnimation::addPartGroup(int group, int priority, const std::vectormData.mPart == ESM::BodyPart::MP_Upperarm)) bodypart = NULL; } + else if (!bodypart) + std::cerr << "Failed to find body part '" << part->mFemale << "'" << std::endl; } if(!bodypart && !part->mMale.empty()) { @@ -824,6 +826,8 @@ void NpcAnimation::addPartGroup(int group, int priority, const std::vectormData.mPart == ESM::BodyPart::MP_Upperarm)) bodypart = NULL; } + else if (!bodypart) + std::cerr << "Failed to find body part '" << part->mMale << "'" << std::endl; } if(bodypart) From bf90b86f73d47a95442865b9254b46d8e350c0ae Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 23 Jan 2015 20:09:30 +0100 Subject: [PATCH 0393/3725] ESSImport: add some missing subrecords --- apps/essimporter/importacdt.cpp | 4 ++++ apps/essimporter/importplayer.cpp | 9 ++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/apps/essimporter/importacdt.cpp b/apps/essimporter/importacdt.cpp index e590e2826..00bd4ad80 100644 --- a/apps/essimporter/importacdt.cpp +++ b/apps/essimporter/importacdt.cpp @@ -60,6 +60,10 @@ namespace ESSImport if (esm.isNextSub("PWPS")) esm.skipHSub(); + // unsure at which point between LSTN and CHRD + if (esm.isNextSub("APUD")) + esm.skipHSub(); // 40 bytes, starts with string "ancestor guardian"... + if (esm.isNextSub("WNAM")) { esm.skipHSub(); // seen values: "ancestor guardian", "bound dagger_en". Summoned creature / bound weapons? diff --git a/apps/essimporter/importplayer.cpp b/apps/essimporter/importplayer.cpp index ea9f1932c..9845ab072 100644 --- a/apps/essimporter/importplayer.cpp +++ b/apps/essimporter/importplayer.cpp @@ -63,8 +63,11 @@ namespace ESSImport mFactions.push_back(fnam); } + if (esm.isNextSub("AADT")) + esm.skipHSub(); // 44 bytes, no clue + if (esm.isNextSub("KNAM")) - esm.skipHSub(); + esm.skipHSub(); // assigned Quick Keys, I think if (esm.isNextSub("WERE")) { @@ -73,6 +76,10 @@ namespace ESSImport esm.getSubHeader(); esm.skip(152); } + + // unsure if before or after WERE + if (esm.isNextSub("ANIS")) + esm.skipHSub(); } } From 8e5c8aa562ba4d03c112bf78ee3a840d0c05c12d Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 23 Jan 2015 23:57:00 +0100 Subject: [PATCH 0394/3725] Add support for passing in Ogre plugin directory via CMake --- CMakeLists.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7ceee29e6..c3def1381 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -51,6 +51,8 @@ option(OGRE_STATIC "Link static build of Ogre and Ogre Plugins into the binarie option(BOOST_STATIC "Link static build of Boost into the binaries" FALSE) option(SDL2_STATIC "Link static build of SDL into the binaries" FALSE) +set(CUSTOM_OGRE_PLUGIN_DIR "" CACHE PATH "Specify a custom directory for Ogre plugins (autodetected by default)") + option(OPENMW_UNITY_BUILD "Use fewer compilation units to speed up compile time" FALSE) # Apps and tools @@ -323,8 +325,10 @@ if (APPLE AND OPENMW_OSX_DEPLOYMENT) # make it empty so plugin loading code can check this and try to find plugins inside app bundle add_definitions(-DOGRE_PLUGIN_DIR="") else() - if (NOT DEFINED ${OGRE_PLUGIN_DIR}) + if (CUSTOM_OGRE_PLUGIN_DIR STREQUAL "") set(OGRE_PLUGIN_DIR ${OGRE_PLUGIN_DIR_REL}) + else() + set(OGRE_PLUGIN_DIR ${CUSTOM_OGRE_PLUGIN_DIR}) endif() add_definitions(-DOGRE_PLUGIN_DIR="${OGRE_PLUGIN_DIR}") From 09f11fbff224b0c5c364629d56bd2929d0956875 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 24 Jan 2015 00:18:17 +0100 Subject: [PATCH 0395/3725] ESSImport: convert selected spell / selected enchant item --- apps/essimporter/converter.hpp | 21 +++++++++++++++++++++ apps/essimporter/importacdt.cpp | 11 +++++------ apps/essimporter/importacdt.hpp | 3 +++ 3 files changed, 29 insertions(+), 6 deletions(-) diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index 7565b78d4..6f85b01cf 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -226,7 +226,28 @@ public: ESM::NpcStats& npcStats = mContext->mPlayer.mObject.mNpcStats; convertNpcData(refr.mActorData, npcStats); + + mSelectedSpell = refr.mActorData.mSelectedSpell; + if (!refr.mActorData.mSelectedEnchantItem.empty()) + { + ESM::InventoryState& invState = mContext->mPlayer.mObject.mInventory; + + for (unsigned int i=0; i Date: Sat, 24 Jan 2015 14:22:29 +0100 Subject: [PATCH 0396/3725] save MVRF subrecords --- apps/opencs/model/doc/savingstages.cpp | 5 +---- components/esm/cellref.cpp | 6 +++--- components/esm/cellref.hpp | 2 +- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/apps/opencs/model/doc/savingstages.cpp b/apps/opencs/model/doc/savingstages.cpp index 6b8750b44..4354a0313 100644 --- a/apps/opencs/model/doc/savingstages.cpp +++ b/apps/opencs/model/doc/savingstages.cpp @@ -314,10 +314,7 @@ void CSMDoc::WriteCellCollectionStage::perform (int stage, Messages& messages) char ignore; stream >> ignore >> moved.mTarget[0] >> moved.mTarget[1]; - mState.getWriter().startSubRecord ("MVRF"); - - mState.getWriter().endRecord ("MVRF"); - mState.getWriter().writeHNT ("FRMR", moved.mRefNum.mIndex, 4); + ref.get().mRefNum.save (mState.getWriter(), false, "MVRF"); mState.getWriter().writeHNT ("CNDT", moved.mTarget, 8); } diff --git a/components/esm/cellref.cpp b/components/esm/cellref.cpp index 0e258571f..546151e27 100644 --- a/components/esm/cellref.cpp +++ b/components/esm/cellref.cpp @@ -12,15 +12,15 @@ void ESM::RefNum::load (ESMReader& esm, bool wide) esm.getHNT (mIndex, "FRMR"); } -void ESM::RefNum::save (ESMWriter &esm, bool wide) const +void ESM::RefNum::save (ESMWriter &esm, bool wide, const std::string& tag) const { if (wide) - esm.writeHNT ("FRMR", *this, 8); + esm.writeHNT (tag, *this, 8); else { int refNum = (mIndex & 0xffffff) | ((mContentFile==-1 ? 0xff : mContentFile)<<24); - esm.writeHNT ("FRMR", refNum, 4); + esm.writeHNT (tag, refNum, 4); } } diff --git a/components/esm/cellref.hpp b/components/esm/cellref.hpp index 505f676b1..d4e63d6e8 100644 --- a/components/esm/cellref.hpp +++ b/components/esm/cellref.hpp @@ -18,7 +18,7 @@ namespace ESM void load (ESMReader& esm, bool wide = false); - void save (ESMWriter &esm, bool wide = false) const; + void save (ESMWriter &esm, bool wide = false, const std::string& tag = "FRMR") const; }; /* Cell reference. This represents ONE object (of many) inside the From 7d762133748cb06439628cb4ada69b3c10c2b085 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 24 Jan 2015 14:32:02 +0100 Subject: [PATCH 0397/3725] Fix loading faction reactions for older savegames (Fixes #2301) --- components/esm/dialoguestate.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esm/dialoguestate.cpp b/components/esm/dialoguestate.cpp index f546462a3..f302e36dc 100644 --- a/components/esm/dialoguestate.cpp +++ b/components/esm/dialoguestate.cpp @@ -25,7 +25,7 @@ void ESM::DialogueState::load (ESMReader &esm) while (esm.isNextSub ("REAC")) { esm.skipHSub(); - esm.getSubHeader(); + esm.getSubName(); esm.skipHSub(); } } From 7f905470fae10ac8d5665b19adbc995a92cb720d Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 24 Jan 2015 15:01:38 +0100 Subject: [PATCH 0398/3725] fixed moved reference loading --- apps/opencs/model/world/refcollection.cpp | 3 +-- components/esm/cellref.cpp | 5 +++-- components/esm/loadcell.cpp | 20 +++++++++++++++----- components/esm/loadcell.hpp | 3 ++- 4 files changed, 21 insertions(+), 10 deletions(-) diff --git a/apps/opencs/model/world/refcollection.cpp b/apps/opencs/model/world/refcollection.cpp index dcb295626..39f85da70 100644 --- a/apps/opencs/model/world/refcollection.cpp +++ b/apps/opencs/model/world/refcollection.cpp @@ -21,7 +21,7 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool bool deleted = false; - while (ESM::Cell::getNextRef (reader, ref, deleted)) + while (ESM::Cell::getNextRef (reader, ref, deleted, true)) { // Keep mOriginalCell empty when in modified (as an indicator that the // original cell will always be equal the current cell). @@ -29,7 +29,6 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool if (cell.get().isExterior()) { - // ignoring moved references sub-record; instead calculate cell from coordinates std::pair index = ref.getCellIndex(); diff --git a/components/esm/cellref.cpp b/components/esm/cellref.cpp index 546151e27..8579d891f 100644 --- a/components/esm/cellref.cpp +++ b/components/esm/cellref.cpp @@ -25,7 +25,7 @@ void ESM::RefNum::save (ESMWriter &esm, bool wide, const std::string& tag) const } -void ESM::CellRef::load (ESMReader& esm, bool wideRefNum) +void ESM::CellRef::load (ESMReader& esm, bool wideRefNum, bool ignoreRefNum) { // According to Hrnchamd, this does not belong to the actual ref. Instead, it is a marker indicating that // the following refs are part of a "temp refs" section. A temp ref is not being tracked by the moved references system. @@ -34,7 +34,8 @@ void ESM::CellRef::load (ESMReader& esm, bool wideRefNum) if (esm.isNextSub ("NAM0")) esm.skipHSub(); - mRefNum.load (esm, wideRefNum); + if (!ignoreRefNum) + mRefNum.load (esm, wideRefNum); mRefID = esm.getHNString ("NAME"); diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index e4f847dec..d836ec9cf 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -168,7 +168,7 @@ std::string Cell::getDescription() const } } -bool Cell::getNextRef(ESMReader &esm, CellRef &ref, bool& deleted) +bool Cell::getNextRef(ESMReader &esm, CellRef &ref, bool& deleted, bool ignoreMoves) { // TODO: Try and document reference numbering, I don't think this has been done anywhere else. if (!esm.hasMoreSubs()) @@ -176,10 +176,20 @@ bool Cell::getNextRef(ESMReader &esm, CellRef &ref, bool& deleted) // NOTE: We should not need this check. It is a safety check until we have checked // more plugins, and how they treat these moved references. - if (esm.isNextSub("MVRF")) { - // skip rest of cell record (moved references), they are handled elsewhere - esm.skipRecord(); // skip MVRF, CNDT - return false; + if (esm.isNextSub("MVRF")) + { + if (ignoreMoves) + { + MovedCellRef mref; + esm.getHT (mref.mRefNum.mIndex); + esm.getHNOT (mref.mTarget, "CNDT"); + } + else + { + // skip rest of cell record (moved references), they are handled elsewhere + esm.skipRecord(); // skip MVRF, CNDT + return false; + } } ref.load (esm); diff --git a/components/esm/loadcell.hpp b/components/esm/loadcell.hpp index e1a6eee1a..8eeecd893 100644 --- a/components/esm/loadcell.hpp +++ b/components/esm/loadcell.hpp @@ -156,7 +156,8 @@ struct Cell All fields of the CellRef struct are overwritten. You can safely reuse one memory location without blanking it between calls. */ - static bool getNextRef(ESMReader &esm, CellRef &ref, bool& deleted); + /// \param ignoreMoves ignore MVRF record and read reference like a regular CellRef. + static bool getNextRef(ESMReader &esm, CellRef &ref, bool& deleted, bool ignoreMoves = false); /* This fetches an MVRF record, which is used to track moved references. * Since they are comparably rare, we use a separate method for this. From b1bd236345fbe4fbd84f9855c958c02d323a9863 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 24 Jan 2015 16:15:52 +0100 Subject: [PATCH 0399/3725] ESSImport: convert script local variables Had to add special reading code to openmw, because the variable names are not stored. --- apps/essimporter/CMakeLists.txt | 1 + apps/essimporter/converter.cpp | 3 ++ apps/essimporter/convertscri.cpp | 32 ++++++++++++++++ apps/essimporter/convertscri.hpp | 16 ++++++++ apps/essimporter/importer.cpp | 6 +++ apps/openmw/mwscript/locals.cpp | 63 +++++++++++++++++++++++++------- components/esm/locals.cpp | 6 +-- components/esm/variant.cpp | 26 ++++++++++++- components/esm/variant.hpp | 3 +- components/esm/variantimp.cpp | 33 +++++++++++++++-- 10 files changed, 167 insertions(+), 22 deletions(-) create mode 100644 apps/essimporter/convertscri.cpp create mode 100644 apps/essimporter/convertscri.hpp diff --git a/apps/essimporter/CMakeLists.txt b/apps/essimporter/CMakeLists.txt index 5db3a86dc..409b8bcff 100644 --- a/apps/essimporter/CMakeLists.txt +++ b/apps/essimporter/CMakeLists.txt @@ -23,6 +23,7 @@ set(ESSIMPORTER_FILES convertinventory.cpp convertcrec.cpp convertcntc.cpp + convertscri.cpp ) add_executable(openmw-essimporter diff --git a/apps/essimporter/converter.cpp b/apps/essimporter/converter.cpp index 75c2911fd..3b82988b8 100644 --- a/apps/essimporter/converter.cpp +++ b/apps/essimporter/converter.cpp @@ -9,6 +9,7 @@ #include "convertcrec.hpp" #include "convertcntc.hpp" +#include "convertscri.hpp" namespace { @@ -29,6 +30,8 @@ namespace objstate.mRef.mRefNum = cellref.mRefNum; if (cellref.mDeleted) objstate.mCount = 0; + convertSCRI(cellref.mSCRI, objstate.mLocals); + objstate.mHasLocals = !objstate.mLocals.mVariables.empty(); } bool isIndexedRefId(const std::string& indexedRefId) diff --git a/apps/essimporter/convertscri.cpp b/apps/essimporter/convertscri.cpp new file mode 100644 index 000000000..dbe35a010 --- /dev/null +++ b/apps/essimporter/convertscri.cpp @@ -0,0 +1,32 @@ +#include "convertscri.hpp" + +#include + +namespace +{ + + template + void storeVariables(const std::vector& variables, ESM::Locals& locals, const std::string& scriptname) + { + for (typename std::vector::const_iterator it = variables.begin(); it != variables.end(); ++it) + { + ESM::Variant val(*it); + val.setType(VariantType); + locals.mVariables.push_back(std::make_pair(std::string(), val)); + } + } + +} + +namespace ESSImport +{ + + void convertSCRI(const SCRI &scri, ESM::Locals &locals) + { + // order *is* important, as we do not have variable names available in this format + storeVariables (scri.mShorts, locals, scri.mScript); + storeVariables (scri.mLongs, locals, scri.mScript); + storeVariables (scri.mFloats, locals, scri.mScript); + } + +} diff --git a/apps/essimporter/convertscri.hpp b/apps/essimporter/convertscri.hpp new file mode 100644 index 000000000..2d8945666 --- /dev/null +++ b/apps/essimporter/convertscri.hpp @@ -0,0 +1,16 @@ +#ifndef OPENMW_ESSIMPORT_CONVERTSCRI_H +#define OPENMW_ESSIMPORT_CONVERTSCRI_H + +#include "importscri.hpp" + +#include + +namespace ESSImport +{ + + /// Convert script variable assignments + void convertSCRI (const SCRI& scri, ESM::Locals& locals); + +} + +#endif diff --git a/apps/essimporter/importer.cpp b/apps/essimporter/importer.cpp index ed149b023..73a12769a 100644 --- a/apps/essimporter/importer.cpp +++ b/apps/essimporter/importer.cpp @@ -237,6 +237,12 @@ namespace ESSImport converters[recJOUR ] = boost::shared_ptr(new ConvertJOUR()); converters[ESM::REC_SCPT] = boost::shared_ptr(new ConvertSCPT()); + // TODO: + // - REGN (weather in certain regions?) + // - VFXM + // - SPLM (active spell effects) + // - PROJ (magic projectiles in air) + std::set unknownRecords; for (std::map >::const_iterator it = converters.begin(); diff --git a/apps/openmw/mwscript/locals.cpp b/apps/openmw/mwscript/locals.cpp index a1ee48ae6..fe3e49827 100644 --- a/apps/openmw/mwscript/locals.cpp +++ b/apps/openmw/mwscript/locals.cpp @@ -10,6 +10,8 @@ #include "../mwbase/environment.hpp" #include "../mwbase/scriptmanager.hpp" +#include + namespace MWScript { void Locals::configure (const ESM::Script& script) @@ -124,27 +126,60 @@ namespace MWScript const Compiler::Locals& declarations = MWBase::Environment::get().getScriptManager()->getLocals(script); - for (std::vector >::const_iterator iter - = locals.mVariables.begin(); iter!=locals.mVariables.end(); ++iter) + int index = 0, numshorts = 0, numlongs = 0; + for (unsigned int v=0; vfirst); - char index = declarations.getIndex (iter->first); + ESM::VarType type = locals.mVariables[v].second.getType(); + if (type == ESM::VT_Short) + ++numshorts; + else if (type == ESM::VT_Int) + ++numlongs; + } - try + for (std::vector >::const_iterator iter + = locals.mVariables.begin(); iter!=locals.mVariables.end(); ++iter,++index) + { + if (iter->first.empty()) { - switch (type) + // no variable names available (this will happen for legacy, i.e. ESS-imported savegames only) + try { - case 's': mShorts.at (index) = iter->second.getInteger(); break; - case 'l': mLongs.at (index) = iter->second.getInteger(); break; - case 'f': mFloats.at (index) = iter->second.getFloat(); break; - - // silently ignore locals that don't exist anymore + if (index >= numshorts+numlongs) + mFloats.at(index - (numshorts+numlongs)) = iter->second.getFloat(); + else if (index >= numshorts) + mLongs.at(index - numshorts) = iter->second.getInteger(); + else + mShorts.at(index) = iter->second.getInteger(); + } + catch (std::exception& e) + { + std::cerr << "Failed to read local variable state for script '" + << script << "' (legacy format): " << e.what() + << "\nNum shorts: " << numshorts << " / " << mShorts.size() + << " Num longs: " << numlongs << " / " << mLongs.size() << std::endl; } } - catch (...) + else { - // ignore type changes - /// \todo write to log + char type = declarations.getType (iter->first); + char index = declarations.getIndex (iter->first); + + try + { + switch (type) + { + case 's': mShorts.at (index) = iter->second.getInteger(); break; + case 'l': mLongs.at (index) = iter->second.getInteger(); break; + case 'f': mFloats.at (index) = iter->second.getFloat(); break; + + // silently ignore locals that don't exist anymore + } + } + catch (...) + { + // ignore type changes + /// \todo write to log + } } } } diff --git a/components/esm/locals.cpp b/components/esm/locals.cpp index 9c470a025..f0cfd49f0 100644 --- a/components/esm/locals.cpp +++ b/components/esm/locals.cpp @@ -11,7 +11,7 @@ void ESM::Locals::load (ESMReader &esm) std::string id = esm.getHString(); Variant value; - value.read (esm, Variant::Format_Info); + value.read (esm, Variant::Format_Local); mVariables.push_back (std::make_pair (id, value)); } @@ -23,6 +23,6 @@ void ESM::Locals::save (ESMWriter &esm) const iter!=mVariables.end(); ++iter) { esm.writeHNString ("LOCA", iter->first); - iter->second.write (esm, Variant::Format_Info); + iter->second.write (esm, Variant::Format_Local); } -} \ No newline at end of file +} diff --git a/components/esm/variant.cpp b/components/esm/variant.cpp index 4127a9d62..c65eed5e0 100644 --- a/components/esm/variant.cpp +++ b/components/esm/variant.cpp @@ -13,6 +13,7 @@ namespace const uint32_t STRV = ESM::FourCC<'S','T','R','V'>::value; const uint32_t INTV = ESM::FourCC<'I','N','T','V'>::value; const uint32_t FLTV = ESM::FourCC<'F','L','T','V'>::value; + const uint32_t STTV = ESM::FourCC<'S','T','T','V'>::value; } ESM::Variant::Variant() : mType (VT_None), mData (0) {} @@ -141,7 +142,7 @@ void ESM::Variant::read (ESMReader& esm, Format format) esm.fail ("invalid subrecord: " + name.toString()); } } - else // info + else if (format == Format_Info) { esm.getSubName(); NAME name = esm.retSubName(); @@ -157,6 +158,26 @@ void ESM::Variant::read (ESMReader& esm, Format format) else esm.fail ("invalid subrecord: " + name.toString()); } + else if (format == Format_Local) + { + esm.getSubName(); + NAME name = esm.retSubName(); + + if (name==INTV) + { + type = VT_Int; + } + else if (name==FLTV) + { + type = VT_Float; + } + else if (name==STTV) + { + type = VT_Short; + } + else + esm.fail ("invalid subrecord: " + name.toString()); + } setType (type); @@ -179,6 +200,9 @@ void ESM::Variant::write (ESMWriter& esm, Format format) const if (format==Format_Info) throw std::runtime_error ("can not serialise variant of type none to info format"); + if (format==Format_Local) + throw std::runtime_error ("can not serialise variant of type none to local format"); + // nothing to do here for GMST format } else diff --git a/components/esm/variant.hpp b/components/esm/variant.hpp index d6c1a5489..5f179a7bd 100644 --- a/components/esm/variant.hpp +++ b/components/esm/variant.hpp @@ -33,7 +33,8 @@ namespace ESM { Format_Global, Format_Gmst, - Format_Info // also used for local variables in saved game files + Format_Info, + Format_Local // local script variables in save game files }; Variant(); diff --git a/components/esm/variantimp.cpp b/components/esm/variantimp.cpp index 1bacdc077..fd068fc19 100644 --- a/components/esm/variantimp.cpp +++ b/components/esm/variantimp.cpp @@ -81,6 +81,9 @@ void ESM::VariantStringData::read (ESMReader& esm, Variant::Format format, VarTy if (format==Variant::Format_Info) esm.fail ("info variables of type string not supported"); + if (format==Variant::Format_Local) + esm.fail ("local variables of type string not supported"); + // GMST mValue = esm.getHString(); } @@ -173,6 +176,21 @@ void ESM::VariantIntegerData::read (ESMReader& esm, Variant::Format format, VarT esm.getHT (mValue); } + else if (format==Variant::Format_Local) + { + if (type==VT_Short) + { + short value; + esm.getHT(value); + mValue = value; + } + else if (type==VT_Int) + { + esm.getHT(mValue); + } + else + esm.fail("unsupported local variable integer type"); + } } void ESM::VariantIntegerData::write (ESMWriter& esm, Variant::Format format, VarType type) const @@ -204,6 +222,15 @@ void ESM::VariantIntegerData::write (ESMWriter& esm, Variant::Format format, Var esm.writeHNT ("INTV", mValue); } + else if (format==Variant::Format_Local) + { + if (type==VT_Short) + esm.writeHNT ("STTV", (short)mValue); + else if (type == VT_Int) + esm.writeHNT ("INTV", mValue); + else + throw std::runtime_error("unsupported local variable integer type"); + } } bool ESM::VariantIntegerData::isEqual (const VariantDataBase& value) const @@ -252,7 +279,7 @@ void ESM::VariantFloatData::read (ESMReader& esm, Variant::Format format, VarTyp { esm.getHNT (mValue, "FLTV"); } - else if (format==Variant::Format_Gmst || format==Variant::Format_Info) + else if (format==Variant::Format_Gmst || format==Variant::Format_Info || format==Variant::Format_Local) { esm.getHT (mValue); } @@ -268,7 +295,7 @@ void ESM::VariantFloatData::write (ESMWriter& esm, Variant::Format format, VarTy esm.writeHNString ("FNAM", "f"); esm.writeHNT ("FLTV", mValue); } - else if (format==Variant::Format_Gmst || format==Variant::Format_Info) + else if (format==Variant::Format_Gmst || format==Variant::Format_Info || format==Variant::Format_Local) { esm.writeHNT ("FLTV", mValue); } @@ -277,4 +304,4 @@ void ESM::VariantFloatData::write (ESMWriter& esm, Variant::Format format, VarTy bool ESM::VariantFloatData::isEqual (const VariantDataBase& value) const { return dynamic_cast (value).mValue==mValue; -} \ No newline at end of file +} From 72f7c2e555222120b870765758ab41e0ff29245c Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 24 Jan 2015 16:26:43 +0100 Subject: [PATCH 0400/3725] Move weather reset to clear() method --- apps/openmw/mwworld/weather.cpp | 18 ++++++++++-------- apps/openmw/mwworld/weather.hpp | 2 ++ apps/openmw/mwworld/worldimp.cpp | 1 + 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 6532c5969..a74c24768 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -770,14 +770,6 @@ bool WeatherManager::readRecord(ESM::ESMReader& reader, uint32_t type) ESM::WeatherState state; state.load(reader); - // reset other temporary state, now that we loaded successfully - stopSounds(); // let's hope this never throws - mRegionOverrides.clear(); - mRegionMods.clear(); - mThunderFlash = 0.0; - mThunderChance = 0.0; - mThunderChanceNeeded = 50.0; - // swap in the loaded values now that we can't fail mHour = state.mHour; mWindSpeed = state.mWindSpeed; @@ -794,6 +786,16 @@ bool WeatherManager::readRecord(ESM::ESMReader& reader, uint32_t type) return false; } +void WeatherManager::clear() +{ + stopSounds(); + mRegionOverrides.clear(); + mRegionMods.clear(); + mThunderFlash = 0.0; + mThunderChance = 0.0; + mThunderChanceNeeded = 50.0; +} + void WeatherManager::switchToNextWeather(bool instantly) { MWBase::World* world = MWBase::Environment::get().getWorld(); diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index 830b5c376..a2e668159 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -201,6 +201,8 @@ namespace MWWorld bool readRecord(ESM::ESMReader& reader, uint32_t type); + void clear(); + private: float mHour; float mWindSpeed; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index ceac85bca..8bcfcb421 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -265,6 +265,7 @@ namespace MWWorld void World::clear() { + mWeatherManager->clear(); mRendering->clear(); mProjectileManager->clear(); From 33ce03dfc597dd4d2f08356bfb0f3fbf1364eb0c Mon Sep 17 00:00:00 2001 From: Nathan Aclander Date: Sat, 24 Jan 2015 17:17:05 -0800 Subject: [PATCH 0401/3725] Should be compared against uint only --- components/esm/esmcommon.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/esm/esmcommon.hpp b/components/esm/esmcommon.hpp index 1bdadead2..80706793a 100644 --- a/components/esm/esmcommon.hpp +++ b/components/esm/esmcommon.hpp @@ -40,8 +40,8 @@ union NAME_T } bool operator!=(const std::string &str) const { return !((*this)==str); } - bool operator==(int v) const { return v == val; } - bool operator!=(int v) const { return v != val; } + bool operator==(uint32_t v) const { return v == val; } + bool operator!=(uint32_t v) const { return v != val; } std::string toString() const { return std::string(name, strnlen(name, LEN)); } From f7f593b1436d59b41a52e6e0dbec934b9d8e92af Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 25 Jan 2015 18:30:33 +0100 Subject: [PATCH 0402/3725] updated credits file --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index d2c5cdc04..f261ea423 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -75,6 +75,7 @@ Programmers Michał Bień (Glorf) Miroslav Puda (pakanek) MiroslavR + naclander Narmo Nathan Jeffords (blunted2night) Nikolay Kasyanov (corristo) From b0b275a936a815de94eed2ee1391df2a6062137b Mon Sep 17 00:00:00 2001 From: dteviot Date: Mon, 26 Jan 2015 12:53:01 +1300 Subject: [PATCH 0403/3725] Fix for MSVC 2013 compiler issues. Fixes: C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\utility(199): error C2079: 'std::pair::second' uses undefined class 'boost::shared_ptr' Which cascades to 36 more errors. --- apps/essimporter/importer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/essimporter/importer.cpp b/apps/essimporter/importer.cpp index 73a12769a..10fad37b0 100644 --- a/apps/essimporter/importer.cpp +++ b/apps/essimporter/importer.cpp @@ -1,4 +1,5 @@ #include "importer.hpp" +#include #include From e02bab67ba67dffc133f0583cc0f593709af90c5 Mon Sep 17 00:00:00 2001 From: dteviot Date: Mon, 26 Jan 2015 13:17:16 +1300 Subject: [PATCH 0404/3725] Fixed MSVC warnings. warning C4099: 'ESM::ESMReader' : type name first seen using 'class' now seen using 'struct' warning C4099: 'ESM::CellId' : type name first seen using 'struct' now seen using 'class' --- apps/essimporter/importacdt.hpp | 2 +- apps/essimporter/importdial.hpp | 2 +- apps/essimporter/importinfo.hpp | 2 +- apps/essimporter/importjour.hpp | 2 +- apps/essimporter/importklst.hpp | 2 +- apps/essimporter/importques.hpp | 2 +- components/esm/loadcell.hpp | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/essimporter/importacdt.hpp b/apps/essimporter/importacdt.hpp index 4eb5edb73..53783a364 100644 --- a/apps/essimporter/importacdt.hpp +++ b/apps/essimporter/importacdt.hpp @@ -9,7 +9,7 @@ namespace ESM { - struct ESMReader; + class ESMReader; } namespace ESSImport diff --git a/apps/essimporter/importdial.hpp b/apps/essimporter/importdial.hpp index fe4b0c5b4..9a1e88233 100644 --- a/apps/essimporter/importdial.hpp +++ b/apps/essimporter/importdial.hpp @@ -2,7 +2,7 @@ #define OPENMW_ESSIMPORT_IMPORTDIAL_H namespace ESM { - struct ESMReader; + class ESMReader; } namespace ESSImport diff --git a/apps/essimporter/importinfo.hpp b/apps/essimporter/importinfo.hpp index 08f588f8d..f4d616786 100644 --- a/apps/essimporter/importinfo.hpp +++ b/apps/essimporter/importinfo.hpp @@ -5,7 +5,7 @@ namespace ESM { - struct ESMReader; + class ESMReader; } namespace ESSImport diff --git a/apps/essimporter/importjour.hpp b/apps/essimporter/importjour.hpp index fe8775a93..1b2d094f6 100644 --- a/apps/essimporter/importjour.hpp +++ b/apps/essimporter/importjour.hpp @@ -5,7 +5,7 @@ namespace ESM { - struct ESMReader; + class ESMReader; } namespace ESSImport diff --git a/apps/essimporter/importklst.hpp b/apps/essimporter/importklst.hpp index e333e7150..d07332600 100644 --- a/apps/essimporter/importklst.hpp +++ b/apps/essimporter/importklst.hpp @@ -6,7 +6,7 @@ namespace ESM { - struct ESMReader; + class ESMReader; } namespace ESSImport diff --git a/apps/essimporter/importques.hpp b/apps/essimporter/importques.hpp index d7e718b92..51fe22434 100644 --- a/apps/essimporter/importques.hpp +++ b/apps/essimporter/importques.hpp @@ -6,7 +6,7 @@ namespace ESM { - struct ESMReader; + class ESMReader; } namespace ESSImport diff --git a/components/esm/loadcell.hpp b/components/esm/loadcell.hpp index e1a6eee1a..4c2ac68dc 100644 --- a/components/esm/loadcell.hpp +++ b/components/esm/loadcell.hpp @@ -18,7 +18,7 @@ namespace ESM { class ESMReader; class ESMWriter; - class CellId; +struct CellId; /* Moved cell reference tracking object. This mainly stores the target cell of the reference, so we can easily know where it has been moved when another From f95743ccc3646aa22f36f250a75daeac14f0a6a6 Mon Sep 17 00:00:00 2001 From: dteviot Date: Mon, 26 Jan 2015 13:18:21 +1300 Subject: [PATCH 0405/3725] Fixed MSVC warning. warning C4305: 'return' : truncation from 'double' to 'float' --- components/esm/esmreader.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esm/esmreader.hpp b/components/esm/esmreader.hpp index e7721bb8f..ebbc935f6 100644 --- a/components/esm/esmreader.hpp +++ b/components/esm/esmreader.hpp @@ -32,7 +32,7 @@ public: int getVer() const { return mHeader.mData.version; } int getRecordCount() const { return mHeader.mData.records; } - float getFVer() const { if(mHeader.mData.version == VER_12) return 1.2; else return 1.3; } + float getFVer() const { return (mHeader.mData.version == VER_12) ? 1.2f : 1.3f; } const std::string getAuthor() const { return mHeader.mData.author.toString(); } const std::string getDesc() const { return mHeader.mData.desc.toString(); } const std::vector &getGameFiles() const { return mHeader.mMaster; } From 946dd16696761a8e87565ed1bd93826b05b0e6b8 Mon Sep 17 00:00:00 2001 From: dteviot Date: Mon, 26 Jan 2015 13:57:22 +1300 Subject: [PATCH 0406/3725] Fixed Windows warning. warning C4800: 'int' : forcing value to bool 'true' or 'false' (performance warning) --- apps/essimporter/converter.hpp | 2 +- components/esm/loadcell.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index 6f85b01cf..90b75fee1 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -263,7 +263,7 @@ public: for (std::vector::const_iterator it = pcdt.mFactions.begin(); it != pcdt.mFactions.end(); ++it) { ESM::NpcStats::Faction faction; - faction.mExpelled = it->mFlags & 0x2; + faction.mExpelled = (it->mFlags & 0x2) != 0; faction.mRank = it->mRank; faction.mReputation = it->mReputation; mContext->mPlayer.mObject.mNpcStats.mFactions[it->mFactionName.toString()] = faction; diff --git a/components/esm/loadcell.hpp b/components/esm/loadcell.hpp index 4c2ac68dc..d982bbfd4 100644 --- a/components/esm/loadcell.hpp +++ b/components/esm/loadcell.hpp @@ -137,7 +137,7 @@ struct Cell bool hasWater() const { - return (mData.mFlags&HasWater); + return (mData.mFlags&HasWater) != 0; } // Restore the given reader to the stored position. Will try to open From 70e4f821ba394840554199f1f84066a8711e454a Mon Sep 17 00:00:00 2001 From: dteviot Date: Mon, 26 Jan 2015 13:58:13 +1300 Subject: [PATCH 0407/3725] Fix Windows warning warning C4244: 'initializing' : conversion from 'float' to 'int', possible loss of data --- apps/essimporter/importer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/essimporter/importer.cpp b/apps/essimporter/importer.cpp index 10fad37b0..8f6563dee 100644 --- a/apps/essimporter/importer.cpp +++ b/apps/essimporter/importer.cpp @@ -342,8 +342,8 @@ namespace ESSImport { // exterior cell -> determine cell coordinates based on position const int cellSize = 8192; - int cellX = std::floor(context.mPlayer.mObject.mPosition.pos[0]/cellSize); - int cellY = std::floor(context.mPlayer.mObject.mPosition.pos[1]/cellSize); + int cellX = static_cast(std::floor(context.mPlayer.mObject.mPosition.pos[0]/cellSize)); + int cellY = static_cast(std::floor(context.mPlayer.mObject.mPosition.pos[1] / cellSize)); context.mPlayer.mCellId.mIndex.mX = cellX; context.mPlayer.mCellId.mIndex.mY = cellY; } From 1410819e20308b09bdab02c04308ea12c1fdfcb6 Mon Sep 17 00:00:00 2001 From: Jordan Ayers Date: Sun, 25 Jan 2015 22:23:38 -0600 Subject: [PATCH 0408/3725] Dialog fix for line breaks in the middle of words. Issue 1049 Adjust the TypesetBookImpl::Typesetter to not assume a word break at the end of write() calls. A word break is assumed if any of the other content insertion methods are used (section break, add/select content, etc). --- apps/openmw/mwgui/bookpage.cpp | 88 ++++++++++++++++++++++++++++------ 1 file changed, 74 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwgui/bookpage.cpp b/apps/openmw/mwgui/bookpage.cpp index 3b1d40fc3..c9cfc8c2c 100644 --- a/apps/openmw/mwgui/bookpage.cpp +++ b/apps/openmw/mwgui/bookpage.cpp @@ -195,8 +195,20 @@ struct TypesetBookImpl : TypesetBook struct TypesetBookImpl::Typesetter : BookTypesetter { + struct PartialText { + StyleImpl *mStyle; + Utf8Stream::Point mBegin; + Utf8Stream::Point mEnd; + int mWidth; + + PartialText( StyleImpl *style, Utf8Stream::Point begin, Utf8Stream::Point end, int width) : + mStyle(style), mBegin(begin), mEnd(end), mWidth(width) + {} + }; + typedef TypesetBookImpl Book; typedef boost::shared_ptr BookPtr; + typedef std::vector::const_iterator PartialTextConstIterator; int mPageWidth; int mPageHeight; @@ -207,6 +219,8 @@ struct TypesetBookImpl::Typesetter : BookTypesetter Run * mRun; std::vector mSectionAlignment; + std::vector mPartialWhitespace; + std::vector mPartialWord; Book::Content const * mCurrentContent; Alignment mCurrentAlignment; @@ -273,6 +287,8 @@ struct TypesetBookImpl::Typesetter : BookTypesetter intptr_t addContent (Utf8Span text, bool select) { + add_partial_text(); + Contents::iterator i = mBook->mContents.insert (mBook->mContents.end (), Content (text.first, text.second)); if (select) @@ -283,6 +299,8 @@ struct TypesetBookImpl::Typesetter : BookTypesetter void selectContent (intptr_t contentHandle) { + add_partial_text(); + mCurrentContent = reinterpret_cast (contentHandle); } @@ -302,12 +320,16 @@ struct TypesetBookImpl::Typesetter : BookTypesetter { assert (margin == 0); //TODO: figure out proper behavior here... + add_partial_text(); + mRun = NULL; mLine = NULL; } void sectionBreak (float margin) { + add_partial_text(); + if (mBook->mSections.size () > 0) { mRun = NULL; @@ -321,6 +343,8 @@ struct TypesetBookImpl::Typesetter : BookTypesetter void setSectionAlignment (Alignment sectionAlignment) { + add_partial_text(); + if (mSection != NULL) mSectionAlignment.back () = sectionAlignment; mCurrentAlignment = sectionAlignment; @@ -331,6 +355,8 @@ struct TypesetBookImpl::Typesetter : BookTypesetter int curPageStart = 0; int curPageStop = 0; + add_partial_text(); + std::vector ::iterator sa = mSectionAlignment.begin (); for (Sections::iterator i = mBook->mSections.begin (); i != mBook->mSections.end (); ++i, ++sa) { @@ -415,23 +441,23 @@ struct TypesetBookImpl::Typesetter : BookTypesetter void writeImpl (StyleImpl * style, Utf8Stream::Point _begin, Utf8Stream::Point _end) { - int line_height = style->mFont->getDefaultHeight (); - Utf8Stream stream (_begin, _end); while (!stream.eof ()) { if (ucsLineBreak (stream.peek ())) { + add_partial_text(); stream.consume (); mLine = NULL, mRun = NULL; continue; } + if (ucsBreakingSpace (stream.peek ()) && !mPartialWord.empty()) + add_partial_text(); + int word_width = 0; - int word_height = 0; int space_width = 0; - int character_count = 0; Utf8Stream::Point lead = stream.current (); @@ -450,8 +476,6 @@ struct TypesetBookImpl::Typesetter : BookTypesetter MyGUI::GlyphInfo* gi = style->mFont->getGlyphInfo (stream.peek ()); if (gi) word_width += gi->advance + gi->bearingX; - word_height = line_height; - ++character_count; stream.consume (); } @@ -460,21 +484,57 @@ struct TypesetBookImpl::Typesetter : BookTypesetter if (lead == extent) break; - int left = mLine ? mLine->mRect.right : 0; + if ( lead != origin ) + mPartialWhitespace.push_back (PartialText (style, lead, origin, space_width)); + if ( origin != extent ) + mPartialWord.push_back (PartialText (style, origin, extent, word_width)); + } + } - if (left + space_width + word_width > mPageWidth) - { - mLine = NULL, mRun = NULL; + void add_partial_text () + { + if (mPartialWhitespace.empty() && mPartialWord.empty()) + return; - append_run (style, origin, extent, extent - origin, word_width, mBook->mRect.bottom + word_height); - } - else + int space_width = 0; + int word_width = 0; + + for (PartialTextConstIterator i = mPartialWhitespace.begin (); i != mPartialWhitespace.end (); ++i) + space_width += i->mWidth; + for (PartialTextConstIterator i = mPartialWord.begin (); i != mPartialWord.end (); ++i) + word_width += i->mWidth; + + int left = mLine ? mLine->mRect.right : 0; + + if (left + space_width + word_width > mPageWidth) + { + mLine = NULL, mRun = NULL, left = 0; + } + else + { + for (PartialTextConstIterator i = mPartialWhitespace.begin (); i != mPartialWhitespace.end (); ++i) { int top = mLine ? mLine->mRect.top : mBook->mRect.bottom; + int line_height = i->mStyle->mFont->getDefaultHeight (); + + append_run ( i->mStyle, i->mBegin, i->mEnd, 0, left + i->mWidth, top + line_height); - append_run (style, lead, extent, extent - origin, left + space_width + word_width, top + word_height); + left = mLine->mRect.right; } } + + for (PartialTextConstIterator i = mPartialWord.begin (); i != mPartialWord.end (); ++i) + { + int top = mLine ? mLine->mRect.top : mBook->mRect.bottom; + int line_height = i->mStyle->mFont->getDefaultHeight (); + + append_run (i->mStyle, i->mBegin, i->mEnd, i->mEnd - i->mBegin, left + i->mWidth, top + line_height); + + left = mLine->mRect.right; + } + + mPartialWhitespace.clear(); + mPartialWord.clear(); } void append_run (StyleImpl * style, Utf8Stream::Point begin, Utf8Stream::Point end, int pc, int right, int bottom) From e298589e7fc3641abd5a20b2da3fd6400d272d5c Mon Sep 17 00:00:00 2001 From: dteviot Date: Mon, 26 Jan 2015 18:46:18 +1300 Subject: [PATCH 0409/3725] Reorganised DataFilesPage.cpp code. Removed some recursive calling of saveSettings() and loadSettings(). --- apps/launcher/datafilespage.cpp | 48 +++++++++++++++------------------ apps/launcher/datafilespage.hpp | 1 + 2 files changed, 22 insertions(+), 27 deletions(-) diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index 245665421..ff1364b08 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -69,19 +69,6 @@ void Launcher::DataFilesPage::buildView() bool Launcher::DataFilesPage::loadSettings() { - QStringList paths = mGameSettings.getDataDirs(); - - foreach (const QString &path, paths) - mSelector->addFiles(path); - - mDataLocal = mGameSettings.getDataLocal(); - - if (!mDataLocal.isEmpty()) - mSelector->addFiles(mDataLocal); - - paths.insert (0, mDataLocal); - PathIterator pathIterator (paths); - QStringList profiles = mLauncherSettings.getContentLists(); QString currentProfile = mLauncherSettings.getCurrentContentListName(); @@ -94,11 +81,27 @@ bool Launcher::DataFilesPage::loadSettings() if (!currentProfile.isEmpty()) addProfile(currentProfile, true); - mSelector->setProfileContent(filesInProfile(currentProfile, pathIterator)); - return true; } +void Launcher::DataFilesPage::populateFileViews(const QString& contentModelName) +{ + QStringList paths = mGameSettings.getDataDirs(); + + foreach(const QString &path, paths) + mSelector->addFiles(path); + + mDataLocal = mGameSettings.getDataLocal(); + + if (!mDataLocal.isEmpty()) + mSelector->addFiles(mDataLocal); + + paths.insert(0, mDataLocal); + PathIterator pathIterator(paths); + + mSelector->setProfileContent(filesInProfile(contentModelName, pathIterator)); +} + QStringList Launcher::DataFilesPage::filesInProfile(const QString& profileName, PathIterator& pathIterator) { QStringList files = mLauncherSettings.getContentListFiles(profileName); @@ -175,7 +178,7 @@ void Launcher::DataFilesPage::setProfile (const QString &previous, const QString ui.profilesComboBox->setCurrentProfile (ui.profilesComboBox->findText (current)); - loadSettings(); + populateFileViews(current); checkForDefaultProfile(); } @@ -229,13 +232,6 @@ void Launcher::DataFilesPage::on_newProfileAction_triggered() mLauncherSettings.setCurrentContentListName(profile); addProfile(profile, true); - mSelector->clearCheckStates(); - - mSelector->setGameFile(); - - saveSettings(); - - emit signalProfileChanged (ui.profilesComboBox->findText(profile)); } void Launcher::DataFilesPage::addProfile (const QString &profile, bool setAsCurrent) @@ -262,15 +258,13 @@ void Launcher::DataFilesPage::on_deleteProfileAction_triggered() // this should work since the Default profile can't be deleted and is always index 0 int next = ui.profilesComboBox->currentIndex()-1; + + // changing the profile forces a reload of plugin file views. ui.profilesComboBox->setCurrentIndex(next); removeProfile(profile); ui.profilesComboBox->removeItem(ui.profilesComboBox->findText(profile)); - saveSettings(); - - loadSettings(); - checkForDefaultProfile(); } diff --git a/apps/launcher/datafilespage.hpp b/apps/launcher/datafilespage.hpp index c2fc22461..73b840c5c 100644 --- a/apps/launcher/datafilespage.hpp +++ b/apps/launcher/datafilespage.hpp @@ -82,6 +82,7 @@ namespace Launcher bool showDeleteMessageBox (const QString &text); void addProfile (const QString &profile, bool setAsCurrent); void checkForDefaultProfile(); + void populateFileViews(const QString& contentModelName); class PathIterator { From 697ab16ec5b3ed0502e47b71ea7aa7a883320bd8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 27 Jan 2015 19:00:26 +0100 Subject: [PATCH 0410/3725] Fix for coverity defects --- apps/openmw/mwdialogue/keywordsearch.hpp | 2 +- apps/openmw/mwworld/esmstore.cpp | 2 +- apps/wizard/unshield/unshieldworker.cpp | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwdialogue/keywordsearch.hpp b/apps/openmw/mwdialogue/keywordsearch.hpp index 0bb3616d9..c4e1d7553 100644 --- a/apps/openmw/mwdialogue/keywordsearch.hpp +++ b/apps/openmw/mwdialogue/keywordsearch.hpp @@ -161,7 +161,7 @@ public: while (matches.size()) { int longestKeywordSize = 0; - typename std::vector::iterator longestKeyword; + typename std::vector::iterator longestKeyword = matches.begin(); for (typename std::vector::iterator it = matches.begin(); it != matches.end(); ++it) { int size = it->mEnd - it->mBeg; diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index caa88d751..12e02f938 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -82,7 +82,7 @@ void ESMStore::load(ESM::ESMReader &esm, Loading::Listener* listener) } else if (n.val == ESM::REC_SKIL) { mSkills.load (esm); } - else if (n.val==ESM::REC_FILT || ESM::REC_DBGP) + else if (n.val==ESM::REC_FILT || n.val == ESM::REC_DBGP) { // ignore project file only records esm.skipRecord(); diff --git a/apps/wizard/unshield/unshieldworker.cpp b/apps/wizard/unshield/unshieldworker.cpp index 5fa043347..11e090ed1 100644 --- a/apps/wizard/unshield/unshieldworker.cpp +++ b/apps/wizard/unshield/unshieldworker.cpp @@ -739,7 +739,8 @@ bool Wizard::UnshieldWorker::extractFile(Unshield *unshield, const QString &dest // Ensure the target path exists QDir dir; - dir.mkpath(path); + if (!dir.mkpath(path)) + return false; QString fileName(path); fileName.append(QString::fromUtf8(unshield_file_name(unshield, index))); From 62acb0373519d310799967ce7b0f556e27ddd1c4 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Tue, 27 Jan 2015 21:07:26 +0100 Subject: [PATCH 0411/3725] More Ogre + recent Boost build fixes --- apps/opencs/view/render/cell.hpp | 2 ++ apps/opencs/view/render/object.hpp | 2 ++ 2 files changed, 4 insertions(+) diff --git a/apps/opencs/view/render/cell.hpp b/apps/opencs/view/render/cell.hpp index 9f38b0d9f..73d794948 100644 --- a/apps/opencs/view/render/cell.hpp +++ b/apps/opencs/view/render/cell.hpp @@ -9,7 +9,9 @@ #include +#ifndef Q_MOC_RUN #include +#endif #include "object.hpp" diff --git a/apps/opencs/view/render/object.hpp b/apps/opencs/view/render/object.hpp index 05a32fbea..3ed4fa793 100644 --- a/apps/opencs/view/render/object.hpp +++ b/apps/opencs/view/render/object.hpp @@ -3,7 +3,9 @@ #include +#ifndef Q_MOC_RUN #include +#endif class QModelIndex; From 9b3728d87856d1c515882c8ccd6bd08e6a96e5d7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 24 Jan 2015 17:15:25 +0100 Subject: [PATCH 0412/3725] ESSImport: convert weather state --- apps/essimporter/converter.hpp | 63 +++++++++++++++++++++++++++++++-- apps/essimporter/importgame.cpp | 3 ++ apps/essimporter/importgame.hpp | 2 +- 3 files changed, 65 insertions(+), 3 deletions(-) diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index 90b75fee1..28d904d3c 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -13,6 +13,7 @@ #include #include #include +#include #include "importcrec.hpp" #include "importcntc.hpp" @@ -455,11 +456,69 @@ public: class ConvertGAME : public Converter { public: + ConvertGAME() : mHasGame(false) {} + + std::string toString(int weatherId) + { + switch (weatherId) + { + case 0: + return "clear"; + case 1: + return "cloudy"; + case 2: + return "foggy"; + case 3: + return "overcast"; + case 4: + return "rain"; + case 5: + return "thunderstorm"; + case 6: + return "ashstorm"; + case 7: + return "blight"; + case 8: + return "snow"; + case 9: + return "blizzard"; + case -1: + return ""; + default: + { + std::stringstream error; + error << "unknown weather id: " << weatherId; + throw std::runtime_error(error.str()); + } + } + } + virtual void read(ESM::ESMReader &esm) { - GAME game; - game.load(esm); + mGame.load(esm); + mHasGame = true; } + + virtual void write(ESM::ESMWriter &esm) + { + if (!mHasGame) + return; + esm.startRecord(ESM::REC_WTHR); + ESM::WeatherState weather; + weather.mCurrentWeather = toString(mGame.mGMDT.mCurrentWeather); + weather.mNextWeather = toString(mGame.mGMDT.mNextWeather); + weather.mRemainingTransitionTime = mGame.mGMDT.mWeatherTransition/100.f*(0.015*24*3600); + weather.mHour = mContext->mHour; + weather.mWindSpeed = 0.f; + weather.mTimePassed = 0.0; + weather.mFirstUpdate = false; + weather.save(esm); + esm.endRecord(ESM::REC_WTHR); + } + +private: + bool mHasGame; + GAME mGame; }; /// Running global script diff --git a/apps/essimporter/importgame.cpp b/apps/essimporter/importgame.cpp index 0b3a4f1a7..c9da71e0c 100644 --- a/apps/essimporter/importgame.cpp +++ b/apps/essimporter/importgame.cpp @@ -8,6 +8,9 @@ namespace ESSImport void GAME::load(ESM::ESMReader &esm) { esm.getHNT(mGMDT, "GMDT"); + mGMDT.mWeatherTransition &= (0x000000ff); + mGMDT.mSecundaPhase &= (0x000000ff); + mGMDT.mMasserPhase &= (0x000000ff); } } diff --git a/apps/essimporter/importgame.hpp b/apps/essimporter/importgame.hpp index 7bb814320..fca7d72a0 100644 --- a/apps/essimporter/importgame.hpp +++ b/apps/essimporter/importgame.hpp @@ -20,7 +20,7 @@ namespace ESSImport int mCurrentWeather, mNextWeather; int mWeatherTransition; // 0-100 transition between weathers, top 3 bytes may be garbage float mTimeOfNextTransition; // weather changes when gamehour == timeOfNextTransition - int masserPhase, secundaPhase; // top 3 bytes may be garbage + int mMasserPhase, mSecundaPhase; // top 3 bytes may be garbage }; GMDT mGMDT; From 60f722b0a9bca552475e2d721c23287e5457994a Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 24 Jan 2015 17:28:05 +0100 Subject: [PATCH 0413/3725] Treat the first mouse motion event as non-relative This fixes incorrect starting camera orientation when using --skip-menu or --load-savegame. --- extern/sdl4ogre/sdlinputwrapper.cpp | 10 +++++++++- extern/sdl4ogre/sdlinputwrapper.hpp | 2 ++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/extern/sdl4ogre/sdlinputwrapper.cpp b/extern/sdl4ogre/sdlinputwrapper.cpp index 0c29be939..a6c7d3e5c 100644 --- a/extern/sdl4ogre/sdlinputwrapper.cpp +++ b/extern/sdl4ogre/sdlinputwrapper.cpp @@ -30,7 +30,8 @@ namespace SFO mWantMouseVisible(false), mAllowGrab(grab), mWarpX(0), - mWarpY(0) + mWarpY(0), + mFirstMouseMove(true) { _setupOISKeys(); } @@ -316,6 +317,13 @@ namespace SFO pack_evt.y = mMouseY = evt.motion.y; pack_evt.xrel = evt.motion.xrel; pack_evt.yrel = evt.motion.yrel; + if (mFirstMouseMove) + { + // first event should be treated as non-relative, since there's no point of reference + // SDL then (incorrectly) uses (0,0) as point of reference, on Linux at least... + pack_evt.xrel = pack_evt.yrel = 0; + mFirstMouseMove = false; + } } else if(evt.type == SDL_MOUSEWHEEL) { diff --git a/extern/sdl4ogre/sdlinputwrapper.hpp b/extern/sdl4ogre/sdlinputwrapper.hpp index 339e99de1..af16ab68d 100644 --- a/extern/sdl4ogre/sdlinputwrapper.hpp +++ b/extern/sdl4ogre/sdlinputwrapper.hpp @@ -71,6 +71,8 @@ namespace SFO bool mGrabPointer; bool mMouseRelative; + bool mFirstMouseMove; + Sint32 mMouseZ; Sint32 mMouseX; Sint32 mMouseY; From 4921c6ef9eb5b0ee52097cd6bca40b3a0634d391 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 24 Jan 2015 19:26:31 +0100 Subject: [PATCH 0414/3725] Split window caption bars so that the caption can be transparent (Fixes #531) Fix transparent window background not applying to the header bar (Fixes #2294) --- apps/openmw/mwgui/container.cpp | 2 - apps/openmw/mwgui/statswindow.cpp | 1 - apps/openmw/mwgui/tradewindow.cpp | 2 - components/CMakeLists.txt | 2 +- components/widgets/widgets.cpp | 2 + components/widgets/windowcaption.cpp | 58 ++++++++++++++++++++++++++++ components/widgets/windowcaption.hpp | 32 +++++++++++++++ files/mygui/openmw_hud_box.skin.xml | 16 ++++---- files/mygui/openmw_windows.skin.xml | 37 ++++++------------ libs/openengine/gui/layout.cpp | 22 ----------- libs/openengine/gui/layout.hpp | 4 -- 11 files changed, 112 insertions(+), 66 deletions(-) create mode 100644 components/widgets/windowcaption.cpp create mode 100644 components/widgets/windowcaption.hpp diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 49e641aed..53b1e679a 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -154,8 +154,6 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mCloseButton); - // Careful here. setTitle may cause size updates, causing itemview redraw, so make sure to do it last - // or we end up using a possibly invalid model. setTitle(container.getClass().getName(container)); } diff --git a/apps/openmw/mwgui/statswindow.cpp b/apps/openmw/mwgui/statswindow.cpp index 19f9c749c..a407aedc7 100644 --- a/apps/openmw/mwgui/statswindow.cpp +++ b/apps/openmw/mwgui/statswindow.cpp @@ -108,7 +108,6 @@ namespace MWGui void StatsWindow::setPlayerName(const std::string& playerName) { mMainWidget->castType()->setCaption(playerName); - adjustWindowCaption(); } void StatsWindow::setValue (const std::string& id, const MWMechanics::AttributeValue& value) diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index bafa89d5b..fab7c63a6 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -133,8 +133,6 @@ namespace MWGui updateLabels(); - // Careful here. setTitle may cause size updates, causing itemview redraw, so make sure to do it last - // or we end up using a possibly invalid model. setTitle(actor.getClass().getName(actor)); onFilterChanged(mFilterAll); diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index a0500127c..2126c5ca5 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -113,7 +113,7 @@ add_component_dir (ogreinit ) add_component_dir (widgets - box imagebutton tags list numericeditbox sharedstatebutton widgets + box imagebutton tags list numericeditbox sharedstatebutton windowcaption widgets ) add_component_dir (fontloader diff --git a/components/widgets/widgets.cpp b/components/widgets/widgets.cpp index 82839c6c9..3b6361cf8 100644 --- a/components/widgets/widgets.cpp +++ b/components/widgets/widgets.cpp @@ -7,6 +7,7 @@ #include "box.hpp" #include "imagebutton.hpp" #include "sharedstatebutton.hpp" +#include "windowcaption.hpp" namespace Gui { @@ -22,6 +23,7 @@ namespace Gui MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); + MyGUI::FactoryManager::getInstance().registerFactory("Widget"); } } diff --git a/components/widgets/windowcaption.cpp b/components/widgets/windowcaption.cpp new file mode 100644 index 000000000..bcb0a7c12 --- /dev/null +++ b/components/widgets/windowcaption.cpp @@ -0,0 +1,58 @@ +#include "windowcaption.hpp" + +#include + +namespace Gui +{ + + WindowCaption::WindowCaption() + : mLeft(NULL) + , mRight(NULL) + { + } + + void WindowCaption::initialiseOverride() + { + Base::initialiseOverride(); + + assignWidget(mLeft, "Left"); + assignWidget(mRight, "Right"); + + assignWidget(mClient, "Client"); + if (!mClient) + throw std::runtime_error("WindowCaption needs an EditBox Client widget in its skin"); + } + + void WindowCaption::setCaption(const MyGUI::UString &_value) + { + EditBox::setCaption(_value); + align(); + } + + void WindowCaption::setSize(const MyGUI::IntSize& _value) + { + Base::setSize(_value); + align(); + } + + void WindowCaption::setCoord(const MyGUI::IntCoord& _value) + { + Base::setCoord(_value); + align(); + } + + void WindowCaption::align() + { + MyGUI::IntSize textSize = getTextSize(); + MyGUI::Widget* caption = mClient; + caption->setSize(textSize.width + 24, caption->getHeight()); + + int barwidth = (getWidth()-caption->getWidth())/2; + caption->setPosition(barwidth, caption->getTop()); + if (mLeft) + mLeft->setCoord(0, mLeft->getTop(), barwidth, mLeft->getHeight()); + if (mRight) + mRight->setCoord(barwidth + caption->getWidth(), mRight->getTop(), barwidth, mRight->getHeight()); + } + +} diff --git a/components/widgets/windowcaption.hpp b/components/widgets/windowcaption.hpp new file mode 100644 index 000000000..bdd4c0a2e --- /dev/null +++ b/components/widgets/windowcaption.hpp @@ -0,0 +1,32 @@ +#ifndef OPENMW_WIDGETS_WINDOWCAPTION_H +#define OPENMW_WIDGETS_WINDOWCAPTION_H + +#include + +namespace Gui +{ + + /// Window caption that automatically adjusts "Left" and "Right" widgets in its skin + /// based on the text size of the caption in the middle + class WindowCaption : public MyGUI::EditBox + { + MYGUI_RTTI_DERIVED(WindowCaption) + public: + WindowCaption(); + + virtual void setCaption(const MyGUI::UString &_value); + virtual void initialiseOverride(); + + virtual void setSize(const MyGUI::IntSize& _value); + virtual void setCoord(const MyGUI::IntCoord& _value); + + private: + MyGUI::Widget* mLeft; + MyGUI::Widget* mRight; + + void align(); + }; + +} + +#endif diff --git a/files/mygui/openmw_hud_box.skin.xml b/files/mygui/openmw_hud_box.skin.xml index e7457e7d2..4e6349768 100644 --- a/files/mygui/openmw_hud_box.skin.xml +++ b/files/mygui/openmw_hud_box.skin.xml @@ -6,13 +6,13 @@ - + - + - + - + @@ -22,13 +22,13 @@ - + - + - + - + diff --git a/files/mygui/openmw_windows.skin.xml b/files/mygui/openmw_windows.skin.xml index d01bd8ef2..57d50fe74 100644 --- a/files/mygui/openmw_windows.skin.xml +++ b/files/mygui/openmw_windows.skin.xml @@ -395,17 +395,9 @@ - - - - - - - - - - - + + + @@ -538,12 +531,7 @@ - - - - - - + @@ -695,7 +684,8 @@ - + + @@ -814,12 +804,7 @@ - - - - - - + - + + + + + + + + + + + + + + diff --git a/files/mygui/openmw_windows.skin.xml b/files/mygui/openmw_windows.skin.xml index ebbc77bef..2854401c8 100644 --- a/files/mygui/openmw_windows.skin.xml +++ b/files/mygui/openmw_windows.skin.xml @@ -804,7 +804,7 @@ - +
+
diff --git a/files/mygui/openmw_trainingwindow.layout b/files/mygui/openmw_trainingwindow.layout index c58bd0ab3..d6cea8727 100644 --- a/files/mygui/openmw_trainingwindow.layout +++ b/files/mygui/openmw_trainingwindow.layout @@ -1,26 +1,22 @@ - + + + + - - - - - + + - - - - - + - + diff --git a/files/mygui/openmw_travel_window.layout b/files/mygui/openmw_travel_window.layout index 30b470e08..4b383ee7c 100644 --- a/files/mygui/openmw_travel_window.layout +++ b/files/mygui/openmw_travel_window.layout @@ -1,31 +1,28 @@ - + + + - - - + + - - - - + - - - + + + - - - + + - + From 0557d45bd156844772a5be5cdc602cdf22781eb5 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 3 Feb 2015 13:18:03 +0100 Subject: [PATCH 0480/3725] renamed opencs into openmw-cs --- CMakeLists.txt | 14 +++++++------- apps/opencs/CMakeLists.txt | 14 +++++++------- apps/opencs/editor.cpp | 4 ++-- apps/opencs/main.cpp | 2 +- files/mac/{opencs.icns => openmw-cs.icns} | Bin files/opencs/{opencs.png => openmw-cs.png} | Bin files/opencs/resources.qrc | 2 +- files/{opencs.desktop => openmw-cs.desktop} | 6 +++--- files/windows/opencs.rc | 2 +- files/windows/{opencs.ico => openmw-cs.ico} | Bin 10 files changed, 22 insertions(+), 22 deletions(-) rename files/mac/{opencs.icns => openmw-cs.icns} (100%) rename files/opencs/{opencs.png => openmw-cs.png} (100%) rename files/{opencs.desktop => openmw-cs.desktop} (83%) rename files/windows/{opencs.ico => openmw-cs.ico} (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index f31603460..019d53c4e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -373,8 +373,8 @@ if (NOT WIN32 AND NOT APPLE) "${OpenMW_BINARY_DIR}/openmw.desktop") configure_file(${OpenMW_SOURCE_DIR}/files/openmw-mimeinfo.xml "${OpenMW_BINARY_DIR}/openmw-mimeinfo.xml") - configure_file(${OpenMW_SOURCE_DIR}/files/opencs.desktop - "${OpenMW_BINARY_DIR}/opencs.desktop") + configure_file(${OpenMW_SOURCE_DIR}/files/openmw-cs.desktop + "${OpenMW_BINARY_DIR}/openmw-cs.desktop") endif() # Compiler settings @@ -423,7 +423,7 @@ IF(NOT WIN32 AND NOT APPLE) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/openmw-essimporter" DESTINATION "${BINDIR}" ) ENDIF(BUILD_ESSIMPORTER) IF(BUILD_OPENCS) - INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/opencs" DESTINATION "${BINDIR}" ) + INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/openmw-cs" DESTINATION "${BINDIR}" ) ENDIF(BUILD_OPENCS) IF(BUILD_NIFTEST) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/niftest" DESTINATION "${BINDIR}" ) @@ -444,8 +444,8 @@ IF(NOT WIN32 AND NOT APPLE) INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw-mimeinfo.xml" DESTINATION "${DATAROOTDIR}/mime/packages" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") INSTALL(FILES "${OpenMW_SOURCE_DIR}/files/launcher/images/openmw.png" DESTINATION "${ICONDIR}" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") IF(BUILD_OPENCS) - INSTALL(FILES "${OpenMW_BINARY_DIR}/opencs.desktop" DESTINATION "${DATAROOTDIR}/applications" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "opencs") - INSTALL(FILES "${OpenMW_SOURCE_DIR}/files/opencs/opencs.png" DESTINATION "${ICONDIR}" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "opencs") + INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw-cs.desktop" DESTINATION "${DATAROOTDIR}/applications" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "opencs") + INSTALL(FILES "${OpenMW_SOURCE_DIR}/files/opencs/openmw-cs.png" DESTINATION "${ICONDIR}" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "opencs") ENDIF(BUILD_OPENCS) # Install global configuration files @@ -485,7 +485,7 @@ if(WIN32) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/openmw-essimporter.exe" DESTINATION ".") ENDIF(BUILD_ESSIMPORTER) IF(BUILD_OPENCS) - INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/opencs.exe" DESTINATION ".") + INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/openmw-cs.exe" DESTINATION ".") INSTALL(FILES "${OpenMW_BINARY_DIR}/opencs.ini" DESTINATION ".") ENDIF(BUILD_OPENCS) IF(BUILD_WIZARD) @@ -509,7 +509,7 @@ if(WIN32) SET(CPACK_PACKAGE_EXECUTABLES "${CPACK_PACKAGE_EXECUTABLES};openmw-launcher;OpenMW Launcher") ENDIF(BUILD_LAUNCHER) IF(BUILD_OPENCS) - SET(CPACK_PACKAGE_EXECUTABLES "${CPACK_PACKAGE_EXECUTABLES};opencs;OpenMW Construction Set") + SET(CPACK_PACKAGE_EXECUTABLES "${CPACK_PACKAGE_EXECUTABLES};openmw-cs;OpenMW Construction Set") ENDIF(BUILD_OPENCS) IF(BUILD_WIZARD) SET(CPACK_PACKAGE_EXECUTABLES "${CPACK_PACKAGE_EXECUTABLES};openmw-wizard;OpenMW Wizard") diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 468e172cd..be30431df 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -146,7 +146,7 @@ set (OPENCS_UI ${CMAKE_SOURCE_DIR}/files/ui/filedialog.ui ) -source_group (opencs FILES ${OPENCS_SRC} ${OPENCS_HDR}) +source_group (openmw-cs FILES ${OPENCS_SRC} ${OPENCS_HDR}) if(WIN32) set(QT_USE_QTMAIN TRUE) @@ -169,12 +169,12 @@ qt4_add_resources(OPENCS_RES_SRC ${OPENCS_RES}) include_directories(${CMAKE_CURRENT_BINARY_DIR} ${BULLET_INCLUDE_DIRS}) if(APPLE) - set (OPENCS_MAC_ICON ${CMAKE_SOURCE_DIR}/files/mac/opencs.icns) + set (OPENCS_MAC_ICON ${CMAKE_SOURCE_DIR}/files/mac/openmw-cs.icns) else() set (OPENCS_MAC_ICON "") endif(APPLE) -add_executable(opencs +add_executable(openmw-cs MACOSX_BUNDLE ${OENGINE_BULLET} ${OPENCS_SRC} @@ -187,8 +187,8 @@ add_executable(opencs if(APPLE) set_target_properties(opencs PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${OpenMW_BINARY_DIR}" - OUTPUT_NAME "OpenCS" - MACOSX_BUNDLE_ICON_FILE "opencs.icns" + OUTPUT_NAME "OpenMW-CS" + MACOSX_BUNDLE_ICON_FILE "openmw-cs.icns" MACOSX_BUNDLE_BUNDLE_NAME "OpenCS" MACOSX_BUNDLE_GUI_IDENTIFIER "org.openmw.opencs" MACOSX_BUNDLE_SHORT_VERSION_STRING ${OPENMW_VERSION} @@ -199,7 +199,7 @@ if(APPLE) MACOSX_PACKAGE_LOCATION Resources) endif(APPLE) -target_link_libraries(opencs +target_link_libraries(openmw-cs ${OGRE_LIBRARIES} ${OGRE_Overlay_LIBRARIES} ${OGRE_STATIC_PLUGINS} @@ -211,5 +211,5 @@ target_link_libraries(opencs ) if(APPLE) - INSTALL(TARGETS opencs BUNDLE DESTINATION OpenMW COMPONENT BUNDLE) + INSTALL(TARGETS opencs BUNDLE DESTINATION OpenMW-CS COMPONENT BUNDLE) endif() diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 58614ec5f..1d31c8396 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -96,7 +96,7 @@ void CS::Editor::setupDataFiles (const Files::PathContainer& dataDirs) std::pair > CS::Editor::readConfig() { boost::program_options::variables_map variables; - boost::program_options::options_description desc("Syntax: opencs \nAllowed options"); + boost::program_options::options_description desc("Syntax: openmw-cs \nAllowed options"); desc.add_options() ("data", boost::program_options::value()->default_value(Files::PathContainer(), "data")->multitoken()->composing()) @@ -249,7 +249,7 @@ bool CS::Editor::makeIPCServer() try { mPid = boost::filesystem::temp_directory_path(); - mPid /= "opencs.pid"; + mPid /= "openmw-cs.pid"; bool pidExists = boost::filesystem::exists(mPid); mPidFile.open(mPid); diff --git a/apps/opencs/main.cpp b/apps/opencs/main.cpp index 0b8da61ef..b11561c13 100644 --- a/apps/opencs/main.cpp +++ b/apps/opencs/main.cpp @@ -78,7 +78,7 @@ int main(int argc, char *argv[]) application.setLibraryPaths(libraryPaths); #endif - application.setWindowIcon (QIcon (":./opencs.png")); + application.setWindowIcon (QIcon (":./openmw-cs.png")); CS::Editor editor (ogreInit); diff --git a/files/mac/opencs.icns b/files/mac/openmw-cs.icns similarity index 100% rename from files/mac/opencs.icns rename to files/mac/openmw-cs.icns diff --git a/files/opencs/opencs.png b/files/opencs/openmw-cs.png similarity index 100% rename from files/opencs/opencs.png rename to files/opencs/openmw-cs.png diff --git a/files/opencs/resources.qrc b/files/opencs/resources.qrc index 0cc6996a8..1bcd3ab4f 100644 --- a/files/opencs/resources.qrc +++ b/files/opencs/resources.qrc @@ -1,6 +1,6 @@ - opencs.png + openmw-cs.png activator.png added.png apparatus.png diff --git a/files/opencs.desktop b/files/openmw-cs.desktop similarity index 83% rename from files/opencs.desktop rename to files/openmw-cs.desktop index 638de6ebf..a5e3c27f2 100644 --- a/files/opencs.desktop +++ b/files/openmw-cs.desktop @@ -4,7 +4,7 @@ Name=OpenMW Content Editor GenericName=Content Editor Comment=A replacement for the Morrowind Construction Set. Keywords=Morrowind;Construction Set;Creation Kit Editor;Set;Kit; -TryExec=opencs -Exec=opencs -Icon=opencs +TryExec=openmw-cs +Exec=openmw-cs +Icon=openmw-cs Categories=Game;RolePlaying; diff --git a/files/windows/opencs.rc b/files/windows/opencs.rc index 8839f1861..3ae18dddd 100644 --- a/files/windows/opencs.rc +++ b/files/windows/opencs.rc @@ -1 +1 @@ -IDI_ICON1 ICON DISCARDABLE "opencs.ico" +IDI_ICON1 ICON DISCARDABLE "openmw-cs.ico" diff --git a/files/windows/opencs.ico b/files/windows/openmw-cs.ico similarity index 100% rename from files/windows/opencs.ico rename to files/windows/openmw-cs.ico From c02537c3b16c55fb889824595eb4bc9912f578f2 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 3 Feb 2015 13:42:47 +0100 Subject: [PATCH 0481/3725] incremented version number --- CMakeLists.txt | 2 +- README.md | 44 ++++++++++++++++++++++---------------------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 019d53c4e..8fe213b49 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,7 +12,7 @@ set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/) message(STATUS "Configuring OpenMW...") set(OPENMW_VERSION_MAJOR 0) -set(OPENMW_VERSION_MINOR 34) +set(OPENMW_VERSION_MINOR 35) set(OPENMW_VERSION_RELEASE 0) set(OPENMW_VERSION_COMMITHASH "") diff --git a/README.md b/README.md index e17784752..1698a7ebc 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ OpenMW 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.34.0 +* Version: 0.35.0 * License: GPL (see docs/license/GPL3.txt for more information) * Website: http://www.openmw.org * IRC: #openmw on irc.freenode.net @@ -39,26 +39,26 @@ Command line options --version print version information and quit --data arg (=data) set data directories (later directories have higher priority) - --data-local arg set local data directory (highest + --data-local arg set local data directory (highest priority) --fallback-archive arg (=fallback-archive) - set fallback BSA archives (later + set fallback BSA archives (later archives have higher priority) --resources arg (=resources) set resources directory --start arg set initial cell - --content arg content file(s): esm/esp, or + --content arg content file(s): esm/esp, or omwgame/omwaddon --no-sound [=arg(=1)] (=0) disable all sounds --script-verbose [=arg(=1)] (=0) verbose script output --script-all [=arg(=1)] (=0) compile all scripts (excluding dialogue scripts) at startup --script-all-dialogue [=arg(=1)] (=0) compile all dialogue scripts at startup - --script-console [=arg(=1)] (=0) enable console-only script + --script-console [=arg(=1)] (=0) enable console-only script functionality - --script-run arg select a file containing a list of - console commands that is executed on + --script-run arg select a file containing a list of + console commands that is executed on startup - --script-warn [=arg(=1)] (=1) handling of warnings when compiling + --script-warn [=arg(=1)] (=1) handling of warnings when compiling scripts 0 - ignore warning 1 - show warning but consider script as @@ -70,27 +70,27 @@ Command line options enable script blacklisting --load-savegame arg load a save game file on game startup --skip-menu [=arg(=1)] (=0) skip main menu on game startup - --new-game [=arg(=1)] (=0) run new game sequence (ignored if + --new-game [=arg(=1)] (=0) run new game sequence (ignored if skip-menu=0) - --fs-strict [=arg(=1)] (=0) strict file system handling (no case + --fs-strict [=arg(=1)] (=0) strict file system handling (no case folding) - --encoding arg (=win1252) Character encoding used in OpenMW game + --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 + + 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 + + win1251 - Cyrillic alphabet such as + Russian, Bulgarian, Serbian Cyrillic and other languages - - win1252 - Western European (Latin) + + win1252 - Western European (Latin) alphabet, used by default --fallback arg fallback values --no-grab Don't grab mouse cursor - --export-fonts [=arg(=1)] (=0) Export Morrowind .fnt fonts to PNG + --export-fonts [=arg(=1)] (=0) Export Morrowind .fnt fonts to PNG image and XML file in current directory --activate-dist arg (=-1) activation distance override From 0b7b62744368a42a32f889ef6408dd1bdd283b04 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Feb 2015 13:57:40 +0100 Subject: [PATCH 0482/3725] CMake fix for opencs rename --- apps/opencs/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index be30431df..e713c65bc 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -185,7 +185,7 @@ add_executable(openmw-cs ) if(APPLE) - set_target_properties(opencs PROPERTIES + set_target_properties(openmw-cs PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${OpenMW_BINARY_DIR}" OUTPUT_NAME "OpenMW-CS" MACOSX_BUNDLE_ICON_FILE "openmw-cs.icns" @@ -211,5 +211,5 @@ target_link_libraries(openmw-cs ) if(APPLE) - INSTALL(TARGETS opencs BUNDLE DESTINATION OpenMW-CS COMPONENT BUNDLE) + INSTALL(TARGETS openmw-cs BUNDLE DESTINATION OpenMW-CS COMPONENT BUNDLE) endif() From 9cfaffc7cc6db0e68f90c606ea3b07caa002a1d8 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 3 Feb 2015 14:12:30 +0100 Subject: [PATCH 0483/3725] updated changelog --- CHANGELOG.md | 124 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 750cb5476..c2aa03dc2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,127 @@ +0.35.0 +------ + + Bug #244: Clipping/static in relation to the ghostgate/fence sound. + Bug #531: Missing transparent menu items + Bug #811: Content Lists in openmw.cfg are overwritten + Bug #925: OpenCS doesn't launch because it thinks its already started + Bug #969: Water shader strange behaviour on AMD card + Bug #1049: Partially highlighted word in dialogue may cause incorrect line break + Bug #1069: omwlauncher.exe crashes due to file lock + Bug #1192: It is possible to jump on top of hostile creatures in combat + Bug #1342: Loud ambient sounds + Bug #1431: Creatures can climb the player + Bug #1605: Guard in CharGen doesn't turn around to face you when reaching stairs + Bug #1624: Moon edges don't transition properly + Bug #1634: Items dropped by PC have collision + Bug #1637: Weird NPC behaviour in Vivec, Hlaalu Ancestral Vaults? + Bug #1638: Cannot climb staircases + Bug #1648: Enchanted equipment badly handled at game reload + Bug #1663: Crash when casting spell at enemy near you + Bug #1683: Scale doesn't apply to animated collision nodes + Bug #1702: Active enchanted item forgotten + Bug #1730: Scripts names starting with digit(s) fail to compile + Bug #1743: Moons are transparent + Bug #1745: Shadows crash: Assertion `mEffects.empty()' failed. + Bug #1785: Can't equip two-handed weapon and shield + Bug #1809: Player falls too easily + Bug #1825: Sword of Perithia can´t run in OpenMW + Bug #1899: The launcher resets any alterations you´ve made in the mod list order, + Bug #1964: Idle voices/dialogs not triggered correctly + Bug #1980: Please, change default click behavior in OpenMW Launchers Data Files list + Bug #1984: Vampire corpses standing up when looting the first item + Bug #1985: Calm spell does nothing + Bug #1986: Spell name lights up on mouseover but spell cost does not + Bug #1989: Tooltip still shown when menu toggled off + Bug #2010: Raindrops Displayed While Underwater + Bug #2023: Walking into plants causes massive framedrop + Bug #2031: [MOD: Shrines - Restore Health and Cancel Options]: Restore health option doesn't work + Bug #2039: Lake Fjalding pillar of fire not rendered + Bug #2040: AI_follow should stop further from the target + Bug #2076: Slaughterfish AI + Bug #2077: Direction of long jump can be changed much more than it is possible in vanilla + Bug #2078: error during rendering: Object '' not found (const) + Bug #2105: Lockpicking causes screen sync glitch + Bug #2113: [MOD: Julan Ashlander Companion] Julan does not act correctly within the Ghostfence. + Bug #2123: Window glow mod: Collision issues + Bug #2133: Missing collision for bridges in Balmora when using Morrowind Rebirth 2.81 + Bug #2135: Casting a summon spell while the summon is active does not reset the summon. + Bug #2144: Changing equipment will unequip drawn arrows/bolts + Bug #2169: Yellow on faces when using opengl renderer and mods from overhaul on windows + Bug #2175: Pathgrid mods do not overwrite the existing pathgrid + Bug #2176: Morrowind -Russian localization end add-on ChaosHeart. Error in framelistener;object ;frenzying toush; not found + Bug #2181: Mod Morrowind crafting merchants die. + Bug #2182: mods changing skill progression double the bonus for class specialization + Bug #2183: Editor: Skills "use value" only allows integer between 0 and 99 + Bug #2184: Animated Morrowind Expanded produces an error on Open MW Launch + Bug #2185: Conditional Operator formats + Bug #2193: Quest: Gateway Ghost + Bug #2194: Cannot summon multiples of the same creature + Bug #2195: Pathgrid in the (0,0) exterior cell not loaded + Bug #2200: Outdoor NPCs can stray away and keep walking into a wall + Bug #2201: Creatures do not receive fall damage + Bug #2202: The enchantment the item can hold is calculated incorrectly + Bug #2203: Having the mod Living Cities of Vvardenfall running causes the game world to fail to load after leaving the prison ship + Bug #2204: Abot's Water Life - Book rendered incorrectly + Bug #2205: sound_waterfall script no longer compiles + Bug #2206: Dialogue script fails to compile (extra .) + Bug #2207: Script using – instead of - character does not compile + Bug #2208: Failing dialogue scripts in french Morrowind.esm + Bug #2214: LGNPC Vivec Redoran 1.62 and The King Rat (Size and inventory Issues) + Bug #2215: Beast races can use enchanted boots + Bug #2218: Incorrect names body parts in 3D models for open helmet with skinning + Bug #2219: Orcs in Ghorak Manor in Caldera don't attack if you pick their pockets. + Bug #2220: Chargen race preview head incorrect orientation + Bug #2223: Reseting rock falling animation + Bug #2224: Fortify Attribute effects do not stack when Spellmaking. + Bug #2226: OpenCS pseudo-crash + Bug #2230: segfaulting when entering Ald'ruhn with a specific mod: "fermeture la nuit" (closed by night) + Bug #2233: Area effect spells on touch do not have the area effect + Bug #2234: Dwarven Crossbow clips through the ground when dropped + Bug #2235: class SettingsBase<> reverses the order of entries with multiple keys. + Bug #2236: Weird two handed longsword + torch interaction + Bug #2237: Shooting arrows while sneaking do not agro + Bug #2238: Bipedal creatures not using weapons are not handled properly + Bug #2245: Incorrect topic highlighting in HT_SpyBaladas quest + Bug #2252: Tab completion incomplete for places using COC from the console. + Bug #2255: Camera reverts to first person on load + Bug #2259: enhancement: the save/load progress bar is not very progressive + Bug #2263: TogglePOV can not be bound to Alt key + Bug #2267: dialogue disabling via mod + Bug #2268: Highlighting Files with load order problems in Data Files tab of Launcher + Bug #2276: [Mod]ShotN issues with Karthwasten + Bug #2283: Count argument for PlaceAt functions not working + Bug #2284: Local map notes should be visible on door marker leading to the cell with the note + Bug #2293: There is a graphical glitch at the end of the spell's animation in 3rd Person (looking over the shoulder) view + Bug #2294: When using Skyrim UI Overhaul, the tops of pinnable menus are invisible + Bug #2302: Random leveled items repeat way too often in a single dungeon + Bug #2306: Enchanted arrows should not be retrievable from corpses + Bug #2308: No sound effect when drawing the next throwing knife + Bug #2309: Guards chase see the player character even if they're invisible + Bug #2319: Inverted controls and other issues after becoming a vampire + Bug #2324: Spells cast when crossing cell border are imprinted on the local map + Bug #2330: Actors with Drain Health effect retain health after dying + Bug #2331: tgm (god mode) won't allow the player to cast spells if the player doesn't have enough mana + Bug #2332: Error in framelistener: Need a skeleton to attach the arrow to + Feature #114: ess-Importer + Feature #504: Editor: Delete selected rows from result windows + Feature #1024: Addition of remaining equipping hotkeys + Feature #1067: Handle NIF interpolation type 4 (XYZ_ROTATION_KEY) + Feature #1125: AI fast-forward + Feature #1228: Drowning while knocked out + Feature #1325: Editor: Opening window and User Settings window cleanup + Feature #1537: Ability to change the grid size from 3x3 to 5x5 (or more with good pc) + Feature #1546: Leveled list script functions + Feature #1659: Test dialogue scripts in --script-all + Feature #1720: NPC lookAt controller + Feature #2178: Load initial particle system state from NIF files + Feature #2197: Editor: When clicking on a script error in the report window set cursor in script editor to the respective line/column + Feature #2261: Warn when loading save games with mod mismatch + Feature #2313: ess-Importer: convert global map exploration overlay + Feature #2318: Add commandline option to load a save game + Task #810: Rename "profile" to "content list" + Task #2196: Label local/global openmw.cfg files via comments + 0.34.0 ------ From 42363191a41a30833247fbfe9eba634e8f035a3a Mon Sep 17 00:00:00 2001 From: Lazaroth Date: Tue, 3 Feb 2015 15:25:36 +0100 Subject: [PATCH 0484/3725] Layout tweaks --- files/mygui/openmw_enchanting_dialog.layout | 2 -- files/mygui/openmw_merchantrepair.layout | 20 ++++++++------- files/mygui/openmw_persuasion_dialog.layout | 14 +++++------ files/mygui/openmw_spell_buying_window.layout | 22 ++++++++-------- .../mygui/openmw_spellcreation_dialog.layout | 14 ++++------- files/mygui/openmw_trade_window.layout | 5 ++-- files/mygui/openmw_trainingwindow.layout | 20 +++++++++------ files/mygui/openmw_travel_window.layout | 25 ++++++++++--------- 8 files changed, 62 insertions(+), 60 deletions(-) diff --git a/files/mygui/openmw_enchanting_dialog.layout b/files/mygui/openmw_enchanting_dialog.layout index ed62c8dc6..b90fc7a77 100644 --- a/files/mygui/openmw_enchanting_dialog.layout +++ b/files/mygui/openmw_enchanting_dialog.layout @@ -141,8 +141,6 @@ - - diff --git a/files/mygui/openmw_merchantrepair.layout b/files/mygui/openmw_merchantrepair.layout index da7f37fe7..23ab6008f 100644 --- a/files/mygui/openmw_merchantrepair.layout +++ b/files/mygui/openmw_merchantrepair.layout @@ -1,26 +1,28 @@ - + - - - + + + + + - - - + + + - + - + diff --git a/files/mygui/openmw_persuasion_dialog.layout b/files/mygui/openmw_persuasion_dialog.layout index 87851b479..6fb298914 100644 --- a/files/mygui/openmw_persuasion_dialog.layout +++ b/files/mygui/openmw_persuasion_dialog.layout @@ -1,17 +1,13 @@ - + - + - - - - @@ -39,7 +35,11 @@ - + + + + + diff --git a/files/mygui/openmw_spell_buying_window.layout b/files/mygui/openmw_spell_buying_window.layout index 73820c3d4..0350f1e27 100644 --- a/files/mygui/openmw_spell_buying_window.layout +++ b/files/mygui/openmw_spell_buying_window.layout @@ -1,26 +1,28 @@ - + - - - + + + + + - - - + + + - - + + - + diff --git a/files/mygui/openmw_spellcreation_dialog.layout b/files/mygui/openmw_spellcreation_dialog.layout index 90b95b2f4..11197bf2a 100644 --- a/files/mygui/openmw_spellcreation_dialog.layout +++ b/files/mygui/openmw_spellcreation_dialog.layout @@ -1,10 +1,9 @@ - + - @@ -16,9 +15,7 @@ - - - + @@ -33,7 +30,6 @@ - @@ -46,7 +42,6 @@ - @@ -70,7 +65,7 @@ - + @@ -83,8 +78,9 @@ + + - diff --git a/files/mygui/openmw_trade_window.layout b/files/mygui/openmw_trade_window.layout index 8668243cc..b2017661b 100644 --- a/files/mygui/openmw_trade_window.layout +++ b/files/mygui/openmw_trade_window.layout @@ -29,10 +29,10 @@ - + - + @@ -63,7 +63,6 @@ - diff --git a/files/mygui/openmw_trainingwindow.layout b/files/mygui/openmw_trainingwindow.layout index d6cea8727..c58bd0ab3 100644 --- a/files/mygui/openmw_trainingwindow.layout +++ b/files/mygui/openmw_trainingwindow.layout @@ -1,22 +1,26 @@ - - - - + - + + + + + - - + + + + + - + diff --git a/files/mygui/openmw_travel_window.layout b/files/mygui/openmw_travel_window.layout index 4b383ee7c..3603f7dcb 100644 --- a/files/mygui/openmw_travel_window.layout +++ b/files/mygui/openmw_travel_window.layout @@ -1,28 +1,29 @@ - + - - - - + + + + + + - - - - + + + - - + + - + From abb334bc1e0e77ed142afda1e6f003f7def6995d Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Tue, 3 Feb 2015 22:43:15 +0100 Subject: [PATCH 0485/3725] Missing change for the tool rename --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8fe213b49..b5cd54bab 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -714,7 +714,7 @@ if (WIN32) if (BUILD_OPENCS) # QT triggers an informational warning that the object layout may differ when compiled with /vd2 set(OPENCS_WARNINGS "${WARNINGS} ${MT_BUILD} /wd4435") - set_target_properties(opencs PROPERTIES COMPILE_FLAGS ${OPENCS_WARNINGS}) + set_target_properties(openmw-cs PROPERTIES COMPILE_FLAGS ${OPENCS_WARNINGS}) endif (BUILD_OPENCS) if (BUILD_MWINIIMPORTER) set_target_properties(openmw-iniimporter PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") From 14923f3e8bf0fb07c2ee05e0c048e412fb9f91ab Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Feb 2015 23:05:06 +0100 Subject: [PATCH 0486/3725] Fix for broken unsetRefNum --- apps/openmw/mwworld/cellref.cpp | 6 +++--- apps/openmw/mwworld/cellref.hpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwworld/cellref.cpp b/apps/openmw/mwworld/cellref.cpp index 744e0e27a..d2cced3b8 100644 --- a/apps/openmw/mwworld/cellref.cpp +++ b/apps/openmw/mwworld/cellref.cpp @@ -5,19 +5,19 @@ namespace MWWorld { - ESM::RefNum CellRef::getRefNum() const + const ESM::RefNum& CellRef::getRefNum() const { return mCellRef.mRefNum; } bool CellRef::hasContentFile() const { - return getRefNum().hasContentFile(); + return mCellRef.mRefNum.hasContentFile(); } void CellRef::unsetRefNum() { - getRefNum().unset(); + mCellRef.mRefNum.unset(); } std::string CellRef::getRefId() const diff --git a/apps/openmw/mwworld/cellref.hpp b/apps/openmw/mwworld/cellref.hpp index 054fd7fc6..f063b2727 100644 --- a/apps/openmw/mwworld/cellref.hpp +++ b/apps/openmw/mwworld/cellref.hpp @@ -23,7 +23,7 @@ namespace MWWorld } // Note: Currently unused for items in containers - ESM::RefNum getRefNum() const; + const ESM::RefNum& getRefNum() const; // Set RefNum to its default state. void unsetRefNum(); From fbb8998184f49ff077bb4941de88abb9931e5043 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 4 Feb 2015 16:41:14 +0100 Subject: [PATCH 0487/3725] Account for not yet listed cells in getInteriorPtrs --- apps/openmw/mwworld/cells.cpp | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwworld/cells.cpp b/apps/openmw/mwworld/cells.cpp index fd5ec20dc..2aa817fa5 100644 --- a/apps/openmw/mwworld/cells.cpp +++ b/apps/openmw/mwworld/cells.cpp @@ -241,26 +241,30 @@ MWWorld::Ptr MWWorld::Cells::getPtr (const std::string& name) void MWWorld::Cells::getExteriorPtrs(const std::string &name, std::vector &out) { - for (std::map, CellStore>::iterator iter = mExteriors.begin(); - iter!=mExteriors.end(); ++iter) + const MWWorld::Store &cells = mStore.get(); + for (MWWorld::Store::iterator iter = cells.extBegin(); iter != cells.extEnd(); ++iter) { - Ptr ptr = getPtrAndCache (name, iter->second); + CellStore *cellStore = getCellStore (&(*iter)); + + Ptr ptr = getPtrAndCache (name, *cellStore); + if (!ptr.isEmpty()) out.push_back(ptr); } - } void MWWorld::Cells::getInteriorPtrs(const std::string &name, std::vector &out) { - for (std::map::iterator iter = mInteriors.begin(); - iter!=mInteriors.end(); ++iter) + const MWWorld::Store &cells = mStore.get(); + for (MWWorld::Store::iterator iter = cells.intBegin(); iter != cells.intEnd(); ++iter) { - Ptr ptr = getPtrAndCache (name, iter->second); + CellStore *cellStore = getCellStore (&(*iter)); + + Ptr ptr = getPtrAndCache (name, *cellStore); + if (!ptr.isEmpty()) out.push_back(ptr); } - } int MWWorld::Cells::countSavedGameRecords() const From 1f036c0381f3cbaaf3f21670d998b3f422a339c3 Mon Sep 17 00:00:00 2001 From: Jordan Ayers Date: Wed, 4 Feb 2015 12:06:29 -0600 Subject: [PATCH 0488/3725] Patch for COC Spawn Issue. OMW Bug #1079 Fall back to the first static's position, if there are no door markers. --- apps/openmw/mwworld/worldimp.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 1036d8ce6..e08000b0b 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2383,6 +2383,7 @@ namespace MWWorld bool World::findInteriorPosition(const std::string &name, ESM::Position &pos) { typedef MWWorld::CellRefList::List DoorList; + typedef MWWorld::CellRefList::List StaticList; pos.rot[0] = pos.rot[1] = pos.rot[2] = 0; pos.pos[0] = pos.pos[1] = pos.pos[2] = 0; @@ -2427,6 +2428,13 @@ namespace MWWorld } } } + // Fall back to the first static location. + const StaticList &statics = cellStore->get().mList; + if ( statics.begin() != statics.end() ) { + pos = statics.begin()->mRef.getPosition(); + return true; + } + return false; } From 0c6e2170dbb5c880b4c3c8df3ff43566849cd804 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 31 Jan 2015 23:27:34 +0100 Subject: [PATCH 0489/3725] Include cleanup --- apps/launcher/graphicspage.cpp | 2 +- apps/openmw/mwbase/environment.hpp | 4 ++-- apps/openmw/mwbase/inputmanager.hpp | 4 +--- apps/openmw/mwbase/soundmanager.hpp | 4 +--- apps/openmw/mwbase/windowmanager.hpp | 18 +++++++++++------- apps/openmw/mwbase/world.hpp | 14 +++++--------- apps/openmw/mwdialogue/scripttest.cpp | 2 ++ apps/openmw/mwgui/hud.cpp | 1 + apps/openmw/mwgui/inventorywindow.cpp | 2 ++ apps/openmw/mwgui/itemmodel.cpp | 2 ++ apps/openmw/mwgui/journalviewmodel.cpp | 2 ++ apps/openmw/mwgui/loadingscreen.cpp | 2 ++ apps/openmw/mwgui/mainmenu.cpp | 1 + apps/openmw/mwgui/mapwindow.cpp | 1 + apps/openmw/mwgui/settingswindow.cpp | 1 + apps/openmw/mwgui/tooltips.cpp | 1 + apps/openmw/mwgui/waitdialog.cpp | 1 + apps/openmw/mwgui/windowbase.cpp | 2 ++ apps/openmw/mwgui/windowmanagerimp.cpp | 5 +++++ apps/openmw/mwgui/windowmanagerimp.hpp | 7 ++++--- apps/openmw/mwmechanics/actors.hpp | 1 + apps/openmw/mwmechanics/character.cpp | 2 ++ apps/openmw/mwrender/animation.cpp | 1 + apps/openmw/mwrender/globalmap.cpp | 1 + apps/openmw/mwscript/animationextensions.cpp | 1 + apps/openmw/mwstate/statemanagerimp.cpp | 1 + apps/openmw/mwworld/livecellref.cpp | 3 ++- extern/sdl4ogre/events.h | 6 +++--- extern/sdl4ogre/sdlcursormanager.cpp | 3 +++ extern/sdl4ogre/sdlcursormanager.hpp | 5 +++-- 30 files changed, 66 insertions(+), 34 deletions(-) diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index 1f85bb5e7..dccf8bb8c 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -10,7 +10,7 @@ #define MAC_OS_X_VERSION_MIN_REQUIRED __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ #endif // MAC_OS_X_VERSION_MIN_REQUIRED -#include +#include #include #include diff --git a/apps/openmw/mwbase/environment.hpp b/apps/openmw/mwbase/environment.hpp index eb636ea2f..7f7919f81 100644 --- a/apps/openmw/mwbase/environment.hpp +++ b/apps/openmw/mwbase/environment.hpp @@ -1,5 +1,5 @@ -#ifndef GAME_BASE_INVIRONMENT_H -#define GAME_BASE_INVIRONMENT_H +#ifndef GAME_BASE_ENVIRONMENT_H +#define GAME_BASE_ENVIRONMENT_H namespace MWBase { diff --git a/apps/openmw/mwbase/inputmanager.hpp b/apps/openmw/mwbase/inputmanager.hpp index d44da4974..11eb1721f 100644 --- a/apps/openmw/mwbase/inputmanager.hpp +++ b/apps/openmw/mwbase/inputmanager.hpp @@ -3,8 +3,6 @@ #include -#include - namespace MWBase { /// \brief Interface for input manager (implemented in MWInput) @@ -29,7 +27,7 @@ namespace MWBase virtual void changeInputMode(bool guiMode) = 0; - virtual void processChangedSettings(const Settings::CategorySettingVector& changed) = 0; + virtual void processChangedSettings(const std::vector< std::pair >& changed) = 0; virtual void setDragDrop(bool dragDrop) = 0; diff --git a/apps/openmw/mwbase/soundmanager.hpp b/apps/openmw/mwbase/soundmanager.hpp index bc2f3f1c6..a4c08f06f 100644 --- a/apps/openmw/mwbase/soundmanager.hpp +++ b/apps/openmw/mwbase/soundmanager.hpp @@ -5,8 +5,6 @@ #include -#include - #include "../mwworld/ptr.hpp" namespace Ogre @@ -74,7 +72,7 @@ namespace MWBase virtual ~SoundManager() {} - virtual void processChangedSettings(const Settings::CategorySettingVector& settings) = 0; + virtual void processChangedSettings(const std::vector< std::pair >& settings) = 0; virtual void stopMusic() = 0; ///< Stops music if it's playing diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 69027d734..fc745d3e6 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -5,16 +5,20 @@ #include #include -#include - -#include - -#include - #include "../mwmechanics/stat.hpp" #include "../mwgui/mode.hpp" +namespace Loading +{ + class Listener; +} + +namespace Translation +{ + class Storage; +} + namespace MyGUI { class Gui; @@ -267,7 +271,7 @@ namespace MWBase */ virtual std::string getGameSettingString(const std::string &id, const std::string &default_) = 0; - virtual void processChangedSettings(const Settings::CategorySettingVector& changed) = 0; + virtual void processChangedSettings(const std::vector< std::pair >& changed) = 0; virtual void windowResized(int x, int y) = 0; diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 9d8fc90a1..3af2a2775 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -4,25 +4,21 @@ #include #include -#include - #include -#include "../mwworld/globals.hpp" #include "../mwworld/ptr.hpp" namespace Ogre { class Vector2; class Vector3; + class Quaternion; + class Image; } -namespace OEngine +namespace Loading { - namespace Physic - { - class PhysicEngine; - } + class Listener; } namespace ESM @@ -390,7 +386,7 @@ namespace MWBase virtual bool canPlaceObject (float cursorX, float cursorY) = 0; ///< @return true if it is possible to place on object at specified cursor location - virtual void processChangedSettings (const Settings::CategorySettingVector& settings) = 0; + virtual void processChangedSettings (const std::vector< std::pair >& settings) = 0; virtual bool isFlying(const MWWorld::Ptr &ptr) const = 0; virtual bool isSlowFalling(const MWWorld::Ptr &ptr) const = 0; diff --git a/apps/openmw/mwdialogue/scripttest.cpp b/apps/openmw/mwdialogue/scripttest.cpp index b2c8f536a..fd477365f 100644 --- a/apps/openmw/mwdialogue/scripttest.cpp +++ b/apps/openmw/mwdialogue/scripttest.cpp @@ -1,5 +1,7 @@ #include "scripttest.hpp" +#include + #include "../mwworld/manualref.hpp" #include "../mwworld/class.hpp" diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 13a5c559c..1f7ead6f5 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -10,6 +10,7 @@ #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/soundmanager.hpp" diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index ed0f505f5..ae7d60d44 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -8,6 +8,8 @@ #include #include +#include + #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/soundmanager.hpp" diff --git a/apps/openmw/mwgui/itemmodel.cpp b/apps/openmw/mwgui/itemmodel.cpp index f5135ce80..8224fd55b 100644 --- a/apps/openmw/mwgui/itemmodel.cpp +++ b/apps/openmw/mwgui/itemmodel.cpp @@ -1,5 +1,7 @@ #include "itemmodel.hpp" +#include + #include "../mwworld/class.hpp" #include "../mwworld/containerstore.hpp" #include "../mwworld/store.hpp" diff --git a/apps/openmw/mwgui/journalviewmodel.cpp b/apps/openmw/mwgui/journalviewmodel.cpp index add2ac62c..3a86613f6 100644 --- a/apps/openmw/mwgui/journalviewmodel.cpp +++ b/apps/openmw/mwgui/journalviewmodel.cpp @@ -8,6 +8,8 @@ #include +#include + #include "../mwbase/world.hpp" #include "../mwbase/journal.hpp" #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index 270066c97..9e3343c78 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -15,6 +15,8 @@ #include #include +#include + #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/statemanager.hpp" diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index f1c4c4088..6ad4da3bf 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -9,6 +9,7 @@ #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 61712a470..13e2e3904 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -13,6 +13,7 @@ #include #include +#include #include "../mwbase/windowmanager.hpp" #include "../mwbase/world.hpp" diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index f8741a67a..281093452 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -15,6 +15,7 @@ #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 2849688c2..275071737 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -8,6 +8,7 @@ #include #include +#include #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index 718e04e52..fedb0324e 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -3,6 +3,7 @@ #include #include +#include #include "../mwbase/windowmanager.hpp" #include "../mwbase/world.hpp" diff --git a/apps/openmw/mwgui/windowbase.cpp b/apps/openmw/mwgui/windowbase.cpp index 7f2eaec2e..8fdcf6b20 100644 --- a/apps/openmw/mwgui/windowbase.cpp +++ b/apps/openmw/mwgui/windowbase.cpp @@ -2,6 +2,8 @@ #include +#include + #include "../mwbase/windowmanager.hpp" #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 975ee6c29..a35498dea 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -19,6 +19,9 @@ #include #include +#include +#include + #include #include @@ -26,6 +29,8 @@ #include +#include + #include #include diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index a08c59a2f..b3eb9cd0a 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -5,13 +5,14 @@ This class owns and controls all the MW specific windows in the GUI. It can enable/disable Gui mode, and is responsible for sending and retrieving information from the Gui. - - MyGUI should be initialized separately before creating instances of - this class. **/ +#include + #include "../mwbase/windowmanager.hpp" +#include + #include "mapwindow.hpp" #include diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index 39598b2a2..70f1b47d9 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -5,6 +5,7 @@ #include #include #include +#include #include "movement.hpp" #include "../mwbase/world.hpp" diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 91b375714..449c030f4 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -27,6 +27,8 @@ #include "creaturestats.hpp" #include "security.hpp" +#include + #include "../mwrender/animation.hpp" #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index ec5398309..50afc5afd 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include diff --git a/apps/openmw/mwrender/globalmap.cpp b/apps/openmw/mwrender/globalmap.cpp index f0f6158ed..de78748b5 100644 --- a/apps/openmw/mwrender/globalmap.cpp +++ b/apps/openmw/mwrender/globalmap.cpp @@ -11,6 +11,7 @@ #include #include +#include #include diff --git a/apps/openmw/mwscript/animationextensions.cpp b/apps/openmw/mwscript/animationextensions.cpp index 613cf7d24..00b8a9620 100644 --- a/apps/openmw/mwscript/animationextensions.cpp +++ b/apps/openmw/mwscript/animationextensions.cpp @@ -2,6 +2,7 @@ #include "animationextensions.hpp" #include +#include #include #include diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index a282f152a..d623ba465 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -13,6 +13,7 @@ #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" diff --git a/apps/openmw/mwworld/livecellref.cpp b/apps/openmw/mwworld/livecellref.cpp index dd313632b..bfc708185 100644 --- a/apps/openmw/mwworld/livecellref.cpp +++ b/apps/openmw/mwworld/livecellref.cpp @@ -1,6 +1,7 @@ - #include "livecellref.hpp" +#include + #include #include "../mwbase/environment.hpp" diff --git a/extern/sdl4ogre/events.h b/extern/sdl4ogre/events.h index 0fb4d6f06..6961e81fc 100644 --- a/extern/sdl4ogre/events.h +++ b/extern/sdl4ogre/events.h @@ -1,8 +1,8 @@ #ifndef _SFO_EVENTS_H #define _SFO_EVENTS_H -#include - +#include +#include //////////// // Events // @@ -65,7 +65,7 @@ public: virtual ~WindowListener() {} /** @remarks The window's visibility changed */ - virtual void windowVisibilityChange( bool visible ) {}; + virtual void windowVisibilityChange( bool visible ) {} /** @remarks The window got / lost input focus */ virtual void windowFocusChange( bool have_focus ) {} diff --git a/extern/sdl4ogre/sdlcursormanager.cpp b/extern/sdl4ogre/sdlcursormanager.cpp index 5ef274b7e..7623d57db 100644 --- a/extern/sdl4ogre/sdlcursormanager.cpp +++ b/extern/sdl4ogre/sdlcursormanager.cpp @@ -4,6 +4,9 @@ #include #include +#include +#include + #include namespace SFO diff --git a/extern/sdl4ogre/sdlcursormanager.hpp b/extern/sdl4ogre/sdlcursormanager.hpp index 7e3e59b4a..58324fc01 100644 --- a/extern/sdl4ogre/sdlcursormanager.hpp +++ b/extern/sdl4ogre/sdlcursormanager.hpp @@ -1,11 +1,12 @@ #ifndef SDL4OGRE_CURSORMANAGER_H #define SDL4OGRE_CURSORMANAGER_H -#include - #include "cursormanager.hpp" #include +struct SDL_Cursor; +struct SDL_Surface; + namespace SFO { class SDLCursorManager : From 6d097fbfbd8f051de27bfcd81bb0746f1509bf47 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 1 Feb 2015 00:26:06 +0100 Subject: [PATCH 0490/3725] Normalise spelling of "levelled" throughout the code --- apps/esmtool/record.cpp | 4 ++-- apps/essimporter/importcellref.cpp | 4 ++-- apps/openmw/mwmechanics/levelledlist.hpp | 8 ++++---- apps/openmw/mwmechanics/npcstats.cpp | 2 +- apps/openmw/mwscript/miscextensions.cpp | 10 +++++----- components/esm/loadlevlist.cpp | 6 +++--- components/esm/loadlevlist.hpp | 12 ++++++------ 7 files changed, 23 insertions(+), 23 deletions(-) diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index df2631c13..e167278f3 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -837,7 +837,7 @@ void Record::print() std::cout << " Chance for None: " << (int)mData.mChanceNone << std::endl; std::cout << " Flags: " << creatureListFlags(mData.mFlags) << std::endl; std::cout << " Number of items: " << mData.mList.size() << std::endl; - std::vector::iterator iit; + std::vector::iterator iit; for (iit = mData.mList.begin(); iit != mData.mList.end(); ++iit) std::cout << " Creature: Level: " << iit->mLevel << " Creature: " << iit->mId << std::endl; @@ -849,7 +849,7 @@ void Record::print() std::cout << " Chance for None: " << (int)mData.mChanceNone << std::endl; std::cout << " Flags: " << itemListFlags(mData.mFlags) << std::endl; std::cout << " Number of items: " << mData.mList.size() << std::endl; - std::vector::iterator iit; + std::vector::iterator iit; for (iit = mData.mList.begin(); iit != mData.mList.end(); ++iit) std::cout << " Inventory: Level: " << iit->mLevel << " Item: " << iit->mId << std::endl; diff --git a/apps/essimporter/importcellref.cpp b/apps/essimporter/importcellref.cpp index 906b2ed24..cca356b2a 100644 --- a/apps/essimporter/importcellref.cpp +++ b/apps/essimporter/importcellref.cpp @@ -22,7 +22,7 @@ namespace ESSImport ActorData::load(esm); if (esm.isNextSub("LVCR")) { - // occurs on leveled creature spawner references + // occurs on levelled creature spawner references // probably some identifier for the creature that has been spawned? unsigned char lvcr; esm.getHT(lvcr); @@ -32,7 +32,7 @@ namespace ESSImport mEnabled = true; esm.getHNOT(mEnabled, "ZNAM"); - // DATA should occur for all references, except leveled creature spawners + // DATA should occur for all references, except levelled creature spawners // I've seen DATA *twice* on a creature record, and with the exact same content too! weird // alarmvoi0000.ess esm.getHNOT(mPos, "DATA", 24); diff --git a/apps/openmw/mwmechanics/levelledlist.hpp b/apps/openmw/mwmechanics/levelledlist.hpp index 96410c35d..de652a9c8 100644 --- a/apps/openmw/mwmechanics/levelledlist.hpp +++ b/apps/openmw/mwmechanics/levelledlist.hpp @@ -12,9 +12,9 @@ namespace MWMechanics { /// @return ID of resulting item, or empty if none - inline std::string getLevelledItem (const ESM::LeveledListBase* levItem, bool creature, unsigned char failChance=0) + inline std::string getLevelledItem (const ESM::LevelledListBase* levItem, bool creature, unsigned char failChance=0) { - const std::vector& items = levItem->mList; + const std::vector& items = levItem->mList; const MWWorld::Ptr& player = MWBase::Environment::get().getWorld()->getPlayerPtr(); int playerLevel = player.getClass().getCreatureStats(player).getLevel(); @@ -27,7 +27,7 @@ namespace MWMechanics std::vector candidates; int highestLevel = 0; - for (std::vector::const_iterator it = items.begin(); it != items.end(); ++it) + for (std::vector::const_iterator it = items.begin(); it != items.end(); ++it) { if (it->mLevel > highestLevel && it->mLevel <= playerLevel) highestLevel = it->mLevel; @@ -39,7 +39,7 @@ namespace MWMechanics allLevels = levItem->mFlags & ESM::CreatureLevList::AllLevels; std::pair highest = std::make_pair(-1, ""); - for (std::vector::const_iterator it = items.begin(); it != items.end(); ++it) + for (std::vector::const_iterator it = items.begin(); it != items.end(); ++it) { if (playerLevel >= it->mLevel && (allLevels || it->mLevel == highestLevel)) diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index c517b4df8..7219d6185 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -200,7 +200,7 @@ void MWMechanics::NpcStats::useSkill (int skillIndex, const ESM::Class& class_, if (value.getProgress()>=1) { - // skill leveled up + // skill levelled up increaseSkill(skillIndex, class_, false); } } diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 37bb4235e..bffeef768 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -34,24 +34,24 @@ namespace { - void addToLevList(ESM::LeveledListBase* list, const std::string& itemId, int level) + void addToLevList(ESM::LevelledListBase* list, const std::string& itemId, int level) { - for (std::vector::iterator it = list->mList.begin(); it != list->mList.end();) + for (std::vector::iterator it = list->mList.begin(); it != list->mList.end();) { if (it->mLevel == level && itemId == it->mId) return; } - ESM::LeveledListBase::LevelItem item; + ESM::LevelledListBase::LevelItem item; item.mId = itemId; item.mLevel = level; list->mList.push_back(item); } - void removeFromLevList(ESM::LeveledListBase* list, const std::string& itemId, int level) + void removeFromLevList(ESM::LevelledListBase* list, const std::string& itemId, int level) { // level of -1 removes all items with that itemId - for (std::vector::iterator it = list->mList.begin(); it != list->mList.end();) + for (std::vector::iterator it = list->mList.begin(); it != list->mList.end();) { if (level != -1 && it->mLevel != level) { diff --git a/components/esm/loadlevlist.cpp b/components/esm/loadlevlist.cpp index 6385b9a71..f2c695c1f 100644 --- a/components/esm/loadlevlist.cpp +++ b/components/esm/loadlevlist.cpp @@ -7,7 +7,7 @@ namespace ESM { -void LeveledListBase::load(ESMReader &esm) +void LevelledListBase::load(ESMReader &esm) { esm.getHNT(mFlags, "DATA"); esm.getHNT(mChanceNone, "NNAM"); @@ -34,7 +34,7 @@ void LeveledListBase::load(ESMReader &esm) esm.getHNT(li.mLevel, "INTV"); } } -void LeveledListBase::save(ESMWriter &esm) const +void LevelledListBase::save(ESMWriter &esm) const { esm.writeHNT("DATA", mFlags); esm.writeHNT("NNAM", mChanceNone); @@ -47,7 +47,7 @@ void LeveledListBase::save(ESMWriter &esm) const } } - void LeveledListBase::blank() + void LevelledListBase::blank() { mFlags = 0; mChanceNone = 0; diff --git a/components/esm/loadlevlist.hpp b/components/esm/loadlevlist.hpp index a4e1b85c2..bcea2b234 100644 --- a/components/esm/loadlevlist.hpp +++ b/components/esm/loadlevlist.hpp @@ -11,14 +11,14 @@ class ESMReader; class ESMWriter; /* - * Leveled lists. Since these have identical layout, I only bothered + * Levelled lists. Since these have identical layout, I only bothered * to implement it once. * - * We should later implement the ability to merge leveled lists from + * We should later implement the ability to merge levelled lists from * several files. */ -struct LeveledListBase +struct LevelledListBase { int mFlags; unsigned char mChanceNone; // Chance that none are selected (0-100) @@ -43,7 +43,7 @@ struct LeveledListBase ///< Set record to default state (does not touch the ID). }; -struct CreatureLevList: LeveledListBase +struct CreatureLevList: LevelledListBase { static unsigned int sRecordId; @@ -61,7 +61,7 @@ struct CreatureLevList: LeveledListBase } }; -struct ItemLevList: LeveledListBase +struct ItemLevList: LevelledListBase { static unsigned int sRecordId; @@ -72,7 +72,7 @@ struct ItemLevList: LeveledListBase // list is instantiated, instead of // giving several identical items // (used when a container has more - // than one instance of one leveled + // than one instance of one levelled // list.) AllLevels = 0x02 // Calculate from all levels <= player // level, not just the closest below From 9825b68dfb6d5ab015d283c6bb858246b40ba9b2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 1 Feb 2015 16:19:05 +0100 Subject: [PATCH 0491/3725] Fix SDL eating SIGINT signals in the launcher (Fixes #2328) --- apps/launcher/main.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/launcher/main.cpp b/apps/launcher/main.cpp index e4fae74f4..5c3f38458 100644 --- a/apps/launcher/main.cpp +++ b/apps/launcher/main.cpp @@ -1,4 +1,5 @@ #include +#include #include #include @@ -26,6 +27,8 @@ int main(int argc, char *argv[]) qDebug() << "SDL_Init failed: " << QString::fromStdString(SDL_GetError()); return 0; } + signal(SIGINT, SIG_DFL); // We don't want to use the SDL event loop in the launcher, + // so reset SIGINT which SDL wants to redirect to an SDL_Quit event. QApplication app(argc, argv); From 6ea59c93abf46402f505c8dd8519b42a7249dc15 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 2 Feb 2015 04:20:33 +0100 Subject: [PATCH 0492/3725] Ignore the object scale in Move instruction (Fixes #2275) --- apps/openmw/mwscript/transformationextensions.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 3bbde2003..fcfc36995 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -691,10 +691,10 @@ namespace MWScript if (!ptr.getRefData().getBaseNode()) return; - Ogre::Vector3 worldPos = ptr.getRefData().getBaseNode()->convertLocalToWorldPosition(posChange); - - dynamic_cast(runtime.getContext()).updatePtr( - MWBase::Environment::get().getWorld()->moveObject(ptr, worldPos.x, worldPos.y, worldPos.z)); + Ogre::Vector3 diff = ptr.getRefData().getBaseNode()->getOrientation() * posChange; + Ogre::Vector3 worldPos(ptr.getRefData().getPosition().pos); + worldPos += diff; + MWBase::Environment::get().getWorld()->moveObject(ptr, worldPos.x, worldPos.y, worldPos.z); } }; From 27dc49a1357c2078d2305f0859efd3ccc3de8639 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Feb 2015 00:53:30 +0100 Subject: [PATCH 0493/3725] Rewrite game settings manager Removes the abhorrent dependency on Ogre for this code and improves the error handling. --- apps/openmw/engine.cpp | 6 +- apps/openmw/mwbase/inputmanager.hpp | 4 +- apps/openmw/mwbase/soundmanager.hpp | 4 +- apps/openmw/mwbase/windowmanager.hpp | 2 +- apps/openmw/mwbase/world.hpp | 3 +- components/settings/settings.cpp | 224 +++++++++++++++------------ components/settings/settings.hpp | 13 +- 7 files changed, 137 insertions(+), 119 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 859baebe4..a9a7f0632 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -292,14 +292,10 @@ std::string OMW::Engine::loadSettings (Settings::Manager & settings) else throw std::runtime_error ("No default settings file found! Make sure the file \"settings-default.cfg\" was properly installed."); - // load user settings if they exist, otherwise just load the default settings as user settings + // load user settings if they exist const std::string settingspath = mCfgMgr.getUserConfigPath().string() + "/settings.cfg"; if (boost::filesystem::exists(settingspath)) settings.loadUser(settingspath); - else if (boost::filesystem::exists(localdefault)) - settings.loadUser(localdefault); - else if (boost::filesystem::exists(globaldefault)) - settings.loadUser(globaldefault); mFpsLevel = settings.getInt("fps", "HUD"); diff --git a/apps/openmw/mwbase/inputmanager.hpp b/apps/openmw/mwbase/inputmanager.hpp index 11eb1721f..a53d8d9dc 100644 --- a/apps/openmw/mwbase/inputmanager.hpp +++ b/apps/openmw/mwbase/inputmanager.hpp @@ -2,6 +2,8 @@ #define GAME_MWBASE_INPUTMANAGER_H #include +#include +#include namespace MWBase { @@ -27,7 +29,7 @@ namespace MWBase virtual void changeInputMode(bool guiMode) = 0; - virtual void processChangedSettings(const std::vector< std::pair >& changed) = 0; + virtual void processChangedSettings(const std::set< std::pair >& changed) = 0; virtual void setDragDrop(bool dragDrop) = 0; diff --git a/apps/openmw/mwbase/soundmanager.hpp b/apps/openmw/mwbase/soundmanager.hpp index a4c08f06f..f3381a8fd 100644 --- a/apps/openmw/mwbase/soundmanager.hpp +++ b/apps/openmw/mwbase/soundmanager.hpp @@ -2,7 +2,7 @@ #define GAME_MWBASE_SOUNDMANAGER_H #include - +#include #include #include "../mwworld/ptr.hpp" @@ -72,7 +72,7 @@ namespace MWBase virtual ~SoundManager() {} - virtual void processChangedSettings(const std::vector< std::pair >& settings) = 0; + virtual void processChangedSettings(const std::set< std::pair >& settings) = 0; virtual void stopMusic() = 0; ///< Stops music if it's playing diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index fc745d3e6..c984b5e54 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -271,7 +271,7 @@ namespace MWBase */ virtual std::string getGameSettingString(const std::string &id, const std::string &default_) = 0; - virtual void processChangedSettings(const std::vector< std::pair >& changed) = 0; + virtual void processChangedSettings(const std::set< std::pair >& changed) = 0; virtual void windowResized(int x, int y) = 0; diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 3af2a2775..154d96f7d 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -3,6 +3,7 @@ #include #include +#include #include @@ -386,7 +387,7 @@ namespace MWBase virtual bool canPlaceObject (float cursorX, float cursorY) = 0; ///< @return true if it is possible to place on object at specified cursor location - virtual void processChangedSettings (const std::vector< std::pair >& settings) = 0; + virtual void processChangedSettings (const std::set< std::pair >& settings) = 0; virtual bool isFlying(const MWWorld::Ptr &ptr) const = 0; virtual bool isSlowFalling(const MWWorld::Ptr &ptr) const = 0; diff --git a/components/settings/settings.cpp b/components/settings/settings.cpp index 5fc2ca3c1..a9a78d035 100644 --- a/components/settings/settings.cpp +++ b/components/settings/settings.cpp @@ -1,95 +1,144 @@ #include "settings.hpp" #include -#include -#include -#include #include -#include -#include - -using namespace Settings; +#include +#include +#include -namespace bfs = boost::filesystem; +namespace Settings +{ -Ogre::ConfigFile Manager::mFile = Ogre::ConfigFile(); -Ogre::ConfigFile Manager::mDefaultFile = Ogre::ConfigFile(); +CategorySettingValueMap Manager::mDefaultSettings = CategorySettingValueMap(); +CategorySettingValueMap Manager::mUserSettings = CategorySettingValueMap(); CategorySettingVector Manager::mChangedSettings = CategorySettingVector(); -CategorySettingValueMap Manager::mNewSettings = CategorySettingValueMap(); - -void Manager::loadUser (const std::string& file) -{ - Ogre::DataStreamPtr stream = openConstrainedFileDataStream(file.c_str()); - mFile.load(stream); -} -void Manager::loadDefault (const std::string& file) -{ - Ogre::DataStreamPtr stream = openConstrainedFileDataStream(file.c_str()); - mDefaultFile.load(stream); -} -void Manager::saveUser(const std::string& file) +class SettingsFileParser { - bfs::ofstream fout((bfs::path(file))); +public: + SettingsFileParser() : mLine(0) {} - Ogre::ConfigFile::SectionIterator seci = mFile.getSectionIterator(); - - while (seci.hasMoreElements()) + void loadSettingsFile (const std::string& file, CategorySettingValueMap& settings) { - Ogre::String sectionName = seci.peekNextKey(); + mFile = file; + boost::filesystem::ifstream stream; + stream.open(boost::filesystem::path(file)); + std::string currentCategory; + mLine = 0; + while (!stream.eof() && !stream.fail()) + { + ++mLine; + std::string line; + std::getline( stream, line ); - if (sectionName.length() > 0) - fout << '\n' << '[' << seci.peekNextKey() << ']' << '\n'; + size_t i = 0; + if (!skipWhiteSpace(i, line)) + continue; - Ogre::ConfigFile::SettingsMultiMap *settings = seci.getNext(); - Ogre::ConfigFile::SettingsMultiMap::iterator i; - for (i = settings->begin(); i != settings->end(); ++i) - { - fout << i->first.c_str() << " = " << i->second.c_str() << '\n'; - } + if (line[i] == '#') // skip comment + continue; - CategorySettingValueMap::iterator it = mNewSettings.begin(); - while (it != mNewSettings.end()) - { - if (it->first.first == sectionName) + if (line[i] == '[') { - fout << it->first.second << " = " << it->second << '\n'; - mNewSettings.erase(it++); + size_t end = line.find(']', i); + if (end == std::string::npos) + fail("unterminated category"); + + currentCategory = line.substr(i+1, end - (i+1)); + boost::algorithm::trim(currentCategory); + i = end+1; } - else - ++it; + + if (!skipWhiteSpace(i, line)) + continue; + + if (currentCategory.empty()) + fail("empty category name"); + + size_t settingEnd = line.find('=', i); + if (settingEnd == std::string::npos) + fail("unterminated setting name"); + + std::string setting = line.substr(i, (settingEnd-i)); + boost::algorithm::trim(setting); + + size_t valueBegin = settingEnd+1; + std::string value = line.substr(valueBegin); + boost::algorithm::trim(value); + + if (settings.insert(std::make_pair(std::make_pair(currentCategory, setting), value)).second == false) + fail(std::string("duplicate setting: [" + currentCategory + "] " + setting)); } } - std::string category = ""; - for (CategorySettingValueMap::iterator it = mNewSettings.begin(); - it != mNewSettings.end(); ++it) +private: + /// Increment i until it longer points to a whitespace character + /// in the string or has reached the end of the string. + /// @return false if we have reached the end of the string + bool skipWhiteSpace(size_t& i, std::string& str) { - if (category != it->first.first) + while (i < str.size() && std::isspace(str[i], std::locale::classic())) { - category = it->first.first; - fout << '\n' << '[' << category << ']' << '\n'; + ++i; } - fout << it->first.second << " = " << it->second << '\n'; + return i < str.size(); } - fout.close(); + void fail(const std::string& message) + { + std::stringstream error; + error << "Error on line " << mLine << " in " << mFile << ":\n" << message; + throw std::runtime_error(error.str()); + } + + std::string mFile; + int mLine; +}; + +void Manager::loadDefault(const std::string &file) +{ + SettingsFileParser parser; + parser.loadSettingsFile(file, mDefaultSettings); } -std::string Manager::getString (const std::string& setting, const std::string& category) +void Manager::loadUser(const std::string &file) { - if (mNewSettings.find(std::make_pair(category, setting)) != mNewSettings.end()) - return mNewSettings[std::make_pair(category, setting)]; + SettingsFileParser parser; + parser.loadSettingsFile(file, mUserSettings); +} + +void Manager::saveUser(const std::string &file) +{ + boost::filesystem::ofstream stream; + stream.open(boost::filesystem::path(file)); + std::string currentCategory; + for (CategorySettingValueMap::iterator it = mUserSettings.begin(); it != mUserSettings.end(); ++it) + { + if (it->first.first != currentCategory) + { + currentCategory = it->first.first; + stream << "\n[" << currentCategory << "]\n"; + } + stream << it->first.second << " = " << it->second << "\n"; + } +} + +std::string Manager::getString(const std::string &setting, const std::string &category) +{ + CategorySettingValueMap::key_type key = std::make_pair(category, setting); + CategorySettingValueMap::iterator it = mUserSettings.find(key); + if (it != mUserSettings.end()) + return it->second; - std::string defaultval = mDefaultFile.getSetting(setting, category, "NOTFOUND"); - std::string val = mFile.getSetting(setting, category, defaultval); + it = mDefaultSettings.find(key); + if (it != mDefaultSettings.end()) + return it->second; - if (val == "NOTFOUND") - throw std::runtime_error("Trying to retrieve a non-existing setting: " + setting + " Make sure the settings-default.cfg file was properly installed."); - return val; + throw std::runtime_error(std::string("Trying to retrieve a non-existing setting: ") + setting + + ".\nMake sure the settings-default.cfg file file was properly installed."); } float Manager::getFloat (const std::string& setting, const std::string& category) @@ -107,51 +156,20 @@ bool Manager::getBool (const std::string& setting, const std::string& category) return Ogre::StringConverter::parseBool( getString(setting, category) ); } -void Manager::setString (const std::string& setting, const std::string& category, const std::string& value) +void Manager::setString(const std::string &setting, const std::string &category, const std::string &value) { - CategorySetting s = std::make_pair(category, setting); + CategorySettingValueMap::key_type key = std::make_pair(category, setting); - bool found=false; - try + CategorySettingValueMap::iterator found = mUserSettings.find(key); + if (found != mUserSettings.end()) { - Ogre::ConfigFile::SettingsIterator it = mFile.getSettingsIterator(category); - while (it.hasMoreElements()) - { - Ogre::ConfigFile::SettingsMultiMap::iterator i = it.current(); - - if ((*i).first == setting) - { - if ((*i).second != value) - { - mChangedSettings.push_back(std::make_pair(category, setting)); - (*i).second = value; - } - found = true; - } - - it.getNext(); - } + if (found->second == value) + return; } - catch (Ogre::Exception&) - {} - if (!found) - { - if (mNewSettings.find(s) != mNewSettings.end()) - { - if (mNewSettings[s] != value) - { - mChangedSettings.push_back(std::make_pair(category, setting)); - mNewSettings[s] = value; - } - } - else - { - if (mDefaultFile.getSetting(setting, category) != value) - mChangedSettings.push_back(std::make_pair(category, setting)); - mNewSettings[s] = value; - } - } + mUserSettings[key] = value; + + mChangedSettings.insert(key); } void Manager::setInt (const std::string& setting, const std::string& category, const int value) @@ -159,12 +177,12 @@ void Manager::setInt (const std::string& setting, const std::string& category, c setString(setting, category, Ogre::StringConverter::toString(value)); } -void Manager::setFloat (const std::string& setting, const std::string& category, const float value) +void Manager::setFloat (const std::string &setting, const std::string &category, const float value) { setString(setting, category, Ogre::StringConverter::toString(value)); } -void Manager::setBool (const std::string& setting, const std::string& category, const bool value) +void Manager::setBool(const std::string &setting, const std::string &category, const bool value) { setString(setting, category, Ogre::StringConverter::toString(value)); } @@ -175,3 +193,5 @@ const CategorySettingVector Manager::apply() mChangedSettings.clear(); return vec; } + +} diff --git a/components/settings/settings.hpp b/components/settings/settings.hpp index 03b0b517c..c16ff5a1e 100644 --- a/components/settings/settings.hpp +++ b/components/settings/settings.hpp @@ -1,12 +1,14 @@ #ifndef COMPONENTS_SETTINGS_H #define COMPONENTS_SETTINGS_H -#include +#include +#include +#include namespace Settings { typedef std::pair < std::string, std::string > CategorySetting; - typedef std::vector< std::pair > CategorySettingVector; + typedef std::set< std::pair > CategorySettingVector; typedef std::map < CategorySetting, std::string > CategorySettingValueMap; /// @@ -15,15 +17,12 @@ namespace Settings class Manager { public: - static Ogre::ConfigFile mFile; - static Ogre::ConfigFile mDefaultFile; + static CategorySettingValueMap mDefaultSettings; + static CategorySettingValueMap mUserSettings; static CategorySettingVector mChangedSettings; ///< tracks all the settings that were changed since the last apply() call - static CategorySettingValueMap mNewSettings; - ///< tracks all the settings that are in the default file, but not in user file yet - void loadDefault (const std::string& file); ///< load file as the default settings (can be overridden by user settings) From 955505c167800109590f4c56f40c679cef344611 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Feb 2015 01:05:40 +0100 Subject: [PATCH 0494/3725] Remove unused function --- apps/openmw/engine.cpp | 10 +--------- apps/openmw/engine.hpp | 4 ---- apps/openmw/mwgui/windowmanagerimp.cpp | 5 ++--- apps/openmw/mwgui/windowmanagerimp.hpp | 3 +-- 4 files changed, 4 insertions(+), 18 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index a9a7f0632..c70acaba8 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -170,7 +170,6 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) : mOgre (0) - , mFpsLevel(0) , mVerboseScripts (false) , mSkipMenu (false) , mUseSound (true) @@ -297,8 +296,6 @@ std::string OMW::Engine::loadSettings (Settings::Manager & settings) if (boost::filesystem::exists(settingspath)) settings.loadUser(settingspath); - mFpsLevel = settings.getInt("fps", "HUD"); - // load nif overrides NifOverrides::Overrides nifOverrides; std::string transparencyOverrides = "/transparency-overrides.cfg"; @@ -373,7 +370,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) mEnvironment.setInputManager (input); MWGui::WindowManager* window = new MWGui::WindowManager( - mExtensions, mFpsLevel, mOgre, mCfgMgr.getLogPath().string() + std::string("/"), + mExtensions, mOgre, mCfgMgr.getLogPath().string() + std::string("/"), mCfgMgr.getCachePath ().string(), mScriptConsoleMode, mTranslationDataStorage, mEncoding, mExportFonts, mFallbackMap); mEnvironment.setWindowManager (window); @@ -574,11 +571,6 @@ void OMW::Engine::setSoundUsage(bool soundUsage) mUseSound = soundUsage; } -void OMW::Engine::showFPS(int level) -{ - mFpsLevel = level; -} - void OMW::Engine::setEncoding(const ToUTF8::FromType& encoding) { mEncoding = encoding; diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index 079dd922c..3b088595c 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -71,7 +71,6 @@ namespace OMW OEngine::Render::OgreRenderer *mOgre; std::string mCellName; std::vector mContentFiles; - int mFpsLevel; bool mVerboseScripts; bool mSkipMenu; bool mUseSound; @@ -151,9 +150,6 @@ namespace OMW */ void addContentFile(const std::string& file); - /// Enable fps counter - void showFPS(int level); - /// Enable or disable verbose script output void setScriptsVerbosity(bool scriptsVerbosity); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index a35498dea..715f47c46 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -96,7 +96,7 @@ namespace MWGui { WindowManager::WindowManager( - const Compiler::Extensions& extensions, int fpsLevel, OEngine::Render::OgreRenderer *ogre, + const Compiler::Extensions& extensions, OEngine::Render::OgreRenderer *ogre, const std::string& logpath, const std::string& cacheDir, bool consoleOnlyScripts, Translation::Storage& translationDataStorage, ToUTF8::FromType encoding, bool exportFonts, const std::map& fallbackMap) : mConsoleOnlyScripts(consoleOnlyScripts) @@ -167,7 +167,6 @@ namespace MWGui , mForceHidden(GW_None) , mAllowed(GW_ALL) , mRestAllowed(true) - , mShowFPSLevel(fpsLevel) , mFPS(0.0f) , mTriangleCount(0) , mBatchCount(0) @@ -269,7 +268,7 @@ namespace MWGui trackWindow(mDialogueWindow, "dialogue"); mContainerWindow = new ContainerWindow(mDragAndDrop); trackWindow(mContainerWindow, "container"); - mHud = new HUD(mCustomMarkers, mShowFPSLevel, mDragAndDrop); + mHud = new HUD(mCustomMarkers, Settings::Manager::getInt("fps", "HUD"), mDragAndDrop); mToolTips = new ToolTips(); mScrollWindow = new ScrollWindow(); mBookWindow = new BookWindow(); diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index b3eb9cd0a..9f01b136c 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -97,7 +97,7 @@ namespace MWGui typedef std::pair Faction; typedef std::vector FactionList; - WindowManager(const Compiler::Extensions& extensions, int fpsLevel, + WindowManager(const Compiler::Extensions& extensions, OEngine::Render::OgreRenderer *mOgre, const std::string& logpath, const std::string& cacheDir, bool consoleOnlyScripts, Translation::Storage& translationDataStorage, ToUTF8::FromType encoding, bool exportFonts, const std::map& fallbackMap); @@ -451,7 +451,6 @@ namespace MWGui void updateVisible(); // Update visibility of all windows based on mode, shown and allowed settings - int mShowFPSLevel; float mFPS; unsigned int mTriangleCount; unsigned int mBatchCount; From ab9100fa904898606cc41f6df706b85a583bc2dc Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Feb 2015 13:12:58 +0100 Subject: [PATCH 0495/3725] Prevent dropping item on itself in ContentModel (Fixes #2334) Also improves the drop indicator, it is now shown in between items instead of on an item. --- components/contentselector/model/contentmodel.cpp | 7 +++---- components/contentselector/model/contentmodel.hpp | 1 - components/contentselector/view/contentselector.cpp | 3 ++- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/components/contentselector/model/contentmodel.cpp b/components/contentselector/model/contentmodel.cpp index b81b1cbf6..198bbffbb 100644 --- a/components/contentselector/model/contentmodel.cpp +++ b/components/contentselector/model/contentmodel.cpp @@ -15,8 +15,7 @@ ContentSelectorModel::ContentModel::ContentModel(QObject *parent, QIcon warningI mMimeType ("application/omwcontent"), mMimeTypes (QStringList() << mMimeType), mColumnCount (1), - mDragDropFlags (Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled), - mDropActions (Qt::CopyAction | Qt::MoveAction) + mDropActions (Qt::MoveAction) { setEncoding ("win1252"); uncheckAll(); @@ -104,7 +103,7 @@ QModelIndex ContentSelectorModel::ContentModel::indexFromItem(const EsmFile *ite Qt::ItemFlags ContentSelectorModel::ContentModel::flags(const QModelIndex &index) const { if (!index.isValid()) - return Qt::NoItemFlags; + return Qt::ItemIsDropEnabled; const EsmFile *file = item(index.row()); @@ -152,7 +151,7 @@ Qt::ItemFlags ContentSelectorModel::ContentModel::flags(const QModelIndex &index if (gamefileChecked) { if (allDependenciesFound) - returnFlags = returnFlags | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | mDragDropFlags; + returnFlags = returnFlags | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsDragEnabled; else returnFlags = Qt::ItemIsSelectable; } diff --git a/components/contentselector/model/contentmodel.hpp b/components/contentselector/model/contentmodel.hpp index 2ced40f04..6af5425c7 100644 --- a/components/contentselector/model/contentmodel.hpp +++ b/components/contentselector/model/contentmodel.hpp @@ -89,7 +89,6 @@ namespace ContentSelectorModel QString mMimeType; QStringList mMimeTypes; int mColumnCount; - Qt::ItemFlags mDragDropFlags; Qt::DropActions mDropActions; }; } diff --git a/components/contentselector/view/contentselector.cpp b/components/contentselector/view/contentselector.cpp index 2d560e054..ad023e5b2 100644 --- a/components/contentselector/view/contentselector.cpp +++ b/components/contentselector/view/contentselector.cpp @@ -15,7 +15,8 @@ ContentSelectorView::ContentSelector::ContentSelector(QWidget *parent) : QObject(parent) { - ui.setupUi (parent); + ui.setupUi(parent); + ui.addonView->setDragDropMode(QAbstractItemView::InternalMove); buildContentModel(); buildGameFileView(); From 2bf1dd8f46fa3bf19fb5416bc6b269631495a84f Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Feb 2015 14:01:31 +0100 Subject: [PATCH 0496/3725] Make the status badges consistent, again --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1698a7ebc..ed21b852f 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ OpenMW ====== -[![Build Status](https://img.shields.io/travis/OpenMW/openmw.svg)](https://travis-ci.org/OpenMW/openmw) [![Coverity Scan Build Status](https://scan.coverity.com/projects/3740/badge.svg)](https://scan.coverity.com/projects/3740) +[![Build Status](https://img.shields.io/travis/OpenMW/openmw.svg?style=plastic)](https://travis-ci.org/OpenMW/openmw) [![Coverity Scan Build Status](https://scan.coverity.com/projects/3740/badge.svg)](https://scan.coverity.com/projects/3740) 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. From aa6ebcd75cd95c5423b7216759f19cfc6d65224a Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Feb 2015 23:43:56 +0100 Subject: [PATCH 0497/3725] Change stolen items handling to match MW (Fixes #1443, Fixes #2290) --- apps/openmw/mwbase/mechanicsmanager.hpp | 4 +++- apps/openmw/mwgui/container.cpp | 2 +- apps/openmw/mwgui/inventorywindow.cpp | 2 +- .../mwmechanics/mechanicsmanagerimp.cpp | 24 ++++++++++++++++--- .../mwmechanics/mechanicsmanagerimp.hpp | 4 +++- apps/openmw/mwworld/actiontake.cpp | 2 +- 6 files changed, 30 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index 33a2ef1ea..58f2f6ee5 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -129,7 +129,9 @@ namespace MWBase /// @return false if the attack was considered a "friendly hit" and forgiven virtual bool actorAttacked (const MWWorld::Ptr& victim, const MWWorld::Ptr& attacker) = 0; /// Utility to check if taking this item is illegal and calling commitCrime if so - virtual void itemTaken (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, int count) = 0; + /// @param container The container the item is in; may be empty for an item in the world + virtual void itemTaken (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, const MWWorld::Ptr& container, + int count) = 0; /// Utility to check if opening (i.e. unlocking) this object is illegal and calling commitCrime if so virtual void objectOpened (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item) = 0; /// Attempt sleeping in a bed. If this is illegal, call commitCrime. diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 53b1e679a..579730f42 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -285,7 +285,7 @@ namespace MWGui if (mPtr.getClass().isActor() && mPtr.getClass().getCreatureStats(mPtr).isDead()) return true; else - MWBase::Environment::get().getMechanicsManager()->itemTaken(player, item.mBase, count); + MWBase::Environment::get().getMechanicsManager()->itemTaken(player, item.mBase, mPtr, count); } return true; } diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index ae7d60d44..5cb67c048 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -624,7 +624,7 @@ namespace MWGui throw std::runtime_error("Added item not found"); mDragAndDrop->startDrag(i, mSortModel, mTradeModel, mItemView, count); - MWBase::Environment::get().getMechanicsManager()->itemTaken(player, newObject, count); + MWBase::Environment::get().getMechanicsManager()->itemTaken(player, newObject, MWWorld::Ptr(), count); if (MWBase::Environment::get().getWindowManager()->getSpellWindow()) MWBase::Environment::get().getWindowManager()->getSpellWindow()->updateSpells(); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index d52dcb43c..caa242338 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -936,11 +936,29 @@ namespace MWMechanics commitCrime(ptr, victim, OT_Trespassing); } - void MechanicsManager::itemTaken(const MWWorld::Ptr &ptr, const MWWorld::Ptr &item, int count) + void MechanicsManager::itemTaken(const MWWorld::Ptr &ptr, const MWWorld::Ptr &item, const MWWorld::Ptr& container, + int count) { MWWorld::Ptr victim; - if (isAllowedToUse(ptr, item, victim)) - return; + + if (!container.isEmpty()) + { + // Inherit the owner of the container + if (isAllowedToUse(ptr, container, victim)) + return; + } + else + { + if (isAllowedToUse(ptr, item, victim)) + return; + + if (!item.getCellRef().hasContentFile()) + { + // this is a manually placed item, which means it was already stolen + return; + } + } + commitCrime(ptr, victim, OT_Theft, item.getClass().getValue(item) * count); } diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index 2f443ad59..79580c050 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -121,7 +121,9 @@ namespace MWMechanics /// @return false if the attack was considered a "friendly hit" and forgiven virtual bool actorAttacked (const MWWorld::Ptr& victim, const MWWorld::Ptr& attacker); /// Utility to check if taking this item is illegal and calling commitCrime if so - virtual void itemTaken (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, int count); + /// @param container The container the item is in; may be empty for an item in the world + virtual void itemTaken (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, const MWWorld::Ptr& container, + int count); /// Utility to check if opening (i.e. unlocking) this object is illegal and calling commitCrime if so virtual void objectOpened (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item); /// Attempt sleeping in a bed. If this is illegal, call commitCrime. diff --git a/apps/openmw/mwworld/actiontake.cpp b/apps/openmw/mwworld/actiontake.cpp index 548a94981..269d941dc 100644 --- a/apps/openmw/mwworld/actiontake.cpp +++ b/apps/openmw/mwworld/actiontake.cpp @@ -16,7 +16,7 @@ namespace MWWorld void ActionTake::executeImp (const Ptr& actor) { MWBase::Environment::get().getMechanicsManager()->itemTaken( - actor, getTarget(), getTarget().getRefData().getCount()); + actor, getTarget(), MWWorld::Ptr(), getTarget().getRefData().getCount()); actor.getClass().getContainerStore (actor).add (getTarget(), getTarget().getRefData().getCount(), actor); MWBase::Environment::get().getWorld()->deleteObject (getTarget()); } From 8087a7d920ebd20d63f0b820856a45e795b9ab2c Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 4 Feb 2015 00:21:35 +0100 Subject: [PATCH 0498/3725] Add possibility to dress up corpses (Fixes #2221) --- apps/openmw/mwworld/inventorystore.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 4950be912..020f9561a 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -133,12 +133,11 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::add(const Ptr& itemPtr, const MWWorld::ContainerStoreIterator& retVal = MWWorld::ContainerStore::add(itemPtr, count, actorPtr, setOwner); // Auto-equip items if an armor/clothing or weapon item is added, but not for the player nor werewolves - if ((actorPtr.getRefData().getHandle() != "player") - && !(actorPtr.getClass().isNpc() && actorPtr.getClass().getNpcStats(actorPtr).isWerewolf()) - && !actorPtr.getClass().getCreatureStats(actorPtr).isDead()) + if (actorPtr.getRefData().getHandle() != "player" + && !(actorPtr.getClass().isNpc() && actorPtr.getClass().getNpcStats(actorPtr).isWerewolf())) { std::string type = itemPtr.getTypeName(); - if ((type == typeid(ESM::Armor).name()) || (type == typeid(ESM::Clothing).name()) || (type == typeid(ESM::Weapon).name())) + if (type == typeid(ESM::Armor).name() || type == typeid(ESM::Clothing).name()) autoEquip(actorPtr); } @@ -234,7 +233,9 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor) // ...unless this is a companion, he should always equip items given to him. if (!Misc::StringUtils::ciEqual(test.getCellRef().getOwner(), actor.getCellRef().getRefId()) && (actor.getClass().getScript(actor).empty() || - !actor.getRefData().getLocals().getIntVar(actor.getClass().getScript(actor), "companion"))) + !actor.getRefData().getLocals().getIntVar(actor.getClass().getScript(actor), "companion")) + && !actor.getClass().getCreatureStats(actor).isDead() // Corpses can be dressed up by the player as desired + ) { continue; } @@ -506,8 +507,7 @@ int MWWorld::InventoryStore::remove(const Ptr& item, int count, const Ptr& actor && !(actor.getClass().isNpc() && actor.getClass().getNpcStats(actor).isWerewolf())) { std::string type = item.getTypeName(); - if (((type == typeid(ESM::Armor).name()) || (type == typeid(ESM::Clothing).name())) - && !actor.getClass().getCreatureStats(actor).isDead()) + if (type == typeid(ESM::Armor).name() || type == typeid(ESM::Clothing).name()) autoEquip(actor); } From f8b4ff300412344c652a104b8d77ecc7aa281b0f Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 4 Feb 2015 01:25:37 +0100 Subject: [PATCH 0499/3725] Documentation fix --- components/terrain/quadtreenode.hpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/components/terrain/quadtreenode.hpp b/components/terrain/quadtreenode.hpp index 626572701..e8392b8e4 100644 --- a/components/terrain/quadtreenode.hpp +++ b/components/terrain/quadtreenode.hpp @@ -98,7 +98,6 @@ namespace Terrain DefaultWorld* getTerrain() { return mTerrain; } /// Adjust LODs for the given camera position, possibly splitting up chunks or merging them. - /// @param force Always choose to render this node, even if not the perfect LOD. /// @return Did we (or all of our children) choose to render? bool update (const Ogre::Vector3& cameraPos); @@ -124,7 +123,6 @@ namespace Terrain /// call this method on their children. /// @note Do not call this before World::areLayersLoaded() == true /// @param area area in image space to put the quad - /// @param quads collect quads here so they can be deleted later void prepareForCompositeMap(Ogre::TRect area); /// Create a chunk for this node from the given data. From c1862cbfc28063be922c98f39e2a7489596a7211 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 4 Feb 2015 02:39:47 +0100 Subject: [PATCH 0500/3725] Clarify documentation for --load-savegame --- README.md | 4 +++- apps/openmw/main.cpp | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ed21b852f..9207c5728 100644 --- a/README.md +++ b/README.md @@ -68,7 +68,9 @@ Command line options of the blacklist is enabled) --script-blacklist-use [=arg(=1)] (=1) enable script blacklisting - --load-savegame arg load a save game file on game startup + --load-savegame arg load a save game file on game startup + (specify an absolute or relative + filename for this option) --skip-menu [=arg(=1)] (=0) skip main menu on game startup --new-game [=arg(=1)] (=0) run new game sequence (ignored if skip-menu=0) diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index b96b90989..f4875e68a 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -153,7 +153,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat ->default_value(true), "enable script blacklisting") ("load-savegame", bpo::value()->default_value(""), - "load a save game file on game startup") + "load a save game file on game startup (specify an absolute or relative filename for this option)") ("skip-menu", bpo::value()->implicit_value(true) ->default_value(false), "skip main menu on game startup") From 9d9cabf40d1b6fd73c90db416de8c4b9bf980b87 Mon Sep 17 00:00:00 2001 From: dteviot Date: Fri, 6 Feb 2015 12:24:06 +1300 Subject: [PATCH 0501/3725] Fix: Importer creates a single Content List (Fixes #2345) --- apps/launcher/datafilespage.cpp | 9 ++++++--- apps/launcher/datafilespage.hpp | 4 ++++ apps/launcher/settingspage.cpp | 22 +++++++++++++++++----- 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index ff1364b08..7861894b0 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -20,6 +20,9 @@ #include "utils/textinputdialog.hpp" #include "utils/profilescombobox.hpp" + +const char *Launcher::DataFilesPage::mDefaultContentListName = "Default"; + Launcher::DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, Config::GameSettings &gameSettings, Config::LauncherSettings &launcherSettings, QWidget *parent) : mCfgMgr(cfg) , mGameSettings(gameSettings) @@ -48,9 +51,9 @@ void Launcher::DataFilesPage::buildView() ui.deleteProfileButton->setToolTip ("Delete an existing Content List"); //combo box - ui.profilesComboBox->addItem ("Default"); + ui.profilesComboBox->addItem(mDefaultContentListName); ui.profilesComboBox->setPlaceholderText (QString("Select a Content List...")); - ui.profilesComboBox->setCurrentIndex(ui.profilesComboBox->findText(QLatin1String("Default"))); + ui.profilesComboBox->setCurrentIndex(ui.profilesComboBox->findText(QLatin1String(mDefaultContentListName))); // Add the actions to the toolbuttons ui.newProfileButton->setDefaultAction (ui.newProfileAction); @@ -284,7 +287,7 @@ void Launcher::DataFilesPage::updateOkButton(const QString &text) void Launcher::DataFilesPage::checkForDefaultProfile() { //don't allow deleting "Default" profile - bool success = (ui.profilesComboBox->currentText() != "Default"); + bool success = (ui.profilesComboBox->currentText() != mDefaultContentListName); ui.deleteProfileAction->setEnabled (success); ui.profilesComboBox->setEditEnabled (success); diff --git a/apps/launcher/datafilespage.hpp b/apps/launcher/datafilespage.hpp index 73b840c5c..1e0fc8e7a 100644 --- a/apps/launcher/datafilespage.hpp +++ b/apps/launcher/datafilespage.hpp @@ -58,6 +58,10 @@ namespace Launcher void on_newProfileAction_triggered(); void on_deleteProfileAction_triggered(); + public: + /// Content List that is aways present + const static char *mDefaultContentListName; + private: TextInputDialog *mProfileDialog; diff --git a/apps/launcher/settingspage.cpp b/apps/launcher/settingspage.cpp index ace8f4310..88c60766b 100644 --- a/apps/launcher/settingspage.cpp +++ b/apps/launcher/settingspage.cpp @@ -11,6 +11,7 @@ #include #include "utils/textinputdialog.hpp" +#include "datafilespage.hpp" using namespace Process; @@ -198,22 +199,33 @@ void Launcher::SettingsPage::importerFinished(int exitCode, QProcess::ExitStatus if (exitCode != 0 || exitStatus == QProcess::CrashExit) return; - // Re-read the settings in their current state + // Importer may have changed settings, so refresh mMain->reloadSettings(); // Import selected data files from openmw.cfg if (addonsCheckBox->isChecked()) { + // Because we've reloaded settings, the current content list matches content in OpenMW.cfg + QString oldContentListName = mLauncherSettings.getCurrentContentListName(); if (mProfileDialog->exec() == QDialog::Accepted) { - const QString profile(mProfileDialog->lineEdit()->text()); + // remove the current content list to prevent duplication + //... except, not allowed to delete the Default content list + if (oldContentListName.compare(DataFilesPage::mDefaultContentListName) != 0) + { + mLauncherSettings.removeContentList(oldContentListName); + } + + const QString newContentListName(mProfileDialog->lineEdit()->text()); const QStringList files(mGameSettings.getContentList()); - mLauncherSettings.setCurrentContentListName(profile); - mLauncherSettings.setContentList(profile, files); + mLauncherSettings.setCurrentContentListName(newContentListName); + mLauncherSettings.setContentList(newContentListName, files); + + // Make DataFiles Page load the new content list. + mMain->reloadSettings(); } } - mMain->reloadSettings(); importerButton->setEnabled(true); } From cac250a90d213d33e0560b0b49da1b17c790bba0 Mon Sep 17 00:00:00 2001 From: dteviot Date: Fri, 6 Feb 2015 12:45:15 +1300 Subject: [PATCH 0502/3725] Fixed typo in comment. --- apps/launcher/datafilespage.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/launcher/datafilespage.hpp b/apps/launcher/datafilespage.hpp index 1e0fc8e7a..d25d20fc9 100644 --- a/apps/launcher/datafilespage.hpp +++ b/apps/launcher/datafilespage.hpp @@ -59,7 +59,7 @@ namespace Launcher void on_deleteProfileAction_triggered(); public: - /// Content List that is aways present + /// Content List that is always present const static char *mDefaultContentListName; private: From bea88c3643b78ddf81dbb50a367688b2b16589f9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 4 Feb 2015 21:18:43 +0100 Subject: [PATCH 0503/3725] Stolen item tracking overhaul part 2 (Fixes #2338) --- apps/openmw/mwbase/mechanicsmanager.hpp | 12 +- apps/openmw/mwclass/container.cpp | 9 +- apps/openmw/mwclass/creature.cpp | 5 +- apps/openmw/mwclass/npc.cpp | 6 +- apps/openmw/mwgui/enchantingdialog.cpp | 3 +- apps/openmw/mwgui/inventoryitemmodel.cpp | 11 +- apps/openmw/mwgui/itemmodel.hpp | 13 +- apps/openmw/mwgui/tooltips.cpp | 10 ++ apps/openmw/mwgui/tradeitemmodel.cpp | 4 +- apps/openmw/mwgui/tradewindow.cpp | 5 +- .../mwmechanics/mechanicsmanagerimp.cpp | 120 +++++++++++++++--- .../mwmechanics/mechanicsmanagerimp.hpp | 20 ++- apps/openmw/mwstate/statemanagerimp.cpp | 1 + apps/openmw/mwworld/cellref.cpp | 9 ++ apps/openmw/mwworld/cellref.hpp | 2 + apps/openmw/mwworld/class.hpp | 2 + apps/openmw/mwworld/containerstore.cpp | 53 ++++---- apps/openmw/mwworld/containerstore.hpp | 8 +- apps/openmw/mwworld/worldimp.cpp | 14 +- components/CMakeLists.txt | 2 +- components/esm/defs.hpp | 1 + components/esm/stolenitems.cpp | 47 +++++++ components/esm/stolenitems.hpp | 24 ++++ 23 files changed, 289 insertions(+), 92 deletions(-) create mode 100644 components/esm/stolenitems.cpp create mode 100644 components/esm/stolenitems.hpp diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index 58f2f6ee5..f7fc515f5 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -138,9 +138,6 @@ namespace MWBase /// @return was it illegal, and someone saw you doing it? virtual bool sleepInBed (const MWWorld::Ptr& ptr, const MWWorld::Ptr& bed) = 0; - /// @return is \a ptr allowed to take/use \a item or is it a crime? - virtual bool isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, MWWorld::Ptr& victim) = 0; - enum PersuasionType { PT_Admire, @@ -205,6 +202,15 @@ namespace MWBase virtual void keepPlayerAlive() = 0; virtual bool isReadyToBlock (const MWWorld::Ptr& ptr) const = 0; + + virtual void confiscateStolenItems (const MWWorld::Ptr& player, const MWWorld::Ptr& targetContainer) = 0; + + /// List the owners that the player has stolen this item from (the owner can be an NPC or a faction). + /// + virtual std::vector > getStolenItemOwners(const std::string& itemid) = 0; + + /// Has the player stolen this item from the given owner? + virtual bool isItemStolenFrom(const std::string& itemid, const std::string& ownerid) = 0; }; } diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index c6a7bbf74..5f49a74b6 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -59,8 +59,10 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); + // setting ownership not needed, since taking items from a container inherits the + // container's owner automatically data->mContainerStore.fill( - ref->mBase->mInventory, ptr.getCellRef().getOwner(), ptr.getCellRef().getFaction(), ptr.getCellRef().getFactionRank(), MWBase::Environment::get().getWorld()->getStore()); + ref->mBase->mInventory, ""); // store ptr.getRefData().setCustomData (data.release()); @@ -82,7 +84,10 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); const ESM::InventoryList& list = ref->mBase->mInventory; MWWorld::ContainerStore& store = getContainerStore(ptr); - store.restock(list, ptr, ptr.getCellRef().getOwner(), ptr.getCellRef().getFaction(), ptr.getCellRef().getFactionRank()); + + // setting ownership not needed, since taking items from a container inherits the + // container's owner automatically + store.restock(list, ptr, ""); } void Container::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index df3f9c0d3..e44f4ffc1 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -139,8 +139,7 @@ namespace MWClass // store ptr.getRefData().setCustomData(data.release()); - getContainerStore(ptr).fill(ref->mBase->mInventory, getId(ptr), "", -1, - MWBase::Environment::get().getWorld()->getStore()); + getContainerStore(ptr).fill(ref->mBase->mInventory, getId(ptr)); if (ref->mBase->mFlags & ESM::Creature::Weapon) getInventoryStore(ptr).autoEquip(ptr); @@ -886,7 +885,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); const ESM::InventoryList& list = ref->mBase->mInventory; MWWorld::ContainerStore& store = getContainerStore(ptr); - store.restock(list, ptr, ptr.getCellRef().getRefId(), "", -1); + store.restock(list, ptr, ptr.getCellRef().getRefId()); } int Creature::getBaseFightRating(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index c55f81d91..cedff1291 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -384,8 +384,8 @@ namespace MWClass } // inventory - data->mInventoryStore.fill(ref->mBase->mInventory, getId(ptr), "", -1, - MWBase::Environment::get().getWorld()->getStore()); + // setting ownership is used to make the NPC auto-equip his initial equipment only, and not bartered items + data->mInventoryStore.fill(ref->mBase->mInventory, getId(ptr)); data->mNpcStats.setGoldPool(gold); @@ -1328,7 +1328,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); const ESM::InventoryList& list = ref->mBase->mInventory; MWWorld::ContainerStore& store = getContainerStore(ptr); - store.restock(list, ptr, ptr.getCellRef().getRefId(), "", -1); + store.restock(list, ptr, ptr.getCellRef().getRefId()); } int Npc::getBaseFightRating (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 3376858c1..43f2493a9 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -339,7 +339,8 @@ namespace MWGui for (int i=0; i<2; ++i) { MWWorld::Ptr item = (i == 0) ? mEnchanting.getOldItem() : mEnchanting.getGem(); - if (Misc::StringUtils::ciEqual(item.getCellRef().getOwner(), mPtr.getCellRef().getRefId())) + if (MWBase::Environment::get().getMechanicsManager()->isItemStolenFrom(item.getCellRef().getRefId(), + mPtr.getCellRef().getRefId())) { std::string msg = MWBase::Environment::get().getWorld()->getStore().get().find("sNotifyMessage49")->getString(); if (msg.find("%s") != std::string::npos) diff --git a/apps/openmw/mwgui/inventoryitemmodel.cpp b/apps/openmw/mwgui/inventoryitemmodel.cpp index cee0dc6ee..e8354b740 100644 --- a/apps/openmw/mwgui/inventoryitemmodel.cpp +++ b/apps/openmw/mwgui/inventoryitemmodel.cpp @@ -65,16 +65,7 @@ MWWorld::Ptr InventoryItemModel::moveItem(const ItemStack &item, size_t count, I if (item.mFlags & ItemStack::Flag_Bound) return MWWorld::Ptr(); - bool setNewOwner = false; - - // Are you dead? Then you wont need that anymore - if (mActor.getClass().isActor() && mActor.getClass().getCreatureStats(mActor).isDead() - // Make sure that the item is actually owned by the dead actor - // Prevents a potential exploit for resetting the owner of any item, by placing the item in a corpse - && Misc::StringUtils::ciEqual(item.mBase.getCellRef().getOwner(), mActor.getCellRef().getRefId())) - setNewOwner = true; - - MWWorld::Ptr ret = otherModel->copyItem(item, count, setNewOwner); + MWWorld::Ptr ret = otherModel->copyItem(item, count, false); removeItem(item, count); return ret; } diff --git a/apps/openmw/mwgui/itemmodel.hpp b/apps/openmw/mwgui/itemmodel.hpp index c1b243a76..53c7018e2 100644 --- a/apps/openmw/mwgui/itemmodel.hpp +++ b/apps/openmw/mwgui/itemmodel.hpp @@ -46,20 +46,27 @@ namespace MWGui ItemModel(); virtual ~ItemModel() {} - typedef int ModelIndex; + typedef int ModelIndex; // -1 means invalid index + /// Throws for invalid index or out of range index virtual ItemStack getItem (ModelIndex index) = 0; - ///< throws for invalid index + + /// The number of items in the model, this specifies the range of indices you can pass to + /// the getItem function (but this range is only valid until the next call to update()) virtual size_t getItemCount() = 0; + /// Returns an invalid index if the item was not found virtual ModelIndex getIndex (ItemStack item) = 0; + /// Rebuild the item model, this will invalidate existing model indices virtual void update() = 0; /// Move items from this model to \a otherModel. + /// @note Derived implementations may return an empty Ptr if the move was unsuccessful. virtual MWWorld::Ptr moveItem (const ItemStack& item, size_t count, ItemModel* otherModel); - /// @param setNewOwner Set the copied item's owner to the actor we are copying to, or keep the original owner? + /// @param setNewOwner If true, set the copied item's owner to the actor we are copying to, + /// otherwise reset owner to "" virtual MWWorld::Ptr copyItem (const ItemStack& item, size_t count, bool setNewOwner=false) = 0; virtual void removeItem (const ItemStack& item, size_t count) = 0; diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 275071737..c6210ac64 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -13,6 +13,7 @@ #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwbase/mechanicsmanager.hpp" #include "../mwworld/class.hpp" #include "../mwworld/esmstore.hpp" @@ -586,6 +587,15 @@ namespace MWGui ret += getMiscString(cellref.getFaction(), "Faction"); if (cellref.getFactionRank() > 0) ret += getValueString(cellref.getFactionRank(), "Rank"); + + std::vector > itemOwners = + MWBase::Environment::get().getMechanicsManager()->getStolenItemOwners(cellref.getRefId()); + + for (std::vector >::const_iterator it = itemOwners.begin(); it != itemOwners.end(); ++it) + { + ret += std::string("\nStolen ") + MyGUI::utility::toString(it->second) + " from " + it->first; + } + ret += getMiscString(cellref.getGlobalVariable(), "Global"); return ret; } diff --git a/apps/openmw/mwgui/tradeitemmodel.cpp b/apps/openmw/mwgui/tradeitemmodel.cpp index df0cbcac9..a5a2b3e88 100644 --- a/apps/openmw/mwgui/tradeitemmodel.cpp +++ b/apps/openmw/mwgui/tradeitemmodel.cpp @@ -135,11 +135,9 @@ namespace MWGui if (i == sourceModel->getItemCount()) throw std::runtime_error("The borrowed item disappeared"); - // reset owner while copying, but only for items bought by the player - bool setNewOwner = (mMerchant.isEmpty()); const ItemStack& item = sourceModel->getItem(i); // copy the borrowed items to our model - copyItem(item, it->mCount, setNewOwner); + copyItem(item, it->mCount); // then remove them from the source model sourceModel->removeItem(item, it->mCount); } diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index fab7c63a6..87b2362ef 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -300,7 +300,8 @@ namespace MWGui // check if the player is attempting to sell back an item stolen from this actor for (std::vector::iterator it = merchantBought.begin(); it != merchantBought.end(); ++it) { - if (Misc::StringUtils::ciEqual(it->mBase.getCellRef().getOwner(), mPtr.getCellRef().getRefId())) + if (MWBase::Environment::get().getMechanicsManager()->isItemStolenFrom(it->mBase.getCellRef().getRefId(), + mPtr.getCellRef().getRefId())) { std::string msg = gmst.find("sNotifyMessage49")->getString(); if (msg.find("%s") != std::string::npos) @@ -315,6 +316,8 @@ namespace MWGui } } + // TODO: move to mwmechanics + // Is the player buying? bool buying = (mCurrentMerchantOffer < 0); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index caa242338..4e4a1a8a6 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -2,6 +2,8 @@ #include "mechanicsmanagerimp.hpp" #include "npcstats.hpp" +#include + #include "../mwworld/esmstore.hpp" #include "../mwworld/inventorystore.hpp" @@ -873,31 +875,31 @@ namespace MWMechanics mAI = true; } - bool MechanicsManager::isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, MWWorld::Ptr& victim) + bool MechanicsManager::isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::CellRef& cellref, MWWorld::Ptr& victim) { - const std::string& owner = item.getCellRef().getOwner(); + const std::string& owner = cellref.getOwner(); bool isOwned = !owner.empty() && owner != "player"; - const std::string& faction = item.getCellRef().getFaction(); + const std::string& faction = cellref.getFaction(); bool isFactionOwned = false; if (!faction.empty() && ptr.getClass().isNpc()) { const std::map& factions = ptr.getClass().getNpcStats(ptr).getFactionRanks(); std::map::const_iterator found = factions.find(Misc::StringUtils::lowerCase(faction)); if (found == factions.end() - || found->second < item.getCellRef().getFactionRank()) + || found->second < cellref.getFactionRank()) isFactionOwned = true; } - const std::string& globalVariable = item.getCellRef().getGlobalVariable(); + const std::string& globalVariable = cellref.getGlobalVariable(); if (!globalVariable.empty() && MWBase::Environment::get().getWorld()->getGlobalInt(Misc::StringUtils::lowerCase(globalVariable)) == 1) { isOwned = false; isFactionOwned = false; } - if (!item.getCellRef().getOwner().empty()) - victim = MWBase::Environment::get().getWorld()->searchPtr(item.getCellRef().getOwner(), true); + if (!cellref.getOwner().empty()) + victim = MWBase::Environment::get().getWorld()->searchPtr(cellref.getOwner(), true); return (!isOwned && !isFactionOwned); } @@ -916,7 +918,7 @@ namespace MWMechanics } MWWorld::Ptr victim; - if (isAllowedToUse(ptr, bed, victim)) + if (isAllowedToUse(ptr, bed.getCellRef(), victim)) return false; if(commitCrime(ptr, victim, OT_SleepingInOwnedBed)) @@ -931,27 +933,82 @@ namespace MWMechanics void MechanicsManager::objectOpened(const MWWorld::Ptr &ptr, const MWWorld::Ptr &item) { MWWorld::Ptr victim; - if (isAllowedToUse(ptr, item, victim)) + if (isAllowedToUse(ptr, item.getCellRef(), victim)) return; commitCrime(ptr, victim, OT_Trespassing); } + std::vector > MechanicsManager::getStolenItemOwners(const std::string& itemid) + { + std::vector > result; + StolenItemsMap::const_iterator it = mStolenItems.find(Misc::StringUtils::lowerCase(itemid)); + if (it == mStolenItems.end()) + return result; + else + { + const OwnerMap& owners = it->second; + for (OwnerMap::const_iterator ownerIt = owners.begin(); ownerIt != owners.end(); ++ownerIt) + result.push_back(std::make_pair(ownerIt->first.first, ownerIt->second)); + return result; + } + } + + bool MechanicsManager::isItemStolenFrom(const std::string &itemid, const std::string &ownerid) + { + StolenItemsMap::const_iterator it = mStolenItems.find(Misc::StringUtils::lowerCase(itemid)); + if (it == mStolenItems.end()) + return false; + const OwnerMap& owners = it->second; + OwnerMap::const_iterator ownerFound = owners.find(std::make_pair(Misc::StringUtils::lowerCase(ownerid), false)); + return ownerFound != owners.end(); + } + + void MechanicsManager::confiscateStolenItems(const MWWorld::Ptr &player, const MWWorld::Ptr &targetContainer) + { + MWWorld::ContainerStore& store = player.getClass().getContainerStore(player); + for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it) + { + StolenItemsMap::iterator stolenIt = mStolenItems.find(Misc::StringUtils::lowerCase(it->getClass().getId(*it))); + if (stolenIt == mStolenItems.end()) + continue; + OwnerMap& owners = stolenIt->second; + int itemCount = it->getRefData().getCount(); + for (OwnerMap::iterator ownerIt = owners.begin(); ownerIt != owners.end();) + { + int toRemove = std::min(itemCount, ownerIt->second); + itemCount -= toRemove; + ownerIt->second -= toRemove; + if (ownerIt->second == 0) + owners.erase(ownerIt++); + else + ++ownerIt; + } + + int toMove = it->getRefData().getCount() - itemCount; + + targetContainer.getClass().getContainerStore(targetContainer).add(*it, toMove, targetContainer); + store.remove(*it, toMove, player); + } + // TODO: unhardcode the locklevel + targetContainer.getClass().lock(targetContainer,50); + } + void MechanicsManager::itemTaken(const MWWorld::Ptr &ptr, const MWWorld::Ptr &item, const MWWorld::Ptr& container, int count) { + if (ptr != MWBase::Environment::get().getWorld()->getPlayerPtr()) + return; + MWWorld::Ptr victim; + const MWWorld::CellRef* ownerCellRef = &item.getCellRef(); if (!container.isEmpty()) { // Inherit the owner of the container - if (isAllowedToUse(ptr, container, victim)) - return; + ownerCellRef = &container.getCellRef(); } else { - if (isAllowedToUse(ptr, item, victim)) - return; - if (!item.getCellRef().hasContentFile()) { // this is a manually placed item, which means it was already stolen @@ -959,6 +1016,20 @@ namespace MWMechanics } } + if (isAllowedToUse(ptr, *ownerCellRef, victim)) + return; + + Owner owner; + owner.first = ownerCellRef->getOwner(); + owner.second = false; + if (owner.first.empty()) + { + owner.first = ownerCellRef->getFaction(); + owner.second = true; + } + Misc::StringUtils::toLower(owner.first); + mStolenItems[Misc::StringUtils::lowerCase(item.getClass().getId(item))][owner] += count; + commitCrime(ptr, victim, OT_Theft, item.getClass().getValue(item) * count); } @@ -967,7 +1038,7 @@ namespace MWMechanics // NOTE: victim may be empty // Only player can commit crime - if (player.getRefData().getHandle() != "player") + if (player != MWBase::Environment::get().getWorld()->getPlayerPtr()) return false; // Find all the actors within the alarm radius @@ -1369,22 +1440,37 @@ namespace MWMechanics int MechanicsManager::countSavedGameRecords() const { - return 1; // Death counter + return 1 // Death counter + +1; // Stolen items } void MechanicsManager::write(ESM::ESMWriter &writer, Loading::Listener &listener) const { mActors.write(writer, listener); + + ESM::StolenItems items; + items.mStolenItems = mStolenItems; + writer.startRecord(ESM::REC_STLN); + items.write(writer); + writer.endRecord(ESM::REC_STLN); } void MechanicsManager::readRecord(ESM::ESMReader &reader, uint32_t type) { - mActors.readRecord(reader, type); + if (type == ESM::REC_STLN) + { + ESM::StolenItems items; + items.load(reader); + mStolenItems = items.mStolenItems; + } + else + mActors.readRecord(reader, type); } void MechanicsManager::clear() { mActors.clear(); + mStolenItems.clear(); } bool MechanicsManager::isAggressive(const MWWorld::Ptr &ptr, const MWWorld::Ptr &target) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index 79580c050..d08334ae8 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -35,6 +35,11 @@ namespace MWMechanics Objects mObjects; Actors mActors; + typedef std::pair Owner; // < Owner id, bool isFaction > + typedef std::map OwnerMap; // < Owner, number of stolen items with this id from this owner > + typedef std::map StolenItemsMap; + StolenItemsMap mStolenItems; + public: void buildPlayer(); @@ -130,9 +135,6 @@ namespace MWMechanics /// @return was it illegal, and someone saw you doing it? Also returns fail when enemies are nearby virtual bool sleepInBed (const MWWorld::Ptr& ptr, const MWWorld::Ptr& bed); - /// @return is \a ptr allowed to take/use \a item or is it a crime? - virtual bool isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, MWWorld::Ptr& victim); - virtual void forceStateUpdate(const MWWorld::Ptr &ptr); virtual void playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number); @@ -170,9 +172,21 @@ namespace MWMechanics virtual bool isReadyToBlock (const MWWorld::Ptr& ptr) const; + virtual void confiscateStolenItems (const MWWorld::Ptr& player, const MWWorld::Ptr& targetContainer); + + /// List the owners that the player has stolen this item from (the owner can be an NPC or a faction). + /// + virtual std::vector > getStolenItemOwners(const std::string& itemid); + + /// Has the player stolen this item from the given owner? + virtual bool isItemStolenFrom(const std::string& itemid, const std::string& ownerid); + private: void reportCrime (const MWWorld::Ptr& ptr, const MWWorld::Ptr& victim, OffenseType type, int arg=0); + + /// @return is \a ptr allowed to take/use \a cellref or is it a crime? + virtual bool isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::CellRef& cellref, MWWorld::Ptr& victim); }; } diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index d623ba465..0883bc63b 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -421,6 +421,7 @@ void MWState::StateManager::loadGame (const Character *character, const std::str break; case ESM::REC_DCOU: + case ESM::REC_STLN: MWBase::Environment::get().getMechanicsManager()->readRecord(reader, n.val); break; diff --git a/apps/openmw/mwworld/cellref.cpp b/apps/openmw/mwworld/cellref.cpp index d2cced3b8..0d81e0636 100644 --- a/apps/openmw/mwworld/cellref.cpp +++ b/apps/openmw/mwworld/cellref.cpp @@ -117,6 +117,15 @@ namespace MWWorld return mCellRef.mGlobalVariable; } + void CellRef::resetGlobalVariable() + { + if (!mCellRef.mGlobalVariable.empty()) + { + mChanged = true; + mCellRef.mGlobalVariable.erase(); + } + } + void CellRef::setFactionRank(int factionRank) { if (factionRank != mCellRef.mFactionRank) diff --git a/apps/openmw/mwworld/cellref.hpp b/apps/openmw/mwworld/cellref.hpp index f063b2727..b8e85f286 100644 --- a/apps/openmw/mwworld/cellref.hpp +++ b/apps/openmw/mwworld/cellref.hpp @@ -75,6 +75,8 @@ namespace MWWorld // Used by bed rent scripts to allow the player to use the bed for the duration of the rent. std::string getGlobalVariable() const; + void resetGlobalVariable(); + // ID of creature trapped in this soul gem std::string getSoul() const; void setSoul(const std::string& soul); diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 751375c55..380d2a34b 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -80,6 +80,8 @@ namespace MWWorld virtual std::string getId (const Ptr& ptr) const; ///< Return ID of \a ptr or throw an exception, if class does not support ID retrieval /// (default implementation: throw an exception) + /// @note This function is currently redundant; the same ID can be retrieved by CellRef::getRefId. + /// Leaving it here for now in case we want to optimize later. virtual void insertObjectRendering (const Ptr& ptr, const std::string& mesh, MWRender::RenderingInterface& renderingInterface) const; virtual void insertObject(const Ptr& ptr, const std::string& mesh, MWWorld::PhysicsSystem& physics) const; diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index b21486c2c..c2906e447 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -222,29 +222,22 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& itemPtr MWWorld::ContainerStoreIterator it = end(); - if (setOwner && actorPtr.getClass().isActor()) + // HACK: Set owner on the original item, then reset it after we have copied it + // If we set the owner on the copied item, it would not stack correctly... + std::string oldOwner = itemPtr.getCellRef().getOwner(); + if (!setOwner || actorPtr == MWBase::Environment::get().getWorld()->getPlayerPtr()) // No point in setting owner to the player - NPCs will not respect this anyway { - // HACK: Set owner on the original item, then reset it after we have copied it - // If we set the owner on the copied item, it would not stack correctly... - std::string oldOwner = itemPtr.getCellRef().getOwner(); - if (actorPtr == player) - { - // No point in setting owner to the player - NPCs will not respect this anyway - // Additionally, setting it to "player" would make those items not stack with items that don't have an owner - itemPtr.getCellRef().setOwner(""); - } - else - itemPtr.getCellRef().setOwner(actorPtr.getCellRef().getRefId()); - - it = addImp(itemPtr, count); - - itemPtr.getCellRef().setOwner(oldOwner); + itemPtr.getCellRef().setOwner(""); } else { - it = addImp(itemPtr, count); + itemPtr.getCellRef().setOwner(actorPtr.getCellRef().getRefId()); } + it = addImp(itemPtr, count); + + itemPtr.getCellRef().setOwner(oldOwner); + // The copy of the original item we just made MWWorld::Ptr item = *it; @@ -258,6 +251,14 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& itemPtr pos.pos[1] = 0; pos.pos[2] = 0; item.getCellRef().setPosition(pos); + + // reset ownership stuff, owner was already handled above + item.getCellRef().resetGlobalVariable(); + item.getCellRef().setFaction(""); + item.getCellRef().setFactionRank(-1); + + // must reset the RefNum on the copied item, so that the RefNum on the original item stays unique + // maybe we should do this in the copy constructor instead? item.getCellRef().unsetRefNum(); // destroy link to content file std::string script = item.getClass().getScript(item); @@ -399,19 +400,19 @@ int MWWorld::ContainerStore::remove(const Ptr& item, int count, const Ptr& actor return count - toRemove; } -void MWWorld::ContainerStore::fill (const ESM::InventoryList& items, const std::string& owner, const std::string& faction, int factionRank, const MWWorld::ESMStore& store) +void MWWorld::ContainerStore::fill (const ESM::InventoryList& items, const std::string& owner) { for (std::vector::const_iterator iter (items.mList.begin()); iter!=items.mList.end(); ++iter) { std::string id = Misc::StringUtils::lowerCase(iter->mItem.toString()); - addInitialItem(id, owner, faction, factionRank, iter->mCount); + addInitialItem(id, owner, iter->mCount); } flagAsModified(); } -void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std::string& owner, const std::string& faction, int factionRank, +void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std::string& owner, int count, bool topLevel, const std::string& levItem) { ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), id, count); @@ -423,7 +424,7 @@ void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std:: if (topLevel && std::abs(count) > 1 && levItem->mFlags & ESM::ItemLevList::Each) { for (int i=0; i 0 ? 1 : -1, true, levItem->mId); + addInitialItem(id, owner, count > 0 ? 1 : -1, true, levItem->mId); return; } else @@ -431,7 +432,7 @@ void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std:: std::string id = MWMechanics::getLevelledItem(ref.getPtr().get()->mBase, false); if (id.empty()) return; - addInitialItem(id, owner, faction, factionRank, count, false, levItem->mId); + addInitialItem(id, owner, count, false, levItem->mId); } } else @@ -447,13 +448,11 @@ void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std:: count = std::abs(count); ref.getPtr().getCellRef().setOwner(owner); - ref.getPtr().getCellRef().setFaction(faction); - ref.getPtr().getCellRef().setFactionRank(factionRank); addImp (ref.getPtr(), count); } } -void MWWorld::ContainerStore::restock (const ESM::InventoryList& items, const MWWorld::Ptr& ptr, const std::string& owner, const std::string& faction, int factionRank) +void MWWorld::ContainerStore::restock (const ESM::InventoryList& items, const MWWorld::Ptr& ptr, const std::string& owner) { // Remove the items already spawned by levelled items that will restock for (std::map::iterator it = mLevelledItemMap.begin(); it != mLevelledItemMap.end(); ++it) @@ -472,13 +471,13 @@ void MWWorld::ContainerStore::restock (const ESM::InventoryList& items, const MW if (MWBase::Environment::get().getWorld()->getStore().get().search(it->mItem.toString())) { - addInitialItem(item, owner, faction, factionRank, it->mCount, true); + addInitialItem(item, owner, it->mCount, true); } else { int currentCount = count(item); if (currentCount < std::abs(it->mCount)) - addInitialItem(item, owner, faction, factionRank, std::abs(it->mCount) - currentCount, true); + addInitialItem(item, owner, std::abs(it->mCount) - currentCount, true); } } flagAsModified(); diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index d909a98cc..e9750a622 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -75,7 +75,7 @@ namespace MWWorld mutable float mCachedWeight; mutable bool mWeightUpToDate; ContainerStoreIterator addImp (const Ptr& ptr, int count); - void addInitialItem (const std::string& id, const std::string& owner, const std::string& faction, int factionRank, int count, bool topLevel=true, const std::string& levItem = ""); + void addInitialItem (const std::string& id, const std::string& owner, int count, bool topLevel=true, const std::string& levItem = ""); template ContainerStoreIterator getState (CellRefList& collection, @@ -112,7 +112,7 @@ namespace MWWorld /// \attention Do not add items to an existing stack by increasing the count instead of /// calling this function! /// - /// @param setOwner Set the owner of the added item to \a actorPtr? + /// @param setOwner Set the owner of the added item to \a actorPtr? If false, the owner is reset to "". /// /// @return if stacking happened, return iterator to the item that was stacked against, otherwise iterator to the newly inserted item. @@ -151,10 +151,10 @@ namespace MWWorld virtual bool stacks (const Ptr& ptr1, const Ptr& ptr2); ///< @return true if the two specified objects can stack with each other - void fill (const ESM::InventoryList& items, const std::string& owner, const std::string& faction, int factionRank, const MWWorld::ESMStore& store); + void fill (const ESM::InventoryList& items, const std::string& owner); ///< Insert items into *this. - void restock (const ESM::InventoryList& items, const MWWorld::Ptr& ptr, const std::string& owner, const std::string& faction, int factionRank); + void restock (const ESM::InventoryList& items, const MWWorld::Ptr& ptr, const std::string& owner); virtual void clear(); ///< Empty container. diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 1036d8ce6..933a1fa42 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2980,18 +2980,10 @@ namespace MWWorld if (!closestChest.isEmpty()) //Found a close chest { - ContainerStore& store = ptr.getClass().getContainerStore(ptr); - for (ContainerStoreIterator it = store.begin(); it != store.end(); ++it) //Move all stolen stuff into chest - { - MWWorld::Ptr dummy; - if (!MWBase::Environment::get().getMechanicsManager()->isAllowedToUse(getPlayerPtr(), *it, dummy)) - { - closestChest.getClass().getContainerStore(closestChest).add(*it, it->getRefData().getCount(), closestChest); - store.remove(*it, it->getRefData().getCount(), ptr); - } - } - closestChest.getClass().lock(closestChest,50); + MWBase::Environment::get().getMechanicsManager()->confiscateStolenItems(ptr, closestChest); } + else + std::cerr << "Failed to confiscate items: no stolen_goods container found" << std::endl; } void World::goToJail() diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 814dde6a2..6f8352ddb 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -63,7 +63,7 @@ add_component_dir (esm loadweap records aipackage effectlist spelllist variant variantimp loadtes3 cellref filter savedgame journalentry queststate locals globalscript player objectstate cellid cellstate globalmap inventorystate containerstate npcstate creaturestate dialoguestate statstate npcstats creaturestats weatherstate quickkeys fogstate spellstate activespells creaturelevliststate doorstate projectilestate debugprofile - aisequence magiceffects util custommarkerstate + aisequence magiceffects util custommarkerstate stolenitems ) add_component_dir (esmterrain diff --git a/components/esm/defs.hpp b/components/esm/defs.hpp index 60926d562..7ef8102c2 100644 --- a/components/esm/defs.hpp +++ b/components/esm/defs.hpp @@ -117,6 +117,7 @@ enum RecNameInts REC_MARK = FourCC<'M','A','R','K'>::value, REC_ENAB = FourCC<'E','N','A','B'>::value, REC_CAM_ = FourCC<'C','A','M','_'>::value, + REC_STLN = FourCC<'S','T','L','N'>::value, // format 1 REC_FILT = FourCC<'F','I','L','T'>::value, diff --git a/components/esm/stolenitems.cpp b/components/esm/stolenitems.cpp new file mode 100644 index 000000000..c51b0b99b --- /dev/null +++ b/components/esm/stolenitems.cpp @@ -0,0 +1,47 @@ +#include "stolenitems.hpp" + +#include +#include + +namespace ESM +{ + + void StolenItems::write(ESMWriter &esm) const + { + for (StolenItemsMap::const_iterator it = mStolenItems.begin(); it != mStolenItems.end(); ++it) + { + esm.writeHNString("NAME", it->first); + for (std::map, int>::const_iterator ownerIt = it->second.begin(); + ownerIt != it->second.end(); ++ownerIt) + { + if (ownerIt->first.second) + esm.writeHNString("FNAM", ownerIt->first.first); + else + esm.writeHNString("ONAM", ownerIt->first.first); + esm.writeHNT("COUN", ownerIt->second); + } + } + } + + void StolenItems::load(ESMReader &esm) + { + while (esm.isNextSub("NAME")) + { + std::string itemid = esm.getHString(); + + std::map, int> ownerMap; + while (esm.isNextSub("FNAM") || esm.isNextSub("ONAM")) + { + std::string subname = esm.retSubName().toString(); + std::string owner = esm.getHString(); + bool isFaction = (subname == "FNAM"); + int count; + esm.getHNT(count, "COUN"); + ownerMap.insert(std::make_pair(std::make_pair(owner, isFaction), count)); + } + + mStolenItems[itemid] = ownerMap; + } + } + +} diff --git a/components/esm/stolenitems.hpp b/components/esm/stolenitems.hpp new file mode 100644 index 000000000..928fbbf75 --- /dev/null +++ b/components/esm/stolenitems.hpp @@ -0,0 +1,24 @@ +#ifndef OPENMW_COMPONENTS_ESM_STOLENITEMS_H +#define OPENMW_COMPONENTS_ESM_STOLENITEMS_H + +#include +#include + +namespace ESM +{ + class ESMReader; + class ESMWriter; + + // format 0, saved games only + struct StolenItems + { + typedef std::map, int> > StolenItemsMap; + StolenItemsMap mStolenItems; + + void load(ESM::ESMReader& esm); + void write(ESM::ESMWriter& esm) const; + }; + +} + +#endif From 356d1c7657124ccad4987a78fb0672e379909070 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 4 Feb 2015 22:10:58 +0100 Subject: [PATCH 0504/3725] ESSImport: convert stolen item tracker --- apps/essimporter/converter.hpp | 35 ++++++++++++++++++++++++++++++---- apps/openmw/mwgui/tooltips.cpp | 2 +- 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index 775995605..c23083f8e 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -18,6 +18,7 @@ #include #include #include +#include #include "importcrec.hpp" #include "importcntc.hpp" @@ -387,24 +388,50 @@ public: virtual void read(ESM::ESMReader &esm) { std::string itemid = esm.getHNString("NAME"); + Misc::StringUtils::toLower(itemid); while (esm.isNextSub("FNAM") || esm.isNextSub("ONAM")) { if (esm.retSubName().toString() == "FNAM") { std::string factionid = esm.getHString(); - mFactionStolenItems.insert(std::make_pair(itemid, factionid)); + mStolenItems[itemid].insert(std::make_pair(Misc::StringUtils::lowerCase(factionid), true)); } else { std::string ownerid = esm.getHString(); - mStolenItems.insert(std::make_pair(itemid, ownerid)); + mStolenItems[itemid].insert(std::make_pair(Misc::StringUtils::lowerCase(ownerid), false)); } } } + virtual void write(ESM::ESMWriter &esm) + { + ESM::StolenItems items; + for (std::map >::const_iterator it = mStolenItems.begin(); it != mStolenItems.end(); ++it) + { + std::map, int> owners; + for (std::set::const_iterator ownerIt = it->second.begin(); ownerIt != it->second.end(); ++ownerIt) + { + owners.insert(std::make_pair(std::make_pair(ownerIt->first, ownerIt->second) + // Since OpenMW doesn't suffer from the owner contamination bug, + // it needs a count argument. But for legacy savegames, we don't know + // this count, so must assume all items of that ID are stolen, + // like vanilla MW did. + ,std::numeric_limits::max())); + } + + items.mStolenItems.insert(std::make_pair(it->first, owners)); + } + + esm.startRecord(ESM::REC_STLN); + items.write(esm); + esm.endRecord(ESM::REC_STLN); + } + private: - std::multimap mStolenItems; - std::multimap mFactionStolenItems; + typedef std::pair Owner; // + + std::map > mStolenItems; }; /// Seen responses for a dialogue topic? diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index c6210ac64..2c10004a6 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -593,7 +593,7 @@ namespace MWGui for (std::vector >::const_iterator it = itemOwners.begin(); it != itemOwners.end(); ++it) { - ret += std::string("\nStolen ") + MyGUI::utility::toString(it->second) + " from " + it->first; + ret += std::string("\nStolen from ") + it->first; } ret += getMiscString(cellref.getGlobalVariable(), "Global"); From dd8aab2a7ff2597d1665dfefc2d2773a2fa71d23 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 4 Feb 2015 22:17:30 +0100 Subject: [PATCH 0505/3725] Adjust help for --load-savegame again --- README.md | 5 +++-- apps/openmw/main.cpp | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 9207c5728..63a313896 100644 --- a/README.md +++ b/README.md @@ -69,8 +69,9 @@ Command line options --script-blacklist-use [=arg(=1)] (=1) enable script blacklisting --load-savegame arg load a save game file on game startup - (specify an absolute or relative - filename for this option) + (specify an absolute filename or a + filename relative to the current + working directory) --skip-menu [=arg(=1)] (=0) skip main menu on game startup --new-game [=arg(=1)] (=0) run new game sequence (ignored if skip-menu=0) diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index f4875e68a..475fe63a2 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -153,7 +153,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat ->default_value(true), "enable script blacklisting") ("load-savegame", bpo::value()->default_value(""), - "load a save game file on game startup (specify an absolute or relative filename for this option)") + "load a save game file on game startup (specify an absolute filename or a filename relative to the current working directory)") ("skip-menu", bpo::value()->implicit_value(true) ->default_value(false), "skip main menu on game startup") From ae77eacd7ea5f3ef5766138178d73345256f2b6e Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 4 Feb 2015 23:15:12 +0100 Subject: [PATCH 0506/3725] Skill progress refactoring --- apps/openmw/mwgui/statswindow.cpp | 6 ++- apps/openmw/mwmechanics/npcstats.cpp | 54 +++++++++++------------- apps/openmw/mwmechanics/npcstats.hpp | 6 +-- apps/openmw/mwscript/statsextensions.cpp | 17 -------- 4 files changed, 31 insertions(+), 52 deletions(-) diff --git a/apps/openmw/mwgui/statswindow.cpp b/apps/openmw/mwgui/statswindow.cpp index a407aedc7..f624d751d 100644 --- a/apps/openmw/mwgui/statswindow.cpp +++ b/apps/openmw/mwgui/statswindow.cpp @@ -383,11 +383,15 @@ namespace MWGui const MWMechanics::SkillValue &stat = mSkillValues.find(skillId)->second; int base = stat.getBase(); int modified = stat.getModified(); - int progressPercent = stat.getProgress() * 100; + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); const MWWorld::ESMStore &esmStore = MWBase::Environment::get().getWorld()->getStore(); + int progressRequirement = player.getClass().getNpcStats(player).getSkillProgressRequirement(skillId, + *esmStore.get().find(player.get()->mBase->mClass)); + int progressPercent = int(int(stat.getProgress()) / float(progressRequirement) * 100.f); + const ESM::Skill* skill = esmStore.get().find(skillId); std::string icon = "icons\\k\\" + ESM::Skill::sIconNames[skillId]; diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index 7219d6185..bd1cd5572 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -125,32 +125,9 @@ bool MWMechanics::NpcStats::isInFaction (const std::string& faction) const return (mFactionRank.find(Misc::StringUtils::lowerCase(faction)) != mFactionRank.end()); } -float MWMechanics::NpcStats::getSkillGain (int skillIndex, const ESM::Class& class_, int usageType, - int level, float extraFactor) const +float MWMechanics::NpcStats::getSkillProgressRequirement (int skillIndex, const ESM::Class& class_) const { - if (level<0) - level = static_cast (getSkill (skillIndex).getBase()); - - const ESM::Skill *skill = - MWBase::Environment::get().getWorld()->getStore().get().find (skillIndex); - - float skillFactor = 1; - - if (usageType>=4) - throw std::runtime_error ("skill usage type out of range"); - - if (usageType>=0) - { - skillFactor = skill->mData.mUseValue[usageType]; - - if (skillFactor<0) - throw std::runtime_error ("invalid skill gain factor"); - - if (skillFactor==0) - return 0; - } - - skillFactor *= extraFactor; + float progressRequirement = 1 + getSkill (skillIndex).getBase(); const MWWorld::Store &gmst = MWBase::Environment::get().getWorld()->getStore().get(); @@ -173,11 +150,15 @@ float MWMechanics::NpcStats::getSkillGain (int skillIndex, const ESM::Class& cla break; } + progressRequirement *= typeFactor; + if (typeFactor<=0) throw std::runtime_error ("invalid skill type factor"); float specialisationFactor = 1; + const ESM::Skill *skill = + MWBase::Environment::get().getWorld()->getStore().get().find (skillIndex); if (skill->mData.mSpecialization==class_.mData.mSpecialization) { specialisationFactor = gmst.find ("fSpecialSkillBonus")->getFloat(); @@ -185,7 +166,9 @@ float MWMechanics::NpcStats::getSkillGain (int skillIndex, const ESM::Class& cla if (specialisationFactor<=0) throw std::runtime_error ("invalid skill specialisation factor"); } - return 1.0 / ((level+1) * (1.0/skillFactor) * typeFactor * specialisationFactor); + progressRequirement *= specialisationFactor; + + return progressRequirement; } void MWMechanics::NpcStats::useSkill (int skillIndex, const ESM::Class& class_, int usageType, float extraFactor) @@ -194,11 +177,24 @@ void MWMechanics::NpcStats::useSkill (int skillIndex, const ESM::Class& class_, if(mIsWerewolf) return; + const ESM::Skill *skill = + MWBase::Environment::get().getWorld()->getStore().get().find (skillIndex); + float skillGain = 1; + if (usageType>=4) + throw std::runtime_error ("skill usage type out of range"); + if (usageType>=0) + { + skillGain = skill->mData.mUseValue[usageType]; + if (skillGain<0) + throw std::runtime_error ("invalid skill gain factor"); + } + skillGain *= extraFactor; + MWMechanics::SkillValue& value = getSkill (skillIndex); - value.setProgress(value.getProgress() + getSkillGain (skillIndex, class_, usageType, -1, extraFactor)); + value.setProgress(value.getProgress() + skillGain); - if (value.getProgress()>=1) + if (int(value.getProgress())>=int(getSkillProgressRequirement(skillIndex, class_))) { // skill levelled up increaseSkill(skillIndex, class_, false); @@ -256,7 +252,7 @@ void MWMechanics::NpcStats::increaseSkill(int skillIndex, const ESM::Class &clas MWBase::Environment::get().getWindowManager ()->messageBox ("#{sLevelUpMsg}", MWGui::ShowInDialogueMode_Never); } - getSkill (skillIndex).setBase (base); + getSkill(skillIndex).setBase (base); if (!preserveProgress) getSkill(skillIndex).setProgress(0); } diff --git a/apps/openmw/mwmechanics/npcstats.hpp b/apps/openmw/mwmechanics/npcstats.hpp index fc4f297db..1cb62276f 100644 --- a/apps/openmw/mwmechanics/npcstats.hpp +++ b/apps/openmw/mwmechanics/npcstats.hpp @@ -74,11 +74,7 @@ namespace MWMechanics bool isInFaction (const std::string& faction) const; - float getSkillGain (int skillIndex, const ESM::Class& class_, int usageType = -1, - int level = -1, float extraFactor=1.f) const; - ///< \param usageType: Usage specific factor, specified in the respective skill record; - /// -1: use a factor of 1.0 instead. - /// \param level Level to base calculation on; -1: use current level. + float getSkillProgressRequirement (int skillIndex, const ESM::Class& class_) const; void useSkill (int skillIndex, const ESM::Class& class_, int usageType = -1, float extraFactor=1.f); ///< Increase skill by usage. diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index f0cf12e5e..abef636cc 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -348,29 +348,12 @@ namespace MWScript MWMechanics::NpcStats& stats = ptr.getClass().getNpcStats (ptr); - MWWorld::LiveCellRef *ref = ptr.get(); - - assert (ref); - - const ESM::Class& class_ = - *MWBase::Environment::get().getWorld()->getStore().get().find (ref->mBase->mClass); - - float level = stats.getSkill(mIndex).getBase(); - float progress = stats.getSkill(mIndex).getProgress(); - int newLevel = value - (stats.getSkill(mIndex).getModified() - stats.getSkill(mIndex).getBase()); if (newLevel<0) newLevel = 0; - progress = (progress / stats.getSkillGain (mIndex, class_, -1, level)) - * stats.getSkillGain (mIndex, class_, -1, newLevel); - - if (progress>=1) - progress = 0.999999999; - stats.getSkill (mIndex).setBase (newLevel); - stats.getSkill (mIndex).setProgress(progress); } }; From f0b1d889c0f9f054207b07194f583f6a355d336e Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 4 Feb 2015 23:24:49 +0100 Subject: [PATCH 0507/3725] ESSImport: import player skill progress --- apps/essimporter/convertplayer.cpp | 5 ++--- apps/openmw/mwmechanics/npcstats.hpp | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/apps/essimporter/convertplayer.cpp b/apps/essimporter/convertplayer.cpp index ef22660f5..532efa7f5 100644 --- a/apps/essimporter/convertplayer.cpp +++ b/apps/essimporter/convertplayer.cpp @@ -17,6 +17,8 @@ namespace ESSImport } for (int i=0; i<8; ++i) out.mObject.mNpcStats.mSkillIncrease[i] = pcdt.mPNAM.mSkillIncreases[i]; + for (int i=0; i<27; ++i) + out.mObject.mNpcStats.mSkills[i].mRegular.mProgress = pcdt.mPNAM.mSkillProgress[i]; out.mObject.mNpcStats.mLevelProgress = pcdt.mPNAM.mLevelProgress; if (pcdt.mPNAM.mDrawState & PCDT::DrawState_Weapon) @@ -24,9 +26,6 @@ namespace ESSImport if (pcdt.mPNAM.mDrawState & PCDT::DrawState_Spell) out.mObject.mCreatureStats.mDrawState = 2; - // TODO: convert PNAM.mSkillProgress, needs to be converted to uniform scale - // (or change openmw to accept non-uniform skill progress) - firstPersonCam = (pcdt.mPNAM.mCameraState == PCDT::CameraState_FirstPerson); for (std::vector::const_iterator it = pcdt.mKnownDialogueTopics.begin(); diff --git a/apps/openmw/mwmechanics/npcstats.hpp b/apps/openmw/mwmechanics/npcstats.hpp index 1cb62276f..224366a3e 100644 --- a/apps/openmw/mwmechanics/npcstats.hpp +++ b/apps/openmw/mwmechanics/npcstats.hpp @@ -23,7 +23,7 @@ namespace MWMechanics class NpcStats : public CreatureStats { int mDisposition; - SkillValue mSkill[ESM::Skill::Length]; + SkillValue mSkill[ESM::Skill::Length]; // SkillValue.mProgress used by the player only SkillValue mWerewolfSkill[ESM::Skill::Length]; int mReputation; int mCrimeId; From 5096e5dc0c1cadad9d9b14ec9175a30e210411e6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 4 Feb 2015 23:45:01 +0100 Subject: [PATCH 0508/3725] esmtool minor/major skills fix --- apps/esmtool/record.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index e167278f3..97b0635fe 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -535,10 +535,10 @@ void Record::print() std::cout << " Specialization: " << specializationLabel(mData.mData.mSpecialization) << " (" << mData.mData.mSpecialization << ")" << std::endl; for (int i = 0; i != 5; i++) - std::cout << " Major Skill: " << skillLabel(mData.mData.mSkills[i][0]) + std::cout << " Minor Skill: " << skillLabel(mData.mData.mSkills[i][0]) << " (" << mData.mData.mSkills[i][0] << ")" << std::endl; for (int i = 0; i != 5; i++) - std::cout << " Minor Skill: " << skillLabel(mData.mData.mSkills[i][1]) + std::cout << " Major Skill: " << skillLabel(mData.mData.mSkills[i][1]) << " (" << mData.mData.mSkills[i][1] << ")" << std::endl; } From 55cd9b526c93a44e22ccd784df93e590c61b1b04 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 5 Feb 2015 00:56:32 +0100 Subject: [PATCH 0509/3725] Skill progress bar changed to match MW --- apps/essimporter/importacdt.hpp | 2 +- apps/openmw/mwgui/statswindow.cpp | 12 ++++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/apps/essimporter/importacdt.hpp b/apps/essimporter/importacdt.hpp index 1e0317049..47055092d 100644 --- a/apps/essimporter/importacdt.hpp +++ b/apps/essimporter/importacdt.hpp @@ -61,7 +61,7 @@ namespace ESSImport bool mHasACSC; ACSC mACSC; - int mSkills[27][2]; + int mSkills[27][2]; // skills, base and modified // creature combat stats, base and modified // I think these can be ignored in the conversion, because it is not possible diff --git a/apps/openmw/mwgui/statswindow.cpp b/apps/openmw/mwgui/statswindow.cpp index f624d751d..2a22f4239 100644 --- a/apps/openmw/mwgui/statswindow.cpp +++ b/apps/openmw/mwgui/statswindow.cpp @@ -376,9 +376,8 @@ namespace MWGui for (SkillList::const_iterator it = skills.begin(); it != end; ++it) { int skillId = *it; - if (skillId < 0 || skillId > ESM::Skill::Length) // Skip unknown skill indexes + if (skillId < 0 || skillId >= ESM::Skill::Length) // Skip unknown skill indexes continue; - assert(skillId >= 0 && skillId < ESM::Skill::Length); const std::string &skillNameId = ESM::Skill::sSkillNameIds[skillId]; const MWMechanics::SkillValue &stat = mSkillValues.find(skillId)->second; int base = stat.getBase(); @@ -388,9 +387,14 @@ namespace MWGui const MWWorld::ESMStore &esmStore = MWBase::Environment::get().getWorld()->getStore(); - int progressRequirement = player.getClass().getNpcStats(player).getSkillProgressRequirement(skillId, + float progressRequirement = player.getClass().getNpcStats(player).getSkillProgressRequirement(skillId, *esmStore.get().find(player.get()->mBase->mClass)); - int progressPercent = int(int(stat.getProgress()) / float(progressRequirement) * 100.f); + + // This is how vanilla MW displays the progress bar (I think). Note it's slightly inaccurate, + // due to the int casting in the skill levelup logic. Also the progress label could in rare cases + // reach 100% without the skill levelling up. + // Leaving the original display logic for now, for consistency with ess-imported savegames. + int progressPercent = int(float(stat.getProgress()) / float(progressRequirement) * 100.f + 0.5f); const ESM::Skill* skill = esmStore.get().find(skillId); From b5e0e45c78716e37dbeeaebb49c3d198a71ef140 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 5 Feb 2015 01:03:10 +0100 Subject: [PATCH 0510/3725] Fix iLevelUpTotal not being used in the levelUp logic --- apps/openmw/mwmechanics/npcstats.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index bd1cd5572..9d3d967b9 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -264,13 +264,14 @@ int MWMechanics::NpcStats::getLevelProgress () const void MWMechanics::NpcStats::levelUp() { - mLevelProgress -= 10; - for (int i=0; i &gmst = MWBase::Environment::get().getWorld()->getStore().get(); + mLevelProgress -= gmst.find("iLevelUpTotal")->getInt(); + + for (int i=0; i Date: Thu, 5 Feb 2015 01:08:26 +0100 Subject: [PATCH 0511/3725] Cap the displayed attribute multiplier in levelup to attribute points left to 100 --- apps/openmw/mwgui/levelupdialog.cpp | 1 + apps/openmw/mwmechanics/npcstats.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/apps/openmw/mwgui/levelupdialog.cpp b/apps/openmw/mwgui/levelupdialog.cpp index 8553811aa..6759824f9 100644 --- a/apps/openmw/mwgui/levelupdialog.cpp +++ b/apps/openmw/mwgui/levelupdialog.cpp @@ -176,6 +176,7 @@ namespace MWGui availableAttributes++; int mult = pcStats.getLevelupAttributeMultiplier (i); + mult = std::min(mult, 100-pcStats.getAttribute(i).getBase()); text->setCaption(mult <= 1 ? "" : "x" + MyGUI::utility::toString(mult)); } else diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index 9d3d967b9..3aa034a3c 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -268,6 +268,7 @@ void MWMechanics::NpcStats::levelUp() MWBase::Environment::get().getWorld()->getStore().get(); mLevelProgress -= gmst.find("iLevelUpTotal")->getInt(); + mLevelProgress = std::max(0, mLevelProgress); // might be necessary when levelup was invoked via console for (int i=0; i Date: Thu, 5 Feb 2015 01:15:42 +0100 Subject: [PATCH 0512/3725] UI consistency fix in levelup dialog --- apps/openmw/mwgui/levelupdialog.cpp | 3 ++- files/mygui/openmw_levelup_dialog.layout | 16 ++++++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwgui/levelupdialog.cpp b/apps/openmw/mwgui/levelupdialog.cpp index 6759824f9..c392372ff 100644 --- a/apps/openmw/mwgui/levelupdialog.cpp +++ b/apps/openmw/mwgui/levelupdialog.cpp @@ -139,7 +139,6 @@ namespace MWGui if(world->getStore().get().isDynamic(cls->mId)) { - // Vanilla uses thief.dds for custom classes. // Choosing Stealth specialization and Speed/Agility as attributes, if possible. Otherwise fall back to first class found. MWWorld::SharedIterator it = world->getStore().get().begin(); for(; it != world->getStore().get().end(); ++it) @@ -173,6 +172,7 @@ namespace MWGui if (pcStats.getAttribute(i).getBase() < 100) { mAttributes[i]->setEnabled(true); + mAttributeValues[i]->setEnabled(true); availableAttributes++; int mult = pcStats.getLevelupAttributeMultiplier (i); @@ -182,6 +182,7 @@ namespace MWGui else { mAttributes[i]->setEnabled(false); + mAttributeValues[i]->setEnabled(false); text->setCaption(""); } diff --git a/files/mygui/openmw_levelup_dialog.layout b/files/mygui/openmw_levelup_dialog.layout index 190f16e5d..ead181d26 100644 --- a/files/mygui/openmw_levelup_dialog.layout +++ b/files/mygui/openmw_levelup_dialog.layout @@ -50,7 +50,7 @@ - + @@ -64,7 +64,7 @@ - + @@ -78,7 +78,7 @@ - + @@ -92,7 +92,7 @@ - + @@ -107,7 +107,7 @@ - + @@ -121,7 +121,7 @@ - + @@ -135,7 +135,7 @@ - + @@ -149,7 +149,7 @@ - + From d18d2a1882a297e21364b8f7aaaba5b4abf7d77e Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 5 Feb 2015 04:28:05 +0100 Subject: [PATCH 0513/3725] Skip rest of LEVI record if it has no items (Bug #2348) --- components/esm/loadlevlist.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/components/esm/loadlevlist.cpp b/components/esm/loadlevlist.cpp index f2c695c1f..0d0267764 100644 --- a/components/esm/loadlevlist.cpp +++ b/components/esm/loadlevlist.cpp @@ -19,7 +19,10 @@ void LevelledListBase::load(ESMReader &esm) mList.resize(len); } else + { + esm.skipRecord(); return; + } // TODO: Merge with an existing lists here. This can be done // simply by adding the lists together, making sure that they are From 01b41778720b71dcefc4a26860861cebefd04429 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 5 Feb 2015 04:29:52 +0100 Subject: [PATCH 0514/3725] Make sure birthsign spells are added when loading savegame --- apps/openmw/mwworld/player.cpp | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index c1e176b91..8f3560a69 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -260,9 +260,20 @@ namespace MWWorld mCellStore = world.getExterior(0,0); } - if (!player.mBirthsign.empty() && - !world.getStore().get().search (player.mBirthsign)) - throw std::runtime_error ("invalid player state record (birthsign)"); + if (!player.mBirthsign.empty()) + { + const ESM::BirthSign* sign = world.getStore().get().search (player.mBirthsign); + if (!sign) + throw std::runtime_error ("invalid player state record (birthsign does not exist)"); + + // To handle the case where a birth sign was edited in between play sessions (does not yet handle removing the old spells) + // Also needed for ess-imported savegames which do not specify the birtsign spells in the player's spell list. + for (std::vector::const_iterator iter (sign->mPowers.mList.begin()); + iter!=sign->mPowers.mList.end(); ++iter) + { + getPlayer().getClass().getCreatureStats(getPlayer()).getSpells().add (*iter); + } + } mCurrentCrimeId = player.mCurrentCrimeId; mPaidCrimeId = player.mPaidCrimeId; From cff0127ce70d1eafb7474d0821adfd6aee7bdb77 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 5 Feb 2015 04:31:50 +0100 Subject: [PATCH 0515/3725] Update comment on merging levelled lists --- components/esm/loadlevlist.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/components/esm/loadlevlist.cpp b/components/esm/loadlevlist.cpp index 0d0267764..2cbfac0b4 100644 --- a/components/esm/loadlevlist.cpp +++ b/components/esm/loadlevlist.cpp @@ -24,11 +24,12 @@ void LevelledListBase::load(ESMReader &esm) return; } - // TODO: Merge with an existing lists here. This can be done - // simply by adding the lists together, making sure that they are - // sorted by level. A better way might be to exclude repeated - // items. Also, some times we don't want to merge lists, just - // overwrite. Figure out a way to give the user this option. + // If this levelled list was already loaded by a previous content file, + // we overwrite the list. Merging lists should probably be left to external tools, + // with the limited amount of information there is in the records, all merging methods + // will be flawed in some way. For a proper fix the ESM format would have to be changed + // to actually track list changes instead of including the whole list for every file + // that does something with that list. for (size_t i = 0; i < mList.size(); i++) { From 4c6b9f8266b67e34bc6c6552c3a3ff0a0c0e406b Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 5 Feb 2015 15:39:53 +0100 Subject: [PATCH 0516/3725] Remove redundant decoder in ContentModel --- components/contentselector/model/contentmodel.cpp | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/components/contentselector/model/contentmodel.cpp b/components/contentselector/model/contentmodel.cpp index 198bbffbb..56a86f87f 100644 --- a/components/contentselector/model/contentmodel.cpp +++ b/components/contentselector/model/contentmodel.cpp @@ -442,11 +442,6 @@ void ContentSelectorModel::ContentModel::addFiles(const QString &path) filters << "*.esp" << "*.esm" << "*.omwgame" << "*.omwaddon"; dir.setNameFilters(filters); - QTextCodec *codec = QTextCodec::codecForName("UTF8"); - - // Create a decoder for non-latin characters in esx metadata - QTextDecoder *decoder = codec->makeDecoder(); - foreach (const QString &path, dir.entryList()) { QFileInfo info(dir.absoluteFilePath(path)); @@ -466,11 +461,11 @@ void ContentSelectorModel::ContentModel::addFiles(const QString &path) foreach (const ESM::Header::MasterData &item, fileReader.getGameFiles()) file->addGameFile(QString::fromStdString(item.name)); - file->setAuthor (decoder->toUnicode(fileReader.getAuthor().c_str())); + file->setAuthor (QString::fromUtf8(fileReader.getAuthor().c_str())); file->setDate (info.lastModified()); file->setFormat (fileReader.getFormat()); file->setFilePath (info.absoluteFilePath()); - file->setDescription(decoder->toUnicode(fileReader.getDesc().c_str())); + file->setDescription(QString::fromUtf8(fileReader.getDesc().c_str())); // Put the file in the table addFile(file); @@ -483,8 +478,6 @@ void ContentSelectorModel::ContentModel::addFiles(const QString &path) } - delete decoder; - sortFiles(); } From 5534306eb332f42160dc79093c2c9894149baae9 Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Fri, 6 Feb 2015 08:59:00 +0200 Subject: [PATCH 0517/3725] Few rename fixes --- CMakeLists.txt | 2 +- apps/opencs/CMakeLists.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b5cd54bab..ab4363e2e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -761,7 +761,7 @@ if (APPLE) set(OPENMW_APP "\${CMAKE_INSTALL_PREFIX}/${INSTALL_SUBDIR}/${APP_BUNDLE_NAME}") - set(OPENCS_BUNDLE_NAME "OpenCS.app") + set(OPENCS_BUNDLE_NAME "OpenMW-CS.app") set(OPENCS_APP "\${CMAKE_INSTALL_PREFIX}/${INSTALL_SUBDIR}/${OPENCS_BUNDLE_NAME}") set(ABSOLUTE_PLUGINS "") diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index e713c65bc..0b83feb45 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -211,5 +211,5 @@ target_link_libraries(openmw-cs ) if(APPLE) - INSTALL(TARGETS openmw-cs BUNDLE DESTINATION OpenMW-CS COMPONENT BUNDLE) + INSTALL(TARGETS openmw-cs BUNDLE DESTINATION OpenMW COMPONENT BUNDLE) endif() From 28eb766bbaab526ad35e0d4e06f7a5148c7e3e44 Mon Sep 17 00:00:00 2001 From: Rosanne DiMesio Date: Fri, 6 Feb 2015 14:27:12 -0600 Subject: [PATCH 0518/3725] Respect LIB_SUFFIX --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b5cd54bab..f2fd9b8de 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -392,7 +392,7 @@ IF(NOT WIN32 AND NOT APPLE) # Linux building # Paths SET(BINDIR "${CMAKE_INSTALL_PREFIX}/bin" CACHE PATH "Where to install binaries") - SET(LIBDIR "${CMAKE_INSTALL_PREFIX}/lib" CACHE PATH "Where to install libraries") + SET(LIBDIR "${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}" CACHE PATH "Where to install libraries") SET(DATAROOTDIR "${CMAKE_INSTALL_PREFIX}/share" CACHE PATH "Sets the root of data directories to a non-default location") SET(GLOBAL_DATA_PATH "${DATAROOTDIR}/games/" CACHE PATH "Set data path prefix") SET(DATADIR "${GLOBAL_DATA_PATH}/openmw" CACHE PATH "Sets the openmw data directories to a non-default location") From 1d9e9735730a6b0db4aab7a716432d973f13317d Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Sat, 7 Feb 2015 04:05:28 +0100 Subject: [PATCH 0519/3725] Add training progress bar, implement jail screen, tweak wait dialog (Fixes #1714) --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwbase/windowmanager.hpp | 3 + apps/openmw/mwgui/jailscreen.cpp | 136 ++++++++++++++++++++++++ apps/openmw/mwgui/jailscreen.hpp | 33 ++++++ apps/openmw/mwgui/mode.hpp | 1 + apps/openmw/mwgui/timeadvancer.cpp | 73 +++++++++++++ apps/openmw/mwgui/timeadvancer.hpp | 40 +++++++ apps/openmw/mwgui/trainingwindow.cpp | 22 ++++ apps/openmw/mwgui/trainingwindow.hpp | 8 ++ apps/openmw/mwgui/waitdialog.cpp | 92 ++++++++-------- apps/openmw/mwgui/waitdialog.hpp | 13 ++- apps/openmw/mwgui/windowmanagerimp.cpp | 15 +++ apps/openmw/mwgui/windowmanagerimp.hpp | 4 + apps/openmw/mwscript/miscextensions.cpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 54 +--------- 15 files changed, 394 insertions(+), 104 deletions(-) create mode 100644 apps/openmw/mwgui/jailscreen.cpp create mode 100644 apps/openmw/mwgui/jailscreen.hpp create mode 100644 apps/openmw/mwgui/timeadvancer.cpp create mode 100644 apps/openmw/mwgui/timeadvancer.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index cb6cc301b..eabbb7577 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -41,7 +41,7 @@ add_openmw_dir (mwgui itemmodel containeritemmodel inventoryitemmodel sortfilteritemmodel itemview tradeitemmodel companionitemmodel pickpocketitemmodel controllers savegamedialog recharge mode videowidget backgroundimage itemwidget screenfader debugwindow spellmodel spellview - draganddrop + draganddrop timeadvancer jailscreen ) add_openmw_dir (mwdialogue diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index c984b5e54..32994a5a6 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -63,6 +63,7 @@ namespace MWGui class ContainerWindow; class DialogueWindow; class WindowModal; + class JailScreen; enum ShowInDialogueMode { ShowInDialogueMode_IfPossible, @@ -114,6 +115,8 @@ namespace MWBase virtual void removeGuiMode (MWGui::GuiMode mode) = 0; ///< can be anywhere in the stack + virtual void goToJail(int days) = 0; + virtual void updatePlayer() = 0; virtual MWGui::GuiMode getMode() const = 0; diff --git a/apps/openmw/mwgui/jailscreen.cpp b/apps/openmw/mwgui/jailscreen.cpp new file mode 100644 index 000000000..0155ee5ff --- /dev/null +++ b/apps/openmw/mwgui/jailscreen.cpp @@ -0,0 +1,136 @@ +#include +#include +#include +#include + +#include "../mwbase/windowmanager.hpp" +#include "../mwbase/mechanicsmanager.hpp" +#include "../mwbase/world.hpp" +#include "../mwbase/environment.hpp" + +#include "../mwmechanics/npcstats.hpp" + +#include "../mwworld/esmstore.hpp" +#include "../mwworld/store.hpp" +#include "../mwworld/class.hpp" + +#include "jailscreen.hpp" + +namespace MWGui +{ + JailScreen::JailScreen() + : WindowBase("openmw_loading_screen.layout"), + mTimeAdvancer(0.0125), + mDays(1), + mFadeTimeRemaining(0) + { + getWidget(mLoadingText, "LoadingText"); + getWidget(mProgressBar, "ProgressBar"); + getWidget(mLoadingBox, "LoadingBox"); + + setVisible(false); + + mTimeAdvancer.eventProgressChanged += MyGUI::newDelegate(this, &JailScreen::onJailProgressChanged); + mTimeAdvancer.eventFinished += MyGUI::newDelegate(this, &JailScreen::onJailFinished); + + mLoadingText->setCaptionWithReplacing("#{sInPrisonTitle}"); + + center(); + } + + void JailScreen::goToJail(int days) + { + mDays = days; + + MWBase::Environment::get().getWindowManager()->fadeScreenOut(0.5); + mFadeTimeRemaining = 0.5; + + setVisible(false); + mProgressBar->setScrollRange(days*24+1); + mProgressBar->setScrollPosition(0); + mProgressBar->setTrackSize(0); + } + + void JailScreen::onFrame(float dt) + { + mTimeAdvancer.onFrame(dt); + + if (mFadeTimeRemaining <= 0) + return; + + mFadeTimeRemaining -= dt; + + if (mFadeTimeRemaining <= 0) + { + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWBase::Environment::get().getWorld()->teleportToClosestMarker(player, "prisonmarker"); + + setVisible(true); + mTimeAdvancer.run(mDays*24); + } + } + + void JailScreen::onJailProgressChanged(int cur, int /*total*/) + { + mProgressBar->setScrollPosition(0); + mProgressBar->setTrackSize(cur / (float)(mProgressBar->getScrollRange()) * mProgressBar->getLineSize()); + } + + void JailScreen::onJailFinished() + { + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->fadeScreenIn(0.5); + + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + + MWBase::Environment::get().getWorld()->advanceTime(mDays * 24); + for (int i=0; irest(true); + + std::set skills; + for (int day=0; day (RAND_MAX) + 1) * ESM::Skill::Length; + skills.insert(skill); + + MWMechanics::SkillValue& value = player.getClass().getNpcStats(player).getSkill(skill); + if (skill == ESM::Skill::Security || skill == ESM::Skill::Sneak) + value.setBase(std::min(100, value.getBase()+1)); + else + value.setBase(value.getBase()-1); + } + + const MWWorld::Store& gmst = MWBase::Environment::get().getWorld()->getStore().get(); + + std::string message; + if (mDays == 1) + message = gmst.find("sNotifyMessage42")->getString(); + else + message = gmst.find("sNotifyMessage43")->getString(); + + std::stringstream dayStr; + dayStr << mDays; + if (message.find("%d") != std::string::npos) + message.replace(message.find("%d"), 2, dayStr.str()); + + for (std::set::iterator it = skills.begin(); it != skills.end(); ++it) + { + std::string skillName = gmst.find(ESM::Skill::sSkillNameIds[*it])->getString(); + std::stringstream skillValue; + skillValue << player.getClass().getNpcStats(player).getSkill(*it).getBase(); + std::string skillMsg = gmst.find("sNotifyMessage44")->getString(); + if (*it == ESM::Skill::Sneak || *it == ESM::Skill::Security) + skillMsg = gmst.find("sNotifyMessage39")->getString(); + + if (skillMsg.find("%s") != std::string::npos) + skillMsg.replace(skillMsg.find("%s"), 2, skillName); + if (skillMsg.find("%d") != std::string::npos) + skillMsg.replace(skillMsg.find("%d"), 2, skillValue.str()); + message += "\n" + skillMsg; + } + + std::vector buttons; + buttons.push_back("#{sOk}"); + MWBase::Environment::get().getWindowManager()->interactiveMessageBox(message, buttons); + } +} diff --git a/apps/openmw/mwgui/jailscreen.hpp b/apps/openmw/mwgui/jailscreen.hpp new file mode 100644 index 000000000..06e9a3aa0 --- /dev/null +++ b/apps/openmw/mwgui/jailscreen.hpp @@ -0,0 +1,33 @@ +#ifndef MWGUI_JAILSCREEN_H +#define MWGUI_JAILSCREEN_H + +#include "windowbase.hpp" +#include "timeadvancer.hpp" + +namespace MWGui +{ + class JailScreen : public WindowBase + { + public: + JailScreen(); + void goToJail(int days); + + void onFrame(float dt); + + private: + int mDays; + + float mFadeTimeRemaining; + + MyGUI::Widget* mLoadingBox; + MyGUI::TextBox* mLoadingText; + MyGUI::ScrollBar* mProgressBar; + + void onJailProgressChanged(int cur, int total); + void onJailFinished(); + + TimeAdvancer mTimeAdvancer; + }; +} + +#endif diff --git a/apps/openmw/mwgui/mode.hpp b/apps/openmw/mwgui/mode.hpp index a1688d2e5..db851e067 100644 --- a/apps/openmw/mwgui/mode.hpp +++ b/apps/openmw/mwgui/mode.hpp @@ -46,6 +46,7 @@ namespace MWGui GM_Loading, GM_LoadingWallpaper, + GM_Jail, GM_QuickKeysMenu }; diff --git a/apps/openmw/mwgui/timeadvancer.cpp b/apps/openmw/mwgui/timeadvancer.cpp new file mode 100644 index 000000000..43504ce87 --- /dev/null +++ b/apps/openmw/mwgui/timeadvancer.cpp @@ -0,0 +1,73 @@ +#include "timeadvancer.hpp" + +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" + +namespace MWGui +{ + TimeAdvancer::TimeAdvancer(float delay) + : mRunning(false), + mCurHour(0), + mHours(1), + mInterruptAt(-1), + mDelay(delay), + mRemainingTime(delay) + { + } + + void TimeAdvancer::run(int hours, int interruptAt) + { + mHours = hours; + mCurHour = 0; + mInterruptAt = interruptAt; + mRemainingTime = mDelay; + + mRunning = true; + } + + void TimeAdvancer::stop() + { + mRunning = false; + } + + void TimeAdvancer::onFrame(float dt) + { + if (!mRunning) + return; + + if (mCurHour == mInterruptAt) + { + stop(); + eventInterrupted(); + return; + } + + mRemainingTime -= dt; + + while (mRemainingTime <= 0) + { + mRemainingTime += mDelay; + ++mCurHour; + + if (mCurHour <= mHours) + eventProgressChanged(mCurHour, mHours); + else + { + stop(); + eventFinished(); + return; + } + + } + } + + int TimeAdvancer::getHours() + { + return mHours; + } + + bool TimeAdvancer::isRunning() + { + return mRunning; + } +} diff --git a/apps/openmw/mwgui/timeadvancer.hpp b/apps/openmw/mwgui/timeadvancer.hpp new file mode 100644 index 000000000..8367b5a8b --- /dev/null +++ b/apps/openmw/mwgui/timeadvancer.hpp @@ -0,0 +1,40 @@ +#ifndef MWGUI_TIMEADVANCER_H +#define MWGUI_TIMEADVANCER_H + +#include + +namespace MWGui +{ + class TimeAdvancer + { + public: + TimeAdvancer(float delay); + + void run(int hours, int interruptAt=-1); + void stop(); + void onFrame(float dt); + + int getHours(); + bool isRunning(); + + // signals + typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void; + typedef MyGUI::delegates::CMultiDelegate2 EventHandle_IntInt; + + EventHandle_IntInt eventProgressChanged; + EventHandle_Void eventInterrupted; + EventHandle_Void eventFinished; + + private: + bool mRunning; + + int mCurHour; + int mHours; + int mInterruptAt; + + float mDelay; + float mRemainingTime; + }; +} + +#endif diff --git a/apps/openmw/mwgui/trainingwindow.cpp b/apps/openmw/mwgui/trainingwindow.cpp index 88ba62cc1..5a5f61115 100644 --- a/apps/openmw/mwgui/trainingwindow.cpp +++ b/apps/openmw/mwgui/trainingwindow.cpp @@ -40,12 +40,18 @@ namespace MWGui TrainingWindow::TrainingWindow() : WindowBase("openmw_trainingwindow.layout") , mFadeTimeRemaining(0) + , mTimeAdvancer(0.05) { getWidget(mTrainingOptions, "TrainingOptions"); getWidget(mCancelButton, "CancelButton"); getWidget(mPlayerGold, "PlayerGold"); mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &TrainingWindow::onCancelButtonClicked); + + mTimeAdvancer.eventProgressChanged += MyGUI::newDelegate(this, &TrainingWindow::onTrainingProgressChanged); + mTimeAdvancer.eventFinished += MyGUI::newDelegate(this, &TrainingWindow::onTrainingFinished); + + mProgressBar.setVisible(false); } void TrainingWindow::open() @@ -173,12 +179,28 @@ namespace MWGui MWBase::Environment::get().getMechanicsManager()->rest(false); MWBase::Environment::get().getMechanicsManager()->rest(false); + mProgressBar.setVisible(true); + mProgressBar.setProgress(0, 2); + mTimeAdvancer.run(2); + MWBase::Environment::get().getWindowManager()->fadeScreenOut(0.25); mFadeTimeRemaining = 0.5; } + void TrainingWindow::onTrainingProgressChanged(int cur, int total) + { + mProgressBar.setProgress(cur, total); + } + + void TrainingWindow::onTrainingFinished() + { + mProgressBar.setVisible(false); + } + void TrainingWindow::onFrame(float dt) { + mTimeAdvancer.onFrame(dt); + if (mFadeTimeRemaining <= 0) return; diff --git a/apps/openmw/mwgui/trainingwindow.hpp b/apps/openmw/mwgui/trainingwindow.hpp index 1fc902b20..7c4582062 100644 --- a/apps/openmw/mwgui/trainingwindow.hpp +++ b/apps/openmw/mwgui/trainingwindow.hpp @@ -3,6 +3,8 @@ #include "windowbase.hpp" #include "referenceinterface.hpp" +#include "timeadvancer.hpp" +#include "waitdialog.hpp" namespace MWGui { @@ -26,11 +28,17 @@ namespace MWGui void onCancelButtonClicked (MyGUI::Widget* sender); void onTrainingSelected(MyGUI::Widget* sender); + void onTrainingProgressChanged(int cur, int total); + void onTrainingFinished(); + MyGUI::Widget* mTrainingOptions; MyGUI::Button* mCancelButton; MyGUI::TextBox* mPlayerGold; float mFadeTimeRemaining; + + WaitDialogProgressBar mProgressBar; + TimeAdvancer mTimeAdvancer; }; } diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index fedb0324e..ad873a7c3 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -49,12 +49,11 @@ namespace MWGui WaitDialog::WaitDialog() : WindowBase("openmw_wait_dialog.layout") , mProgressBar() - , mWaiting(false) + , mTimeAdvancer(0.05) , mSleeping(false) , mHours(1) - , mRemainingTime(0.05) - , mCurHour(0) , mManualHours(1) + , mFadeTimeRemaining(0) , mInterruptAt(-1) { getWidget(mDateTimeText, "DateTimeText"); @@ -70,6 +69,10 @@ namespace MWGui mWaitButton->eventMouseButtonClick += MyGUI::newDelegate(this, &WaitDialog::onWaitButtonClicked); mHourSlider->eventScrollChangePosition += MyGUI::newDelegate(this, &WaitDialog::onHourSliderChangedPosition); + mTimeAdvancer.eventProgressChanged += MyGUI::newDelegate(this, &WaitDialog::onWaitingProgressChanged); + mTimeAdvancer.eventInterrupted += MyGUI::newDelegate(this, &WaitDialog::onWaitingInterrupted); + mTimeAdvancer.eventFinished += MyGUI::newDelegate(this, &WaitDialog::onWaitingFinished); + mProgressBar.setVisible (false); } @@ -133,11 +136,9 @@ namespace MWGui MWBase::World* world = MWBase::Environment::get().getWorld(); MWBase::Environment::get().getWindowManager()->fadeScreenOut(0.2); + mFadeTimeRemaining = 0.4; setVisible(false); - mProgressBar.setVisible (true); - mWaiting = true; - mCurHour = 0; mHours = hoursToWait; // FIXME: move this somewhere else? @@ -164,8 +165,7 @@ namespace MWGui } } - mRemainingTime = 0.05; - mProgressBar.setProgress (0, mHours); + mProgressBar.setProgress (0, hoursToWait); } void WaitDialog::onCancelButtonClicked(MyGUI::Widget* sender) @@ -179,6 +179,36 @@ namespace MWGui mManualHours = position+1; } + void WaitDialog::onWaitingProgressChanged(int cur, int total) + { + mProgressBar.setProgress(cur, total); + MWBase::Environment::get().getWorld()->advanceTime(1); + MWBase::Environment::get().getMechanicsManager()->rest(mSleeping); + } + + void WaitDialog::onWaitingInterrupted() + { + MWBase::Environment::get().getWindowManager()->messageBox("#{sSleepInterrupt}"); + MWBase::Environment::get().getWorld()->spawnRandomCreature(mInterruptCreatureList); + stopWaiting(); + } + + void WaitDialog::onWaitingFinished() + { + stopWaiting(); + + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + const MWMechanics::NpcStats &pcstats = player.getClass().getNpcStats(player); + + // trigger levelup if possible + const MWWorld::Store &gmst = + MWBase::Environment::get().getWorld()->getStore().get(); + if (mSleeping && pcstats.getLevelProgress () >= gmst.find("iLevelUpTotal")->getInt()) + { + MWBase::Environment::get().getWindowManager()->pushGuiMode (GM_Levelup); + } + } + void WaitDialog::setCanRest (bool canRest) { MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); @@ -205,45 +235,17 @@ namespace MWGui void WaitDialog::onFrame(float dt) { - if (!mWaiting) - return; + mTimeAdvancer.onFrame(dt); - if (mCurHour == mInterruptAt) - { - MWBase::Environment::get().getWindowManager()->messageBox("#{sSleepInterrupt}"); - MWBase::Environment::get().getWorld()->spawnRandomCreature(mInterruptCreatureList); - stopWaiting(); - } + if (mFadeTimeRemaining <= 0) + return; - mRemainingTime -= dt; + mFadeTimeRemaining -= dt; - while (mRemainingTime < 0) + if (mFadeTimeRemaining <= 0) { - mRemainingTime += 0.05; - ++mCurHour; - mProgressBar.setProgress (mCurHour, mHours); - - if (mCurHour <= mHours) - { - MWBase::Environment::get().getWorld ()->advanceTime (1); - MWBase::Environment::get().getMechanicsManager ()->rest (mSleeping); - } - } - - if (mCurHour > mHours) - { - stopWaiting(); - - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); - const MWMechanics::NpcStats &pcstats = player.getClass().getNpcStats(player); - - // trigger levelup if possible - const MWWorld::Store &gmst = - MWBase::Environment::get().getWorld()->getStore().get(); - if (mSleeping && pcstats.getLevelProgress () >= gmst.find("iLevelUpTotal")->getInt()) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode (GM_Levelup); - } + mProgressBar.setVisible(true); + mTimeAdvancer.run(mHours, mInterruptAt); } } @@ -253,14 +255,14 @@ namespace MWGui mProgressBar.setVisible (false); MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Rest); MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_RestBed); - mWaiting = false; + mTimeAdvancer.stop(); } void WaitDialog::wakeUp () { mSleeping = false; - mWaiting = false; + mTimeAdvancer.stop(); stopWaiting(); } diff --git a/apps/openmw/mwgui/waitdialog.hpp b/apps/openmw/mwgui/waitdialog.hpp index 435c1cb54..e8f58c574 100644 --- a/apps/openmw/mwgui/waitdialog.hpp +++ b/apps/openmw/mwgui/waitdialog.hpp @@ -1,6 +1,8 @@ #ifndef MWGUI_WAIT_DIALOG_H #define MWGUI_WAIT_DIALOG_H +#include "timeadvancer.hpp" + #include "windowbase.hpp" namespace MWGui @@ -38,7 +40,7 @@ namespace MWGui void bedActivated() { setCanRest(true); } - bool getSleeping() { return mWaiting && mSleeping; } + bool getSleeping() { return mTimeAdvancer.isRunning() && mSleeping; } void wakeUp(); void autosave(); @@ -51,12 +53,11 @@ namespace MWGui MyGUI::Button* mCancelButton; MWGui::Widgets::MWScrollBar* mHourSlider; - bool mWaiting; + TimeAdvancer mTimeAdvancer; bool mSleeping; - int mCurHour; int mHours; int mManualHours; // stores the hours to rest selected via slider - float mRemainingTime; + float mFadeTimeRemaining; int mInterruptAt; std::string mInterruptCreatureList; @@ -68,6 +69,10 @@ namespace MWGui void onCancelButtonClicked(MyGUI::Widget* sender); void onHourSliderChangedPosition(MyGUI::ScrollBar* sender, size_t position); + void onWaitingProgressChanged(int cur, int total); + void onWaitingInterrupted(); + void onWaitingFinished(); + void setCanRest(bool canRest); void startWaiting(int hoursToWait); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 715f47c46..d67ab17e0 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -91,6 +91,7 @@ #include "draganddrop.hpp" #include "container.hpp" #include "controllers.hpp" +#include "jailscreen.hpp" namespace MWGui { @@ -143,6 +144,7 @@ namespace MWGui , mHitFader(NULL) , mScreenFader(NULL) , mDebugWindow(NULL) + , mJailScreen(NULL) , mTranslationDataStorage (translationDataStorage) , mCharGen(NULL) , mInputBlocker(NULL) @@ -290,6 +292,7 @@ namespace MWGui mSoulgemDialog = new SoulgemDialog(mMessageBoxManager); mCompanionWindow = new CompanionWindow(mDragAndDrop, mMessageBoxManager); trackWindow(mCompanionWindow, "companion"); + mJailScreen = new JailScreen(); mWerewolfFader = new ScreenFader("textures\\werewolfoverlay.dds"); mBlindnessFader = new ScreenFader("black.png"); @@ -402,6 +405,7 @@ namespace MWGui delete mScreenFader; delete mBlindnessFader; delete mDebugWindow; + delete mJailScreen; delete mCursorManager; @@ -467,6 +471,7 @@ namespace MWGui mInventoryWindow->setTrading(false); mRecharge->setVisible(false); mVideoBackground->setVisible(false); + mJailScreen->setVisible(false); mHud->setVisible(mHudEnabled && mGuiEnabled); mToolTips->setVisible(mGuiEnabled); @@ -612,6 +617,9 @@ namespace MWGui case GM_Journal: mJournal->setVisible(true); break; + case GM_Jail: + mJailScreen->setVisible(true); + break; case GM_LoadingWallpaper: case GM_Loading: // Don't need to show anything here - GM_LoadingWallpaper covers everything else anyway, @@ -912,6 +920,7 @@ namespace MWGui mCompanionWindow->checkReferenceAvailable(); mConsole->checkReferenceAvailable(); mCompanionWindow->onFrame(); + mJailScreen->onFrame(frameDuration); mWerewolfFader->update(frameDuration); mBlindnessFader->update(frameDuration); @@ -1187,6 +1196,12 @@ namespace MWGui updateVisible(); } + void WindowManager::goToJail(int days) + { + pushGuiMode(MWGui::GM_Jail); + mJailScreen->goToJail(days); + } + void WindowManager::setSelectedSpell(const std::string& spellId, int successChancePercent) { mSelectedSpell = spellId; diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 9f01b136c..19c5e3166 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -90,6 +90,7 @@ namespace MWGui class WindowModal; class ScreenFader; class DebugWindow; + class JailScreen; class WindowManager : public MWBase::WindowManager { @@ -128,6 +129,8 @@ namespace MWGui virtual void popGuiMode(); virtual void removeGuiMode(GuiMode mode); ///< can be anywhere in the stack + virtual void goToJail(int days); + virtual GuiMode getMode() const; virtual bool containsMode(GuiMode mode) const; @@ -404,6 +407,7 @@ namespace MWGui ScreenFader* mHitFader; ScreenFader* mScreenFader; DebugWindow* mDebugWindow; + JailScreen* mJailScreen; Translation::Storage& mTranslationDataStorage; diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index bffeef768..40a356125 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -1008,7 +1008,7 @@ namespace MWScript virtual void execute (Interpreter::Runtime &runtime) { /// \todo implement jail check - runtime.push (0); + runtime.push (MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_Jail); } }; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index a8238d161..af3fa5b3e 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -3019,59 +3019,7 @@ namespace MWWorld MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Dialogue); - MWWorld::Ptr player = getPlayerPtr(); - teleportToClosestMarker(player, "prisonmarker"); - - int days = mDaysInPrison; - advanceTime(days * 24); - for (int i=0; irest (true); - - std::set skills; - for (int day=0; day (RAND_MAX) + 1) * ESM::Skill::Length; - skills.insert(skill); - - MWMechanics::SkillValue& value = player.getClass().getNpcStats(player).getSkill(skill); - if (skill == ESM::Skill::Security || skill == ESM::Skill::Sneak) - value.setBase(std::min(100, value.getBase()+1)); - else - value.setBase(value.getBase()-1); - } - - const Store& gmst = getStore().get(); - - std::string message; - if (days == 1) - message = gmst.find("sNotifyMessage42")->getString(); - else - message = gmst.find("sNotifyMessage43")->getString(); - - std::stringstream dayStr; - dayStr << days; - if (message.find("%d") != std::string::npos) - message.replace(message.find("%d"), 2, dayStr.str()); - - for (std::set::iterator it = skills.begin(); it != skills.end(); ++it) - { - std::string skillName = gmst.find(ESM::Skill::sSkillNameIds[*it])->getString(); - std::stringstream skillValue; - skillValue << player.getClass().getNpcStats(player).getSkill(*it).getBase(); - std::string skillMsg = gmst.find("sNotifyMessage44")->getString(); - if (*it == ESM::Skill::Sneak || *it == ESM::Skill::Security) - skillMsg = gmst.find("sNotifyMessage39")->getString(); - - if (skillMsg.find("%s") != std::string::npos) - skillMsg.replace(skillMsg.find("%s"), 2, skillName); - if (skillMsg.find("%d") != std::string::npos) - skillMsg.replace(skillMsg.find("%d"), 2, skillValue.str()); - message += "\n" + skillMsg; - } - - std::vector buttons; - buttons.push_back("#{sOk}"); - MWBase::Environment::get().getWindowManager()->interactiveMessageBox(message, buttons); + MWBase::Environment::get().getWindowManager()->goToJail(mDaysInPrison); } } From 2d17eaa5ea5ad5e57928649cf0553f01a8413e20 Mon Sep 17 00:00:00 2001 From: Jordan Ayers Date: Fri, 6 Feb 2015 19:21:40 -0600 Subject: [PATCH 0520/3725] Fix argument name for setSunDirection. --- apps/openmw/mwrender/renderingmanager.cpp | 4 ++-- apps/openmw/mwrender/renderingmanager.hpp | 2 +- apps/openmw/mwrender/sky.cpp | 4 ++-- apps/openmw/mwrender/sky.hpp | 2 +- apps/openmw/mwworld/weather.cpp | 4 ++-- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 3ffd787c7..3e95648c4 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -630,12 +630,12 @@ void RenderingManager::sunDisable(bool real) } } -void RenderingManager::setSunDirection(const Ogre::Vector3& direction, bool is_moon) +void RenderingManager::setSunDirection(const Ogre::Vector3& direction, bool is_night) { // direction * -1 (because 'direction' is camera to sun vector and not sun to camera), if (mSun) mSun->setDirection(Vector3(-direction.x, -direction.y, -direction.z)); - mSkyManager->setSunDirection(direction, is_moon); + mSkyManager->setSunDirection(direction, is_night); } void RenderingManager::setGlare(bool glare) diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index d4b85133d..9f029c1b9 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -141,7 +141,7 @@ public: void setAmbientColour(const Ogre::ColourValue& colour); void setSunColour(const Ogre::ColourValue& colour); - void setSunDirection(const Ogre::Vector3& direction, bool is_moon); + void setSunDirection(const Ogre::Vector3& direction, bool is_night); void sunEnable(bool real); ///< @param real whether or not to really disable the sunlight (otherwise just set diffuse to 0) void sunDisable(bool real); diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 454ed8820..f6287de5e 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -767,14 +767,14 @@ void SkyManager::setStormDirection(const Vector3 &direction) mStormDirection = direction; } -void SkyManager::setSunDirection(const Vector3& direction, bool is_moon) +void SkyManager::setSunDirection(const Vector3& direction, bool is_night) { if (!mCreated) return; mSun->setPosition(direction); mSunGlare->setPosition(direction); float height = direction.z; - float fade = is_moon ? 0.0 : (( height > 0.5) ? 1.0 : height * 2); + float fade = is_night ? 0.0 : (( height > 0.5) ? 1.0 : height * 2); sh::Factory::getInstance ().setSharedParameter ("waterSunFade_sunHeight", sh::makeProperty(new sh::Vector2(fade, height))); } diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index 70251f490..6950dbab3 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -153,7 +153,7 @@ namespace MWRender void setStormDirection(const Ogre::Vector3& direction); - void setSunDirection(const Ogre::Vector3& direction, bool is_moon); + void setSunDirection(const Ogre::Vector3& direction, bool is_night); void setMasserDirection(const Ogre::Vector3& direction); diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index a74c24768..a893b657a 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -443,13 +443,13 @@ void WeatherManager::update(float duration, bool paused) int facing = (mHour > 13.f) ? 1 : -1; - bool sun_is_moon = mHour >= mNightStart || mHour <= mSunriseTime; + bool is_night = mHour >= mNightStart || mHour <= mSunriseTime; Vector3 final( (height - 1) * facing, (height - 1) * facing, height); - mRendering->setSunDirection(final, sun_is_moon); + mRendering->setSunDirection(final, is_night); /* * TODO: import separated fadeInStart/Finish, fadeOutStart/Finish From c8a924196deacac0193f6698baa0bfa63a8f517d Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 7 Feb 2015 17:22:29 +0100 Subject: [PATCH 0521/3725] updated credits file --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index f261ea423..bc39b1c70 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -84,6 +84,7 @@ Programmers Paul McElroy (Greendogo) Pieter van der Kloet (pvdk) Radu-Marius Popovici (rpopovici) + rdimesio riothamus Robert MacGregor (Ragora) Rohit Nirmal From 1230cf49bf63cebe82e355e517ae58205afb9c31 Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Sat, 7 Feb 2015 18:38:41 +0100 Subject: [PATCH 0522/3725] Properly center jail progress widget, fix a bug with it not disappearing if the console is open --- apps/openmw/mwgui/jailscreen.cpp | 11 ++--------- apps/openmw/mwgui/jailscreen.hpp | 2 -- files/mygui/CMakeLists.txt | 1 + files/mygui/openmw_jail_screen.layout | 15 +++++++++++++++ 4 files changed, 18 insertions(+), 11 deletions(-) create mode 100644 files/mygui/openmw_jail_screen.layout diff --git a/apps/openmw/mwgui/jailscreen.cpp b/apps/openmw/mwgui/jailscreen.cpp index 0155ee5ff..548b1b604 100644 --- a/apps/openmw/mwgui/jailscreen.cpp +++ b/apps/openmw/mwgui/jailscreen.cpp @@ -1,7 +1,4 @@ -#include #include -#include -#include #include "../mwbase/windowmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" @@ -19,22 +16,18 @@ namespace MWGui { JailScreen::JailScreen() - : WindowBase("openmw_loading_screen.layout"), + : WindowBase("openmw_jail_screen.layout"), mTimeAdvancer(0.0125), mDays(1), mFadeTimeRemaining(0) { - getWidget(mLoadingText, "LoadingText"); getWidget(mProgressBar, "ProgressBar"); - getWidget(mLoadingBox, "LoadingBox"); setVisible(false); mTimeAdvancer.eventProgressChanged += MyGUI::newDelegate(this, &JailScreen::onJailProgressChanged); mTimeAdvancer.eventFinished += MyGUI::newDelegate(this, &JailScreen::onJailFinished); - mLoadingText->setCaptionWithReplacing("#{sInPrisonTitle}"); - center(); } @@ -78,7 +71,7 @@ namespace MWGui void JailScreen::onJailFinished() { - MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Jail); MWBase::Environment::get().getWindowManager()->fadeScreenIn(0.5); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); diff --git a/apps/openmw/mwgui/jailscreen.hpp b/apps/openmw/mwgui/jailscreen.hpp index 06e9a3aa0..7a544126d 100644 --- a/apps/openmw/mwgui/jailscreen.hpp +++ b/apps/openmw/mwgui/jailscreen.hpp @@ -19,8 +19,6 @@ namespace MWGui float mFadeTimeRemaining; - MyGUI::Widget* mLoadingBox; - MyGUI::TextBox* mLoadingText; MyGUI::ScrollBar* mProgressBar; void onJailProgressChanged(int cur, int total); diff --git a/files/mygui/CMakeLists.txt b/files/mygui/CMakeLists.txt index 638266b0c..13d1a9e1a 100644 --- a/files/mygui/CMakeLists.txt +++ b/files/mygui/CMakeLists.txt @@ -86,6 +86,7 @@ set(MYGUI_FILES openmw_edit_note.layout openmw_debug_window.layout openmw_debug_window.skin.xml + openmw_jail_screen.layout DejaVuLGCSansMono.ttf ../launcher/images/openmw.png OpenMWResourcePlugin.xml diff --git a/files/mygui/openmw_jail_screen.layout b/files/mygui/openmw_jail_screen.layout new file mode 100644 index 000000000..4385494e1 --- /dev/null +++ b/files/mygui/openmw_jail_screen.layout @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + From 9bbe6f8c5e52808e8b1886b3c594e01934dd892c Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Sat, 7 Feb 2015 18:39:05 +0100 Subject: [PATCH 0523/3725] Remove todo --- apps/openmw/mwscript/miscextensions.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 40a356125..1cc1b25e4 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -1007,7 +1007,6 @@ namespace MWScript virtual void execute (Interpreter::Runtime &runtime) { - /// \todo implement jail check runtime.push (MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_Jail); } }; From 23024d2bebc2a376b062b2bbe94bfe880f9e975d Mon Sep 17 00:00:00 2001 From: Jordan Ayers Date: Sat, 7 Feb 2015 12:36:27 -0600 Subject: [PATCH 0524/3725] Re-work the sun's trajectory. OMW Bug #781 Have the sun travel 15 degrees south of vertical. --- apps/openmw/mwworld/weather.cpp | 44 +++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index a893b657a..dcd8e5a11 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -1,5 +1,7 @@ #include "weather.hpp" +#include + #include #include "../mwbase/environment.hpp" @@ -427,29 +429,33 @@ void WeatherManager::update(float duration, bool paused) else mRendering->getSkyManager()->sunEnable(); - // sun angle - float height; - - //Day duration - float dayDuration = (mNightStart - 1) - mSunriseTime; + // Update the sun direction. Run it east to west at 15 degrees south from overhead. + // The sun's speed at day and night will differ, since mSunriseTime and mNightStart + // mark when the sun is level with the horizon. + { + assert( mNightStart > mSunriseTime ); - // rise at 6, set at 20 - if (mHour >= mSunriseTime && mHour <= mNightStart) - height = 1 - std::abs(((mHour - dayDuration) / 7.f)); - else if (mHour > mNightStart) - height = (mHour - mNightStart) / 4.f; - else //if (mHour > 0 && mHour < 6) - height = 1 - (mHour / mSunriseTime); + float adjustedHour = mHour; + if ( mHour < mSunriseTime ) + adjustedHour += 24.f; - int facing = (mHour > 13.f) ? 1 : -1; + const bool is_night = mHour >= mNightStart || mHour <= mSunriseTime; + const float dayDuration = mNightStart - mSunriseTime; + const float nightDuration = 24.f - dayDuration; - bool is_night = mHour >= mNightStart || mHour <= mSunriseTime; + double theta; + if ( !is_night ) { + theta = M_PI * (adjustedHour - mSunriseTime) / dayDuration; + } else { + theta = M_PI * (adjustedHour - mNightStart) / nightDuration; + } - Vector3 final( - (height - 1) * facing, - (height - 1) * facing, - height); - mRendering->setSunDirection(final, is_night); + Vector3 final( + cos( theta ), + -0.268, // approx tan( 15 degrees ) + sin( theta ) ); + mRendering->setSunDirection( final, is_night ); + } /* * TODO: import separated fadeInStart/Finish, fadeOutStart/Finish From 2223a69ab827e3315781bd3ddd32eda68dd7cc9b Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Sat, 7 Feb 2015 20:13:11 +0100 Subject: [PATCH 0525/3725] Fix getpcinjail returning 0 when the console is open --- apps/openmw/mwscript/miscextensions.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 1cc1b25e4..20724cd23 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -1007,7 +1007,7 @@ namespace MWScript virtual void execute (Interpreter::Runtime &runtime) { - runtime.push (MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_Jail); + runtime.push (MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_Jail)); } }; From c63ab673e1f1a09862d500400cb4cc3713dbc46e Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 7 Feb 2015 23:24:27 +0100 Subject: [PATCH 0526/3725] Revert "Add freedesktop.org mimeinfo for OpenMW save game files" This reverts commit 94002b0758a8825215074b5341b6ec6b0cd28660. Conflicts: CMakeLists.txt --- CMakeLists.txt | 3 --- files/openmw-mimeinfo.xml | 11 ----------- files/openmw.desktop | 13 ------------- 3 files changed, 27 deletions(-) delete mode 100644 files/openmw-mimeinfo.xml diff --git a/CMakeLists.txt b/CMakeLists.txt index ab4363e2e..d22e0b129 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -371,8 +371,6 @@ configure_file(${OpenMW_SOURCE_DIR}/files/opencs/defaultfilters if (NOT WIN32 AND NOT APPLE) configure_file(${OpenMW_SOURCE_DIR}/files/openmw.desktop "${OpenMW_BINARY_DIR}/openmw.desktop") - configure_file(${OpenMW_SOURCE_DIR}/files/openmw-mimeinfo.xml - "${OpenMW_BINARY_DIR}/openmw-mimeinfo.xml") configure_file(${OpenMW_SOURCE_DIR}/files/openmw-cs.desktop "${OpenMW_BINARY_DIR}/openmw-cs.desktop") endif() @@ -441,7 +439,6 @@ IF(NOT WIN32 AND NOT APPLE) # Install icon and desktop file INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.desktop" DESTINATION "${DATAROOTDIR}/applications" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") - INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw-mimeinfo.xml" DESTINATION "${DATAROOTDIR}/mime/packages" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") INSTALL(FILES "${OpenMW_SOURCE_DIR}/files/launcher/images/openmw.png" DESTINATION "${ICONDIR}" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") IF(BUILD_OPENCS) INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw-cs.desktop" DESTINATION "${DATAROOTDIR}/applications" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "opencs") diff --git a/files/openmw-mimeinfo.xml b/files/openmw-mimeinfo.xml deleted file mode 100644 index 1355383a5..000000000 --- a/files/openmw-mimeinfo.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - OpenMW Savegame - - - - diff --git a/files/openmw.desktop b/files/openmw.desktop index 6d64c5a7c..36d01b33e 100644 --- a/files/openmw.desktop +++ b/files/openmw.desktop @@ -8,16 +8,3 @@ TryExec=openmw-launcher Exec=openmw-launcher Icon=openmw Categories=Game;RolePlaying; - -[Desktop Entry] -Type=Application -Name=OpenMW -GenericName=Role Playing Game -Comment=An engine replacement for The Elder Scrolls III: Morrowind -Keywords=Morrowind;Reimplementation Mods;esm;bsa; -Exec=openmw --load-savegame=%f -Icon=openmw -Categories=Game;RolePlaying; -Terminal=false -NoDisplay=true -MimeType=application/x-openmw-savegame; From 01e32aef79fcdcf14c8dfcbb2d61d11589e05e31 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 8 Feb 2015 14:34:31 +0100 Subject: [PATCH 0527/3725] Fix exception moving a disabled object between cells --- apps/openmw/mwrender/renderingmanager.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 3ffd787c7..88ede1682 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -297,6 +297,8 @@ void RenderingManager::rotateObject(const MWWorld::Ptr &ptr) void RenderingManager::updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur) { + if (!old.getRefData().getBaseNode()) + return; Ogre::SceneNode *child = mRendering.getScene()->getSceneNode(old.getRefData().getHandle()); From ad8790fba0b81e03027b3f778cda002eb213155d Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 8 Feb 2015 15:39:10 +0100 Subject: [PATCH 0528/3725] Fix setWaterLevel script instruction not affecting physics --- apps/openmw/mwsound/soundmanagerimp.cpp | 4 ++-- apps/openmw/mwworld/physicssystem.cpp | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index d856f41ee..0bc155118 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -723,9 +723,9 @@ namespace MWSound MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); - const ESM::Cell *cell = player.getCell()->getCell(); + const MWWorld::CellStore *cell = player.getCell(); - mListenerUnderwater = ((cell->mData.mFlags&cell->HasWater) && mListenerPos.z < cell->mWater); + mListenerUnderwater = ((cell->getCell()->mData.mFlags&ESM::Cell::HasWater) && mListenerPos.z < cell->getWaterLevel()); } void SoundManager::updatePtr(const MWWorld::Ptr &old, const MWWorld::Ptr &updated) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index bea99029a..d31ae520b 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -862,9 +862,9 @@ namespace MWWorld for(;iter != mMovementQueue.end();++iter) { float waterlevel = -std::numeric_limits::max(); - const ESM::Cell *cell = iter->first.getCell()->getCell(); - if(cell->hasWater()) - waterlevel = cell->mWater; + const MWWorld::CellStore *cell = iter->first.getCell(); + if(cell->getCell()->hasWater()) + waterlevel = cell->getWaterLevel(); float oldHeight = iter->first.getRefData().getPosition().pos[2]; @@ -872,7 +872,7 @@ namespace MWWorld bool waterCollision = false; if (effects.get(ESM::MagicEffect::WaterWalking).getMagnitude() - && cell->hasWater() + && cell->getCell()->hasWater() && !world->isUnderwater(iter->first.getCell(), Ogre::Vector3(iter->first.getRefData().getPosition().pos))) waterCollision = true; From b542143e3a231bd7418ffc0975793ea2df5a1cb4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 8 Feb 2015 21:04:01 +0100 Subject: [PATCH 0529/3725] Fix faction reputation case sensitivity issue (Fixes #2360) --- apps/openmw/mwmechanics/npcstats.cpp | 30 ++++++++++++++-------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index c517b4df8..f6e3090d7 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -125,6 +125,21 @@ bool MWMechanics::NpcStats::isInFaction (const std::string& faction) const return (mFactionRank.find(Misc::StringUtils::lowerCase(faction)) != mFactionRank.end()); } +int MWMechanics::NpcStats::getFactionReputation (const std::string& faction) const +{ + std::map::const_iterator iter = mFactionReputation.find (Misc::StringUtils::lowerCase(faction)); + + if (iter==mFactionReputation.end()) + return 0; + + return iter->second; +} + +void MWMechanics::NpcStats::setFactionReputation (const std::string& faction, int value) +{ + mFactionReputation[Misc::StringUtils::lowerCase(faction)] = value; +} + float MWMechanics::NpcStats::getSkillGain (int skillIndex, const ESM::Class& class_, int usageType, int level, float extraFactor) const { @@ -329,21 +344,6 @@ void MWMechanics::NpcStats::setBounty (int bounty) mBounty = bounty; } -int MWMechanics::NpcStats::getFactionReputation (const std::string& faction) const -{ - std::map::const_iterator iter = mFactionReputation.find (faction); - - if (iter==mFactionReputation.end()) - return 0; - - return iter->second; -} - -void MWMechanics::NpcStats::setFactionReputation (const std::string& faction, int value) -{ - mFactionReputation[faction] = value; -} - int MWMechanics::NpcStats::getReputation() const { return mReputation; From 9dbd9af31c422fd236e300d53e350c7801ff027e Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 8 Feb 2015 21:26:58 +0100 Subject: [PATCH 0530/3725] Adjust fix for Bug #2360 to repair affected savegames --- apps/openmw/mwmechanics/npcstats.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index f6e3090d7..a3a29acab 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -515,7 +515,7 @@ void MWMechanics::NpcStats::readState (const ESM::NpcStats& state) mFactionRank[iter->first] = iter->second.mRank; if (iter->second.mReputation) - mFactionReputation[iter->first] = iter->second.mReputation; + mFactionReputation[Misc::StringUtils::lowerCase(iter->first)] = iter->second.mReputation; } mDisposition = state.mDisposition; From ec3487b669c35e9df8260fa66f0c2f8de904cf5e Mon Sep 17 00:00:00 2001 From: Jordan Ayers Date: Sun, 8 Feb 2015 14:26:38 -0600 Subject: [PATCH 0531/3725] Sun trajectory: handle mNightStart <= mSunriseTime OMW Bug #781 Note: mNightStart == mSunriseTime is treated as 24-hour night. --- apps/openmw/mwworld/weather.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index dcd8e5a11..7a36d6ac7 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -429,30 +429,32 @@ void WeatherManager::update(float duration, bool paused) else mRendering->getSkyManager()->sunEnable(); - // Update the sun direction. Run it east to west at 15 degrees south from overhead. - // The sun's speed at day and night will differ, since mSunriseTime and mNightStart + // Update the sun direction. Run it east to west at a fixed angle from overhead. + // The sun's speed at day and night may differ, since mSunriseTime and mNightStart // mark when the sun is level with the horizon. { - assert( mNightStart > mSunriseTime ); - + // Shift times into a 24-hour window beginning at mSunriseTime... float adjustedHour = mHour; + float adjustedNightStart = mNightStart; if ( mHour < mSunriseTime ) adjustedHour += 24.f; + if ( mNightStart < mSunriseTime ) + adjustedNightStart += 24.f; - const bool is_night = mHour >= mNightStart || mHour <= mSunriseTime; - const float dayDuration = mNightStart - mSunriseTime; + const bool is_night = adjustedHour >= adjustedNightStart; + const float dayDuration = adjustedNightStart - mSunriseTime; const float nightDuration = 24.f - dayDuration; double theta; if ( !is_night ) { theta = M_PI * (adjustedHour - mSunriseTime) / dayDuration; } else { - theta = M_PI * (adjustedHour - mNightStart) / nightDuration; + theta = M_PI * (adjustedHour - adjustedNightStart) / nightDuration; } Vector3 final( cos( theta ), - -0.268, // approx tan( 15 degrees ) + -0.268f, // approx tan( -15 degrees ) sin( theta ) ); mRendering->setSunDirection( final, is_night ); } From df5a08b6de043ddde3f1f777921d55f9d43ab33b Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Mon, 9 Feb 2015 15:01:49 +0100 Subject: [PATCH 0532/3725] Move manualref code out of header --- apps/openmw/mwclass/misc.cpp | 1 + apps/openmw/mwdialogue/scripttest.cpp | 1 + apps/openmw/mwgui/tradewindow.cpp | 1 + apps/openmw/mwmechanics/enchanting.cpp | 1 + apps/openmw/mwmechanics/levelledlist.hpp | 1 + apps/openmw/mwmechanics/obstacle.hpp | 2 - .../mwscript/transformationextensions.cpp | 1 + apps/openmw/mwworld/manualref.cpp | 67 +++++++++++++++++++ apps/openmw/mwworld/manualref.hpp | 62 +---------------- apps/openmw/mwworld/projectilemanager.cpp | 1 + 10 files changed, 75 insertions(+), 63 deletions(-) create mode 100644 apps/openmw/mwworld/manualref.cpp diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index 271a7510e..f9cfd8e0b 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -12,6 +12,7 @@ #include "../mwworld/ptr.hpp" #include "../mwworld/actiontake.hpp" #include "../mwworld/cellstore.hpp" +#include "../mwworld/esmstore.hpp" #include "../mwworld/physicssystem.hpp" #include "../mwworld/manualref.hpp" #include "../mwworld/nullaction.hpp" diff --git a/apps/openmw/mwdialogue/scripttest.cpp b/apps/openmw/mwdialogue/scripttest.cpp index fd477365f..3f4654610 100644 --- a/apps/openmw/mwdialogue/scripttest.cpp +++ b/apps/openmw/mwdialogue/scripttest.cpp @@ -3,6 +3,7 @@ #include #include "../mwworld/manualref.hpp" +#include "../mwworld/esmstore.hpp" #include "../mwworld/class.hpp" #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 87b2362ef..40cf3e9bf 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -16,6 +16,7 @@ #include "../mwworld/manualref.hpp" #include "../mwworld/class.hpp" #include "../mwworld/containerstore.hpp" +#include "../mwworld/esmstore.hpp" #include "../mwmechanics/creaturestats.hpp" diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp index 002831acc..de5921a70 100644 --- a/apps/openmw/mwmechanics/enchanting.cpp +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -2,6 +2,7 @@ #include "../mwworld/manualref.hpp" #include "../mwworld/class.hpp" #include "../mwworld/containerstore.hpp" +#include "../mwworld/esmstore.hpp" #include "../mwbase/mechanicsmanager.hpp" #include "creaturestats.hpp" diff --git a/apps/openmw/mwmechanics/levelledlist.hpp b/apps/openmw/mwmechanics/levelledlist.hpp index de652a9c8..691996410 100644 --- a/apps/openmw/mwmechanics/levelledlist.hpp +++ b/apps/openmw/mwmechanics/levelledlist.hpp @@ -2,6 +2,7 @@ #define OPENMW_MECHANICS_LEVELLEDLIST_H #include "../mwworld/ptr.hpp" +#include "../mwworld/esmstore.hpp" #include "../mwworld/manualref.hpp" #include "../mwworld/class.hpp" #include "../mwbase/world.hpp" diff --git a/apps/openmw/mwmechanics/obstacle.hpp b/apps/openmw/mwmechanics/obstacle.hpp index 76ab9d029..e2d4d7b42 100644 --- a/apps/openmw/mwmechanics/obstacle.hpp +++ b/apps/openmw/mwmechanics/obstacle.hpp @@ -1,8 +1,6 @@ #ifndef OPENMW_MECHANICS_OBSTACLE_H #define OPENMW_MECHANICS_OBSTACLE_H -//#include "../mwbase/world.hpp" -//#include "../mwworld/class.hpp" #include "../mwworld/cellstore.hpp" namespace MWWorld diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index fcfc36995..15fe58065 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -11,6 +11,7 @@ #include "../mwbase/environment.hpp" +#include "../mwworld/cellstore.hpp" #include "../mwworld/class.hpp" #include "../mwworld/manualref.hpp" #include "../mwworld/player.hpp" diff --git a/apps/openmw/mwworld/manualref.cpp b/apps/openmw/mwworld/manualref.cpp new file mode 100644 index 000000000..30b4fe353 --- /dev/null +++ b/apps/openmw/mwworld/manualref.cpp @@ -0,0 +1,67 @@ +#include "manualref.hpp" + +#include "esmstore.hpp" +#include "cellstore.hpp" + +namespace +{ + + template + void create(const MWWorld::Store& list, const std::string& name, boost::any& refValue, MWWorld::Ptr& ptrValue) + { + const T* base = list.find(name); + + ESM::CellRef cellRef; + cellRef.mRefNum.unset(); + cellRef.mRefID = name; + cellRef.mScale = 1; + cellRef.mFactionRank = 0; + cellRef.mChargeInt = -1; + cellRef.mGoldValue = 1; + cellRef.mEnchantmentCharge = -1; + cellRef.mTeleport = false; + cellRef.mLockLevel = 0; + cellRef.mReferenceBlocked = 0; + + MWWorld::LiveCellRef ref(cellRef, base); + + refValue = ref; + ptrValue = MWWorld::Ptr(&boost::any_cast&>(refValue), 0); + } +} + +MWWorld::ManualRef::ManualRef(const MWWorld::ESMStore& store, const std::string& name, const int count) +{ + std::string lowerName = Misc::StringUtils::lowerCase(name); + switch (store.find(lowerName)) + { + case ESM::REC_ACTI: create(store.get(), lowerName, mRef, mPtr); break; + case ESM::REC_ALCH: create(store.get(), lowerName, mRef, mPtr); break; + case ESM::REC_APPA: create(store.get(), lowerName, mRef, mPtr); break; + case ESM::REC_ARMO: create(store.get(), lowerName, mRef, mPtr); break; + case ESM::REC_BOOK: create(store.get(), lowerName, mRef, mPtr); break; + case ESM::REC_CLOT: create(store.get(), lowerName, mRef, mPtr); break; + case ESM::REC_CONT: create(store.get(), lowerName, mRef, mPtr); break; + case ESM::REC_CREA: create(store.get(), lowerName, mRef, mPtr); break; + case ESM::REC_DOOR: create(store.get(), lowerName, mRef, mPtr); break; + case ESM::REC_INGR: create(store.get(), lowerName, mRef, mPtr); break; + case ESM::REC_LEVC: create(store.get(), lowerName, mRef, mPtr); break; + case ESM::REC_LEVI: create(store.get(), lowerName, mRef, mPtr); break; + case ESM::REC_LIGH: create(store.get(), lowerName, mRef, mPtr); break; + case ESM::REC_LOCK: create(store.get(), lowerName, mRef, mPtr); break; + case ESM::REC_MISC: create(store.get(), lowerName, mRef, mPtr); break; + case ESM::REC_NPC_: create(store.get(), lowerName, mRef, mPtr); break; + case ESM::REC_PROB: create(store.get(), lowerName, mRef, mPtr); break; + case ESM::REC_REPA: create(store.get(), lowerName, mRef, mPtr); break; + case ESM::REC_STAT: create(store.get(), lowerName, mRef, mPtr); break; + case ESM::REC_WEAP: create(store.get(), lowerName, mRef, mPtr); break; + + case 0: + throw std::logic_error("failed to create manual cell ref for " + lowerName + " (unknown ID)"); + + default: + throw std::logic_error("failed to create manual cell ref for " + lowerName + " (unknown type)"); + } + + mPtr.getRefData().setCount(count); +} \ No newline at end of file diff --git a/apps/openmw/mwworld/manualref.hpp b/apps/openmw/mwworld/manualref.hpp index f32b07471..2fc599471 100644 --- a/apps/openmw/mwworld/manualref.hpp +++ b/apps/openmw/mwworld/manualref.hpp @@ -3,9 +3,7 @@ #include -#include "esmstore.hpp" #include "ptr.hpp" -#include "cellstore.hpp" namespace MWWorld { @@ -18,66 +16,8 @@ namespace MWWorld ManualRef (const ManualRef&); ManualRef& operator= (const ManualRef&); - template - void create (const MWWorld::Store& list, const std::string& name) - { - const T* base = list.find(name); - - ESM::CellRef cellRef; - cellRef.mRefNum.unset(); - cellRef.mRefID = name; - cellRef.mScale = 1; - cellRef.mFactionRank = 0; - cellRef.mChargeInt = -1; - cellRef.mGoldValue = 1; - cellRef.mEnchantmentCharge = -1; - cellRef.mTeleport = false; - cellRef.mLockLevel = 0; - cellRef.mReferenceBlocked = 0; - - LiveCellRef ref(cellRef, base); - - mRef = ref; - mPtr = Ptr (&boost::any_cast&> (mRef), 0); - } - public: - - ManualRef (const MWWorld::ESMStore& store, const std::string& name, const int count=1) - { - std::string lowerName = Misc::StringUtils::lowerCase (name); - switch (store.find (lowerName)) - { - case ESM::REC_ACTI: create (store.get(), lowerName); break; - case ESM::REC_ALCH: create (store.get(), lowerName); break; - case ESM::REC_APPA: create (store.get(), lowerName); break; - case ESM::REC_ARMO: create (store.get(), lowerName); break; - case ESM::REC_BOOK: create (store.get(), lowerName); break; - case ESM::REC_CLOT: create (store.get(), lowerName); break; - case ESM::REC_CONT: create (store.get(), lowerName); break; - case ESM::REC_CREA: create (store.get(), lowerName); break; - case ESM::REC_DOOR: create (store.get(), lowerName); break; - case ESM::REC_INGR: create (store.get(), lowerName); break; - case ESM::REC_LEVC: create (store.get(), lowerName); break; - case ESM::REC_LEVI: create (store.get(), lowerName); break; - case ESM::REC_LIGH: create (store.get(), lowerName); break; - case ESM::REC_LOCK: create (store.get(), lowerName); break; - case ESM::REC_MISC: create (store.get(), lowerName); break; - case ESM::REC_NPC_: create (store.get(), lowerName); break; - case ESM::REC_PROB: create (store.get(), lowerName); break; - case ESM::REC_REPA: create (store.get(), lowerName); break; - case ESM::REC_STAT: create (store.get(), lowerName); break; - case ESM::REC_WEAP: create (store.get(), lowerName); break; - - case 0: - throw std::logic_error ("failed to create manual cell ref for " + lowerName + " (unknown ID)"); - - default: - throw std::logic_error ("failed to create manual cell ref for " + lowerName + " (unknown type)"); - } - - mPtr.getRefData().setCount(count); - } + ManualRef(const MWWorld::ESMStore& store, const std::string& name, const int count = 1); const Ptr& getPtr() const { diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 7af51fd28..c97e4e3a5 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -9,6 +9,7 @@ #include "../mwworld/manualref.hpp" #include "../mwworld/class.hpp" +#include "../mwworld/esmstore.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwbase/soundmanager.hpp" From 8c49812d56f428c630fa3ab375e5a906f1b106e6 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Mon, 9 Feb 2015 15:12:10 +0100 Subject: [PATCH 0533/3725] Remove unneeded include in obstacle.hpp --- apps/openmw/mwmechanics/aiwander.hpp | 1 + apps/openmw/mwmechanics/obstacle.hpp | 2 -- apps/openmw/mwworld/worldimp.cpp | 1 + 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 975ebfb81..5e1b41813 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -17,6 +17,7 @@ namespace ESM { + class Cell; namespace AiSequence { struct AiWander; diff --git a/apps/openmw/mwmechanics/obstacle.hpp b/apps/openmw/mwmechanics/obstacle.hpp index e2d4d7b42..e0ae9203d 100644 --- a/apps/openmw/mwmechanics/obstacle.hpp +++ b/apps/openmw/mwmechanics/obstacle.hpp @@ -1,8 +1,6 @@ #ifndef OPENMW_MECHANICS_OBSTACLE_H #define OPENMW_MECHANICS_OBSTACLE_H -#include "../mwworld/cellstore.hpp" - namespace MWWorld { class Ptr; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index a8238d161..3ed273967 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -44,6 +44,7 @@ #include "player.hpp" #include "manualref.hpp" +#include "cellstore.hpp" #include "cellfunctors.hpp" #include "containerstore.hpp" #include "inventorystore.hpp" From d3128a12b6bdb6deb579b4098e0f7e066358daf3 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Mon, 9 Feb 2015 16:23:41 +0100 Subject: [PATCH 0534/3725] Remove a large include form mwbase/windowmanager.hpp --- apps/openmw/mwbase/windowmanager.hpp | 12 ++++++++++-- apps/openmw/mwgui/journalwindow.cpp | 1 + apps/openmw/mwgui/settingswindow.cpp | 1 + apps/openmw/mwgui/windowmanagerimp.cpp | 1 + apps/openmw/mwgui/windowmanagerimp.hpp | 1 + apps/openmw/mwmechanics/npcstats.hpp | 2 -- apps/openmw/mwscript/containerextensions.cpp | 2 ++ 7 files changed, 16 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index c984b5e54..0d0731265 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -1,11 +1,11 @@ #ifndef GAME_MWBASE_WINDOWMANAGER_H #define GAME_MWBASE_WINDOWMANAGER_H +#include #include #include #include - -#include "../mwmechanics/stat.hpp" +#include #include "../mwgui/mode.hpp" @@ -42,6 +42,14 @@ namespace ESM struct CellId; } +namespace MWMechanics +{ + class AttributeValue; + template + class DynamicStat; + class SkillValue; +} + namespace MWWorld { class CellStore; diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index afff5601a..d7e27a277 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -11,6 +11,7 @@ #include #include +#include #include #include diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 281093452..a4f87e598 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -14,6 +14,7 @@ #include +#include #include #include diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 715f47c46..7f32f2b27 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -42,6 +42,7 @@ #include "../mwworld/cellstore.hpp" #include "../mwworld/esmstore.hpp" +#include "../mwmechanics/stat.hpp" #include "../mwmechanics/npcstats.hpp" #include "../mwsound/soundmanagerimp.hpp" diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 9f01b136c..dfeef982b 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -12,6 +12,7 @@ #include "../mwbase/windowmanager.hpp" #include +#include #include "mapwindow.hpp" diff --git a/apps/openmw/mwmechanics/npcstats.hpp b/apps/openmw/mwmechanics/npcstats.hpp index 224366a3e..0b9090f28 100644 --- a/apps/openmw/mwmechanics/npcstats.hpp +++ b/apps/openmw/mwmechanics/npcstats.hpp @@ -6,8 +6,6 @@ #include #include -#include "stat.hpp" - #include "creaturestats.hpp" namespace ESM diff --git a/apps/openmw/mwscript/containerextensions.cpp b/apps/openmw/mwscript/containerextensions.cpp index 58b1b375b..69dfc9972 100644 --- a/apps/openmw/mwscript/containerextensions.cpp +++ b/apps/openmw/mwscript/containerextensions.cpp @@ -14,6 +14,8 @@ #include #include +#include + #include #include "../mwbase/environment.hpp" From f2c5060cc09fd17a4fab0c5c4c36ca6c03e66670 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Mon, 9 Feb 2015 16:37:20 +0100 Subject: [PATCH 0535/3725] Fix cstdint issue on travis GCC build --- apps/openmw/mwbase/windowmanager.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 0d0731265..36a99306b 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -1,7 +1,7 @@ #ifndef GAME_MWBASE_WINDOWMANAGER_H #define GAME_MWBASE_WINDOWMANAGER_H -#include +#include #include #include #include From cfcaf4528fa7f11a283afdd17276c4b5d1d9531c Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Mon, 9 Feb 2015 16:50:34 +0100 Subject: [PATCH 0536/3725] Some more forward-declaring for OpenMW-CS --- apps/opencs/model/world/pathgrid.cpp | 3 ++- apps/opencs/model/world/pathgrid.hpp | 9 ++++++--- apps/opencs/model/world/subcellcollection.hpp | 11 ++++++++++- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/apps/opencs/model/world/pathgrid.cpp b/apps/opencs/model/world/pathgrid.cpp index 1c82585df..5c66e7d8e 100644 --- a/apps/opencs/model/world/pathgrid.cpp +++ b/apps/opencs/model/world/pathgrid.cpp @@ -1,4 +1,5 @@ - +#include "cell.hpp" +#include "idcollection.hpp" #include "pathgrid.hpp" #include diff --git a/apps/opencs/model/world/pathgrid.hpp b/apps/opencs/model/world/pathgrid.hpp index 3c9fcff50..7ce5aff8c 100644 --- a/apps/opencs/model/world/pathgrid.hpp +++ b/apps/opencs/model/world/pathgrid.hpp @@ -6,11 +6,14 @@ #include -#include "idcollection.hpp" -#include "cell.hpp" - namespace CSMWorld { + struct Cell; + template + struct IdAccessor; + template> + class IdCollection; + /// \brief Wrapper for Pathgrid record /// /// \attention The mData.mX and mData.mY fields of the ESM::Pathgrid struct are not used. diff --git a/apps/opencs/model/world/subcellcollection.hpp b/apps/opencs/model/world/subcellcollection.hpp index 28f0de695..2100df4f4 100644 --- a/apps/opencs/model/world/subcellcollection.hpp +++ b/apps/opencs/model/world/subcellcollection.hpp @@ -1,10 +1,19 @@ #ifndef CSM_WOLRD_SUBCOLLECTION_H #define CSM_WOLRD_SUBCOLLECTION_H -#include "idcollection.hpp" +namespace ESM +{ + class ESMReader; +} namespace CSMWorld { + struct Cell; + template + struct IdAccessor; + template> + class IdCollection; + /// \brief Single type collection of top level records that are associated with cells template > class SubCellCollection : public IdCollection From f77ae711e426d873eefc8fc53af9a0b6b9c3b76b Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Mon, 9 Feb 2015 17:10:09 +0100 Subject: [PATCH 0537/3725] Fix template closer --- apps/opencs/model/world/pathgrid.hpp | 2 +- apps/opencs/model/world/subcellcollection.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/world/pathgrid.hpp b/apps/opencs/model/world/pathgrid.hpp index 7ce5aff8c..f13ad38c0 100644 --- a/apps/opencs/model/world/pathgrid.hpp +++ b/apps/opencs/model/world/pathgrid.hpp @@ -11,7 +11,7 @@ namespace CSMWorld struct Cell; template struct IdAccessor; - template> + template > class IdCollection; /// \brief Wrapper for Pathgrid record diff --git a/apps/opencs/model/world/subcellcollection.hpp b/apps/opencs/model/world/subcellcollection.hpp index 2100df4f4..4ed4308ea 100644 --- a/apps/opencs/model/world/subcellcollection.hpp +++ b/apps/opencs/model/world/subcellcollection.hpp @@ -11,7 +11,7 @@ namespace CSMWorld struct Cell; template struct IdAccessor; - template> + template > class IdCollection; /// \brief Single type collection of top level records that are associated with cells From b714e5211d19a341a95bc10bcf4c9e0ef7271227 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Mon, 9 Feb 2015 17:25:55 +0100 Subject: [PATCH 0538/3725] Redefinition of default template argument Sometimes it's annoying how MSVC casually allows you to break C++ standards --- apps/opencs/model/world/pathgrid.hpp | 4 +--- apps/opencs/model/world/subcellcollection.hpp | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/apps/opencs/model/world/pathgrid.hpp b/apps/opencs/model/world/pathgrid.hpp index f13ad38c0..d8cc89f24 100644 --- a/apps/opencs/model/world/pathgrid.hpp +++ b/apps/opencs/model/world/pathgrid.hpp @@ -9,9 +9,7 @@ namespace CSMWorld { struct Cell; - template - struct IdAccessor; - template > + template class IdCollection; /// \brief Wrapper for Pathgrid record diff --git a/apps/opencs/model/world/subcellcollection.hpp b/apps/opencs/model/world/subcellcollection.hpp index 4ed4308ea..74bb6c955 100644 --- a/apps/opencs/model/world/subcellcollection.hpp +++ b/apps/opencs/model/world/subcellcollection.hpp @@ -9,9 +9,7 @@ namespace ESM namespace CSMWorld { struct Cell; - template - struct IdAccessor; - template > + template class IdCollection; /// \brief Single type collection of top level records that are associated with cells From fce404acc5b09a8989444bd155f6fe939a4ac749 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Mon, 9 Feb 2015 17:45:48 +0100 Subject: [PATCH 0539/3725] Remove some including of mwbase/world.hpp Since ref.hpp is rather well used in OpenMW-CS this should help compile times there --- apps/openmw/mwscript/animationextensions.cpp | 1 + apps/openmw/mwscript/containerextensions.cpp | 1 + apps/openmw/mwscript/controlextensions.cpp | 1 + apps/openmw/mwscript/dialogueextensions.cpp | 1 + apps/openmw/mwscript/guiextensions.cpp | 2 +- apps/openmw/mwscript/miscextensions.cpp | 1 + apps/openmw/mwscript/ref.cpp | 29 ++++++++++++++++ apps/openmw/mwscript/ref.hpp | 33 +++++-------------- apps/openmw/mwscript/statsextensions.cpp | 1 + .../mwscript/transformationextensions.cpp | 1 + 10 files changed, 45 insertions(+), 26 deletions(-) create mode 100644 apps/openmw/mwscript/ref.cpp diff --git a/apps/openmw/mwscript/animationextensions.cpp b/apps/openmw/mwscript/animationextensions.cpp index 00b8a9620..c43cdf565 100644 --- a/apps/openmw/mwscript/animationextensions.cpp +++ b/apps/openmw/mwscript/animationextensions.cpp @@ -11,6 +11,7 @@ #include #include +#include "../mwbase/environment.hpp" #include "../mwbase/mechanicsmanager.hpp" #include "interpretercontext.hpp" diff --git a/apps/openmw/mwscript/containerextensions.cpp b/apps/openmw/mwscript/containerextensions.cpp index 69dfc9972..86329191e 100644 --- a/apps/openmw/mwscript/containerextensions.cpp +++ b/apps/openmw/mwscript/containerextensions.cpp @@ -20,6 +20,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwbase/world.hpp" #include "../mwworld/class.hpp" #include "../mwworld/containerstore.hpp" diff --git a/apps/openmw/mwscript/controlextensions.cpp b/apps/openmw/mwscript/controlextensions.cpp index fb6b73be6..fd7fe4737 100644 --- a/apps/openmw/mwscript/controlextensions.cpp +++ b/apps/openmw/mwscript/controlextensions.cpp @@ -10,6 +10,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/inputmanager.hpp" +#include "../mwbase/world.hpp" #include "../mwworld/class.hpp" #include "../mwworld/ptr.hpp" diff --git a/apps/openmw/mwscript/dialogueextensions.cpp b/apps/openmw/mwscript/dialogueextensions.cpp index ea4b8d06e..8b6805264 100644 --- a/apps/openmw/mwscript/dialogueextensions.cpp +++ b/apps/openmw/mwscript/dialogueextensions.cpp @@ -11,6 +11,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/dialoguemanager.hpp" #include "../mwbase/journal.hpp" +#include "../mwbase/world.hpp" #include "../mwworld/class.hpp" #include "../mwmechanics/npcstats.hpp" diff --git a/apps/openmw/mwscript/guiextensions.cpp b/apps/openmw/mwscript/guiextensions.cpp index f5549a172..40c555f50 100644 --- a/apps/openmw/mwscript/guiextensions.cpp +++ b/apps/openmw/mwscript/guiextensions.cpp @@ -12,7 +12,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" - +#include "../mwbase/world.hpp" #include "../mwbase/mechanicsmanager.hpp" #include "interpretercontext.hpp" diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index bffeef768..f4e82ebd4 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -17,6 +17,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwbase/scriptmanager.hpp" +#include "../mwbase/world.hpp" #include "../mwworld/class.hpp" #include "../mwworld/player.hpp" diff --git a/apps/openmw/mwscript/ref.cpp b/apps/openmw/mwscript/ref.cpp new file mode 100644 index 000000000..6347c2c2e --- /dev/null +++ b/apps/openmw/mwscript/ref.cpp @@ -0,0 +1,29 @@ +#include "ref.hpp" + +#include + +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" + +#include "interpretercontext.hpp" + +MWWorld::Ptr MWScript::ExplicitRef::operator() (Interpreter::Runtime& runtime, bool required, + bool activeOnly) const +{ + std::string id = runtime.getStringLiteral(runtime[0].mInteger); + runtime.pop(); + + if (required) + return MWBase::Environment::get().getWorld()->getPtr(id, activeOnly); + else + return MWBase::Environment::get().getWorld()->searchPtr(id, activeOnly); +} + +MWWorld::Ptr MWScript::ImplicitRef::operator() (Interpreter::Runtime& runtime, bool required, + bool activeOnly) const +{ + MWScript::InterpreterContext& context + = static_cast (runtime.getContext()); + + return context.getReference(required); +} diff --git a/apps/openmw/mwscript/ref.hpp b/apps/openmw/mwscript/ref.hpp index 18f7453e4..e572f5147 100644 --- a/apps/openmw/mwscript/ref.hpp +++ b/apps/openmw/mwscript/ref.hpp @@ -3,14 +3,12 @@ #include -#include - -#include "../mwbase/environment.hpp" -#include "../mwbase/world.hpp" - #include "../mwworld/ptr.hpp" -#include "interpretercontext.hpp" +namespace Interpreter +{ + class Runtime; +} namespace MWScript { @@ -18,31 +16,16 @@ namespace MWScript { static const bool implicit = false; - MWWorld::Ptr operator() (Interpreter::Runtime& runtime, bool required=true, - bool activeOnly = false) const - { - std::string id = runtime.getStringLiteral (runtime[0].mInteger); - runtime.pop(); - - if (required) - return MWBase::Environment::get().getWorld()->getPtr (id, activeOnly); - else - return MWBase::Environment::get().getWorld()->searchPtr (id, activeOnly); - } + MWWorld::Ptr operator() (Interpreter::Runtime& runtime, bool required = true, + bool activeOnly = false) const; }; struct ImplicitRef { static const bool implicit = true; - MWWorld::Ptr operator() (Interpreter::Runtime& runtime, bool required=true, - bool activeOnly = false) const - { - MWScript::InterpreterContext& context - = static_cast (runtime.getContext()); - - return context.getReference(required); - } + MWWorld::Ptr operator() (Interpreter::Runtime& runtime, bool required = true, + bool activeOnly = false) const; }; } diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index abef636cc..b8bb76388 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -18,6 +18,7 @@ #include "../mwbase/dialoguemanager.hpp" #include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwbase/world.hpp" #include "../mwworld/class.hpp" #include "../mwworld/player.hpp" diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 15fe58065..7af35a9ff 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -10,6 +10,7 @@ #include #include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" #include "../mwworld/cellstore.hpp" #include "../mwworld/class.hpp" From a7320781a5e46400f359de39c032fbc233954919 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 9 Feb 2015 17:58:33 +0100 Subject: [PATCH 0540/3725] updated credits file --- AUTHORS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AUTHORS.md b/AUTHORS.md index bc39b1c70..59aa42721 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -33,7 +33,7 @@ Programmers Douglas Diniz (Dgdiniz) Douglas Mencken (dougmencken) dreamer-dead - dteviot + David Teviotdale (dteviot) Edmondo Tommasina (edmondo) Eduard Cot (trombonecot) Eli2 From dbd4abd6fe3ae3b3f1e812c8069b094bad50846e Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 9 Feb 2015 19:28:29 +0100 Subject: [PATCH 0541/3725] Fix ripples for D3D - added simpler effect (Fixes #1649) --- apps/openmw/engine.cpp | 1 + apps/openmw/mwrender/renderconst.hpp | 1 + apps/openmw/mwrender/renderingmanager.cpp | 3 +- apps/openmw/mwrender/ripplesimulation.cpp | 275 ++++++------------ apps/openmw/mwrender/ripplesimulation.hpp | 62 ++-- apps/openmw/mwrender/water.cpp | 20 +- apps/openmw/mwrender/water.hpp | 9 +- apps/openmw/mwworld/fallback.cpp | 9 + apps/openmw/mwworld/fallback.hpp | 1 + files/CMakeLists.txt | 7 +- files/materials/ripples.particle | 26 ++ files/materials/water.mat | 24 ++ files/materials/water.shader | 17 +- files/materials/watersim.mat | 59 ---- files/materials/watersim.shaderset | 31 -- files/materials/watersim_addimpulse.shader | 12 - files/materials/watersim_common.h | 25 -- files/materials/watersim_heightmap.shader | 51 ---- .../materials/watersim_heighttonormal.shader | 36 --- 19 files changed, 195 insertions(+), 474 deletions(-) create mode 100644 files/materials/ripples.particle delete mode 100644 files/materials/watersim.mat delete mode 100644 files/materials/watersim.shaderset delete mode 100644 files/materials/watersim_addimpulse.shader delete mode 100644 files/materials/watersim_common.h delete mode 100644 files/materials/watersim_heightmap.shader delete mode 100644 files/materials/watersim_heighttonormal.shader diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 859baebe4..9b87c612d 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -349,6 +349,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) addResourcesDirectory(mResDir / "mygui"); addResourcesDirectory(mResDir / "water"); addResourcesDirectory(mResDir / "shadows"); + addResourcesDirectory(mResDir / "materials"); OEngine::Render::WindowSettings windowSettings; windowSettings.fullscreen = settings.getBool("fullscreen", "Video"); diff --git a/apps/openmw/mwrender/renderconst.hpp b/apps/openmw/mwrender/renderconst.hpp index 4ac21ad51..cfd84cb32 100644 --- a/apps/openmw/mwrender/renderconst.hpp +++ b/apps/openmw/mwrender/renderconst.hpp @@ -21,6 +21,7 @@ enum RenderQueueGroups RQG_UnderWater = Ogre::RENDER_QUEUE_4, RQG_Water = RQG_Alpha, + RQG_Ripples = RQG_Water+1, // Sky late (sun & sun flare) RQG_SkiesLate = Ogre::RENDER_QUEUE_SKIES_LATE diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 88ede1682..8b7f04b19 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -175,7 +175,7 @@ RenderingManager::RenderingManager(OEngine::Render::OgreRenderer& _rend, const b mDebugging = new Debugging(mRootNode, engine); mLocalMap = new MWRender::LocalMap(&mRendering, this); - mWater = new MWRender::Water(mRendering.getCamera(), this); + mWater = new MWRender::Water(mRendering.getCamera(), this, mFallback); setMenuTransparency(Settings::Manager::getFloat("menu transparency", "GUI")); } @@ -693,6 +693,7 @@ void RenderingManager::enableLights(bool sun) void RenderingManager::notifyWorldSpaceChanged() { mEffectManager->clear(); + mWater->clearRipples(); } Ogre::Vector4 RenderingManager::boundingBoxToScreen(Ogre::AxisAlignedBox bounds) diff --git a/apps/openmw/mwrender/ripplesimulation.cpp b/apps/openmw/mwrender/ripplesimulation.cpp index 64b5e48c3..84794162f 100644 --- a/apps/openmw/mwrender/ripplesimulation.cpp +++ b/apps/openmw/mwrender/ripplesimulation.cpp @@ -1,162 +1,72 @@ #include "ripplesimulation.hpp" -#include -#include -#include -#include -#include +#include + #include -#include -#include +#include +#include +#include #include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" -namespace MWRender -{ +#include "../mwworld/fallback.hpp" +#include "renderconst.hpp" -RippleSimulation::RippleSimulation(Ogre::SceneManager* mainSceneManager) - : mMainSceneMgr(mainSceneManager), - mTime(0), - mCurrentFrameOffset(0,0), - mPreviousFrameOffset(0,0), - mRippleCenter(0,0), - mTextureSize(512), - mRippleAreaLength(1000), - mImpulseSize(20), - mTexelOffset(0,0), - mFirstUpdate(true), - mRectangle(NULL), - mImpulse(NULL) +namespace MWRender { - Ogre::AxisAlignedBox aabInf; - aabInf.setInfinite(); - - mSceneMgr = Ogre::Root::getSingleton().createSceneManager(Ogre::ST_GENERIC); - - mCamera = mSceneMgr->createCamera("RippleCamera"); - - mRectangle = new Ogre::Rectangle2D(true); - mRectangle->setBoundingBox(aabInf); - mRectangle->setCorners(-1.0, 1.0, 1.0, -1.0, false); - Ogre::SceneNode* node = mSceneMgr->getRootSceneNode()->createChildSceneNode(); - node->attachObject(mRectangle); - mImpulse = new Ogre::Rectangle2D(true); - mImpulse->setCorners(-0.1, 0.1, 0.1, -0.1, false); - mImpulse->setBoundingBox(aabInf); - mImpulse->setMaterial("AddImpulse"); - Ogre::SceneNode* impulseNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(); - impulseNode->attachObject(mImpulse); - - //float w=0.05; - for (int i=0; i<4; ++i) - { - Ogre::TexturePtr texture; - if (i != 3) - texture = Ogre::TextureManager::getSingleton().createManual("RippleHeight" + Ogre::StringConverter::toString(i), - Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::TEX_TYPE_2D, mTextureSize, mTextureSize, 1, 0, Ogre::PF_R8G8B8, Ogre::TU_RENDERTARGET); - else - texture = Ogre::TextureManager::getSingleton().createManual("RippleNormal", - Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::TEX_TYPE_2D, mTextureSize, mTextureSize, 1, 0, Ogre::PF_R8G8B8, Ogre::TU_RENDERTARGET); - - - Ogre::RenderTexture* rt = texture->getBuffer()->getRenderTarget(); - rt->removeAllViewports(); - rt->addViewport(mCamera); - rt->setAutoUpdated(false); - rt->getViewport(0)->setClearEveryFrame(false); +RippleSimulation::RippleSimulation(Ogre::SceneManager* mainSceneManager, const MWWorld::Fallback* fallback) + : mSceneMgr(mainSceneManager) + , mParticleSystem(NULL) + , mSceneNode(NULL) +{ + mRippleLifeTime = fallback->getFallbackFloat("Water_RippleLifetime"); + mRippleRotSpeed = fallback->getFallbackFloat("Water_RippleRotSpeed"); - // debug overlay - /* - Ogre::Rectangle2D* debugOverlay = new Ogre::Rectangle2D(true); - debugOverlay->setCorners(w*2-1, 0.9, (w+0.18)*2-1, 0.4, false); - w += 0.2; - debugOverlay->setBoundingBox(aabInf); - Ogre::SceneNode* debugNode = mMainSceneMgr->getRootSceneNode()->createChildSceneNode(); - debugNode->attachObject(debugOverlay); + // Unknown: + // fallback=Water_RippleScale,0.15, 6.5 + // fallback=Water_RippleAlphas,0.7, 0.1, 0.01 - Ogre::MaterialPtr debugMaterial = Ogre::MaterialManager::getSingleton().create("RippleDebug" + Ogre::StringConverter::toString(i), - Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); + // Instantiate from ripples.particle file + mParticleSystem = mSceneMgr->createParticleSystem("openmw/Ripples", "openmw/Ripples"); - if (i != 3) - debugMaterial->getTechnique(0)->getPass(0)->createTextureUnitState("RippleHeight" + Ogre::StringConverter::toString(i)); - else - debugMaterial->getTechnique(0)->getPass(0)->createTextureUnitState("RippleNormal"); - debugMaterial->getTechnique(0)->getPass(0)->setLightingEnabled(false); + mParticleSystem->setRenderQueueGroup(RQG_Ripples); + mParticleSystem->setVisibilityFlags(RV_Effects); - debugOverlay->setMaterial("RippleDebug" + Ogre::StringConverter::toString(i)); - */ + int rippleFrameCount = fallback->getFallbackInt("Water_RippleFrameCount"); + std::string tex = fallback->getFallbackString("Water_RippleTexture"); - mRenderTargets[i] = rt; - mTextures[i] = texture; - } + sh::MaterialInstance* mat = sh::Factory::getInstance().getMaterialInstance("openmw/Ripple"); + mat->setProperty("anim_texture2", sh::makeProperty(new sh::StringValue(std::string("textures\\water\\") + tex + ".dds " + + Ogre::StringConverter::toString(rippleFrameCount) + + " " + + Ogre::StringConverter::toString(0.3)))); - sh::Factory::getInstance().setSharedParameter("rippleTextureSize", sh::makeProperty( - new sh::Vector4(1.0/512, 1.0/512, 512, 512))); - sh::Factory::getInstance().setSharedParameter("rippleCenter", sh::makeProperty( - new sh::Vector3(0, 0, 0))); - sh::Factory::getInstance().setSharedParameter("rippleAreaLength", sh::makeProperty( - new sh::FloatValue(mRippleAreaLength))); + // seems to be required to allocate mFreeParticles. TODO: patch Ogre to handle this better + mParticleSystem->_update(0.f); + mSceneNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(); + mSceneNode->attachObject(mParticleSystem); } RippleSimulation::~RippleSimulation() { - delete mRectangle; - delete mImpulse; + if (mParticleSystem) + mSceneMgr->destroyParticleSystem(mParticleSystem); + mParticleSystem = NULL; - Ogre::Root::getSingleton().destroySceneManager(mSceneMgr); + if (mSceneNode) + mSceneMgr->destroySceneNode(mSceneNode); + mSceneNode = NULL; } void RippleSimulation::update(float dt, Ogre::Vector2 position) { - // try to keep 20 fps - mTime += dt; - - while (mTime >= 1/20.0 || mFirstUpdate) - { - mPreviousFrameOffset = mCurrentFrameOffset; - - mCurrentFrameOffset = position - mRippleCenter; - // add texel offsets from previous frame. - mCurrentFrameOffset += mTexelOffset; - - mTexelOffset = Ogre::Vector2(std::fmod(mCurrentFrameOffset.x, 1.0f/mTextureSize), - std::fmod(mCurrentFrameOffset.y, 1.0f/mTextureSize)); - - // now subtract new offset in order to snap to texels - mCurrentFrameOffset -= mTexelOffset; - - // texture coordinate space - mCurrentFrameOffset /= mRippleAreaLength; - - mRippleCenter = position; - - addImpulses(); - waterSimulation(); - heightMapToNormalMap(); - - swapHeightMaps(); - if (!mFirstUpdate) - mTime -= 1/20.0; - else - mFirstUpdate = false; - } - - sh::Factory::getInstance().setSharedParameter("rippleCenter", sh::makeProperty( - new sh::Vector3(mRippleCenter.x + mTexelOffset.x, mRippleCenter.y + mTexelOffset.y, 0))); -} - -void RippleSimulation::addImpulses() -{ - mRectangle->setVisible(false); - mImpulse->setVisible(true); - - /// \todo it should be more efficient to render all emitters at once + bool newParticle = false; for (std::vector::iterator it=mEmitters.begin(); it !=mEmitters.end(); ++it) { if (it->mPtr == MWBase::Environment::get().getWorld ()->getPlayerPtr()) @@ -165,69 +75,50 @@ void RippleSimulation::addImpulses() // for non-player actors this is done in updateObjectCell it->mPtr = MWBase::Environment::get().getWorld ()->getPlayerPtr(); } - const float* _currentPos = it->mPtr.getRefData().getPosition().pos; - Ogre::Vector3 currentPos (_currentPos[0], _currentPos[1], _currentPos[2]); - - if ( (currentPos - it->mLastEmitPosition).length() > 2 - && MWBase::Environment::get().getWorld ()->isUnderwater (it->mPtr.getCell(), currentPos)) + Ogre::Vector3 currentPos (it->mPtr.getRefData().getPosition().pos); + currentPos.z = 0; + if ( (currentPos - it->mLastEmitPosition).length() > 10 + // Only emit when close to the water surface, not above it and not too deep in the water + && MWBase::Environment::get().getWorld ()->isUnderwater (it->mPtr.getCell(), + Ogre::Vector3(it->mPtr.getRefData().getPosition().pos)) + && !MWBase::Environment::get().getWorld()->isSubmerged(it->mPtr)) { it->mLastEmitPosition = currentPos; - Ogre::Vector2 pos (currentPos.x, currentPos.y); - pos -= mRippleCenter; - pos /= mRippleAreaLength; - float size = mImpulseSize / mRippleAreaLength; - mImpulse->setCorners(pos.x-size, pos.y+size, pos.x+size, pos.y-size, false); - - // don't render if we are offscreen - if (pos.x - size >= 1.0 || pos.y+size <= -1.0 || pos.x+size <= -1.0 || pos.y-size >= 1.0) - continue; - mRenderTargets[1]->update(); + newParticle = true; + Ogre::Particle* created = mParticleSystem->createParticle(); + if (!created) + break; // TODO: cleanup the oldest particle to make room +#if OGRE_VERSION >= (1 << 16 | 10 << 8 | 0) + Ogre::Vector3& position = created->mPosition; + Ogre::Vector3& direction = created->mDirection; + Ogre::ColourValue& colour = created->mColour; + float& totalTimeToLive = created->mTotalTimeToLive; + float& timeToLive = created->mTimeToLive; + Ogre::Radian& rotSpeed = created->mRotationSpeed; + Ogre::Radian& rotation = created->mRotation; +#else + Ogre::Vector3& position = created->position; + Ogre::Vector3& direction = created->direction; + Ogre::ColourValue& colour = created->colour; + float& totalTimeToLive = created->totalTimeToLive; + float& timeToLive = created->timeToLive; + Ogre::Radian& rotSpeed = created->rotationSpeed; + Ogre::Radian& rotation = created->rotation; +#endif + timeToLive = totalTimeToLive = mRippleLifeTime; + colour = Ogre::ColourValue(0.f, 0.f, 0.f, 0.7); // Water_RippleAlphas.x? + direction = Ogre::Vector3(0,0,0); + position = currentPos; + position.z = 0; // Z is set by the Scene Node + rotSpeed = mRippleRotSpeed; + rotation = Ogre::Radian(Ogre::Math::RangeRandom(-Ogre::Math::PI, Ogre::Math::PI)); + created->setDimensions(50,50); } } - mImpulse->setVisible(false); - mRectangle->setVisible(true); -} - -void RippleSimulation::waterSimulation() -{ - mRectangle->setMaterial("HeightmapSimulation"); - - sh::Factory::getInstance().setTextureAlias("Heightmap0", mTextures[0]->getName()); - sh::Factory::getInstance().setTextureAlias("Heightmap1", mTextures[1]->getName()); - - sh::Factory::getInstance().setSharedParameter("currentFrameOffset", sh::makeProperty( - new sh::Vector3(mCurrentFrameOffset.x, mCurrentFrameOffset.y, 0))); - sh::Factory::getInstance().setSharedParameter("previousFrameOffset", sh::makeProperty( - new sh::Vector3(mPreviousFrameOffset.x, mPreviousFrameOffset.y, 0))); - - mRenderTargets[2]->update(); -} - -void RippleSimulation::heightMapToNormalMap() -{ - mRectangle->setMaterial("HeightToNormalMap"); - - sh::Factory::getInstance().setTextureAlias("Heightmap2", mTextures[2]->getName()); - - mRenderTargets[TEX_NORMAL]->update(); -} - -void RippleSimulation::swapHeightMaps() -{ - // 0 -> 1 -> 2 to 2 -> 0 ->1 - Ogre::RenderTexture* tmp = mRenderTargets[0]; - Ogre::TexturePtr tmp2 = mTextures[0]; - - mRenderTargets[0] = mRenderTargets[1]; - mTextures[0] = mTextures[1]; - - mRenderTargets[1] = mRenderTargets[2]; - mTextures[1] = mTextures[2]; - - mRenderTargets[2] = tmp; - mTextures[2] = tmp2; + if (newParticle) // now apparently needs another update, otherwise it won't render in the first frame after a particle is created. TODO: patch Ogre to handle this better + mParticleSystem->_update(0.f); } void RippleSimulation::addEmitter(const MWWorld::Ptr& ptr, float scale, float force) @@ -264,5 +155,15 @@ void RippleSimulation::updateEmitterPtr (const MWWorld::Ptr& old, const MWWorld: } } +void RippleSimulation::setWaterHeight(float height) +{ + mSceneNode->setPosition(0,0,height); +} + +void RippleSimulation::clear() +{ + mParticleSystem->clear(); +} + } diff --git a/apps/openmw/mwrender/ripplesimulation.hpp b/apps/openmw/mwrender/ripplesimulation.hpp index e203212cf..4551476a4 100644 --- a/apps/openmw/mwrender/ripplesimulation.hpp +++ b/apps/openmw/mwrender/ripplesimulation.hpp @@ -1,19 +1,19 @@ #ifndef RIPPLE_SIMULATION_H #define RIPPLE_SIMULATION_H -#include -#include -#include #include #include "../mwworld/ptr.hpp" namespace Ogre { - class RenderTexture; - class Camera; class SceneManager; - class Rectangle2D; + class ParticleSystem; +} + +namespace MWWorld +{ + class Fallback; } namespace MWRender @@ -30,9 +30,11 @@ struct Emitter class RippleSimulation { public: - RippleSimulation(Ogre::SceneManager* mainSceneManager); + RippleSimulation(Ogre::SceneManager* mainSceneManager, const MWWorld::Fallback* fallback); ~RippleSimulation(); + /// @param dt Time since the last frame + /// @param position Position of the player void update(float dt, Ogre::Vector2 position); /// adds an emitter, position will be tracked automatically @@ -40,47 +42,21 @@ public: void removeEmitter (const MWWorld::Ptr& ptr); void updateEmitterPtr (const MWWorld::Ptr& old, const MWWorld::Ptr& ptr); -private: - RippleSimulation(const RippleSimulation&); - RippleSimulation& operator=(const RippleSimulation&); - - std::vector mEmitters; - - Ogre::RenderTexture* mRenderTargets[4]; - Ogre::TexturePtr mTextures[4]; - - int mTextureSize; - float mRippleAreaLength; - float mImpulseSize; - - bool mFirstUpdate; + /// Change the height of the water surface, thus moving all ripples with it + void setWaterHeight(float height); - Ogre::Camera* mCamera; + /// Remove all active ripples + void clear(); - // own scenemanager to render our simulation +private: Ogre::SceneManager* mSceneMgr; - Ogre::Rectangle2D* mRectangle; - - // scenemanager to create the debug overlays on - Ogre::SceneManager* mMainSceneMgr; - - static const int TEX_NORMAL = 3; - - Ogre::Rectangle2D* mImpulse; + Ogre::ParticleSystem* mParticleSystem; + Ogre::SceneNode* mSceneNode; - void addImpulses(); - void heightMapToNormalMap(); - void waterSimulation(); - void swapHeightMaps(); - - float mTime; - - Ogre::Vector2 mRippleCenter; - - Ogre::Vector2 mTexelOffset; + std::vector mEmitters; - Ogre::Vector2 mCurrentFrameOffset; - Ogre::Vector2 mPreviousFrameOffset; + float mRippleLifeTime; + float mRippleRotSpeed; }; } diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 44e184269..456fc47e9 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -20,9 +20,6 @@ #include #include -#include "../mwbase/environment.hpp" -#include "../mwbase/world.hpp" - using namespace Ogre; namespace MWRender @@ -187,7 +184,7 @@ void PlaneReflection::setVisibilityMask (int flags) // -------------------------------------------------------------------------------------------------------------------------------- -Water::Water (Ogre::Camera *camera, RenderingManager* rend) : +Water::Water (Ogre::Camera *camera, RenderingManager* rend, const MWWorld::Fallback* fallback) : mCamera (camera), mSceneMgr (camera->getSceneManager()), mIsUnderwater(false), mVisibilityFlags(0), mActive(1), mToggled(1), @@ -198,7 +195,7 @@ Water::Water (Ogre::Camera *camera, RenderingManager* rend) : mSimulation(NULL), mPlayer(0,0) { - mSimulation = new RippleSimulation(mSceneMgr); + mSimulation = new RippleSimulation(mSceneMgr, fallback); mSky = rend->getSkyManager(); @@ -313,6 +310,8 @@ void Water::setHeight(const float height) { mTop = height; + mSimulation->setWaterHeight(height); + mWaterPlane = Plane(Vector3::UNIT_Z, -height); if (mReflection) @@ -382,9 +381,13 @@ void Water::update(float dt, Ogre::Vector3 player) void Water::frameStarted(float dt) { + if (!mActive) + return; + + mSimulation->update(dt, mPlayer); + if (mReflection) { - mSimulation->update(dt, mPlayer); mReflection->update(); } } @@ -497,4 +500,9 @@ void Water::updateEmitterPtr (const MWWorld::Ptr& old, const MWWorld::Ptr& ptr) mSimulation->updateEmitterPtr(old, ptr); } +void Water::clearRipples() +{ + mSimulation->clear(); +} + } // namespace diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index 6a7b05a3a..10d0a06ff 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -30,6 +30,11 @@ namespace Ogre struct RenderTargetEvent; } +namespace MWWorld +{ + class Fallback; +} + namespace MWRender { class SkyManager; @@ -145,9 +150,11 @@ namespace MWRender { Ogre::Vector2 mPlayer; public: - Water (Ogre::Camera *camera, RenderingManager* rend); + Water (Ogre::Camera *camera, RenderingManager* rend, const MWWorld::Fallback* fallback); ~Water(); + void clearRipples(); + void setActive(bool active); bool toggle(); diff --git a/apps/openmw/mwworld/fallback.cpp b/apps/openmw/mwworld/fallback.cpp index c0b21b2ef..3a8154ca7 100644 --- a/apps/openmw/mwworld/fallback.cpp +++ b/apps/openmw/mwworld/fallback.cpp @@ -22,6 +22,15 @@ namespace MWWorld else return boost::lexical_cast(fallback); } + int Fallback::getFallbackInt(const std::string& fall) const + { + std::string fallback=getFallbackString(fall); + if(fallback.empty()) + return 0; + else + return boost::lexical_cast(fallback); + } + bool Fallback::getFallbackBool(const std::string& fall) const { std::string fallback=getFallbackString(fall); diff --git a/apps/openmw/mwworld/fallback.hpp b/apps/openmw/mwworld/fallback.hpp index 6c5802e07..f69a5e57b 100644 --- a/apps/openmw/mwworld/fallback.hpp +++ b/apps/openmw/mwworld/fallback.hpp @@ -15,6 +15,7 @@ namespace MWWorld Fallback(const std::map& fallback); std::string getFallbackString(const std::string& fall) const; float getFallbackFloat(const std::string& fall) const; + int getFallbackInt(const std::string& fall) const; bool getFallbackBool(const std::string& fall) const; Ogre::ColourValue getFallbackColour(const std::string& fall) const; }; diff --git a/files/CMakeLists.txt b/files/CMakeLists.txt index 9b2325744..da3451d93 100644 --- a/files/CMakeLists.txt +++ b/files/CMakeLists.txt @@ -38,15 +38,10 @@ set(MATERIAL_FILES selection.mat selection.shader selection.shaderset - watersim_heightmap.shader - watersim_addimpulse.shader - watersim_heighttonormal.shader - watersim_common.h - watersim.mat - watersim.shaderset mygui.mat mygui.shader mygui.shaderset + ripples.particle ) copy_all_files(${CMAKE_CURRENT_SOURCE_DIR}/water "${OpenMW_BINARY_DIR}/resources/water/" "${WATER_FILES}") diff --git a/files/materials/ripples.particle b/files/materials/ripples.particle new file mode 100644 index 000000000..e8402b691 --- /dev/null +++ b/files/materials/ripples.particle @@ -0,0 +1,26 @@ +particle_system openmw/Ripples +{ + material openmw/Ripple + particle_width 50 + particle_height 50 + // To make the particles move with the scene node when the waterlevel changes + local_space true + quota 300 + billboard_type perpendicular_common + common_up_vector 0 1 0 + common_direction 0 0 1 + + affector ColourFader + { + alpha -0.33 + } + + affector Scaler + { + rate 100 + } + + affector Rotator + { + } +} diff --git a/files/materials/water.mat b/files/materials/water.mat index ade55f326..cf03be39e 100644 --- a/files/materials/water.mat +++ b/files/materials/water.mat @@ -75,3 +75,27 @@ material Water } } } + +material openmw/Ripple +{ + // this will be overridden by Water_RippleFrameCount fallback setting + anim_texture2 textures\water\ripple.dds 4 0.25 + pass + { + scene_blend alpha_blend + depth_write off + cull_hardware none + diffuse vertexcolour + emissive 1 1 1 + ambient 0 0 0 + texture_unit diffuseMap + { + create_in_ffp true + anim_texture2 $anim_texture2 + + // to make sure rotating doesn't cause the texture to repeat + tex_address_mode border + tex_border_colour 0 0 0 0 + } + } +} diff --git a/files/materials/water.shader b/files/materials/water.shader index 4dec57276..373277d0b 100644 --- a/files/materials/water.shader +++ b/files/materials/water.shader @@ -64,7 +64,6 @@ #include "shadows.h" #endif -#define RIPPLES 1 #define REFRACTION @shGlobalSettingBool(refraction) #ifdef SH_VERTEX_SHADER @@ -187,11 +186,6 @@ shInput(float3, screenCoordsPassthrough) shInput(float4, position) shInput(float, depthPassthrough) - - #if RIPPLES - shUniform(float3, rippleCenter) @shSharedParameter(rippleCenter, rippleCenter) - shUniform(float, rippleAreaLength) @shSharedParameter(rippleAreaLength, rippleAreaLength) - #endif shUniform(float, far) @shAutoConstant(far, far_clip_distance) @@ -203,10 +197,6 @@ shSampler2D(normalMap) shUniform(float4x4, wMat) @shAutoConstant(wMat, world_matrix) - - #if RIPPLES - shSampler2D(rippleNormalMap) - #endif shUniform(float3, windDir_windSpeed) @shSharedParameter(windDir_windSpeed) #define WIND_SPEED windDir_windSpeed.z @@ -296,12 +286,7 @@ normal2 * MID_WAVES_X + normal3 * MID_WAVES_Y + normal4 * SMALL_WAVES_X + normal5 * SMALL_WAVES_Y); - float4 worldPosition = shMatrixMult(wMat, float4(position.xyz, 1)); - float2 relPos = (worldPosition.xy - rippleCenter.xy) / rippleAreaLength + 0.5; - float3 normal_ripple = normalize(shSample(rippleNormalMap, relPos.xy).xyz * 2.0 - 1.0); - - //normal = normalize(normal + normal_ripple); - normal = normalize(float3(normal.x * BUMP + normal_ripple.x, normal.y * BUMP + normal_ripple.y, normal.z)); + normal = normalize(float3(normal.x * BUMP, normal.y * BUMP, normal.z)); normal = float3(normal.x, normal.y, -normal.z); // normal for sunlight scattering diff --git a/files/materials/watersim.mat b/files/materials/watersim.mat deleted file mode 100644 index b58b1a851..000000000 --- a/files/materials/watersim.mat +++ /dev/null @@ -1,59 +0,0 @@ -material HeightmapSimulation -{ - allow_fixed_function false - pass - { - depth_check off - depth_write off - vertex_program transform_vertex - fragment_program watersim_fragment - - texture_unit heightPrevSampler - { - tex_address_mode border - tex_border_colour 0 0 0 - texture_alias Heightmap0 - } - texture_unit heightCurrentSampler - { - tex_address_mode border - tex_border_colour 0 0 0 - texture_alias Heightmap1 - } - } -} - -material HeightToNormalMap -{ - allow_fixed_function false - pass - { - depth_check off - depth_write off - vertex_program transform_vertex - fragment_program height_to_normal_fragment - - texture_unit heightCurrentSampler - { - texture_alias Heightmap2 - } - } -} - -material AddImpulse -{ - allow_fixed_function false - pass - { - depth_check off - depth_write off - scene_blend alpha_blend - vertex_program transform_vertex - fragment_program add_impulse_fragment - - texture_unit alphaMap - { - texture circle.png - } - } -} diff --git a/files/materials/watersim.shaderset b/files/materials/watersim.shaderset deleted file mode 100644 index ea512e25f..000000000 --- a/files/materials/watersim.shaderset +++ /dev/null @@ -1,31 +0,0 @@ -shader_set transform_vertex -{ - source quad.shader - type vertex - profiles_cg vs_2_0 vp40 arbvp1 - profiles_hlsl vs_2_0 -} - -shader_set watersim_fragment -{ - source watersim_heightmap.shader - type fragment - profiles_cg ps_3_0 ps_2_x ps_2_0 fp40 arbfp1 - profiles_hlsl ps_3_0 ps_2_0 -} - -shader_set height_to_normal_fragment -{ - source watersim_heighttonormal.shader - type fragment - profiles_cg ps_3_0 ps_2_x ps_2_0 fp40 arbfp1 - profiles_hlsl ps_3_0 ps_2_0 -} - -shader_set add_impulse_fragment -{ - source watersim_addimpulse.shader - type fragment - profiles_cg ps_3_0 ps_2_x ps_2_0 fp40 arbfp1 - profiles_hlsl ps_3_0 ps_2_0 -} diff --git a/files/materials/watersim_addimpulse.shader b/files/materials/watersim_addimpulse.shader deleted file mode 100644 index 3ca4192cd..000000000 --- a/files/materials/watersim_addimpulse.shader +++ /dev/null @@ -1,12 +0,0 @@ -#include "core.h" -#include "watersim_common.h" - - SH_BEGIN_PROGRAM - shInput(float2, UV) - shSampler2D(alphaMap) - - SH_START_PROGRAM - { - shOutputColour(0) = EncodeHeightmap(1.0); - shOutputColour(0).a = shSample (alphaMap, UV.xy).a; - } diff --git a/files/materials/watersim_common.h b/files/materials/watersim_common.h deleted file mode 100644 index aa7a636a0..000000000 --- a/files/materials/watersim_common.h +++ /dev/null @@ -1,25 +0,0 @@ -float DecodeHeightmap(float4 heightmap) -{ - float4 table = float4(1.0, -1.0, 0.0, 0.0); - return dot(heightmap, table); -} - -float DecodeHeightmap(shTexture2D HeightmapSampler, float2 texcoord) -{ - float4 heightmap = shSample(HeightmapSampler, texcoord); - return DecodeHeightmap(heightmap); -} - -float4 EncodeHeightmap(float fHeight) -{ - float h = fHeight; - float positive = fHeight > 0.0 ? fHeight : 0.0; - float negative = fHeight < 0.0 ? -fHeight : 0.0; - - float4 color = float4(0,0,0,0); - - color.r = positive; - color.g = negative; - - return color; -} diff --git a/files/materials/watersim_heightmap.shader b/files/materials/watersim_heightmap.shader deleted file mode 100644 index ec8ae4174..000000000 --- a/files/materials/watersim_heightmap.shader +++ /dev/null @@ -1,51 +0,0 @@ -#include "core.h" - -#define DAMPING 0.95 - -#include "watersim_common.h" - - SH_BEGIN_PROGRAM - shInput(float2, UV) - shSampler2D(heightPrevSampler) - shSampler2D(heightCurrentSampler) - shUniform(float3, previousFrameOffset) @shSharedParameter(previousFrameOffset, previousFrameOffset) - shUniform(float3, currentFrameOffset) @shSharedParameter(currentFrameOffset, currentFrameOffset) - shUniform(float4, rippleTextureSize) @shSharedParameter(rippleTextureSize, rippleTextureSize) - - SH_START_PROGRAM - { -#if !SH_HLSL - const float3 offset[4] = float3[4]( - float3(-1.0, 0.0, 0.25), - float3( 1.0, 0.0, 0.25), - float3( 0.0,-1.0, 0.25), - float3( 0.0, 1.0, 0.25) - ); -#else - const float3 offset[4] = { - float3(-1.0, 0.0, 0.25), - float3( 1.0, 0.0, 0.25), - float3( 0.0,-1.0, 0.25), - float3( 0.0, 1.0, 0.25) - }; -#endif - - float fHeightPrev = DecodeHeightmap(heightPrevSampler, UV.xy + previousFrameOffset.xy + currentFrameOffset.xy); - - float fNeighCurrent = 0; - for ( int i=0; i<4; i++ ) - { - float2 vTexcoord = UV + currentFrameOffset.xy + offset[i].xy * rippleTextureSize.xy; - fNeighCurrent += (DecodeHeightmap(heightCurrentSampler, vTexcoord) * offset[i].z); - } - - float fHeight = fNeighCurrent * 2.0 - fHeightPrev; - - fHeight *= DAMPING; - - shOutputColour(0) = EncodeHeightmap(fHeight); - } - - - - diff --git a/files/materials/watersim_heighttonormal.shader b/files/materials/watersim_heighttonormal.shader deleted file mode 100644 index eaa4af498..000000000 --- a/files/materials/watersim_heighttonormal.shader +++ /dev/null @@ -1,36 +0,0 @@ -#include "core.h" -#include "watersim_common.h" - - SH_BEGIN_PROGRAM - shInput(float2, UV) - shSampler2D(heightCurrentSampler) - shUniform(float4, rippleTextureSize) @shSharedParameter(rippleTextureSize, rippleTextureSize) - - SH_START_PROGRAM - { -#if !SH_HLSL - float2 offset[4] = float2[4] ( - float2(-1.0, 0.0), - float2( 1.0, 0.0), - float2( 0.0,-1.0), - float2( 0.0, 1.0) - ); -#else - float2 offset[4] = { - float2(-1.0, 0.0), - float2( 1.0, 0.0), - float2( 0.0,-1.0), - float2( 0.0, 1.0) - }; -#endif - - float fHeightL = DecodeHeightmap(heightCurrentSampler, UV.xy + offset[0]*rippleTextureSize.xy); - float fHeightR = DecodeHeightmap(heightCurrentSampler, UV.xy + offset[1]*rippleTextureSize.xy); - float fHeightT = DecodeHeightmap(heightCurrentSampler, UV.xy + offset[2]*rippleTextureSize.xy); - float fHeightB = DecodeHeightmap(heightCurrentSampler, UV.xy + offset[3]*rippleTextureSize.xy); - - float3 n = float3(fHeightB - fHeightT, fHeightR - fHeightL, 1.0); - float3 normal = (n + 1.0) * 0.5; - - shOutputColour(0) = float4(normal.rgb, 1.0); - } From 801c0eb57c4300ffb35556711a84411a1b62b28a Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 6 Feb 2015 17:34:08 +0100 Subject: [PATCH 0542/3725] Detect Creature should detect alive creatures only (Fixes #2353) --- apps/openmw/mwworld/worldimp.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index a60eae48a..0694a3da6 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2886,6 +2886,9 @@ namespace MWWorld } else if (ptr.getClass().getTypeName() != typeid(ESM::Creature).name()) return false; + + if (ptr.getClass().getCreatureStats(ptr).isDead()) + return false; } if (mType == World::Detect_Key && !ptr.getClass().isKey(ptr)) return false; From 03257ecae538feb9fdd1482629a16883c57ca191 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 6 Feb 2015 18:05:02 +0100 Subject: [PATCH 0543/3725] QString encoding fix --- apps/launcher/graphicspage.cpp | 10 +++++----- apps/launcher/main.cpp | 2 +- components/contentselector/model/contentmodel.cpp | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index dccf8bb8c..cdb51348c 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -67,7 +67,7 @@ bool Launcher::GraphicsPage::setupOgre() } catch(Ogre::Exception &ex) { - QString ogreError = QString::fromStdString(ex.getFullDescription().c_str()); + QString ogreError = QString::fromUtf8(ex.getFullDescription().c_str()); QMessageBox msgBox; msgBox.setWindowTitle("Error creating Ogre::Root"); msgBox.setIcon(QMessageBox::Critical); @@ -135,7 +135,7 @@ bool Launcher::GraphicsPage::setupSDL() msgBox.setWindowTitle(tr("Error receiving number of screens")); msgBox.setIcon(QMessageBox::Critical); msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(tr("
SDL_GetNumDisplayModes failed:

") + QString::fromStdString(SDL_GetError()) + "
"); + msgBox.setText(tr("
SDL_GetNumDisplayModes failed:

") + QString::fromUtf8(SDL_GetError()) + "
"); msgBox.exec(); return false; } @@ -237,7 +237,7 @@ QStringList Launcher::GraphicsPage::getAvailableOptions(const QString &key, Ogre opt_it != i->second.possibleValues.end(); ++opt_it, ++idx) { if (strcmp (key.toStdString().c_str(), i->first.c_str()) == 0) { - result << ((key == "FSAA") ? QString("MSAA ") : QString("")) + QString::fromStdString((*opt_it).c_str()).simplified(); + result << ((key == "FSAA") ? QString("MSAA ") : QString("")) + QString::fromUtf8((*opt_it).c_str()).simplified(); } } } @@ -266,7 +266,7 @@ QStringList Launcher::GraphicsPage::getAvailableResolutions(int screen) msgBox.setWindowTitle(tr("Error receiving resolutions")); msgBox.setIcon(QMessageBox::Critical); msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(tr("
SDL_GetNumDisplayModes failed:

") + QString::fromStdString(SDL_GetError()) + "
"); + msgBox.setText(tr("
SDL_GetNumDisplayModes failed:

") + QString::fromUtf8(SDL_GetError()) + "
"); msgBox.exec(); return result; } @@ -279,7 +279,7 @@ QStringList Launcher::GraphicsPage::getAvailableResolutions(int screen) msgBox.setWindowTitle(tr("Error receiving resolutions")); msgBox.setIcon(QMessageBox::Critical); msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(tr("
SDL_GetDisplayMode failed:

") + QString::fromStdString(SDL_GetError()) + "
"); + msgBox.setText(tr("
SDL_GetDisplayMode failed:

") + QString::fromUtf8(SDL_GetError()) + "
"); msgBox.exec(); return result; } diff --git a/apps/launcher/main.cpp b/apps/launcher/main.cpp index 5c3f38458..11ea56869 100644 --- a/apps/launcher/main.cpp +++ b/apps/launcher/main.cpp @@ -24,7 +24,7 @@ int main(int argc, char *argv[]) SDL_SetMainReady(); if (SDL_Init(SDL_INIT_VIDEO) != 0) { - qDebug() << "SDL_Init failed: " << QString::fromStdString(SDL_GetError()); + qDebug() << "SDL_Init failed: " << QString::fromUtf8(SDL_GetError()); return 0; } signal(SIGINT, SIG_DFL); // We don't want to use the SDL event loop in the launcher, diff --git a/components/contentselector/model/contentmodel.cpp b/components/contentselector/model/contentmodel.cpp index 56a86f87f..ec1fcc21e 100644 --- a/components/contentselector/model/contentmodel.cpp +++ b/components/contentselector/model/contentmodel.cpp @@ -459,7 +459,7 @@ void ContentSelectorModel::ContentModel::addFiles(const QString &path) EsmFile *file = new EsmFile(path); foreach (const ESM::Header::MasterData &item, fileReader.getGameFiles()) - file->addGameFile(QString::fromStdString(item.name)); + file->addGameFile(QString::fromUtf8(item.name.c_str())); file->setAuthor (QString::fromUtf8(fileReader.getAuthor().c_str())); file->setDate (info.lastModified()); From 399c24c64668046f879e788418def56285dd5d8f Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 7 Feb 2015 23:27:32 +0100 Subject: [PATCH 0544/3725] CMake cleanup: remove redundant setting of Permissions to default values --- CMakeLists.txt | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2b80d4c95..ed4136813 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -438,23 +438,23 @@ IF(NOT WIN32 AND NOT APPLE) INSTALL(FILES "extern/shiny/License.txt" DESTINATION "${LICDIR}" RENAME "Shiny License.txt" ) # Install icon and desktop file - INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.desktop" DESTINATION "${DATAROOTDIR}/applications" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") - INSTALL(FILES "${OpenMW_SOURCE_DIR}/files/launcher/images/openmw.png" DESTINATION "${ICONDIR}" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") + INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.desktop" DESTINATION "${DATAROOTDIR}/applications" COMPONENT "openmw") + INSTALL(FILES "${OpenMW_SOURCE_DIR}/files/launcher/images/openmw.png" DESTINATION "${ICONDIR}" COMPONENT "openmw") IF(BUILD_OPENCS) - INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw-cs.desktop" DESTINATION "${DATAROOTDIR}/applications" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "opencs") - INSTALL(FILES "${OpenMW_SOURCE_DIR}/files/opencs/openmw-cs.png" DESTINATION "${ICONDIR}" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "opencs") + INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw-cs.desktop" DESTINATION "${DATAROOTDIR}/applications" COMPONENT "opencs") + INSTALL(FILES "${OpenMW_SOURCE_DIR}/files/opencs/openmw-cs.png" DESTINATION "${ICONDIR}" COMPONENT "opencs") ENDIF(BUILD_OPENCS) # Install global configuration files - INSTALL(FILES "${OpenMW_BINARY_DIR}/settings-default.cfg" DESTINATION "${SYSCONFDIR}" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") - INSTALL(FILES "${OpenMW_BINARY_DIR}/transparency-overrides.cfg" DESTINATION "${SYSCONFDIR}" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") - INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" DESTINATION "${SYSCONFDIR}" RENAME "openmw.cfg" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") + INSTALL(FILES "${OpenMW_BINARY_DIR}/settings-default.cfg" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw") + INSTALL(FILES "${OpenMW_BINARY_DIR}/transparency-overrides.cfg" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw") + INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" DESTINATION "${SYSCONFDIR}" RENAME "openmw.cfg" COMPONENT "openmw") IF(BUILD_OPENCS) - INSTALL(FILES "${OpenMW_BINARY_DIR}/opencs.ini" DESTINATION "${SYSCONFDIR}" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "opencs") + INSTALL(FILES "${OpenMW_BINARY_DIR}/opencs.ini" DESTINATION "${SYSCONFDIR}" COMPONENT "opencs") ENDIF(BUILD_OPENCS) # Install resources - INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION "${DATADIR}" FILE_PERMISSIONS OWNER_READ GROUP_READ WORLD_READ COMPONENT "Resources") + INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION "${DATADIR}" COMPONENT "Resources") INSTALL(DIRECTORY DESTINATION "${DATADIR}/data" COMPONENT "Resources") ENDIF(NOT WIN32 AND NOT APPLE) From 218f789d88ac1ea46ba9675dc9dcd67009602184 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 8 Feb 2015 01:08:07 +0100 Subject: [PATCH 0545/3725] Fix player DrawState reset when selecting enchanted item (Fixes #2356) --- apps/openmw/mwgui/spellwindow.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index 6d3c79b34..69365c108 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -95,8 +95,9 @@ namespace MWGui return; } - MWBase::Environment::get().getWindowManager()->unsetSelectedSpell(); store.setSelectedEnchantItem(it); + // to reset WindowManager::mSelectedSpell immediately + MWBase::Environment::get().getWindowManager()->setSelectedEnchantItem(*it); updateSpells(); } From ee574e08ef48c2496ad522c9fa8aecd5b218dccc Mon Sep 17 00:00:00 2001 From: jacmoe Date: Tue, 3 Feb 2015 23:12:33 +0100 Subject: [PATCH 0546/3725] MIT License header added to all terrain component files. --- components/terrain/buffercache.cpp | 21 +++++++++++++++++++++ components/terrain/buffercache.hpp | 21 +++++++++++++++++++++ components/terrain/chunk.cpp | 21 +++++++++++++++++++++ components/terrain/chunk.hpp | 21 +++++++++++++++++++++ components/terrain/defaultworld.cpp | 21 +++++++++++++++++++++ components/terrain/defaultworld.hpp | 21 +++++++++++++++++++++ components/terrain/defs.hpp | 21 +++++++++++++++++++++ components/terrain/material.cpp | 21 +++++++++++++++++++++ components/terrain/material.hpp | 21 +++++++++++++++++++++ components/terrain/quadtreenode.cpp | 21 +++++++++++++++++++++ components/terrain/quadtreenode.hpp | 21 +++++++++++++++++++++ components/terrain/storage.cpp | 21 +++++++++++++++++++++ components/terrain/storage.hpp | 21 +++++++++++++++++++++ components/terrain/terraingrid.cpp | 21 +++++++++++++++++++++ components/terrain/terraingrid.hpp | 21 +++++++++++++++++++++ components/terrain/world.cpp | 21 +++++++++++++++++++++ components/terrain/world.hpp | 21 +++++++++++++++++++++ files/materials/terrain.shader | 22 ++++++++++++++++++++++ 18 files changed, 379 insertions(+) diff --git a/components/terrain/buffercache.cpp b/components/terrain/buffercache.cpp index 3d0b35910..01032bcda 100644 --- a/components/terrain/buffercache.cpp +++ b/components/terrain/buffercache.cpp @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2015 scrawl + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ #include "buffercache.hpp" #include diff --git a/components/terrain/buffercache.hpp b/components/terrain/buffercache.hpp index 51c0a61af..887f0822e 100644 --- a/components/terrain/buffercache.hpp +++ b/components/terrain/buffercache.hpp @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2015 scrawl + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ #ifndef COMPONENTS_TERRAIN_BUFFERCACHE_H #define COMPONENTS_TERRAIN_BUFFERCACHE_H diff --git a/components/terrain/chunk.cpp b/components/terrain/chunk.cpp index 9c60ee017..cce5abd36 100644 --- a/components/terrain/chunk.cpp +++ b/components/terrain/chunk.cpp @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2015 scrawl + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ #include "chunk.hpp" #include diff --git a/components/terrain/chunk.hpp b/components/terrain/chunk.hpp index 9b2ed76ac..22b4f26ef 100644 --- a/components/terrain/chunk.hpp +++ b/components/terrain/chunk.hpp @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2015 scrawl + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ #ifndef COMPONENTS_TERRAIN_TERRAINBATCH_H #define COMPONENTS_TERRAIN_TERRAINBATCH_H diff --git a/components/terrain/defaultworld.cpp b/components/terrain/defaultworld.cpp index 943658235..e14c64f3a 100644 --- a/components/terrain/defaultworld.cpp +++ b/components/terrain/defaultworld.cpp @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2015 scrawl + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ #include "defaultworld.hpp" #include diff --git a/components/terrain/defaultworld.hpp b/components/terrain/defaultworld.hpp index 62441c420..90e8cc2b6 100644 --- a/components/terrain/defaultworld.hpp +++ b/components/terrain/defaultworld.hpp @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2015 scrawl + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ #ifndef COMPONENTS_TERRAIN_H #define COMPONENTS_TERRAIN_H diff --git a/components/terrain/defs.hpp b/components/terrain/defs.hpp index 685937653..6d173d136 100644 --- a/components/terrain/defs.hpp +++ b/components/terrain/defs.hpp @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2015 scrawl + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ #ifndef COMPONENTS_TERRAIN_DEFS_HPP #define COMPONENTS_TERRAIN_DEFS_HPP diff --git a/components/terrain/material.cpp b/components/terrain/material.cpp index a40e576ed..4ff04ab93 100644 --- a/components/terrain/material.cpp +++ b/components/terrain/material.cpp @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2015 scrawl + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ #include "material.hpp" #include diff --git a/components/terrain/material.hpp b/components/terrain/material.hpp index b9000cb1b..f35080e7c 100644 --- a/components/terrain/material.hpp +++ b/components/terrain/material.hpp @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2015 scrawl + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ #ifndef COMPONENTS_TERRAIN_MATERIAL_H #define COMPONENTS_TERRAIN_MATERIAL_H diff --git a/components/terrain/quadtreenode.cpp b/components/terrain/quadtreenode.cpp index 755c45c21..5fce5eae9 100644 --- a/components/terrain/quadtreenode.cpp +++ b/components/terrain/quadtreenode.cpp @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2015 scrawl + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ #include "quadtreenode.hpp" #include diff --git a/components/terrain/quadtreenode.hpp b/components/terrain/quadtreenode.hpp index e8392b8e4..1ecd6fcd5 100644 --- a/components/terrain/quadtreenode.hpp +++ b/components/terrain/quadtreenode.hpp @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2015 scrawl + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ #ifndef COMPONENTS_TERRAIN_QUADTREENODE_H #define COMPONENTS_TERRAIN_QUADTREENODE_H diff --git a/components/terrain/storage.cpp b/components/terrain/storage.cpp index e69de29bb..14009127d 100644 --- a/components/terrain/storage.cpp +++ b/components/terrain/storage.cpp @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2015 scrawl + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ diff --git a/components/terrain/storage.hpp b/components/terrain/storage.hpp index aa52ffc4b..7846e91c6 100644 --- a/components/terrain/storage.hpp +++ b/components/terrain/storage.hpp @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2015 scrawl + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ #ifndef COMPONENTS_TERRAIN_STORAGE_H #define COMPONENTS_TERRAIN_STORAGE_H diff --git a/components/terrain/terraingrid.cpp b/components/terrain/terraingrid.cpp index 6a66ac3d7..269152e61 100644 --- a/components/terrain/terraingrid.cpp +++ b/components/terrain/terraingrid.cpp @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2015 scrawl + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ #include "terraingrid.hpp" #include diff --git a/components/terrain/terraingrid.hpp b/components/terrain/terraingrid.hpp index 7cbf45576..97ef6d14d 100644 --- a/components/terrain/terraingrid.hpp +++ b/components/terrain/terraingrid.hpp @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2015 scrawl + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ #ifndef COMPONENTS_TERRAIN_TERRAINGRID_H #define COMPONENTS_TERRAIN_TERRAINGRID_H diff --git a/components/terrain/world.cpp b/components/terrain/world.cpp index 93caeb8df..5cc2647c6 100644 --- a/components/terrain/world.cpp +++ b/components/terrain/world.cpp @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2015 scrawl + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ #include "world.hpp" #include diff --git a/components/terrain/world.hpp b/components/terrain/world.hpp index beca7903a..3e63b4c93 100644 --- a/components/terrain/world.hpp +++ b/components/terrain/world.hpp @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2015 scrawl + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ #ifndef COMPONENTS_TERRAIN_WORLD_H #define COMPONENTS_TERRAIN_WORLD_H diff --git a/files/materials/terrain.shader b/files/materials/terrain.shader index 8384588e4..a4ca10fcc 100644 --- a/files/materials/terrain.shader +++ b/files/materials/terrain.shader @@ -1,3 +1,25 @@ +/* + * Copyright (c) 2015 scrawl + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + #include "core.h" #define IS_FIRST_PASS (@shPropertyString(pass_index) == 0) From 9da0a9f8c4dab03e1917d54ba8d8a4f23f02693f Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Tue, 10 Feb 2015 00:55:31 +0100 Subject: [PATCH 0547/3725] Enable link-time optimization on MSVC --- CMakeLists.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index d22e0b129..382a8e8e4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -384,6 +384,12 @@ if (CMAKE_COMPILER_IS_GNUCC) if ("${GCC_VERSION}" VERSION_GREATER 4.6 OR "${GCC_VERSION}" VERSION_EQUAL 4.6) SET(CMAKE_CXX_FLAGS "-Wno-unused-but-set-parameter ${CMAKE_CXX_FLAGS}") endif("${GCC_VERSION}" VERSION_GREATER 4.6 OR "${GCC_VERSION}" VERSION_EQUAL 4.6) +elseif (MSVC) + # Enable link-time code generation globally for all linking + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /GL") + set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /LTCG") + set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /LTCG") + set(CMAKE_STATIC_LINKER_FLAGS_RELEASE "${CMAKE_STATIC_LINKER_FLAGS_RELEASE} /LTCG") endif (CMAKE_COMPILER_IS_GNUCC) IF(NOT WIN32 AND NOT APPLE) From 1a19253158bb3eba7fb671fb90886a286d247c81 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Tue, 10 Feb 2015 15:32:54 +0100 Subject: [PATCH 0548/3725] Fix MSVC build due to missing M_PI define Apparently the header guard on cmath only adds the defines if _USE_MATH_DEFINES is defined when cmath is included for the first time. So enabling that define and moving cmath up to be the first include, so that nothing else includes it without the define set. --- apps/openmw/mwworld/weather.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 7a36d6ac7..4440ed030 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -1,7 +1,8 @@ -#include "weather.hpp" - +#define _USE_MATH_DEFINES #include +#include "weather.hpp" + #include #include "../mwbase/environment.hpp" From 3ccf4642b4e7f68c73c43ed451732789cf559683 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 10 Feb 2015 20:25:57 +0100 Subject: [PATCH 0549/3725] Implement ToggleScripts --- apps/openmw/engine.cpp | 13 +++++++----- apps/openmw/mwbase/world.hpp | 3 +++ apps/openmw/mwgui/inventorywindow.cpp | 2 +- apps/openmw/mwscript/docs/vmformat.txt | 3 ++- apps/openmw/mwscript/miscextensions.cpp | 14 +++++++++++++ apps/openmw/mwworld/worldimp.cpp | 28 ++++++++++++++++++++----- apps/openmw/mwworld/worldimp.hpp | 4 ++++ components/compiler/extensions0.cpp | 1 + components/compiler/opcodes.hpp | 1 + 9 files changed, 57 insertions(+), 12 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 611f0a304..669bae60a 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -109,11 +109,14 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) { if (!paused) { - // local scripts - executeLocalScripts(); - - // global scripts - MWBase::Environment::get().getScriptManager()->getGlobalScripts().run(); + if (MWBase::Environment::get().getWorld()->getScriptsEnabled()) + { + // local scripts + executeLocalScripts(); + + // global scripts + MWBase::Environment::get().getScriptManager()->getGlobalScripts().run(); + } MWBase::Environment::get().getWorld()->markCellAsUnchanged(); } diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 154d96f7d..8180d0b1a 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -489,6 +489,9 @@ namespace MWBase virtual bool toggleGodMode() = 0; + virtual bool toggleScripts() = 0; + virtual bool getScriptsEnabled() const = 0; + /** * @brief startSpellCast attempt to start casting a spell. Might fail immediately if conditions are not met. * @param actor diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 5cb67c048..4270c4be1 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -420,7 +420,7 @@ namespace MWGui // Give the script a chance to run once before we do anything else // this is important when setting pcskipequip as a reaction to onpcequip being set (bk_treasuryreport does this) - if (!script.empty()) + if (!script.empty() && MWBase::Environment::get().getWorld()->getScriptsEnabled()) { MWScript::InterpreterContext interpreterContext (&ptr.getRefData().getLocals(), ptr); MWBase::Environment::get().getScriptManager()->run (script, interpreterContext); diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index 41cc6b88a..93720aef6 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -444,5 +444,6 @@ op 0x20002fd: AddToLevItem op 0x20002fe: RemoveFromLevItem op 0x20002ff: SetFactionReaction op 0x2000300: EnableLevelupMenu +op 0x2000301: ToggleScripts -opcodes 0x2000301-0x3ffffff unused +opcodes 0x2000302-0x3ffffff unused diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index cdc9f58cf..52094947c 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -915,6 +915,19 @@ namespace MWScript } }; + class OpToggleScripts : public Interpreter::Opcode0 + { + public: + virtual void execute (Interpreter::Runtime& runtime) + { + InterpreterContext& context = static_cast (runtime.getContext()); + + bool enabled = MWBase::Environment::get().getWorld()->toggleScripts(); + + context.report(enabled ? "Scripts -> On" : "Scripts -> Off"); + } + }; + class OpToggleGodMode : public Interpreter::Opcode0 { public: @@ -1220,6 +1233,7 @@ namespace MWScript interpreter.installSegment5 (Compiler::Misc::opcodeShowVars, new OpShowVars); interpreter.installSegment5 (Compiler::Misc::opcodeShowVarsExplicit, new OpShowVars); interpreter.installSegment5 (Compiler::Misc::opcodeToggleGodMode, new OpToggleGodMode); + interpreter.installSegment5 (Compiler::Misc::opcodeToggleScripts, new OpToggleScripts); interpreter.installSegment5 (Compiler::Misc::opcodeDisableLevitation, new OpEnableLevitation); interpreter.installSegment5 (Compiler::Misc::opcodeEnableLevitation, new OpEnableLevitation); interpreter.installSegment5 (Compiler::Misc::opcodeCast, new OpCast); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 0694a3da6..188f3cdad 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -151,7 +151,8 @@ namespace MWWorld mFallback(fallbackMap), mTeleportEnabled(true), mLevitationEnabled(true), mGodMode(false), mContentFiles (contentFiles), mGoToJail(false), mDaysInPrison(0), - mStartCell (startCell), mStartupScript(startupScript) + mStartCell (startCell), mStartupScript(startupScript), + mScriptsEnabled(true) { mPhysics = new PhysicsSystem(renderer); mPhysEngine = mPhysics->getEngine(); @@ -293,6 +294,7 @@ namespace MWWorld mDoorStates.clear(); mGodMode = false; + mScriptsEnabled = true; mSky = true; mTeleportEnabled = true; mLevitationEnabled = true; @@ -2587,6 +2589,17 @@ namespace MWWorld return mGodMode; } + bool World::toggleScripts() + { + mScriptsEnabled = !mScriptsEnabled; + return mScriptsEnabled; + } + + bool World::getScriptsEnabled() const + { + return mScriptsEnabled; + } + void World::loadContentFiles(const Files::Collections& fileCollections, const std::vector& content, ContentLoader& contentLoader) { @@ -3167,12 +3180,17 @@ namespace MWWorld breakInvisibility(actor); - if (!script.empty()) + if (mScriptsEnabled) { - getLocalScripts().setIgnore (object); - MWBase::Environment::get().getScriptManager()->run (script, interpreterContext); + if (!script.empty()) + { + getLocalScripts().setIgnore (object); + MWBase::Environment::get().getScriptManager()->run (script, interpreterContext); + } + if (!interpreterContext.hasActivationBeenHandled()) + interpreterContext.executeActivation(object, actor); } - if (!interpreterContext.hasActivationBeenHandled()) + else interpreterContext.executeActivation(object, actor); } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 1d103c6a9..9980f6f90 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -82,6 +82,7 @@ namespace MWWorld boost::shared_ptr mProjectileManager; bool mGodMode; + bool mScriptsEnabled; std::vector mContentFiles; // not implemented @@ -572,6 +573,9 @@ namespace MWWorld virtual bool toggleGodMode(); + virtual bool toggleScripts(); + virtual bool getScriptsEnabled() const; + /** * @brief startSpellCast attempt to start casting a spell. Might fail immediately if conditions are not met. * @param actor diff --git a/components/compiler/extensions0.cpp b/components/compiler/extensions0.cpp index 70338669e..c56ee2ffb 100644 --- a/components/compiler/extensions0.cpp +++ b/components/compiler/extensions0.cpp @@ -303,6 +303,7 @@ namespace Compiler extensions.registerInstruction ("sv", "", opcodeShowVars, opcodeShowVarsExplicit); extensions.registerInstruction("tgm", "", opcodeToggleGodMode); extensions.registerInstruction("togglegodmode", "", opcodeToggleGodMode); + extensions.registerInstruction("togglescripts", "", opcodeToggleScripts); extensions.registerInstruction ("disablelevitation", "", opcodeDisableLevitation); extensions.registerInstruction ("enablelevitation", "", opcodeEnableLevitation); extensions.registerFunction ("getpcinjail", 'l', "", opcodeGetPcInJail); diff --git a/components/compiler/opcodes.hpp b/components/compiler/opcodes.hpp index e5cf2e965..a4aab8aa1 100644 --- a/components/compiler/opcodes.hpp +++ b/components/compiler/opcodes.hpp @@ -278,6 +278,7 @@ namespace Compiler const int opcodeShowVars = 0x200021d; const int opcodeShowVarsExplicit = 0x200021e; const int opcodeToggleGodMode = 0x200021f; + const int opcodeToggleScripts = 0x2000301; const int opcodeDisableLevitation = 0x2000220; const int opcodeEnableLevitation = 0x2000221; const int opcodeCast = 0x2000227; From bf1839b3701df0937e096f8aed2f2b1c9c1b8c32 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 10 Feb 2015 22:01:57 +0100 Subject: [PATCH 0550/3725] Always print the exception to stderr --- apps/openmw/main.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 475fe63a2..82fda060e 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -390,12 +390,12 @@ int main(int argc, char**argv) catch (std::exception &e) { #if OGRE_PLATFORM == OGRE_PLATFORM_LINUX || OGRE_PLATFORM == OGRE_PLATFORM_APPLE - if (isatty(fileno(stdin))) - std::cerr << "\nERROR: " << e.what() << std::endl; - else + if (!isatty(fileno(stdin))) #endif SDL_ShowSimpleMessageBox(0, "OpenMW: Fatal error", e.what(), NULL); + std::cerr << "\nERROR: " << e.what() << std::endl; + ret = 1; } From 9009889d240185fb50e251d175341288957852a8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 10 Feb 2015 23:16:25 +0100 Subject: [PATCH 0551/3725] Don't rely on subrecord order when reading (Fixes #2361) --- components/esm/aipackage.cpp | 67 +++++++----- components/esm/aipackage.hpp | 12 ++- components/esm/loadarmo.cpp | 101 ++++++++++++------ components/esm/loadarmo.hpp | 4 + components/esm/loadbook.cpp | 68 ++++++++---- components/esm/loadclot.cpp | 47 ++++++-- components/esm/loadcont.cpp | 11 +- components/esm/loadcont.hpp | 4 + components/esm/loaddoor.cpp | 52 ++++++--- components/esm/loadmgef.cpp | 75 +++++++++---- components/esm/loadmisc.cpp | 55 +++++++--- components/esm/loadnpc.cpp | 200 +++++++++++++++++++++-------------- components/esm/loadrace.cpp | 32 +++++- components/esm/loadspel.cpp | 27 ++++- components/esm/loadweap.cpp | 62 +++++++---- components/esm/spelllist.cpp | 7 +- components/esm/spelllist.hpp | 5 + 17 files changed, 575 insertions(+), 254 deletions(-) diff --git a/components/esm/aipackage.cpp b/components/esm/aipackage.cpp index 209a1fe26..8ad64b797 100644 --- a/components/esm/aipackage.cpp +++ b/components/esm/aipackage.cpp @@ -11,36 +11,55 @@ namespace ESM mServices = 0; } + void AIPackageList::add(ESMReader &esm) + { + AIPackage pack; + if (esm.retSubName() == AI_CNDT) { + mList.back().mCellName = esm.getHString(); + } else if (esm.retSubName() == AI_Wander) { + pack.mType = AI_Wander; + esm.getHExact(&pack.mWander, 14); + mList.push_back(pack); + } else if (esm.retSubName() == AI_Travel) { + pack.mType = AI_Travel; + esm.getHExact(&pack.mTravel, 16); + mList.push_back(pack); + } else if (esm.retSubName() == AI_Escort || + esm.retSubName() == AI_Follow) + { + pack.mType = + (esm.retSubName() == AI_Escort) ? AI_Escort : AI_Follow; + esm.getHExact(&pack.mTarget, 48); + mList.push_back(pack); + } else if (esm.retSubName() == AI_Activate) { + pack.mType = AI_Activate; + esm.getHExact(&pack.mActivate, 33); + mList.push_back(pack); + } else { // not AI package related data, so leave + return; + } + + } + void AIPackageList::load(ESMReader &esm) { mList.clear(); while (esm.hasMoreSubs()) { // initialize every iteration - AIPackage pack; - esm.getSubName(); - if (esm.retSubName() == 0x54444e43) { // CNDT - mList.back().mCellName = esm.getHString(); - } else if (esm.retSubName() == AI_Wander) { - pack.mType = AI_Wander; - esm.getHExact(&pack.mWander, 14); - mList.push_back(pack); - } else if (esm.retSubName() == AI_Travel) { - pack.mType = AI_Travel; - esm.getHExact(&pack.mTravel, 16); - mList.push_back(pack); - } else if (esm.retSubName() == AI_Escort || - esm.retSubName() == AI_Follow) + esm.getSubName(); + switch (esm.retSubName().val) { - pack.mType = - (esm.retSubName() == AI_Escort) ? AI_Escort : AI_Follow; - esm.getHExact(&pack.mTarget, 48); - mList.push_back(pack); - } else if (esm.retSubName() == AI_Activate) { - pack.mType = AI_Activate; - esm.getHExact(&pack.mActivate, 33); - mList.push_back(pack); - } else { // not AI package related data, so leave - return; + case AI_Wander: + case AI_Activate: + case AI_Escort: + case AI_Follow: + case AI_Travel: + case AI_CNDT: + + add(esm); + break; + default: + return; } } } diff --git a/components/esm/aipackage.hpp b/components/esm/aipackage.hpp index cbe82f16e..30bd2ce04 100644 --- a/components/esm/aipackage.hpp +++ b/components/esm/aipackage.hpp @@ -63,7 +63,8 @@ namespace ESM AI_Travel = 0x545f4941, AI_Follow = 0x465f4941, AI_Escort = 0x455f4941, - AI_Activate = 0x415f4941 + AI_Activate = 0x415f4941, + AI_CNDT = 0x54444e43 }; /// \note Used for storaging packages in a single container @@ -90,11 +91,12 @@ namespace ESM { std::vector mList; - /// \note This breaks consistency of subrecords reading: - /// after calling it subrecord name is already read, so - /// it needs to use retSubName() if needed. But, hey, there - /// is only one field left (XSCL) and only two records uses AI + /// Add a single AIPackage, assumes subrecord name was already read + void add(ESMReader &esm); + + /// TODO: remove this method. The ESM format does not guarantee that all AI packages follow one another void load(ESMReader &esm); + void save(ESMWriter &esm) const; }; } diff --git a/components/esm/loadarmo.cpp b/components/esm/loadarmo.cpp index f8c3a4718..066551d6f 100644 --- a/components/esm/loadarmo.cpp +++ b/components/esm/loadarmo.cpp @@ -7,52 +7,87 @@ namespace ESM { -void PartReferenceList::load(ESMReader &esm) -{ - mParts.clear(); - while (esm.isNextSub("INDX")) + void PartReferenceList::add(ESMReader &esm) { PartReference pr; esm.getHT(pr.mPart); // The INDX byte pr.mMale = esm.getHNOString("BNAM"); pr.mFemale = esm.getHNOString("CNAM"); mParts.push_back(pr); + } -} -void PartReferenceList::save(ESMWriter &esm) const -{ - for (std::vector::const_iterator it = mParts.begin(); it != mParts.end(); ++it) + void PartReferenceList::load(ESMReader &esm) { - esm.writeHNT("INDX", it->mPart); - esm.writeHNOString("BNAM", it->mMale); - esm.writeHNOString("CNAM", it->mFemale); + mParts.clear(); + while (esm.isNextSub("INDX")) + { + add(esm); + } } -} -unsigned int Armor::sRecordId = REC_ARMO; + void PartReferenceList::save(ESMWriter &esm) const + { + for (std::vector::const_iterator it = mParts.begin(); it != mParts.end(); ++it) + { + esm.writeHNT("INDX", it->mPart); + esm.writeHNOString("BNAM", it->mMale); + esm.writeHNOString("CNAM", it->mFemale); + } + } -void Armor::load(ESMReader &esm) -{ - mModel = esm.getHNString("MODL"); - mName = esm.getHNOString("FNAM"); - mScript = esm.getHNOString("SCRI"); - esm.getHNT(mData, "AODT", 24); - mIcon = esm.getHNOString("ITEX"); - mParts.load(esm); - mEnchant = esm.getHNOString("ENAM"); -} + unsigned int Armor::sRecordId = REC_ARMO; -void Armor::save(ESMWriter &esm) const -{ - esm.writeHNCString("MODL", mModel); - esm.writeHNOCString("FNAM", mName); - esm.writeHNOCString("SCRI", mScript); - esm.writeHNT("AODT", mData, 24); - esm.writeHNOCString("ITEX", mIcon); - mParts.save(esm); - esm.writeHNOCString("ENAM", mEnchant); -} + void Armor::load(ESMReader &esm) + { + mParts.mParts.clear(); + bool hasData = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'A','O','D','T'>::value: + esm.getHT(mData, 24); + hasData = true; + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + case ESM::FourCC<'I','T','E','X'>::value: + mIcon = esm.getHString(); + break; + case ESM::FourCC<'E','N','A','M'>::value: + mEnchant = esm.getHString(); + break; + case ESM::FourCC<'I','N','D','X'>::value: + mParts.add(esm); + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasData) + esm.fail("Missing CTDT subrecord"); + } + + void Armor::save(ESMWriter &esm) const + { + esm.writeHNCString("MODL", mModel); + esm.writeHNOCString("FNAM", mName); + esm.writeHNOCString("SCRI", mScript); + esm.writeHNT("AODT", mData, 24); + esm.writeHNOCString("ITEX", mIcon); + mParts.save(esm); + esm.writeHNOCString("ENAM", mEnchant); + } void Armor::blank() { diff --git a/components/esm/loadarmo.hpp b/components/esm/loadarmo.hpp index 6be9dd971..356dfc1c5 100644 --- a/components/esm/loadarmo.hpp +++ b/components/esm/loadarmo.hpp @@ -55,6 +55,10 @@ struct PartReferenceList { std::vector mParts; + /// Load one part, assumes the subrecord name was already read + void add(ESMReader &esm); + + /// TODO: remove this method. The ESM format does not guarantee that all Part subrecords follow one another. void load(ESMReader &esm); void save(ESMWriter &esm) const; }; diff --git a/components/esm/loadbook.cpp b/components/esm/loadbook.cpp index c8b7e9478..47f52fc31 100644 --- a/components/esm/loadbook.cpp +++ b/components/esm/loadbook.cpp @@ -8,26 +8,54 @@ namespace ESM { unsigned int Book::sRecordId = REC_BOOK; -void Book::load(ESMReader &esm) -{ - mModel = esm.getHNString("MODL"); - mName = esm.getHNOString("FNAM"); - esm.getHNT(mData, "BKDT", 20); - mScript = esm.getHNOString("SCRI"); - mIcon = esm.getHNOString("ITEX"); - mText = esm.getHNOString("TEXT"); - mEnchant = esm.getHNOString("ENAM"); -} -void Book::save(ESMWriter &esm) const -{ - esm.writeHNCString("MODL", mModel); - esm.writeHNOCString("FNAM", mName); - esm.writeHNT("BKDT", mData, 20); - esm.writeHNOCString("SCRI", mScript); - esm.writeHNOCString("ITEX", mIcon); - esm.writeHNOString("TEXT", mText); - esm.writeHNOCString("ENAM", mEnchant); -} + void Book::load(ESMReader &esm) + { + bool hasData = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'B','K','D','T'>::value: + esm.getHT(mData, 20); + hasData = true; + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + case ESM::FourCC<'I','T','E','X'>::value: + mIcon = esm.getHString(); + break; + case ESM::FourCC<'E','N','A','M'>::value: + mEnchant = esm.getHString(); + break; + case ESM::FourCC<'T','E','X','T'>::value: + mText = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasData) + esm.fail("Missing BKDT subrecord"); + } + void Book::save(ESMWriter &esm) const + { + esm.writeHNCString("MODL", mModel); + esm.writeHNOCString("FNAM", mName); + esm.writeHNT("BKDT", mData, 20); + esm.writeHNOCString("SCRI", mScript); + esm.writeHNOCString("ITEX", mIcon); + esm.writeHNOString("TEXT", mText); + esm.writeHNOCString("ENAM", mEnchant); + } void Book::blank() { diff --git a/components/esm/loadclot.cpp b/components/esm/loadclot.cpp index 17ecdf3ae..5f49b5e70 100644 --- a/components/esm/loadclot.cpp +++ b/components/esm/loadclot.cpp @@ -10,17 +10,42 @@ namespace ESM void Clothing::load(ESMReader &esm) { - mModel = esm.getHNString("MODL"); - mName = esm.getHNOString("FNAM"); - esm.getHNT(mData, "CTDT", 12); - - mScript = esm.getHNOString("SCRI"); - mIcon = esm.getHNOString("ITEX"); - - mParts.load(esm); - - - mEnchant = esm.getHNOString("ENAM"); + mParts.mParts.clear(); + bool hasData = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'C','T','D','T'>::value: + esm.getHT(mData, 12); + hasData = true; + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + case ESM::FourCC<'I','T','E','X'>::value: + mIcon = esm.getHString(); + break; + case ESM::FourCC<'E','N','A','M'>::value: + mEnchant = esm.getHString(); + break; + case ESM::FourCC<'I','N','D','X'>::value: + mParts.add(esm); + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasData) + esm.fail("Missing CTDT subrecord"); } void Clothing::save(ESMWriter &esm) const diff --git a/components/esm/loadcont.cpp b/components/esm/loadcont.cpp index 51a385f06..f48f06930 100644 --- a/components/esm/loadcont.cpp +++ b/components/esm/loadcont.cpp @@ -7,14 +7,19 @@ namespace ESM { +void InventoryList::add(ESMReader &esm) +{ + ContItem ci; + esm.getHT(ci, 36); + mList.push_back(ci); +} + void InventoryList::load(ESMReader &esm) { mList.clear(); - ContItem ci; while (esm.isNextSub("NPCO")) { - esm.getHT(ci, 36); - mList.push_back(ci); + add(esm); } } diff --git a/components/esm/loadcont.hpp b/components/esm/loadcont.hpp index 2808b67b5..93db94759 100644 --- a/components/esm/loadcont.hpp +++ b/components/esm/loadcont.hpp @@ -26,6 +26,10 @@ struct InventoryList { std::vector mList; + /// Load one item, assumes subrecord name is already read + void add(ESMReader &esm); + + /// TODO: remove this method, the ESM format doesn't guarantee that all ContItems follow one another void load(ESMReader &esm); void save(ESMWriter &esm) const; }; diff --git a/components/esm/loaddoor.cpp b/components/esm/loaddoor.cpp index c56b06337..f446eed61 100644 --- a/components/esm/loaddoor.cpp +++ b/components/esm/loaddoor.cpp @@ -8,23 +8,43 @@ namespace ESM { unsigned int Door::sRecordId = REC_DOOR; -void Door::load(ESMReader &esm) -{ - mModel = esm.getHNString("MODL"); - mName = esm.getHNOString("FNAM"); - mScript = esm.getHNOString("SCRI"); - mOpenSound = esm.getHNOString("SNAM"); - mCloseSound = esm.getHNOString("ANAM"); -} + void Door::load(ESMReader &esm) + { + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + case ESM::FourCC<'S','N','A','M'>::value: + mOpenSound = esm.getHString(); + break; + case ESM::FourCC<'A','N','A','M'>::value: + mCloseSound = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + } + } + } -void Door::save(ESMWriter &esm) const -{ - esm.writeHNCString("MODL", mModel); - esm.writeHNOCString("FNAM", mName); - esm.writeHNOCString("SCRI", mScript); - esm.writeHNOCString("SNAM", mOpenSound); - esm.writeHNOCString("ANAM", mCloseSound); -} + void Door::save(ESMWriter &esm) const + { + esm.writeHNCString("MODL", mModel); + esm.writeHNOCString("FNAM", mName); + esm.writeHNOCString("SCRI", mScript); + esm.writeHNOCString("SNAM", mOpenSound); + esm.writeHNOCString("ANAM", mCloseSound); + } void Door::blank() { diff --git a/components/esm/loadmgef.cpp b/components/esm/loadmgef.cpp index cbdca3e31..3ec07a2a9 100644 --- a/components/esm/loadmgef.cpp +++ b/components/esm/loadmgef.cpp @@ -191,33 +191,64 @@ namespace ESM void MagicEffect::load(ESMReader &esm) { - esm.getHNT(mIndex, "INDX"); + esm.getHNT(mIndex, "INDX"); mId = indexToId (mIndex); - esm.getHNT(mData, "MEDT", 36); - if (esm.getFormat() == 0) - { - // don't allow mods to change fixed flags in the legacy format - mData.mFlags &= (AllowSpellmaking | AllowEnchanting | NegativeLight); - if (mIndex>=0 && mIndex=0 && mIndex::value: + mIcon = esm.getHString(); + break; + case ESM::FourCC<'P','T','E','X'>::value: + mParticle = esm.getHString(); + break; + case ESM::FourCC<'B','S','N','D'>::value: + mBoltSound = esm.getHString(); + break; + case ESM::FourCC<'C','S','N','D'>::value: + mCastSound = esm.getHString(); + break; + case ESM::FourCC<'H','S','N','D'>::value: + mHitSound = esm.getHString(); + break; + case ESM::FourCC<'A','S','N','D'>::value: + mAreaSound = esm.getHString(); + break; + case ESM::FourCC<'C','V','F','X'>::value: + mCasting = esm.getHString(); + break; + case ESM::FourCC<'B','V','F','X'>::value: + mBolt = esm.getHString(); + break; + case ESM::FourCC<'H','V','F','X'>::value: + mHit = esm.getHString(); + break; + case ESM::FourCC<'A','V','F','X'>::value: + mArea = esm.getHString(); + break; + case ESM::FourCC<'D','E','S','C'>::value: + mDescription = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord " + esm.retSubName().toString()); + } + } } void MagicEffect::save(ESMWriter &esm) const { diff --git a/components/esm/loadmisc.cpp b/components/esm/loadmisc.cpp index 2ca09e8ae..81c094f2b 100644 --- a/components/esm/loadmisc.cpp +++ b/components/esm/loadmisc.cpp @@ -8,22 +8,45 @@ namespace ESM { unsigned int Miscellaneous::sRecordId = REC_MISC; -void Miscellaneous::load(ESMReader &esm) -{ - mModel = esm.getHNString("MODL"); - mName = esm.getHNOString("FNAM"); - esm.getHNT(mData, "MCDT", 12); - mScript = esm.getHNOString("SCRI"); - mIcon = esm.getHNOString("ITEX"); -} -void Miscellaneous::save(ESMWriter &esm) const -{ - esm.writeHNCString("MODL", mModel); - esm.writeHNOCString("FNAM", mName); - esm.writeHNT("MCDT", mData, 12); - esm.writeHNOCString("SCRI", mScript); - esm.writeHNOCString("ITEX", mIcon); -} + void Miscellaneous::load(ESMReader &esm) + { + bool hasData = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'M','C','D','T'>::value: + esm.getHT(mData, 12); + hasData = true; + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + case ESM::FourCC<'I','T','E','X'>::value: + mIcon = esm.getHString(); + break; + } + } + if (!hasData) + esm.fail("Missing MCDT subrecord"); + } + + void Miscellaneous::save(ESMWriter &esm) const + { + esm.writeHNCString("MODL", mModel); + esm.writeHNOCString("FNAM", mName); + esm.writeHNT("MCDT", mData, 12); + esm.writeHNOCString("SCRI", mScript); + esm.writeHNOCString("ITEX", mIcon); + } void Miscellaneous::blank() { diff --git a/components/esm/loadnpc.cpp b/components/esm/loadnpc.cpp index 6ca070cf3..3d617241b 100644 --- a/components/esm/loadnpc.cpp +++ b/components/esm/loadnpc.cpp @@ -8,92 +8,136 @@ namespace ESM { unsigned int NPC::sRecordId = REC_NPC_; -void NPC::load(ESMReader &esm) -{ - mPersistent = esm.getRecordFlags() & 0x0400; - - mModel = esm.getHNOString("MODL"); - mName = esm.getHNOString("FNAM"); - - mRace = esm.getHNString("RNAM"); - mClass = esm.getHNString("CNAM"); - mFaction = esm.getHNString("ANAM"); - mHead = esm.getHNString("BNAM"); - mHair = esm.getHNString("KNAM"); - - mScript = esm.getHNOString("SCRI"); - - esm.getSubNameIs("NPDT"); - esm.getSubHeader(); - if (esm.getSubSize() == 52) - { - mNpdtType = NPC_DEFAULT; - esm.getExact(&mNpdt52, 52); - } - else if (esm.getSubSize() == 12) + void NPC::load(ESMReader &esm) { - mNpdtType = NPC_WITH_AUTOCALCULATED_STATS; - esm.getExact(&mNpdt12, 12); - } - else - esm.fail("NPC_NPDT must be 12 or 52 bytes long"); - - esm.getHNT(mFlags, "FLAG"); + mPersistent = esm.getRecordFlags() & 0x0400; - mInventory.load(esm); - mSpells.load(esm); + mSpells.mList.clear(); + mInventory.mList.clear(); + mTransport.clear(); + mAiPackage.mList.clear(); - if (esm.isNextSub("AIDT")) - { - esm.getHExact(&mAiData, sizeof(mAiData)); - mHasAI= true; - } - else + bool hasNpdt = false; + bool hasFlags = false; mHasAI = false; - - mTransport.clear(); - while (esm.isNextSub("DODT") || esm.isNextSub("DNAM")) { - if (esm.retSubName() == 0x54444f44) { // DODT struct - Dest dodt; - esm.getHExact(&dodt.mPos, 24); - mTransport.push_back(dodt); - } else if (esm.retSubName() == 0x4d414e44) { // DNAM struct - mTransport.back().mCellName = esm.getHString(); + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'R','N','A','M'>::value: + mRace = esm.getHString(); + break; + case ESM::FourCC<'C','N','A','M'>::value: + mClass = esm.getHString(); + break; + case ESM::FourCC<'A','N','A','M'>::value: + mFaction = esm.getHString(); + break; + case ESM::FourCC<'B','N','A','M'>::value: + mHead = esm.getHString(); + break; + case ESM::FourCC<'K','N','A','M'>::value: + mHair = esm.getHString(); + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + case ESM::FourCC<'N','P','D','T'>::value: + hasNpdt = true; + esm.getSubHeader(); + if (esm.getSubSize() == 52) + { + mNpdtType = NPC_DEFAULT; + esm.getExact(&mNpdt52, 52); + } + else if (esm.getSubSize() == 12) + { + mNpdtType = NPC_WITH_AUTOCALCULATED_STATS; + esm.getExact(&mNpdt12, 12); + } + else + esm.fail("NPC_NPDT must be 12 or 52 bytes long"); + break; + case ESM::FourCC<'F','L','A','G'>::value: + hasFlags = true; + esm.getHT(mFlags); + break; + case ESM::FourCC<'N','P','C','S'>::value: + mSpells.add(esm); + break; + case ESM::FourCC<'N','P','C','O'>::value: + mInventory.add(esm); + break; + case ESM::FourCC<'A','I','D','T'>::value: + esm.getHExact(&mAiData, sizeof(mAiData)); + mHasAI= true; + break; + case ESM::FourCC<'D','O','D','T'>::value: + { + Dest dodt; + esm.getHExact(&dodt.mPos, 24); + mTransport.push_back(dodt); + break; + } + case ESM::FourCC<'D','N','A','M'>::value: + mTransport.back().mCellName = esm.getHString(); + break; + case AI_Wander: + case AI_Activate: + case AI_Escort: + case AI_Follow: + case AI_Travel: + case AI_CNDT: + mAiPackage.add(esm); + break; + default: + esm.fail("Unknown subrecord " + esm.retSubName().toString()); + } } + if (!hasNpdt) + esm.fail("Missing NPDT subrecord"); + if (!hasFlags) + esm.fail("Missing FLAG subrecord"); } - mAiPackage.load(esm); -} -void NPC::save(ESMWriter &esm) const -{ - esm.writeHNOCString("MODL", mModel); - esm.writeHNOCString("FNAM", mName); - esm.writeHNCString("RNAM", mRace); - esm.writeHNCString("CNAM", mClass); - esm.writeHNCString("ANAM", mFaction); - esm.writeHNCString("BNAM", mHead); - esm.writeHNCString("KNAM", mHair); - esm.writeHNOCString("SCRI", mScript); - - if (mNpdtType == NPC_DEFAULT) - esm.writeHNT("NPDT", mNpdt52, 52); - else if (mNpdtType == NPC_WITH_AUTOCALCULATED_STATS) - esm.writeHNT("NPDT", mNpdt12, 12); - - esm.writeHNT("FLAG", mFlags); - - mInventory.save(esm); - mSpells.save(esm); - if (mHasAI) { - esm.writeHNT("AIDT", mAiData, sizeof(mAiData)); - } + void NPC::save(ESMWriter &esm) const + { + esm.writeHNOCString("MODL", mModel); + esm.writeHNOCString("FNAM", mName); + esm.writeHNCString("RNAM", mRace); + esm.writeHNCString("CNAM", mClass); + esm.writeHNCString("ANAM", mFaction); + esm.writeHNCString("BNAM", mHead); + esm.writeHNCString("KNAM", mHair); + esm.writeHNOCString("SCRI", mScript); + + if (mNpdtType == NPC_DEFAULT) + esm.writeHNT("NPDT", mNpdt52, 52); + else if (mNpdtType == NPC_WITH_AUTOCALCULATED_STATS) + esm.writeHNT("NPDT", mNpdt12, 12); + + esm.writeHNT("FLAG", mFlags); + + mInventory.save(esm); + mSpells.save(esm); + if (mHasAI) { + esm.writeHNT("AIDT", mAiData, sizeof(mAiData)); + } - typedef std::vector::const_iterator DestIter; - for (DestIter it = mTransport.begin(); it != mTransport.end(); ++it) { - esm.writeHNT("DODT", it->mPos, sizeof(it->mPos)); - esm.writeHNOCString("DNAM", it->mCellName); + typedef std::vector::const_iterator DestIter; + for (DestIter it = mTransport.begin(); it != mTransport.end(); ++it) { + esm.writeHNT("DODT", it->mPos, sizeof(it->mPos)); + esm.writeHNOCString("DNAM", it->mCellName); + } + mAiPackage.save(esm); } - mAiPackage.save(esm); -} bool NPC::isMale() const { return (mFlags & Female) == 0; diff --git a/components/esm/loadrace.cpp b/components/esm/loadrace.cpp index 17f2e0267..211fd5ffb 100644 --- a/components/esm/loadrace.cpp +++ b/components/esm/loadrace.cpp @@ -20,10 +20,34 @@ namespace ESM void Race::load(ESMReader &esm) { - mName = esm.getHNOString("FNAM"); - esm.getHNT(mData, "RADT", 140); - mPowers.load(esm); - mDescription = esm.getHNOString("DESC"); + mPowers.mList.clear(); + + bool hasData = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'R','A','D','T'>::value: + esm.getHT(mData, 140); + hasData = true; + break; + case ESM::FourCC<'D','E','S','C'>::value: + mDescription = esm.getHString(); + break; + case ESM::FourCC<'N','P','C','S'>::value: + mPowers.add(esm); + break; + default: + esm.fail("Unknown subrecord " + esm.retSubName().toString()); + } + } + if (!hasData) + esm.fail("Missing RADT subrecord"); } void Race::save(ESMWriter &esm) const { diff --git a/components/esm/loadspel.cpp b/components/esm/loadspel.cpp index 2c98d796d..716f47e71 100644 --- a/components/esm/loadspel.cpp +++ b/components/esm/loadspel.cpp @@ -10,9 +10,30 @@ namespace ESM void Spell::load(ESMReader &esm) { - mName = esm.getHNOString("FNAM"); - esm.getHNT(mData, "SPDT", 12); - mEffects.load(esm); + bool hasData = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t val = esm.retSubName().val; + + switch (val) + { + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'S','P','D','T'>::value: + esm.getHT(mData, 12); + hasData = true; + break; + case ESM::FourCC<'E','N','A','M'>::value: + ENAMstruct s; + esm.getHT(s, 24); + mEffects.mList.push_back(s); + break; + } + } + if (!hasData) + esm.fail("Missing SPDT subrecord"); } void Spell::save(ESMWriter &esm) const diff --git a/components/esm/loadweap.cpp b/components/esm/loadweap.cpp index 1d0b149df..981a5815a 100644 --- a/components/esm/loadweap.cpp +++ b/components/esm/loadweap.cpp @@ -8,24 +8,50 @@ namespace ESM { unsigned int Weapon::sRecordId = REC_WEAP; -void Weapon::load(ESMReader &esm) -{ - mModel = esm.getHNString("MODL"); - mName = esm.getHNOString("FNAM"); - esm.getHNT(mData, "WPDT", 32); - mScript = esm.getHNOString("SCRI"); - mIcon = esm.getHNOString("ITEX"); - mEnchant = esm.getHNOString("ENAM"); -} -void Weapon::save(ESMWriter &esm) const -{ - esm.writeHNCString("MODL", mModel); - esm.writeHNOCString("FNAM", mName); - esm.writeHNT("WPDT", mData, 32); - esm.writeHNOCString("SCRI", mScript); - esm.writeHNOCString("ITEX", mIcon); - esm.writeHNOCString("ENAM", mEnchant); -} + void Weapon::load(ESMReader &esm) + { + bool hasData = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'W','P','D','T'>::value: + esm.getHT(mData, 32); + hasData = true; + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + case ESM::FourCC<'I','T','E','X'>::value: + mIcon = esm.getHString(); + break; + case ESM::FourCC<'E','N','A','M'>::value: + mEnchant = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasData) + esm.fail("Missing WPDT subrecord"); + } + void Weapon::save(ESMWriter &esm) const + { + esm.writeHNCString("MODL", mModel); + esm.writeHNOCString("FNAM", mName); + esm.writeHNT("WPDT", mData, 32); + esm.writeHNOCString("SCRI", mScript); + esm.writeHNOCString("ITEX", mIcon); + esm.writeHNOCString("ENAM", mEnchant); + } void Weapon::blank() { diff --git a/components/esm/spelllist.cpp b/components/esm/spelllist.cpp index 8ec386db4..98bd53ae6 100644 --- a/components/esm/spelllist.cpp +++ b/components/esm/spelllist.cpp @@ -9,10 +9,15 @@ void SpellList::load(ESMReader &esm) { mList.clear(); while (esm.isNextSub("NPCS")) { - mList.push_back(esm.getHString()); + add(esm); } } +void SpellList::add(ESMReader &esm) +{ + mList.push_back(esm.getHString()); +} + void SpellList::save(ESMWriter &esm) const { for (std::vector::const_iterator it = mList.begin(); it != mList.end(); ++it) { diff --git a/components/esm/spelllist.hpp b/components/esm/spelllist.hpp index bcd6ba798..9493199a8 100644 --- a/components/esm/spelllist.hpp +++ b/components/esm/spelllist.hpp @@ -19,6 +19,11 @@ namespace ESM /// Is this spell ID in mList? bool exists(const std::string& spell) const; + /// Load one spell, assumes the subrecord name was already read + void add(ESMReader &esm); + + /// Load all spells + /// TODO: remove this method, the ESM format doesn't guarantee that all spell subrecords follow one another void load(ESMReader &esm); void save(ESMWriter &esm) const; }; From 6b0ca73352efc386507ae7115ad3ed3ed6f0cf73 Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Wed, 11 Feb 2015 10:04:00 +0200 Subject: [PATCH 0552/3725] CI: use Qt from our homebrew tap --- CI/before_install.osx.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CI/before_install.osx.sh b/CI/before_install.osx.sh index 165763efa..8bfe2b70f 100755 --- a/CI/before_install.osx.sh +++ b/CI/before_install.osx.sh @@ -6,4 +6,4 @@ export CC=clang brew tap openmw/openmw brew update brew unlink boost -brew install openmw-mygui openmw-bullet openmw-sdl2 openmw-ffmpeg qt unshield +brew install openmw-mygui openmw-bullet openmw-sdl2 openmw-ffmpeg openmw/openmw/qt unshield From ca53ca89261b46a907fc7d08391ee1e2e4b8cd6c Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Wed, 11 Feb 2015 10:08:29 +0200 Subject: [PATCH 0553/3725] CI: perform `make package` on OS X --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index f9c917bbb..042d4b8f1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -31,6 +31,7 @@ before_script: script: - cd ./build - if [ "$COVERITY_SCAN_BRANCH" != 1 ]; then make -j4; fi + - if [ "$COVERITY_SCAN_BRANCH" != 1 ] && ["${TRAVIS_OS_NAME}" = "osx"]; then make package; fi after_script: - if [ "${TRAVIS_OS_NAME}" = "linux" ]; then ./openmw_test_suite; fi notifications: From dfaab1188f86c62d23f360ffebaa1f4a0c821900 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 11 Feb 2015 12:10:46 +0100 Subject: [PATCH 0554/3725] Fix for broken levelled creature spawning (Fixes #2365) --- apps/openmw/mwclass/creaturelevlist.cpp | 2 +- apps/openmw/mwclass/creaturelevlist.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwclass/creaturelevlist.cpp b/apps/openmw/mwclass/creaturelevlist.cpp index b1e27c345..dbc4b6af7 100644 --- a/apps/openmw/mwclass/creaturelevlist.cpp +++ b/apps/openmw/mwclass/creaturelevlist.cpp @@ -52,7 +52,7 @@ namespace MWClass registerClass (typeid (ESM::CreatureLevList).name(), instance); } - void CreatureLevList::insertObjectRendering(const MWWorld::Ptr &ptr, MWRender::RenderingInterface &renderingInterface) const + void CreatureLevList::insertObjectRendering(const MWWorld::Ptr &ptr, const std::string& model, MWRender::RenderingInterface &renderingInterface) const { ensureCustomData(ptr); diff --git a/apps/openmw/mwclass/creaturelevlist.hpp b/apps/openmw/mwclass/creaturelevlist.hpp index 7016524eb..177aa7235 100644 --- a/apps/openmw/mwclass/creaturelevlist.hpp +++ b/apps/openmw/mwclass/creaturelevlist.hpp @@ -20,7 +20,7 @@ namespace MWClass static void registerSelf(); - virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; + virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering virtual void readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state) From cfe81bafe82a5a396ad7d82c16e3dc229bae2999 Mon Sep 17 00:00:00 2001 From: slothlife Date: Wed, 11 Feb 2015 21:46:00 -0600 Subject: [PATCH 0555/3725] Remove setting CMAKE_BUILD_TYPE to Debug Setting was causing single-target configurations (ninja, make) to incorrectly link vs debug runtimes on Windows. --- apps/opencs/CMakeLists.txt | 2 -- components/CMakeLists.txt | 1 - 2 files changed, 3 deletions(-) diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 0b83feb45..b65aee4cf 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -4,8 +4,6 @@ set (OPENCS_SRC main.cpp opencs_units (. editor) -set (CMAKE_BUILD_TYPE DEBUG) - opencs_units (model/doc document operation saving documentmanager loader runner ) diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 6f8352ddb..a49e54dd3 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -1,5 +1,4 @@ project (Components) -set (CMAKE_BUILD_TYPE DEBUG) # Version file set (VERSION_HPP_IN ${CMAKE_CURRENT_SOURCE_DIR}/version/version.hpp.cmake) From 49d912e5b6b1d728bf10c92d0b803dfda7596b89 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 12 Feb 2015 04:56:05 +0100 Subject: [PATCH 0556/3725] Don't rely on subrecord order part 2 Nice side effects: - Subrecord name comparison now uses magic number instead of string (faster) - Improves the error message for unknown subrecords: will print the record in question instead of failing to read the next record with a strange error --- components/esm/aipackage.cpp | 23 ------ components/esm/aipackage.hpp | 3 - components/esm/effectlist.cpp | 11 ++- components/esm/effectlist.hpp | 6 +- components/esm/loadacti.cpp | 40 +++++++---- components/esm/loadalch.cpp | 63 ++++++++++++----- components/esm/loadappa.cpp | 40 +++++++---- components/esm/loadbody.cpp | 27 ++++++- components/esm/loadbsgn.cpp | 28 ++++++-- components/esm/loadclas.cpp | 70 +++++++++++------- components/esm/loadcont.cpp | 105 +++++++++++++++------------ components/esm/loadcont.hpp | 3 +- components/esm/loadcrea.cpp | 125 +++++++++++++++++++++------------ components/esm/loadench.cpp | 24 ++++++- components/esm/loadfact.cpp | 53 +++++++++----- components/esm/loadingr.cpp | 88 +++++++++++++++-------- components/esm/loadlevlist.cpp | 75 ++++++++++---------- components/esm/loadligh.cpp | 63 ++++++++++++----- components/esm/loadlock.cpp | 58 ++++++++++----- components/esm/loadmgef.cpp | 2 +- components/esm/loadmgef.hpp | 4 +- components/esm/loadnpc.cpp | 2 +- components/esm/loadprob.cpp | 58 ++++++++++----- components/esm/loadrace.cpp | 2 +- components/esm/loadrepa.cpp | 36 ++++++++-- components/esm/loadscpt.cpp | 106 ++++++++++++++-------------- components/esm/loadscpt.hpp | 3 + components/esm/loadskil.cpp | 54 ++++++++++---- components/esm/loadsndg.cpp | 45 ++++++++---- components/esm/loadsoun.cpp | 45 +++++++----- components/esm/loadspel.cpp | 58 +++++++-------- components/esm/loadsscr.cpp | 42 ++++++++--- components/esm/loadstat.cpp | 19 ++--- components/esm/loadtes3.hpp | 4 +- components/esm/spelllist.cpp | 8 --- components/esm/spelllist.hpp | 4 +- 36 files changed, 889 insertions(+), 508 deletions(-) diff --git a/components/esm/aipackage.cpp b/components/esm/aipackage.cpp index 8ad64b797..efcd6651e 100644 --- a/components/esm/aipackage.cpp +++ b/components/esm/aipackage.cpp @@ -41,29 +41,6 @@ namespace ESM } - void AIPackageList::load(ESMReader &esm) - { - mList.clear(); - while (esm.hasMoreSubs()) { - // initialize every iteration - esm.getSubName(); - switch (esm.retSubName().val) - { - case AI_Wander: - case AI_Activate: - case AI_Escort: - case AI_Follow: - case AI_Travel: - case AI_CNDT: - - add(esm); - break; - default: - return; - } - } - } - void AIPackageList::save(ESMWriter &esm) const { typedef std::vector::const_iterator PackageIter; diff --git a/components/esm/aipackage.hpp b/components/esm/aipackage.hpp index 30bd2ce04..5e08806c8 100644 --- a/components/esm/aipackage.hpp +++ b/components/esm/aipackage.hpp @@ -94,9 +94,6 @@ namespace ESM /// Add a single AIPackage, assumes subrecord name was already read void add(ESMReader &esm); - /// TODO: remove this method. The ESM format does not guarantee that all AI packages follow one another - void load(ESMReader &esm); - void save(ESMWriter &esm) const; }; } diff --git a/components/esm/effectlist.cpp b/components/esm/effectlist.cpp index fc9acccf2..f6d5a6e07 100644 --- a/components/esm/effectlist.cpp +++ b/components/esm/effectlist.cpp @@ -8,13 +8,18 @@ namespace ESM { void EffectList::load(ESMReader &esm) { mList.clear(); - ENAMstruct s; while (esm.isNextSub("ENAM")) { - esm.getHT(s, 24); - mList.push_back(s); + add(esm); } } +void EffectList::add(ESMReader &esm) +{ + ENAMstruct s; + esm.getHT(s, 24); + mList.push_back(s); +} + void EffectList::save(ESMWriter &esm) const { for (std::vector::const_iterator it = mList.begin(); it != mList.end(); ++it) { diff --git a/components/esm/effectlist.hpp b/components/esm/effectlist.hpp index 04adcc5cd..d581f8337 100644 --- a/components/esm/effectlist.hpp +++ b/components/esm/effectlist.hpp @@ -29,11 +29,15 @@ namespace ESM }; #pragma pack(pop) + /// EffectList, ENAM subrecord struct EffectList { - std::vector mList; + /// Load one effect, assumes subrecord name was already read + void add(ESMReader &esm); + + /// Load all effects void load(ESMReader &esm); void save(ESMWriter &esm) const; }; diff --git a/components/esm/loadacti.cpp b/components/esm/loadacti.cpp index 8efea3302..b5adce550 100644 --- a/components/esm/loadacti.cpp +++ b/components/esm/loadacti.cpp @@ -8,18 +8,34 @@ namespace ESM { unsigned int Activator::sRecordId = REC_ACTI; -void Activator::load(ESMReader &esm) -{ - mModel = esm.getHNString("MODL"); - mName = esm.getHNOString("FNAM"); - mScript = esm.getHNOString("SCRI"); -} -void Activator::save(ESMWriter &esm) const -{ - esm.writeHNCString("MODL", mModel); - esm.writeHNOCString("FNAM", mName); - esm.writeHNOCString("SCRI", mScript); -} + void Activator::load(ESMReader &esm) + { + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + } + } + } + void Activator::save(ESMWriter &esm) const + { + esm.writeHNCString("MODL", mModel); + esm.writeHNOCString("FNAM", mName); + esm.writeHNOCString("SCRI", mScript); + } void Activator::blank() { diff --git a/components/esm/loadalch.cpp b/components/esm/loadalch.cpp index aac88482f..18db512c0 100644 --- a/components/esm/loadalch.cpp +++ b/components/esm/loadalch.cpp @@ -8,24 +8,51 @@ namespace ESM { unsigned int Potion::sRecordId = REC_ALCH; -void Potion::load(ESMReader &esm) -{ - mModel = esm.getHNOString("MODL"); - mIcon = esm.getHNOString("TEXT"); // not ITEX here for some reason - mScript = esm.getHNOString("SCRI"); - mName = esm.getHNOString("FNAM"); - esm.getHNT(mData, "ALDT", 12); - mEffects.load(esm); -} -void Potion::save(ESMWriter &esm) const -{ - esm.writeHNCString("MODL", mModel); - esm.writeHNOCString("TEXT", mIcon); - esm.writeHNOCString("SCRI", mScript); - esm.writeHNOCString("FNAM", mName); - esm.writeHNT("ALDT", mData, 12); - mEffects.save(esm); -} + void Potion::load(ESMReader &esm) + { + mEffects.mList.clear(); + bool hasData = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'T','E','X','T'>::value: // not ITEX here for some reason + mIcon = esm.getHString(); + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'A','L','D','T'>::value: + esm.getHT(mData, 12); + hasData = true; + break; + case ESM::FourCC<'E','N','A','M'>::value: + mEffects.add(esm); + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasData) + esm.fail("Missing ALDT"); + } + void Potion::save(ESMWriter &esm) const + { + esm.writeHNCString("MODL", mModel); + esm.writeHNOCString("TEXT", mIcon); + esm.writeHNOCString("SCRI", mScript); + esm.writeHNOCString("FNAM", mName); + esm.writeHNT("ALDT", mData, 12); + mEffects.save(esm); + } void Potion::blank() { diff --git a/components/esm/loadappa.cpp b/components/esm/loadappa.cpp index 29ea78acc..f2c82aacf 100644 --- a/components/esm/loadappa.cpp +++ b/components/esm/loadappa.cpp @@ -10,25 +10,35 @@ namespace ESM void Apparatus::load(ESMReader &esm) { - // we will not treat duplicated subrecords as errors here + bool hasData = false; while (esm.hasMoreSubs()) { esm.getSubName(); - NAME subName = esm.retSubName(); - - if (subName == "MODL") - mModel = esm.getHString(); - else if (subName == "FNAM") - mName = esm.getHString(); - else if (subName == "AADT") - esm.getHT(mData); - else if (subName == "SCRI") - mScript = esm.getHString(); - else if (subName == "ITEX") - mIcon = esm.getHString(); - else - esm.fail("wrong subrecord type " + subName.toString() + " for APPA record"); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'A','A','D','T'>::value: + esm.getHT(mData); + hasData = true; + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + case ESM::FourCC<'I','T','E','X'>::value: + mIcon = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + } } + if (!hasData) + esm.fail("Missing AADT"); } void Apparatus::save(ESMWriter &esm) const diff --git a/components/esm/loadbody.cpp b/components/esm/loadbody.cpp index 9a1164d04..ed24ded57 100644 --- a/components/esm/loadbody.cpp +++ b/components/esm/loadbody.cpp @@ -11,9 +11,30 @@ namespace ESM void BodyPart::load(ESMReader &esm) { - mModel = esm.getHNString("MODL"); - mRace = esm.getHNOString("FNAM"); - esm.getHNT(mData, "BYDT", 4); + bool hasData = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mRace = esm.getHString(); + break; + case ESM::FourCC<'B','Y','D','T'>::value: + esm.getHT(mData, 4); + hasData = true; + break; + default: + esm.fail("Unknown subrecord"); + } + } + + if (!hasData) + esm.fail("Missing BYDT subrecord"); } void BodyPart::save(ESMWriter &esm) const { diff --git a/components/esm/loadbsgn.cpp b/components/esm/loadbsgn.cpp index db1a72a36..e0cd83ea0 100644 --- a/components/esm/loadbsgn.cpp +++ b/components/esm/loadbsgn.cpp @@ -10,11 +10,29 @@ namespace ESM void BirthSign::load(ESMReader &esm) { - mName = esm.getHNOString("FNAM"); - mTexture = esm.getHNOString("TNAM"); - mDescription = esm.getHNOString("DESC"); - - mPowers.load(esm); + mPowers.mList.clear(); + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'T','N','A','M'>::value: + mTexture = esm.getHString(); + break; + case ESM::FourCC<'D','E','S','C'>::value: + mDescription = esm.getHString(); + break; + case ESM::FourCC<'N','P','C','S'>::value: + mPowers.add(esm); + break; + default: + esm.fail("Unknown subrecord"); + } + } } void BirthSign::save(ESMWriter &esm) const diff --git a/components/esm/loadclas.cpp b/components/esm/loadclas.cpp index ec339bd15..66acaea72 100644 --- a/components/esm/loadclas.cpp +++ b/components/esm/loadclas.cpp @@ -10,17 +10,17 @@ namespace ESM { unsigned int Class::sRecordId = REC_CLAS; -const Class::Specialization Class::sSpecializationIds[3] = { - Class::Combat, - Class::Magic, - Class::Stealth -}; + const Class::Specialization Class::sSpecializationIds[3] = { + Class::Combat, + Class::Magic, + Class::Stealth + }; -const char *Class::sGmstSpecializationIds[3] = { - "sSpecializationCombat", - "sSpecializationMagic", - "sSpecializationStealth" -}; + const char *Class::sGmstSpecializationIds[3] = { + "sSpecializationCombat", + "sSpecializationMagic", + "sSpecializationStealth" + }; int& Class::CLDTstruct::getSkill (int index, bool major) @@ -39,22 +39,40 @@ const char *Class::sGmstSpecializationIds[3] = { return mSkills[index][major ? 1 : 0]; } -void Class::load(ESMReader &esm) -{ - mName = esm.getHNOString("FNAM"); - esm.getHNT(mData, "CLDT", 60); - - if (mData.mIsPlayable > 1) - esm.fail("Unknown bool value"); - - mDescription = esm.getHNOString("DESC"); -} -void Class::save(ESMWriter &esm) const -{ - esm.writeHNOCString("FNAM", mName); - esm.writeHNT("CLDT", mData, 60); - esm.writeHNOString("DESC", mDescription); -} + void Class::load(ESMReader &esm) + { + bool hasData = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'C','L','D','T'>::value: + esm.getHT(mData, 60); + if (mData.mIsPlayable > 1) + esm.fail("Unknown bool value"); + hasData = true; + break; + case ESM::FourCC<'D','E','S','C'>::value: + mDescription = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasData) + esm.fail("Missing CLDT subrecord"); + } + void Class::save(ESMWriter &esm) const + { + esm.writeHNOCString("FNAM", mName); + esm.writeHNT("CLDT", mData, 60); + esm.writeHNOString("DESC", mDescription); + } void Class::blank() { diff --git a/components/esm/loadcont.cpp b/components/esm/loadcont.cpp index f48f06930..999c3f92a 100644 --- a/components/esm/loadcont.cpp +++ b/components/esm/loadcont.cpp @@ -7,60 +7,79 @@ namespace ESM { -void InventoryList::add(ESMReader &esm) -{ - ContItem ci; - esm.getHT(ci, 36); - mList.push_back(ci); -} - -void InventoryList::load(ESMReader &esm) -{ - mList.clear(); - while (esm.isNextSub("NPCO")) + void InventoryList::add(ESMReader &esm) { - add(esm); + ContItem ci; + esm.getHT(ci, 36); + mList.push_back(ci); } -} -void InventoryList::save(ESMWriter &esm) const -{ - for (std::vector::const_iterator it = mList.begin(); it != mList.end(); ++it) + void InventoryList::save(ESMWriter &esm) const { - esm.writeHNT("NPCO", *it, 36); + for (std::vector::const_iterator it = mList.begin(); it != mList.end(); ++it) + { + esm.writeHNT("NPCO", *it, 36); + } } -} unsigned int Container::sRecordId = REC_CONT; -void Container::load(ESMReader &esm) -{ - mModel = esm.getHNString("MODL"); - mName = esm.getHNOString("FNAM"); - esm.getHNT(mWeight, "CNDT", 4); - esm.getHNT(mFlags, "FLAG", 4); - - if (mFlags & 0xf4) - esm.fail("Unknown flags"); - if (!(mFlags & 0x8)) - esm.fail("Flag 8 not set"); - - mScript = esm.getHNOString("SCRI"); - - mInventory.load(esm); -} + void Container::load(ESMReader &esm) + { + mInventory.mList.clear(); + bool hasWeight = false; + bool hasFlags = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'C','N','D','T'>::value: + esm.getHT(mWeight, 4); + hasWeight = true; + break; + case ESM::FourCC<'F','L','A','G'>::value: + esm.getHT(mFlags, 4); + if (mFlags & 0xf4) + esm.fail("Unknown flags"); + if (!(mFlags & 0x8)) + esm.fail("Flag 8 not set"); + hasFlags = true; + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + case ESM::FourCC<'N','P','C','O'>::value: + mInventory.add(esm); + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasWeight) + esm.fail("Missing CNDT subrecord"); + if (!hasFlags) + esm.fail("Missing FLAG subrecord"); + } -void Container::save(ESMWriter &esm) const -{ - esm.writeHNCString("MODL", mModel); - esm.writeHNOCString("FNAM", mName); - esm.writeHNT("CNDT", mWeight, 4); - esm.writeHNT("FLAG", mFlags, 4); + void Container::save(ESMWriter &esm) const + { + esm.writeHNCString("MODL", mModel); + esm.writeHNOCString("FNAM", mName); + esm.writeHNT("CNDT", mWeight, 4); + esm.writeHNT("FLAG", mFlags, 4); - esm.writeHNOCString("SCRI", mScript); + esm.writeHNOCString("SCRI", mScript); - mInventory.save(esm); -} + mInventory.save(esm); + } void Container::blank() { diff --git a/components/esm/loadcont.hpp b/components/esm/loadcont.hpp index 93db94759..76c522d74 100644 --- a/components/esm/loadcont.hpp +++ b/components/esm/loadcont.hpp @@ -22,6 +22,7 @@ struct ContItem NAME32 mItem; }; +/// InventoryList, NPCO subrecord struct InventoryList { std::vector mList; @@ -29,8 +30,6 @@ struct InventoryList /// Load one item, assumes subrecord name is already read void add(ESMReader &esm); - /// TODO: remove this method, the ESM format doesn't guarantee that all ContItems follow one another - void load(ESMReader &esm); void save(ESMWriter &esm) const; }; diff --git a/components/esm/loadcrea.cpp b/components/esm/loadcrea.cpp index 650de0801..2e9f924b7 100644 --- a/components/esm/loadcrea.cpp +++ b/components/esm/loadcrea.cpp @@ -8,55 +8,94 @@ namespace ESM { unsigned int Creature::sRecordId = REC_CREA; -void Creature::load(ESMReader &esm) -{ - mPersistent = esm.getRecordFlags() & 0x0400; - - mModel = esm.getHNString("MODL"); - mOriginal = esm.getHNOString("CNAM"); - mName = esm.getHNOString("FNAM"); - mScript = esm.getHNOString("SCRI"); - - esm.getHNT(mData, "NPDT", 96); - - esm.getHNT(mFlags, "FLAG"); - mScale = 1.0; - esm.getHNOT(mScale, "XSCL"); - - mInventory.load(esm); - mSpells.load(esm); - - if (esm.isNextSub("AIDT")) + void Creature::load(ESMReader &esm) { - esm.getHExact(&mAiData, sizeof(mAiData)); - mHasAI = true; - } - else - mHasAI = false; + mPersistent = esm.getRecordFlags() & 0x0400; - mAiPackage.load(esm); - esm.skipRecord(); -} + mAiPackage.mList.clear(); + mInventory.mList.clear(); + mSpells.mList.clear(); -void Creature::save(ESMWriter &esm) const -{ - esm.writeHNCString("MODL", mModel); - esm.writeHNOCString("CNAM", mOriginal); - esm.writeHNOCString("FNAM", mName); - esm.writeHNOCString("SCRI", mScript); - esm.writeHNT("NPDT", mData, 96); - esm.writeHNT("FLAG", mFlags); - if (mScale != 1.0) { - esm.writeHNT("XSCL", mScale); + mScale = 1.f; + mHasAI = false; + bool hasNpdt = false; + bool hasFlags = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'C','N','A','M'>::value: + mOriginal = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + case ESM::FourCC<'N','P','D','T'>::value: + esm.getHT(mData, 96); + hasNpdt = true; + break; + case ESM::FourCC<'F','L','A','G'>::value: + esm.getHT(mFlags); + hasFlags = true; + break; + case ESM::FourCC<'X','S','C','L'>::value: + esm.getHT(mScale); + break; + case ESM::FourCC<'N','P','C','O'>::value: + mInventory.add(esm); + break; + case ESM::FourCC<'N','P','C','S'>::value: + mSpells.add(esm); + break; + case ESM::FourCC<'A','I','D','T'>::value: + esm.getHExact(&mAiData, sizeof(mAiData)); + mHasAI = true; + break; + case AI_Wander: + case AI_Activate: + case AI_Escort: + case AI_Follow: + case AI_Travel: + case AI_CNDT: + mAiPackage.add(esm); + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasNpdt) + esm.fail("Missing NPDT subrecord"); + if (!hasFlags) + esm.fail("Missing FLAG subrecord"); } - mInventory.save(esm); - mSpells.save(esm); - if (mHasAI) { - esm.writeHNT("AIDT", mAiData, sizeof(mAiData)); + void Creature::save(ESMWriter &esm) const + { + esm.writeHNCString("MODL", mModel); + esm.writeHNOCString("CNAM", mOriginal); + esm.writeHNOCString("FNAM", mName); + esm.writeHNOCString("SCRI", mScript); + esm.writeHNT("NPDT", mData, 96); + esm.writeHNT("FLAG", mFlags); + if (mScale != 1.0) { + esm.writeHNT("XSCL", mScale); + } + + mInventory.save(esm); + mSpells.save(esm); + if (mHasAI) { + esm.writeHNT("AIDT", mAiData, sizeof(mAiData)); + } + mAiPackage.save(esm); } - mAiPackage.save(esm); -} void Creature::blank() { diff --git a/components/esm/loadench.cpp b/components/esm/loadench.cpp index 243803833..54690d9a0 100644 --- a/components/esm/loadench.cpp +++ b/components/esm/loadench.cpp @@ -10,8 +10,28 @@ namespace ESM void Enchantment::load(ESMReader &esm) { - esm.getHNT(mData, "ENDT", 16); - mEffects.load(esm); + mEffects.mList.clear(); + bool hasData = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'E','N','D','T'>::value: + esm.getHT(mData, 16); + hasData = true; + break; + case ESM::FourCC<'E','N','A','M'>::value: + mEffects.add(esm); + break; + default: + esm.fail("Unknown subrecord"); + break; + } + } + if (!hasData) + esm.fail("Missing ENDT subrecord"); } void Enchantment::save(ESMWriter &esm) const diff --git a/components/esm/loadfact.cpp b/components/esm/loadfact.cpp index db7e5b7b4..006ca0ce0 100644 --- a/components/esm/loadfact.cpp +++ b/components/esm/loadfact.cpp @@ -28,27 +28,46 @@ namespace ESM void Faction::load(ESMReader &esm) { - mName = esm.getHNOString("FNAM"); + mReactions.clear(); + for (int i=0;i<10;++i) + mRanks[i].clear(); - // Read rank names. These are optional. - int i = 0; - while (esm.isNextSub("RNAM") && i < 10) - mRanks[i++] = esm.getHString(); - - // Main data struct - esm.getHNT(mData, "FADT", 240); - - if (mData.mIsHidden > 1) - esm.fail("Unknown flag!"); - - // Read faction response values + int rankCounter=0; + bool hasData = false; while (esm.hasMoreSubs()) { - std::string faction = esm.getHNString("ANAM"); - int reaction; - esm.getHNT(reaction, "INTV"); - mReactions[faction] = reaction; + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'R','N','A','M'>::value: + if (rankCounter >= 10) + esm.fail("Rank out of range"); + mRanks[rankCounter++] = esm.getHString(); + break; + case ESM::FourCC<'F','A','D','T'>::value: + esm.getHT(mData, 240); + if (mData.mIsHidden > 1) + esm.fail("Unknown flag!"); + hasData = true; + break; + case ESM::FourCC<'A','N','A','M'>::value: + { + std::string faction = esm.getHString(); + int reaction; + esm.getHNT(reaction, "INTV"); + mReactions[faction] = reaction; + break; + } + default: + esm.fail("Unknown subrecord"); + } } + if (!hasData) + esm.fail("Missing FADT subrecord"); } void Faction::save(ESMWriter &esm) const { diff --git a/components/esm/loadingr.cpp b/components/esm/loadingr.cpp index 5c98cb8b9..7e0cc3168 100644 --- a/components/esm/loadingr.cpp +++ b/components/esm/loadingr.cpp @@ -8,45 +8,71 @@ namespace ESM { unsigned int Ingredient::sRecordId = REC_INGR; -void Ingredient::load(ESMReader &esm) -{ - mModel = esm.getHNString("MODL"); - mName = esm.getHNOString("FNAM"); - esm.getHNT(mData, "IRDT", 56); - mScript = esm.getHNOString("SCRI"); - mIcon = esm.getHNOString("ITEX"); - // horrible hack to fix broken data in records - for (int i=0; i<4; ++i) + void Ingredient::load(ESMReader &esm) { - if (mData.mEffectID[i] != 85 && - mData.mEffectID[i] != 22 && - mData.mEffectID[i] != 17 && - mData.mEffectID[i] != 79 && - mData.mEffectID[i] != 74) + bool hasData = false; + while (esm.hasMoreSubs()) { - mData.mAttributes[i] = -1; + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'I','R','D','T'>::value: + esm.getHT(mData, 56); + hasData = true; + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + case ESM::FourCC<'I','T','E','X'>::value: + mIcon = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + } } - // is this relevant in cycle from 0 to 4? - if (mData.mEffectID[i] != 89 && - mData.mEffectID[i] != 26 && - mData.mEffectID[i] != 21 && - mData.mEffectID[i] != 83 && - mData.mEffectID[i] != 78) + if (!hasData) + esm.fail("Missing IRDT subrecord"); + + // horrible hack to fix broken data in records + for (int i=0; i<4; ++i) { - mData.mSkills[i] = -1; + if (mData.mEffectID[i] != 85 && + mData.mEffectID[i] != 22 && + mData.mEffectID[i] != 17 && + mData.mEffectID[i] != 79 && + mData.mEffectID[i] != 74) + { + mData.mAttributes[i] = -1; + } + + // is this relevant in cycle from 0 to 4? + if (mData.mEffectID[i] != 89 && + mData.mEffectID[i] != 26 && + mData.mEffectID[i] != 21 && + mData.mEffectID[i] != 83 && + mData.mEffectID[i] != 78) + { + mData.mSkills[i] = -1; + } } } -} -void Ingredient::save(ESMWriter &esm) const -{ - esm.writeHNCString("MODL", mModel); - esm.writeHNOCString("FNAM", mName); - esm.writeHNT("IRDT", mData, 56); - esm.writeHNOCString("SCRI", mScript); - esm.writeHNOCString("ITEX", mIcon); -} + void Ingredient::save(ESMWriter &esm) const + { + esm.writeHNCString("MODL", mModel); + esm.writeHNOCString("FNAM", mName); + esm.writeHNT("IRDT", mData, 56); + esm.writeHNOCString("SCRI", mScript); + esm.writeHNOCString("ITEX", mIcon); + } void Ingredient::blank() { diff --git a/components/esm/loadlevlist.cpp b/components/esm/loadlevlist.cpp index 2cbfac0b4..6080d1e1a 100644 --- a/components/esm/loadlevlist.cpp +++ b/components/esm/loadlevlist.cpp @@ -7,49 +7,50 @@ namespace ESM { -void LevelledListBase::load(ESMReader &esm) -{ - esm.getHNT(mFlags, "DATA"); - esm.getHNT(mChanceNone, "NNAM"); - - if (esm.isNextSub("INDX")) - { - int len; - esm.getHT(len); - mList.resize(len); - } - else + void LevelledListBase::load(ESMReader &esm) { - esm.skipRecord(); - return; - } + esm.getHNT(mFlags, "DATA"); + esm.getHNT(mChanceNone, "NNAM"); - // If this levelled list was already loaded by a previous content file, - // we overwrite the list. Merging lists should probably be left to external tools, - // with the limited amount of information there is in the records, all merging methods - // will be flawed in some way. For a proper fix the ESM format would have to be changed - // to actually track list changes instead of including the whole list for every file - // that does something with that list. + if (esm.isNextSub("INDX")) + { + int len; + esm.getHT(len); + mList.resize(len); + } + else + { + // Original engine ignores rest of the record, even if there are items following + esm.skipRecord(); + return; + } - for (size_t i = 0; i < mList.size(); i++) - { - LevelItem &li = mList[i]; - li.mId = esm.getHNString(mRecName); - esm.getHNT(li.mLevel, "INTV"); - } -} -void LevelledListBase::save(ESMWriter &esm) const -{ - esm.writeHNT("DATA", mFlags); - esm.writeHNT("NNAM", mChanceNone); - esm.writeHNT("INDX", mList.size()); + // If this levelled list was already loaded by a previous content file, + // we overwrite the list. Merging lists should probably be left to external tools, + // with the limited amount of information there is in the records, all merging methods + // will be flawed in some way. For a proper fix the ESM format would have to be changed + // to actually track list changes instead of including the whole list for every file + // that does something with that list. - for (std::vector::const_iterator it = mList.begin(); it != mList.end(); ++it) + for (size_t i = 0; i < mList.size(); i++) + { + LevelItem &li = mList[i]; + li.mId = esm.getHNString(mRecName); + esm.getHNT(li.mLevel, "INTV"); + } + } + void LevelledListBase::save(ESMWriter &esm) const { - esm.writeHNCString(mRecName, it->mId); - esm.writeHNT("INTV", it->mLevel); + esm.writeHNT("DATA", mFlags); + esm.writeHNT("NNAM", mChanceNone); + esm.writeHNT("INDX", mList.size()); + + for (std::vector::const_iterator it = mList.begin(); it != mList.end(); ++it) + { + esm.writeHNCString(mRecName, it->mId); + esm.writeHNT("INTV", it->mLevel); + } } -} void LevelledListBase::blank() { diff --git a/components/esm/loadligh.cpp b/components/esm/loadligh.cpp index f88ff09d6..26d70d964 100644 --- a/components/esm/loadligh.cpp +++ b/components/esm/loadligh.cpp @@ -8,25 +8,50 @@ namespace ESM { unsigned int Light::sRecordId = REC_LIGH; -void Light::load(ESMReader &esm) -{ - mModel = esm.getHNOString("MODL"); - mName = esm.getHNOString("FNAM"); - mIcon = esm.getHNOString("ITEX"); - assert(sizeof(mData) == 24); - esm.getHNT(mData, "LHDT", 24); - mScript = esm.getHNOString("SCRI"); - mSound = esm.getHNOString("SNAM"); -} -void Light::save(ESMWriter &esm) const -{ - esm.writeHNCString("MODL", mModel); - esm.writeHNOCString("FNAM", mName); - esm.writeHNOCString("ITEX", mIcon); - esm.writeHNT("LHDT", mData, 24); - esm.writeHNOCString("SCRI", mScript); - esm.writeHNOCString("SNAM", mSound); -} + void Light::load(ESMReader &esm) + { + bool hasData = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'I','T','E','X'>::value: + mIcon = esm.getHString(); + break; + case ESM::FourCC<'L','H','D','T'>::value: + esm.getHT(mData, 24); + hasData = true; + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + case ESM::FourCC<'S','N','A','M'>::value: + mSound = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasData) + esm.fail("Missing LHDT subrecord"); + } + void Light::save(ESMWriter &esm) const + { + esm.writeHNCString("MODL", mModel); + esm.writeHNOCString("FNAM", mName); + esm.writeHNOCString("ITEX", mIcon); + esm.writeHNT("LHDT", mData, 24); + esm.writeHNOCString("SCRI", mScript); + esm.writeHNOCString("SNAM", mSound); + } void Light::blank() { diff --git a/components/esm/loadlock.cpp b/components/esm/loadlock.cpp index 42677a22b..2747a6f78 100644 --- a/components/esm/loadlock.cpp +++ b/components/esm/loadlock.cpp @@ -8,26 +8,48 @@ namespace ESM { unsigned int Lockpick::sRecordId = REC_LOCK; -void Lockpick::load(ESMReader &esm) -{ - mModel = esm.getHNString("MODL"); - mName = esm.getHNOString("FNAM"); - - esm.getHNT(mData, "LKDT", 16); - - mScript = esm.getHNOString("SCRI"); - mIcon = esm.getHNOString("ITEX"); -} + void Lockpick::load(ESMReader &esm) + { + bool hasData = true; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'L','K','D','T'>::value: + esm.getHT(mData, 16); + hasData = true; + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + case ESM::FourCC<'I','T','E','X'>::value: + mIcon = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasData) + esm.fail("Missing LKDT subrecord"); + } -void Lockpick::save(ESMWriter &esm) const -{ - esm.writeHNCString("MODL", mModel); - esm.writeHNOCString("FNAM", mName); + void Lockpick::save(ESMWriter &esm) const + { + esm.writeHNCString("MODL", mModel); + esm.writeHNOCString("FNAM", mName); - esm.writeHNT("LKDT", mData, 16); - esm.writeHNOString("SCRI", mScript); - esm.writeHNOCString("ITEX", mIcon); -} + esm.writeHNT("LKDT", mData, 16); + esm.writeHNOString("SCRI", mScript); + esm.writeHNOCString("ITEX", mIcon); + } void Lockpick::blank() { diff --git a/components/esm/loadmgef.cpp b/components/esm/loadmgef.cpp index 3ec07a2a9..6f859ab3c 100644 --- a/components/esm/loadmgef.cpp +++ b/components/esm/loadmgef.cpp @@ -246,7 +246,7 @@ void MagicEffect::load(ESMReader &esm) mDescription = esm.getHString(); break; default: - esm.fail("Unknown subrecord " + esm.retSubName().toString()); + esm.fail("Unknown subrecord"); } } } diff --git a/components/esm/loadmgef.hpp b/components/esm/loadmgef.hpp index 4c7ac938a..e66322832 100644 --- a/components/esm/loadmgef.hpp +++ b/components/esm/loadmgef.hpp @@ -57,9 +57,9 @@ struct MagicEffect // Glow color for enchanted items with this effect int mRed, mGreen, mBlue; - float mUnknown1; + float mUnknown1; // Called "Size X" in CS float mSpeed; // Speed of fired projectile - float mUnknown2; + float mUnknown2; // Called "Size Cap" in CS }; // 36 bytes static const std::map sNames; diff --git a/components/esm/loadnpc.cpp b/components/esm/loadnpc.cpp index 3d617241b..d90b4816d 100644 --- a/components/esm/loadnpc.cpp +++ b/components/esm/loadnpc.cpp @@ -99,7 +99,7 @@ namespace ESM mAiPackage.add(esm); break; default: - esm.fail("Unknown subrecord " + esm.retSubName().toString()); + esm.fail("Unknown subrecord"); } } if (!hasNpdt) diff --git a/components/esm/loadprob.cpp b/components/esm/loadprob.cpp index b736bb64b..c5f80c584 100644 --- a/components/esm/loadprob.cpp +++ b/components/esm/loadprob.cpp @@ -8,26 +8,48 @@ namespace ESM { unsigned int Probe::sRecordId = REC_PROB; -void Probe::load(ESMReader &esm) -{ - mModel = esm.getHNString("MODL"); - mName = esm.getHNOString("FNAM"); - - esm.getHNT(mData, "PBDT", 16); - - mScript = esm.getHNOString("SCRI"); - mIcon = esm.getHNOString("ITEX"); -} + void Probe::load(ESMReader &esm) + { + bool hasData = true; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'P','B','D','T'>::value: + esm.getHT(mData, 16); + hasData = true; + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + case ESM::FourCC<'I','T','E','X'>::value: + mIcon = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasData) + esm.fail("Missing PBDT subrecord"); + } -void Probe::save(ESMWriter &esm) const -{ - esm.writeHNCString("MODL", mModel); - esm.writeHNOCString("FNAM", mName); + void Probe::save(ESMWriter &esm) const + { + esm.writeHNCString("MODL", mModel); + esm.writeHNOCString("FNAM", mName); - esm.writeHNT("PBDT", mData, 16); - esm.writeHNOString("SCRI", mScript); - esm.writeHNOCString("ITEX", mIcon); -} + esm.writeHNT("PBDT", mData, 16); + esm.writeHNOString("SCRI", mScript); + esm.writeHNOCString("ITEX", mIcon); + } void Probe::blank() { diff --git a/components/esm/loadrace.cpp b/components/esm/loadrace.cpp index 211fd5ffb..967c0d0d7 100644 --- a/components/esm/loadrace.cpp +++ b/components/esm/loadrace.cpp @@ -43,7 +43,7 @@ void Race::load(ESMReader &esm) mPowers.add(esm); break; default: - esm.fail("Unknown subrecord " + esm.retSubName().toString()); + esm.fail("Unknown subrecord"); } } if (!hasData) diff --git a/components/esm/loadrepa.cpp b/components/esm/loadrepa.cpp index 4e6cd7794..f90f9e39d 100644 --- a/components/esm/loadrepa.cpp +++ b/components/esm/loadrepa.cpp @@ -10,13 +10,35 @@ namespace ESM void Repair::load(ESMReader &esm) { - mModel = esm.getHNString("MODL"); - mName = esm.getHNOString("FNAM"); - - esm.getHNT(mData, "RIDT", 16); - - mScript = esm.getHNOString("SCRI"); - mIcon = esm.getHNOString("ITEX"); + bool hasData = true; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'R','I','D','T'>::value: + esm.getHT(mData, 16); + hasData = true; + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + case ESM::FourCC<'I','T','E','X'>::value: + mIcon = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasData) + esm.fail("Missing RIDT subrecord"); } void Repair::save(ESMWriter &esm) const diff --git a/components/esm/loadscpt.cpp b/components/esm/loadscpt.cpp index 2df8e66ce..0c2bdd42f 100644 --- a/components/esm/loadscpt.cpp +++ b/components/esm/loadscpt.cpp @@ -9,17 +9,7 @@ namespace ESM unsigned int Script::sRecordId = REC_SCPT; -void Script::load(ESMReader &esm) -{ - SCHD data; - esm.getHNT(data, "SCHD", 52); - mData = data.mData; - mId = data.mName.toString(); - - mVarNames.clear(); - - // List of local variables - if (esm.isNextSub("SCVR")) + void Script::loadSCVR(ESMReader &esm) { int s = mData.mStringTableSize; @@ -66,58 +56,70 @@ void Script::load(ESMReader &esm) } } - // Script mData - if (esm.isNextSub("SCDT")) + void Script::load(ESMReader &esm) { - mScriptData.resize(mData.mScriptDataSize); - esm.getHExact(&mScriptData[0], mScriptData.size()); - } + SCHD data; + esm.getHNT(data, "SCHD", 52); + mData = data.mData; + mId = data.mName.toString(); + + mVarNames.clear(); - // Script text - mScriptText = esm.getHNOString("SCTX"); - - // NOTE: A minor hack/workaround... - // - // MAO_Containers.esp from Morrowind Acoustic Overhaul has SCVR records - // at the end (see Bug #1849). Since OpenMW does not use SCVR subrecords - // for variable names just skip these as a quick fix. An alternative - // solution would be to decode and validate SCVR subrecords even if they - // appear here. - if (esm.isNextSub("SCVR")) { - esm.skipHSub(); + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'S','C','V','R'>::value: + // list of local variables + loadSCVR(esm); + break; + case ESM::FourCC<'S','C','D','T'>::value: + // compiled script + mScriptData.resize(mData.mScriptDataSize); + esm.getHExact(&mScriptData[0], mScriptData.size()); + break; + case ESM::FourCC<'S','C','T','X'>::value: + mScriptText = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + } + } } -} -void Script::save(ESMWriter &esm) const -{ - std::string varNameString; - if (!mVarNames.empty()) - for (std::vector::const_iterator it = mVarNames.begin(); it != mVarNames.end(); ++it) - varNameString.append(*it); - SCHD data; - memset(&data, 0, sizeof(data)); + void Script::save(ESMWriter &esm) const + { + std::string varNameString; + if (!mVarNames.empty()) + for (std::vector::const_iterator it = mVarNames.begin(); it != mVarNames.end(); ++it) + varNameString.append(*it); - data.mData = mData; - memcpy(data.mName.name, mId.c_str(), mId.size()); + SCHD data; + memset(&data, 0, sizeof(data)); - esm.writeHNT("SCHD", data, 52); + data.mData = mData; + memcpy(data.mName.name, mId.c_str(), mId.size()); - if (!mVarNames.empty()) - { - esm.startSubRecord("SCVR"); - for (std::vector::const_iterator it = mVarNames.begin(); it != mVarNames.end(); ++it) + esm.writeHNT("SCHD", data, 52); + + if (!mVarNames.empty()) { - esm.writeHCString(*it); + esm.startSubRecord("SCVR"); + for (std::vector::const_iterator it = mVarNames.begin(); it != mVarNames.end(); ++it) + { + esm.writeHCString(*it); + } + esm.endRecord("SCVR"); } - esm.endRecord("SCVR"); - } - esm.startSubRecord("SCDT"); - esm.write(reinterpret_cast(&mScriptData[0]), mData.mScriptDataSize); - esm.endRecord("SCDT"); + esm.startSubRecord("SCDT"); + esm.write(reinterpret_cast(&mScriptData[0]), mData.mScriptDataSize); + esm.endRecord("SCDT"); - esm.writeHNOString("SCTX", mScriptText); -} + esm.writeHNOString("SCTX", mScriptText); + } void Script::blank() { diff --git a/components/esm/loadscpt.hpp b/components/esm/loadscpt.hpp index d5b87b5dc..deb71de6a 100644 --- a/components/esm/loadscpt.hpp +++ b/components/esm/loadscpt.hpp @@ -53,6 +53,9 @@ public: void blank(); ///< Set record to default state (does not touch the ID/index). + +private: + void loadSCVR(ESMReader &esm); }; } #endif diff --git a/components/esm/loadskil.cpp b/components/esm/loadskil.cpp index b6724e938..7883b8a1a 100644 --- a/components/esm/loadskil.cpp +++ b/components/esm/loadskil.cpp @@ -129,23 +129,47 @@ namespace ESM unsigned int Skill::sRecordId = REC_SKIL; -void Skill::load(ESMReader &esm) -{ - esm.getHNT(mIndex, "INDX"); - esm.getHNT(mData, "SKDT", 24); - mDescription = esm.getHNOString("DESC"); + void Skill::load(ESMReader &esm) + { + bool hasIndex = false; + bool hasData = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'I','N','D','X'>::value: + esm.getHT(mIndex); + hasIndex = true; + break; + case ESM::FourCC<'S','K','D','T'>::value: + esm.getHT(mData, 24); + hasData = true; + break; + case ESM::FourCC<'D','E','S','C'>::value: + mDescription = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasIndex) + esm.fail("Missing INDX"); + if (!hasData) + esm.fail("Missing SKDT"); - // create an ID from the index and the name (only used in the editor and likely to change in the - // future) - mId = indexToId (mIndex); -} + // create an ID from the index and the name (only used in the editor and likely to change in the + // future) + mId = indexToId (mIndex); + } -void Skill::save(ESMWriter &esm) const -{ - esm.writeHNT("INDX", mIndex); - esm.writeHNT("SKDT", mData, 24); - esm.writeHNOString("DESC", mDescription); -} + void Skill::save(ESMWriter &esm) const + { + esm.writeHNT("INDX", mIndex); + esm.writeHNT("SKDT", mData, 24); + esm.writeHNOString("DESC", mDescription); + } void Skill::blank() { diff --git a/components/esm/loadsndg.cpp b/components/esm/loadsndg.cpp index 9ab061ec2..5ee6f5245 100644 --- a/components/esm/loadsndg.cpp +++ b/components/esm/loadsndg.cpp @@ -8,19 +8,38 @@ namespace ESM { unsigned int SoundGenerator::sRecordId = REC_SNDG; -void SoundGenerator::load(ESMReader &esm) -{ - esm.getHNT(mType, "DATA", 4); - - mCreature = esm.getHNOString("CNAM"); - mSound = esm.getHNOString("SNAM"); -} -void SoundGenerator::save(ESMWriter &esm) const -{ - esm.writeHNT("DATA", mType, 4); - esm.writeHNOCString("CNAM", mCreature); - esm.writeHNOCString("SNAM", mSound); -} + void SoundGenerator::load(ESMReader &esm) + { + bool hasData = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'D','A','T','A'>::value: + esm.getHT(mType, 4); + hasData = true; + break; + case ESM::FourCC<'C','N','A','M'>::value: + mCreature = esm.getHString(); + break; + case ESM::FourCC<'S','N','A','M'>::value: + mSound = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasData) + esm.fail("Missing DATA"); + } + void SoundGenerator::save(ESMWriter &esm) const + { + esm.writeHNT("DATA", mType, 4); + esm.writeHNOCString("CNAM", mCreature); + esm.writeHNOCString("SNAM", mSound); + } void SoundGenerator::blank() { diff --git a/components/esm/loadsoun.cpp b/components/esm/loadsoun.cpp index 28e4d7d9c..690c1b448 100644 --- a/components/esm/loadsoun.cpp +++ b/components/esm/loadsoun.cpp @@ -8,22 +8,35 @@ namespace ESM { unsigned int Sound::sRecordId = REC_SOUN; -void Sound::load(ESMReader &esm) -{ - mSound = esm.getHNOString("FNAM"); - esm.getHNT(mData, "DATA", 3); - /* - cout << "vol=" << (int)data.volume - << " min=" << (int)data.minRange - << " max=" << (int)data.maxRange - << endl; - */ -} -void Sound::save(ESMWriter &esm) const -{ - esm.writeHNOCString("FNAM", mSound); - esm.writeHNT("DATA", mData, 3); -} + void Sound::load(ESMReader &esm) + { + bool hasData = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'F','N','A','M'>::value: + mSound = esm.getHString(); + break; + case ESM::FourCC<'D','A','T','A'>::value: + esm.getHT(mData, 3); + hasData = true; + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasData) + esm.fail("Missing DATA"); + } + + void Sound::save(ESMWriter &esm) const + { + esm.writeHNOCString("FNAM", mSound); + esm.writeHNT("DATA", mData, 3); + } void Sound::blank() { diff --git a/components/esm/loadspel.cpp b/components/esm/loadspel.cpp index 716f47e71..cd630d6ab 100644 --- a/components/esm/loadspel.cpp +++ b/components/esm/loadspel.cpp @@ -8,40 +8,40 @@ namespace ESM { unsigned int Spell::sRecordId = REC_SPEL; -void Spell::load(ESMReader &esm) -{ - bool hasData = false; - while (esm.hasMoreSubs()) + void Spell::load(ESMReader &esm) { - esm.getSubName(); - uint32_t val = esm.retSubName().val; - - switch (val) + bool hasData = false; + while (esm.hasMoreSubs()) { - case ESM::FourCC<'F','N','A','M'>::value: - mName = esm.getHString(); - break; - case ESM::FourCC<'S','P','D','T'>::value: - esm.getHT(mData, 12); - hasData = true; - break; - case ESM::FourCC<'E','N','A','M'>::value: - ENAMstruct s; - esm.getHT(s, 24); - mEffects.mList.push_back(s); - break; + esm.getSubName(); + uint32_t val = esm.retSubName().val; + + switch (val) + { + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'S','P','D','T'>::value: + esm.getHT(mData, 12); + hasData = true; + break; + case ESM::FourCC<'E','N','A','M'>::value: + ENAMstruct s; + esm.getHT(s, 24); + mEffects.mList.push_back(s); + break; + } } + if (!hasData) + esm.fail("Missing SPDT subrecord"); } - if (!hasData) - esm.fail("Missing SPDT subrecord"); -} -void Spell::save(ESMWriter &esm) const -{ - esm.writeHNOCString("FNAM", mName); - esm.writeHNT("SPDT", mData, 12); - mEffects.save(esm); -} + void Spell::save(ESMWriter &esm) const + { + esm.writeHNOCString("FNAM", mName); + esm.writeHNT("SPDT", mData, 12); + mEffects.save(esm); + } void Spell::blank() { diff --git a/components/esm/loadsscr.cpp b/components/esm/loadsscr.cpp index 69b04bb23..816075b7e 100644 --- a/components/esm/loadsscr.cpp +++ b/components/esm/loadsscr.cpp @@ -8,15 +8,37 @@ namespace ESM { unsigned int StartScript::sRecordId = REC_SSCR; -void StartScript::load(ESMReader &esm) -{ - mData = esm.getHNString("DATA"); - mScript = esm.getHNString("NAME"); -} -void StartScript::save(ESMWriter &esm) const -{ - esm.writeHNString("DATA", mData); - esm.writeHNString("NAME", mScript); -} + void StartScript::load(ESMReader &esm) + { + bool hasData = false; + bool hasName = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'D','A','T','A'>::value: + mData = esm.getHString(); + hasData = true; + break; + case ESM::FourCC<'N','A','M','E'>::value: + mScript = esm.getHString(); + hasName = true; + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasData) + esm.fail("Missing DATA"); + if (!hasName) + esm.fail("Missing NAME"); + } + void StartScript::save(ESMWriter &esm) const + { + esm.writeHNString("DATA", mData); + esm.writeHNString("NAME", mScript); + } } diff --git a/components/esm/loadstat.cpp b/components/esm/loadstat.cpp index 53d1b4bb5..2bb817332 100644 --- a/components/esm/loadstat.cpp +++ b/components/esm/loadstat.cpp @@ -8,15 +8,16 @@ namespace ESM { unsigned int Static::sRecordId = REC_STAT; -void Static::load(ESMReader &esm) -{ - mPersistent = esm.getRecordFlags() & 0x0400; - mModel = esm.getHNString("MODL"); -} -void Static::save(ESMWriter &esm) const -{ - esm.writeHNCString("MODL", mModel); -} + void Static::load(ESMReader &esm) + { + mPersistent = esm.getRecordFlags() & 0x0400; + + mModel = esm.getHNString("MODL"); + } + void Static::save(ESMWriter &esm) const + { + esm.writeHNCString("MODL", mModel); + } void Static::blank() { diff --git a/components/esm/loadtes3.hpp b/components/esm/loadtes3.hpp index 2c63e3691..f2dde4d1f 100644 --- a/components/esm/loadtes3.hpp +++ b/components/esm/loadtes3.hpp @@ -50,8 +50,8 @@ namespace ESM NAME32 mPlayerName; }; GMDT mGameData; // Used in .ess savegames only - std::vector mSCRD; // Used in .ess savegames only, screenshot? - std::vector mSCRS; // Used in .ess savegames only, screenshot? + std::vector mSCRD; // Used in .ess savegames only, unknown + std::vector mSCRS; // Used in .ess savegames only, screenshot Data mData; int mFormat; diff --git a/components/esm/spelllist.cpp b/components/esm/spelllist.cpp index 98bd53ae6..71c7b340d 100644 --- a/components/esm/spelllist.cpp +++ b/components/esm/spelllist.cpp @@ -5,14 +5,6 @@ namespace ESM { -void SpellList::load(ESMReader &esm) -{ - mList.clear(); - while (esm.isNextSub("NPCS")) { - add(esm); - } -} - void SpellList::add(ESMReader &esm) { mList.push_back(esm.getHString()); diff --git a/components/esm/spelllist.hpp b/components/esm/spelllist.hpp index 9493199a8..6fb098065 100644 --- a/components/esm/spelllist.hpp +++ b/components/esm/spelllist.hpp @@ -11,6 +11,7 @@ namespace ESM /** A list of references to spells and spell effects. This is shared between the records BSGN, NPC and RACE. + NPCS subrecord. */ struct SpellList { @@ -22,9 +23,6 @@ namespace ESM /// Load one spell, assumes the subrecord name was already read void add(ESMReader &esm); - /// Load all spells - /// TODO: remove this method, the ESM format doesn't guarantee that all spell subrecords follow one another - void load(ESMReader &esm); void save(ESMWriter &esm) const; }; } From e1314d62117a31d3bd77912c6c70f67b26262a6f Mon Sep 17 00:00:00 2001 From: Kamil Bar Date: Fri, 13 Feb 2015 04:11:36 +0100 Subject: [PATCH 0557/3725] Implement OpenCS reference validation (Feature #831) --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/tools/referencecheck.cpp | 103 +++++++++++++++++++++ apps/opencs/model/tools/referencecheck.hpp | 28 ++++++ apps/opencs/model/tools/tools.cpp | 3 + 4 files changed, 135 insertions(+), 1 deletion(-) create mode 100644 apps/opencs/model/tools/referencecheck.cpp create mode 100644 apps/opencs/model/tools/referencecheck.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 0b83feb45..d29546208 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -41,7 +41,7 @@ opencs_units (model/tools opencs_units_noqt (model/tools mandatoryid skillcheck classcheck factioncheck racecheck soundcheck regioncheck - birthsigncheck spellcheck referenceablecheck scriptcheck bodypartcheck + birthsigncheck spellcheck referencecheck referenceablecheck scriptcheck bodypartcheck ) diff --git a/apps/opencs/model/tools/referencecheck.cpp b/apps/opencs/model/tools/referencecheck.cpp new file mode 100644 index 000000000..eb97645eb --- /dev/null +++ b/apps/opencs/model/tools/referencecheck.cpp @@ -0,0 +1,103 @@ +#include "referencecheck.hpp" + +#include + +CSMTools::ReferenceCheckStage::ReferenceCheckStage( + const CSMWorld::RefCollection& references, + const CSMWorld::RefIdCollection& referencables, + const CSMWorld::IdCollection& cells, + const CSMWorld::IdCollection& factions) + : + mReferences(references), + mReferencables(referencables), + mCells(cells), + mFactions(factions) +{ +} + +void CSMTools::ReferenceCheckStage::perform(int stage, CSMDoc::Messages &messages) +{ + const CSMWorld::Record& record = mReferences.getRecord(stage); + + if (record.isDeleted()) + return; + + const CSMWorld::CellRef& cellRef = record.get(); + const CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Reference, cellRef.mId); + + // Check for empty reference id + if (cellRef.mRefID.empty()) + messages.push_back(std::make_pair(id, " is an empty reference")); + + // Check for non existing referenced object + if (mReferencables.searchId(cellRef.mRefID) == -1) + messages.push_back(std::make_pair(id, " is referencing non existing object " + cellRef.mRefID)); + + // Check if referenced object is in valid cell + if (mCells.searchId(cellRef.mCell) == -1) + messages.push_back(std::make_pair(id, " is referencing object from non existing cell " + cellRef.mCell)); + + // If object have owner, check if that owner reference is valid + if (!cellRef.mOwner.empty() and mReferencables.searchId(cellRef.mOwner) == -1) + messages.push_back(std::make_pair(id, " has non existing owner " + cellRef.mOwner)); + + // If object have creature soul trapped, check if that creature reference is valid + if (!cellRef.mSoul.empty()) + if (mReferencables.searchId(cellRef.mSoul) == -1) + messages.push_back(std::make_pair(id, " has non existing trapped soul " + cellRef.mSoul)); + + bool hasFaction = !cellRef.mFaction.empty(); + + // If object have faction, check if that faction reference is valid + if (hasFaction) + if (mFactions.searchId(cellRef.mFaction) == -1) + messages.push_back(std::make_pair(id, " has non existing faction " + cellRef.mFaction)); + + // Check item's faction rank + if (hasFaction && cellRef.mFactionRank < -1) + messages.push_back(std::make_pair(id, " has faction set but has invalid faction rank " + cellRef.mFactionRank)); + else if (!hasFaction && cellRef.mFactionRank != -2) + messages.push_back(std::make_pair(id, " has invalid faction rank " + cellRef.mFactionRank)); + + // If door have destination cell, check if that reference is valid + if (!cellRef.mDestCell.empty()) + if (mCells.searchId(cellRef.mDestCell) == -1) + messages.push_back(std::make_pair(id, " has non existing destination cell " + cellRef.mDestCell)); + + // Check if scale isn't negative + if (cellRef.mScale < 0) + { + std::string str = " has negative scale "; + str += boost::lexical_cast(cellRef.mScale); + messages.push_back(std::make_pair(id, id.getId() + str)); + } + + // Check if charge isn't negative + if (cellRef.mChargeFloat < 0) + { + std::string str = " has negative charges "; + str += boost::lexical_cast(cellRef.mChargeFloat); + messages.push_back(std::make_pair(id, id.getId() + str)); + } + + // Check if enchantement points aren't negative or are at full (-1) + if (cellRef.mEnchantmentCharge < 0 && cellRef.mEnchantmentCharge != -1) + { + std::string str = " has negative enchantment points "; + str += boost::lexical_cast(cellRef.mEnchantmentCharge); + messages.push_back(std::make_pair(id, id.getId() + str)); + } + + // Check if gold value isn't negative + if (cellRef.mGoldValue < 0) + { + std::string str = " has negative gold value "; + str += cellRef.mGoldValue; + messages.push_back(std::make_pair(id, id.getId() + str)); + } +} + +int CSMTools::ReferenceCheckStage::setup() +{ + return mReferences.getSize(); +} \ No newline at end of file diff --git a/apps/opencs/model/tools/referencecheck.hpp b/apps/opencs/model/tools/referencecheck.hpp new file mode 100644 index 000000000..d1eacb5b5 --- /dev/null +++ b/apps/opencs/model/tools/referencecheck.hpp @@ -0,0 +1,28 @@ +#ifndef CSM_TOOLS_REFERENCECHECK_H +#define CSM_TOOLS_REFERENCECHECK_H + +#include "../doc/state.hpp" +#include "../doc/document.hpp" + +namespace CSMTools +{ + class ReferenceCheckStage : public CSMDoc::Stage + { + public: + ReferenceCheckStage (const CSMWorld::RefCollection& references, + const CSMWorld::RefIdCollection& referencables, + const CSMWorld::IdCollection& cells, + const CSMWorld::IdCollection& factions); + + virtual void perform(int stage, CSMDoc::Messages& messages); + virtual int setup(); + + private: + const CSMWorld::RefCollection& mReferences; + const CSMWorld::RefIdCollection& mReferencables; + const CSMWorld::IdCollection& mCells; + const CSMWorld::IdCollection& mFactions; + }; +} + +#endif // CSM_TOOLS_REFERENCECHECK_H \ No newline at end of file diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index 6e157f664..0c20bd17b 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -23,6 +23,7 @@ #include "referenceablecheck.hpp" #include "scriptcheck.hpp" #include "bodypartcheck.hpp" +#include "referencecheck.hpp" CSMDoc::Operation *CSMTools::Tools::get (int type) { @@ -82,6 +83,8 @@ CSMDoc::Operation *CSMTools::Tools::getVerifier() mVerifier->appendStage (new ReferenceableCheckStage (mData.getReferenceables().getDataSet(), mData.getRaces(), mData.getClasses(), mData.getFactions())); + mVerifier->appendStage (new ReferenceCheckStage(mData.getReferences(), mData.getReferenceables(), mData.getCells(), mData.getFactions())); + mVerifier->appendStage (new ScriptCheckStage (mDocument)); mVerifier->appendStage( From 1d18d3ff4cb5a6f28b7f0d7ca03f076a5794a447 Mon Sep 17 00:00:00 2001 From: Jordan Ayers Date: Thu, 12 Feb 2015 22:27:47 -0600 Subject: [PATCH 0558/3725] Add a full search to findInteriorPositionInWorldSpace. Part of OMW Bug #1533 Implement a search for one of the 'nearest' exterior cells. In this case, 'nearest' means the fewest number of cells away via door markers. This causes the world map position to update immediately after teleporting, unless the new cell has no connecting path to an exterior. Intervention spells and Jail travel will be much closer to vanialla Morrowind, except for in Mournhold. --- apps/openmw/mwworld/worldimp.cpp | 49 +++++++++++++++++++++++++------- 1 file changed, 38 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 188f3cdad..23cef1596 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2784,18 +2784,45 @@ namespace MWWorld { if (cell->isExterior()) return false; - MWWorld::CellRefList& doors = cell->get(); - CellRefList::List& refList = doors.mList; - // Check if any door in the cell leads to an exterior directly - for (CellRefList::List::iterator it = refList.begin(); it != refList.end(); ++it) - { - MWWorld::LiveCellRef& ref = *it; - if (ref.mRef.getTeleport() && ref.mRef.getDestCell().empty()) - { - ESM::Position pos = ref.mRef.getDoorDest(); - result = Ogre::Vector3(pos.pos); - return true; + // Search for a 'nearest' exterior, counting each cell between the starting + // cell and the exterior as a distance of 1. Will fail for isolated interiors. + std::set< std::string >checkedCells; + std::set< std::string >currentCells; + std::set< std::string >nextCells; + nextCells.insert( cell->getCell()->mName ); + + while ( !nextCells.empty() ) { + currentCells = nextCells; + nextCells.clear(); + for( std::set< std::string >::const_iterator i = currentCells.begin(); i != currentCells.end(); ++i ) { + MWWorld::CellStore *next = getInterior( *i ); + if ( !next ) continue; + + MWWorld::CellRefList& doors = next->get(); + CellRefList::List& refList = doors.mList; + + // Check if any door in the cell leads to an exterior directly + for (CellRefList::List::iterator it = refList.begin(); it != refList.end(); ++it) + { + MWWorld::LiveCellRef& ref = *it; + if (!ref.mRef.getTeleport()) continue; + + if (ref.mRef.getDestCell().empty()) + { + ESM::Position pos = ref.mRef.getDoorDest(); + result = Ogre::Vector3(pos.pos); + return true; + } + else + { + std::string dest = ref.mRef.getDestCell(); + if ( !checkedCells.count(dest) && !currentCells.count(dest) ) + nextCells.insert(dest); + } + } + + checkedCells.insert( *i ); } } From 52a064afc39a205eb0b893862b76d331dc6063cf Mon Sep 17 00:00:00 2001 From: Kamil Bar Date: Fri, 13 Feb 2015 12:13:40 +0100 Subject: [PATCH 0559/3725] Fixed charges checking --- apps/opencs/model/tools/referencecheck.cpp | 40 +++++++++++++++------- apps/opencs/model/tools/referencecheck.hpp | 1 + 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/apps/opencs/model/tools/referencecheck.cpp b/apps/opencs/model/tools/referencecheck.cpp index eb97645eb..f1d092be5 100644 --- a/apps/opencs/model/tools/referencecheck.cpp +++ b/apps/opencs/model/tools/referencecheck.cpp @@ -10,6 +10,7 @@ CSMTools::ReferenceCheckStage::ReferenceCheckStage( : mReferences(references), mReferencables(referencables), + mDataSet(referencables.getDataSet()), mCells(cells), mFactions(factions) { @@ -26,12 +27,33 @@ void CSMTools::ReferenceCheckStage::perform(int stage, CSMDoc::Messages &message const CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Reference, cellRef.mId); // Check for empty reference id - if (cellRef.mRefID.empty()) + if (cellRef.mRefID.empty()) { messages.push_back(std::make_pair(id, " is an empty reference")); - - // Check for non existing referenced object - if (mReferencables.searchId(cellRef.mRefID) == -1) - messages.push_back(std::make_pair(id, " is referencing non existing object " + cellRef.mRefID)); + } else { + // Check for non existing referenced object + if (mReferencables.searchId(cellRef.mRefID) == -1) { + messages.push_back(std::make_pair(id, " is referencing non existing object " + cellRef.mRefID)); + } else { + // Check if reference charge isn't negative if it's proper type + CSMWorld::RefIdData::LocalIndex localIndex = mDataSet.searchId(cellRef.mRefID); + if (localIndex.second == CSMWorld::UniversalId::Type_Armor || + localIndex.second == CSMWorld::UniversalId::Type_Weapon) { + if (cellRef.mChargeFloat < 0) { + std::string str = " has negative durability "; + str += boost::lexical_cast(cellRef.mChargeFloat); + messages.push_back(std::make_pair(id, id.getId() + str)); + } + } else if (localIndex.second == CSMWorld::UniversalId::Type_Lockpick || + localIndex.second == CSMWorld::UniversalId::Type_Probe || + localIndex.second == CSMWorld::UniversalId::Type_Repair) { + if (cellRef.mChargeInt < -1) { + std::string str = " has invalid charges "; + str += boost::lexical_cast(cellRef.mChargeFloat); + messages.push_back(std::make_pair(id, id.getId() + str)); + } + } + } + } // Check if referenced object is in valid cell if (mCells.searchId(cellRef.mCell) == -1) @@ -72,14 +94,6 @@ void CSMTools::ReferenceCheckStage::perform(int stage, CSMDoc::Messages &message messages.push_back(std::make_pair(id, id.getId() + str)); } - // Check if charge isn't negative - if (cellRef.mChargeFloat < 0) - { - std::string str = " has negative charges "; - str += boost::lexical_cast(cellRef.mChargeFloat); - messages.push_back(std::make_pair(id, id.getId() + str)); - } - // Check if enchantement points aren't negative or are at full (-1) if (cellRef.mEnchantmentCharge < 0 && cellRef.mEnchantmentCharge != -1) { diff --git a/apps/opencs/model/tools/referencecheck.hpp b/apps/opencs/model/tools/referencecheck.hpp index d1eacb5b5..9cf685b3a 100644 --- a/apps/opencs/model/tools/referencecheck.hpp +++ b/apps/opencs/model/tools/referencecheck.hpp @@ -20,6 +20,7 @@ namespace CSMTools private: const CSMWorld::RefCollection& mReferences; const CSMWorld::RefIdCollection& mReferencables; + const CSMWorld::RefIdData& mDataSet; const CSMWorld::IdCollection& mCells; const CSMWorld::IdCollection& mFactions; }; From 9628415e21aca4cc7649f2f32fab3fb2b52ad209 Mon Sep 17 00:00:00 2001 From: Kamil Bar Date: Fri, 13 Feb 2015 12:16:46 +0100 Subject: [PATCH 0560/3725] Missing change & changed comments to represent actual code --- apps/opencs/model/tools/referencecheck.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/tools/referencecheck.cpp b/apps/opencs/model/tools/referencecheck.cpp index f1d092be5..d8e056a76 100644 --- a/apps/opencs/model/tools/referencecheck.cpp +++ b/apps/opencs/model/tools/referencecheck.cpp @@ -34,7 +34,7 @@ void CSMTools::ReferenceCheckStage::perform(int stage, CSMDoc::Messages &message if (mReferencables.searchId(cellRef.mRefID) == -1) { messages.push_back(std::make_pair(id, " is referencing non existing object " + cellRef.mRefID)); } else { - // Check if reference charge isn't negative if it's proper type + // Check if reference charge is valid for it's proper referenced type CSMWorld::RefIdData::LocalIndex localIndex = mDataSet.searchId(cellRef.mRefID); if (localIndex.second == CSMWorld::UniversalId::Type_Armor || localIndex.second == CSMWorld::UniversalId::Type_Weapon) { @@ -48,7 +48,7 @@ void CSMTools::ReferenceCheckStage::perform(int stage, CSMDoc::Messages &message localIndex.second == CSMWorld::UniversalId::Type_Repair) { if (cellRef.mChargeInt < -1) { std::string str = " has invalid charges "; - str += boost::lexical_cast(cellRef.mChargeFloat); + str += boost::lexical_cast(cellRef.mChargeInt); messages.push_back(std::make_pair(id, id.getId() + str)); } } From 3b7a23aa725935cb69ebd23ded4bfe36510e8333 Mon Sep 17 00:00:00 2001 From: Kamil Bar Date: Fri, 13 Feb 2015 13:11:10 +0100 Subject: [PATCH 0561/3725] Fixed charge checks for light and other objects, corrected CellRef charge union comments --- apps/opencs/model/tools/referencecheck.cpp | 19 ++++++------------- components/esm/cellref.hpp | 6 ++++-- 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/apps/opencs/model/tools/referencecheck.cpp b/apps/opencs/model/tools/referencecheck.cpp index d8e056a76..aae83bd5e 100644 --- a/apps/opencs/model/tools/referencecheck.cpp +++ b/apps/opencs/model/tools/referencecheck.cpp @@ -36,21 +36,14 @@ void CSMTools::ReferenceCheckStage::perform(int stage, CSMDoc::Messages &message } else { // Check if reference charge is valid for it's proper referenced type CSMWorld::RefIdData::LocalIndex localIndex = mDataSet.searchId(cellRef.mRefID); - if (localIndex.second == CSMWorld::UniversalId::Type_Armor || - localIndex.second == CSMWorld::UniversalId::Type_Weapon) { - if (cellRef.mChargeFloat < 0) { - std::string str = " has negative durability "; + bool isLight = localIndex.second == CSMWorld::UniversalId::Type_Light; + if ((isLight && cellRef.mChargeFloat < -1) || (!isLight && cellRef.mChargeInt < -1)) { + std::string str = " has invalid charge "; + if (localIndex.second == CSMWorld::UniversalId::Type_Light) str += boost::lexical_cast(cellRef.mChargeFloat); - messages.push_back(std::make_pair(id, id.getId() + str)); - } - } else if (localIndex.second == CSMWorld::UniversalId::Type_Lockpick || - localIndex.second == CSMWorld::UniversalId::Type_Probe || - localIndex.second == CSMWorld::UniversalId::Type_Repair) { - if (cellRef.mChargeInt < -1) { - std::string str = " has invalid charges "; + else str += boost::lexical_cast(cellRef.mChargeInt); - messages.push_back(std::make_pair(id, id.getId() + str)); - } + messages.push_back(std::make_pair(id, id.getId() + str)); } } } diff --git a/components/esm/cellref.hpp b/components/esm/cellref.hpp index 56932aa4d..01b6a8473 100644 --- a/components/esm/cellref.hpp +++ b/components/esm/cellref.hpp @@ -59,10 +59,12 @@ namespace ESM // For weapon or armor, this is the remaining item health. // For tools (lockpicks, probes, repair hammer) it is the remaining uses. + // For lights it is remaining time. + // This could be -1 if the charge was not touched yet (i.e. full). union { - int mChargeInt; - float mChargeFloat; + int mChargeInt; // Used by everything except lights + float mChargeFloat; // Used only by lights }; // Remaining enchantment charge. This could be -1 if the charge was not touched yet (i.e. full). From a139e4efb08c102edf7afeb4d46cdafed8f2d98f Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 13 Feb 2015 16:51:34 +0100 Subject: [PATCH 0562/3725] Grey out completed quests in journal quests list --- apps/openmw/mwgui/journalviewmodel.cpp | 4 ++-- apps/openmw/mwgui/journalviewmodel.hpp | 4 ++-- apps/openmw/mwgui/journalwindow.cpp | 22 +++++++++++++++++++++- components/widgets/list.cpp | 4 ++-- components/widgets/list.hpp | 2 +- files/mygui/openmw_journal.skin.xml | 6 +++--- 6 files changed, 31 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwgui/journalviewmodel.cpp b/apps/openmw/mwgui/journalviewmodel.cpp index 3a86613f6..9a47070c2 100644 --- a/apps/openmw/mwgui/journalviewmodel.cpp +++ b/apps/openmw/mwgui/journalviewmodel.cpp @@ -199,7 +199,7 @@ struct JournalViewModelImpl : JournalViewModel }; - void visitQuestNames (bool active_only, boost::function visitor) const + void visitQuestNames (bool active_only, boost::function visitor) const { MWBase::Journal * journal = MWBase::Environment::get ().getJournal (); @@ -231,7 +231,7 @@ struct JournalViewModelImpl : JournalViewModel if (visitedQuests.find(quest.getName()) != visitedQuests.end()) continue; - visitor (quest.getName()); + visitor (quest.getName(), isFinished); visitedQuests.insert(quest.getName()); } diff --git a/apps/openmw/mwgui/journalviewmodel.hpp b/apps/openmw/mwgui/journalviewmodel.hpp index 5f0189b59..b3c6b0183 100644 --- a/apps/openmw/mwgui/journalviewmodel.hpp +++ b/apps/openmw/mwgui/journalviewmodel.hpp @@ -67,8 +67,8 @@ namespace MWGui /// returns true if their are no journal entries to display virtual bool isEmpty () const = 0; - /// walks the active and optionally completed, quests providing the name - virtual void visitQuestNames (bool active_only, boost::function visitor) const = 0; + /// walks the active and optionally completed, quests providing the name and completed status + virtual void visitQuestNames (bool active_only, boost::function visitor) const = 0; /// walks over the journal entries related to all quests with the given name /// If \a questName is empty, simply visits all journal entries diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index d7e27a277..4cfcc8064 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -7,6 +7,7 @@ #include #include +#include #include #include @@ -428,11 +429,24 @@ namespace AddNamesToList(Gui::MWList* list) : mList(list) {} Gui::MWList* mList; - void operator () (const std::string& name) + void operator () (const std::string& name, bool finished=false) { mList->addItem(name); } }; + struct SetNamesInactive + { + SetNamesInactive(Gui::MWList* list) : mList(list) {} + + Gui::MWList* mList; + void operator () (const std::string& name, bool finished) + { + if (finished) + { + mList->getItemWidget(name)->setStateSelected(true); + } + } + }; void notifyQuests(MyGUI::Widget* _sender) { @@ -453,6 +467,12 @@ namespace mModel->visitQuestNames(!mAllQuests, add); list->adjustSize(); + + if (mAllQuests) + { + SetNamesInactive setInactive(list); + mModel->visitQuestNames(!mAllQuests, setInactive); + } } void notifyShowAll(MyGUI::Widget* _sender) diff --git a/components/widgets/list.cpp b/components/widgets/list.cpp index 28271e87d..f3d3a2c28 100644 --- a/components/widgets/list.cpp +++ b/components/widgets/list.cpp @@ -152,9 +152,9 @@ namespace Gui eventWidgetSelected(_sender); } - MyGUI::Widget* MWList::getItemWidget(const std::string& name) + MyGUI::Button *MWList::getItemWidget(const std::string& name) { - return mScrollView->findWidget (getName() + "_item_" + name); + return mScrollView->findWidget (getName() + "_item_" + name)->castType(); } } diff --git a/components/widgets/list.hpp b/components/widgets/list.hpp index 093cd8c18..72c8a733c 100644 --- a/components/widgets/list.hpp +++ b/components/widgets/list.hpp @@ -43,7 +43,7 @@ namespace Gui std::string getItemNameAt(unsigned int at); ///< \attention if there are separators, this method will return "" at the place where the separator is void clear(); - MyGUI::Widget* getItemWidget(const std::string& name); + MyGUI::Button* getItemWidget(const std::string& name); ///< get widget for an item name, useful to set up tooltip virtual void setPropertyOverride(const std::string& _key, const std::string& _value); diff --git a/files/mygui/openmw_journal.skin.xml b/files/mygui/openmw_journal.skin.xml index 942c9a4d4..42be2bb62 100644 --- a/files/mygui/openmw_journal.skin.xml +++ b/files/mygui/openmw_journal.skin.xml @@ -28,9 +28,9 @@ - - - + + +
From 8b417c06db7fcfd0c44e88a07b5e4f2b2ea4c868 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 13 Feb 2015 17:26:33 +0100 Subject: [PATCH 0563/3725] Fix missing clear in ESM::Spell::load (Fixes #2368) --- components/esm/loadspel.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/components/esm/loadspel.cpp b/components/esm/loadspel.cpp index cd630d6ab..96c048e0a 100644 --- a/components/esm/loadspel.cpp +++ b/components/esm/loadspel.cpp @@ -10,6 +10,7 @@ namespace ESM void Spell::load(ESMReader &esm) { + mEffects.mList.clear(); bool hasData = false; while (esm.hasMoreSubs()) { From 96a295c44f33926756d6bff35cc7982919561cc6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 13 Feb 2015 17:37:56 +0100 Subject: [PATCH 0564/3725] Fix for deleting all items in a levelled list --- components/esm/loadlevlist.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/components/esm/loadlevlist.cpp b/components/esm/loadlevlist.cpp index 6080d1e1a..ca5c5d74d 100644 --- a/components/esm/loadlevlist.cpp +++ b/components/esm/loadlevlist.cpp @@ -21,6 +21,7 @@ namespace ESM else { // Original engine ignores rest of the record, even if there are items following + mList.clear(); esm.skipRecord(); return; } From 74232b90fcf928ad6f07a92886245bf6937f07b2 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 13 Feb 2015 18:26:36 +0100 Subject: [PATCH 0565/3725] updated credits file --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index 59aa42721..540c0ede5 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -78,6 +78,7 @@ Programmers naclander Narmo Nathan Jeffords (blunted2night) + NeveHanter Nikolay Kasyanov (corristo) nobrakal Nolan Poe (nopoe) From a1ee26922e2aca1c975e9095de93f56a10d9e6ce Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 14 Feb 2015 12:00:16 +0100 Subject: [PATCH 0566/3725] ESSImport: note location of corpse clear countdown --- apps/essimporter/importacdt.hpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/apps/essimporter/importacdt.hpp b/apps/essimporter/importacdt.hpp index 47055092d..eacb2edf1 100644 --- a/apps/essimporter/importacdt.hpp +++ b/apps/essimporter/importacdt.hpp @@ -43,13 +43,17 @@ namespace ESSImport float mMagicEffects[27]; // Effect attributes: https://wiki.openmw.org/index.php?title=Research:Magic#Effect_attributes unsigned char mUnknown4[4]; unsigned int mGoldPool; - unsigned char mUnknown5[4]; + unsigned char mCountDown; // seen the same value as in ACSC.mCorpseClearCountdown, maybe + // this one is for respawning? + unsigned char mUnknown5[3]; }; struct ACSC { unsigned char mUnknown1[17]; unsigned char mFlags; // ACSCFlags - unsigned char mUnknown2[94]; + unsigned char mUnknown2[22]; + unsigned char mCorpseClearCountdown; // hours? + unsigned char mUnknown3[71]; }; #pragma pack(pop) From 0e88fb3dca206ce61d938db7d70f96bfb26b1a2d Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 14 Feb 2015 12:25:52 +0100 Subject: [PATCH 0567/3725] ESSImport: read AiPackages --- apps/essimporter/importcrec.cpp | 4 ++-- apps/essimporter/importcrec.hpp | 2 ++ apps/essimporter/importnpcc.cpp | 3 +-- apps/essimporter/importnpcc.hpp | 1 + 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/apps/essimporter/importcrec.cpp b/apps/essimporter/importcrec.cpp index 7a8a3eb00..64879f2af 100644 --- a/apps/essimporter/importcrec.cpp +++ b/apps/essimporter/importcrec.cpp @@ -14,10 +14,10 @@ namespace ESSImport float scale; esm.getHNOT(scale, "XSCL"); - // FIXME: use AiPackageList, need to fix getSubName() + while (esm.isNextSub("AI_W") || esm.isNextSub("AI_E") || esm.isNextSub("AI_T") || esm.isNextSub("AI_F") || esm.isNextSub("AI_A")) - esm.skipHSub(); + mAiPackages.add(esm); mInventory.load(esm); } diff --git a/apps/essimporter/importcrec.hpp b/apps/essimporter/importcrec.hpp index 16b752807..5110fbc68 100644 --- a/apps/essimporter/importcrec.hpp +++ b/apps/essimporter/importcrec.hpp @@ -2,6 +2,7 @@ #define OPENMW_ESSIMPORT_CREC_H #include "importinventory.hpp" +#include namespace ESM { @@ -17,6 +18,7 @@ namespace ESSImport int mIndex; Inventory mInventory; + ESM::AIPackageList mAiPackages; void load(ESM::ESMReader& esm); }; diff --git a/apps/essimporter/importnpcc.cpp b/apps/essimporter/importnpcc.cpp index 547b01441..3cbd749ce 100644 --- a/apps/essimporter/importnpcc.cpp +++ b/apps/essimporter/importnpcc.cpp @@ -9,10 +9,9 @@ namespace ESSImport { esm.getHNT(mNPDT, "NPDT"); - // FIXME: use AiPackageList, need to fix getSubName() while (esm.isNextSub("AI_W") || esm.isNextSub("AI_E") || esm.isNextSub("AI_T") || esm.isNextSub("AI_F") || esm.isNextSub("AI_A")) - esm.skipHSub(); + mAiPackages.add(esm); mInventory.load(esm); } diff --git a/apps/essimporter/importnpcc.hpp b/apps/essimporter/importnpcc.hpp index c69fa3e03..a23ab1e50 100644 --- a/apps/essimporter/importnpcc.hpp +++ b/apps/essimporter/importnpcc.hpp @@ -27,6 +27,7 @@ namespace ESSImport } mNPDT; Inventory mInventory; + ESM::AIPackageList mAiPackages; void load(ESM::ESMReader &esm); }; From 93ffdb427c3d4faafb59f0317a112baba680fada Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 14 Feb 2015 15:53:01 +0100 Subject: [PATCH 0568/3725] Small tweak to ripples --- apps/openmw/mwrender/ripplesimulation.cpp | 1 - files/materials/ripples.particle | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwrender/ripplesimulation.cpp b/apps/openmw/mwrender/ripplesimulation.cpp index 84794162f..dcafcb79f 100644 --- a/apps/openmw/mwrender/ripplesimulation.cpp +++ b/apps/openmw/mwrender/ripplesimulation.cpp @@ -113,7 +113,6 @@ void RippleSimulation::update(float dt, Ogre::Vector2 position) position.z = 0; // Z is set by the Scene Node rotSpeed = mRippleRotSpeed; rotation = Ogre::Radian(Ogre::Math::RangeRandom(-Ogre::Math::PI, Ogre::Math::PI)); - created->setDimensions(50,50); } } diff --git a/files/materials/ripples.particle b/files/materials/ripples.particle index e8402b691..58045f6d7 100644 --- a/files/materials/ripples.particle +++ b/files/materials/ripples.particle @@ -1,8 +1,8 @@ particle_system openmw/Ripples { material openmw/Ripple - particle_width 50 - particle_height 50 + particle_width 30 + particle_height 30 // To make the particles move with the scene node when the waterlevel changes local_space true quota 300 @@ -17,7 +17,7 @@ particle_system openmw/Ripples affector Scaler { - rate 100 + rate 120 } affector Rotator From 37a85e31d6681141e341bb62fc072328c35e1a2c Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 14 Feb 2015 16:51:47 +0100 Subject: [PATCH 0569/3725] Ripples fix --- apps/openmw/mwrender/ripplesimulation.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwrender/ripplesimulation.cpp b/apps/openmw/mwrender/ripplesimulation.cpp index dcafcb79f..bb1bccc0a 100644 --- a/apps/openmw/mwrender/ripplesimulation.cpp +++ b/apps/openmw/mwrender/ripplesimulation.cpp @@ -113,6 +113,7 @@ void RippleSimulation::update(float dt, Ogre::Vector2 position) position.z = 0; // Z is set by the Scene Node rotSpeed = mRippleRotSpeed; rotation = Ogre::Radian(Ogre::Math::RangeRandom(-Ogre::Math::PI, Ogre::Math::PI)); + created->setDimensions(mParticleSystem->getDefaultWidth(), mParticleSystem->getDefaultHeight()); } } From 81925645a34b4591d6be7ccf0b8ce13d6efa536b Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 14 Feb 2015 16:51:54 +0100 Subject: [PATCH 0570/3725] Unreachable enemies combat AI fix (Fixes #2271) --- apps/openmw/mwmechanics/aicombat.cpp | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index f2b125add..fd4fd293d 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -207,16 +207,6 @@ namespace MWMechanics const MWWorld::Class& actorClass = actor.getClass(); MWBase::World* world = MWBase::Environment::get().getWorld(); - // can't fight if attacker can't go where target is. E.g. A fish can't attack person on land. - if (!actorClass.isNpc() && !MWMechanics::isEnvironmentCompatible(actor, target)) - { - actorClass.getCreatureStats(actor).setAttackingOrSpell(false); - return true; - } - - - - //Update every frame bool& combatMove = storage.mCombatMove; @@ -476,6 +466,19 @@ namespace MWMechanics // for distant combat we should know if target is in LOS even if distToTarget < rangeAttack bool inLOS = distantCombat ? world->getLOS(actor, target) : true; + // can't fight if attacker can't go where target is. E.g. A fish can't attack person on land. + if (distToTarget >= rangeAttack + && !actorClass.isNpc() && !MWMechanics::isEnvironmentCompatible(actor, target)) + { + // TODO: start fleeing? + movement.mPosition[0] = 0; + movement.mPosition[1] = 0; + movement.mPosition[2] = 0; + readyToAttack = false; + actorClass.getCreatureStats(actor).setAttackingOrSpell(false); + return false; + } + // (within attack dist) || (not quite attack dist while following) if(inLOS && (distToTarget < rangeAttack || (distToTarget <= rangeFollow && followTarget && !isStuck))) { From 5ef78903dc28554ad58784ac13f9aba1a135c5ad Mon Sep 17 00:00:00 2001 From: Jordan Ayers Date: Sat, 14 Feb 2015 15:43:09 -0600 Subject: [PATCH 0571/3725] Teleportation: Support markers in Mournhold. OMW Bug #1533 Note: the 'stolen goods' search is not yet correct for Mournhald. --- apps/openmw/mwworld/worldimp.cpp | 104 +++++++++++++++++++++++++------ apps/openmw/mwworld/worldimp.hpp | 2 + 2 files changed, 87 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 23cef1596..fda73238a 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2830,33 +2830,99 @@ namespace MWWorld return false; } - void World::teleportToClosestMarker (const MWWorld::Ptr& ptr, - const std::string& id) + MWWorld::Ptr World::getClosestMarker( const MWWorld::Ptr &ptr, const std::string &id ) { - Ogre::Vector3 worldPos; - if (!findInteriorPositionInWorldSpace(ptr.getCell(), worldPos)) - worldPos = mPlayer->getLastKnownExteriorPosition(); + // Search for a 'nearest' marker, counting each cell between the starting + // cell and the exterior as a distance of 1. If an exterior is found, jump + // to the nearest exterior marker, without further interior searching. + std::set< std::string >checkedCells; + std::set< std::string >currentCells; + std::set< std::string >nextCells; + nextCells.insert( ptr.getCell()->getCell()->mName ); + while ( !nextCells.empty() ) { + currentCells = nextCells; + nextCells.clear(); + for( std::set< std::string >::const_iterator i = currentCells.begin(); i != currentCells.end(); ++i ) { + MWWorld::CellStore *next = getInterior( *i ); + checkedCells.insert( *i ); + if ( !next ) continue; - MWWorld::Ptr closestMarker; - float closestDistance = FLT_MAX; + MWWorld::CellRefList& statics = next->get(); + CellRefList::List& staticList = statics.mList; + for (CellRefList::List::iterator it = staticList.begin(); it != staticList.end(); ++it) + { + MWWorld::LiveCellRef& ref = *it; + if ( id == ref.mRef.getRefId() ) { + return MWWorld::Ptr( &ref, next ); + } + } - std::vector markers; - mCells.getExteriorPtrs(id, markers); + MWWorld::CellRefList& doors = next->get(); + CellRefList::List& doorList = doors.mList; - for (std::vector::iterator it = markers.begin(); it != markers.end(); ++it) - { - ESM::Position pos = it->getRefData().getPosition(); - Ogre::Vector3 markerPos = Ogre::Vector3(pos.pos); - float distance = worldPos.squaredDistance(markerPos); - if (distance < closestDistance) - { - closestDistance = distance; - closestMarker = *it; + // Check if any door in the cell leads to an exterior directly + for (CellRefList::List::iterator it = doorList.begin(); it != doorList.end(); ++it) + { + MWWorld::LiveCellRef& ref = *it; + + if ( id == ref.mRef.getRefId() ) { + return MWWorld::Ptr( &ref, next ); + } + + if (!ref.mRef.getTeleport()) continue; + + if (ref.mRef.getDestCell().empty()) + { + Ogre::Vector3 worldPos = Ogre::Vector3(ref.mRef.getDoorDest().pos); + float closestDistance = FLT_MAX; + + MWWorld::Ptr closestMarker; + std::vector markers; + mCells.getExteriorPtrs(id, markers); + for (std::vector::iterator it2 = markers.begin(); it2 != markers.end(); ++it2) + { + ESM::Position pos = it2->getRefData().getPosition(); + Ogre::Vector3 markerPos = Ogre::Vector3(pos.pos); + float distance = worldPos.squaredDistance(markerPos); + if (distance < closestDistance) + { + closestDistance = distance; + closestMarker = *it2; + } + + } + + return closestMarker; + } + else + { + std::string dest = ref.mRef.getDestCell(); + if ( !checkedCells.count(dest) && !currentCells.count(dest) ) + nextCells.insert(dest); + } + } } + } + return MWWorld::Ptr(); + } + + void World::teleportToClosestMarker (const MWWorld::Ptr& ptr, + const std::string& id) + { + MWWorld::Ptr closestMarker = getClosestMarker( ptr, id ); + + if ( closestMarker.isEmpty() ) + { + std::cerr << "Failed to teleport: no closest marker found" << std::endl; + return; } - MWWorld::ActionTeleport action("", closestMarker.getRefData().getPosition()); + std::string cellName; + if ( !closestMarker.mCell->isExterior() ) + cellName = closestMarker.mCell->getCell()->mName; + + MWWorld::ActionTeleport action(cellName, closestMarker.getRefData().getPosition()); action.execute(ptr); } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 9980f6f90..7a3505fd4 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -151,6 +151,8 @@ namespace MWWorld float feetToGameUnits(float feet); + MWWorld::Ptr getClosestMarker( const MWWorld::Ptr &ptr, const std::string &id ); + public: World (OEngine::Render::OgreRenderer& renderer, From 6d1aec6970ef753e08e687c06eb80cdfd403cc9a Mon Sep 17 00:00:00 2001 From: Jordan Ayers Date: Sat, 14 Feb 2015 16:09:17 -0600 Subject: [PATCH 0572/3725] Confiscate stolen goods: Support Mournhold prisons. OMW Bug #1533 --- apps/openmw/mwworld/worldimp.cpp | 37 ++++++++++++++++---------------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index fda73238a..54385cf83 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -3071,28 +3071,29 @@ namespace MWWorld void World::confiscateStolenItems(const Ptr &ptr) { - Ogre::Vector3 playerPos; - if (!findInteriorPositionInWorldSpace(ptr.getCell(), playerPos)) - playerPos = mPlayer->getLastKnownExteriorPosition(); + MWWorld::Ptr prisonMarker = getClosestMarker( ptr, "prisonmarker" ); + std::string prisonName = prisonMarker.mRef->mRef.getDestCell(); + if ( prisonName.empty() ) + { + std::cerr << "Failed to confiscate items: prison marker not linked to prison interior" << std::endl; + return; + } + MWWorld::CellStore *prison = getInterior( prisonName ); + if ( !prison ) + { + std::cerr << "Failed to confiscate items: failed to load cell " << prisonName << std::endl; + return; + } MWWorld::Ptr closestChest; - float closestDistance = FLT_MAX; - - //Find closest stolen_goods chest - std::vector chests; - mCells.getInteriorPtrs("stolen_goods", chests); - Ogre::Vector3 chestPos; - for (std::vector::iterator it = chests.begin(); it != chests.end(); ++it) + MWWorld::CellRefList& containers = prison->get(); + CellRefList::List& refList = containers.mList; + for (CellRefList::List::iterator it = refList.begin(); it != refList.end(); ++it) { - if (!findInteriorPositionInWorldSpace(it->getCell(), chestPos)) - continue; - - float distance = playerPos.squaredDistance(chestPos); - if (distance < closestDistance) - { - closestDistance = distance; - closestChest = *it; + MWWorld::LiveCellRef& ref = *it; + if ( ref.mRef.getRefId() == "stolen_goods" ) { + closestChest = MWWorld::Ptr( &ref, prison ); } } From a61019dfa804fc2d1a6d54ec7e6600cacda22116 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Sun, 15 Feb 2015 04:47:25 +0100 Subject: [PATCH 0573/3725] Update referencecheck.cpp MSVC does not allow for the usage of 'and' or 'or' literals --- apps/opencs/model/tools/referencecheck.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/tools/referencecheck.cpp b/apps/opencs/model/tools/referencecheck.cpp index aae83bd5e..0c1d7d38f 100644 --- a/apps/opencs/model/tools/referencecheck.cpp +++ b/apps/opencs/model/tools/referencecheck.cpp @@ -53,7 +53,7 @@ void CSMTools::ReferenceCheckStage::perform(int stage, CSMDoc::Messages &message messages.push_back(std::make_pair(id, " is referencing object from non existing cell " + cellRef.mCell)); // If object have owner, check if that owner reference is valid - if (!cellRef.mOwner.empty() and mReferencables.searchId(cellRef.mOwner) == -1) + if (!cellRef.mOwner.empty() && mReferencables.searchId(cellRef.mOwner) == -1) messages.push_back(std::make_pair(id, " has non existing owner " + cellRef.mOwner)); // If object have creature soul trapped, check if that creature reference is valid @@ -107,4 +107,4 @@ void CSMTools::ReferenceCheckStage::perform(int stage, CSMDoc::Messages &message int CSMTools::ReferenceCheckStage::setup() { return mReferences.getSize(); -} \ No newline at end of file +} From f1fd27aeaf2585348b46b526e0267fb36443e8f3 Mon Sep 17 00:00:00 2001 From: slothlife Date: Sat, 14 Feb 2015 23:34:43 -0600 Subject: [PATCH 0574/3725] Select CMAKE_BUILD_TYPE if not specified A suggestion by kcat to ensure CMake selects a reasonable default for the build type if users don't set it themselves. --- CMakeLists.txt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 37f8552cd..c8682dace 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,12 @@ project(OpenMW) +# If the user doesn't supply a CMAKE_BUILD_TYPE via command line, choose one for them. +IF(NOT CMAKE_BUILD_TYPE) + SET(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING + "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." + FORCE) +ENDIF() + if (APPLE) set(APP_BUNDLE_NAME "${CMAKE_PROJECT_NAME}.app") From 0e955124003b29f1fc201cc946bdf4763d13cb9f Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Sun, 15 Feb 2015 16:02:49 +0200 Subject: [PATCH 0575/3725] CI: fix `make package` condition by adding missing spaces --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 042d4b8f1..1be8aa59c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -31,7 +31,7 @@ before_script: script: - cd ./build - if [ "$COVERITY_SCAN_BRANCH" != 1 ]; then make -j4; fi - - if [ "$COVERITY_SCAN_BRANCH" != 1 ] && ["${TRAVIS_OS_NAME}" = "osx"]; then make package; fi + - if [ "$COVERITY_SCAN_BRANCH" != 1 ] && [ "${TRAVIS_OS_NAME}" = "osx" ]; then make package; fi after_script: - if [ "${TRAVIS_OS_NAME}" = "linux" ]; then ./openmw_test_suite; fi notifications: From a9b74671a6c7a8aea6f575313e9696886c2b3574 Mon Sep 17 00:00:00 2001 From: slothlife Date: Sun, 15 Feb 2015 20:10:21 -0600 Subject: [PATCH 0576/3725] Fix various MSVC warnings --- CMakeLists.txt | 13 ++++++++++--- apps/openmw/mwmechanics/magiceffects.hpp | 2 ++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2a117d42d..0c3d7c378 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -672,6 +672,7 @@ if (WIN32) 4193 # #pragma warning(pop) : no matching '#pragma warning(push)' 4251 # class 'XXXX' needs to have dll-interface to be used by clients of class 'YYYY' 4275 # non dll-interface struct 'XXXX' used as base for dll-interface class 'YYYY' + 4315 # undocumented, 'this' pointer for member might not be aligned (OgreMemoryStlAllocator.h) # caused by boost 4191 # 'type cast' : unsafe conversion (1.56, thread_primitives.hpp, normally off) @@ -679,6 +680,7 @@ if (WIN32) # OpenMW specific warnings 4099 # Type mismatch, declared class or struct is defined with other type 4100 # Unreferenced formal parameter (-Wunused-parameter) + 4101 # Unreferenced local variable (-Wunused-variable) 4127 # Conditional expression is constant 4242 # Storing value in a variable of a smaller type, possible loss of data 4244 # Storing value of one type in variable of another (size_t in int, for example) @@ -700,14 +702,16 @@ if (WIN32) # boost::wave has a few issues with signed / unsigned conversions, so we suppress those here set(SHINY_WARNINGS "${WARNINGS} /wd4245") set_target_properties(shiny PROPERTIES COMPILE_FLAGS "${SHINY_WARNINGS} ${MT_BUILD}") - # there's an unreferenced local variable in the ogre platform, suppress it - set(SHINY_OGRE_WARNINGS "${WARNINGS} /wd4101") - set_target_properties(shiny.OgrePlatform PROPERTIES COMPILE_FLAGS "${SHINY_OGRE_WARNINGS} ${MT_BUILD}") + set_target_properties(shiny.OgrePlatform PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") set_target_properties(sdl4ogre PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") # oics uses tinyxml, which has an initialized but unused variable set(OICS_WARNINGS "${WARNINGS} /wd4189") set_target_properties(oics PROPERTIES COMPILE_FLAGS "${OICS_WARNINGS} ${MT_BUILD}") set_target_properties(components PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") + set_target_properties(ogre-ffmpeg-videoplayer PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") + if (BUILD_MYGUI_PLUGIN) + set_target_properties(Plugin_MyGUI_OpenMW_Resources PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") + endif (BUILD_MYGUI_PLUGIN) if (BUILD_LAUNCHER) set_target_properties(openmw-launcher PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") endif (BUILD_LAUNCHER) @@ -726,6 +730,9 @@ if (WIN32) set(OPENCS_WARNINGS "${WARNINGS} ${MT_BUILD} /wd4435") set_target_properties(openmw-cs PROPERTIES COMPILE_FLAGS ${OPENCS_WARNINGS}) endif (BUILD_OPENCS) + if (BUILD_ESSIMPORTER) + set_target_properties(openmw-essimporter PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") + endif (BUILD_ESSIMPORTER) if (BUILD_MWINIIMPORTER) set_target_properties(openmw-iniimporter PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") endif (BUILD_MWINIIMPORTER) diff --git a/apps/openmw/mwmechanics/magiceffects.hpp b/apps/openmw/mwmechanics/magiceffects.hpp index c384d0857..86f5a1804 100644 --- a/apps/openmw/mwmechanics/magiceffects.hpp +++ b/apps/openmw/mwmechanics/magiceffects.hpp @@ -72,6 +72,8 @@ namespace MWMechanics // Used by effect management classes (ActiveSpells, InventoryStore, Spells) to list active effect sources for GUI display struct EffectSourceVisitor { + virtual ~EffectSourceVisitor() { } + virtual void visit (MWMechanics::EffectKey key, const std::string& sourceName, const std::string& sourceId, int casterActorId, float magnitude, float remainingTime = -1, float totalTime = -1) = 0; From e5c1c316480c3d5f7daa1ca3010004a7a21a37ef Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 16 Feb 2015 14:27:25 +1100 Subject: [PATCH 0577/3725] Ignore case when detecting legacy extensions (.esm or .exp). Should resolve bug #2227. --- apps/opencs/view/doc/adjusterwidget.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/doc/adjusterwidget.cpp b/apps/opencs/view/doc/adjusterwidget.cpp index 09e58690f..6571ad7c8 100644 --- a/apps/opencs/view/doc/adjusterwidget.cpp +++ b/apps/opencs/view/doc/adjusterwidget.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include @@ -72,8 +73,11 @@ void CSVDoc::AdjusterWidget::setName (const QString& name, bool addon) { boost::filesystem::path path (name.toUtf8().data()); - bool isLegacyPath = (path.extension() == ".esm" || - path.extension() == ".esp"); + std::string extension = path.extension().string(); + boost::algorithm::to_lower(extension); + + bool isLegacyPath = (extension == ".esm" || + extension == ".esp"); bool isFilePathChanged = (path.parent_path().string() != mLocalData.string()); From efdee1947765bb796bda5182e6cd193c03d90377 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 16 Feb 2015 16:41:53 +1100 Subject: [PATCH 0578/3725] Suppress warning about the lack of virtual destructor. --- apps/openmw/mwmechanics/summoning.cpp | 4 ++++ apps/openmw/mwmechanics/summoning.hpp | 1 + 2 files changed, 5 insertions(+) diff --git a/apps/openmw/mwmechanics/summoning.cpp b/apps/openmw/mwmechanics/summoning.cpp index ec9bd0ea0..668031141 100644 --- a/apps/openmw/mwmechanics/summoning.cpp +++ b/apps/openmw/mwmechanics/summoning.cpp @@ -51,6 +51,10 @@ namespace MWMechanics } + UpdateSummonedCreatures::~UpdateSummonedCreatures() + { + } + void UpdateSummonedCreatures::visit(EffectKey key, const std::string &sourceName, const std::string &sourceId, int casterActorId, float magnitude, float remainingTime, float totalTime) { if (isSummoningEffect(key.mId) && magnitude > 0) diff --git a/apps/openmw/mwmechanics/summoning.hpp b/apps/openmw/mwmechanics/summoning.hpp index b8fe37783..8e418cdeb 100644 --- a/apps/openmw/mwmechanics/summoning.hpp +++ b/apps/openmw/mwmechanics/summoning.hpp @@ -14,6 +14,7 @@ namespace MWMechanics struct UpdateSummonedCreatures : public EffectSourceVisitor { UpdateSummonedCreatures(const MWWorld::Ptr& actor); + virtual ~UpdateSummonedCreatures(); virtual void visit (MWMechanics::EffectKey key, const std::string& sourceName, const std::string& sourceId, int casterActorId, From 8d7de7d1ece744356fee88f7e8613089725fcd67 Mon Sep 17 00:00:00 2001 From: dteviot Date: Tue, 17 Feb 2015 22:14:25 +1300 Subject: [PATCH 0579/3725] Telekinesis allows safe opening of traps (Fixes #1916) When trap activated at beyond normal activation distance, assume telekinesis used and detonate trap at trapped object's location. Also some minor code refactoring of spellcasting. 1. Corrected parameter passed to explodeSpell(). 2. For loop now correctly does an early exit. 3. Removed duplicated tests. --- apps/openmw/mwbase/world.hpp | 4 +++- apps/openmw/mwmechanics/spellcasting.cpp | 16 ++++++------- apps/openmw/mwworld/actiontrap.cpp | 29 +++++++++++++++++++++--- apps/openmw/mwworld/worldimp.cpp | 4 ++-- apps/openmw/mwworld/worldimp.hpp | 2 +- 5 files changed, 39 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index f58ef0809..f71975433 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -269,6 +269,8 @@ namespace MWBase virtual MWWorld::Ptr getFacedObject() = 0; ///< Return pointer to the object the player is looking at, if it is within activation range + virtual float getMaxActivationDistance() = 0; + /// Returns a pointer to the object the provided object would hit (if within the /// specified distance), and the point where the hit occurs. This will attempt to /// use the "Head" node, or alternatively the "Bip01 Head" node as a basis. @@ -548,7 +550,7 @@ namespace MWBase virtual void spawnEffect (const std::string& model, const std::string& textureOverride, const Ogre::Vector3& worldPos) = 0; virtual void explodeSpell (const Ogre::Vector3& origin, const ESM::EffectList& effects, - const MWWorld::Ptr& caster, int rangeType, const std::string& id, const std::string& sourceName) = 0; + const MWWorld::Ptr& caster, ESM::RangeType rangeType, const std::string& id, const std::string& sourceName) = 0; virtual void activate (const MWWorld::Ptr& object, const MWWorld::Ptr& actor) = 0; diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 49887e560..4ce3fcaf5 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -309,9 +309,11 @@ namespace MWMechanics for (std::vector::const_iterator iter (effects.mList.begin()); iter!=effects.mList.end(); ++iter) { - if (iter->mRange != range) - continue; - found = true; + if (iter->mRange == range) + { + found = true; + break; + } } if (!found) return; @@ -766,8 +768,7 @@ namespace MWMechanics if (!mTarget.isEmpty()) { - if (!mTarget.getClass().isActor() || !mTarget.getClass().getCreatureStats(mTarget).isDead()) - inflict(mTarget, mCaster, enchantment->mEffects, ESM::RT_Touch); + inflict(mTarget, mCaster, enchantment->mEffects, ESM::RT_Touch); } std::string projectileModel; @@ -851,10 +852,7 @@ namespace MWMechanics if (!mTarget.isEmpty()) { - if (!mTarget.getClass().isActor() || !mTarget.getClass().getCreatureStats(mTarget).isDead()) - { - inflict(mTarget, mCaster, spell->mEffects, ESM::RT_Touch); - } + inflict(mTarget, mCaster, spell->mEffects, ESM::RT_Touch); } diff --git a/apps/openmw/mwworld/actiontrap.cpp b/apps/openmw/mwworld/actiontrap.cpp index 1472afc08..d153b7e61 100644 --- a/apps/openmw/mwworld/actiontrap.cpp +++ b/apps/openmw/mwworld/actiontrap.cpp @@ -1,16 +1,39 @@ #include "actiontrap.hpp" #include "../mwmechanics/spellcasting.hpp" +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" namespace MWWorld { void ActionTrap::executeImp(const Ptr &actor) { - MWMechanics::CastSpell cast(mTrapSource, actor); - cast.mHitPosition = Ogre::Vector3(actor.getRefData().getPosition().pos); - cast.cast(mSpellId); + Ogre::Vector3 actorPosition(actor.getRefData().getPosition().pos); + Ogre::Vector3 trapPosition(mTrapSource.getRefData().getPosition().pos); + float activationDistance = MWBase::Environment::get().getWorld()->getMaxActivationDistance(); + // GUI calcs if object in activation distance include object and player geometry + const float fudgeFactor = 1.25f; + + // Hack: if actor is beyond activation range, then assume actor is using telekinesis + // to open door/container. + // Note, can't just detonate the trap at the trapped object's location and use the blast + // radius, because for most trap spells this is 1 foot, much less than the activation distance. + if (trapPosition.distance(actorPosition) < (activationDistance * fudgeFactor)) + { + // assume actor touched trap + MWMechanics::CastSpell cast(mTrapSource, actor); + cast.mHitPosition = actorPosition; + cast.cast(mSpellId); + } + else + { + // assume telekinesis used + MWMechanics::CastSpell cast(mTrapSource, mTrapSource); + cast.mHitPosition = trapPosition; + cast.cast(mSpellId); + } mTrapSource.getCellRef().setTrap(""); } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 8bcfcb421..333f172b9 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -3128,7 +3128,7 @@ namespace MWWorld mRendering->spawnEffect(model, textureOverride, worldPos); } - void World::explodeSpell(const Vector3 &origin, const ESM::EffectList &effects, const Ptr &caster, int rangeType, + void World::explodeSpell(const Vector3 &origin, const ESM::EffectList &effects, const Ptr &caster, ESM::RangeType rangeType, const std::string& id, const std::string& sourceName) { std::map > toApply; @@ -3187,7 +3187,7 @@ namespace MWWorld cast.mStack = false; ESM::EffectList effects; effects.mList = apply->second; - cast.inflict(apply->first, caster, effects, (ESM::RangeType)rangeType, false, true); + cast.inflict(apply->first, caster, effects, rangeType, false, true); } } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 9834015ac..84da984f8 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -627,7 +627,7 @@ namespace MWWorld virtual void spawnEffect (const std::string& model, const std::string& textureOverride, const Ogre::Vector3& worldPos); virtual void explodeSpell (const Ogre::Vector3& origin, const ESM::EffectList& effects, - const MWWorld::Ptr& caster, int rangeType, const std::string& id, const std::string& sourceName); + const MWWorld::Ptr& caster, ESM::RangeType rangeType, const std::string& id, const std::string& sourceName); virtual void activate (const MWWorld::Ptr& object, const MWWorld::Ptr& actor); From 6e2d6a028200df830b2ca90c95987f873e7c5199 Mon Sep 17 00:00:00 2001 From: dteviot Date: Tue, 17 Feb 2015 22:51:30 +1300 Subject: [PATCH 0580/3725] Minor correction, MWWorld::getMaxActivationDistance() is now public. --- apps/openmw/mwworld/worldimp.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 84da984f8..1636980cb 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -114,7 +114,6 @@ namespace MWWorld void performUpdateSceneQueries (); void getFacedHandle(std::string& facedHandle, float maxDistance, bool ignorePlayer=true); - float getMaxActivationDistance (); float getNpcActivationDistance (); float getObjectActivationDistance (); @@ -361,6 +360,8 @@ namespace MWWorld virtual MWWorld::Ptr safePlaceObject(const MWWorld::Ptr& ptr, MWWorld::CellStore* cell, ESM::Position pos); ///< place an object in a "safe" location (ie not in the void, etc). Makes a copy of the Ptr. + virtual float getMaxActivationDistance(); + virtual void indexToPosition (int cellX, int cellY, float &x, float &y, bool centre = false) const; ///< Convert cell numbers to position. From 5a3d796578fe944fe82cf71640484636701ce8ec Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 17 Feb 2015 12:26:28 +0100 Subject: [PATCH 0581/3725] Implement std::istream subclass for constrained file streams --- components/files/constrainedfilestream.cpp | 107 +++++++++++++++++++++ components/files/constrainedfilestream.hpp | 20 ++++ 2 files changed, 127 insertions(+) create mode 100644 components/files/constrainedfilestream.cpp create mode 100644 components/files/constrainedfilestream.hpp diff --git a/components/files/constrainedfilestream.cpp b/components/files/constrainedfilestream.cpp new file mode 100644 index 000000000..404fddfcb --- /dev/null +++ b/components/files/constrainedfilestream.cpp @@ -0,0 +1,107 @@ +#include "constrainedfilestream.hpp" + +#include + +#include "lowlevelfile.hpp" + +namespace Files +{ + + class ConstrainedFileStreamBuf : public std::streambuf + { + // somewhat arbitrary though 64KB buffers didn't seem to improve performance any + static const size_t sBufferSize = 4096; + + size_t mOrigin; + size_t mSize; + + LowLevelFile mFile; + + char mBuffer[sBufferSize]; + + public: + ConstrainedFileStreamBuf(const std::string &fname, size_t start, size_t length) + { + mFile.open (fname.c_str ()); + mSize = length != 0xFFFFFFFF ? length : mFile.size () - start; + + if (start != 0) + mFile.seek(start); + + mOrigin = start; + } + + virtual int_type underflow() + { + if(gptr() == egptr()) + { + // Read in the next chunk of data, and set the read pointers on success + size_t got = mFile.read(mBuffer, sBufferSize); + // Failure will throw exception in LowLevelFile + /*if(got != -1) */ + setg(&mBuffer[0], &mBuffer[0], mBuffer+got); + } + if(gptr() == egptr()) + return traits_type::eof(); + + return traits_type::to_int_type(*gptr()); + } + + virtual pos_type seekoff(off_type offset, std::ios_base::seekdir whence, std::ios_base::openmode mode) + { + if((mode&std::ios_base::out) || !(mode&std::ios_base::in)) + return traits_type::eof(); + + // new file position, relative to mOrigin + size_t newPos; + switch (whence) + { + case std::ios_base::beg: + newPos = offset; + break; + case std::ios_base::cur: + newPos = (mFile.tell() - mOrigin) + offset; + break; + case std::ios_base::end: + newPos = mSize + offset; + break; + default: + return traits_type::eof(); + } + mFile.seek(mOrigin+newPos); + + // EOF handled by exception in LowLevelFile + + // Clear read pointers so underflow() gets called on the next read attempt. + setg(0, 0, 0); + + return newPos; + } + + virtual pos_type seekpos(pos_type pos, std::ios_base::openmode mode) + { + if((mode&std::ios_base::out) || !(mode&std::ios_base::in)) + return traits_type::eof(); + + if(pos >= (int)mSize) + return traits_type::eof(); + mFile.seek(mOrigin + pos); + + // Clear read pointers so underflow() gets called on the next read attempt. + setg(0, 0, 0); + return pos; + } + + }; + + ConstrainedFileStream::ConstrainedFileStream(const char *filename, size_t start, size_t length) + : std::istream(new ConstrainedFileStreamBuf(filename, start, length)) + { + + } + + ConstrainedFileStream::~ConstrainedFileStream() + { + delete rdbuf(); + } +} diff --git a/components/files/constrainedfilestream.hpp b/components/files/constrainedfilestream.hpp new file mode 100644 index 000000000..10fe223bc --- /dev/null +++ b/components/files/constrainedfilestream.hpp @@ -0,0 +1,20 @@ +#ifndef OPENMW_CONSTRAINEDFILESTREAM_H +#define OPENMW_CONSTRAINEDFILESTREAM_H + +#include + +namespace Files +{ + +/// A file stream constrained to a specific region in the file, specified by the 'start' and 'length' parameters. +class ConstrainedFileStream : public std::istream +{ +public: + ConstrainedFileStream(const char *filename, + size_t start=0, size_t length=0xFFFFFFFF); + virtual ~ConstrainedFileStream(); +}; + +} + +#endif From 1124343e0d80610a41d98a9d83a3073136e67ee3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 17 Feb 2015 16:05:28 +0100 Subject: [PATCH 0582/3725] Add BUILD_OPENMW switch, build will be broken in next commit --- CMakeLists.txt | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2a117d42d..fb5583bb2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -63,6 +63,7 @@ set(CUSTOM_OGRE_PLUGIN_DIR "" CACHE PATH "Specify a custom directory for Ogre pl option(OPENMW_UNITY_BUILD "Use fewer compilation units to speed up compile time" FALSE) # Apps and tools +option(BUILD_OPENMW "build OpenMW" ON) option(BUILD_BSATOOL "build BSA extractor" ON) option(BUILD_ESMTOOL "build ESM inspector" ON) option(BUILD_LAUNCHER "build Launcher" ON) @@ -417,7 +418,9 @@ IF(NOT WIN32 AND NOT APPLE) SET(SYSCONFDIR "${GLOBAL_CONFIG_PATH}/openmw" CACHE PATH "Set config dir") # Install binaries - INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/openmw" DESTINATION "${BINDIR}" ) + IF(BUILD_OPENMW) + INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/openmw" DESTINATION "${BINDIR}" ) + ENDIF(BUILD_OPENMW) IF(BUILD_LAUNCHER) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/openmw-launcher" DESTINATION "${BINDIR}" ) ENDIF(BUILD_LAUNCHER) @@ -586,7 +589,9 @@ if (BUILD_NIFTEST) endif(BUILD_NIFTEST) # Apps and tools -add_subdirectory( apps/openmw ) +if (BUILD_OPENMW) + add_subdirectory( apps/openmw ) +endif() if (BUILD_BSATOOL) add_subdirectory( apps/bsatool ) From d4dff6ed55bacaab82a1633aaf5cf3ddd8805f80 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 17 Feb 2015 16:19:21 +0100 Subject: [PATCH 0583/3725] Port BSAFile to istream, remove OGRE bsa resource system --- CMakeLists.txt | 8 +- components/CMakeLists.txt | 2 +- components/bsa/bsa_archive.cpp | 385 --------------------- components/bsa/bsa_archive.hpp | 40 --- components/bsa/bsa_file.cpp | 7 +- components/bsa/bsa_file.hpp | 4 +- components/bsa/resources.cpp | 53 --- components/bsa/resources.hpp | 16 - components/files/constrainedfilestream.hpp | 10 + 9 files changed, 22 insertions(+), 503 deletions(-) delete mode 100644 components/bsa/bsa_archive.cpp delete mode 100644 components/bsa/bsa_archive.hpp delete mode 100644 components/bsa/resources.cpp delete mode 100644 components/bsa/resources.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index fb5583bb2..a0cf56ab4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -570,10 +570,10 @@ if(WIN32) endif(WIN32) # Extern -add_subdirectory (extern/shiny) -add_subdirectory (extern/ogre-ffmpeg-videoplayer) -add_subdirectory (extern/oics) -add_subdirectory (extern/sdl4ogre) +#add_subdirectory (extern/shiny) +#add_subdirectory (extern/ogre-ffmpeg-videoplayer) +#add_subdirectory (extern/oics) +#add_subdirectory (extern/sdl4ogre) # Components add_subdirectory (components) diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index a49e54dd3..f6b1c8cba 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -79,7 +79,7 @@ IF(NOT WIN32 AND NOT APPLE) ENDIF() add_component_dir (files linuxpath androidpath windowspath macospath fixedpath multidircollection collections configurationmanager - constrainedfiledatastream lowlevelfile + constrainedfiledatastream lowlevelfile constrainedfilestream ) add_component_dir (compiler diff --git a/components/bsa/bsa_archive.cpp b/components/bsa/bsa_archive.cpp deleted file mode 100644 index 4f656f9c4..000000000 --- a/components/bsa/bsa_archive.cpp +++ /dev/null @@ -1,385 +0,0 @@ -/* - OpenMW - The completely unofficial reimplementation of Morrowind - Copyright (C) 2008-2010 Nicolay Korslund - Email: < korslund@gmail.com > - WWW: http://openmw.sourceforge.net/ - - This file (cpp_bsaarchive.cpp) is part of the OpenMW package. - - OpenMW is distributed as free software: you can redistribute it - and/or modify it under the terms of the GNU General Public License - version 3, as published by the Free Software Foundation. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - version 3 along with this program. If not, see - http://www.gnu.org/licenses/ . - - */ - -#include "bsa_archive.hpp" - -#include - -#include -#include -#include -#include -#include -#include "bsa_file.hpp" - -#include "../files/constrainedfiledatastream.hpp" - -using namespace Ogre; - -static bool fsstrict = false; - -static char strict_normalize_char(char ch) -{ - return ch == '\\' ? '/' : ch; -} - -static char nonstrict_normalize_char(char ch) -{ - return ch == '\\' ? '/' : std::tolower(ch,std::locale::classic()); -} - -template -static std::string normalize_path(T1 begin, T2 end) -{ - std::string normalized; - normalized.reserve(std::distance(begin, end)); - char (*normalize_char)(char) = fsstrict ? &strict_normalize_char : &nonstrict_normalize_char; - std::transform(begin, end, std::back_inserter(normalized), normalize_char); - return normalized; -} - -/// An OGRE Archive wrapping a BSAFile archive -class DirArchive: public Ogre::Archive -{ - typedef std::map index; - - index mIndex; - - index::const_iterator lookup_filename (std::string const & filename) const - { - std::string normalized = normalize_path (filename.begin (), filename.end ()); - return mIndex.find (normalized); - } - -public: - - DirArchive(const String& name) - : Archive(name, "Dir") - { - typedef boost::filesystem::recursive_directory_iterator directory_iterator; - - directory_iterator end; - - size_t prefix = name.size (); - - if (name.size () > 0 && name [prefix - 1] != '\\' && name [prefix - 1] != '/') - ++prefix; - - for (directory_iterator i (name); i != end; ++i) - { - if(boost::filesystem::is_directory (*i)) - continue; - - std::string proper = i->path ().string (); - - std::string searchable = normalize_path (proper.begin () + prefix, proper.end ()); - - mIndex.insert (std::make_pair (searchable, proper)); - } - } - - bool isCaseSensitive() const { return fsstrict; } - - // The archive is loaded in the constructor, and never unloaded. - void load() {} - void unload() {} - - DataStreamPtr open(const String& filename, bool readonly = true) const - { - index::const_iterator i = lookup_filename (filename); - - if (i == mIndex.end ()) - { - std::ostringstream os; - os << "The file '" << filename << "' could not be found."; - throw std::runtime_error (os.str ()); - } - - return openConstrainedFileDataStream (i->second.c_str ()); - } - - StringVectorPtr list(bool recursive = true, bool dirs = false) - { - return find ("*", recursive, dirs); - } - - FileInfoListPtr listFileInfo(bool recursive = true, bool dirs = false) - { - return findFileInfo ("*", recursive, dirs); - } - - StringVectorPtr find(const String& pattern, bool recursive = true, - bool dirs = false) - { - std::string normalizedPattern = normalize_path(pattern.begin(), pattern.end()); - StringVectorPtr ptr = StringVectorPtr(new StringVector()); - for(index::const_iterator iter = mIndex.begin();iter != mIndex.end();++iter) - { - if(Ogre::StringUtil::match(iter->first, normalizedPattern) || - (recursive && Ogre::StringUtil::match(iter->first, "*/"+normalizedPattern))) - ptr->push_back(iter->first); - } - return ptr; - } - - bool exists(const String& filename) - { - return lookup_filename(filename) != mIndex.end (); - } - - time_t getModifiedTime(const String&) { return 0; } - - FileInfoListPtr findFileInfo(const String& pattern, bool recursive = true, - bool dirs = false) const - { - std::string normalizedPattern = normalize_path(pattern.begin(), pattern.end()); - FileInfoListPtr ptr = FileInfoListPtr(new FileInfoList()); - - index::const_iterator i = mIndex.find(normalizedPattern); - if(i != mIndex.end()) - { - std::string::size_type pt = i->first.rfind('/'); - if(pt == std::string::npos) - pt = 0; - - FileInfo fi; - fi.archive = const_cast(this); - fi.path = i->first.substr(0, pt); - fi.filename = i->first.substr((i->first[pt]=='/') ? pt+1 : pt); - fi.compressedSize = fi.uncompressedSize = 0; - - ptr->push_back(fi); - } - else - { - for(index::const_iterator iter = mIndex.begin();iter != mIndex.end();++iter) - { - if(Ogre::StringUtil::match(iter->first, normalizedPattern) || - (recursive && Ogre::StringUtil::match(iter->first, "*/"+normalizedPattern))) - { - std::string::size_type pt = iter->first.rfind('/'); - if(pt == std::string::npos) - pt = 0; - - FileInfo fi; - fi.archive = const_cast(this); - fi.path = iter->first.substr(0, pt); - fi.filename = iter->first.substr((iter->first[pt]=='/') ? pt+1 : pt); - fi.compressedSize = fi.uncompressedSize = 0; - - ptr->push_back(fi); - } - } - } - - return ptr; - } -}; - -class BSAArchive : public Archive -{ - Bsa::BSAFile arc; - - static const char *extractFilename(const Bsa::BSAFile::FileStruct &entry) - { - return entry.name; - } - -public: - BSAArchive(const String& name) - : Archive(name, "BSA") - { arc.open(name); } - - bool isCaseSensitive() const { return false; } - - // The archive is loaded in the constructor, and never unloaded. - void load() {} - void unload() {} - - DataStreamPtr open(const String& filename, bool readonly = true) const - { - // Get a non-const reference to arc. This is a hack and it's all - // OGRE's fault. You should NOT expect an open() command not to - // have any side effects on the archive, and hence this function - // should not have been declared const in the first place. - Bsa::BSAFile *narc = const_cast(&arc); - - // Open the file - return narc->getFile(filename.c_str()); - } - - bool exists(const String& filename) { - return arc.exists(filename.c_str()); - } - - time_t getModifiedTime(const String&) { return 0; } - - // This is never called as far as I can see. - StringVectorPtr list(bool recursive = true, bool dirs = false) - { - return find ("*", recursive, dirs); - } - - // Also never called. - FileInfoListPtr listFileInfo(bool recursive = true, bool dirs = false) - { - return findFileInfo ("*", recursive, dirs); - } - - StringVectorPtr find(const String& pattern, bool recursive = true, - bool dirs = false) - { - std::string normalizedPattern = normalize_path(pattern.begin(), pattern.end()); - const Bsa::BSAFile::FileList &filelist = arc.getList(); - StringVectorPtr ptr = StringVectorPtr(new StringVector()); - for(Bsa::BSAFile::FileList::const_iterator iter = filelist.begin();iter != filelist.end();++iter) - { - std::string ent = normalize_path(iter->name, iter->name+std::strlen(iter->name)); - if(Ogre::StringUtil::match(ent, normalizedPattern) || - (recursive && Ogre::StringUtil::match(ent, "*/"+normalizedPattern))) - ptr->push_back(iter->name); - } - return ptr; - } - - FileInfoListPtr findFileInfo(const String& pattern, bool recursive = true, - bool dirs = false) const - { - std::string normalizedPattern = normalize_path(pattern.begin(), pattern.end()); - FileInfoListPtr ptr = FileInfoListPtr(new FileInfoList()); - const Bsa::BSAFile::FileList &filelist = arc.getList(); - - for(Bsa::BSAFile::FileList::const_iterator iter = filelist.begin();iter != filelist.end();++iter) - { - std::string ent = normalize_path(iter->name, iter->name+std::strlen(iter->name)); - if(Ogre::StringUtil::match(ent, normalizedPattern) || - (recursive && Ogre::StringUtil::match(ent, "*/"+normalizedPattern))) - { - std::string::size_type pt = ent.rfind('/'); - if(pt == std::string::npos) - pt = 0; - - FileInfo fi; - fi.archive = const_cast(this); - fi.path = std::string(iter->name, pt); - fi.filename = std::string(iter->name + ((ent[pt]=='/') ? pt+1 : pt)); - fi.compressedSize = fi.uncompressedSize = iter->fileSize; - - ptr->push_back(fi); - } - } - - return ptr; - } -}; - -// An archive factory for BSA archives -class BSAArchiveFactory : public ArchiveFactory -{ -public: - const String& getType() const - { - static String name = "BSA"; - return name; - } - - Archive *createInstance( const String& name ) - { - return new BSAArchive(name); - } - - virtual Archive* createInstance(const String& name, bool readOnly) - { - return new BSAArchive(name); - } - - void destroyInstance( Archive* arch) { delete arch; } -}; - -class DirArchiveFactory : public ArchiveFactory -{ -public: - const String& getType() const - { - static String name = "Dir"; - return name; - } - - Archive *createInstance( const String& name ) - { - return new DirArchive(name); - } - - virtual Archive* createInstance(const String& name, bool readOnly) - { - return new DirArchive(name); - } - - void destroyInstance( Archive* arch) { delete arch; } -}; - - -static bool init = false; -static bool init2 = false; - -static void insertBSAFactory() -{ - if(!init) - { - ArchiveManager::getSingleton().addArchiveFactory( new BSAArchiveFactory ); - init = true; - } -} - -static void insertDirFactory() -{ - if(!init2) - { - ArchiveManager::getSingleton().addArchiveFactory( new DirArchiveFactory ); - init2 = true; - } -} - - -namespace Bsa -{ - -// The function below is the only publicly exposed part of this file - -void addBSA(const std::string& name, const std::string& group) -{ - insertBSAFactory(); - ResourceGroupManager::getSingleton(). - addResourceLocation(name, "BSA", group, true); -} - -void addDir(const std::string& name, const bool& fs, const std::string& group) -{ - fsstrict = fs; - insertDirFactory(); - - ResourceGroupManager::getSingleton(). - addResourceLocation(name, "Dir", group, true); -} - -} diff --git a/components/bsa/bsa_archive.hpp b/components/bsa/bsa_archive.hpp deleted file mode 100644 index 7f9ebaae1..000000000 --- a/components/bsa/bsa_archive.hpp +++ /dev/null @@ -1,40 +0,0 @@ -/* - OpenMW - The completely unofficial reimplementation of Morrowind - Copyright (C) 2008-2010 Nicolay Korslund - Email: < korslund@gmail.com > - WWW: http://openmw.sourceforge.net/ - - This file (cpp_bsaarchive.h) is part of the OpenMW package. - - OpenMW is distributed as free software: you can redistribute it - and/or modify it under the terms of the GNU General Public License - version 3, as published by the Free Software Foundation. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - version 3 along with this program. If not, see - http://www.gnu.org/licenses/ . - - */ - -#include -#include - -#ifndef BSA_BSA_ARCHIVE_H -#define BSA_BSA_ARCHIVE_H - -namespace Bsa -{ - -/// Add the given BSA file as an input archive in the Ogre resource -/// system. -void addBSA(const std::string& file, const std::string& group="General"); -void addDir(const std::string& file, const bool& fs, const std::string& group="General"); - -} - -#endif diff --git a/components/bsa/bsa_file.cpp b/components/bsa/bsa_file.cpp index 0958c8f0c..bd6ea8075 100644 --- a/components/bsa/bsa_file.cpp +++ b/components/bsa/bsa_file.cpp @@ -28,7 +28,7 @@ #include #include -#include "../files/constrainedfiledatastream.hpp" +#include "../files/constrainedfilestream.hpp" using namespace std; using namespace Bsa; @@ -168,7 +168,7 @@ void BSAFile::open(const string &file) readHeader(); } -Ogre::DataStreamPtr BSAFile::getFile(const char *file) +Files::IStreamPtr BSAFile::getFile(const char *file) { assert(file); int i = getIndex(file); @@ -176,5 +176,6 @@ Ogre::DataStreamPtr BSAFile::getFile(const char *file) fail("File not found: " + string(file)); const FileStruct &fs = files[i]; - return openConstrainedFileDataStream (filename.c_str (), fs.offset, fs.fileSize); + + return Files::openConstrainedFileStream (filename.c_str (), fs.offset, fs.fileSize); } diff --git a/components/bsa/bsa_file.hpp b/components/bsa/bsa_file.hpp index 017adf1e3..3024cb610 100644 --- a/components/bsa/bsa_file.hpp +++ b/components/bsa/bsa_file.hpp @@ -32,6 +32,8 @@ #include +#include + namespace Bsa { @@ -116,7 +118,7 @@ public: /** Open a file contained in the archive. Throws an exception if the file doesn't exist. */ - Ogre::DataStreamPtr getFile(const char *file); + Files::IStreamPtr getFile(const char *file); /// Get a list of all files const FileList &getList() const diff --git a/components/bsa/resources.cpp b/components/bsa/resources.cpp deleted file mode 100644 index d06b3b485..000000000 --- a/components/bsa/resources.cpp +++ /dev/null @@ -1,53 +0,0 @@ - -#include "resources.hpp" - -#include - -#include -#include - -#include "bsa_archive.hpp" - -void Bsa::registerResources (const Files::Collections& collections, - const std::vector& archives, bool useLooseFiles, bool fsStrict) -{ - const Files::PathContainer& dataDirs = collections.getPaths(); - - int i=0; - - if (useLooseFiles) - for (Files::PathContainer::const_iterator iter = dataDirs.begin(); iter != dataDirs.end(); ++iter) - { - // Last data dir has the highest priority - std::string groupName = "Data" + Ogre::StringConverter::toString(dataDirs.size()-i, 8, '0'); - Ogre::ResourceGroupManager::getSingleton ().createResourceGroup (groupName); - - std::string dataDirectory = iter->string(); - std::cout << "Data dir " << dataDirectory << std::endl; - Bsa::addDir(dataDirectory, fsStrict, groupName); - ++i; - } - - i=0; - for (std::vector::const_iterator archive = archives.begin(); archive != archives.end(); ++archive) - { - if (collections.doesExist(*archive)) - { - // Last BSA has the highest priority - std::string groupName = "DataBSA" + Ogre::StringConverter::toString(archives.size()-i, 8, '0'); - - Ogre::ResourceGroupManager::getSingleton ().createResourceGroup (groupName); - - const std::string archivePath = collections.getPath(*archive).string(); - std::cout << "Adding BSA archive " << archivePath << std::endl; - Bsa::addBSA(archivePath, groupName); - ++i; - } - else - { - std::stringstream message; - message << "Archive '" << *archive << "' not found"; - throw std::runtime_error(message.str()); - } - } -} \ No newline at end of file diff --git a/components/bsa/resources.hpp b/components/bsa/resources.hpp deleted file mode 100644 index 8c3fb7bef..000000000 --- a/components/bsa/resources.hpp +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef BSA_BSA_RESOURCES_H -#define BSA_BSA_RESOURCES_H - -#include -#include - -#include "../files/collections.hpp" - -namespace Bsa -{ - void registerResources (const Files::Collections& collections, - const std::vector& archives, bool useLooseFiles, bool fsStrict); - ///< Register resources directories and archives as OGRE resources groups -} - -#endif diff --git a/components/files/constrainedfilestream.hpp b/components/files/constrainedfilestream.hpp index 10fe223bc..318a02294 100644 --- a/components/files/constrainedfilestream.hpp +++ b/components/files/constrainedfilestream.hpp @@ -3,6 +3,8 @@ #include +#include + namespace Files { @@ -15,6 +17,14 @@ public: virtual ~ConstrainedFileStream(); }; +typedef boost::shared_ptr IStreamPtr; + +IStreamPtr openConstrainedFileStream(const char *filename, + size_t start=0, size_t length=0xFFFFFFFF) +{ + return IStreamPtr(new ConstrainedFileStream(filename, start, length)); +} + } #endif From 8c10d4badb59a8cd5aaf146551ea7b422275a43f Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 17 Feb 2015 17:08:55 +0100 Subject: [PATCH 0584/3725] NIF reader compiles without Ogre --- CMakeLists.txt | 3 ++ components/CMakeLists.txt | 22 ++++---- components/nif/controlled.hpp | 4 +- components/nif/controller.hpp | 4 +- components/nif/data.hpp | 20 ++++---- components/nif/effect.hpp | 6 +-- components/nif/niffile.cpp | 95 ++++++++++++++++++----------------- components/nif/niffile.hpp | 8 ++- components/nif/nifkey.hpp | 47 +++++++++-------- components/nif/nifstream.cpp | 71 +++++++++++++------------- components/nif/nifstream.hpp | 37 +++++++------- components/nif/niftypes.hpp | 21 ++++++-- components/nif/node.cpp | 58 --------------------- components/nif/node.hpp | 22 ++------ components/nif/property.hpp | 12 +---- 15 files changed, 187 insertions(+), 243 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a0cf56ab4..cbe142fcc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -221,6 +221,9 @@ if (${OGRE_VERSION} VERSION_LESS "1.9") message(FATAL_ERROR "OpenMW requires Ogre 1.9 or later, please install the latest stable version from http://ogre3d.org") endif() +find_package(OpenSceneGraph 3.2.0 REQUIRED osgDB) +include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS}) + find_package(MyGUI REQUIRED) if (${MYGUI_VERSION} VERSION_LESS "3.2.1") message(FATAL_ERROR "OpenMW requires MyGUI 3.2.1 or later, please install the latest version from http://mygui.info") diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index f6b1c8cba..ecaeb115b 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -31,24 +31,24 @@ add_component_dir (nifoverrides ) add_component_dir (bsa - bsa_archive bsa_file resources + bsa_file ) add_component_dir (nif controlled effect niftypes record controller extra node record_ptr data niffile property nifkey data node base nifstream ) -add_component_dir (nifcache - nifcache - ) +#add_component_dir (nifcache +# nifcache +# ) -add_component_dir (nifogre - ogrenifloader skeleton material mesh particles controller - ) +#add_component_dir (nifogre +# ogrenifloader skeleton material mesh particles controller +# ) -add_component_dir (nifbullet - bulletnifloader - ) +#add_component_dir (nifbullet +# bulletnifloader +# ) add_component_dir (to_utf8 to_utf8 @@ -160,7 +160,7 @@ include_directories(${BULLET_INCLUDE_DIRS} ${CMAKE_CURRENT_BINARY_DIR}) add_library(components STATIC ${COMPONENT_FILES} ${MOC_SRCS} ${ESM_UI_HDR}) -target_link_libraries(components ${Boost_LIBRARIES} ${OGRE_LIBRARIES}) +target_link_libraries(components ${Boost_LIBRARIES} ${OGRE_LIBRARIES} ${OPENSCENEGRAPH_LIBRARIES}) if (GIT_CHECKOUT) add_dependencies (components git-version) diff --git a/components/nif/controlled.hpp b/components/nif/controlled.hpp index 815aa7d3f..51890f069 100644 --- a/components/nif/controlled.hpp +++ b/components/nif/controlled.hpp @@ -129,8 +129,8 @@ public: * 1 - Point (fixed origin) */ int mType; - Ogre::Vector3 mPosition; - Ogre::Vector3 mDirection; + osg::Vec3f mPosition; + osg::Vec3f mDirection; void read(NIFStream *nif) { diff --git a/components/nif/controller.hpp b/components/nif/controller.hpp index 9ae527e5a..718748c31 100644 --- a/components/nif/controller.hpp +++ b/components/nif/controller.hpp @@ -33,7 +33,7 @@ class NiParticleSystemController : public Controller { public: struct Particle { - Ogre::Vector3 velocity; + osg::Vec3f velocity; float lifetime; float lifespan; float timestamp; @@ -64,7 +64,7 @@ public: }; int emitFlags; - Ogre::Vector3 offsetRandom; + osg::Vec3f offsetRandom; NodePtr emitter; diff --git a/components/nif/data.hpp b/components/nif/data.hpp index d9de12fb5..db5a5643d 100644 --- a/components/nif/data.hpp +++ b/components/nif/data.hpp @@ -33,10 +33,10 @@ namespace Nif class ShapeData : public Record { public: - std::vector vertices, normals; - std::vector colors; - std::vector< std::vector > uvlist; - Ogre::Vector3 center; + std::vector vertices, normals; + std::vector colors; + std::vector< std::vector > uvlist; + osg::Vec3f center; float radius; void read(NIFStream *nif) @@ -131,7 +131,7 @@ public: class NiRotatingParticlesData : public NiAutoNormalParticlesData { public: - std::vector rotations; + std::vector rotations; void read(NIFStream *nif) { @@ -272,9 +272,9 @@ class NiSkinData : public Record public: struct BoneTrafo { - Ogre::Matrix3 rotation; // Rotation offset from bone? - Ogre::Vector3 trans; // Translation - float scale; // Probably scale (always 1) + Matrix3 rotation; // Rotation offset from bone? + osg::Vec3f trans; // Translation + float scale; // Scale }; struct VertWeight @@ -286,7 +286,7 @@ public: struct BoneInfo { BoneTrafo trafo; - Ogre::Vector4 unknown; + osg::Vec4f unknown; std::vector weights; }; @@ -327,7 +327,7 @@ struct NiMorphData : public Record { struct MorphData { FloatKeyMap mData; - std::vector mVertices; + std::vector mVertices; }; std::vector mMorphs; diff --git a/components/nif/effect.hpp b/components/nif/effect.hpp index cc1b0f41c..679557e25 100644 --- a/components/nif/effect.hpp +++ b/components/nif/effect.hpp @@ -38,9 +38,9 @@ struct NiLight : Effect struct SLight { float dimmer; - Ogre::Vector3 ambient; - Ogre::Vector3 diffuse; - Ogre::Vector3 specular; + osg::Vec3f ambient; + osg::Vec3f diffuse; + osg::Vec3f specular; void read(NIFStream *nif) { diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index 4f3ee95cb..f7d864198 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -2,16 +2,16 @@ #include "effect.hpp" #include - -#include +#include namespace Nif { /// Open a NIF stream. The name is used for error messages. -NIFFile::NIFFile(const std::string &name) +NIFFile::NIFFile(Files::IStreamPtr stream, const std::string &name) : ver(0) , filename(name) + , mStream(stream) { parse(); } @@ -121,63 +121,68 @@ std::string NIFFile::printVersion(unsigned int version) version_out.full = version; - return Ogre::StringConverter::toString(version_out.quad[3]) - +"." + Ogre::StringConverter::toString(version_out.quad[2]) - +"." + Ogre::StringConverter::toString(version_out.quad[1]) - +"." + Ogre::StringConverter::toString(version_out.quad[0]); + std::stringstream stream; + stream << version_out.quad[3] << "." + << version_out.quad[2] << "." + << version_out.quad[1] << "." + << version_out.quad[0]; + return stream.str(); } void NIFFile::parse() { - NIFStream nif (this, Ogre::ResourceGroupManager::getSingleton().openResource(filename)); - - // Check the header string - std::string head = nif.getVersionString(); - if(head.compare(0, 22, "NetImmerse File Format") != 0) - fail("Invalid NIF header: " + head); - - // Get BCD version - ver = nif.getUInt(); - if(ver != VER_MW) - fail("Unsupported NIF version: " + printVersion(ver)); - // Number of records - size_t recNum = nif.getInt(); - records.resize(recNum); - - /* The format for 10.0.1.0 seems to be a bit different. After the + NIFStream nif (this, mStream); + + // Check the header string + std::string head = nif.getVersionString(); + if(head.compare(0, 22, "NetImmerse File Format") != 0) + fail("Invalid NIF header: " + head); + + // Get BCD version + ver = nif.getUInt(); + if(ver != VER_MW) + fail("Unsupported NIF version: " + printVersion(ver)); + // Number of records + size_t recNum = nif.getInt(); + records.resize(recNum); + + /* The format for 10.0.1.0 seems to be a bit different. After the header, it contains the number of records, r (int), just like 4.0.0.2, but following that it contains a short x, followed by x strings. Then again by r shorts, one for each record, giving which of the above strings to use to identify the record. After this follows two ints (zero?) and then the record data. However we do not support or plan to support other versions yet. - */ + */ - for(size_t i = 0;i < recNum;i++) + for(size_t i = 0;i < recNum;i++) { - Record *r = NULL; - - std::string rec = nif.getString(); - if(rec.empty()) - fail("Record number " + Ogre::StringConverter::toString(i) + " out of " + Ogre::StringConverter::toString(recNum) + " is blank."); + Record *r = NULL; + std::string rec = nif.getString(); + if(rec.empty()) + { + std::stringstream error; + error << "Record number " << i << " out of " << recNum << " is blank."; + fail(error.str()); + } - std::map::const_iterator entry = factories.find(rec); - - if (entry != factories.end()) - { - r = entry->second.mCreate (); - r->recType = entry->second.mType; - } - else - fail("Unknown record type " + rec); + std::map::const_iterator entry = factories.find(rec); - assert(r != NULL); - assert(r->recType != RC_MISSING); - r->recName = rec; - r->recIndex = i; - records[i] = r; - r->read(&nif); + if (entry != factories.end()) + { + r = entry->second.mCreate (); + r->recType = entry->second.mType; + } + else + fail("Unknown record type " + rec); + + assert(r != NULL); + assert(r->recType != RC_MISSING); + r->recName = rec; + r->recIndex = i; + records[i] = r; + r->read(&nif); } size_t rootNum = nif.getUInt(); diff --git a/components/nif/niffile.hpp b/components/nif/niffile.hpp index ceb9984fb..9f08f3f1d 100644 --- a/components/nif/niffile.hpp +++ b/components/nif/niffile.hpp @@ -7,6 +7,8 @@ #include #include +#include + #include "record.hpp" namespace Nif @@ -42,6 +44,8 @@ class NIFFile ///\overload void operator = (NIFFile const &); + Files::IStreamPtr mStream; + public: /// Used if file parsing fails void fail(const std::string &msg) @@ -57,8 +61,8 @@ public: << "File: " << filename < - #include "nifstream.hpp" +#include +#include + namespace Nif { template struct KeyT { T mValue; + + // FIXME: Implement Quadratic and TBC interpolation + /* T mForwardValue; // Only for Quadratic interpolation, and never for QuaternionKeyList T mBackwardValue; // Only for Quadratic interpolation, and never for QuaternionKeyList float mTension; // Only for TBC interpolation float mBias; // Only for TBC interpolation float mContinuity; // Only for TBC interpolation + */ }; -typedef KeyT FloatKey; -typedef KeyT Vector3Key; -typedef KeyT Vector4Key; -typedef KeyT QuaternionKey; template struct KeyMapT { @@ -92,7 +93,12 @@ struct KeyMapT { { //Don't try to read XYZ keys into the wrong part if ( count != 1 ) - nif->file->fail("XYZ_ROTATION_KEY count should always be '1' . Retrieved Value: "+Ogre::StringConverter::toString(count)); + { + std::stringstream error; + error << "XYZ_ROTATION_KEY count should always be '1' . Retrieved Value: " + << count; + nif->file->fail(error.str()); + } } else if (0 == mInterpolationType) { @@ -100,7 +106,11 @@ struct KeyMapT { nif->file->fail("Interpolation type 0 doesn't work with keys"); } else - nif->file->fail("Unhandled interpolation type: "+Ogre::StringConverter::toString(mInterpolationType)); + { + std::stringstream error; + error << "Unhandled interpolation type: " << mInterpolationType; + nif->file->fail(error.str()); + } } private: @@ -109,31 +119,26 @@ private: key.mValue = (nif.*getValue)(); } - static void readQuadratic(NIFStream &nif, KeyT &key) - { - readValue(nif, key); - } - template static void readQuadratic(NIFStream &nif, KeyT &key) { readValue(nif, key); - key.mForwardValue = (nif.*getValue)(); - key.mBackwardValue = (nif.*getValue)(); + /*key.mForwardValue = */(nif.*getValue)(); + /*key.mBackwardValue = */(nif.*getValue)(); } static void readTBC(NIFStream &nif, KeyT &key) { readValue(nif, key); - key.mTension = nif.getFloat(); - key.mBias = nif.getFloat(); - key.mContinuity = nif.getFloat(); + /*key.mTension = */nif.getFloat(); + /*key.mBias = */nif.getFloat(); + /*key.mContinuity = */nif.getFloat(); } }; typedef KeyMapT FloatKeyMap; -typedef KeyMapT Vector3KeyMap; -typedef KeyMapT Vector4KeyMap; -typedef KeyMapT QuaternionKeyMap; +typedef KeyMapT Vector3KeyMap; +typedef KeyMapT Vector4KeyMap; +typedef KeyMapT QuaternionKeyMap; } // Namespace #endif //#ifndef OPENMW_COMPONENTS_NIF_NIFKEY_HPP diff --git a/components/nif/nifstream.cpp b/components/nif/nifstream.cpp index e5699db7b..628541933 100644 --- a/components/nif/nifstream.cpp +++ b/components/nif/nifstream.cpp @@ -9,19 +9,19 @@ namespace Nif uint8_t NIFStream::read_byte() { uint8_t byte; - if(inp->read(&byte, 1) != 1) return 0; + inp->read((char*)&byte, 1); return byte; } uint16_t NIFStream::read_le16() { uint8_t buffer[2]; - if(inp->read(buffer, 2) != 2) return 0; + inp->read((char*)buffer, 2); return buffer[0] | (buffer[1]<<8); } uint32_t NIFStream::read_le32() { uint8_t buffer[4]; - if(inp->read(buffer, 4) != 4) return 0; + inp->read((char*)buffer, 4); return buffer[0] | (buffer[1]<<8) | (buffer[2]<<16) | (buffer[3]<<24); } float NIFStream::read_le32f() @@ -34,43 +34,45 @@ float NIFStream::read_le32f() } //Public functions -Ogre::Vector2 NIFStream::getVector2() +osg::Vec2f NIFStream::getVector2() { - float a[2]; + osg::Vec2f vec; for(size_t i = 0;i < 2;i++) - a[i] = getFloat(); - return Ogre::Vector2(a); + vec._v[i] = getFloat(); + return vec; } -Ogre::Vector3 NIFStream::getVector3() +osg::Vec3f NIFStream::getVector3() { - float a[3]; + osg::Vec3f vec; for(size_t i = 0;i < 3;i++) - a[i] = getFloat(); - return Ogre::Vector3(a); + vec._v[i] = getFloat(); + return vec; } -Ogre::Vector4 NIFStream::getVector4() +osg::Vec4f NIFStream::getVector4() { - float a[4]; + osg::Vec4f vec; for(size_t i = 0;i < 4;i++) - a[i] = getFloat(); - return Ogre::Vector4(a); + vec._v[i] = getFloat(); + return vec; } -Ogre::Matrix3 NIFStream::getMatrix3() +Matrix3 NIFStream::getMatrix3() { - Ogre::Real a[3][3]; + Matrix3 mat; for(size_t i = 0;i < 3;i++) { for(size_t j = 0;j < 3;j++) - a[i][j] = Ogre::Real(getFloat()); + mat.mValues[i][j] = getFloat(); } - return Ogre::Matrix3(a); + return mat; } -Ogre::Quaternion NIFStream::getQuaternion() +osg::Quat NIFStream::getQuaternion() { - float a[4]; - for(size_t i = 0;i < 4;i++) - a[i] = getFloat(); - return Ogre::Quaternion(a); + osg::Quat quat; + quat.w() = getFloat(); + quat.x() = getFloat(); + quat.y() = getFloat(); + quat.z() = getFloat(); + return quat; } Transformation NIFStream::getTrafo() { @@ -83,16 +85,9 @@ Transformation NIFStream::getTrafo() std::string NIFStream::getString(size_t length) { - //Make sure we're not reading in too large of a string - unsigned int fileSize = inp->size(); - if(fileSize != 0 && fileSize < length) - file->fail("Attempted to read a string with " + Ogre::StringConverter::toString(length) + " characters , but file is only "+Ogre::StringConverter::toString(fileSize)+ " bytes!"); - std::vector str (length+1, 0); - if(inp->read(&str[0], length) != length) - throw std::runtime_error (": String length in NIF file "+ file->getFilename() +" does not match! Expected length: " - + Ogre::StringConverter::toString(length)); + inp->read(&str[0], length); return &str[0]; } @@ -103,7 +98,9 @@ std::string NIFStream::getString() } std::string NIFStream::getVersionString() { - return inp->getLine(); + std::string result; + std::getline(*inp, result); + return result; } void NIFStream::getShorts(std::vector &vec, size_t size) @@ -118,25 +115,25 @@ void NIFStream::getFloats(std::vector &vec, size_t size) for(size_t i = 0;i < vec.size();i++) vec[i] = getFloat(); } -void NIFStream::getVector2s(std::vector &vec, size_t size) +void NIFStream::getVector2s(std::vector &vec, size_t size) { vec.resize(size); for(size_t i = 0;i < vec.size();i++) vec[i] = getVector2(); } -void NIFStream::getVector3s(std::vector &vec, size_t size) +void NIFStream::getVector3s(std::vector &vec, size_t size) { vec.resize(size); for(size_t i = 0;i < vec.size();i++) vec[i] = getVector3(); } -void NIFStream::getVector4s(std::vector &vec, size_t size) +void NIFStream::getVector4s(std::vector &vec, size_t size) { vec.resize(size); for(size_t i = 0;i < vec.size();i++) vec[i] = getVector4(); } -void NIFStream::getQuaternions(std::vector &quat, size_t size) +void NIFStream::getQuaternions(std::vector &quat, size_t size) { quat.resize(size); for(size_t i = 0;i < quat.size();i++) diff --git a/components/nif/nifstream.hpp b/components/nif/nifstream.hpp index 6c5e83eeb..b732c83af 100644 --- a/components/nif/nifstream.hpp +++ b/components/nif/nifstream.hpp @@ -5,14 +5,13 @@ #include #include +#include -#include -#include -#include -#include -#include -#include -#include +#include + +#include +#include +#include #include "niftypes.hpp" @@ -24,7 +23,7 @@ class NIFFile; class NIFStream { /// Input stream - Ogre::DataStreamPtr inp; + Files::IStreamPtr inp; uint8_t read_byte(); uint16_t read_le16(); @@ -35,9 +34,9 @@ public: NIFFile * const file; - NIFStream (NIFFile * file, Ogre::DataStreamPtr inp): file (file), inp (inp) {} + NIFStream (NIFFile * file, Files::IStreamPtr inp): file (file), inp (inp) {} - void skip(size_t size) { inp->skip(size); } + void skip(size_t size) { inp->ignore(size); } char getChar() { return read_byte(); } short getShort() { return read_le16(); } @@ -46,11 +45,11 @@ public: unsigned int getUInt() { return read_le32(); } float getFloat() { return read_le32f(); } - Ogre::Vector2 getVector2(); - Ogre::Vector3 getVector3(); - Ogre::Vector4 getVector4(); - Ogre::Matrix3 getMatrix3(); - Ogre::Quaternion getQuaternion(); + osg::Vec2f getVector2(); + osg::Vec3f getVector3(); + osg::Vec4f getVector4(); + Matrix3 getMatrix3(); + osg::Quat getQuaternion(); Transformation getTrafo(); ///Read in a string of the given length @@ -62,10 +61,10 @@ public: void getShorts(std::vector &vec, size_t size); void getFloats(std::vector &vec, size_t size); - void getVector2s(std::vector &vec, size_t size); - void getVector3s(std::vector &vec, size_t size); - void getVector4s(std::vector &vec, size_t size); - void getQuaternions(std::vector &quat, size_t size); + void getVector2s(std::vector &vec, size_t size); + void getVector3s(std::vector &vec, size_t size); + void getVector4s(std::vector &vec, size_t size); + void getQuaternions(std::vector &quat, size_t size); }; } diff --git a/components/nif/niftypes.hpp b/components/nif/niftypes.hpp index 786c48b65..864795afb 100644 --- a/components/nif/niftypes.hpp +++ b/components/nif/niftypes.hpp @@ -24,24 +24,35 @@ #ifndef OPENMW_COMPONENTS_NIF_NIFTYPES_HPP #define OPENMW_COMPONENTS_NIF_NIFTYPES_HPP -#include -#include +#include // Common types used in NIF files namespace Nif { +struct Matrix3 +{ + float mValues[3][3]; + + Matrix3() + { + for (int i=0;i<3;++i) + for (int j=0;j<3;++j) + mValues[i][j] = 0; + } +}; + struct Transformation { - Ogre::Vector3 pos; - Ogre::Matrix3 rotation; + osg::Vec3f pos; + Matrix3 rotation; float scale; static const Transformation& getIdentity() { static const Transformation identity = { - Ogre::Vector3::ZERO, Ogre::Matrix3::IDENTITY, 1.0f + osg::Vec3f(), Matrix3(), 1.0f }; return identity; } diff --git a/components/nif/node.cpp b/components/nif/node.cpp index fb68da548..b0c5d990e 100644 --- a/components/nif/node.cpp +++ b/components/nif/node.cpp @@ -1,60 +1,2 @@ #include "node.hpp" -namespace Nif -{ - -void Node::getProperties(const Nif::NiTexturingProperty *&texprop, - const Nif::NiMaterialProperty *&matprop, - const Nif::NiAlphaProperty *&alphaprop, - const Nif::NiVertexColorProperty *&vertprop, - const Nif::NiZBufferProperty *&zprop, - const Nif::NiSpecularProperty *&specprop, - const Nif::NiWireframeProperty *&wireprop, - const Nif::NiStencilProperty *&stencilprop) const -{ - if(parent) - parent->getProperties(texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop, stencilprop); - - for(size_t i = 0;i < props.length();i++) - { - // Entries may be empty - if(props[i].empty()) - continue; - - const Nif::Property *pr = props[i].getPtr(); - if(pr->recType == Nif::RC_NiTexturingProperty) - texprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiMaterialProperty) - matprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiAlphaProperty) - alphaprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiVertexColorProperty) - vertprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiZBufferProperty) - zprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiSpecularProperty) - specprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiWireframeProperty) - wireprop = static_cast(pr); - else if (pr->recType == Nif::RC_NiStencilProperty) - stencilprop = static_cast(pr); - else - std::cerr<< "Unhandled property type: "<recName <getWorldTransform() * getLocalTransform(); - return getLocalTransform(); -} - -} diff --git a/components/nif/node.hpp b/components/nif/node.hpp index a26480d59..123b70cad 100644 --- a/components/nif/node.hpp +++ b/components/nif/node.hpp @@ -1,8 +1,6 @@ #ifndef OPENMW_COMPONENTS_NIF_NODE_HPP #define OPENMW_COMPONENTS_NIF_NODE_HPP -#include - #include "controlled.hpp" #include "extra.hpp" #include "data.hpp" @@ -26,14 +24,14 @@ public: // Node flags. Interpretation depends somewhat on the type of node. int flags; Transformation trafo; - Ogre::Vector3 velocity; // Unused? Might be a run-time game state + osg::Vec3f velocity; // Unused? Might be a run-time game state PropertyList props; // Bounding box info bool hasBounds; - Ogre::Vector3 boundPos; - Ogre::Matrix3 boundRot; - Ogre::Vector3 boundXYZ; // Box size + osg::Vec3f boundPos; + Matrix3 boundRot; + osg::Vec3f boundXYZ; // Box size void read(NIFStream *nif) { @@ -91,18 +89,6 @@ public: boneTrafo = &bi.trafo; boneIndex = ind; } - - void getProperties(const Nif::NiTexturingProperty *&texprop, - const Nif::NiMaterialProperty *&matprop, - const Nif::NiAlphaProperty *&alphaprop, - const Nif::NiVertexColorProperty *&vertprop, - const Nif::NiZBufferProperty *&zprop, - const Nif::NiSpecularProperty *&specprop, - const Nif::NiWireframeProperty *&wireprop, - const Nif::NiStencilProperty *&stencilprop) const; - - Ogre::Matrix4 getLocalTransform() const; - Ogre::Matrix4 getWorldTransform() const; }; struct NiNode : Node diff --git a/components/nif/property.hpp b/components/nif/property.hpp index 77f61d068..52ee7f6e1 100644 --- a/components/nif/property.hpp +++ b/components/nif/property.hpp @@ -159,7 +159,7 @@ class NiFogProperty : public Property { public: float mFogDepth; - Ogre::Vector3 mColour; + osg::Vec3f mColour; void read(NIFStream *nif) @@ -194,7 +194,7 @@ struct StructPropT : Property struct S_MaterialProperty { // The vector components are R,G,B - Ogre::Vector3 ambient, diffuse, specular, emissive; + osg::Vec3f ambient, diffuse, specular, emissive; float glossiness, alpha; void read(NIFStream *nif) @@ -265,14 +265,6 @@ struct S_AlphaProperty Taken from: http://niftools.sourceforge.net/doc/nif/NiAlphaProperty.html - - Right now we only use standard alpha blending (see the Ogre code - that sets it up) and it appears that this is the only blending - used in the original game. Bloodmoon (along with several mods) do - however use other settings, such as discarding pixel values with - alpha < 1.0. This is faster because we don't have to mess with the - depth stuff like we did for blending. And OGRE has settings for - this too. */ // Tested against when certain flags are set (see above.) From 6d62aa754445931fad3d7e5bc7389f8b6e6ccc36 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 18 Feb 2015 19:06:36 +0100 Subject: [PATCH 0585/3725] Don't prompt for spell deletion when using cycling keys (Fixes #2382) --- apps/openmw/mwgui/spellwindow.cpp | 71 +++++++++++++++++-------------- apps/openmw/mwgui/spellwindow.hpp | 1 + 2 files changed, 39 insertions(+), 33 deletions(-) diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index 69365c108..cc032691e 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -102,52 +102,53 @@ namespace MWGui updateSpells(); } - void SpellWindow::onModelIndexSelected(SpellModel::ModelIndex index) + void SpellWindow::askDeleteSpell(const std::string &spellId) { - const Spell& spell = mSpellView->getModel()->getItem(index); - if (spell.mType == Spell::Type_EnchantedItem) + // delete spell, if allowed + const ESM::Spell* spell = + MWBase::Environment::get().getWorld()->getStore().get().find(spellId); + + if (spell->mData.mFlags & ESM::Spell::F_Always + || spell->mData.mType == ESM::Spell::ST_Power) { - onEnchantedItemSelected(spell.mItem, spell.mActive); + MWBase::Environment::get().getWindowManager()->messageBox("#{sDeleteSpellError}"); } else { - onSpellSelected(spell.mId); + // ask for confirmation + mSpellToDelete = spellId; + ConfirmationDialog* dialog = MWBase::Environment::get().getWindowManager()->getConfirmationDialog(); + std::string question = MWBase::Environment::get().getWindowManager()->getGameSettingString("sQuestionDeleteSpell", "Delete %s?"); + question = boost::str(boost::format(question) % spell->mName); + dialog->open(question); + dialog->eventOkClicked.clear(); + dialog->eventOkClicked += MyGUI::newDelegate(this, &SpellWindow::onDeleteSpellAccept); + dialog->eventCancelClicked.clear(); } } - void SpellWindow::onSpellSelected(const std::string& spellId) + void SpellWindow::onModelIndexSelected(SpellModel::ModelIndex index) { - if (MyGUI::InputManager::getInstance().isShiftPressed()) + const Spell& spell = mSpellView->getModel()->getItem(index); + if (spell.mType == Spell::Type_EnchantedItem) { - // delete spell, if allowed - const ESM::Spell* spell = - MWBase::Environment::get().getWorld()->getStore().get().find(spellId); - - if (spell->mData.mFlags & ESM::Spell::F_Always - || spell->mData.mType == ESM::Spell::ST_Power) - { - MWBase::Environment::get().getWindowManager()->messageBox("#{sDeleteSpellError}"); - } - else - { - // ask for confirmation - mSpellToDelete = spellId; - ConfirmationDialog* dialog = MWBase::Environment::get().getWindowManager()->getConfirmationDialog(); - std::string question = MWBase::Environment::get().getWindowManager()->getGameSettingString("sQuestionDeleteSpell", "Delete %s?"); - question = boost::str(boost::format(question) % spell->mName); - dialog->open(question); - dialog->eventOkClicked.clear(); - dialog->eventOkClicked += MyGUI::newDelegate(this, &SpellWindow::onDeleteSpellAccept); - dialog->eventCancelClicked.clear(); - } + onEnchantedItemSelected(spell.mItem, spell.mActive); } else { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); - MWWorld::InventoryStore& store = player.getClass().getInventoryStore(player); - store.setSelectedEnchantItem(store.end()); - MWBase::Environment::get().getWindowManager()->setSelectedSpell(spellId, int(MWMechanics::getSpellSuccessChance(spellId, player))); + if (MyGUI::InputManager::getInstance().isShiftPressed()) + askDeleteSpell(spell.mId); + else + onSpellSelected(spell.mId); } + } + + void SpellWindow::onSpellSelected(const std::string& spellId) + { + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::InventoryStore& store = player.getClass().getInventoryStore(player); + store.setSelectedEnchantItem(store.end()); + MWBase::Environment::get().getWindowManager()->setSelectedSpell(spellId, int(MWMechanics::getSpellSuccessChance(spellId, player))); updateSpells(); } @@ -184,6 +185,10 @@ namespace MWGui return; selected = (selected + itemcount) % itemcount; - onModelIndexSelected(selected); + const Spell& spell = mSpellView->getModel()->getItem(selected); + if (spell.mType == Spell::Type_EnchantedItem) + onEnchantedItemSelected(spell.mItem, spell.mActive); + else + onSpellSelected(spell.mId); } } diff --git a/apps/openmw/mwgui/spellwindow.hpp b/apps/openmw/mwgui/spellwindow.hpp index 650218d30..8b5474f58 100644 --- a/apps/openmw/mwgui/spellwindow.hpp +++ b/apps/openmw/mwgui/spellwindow.hpp @@ -33,6 +33,7 @@ namespace MWGui void onSpellSelected(const std::string& spellId); void onModelIndexSelected(SpellModel::ModelIndex index); void onDeleteSpellAccept(); + void askDeleteSpell(const std::string& spellId); virtual void onPinToggled(); virtual void onTitleDoubleClicked(); From a5847afdac83fb28e0c22fa3388ca49b077adaf9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 20 Feb 2015 00:00:13 +0100 Subject: [PATCH 0586/3725] Fix ignored clicks on HUD mini-map (Fixes #2388) --- apps/openmw/mwgui/hud.cpp | 10 ++++++++++ apps/openmw/mwgui/hud.hpp | 4 ++++ files/mygui/openmw_hud.layout | 3 ++- 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 1f7ead6f5..a4e67e9b1 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -671,4 +671,14 @@ namespace MWGui mEnemyHealthTimer = -1; } + void HUD::customMarkerCreated(MyGUI::Widget *marker) + { + marker->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onMapClicked); + } + + void HUD::doorMarkerCreated(MyGUI::Widget *marker) + { + marker->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onMapClicked); + } + } diff --git a/apps/openmw/mwgui/hud.hpp b/apps/openmw/mwgui/hud.hpp index 41a535a08..263c08774 100644 --- a/apps/openmw/mwgui/hud.hpp +++ b/apps/openmw/mwgui/hud.hpp @@ -119,6 +119,10 @@ namespace MWGui void onMagicClicked(MyGUI::Widget* _sender); void onMapClicked(MyGUI::Widget* _sender); + // LocalMapBase + virtual void customMarkerCreated(MyGUI::Widget* marker); + virtual void doorMarkerCreated(MyGUI::Widget* marker); + void updateEnemyHealthBar(); void updatePositions(); diff --git a/files/mygui/openmw_hud.layout b/files/mygui/openmw_hud.layout index 84fd9d247..8334e34b9 100644 --- a/files/mygui/openmw_hud.layout +++ b/files/mygui/openmw_hud.layout @@ -112,7 +112,8 @@
- + + From 539e8276c814c44bf84525c5c569641c0be6849e Mon Sep 17 00:00:00 2001 From: Nathan Aclander Date: Thu, 19 Feb 2015 19:05:19 -0800 Subject: [PATCH 0587/3725] Silenced clang warning by converting int to string --- apps/opencs/model/tools/referencecheck.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/tools/referencecheck.cpp b/apps/opencs/model/tools/referencecheck.cpp index 0c1d7d38f..8f80c066e 100644 --- a/apps/opencs/model/tools/referencecheck.cpp +++ b/apps/opencs/model/tools/referencecheck.cpp @@ -66,18 +66,18 @@ void CSMTools::ReferenceCheckStage::perform(int stage, CSMDoc::Messages &message // If object have faction, check if that faction reference is valid if (hasFaction) if (mFactions.searchId(cellRef.mFaction) == -1) - messages.push_back(std::make_pair(id, " has non existing faction " + cellRef.mFaction)); + messages.push_back(std::make_pair(id, " has non existing faction " + boost::lexical_cast(cellRef.mFaction))); // Check item's faction rank if (hasFaction && cellRef.mFactionRank < -1) messages.push_back(std::make_pair(id, " has faction set but has invalid faction rank " + cellRef.mFactionRank)); else if (!hasFaction && cellRef.mFactionRank != -2) - messages.push_back(std::make_pair(id, " has invalid faction rank " + cellRef.mFactionRank)); + messages.push_back(std::make_pair(id, " has invalid faction rank " + boost::lexical_cast(cellRef.mFactionRank))); // If door have destination cell, check if that reference is valid if (!cellRef.mDestCell.empty()) if (mCells.searchId(cellRef.mDestCell) == -1) - messages.push_back(std::make_pair(id, " has non existing destination cell " + cellRef.mDestCell)); + messages.push_back(std::make_pair(id, " has non existing destination cell " + boost::lexical_cast(cellRef.mDestCell))); // Check if scale isn't negative if (cellRef.mScale < 0) From f6f37e02df0cb64817c8e59834b45c569fe5afb4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 20 Feb 2015 17:56:49 +0100 Subject: [PATCH 0588/3725] NIF Transformation redundancy fix and include fixes --- components/nif/data.hpp | 17 ++++++----------- components/nif/niftypes.hpp | 2 +- components/nif/node.hpp | 4 ++-- components/nif/property.hpp | 3 +++ 4 files changed, 12 insertions(+), 14 deletions(-) diff --git a/components/nif/data.hpp b/components/nif/data.hpp index db5a5643d..656d27628 100644 --- a/components/nif/data.hpp +++ b/components/nif/data.hpp @@ -26,6 +26,8 @@ #include "base.hpp" +#include "niftypes.hpp" // Transformation + namespace Nif { @@ -270,13 +272,6 @@ public: class NiSkinData : public Record { public: - struct BoneTrafo - { - Matrix3 rotation; // Rotation offset from bone? - osg::Vec3f trans; // Translation - float scale; // Scale - }; - struct VertWeight { short vertex; @@ -285,18 +280,18 @@ public: struct BoneInfo { - BoneTrafo trafo; + Transformation trafo; osg::Vec4f unknown; std::vector weights; }; - BoneTrafo trafo; + Transformation trafo; std::vector bones; void read(NIFStream *nif) { trafo.rotation = nif->getMatrix3(); - trafo.trans = nif->getVector3(); + trafo.pos = nif->getVector3(); trafo.scale = nif->getFloat(); int boneNum = nif->getInt(); @@ -308,7 +303,7 @@ public: BoneInfo &bi = bones[i]; bi.trafo.rotation = nif->getMatrix3(); - bi.trafo.trans = nif->getVector3(); + bi.trafo.pos = nif->getVector3(); bi.trafo.scale = nif->getFloat(); bi.unknown = nif->getVector4(); diff --git a/components/nif/niftypes.hpp b/components/nif/niftypes.hpp index 864795afb..4f6998200 100644 --- a/components/nif/niftypes.hpp +++ b/components/nif/niftypes.hpp @@ -39,7 +39,7 @@ struct Matrix3 { for (int i=0;i<3;++i) for (int j=0;j<3;++j) - mValues[i][j] = 0; + mValues[i][j] = (i==j) ? 1.f : 0.f; } }; diff --git a/components/nif/node.hpp b/components/nif/node.hpp index 123b70cad..7f94c0d05 100644 --- a/components/nif/node.hpp +++ b/components/nif/node.hpp @@ -68,7 +68,7 @@ public: NiNode *parent; // Bone transformation. If set, node is a part of a skeleton. - const NiSkinData::BoneTrafo *boneTrafo; + const Transformation *boneTrafo; // Bone weight info, from NiSkinData const NiSkinData::BoneInfo *boneInfo; @@ -77,7 +77,7 @@ public: // boneTrafo is set it is the root bone in the skeleton. short boneIndex; - void makeRootBone(const NiSkinData::BoneTrafo *tr) + void makeRootBone(const Transformation *tr) { boneTrafo = tr; boneIndex = -1; diff --git a/components/nif/property.hpp b/components/nif/property.hpp index 52ee7f6e1..610f5427a 100644 --- a/components/nif/property.hpp +++ b/components/nif/property.hpp @@ -26,6 +26,9 @@ #include "base.hpp" +#include "controlled.hpp" +#include "data.hpp" + namespace Nif { From 68bce7825e4731b77d598ece1700762099f31637 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 20 Feb 2015 17:57:18 +0100 Subject: [PATCH 0589/3725] Multiple definition fix --- components/files/constrainedfilestream.cpp | 7 +++++++ components/files/constrainedfilestream.hpp | 6 +----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/components/files/constrainedfilestream.cpp b/components/files/constrainedfilestream.cpp index 404fddfcb..fddfa7e52 100644 --- a/components/files/constrainedfilestream.cpp +++ b/components/files/constrainedfilestream.cpp @@ -104,4 +104,11 @@ namespace Files { delete rdbuf(); } + + + IStreamPtr openConstrainedFileStream(const char *filename, + size_t start, size_t length) + { + return IStreamPtr(new ConstrainedFileStream(filename, start, length)); + } } diff --git a/components/files/constrainedfilestream.hpp b/components/files/constrainedfilestream.hpp index 318a02294..069ceec58 100644 --- a/components/files/constrainedfilestream.hpp +++ b/components/files/constrainedfilestream.hpp @@ -19,11 +19,7 @@ public: typedef boost::shared_ptr IStreamPtr; -IStreamPtr openConstrainedFileStream(const char *filename, - size_t start=0, size_t length=0xFFFFFFFF) -{ - return IStreamPtr(new ConstrainedFileStream(filename, start, length)); -} +IStreamPtr openConstrainedFileStream(const char *filename, size_t start=0, size_t length=0xFFFFFFFF); } From 6d7e1242cc62a3e9ac527e0c007829ee1c47952e Mon Sep 17 00:00:00 2001 From: Nathan Aclander Date: Fri, 20 Feb 2015 20:18:31 -0800 Subject: [PATCH 0590/3725] Fixed incorrect casting Only cast to strings things that are ints. Also I missed an mFactionRank to cast. --- apps/opencs/model/tools/referencecheck.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/tools/referencecheck.cpp b/apps/opencs/model/tools/referencecheck.cpp index 8f80c066e..68de87d80 100644 --- a/apps/opencs/model/tools/referencecheck.cpp +++ b/apps/opencs/model/tools/referencecheck.cpp @@ -66,18 +66,18 @@ void CSMTools::ReferenceCheckStage::perform(int stage, CSMDoc::Messages &message // If object have faction, check if that faction reference is valid if (hasFaction) if (mFactions.searchId(cellRef.mFaction) == -1) - messages.push_back(std::make_pair(id, " has non existing faction " + boost::lexical_cast(cellRef.mFaction))); + messages.push_back(std::make_pair(id, " has non existing faction " + cellRef.mFaction)); // Check item's faction rank if (hasFaction && cellRef.mFactionRank < -1) - messages.push_back(std::make_pair(id, " has faction set but has invalid faction rank " + cellRef.mFactionRank)); + messages.push_back(std::make_pair(id, " has faction set but has invalid faction rank " + boost::lexical_cast(cellRef.mFactionRank))); else if (!hasFaction && cellRef.mFactionRank != -2) messages.push_back(std::make_pair(id, " has invalid faction rank " + boost::lexical_cast(cellRef.mFactionRank))); // If door have destination cell, check if that reference is valid if (!cellRef.mDestCell.empty()) if (mCells.searchId(cellRef.mDestCell) == -1) - messages.push_back(std::make_pair(id, " has non existing destination cell " + boost::lexical_cast(cellRef.mDestCell))); + messages.push_back(std::make_pair(id, " has non existing destination cell " + cellRef.mDestCell)); // Check if scale isn't negative if (cellRef.mScale < 0) From accc078e0efa55538eb1dad341acdff4843498c0 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 22 Feb 2015 08:46:12 +1300 Subject: [PATCH 0591/3725] Morrowind.ini import progress bar. (Fixes #2344) 1. Show a "bouncing ball" Progress bar when importing from morrowind.ini. 2. Removed dialog that asks for content list name when import game files from morrowind.ini. Instead, name is time stamp. 3. Removed commented out code. 4. Additional bugfix. No longer create a empty content list when OpenMW.cfg has no content files. --- apps/launcher/maindialog.cpp | 18 +------- apps/launcher/settingspage.cpp | 59 ++++++++++++++------------ apps/launcher/settingspage.hpp | 4 +- components/config/launchersettings.cpp | 6 +++ files/ui/settingspage.ui | 7 +++ 5 files changed, 49 insertions(+), 45 deletions(-) diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index b93d55c17..e4aa3e526 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -238,24 +238,8 @@ void Launcher::MainDialog::changePage(QListWidgetItem *current, QListWidgetItem current = previous; int currentIndex = iconWidget->row(current); -// int previousIndex = iconWidget->row(previous); - pagesWidget->setCurrentIndex(currentIndex); - - // DataFilesPage *previousPage = dynamic_cast(pagesWidget->widget(previousIndex)); - // DataFilesPage *currentPage = dynamic_cast(pagesWidget->widget(currentIndex)); - - // //special call to update/save data files page list view when it's displayed/hidden. - // if (previousPage) - // { - // if (previousPage->objectName() == "DataFilesPage") - // previousPage->saveSettings(); - // } - // else if (currentPage) - // { - // if (currentPage->objectName() == "DataFilesPage") - // currentPage->loadSettings(); - // } + mSettingsPage->resetProgressBar(); } bool Launcher::MainDialog::setupLauncherSettings() diff --git a/apps/launcher/settingspage.cpp b/apps/launcher/settingspage.cpp index c172a3121..a1f6fb0c2 100644 --- a/apps/launcher/settingspage.cpp +++ b/apps/launcher/settingspage.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include @@ -39,6 +40,7 @@ Launcher::SettingsPage::SettingsPage(Files::ConfigurationManager &cfg, mWizardInvoker = new ProcessInvoker(); mImporterInvoker = new ProcessInvoker(); + resetProgressBar(); connect(mWizardInvoker->getProcess(), SIGNAL(started()), this, SLOT(wizardStarted())); @@ -141,8 +143,13 @@ void Launcher::SettingsPage::on_importerButton_clicked() qDebug() << "arguments " << arguments; + // start the progress bar as a "bouncing ball" + progressBar->setMaximum(0); + progressBar->setValue(0); if (!mImporterInvoker->startProcess(QLatin1String("openmw-iniimporter"), arguments, false)) - return; + { + resetProgressBar(); + } } void Launcher::SettingsPage::on_browseButton_clicked() @@ -197,38 +204,36 @@ void Launcher::SettingsPage::importerStarted() void Launcher::SettingsPage::importerFinished(int exitCode, QProcess::ExitStatus exitStatus) { if (exitCode != 0 || exitStatus == QProcess::CrashExit) - return; - - // Importer may have changed settings, so refresh - mMain->reloadSettings(); - - // Import selected data files from openmw.cfg - if (addonsCheckBox->isChecked()) { - // Because we've reloaded settings, the current content list matches content in OpenMW.cfg - QString oldContentListName = mLauncherSettings.getCurrentContentListName(); - if (mProfileDialog->exec() == QDialog::Accepted) - { - // remove the current content list to prevent duplication - //... except, not allowed to delete the Default content list - if (oldContentListName.compare(DataFilesPage::mDefaultContentListName) != 0) - { - mLauncherSettings.removeContentList(oldContentListName); - } - - const QString newContentListName(mProfileDialog->lineEdit()->text()); - const QStringList files(mGameSettings.getContentList()); - mLauncherSettings.setCurrentContentListName(newContentListName); - mLauncherSettings.setContentList(newContentListName, files); - - // Make DataFiles Page load the new content list. - mMain->reloadSettings(); - } + resetProgressBar(); + + QMessageBox msgBox; + msgBox.setWindowTitle(tr("Importer finished")); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setIcon(QMessageBox::Warning); + msgBox.setText(tr("Failed to import settings from INI file.")); + msgBox.exec(); + } + else + { + // indicate progress finished + progressBar->setMaximum(1); + progressBar->setValue(1); + + // Importer may have changed settings, so refresh + mMain->reloadSettings(); } importerButton->setEnabled(true); } +void Launcher::SettingsPage::resetProgressBar() +{ + // set progress bar to 0 % + progressBar->setMaximum(1); + progressBar->setValue(0); +} + void Launcher::SettingsPage::updateOkButton(const QString &text) { // We do this here because we need to access the profiles diff --git a/apps/launcher/settingspage.hpp b/apps/launcher/settingspage.hpp index 124c80600..ccc2061dd 100644 --- a/apps/launcher/settingspage.hpp +++ b/apps/launcher/settingspage.hpp @@ -29,6 +29,9 @@ namespace Launcher void saveSettings(); bool loadSettings(); + + /// set progress bar on page to 0% + void resetProgressBar(); private slots: @@ -57,7 +60,6 @@ namespace Launcher MainDialog *mMain; TextInputDialog *mProfileDialog; - }; } diff --git a/components/config/launchersettings.cpp b/components/config/launchersettings.cpp index 66f05f691..1d4b428c9 100644 --- a/components/config/launchersettings.cpp +++ b/components/config/launchersettings.cpp @@ -105,6 +105,12 @@ void Config::LauncherSettings::setContentList(const GameSettings& gameSettings) // obtain content list from game settings (if present) const QStringList files(gameSettings.getContentList()); + // if openmw.cfg has no content, exit so we don't create an empty content list. + if (files.isEmpty()) + { + return; + } + // if any existing profile in launcher matches the content list, make that profile the default foreach(const QString &listName, getContentLists()) { diff --git a/files/ui/settingspage.ui b/files/ui/settingspage.ui index 6c873ea92..7f5e4a7de 100644 --- a/files/ui/settingspage.ui +++ b/files/ui/settingspage.ui @@ -131,6 +131,13 @@
+ + + + 4 + + + From 9708e8529fd4253bf34ee3243a68e562efd39368 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 22 Feb 2015 08:58:17 +1300 Subject: [PATCH 0592/3725] Removed unneeded include. --- apps/launcher/settingspage.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/launcher/settingspage.cpp b/apps/launcher/settingspage.cpp index a1f6fb0c2..5b26b01b9 100644 --- a/apps/launcher/settingspage.cpp +++ b/apps/launcher/settingspage.cpp @@ -4,7 +4,6 @@ #include #include #include -#include #include From 514fba5f733f296d995fb6fd6004addd7c20fedc Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 22 Feb 2015 10:02:25 +1300 Subject: [PATCH 0593/3725] On Windows content list imported from morrowind.ini is sorted by file modified time stamps. --- apps/mwiniimporter/importer.cpp | 42 +++++++++++++++++++++++++-------- apps/mwiniimporter/importer.hpp | 12 +++++++--- apps/mwiniimporter/main.cpp | 6 ++--- 3 files changed, 44 insertions(+), 16 deletions(-) diff --git a/apps/mwiniimporter/importer.cpp b/apps/mwiniimporter/importer.cpp index 80f186b1f..6b8424da6 100644 --- a/apps/mwiniimporter/importer.cpp +++ b/apps/mwiniimporter/importer.cpp @@ -8,7 +8,7 @@ #include #include -#include +#include #include namespace bfs = boost::filesystem; @@ -660,7 +660,7 @@ std::string MwIniImporter::numberToString(int n) { return str.str(); } -MwIniImporter::multistrmap MwIniImporter::loadIniFile(const std::string& filename) const { +MwIniImporter::multistrmap MwIniImporter::loadIniFile(const boost::filesystem::path& filename) const { std::cout << "load ini file: " << filename << std::endl; std::string section(""); @@ -719,7 +719,7 @@ MwIniImporter::multistrmap MwIniImporter::loadIniFile(const std::string& filenam return map; } -MwIniImporter::multistrmap MwIniImporter::loadCfgFile(const std::string& filename) { +MwIniImporter::multistrmap MwIniImporter::loadCfgFile(const boost::filesystem::path& filename) { std::cout << "load cfg file: " << filename << std::endl; MwIniImporter::multistrmap map; @@ -825,10 +825,14 @@ void MwIniImporter::importArchives(multistrmap &cfg, const multistrmap &ini) con } } -void MwIniImporter::importGameFiles(multistrmap &cfg, const multistrmap &ini) const { - std::vector contentFiles; +void MwIniImporter::importGameFiles(multistrmap &cfg, const multistrmap &ini, const boost::filesystem::path& iniFilename) const { + std::vector > contentFiles; std::string baseGameFile("Game Files:GameFile"); std::string gameFile(""); + std::time_t defaultTime = 0; + + // assume the Game Files are all in a "Data Files" directory under the directory holding Morrowind.ini + const boost::filesystem::path gameFilesDir(iniFilename.parent_path() /= "Data Files"); multistrmap::const_iterator it = ini.begin(); for(int i=0; it != ini.end(); i++) { @@ -845,18 +849,20 @@ void MwIniImporter::importGameFiles(multistrmap &cfg, const multistrmap &ini) co Misc::StringUtils::toLower(filetype); if(filetype.compare("esm") == 0 || filetype.compare("esp") == 0) { - contentFiles.push_back(*entry); + boost::filesystem::path filepath(gameFilesDir); + filepath /= *entry; + contentFiles.push_back(std::make_pair(lastWriteTime(filepath, defaultTime), *entry)); } } - - gameFile = ""; } cfg.erase("content"); cfg.insert( std::make_pair("content", std::vector() ) ); - for(std::vector::const_iterator it=contentFiles.begin(); it!=contentFiles.end(); ++it) { - cfg["content"].push_back(*it); + // this will sort files by time order first, then alphabetical (maybe), I suspect non ASCII filenames will be stuffed. + sort(contentFiles.begin(), contentFiles.end()); + for(std::vector >::const_iterator it=contentFiles.begin(); it!=contentFiles.end(); ++it) { + cfg["content"].push_back(it->second); } } @@ -873,3 +879,19 @@ void MwIniImporter::setInputEncoding(const ToUTF8::FromType &encoding) { mEncoding = encoding; } + +std::time_t MwIniImporter::lastWriteTime(const boost::filesystem::path& filename, std::time_t defaultTime) +{ + std::time_t writeTime(defaultTime); + if (boost::filesystem::exists(filename)) + { + writeTime = boost::filesystem::last_write_time(filename); + std::cout << "content file: " << filename << " timestamp = (" << writeTime << + ") " << asctime(localtime(&writeTime)) << std::endl; + } + else + { + std::cout << "content file: " << filename << " not found" << std::endl; + } + return writeTime; +} \ No newline at end of file diff --git a/apps/mwiniimporter/importer.hpp b/apps/mwiniimporter/importer.hpp index 72b14ba75..c73cc65b5 100644 --- a/apps/mwiniimporter/importer.hpp +++ b/apps/mwiniimporter/importer.hpp @@ -6,6 +6,7 @@ #include #include #include +#include #include @@ -17,17 +18,22 @@ class MwIniImporter { MwIniImporter(); void setInputEncoding(const ToUTF8::FromType& encoding); void setVerbose(bool verbose); - multistrmap loadIniFile(const std::string& filename) const; - static multistrmap loadCfgFile(const std::string& filename); + multistrmap loadIniFile(const boost::filesystem::path& filename) const; + static multistrmap loadCfgFile(const boost::filesystem::path& filename); void merge(multistrmap &cfg, const multistrmap &ini) const; void mergeFallback(multistrmap &cfg, const multistrmap &ini) const; - void importGameFiles(multistrmap &cfg, const multistrmap &ini) const; + void importGameFiles(multistrmap &cfg, const multistrmap &ini, + const boost::filesystem::path& iniFilename) const; void importArchives(multistrmap &cfg, const multistrmap &ini) const; static void writeToFile(std::ostream &out, const multistrmap &cfg); private: static void insertMultistrmap(multistrmap &cfg, const std::string& key, const std::string& value); static std::string numberToString(int n); + + /// \return file's "last modified time", used in original MW to determine plug-in load order + static std::time_t lastWriteTime(const boost::filesystem::path& filename, std::time_t defaultTime); + bool mVerbose; strmap mMergeMap; std::vector mMergeFallback; diff --git a/apps/mwiniimporter/main.cpp b/apps/mwiniimporter/main.cpp index f108678f3..3c48fedc9 100644 --- a/apps/mwiniimporter/main.cpp +++ b/apps/mwiniimporter/main.cpp @@ -93,8 +93,8 @@ int wmain(int argc, wchar_t *wargv[]) { bpo::notify(vm); - std::string iniFile = vm["ini"].as(); - std::string cfgFile = vm["cfg"].as(); + boost::filesystem::path iniFile(vm["ini"].as()); + boost::filesystem::path cfgFile(vm["cfg"].as()); // if no output is given, write back to cfg file std::string outputFile(vm["output"].as()); @@ -123,7 +123,7 @@ int wmain(int argc, wchar_t *wargv[]) { importer.mergeFallback(cfg, ini); if(vm.count("game-files")) { - importer.importGameFiles(cfg, ini); + importer.importGameFiles(cfg, ini, iniFile); } if(!vm.count("no-archives")) { From 5eadffd0c49c045eb5bca39a02f4bce311420833 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 22 Feb 2015 00:13:03 +0100 Subject: [PATCH 0594/3725] Make launcher's version label selectable so it can be copy-pasted into issue reports --- apps/launcher/maindialog.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index b93d55c17..64cd034cb 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -61,6 +61,7 @@ Launcher::MainDialog::MainDialog(QWidget *parent) QString revision(OPENMW_VERSION_COMMITHASH); QString tag(OPENMW_VERSION_TAGHASH); + versionLabel->setTextInteractionFlags(Qt::TextSelectableByMouse); if (!revision.isEmpty() && !tag.isEmpty()) { if (revision == tag) { From c21b59ecff764b774a3db95778c6434c04e0f8d5 Mon Sep 17 00:00:00 2001 From: Jordan Ayers Date: Sat, 21 Feb 2015 15:55:22 -0600 Subject: [PATCH 0595/3725] Teleportation: Avoid marking searched cells as changed. OMW Bug #1533 Only mark cells with the target marker / evidence chest as 'changed'. --- apps/openmw/mwworld/cellstore.hpp | 11 +++++++++++ apps/openmw/mwworld/worldimp.cpp | 33 ++++++++----------------------- 2 files changed, 19 insertions(+), 25 deletions(-) diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index f6f2a3b48..1d4e99532 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -184,6 +184,11 @@ namespace MWWorld throw std::runtime_error ("Storage for this type not exist in cells"); } + template + CellRefList& getReadOnly() { + throw std::runtime_error ("Read Only access not available for this type"); + } + bool isPointConnected(const int start, const int end) const; std::list aStarSearch(const int start, const int end) const; @@ -357,6 +362,12 @@ namespace MWWorld return mWeapons; } + template<> + inline CellRefList& CellStore::getReadOnly() + { + return mDoors; + } + bool operator== (const CellStore& left, const CellStore& right); bool operator!= (const CellStore& left, const CellStore& right); } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 54385cf83..dd730b32a 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2799,7 +2799,7 @@ namespace MWWorld MWWorld::CellStore *next = getInterior( *i ); if ( !next ) continue; - MWWorld::CellRefList& doors = next->get(); + MWWorld::CellRefList& doors = next->getReadOnly(); CellRefList::List& refList = doors.mList; // Check if any door in the cell leads to an exterior directly @@ -2838,6 +2838,8 @@ namespace MWWorld std::set< std::string >checkedCells; std::set< std::string >currentCells; std::set< std::string >nextCells; + MWWorld::Ptr closestMarker; + nextCells.insert( ptr.getCell()->getCell()->mName ); while ( !nextCells.empty() ) { currentCells = nextCells; @@ -2847,17 +2849,13 @@ namespace MWWorld checkedCells.insert( *i ); if ( !next ) continue; - MWWorld::CellRefList& statics = next->get(); - CellRefList::List& staticList = statics.mList; - for (CellRefList::List::iterator it = staticList.begin(); it != staticList.end(); ++it) + closestMarker = next->search( id ); + if ( !closestMarker.isEmpty() ) { - MWWorld::LiveCellRef& ref = *it; - if ( id == ref.mRef.getRefId() ) { - return MWWorld::Ptr( &ref, next ); - } + return closestMarker; } - MWWorld::CellRefList& doors = next->get(); + MWWorld::CellRefList& doors = next->getReadOnly(); CellRefList::List& doorList = doors.mList; // Check if any door in the cell leads to an exterior directly @@ -2865,10 +2863,6 @@ namespace MWWorld { MWWorld::LiveCellRef& ref = *it; - if ( id == ref.mRef.getRefId() ) { - return MWWorld::Ptr( &ref, next ); - } - if (!ref.mRef.getTeleport()) continue; if (ref.mRef.getDestCell().empty()) @@ -3085,18 +3079,7 @@ namespace MWWorld return; } - MWWorld::Ptr closestChest; - - MWWorld::CellRefList& containers = prison->get(); - CellRefList::List& refList = containers.mList; - for (CellRefList::List::iterator it = refList.begin(); it != refList.end(); ++it) - { - MWWorld::LiveCellRef& ref = *it; - if ( ref.mRef.getRefId() == "stolen_goods" ) { - closestChest = MWWorld::Ptr( &ref, prison ); - } - } - + MWWorld::Ptr closestChest = prison->search( "stolen_goods" ); if (!closestChest.isEmpty()) //Found a close chest { MWBase::Environment::get().getMechanicsManager()->confiscateStolenItems(ptr, closestChest); From f6128a85b2531806e2ef01b6d0c6f5ffd68ec6f5 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 22 Feb 2015 13:48:44 +1300 Subject: [PATCH 0596/3725] resolve symlinks when searching for file's last modified time. --- apps/mwiniimporter/importer.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/apps/mwiniimporter/importer.cpp b/apps/mwiniimporter/importer.cpp index 6b8424da6..b71ebd2b8 100644 --- a/apps/mwiniimporter/importer.cpp +++ b/apps/mwiniimporter/importer.cpp @@ -883,15 +883,16 @@ void MwIniImporter::setInputEncoding(const ToUTF8::FromType &encoding) std::time_t MwIniImporter::lastWriteTime(const boost::filesystem::path& filename, std::time_t defaultTime) { std::time_t writeTime(defaultTime); - if (boost::filesystem::exists(filename)) + boost::filesystem::path resolved = boost::filesystem::canonical(filename); + if (boost::filesystem::exists(resolved)) { - writeTime = boost::filesystem::last_write_time(filename); - std::cout << "content file: " << filename << " timestamp = (" << writeTime << + writeTime = boost::filesystem::last_write_time(resolved); + std::cout << "content file: " << resolved << " timestamp = (" << writeTime << ") " << asctime(localtime(&writeTime)) << std::endl; } else { - std::cout << "content file: " << filename << " not found" << std::endl; + std::cout << "content file: " << resolved << " not found" << std::endl; } return writeTime; } \ No newline at end of file From 8f0ab7d09fcc8f6fe52733b435a15f4f4b5ea234 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 22 Feb 2015 14:12:05 +0100 Subject: [PATCH 0597/3725] ESM component no longer relies on Ogre DataStreams --- components/esm/esmreader.cpp | 44 +++++++++++++--------- components/esm/esmreader.hpp | 17 ++++----- components/esm/loadscpt.cpp | 2 + components/files/constrainedfilestream.cpp | 20 ++++++---- 4 files changed, 49 insertions(+), 34 deletions(-) diff --git a/components/esm/esmreader.cpp b/components/esm/esmreader.cpp index bbe475ff7..2762a1fc9 100644 --- a/components/esm/esmreader.cpp +++ b/components/esm/esmreader.cpp @@ -16,7 +16,7 @@ using namespace Misc; ESM_Context ESMReader::getContext() { // Update the file position before returning - mCtx.filePos = mEsm->tell(); + mCtx.filePos = mEsm->tellg(); return mCtx; } @@ -44,12 +44,12 @@ void ESMReader::restoreContext(const ESM_Context &rc) mCtx = rc; // Make sure we seek to the right place - mEsm->seek(mCtx.filePos); + mEsm->seekg(mCtx.filePos); } void ESMReader::close() { - mEsm.setNull(); + mEsm.reset(); mCtx.filename.clear(); mCtx.leftFile = 0; mCtx.leftRec = 0; @@ -59,15 +59,22 @@ void ESMReader::close() mCtx.subName.val = 0; } -void ESMReader::openRaw(Ogre::DataStreamPtr _esm, const std::string &name) +void ESMReader::openRaw(Files::IStreamPtr _esm, const std::string& name) { close(); mEsm = _esm; mCtx.filename = name; - mCtx.leftFile = mEsm->size(); + mEsm->seekg(0, mEsm->end); + mCtx.leftFile = mEsm->tellg(); + mEsm->seekg(0, mEsm->beg); } -void ESMReader::open(Ogre::DataStreamPtr _esm, const std::string &name) +void ESMReader::openRaw(const std::string& filename) +{ + openRaw(Files::openConstrainedFileStream(filename.c_str()), filename); +} + +void ESMReader::open(Files::IStreamPtr _esm, const std::string &name) { openRaw(_esm, name); @@ -81,12 +88,7 @@ void ESMReader::open(Ogre::DataStreamPtr _esm, const std::string &name) void ESMReader::open(const std::string &file) { - open (openConstrainedFileDataStream (file.c_str ()), file); -} - -void ESMReader::openRaw(const std::string &file) -{ - openRaw (openConstrainedFileDataStream (file.c_str ()), file); + open (Files::openConstrainedFileStream (file.c_str ()), file); } int64_t ESMReader::getHNLong(const char *name) @@ -296,9 +298,7 @@ void ESMReader::getExact(void*x, int size) { try { - int t = mEsm->read(x, size); - if (t != size) - fail("Read error"); + mEsm->read((char*)x, size); } catch (std::exception& e) { @@ -340,8 +340,8 @@ void ESMReader::fail(const std::string &msg) ss << "\n File: " << mCtx.filename; ss << "\n Record: " << mCtx.recName.toString(); ss << "\n Subrecord: " << mCtx.subName.toString(); - if (!mEsm.isNull()) - ss << "\n Offset: 0x" << hex << mEsm->tell(); + if (mEsm.get()) + ss << "\n Offset: 0x" << hex << mEsm->tellg(); throw std::runtime_error(ss.str()); } @@ -350,4 +350,14 @@ void ESMReader::setEncoder(ToUTF8::Utf8Encoder* encoder) mEncoder = encoder; } +size_t ESMReader::getFileOffset() +{ + return mEsm->tellg(); +} + +void ESMReader::skip(int bytes) +{ + mEsm->seekg(getFileOffset()+bytes); +} + } diff --git a/components/esm/esmreader.hpp b/components/esm/esmreader.hpp index ebbc935f6..31fc3e32d 100644 --- a/components/esm/esmreader.hpp +++ b/components/esm/esmreader.hpp @@ -7,7 +7,7 @@ #include #include -#include +#include #include @@ -63,20 +63,18 @@ public: /// Raw opening. Opens the file and sets everything up but doesn't /// parse the header. - void openRaw(Ogre::DataStreamPtr _esm, const std::string &name); + void openRaw(Files::IStreamPtr _esm, const std::string &name); /// Load ES file from a new stream, parses the header. Closes the /// currently open file first, if any. - void open(Ogre::DataStreamPtr _esm, const std::string &name); + void open(Files::IStreamPtr _esm, const std::string &name); void open(const std::string &file); - void openRaw(const std::string &file); + void openRaw(const std::string &filename); - /// 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(); } + size_t getFileOffset(); // 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 @@ -252,8 +250,7 @@ public: // them from native encoding to UTF8 in the process. std::string getString(int size); - void skip(int bytes) { mEsm->seek(mEsm->tell()+bytes); } - uint64_t getOffset() { return mEsm->tell(); } + void skip(int bytes); /// Used for error handling void fail(const std::string &msg); @@ -265,7 +262,7 @@ public: unsigned int getRecordFlags() { return mRecordFlags; } private: - Ogre::DataStreamPtr mEsm; + Files::IStreamPtr mEsm; ESM_Context mCtx; diff --git a/components/esm/loadscpt.cpp b/components/esm/loadscpt.cpp index 2df8e66ce..d9eb7290c 100644 --- a/components/esm/loadscpt.cpp +++ b/components/esm/loadscpt.cpp @@ -4,6 +4,8 @@ #include "esmwriter.hpp" #include "defs.hpp" +#include + namespace ESM { diff --git a/components/files/constrainedfilestream.cpp b/components/files/constrainedfilestream.cpp index fddfa7e52..23eab2088 100644 --- a/components/files/constrainedfilestream.cpp +++ b/components/files/constrainedfilestream.cpp @@ -1,6 +1,7 @@ #include "constrainedfilestream.hpp" #include +#include #include "lowlevelfile.hpp" @@ -28,6 +29,8 @@ namespace Files if (start != 0) mFile.seek(start); + setg(0,0,0); + mOrigin = start; } @@ -35,11 +38,11 @@ namespace Files { if(gptr() == egptr()) { + size_t toRead = std::min((mOrigin+mSize)-(mFile.tell()), sBufferSize); // Read in the next chunk of data, and set the read pointers on success - size_t got = mFile.read(mBuffer, sBufferSize); // Failure will throw exception in LowLevelFile - /*if(got != -1) */ - setg(&mBuffer[0], &mBuffer[0], mBuffer+got); + size_t got = mFile.read(mBuffer, toRead); + setg(&mBuffer[0], &mBuffer[0], &mBuffer[0]+got); } if(gptr() == egptr()) return traits_type::eof(); @@ -60,7 +63,7 @@ namespace Files newPos = offset; break; case std::ios_base::cur: - newPos = (mFile.tell() - mOrigin) + offset; + newPos = (mFile.tell() - mOrigin - (egptr() - gptr())) + offset; break; case std::ios_base::end: newPos = mSize + offset; @@ -68,9 +71,11 @@ namespace Files default: return traits_type::eof(); } - mFile.seek(mOrigin+newPos); - // EOF handled by exception in LowLevelFile + if (newPos > mSize) + return traits_type::eof(); + + mFile.seek(mOrigin+newPos); // Clear read pointers so underflow() gets called on the next read attempt. setg(0, 0, 0); @@ -83,8 +88,9 @@ namespace Files if((mode&std::ios_base::out) || !(mode&std::ios_base::in)) return traits_type::eof(); - if(pos >= (int)mSize) + if ((size_t)pos > mSize) return traits_type::eof(); + mFile.seek(mOrigin + pos); // Clear read pointers so underflow() gets called on the next read attempt. From 227c7bb55f7c4e8896d15450d8efc8362bd5c795 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 22 Feb 2015 14:14:13 +0100 Subject: [PATCH 0598/3725] esmtool works again --- apps/esmtool/esmtool.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/esmtool/esmtool.cpp b/apps/esmtool/esmtool.cpp index 98e18521e..3347aaf34 100644 --- a/apps/esmtool/esmtool.cpp +++ b/apps/esmtool/esmtool.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include @@ -284,7 +285,7 @@ void printRaw(ESM::ESMReader &esm) esm.getRecHeader(); while(esm.hasMoreSubs()) { - uint64_t offs = esm.getOffset(); + size_t offs = esm.getFileOffset(); esm.getSubName(); esm.skipHSub(); n = esm.retSubName(); From da690c91b34ed5cede12242b0e20a7d60dffa634 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 22 Feb 2015 14:19:00 +0100 Subject: [PATCH 0599/3725] Delete the old Ogre DataStream class --- components/CMakeLists.txt | 2 +- components/esm/esmreader.cpp | 3 +- .../files/constrainedfiledatastream.cpp | 182 ------------------ .../files/constrainedfiledatastream.hpp | 8 - 4 files changed, 2 insertions(+), 193 deletions(-) delete mode 100644 components/files/constrainedfiledatastream.cpp delete mode 100644 components/files/constrainedfiledatastream.hpp diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index ecaeb115b..43fca28e8 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -79,7 +79,7 @@ IF(NOT WIN32 AND NOT APPLE) ENDIF() add_component_dir (files linuxpath androidpath windowspath macospath fixedpath multidircollection collections configurationmanager - constrainedfiledatastream lowlevelfile constrainedfilestream + lowlevelfile constrainedfilestream ) add_component_dir (compiler diff --git a/components/esm/esmreader.cpp b/components/esm/esmreader.cpp index 2762a1fc9..933d89099 100644 --- a/components/esm/esmreader.cpp +++ b/components/esm/esmreader.cpp @@ -1,7 +1,6 @@ #include "esmreader.hpp" -#include -#include "../files/constrainedfiledatastream.hpp" +#include namespace ESM { diff --git a/components/files/constrainedfiledatastream.cpp b/components/files/constrainedfiledatastream.cpp deleted file mode 100644 index d4d7c231a..000000000 --- a/components/files/constrainedfiledatastream.cpp +++ /dev/null @@ -1,182 +0,0 @@ -#include "constrainedfiledatastream.hpp" -#include "lowlevelfile.hpp" - -#include -#include - -#include - -namespace { - -class ConstrainedDataStream : public Ogre::DataStream { -public: - - static const size_t sBufferSize = 4096; // somewhat arbitrary though 64KB buffers didn't seem to improve performance any - static const size_t sBufferThreshold = 1024; // reads larger than this bypass buffering as cost of memcpy outweighs cost of system call - - ConstrainedDataStream(const Ogre::String &fname, size_t start, size_t length) - : Ogre::DataStream(fname) - { - mFile.open (fname.c_str ()); - mSize = length != 0xFFFFFFFF ? length : mFile.size () - start; - - mPos = 0; - mOrigin = start; - mExtent = start + mSize; - - mBufferOrigin = 0; - mBufferExtent = 0; - } - - - size_t read(void* buf, size_t count) - { - try - { - assert (mPos <= mSize); - - uint8_t * out = reinterpret_cast (buf); - - size_t posBeg = mOrigin + mPos; - size_t posEnd = posBeg + count; - - if (posEnd > mExtent) - posEnd = mExtent; - - size_t posCur = posBeg; - - while (posCur != posEnd) - { - size_t readLeft = posEnd - posCur; - - if (posCur < mBufferOrigin || posCur >= mBufferExtent) - { - if (readLeft >= sBufferThreshold || (posCur == mOrigin && posEnd == mExtent)) - { - assert (mFile.tell () == mBufferExtent); - - if (posCur != mBufferExtent) - mFile.seek (posCur); - - posCur += mFile.read (out, readLeft); - - mBufferOrigin = mBufferExtent = posCur; - - mPos = posCur - mOrigin; - - return posCur - posBeg; - } - else - { - size_t newBufferOrigin; - - if ((posCur < mBufferOrigin) && (mBufferOrigin - posCur < sBufferSize)) - newBufferOrigin = std::max (mOrigin, mBufferOrigin > sBufferSize ? mBufferOrigin - sBufferSize : 0); - else - newBufferOrigin = posCur; - - fill (newBufferOrigin); - } - } - - size_t xfer = std::min (readLeft, mBufferExtent - posCur); - - memcpy (out, mBuffer + (posCur - mBufferOrigin), xfer); - - posCur += xfer; - out += xfer; - } - - count = posEnd - posBeg; - mPos += count; - return count; - } - catch (std::exception& e) - { - std::stringstream error; - error << "Failed to read '" << mName << "': " << e.what(); - throw std::runtime_error(error.str()); - } - } - - void skip(long count) - { - assert (mPos <= mSize); - - if((count >= 0 && (size_t)count <= mSize-mPos) || - (count < 0 && (size_t)-count <= mPos)) - mPos += count; - } - - void seek(size_t pos) - { - assert (mPos <= mSize); - - if (pos < mSize) - mPos = pos; - } - - virtual size_t tell() const - { - assert (mPos <= mSize); - - return mPos; - } - - virtual bool eof() const - { - assert (mPos <= mSize); - - return mPos == mSize; - } - - virtual void close() - { - mFile.close(); - } - -private: - - void fill (size_t newOrigin) - { - assert (mFile.tell () == mBufferExtent); - - size_t newExtent = newOrigin + sBufferSize; - - if (newExtent > mExtent) - newExtent = mExtent; - - size_t oldExtent = mBufferExtent; - - if (newOrigin != oldExtent) - mFile.seek (newOrigin); - - mBufferOrigin = mBufferExtent = newOrigin; - - size_t amountRequested = newExtent - newOrigin; - - size_t amountRead = mFile.read (mBuffer, amountRequested); - - if (amountRead != amountRequested) - throw std::runtime_error ("An unexpected condition occurred while reading from a file."); - - mBufferExtent = newExtent; - } - - LowLevelFile mFile; - - size_t mOrigin; - size_t mExtent; - size_t mPos; - - uint8_t mBuffer [sBufferSize]; - size_t mBufferOrigin; - size_t mBufferExtent; -}; - -} // end of unnamed namespace - -Ogre::DataStreamPtr openConstrainedFileDataStream (char const * filename, size_t offset, size_t length) -{ - return Ogre::DataStreamPtr(new ConstrainedDataStream(filename, offset, length)); -} diff --git a/components/files/constrainedfiledatastream.hpp b/components/files/constrainedfiledatastream.hpp deleted file mode 100644 index 367defcbc..000000000 --- a/components/files/constrainedfiledatastream.hpp +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef COMPONENTS_FILES_CONSTRAINEDFILEDATASTREAM_HPP -#define COMPONENTS_FILES_CONSTRAINEDFILEDATASTREAM_HPP - -#include - -Ogre::DataStreamPtr openConstrainedFileDataStream (char const * filename, size_t offset = 0, size_t length = 0xFFFFFFFF); - -#endif // COMPONENTS_FILES_CONSTRAINEDFILEDATASTREAM_HPP From 387969bf4250f95c9cffd5d5ccd8ae8a5b5a55bd Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 22 Feb 2015 18:05:46 +0100 Subject: [PATCH 0600/3725] Remove an old .gitignore --- components/nif/.gitignore | 1 - 1 file changed, 1 deletion(-) delete mode 100644 components/nif/.gitignore diff --git a/components/nif/.gitignore b/components/nif/.gitignore deleted file mode 100644 index 731498d9a..000000000 --- a/components/nif/.gitignore +++ /dev/null @@ -1 +0,0 @@ -old_d From 399259a95cb1632ec1f183602c4dc77564786308 Mon Sep 17 00:00:00 2001 From: Jordan Ayers Date: Sun, 22 Feb 2015 12:12:54 -0600 Subject: [PATCH 0601/3725] Improve CellStore exception messages. --- apps/openmw/mwworld/cellstore.hpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index 1d4e99532..cd7af5ad6 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -3,6 +3,8 @@ #include #include +#include +#include #include #include "livecellref.hpp" @@ -181,12 +183,12 @@ namespace MWWorld template CellRefList& get() { - throw std::runtime_error ("Storage for this type not exist in cells"); + throw std::runtime_error ("Storage for type " + std::string(typeid(T).name())+ " does not exist in cells"); } template CellRefList& getReadOnly() { - throw std::runtime_error ("Read Only access not available for this type"); + throw std::runtime_error ("Read Only CellRefList access not available for type " + std::string(typeid(T).name()) ); } bool isPointConnected(const int start, const int end) const; From 6b36e55a4e78df0a7e996bd8dfa55895ce78e15e Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 22 Feb 2015 19:17:03 +0100 Subject: [PATCH 0602/3725] NIF reader cleanup: move definitions to cpp file --- components/nif/base.hpp | 22 +--- components/nif/controlled.hpp | 78 ++----------- components/nif/controller.hpp | 182 +++-------------------------- components/nif/data.cpp | 209 +++++++++++++++++++++++++++++++++ components/nif/data.hpp | 210 +++------------------------------- components/nif/effect.hpp | 52 +-------- components/nif/extra.hpp | 35 +----- components/nif/nifkey.hpp | 4 + components/nif/property.hpp | 109 ++---------------- components/nif/record.hpp | 6 - 10 files changed, 274 insertions(+), 633 deletions(-) diff --git a/components/nif/base.hpp b/components/nif/base.hpp index 30c652b64..4b2e40dec 100644 --- a/components/nif/base.hpp +++ b/components/nif/base.hpp @@ -32,26 +32,8 @@ public: float timeStart, timeStop; ControlledPtr target; - void read(NIFStream *nif) - { - next.read(nif); - - flags = nif->getUShort(); - - frequency = nif->getFloat(); - phase = nif->getFloat(); - timeStart = nif->getFloat(); - timeStop = nif->getFloat(); - - target.read(nif); - } - - void post(NIFFile *nif) - { - Record::post(nif); - next.post(nif); - target.post(nif); - } + void read(NIFStream *nif); + void post(NIFFile *nif); }; /// Anything that has a controller diff --git a/components/nif/controlled.hpp b/components/nif/controlled.hpp index 51890f069..ac75c3508 100644 --- a/components/nif/controlled.hpp +++ b/components/nif/controlled.hpp @@ -62,31 +62,8 @@ public: */ int alpha; - void read(NIFStream *nif) - { - Named::read(nif); - - external = !!nif->getChar(); - if(external) - filename = nif->getString(); - else - { - nif->getChar(); // always 1 - data.read(nif); - } - - pixel = nif->getInt(); - mipmap = nif->getInt(); - alpha = nif->getInt(); - - nif->getChar(); // always 1 - } - - void post(NIFFile *nif) - { - Named::post(nif); - data.post(nif); - } + void read(NIFStream *nif); + void post(NIFFile *nif); }; class NiParticleGrowFade : public Controlled @@ -95,12 +72,7 @@ public: float growTime; float fadeTime; - void read(NIFStream *nif) - { - Controlled::read(nif); - growTime = nif->getFloat(); - fadeTime = nif->getFloat(); - } + void read(NIFStream *nif); }; class NiParticleColorModifier : public Controlled @@ -108,17 +80,8 @@ class NiParticleColorModifier : public Controlled public: NiColorDataPtr data; - void read(NIFStream *nif) - { - Controlled::read(nif); - data.read(nif); - } - - void post(NIFFile *nif) - { - Controlled::post(nif); - data.post(nif); - } + void read(NIFStream *nif); + void post(NIFFile *nif); }; class NiGravity : public Controlled @@ -132,45 +95,20 @@ public: osg::Vec3f mPosition; osg::Vec3f mDirection; - void read(NIFStream *nif) - { - Controlled::read(nif); - - /*unknown*/nif->getFloat(); - mForce = nif->getFloat(); - mType = nif->getUInt(); - mPosition = nif->getVector3(); - mDirection = nif->getVector3(); - } + void read(NIFStream *nif); }; // NiPinaColada class NiPlanarCollider : public Controlled { public: - void read(NIFStream *nif) - { - Controlled::read(nif); - - // (I think) 4 floats + 4 vectors - nif->skip(4*16); - } + void read(NIFStream *nif); }; class NiParticleRotation : public Controlled { public: - void read(NIFStream *nif) - { - Controlled::read(nif); - - /* - byte (0 or 1) - float (1) - float*3 - */ - nif->skip(17); - } + void read(NIFStream *nif); }; diff --git a/components/nif/controller.hpp b/components/nif/controller.hpp index 718748c31..73344e77b 100644 --- a/components/nif/controller.hpp +++ b/components/nif/controller.hpp @@ -74,66 +74,8 @@ public: ExtraPtr extra; - void read(NIFStream *nif) - { - Controller::read(nif); - - velocity = nif->getFloat(); - velocityRandom = nif->getFloat(); - verticalDir = nif->getFloat(); - verticalAngle = nif->getFloat(); - horizontalDir = nif->getFloat(); - horizontalAngle = nif->getFloat(); - /*normal?*/ nif->getVector3(); - /*color?*/ nif->getVector4(); - size = nif->getFloat(); - startTime = nif->getFloat(); - stopTime = nif->getFloat(); - nif->getChar(); - emitRate = nif->getFloat(); - lifetime = nif->getFloat(); - lifetimeRandom = nif->getFloat(); - - emitFlags = nif->getUShort(); - offsetRandom = nif->getVector3(); - - emitter.read(nif); - - /* Unknown Short, 0? - * Unknown Float, 1.0? - * Unknown Int, 1? - * Unknown Int, 0? - * Unknown Short, 0? - */ - nif->skip(16); - - numParticles = nif->getUShort(); - activeCount = nif->getUShort(); - - particles.resize(numParticles); - for(size_t i = 0;i < particles.size();i++) - { - particles[i].velocity = nif->getVector3(); - nif->getVector3(); /* unknown */ - particles[i].lifetime = nif->getFloat(); - particles[i].lifespan = nif->getFloat(); - particles[i].timestamp = nif->getFloat(); - nif->getUShort(); /* unknown */ - particles[i].vertex = nif->getUShort(); - } - - nif->getUInt(); /* -1? */ - extra.read(nif); - nif->getUInt(); /* -1? */ - nif->getChar(); - } - - void post(NIFFile *nif) - { - Controller::post(nif); - emitter.post(nif); - extra.post(nif); - } + void read(NIFStream *nif); + void post(NIFFile *nif); }; typedef NiParticleSystemController NiBSPArrayController; @@ -142,17 +84,8 @@ class NiMaterialColorController : public Controller public: NiPosDataPtr data; - void read(NIFStream *nif) - { - Controller::read(nif); - data.read(nif); - } - - void post(NIFFile *nif) - { - Controller::post(nif); - data.post(nif); - } + void read(NIFStream *nif); + void post(NIFFile *nif); }; class NiPathController : public Controller @@ -161,27 +94,8 @@ public: NiPosDataPtr posData; NiFloatDataPtr floatData; - void read(NIFStream *nif) - { - Controller::read(nif); - - /* - int = 1 - 2xfloat - short = 0 or 1 - */ - nif->skip(14); - posData.read(nif); - floatData.read(nif); - } - - void post(NIFFile *nif) - { - Controller::post(nif); - - posData.post(nif); - floatData.post(nif); - } + void read(NIFStream *nif); + void post(NIFFile *nif); }; class NiUVController : public Controller @@ -189,19 +103,8 @@ class NiUVController : public Controller public: NiUVDataPtr data; - void read(NIFStream *nif) - { - Controller::read(nif); - - nif->getUShort(); // always 0 - data.read(nif); - } - - void post(NIFFile *nif) - { - Controller::post(nif); - data.post(nif); - } + void read(NIFStream *nif); + void post(NIFFile *nif); }; class NiKeyframeController : public Controller @@ -209,17 +112,8 @@ class NiKeyframeController : public Controller public: NiKeyframeDataPtr data; - void read(NIFStream *nif) - { - Controller::read(nif); - data.read(nif); - } - - void post(NIFFile *nif) - { - Controller::post(nif); - data.post(nif); - } + void read(NIFStream *nif); + void post(NIFFile *nif); }; class NiAlphaController : public Controller @@ -227,17 +121,8 @@ class NiAlphaController : public Controller public: NiFloatDataPtr data; - void read(NIFStream *nif) - { - Controller::read(nif); - data.read(nif); - } - - void post(NIFFile *nif) - { - Controller::post(nif); - data.post(nif); - } + void read(NIFStream *nif); + void post(NIFFile *nif); }; class NiGeomMorpherController : public Controller @@ -245,18 +130,8 @@ class NiGeomMorpherController : public Controller public: NiMorphDataPtr data; - void read(NIFStream *nif) - { - Controller::read(nif); - data.read(nif); - nif->getChar(); // always 0 - } - - void post(NIFFile *nif) - { - Controller::post(nif); - data.post(nif); - } + void read(NIFStream *nif); + void post(NIFFile *nif); }; class NiVisController : public Controller @@ -264,17 +139,8 @@ class NiVisController : public Controller public: NiVisDataPtr data; - void read(NIFStream *nif) - { - Controller::read(nif); - data.read(nif); - } - - void post(NIFFile *nif) - { - Controller::post(nif); - data.post(nif); - } + void read(NIFStream *nif); + void post(NIFFile *nif); }; class NiFlipController : public Controller @@ -284,20 +150,8 @@ public: float mDelta; // Time between two flips. delta = (start_time - stop_time) / num_sources NiSourceTextureList mSources; - void read(NIFStream *nif) - { - Controller::read(nif); - mTexSlot = nif->getUInt(); - /*unknown=*/nif->getUInt();/*0?*/ - mDelta = nif->getFloat(); - mSources.read(nif); - } - - void post(NIFFile *nif) - { - Controller::post(nif); - mSources.post(nif); - } + void read(NIFStream *nif); + void post(NIFFile *nif); }; } // Namespace diff --git a/components/nif/data.cpp b/components/nif/data.cpp index 4248b93d2..c4de1e1bf 100644 --- a/components/nif/data.cpp +++ b/components/nif/data.cpp @@ -3,6 +3,13 @@ namespace Nif { +void NiSkinInstance::read(NIFStream *nif) +{ + data.read(nif); + root.read(nif); + bones.read(nif); +} + void NiSkinInstance::post(NIFFile *nif) { data.post(nif); @@ -26,4 +33,206 @@ void NiSkinInstance::post(NIFFile *nif) } } +void ShapeData::read(NIFStream *nif) +{ + int verts = nif->getUShort(); + + if(nif->getInt()) + nif->getVector3s(vertices, verts); + + if(nif->getInt()) + nif->getVector3s(normals, verts); + + center = nif->getVector3(); + radius = nif->getFloat(); + + if(nif->getInt()) + nif->getVector4s(colors, verts); + + // Only the first 6 bits are used as a count. I think the rest are + // flags of some sort. + int uvs = nif->getUShort(); + uvs &= 0x3f; + + if(nif->getInt()) + { + uvlist.resize(uvs); + for(int i = 0;i < uvs;i++) + nif->getVector2s(uvlist[i], verts); + } +} + +void NiTriShapeData::read(NIFStream *nif) +{ + ShapeData::read(nif); + + /*int tris =*/ nif->getUShort(); + + // We have three times as many vertices as triangles, so this + // is always equal to tris*3. + int cnt = nif->getInt(); + nif->getShorts(triangles, cnt); + + // Read the match list, which lists the vertices that are equal to + // vertices. We don't actually need need this for anything, so + // just skip it. + int verts = nif->getUShort(); + for(int i=0;i < verts;i++) + { + // Number of vertices matching vertex 'i' + int num = nif->getUShort(); + nif->skip(num * sizeof(short)); + } +} + +void NiAutoNormalParticlesData::read(NIFStream *nif) +{ + ShapeData::read(nif); + + // Should always match the number of vertices + numParticles = nif->getUShort(); + + particleRadius = nif->getFloat(); + activeCount = nif->getUShort(); + + if(nif->getInt()) + { + // Particle sizes + nif->getFloats(sizes, vertices.size()); + } +} + +void NiRotatingParticlesData::read(NIFStream *nif) +{ + NiAutoNormalParticlesData::read(nif); + + if(nif->getInt()) + { + // Rotation quaternions. + nif->getQuaternions(rotations, vertices.size()); + } +} + +void NiPosData::read(NIFStream *nif) +{ + mKeyList.read(nif); +} + +void NiUVData::read(NIFStream *nif) +{ + for(int i = 0;i < 4;i++) + mKeyList[i].read(nif); +} + +void NiFloatData::read(NIFStream *nif) +{ + mKeyList.read(nif); +} + +void NiPixelData::read(NIFStream *nif) +{ + nif->getInt(); // always 0 or 1 + + rmask = nif->getInt(); // usually 0xff + gmask = nif->getInt(); // usually 0xff00 + bmask = nif->getInt(); // usually 0xff0000 + amask = nif->getInt(); // usually 0xff000000 or zero + + bpp = nif->getInt(); + + // Unknown + nif->skip(12); + + mips = nif->getInt(); + + // Bytes per pixel, should be bpp * 8 + /*int bytes =*/ nif->getInt(); + + for(int i=0; igetInt(); + /*int y =*/ nif->getInt(); + /*int offset =*/ nif->getInt(); + } + + // Skip the data + unsigned int dataSize = nif->getInt(); + nif->skip(dataSize); +} + +void NiColorData::read(NIFStream *nif) +{ + mKeyMap.read(nif); +} + +void NiVisData::read(NIFStream *nif) +{ + int count = nif->getInt(); + mVis.resize(count); + for(size_t i = 0;i < mVis.size();i++) + { + mVis[i].time = nif->getFloat(); + mVis[i].isSet = nif->getChar(); + } +} + +void NiSkinData::read(NIFStream *nif) +{ + trafo.rotation = nif->getMatrix3(); + trafo.pos = nif->getVector3(); + trafo.scale = nif->getFloat(); + + int boneNum = nif->getInt(); + nif->getInt(); // -1 + + bones.resize(boneNum); + for(int i=0;igetMatrix3(); + bi.trafo.pos = nif->getVector3(); + bi.trafo.scale = nif->getFloat(); + bi.unknown = nif->getVector4(); + + // Number of vertex weights + bi.weights.resize(nif->getUShort()); + for(size_t j = 0;j < bi.weights.size();j++) + { + bi.weights[j].vertex = nif->getUShort(); + bi.weights[j].weight = nif->getFloat(); + } + } +} + +void NiMorphData::read(NIFStream *nif) +{ + int morphCount = nif->getInt(); + int vertCount = nif->getInt(); + /*relative targets?*/nif->getChar(); + + mMorphs.resize(morphCount); + for(int i = 0;i < morphCount;i++) + { + mMorphs[i].mData.read(nif, true); + nif->getVector3s(mMorphs[i].mVertices, vertCount); + } +} + +void NiKeyframeData::read(NIFStream *nif) +{ + mRotations.read(nif); + if(mRotations.mInterpolationType == mRotations.sXYZInterpolation) + { + //Chomp unused float + nif->getFloat(); + mXRotations.read(nif, true); + mYRotations.read(nif, true); + mZRotations.read(nif, true); + } + mTranslations.read(nif); + mScales.read(nif); +} + } // Namespace diff --git a/components/nif/data.hpp b/components/nif/data.hpp index 656d27628..3b1244831 100644 --- a/components/nif/data.hpp +++ b/components/nif/data.hpp @@ -41,34 +41,7 @@ public: osg::Vec3f center; float radius; - void read(NIFStream *nif) - { - int verts = nif->getUShort(); - - if(nif->getInt()) - nif->getVector3s(vertices, verts); - - if(nif->getInt()) - nif->getVector3s(normals, verts); - - center = nif->getVector3(); - radius = nif->getFloat(); - - if(nif->getInt()) - nif->getVector4s(colors, verts); - - // Only the first 6 bits are used as a count. I think the rest are - // flags of some sort. - int uvs = nif->getUShort(); - uvs &= 0x3f; - - if(nif->getInt()) - { - uvlist.resize(uvs); - for(int i = 0;i < uvs;i++) - nif->getVector2s(uvlist[i], verts); - } - } + void read(NIFStream *nif); }; class NiTriShapeData : public ShapeData @@ -77,28 +50,7 @@ public: // Triangles, three vertex indices per triangle std::vector triangles; - void read(NIFStream *nif) - { - ShapeData::read(nif); - - /*int tris =*/ nif->getUShort(); - - // We have three times as many vertices as triangles, so this - // is always equal to tris*3. - int cnt = nif->getInt(); - nif->getShorts(triangles, cnt); - - // Read the match list, which lists the vertices that are equal to - // vertices. We don't actually need need this for anything, so - // just skip it. - int verts = nif->getUShort(); - for(int i=0;i < verts;i++) - { - // Number of vertices matching vertex 'i' - int num = nif->getUShort(); - nif->skip(num * sizeof(short)); - } - } + void read(NIFStream *nif); }; class NiAutoNormalParticlesData : public ShapeData @@ -112,22 +64,7 @@ public: std::vector sizes; - void read(NIFStream *nif) - { - ShapeData::read(nif); - - // Should always match the number of vertices - numParticles = nif->getUShort(); - - particleRadius = nif->getFloat(); - activeCount = nif->getUShort(); - - if(nif->getInt()) - { - // Particle sizes - nif->getFloats(sizes, vertices.size()); - } - } + void read(NIFStream *nif); }; class NiRotatingParticlesData : public NiAutoNormalParticlesData @@ -135,16 +72,7 @@ class NiRotatingParticlesData : public NiAutoNormalParticlesData public: std::vector rotations; - void read(NIFStream *nif) - { - NiAutoNormalParticlesData::read(nif); - - if(nif->getInt()) - { - // Rotation quaternions. - nif->getQuaternions(rotations, vertices.size()); - } - } + void read(NIFStream *nif); }; class NiPosData : public Record @@ -152,10 +80,7 @@ class NiPosData : public Record public: Vector3KeyMap mKeyList; - void read(NIFStream *nif) - { - mKeyList.read(nif); - } + void read(NIFStream *nif); }; class NiUVData : public Record @@ -163,11 +88,7 @@ class NiUVData : public Record public: FloatKeyMap mKeyList[4]; - void read(NIFStream *nif) - { - for(int i = 0;i < 4;i++) - mKeyList[i].read(nif); - } + void read(NIFStream *nif); }; class NiFloatData : public Record @@ -175,10 +96,7 @@ class NiFloatData : public Record public: FloatKeyMap mKeyList; - void read(NIFStream *nif) - { - mKeyList.read(nif); - } + void read(NIFStream *nif); }; class NiPixelData : public Record @@ -187,37 +105,7 @@ public: unsigned int rmask, gmask, bmask, amask; int bpp, mips; - void read(NIFStream *nif) - { - nif->getInt(); // always 0 or 1 - - rmask = nif->getInt(); // usually 0xff - gmask = nif->getInt(); // usually 0xff00 - bmask = nif->getInt(); // usually 0xff0000 - amask = nif->getInt(); // usually 0xff000000 or zero - - bpp = nif->getInt(); - - // Unknown - nif->skip(12); - - mips = nif->getInt(); - - // Bytes per pixel, should be bpp * 8 - /*int bytes =*/ nif->getInt(); - - for(int i=0; igetInt(); - /*int y =*/ nif->getInt(); - /*int offset =*/ nif->getInt(); - } - - // Skip the data - unsigned int dataSize = nif->getInt(); - nif->skip(dataSize); - } + void read(NIFStream *nif); }; class NiColorData : public Record @@ -225,10 +113,7 @@ class NiColorData : public Record public: Vector4KeyMap mKeyMap; - void read(NIFStream *nif) - { - mKeyMap.read(nif); - } + void read(NIFStream *nif); }; class NiVisData : public Record @@ -240,16 +125,7 @@ public: }; std::vector mVis; - void read(NIFStream *nif) - { - int count = nif->getInt(); - mVis.resize(count); - for(size_t i = 0;i < mVis.size();i++) - { - mVis[i].time = nif->getFloat(); - mVis[i].isSet = nif->getChar(); - } - } + void read(NIFStream *nif); }; class NiSkinInstance : public Record @@ -259,13 +135,7 @@ public: NodePtr root; NodeList bones; - void read(NIFStream *nif) - { - data.read(nif); - root.read(nif); - bones.read(nif); - } - + void read(NIFStream *nif); void post(NIFFile *nif); }; @@ -288,34 +158,7 @@ public: Transformation trafo; std::vector bones; - void read(NIFStream *nif) - { - trafo.rotation = nif->getMatrix3(); - trafo.pos = nif->getVector3(); - trafo.scale = nif->getFloat(); - - int boneNum = nif->getInt(); - nif->getInt(); // -1 - - bones.resize(boneNum); - for(int i=0;igetMatrix3(); - bi.trafo.pos = nif->getVector3(); - bi.trafo.scale = nif->getFloat(); - bi.unknown = nif->getVector4(); - - // Number of vertex weights - bi.weights.resize(nif->getUShort()); - for(size_t j = 0;j < bi.weights.size();j++) - { - bi.weights[j].vertex = nif->getUShort(); - bi.weights[j].weight = nif->getFloat(); - } - } - } + void read(NIFStream *nif); }; struct NiMorphData : public Record @@ -326,19 +169,7 @@ struct NiMorphData : public Record }; std::vector mMorphs; - void read(NIFStream *nif) - { - int morphCount = nif->getInt(); - int vertCount = nif->getInt(); - /*relative targets?*/nif->getChar(); - - mMorphs.resize(morphCount); - for(int i = 0;i < morphCount;i++) - { - mMorphs[i].mData.read(nif, true); - nif->getVector3s(mMorphs[i].mVertices, vertCount); - } - } + void read(NIFStream *nif); }; @@ -353,20 +184,7 @@ struct NiKeyframeData : public Record Vector3KeyMap mTranslations; FloatKeyMap mScales; - void read(NIFStream *nif) - { - mRotations.read(nif); - if(mRotations.mInterpolationType == mRotations.sXYZInterpolation) - { - //Chomp unused float - nif->getFloat(); - mXRotations.read(nif, true); - mYRotations.read(nif, true); - mZRotations.read(nif, true); - } - mTranslations.read(nif); - mScales.read(nif); - } + void read(NIFStream *nif); }; } // Namespace diff --git a/components/nif/effect.hpp b/components/nif/effect.hpp index 679557e25..fae1cd7f5 100644 --- a/components/nif/effect.hpp +++ b/components/nif/effect.hpp @@ -42,63 +42,19 @@ struct NiLight : Effect osg::Vec3f diffuse; osg::Vec3f specular; - void read(NIFStream *nif) - { - dimmer = nif->getFloat(); - ambient = nif->getVector3(); - diffuse = nif->getVector3(); - specular = nif->getVector3(); - } + void read(NIFStream *nif); }; SLight light; - void read(NIFStream *nif) - { - Effect::read(nif); - - nif->getInt(); // 1 - nif->getInt(); // 1? - light.read(nif); - } + void read(NIFStream *nif); }; struct NiTextureEffect : Effect { NiSourceTexturePtr texture; - void read(NIFStream *nif) - { - Effect::read(nif); - - int tmp = nif->getInt(); - if(tmp) nif->getInt(); // always 1? - - /* - 3 x Vector4 = [1,0,0,0] - int = 2 - int = 0 or 3 - int = 2 - int = 2 - */ - nif->skip(16*4); - - texture.read(nif); - - /* - byte = 0 - vector4 = [1,0,0,0] - short = 0 - short = -75 - short = 0 - */ - nif->skip(23); - } - - void post(NIFFile *nif) - { - Effect::post(nif); - texture.post(nif); - } + void read(NIFStream *nif); + void post(NIFFile *nif); }; } // Namespace diff --git a/components/nif/extra.hpp b/components/nif/extra.hpp index 2913c62b0..1e5a8616d 100644 --- a/components/nif/extra.hpp +++ b/components/nif/extra.hpp @@ -32,17 +32,7 @@ namespace Nif class NiVertWeightsExtraData : public Extra { public: - void read(NIFStream *nif) - { - Extra::read(nif); - - // We should have s*4+2 == i, for some reason. Might simply be the - // size of the rest of the record, unhelpful as that may be. - /*int i =*/ nif->getInt(); - int s = nif->getUShort(); - - nif->skip(s * sizeof(float)); // vertex weights I guess - } + void read(NIFStream *nif); }; class NiTextKeyExtraData : public Extra @@ -55,20 +45,7 @@ public: }; std::vector list; - void read(NIFStream *nif) - { - Extra::read(nif); - - nif->getInt(); // 0 - - int keynum = nif->getInt(); - list.resize(keynum); - for(int i=0; igetFloat(); - list[i].text = nif->getString(); - } - } + void read(NIFStream *nif); }; class NiStringExtraData : public Extra @@ -80,13 +57,7 @@ public: */ std::string string; - void read(NIFStream *nif) - { - Extra::read(nif); - - nif->getInt(); // size of string + 4. Really useful... - string = nif->getString(); - } + void read(NIFStream *nif); }; } // Namespace diff --git a/components/nif/nifkey.hpp b/components/nif/nifkey.hpp index b8b01513b..549ea3eb3 100644 --- a/components/nif/nifkey.hpp +++ b/components/nif/nifkey.hpp @@ -24,6 +24,10 @@ struct KeyT { float mContinuity; // Only for TBC interpolation */ }; +typedef KeyT FloatKey; +typedef KeyT Vector3Key; +typedef KeyT Vector4Key; +typedef KeyT QuaternionKey; template struct KeyMapT { diff --git a/components/nif/property.hpp b/components/nif/property.hpp index 610f5427a..b06044e9f 100644 --- a/components/nif/property.hpp +++ b/components/nif/property.hpp @@ -26,9 +26,6 @@ #include "base.hpp" -#include "controlled.hpp" -#include "data.hpp" - namespace Nif { @@ -38,11 +35,7 @@ public: // The meaning of these depends on the actual property type. int flags; - void read(NIFStream *nif) - { - Named::read(nif); - flags = nif->getUShort(); - } + void read(NIFStream *nif); }; class NiTexturingProperty : public Property @@ -70,26 +63,8 @@ public: int clamp, uvSet, filter; short unknown2; - void read(NIFStream *nif) - { - inUse = !!nif->getInt(); - if(!inUse) return; - - texture.read(nif); - clamp = nif->getInt(); - filter = nif->getInt(); - uvSet = nif->getInt(); - - // I have no idea, but I think these are actually two - // PS2-specific shorts (ps2L and ps2K), followed by an unknown - // short. - nif->skip(6); - } - - void post(NIFFile *nif) - { - texture.post(nif); - } + void read(NIFStream *nif); + void post(NIFFile *nif); }; /* Apply mode: @@ -120,42 +95,14 @@ public: GlossTexture = 3, GlowTexture = 4, BumpTexture = 5, - DecalTexture = 6 + DecalTexture = 6, + NumTextures = 7 // Sentry value }; Texture textures[7]; - void read(NIFStream *nif) - { - Property::read(nif); - apply = nif->getInt(); - - // Unknown, always 7. Probably the number of textures to read - // below - nif->getInt(); - - textures[0].read(nif); // Base - textures[1].read(nif); // Dark - textures[2].read(nif); // Detail - textures[3].read(nif); // Gloss (never present) - textures[4].read(nif); // Glow - textures[5].read(nif); // Bump map - if(textures[5].inUse) - { - // Ignore these at the moment - /*float lumaScale =*/ nif->getFloat(); - /*float lumaOffset =*/ nif->getFloat(); - /*const Vector4 *lumaMatrix =*/ nif->getVector4(); - } - textures[6].read(nif); // Decal - } - - void post(NIFFile *nif) - { - Property::post(nif); - for(int i = 0;i < 7;i++) - textures[i].post(nif); - } + void read(NIFStream *nif); + void post(NIFFile *nif); }; class NiFogProperty : public Property @@ -164,14 +111,7 @@ public: float mFogDepth; osg::Vec3f mColour; - - void read(NIFStream *nif) - { - Property::read(nif); - - mFogDepth = nif->getFloat(); - mColour = nif->getVector3(); - } + void read(NIFStream *nif); }; // These contain no other data than the 'flags' field in Property @@ -200,15 +140,7 @@ struct S_MaterialProperty osg::Vec3f ambient, diffuse, specular, emissive; float glossiness, alpha; - void read(NIFStream *nif) - { - ambient = nif->getVector3(); - diffuse = nif->getVector3(); - specular = nif->getVector3(); - emissive = nif->getVector3(); - glossiness = nif->getFloat(); - alpha = nif->getFloat(); - } + void read(NIFStream *nif); }; struct S_VertexColorProperty @@ -224,11 +156,7 @@ struct S_VertexColorProperty */ int vertmode, lightmode; - void read(NIFStream *nif) - { - vertmode = nif->getInt(); - lightmode = nif->getInt(); - } + void read(NIFStream *nif); }; struct S_AlphaProperty @@ -273,10 +201,7 @@ struct S_AlphaProperty // Tested against when certain flags are set (see above.) unsigned char threshold; - void read(NIFStream *nif) - { - threshold = nif->getChar(); - } + void read(NIFStream *nif); }; /* @@ -322,17 +247,7 @@ struct S_StencilProperty */ int drawMode; - void read(NIFStream *nif) - { - enabled = nif->getChar(); - compareFunc = nif->getInt(); - stencilRef = nif->getUInt(); - stencilMask = nif->getUInt(); - failAction = nif->getInt(); - zFailAction = nif->getInt(); - zPassAction = nif->getInt(); - drawMode = nif->getInt(); - } + void read(NIFStream *nif); }; class NiAlphaProperty : public StructPropT { }; diff --git a/components/nif/record.hpp b/components/nif/record.hpp index 07d7540f8..1022802cc 100644 --- a/components/nif/record.hpp +++ b/components/nif/record.hpp @@ -110,12 +110,6 @@ struct Record virtual void post(NIFFile *nif) {} virtual ~Record() {} - - /* - Use these later if you want custom allocation of all NIF objects - static void* operator new(size_t size); - static void operator delete(void *p); - */ }; } // Namespace From 5edafc2a4cf50afb0ef083df70ae245779219697 Mon Sep 17 00:00:00 2001 From: Jordan Ayers Date: Sun, 22 Feb 2015 12:25:10 -0600 Subject: [PATCH 0603/3725] Cleanup: Add const to read-only CellRefList access. OMW Bug #1533 --- apps/openmw/mwworld/cellstore.hpp | 4 ++-- apps/openmw/mwworld/worldimp.cpp | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index cd7af5ad6..d7036d6b1 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -187,7 +187,7 @@ namespace MWWorld } template - CellRefList& getReadOnly() { + const CellRefList& getReadOnly() { throw std::runtime_error ("Read Only CellRefList access not available for type " + std::string(typeid(T).name()) ); } @@ -365,7 +365,7 @@ namespace MWWorld } template<> - inline CellRefList& CellStore::getReadOnly() + inline const CellRefList& CellStore::getReadOnly() { return mDoors; } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index dd730b32a..5f42a5379 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2799,13 +2799,13 @@ namespace MWWorld MWWorld::CellStore *next = getInterior( *i ); if ( !next ) continue; - MWWorld::CellRefList& doors = next->getReadOnly(); - CellRefList::List& refList = doors.mList; + const MWWorld::CellRefList& doors = next->getReadOnly(); + const CellRefList::List& refList = doors.mList; // Check if any door in the cell leads to an exterior directly - for (CellRefList::List::iterator it = refList.begin(); it != refList.end(); ++it) + for (CellRefList::List::const_iterator it = refList.begin(); it != refList.end(); ++it) { - MWWorld::LiveCellRef& ref = *it; + const MWWorld::LiveCellRef& ref = *it; if (!ref.mRef.getTeleport()) continue; if (ref.mRef.getDestCell().empty()) @@ -2855,13 +2855,13 @@ namespace MWWorld return closestMarker; } - MWWorld::CellRefList& doors = next->getReadOnly(); - CellRefList::List& doorList = doors.mList; + const MWWorld::CellRefList& doors = next->getReadOnly(); + const CellRefList::List& doorList = doors.mList; // Check if any door in the cell leads to an exterior directly - for (CellRefList::List::iterator it = doorList.begin(); it != doorList.end(); ++it) + for (CellRefList::List::const_iterator it = doorList.begin(); it != doorList.end(); ++it) { - MWWorld::LiveCellRef& ref = *it; + const MWWorld::LiveCellRef& ref = *it; if (!ref.mRef.getTeleport()) continue; From 68f89318e755d55e8e51bc3bdf079682cf2283fa Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 22 Feb 2015 20:56:47 +0100 Subject: [PATCH 0604/3725] Fix canvas align in skill view --- files/mygui/openmw_stats_window.layout | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/files/mygui/openmw_stats_window.layout b/files/mygui/openmw_stats_window.layout index 11119c404..1d9b75b9b 100644 --- a/files/mygui/openmw_stats_window.layout +++ b/files/mygui/openmw_stats_window.layout @@ -235,7 +235,9 @@ - + + + From 47c053444f2ed3011372cdd385601020975d6475 Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Mon, 23 Feb 2015 00:23:09 +0100 Subject: [PATCH 0605/3725] Make the jail progress last one second --- apps/openmw/mwgui/jailscreen.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwgui/jailscreen.cpp b/apps/openmw/mwgui/jailscreen.cpp index 548b1b604..58873c566 100644 --- a/apps/openmw/mwgui/jailscreen.cpp +++ b/apps/openmw/mwgui/jailscreen.cpp @@ -17,7 +17,7 @@ namespace MWGui { JailScreen::JailScreen() : WindowBase("openmw_jail_screen.layout"), - mTimeAdvancer(0.0125), + mTimeAdvancer(0.01), mDays(1), mFadeTimeRemaining(0) { @@ -39,7 +39,7 @@ namespace MWGui mFadeTimeRemaining = 0.5; setVisible(false); - mProgressBar->setScrollRange(days*24+1); + mProgressBar->setScrollRange(100+1); mProgressBar->setScrollPosition(0); mProgressBar->setTrackSize(0); } @@ -59,7 +59,7 @@ namespace MWGui MWBase::Environment::get().getWorld()->teleportToClosestMarker(player, "prisonmarker"); setVisible(true); - mTimeAdvancer.run(mDays*24); + mTimeAdvancer.run(100); } } From 84762c4eb8f49bddbb5947a54cb2321cde86f421 Mon Sep 17 00:00:00 2001 From: dteviot Date: Mon, 23 Feb 2015 19:30:46 +1300 Subject: [PATCH 0606/3725] Progress bar at 0% shows no text. --- apps/launcher/settingspage.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/launcher/settingspage.cpp b/apps/launcher/settingspage.cpp index 5b26b01b9..c228aba50 100644 --- a/apps/launcher/settingspage.cpp +++ b/apps/launcher/settingspage.cpp @@ -229,8 +229,7 @@ void Launcher::SettingsPage::importerFinished(int exitCode, QProcess::ExitStatus void Launcher::SettingsPage::resetProgressBar() { // set progress bar to 0 % - progressBar->setMaximum(1); - progressBar->setValue(0); + progressBar->reset(); } void Launcher::SettingsPage::updateOkButton(const QString &text) From 6dc202cba337416e68a54100ee76931abbbca60e Mon Sep 17 00:00:00 2001 From: dteviot Date: Mon, 23 Feb 2015 19:41:41 +1300 Subject: [PATCH 0607/3725] Removed unneeded parameter from ContentModel::setContentList() --- components/contentselector/model/contentmodel.cpp | 4 ++-- components/contentselector/model/contentmodel.hpp | 2 +- components/contentselector/view/contentselector.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/components/contentselector/model/contentmodel.cpp b/components/contentselector/model/contentmodel.cpp index ec1fcc21e..02a260022 100644 --- a/components/contentselector/model/contentmodel.cpp +++ b/components/contentselector/model/contentmodel.cpp @@ -536,13 +536,13 @@ bool ContentSelectorModel::ContentModel::isLoadOrderError(const EsmFile *file) c return mPluginsWithLoadOrderError.contains(file->filePath()); } -void ContentSelectorModel::ContentModel::setContentList(const QStringList &fileList, bool isChecked) +void ContentSelectorModel::ContentModel::setContentList(const QStringList &fileList) { mPluginsWithLoadOrderError.clear(); int previousPosition = -1; foreach (const QString &filepath, fileList) { - if (setCheckState(filepath, isChecked)) + if (setCheckState(filepath, true)) { // as necessary, move plug-ins in visible list to match sequence of supplied filelist const EsmFile* file = item(filepath); diff --git a/components/contentselector/model/contentmodel.hpp b/components/contentselector/model/contentmodel.hpp index 6af5425c7..3d8229aeb 100644 --- a/components/contentselector/model/contentmodel.hpp +++ b/components/contentselector/model/contentmodel.hpp @@ -51,7 +51,7 @@ namespace ContentSelectorModel bool isEnabled (QModelIndex index) const; bool isChecked(const QString &filepath) const; bool setCheckState(const QString &filepath, bool isChecked); - void setContentList(const QStringList &fileList, bool isChecked); + void setContentList(const QStringList &fileList); ContentFileList checkedItems() const; void uncheckAll(); diff --git a/components/contentselector/view/contentselector.cpp b/components/contentselector/view/contentselector.cpp index ad023e5b2..3aa5ddf80 100644 --- a/components/contentselector/view/contentselector.cpp +++ b/components/contentselector/view/contentselector.cpp @@ -113,7 +113,7 @@ void ContentSelectorView::ContentSelector::setContentList(const QStringList &lis slotCurrentGameFileIndexChanged (ui.gameFileView->currentIndex()); } else - mContentModel->setContentList(list, true); + mContentModel->setContentList(list); } ContentSelectorModel::ContentFileList From 63af9d848a5ca9dba169ff2cd4c957cdd0957cdd Mon Sep 17 00:00:00 2001 From: dteviot Date: Mon, 23 Feb 2015 19:58:31 +1300 Subject: [PATCH 0608/3725] Add constraint: Bloodmoon.esm requires Tribunal.esm. --- components/contentselector/model/contentmodel.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/components/contentselector/model/contentmodel.cpp b/components/contentselector/model/contentmodel.cpp index 02a260022..a4fbdcf06 100644 --- a/components/contentselector/model/contentmodel.cpp +++ b/components/contentselector/model/contentmodel.cpp @@ -467,6 +467,14 @@ void ContentSelectorModel::ContentModel::addFiles(const QString &path) file->setFilePath (info.absoluteFilePath()); file->setDescription(QString::fromUtf8(fileReader.getDesc().c_str())); + // HACK + // Bloodmoon.esm requires Tribunal.esm, but this requirement is missing + // from the file supplied by Bethesda, so we have to add it ourselves + if (file->fileName().compare("Bloodmoon.esm", Qt::CaseInsensitive) == 0) + { + file->addGameFile(QString::fromUtf8("Tribunal.esm")); + } + // Put the file in the table addFile(file); From 77bb77b367a39bae791449500c212dd39493d227 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 23 Feb 2015 19:07:12 +0100 Subject: [PATCH 0609/3725] Fix for instant restore effects (Fixes #2392) --- apps/openmw/mwmechanics/spellcasting.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 4ce3fcaf5..105fa5866 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -594,6 +594,7 @@ namespace MWMechanics value.restore(magnitude); target.getClass().getCreatureStats(target).setAttribute(attribute, value); } + // TODO: refactor the effect tick functions in Actors so they can be reused here else if (effectId == ESM::MagicEffect::DamageHealth) { applyDynamicStatsEffect(0, target, magnitude * -1); @@ -683,7 +684,7 @@ namespace MWMechanics void CastSpell::applyDynamicStatsEffect(int attribute, const MWWorld::Ptr& target, float magnitude) { DynamicStat value = target.getClass().getCreatureStats(target).getDynamic(attribute); - value.modify(magnitude); + value.setCurrent(value.getCurrent()+magnitude, attribute == 2); target.getClass().getCreatureStats(target).setDynamic(attribute, value); } From 8e01d8cb19a9136470c86ba02d9f3b8b883753c9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 23 Feb 2015 21:06:10 +0100 Subject: [PATCH 0610/3725] Add OSG nifloader, currently supports geometry, materials, basic texturing, skinning, morphing, and most controllers. --- CMakeLists.txt | 4 +- apps/nifosgtest/CMakeLists.txt | 7 + apps/nifosgtest/test.cpp | 100 ++++ components/CMakeLists.txt | 4 + components/nif/controlled.cpp | 88 ++++ components/nif/controller.cpp | 203 +++++++++ components/nif/effect.cpp | 61 +++ components/nif/extra.cpp | 43 ++ components/nif/property.cpp | 111 +++++ components/nifosg/controller.cpp | 275 +++++++++++ components/nifosg/controller.hpp | 214 +++++++++ components/nifosg/nifloader.cpp | 759 +++++++++++++++++++++++++++++++ components/nifosg/nifloader.hpp | 84 ++++ 13 files changed, 1952 insertions(+), 1 deletion(-) create mode 100644 apps/nifosgtest/CMakeLists.txt create mode 100644 apps/nifosgtest/test.cpp create mode 100644 components/nif/controlled.cpp create mode 100644 components/nif/controller.cpp create mode 100644 components/nif/effect.cpp create mode 100644 components/nif/extra.cpp create mode 100644 components/nif/property.cpp create mode 100644 components/nifosg/controller.cpp create mode 100644 components/nifosg/controller.hpp create mode 100644 components/nifosg/nifloader.cpp create mode 100644 components/nifosg/nifloader.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index cbe142fcc..d5b37a05b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -221,7 +221,7 @@ if (${OGRE_VERSION} VERSION_LESS "1.9") message(FATAL_ERROR "OpenMW requires Ogre 1.9 or later, please install the latest stable version from http://ogre3d.org") endif() -find_package(OpenSceneGraph 3.2.0 REQUIRED osgDB) +find_package(OpenSceneGraph 3.2.0 REQUIRED osgDB osgViewer osgGA osgAnimation) include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS}) find_package(MyGUI REQUIRED) @@ -592,6 +592,8 @@ if (BUILD_NIFTEST) endif(BUILD_NIFTEST) # Apps and tools +add_subdirectory( apps/nifosgtest ) + if (BUILD_OPENMW) add_subdirectory( apps/openmw ) endif() diff --git a/apps/nifosgtest/CMakeLists.txt b/apps/nifosgtest/CMakeLists.txt new file mode 100644 index 000000000..265577d98 --- /dev/null +++ b/apps/nifosgtest/CMakeLists.txt @@ -0,0 +1,7 @@ +set (FILES + test.cpp +) + +add_executable (test ${FILES}) + +target_link_libraries (test ${OPENSCENEGRAPH_LIBRARIES} "components") diff --git a/apps/nifosgtest/test.cpp b/apps/nifosgtest/test.cpp new file mode 100644 index 000000000..fc82059fc --- /dev/null +++ b/apps/nifosgtest/test.cpp @@ -0,0 +1,100 @@ +#include + +#include +#include + +#include + +#include + +#include +#include + +#include + +// EventHandler to toggle wireframe when 'w' key is pressed +class EventHandler : public osgGA::GUIEventHandler +{ +public: + EventHandler(osg::Node* node) + : mWireframe(false) + , mNode(node) + { + + } + + virtual bool handle(const osgGA::GUIEventAdapter& adapter,osgGA::GUIActionAdapter& action) + { + switch (adapter.getEventType()) + { + case osgGA::GUIEventAdapter::KEYDOWN: + if (adapter.getKey() == osgGA::GUIEventAdapter::KEY_W) + { + mWireframe = !mWireframe; + osg::PolygonMode* mode = new osg::PolygonMode; + mode->setMode(osg::PolygonMode::FRONT_AND_BACK, + mWireframe ? osg::PolygonMode::LINE : osg::PolygonMode::FILL); + mNode->getOrCreateStateSet()->setAttributeAndModes(mode, osg::StateAttribute::ON); + mNode->getOrCreateStateSet()->setMode(GL_CULL_FACE, mWireframe ? osg::StateAttribute::OFF + : osg::StateAttribute::ON); + return true; + } + default: + break; + } + return false; + } + +private: + bool mWireframe; + osg::Node* mNode; +}; + +int main(int argc, char** argv) +{ + if (argc < 3) + { + std::cout << "Usage: " << argv[0] << " " << std::endl; + return 1; + } + + Bsa::BSAFile bsa; + bsa.open(argv[1]); + + Nif::NIFFilePtr nif(new Nif::NIFFile(bsa.getFile(argv[2]), std::string(argv[2]))); + + osgViewer::Viewer viewer; + + osg::ref_ptr root(new osg::Group()); + root->getOrCreateStateSet()->setMode(GL_CULL_FACE, osg::StateAttribute::ON); + // To prevent lighting issues with scaled meshes + root->getOrCreateStateSet()->setMode(GL_NORMALIZE, osg::StateAttribute::ON); + + osg::Group* newNode = new osg::Group; + NifOsg::Loader loader; + loader.resourceManager = &bsa; + loader.loadAsSkeleton(nif, newNode); + + //osgDB::writeNodeFile(*newNode, "out.osg"); + + for (int x=0; x<1;++x) + { + root->addChild(newNode); + } + + viewer.setSceneData(root); + + viewer.setUpViewInWindow(0, 0, 800, 600); + viewer.realize(); + viewer.setCameraManipulator(new osgGA::TrackballManipulator()); + viewer.addEventHandler(new EventHandler(root)); + + while (!viewer.done()) + { + viewer.frame(); + + for (unsigned int i=0; igetChar(); + if(external) + filename = nif->getString(); + else + { + nif->getChar(); // always 1 + data.read(nif); + } + + pixel = nif->getInt(); + mipmap = nif->getInt(); + alpha = nif->getInt(); + + nif->getChar(); // always 1 + } + + void NiSourceTexture::post(NIFFile *nif) + { + Named::post(nif); + data.post(nif); + } + + void NiParticleGrowFade::read(NIFStream *nif) + { + Controlled::read(nif); + growTime = nif->getFloat(); + fadeTime = nif->getFloat(); + } + + void NiParticleColorModifier::read(NIFStream *nif) + { + Controlled::read(nif); + data.read(nif); + } + + void NiParticleColorModifier::post(NIFFile *nif) + { + Controlled::post(nif); + data.post(nif); + } + + void NiGravity::read(NIFStream *nif) + { + Controlled::read(nif); + + /*unknown*/nif->getFloat(); + mForce = nif->getFloat(); + mType = nif->getUInt(); + mPosition = nif->getVector3(); + mDirection = nif->getVector3(); + } + + void NiPlanarCollider::read(NIFStream *nif) + { + Controlled::read(nif); + + // (I think) 4 floats + 4 vectors + nif->skip(4*16); + } + + void NiParticleRotation::read(NIFStream *nif) + { + Controlled::read(nif); + + /* + byte (0 or 1) + float (1) + float*3 + */ + nif->skip(17); + } + + + + + +} diff --git a/components/nif/controller.cpp b/components/nif/controller.cpp new file mode 100644 index 000000000..376a1fe12 --- /dev/null +++ b/components/nif/controller.cpp @@ -0,0 +1,203 @@ +#include "controller.hpp" + +#include "node.hpp" +#include "data.hpp" + +namespace Nif +{ + + void Controller::read(NIFStream *nif) + { + next.read(nif); + + flags = nif->getUShort(); + + frequency = nif->getFloat(); + phase = nif->getFloat(); + timeStart = nif->getFloat(); + timeStop = nif->getFloat(); + + target.read(nif); + } + + void Controller::post(NIFFile *nif) + { + Record::post(nif); + next.post(nif); + target.post(nif); + } + + void NiParticleSystemController::read(NIFStream *nif) + { + Controller::read(nif); + + velocity = nif->getFloat(); + velocityRandom = nif->getFloat(); + verticalDir = nif->getFloat(); + verticalAngle = nif->getFloat(); + horizontalDir = nif->getFloat(); + horizontalAngle = nif->getFloat(); + /*normal?*/ nif->getVector3(); + /*color?*/ nif->getVector4(); + size = nif->getFloat(); + startTime = nif->getFloat(); + stopTime = nif->getFloat(); + nif->getChar(); + emitRate = nif->getFloat(); + lifetime = nif->getFloat(); + lifetimeRandom = nif->getFloat(); + + emitFlags = nif->getUShort(); + offsetRandom = nif->getVector3(); + + emitter.read(nif); + + /* Unknown Short, 0? + * Unknown Float, 1.0? + * Unknown Int, 1? + * Unknown Int, 0? + * Unknown Short, 0? + */ + nif->skip(16); + + numParticles = nif->getUShort(); + activeCount = nif->getUShort(); + + particles.resize(numParticles); + for(size_t i = 0;i < particles.size();i++) + { + particles[i].velocity = nif->getVector3(); + nif->getVector3(); /* unknown */ + particles[i].lifetime = nif->getFloat(); + particles[i].lifespan = nif->getFloat(); + particles[i].timestamp = nif->getFloat(); + nif->getUShort(); /* unknown */ + particles[i].vertex = nif->getUShort(); + } + + nif->getUInt(); /* -1? */ + extra.read(nif); + nif->getUInt(); /* -1? */ + nif->getChar(); + } + + void NiParticleSystemController::post(NIFFile *nif) + { + Controller::post(nif); + emitter.post(nif); + extra.post(nif); + } + + void NiMaterialColorController::read(NIFStream *nif) + { + Controller::read(nif); + data.read(nif); + } + + void NiMaterialColorController::post(NIFFile *nif) + { + Controller::post(nif); + data.post(nif); + } + + void NiPathController::read(NIFStream *nif) + { + Controller::read(nif); + + /* + int = 1 + 2xfloat + short = 0 or 1 + */ + nif->skip(14); + posData.read(nif); + floatData.read(nif); + } + + void NiPathController::post(NIFFile *nif) + { + Controller::post(nif); + + posData.post(nif); + floatData.post(nif); + } + + void NiUVController::read(NIFStream *nif) + { + Controller::read(nif); + + nif->getUShort(); // always 0 + data.read(nif); + } + + void NiUVController::post(NIFFile *nif) + { + Controller::post(nif); + data.post(nif); + } + + void NiKeyframeController::read(NIFStream *nif) + { + Controller::read(nif); + data.read(nif); + } + + void NiKeyframeController::post(NIFFile *nif) + { + Controller::post(nif); + data.post(nif); + } + + void NiAlphaController::read(NIFStream *nif) + { + Controller::read(nif); + data.read(nif); + } + + void NiAlphaController::post(NIFFile *nif) + { + Controller::post(nif); + data.post(nif); + } + + void NiGeomMorpherController::read(NIFStream *nif) + { + Controller::read(nif); + data.read(nif); + nif->getChar(); // always 0 + } + + void NiGeomMorpherController::post(NIFFile *nif) + { + Controller::post(nif); + data.post(nif); + } + + void NiVisController::read(NIFStream *nif) + { + Controller::read(nif); + data.read(nif); + } + + void NiVisController::post(NIFFile *nif) + { + Controller::post(nif); + data.post(nif); + } + + void NiFlipController::read(NIFStream *nif) + { + Controller::read(nif); + mTexSlot = nif->getUInt(); + /*unknown=*/nif->getUInt();/*0?*/ + mDelta = nif->getFloat(); + mSources.read(nif); + } + + void NiFlipController::post(NIFFile *nif) + { + Controller::post(nif); + mSources.post(nif); + } + +} diff --git a/components/nif/effect.cpp b/components/nif/effect.cpp new file mode 100644 index 000000000..41dcb09de --- /dev/null +++ b/components/nif/effect.cpp @@ -0,0 +1,61 @@ +#include "effect.hpp" + +#include "node.hpp" + +namespace Nif +{ + +void NiLight::SLight::read(NIFStream *nif) +{ + dimmer = nif->getFloat(); + ambient = nif->getVector3(); + diffuse = nif->getVector3(); + specular = nif->getVector3(); +} + +void NiLight::read(NIFStream *nif) +{ + Effect::read(nif); + + nif->getInt(); // 1 + nif->getInt(); // 1? + light.read(nif); +} + +void NiTextureEffect::read(NIFStream *nif) +{ + Effect::read(nif); + + int tmp = nif->getInt(); + if(tmp) nif->getInt(); // always 1? + + /* + 3 x Vector4 = [1,0,0,0] + int = 2 + int = 0 or 3 + int = 2 + int = 2 + */ + nif->skip(16*4); + + texture.read(nif); + + /* + byte = 0 + vector4 = [1,0,0,0] + short = 0 + short = -75 + short = 0 + */ + nif->skip(23); +} + +void NiTextureEffect::post(NIFFile *nif) +{ + Effect::post(nif); + texture.post(nif); +} + + + +} diff --git a/components/nif/extra.cpp b/components/nif/extra.cpp new file mode 100644 index 000000000..b7e221668 --- /dev/null +++ b/components/nif/extra.cpp @@ -0,0 +1,43 @@ +#include "extra.hpp" + +namespace Nif +{ + +void NiStringExtraData::read(NIFStream *nif) +{ + Extra::read(nif); + + nif->getInt(); // size of string + 4. Really useful... + string = nif->getString(); +} + +void NiTextKeyExtraData::read(NIFStream *nif) +{ + Extra::read(nif); + + nif->getInt(); // 0 + + int keynum = nif->getInt(); + list.resize(keynum); + for(int i=0; igetFloat(); + list[i].text = nif->getString(); + } +} + +void NiVertWeightsExtraData::read(NIFStream *nif) +{ + Extra::read(nif); + + // We should have s*4+2 == i, for some reason. Might simply be the + // size of the rest of the record, unhelpful as that may be. + /*int i =*/ nif->getInt(); + int s = nif->getUShort(); + + nif->skip(s * sizeof(float)); // vertex weights I guess +} + + + +} diff --git a/components/nif/property.cpp b/components/nif/property.cpp new file mode 100644 index 000000000..47c6d35b3 --- /dev/null +++ b/components/nif/property.cpp @@ -0,0 +1,111 @@ +#include "property.hpp" + +#include "data.hpp" +#include "controlled.hpp" + +namespace Nif +{ + +void Property::read(NIFStream *nif) +{ + Named::read(nif); + flags = nif->getUShort(); +} + +void NiTexturingProperty::Texture::read(NIFStream *nif) +{ + inUse = !!nif->getInt(); + if(!inUse) return; + + texture.read(nif); + clamp = nif->getInt(); + filter = nif->getInt(); + uvSet = nif->getInt(); + + // I have no idea, but I think these are actually two + // PS2-specific shorts (ps2L and ps2K), followed by an unknown + // short. + nif->skip(6); +} + +void NiTexturingProperty::Texture::post(NIFFile *nif) +{ + texture.post(nif); +} + +void NiTexturingProperty::read(NIFStream *nif) +{ + Property::read(nif); + apply = nif->getInt(); + + // Unknown, always 7. Probably the number of textures to read + // below + nif->getInt(); + + textures[0].read(nif); // Base + textures[1].read(nif); // Dark + textures[2].read(nif); // Detail + textures[3].read(nif); // Gloss (never present) + textures[4].read(nif); // Glow + textures[5].read(nif); // Bump map + if(textures[5].inUse) + { + // Ignore these at the moment + /*float lumaScale =*/ nif->getFloat(); + /*float lumaOffset =*/ nif->getFloat(); + /*const Vector4 *lumaMatrix =*/ nif->getVector4(); + } + textures[6].read(nif); // Decal +} + +void NiTexturingProperty::post(NIFFile *nif) +{ + Property::post(nif); + for(int i = 0;i < 7;i++) + textures[i].post(nif); +} + +void NiFogProperty::read(NIFStream *nif) +{ + Property::read(nif); + + mFogDepth = nif->getFloat(); + mColour = nif->getVector3(); +} + +void S_MaterialProperty::read(NIFStream *nif) +{ + ambient = nif->getVector3(); + diffuse = nif->getVector3(); + specular = nif->getVector3(); + emissive = nif->getVector3(); + glossiness = nif->getFloat(); + alpha = nif->getFloat(); +} + +void S_VertexColorProperty::read(NIFStream *nif) +{ + vertmode = nif->getInt(); + lightmode = nif->getInt(); +} + +void S_AlphaProperty::read(NIFStream *nif) +{ + threshold = nif->getChar(); +} + +void S_StencilProperty::read(NIFStream *nif) +{ + enabled = nif->getChar(); + compareFunc = nif->getInt(); + stencilRef = nif->getUInt(); + stencilMask = nif->getUInt(); + failAction = nif->getInt(); + zFailAction = nif->getInt(); + zPassAction = nif->getInt(); + drawMode = nif->getInt(); +} + + + +} diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp new file mode 100644 index 000000000..4e600c3a1 --- /dev/null +++ b/components/nifosg/controller.cpp @@ -0,0 +1,275 @@ +#include "controller.hpp" + +#include +#include +#include + +#include + +namespace NifOsg +{ + +float ValueInterpolator::interpKey(const Nif::FloatKeyMap::MapType &keys, float time, float def) const +{ + if (keys.size() == 0) + return def; + + if(time <= keys.begin()->first) + return keys.begin()->second.mValue; + + Nif::FloatKeyMap::MapType::const_iterator it = keys.lower_bound(time); + if (it != keys.end()) + { + float aTime = it->first; + const Nif::FloatKey* aKey = &it->second; + + assert (it != keys.begin()); // Shouldn't happen, was checked at beginning of this function + + Nif::FloatKeyMap::MapType::const_iterator last = --it; + float aLastTime = last->first; + const Nif::FloatKey* aLastKey = &last->second; + + float a = (time - aLastTime) / (aTime - aLastTime); + return aLastKey->mValue + ((aKey->mValue - aLastKey->mValue) * a); + } + else + return keys.rbegin()->second.mValue; +} + +osg::Vec3f ValueInterpolator::interpKey(const Nif::Vector3KeyMap::MapType &keys, float time) const +{ + if(time <= keys.begin()->first) + return keys.begin()->second.mValue; + + Nif::Vector3KeyMap::MapType::const_iterator it = keys.lower_bound(time); + if (it != keys.end()) + { + float aTime = it->first; + const Nif::KeyT* aKey = &it->second; + + assert (it != keys.begin()); // Shouldn't happen, was checked at beginning of this function + + Nif::Vector3KeyMap::MapType::const_iterator last = --it; + float aLastTime = last->first; + const Nif::KeyT* aLastKey = &last->second; + + float a = (time - aLastTime) / (aTime - aLastTime); + return aLastKey->mValue + ((aKey->mValue - aLastKey->mValue) * a); + } + else + return keys.rbegin()->second.mValue; +} + +ControllerFunction::ControllerFunction(const Nif::Controller *ctrl, bool deltaInput) + : mDeltaInput(deltaInput) + , mFrequency(ctrl->frequency) + , mPhase(ctrl->phase) + , mStartTime(ctrl->timeStart) + , mStopTime(ctrl->timeStop) + , mDeltaCount(0.f) +{ + if(mDeltaInput) + mDeltaCount = mPhase; +} + +float ControllerFunction::calculate(float value) +{ + if(mDeltaInput) + { + if (mStopTime - mStartTime == 0.f) + return 0.f; + + mDeltaCount += value*mFrequency; + if(mDeltaCount < mStartTime) + mDeltaCount = mStopTime - std::fmod(mStartTime - mDeltaCount, + mStopTime - mStartTime); + mDeltaCount = std::fmod(mDeltaCount - mStartTime, + mStopTime - mStartTime) + mStartTime; + return mDeltaCount; + } + + value = std::min(mStopTime, std::max(mStartTime, value+mPhase)); + return value; +} + +osg::Quat KeyframeController::Value::interpKey(const Nif::QuaternionKeyMap::MapType &keys, float time) +{ + if(time <= keys.begin()->first) + return keys.begin()->second.mValue; + + Nif::QuaternionKeyMap::MapType::const_iterator it = keys.lower_bound(time); + if (it != keys.end()) + { + float aTime = it->first; + const Nif::QuaternionKey* aKey = &it->second; + + assert (it != keys.begin()); // Shouldn't happen, was checked at beginning of this function + + Nif::QuaternionKeyMap::MapType::const_iterator last = --it; + float aLastTime = last->first; + const Nif::QuaternionKey* aLastKey = &last->second; + + float a = (time - aLastTime) / (aTime - aLastTime); + + osg::Quat v1 = aLastKey->mValue; + osg::Quat v2 = aKey->mValue; + // don't take the long path + if (v1.x()*v2.x() + v1.y()*v2.y() + v1.z()*v2.z() + v1.w()*v2.w() < 0) // dotProduct(v1,v2) + v1 = -v1; + + osg::Quat result; + result.slerp(a, v1, v2); + return result; + } + else + return keys.rbegin()->second.mValue; +} + +osg::Quat KeyframeController::Value::getXYZRotation(float time) const +{ + float xrot = interpKey(mXRotations->mKeys, time); + float yrot = interpKey(mYRotations->mKeys, time); + float zrot = interpKey(mZRotations->mKeys, time); + osg::Quat xr(xrot, osg::Vec3f(1,0,0)); + osg::Quat yr(yrot, osg::Vec3f(0,1,0)); + osg::Quat zr(zrot, osg::Vec3f(0,0,1)); + return (zr*yr*xr); +} + +KeyframeController::Value::Value(osg::Node *target, const Nif::NIFFilePtr &nif, const Nif::NiKeyframeData *data, + osg::Quat initialQuat, float initialScale) + : NodeTargetValue(target) + , mRotations(&data->mRotations) + , mXRotations(&data->mXRotations) + , mYRotations(&data->mYRotations) + , mZRotations(&data->mZRotations) + , mTranslations(&data->mTranslations) + , mScales(&data->mScales) + , mNif(nif) + , mInitialQuat(initialQuat) + , mInitialScale(initialScale) +{ } + +osg::Vec3f KeyframeController::Value::getTranslation(float time) const +{ + if(mTranslations->mKeys.size() > 0) + return interpKey(mTranslations->mKeys, time); + osg::MatrixTransform* trans = static_cast(mNode); + return trans->getMatrix().getTrans(); +} + +void KeyframeController::Value::setValue(float time) +{ + osg::MatrixTransform* trans = static_cast(mNode); + osg::Matrix mat = trans->getMatrix(); + + if(mRotations->mKeys.size() > 0) + mat.setRotate(interpKey(mRotations->mKeys, time)); + else if (!mXRotations->mKeys.empty() || !mYRotations->mKeys.empty() || !mZRotations->mKeys.empty()) + mat.setRotate(getXYZRotation(time)); + else + mat.setRotate(mInitialQuat); + + // let's hope no one's using multiple KeyframeControllers on the same node (not that would make any sense...) + float scale = mInitialScale; + if(mScales->mKeys.size() > 0) + scale = interpKey(mScales->mKeys, time); + + for (int i=0;i<3;++i) + for (int j=0;j<3;++j) + mat(i,j) *= scale; + + if(mTranslations->mKeys.size() > 0) + mat.setTrans(interpKey(mTranslations->mKeys, time)); + trans->setMatrix(mat); +} + +Controller::Controller(boost::shared_ptr src, boost::shared_ptr dest, boost::shared_ptr function) + : mSource(src) + , mDestValue(dest) + , mFunction(function) +{ + +} + +void Controller::update() +{ + if (mSource.get()) + { + mDestValue->setValue(mFunction->calculate(mSource->getValue())); + } +} + +GeomMorpherController::Value::Value(osgAnimation::MorphGeometry *geom, const Nif::NiMorphData* morphData) + : mGeom(geom) + , mMorphs(morphData->mMorphs) +{ + +} + +void GeomMorpherController::Value::setValue(float time) +{ + if (mMorphs.size() <= 1) + return; + int i = 0; + for (std::vector::iterator it = mMorphs.begin()+1; it != mMorphs.end(); ++it,++i) + { + float val = 0; + if (!it->mData.mKeys.empty()) + val = interpKey(it->mData.mKeys, time); + val = std::max(0.f, std::min(1.f, val)); + + mGeom->setWeight(i, val); + } +} + +UVController::Value::Value(osg::StateSet *target, const Nif::NiUVData *data, std::set textureUnits) + : mStateSet(target) + , mUTrans(data->mKeyList[0]) + , mVTrans(data->mKeyList[1]) + , mUScale(data->mKeyList[2]) + , mVScale(data->mKeyList[3]) + , mTextureUnits(textureUnits) +{ +} + +void UVController::Value::setValue(float value) +{ + float uTrans = interpKey(mUTrans.mKeys, value, 0.0f); + float vTrans = interpKey(mVTrans.mKeys, value, 0.0f); + float uScale = interpKey(mUScale.mKeys, value, 1.0f); + float vScale = interpKey(mVScale.mKeys, value, 1.0f); + + osg::Matrixf mat = osg::Matrixf::scale(uScale, vScale, 1); + mat.setTrans(uTrans, vTrans, 0); + + osg::TexMat* texMat = new osg::TexMat; + texMat->setMatrix(mat); + + for (std::set::const_iterator it = mTextureUnits.begin(); it != mTextureUnits.end(); ++it) + { + mStateSet->setTextureAttributeAndModes(*it, texMat, osg::StateAttribute::ON); + } +} + +bool VisController::Value::calculate(float time) const +{ + if(mData.size() == 0) + return true; + + for(size_t i = 1;i < mData.size();i++) + { + if(mData[i].time > time) + return mData[i-1].isSet; + } + return mData.back().isSet; +} + +void VisController::Value::setValue(float time) +{ + bool vis = calculate(time); + mNode->setNodeMask(vis ? ~0 : 0); +} + + +} diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp new file mode 100644 index 000000000..e45bc7fea --- /dev/null +++ b/components/nifosg/controller.hpp @@ -0,0 +1,214 @@ +#ifndef COMPONENTS_NIFOSG_CONTROLLER_H +#define COMPONENTS_NIFOSG_CONTROLLER_H + +#include +#include +#include +#include + +#include + +#include + +#include //UVController + +#include + + +namespace osg +{ + class Node; + class StateSet; +} + +namespace osgAnimation +{ + class MorphGeometry; +} + +namespace NifOsg +{ + + // FIXME: Should not be here. We might also want to use this for non-NIF model formats + class ValueInterpolator + { + protected: + float interpKey(const Nif::FloatKeyMap::MapType &keys, float time, float def=0.f) const; + + osg::Vec3f interpKey(const Nif::Vector3KeyMap::MapType &keys, float time) const; + }; + + // FIXME: Should not be here. We might also want to use this for non-NIF model formats + class ControllerFunction + { + private: + float mFrequency; + float mPhase; + float mStartTime; + bool mDeltaInput; + float mDeltaCount; + public: + float mStopTime; + + public: + ControllerFunction(const Nif::Controller *ctrl, bool deltaInput); + + float calculate(float value); + }; + typedef ControllerFunction DefaultFunction; + + class ControllerSource + { + public: + virtual float getValue() const = 0; + }; + + // FIXME: Should return a dt instead of time + class FrameTimeSource : public ControllerSource + { + public: + + virtual float getValue() const + { + return mTimer.time_s(); + } + + private: + osg::Timer mTimer; + }; + + class ControllerValue + { + public: + virtual void setValue(float value) = 0; + }; + + class Controller + { + public: + Controller (boost::shared_ptr src, boost::shared_ptr dest, + boost::shared_ptr function); + + virtual void update(); + + boost::shared_ptr mSource; + boost::shared_ptr mDestValue; + + // The source value gets passed through this function before it's passed on to the DestValue. + boost::shared_ptr mFunction; + }; + + // FIXME: Should be with other general extensions. + class NodeTargetValue : public ControllerValue + { + protected: + osg::Node *mNode; + + public: + NodeTargetValue(osg::Node *target) : mNode(target) + { } + + virtual osg::Vec3f getTranslation(float value) const = 0; + + osg::Node *getNode() const + { return mNode; } + }; + + class GeomMorpherController + { + public: + class Value : public ControllerValue, public ValueInterpolator + { + public: + // FIXME: don't copy the morph data? + Value(osgAnimation::MorphGeometry* geom, const Nif::NiMorphData *data); + + virtual void setValue(float time); + + private: + osgAnimation::MorphGeometry* mGeom; + std::vector mMorphs; + }; + }; + + class KeyframeController + { + public: + class Value : public NodeTargetValue, public ValueInterpolator + { + private: + const Nif::QuaternionKeyMap* mRotations; + const Nif::FloatKeyMap* mXRotations; + const Nif::FloatKeyMap* mYRotations; + const Nif::FloatKeyMap* mZRotations; + const Nif::Vector3KeyMap* mTranslations; + const Nif::FloatKeyMap* mScales; + Nif::NIFFilePtr mNif; // Hold a SharedPtr to make sure key lists stay valid + + osg::Quat mInitialQuat; + float mInitialScale; + + using ValueInterpolator::interpKey; + + + osg::Quat interpKey(const Nif::QuaternionKeyMap::MapType &keys, float time); + + osg::Quat getXYZRotation(float time) const; + + public: + /// @note The NiKeyFrameData must be valid as long as this KeyframeController exists. + Value(osg::Node *target, const Nif::NIFFilePtr& nif, const Nif::NiKeyframeData *data, + osg::Quat initialQuat, float initialScale); + + virtual osg::Vec3f getTranslation(float time) const; + + virtual void setValue(float time); + }; + }; + + class UVController + { + public: + class Value : public ControllerValue, ValueInterpolator + { + private: + osg::StateSet* mStateSet; + Nif::FloatKeyMap mUTrans; + Nif::FloatKeyMap mVTrans; + Nif::FloatKeyMap mUScale; + Nif::FloatKeyMap mVScale; + std::set mTextureUnits; + + public: + Value(osg::StateSet* target, const Nif::NiUVData *data, std::set textureUnits); + + virtual void setValue(float value); + }; + }; + + class VisController + { + public: + class Value : public NodeTargetValue + { + private: + std::vector mData; + + bool calculate(float time) const; + + public: + Value(osg::Node *target, const Nif::NiVisData *data) + : NodeTargetValue(target) + , mData(data->mVis) + { } + + virtual osg::Vec3f getTranslation(float time) const + { return osg::Vec3f(); } + + virtual void setValue(float time); + }; + }; + +} + +#endif diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp new file mode 100644 index 000000000..2eb57a4f8 --- /dev/null +++ b/components/nifosg/nifloader.cpp @@ -0,0 +1,759 @@ +#include "nifloader.hpp" + +#include +#include +#include +#include +#include + +// resource +#include +#include +#include +#include + +// skel +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace +{ + osg::Matrixf toMatrix(const Nif::Transformation& nifTrafo) + { + osg::Matrixf transform; + transform.setTrans(nifTrafo.pos); + + for (int i=0;i<3;++i) + for (int j=0;j<3;++j) + transform(j,i) = nifTrafo.rotation.mValues[i][j] * nifTrafo.scale; // NB column/row major difference + + return transform; + } + + osg::Matrixf getWorldTransform(const Nif::Node* node) + { + if(node->parent != NULL) + return toMatrix(node->trafo) * getWorldTransform(node->parent); + return toMatrix(node->trafo); + } + + osg::BlendFunc::BlendFuncMode getBlendMode(int mode) + { + switch(mode) + { + case 0: return osg::BlendFunc::ONE; + case 1: return osg::BlendFunc::ZERO; + case 2: return osg::BlendFunc::SRC_COLOR; + case 3: return osg::BlendFunc::ONE_MINUS_SRC_COLOR; + case 4: return osg::BlendFunc::DST_COLOR; + case 5: return osg::BlendFunc::ONE_MINUS_DST_COLOR; + case 6: return osg::BlendFunc::SRC_ALPHA; + case 7: return osg::BlendFunc::ONE_MINUS_SRC_ALPHA; + case 8: return osg::BlendFunc::DST_ALPHA; + case 9: return osg::BlendFunc::ONE_MINUS_DST_ALPHA; + case 10: return osg::BlendFunc::SRC_ALPHA_SATURATE; + default: + std::cerr<< "Unexpected blend mode: "<< mode << std::endl; + return osg::BlendFunc::SRC_ALPHA; + } + } + + osg::AlphaFunc::ComparisonFunction getTestMode(int mode) + { + switch (mode) + { + case 0: return osg::AlphaFunc::ALWAYS; + case 1: return osg::AlphaFunc::LESS; + case 2: return osg::AlphaFunc::EQUAL; + case 3: return osg::AlphaFunc::LEQUAL; + case 4: return osg::AlphaFunc::GREATER; + case 5: return osg::AlphaFunc::NOTEQUAL; + case 6: return osg::AlphaFunc::GEQUAL; + case 7: return osg::AlphaFunc::NEVER; + default: + std::cerr << "Unexpected blend mode: " << mode << std::endl; + return osg::AlphaFunc::LEQUAL; + } + } + + // Collect all properties affecting the given node that should be applied to an osg::Material. + void collectMaterialProperties(const Nif::Node* nifNode, std::vector& out) + { + const Nif::PropertyList& props = nifNode->props; + for (size_t i = 0; i recType) + { + case Nif::RC_NiMaterialProperty: + case Nif::RC_NiVertexColorProperty: + case Nif::RC_NiSpecularProperty: + out.push_back(props[i].getPtr()); + break; + default: + break; + } + } + } + if (nifNode->parent) + collectMaterialProperties(nifNode->parent, out); + } + + void updateMaterialProperties(osg::StateSet* stateset, const std::vector& properties) + { + int specFlags = 0; // Specular is disabled by default, even if there's a specular color in the NiMaterialProperty + osg::Material* mat = new osg::Material; + // FIXME: color mode should be disabled if the TriShape has no vertex colors + mat->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE); + for (std::vector::const_reverse_iterator it = properties.rbegin(); it != properties.rend(); ++it) + { + const Nif::Property* property = *it; + switch (property->recType) + { + case Nif::RC_NiSpecularProperty: + { + specFlags = property->flags; + break; + } + case Nif::RC_NiMaterialProperty: + { + const Nif::NiMaterialProperty* matprop = static_cast(property); + + mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(matprop->data.diffuse, matprop->data.alpha)); + mat->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(matprop->data.ambient, 1.f)); + mat->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(matprop->data.emissive, 1.f)); + + mat->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4f(matprop->data.specular, 1.f)); + mat->setShininess(osg::Material::FRONT_AND_BACK, matprop->data.glossiness); + + break; + } + case Nif::RC_NiVertexColorProperty: + { + const Nif::NiVertexColorProperty* vertprop = static_cast(property); + switch (vertprop->flags) + { + case 0: + mat->setColorMode(osg::Material::OFF); + break; + case 1: + mat->setColorMode(osg::Material::EMISSION); + break; + case 2: + mat->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE); + break; + } + } + } + } + + if (specFlags == 0) + mat->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f,0.f,0.f,0.f)); + + stateset->setAttributeAndModes(mat, osg::StateAttribute::ON); + } + + // NodeCallback used to update the bone matrices in skeleton space as needed for skinning. + class UpdateBone : public osg::NodeCallback + { + public: + // Callback method called by the NodeVisitor when visiting a node. + void operator()(osg::Node* node, osg::NodeVisitor* nv) + { + if (nv && nv->getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR) + { + osgAnimation::Bone* b = dynamic_cast(node); + if (!b) + { + OSG_WARN << "Warning: UpdateBone set on non-Bone object." << std::endl; + return; + } + + osgAnimation::Bone* parent = b->getBoneParent(); + if (parent) + b->setMatrixInSkeletonSpace(b->getMatrixInBoneSpace() * parent->getMatrixInSkeletonSpace()); + else + b->setMatrixInSkeletonSpace(b->getMatrixInBoneSpace()); + } + traverse(node,nv); + } + }; + + // NodeCallback used to set the inverse of the parent bone's matrix in skeleton space + // on the MatrixTransform that the NodeCallback is attached to. This is used so we can + // attach skinned meshes to their actual parent node, while still having the skinning + // work in skeleton space as expected. + class InvertBoneMatrix : public osg::NodeCallback + { + public: + InvertBoneMatrix(osg::Node* skelRootNode) + : mSkelRoot(skelRootNode) + { + } + + void operator()(osg::Node* node, osg::NodeVisitor* nv) + { + if (nv && nv->getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR) + { + osg::NodePath path = nv->getNodePath(); + path.pop_back(); + + osg::MatrixTransform* trans = dynamic_cast(node); + + osg::NodePath::iterator found = std::find(path.begin(), path.end(), mSkelRoot); + if (found != path.end()) + { + path.erase(path.begin(),found+1); + + osg::Matrix worldMat = osg::computeLocalToWorld( path ); + trans->setMatrix(osg::Matrix::inverse(worldMat)); + } + } + traverse(node,nv); + } + private: + osg::Node* mSkelRoot; + }; + + osg::ref_ptr handleMorphGeometry(const Nif::NiGeomMorpherController* morpher) + { + osg::ref_ptr morphGeom = new osgAnimation::MorphGeometry; + morphGeom->setMethod(osgAnimation::MorphGeometry::RELATIVE); + // NIF format doesn't specify morphed normals + morphGeom->setMorphNormals(false); + + const std::vector& morphs = morpher->data.getPtr()->mMorphs; + // Note we are not interested in morph 0, which just contains the original vertices + for (unsigned int i = 1; i < morphs.size(); ++i) + { + osg::ref_ptr morphTarget = new osg::Geometry; + morphTarget->setVertexArray(new osg::Vec3Array(morphs[i].mVertices.size(), &morphs[i].mVertices[0])); + morphGeom->addMorphTarget(morphTarget, 0.f); + } + return morphGeom; + } +} + +namespace NifOsg +{ + + void Loader::load(Nif::NIFFilePtr nif, osg::Group *parentNode) + { + mNif = nif; + + if (nif->numRoots() < 1) + { + nif->warn("Found no root nodes"); + return; + } + + const Nif::Record* r = nif->getRoot(0); + assert(r != NULL); + + const Nif::Node* nifNode = dynamic_cast(r); + if (nifNode == NULL) + { + nif->warn("First root was not a node, but a " + r->recName); + return; + } + + mRootNode = parentNode; + handleNode(nifNode, parentNode, false, std::map()); + } + + void Loader::loadAsSkeleton(Nif::NIFFilePtr nif, osg::Group *parentNode) + { + mNif = nif; + + if (nif->numRoots() < 1) + { + nif->warn("Found no root nodes"); + return; + } + + const Nif::Record* r = nif->getRoot(0); + assert(r != NULL); + + const Nif::Node* nifNode = dynamic_cast(r); + if (nifNode == NULL) + { + nif->warn("First root was not a node, but a " + r->recName); + return; + } + + mRootNode = parentNode; + + osgAnimation::Skeleton* skel = new osgAnimation::Skeleton; + mSkeleton = skel; + mRootNode->addChild(mSkeleton); + + handleNode(nifNode, mSkeleton, true, std::map()); + } + + void Loader::applyNodeProperties(const Nif::Node *nifNode, osg::Node *applyTo, std::map& boundTextures) + { + const Nif::PropertyList& props = nifNode->props; + for (size_t i = 0; i value, int animflags) + { + // FIXME animflags currently not passed to this function + //bool autoPlay = animflags & Nif::NiNode::AnimFlag_AutoPlay; + boost::shared_ptr src(new FrameTimeSource); // if autoPlay + + boost::shared_ptr function (new ControllerFunction(ctrl + , 0/*autoPlay*/)); + //scene->mMaxControllerLength = std::max(function->mStopTime, scene->mMaxControllerLength); + + mControllers.push_back(Controller(src, value, function)); + } + + void Loader::handleNode(const Nif::Node* nifNode, osg::Group* parentNode, bool createSkeleton, + std::map boundTextures) + { + osg::ref_ptr transformNode; + if (createSkeleton) + { + osgAnimation::Bone* bone = new osgAnimation::Bone; + transformNode = bone; + bone->setMatrix(toMatrix(nifNode->trafo)); + bone->setName(nifNode->name); + bone->setUpdateCallback(new UpdateBone); + bone->setInvBindMatrixInSkeletonSpace(osg::Matrixf::inverse(getWorldTransform(nifNode))); + } + else + { + transformNode = new osg::MatrixTransform; + transformNode->setMatrix(toMatrix(nifNode->trafo)); + } + + // Hide collision shapes, but don't skip the subgraph + // We still need to animate the hidden bones so the physics system can access them + // FIXME: skip creation of the TriShapes + if (nifNode->recType == Nif::RC_RootCollisionNode) + transformNode->setNodeMask(0); + + // We could probably skip hidden nodes entirely if they don't have a VisController that + // might make them visible later + if (nifNode->flags & Nif::NiNode::Flag_Hidden) + transformNode->setNodeMask(0); + + // Insert bones at position 0 to prevent update order problems (see comment in osg Skeleton.cpp) + parentNode->insertChild(0, transformNode); + + applyNodeProperties(nifNode, transformNode, boundTextures); + + if (nifNode->recType == Nif::RC_NiTriShape) + { + const Nif::NiTriShape* triShape = static_cast(nifNode); + if (!createSkeleton || triShape->skin.empty()) + handleTriShape(triShape, transformNode, boundTextures); + else + handleSkinnedTriShape(triShape, transformNode, boundTextures); + + if (!nifNode->controller.empty()) + handleMeshControllers(nifNode, transformNode, boundTextures); + } + + if (!nifNode->controller.empty()) + handleNodeControllers(nifNode, transformNode); + + const Nif::NiNode *ninode = dynamic_cast(nifNode); + if(ninode) + { + const Nif::NodeList &children = ninode->children; + for(size_t i = 0;i < children.length();++i) + { + if(!children[i].empty()) + handleNode(children[i].getPtr(), transformNode, createSkeleton, boundTextures); + } + } + } + + void Loader::handleMeshControllers(const Nif::Node *nifNode, osg::MatrixTransform *transformNode, const std::map &boundTextures) + { + for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next) + { + if (ctrl->recType == Nif::RC_NiUVController) + { + const Nif::NiUVController *uvctrl = static_cast(ctrl.getPtr()); + std::set texUnits; + for (std::map::const_iterator it = boundTextures.begin(); it != boundTextures.end(); ++it) + texUnits.insert(it->first); + boost::shared_ptr dest(new UVController::Value(transformNode->getOrCreateStateSet() + , uvctrl->data.getPtr(), texUnits)); + createController(uvctrl, dest, 0); + } + } + } + + void Loader::handleNodeControllers(const Nif::Node* nifNode, osg::MatrixTransform* transformNode) + { + bool seenKeyframeCtrl = false; + for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next) + { + if (ctrl->recType == Nif::RC_NiKeyframeController) + { + const Nif::NiKeyframeController *key = static_cast(ctrl.getPtr()); + if(!key->data.empty()) + { + if (seenKeyframeCtrl) + { + std::cerr << "Warning: multiple KeyframeControllers on the same node" << std::endl; + continue; + } + boost::shared_ptr dest(new KeyframeController::Value(transformNode, mNif, key->data.getPtr(), + transformNode->getMatrix().getRotate(), nifNode->trafo.scale)); + + createController(key, dest, 0); + seenKeyframeCtrl = true; + } + } + else if (ctrl->recType == Nif::RC_NiVisController) + { + const Nif::NiVisController* visctrl = static_cast(ctrl.getPtr()); + boost::shared_ptr dest(new VisController::Value(transformNode, visctrl->data.getPtr())); + createController(visctrl, dest, 0); + } + } + } + + void Loader::triShapeToGeometry(const Nif::NiTriShape *triShape, osg::Geometry *geometry, const std::map& boundTextures) + { + const Nif::NiTriShapeData* data = triShape->data.getPtr(); + + const Nif::NiSkinInstance *skin = (triShape->skin.empty() ? NULL : triShape->skin.getPtr()); + if (skin) + { + // Convert vertices and normals to bone space from bind position. It would be + // better to transform the bones into bind position, but there doesn't seem to + // be a reliable way to do that. + osg::ref_ptr newVerts (new osg::Vec3Array(data->vertices.size())); + osg::ref_ptr newNormals (new osg::Vec3Array(data->normals.size())); + + const Nif::NiSkinData *skinData = skin->data.getPtr(); + const Nif::NodeList &bones = skin->bones; + for(size_t b = 0;b < bones.length();b++) + { + osg::Matrixf mat = toMatrix(skinData->bones[b].trafo); + + mat = mat * getWorldTransform(bones[b].getPtr()); + + const std::vector &weights = skinData->bones[b].weights; + for(size_t i = 0;i < weights.size();i++) + { + size_t index = weights[i].vertex; + float weight = weights[i].weight; + + osg::Vec4f mult = (osg::Vec4f(data->vertices.at(index),1.f) * mat) * weight; + (*newVerts)[index] += osg::Vec3f(mult.x(),mult.y(),mult.z()); + if(newNormals->size() > index) + { + osg::Vec4 normal(data->normals[index].x(), data->normals[index].y(), data->normals[index].z(), 0.f); + normal = (normal * mat) * weight; + (*newNormals)[index] += osg::Vec3f(normal.x(),normal.y(),normal.z()); + } + } + } + // Interpolating normalized normals doesn't necessarily give you a normalized result + // Currently we're using GL_NORMALIZE, so this isn't needed + //for (unsigned int i=0;isize();++i) + // (*newNormals)[i].normalize(); + + geometry->setVertexArray(newVerts); + if (!data->normals.empty()) + geometry->setNormalArray(newNormals, osg::Array::BIND_PER_VERTEX); + } + else + { + geometry->setVertexArray(new osg::Vec3Array(data->vertices.size(), &data->vertices[0])); + if (!data->normals.empty()) + geometry->setNormalArray(new osg::Vec3Array(data->normals.size(), &data->normals[0]), osg::Array::BIND_PER_VERTEX); + } + + for (std::map::const_iterator it = boundTextures.begin(); it != boundTextures.end(); ++it) + { + int textureStage = it->first; + int uvSet = it->second; + if (uvSet >= (int)data->uvlist.size()) + { + // Occurred in "ascendedsleeper.nif", but only for hidden Shadow nodes, apparently + //std::cerr << "Warning: using an undefined UV set " << uvSet << " on TriShape " << triShape->name << std::endl; + continue; + } + + geometry->setTexCoordArray(textureStage, new osg::Vec2Array(data->uvlist[uvSet].size(), &data->uvlist[uvSet][0]), osg::Array::BIND_PER_VERTEX); + } + + // FIXME: material ColorMode should be disabled if the TriShape has no vertex colors + if (!data->colors.empty()) + geometry->setColorArray(new osg::Vec4Array(data->colors.size(), &data->colors[0]), osg::Array::BIND_PER_VERTEX); + + geometry->addPrimitiveSet(new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLES, + data->triangles.size(), + (unsigned short*)&data->triangles[0])); + } + + void Loader::handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, const std::map& boundTextures) + { + osg::ref_ptr geometry; + if(!triShape->controller.empty()) + { + Nif::ControllerPtr ctrl = triShape->controller; + do { + if(ctrl->recType == Nif::RC_NiGeomMorpherController && ctrl->flags & Nif::NiNode::ControllerFlag_Active) + { + geometry = handleMorphGeometry(static_cast(ctrl.getPtr())); + boost::shared_ptr value( + new GeomMorpherController::Value(static_cast(geometry.get()), + static_cast(ctrl.getPtr())->data.getPtr())); + createController(ctrl.getPtr(), value, 0); + break; + } + } while(!(ctrl=ctrl->next).empty()); + } + + if (!geometry.get()) + geometry = new osg::Geometry; + triShapeToGeometry(triShape, geometry.get(), boundTextures); + + osg::ref_ptr geode (new osg::Geode); + geode->addDrawable(geometry.get()); + + parentNode->addChild(geode.get()); + } + + void Loader::handleSkinnedTriShape(const Nif::NiTriShape *triShape, osg::Group *parentNode, const std::map& boundTextures) + { + osg::ref_ptr geometry (new osg::Geometry); + triShapeToGeometry(triShape, geometry.get(), boundTextures); + + osg::ref_ptr rig(new osgAnimation::RigGeometry); + rig->setSourceGeometry(geometry); + // Slightly expand the bounding box to account for movement of the bones + // For more accuracy the skinning should be relative to the parent of the first skinned bone, + // rather than the root bone. + osg::BoundingBox box = geometry->getBound(); + box.expandBy(box._min-(box._max-box._min)/2); + box.expandBy(box._max+(box._max-box._min)/2); + rig->setInitialBound(box); + + const Nif::NiSkinInstance *skin = triShape->skin.getPtr(); + + // Assign bone weights + osg::ref_ptr map (new osgAnimation::VertexInfluenceMap); + + const Nif::NiSkinData *data = skin->data.getPtr(); + const Nif::NodeList &bones = skin->bones; + for(size_t i = 0;i < bones.length();i++) + { + std::string boneName = bones[i].getPtr()->name; + + osgAnimation::VertexInfluence influence; + influence.setName(boneName); + const std::vector &weights = data->bones[i].weights; + influence.reserve(weights.size()); + for(size_t j = 0;j < weights.size();j++) + { + osgAnimation::VertexIndexWeight indexWeight = std::make_pair(weights[j].vertex, weights[j].weight); + influence.push_back(indexWeight); + } + + map->insert(std::make_pair(boneName, influence)); + } + rig->setInfluenceMap(map.get()); + + osg::ref_ptr trans(new osg::MatrixTransform); + trans->setUpdateCallback(new InvertBoneMatrix(mSkeleton)); + + osg::ref_ptr geode (new osg::Geode); + geode->addDrawable(rig.get()); + + trans->addChild(geode.get()); + parentNode->addChild(trans.get()); + } + + void Loader::handleProperty(const Nif::Property *property, const Nif::Node* nifNode, + osg::Node *node, std::map& boundTextures) + { + osg::StateSet* stateset = node->getOrCreateStateSet(); + + switch (property->recType) + { + case Nif::RC_NiStencilProperty: + { + const Nif::NiStencilProperty* stencilprop = static_cast(property); + osg::FrontFace* frontFace = new osg::FrontFace; + switch (stencilprop->data.drawMode) + { + case 1: + frontFace->setMode(osg::FrontFace::CLOCKWISE); + break; + case 0: + case 2: + default: + frontFace->setMode(osg::FrontFace::COUNTER_CLOCKWISE); + break; + } + + stateset->setAttribute(frontFace, osg::StateAttribute::ON); + stateset->setMode(GL_CULL_FACE, stencilprop->data.drawMode == 3 ? osg::StateAttribute::OFF + : osg::StateAttribute::ON); + + // Stencil settings not enabled yet, not sure if the original engine is actually using them, + // since they might conflict with Morrowind's stencil shadows. + /* + osg::Stencil* stencil = new osg::Stencil; + stencil->setFunction(func, stencilprop->data.stencilRef, stencilprop->data.stencilMask); + + stateset->setMode(GL_STENCIL_TEST, stencilprop->data.enabled != 0 ? osg::StateAttribute::ON + : osg::StateAttribute::OFF); + */ + } + case Nif::RC_NiWireframeProperty: + { + const Nif::NiWireframeProperty* wireprop = static_cast(property); + osg::PolygonMode* mode = new osg::PolygonMode; + mode->setMode(osg::PolygonMode::FRONT_AND_BACK, wireprop->flags == 0 ? osg::PolygonMode::FILL + : osg::PolygonMode::LINE); + stateset->setAttributeAndModes(mode, osg::StateAttribute::ON); + break; + } + case Nif::RC_NiZBufferProperty: + { + const Nif::NiZBufferProperty* zprop = static_cast(property); + // VER_MW doesn't support a DepthFunction according to NifSkope + osg::Depth* depth = new osg::Depth; + depth->setWriteMask((zprop->flags>>1)&1); + stateset->setAttributeAndModes(depth, osg::StateAttribute::ON); + break; + } + // OSG groups the material properties that NIFs have separate, so we have to parse them all again when one changed + case Nif::RC_NiMaterialProperty: + case Nif::RC_NiVertexColorProperty: + case Nif::RC_NiSpecularProperty: + { + // TODO: handle these in handleTriShape so we know whether vertex colors are available + std::vector materialProps; + collectMaterialProperties(nifNode, materialProps); + updateMaterialProperties(stateset, materialProps); + break; + } + case Nif::RC_NiAlphaProperty: + { + const Nif::NiAlphaProperty* alphaprop = static_cast(property); + osg::BlendFunc* blendfunc = new osg::BlendFunc; + if (alphaprop->flags&1) + { + blendfunc->setFunction(getBlendMode((alphaprop->flags>>1)&0xf), + getBlendMode((alphaprop->flags>>5)&0xf)); + stateset->setAttributeAndModes(blendfunc, osg::StateAttribute::ON); + + bool noSort = (alphaprop->flags>>13)&1; + if (!noSort) + { + stateset->setNestRenderBins(false); + stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); + } + } + else + { + stateset->setAttributeAndModes(blendfunc, osg::StateAttribute::OFF); + stateset->setNestRenderBins(false); + stateset->setRenderingHint(osg::StateSet::OPAQUE_BIN); + } + + osg::AlphaFunc* alphafunc = new osg::AlphaFunc; + if((alphaprop->flags>>9)&1) + { + alphafunc->setFunction(getTestMode((alphaprop->flags>>10)&0x7), alphaprop->data.threshold/255.f); + stateset->setAttributeAndModes(alphafunc, osg::StateAttribute::ON); + } + else + stateset->setAttributeAndModes(alphafunc, osg::StateAttribute::OFF); + break; + } + case Nif::RC_NiTexturingProperty: + { + const Nif::NiTexturingProperty* texprop = static_cast(property); + for (int i=0; itextures[i].inUse) + { + const Nif::NiTexturingProperty::Texture& tex = texprop->textures[i]; + if(tex.texture.empty()) + { + std::cerr << "Warning: texture layer " << i << " is in use but empty " << std::endl; + continue; + } + const Nif::NiSourceTexture *st = tex.texture.getPtr(); + std::string filename (st->filename); + Misc::StringUtils::toLower(filename); + filename = "textures\\" + filename; + size_t found = filename.find(".tga"); + if (found == std::string::npos) + found = filename.find(".bmp"); + if (found != std::string::npos) + filename.replace(found, 4, ".dds"); + + // tx_creature_werewolf.dds isn't loading in the correct format without this option + osgDB::Options* opts = new osgDB::Options; + opts->setOptionString("dds_dxt1_detect_rgba"); + osgDB::ReaderWriter* reader = osgDB::Registry::instance()->getReaderWriterForExtension("dds"); + osgDB::ReaderWriter::ReadResult result = reader->readImage(*resourceManager->getFile(filename.c_str()), opts); + osg::Image* image = result.getImage(); + osg::Texture2D* texture2d = new osg::Texture2D; + texture2d->setImage(image); + + unsigned int clamp = static_cast(tex.clamp); + int wrapT = (clamp) & 0x1; + int wrapS = (clamp >> 1) & 0x1; + + texture2d->setWrap(osg::Texture::WRAP_S, wrapS ? osg::Texture::REPEAT : osg::Texture::CLAMP); + texture2d->setWrap(osg::Texture::WRAP_T, wrapT ? osg::Texture::REPEAT : osg::Texture::CLAMP); + + stateset->setTextureAttributeAndModes(i, texture2d, osg::StateAttribute::ON); + + boundTextures[i] = tex.uvSet; + } + else if (boundTextures.find(i) != boundTextures.end()) + { + stateset->setTextureAttributeAndModes(i, new osg::Texture2D, osg::StateAttribute::OFF); + boundTextures.erase(i); + } + } + break; + } + case Nif::RC_NiDitherProperty: + { + stateset->setMode(GL_DITHER, property->flags != 0 ? osg::StateAttribute::ON + : osg::StateAttribute::OFF); + break; + } + default: + std::cerr << "Unhandled " << property->recName << std::endl; + break; + } + } +} diff --git a/components/nifosg/nifloader.hpp b/components/nifosg/nifloader.hpp new file mode 100644 index 000000000..a089f7651 --- /dev/null +++ b/components/nifosg/nifloader.hpp @@ -0,0 +1,84 @@ +#ifndef OPENMW_COMPONENTS_NIFOSG_LOADER +#define OPENMW_COMPONENTS_NIFOSG_LOADER + +#include + +#include // NIFFilePtr + +#include + +#include "controller.hpp" + +namespace osg +{ + class Geometry; +} +namespace osgAnimation +{ + class Bone; +} + +namespace Nif +{ + class Node; + class NiTriShape; + class Property; +} +namespace Bsa +{ + class BSAFile; +} + +namespace NifOsg +{ + + /// The main class responsible for loading NIF files into an OSG-Scenegraph. + class Loader + { + public: + /// @param node The parent of the root node for the created NIF file. + void load(Nif::NIFFilePtr file, osg::Group* parentNode); + + void loadAsSkeleton(Nif::NIFFilePtr file, osg::Group* parentNode); + + // FIXME replace with resource system + Bsa::BSAFile* resourceManager; + + // FIXME move + std::vector mControllers; + + private: + + /// @param createSkeleton If true, use an osgAnimation::Bone for NIF nodes, otherwise an osg::MatrixTransform. + void handleNode(const Nif::Node* nifNode, osg::Group* parentNode, bool createSkeleton, std::map boundTextures); + + void handleMeshControllers(const Nif::Node* nifNode, osg::MatrixTransform* transformNode, const std::map& boundTextures); + + void handleNodeControllers(const Nif::Node* nifNode, osg::MatrixTransform* transformNode); + + void handleProperty (const Nif::Property* property, const Nif::Node* nifNode, + osg::Node* node, std::map& boundTextures); + + // Creates an osg::Geometry object for the given TriShape, populates it, and attaches it to the given node. + void handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, const std::map& boundTextures); + + // Fills the vertex data for the given TriShape into the given Geometry. + void triShapeToGeometry(const Nif::NiTriShape* triShape, osg::Geometry* geom, const std::map& boundTextures); + + // Creates a skinned osg::Geometry object for the given TriShape, populates it, and attaches it to the given node. + void handleSkinnedTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, const std::map& boundTextures); + + // Applies the Properties of the given nifNode onto the StateSet of the given OSG node. + void applyNodeProperties(const Nif::Node* nifNode, osg::Node* applyTo, std::map& boundTextures); + + void createController(const Nif::Controller* ctrl, boost::shared_ptr value, int animflags); + + Nif::NIFFilePtr mNif; + + osg::Group* mRootNode; + osg::Group* mSkeleton; + }; + +} + +#endif From 6c63bab8e48a7e376f78462e2d73a08dac868975 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 23 Feb 2015 21:08:15 +0100 Subject: [PATCH 0611/3725] Change Nif::Property flags to unsigned --- components/nif/property.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/nif/property.hpp b/components/nif/property.hpp index b06044e9f..2633b16c5 100644 --- a/components/nif/property.hpp +++ b/components/nif/property.hpp @@ -33,7 +33,7 @@ class Property : public Named { public: // The meaning of these depends on the actual property type. - int flags; + unsigned int flags; void read(NIFStream *nif); }; From 74dfb23e7bb4063324b7ea643a136b1cf3421dda Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 23 Feb 2015 21:16:37 +0100 Subject: [PATCH 0612/3725] Handle material properties in trishapeToGeometry --- components/nifosg/nifloader.cpp | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 2eb57a4f8..b895f8e13 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -113,12 +113,11 @@ namespace collectMaterialProperties(nifNode->parent, out); } - void updateMaterialProperties(osg::StateSet* stateset, const std::vector& properties) + void updateMaterialProperties(osg::StateSet* stateset, const std::vector& properties, bool hasVertexColors) { int specFlags = 0; // Specular is disabled by default, even if there's a specular color in the NiMaterialProperty osg::Material* mat = new osg::Material; - // FIXME: color mode should be disabled if the TriShape has no vertex colors - mat->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE); + mat->setColorMode(hasVertexColors ? osg::Material::AMBIENT_AND_DIFFUSE : osg::Material::OFF); for (std::vector::const_reverse_iterator it = properties.rbegin(); it != properties.rend(); ++it) { const Nif::Property* property = *it; @@ -145,6 +144,8 @@ namespace case Nif::RC_NiVertexColorProperty: { const Nif::NiVertexColorProperty* vertprop = static_cast(property); + if (!hasVertexColors) + break; switch (vertprop->flags) { case 0: @@ -504,13 +505,20 @@ namespace NifOsg geometry->setTexCoordArray(textureStage, new osg::Vec2Array(data->uvlist[uvSet].size(), &data->uvlist[uvSet][0]), osg::Array::BIND_PER_VERTEX); } - // FIXME: material ColorMode should be disabled if the TriShape has no vertex colors if (!data->colors.empty()) geometry->setColorArray(new osg::Vec4Array(data->colors.size(), &data->colors[0]), osg::Array::BIND_PER_VERTEX); geometry->addPrimitiveSet(new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLES, data->triangles.size(), (unsigned short*)&data->triangles[0])); + + // osg::Material properties are handled here for two reasons: + // - if there are no vertex colors, we need to disable colorMode. + // - there are 3 "overlapping" nif properties that all affect the osg::Material, handling them + // above the actual renderable would be tedious. + std::vector materialProps; + collectMaterialProperties(triShape, materialProps); + updateMaterialProperties(geometry->getOrCreateStateSet(), materialProps, !data->colors.empty()); } void Loader::handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, const std::map& boundTextures) @@ -653,9 +661,6 @@ namespace NifOsg case Nif::RC_NiSpecularProperty: { // TODO: handle these in handleTriShape so we know whether vertex colors are available - std::vector materialProps; - collectMaterialProperties(nifNode, materialProps); - updateMaterialProperties(stateset, materialProps); break; } case Nif::RC_NiAlphaProperty: From 3839d6f777d629ed8d330f07d43ff4681cbcb328 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 23 Feb 2015 21:21:19 +0100 Subject: [PATCH 0613/3725] Simplify controller classes --- components/nifosg/controller.cpp | 22 +++--- components/nifosg/controller.hpp | 118 +++++++++++++------------------ components/nifosg/nifloader.cpp | 8 +-- 3 files changed, 66 insertions(+), 82 deletions(-) diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index 4e600c3a1..086e679d6 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -92,7 +92,7 @@ float ControllerFunction::calculate(float value) return value; } -osg::Quat KeyframeController::Value::interpKey(const Nif::QuaternionKeyMap::MapType &keys, float time) +osg::Quat KeyframeControllerValue::interpKey(const Nif::QuaternionKeyMap::MapType &keys, float time) { if(time <= keys.begin()->first) return keys.begin()->second.mValue; @@ -125,7 +125,7 @@ osg::Quat KeyframeController::Value::interpKey(const Nif::QuaternionKeyMap::MapT return keys.rbegin()->second.mValue; } -osg::Quat KeyframeController::Value::getXYZRotation(float time) const +osg::Quat KeyframeControllerValue::getXYZRotation(float time) const { float xrot = interpKey(mXRotations->mKeys, time); float yrot = interpKey(mYRotations->mKeys, time); @@ -136,7 +136,7 @@ osg::Quat KeyframeController::Value::getXYZRotation(float time) const return (zr*yr*xr); } -KeyframeController::Value::Value(osg::Node *target, const Nif::NIFFilePtr &nif, const Nif::NiKeyframeData *data, +KeyframeControllerValue::KeyframeControllerValue(osg::Node *target, const Nif::NIFFilePtr &nif, const Nif::NiKeyframeData *data, osg::Quat initialQuat, float initialScale) : NodeTargetValue(target) , mRotations(&data->mRotations) @@ -150,7 +150,7 @@ KeyframeController::Value::Value(osg::Node *target, const Nif::NIFFilePtr &nif, , mInitialScale(initialScale) { } -osg::Vec3f KeyframeController::Value::getTranslation(float time) const +osg::Vec3f KeyframeControllerValue::getTranslation(float time) const { if(mTranslations->mKeys.size() > 0) return interpKey(mTranslations->mKeys, time); @@ -158,7 +158,7 @@ osg::Vec3f KeyframeController::Value::getTranslation(float time) const return trans->getMatrix().getTrans(); } -void KeyframeController::Value::setValue(float time) +void KeyframeControllerValue::setValue(float time) { osg::MatrixTransform* trans = static_cast(mNode); osg::Matrix mat = trans->getMatrix(); @@ -200,14 +200,14 @@ void Controller::update() } } -GeomMorpherController::Value::Value(osgAnimation::MorphGeometry *geom, const Nif::NiMorphData* morphData) +GeomMorpherControllerValue::GeomMorpherControllerValue(osgAnimation::MorphGeometry *geom, const Nif::NiMorphData* morphData) : mGeom(geom) , mMorphs(morphData->mMorphs) { } -void GeomMorpherController::Value::setValue(float time) +void GeomMorpherControllerValue::setValue(float time) { if (mMorphs.size() <= 1) return; @@ -223,7 +223,7 @@ void GeomMorpherController::Value::setValue(float time) } } -UVController::Value::Value(osg::StateSet *target, const Nif::NiUVData *data, std::set textureUnits) +UVControllerValue::UVControllerValue(osg::StateSet *target, const Nif::NiUVData *data, std::set textureUnits) : mStateSet(target) , mUTrans(data->mKeyList[0]) , mVTrans(data->mKeyList[1]) @@ -233,7 +233,7 @@ UVController::Value::Value(osg::StateSet *target, const Nif::NiUVData *data, std { } -void UVController::Value::setValue(float value) +void UVControllerValue::setValue(float value) { float uTrans = interpKey(mUTrans.mKeys, value, 0.0f); float vTrans = interpKey(mVTrans.mKeys, value, 0.0f); @@ -252,7 +252,7 @@ void UVController::Value::setValue(float value) } } -bool VisController::Value::calculate(float time) const +bool VisControllerValue::calculate(float time) const { if(mData.size() == 0) return true; @@ -265,7 +265,7 @@ bool VisController::Value::calculate(float time) const return mData.back().isSet; } -void VisController::Value::setValue(float time) +void VisControllerValue::setValue(float time) { bool vis = calculate(time); mNode->setNodeMask(vis ? ~0 : 0); diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index e45bc7fea..d916f894f 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -114,99 +114,83 @@ namespace NifOsg { return mNode; } }; - class GeomMorpherController + class GeomMorpherControllerValue : public ControllerValue, public ValueInterpolator { public: - class Value : public ControllerValue, public ValueInterpolator - { - public: - // FIXME: don't copy the morph data? - Value(osgAnimation::MorphGeometry* geom, const Nif::NiMorphData *data); + // FIXME: don't copy the morph data? + GeomMorpherControllerValue(osgAnimation::MorphGeometry* geom, const Nif::NiMorphData *data); - virtual void setValue(float time); + virtual void setValue(float time); - private: - osgAnimation::MorphGeometry* mGeom; - std::vector mMorphs; - }; + private: + osgAnimation::MorphGeometry* mGeom; + std::vector mMorphs; }; - class KeyframeController + class KeyframeControllerValue : public NodeTargetValue, public ValueInterpolator { - public: - class Value : public NodeTargetValue, public ValueInterpolator - { - private: - const Nif::QuaternionKeyMap* mRotations; - const Nif::FloatKeyMap* mXRotations; - const Nif::FloatKeyMap* mYRotations; - const Nif::FloatKeyMap* mZRotations; - const Nif::Vector3KeyMap* mTranslations; - const Nif::FloatKeyMap* mScales; - Nif::NIFFilePtr mNif; // Hold a SharedPtr to make sure key lists stay valid + private: + const Nif::QuaternionKeyMap* mRotations; + const Nif::FloatKeyMap* mXRotations; + const Nif::FloatKeyMap* mYRotations; + const Nif::FloatKeyMap* mZRotations; + const Nif::Vector3KeyMap* mTranslations; + const Nif::FloatKeyMap* mScales; + Nif::NIFFilePtr mNif; // Hold a SharedPtr to make sure key lists stay valid - osg::Quat mInitialQuat; - float mInitialScale; + osg::Quat mInitialQuat; + float mInitialScale; - using ValueInterpolator::interpKey; + using ValueInterpolator::interpKey; - osg::Quat interpKey(const Nif::QuaternionKeyMap::MapType &keys, float time); + osg::Quat interpKey(const Nif::QuaternionKeyMap::MapType &keys, float time); - osg::Quat getXYZRotation(float time) const; + osg::Quat getXYZRotation(float time) const; - public: - /// @note The NiKeyFrameData must be valid as long as this KeyframeController exists. - Value(osg::Node *target, const Nif::NIFFilePtr& nif, const Nif::NiKeyframeData *data, - osg::Quat initialQuat, float initialScale); + public: + /// @note The NiKeyFrameData must be valid as long as this KeyframeController exists. + KeyframeControllerValue(osg::Node *target, const Nif::NIFFilePtr& nif, const Nif::NiKeyframeData *data, + osg::Quat initialQuat, float initialScale); - virtual osg::Vec3f getTranslation(float time) const; + virtual osg::Vec3f getTranslation(float time) const; - virtual void setValue(float time); - }; + virtual void setValue(float time); }; - class UVController + class UVControllerValue : public ControllerValue, ValueInterpolator { + private: + osg::StateSet* mStateSet; + Nif::FloatKeyMap mUTrans; + Nif::FloatKeyMap mVTrans; + Nif::FloatKeyMap mUScale; + Nif::FloatKeyMap mVScale; + std::set mTextureUnits; + public: - class Value : public ControllerValue, ValueInterpolator - { - private: - osg::StateSet* mStateSet; - Nif::FloatKeyMap mUTrans; - Nif::FloatKeyMap mVTrans; - Nif::FloatKeyMap mUScale; - Nif::FloatKeyMap mVScale; - std::set mTextureUnits; - - public: - Value(osg::StateSet* target, const Nif::NiUVData *data, std::set textureUnits); - - virtual void setValue(float value); - }; + UVControllerValue(osg::StateSet* target, const Nif::NiUVData *data, std::set textureUnits); + + virtual void setValue(float value); }; - class VisController + class VisControllerValue : public NodeTargetValue { - public: - class Value : public NodeTargetValue - { - private: - std::vector mData; + private: + std::vector mData; - bool calculate(float time) const; + bool calculate(float time) const; - public: - Value(osg::Node *target, const Nif::NiVisData *data) - : NodeTargetValue(target) - , mData(data->mVis) - { } + public: + VisControllerValue(osg::Node *target, const Nif::NiVisData *data) + : NodeTargetValue(target) + , mData(data->mVis) + { } - virtual osg::Vec3f getTranslation(float time) const - { return osg::Vec3f(); } + virtual osg::Vec3f getTranslation(float time) const + { return osg::Vec3f(); } - virtual void setValue(float time); - }; + virtual void setValue(float time); }; } diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index b895f8e13..abeb17b6f 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -400,7 +400,7 @@ namespace NifOsg std::set texUnits; for (std::map::const_iterator it = boundTextures.begin(); it != boundTextures.end(); ++it) texUnits.insert(it->first); - boost::shared_ptr dest(new UVController::Value(transformNode->getOrCreateStateSet() + boost::shared_ptr dest(new UVControllerValue(transformNode->getOrCreateStateSet() , uvctrl->data.getPtr(), texUnits)); createController(uvctrl, dest, 0); } @@ -422,7 +422,7 @@ namespace NifOsg std::cerr << "Warning: multiple KeyframeControllers on the same node" << std::endl; continue; } - boost::shared_ptr dest(new KeyframeController::Value(transformNode, mNif, key->data.getPtr(), + boost::shared_ptr dest(new KeyframeControllerValue(transformNode, mNif, key->data.getPtr(), transformNode->getMatrix().getRotate(), nifNode->trafo.scale)); createController(key, dest, 0); @@ -432,7 +432,7 @@ namespace NifOsg else if (ctrl->recType == Nif::RC_NiVisController) { const Nif::NiVisController* visctrl = static_cast(ctrl.getPtr()); - boost::shared_ptr dest(new VisController::Value(transformNode, visctrl->data.getPtr())); + boost::shared_ptr dest(new VisControllerValue(transformNode, visctrl->data.getPtr())); createController(visctrl, dest, 0); } } @@ -532,7 +532,7 @@ namespace NifOsg { geometry = handleMorphGeometry(static_cast(ctrl.getPtr())); boost::shared_ptr value( - new GeomMorpherController::Value(static_cast(geometry.get()), + new GeomMorpherControllerValue(static_cast(geometry.get()), static_cast(ctrl.getPtr())->data.getPtr())); createController(ctrl.getPtr(), value, 0); break; From c54ee16748390b3bb0775b0508be6135ecf357b9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 23 Feb 2015 21:44:01 +0100 Subject: [PATCH 0614/3725] Add AlphaController and MaterialColorController --- components/nifosg/controller.cpp | 39 +++++++++ components/nifosg/controller.hpp | 24 ++++++ components/nifosg/nifloader.cpp | 137 ++++++++++++++++++------------- components/nifosg/nifloader.hpp | 4 + 4 files changed, 148 insertions(+), 56 deletions(-) diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index 086e679d6..8ac7f004c 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -2,8 +2,11 @@ #include #include +#include #include +#include + #include namespace NifOsg @@ -271,5 +274,41 @@ void VisControllerValue::setValue(float time) mNode->setNodeMask(vis ? ~0 : 0); } +AlphaControllerValue::AlphaControllerValue(osg::StateSet *target, const Nif::NiFloatData *data) + : mTarget(target) + , mData(data->mKeyList) +{ +} + +void AlphaControllerValue::setValue(float time) +{ + float value = interpKey(mData.mKeys, time); + osg::Material* mat = dynamic_cast(mTarget->getAttribute(osg::StateAttribute::MATERIAL)); + if (!mat) + return; + + osg::Vec4f diffuse = mat->getDiffuse(osg::Material::FRONT_AND_BACK); + diffuse.a() = value; + mat->setDiffuse(osg::Material::FRONT_AND_BACK, diffuse); +} + +MaterialColorControllerValue::MaterialColorControllerValue(osg::StateSet *target, const Nif::NiPosData *data) + : mTarget(target), mData(data->mKeyList) +{ + +} + +void MaterialColorControllerValue::setValue(float time) +{ + osg::Vec3f value = interpKey(mData.mKeys, time); + osg::Material* mat = dynamic_cast(mTarget->getAttribute(osg::StateAttribute::MATERIAL)); + if (!mat) + return; + + osg::Vec4f diffuse = mat->getDiffuse(osg::Material::FRONT_AND_BACK); + diffuse.set(value.x(), value.y(), value.z(), diffuse.a()); + mat->setDiffuse(osg::Material::FRONT_AND_BACK, diffuse); +} + } diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index d916f894f..af09bda64 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -193,6 +193,30 @@ namespace NifOsg virtual void setValue(float time); }; + class AlphaControllerValue : public ControllerValue, public ValueInterpolator + { + private: + osg::StateSet* mTarget; + Nif::FloatKeyMap mData; + + public: + AlphaControllerValue(osg::StateSet* target, const Nif::NiFloatData *data); + + virtual void setValue(float time); + }; + + class MaterialColorControllerValue : public ControllerValue, public ValueInterpolator + { + private: + osg::StateSet* mTarget; + Nif::Vector3KeyMap mData; + + public: + MaterialColorControllerValue(osg::StateSet* target, const Nif::NiPosData *data); + + virtual void setValue(float time); + }; + } #endif diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index abeb17b6f..ebc4911c8 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -113,61 +113,6 @@ namespace collectMaterialProperties(nifNode->parent, out); } - void updateMaterialProperties(osg::StateSet* stateset, const std::vector& properties, bool hasVertexColors) - { - int specFlags = 0; // Specular is disabled by default, even if there's a specular color in the NiMaterialProperty - osg::Material* mat = new osg::Material; - mat->setColorMode(hasVertexColors ? osg::Material::AMBIENT_AND_DIFFUSE : osg::Material::OFF); - for (std::vector::const_reverse_iterator it = properties.rbegin(); it != properties.rend(); ++it) - { - const Nif::Property* property = *it; - switch (property->recType) - { - case Nif::RC_NiSpecularProperty: - { - specFlags = property->flags; - break; - } - case Nif::RC_NiMaterialProperty: - { - const Nif::NiMaterialProperty* matprop = static_cast(property); - - mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(matprop->data.diffuse, matprop->data.alpha)); - mat->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(matprop->data.ambient, 1.f)); - mat->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(matprop->data.emissive, 1.f)); - - mat->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4f(matprop->data.specular, 1.f)); - mat->setShininess(osg::Material::FRONT_AND_BACK, matprop->data.glossiness); - - break; - } - case Nif::RC_NiVertexColorProperty: - { - const Nif::NiVertexColorProperty* vertprop = static_cast(property); - if (!hasVertexColors) - break; - switch (vertprop->flags) - { - case 0: - mat->setColorMode(osg::Material::OFF); - break; - case 1: - mat->setColorMode(osg::Material::EMISSION); - break; - case 2: - mat->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE); - break; - } - } - } - } - - if (specFlags == 0) - mat->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f,0.f,0.f,0.f)); - - stateset->setAttributeAndModes(mat, osg::StateAttribute::ON); - } - // NodeCallback used to update the bone matrices in skeleton space as needed for skinning. class UpdateBone : public osg::NodeCallback { @@ -438,6 +383,27 @@ namespace NifOsg } } + void Loader::handleMaterialControllers(const Nif::Property *materialProperty, osg::StateSet *stateset) + { + for (Nif::ControllerPtr ctrl = materialProperty->controller; !ctrl.empty(); ctrl = ctrl->next) + { + if (ctrl->recType == Nif::RC_NiAlphaController) + { + const Nif::NiAlphaController* alphactrl = static_cast(ctrl.getPtr()); + boost::shared_ptr dest(new AlphaControllerValue(stateset, alphactrl->data.getPtr())); + createController(alphactrl, dest, 0); + } + else if (ctrl->recType == Nif::RC_NiMaterialColorController) + { + const Nif::NiMaterialColorController* matctrl = static_cast(ctrl.getPtr()); + boost::shared_ptr dest(new MaterialColorControllerValue(stateset, matctrl->data.getPtr())); + createController(matctrl, dest, 0); + } + else + std::cerr << "Unexpected material controller " << ctrl->recType << std::endl; + } + } + void Loader::triShapeToGeometry(const Nif::NiTriShape *triShape, osg::Geometry *geometry, const std::map& boundTextures) { const Nif::NiTriShapeData* data = triShape->data.getPtr(); @@ -518,7 +484,7 @@ namespace NifOsg // above the actual renderable would be tedious. std::vector materialProps; collectMaterialProperties(triShape, materialProps); - updateMaterialProperties(geometry->getOrCreateStateSet(), materialProps, !data->colors.empty()); + applyMaterialProperties(geometry->getOrCreateStateSet(), materialProps, !data->colors.empty()); } void Loader::handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, const std::map& boundTextures) @@ -761,4 +727,63 @@ namespace NifOsg break; } } + + void Loader::applyMaterialProperties(osg::StateSet* stateset, const std::vector& properties, bool hasVertexColors) + { + int specFlags = 0; // Specular is disabled by default, even if there's a specular color in the NiMaterialProperty + osg::Material* mat = new osg::Material; + mat->setColorMode(hasVertexColors ? osg::Material::AMBIENT_AND_DIFFUSE : osg::Material::OFF); + // TODO: check if the OpenGL default material values are actually the default NIF material values, for when there's no NiMaterialProperty + for (std::vector::const_reverse_iterator it = properties.rbegin(); it != properties.rend(); ++it) + { + const Nif::Property* property = *it; + switch (property->recType) + { + case Nif::RC_NiSpecularProperty: + { + specFlags = property->flags; + break; + } + case Nif::RC_NiMaterialProperty: + { + const Nif::NiMaterialProperty* matprop = static_cast(property); + + mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(matprop->data.diffuse, matprop->data.alpha)); + mat->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(matprop->data.ambient, 1.f)); + mat->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(matprop->data.emissive, 1.f)); + + mat->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4f(matprop->data.specular, 1.f)); + mat->setShininess(osg::Material::FRONT_AND_BACK, matprop->data.glossiness); + + if (!matprop->controller.empty()) + handleMaterialControllers(matprop, stateset); + + break; + } + case Nif::RC_NiVertexColorProperty: + { + const Nif::NiVertexColorProperty* vertprop = static_cast(property); + if (!hasVertexColors) + break; + switch (vertprop->flags) + { + case 0: + mat->setColorMode(osg::Material::OFF); + break; + case 1: + mat->setColorMode(osg::Material::EMISSION); + break; + case 2: + mat->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE); + break; + } + } + } + } + + if (specFlags == 0) + mat->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f,0.f,0.f,0.f)); + + stateset->setAttributeAndModes(mat, osg::StateAttribute::ON); + } } diff --git a/components/nifosg/nifloader.hpp b/components/nifosg/nifloader.hpp index a089f7651..3b2443eb9 100644 --- a/components/nifosg/nifloader.hpp +++ b/components/nifosg/nifloader.hpp @@ -56,6 +56,8 @@ namespace NifOsg void handleNodeControllers(const Nif::Node* nifNode, osg::MatrixTransform* transformNode); + void handleMaterialControllers(const Nif::Property* materialProperty, osg::StateSet* stateset); + void handleProperty (const Nif::Property* property, const Nif::Node* nifNode, osg::Node* node, std::map& boundTextures); @@ -71,6 +73,8 @@ namespace NifOsg // Applies the Properties of the given nifNode onto the StateSet of the given OSG node. void applyNodeProperties(const Nif::Node* nifNode, osg::Node* applyTo, std::map& boundTextures); + void applyMaterialProperties(osg::StateSet* stateset, const std::vector& properties, bool hasVertexColors); + void createController(const Nif::Controller* ctrl, boost::shared_ptr value, int animflags); Nif::NIFFilePtr mNif; From 6c8613ae356df1642991ab19ec8433c2d723dbe1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 23 Feb 2015 23:21:56 +0100 Subject: [PATCH 0615/3725] Add DarkTexture and DetailTexture --- components/nifosg/nifloader.cpp | 49 +++++++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index ebc4911c8..135578888 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -26,6 +26,8 @@ #include #include #include +#include +#include #include @@ -668,10 +670,17 @@ namespace NifOsg const Nif::NiTexturingProperty* texprop = static_cast(property); for (int i=0; itextures[i].inUse) { + if (i != Nif::NiTexturingProperty::BaseTexture + && i != Nif::NiTexturingProperty::GlowTexture + && i != Nif::NiTexturingProperty::DarkTexture + && i != Nif::NiTexturingProperty::DetailTexture) + { + std::cerr << "Warning: unhandled texture stage " << i << std::endl; + continue; + } + const Nif::NiTexturingProperty::Texture& tex = texprop->textures[i]; if(tex.texture.empty()) { @@ -679,6 +688,11 @@ namespace NifOsg continue; } const Nif::NiSourceTexture *st = tex.texture.getPtr(); + if (!st->external) + { + std::cerr << "Warning: unhandled internal texture " << std::endl; + continue; + } std::string filename (st->filename); Misc::StringUtils::toLower(filename); filename = "textures\\" + filename; @@ -706,6 +720,37 @@ namespace NifOsg stateset->setTextureAttributeAndModes(i, texture2d, osg::StateAttribute::ON); + if (i == Nif::NiTexturingProperty::GlowTexture) + { + osg::TexEnv* texEnv = new osg::TexEnv; + texEnv->setMode(osg::TexEnv::ADD); + stateset->setTextureAttributeAndModes(i, texEnv, osg::StateAttribute::ON); + } + else if (i == Nif::NiTexturingProperty::DarkTexture) + { + // untested + osg::TexEnv* texEnv = new osg::TexEnv; + texEnv->setMode(osg::TexEnv::MODULATE); + stateset->setTextureAttributeAndModes(i, texEnv, osg::StateAttribute::ON); + } + else if (i == Nif::NiTexturingProperty::DetailTexture) + { + // untested + osg::TexEnvCombine* texEnv = new osg::TexEnvCombine; + texEnv->setScale_RGB(2.f); + texEnv->setCombine_Alpha(GL_MODULATE); + texEnv->setOperand0_Alpha(GL_SRC_ALPHA); + texEnv->setOperand1_Alpha(GL_SRC_ALPHA); + texEnv->setSource0_Alpha(GL_PREVIOUS); + texEnv->setSource1_Alpha(GL_TEXTURE); + texEnv->setCombine_RGB(GL_MODULATE); + texEnv->setOperand0_RGB(GL_SRC_COLOR); + texEnv->setOperand1_RGB(GL_SRC_COLOR); + texEnv->setSource0_RGB(GL_PREVIOUS); + texEnv->setSource1_RGB(GL_TEXTURE); + stateset->setTextureAttributeAndModes(i, texEnv, osg::StateAttribute::ON); + } + boundTextures[i] = tex.uvSet; } else if (boundTextures.find(i) != boundTextures.end()) From 2a92fb57f72f8934b961adf3efd46bc8bbe85036 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 24 Feb 2015 00:02:10 +0100 Subject: [PATCH 0616/3725] Add FlipController --- components/nifosg/controller.cpp | 21 ++++++ components/nifosg/controller.hpp | 19 ++++++ components/nifosg/nifloader.cpp | 107 ++++++++++++++++++++++--------- components/nifosg/nifloader.hpp | 23 ++++--- 4 files changed, 130 insertions(+), 40 deletions(-) diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index 8ac7f004c..041036e5b 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -310,5 +311,25 @@ void MaterialColorControllerValue::setValue(float time) mat->setDiffuse(osg::Material::FRONT_AND_BACK, diffuse); } +FlipControllerValue::FlipControllerValue(osg::StateSet* target, const Nif::NiFlipController *ctrl, + std::vector > textures) + : mTexSlot(ctrl->mTexSlot) + , mDelta(ctrl->mDelta) + , mTextures(textures) + , mTarget(target) +{ +} + +void FlipControllerValue::setValue(float time) +{ + if (mDelta == 0) + return; + int curTexture = int(time / mDelta) % mTextures.size(); + osg::Texture2D* tex = dynamic_cast(mTarget->getAttribute(osg::StateAttribute::TEXTURE)); + if (!tex) + return; + tex->setImage(mTextures[curTexture].get()); +} + } diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index af09bda64..421f00277 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -12,6 +12,10 @@ #include //UVController +// FlipController +#include +#include + #include @@ -217,6 +221,21 @@ namespace NifOsg virtual void setValue(float time); }; + // untested + class FlipControllerValue : public ControllerValue + { + private: + osg::StateSet* mTarget; + int mTexSlot; + float mDelta; + std::vector > mTextures; + + public: + FlipControllerValue(osg::StateSet* target, const Nif::NiFlipController* ctrl, std::vector > textures); + + virtual void setValue(float time); + }; + } #endif diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 135578888..34c2f0ce0 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -220,7 +220,7 @@ namespace NifOsg } mRootNode = parentNode; - handleNode(nifNode, parentNode, false, std::map()); + handleNode(nifNode, parentNode, false, std::map(), 0); } void Loader::loadAsSkeleton(Nif::NIFFilePtr nif, osg::Group *parentNode) @@ -249,16 +249,16 @@ namespace NifOsg mSkeleton = skel; mRootNode->addChild(mSkeleton); - handleNode(nifNode, mSkeleton, true, std::map()); + handleNode(nifNode, mSkeleton, true, std::map(), 0); } - void Loader::applyNodeProperties(const Nif::Node *nifNode, osg::Node *applyTo, std::map& boundTextures) + void Loader::applyNodeProperties(const Nif::Node *nifNode, osg::Node *applyTo, std::map& boundTextures, int animflags) { const Nif::PropertyList& props = nifNode->props; for (size_t i = 0; i boundTextures) + std::map boundTextures, int animflags, bool collisionNode) { osg::ref_ptr transformNode; if (createSkeleton) @@ -294,11 +294,16 @@ namespace NifOsg transformNode->setMatrix(toMatrix(nifNode->trafo)); } + if (nifNode->recType == Nif::RC_NiBSAnimationNode) + animflags |= nifNode->flags; + // Hide collision shapes, but don't skip the subgraph // We still need to animate the hidden bones so the physics system can access them - // FIXME: skip creation of the TriShapes if (nifNode->recType == Nif::RC_RootCollisionNode) + { + collisionNode = true; transformNode->setNodeMask(0); + } // We could probably skip hidden nodes entirely if they don't have a VisController that // might make them visible later @@ -308,22 +313,22 @@ namespace NifOsg // Insert bones at position 0 to prevent update order problems (see comment in osg Skeleton.cpp) parentNode->insertChild(0, transformNode); - applyNodeProperties(nifNode, transformNode, boundTextures); + applyNodeProperties(nifNode, transformNode, boundTextures, animflags); - if (nifNode->recType == Nif::RC_NiTriShape) + if (nifNode->recType == Nif::RC_NiTriShape && !collisionNode) { const Nif::NiTriShape* triShape = static_cast(nifNode); if (!createSkeleton || triShape->skin.empty()) - handleTriShape(triShape, transformNode, boundTextures); + handleTriShape(triShape, transformNode, boundTextures, animflags); else - handleSkinnedTriShape(triShape, transformNode, boundTextures); + handleSkinnedTriShape(triShape, transformNode, boundTextures, animflags); if (!nifNode->controller.empty()) - handleMeshControllers(nifNode, transformNode, boundTextures); + handleMeshControllers(nifNode, transformNode, boundTextures, animflags); } if (!nifNode->controller.empty()) - handleNodeControllers(nifNode, transformNode); + handleNodeControllers(nifNode, transformNode, animflags); const Nif::NiNode *ninode = dynamic_cast(nifNode); if(ninode) @@ -332,12 +337,12 @@ namespace NifOsg for(size_t i = 0;i < children.length();++i) { if(!children[i].empty()) - handleNode(children[i].getPtr(), transformNode, createSkeleton, boundTextures); + handleNode(children[i].getPtr(), transformNode, createSkeleton, boundTextures, animflags, collisionNode); } } } - void Loader::handleMeshControllers(const Nif::Node *nifNode, osg::MatrixTransform *transformNode, const std::map &boundTextures) + void Loader::handleMeshControllers(const Nif::Node *nifNode, osg::MatrixTransform *transformNode, const std::map &boundTextures, int animflags) { for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next) { @@ -349,12 +354,12 @@ namespace NifOsg texUnits.insert(it->first); boost::shared_ptr dest(new UVControllerValue(transformNode->getOrCreateStateSet() , uvctrl->data.getPtr(), texUnits)); - createController(uvctrl, dest, 0); + createController(uvctrl, dest, animflags); } } } - void Loader::handleNodeControllers(const Nif::Node* nifNode, osg::MatrixTransform* transformNode) + void Loader::handleNodeControllers(const Nif::Node* nifNode, osg::MatrixTransform* transformNode, int animflags) { bool seenKeyframeCtrl = false; for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next) @@ -372,7 +377,7 @@ namespace NifOsg boost::shared_ptr dest(new KeyframeControllerValue(transformNode, mNif, key->data.getPtr(), transformNode->getMatrix().getRotate(), nifNode->trafo.scale)); - createController(key, dest, 0); + createController(key, dest, animflags); seenKeyframeCtrl = true; } } @@ -380,12 +385,12 @@ namespace NifOsg { const Nif::NiVisController* visctrl = static_cast(ctrl.getPtr()); boost::shared_ptr dest(new VisControllerValue(transformNode, visctrl->data.getPtr())); - createController(visctrl, dest, 0); + createController(visctrl, dest, animflags); } } } - void Loader::handleMaterialControllers(const Nif::Property *materialProperty, osg::StateSet *stateset) + void Loader::handleMaterialControllers(const Nif::Property *materialProperty, osg::StateSet *stateset, int animflags) { for (Nif::ControllerPtr ctrl = materialProperty->controller; !ctrl.empty(); ctrl = ctrl->next) { @@ -393,20 +398,59 @@ namespace NifOsg { const Nif::NiAlphaController* alphactrl = static_cast(ctrl.getPtr()); boost::shared_ptr dest(new AlphaControllerValue(stateset, alphactrl->data.getPtr())); - createController(alphactrl, dest, 0); + createController(alphactrl, dest, animflags); } else if (ctrl->recType == Nif::RC_NiMaterialColorController) { const Nif::NiMaterialColorController* matctrl = static_cast(ctrl.getPtr()); boost::shared_ptr dest(new MaterialColorControllerValue(stateset, matctrl->data.getPtr())); - createController(matctrl, dest, 0); + createController(matctrl, dest, animflags); } else std::cerr << "Unexpected material controller " << ctrl->recType << std::endl; } } - void Loader::triShapeToGeometry(const Nif::NiTriShape *triShape, osg::Geometry *geometry, const std::map& boundTextures) + void Loader::handleTextureControllers(const Nif::Property *texProperty, osg::StateSet *stateset, int animflags) + { + for (Nif::ControllerPtr ctrl = texProperty->controller; !ctrl.empty(); ctrl = ctrl->next) + { + if (ctrl->recType == Nif::RC_NiFlipController) + { + const Nif::NiFlipController* flipctrl = static_cast(ctrl.getPtr()); + std::vector > textures; + for (unsigned int i=0; imSources.length(); ++i) + { + Nif::NiSourceTexturePtr st = flipctrl->mSources[i]; + if (st.empty()) + continue; + + // FIXME: replace by ResourceHelpers + std::string filename (st->filename); + Misc::StringUtils::toLower(filename); + filename = "textures\\" + filename; + size_t found = filename.find(".tga"); + if (found == std::string::npos) + found = filename.find(".bmp"); + if (found != std::string::npos) + filename.replace(found, 4, ".dds"); + + // tx_creature_werewolf.dds isn't loading in the correct format without this option + osgDB::Options* opts = new osgDB::Options; + opts->setOptionString("dds_dxt1_detect_rgba"); + osgDB::ReaderWriter* reader = osgDB::Registry::instance()->getReaderWriterForExtension("dds"); + osgDB::ReaderWriter::ReadResult result = reader->readImage(*resourceManager->getFile(filename.c_str()), opts); + textures.push_back(osg::ref_ptr(result.getImage())); + } + boost::shared_ptr dest(new FlipControllerValue(stateset, flipctrl, textures)); + createController(flipctrl, dest, animflags); + } + else + std::cerr << "Unexpected texture controller " << ctrl->recName << std::endl; + } + } + + void Loader::triShapeToGeometry(const Nif::NiTriShape *triShape, osg::Geometry *geometry, const std::map& boundTextures, int animflags) { const Nif::NiTriShapeData* data = triShape->data.getPtr(); @@ -486,10 +530,10 @@ namespace NifOsg // above the actual renderable would be tedious. std::vector materialProps; collectMaterialProperties(triShape, materialProps); - applyMaterialProperties(geometry->getOrCreateStateSet(), materialProps, !data->colors.empty()); + applyMaterialProperties(geometry->getOrCreateStateSet(), materialProps, !data->colors.empty(), animflags); } - void Loader::handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, const std::map& boundTextures) + void Loader::handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, const std::map& boundTextures, int animflags) { osg::ref_ptr geometry; if(!triShape->controller.empty()) @@ -510,7 +554,7 @@ namespace NifOsg if (!geometry.get()) geometry = new osg::Geometry; - triShapeToGeometry(triShape, geometry.get(), boundTextures); + triShapeToGeometry(triShape, geometry.get(), boundTextures, animflags); osg::ref_ptr geode (new osg::Geode); geode->addDrawable(geometry.get()); @@ -518,10 +562,10 @@ namespace NifOsg parentNode->addChild(geode.get()); } - void Loader::handleSkinnedTriShape(const Nif::NiTriShape *triShape, osg::Group *parentNode, const std::map& boundTextures) + void Loader::handleSkinnedTriShape(const Nif::NiTriShape *triShape, osg::Group *parentNode, const std::map& boundTextures, int animflags) { osg::ref_ptr geometry (new osg::Geometry); - triShapeToGeometry(triShape, geometry.get(), boundTextures); + triShapeToGeometry(triShape, geometry.get(), boundTextures, animflags); osg::ref_ptr rig(new osgAnimation::RigGeometry); rig->setSourceGeometry(geometry); @@ -569,7 +613,7 @@ namespace NifOsg } void Loader::handleProperty(const Nif::Property *property, const Nif::Node* nifNode, - osg::Node *node, std::map& boundTextures) + osg::Node *node, std::map& boundTextures, int animflags) { osg::StateSet* stateset = node->getOrCreateStateSet(); @@ -693,6 +737,8 @@ namespace NifOsg std::cerr << "Warning: unhandled internal texture " << std::endl; continue; } + + // FIXME: replace by ResourceHelpers std::string filename (st->filename); Misc::StringUtils::toLower(filename); filename = "textures\\" + filename; @@ -758,6 +804,7 @@ namespace NifOsg stateset->setTextureAttributeAndModes(i, new osg::Texture2D, osg::StateAttribute::OFF); boundTextures.erase(i); } + handleTextureControllers(texprop, stateset, animflags); } break; } @@ -773,7 +820,7 @@ namespace NifOsg } } - void Loader::applyMaterialProperties(osg::StateSet* stateset, const std::vector& properties, bool hasVertexColors) + void Loader::applyMaterialProperties(osg::StateSet* stateset, const std::vector& properties, bool hasVertexColors, int animflags) { int specFlags = 0; // Specular is disabled by default, even if there's a specular color in the NiMaterialProperty osg::Material* mat = new osg::Material; @@ -801,7 +848,7 @@ namespace NifOsg mat->setShininess(osg::Material::FRONT_AND_BACK, matprop->data.glossiness); if (!matprop->controller.empty()) - handleMaterialControllers(matprop, stateset); + handleMaterialControllers(matprop, stateset, animflags); break; } diff --git a/components/nifosg/nifloader.hpp b/components/nifosg/nifloader.hpp index 3b2443eb9..7f4aa7ea4 100644 --- a/components/nifosg/nifloader.hpp +++ b/components/nifosg/nifloader.hpp @@ -50,30 +50,33 @@ namespace NifOsg private: /// @param createSkeleton If true, use an osgAnimation::Bone for NIF nodes, otherwise an osg::MatrixTransform. - void handleNode(const Nif::Node* nifNode, osg::Group* parentNode, bool createSkeleton, std::map boundTextures); + void handleNode(const Nif::Node* nifNode, osg::Group* parentNode, bool createSkeleton, + std::map boundTextures, int animflags, bool collisionNode=false); - void handleMeshControllers(const Nif::Node* nifNode, osg::MatrixTransform* transformNode, const std::map& boundTextures); + void handleMeshControllers(const Nif::Node* nifNode, osg::MatrixTransform* transformNode, const std::map& boundTextures, int animflags); - void handleNodeControllers(const Nif::Node* nifNode, osg::MatrixTransform* transformNode); + void handleNodeControllers(const Nif::Node* nifNode, osg::MatrixTransform* transformNode, int animflags); - void handleMaterialControllers(const Nif::Property* materialProperty, osg::StateSet* stateset); + void handleMaterialControllers(const Nif::Property* materialProperty, osg::StateSet* stateset, int animflags); + + void handleTextureControllers(const Nif::Property* texProperty, osg::StateSet* stateset, int animflags); void handleProperty (const Nif::Property* property, const Nif::Node* nifNode, - osg::Node* node, std::map& boundTextures); + osg::Node* node, std::map& boundTextures, int animflags); // Creates an osg::Geometry object for the given TriShape, populates it, and attaches it to the given node. - void handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, const std::map& boundTextures); + void handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, const std::map& boundTextures, int animflags); // Fills the vertex data for the given TriShape into the given Geometry. - void triShapeToGeometry(const Nif::NiTriShape* triShape, osg::Geometry* geom, const std::map& boundTextures); + void triShapeToGeometry(const Nif::NiTriShape* triShape, osg::Geometry* geom, const std::map& boundTextures, int animflags); // Creates a skinned osg::Geometry object for the given TriShape, populates it, and attaches it to the given node. - void handleSkinnedTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, const std::map& boundTextures); + void handleSkinnedTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, const std::map& boundTextures, int animflags); // Applies the Properties of the given nifNode onto the StateSet of the given OSG node. - void applyNodeProperties(const Nif::Node* nifNode, osg::Node* applyTo, std::map& boundTextures); + void applyNodeProperties(const Nif::Node* nifNode, osg::Node* applyTo, std::map& boundTextures, int animflags); - void applyMaterialProperties(osg::StateSet* stateset, const std::vector& properties, bool hasVertexColors); + void applyMaterialProperties(osg::StateSet* stateset, const std::vector& properties, bool hasVertexColors, int animflags); void createController(const Nif::Controller* ctrl, boost::shared_ptr value, int animflags); From 8d64f2081ed8ddb9251a4865fece9e011e9dd161 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 24 Feb 2015 01:25:31 +0100 Subject: [PATCH 0617/3725] Add particle system state loading --- CMakeLists.txt | 2 +- components/nifosg/nifloader.cpp | 118 ++++++++++++++++++++++++++++---- components/nifosg/nifloader.hpp | 7 +- 3 files changed, 111 insertions(+), 16 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d5b37a05b..1059b1c3a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -221,7 +221,7 @@ if (${OGRE_VERSION} VERSION_LESS "1.9") message(FATAL_ERROR "OpenMW requires Ogre 1.9 or later, please install the latest stable version from http://ogre3d.org") endif() -find_package(OpenSceneGraph 3.2.0 REQUIRED osgDB osgViewer osgGA osgAnimation) +find_package(OpenSceneGraph 3.2.0 REQUIRED osgDB osgViewer osgGA osgAnimation osgParticle) include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS}) find_package(MyGUI REQUIRED) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 34c2f0ce0..feffe2cba 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -18,6 +18,10 @@ #include #include +// particle +#include +#include + #include #include #include @@ -177,6 +181,17 @@ namespace osg::Node* mSkelRoot; }; + // HACK: Particle doesn't allow setting the initial age, but we need this for loading the particle system state + class ParticleAgeSetter : public osgParticle::Particle + { + public: + ParticleAgeSetter(float age) + : Particle() + { + _t0 = age; + } + }; + osg::ref_ptr handleMorphGeometry(const Nif::NiGeomMorpherController* morpher) { osg::ref_ptr morphGeom = new osgAnimation::MorphGeometry; @@ -220,7 +235,7 @@ namespace NifOsg } mRootNode = parentNode; - handleNode(nifNode, parentNode, false, std::map(), 0); + handleNode(nifNode, parentNode, false, std::map(), 0, 0); } void Loader::loadAsSkeleton(Nif::NIFFilePtr nif, osg::Group *parentNode) @@ -249,7 +264,7 @@ namespace NifOsg mSkeleton = skel; mRootNode->addChild(mSkeleton); - handleNode(nifNode, mSkeleton, true, std::map(), 0); + handleNode(nifNode, mSkeleton, true, std::map(), 0, 0); } void Loader::applyNodeProperties(const Nif::Node *nifNode, osg::Node *applyTo, std::map& boundTextures, int animflags) @@ -276,7 +291,7 @@ namespace NifOsg } void Loader::handleNode(const Nif::Node* nifNode, osg::Group* parentNode, bool createSkeleton, - std::map boundTextures, int animflags, bool collisionNode) + std::map boundTextures, int animflags, int particleflags, bool collisionNode) { osg::ref_ptr transformNode; if (createSkeleton) @@ -327,6 +342,9 @@ namespace NifOsg handleMeshControllers(nifNode, transformNode, boundTextures, animflags); } + if(nifNode->recType == Nif::RC_NiAutoNormalParticles || nifNode->recType == Nif::RC_NiRotatingParticles) + handleParticleSystem(nifNode, transformNode, particleflags, animflags); + if (!nifNode->controller.empty()) handleNodeControllers(nifNode, transformNode, animflags); @@ -337,7 +355,7 @@ namespace NifOsg for(size_t i = 0;i < children.length();++i) { if(!children[i].empty()) - handleNode(children[i].getPtr(), transformNode, createSkeleton, boundTextures, animflags, collisionNode); + handleNode(children[i].getPtr(), transformNode, createSkeleton, boundTextures, animflags, particleflags, collisionNode); } } } @@ -346,6 +364,8 @@ namespace NifOsg { for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next) { + if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active)) + continue; if (ctrl->recType == Nif::RC_NiUVController) { const Nif::NiUVController *uvctrl = static_cast(ctrl.getPtr()); @@ -364,6 +384,8 @@ namespace NifOsg bool seenKeyframeCtrl = false; for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next) { + if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active)) + continue; if (ctrl->recType == Nif::RC_NiKeyframeController) { const Nif::NiKeyframeController *key = static_cast(ctrl.getPtr()); @@ -394,6 +416,8 @@ namespace NifOsg { for (Nif::ControllerPtr ctrl = materialProperty->controller; !ctrl.empty(); ctrl = ctrl->next) { + if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active)) + continue; if (ctrl->recType == Nif::RC_NiAlphaController) { const Nif::NiAlphaController* alphactrl = static_cast(ctrl.getPtr()); @@ -415,6 +439,8 @@ namespace NifOsg { for (Nif::ControllerPtr ctrl = texProperty->controller; !ctrl.empty(); ctrl = ctrl->next) { + if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active)) + continue; if (ctrl->recType == Nif::RC_NiFlipController) { const Nif::NiFlipController* flipctrl = static_cast(ctrl.getPtr()); @@ -450,6 +476,71 @@ namespace NifOsg } } + void Loader::handleParticleSystem(const Nif::Node *nifNode, osg::Group *parentNode, int particleflags, int animflags) + { + osg::ref_ptr partsys (new osgParticle::ParticleSystem); + + const Nif::NiAutoNormalParticlesData *particledata = NULL; + if(nifNode->recType == Nif::RC_NiAutoNormalParticles) + particledata = static_cast(nifNode)->data.getPtr(); + else if(nifNode->recType == Nif::RC_NiRotatingParticles) + particledata = static_cast(nifNode)->data.getPtr(); + else + return; + + const Nif::NiParticleSystemController* partctrl = NULL; + for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next) + { + if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active)) + continue; + if(ctrl->recType == Nif::RC_NiParticleSystemController || ctrl->recType == Nif::RC_NiBSPArrayController) + partctrl = static_cast(ctrl.getPtr()); + } + if (!partctrl) + return; + + int i=0; + for (std::vector::const_iterator it = partctrl->particles.begin(); + iactiveCount && it != partctrl->particles.end(); ++it, ++i) + { + const Nif::NiParticleSystemController::Particle& particle = *it; + + ParticleAgeSetter particletemplate(std::max(0.f, particle.lifespan - particle.lifetime)); + + osgParticle::Particle* created = partsys->createParticle(&particletemplate); + created->setLifeTime(500);//std::max(0.f, particle.lifespan)); + created->setVelocity(particle.velocity); + created->setPosition(particledata->vertices.at(particle.vertex)); + + osg::Vec4f partcolor (1.f,1.f,1.f,1.f); + if (particle.vertex < int(particledata->colors.size())) + partcolor = particledata->colors.at(particle.vertex); + + float size = particledata->sizes.at(particle.vertex) * partctrl->size; + + created->setSizeRange(osgParticle::rangef(size, size)); + } + + osg::NodeVisitor visitor; + partsys->update(0.f, visitor); + partsys->setFrozen(true); + partsys->setSortMode(osgParticle::ParticleSystem::SORT_BACK_TO_FRONT); + + std::vector materialProps; + collectMaterialProperties(nifNode, materialProps); + applyMaterialProperties(partsys->getOrCreateStateSet(), materialProps, true, animflags); + + partsys->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF); + partsys->getOrCreateStateSet()->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); + osg::ref_ptr geode (new osg::Geode); + geode->addDrawable(partsys); + parentNode->addChild(geode); + + osgParticle::ParticleSystemUpdater* updater = new osgParticle::ParticleSystemUpdater; + updater->addParticleSystem(partsys); + parentNode->addChild(updater); + } + void Loader::triShapeToGeometry(const Nif::NiTriShape *triShape, osg::Geometry *geometry, const std::map& boundTextures, int animflags) { const Nif::NiTriShapeData* data = triShape->data.getPtr(); @@ -554,18 +645,18 @@ namespace NifOsg if (!geometry.get()) geometry = new osg::Geometry; - triShapeToGeometry(triShape, geometry.get(), boundTextures, animflags); + triShapeToGeometry(triShape, geometry, boundTextures, animflags); osg::ref_ptr geode (new osg::Geode); - geode->addDrawable(geometry.get()); + geode->addDrawable(geometry); - parentNode->addChild(geode.get()); + parentNode->addChild(geode); } void Loader::handleSkinnedTriShape(const Nif::NiTriShape *triShape, osg::Group *parentNode, const std::map& boundTextures, int animflags) { osg::ref_ptr geometry (new osg::Geometry); - triShapeToGeometry(triShape, geometry.get(), boundTextures, animflags); + triShapeToGeometry(triShape, geometry, boundTextures, animflags); osg::ref_ptr rig(new osgAnimation::RigGeometry); rig->setSourceGeometry(geometry); @@ -600,16 +691,16 @@ namespace NifOsg map->insert(std::make_pair(boneName, influence)); } - rig->setInfluenceMap(map.get()); + rig->setInfluenceMap(map); osg::ref_ptr trans(new osg::MatrixTransform); trans->setUpdateCallback(new InvertBoneMatrix(mSkeleton)); osg::ref_ptr geode (new osg::Geode); - geode->addDrawable(rig.get()); + geode->addDrawable(rig); - trans->addChild(geode.get()); - parentNode->addChild(trans.get()); + trans->addChild(geode); + parentNode->addChild(trans); } void Loader::handleProperty(const Nif::Property *property, const Nif::Node* nifNode, @@ -820,7 +911,8 @@ namespace NifOsg } } - void Loader::applyMaterialProperties(osg::StateSet* stateset, const std::vector& properties, bool hasVertexColors, int animflags) + void Loader::applyMaterialProperties(osg::StateSet* stateset, const std::vector& properties, + bool hasVertexColors, int animflags) { int specFlags = 0; // Specular is disabled by default, even if there's a specular color in the NiMaterialProperty osg::Material* mat = new osg::Material; diff --git a/components/nifosg/nifloader.hpp b/components/nifosg/nifloader.hpp index 7f4aa7ea4..0535aa838 100644 --- a/components/nifosg/nifloader.hpp +++ b/components/nifosg/nifloader.hpp @@ -51,7 +51,7 @@ namespace NifOsg /// @param createSkeleton If true, use an osgAnimation::Bone for NIF nodes, otherwise an osg::MatrixTransform. void handleNode(const Nif::Node* nifNode, osg::Group* parentNode, bool createSkeleton, - std::map boundTextures, int animflags, bool collisionNode=false); + std::map boundTextures, int animflags, int particleflags, bool collisionNode=false); void handleMeshControllers(const Nif::Node* nifNode, osg::MatrixTransform* transformNode, const std::map& boundTextures, int animflags); @@ -64,6 +64,8 @@ namespace NifOsg void handleProperty (const Nif::Property* property, const Nif::Node* nifNode, osg::Node* node, std::map& boundTextures, int animflags); + void handleParticleSystem(const Nif::Node* nifNode, osg::Group* parentNode, int particleflags, int animflags); + // Creates an osg::Geometry object for the given TriShape, populates it, and attaches it to the given node. void handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, const std::map& boundTextures, int animflags); @@ -76,7 +78,8 @@ namespace NifOsg // Applies the Properties of the given nifNode onto the StateSet of the given OSG node. void applyNodeProperties(const Nif::Node* nifNode, osg::Node* applyTo, std::map& boundTextures, int animflags); - void applyMaterialProperties(osg::StateSet* stateset, const std::vector& properties, bool hasVertexColors, int animflags); + void applyMaterialProperties(osg::StateSet* stateset, const std::vector& properties, + bool hasVertexColors, int animflags); void createController(const Nif::Controller* ctrl, boost::shared_ptr value, int animflags); From 6878e317a7c9c64ac9916ade1e9864dca5db6815 Mon Sep 17 00:00:00 2001 From: dteviot Date: Tue, 24 Feb 2015 20:06:06 +1300 Subject: [PATCH 0618/3725] launcher: decouple Combo Box model from Plug-ins model. fixes bug reported by scrawl 1. openmw.cfg had content files in order 'Bloodmoon.esm, Tribunal.esm, Morrowind.esm' 2. Blank_ESM_2.0.esm is in the Data Files directory 3. Do an ini file import. 4. Imported profile will have Blank_ESM_2.0.esm as the game file. Should be Morrowind.esm. Root cause: Game File combo box and Plugins Grid shared same data model, so changing plug-in file order also changed order of Game File combo box. --- .../contentselector/model/contentmodel.cpp | 15 ++++++- .../contentselector/model/contentmodel.hpp | 1 + .../contentselector/view/contentselector.cpp | 42 +++++++++++-------- .../contentselector/view/contentselector.hpp | 2 +- 4 files changed, 41 insertions(+), 19 deletions(-) diff --git a/components/contentselector/model/contentmodel.cpp b/components/contentselector/model/contentmodel.cpp index a4fbdcf06..485510df4 100644 --- a/components/contentselector/model/contentmodel.cpp +++ b/components/contentselector/model/contentmodel.cpp @@ -489,6 +489,19 @@ void ContentSelectorModel::ContentModel::addFiles(const QString &path) sortFiles(); } +QStringList ContentSelectorModel::ContentModel::gameFiles() const +{ + QStringList gameFiles; + foreach(const ContentSelectorModel::EsmFile *file, mFiles) + { + if (file->isGameFile()) + { + gameFiles.append(file->fileName()); + } + } + return gameFiles; +} + void ContentSelectorModel::ContentModel::sortFiles() { //first, sort the model such that all dependencies are ordered upstream (gamefile) first. @@ -589,7 +602,7 @@ void ContentSelectorModel::ContentModel::checkForLoadOrderErrors() QList ContentSelectorModel::ContentModel::checkForLoadOrderErrors(const EsmFile *file, int row) const { QList errors = QList(); - foreach(QString dependentfileName, file->gameFiles()) + foreach(const QString &dependentfileName, file->gameFiles()) { const EsmFile* dependentFile = item(dependentfileName); diff --git a/components/contentselector/model/contentmodel.hpp b/components/contentselector/model/contentmodel.hpp index 3d8229aeb..658555852 100644 --- a/components/contentselector/model/contentmodel.hpp +++ b/components/contentselector/model/contentmodel.hpp @@ -47,6 +47,7 @@ namespace ContentSelectorModel QModelIndex indexFromItem(const EsmFile *item) const; const EsmFile *item(const QString &name) const; + QStringList gameFiles() const; bool isEnabled (QModelIndex index) const; bool isChecked(const QString &filepath) const; diff --git a/components/contentselector/view/contentselector.cpp b/components/contentselector/view/contentselector.cpp index 3aa5ddf80..2363ae477 100644 --- a/components/contentselector/view/contentselector.cpp +++ b/components/contentselector/view/contentselector.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include ContentSelectorView::ContentSelector::ContentSelector(QWidget *parent) : @@ -33,13 +34,7 @@ void ContentSelectorView::ContentSelector::buildGameFileView() { ui.gameFileView->setVisible (true); - mGameFileProxyModel = new QSortFilterProxyModel(this); - mGameFileProxyModel->setFilterRegExp(QString::number((int)ContentSelectorModel::ContentType_GameFile)); - mGameFileProxyModel->setFilterRole (Qt::UserRole); - mGameFileProxyModel->setSourceModel (mContentModel); - ui.gameFileView->setPlaceholderText(QString("Select a game file...")); - ui.gameFileView->setModel(mGameFileProxyModel); connect (ui.gameFileView, SIGNAL (currentIndexChanged(int)), this, SLOT (slotCurrentGameFileIndexChanged(int))); @@ -129,6 +124,15 @@ void ContentSelectorView::ContentSelector::addFiles(const QString &path) { mContentModel->addFiles(path); + // add any game files to the combo box + foreach(const QString gameFileName, mContentModel->gameFiles()) + { + if (ui.gameFileView->findText(gameFileName) == -1) + { + ui.gameFileView->addItem(gameFileName); + } + } + if (ui.gameFileView->currentIndex() != -1) ui.gameFileView->setCurrentIndex(-1); @@ -150,29 +154,33 @@ void ContentSelectorView::ContentSelector::slotCurrentGameFileIndexChanged(int i { static int oldIndex = -1; - QAbstractItemModel *const model = ui.gameFileView->model(); - QSortFilterProxyModel *proxy = dynamic_cast(model); - - if (proxy) - proxy->setDynamicSortFilter(false); - if (index != oldIndex) { if (oldIndex > -1) - model->setData(model->index(oldIndex, 0), false, Qt::UserRole + 1); + { + setGameFileSelected(oldIndex, false); + } oldIndex = index; - model->setData(model->index(index, 0), true, Qt::UserRole + 1); + setGameFileSelected(index, true); mContentModel->checkForLoadOrderErrors(); } - if (proxy) - proxy->setDynamicSortFilter(true); - emit signalCurrentGamefileIndexChanged (index); } +void ContentSelectorView::ContentSelector::setGameFileSelected(int index, bool selected) +{ + QString fileName = ui.gameFileView->itemText(index); + const ContentSelectorModel::EsmFile* file = mContentModel->item(fileName); + if (file != NULL) + { + QModelIndex index(mContentModel->indexFromItem(file)); + mContentModel->setData(index, selected, Qt::UserRole + 1); + } +} + void ContentSelectorView::ContentSelector::slotAddonTableItemActivated(const QModelIndex &index) { QModelIndex sourceIndex = mAddonProxyModel->mapToSource (index); diff --git a/components/contentselector/view/contentselector.hpp b/components/contentselector/view/contentselector.hpp index 8651dac2e..2507cf6ad 100644 --- a/components/contentselector/view/contentselector.hpp +++ b/components/contentselector/view/contentselector.hpp @@ -19,7 +19,6 @@ namespace ContentSelectorView protected: ContentSelectorModel::ContentModel *mContentModel; - QSortFilterProxyModel *mGameFileProxyModel; QSortFilterProxyModel *mAddonProxyModel; public: @@ -52,6 +51,7 @@ namespace ContentSelectorView void buildContentModel(); void buildGameFileView(); void buildAddonView(); + void setGameFileSelected(int index, bool selected); signals: void signalCurrentGamefileIndexChanged (int); From cc815c63f18407de5ffc684e3282a53479ecf348 Mon Sep 17 00:00:00 2001 From: dteviot Date: Tue, 24 Feb 2015 20:14:18 +1300 Subject: [PATCH 0619/3725] Fix: no longer loose changes when run install wizard or iniimport. --- apps/launcher/settingspage.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/launcher/settingspage.cpp b/apps/launcher/settingspage.cpp index c228aba50..34b4b41a9 100644 --- a/apps/launcher/settingspage.cpp +++ b/apps/launcher/settingspage.cpp @@ -95,7 +95,7 @@ Launcher::SettingsPage::~SettingsPage() void Launcher::SettingsPage::on_wizardButton_clicked() { - saveSettings(); + mMain->writeSettings(); if (!mWizardInvoker->startProcess(QLatin1String("openmw-wizard"), false)) return; @@ -103,7 +103,7 @@ void Launcher::SettingsPage::on_wizardButton_clicked() void Launcher::SettingsPage::on_importerButton_clicked() { - saveSettings(); + mMain->writeSettings(); // Create the file if it doesn't already exist, else the importer will fail QString path(QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str())); From e1032620959de5c4d04c87d92cd420000774d084 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 24 Feb 2015 18:15:41 +0100 Subject: [PATCH 0620/3725] updated credits file --- AUTHORS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AUTHORS.md b/AUTHORS.md index 540c0ede5..90c543ada 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -39,6 +39,7 @@ Programmers Eli2 Emanuel Guével (potatoesmaster) eroen + Evgeniy Mineev (sandstranger) Fil Krynicki (filkry) Gašper Sedej gugus/gus @@ -91,7 +92,6 @@ Programmers Rohit Nirmal Roman Melnik (Kromgart) Roman Proskuryakov (humbug) - sandstranger Sandy Carter (bwrsandman) Scott Howard Sebastian Wick (swick) From 24de6ba27e06a381a56abdc7913586b75634569e Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 24 Feb 2015 17:09:49 +0100 Subject: [PATCH 0621/3725] Fix crash for LAND records without data --- apps/openmw/mwworld/scene.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 72d475f16..f03f65b36 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -230,7 +230,7 @@ namespace MWWorld cell->getCell()->getGridX(), cell->getCell()->getGridY() ); - if (land) { + if (land && land->mDataTypes&ESM::Land::DATA_VHGT) { // Actually only VHGT is needed here, but we'll need the rest for rendering anyway. // Load everything now to reduce IO overhead. const int flags = ESM::Land::DATA_VCLR|ESM::Land::DATA_VHGT|ESM::Land::DATA_VNML|ESM::Land::DATA_VTEX; From 5672c86924fe8aa9c104e9d0d23714ac1230640a Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Tue, 24 Feb 2015 23:37:53 +0100 Subject: [PATCH 0622/3725] Rename window title for OpenMW-CS --- apps/opencs/view/doc/startup.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/view/doc/startup.cpp b/apps/opencs/view/doc/startup.cpp index 799a07e14..58a46c603 100644 --- a/apps/opencs/view/doc/startup.cpp +++ b/apps/opencs/view/doc/startup.cpp @@ -96,7 +96,7 @@ QWidget *CSVDoc::StartupDialogue::createTools() CSVDoc::StartupDialogue::StartupDialogue() : mWidth (0), mColumn (2) { - setWindowTitle ("Open CS"); + setWindowTitle ("OpenMW-CS"); QVBoxLayout *layout = new QVBoxLayout (this); From 691ebd237215e502f8e096a8f5f5b8253fb9275c Mon Sep 17 00:00:00 2001 From: Jordan Ayers Date: Tue, 24 Feb 2015 20:51:57 -0600 Subject: [PATCH 0623/3725] Correction to teleportation changes. OMW Bug #2400 Related to OMW Bug #1533 Don't crash when finding the closest marker to an exterior position. --- apps/openmw/mwworld/worldimp.cpp | 47 +++++++++++++++++++------------- apps/openmw/mwworld/worldimp.hpp | 1 + 2 files changed, 29 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 6462629f4..4cafab41d 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2832,6 +2832,10 @@ namespace MWWorld MWWorld::Ptr World::getClosestMarker( const MWWorld::Ptr &ptr, const std::string &id ) { + if ( ptr.getCell()->isExterior() ) { + return getClosestMarkerFromExteriorPosition(mPlayer->getLastKnownExteriorPosition(), id); + } + // Search for a 'nearest' marker, counting each cell between the starting // cell and the exterior as a distance of 1. If an exterior is found, jump // to the nearest exterior marker, without further interior searching. @@ -2868,25 +2872,7 @@ namespace MWWorld if (ref.mRef.getDestCell().empty()) { Ogre::Vector3 worldPos = Ogre::Vector3(ref.mRef.getDoorDest().pos); - float closestDistance = FLT_MAX; - - MWWorld::Ptr closestMarker; - std::vector markers; - mCells.getExteriorPtrs(id, markers); - for (std::vector::iterator it2 = markers.begin(); it2 != markers.end(); ++it2) - { - ESM::Position pos = it2->getRefData().getPosition(); - Ogre::Vector3 markerPos = Ogre::Vector3(pos.pos); - float distance = worldPos.squaredDistance(markerPos); - if (distance < closestDistance) - { - closestDistance = distance; - closestMarker = *it2; - } - - } - - return closestMarker; + return getClosestMarkerFromExteriorPosition(worldPos, id); } else { @@ -2901,6 +2887,29 @@ namespace MWWorld return MWWorld::Ptr(); } + MWWorld::Ptr World::getClosestMarkerFromExteriorPosition( const Ogre::Vector3 worldPos, const std::string &id ) { + MWWorld::Ptr closestMarker; + float closestDistance = FLT_MAX; + + std::vector markers; + mCells.getExteriorPtrs(id, markers); + for (std::vector::iterator it2 = markers.begin(); it2 != markers.end(); ++it2) + { + ESM::Position pos = it2->getRefData().getPosition(); + Ogre::Vector3 markerPos = Ogre::Vector3(pos.pos); + float distance = worldPos.squaredDistance(markerPos); + if (distance < closestDistance) + { + closestDistance = distance; + closestMarker = *it2; + } + + } + + return closestMarker; + } + + void World::teleportToClosestMarker (const MWWorld::Ptr& ptr, const std::string& id) { diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 22509f801..1db86f738 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -151,6 +151,7 @@ namespace MWWorld float feetToGameUnits(float feet); MWWorld::Ptr getClosestMarker( const MWWorld::Ptr &ptr, const std::string &id ); + MWWorld::Ptr getClosestMarkerFromExteriorPosition( const Ogre::Vector3 worldPos, const std::string &id ); public: From 659a8ba279e1affc6ef954c4cbae9ba76eea92cb Mon Sep 17 00:00:00 2001 From: Jordan Ayers Date: Tue, 24 Feb 2015 21:10:01 -0600 Subject: [PATCH 0624/3725] Correction to teleportation changes. OMW Bug #2400 Related to OMW Bug #1533 Don't crash on confiscating items if a prison marker cannot be found. --- apps/openmw/mwworld/worldimp.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 4cafab41d..fe56fc3bb 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -3075,6 +3075,11 @@ namespace MWWorld void World::confiscateStolenItems(const Ptr &ptr) { MWWorld::Ptr prisonMarker = getClosestMarker( ptr, "prisonmarker" ); + if ( prisonMarker.isEmpty() ) + { + std::cerr << "Failed to confiscate items: no closest prison marker found." << std::endl; + return; + } std::string prisonName = prisonMarker.mRef->mRef.getDestCell(); if ( prisonName.empty() ) { From 9d61457956e35b56dfbf24e9cab8a532cad61591 Mon Sep 17 00:00:00 2001 From: dteviot Date: Wed, 25 Feb 2015 20:54:52 +1300 Subject: [PATCH 0625/3725] AddOn files can be checked if game file is checked, but dependencies do not exist. --- .../contentselector/model/contentmodel.cpp | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/components/contentselector/model/contentmodel.cpp b/components/contentselector/model/contentmodel.cpp index 485510df4..cd0c67ee7 100644 --- a/components/contentselector/model/contentmodel.cpp +++ b/components/contentselector/model/contentmodel.cpp @@ -110,15 +110,14 @@ Qt::ItemFlags ContentSelectorModel::ContentModel::flags(const QModelIndex &index if (!file) return Qt::NoItemFlags; - //game files can always be checked + //game files are not shown if (file->isGameFile()) - return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable; + return Qt::NoItemFlags; Qt::ItemFlags returnFlags; - bool allDependenciesFound = true; bool gamefileChecked = false; - //addon can be checked if its gamefile is and all other dependencies exist + // addon can be checked if its gamefile is foreach (const QString &fileName, file->gameFiles()) { bool depFound = false; @@ -144,16 +143,11 @@ Qt::ItemFlags ContentSelectorModel::ContentModel::flags(const QModelIndex &index if (gamefileChecked || !(dependency->isGameFile())) break; } - - allDependenciesFound = allDependenciesFound && depFound; } if (gamefileChecked) { - if (allDependenciesFound) - returnFlags = returnFlags | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsDragEnabled; - else - returnFlags = Qt::ItemIsSelectable; + returnFlags = Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsDragEnabled; } return returnFlags; @@ -468,7 +462,7 @@ void ContentSelectorModel::ContentModel::addFiles(const QString &path) file->setDescription(QString::fromUtf8(fileReader.getDesc().c_str())); // HACK - // Bloodmoon.esm requires Tribunal.esm, but this requirement is missing + // Load order constraint of Bloodmoon.esm needing Tribunal.esm is missing // from the file supplied by Bethesda, so we have to add it ourselves if (file->fileName().compare("Bloodmoon.esm", Qt::CaseInsensitive) == 0) { From 931c95d0b130e07a4f9e8fb2f41c99235607cc41 Mon Sep 17 00:00:00 2001 From: dteviot Date: Thu, 26 Feb 2015 06:17:29 +1300 Subject: [PATCH 0626/3725] workaround for not building on Linux version of Travis. --- apps/mwiniimporter/importer.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/apps/mwiniimporter/importer.cpp b/apps/mwiniimporter/importer.cpp index b71ebd2b8..00774d798 100644 --- a/apps/mwiniimporter/importer.cpp +++ b/apps/mwiniimporter/importer.cpp @@ -883,16 +883,23 @@ void MwIniImporter::setInputEncoding(const ToUTF8::FromType &encoding) std::time_t MwIniImporter::lastWriteTime(const boost::filesystem::path& filename, std::time_t defaultTime) { std::time_t writeTime(defaultTime); - boost::filesystem::path resolved = boost::filesystem::canonical(filename); - if (boost::filesystem::exists(resolved)) + if (boost::filesystem::exists(filename)) { + // FixMe: remove #if when Boost on Travis Linux updated + // Travis seems to be using older version of boost for Linux + // This should allow things to build until fixed +#if BOOST_FILESYSTEM_VERSION == 3 + boost::filesystem::path resolved = boost::filesystem::canonical(filename); +#else + boost::filesystem::path resolved = filename; +#endif writeTime = boost::filesystem::last_write_time(resolved); std::cout << "content file: " << resolved << " timestamp = (" << writeTime << ") " << asctime(localtime(&writeTime)) << std::endl; } else { - std::cout << "content file: " << resolved << " not found" << std::endl; + std::cout << "content file: " << filename << " not found" << std::endl; } return writeTime; } \ No newline at end of file From 3158d34abb3da8f6a22a4ea7bbf962eb0ccb51f3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 25 Feb 2015 20:25:41 +0100 Subject: [PATCH 0627/3725] Fix for incorrect OpenCS verifier warning: pcvampire and pcwerewolf are not required, pcyear does not exist at all. --- apps/opencs/model/tools/tools.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index 0c20bd17b..e78758bb6 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -58,9 +58,6 @@ CSMDoc::Operation *CSMTools::Tools::getVerifier() mandatoryIds.push_back ("GameHour"); mandatoryIds.push_back ("Month"); mandatoryIds.push_back ("PCRace"); - mandatoryIds.push_back ("PCVampire"); - mandatoryIds.push_back ("PCWerewolf"); - mandatoryIds.push_back ("PCYear"); mVerifier->appendStage (new MandatoryIdStage (mData.getGlobals(), CSMWorld::UniversalId (CSMWorld::UniversalId::Type_Globals), mandatoryIds)); From e7989a197d8e3b2d81d7aea63012f575a373ee4c Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 25 Feb 2015 20:32:11 +0100 Subject: [PATCH 0628/3725] Add defaults for some required globals (Fixes #2397) --- apps/openmw/mwworld/worldimp.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 6462629f4..f78323be6 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -423,6 +423,19 @@ namespace MWWorld globals["werewolfclawmult"] = ESM::Variant(25.f); globals["pcknownwerewolf"] = ESM::Variant(0); + // following should exist in all versions of MW, but not necessarily in TCs + globals["gamehour"] = ESM::Variant(0.f); + globals["timescale"] = ESM::Variant(30.f); + globals["day"] = ESM::Variant(1); + globals["month"] = ESM::Variant(1); + globals["year"] = ESM::Variant(1); + globals["pcrace"] = ESM::Variant(0); + globals["pchascrimegold"] = ESM::Variant(0); + globals["pchasgolddiscount"] = ESM::Variant(0); + globals["crimegolddiscount"] = ESM::Variant(0); + globals["crimegoldturnin"] = ESM::Variant(0); + globals["pchasturnin"] = ESM::Variant(0); + for (std::map::iterator it = gmst.begin(); it != gmst.end(); ++it) { if (!mStore.get().search(it->first)) From 72e94380be20aab94e23d6503a2983f76d74e174 Mon Sep 17 00:00:00 2001 From: dteviot Date: Thu, 26 Feb 2015 20:07:23 +1300 Subject: [PATCH 0629/3725] fix: boost::filesystem::canonical() available from version 1.48. --- apps/mwiniimporter/importer.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/apps/mwiniimporter/importer.cpp b/apps/mwiniimporter/importer.cpp index 00774d798..efebe5a4d 100644 --- a/apps/mwiniimporter/importer.cpp +++ b/apps/mwiniimporter/importer.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -885,10 +886,10 @@ std::time_t MwIniImporter::lastWriteTime(const boost::filesystem::path& filename std::time_t writeTime(defaultTime); if (boost::filesystem::exists(filename)) { - // FixMe: remove #if when Boost on Travis Linux updated - // Travis seems to be using older version of boost for Linux - // This should allow things to build until fixed -#if BOOST_FILESYSTEM_VERSION == 3 + // FixMe: remove #if when Boost dependency for Linux builds updated + // This allows Linux to build until then +#if (BOOST_VERSION >= 104800) + // need to resolve any symlinks so that we get time of file, not symlink boost::filesystem::path resolved = boost::filesystem::canonical(filename); #else boost::filesystem::path resolved = filename; From 1bb29f610fe25dff6ae26fba0310dfab407c2da7 Mon Sep 17 00:00:00 2001 From: sylar Date: Thu, 26 Feb 2015 18:29:38 +0400 Subject: [PATCH 0630/3725] enable mipmapping for Android again --- apps/openmw/mwrender/renderingmanager.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index b83a078ba..05b43d54f 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -120,14 +120,12 @@ RenderingManager::RenderingManager(OEngine::Render::OgreRenderer& _rend, const b // Set default texture filtering options TextureFilterOptions tfo; std::string filter = Settings::Manager::getString("texture filtering", "General"); -#ifndef ANDROID + if (filter == "anisotropic") tfo = TFO_ANISOTROPIC; else if (filter == "trilinear") tfo = TFO_TRILINEAR; else if (filter == "bilinear") tfo = TFO_BILINEAR; else /*if (filter == "none")*/ tfo = TFO_NONE; -#else - tfo = TFO_NONE; -#endif + MaterialManager::getSingleton().setDefaultTextureFiltering(tfo); MaterialManager::getSingleton().setDefaultAnisotropy( (filter == "anisotropic") ? Settings::Manager::getInt("anisotropy", "General") : 1 ); From 70398e2f9f2a9a0701c0c401e0d3c43f187f9267 Mon Sep 17 00:00:00 2001 From: sylar Date: Thu, 26 Feb 2015 18:30:14 +0400 Subject: [PATCH 0631/3725] change Jni name method --- components/files/androidpath.cpp | 2 +- components/files/androidpath.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/components/files/androidpath.cpp b/components/files/androidpath.cpp index 117626095..009bd98a2 100644 --- a/components/files/androidpath.cpp +++ b/components/files/androidpath.cpp @@ -27,7 +27,7 @@ char const * Buffer::getData() } -JNIEXPORT void JNICALL Java_org_libsdl_app_SDLActivity_getPathToJni(JNIEnv *env, jobject obj, jstring prompt) +JNIEXPORT void JNICALL Java_ui_activity_GameActivity_getPathToJni(JNIEnv *env, jobject obj, jstring prompt) { jboolean iscopy; Buffer::setData((env)->GetStringUTFChars(prompt, &iscopy)); diff --git a/components/files/androidpath.h b/components/files/androidpath.h index 3157c067f..a93a160e0 100644 --- a/components/files/androidpath.h +++ b/components/files/androidpath.h @@ -1,8 +1,8 @@ /* DO NOT EDIT THIS FILE - it is machine generated */ #include -#ifndef _Included_org_libsdl_app_SDLActivity_getPathToJni -#define _Included_org_libsdl_app_SDLActivity_getPathToJni +#ifndef _Included_ui_activity_GameActivity_getPathToJni +#define _Included_ui_activity_GameActivity_getPathToJni #ifdef __cplusplus extern "C" { #endif @@ -11,7 +11,7 @@ extern "C" { * Method: getPathToJni * Signature: (I)I */ -JNIEXPORT void JNICALL Java_org_libsdl_app_SDLActivity_getPathToJni(JNIEnv *env, jobject obj, jstring prompt); +JNIEXPORT void JNICALL Java_ui_activity_GameActivity_getPathToJni(JNIEnv *env, jobject obj, jstring prompt); #ifdef __cplusplus } From cda3782cf2d8185896c8139df015d1c76ddb0efb Mon Sep 17 00:00:00 2001 From: sylar Date: Thu, 26 Feb 2015 18:30:38 +0400 Subject: [PATCH 0632/3725] fix crash game on Android after start loading --- apps/openmw/mwworld/refdata.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/refdata.hpp b/apps/openmw/mwworld/refdata.hpp index da7986ba0..e90b44f9c 100644 --- a/apps/openmw/mwworld/refdata.hpp +++ b/apps/openmw/mwworld/refdata.hpp @@ -33,11 +33,11 @@ namespace MWWorld MWScript::Locals mLocals; // if we find the overhead of heaving a locals // object in the refdata of refs without a script, // we can make this a pointer later. + bool mDeleted; // separate delete flag used for deletion by a content file bool mHasLocals; bool mEnabled; int mCount; // 0: deleted - bool mDeleted; // separate delete flag used for deletion by a content file ESM::Position mPosition; From 7e684853fcaff8f3b7de39e941eaf26c00dae652 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 26 Feb 2015 21:20:07 +0100 Subject: [PATCH 0633/3725] Add StatsHandler for profiling (S key) --- apps/nifosgtest/test.cpp | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/apps/nifosgtest/test.cpp b/apps/nifosgtest/test.cpp index fc82059fc..668bda373 100644 --- a/apps/nifosgtest/test.cpp +++ b/apps/nifosgtest/test.cpp @@ -1,4 +1,5 @@ #include +#include #include #include @@ -13,10 +14,10 @@ #include // EventHandler to toggle wireframe when 'w' key is pressed -class EventHandler : public osgGA::GUIEventHandler +class WireframeKeyHandler : public osgGA::GUIEventHandler { public: - EventHandler(osg::Node* node) + WireframeKeyHandler(osg::Node* node) : mWireframe(false) , mNode(node) { @@ -70,12 +71,17 @@ int main(int argc, char** argv) // To prevent lighting issues with scaled meshes root->getOrCreateStateSet()->setMode(GL_NORMALIZE, osg::StateAttribute::ON); + + //osgDB::writeNodeFile(*newNode, "out.osg"); + + std::vector controllers; osg::Group* newNode = new osg::Group; NifOsg::Loader loader; loader.resourceManager = &bsa; loader.loadAsSkeleton(nif, newNode); - //osgDB::writeNodeFile(*newNode, "out.osg"); + for (unsigned int i=0; i Date: Fri, 27 Feb 2015 08:56:20 +0400 Subject: [PATCH 0634/3725] fix transpose error fo gles2 --- files/materials/objects.shader | 17 ++++++++++++++--- files/materials/terrain.shader | 15 +++++++++++++-- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/files/materials/objects.shader b/files/materials/objects.shader index 2368d9961..ab693eb39 100644 --- a/files/materials/objects.shader +++ b/files/materials/objects.shader @@ -243,7 +243,9 @@ } #else - +#if NORMAL_MAP && SH_GLSLES + mat3 transpose( mat3 m); +#endif // ----------------------------------- FRAGMENT ------------------------------------------ #if UNDERWATER @@ -376,13 +378,13 @@ float3 binormal = cross(tangentPassthrough.xyz, normal.xyz); float3x3 tbn = float3x3(tangentPassthrough.xyz, binormal, normal.xyz); - #if SH_GLSL + #if SH_GLSL || SH_GLSLES tbn = transpose(tbn); #endif float4 normalTex = shSample(normalMap, UV.xy); - normal = normalize (shMatrixMult( transpose(tbn), normalTex.xyz * 2 - 1 )); + normal = normalize (shMatrixMult( transpose(tbn), normalTex.xyz * 2.0 - float (1.0,1.0,1.0) )); #endif #if ENV_MAP || SPECULAR || PARALLAX @@ -576,5 +578,14 @@ // prevent negative colour output (for example with negative lights) shOutputColour(0).xyz = max(shOutputColour(0).xyz, float3(0.0,0.0,0.0)); } +#if NORMAL_MAP && SH_GLSLES + mat3 transpose(mat3 m){ + return mat3( + m[0][0],m[1][0],m[2][0], + m[0][1],m[1][1],m[2][1], + m[0][2],m[1][2],m[2][2] + ); + } +#endif #endif diff --git a/files/materials/terrain.shader b/files/materials/terrain.shader index a4ca10fcc..9bb5d247d 100644 --- a/files/materials/terrain.shader +++ b/files/materials/terrain.shader @@ -221,6 +221,9 @@ #if UNDERWATER #include "underwater.h" #endif +#if NORMAL_MAP && SH_GLSLES + mat3 transpose(mat3 m); +#endif SH_BEGIN_PROGRAM @@ -319,7 +322,7 @@ shUniform(float4, cameraPos) @shAutoConstant(cameraPos, camera_position) // derive final matrix float3x3 tbn = float3x3(tangent, binormal, normal); - #if SH_GLSL + #if SH_GLSL || SH_GLSLES tbn = transpose(tbn); #endif #endif @@ -492,5 +495,13 @@ albedo = shLerp(albedo, diffuseTex, blendValues@shPropertyString(blendmap_compon shOutputColour(0).a = 1.0-previousAlpha; #endif } - +#if NORMAL_MAP && SH_GLSLES + mat3 transpose(mat3 m){ + return mat3( + m[0][0],m[1][0],m[2][0], + m[0][1],m[1][1],m[2][1], + m[0][2],m[1][2],m[2][2] + ); + } +#endif #endif From edd3f9f95c8256710f8063afcb10eb7f1f610043 Mon Sep 17 00:00:00 2001 From: sylar Date: Fri, 27 Feb 2015 08:58:00 +0400 Subject: [PATCH 0635/3725] small fix for float --- files/materials/objects.shader | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/materials/objects.shader b/files/materials/objects.shader index ab693eb39..828674cc7 100644 --- a/files/materials/objects.shader +++ b/files/materials/objects.shader @@ -384,7 +384,7 @@ float4 normalTex = shSample(normalMap, UV.xy); - normal = normalize (shMatrixMult( transpose(tbn), normalTex.xyz * 2.0 - float (1.0,1.0,1.0) )); + normal = normalize (shMatrixMult( transpose(tbn), normalTex.xyz * 2.0 - float3 (1.0,1.0,1.0) )); #endif #if ENV_MAP || SPECULAR || PARALLAX From f91696723f14536c38c66e0508f86a722dd05773 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 27 Feb 2015 19:58:43 +0100 Subject: [PATCH 0636/3725] Fix compile error --- components/files/constrainedfilestream.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/components/files/constrainedfilestream.cpp b/components/files/constrainedfilestream.cpp index 23eab2088..3e5d0c245 100644 --- a/components/files/constrainedfilestream.cpp +++ b/components/files/constrainedfilestream.cpp @@ -5,13 +5,16 @@ #include "lowlevelfile.hpp" -namespace Files +namespace { +// somewhat arbitrary though 64KB buffers didn't seem to improve performance any +const size_t sBufferSize = 4096; +} +namespace Files +{ class ConstrainedFileStreamBuf : public std::streambuf { - // somewhat arbitrary though 64KB buffers didn't seem to improve performance any - static const size_t sBufferSize = 4096; size_t mOrigin; size_t mSize; From 2eedb3acece4db39da6d56dd905d2c4353e3ae0c Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 27 Feb 2015 20:22:43 +0100 Subject: [PATCH 0637/3725] Include fix --- apps/openmw/mwgui/review.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwgui/review.cpp b/apps/openmw/mwgui/review.cpp index 1bcd2d31a..023f23815 100644 --- a/apps/openmw/mwgui/review.cpp +++ b/apps/openmw/mwgui/review.cpp @@ -1,5 +1,7 @@ #include "review.hpp" +#include + #include #include #include From 1e4a845b6f7bded5f8ff6ab7465f3cef0847df42 Mon Sep 17 00:00:00 2001 From: Digmaster Date: Sat, 20 Dec 2014 14:46:11 -0600 Subject: [PATCH 0638/3725] Minor code cleanup --- CMakeLists.txt | 3 ++ apps/openmw/mwbase/inputmanager.hpp | 6 +++- apps/openmw/mwinput/inputmanagerimp.cpp | 40 +++++++++++++++++++-- apps/openmw/mwinput/inputmanagerimp.hpp | 15 +++++--- apps/openmw/mwscript/interpretercontext.cpp | 12 +++++-- extern/oics/ICSInputControlSystem.cpp | 36 +------------------ extern/oics/ICSInputControlSystem.h | 3 +- files/CMakeLists.txt | 6 ---- 8 files changed, 68 insertions(+), 53 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5a923c631..d8872e162 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -379,6 +379,9 @@ configure_file(${OpenMW_SOURCE_DIR}/files/opencs.ini configure_file(${OpenMW_SOURCE_DIR}/files/opencs/defaultfilters "${OpenMW_BINARY_DIR}/resources/defaultfilters" COPYONLY) +configure_file(${OpenMW_SOURCE_DIR}/files/gamecontrollerdb.txt + "${OpenMW_BINARY_DIR}/gamecontrollerdb.txt") + if (NOT WIN32 AND NOT APPLE) configure_file(${OpenMW_SOURCE_DIR}/files/openmw.desktop "${OpenMW_BINARY_DIR}/openmw.desktop") diff --git a/apps/openmw/mwbase/inputmanager.hpp b/apps/openmw/mwbase/inputmanager.hpp index 3ffa7148a..59b4e3b77 100644 --- a/apps/openmw/mwbase/inputmanager.hpp +++ b/apps/openmw/mwbase/inputmanager.hpp @@ -46,10 +46,14 @@ namespace MWBase ///Actions available for binding to controller buttons virtual std::vector getActionControllerSorting() = 0; virtual int getNumActions() = 0; - ///If keyboard is true, only pay attention to keyboard events. If false, only pay attention to cntroller events (excluding esc) + ///If keyboard is true, only pay attention to keyboard events. If false, only pay attention to controller events (excluding esc) virtual void enableDetectingBindingMode (int action, bool keyboard) = 0; virtual void resetToDefaultKeyBindings() = 0; virtual void resetToDefaultControllerBindings() = 0; + + /// Returns if the last used input device was a joystick or a keyboard + /// @return true if joystick, false otherwise + virtual bool joystickLastUsed() = 0; }; } diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 3d1239f54..180d371cf 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -124,6 +124,7 @@ namespace MWInput , mAttemptJump(false) , mControlsDisabled(false) , mJoystickLastUsed(false) + , mDetectingKeyboard(false) { Ogre::RenderWindow* window = ogre.getWindow (); @@ -135,8 +136,7 @@ namespace MWInput mInputManager->setControllerEventCallback(this); std::string file = userFileExists ? userFile : ""; - std::string controllerdb = Settings::Manager::getString("gamecontrollerdb file", "Input"); - mInputBinder = new ICS::InputControlSystem(file, true, this, NULL, controllerdb, A_Last); + mInputBinder = new ICS::InputControlSystem(file, true, this, NULL, A_Last); adjustMouseRegion (window->getWidth(), window->getHeight()); loadKeyDefaults(); @@ -154,6 +154,42 @@ namespace MWInput mControlSwitch["playermagic"] = true; mControlSwitch["playerviewswitch"] = true; mControlSwitch["vanitymode"] = true; + + /* Joystick Init */ + + //Load controller mappings +#if SDL_VERSION_ATLEAST(2,0,2) + Files::ConfigurationManager cfgMgr; + std::string db = cfgMgr.getLocalPath().string() + "/gamecontrollerdb.txt"; + if(boost::filesystem::exists(db)) + { + int res = SDL_GameControllerAddMappingsFromFile(db.c_str()); + if(res == -1) + { + //ICS_LOG(std::string("Error loading controller bindings: ")+SDL_GetError()); + } + else + { + //ICS_LOG(std::string("Loaded ")+boost::lexical_cast(res)+" Game controller bindings"); + } + } +#endif + + //Open all presently connected sticks + int numSticks = SDL_NumJoysticks(); + for(int i = 0; i < numSticks; i++) + { + if(SDL_IsGameController(i)) + { + SDL_ControllerDeviceEvent evt; + evt.which = i; + controllerAdded(evt); + } + else + { + //ICS_LOG(std::string("Unusable controller plugged in: ")+SDL_JoystickNameForIndex(i)); + } + } } void InputManager::clear() diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 61dbf18f8..df490ea00 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -4,6 +4,7 @@ #include "../mwgui/mode.hpp" #include +#include #include "../mwbase/inputmanager.hpp" #include @@ -41,6 +42,11 @@ namespace MyGUI class MouseButton; } +namespace Files +{ + struct ConfigurationManager; +} + #include #include @@ -85,8 +91,6 @@ namespace MWInput virtual std::string getActionDescription (int action); virtual std::string getActionKeyBindingName (int action); virtual std::string getActionControllerBindingName (int action); - virtual std::string sdlControllerAxisToString(int axis); - virtual std::string sdlControllerButtonToString(int button); virtual int getNumActions() { return A_Last; } virtual std::vector getActionKeySorting(); virtual std::vector getActionControllerSorting(); @@ -94,6 +98,8 @@ namespace MWInput virtual void resetToDefaultKeyBindings(); virtual void resetToDefaultControllerBindings(); + virtual bool joystickLastUsed() {return mJoystickLastUsed;} + public: virtual void keyPressed(const SDL_KeyboardEvent &arg ); virtual void keyReleased( const SDL_KeyboardEvent &arg ); @@ -181,6 +187,9 @@ namespace MWInput void adjustMouseRegion(int width, int height); MyGUI::MouseButton sdlButtonToMyGUI(Uint8 button); + virtual std::string sdlControllerAxisToString(int axis); + virtual std::string sdlControllerButtonToString(int button); + void resetIdleTime(); void updateIdleTime(float dt); @@ -201,8 +210,6 @@ namespace MWInput void quickLoad(); void quickSave(); - bool isAReverse(int action); - void quickKey (int index); void showQuickKeysMenu(); diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index b71e92555..f4e637a59 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -268,15 +268,21 @@ namespace MWScript std::string InterpreterContext::getActionBinding(const std::string& action) const { - std::vector actions = MWBase::Environment::get().getInputManager()->getActionKeySorting (); + MWBase::InputManager* input = MWBase::Environment::get().getInputManager(); + std::vector actions = input->getActionKeySorting (); for (std::vector::const_iterator it = actions.begin(); it != actions.end(); ++it) { - std::string desc = MWBase::Environment::get().getInputManager()->getActionDescription (*it); + std::string desc = input->getActionDescription (*it); if(desc == "") continue; if(desc == action) - return MWBase::Environment::get().getInputManager()->getActionKeyBindingName (*it); + { + if(input->joystickLastUsed()) + return input->getActionControllerBindingName(*it); + else + return input->getActionKeyBindingName (*it); + } } return "None"; diff --git a/extern/oics/ICSInputControlSystem.cpp b/extern/oics/ICSInputControlSystem.cpp index a8efd54bc..a38b46e98 100644 --- a/extern/oics/ICSInputControlSystem.cpp +++ b/extern/oics/ICSInputControlSystem.cpp @@ -30,7 +30,7 @@ namespace ICS { InputControlSystem::InputControlSystem(std::string file, bool active , DetectingBindingListener* detectingBindingListener - , InputControlSystemLog* log, std::string controllerdb, size_t channelCount) + , InputControlSystemLog* log, size_t channelCount) : mFileName(file) , mDetectingBindingListener(detectingBindingListener) , mDetectingBindingControl(NULL) @@ -273,40 +273,6 @@ namespace ICS } delete xmlDoc; - } - - /* Joystick Init */ - - //Load controller mappings -#if SDL_VERSION_ATLEAST(2,0,2) - if(!controllerdb.empty()) - { - int res = SDL_GameControllerAddMappingsFromFile(controllerdb.c_str()); - if(res == -1) - { - ICS_LOG(std::string("Error loading controller bindings: ")+SDL_GetError()); - } - else - { - ICS_LOG(std::string("Loaded ")+boost::lexical_cast(res)+" Game controller bindings"); - } - } -#endif - - //Open all presently connected sticks - int numSticks = SDL_NumJoysticks(); - for(int i = 0; i < numSticks; i++) - { - if(SDL_IsGameController(i)) - { - SDL_ControllerDeviceEvent evt; - evt.which = i; - controllerAdded(evt); - } - else - { - ICS_LOG(std::string("Unusable controller plugged in: ")+SDL_JoystickNameForIndex(i)); - } } ICS_LOG(" - InputControlSystem Created - "); diff --git a/extern/oics/ICSInputControlSystem.h b/extern/oics/ICSInputControlSystem.h index f58d242fc..0bdd67b34 100644 --- a/extern/oics/ICSInputControlSystem.h +++ b/extern/oics/ICSInputControlSystem.h @@ -74,8 +74,7 @@ namespace ICS InputControlSystem(std::string file = "", bool active = true , DetectingBindingListener* detectingBindingListener = NULL - , InputControlSystemLog* log = NULL, std::string controllerdb = "" - , size_t channelCount = 16); + , InputControlSystemLog* log = NULL, size_t channelCount = 16); ~InputControlSystem(); std::string getFileName(){ return mFileName; }; diff --git a/files/CMakeLists.txt b/files/CMakeLists.txt index 4635cbfa4..9b2325744 100644 --- a/files/CMakeLists.txt +++ b/files/CMakeLists.txt @@ -49,12 +49,6 @@ set(MATERIAL_FILES mygui.shaderset ) -set(ETC_FILES - gamecontrollerdb.txt -) - copy_all_files(${CMAKE_CURRENT_SOURCE_DIR}/water "${OpenMW_BINARY_DIR}/resources/water/" "${WATER_FILES}") copy_all_files(${CMAKE_CURRENT_SOURCE_DIR}/materials "${OpenMW_BINARY_DIR}/resources/materials/" "${MATERIAL_FILES}") - -copy_all_files(${CMAKE_CURRENT_SOURCE_DIR} "${OpenMW_BINARY_DIR}/resources/" "${ETC_FILES}") From e3e6190b85c5ce274c7f2b2ca90d53ee56d8b50c Mon Sep 17 00:00:00 2001 From: Digmaster Date: Mon, 19 Jan 2015 15:36:15 -0600 Subject: [PATCH 0639/3725] Added multiple joystick support in ICS. Will fix other issues shortly --- apps/openmw/mwinput/inputmanagerimp.cpp | 53 ++-- apps/openmw/mwinput/inputmanagerimp.hpp | 16 +- extern/oics/ICSInputControlSystem.cpp | 90 +++---- extern/oics/ICSInputControlSystem.h | 44 ++-- .../oics/ICSInputControlSystem_joystick.cpp | 232 ++++++++++-------- extern/sdl4ogre/events.h | 10 +- extern/sdl4ogre/sdlinputwrapper.cpp | 8 +- 7 files changed, 245 insertions(+), 208 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 180d371cf..7b8580080 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -125,6 +125,7 @@ namespace MWInput , mControlsDisabled(false) , mJoystickLastUsed(false) , mDetectingKeyboard(false) + , mFakeDeviceID(1) { Ogre::RenderWindow* window = ogre.getWindow (); @@ -183,7 +184,7 @@ namespace MWInput { SDL_ControllerDeviceEvent evt; evt.which = i; - controllerAdded(evt); + controllerAdded(mFakeDeviceID, evt); } else { @@ -768,7 +769,7 @@ namespace MWInput } } - void InputManager::buttonPressed( const SDL_ControllerButtonEvent &arg ) + void InputManager::buttonPressed(int deviceID, const SDL_ControllerButtonEvent &arg ) { mJoystickLastUsed = true; bool guiMode = false; @@ -798,14 +799,14 @@ namespace MWInput setPlayerControlsEnabled(!guiFocus); if (!mControlsDisabled) - mInputBinder->buttonPressed(arg); + mInputBinder->buttonPressed(deviceID, arg); } - void InputManager::buttonReleased( const SDL_ControllerButtonEvent &arg ) + void InputManager::buttonReleased(int deviceID, const SDL_ControllerButtonEvent &arg ) { mJoystickLastUsed = true; if(mInputBinder->detectingBindingState()) - mInputBinder->buttonReleased(arg); + mInputBinder->buttonReleased(deviceID, arg); else if(arg.button == SDL_CONTROLLER_BUTTON_A || arg.button == SDL_CONTROLLER_BUTTON_B) { bool guiMode = MWBase::Environment::get().getWindowManager()->isGuiMode(); @@ -814,26 +815,26 @@ namespace MWInput if(mInputBinder->detectingBindingState()) return; // don't allow same mouseup to bind as initiated bind setPlayerControlsEnabled(!guiMode); - mInputBinder->buttonReleased(arg); + mInputBinder->buttonReleased(deviceID, arg); } else - mInputBinder->buttonReleased(arg); + mInputBinder->buttonReleased(deviceID, arg); //to escape inital movie OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(SDLK_ESCAPE); setPlayerControlsEnabled(!MyGUI::InputManager::getInstance().injectKeyRelease(MyGUI::KeyCode::Enum(kc))); } - void InputManager::axisMoved( const SDL_ControllerAxisEvent &arg ) + void InputManager::axisMoved(int deviceID, const SDL_ControllerAxisEvent &arg ) { mJoystickLastUsed = true; if (!mControlsDisabled) - mInputBinder->axisMoved(arg); + mInputBinder->axisMoved(deviceID, arg); } - void InputManager::controllerAdded(const SDL_ControllerDeviceEvent &arg) + void InputManager::controllerAdded(int deviceID, const SDL_ControllerDeviceEvent &arg) { - mInputBinder->controllerAdded(arg); + mInputBinder->controllerAdded(deviceID, arg); } void InputManager::controllerRemoved(const SDL_ControllerDeviceEvent &arg) { @@ -1221,20 +1222,20 @@ namespace MWInput control = mInputBinder->getChannel(i)->getAttachedControls ().front().control; } - if (!controlExists || force || ( mInputBinder->getJoystickAxisBinding (control, ICS::Control::INCREASE) == ICS::InputControlSystem::UNASSIGNED && mInputBinder->getJoystickButtonBinding (control, ICS::Control::INCREASE) == ICS_MAX_DEVICE_BUTTONS )) + if (!controlExists || force || ( mInputBinder->getJoystickAxisBinding (control, mFakeDeviceID, ICS::Control::INCREASE) == ICS::InputControlSystem::UNASSIGNED && mInputBinder->getJoystickButtonBinding (control, mFakeDeviceID, ICS::Control::INCREASE) == ICS_MAX_DEVICE_BUTTONS )) { clearAllControllerBindings(control); if (defaultButtonBindings.find(i) != defaultButtonBindings.end()) { control->setInitialValue(0.0f); - mInputBinder->addJoystickButtonBinding(control, defaultButtonBindings[i], ICS::Control::INCREASE); + mInputBinder->addJoystickButtonBinding(control, mFakeDeviceID, defaultButtonBindings[i], ICS::Control::INCREASE); } else if (defaultAxisBindings.find(i) != defaultAxisBindings.end()) { control->setValue(0.5f); control->setInitialValue(0.5f); - mInputBinder->addJoystickAxisBinding(control, defaultAxisBindings[i], ICS::Control::INCREASE); + mInputBinder->addJoystickAxisBinding(control, mFakeDeviceID, defaultAxisBindings[i], ICS::Control::INCREASE); } } } @@ -1307,10 +1308,10 @@ namespace MWInput ICS::Control* c = mInputBinder->getChannel (action)->getAttachedControls ().front().control; - if (mInputBinder->getJoystickAxisBinding (c, ICS::Control::INCREASE) != ICS::InputControlSystem::UNASSIGNED) - return sdlControllerAxisToString(mInputBinder->getJoystickAxisBinding (c, ICS::Control::INCREASE)); - else if (mInputBinder->getJoystickButtonBinding (c, ICS::Control::INCREASE) != ICS_MAX_DEVICE_BUTTONS ) - return sdlControllerButtonToString(mInputBinder->getJoystickButtonBinding (c, ICS::Control::INCREASE)); + if (mInputBinder->getJoystickAxisBinding (c, mFakeDeviceID, ICS::Control::INCREASE) != ICS::InputControlSystem::UNASSIGNED) + return sdlControllerAxisToString(mInputBinder->getJoystickAxisBinding (c, mFakeDeviceID, ICS::Control::INCREASE)); + else if (mInputBinder->getJoystickButtonBinding (c, mFakeDeviceID, ICS::Control::INCREASE) != ICS_MAX_DEVICE_BUTTONS ) + return sdlControllerButtonToString(mInputBinder->getJoystickButtonBinding (c, mFakeDeviceID, ICS::Control::INCREASE)); else return "#{sNone}"; } @@ -1489,7 +1490,7 @@ namespace MWInput MWBase::Environment::get().getWindowManager ()->notifyInputActionBound (); } - void InputManager::joystickAxisBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control + void InputManager::joystickAxisBindingDetected(ICS::InputControlSystem* ICS, int deviceID, ICS::Control* control , int axis, ICS::Control::ControlChangingDirection direction) { //only allow binding to the trigers @@ -1501,18 +1502,18 @@ namespace MWInput clearAllControllerBindings(control); control->setValue(0.5f); //axis bindings must start at 0.5 control->setInitialValue(0.5f); - ICS::DetectingBindingListener::joystickAxisBindingDetected (ICS, control, axis, direction); + ICS::DetectingBindingListener::joystickAxisBindingDetected (ICS, deviceID, control, axis, direction); MWBase::Environment::get().getWindowManager ()->notifyInputActionBound (); } - void InputManager::joystickButtonBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control + void InputManager::joystickButtonBindingDetected(ICS::InputControlSystem* ICS, int deviceID, ICS::Control* control , unsigned int button, ICS::Control::ControlChangingDirection direction) { if(mDetectingKeyboard) return; clearAllControllerBindings(control); control->setInitialValue(0.0f); - ICS::DetectingBindingListener::joystickButtonBindingDetected (ICS, control, button, direction); + ICS::DetectingBindingListener::joystickButtonBindingDetected (ICS, deviceID, control, button, direction); MWBase::Environment::get().getWindowManager ()->notifyInputActionBound (); } @@ -1528,10 +1529,10 @@ namespace MWInput void InputManager::clearAllControllerBindings (ICS::Control* control) { // right now we don't really need multiple bindings for the same action, so remove all others first - if (mInputBinder->getJoystickAxisBinding (control, ICS::Control::INCREASE) != SDL_SCANCODE_UNKNOWN) - mInputBinder->removeJoystickAxisBinding (mInputBinder->getJoystickAxisBinding (control, ICS::Control::INCREASE)); - if (mInputBinder->getJoystickButtonBinding (control, ICS::Control::INCREASE) != ICS_MAX_DEVICE_BUTTONS) - mInputBinder->removeJoystickButtonBinding (mInputBinder->getJoystickButtonBinding (control, ICS::Control::INCREASE)); + if (mInputBinder->getJoystickAxisBinding (control, mFakeDeviceID, ICS::Control::INCREASE) != SDL_SCANCODE_UNKNOWN) + mInputBinder->removeJoystickAxisBinding (mFakeDeviceID, mInputBinder->getJoystickAxisBinding (control, mFakeDeviceID, ICS::Control::INCREASE)); + if (mInputBinder->getJoystickButtonBinding (control, mFakeDeviceID, ICS::Control::INCREASE) != ICS_MAX_DEVICE_BUTTONS) + mInputBinder->removeJoystickButtonBinding (mFakeDeviceID, mInputBinder->getJoystickButtonBinding (control, mFakeDeviceID, ICS::Control::INCREASE)); } void InputManager::resetToDefaultKeyBindings() diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index df490ea00..e8ee955e2 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -109,11 +109,11 @@ namespace MWInput virtual void mouseReleased( const SDL_MouseButtonEvent &arg, Uint8 id ); virtual void mouseMoved( const SFO::MouseMotionEvent &arg ); - virtual void buttonPressed( const SDL_ControllerButtonEvent &arg); - virtual void buttonReleased( const SDL_ControllerButtonEvent &arg); - virtual void axisMoved( const SDL_ControllerAxisEvent &arg); - virtual void controllerAdded( const SDL_ControllerDeviceEvent &arg); - virtual void controllerRemoved( const SDL_ControllerDeviceEvent &arg); + virtual void buttonPressed(int deviceID, const SDL_ControllerButtonEvent &arg); + virtual void buttonReleased(int deviceID, const SDL_ControllerButtonEvent &arg); + virtual void axisMoved(int deviceID, const SDL_ControllerAxisEvent &arg); + virtual void controllerAdded(int deviceID, const SDL_ControllerDeviceEvent &arg); + virtual void controllerRemoved(const SDL_ControllerDeviceEvent &arg); virtual void windowVisibilityChange( bool visible ); virtual void windowFocusChange( bool have_focus ); @@ -131,10 +131,10 @@ namespace MWInput virtual void mouseButtonBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control , unsigned int button, ICS::Control::ControlChangingDirection direction); - virtual void joystickAxisBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control + virtual void joystickAxisBindingDetected(ICS::InputControlSystem* ICS, int deviceID, ICS::Control* control , int axis, ICS::Control::ControlChangingDirection direction); - virtual void joystickButtonBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control + virtual void joystickButtonBindingDetected(ICS::InputControlSystem* ICS, int deviceID, ICS::Control* control , unsigned int button, ICS::Control::ControlChangingDirection direction); void clearAllKeyBindings (ICS::Control* control); @@ -218,6 +218,8 @@ namespace MWInput void loadKeyDefaults(bool force = false); void loadControllerDefaults(bool force = false); + int mFakeDeviceID; //As we only support one controller at a time, use a fake deviceID so we don't lose bindings when switching controllers + private: enum Actions { diff --git a/extern/oics/ICSInputControlSystem.cpp b/extern/oics/ICSInputControlSystem.cpp index a38b46e98..95adb247e 100644 --- a/extern/oics/ICSInputControlSystem.cpp +++ b/extern/oics/ICSInputControlSystem.cpp @@ -536,65 +536,71 @@ namespace ICS } binder.SetAttribute( "direction", "DECREASE" ); control.InsertEndChild(binder); - } - if(getJoystickAxisBinding(*o, Control/*::ControlChangingDirection*/::INCREASE) - != /*NamedAxis::*/UNASSIGNED) - { - TiXmlElement binder( "JoystickAxisBinder" ); - - binder.SetAttribute( "axis", ToString( - getJoystickAxisBinding(*o, Control/*::ControlChangingDirection*/::INCREASE)).c_str() ); - - binder.SetAttribute( "direction", "INCREASE" ); + } + JoystickIDList::const_iterator it = mJoystickIDList.begin(); + while(it!=mJoystickIDList.end()) + { + int deviceID = *it; + if(getJoystickAxisBinding(*o, deviceID, Control/*::ControlChangingDirection*/::INCREASE) + != /*NamedAxis::*/UNASSIGNED) + { + TiXmlElement binder( "JoystickAxisBinder" ); + + binder.SetAttribute( "axis", ToString( + getJoystickAxisBinding(*o, deviceID, Control/*::ControlChangingDirection*/::INCREASE)).c_str() ); + + binder.SetAttribute( "direction", "INCREASE" ); - binder.SetAttribute( "deviceId", "1" ); //completely useless, but required for backwards compatability + binder.SetAttribute( "deviceId", deviceID ); //completely useless, but required for backwards compatability - control.InsertEndChild(binder); - } + control.InsertEndChild(binder); + } - if(getJoystickAxisBinding(*o, Control/*::ControlChangingDirection*/::DECREASE) - != /*NamedAxis::*/UNASSIGNED) - { - TiXmlElement binder( "JoystickAxisBinder" ); + if(getJoystickAxisBinding(*o, deviceID, Control/*::ControlChangingDirection*/::DECREASE) + != /*NamedAxis::*/UNASSIGNED) + { + TiXmlElement binder( "JoystickAxisBinder" ); - binder.SetAttribute( "axis", ToString( - getJoystickAxisBinding(*o, Control/*::ControlChangingDirection*/::DECREASE)).c_str() ); + binder.SetAttribute( "axis", ToString( + getJoystickAxisBinding(*o, deviceID, Control/*::ControlChangingDirection*/::DECREASE)).c_str() ); - binder.SetAttribute( "direction", "DECREASE" ); + binder.SetAttribute( "direction", "DECREASE" ); - binder.SetAttribute( "deviceId", "1" ); //completely useless, but required for backwards compatability + binder.SetAttribute( "deviceId", deviceID ); //completely useless, but required for backwards compatability - control.InsertEndChild(binder); - } + control.InsertEndChild(binder); + } - if(getJoystickButtonBinding(*o, Control/*::ControlChangingDirection*/::INCREASE) - != ICS_MAX_DEVICE_BUTTONS) - { - TiXmlElement binder( "JoystickButtonBinder" ); + if(getJoystickButtonBinding(*o, deviceID, Control/*::ControlChangingDirection*/::INCREASE) + != ICS_MAX_DEVICE_BUTTONS) + { + TiXmlElement binder( "JoystickButtonBinder" ); - binder.SetAttribute( "button", ToString( - getJoystickButtonBinding(*o, Control/*::ControlChangingDirection*/::INCREASE)).c_str() ); + binder.SetAttribute( "button", ToString( + getJoystickButtonBinding(*o, deviceID, Control/*::ControlChangingDirection*/::INCREASE)).c_str() ); - binder.SetAttribute( "direction", "INCREASE" ); + binder.SetAttribute( "direction", "INCREASE" ); - binder.SetAttribute( "deviceId", "1" ); //completely useless, but required for backwards compatability + binder.SetAttribute( "deviceId", deviceID ); //completely useless, but required for backwards compatability - control.InsertEndChild(binder); - } + control.InsertEndChild(binder); + } - if(getJoystickButtonBinding(*o, Control/*::ControlChangingDirection*/::DECREASE) - != ICS_MAX_DEVICE_BUTTONS) - { - TiXmlElement binder( "JoystickButtonBinder" ); + if(getJoystickButtonBinding(*o, deviceID, Control/*::ControlChangingDirection*/::DECREASE) + != ICS_MAX_DEVICE_BUTTONS) + { + TiXmlElement binder( "JoystickButtonBinder" ); - binder.SetAttribute( "button", ToString( - getJoystickButtonBinding(*o, Control/*::ControlChangingDirection*/::DECREASE)).c_str() ); + binder.SetAttribute( "button", ToString( + getJoystickButtonBinding(*o, deviceID, Control/*::ControlChangingDirection*/::DECREASE)).c_str() ); - binder.SetAttribute( "direction", "DECREASE" ); + binder.SetAttribute( "direction", "DECREASE" ); - binder.SetAttribute( "deviceId", "1" ); //completely useless, but required for backwards compatability + binder.SetAttribute( "deviceId", deviceID ); //completely useless, but required for backwards compatability - control.InsertEndChild(binder); + control.InsertEndChild(binder); + } + it++; } diff --git a/extern/oics/ICSInputControlSystem.h b/extern/oics/ICSInputControlSystem.h index 0bdd67b34..51b701b48 100644 --- a/extern/oics/ICSInputControlSystem.h +++ b/extern/oics/ICSInputControlSystem.h @@ -64,7 +64,8 @@ namespace ICS typedef NamedAxis MouseAxis; // MouseAxis is deprecated. It will be removed in future versions - typedef std::map JoystickIDList; + typedef std::map JoystickInstanceMap; + typedef std::list JoystickIDList; typedef struct { @@ -100,9 +101,10 @@ namespace ICS inline void activate(){ this->mActive = true; }; inline void deactivate(){ this->mActive = false; }; - void controllerAdded (const SDL_ControllerDeviceEvent &args); + void controllerAdded (int deviceID, const SDL_ControllerDeviceEvent &args); void controllerRemoved(const SDL_ControllerDeviceEvent &args); - JoystickIDList& getJoystickIdList(){ return mJoystickIDList; }; + JoystickIDList& getJoystickIdList(){ return mJoystickIDList; }; + JoystickInstanceMap& getJoystickInstanceMap(){ return mJoystickInstanceMap; }; // MouseListener void mouseMoved(const SFO::MouseMotionEvent &evt); @@ -114,28 +116,28 @@ namespace ICS void keyReleased(const SDL_KeyboardEvent &evt); // ControllerListener - void buttonPressed(const SDL_ControllerButtonEvent &evt); - void buttonReleased(const SDL_ControllerButtonEvent &evt); - void axisMoved(const SDL_ControllerAxisEvent &evt); + void buttonPressed(int deviceID, const SDL_ControllerButtonEvent &evt); + void buttonReleased(int deviceID, const SDL_ControllerButtonEvent &evt); + void axisMoved(int deviceID, const SDL_ControllerAxisEvent &evt); void addKeyBinding(Control* control, SDL_Scancode key, Control::ControlChangingDirection direction); bool isKeyBound(SDL_Scancode key) const; void addMouseAxisBinding(Control* control, NamedAxis axis, Control::ControlChangingDirection direction); void addMouseButtonBinding(Control* control, unsigned int button, Control::ControlChangingDirection direction); bool isMouseButtonBound(unsigned int button) const; - void addJoystickAxisBinding(Control* control, int axis, Control::ControlChangingDirection direction); - void addJoystickButtonBinding(Control* control, unsigned int button, Control::ControlChangingDirection direction); + void addJoystickAxisBinding(Control* control, int deviceID, int axis, Control::ControlChangingDirection direction); + void addJoystickButtonBinding(Control* control, int deviceID, unsigned int button, Control::ControlChangingDirection direction); void removeKeyBinding(SDL_Scancode key); void removeMouseAxisBinding(NamedAxis axis); void removeMouseButtonBinding(unsigned int button); - void removeJoystickAxisBinding(int axis); - void removeJoystickButtonBinding(unsigned int button); + void removeJoystickAxisBinding(int deviceID, int axis); + void removeJoystickButtonBinding(int deviceID, unsigned int button); SDL_Scancode getKeyBinding(Control* control, ICS::Control::ControlChangingDirection direction); NamedAxis getMouseAxisBinding(Control* control, ICS::Control::ControlChangingDirection direction); unsigned int getMouseButtonBinding(Control* control, ICS::Control::ControlChangingDirection direction); - int getJoystickAxisBinding(Control* control, ICS::Control::ControlChangingDirection direction); - unsigned int getJoystickButtonBinding(Control* control, ICS::Control::ControlChangingDirection direction); + int getJoystickAxisBinding(Control* control, int deviceID, ICS::Control::ControlChangingDirection direction); + unsigned int getJoystickButtonBinding(Control* control, int deviceID, ICS::Control::ControlChangingDirection direction); std::string scancodeToString(SDL_Scancode key); @@ -183,14 +185,15 @@ namespace ICS typedef std::map ControlsKeyBinderMapType; // typedef std::map ControlsAxisBinderMapType; // - typedef std::map ControlsButtonBinderMapType; // - typedef std::map ControlsPOVBinderMapType; // - typedef std::map ControlsSliderBinderMapType; // + typedef std::map ControlsButtonBinderMapType; // + + typedef std::map JoystickAxisBinderMapType; // > + typedef std::map JoystickButtonBinderMapType; // > ControlsAxisBinderMapType mControlsMouseAxisBinderMap; // ControlsButtonBinderMapType mControlsMouseButtonBinderMap; // - ControlsAxisBinderMapType mControlsJoystickAxisBinderMap; // - ControlsButtonBinderMapType mControlsJoystickButtonBinderMap; // + JoystickAxisBinderMapType mControlsJoystickAxisBinderMap; // + JoystickButtonBinderMapType mControlsJoystickButtonBinderMap; // std::vector mControls; std::vector mChannels; @@ -207,7 +210,8 @@ namespace ICS bool mXmouseAxisBinded; bool mYmouseAxisBinded; - JoystickIDList mJoystickIDList; + JoystickIDList mJoystickIDList; + JoystickInstanceMap mJoystickInstanceMap; int mMouseAxisBindingInitialValues[3]; @@ -229,10 +233,10 @@ namespace ICS virtual void mouseButtonBindingDetected(InputControlSystem* ICS, Control* control , unsigned int button, Control::ControlChangingDirection direction); - virtual void joystickAxisBindingDetected(InputControlSystem* ICS, Control* control + virtual void joystickAxisBindingDetected(InputControlSystem* ICS, int deviceID, Control* control , int axis, Control::ControlChangingDirection direction); - virtual void joystickButtonBindingDetected(InputControlSystem* ICS, Control* control + virtual void joystickButtonBindingDetected(InputControlSystem* ICS, int deviceID, Control* control , unsigned int button, Control::ControlChangingDirection direction); }; diff --git a/extern/oics/ICSInputControlSystem_joystick.cpp b/extern/oics/ICSInputControlSystem_joystick.cpp index d8dbfa112..ab219d074 100644 --- a/extern/oics/ICSInputControlSystem_joystick.cpp +++ b/extern/oics/ICSInputControlSystem_joystick.cpp @@ -48,7 +48,7 @@ namespace ICS dir = Control::DECREASE; } - addJoystickAxisBinding(mControls.back(), FromString(xmlJoystickBinder->Attribute("axis")), dir); + addJoystickAxisBinding(mControls.back(), FromString(xmlJoystickBinder->Attribute("deviceId")), FromString(xmlJoystickBinder->Attribute("axis")), dir); xmlJoystickBinder = xmlJoystickBinder->NextSiblingElement("JoystickAxisBinder"); } @@ -69,170 +69,193 @@ namespace ICS dir = Control::DECREASE; } - addJoystickButtonBinding(mControls.back(), FromString(xmlJoystickButtonBinder->Attribute("button")), dir); + addJoystickButtonBinding(mControls.back(), FromString(xmlJoystickButtonBinder->Attribute("deviceId")), FromString(xmlJoystickButtonBinder->Attribute("button")), dir); xmlJoystickButtonBinder = xmlJoystickButtonBinder->NextSiblingElement("JoystickButtonBinder"); } } // add bindings - void InputControlSystem::addJoystickAxisBinding(Control* control, int axis, Control::ControlChangingDirection direction) + void InputControlSystem::addJoystickAxisBinding(Control* control, int deviceID, int axis, Control::ControlChangingDirection direction) { ICS_LOG("\tAdding AxisBinder [axis=" - + ToString(axis) + ", direction=" - + ToString(direction) + "]"); + + ToString(axis) + ", deviceID=" + + ToString(deviceID) + ", direction=" + + ToString(direction) + "]"); control->setValue(0.5f); //all joystick axis start at .5, so do that ControlAxisBinderItem controlAxisBinderItem; controlAxisBinderItem.control = control; controlAxisBinderItem.direction = direction; - mControlsJoystickAxisBinderMap[ axis ] = controlAxisBinderItem; + mControlsJoystickAxisBinderMap[deviceID][axis] = controlAxisBinderItem; } - void InputControlSystem::addJoystickButtonBinding(Control* control, unsigned int button, Control::ControlChangingDirection direction) + void InputControlSystem::addJoystickButtonBinding(Control* control, int deviceID, unsigned int button, Control::ControlChangingDirection direction) { ICS_LOG("\tAdding JoystickButtonBinder [button=" - + ToString(button) + ", direction=" - + ToString(direction) + "]"); + + ToString(button) + ", deviceID=" + + ToString(deviceID) + ", direction=" + + ToString(direction) + "]"); ControlButtonBinderItem controlJoystickButtonBinderItem; controlJoystickButtonBinderItem.direction = direction; controlJoystickButtonBinderItem.control = control; - mControlsJoystickButtonBinderMap[ button ] = controlJoystickButtonBinderItem; + mControlsJoystickButtonBinderMap[deviceID][button] = controlJoystickButtonBinderItem; } // get bindings - int InputControlSystem::getJoystickAxisBinding(Control* control, ICS::Control::ControlChangingDirection direction) - { - ControlsAxisBinderMapType::iterator it = mControlsJoystickAxisBinderMap.begin(); - while(it != mControlsJoystickAxisBinderMap.end()) - { - if(it->first >= 0 && it->second.control == control && it->second.direction == direction) + int InputControlSystem::getJoystickAxisBinding(Control* control, int deviceID, ICS::Control::ControlChangingDirection direction) + { + if(mControlsJoystickAxisBinderMap.find(deviceID) != mControlsJoystickAxisBinderMap.end()) + { + ControlsAxisBinderMapType::iterator it = mControlsJoystickAxisBinderMap[deviceID].begin(); + while(it != mControlsJoystickAxisBinderMap[deviceID].end()) { - return it->first; - } - ++it; + if(it->first >= 0 && it->second.control == control && it->second.direction == direction) + { + return it->first; + } + ++it; + } } return /*NamedAxis::*/UNASSIGNED; } - unsigned int InputControlSystem::getJoystickButtonBinding(Control* control, ICS::Control::ControlChangingDirection direction) - { - ControlsButtonBinderMapType::iterator it = mControlsJoystickButtonBinderMap.begin(); - while(it != mControlsJoystickButtonBinderMap.end()) - { - if(it->second.control == control && it->second.direction == direction) + unsigned int InputControlSystem::getJoystickButtonBinding(Control* control, int deviceID, ICS::Control::ControlChangingDirection direction) + { + if(mControlsJoystickButtonBinderMap.find(deviceID) != mControlsJoystickButtonBinderMap.end()) + { + ControlsButtonBinderMapType::iterator it = mControlsJoystickButtonBinderMap[deviceID].begin(); + while(it != mControlsJoystickButtonBinderMap[deviceID].end()) { - return it->first; - } - ++it; + if(it->second.control == control && it->second.direction == direction) + { + return it->first; + } + ++it; + } } return ICS_MAX_DEVICE_BUTTONS; } // remove bindings - void InputControlSystem::removeJoystickAxisBinding(int axis) - { - ControlsButtonBinderMapType::iterator it = mControlsJoystickAxisBinderMap.find(axis); - if(it != mControlsJoystickAxisBinderMap.end()) - { - mControlsJoystickAxisBinderMap.erase(it); + void InputControlSystem::removeJoystickAxisBinding(int deviceID, int axis) + { + if(mControlsJoystickAxisBinderMap.find(deviceID) != mControlsJoystickAxisBinderMap.end()) + { + ControlsAxisBinderMapType::iterator it = mControlsJoystickAxisBinderMap[deviceID].find(axis); + if(it != mControlsJoystickAxisBinderMap[deviceID].end()) + { + mControlsJoystickAxisBinderMap[deviceID].erase(it); + } } } - void InputControlSystem::removeJoystickButtonBinding(unsigned int button) - { - ControlsButtonBinderMapType::iterator it = mControlsJoystickButtonBinderMap.find(button); - if(it != mControlsJoystickButtonBinderMap.end()) - { - mControlsJoystickButtonBinderMap.erase(it); + void InputControlSystem::removeJoystickButtonBinding(int deviceID, unsigned int button) + { + if(mControlsJoystickButtonBinderMap.find(deviceID) != mControlsJoystickButtonBinderMap.end()) + { + ControlsButtonBinderMapType::iterator it = mControlsJoystickButtonBinderMap[deviceID].find(button); + if(it != mControlsJoystickButtonBinderMap[deviceID].end()) + { + mControlsJoystickButtonBinderMap[deviceID].erase(it); + } } } // joyStick listeners - void InputControlSystem::buttonPressed(const SDL_ControllerButtonEvent &evt) + void InputControlSystem::buttonPressed(int deviceID, const SDL_ControllerButtonEvent &evt) { if(mActive) { if(!mDetectingBindingControl) - { - ControlsButtonBinderMapType::const_iterator it = mControlsJoystickButtonBinderMap.find(evt.button); - if(it != mControlsJoystickButtonBinderMap.end()) + { + if(mControlsJoystickButtonBinderMap.find(deviceID) != mControlsJoystickButtonBinderMap.end()) { - it->second.control->setIgnoreAutoReverse(false); - if(!it->second.control->getAutoChangeDirectionOnLimitsAfterStop()) + ControlsButtonBinderMapType::const_iterator it = mControlsJoystickButtonBinderMap[deviceID].find(evt.button); + if(it != mControlsJoystickButtonBinderMap[deviceID].end()) { - it->second.control->setChangingDirection(it->second.direction); - } - else - { - if(it->second.control->getValue() == 1) + it->second.control->setIgnoreAutoReverse(false); + if(!it->second.control->getAutoChangeDirectionOnLimitsAfterStop()) { - it->second.control->setChangingDirection(Control::DECREASE); + it->second.control->setChangingDirection(it->second.direction); } - else if(it->second.control->getValue() == 0) + else { - it->second.control->setChangingDirection(Control::INCREASE); + if(it->second.control->getValue() == 1) + { + it->second.control->setChangingDirection(Control::DECREASE); + } + else if(it->second.control->getValue() == 0) + { + it->second.control->setChangingDirection(Control::INCREASE); + } } - } + } } } } } - void InputControlSystem::buttonReleased(const SDL_ControllerButtonEvent &evt) + void InputControlSystem::buttonReleased(int deviceID, const SDL_ControllerButtonEvent &evt) { if(mActive) { if(!mDetectingBindingControl) - { - ControlsButtonBinderMapType::const_iterator it = mControlsJoystickButtonBinderMap.find(evt.button); - if(it != mControlsJoystickButtonBinderMap.end()) + { + if(mControlsJoystickButtonBinderMap.find(deviceID) != mControlsJoystickButtonBinderMap.end()) { - it->second.control->setChangingDirection(Control::STOP); + ControlsButtonBinderMapType::const_iterator it = mControlsJoystickButtonBinderMap[deviceID].find(evt.button); + if(it != mControlsJoystickButtonBinderMap[deviceID].end()) + { + it->second.control->setChangingDirection(Control::STOP); + } } } else if(mDetectingBindingListener) { - mDetectingBindingListener->joystickButtonBindingDetected(this, + mDetectingBindingListener->joystickButtonBindingDetected(this, deviceID, mDetectingBindingControl, evt.button, mDetectingBindingDirection); } } } - void InputControlSystem::axisMoved(const SDL_ControllerAxisEvent &evt) + void InputControlSystem::axisMoved(int deviceID, const SDL_ControllerAxisEvent &evt) { if(mActive) { if(!mDetectingBindingControl) - { - ControlAxisBinderItem joystickBinderItem = mControlsJoystickAxisBinderMap[evt.axis]; // joystic axis start at 0 index - Control* ctrl = joystickBinderItem.control; - if(ctrl) + { + if(mControlsJoystickAxisBinderMap.find(deviceID) != mControlsJoystickAxisBinderMap.end()) { - ctrl->setIgnoreAutoReverse(true); - - float axisRange = SDL_JOY_AXIS_MAX - SDL_JOY_AXIS_MIN; - float valDisplaced = (float)(evt.value - SDL_JOY_AXIS_MIN); - float percent = valDisplaced / axisRange * (1+DEADZONE*2) - DEADZONE; //Assures all values, 0 through 1, are seen - if(percent > .5-DEADZONE && percent < .5+DEADZONE) //close enough to center - percent = .5; - else if(percent > .5) - percent -= DEADZONE; - else - percent += DEADZONE; - - if(joystickBinderItem.direction == Control::INCREASE) - { - ctrl->setValue( percent ); - } - else if(joystickBinderItem.direction == Control::DECREASE) + ControlAxisBinderItem joystickBinderItem = mControlsJoystickAxisBinderMap[deviceID][evt.axis]; // joystic axis start at 0 index + Control* ctrl = joystickBinderItem.control; + if(ctrl) { - ctrl->setValue( 1 - ( percent ) ); - } + ctrl->setIgnoreAutoReverse(true); + + float axisRange = SDL_JOY_AXIS_MAX - SDL_JOY_AXIS_MIN; + float valDisplaced = (float)(evt.value - SDL_JOY_AXIS_MIN); + float percent = valDisplaced / axisRange * (1+DEADZONE*2) - DEADZONE; //Assures all values, 0 through 1, are seen + if(percent > .5-DEADZONE && percent < .5+DEADZONE) //close enough to center + percent = .5; + else if(percent > .5) + percent -= DEADZONE; + else + percent += DEADZONE; + + if(joystickBinderItem.direction == Control::INCREASE) + { + ctrl->setValue( percent ); + } + else if(joystickBinderItem.direction == Control::DECREASE) + { + ctrl->setValue( 1 - ( percent ) ); + } + } } } else if(mDetectingBindingListener) @@ -244,7 +267,7 @@ namespace ICS { if( abs( evt.value ) > ICS_JOYSTICK_AXIS_BINDING_MARGIN) { - mDetectingBindingListener->joystickAxisBindingDetected(this, + mDetectingBindingListener->joystickAxisBindingDetected(this, deviceID, mDetectingBindingControl, evt.axis, mDetectingBindingDirection); } } @@ -252,67 +275,68 @@ namespace ICS } } - void InputControlSystem::controllerAdded(const SDL_ControllerDeviceEvent &args) + void InputControlSystem::controllerAdded(int deviceID, const SDL_ControllerDeviceEvent &args) { ICS_LOG("Adding joystick (index: " + ToString(args.which) + ")"); SDL_GameController* cntrl = SDL_GameControllerOpen(args.which); int instanceID = SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(cntrl)); - if(mJoystickIDList.empty()) // + if(std::find(mJoystickIDList.begin(), mJoystickIDList.end(), deviceID)==mJoystickIDList.end()) { for(int j = 0 ; j < ICS_MAX_JOYSTICK_AXIS ; j++) { - if(mControlsJoystickAxisBinderMap.find(j) == mControlsJoystickAxisBinderMap.end()) + if(mControlsJoystickAxisBinderMap[deviceID].find(j) == mControlsJoystickAxisBinderMap[deviceID].end()) { ControlAxisBinderItem controlJoystickBinderItem; controlJoystickBinderItem.direction = Control::STOP; controlJoystickBinderItem.control = NULL; - mControlsJoystickAxisBinderMap[j] = controlJoystickBinderItem; + mControlsJoystickAxisBinderMap[deviceID][j] = controlJoystickBinderItem; } } + mJoystickIDList.push_front(deviceID); } - mJoystickIDList[instanceID] = cntrl; + mJoystickInstanceMap[instanceID] = cntrl; } void InputControlSystem::controllerRemoved(const SDL_ControllerDeviceEvent &args) { ICS_LOG("Removing joystick (instance id: " + ToString(args.which) + ")"); - if(mJoystickIDList.count(args.which)!=0) + if(mJoystickInstanceMap.count(args.which)!=0) { - SDL_GameControllerClose(mJoystickIDList.at(args.which)); - mJoystickIDList.erase(args.which); + SDL_GameControllerClose(mJoystickInstanceMap.at(args.which)); + mJoystickInstanceMap.erase(args.which); } } // joystick auto bindings - void DetectingBindingListener::joystickAxisBindingDetected(InputControlSystem* ICS, Control* control, int axis, Control::ControlChangingDirection direction) + void DetectingBindingListener::joystickAxisBindingDetected(InputControlSystem* ICS, int deviceID, Control* control, int axis, Control::ControlChangingDirection direction) { // if the joystick axis is used by another control, remove it - ICS->removeJoystickAxisBinding(axis); + ICS->removeJoystickAxisBinding(deviceID, axis); // if the control has an axis assigned, remove it - int oldAxis = ICS->getJoystickAxisBinding(control, direction); + int oldAxis = ICS->getJoystickAxisBinding(control, deviceID, direction); if(oldAxis != InputControlSystem::UNASSIGNED) { - ICS->removeJoystickAxisBinding(oldAxis); + ICS->removeJoystickAxisBinding(deviceID, oldAxis); } - ICS->addJoystickAxisBinding(control, axis, direction); + ICS->addJoystickAxisBinding(control, deviceID, axis, direction); ICS->cancelDetectingBindingState(); } - void DetectingBindingListener::joystickButtonBindingDetected(InputControlSystem* ICS, Control* control + void DetectingBindingListener::joystickButtonBindingDetected(InputControlSystem* ICS, int deviceID, Control* control , unsigned int button, Control::ControlChangingDirection direction) { // if the joystick button is used by another control, remove it - ICS->removeJoystickButtonBinding(button); + ICS->removeJoystickButtonBinding(deviceID, button); // if the control has a joystick button assigned, remove it - unsigned int oldButton = ICS->getJoystickButtonBinding(control, direction); + unsigned int oldButton = ICS->getJoystickButtonBinding(control, deviceID, direction); if(oldButton != ICS_MAX_DEVICE_BUTTONS) { - ICS->removeJoystickButtonBinding(oldButton); + ICS->removeJoystickButtonBinding(deviceID, oldButton); } - ICS->addJoystickButtonBinding(control, button, direction); + ICS->addJoystickButtonBinding(control, deviceID, button, direction); ICS->cancelDetectingBindingState(); } } diff --git a/extern/sdl4ogre/events.h b/extern/sdl4ogre/events.h index ebabb4cbb..a12283def 100644 --- a/extern/sdl4ogre/events.h +++ b/extern/sdl4ogre/events.h @@ -45,19 +45,19 @@ class ControllerListener public: virtual ~ControllerListener() {} /** @remarks Joystick button down event */ - virtual void buttonPressed( const SDL_ControllerButtonEvent &evt) = 0; + virtual void buttonPressed(int deviceID, const SDL_ControllerButtonEvent &evt) = 0; /** @remarks Joystick button up event */ - virtual void buttonReleased( const SDL_ControllerButtonEvent &evt) = 0; + virtual void buttonReleased(int deviceID, const SDL_ControllerButtonEvent &evt) = 0; /** @remarks Joystick axis moved event */ - virtual void axisMoved( const SDL_ControllerAxisEvent &arg) = 0; + virtual void axisMoved(int deviceID, const SDL_ControllerAxisEvent &arg) = 0; /** @remarks Joystick Added **/ - virtual void controllerAdded( const SDL_ControllerDeviceEvent &arg) = 0; + virtual void controllerAdded(int deviceID, const SDL_ControllerDeviceEvent &arg) = 0; /** @remarks Joystick Removed **/ - virtual void controllerRemoved( const SDL_ControllerDeviceEvent &arg) = 0; + virtual void controllerRemoved(const SDL_ControllerDeviceEvent &arg) = 0; }; diff --git a/extern/sdl4ogre/sdlinputwrapper.cpp b/extern/sdl4ogre/sdlinputwrapper.cpp index f211811cc..d2938eb14 100644 --- a/extern/sdl4ogre/sdlinputwrapper.cpp +++ b/extern/sdl4ogre/sdlinputwrapper.cpp @@ -97,7 +97,7 @@ namespace SFO break; case SDL_CONTROLLERDEVICEADDED: if(mConListener) - mConListener->controllerAdded(evt.cdevice); + mConListener->controllerAdded(1, evt.cdevice); //We only support one joystick, so give everything a generic deviceID break; case SDL_CONTROLLERDEVICEREMOVED: if(mConListener) @@ -105,15 +105,15 @@ namespace SFO break; case SDL_CONTROLLERBUTTONDOWN: if(mConListener) - mConListener->buttonPressed(evt.cbutton); + mConListener->buttonPressed(1, evt.cbutton); break; case SDL_CONTROLLERBUTTONUP: if(mConListener) - mConListener->buttonReleased(evt.cbutton); + mConListener->buttonReleased(1, evt.cbutton); break; case SDL_CONTROLLERAXISMOTION: if(mConListener) - mConListener->axisMoved(evt.caxis); + mConListener->axisMoved(1, evt.caxis); break; case SDL_WINDOWEVENT: handleWindowEvent(evt); From 796b4b01b0dcecb7b7bc860c0ecca7e5ffac8a1e Mon Sep 17 00:00:00 2001 From: Digmaster Date: Mon, 19 Jan 2015 18:20:49 -0600 Subject: [PATCH 0640/3725] Fix activating every frame when action is bound to a trigger --- apps/openmw/mwinput/inputmanagerimp.cpp | 29 +++++++++++++++++-------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 7b8580080..76d0b877a 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -233,14 +233,26 @@ namespace MWInput int action = channel->getNumber(); - if(currentValue > .8) currentValue = 1.0; - else if(currentValue < .6) currentValue = 0.0; - else return; - - if(previousValue > .8) previousValue = 1.0; - else if(previousValue < .6) previousValue = 0.0; - - if(currentValue == previousValue) return; + if((previousValue == 1 || previousValue == 0) && (currentValue==1 || currentValue==0)) + { + //Is a normal button press, so don't change it at all + } + //Otherwise only trigger button presses as they go through specific points + else if(previousValue >= .8 && currentValue < .8) + { + currentValue = 0.0; + previousValue = 1.0; + } + else if(previousValue <= .6 && currentValue > .6) + { + currentValue = 1.0; + previousValue = 0.0; + } + else + { + //If it's not switching between those values, ignore the channel change. + return; + } if (mControlSwitch["playercontrols"]) { @@ -271,7 +283,6 @@ namespace MWInput break; case A_Activate: resetIdleTime(); - if (!MWBase::Environment::get().getWindowManager()->isGuiMode()) activate(); break; From a192836582cbfeab7eff133dea989b13641c67ed Mon Sep 17 00:00:00 2001 From: Digmaster Date: Mon, 19 Jan 2015 18:55:17 -0600 Subject: [PATCH 0641/3725] (hopefully) correct gamecontrollerdb.txt behavior --- CMakeLists.txt | 3 +++ apps/openmw/engine.cpp | 14 +++++++++++++- apps/openmw/mwinput/inputmanagerimp.cpp | 17 ++++------------- apps/openmw/mwinput/inputmanagerimp.hpp | 3 ++- 4 files changed, 22 insertions(+), 15 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d8872e162..8efb90436 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -460,6 +460,7 @@ IF(NOT WIN32 AND NOT APPLE) INSTALL(FILES "${OpenMW_BINARY_DIR}/settings-default.cfg" DESTINATION "${SYSCONFDIR}" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") INSTALL(FILES "${OpenMW_BINARY_DIR}/transparency-overrides.cfg" DESTINATION "${SYSCONFDIR}" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" DESTINATION "${SYSCONFDIR}" RENAME "openmw.cfg" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") + INSTALL(FILES "${OpenMW_BINARY_DIR}/gamecontrollerdb.txt" DESTINATION "${SYSCONFDIR}" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") IF(BUILD_OPENCS) INSTALL(FILES "${OpenMW_BINARY_DIR}/opencs.ini" DESTINATION "${SYSCONFDIR}" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "opencs") ENDIF(BUILD_OPENCS) @@ -479,6 +480,7 @@ if(WIN32) "${OpenMW_SOURCE_DIR}/Docs/license/DejaVu Font License.txt" "${OpenMW_BINARY_DIR}/settings-default.cfg" "${OpenMW_BINARY_DIR}/transparency-overrides.cfg" + "${OpenMW_BINARY_DIR}/gamecontrollerdb.txt" "${OpenMW_BINARY_DIR}/Release/openmw.exe" DESTINATION ".") @@ -750,6 +752,7 @@ if (APPLE) install(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) install(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" RENAME "openmw.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) install(FILES "${OpenMW_BINARY_DIR}/settings-default.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) + install(FILES "${OpenMW_BINARY_DIR}/gamecontrollerdb.txt" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) install(FILES "${OpenMW_BINARY_DIR}/transparency-overrides.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) install(FILES "${OpenMW_BINARY_DIR}/opencs.ini" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 0e636e054..9c485c2af 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -368,7 +368,19 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) std::string keybinderUser = (mCfgMgr.getUserConfigPath() / "input_v2.xml").string(); bool keybinderUserExists = boost::filesystem::exists(keybinderUser); - MWInput::InputManager* input = new MWInput::InputManager (*mOgre, *this, keybinderUser, keybinderUserExists, mGrab); + + // find correct path to the game controller bindings + const std::string localdefault = mCfgMgr.getLocalPath().string() + "/gamecontrollerdb.cfg"; + const std::string globaldefault = mCfgMgr.getGlobalPath().string() + "/gamecontrollerdb.cfg"; + std::string gameControllerdb; + if (boost::filesystem::exists(localdefault)) + gameControllerdb = localdefault; + else if (boost::filesystem::exists(globaldefault)) + gameControllerdb = globaldefault; + else + gameControllerdb = ""; //if it doesn't exist, pass in an empty string + + MWInput::InputManager* input = new MWInput::InputManager (*mOgre, *this, keybinderUser, keybinderUserExists, gameControllerdb, mGrab); mEnvironment.setInputManager (input); MWGui::WindowManager* window = new MWGui::WindowManager( diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 76d0b877a..05ce62374 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -100,7 +100,8 @@ namespace MWInput { InputManager::InputManager(OEngine::Render::OgreRenderer &ogre, OMW::Engine& engine, - const std::string& userFile, bool userFileExists, bool grab) + const std::string& userFile, bool userFileExists, + const std::string& controllerBindingsFile, bool grab) : mOgre(ogre) , mPlayer(NULL) , mEngine(engine) @@ -160,19 +161,9 @@ namespace MWInput //Load controller mappings #if SDL_VERSION_ATLEAST(2,0,2) - Files::ConfigurationManager cfgMgr; - std::string db = cfgMgr.getLocalPath().string() + "/gamecontrollerdb.txt"; - if(boost::filesystem::exists(db)) + if(controllerBindingsFile!="") { - int res = SDL_GameControllerAddMappingsFromFile(db.c_str()); - if(res == -1) - { - //ICS_LOG(std::string("Error loading controller bindings: ")+SDL_GetError()); - } - else - { - //ICS_LOG(std::string("Loaded ")+boost::lexical_cast(res)+" Game controller bindings"); - } + SDL_GameControllerAddMappingsFromFile(controllerBindingsFile.c_str()); } #endif diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index e8ee955e2..a72275a9c 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -68,7 +68,8 @@ namespace MWInput public: InputManager(OEngine::Render::OgreRenderer &_ogre, OMW::Engine& engine, - const std::string& userFile, bool userFileExists, bool grab); + const std::string& userFile, bool userFileExists, + const std::string& controllerBindingsFile, bool grab); virtual ~InputManager(); From df5513da7c6bb66529eaa2637444635bc5c02f36 Mon Sep 17 00:00:00 2001 From: Digmaster Date: Sat, 24 Jan 2015 16:03:55 -0600 Subject: [PATCH 0642/3725] uses v3 input bindings, not v2 --- apps/openmw/engine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 9c485c2af..41179f6e5 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -366,7 +366,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) // 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.getUserConfigPath() / "input_v2.xml").string(); + std::string keybinderUser = (mCfgMgr.getUserConfigPath() / "input_v3.xml").string(); bool keybinderUserExists = boost::filesystem::exists(keybinderUser); // find correct path to the game controller bindings From 5d77ebdc60f7a93f0442862d599f809f99cd53e9 Mon Sep 17 00:00:00 2001 From: Digmaster Date: Sat, 24 Jan 2015 16:44:17 -0600 Subject: [PATCH 0643/3725] If v3 doesn't exist, copy from v2 --- apps/openmw/engine.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 5a50d6d27..7764b8775 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -373,6 +373,11 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) std::string keybinderUser = (mCfgMgr.getUserConfigPath() / "input_v3.xml").string(); bool keybinderUserExists = boost::filesystem::exists(keybinderUser); + if(!keybinderUserExists) + { + boost::filesystem::copy_file(mCfgMgr.getUserConfigPath() / "input_v2.xml", mCfgMgr.getUserConfigPath() / "input_v3.xml"); + keybinderUserExists=true; + } // find correct path to the game controller bindings const std::string localdefault = mCfgMgr.getLocalPath().string() + "/gamecontrollerdb.cfg"; From 464bbe4d6f0e0ec212cd5a37ee442fed58e24763 Mon Sep 17 00:00:00 2001 From: Digmaster Date: Sun, 25 Jan 2015 01:11:21 -0600 Subject: [PATCH 0644/3725] if v2 doesn't exist, don't erroneously set keyboardUserExists to true. --- apps/openmw/engine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 7764b8775..282182493 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -376,7 +376,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) if(!keybinderUserExists) { boost::filesystem::copy_file(mCfgMgr.getUserConfigPath() / "input_v2.xml", mCfgMgr.getUserConfigPath() / "input_v3.xml"); - keybinderUserExists=true; + keybinderUserExists = boost::filesystem::exists(keybinderUser); } // find correct path to the game controller bindings From 84ff11d0ab13e08cd03aaf9fd8405ff8026f5fc6 Mon Sep 17 00:00:00 2001 From: Digmaster Date: Mon, 26 Jan 2015 12:50:44 -0600 Subject: [PATCH 0645/3725] check if v2 exists before attemping to copy it --- apps/openmw/engine.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 282182493..d7230a394 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -375,8 +375,11 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) bool keybinderUserExists = boost::filesystem::exists(keybinderUser); if(!keybinderUserExists) { - boost::filesystem::copy_file(mCfgMgr.getUserConfigPath() / "input_v2.xml", mCfgMgr.getUserConfigPath() / "input_v3.xml"); - keybinderUserExists = boost::filesystem::exists(keybinderUser); + std::string input2 = (mCfgMgr.getUserConfigPath() / "input_v2.xml").string(); + if(boost::filesystem::exists(input2)) { + boost::filesystem::copy_file(input2, keybinderUser); + keybinderUserExists = boost::filesystem::exists(keybinderUser); + } } // find correct path to the game controller bindings From 0cd5437595e4a791cd18ff7288169d8f153c8a4b Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 27 Feb 2015 22:37:29 +0100 Subject: [PATCH 0646/3725] gamecontrollerdb.txt updated from upstream, added link and license --- files/gamecontrollerdb.txt | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/files/gamecontrollerdb.txt b/files/gamecontrollerdb.txt index 9ad8778a0..bd8d9c5fc 100644 --- a/files/gamecontrollerdb.txt +++ b/files/gamecontrollerdb.txt @@ -1,3 +1,24 @@ +# from https://github.com/gabomdq/SDL_GameControllerDB +# License: +# Simple DirectMedia Layer +# Copyright (C) 1997-2013 Sam Lantinga +# +# This software is provided 'as-is', without any express or implied +# warranty. In no event will the authors be held liable for any damages +# arising from the use of this software. +# +# Permission is granted to anyone to use this software for any purpose, +# including commercial applications, and to alter it and redistribute it +# freely, subject to the following restrictions: +# +# 1. The origin of this software must not be misrepresented; you must not +# claim that you wrote the original software. If you use this software +# in a product, an acknowledgment in the product documentation would be +# appreciated but is not required. +# 2. Altered source versions must be plainly marked as such, and must not be +# misrepresented as being the original software. +# 3. This notice may not be removed or altered from any source distribution. + # Windows - DINPUT 8f0e1200000000000000504944564944,Acme,platform:Windows,x:b2,a:b0,b:b1,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2, 341a3608000000000000504944564944,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, @@ -8,7 +29,6 @@ ffff0000000000000000504944564944,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4, 4c056802000000000000504944564944,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Windows, 25090500000000000000504944564944,PS3 DualShock,a:b2,b:b1,back:b9,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b0,y:b3,platform:Windows, 4c05c405000000000000504944564944,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, -xinput,X360 Controller,a:b10,b:b11,back:b5,dpdown:b1,dpleft:b2,dpright:b3,dpup:b0,guide:b14,leftshoulder:b8,leftstick:b6,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b7,righttrigger:a5,rightx:a2,righty:a3,start:b4,x:b12,y:b13,platform:Windows, 6d0418c2000000000000504944564944,Logitech RumblePad 2 USB,platform:Windows,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3, 36280100000000000000504944564944,OUYA Controller,platform:Windows,a:b0,b:b3,y:b2,x:b1,start:b14,guide:b15,leftstick:b6,rightstick:b7,leftshoulder:b4,rightshoulder:b5,dpup:b8,dpleft:b10,dpdown:b9,dpright:b11,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b12,righttrigger:b13, 4f0400b3000000000000504944564944,Thrustmaster Firestorm Dual Power,a:b0,b:b2,y:b3,x:b1,start:b10,guide:b8,back:b9,leftstick:b11,rightstick:b12,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Windows, @@ -16,6 +36,9 @@ xinput,X360 Controller,a:b10,b:b11,back:b5,dpdown:b1,dpleft:b2,dpright:b3,dpup:b 00f0f100000000000000504944564944,RetroUSB.com Super RetroPort,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Windows, 28040140000000000000504944564944,GamePad Pro USB,platform:Windows,a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,lefttrigger:b6,righttrigger:b7, ff113133000000000000504944564944,SVEN X-PAD,platform:Windows,a:b2,b:b3,y:b1,x:b0,start:b5,back:b4,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a4,lefttrigger:b8,righttrigger:b9, +8f0e0300000000000000504944564944,Piranha xtreme,platform:Windows,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2, +8f0e0d31000000000000504944564944,Multilaser JS071 USB,platform:Windows,a:b1,b:b2,y:b3,x:b0,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7, +10080300000000000000504944564944,PS2 USB,platform:Windows,a:b2,b:b1,y:b0,x:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a4,righty:a2,lefttrigger:b4,righttrigger:b5, # OS X 0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X, @@ -28,6 +51,8 @@ ff113133000000000000504944564944,SVEN X-PAD,platform:Windows,a:b2,b:b3,y:b1,x:b0 5e040000000000008e02000000000000,X360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, 891600000000000000fd000000000000,Razer Onza Tournament,a:b0,b:b1,y:b3,x:b2,start:b8,guide:b10,back:b9,leftstick:b6,rightstick:b7,leftshoulder:b4,rightshoulder:b5,dpup:b11,dpleft:b13,dpdown:b12,dpright:b14,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Mac OS X, 4f0400000000000000b3000000000000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,y:b3,x:b1,start:b10,guide:b8,back:b9,leftstick:b11,rightstick:,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Mac OS X, +8f0e0000000000000300000000000000,Piranha xtreme,platform:Mac OS X,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2, +0d0f0000000000004d00000000000000,HORI Gem Pad 3,platform:Mac OS X,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7, # Linux 0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, @@ -73,3 +98,4 @@ ff113133000000000000504944564944,SVEN X-PAD,platform:Windows,a:b2,b:b3,y:b1,x:b0 03000000666600000488000000010000,Super Joy Box 5 Pro,platform:Linux,a:b2,b:b1,x:b3,y:b0,back:b9,start:b8,leftshoulder:b6,rightshoulder:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b4,righttrigger:b5,dpup:b12,dpleft:b15,dpdown:b14,dpright:b13, 05000000362800000100000002010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,platform:Linux,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2, 05000000362800000100000003010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,platform:Linux,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2, +030000008916000001fd000024010000,Razer Onza Classic Edition,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8tart:b7,dpleft:b11,dpdown:b14,dpright:b12,dpup:b13,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4, From 54e3ebde63e22f1920c5a70acf7fc18299ffb229 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sat, 28 Feb 2015 17:13:21 +1300 Subject: [PATCH 0647/3725] addon list in launcher shows addon files with no dependencies (Fixes #2348) Also, game files must end with ".esm" or ".omwgame". --- components/contentselector/model/contentmodel.cpp | 3 ++- components/contentselector/model/esmfile.cpp | 6 ++++++ components/contentselector/model/esmfile.hpp | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/components/contentselector/model/contentmodel.cpp b/components/contentselector/model/contentmodel.cpp index cd0c67ee7..7850b2cd6 100644 --- a/components/contentselector/model/contentmodel.cpp +++ b/components/contentselector/model/contentmodel.cpp @@ -115,9 +115,10 @@ Qt::ItemFlags ContentSelectorModel::ContentModel::flags(const QModelIndex &index return Qt::NoItemFlags; Qt::ItemFlags returnFlags; - bool gamefileChecked = false; // addon can be checked if its gamefile is + // ... special case, addon with no dependency can be used with any gamefile. + bool gamefileChecked = (file->gameFiles().count() == 0); foreach (const QString &fileName, file->gameFiles()) { bool depFound = false; diff --git a/components/contentselector/model/esmfile.cpp b/components/contentselector/model/esmfile.cpp index a0a09105a..9f85e5f43 100644 --- a/components/contentselector/model/esmfile.cpp +++ b/components/contentselector/model/esmfile.cpp @@ -62,6 +62,12 @@ QByteArray ContentSelectorModel::EsmFile::encodedData() const return encodedData; } +bool ContentSelectorModel::EsmFile::isGameFile() const +{ + return (mGameFiles.size() == 0) && + (mFileName.endsWith(QLatin1String(".esm")) || mFileName.endsWith(QLatin1String(".omwgame"))); +} + QVariant ContentSelectorModel::EsmFile::fileProperty(const FileProperty prop) const { switch (prop) diff --git a/components/contentselector/model/esmfile.hpp b/components/contentselector/model/esmfile.hpp index 7e1edcaba..d0cebab3c 100644 --- a/components/contentselector/model/esmfile.hpp +++ b/components/contentselector/model/esmfile.hpp @@ -64,7 +64,7 @@ namespace ContentSelectorModel .arg(mGameFiles.join(", ")); } - inline bool isGameFile() const { return (mGameFiles.size() == 0); } + bool isGameFile() const; QByteArray encodedData() const; public: From 5e2839977bd7c40dee207122524af4107d4efb18 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sat, 28 Feb 2015 20:25:03 +1300 Subject: [PATCH 0648/3725] file extension comparison needs to be case insensitive. --- components/contentselector/model/esmfile.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/components/contentselector/model/esmfile.cpp b/components/contentselector/model/esmfile.cpp index 9f85e5f43..1ac1c7500 100644 --- a/components/contentselector/model/esmfile.cpp +++ b/components/contentselector/model/esmfile.cpp @@ -65,7 +65,8 @@ QByteArray ContentSelectorModel::EsmFile::encodedData() const bool ContentSelectorModel::EsmFile::isGameFile() const { return (mGameFiles.size() == 0) && - (mFileName.endsWith(QLatin1String(".esm")) || mFileName.endsWith(QLatin1String(".omwgame"))); + (mFileName.endsWith(QLatin1String(".esm"), Qt::CaseInsensitive) || + mFileName.endsWith(QLatin1String(".omwgame"), Qt::CaseInsensitive)); } QVariant ContentSelectorModel::EsmFile::fileProperty(const FileProperty prop) const From f82751422d87e9e2f99392d9fdece404e0168f6d Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 28 Feb 2015 16:31:22 +0100 Subject: [PATCH 0649/3725] Fix constant effect restore enchantments being applied incorrectly (Fixes #2408) --- apps/openmw/mwmechanics/spellcasting.cpp | 80 +++++++++++++----------- apps/openmw/mwmechanics/spellcasting.hpp | 2 - 2 files changed, 45 insertions(+), 37 deletions(-) diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 105fa5866..e702401a6 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -56,6 +56,42 @@ namespace } } + void applyDynamicStatsEffect(int attribute, const MWWorld::Ptr& target, float magnitude) + { + MWMechanics::DynamicStat value = target.getClass().getCreatureStats(target).getDynamic(attribute); + value.setCurrent(value.getCurrent()+magnitude, attribute == 2); + target.getClass().getCreatureStats(target).setDynamic(attribute, value); + } + + // TODO: refactor the effect tick functions in Actors so they can be reused here + void applyInstantEffectTick(int effectId, const MWWorld::Ptr& target, float magnitude) + { + if (effectId == ESM::MagicEffect::DamageHealth) + { + applyDynamicStatsEffect(0, target, magnitude * -1); + } + else if (effectId == ESM::MagicEffect::RestoreHealth) + { + applyDynamicStatsEffect(0, target, magnitude); + } + else if (effectId == ESM::MagicEffect::DamageFatigue) + { + applyDynamicStatsEffect(2, target, magnitude * -1); + } + else if (effectId == ESM::MagicEffect::RestoreFatigue) + { + applyDynamicStatsEffect(2, target, magnitude); + } + else if (effectId == ESM::MagicEffect::DamageMagicka) + { + applyDynamicStatsEffect(1, target, magnitude * -1); + } + else if (effectId == ESM::MagicEffect::RestoreMagicka) + { + applyDynamicStatsEffect(1, target, magnitude); + } + } + } namespace MWMechanics @@ -438,8 +474,8 @@ namespace MWMechanics float magnitude = effectIt->mMagnMin + (effectIt->mMagnMax - effectIt->mMagnMin) * random; magnitude *= magnitudeMult; - bool hasDuration = !(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration) && effectIt->mDuration > 0; - if (target.getClass().isActor() && hasDuration) + bool hasDuration = !(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration); + if (target.getClass().isActor() && hasDuration && effectIt->mDuration > 0) { ActiveSpells::ActiveEffect effect; effect.mEffectId = effectIt->mEffectID; @@ -471,7 +507,12 @@ namespace MWMechanics } } else - applyInstantEffect(target, caster, EffectKey(*effectIt), magnitude); + { + if (hasDuration && target.getClass().isActor()) + applyInstantEffectTick(effectIt->mEffectID, target, magnitude); + else + applyInstantEffect(target, caster, EffectKey(*effectIt), magnitude); + } // Re-casting a summon effect will remove the creature from previous castings of that effect. if (isSummoningEffect(effectIt->mEffectID) && !target.isEmpty() && target.getClass().isActor()) @@ -594,31 +635,6 @@ namespace MWMechanics value.restore(magnitude); target.getClass().getCreatureStats(target).setAttribute(attribute, value); } - // TODO: refactor the effect tick functions in Actors so they can be reused here - else if (effectId == ESM::MagicEffect::DamageHealth) - { - applyDynamicStatsEffect(0, target, magnitude * -1); - } - else if (effectId == ESM::MagicEffect::RestoreHealth) - { - applyDynamicStatsEffect(0, target, magnitude); - } - else if (effectId == ESM::MagicEffect::DamageFatigue) - { - applyDynamicStatsEffect(2, target, magnitude * -1); - } - else if (effectId == ESM::MagicEffect::RestoreFatigue) - { - applyDynamicStatsEffect(2, target, magnitude); - } - else if (effectId == ESM::MagicEffect::DamageMagicka) - { - applyDynamicStatsEffect(1, target, magnitude * -1); - } - else if (effectId == ESM::MagicEffect::RestoreMagicka) - { - applyDynamicStatsEffect(1, target, magnitude); - } else if (effectId == ESM::MagicEffect::DamageSkill || effectId == ESM::MagicEffect::RestoreSkill) { if (target.getTypeName() != typeid(ESM::NPC).name()) @@ -680,13 +696,7 @@ namespace MWMechanics } } } - - void CastSpell::applyDynamicStatsEffect(int attribute, const MWWorld::Ptr& target, float magnitude) - { - DynamicStat value = target.getClass().getCreatureStats(target).getDynamic(attribute); - value.setCurrent(value.getCurrent()+magnitude, attribute == 2); - target.getClass().getCreatureStats(target).setDynamic(attribute, value); - } + bool CastSpell::cast(const std::string &id) { diff --git a/apps/openmw/mwmechanics/spellcasting.hpp b/apps/openmw/mwmechanics/spellcasting.hpp index 2d550e085..dca4f0192 100644 --- a/apps/openmw/mwmechanics/spellcasting.hpp +++ b/apps/openmw/mwmechanics/spellcasting.hpp @@ -97,8 +97,6 @@ namespace MWMechanics /// @note \a caster can be any type of object, or even an empty object. void applyInstantEffect (const MWWorld::Ptr& target, const MWWorld::Ptr& caster, const MWMechanics::EffectKey& effect, float magnitude); - - void applyDynamicStatsEffect (int attribute, const MWWorld::Ptr& target, float magnitude); }; } From 76732b475a01a4fbfd7837a7cb034be4096bc6c2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 28 Feb 2015 16:37:06 +0100 Subject: [PATCH 0650/3725] Remove leftover --- files/settings-default.cfg | 2 -- 1 file changed, 2 deletions(-) diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 422561a02..19b570e2a 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -194,8 +194,6 @@ always run = false allow third person zoom = false -gamecontrollerdb file = resources/gamecontrollerdb.txt - [Game] # Always use the most powerful attack when striking with a weapon (chop, slash or thrust) best attack = false From 960e99c4f375de2e13d8a8d14b9049d3513b25fb Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 28 Feb 2015 17:43:15 +0100 Subject: [PATCH 0651/3725] Loading screen align fix --- files/mygui/openmw_loading_screen.layout | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/mygui/openmw_loading_screen.layout b/files/mygui/openmw_loading_screen.layout index 8a1514f84..92bc5aa4c 100644 --- a/files/mygui/openmw_loading_screen.layout +++ b/files/mygui/openmw_loading_screen.layout @@ -10,7 +10,7 @@
- + From 2f2a95f735d0006d581ef12f0c5e16d0c4c170d7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 28 Feb 2015 19:33:49 +0100 Subject: [PATCH 0652/3725] Fix crash for terrain without data, part 2 --- apps/openmw/mwworld/scene.cpp | 2 +- libs/openengine/bullet/physic.cpp | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index f03f65b36..08767df80 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -199,7 +199,7 @@ namespace MWWorld (*iter)->getCell()->getGridX(), (*iter)->getCell()->getGridY() ); - if (land) + if (land && land->mDataTypes&ESM::Land::DATA_VHGT) mPhysics->removeHeightField ((*iter)->getCell()->getGridX(), (*iter)->getCell()->getGridY()); } diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index 1ef00a0e1..b3e9f1395 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -414,13 +414,17 @@ namespace Physic + boost::lexical_cast(x) + "_" + boost::lexical_cast(y); - HeightField hf = mHeightFieldMap [name]; + HeightFieldContainer::iterator it = mHeightFieldMap.find(name); + if (it == mHeightFieldMap.end()) + return; + + const HeightField& hf = it->second; mDynamicsWorld->removeRigidBody(hf.mBody); delete hf.mShape; delete hf.mBody; - mHeightFieldMap.erase(name); + mHeightFieldMap.erase(it); } void PhysicEngine::adjustRigidBody(RigidBody* body, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, From 41e15e0c2d2ac255f14e55acc38a981bd3fc74a5 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 1 Mar 2015 10:27:51 +1300 Subject: [PATCH 0653/3725] Limit maximum attribute damage (Fixes #2367) Maximum damage that an attribute can have = base + fortify. --- apps/openmw/mwmechanics/actors.cpp | 8 ++++---- apps/openmw/mwmechanics/stat.cpp | 5 +++++ apps/openmw/mwmechanics/stat.hpp | 21 +++++++++++++-------- 3 files changed, 22 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index f8068e800..aa2cc8615 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -515,8 +515,8 @@ namespace MWMechanics for(int i = 0;i < ESM::Attribute::Length;++i) { AttributeValue stat = creatureStats.getAttribute(i); - stat.setModifier(effects.get(EffectKey(ESM::MagicEffect::FortifyAttribute, i)).getMagnitude() - - effects.get(EffectKey(ESM::MagicEffect::DrainAttribute, i)).getMagnitude() - + stat.setModifiers(effects.get(EffectKey(ESM::MagicEffect::FortifyAttribute, i)).getMagnitude(), + effects.get(EffectKey(ESM::MagicEffect::DrainAttribute, i)).getMagnitude(), effects.get(EffectKey(ESM::MagicEffect::AbsorbAttribute, i)).getMagnitude()); stat.damage(effects.get(EffectKey(ESM::MagicEffect::DamageAttribute, i)).getMagnitude() * duration * 1.5); @@ -782,8 +782,8 @@ namespace MWMechanics for(int i = 0;i < ESM::Skill::Length;++i) { SkillValue& skill = npcStats.getSkill(i); - skill.setModifier(effects.get(EffectKey(ESM::MagicEffect::FortifySkill, i)).getMagnitude() - - effects.get(EffectKey(ESM::MagicEffect::DrainSkill, i)).getMagnitude() - + skill.setModifiers(effects.get(EffectKey(ESM::MagicEffect::FortifySkill, i)).getMagnitude(), + effects.get(EffectKey(ESM::MagicEffect::DrainSkill, i)).getMagnitude(), effects.get(EffectKey(ESM::MagicEffect::AbsorbSkill, i)).getMagnitude()); skill.damage(effects.get(EffectKey(ESM::MagicEffect::DamageSkill, i)).getMagnitude() * duration * 1.5); diff --git a/apps/openmw/mwmechanics/stat.cpp b/apps/openmw/mwmechanics/stat.cpp index 61b6d60ad..554f619a5 100644 --- a/apps/openmw/mwmechanics/stat.cpp +++ b/apps/openmw/mwmechanics/stat.cpp @@ -15,6 +15,11 @@ void MWMechanics::AttributeValue::readState (const ESM::StatState& state) mDamage = state.mDamage; } +void MWMechanics::AttributeValue::setModifiers(int fortify, int drain, int absorb) +{ + mFortified = fortify; + mModifier = (fortify - drain) - absorb; +} void MWMechanics::SkillValue::writeState (ESM::StatState& state) const { diff --git a/apps/openmw/mwmechanics/stat.hpp b/apps/openmw/mwmechanics/stat.hpp index 1c33db0fd..294dbcb6c 100644 --- a/apps/openmw/mwmechanics/stat.hpp +++ b/apps/openmw/mwmechanics/stat.hpp @@ -235,26 +235,29 @@ namespace MWMechanics class AttributeValue { int mBase; - int mModifier; + int mFortified; + int mModifier; // net effect of Fortified, Drain & Absorb float mDamage; // needs to be float to allow continuous damage public: - AttributeValue() : mBase(0), mModifier(0), mDamage(0) {} + AttributeValue() : mBase(0), mFortified(0), mModifier(0), mDamage(0) {} int getModified() const { return std::max(0, mBase - (int) mDamage + mModifier); } int getBase() const { return mBase; } int getModifier() const { return mModifier; } void setBase(int base) { mBase = std::max(0, base); } - void setModifier(int mod) { mModifier = mod; } + void setModifiers(int fortify, int drain, int absorb); - void damage(float damage) { mDamage += damage; } + void damage(float damage) { mDamage = std::min(mDamage + damage, (float)(mBase + mFortified)); } void restore(float amount) { mDamage -= std::min(mDamage, amount); } int getDamage() const { return mDamage; } void writeState (ESM::StatState& state) const; void readState (const ESM::StatState& state); + + friend bool operator== (const AttributeValue& left, const AttributeValue& right); }; class SkillValue : public AttributeValue @@ -268,13 +271,16 @@ namespace MWMechanics void writeState (ESM::StatState& state) const; void readState (const ESM::StatState& state); + + friend bool operator== (const SkillValue& left, const SkillValue& right); }; inline bool operator== (const AttributeValue& left, const AttributeValue& right) { return left.getBase() == right.getBase() + && left.mFortified == right.mFortified && left.getModifier() == right.getModifier() - && left.getDamage() == right.getDamage(); + && left.mDamage == right.mDamage; } inline bool operator!= (const AttributeValue& left, const AttributeValue& right) { @@ -283,9 +289,8 @@ namespace MWMechanics inline bool operator== (const SkillValue& left, const SkillValue& right) { - return left.getBase() == right.getBase() - && left.getModifier() == right.getModifier() - && left.getDamage() == right.getDamage() + // delegate to base class for most of the work + return (static_cast(left) == right) && left.getProgress() == right.getProgress(); } inline bool operator!= (const SkillValue& left, const SkillValue& right) From c4625b94e5979ed42d29c48019830ec631f56778 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 1 Mar 2015 12:52:43 +1100 Subject: [PATCH 0654/3725] Fix OpenCS crashing since commit 9d6145 by showing gamefiles if the content selector was created from OpenCS. --- apps/opencs/view/doc/filedialog.cpp | 4 ++-- .../contentselector/model/contentmodel.cpp | 16 +++++++++++----- .../contentselector/model/contentmodel.hpp | 3 ++- .../contentselector/view/contentselector.cpp | 8 ++++---- .../contentselector/view/contentselector.hpp | 4 ++-- 5 files changed, 21 insertions(+), 14 deletions(-) diff --git a/apps/opencs/view/doc/filedialog.cpp b/apps/opencs/view/doc/filedialog.cpp index 6a72f13ed..c895a3399 100644 --- a/apps/opencs/view/doc/filedialog.cpp +++ b/apps/opencs/view/doc/filedialog.cpp @@ -24,7 +24,7 @@ CSVDoc::FileDialog::FileDialog(QWidget *parent) : resize(400, 400); setObjectName ("FileDialog"); - mSelector = new ContentSelectorView::ContentSelector (ui.contentSelectorWidget); + mSelector = new ContentSelectorView::ContentSelector (ui.contentSelectorWidget, true); mAdjusterWidget = new AdjusterWidget (this); } @@ -147,7 +147,7 @@ void CSVDoc::FileDialog::slotUpdateAcceptButton(int) void CSVDoc::FileDialog::slotUpdateAcceptButton(const QString &name, bool) { - bool success = (mSelector->selectedFiles().size() > 0); + bool success = !mSelector->selectedFiles().empty(); bool isNew = (mAction == ContentAction_New); diff --git a/components/contentselector/model/contentmodel.cpp b/components/contentselector/model/contentmodel.cpp index 7850b2cd6..3e3536413 100644 --- a/components/contentselector/model/contentmodel.cpp +++ b/components/contentselector/model/contentmodel.cpp @@ -9,13 +9,14 @@ #include "components/esm/esmreader.hpp" -ContentSelectorModel::ContentModel::ContentModel(QObject *parent, QIcon warningIcon) : +ContentSelectorModel::ContentModel::ContentModel(QObject *parent, QIcon warningIcon, bool showGameFiles) : QAbstractTableModel(parent), mWarningIcon(warningIcon), mMimeType ("application/omwcontent"), mMimeTypes (QStringList() << mMimeType), mColumnCount (1), - mDropActions (Qt::MoveAction) + mDropActions (Qt::MoveAction), + mShowGameFiles(showGameFiles) { setEncoding ("win1252"); uncheckAll(); @@ -110,9 +111,14 @@ Qt::ItemFlags ContentSelectorModel::ContentModel::flags(const QModelIndex &index if (!file) return Qt::NoItemFlags; - //game files are not shown + //game files are not shown (unless OpenCS) if (file->isGameFile()) - return Qt::NoItemFlags; + { + if(mShowGameFiles) + return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable; + else + return Qt::NoItemFlags; + } Qt::ItemFlags returnFlags; @@ -463,7 +469,7 @@ void ContentSelectorModel::ContentModel::addFiles(const QString &path) file->setDescription(QString::fromUtf8(fileReader.getDesc().c_str())); // HACK - // Load order constraint of Bloodmoon.esm needing Tribunal.esm is missing + // Load order constraint of Bloodmoon.esm needing Tribunal.esm is missing // from the file supplied by Bethesda, so we have to add it ourselves if (file->fileName().compare("Bloodmoon.esm", Qt::CaseInsensitive) == 0) { diff --git a/components/contentselector/model/contentmodel.hpp b/components/contentselector/model/contentmodel.hpp index 658555852..887ad51b3 100644 --- a/components/contentselector/model/contentmodel.hpp +++ b/components/contentselector/model/contentmodel.hpp @@ -23,7 +23,7 @@ namespace ContentSelectorModel { Q_OBJECT public: - explicit ContentModel(QObject *parent, QIcon warningIcon); + explicit ContentModel(QObject *parent, QIcon warningIcon, bool showGameFiles = false); ~ContentModel(); void setEncoding(const QString &encoding); @@ -66,6 +66,7 @@ namespace ContentSelectorModel void addFile(EsmFile *file); const EsmFile *item(int row) const; EsmFile *item(int row); + bool mShowGameFiles; void sortFiles(); diff --git a/components/contentselector/view/contentselector.cpp b/components/contentselector/view/contentselector.cpp index 2363ae477..9d35de8f6 100644 --- a/components/contentselector/view/contentselector.cpp +++ b/components/contentselector/view/contentselector.cpp @@ -13,21 +13,21 @@ #include #include -ContentSelectorView::ContentSelector::ContentSelector(QWidget *parent) : +ContentSelectorView::ContentSelector::ContentSelector(QWidget *parent, bool showGameFiles) : QObject(parent) { ui.setupUi(parent); ui.addonView->setDragDropMode(QAbstractItemView::InternalMove); - buildContentModel(); + buildContentModel(showGameFiles); buildGameFileView(); buildAddonView(); } -void ContentSelectorView::ContentSelector::buildContentModel() +void ContentSelectorView::ContentSelector::buildContentModel(bool showGameFiles) { QIcon warningIcon(ui.addonView->style()->standardIcon(QStyle::SP_MessageBoxWarning).pixmap(QSize(16, 15))); - mContentModel = new ContentSelectorModel::ContentModel(this, warningIcon); + mContentModel = new ContentSelectorModel::ContentModel(this, warningIcon, showGameFiles); } void ContentSelectorView::ContentSelector::buildGameFileView() diff --git a/components/contentselector/view/contentselector.hpp b/components/contentselector/view/contentselector.hpp index 2507cf6ad..eb060f7a9 100644 --- a/components/contentselector/view/contentselector.hpp +++ b/components/contentselector/view/contentselector.hpp @@ -23,7 +23,7 @@ namespace ContentSelectorView public: - explicit ContentSelector(QWidget *parent = 0); + explicit ContentSelector(QWidget *parent = 0, bool showGameFiles = false); QString currentFile() const; @@ -48,7 +48,7 @@ namespace ContentSelectorView Ui::ContentSelector ui; - void buildContentModel(); + void buildContentModel(bool showGameFiles); void buildGameFileView(); void buildAddonView(); void setGameFileSelected(int index, bool selected); From 5ff66ad40b5f439e9fb676c1b5ab90a473753d59 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 1 Mar 2015 13:09:23 +1100 Subject: [PATCH 0655/3725] Fix Bug #2402. SKIL records should not have NAME subrecord. --- apps/opencs/model/doc/savingstages.hpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/doc/savingstages.hpp b/apps/opencs/model/doc/savingstages.hpp index 87c9ba7eb..6607e9968 100644 --- a/apps/opencs/model/doc/savingstages.hpp +++ b/apps/opencs/model/doc/savingstages.hpp @@ -103,8 +103,20 @@ namespace CSMDoc if (state==CSMWorld::RecordBase::State_Modified || state==CSMWorld::RecordBase::State_ModifiedOnly) { - mState.getWriter().startRecord (mCollection.getRecord (stage).mModified.sRecordId); - mState.getWriter().writeHNCString ("NAME", mCollection.getId (stage)); + // FIXME: A quick Workaround to support SKIL records which should not write NAME. + // If there are more idcollection records that don't use NAME then a more + // generic solution may be required. The conversion code was simply + // copied from esmwriter. There's room for improving speed a little bit + // here if it turns out to be an issue. + uint32_t name = mCollection.getRecord (stage).mModified.sRecordId; + mState.getWriter().startRecord (name); + std::string type; + for (int i=0; i<4; ++i) + /// \todo make endianess agnostic + type += reinterpret_cast (&name)[i]; + + if(type != "SKIL") + mState.getWriter().writeHNCString ("NAME", mCollection.getId (stage)); mCollection.getRecord (stage).mModified.save (mState.getWriter()); mState.getWriter().endRecord (mCollection.getRecord (stage).mModified.sRecordId); } From cdee6f41fc651dc68d256e29e5a6e3c560d5b9d5 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 1 Mar 2015 15:34:18 +1300 Subject: [PATCH 0656/3725] fix: multi effect spell with different ranges (Fixes #2285) Applies all effects for a spell with multiple effects, where not all effects have the same range. --- apps/openmw/mwmechanics/activespells.cpp | 43 +++++++++++++++++++----- apps/openmw/mwmechanics/activespells.hpp | 3 ++ 2 files changed, 37 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwmechanics/activespells.cpp b/apps/openmw/mwmechanics/activespells.cpp index 6e15449e1..eec4f2bd3 100644 --- a/apps/openmw/mwmechanics/activespells.cpp +++ b/apps/openmw/mwmechanics/activespells.cpp @@ -152,12 +152,7 @@ namespace MWMechanics void ActiveSpells::addSpell(const std::string &id, bool stack, std::vector effects, const std::string &displayName, int casterActorId) { - bool exists = false; - for (TContainer::const_iterator it = begin(); it != end(); ++it) - { - if (id == it->first) - exists = true; - } + TContainer::iterator it(mSpells.find(id)); ActiveSpellParams params; params.mTimeStamp = MWBase::Environment::get().getWorld()->getTimeStamp(); @@ -165,14 +160,44 @@ namespace MWMechanics params.mDisplayName = displayName; params.mCasterActorId = casterActorId; - if (!exists || stack) - mSpells.insert (std::make_pair(id, params)); + if (it == end() || stack) + { + mSpells.insert(std::make_pair(id, params)); + } else - mSpells.find(id)->second = params; + { + // addSpell() is called with effects for a range. + // but a spell may have effects with different ranges (e.g. Touch & Target) + // so, if we see new effects for same spell assume additional + // spell effects and add to existing effects of spell + mergeEffects(params.mEffects, it->second.mEffects); + it->second = params; + } mSpellsChanged = true; } + void ActiveSpells::mergeEffects(std::vector& addTo, const std::vector& from) + { + for (std::vector::const_iterator effect(from.begin()); effect != from.end(); ++effect) + { + // if effect is not in addTo, add it + bool missing = true; + for (std::vector::const_iterator iter(addTo.begin()); iter != addTo.end(); ++iter) + { + if (effect->mEffectId == iter->mEffectId) + { + missing = false; + break; + } + } + if (missing) + { + addTo.push_back(*effect); + } + } + } + void ActiveSpells::removeEffects(const std::string &id) { mSpells.erase(Misc::StringUtils::lowerCase(id)); diff --git a/apps/openmw/mwmechanics/activespells.hpp b/apps/openmw/mwmechanics/activespells.hpp index 4f9d15d8c..2a4d75d40 100644 --- a/apps/openmw/mwmechanics/activespells.hpp +++ b/apps/openmw/mwmechanics/activespells.hpp @@ -55,6 +55,9 @@ namespace MWMechanics void rebuildEffects() const; + /// Add any effects that are in "from" and not in "addTo" to "addTo" + void mergeEffects(std::vector& addTo, const std::vector& from); + double timeToExpire (const TIterator& iterator) const; ///< Returns time (in in-game hours) until the spell pointed to by \a iterator /// expires. From 4c57cfc2d32c35a8acc156f4ccc8fff893a6528e Mon Sep 17 00:00:00 2001 From: sylar Date: Sun, 1 Mar 2015 09:49:33 +0400 Subject: [PATCH 0657/3725] fixes for glsles2 --- files/materials/atmosphere.shader | 2 +- files/materials/clouds.shader | 2 +- files/materials/moon.shader | 2 +- files/materials/objects.shader | 4 ++-- files/materials/stars.shader | 2 +- files/materials/sun.shader | 2 +- files/materials/terrain.shader | 2 +- files/materials/underwater.h | 4 ++-- files/materials/water.shader | 2 +- 9 files changed, 11 insertions(+), 11 deletions(-) diff --git a/files/materials/atmosphere.shader b/files/materials/atmosphere.shader index 5040052fc..3eaa73b1c 100644 --- a/files/materials/atmosphere.shader +++ b/files/materials/atmosphere.shader @@ -11,7 +11,7 @@ SH_START_PROGRAM { float4x4 viewFixed = view; -#if !SH_GLSL +#if !SH_GLSL && !SH_GLSLES viewFixed[0][3] = 0.0; viewFixed[1][3] = 0.0; viewFixed[2][3] = 0.0; diff --git a/files/materials/clouds.shader b/files/materials/clouds.shader index 93d0780e0..5902d2fdc 100644 --- a/files/materials/clouds.shader +++ b/files/materials/clouds.shader @@ -13,7 +13,7 @@ { float4x4 worldviewFixed = worldview; -#if !SH_GLSL +#if !SH_GLSL && !SH_GLSLES worldviewFixed[0][3] = 0.0; worldviewFixed[1][3] = 0.0; worldviewFixed[2][3] = 0.0; diff --git a/files/materials/moon.shader b/files/materials/moon.shader index 0e1a4ffc8..151b94180 100644 --- a/files/materials/moon.shader +++ b/files/materials/moon.shader @@ -12,7 +12,7 @@ shUniform(float4x4, projection) @shAutoConstant(projection, projection_matrix) SH_START_PROGRAM { float4x4 viewFixed = view; -#if !SH_GLSL +#if !SH_GLSL && !SH_GLSLES viewFixed[0][3] = 0.0; viewFixed[1][3] = 0.0; viewFixed[2][3] = 0.0; diff --git a/files/materials/objects.shader b/files/materials/objects.shader index 828674cc7..5c74b1139 100644 --- a/files/materials/objects.shader +++ b/files/materials/objects.shader @@ -166,7 +166,7 @@ #if VIEWPROJ_FIX float4x4 vpFixed = vpMatrix; -#if !SH_GLSL +#if !SH_GLSL && !SH_GLSLES vpFixed[2] = vpRow2Fix; #else vpFixed[0][2] = vpRow2Fix.x; @@ -384,7 +384,7 @@ float4 normalTex = shSample(normalMap, UV.xy); - normal = normalize (shMatrixMult( transpose(tbn), normalTex.xyz * 2.0 - float3 (1.0,1.0,1.0) )); + normal = normalize (shMatrixMult( transpose(tbn), normalTex.xyz * 2.0 - 1.0 )); #endif #if ENV_MAP || SPECULAR || PARALLAX diff --git a/files/materials/stars.shader b/files/materials/stars.shader index f2eb616a2..830be862a 100644 --- a/files/materials/stars.shader +++ b/files/materials/stars.shader @@ -13,7 +13,7 @@ SH_START_PROGRAM { float4x4 worldviewFixed = worldview; -#if !SH_GLSL +#if !SH_GLSL && !SH_GLSLES worldviewFixed[0][3] = 0.0; worldviewFixed[1][3] = 0.0; worldviewFixed[2][3] = 0.0; diff --git a/files/materials/sun.shader b/files/materials/sun.shader index fc747b522..72e49d1a7 100644 --- a/files/materials/sun.shader +++ b/files/materials/sun.shader @@ -12,7 +12,7 @@ shUniform(float4x4, projection) @shAutoConstant(projection, projection_matrix) SH_START_PROGRAM { float4x4 viewFixed = view; -#if !SH_GLSL +#if !SH_GLSL && !SH_GLSLES viewFixed[0][3] = 0.0; viewFixed[1][3] = 0.0; viewFixed[2][3] = 0.0; diff --git a/files/materials/terrain.shader b/files/materials/terrain.shader index 9bb5d247d..f20fce506 100644 --- a/files/materials/terrain.shader +++ b/files/materials/terrain.shader @@ -136,7 +136,7 @@ #if NEED_DEPTH #if VIEWPROJ_FIX float4x4 vpFixed = viewProjMatrix; -#if !SH_GLSL +#if !SH_GLSL && !SH_GLSLES vpFixed[2] = vpRow2Fix; #else vpFixed[0][2] = vpRow2Fix.x; diff --git a/files/materials/underwater.h b/files/materials/underwater.h index 332a0fd7d..2f38f6546 100644 --- a/files/materials/underwater.h +++ b/files/materials/underwater.h @@ -93,7 +93,7 @@ float3 getCaustics (shTexture2D causticMap, float3 worldPos, float3 waterEyePos, // NOTE: the original shader calculated a tangent space basis here, // but using only the world normal is cheaper and i couldn't see a visual difference // also, if this effect gets moved to screen-space some day, it's unlikely to have tangent information - float3 causticNorm = worldNormal.xyz * perturb(causticMap, causticPos.xy, causticdepth, windDir_windSpeed.xy, windDir_windSpeed.z, waterTimer).xyz * 2 - 1; + float3 causticNorm = worldNormal.xyz * perturb(causticMap, causticPos.xy, causticdepth, windDir_windSpeed.xy, windDir_windSpeed.z, waterTimer).xyz * 2.0 - 1.0; causticNorm = float3(causticNorm.x, causticNorm.y, -causticNorm.z); //float fresnel = pow(clamp(dot(LV,causticnorm),0.0,1.0),2.0); @@ -111,7 +111,7 @@ float3 getCaustics (shTexture2D causticMap, float3 worldPos, float3 waterEyePos, //caustics = shSaturate(pow(float3(causticR,causticG,causticB)*5.5,float3(5.5*causticdepth)))*NdotL*sunFade*causticdepth; caustics = shSaturate(pow(float3(causticR,causticG,causticB)*5.5,float3(5.5*causticdepth,5.5*causticdepth,5.5*causticdepth)))*NdotL*causticdepth; - caustics *= 3; + caustics *= 3.0; // shore transition caustics = shLerp (float3(1,1,1), caustics, waterDepth); diff --git a/files/materials/water.shader b/files/materials/water.shader index 10d63cdf4..eff245b5e 100644 --- a/files/materials/water.shader +++ b/files/materials/water.shader @@ -97,7 +97,7 @@ shOutputPosition = shMatrixMult(wvp, shInputPosition); - #if !SH_GLSL + #if !SH_GLSL && !SH_GLSLES float4x4 scalemat = float4x4( 0.5, 0.0, 0.0, 0.5, 0.0, -0.5, 0.0, 0.5, 0.0, 0.0, 0.5, 0.5, From 239c0071f5233e436232f37a7fb8f42aa1f23973 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 1 Mar 2015 19:28:20 +0100 Subject: [PATCH 0658/3725] Armor tooltip should show the effective armor rating --- apps/openmw/mwclass/armor.cpp | 19 ++++++++++++++++++- apps/openmw/mwclass/armor.hpp | 3 +++ apps/openmw/mwclass/npc.cpp | 11 +---------- apps/openmw/mwworld/class.cpp | 5 +++++ apps/openmw/mwworld/class.hpp | 3 +++ 5 files changed, 30 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index 64043157d..0f99d91da 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -245,7 +245,8 @@ namespace MWClass else typeText = "#{sHeavy}"; - text += "\n#{sArmorRating}: " + MWGui::ToolTips::toString(ref->mBase->mData.mArmor); + text += "\n#{sArmorRating}: " + MWGui::ToolTips::toString(getEffectiveArmorRating(ptr, + MWBase::Environment::get().getWorld()->getPlayerPtr())); int remainingHealth = getItemHealth(ptr); text += "\n#{sCondition}: " + MWGui::ToolTips::toString(remainingHealth) + "/" @@ -290,6 +291,22 @@ namespace MWClass return record->mId; } + int Armor::getEffectiveArmorRating(const MWWorld::Ptr &ptr, const MWWorld::Ptr &actor) const + { + MWWorld::LiveCellRef *ref = ptr.get(); + + int armorSkillType = getEquipmentSkill(ptr); + int armorSkill = actor.getClass().getSkill(actor, armorSkillType); + + const MWBase::World *world = MWBase::Environment::get().getWorld(); + int iBaseArmorSkill = world->getStore().get().find("iBaseArmorSkill")->getInt(); + + if(ref->mBase->mData.mWeight == 0) + return ref->mBase->mData.mArmor; + else + return ref->mBase->mData.mArmor * armorSkill / iBaseArmorSkill; + } + std::pair Armor::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const { MWWorld::InventoryStore& invStore = npc.getClass().getInventoryStore(npc); diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index 8c8e74cf4..21d711a0d 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -86,6 +86,9 @@ namespace MWClass virtual int getEnchantmentPoints (const MWWorld::Ptr& ptr) const; virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; + + /// Get the effective armor rating, factoring in the actor's skills, for the given armor. + virtual int getEffectiveArmorRating(const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const; }; } diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index cedff1291..52e5a0a95 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -1086,7 +1086,6 @@ namespace MWClass MWMechanics::NpcStats &stats = getNpcStats(ptr); MWWorld::InventoryStore &invStore = getInventoryStore(ptr); - int iBaseArmorSkill = store.find("iBaseArmorSkill")->getInt(); float fUnarmoredBase1 = store.find("fUnarmoredBase1")->getFloat(); float fUnarmoredBase2 = store.find("fUnarmoredBase2")->getFloat(); int unarmoredSkill = stats.getSkill(ESM::Skill::Unarmored).getModified(); @@ -1102,15 +1101,7 @@ namespace MWClass } else { - MWWorld::LiveCellRef *ref = it->get(); - - int armorSkillType = it->getClass().getEquipmentSkill(*it); - int armorSkill = stats.getSkill(armorSkillType).getModified(); - - if(ref->mBase->mData.mWeight == 0) - ratings[i] = ref->mBase->mData.mArmor; - else - ratings[i] = ref->mBase->mData.mArmor * armorSkill / iBaseArmorSkill; + ratings[i] = it->getClass().getEffectiveArmorRating(*it, ptr); } } diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index afc5ed635..6fa9ba9b6 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -454,4 +454,9 @@ namespace MWWorld { return -1; } + + int Class::getEffectiveArmorRating(const Ptr &ptr, const Ptr &actor) const + { + throw std::runtime_error("class does not support armor ratings"); + } } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 380d2a34b..782aa7815 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -347,6 +347,9 @@ namespace MWWorld virtual std::string getPrimaryFaction (const MWWorld::Ptr& ptr) const; virtual int getPrimaryFactionRank (const MWWorld::Ptr& ptr) const; + + /// Get the effective armor rating, factoring in the actor's skills, for the given armor. + virtual int getEffectiveArmorRating(const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const; }; } From 1ee615394095a3367cc0d4544aab6b0de55877d9 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 2 Mar 2015 06:51:31 +1100 Subject: [PATCH 0659/3725] Remove unnecessary boolean passing between objects. --- apps/opencs/view/doc/filedialog.cpp | 2 +- components/contentselector/model/contentmodel.cpp | 14 ++++---------- components/contentselector/model/contentmodel.hpp | 3 +-- .../contentselector/view/contentselector.cpp | 8 ++++---- .../contentselector/view/contentselector.hpp | 4 ++-- 5 files changed, 12 insertions(+), 19 deletions(-) diff --git a/apps/opencs/view/doc/filedialog.cpp b/apps/opencs/view/doc/filedialog.cpp index c895a3399..8dd83f24a 100644 --- a/apps/opencs/view/doc/filedialog.cpp +++ b/apps/opencs/view/doc/filedialog.cpp @@ -24,7 +24,7 @@ CSVDoc::FileDialog::FileDialog(QWidget *parent) : resize(400, 400); setObjectName ("FileDialog"); - mSelector = new ContentSelectorView::ContentSelector (ui.contentSelectorWidget, true); + mSelector = new ContentSelectorView::ContentSelector (ui.contentSelectorWidget); mAdjusterWidget = new AdjusterWidget (this); } diff --git a/components/contentselector/model/contentmodel.cpp b/components/contentselector/model/contentmodel.cpp index 3e3536413..3dc02af21 100644 --- a/components/contentselector/model/contentmodel.cpp +++ b/components/contentselector/model/contentmodel.cpp @@ -9,14 +9,13 @@ #include "components/esm/esmreader.hpp" -ContentSelectorModel::ContentModel::ContentModel(QObject *parent, QIcon warningIcon, bool showGameFiles) : +ContentSelectorModel::ContentModel::ContentModel(QObject *parent, QIcon warningIcon) : QAbstractTableModel(parent), mWarningIcon(warningIcon), mMimeType ("application/omwcontent"), mMimeTypes (QStringList() << mMimeType), mColumnCount (1), - mDropActions (Qt::MoveAction), - mShowGameFiles(showGameFiles) + mDropActions (Qt::MoveAction) { setEncoding ("win1252"); uncheckAll(); @@ -111,14 +110,9 @@ Qt::ItemFlags ContentSelectorModel::ContentModel::flags(const QModelIndex &index if (!file) return Qt::NoItemFlags; - //game files are not shown (unless OpenCS) + //game files can always be checked if (file->isGameFile()) - { - if(mShowGameFiles) - return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable; - else - return Qt::NoItemFlags; - } + return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable; Qt::ItemFlags returnFlags; diff --git a/components/contentselector/model/contentmodel.hpp b/components/contentselector/model/contentmodel.hpp index 887ad51b3..658555852 100644 --- a/components/contentselector/model/contentmodel.hpp +++ b/components/contentselector/model/contentmodel.hpp @@ -23,7 +23,7 @@ namespace ContentSelectorModel { Q_OBJECT public: - explicit ContentModel(QObject *parent, QIcon warningIcon, bool showGameFiles = false); + explicit ContentModel(QObject *parent, QIcon warningIcon); ~ContentModel(); void setEncoding(const QString &encoding); @@ -66,7 +66,6 @@ namespace ContentSelectorModel void addFile(EsmFile *file); const EsmFile *item(int row) const; EsmFile *item(int row); - bool mShowGameFiles; void sortFiles(); diff --git a/components/contentselector/view/contentselector.cpp b/components/contentselector/view/contentselector.cpp index 9d35de8f6..2363ae477 100644 --- a/components/contentselector/view/contentselector.cpp +++ b/components/contentselector/view/contentselector.cpp @@ -13,21 +13,21 @@ #include #include -ContentSelectorView::ContentSelector::ContentSelector(QWidget *parent, bool showGameFiles) : +ContentSelectorView::ContentSelector::ContentSelector(QWidget *parent) : QObject(parent) { ui.setupUi(parent); ui.addonView->setDragDropMode(QAbstractItemView::InternalMove); - buildContentModel(showGameFiles); + buildContentModel(); buildGameFileView(); buildAddonView(); } -void ContentSelectorView::ContentSelector::buildContentModel(bool showGameFiles) +void ContentSelectorView::ContentSelector::buildContentModel() { QIcon warningIcon(ui.addonView->style()->standardIcon(QStyle::SP_MessageBoxWarning).pixmap(QSize(16, 15))); - mContentModel = new ContentSelectorModel::ContentModel(this, warningIcon, showGameFiles); + mContentModel = new ContentSelectorModel::ContentModel(this, warningIcon); } void ContentSelectorView::ContentSelector::buildGameFileView() diff --git a/components/contentselector/view/contentselector.hpp b/components/contentselector/view/contentselector.hpp index eb060f7a9..2507cf6ad 100644 --- a/components/contentselector/view/contentselector.hpp +++ b/components/contentselector/view/contentselector.hpp @@ -23,7 +23,7 @@ namespace ContentSelectorView public: - explicit ContentSelector(QWidget *parent = 0, bool showGameFiles = false); + explicit ContentSelector(QWidget *parent = 0); QString currentFile() const; @@ -48,7 +48,7 @@ namespace ContentSelectorView Ui::ContentSelector ui; - void buildContentModel(bool showGameFiles); + void buildContentModel(); void buildGameFileView(); void buildAddonView(); void setGameFileSelected(int index, bool selected); From a653716e2c08df5581771452ac6d4e067fd66be3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 1 Mar 2015 22:22:20 +0100 Subject: [PATCH 0660/3725] Fix for damage/restore effects using the instant apply path when they have a duration --- apps/openmw/mwmechanics/spellcasting.cpp | 58 ++++++++++-------------- 1 file changed, 24 insertions(+), 34 deletions(-) diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index e702401a6..b91ea9984 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -64,8 +64,9 @@ namespace } // TODO: refactor the effect tick functions in Actors so they can be reused here - void applyInstantEffectTick(int effectId, const MWWorld::Ptr& target, float magnitude) + void applyInstantEffectTick(MWMechanics::EffectKey effect, const MWWorld::Ptr& target, float magnitude) { + int effectId = effect.mId; if (effectId == ESM::MagicEffect::DamageHealth) { applyDynamicStatsEffect(0, target, magnitude * -1); @@ -90,6 +91,27 @@ namespace { applyDynamicStatsEffect(1, target, magnitude); } + else if (effectId == ESM::MagicEffect::DamageAttribute || effectId == ESM::MagicEffect::RestoreAttribute) + { + int attribute = effect.mArg; + MWMechanics::AttributeValue value = target.getClass().getCreatureStats(target).getAttribute(attribute); + if (effectId == ESM::MagicEffect::DamageAttribute) + value.damage(magnitude); + else + value.restore(magnitude); + target.getClass().getCreatureStats(target).setAttribute(attribute, value); + } + else if (effectId == ESM::MagicEffect::DamageSkill || effectId == ESM::MagicEffect::RestoreSkill) + { + if (target.getTypeName() != typeid(ESM::NPC).name()) + return; + int skill = effect.mArg; + MWMechanics::SkillValue& value = target.getClass().getNpcStats(target).getSkill(skill); + if (effectId == ESM::MagicEffect::DamageSkill) + value.damage(magnitude); + else + value.restore(magnitude); + } } } @@ -509,7 +531,7 @@ namespace MWMechanics else { if (hasDuration && target.getClass().isActor()) - applyInstantEffectTick(effectIt->mEffectID, target, magnitude); + applyInstantEffectTick(EffectKey(*effectIt), target, magnitude); else applyInstantEffect(target, caster, EffectKey(*effectIt), magnitude); } @@ -526,16 +548,6 @@ namespace MWMechanics } } - // HACK: Damage attribute/skill actually has a duration, even though the actual effect is instant and permanent. - // This was probably just done to have the effect visible in the magic menu for a while - // to notify the player they've been damaged? - if (effectIt->mEffectID == ESM::MagicEffect::DamageAttribute - || effectIt->mEffectID == ESM::MagicEffect::DamageSkill - || effectIt->mEffectID == ESM::MagicEffect::RestoreAttribute - || effectIt->mEffectID == ESM::MagicEffect::RestoreSkill - ) - applyInstantEffect(target, caster, EffectKey(*effectIt), magnitude); - if (target.getClass().isActor() || magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration) { // Play sound, only for the first effect @@ -625,28 +637,6 @@ namespace MWMechanics } else { - if (effectId == ESM::MagicEffect::DamageAttribute || effectId == ESM::MagicEffect::RestoreAttribute) - { - int attribute = effect.mArg; - AttributeValue value = target.getClass().getCreatureStats(target).getAttribute(attribute); - if (effectId == ESM::MagicEffect::DamageAttribute) - value.damage(magnitude); - else - value.restore(magnitude); - target.getClass().getCreatureStats(target).setAttribute(attribute, value); - } - else if (effectId == ESM::MagicEffect::DamageSkill || effectId == ESM::MagicEffect::RestoreSkill) - { - if (target.getTypeName() != typeid(ESM::NPC).name()) - return; - int skill = effect.mArg; - SkillValue& value = target.getClass().getNpcStats(target).getSkill(skill); - if (effectId == ESM::MagicEffect::DamageSkill) - value.damage(magnitude); - else - value.restore(magnitude); - } - if (effectId == ESM::MagicEffect::CurePoison) target.getClass().getCreatureStats(target).getActiveSpells().purgeEffect(ESM::MagicEffect::Poison); else if (effectId == ESM::MagicEffect::CureParalyzation) From fb0fdf0312d872bad23e8db1fcde0426351e997b Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 1 Mar 2015 23:58:16 +0100 Subject: [PATCH 0661/3725] New look for fps counter --- files/mygui/openmw_hud.layout | 18 +++++++++--------- files/mygui/openmw_text.skin.xml | 4 +++- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/files/mygui/openmw_hud.layout b/files/mygui/openmw_hud.layout index 8334e34b9..0cbe0dd97 100644 --- a/files/mygui/openmw_hud.layout +++ b/files/mygui/openmw_hud.layout @@ -127,35 +127,35 @@
- + - + - + - + - - + + - - + + - + diff --git a/files/mygui/openmw_text.skin.xml b/files/mygui/openmw_text.skin.xml index fe01d3417..e459f22fa 100644 --- a/files/mygui/openmw_text.skin.xml +++ b/files/mygui/openmw_text.skin.xml @@ -19,9 +19,11 @@ color_misc=0,205,205 # ???? - + + + From 0ad514b29be91a0bac47bc46f6cc6ebfc831413e Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 2 Mar 2015 01:03:03 +0100 Subject: [PATCH 0662/3725] Fix collision for nodes with MRK extra data (Fixes #2415) --- components/nifbullet/bulletnifloader.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/components/nifbullet/bulletnifloader.cpp b/components/nifbullet/bulletnifloader.cpp index 35d552726..cdc06f985 100644 --- a/components/nifbullet/bulletnifloader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -274,10 +274,12 @@ void ManualBulletShapeLoader::handleNode(const Nif::Node *node, int flags, // No collision. Use an internal flag setting to mark this. flags |= 0x800; } - else if (sd->string == "MRK" && !mShowMarkers) - // Marker objects. These are only visible in the - // editor. + else if (sd->string == "MRK" && !mShowMarkers && raycasting) + { + // Marker objects should be invisible, but still have collision. + // Except in the editor, the marker objects are visible. return; + } } } From 191c0104f600abfa1edd27590790302bec17f36a Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 2 Mar 2015 15:19:57 +0100 Subject: [PATCH 0663/3725] Crash fix for creatures with no skeleton base (Fixes #2419) --- apps/openmw/mwrender/animation.cpp | 4 ++ apps/openmw/mwrender/creatureanimation.cpp | 7 +++- apps/openmw/mwrender/npcanimation.cpp | 46 +++++++++++++--------- 3 files changed, 37 insertions(+), 20 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 50afc5afd..01a88faf2 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1271,7 +1271,11 @@ void Animation::addEffect(const std::string &model, int effectId, bool loop, con if (bonename.empty()) params.mObjects = NifOgre::Loader::createObjects(mInsert, model); else + { + if (!mSkelBase) + return; params.mObjects = NifOgre::Loader::createObjects(mSkelBase, bonename, "", mInsert, model); + } setRenderProperties(params.mObjects, RV_Effects, RQG_Main, RQG_Alpha, 0.f, false, NULL); diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index 2bdf8a499..7260fc6d1 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -88,6 +88,9 @@ void CreatureWeaponAnimation::updateParts() void CreatureWeaponAnimation::updatePart(NifOgre::ObjectScenePtr& scene, int slot) { + if (!mSkelBase) + return; + MWWorld::InventoryStore& inv = mPtr.getClass().getInventoryStore(mPtr); MWWorld::ContainerStoreIterator it = inv.getSlot(slot); @@ -181,7 +184,9 @@ void CreatureWeaponAnimation::releaseArrow() Ogre::Vector3 CreatureWeaponAnimation::runAnimation(float duration) { Ogre::Vector3 ret = Animation::runAnimation(duration); - pitchSkeleton(mPtr.getRefData().getPosition().rot[0], mSkelBase->getSkeleton()); + + if (mSkelBase) + pitchSkeleton(mPtr.getRefData().getPosition().rot[0], mSkelBase->getSkeleton()); if (!mWeapon.isNull()) { diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 0926498c0..66ba25859 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -335,7 +335,10 @@ void NpcAnimation::updateNpcBase() } void NpcAnimation::updateParts() -{ +{ + if (!mSkelBase) + return; + mAlpha = 1.f; const MWWorld::Class &cls = mPtr.getClass(); @@ -621,30 +624,33 @@ NifOgre::ObjectScenePtr NpcAnimation::insertBoundedPart(const std::string &model } Ogre::Vector3 NpcAnimation::runAnimation(float timepassed) -{ +{ Ogre::Vector3 ret = Animation::runAnimation(timepassed); mHeadAnimationTime->update(timepassed); - Ogre::SkeletonInstance *baseinst = mSkelBase->getSkeleton(); - if(mViewMode == VM_FirstPerson) + if (mSkelBase) { - float pitch = mPtr.getRefData().getPosition().rot[0]; - Ogre::Node *node = baseinst->getBone("Bip01 Neck"); - node->pitch(Ogre::Radian(-pitch), Ogre::Node::TS_WORLD); + Ogre::SkeletonInstance *baseinst = mSkelBase->getSkeleton(); + if(mViewMode == VM_FirstPerson) + { + float pitch = mPtr.getRefData().getPosition().rot[0]; + Ogre::Node *node = baseinst->getBone("Bip01 Neck"); + node->pitch(Ogre::Radian(-pitch), Ogre::Node::TS_WORLD); - // This has to be done before this function ends; - // updateSkeletonInstance, below, touches the hands. - node->translate(mFirstPersonOffset, Ogre::Node::TS_WORLD); - } - else - { - // In third person mode we may still need pitch for ranged weapon targeting - pitchSkeleton(mPtr.getRefData().getPosition().rot[0], baseinst); + // This has to be done before this function ends; + // updateSkeletonInstance, below, touches the hands. + node->translate(mFirstPersonOffset, Ogre::Node::TS_WORLD); + } + else + { + // In third person mode we may still need pitch for ranged weapon targeting + pitchSkeleton(mPtr.getRefData().getPosition().rot[0], baseinst); - Ogre::Node* node = baseinst->getBone("Bip01 Head"); - if (node) - node->rotate(Ogre::Quaternion(mHeadYaw, Ogre::Vector3::UNIT_Z) * Ogre::Quaternion(mHeadPitch, Ogre::Vector3::UNIT_X), Ogre::Node::TS_WORLD); + Ogre::Node* node = baseinst->getBone("Bip01 Head"); + if (node) + node->rotate(Ogre::Quaternion(mHeadYaw, Ogre::Vector3::UNIT_Z) * Ogre::Quaternion(mHeadPitch, Ogre::Vector3::UNIT_X), Ogre::Node::TS_WORLD); + } } mFirstPersonOffset = 0.f; // reset the X, Y, Z offset for the next frame. @@ -659,7 +665,9 @@ Ogre::Vector3 NpcAnimation::runAnimation(float timepassed) if (!isSkinned(mObjectParts[i])) continue; - updateSkeletonInstance(baseinst, mObjectParts[i]->mSkelBase->getSkeleton()); + if (mSkelBase) + updateSkeletonInstance(mSkelBase->getSkeleton(), mObjectParts[i]->mSkelBase->getSkeleton()); + mObjectParts[i]->mSkelBase->getAllAnimationStates()->_notifyDirty(); } From c57f9ad5dc0e9c4cb5cac02eb9dca2ce5c172a81 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 2 Mar 2015 15:44:27 +0100 Subject: [PATCH 0664/3725] CMake: don't use CMAKE_CXX_FLAGS for gcc warning levels, it only works for CMAKE_BUILD_TYPE=None --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2ed6d6e17..20b38ce95 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -387,12 +387,12 @@ endif() # Compiler settings if (CMAKE_COMPILER_IS_GNUCC) - SET(CMAKE_CXX_FLAGS "-Wall -Wextra -Wno-unused-parameter -Wno-reorder -std=c++98 -pedantic -Wno-long-long ${CMAKE_CXX_FLAGS}") + set_property(GLOBAL APPEND_STRING PROPERTY COMPILE_FLAGS "-Wall -Wextra -Wno-unused-parameter -Wno-reorder -std=c++98 -pedantic -Wno-long-long") execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION) if ("${GCC_VERSION}" VERSION_GREATER 4.6 OR "${GCC_VERSION}" VERSION_EQUAL 4.6) - SET(CMAKE_CXX_FLAGS "-Wno-unused-but-set-parameter ${CMAKE_CXX_FLAGS}") + set_property(GLOBAL APPEND_STRING PROPERTY COMPILE_FLAGS "-Wno-unused-but-set-parameter") endif("${GCC_VERSION}" VERSION_GREATER 4.6 OR "${GCC_VERSION}" VERSION_EQUAL 4.6) elseif (MSVC) # Enable link-time code generation globally for all linking From c6aa374934f7ffbcb5bff6ba221cbc61cc1587e7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 2 Mar 2015 15:45:29 +0100 Subject: [PATCH 0665/3725] CMake: set windows warning levels globally instead of per target --- CMakeLists.txt | 30 ++++-------------------------- 1 file changed, 4 insertions(+), 26 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 20b38ce95..7b668cde1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -705,43 +705,21 @@ if (WIN32) set(WARNINGS "${WARNINGS} /wd${d}") endforeach(d) + set_property(GLOBAL APPEND_STRING PROPERTY COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") + # boost::wave has a few issues with signed / unsigned conversions, so we suppress those here set(SHINY_WARNINGS "${WARNINGS} /wd4245") set_target_properties(shiny PROPERTIES COMPILE_FLAGS "${SHINY_WARNINGS} ${MT_BUILD}") - set_target_properties(shiny.OgrePlatform PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") - set_target_properties(sdl4ogre PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") + # oics uses tinyxml, which has an initialized but unused variable set(OICS_WARNINGS "${WARNINGS} /wd4189") set_target_properties(oics PROPERTIES COMPILE_FLAGS "${OICS_WARNINGS} ${MT_BUILD}") - set_target_properties(components PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") - set_target_properties(ogre-ffmpeg-videoplayer PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") - if (BUILD_MYGUI_PLUGIN) - set_target_properties(Plugin_MyGUI_OpenMW_Resources PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") - endif (BUILD_MYGUI_PLUGIN) - if (BUILD_LAUNCHER) - set_target_properties(openmw-launcher PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") - endif (BUILD_LAUNCHER) - set_target_properties(openmw PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") - if (BUILD_BSATOOL) - set_target_properties(bsatool PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") - endif (BUILD_BSATOOL) - if (BUILD_ESMTOOL) - set_target_properties(esmtool PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") - endif (BUILD_ESMTOOL) - if (BUILD_WIZARD) - set_target_properties(openmw-wizard PROPERTIES COMPILE_FLAGS ${WARNINGS}) - endif (BUILD_WIZARD) + if (BUILD_OPENCS) # QT triggers an informational warning that the object layout may differ when compiled with /vd2 set(OPENCS_WARNINGS "${WARNINGS} ${MT_BUILD} /wd4435") set_target_properties(openmw-cs PROPERTIES COMPILE_FLAGS ${OPENCS_WARNINGS}) endif (BUILD_OPENCS) - if (BUILD_ESSIMPORTER) - set_target_properties(openmw-essimporter PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") - endif (BUILD_ESSIMPORTER) - if (BUILD_MWINIIMPORTER) - set_target_properties(openmw-iniimporter PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") - endif (BUILD_MWINIIMPORTER) endif(MSVC) # Same for MinGW From 1eaa64c49caeb753facf36c5173d5236c1f969e0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 2 Mar 2015 15:45:44 +0100 Subject: [PATCH 0666/3725] CMake: remove lines for MinGW, no one is maintaining those --- CMakeLists.txt | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7b668cde1..b01525692 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -722,22 +722,6 @@ if (WIN32) endif (BUILD_OPENCS) endif(MSVC) - # Same for MinGW - if (MINGW) - if (USE_DEBUG_CONSOLE) - set_target_properties(openmw PROPERTIES LINK_FLAGS_DEBUG "-Wl,-subsystem,console") - set_target_properties(openmw PROPERTIES LINK_FLAGS_RELWITHDEBINFO "-Wl,-subsystem,console") - set_target_properties(openmw PROPERTIES COMPILE_DEFINITIONS_DEBUG "_CONSOLE") - else(USE_DEBUG_CONSOLE) - set_target_properties(openmw PROPERTIES LINK_FLAGS_DEBUG "-Wl,-subsystem,windows") - set_target_properties(openmw PROPERTIES LINK_FLAGS_RELWITHDEBINFO "-Wl,-subsystem,windows") - endif(USE_DEBUG_CONSOLE) - - set_target_properties(openmw PROPERTIES LINK_FLAGS_RELEASE "-Wl,-subsystem,console") - set_target_properties(openmw PROPERTIES LINK_FLAGS_MINSIZEREL "-Wl,-subsystem,console") - set_target_properties(openmw PROPERTIES COMPILE_DEFINITIONS_RELEASE "_CONSOLE") - endif(MINGW) - # TODO: At some point release builds should not use the console but rather write to a log file #set_target_properties(openmw PROPERTIES LINK_FLAGS_RELEASE "/SUBSYSTEM:WINDOWS") #set_target_properties(openmw PROPERTIES LINK_FLAGS_MINSIZEREL "/SUBSYSTEM:WINDOWS") From 730138035d1e532a928baa29e418241a4d562ef6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 2 Mar 2015 17:25:26 +0100 Subject: [PATCH 0667/3725] Cycle infinite loop fix (Fixes #2421) --- apps/openmw/mwgui/inventorywindow.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 4270c4be1..e8e88ef65 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -653,16 +653,13 @@ namespace MWGui if (selected != -1) lastId = model.getItem(selected).mBase.getCellRef().getRefId(); ItemModel::ModelIndex cycled = selected; - while (!found) + for (int i=0; i Date: Mon, 2 Mar 2015 11:53:59 -0500 Subject: [PATCH 0668/3725] if cell doesn't exist, PositionCell and PlaceItemCell warn std::err but still execute, bug #2407 --- .../mwscript/transformationextensions.cpp | 28 ++++++++----------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 7af35a9ff..9166bf909 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -310,12 +310,13 @@ namespace MWScript } catch(std::exception&) { - const ESM::Cell* cell = MWBase::Environment::get().getWorld()->getExterior(cellID); - if(cell) + const ESM::Cell* cell = MWBase::Environment::get().getWorld()->getExterior(cellID); + int cx,cy; + MWBase::Environment::get().getWorld()->positionToIndex(x,y,cx,cy); + store = MWBase::Environment::get().getWorld()->getExterior(cx,cy); + if(!cell) { - int cx,cy; - MWBase::Environment::get().getWorld()->positionToIndex(x,y,cx,cy); - store = MWBase::Environment::get().getWorld()->getExterior(cx,cy); + std::cerr << "unknown cell (" << cellID << ")\n"; } } if(store) @@ -335,10 +336,6 @@ namespace MWScript ptr.getClass().adjustPosition(ptr, false); } - else - { - throw std::runtime_error (std::string("unknown cell (") + cellID + ")"); - } } }; @@ -426,11 +423,12 @@ namespace MWScript catch(std::exception&) { const ESM::Cell* cell = MWBase::Environment::get().getWorld()->getExterior(cellID); - if(cell) + int cx,cy; + MWBase::Environment::get().getWorld()->positionToIndex(x,y,cx,cy); + store = MWBase::Environment::get().getWorld()->getExterior(cx,cy); + if(!cell) { - int cx,cy; - MWBase::Environment::get().getWorld()->positionToIndex(x,y,cx,cy); - store = MWBase::Environment::get().getWorld()->getExterior(cx,cy); + std::cerr << "unknown cell (" << cellID << ")\n"; } } if(store) @@ -446,10 +444,6 @@ namespace MWScript MWWorld::Ptr placed = MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),store,pos); placed.getClass().adjustPosition(placed, true); } - else - { - throw std::runtime_error ( std::string("unknown cell (") + cellID + ")"); - } } }; From 653ddd3f2520cefa189901f195aca181bd9a0a53 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 2 Mar 2015 20:16:11 +0100 Subject: [PATCH 0669/3725] Warning fix --- apps/openmw/mwgui/inventorywindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index e8e88ef65..b0adddffa 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -653,7 +653,7 @@ namespace MWGui if (selected != -1) lastId = model.getItem(selected).mBase.getCellRef().getRefId(); ItemModel::ModelIndex cycled = selected; - for (int i=0; i Date: Mon, 2 Mar 2015 21:12:21 +0100 Subject: [PATCH 0670/3725] Remove "loading cell" message This spams the log too much, in particular when loading a savegame. --- apps/openmw/mwworld/cellstore.cpp | 2 -- apps/openmw/mwworld/scene.cpp | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 545bbd4b3..7da7c187d 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -407,8 +407,6 @@ namespace MWWorld if (mState==State_Preloaded) mIds.clear(); - std::cout << "loading cell " << mCell->getDescription() << std::endl; - loadRefs (store, esm); mState = State_Loaded; diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 08767df80..96e5ef224 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -219,6 +219,8 @@ namespace MWWorld if(result.second) { + std::cout << "loading cell " << cell->getCell()->getDescription() << std::endl; + float verts = ESM::Land::LAND_SIZE; float worldsize = ESM::Land::REAL_SIZE; From a8427c2efb6427c5751cda271e8db2408aa0e2b9 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Tue, 3 Mar 2015 07:36:11 +1100 Subject: [PATCH 0671/3725] Do not add NAME subrecords while saving magic effects or scripts. --- apps/opencs/model/doc/savingstages.hpp | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/apps/opencs/model/doc/savingstages.hpp b/apps/opencs/model/doc/savingstages.hpp index 6607e9968..8b79f2ddb 100644 --- a/apps/opencs/model/doc/savingstages.hpp +++ b/apps/opencs/model/doc/savingstages.hpp @@ -103,19 +103,14 @@ namespace CSMDoc if (state==CSMWorld::RecordBase::State_Modified || state==CSMWorld::RecordBase::State_ModifiedOnly) { - // FIXME: A quick Workaround to support SKIL records which should not write NAME. - // If there are more idcollection records that don't use NAME then a more - // generic solution may be required. The conversion code was simply - // copied from esmwriter. There's room for improving speed a little bit - // here if it turns out to be an issue. + // FIXME: A quick Workaround to support records which should not write + // NAME, including SKIL, MGEF and SCPT. If there are many more + // idcollection records that doesn't use NAME then a more generic + // solution may be required. uint32_t name = mCollection.getRecord (stage).mModified.sRecordId; mState.getWriter().startRecord (name); - std::string type; - for (int i=0; i<4; ++i) - /// \todo make endianess agnostic - type += reinterpret_cast (&name)[i]; - if(type != "SKIL") + if(name != ESM::REC_SKIL && name != ESM::REC_MGEF && name != ESM::REC_SCPT) mState.getWriter().writeHNCString ("NAME", mCollection.getId (stage)); mCollection.getRecord (stage).mModified.save (mState.getWriter()); mState.getWriter().endRecord (mCollection.getRecord (stage).mModified.sRecordId); From 8eb1f4e70e5e7a431c807d2412ca32bfafa20cb8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 2 Mar 2015 22:13:50 +0100 Subject: [PATCH 0672/3725] Remove more log spam --- apps/openmw/mwworld/scene.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 96e5ef224..8d689240b 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -492,8 +492,6 @@ namespace MWWorld loadingListener->setProgressRange(refsToLoad); // Load cell. - std::cout << "cellName: " << cell->getCell()->mName << std::endl; - loadCell (cell, loadingListener); changePlayerCell(cell, position, true); From f6509fe53eeffd1fc3834616b68989b09300087c Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 2 Mar 2015 22:23:00 +0100 Subject: [PATCH 0673/3725] Another crash fix for land record without data --- apps/opencs/view/render/cell.cpp | 2 +- components/esmterrain/storage.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index a0d0f6e71..ae2fad95a 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -78,7 +78,7 @@ CSVRender::Cell::Cell (CSMWorld::Data& data, Ogre::SceneManager *sceneManager, if (landIndex != -1) { const ESM::Land* esmLand = land.getRecord(mId).get().mLand.get(); - if(esmLand) + if(esmLand && esmLand->mDataTypes&ESM::Land::DATA_VHGT) { mTerrain.reset(new Terrain::TerrainGrid(sceneManager, new TerrainStorage(mData), Element_Terrain, true, Terrain::Align_XY)); diff --git a/components/esmterrain/storage.cpp b/components/esmterrain/storage.cpp index d4a0a0df2..e925a1e17 100644 --- a/components/esmterrain/storage.cpp +++ b/components/esmterrain/storage.cpp @@ -383,7 +383,7 @@ namespace ESMTerrain int cellY = std::floor(worldPos.y / 8192.f); ESM::Land* land = getLand(cellX, cellY); - if (!land) + if (!land || !(land->mDataTypes&ESM::Land::DATA_VHGT)) return -2048; // Mostly lifted from Ogre::Terrain::getHeightAtTerrainPosition From 7c0f5b72c5941ccca810fff45fe6286fc6be68bf Mon Sep 17 00:00:00 2001 From: cc9cii Date: Tue, 3 Mar 2015 08:31:06 +1100 Subject: [PATCH 0674/3725] Add enum namespace to workaround travis. --- apps/opencs/model/doc/savingstages.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/doc/savingstages.hpp b/apps/opencs/model/doc/savingstages.hpp index 8b79f2ddb..edf8c2640 100644 --- a/apps/opencs/model/doc/savingstages.hpp +++ b/apps/opencs/model/doc/savingstages.hpp @@ -110,7 +110,8 @@ namespace CSMDoc uint32_t name = mCollection.getRecord (stage).mModified.sRecordId; mState.getWriter().startRecord (name); - if(name != ESM::REC_SKIL && name != ESM::REC_MGEF && name != ESM::REC_SCPT) + if(name != ESM::RecNameInts::REC_SKIL && + name != ESM::RecNameInts::REC_MGEF && name != ESM::RecNameInts::REC_SCPT) mState.getWriter().writeHNCString ("NAME", mCollection.getId (stage)); mCollection.getRecord (stage).mModified.save (mState.getWriter()); mState.getWriter().endRecord (mCollection.getRecord (stage).mModified.sRecordId); From 17e3069896f9d5453281650b4f6bb6ed81c7fc9d Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 2 Mar 2015 22:33:37 +0100 Subject: [PATCH 0675/3725] Minor efficiency fix --- components/esmterrain/storage.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/components/esmterrain/storage.cpp b/components/esmterrain/storage.cpp index e925a1e17..9c7beebce 100644 --- a/components/esmterrain/storage.cpp +++ b/components/esmterrain/storage.cpp @@ -465,8 +465,9 @@ namespace ESMTerrain Terrain::LayerInfo Storage::getLayerInfo(const std::string& texture) { // Already have this cached? - if (mLayerInfoMap.find(texture) != mLayerInfoMap.end()) - return mLayerInfoMap[texture]; + std::map::iterator found = mLayerInfoMap.find(texture); + if (found != mLayerInfoMap.end()) + return found->second; Terrain::LayerInfo info; info.mParallax = false; From 666248618eb2e4ca2003f51a5dbc1891baa98998 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 2 Mar 2015 23:20:59 +0100 Subject: [PATCH 0676/3725] Fix reference cell movement leaving behind deleted Ptrs for script access --- apps/openmw/mwworld/worldimp.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 8a2b67bfc..3ef4f8e81 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1206,6 +1206,10 @@ namespace MWWorld } } ptr.getRefData().setCount(0); + // Deleted references can still be accessed by scripts, + // so we need this extra step to remove access to the old reference completely. + // This will no longer be necessary once we have a proper cell movement tracker. + ptr.getCellRef().unsetRefNum(); } } if (haveToMove && ptr.getRefData().getBaseNode()) From f09cbfb1678f7df933d858889dfa0da0b884afc1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 2 Mar 2015 23:29:33 +0100 Subject: [PATCH 0677/3725] Add a comment --- apps/openmw/mwworld/store.hpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index a155a3760..50dd37ac0 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -555,6 +555,9 @@ namespace MWWorld if (left.first == right.first) return left.second > right.second; + // Exterior cells are listed in descending, row-major order, + // this is a workaround for an ambiguous chargen_plank reference in the vanilla game. + // there is one at -22,16 and one at -2,-9, the latter should be used. return left.first > right.first; } }; From 66ef9d237ce5612fa9940f716909667016f9f9d9 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Tue, 3 Mar 2015 10:12:40 +1100 Subject: [PATCH 0678/3725] Another try to make it work with gcc/travis. --- apps/opencs/model/doc/savingstages.hpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/doc/savingstages.hpp b/apps/opencs/model/doc/savingstages.hpp index edf8c2640..907041114 100644 --- a/apps/opencs/model/doc/savingstages.hpp +++ b/apps/opencs/model/doc/savingstages.hpp @@ -7,6 +7,8 @@ #include "../world/idcollection.hpp" #include "../world/scope.hpp" +#include + #include "savingstate.hpp" namespace ESM @@ -110,8 +112,7 @@ namespace CSMDoc uint32_t name = mCollection.getRecord (stage).mModified.sRecordId; mState.getWriter().startRecord (name); - if(name != ESM::RecNameInts::REC_SKIL && - name != ESM::RecNameInts::REC_MGEF && name != ESM::RecNameInts::REC_SCPT) + if(name != ESM::REC_SKIL && name != ESM::REC_MGEF && name != ESM::REC_SCPT) mState.getWriter().writeHNCString ("NAME", mCollection.getId (stage)); mCollection.getRecord (stage).mModified.save (mState.getWriter()); mState.getWriter().endRecord (mCollection.getRecord (stage).mModified.sRecordId); From a8cb4e807b63657bcb6c5d8c2937dee664cb5aba Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Mar 2015 11:23:50 +0100 Subject: [PATCH 0679/3725] Warning fix --- apps/openmw/mwinput/inputmanagerimp.cpp | 12 ++++++------ components/config/launchersettings.hpp | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 4212c562b..284919f64 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -816,7 +816,7 @@ namespace MWInput setPlayerControlsEnabled(!guiMode); - //esc, to leave inital movie screen + //esc, to leave initial movie screen OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(SDLK_ESCAPE); bool guiFocus = MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::Enum(kc), 0); setPlayerControlsEnabled(!guiFocus); @@ -843,7 +843,7 @@ namespace MWInput else mInputBinder->buttonReleased(deviceID, arg); - //to escape inital movie + //to escape initial movie OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(SDLK_ESCAPE); setPlayerControlsEnabled(!MyGUI::InputManager::getInstance().injectKeyRelease(MyGUI::KeyCode::Enum(kc))); } @@ -1236,11 +1236,11 @@ namespace MWInput bool controlExists = mInputBinder->getChannel(i)->getControlsCount () != 0; if (!controlExists) { - int inital; + float initial; if (defaultButtonBindings.find(i) != defaultButtonBindings.end()) - inital = 0.0f; - else inital = 0.5f; - control = new ICS::Control(boost::lexical_cast(i), false, true, inital, ICS::ICS_MAX, ICS::ICS_MAX); + initial = 0.0f; + else initial = 0.5f; + control = new ICS::Control(boost::lexical_cast(i), false, true, initial, ICS::ICS_MAX, ICS::ICS_MAX); mInputBinder->addControl(control); control->attachChannel(mInputBinder->getChannel(i), ICS::Channel::DIRECT); } diff --git a/components/config/launchersettings.hpp b/components/config/launchersettings.hpp index cbe21c54a..c5eefb22a 100644 --- a/components/config/launchersettings.hpp +++ b/components/config/launchersettings.hpp @@ -17,7 +17,7 @@ namespace Config /// \return names of all Content Lists in the launcher's .cfg file. QStringList getContentLists(); - /// Set initally selected content list to match values from openmw.cfg, creating if necessary + /// Set initially selected content list to match values from openmw.cfg, creating if necessary void setContentList(const GameSettings& gameSettings); /// Create a Content List (or replace if it already exists) From cdf53c17e7e250717b26a2349d64744d13603d1d Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 3 Mar 2015 11:54:35 +0100 Subject: [PATCH 0680/3725] updated version number --- CMakeLists.txt | 2 +- README.md | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b01525692..6b6944d5c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,7 +20,7 @@ message(STATUS "Configuring OpenMW...") set(OPENMW_VERSION_MAJOR 0) set(OPENMW_VERSION_MINOR 35) -set(OPENMW_VERSION_RELEASE 0) +set(OPENMW_VERSION_RELEASE 1) set(OPENMW_VERSION_COMMITHASH "") set(OPENMW_VERSION_TAGHASH "") diff --git a/README.md b/README.md index 63a313896..ce37de8c5 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ OpenMW 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.35.0 +* Version: 0.35.1 * License: GPL (see docs/license/GPL3.txt for more information) * Website: http://www.openmw.org * IRC: #openmw on irc.freenode.net @@ -68,9 +68,9 @@ Command line options of the blacklist is enabled) --script-blacklist-use [=arg(=1)] (=1) enable script blacklisting - --load-savegame arg load a save game file on game startup - (specify an absolute filename or a - filename relative to the current + --load-savegame arg load a save game file on game startup + (specify an absolute filename or a + filename relative to the current working directory) --skip-menu [=arg(=1)] (=0) skip main menu on game startup --new-game [=arg(=1)] (=0) run new game sequence (ignored if From bf92d5cde9e501e2bfcc081707968938a79076a0 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 3 Mar 2015 13:04:57 +0100 Subject: [PATCH 0681/3725] removed redundant mScript field in ESM::StartScript --- apps/esmtool/record.cpp | 2 +- apps/openmw/mwscript/globalscripts.cpp | 2 +- apps/openmw/mwworld/store.hpp | 13 ------------- components/esm/loadsscr.cpp | 4 ++-- components/esm/loadsscr.hpp | 2 +- 5 files changed, 5 insertions(+), 18 deletions(-) diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index 97b0635fe..6fd4b80fb 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -1253,7 +1253,7 @@ void Record::print() template<> void Record::print() { - std::cout << "Start Script: " << mData.mScript << std::endl; + std::cout << "Start Script: " << mData.mId << std::endl; std::cout << "Start Data: " << mData.mData << std::endl; } diff --git a/apps/openmw/mwscript/globalscripts.cpp b/apps/openmw/mwscript/globalscripts.cpp index 92fd51d87..a6ad2cc11 100644 --- a/apps/openmw/mwscript/globalscripts.cpp +++ b/apps/openmw/mwscript/globalscripts.cpp @@ -100,7 +100,7 @@ namespace MWScript mStore.get().begin(); iter != mStore.get().end(); ++iter) { - scripts.push_back (iter->mScript); + scripts.push_back (iter->mId); } // add scripts diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index 50dd37ac0..a887272c5 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -364,19 +364,6 @@ namespace MWWorld inserted.first->second = scpt; } - template <> - inline void Store::load(ESM::ESMReader &esm, const std::string &id) { - ESM::StartScript s; - s.load(esm); - s.mId = Misc::StringUtils::toLower(s.mScript); - - std::pair inserted = mStatic.insert(std::make_pair(s.mId, s)); - if (inserted.second) - mShared.push_back(&inserted.first->second); - else - inserted.first->second = s; - } - template <> class Store : public StoreBase { diff --git a/components/esm/loadsscr.cpp b/components/esm/loadsscr.cpp index 816075b7e..9b02b51c9 100644 --- a/components/esm/loadsscr.cpp +++ b/components/esm/loadsscr.cpp @@ -23,7 +23,7 @@ namespace ESM hasData = true; break; case ESM::FourCC<'N','A','M','E'>::value: - mScript = esm.getHString(); + mId = esm.getHString(); hasName = true; break; default: @@ -38,7 +38,7 @@ namespace ESM void StartScript::save(ESMWriter &esm) const { esm.writeHNString("DATA", mData); - esm.writeHNString("NAME", mScript); + esm.writeHNString("NAME", mId); } } diff --git a/components/esm/loadsscr.hpp b/components/esm/loadsscr.hpp index d09ad883e..954a4a2b6 100644 --- a/components/esm/loadsscr.hpp +++ b/components/esm/loadsscr.hpp @@ -22,7 +22,7 @@ struct StartScript static unsigned int sRecordId; std::string mData; - std::string mId, mScript; + std::string mId; // Load a record and add it to the list void load(ESMReader &esm); From 4e1c086d6acfd9a9e2de7a8aa030b1a12f4fcaac Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 3 Mar 2015 13:52:36 +0100 Subject: [PATCH 0682/3725] load start up script records --- apps/opencs/model/world/data.cpp | 16 ++++++++++++++++ apps/opencs/model/world/data.hpp | 6 ++++++ apps/opencs/model/world/universalid.cpp | 2 ++ apps/opencs/model/world/universalid.hpp | 2 ++ components/esm/loadsscr.cpp | 4 ++++ components/esm/loadsscr.hpp | 2 ++ 6 files changed, 32 insertions(+) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 67f6822c7..313518091 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -254,6 +254,10 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mPathgrids.addColumn (new RecordStateColumn); mPathgrids.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Pathgrid)); + mStartScripts.addColumn (new StringIdColumn); + mStartScripts.addColumn (new RecordStateColumn); + mStartScripts.addColumn (new FixedRecordTypeColumn (UniversalId::Type_StartScript)); + mRefs.addColumn (new StringIdColumn (true)); mRefs.addColumn (new RecordStateColumn); mRefs.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Reference)); @@ -327,6 +331,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc addModel (new IdTable (&mSoundGens), UniversalId::Type_SoundGen); addModel (new IdTable (&mMagicEffects), UniversalId::Type_MagicEffect); addModel (new IdTable (&mPathgrids), UniversalId::Type_Pathgrid); + addModel (new IdTable (&mStartScripts), UniversalId::Type_StartScript); addModel (new IdTable (&mReferenceables, IdTable::Feature_Preview), UniversalId::Type_Referenceable); addModel (new IdTable (&mRefs, IdTable::Feature_ViewCell | IdTable::Feature_Preview), UniversalId::Type_Reference); @@ -615,6 +620,16 @@ CSMWorld::SubCellCollection& CSMWorld::Data::getPathgrids() return mPathgrids; } +const CSMWorld::IdCollection& CSMWorld::Data::getStartScripts() const +{ + return mStartScripts; +} + +CSMWorld::IdCollection& CSMWorld::Data::getStartScripts() +{ + return mStartScripts; +} + const CSMWorld::Resources& CSMWorld::Data::getResources (const UniversalId& id) const { return mResourcesManager.get (id.getType()); @@ -719,6 +734,7 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Messages& messages) case ESM::REC_SNDG: mSoundGens.load (*mReader, mBase); break; case ESM::REC_MGEF: mMagicEffects.load (*mReader, mBase); break; case ESM::REC_PGRD: mPathgrids.load (*mReader, mBase); break; + case ESM::REC_SSCR: mStartScripts.load (*mReader, mBase); break; case ESM::REC_LTEX: mLandTextures.load (*mReader, mBase); break; diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 02f7bc452..298a9be1f 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -80,6 +81,7 @@ namespace CSMWorld SubCellCollection mPathgrids; IdCollection mDebugProfiles; IdCollection mSoundGens; + IdCollection mStartScripts; InfoCollection mTopicInfos; InfoCollection mJournalInfos; IdCollection mCells; @@ -225,6 +227,10 @@ namespace CSMWorld SubCellCollection& getPathgrids(); + const IdCollection& getStartScripts() const; + + IdCollection& getStartScripts(); + /// Throws an exception, if \a id does not match a resources list. const Resources& getResources (const UniversalId& id) const; diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index d19959d44..50ac846db 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -55,6 +55,7 @@ namespace { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_SoundGens, "Sound Generators", 0 }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_MagicEffects, "Magic Effects", 0 }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Pathgrids, "Pathgrids", 0 }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_StartScripts, "Start Scripts", 0 }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0, 0 } // end marker }; @@ -118,6 +119,7 @@ namespace { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_SoundGen, "Sound Generator", 0 }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_MagicEffect, "Magic Effect", 0 }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Pathgrid, "Pathgrid", 0 }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_StartScript, "Start Script", 0 }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0, 0 } // end marker }; diff --git a/apps/opencs/model/world/universalid.hpp b/apps/opencs/model/world/universalid.hpp index ce2d021d0..a716aec03 100644 --- a/apps/opencs/model/world/universalid.hpp +++ b/apps/opencs/model/world/universalid.hpp @@ -128,6 +128,8 @@ namespace CSMWorld Type_MagicEffect, Type_Pathgrids, Type_Pathgrid, + Type_StartScripts, + Type_StartScript, Type_RunLog }; diff --git a/components/esm/loadsscr.cpp b/components/esm/loadsscr.cpp index 9b02b51c9..7380dd0a7 100644 --- a/components/esm/loadsscr.cpp +++ b/components/esm/loadsscr.cpp @@ -41,4 +41,8 @@ namespace ESM esm.writeHNString("NAME", mId); } + void StartScript::blank() + { + mData.clear(); + } } diff --git a/components/esm/loadsscr.hpp b/components/esm/loadsscr.hpp index 954a4a2b6..1420d16c4 100644 --- a/components/esm/loadsscr.hpp +++ b/components/esm/loadsscr.hpp @@ -27,6 +27,8 @@ struct StartScript // Load a record and add it to the list void load(ESMReader &esm); void save(ESMWriter &esm) const; + + void blank(); }; } From a148b851c0294f7222a75d3217311fe0d6c57c63 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 3 Mar 2015 14:32:12 +0100 Subject: [PATCH 0683/3725] added start script table --- apps/opencs/view/doc/view.cpp | 9 +++++++++ apps/opencs/view/doc/view.hpp | 2 ++ apps/opencs/view/world/subviews.cpp | 2 ++ 3 files changed, 13 insertions(+) diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 9117a6d03..211f74187 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -173,6 +173,10 @@ void CSVDoc::View::setupMechanicsMenu() QAction *effects = new QAction (tr ("Magic Effects"), this); connect (effects, SIGNAL (triggered()), this, SLOT (addMagicEffectsSubView())); mechanics->addAction (effects); + + QAction *startScripts = new QAction (tr ("Start Scripts"), this); + connect (startScripts, SIGNAL (triggered()), this, SLOT (addStartScriptsSubView())); + mechanics->addAction (startScripts); } void CSVDoc::View::setupCharacterMenu() @@ -716,6 +720,11 @@ void CSVDoc::View::addPathgridSubView() addSubView (CSMWorld::UniversalId::Type_Pathgrids); } +void CSVDoc::View::addStartScriptsSubView() +{ + addSubView (CSMWorld::UniversalId::Type_StartScripts); +} + void CSVDoc::View::abortOperation (int type) { mDocument->abortOperation (type); diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index 55ea5ee51..baadca85c 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -215,6 +215,8 @@ namespace CSVDoc void addPathgridSubView(); + void addStartScriptsSubView(); + void toggleShowStatusBar (bool show); void loadErrorLog(); diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp index c5d969d0d..5e01ef283 100644 --- a/apps/opencs/view/world/subviews.cpp +++ b/apps/opencs/view/world/subviews.cpp @@ -43,6 +43,7 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) CSMWorld::UniversalId::Type_BodyParts, CSMWorld::UniversalId::Type_SoundGens, CSMWorld::UniversalId::Type_Pathgrids, + CSMWorld::UniversalId::Type_StartScripts, CSMWorld::UniversalId::Type_None // end marker }; @@ -123,6 +124,7 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) CSMWorld::UniversalId::Type_BodyPart, CSMWorld::UniversalId::Type_SoundGen, CSMWorld::UniversalId::Type_Pathgrid, + CSMWorld::UniversalId::Type_StartScript, CSMWorld::UniversalId::Type_None // end marker }; From 1ed606065c13677d87be2bc97b1a76697c3c53de Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 3 Mar 2015 16:11:00 +0100 Subject: [PATCH 0684/3725] save start script records --- apps/opencs/model/doc/saving.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/opencs/model/doc/saving.cpp b/apps/opencs/model/doc/saving.cpp index 70e9e1d87..b52186a47 100644 --- a/apps/opencs/model/doc/saving.cpp +++ b/apps/opencs/model/doc/saving.cpp @@ -78,6 +78,9 @@ CSMDoc::Saving::Saving (Document& document, const boost::filesystem::path& proje appendStage (new WriteCollectionStage > (mDocument.getData().getMagicEffects(), mState)); + appendStage (new WriteCollectionStage > + (mDocument.getData().getStartScripts(), mState)); + appendStage (new WriteDialogueCollectionStage (mDocument, mState, false)); appendStage (new WriteDialogueCollectionStage (mDocument, mState, true)); From d01e8cc97d290fc59486a1a3a0e086fce57776aa Mon Sep 17 00:00:00 2001 From: Scott Howard Date: Tue, 3 Mar 2015 17:36:22 -0500 Subject: [PATCH 0685/3725] PositionCell/PlaceItemCell: add console message if cell doesn't exist --- apps/openmw/mwscript/transformationextensions.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 9166bf909..734df7d74 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -316,6 +316,7 @@ namespace MWScript store = MWBase::Environment::get().getWorld()->getExterior(cx,cy); if(!cell) { + runtime.getContext().report ("unknown cell (" + cellID + ")"); std::cerr << "unknown cell (" << cellID << ")\n"; } } @@ -428,6 +429,7 @@ namespace MWScript store = MWBase::Environment::get().getWorld()->getExterior(cx,cy); if(!cell) { + runtime.getContext().report ("unknown cell (" + cellID + ")"); std::cerr << "unknown cell (" << cellID << ")\n"; } } From 8931ddf42804ccb4139a367e8389657a65c02447 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Mar 2015 23:46:53 +0100 Subject: [PATCH 0686/3725] Remove unneeded casts --- apps/openmw/mwscript/aiextensions.cpp | 5 +-- apps/openmw/mwscript/controlextensions.cpp | 5 +-- apps/openmw/mwscript/miscextensions.cpp | 48 ++++++---------------- apps/openmw/mwscript/skyextensions.cpp | 5 +-- 4 files changed, 16 insertions(+), 47 deletions(-) diff --git a/apps/openmw/mwscript/aiextensions.cpp b/apps/openmw/mwscript/aiextensions.cpp index a3f935487..163aedf76 100644 --- a/apps/openmw/mwscript/aiextensions.cpp +++ b/apps/openmw/mwscript/aiextensions.cpp @@ -466,12 +466,9 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { - InterpreterContext& context - = static_cast (runtime.getContext()); - bool enabled = MWBase::Environment::get().getMechanicsManager()->toggleAI(); - context.report (enabled ? "AI -> On" : "AI -> Off"); + runtime.getContext().report (enabled ? "AI -> On" : "AI -> Off"); } }; diff --git a/apps/openmw/mwscript/controlextensions.cpp b/apps/openmw/mwscript/controlextensions.cpp index fd7fe4737..904e0ee85 100644 --- a/apps/openmw/mwscript/controlextensions.cpp +++ b/apps/openmw/mwscript/controlextensions.cpp @@ -65,12 +65,9 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { - InterpreterContext& context - = static_cast (runtime.getContext()); - bool enabled = MWBase::Environment::get().getWorld()->toggleCollisionMode(); - context.report (enabled ? "Collision -> On" : "Collision -> Off"); + runtime.getContext().report (enabled ? "Collision -> On" : "Collision -> Off"); } }; diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 52094947c..507b27807 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -212,13 +212,10 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { - InterpreterContext& context = - static_cast (runtime.getContext()); - bool enabled = MWBase::Environment::get().getWorld()->toggleRenderMode (MWBase::World::Render_CollisionDebug); - context.report (enabled ? + runtime.getContext().report (enabled ? "Collision Mesh Rendering -> On" : "Collision Mesh Rendering -> Off"); } }; @@ -230,13 +227,10 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { - InterpreterContext& context = - static_cast (runtime.getContext()); - bool enabled = MWBase::Environment::get().getWorld()->toggleRenderMode (MWBase::World::Render_BoundingBoxes); - context.report (enabled ? + runtime.getContext().report (enabled ? "Bounding Box Rendering -> On" : "Bounding Box Rendering -> Off"); } }; @@ -247,13 +241,10 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { - InterpreterContext& context = - static_cast (runtime.getContext()); - bool enabled = MWBase::Environment::get().getWorld()->toggleRenderMode (MWBase::World::Render_Wireframe); - context.report (enabled ? + runtime.getContext().report (enabled ? "Wireframe Rendering -> On" : "Wireframe Rendering -> Off"); } }; @@ -263,13 +254,10 @@ namespace MWScript public: virtual void execute (Interpreter::Runtime& runtime) { - InterpreterContext& context = - static_cast (runtime.getContext()); - bool enabled = MWBase::Environment::get().getWorld()->toggleRenderMode (MWBase::World::Render_Pathgrid); - context.report (enabled ? + runtime.getContext().report (enabled ? "Path Grid rendering -> On" : "Path Grid Rendering -> Off"); } }; @@ -386,17 +374,14 @@ namespace MWScript virtual void execute(Interpreter::Runtime &runtime) { - InterpreterContext& context = - static_cast (runtime.getContext()); - MWBase::World *world = MWBase::Environment::get().getWorld(); if (world->toggleVanityMode(sActivate)) { - context.report(sActivate ? "Vanity Mode -> On" : "Vanity Mode -> Off"); + runtime.getContext().report(sActivate ? "Vanity Mode -> On" : "Vanity Mode -> Off"); sActivate = !sActivate; } else { - context.report("Vanity Mode -> No"); + runtime.getContext().report("Vanity Mode -> No"); } } }; @@ -862,14 +847,11 @@ namespace MWScript void printGlobalVars(Interpreter::Runtime &runtime) { - InterpreterContext& context = - static_cast (runtime.getContext()); - std::stringstream str; str<< "Global variables:"; MWBase::World *world = MWBase::Environment::get().getWorld(); - std::vector names = context.getGlobals(); + std::vector names = runtime.getContext().getGlobals(); for(size_t i = 0;i < names.size();++i) { char type = world->getGlobalVariableType (names[i]); @@ -879,17 +861,17 @@ namespace MWScript { case 's': - str << context.getGlobalShort (names[i]) << " (short)"; + str << runtime.getContext().getGlobalShort (names[i]) << " (short)"; break; case 'l': - str << context.getGlobalLong (names[i]) << " (long)"; + str << runtime.getContext().getGlobalLong (names[i]) << " (long)"; break; case 'f': - str << context.getGlobalFloat (names[i]) << " (float)"; + str << runtime.getContext().getGlobalFloat (names[i]) << " (float)"; break; default: @@ -898,7 +880,7 @@ namespace MWScript } } - context.report (str.str()); + runtime.getContext().report (str.str()); } public: @@ -920,11 +902,9 @@ namespace MWScript public: virtual void execute (Interpreter::Runtime& runtime) { - InterpreterContext& context = static_cast (runtime.getContext()); - bool enabled = MWBase::Environment::get().getWorld()->toggleScripts(); - context.report(enabled ? "Scripts -> On" : "Scripts -> Off"); + runtime.getContext().report(enabled ? "Scripts -> On" : "Scripts -> Off"); } }; @@ -933,11 +913,9 @@ namespace MWScript public: virtual void execute (Interpreter::Runtime& runtime) { - InterpreterContext& context = static_cast (runtime.getContext()); - bool enabled = MWBase::Environment::get().getWorld()->toggleGodMode(); - context.report (enabled ? "God Mode -> On" : "God Mode -> Off"); + runtime.getContext().report (enabled ? "God Mode -> On" : "God Mode -> Off"); } }; diff --git a/apps/openmw/mwscript/skyextensions.cpp b/apps/openmw/mwscript/skyextensions.cpp index 0ccd0ce31..d28d01b63 100644 --- a/apps/openmw/mwscript/skyextensions.cpp +++ b/apps/openmw/mwscript/skyextensions.cpp @@ -25,10 +25,7 @@ namespace MWScript { bool enabled = MWBase::Environment::get().getWorld()->toggleSky(); - InterpreterContext& context = - static_cast (runtime.getContext()); - - context.report (enabled ? "Sky -> On" : "Sky -> Off"); + runtime.getContext().report (enabled ? "Sky -> On" : "Sky -> Off"); } }; From cced508916b2dd9201ca468d2629862fd42b9daf Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 4 Mar 2015 01:49:00 +0100 Subject: [PATCH 0687/3725] Remove unintended 1.5 factor for damage/restore magic effects --- apps/openmw/mwmechanics/actors.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index aa2cc8615..d91d54f6f 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -519,8 +519,8 @@ namespace MWMechanics effects.get(EffectKey(ESM::MagicEffect::DrainAttribute, i)).getMagnitude(), effects.get(EffectKey(ESM::MagicEffect::AbsorbAttribute, i)).getMagnitude()); - stat.damage(effects.get(EffectKey(ESM::MagicEffect::DamageAttribute, i)).getMagnitude() * duration * 1.5); - stat.restore(effects.get(EffectKey(ESM::MagicEffect::RestoreAttribute, i)).getMagnitude() * duration * 1.5); + stat.damage(effects.get(EffectKey(ESM::MagicEffect::DamageAttribute, i)).getMagnitude() * duration); + stat.restore(effects.get(EffectKey(ESM::MagicEffect::RestoreAttribute, i)).getMagnitude() * duration); creatureStats.setAttribute(i, stat); } @@ -786,8 +786,8 @@ namespace MWMechanics effects.get(EffectKey(ESM::MagicEffect::DrainSkill, i)).getMagnitude(), effects.get(EffectKey(ESM::MagicEffect::AbsorbSkill, i)).getMagnitude()); - skill.damage(effects.get(EffectKey(ESM::MagicEffect::DamageSkill, i)).getMagnitude() * duration * 1.5); - skill.restore(effects.get(EffectKey(ESM::MagicEffect::RestoreSkill, i)).getMagnitude() * duration * 1.5); + skill.damage(effects.get(EffectKey(ESM::MagicEffect::DamageSkill, i)).getMagnitude() * duration); + skill.restore(effects.get(EffectKey(ESM::MagicEffect::RestoreSkill, i)).getMagnitude() * duration); } } From 80fe24207c17c5294627ba745ef9c6c5c9ca3447 Mon Sep 17 00:00:00 2001 From: dteviot Date: Thu, 5 Mar 2015 20:21:22 +1300 Subject: [PATCH 0688/3725] correction from Scrawl. Now correctly handles skills/attributes. Also, document what ContentSelectorView::ContentSelector::slotAddonTableItemActivated() is doing. --- apps/openmw/mwmechanics/activespells.cpp | 2 +- components/contentselector/view/contentselector.cpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/activespells.cpp b/apps/openmw/mwmechanics/activespells.cpp index eec4f2bd3..b4701126b 100644 --- a/apps/openmw/mwmechanics/activespells.cpp +++ b/apps/openmw/mwmechanics/activespells.cpp @@ -185,7 +185,7 @@ namespace MWMechanics bool missing = true; for (std::vector::const_iterator iter(addTo.begin()); iter != addTo.end(); ++iter) { - if (effect->mEffectId == iter->mEffectId) + if ((effect->mEffectId == iter->mEffectId) && (effect->mArg == iter->mArg)) { missing = false; break; diff --git a/components/contentselector/view/contentselector.cpp b/components/contentselector/view/contentselector.cpp index 2363ae477..e3093d568 100644 --- a/components/contentselector/view/contentselector.cpp +++ b/components/contentselector/view/contentselector.cpp @@ -183,6 +183,7 @@ void ContentSelectorView::ContentSelector::setGameFileSelected(int index, bool s void ContentSelectorView::ContentSelector::slotAddonTableItemActivated(const QModelIndex &index) { + // toggles check state when an AddOn file is double clicked or activated by keyboard QModelIndex sourceIndex = mAddonProxyModel->mapToSource (index); if (!mContentModel->isEnabled (sourceIndex)) From 0b70fdac578329481507696a98070927b9f4cb73 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 5 Mar 2015 11:24:01 +0100 Subject: [PATCH 0689/3725] added start script verifier --- apps/opencs/CMakeLists.txt | 1 + apps/opencs/model/tools/startscriptcheck.cpp | 31 ++++++++++++++++++++ apps/opencs/model/tools/startscriptcheck.hpp | 28 ++++++++++++++++++ apps/opencs/model/tools/tools.cpp | 3 ++ 4 files changed, 63 insertions(+) create mode 100644 apps/opencs/model/tools/startscriptcheck.cpp create mode 100644 apps/opencs/model/tools/startscriptcheck.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 1d6b40d5f..d2d745cc2 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -40,6 +40,7 @@ opencs_units (model/tools opencs_units_noqt (model/tools mandatoryid skillcheck classcheck factioncheck racecheck soundcheck regioncheck birthsigncheck spellcheck referencecheck referenceablecheck scriptcheck bodypartcheck + startscriptcheck ) diff --git a/apps/opencs/model/tools/startscriptcheck.cpp b/apps/opencs/model/tools/startscriptcheck.cpp new file mode 100644 index 000000000..e3c01368b --- /dev/null +++ b/apps/opencs/model/tools/startscriptcheck.cpp @@ -0,0 +1,31 @@ + +#include "startscriptcheck.hpp" + +#include + +CSMTools::StartScriptCheckStage::StartScriptCheckStage ( + const CSMWorld::IdCollection& startScripts, + const CSMWorld::IdCollection& scripts) +: mStartScripts (startScripts), mScripts (scripts) +{} + +void CSMTools::StartScriptCheckStage::perform(int stage, CSMDoc::Messages& messages) +{ + const CSMWorld::Record& record = mStartScripts.getRecord (stage); + + if (record.isDeleted()) + return; + + std::string scriptId = record.get().mId; + + CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_StartScript, scriptId); + + if (mScripts.searchId (Misc::StringUtils::lowerCase (scriptId))==-1) + messages.push_back ( + std::make_pair (id, "Start script " + scriptId + " does not exist")); +} + +int CSMTools::StartScriptCheckStage::setup() +{ + return mStartScripts.getSize(); +} diff --git a/apps/opencs/model/tools/startscriptcheck.hpp b/apps/opencs/model/tools/startscriptcheck.hpp new file mode 100644 index 000000000..cb82cbae7 --- /dev/null +++ b/apps/opencs/model/tools/startscriptcheck.hpp @@ -0,0 +1,28 @@ +#ifndef CSM_TOOLS_STARTSCRIPTCHECK_H +#define CSM_TOOLS_STARTSCRIPTCHECK_H + +#include +#include + +#include "../doc/stage.hpp" + +#include "../world/idcollection.hpp" + +namespace CSMTools +{ + class StartScriptCheckStage : public CSMDoc::Stage + { + const CSMWorld::IdCollection& mStartScripts; + const CSMWorld::IdCollection& mScripts; + + public: + + StartScriptCheckStage (const CSMWorld::IdCollection& startScripts, + const CSMWorld::IdCollection& scripts); + + virtual void perform(int stage, CSMDoc::Messages& messages); + virtual int setup(); + }; +} + +#endif diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index e78758bb6..2139f890f 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -24,6 +24,7 @@ #include "scriptcheck.hpp" #include "bodypartcheck.hpp" #include "referencecheck.hpp" +#include "startscriptcheck.hpp" CSMDoc::Operation *CSMTools::Tools::get (int type) { @@ -84,6 +85,8 @@ CSMDoc::Operation *CSMTools::Tools::getVerifier() mVerifier->appendStage (new ScriptCheckStage (mDocument)); + mVerifier->appendStage (new StartScriptCheckStage (mData.getStartScripts(), mData.getScripts())); + mVerifier->appendStage( new BodyPartCheckStage( mData.getBodyParts(), From c7cd576002512e41a8675145549418d8c265943d Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 5 Mar 2015 23:12:47 +0100 Subject: [PATCH 0690/3725] Remove leftover of old tests --- libs/openengine/testall.sh | 11 ----------- 1 file changed, 11 deletions(-) delete mode 100755 libs/openengine/testall.sh diff --git a/libs/openengine/testall.sh b/libs/openengine/testall.sh deleted file mode 100755 index 097fdabd5..000000000 --- a/libs/openengine/testall.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash - -function run() -{ - echo "TESTING $1" - cd "$1/tests/" - ./test.sh - cd ../../ -} - -run input From d28f257adac9b7fa52c165f66f5f60837d39df64 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Fri, 6 Mar 2015 11:53:46 +1100 Subject: [PATCH 0691/3725] Fix for bug #2428. Set default flag value (mandatory) for containers. --- components/esm/loadcont.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esm/loadcont.cpp b/components/esm/loadcont.cpp index 999c3f92a..3481189c3 100644 --- a/components/esm/loadcont.cpp +++ b/components/esm/loadcont.cpp @@ -87,7 +87,7 @@ namespace ESM mModel.clear(); mScript.clear(); mWeight = 0; - mFlags = 0; + mFlags = 0x8; // set default flag value mInventory.mList.clear(); } } From 0fda1cdd53b44c7d909b4e594fab409718d61896 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 6 Mar 2015 00:56:37 +0100 Subject: [PATCH 0692/3725] Move oengine to a static library, fixes duplicate compilation of oengine/bullet files by openmw and opencs --- CMakeLists.txt | 42 +++---------------- apps/opencs/CMakeLists.txt | 5 ++- apps/openmw/CMakeLists.txt | 5 +-- extern/sdl4ogre/CMakeLists.txt | 1 + .../ogre => extern/sdl4ogre}/imagerotate.cpp | 6 ++- .../ogre => extern/sdl4ogre}/imagerotate.hpp | 6 +-- extern/sdl4ogre/sdlcursormanager.cpp | 4 +- libs/openengine/CMakeLists.txt | 33 +++++++++++++++ 8 files changed, 53 insertions(+), 49 deletions(-) rename {libs/openengine/ogre => extern/sdl4ogre}/imagerotate.cpp (99%) rename {libs/openengine/ogre => extern/sdl4ogre}/imagerotate.hpp (94%) create mode 100644 libs/openengine/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index 2ed6d6e17..27ea78331 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -97,43 +97,6 @@ endif() # We probably support older versions than this. cmake_minimum_required(VERSION 2.6) -# source directory: libs - -set(LIBS_DIR ${CMAKE_SOURCE_DIR}/libs) - -set(OENGINE_OGRE - ${LIBS_DIR}/openengine/ogre/renderer.cpp - ${LIBS_DIR}/openengine/ogre/lights.cpp - ${LIBS_DIR}/openengine/ogre/selectionbuffer.cpp - ${LIBS_DIR}/openengine/ogre/imagerotate.cpp -) - -set(OENGINE_GUI - ${LIBS_DIR}/openengine/gui/loglistener.cpp - ${LIBS_DIR}/openengine/gui/manager.cpp - ${LIBS_DIR}/openengine/gui/layout.cpp -) - -set(OENGINE_BULLET - ${LIBS_DIR}/openengine/bullet/BtOgre.cpp - ${LIBS_DIR}/openengine/bullet/BtOgreExtras.h - ${LIBS_DIR}/openengine/bullet/BtOgreGP.h - ${LIBS_DIR}/openengine/bullet/BtOgrePG.h - ${LIBS_DIR}/openengine/bullet/physic.cpp - ${LIBS_DIR}/openengine/bullet/physic.hpp - ${LIBS_DIR}/openengine/bullet/BulletShapeLoader.cpp - ${LIBS_DIR}/openengine/bullet/BulletShapeLoader.h - ${LIBS_DIR}/openengine/bullet/trace.cpp - ${LIBS_DIR}/openengine/bullet/trace.h - -) - -set(OENGINE_ALL ${OENGINE_OGRE} ${OENGINE_GUI} ${OENGINE_BULLET}) -source_group(libs\\openengine FILES ${OENGINE_ALL}) - -set(OPENMW_LIBS ${OENGINE_ALL}) -set(OPENMW_LIBS_HEADER) - # Sound setup set(FFmpeg_FIND_COMPONENTS AVCODEC AVFORMAT AVUTIL SWSCALE SWRESAMPLE AVRESAMPLE) unset(FFMPEG_LIBRARIES CACHE) @@ -275,6 +238,7 @@ include_directories("." ${MYGUI_INCLUDE_DIRS} ${MYGUI_PLATFORM_INCLUDE_DIRS} ${OPENAL_INCLUDE_DIR} + ${BULLET_INCLUDE_DIRS} ${LIBS_DIR} ) @@ -572,6 +536,10 @@ if(WIN32) include(CPack) endif(WIN32) +# Libs +include_directories(libs) +add_subdirectory(libs/openengine) + # Extern add_subdirectory (extern/shiny) add_subdirectory (extern/ogre-ffmpeg-videoplayer) diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 1d6b40d5f..3ea611694 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -164,7 +164,8 @@ qt4_wrap_ui(OPENCS_UI_HDR ${OPENCS_UI}) qt4_wrap_cpp(OPENCS_MOC_SRC ${OPENCS_HDR_QT}) qt4_add_resources(OPENCS_RES_SRC ${OPENCS_RES}) -include_directories(${CMAKE_CURRENT_BINARY_DIR} ${BULLET_INCLUDE_DIRS}) +# for compiled .ui files +include_directories(${CMAKE_CURRENT_BINARY_DIR}) if(APPLE) set (OPENCS_MAC_ICON ${CMAKE_SOURCE_DIR}/files/mac/openmw-cs.icns) @@ -174,7 +175,6 @@ endif(APPLE) add_executable(openmw-cs MACOSX_BUNDLE - ${OENGINE_BULLET} ${OPENCS_SRC} ${OPENCS_UI_HDR} ${OPENCS_MOC_SRC} @@ -198,6 +198,7 @@ if(APPLE) endif(APPLE) target_link_libraries(openmw-cs + ${OENGINE_LIBRARY} ${OGRE_LIBRARIES} ${OGRE_Overlay_LIBRARIES} ${OGRE_STATIC_PLUGINS} diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index eabbb7577..860cc2fcb 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -104,7 +104,6 @@ find_package(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS}) if (NOT ANDROID) add_executable(openmw - ${OPENMW_LIBS} ${OPENMW_LIBS_HEADER} ${OPENMW_FILES} ${GAME} ${GAME_HEADER} ${APPLE_BUNDLE_RESOURCES} @@ -112,7 +111,6 @@ if (NOT ANDROID) else () add_library(openmw SHARED - ${OPENMW_LIBS} ${OPENMW_LIBS_HEADER} ${OPENMW_FILES} ${GAME} ${GAME_HEADER} ) @@ -120,9 +118,10 @@ endif () # Sound stuff - here so CMake doesn't stupidly recompile EVERYTHING # when we change the backend. -include_directories(${SOUND_INPUT_INCLUDES} ${BULLET_INCLUDE_DIRS}) +include_directories(${SOUND_INPUT_INCLUDES}) target_link_libraries(openmw + ${OENGINE_LIBRARY} ${OGRE_LIBRARIES} ${OGRE_STATIC_PLUGINS} ${SHINY_LIBRARIES} diff --git a/extern/sdl4ogre/CMakeLists.txt b/extern/sdl4ogre/CMakeLists.txt index 86ce7b70e..b8c56bd00 100644 --- a/extern/sdl4ogre/CMakeLists.txt +++ b/extern/sdl4ogre/CMakeLists.txt @@ -6,6 +6,7 @@ set(SDL4OGRE_SOURCE_FILES sdlinputwrapper.cpp sdlcursormanager.cpp sdlwindowhelper.cpp + imagerotate.cpp ) if (APPLE) diff --git a/libs/openengine/ogre/imagerotate.cpp b/extern/sdl4ogre/imagerotate.cpp similarity index 99% rename from libs/openengine/ogre/imagerotate.cpp rename to extern/sdl4ogre/imagerotate.cpp index cc5f572cf..b825943fc 100644 --- a/libs/openengine/ogre/imagerotate.cpp +++ b/extern/sdl4ogre/imagerotate.cpp @@ -17,7 +17,9 @@ #include using namespace Ogre; -using namespace OEngine::Render; + +namespace SFO +{ void ImageRotate::rotate(const std::string& sourceImage, const std::string& destImage, const float angle) { @@ -93,3 +95,5 @@ void ImageRotate::rotate(const std::string& sourceImage, const std::string& dest root->destroySceneManager(sceneMgr); delete rect; } + +} diff --git a/libs/openengine/ogre/imagerotate.hpp b/extern/sdl4ogre/imagerotate.hpp similarity index 94% rename from libs/openengine/ogre/imagerotate.hpp rename to extern/sdl4ogre/imagerotate.hpp index a3f6d662f..7135a571a 100644 --- a/libs/openengine/ogre/imagerotate.hpp +++ b/extern/sdl4ogre/imagerotate.hpp @@ -3,9 +3,8 @@ #include -namespace OEngine -{ -namespace Render + +namespace SFO { /// Rotate an image by certain degrees and save as file, uses the GPU @@ -22,6 +21,5 @@ namespace Render }; } -} #endif diff --git a/extern/sdl4ogre/sdlcursormanager.cpp b/extern/sdl4ogre/sdlcursormanager.cpp index 7623d57db..61508a64e 100644 --- a/extern/sdl4ogre/sdlcursormanager.cpp +++ b/extern/sdl4ogre/sdlcursormanager.cpp @@ -7,7 +7,7 @@ #include #include -#include +#include "imagerotate.hpp" namespace SFO { @@ -91,7 +91,7 @@ namespace SFO // we use a render target to uncompress the DDS texture // just blitting doesn't seem to work on D3D9 - OEngine::Render::ImageRotate::rotate(tex->getName(), tempName, -rotDegrees); + ImageRotate::rotate(tex->getName(), tempName, -rotDegrees); Ogre::TexturePtr resultTexture = Ogre::TextureManager::getSingleton().getByName(tempName); diff --git a/libs/openengine/CMakeLists.txt b/libs/openengine/CMakeLists.txt new file mode 100644 index 000000000..7a0a791d1 --- /dev/null +++ b/libs/openengine/CMakeLists.txt @@ -0,0 +1,33 @@ +set(OENGINE_OGRE + ogre/renderer.cpp + ogre/lights.cpp + ogre/selectionbuffer.cpp +) + +set(OENGINE_GUI + gui/loglistener.cpp + gui/manager.cpp + gui/layout.cpp +) + +set(OENGINE_BULLET + bullet/BtOgre.cpp + bullet/BtOgreExtras.h + bullet/BtOgreGP.h + bullet/BtOgrePG.h + bullet/physic.cpp + bullet/physic.hpp + bullet/BulletShapeLoader.cpp + bullet/BulletShapeLoader.h + bullet/trace.cpp + bullet/trace.h +) + +set(OENGINE_ALL ${OENGINE_OGRE} ${OENGINE_GUI} ${OENGINE_BULLET}) + +set(OENGINE_LIBRARY "oengine") +set(OENGINE_LIBRARY ${OENGINE_LIBRARY} PARENT_SCOPE) + +source_group(oengine FILES ${OENGINE_ALL}) + +add_library(${OENGINE_LIBRARY} STATIC ${OENGINE_ALL}) From 5a47b7ae6e50e581b5f55eac9b9d2cf9cefda363 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 6 Mar 2015 00:57:26 +0100 Subject: [PATCH 0693/3725] Warning fix --- extern/ogre-ffmpeg-videoplayer/audiodecoder.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extern/ogre-ffmpeg-videoplayer/audiodecoder.cpp b/extern/ogre-ffmpeg-videoplayer/audiodecoder.cpp index cfc6c17b9..1a56802da 100644 --- a/extern/ogre-ffmpeg-videoplayer/audiodecoder.cpp +++ b/extern/ogre-ffmpeg-videoplayer/audiodecoder.cpp @@ -222,7 +222,7 @@ int MovieAudioDecoder::audio_decode_frame(AVFrame *frame, int &sample_skip) } /* if update, update the audio clock w/pts */ - if((uint64_t)pkt->pts != AV_NOPTS_VALUE) + if(pkt->pts != AV_NOPTS_VALUE) mAudioClock = av_q2d(mAVStream->time_base)*pkt->pts; } } From 6d6ff8c6a47e102679b40c388b7dbf099c07cbba Mon Sep 17 00:00:00 2001 From: cc9cii Date: Fri, 6 Mar 2015 14:36:13 +1100 Subject: [PATCH 0694/3725] Resolved compile issues, but not fully working. --- apps/opencs/model/world/idtable.cpp | 26 ++++++------ apps/opencs/view/world/dialoguesubview.cpp | 46 +++++++++++----------- apps/opencs/view/world/dialoguesubview.hpp | 8 ++-- apps/opencs/view/world/nestedtable.cpp | 8 ++-- apps/opencs/view/world/nestedtable.hpp | 14 +++---- 5 files changed, 51 insertions(+), 51 deletions(-) diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 2852cb581..fc8ac66b7 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -31,7 +31,7 @@ int CSMWorld::IdTable::columnCount (const QModelIndex & parent) const { return dynamic_cast(mIdCollection)->getNestedColumnsCount(parent.row(), parent.column()); } - + return mIdCollection->getColumns(); } @@ -72,7 +72,7 @@ QVariant CSMWorld::IdTable::headerData (int section, { return mIdCollection->getColumn (section).mDisplayType; } - + return QVariant(); } @@ -104,7 +104,7 @@ bool CSMWorld::IdTable::setData (const QModelIndex &index, const QVariant &value const std::pair& parentAdress(unfoldIndexAdress(index.internalId())); dynamic_cast(mIdCollection)->setNestedData(parentAdress.first, parentAdress.second, value, index.row(), index.column()); - + emit dataChanged (CSMWorld::IdTable::index (parentAdress.first, 0), CSMWorld::IdTable::index (parentAdress.second, mIdCollection->getColumns()-1)); @@ -114,17 +114,17 @@ bool CSMWorld::IdTable::setData (const QModelIndex &index, const QVariant &value return false; } } - + if (mIdCollection->getColumn (index.column()).isEditable() && role==Qt::EditRole) { mIdCollection->setData (index.row(), index.column(), value); - + emit dataChanged (CSMWorld::IdTable::index (index.row(), 0), CSMWorld::IdTable::index (index.row(), mIdCollection->getColumns()-1)); - + return true; - } - + } + return false; } @@ -177,7 +177,7 @@ void CSMWorld::IdTable::addNestedRow(const QModelIndex& parent, int position) dynamic_cast(mIdCollection)->addNestedRow(row, parent.column(), position); endInsertRows(); - + emit dataChanged (CSMWorld::IdTable::index (row, 0), CSMWorld::IdTable::index (row, mIdCollection->getColumns()-1)); } @@ -353,7 +353,7 @@ std::pair< int, int > CSMWorld::IdTable::unfoldIndexAdress (unsigned int id) con --id; int row = id / this->columnCount(); int column = id - row * this->columnCount(); - return std::make_pair(row, column); + return std::make_pair (row, column); } bool CSMWorld::IdTable::hasChildren(const QModelIndex& index) const @@ -370,14 +370,14 @@ void CSMWorld::IdTable::setNestedTable(const QModelIndex& index, const CSMWorld: { throw std::logic_error("Tried to set nested table, but index has no children"); } - + bool removeRowsMode = false; if (nestedTable.size() != this->nestedTable(index)->size()) { emit resetStart(this->index(index.row(), 0).data().toString()); removeRowsMode = true; } - + dynamic_cast(mIdCollection)->setNestedTable(index.row(), index.column(), nestedTable); emit dataChanged (CSMWorld::IdTable::index (index.row(), 0), @@ -395,6 +395,6 @@ CSMWorld::NestedTableWrapperBase* CSMWorld::IdTable::nestedTable(const QModelInd { throw std::logic_error("Tried to retrive nested table, but index has no children"); } - + return dynamic_cast(mIdCollection)->nestedTable(index.row(), index.column()); } diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index f6ad79a6a..a2b6f45f1 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -281,7 +281,7 @@ QWidget* CSVWorld::DialogueDelegateDispatcher::makeEditor(CSMWorld::ColumnBase:: connect(proxy, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*)), this, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*))); - skip = true; + //skip = true; } else if (qobject_cast(editor)) { @@ -298,7 +298,7 @@ QWidget* CSVWorld::DialogueDelegateDispatcher::makeEditor(CSMWorld::ColumnBase:: else if (qobject_cast(editor)) { connect(editor, SIGNAL(editingFinished()), proxy, SLOT(editorDataCommited())); - } //lisp cond pairs would be nice in the C++ + } connect(proxy, SIGNAL(editorDataCommited(QWidget*, const QModelIndex&, CSMWorld::ColumnBase::Display)), this, SLOT(editorDataCommited(QWidget*, const QModelIndex&, CSMWorld::ColumnBase::Display))); @@ -328,8 +328,8 @@ CSVWorld::EditWidget::~EditWidget() } } -CSVWorld::EditWidget::EditWidget(QWidget *parent, int row, CSMWorld::IdTable* table, QUndoStack& undoStack, bool createAndDelete) : -mDispatcher(this, table, undoStack), +CSVWorld::EditWidget::EditWidget(QWidget *parent, int row, CSMWorld::IdTable* table, CSMDoc::Document& document, bool createAndDelete) : +mDispatcher(this, table, document), QScrollArea(parent), mWidgetMapper(NULL), mMainWidget(NULL), @@ -338,7 +338,7 @@ mTable(table) { remake (row); - connect(&mDispatcher, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*)), + connect(&mDispatcher, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*)), this, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*))); } @@ -349,7 +349,7 @@ void CSVWorld::EditWidget::remake(int row) delete mNestedModels[i]; } mNestedModels.clear(); - + if (mMainWidget) { delete mMainWidget; @@ -401,8 +401,8 @@ void CSVWorld::EditWidget::remake(int row) if (mTable->hasChildren(mTable->index(row, i))) { mNestedModels.push_back(new CSMWorld::NestedTableModel (mTable->index(row, i), display, mTable)); - - NestedTable* table = new NestedTable(mUndoStack, *(mNestedModels.rbegin()), this); + + NestedTable* table = new NestedTable(mDocument, *(mNestedModels.rbegin()), this); tablesLayout->addWidget(table); } else @@ -517,7 +517,7 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSM mMainLayout = new QVBoxLayout(mainWidget); - mEditWidget = new EditWidget(mainWidget, mTable->getModelIndex(mCurrentId, 0).row(), mTable, mUndoStack, false); + mEditWidget = new EditWidget(mainWidget, mTable->getModelIndex(mCurrentId, 0).row(), mTable, document, false); connect(mEditWidget, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*)), this, SLOT(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*))); @@ -570,7 +570,7 @@ void CSVWorld::DialogueSubView::prevId () setUniversalId(CSMWorld::UniversalId (static_cast (mTable->data (mTable->index (newRow, 2)).toInt()), mTable->data (mTable->index (newRow, 0)).toString().toUtf8().constData())); - changeCurrentId(std::string(mTable->data (mTable->index (newRow, 0)).toString().toUtf8().constData())); + changeCurrentId(std::string(mTable->data (mTable->index (newRow, 0)).toString().toUtf8().constData())); mEditWidget->setDisabled(mLocked); @@ -604,9 +604,9 @@ void CSVWorld::DialogueSubView::nextId () mEditWidget->remake(newRow); setUniversalId(CSMWorld::UniversalId (static_cast (mTable->data (mTable->index (newRow, 2)).toInt()), - mTable->data (mTable->index (newRow, 0)).toString().toUtf8().constData())); + mTable->data (mTable->index (newRow, 0)).toString().toUtf8().constData())); - changeCurrentId(std::string(mTable->data (mTable->index (newRow, 0)).toString().toUtf8().constData())); + changeCurrentId(std::string(mTable->data (mTable->index (newRow, 0)).toString().toUtf8().constData())); mEditWidget->setDisabled(mLocked); @@ -623,11 +623,11 @@ void CSVWorld::DialogueSubView::setEditLock (bool locked) if (currentIndex.isValid()) { - CSMWorld::RecordBase::State state = static_cast(mTable->data (mTable->index (currentIndex.row(), 1)).toInt()); + CSMWorld::RecordBase::State state = static_cast(mTable->data (mTable->index (currentIndex.row(), 1)).toInt()); - mEditWidget->setDisabled (state==CSMWorld::RecordBase::State_Deleted || locked); + mEditWidget->setDisabled (state==CSMWorld::RecordBase::State_Deleted || locked); - mCommandDispatcher.setEditLock (locked); + mCommandDispatcher.setEditLock (locked); } } @@ -640,14 +640,14 @@ void CSVWorld::DialogueSubView::dataChanged (const QModelIndex & index) { CSMWorld::RecordBase::State state = static_cast(mTable->data (mTable->index (currentIndex.row(), 1)).toInt()); - mEditWidget->setDisabled (state==CSMWorld::RecordBase::State_Deleted || mLocked); + mEditWidget->setDisabled (state==CSMWorld::RecordBase::State_Deleted || mLocked); } } void CSVWorld::DialogueSubView::tableMimeDataDropped (QWidget* editor, - const QModelIndex& index, - const CSMWorld::UniversalId& id, - const CSMDoc::Document* document) + const QModelIndex& index, + const CSMWorld::UniversalId& id, + const CSMDoc::Document* document) { if (document == &mDocument) { @@ -672,10 +672,10 @@ void CSVWorld::DialogueSubView::showPreview () QModelIndex currentIndex(mTable->getModelIndex(mCurrentId, 0)); if (currentIndex.isValid() && - mTable->getFeatures() & CSMWorld::IdTable::Feature_Preview && - currentIndex.row() < mTable->rowCount()) + mTable->getFeatures() & CSMWorld::IdTable::Feature_Preview && + currentIndex.row() < mTable->rowCount()) { - emit focusId(CSMWorld::UniversalId(CSMWorld::UniversalId::Type_Preview, mCurrentId), ""); + emit focusId(CSMWorld::UniversalId(CSMWorld::UniversalId::Type_Preview, mCurrentId), ""); } } @@ -684,7 +684,7 @@ void CSVWorld::DialogueSubView::viewRecord () QModelIndex currentIndex(mTable->getModelIndex (mCurrentId, 0)); if (currentIndex.isValid() && - currentIndex.row() < mTable->rowCount()) + currentIndex.row() < mTable->rowCount()) { std::pair params = mTable->view (currentIndex.row()); diff --git a/apps/opencs/view/world/dialoguesubview.hpp b/apps/opencs/view/world/dialoguesubview.hpp index 3f48aef42..45581bc3f 100644 --- a/apps/opencs/view/world/dialoguesubview.hpp +++ b/apps/opencs/view/world/dialoguesubview.hpp @@ -118,12 +118,12 @@ namespace CSVWorld NotEditableSubDelegate mNotEditableDelegate; std::vector mProxys; -//once we move to the C++11 we should use unique_ptr + //once we move to the C++11 we should use unique_ptr public: DialogueDelegateDispatcher(QObject* parent, CSMWorld::IdTable* table, - QUndoStack& undoStack); + CSMDoc::Document& document); ~DialogueDelegateDispatcher(); @@ -175,10 +175,10 @@ namespace CSVWorld public: EditWidget (QWidget *parent, int row, CSMWorld::IdTable* table, - QUndoStack& undoStack, bool createAndDelete = false); + CSMDoc::Document& document, bool createAndDelete = false); virtual ~EditWidget(); - + void remake(int row); signals: diff --git a/apps/opencs/view/world/nestedtable.cpp b/apps/opencs/view/world/nestedtable.cpp index 21bef504b..14e079c98 100644 --- a/apps/opencs/view/world/nestedtable.cpp +++ b/apps/opencs/view/world/nestedtable.cpp @@ -9,11 +9,11 @@ #include #include -CSVWorld::NestedTable::NestedTable(QUndoStack& undoStack, +CSVWorld::NestedTable::NestedTable(CSMDoc::Document& document, CSMWorld::NestedTableModel* model, QWidget* parent) : QTableView(parent), - mUndoStack(undoStack), + mUndoStack(document.getUndoStack()), mModel(model) { @@ -31,9 +31,9 @@ CSVWorld::NestedTable::NestedTable(QUndoStack& undoStack, model->headerData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Display).toInt()); CommandDelegate *delegate = CommandDelegateFactoryCollection::get().makeDelegate(display, - undoStack, + document, this); - + setItemDelegateForColumn(i, delegate); } diff --git a/apps/opencs/view/world/nestedtable.hpp b/apps/opencs/view/world/nestedtable.hpp index 35fa22494..6b6b6aaba 100644 --- a/apps/opencs/view/world/nestedtable.hpp +++ b/apps/opencs/view/world/nestedtable.hpp @@ -29,23 +29,23 @@ namespace CSVWorld QAction *mRemoveRowAction; QUndoStack& mUndoStack; CSMWorld::NestedTableModel* mModel; - + public: - NestedTable(QUndoStack& undoStack, + NestedTable(CSMDoc::Document& document, CSMWorld::NestedTableModel* model, QWidget* parent = NULL); - + protected: void dragEnterEvent(QDragEnterEvent *event); - + void dragMoveEvent(QDragMoveEvent *event); - + private: void contextMenuEvent (QContextMenuEvent *event); - + private slots: void removeRowActionTriggered(); - + void addNewRowActionTriggered(); }; } From 727b68dd15472a2a647966db85bd2d1d6b931b90 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Fri, 6 Mar 2015 19:20:50 +1100 Subject: [PATCH 0695/3725] Reduce difference with the master branch where possible. --- apps/opencs/CMakeLists.txt | 5 +-- apps/opencs/model/doc/document.cpp | 5 ++- apps/opencs/model/tools/startscriptcheck.cpp | 31 +++++++++++++++++++ apps/opencs/model/tools/startscriptcheck.hpp | 28 +++++++++++++++++ apps/opencs/model/tools/tools.cpp | 3 ++ apps/opencs/model/world/collection.hpp | 4 +-- apps/opencs/model/world/collectionbase.cpp | 3 +- apps/opencs/model/world/columnimp.hpp | 1 - apps/opencs/view/world/enumdelegate.cpp | 1 + apps/opencs/view/world/util.cpp | 2 +- apps/openmw/mwmechanics/activespells.cpp | 2 +- .../mwscript/transformationextensions.cpp | 2 ++ .../contentselector/view/contentselector.cpp | 1 + 13 files changed, 75 insertions(+), 13 deletions(-) create mode 100644 apps/opencs/model/tools/startscriptcheck.cpp create mode 100644 apps/opencs/model/tools/startscriptcheck.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index ab3765bb6..2125deeff 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -19,7 +19,7 @@ opencs_hdrs_noqt (model/doc opencs_units (model/world idtable idtableproxymodel regionmap data commanddispatcher - idtablebase resourcetable nestedtablemodel + idtablebase resourcetable nestedtablemodel ) @@ -41,6 +41,7 @@ opencs_units (model/tools opencs_units_noqt (model/tools mandatoryid skillcheck classcheck factioncheck racecheck soundcheck regioncheck birthsigncheck spellcheck referencecheck referenceablecheck scriptcheck bodypartcheck + startscriptcheck ) @@ -64,7 +65,7 @@ opencs_units (view/world cellcreator referenceablecreator referencecreator scenesubview infocreator scriptedit dialoguesubview previewsubview regionmap dragrecordtable nestedtable ) - + opencs_units_noqt (view/world subviews enumdelegate vartypedelegate recordstatusdelegate idtypedelegate datadisplaydelegate scripthighlighter idvalidator dialoguecreator physicssystem diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 61fe4b322..e688a9474 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -2,7 +2,6 @@ #include #include -#include #include @@ -2243,7 +2242,7 @@ void CSMDoc::Document::createBase() record.blank(); getData().getMagicEffects().add (record); -} + } } CSMDoc::Document::Document (const Files::ConfigurationManager& configuration, @@ -2265,7 +2264,7 @@ CSMDoc::Document::Document (const Files::ConfigurationManager& configuration, { boost::filesystem::path customFiltersPath (configuration.getUserDataPath()); customFiltersPath /= "defaultfilters"; - + std::ofstream destination (mProjectPath.string().c_str(), std::ios::binary); if (boost::filesystem::exists (customFiltersPath)) diff --git a/apps/opencs/model/tools/startscriptcheck.cpp b/apps/opencs/model/tools/startscriptcheck.cpp new file mode 100644 index 000000000..e3c01368b --- /dev/null +++ b/apps/opencs/model/tools/startscriptcheck.cpp @@ -0,0 +1,31 @@ + +#include "startscriptcheck.hpp" + +#include + +CSMTools::StartScriptCheckStage::StartScriptCheckStage ( + const CSMWorld::IdCollection& startScripts, + const CSMWorld::IdCollection& scripts) +: mStartScripts (startScripts), mScripts (scripts) +{} + +void CSMTools::StartScriptCheckStage::perform(int stage, CSMDoc::Messages& messages) +{ + const CSMWorld::Record& record = mStartScripts.getRecord (stage); + + if (record.isDeleted()) + return; + + std::string scriptId = record.get().mId; + + CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_StartScript, scriptId); + + if (mScripts.searchId (Misc::StringUtils::lowerCase (scriptId))==-1) + messages.push_back ( + std::make_pair (id, "Start script " + scriptId + " does not exist")); +} + +int CSMTools::StartScriptCheckStage::setup() +{ + return mStartScripts.getSize(); +} diff --git a/apps/opencs/model/tools/startscriptcheck.hpp b/apps/opencs/model/tools/startscriptcheck.hpp new file mode 100644 index 000000000..cb82cbae7 --- /dev/null +++ b/apps/opencs/model/tools/startscriptcheck.hpp @@ -0,0 +1,28 @@ +#ifndef CSM_TOOLS_STARTSCRIPTCHECK_H +#define CSM_TOOLS_STARTSCRIPTCHECK_H + +#include +#include + +#include "../doc/stage.hpp" + +#include "../world/idcollection.hpp" + +namespace CSMTools +{ + class StartScriptCheckStage : public CSMDoc::Stage + { + const CSMWorld::IdCollection& mStartScripts; + const CSMWorld::IdCollection& mScripts; + + public: + + StartScriptCheckStage (const CSMWorld::IdCollection& startScripts, + const CSMWorld::IdCollection& scripts); + + virtual void perform(int stage, CSMDoc::Messages& messages); + virtual int setup(); + }; +} + +#endif diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index e78758bb6..2139f890f 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -24,6 +24,7 @@ #include "scriptcheck.hpp" #include "bodypartcheck.hpp" #include "referencecheck.hpp" +#include "startscriptcheck.hpp" CSMDoc::Operation *CSMTools::Tools::get (int type) { @@ -84,6 +85,8 @@ CSMDoc::Operation *CSMTools::Tools::getVerifier() mVerifier->appendStage (new ScriptCheckStage (mDocument)); + mVerifier->appendStage (new StartScriptCheckStage (mData.getStartScripts(), mData.getScripts())); + mVerifier->appendStage( new BodyPartCheckStage( mData.getBodyParts(), diff --git a/apps/opencs/model/world/collection.hpp b/apps/opencs/model/world/collection.hpp index 5c32e7716..1fb3e1f1d 100644 --- a/apps/opencs/model/world/collection.hpp +++ b/apps/opencs/model/world/collection.hpp @@ -2,13 +2,11 @@ #define CSM_WOLRD_COLLECTION_H #include -#include #include #include #include #include #include -#include #include @@ -94,7 +92,7 @@ namespace CSMWorld virtual void purge(); ///< Remove records that are flagged as erased. - virtual void removeRows (int index, int count); + virtual void removeRows (int index, int count) ; virtual void appendBlankRecord (const std::string& id, UniversalId::Type type = UniversalId::Type_None); diff --git a/apps/opencs/model/world/collectionbase.cpp b/apps/opencs/model/world/collectionbase.cpp index 5b0c359c9..241f198cb 100644 --- a/apps/opencs/model/world/collectionbase.cpp +++ b/apps/opencs/model/world/collectionbase.cpp @@ -2,7 +2,6 @@ #include "collectionbase.hpp" #include -#include #include "columnbase.hpp" @@ -29,4 +28,4 @@ int CSMWorld::CollectionBase::findColumnIndex (Columns::ColumnId id) const throw std::logic_error ("invalid column index"); return index; -} +} \ No newline at end of file diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index dc8edbc51..da14bb495 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -6,7 +6,6 @@ #include #include -#include #include diff --git a/apps/opencs/view/world/enumdelegate.cpp b/apps/opencs/view/world/enumdelegate.cpp index 7c305b1b6..168e5cb0a 100644 --- a/apps/opencs/view/world/enumdelegate.cpp +++ b/apps/opencs/view/world/enumdelegate.cpp @@ -46,6 +46,7 @@ QWidget *CSVWorld::EnumDelegate::createEditor(QWidget *parent, const QModelIndex& index) const { return createEditor(parent, option, index, CSMWorld::ColumnBase::Display_None); + //overloading virtual functions is HARD } QWidget *CSVWorld::EnumDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem& option, diff --git a/apps/opencs/view/world/util.cpp b/apps/opencs/view/world/util.cpp index 11521bb67..c65e12c60 100644 --- a/apps/opencs/view/world/util.cpp +++ b/apps/opencs/view/world/util.cpp @@ -186,7 +186,7 @@ QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleO } case CSMWorld::ColumnBase::Display_Boolean: - + return new QCheckBox(parent); case CSMWorld::ColumnBase::Display_String: diff --git a/apps/openmw/mwmechanics/activespells.cpp b/apps/openmw/mwmechanics/activespells.cpp index eec4f2bd3..b4701126b 100644 --- a/apps/openmw/mwmechanics/activespells.cpp +++ b/apps/openmw/mwmechanics/activespells.cpp @@ -185,7 +185,7 @@ namespace MWMechanics bool missing = true; for (std::vector::const_iterator iter(addTo.begin()); iter != addTo.end(); ++iter) { - if (effect->mEffectId == iter->mEffectId) + if ((effect->mEffectId == iter->mEffectId) && (effect->mArg == iter->mArg)) { missing = false; break; diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 9166bf909..734df7d74 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -316,6 +316,7 @@ namespace MWScript store = MWBase::Environment::get().getWorld()->getExterior(cx,cy); if(!cell) { + runtime.getContext().report ("unknown cell (" + cellID + ")"); std::cerr << "unknown cell (" << cellID << ")\n"; } } @@ -428,6 +429,7 @@ namespace MWScript store = MWBase::Environment::get().getWorld()->getExterior(cx,cy); if(!cell) { + runtime.getContext().report ("unknown cell (" + cellID + ")"); std::cerr << "unknown cell (" << cellID << ")\n"; } } diff --git a/components/contentselector/view/contentselector.cpp b/components/contentselector/view/contentselector.cpp index 2363ae477..e3093d568 100644 --- a/components/contentselector/view/contentselector.cpp +++ b/components/contentselector/view/contentselector.cpp @@ -183,6 +183,7 @@ void ContentSelectorView::ContentSelector::setGameFileSelected(int index, bool s void ContentSelectorView::ContentSelector::slotAddonTableItemActivated(const QModelIndex &index) { + // toggles check state when an AddOn file is double clicked or activated by keyboard QModelIndex sourceIndex = mAddonProxyModel->mapToSource (index); if (!mContentModel->isEnabled (sourceIndex)) From 407cd50890d0949bf774cccb74feb8626055f18c Mon Sep 17 00:00:00 2001 From: dteviot Date: Fri, 6 Mar 2015 21:36:42 +1300 Subject: [PATCH 0696/3725] fixed warning C4099: type name first seen using 'class' now seen using 'struct' --- apps/openmw/mwbase/soundmanager.hpp | 2 +- apps/openmw/mwbase/world.hpp | 2 +- apps/openmw/mwclass/npc.hpp | 2 +- apps/openmw/mwgui/bookpage.cpp | 4 ++-- apps/openmw/mwgui/savegamedialog.hpp | 2 +- apps/openmw/mwgui/tooltips.hpp | 2 +- apps/openmw/mwgui/windowmanagerimp.hpp | 2 +- apps/openmw/mwinput/inputmanagerimp.hpp | 2 +- apps/openmw/mwmechanics/aipackage.hpp | 2 +- apps/openmw/mwmechanics/aisequence.hpp | 2 +- apps/openmw/mwmechanics/aiwander.hpp | 2 +- apps/openmw/mwmechanics/character.hpp | 2 +- apps/openmw/mwmechanics/pathgrid.hpp | 2 +- apps/openmw/mwmechanics/spellcasting.hpp | 2 +- apps/openmw/mwrender/globalmap.hpp | 2 +- apps/openmw/mwrender/localmap.hpp | 2 +- apps/openmw/mwscript/globalscripts.hpp | 2 +- apps/openmw/mwscript/interpretercontext.hpp | 2 +- apps/openmw/mwscript/locals.hpp | 2 +- apps/openmw/mwscript/scriptmanagerimp.hpp | 2 +- apps/openmw/mwsound/openal_output.hpp | 2 +- apps/openmw/mwsound/sound_output.hpp | 2 +- apps/openmw/mwworld/localscripts.hpp | 2 +- apps/openmw/mwworld/ptr.hpp | 2 +- apps/openmw/mwworld/timestamp.hpp | 2 +- components/nif/node.hpp | 2 +- components/nif/recordptr.hpp | 4 ++-- components/nifbullet/bulletnifloader.hpp | 4 ++-- components/nifogre/mesh.hpp | 2 +- 29 files changed, 32 insertions(+), 32 deletions(-) diff --git a/apps/openmw/mwbase/soundmanager.hpp b/apps/openmw/mwbase/soundmanager.hpp index f3381a8fd..e71558de0 100644 --- a/apps/openmw/mwbase/soundmanager.hpp +++ b/apps/openmw/mwbase/soundmanager.hpp @@ -20,7 +20,7 @@ namespace MWWorld namespace MWSound { class Sound; - class Sound_Decoder; + struct Sound_Decoder; typedef boost::shared_ptr DecoderPtr; } diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 9eb272e1b..56f575d3a 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -49,7 +49,7 @@ namespace MWRender namespace MWMechanics { - class Movement; + struct Movement; } namespace MWWorld diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index 9aece7368..c00665eb3 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -5,7 +5,7 @@ namespace ESM { - class GameSetting; + struct GameSetting; } namespace MWClass diff --git a/apps/openmw/mwgui/bookpage.cpp b/apps/openmw/mwgui/bookpage.cpp index c9cfc8c2c..57e171659 100644 --- a/apps/openmw/mwgui/bookpage.cpp +++ b/apps/openmw/mwgui/bookpage.cpp @@ -16,8 +16,8 @@ namespace MWGui { struct TypesetBookImpl; -struct PageDisplay; -struct BookPageImpl; +class PageDisplay; +class BookPageImpl; static bool ucsSpace (int codePoint); static bool ucsLineBreak (int codePoint); diff --git a/apps/openmw/mwgui/savegamedialog.hpp b/apps/openmw/mwgui/savegamedialog.hpp index 11470a20f..2192adbde 100644 --- a/apps/openmw/mwgui/savegamedialog.hpp +++ b/apps/openmw/mwgui/savegamedialog.hpp @@ -6,7 +6,7 @@ namespace MWState { class Character; - class Slot; + struct Slot; } namespace MWGui diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp index 4bd4d88aa..71b4a560f 100644 --- a/apps/openmw/mwgui/tooltips.hpp +++ b/apps/openmw/mwgui/tooltips.hpp @@ -9,7 +9,7 @@ namespace ESM { - class Class; + struct Class; struct Race; } diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 735b02d2d..8417d00bf 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -65,7 +65,7 @@ namespace MWGui class MainMenu; class StatsWindow; class InventoryWindow; - class JournalWindow; + struct JournalWindow; class CharacterCreation; class DragAndDrop; class ToolTips; diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index c533296ff..39091b7b1 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -39,7 +39,7 @@ namespace ICS namespace MyGUI { - class MouseButton; + struct MouseButton; } namespace Files diff --git a/apps/openmw/mwmechanics/aipackage.hpp b/apps/openmw/mwmechanics/aipackage.hpp index 80b48fc37..179ae440b 100644 --- a/apps/openmw/mwmechanics/aipackage.hpp +++ b/apps/openmw/mwmechanics/aipackage.hpp @@ -16,7 +16,7 @@ namespace ESM { namespace AiSequence { - class AiSequence; + struct AiSequence; } } diff --git a/apps/openmw/mwmechanics/aisequence.hpp b/apps/openmw/mwmechanics/aisequence.hpp index e43ce72f1..19f1e1454 100644 --- a/apps/openmw/mwmechanics/aisequence.hpp +++ b/apps/openmw/mwmechanics/aisequence.hpp @@ -15,7 +15,7 @@ namespace ESM { namespace AiSequence { - class AiSequence; + struct AiSequence; } } diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 5e1b41813..54e215cb9 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -17,7 +17,7 @@ namespace ESM { - class Cell; + struct Cell; namespace AiSequence { struct AiWander; diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 8a77494b9..da74b2a33 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -21,7 +21,7 @@ namespace MWRender namespace MWMechanics { -class Movement; +struct Movement; class CreatureStats; enum Priority { diff --git a/apps/openmw/mwmechanics/pathgrid.hpp b/apps/openmw/mwmechanics/pathgrid.hpp index 2742957a6..67fbacded 100644 --- a/apps/openmw/mwmechanics/pathgrid.hpp +++ b/apps/openmw/mwmechanics/pathgrid.hpp @@ -6,7 +6,7 @@ namespace ESM { - class Cell; + struct Cell; } namespace MWWorld diff --git a/apps/openmw/mwmechanics/spellcasting.hpp b/apps/openmw/mwmechanics/spellcasting.hpp index dca4f0192..f50584edf 100644 --- a/apps/openmw/mwmechanics/spellcasting.hpp +++ b/apps/openmw/mwmechanics/spellcasting.hpp @@ -17,7 +17,7 @@ namespace ESM namespace MWMechanics { - class EffectKey; + struct EffectKey; class MagicEffects; ESM::Skill::SkillEnum spellSchoolToSkill(int school); diff --git a/apps/openmw/mwrender/globalmap.hpp b/apps/openmw/mwrender/globalmap.hpp index b3ae85b11..a162ab68f 100644 --- a/apps/openmw/mwrender/globalmap.hpp +++ b/apps/openmw/mwrender/globalmap.hpp @@ -12,7 +12,7 @@ namespace Loading namespace ESM { - class GlobalMap; + struct GlobalMap; } namespace MWRender diff --git a/apps/openmw/mwrender/localmap.hpp b/apps/openmw/mwrender/localmap.hpp index 7cfa38814..014c67f16 100644 --- a/apps/openmw/mwrender/localmap.hpp +++ b/apps/openmw/mwrender/localmap.hpp @@ -14,7 +14,7 @@ namespace MWWorld namespace ESM { - class FogTexture; + struct FogTexture; } namespace MWRender diff --git a/apps/openmw/mwscript/globalscripts.hpp b/apps/openmw/mwscript/globalscripts.hpp index 9f009db98..9b7aa0514 100644 --- a/apps/openmw/mwscript/globalscripts.hpp +++ b/apps/openmw/mwscript/globalscripts.hpp @@ -21,7 +21,7 @@ namespace Loading namespace MWWorld { - struct ESMStore; + class ESMStore; } namespace MWScript diff --git a/apps/openmw/mwscript/interpretercontext.hpp b/apps/openmw/mwscript/interpretercontext.hpp index 698df62c2..d3841befd 100644 --- a/apps/openmw/mwscript/interpretercontext.hpp +++ b/apps/openmw/mwscript/interpretercontext.hpp @@ -20,7 +20,7 @@ namespace MWInput namespace MWScript { - struct Locals; + class Locals; class InterpreterContext : public Interpreter::Context { diff --git a/apps/openmw/mwscript/locals.hpp b/apps/openmw/mwscript/locals.hpp index bd95835ac..a9fcf317c 100644 --- a/apps/openmw/mwscript/locals.hpp +++ b/apps/openmw/mwscript/locals.hpp @@ -7,7 +7,7 @@ namespace ESM { - struct Script; + class Script; struct Locals; } diff --git a/apps/openmw/mwscript/scriptmanagerimp.hpp b/apps/openmw/mwscript/scriptmanagerimp.hpp index 6026f6aba..e4a123b86 100644 --- a/apps/openmw/mwscript/scriptmanagerimp.hpp +++ b/apps/openmw/mwscript/scriptmanagerimp.hpp @@ -16,7 +16,7 @@ namespace MWWorld { - struct ESMStore; + class ESMStore; } namespace Compiler diff --git a/apps/openmw/mwsound/openal_output.hpp b/apps/openmw/mwsound/openal_output.hpp index be12bfbec..1a95d6150 100644 --- a/apps/openmw/mwsound/openal_output.hpp +++ b/apps/openmw/mwsound/openal_output.hpp @@ -69,7 +69,7 @@ namespace MWSound OpenAL_Output(SoundManager &mgr); virtual ~OpenAL_Output(); - class StreamThread; + struct StreamThread; std::auto_ptr mStreamThread; friend class OpenAL_Sound; diff --git a/apps/openmw/mwsound/sound_output.hpp b/apps/openmw/mwsound/sound_output.hpp index a9a999a5c..4f5c210bb 100644 --- a/apps/openmw/mwsound/sound_output.hpp +++ b/apps/openmw/mwsound/sound_output.hpp @@ -13,7 +13,7 @@ namespace MWSound { class SoundManager; - class Sound_Decoder; + struct Sound_Decoder; class Sound; class Sound_Output diff --git a/apps/openmw/mwworld/localscripts.hpp b/apps/openmw/mwworld/localscripts.hpp index 840243fff..9d612cb33 100644 --- a/apps/openmw/mwworld/localscripts.hpp +++ b/apps/openmw/mwworld/localscripts.hpp @@ -8,7 +8,7 @@ namespace MWWorld { - struct ESMStore; + class ESMStore; class CellStore; class RefData; diff --git a/apps/openmw/mwworld/ptr.hpp b/apps/openmw/mwworld/ptr.hpp index 4d928dacf..c97d2e6d1 100644 --- a/apps/openmw/mwworld/ptr.hpp +++ b/apps/openmw/mwworld/ptr.hpp @@ -12,7 +12,7 @@ namespace MWWorld { class ContainerStore; class CellStore; - class LiveCellRefBase; + struct LiveCellRefBase; /// \brief Pointer to a LiveCellRef diff --git a/apps/openmw/mwworld/timestamp.hpp b/apps/openmw/mwworld/timestamp.hpp index 54cd40baf..36d11cee0 100644 --- a/apps/openmw/mwworld/timestamp.hpp +++ b/apps/openmw/mwworld/timestamp.hpp @@ -3,7 +3,7 @@ namespace ESM { - class TimeStamp; + struct TimeStamp; } namespace MWWorld diff --git a/components/nif/node.hpp b/components/nif/node.hpp index a26480d59..e6edf6432 100644 --- a/components/nif/node.hpp +++ b/components/nif/node.hpp @@ -14,7 +14,7 @@ namespace Nif { -class NiNode; +struct NiNode; /** A Node is an object that's part of the main NIF tree. It has parent node (unless it's the root), and transformation (location diff --git a/components/nif/recordptr.hpp b/components/nif/recordptr.hpp index 5eac277d0..25beaf098 100644 --- a/components/nif/recordptr.hpp +++ b/components/nif/recordptr.hpp @@ -122,10 +122,10 @@ class Controller; class Controlled; class NiSkinData; class NiFloatData; -class NiMorphData; +struct NiMorphData; class NiPixelData; class NiColorData; -class NiKeyframeData; +struct NiKeyframeData; class NiTriShapeData; class NiSkinInstance; class NiSourceTexture; diff --git a/components/nifbullet/bulletnifloader.hpp b/components/nifbullet/bulletnifloader.hpp index 56d98834d..0d81d84b6 100644 --- a/components/nifbullet/bulletnifloader.hpp +++ b/components/nifbullet/bulletnifloader.hpp @@ -38,8 +38,8 @@ namespace Nif { class Node; - class Transformation; - class NiTriShape; + struct Transformation; + struct NiTriShape; } namespace NifBullet diff --git a/components/nifogre/mesh.hpp b/components/nifogre/mesh.hpp index 731e49c90..69b3f2f78 100644 --- a/components/nifogre/mesh.hpp +++ b/components/nifogre/mesh.hpp @@ -10,7 +10,7 @@ namespace Nif { - class NiTriShape; + struct NiTriShape; } namespace NifOgre From 45b6538820482abef35f6ea0d4efb409fbde6d60 Mon Sep 17 00:00:00 2001 From: dteviot Date: Fri, 6 Mar 2015 23:19:57 +1300 Subject: [PATCH 0697/3725] fixed MSVC 2013 warning C4800 forcing value to bool 'true' or 'false' --- apps/esmtool/record.cpp | 4 +-- apps/essimporter/convertacdt.cpp | 6 ++-- apps/essimporter/importcellref.cpp | 2 +- apps/mwiniimporter/main.cpp | 2 +- apps/openmw/mwclass/apparatus.cpp | 2 +- apps/openmw/mwclass/creature.cpp | 8 ++--- apps/openmw/mwclass/ingredient.cpp | 2 +- apps/openmw/mwclass/light.cpp | 4 +-- apps/openmw/mwclass/lockpick.cpp | 2 +- apps/openmw/mwclass/misc.cpp | 2 +- apps/openmw/mwclass/npc.cpp | 2 +- apps/openmw/mwclass/potion.cpp | 2 +- apps/openmw/mwclass/probe.cpp | 2 +- apps/openmw/mwclass/repair.cpp | 2 +- apps/openmw/mwgui/spellcreationdialog.cpp | 4 +-- apps/openmw/mwgui/widgets.cpp | 2 +- apps/openmw/mwgui/windowmanagerimp.cpp | 8 ++--- apps/openmw/mwgui/windowmanagerimp.hpp | 2 +- apps/openmw/mwinput/inputmanagerimp.cpp | 2 +- apps/openmw/mwmechanics/alchemy.cpp | 2 +- apps/openmw/mwmechanics/creaturestats.cpp | 2 +- apps/openmw/mwmechanics/levelledlist.hpp | 2 +- apps/openmw/mwmechanics/spellcasting.cpp | 2 +- apps/openmw/mwrender/npcanimation.cpp | 4 +-- apps/openmw/mwscript/miscextensions.cpp | 2 +- apps/openmw/mwworld/refdata.cpp | 2 +- components/esm/aipackage.hpp | 2 +- components/esm/aisequence.hpp | 2 +- components/esm/loadcrea.cpp | 2 +- components/esm/loadnpc.cpp | 2 +- components/esm/loadstat.cpp | 2 +- components/nif/data.hpp | 4 +-- components/nifogre/ogrenifloader.cpp | 38 +++++++++++++---------- components/terrain/material.hpp | 2 +- extern/sdl4ogre/sdlinputwrapper.cpp | 4 +-- libs/openengine/bullet/physic.cpp | 6 ++-- libs/openengine/bullet/physic.hpp | 2 +- 37 files changed, 73 insertions(+), 69 deletions(-) diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index 6fd4b80fb..9e4b1496b 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -15,8 +15,8 @@ void printAIPackage(ESM::AIPackage p) std::cout << " Distance: " << p.mWander.mDistance << std::endl; std::cout << " Duration: " << p.mWander.mDuration << std::endl; std::cout << " Time of Day: " << (int)p.mWander.mTimeOfDay << std::endl; - if (p.mWander.mShouldRepeat != 1) - std::cout << " Should repeat: " << (bool)p.mWander.mShouldRepeat << std::endl; + if (!p.mWander.mShouldRepeat) + std::cout << " Should repeat: " << p.mWander.mShouldRepeat << std::endl; std::cout << " Idle: "; for (int i = 0; i != 8; i++) diff --git a/apps/essimporter/convertacdt.cpp b/apps/essimporter/convertacdt.cpp index 718403a8c..91dd8ef23 100644 --- a/apps/essimporter/convertacdt.cpp +++ b/apps/essimporter/convertacdt.cpp @@ -28,13 +28,13 @@ namespace ESSImport cStats.mAttributes[i].mCurrent = acdt.mAttributes[i][0]; } cStats.mGoldPool = acdt.mGoldPool; - cStats.mTalkedTo = acdt.mFlags & TalkedToPlayer; - cStats.mAttacked = acdt.mFlags & Attacked; + cStats.mTalkedTo = (acdt.mFlags & TalkedToPlayer) != 0; + cStats.mAttacked = (acdt.mFlags & Attacked) != 0; } void convertACSC (const ACSC& acsc, ESM::CreatureStats& cStats) { - cStats.mDead = acsc.mFlags & Dead; + cStats.mDead = (acsc.mFlags & Dead) != 0; } void convertNpcData (const ActorData& actorData, ESM::NpcStats& npcStats) diff --git a/apps/essimporter/importcellref.cpp b/apps/essimporter/importcellref.cpp index cca356b2a..442a7781c 100644 --- a/apps/essimporter/importcellref.cpp +++ b/apps/essimporter/importcellref.cpp @@ -43,7 +43,7 @@ namespace ESSImport { unsigned int deleted; esm.getHT(deleted); - mDeleted = (deleted >> 24) & 0x2; // the other 3 bytes seem to be uninitialized garbage + mDeleted = ((deleted >> 24) & 0x2) != 0; // the other 3 bytes seem to be uninitialized garbage } if (esm.isNextSub("MVRF")) diff --git a/apps/mwiniimporter/main.cpp b/apps/mwiniimporter/main.cpp index 3c48fedc9..a3f115fcf 100644 --- a/apps/mwiniimporter/main.cpp +++ b/apps/mwiniimporter/main.cpp @@ -110,7 +110,7 @@ int wmain(int argc, wchar_t *wargv[]) { std::cerr << "cfg file does not exist" << std::endl; MwIniImporter importer; - importer.setVerbose(vm.count("verbose")); + importer.setVerbose(vm.count("verbose") != 0); // Font encoding settings std::string encoding(vm["encoding"].as()); diff --git a/apps/openmw/mwclass/apparatus.cpp b/apps/openmw/mwclass/apparatus.cpp index 316ba3ab6..2abd071bd 100644 --- a/apps/openmw/mwclass/apparatus.cpp +++ b/apps/openmw/mwclass/apparatus.cpp @@ -155,7 +155,7 @@ namespace MWClass bool Apparatus::canSell (const MWWorld::Ptr& item, int npcServices) const { - return npcServices & ESM::NPC::Apparatus; + return (npcServices & ESM::NPC::Apparatus) != 0; } float Apparatus::getWeight(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index e44f4ffc1..c59f8428c 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -164,7 +164,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); MWRender::Actors& actors = renderingInterface.getActors(); - actors.insertCreature(ptr, model, ref->mBase->mFlags & ESM::Creature::Weapon); + actors.insertCreature(ptr, model, (ref->mBase->mFlags & ESM::Creature::Weapon) != 0); } void Creature::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const @@ -493,7 +493,7 @@ namespace MWClass { MWWorld::LiveCellRef *ref = ptr.get(); - return (ref->mBase->mFlags & ESM::Creature::Weapon); + return (ref->mBase->mFlags & ESM::Creature::Weapon) != 0; } std::string Creature::getScript (const MWWorld::Ptr& ptr) const @@ -508,7 +508,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->mBase->mFlags & ESM::Creature::Essential; + return (ref->mBase->mFlags & ESM::Creature::Essential) != 0; } void Creature::registerSelf() @@ -713,7 +713,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->mBase->mFlags & ESM::Creature::Flies; + return (ref->mBase->mFlags & ESM::Creature::Flies) != 0; } bool Creature::canSwim(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/ingredient.cpp b/apps/openmw/mwclass/ingredient.cpp index 9f662a60e..de43e818e 100644 --- a/apps/openmw/mwclass/ingredient.cpp +++ b/apps/openmw/mwclass/ingredient.cpp @@ -192,7 +192,7 @@ namespace MWClass bool Ingredient::canSell (const MWWorld::Ptr& item, int npcServices) const { - return npcServices & ESM::NPC::Ingredients; + return (npcServices & ESM::NPC::Ingredients) != 0; } diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 35a21b63e..032c40237 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -50,7 +50,7 @@ namespace MWClass assert (ref->mBase != NULL); if(!model.empty()) - physics.addObject(ptr, model, ref->mBase->mData.mFlags & ESM::Light::Carry); + physics.addObject(ptr, model, (ref->mBase->mData.mFlags & ESM::Light::Carry) != 0); if (!ref->mBase->mSound.empty() && !(ref->mBase->mData.mFlags & ESM::Light::OffDefault)) MWBase::Environment::get().getSoundManager()->playSound3D(ptr, ref->mBase->mSound, 1.0, 1.0, @@ -221,7 +221,7 @@ namespace MWClass bool Light::canSell (const MWWorld::Ptr& item, int npcServices) const { - return npcServices & ESM::NPC::Lights; + return (npcServices & ESM::NPC::Lights) != 0; } float Light::getWeight(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index e78c43eee..478c50301 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -173,7 +173,7 @@ namespace MWClass bool Lockpick::canSell (const MWWorld::Ptr& item, int npcServices) const { - return npcServices & ESM::NPC::Picks; + return (npcServices & ESM::NPC::Picks) != 0; } int Lockpick::getItemMaxHealth (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index f9cfd8e0b..f5daafeec 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -259,7 +259,7 @@ namespace MWClass { MWWorld::LiveCellRef *ref = ptr.get(); - return ref->mBase->mData.mIsKey; + return ref->mBase->mData.mIsKey != 0; } } diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 52e5a0a95..d06d7cfe1 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -993,7 +993,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->mBase->mFlags & ESM::NPC::Essential; + return (ref->mBase->mFlags & ESM::NPC::Essential) != 0; } void Npc::registerSelf() diff --git a/apps/openmw/mwclass/potion.cpp b/apps/openmw/mwclass/potion.cpp index bd06f89fc..ee299ab4f 100644 --- a/apps/openmw/mwclass/potion.cpp +++ b/apps/openmw/mwclass/potion.cpp @@ -185,7 +185,7 @@ namespace MWClass bool Potion::canSell (const MWWorld::Ptr& item, int npcServices) const { - return npcServices & ESM::NPC::Potions; + return (npcServices & ESM::NPC::Potions) != 0; } float Potion::getWeight(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index a11725f26..da22e9be6 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -172,7 +172,7 @@ namespace MWClass bool Probe::canSell (const MWWorld::Ptr& item, int npcServices) const { - return npcServices & ESM::NPC::Probes; + return (npcServices & ESM::NPC::Probes) != 0; } int Probe::getItemMaxHealth (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/repair.cpp b/apps/openmw/mwclass/repair.cpp index e9c4ac9b1..c02146f12 100644 --- a/apps/openmw/mwclass/repair.cpp +++ b/apps/openmw/mwclass/repair.cpp @@ -172,7 +172,7 @@ namespace MWClass bool Repair::canSell (const MWWorld::Ptr& item, int npcServices) const { - return npcServices & ESM::NPC::RepairItem; + return (npcServices & ESM::NPC::RepairItem) != 0; } float Repair::getWeight(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index f4c9d021a..2757b7cae 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -114,7 +114,7 @@ namespace MWGui void EditEffectDialog::newEffect (const ESM::MagicEffect *effect) { - bool allowSelf = effect->mData.mFlags & ESM::MagicEffect::CastSelf; + bool allowSelf = (effect->mData.mFlags & ESM::MagicEffect::CastSelf) != 0; bool allowTouch = (effect->mData.mFlags & ESM::MagicEffect::CastTouch) && !mConstantEffect; bool allowTarget = (effect->mData.mFlags & ESM::MagicEffect::CastTarget) && !mConstantEffect; @@ -226,7 +226,7 @@ namespace MWGui // cycle through range types until we find something that's allowed // does not handle the case where nothing is allowed (this should be prevented before opening the Add Effect dialog) - bool allowSelf = mMagicEffect->mData.mFlags & ESM::MagicEffect::CastSelf; + bool allowSelf = (mMagicEffect->mData.mFlags & ESM::MagicEffect::CastSelf) != 0; bool allowTouch = (mMagicEffect->mData.mFlags & ESM::MagicEffect::CastTouch) && !mConstantEffect; bool allowTarget = (mMagicEffect->mData.mFlags & ESM::MagicEffect::CastTarget) && !mConstantEffect; if (mEffect.mRange == ESM::RT_Self && !allowSelf) diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index 26fe31567..79c0f93f0 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -239,7 +239,7 @@ namespace MWGui params.mMagnMin = it->mMagnMin; params.mMagnMax = it->mMagnMax; params.mRange = it->mRange; - params.mIsConstant = (flags & MWEffectList::EF_Constant); + params.mIsConstant = (flags & MWEffectList::EF_Constant) != 0; params.mNoTarget = (flags & MWEffectList::EF_NoTarget); effect->setSpellEffect(params); effects.push_back(effect); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index c74cff31c..bd7e22e7c 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -566,10 +566,10 @@ namespace MWGui // Show the windows we want mMap ->setVisible(eff & GW_Map); - mStatsWindow ->setVisible(eff & GW_Stats); - mInventoryWindow->setVisible(eff & GW_Inventory); + mStatsWindow ->setVisible((eff & GW_Stats) != 0); + mInventoryWindow->setVisible((eff & GW_Inventory) != 0); mInventoryWindow->setGuiMode(mode); - mSpellWindow ->setVisible(eff & GW_Magic); + mSpellWindow ->setVisible((eff & GW_Magic) != 0); break; } case GM_Container: @@ -1301,7 +1301,7 @@ namespace MWGui bool WindowManager::isAllowed (GuiWindow wnd) const { - return mAllowed & wnd; + return (mAllowed & wnd) != 0; } void WindowManager::allow (GuiWindow wnd) diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 8417d00bf..fbbc295b3 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -277,7 +277,7 @@ namespace MWGui virtual void enableRest() { mRestAllowed = true; } virtual bool getRestEnabled(); - virtual bool getJournalAllowed() { return (mAllowed & GW_Magic); } + virtual bool getJournalAllowed() { return (mAllowed & GW_Magic) != 0; } virtual bool getPlayerSleeping(); virtual void wakeUpPlayer(); diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 4212c562b..e84e2c5b3 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -250,7 +250,7 @@ namespace MWInput if (mControlSwitch["playercontrols"]) { if (action == A_Use) - mPlayer->getPlayer().getClass().getCreatureStats(mPlayer->getPlayer()).setAttackingOrSpell(currentValue); + mPlayer->getPlayer().getClass().getCreatureStats(mPlayer->getPlayer()).setAttackingOrSpell(currentValue != 0); else if (action == A_Jump) mAttemptJump = (currentValue == 1.0 && previousValue == 0.0); } diff --git a/apps/openmw/mwmechanics/alchemy.cpp b/apps/openmw/mwmechanics/alchemy.cpp index f3d376a70..6e54b6f83 100644 --- a/apps/openmw/mwmechanics/alchemy.cpp +++ b/apps/openmw/mwmechanics/alchemy.cpp @@ -67,7 +67,7 @@ void MWMechanics::Alchemy::applyTools (int flags, float& value) const { bool magnitude = !(flags & ESM::MagicEffect::NoMagnitude); bool duration = !(flags & ESM::MagicEffect::NoDuration); - bool negative = flags & (ESM::MagicEffect::Harmful); + bool negative = (flags & ESM::MagicEffect::Harmful) != 0; int tool = negative ? ESM::Apparatus::Retort : ESM::Apparatus::Albemic; diff --git a/apps/openmw/mwmechanics/creaturestats.cpp b/apps/openmw/mwmechanics/creaturestats.cpp index 05ea9fb5e..1947ad839 100644 --- a/apps/openmw/mwmechanics/creaturestats.cpp +++ b/apps/openmw/mwmechanics/creaturestats.cpp @@ -439,7 +439,7 @@ namespace MWMechanics bool CreatureStats::getMovementFlag (Flag flag) const { - return mMovementFlags & flag; + return (mMovementFlags & flag) != 0; } void CreatureStats::setMovementFlag (Flag flag, bool state) diff --git a/apps/openmw/mwmechanics/levelledlist.hpp b/apps/openmw/mwmechanics/levelledlist.hpp index 691996410..db13c1a45 100644 --- a/apps/openmw/mwmechanics/levelledlist.hpp +++ b/apps/openmw/mwmechanics/levelledlist.hpp @@ -35,7 +35,7 @@ namespace MWMechanics } // For levelled creatures, the flags are swapped. This file format just makes so much sense. - bool allLevels = levItem->mFlags & ESM::ItemLevList::AllLevels; + bool allLevels = (levItem->mFlags & ESM::ItemLevList::AllLevels) != 0; if (creature) allLevels = levItem->mFlags & ESM::CreatureLevList::AllLevels; diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index b91ea9984..06a3c1dfd 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -573,7 +573,7 @@ namespace MWMechanics castStatic = MWBase::Environment::get().getWorld()->getStore().get().find ("VFX_DefaultHit"); // TODO: VFX are no longer active after saving/reloading the game - bool loop = magicEffect->mData.mFlags & ESM::MagicEffect::ContinuousVfx; + bool loop = (magicEffect->mData.mFlags & ESM::MagicEffect::ContinuousVfx) != 0; // Note: in case of non actor, a free effect should be fine as well MWRender::Animation* anim = MWBase::Environment::get().getWorld()->getAnimation(target); if (anim) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 66ba25859..a2ad1e02c 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -377,7 +377,7 @@ void NpcAnimation::updateParts() }; static const size_t slotlistsize = sizeof(slotlist)/sizeof(slotlist[0]); - bool wasArrowAttached = (mAmmunition.get()); + bool wasArrowAttached = (mAmmunition.get() != NULL); MWWorld::InventoryStore& inv = mPtr.getClass().getInventoryStore(mPtr); for(size_t i = 0;i < slotlistsize && mViewMode != VM_HeadOnly;i++) @@ -941,7 +941,7 @@ void NpcAnimation::permanentEffectAdded(const ESM::MagicEffect *magicEffect, boo if (!magicEffect->mHit.empty()) { const ESM::Static* castStatic = MWBase::Environment::get().getWorld()->getStore().get().find (magicEffect->mHit); - bool loop = magicEffect->mData.mFlags & ESM::MagicEffect::ContinuousVfx; + bool loop = (magicEffect->mData.mFlags & ESM::MagicEffect::ContinuousVfx) != 0; // Don't play particle VFX unless the effect is new or it should be looping. if (isNew || loop) addEffect("meshes\\" + castStatic->mModel, magicEffect->mIndex, loop, ""); diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 52094947c..f69031b2c 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -81,7 +81,7 @@ namespace MWScript std::string name = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); - bool allowSkipping = runtime[0].mInteger; + bool allowSkipping = runtime[0].mInteger != 0; runtime.pop(); MWBase::Environment::get().getWindowManager()->playVideo (name, allowSkipping); diff --git a/apps/openmw/mwworld/refdata.cpp b/apps/openmw/mwworld/refdata.cpp index c2a5e5f83..14a315a81 100644 --- a/apps/openmw/mwworld/refdata.cpp +++ b/apps/openmw/mwworld/refdata.cpp @@ -59,7 +59,7 @@ namespace MWWorld } RefData::RefData (const ESM::ObjectState& objectState) - : mBaseNode (0), mHasLocals (false), mEnabled (objectState.mEnabled), + : mBaseNode (0), mHasLocals (false), mEnabled (objectState.mEnabled != 0), mCount (objectState.mCount), mPosition (objectState.mPosition), mCustomData (0), mChanged(true), // Loading from a savegame -> assume changed mDeleted(false) diff --git a/components/esm/aipackage.hpp b/components/esm/aipackage.hpp index 5e08806c8..b164b3d62 100644 --- a/components/esm/aipackage.hpp +++ b/components/esm/aipackage.hpp @@ -32,7 +32,7 @@ namespace ESM short mDuration; unsigned char mTimeOfDay; unsigned char mIdle[8]; - unsigned char mShouldRepeat; + bool mShouldRepeat; }; struct AITravel diff --git a/components/esm/aisequence.hpp b/components/esm/aisequence.hpp index 2560fbe7d..c2142ab34 100644 --- a/components/esm/aisequence.hpp +++ b/components/esm/aisequence.hpp @@ -44,7 +44,7 @@ namespace ESM short mDuration; unsigned char mTimeOfDay; unsigned char mIdle[8]; - unsigned char mShouldRepeat; + bool mShouldRepeat; }; struct AiTravelData { diff --git a/components/esm/loadcrea.cpp b/components/esm/loadcrea.cpp index 2e9f924b7..86eede34e 100644 --- a/components/esm/loadcrea.cpp +++ b/components/esm/loadcrea.cpp @@ -10,7 +10,7 @@ namespace ESM { void Creature::load(ESMReader &esm) { - mPersistent = esm.getRecordFlags() & 0x0400; + mPersistent = (esm.getRecordFlags() & 0x0400) != 0; mAiPackage.mList.clear(); mInventory.mList.clear(); diff --git a/components/esm/loadnpc.cpp b/components/esm/loadnpc.cpp index d90b4816d..98cedbe42 100644 --- a/components/esm/loadnpc.cpp +++ b/components/esm/loadnpc.cpp @@ -10,7 +10,7 @@ namespace ESM void NPC::load(ESMReader &esm) { - mPersistent = esm.getRecordFlags() & 0x0400; + mPersistent = (esm.getRecordFlags() & 0x0400) != 0; mSpells.mList.clear(); mInventory.mList.clear(); diff --git a/components/esm/loadstat.cpp b/components/esm/loadstat.cpp index 2bb817332..ed90b0475 100644 --- a/components/esm/loadstat.cpp +++ b/components/esm/loadstat.cpp @@ -10,7 +10,7 @@ namespace ESM void Static::load(ESMReader &esm) { - mPersistent = esm.getRecordFlags() & 0x0400; + mPersistent = (esm.getRecordFlags() & 0x0400) != 0; mModel = esm.getHNString("MODL"); } diff --git a/components/nif/data.hpp b/components/nif/data.hpp index d9de12fb5..1fa94d9c2 100644 --- a/components/nif/data.hpp +++ b/components/nif/data.hpp @@ -234,7 +234,7 @@ class NiVisData : public Record public: struct VisData { float time; - char isSet; + bool isSet; }; std::vector mVis; @@ -245,7 +245,7 @@ public: for(size_t i = 0;i < mVis.size();i++) { mVis[i].time = nif->getFloat(); - mVis[i].isSet = nif->getChar(); + mVis[i].isSet = nif->getChar() != 0; } } }; diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 17df7a3cd..0009c9f83 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -379,7 +379,7 @@ public: return mData.back().isSet; } - static void setVisible(Ogre::Node *node, int vis) + static void setVisible(Ogre::Node *node, bool vis) { // Skinned meshes are attached to the scene node, not the bone. // We use the Node's user data to connect it with the mesh. @@ -746,16 +746,17 @@ private: { if (ctrl->flags & Nif::NiNode::ControllerFlag_Active) { + bool isAnimationAutoPlay = (animflags & Nif::NiNode::AnimFlag_AutoPlay) != 0; if(ctrl->recType == Nif::RC_NiUVController) { const Nif::NiUVController *uv = static_cast(ctrl.getPtr()); - Ogre::ControllerValueRealPtr srcval((animflags&Nif::NiNode::AnimFlag_AutoPlay) ? + Ogre::ControllerValueRealPtr srcval(isAnimationAutoPlay ? Ogre::ControllerManager::getSingleton().getFrameTimeSource() : Ogre::ControllerValueRealPtr()); Ogre::ControllerValueRealPtr dstval(OGRE_NEW UVController::Value(entity, uv->data.getPtr(), &scene->mMaterialControllerMgr)); - UVController::Function* function = OGRE_NEW UVController::Function(uv, (animflags&Nif::NiNode::AnimFlag_AutoPlay)); + UVController::Function* function = OGRE_NEW UVController::Function(uv, isAnimationAutoPlay); scene->mMaxControllerLength = std::max(function->mStopTime, scene->mMaxControllerLength); Ogre::ControllerFunctionRealPtr func(function); @@ -765,13 +766,13 @@ private: { const Nif::NiGeomMorpherController *geom = static_cast(ctrl.getPtr()); - Ogre::ControllerValueRealPtr srcval((animflags&Nif::NiNode::AnimFlag_AutoPlay) ? + Ogre::ControllerValueRealPtr srcval(isAnimationAutoPlay ? Ogre::ControllerManager::getSingleton().getFrameTimeSource() : Ogre::ControllerValueRealPtr()); Ogre::ControllerValueRealPtr dstval(OGRE_NEW GeomMorpherController::Value( entity, geom->data.getPtr(), geom->recIndex)); - GeomMorpherController::Function* function = OGRE_NEW GeomMorpherController::Function(geom, (animflags&Nif::NiNode::AnimFlag_AutoPlay)); + GeomMorpherController::Function* function = OGRE_NEW GeomMorpherController::Function(geom, isAnimationAutoPlay); scene->mMaxControllerLength = std::max(function->mStopTime, scene->mMaxControllerLength); Ogre::ControllerFunctionRealPtr func(function); @@ -796,7 +797,8 @@ private: const Nif::NiStencilProperty *stencilprop = NULL; node->getProperties(texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop, stencilprop); - Ogre::ControllerValueRealPtr srcval((animflags&Nif::NiNode::AnimFlag_AutoPlay) ? + bool isAnimationAutoPlay = (animflags & Nif::NiNode::AnimFlag_AutoPlay) != 0; + Ogre::ControllerValueRealPtr srcval(isAnimationAutoPlay ? Ogre::ControllerManager::getSingleton().getFrameTimeSource() : Ogre::ControllerValueRealPtr()); @@ -809,7 +811,7 @@ private: { const Nif::NiAlphaController *alphaCtrl = static_cast(ctrls.getPtr()); Ogre::ControllerValueRealPtr dstval(OGRE_NEW AlphaController::Value(movable, alphaCtrl->data.getPtr(), &scene->mMaterialControllerMgr)); - AlphaController::Function* function = OGRE_NEW AlphaController::Function(alphaCtrl, (animflags&Nif::NiNode::AnimFlag_AutoPlay)); + AlphaController::Function* function = OGRE_NEW AlphaController::Function(alphaCtrl, isAnimationAutoPlay); scene->mMaxControllerLength = std::max(function->mStopTime, scene->mMaxControllerLength); Ogre::ControllerFunctionRealPtr func(function); scene->mControllers.push_back(Ogre::Controller(srcval, dstval, func)); @@ -818,7 +820,7 @@ private: { const Nif::NiMaterialColorController *matCtrl = static_cast(ctrls.getPtr()); Ogre::ControllerValueRealPtr dstval(OGRE_NEW MaterialColorController::Value(movable, matCtrl->data.getPtr(), &scene->mMaterialControllerMgr)); - MaterialColorController::Function* function = OGRE_NEW MaterialColorController::Function(matCtrl, (animflags&Nif::NiNode::AnimFlag_AutoPlay)); + MaterialColorController::Function* function = OGRE_NEW MaterialColorController::Function(matCtrl, isAnimationAutoPlay); scene->mMaxControllerLength = std::max(function->mStopTime, scene->mMaxControllerLength); Ogre::ControllerFunctionRealPtr func(function); scene->mControllers.push_back(Ogre::Controller(srcval, dstval, func)); @@ -839,7 +841,7 @@ private: Ogre::ControllerValueRealPtr dstval(OGRE_NEW FlipController::Value( movable, flipCtrl, &scene->mMaterialControllerMgr)); - FlipController::Function* function = OGRE_NEW FlipController::Function(flipCtrl, (animflags&Nif::NiNode::AnimFlag_AutoPlay)); + FlipController::Function* function = OGRE_NEW FlipController::Function(flipCtrl, isAnimationAutoPlay); scene->mMaxControllerLength = std::max(function->mStopTime, scene->mMaxControllerLength); Ogre::ControllerFunctionRealPtr func(function); scene->mControllers.push_back(Ogre::Controller(srcval, dstval, func)); @@ -967,7 +969,7 @@ private: partsys->setCullIndividually(false); partsys->setParticleQuota(particledata->numParticles); - partsys->setKeepParticlesInLocalSpace(partflags & (Nif::NiNode::ParticleFlag_LocalSpace)); + partsys->setKeepParticlesInLocalSpace((partflags & Nif::NiNode::ParticleFlag_LocalSpace) != 0); int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, partnode->recIndex); Ogre::Bone *trgtbone = scene->mSkelBase->getSkeleton()->getBone(trgtid); @@ -1017,13 +1019,14 @@ private: createParticleInitialState(partsys, particledata, partctrl); - Ogre::ControllerValueRealPtr srcval((partflags&Nif::NiNode::ParticleFlag_AutoPlay) ? + bool isParticleAutoPlay = (partflags&Nif::NiNode::ParticleFlag_AutoPlay) != 0; + Ogre::ControllerValueRealPtr srcval(isParticleAutoPlay ? Ogre::ControllerManager::getSingleton().getFrameTimeSource() : Ogre::ControllerValueRealPtr()); Ogre::ControllerValueRealPtr dstval(OGRE_NEW ParticleSystemController::Value(partsys, partctrl)); ParticleSystemController::Function* function = - OGRE_NEW ParticleSystemController::Function(partctrl, (partflags&Nif::NiNode::ParticleFlag_AutoPlay)); + OGRE_NEW ParticleSystemController::Function(partctrl, isParticleAutoPlay); scene->mMaxControllerLength = std::max(function->mStopTime, scene->mMaxControllerLength); Ogre::ControllerFunctionRealPtr func(function); @@ -1032,7 +1035,7 @@ private: // Emitting state will be overwritten on frame update by the ParticleSystemController, // but set up an initial value anyway so the user can fast-forward particle systems // immediately after creation if desired. - partsys->setEmitting(partflags&Nif::NiNode::ParticleFlag_AutoPlay); + partsys->setEmitting(isParticleAutoPlay); } ctrl = ctrl->next; } @@ -1094,18 +1097,19 @@ private: do { if (ctrl->flags & Nif::NiNode::ControllerFlag_Active) { + bool isAnimationAutoPlay = (animflags & Nif::NiNode::AnimFlag_AutoPlay) != 0; if(ctrl->recType == Nif::RC_NiVisController) { const Nif::NiVisController *vis = static_cast(ctrl.getPtr()); int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, ctrl->target->recIndex); Ogre::Bone *trgtbone = scene->mSkelBase->getSkeleton()->getBone(trgtid); - Ogre::ControllerValueRealPtr srcval((animflags&Nif::NiNode::AnimFlag_AutoPlay) ? + Ogre::ControllerValueRealPtr srcval(isAnimationAutoPlay ? Ogre::ControllerManager::getSingleton().getFrameTimeSource() : Ogre::ControllerValueRealPtr()); Ogre::ControllerValueRealPtr dstval(OGRE_NEW VisController::Value(trgtbone, vis->data.getPtr())); - VisController::Function* function = OGRE_NEW VisController::Function(vis, (animflags&Nif::NiNode::AnimFlag_AutoPlay)); + VisController::Function* function = OGRE_NEW VisController::Function(vis, isAnimationAutoPlay); scene->mMaxControllerLength = std::max(function->mStopTime, scene->mMaxControllerLength); Ogre::ControllerFunctionRealPtr func(function); @@ -1120,11 +1124,11 @@ private: Ogre::Bone *trgtbone = scene->mSkelBase->getSkeleton()->getBone(trgtid); // The keyframe controller will control this bone manually trgtbone->setManuallyControlled(true); - Ogre::ControllerValueRealPtr srcval((animflags&Nif::NiNode::AnimFlag_AutoPlay) ? + Ogre::ControllerValueRealPtr srcval(isAnimationAutoPlay ? Ogre::ControllerManager::getSingleton().getFrameTimeSource() : Ogre::ControllerValueRealPtr()); Ogre::ControllerValueRealPtr dstval(OGRE_NEW KeyframeController::Value(trgtbone, nif, key->data.getPtr())); - KeyframeController::Function* function = OGRE_NEW KeyframeController::Function(key, (animflags&Nif::NiNode::AnimFlag_AutoPlay)); + KeyframeController::Function* function = OGRE_NEW KeyframeController::Function(key, isAnimationAutoPlay); scene->mMaxControllerLength = std::max(function->mStopTime, scene->mMaxControllerLength); Ogre::ControllerFunctionRealPtr func(function); diff --git a/components/terrain/material.hpp b/components/terrain/material.hpp index f35080e7c..b79df9f48 100644 --- a/components/terrain/material.hpp +++ b/components/terrain/material.hpp @@ -35,7 +35,7 @@ namespace Terrain MaterialGenerator (); void setLayerList (const std::vector& layerList) { mLayerList = layerList; } - bool hasLayers() { return mLayerList.size(); } + bool hasLayers() { return mLayerList.size() > 0; } void setBlendmapList (const std::vector& blendmapList) { mBlendmapList = blendmapList; } const std::vector& getBlendmapList() { return mBlendmapList; } void setCompositeMap (const std::string& name) { mCompositeMap = name; } diff --git a/extern/sdl4ogre/sdlinputwrapper.cpp b/extern/sdl4ogre/sdlinputwrapper.cpp index 439c4c131..aaf669ff4 100644 --- a/extern/sdl4ogre/sdlinputwrapper.cpp +++ b/extern/sdl4ogre/sdlinputwrapper.cpp @@ -201,12 +201,12 @@ namespace SFO bool InputWrapper::isModifierHeld(SDL_Keymod mod) { - return SDL_GetModState() & mod; + return (SDL_GetModState() & mod) != 0; } bool InputWrapper::isKeyDown(SDL_Scancode key) { - return SDL_GetKeyboardState(NULL)[key]; + return (SDL_GetKeyboardState(NULL)[key]) != 0; } /// \brief Moves the mouse to the specified point within the viewport diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index b3e9f1395..e0482104a 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -283,14 +283,14 @@ namespace Physic } } - void PhysicEngine::setDebugRenderingMode(int mode) + void PhysicEngine::setDebugRenderingMode(bool isDebug) { if(!isDebugCreated) { createDebugRendering(); } - mDebugDrawer->setDebugMode(mode); - mDebugActive = mode; + mDebugDrawer->setDebugMode(isDebug); + mDebugActive = isDebug; } bool PhysicEngine::toggleDebugRendering() diff --git a/libs/openengine/bullet/physic.hpp b/libs/openengine/bullet/physic.hpp index f497150f9..1a16ff4e8 100644 --- a/libs/openengine/bullet/physic.hpp +++ b/libs/openengine/bullet/physic.hpp @@ -283,7 +283,7 @@ namespace Physic * Set the debug rendering mode. 0 to turn it off. * Important Note: this will crash if the Render is not yet initialise! */ - void setDebugRenderingMode(int mode); + void setDebugRenderingMode(bool isDebug); bool toggleDebugRendering(); From 27f91a83263a6ce1473f4859d9d9c16932d464e6 Mon Sep 17 00:00:00 2001 From: dteviot Date: Thu, 5 Mar 2015 20:21:22 +1300 Subject: [PATCH 0698/3725] correction from Scrawl. Now correctly handles skills/attributes. Also, document what ContentSelectorView::ContentSelector::slotAddonTableItemActivated() is doing. --- apps/openmw/mwmechanics/activespells.cpp | 2 +- components/contentselector/view/contentselector.cpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/activespells.cpp b/apps/openmw/mwmechanics/activespells.cpp index eec4f2bd3..b4701126b 100644 --- a/apps/openmw/mwmechanics/activespells.cpp +++ b/apps/openmw/mwmechanics/activespells.cpp @@ -185,7 +185,7 @@ namespace MWMechanics bool missing = true; for (std::vector::const_iterator iter(addTo.begin()); iter != addTo.end(); ++iter) { - if (effect->mEffectId == iter->mEffectId) + if ((effect->mEffectId == iter->mEffectId) && (effect->mArg == iter->mArg)) { missing = false; break; diff --git a/components/contentselector/view/contentselector.cpp b/components/contentselector/view/contentselector.cpp index 2363ae477..e3093d568 100644 --- a/components/contentselector/view/contentselector.cpp +++ b/components/contentselector/view/contentselector.cpp @@ -183,6 +183,7 @@ void ContentSelectorView::ContentSelector::setGameFileSelected(int index, bool s void ContentSelectorView::ContentSelector::slotAddonTableItemActivated(const QModelIndex &index) { + // toggles check state when an AddOn file is double clicked or activated by keyboard QModelIndex sourceIndex = mAddonProxyModel->mapToSource (index); if (!mContentModel->isEnabled (sourceIndex)) From 900745f577c5f0ce55d354404205891dc2a1bdd4 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 6 Mar 2015 20:05:05 +0100 Subject: [PATCH 0699/3725] updated changelog --- CHANGELOG.md | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c2aa03dc2..8bbee6fe0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,41 @@ +0.35.1 +------ + + Bug #781: incorrect trajectory of the sun + Bug #1079: Wrong starting position in "Character Stuff Wonderland" + Bug #1443: Repetitive taking of a stolen object is repetitively considered as a crime + Bug #1533: Divine Intervention goes to the wrong place. + Bug #1714: No visual indicator for time passed during training + Bug #1916: Telekinesis does not allow safe opening of traps + Bug #2227: Editor: addon file name inconsistency + Bug #2271: Player can melee enemies from water with impunity + Bug #2275: Objects with bigger scale move further using Move script + Bug #2285: Aryon's Dominator enchantment does not work properly + Bug #2290: No punishment for stealing gold from owned containers + Bug #2328: Launcher does not respond to Ctrl+C + Bug #2334: Drag-and-drop on a content file in the launcher creates duplicate items + Bug #2338: Arrows reclaimed from corpses do not stack sometimes + Bug #2344: Launcher - Settings importer running correctly? + Bug #2348: Mod: H.E.L.L.U.V.A. Handy Holdables does not appear in the content list + Bug #2353: Detect Animal detects dead creatures + Bug #2354: Cmake does not respect LIB_SUFFIX + Bug #2356: Active magic set inactive when switching magic items + Bug #2361: ERROR: ESM Error: Previous record contains unread bytes + Bug #2382: Switching spells with "next spell" or "previous spell" while holding shift promps delete spell dialog + Bug #2388: Regression: Can't toggle map on/off + Bug #2392: MOD Shrines - Restore Health and Cancel Options adds 100 health points + Bug #2394: List of Data Files tab in openmw-laucher needs to show all content files. + Bug #2402: Editor: skills saved incorrectly + Bug #2408: Equipping a constant effect Restore Health/Magicka/Fatigue item will permanently boost the stat it's restoring + Bug #2415: It is now possible to fall off the prison ship into the water when starting a new game + Bug #2419: MOD MCA crash to desktop + Bug #2420: Game crashes when character enters a certain area + Bug #2421: infinite loop when using cycle weapon without having a weapon + Feature #2221: Cannot dress dead NPCs + Feature #2349: Check CMake sets correct MSVC compiler settings for release build. + Feature #2397: Set default values for global mandatory records. + Feature #2412: Basic joystick support + 0.35.0 ------ From f2ac939e61e60d106165b4ba98f723b63909ebfa Mon Sep 17 00:00:00 2001 From: dteviot Date: Sat, 7 Mar 2015 11:04:54 +1300 Subject: [PATCH 0700/3725] reverted mShouldRepeat back to unsigned char. As recommended by Scrawl. --- apps/esmtool/record.cpp | 4 ++-- apps/openmw/mwgui/windowmanagerimp.cpp | 2 +- apps/openmw/mwmechanics/aisequence.cpp | 2 +- apps/openmw/mwmechanics/aiwander.cpp | 2 +- components/esm/aipackage.hpp | 2 +- components/esm/aisequence.hpp | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index 9e4b1496b..be9b03e80 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -15,8 +15,8 @@ void printAIPackage(ESM::AIPackage p) std::cout << " Distance: " << p.mWander.mDistance << std::endl; std::cout << " Duration: " << p.mWander.mDuration << std::endl; std::cout << " Time of Day: " << (int)p.mWander.mTimeOfDay << std::endl; - if (!p.mWander.mShouldRepeat) - std::cout << " Should repeat: " << p.mWander.mShouldRepeat << std::endl; + if (p.mWander.mShouldRepeat != 1) + std::cout << " Should repeat: " << (bool)(p.mWander.mShouldRepeat != 0) << std::endl; std::cout << " Idle: "; for (int i = 0; i != 8; i++) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index bd7e22e7c..d8074a5d8 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -565,7 +565,7 @@ namespace MWGui int eff = mShown & mAllowed & ~mForceHidden; // Show the windows we want - mMap ->setVisible(eff & GW_Map); + mMap ->setVisible((eff & GW_Map) != 0); mStatsWindow ->setVisible((eff & GW_Stats) != 0); mInventoryWindow->setVisible((eff & GW_Inventory) != 0); mInventoryWindow->setGuiMode(mode); diff --git a/apps/openmw/mwmechanics/aisequence.cpp b/apps/openmw/mwmechanics/aisequence.cpp index 533bcd17c..bb078f883 100644 --- a/apps/openmw/mwmechanics/aisequence.cpp +++ b/apps/openmw/mwmechanics/aisequence.cpp @@ -294,7 +294,7 @@ void AiSequence::fill(const ESM::AIPackageList &list) idles.reserve(8); for (int i=0; i<8; ++i) idles.push_back(data.mIdle[i]); - package = new MWMechanics::AiWander(data.mDistance, data.mDuration, data.mTimeOfDay, idles, data.mShouldRepeat); + package = new MWMechanics::AiWander(data.mDistance, data.mDuration, data.mTimeOfDay, idles, data.mShouldRepeat != 0); } else if (it->mType == ESM::AI_Escort) { diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index fbb147b34..738facb13 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -785,7 +785,7 @@ namespace MWMechanics , mDuration(wander->mData.mDuration) , mStartTime(MWWorld::TimeStamp(wander->mStartTime)) , mTimeOfDay(wander->mData.mTimeOfDay) - , mRepeat(wander->mData.mShouldRepeat) + , mRepeat(wander->mData.mShouldRepeat != 0) , mStoredInitialActorPosition(wander->mStoredInitialActorPosition) { if (mStoredInitialActorPosition) diff --git a/components/esm/aipackage.hpp b/components/esm/aipackage.hpp index b164b3d62..5e08806c8 100644 --- a/components/esm/aipackage.hpp +++ b/components/esm/aipackage.hpp @@ -32,7 +32,7 @@ namespace ESM short mDuration; unsigned char mTimeOfDay; unsigned char mIdle[8]; - bool mShouldRepeat; + unsigned char mShouldRepeat; }; struct AITravel diff --git a/components/esm/aisequence.hpp b/components/esm/aisequence.hpp index c2142ab34..2560fbe7d 100644 --- a/components/esm/aisequence.hpp +++ b/components/esm/aisequence.hpp @@ -44,7 +44,7 @@ namespace ESM short mDuration; unsigned char mTimeOfDay; unsigned char mIdle[8]; - bool mShouldRepeat; + unsigned char mShouldRepeat; }; struct AiTravelData { From ca21181483d203de200c3ee963a3abe07f5ede14 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 7 Mar 2015 11:42:50 +1100 Subject: [PATCH 0701/3725] Fix typo to get table display working. --- apps/opencs/model/world/columnbase.hpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index 5926df269..607f585b7 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -145,9 +145,9 @@ namespace CSMWorld void addNestedColumn(int columnId, Display displayType); bool canHaveNestedColumns() const; - + const ColumnBase& nestedColumn(int subColumn) const; - + int nestedColumnCount() const; }; @@ -157,15 +157,15 @@ namespace CSMWorld public: NestedColumn(int columnId, Display displayType, int flag, const NestColumn* parent); - + virtual bool isEditable() const; }; - + template struct Column : public NestColumn { Column (int columnId, Display displayType, int flags = Flag_Table | Flag_Dialogue, bool canNest = false) - : NestColumn (columnId, displayType, canNest, flags) {} + : NestColumn (columnId, displayType, flags, canNest) {} virtual QVariant get (const Record& record) const = 0; From 58807064b4f427c45613f3feafaf1ae28c166230 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 7 Mar 2015 15:31:21 +0100 Subject: [PATCH 0702/3725] Revert "Fix reference cell movement leaving behind deleted Ptrs for script access" This reverts commit 666248618eb2e4ca2003f51a5dbc1891baa98998. --- apps/openmw/mwworld/worldimp.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 3ef4f8e81..8a2b67bfc 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1206,10 +1206,6 @@ namespace MWWorld } } ptr.getRefData().setCount(0); - // Deleted references can still be accessed by scripts, - // so we need this extra step to remove access to the old reference completely. - // This will no longer be necessary once we have a proper cell movement tracker. - ptr.getCellRef().unsetRefNum(); } } if (haveToMove && ptr.getRefData().getBaseNode()) From a54ab153b0cdd226f9ad2e9c91913408dbf6a0da Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 8 Mar 2015 10:05:10 +1100 Subject: [PATCH 0703/3725] Cloned references should be considered "Base" rather than "Modified". Should fix bug #2429. --- apps/opencs/model/world/refidcollection.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 779d5a40c..75429d906 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -471,7 +471,7 @@ void CSMWorld::RefIdCollection::cloneRecord(const std::string& origin, const CSMWorld::UniversalId::Type type) { std::auto_ptr newRecord(mData.getRecord(mData.searchId(origin)).clone()); - newRecord->mState = RecordBase::State_ModifiedOnly; + newRecord->mState = RecordBase::State_BaseOnly; mAdapters.find(type)->second->setId(*newRecord, destination); mData.insertRecord(*newRecord, type, destination); } From e197f5318b7a2f820694096e82964142635ad28c Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 8 Mar 2015 13:07:29 +1300 Subject: [PATCH 0704/3725] fixing MSVC 2013 warning C4244: & C4305 conversion from 'const float' to 'int', possible loss of data conversion from 'double' to 'int', possible loss of data conversion from 'float' to 'int', possible loss of data --- apps/esmtool/esmtool.cpp | 2 +- apps/essimporter/convertacdt.cpp | 6 +- apps/essimporter/converter.hpp | 2 +- apps/openmw/engine.cpp | 2 +- apps/openmw/mwclass/armor.cpp | 6 +- apps/openmw/mwclass/clothing.cpp | 2 +- apps/openmw/mwclass/creature.cpp | 16 ++-- apps/openmw/mwclass/door.cpp | 10 +-- apps/openmw/mwclass/light.cpp | 2 +- apps/openmw/mwclass/npc.cpp | 26 +++---- apps/openmw/mwclass/weapon.cpp | 2 +- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 6 +- apps/openmw/mwgui/backgroundimage.cpp | 4 +- apps/openmw/mwgui/bookpage.cpp | 26 +++---- apps/openmw/mwgui/bookpage.hpp | 2 +- apps/openmw/mwgui/companionwindow.cpp | 2 +- apps/openmw/mwgui/controllers.cpp | 4 +- apps/openmw/mwgui/dialogue.cpp | 6 +- apps/openmw/mwgui/hud.cpp | 4 +- apps/openmw/mwgui/inventorywindow.cpp | 12 +-- apps/openmw/mwgui/itemview.cpp | 4 +- apps/openmw/mwgui/jailscreen.cpp | 6 +- apps/openmw/mwgui/loadingscreen.cpp | 10 +-- apps/openmw/mwgui/mapwindow.cpp | 34 ++++---- apps/openmw/mwgui/merchantrepair.cpp | 12 +-- apps/openmw/mwgui/messagebox.cpp | 2 +- apps/openmw/mwgui/race.cpp | 4 +- apps/openmw/mwgui/recharge.cpp | 12 +-- apps/openmw/mwgui/review.cpp | 10 +-- apps/openmw/mwgui/settingswindow.cpp | 6 +- apps/openmw/mwgui/spellbuyingwindow.cpp | 4 +- apps/openmw/mwgui/spellcreationdialog.cpp | 8 +- apps/openmw/mwgui/spellicons.cpp | 2 +- apps/openmw/mwgui/spellmodel.cpp | 2 +- apps/openmw/mwgui/spellview.cpp | 4 +- apps/openmw/mwgui/statswindow.cpp | 6 +- apps/openmw/mwgui/tooltips.cpp | 4 +- apps/openmw/mwgui/tradewindow.cpp | 25 +++--- apps/openmw/mwgui/trainingwindow.cpp | 2 +- apps/openmw/mwgui/travelwindow.cpp | 8 +- apps/openmw/mwgui/videowidget.cpp | 4 +- apps/openmw/mwgui/waitdialog.cpp | 12 +-- apps/openmw/mwgui/widgets.cpp | 4 +- apps/openmw/mwgui/windowmanagerimp.cpp | 24 +++--- apps/openmw/mwinput/inputmanagerimp.cpp | 34 ++++---- apps/openmw/mwmechanics/disease.hpp | 10 +-- apps/openmw/mwmechanics/levelledlist.hpp | 2 +- .../mwmechanics/mechanicsmanagerimp.cpp | 77 +++++++++---------- apps/openmw/mwmechanics/stat.hpp | 1 - apps/openmw/mwrender/animation.cpp | 4 +- apps/openmw/mwrender/characterpreview.cpp | 4 +- apps/openmw/mwrender/globalmap.cpp | 35 +++++---- apps/openmw/mwrender/localmap.cpp | 42 +++++----- apps/openmw/mwrender/npcanimation.cpp | 2 +- apps/openmw/mwrender/refraction.cpp | 2 +- apps/openmw/mwrender/renderingmanager.cpp | 24 +++--- apps/openmw/mwrender/ripplesimulation.cpp | 2 +- apps/openmw/mwrender/shadows.cpp | 4 +- apps/openmw/mwrender/sky.cpp | 24 +++--- apps/openmw/mwrender/terrainstorage.cpp | 8 +- apps/openmw/mwrender/water.cpp | 7 +- apps/openmw/mwrender/water.hpp | 2 +- apps/openmw/mwscript/aiextensions.cpp | 10 +-- apps/openmw/mwscript/interpretercontext.cpp | 2 +- apps/openmw/mwscript/locals.cpp | 4 +- apps/openmw/mwscript/miscextensions.cpp | 2 +- apps/openmw/mwscript/statsextensions.cpp | 9 +-- .../mwscript/transformationextensions.cpp | 4 +- apps/openmw/mwsound/loudness.cpp | 2 +- apps/openmw/mwsound/openal_output.cpp | 8 +- apps/openmw/mwsound/sound.cpp | 2 +- apps/openmw/mwsound/soundmanagerimp.cpp | 4 +- apps/openmw/mwworld/containerstore.cpp | 2 +- apps/openmw/mwworld/esmstore.cpp | 2 +- apps/openmw/mwworld/player.cpp | 8 +- apps/openmw/mwworld/projectilemanager.cpp | 2 +- apps/openmw/mwworld/timestamp.cpp | 2 +- apps/openmw/mwworld/weather.cpp | 16 ++-- apps/openmw/mwworld/worldimp.cpp | 64 ++++++--------- apps/openmw/mwworld/worldimp.hpp | 3 - components/esm/loadpgrd.cpp | 14 ++-- components/esm/loadrace.cpp | 2 +- components/esm/statstate.hpp | 2 +- components/esm/variantimp.cpp | 6 +- components/esmterrain/storage.cpp | 42 +++++----- components/fontloader/fontloader.cpp | 8 +- components/terrain/defaultworld.cpp | 10 +-- components/terrain/defaultworld.hpp | 2 +- components/terrain/material.cpp | 2 +- components/terrain/quadtreenode.cpp | 2 +- components/terrain/quadtreenode.hpp | 2 +- components/terrain/terraingrid.cpp | 14 ++-- components/widgets/list.cpp | 4 +- extern/sdl4ogre/sdlcursormanager.cpp | 5 +- extern/sdl4ogre/sdlwindowhelper.cpp | 3 +- libs/openengine/bullet/BtOgre.cpp | 10 +-- libs/openengine/bullet/physic.cpp | 6 +- libs/openengine/ogre/lights.cpp | 10 +-- libs/openengine/ogre/renderer.cpp | 2 +- libs/openengine/ogre/selectionbuffer.cpp | 4 +- 100 files changed, 457 insertions(+), 474 deletions(-) diff --git a/apps/esmtool/esmtool.cpp b/apps/esmtool/esmtool.cpp index 98e18521e..eef970d37 100644 --- a/apps/esmtool/esmtool.cpp +++ b/apps/esmtool/esmtool.cpp @@ -460,7 +460,7 @@ int clone(Arguments& info) for (Stats::iterator it = stats.begin(); it != stats.end(); ++it) { name.val = it->first; - float amount = it->second; + int amount = it->second; std::cout << std::setw(digitCount) << amount << " " << name.toString() << " "; if (++i % 3 == 0) diff --git a/apps/essimporter/convertacdt.cpp b/apps/essimporter/convertacdt.cpp index 91dd8ef23..55a20ec3d 100644 --- a/apps/essimporter/convertacdt.cpp +++ b/apps/essimporter/convertacdt.cpp @@ -23,9 +23,9 @@ namespace ESSImport } for (int i=0; i<8; ++i) { - cStats.mAttributes[i].mBase = acdt.mAttributes[i][1]; - cStats.mAttributes[i].mMod = acdt.mAttributes[i][0]; - cStats.mAttributes[i].mCurrent = acdt.mAttributes[i][0]; + cStats.mAttributes[i].mBase = static_cast(acdt.mAttributes[i][1]); + cStats.mAttributes[i].mMod = static_cast(acdt.mAttributes[i][0]); + cStats.mAttributes[i].mCurrent = static_cast(acdt.mAttributes[i][0]); } cStats.mGoldPool = acdt.mGoldPool; cStats.mTalkedTo = (acdt.mFlags & TalkedToPlayer) != 0; diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index c23083f8e..5711e6754 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -553,7 +553,7 @@ public: ESM::WeatherState weather; weather.mCurrentWeather = toString(mGame.mGMDT.mCurrentWeather); weather.mNextWeather = toString(mGame.mGMDT.mNextWeather); - weather.mRemainingTransitionTime = mGame.mGMDT.mWeatherTransition/100.f*(0.015*24*3600); + weather.mRemainingTransitionTime = mGame.mGMDT.mWeatherTransition/100.f*(0.015f*24*3600); weather.mHour = mContext->mHour; weather.mWindSpeed = 0.f; weather.mTimePassed = 0.0; diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 96cebd024..76b573941 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -191,7 +191,7 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) , mExportFonts(false) , mNewGame (false) { - std::srand ( std::time(NULL) ); + std::srand ( static_cast(std::time(NULL)) ); MWClass::registerClasses(); Uint32 flags = SDL_INIT_VIDEO|SDL_INIT_NOPARACHUTE|SDL_INIT_GAMECONTROLLER|SDL_INIT_JOYSTICK; diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index 0f99d91da..686f5af61 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -154,9 +154,9 @@ namespace MWClass const MWWorld::Store &gmst = MWBase::Environment::get().getWorld()->getStore().get(); - float iWeight = gmst.find (typeGmst)->getInt(); + float iWeight = floor(gmst.find(typeGmst)->getFloat()); - float epsilon = 5e-4; + float epsilon = 0.0005f; if (ref->mBase->mData.mWeight == 0) return ESM::Skill::Unarmored; @@ -262,7 +262,7 @@ namespace MWClass info.enchant = ref->mBase->mEnchant; if (!info.enchant.empty()) - info.remainingEnchantCharge = ptr.getCellRef().getEnchantmentCharge(); + info.remainingEnchantCharge = static_cast(ptr.getCellRef().getEnchantmentCharge()); info.text = text; diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index 0fa686dda..b387a3e9f 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -203,7 +203,7 @@ namespace MWClass info.enchant = ref->mBase->mEnchant; if (!info.enchant.empty()) - info.remainingEnchantCharge = ptr.getCellRef().getEnchantmentCharge(); + info.remainingEnchantCharge = static_cast(ptr.getCellRef().getEnchantmentCharge()); info.text = text; diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index c59f8428c..ace4949ed 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -103,9 +103,9 @@ namespace MWClass data->mCreatureStats.setAttribute(ESM::Attribute::Endurance, ref->mBase->mData.mEndurance); data->mCreatureStats.setAttribute(ESM::Attribute::Personality, ref->mBase->mData.mPersonality); data->mCreatureStats.setAttribute(ESM::Attribute::Luck, ref->mBase->mData.mLuck); - data->mCreatureStats.setHealth (ref->mBase->mData.mHealth); - data->mCreatureStats.setMagicka (ref->mBase->mData.mMana); - data->mCreatureStats.setFatigue (ref->mBase->mData.mFatigue); + data->mCreatureStats.setHealth(static_cast(ref->mBase->mData.mHealth)); + data->mCreatureStats.setMagicka(static_cast(ref->mBase->mData.mMana)); + data->mCreatureStats.setFatigue(static_cast(ref->mBase->mData.mFatigue)); data->mCreatureStats.setLevel(ref->mBase->mData.mLevel); @@ -289,7 +289,7 @@ namespace MWClass { damage = attack[0] + ((attack[1]-attack[0])*stats.getAttackStrength()); damage *= gmst.find("fDamageStrengthBase")->getFloat() + - (stats.getAttribute(ESM::Attribute::Strength).getModified() * gmst.find("fDamageStrengthMult")->getFloat() * 0.1); + (stats.getAttribute(ESM::Attribute::Strength).getModified() * gmst.find("fDamageStrengthMult")->getFloat() * 0.1f); MWMechanics::adjustWeaponDamage(damage, weapon); MWMechanics::reduceWeaponCondition(damage, true, weapon, ptr); } @@ -376,8 +376,8 @@ namespace MWClass // Check for knockdown float agilityTerm = getCreatureStats(ptr).getAttribute(ESM::Attribute::Agility).getModified() * getGmst().fKnockDownMult->getFloat(); float knockdownTerm = getCreatureStats(ptr).getAttribute(ESM::Attribute::Agility).getModified() - * getGmst().iKnockDownOddsMult->getInt() * 0.01 + getGmst().iKnockDownOddsBase->getInt(); - int roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 100; // [0, 99] + * getGmst().iKnockDownOddsMult->getInt() * 0.01f + getGmst().iKnockDownOddsBase->getInt(); + int roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 100); // [0, 99] if (ishealth && agilityTerm <= damage && knockdownTerm <= roll) { getCreatureStats(ptr).setKnockedDown(true); @@ -528,7 +528,7 @@ namespace MWClass MWMechanics::CreatureStats& stats = getCreatureStats(ptr); const GMST& gmst = getGmst(); - float walkSpeed = gmst.fMinWalkSpeedCreature->getFloat() + 0.01 * stats.getAttribute(ESM::Attribute::Speed).getModified() + float walkSpeed = gmst.fMinWalkSpeedCreature->getFloat() + 0.01f * stats.getAttribute(ESM::Attribute::Speed).getModified() * (gmst.fMaxWalkSpeedCreature->getFloat() - gmst.fMinWalkSpeedCreature->getFloat()); const MWBase::World *world = MWBase::Environment::get().getWorld(); @@ -626,7 +626,7 @@ namespace MWClass float Creature::getCapacity (const MWWorld::Ptr& ptr) const { const MWMechanics::CreatureStats& stats = getCreatureStats (ptr); - return stats.getAttribute(0).getModified()*5; + return static_cast(stats.getAttribute(0).getModified() * 5); } float Creature::getEncumbrance (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 10b9b437d..6e1d5334d 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -167,19 +167,19 @@ namespace MWClass if (opening) { MWBase::Environment::get().getSoundManager()->fadeOutSound3D(ptr, - closeSound, 0.5); - float offset = ptr.getRefData().getLocalRotation().rot[2]/ 3.14159265 * 2.0; + closeSound, 0.5f); + float offset = ptr.getRefData().getLocalRotation().rot[2]/ 3.14159265f * 2.0f; action->setSoundOffset(offset); action->setSound(openSound); } else { MWBase::Environment::get().getSoundManager()->fadeOutSound3D(ptr, - openSound, 0.5); - float offset = 1.0 - ptr.getRefData().getLocalRotation().rot[2]/ 3.14159265 * 2.0; + openSound, 0.5f); + float offset = 1.0 - ptr.getRefData().getLocalRotation().rot[2]/ 3.14159265f * 2.0f; //most if not all door have closing bang somewhere in the middle of the sound, //so we divide offset by two - action->setSoundOffset(offset * 0.5); + action->setSoundOffset(offset * 0.5f); action->setSound(closeSound); } diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 032c40237..90c708f97 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -205,7 +205,7 @@ namespace MWClass { MWWorld::LiveCellRef *ref = ptr.get(); if (ptr.getCellRef().getCharge() == -1) - return ref->mBase->mData.mTime; + return static_cast(ref->mBase->mData.mTime); else return ptr.getCellRef().getChargeFloat(); } diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index d06d7cfe1..c62257572 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -66,12 +66,12 @@ namespace double i = floor(d); d -= i; if(d < 0.5) - return i; + return static_cast(i); if(d > 0.5) - return i + 1.0; + return static_cast(i) + 1; if(is_even(i)) - return i; - return i + 1.0; + return static_cast(i); + return static_cast(i) + 1; } void autoCalculateAttributes (const ESM::NPC* npc, MWMechanics::CreatureStats& creatureStats) @@ -116,7 +116,7 @@ namespace continue; // is this a minor or major skill? - float add=0.2; + float add=0.2f; for (int k=0; k<5; ++k) { if (class_->mData.mSkills[k][0] == j) @@ -149,7 +149,7 @@ namespace || class_->mData.mAttribute[1] == ESM::Attribute::Endurance) multiplier += 1; - creatureStats.setHealth(static_cast (0.5 * (strength + endurance)) + multiplier * (creatureStats.getLevel() - 1)); + creatureStats.setHealth(floor(0.5f * (strength + endurance)) + multiplier * (creatureStats.getLevel() - 1)); } /** @@ -539,7 +539,7 @@ namespace MWClass { damage = attack[0] + ((attack[1]-attack[0])*stats.getAttackStrength()); damage *= gmst.fDamageStrengthBase->getFloat() + - (stats.getAttribute(ESM::Attribute::Strength).getModified() * gmst.fDamageStrengthMult->getFloat() * 0.1); + (stats.getAttribute(ESM::Attribute::Strength).getModified() * gmst.fDamageStrengthMult->getFloat() * 0.1f); } MWMechanics::adjustWeaponDamage(damage, weapon); MWMechanics::reduceWeaponCondition(damage, true, weapon, ptr); @@ -648,7 +648,7 @@ namespace MWClass const GMST& gmst = getGmst(); int chance = store.get().find("iVoiceHitOdds")->getInt(); - int roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 100; // [0, 99] + int roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 100); // [0, 99] if (roll < chance) { MWBase::Environment::get().getDialogueManager()->say(ptr, "hit"); @@ -657,8 +657,8 @@ namespace MWClass // Check for knockdown float agilityTerm = getCreatureStats(ptr).getAttribute(ESM::Attribute::Agility).getModified() * gmst.fKnockDownMult->getFloat(); float knockdownTerm = getCreatureStats(ptr).getAttribute(ESM::Attribute::Agility).getModified() - * gmst.iKnockDownOddsMult->getInt() * 0.01 + gmst.iKnockDownOddsBase->getInt(); - roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 100; // [0, 99] + * gmst.iKnockDownOddsMult->getInt() * 0.01f + gmst.iKnockDownOddsBase->getInt(); + roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 100); // [0, 99] if (ishealth && agilityTerm <= damage && knockdownTerm <= roll) { getCreatureStats(ptr).setKnockedDown(true); @@ -690,7 +690,7 @@ namespace MWClass float unmitigatedDamage = damage; float x = damage / (damage + getArmorRating(ptr)); damage *= std::max(gmst.fCombatArmorMinMult->getFloat(), x); - int damageDiff = unmitigatedDamage - damage; + int damageDiff = static_cast(unmitigatedDamage - damage); if (damage < 1) damage = 1; @@ -938,7 +938,7 @@ namespace MWClass gmst.fJumpEncumbranceMultiplier->getFloat() * (1.0f - Npc::getEncumbrance(ptr)/Npc::getCapacity(ptr)); - float a = npcdata->mNpcStats.getSkill(ESM::Skill::Acrobatics).getModified(); + float a = static_cast(npcdata->mNpcStats.getSkill(ESM::Skill::Acrobatics).getModified()); float b = 0.0f; if(a > 50.0f) { @@ -1097,7 +1097,7 @@ namespace MWClass if (it == invStore.end() || it->getTypeName() != typeid(ESM::Armor).name()) { // unarmored - ratings[i] = (fUnarmoredBase1 * unarmoredSkill) * (fUnarmoredBase2 * unarmoredSkill); + ratings[i] = static_cast((fUnarmoredBase1 * unarmoredSkill) * (fUnarmoredBase2 * unarmoredSkill)); } else { diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index d1a44fd0e..a484ad668 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -345,7 +345,7 @@ namespace MWClass info.enchant = ref->mBase->mEnchant; if (!info.enchant.empty()) - info.remainingEnchantCharge = ptr.getCellRef().getEnchantmentCharge(); + info.remainingEnchantCharge = static_cast(ptr.getCellRef().getEnchantmentCharge()); if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { text += MWGui::ToolTips::getCellRefString(ptr.getCellRef()); diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 1d1f655aa..e8dcf535c 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -444,7 +444,7 @@ namespace MWDialogue if (mActor.getClass().isNpc()) { MWMechanics::NpcStats& npcStats = mActor.getClass().getNpcStats(mActor); - npcStats.setBaseDisposition(npcStats.getBaseDisposition() + mPermanentDispositionChange); + npcStats.setBaseDisposition(static_cast(npcStats.getBaseDisposition() + mPermanentDispositionChange)); } mPermanentDispositionChange = 0; mTemporaryDispositionChange = 0; @@ -521,7 +521,7 @@ namespace MWDialogue mPermanentDispositionChange += perm; // change temp disposition so that final disposition is between 0...100 - int curDisp = MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mActor); + float curDisp = static_cast(MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mActor)); if (curDisp + mTemporaryDispositionChange < 0) mTemporaryDispositionChange = -curDisp; else if (curDisp + mTemporaryDispositionChange > 100) @@ -564,7 +564,7 @@ namespace MWDialogue int DialogueManager::getTemporaryDispositionChange() const { - return mTemporaryDispositionChange; + return static_cast(mTemporaryDispositionChange); } void DialogueManager::applyDispositionChange(int delta) diff --git a/apps/openmw/mwgui/backgroundimage.cpp b/apps/openmw/mwgui/backgroundimage.cpp index 9c07c5780..ee966c189 100644 --- a/apps/openmw/mwgui/backgroundimage.cpp +++ b/apps/openmw/mwgui/backgroundimage.cpp @@ -41,8 +41,8 @@ void BackgroundImage::adjustSize() MyGUI::IntSize screenSize = getSize(); - int leftPadding = std::max(0.0, (screenSize.width - screenSize.height * mAspect) / 2); - int topPadding = std::max(0.0, (screenSize.height - screenSize.width / mAspect) / 2); + int leftPadding = std::max(0, static_cast(screenSize.width - screenSize.height * mAspect) / 2); + int topPadding = std::max(0, static_cast(screenSize.height - screenSize.width / mAspect) / 2); mChild->setCoord(leftPadding, topPadding, screenSize.width - leftPadding*2, screenSize.height - topPadding*2); } diff --git a/apps/openmw/mwgui/bookpage.cpp b/apps/openmw/mwgui/bookpage.cpp index 57e171659..9d2f52bfd 100644 --- a/apps/openmw/mwgui/bookpage.cpp +++ b/apps/openmw/mwgui/bookpage.cpp @@ -326,7 +326,7 @@ struct TypesetBookImpl::Typesetter : BookTypesetter mLine = NULL; } - void sectionBreak (float margin) + void sectionBreak (int margin) { add_partial_text(); @@ -465,7 +465,7 @@ struct TypesetBookImpl::Typesetter : BookTypesetter { MyGUI::GlyphInfo* gi = style->mFont->getGlyphInfo (stream.peek ()); if (gi) - space_width += gi->advance + gi->bearingX; + space_width += static_cast(gi->advance + gi->bearingX); stream.consume (); } @@ -475,7 +475,7 @@ struct TypesetBookImpl::Typesetter : BookTypesetter { MyGUI::GlyphInfo* gi = style->mFont->getGlyphInfo (stream.peek ()); if (gi) - word_width += gi->advance + gi->bearingX; + word_width += static_cast(gi->advance + gi->bearingX); stream.consume (); } @@ -623,15 +623,15 @@ namespace RenderXform (MyGUI::ICroppedRectangle* croppedParent, MyGUI::RenderTargetInfo const & renderTargetInfo) { - clipTop = croppedParent->_getMarginTop (); - clipLeft = croppedParent->_getMarginLeft (); - clipRight = croppedParent->getWidth () - croppedParent->_getMarginRight (); - clipBottom = croppedParent->getHeight () - croppedParent->_getMarginBottom (); + clipTop = static_cast(croppedParent->_getMarginTop()); + clipLeft = static_cast(croppedParent->_getMarginLeft ()); + clipRight = static_cast(croppedParent->getWidth () - croppedParent->_getMarginRight ()); + clipBottom = static_cast(croppedParent->getHeight() - croppedParent->_getMarginBottom()); - absoluteLeft = croppedParent->getAbsoluteLeft(); - absoluteTop = croppedParent->getAbsoluteTop(); - leftOffset = renderTargetInfo.leftOffset; - topOffset = renderTargetInfo.topOffset; + absoluteLeft = static_cast(croppedParent->getAbsoluteLeft()); + absoluteTop = static_cast(croppedParent->getAbsoluteTop()); + leftOffset = static_cast(renderTargetInfo.leftOffset); + topOffset = static_cast(renderTargetInfo.topOffset); pixScaleX = renderTargetInfo.pixScaleX; pixScaleY = renderTargetInfo.pixScaleY; @@ -1136,7 +1136,7 @@ public: MyGUI::Colour colour = isActive ? (this_->mItemActive ? run.mStyle->mActiveColour: run.mStyle->mHotColour) : run.mStyle->mNormalColour; - glyphStream.reset (section.mRect.left + line.mRect.left + run.mLeft, line.mRect.top, colour); + glyphStream.reset(static_cast(section.mRect.left + line.mRect.left + run.mLeft), static_cast(line.mRect.top), colour); Utf8Stream stream (run.mRange); @@ -1164,7 +1164,7 @@ public: RenderXform renderXform (mCroppedParent, textFormat.mRenderItem->getRenderTarget()->getInfo()); - GlyphStream glyphStream (textFormat.mFont, mCoord.left, mCoord.top-mViewTop, + GlyphStream glyphStream(textFormat.mFont, static_cast(mCoord.left), static_cast(mCoord.top - mViewTop), -1 /*mNode->getNodeDepth()*/, vertices, renderXform); int visit_top = (std::max) (mViewTop, mViewTop + int (renderXform.clipTop )); diff --git a/apps/openmw/mwgui/bookpage.hpp b/apps/openmw/mwgui/bookpage.hpp index 458cf2a19..c7340ec7c 100644 --- a/apps/openmw/mwgui/bookpage.hpp +++ b/apps/openmw/mwgui/bookpage.hpp @@ -71,7 +71,7 @@ namespace MWGui /// to begin when additional text is inserted. Pagination attempts to keep /// sections together on a single page. The margin parameter adds additional space /// before the next line of text. - virtual void sectionBreak (float margin = 0) = 0; + virtual void sectionBreak (int margin = 0) = 0; /// Changes the alignment for the current section of text. virtual void setSectionAlignment (Alignment sectionAlignment) = 0; diff --git a/apps/openmw/mwgui/companionwindow.cpp b/apps/openmw/mwgui/companionwindow.cpp index 8f709ec8d..fe47437ca 100644 --- a/apps/openmw/mwgui/companionwindow.cpp +++ b/apps/openmw/mwgui/companionwindow.cpp @@ -129,7 +129,7 @@ void CompanionWindow::updateEncumbranceBar() return; float capacity = mPtr.getClass().getCapacity(mPtr); float encumbrance = mPtr.getClass().getEncumbrance(mPtr); - mEncumbranceBar->setValue(encumbrance, capacity); + mEncumbranceBar->setValue(static_cast(encumbrance), static_cast(capacity)); if (mModel && mModel->hasProfit(mPtr)) { diff --git a/apps/openmw/mwgui/controllers.cpp b/apps/openmw/mwgui/controllers.cpp index ad804997a..72f2eb7f3 100644 --- a/apps/openmw/mwgui/controllers.cpp +++ b/apps/openmw/mwgui/controllers.cpp @@ -9,8 +9,8 @@ namespace MWGui { ControllerRepeatEvent::ControllerRepeatEvent() : - mInit(0.5), - mStep(0.1), + mInit(0.5f), + mStep(0.1f), mEnabled(true), mTimeLeft(0) { diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index eee86c6d2..3bc4292e3 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -549,7 +549,7 @@ namespace MWGui size_t range = book->getSize().second - viewHeight; mScrollBar->setScrollRange(range); mScrollBar->setScrollPosition(range-1); - mScrollBar->setTrackSize(viewHeight / static_cast(book->getSize().second) * mScrollBar->getLineSize()); + mScrollBar->setTrackSize(static_cast(viewHeight / static_cast(book->getSize().second) * mScrollBar->getLineSize())); onScrollbarMoved(mScrollBar, range-1); } else @@ -637,14 +637,14 @@ namespace MWGui if (dispositionVisible && !dispositionWasVisible) { mDispositionBar->setVisible(true); - float offset = mDispositionBar->getHeight()+5; + int offset = mDispositionBar->getHeight()+5; mTopicsList->setCoord(mTopicsList->getCoord() + MyGUI::IntCoord(0,offset,0,-offset)); mTopicsList->adjustSize(); } else if (!dispositionVisible && dispositionWasVisible) { mDispositionBar->setVisible(false); - float offset = mDispositionBar->getHeight()+5; + int offset = mDispositionBar->getHeight()+5; mTopicsList->setCoord(mTopicsList->getCoord() - MyGUI::IntCoord(0,offset,0,-offset)); mTopicsList->adjustSize(); } diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index a4e67e9b1..97a113527 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -262,7 +262,7 @@ namespace MWGui void HUD::setDrowningTimeLeft(float time, float maxTime) { - size_t progress = time/maxTime*200.0; + size_t progress = static_cast(time / maxTime * 200); mDrowning->setProgressPosition(progress); bool isDrowning = (progress == 0); @@ -631,7 +631,7 @@ namespace MWGui mEnemyHealth->setProgressRange(100); // Health is usually cast to int before displaying. Actors die whenever they are < 1 health. // Therefore any value < 1 should show as an empty health bar. We do the same in statswindow :) - mEnemyHealth->setProgressPosition(int(stats.getHealth().getCurrent()) / stats.getHealth().getModified() * 100); + mEnemyHealth->setProgressPosition(static_cast(stats.getHealth().getCurrent() / stats.getHealth().getModified() * 100)); static const float fNPCHealthBarFade = MWBase::Environment::get().getWorld()->getStore().get().find("fNPCHealthBarFade")->getFloat(); if (fNPCHealthBarFade > 0.f) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index b0adddffa..a6722319d 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -101,7 +101,7 @@ namespace MWGui void InventoryWindow::adjustPanes() { const float aspect = 0.5; // fixed aspect ratio for the avatar image - float leftPaneWidth = (mMainWidget->getSize().height-44-mArmorRating->getHeight()) * aspect; + int leftPaneWidth = static_cast(mMainWidget->getSize().height - 44 - mArmorRating->getHeight()) * aspect); mLeftPane->setSize( leftPaneWidth, mMainWidget->getSize().height-44 ); mRightPane->setCoord( mLeftPane->getPosition().left + leftPaneWidth + 4, mRightPane->getPosition().top, @@ -153,10 +153,10 @@ namespace MWGui } MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize(); - MyGUI::IntPoint pos (Settings::Manager::getFloat(setting + " x", "Windows") * viewSize.width, - Settings::Manager::getFloat(setting + " y", "Windows") * viewSize.height); - MyGUI::IntSize size (Settings::Manager::getFloat(setting + " w", "Windows") * viewSize.width, - Settings::Manager::getFloat(setting + " h", "Windows") * viewSize.height); + MyGUI::IntPoint pos(static_cast(Settings::Manager::getFloat(setting + " x", "Windows") * viewSize.width), + static_cast(Settings::Manager::getFloat(setting + " y", "Windows") * viewSize.height)); + MyGUI::IntSize size(static_cast(Settings::Manager::getFloat(setting + " w", "Windows") * viewSize.width), + static_cast(Settings::Manager::getFloat(setting + " h", "Windows") * viewSize.height)); if (size.width != mMainWidget->getWidth() || size.height != mMainWidget->getHeight()) mPreviewResize = true; @@ -519,7 +519,7 @@ namespace MWGui float capacity = player.getClass().getCapacity(player); float encumbrance = player.getClass().getEncumbrance(player); mTradeModel->adjustEncumbrance(encumbrance); - mEncumbranceBar->setValue(encumbrance, capacity); + mEncumbranceBar->setValue(static_cast(encumbrance), static_cast(capacity)); } void InventoryWindow::onFrame() diff --git a/apps/openmw/mwgui/itemview.cpp b/apps/openmw/mwgui/itemview.cpp index e30f6e7a8..aade232d2 100644 --- a/apps/openmw/mwgui/itemview.cpp +++ b/apps/openmw/mwgui/itemview.cpp @@ -141,10 +141,10 @@ void ItemView::onSelectedBackground(MyGUI::Widget *sender) void ItemView::onMouseWheel(MyGUI::Widget *_sender, int _rel) { - if (mScrollView->getViewOffset().left + _rel*0.3 > 0) + if (mScrollView->getViewOffset().left + _rel*0.3f > 0) mScrollView->setViewOffset(MyGUI::IntPoint(0, 0)); else - mScrollView->setViewOffset(MyGUI::IntPoint(mScrollView->getViewOffset().left + _rel*0.3, 0)); + mScrollView->setViewOffset(MyGUI::IntPoint(static_cast(mScrollView->getViewOffset().left + _rel*0.3f), 0)); } void ItemView::setSize(const MyGUI::IntSize &_value) diff --git a/apps/openmw/mwgui/jailscreen.cpp b/apps/openmw/mwgui/jailscreen.cpp index 58873c566..728c46023 100644 --- a/apps/openmw/mwgui/jailscreen.cpp +++ b/apps/openmw/mwgui/jailscreen.cpp @@ -17,7 +17,7 @@ namespace MWGui { JailScreen::JailScreen() : WindowBase("openmw_jail_screen.layout"), - mTimeAdvancer(0.01), + mTimeAdvancer(0.01f), mDays(1), mFadeTimeRemaining(0) { @@ -66,7 +66,7 @@ namespace MWGui void JailScreen::onJailProgressChanged(int cur, int /*total*/) { mProgressBar->setScrollPosition(0); - mProgressBar->setTrackSize(cur / (float)(mProgressBar->getScrollRange()) * mProgressBar->getLineSize()); + mProgressBar->setTrackSize(static_cast(cur / (float)(mProgressBar->getScrollRange()) * mProgressBar->getLineSize())); } void JailScreen::onJailFinished() @@ -83,7 +83,7 @@ namespace MWGui std::set skills; for (int day=0; day (RAND_MAX) + 1) * ESM::Skill::Length; + int skill = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * ESM::Skill::Length); skills.insert(skill); MWMechanics::SkillValue& value = player.getClass().getNpcStats(player).getSkill(skill); diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index 9e3343c78..f920acf1a 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -33,8 +33,8 @@ namespace MWGui : mSceneMgr(sceneMgr) , mWindow(rw) , WindowBase("openmw_loading_screen.layout") - , mLastRenderTime(0.f) - , mLastWallpaperChangeTime(0.f) + , mLastRenderTime(0) + , mLastWallpaperChangeTime(0) , mProgress(0) , mVSyncWasEnabled(false) { @@ -173,7 +173,7 @@ namespace MWGui return; mProgress = value; mProgressBar->setScrollPosition(0); - mProgressBar->setTrackSize(value / (float)(mProgressBar->getScrollRange()) * mProgressBar->getLineSize()); + mProgressBar->setTrackSize(static_cast(value / (float)(mProgressBar->getScrollRange()) * mProgressBar->getLineSize())); draw(); } @@ -182,7 +182,7 @@ namespace MWGui mProgressBar->setScrollPosition(0); size_t value = mProgress + increase; mProgress = value; - mProgressBar->setTrackSize(value / (float)(mProgressBar->getScrollRange()) * mProgressBar->getLineSize()); + mProgressBar->setTrackSize(static_cast(value / (float)(mProgressBar->getScrollRange()) * mProgressBar->getLineSize())); draw(); } @@ -193,7 +193,7 @@ namespace MWGui time = (time-2)*-1; mProgressBar->setTrackSize(50); - mProgressBar->setScrollPosition(time * (mProgressBar->getScrollRange()-1)); + mProgressBar->setScrollPosition(static_cast(time * (mProgressBar->getScrollRange() - 1))); draw(); } diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 13e2e3904..271e43d29 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -244,14 +244,14 @@ namespace MWGui // Image space is -Y up, cells are Y up nY = 1 - (worldY - cellSize * cellY) / cellSize; - float cellDx = cellX - mCurX; - float cellDy = cellY - mCurY; + float cellDx = static_cast(cellX - mCurX); + float cellDy = static_cast(cellY - mCurY); markerPos.cellX = cellX; markerPos.cellY = cellY; - widgetPos = MyGUI::IntPoint(nX * mMapWidgetSize + (1+cellDx) * mMapWidgetSize, - nY * mMapWidgetSize - (cellDy-1) * mMapWidgetSize); + widgetPos = MyGUI::IntPoint(static_cast(nX * mMapWidgetSize + (1 + cellDx) * mMapWidgetSize), + static_cast(nY * mMapWidgetSize - (cellDy-1) * mMapWidgetSize)); } else { @@ -263,8 +263,8 @@ namespace MWGui markerPos.cellY = cellY; // Image space is -Y up, cells are Y up - widgetPos = MyGUI::IntPoint(nX * mMapWidgetSize + (1+(cellX-mCurX)) * mMapWidgetSize, - nY * mMapWidgetSize + (1-(cellY-mCurY)) * mMapWidgetSize); + widgetPos = MyGUI::IntPoint(static_cast(nX * mMapWidgetSize + (1 + (cellX - mCurX)) * mMapWidgetSize), + static_cast(nY * mMapWidgetSize + (1-(cellY-mCurY)) * mMapWidgetSize)); } markerPos.nX = nX; @@ -309,8 +309,8 @@ namespace MWGui markerWidget->setUserString("ToolTipType", "Layout"); markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine"); markerWidget->setUserString("Caption_TextOneLine", MyGUI::TextIterator::toTagsString(marker.mNote)); - markerWidget->setNormalColour(MyGUI::Colour(1.0,0.3,0.3)); - markerWidget->setHoverColour(MyGUI::Colour(1.0,0.5,0.5)); + markerWidget->setNormalColour(MyGUI::Colour(1.0f, 0.3f, 0.3f)); + markerWidget->setHoverColour(MyGUI::Colour(1.0f, 0.5f, 0.5f)); markerWidget->setUserData(marker); markerWidget->setNeedMouseFocus(true); customMarkerCreated(markerWidget); @@ -424,7 +424,7 @@ namespace MWGui void LocalMapBase::setPlayerPos(int cellX, int cellY, const float nx, const float ny) { - MyGUI::IntPoint pos(mMapWidgetSize+nx*mMapWidgetSize-16, mMapWidgetSize+ny*mMapWidgetSize-16); + MyGUI::IntPoint pos(static_cast(mMapWidgetSize + nx*mMapWidgetSize - 16), static_cast(mMapWidgetSize + ny*mMapWidgetSize - 16)); pos.left += (cellX - mCurX) * mMapWidgetSize; pos.top -= (cellY - mCurY) * mMapWidgetSize; @@ -435,7 +435,7 @@ namespace MWGui mCompass->setPosition(pos); MyGUI::IntPoint middle (pos.left+16, pos.top+16); MyGUI::IntCoord viewsize = mLocalMap->getCoord(); - MyGUI::IntPoint viewOffset(0.5*viewsize.width - middle.left, 0.5*viewsize.height - middle.top); + MyGUI::IntPoint viewOffset((viewsize.width / 2) - middle.left, (viewsize.height / 2) - middle.top); mLocalMap->setViewOffset(viewOffset); } } @@ -668,7 +668,7 @@ namespace MWGui else { worldPos.x = (x + nX) * cellSize; - worldPos.y = (y + (1.0-nY)) * cellSize; + worldPos.y = (y + (1.0f-nY)) * cellSize; } mEditingMarker.mWorldX = worldPos.x; @@ -737,8 +737,8 @@ namespace MWGui int markerSize = 12; int offset = mGlobalMapRender->getCellSize()/2 - markerSize/2; MyGUI::IntCoord widgetCoord( - worldX * mGlobalMapRender->getWidth()+offset, - worldY * mGlobalMapRender->getHeight()+offset, + static_cast(worldX * mGlobalMapRender->getWidth()+offset), + static_cast(worldY * mGlobalMapRender->getHeight() + offset), markerSize, markerSize); MyGUI::Widget* markerWidget = mGlobalMap->createWidget("MarkerButton", @@ -833,11 +833,11 @@ namespace MWGui worldX *= mGlobalMapRender->getWidth(); worldY *= mGlobalMapRender->getHeight(); - mPlayerArrowGlobal->setPosition(MyGUI::IntPoint(worldX - 16, worldY - 16)); + mPlayerArrowGlobal->setPosition(MyGUI::IntPoint(static_cast(worldX - 16), static_cast(worldY - 16))); // set the view offset so that player is in the center MyGUI::IntSize viewsize = mGlobalMap->getSize(); - MyGUI::IntPoint viewoffs(0.5*viewsize.width - worldX, 0.5*viewsize.height - worldY); + MyGUI::IntPoint viewoffs((viewsize.width / 2) - worldX, (viewsize.height / 2) - worldY); mGlobalMap->setViewOffset(viewoffs); } } @@ -854,11 +854,11 @@ namespace MWGui x *= mGlobalMapRender->getWidth(); y *= mGlobalMapRender->getHeight(); - mPlayerArrowGlobal->setPosition(MyGUI::IntPoint(x - 16, y - 16)); + mPlayerArrowGlobal->setPosition(MyGUI::IntPoint(static_cast(x - 16), static_cast(y - 16))); // set the view offset so that player is in the center MyGUI::IntSize viewsize = mGlobalMap->getSize(); - MyGUI::IntPoint viewoffs(0.5*viewsize.width - x, 0.5*viewsize.height - y); + MyGUI::IntPoint viewoffs((viewsize.width / 2) - x, (viewsize.height / 2) - y); mGlobalMap->setViewOffset(viewoffs); } diff --git a/apps/openmw/mwgui/merchantrepair.cpp b/apps/openmw/mwgui/merchantrepair.cpp index 907c664b1..4407bf927 100644 --- a/apps/openmw/mwgui/merchantrepair.cpp +++ b/apps/openmw/mwgui/merchantrepair.cpp @@ -59,11 +59,11 @@ void MerchantRepair::startRepair(const MWWorld::Ptr &actor) float fRepairMult = MWBase::Environment::get().getWorld()->getStore().get() .find("fRepairMult")->getFloat(); - float p = std::max(1, basePrice); - float r = std::max(1, static_cast(maxDurability / p)); + float p = static_cast(std::max(1, basePrice)); + float r = static_cast(std::max(1, static_cast(maxDurability / p))); - int x = ((maxDurability - durability) / r); - x = (fRepairMult * x); + int x = static_cast((maxDurability - durability) / r); + x = static_cast(fRepairMult * x); int price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mActor, x, true); @@ -105,10 +105,10 @@ void MerchantRepair::startRepair(const MWWorld::Ptr &actor) void MerchantRepair::onMouseWheel(MyGUI::Widget* _sender, int _rel) { - if (mList->getViewOffset().top + _rel*0.3 > 0) + if (mList->getViewOffset().top + _rel*0.3f > 0) mList->setViewOffset(MyGUI::IntPoint(0, 0)); else - mList->setViewOffset(MyGUI::IntPoint(0, mList->getViewOffset().top + _rel*0.3)); + mList->setViewOffset(MyGUI::IntPoint(0, static_cast(mList->getViewOffset().top + _rel*0.3f))); } void MerchantRepair::open() diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index cdbcf784d..b7c67e68b 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -70,7 +70,7 @@ namespace MWGui it = mMessageBoxes.begin(); while(it != mMessageBoxes.end()) { - (*it)->update(height); + (*it)->update(static_cast(height)); height += (*it)->getHeight(); ++it; } diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index b03bf758a..97dbfbafc 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -203,7 +203,7 @@ namespace MWGui void RaceDialog::onHeadRotate(MyGUI::ScrollBar* scroll, size_t _position) { - float angle = (float(_position) / (scroll->getScrollRange()-1) - 0.5) * 3.14 * 2; + float angle = (float(_position) / (scroll->getScrollRange()-1) - 0.5f) * 3.14f * 2; mPreview->update (angle); mPreviewDirty = true; mCurrentAngle = angle; @@ -404,7 +404,7 @@ namespace MWGui skillWidget = mSkillList->createWidget("MW_StatNameValue", coord1, MyGUI::Align::Default, std::string("Skill") + MyGUI::utility::toString(i)); skillWidget->setSkillNumber(skillId); - skillWidget->setSkillValue(Widgets::MWSkill::SkillValue(race->mData.mBonus[i].mBonus)); + skillWidget->setSkillValue(Widgets::MWSkill::SkillValue(static_cast(race->mData.mBonus[i].mBonus))); ToolTips::createSkillToolTip(skillWidget, skillId); diff --git a/apps/openmw/mwgui/recharge.cpp b/apps/openmw/mwgui/recharge.cpp index 2c854a8f5..1af31373c 100644 --- a/apps/openmw/mwgui/recharge.cpp +++ b/apps/openmw/mwgui/recharge.cpp @@ -119,7 +119,7 @@ void Recharge::updateView() Widgets::MWDynamicStatPtr chargeWidget = mView->createWidget ("MW_ChargeBar", MyGUI::IntCoord(72, currentY+2, 199, 20), MyGUI::Align::Default); - chargeWidget->setValue(iter->getCellRef().getEnchantmentCharge(), enchantment->mData.mCharge); + chargeWidget->setValue(static_cast(iter->getCellRef().getEnchantmentCharge()), enchantment->mData.mCharge); chargeWidget->setNeedMouseFocus(false); currentY += 32 + 4; @@ -149,11 +149,11 @@ void Recharge::onItemClicked(MyGUI::Widget *sender) MWMechanics::CreatureStats& stats = player.getClass().getCreatureStats(player); MWMechanics::NpcStats& npcStats = player.getClass().getNpcStats(player); - float luckTerm = 0.1 * stats.getAttribute(ESM::Attribute::Luck).getModified(); + float luckTerm = 0.1f * stats.getAttribute(ESM::Attribute::Luck).getModified(); if (luckTerm < 1|| luckTerm > 10) luckTerm = 1; - float intelligenceTerm = 0.2 * stats.getAttribute(ESM::Attribute::Intelligence).getModified(); + float intelligenceTerm = 0.2f * stats.getAttribute(ESM::Attribute::Intelligence).getModified(); if (intelligenceTerm > 20) intelligenceTerm = 20; @@ -161,7 +161,7 @@ void Recharge::onItemClicked(MyGUI::Widget *sender) intelligenceTerm = 1; float x = (npcStats.getSkill(ESM::Skill::Enchant).getModified() + intelligenceTerm + luckTerm) * stats.getFatigueTerm(); - int roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 100; // [0, 99] + int roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 100); // [0, 99] if (roll < x) { std::string soul = gem.getCellRef().getSoul(); @@ -197,10 +197,10 @@ void Recharge::onItemClicked(MyGUI::Widget *sender) void Recharge::onMouseWheel(MyGUI::Widget* _sender, int _rel) { - if (mView->getViewOffset().top + _rel*0.3 > 0) + if (mView->getViewOffset().top + _rel*0.3f > 0) mView->setViewOffset(MyGUI::IntPoint(0, 0)); else - mView->setViewOffset(MyGUI::IntPoint(0, mView->getViewOffset().top + _rel*0.3)); + mView->setViewOffset(MyGUI::IntPoint(0, static_cast(mView->getViewOffset().top + _rel*0.3f))); } } diff --git a/apps/openmw/mwgui/review.cpp b/apps/openmw/mwgui/review.cpp index 1bcd2d31a..47c7cef21 100644 --- a/apps/openmw/mwgui/review.cpp +++ b/apps/openmw/mwgui/review.cpp @@ -146,21 +146,21 @@ namespace MWGui void ReviewDialog::setHealth(const MWMechanics::DynamicStat& value) { - mHealth->setValue(value.getCurrent(), value.getModified()); + mHealth->setValue(static_cast(value.getCurrent()), static_cast(value.getModified())); std::string valStr = MyGUI::utility::toString(value.getCurrent()) + "/" + MyGUI::utility::toString(value.getModified()); mHealth->setUserString("Caption_HealthDescription", "#{sHealthDesc}\n" + valStr); } void ReviewDialog::setMagicka(const MWMechanics::DynamicStat& value) { - mMagicka->setValue(value.getCurrent(), value.getModified()); + mMagicka->setValue(static_cast(value.getCurrent()), static_cast(value.getModified())); std::string valStr = MyGUI::utility::toString(value.getCurrent()) + "/" + MyGUI::utility::toString(value.getModified()); mMagicka->setUserString("Caption_HealthDescription", "#{sIntDesc}\n" + valStr); } void ReviewDialog::setFatigue(const MWMechanics::DynamicStat& value) { - mFatigue->setValue(value.getCurrent(), value.getModified()); + mFatigue->setValue(static_cast(value.getCurrent()), static_cast(value.getModified())); std::string valStr = MyGUI::utility::toString(value.getCurrent()) + "/" + MyGUI::utility::toString(value.getModified()); mFatigue->setUserString("Caption_HealthDescription", "#{sFatDesc}\n" + valStr); } @@ -180,7 +180,7 @@ namespace MWGui MyGUI::TextBox* widget = mSkillWidgetMap[skillId]; if (widget) { - float modified = value.getModified(), base = value.getBase(); + float modified = static_cast(value.getModified()), base = static_cast(value.getBase()); std::string text = MyGUI::utility::toString(std::floor(modified)); std::string state = "normal"; if (modified > base) @@ -376,7 +376,7 @@ namespace MWGui if (mSkillView->getViewOffset().top + _rel*0.3 > 0) mSkillView->setViewOffset(MyGUI::IntPoint(0, 0)); else - mSkillView->setViewOffset(MyGUI::IntPoint(0, mSkillView->getViewOffset().top + _rel*0.3)); + mSkillView->setViewOffset(MyGUI::IntPoint(0, static_cast(mSkillView->getViewOffset().top + _rel*0.3))); } } diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 301e9de7e..5bb82bc69 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -152,7 +152,7 @@ namespace MWGui } else { - int value = Settings::Manager::getFloat(getSettingName(current), getSettingCategory(current)); + int value = Settings::Manager::getInt(getSettingName(current), getSettingCategory(current)); scroll->setScrollPosition(value); } scroll->eventScrollChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onSliderChangePosition); @@ -557,10 +557,10 @@ namespace MWGui void SettingsWindow::onInputTabMouseWheel(MyGUI::Widget* _sender, int _rel) { - if (mControlsBox->getViewOffset().top + _rel*0.3 > 0) + if (mControlsBox->getViewOffset().top + _rel*0.3f > 0) mControlsBox->setViewOffset(MyGUI::IntPoint(0, 0)); else - mControlsBox->setViewOffset(MyGUI::IntPoint(0, mControlsBox->getViewOffset().top + _rel*0.3)); + mControlsBox->setViewOffset(MyGUI::IntPoint(0, static_cast(mControlsBox->getViewOffset().top + _rel*0.3f))); } void SettingsWindow::onResetDefaultBindings(MyGUI::Widget* _sender) diff --git a/apps/openmw/mwgui/spellbuyingwindow.cpp b/apps/openmw/mwgui/spellbuyingwindow.cpp index 54094b606..57b02940e 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.cpp +++ b/apps/openmw/mwgui/spellbuyingwindow.cpp @@ -46,7 +46,7 @@ namespace MWGui MWBase::Environment::get().getWorld()->getStore(); const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get().find(spellId); - int price = spell->mData.mCost*store.get().find("fSpellValueMult")->getFloat(); + int price = static_cast(spell->mData.mCost*store.get().find("fSpellValueMult")->getFloat()); price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr,price,true); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); @@ -187,7 +187,7 @@ namespace MWGui if (mSpellsView->getViewOffset().top + _rel*0.3 > 0) mSpellsView->setViewOffset(MyGUI::IntPoint(0, 0)); else - mSpellsView->setViewOffset(MyGUI::IntPoint(0, mSpellsView->getViewOffset().top + _rel*0.3)); + mSpellsView->setViewOffset(MyGUI::IntPoint(0, static_cast(mSpellsView->getViewOffset().top + _rel*0.3f))); } } diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index 2757b7cae..c744d3ed6 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -440,14 +440,14 @@ namespace MWGui for (std::vector::const_iterator it = mEffects.begin(); it != mEffects.end(); ++it) { - float x = 0.5 * (it->mMagnMin + it->mMagnMax); + float x = 0.5f * (it->mMagnMin + it->mMagnMax); const ESM::MagicEffect* effect = store.get().find(it->mEffectID); - x *= 0.1 * effect->mData.mBaseCost; + x *= 0.1f * effect->mData.mBaseCost; x *= 1 + it->mDuration; - x += 0.05 * std::max(1, it->mArea) * effect->mData.mBaseCost; + x += 0.05f * std::max(1, it->mArea) * effect->mData.mBaseCost; float fEffectCostMult = store.get().find("fEffectCostMult")->getFloat(); @@ -471,7 +471,7 @@ namespace MWGui float fSpellMakingValueMult = store.get().find("fSpellMakingValueMult")->getFloat(); - int price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr,int(y) * fSpellMakingValueMult,true); + int price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr, static_cast(y * fSpellMakingValueMult),true); mPriceLabel->setCaption(MyGUI::utility::toString(int(price))); diff --git a/apps/openmw/mwgui/spellicons.cpp b/apps/openmw/mwgui/spellicons.cpp index 20c6f3ba8..c597cfaeb 100644 --- a/apps/openmw/mwgui/spellicons.cpp +++ b/apps/openmw/mwgui/spellicons.cpp @@ -30,7 +30,7 @@ namespace MWGui { MagicEffectInfo newEffectSource; newEffectSource.mKey = key; - newEffectSource.mMagnitude = magnitude; + newEffectSource.mMagnitude = static_cast(magnitude); newEffectSource.mPermanent = mIsPermanent; newEffectSource.mRemainingTime = remainingTime; newEffectSource.mSource = sourceName; diff --git a/apps/openmw/mwgui/spellmodel.cpp b/apps/openmw/mwgui/spellmodel.cpp index 4713720cd..91512a011 100644 --- a/apps/openmw/mwgui/spellmodel.cpp +++ b/apps/openmw/mwgui/spellmodel.cpp @@ -103,7 +103,7 @@ namespace MWGui && item.getClass().canBeEquipped(item, mActor).first == 0) continue; - int castCost = MWMechanics::getEffectiveEnchantmentCastCost(enchant->mData.mCost, mActor); + int castCost = MWMechanics::getEffectiveEnchantmentCastCost(static_cast(enchant->mData.mCost), mActor); std::string cost = boost::lexical_cast(castCost); int currentCharge = int(item.getCellRef().getEnchantmentCharge()); diff --git a/apps/openmw/mwgui/spellview.cpp b/apps/openmw/mwgui/spellview.cpp index 1c17a11f6..668b239bc 100644 --- a/apps/openmw/mwgui/spellview.cpp +++ b/apps/openmw/mwgui/spellview.cpp @@ -236,10 +236,10 @@ namespace MWGui void SpellView::onMouseWheel(MyGUI::Widget* _sender, int _rel) { - if (mScrollView->getViewOffset().top + _rel*0.3 > 0) + if (mScrollView->getViewOffset().top + _rel*0.3f > 0) mScrollView->setViewOffset(MyGUI::IntPoint(0, 0)); else - mScrollView->setViewOffset(MyGUI::IntPoint(0, mScrollView->getViewOffset().top + _rel*0.3)); + mScrollView->setViewOffset(MyGUI::IntPoint(0, static_cast(mScrollView->getViewOffset().top + _rel*0.3f))); } } diff --git a/apps/openmw/mwgui/statswindow.cpp b/apps/openmw/mwgui/statswindow.cpp index 2a22f4239..cb1bf6f37 100644 --- a/apps/openmw/mwgui/statswindow.cpp +++ b/apps/openmw/mwgui/statswindow.cpp @@ -80,13 +80,13 @@ namespace MWGui if (mSkillView->getViewOffset().top + _rel*0.3 > 0) mSkillView->setViewOffset(MyGUI::IntPoint(0, 0)); else - mSkillView->setViewOffset(MyGUI::IntPoint(0, mSkillView->getViewOffset().top + _rel*0.3)); + mSkillView->setViewOffset(MyGUI::IntPoint(0, static_cast(mSkillView->getViewOffset().top + _rel*0.3))); } void StatsWindow::onWindowResize(MyGUI::Window* window) { - mLeftPane->setCoord( MyGUI::IntCoord(0, 0, 0.44*window->getSize().width, window->getSize().height) ); - mRightPane->setCoord( MyGUI::IntCoord(0.44*window->getSize().width, 0, 0.56*window->getSize().width, window->getSize().height) ); + mLeftPane->setCoord( MyGUI::IntCoord(0, 0, static_cast(0.44*window->getSize().width), window->getSize().height) ); + mRightPane->setCoord( MyGUI::IntCoord(static_cast(0.44*window->getSize().width), 0, static_cast(0.56*window->getSize().width), window->getSize().height) ); // Canvas size must be expressed with VScroll disabled, otherwise MyGUI would expand the scroll area when the scrollbar is hidden mSkillView->setVisibleVScroll(false); mSkillView->setCanvasSize (mSkillView->getWidth(), mSkillView->getCanvasSize().height); diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 2c10004a6..4e03b788a 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -308,7 +308,7 @@ namespace MWGui void ToolTips::position(MyGUI::IntPoint& position, MyGUI::IntSize size, MyGUI::IntSize viewportSize) { position += MyGUI::IntPoint(0, 32) - - MyGUI::IntPoint((MyGUI::InputManager::getInstance().getMousePosition().left / float(viewportSize.width) * size.width), 0); + - MyGUI::IntPoint(static_cast(MyGUI::InputManager::getInstance().getMousePosition().left / float(viewportSize.width) * size.width), 0); if ((position.left + size.width) > viewportSize.width) { @@ -413,7 +413,7 @@ namespace MWGui { MyGUI::ImageBox* icon = mDynamicToolTipBox->createWidget("MarkerButton", MyGUI::IntCoord(padding.left, totalSize.height+padding.top, 8, 8), MyGUI::Align::Default); - icon->setColour(MyGUI::Colour(1.0,0.3,0.3)); + icon->setColour(MyGUI::Colour(1.0f, 0.3f, 0.3f)); MyGUI::EditBox* edit = mDynamicToolTipBox->createWidget("SandText", MyGUI::IntCoord(padding.left+8+4, totalSize.height+padding.top, 300-padding.left-8-4, 300-totalSize.height), MyGUI::Align::Default); diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 40cf3e9bf..5015ef456 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -34,18 +34,21 @@ namespace int getEffectiveValue (MWWorld::Ptr item, int count) { - int price = item.getClass().getValue(item) * count; + float price = item.getClass().getValue(item); if (item.getClass().hasItemHealth(item)) - price *= (static_cast(item.getClass().getItemHealth(item)) / item.getClass().getItemMaxHealth(item)); - return price; + { + price *= item.getClass().getItemHealth(item); + price /= item.getClass().getItemMaxHealth(item); + } + return static_cast(price * count); } } namespace MWGui { - const float TradeWindow::sBalanceChangeInitialPause = 0.5; - const float TradeWindow::sBalanceChangeInterval = 0.1; + const float TradeWindow::sBalanceChangeInitialPause = 0.5f; + const float TradeWindow::sBalanceChangeInterval = 0.1f; TradeWindow::TradeWindow() : WindowBase("openmw_trade_window.layout") @@ -340,16 +343,16 @@ namespace MWGui else d = int(100 * (b - a) / a); - float clampedDisposition = std::max(0,std::min(int(MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mPtr) - + MWBase::Environment::get().getDialogueManager()->getTemporaryDispositionChange()),100)); + float clampedDisposition = std::max(0,std::min(MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mPtr) + + MWBase::Environment::get().getDialogueManager()->getTemporaryDispositionChange(),100)); const MWMechanics::CreatureStats &sellerStats = mPtr.getClass().getCreatureStats(mPtr); const MWMechanics::CreatureStats &playerStats = player.getClass().getCreatureStats(player); - float a1 = player.getClass().getSkill(player, ESM::Skill::Mercantile); + float a1 = static_cast(player.getClass().getSkill(player, ESM::Skill::Mercantile)); float b1 = 0.1f * playerStats.getAttribute(ESM::Attribute::Luck).getModified(); float c1 = 0.2f * playerStats.getAttribute(ESM::Attribute::Personality).getModified(); - float d1 = mPtr.getClass().getSkill(mPtr, ESM::Skill::Mercantile); + float d1 = static_cast(mPtr.getClass().getSkill(mPtr, ESM::Skill::Mercantile)); float e1 = 0.1f * sellerStats.getAttribute(ESM::Attribute::Luck).getModified(); float f1 = 0.2f * sellerStats.getAttribute(ESM::Attribute::Personality).getModified(); @@ -379,9 +382,9 @@ namespace MWGui int finalPrice = std::abs(mCurrentBalance); int initialMerchantOffer = std::abs(mCurrentMerchantOffer); if (!buying && (finalPrice > initialMerchantOffer) && finalPrice > 0) - skillGain = int(100 * (finalPrice - initialMerchantOffer) / float(finalPrice)); + skillGain = floor(100 * (finalPrice - initialMerchantOffer) / float(finalPrice)); else if (buying && (finalPrice < initialMerchantOffer) && initialMerchantOffer > 0) - skillGain = int(100 * (initialMerchantOffer - finalPrice) / float(initialMerchantOffer)); + skillGain = floor(100 * (initialMerchantOffer - finalPrice) / float(initialMerchantOffer)); player.getClass().skillUsageSucceeded(player, ESM::Skill::Mercantile, 0, skillGain); } diff --git a/apps/openmw/mwgui/trainingwindow.cpp b/apps/openmw/mwgui/trainingwindow.cpp index 5a5f61115..6376ced57 100644 --- a/apps/openmw/mwgui/trainingwindow.cpp +++ b/apps/openmw/mwgui/trainingwindow.cpp @@ -40,7 +40,7 @@ namespace MWGui TrainingWindow::TrainingWindow() : WindowBase("openmw_trainingwindow.layout") , mFadeTimeRemaining(0) - , mTimeAdvancer(0.05) + , mTimeAdvancer(0.05f) { getWidget(mTrainingOptions, "TrainingOptions"); getWidget(mCancelButton, "CancelButton"); diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index 50e08223e..6a45e6026 100644 --- a/apps/openmw/mwgui/travelwindow.cpp +++ b/apps/openmw/mwgui/travelwindow.cpp @@ -66,13 +66,13 @@ namespace MWGui if(interior) { - price = gmst.find("fMagesGuildTravel")->getFloat(); + price = gmst.find("fMagesGuildTravel")->getInt(); } else { ESM::Position PlayerPos = player.getRefData().getPosition(); float d = sqrt( pow(pos.pos[0] - PlayerPos.pos[0],2) + pow(pos.pos[1] - PlayerPos.pos[1],2) + pow(pos.pos[2] - PlayerPos.pos[2],2) ); - price = d/gmst.find("fTravelMult")->getFloat(); + price = static_cast(d / gmst.find("fTravelMult")->getFloat()); } price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr,price,true); @@ -209,10 +209,10 @@ namespace MWGui void TravelWindow::onMouseWheel(MyGUI::Widget* _sender, int _rel) { - if (mDestinationsView->getViewOffset().top + _rel*0.3 > 0) + if (mDestinationsView->getViewOffset().top + _rel*0.3f > 0) mDestinationsView->setViewOffset(MyGUI::IntPoint(0, 0)); else - mDestinationsView->setViewOffset(MyGUI::IntPoint(0, mDestinationsView->getViewOffset().top + _rel*0.3)); + mDestinationsView->setViewOffset(MyGUI::IntPoint(0, static_cast(mDestinationsView->getViewOffset().top + _rel*0.3f))); } } diff --git a/apps/openmw/mwgui/videowidget.cpp b/apps/openmw/mwgui/videowidget.cpp index 046070841..f865de377 100644 --- a/apps/openmw/mwgui/videowidget.cpp +++ b/apps/openmw/mwgui/videowidget.cpp @@ -58,8 +58,8 @@ void VideoWidget::autoResize(bool stretch) { double imageaspect = static_cast(getVideoWidth())/getVideoHeight(); - int leftPadding = std::max(0.0, (screenSize.width - screenSize.height * imageaspect) / 2); - int topPadding = std::max(0.0, (screenSize.height - screenSize.width / imageaspect) / 2); + int leftPadding = std::max(0, static_cast(screenSize.width - screenSize.height * imageaspect) / 2); + int topPadding = std::max(0, static_cast(screenSize.height - screenSize.width / imageaspect) / 2); setCoord(leftPadding, topPadding, screenSize.width - leftPadding*2, screenSize.height - topPadding*2); diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index ad873a7c3..b73ab38f2 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -49,7 +49,7 @@ namespace MWGui WaitDialog::WaitDialog() : WindowBase("openmw_wait_dialog.layout") , mProgressBar() - , mTimeAdvancer(0.05) + , mTimeAdvancer(0.05f) , mSleeping(false) , mHours(1) , mManualHours(1) @@ -104,7 +104,7 @@ namespace MWGui mHourSlider->setScrollPosition (0); std::string month = MWBase::Environment::get().getWorld ()->getMonthName(); - int hour = MWBase::Environment::get().getWorld ()->getTimeStamp ().getHour (); + int hour = static_cast(MWBase::Environment::get().getWorld()->getTimeStamp().getHour()); bool pm = hour >= 12; if (hour >= 13) hour -= 12; if (hour == 0) hour = 12; @@ -135,8 +135,8 @@ namespace MWGui MWBase::Environment::get().getStateManager()->quickSave("Autosave"); MWBase::World* world = MWBase::Environment::get().getWorld(); - MWBase::Environment::get().getWindowManager()->fadeScreenOut(0.2); - mFadeTimeRemaining = 0.4; + MWBase::Environment::get().getWindowManager()->fadeScreenOut(0.2f); + mFadeTimeRemaining = 0.4f; setVisible(false); mHours = hoursToWait; @@ -153,7 +153,7 @@ namespace MWGui if (!region->mSleepList.empty()) { float fSleepRandMod = world->getStore().get().find("fSleepRandMod")->getFloat(); - int x = std::rand()/ (static_cast (RAND_MAX) + 1) * hoursToWait; // [0, hoursRested] + int x = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * hoursToWait); // [0, hoursRested] float y = fSleepRandMod * hoursToWait; if (x > y) { @@ -251,7 +251,7 @@ namespace MWGui void WaitDialog::stopWaiting () { - MWBase::Environment::get().getWindowManager()->fadeScreenIn(0.2); + MWBase::Environment::get().getWindowManager()->fadeScreenIn(0.2f); mProgressBar.setVisible (false); MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Rest); MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_RestBed); diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index 79c0f93f0..718624a16 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -540,8 +540,8 @@ namespace MWGui MWScrollBar::MWScrollBar() : mEnableRepeat(true) - , mRepeatTriggerTime(0.5) - , mRepeatStepTime(0.1) + , mRepeatTriggerTime(0.5f) + , mRepeatStepTime(0.1f) , mIsIncreasing(true) { } diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index d8074a5d8..815f342a4 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1103,10 +1103,10 @@ namespace MWGui for (std::map::iterator it = mTrackedWindows.begin(); it != mTrackedWindows.end(); ++it) { - MyGUI::IntPoint pos (Settings::Manager::getFloat(it->second + " x", "Windows") * x, - Settings::Manager::getFloat(it->second+ " y", "Windows") * y); - MyGUI::IntSize size (Settings::Manager::getFloat(it->second + " w", "Windows") * x, - Settings::Manager::getFloat(it->second + " h", "Windows") * y); + MyGUI::IntPoint pos(static_cast(Settings::Manager::getFloat(it->second + " x", "Windows") * x), + static_cast( Settings::Manager::getFloat(it->second+ " y", "Windows") * y)); + MyGUI::IntSize size(static_cast(Settings::Manager::getFloat(it->second + " w", "Windows") * x), + static_cast(Settings::Manager::getFloat(it->second + " h", "Windows") * y)); it->first->setPosition(pos); it->first->setSize(size); } @@ -1221,7 +1221,7 @@ namespace MWGui .find(item.getClass().getEnchantment(item)); int chargePercent = (item.getCellRef().getEnchantmentCharge() == -1) ? 100 - : (item.getCellRef().getEnchantmentCharge() / static_cast(ench->mData.mCharge) * 100); + : static_cast(item.getCellRef().getEnchantmentCharge() / static_cast(ench->mData.mCharge) * 100); mHud->setSelectedEnchantItem(item, chargePercent); mSpellWindow->setTitle(item.getClass().getName(item)); } @@ -1229,7 +1229,7 @@ namespace MWGui void WindowManager::setSelectedWeapon(const MWWorld::Ptr& item) { int durabilityPercent = - (item.getClass().getItemHealth(item) / static_cast(item.getClass().getItemMaxHealth(item)) * 100); + static_cast(item.getClass().getItemHealth(item) / static_cast(item.getClass().getItemMaxHealth(item)) * 100); mHud->setSelectedWeapon(item, durabilityPercent); mInventoryWindow->setTitle(item.getClass().getName(item)); } @@ -1262,8 +1262,8 @@ namespace MWGui void WindowManager::getMousePosition(float &x, float &y) { const MyGUI::IntPoint& pos = MyGUI::InputManager::getInstance().getMousePosition(); - x = pos.left; - y = pos.top; + x = static_cast(pos.left); + y = static_cast(pos.top); const MyGUI::IntSize& viewSize = MyGUI::RenderManager::getInstance().getViewSize(); x /= viewSize.width; y /= viewSize.height; @@ -1569,10 +1569,10 @@ namespace MWGui void WindowManager::trackWindow(OEngine::GUI::Layout *layout, const std::string &name) { MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize(); - MyGUI::IntPoint pos (Settings::Manager::getFloat(name + " x", "Windows") * viewSize.width, - Settings::Manager::getFloat(name + " y", "Windows") * viewSize.height); - MyGUI::IntSize size (Settings::Manager::getFloat(name + " w", "Windows") * viewSize.width, - Settings::Manager::getFloat(name + " h", "Windows") * viewSize.height); + MyGUI::IntPoint pos(static_cast(Settings::Manager::getFloat(name + " x", "Windows") * viewSize.width), + static_cast(Settings::Manager::getFloat(name + " y", "Windows") * viewSize.height)); + MyGUI::IntSize size (static_cast(Settings::Manager::getFloat(name + " w", "Windows") * viewSize.width), + static_cast(Settings::Manager::getFloat(name + " h", "Windows") * viewSize.height)); layout->mMainWidget->setPosition(pos); layout->mMainWidget->setSize(size); diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index e84e2c5b3..829ea1482 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -377,7 +377,7 @@ namespace MWInput //cursor is if( !is_relative && was_relative != is_relative ) { - mInputManager->warpMouse(mMouseX, mMouseY); + mInputManager->warpMouse(static_cast(mMouseX), static_cast(mMouseY)); } } @@ -415,13 +415,13 @@ namespace MWInput // game mode does not move the position of the GUI cursor mMouseX += xAxis * dt * 1500.0f; mMouseY += yAxis * dt * 1500.0f; - mMouseWheel -= zAxis * dt * 1500.0f; + mMouseWheel -= static_cast(zAxis * dt * 1500.0f); mMouseX = std::max(0.f, std::min(mMouseX, float(viewSize.width))); mMouseY = std::max(0.f, std::min(mMouseY, float(viewSize.height))); - MyGUI::InputManager::getInstance().injectMouseMove( mMouseX, mMouseY, mMouseWheel); - mInputManager->warpMouse(mMouseX, mMouseY); + MyGUI::InputManager::getInstance().injectMouseMove(static_cast(mMouseX), static_cast(mMouseY), mMouseWheel); + mInputManager->warpMouse(static_cast(mMouseX), static_cast(mMouseY)); } if (mMouseLookEnabled) { @@ -703,7 +703,7 @@ namespace MWInput if (id == SDL_BUTTON_LEFT || id == SDL_BUTTON_RIGHT) // MyGUI only uses these mouse events { guiMode = MWBase::Environment::get().getWindowManager()->isGuiMode(); - guiMode = MyGUI::InputManager::getInstance().injectMousePress(mMouseX, mMouseY, sdlButtonToMyGUI(id)) && guiMode; + guiMode = MyGUI::InputManager::getInstance().injectMousePress(static_cast(mMouseX), static_cast(mMouseY), sdlButtonToMyGUI(id)) && guiMode; if (MyGUI::InputManager::getInstance ().getMouseFocusWidget () != 0) { MyGUI::Button* b = MyGUI::InputManager::getInstance ().getMouseFocusWidget ()->castType(false); @@ -730,7 +730,7 @@ namespace MWInput mInputBinder->mouseReleased (arg, id); } else { bool guiMode = MWBase::Environment::get().getWindowManager()->isGuiMode(); - guiMode = MyGUI::InputManager::getInstance().injectMouseRelease(mMouseX, mMouseY, sdlButtonToMyGUI(id)) && guiMode; + guiMode = MyGUI::InputManager::getInstance().injectMouseRelease(static_cast(mMouseX), static_cast(mMouseY), sdlButtonToMyGUI(id)) && guiMode; if(mInputBinder->detectingBindingState()) return; // don't allow same mouseup to bind as initiated bind @@ -752,8 +752,8 @@ namespace MWInput // We keep track of our own mouse position, so that moving the mouse while in // game mode does not move the position of the GUI cursor - mMouseX = arg.x; - mMouseY = arg.y; + mMouseX = static_cast(arg.x); + mMouseY = static_cast(arg.y); mMouseX = std::max(0.f, std::min(mMouseX, float(viewSize.width))); mMouseY = std::max(0.f, std::min(mMouseY, float(viewSize.height))); @@ -767,8 +767,8 @@ namespace MWInput { resetIdleTime(); - double x = arg.xrel * mCameraSensitivity * (1.0f/256.f); - double y = arg.yrel * mCameraSensitivity * (1.0f/256.f) * (mInvertY ? -1 : 1) * mCameraYMultiplier; + float x = arg.xrel * mCameraSensitivity * (1.0f/256.f); + float y = arg.yrel * mCameraSensitivity * (1.0f/256.f) * (mInvertY ? -1 : 1) * mCameraYMultiplier; float rot[3]; rot[0] = -y; @@ -784,10 +784,10 @@ namespace MWInput if (arg.zrel && mControlSwitch["playerviewswitch"] && mControlSwitch["playercontrols"]) //Check to make sure you are allowed to zoomout and there is a change { - MWBase::Environment::get().getWorld()->changeVanityModeScale(arg.zrel); + MWBase::Environment::get().getWorld()->changeVanityModeScale(static_cast(arg.zrel)); if (Settings::Manager::getBool("allow third person zoom", "Input")) - MWBase::Environment::get().getWorld()->setCameraDistance(arg.zrel, true, true); + MWBase::Environment::get().getWorld()->setCameraDistance(static_cast(arg.zrel), true, true); } } } @@ -802,7 +802,8 @@ namespace MWInput guiMode = MWBase::Environment::get().getWindowManager()->isGuiMode(); if(!mInputBinder->detectingBindingState()) { - guiMode = MyGUI::InputManager::getInstance().injectMousePress(mMouseX, mMouseY, sdlButtonToMyGUI((arg.button == SDL_CONTROLLER_BUTTON_B) ? SDL_BUTTON_RIGHT : SDL_BUTTON_LEFT)) && guiMode; + guiMode = MyGUI::InputManager::getInstance().injectMousePress(static_cast(mMouseX), static_cast(mMouseY), + sdlButtonToMyGUI((arg.button == SDL_CONTROLLER_BUTTON_B) ? SDL_BUTTON_RIGHT : SDL_BUTTON_LEFT)) && guiMode; if (MyGUI::InputManager::getInstance ().getMouseFocusWidget () != 0) { MyGUI::Button* b = MyGUI::InputManager::getInstance ().getMouseFocusWidget ()->castType(false); @@ -833,7 +834,7 @@ namespace MWInput else if(arg.button == SDL_CONTROLLER_BUTTON_A || arg.button == SDL_CONTROLLER_BUTTON_B) { bool guiMode = MWBase::Environment::get().getWindowManager()->isGuiMode(); - guiMode = MyGUI::InputManager::getInstance().injectMouseRelease(mMouseX, mMouseY, sdlButtonToMyGUI((arg.button == SDL_CONTROLLER_BUTTON_B) ? SDL_BUTTON_RIGHT : SDL_BUTTON_LEFT)) && guiMode; + guiMode = MyGUI::InputManager::getInstance().injectMouseRelease(static_cast(mMouseX), static_cast(mMouseY), sdlButtonToMyGUI((arg.button == SDL_CONTROLLER_BUTTON_B) ? SDL_BUTTON_RIGHT : SDL_BUTTON_LEFT)) && guiMode; if(mInputBinder->detectingBindingState()) return; // don't allow same mouseup to bind as initiated bind @@ -1236,10 +1237,7 @@ namespace MWInput bool controlExists = mInputBinder->getChannel(i)->getControlsCount () != 0; if (!controlExists) { - int inital; - if (defaultButtonBindings.find(i) != defaultButtonBindings.end()) - inital = 0.0f; - else inital = 0.5f; + float inital = (defaultButtonBindings.find(i) != defaultButtonBindings.end()) ? 0.0f : 0.5f; control = new ICS::Control(boost::lexical_cast(i), false, true, inital, ICS::ICS_MAX, ICS::ICS_MAX); mInputBinder->addControl(control); control->attachChannel(mInputBinder->getChannel(i), ICS::Channel::DIRECT); diff --git a/apps/openmw/mwmechanics/disease.hpp b/apps/openmw/mwmechanics/disease.hpp index a973c0e35..2f7d65dfd 100644 --- a/apps/openmw/mwmechanics/disease.hpp +++ b/apps/openmw/mwmechanics/disease.hpp @@ -37,19 +37,19 @@ namespace MWMechanics float resist = 0.f; if (spells.hasCorprusEffect(spell)) - resist = 1.f - 0.01 * (actorEffects.get(ESM::MagicEffect::ResistCorprusDisease).getMagnitude() + resist = 1.f - 0.01f * (actorEffects.get(ESM::MagicEffect::ResistCorprusDisease).getMagnitude() - actorEffects.get(ESM::MagicEffect::WeaknessToCorprusDisease).getMagnitude()); else if (spell->mData.mType == ESM::Spell::ST_Disease) - resist = 1.f - 0.01 * (actorEffects.get(ESM::MagicEffect::ResistCommonDisease).getMagnitude() + resist = 1.f - 0.01f * (actorEffects.get(ESM::MagicEffect::ResistCommonDisease).getMagnitude() - actorEffects.get(ESM::MagicEffect::WeaknessToCommonDisease).getMagnitude()); else if (spell->mData.mType == ESM::Spell::ST_Blight) - resist = 1.f - 0.01 * (actorEffects.get(ESM::MagicEffect::ResistBlightDisease).getMagnitude() + resist = 1.f - 0.01f * (actorEffects.get(ESM::MagicEffect::ResistBlightDisease).getMagnitude() - actorEffects.get(ESM::MagicEffect::WeaknessToBlightDisease).getMagnitude()); else continue; - int x = fDiseaseXferChance * 100 * resist; - float roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 10000; // [0, 9999] + int x = static_cast(fDiseaseXferChance * 100 * resist); + float roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 10000); // [0, 9999] if (roll < x) { diff --git a/apps/openmw/mwmechanics/levelledlist.hpp b/apps/openmw/mwmechanics/levelledlist.hpp index db13c1a45..cd1276038 100644 --- a/apps/openmw/mwmechanics/levelledlist.hpp +++ b/apps/openmw/mwmechanics/levelledlist.hpp @@ -22,7 +22,7 @@ namespace MWMechanics failChance += levItem->mChanceNone; - int random = std::rand()/ (static_cast (RAND_MAX) + 1) * 100; // [0, 99] + int random = static_cast(static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 100)); // [0, 99] if (random < failChance) return std::string(); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 4e4a1a8a6..5633ce3b7 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -556,7 +556,7 @@ namespace MWMechanics int MechanicsManager::getDerivedDisposition(const MWWorld::Ptr& ptr) { const MWMechanics::NpcStats& npcSkill = ptr.getClass().getNpcStats(ptr); - float x = npcSkill.getBaseDisposition(); + float x = static_cast(npcSkill.getBaseDisposition()); MWWorld::LiveCellRef* npc = ptr.get(); MWWorld::Ptr playerPtr = MWBase::Environment::get().getWorld()->getPlayerPtr(); @@ -583,7 +583,7 @@ namespace MWMechanics if (!playerStats.getExpelled(npcFaction)) { // faction reaction towards itself. yes, that exists - reaction = MWBase::Environment::get().getDialogueManager()->getFactionReaction(npcFaction, npcFaction); + reaction = static_cast(MWBase::Environment::get().getDialogueManager()->getFactionReaction(npcFaction, npcFaction)); rank = playerStats.getFactionRanks().find(npcFaction)->second; } @@ -597,7 +597,7 @@ namespace MWMechanics int itReaction = MWBase::Environment::get().getDialogueManager()->getFactionReaction(npcFaction, itFaction); if (playerFactionIt == playerStats.getFactionRanks().begin() || itReaction < reaction) - reaction = itReaction; + reaction = static_cast(itReaction); } } else @@ -643,17 +643,17 @@ namespace MWMechanics // otherwise one would get different prices when exiting and re-entering the dialogue window... int clampedDisposition = std::max(0, std::min(getDerivedDisposition(ptr) + MWBase::Environment::get().getDialogueManager()->getTemporaryDispositionChange(),100)); - float a = std::min(playerStats.getSkill(ESM::Skill::Mercantile).getModified(), 100); + float a = static_cast(std::min(playerStats.getSkill(ESM::Skill::Mercantile).getModified(), 100)); float b = std::min(0.1f * playerStats.getAttribute(ESM::Attribute::Luck).getModified(), 10.f); float c = std::min(0.2f * playerStats.getAttribute(ESM::Attribute::Personality).getModified(), 10.f); - float d = std::min(sellerStats.getSkill(ESM::Skill::Mercantile).getModified(), 100); + float d = static_cast(std::min(sellerStats.getSkill(ESM::Skill::Mercantile).getModified(), 100)); float e = std::min(0.1f * sellerStats.getAttribute(ESM::Attribute::Luck).getModified(), 10.f); float f = std::min(0.2f * sellerStats.getAttribute(ESM::Attribute::Personality).getModified(), 10.f); float pcTerm = (clampedDisposition - 50 + a + b + c) * playerStats.getFatigueTerm(); float npcTerm = (d + e + f) * sellerStats.getFatigueTerm(); - float buyTerm = 0.01 * (100 - 0.5 * (pcTerm - npcTerm)); - float sellTerm = 0.01 * (50 - 0.5 * (npcTerm - pcTerm)); + float buyTerm = 0.01f * (100 - 0.5f * (pcTerm - npcTerm)); + float sellTerm = 0.01f * (50 - 0.5f * (npcTerm - pcTerm)); float x; if(buying) x = buyTerm; @@ -704,7 +704,7 @@ namespace MWMechanics int currentDisposition = std::min(100, std::max(0, int(getDerivedDisposition(npc) + currentTemporaryDispositionDelta))); - float d = 1 - 0.02 * abs(currentDisposition - 50); + float d = 1 - 0.02f * abs(currentDisposition - 50); float target1 = d * (playerRating1 - npcRating1 + 50); float target2 = d * (playerRating2 - npcRating2 + 50); @@ -715,8 +715,8 @@ namespace MWMechanics float target3 = d * (playerRating3 - npcRating3 + 50) + bribeMod; - float iPerMinChance = gmst.find("iPerMinChance")->getInt(); - float iPerMinChange = gmst.find("iPerMinChange")->getInt(); + float iPerMinChance = floor(gmst.find("iPerMinChance")->getFloat()); + float iPerMinChange = floor(gmst.find("iPerMinChange")->getFloat()); float fPerDieRollMult = gmst.find("fPerDieRollMult")->getFloat(); float fPerTempMult = gmst.find("fPerTempMult")->getFloat(); @@ -729,7 +729,7 @@ namespace MWMechanics { target1 = std::max(iPerMinChance, target1); success = (roll <= target1); - float c = int(fPerDieRollMult * (target1 - roll)); + float c = floor(fPerDieRollMult * (target1 - roll)); x = success ? std::max(iPerMinChange, c) : c; } else if (type == PT_Intimidate) @@ -740,13 +740,13 @@ namespace MWMechanics float r; if (roll != target2) - r = int(target2 - roll); + r = floor(target2 - roll); else r = 1; if (roll <= target2) { - float s = int(r * fPerDieRollMult * fPerTempMult); + float s = floor(r * fPerDieRollMult * fPerTempMult); int flee = npcStats.getAiSetting(MWMechanics::CreatureStats::AI_Flee).getBase(); int fight = npcStats.getAiSetting(MWMechanics::CreatureStats::AI_Fight).getBase(); @@ -756,7 +756,7 @@ namespace MWMechanics std::max(0, std::min(100, fight + int(std::min(-iPerMinChange, -s))))); } - float c = -std::abs(int(r * fPerDieRollMult)); + float c = -std::abs(floor(r * fPerDieRollMult)); if (success) { if (std::abs(c) < iPerMinChange) @@ -766,13 +766,13 @@ namespace MWMechanics } else { - x = -int(c * fPerTempMult); + x = -floor(c * fPerTempMult); y = c; } } else { - x = int(c * fPerTempMult); + x = floor(c * fPerTempMult); y = c; } } @@ -781,7 +781,7 @@ namespace MWMechanics target1 = std::max(iPerMinChance, target1); success = (roll <= target1); - float c = std::abs(int(target1 - roll)); + float c = std::abs(floor(target1 - roll)); if (success) { @@ -793,7 +793,7 @@ namespace MWMechanics npcStats.setAiSetting (CreatureStats::AI_Fight, std::max(0, std::min(100, fight + std::max(int(iPerMinChange), int(s))))); } - x = int(-c * fPerDieRollMult); + x = floor(-c * fPerDieRollMult); if (success && std::abs(x) < iPerMinChange) x = -iPerMinChange; @@ -802,7 +802,7 @@ namespace MWMechanics { target3 = std::max(iPerMinChance, target3); success = (roll <= target3); - float c = int((target3 - roll) * fPerDieRollMult); + float c = floor((target3 - roll) * fPerDieRollMult); x = success ? std::max(iPerMinChange, c) : c; } @@ -812,11 +812,11 @@ namespace MWMechanics float cappedDispositionChange = tempChange; if (currentDisposition + tempChange > 100.f) - cappedDispositionChange = 100 - currentDisposition; + cappedDispositionChange = static_cast(100 - currentDisposition); if (currentDisposition + tempChange < 0.f) - cappedDispositionChange = -currentDisposition; + cappedDispositionChange = static_cast(-currentDisposition); - permChange = int(cappedDispositionChange / fPerTempMult); + permChange = floor(cappedDispositionChange / fPerTempMult); if (type == PT_Intimidate) { permChange = success ? -int(cappedDispositionChange/ fPerTempMult) : y; @@ -1104,7 +1104,7 @@ namespace MWMechanics if (type == OT_Trespassing || type == OT_SleepingInOwnedBed) { arg = store.find("iCrimeTresspass")->getInt(); - disp = dispVictim = store.find("iDispTresspass")->getInt(); + disp = dispVictim = store.find("iDispTresspass")->getFloat(); } else if (type == OT_Pickpocket) { @@ -1114,18 +1114,18 @@ namespace MWMechanics else if (type == OT_Assault) { arg = store.find("iCrimeAttack")->getInt(); - disp = store.find("iDispAttackMod")->getInt(); + disp = store.find("iDispAttackMod")->getFloat(); dispVictim = store.find("fDispAttacking")->getFloat(); } else if (type == OT_Murder) { arg = store.find("iCrimeKilling")->getInt(); - disp = dispVictim = store.find("iDispKilling")->getInt(); + disp = dispVictim = store.find("iDispKilling")->getFloat(); } else if (type == OT_Theft) { disp = dispVictim = store.find("fDispStealing")->getFloat() * arg; - arg *= store.find("fCrimeStealing")->getFloat(); + arg = static_cast(arg * store.find("fCrimeStealing")->getFloat()); arg = std::max(1, arg); // Minimum bounty of 1, in case items with zero value are stolen } @@ -1163,7 +1163,7 @@ namespace MWMechanics else if (type == OT_Murder) fight = fightVictim = esmStore.get().find("iFightKilling")->getInt(); else if (type == OT_Theft) - fight = fightVictim = esmStore.get().find("fFightStealing")->getFloat(); + fight = fightVictim = esmStore.get().find("fFightStealing")->getInt(); bool reported = false; @@ -1197,21 +1197,21 @@ namespace MWMechanics { float dispTerm = (*it == victim) ? dispVictim : disp; - float alarmTerm = 0.01 * it->getClass().getCreatureStats(*it).getAiSetting(CreatureStats::AI_Alarm).getBase(); + float alarmTerm = 0.01f * it->getClass().getCreatureStats(*it).getAiSetting(CreatureStats::AI_Alarm).getBase(); if (type == OT_Pickpocket && alarmTerm <= 0) alarmTerm = 1.0; if (*it != victim) dispTerm *= alarmTerm; - float fightTerm = (*it == victim) ? fightVictim : fight; + float fightTerm = static_cast((*it == victim) ? fightVictim : fight); fightTerm += getFightDispositionBias(dispTerm); fightTerm += getFightDistanceBias(*it, player); fightTerm *= alarmTerm; int observerFightRating = it->getClass().getCreatureStats(*it).getAiSetting(CreatureStats::AI_Fight).getBase(); if (observerFightRating + fightTerm > 100) - fightTerm = 100 - observerFightRating; + fightTerm = static_cast(100 - observerFightRating); fightTerm = std::max(0.f, fightTerm); if (observerFightRating + fightTerm >= 100) @@ -1221,9 +1221,9 @@ namespace MWMechanics NpcStats& observerStats = it->getClass().getNpcStats(*it); // Apply aggression value to the base Fight rating, so that the actor can continue fighting // after a Calm spell wears off - observerStats.setAiSetting(CreatureStats::AI_Fight, observerFightRating + fightTerm); + observerStats.setAiSetting(CreatureStats::AI_Fight, observerFightRating + static_cast(fightTerm)); - observerStats.setBaseDisposition(observerStats.getBaseDisposition()+dispTerm); + observerStats.setBaseDisposition(observerStats.getBaseDisposition() + static_cast(dispTerm)); // Set the crime ID, which we will use to calm down participants // once the bounty has been paid. @@ -1334,7 +1334,7 @@ namespace MWMechanics { static float fSneakSkillMult = store.find("fSneakSkillMult")->getFloat(); static float fSneakBootMult = store.find("fSneakBootMult")->getFloat(); - float sneak = ptr.getClass().getSkill(ptr, ESM::Skill::Sneak); + float sneak = static_cast(ptr.getClass().getSkill(ptr, ESM::Skill::Sneak)); int agility = stats.getAttribute(ESM::Attribute::Agility).getModified(); int luck = stats.getAttribute(ESM::Attribute::Luck).getModified(); float bootWeight = 0; @@ -1345,7 +1345,7 @@ namespace MWMechanics if (it != inv.end()) bootWeight = it->getClass().getWeight(*it); } - sneakTerm = fSneakSkillMult * sneak + 0.2 * agility + 0.1 * luck + bootWeight * fSneakBootMult; + sneakTerm = fSneakSkillMult * sneak + 0.2f * agility + 0.1f * luck + bootWeight * fSneakBootMult; } static float fSneakDistBase = store.find("fSneakDistanceBase")->getFloat(); @@ -1364,7 +1364,7 @@ namespace MWMechanics float obsBlind = observerStats.getMagicEffects().get(ESM::MagicEffect::Blind).getMagnitude(); int obsSneak = observer.getClass().getSkill(observer, ESM::Skill::Sneak); - float obsTerm = obsSneak + 0.2 * obsAgility + 0.1 * obsLuck - obsBlind; + float obsTerm = obsSneak + 0.2f * obsAgility + 0.1f * obsLuck - obsBlind; // is ptr behind the observer? static float fSneakNoViewMult = store.find("fSneakNoViewMult")->getFloat(); @@ -1378,7 +1378,7 @@ namespace MWMechanics y = obsTerm * observerStats.getFatigueTerm() * fSneakViewMult; float target = x - y; - int roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 100; // [0, 99] + int roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 100); // [0, 99] return (roll >= target); } @@ -1479,9 +1479,8 @@ namespace MWMechanics if (ptr.getClass().isNpc()) disposition = getDerivedDisposition(ptr); - int fight = std::max(0.f, ptr.getClass().getCreatureStats(ptr).getAiSetting(CreatureStats::AI_Fight).getModified() - + getFightDistanceBias(ptr, target) - + getFightDispositionBias(disposition)); + int fight = std::max(0, ptr.getClass().getCreatureStats(ptr).getAiSetting(CreatureStats::AI_Fight).getModified() + + static_cast(getFightDistanceBias(ptr, target) + getFightDispositionBias(disposition))); if (ptr.getClass().isNpc() && target.getClass().isNpc()) { diff --git a/apps/openmw/mwmechanics/stat.hpp b/apps/openmw/mwmechanics/stat.hpp index 294dbcb6c..5c41e007e 100644 --- a/apps/openmw/mwmechanics/stat.hpp +++ b/apps/openmw/mwmechanics/stat.hpp @@ -251,7 +251,6 @@ namespace MWMechanics void damage(float damage) { mDamage = std::min(mDamage + damage, (float)(mBase + mFortified)); } void restore(float amount) { mDamage -= std::min(mDamage, amount); } - int getDamage() const { return mDamage; } void writeState (ESM::StatState& state) const; diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 01a88faf2..871561bdc 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -365,7 +365,7 @@ void Animation::addExtraLight(Ogre::SceneManager *sceneMgr, NifOgre::ObjectScene // with the standard 1 / (c + d*l + d*d*q) equation the attenuation factor never becomes zero, // so we ignore lights if their attenuation falls below this factor. - const float threshold = 0.03; + const float threshold = 0.03f; float quadraticAttenuation = 0; float linearAttenuation = 0; @@ -1477,7 +1477,7 @@ void Animation::setLightEffect(float effect) } mGlowLight->setType(Ogre::Light::LT_POINT); effect += 3; - mGlowLight->setAttenuation(1.0f / (0.03 * (0.5/effect)), 0, 0.5/effect, 0); + mGlowLight->setAttenuation(1.0f / (0.03f * (0.5f/effect)), 0, 0.5f/effect, 0); } } diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 756c79ad8..8071dd5fd 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -69,13 +69,13 @@ namespace MWRender /// \todo Read the fallback values from INIImporter (Inventory:Directional*) l = mSceneMgr->createLight(); l->setType (Ogre::Light::LT_DIRECTIONAL); - l->setDirection (Ogre::Vector3(0.3, -0.7, 0.3)); + l->setDirection (Ogre::Vector3(0.3f, -0.7f, 0.3f)); l->setDiffuseColour (Ogre::ColourValue(1,1,1)); mSceneMgr->setAmbientLight (Ogre::ColourValue(0.25, 0.25, 0.25)); mCamera = mSceneMgr->createCamera (mName); - mCamera->setFOVy(Ogre::Degree(12.3)); + mCamera->setFOVy(Ogre::Degree(12.3f)); mCamera->setAspectRatio (float(mSizeX) / float(mSizeY)); Ogre::SceneNode* renderRoot = mSceneMgr->getRootSceneNode()->createChildSceneNode("renderRoot"); diff --git a/apps/openmw/mwrender/globalmap.cpp b/apps/openmw/mwrender/globalmap.cpp index de78748b5..95d4429d6 100644 --- a/apps/openmw/mwrender/globalmap.cpp +++ b/apps/openmw/mwrender/globalmap.cpp @@ -86,8 +86,8 @@ namespace MWRender { for (int cellX=0; cellX(float(cellX)/float(mCellSize) * 9); + int vertexY = static_cast(float(cellY) / float(mCellSize) * 9); int texelX = (x-mMinX) * mCellSize + cellX; @@ -102,9 +102,9 @@ namespace MWRender y = (SCHAR_MIN << 4) / 2048.f; if (y < 0) { - r = (14 * y + 38); - g = 20 * y + 56; - b = 18 * y + 51; + r = static_cast(14 * y + 38); + g = static_cast(20 * y + 56); + b = static_cast(18 * y + 51); } else if (y < 0.3f) { @@ -112,20 +112,20 @@ namespace MWRender y *= 8.f; else { - y -= 0.1; - y += 0.8; + y -= 0.1f; + y += 0.8f; } - r = 66 - 32 * y; - g = 48 - 23 * y; - b = 33 - 16 * y; + r = static_cast(66 - 32 * y); + g = static_cast(48 - 23 * y); + b = static_cast(33 - 16 * y); } else { y -= 0.3f; y *= 1.428f; - r = 34 - 29 * y; - g = 25 - 20 * y; - b = 17 - 12 * y; + r = static_cast(34 - 29 * y); + g = static_cast(25 - 20 * y); + b = static_cast(17 - 12 * y); } data[texelY * mWidth * 3 + texelX * 3] = r; @@ -172,9 +172,9 @@ namespace MWRender void GlobalMap::exploreCell(int cellX, int cellY) { - float originX = (cellX - mMinX) * mCellSize; + float originX = static_cast((cellX - mMinX) * mCellSize); // NB y + 1, because we want the top left corner, not bottom left where the origin of the cell is - float originY = mHeight - (cellY+1 - mMinY) * mCellSize; + float originY = static_cast(mHeight - (cellY + 1 - mMinY) * mCellSize); if (cellX > mMaxX || cellX < mMinX || cellY > mMaxY || cellY < mMinY) return; @@ -188,7 +188,8 @@ namespace MWRender int mapHeight = localMapTexture->getHeight(); mOverlayTexture->load(); mOverlayTexture->getBuffer()->blit(localMapTexture->getBuffer(), Ogre::Image::Box(0,0,mapWidth,mapHeight), - Ogre::Image::Box(originX,originY,originX+mCellSize,originY+mCellSize)); + Ogre::Image::Box(static_cast(originX), static_cast(originY), + static_cast(originX + mCellSize), static_cast(originY + mCellSize))); Ogre::Image backup; std::vector data; @@ -204,7 +205,7 @@ namespace MWRender assert (originY+y < mOverlayImage.getHeight()); assert (x < int(backup.getWidth())); assert (y < int(backup.getHeight())); - mOverlayImage.setColourAt(backup.getColourAt(x, y, 0), originX+x, originY+y, 0); + mOverlayImage.setColourAt(backup.getColourAt(x, y, 0), static_cast(originX + x), static_cast(originY + y), 0); } } } diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 638a08623..0299dc493 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -43,9 +43,9 @@ LocalMap::LocalMap(OEngine::Render::OgreRenderer* rend, MWRender::RenderingManag mLight = mRendering->getScene()->createLight(); mLight->setType (Ogre::Light::LT_DIRECTIONAL); - mLight->setDirection (Ogre::Vector3(0.3, 0.3, -0.7)); + mLight->setDirection (Ogre::Vector3(0.3f, 0.3f, -0.7f)); mLight->setVisible (false); - mLight->setDiffuseColour (ColourValue(0.7,0.7,0.7)); + mLight->setDiffuseColour (ColourValue(0.7f,0.7f,0.7f)); mRenderTexture = TextureManager::getSingleton().createManual( "localmap/rtt", @@ -114,8 +114,8 @@ void LocalMap::saveFogOfWar(MWWorld::CellStore* cell) Vector2 min(mBounds.getMinimum().x, mBounds.getMinimum().y); Vector2 max(mBounds.getMaximum().x, mBounds.getMaximum().y); Vector2 length = max-min; - const int segsX = std::ceil( length.x / sSize ); - const int segsY = std::ceil( length.y / sSize ); + const int segsX = static_cast(std::ceil(length.x / sSize)); + const int segsY = static_cast(std::ceil(length.y / sSize)); mInteriorName = cell->getCell()->mName; @@ -175,7 +175,7 @@ void LocalMap::requestMap(MWWorld::CellStore* cell, float zMin, float zMax) // Note: using force=true for exterior cell maps. // They must be updated even if they were visited before, because the set of surrounding active cells might be different // (and objects in a different cell can "bleed" into another cell's map if they cross the border) - render((x+0.5)*sSize, (y+0.5)*sSize, zMin, zMax, sSize, sSize, name, true); + render((x+0.5f)*sSize, (y+0.5f)*sSize, zMin, zMax, static_cast(sSize), static_cast(sSize), name, true); if (mBuffers.find(name) == mBuffers.end()) { @@ -226,7 +226,7 @@ void LocalMap::requestMap(MWWorld::CellStore* cell, // Do NOT change padding! This will break older savegames. // If the padding really needs to be changed, then it must be saved in the ESM::FogState and // assume the old (500) value as default for older savegames. - const int padding = 500; + const Ogre::Real padding = 500.0f; // Apply a little padding mBounds.setMinimum (mBounds.getMinimum() - Vector3(padding,padding,0)); @@ -279,8 +279,8 @@ void LocalMap::requestMap(MWWorld::CellStore* cell, mCameraPosNode->setPosition(Vector3(center.x, center.y, 0)); // divide into segments - const int segsX = std::ceil( length.x / sSize ); - const int segsY = std::ceil( length.y / sSize ); + const int segsX = static_cast(std::ceil(length.x / sSize)); + const int segsY = static_cast(std::ceil(length.y / sSize)); mInteriorName = cell->getCell()->mName; @@ -289,12 +289,12 @@ void LocalMap::requestMap(MWWorld::CellStore* cell, { for (int y=0; y(sSize*x), static_cast(sSize*y)); Vector2 newcenter = start + sSize/2; std::string texturePrefix = cell->getCell()->mName + "_" + coordStr(x,y); - render(newcenter.x - center.x, newcenter.y - center.y, zMin, zMax, sSize, sSize, texturePrefix); + render(newcenter.x - center.x, newcenter.y - center.y, zMin, zMax, static_cast(sSize), static_cast(sSize), texturePrefix); if (!cell->getFog()) createFogOfWar(texturePrefix); @@ -397,7 +397,7 @@ void LocalMap::render(const float x, const float y, // set up lighting Ogre::ColourValue oldAmbient = mRendering->getScene()->getAmbientLight(); - mRendering->getScene()->setAmbientLight(Ogre::ColourValue(0.3, 0.3, 0.3)); + mRendering->getScene()->setAmbientLight(Ogre::ColourValue(0.3f, 0.3f, 0.3f)); mRenderingManager->disableLights(true); mLight->setVisible(true); @@ -439,11 +439,11 @@ void LocalMap::worldToInteriorMapPosition (Ogre::Vector2 pos, float& nX, float& Vector2 min(mBounds.getMinimum().x, mBounds.getMinimum().y); - x = std::ceil((pos.x - min.x)/sSize)-1; - y = std::ceil((pos.y - min.y)/sSize)-1; + x = static_cast(std::ceil((pos.x - min.x) / sSize) - 1); + y = static_cast(std::ceil((pos.y - min.y) / sSize) - 1); nX = (pos.x - min.x - sSize*x)/sSize; - nY = 1.0-(pos.y - min.y - sSize*y)/sSize; + nY = 1.0f-(pos.y - min.y - sSize*y)/sSize; } Ogre::Vector2 LocalMap::interiorMapToWorldPosition (float nX, float nY, int x, int y) @@ -452,7 +452,7 @@ Ogre::Vector2 LocalMap::interiorMapToWorldPosition (float nX, float nY, int x, i Ogre::Vector2 pos; pos.x = sSize * (nX + x) + min.x; - pos.y = sSize * (1.0-nY + y) + min.y; + pos.y = sSize * (1.0f-nY + y) + min.y; pos = rotatePoint(pos, Vector2(mBounds.getCenter().x, mBounds.getCenter().y), -mAngle); return pos; @@ -468,8 +468,8 @@ bool LocalMap::isPositionExplored (float nX, float nY, int x, int y, bool interi nX = std::max(0.f, std::min(1.f, nX)); nY = std::max(0.f, std::min(1.f, nY)); - int texU = (sFogOfWarResolution-1) * nX; - int texV = (sFogOfWarResolution-1) * nY; + int texU = static_cast((sFogOfWarResolution - 1) * nX); + int texV = static_cast((sFogOfWarResolution - 1) * nY); Ogre::uint32 clr = mBuffers[texName][texV * sFogOfWarResolution + texU]; uint8 alpha = (clr >> 24); @@ -522,8 +522,8 @@ void LocalMap::updatePlayer (const Ogre::Vector3& position, const Ogre::Quaterni if (!mInterior) { - x = std::ceil(pos.x / sSize)-1; - y = std::ceil(pos.y / sSize)-1; + x = static_cast(std::ceil(pos.x / sSize) - 1); + y = static_cast(std::ceil(pos.y / sSize) - 1); } else MWBase::Environment::get().getWindowManager()->setActiveMap(x,y,mInterior); @@ -533,7 +533,7 @@ void LocalMap::updatePlayer (const Ogre::Vector3& position, const Ogre::Quaterni if (!mInterior) { u = std::abs((pos.x - (sSize*x))/sSize); - v = 1.0-std::abs((pos.y - (sSize*y))/sSize); + v = 1.0f-std::abs((pos.y - (sSize*y))/sSize); texBaseName = "Cell_"; } else @@ -545,7 +545,7 @@ void LocalMap::updatePlayer (const Ogre::Vector3& position, const Ogre::Quaterni MWBase::Environment::get().getWindowManager()->setPlayerDir(playerdirection.x, playerdirection.y); // explore radius (squared) - const float exploreRadius = (mInterior ? 0.1 : 0.3) * (sFogOfWarResolution-1); // explore radius from 0 to sFogOfWarResolution-1 + const float exploreRadius = (mInterior ? 0.1f : 0.3f) * (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) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index a2ad1e02c..284788522 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -101,7 +101,7 @@ void HeadAnimationTime::setEnabled(bool enabled) void HeadAnimationTime::resetBlinkTimer() { - mBlinkTimer = -(2 + (std::rand() / double(RAND_MAX*1.0)) * 6); + mBlinkTimer = -(2 + (std::rand() / static_cast(RAND_MAX)) * 6); } void HeadAnimationTime::update(float dt) diff --git a/apps/openmw/mwrender/refraction.cpp b/apps/openmw/mwrender/refraction.cpp index 6cc49089a..739ed24d9 100644 --- a/apps/openmw/mwrender/refraction.cpp +++ b/apps/openmw/mwrender/refraction.cpp @@ -35,7 +35,7 @@ namespace MWRender vp->setShadowsEnabled(false); vp->setVisibilityMask(RV_Refraction); vp->setMaterialScheme("water_refraction"); - vp->setBackgroundColour (Ogre::ColourValue(0.090195, 0.115685, 0.12745)); + vp->setBackgroundColour (Ogre::ColourValue(0.090195f, 0.115685f, 0.12745f)); mRenderTarget->setAutoUpdated(true); mRenderTarget->addListener(this); } diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 05b43d54f..78ab45881 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -148,8 +148,8 @@ RenderingManager::RenderingManager(OEngine::Render::OgreRenderer& _rend, const b sh::Factory::getInstance ().setSharedParameter ("waterEnabled", sh::makeProperty (new sh::FloatValue(0.0))); sh::Factory::getInstance ().setSharedParameter ("waterLevel", sh::makeProperty(new sh::FloatValue(0))); sh::Factory::getInstance ().setSharedParameter ("waterTimer", sh::makeProperty(new sh::FloatValue(0))); - sh::Factory::getInstance ().setSharedParameter ("windDir_windSpeed", sh::makeProperty(new sh::Vector3(0.5, -0.8, 0.2))); - sh::Factory::getInstance ().setSharedParameter ("waterSunFade_sunHeight", sh::makeProperty(new sh::Vector2(1, 0.6))); + sh::Factory::getInstance ().setSharedParameter ("windDir_windSpeed", sh::makeProperty(new sh::Vector3(0.5f, -0.8f, 0.2f))); + sh::Factory::getInstance ().setSharedParameter ("waterSunFade_sunHeight", sh::makeProperty(new sh::Vector2(1, 0.6f))); sh::Factory::getInstance ().setGlobalSetting ("refraction", Settings::Manager::getBool("refraction", "Water") ? "true" : "false"); sh::Factory::getInstance ().setGlobalSetting ("viewproj_fix", "false"); sh::Factory::getInstance ().setSharedParameter ("vpRow2Fix", sh::makeProperty (new sh::Vector4(0,0,0,0))); @@ -346,7 +346,7 @@ void RenderingManager::update (float duration, bool paused) MWWorld::Ptr player = world->getPlayerPtr(); - int blind = player.getClass().getCreatureStats(player).getMagicEffects().get(ESM::MagicEffect::Blind).getMagnitude(); + int blind = static_cast(player.getClass().getCreatureStats(player).getMagicEffects().get(ESM::MagicEffect::Blind).getMagnitude()); MWBase::Environment::get().getWindowManager()->setBlindness(std::max(0, std::min(100, blind))); setAmbientMode(); @@ -365,7 +365,7 @@ void RenderingManager::update (float duration, bool paused) btVector3 btOrig(orig.x, orig.y, orig.z); btVector3 btDest(dest.x, dest.y, dest.z); - std::pair test = mPhysicsEngine->sphereCast(mRendering.getCamera()->getNearClipDistance()*2.5, btOrig, btDest); + std::pair test = mPhysicsEngine->sphereCast(mRendering.getCamera()->getNearClipDistance()*2.5f, btOrig, btDest); if(test.first) mCamera->setCameraDistance(test.second * orig.distance(dest), false, false); } @@ -375,8 +375,8 @@ void RenderingManager::update (float duration, bool paused) bool isInAir = !world->isOnGround(player); bool isSwimming = world->isSwimming(player); - static const int i1stPersonSneakDelta = MWBase::Environment::get().getWorld()->getStore().get() - .find("i1stPersonSneakDelta")->getInt(); + static const float i1stPersonSneakDelta = MWBase::Environment::get().getWorld()->getStore().get() + .find("i1stPersonSneakDelta")->getFloat(); if(!paused && isSneaking && !(isSwimming || isInAir)) mCamera->setSneakOffset(i1stPersonSneakDelta); @@ -538,7 +538,7 @@ void RenderingManager::applyFog (bool underwater) } else { - Ogre::ColourValue clv(0.090195, 0.115685, 0.12745); + Ogre::ColourValue clv(0.090195f, 0.115685f, 0.12745f); mRendering.getScene()->setFog (FOG_LINEAR, Ogre::ColourValue(clv), 0, 0, 1000); mRendering.getViewport()->setBackgroundColour (Ogre::ColourValue(clv)); mWater->setViewportBackground (Ogre::ColourValue(clv)); @@ -598,9 +598,9 @@ void RenderingManager::setAmbientColour(const Ogre::ColourValue& colour) mAmbientColor = colour; MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); - int nightEye = player.getClass().getCreatureStats(player).getMagicEffects().get(ESM::MagicEffect::NightEye).getMagnitude(); + int nightEye = static_cast(player.getClass().getCreatureStats(player).getMagicEffects().get(ESM::MagicEffect::NightEye).getMagnitude()); Ogre::ColourValue final = colour; - final += Ogre::ColourValue(0.7,0.7,0.7,0) * std::min(1.f, (nightEye/100.f)); + final += Ogre::ColourValue(0.7f,0.7f,0.7f,0) * std::min(1.f, (nightEye/100.f)); mRendering.getScene()->setAmbientLight(final); } @@ -662,7 +662,7 @@ void RenderingManager::requestMap(MWWorld::CellStore* cell) assert(mTerrain); Ogre::AxisAlignedBox dims = mObjects->getDimensions(cell); - Ogre::Vector2 center (cell->getCell()->getGridX() + 0.5, cell->getCell()->getGridY() + 0.5); + Ogre::Vector2 center (cell->getCell()->getGridX() + 0.5f, cell->getCell()->getGridY() + 0.5f); dims.merge(mTerrain->getWorldBoundingBox(center)); mLocalMap->requestMap(cell, dims.getMinimum().z, dims.getMaximum().z); @@ -714,8 +714,8 @@ Ogre::Vector4 RenderingManager::boundingBoxToScreen(Ogre::AxisAlignedBox bounds) // make 2D relative/normalized coords from the view-space vertex // by dividing out the Z (depth) factor -- this is an approximation - float x = corner.x / corner.z + 0.5; - float y = corner.y / corner.z + 0.5; + float x = corner.x / corner.z + 0.5f; + float y = corner.y / corner.z + 0.5f; if (x < min_x) min_x = x; diff --git a/apps/openmw/mwrender/ripplesimulation.cpp b/apps/openmw/mwrender/ripplesimulation.cpp index bb1bccc0a..f75061af4 100644 --- a/apps/openmw/mwrender/ripplesimulation.cpp +++ b/apps/openmw/mwrender/ripplesimulation.cpp @@ -107,7 +107,7 @@ void RippleSimulation::update(float dt, Ogre::Vector2 position) Ogre::Radian& rotation = created->rotation; #endif timeToLive = totalTimeToLive = mRippleLifeTime; - colour = Ogre::ColourValue(0.f, 0.f, 0.f, 0.7); // Water_RippleAlphas.x? + colour = Ogre::ColourValue(0.f, 0.f, 0.f, 0.7f); // Water_RippleAlphas.x? direction = Ogre::Vector3(0,0,0); position = currentPos; position.z = 0; // Z is set by the Scene Node diff --git a/apps/openmw/mwrender/shadows.cpp b/apps/openmw/mwrender/shadows.cpp index 5a6ccaca6..f2e60b11b 100644 --- a/apps/openmw/mwrender/shadows.cpp +++ b/apps/openmw/mwrender/shadows.cpp @@ -21,7 +21,7 @@ using namespace MWRender; Shadows::Shadows(OEngine::Render::OgreRenderer* rend) : mRendering(rend), mSceneMgr(rend->getScene()), mPSSMSetup(NULL), - mShadowFar(1000), mFadeStart(0.9) + mShadowFar(1000), mFadeStart(0.9f) { recreate(); } @@ -58,7 +58,7 @@ void Shadows::recreate() mSceneMgr->setShadowTexturePixelFormat(PF_FLOAT32_R); mSceneMgr->setShadowDirectionalLightExtrusionDistance(1000000); - mShadowFar = split ? Settings::Manager::getInt("split shadow distance", "Shadows") : Settings::Manager::getInt("shadow distance", "Shadows"); + mShadowFar = Settings::Manager::getFloat(split ? "split shadow distance" : "shadow distance", "Shadows"); mSceneMgr->setShadowFarDistance(mShadowFar); mFadeStart = Settings::Manager::getFloat("fade start", "Shadows"); diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index f6287de5e..6e9684475 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -310,22 +310,22 @@ void SkyManager::create() // Create light used for thunderstorm mLightning = mSceneMgr->createLight(); mLightning->setType (Ogre::Light::LT_DIRECTIONAL); - mLightning->setDirection (Ogre::Vector3(0.3, -0.7, 0.3)); + mLightning->setDirection (Ogre::Vector3(0.3f, -0.7f, 0.3f)); mLightning->setVisible (false); mLightning->setDiffuseColour (ColourValue(3,3,3)); const MWWorld::Fallback* fallback=MWBase::Environment::get().getWorld()->getFallback(); - mSecunda = new Moon("secunda_texture", fallback->getFallbackFloat("Moons_Secunda_Size")/100, Vector3(-0.4, 0.4, 0.5), mRootNode, "openmw_moon"); + mSecunda = new Moon("secunda_texture", fallback->getFallbackFloat("Moons_Secunda_Size")/100, Vector3(-0.4f, 0.4f, 0.5f), mRootNode, "openmw_moon"); mSecunda->setType(Moon::Type_Secunda); mSecunda->setRenderQueue(RQG_SkiesEarly+4); - mMasser = new Moon("masser_texture", fallback->getFallbackFloat("Moons_Masser_Size")/100, Vector3(-0.4, 0.4, 0.5), mRootNode, "openmw_moon"); + mMasser = new Moon("masser_texture", fallback->getFallbackFloat("Moons_Masser_Size")/100, Vector3(-0.4f, 0.4f, 0.5f), mRootNode, "openmw_moon"); mMasser->setRenderQueue(RQG_SkiesEarly+3); mMasser->setType(Moon::Type_Masser); - mSun = new BillboardObject("textures\\tx_sun_05.dds", 1, Vector3(0.4, 0.4, 0.4), mRootNode, "openmw_sun"); + mSun = new BillboardObject("textures\\tx_sun_05.dds", 1, Vector3(0.4f, 0.4f, 0.4f), mRootNode, "openmw_sun"); mSun->setRenderQueue(RQG_SkiesEarly+4); - mSunGlare = new BillboardObject("textures\\tx_sun_flash_grey_05.dds", 3, Vector3(0.4, 0.4, 0.4), mRootNode, "openmw_sun"); + mSunGlare = new BillboardObject("textures\\tx_sun_flash_grey_05.dds", 3, Vector3(0.4f, 0.4f, 0.4f), mRootNode, "openmw_sun"); mSunGlare->setRenderQueue(RQG_SkiesLate); mSunGlare->setVisibilityFlags(RV_NoReflection); @@ -464,8 +464,8 @@ void SkyManager::updateRain(float dt) // TODO: handle rain settings from Morrowind.ini const float rangeRandom = 100; - float xOffs = (std::rand()/(RAND_MAX+1.0)) * rangeRandom - (rangeRandom/2); - float yOffs = (std::rand()/(RAND_MAX+1.0)) * rangeRandom - (rangeRandom/2); + float xOffs = (std::rand()/(RAND_MAX+1.0f)) * rangeRandom - (rangeRandom/2); + float yOffs = (std::rand()/(RAND_MAX+1.0f)) * rangeRandom - (rangeRandom/2); // Create a separate node to control the offset, since a node with setInheritOrientation(false) will still // consider the orientation of the parent node for its position, just not for its orientation @@ -680,9 +680,9 @@ void SkyManager::setWeather(const MWWorld::WeatherResult& weather) if (mCloudColour != weather.mSunColor) { - ColourValue clr( weather.mSunColor.r*0.7 + weather.mAmbientColor.r*0.7, - weather.mSunColor.g*0.7 + weather.mAmbientColor.g*0.7, - weather.mSunColor.b*0.7 + weather.mAmbientColor.b*0.7); + ColourValue clr( weather.mSunColor.r*0.7f + weather.mAmbientColor.r*0.7f, + weather.mSunColor.g*0.7f + weather.mAmbientColor.g*0.7f, + weather.mSunColor.b*0.7f + weather.mAmbientColor.b*0.7f); sh::Factory::getInstance().setSharedParameter ("cloudColour", sh::makeProperty(new sh::Vector3(clr.r, clr.g, clr.b))); @@ -774,7 +774,7 @@ void SkyManager::setSunDirection(const Vector3& direction, bool is_night) mSunGlare->setPosition(direction); float height = direction.z; - float fade = is_night ? 0.0 : (( height > 0.5) ? 1.0 : height * 2); + float fade = is_night ? 0.0f : (( height > 0.5) ? 1.0f : height * 2); sh::Factory::getInstance ().setSharedParameter ("waterSunFade_sunHeight", sh::makeProperty(new sh::Vector2(fade, height))); } @@ -836,7 +836,7 @@ void SkyManager::setSecundaFade(const float fade) void SkyManager::setHour(double hour) { - mHour = hour; + mHour = static_cast(hour); } void SkyManager::setDate(int day, int month) diff --git a/apps/openmw/mwrender/terrainstorage.cpp b/apps/openmw/mwrender/terrainstorage.cpp index e74b6af12..8ad2ea321 100644 --- a/apps/openmw/mwrender/terrainstorage.cpp +++ b/apps/openmw/mwrender/terrainstorage.cpp @@ -36,13 +36,13 @@ namespace MWRender for (; it != esmStore.get().extEnd(); ++it) { if (it->getGridX() < minX) - minX = it->getGridX(); + minX = static_cast(it->getGridX()); if (it->getGridX() > maxX) - maxX = it->getGridX(); + maxX = static_cast(it->getGridX()); if (it->getGridY() < minY) - minY = it->getGridY(); + minY = static_cast(it->getGridY()); if (it->getGridY() > maxY) - maxY = it->getGridY(); + maxY = static_cast(it->getGridY()); } // since grid coords are at cell origin, we need to add 1 cell diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 456fc47e9..a16b156ae 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -210,7 +210,8 @@ Water::Water (Ogre::Camera *camera, RenderingManager* rend, const MWWorld::Fallb int waterScale = 30; MeshManager::getSingleton().createPlane("water", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, mWaterPlane, - CELL_SIZE*5*waterScale, CELL_SIZE*5*waterScale, 40, 40, true, 1, 3*waterScale,3*waterScale, Vector3::UNIT_Y); + static_cast(CELL_SIZE*5*waterScale), static_cast(CELL_SIZE*5*waterScale), + 40, 40, true, 1, static_cast(3 * waterScale), static_cast(3 * waterScale), Vector3::UNIT_Y); mWater = mSceneMgr->createEntity("water"); mWater->setVisibilityFlags(RV_Water); @@ -284,7 +285,7 @@ void Water::setActive(bool active) mActive = active; updateVisible(); - sh::Factory::getInstance ().setSharedParameter ("waterEnabled", sh::makeProperty (new sh::FloatValue(active ? 1.0 : 0.0))); + sh::Factory::getInstance ().setSharedParameter ("waterEnabled", sh::makeProperty (new sh::FloatValue(active ? 1.0f : 0.0f))); } Water::~Water() @@ -351,7 +352,7 @@ Water::updateUnderwater(bool underwater) Vector3 Water::getSceneNodeCoordinates(int gridX, int gridY) { - return Vector3(gridX * CELL_SIZE + (CELL_SIZE / 2), gridY * CELL_SIZE + (CELL_SIZE / 2), mTop); + return Vector3(static_cast(gridX * CELL_SIZE + (CELL_SIZE / 2)), static_cast(gridY * CELL_SIZE + (CELL_SIZE / 2)), mTop); } void Water::setViewportBackground(const ColourValue& bg) diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index 10d0a06ff..775950431 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -122,7 +122,7 @@ namespace MWRender { bool mIsUnderwater; bool mActive; bool mToggled; - int mTop; + float mTop; float mWaterTimer; diff --git a/apps/openmw/mwscript/aiextensions.cpp b/apps/openmw/mwscript/aiextensions.cpp index a3f935487..d6eb80265 100644 --- a/apps/openmw/mwscript/aiextensions.cpp +++ b/apps/openmw/mwscript/aiextensions.cpp @@ -107,7 +107,7 @@ namespace MWScript // discard additional arguments (reset), because we have no idea what they mean. for (unsigned int i=0; i(duration), x, y, z); ptr.getClass().getCreatureStats (ptr).getAiSequence().stack(escortPackage, ptr); std::cout << "AiEscort: " << x << ", " << y << ", " << z << ", " << duration @@ -145,7 +145,7 @@ namespace MWScript // discard additional arguments (reset), because we have no idea what they mean. for (unsigned int i=0; i(duration), x, y, z); ptr.getClass().getCreatureStats (ptr).getAiSequence().stack(escortPackage, ptr); std::cout << "AiEscort: " << x << ", " << y << ", " << z << ", " << duration @@ -177,13 +177,13 @@ namespace MWScript { MWWorld::Ptr ptr = R()(runtime); - Interpreter::Type_Integer range = runtime[0].mFloat; + Interpreter::Type_Integer range = static_cast(runtime[0].mFloat); runtime.pop(); - Interpreter::Type_Integer duration = runtime[0].mFloat; + Interpreter::Type_Integer duration = static_cast(runtime[0].mFloat); runtime.pop(); - Interpreter::Type_Integer time = runtime[0].mFloat; + Interpreter::Type_Integer time = static_cast(runtime[0].mFloat); runtime.pop(); std::vector idleList; diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index c4e0b4261..a8c04aa4b 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -475,7 +475,7 @@ namespace MWScript for (int i=0; i<3; ++i) diff[i] = pos1[i] - pos2[i]; - return std::sqrt (diff[0]*diff[0] + diff[1]*diff[1] + diff[2]*diff[2]); + return static_cast(std::sqrt(diff[0] * diff[0] + diff[1] * diff[1] + diff[2] * diff[2])); } bool InterpreterContext::hasBeenActivated (const MWWorld::Ptr& ptr) diff --git a/apps/openmw/mwscript/locals.cpp b/apps/openmw/mwscript/locals.cpp index 9dbf07fba..a18d0d5ae 100644 --- a/apps/openmw/mwscript/locals.cpp +++ b/apps/openmw/mwscript/locals.cpp @@ -63,7 +63,7 @@ namespace MWScript return mLongs.at (index); case 'f': - return mFloats.at (index); + return static_cast(mFloats.at(index)); default: return 0; } @@ -87,7 +87,7 @@ namespace MWScript mLongs.at (index) = val; break; case 'f': - mFloats.at (index) = val; break; + mFloats.at(index) = static_cast(val); break; } return true; } diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index f69031b2c..446be1cbc 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -312,7 +312,7 @@ namespace MWScript Interpreter::Type_Float time = runtime[0].mFloat; runtime.pop(); - MWBase::Environment::get().getWindowManager()->fadeScreenTo(alpha, time, false); + MWBase::Environment::get().getWindowManager()->fadeScreenTo(static_cast(alpha), time, false); } }; diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index b8bb76388..d825b085e 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -169,7 +169,7 @@ namespace MWScript if (mIndex==0 && ptr.getClass().hasItemHealth (ptr)) { // health is a special case - value = ptr.getClass().getItemMaxHealth (ptr); + value = static_cast(ptr.getClass().getItemMaxHealth(ptr)); } else { value = ptr.getClass() @@ -402,7 +402,7 @@ namespace MWScript MWBase::World *world = MWBase::Environment::get().getWorld(); MWWorld::Ptr player = world->getPlayerPtr(); - int bounty = runtime[0].mFloat; + int bounty = static_cast(runtime[0].mFloat); runtime.pop(); player.getClass().getNpcStats (player).setBounty(bounty); @@ -420,7 +420,7 @@ namespace MWScript MWBase::World *world = MWBase::Environment::get().getWorld(); MWWorld::Ptr player = world->getPlayerPtr(); - player.getClass().getNpcStats (player).setBounty(runtime[0].mFloat + player.getClass().getNpcStats (player).getBounty()); + player.getClass().getNpcStats(player).setBounty(static_cast(runtime[0].mFloat) + player.getClass().getNpcStats(player).getBounty()); runtime.pop(); } }; @@ -1195,11 +1195,10 @@ namespace MWScript float currentValue = stats.getMagicEffects().get(mPositiveEffect).getMagnitude(); if (mNegativeEffect != -1) currentValue -= stats.getMagicEffects().get(mNegativeEffect).getMagnitude(); - currentValue = int(currentValue); int arg = runtime[0].mInteger; runtime.pop(); - stats.getMagicEffects().modifyBase(mPositiveEffect, (arg - currentValue)); + stats.getMagicEffects().modifyBase(mPositiveEffect, (arg - static_cast(currentValue))); } }; diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 734df7d74..1ed5f0c30 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -332,7 +332,7 @@ namespace MWScript // except for when you position the player, then degrees must be used. // See "Morrowind Scripting for Dummies (9th Edition)" pages 50 and 54 for reference. if(ptr != MWBase::Environment::get().getWorld()->getPlayerPtr()) - zRot = zRot/60.; + zRot = zRot/60.0f; MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay,zRot); ptr.getClass().adjustPosition(ptr, false); @@ -389,7 +389,7 @@ namespace MWScript // except for when you position the player, then degrees must be used. // See "Morrowind Scripting for Dummies (9th Edition)" pages 50 and 54 for reference. if(ptr != MWBase::Environment::get().getWorld()->getPlayerPtr()) - zRot = zRot/60.; + zRot = zRot/60.0f; MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay,zRot); ptr.getClass().adjustPosition(ptr, false); } diff --git a/apps/openmw/mwsound/loudness.cpp b/apps/openmw/mwsound/loudness.cpp index c64913b1f..007791984 100644 --- a/apps/openmw/mwsound/loudness.cpp +++ b/apps/openmw/mwsound/loudness.cpp @@ -8,7 +8,7 @@ namespace MWSound void analyzeLoudness(const std::vector &data, int sampleRate, ChannelConfig chans, SampleType type, std::vector &out, float valuesPerSecond) { - int samplesPerSegment = sampleRate / valuesPerSecond; + int samplesPerSegment = static_cast(sampleRate / valuesPerSecond); int numSamples = bytesToFrames(data.size(), chans, type); int advance = framesToBytes(1, chans, type); diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index bc9478945..1b3dced80 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -801,7 +801,7 @@ const CachedSound& OpenAL_Output::getBuffer(const std::string &fname) decoder->close(); CachedSound cached; - analyzeLoudness(data, srate, chans, type, cached.mLoudnessVector, loudnessFPS); + analyzeLoudness(data, srate, chans, type, cached.mLoudnessVector, static_cast(loudnessFPS)); alGenBuffers(1, &buf); throwALerror(); @@ -885,7 +885,7 @@ MWBase::SoundPtr OpenAL_Output::playSound(const std::string &fname, float vol, f offset=1; alSourcei(src, AL_BUFFER, buf); - alSourcef(src, AL_SEC_OFFSET, sound->getLength()*offset/pitch); + alSourcef(src, AL_SEC_OFFSET, static_cast(sound->getLength()*offset / pitch)); alSourcePlay(src); throwALerror(); @@ -910,7 +910,7 @@ MWBase::SoundPtr OpenAL_Output::playSound3D(const std::string &fname, const Ogre sound.reset(new OpenAL_Sound3D(*this, src, buf, pos, vol, basevol, pitch, min, max, flags)); if (extractLoudness) - sound->setLoudnessVector(cached.mLoudnessVector, loudnessFPS); + sound->setLoudnessVector(cached.mLoudnessVector, static_cast(loudnessFPS)); } catch(std::exception&) { @@ -929,7 +929,7 @@ MWBase::SoundPtr OpenAL_Output::playSound3D(const std::string &fname, const Ogre offset=1; alSourcei(src, AL_BUFFER, buf); - alSourcef(src, AL_SEC_OFFSET, sound->getLength()*offset/pitch); + alSourcef(src, AL_SEC_OFFSET, static_cast(sound->getLength()*offset / pitch)); alSourcePlay(src); throwALerror(); diff --git a/apps/openmw/mwsound/sound.cpp b/apps/openmw/mwsound/sound.cpp index b3105a82c..8b6bfda82 100644 --- a/apps/openmw/mwsound/sound.cpp +++ b/apps/openmw/mwsound/sound.cpp @@ -7,7 +7,7 @@ namespace MWSound { if (mLoudnessVector.empty()) return 0.f; - int index = getTimeOffset() * mLoudnessFPS; + int index = static_cast(getTimeOffset() * mLoudnessFPS); index = std::max(0, std::min(index, int(mLoudnessVector.size()-1))); diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 0bc155118..b3978f9d5 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -106,7 +106,7 @@ namespace MWSound MWBase::World* world = MWBase::Environment::get().getWorld(); const ESM::Sound *snd = world->getStore().get().find(soundId); - volume *= pow(10.0, (snd->mData.mVolume/255.0*3348.0 - 3348.0) / 2000.0); + volume *= static_cast(pow(10.0, (snd->mData.mVolume / 255.0*3348.0 - 3348.0) / 2000.0)); if(snd->mData.mMinRange == 0 && snd->mData.mMaxRange == 0) { @@ -559,7 +559,7 @@ namespace MWSound if(!cell->isExterior() || sTimePassed < sTimeToNextEnvSound) return; - float a = std::rand() / (double)RAND_MAX; + float a = std::rand() / static_cast(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); diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index c2906e447..8ef6799ba 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -185,7 +185,7 @@ bool MWWorld::ContainerStore::stacks(const Ptr& ptr1, const Ptr& ptr2) { const ESM::Enchantment* enchantment = MWBase::Environment::get().getWorld()->getStore().get().find( ptr1.getClass().getEnchantment(ptr1)); - float maxCharge = enchantment->mData.mCharge; + float maxCharge = static_cast(enchantment->mData.mCharge); float enchantCharge1 = ptr1.getCellRef().getEnchantmentCharge() == -1 ? maxCharge : ptr1.getCellRef().getEnchantmentCharge(); float enchantCharge2 = ptr2.getCellRef().getEnchantmentCharge() == -1 ? maxCharge : ptr2.getCellRef().getEnchantmentCharge(); if (enchantCharge1 != maxCharge || enchantCharge2 != maxCharge) diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index 36c198f01..5d9beecb6 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -124,7 +124,7 @@ void ESMStore::load(ESM::ESMReader &esm, Loading::Listener* listener) mIds[Misc::StringUtils::lowerCase (id)] = n.val; } } - listener->setProgress(esm.getFileOffset() / (float)esm.getFileSize() * 1000); + listener->setProgress(static_cast(esm.getFileOffset() / (float)esm.getFileSize() * 1000)); } } diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index 8f3560a69..58718074e 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -97,13 +97,13 @@ namespace MWWorld if (mAutoMove) value = 1; - ptr.getClass().getMovementSettings (ptr).mPosition[1] = value; + ptr.getClass().getMovementSettings(ptr).mPosition[1] = static_cast(value); } void Player::setLeftRight (int value) { MWWorld::Ptr ptr = getPlayer(); - ptr.getClass().getMovementSettings (ptr).mPosition[0] = value; + ptr.getClass().getMovementSettings(ptr).mPosition[0] = static_cast(value); } void Player::setForwardBackward (int value) @@ -115,13 +115,13 @@ namespace MWWorld if (mAutoMove) value = 1; - ptr.getClass().getMovementSettings (ptr).mPosition[1] = value; + ptr.getClass().getMovementSettings(ptr).mPosition[1] = static_cast(value); } void Player::setUpDown(int value) { MWWorld::Ptr ptr = getPlayer(); - ptr.getClass().getMovementSettings (ptr).mPosition[2] = value; + ptr.getClass().getMovementSettings(ptr).mPosition[2] = static_cast(value); } void Player::setRunState(bool run) diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index c97e4e3a5..acbe819f1 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -68,7 +68,7 @@ namespace MWWorld { float height = 0; if (OEngine::Physic::PhysicActor* actor = mPhysEngine.getCharacter(caster.getRefData().getHandle())) - height = actor->getHalfExtents().z * 2 * 0.75; // Spawn at 0.75 * ActorHeight + height = actor->getHalfExtents().z * 2 * 0.75f; // Spawn at 0.75 * ActorHeight Ogre::Vector3 pos(caster.getRefData().getPosition().pos); pos.z += height; diff --git a/apps/openmw/mwworld/timestamp.cpp b/apps/openmw/mwworld/timestamp.cpp index a73ed7ca5..bd07b91f3 100644 --- a/apps/openmw/mwworld/timestamp.cpp +++ b/apps/openmw/mwworld/timestamp.cpp @@ -33,7 +33,7 @@ namespace MWWorld mHour = static_cast (std::fmod (hours, 24)); - mDay += hours / 24; + mDay += static_cast(hours / 24); return *this; } diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 4440ed030..69495cdd2 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -142,7 +142,7 @@ WeatherManager::WeatherManager(MWRender::RenderingManager* rendering,MWWorld::Fa * These values are fallbacks attached to weather. */ mNightStart = mSunsetTime + mSunsetDuration; - mNightEnd = mSunriseTime - 0.5; + mNightEnd = mSunriseTime - 0.5f; mDayStart = mSunriseTime + mSunriseDuration; mDayEnd = mSunsetTime; @@ -368,7 +368,7 @@ void WeatherManager::transition(float factor) mResult.mParticleEffect = other.mParticleEffect; mResult.mRainSpeed = other.mRainSpeed; mResult.mRainFrequency = other.mRainFrequency; - mResult.mAmbientSoundVolume = 2*(factor-0.5); + mResult.mAmbientSoundVolume = 2*(factor-0.5f); mResult.mEffectFade = mResult.mAmbientSoundVolume; mResult.mAmbientLoopSoundID = other.mAmbientLoopSoundID; } @@ -376,7 +376,7 @@ void WeatherManager::transition(float factor) void WeatherManager::update(float duration, bool paused) { - float timePassed = mTimePassed; + float timePassed = static_cast(mTimePassed); mTimePassed = 0; mWeatherUpdateTime -= timePassed; @@ -454,9 +454,9 @@ void WeatherManager::update(float duration, bool paused) } Vector3 final( - cos( theta ), + static_cast(cos(theta)), -0.268f, // approx tan( -15 degrees ) - sin( theta ) ); + static_cast(sin(theta))); mRendering->setSunDirection( final, is_night ); } @@ -488,8 +488,8 @@ void WeatherManager::update(float duration, bool paused) moonHeight); Vector3 secunda( - (moonHeight - 1) * facing * 1.25, - (1 - moonHeight) * facing * 0.8, + (moonHeight - 1) * facing * 1.25f, + (1 - moonHeight) * facing * 0.8f, moonHeight); mRendering->getSkyManager()->setMasserDirection(masser); @@ -542,7 +542,7 @@ void WeatherManager::update(float duration, bool paused) mRendering->getSkyManager()->setLightningStrength( mThunderFlash / mThunderThreshold ); else { - mThunderChanceNeeded = rand() % 100; + mThunderChanceNeeded = static_cast(rand() % 100); mThunderChance = 0; mRendering->getSkyManager()->setLightningStrength( 0.f ); } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 3ef4f8e81..ebd756781 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -570,9 +570,9 @@ namespace MWWorld if (name=="gamehour") setHour (value); else if (name=="day") - setDay (value); + setDay(static_cast(value)); else if (name=="month") - setMonth (value); + setMonth(static_cast(value)); else mGlobalVariables[name].setFloat (value); } @@ -800,7 +800,7 @@ namespace MWWorld void World::advanceTime (double hours) { - MWBase::Environment::get().getMechanicsManager()->advanceTime(hours*3600); + MWBase::Environment::get().getMechanicsManager()->advanceTime(static_cast(hours * 3600)); mWeatherManager->advanceTime (hours); @@ -808,7 +808,7 @@ namespace MWWorld setHour (hours); - int days = hours / 24; + int days = static_cast(hours / 24); if (days>0) mGlobalVariables["dayspassed"].setInteger ( @@ -820,15 +820,15 @@ namespace MWWorld if (hour<0) hour = 0; - int days = hour / 24; + int days = static_cast(hour / 24); hour = std::fmod (hour, 24); - mGlobalVariables["gamehour"].setFloat (hour); + mGlobalVariables["gamehour"].setFloat(static_cast(hour)); mRendering->skySetHour (hour); - mWeatherManager->setHour (hour); + mWeatherManager->setHour(static_cast(hour)); if (days>0) setDay (days + mGlobalVariables["day"].getInteger()); @@ -1015,25 +1015,9 @@ namespace MWWorld float World::getMaxActivationDistance () { if (mActivationDistanceOverride >= 0) - return mActivationDistanceOverride; - - return (std::max) (getNpcActivationDistance (), getObjectActivationDistance ()); - } - - float World::getNpcActivationDistance () - { - if (mActivationDistanceOverride >= 0) - return mActivationDistanceOverride; - - return getStore().get().find ("iMaxActivateDist")->getInt()*5/4; - } - - float World::getObjectActivationDistance () - { - if (mActivationDistanceOverride >= 0) - return mActivationDistanceOverride; + return static_cast(mActivationDistanceOverride); - return getStore().get().find ("iMaxActivateDist")->getInt(); + return getStore().get().find("iMaxActivateDist")->getFloat() * 5 / 4; } MWWorld::Ptr World::getFacedObject() @@ -1387,8 +1371,8 @@ namespace MWWorld { const int cellSize = 8192; - x = cellSize * cellX; - y = cellSize * cellY; + x = static_cast(cellSize * cellX); + y = static_cast(cellSize * cellY); if (centre) { @@ -1401,8 +1385,8 @@ namespace MWWorld { const int cellSize = 8192; - cellX = std::floor(x/cellSize); - cellY = std::floor(y/cellSize); + cellX = static_cast(std::floor(x / cellSize)); + cellY = static_cast(std::floor(y / cellSize)); } void World::queueMovement(const Ptr &ptr, const Vector3 &velocity) @@ -1621,7 +1605,7 @@ namespace MWWorld { Ogre::Vector3 playerPos = mPlayer->getPlayer().getRefData().getBaseNode()->getPosition(); const OEngine::Physic::PhysicActor *actor = mPhysEngine->getCharacter(getPlayerPtr().getRefData().getHandle()); - if(actor) playerPos.z += 1.85*actor->getHalfExtents().z; + if(actor) playerPos.z += 1.85f * actor->getHalfExtents().z; Ogre::Quaternion playerOrient = Ogre::Quaternion(Ogre::Radian(getPlayerPtr().getRefData().getPosition().rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z) * Ogre::Quaternion(Ogre::Radian(getPlayerPtr().getRefData().getPosition().rot[0]), Ogre::Vector3::NEGATIVE_UNIT_X) * Ogre::Quaternion(Ogre::Radian(getPlayerPtr().getRefData().getPosition().rot[1]), Ogre::Vector3::NEGATIVE_UNIT_Y); @@ -2013,7 +1997,7 @@ namespace MWWorld bool World::isSubmerged(const MWWorld::Ptr &object) const { - return isUnderwater(object, 1.0/mSwimHeightScale); + return isUnderwater(object, 1.0f/mSwimHeightScale); } bool World::isSwimming(const MWWorld::Ptr &object) const @@ -2371,8 +2355,8 @@ namespace MWWorld Ogre::Vector3 halfExt2 = actor2->getHalfExtents(); const float* pos2 = targetActor.getRefData().getPosition().pos; - btVector3 from(pos1[0],pos1[1],pos1[2]+halfExt1.z*2*0.9); // eye level - btVector3 to(pos2[0],pos2[1],pos2[2]+halfExt2.z*2*0.9); + btVector3 from(pos1[0],pos1[1],pos1[2]+halfExt1.z*2*0.9f); // eye level + btVector3 to(pos2[0],pos2[1],pos2[2]+halfExt2.z*2*0.9f); std::pair result = mPhysEngine->rayTest(from, to,false); if(result.first == "") return true; @@ -2591,7 +2575,7 @@ namespace MWWorld const Store &gmst = getStore().get(); MWMechanics::NpcStats &stats = actor.getClass().getNpcStats(actor); - stats.getSkill(ESM::Skill::Acrobatics).setBase(gmst.find("fWerewolfAcrobatics")->getFloat()); + stats.getSkill(ESM::Skill::Acrobatics).setBase(gmst.find("fWerewolfAcrobatics")->getInt()); } bool World::getGodModeState() @@ -3071,8 +3055,8 @@ namespace MWWorld float fCrimeGoldDiscountMult = getStore().get().find("fCrimeGoldDiscountMult")->getFloat(); float fCrimeGoldTurnInMult = getStore().get().find("fCrimeGoldTurnInMult")->getFloat(); - int discount = bounty * fCrimeGoldDiscountMult; - int turnIn = bounty * fCrimeGoldTurnInMult; + int discount = static_cast(bounty * fCrimeGoldDiscountMult); + int turnIn = static_cast(bounty * fCrimeGoldTurnInMult); if (bounty > 0) { @@ -3153,7 +3137,7 @@ namespace MWWorld const ESM::CreatureLevList* list = getStore().get().find(creatureList); int iNumberCreatures = getStore().get().find("iNumberCreatures")->getInt(); - int numCreatures = 1 + std::rand()/ (static_cast (RAND_MAX) + 1) * iNumberCreatures; // [1, iNumberCreatures] + int numCreatures = static_cast(1 + std::rand() / (static_cast (RAND_MAX)+1) * iNumberCreatures); // [1, iNumberCreatures] for (int i=0; i (RAND_MAX) + 1) * 3; // [0, 2] + int roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 3); // [0, 2] modelName << roll; std::string model = "meshes\\" + getFallback()->getFallbackString(modelName.str()); @@ -3235,7 +3219,7 @@ namespace MWWorld else areaStatic = getStore().get().find ("VFX_DefaultArea"); - mRendering->spawnEffect("meshes\\" + areaStatic->mModel, "", origin, effectIt->mArea); + mRendering->spawnEffect("meshes\\" + areaStatic->mModel, "", origin, static_cast(effectIt->mArea)); // Play explosion sound (make sure to use NoTrack, since we will delete the projectile now) static const std::string schools[] = { @@ -3251,7 +3235,7 @@ namespace MWWorld // Get the actors in range of the effect std::vector objects; MWBase::Environment::get().getMechanicsManager()->getObjectsInRange( - origin, feetToGameUnits(effectIt->mArea), objects); + origin, feetToGameUnits(static_cast(effectIt->mArea)), objects); for (std::vector::iterator affected = objects.begin(); affected != objects.end(); ++affected) toApply[*affected].push_back(*effectIt); } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 1db86f738..63d6506de 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -115,9 +115,6 @@ namespace MWWorld void performUpdateSceneQueries (); void getFacedHandle(std::string& facedHandle, float maxDistance, bool ignorePlayer=true); - float getNpcActivationDistance (); - float getObjectActivationDistance (); - void removeContainerScripts(const Ptr& reference); void addContainerScripts(const Ptr& reference, CellStore* cell); void PCDropped (const Ptr& item); diff --git a/components/esm/loadpgrd.cpp b/components/esm/loadpgrd.cpp index 61f56b511..fc0974c9d 100644 --- a/components/esm/loadpgrd.cpp +++ b/components/esm/loadpgrd.cpp @@ -10,22 +10,22 @@ namespace ESM Pathgrid::Point& Pathgrid::Point::operator=(const float rhs[3]) { - mX = rhs[0]; - mY = rhs[1]; - mZ = rhs[2]; + mX = static_cast(rhs[0]); + mY = static_cast(rhs[1]); + mZ = static_cast(rhs[2]); mAutogenerated = 0; mConnectionNum = 0; mUnknown = 0; return *this; } Pathgrid::Point::Point(const float rhs[3]) - : mAutogenerated(0), + : mX(static_cast(rhs[0])), + mY(static_cast(rhs[1])), + mZ(static_cast(rhs[2])), + mAutogenerated(0), mConnectionNum(0), mUnknown(0) { - mX = rhs[0]; - mY = rhs[1]; - mZ = rhs[2]; } Pathgrid::Point::Point():mX(0),mY(0),mZ(0),mAutogenerated(0), mConnectionNum(0),mUnknown(0) diff --git a/components/esm/loadrace.cpp b/components/esm/loadrace.cpp index 967c0d0d7..e88454d4c 100644 --- a/components/esm/loadrace.cpp +++ b/components/esm/loadrace.cpp @@ -15,7 +15,7 @@ namespace ESM int Race::MaleFemaleF::getValue (bool male) const { - return male ? mMale : mFemale; + return static_cast(male ? mMale : mFemale); } void Race::load(ESMReader &esm) diff --git a/components/esm/statstate.hpp b/components/esm/statstate.hpp index 801d0ce82..f57ba9f30 100644 --- a/components/esm/statstate.hpp +++ b/components/esm/statstate.hpp @@ -40,7 +40,7 @@ namespace ESM // mDamage was changed to a float; ensure backwards compatibility T oldDamage = 0; esm.getHNOT(oldDamage, "STDA"); - mDamage = oldDamage; + mDamage = static_cast(oldDamage); esm.getHNOT (mDamage, "STDF"); diff --git a/components/esm/variantimp.cpp b/components/esm/variantimp.cpp index fd068fc19..eeb0bf04f 100644 --- a/components/esm/variantimp.cpp +++ b/components/esm/variantimp.cpp @@ -128,7 +128,7 @@ int ESM::VariantIntegerData::getInteger (bool default_) const float ESM::VariantIntegerData::getFloat (bool default_) const { - return mValue; + return static_cast(mValue); } void ESM::VariantIntegerData::setInteger (int value) @@ -202,7 +202,7 @@ void ESM::VariantIntegerData::write (ESMWriter& esm, Variant::Format format, Var { if (type==VT_Short || type==VT_Long) { - float value = mValue; + float value = static_cast(mValue); esm.writeHNString ("FNAM", type==VT_Short ? "s" : "l"); esm.writeHNT ("FLTV", value); } @@ -262,7 +262,7 @@ float ESM::VariantFloatData::getFloat (bool default_) const void ESM::VariantFloatData::setInteger (int value) { - mValue = value; + mValue = static_cast(value); } void ESM::VariantFloatData::setFloat (float value) diff --git a/components/esmterrain/storage.cpp b/components/esmterrain/storage.cpp index 9c7beebce..763f0f4e0 100644 --- a/components/esmterrain/storage.cpp +++ b/components/esmterrain/storage.cpp @@ -27,8 +27,8 @@ namespace ESMTerrain assert(origin.x == (int) origin.x); assert(origin.y == (int) origin.y); - int cellX = origin.x; - int cellY = origin.y; + int cellX = static_cast(origin.x); + int cellY = static_cast(origin.y); const ESM::Land* land = getLand(cellX, cellY); if (!land || !(land->mDataTypes&ESM::Land::DATA_VHGT)) @@ -135,10 +135,10 @@ namespace ESMTerrain assert(origin.x == (int) origin.x); assert(origin.y == (int) origin.y); - int startX = origin.x; - int startY = origin.y; + int startX = static_cast(origin.x); + int startY = static_cast(origin.y); - size_t numVerts = size*(ESM::Land::LAND_SIZE-1)/increment + 1; + size_t numVerts = static_cast(size*(ESM::Land::LAND_SIZE - 1) / increment + 1); colours.resize(numVerts*numVerts*4); positions.resize(numVerts*numVerts*3); @@ -175,12 +175,12 @@ namespace ESMTerrain vertX = vertX_; for (int row=rowStart; row(vertX*numVerts * 3 + vertY * 3)] = ((vertX / float(numVerts - 1) - 0.5f) * size * 8192); + positions[static_cast(vertX*numVerts * 3 + vertY * 3 + 1)] = ((vertY / float(numVerts - 1) - 0.5f) * size * 8192); if (land) - positions[vertX*numVerts*3 + vertY*3 + 2] = land->mLandData->mHeights[col*ESM::Land::LAND_SIZE+row]; + positions[static_cast(vertX*numVerts * 3 + vertY * 3 + 2)] = land->mLandData->mHeights[col*ESM::Land::LAND_SIZE + row]; else - positions[vertX*numVerts*3 + vertY*3 + 2] = -2048; + positions[static_cast(vertX*numVerts * 3 + vertY * 3 + 2)] = -2048; if (land && land->mDataTypes&ESM::Land::DATA_VNML) { @@ -202,9 +202,9 @@ namespace ESMTerrain assert(normal.z > 0); - normals[vertX*numVerts*3 + vertY*3] = normal.x; - normals[vertX*numVerts*3 + vertY*3 + 1] = normal.y; - normals[vertX*numVerts*3 + vertY*3 + 2] = normal.z; + normals[static_cast(vertX*numVerts * 3 + vertY * 3)] = normal.x; + normals[static_cast(vertX*numVerts * 3 + vertY * 3 + 1)] = normal.y; + normals[static_cast(vertX*numVerts * 3 + vertY * 3 + 2)] = normal.z; if (land && land->mDataTypes&ESM::Land::DATA_VCLR) { @@ -226,7 +226,7 @@ namespace ESMTerrain color.a = 1; Ogre::uint32 rsColor; Ogre::Root::getSingleton().getRenderSystem()->convertColourValue(color, &rsColor); - memcpy(&colours[vertX*numVerts*4 + vertY*4], &rsColor, sizeof(Ogre::uint32)); + memcpy(&colours[static_cast(vertX*numVerts * 4 + vertY * 4)], &rsColor, sizeof(Ogre::uint32)); ++vertX; } @@ -293,7 +293,7 @@ namespace ESMTerrain { out.push_back(Terrain::LayerCollection()); out.back().mTarget = *it; - getBlendmapsImpl((*it)->getSize(), (*it)->getCenter(), pack, out.back().mBlendmaps, out.back().mLayers); + getBlendmapsImpl(static_cast((*it)->getSize()), (*it)->getCenter(), pack, out.back().mBlendmaps, out.back().mLayers); } } @@ -311,8 +311,8 @@ namespace ESMTerrain // and interpolate the rest of the cell by hand? :/ Ogre::Vector2 origin = chunkCenter - Ogre::Vector2(chunkSize/2.f, chunkSize/2.f); - int cellX = origin.x; - int cellY = origin.y; + int cellX = static_cast(origin.x); + int cellY = static_cast(origin.y); // Save the used texture indices so we know the total number of textures // and number of required blend maps @@ -343,7 +343,7 @@ namespace ESMTerrain int numTextures = textureIndices.size(); // numTextures-1 since the base layer doesn't need blending - int numBlendmaps = pack ? std::ceil((numTextures-1) / 4.f) : (numTextures-1); + int numBlendmaps = pack ? static_cast(std::ceil((numTextures - 1) / 4.f)) : (numTextures - 1); int channels = pack ? 4 : 1; @@ -364,7 +364,7 @@ namespace ESMTerrain { UniqueTextureId id = getVtexIndexAt(cellX, cellY, x, y); int layerIndex = textureIndicesMap.find(id)->second; - int blendIndex = (pack ? std::floor((layerIndex-1)/4.f) : layerIndex-1); + int blendIndex = (pack ? static_cast(std::floor((layerIndex - 1) / 4.f)) : layerIndex - 1); int channel = pack ? std::max(0, (layerIndex-1) % 4) : 0; if (blendIndex == i) @@ -379,8 +379,8 @@ namespace ESMTerrain float Storage::getHeightAt(const Ogre::Vector3 &worldPos) { - int cellX = std::floor(worldPos.x / 8192.f); - int cellY = std::floor(worldPos.y / 8192.f); + int cellX = static_cast(std::floor(worldPos.x / 8192.f)); + int cellY = static_cast(std::floor(worldPos.y / 8192.f)); ESM::Land* land = getLand(cellX, cellY); if (!land || !(land->mDataTypes&ESM::Land::DATA_VHGT)) @@ -519,7 +519,7 @@ namespace ESMTerrain float Storage::getCellWorldSize() { - return ESM::Land::REAL_SIZE; + return static_cast(ESM::Land::REAL_SIZE); } int Storage::getCellVertices() diff --git a/components/fontloader/fontloader.cpp b/components/fontloader/fontloader.cpp index 17c630fd9..0ca37ad11 100644 --- a/components/fontloader/fontloader.cpp +++ b/components/fontloader/fontloader.cpp @@ -288,7 +288,7 @@ namespace Gui code->addAttribute("advance", data[i].width); code->addAttribute("bearing", MyGUI::utility::toString(data[i].kerning) + " " + MyGUI::utility::toString((fontSize-data[i].ascent))); - code->addAttribute("size", MyGUI::IntSize(data[i].width, data[i].height)); + code->addAttribute("size", MyGUI::IntSize(static_cast(data[i].width), static_cast(data[i].height))); // More hacks! The french game uses several win1252 characters that are not included // in the cp437 encoding of the font. Fall back to similar available characters. @@ -334,7 +334,7 @@ namespace Gui code->addAttribute("advance", data[i].width); code->addAttribute("bearing", MyGUI::utility::toString(data[i].kerning) + " " + MyGUI::utility::toString((fontSize-data[i].ascent))); - code->addAttribute("size", MyGUI::IntSize(data[i].width, data[i].height)); + code->addAttribute("size", MyGUI::IntSize(static_cast(data[i].width), static_cast(data[i].height))); } } @@ -350,7 +350,7 @@ namespace Gui cursorCode->addAttribute("advance", data[i].width); cursorCode->addAttribute("bearing", MyGUI::utility::toString(data[i].kerning) + " " + MyGUI::utility::toString((fontSize-data[i].ascent))); - cursorCode->addAttribute("size", MyGUI::IntSize(data[i].width, data[i].height)); + cursorCode->addAttribute("size", MyGUI::IntSize(static_cast(data[i].width), static_cast(data[i].height))); } // Question mark, use for NotDefined marker (used for glyphs not existing in the font) @@ -365,7 +365,7 @@ namespace Gui cursorCode->addAttribute("advance", data[i].width); cursorCode->addAttribute("bearing", MyGUI::utility::toString(data[i].kerning) + " " + MyGUI::utility::toString((fontSize-data[i].ascent))); - cursorCode->addAttribute("size", MyGUI::IntSize(data[i].width, data[i].height)); + cursorCode->addAttribute("size", MyGUI::IntSize(static_cast(data[i].width), static_cast(data[i].height))); } } diff --git a/components/terrain/defaultworld.cpp b/components/terrain/defaultworld.cpp index e14c64f3a..c6f0f7136 100644 --- a/components/terrain/defaultworld.cpp +++ b/components/terrain/defaultworld.cpp @@ -108,8 +108,8 @@ namespace Terrain storage->getBounds(mMinX, mMaxX, mMinY, mMaxY); - int origSizeX = mMaxX-mMinX; - int origSizeY = mMaxY-mMinY; + int origSizeX = static_cast(mMaxX - mMinX); + int origSizeY = static_cast(mMaxY - mMinY); // Dividing a quad tree only works well for powers of two, so round up to the nearest one int size = nextPowerOfTwo(std::max(origSizeX, origSizeY)); @@ -124,7 +124,7 @@ namespace Terrain LayersRequestData data; data.mPack = getShadersEnabled(); - mRootNode = new QuadTreeNode(this, Root, size, Ogre::Vector2(centerX, centerY), NULL); + mRootNode = new QuadTreeNode(this, Root, static_cast(size), Ogre::Vector2(centerX, centerY), NULL); buildQuadTree(mRootNode, data.mNodes); //loadingListener->indicateProgress(); mRootNode->initAabb(); @@ -160,7 +160,7 @@ namespace Terrain float minZ,maxZ; Ogre::Vector2 center = node->getCenter(); float cellWorldSize = getStorage()->getCellWorldSize(); - if (mStorage->getMinMaxHeights(node->getSize(), center, minZ, maxZ)) + if (mStorage->getMinMaxHeights(static_cast(node->getSize()), center, minZ, maxZ)) { Ogre::AxisAlignedBox bounds(Ogre::Vector3(-halfSize*cellWorldSize, -halfSize*cellWorldSize, minZ), Ogre::Vector3(halfSize*cellWorldSize, halfSize*cellWorldSize, maxZ)); @@ -275,7 +275,7 @@ namespace Terrain LoadResponseData* responseData = new LoadResponseData(); - getStorage()->fillVertexBuffers(node->getNativeLodLevel(), node->getSize(), node->getCenter(), getAlign(), + getStorage()->fillVertexBuffers(node->getNativeLodLevel(), static_cast(node->getSize()), node->getCenter(), getAlign(), responseData->mPositions, responseData->mNormals, responseData->mColours); return OGRE_NEW Ogre::WorkQueue::Response(req, true, Ogre::Any(responseData)); diff --git a/components/terrain/defaultworld.hpp b/components/terrain/defaultworld.hpp index 90e8cc2b6..4caef8462 100644 --- a/components/terrain/defaultworld.hpp +++ b/components/terrain/defaultworld.hpp @@ -84,7 +84,7 @@ namespace Terrain /// adding or removing passes. This can only be achieved by a full rebuild.) virtual void applyMaterials(bool shadows, bool splitShadows); - int getMaxBatchSize() { return mMaxBatchSize; } + int getMaxBatchSize() { return static_cast(mMaxBatchSize); } /// Wait until all background loading is complete. void syncLoad(); diff --git a/components/terrain/material.cpp b/components/terrain/material.cpp index 4ff04ab93..4d2318aa6 100644 --- a/components/terrain/material.cpp +++ b/components/terrain/material.cpp @@ -36,7 +36,7 @@ namespace int getBlendmapIndexForLayer (int layerIndex) { - return std::floor((layerIndex-1)/4.f); + return static_cast(std::floor((layerIndex - 1) / 4.f)); } std::string getBlendmapComponentForLayer (int layerIndex) diff --git a/components/terrain/quadtreenode.cpp b/components/terrain/quadtreenode.cpp index 5fce5eae9..6a9964213 100644 --- a/components/terrain/quadtreenode.cpp +++ b/components/terrain/quadtreenode.cpp @@ -135,7 +135,7 @@ QuadTreeNode::QuadTreeNode(DefaultWorld* terrain, ChildDirection dir, float size : mMaterialGenerator(NULL) , mIsDummy(false) , mSize(size) - , mLodLevel(Log2(mSize)) + , mLodLevel(Log2(static_cast(mSize))) , mBounds(Ogre::AxisAlignedBox::BOX_NULL) , mWorldBounds(Ogre::AxisAlignedBox::BOX_NULL) , mDirection(dir) diff --git a/components/terrain/quadtreenode.hpp b/components/terrain/quadtreenode.hpp index 1ecd6fcd5..e44b64600 100644 --- a/components/terrain/quadtreenode.hpp +++ b/components/terrain/quadtreenode.hpp @@ -95,7 +95,7 @@ namespace Terrain Ogre::SceneNode* getSceneNode() { return mSceneNode; } - int getSize() { return mSize; } + int getSize() { return static_cast(mSize); } Ogre::Vector2 getCenter() { return mCenter; } bool hasChildren() { return mChildren[0] != 0; } diff --git a/components/terrain/terraingrid.cpp b/components/terrain/terraingrid.cpp index 269152e61..bb99ca23e 100644 --- a/components/terrain/terraingrid.cpp +++ b/components/terrain/terraingrid.cpp @@ -56,16 +56,16 @@ void TerrainGrid::loadCell(int x, int y) if (mGrid.find(std::make_pair(x, y)) != mGrid.end()) return; // already loaded - Ogre::Vector2 center(x+0.5, y+0.5); + Ogre::Vector2 center(x+0.5f, y+0.5f); float minH, maxH; if (!mStorage->getMinMaxHeights(1, center, minH, maxH)) return; // no terrain defined - Ogre::Vector3 min (-0.5*mStorage->getCellWorldSize(), - -0.5*mStorage->getCellWorldSize(), + Ogre::Vector3 min (-0.5f*mStorage->getCellWorldSize(), + -0.5f*mStorage->getCellWorldSize(), minH); - Ogre::Vector3 max (0.5*mStorage->getCellWorldSize(), - 0.5*mStorage->getCellWorldSize(), + Ogre::Vector3 max (0.5f*mStorage->getCellWorldSize(), + 0.5f*mStorage->getCellWorldSize(), maxH); Ogre::AxisAlignedBox bounds(min, max); @@ -163,8 +163,8 @@ void TerrainGrid::setVisible(bool visible) Ogre::AxisAlignedBox TerrainGrid::getWorldBoundingBox (const Ogre::Vector2& center) { - int cellX = std::floor(center.x); - int cellY = std::floor(center.y); + int cellX = static_cast(std::floor(center.x)); + int cellY = static_cast(std::floor(center.y)); Grid::iterator it = mGrid.find(std::make_pair(cellX, cellY)); if (it == mGrid.end()) diff --git a/components/widgets/list.cpp b/components/widgets/list.cpp index f3d3a2c28..8517a0303 100644 --- a/components/widgets/list.cpp +++ b/components/widgets/list.cpp @@ -138,10 +138,10 @@ namespace Gui void MWList::onMouseWheel(MyGUI::Widget* _sender, int _rel) { //NB view offset is negative - if (mScrollView->getViewOffset().top + _rel*0.3 > 0) + if (mScrollView->getViewOffset().top + _rel*0.3f > 0) mScrollView->setViewOffset(MyGUI::IntPoint(0, 0)); else - mScrollView->setViewOffset(MyGUI::IntPoint(0, mScrollView->getViewOffset().top + _rel*0.3)); + mScrollView->setViewOffset(MyGUI::IntPoint(0, static_cast(mScrollView->getViewOffset().top + _rel*0.3))); } void MWList::onItemSelected(MyGUI::Widget* _sender) diff --git a/extern/sdl4ogre/sdlcursormanager.cpp b/extern/sdl4ogre/sdlcursormanager.cpp index 7623d57db..fab9051e7 100644 --- a/extern/sdl4ogre/sdlcursormanager.cpp +++ b/extern/sdl4ogre/sdlcursormanager.cpp @@ -91,7 +91,7 @@ namespace SFO // we use a render target to uncompress the DDS texture // just blitting doesn't seem to work on D3D9 - OEngine::Render::ImageRotate::rotate(tex->getName(), tempName, -rotDegrees); + OEngine::Render::ImageRotate::rotate(tex->getName(), tempName, static_cast(-rotDegrees)); Ogre::TexturePtr resultTexture = Ogre::TextureManager::getSingleton().getByName(tempName); @@ -110,7 +110,8 @@ namespace SFO Ogre::ColourValue clr = destImage.getColourAt(x, y, 0); //set the pixel on the SDL surface to the same value as the Ogre texture's - _putPixel(surf, x, y, SDL_MapRGBA(surf->format, clr.r*255, clr.g*255, clr.b*255, clr.a*255)); + _putPixel(surf, x, y, SDL_MapRGBA(surf->format, static_cast(clr.r * 255), + static_cast(clr.g * 255), static_cast(clr.b * 255), static_cast(clr.a * 255))); } } diff --git a/extern/sdl4ogre/sdlwindowhelper.cpp b/extern/sdl4ogre/sdlwindowhelper.cpp index 44993947f..637fae0ef 100644 --- a/extern/sdl4ogre/sdlwindowhelper.cpp +++ b/extern/sdl4ogre/sdlwindowhelper.cpp @@ -93,7 +93,8 @@ void SDLWindowHelper::setWindowIcon(const std::string &name) int bpp = surface->format->BytesPerPixel; /* Here p is the address to the pixel we want to set */ Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp; - Uint32 pixel = SDL_MapRGBA(surface->format, clr.r*255, clr.g*255, clr.b*255, clr.a*255); + Uint32 pixel = SDL_MapRGBA(surface->format, static_cast(clr.r * 255), + static_cast(clr.g * 255), static_cast(clr.b * 255), static_cast(clr.a * 255)); switch(bpp) { case 1: *p = pixel; diff --git a/libs/openengine/bullet/BtOgre.cpp b/libs/openengine/bullet/BtOgre.cpp index de9ea6f57..88619b7fc 100644 --- a/libs/openengine/bullet/BtOgre.cpp +++ b/libs/openengine/bullet/BtOgre.cpp @@ -215,7 +215,7 @@ namespace BtOgre { if (mBoundRadius == (-1)) { getSize(); - mBoundRadius = (std::max(mBounds.x,std::max(mBounds.y,mBounds.z)) * 0.5); + mBoundRadius = (std::max(mBounds.x,std::max(mBounds.y,mBounds.z)) * 0.5f); } return mBoundRadius; } @@ -737,7 +737,7 @@ namespace BtOgre { { box_kCenter += vertices[c]; } - const Ogre::Real invVertexCount = 1.0 / vertex_count; + const Ogre::Real invVertexCount = 1.0f / vertex_count; box_kCenter *= invVertexCount; } Quaternion orient = boneOrientation; @@ -782,9 +782,9 @@ namespace BtOgre { box_afExtent.y = ((Real)0.5)*(fY1Max - fY1Min); box_afExtent.z = ((Real)0.5)*(fY2Max - fY2Min); - box_kCenter += (0.5*(fY0Max+fY0Min))*box_akAxis[0] + - (0.5*(fY1Max+fY1Min))*box_akAxis[1] + - (0.5*(fY2Max+fY2Min))*box_akAxis[2]; + box_kCenter += (0.5f*(fY0Max+fY0Min))*box_akAxis[0] + + (0.5f*(fY1Max+fY1Min))*box_akAxis[1] + + (0.5f*(fY2Max+fY2Min))*box_akAxis[2]; box_afExtent *= 2.0; diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index e0482104a..81a2eb043 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -385,7 +385,7 @@ namespace Physic } btHeightfieldTerrainShape* hfShape = new btHeightfieldTerrainShape( - sqrtVerts, sqrtVerts, heights, 1, + static_cast(sqrtVerts), static_cast(sqrtVerts), heights, 1, minh, maxh, 2, PHY_FLOAT,true); @@ -396,7 +396,7 @@ namespace Physic btRigidBody::btRigidBodyConstructionInfo CI = btRigidBody::btRigidBodyConstructionInfo(0,0,hfShape); RigidBody* body = new RigidBody(CI,name); - body->getWorldTransform().setOrigin(btVector3( (x+0.5)*triSize*(sqrtVerts-1), (y+0.5)*triSize*(sqrtVerts-1), (maxh+minh)/2.f)); + body->getWorldTransform().setOrigin(btVector3( (x+0.5f)*triSize*(sqrtVerts-1), (y+0.5f)*triSize*(sqrtVerts-1), (maxh+minh)/2.f)); HeightField hf; hf.mBody = body; @@ -720,7 +720,7 @@ namespace Physic void PhysicEngine::stepSimulation(double deltaT) { // This seems to be needed for character controller objects - mDynamicsWorld->stepSimulation(deltaT,10, 1/60.0); + mDynamicsWorld->stepSimulation(static_cast(deltaT), 10, 1 / 60.0f); if(isDebugCreated) { mDebugDrawer->step(); diff --git a/libs/openengine/ogre/lights.cpp b/libs/openengine/ogre/lights.cpp index 348057b84..97fa938da 100644 --- a/libs/openengine/ogre/lights.cpp +++ b/libs/openengine/ogre/lights.cpp @@ -74,16 +74,16 @@ Ogre::Real LightFunction::calculate(Ogre::Real value) if(mType == LT_Normal) { // Less than 1/255 light modifier for a constant light: - brightness = 1.0 + flickerAmplitude(mDeltaCount*slow)/255.0f; + brightness = 1.0f + flickerAmplitude(mDeltaCount*slow)/255.0f; } else if(mType == LT_Flicker) - brightness = 0.75 + flickerAmplitude(mDeltaCount*fast)*0.25; + brightness = 0.75f + flickerAmplitude(mDeltaCount*fast)*0.25f; else if(mType == LT_FlickerSlow) - brightness = 0.75 + flickerAmplitude(mDeltaCount*slow)*0.25; + brightness = 0.75f + flickerAmplitude(mDeltaCount*slow)*0.25f; else if(mType == LT_Pulse) - brightness = 1.0 + pulseAmplitude(mDeltaCount*fast)*0.25; + brightness = 1.0f + pulseAmplitude(mDeltaCount*fast)*0.25f; else if(mType == LT_PulseSlow) - brightness = 1.0 + pulseAmplitude(mDeltaCount*slow)*0.25; + brightness = 1.0f + pulseAmplitude(mDeltaCount*slow)*0.25f; return brightness; } diff --git a/libs/openengine/ogre/renderer.cpp b/libs/openengine/ogre/renderer.cpp index 0e37d2802..bdeeeb8c4 100644 --- a/libs/openengine/ogre/renderer.cpp +++ b/libs/openengine/ogre/renderer.cpp @@ -184,7 +184,7 @@ void OgreRenderer::setWindowGammaContrast(float gamma, float contrast) if (value > 65535) value = 65535; else if (value < 0) value = 0; - red[i] = green[i] = blue[i] = value; + red[i] = green[i] = blue[i] = static_cast(value); } if (SDL_SetWindowGammaRamp(mSDLWindow, red, green, blue) < 0) std::cout << "Couldn't set gamma: " << SDL_GetError() << std::endl; diff --git a/libs/openengine/ogre/selectionbuffer.cpp b/libs/openengine/ogre/selectionbuffer.cpp index 0ca24676e..87b85732b 100644 --- a/libs/openengine/ogre/selectionbuffer.cpp +++ b/libs/openengine/ogre/selectionbuffer.cpp @@ -26,7 +26,7 @@ namespace Render setupRenderTarget(); - mCurrentColour = Ogre::ColourValue(0.3, 0.3, 0.3); + mCurrentColour = Ogre::ColourValue(0.3f, 0.3f, 0.3f); } void SelectionBuffer::setupRenderTarget() @@ -145,7 +145,7 @@ namespace Render void SelectionBuffer::getNextColour () { - Ogre::ARGB color = (float(rand()) / float(RAND_MAX)) * std::numeric_limits::max(); + Ogre::ARGB color = static_cast((float(rand()) / float(RAND_MAX)) * std::numeric_limits::max()); if (mCurrentColour.getAsARGB () == color) { From e6cd8484a2366c38f9bbfc3167ee1dafa93b896c Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 8 Mar 2015 13:22:56 +1300 Subject: [PATCH 0705/3725] fixing MSVC 2013 warning C4244: & C4305 fixes for mistakes in last commit. --- apps/openmw/mwclass/door.cpp | 2 +- apps/openmw/mwgui/bookpage.cpp | 16 ++++++++-------- apps/openmw/mwgui/inventorywindow.cpp | 2 +- apps/openmw/mwgui/mapwindow.cpp | 17 +++-------------- apps/openmw/mwgui/settingswindow.cpp | 2 +- apps/openmw/mwgui/tradewindow.cpp | 2 +- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 2 +- 8 files changed, 17 insertions(+), 28 deletions(-) diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 6e1d5334d..2d39881b1 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -176,7 +176,7 @@ namespace MWClass { MWBase::Environment::get().getSoundManager()->fadeOutSound3D(ptr, openSound, 0.5f); - float offset = 1.0 - ptr.getRefData().getLocalRotation().rot[2]/ 3.14159265f * 2.0f; + float offset = 1.0f - ptr.getRefData().getLocalRotation().rot[2]/ 3.14159265f * 2.0f; //most if not all door have closing bang somewhere in the middle of the sound, //so we divide offset by two action->setSoundOffset(offset * 0.5f); diff --git a/apps/openmw/mwgui/bookpage.cpp b/apps/openmw/mwgui/bookpage.cpp index 9d2f52bfd..962e594ae 100644 --- a/apps/openmw/mwgui/bookpage.cpp +++ b/apps/openmw/mwgui/bookpage.cpp @@ -624,14 +624,14 @@ namespace RenderXform (MyGUI::ICroppedRectangle* croppedParent, MyGUI::RenderTargetInfo const & renderTargetInfo) { clipTop = static_cast(croppedParent->_getMarginTop()); - clipLeft = static_cast(croppedParent->_getMarginLeft ()); - clipRight = static_cast(croppedParent->getWidth () - croppedParent->_getMarginRight ()); - clipBottom = static_cast(croppedParent->getHeight() - croppedParent->_getMarginBottom()); - - absoluteLeft = static_cast(croppedParent->getAbsoluteLeft()); - absoluteTop = static_cast(croppedParent->getAbsoluteTop()); - leftOffset = static_cast(renderTargetInfo.leftOffset); - topOffset = static_cast(renderTargetInfo.topOffset); + clipLeft = static_cast(croppedParent->_getMarginLeft ()); + clipRight = static_cast(croppedParent->getWidth () - croppedParent->_getMarginRight ()); + clipBottom = static_cast(croppedParent->getHeight() - croppedParent->_getMarginBottom()); + + absoluteLeft = static_cast(croppedParent->getAbsoluteLeft()); + absoluteTop = static_cast(croppedParent->getAbsoluteTop()); + leftOffset = static_cast(renderTargetInfo.leftOffset); + topOffset = static_cast(renderTargetInfo.topOffset); pixScaleX = renderTargetInfo.pixScaleX; pixScaleY = renderTargetInfo.pixScaleY; diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index a6722319d..919228195 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -101,7 +101,7 @@ namespace MWGui void InventoryWindow::adjustPanes() { const float aspect = 0.5; // fixed aspect ratio for the avatar image - int leftPaneWidth = static_cast(mMainWidget->getSize().height - 44 - mArmorRating->getHeight()) * aspect); + int leftPaneWidth = static_cast((mMainWidget->getSize().height - 44 - mArmorRating->getHeight()) * aspect); mLeftPane->setSize( leftPaneWidth, mMainWidget->getSize().height-44 ); mRightPane->setCoord( mLeftPane->getPosition().left + leftPaneWidth + 4, mRightPane->getPosition().top, diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 271e43d29..02e8ffdfe 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -264,7 +264,7 @@ namespace MWGui // Image space is -Y up, cells are Y up widgetPos = MyGUI::IntPoint(static_cast(nX * mMapWidgetSize + (1 + (cellX - mCurX)) * mMapWidgetSize), - static_cast(nY * mMapWidgetSize + (1-(cellY-mCurY)) * mMapWidgetSize)); + static_cast(nY * mMapWidgetSize + (1-(cellY-mCurY)) * mMapWidgetSize)); } markerPos.nX = nX; @@ -827,18 +827,7 @@ namespace MWGui if (MWBase::Environment::get().getWorld ()->isCellExterior ()) { Ogre::Vector3 pos = MWBase::Environment::get().getWorld ()->getPlayerPtr().getRefData ().getBaseNode ()->_getDerivedPosition (); - - float worldX, worldY; - mGlobalMapRender->worldPosToImageSpace (pos.x, pos.y, worldX, worldY); - worldX *= mGlobalMapRender->getWidth(); - worldY *= mGlobalMapRender->getHeight(); - - mPlayerArrowGlobal->setPosition(MyGUI::IntPoint(static_cast(worldX - 16), static_cast(worldY - 16))); - - // set the view offset so that player is in the center - MyGUI::IntSize viewsize = mGlobalMap->getSize(); - MyGUI::IntPoint viewoffs((viewsize.width / 2) - worldX, (viewsize.height / 2) - worldY); - mGlobalMap->setViewOffset(viewoffs); + setGlobalMapPlayerPosition(pos.x, pos.y); } } @@ -858,7 +847,7 @@ namespace MWGui // set the view offset so that player is in the center MyGUI::IntSize viewsize = mGlobalMap->getSize(); - MyGUI::IntPoint viewoffs((viewsize.width / 2) - x, (viewsize.height / 2) - y); + MyGUI::IntPoint viewoffs(static_cast(viewsize.width * 0.5f - x), static_cast(viewsize.height *0.5 - y)); mGlobalMap->setViewOffset(viewoffs); } diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 5bb82bc69..d895a28ea 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -148,7 +148,7 @@ namespace MWGui value = std::max(min, std::min(value, max)); value = (value-min)/(max-min); - scroll->setScrollPosition( value * (scroll->getScrollRange()-1)); + scroll->setScrollPosition(static_cast(value * (scroll->getScrollRange() - 1))); } else { diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 5015ef456..841e2e185 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -34,7 +34,7 @@ namespace int getEffectiveValue (MWWorld::Ptr item, int count) { - float price = item.getClass().getValue(item); + float price = static_cast(item.getClass().getValue(item)); if (item.getClass().hasItemHealth(item)) { price *= item.getClass().getItemHealth(item); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 5633ce3b7..bf1d3ec19 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1480,7 +1480,7 @@ namespace MWMechanics disposition = getDerivedDisposition(ptr); int fight = std::max(0, ptr.getClass().getCreatureStats(ptr).getAiSetting(CreatureStats::AI_Fight).getModified() - + static_cast(getFightDistanceBias(ptr, target) + getFightDispositionBias(disposition))); + + static_cast(getFightDistanceBias(ptr, target) + getFightDispositionBias(static_cast(disposition)))); if (ptr.getClass().isNpc() && target.getClass().isNpc()) { diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index ebd756781..97b2cd204 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1350,7 +1350,7 @@ namespace MWWorld pos.pos[2] += dist; actor.getRefData().setPosition(pos); - Ogre::Vector3 traced = mPhysics->traceDown(actor, dist*1.1); + Ogre::Vector3 traced = mPhysics->traceDown(actor, dist*1.1f); moveObject(actor, actor.getCell(), traced.x, traced.y, traced.z); } From ca8c8c6aa4ff1c6889e31a4c579f182f1ff7794f Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 8 Mar 2015 17:42:07 +1300 Subject: [PATCH 0706/3725] fixing MSVC 2013 warning C4244: & C4305 conversion from 'const float' to 'int', possible loss of data conversion from 'double' to 'int', possible loss of data conversion from 'float' to 'int', possible loss of data --- apps/openmw/mwgui/repair.cpp | 4 +- apps/openmw/mwmechanics/activespells.cpp | 10 ++-- apps/openmw/mwmechanics/actors.cpp | 30 +++++------ apps/openmw/mwmechanics/aiavoiddoor.cpp | 4 +- apps/openmw/mwmechanics/aicombat.cpp | 30 +++++------ apps/openmw/mwmechanics/aicombataction.cpp | 16 +++--- apps/openmw/mwmechanics/aiescort.cpp | 8 +-- apps/openmw/mwmechanics/aipackage.cpp | 2 +- apps/openmw/mwmechanics/aitravel.cpp | 12 ++--- apps/openmw/mwmechanics/aiwander.cpp | 57 +++++++------------- apps/openmw/mwmechanics/alchemy.cpp | 18 +++---- apps/openmw/mwmechanics/autocalcspell.cpp | 2 +- apps/openmw/mwmechanics/character.cpp | 16 +++--- apps/openmw/mwmechanics/combat.cpp | 26 ++++----- apps/openmw/mwmechanics/creaturestats.cpp | 6 +-- apps/openmw/mwmechanics/enchanting.cpp | 18 +++---- apps/openmw/mwmechanics/npcstats.cpp | 4 +- apps/openmw/mwmechanics/pathfinding.cpp | 23 ++++---- apps/openmw/mwmechanics/pathfinding.hpp | 26 +++++++-- apps/openmw/mwmechanics/pathgrid.cpp | 14 ++--- apps/openmw/mwmechanics/pickpocket.cpp | 14 ++--- apps/openmw/mwmechanics/repair.cpp | 6 +-- apps/openmw/mwmechanics/security.cpp | 16 +++--- apps/openmw/mwmechanics/spellcasting.cpp | 62 +++++++++++----------- apps/openmw/mwmechanics/stat.cpp | 6 +-- apps/openmw/mwmechanics/stat.hpp | 2 +- apps/openmw/mwrender/objects.cpp | 2 +- apps/openmw/mwworld/inventorystore.cpp | 2 +- 28 files changed, 214 insertions(+), 222 deletions(-) diff --git a/apps/openmw/mwgui/repair.cpp b/apps/openmw/mwgui/repair.cpp index c3c971400..9f26923d4 100644 --- a/apps/openmw/mwgui/repair.cpp +++ b/apps/openmw/mwgui/repair.cpp @@ -150,10 +150,10 @@ void Repair::onRepairItem(MyGUI::Widget *sender) void Repair::onMouseWheel(MyGUI::Widget* _sender, int _rel) { - if (mRepairView->getViewOffset().top + _rel*0.3 > 0) + if (mRepairView->getViewOffset().top + _rel*0.3f > 0) mRepairView->setViewOffset(MyGUI::IntPoint(0, 0)); else - mRepairView->setViewOffset(MyGUI::IntPoint(0, mRepairView->getViewOffset().top + _rel*0.3)); + mRepairView->setViewOffset(MyGUI::IntPoint(0, static_cast(mRepairView->getViewOffset().top + _rel*0.3f))); } } diff --git a/apps/openmw/mwmechanics/activespells.cpp b/apps/openmw/mwmechanics/activespells.cpp index b4701126b..5eea08caa 100644 --- a/apps/openmw/mwmechanics/activespells.cpp +++ b/apps/openmw/mwmechanics/activespells.cpp @@ -74,9 +74,9 @@ namespace MWMechanics for (std::vector::const_iterator effectIt = effects.begin(); effectIt != effects.end(); ++effectIt) { - int duration = effectIt->mDuration; + double duration = effectIt->mDuration; MWWorld::TimeStamp end = start; - end += static_cast (duration)* + end += duration * MWBase::Environment::get().getWorld()->getTimeScaleFactor()/(60*60); if (end>now) @@ -110,7 +110,7 @@ namespace MWMechanics { const std::vector& effects = iterator->second.mEffects; - int duration = 0; + float duration = 0; for (std::vector::const_iterator iter (effects.begin()); iter!=effects.end(); ++iter) @@ -216,7 +216,7 @@ namespace MWMechanics std::string name = it->second.mDisplayName; float remainingTime = effectIt->mDuration + - (it->second.mTimeStamp - MWBase::Environment::get().getWorld()->getTimeStamp())*3600/timeScale; + static_cast(it->second.mTimeStamp - MWBase::Environment::get().getWorld()->getTimeStamp())*3600/timeScale; float magnitude = effectIt->mMagnitude; if (magnitude) @@ -229,7 +229,7 @@ namespace MWMechanics { for (TContainer::iterator it = mSpells.begin(); it != mSpells.end(); ) { - int roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 100; // [0, 99] + int roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 100); // [0, 99] if (roll < chance) mSpells.erase(it++); else diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index aa2cc8615..f9de97132 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -84,8 +84,8 @@ bool disintegrateSlot (MWWorld::Ptr ptr, int slot, float disintegrate) // FIXME: charge should be a float, not int so that damage < 1 per frame can be applied. // This was also a bug in the original engine. charge -= - std::min(disintegrate, - static_cast(charge)); + std::min(static_cast(disintegrate), + charge); item->getCellRef().setCharge(charge); if (charge == 0) @@ -163,7 +163,7 @@ void getRestorationPerHourOfSleep (const MWWorld::Ptr& ptr, float& health, float bool stunted = stats.getMagicEffects ().get(ESM::MagicEffect::StuntedMagicka).getMagnitude() > 0; int endurance = stats.getAttribute (ESM::Attribute::Endurance).getModified (); - health = 0.1 * endurance; + health = 0.1f * endurance; magicka = 0; if (!stunted) @@ -203,7 +203,7 @@ namespace MWMechanics static const float fSoulgemMult = world->getStore().get().find("fSoulgemMult")->getFloat(); - float creatureSoulValue = mCreature.get()->mBase->mData.mSoul; + int creatureSoulValue = mCreature.get()->mBase->mData.mSoul; if (creatureSoulValue == 0) return; @@ -519,8 +519,8 @@ namespace MWMechanics effects.get(EffectKey(ESM::MagicEffect::DrainAttribute, i)).getMagnitude(), effects.get(EffectKey(ESM::MagicEffect::AbsorbAttribute, i)).getMagnitude()); - stat.damage(effects.get(EffectKey(ESM::MagicEffect::DamageAttribute, i)).getMagnitude() * duration * 1.5); - stat.restore(effects.get(EffectKey(ESM::MagicEffect::RestoreAttribute, i)).getMagnitude() * duration * 1.5); + stat.damage(effects.get(EffectKey(ESM::MagicEffect::DamageAttribute, i)).getMagnitude() * duration * 1.5f); + stat.restore(effects.get(EffectKey(ESM::MagicEffect::RestoreAttribute, i)).getMagnitude() * duration * 1.5f); creatureStats.setAttribute(i, stat); } @@ -566,19 +566,19 @@ namespace MWMechanics if (!creature || ptr.get()->mBase->mData.mType == ESM::Creature::Creatures) { Stat stat = creatureStats.getAiSetting(CreatureStats::AI_Fight); - stat.setModifier(creatureStats.getMagicEffects().get(ESM::MagicEffect::FrenzyHumanoid+creature).getMagnitude() - - creatureStats.getMagicEffects().get(ESM::MagicEffect::CalmHumanoid+creature).getMagnitude()); + stat.setModifier(static_cast(creatureStats.getMagicEffects().get(ESM::MagicEffect::FrenzyHumanoid + creature).getMagnitude() + - creatureStats.getMagicEffects().get(ESM::MagicEffect::CalmHumanoid+creature).getMagnitude())); creatureStats.setAiSetting(CreatureStats::AI_Fight, stat); stat = creatureStats.getAiSetting(CreatureStats::AI_Flee); - stat.setModifier(creatureStats.getMagicEffects().get(ESM::MagicEffect::DemoralizeHumanoid+creature).getMagnitude() - - creatureStats.getMagicEffects().get(ESM::MagicEffect::RallyHumanoid+creature).getMagnitude()); + stat.setModifier(static_cast(creatureStats.getMagicEffects().get(ESM::MagicEffect::DemoralizeHumanoid + creature).getMagnitude() + - creatureStats.getMagicEffects().get(ESM::MagicEffect::RallyHumanoid+creature).getMagnitude())); creatureStats.setAiSetting(CreatureStats::AI_Flee, stat); } if (creature && ptr.get()->mBase->mData.mType == ESM::Creature::Undead) { Stat stat = creatureStats.getAiSetting(CreatureStats::AI_Flee); - stat.setModifier(creatureStats.getMagicEffects().get(ESM::MagicEffect::TurnUndead).getMagnitude()); + stat.setModifier(static_cast(creatureStats.getMagicEffects().get(ESM::MagicEffect::TurnUndead).getMagnitude())); creatureStats.setAiSetting(CreatureStats::AI_Flee, stat); } @@ -741,7 +741,7 @@ namespace MWMechanics for (std::map::iterator it = boundItemsMap.begin(); it != boundItemsMap.end(); ++it) { bool found = creatureStats.mBoundItems.find(it->first) != creatureStats.mBoundItems.end(); - int magnitude = creatureStats.getMagicEffects().get(it->first).getMagnitude(); + float magnitude = creatureStats.getMagicEffects().get(it->first).getMagnitude(); if (found != (magnitude > 0)) { std::string itemGmst = it->second; @@ -786,8 +786,8 @@ namespace MWMechanics effects.get(EffectKey(ESM::MagicEffect::DrainSkill, i)).getMagnitude(), effects.get(EffectKey(ESM::MagicEffect::AbsorbSkill, i)).getMagnitude()); - skill.damage(effects.get(EffectKey(ESM::MagicEffect::DamageSkill, i)).getMagnitude() * duration * 1.5); - skill.restore(effects.get(EffectKey(ESM::MagicEffect::RestoreSkill, i)).getMagnitude() * duration * 1.5); + skill.damage(effects.get(EffectKey(ESM::MagicEffect::DamageSkill, i)).getMagnitude() * duration * 1.5f); + skill.restore(effects.get(EffectKey(ESM::MagicEffect::RestoreSkill, i)).getMagnitude() * duration * 1.5f); } } @@ -1331,7 +1331,7 @@ namespace MWMechanics ? (stats.getMagicka().getModified() - stats.getMagicka().getCurrent()) / magickaPerHour : 1.0f; - int autoHours = std::ceil(std::max(1.f, std::max(healthHours, magickaHours))); + int autoHours = static_cast(std::ceil(std::max(1.f, std::max(healthHours, magickaHours)))); return autoHours; } diff --git a/apps/openmw/mwmechanics/aiavoiddoor.cpp b/apps/openmw/mwmechanics/aiavoiddoor.cpp index b9954337d..a73d955c5 100644 --- a/apps/openmw/mwmechanics/aiavoiddoor.cpp +++ b/apps/openmw/mwmechanics/aiavoiddoor.cpp @@ -31,12 +31,12 @@ bool MWMechanics::AiAvoidDoor::execute (const MWWorld::Ptr& actor, AiState& stat float x = pos.pos[0] - mLastPos.pos[0]; float y = pos.pos[1] - mLastPos.pos[1]; float z = pos.pos[2] - mLastPos.pos[2]; - int distance = x * x + y * y + z * z; + float distance = x * x + y * y + z * z; if(distance < 10 * 10) { //Got stuck, didn't move if(mAdjAngle == 0) //Try going in various directions mAdjAngle = 1.57079632679f; //pi/2 else if (mAdjAngle == 1.57079632679f) - mAdjAngle = -1.57079632679; + mAdjAngle = -1.57079632679f; else mAdjAngle = 0; mDuration = 1; //reset timer diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index fd4fd293d..c16baefaa 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -404,7 +404,7 @@ namespace MWMechanics { const MWWorld::ESMStore &store = world->getStore(); int chance = store.get().find("iVoiceAttackOdds")->getInt(); - int roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 100; // [0, 99] + int roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 100); // [0, 99] if (roll < chance) { MWBase::Environment::get().getDialogueManager()->say(actor, "attack"); @@ -521,7 +521,7 @@ namespace MWMechanics //apply sideway movement (kind of dodging) with some probability if(static_cast(rand())/RAND_MAX < 0.25) { - movement.mPosition[0] = static_cast(rand())/RAND_MAX < 0.5? 1: -1; + movement.mPosition[0] = static_cast(rand())/RAND_MAX < 0.5? 1.0f : -1.0f; timerCombatMove = 0.05f + 0.15f * static_cast(rand())/RAND_MAX; combatMove = true; } @@ -588,7 +588,7 @@ namespace MWMechanics // get point just before target std::list::const_iterator pntIter = --mPathFinder.getPath().end(); --pntIter; - Ogre::Vector3 vBeforeTarget = Ogre::Vector3(pntIter->mX, pntIter->mY, pntIter->mZ); + Ogre::Vector3 vBeforeTarget(PathFinder::MakeOgreVector3(*pntIter)); // if current actor pos is closer to target then last point of path (excluding target itself) then go straight on target if(distToTarget <= (vTargetPos - vBeforeTarget).length()) @@ -685,27 +685,21 @@ namespace MWMechanics if(!mPathFinder.getPath().empty()) { ESM::Pathgrid::Point lastPt = mPathFinder.getPath().back(); - Ogre::Vector3 currPathTarget(lastPt.mX, lastPt.mY, lastPt.mZ); + Ogre::Vector3 currPathTarget(PathFinder::MakeOgreVector3(lastPt)); dist = (newPathTarget - currPathTarget).length(); } else dist = 1e+38F; // necessarily construct a new path - float targetPosThreshold = (actor.getCell()->getCell()->isExterior())? 300 : 100; + float targetPosThreshold = (actor.getCell()->getCell()->isExterior())? 300.0f : 100.0f; //construct new path only if target has moved away more than on [targetPosThreshold] if(dist > targetPosThreshold) { ESM::Position pos = actor.getRefData().getPosition(); - ESM::Pathgrid::Point start; - start.mX = pos.pos[0]; - start.mY = pos.pos[1]; - start.mZ = pos.pos[2]; + ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(pos)); - ESM::Pathgrid::Point dest; - dest.mX = newPathTarget.x; - dest.mY = newPathTarget.y; - dest.mZ = newPathTarget.z; + ESM::Pathgrid::Point dest(PathFinder::MakePathgridPoint(newPathTarget)); if(!mPathFinder.isPathConstructed()) mPathFinder.buildPath(start, dest, actor.getCell(), false); @@ -770,7 +764,7 @@ ESM::Weapon::AttackType chooseBestAttack(const ESM::Weapon* weapon, MWMechanics: float roll = static_cast(rand())/RAND_MAX; if(roll <= 0.333f) //side punch { - movement.mPosition[0] = (static_cast(rand())/RAND_MAX < 0.5f)? 1: -1; + movement.mPosition[0] = (static_cast(rand())/RAND_MAX < 0.5f)? 1.0f : -1.0f; movement.mPosition[1] = 0; attackType = ESM::Weapon::AT_Slash; } @@ -792,16 +786,16 @@ ESM::Weapon::AttackType chooseBestAttack(const ESM::Weapon* weapon, MWMechanics: int chop = (weapon->mData.mChop[0] + weapon->mData.mChop[1])/2; int thrust = (weapon->mData.mThrust[0] + weapon->mData.mThrust[1])/2; - float total = slash + chop + thrust; + float total = static_cast(slash + chop + thrust); float roll = static_cast(rand())/RAND_MAX; - if(roll <= static_cast(slash)/total) + if(roll <= (slash/total)) { - movement.mPosition[0] = (static_cast(rand())/RAND_MAX < 0.5f)? 1: -1; + movement.mPosition[0] = (static_cast(rand())/RAND_MAX < 0.5f)? 1.0f : -1.0f; movement.mPosition[1] = 0; attackType = ESM::Weapon::AT_Slash; } - else if(roll <= (static_cast(slash) + static_cast(thrust))/total) + else if(roll <= (slash + (thrust/total))) { movement.mPosition[1] = 1; attackType = ESM::Weapon::AT_Thrust; diff --git a/apps/openmw/mwmechanics/aicombataction.cpp b/apps/openmw/mwmechanics/aicombataction.cpp index 175b98001..33e3c3d67 100644 --- a/apps/openmw/mwmechanics/aicombataction.cpp +++ b/apps/openmw/mwmechanics/aicombataction.cpp @@ -323,14 +323,14 @@ namespace MWMechanics if (effect.mAttribute >= 0 && effect.mAttribute < ESM::Attribute::Length) { const float attributePriorities[ESM::Attribute::Length] = { - 1.f, // Strength - 0.5, // Intelligence - 0.6, // Willpower - 0.7, // Agility - 0.5, // Speed - 0.8, // Endurance - 0.7, // Personality - 0.3 // Luck + 1.0f, // Strength + 0.5f, // Intelligence + 0.6f, // Willpower + 0.7f, // Agility + 0.5f, // Speed + 0.8f, // Endurance + 0.7f, // Personality + 0.3f // Luck }; rating *= attributePriorities[effect.mAttribute]; } diff --git a/apps/openmw/mwmechanics/aiescort.cpp b/apps/openmw/mwmechanics/aiescort.cpp index c89cfe492..91bf7c9b0 100644 --- a/apps/openmw/mwmechanics/aiescort.cpp +++ b/apps/openmw/mwmechanics/aiescort.cpp @@ -23,7 +23,7 @@ namespace MWMechanics { AiEscort::AiEscort(const std::string &actorId, int duration, float x, float y, float z) - : mActorId(actorId), mX(x), mY(y), mZ(z), mRemainingDuration(duration) + : mActorId(actorId), mX(x), mY(y), mZ(z), mRemainingDuration(static_cast(duration)) , mCellX(std::numeric_limits::max()) , mCellY(std::numeric_limits::max()) { @@ -36,7 +36,7 @@ namespace MWMechanics } AiEscort::AiEscort(const std::string &actorId, const std::string &cellId,int duration, float x, float y, float z) - : mActorId(actorId), mCellId(cellId), mX(x), mY(y), mZ(z), mRemainingDuration(duration) + : mActorId(actorId), mCellId(cellId), mX(x), mY(y), mZ(z), mRemainingDuration(static_cast(duration)) , mCellX(std::numeric_limits::max()) , mCellY(std::numeric_limits::max()) { @@ -86,13 +86,13 @@ namespace MWMechanics for (short counter = 0; counter < 3; counter++) differenceBetween[counter] = (leaderPos[counter] - followerPos[counter]); - float distanceBetweenResult = + double distanceBetweenResult = (differenceBetween[0] * differenceBetween[0]) + (differenceBetween[1] * differenceBetween[1]) + (differenceBetween[2] * differenceBetween[2]); if(distanceBetweenResult <= mMaxDist * mMaxDist) { - ESM::Pathgrid::Point point(mX,mY,mZ); + ESM::Pathgrid::Point point(static_cast(mX), static_cast(mY), static_cast(mZ)); point.mAutogenerated = 0; point.mConnectionNum = 0; point.mUnknown = 0; diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index f015bb8a4..f93376779 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -16,7 +16,7 @@ MWMechanics::AiPackage::~AiPackage() {} -MWMechanics::AiPackage::AiPackage() : mTimer(.26), mStuckTimer(0) { //mTimer starts at .26 to force initial pathbuild +MWMechanics::AiPackage::AiPackage() : mTimer(0.26f), mStuckTimer(0) { //mTimer starts at .26 to force initial pathbuild } diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index 7124a1102..a46fe7296 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -93,15 +93,9 @@ namespace MWMechanics mCellX = cell->mData.mX; mCellY = cell->mData.mY; - ESM::Pathgrid::Point dest; - dest.mX = mX; - dest.mY = mY; - dest.mZ = mZ; - - ESM::Pathgrid::Point start; - start.mX = pos.pos[0]; - start.mY = pos.pos[1]; - start.mZ = pos.pos[2]; + ESM::Pathgrid::Point dest(static_cast(mX), static_cast(mY), static_cast(mZ)); + + ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(pos)); mPathFinder.buildPath(start, dest, actor.getCell(), true); } diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 738facb13..842f03edf 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -192,7 +192,7 @@ namespace MWMechanics if(mDistance && // actor is not intended to be stationary idleNow && // but is in idle !walking && // FIXME: some actors are idle while walking - proximityToDoor(actor, MIN_DIST_TO_DOOR_SQUARED*1.6*1.6)) // NOTE: checks interior cells only + proximityToDoor(actor, MIN_DIST_TO_DOOR_SQUARED*1.6f*1.6f)) // NOTE: checks interior cells only { idleNow = false; moveNow = true; @@ -315,13 +315,13 @@ namespace MWMechanics static float fVoiceIdleOdds = MWBase::Environment::get().getWorld()->getStore() .get().find("fVoiceIdleOdds")->getFloat(); - float roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 10000; + float roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 10000; // In vanilla MW the chance was FPS dependent, and did not allow proper changing of fVoiceIdleOdds // due to the roll being an integer. // Our implementation does not have these issues, so needs to be recalibrated. We chose to // use the chance MW would have when run at 60 FPS with the default value of the GMST for calibration. - float x = fVoiceIdleOdds * 0.6 * (MWBase::Environment::get().getFrameDuration() / 0.1); + float x = fVoiceIdleOdds * 0.6f * (MWBase::Environment::get().getFrameDuration() / 0.1f); // Only say Idle voices when player is in LOS // A bit counterintuitive, likely vanilla did this to reduce the appearance of @@ -393,18 +393,10 @@ namespace MWMechanics if (!storage.mPathFinder.isPathConstructed()) { - Ogre::Vector3 destNodePos = mReturnPosition; - - ESM::Pathgrid::Point dest; - dest.mX = destNodePos[0]; - dest.mY = destNodePos[1]; - dest.mZ = destNodePos[2]; + ESM::Pathgrid::Point dest(PathFinder::MakePathgridPoint(mReturnPosition)); // actor position is already in world co-ordinates - ESM::Pathgrid::Point start; - start.mX = pos.pos[0]; - start.mY = pos.pos[1]; - start.mZ = pos.pos[2]; + ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(pos)); // don't take shortcuts for wandering storage.mPathFinder.buildPath(start, dest, actor.getCell(), false); @@ -422,7 +414,7 @@ namespace MWMechanics { // Play a random voice greeting if the player gets too close int hello = cStats.getAiSetting(CreatureStats::AI_Hello).getModified(); - float helloDistance = hello; + float helloDistance = static_cast(hello); static int iGreetDistanceMultiplier =MWBase::Environment::get().getWorld()->getStore() .get().find("iGreetDistanceMultiplier")->getInt(); @@ -500,15 +492,10 @@ namespace MWMechanics assert(mAllowedNodes.size()); unsigned int randNode = (int)(rand() / ((double)RAND_MAX + 1) * mAllowedNodes.size()); // NOTE: initially constructed with local (i.e. cell) co-ordinates - Ogre::Vector3 destNodePos(mAllowedNodes[randNode].mX, - mAllowedNodes[randNode].mY, - mAllowedNodes[randNode].mZ); + Ogre::Vector3 destNodePos(PathFinder::MakeOgreVector3(mAllowedNodes[randNode])); // convert dest to use world co-ordinates - ESM::Pathgrid::Point dest; - dest.mX = destNodePos[0]; - dest.mY = destNodePos[1]; - dest.mZ = destNodePos[2]; + ESM::Pathgrid::Point dest(PathFinder::MakePathgridPoint(destNodePos)); if (currentCell->getCell()->isExterior()) { dest.mX += currentCell->getCell()->mData.mX * ESM::Land::REAL_SIZE; @@ -516,10 +503,7 @@ namespace MWMechanics } // actor position is already in world co-ordinates - ESM::Pathgrid::Point start; - start.mX = pos.pos[0]; - start.mY = pos.pos[1]; - start.mZ = pos.pos[2]; + ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(pos)); // don't take shortcuts for wandering storage.mPathFinder.buildPath(start, dest, actor.getCell(), false); @@ -652,7 +636,7 @@ namespace MWMechanics static float fIdleChanceMultiplier = MWBase::Environment::get().getWorld()->getStore() .get().find("fIdleChanceMultiplier")->getFloat(); - unsigned short idleChance = fIdleChanceMultiplier * mIdle[counter]; + unsigned short idleChance = static_cast(fIdleChanceMultiplier * mIdle[counter]); unsigned short randSelect = (int)(rand() / ((double)RAND_MAX + 1) * int(100 / fIdleChanceMultiplier)); if(randSelect < idleChance && randSelect > idleRoll) { @@ -675,12 +659,12 @@ namespace MWMechanics state.moveIn(new AiWanderStorage()); - int index = std::rand() / (static_cast (RAND_MAX) + 1) * mAllowedNodes.size(); + int index = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * mAllowedNodes.size()); ESM::Pathgrid::Point dest = mAllowedNodes[index]; // apply a slight offset to prevent overcrowding - dest.mX += Ogre::Math::RangeRandom(-64, 64); - dest.mY += Ogre::Math::RangeRandom(-64, 64); + dest.mX += static_cast(Ogre::Math::RangeRandom(-64, 64)); + dest.mY += static_cast(Ogre::Math::RangeRandom(-64, 64)); if (actor.getCell()->isExterior()) { @@ -688,7 +672,8 @@ namespace MWMechanics dest.mY += actor.getCell()->getCell()->mData.mY * ESM::Land::REAL_SIZE; } - MWBase::Environment::get().getWorld()->moveObject(actor, dest.mX, dest.mY, dest.mZ); + MWBase::Environment::get().getWorld()->moveObject(actor, static_cast(dest.mX), + static_cast(dest.mY), static_cast(dest.mZ)); actor.getClass().adjustPosition(actor, false); } @@ -720,8 +705,8 @@ namespace MWMechanics float cellYOffset = 0; if(cell->isExterior()) { - cellXOffset = cell->mData.mX * ESM::Land::REAL_SIZE; - cellYOffset = cell->mData.mY * ESM::Land::REAL_SIZE; + cellXOffset = static_cast(cell->mData.mX * ESM::Land::REAL_SIZE); + cellYOffset = static_cast(cell->mData.mY * ESM::Land::REAL_SIZE); } // convert npcPos to local (i.e. cell) co-ordinates @@ -733,20 +718,18 @@ namespace MWMechanics // NOTE: mPoints and mAllowedNodes are in local co-ordinates for(unsigned int counter = 0; counter < pathgrid->mPoints.size(); counter++) { - Ogre::Vector3 nodePos(pathgrid->mPoints[counter].mX, pathgrid->mPoints[counter].mY, - pathgrid->mPoints[counter].mZ); + Ogre::Vector3 nodePos(PathFinder::MakeOgreVector3(pathgrid->mPoints[counter])); if(npcPos.squaredDistance(nodePos) <= mDistance * mDistance) mAllowedNodes.push_back(pathgrid->mPoints[counter]); } if(!mAllowedNodes.empty()) { - Ogre::Vector3 firstNodePos(mAllowedNodes[0].mX, mAllowedNodes[0].mY, mAllowedNodes[0].mZ); + Ogre::Vector3 firstNodePos(PathFinder::MakeOgreVector3(mAllowedNodes[0])); float closestNode = npcPos.squaredDistance(firstNodePos); unsigned int index = 0; for(unsigned int counterThree = 1; counterThree < mAllowedNodes.size(); counterThree++) { - Ogre::Vector3 nodePos(mAllowedNodes[counterThree].mX, mAllowedNodes[counterThree].mY, - mAllowedNodes[counterThree].mZ); + Ogre::Vector3 nodePos(PathFinder::MakeOgreVector3(mAllowedNodes[counterThree])); float tempDist = npcPos.squaredDistance(nodePos); if(tempDist < closestNode) index = counterThree; diff --git a/apps/openmw/mwmechanics/alchemy.cpp b/apps/openmw/mwmechanics/alchemy.cpp index 6e54b6f83..a833e28d9 100644 --- a/apps/openmw/mwmechanics/alchemy.cpp +++ b/apps/openmw/mwmechanics/alchemy.cpp @@ -94,17 +94,17 @@ void MWMechanics::Alchemy::applyTools (int flags, float& value) const quality = negative ? 2 * toolQuality + 3 * calcinatorQuality : (magnitude && duration ? - 2 * toolQuality + calcinatorQuality : 2/3.0 * (toolQuality + calcinatorQuality) + 0.5); + 2 * toolQuality + calcinatorQuality : 2/3.0f * (toolQuality + calcinatorQuality) + 0.5f); break; case 2: - quality = negative ? 1+toolQuality : (magnitude && duration ? toolQuality : toolQuality + 0.5); + quality = negative ? 1+toolQuality : (magnitude && duration ? toolQuality : toolQuality + 0.5f); break; case 3: - quality = magnitude && duration ? calcinatorQuality : calcinatorQuality + 0.5; + quality = magnitude && duration ? calcinatorQuality : calcinatorQuality + 0.5f; break; } @@ -178,8 +178,8 @@ void MWMechanics::Alchemy::updateEffects() if (!(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration)) applyTools (magicEffect->mData.mFlags, duration); - duration = static_cast (duration+0.5); - magnitude = static_cast (magnitude+0.5); + duration = roundf(duration); + magnitude = roundf(magnitude); if (magnitude>0 && duration>0) { @@ -197,8 +197,8 @@ void MWMechanics::Alchemy::updateEffects() effect.mRange = 0; effect.mArea = 0; - effect.mDuration = duration; - effect.mMagnMin = effect.mMagnMax = magnitude; + effect.mDuration = static_cast(duration); + effect.mMagnMin = effect.mMagnMax = static_cast(magnitude); mEffects.push_back (effect); } @@ -323,8 +323,8 @@ float MWMechanics::Alchemy::getAlchemyFactor() const return (npcStats.getSkill (ESM::Skill::Alchemy).getModified() + - 0.1 * creatureStats.getAttribute (ESM::Attribute::Intelligence).getModified() - + 0.1 * creatureStats.getAttribute (ESM::Attribute::Luck).getModified()); + 0.1f * creatureStats.getAttribute (ESM::Attribute::Intelligence).getModified() + + 0.1f * creatureStats.getAttribute (ESM::Attribute::Luck).getModified()); } int MWMechanics::Alchemy::countIngredients() const diff --git a/apps/openmw/mwmechanics/autocalcspell.cpp b/apps/openmw/mwmechanics/autocalcspell.cpp index 7b8c43a06..e4b143826 100644 --- a/apps/openmw/mwmechanics/autocalcspell.cpp +++ b/apps/openmw/mwmechanics/autocalcspell.cpp @@ -187,7 +187,7 @@ namespace MWMechanics for (std::vector::const_iterator it = effects.mList.begin(); it != effects.mList.end(); ++it) { const ESM::ENAMstruct& effect = *it; - float x = effect.mDuration; + float x = static_cast(effect.mDuration); const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get().find(effect.mEffectID); if (!(magicEffect->mData.mFlags & ESM::MagicEffect::UncappedDamage)) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 449c030f4..c8834e095 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -112,7 +112,7 @@ float getFallDamage(const MWWorld::Ptr& ptr, float fallHeight) if (fallHeight >= fallDistanceMin) { - const float acrobaticsSkill = ptr.getClass().getSkill(ptr, ESM::Skill::Acrobatics); + const float acrobaticsSkill = static_cast(ptr.getClass().getSkill(ptr, ESM::Skill::Acrobatics)); const float jumpSpellBonus = ptr.getClass().getCreatureStats(ptr).getMagicEffects().get(ESM::MagicEffect::Jump).getMagnitude(); const float fallAcroBase = store.find("fFallAcroBase")->getFloat(); const float fallAcroMult = store.find("fFallAcroMult")->getFloat(); @@ -120,7 +120,7 @@ float getFallDamage(const MWWorld::Ptr& ptr, float fallHeight) const float fallDistanceMult = store.find("fFallDistanceMult")->getFloat(); float x = fallHeight - fallDistanceMin; - x -= (1.5 * acrobaticsSkill) + jumpSpellBonus; + x -= (1.5f * acrobaticsSkill) + jumpSpellBonus; x = std::max(0.0f, x); float a = fallAcroBase + fallAcroMult * (100 - acrobaticsSkill); @@ -220,7 +220,7 @@ std::string CharacterController::chooseRandomGroup (const std::string& prefix, i while (mAnimation->hasAnimation(prefix + Ogre::StringConverter::toString(numAnims+1))) ++numAnims; - int roll = std::rand()/ (static_cast (RAND_MAX) + 1) * numAnims + 1; // [1, numAnims] + int roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * numAnims) + 1; // [1, numAnims] if (num) *num = roll; return prefix + Ogre::StringConverter::toString(roll); @@ -829,7 +829,7 @@ bool CharacterController::updateCreatureState() } if (weapType != WeapType_Spell || !mAnimation->hasAnimation("spellcast")) // Not all creatures have a dedicated spellcast animation { - int roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 3; // [0, 2] + int roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 3); // [0, 2] if (roll == 0) mCurrentWeapon = "attack1"; else if (roll == 1) @@ -1531,7 +1531,7 @@ void CharacterController::update(float duration) float normalizedEncumbrance = mPtr.getClass().getNormalizedEncumbrance(mPtr); if (normalizedEncumbrance > 1) normalizedEncumbrance = 1; - const int fatigueDecrease = fatigueJumpBase + (1 - normalizedEncumbrance) * fatigueJumpMult; + const float fatigueDecrease = fatigueJumpBase + (1 - normalizedEncumbrance) * fatigueJumpMult; DynamicStat fatigue = cls.getCreatureStats(mPtr).getFatigue(); fatigue.setCurrent(fatigue.getCurrent() - fatigueDecrease); cls.getCreatureStats(mPtr).setFatigue(fatigue); @@ -1551,12 +1551,12 @@ void CharacterController::update(float duration) // inflict fall damages DynamicStat health = cls.getCreatureStats(mPtr).getHealth(); - int realHealthLost = healthLost * (1.0f - 0.25 * fatigueTerm); + float realHealthLost = static_cast(healthLost * (1.0f - 0.25f * fatigueTerm)); health.setCurrent(health.getCurrent() - realHealthLost); cls.getCreatureStats(mPtr).setHealth(health); cls.onHit(mPtr, realHealthLost, true, MWWorld::Ptr(), MWWorld::Ptr(), true); - const float acrobaticsSkill = cls.getSkill(mPtr, ESM::Skill::Acrobatics); + const int acrobaticsSkill = cls.getSkill(mPtr, ESM::Skill::Acrobatics); if (healthLost > (acrobaticsSkill * fatigueTerm)) { cls.getCreatureStats(mPtr).setKnockedDown(true); @@ -1612,7 +1612,7 @@ void CharacterController::update(float duration) mTurnAnimationThreshold -= duration; if (movestate == CharState_TurnRight || movestate == CharState_TurnLeft) - mTurnAnimationThreshold = 0.05; + mTurnAnimationThreshold = 0.05f; else if (movestate == CharState_None && (mMovementState == CharState_TurnRight || mMovementState == CharState_TurnLeft) && mTurnAnimationThreshold > 0) { diff --git a/apps/openmw/mwmechanics/combat.cpp b/apps/openmw/mwmechanics/combat.cpp index e22e9ec24..42380664b 100644 --- a/apps/openmw/mwmechanics/combat.cpp +++ b/apps/openmw/mwmechanics/combat.cpp @@ -83,8 +83,8 @@ namespace MWMechanics MWMechanics::CreatureStats& attackerStats = attacker.getClass().getCreatureStats(attacker); - float blockTerm = blocker.getClass().getSkill(blocker, ESM::Skill::Block) + 0.2 * blockerStats.getAttribute(ESM::Attribute::Agility).getModified() - + 0.1 * blockerStats.getAttribute(ESM::Attribute::Luck).getModified(); + float blockTerm = blocker.getClass().getSkill(blocker, ESM::Skill::Block) + 0.2f * blockerStats.getAttribute(ESM::Attribute::Agility).getModified() + + 0.1f * blockerStats.getAttribute(ESM::Attribute::Luck).getModified(); float enemySwing = attackerStats.getAttackStrength(); float swingTerm = enemySwing * gmst.find("fSwingBlockMult")->getFloat() + gmst.find("fSwingBlockBase")->getFloat(); @@ -93,13 +93,13 @@ namespace MWMechanics blockerTerm *= gmst.find("fBlockStillBonus")->getFloat(); blockerTerm *= blockerStats.getFatigueTerm(); - float attackerSkill = 0.f; + int attackerSkill = 0; if (weapon.isEmpty()) attackerSkill = attacker.getClass().getSkill(attacker, ESM::Skill::HandToHand); else attackerSkill = attacker.getClass().getSkill(attacker, weapon.getClass().getEquipmentSkill(weapon)); - float attackerTerm = attackerSkill + 0.2 * attackerStats.getAttribute(ESM::Attribute::Agility).getModified() - + 0.1 * attackerStats.getAttribute(ESM::Attribute::Luck).getModified(); + float attackerTerm = attackerSkill + 0.2f * attackerStats.getAttribute(ESM::Attribute::Agility).getModified() + + 0.1f * attackerStats.getAttribute(ESM::Attribute::Luck).getModified(); attackerTerm *= attackerStats.getFatigueTerm(); int x = int(blockerTerm - attackerTerm); @@ -107,7 +107,7 @@ namespace MWMechanics int iBlockMinChance = gmst.find("iBlockMinChance")->getInt(); x = std::min(iBlockMaxChance, std::max(iBlockMinChance, x)); - int roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 100; // [0, 99] + int roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 100); // [0, 99] if (roll < x) { // Reduce shield durability by incoming damage @@ -183,7 +183,7 @@ namespace MWMechanics if(!weapon.isEmpty()) weapskill = weapon.getClass().getEquipmentSkill(weapon); - float skillValue = attacker.getClass().getSkill(attacker, + int skillValue = attacker.getClass().getSkill(attacker, weapon.getClass().getEquipmentSkill(weapon)); if((::rand()/(RAND_MAX+1.0)) > getHitChance(attacker, victim, skillValue)/100.0f) @@ -206,7 +206,7 @@ namespace MWMechanics } damage *= fDamageStrengthBase + - (attackerStats.getAttribute(ESM::Attribute::Strength).getModified() * fDamageStrengthMult * 0.1); + (attackerStats.getAttribute(ESM::Attribute::Strength).getModified() * fDamageStrengthMult * 0.1f); adjustWeaponDamage(damage, weapon); reduceWeaponCondition(damage, true, weapon, attacker); @@ -265,14 +265,14 @@ namespace MWMechanics + 0.2f * attackerStats.getAttribute(ESM::Attribute::Willpower).getModified() + 0.1f * attackerStats.getAttribute(ESM::Attribute::Luck).getModified(); - int fatigueMax = attackerStats.getFatigue().getModified(); - int fatigueCurrent = attackerStats.getFatigue().getCurrent(); + float fatigueMax = attackerStats.getFatigue().getModified(); + float fatigueCurrent = attackerStats.getFatigue().getCurrent(); - float normalisedFatigue = fatigueMax==0 ? 1 : std::max (0.0f, static_cast (fatigueCurrent)/fatigueMax); + float normalisedFatigue = floor(fatigueMax)==0 ? 1 : std::max (0.0f, (fatigueCurrent/fatigueMax)); saveTerm *= 1.25f * normalisedFatigue; - float roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 100; // [0, 99] + float roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 100; // [0, 99] float x = std::max(0.f, saveTerm - roll); int element = ESM::MagicEffect::FireDamage; @@ -344,7 +344,7 @@ namespace MWMechanics const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); float minstrike = store.get().find("fMinHandToHandMult")->getFloat(); float maxstrike = store.get().find("fMaxHandToHandMult")->getFloat(); - damage = attacker.getClass().getSkill(attacker, ESM::Skill::HandToHand); + damage = static_cast(attacker.getClass().getSkill(attacker, ESM::Skill::HandToHand)); damage *= minstrike + ((maxstrike-minstrike)*attacker.getClass().getCreatureStats(attacker).getAttackStrength()); MWMechanics::CreatureStats& otherstats = victim.getClass().getCreatureStats(victim); diff --git a/apps/openmw/mwmechanics/creaturestats.cpp b/apps/openmw/mwmechanics/creaturestats.cpp index 1947ad839..931c2f14e 100644 --- a/apps/openmw/mwmechanics/creaturestats.cpp +++ b/apps/openmw/mwmechanics/creaturestats.cpp @@ -42,10 +42,10 @@ namespace MWMechanics float CreatureStats::getFatigueTerm() const { - int max = getFatigue().getModified(); - int current = getFatigue().getCurrent(); + float max = getFatigue().getModified(); + float current = getFatigue().getCurrent(); - float normalised = max==0 ? 1 : std::max (0.0f, static_cast (current)/max); + float normalised = floor(max) == 0 ? 1 : std::max (0.0f, current / max); const MWWorld::Store &gmst = MWBase::Environment::get().getWorld()->getStore().get(); diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp index de5921a70..d99b337d5 100644 --- a/apps/openmw/mwmechanics/enchanting.cpp +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -176,7 +176,7 @@ namespace MWMechanics int magMax = (it->mMagnMax == 0) ? 1 : it->mMagnMax; int area = (it->mArea == 0) ? 1 : it->mArea; - float magnitudeCost = (magMin + magMax) * baseCost * 0.05; + float magnitudeCost = (magMin + magMax) * baseCost * 0.05f; if (mCastStyle == ESM::Enchantment::ConstantEffect) { magnitudeCost *= store.get().find("fEnchantmentConstantDurationMult")->getFloat(); @@ -186,7 +186,7 @@ namespace MWMechanics magnitudeCost *= it->mDuration; } - float areaCost = area * 0.05 * baseCost; + float areaCost = area * 0.05f * baseCost; const float fEffectCostMult = store.get().find("fEffectCostMult")->getFloat(); @@ -215,7 +215,7 @@ namespace MWMechanics { int baseCost = getBaseCastCost(); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); - return getEffectiveEnchantmentCastCost(baseCost, player); + return getEffectiveEnchantmentCastCost(static_cast(baseCost), player); } @@ -225,7 +225,7 @@ namespace MWMechanics return 0; float priceMultipler = MWBase::Environment::get().getWorld()->getStore().get().find ("fEnchantmentValueMult")->getFloat(); - int price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mEnchanter, (getEnchantPoints() * priceMultipler), true); + int price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mEnchanter, static_cast(getEnchantPoints() * priceMultipler), true); return price; } @@ -247,7 +247,7 @@ namespace MWMechanics const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); - return mOldItemPtr.getClass().getEnchantmentPoints(mOldItemPtr) * store.get().find("fEnchantmentMult")->getFloat(); + return static_cast(mOldItemPtr.getClass().getEnchantmentPoints(mOldItemPtr) * store.get().find("fEnchantmentMult")->getFloat()); } bool Enchanting::soulEmpty() const { @@ -274,13 +274,13 @@ namespace MWMechanics const NpcStats& npcStats = mEnchanter.getClass().getNpcStats (mEnchanter); float chance1 = (npcStats.getSkill (ESM::Skill::Enchant).getModified() + - (0.25 * npcStats.getAttribute (ESM::Attribute::Intelligence).getModified()) - + (0.125 * npcStats.getAttribute (ESM::Attribute::Luck).getModified())); + (0.25f * npcStats.getAttribute (ESM::Attribute::Intelligence).getModified()) + + (0.125f * npcStats.getAttribute (ESM::Attribute::Luck).getModified())); const MWWorld::Store& gmst = MWBase::Environment::get().getWorld()->getStore().get(); - float chance2 = 7.5 / (gmst.find("fEnchantmentChanceMult")->getFloat() * ((mCastStyle == ESM::Enchantment::ConstantEffect) ? - gmst.find("fEnchantmentConstantChanceMult")->getFloat() : 1 )) + float chance2 = 7.5f / (gmst.find("fEnchantmentChanceMult")->getFloat() * ((mCastStyle == ESM::Enchantment::ConstantEffect) ? + gmst.find("fEnchantmentConstantChanceMult")->getFloat() : 1.0f )) * getEnchantPoints(); return (chance1-chance2); diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index 58bf11cff..7f468f6d4 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -142,7 +142,7 @@ void MWMechanics::NpcStats::setFactionReputation (const std::string& faction, in float MWMechanics::NpcStats::getSkillProgressRequirement (int skillIndex, const ESM::Class& class_) const { - float progressRequirement = 1 + getSkill (skillIndex).getBase(); + float progressRequirement = static_cast(1 + getSkill(skillIndex).getBase()); const MWWorld::Store &gmst = MWBase::Environment::get().getWorld()->getStore().get(); @@ -303,7 +303,7 @@ void MWMechanics::NpcStats::updateHealth() const int endurance = getAttribute(ESM::Attribute::Endurance).getBase(); const int strength = getAttribute(ESM::Attribute::Strength).getBase(); - setHealth(static_cast (0.5 * (strength + endurance))); + setHealth(floor(0.5f * (strength + endurance))); } int MWMechanics::NpcStats::getLevelupAttributeMultiplier(int attribute) const diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index 0634725a8..e8abb9e98 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -17,7 +17,7 @@ namespace // float distanceSquared(ESM::Pathgrid::Point point, Ogre::Vector3 pos) { - return Ogre::Vector3(point.mX, point.mY, point.mZ).squaredDistance(pos); + return MWMechanics::PathFinder::MakeOgreVector3(point).squaredDistance(pos); } // Return the closest pathgrid point index from the specified position co @@ -95,7 +95,7 @@ namespace MWMechanics x -= point.mX; y -= point.mY; z -= point.mZ; - return (x * x + y * y + 0.1 * z * z); + return (x * x + y * y + 0.1f * z * z); } float distance(ESM::Pathgrid::Point point, float x, float y, float z) @@ -108,9 +108,9 @@ namespace MWMechanics float distance(ESM::Pathgrid::Point a, ESM::Pathgrid::Point b) { - float x = a.mX - b.mX; - float y = a.mY - b.mY; - float z = a.mZ - b.mZ; + float x = static_cast(a.mX - b.mX); + float y = static_cast(a.mY - b.mY); + float z = static_cast(a.mZ - b.mZ); return sqrt(x * x + y * y + z * z); } @@ -176,8 +176,9 @@ namespace MWMechanics if(allowShortcuts) { // if there's a ray cast hit, can't take a direct path - if(!MWBase::Environment::get().getWorld()->castRay(startPoint.mX, startPoint.mY, startPoint.mZ, - endPoint.mX, endPoint.mY, endPoint.mZ)) + if (!MWBase::Environment::get().getWorld()->castRay( + static_cast(startPoint.mX), static_cast(startPoint.mY), static_cast(startPoint.mZ), + static_cast(endPoint.mX), static_cast(endPoint.mY), static_cast(endPoint.mZ))) { mPath.push_back(endPoint); mIsPathConstructed = true; @@ -206,8 +207,8 @@ namespace MWMechanics float yCell = 0; if (mCell->isExterior()) { - xCell = mCell->getCell()->mData.mX * ESM::Land::REAL_SIZE; - yCell = mCell->getCell()->mData.mY * ESM::Land::REAL_SIZE; + xCell = static_cast(mCell->getCell()->mData.mX * ESM::Land::REAL_SIZE); + yCell = static_cast(mCell->getCell()->mData.mY * ESM::Land::REAL_SIZE); } // NOTE: It is possible that getClosestPoint returns a pathgrind point index @@ -216,12 +217,12 @@ namespace MWMechanics // point right behind the wall that is closer than any pathgrid // point outside the wall int startNode = getClosestPoint(mPathgrid, - Ogre::Vector3(startPoint.mX - xCell, startPoint.mY - yCell, startPoint.mZ)); + Ogre::Vector3(startPoint.mX - xCell, startPoint.mY - yCell, static_cast(startPoint.mZ))); // Some cells don't have any pathgrids at all if(startNode != -1) { std::pair endNode = getClosestReachablePoint(mPathgrid, cell, - Ogre::Vector3(endPoint.mX - xCell, endPoint.mY - yCell, endPoint.mZ), + Ogre::Vector3(endPoint.mX - xCell, endPoint.mY - yCell, static_cast(endPoint.mZ)), startNode); // this shouldn't really happen, but just in case diff --git a/apps/openmw/mwmechanics/pathfinding.hpp b/apps/openmw/mwmechanics/pathfinding.hpp index 7ba2d22ba..490cf9b88 100644 --- a/apps/openmw/mwmechanics/pathfinding.hpp +++ b/apps/openmw/mwmechanics/pathfinding.hpp @@ -1,10 +1,12 @@ #ifndef GAME_MWMECHANICS_PATHFINDING_H #define GAME_MWMECHANICS_PATHFINDING_H +#include #include #include #include +#include namespace MWWorld { @@ -27,11 +29,11 @@ namespace MWMechanics return -1.0; } - static float sgn(float a) + static int sgn(int a) { if(a > 0) - return 1.0; - return -1.0; + return 1; + return -1; } void clearPath(); @@ -74,6 +76,24 @@ namespace MWMechanics mPath.push_back(point); } + /// utility function to convert a Ogre::Vector3 to a Pathgrid::Point + static ESM::Pathgrid::Point MakePathgridPoint(const Ogre::Vector3& v) + { + return ESM::Pathgrid::Point(static_cast(v[0]), static_cast(v[1]), static_cast(v[2])); + } + + /// utility function to convert an ESM::Position to a Pathgrid::Point + static ESM::Pathgrid::Point MakePathgridPoint(const ESM::Position& p) + { + return ESM::Pathgrid::Point(static_cast(p.pos[0]), static_cast(p.pos[1]), static_cast(p.pos[2])); + } + + /// utility function to convert a Pathgrid::Point to a Ogre::Vector3 + static Ogre::Vector3 MakeOgreVector3(const ESM::Pathgrid::Point& p) + { + return Ogre::Vector3(static_cast(p.mX), static_cast(p.mY), static_cast(p.mZ)); + } + private: bool mIsPathConstructed; diff --git a/apps/openmw/mwmechanics/pathgrid.cpp b/apps/openmw/mwmechanics/pathgrid.cpp index 9e50af2b8..c1e094bb1 100644 --- a/apps/openmw/mwmechanics/pathgrid.cpp +++ b/apps/openmw/mwmechanics/pathgrid.cpp @@ -27,7 +27,7 @@ namespace // float manhattan(const ESM::Pathgrid::Point& a, const ESM::Pathgrid::Point& b) { - return 300 * (abs(a.mX - b.mX) + abs(a.mY - b.mY) + abs(a.mZ - b.mZ)); + return 300.0f * (abs(a.mX - b.mX) + abs(a.mY - b.mY) + abs(a.mZ - b.mZ)); } // Choose a heuristics - Note that these may not be the best for directed @@ -317,23 +317,23 @@ namespace MWMechanics float yCell = 0; if (mIsExterior) { - xCell = mPathgrid->mData.mX * ESM::Land::REAL_SIZE; - yCell = mPathgrid->mData.mY * ESM::Land::REAL_SIZE; + xCell = static_cast(mPathgrid->mData.mX * ESM::Land::REAL_SIZE); + yCell = static_cast(mPathgrid->mData.mY * ESM::Land::REAL_SIZE); } while(graphParent[current] != -1) { ESM::Pathgrid::Point pt = mPathgrid->mPoints[current]; - pt.mX += xCell; - pt.mY += yCell; + pt.mX += static_cast(xCell); + pt.mY += static_cast(yCell); path.push_front(pt); current = graphParent[current]; } // add first node to path explicitly ESM::Pathgrid::Point pt = mPathgrid->mPoints[start]; - pt.mX += xCell; - pt.mY += yCell; + pt.mX += static_cast(xCell); + pt.mY += static_cast(yCell); path.push_front(pt); return path; } diff --git a/apps/openmw/mwmechanics/pickpocket.cpp b/apps/openmw/mwmechanics/pickpocket.cpp index 14abcd643..12db9d6f5 100644 --- a/apps/openmw/mwmechanics/pickpocket.cpp +++ b/apps/openmw/mwmechanics/pickpocket.cpp @@ -20,10 +20,10 @@ namespace MWMechanics float Pickpocket::getChanceModifier(const MWWorld::Ptr &ptr, float add) { NpcStats& stats = ptr.getClass().getNpcStats(ptr); - float agility = stats.getAttribute(ESM::Attribute::Agility).getModified(); - float luck = stats.getAttribute(ESM::Attribute::Luck).getModified(); - float sneak = ptr.getClass().getSkill(ptr, ESM::Skill::Sneak); - return (add + 0.2 * agility + 0.1 * luck + sneak) * stats.getFatigueTerm(); + float agility = static_cast(stats.getAttribute(ESM::Attribute::Agility).getModified()); + float luck = static_cast(stats.getAttribute(ESM::Attribute::Luck).getModified()); + float sneak = static_cast(ptr.getClass().getSkill(ptr, ESM::Skill::Sneak)); + return (add + 0.2f * agility + 0.1f * luck + sneak) * stats.getFatigueTerm(); } bool Pickpocket::getDetected(float valueTerm) @@ -33,13 +33,13 @@ namespace MWMechanics float t = 2*x - y; - float pcSneak = mThief.getClass().getSkill(mThief, ESM::Skill::Sneak); + float pcSneak = static_cast(mThief.getClass().getSkill(mThief, ESM::Skill::Sneak)); int iPickMinChance = MWBase::Environment::get().getWorld()->getStore().get() .find("iPickMinChance")->getInt(); int iPickMaxChance = MWBase::Environment::get().getWorld()->getStore().get() .find("iPickMaxChance")->getInt(); - int roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 100; // [0, 99] + int roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 100); // [0, 99] if (t < pcSneak / iPickMinChance) { return (roll > int(pcSneak / iPickMinChance)); @@ -53,7 +53,7 @@ namespace MWMechanics bool Pickpocket::pick(MWWorld::Ptr item, int count) { - float stackValue = item.getClass().getValue(item) * count; + float stackValue = static_cast(item.getClass().getValue(item) * count); float fPickPocketMod = MWBase::Environment::get().getWorld()->getStore().get() .find("fPickPocketMod")->getFloat(); float valueTerm = 10 * fPickPocketMod * stackValue; diff --git a/apps/openmw/mwmechanics/repair.cpp b/apps/openmw/mwmechanics/repair.cpp index 6d6f889ed..486a9183d 100644 --- a/apps/openmw/mwmechanics/repair.cpp +++ b/apps/openmw/mwmechanics/repair.cpp @@ -44,12 +44,12 @@ void Repair::repair(const MWWorld::Ptr &itemToRepair) float toolQuality = ref->mBase->mData.mQuality; - float x = (0.1 * pcStrength + 0.1 * pcLuck + armorerSkill) * fatigueTerm; + float x = (0.1f * pcStrength + 0.1f * pcLuck + armorerSkill) * fatigueTerm; - int roll = static_cast (std::rand()) / RAND_MAX * 100; + int roll = static_cast(static_cast (std::rand()) / RAND_MAX * 100); if (roll <= x) { - int y = fRepairAmountMult * toolQuality * roll; + int y = static_cast(fRepairAmountMult * toolQuality * roll); y = std::max(1, y); // repair by 'y' points diff --git a/apps/openmw/mwmechanics/security.cpp b/apps/openmw/mwmechanics/security.cpp index 4a049d60f..d987814e5 100644 --- a/apps/openmw/mwmechanics/security.cpp +++ b/apps/openmw/mwmechanics/security.cpp @@ -20,9 +20,9 @@ namespace MWMechanics { CreatureStats& creatureStats = actor.getClass().getCreatureStats(actor); NpcStats& npcStats = actor.getClass().getNpcStats(actor); - mAgility = creatureStats.getAttribute(ESM::Attribute::Agility).getModified(); - mLuck = creatureStats.getAttribute(ESM::Attribute::Luck).getModified(); - mSecuritySkill = npcStats.getSkill(ESM::Skill::Security).getModified(); + mAgility = static_cast(creatureStats.getAttribute(ESM::Attribute::Agility).getModified()); + mLuck = static_cast(creatureStats.getAttribute(ESM::Attribute::Luck).getModified()); + mSecuritySkill = static_cast(npcStats.getSkill(ESM::Skill::Security).getModified()); mFatigueTerm = creatureStats.getFatigueTerm(); } @@ -38,7 +38,7 @@ namespace MWMechanics float fPickLockMult = MWBase::Environment::get().getWorld()->getStore().get().find("fPickLockMult")->getFloat(); - float x = 0.2 * mAgility + 0.1 * mLuck + mSecuritySkill; + float x = 0.2f * mAgility + 0.1f * mLuck + mSecuritySkill; x *= pickQuality * mFatigueTerm; x += fPickLockMult * lockStrength; @@ -48,7 +48,7 @@ namespace MWMechanics else { MWBase::Environment::get().getMechanicsManager()->objectOpened(mActor, lock); - int roll = static_cast (std::rand()) / RAND_MAX * 100; + int roll = static_cast(static_cast (std::rand()) / RAND_MAX * 100); if (roll <= x) { lock.getClass().unlock(lock); @@ -76,11 +76,11 @@ namespace MWMechanics float probeQuality = probe.get()->mBase->mData.mQuality; const ESM::Spell* trapSpell = MWBase::Environment::get().getWorld()->getStore().get().find(trap.getCellRef().getTrap()); - float trapSpellPoints = trapSpell->mData.mCost; + int trapSpellPoints = trapSpell->mData.mCost; float fTrapCostMult = MWBase::Environment::get().getWorld()->getStore().get().find("fTrapCostMult")->getFloat(); - float x = 0.2 * mAgility + 0.1 * mLuck + mSecuritySkill; + float x = 0.2f * mAgility + 0.1f * mLuck + mSecuritySkill; x += fTrapCostMult * trapSpellPoints; x *= probeQuality * mFatigueTerm; @@ -90,7 +90,7 @@ namespace MWMechanics else { MWBase::Environment::get().getMechanicsManager()->objectOpened(mActor, trap); - int roll = static_cast (std::rand()) / RAND_MAX * 100; + int roll = static_cast(static_cast (std::rand()) / RAND_MAX * 100); if (roll <= x) { trap.getCellRef().setTrap(""); diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 06a3c1dfd..3ca30977b 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -144,21 +144,21 @@ namespace MWMechanics for (std::vector::const_iterator it = spell->mEffects.mList.begin(); it != spell->mEffects.mList.end(); ++it) { - float x = it->mDuration; + float x = static_cast(it->mDuration); const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get().find( it->mEffectID); if (!(magicEffect->mData.mFlags & ESM::MagicEffect::UncappedDamage)) x = std::max(1.f, x); - x *= 0.1 * magicEffect->mData.mBaseCost; - x *= 0.5 * (it->mMagnMin + it->mMagnMax); - x *= it->mArea * 0.05 * magicEffect->mData.mBaseCost; + x *= 0.1f * magicEffect->mData.mBaseCost; + x *= 0.5f * (it->mMagnMin + it->mMagnMax); + x *= it->mArea * 0.05f * magicEffect->mData.mBaseCost; if (it->mRange == ESM::RT_Target) - x *= 1.5; + x *= 1.5f; static const float fEffectCostMult = MWBase::Environment::get().getWorld()->getStore().get().find( "fEffectCostMult")->getFloat(); x *= fEffectCostMult; - float s = 2 * actor.getClass().getSkill(actor, spellSchoolToSkill(magicEffect->mData.mSchool)); + float s = 2.0f * actor.getClass().getSkill(actor, spellSchoolToSkill(magicEffect->mData.mSchool)); if (s - x < y) { y = s - x; @@ -174,12 +174,12 @@ namespace MWMechanics if (spell->mData.mFlags & ESM::Spell::F_Always) return 100; - int castBonus = -stats.getMagicEffects().get(ESM::MagicEffect::Sound).getMagnitude(); + float castBonus = -stats.getMagicEffects().get(ESM::MagicEffect::Sound).getMagnitude(); int actorWillpower = stats.getAttribute(ESM::Attribute::Willpower).getModified(); int actorLuck = stats.getAttribute(ESM::Attribute::Luck).getModified(); - float castChance = (lowestSkill - spell->mData.mCost + castBonus + 0.2 * actorWillpower + 0.1 * actorLuck) * stats.getFatigueTerm(); + float castChance = (lowestSkill - spell->mData.mCost + castBonus + 0.2f * actorWillpower + 0.1f * actorLuck) * stats.getFatigueTerm(); if (MWBase::Environment::get().getWorld()->getGodModeState() && actor.getRefData().getHandle() == "player") castChance = 100; @@ -267,9 +267,9 @@ namespace MWMechanics float resistance = getEffectResistanceAttribute(effectId, magicEffects); - float willpower = stats.getAttribute(ESM::Attribute::Willpower).getModified(); - float luck = stats.getAttribute(ESM::Attribute::Luck).getModified(); - float x = (willpower + 0.1 * luck) * stats.getFatigueTerm(); + int willpower = stats.getAttribute(ESM::Attribute::Willpower).getModified(); + float luck = static_cast(stats.getAttribute(ESM::Attribute::Luck).getModified()); + float x = (willpower + 0.1f * luck) * stats.getFatigueTerm(); // This makes spells that are easy to cast harder to resist and vice versa float castChance = 100.f; @@ -383,7 +383,7 @@ namespace MWMechanics target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::ResistCommonDisease).getMagnitude() : target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::ResistBlightDisease).getMagnitude(); - int roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 100; // [0, 99] + int roll = static_cast(std::rand()/ (static_cast (RAND_MAX) + 1) * 100); // [0, 99] if (roll <= x) { // Fully resisted, show message @@ -413,8 +413,8 @@ namespace MWMechanics bool absorbed = false; if (spell && caster != target && target.getClass().isActor()) { - int absorb = target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::SpellAbsorption).getMagnitude(); - int roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 100; // [0, 99] + float absorb = target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::SpellAbsorption).getMagnitude(); + int roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 100); // [0, 99] absorbed = (roll < absorb); if (absorbed) { @@ -462,8 +462,8 @@ namespace MWMechanics // Try reflecting if (!reflected && magnitudeMult > 0 && !caster.isEmpty() && caster != target && !(magicEffect->mData.mFlags & ESM::MagicEffect::Unreflectable)) { - int reflect = target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::Reflect).getMagnitude(); - int roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 100; // [0, 99] + float reflect = target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::Reflect).getMagnitude(); + int roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 100); // [0, 99] bool isReflected = (roll < reflect); if (isReflected) { @@ -502,7 +502,7 @@ namespace MWMechanics ActiveSpells::ActiveEffect effect; effect.mEffectId = effectIt->mEffectID; effect.mArg = MWMechanics::EffectKey(*effectIt).mArg; - effect.mDuration = effectIt->mDuration; + effect.mDuration = static_cast(effectIt->mDuration); effect.mMagnitude = magnitude; targetEffects.add(MWMechanics::EffectKey(*effectIt), MWMechanics::EffectParam(effect.mMagnitude)); @@ -613,7 +613,7 @@ namespace MWMechanics { if (caster.getRefData().getHandle() == "player") MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicLockSuccess}"); - target.getCellRef().setLockLevel(magnitude); + target.getCellRef().setLockLevel(static_cast(magnitude)); } } else if (effectId == ESM::MagicEffect::Open) @@ -721,10 +721,10 @@ namespace MWMechanics // Check if there's enough charge left if (enchantment->mData.mType == ESM::Enchantment::WhenUsed || enchantment->mData.mType == ESM::Enchantment::WhenStrikes) { - const int castCost = getEffectiveEnchantmentCastCost(enchantment->mData.mCost, mCaster); + const int castCost = getEffectiveEnchantmentCastCost(static_cast(enchantment->mData.mCost), mCaster); if (item.getCellRef().getEnchantmentCharge() == -1) - item.getCellRef().setEnchantmentCharge(enchantment->mData.mCharge); + item.getCellRef().setEnchantmentCharge(static_cast(enchantment->mData.mCharge)); if (item.getCellRef().getEnchantmentCharge() < castCost) { @@ -823,8 +823,8 @@ namespace MWMechanics bool fail = false; // Check success - int successChance = getSpellSuccessChance(spell, mCaster); - int roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 100; // [0, 99] + float successChance = getSpellSuccessChance(spell, mCaster); + int roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 100); // [0, 99] if (!fail && roll >= successChance) { if (mCaster.getRefData().getHandle() == "player") @@ -899,11 +899,11 @@ namespace MWMechanics const MWMechanics::CreatureStats& creatureStats = mCaster.getClass().getCreatureStats(mCaster); float x = (npcStats.getSkill (ESM::Skill::Alchemy).getModified() + - 0.2 * creatureStats.getAttribute (ESM::Attribute::Intelligence).getModified() - + 0.1 * creatureStats.getAttribute (ESM::Attribute::Luck).getModified()) + 0.2f * creatureStats.getAttribute (ESM::Attribute::Intelligence).getModified() + + 0.1f * creatureStats.getAttribute (ESM::Attribute::Luck).getModified()) * creatureStats.getFatigueTerm(); - int roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 100; // [0, 99] + int roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 100); // [0, 99] if (roll > x) { // "X has no effect on you" @@ -915,24 +915,24 @@ namespace MWMechanics float magnitude = 0; float y = roll / std::min(x, 100.f); - y *= 0.25 * x; + y *= 0.25f * x; if (magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration) - effect.mDuration = int(y); + effect.mDuration = static_cast(y); else effect.mDuration = 1; if (!(magicEffect->mData.mFlags & ESM::MagicEffect::NoMagnitude)) { if (!(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration)) - magnitude = int((0.05 * y) / (0.1 * magicEffect->mData.mBaseCost)); + magnitude = floor((0.05f * y) / (0.1f * magicEffect->mData.mBaseCost)); else - magnitude = int(y / (0.1 * magicEffect->mData.mBaseCost)); + magnitude = floor(y / (0.1f * magicEffect->mData.mBaseCost)); magnitude = std::max(1.f, magnitude); } else magnitude = 1; - effect.mMagnMax = magnitude; - effect.mMagnMin = magnitude; + effect.mMagnMax = static_cast(magnitude); + effect.mMagnMin = static_cast(magnitude); ESM::EffectList effects; effects.mList.push_back(effect); diff --git a/apps/openmw/mwmechanics/stat.cpp b/apps/openmw/mwmechanics/stat.cpp index 554f619a5..3216a46e6 100644 --- a/apps/openmw/mwmechanics/stat.cpp +++ b/apps/openmw/mwmechanics/stat.cpp @@ -15,10 +15,10 @@ void MWMechanics::AttributeValue::readState (const ESM::StatState& state) mDamage = state.mDamage; } -void MWMechanics::AttributeValue::setModifiers(int fortify, int drain, int absorb) +void MWMechanics::AttributeValue::setModifiers(float fortify, float drain, float absorb) { - mFortified = fortify; - mModifier = (fortify - drain) - absorb; + mFortified = static_cast(fortify); + mModifier = mFortified - static_cast(drain + absorb); } void MWMechanics::SkillValue::writeState (ESM::StatState& state) const diff --git a/apps/openmw/mwmechanics/stat.hpp b/apps/openmw/mwmechanics/stat.hpp index 5c41e007e..528bfdbe7 100644 --- a/apps/openmw/mwmechanics/stat.hpp +++ b/apps/openmw/mwmechanics/stat.hpp @@ -247,7 +247,7 @@ namespace MWMechanics int getModifier() const { return mModifier; } void setBase(int base) { mBase = std::max(0, base); } - void setModifiers(int fortify, int drain, int absorb); + void setModifiers(float fortify, float drain, float absorb); void damage(float damage) { mDamage = std::min(mDamage + damage, (float)(mBase + mFortified)); } void restore(float amount) { mDamage -= std::min(mDamage, amount); } diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 965083019..bdaa2d515 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -111,7 +111,7 @@ void Objects::insertModel(const MWWorld::Ptr &ptr, const std::string &mesh, bool sg->setOrigin(ptr.getRefData().getBaseNode()->getPosition()); mStaticGeometrySmall[ptr.getCell()] = sg; - sg->setRenderingDistance(Settings::Manager::getInt("small object distance", "Viewing distance")); + sg->setRenderingDistance(static_cast(Settings::Manager::getInt("small object distance", "Viewing distance"))); } else sg = mStaticGeometrySmall[ptr.getCell()]; diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 020f9561a..9ad490d69 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -630,7 +630,7 @@ void MWWorld::InventoryStore::updateRechargingItems() it->getClass().getEnchantment(*it)); if (enchantment->mData.mType == ESM::Enchantment::WhenUsed || enchantment->mData.mType == ESM::Enchantment::WhenStrikes) - mRechargingItems.push_back(std::make_pair(it, enchantment->mData.mCharge)); + mRechargingItems.push_back(std::make_pair(it, static_cast(enchantment->mData.mCharge))); } } } From 128371c902cf40f98d6199e7dc267c9f3e778130 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 8 Mar 2015 15:50:50 +1100 Subject: [PATCH 0707/3725] Copy base data to modified. --- apps/opencs/model/world/record.hpp | 4 +++- apps/opencs/model/world/refidcollection.cpp | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/world/record.hpp b/apps/opencs/model/world/record.hpp index 861fc47a3..2b556636f 100644 --- a/apps/opencs/model/world/record.hpp +++ b/apps/opencs/model/world/record.hpp @@ -61,7 +61,9 @@ namespace CSMWorld template RecordBase *Record::clone() const { - return new Record (*this); + Record *copy = new Record (*this); + copy->mModified = (*this).get(); + return copy; } template diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 75429d906..779d5a40c 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -471,7 +471,7 @@ void CSMWorld::RefIdCollection::cloneRecord(const std::string& origin, const CSMWorld::UniversalId::Type type) { std::auto_ptr newRecord(mData.getRecord(mData.searchId(origin)).clone()); - newRecord->mState = RecordBase::State_BaseOnly; + newRecord->mState = RecordBase::State_ModifiedOnly; mAdapters.find(type)->second->setId(*newRecord, destination); mData.insertRecord(*newRecord, type, destination); } From f19863b54577406d43f5a30552b26088263bf1f2 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 8 Mar 2015 18:11:54 +1300 Subject: [PATCH 0708/3725] fixing MSVC 2013 warning C4244: & C4305 conversion from 'const float' to 'int', possible loss of data conversion from 'double' to 'int', possible loss of data conversion from 'float' to 'int', possible loss of data --- apps/openmw/mwrender/debugging.cpp | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwrender/debugging.cpp b/apps/openmw/mwrender/debugging.cpp index 972c1b6dd..79eeff2d0 100644 --- a/apps/openmw/mwrender/debugging.cpp +++ b/apps/openmw/mwrender/debugging.cpp @@ -21,6 +21,7 @@ #include "../mwworld/ptr.hpp" #include "../mwworld/cellstore.hpp" #include "../mwworld/esmstore.hpp" +#include "../mwmechanics/pathfinding.hpp" #include "renderconst.hpp" @@ -81,12 +82,12 @@ ManualObject *Debugging::createPathgridLines(const ESM::Pathgrid *pathgrid) { const ESM::Pathgrid::Edge &edge = *it; const ESM::Pathgrid::Point &p1 = pathgrid->mPoints[edge.mV0], &p2 = pathgrid->mPoints[edge.mV1]; - Vector3 direction = (Vector3(p2.mX, p2.mY, p2.mZ) - Vector3(p1.mX, p1.mY, p1.mZ)); + Vector3 direction = (MWMechanics::PathFinder::MakeOgreVector3(p2) - MWMechanics::PathFinder::MakeOgreVector3(p1)); Vector3 lineDisplacement = direction.crossProduct(Vector3::UNIT_Z).normalisedCopy(); lineDisplacement = lineDisplacement * POINT_MESH_BASE + Vector3(0, 0, 10); // move lines up a little, so they will be less covered by meshes/landscape - result->position(Vector3(p1.mX, p1.mY, p1.mZ) + lineDisplacement); - result->position(Vector3(p2.mX, p2.mY, p2.mZ) + lineDisplacement); + result->position(MWMechanics::PathFinder::MakeOgreVector3(p1) + lineDisplacement); + result->position(MWMechanics::PathFinder::MakeOgreVector3(p2) + lineDisplacement); } result->end(); @@ -108,7 +109,7 @@ ManualObject *Debugging::createPathgridPoints(const ESM::Pathgrid *pathgrid) it != pathgrid->mPoints.end(); ++it, startIndex += 6) { - Vector3 pointPos(it->mX, it->mY, it->mZ); + Vector3 pointPos(MWMechanics::PathFinder::MakeOgreVector3(*it)); if (!first) { @@ -117,11 +118,13 @@ ManualObject *Debugging::createPathgridPoints(const ESM::Pathgrid *pathgrid) result->index(startIndex); // start point of current octahedron } + Ogre::Real pointMeshBase = static_cast(POINT_MESH_BASE); + result->position(pointPos + Vector3(0, 0, height)); // 0 - result->position(pointPos + Vector3(-POINT_MESH_BASE, -POINT_MESH_BASE, 0)); // 1 - result->position(pointPos + Vector3(POINT_MESH_BASE, -POINT_MESH_BASE, 0)); // 2 - result->position(pointPos + Vector3(POINT_MESH_BASE, POINT_MESH_BASE, 0)); // 3 - result->position(pointPos + Vector3(-POINT_MESH_BASE, POINT_MESH_BASE, 0)); // 4 + result->position(pointPos + Vector3(-pointMeshBase, -pointMeshBase, 0)); // 1 + result->position(pointPos + Vector3(pointMeshBase, -pointMeshBase, 0)); // 2 + result->position(pointPos + Vector3(pointMeshBase, pointMeshBase, 0)); // 3 + result->position(pointPos + Vector3(-pointMeshBase, pointMeshBase, 0)); // 4 result->position(pointPos + Vector3(0, 0, -height)); // 5 result->index(startIndex + 0); @@ -239,8 +242,8 @@ void Debugging::enableCellPathgrid(MWWorld::CellStore *store) Vector3 cellPathGridPos(0, 0, 0); if (store->getCell()->isExterior()) { - cellPathGridPos.x = store->getCell()->mData.mX * ESM::Land::REAL_SIZE; - cellPathGridPos.y = store->getCell()->mData.mY * ESM::Land::REAL_SIZE; + cellPathGridPos.x = static_cast(store->getCell()->mData.mX * ESM::Land::REAL_SIZE); + cellPathGridPos.y = static_cast(store->getCell()->mData.mY * ESM::Land::REAL_SIZE); } SceneNode *cellPathGrid = mPathGridRoot->createChildSceneNode(cellPathGridPos); cellPathGrid->attachObject(createPathgridLines(pathgrid)); From ba7fc8609cb2fadda7941431ef7585a64772d0bf Mon Sep 17 00:00:00 2001 From: Ivy Foster Date: Sun, 8 Mar 2015 15:23:46 -0500 Subject: [PATCH 0709/3725] Add toggle sneak option; fix bug #2119 To enable toggle sneak mode, set "toggle sneak = true" in the [Input] section of settings.cfg. Outstanding issues: - In toggle sneak mode, holding the Sneak button causes rapid, repeated toggling. - The button in the settings menu doesn't do anything. --- apps/openmw/mwinput/inputmanagerimp.cpp | 19 ++++++++++++++++++- apps/openmw/mwinput/inputmanagerimp.hpp | 3 +++ files/mygui/openmw_settings_window.layout | 18 ++++++++++++++---- files/settings-default.cfg | 2 ++ 4 files changed, 37 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 21576785c..462008b09 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -124,6 +124,8 @@ namespace MWInput , mTimeIdle(0.f) , mOverencumberedMessageDelay(0.f) , mAlwaysRunActive(Settings::Manager::getBool("always run", "Input")) + , mSneakToggles(Settings::Manager::getBool("toggle sneak", "Input")) + , mSneaking(false) , mAttemptJump(false) , mControlsDisabled(false) , mJoystickLastUsed(false) @@ -522,7 +524,16 @@ namespace MWInput } } - mPlayer->setSneak(actionIsActive(A_Sneak)); + if (mSneakToggles) + { + if (actionIsActive(A_Sneak)) + { + toggleSneaking(); + mPlayer->setSneak(mSneaking); + } + } + else + mPlayer->setSneak(actionIsActive(A_Sneak)); if (mAttemptJump && mControlSwitch["playerjumping"]) { @@ -1089,6 +1100,12 @@ namespace MWInput Settings::Manager::setBool("always run", "Input", mAlwaysRunActive); } + void InputManager::toggleSneaking() + { + if (MWBase::Environment::get().getWindowManager()->isGuiMode()) return; + mSneaking = !mSneaking; + } + void InputManager::resetIdleTime() { if (mTimeIdle < 0) diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 39091b7b1..558801023 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -180,6 +180,8 @@ namespace MWInput int mMouseWheel; bool mUserFileExists; bool mAlwaysRunActive; + bool mSneakToggles; + bool mSneaking; bool mAttemptJump; std::map mControlSwitch; @@ -208,6 +210,7 @@ namespace MWInput void toggleJournal(); void activate(); void toggleWalking(); + void toggleSneaking(); void toggleAutoMove(); void rest(); void quickLoad(); diff --git a/files/mygui/openmw_settings_window.layout b/files/mygui/openmw_settings_window.layout index 2efd5841e..73d05600a 100644 --- a/files/mygui/openmw_settings_window.layout +++ b/files/mygui/openmw_settings_window.layout @@ -196,10 +196,20 @@ - + + + + + + + + + + + - + @@ -209,11 +219,11 @@ - + - + diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 19b570e2a..de22e1b56 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -194,6 +194,8 @@ always run = false allow third person zoom = false +toggle sneak = false + [Game] # Always use the most powerful attack when striking with a weapon (chop, slash or thrust) best attack = false From 4f100e687003c7c0e49fc1f78743d885c9c52369 Mon Sep 17 00:00:00 2001 From: Ivy Foster Date: Sun, 8 Mar 2015 16:08:45 -0500 Subject: [PATCH 0710/3725] Fix rapid toggling when holding sneak button. --- apps/openmw/mwinput/inputmanagerimp.cpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 462008b09..05fbbb1fe 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -356,6 +356,12 @@ namespace MWInput case A_CycleWeaponRight: MWBase::Environment::get().getWindowManager()->cycleWeapon(true); break; + case A_Sneak: + if (mSneakToggles) + { + toggleSneaking(); + } + break; } } } @@ -524,16 +530,10 @@ namespace MWInput } } - if (mSneakToggles) + if (!mSneakToggles) { - if (actionIsActive(A_Sneak)) - { - toggleSneaking(); - mPlayer->setSneak(mSneaking); - } - } - else mPlayer->setSneak(actionIsActive(A_Sneak)); + } if (mAttemptJump && mControlSwitch["playerjumping"]) { @@ -1104,6 +1104,7 @@ namespace MWInput { if (MWBase::Environment::get().getWindowManager()->isGuiMode()) return; mSneaking = !mSneaking; + mPlayer->setSneak(mSneaking); } void InputManager::resetIdleTime() From f7089446575de574b5d06a64ac98662ccfa2fcca Mon Sep 17 00:00:00 2001 From: Ivy Foster Date: Sun, 8 Mar 2015 16:15:43 -0500 Subject: [PATCH 0711/3725] Remove toggle sneak menu option Users can change the option in settings.cfg. --- files/mygui/openmw_settings_window.layout | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/files/mygui/openmw_settings_window.layout b/files/mygui/openmw_settings_window.layout index 73d05600a..2efd5841e 100644 --- a/files/mygui/openmw_settings_window.layout +++ b/files/mygui/openmw_settings_window.layout @@ -196,20 +196,10 @@ - - - - - - - - - - - + - + @@ -219,11 +209,11 @@ - + - + From 3d5c1d1190ffcb509ae9be48c9ee2d9252510482 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 7 Mar 2015 16:23:02 +0100 Subject: [PATCH 0712/3725] Adjust fix for maximum attribute damage limit --- apps/openmw/mwmechanics/actors.cpp | 8 ++++---- apps/openmw/mwmechanics/stat.cpp | 8 +------- apps/openmw/mwmechanics/stat.hpp | 27 ++++++++++++++------------- 3 files changed, 19 insertions(+), 24 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 56646a83b..eef30f112 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -515,8 +515,8 @@ namespace MWMechanics for(int i = 0;i < ESM::Attribute::Length;++i) { AttributeValue stat = creatureStats.getAttribute(i); - stat.setModifiers(effects.get(EffectKey(ESM::MagicEffect::FortifyAttribute, i)).getMagnitude(), - effects.get(EffectKey(ESM::MagicEffect::DrainAttribute, i)).getMagnitude(), + stat.setModifier(effects.get(EffectKey(ESM::MagicEffect::FortifyAttribute, i)).getMagnitude() - + effects.get(EffectKey(ESM::MagicEffect::DrainAttribute, i)).getMagnitude() - effects.get(EffectKey(ESM::MagicEffect::AbsorbAttribute, i)).getMagnitude()); stat.damage(effects.get(EffectKey(ESM::MagicEffect::DamageAttribute, i)).getMagnitude() * duration); @@ -782,8 +782,8 @@ namespace MWMechanics for(int i = 0;i < ESM::Skill::Length;++i) { SkillValue& skill = npcStats.getSkill(i); - skill.setModifiers(effects.get(EffectKey(ESM::MagicEffect::FortifySkill, i)).getMagnitude(), - effects.get(EffectKey(ESM::MagicEffect::DrainSkill, i)).getMagnitude(), + skill.setModifier(effects.get(EffectKey(ESM::MagicEffect::FortifySkill, i)).getMagnitude() - + effects.get(EffectKey(ESM::MagicEffect::DrainSkill, i)).getMagnitude() - effects.get(EffectKey(ESM::MagicEffect::AbsorbSkill, i)).getMagnitude()); skill.damage(effects.get(EffectKey(ESM::MagicEffect::DamageSkill, i)).getMagnitude() * duration); diff --git a/apps/openmw/mwmechanics/stat.cpp b/apps/openmw/mwmechanics/stat.cpp index 3216a46e6..1b909d579 100644 --- a/apps/openmw/mwmechanics/stat.cpp +++ b/apps/openmw/mwmechanics/stat.cpp @@ -15,12 +15,6 @@ void MWMechanics::AttributeValue::readState (const ESM::StatState& state) mDamage = state.mDamage; } -void MWMechanics::AttributeValue::setModifiers(float fortify, float drain, float absorb) -{ - mFortified = static_cast(fortify); - mModifier = mFortified - static_cast(drain + absorb); -} - void MWMechanics::SkillValue::writeState (ESM::StatState& state) const { AttributeValue::writeState (state); @@ -31,4 +25,4 @@ void MWMechanics::SkillValue::readState (const ESM::StatState& state) { AttributeValue::readState (state); mProgress = state.mProgress; -} \ No newline at end of file +} diff --git a/apps/openmw/mwmechanics/stat.hpp b/apps/openmw/mwmechanics/stat.hpp index 528bfdbe7..30c7d3130 100644 --- a/apps/openmw/mwmechanics/stat.hpp +++ b/apps/openmw/mwmechanics/stat.hpp @@ -235,28 +235,31 @@ namespace MWMechanics class AttributeValue { int mBase; - int mFortified; - int mModifier; // net effect of Fortified, Drain & Absorb + int mModifier; float mDamage; // needs to be float to allow continuous damage public: - AttributeValue() : mBase(0), mFortified(0), mModifier(0), mDamage(0) {} + AttributeValue() : mBase(0), mModifier(0), mDamage(0) {} int getModified() const { return std::max(0, mBase - (int) mDamage + mModifier); } int getBase() const { return mBase; } int getModifier() const { return mModifier; } void setBase(int base) { mBase = std::max(0, base); } - void setModifiers(float fortify, float drain, float absorb); - void damage(float damage) { mDamage = std::min(mDamage + damage, (float)(mBase + mFortified)); } + void setModifier(int mod) { mModifier = mod; } + + // Maximum attribute damage is limited to the modified value. + // Note: I think MW applies damage directly to mModified, since you can also + // "restore" drained attributes. We need to rewrite the magic effect system to support this. + void damage(float damage) { mDamage += std::min(damage, (float)getModified()); } void restore(float amount) { mDamage -= std::min(mDamage, amount); } + float getDamage() const { return mDamage; } + void writeState (ESM::StatState& state) const; void readState (const ESM::StatState& state); - - friend bool operator== (const AttributeValue& left, const AttributeValue& right); }; class SkillValue : public AttributeValue @@ -270,16 +273,13 @@ namespace MWMechanics void writeState (ESM::StatState& state) const; void readState (const ESM::StatState& state); - - friend bool operator== (const SkillValue& left, const SkillValue& right); }; inline bool operator== (const AttributeValue& left, const AttributeValue& right) { return left.getBase() == right.getBase() - && left.mFortified == right.mFortified && left.getModifier() == right.getModifier() - && left.mDamage == right.mDamage; + && left.getDamage() == right.getDamage(); } inline bool operator!= (const AttributeValue& left, const AttributeValue& right) { @@ -288,8 +288,9 @@ namespace MWMechanics inline bool operator== (const SkillValue& left, const SkillValue& right) { - // delegate to base class for most of the work - return (static_cast(left) == right) + return left.getBase() == right.getBase() + && left.getModifier() == right.getModifier() + && left.getDamage() == right.getDamage() && left.getProgress() == right.getProgress(); } inline bool operator!= (const SkillValue& left, const SkillValue& right) From 36e1b6cc4820491ecb246172830b96c578ca5f43 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 7 Mar 2015 16:30:41 +0100 Subject: [PATCH 0713/3725] Support fatigue below zero for the Drain effect (Fixes #2430) --- apps/openmw/mwmechanics/actors.cpp | 4 +++- apps/openmw/mwmechanics/stat.hpp | 8 ++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index eef30f112..ca4105bc6 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -547,7 +547,9 @@ namespace MWMechanics { DynamicStat stat = creatureStats.getDynamic(i); stat.setModifier(effects.get(ESM::MagicEffect::FortifyHealth+i).getMagnitude() - - effects.get(ESM::MagicEffect::DrainHealth+i).getMagnitude()); + effects.get(ESM::MagicEffect::DrainHealth+i).getMagnitude(), + // Fatigue can be decreased below zero meaning the actor will be knocked out + i == 2); float currentDiff = creatureStats.getMagicEffects().get(ESM::MagicEffect::RestoreHealth+i).getMagnitude() diff --git a/apps/openmw/mwmechanics/stat.hpp b/apps/openmw/mwmechanics/stat.hpp index 30c7d3130..ffbc19e15 100644 --- a/apps/openmw/mwmechanics/stat.hpp +++ b/apps/openmw/mwmechanics/stat.hpp @@ -170,10 +170,10 @@ namespace MWMechanics } /// Change modified relatively. - void modify (const T& diff) + void modify (const T& diff, bool allowCurrentDecreaseBelowZero=false) { mStatic.modify (diff); - setCurrent (getCurrent()+diff); + setCurrent (getCurrent()+diff, allowCurrentDecreaseBelowZero); } void setCurrent (const T& value, bool allowDecreaseBelowZero = false) @@ -198,11 +198,11 @@ namespace MWMechanics } } - void setModifier (const T& modifier) + void setModifier (const T& modifier, bool allowCurrentDecreaseBelowZero=false) { T diff = modifier - mStatic.getModifier(); mStatic.setModifier (modifier); - setCurrent (getCurrent()+diff); + setCurrent (getCurrent()+diff, allowCurrentDecreaseBelowZero); } void writeState (ESM::StatState& state) const From 457c13509790177c7d140602dcda7b07f5f80ab2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 7 Mar 2015 19:03:35 +0100 Subject: [PATCH 0714/3725] Remove old workaround --- apps/openmw/engine.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 76b573941..92731ee1a 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -197,9 +197,6 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) Uint32 flags = SDL_INIT_VIDEO|SDL_INIT_NOPARACHUTE|SDL_INIT_GAMECONTROLLER|SDL_INIT_JOYSTICK; if(SDL_WasInit(flags) == 0) { - //kindly ask SDL not to trash our OGL context - //might this be related to http://bugzilla.libsdl.org/show_bug.cgi?id=748 ? - SDL_SetHint(SDL_HINT_RENDER_DRIVER, "software"); SDL_SetMainReady(); if(SDL_Init(flags) != 0) { From e30f240ba273df552d3fbffbb32aef4c70239ccb Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 8 Mar 2015 20:44:41 +0100 Subject: [PATCH 0715/3725] Add travel service support for creatures (Fixes #2432) --- apps/esmtool/record.cpp | 40 ++++++++++++------- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 3 +- apps/openmw/mwgui/travelwindow.cpp | 16 +++++--- components/CMakeLists.txt | 2 +- components/esm/loadcrea.cpp | 12 ++++++ components/esm/loadcrea.hpp | 4 ++ components/esm/loadnpc.cpp | 24 +++++------ components/esm/loadnpc.hpp | 12 +++--- components/esm/transport.cpp | 33 +++++++++++++++ components/esm/transport.hpp | 36 +++++++++++++++++ 10 files changed, 140 insertions(+), 42 deletions(-) create mode 100644 components/esm/transport.cpp create mode 100644 components/esm/transport.hpp diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index be9b03e80..2ee6c54bb 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -6,6 +6,9 @@ #include +namespace +{ + void printAIPackage(ESM::AIPackage p) { std::cout << " AI Type: " << aiTypeLabel(p.mType) @@ -149,6 +152,26 @@ void printEffectList(ESM::EffectList effects) } } +void printTransport(const std::vector& transport) +{ + std::vector::const_iterator dit; + for (dit = transport.begin(); dit != transport.end(); ++dit) + { + std::cout << " Destination Position: " + << boost::format("%12.3f") % dit->mPos.pos[0] << "," + << boost::format("%12.3f") % dit->mPos.pos[1] << "," + << boost::format("%12.3f") % dit->mPos.pos[2] << ")" << std::endl; + std::cout << " Destination Rotation: " + << boost::format("%9.6f") % dit->mPos.rot[0] << "," + << boost::format("%9.6f") % dit->mPos.rot[1] << "," + << boost::format("%9.6f") % dit->mPos.rot[2] << ")" << std::endl; + if (dit->mCellName != "") + std::cout << " Destination Cell: " << dit->mCellName << std::endl; + } +} + +} + namespace EsmTool { RecordBase * @@ -631,6 +654,8 @@ void Record::print() for (sit = mData.mSpells.mList.begin(); sit != mData.mSpells.mList.end(); ++sit) std::cout << " Spell: " << *sit << std::endl; + printTransport(mData.getTransport()); + std::cout << " Artifical Intelligence: " << mData.mHasAI << std::endl; std::cout << " AI Hello:" << (int)mData.mAiData.mHello << std::endl; std::cout << " AI Fight:" << (int)mData.mAiData.mFight << std::endl; @@ -1042,20 +1067,7 @@ void Record::print() for (sit = mData.mSpells.mList.begin(); sit != mData.mSpells.mList.end(); ++sit) std::cout << " Spell: " << *sit << std::endl; - std::vector::iterator dit; - for (dit = mData.mTransport.begin(); dit != mData.mTransport.end(); ++dit) - { - std::cout << " Destination Position: " - << boost::format("%12.3f") % dit->mPos.pos[0] << "," - << boost::format("%12.3f") % dit->mPos.pos[1] << "," - << boost::format("%12.3f") % dit->mPos.pos[2] << ")" << std::endl; - std::cout << " Destination Rotation: " - << boost::format("%9.6f") % dit->mPos.rot[0] << "," - << boost::format("%9.6f") % dit->mPos.rot[1] << "," - << boost::format("%9.6f") % dit->mPos.rot[2] << ")" << std::endl; - if (dit->mCellName != "") - std::cout << " Destination Cell: " << dit->mCellName << std::endl; - } + printTransport(mData.getTransport()); std::cout << " Artifical Intelligence: " << mData.mHasAI << std::endl; std::cout << " AI Hello:" << (int)mData.mAiData.mHello << std::endl; diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index e8dcf535c..00e59e2a5 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -383,7 +383,8 @@ namespace MWDialogue || services & ESM::NPC::Misc) windowServices |= MWGui::DialogueWindow::Service_Trade; - if(mActor.getTypeName() == typeid(ESM::NPC).name() && !mActor.get()->mBase->mTransport.empty()) + if((mActor.getTypeName() == typeid(ESM::NPC).name() && !mActor.get()->mBase->getTransport().empty()) + || (mActor.getTypeName() == typeid(ESM::Creature).name() && !mActor.get()->mBase->getTransport().empty())) windowServices |= MWGui::DialogueWindow::Service_Travel; if (services & ESM::NPC::Spells) diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index 6a45e6026..4da1ab33a 100644 --- a/apps/openmw/mwgui/travelwindow.cpp +++ b/apps/openmw/mwgui/travelwindow.cpp @@ -111,20 +111,26 @@ namespace MWGui mPtr = actor; clearDestinations(); - for(unsigned int i = 0;i()->mBase->mTransport.size();i++) + std::vector transport; + if (mPtr.getClass().isNpc()) + transport = mPtr.get()->mBase->getTransport(); + else if (mPtr.getTypeName() == typeid(ESM::Creature).name()) + transport = mPtr.get()->mBase->getTransport(); + + for(unsigned int i = 0;i()->mBase->mTransport[i].mCellName; + std::string cellname = transport[i].mCellName; bool interior = true; int x,y; - MWBase::Environment::get().getWorld()->positionToIndex(mPtr.get()->mBase->mTransport[i].mPos.pos[0], - mPtr.get()->mBase->mTransport[i].mPos.pos[1],x,y); + MWBase::Environment::get().getWorld()->positionToIndex(transport[i].mPos.pos[0], + transport[i].mPos.pos[1],x,y); if (cellname == "") { MWWorld::CellStore* cell = MWBase::Environment::get().getWorld()->getExterior(x,y); cellname = MWBase::Environment::get().getWorld()->getCellName(cell); interior = false; } - addDestination(cellname,mPtr.get()->mBase->mTransport[i].mPos,interior); + addDestination(cellname,transport[i].mPos,interior); } updateLabels(); diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index a49e54dd3..971897619 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -62,7 +62,7 @@ add_component_dir (esm loadweap records aipackage effectlist spelllist variant variantimp loadtes3 cellref filter savedgame journalentry queststate locals globalscript player objectstate cellid cellstate globalmap inventorystate containerstate npcstate creaturestate dialoguestate statstate npcstats creaturestats weatherstate quickkeys fogstate spellstate activespells creaturelevliststate doorstate projectilestate debugprofile - aisequence magiceffects util custommarkerstate stolenitems + aisequence magiceffects util custommarkerstate stolenitems transport ) add_component_dir (esmterrain diff --git a/components/esm/loadcrea.cpp b/components/esm/loadcrea.cpp index 86eede34e..50c47349c 100644 --- a/components/esm/loadcrea.cpp +++ b/components/esm/loadcrea.cpp @@ -15,6 +15,7 @@ namespace ESM { mAiPackage.mList.clear(); mInventory.mList.clear(); mSpells.mList.clear(); + mTransport.mList.clear(); mScale = 1.f; mHasAI = false; @@ -59,6 +60,10 @@ namespace ESM { esm.getHExact(&mAiData, sizeof(mAiData)); mHasAI = true; break; + case ESM::FourCC<'D','O','D','T'>::value: + case ESM::FourCC<'D','N','A','M'>::value: + mTransport.add(esm); + break; case AI_Wander: case AI_Activate: case AI_Escort: @@ -94,6 +99,7 @@ namespace ESM { if (mHasAI) { esm.writeHNT("AIDT", mAiData, sizeof(mAiData)); } + mTransport.save(esm); mAiPackage.save(esm); } @@ -120,5 +126,11 @@ namespace ESM { mAiData.blank(); mAiData.mServices = 0; mAiPackage.mList.clear(); + mTransport.mList.clear(); + } + + const std::vector& Creature::getTransport() const + { + return mTransport.mList; } } diff --git a/components/esm/loadcrea.hpp b/components/esm/loadcrea.hpp index e459dded7..1b02aa0ab 100644 --- a/components/esm/loadcrea.hpp +++ b/components/esm/loadcrea.hpp @@ -6,6 +6,7 @@ #include "loadcont.hpp" #include "spelllist.hpp" #include "aipackage.hpp" +#include "transport.hpp" namespace ESM { @@ -92,6 +93,9 @@ struct Creature bool mHasAI; AIData mAiData; AIPackageList mAiPackage; + Transport mTransport; + + const std::vector& getTransport() const; void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadnpc.cpp b/components/esm/loadnpc.cpp index 98cedbe42..751c7f252 100644 --- a/components/esm/loadnpc.cpp +++ b/components/esm/loadnpc.cpp @@ -14,7 +14,7 @@ namespace ESM mSpells.mList.clear(); mInventory.mList.clear(); - mTransport.clear(); + mTransport.mList.clear(); mAiPackage.mList.clear(); bool hasNpdt = false; @@ -81,14 +81,8 @@ namespace ESM mHasAI= true; break; case ESM::FourCC<'D','O','D','T'>::value: - { - Dest dodt; - esm.getHExact(&dodt.mPos, 24); - mTransport.push_back(dodt); - break; - } case ESM::FourCC<'D','N','A','M'>::value: - mTransport.back().mCellName = esm.getHString(); + mTransport.add(esm); break; case AI_Wander: case AI_Activate: @@ -131,11 +125,8 @@ namespace ESM esm.writeHNT("AIDT", mAiData, sizeof(mAiData)); } - typedef std::vector::const_iterator DestIter; - for (DestIter it = mTransport.begin(); it != mTransport.end(); ++it) { - esm.writeHNT("DODT", it->mPos, sizeof(it->mPos)); - esm.writeHNOCString("DNAM", it->mCellName); - } + mTransport.save(esm); + mAiPackage.save(esm); } @@ -177,7 +168,7 @@ namespace ESM mSpells.mList.clear(); mAiData.blank(); mHasAI = false; - mTransport.clear(); + mTransport.mList.clear(); mAiPackage.mList.clear(); mName.clear(); mModel.clear(); @@ -198,4 +189,9 @@ namespace ESM else // NPC_DEFAULT return mNpdt52.mRank; } + + const std::vector& NPC::getTransport() const + { + return mTransport.mList; + } } diff --git a/components/esm/loadnpc.hpp b/components/esm/loadnpc.hpp index 9dc3be513..b535b91b0 100644 --- a/components/esm/loadnpc.hpp +++ b/components/esm/loadnpc.hpp @@ -9,6 +9,7 @@ #include "aipackage.hpp" #include "spelllist.hpp" #include "loadskil.hpp" +#include "transport.hpp" namespace ESM { @@ -98,12 +99,6 @@ struct NPC char mUnknown1, mUnknown2, mUnknown3; int mGold; }; // 12 bytes - - struct Dest - { - Position mPos; - std::string mCellName; - }; #pragma pack(pop) unsigned char mNpdtType; @@ -122,7 +117,10 @@ struct NPC AIData mAiData; bool mHasAI; - std::vector mTransport; + Transport mTransport; + + const std::vector& getTransport() const; + AIPackageList mAiPackage; std::string mId, mName, mModel, mRace, mClass, mFaction, mScript; diff --git a/components/esm/transport.cpp b/components/esm/transport.cpp new file mode 100644 index 000000000..da0a5f767 --- /dev/null +++ b/components/esm/transport.cpp @@ -0,0 +1,33 @@ +#include "transport.hpp" + +#include +#include + +namespace ESM +{ + + void Transport::add(ESMReader &esm) + { + if (esm.retSubName().val == ESM::FourCC<'D','O','D','T'>::value) + { + Dest dodt; + esm.getHExact(&dodt.mPos, 24); + mList.push_back(dodt); + } + else if (esm.retSubName().val == ESM::FourCC<'D','N','A','M'>::value) + { + mList.back().mCellName = esm.getHString(); + } + } + + void Transport::save(ESMWriter &esm) const + { + typedef std::vector::const_iterator DestIter; + for (DestIter it = mList.begin(); it != mList.end(); ++it) + { + esm.writeHNT("DODT", it->mPos, sizeof(it->mPos)); + esm.writeHNOCString("DNAM", it->mCellName); + } + } + +} diff --git a/components/esm/transport.hpp b/components/esm/transport.hpp new file mode 100644 index 000000000..10d4013f7 --- /dev/null +++ b/components/esm/transport.hpp @@ -0,0 +1,36 @@ +#ifndef OPENMW_COMPONENTS_ESM_TRANSPORT_H +#define OPENMW_COMPONENTS_ESM_TRANSPORT_H + +#include +#include + +#include "defs.hpp" + +namespace ESM +{ + + class ESMReader; + class ESMWriter; + + /// List of travel service destination. Shared by CREA and NPC_ records. + struct Transport + { + + struct Dest + { + Position mPos; + std::string mCellName; + }; + + std::vector mList; + + /// Load one destination, assumes the subrecord name was already read + void add(ESMReader &esm); + + void save(ESMWriter &esm) const; + + }; + +} + +#endif From ef34d8b3fb5e00caec7aaa0e6ea2dfe6b499d713 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 8 Mar 2015 22:17:02 +0100 Subject: [PATCH 0716/3725] Markdown syntax fix --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 63a313896..f3f562925 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ Getting Started * [Testing the game](https://wiki.openmw.org/index.php?title=Testing) * [How to contribute](https://wiki.openmw.org/index.php?title=Contribution_Wanted) * [Report a bug](http://bugs.openmw.org/projects/openmw) - read the [guidelines](https://wiki.openmw.org/index.php?title=Bug_Reporting_Guidelines) before submitting your first bug! -* [Known issues] (http://bugs.openmw.org/projects/openmw/issues?utf8=%E2%9C%93&set_filter=1&f%5B%5D=status_id&op%5Bstatus_id%5D=%3D&v%5Bstatus_id%5D%5B%5D=7&f%5B%5D=tracker_id&op%5Btracker_id%5D=%3D&v%5Btracker_id%5D%5B%5D=1&f%5B%5D=&c%5B%5D=project&c%5B%5D=tracker&c%5B%5D=status&c%5B%5D=priority&c%5B%5D=subject&c%5B%5D=assigned_to&c%5B%5D=updated_on&group_by=tracker) +* [Known issues](http://bugs.openmw.org/projects/openmw/issues?utf8=%E2%9C%93&set_filter=1&f%5B%5D=status_id&op%5Bstatus_id%5D=%3D&v%5Bstatus_id%5D%5B%5D=7&f%5B%5D=tracker_id&op%5Btracker_id%5D=%3D&v%5Btracker_id%5D%5B%5D=1&f%5B%5D=&c%5B%5D=project&c%5B%5D=tracker&c%5B%5D=status&c%5B%5D=priority&c%5B%5D=subject&c%5B%5D=assigned_to&c%5B%5D=updated_on&group_by=tracker) The data path ------------- From 6087a18c94e418c43b681accfb72efdef7cb2242 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 9 Mar 2015 14:58:07 +1100 Subject: [PATCH 0717/3725] Implement clone() using a new Record constructor. --- apps/opencs/model/world/record.hpp | 20 +++++++++++++++++--- apps/opencs/model/world/refidcollection.cpp | 1 - 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/apps/opencs/model/world/record.hpp b/apps/opencs/model/world/record.hpp index 2b556636f..1f97ece93 100644 --- a/apps/opencs/model/world/record.hpp +++ b/apps/opencs/model/world/record.hpp @@ -38,6 +38,10 @@ namespace CSMWorld ESXRecordT mBase; ESXRecordT mModified; + Record() {} + Record(State state, + const ESXRecordT *base = 0, const ESXRecordT *modified = 0); + virtual RecordBase *clone() const; virtual void assign (const RecordBase& record); @@ -58,12 +62,22 @@ namespace CSMWorld ///< Merge modified into base. }; + template + Record::Record(State state, const ESXRecordT *base = 0, const ESXRecordT *modified = 0) + { + if(base) + mBase = *base; + + if(modified) + mModified = *modified; + + this->mState = state; + } + template RecordBase *Record::clone() const { - Record *copy = new Record (*this); - copy->mModified = (*this).get(); - return copy; + return new Record (State_ModifiedOnly, 0, &(this->get())); } template diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 779d5a40c..011b5cc0e 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -471,7 +471,6 @@ void CSMWorld::RefIdCollection::cloneRecord(const std::string& origin, const CSMWorld::UniversalId::Type type) { std::auto_ptr newRecord(mData.getRecord(mData.searchId(origin)).clone()); - newRecord->mState = RecordBase::State_ModifiedOnly; mAdapters.find(type)->second->setId(*newRecord, destination); mData.insertRecord(*newRecord, type, destination); } From f90cdec53b122b220a20fadda1e82122b93eb2fb Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 9 Mar 2015 16:24:35 +1100 Subject: [PATCH 0718/3725] Remove default parameters from the implementation. --- apps/opencs/model/world/record.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/world/record.hpp b/apps/opencs/model/world/record.hpp index 1f97ece93..5f935e30d 100644 --- a/apps/opencs/model/world/record.hpp +++ b/apps/opencs/model/world/record.hpp @@ -63,7 +63,7 @@ namespace CSMWorld }; template - Record::Record(State state, const ESXRecordT *base = 0, const ESXRecordT *modified = 0) + Record::Record(State state, const ESXRecordT *base, const ESXRecordT *modified) { if(base) mBase = *base; From 8b3adec3ec5e8009c3266b72a660fe4c2f3712a5 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 9 Mar 2015 21:25:41 +1100 Subject: [PATCH 0719/3725] Added a missing copy constructor. --- apps/opencs/model/world/record.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/world/record.hpp b/apps/opencs/model/world/record.hpp index 5f935e30d..814e116dd 100644 --- a/apps/opencs/model/world/record.hpp +++ b/apps/opencs/model/world/record.hpp @@ -38,7 +38,8 @@ namespace CSMWorld ESXRecordT mBase; ESXRecordT mModified; - Record() {} + Record() = default; + Record(const Record&) = default; Record(State state, const ESXRecordT *base = 0, const ESXRecordT *modified = 0); From bef0bd13f39d74425917633cc61a563f0e8f9929 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 9 Mar 2015 16:46:09 +0100 Subject: [PATCH 0720/3725] updated credits file --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index 90c543ada..0cd961c61 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -39,6 +39,7 @@ Programmers Eli2 Emanuel Guével (potatoesmaster) eroen + escondida Evgeniy Mineev (sandstranger) Fil Krynicki (filkry) Gašper Sedej From 88f746574def3a815c63a9e80c03235d60ed323f Mon Sep 17 00:00:00 2001 From: Scott Howard Date: Mon, 9 Mar 2015 14:37:43 -0400 Subject: [PATCH 0721/3725] fix compiler detection and adding build flags in CMakeLists.txt --- CMakeLists.txt | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 91f12d6da..30710f532 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -349,22 +349,22 @@ if (NOT WIN32 AND NOT APPLE) "${OpenMW_BINARY_DIR}/openmw-cs.desktop") endif() -# Compiler settings -if (CMAKE_COMPILER_IS_GNUCC) - set_property(GLOBAL APPEND_STRING PROPERTY COMPILE_FLAGS "-Wall -Wextra -Wno-unused-parameter -Wno-reorder -std=c++98 -pedantic -Wno-long-long") +# CXX Compiler settings +if (CMAKE_CXX_COMPILER_ID STREQUAL GNU OR CMAKE_CXX_COMPILER_ID STREQUAL Clang) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wno-unused-parameter -Wno-reorder -std=c++98 -pedantic -Wno-long-long") execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION) - if ("${GCC_VERSION}" VERSION_GREATER 4.6 OR "${GCC_VERSION}" VERSION_EQUAL 4.6) - set_property(GLOBAL APPEND_STRING PROPERTY COMPILE_FLAGS "-Wno-unused-but-set-parameter") - endif("${GCC_VERSION}" VERSION_GREATER 4.6 OR "${GCC_VERSION}" VERSION_EQUAL 4.6) + if (CMAKE_CXX_COMPILER_ID STREQUAL GNU AND "${GCC_VERSION}" VERSION_GREATER 4.6 OR "${GCC_VERSION}" VERSION_EQUAL 4.6) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-but-set-parameter") + endif(CMAKE_CXX_COMPILER_ID STREQUAL GNU AND "${GCC_VERSION}" VERSION_GREATER 4.6 OR "${GCC_VERSION}" VERSION_EQUAL 4.6) elseif (MSVC) # Enable link-time code generation globally for all linking set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /GL") set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /LTCG") set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /LTCG") set(CMAKE_STATIC_LINKER_FLAGS_RELEASE "${CMAKE_STATIC_LINKER_FLAGS_RELEASE} /LTCG") -endif (CMAKE_COMPILER_IS_GNUCC) +endif (CMAKE_CXX_COMPILER_ID STREQUAL GNU OR CMAKE_CXX_COMPILER_ID STREQUAL Clang) IF(NOT WIN32 AND NOT APPLE) # Linux building @@ -673,7 +673,7 @@ if (WIN32) set(WARNINGS "${WARNINGS} /wd${d}") endforeach(d) - set_property(GLOBAL APPEND_STRING PROPERTY COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WARNINGS} ${MT_BUILD}") # boost::wave has a few issues with signed / unsigned conversions, so we suppress those here set(SHINY_WARNINGS "${WARNINGS} /wd4245") From 8ac7b77d36477eacae7a2d81009d122390cbb142 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Tue, 10 Mar 2015 06:51:54 +1100 Subject: [PATCH 0722/3725] For RefId's, modify a copy of the base record rather than modifying the record directly. --- apps/opencs/model/world/refidadapterimp.hpp | 70 ++++++++++++++++----- 1 file changed, 53 insertions(+), 17 deletions(-) diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index 034905781..202b7781c 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -156,10 +156,16 @@ namespace CSMWorld Record& record = static_cast&> ( data.getRecord (RefIdData::LocalIndex (index, BaseRefIdAdapter::getType()))); + RecordT record2 = record.get(); if (column==mModel.mModel) - record.get().mModel = value.toString().toUtf8().constData(); + record2.mModel = value.toString().toUtf8().constData(); else + { BaseRefIdAdapter::setData (column, data, index, value); + return; + } + + record.setModified(record2); } struct NameColumns : public ModelColumns @@ -216,12 +222,18 @@ namespace CSMWorld Record& record = static_cast&> ( data.getRecord (RefIdData::LocalIndex (index, BaseRefIdAdapter::getType()))); + RecordT record2 = record.get(); if (column==mName.mName) - record.get().mName = value.toString().toUtf8().constData(); + record2.mName = value.toString().toUtf8().constData(); else if (column==mName.mScript) - record.get().mScript = value.toString().toUtf8().constData(); + record2.mScript = value.toString().toUtf8().constData(); else + { ModelRefIdAdapter::setData (column, data, index, value); + return; + } + + record.setModified(record2); } struct InventoryColumns : public NameColumns @@ -283,14 +295,20 @@ namespace CSMWorld Record& record = static_cast&> ( data.getRecord (RefIdData::LocalIndex (index, BaseRefIdAdapter::getType()))); + RecordT record2 = record.get(); if (column==mInventory.mIcon) - record.get().mIcon = value.toString().toUtf8().constData(); + record2.mIcon = value.toString().toUtf8().constData(); else if (column==mInventory.mWeight) - record.get().mData.mWeight = value.toFloat(); + record2.mData.mWeight = value.toFloat(); else if (column==mInventory.mValue) - record.get().mData.mValue = value.toInt(); + record2.mData.mValue = value.toInt(); else + { NameRefIdAdapter::setData (column, data, index, value); + return; + } + + record.setModified(record2); } class PotionRefIdAdapter : public InventoryRefIdAdapter @@ -364,12 +382,18 @@ namespace CSMWorld Record& record = static_cast&> ( data.getRecord (RefIdData::LocalIndex (index, BaseRefIdAdapter::getType()))); + RecordT record2 = record.get(); if (column==mEnchantable.mEnchantment) - record.get().mEnchant = value.toString().toUtf8().constData(); + record2.mEnchant = value.toString().toUtf8().constData(); else if (column==mEnchantable.mEnchantmentPoints) - record.get().mData.mEnchant = value.toInt(); + record2.mData.mEnchant = value.toInt(); else + { InventoryRefIdAdapter::setData (column, data, index, value); + return; + } + + record.setModified(record2); } struct ToolColumns : public InventoryColumns @@ -426,12 +450,18 @@ namespace CSMWorld Record& record = static_cast&> ( data.getRecord (RefIdData::LocalIndex (index, BaseRefIdAdapter::getType()))); + RecordT record2 = record.get(); if (column==mTools.mQuality) - record.get().mData.mQuality = value.toFloat(); + record2.mData.mQuality = value.toFloat(); else if (column==mTools.mUses) - record.get().mData.mUses = value.toInt(); + record2.mData.mUses = value.toInt(); else + { InventoryRefIdAdapter::setData (column, data, index, value); + return; + } + + record.setModified(record2); } struct ActorColumns : public NameColumns @@ -508,16 +538,17 @@ namespace CSMWorld Record& record = static_cast&> ( data.getRecord (RefIdData::LocalIndex (index, BaseRefIdAdapter::getType()))); + RecordT record2 = record.get(); if (column==mActors.mHasAi) - record.get().mHasAI = value.toInt(); + record2.mHasAI = value.toInt(); else if (column==mActors.mHello) - record.get().mAiData.mHello = value.toInt(); + record2.mAiData.mHello = value.toInt(); else if (column==mActors.mFlee) - record.get().mAiData.mFlee = value.toInt(); + record2.mAiData.mFlee = value.toInt(); else if (column==mActors.mFight) - record.get().mAiData.mFight = value.toInt(); + record2.mAiData.mFight = value.toInt(); else if (column==mActors.mAlarm) - record.get().mAiData.mAlarm = value.toInt(); + record2.mAiData.mAlarm = value.toInt(); else { typename std::map::const_iterator iter = @@ -525,13 +556,18 @@ namespace CSMWorld if (iter!=mActors.mServices.end()) { if (value.toInt()!=0) - record.get().mAiData.mServices |= iter->second; + record2.mAiData.mServices |= iter->second; else - record.get().mAiData.mServices &= ~iter->second; + record2.mAiData.mServices &= ~iter->second; } else + { NameRefIdAdapter::setData (column, data, index, value); + return; + } } + + record.setModified(record2); } class ApparatusRefIdAdapter : public InventoryRefIdAdapter From d7baf923536a01f1f77713c4869480cfb8403ac6 Mon Sep 17 00:00:00 2001 From: Scott Howard Date: Mon, 9 Mar 2015 16:49:40 -0400 Subject: [PATCH 0723/3725] tell include_directories which libraries are system libs --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 30710f532..b5377ee00 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -229,7 +229,8 @@ endif () endif(WIN32) endif(OGRE_STATIC) -include_directories("." +include_directories("." ${LIBS_DIR} + SYSTEM ${OGRE_INCLUDE_DIR} ${OGRE_INCLUDE_DIR}/Ogre ${OGRE_INCLUDE_DIR}/OGRE ${OGRE_INCLUDE_DIRS} ${OGRE_PLUGIN_INCLUDE_DIRS} ${OGRE_INCLUDE_DIR}/Overlay ${OGRE_Overlay_INCLUDE_DIR} ${SDL2_INCLUDE_DIR} @@ -239,7 +240,6 @@ include_directories("." ${MYGUI_PLATFORM_INCLUDE_DIRS} ${OPENAL_INCLUDE_DIR} ${BULLET_INCLUDE_DIRS} - ${LIBS_DIR} ) link_directories(${SDL2_LIBRARY_DIRS} ${Boost_LIBRARY_DIRS} ${OGRE_LIB_DIR} ${MYGUI_LIB_DIR}) From 43ec933b7ba44186de8b2fd0ffa4f4d89a7cfcec Mon Sep 17 00:00:00 2001 From: cc9cii Date: Tue, 10 Mar 2015 09:45:35 +1100 Subject: [PATCH 0724/3725] Revert to the original clone() method. Create a new copy method for modified records. --- apps/opencs/model/world/record.hpp | 25 +++++++++------------ apps/opencs/model/world/refidcollection.cpp | 2 +- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/apps/opencs/model/world/record.hpp b/apps/opencs/model/world/record.hpp index 814e116dd..a0ddd8bc8 100644 --- a/apps/opencs/model/world/record.hpp +++ b/apps/opencs/model/world/record.hpp @@ -22,6 +22,8 @@ namespace CSMWorld virtual RecordBase *clone() const = 0; + virtual RecordBase *modifiedCopy() const = 0; + virtual void assign (const RecordBase& record) = 0; ///< Will throw an exception if the types don't match. @@ -38,13 +40,10 @@ namespace CSMWorld ESXRecordT mBase; ESXRecordT mModified; - Record() = default; - Record(const Record&) = default; - Record(State state, - const ESXRecordT *base = 0, const ESXRecordT *modified = 0); - virtual RecordBase *clone() const; + virtual RecordBase *modifiedCopy() const; + virtual void assign (const RecordBase& record); const ESXRecordT& get() const; @@ -64,21 +63,19 @@ namespace CSMWorld }; template - Record::Record(State state, const ESXRecordT *base, const ESXRecordT *modified) + RecordBase *Record::modifiedCopy() const { - if(base) - mBase = *base; - - if(modified) - mModified = *modified; - - this->mState = state; + Record *record = new Record (*this); + record->mModified = record->mBase; + record->mBase = ESXRecordT(); + record->mState = RecordBase::State_ModifiedOnly; + return record; } template RecordBase *Record::clone() const { - return new Record (State_ModifiedOnly, 0, &(this->get())); + return new Record (*this); } template diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 011b5cc0e..14a8890ad 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -470,7 +470,7 @@ void CSMWorld::RefIdCollection::cloneRecord(const std::string& origin, const std::string& destination, const CSMWorld::UniversalId::Type type) { - std::auto_ptr newRecord(mData.getRecord(mData.searchId(origin)).clone()); + std::auto_ptr newRecord(mData.getRecord(mData.searchId(origin)).modifiedCopy()); mAdapters.find(type)->second->setId(*newRecord, destination); mData.insertRecord(*newRecord, type, destination); } From 28259f914c06100ea58ed31680d7b5deb80ead5f Mon Sep 17 00:00:00 2001 From: cc9cii Date: Wed, 11 Mar 2015 10:49:21 +1100 Subject: [PATCH 0725/3725] Remove potential memory leak. --- apps/opencs/model/world/record.hpp | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/apps/opencs/model/world/record.hpp b/apps/opencs/model/world/record.hpp index a0ddd8bc8..1cf14a8f9 100644 --- a/apps/opencs/model/world/record.hpp +++ b/apps/opencs/model/world/record.hpp @@ -40,6 +40,13 @@ namespace CSMWorld ESXRecordT mBase; ESXRecordT mModified; + Record() = default; + Record(const Record&) = default; + Record& operator= (const Record&) = default; + + Record(State state, + const ESXRecordT *base = 0, const ESXRecordT *modified = 0); + virtual RecordBase *clone() const; virtual RecordBase *modifiedCopy() const; @@ -62,14 +69,22 @@ namespace CSMWorld ///< Merge modified into base. }; + template + Record::Record(State state, const ESXRecordT *base, const ESXRecordT *modified) + { + if(base) + mBase = *base; + + if(modified) + mModified = *modified; + + this->mState = state; + } + template RecordBase *Record::modifiedCopy() const { - Record *record = new Record (*this); - record->mModified = record->mBase; - record->mBase = ESXRecordT(); - record->mState = RecordBase::State_ModifiedOnly; - return record; + return new Record (State_ModifiedOnly, 0, &(this->get())); } template From e2ef8c402233d84f670c82d6cc6e848075c07a03 Mon Sep 17 00:00:00 2001 From: Scott Howard Date: Wed, 11 Mar 2015 10:54:45 -0400 Subject: [PATCH 0726/3725] fix -Wnewline-eof warnings --- apps/mwiniimporter/importer.cpp | 2 +- apps/opencs/model/doc/blacklist.cpp | 2 +- apps/opencs/model/doc/documentmanager.cpp | 2 +- apps/opencs/model/doc/documentmanager.hpp | 2 +- apps/opencs/model/doc/messages.cpp | 2 +- apps/opencs/model/doc/operation.hpp | 2 +- apps/opencs/model/doc/saving.cpp | 2 +- apps/opencs/model/doc/stage.cpp | 2 +- apps/opencs/model/filter/booleannode.cpp | 2 +- apps/opencs/model/filter/booleannode.hpp | 2 +- apps/opencs/model/filter/node.cpp | 2 +- apps/opencs/model/filter/notnode.cpp | 2 +- apps/opencs/model/filter/textnode.cpp | 2 +- apps/opencs/model/filter/unarynode.cpp | 2 +- apps/opencs/model/filter/valuenode.cpp | 2 +- apps/opencs/model/tools/birthsigncheck.cpp | 2 +- apps/opencs/model/tools/bodypartcheck.hpp | 2 +- apps/opencs/model/tools/classcheck.cpp | 2 +- apps/opencs/model/tools/mandatoryid.cpp | 2 +- apps/opencs/model/tools/racecheck.cpp | 2 +- apps/opencs/model/tools/referencecheck.hpp | 2 +- apps/opencs/model/tools/regioncheck.cpp | 2 +- apps/opencs/model/tools/reportmodel.cpp | 2 +- apps/opencs/model/tools/scriptcheck.cpp | 2 +- apps/opencs/model/tools/skillcheck.cpp | 2 +- apps/opencs/model/tools/soundcheck.cpp | 2 +- apps/opencs/model/tools/spellcheck.cpp | 2 +- apps/opencs/model/world/cell.hpp | 2 +- apps/opencs/model/world/collectionbase.cpp | 2 +- apps/opencs/model/world/collectionbase.hpp | 2 +- apps/opencs/model/world/columnbase.cpp | 2 +- apps/opencs/model/world/commanddispatcher.cpp | 2 +- apps/opencs/model/world/commands.cpp | 2 +- apps/opencs/model/world/commands.hpp | 2 +- apps/opencs/model/world/idtablebase.cpp | 2 +- apps/opencs/model/world/infocollection.hpp | 2 +- apps/opencs/model/world/pathgrid.hpp | 2 +- apps/opencs/model/world/record.cpp | 2 +- apps/opencs/model/world/ref.cpp | 2 +- apps/opencs/model/world/refidadapter.cpp | 2 +- apps/opencs/model/world/refidadapter.hpp | 2 +- apps/opencs/model/world/regionmap.cpp | 2 +- apps/opencs/model/world/resources.cpp | 2 +- apps/opencs/model/world/resourcesmanager.cpp | 2 +- apps/opencs/model/world/resourcesmanager.hpp | 2 +- apps/opencs/model/world/resourcetable.cpp | 2 +- apps/opencs/model/world/scope.cpp | 2 +- apps/opencs/model/world/scriptcontext.cpp | 2 +- apps/opencs/view/doc/globaldebugprofilemenu.cpp | 2 +- apps/opencs/view/doc/runlogsubview.cpp | 2 +- apps/opencs/view/doc/subviewfactory.cpp | 2 +- apps/opencs/view/doc/subviewfactoryimp.hpp | 2 +- apps/opencs/view/filter/editwidget.cpp | 2 +- apps/opencs/view/filter/recordfilterbox.hpp | 2 +- apps/opencs/view/render/editmode.cpp | 2 +- apps/opencs/view/render/lighting.cpp | 2 +- apps/opencs/view/render/lightingbright.cpp | 2 +- apps/opencs/view/render/lightingday.cpp | 2 +- apps/opencs/view/render/lightingnight.cpp | 2 +- apps/opencs/view/render/navigationorbit.cpp | 2 +- apps/opencs/view/tools/reporttable.cpp | 2 +- apps/opencs/view/tools/subviews.cpp | 2 +- apps/opencs/view/widget/pushbutton.cpp | 2 +- apps/opencs/view/widget/scenetoolmode.cpp | 2 +- apps/opencs/view/widget/scenetoolrun.cpp | 2 +- apps/opencs/view/world/creator.cpp | 2 +- apps/opencs/view/world/creator.hpp | 2 +- apps/opencs/view/world/dialoguecreator.cpp | 2 +- apps/opencs/view/world/dialoguesubview.hpp | 2 +- apps/opencs/view/world/genericcreator.cpp | 2 +- apps/opencs/view/world/genericcreator.hpp | 2 +- apps/opencs/view/world/idvalidator.cpp | 2 +- apps/opencs/view/world/infocreator.cpp | 2 +- apps/opencs/view/world/previewsubview.cpp | 2 +- apps/opencs/view/world/regionmapsubview.cpp | 2 +- apps/opencs/view/world/scriptedit.cpp | 2 +- apps/opencs/view/world/scriptedit.hpp | 2 +- apps/opencs/view/world/scripthighlighter.cpp | 2 +- apps/opencs/view/world/scriptsubview.hpp | 2 +- apps/opencs/view/world/subviews.cpp | 2 +- apps/openmw/mwmechanics/stat.cpp | 2 +- apps/openmw/mwscript/transformationextensions.hpp | 2 +- apps/openmw/mwworld/failedaction.hpp | 2 +- apps/openmw/mwworld/manualref.cpp | 2 +- components/bsa/resources.cpp | 2 +- components/compiler/extensions0.hpp | 2 +- components/compiler/nullerrorhandler.cpp | 2 +- components/compiler/opcodes.cpp | 2 +- components/compiler/quickfileparser.cpp | 2 +- components/esm/cellid.hpp | 2 +- components/esm/containerstate.cpp | 2 +- components/esm/globalscript.cpp | 2 +- components/esm/queststate.cpp | 2 +- extern/oics/ICSChannelListener.h | 2 +- extern/oics/ICSControlListener.h | 2 +- 95 files changed, 95 insertions(+), 95 deletions(-) diff --git a/apps/mwiniimporter/importer.cpp b/apps/mwiniimporter/importer.cpp index efebe5a4d..479f8cba2 100644 --- a/apps/mwiniimporter/importer.cpp +++ b/apps/mwiniimporter/importer.cpp @@ -903,4 +903,4 @@ std::time_t MwIniImporter::lastWriteTime(const boost::filesystem::path& filename std::cout << "content file: " << filename << " not found" << std::endl; } return writeTime; -} \ No newline at end of file +} diff --git a/apps/opencs/model/doc/blacklist.cpp b/apps/opencs/model/doc/blacklist.cpp index 9b37a4302..083726412 100644 --- a/apps/opencs/model/doc/blacklist.cpp +++ b/apps/opencs/model/doc/blacklist.cpp @@ -28,4 +28,4 @@ void CSMDoc::Blacklist::add (CSMWorld::UniversalId::Type type, std::transform (ids.begin(), ids.end(), list.begin()+size, Misc::StringUtils::lowerCase); std::sort (list.begin(), list.end()); -} \ No newline at end of file +} diff --git a/apps/opencs/model/doc/documentmanager.cpp b/apps/opencs/model/doc/documentmanager.cpp index 9b807225c..7a1a86153 100644 --- a/apps/opencs/model/doc/documentmanager.cpp +++ b/apps/opencs/model/doc/documentmanager.cpp @@ -107,4 +107,4 @@ void CSMDoc::DocumentManager::documentNotLoaded (Document *document, const std:: if (error.empty()) // do not remove the document yet, if we have an error removeDocument (document); -} \ No newline at end of file +} diff --git a/apps/opencs/model/doc/documentmanager.hpp b/apps/opencs/model/doc/documentmanager.hpp index c545b9a9f..3202c4fe1 100644 --- a/apps/opencs/model/doc/documentmanager.hpp +++ b/apps/opencs/model/doc/documentmanager.hpp @@ -99,4 +99,4 @@ namespace CSMDoc }; } -#endif \ No newline at end of file +#endif diff --git a/apps/opencs/model/doc/messages.cpp b/apps/opencs/model/doc/messages.cpp index 1fb423145..9b295fb28 100644 --- a/apps/opencs/model/doc/messages.cpp +++ b/apps/opencs/model/doc/messages.cpp @@ -25,4 +25,4 @@ CSMDoc::Messages::Iterator CSMDoc::Messages::begin() const CSMDoc::Messages::Iterator CSMDoc::Messages::end() const { return mMessages.end(); -} \ No newline at end of file +} diff --git a/apps/opencs/model/doc/operation.hpp b/apps/opencs/model/doc/operation.hpp index 3c9467754..a4ee88a07 100644 --- a/apps/opencs/model/doc/operation.hpp +++ b/apps/opencs/model/doc/operation.hpp @@ -68,4 +68,4 @@ namespace CSMDoc }; } -#endif \ No newline at end of file +#endif diff --git a/apps/opencs/model/doc/saving.cpp b/apps/opencs/model/doc/saving.cpp index b52186a47..04d61ed1b 100644 --- a/apps/opencs/model/doc/saving.cpp +++ b/apps/opencs/model/doc/saving.cpp @@ -97,4 +97,4 @@ CSMDoc::Saving::Saving (Document& document, const boost::filesystem::path& proje appendStage (new CloseSaveStage (mState)); appendStage (new FinalSavingStage (mDocument, mState)); -} \ No newline at end of file +} diff --git a/apps/opencs/model/doc/stage.cpp b/apps/opencs/model/doc/stage.cpp index 99b765770..1a2c5c721 100644 --- a/apps/opencs/model/doc/stage.cpp +++ b/apps/opencs/model/doc/stage.cpp @@ -1,4 +1,4 @@ #include "stage.hpp" -CSMDoc::Stage::~Stage() {} \ No newline at end of file +CSMDoc::Stage::~Stage() {} diff --git a/apps/opencs/model/filter/booleannode.cpp b/apps/opencs/model/filter/booleannode.cpp index 2daa1b6d8..35fc98e08 100644 --- a/apps/opencs/model/filter/booleannode.cpp +++ b/apps/opencs/model/filter/booleannode.cpp @@ -12,4 +12,4 @@ bool CSMFilter::BooleanNode::test (const CSMWorld::IdTableBase& table, int row, std::string CSMFilter::BooleanNode::toString (bool numericColumns) const { return mTrue ? "true" : "false"; -} \ No newline at end of file +} diff --git a/apps/opencs/model/filter/booleannode.hpp b/apps/opencs/model/filter/booleannode.hpp index d9635746c..32206b575 100644 --- a/apps/opencs/model/filter/booleannode.hpp +++ b/apps/opencs/model/filter/booleannode.hpp @@ -26,4 +26,4 @@ namespace CSMFilter }; } -#endif \ No newline at end of file +#endif diff --git a/apps/opencs/model/filter/node.cpp b/apps/opencs/model/filter/node.cpp index 276861cdc..091dc4698 100644 --- a/apps/opencs/model/filter/node.cpp +++ b/apps/opencs/model/filter/node.cpp @@ -3,4 +3,4 @@ CSMFilter::Node::Node() {} -CSMFilter::Node::~Node() {} \ No newline at end of file +CSMFilter::Node::~Node() {} diff --git a/apps/opencs/model/filter/notnode.cpp b/apps/opencs/model/filter/notnode.cpp index 231773075..b5d9da7b7 100644 --- a/apps/opencs/model/filter/notnode.cpp +++ b/apps/opencs/model/filter/notnode.cpp @@ -7,4 +7,4 @@ bool CSMFilter::NotNode::test (const CSMWorld::IdTableBase& table, int row, const std::map& columns) const { return !getChild().test (table, row, columns); -} \ No newline at end of file +} diff --git a/apps/opencs/model/filter/textnode.cpp b/apps/opencs/model/filter/textnode.cpp index 24cdce4f5..73c378f11 100644 --- a/apps/opencs/model/filter/textnode.cpp +++ b/apps/opencs/model/filter/textnode.cpp @@ -82,4 +82,4 @@ std::string CSMFilter::TextNode::toString (bool numericColumns) const stream << ", \"" << mText << "\")"; return stream.str(); -} \ No newline at end of file +} diff --git a/apps/opencs/model/filter/unarynode.cpp b/apps/opencs/model/filter/unarynode.cpp index 43a24b76a..c40d191b6 100644 --- a/apps/opencs/model/filter/unarynode.cpp +++ b/apps/opencs/model/filter/unarynode.cpp @@ -23,4 +23,4 @@ std::vector CSMFilter::UnaryNode::getReferencedColumns() const std::string CSMFilter::UnaryNode::toString (bool numericColumns) const { return mName + " " + mChild->toString (numericColumns); -} \ No newline at end of file +} diff --git a/apps/opencs/model/filter/valuenode.cpp b/apps/opencs/model/filter/valuenode.cpp index 26b982441..72cf5896b 100644 --- a/apps/opencs/model/filter/valuenode.cpp +++ b/apps/opencs/model/filter/valuenode.cpp @@ -94,4 +94,4 @@ std::string CSMFilter::ValueNode::toString (bool numericColumns) const stream << ")"; return stream.str(); -} \ No newline at end of file +} diff --git a/apps/opencs/model/tools/birthsigncheck.cpp b/apps/opencs/model/tools/birthsigncheck.cpp index 1d72e24b8..4e6da4631 100644 --- a/apps/opencs/model/tools/birthsigncheck.cpp +++ b/apps/opencs/model/tools/birthsigncheck.cpp @@ -41,4 +41,4 @@ void CSMTools::BirthsignCheckStage::perform (int stage, CSMDoc::Messages& messag /// \todo test if the texture exists /// \todo check data members that can't be edited in the table view -} \ No newline at end of file +} diff --git a/apps/opencs/model/tools/bodypartcheck.hpp b/apps/opencs/model/tools/bodypartcheck.hpp index 0a6ca959a..dbab5f5c6 100644 --- a/apps/opencs/model/tools/bodypartcheck.hpp +++ b/apps/opencs/model/tools/bodypartcheck.hpp @@ -32,4 +32,4 @@ namespace CSMTools }; } -#endif \ No newline at end of file +#endif diff --git a/apps/opencs/model/tools/classcheck.cpp b/apps/opencs/model/tools/classcheck.cpp index 5b872a266..be57a3729 100644 --- a/apps/opencs/model/tools/classcheck.cpp +++ b/apps/opencs/model/tools/classcheck.cpp @@ -65,4 +65,4 @@ void CSMTools::ClassCheckStage::perform (int stage, CSMDoc::Messages& messages) messages.push_back (std::make_pair (id, ESM::Skill::indexToId (iter->first) + " is listed more than once")); } -} \ No newline at end of file +} diff --git a/apps/opencs/model/tools/mandatoryid.cpp b/apps/opencs/model/tools/mandatoryid.cpp index 87d19401b..4c97d2266 100644 --- a/apps/opencs/model/tools/mandatoryid.cpp +++ b/apps/opencs/model/tools/mandatoryid.cpp @@ -20,4 +20,4 @@ void CSMTools::MandatoryIdStage::perform (int stage, CSMDoc::Messages& messages) if (mIdCollection.searchId (mIds.at (stage))==-1 || mIdCollection.getRecord (mIds.at (stage)).isDeleted()) messages.add (mCollectionId, "Missing mandatory record: " + mIds.at (stage)); -} \ No newline at end of file +} diff --git a/apps/opencs/model/tools/racecheck.cpp b/apps/opencs/model/tools/racecheck.cpp index 143d61772..3b2c8d290 100644 --- a/apps/opencs/model/tools/racecheck.cpp +++ b/apps/opencs/model/tools/racecheck.cpp @@ -70,4 +70,4 @@ void CSMTools::RaceCheckStage::perform (int stage, CSMDoc::Messages& messages) performFinal (messages); else performPerRecord (stage, messages); -} \ No newline at end of file +} diff --git a/apps/opencs/model/tools/referencecheck.hpp b/apps/opencs/model/tools/referencecheck.hpp index 9cf685b3a..70ef02916 100644 --- a/apps/opencs/model/tools/referencecheck.hpp +++ b/apps/opencs/model/tools/referencecheck.hpp @@ -26,4 +26,4 @@ namespace CSMTools }; } -#endif // CSM_TOOLS_REFERENCECHECK_H \ No newline at end of file +#endif // CSM_TOOLS_REFERENCECHECK_H diff --git a/apps/opencs/model/tools/regioncheck.cpp b/apps/opencs/model/tools/regioncheck.cpp index 091836d0d..42abc35c9 100644 --- a/apps/opencs/model/tools/regioncheck.cpp +++ b/apps/opencs/model/tools/regioncheck.cpp @@ -35,4 +35,4 @@ void CSMTools::RegionCheckStage::perform (int stage, CSMDoc::Messages& messages) /// \todo test that the ID in mSleeplist exists /// \todo check data members that can't be edited in the table view -} \ No newline at end of file +} diff --git a/apps/opencs/model/tools/reportmodel.cpp b/apps/opencs/model/tools/reportmodel.cpp index 135420612..ac9dabb25 100644 --- a/apps/opencs/model/tools/reportmodel.cpp +++ b/apps/opencs/model/tools/reportmodel.cpp @@ -78,4 +78,4 @@ const CSMWorld::UniversalId& CSMTools::ReportModel::getUniversalId (int row) con std::string CSMTools::ReportModel::getHint (int row) const { return mRows.at (row).second.second; -} \ No newline at end of file +} diff --git a/apps/opencs/model/tools/scriptcheck.cpp b/apps/opencs/model/tools/scriptcheck.cpp index d9dea7f43..a70ee2ae4 100644 --- a/apps/opencs/model/tools/scriptcheck.cpp +++ b/apps/opencs/model/tools/scriptcheck.cpp @@ -98,4 +98,4 @@ void CSMTools::ScriptCheckStage::perform (int stage, CSMDoc::Messages& messages) } mMessages = 0; -} \ No newline at end of file +} diff --git a/apps/opencs/model/tools/skillcheck.cpp b/apps/opencs/model/tools/skillcheck.cpp index e061e042c..2b55526e0 100644 --- a/apps/opencs/model/tools/skillcheck.cpp +++ b/apps/opencs/model/tools/skillcheck.cpp @@ -39,4 +39,4 @@ void CSMTools::SkillCheckStage::perform (int stage, CSMDoc::Messages& messages) if (skill.mDescription.empty()) messages.push_back (std::make_pair (id, skill.mId + " has an empty description")); -} \ No newline at end of file +} diff --git a/apps/opencs/model/tools/soundcheck.cpp b/apps/opencs/model/tools/soundcheck.cpp index e122ced91..f78932a32 100644 --- a/apps/opencs/model/tools/soundcheck.cpp +++ b/apps/opencs/model/tools/soundcheck.cpp @@ -31,4 +31,4 @@ void CSMTools::SoundCheckStage::perform (int stage, CSMDoc::Messages& messages) messages.push_back (std::make_pair (id, "Maximum range larger than minimum range")); /// \todo check, if the sound file exists -} \ No newline at end of file +} diff --git a/apps/opencs/model/tools/spellcheck.cpp b/apps/opencs/model/tools/spellcheck.cpp index 0b59dc862..bd076d2a5 100644 --- a/apps/opencs/model/tools/spellcheck.cpp +++ b/apps/opencs/model/tools/spellcheck.cpp @@ -37,4 +37,4 @@ void CSMTools::SpellCheckStage::perform (int stage, CSMDoc::Messages& messages) messages.push_back (std::make_pair (id, spell.mId + " has a negative spell costs")); /// \todo check data members that can't be edited in the table view -} \ No newline at end of file +} diff --git a/apps/opencs/model/world/cell.hpp b/apps/opencs/model/world/cell.hpp index a47dbf45d..f393e2cf9 100644 --- a/apps/opencs/model/world/cell.hpp +++ b/apps/opencs/model/world/cell.hpp @@ -21,4 +21,4 @@ namespace CSMWorld }; } -#endif \ No newline at end of file +#endif diff --git a/apps/opencs/model/world/collectionbase.cpp b/apps/opencs/model/world/collectionbase.cpp index 241f198cb..b8eed4192 100644 --- a/apps/opencs/model/world/collectionbase.cpp +++ b/apps/opencs/model/world/collectionbase.cpp @@ -28,4 +28,4 @@ int CSMWorld::CollectionBase::findColumnIndex (Columns::ColumnId id) const throw std::logic_error ("invalid column index"); return index; -} \ No newline at end of file +} diff --git a/apps/opencs/model/world/collectionbase.hpp b/apps/opencs/model/world/collectionbase.hpp index 442055d5f..ef826e31c 100644 --- a/apps/opencs/model/world/collectionbase.hpp +++ b/apps/opencs/model/world/collectionbase.hpp @@ -106,4 +106,4 @@ namespace CSMWorld }; } -#endif \ No newline at end of file +#endif diff --git a/apps/opencs/model/world/columnbase.cpp b/apps/opencs/model/world/columnbase.cpp index f6363fe2e..665ab9354 100644 --- a/apps/opencs/model/world/columnbase.cpp +++ b/apps/opencs/model/world/columnbase.cpp @@ -22,4 +22,4 @@ std::string CSMWorld::ColumnBase::getTitle() const int CSMWorld::ColumnBase::getId() const { return mColumnId; -} \ No newline at end of file +} diff --git a/apps/opencs/model/world/commanddispatcher.cpp b/apps/opencs/model/world/commanddispatcher.cpp index 4e146d87c..ca6faafbc 100644 --- a/apps/opencs/model/world/commanddispatcher.cpp +++ b/apps/opencs/model/world/commanddispatcher.cpp @@ -264,4 +264,4 @@ void CSMWorld::CommandDispatcher::executeExtendedRevert() if (mExtendedTypes.size()>1) mDocument.getUndoStack().endMacro(); -} \ No newline at end of file +} diff --git a/apps/opencs/model/world/commands.cpp b/apps/opencs/model/world/commands.cpp index de0e9a4e5..1d86ba080 100644 --- a/apps/opencs/model/world/commands.cpp +++ b/apps/opencs/model/world/commands.cpp @@ -170,4 +170,4 @@ void CSMWorld::CloneCommand::redo() void CSMWorld::CloneCommand::undo() { mModel.removeRow (mModel.getModelIndex (mId, 0).row()); -} \ No newline at end of file +} diff --git a/apps/opencs/model/world/commands.hpp b/apps/opencs/model/world/commands.hpp index a15c071a8..7267c9c8b 100644 --- a/apps/opencs/model/world/commands.hpp +++ b/apps/opencs/model/world/commands.hpp @@ -141,4 +141,4 @@ namespace CSMWorld }; } -#endif \ No newline at end of file +#endif diff --git a/apps/opencs/model/world/idtablebase.cpp b/apps/opencs/model/world/idtablebase.cpp index 31d8d461e..389f5396e 100644 --- a/apps/opencs/model/world/idtablebase.cpp +++ b/apps/opencs/model/world/idtablebase.cpp @@ -6,4 +6,4 @@ CSMWorld::IdTableBase::IdTableBase (unsigned int features) : mFeatures (features unsigned int CSMWorld::IdTableBase::getFeatures() const { return mFeatures; -} \ No newline at end of file +} diff --git a/apps/opencs/model/world/infocollection.hpp b/apps/opencs/model/world/infocollection.hpp index ae61f5d39..e953effa8 100644 --- a/apps/opencs/model/world/infocollection.hpp +++ b/apps/opencs/model/world/infocollection.hpp @@ -47,4 +47,4 @@ namespace CSMWorld }; } -#endif \ No newline at end of file +#endif diff --git a/apps/opencs/model/world/pathgrid.hpp b/apps/opencs/model/world/pathgrid.hpp index d8cc89f24..7e7b7c3bb 100644 --- a/apps/opencs/model/world/pathgrid.hpp +++ b/apps/opencs/model/world/pathgrid.hpp @@ -26,4 +26,4 @@ namespace CSMWorld }; } -#endif \ No newline at end of file +#endif diff --git a/apps/opencs/model/world/record.cpp b/apps/opencs/model/world/record.cpp index 14f63c155..ef2f4d320 100644 --- a/apps/opencs/model/world/record.cpp +++ b/apps/opencs/model/world/record.cpp @@ -18,4 +18,4 @@ bool CSMWorld::RecordBase::isErased() const bool CSMWorld::RecordBase::isModified() const { return mState==State_Modified || mState==State_ModifiedOnly; -} \ No newline at end of file +} diff --git a/apps/opencs/model/world/ref.cpp b/apps/opencs/model/world/ref.cpp index f3c1b0b73..eee454a16 100644 --- a/apps/opencs/model/world/ref.cpp +++ b/apps/opencs/model/world/ref.cpp @@ -5,4 +5,4 @@ CSMWorld::CellRef::CellRef() { mRefNum.mIndex = 0; mRefNum.mContentFile = 0; -} \ No newline at end of file +} diff --git a/apps/opencs/model/world/refidadapter.cpp b/apps/opencs/model/world/refidadapter.cpp index 94ae38c3c..8f74e6134 100644 --- a/apps/opencs/model/world/refidadapter.cpp +++ b/apps/opencs/model/world/refidadapter.cpp @@ -3,4 +3,4 @@ CSMWorld::RefIdAdapter::RefIdAdapter() {} -CSMWorld::RefIdAdapter::~RefIdAdapter() {} \ No newline at end of file +CSMWorld::RefIdAdapter::~RefIdAdapter() {} diff --git a/apps/opencs/model/world/refidadapter.hpp b/apps/opencs/model/world/refidadapter.hpp index 0870a2d3e..3320af190 100644 --- a/apps/opencs/model/world/refidadapter.hpp +++ b/apps/opencs/model/world/refidadapter.hpp @@ -35,4 +35,4 @@ namespace CSMWorld }; } -#endif \ No newline at end of file +#endif diff --git a/apps/opencs/model/world/regionmap.cpp b/apps/opencs/model/world/regionmap.cpp index 5f030bb52..f63426c04 100644 --- a/apps/opencs/model/world/regionmap.cpp +++ b/apps/opencs/model/world/regionmap.cpp @@ -503,4 +503,4 @@ void CSMWorld::RegionMap::cellsChanged (const QModelIndex& topLeft, const QModel // columns we are interested in. If not we can exit the function here and avoid all updating. addCells (topLeft.row(), bottomRight.row()); -} \ No newline at end of file +} diff --git a/apps/opencs/model/world/resources.cpp b/apps/opencs/model/world/resources.cpp index 13c8df84d..8c9439890 100644 --- a/apps/opencs/model/world/resources.cpp +++ b/apps/opencs/model/world/resources.cpp @@ -105,4 +105,4 @@ int CSMWorld::Resources::searchId (const std::string& id) const CSMWorld::UniversalId::Type CSMWorld::Resources::getType() const { return mType; -} \ No newline at end of file +} diff --git a/apps/opencs/model/world/resourcesmanager.cpp b/apps/opencs/model/world/resourcesmanager.cpp index 50014f4b5..deddd83b5 100644 --- a/apps/opencs/model/world/resourcesmanager.cpp +++ b/apps/opencs/model/world/resourcesmanager.cpp @@ -30,4 +30,4 @@ const CSMWorld::Resources& CSMWorld::ResourcesManager::get (UniversalId::Type ty throw std::logic_error ("Unknown resource type"); return iter->second; -} \ No newline at end of file +} diff --git a/apps/opencs/model/world/resourcesmanager.hpp b/apps/opencs/model/world/resourcesmanager.hpp index 77f210c47..18861a6a5 100644 --- a/apps/opencs/model/world/resourcesmanager.hpp +++ b/apps/opencs/model/world/resourcesmanager.hpp @@ -25,4 +25,4 @@ namespace CSMWorld }; } -#endif \ No newline at end of file +#endif diff --git a/apps/opencs/model/world/resourcetable.cpp b/apps/opencs/model/world/resourcetable.cpp index a7180434a..9257b9d2a 100644 --- a/apps/opencs/model/world/resourcetable.cpp +++ b/apps/opencs/model/world/resourcetable.cpp @@ -143,4 +143,4 @@ std::pair CSMWorld::ResourceTable::view (int bool CSMWorld::ResourceTable::isDeleted (const std::string& id) const { return false; -} \ No newline at end of file +} diff --git a/apps/opencs/model/world/scope.cpp b/apps/opencs/model/world/scope.cpp index e3ebf5ebd..6e4ce4c02 100644 --- a/apps/opencs/model/world/scope.cpp +++ b/apps/opencs/model/world/scope.cpp @@ -22,4 +22,4 @@ CSMWorld::Scope CSMWorld::getScopeFromId (const std::string& id) return Scope_Session; return Scope_Content; -} \ No newline at end of file +} diff --git a/apps/opencs/model/world/scriptcontext.cpp b/apps/opencs/model/world/scriptcontext.cpp index 0d2b9984e..a8c2c9452 100644 --- a/apps/opencs/model/world/scriptcontext.cpp +++ b/apps/opencs/model/world/scriptcontext.cpp @@ -120,4 +120,4 @@ void CSMWorld::ScriptContext::clear() mIds.clear(); mIdsUpdated = false; mLocals.clear(); -} \ No newline at end of file +} diff --git a/apps/opencs/view/doc/globaldebugprofilemenu.cpp b/apps/opencs/view/doc/globaldebugprofilemenu.cpp index 82bd96326..b88381385 100644 --- a/apps/opencs/view/doc/globaldebugprofilemenu.cpp +++ b/apps/opencs/view/doc/globaldebugprofilemenu.cpp @@ -90,4 +90,4 @@ void CSVDoc::GlobalDebugProfileMenu::profileChanged (const QModelIndex& topLeft, void CSVDoc::GlobalDebugProfileMenu::actionTriggered (QAction *action) { emit triggered (std::string (action->text().toUtf8().constData())); -} \ No newline at end of file +} diff --git a/apps/opencs/view/doc/runlogsubview.cpp b/apps/opencs/view/doc/runlogsubview.cpp index 68e888e8d..129396999 100644 --- a/apps/opencs/view/doc/runlogsubview.cpp +++ b/apps/opencs/view/doc/runlogsubview.cpp @@ -17,4 +17,4 @@ CSVDoc::RunLogSubView::RunLogSubView (const CSMWorld::UniversalId& id, void CSVDoc::RunLogSubView::setEditLock (bool locked) { // ignored since this SubView does not have editing -} \ No newline at end of file +} diff --git a/apps/opencs/view/doc/subviewfactory.cpp b/apps/opencs/view/doc/subviewfactory.cpp index 8576f6b1d..3137f7e32 100644 --- a/apps/opencs/view/doc/subviewfactory.cpp +++ b/apps/opencs/view/doc/subviewfactory.cpp @@ -35,4 +35,4 @@ CSVDoc::SubView *CSVDoc::SubViewFactoryManager::makeSubView (const CSMWorld::Uni throw std::runtime_error ("Failed to create a sub view for: " + id.toString()); return iter->second->makeSubView (id, document); -} \ No newline at end of file +} diff --git a/apps/opencs/view/doc/subviewfactoryimp.hpp b/apps/opencs/view/doc/subviewfactoryimp.hpp index 059b24fd0..670137985 100644 --- a/apps/opencs/view/doc/subviewfactoryimp.hpp +++ b/apps/opencs/view/doc/subviewfactoryimp.hpp @@ -48,4 +48,4 @@ namespace CSVDoc } } -#endif \ No newline at end of file +#endif diff --git a/apps/opencs/view/filter/editwidget.cpp b/apps/opencs/view/filter/editwidget.cpp index 68e99e0de..bc7f9b5a1 100644 --- a/apps/opencs/view/filter/editwidget.cpp +++ b/apps/opencs/view/filter/editwidget.cpp @@ -193,4 +193,4 @@ std::string CSVFilter::EditWidget::generateFilter (std::pair< std::string, std:: } return ss.str(); -} \ No newline at end of file +} diff --git a/apps/opencs/view/filter/recordfilterbox.hpp b/apps/opencs/view/filter/recordfilterbox.hpp index f4d17510b..29d12529a 100644 --- a/apps/opencs/view/filter/recordfilterbox.hpp +++ b/apps/opencs/view/filter/recordfilterbox.hpp @@ -43,4 +43,4 @@ namespace CSVFilter } -#endif \ No newline at end of file +#endif diff --git a/apps/opencs/view/render/editmode.cpp b/apps/opencs/view/render/editmode.cpp index 51a137d3b..9361030a3 100644 --- a/apps/opencs/view/render/editmode.cpp +++ b/apps/opencs/view/render/editmode.cpp @@ -16,4 +16,4 @@ unsigned int CSVRender::EditMode::getInteractionMask() const void CSVRender::EditMode::activate (CSVWidget::SceneToolbar *toolbar) { mWorldspaceWidget->setInteractionMask (mMask); -} \ No newline at end of file +} diff --git a/apps/opencs/view/render/lighting.cpp b/apps/opencs/view/render/lighting.cpp index d57570d69..3553ef58c 100644 --- a/apps/opencs/view/render/lighting.cpp +++ b/apps/opencs/view/render/lighting.cpp @@ -1,4 +1,4 @@ #include "lighting.hpp" -CSVRender::Lighting::~Lighting() {} \ No newline at end of file +CSVRender::Lighting::~Lighting() {} diff --git a/apps/opencs/view/render/lightingbright.cpp b/apps/opencs/view/render/lightingbright.cpp index ab845b924..a342ab093 100644 --- a/apps/opencs/view/render/lightingbright.cpp +++ b/apps/opencs/view/render/lightingbright.cpp @@ -27,4 +27,4 @@ void CSVRender::LightingBright::deactivate() } } -void CSVRender::LightingBright::setDefaultAmbient (const Ogre::ColourValue& colour) {} \ No newline at end of file +void CSVRender::LightingBright::setDefaultAmbient (const Ogre::ColourValue& colour) {} diff --git a/apps/opencs/view/render/lightingday.cpp b/apps/opencs/view/render/lightingday.cpp index ab0257c0c..c5189ccfd 100644 --- a/apps/opencs/view/render/lightingday.cpp +++ b/apps/opencs/view/render/lightingday.cpp @@ -33,4 +33,4 @@ void CSVRender::LightingDay::deactivate() void CSVRender::LightingDay::setDefaultAmbient (const Ogre::ColourValue& colour) { mSceneManager->setAmbientLight (colour); -} \ No newline at end of file +} diff --git a/apps/opencs/view/render/lightingnight.cpp b/apps/opencs/view/render/lightingnight.cpp index 516bb3f40..7d94dc964 100644 --- a/apps/opencs/view/render/lightingnight.cpp +++ b/apps/opencs/view/render/lightingnight.cpp @@ -33,4 +33,4 @@ void CSVRender::LightingNight::deactivate() void CSVRender::LightingNight::setDefaultAmbient (const Ogre::ColourValue& colour) { mSceneManager->setAmbientLight (colour); -} \ No newline at end of file +} diff --git a/apps/opencs/view/render/navigationorbit.cpp b/apps/opencs/view/render/navigationorbit.cpp index c6e729e96..c5f3eda96 100644 --- a/apps/opencs/view/render/navigationorbit.cpp +++ b/apps/opencs/view/render/navigationorbit.cpp @@ -97,4 +97,4 @@ bool CSVRender::NavigationOrbit::handleRollKeys (int delta) { mCamera->roll (Ogre::Degree (getFactor (false) * delta)); return true; -} \ No newline at end of file +} diff --git a/apps/opencs/view/tools/reporttable.cpp b/apps/opencs/view/tools/reporttable.cpp index 4cd11925e..da15b4acc 100644 --- a/apps/opencs/view/tools/reporttable.cpp +++ b/apps/opencs/view/tools/reporttable.cpp @@ -133,4 +133,4 @@ void CSVTools::ReportTable::removeSelection() mModel->removeRows (iter->row(), 1); selectionModel()->clear(); -} \ No newline at end of file +} diff --git a/apps/opencs/view/tools/subviews.cpp b/apps/opencs/view/tools/subviews.cpp index 8b04aca50..a50b5724a 100644 --- a/apps/opencs/view/tools/subviews.cpp +++ b/apps/opencs/view/tools/subviews.cpp @@ -11,4 +11,4 @@ void CSVTools::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) new CSVDoc::SubViewFactory); manager.add (CSMWorld::UniversalId::Type_LoadErrorLog, new CSVDoc::SubViewFactory); -} \ No newline at end of file +} diff --git a/apps/opencs/view/widget/pushbutton.cpp b/apps/opencs/view/widget/pushbutton.cpp index d4e600794..1baeb7ca2 100644 --- a/apps/opencs/view/widget/pushbutton.cpp +++ b/apps/opencs/view/widget/pushbutton.cpp @@ -106,4 +106,4 @@ CSVWidget::PushButton::Type CSVWidget::PushButton::getType() const void CSVWidget::PushButton::checkedStateChanged (bool checked) { setExtendedToolTip(); -} \ No newline at end of file +} diff --git a/apps/opencs/view/widget/scenetoolmode.cpp b/apps/opencs/view/widget/scenetoolmode.cpp index 8d871cc5f..39e051c48 100644 --- a/apps/opencs/view/widget/scenetoolmode.cpp +++ b/apps/opencs/view/widget/scenetoolmode.cpp @@ -100,4 +100,4 @@ void CSVWidget::SceneToolMode::selected() emit modeChanged (iter->second); } -} \ No newline at end of file +} diff --git a/apps/opencs/view/widget/scenetoolrun.cpp b/apps/opencs/view/widget/scenetoolrun.cpp index 0c7a4b9f0..8de334efe 100644 --- a/apps/opencs/view/widget/scenetoolrun.cpp +++ b/apps/opencs/view/widget/scenetoolrun.cpp @@ -148,4 +148,4 @@ void CSVWidget::SceneToolRun::clicked (const QModelIndex& index) removeProfile (*iter); updatePanel(); } -} \ No newline at end of file +} diff --git a/apps/opencs/view/world/creator.cpp b/apps/opencs/view/world/creator.cpp index a24c58e54..2e7c7fe22 100644 --- a/apps/opencs/view/world/creator.cpp +++ b/apps/opencs/view/world/creator.cpp @@ -19,4 +19,4 @@ CSVWorld::Creator *CSVWorld::NullCreatorFactory::makeCreator (CSMWorld::Data& da QUndoStack& undoStack, const CSMWorld::UniversalId& id) const { return 0; -} \ No newline at end of file +} diff --git a/apps/opencs/view/world/creator.hpp b/apps/opencs/view/world/creator.hpp index 8e50e8715..7c0422c88 100644 --- a/apps/opencs/view/world/creator.hpp +++ b/apps/opencs/view/world/creator.hpp @@ -101,4 +101,4 @@ namespace CSVWorld } } -#endif \ No newline at end of file +#endif diff --git a/apps/opencs/view/world/dialoguecreator.cpp b/apps/opencs/view/world/dialoguecreator.cpp index 3523d5e32..956cd26df 100644 --- a/apps/opencs/view/world/dialoguecreator.cpp +++ b/apps/opencs/view/world/dialoguecreator.cpp @@ -32,4 +32,4 @@ CSVWorld::Creator *CSVWorld::JournalCreatorFactory::makeCreator (CSMWorld::Data& QUndoStack& undoStack, const CSMWorld::UniversalId& id) const { return new DialogueCreator (data, undoStack, id, ESM::Dialogue::Journal); -} \ No newline at end of file +} diff --git a/apps/opencs/view/world/dialoguesubview.hpp b/apps/opencs/view/world/dialoguesubview.hpp index 4c260170f..5de2c3ad2 100644 --- a/apps/opencs/view/world/dialoguesubview.hpp +++ b/apps/opencs/view/world/dialoguesubview.hpp @@ -209,4 +209,4 @@ namespace CSVWorld }; } -#endif \ No newline at end of file +#endif diff --git a/apps/opencs/view/world/genericcreator.cpp b/apps/opencs/view/world/genericcreator.cpp index afa59bc45..b4cf46040 100644 --- a/apps/opencs/view/world/genericcreator.cpp +++ b/apps/opencs/view/world/genericcreator.cpp @@ -276,4 +276,4 @@ void CSVWorld::GenericCreator::scopeChanged (int index) { update(); updateNamespace(); -} \ No newline at end of file +} diff --git a/apps/opencs/view/world/genericcreator.hpp b/apps/opencs/view/world/genericcreator.hpp index 8c8c34bd8..678005082 100644 --- a/apps/opencs/view/world/genericcreator.hpp +++ b/apps/opencs/view/world/genericcreator.hpp @@ -111,4 +111,4 @@ namespace CSVWorld }; } -#endif \ No newline at end of file +#endif diff --git a/apps/opencs/view/world/idvalidator.cpp b/apps/opencs/view/world/idvalidator.cpp index 7caa20f9b..13b05d2d1 100644 --- a/apps/opencs/view/world/idvalidator.cpp +++ b/apps/opencs/view/world/idvalidator.cpp @@ -120,4 +120,4 @@ void CSVWorld::IdValidator::setNamespace (const std::string& namespace_) std::string CSVWorld::IdValidator::getError() const { return mError; -} \ No newline at end of file +} diff --git a/apps/opencs/view/world/infocreator.cpp b/apps/opencs/view/world/infocreator.cpp index 1d914716b..14034ea7f 100644 --- a/apps/opencs/view/world/infocreator.cpp +++ b/apps/opencs/view/world/infocreator.cpp @@ -94,4 +94,4 @@ std::string CSVWorld::InfoCreator::getErrors() const void CSVWorld::InfoCreator::topicChanged() { update(); -} \ No newline at end of file +} diff --git a/apps/opencs/view/world/previewsubview.cpp b/apps/opencs/view/world/previewsubview.cpp index 1ae466f42..1c2d6b95c 100644 --- a/apps/opencs/view/world/previewsubview.cpp +++ b/apps/opencs/view/world/previewsubview.cpp @@ -67,4 +67,4 @@ void CSVWorld::PreviewSubView::referenceableIdChanged (const std::string& id) setWindowTitle (QString::fromUtf8 (mTitle.c_str())); emit updateTitle(); -} \ No newline at end of file +} diff --git a/apps/opencs/view/world/regionmapsubview.cpp b/apps/opencs/view/world/regionmapsubview.cpp index a7675a4a6..411e24e75 100644 --- a/apps/opencs/view/world/regionmapsubview.cpp +++ b/apps/opencs/view/world/regionmapsubview.cpp @@ -24,4 +24,4 @@ void CSVWorld::RegionMapSubView::editRequest (const CSMWorld::UniversalId& id, const std::string& hint) { focusId (id, hint); -} \ No newline at end of file +} diff --git a/apps/opencs/view/world/scriptedit.cpp b/apps/opencs/view/world/scriptedit.cpp index c2d94ab5d..271b0316d 100644 --- a/apps/opencs/view/world/scriptedit.cpp +++ b/apps/opencs/view/world/scriptedit.cpp @@ -156,4 +156,4 @@ void CSVWorld::ScriptEdit::updateHighlighting() ChangeLock lock (*this); mHighlighter->rehighlight(); -} \ No newline at end of file +} diff --git a/apps/opencs/view/world/scriptedit.hpp b/apps/opencs/view/world/scriptedit.hpp index c67385816..0192bc550 100644 --- a/apps/opencs/view/world/scriptedit.hpp +++ b/apps/opencs/view/world/scriptedit.hpp @@ -76,4 +76,4 @@ namespace CSVWorld void updateHighlighting(); }; } -#endif // SCRIPTEDIT_H \ No newline at end of file +#endif // SCRIPTEDIT_H diff --git a/apps/opencs/view/world/scripthighlighter.cpp b/apps/opencs/view/world/scripthighlighter.cpp index 36cebcb76..6dda8d4fa 100644 --- a/apps/opencs/view/world/scripthighlighter.cpp +++ b/apps/opencs/view/world/scripthighlighter.cpp @@ -142,4 +142,4 @@ void CSVWorld::ScriptHighlighter::highlightBlock (const QString& text) void CSVWorld::ScriptHighlighter::invalidateIds() { mContext.invalidateIds(); -} \ No newline at end of file +} diff --git a/apps/opencs/view/world/scriptsubview.hpp b/apps/opencs/view/world/scriptsubview.hpp index 16ffc7b80..561476577 100644 --- a/apps/opencs/view/world/scriptsubview.hpp +++ b/apps/opencs/view/world/scriptsubview.hpp @@ -46,4 +46,4 @@ namespace CSVWorld }; } -#endif \ No newline at end of file +#endif diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp index 5e01ef283..cd9b37a64 100644 --- a/apps/opencs/view/world/subviews.cpp +++ b/apps/opencs/view/world/subviews.cpp @@ -172,4 +172,4 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) //preview manager.add (CSMWorld::UniversalId::Type_Preview, new CSVDoc::SubViewFactory); -} \ No newline at end of file +} diff --git a/apps/openmw/mwmechanics/stat.cpp b/apps/openmw/mwmechanics/stat.cpp index 3216a46e6..e067e354e 100644 --- a/apps/openmw/mwmechanics/stat.cpp +++ b/apps/openmw/mwmechanics/stat.cpp @@ -31,4 +31,4 @@ void MWMechanics::SkillValue::readState (const ESM::StatState& state) { AttributeValue::readState (state); mProgress = state.mProgress; -} \ No newline at end of file +} diff --git a/apps/openmw/mwscript/transformationextensions.hpp b/apps/openmw/mwscript/transformationextensions.hpp index a25cc0c3d..7a4d29e06 100644 --- a/apps/openmw/mwscript/transformationextensions.hpp +++ b/apps/openmw/mwscript/transformationextensions.hpp @@ -20,4 +20,4 @@ namespace MWScript } } -#endif \ No newline at end of file +#endif diff --git a/apps/openmw/mwworld/failedaction.hpp b/apps/openmw/mwworld/failedaction.hpp index c69d62023..f248ee3bd 100644 --- a/apps/openmw/mwworld/failedaction.hpp +++ b/apps/openmw/mwworld/failedaction.hpp @@ -17,4 +17,4 @@ namespace MWWorld }; } -#endif \ No newline at end of file +#endif diff --git a/apps/openmw/mwworld/manualref.cpp b/apps/openmw/mwworld/manualref.cpp index 30b4fe353..b926c5799 100644 --- a/apps/openmw/mwworld/manualref.cpp +++ b/apps/openmw/mwworld/manualref.cpp @@ -64,4 +64,4 @@ MWWorld::ManualRef::ManualRef(const MWWorld::ESMStore& store, const std::string& } mPtr.getRefData().setCount(count); -} \ No newline at end of file +} diff --git a/components/bsa/resources.cpp b/components/bsa/resources.cpp index d06b3b485..b66da1a76 100644 --- a/components/bsa/resources.cpp +++ b/components/bsa/resources.cpp @@ -50,4 +50,4 @@ void Bsa::registerResources (const Files::Collections& collections, throw std::runtime_error(message.str()); } } -} \ No newline at end of file +} diff --git a/components/compiler/extensions0.hpp b/components/compiler/extensions0.hpp index d51507711..83f3a44fa 100644 --- a/components/compiler/extensions0.hpp +++ b/components/compiler/extensions0.hpp @@ -78,4 +78,4 @@ namespace Compiler } } -#endif \ No newline at end of file +#endif diff --git a/components/compiler/nullerrorhandler.cpp b/components/compiler/nullerrorhandler.cpp index 3071701e8..ee2884705 100644 --- a/components/compiler/nullerrorhandler.cpp +++ b/components/compiler/nullerrorhandler.cpp @@ -3,4 +3,4 @@ void Compiler::NullErrorHandler::report (const std::string& message, const TokenLoc& loc, Type type) {} -void Compiler::NullErrorHandler::report (const std::string& message, Type type) {} \ No newline at end of file +void Compiler::NullErrorHandler::report (const std::string& message, Type type) {} diff --git a/components/compiler/opcodes.cpp b/components/compiler/opcodes.cpp index 8617062d6..03081dff9 100644 --- a/components/compiler/opcodes.cpp +++ b/components/compiler/opcodes.cpp @@ -10,4 +10,4 @@ namespace Compiler "playerviewswitch", "vanitymode" }; } -} \ No newline at end of file +} diff --git a/components/compiler/quickfileparser.cpp b/components/compiler/quickfileparser.cpp index f3d8063b2..4e9f76e13 100644 --- a/components/compiler/quickfileparser.cpp +++ b/components/compiler/quickfileparser.cpp @@ -49,4 +49,4 @@ bool Compiler::QuickFileParser::parseSpecial (int code, const TokenLoc& loc, Sca void Compiler::QuickFileParser::parseEOF (Scanner& scanner) { -} \ No newline at end of file +} diff --git a/components/esm/cellid.hpp b/components/esm/cellid.hpp index 40bc552e0..44a1b387a 100644 --- a/components/esm/cellid.hpp +++ b/components/esm/cellid.hpp @@ -28,4 +28,4 @@ namespace ESM bool operator!= (const CellId& left, const CellId& right); } -#endif \ No newline at end of file +#endif diff --git a/components/esm/containerstate.cpp b/components/esm/containerstate.cpp index 5dcf17733..80ad5cbdc 100644 --- a/components/esm/containerstate.cpp +++ b/components/esm/containerstate.cpp @@ -13,4 +13,4 @@ void ESM::ContainerState::save (ESMWriter &esm, bool inInventory) const ObjectState::save (esm, inInventory); mInventory.save (esm); -} \ No newline at end of file +} diff --git a/components/esm/globalscript.cpp b/components/esm/globalscript.cpp index 467fe54a1..0129f8eb7 100644 --- a/components/esm/globalscript.cpp +++ b/components/esm/globalscript.cpp @@ -26,4 +26,4 @@ void ESM::GlobalScript::save (ESMWriter &esm) const esm.writeHNT ("RUN_", mRunning); esm.writeHNOString ("TARG", mTargetId); -} \ No newline at end of file +} diff --git a/components/esm/queststate.cpp b/components/esm/queststate.cpp index e93826725..c8cff7adc 100644 --- a/components/esm/queststate.cpp +++ b/components/esm/queststate.cpp @@ -16,4 +16,4 @@ void ESM::QuestState::save (ESMWriter &esm) const esm.writeHNString ("YETO", mTopic); esm.writeHNT ("QSTA", mState); esm.writeHNT ("QFIN", mFinished); -} \ No newline at end of file +} diff --git a/extern/oics/ICSChannelListener.h b/extern/oics/ICSChannelListener.h index d520b3bce..a202e7e22 100644 --- a/extern/oics/ICSChannelListener.h +++ b/extern/oics/ICSChannelListener.h @@ -43,4 +43,4 @@ namespace ICS } -#endif \ No newline at end of file +#endif diff --git a/extern/oics/ICSControlListener.h b/extern/oics/ICSControlListener.h index 067b2d6f2..97b3940be 100644 --- a/extern/oics/ICSControlListener.h +++ b/extern/oics/ICSControlListener.h @@ -43,4 +43,4 @@ namespace ICS } -#endif \ No newline at end of file +#endif From 37a6d7da761edb862d9a6af8fd0f11e1a9c9e846 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 11 Mar 2015 20:04:25 +0100 Subject: [PATCH 0727/3725] WindowManager refactoring --- apps/openmw/mwbase/windowmanager.hpp | 24 +++---- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 3 - apps/openmw/mwgui/dialogue.cpp | 43 ++----------- apps/openmw/mwgui/hud.cpp | 3 +- apps/openmw/mwgui/inventorywindow.cpp | 10 +-- apps/openmw/mwgui/windowmanagerimp.cpp | 64 +++++++++++++------ apps/openmw/mwgui/windowmanagerimp.hpp | 20 +++--- apps/openmw/mwinput/inputmanagerimp.cpp | 6 +- apps/openmw/mwworld/actionopen.cpp | 5 +- apps/openmw/mwworld/actionrepair.cpp | 1 - 10 files changed, 77 insertions(+), 102 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 2c4cb360d..b43dde4dd 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -149,17 +149,16 @@ namespace MWBase /// \todo investigate, if we really need to expose every single lousy UI element to the outside world virtual MWGui::DialogueWindow* getDialogueWindow() = 0; - virtual MWGui::ContainerWindow* getContainerWindow() = 0; virtual MWGui::InventoryWindow* getInventoryWindow() = 0; virtual MWGui::BookWindow* getBookWindow() = 0; virtual MWGui::ScrollWindow* getScrollWindow() = 0; virtual MWGui::CountDialog* getCountDialog() = 0; virtual MWGui::ConfirmationDialog* getConfirmationDialog() = 0; virtual MWGui::TradeWindow* getTradeWindow() = 0; - virtual MWGui::SpellBuyingWindow* getSpellBuyingWindow() = 0; - virtual MWGui::TravelWindow* getTravelWindow() = 0; - virtual MWGui::SpellWindow* getSpellWindow() = 0; - virtual MWGui::Console* getConsole() = 0; + + virtual void updateSpellWindow() = 0; + + virtual void setConsoleSelectedObject(const MWWorld::Ptr& object) = 0; virtual void wmUpdateFps(float fps, unsigned int triangleCount, unsigned int batchCount) = 0; @@ -181,12 +180,6 @@ namespace MWBase virtual void configureSkills (const SkillList& major, const SkillList& minor) = 0; ///< configure skill groups, each set contains the skill ID for that group. - virtual void setReputation (int reputation) = 0; - ///< set the current reputation value - - virtual void setBounty (int bounty) = 0; - ///< set the current bounty value - virtual void updateSkillArea() = 0; ///< update display of skills, factions, birth sign, reputation and bounty @@ -303,6 +296,10 @@ namespace MWBase virtual void startTraining(MWWorld::Ptr actor) = 0; virtual void startRepair(MWWorld::Ptr actor) = 0; virtual void startRepairItem(MWWorld::Ptr item) = 0; + virtual void startTravel(const MWWorld::Ptr& actor) = 0; + virtual void startSpellBuying(const MWWorld::Ptr& actor) = 0; + virtual void startTrade(const MWWorld::Ptr& actor) = 0; + virtual void openContainer(const MWWorld::Ptr& container, bool loot) = 0; virtual void showSoulgemDialog (MWWorld::Ptr item) = 0; @@ -332,9 +329,8 @@ namespace MWBase /// Does the current stack of GUI-windows permit saving? virtual bool isSavingAllowed() const = 0; - /// Returns the current Modal - /** Used to send exit command to active Modal when Esc is pressed **/ - virtual MWGui::WindowModal* getCurrentModal() const = 0; + /// Send exit command to active Modal window + virtual void exitCurrentModal() = 0; /// Sets the current Modal /** Used to send exit command to active Modal when Esc is pressed **/ diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 00e59e2a5..b928738dd 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -179,10 +179,7 @@ namespace MWDialogue bool isCompanion = !mActor.getClass().getScript(mActor).empty() && mActor.getRefData().getLocals().getIntVar(mActor.getClass().getScript(mActor), "companion"); if (isCompanion) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Companion); MWBase::Environment::get().getWindowManager()->showCompanionWindow(mActor); - } } bool DialogueManager::compile (const std::string& cmd,std::vector& code) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 3bc4292e3..1b07522f3 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -7,12 +7,14 @@ #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/world.hpp" #include "../mwbase/soundmanager.hpp" +#include "../mwbase/dialoguemanager.hpp" #include "../mwmechanics/npcstats.hpp" @@ -20,12 +22,7 @@ #include "../mwworld/containerstore.hpp" #include "../mwworld/esmstore.hpp" -#include "../mwdialogue/dialoguemanagerimp.hpp" - #include "widgets.hpp" -#include "tradewindow.hpp" -#include "spellbuyingwindow.hpp" -#include "travelwindow.hpp" #include "bookpage.hpp" #include "journalbooks.hpp" // to_utf8_span @@ -337,51 +334,25 @@ namespace MWGui MWBase::Environment::get().getWorld()->getStore().get(); if (topic == gmst.find("sPersuasion")->getString()) - { mPersuasionDialog.setVisible(true); - } else if (topic == gmst.find("sCompanionShare")->getString()) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Companion); MWBase::Environment::get().getWindowManager()->showCompanionWindow(mPtr); - } else if (!MWBase::Environment::get().getDialogueManager()->checkServiceRefused()) { if (topic == gmst.find("sBarter")->getString()) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Barter); - MWBase::Environment::get().getWindowManager()->getTradeWindow()->startTrade(mPtr); - } + MWBase::Environment::get().getWindowManager()->startTrade(mPtr); else if (topic == gmst.find("sSpells")->getString()) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_SpellBuying); - MWBase::Environment::get().getWindowManager()->getSpellBuyingWindow()->startSpellBuying(mPtr); - } + MWBase::Environment::get().getWindowManager()->startSpellBuying(mPtr); else if (topic == gmst.find("sTravel")->getString()) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Travel); - MWBase::Environment::get().getWindowManager()->getTravelWindow()->startTravel(mPtr); - } + MWBase::Environment::get().getWindowManager()->startTravel(mPtr); else if (topic == gmst.find("sSpellMakingMenuTitle")->getString()) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_SpellCreation); MWBase::Environment::get().getWindowManager()->startSpellMaking (mPtr); - } else if (topic == gmst.find("sEnchanting")->getString()) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Enchanting); MWBase::Environment::get().getWindowManager()->startEnchanting (mPtr); - } else if (topic == gmst.find("sServiceTrainingTitle")->getString()) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Training); MWBase::Environment::get().getWindowManager()->startTraining (mPtr); - } else if (topic == gmst.find("sRepair")->getString()) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_MerchantRepair); MWBase::Environment::get().getWindowManager()->startRepair (mPtr); - } } } } @@ -440,8 +411,6 @@ namespace MWGui bool isCompanion = !mPtr.getClass().getScript(mPtr).empty() && mPtr.getRefData().getLocals().getIntVar(mPtr.getClass().getScript(mPtr), "companion"); - bool anyService = mServices > 0 || isCompanion || mPtr.getTypeName() == typeid(ESM::NPC).name(); - const MWWorld::Store &gmst = MWBase::Environment::get().getWorld()->getStore().get(); @@ -472,7 +441,7 @@ namespace MWGui if (isCompanion) mTopicsList->addItem(gmst.find("sCompanionShare")->getString()); - if (anyService) + if (mTopicsList->getItemCount() > 0) mTopicsList->addSeparator(); diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 97a113527..eb458be50 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -24,7 +24,6 @@ #include "../mwmechanics/npcstats.hpp" #include "inventorywindow.hpp" -#include "console.hpp" #include "spellicons.hpp" #include "itemmodel.hpp" #include "draganddrop.hpp" @@ -309,7 +308,7 @@ namespace MWGui MWWorld::Ptr object = MWBase::Environment::get().getWorld()->getFacedObject(); if (mode == GM_Console) - MWBase::Environment::get().getWindowManager()->getConsole()->setSelectedObject(object); + MWBase::Environment::get().getWindowManager()->setConsoleSelectedObject(object); else if ((mode == GM_Container) || (mode == GM_Inventory)) { // pick up object diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 919228195..a94df0b01 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -25,7 +25,6 @@ #include "bookwindow.hpp" #include "scrollwindow.hpp" -#include "spellwindow.hpp" #include "itemview.hpp" #include "inventoryitemmodel.hpp" #include "sortfilteritemmodel.hpp" @@ -317,8 +316,7 @@ namespace MWGui void InventoryWindow::updateItemView() { - if (MWBase::Environment::get().getWindowManager()->getSpellWindow()) - MWBase::Environment::get().getWindowManager()->getSpellWindow()->updateSpells(); + MWBase::Environment::get().getWindowManager()->updateSpellWindow(); mItemView->update(); mPreviewDirty = true; @@ -568,8 +566,7 @@ namespace MWGui void InventoryWindow::notifyContentChanged() { // update the spell window just in case new enchanted items were added to inventory - if (MWBase::Environment::get().getWindowManager()->getSpellWindow()) - MWBase::Environment::get().getWindowManager()->getSpellWindow()->updateSpells(); + MWBase::Environment::get().getWindowManager()->updateSpellWindow(); MWBase::Environment::get().getMechanicsManager()->updateMagicEffects( MWBase::Environment::get().getWorld()->getPlayerPtr()); @@ -626,8 +623,7 @@ namespace MWGui MWBase::Environment::get().getMechanicsManager()->itemTaken(player, newObject, MWWorld::Ptr(), count); - if (MWBase::Environment::get().getWindowManager()->getSpellWindow()) - MWBase::Environment::get().getWindowManager()->getSpellWindow()->updateSpells(); + MWBase::Environment::get().getWindowManager()->updateSpellWindow(); } void InventoryWindow::cycle(bool next) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 815f342a4..fddc92dc1 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -715,16 +715,6 @@ namespace MWGui mPlayerMinorSkills = minor; } - void WindowManager::setReputation (int reputation) - { - mStatsWindow->setReputation (reputation); - } - - void WindowManager::setBounty (int bounty) - { - mStatsWindow->setBounty (bounty); - } - void WindowManager::updateSkillArea() { mStatsWindow->updateSkillArea(); @@ -1287,17 +1277,12 @@ namespace MWGui } MWGui::DialogueWindow* WindowManager::getDialogueWindow() { return mDialogueWindow; } - MWGui::ContainerWindow* WindowManager::getContainerWindow() { return mContainerWindow; } MWGui::InventoryWindow* WindowManager::getInventoryWindow() { return mInventoryWindow; } MWGui::BookWindow* WindowManager::getBookWindow() { return mBookWindow; } MWGui::ScrollWindow* WindowManager::getScrollWindow() { return mScrollWindow; } MWGui::CountDialog* WindowManager::getCountDialog() { return mCountDialog; } MWGui::ConfirmationDialog* WindowManager::getConfirmationDialog() { return mConfirmationDialog; } MWGui::TradeWindow* WindowManager::getTradeWindow() { return mTradeWindow; } - MWGui::SpellBuyingWindow* WindowManager::getSpellBuyingWindow() { return mSpellBuyingWindow; } - MWGui::TravelWindow* WindowManager::getTravelWindow() { return mTravelWindow; } - MWGui::SpellWindow* WindowManager::getSpellWindow() { return mSpellWindow; } - MWGui::Console* WindowManager::getConsole() { return mConsole; } bool WindowManager::isAllowed (GuiWindow wnd) const { @@ -1459,11 +1444,13 @@ namespace MWGui void WindowManager::startSpellMaking(MWWorld::Ptr actor) { + pushGuiMode(GM_SpellCreation); mSpellCreationDialog->startSpellMaking (actor); } void WindowManager::startEnchanting (MWWorld::Ptr actor) { + pushGuiMode(GM_Enchanting); mEnchantingDialog->startEnchanting (actor); } @@ -1474,16 +1461,19 @@ namespace MWGui void WindowManager::startTraining(MWWorld::Ptr actor) { + pushGuiMode(GM_Training); mTrainingWindow->startTraining(actor); } void WindowManager::startRepair(MWWorld::Ptr actor) { + pushGuiMode(GM_MerchantRepair); mMerchantRepair->startRepair(actor); } void WindowManager::startRepairItem(MWWorld::Ptr item) { + pushGuiMode(MWGui::GM_Repair); mRepair->startRepairItem(item); } @@ -1494,6 +1484,7 @@ namespace MWGui void WindowManager::showCompanionWindow(MWWorld::Ptr actor) { + pushGuiMode(MWGui::GM_Companion); mCompanionWindow->open(actor); } @@ -1744,12 +1735,10 @@ namespace MWGui mVideoWidget->autoResize(stretch); } - WindowModal* WindowManager::getCurrentModal() const + void WindowManager::exitCurrentModal() { - if(!mCurrentModals.empty()) - return mCurrentModals.top(); - else - return NULL; + if (!mCurrentModals.empty()) + mCurrentModals.top()->exit(); } void WindowManager::removeCurrentModal(WindowModal* input) @@ -1874,4 +1863,39 @@ namespace MWGui mInventoryWindow->cycle(next); } + void WindowManager::setConsoleSelectedObject(const MWWorld::Ptr &object) + { + mConsole->setSelectedObject(object); + } + + void WindowManager::updateSpellWindow() + { + if (mSpellWindow) + mSpellWindow->updateSpells(); + } + + void WindowManager::startTravel(const MWWorld::Ptr &actor) + { + pushGuiMode(GM_Travel); + mTravelWindow->startTravel(actor); + } + + void WindowManager::startSpellBuying(const MWWorld::Ptr &actor) + { + pushGuiMode(GM_SpellBuying); + mSpellBuyingWindow->startSpellBuying(actor); + } + + void WindowManager::startTrade(const MWWorld::Ptr &actor) + { + pushGuiMode(GM_Barter); + mTradeWindow->startTrade(actor); + } + + void WindowManager::openContainer(const MWWorld::Ptr &container, bool loot) + { + pushGuiMode(GM_Container); + mContainerWindow->open(container, loot); + } + } diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index fbbc295b3..66125d4d0 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -154,17 +154,16 @@ namespace MWGui /// \todo investigate, if we really need to expose every single lousy UI element to the outside world virtual MWGui::DialogueWindow* getDialogueWindow(); - virtual MWGui::ContainerWindow* getContainerWindow(); virtual MWGui::InventoryWindow* getInventoryWindow(); virtual MWGui::BookWindow* getBookWindow(); virtual MWGui::ScrollWindow* getScrollWindow(); virtual MWGui::CountDialog* getCountDialog(); virtual MWGui::ConfirmationDialog* getConfirmationDialog(); virtual MWGui::TradeWindow* getTradeWindow(); - virtual MWGui::SpellBuyingWindow* getSpellBuyingWindow(); - virtual MWGui::TravelWindow* getTravelWindow(); - virtual MWGui::SpellWindow* getSpellWindow(); - virtual MWGui::Console* getConsole(); + + virtual void updateSpellWindow(); + + virtual void setConsoleSelectedObject(const MWWorld::Ptr& object); virtual void wmUpdateFps(float fps, unsigned int triangleCount, unsigned int batchCount); @@ -182,8 +181,6 @@ namespace MWGui virtual void setPlayerClass (const ESM::Class &class_); ///< set current class of player virtual void configureSkills (const SkillList& major, const SkillList& minor); ///< configure skill groups, each set contains the skill ID for that group. - virtual void setReputation (int reputation); ///< set the current reputation value - virtual void setBounty (int bounty); ///< set the current bounty value virtual void updateSkillArea(); ///< update display of skills, factions, birth sign, reputation and bounty virtual void changeCell(MWWorld::CellStore* cell); ///< change the active cell @@ -292,6 +289,10 @@ namespace MWGui virtual void startRepair(MWWorld::Ptr actor); virtual void startRepairItem(MWWorld::Ptr item); virtual void startRecharge(MWWorld::Ptr soulgem); + virtual void startTravel(const MWWorld::Ptr& actor); + virtual void startSpellBuying(const MWWorld::Ptr &actor); + virtual void startTrade(const MWWorld::Ptr &actor); + virtual void openContainer(const MWWorld::Ptr &container, bool loot); virtual void frameStarted(float dt); @@ -317,9 +318,8 @@ namespace MWGui /// Does the current stack of GUI-windows permit saving? virtual bool isSavingAllowed() const; - /// Returns the current Modal - /** Used to send exit command to active Modal when Esc is pressed **/ - virtual WindowModal* getCurrentModal() const; + /// Send exit command to active Modal window **/ + virtual void exitCurrentModal(); /// Sets the current Modal /** Used to send exit command to active Modal when Esc is pressed **/ diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 21576785c..355594204 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -33,8 +33,6 @@ #include "../mwdialogue/dialoguemanagerimp.hpp" -#include "../mwgui/windowbase.hpp" - #include using namespace ICS; @@ -887,7 +885,7 @@ namespace MWInput void InputManager::toggleMainMenu() { if (MyGUI::InputManager::getInstance().isModalAny()) { - MWBase::Environment::get().getWindowManager()->getCurrentModal()->exit(); + MWBase::Environment::get().getWindowManager()->exitCurrentModal(); return; } @@ -1061,7 +1059,7 @@ namespace MWInput } else if (MWBase::Environment::get().getWindowManager()->getMode () == MWGui::GM_QuickKeysMenu) { while(MyGUI::InputManager::getInstance().isModalAny()) { //Handle any open Modal windows - MWBase::Environment::get().getWindowManager()->getCurrentModal()->exit(); + MWBase::Environment::get().getWindowManager()->exitCurrentModal(); } MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode(); //And handle the actual main window } diff --git a/apps/openmw/mwworld/actionopen.cpp b/apps/openmw/mwworld/actionopen.cpp index e9d8b4716..0df451b18 100644 --- a/apps/openmw/mwworld/actionopen.cpp +++ b/apps/openmw/mwworld/actionopen.cpp @@ -3,8 +3,6 @@ #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" -#include "../mwgui/container.hpp" - #include "../mwmechanics/disease.hpp" #include "class.hpp" @@ -25,7 +23,6 @@ namespace MWWorld MWMechanics::diseaseContact(actor, getTarget()); - MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Container); - MWBase::Environment::get().getWindowManager()->getContainerWindow()->open(getTarget(), mLoot); + MWBase::Environment::get().getWindowManager()->openContainer(getTarget(), mLoot); } } diff --git a/apps/openmw/mwworld/actionrepair.cpp b/apps/openmw/mwworld/actionrepair.cpp index a86dc38b1..699440a01 100644 --- a/apps/openmw/mwworld/actionrepair.cpp +++ b/apps/openmw/mwworld/actionrepair.cpp @@ -19,7 +19,6 @@ namespace MWWorld return; } - MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Repair); MWBase::Environment::get().getWindowManager()->startRepairItem(getTarget()); } } From 48ea6286fd7b5ba08f3235d594a9f8ff5b5423ed Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 11 Mar 2015 20:33:55 +0100 Subject: [PATCH 0728/3725] Book/scroll window refactoring --- apps/openmw/mwbase/windowmanager.hpp | 4 ++-- apps/openmw/mwgui/bookwindow.cpp | 4 ++-- apps/openmw/mwgui/bookwindow.hpp | 9 +++++---- apps/openmw/mwgui/inventorywindow.cpp | 9 --------- apps/openmw/mwgui/scrollwindow.cpp | 4 ++-- apps/openmw/mwgui/scrollwindow.hpp | 4 ++-- apps/openmw/mwgui/windowmanagerimp.cpp | 14 ++++++++++++-- apps/openmw/mwgui/windowmanagerimp.hpp | 4 ++-- apps/openmw/mwworld/actionread.cpp | 22 ++++++---------------- 9 files changed, 33 insertions(+), 41 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index b43dde4dd..fdd51ef44 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -150,8 +150,6 @@ namespace MWBase /// \todo investigate, if we really need to expose every single lousy UI element to the outside world virtual MWGui::DialogueWindow* getDialogueWindow() = 0; virtual MWGui::InventoryWindow* getInventoryWindow() = 0; - virtual MWGui::BookWindow* getBookWindow() = 0; - virtual MWGui::ScrollWindow* getScrollWindow() = 0; virtual MWGui::CountDialog* getCountDialog() = 0; virtual MWGui::ConfirmationDialog* getConfirmationDialog() = 0; virtual MWGui::TradeWindow* getTradeWindow() = 0; @@ -300,6 +298,8 @@ namespace MWBase virtual void startSpellBuying(const MWWorld::Ptr& actor) = 0; virtual void startTrade(const MWWorld::Ptr& actor) = 0; virtual void openContainer(const MWWorld::Ptr& container, bool loot) = 0; + virtual void showBook(const MWWorld::Ptr& item, bool showTakeButton) = 0; + virtual void showScroll(const MWWorld::Ptr& item, bool showTakeButton) = 0; virtual void showSoulgemDialog (MWWorld::Ptr item) = 0; diff --git a/apps/openmw/mwgui/bookwindow.cpp b/apps/openmw/mwgui/bookwindow.cpp index da0d1950e..55a9b6191 100644 --- a/apps/openmw/mwgui/bookwindow.cpp +++ b/apps/openmw/mwgui/bookwindow.cpp @@ -73,7 +73,7 @@ namespace MWGui mPages.clear(); } - void BookWindow::open (MWWorld::Ptr book) + void BookWindow::open (MWWorld::Ptr book, bool showTakeButton) { mBook = book; @@ -90,7 +90,7 @@ namespace MWGui updatePages(); - setTakeButtonShow(true); + setTakeButtonShow(showTakeButton); } void BookWindow::exit() diff --git a/apps/openmw/mwgui/bookwindow.hpp b/apps/openmw/mwgui/bookwindow.hpp index ea3057a6f..8ad4f6830 100644 --- a/apps/openmw/mwgui/bookwindow.hpp +++ b/apps/openmw/mwgui/bookwindow.hpp @@ -16,10 +16,7 @@ namespace MWGui virtual void exit(); - void open(MWWorld::Ptr book); - void setTakeButtonShow(bool show); - void nextPage(); - void prevPage(); + void open(MWWorld::Ptr book, bool showTakeButton); void setInventoryAllowed(bool allowed); protected: @@ -28,6 +25,10 @@ namespace MWGui void onCloseButtonClicked (MyGUI::Widget* sender); void onTakeButtonClicked (MyGUI::Widget* sender); void onMouseWheel(MyGUI::Widget* _sender, int _rel); + void setTakeButtonShow(bool show); + + void nextPage(); + void prevPage(); void updatePages(); void clearPages(); diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index a94df0b01..80b246e84 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -23,8 +23,6 @@ #include "../mwbase/scriptmanager.hpp" #include "../mwrender/characterpreview.hpp" -#include "bookwindow.hpp" -#include "scrollwindow.hpp" #include "itemview.hpp" #include "inventoryitemmodel.hpp" #include "sortfilteritemmodel.hpp" @@ -430,13 +428,6 @@ namespace MWGui action->execute (MWBase::Environment::get().getWorld()->getPlayerPtr()); - // this is necessary for books/scrolls: if they are already in the player's inventory, - // the "Take" button should not be visible. - // NOTE: the take button is "reset" when the window opens, so we can safely do the following - // without screwing up future book windows - MWBase::Environment::get().getWindowManager()->getBookWindow()->setTakeButtonShow(false); - MWBase::Environment::get().getWindowManager()->getScrollWindow()->setTakeButtonShow(false); - mSkippedToEquip = MWWorld::Ptr(); } else diff --git a/apps/openmw/mwgui/scrollwindow.cpp b/apps/openmw/mwgui/scrollwindow.cpp index d61693d39..85d1c8c4e 100644 --- a/apps/openmw/mwgui/scrollwindow.cpp +++ b/apps/openmw/mwgui/scrollwindow.cpp @@ -48,7 +48,7 @@ namespace MWGui center(); } - void ScrollWindow::open (MWWorld::Ptr scroll) + void ScrollWindow::open (MWWorld::Ptr scroll, bool showTakeButton) { // no 3d sounds because the object could be in a container. MWBase::Environment::get().getSoundManager()->playSound ("scroll", 1.0, 1.0); @@ -71,7 +71,7 @@ namespace MWGui mTextView->setViewOffset(MyGUI::IntPoint(0,0)); - setTakeButtonShow(true); + setTakeButtonShow(showTakeButton); } void ScrollWindow::exit() diff --git a/apps/openmw/mwgui/scrollwindow.hpp b/apps/openmw/mwgui/scrollwindow.hpp index e1f86529a..3c9e718b6 100644 --- a/apps/openmw/mwgui/scrollwindow.hpp +++ b/apps/openmw/mwgui/scrollwindow.hpp @@ -17,14 +17,14 @@ namespace MWGui public: ScrollWindow (); - void open (MWWorld::Ptr scroll); + void open (MWWorld::Ptr scroll, bool showTakeButton); virtual void exit(); - void setTakeButtonShow(bool show); void setInventoryAllowed(bool allowed); protected: void onCloseButtonClicked (MyGUI::Widget* _sender); void onTakeButtonClicked (MyGUI::Widget* _sender); + void setTakeButtonShow(bool show); private: Gui::ImageButton* mCloseButton; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index fddc92dc1..279c2f22e 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1278,8 +1278,6 @@ namespace MWGui MWGui::DialogueWindow* WindowManager::getDialogueWindow() { return mDialogueWindow; } MWGui::InventoryWindow* WindowManager::getInventoryWindow() { return mInventoryWindow; } - MWGui::BookWindow* WindowManager::getBookWindow() { return mBookWindow; } - MWGui::ScrollWindow* WindowManager::getScrollWindow() { return mScrollWindow; } MWGui::CountDialog* WindowManager::getCountDialog() { return mCountDialog; } MWGui::ConfirmationDialog* WindowManager::getConfirmationDialog() { return mConfirmationDialog; } MWGui::TradeWindow* WindowManager::getTradeWindow() { return mTradeWindow; } @@ -1898,4 +1896,16 @@ namespace MWGui mContainerWindow->open(container, loot); } + void WindowManager::showBook(const MWWorld::Ptr &item, bool showTakeButton) + { + pushGuiMode(GM_Book); + mBookWindow->open(item, showTakeButton); + } + + void WindowManager::showScroll(const MWWorld::Ptr &item, bool showTakeButton) + { + pushGuiMode(GM_Scroll); + mScrollWindow->open(item, showTakeButton); + } + } diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 66125d4d0..297480d20 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -155,8 +155,6 @@ namespace MWGui /// \todo investigate, if we really need to expose every single lousy UI element to the outside world virtual MWGui::DialogueWindow* getDialogueWindow(); virtual MWGui::InventoryWindow* getInventoryWindow(); - virtual MWGui::BookWindow* getBookWindow(); - virtual MWGui::ScrollWindow* getScrollWindow(); virtual MWGui::CountDialog* getCountDialog(); virtual MWGui::ConfirmationDialog* getConfirmationDialog(); virtual MWGui::TradeWindow* getTradeWindow(); @@ -293,6 +291,8 @@ namespace MWGui virtual void startSpellBuying(const MWWorld::Ptr &actor); virtual void startTrade(const MWWorld::Ptr &actor); virtual void openContainer(const MWWorld::Ptr &container, bool loot); + virtual void showBook(const MWWorld::Ptr& item, bool showTakeButton); + virtual void showScroll(const MWWorld::Ptr& item, bool showTakeButton); virtual void frameStarted(float dt); diff --git a/apps/openmw/mwworld/actionread.cpp b/apps/openmw/mwworld/actionread.cpp index 0a4e2d6c9..cd0471a0e 100644 --- a/apps/openmw/mwworld/actionread.cpp +++ b/apps/openmw/mwworld/actionread.cpp @@ -4,13 +4,8 @@ #include "../mwbase/windowmanager.hpp" #include "../mwbase/world.hpp" -#include "../mwworld/player.hpp" - #include "../mwmechanics/npcstats.hpp" -#include "../mwgui/bookwindow.hpp" -#include "../mwgui/scrollwindow.hpp" - #include "player.hpp" #include "class.hpp" #include "esmstore.hpp" @@ -33,27 +28,22 @@ namespace MWWorld return; } + bool showTakeButton = (getTarget().getContainerStore() != &actor.getClass().getContainerStore(actor)); + LiveCellRef *ref = getTarget().get(); if (ref->mBase->mData.mIsScroll) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Scroll); - MWBase::Environment::get().getWindowManager()->getScrollWindow()->open(getTarget()); - } + MWBase::Environment::get().getWindowManager()->showScroll(getTarget(), showTakeButton); else - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Book); - MWBase::Environment::get().getWindowManager()->getBookWindow()->open(getTarget()); - } + MWBase::Environment::get().getWindowManager()->showBook(getTarget(), showTakeButton); - MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayerPtr(); - MWMechanics::NpcStats& npcStats = player.getClass().getNpcStats (player); + MWMechanics::NpcStats& npcStats = actor.getClass().getNpcStats (actor); // Skill gain from books if (ref->mBase->mData.mSkillID >= 0 && ref->mBase->mData.mSkillID < ESM::Skill::Length && !npcStats.hasBeenUsed (ref->mBase->mId)) { - MWWorld::LiveCellRef *playerRef = player.get(); + MWWorld::LiveCellRef *playerRef = actor.get(); const ESM::Class *class_ = MWBase::Environment::get().getWorld()->getStore().get().find ( From 68de87605126fccb4dd816f960c2efc8d4738d96 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 11 Mar 2015 21:12:08 +0100 Subject: [PATCH 0729/3725] Switch to weapon drawstate when creating a bound weapon (Fixes #2387) --- apps/openmw/mwmechanics/actors.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index ca4105bc6..23bd1ea6a 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -54,9 +54,17 @@ void adjustBoundItem (const std::string& item, bool bound, const MWWorld::Ptr& a { if (actor.getClass().getContainerStore(actor).count(item) == 0) { - MWWorld::Ptr newPtr = *actor.getClass().getContainerStore(actor).add(item, 1, actor); + MWWorld::InventoryStore& store = actor.getClass().getInventoryStore(actor); + MWWorld::Ptr newPtr = *store.MWWorld::ContainerStore::add(item, 1, actor); MWWorld::ActionEquip action(newPtr); action.execute(actor); + MWWorld::ContainerStoreIterator rightHand = store.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); + // change draw state only if the item is in player's right hand + if (actor == MWBase::Environment::get().getWorld()->getPlayerPtr() + && rightHand != store.end() && newPtr == *rightHand) + { + MWBase::Environment::get().getWorld()->getPlayer().setDrawState(MWMechanics::DrawState_Weapon); + } } } else From dc9af19dcfbb075cfbafcb741adbd4fb6964c2b7 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Thu, 12 Mar 2015 08:28:26 +1100 Subject: [PATCH 0730/3725] Don't use C++11 features. --- apps/opencs/model/world/record.hpp | 31 +++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/world/record.hpp b/apps/opencs/model/world/record.hpp index 1cf14a8f9..6ff33f0c2 100644 --- a/apps/opencs/model/world/record.hpp +++ b/apps/opencs/model/world/record.hpp @@ -40,9 +40,9 @@ namespace CSMWorld ESXRecordT mBase; ESXRecordT mModified; - Record() = default; - Record(const Record&) = default; - Record& operator= (const Record&) = default; + Record(); + Record(const Record& record); + Record& operator= (const Record& record); Record(State state, const ESXRecordT *base = 0, const ESXRecordT *modified = 0); @@ -69,6 +69,31 @@ namespace CSMWorld ///< Merge modified into base. }; + template + Record::Record() + : mBase(), mModified() + { } + + template + Record::Record(const Record& record) + : mBase(record.mBase), mModified(record.mModified) + { + mState = record.mState; + } + + template + Record& Record::operator= (const Record& record) + { + if(this != &record) + { + mBase = record.mBase; + mModified = record.mModified; + mState = record.mState; + } + + return *this; + } + template Record::Record(State state, const ESXRecordT *base, const ESXRecordT *modified) { From 3879ce6ac168b942bfd6e894983c9baadd48b288 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 11 Mar 2015 23:07:39 +0100 Subject: [PATCH 0731/3725] Get rid of "player" string checks (Fixes #2216) --- apps/openmw/mwclass/creature.cpp | 2 +- apps/openmw/mwclass/npc.cpp | 14 +++++------ apps/openmw/mwmechanics/actors.cpp | 15 ++++++------ apps/openmw/mwmechanics/character.cpp | 16 ++++++------- apps/openmw/mwmechanics/combat.cpp | 8 +++---- apps/openmw/mwmechanics/spellcasting.cpp | 24 +++++++++---------- apps/openmw/mwrender/renderingmanager.cpp | 4 ++-- apps/openmw/mwscript/containerextensions.cpp | 2 +- .../mwscript/transformationextensions.cpp | 8 +++---- apps/openmw/mwsound/soundmanagerimp.cpp | 2 +- apps/openmw/mwworld/action.cpp | 2 +- apps/openmw/mwworld/containerstore.cpp | 2 +- apps/openmw/mwworld/failedaction.cpp | 2 +- apps/openmw/mwworld/inventorystore.cpp | 6 ++--- apps/openmw/mwworld/worldimp.cpp | 10 ++++---- 15 files changed, 59 insertions(+), 58 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index ace4949ed..9a3c6c218 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -355,7 +355,7 @@ namespace MWClass if(!object.isEmpty()) getCreatureStats(ptr).setLastHitObject(object.getClass().getId(object)); - if(setOnPcHitMe && !attacker.isEmpty() && attacker.getRefData().getHandle() == "player") + if(setOnPcHitMe && !attacker.isEmpty() && attacker == MWBase::Environment::get().getWorld()->getPlayerPtr()) { const std::string &script = ptr.get()->mBase->mScript; /* Set the OnPCHitMe script variable. The script is responsible for clearing it. */ diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index c62257572..deb4b90cd 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -507,7 +507,7 @@ namespace MWClass if(otherstats.isDead()) // Can't hit dead actors return; - if(ptr.getRefData().getHandle() == "player") + if(ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) MWBase::Environment::get().getWindowManager()->setEnemy(victim); int weapskill = ESM::Skill::HandToHand; @@ -549,7 +549,7 @@ namespace MWClass { MWMechanics::getHandToHandDamage(ptr, victim, damage, healthdmg); } - if(ptr.getRefData().getHandle() == "player") + if(ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) { skillUsageSucceeded(ptr, weapskill, 0); @@ -625,7 +625,7 @@ namespace MWClass if(!object.isEmpty()) getCreatureStats(ptr).setLastHitObject(object.getClass().getId(object)); - if(setOnPcHitMe && !attacker.isEmpty() && attacker.getRefData().getHandle() == "player") + if(setOnPcHitMe && !attacker.isEmpty() && attacker == MWBase::Environment::get().getWorld()->getPlayerPtr()) { const std::string &script = ptr.getClass().getScript(ptr); /* Set the OnPCHitMe script variable. The script is responsible for clearing it. */ @@ -708,7 +708,7 @@ namespace MWClass if (armorhealth == 0) armor = *inv.unequipItem(armor, ptr); - if (ptr.getRefData().getHandle() == "player") + if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) skillUsageSucceeded(ptr, armor.getClass().getEquipmentSkill(armor), 0); switch(armor.getClass().getEquipmentSkill(armor)) @@ -724,7 +724,7 @@ namespace MWClass break; } } - else if(ptr.getRefData().getHandle() == "player") + else if(ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) skillUsageSucceeded(ptr, ESM::Skill::Unarmored, 0); } } @@ -737,7 +737,7 @@ namespace MWClass if(damage > 0.0f) { sndMgr->playSound3D(ptr, "Health Damage", 1.0f, 1.0f); - if (ptr.getRefData().getHandle() == "player") + if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) MWBase::Environment::get().getWindowManager()->activateHitOverlay(); } float health = getCreatureStats(ptr).getHealth().getCurrent() - damage; @@ -815,7 +815,7 @@ namespace MWClass const MWWorld::Ptr& actor) const { // player got activated by another NPC - if(ptr.getRefData().getHandle() == "player") + if(ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) return boost::shared_ptr(new MWWorld::ActionTalk(actor)); // Werewolfs can't activate NPCs diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 23bd1ea6a..c25e207c6 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -99,7 +99,7 @@ bool disintegrateSlot (MWWorld::Ptr ptr, int slot, float disintegrate) if (charge == 0) { // Will unequip the broken item and try to find a replacement - if (ptr.getRefData().getHandle() != "player") + if (ptr != MWBase::Environment::get().getWorld()->getPlayerPtr()) inv.autoEquip(ptr); else inv.unequipItem(*item, ptr); @@ -154,6 +154,7 @@ void adjustCommandedActor (const MWWorld::Ptr& actor) if (check.mCommanded && !hasCommandPackage) { + // FIXME: don't use refid string MWMechanics::AiFollow package("player", true); stats.getAiSequence().stack(package, actor); } @@ -244,7 +245,7 @@ namespace MWMechanics gem->getContainerStore()->unstack(*gem, caster); gem->getCellRef().setSoul(mCreature.getCellRef().getRefId()); - if (caster.getRefData().getHandle() == "player") + if (caster == MWBase::Environment::get().getWorld()->getPlayerPtr()) MWBase::Environment::get().getWindowManager()->messageBox("#{sSoultrapSuccess}"); const ESM::Static* fx = MWBase::Environment::get().getWorld()->getStore().get() @@ -433,7 +434,7 @@ namespace MWMechanics int intelligence = creatureStats.getAttribute(ESM::Attribute::Intelligence).getModified(); float base = 1.f; - if (ptr.getCellRef().getRefId() == "player") + if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) base = MWBase::Environment::get().getWorld()->getStore().get().find("fPCbaseMagickaMult")->getFloat(); else base = MWBase::Environment::get().getWorld()->getStore().get().find("fNPCbaseMagickaMult")->getFloat(); @@ -543,7 +544,7 @@ namespace MWMechanics { spells.worsenCorprus(it->first); - if (ptr.getRefData().getHandle() == "player") + if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicCorprusWorsens}"); } } @@ -665,7 +666,7 @@ namespace MWMechanics } } - if (receivedMagicDamage && ptr.getRefData().getHandle() == "player") + if (receivedMagicDamage && ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) MWBase::Environment::get().getWindowManager()->activateHitOverlay(false); creatureStats.setHealth(health); @@ -848,7 +849,7 @@ namespace MWMechanics void Actors::updateEquippedLight (const MWWorld::Ptr& ptr, float duration) { - bool isPlayer = ptr.getRefData().getHandle()=="player"; + bool isPlayer = (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()); MWWorld::InventoryStore &inventoryStore = ptr.getClass().getInventoryStore(ptr); MWWorld::ContainerStoreIterator heldIter = @@ -1157,7 +1158,7 @@ namespace MWMechanics // Handle player last, in case a cell transition occurs by casting a teleportation spell // (would invalidate the iterator) - if (iter->first.getCellRef().getRefId() == "player") + if (iter->first == MWBase::Environment::get().getWorld()->getPlayerPtr()) { playerCharacter = iter->second->getCharacterController(); continue; diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index c8834e095..28028500a 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1010,7 +1010,7 @@ bool CharacterController::updateWeaponState() // For the player, set the spell we want to cast // This has to be done at the start of the casting animation, // *not* when selecting a spell in the GUI (otherwise you could change the spell mid-animation) - if (mPtr.getRefData().getHandle() == "player") + if (mPtr == MWBase::Environment::get().getWorld()->getPlayerPtr()) { std::string selectedSpell = MWBase::Environment::get().getWindowManager()->getSelectedSpell(); stats.getSpells().setSelectedSpell(selectedSpell); @@ -1094,7 +1094,7 @@ bool CharacterController::updateWeaponState() mAttackType = "shoot"; else { - if(isWeapon && mPtr.getRefData().getHandle() == "player" && + if(isWeapon && mPtr == MWBase::Environment::get().getWorld()->getPlayerPtr() && Settings::Manager::getBool("best attack", "Game")) { MWWorld::ContainerStoreIterator weapon = mPtr.getClass().getInventoryStore(mPtr).getSlot(MWWorld::InventoryStore::Slot_CarriedRight); @@ -1421,7 +1421,7 @@ void CharacterController::update(float duration) // advance athletics - if(mHasMovedInXY && mPtr.getRefData().getHandle() == "player") + if(mHasMovedInXY && mPtr == MWBase::Environment::get().getWorld()->getPlayerPtr()) { if(inwater) { @@ -1521,7 +1521,7 @@ void CharacterController::update(float duration) } // advance acrobatics - if (mPtr.getRefData().getHandle() == "player") + if (mPtr == MWBase::Environment::get().getWorld()->getPlayerPtr()) cls.skillUsageSucceeded(mPtr, ESM::Skill::Acrobatics, 0); // decrease fatigue @@ -1564,7 +1564,7 @@ void CharacterController::update(float duration) else { // report acrobatics progression - if (mPtr.getRefData().getHandle() == "player") + if (mPtr == MWBase::Environment::get().getWorld()->getPlayerPtr()) cls.skillUsageSucceeded(mPtr, ESM::Skill::Acrobatics, 1); } } @@ -1797,7 +1797,7 @@ bool CharacterController::kill() { if( isDead() ) { - if( mPtr.getRefData().getHandle()=="player" && !isAnimPlaying(mCurrentDeath) ) + if( mPtr == MWBase::Environment::get().getWorld()->getPlayerPtr() && !isAnimPlaying(mCurrentDeath) ) { //player's death animation is over MWBase::Environment::get().getStateManager()->askLoadRecent(); @@ -1813,7 +1813,7 @@ bool CharacterController::kill() mCurrentIdle.clear(); // Play Death Music if it was the player dying - if(mPtr.getRefData().getHandle()=="player") + if(mPtr == MWBase::Environment::get().getWorld()->getPlayerPtr()) MWBase::Environment::get().getSoundManager()->streamMusic("Special/MW_Death.mp3"); return true; @@ -1854,7 +1854,7 @@ void CharacterController::updateMagicEffects() float alpha = 1.f; if (mPtr.getClass().getCreatureStats(mPtr).getMagicEffects().get(ESM::MagicEffect::Invisibility).getMagnitude()) { - if (mPtr.getRefData().getHandle() == "player") + if (mPtr == MWBase::Environment::get().getWorld()->getPlayerPtr()) alpha = 0.4f; else alpha = 0.f; diff --git a/apps/openmw/mwmechanics/combat.cpp b/apps/openmw/mwmechanics/combat.cpp index 42380664b..b8ffa63e2 100644 --- a/apps/openmw/mwmechanics/combat.cpp +++ b/apps/openmw/mwmechanics/combat.cpp @@ -133,7 +133,7 @@ namespace MWMechanics blockerStats.setBlock(true); - if (blocker.getCellRef().getRefId() == "player") + if (blocker == MWBase::Environment::get().getWorld()->getPlayerPtr()) blocker.getClass().skillUsageSucceeded(blocker, ESM::Skill::Block, 0); return true; @@ -157,7 +157,7 @@ namespace MWMechanics && actor.getClass().isNpc() && actor.getClass().getNpcStats(actor).isWerewolf()) damage *= MWBase::Environment::get().getWorld()->getStore().get().find("fWereWolfSilverWeaponDamageMult")->getFloat(); - if (damage == 0 && attacker.getRefData().getHandle() == "player") + if (damage == 0 && attacker == MWBase::Environment::get().getWorld()->getPlayerPtr()) MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicTargetResistsWeapons}"); } @@ -176,7 +176,7 @@ namespace MWMechanics return; } - if(attacker.getRefData().getHandle() == "player") + if(attacker == MWBase::Environment::get().getWorld()->getPlayerPtr()) MWBase::Environment::get().getWindowManager()->setEnemy(victim); int weapskill = ESM::Skill::Marksman; @@ -211,7 +211,7 @@ namespace MWMechanics adjustWeaponDamage(damage, weapon); reduceWeaponCondition(damage, true, weapon, attacker); - if(attacker.getRefData().getHandle() == "player") + if(attacker == MWBase::Environment::get().getWorld()->getPlayerPtr()) attacker.getClass().skillUsageSucceeded(attacker, weapskill, 0); if (victim.getClass().getCreatureStats(victim).getKnockedDown()) diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 3ca30977b..590c8fe83 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -180,7 +180,7 @@ namespace MWMechanics int actorLuck = stats.getAttribute(ESM::Attribute::Luck).getModified(); float castChance = (lowestSkill - spell->mData.mCost + castBonus + 0.2f * actorWillpower + 0.1f * actorLuck) * stats.getFatigueTerm(); - if (MWBase::Environment::get().getWorld()->getGodModeState() && actor.getRefData().getHandle() == "player") + if (MWBase::Environment::get().getWorld()->getGodModeState() && actor == MWBase::Environment::get().getWorld()->getPlayerPtr()) castChance = 100; if (!cap) @@ -387,7 +387,7 @@ namespace MWMechanics if (roll <= x) { // Fully resisted, show message - if (target.getRefData().getHandle() == "player") + if (target == MWBase::Environment::get().getWorld()->getPlayerPtr()) MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicPCResisted}"); return; } @@ -405,7 +405,7 @@ namespace MWMechanics if (target.getClass().isActor()) targetEffects += target.getClass().getCreatureStats(target).getMagicEffects(); - bool castByPlayer = (!caster.isEmpty() && caster.getRefData().getHandle() == "player"); + bool castByPlayer = (!caster.isEmpty() && caster == MWBase::Environment::get().getWorld()->getPlayerPtr()); // Try absorbing if it's a spell // NOTE: Vanilla does this once per effect source instead of adding the % from all sources together, not sure @@ -482,7 +482,7 @@ namespace MWMechanics if (magnitudeMult == 0) { // Fully resisted, show message - if (target.getRefData().getHandle() == "player") + if (target == MWBase::Environment::get().getWorld()->getPlayerPtr()) MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicPCResisted}"); else if (castByPlayer) MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicTargetResisted}"); @@ -611,7 +611,7 @@ namespace MWMechanics { if (target.getCellRef().getLockLevel() < magnitude) //If the door is not already locked to a higher value, lock it to spell magnitude { - if (caster.getRefData().getHandle() == "player") + if (caster == MWBase::Environment::get().getWorld()->getPlayerPtr()) MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicLockSuccess}"); target.getCellRef().setLockLevel(static_cast(magnitude)); } @@ -626,7 +626,7 @@ namespace MWMechanics if (!caster.isEmpty() && caster.getClass().isActor()) MWBase::Environment::get().getMechanicsManager()->objectOpened(caster, target); - if (caster.getRefData().getHandle() == "player") + if (caster == MWBase::Environment::get().getWorld()->getPlayerPtr()) MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicOpenSuccess}"); } target.getCellRef().setLockLevel(-abs(target.getCellRef().getLockLevel())); @@ -652,7 +652,7 @@ namespace MWMechanics else if (effectId == ESM::MagicEffect::RemoveCurse) target.getClass().getCreatureStats(target).getSpells().purgeCurses(); - if (target.getRefData().getHandle() != "player") + if (target != MWBase::Environment::get().getWorld()->getPlayerPtr()) return; if (!MWBase::Environment::get().getWorld()->isTeleportingEnabled()) return; @@ -728,7 +728,7 @@ namespace MWMechanics if (item.getCellRef().getEnchantmentCharge() < castCost) { - if (mCaster.getRefData().getHandle() == "player") + if (mCaster == MWBase::Environment::get().getWorld()->getPlayerPtr()) MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicInsufficientCharge}"); // Failure sound @@ -752,14 +752,14 @@ namespace MWMechanics if (enchantment->mData.mType == ESM::Enchantment::WhenUsed) { - if (mCaster.getRefData().getHandle() == "player") + if (mCaster == MWBase::Environment::get().getWorld()->getPlayerPtr()) mCaster.getClass().skillUsageSucceeded (mCaster, ESM::Skill::Enchant, 1); } if (enchantment->mData.mType == ESM::Enchantment::CastOnce) item.getContainerStore()->remove(item, 1, mCaster); else if (enchantment->mData.mType != ESM::Enchantment::WhenStrikes) { - if (mCaster.getRefData().getHandle() == "player") + if (mCaster == MWBase::Environment::get().getWorld()->getPlayerPtr()) { mCaster.getClass().skillUsageSucceeded (mCaster, ESM::Skill::Enchant, 3); } @@ -827,7 +827,7 @@ namespace MWMechanics int roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 100); // [0, 99] if (!fail && roll >= successChance) { - if (mCaster.getRefData().getHandle() == "player") + if (mCaster == MWBase::Environment::get().getWorld()->getPlayerPtr()) MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicSkillFail}"); fail = true; } @@ -845,7 +845,7 @@ namespace MWMechanics } } - if (mCaster.getRefData().getHandle() == "player" && spellIncreasesSkill(spell)) + if (mCaster == MWBase::Environment::get().getWorld()->getPlayerPtr() && spellIncreasesSkill(spell)) mCaster.getClass().skillUsageSucceeded(mCaster, spellSchoolToSkill(school), 0); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 78ab45881..8fb1ee53c 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -321,7 +321,7 @@ void RenderingManager::updatePlayerPtr(const MWWorld::Ptr &ptr) void RenderingManager::rebuildPtr(const MWWorld::Ptr &ptr) { NpcAnimation *anim = NULL; - if(ptr.getRefData().getHandle() == "player") + if(ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) anim = mPlayerAnimation; else if(ptr.getClass().isActor()) anim = dynamic_cast(mActors->getAnimation(ptr)); @@ -955,7 +955,7 @@ Animation* RenderingManager::getAnimation(const MWWorld::Ptr &ptr) { Animation *anim = mActors->getAnimation(ptr); - if(!anim && ptr.getRefData().getHandle() == "player") + if(!anim && ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) anim = mPlayerAnimation; if (!anim) diff --git a/apps/openmw/mwscript/containerextensions.cpp b/apps/openmw/mwscript/containerextensions.cpp index 86329191e..70475d8e2 100644 --- a/apps/openmw/mwscript/containerextensions.cpp +++ b/apps/openmw/mwscript/containerextensions.cpp @@ -175,7 +175,7 @@ namespace MWScript MWWorld::ActionEquip action (*it); action.execute(ptr); - if (ptr.getRefData().getHandle() == "player" && !ptr.getClass().getScript(ptr).empty()) + if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr() && !ptr.getClass().getScript(ptr).empty()) ptr.getRefData().getLocals().setVarByInt(ptr.getClass().getScript(ptr), "onpcequip", 1); } }; diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 1ed5f0c30..f87983ce8 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -212,7 +212,7 @@ namespace MWScript if (!ptr.isInCell()) return; - if (ptr.getRefData().getHandle() == "player") + if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) { MWBase::Environment::get().getWorld()->getPlayer().setTeleported(true); } @@ -287,7 +287,7 @@ namespace MWScript if (ptr.getContainerStore()) return; - if (ptr.getRefData().getHandle() == "player") + if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) { MWBase::Environment::get().getWorld()->getPlayer().setTeleported(true); } @@ -352,7 +352,7 @@ namespace MWScript if (!ptr.isInCell()) return; - if (ptr.getRefData().getHandle() == "player") + if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) { MWBase::Environment::get().getWorld()->getPlayer().setTeleported(true); } @@ -371,7 +371,7 @@ namespace MWScript // another morrowind oddity: player will be moved to the exterior cell at this location, // non-player actors will move within the cell they are in. MWWorld::Ptr updated; - if (ptr.getRefData().getHandle() == "player") + if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) { MWWorld::CellStore* cell = MWBase::Environment::get().getWorld()->getExterior(cx,cy); MWBase::Environment::get().getWorld()->moveObject(ptr,cell,x,y,z); diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index b3978f9d5..998cc460b 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -477,7 +477,7 @@ namespace MWSound while(snditer != mActiveSounds.end()) { if(snditer->second.first != MWWorld::Ptr() && - snditer->second.first.getCellRef().getRefId() != "player" && + snditer->second.first != MWBase::Environment::get().getWorld()->getPlayerPtr() && snditer->second.first.getCell() == cell) { snditer->first->stop(); diff --git a/apps/openmw/mwworld/action.cpp b/apps/openmw/mwworld/action.cpp index 0fe061e5c..1c360fd4d 100644 --- a/apps/openmw/mwworld/action.cpp +++ b/apps/openmw/mwworld/action.cpp @@ -20,7 +20,7 @@ void MWWorld::Action::execute (const Ptr& actor) { if (!mSoundId.empty()) { - if (mKeepSound && actor.getRefData().getHandle()=="player") + if (mKeepSound && actor == MWBase::Environment::get().getWorld()->getPlayerPtr()) MWBase::Environment::get().getSoundManager()->playSound(mSoundId, 1.0, 1.0, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_Normal,mSoundOffset); else diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 8ef6799ba..d4aadc6c7 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -210,7 +210,7 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add(const std::string & { MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), id, count); // a bit pointless to set owner for the player - if (actorPtr.getRefData().getHandle() != "player") + if (actorPtr != MWBase::Environment::get().getWorld()->getPlayerPtr()) return add(ref.getPtr(), count, actorPtr, true); else return add(ref.getPtr(), count, actorPtr, false); diff --git a/apps/openmw/mwworld/failedaction.cpp b/apps/openmw/mwworld/failedaction.cpp index 7c8ef8c7b..cf5a2a5c2 100644 --- a/apps/openmw/mwworld/failedaction.cpp +++ b/apps/openmw/mwworld/failedaction.cpp @@ -13,7 +13,7 @@ namespace MWWorld void FailedAction::executeImp(const Ptr &actor) { - if(actor.getRefData().getHandle() == "player" && !mMessage.empty()) + if(actor == MWBase::Environment::get().getWorld()->getPlayerPtr() && !mMessage.empty()) MWBase::Environment::get().getWindowManager()->messageBox(mMessage); } } diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 9ad490d69..da43df513 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -133,7 +133,7 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::add(const Ptr& itemPtr, const MWWorld::ContainerStoreIterator& retVal = MWWorld::ContainerStore::add(itemPtr, count, actorPtr, setOwner); // Auto-equip items if an armor/clothing or weapon item is added, but not for the player nor werewolves - if (actorPtr.getRefData().getHandle() != "player" + if (actorPtr != MWBase::Environment::get().getWorld()->getPlayerPtr() && !(actorPtr.getClass().isNpc() && actorPtr.getClass().getNpcStats(actorPtr).isWerewolf())) { std::string type = itemPtr.getTypeName(); @@ -503,7 +503,7 @@ int MWWorld::InventoryStore::remove(const Ptr& item, int count, const Ptr& actor // If an armor/clothing item is removed, try to find a replacement, // but not for the player nor werewolves. - if ((actor.getRefData().getHandle() != "player") + if ((actor != MWBase::Environment::get().getWorld()->getPlayerPtr()) && !(actor.getClass().isNpc() && actor.getClass().getNpcStats(actor).isWerewolf())) { std::string type = item.getTypeName(); @@ -535,7 +535,7 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::unequipSlot(int slot, c { retval = restack(*it); - if (actor.getRefData().getHandle() == "player") + if (actor == MWBase::Environment::get().getWorld()->getPlayerPtr()) { // Unset OnPCEquip Variable on item's script, if it has a script with that variable declared const std::string& script = it->getClass().getScript(*it); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 97b2cd204..518c88ead 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1406,7 +1406,7 @@ namespace MWWorld PtrVelocityList::const_iterator player(results.end()); for(PtrVelocityList::const_iterator iter(results.begin());iter != results.end();++iter) { - if(iter->first.getRefData().getHandle() == "player") + if(iter->first == getPlayerPtr()) { /* Handle player last, in case a cell transition occurs */ player = iter; @@ -2228,7 +2228,7 @@ namespace MWWorld if (healthPerSecond > 0.0f) { - if (actor.getRefData().getHandle() == "player") + if (actor == getPlayerPtr()) MWBase::Environment::get().getWindowManager()->activateHitOverlay(false); if (!MWBase::Environment::get().getSoundManager()->getSoundPlaying(actor, "Health Damage")) @@ -2259,7 +2259,7 @@ namespace MWWorld if (healthPerSecond > 0.0f) { - if (actor.getRefData().getHandle() == "player") + if (actor == getPlayerPtr()) MWBase::Environment::get().getWindowManager()->activateHitOverlay(false); if (!MWBase::Environment::get().getSoundManager()->getSoundPlaying(actor, "Health Damage")) @@ -2516,7 +2516,7 @@ namespace MWWorld // the following is just for reattaching the camera properly. mRendering->rebuildPtr(actor); - if(actor.getRefData().getHandle() == "player") + if(actor == getPlayerPtr()) { // Update the GUI only when called on the player MWBase::WindowManager* windowManager = MWBase::Environment::get().getWindowManager(); @@ -3167,7 +3167,7 @@ namespace MWWorld void World::spawnBloodEffect(const Ptr &ptr, const Vector3 &worldPosition) { - if (ptr.getRefData().getHandle() == "player" && Settings::Manager::getBool("hit fader", "GUI")) + if (ptr == getPlayerPtr() && Settings::Manager::getBool("hit fader", "GUI")) return; int type = ptr.getClass().getBloodTexture(ptr); From 304277429f07659cd8fcf5b1ffc91657bcc0ed21 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 12 Mar 2015 00:21:46 +0100 Subject: [PATCH 0732/3725] Rename variable to not show up in search for "TODO" comments. --- components/fontloader/fontloader.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/components/fontloader/fontloader.cpp b/components/fontloader/fontloader.cpp index 0ca37ad11..eb7dd901d 100644 --- a/components/fontloader/fontloader.cpp +++ b/components/fontloader/fontloader.cpp @@ -20,12 +20,12 @@ namespace { size_t i = 0; unsigned long unicode; - size_t todo; + size_t numbytes; unsigned char ch = utf8[i++]; if (ch <= 0x7F) { unicode = ch; - todo = 0; + numbytes = 0; } else if (ch <= 0xBF) { @@ -34,23 +34,23 @@ namespace else if (ch <= 0xDF) { unicode = ch&0x1F; - todo = 1; + numbytes = 1; } else if (ch <= 0xEF) { unicode = ch&0x0F; - todo = 2; + numbytes = 2; } else if (ch <= 0xF7) { unicode = ch&0x07; - todo = 3; + numbytes = 3; } else { throw std::logic_error("not a UTF-8 string"); } - for (size_t j = 0; j < todo; ++j) + for (size_t j = 0; j < numbytes; ++j) { unsigned char ch = utf8[i++]; if (ch < 0x80 || ch > 0xBF) From 16ddfbca14fca5bdd86af78075e7c9154198aee3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 12 Mar 2015 00:27:01 +0100 Subject: [PATCH 0733/3725] Remove some outdated todo comments --- components/to_utf8/to_utf8.cpp | 8 ++++---- libs/openengine/bullet/physic.hpp | 3 +-- libs/openengine/gui/manager.cpp | 1 - 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/components/to_utf8/to_utf8.cpp b/components/to_utf8/to_utf8.cpp index cb9680441..d7f9c3a38 100644 --- a/components/to_utf8/to_utf8.cpp +++ b/components/to_utf8/to_utf8.cpp @@ -84,11 +84,11 @@ std::string Utf8Encoder::getUtf8(const char* input, size_t size) // is also ok.) assert(input[size] == 0); - // TODO: The rest of this function is designed for single-character + // Note: The rest of this function is designed for single-character // input encodings only. It also assumes that the input the input - // encoding shares its first 128 values (0-127) with ASCII. These - // conditions must be checked again if you add more input encodings - // later. + // encoding shares its first 128 values (0-127) with ASCII. There are + // no plans to add more encodings to this module (we are using utf8 + // for new content files), so that shouldn't be an issue. // Compute output length, and check for pure ascii input at the same // time. diff --git a/libs/openengine/bullet/physic.hpp b/libs/openengine/bullet/physic.hpp index 1a16ff4e8..7784e8941 100644 --- a/libs/openengine/bullet/physic.hpp +++ b/libs/openengine/bullet/physic.hpp @@ -258,13 +258,12 @@ namespace Physic const Ogre::Vector3 &position, float scale, const Ogre::Quaternion &rotation); /** - * Remove a character from the scene. TODO:delete it! for now, a small memory leak^^ done? + * Remove a character from the scene. */ void removeCharacter(const std::string &name); /** * Return a pointer to a character - * TODO:check if the actor exist... */ PhysicActor* getCharacter(const std::string &name); diff --git a/libs/openengine/gui/manager.cpp b/libs/openengine/gui/manager.cpp index 512c7f069..349647892 100644 --- a/libs/openengine/gui/manager.cpp +++ b/libs/openengine/gui/manager.cpp @@ -451,7 +451,6 @@ public: mRenderSystem->_setSceneBlending(Ogre::SBF_SOURCE_ALPHA, Ogre::SBF_ONE_MINUS_SOURCE_ALPHA); // always use wireframe - // TODO: add option to enable wireframe mode in platform mRenderSystem->_setPolygonMode(Ogre::PM_SOLID); } From 5f051b5bf2dda8e2e48827505218b2351ffe9b2b Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 12 Mar 2015 00:32:57 +0100 Subject: [PATCH 0734/3725] Remove comment about GMST cleaning which was removed. --- components/esm/loadgmst.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esm/loadgmst.hpp b/components/esm/loadgmst.hpp index 6b66ac832..398b8047f 100644 --- a/components/esm/loadgmst.hpp +++ b/components/esm/loadgmst.hpp @@ -12,7 +12,7 @@ class ESMReader; class ESMWriter; /* - * Game setting, with automatic cleaning of "dirty" entries. + * Game setting * */ From d00c75d428489819fa9d7229a719a27c5831ff1d Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 12 Mar 2015 00:37:28 +0100 Subject: [PATCH 0735/3725] Remove more outdated TODO comments. --- apps/openmw/mwbase/world.hpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 56f575d3a..9e6c6d9bf 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -205,10 +205,8 @@ namespace MWBase ///< Return a pointer to a liveCellRef which contains \a ptr. /// \note Search is limited to the active cells. - /// \todo enable reference in the OGRE scene virtual void enable (const MWWorld::Ptr& ptr) = 0; - /// \todo disable reference in the OGRE scene virtual void disable (const MWWorld::Ptr& ptr) = 0; virtual void advanceTime (double hours) = 0; From 7fd1c2c2e27426dd735e64879b0a4bc34aa3c477 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 12 Mar 2015 00:43:28 +0100 Subject: [PATCH 0736/3725] CharacterCreation refactoring --- apps/openmw/mwgui/charactercreation.cpp | 97 ++++++------------------- apps/openmw/mwgui/charactercreation.hpp | 2 + 2 files changed, 24 insertions(+), 75 deletions(-) diff --git a/apps/openmw/mwgui/charactercreation.cpp b/apps/openmw/mwgui/charactercreation.cpp index ab412f63b..fb00d6a98 100644 --- a/apps/openmw/mwgui/charactercreation.cpp +++ b/apps/openmw/mwgui/charactercreation.cpp @@ -330,20 +330,7 @@ namespace MWGui updatePlayerHealth(); - //TODO This bit gets repeated a few times; wrap it in a function - MWBase::Environment::get().getWindowManager()->popGuiMode(); - if (mCreationStage == CSE_ReviewNext) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Review); - } - else if (mCreationStage >= CSE_ClassChosen) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Birth); - } - else - { - mCreationStage = CSE_ClassChosen; - } + handleDialogDone(CSE_ClassChosen, GM_Birth); } void CharacterCreation::onPickClassDialogBack() @@ -397,19 +384,7 @@ namespace MWGui mNameDialog = 0; } - MWBase::Environment::get().getWindowManager()->popGuiMode(); - if (mCreationStage == CSE_ReviewNext) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Review); - } - else if (mCreationStage >= CSE_NameChosen) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Race); - } - else - { - mCreationStage = CSE_NameChosen; - } + handleDialogDone(CSE_NameChosen, GM_Race); } void CharacterCreation::onRaceDialogBack() @@ -456,19 +431,7 @@ namespace MWGui updatePlayerHealth(); - MWBase::Environment::get().getWindowManager()->popGuiMode(); - if (mCreationStage == CSE_ReviewNext) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Review); - } - else if (mCreationStage >= CSE_RaceChosen) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); - } - else - { - mCreationStage = CSE_RaceChosen; - } + handleDialogDone(CSE_RaceChosen, GM_Class); } void CharacterCreation::onBirthSignDialogDone(WindowBase* parWindow) @@ -484,15 +447,7 @@ namespace MWGui updatePlayerHealth(); - MWBase::Environment::get().getWindowManager()->popGuiMode(); - if (mCreationStage >= CSE_BirthSignChosen) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Review); - } - else - { - mCreationStage = CSE_BirthSignChosen; - } + handleDialogDone(CSE_BirthSignChosen, GM_Review); } void CharacterCreation::onBirthSignDialogBack() @@ -543,19 +498,7 @@ namespace MWGui updatePlayerHealth(); - MWBase::Environment::get().getWindowManager()->popGuiMode(); - if (mCreationStage == CSE_ReviewNext) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Review); - } - else if (mCreationStage >= CSE_ClassChosen) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Birth); - } - else - { - mCreationStage = CSE_ClassChosen; - } + handleDialogDone(CSE_ClassChosen, GM_Birth); } void CharacterCreation::onCreateClassDialogBack() @@ -711,19 +654,7 @@ namespace MWGui updatePlayerHealth(); - MWBase::Environment::get().getWindowManager()->popGuiMode(); - if (mCreationStage == CSE_ReviewNext) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Review); - } - else if (mCreationStage >= CSE_ClassChosen) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Birth); - } - else - { - mCreationStage = CSE_ClassChosen; - } + handleDialogDone(CSE_ClassChosen, GM_Birth); } CharacterCreation::~CharacterCreation() @@ -739,4 +670,20 @@ namespace MWGui delete mReviewDialog; } + void CharacterCreation::handleDialogDone(CSE currentStage, int nextMode) + { + MWBase::Environment::get().getWindowManager()->popGuiMode(); + if (mCreationStage == CSE_ReviewNext) + { + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Review); + } + else if (mCreationStage >= currentStage) + { + MWBase::Environment::get().getWindowManager()->pushGuiMode((GuiMode)nextMode); + } + else + { + mCreationStage = currentStage; + } + } } diff --git a/apps/openmw/mwgui/charactercreation.hpp b/apps/openmw/mwgui/charactercreation.hpp index c2486c7f0..a4515569d 100644 --- a/apps/openmw/mwgui/charactercreation.hpp +++ b/apps/openmw/mwgui/charactercreation.hpp @@ -104,6 +104,8 @@ namespace MWGui }; CSE mCreationStage; // Which state the character creating is in, controls back/next/ok buttons + + void handleDialogDone(CSE currentStage, int nextMode); }; } From f603a681445c653960adb76d1722b9af44a0db98 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 12 Mar 2015 02:23:46 +0100 Subject: [PATCH 0737/3725] Allow binding Hand To Hand in quick keys menu (Fixes #2024) --- apps/openmw/mwgui/quickkeysmenu.cpp | 29 ++++++++++++++++++++++++----- apps/openmw/mwgui/quickkeysmenu.hpp | 5 +++-- 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index a102de1e5..8f595df80 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -94,12 +94,24 @@ namespace MWGui while (key->getChildCount()) // Destroy number label MyGUI::Gui::getInstance().destroyWidget(key->getChildAt(0)); - mAssigned[index] = Type_Unassigned; + if (index == 9) + { + mAssigned[index] = Type_HandToHand; + + MyGUI::ImageBox* image = key->createWidget("ImageBox", + MyGUI::IntCoord(14, 13, 32, 32), MyGUI::Align::Default); + image->setImageTexture("icons\\k\\stealth_handtohand.dds"); + image->setNeedMouseFocus(false); + } + else + { + mAssigned[index] = Type_Unassigned; - MyGUI::TextBox* textBox = key->createWidgetReal("SandText", MyGUI::FloatCoord(0,0,1,1), MyGUI::Align::Default); - textBox->setTextAlign (MyGUI::Align::Center); - textBox->setCaption (MyGUI::utility::toString(index+1)); - textBox->setNeedMouseFocus (false); + MyGUI::TextBox* textBox = key->createWidgetReal("SandText", MyGUI::FloatCoord(0,0,1,1), MyGUI::Align::Default); + textBox->setTextAlign (MyGUI::Align::Center); + textBox->setCaption (MyGUI::utility::toString(index+1)); + textBox->setNeedMouseFocus (false); + } } void QuickKeysMenu::onQuickKeyButtonClicked(MyGUI::Widget* sender) @@ -338,6 +350,11 @@ namespace MWGui store.setSelectedEnchantItem(it); MWBase::Environment::get().getWorld()->getPlayer().setDrawState(MWMechanics::DrawState_Spell); } + else if (type == Type_HandToHand) + { + store.unequipSlot(MWWorld::InventoryStore::Slot_CarriedRight, player); + MWBase::Environment::get().getWorld()->getPlayer().setDrawState(MWMechanics::DrawState_Weapon); + } } // --------------------------------------------------------------------------------------------------------- @@ -409,6 +426,7 @@ namespace MWGui switch (type) { case Type_Unassigned: + case Type_HandToHand: break; case Type_Item: case Type_MagicItem: @@ -489,6 +507,7 @@ namespace MWGui break; } case Type_Unassigned: + case Type_HandToHand: unassign(button, i); break; } diff --git a/apps/openmw/mwgui/quickkeysmenu.hpp b/apps/openmw/mwgui/quickkeysmenu.hpp index 00afa4561..afbcff001 100644 --- a/apps/openmw/mwgui/quickkeysmenu.hpp +++ b/apps/openmw/mwgui/quickkeysmenu.hpp @@ -37,15 +37,16 @@ namespace MWGui void activateQuickKey(int index); + /// @note This enum is serialized, so don't move the items around! enum QuickKeyType { Type_Item, Type_Magic, Type_MagicItem, - Type_Unassigned + Type_Unassigned, + Type_HandToHand }; - void write (ESM::ESMWriter& writer); void readRecord (ESM::ESMReader& reader, uint32_t type); void clear(); From a846bb1aa3430c57dd3488df16f2a0dfb69bcb74 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 12 Mar 2015 02:44:41 +0100 Subject: [PATCH 0738/3725] Update hit chance according to wiki and implement fCombatInvisoMult --- apps/openmw/mwmechanics/combat.cpp | 35 +++++++++++++++++++---- apps/openmw/mwmechanics/creaturestats.cpp | 2 +- 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwmechanics/combat.cpp b/apps/openmw/mwmechanics/combat.cpp index b8ffa63e2..9d61b2eac 100644 --- a/apps/openmw/mwmechanics/combat.cpp +++ b/apps/openmw/mwmechanics/combat.cpp @@ -241,14 +241,39 @@ namespace MWMechanics { MWMechanics::CreatureStats &stats = attacker.getClass().getCreatureStats(attacker); const MWMechanics::MagicEffects &mageffects = stats.getMagicEffects(); - float hitchance = skillValue + + + MWBase::World *world = MWBase::Environment::get().getWorld(); + const MWWorld::Store &gmst = world->getStore().get(); + + float defenseTerm = 0; + if (victim.getClass().getCreatureStats(victim).getFatigue().getCurrent() >= 0) + { + MWMechanics::CreatureStats& victimStats = victim.getClass().getCreatureStats(victim); + // Maybe we should keep an aware state for actors updated every so often instead of testing every time + bool unaware = (!victimStats.getAiSequence().isInCombat()) + && (attacker == MWBase::Environment::get().getWorld()->getPlayerPtr()) + && (!MWBase::Environment::get().getMechanicsManager()->awarenessCheck(attacker, victim)); + if (!(victimStats.getKnockedDown() || + victimStats.getMagicEffects().get(ESM::MagicEffect::Paralyze).getMagnitude() > 0 + || unaware )) + { + defenseTerm = victimStats.getEvasion(); + } + defenseTerm += std::min(100.f, + gmst.find("fCombatInvisoMult")->getFloat() * + victimStats.getMagicEffects().get(ESM::MagicEffect::Chameleon).getMagnitude()); + defenseTerm += std::min(100.f, + gmst.find("fCombatInvisoMult")->getFloat() * + victimStats.getMagicEffects().get(ESM::MagicEffect::Invisibility).getMagnitude()); + } + float attackTerm = skillValue + (stats.getAttribute(ESM::Attribute::Agility).getModified() / 5.0f) + (stats.getAttribute(ESM::Attribute::Luck).getModified() / 10.0f); - hitchance *= stats.getFatigueTerm(); - hitchance += mageffects.get(ESM::MagicEffect::FortifyAttack).getMagnitude() - + attackTerm *= stats.getFatigueTerm(); + attackTerm += mageffects.get(ESM::MagicEffect::FortifyAttack).getMagnitude() - mageffects.get(ESM::MagicEffect::Blind).getMagnitude(); - hitchance -= victim.getClass().getCreatureStats(victim).getEvasion(); - return hitchance; + + return static_cast((attackTerm - defenseTerm) + 0.5f); } void applyElementalShields(const MWWorld::Ptr &attacker, const MWWorld::Ptr &victim) diff --git a/apps/openmw/mwmechanics/creaturestats.cpp b/apps/openmw/mwmechanics/creaturestats.cpp index 931c2f14e..4c338e23f 100644 --- a/apps/openmw/mwmechanics/creaturestats.cpp +++ b/apps/openmw/mwmechanics/creaturestats.cpp @@ -336,7 +336,7 @@ namespace MWMechanics float evasion = (getAttribute(ESM::Attribute::Agility).getModified() / 5.0f) + (getAttribute(ESM::Attribute::Luck).getModified() / 10.0f); evasion *= getFatigueTerm(); - evasion += mMagicEffects.get(ESM::MagicEffect::Sanctuary).getMagnitude(); + evasion += std::min(100.f, mMagicEffects.get(ESM::MagicEffect::Sanctuary).getMagnitude()); return evasion; } From 767624f518108463b64816411da1f287b0489e09 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 12 Mar 2015 03:08:58 +0100 Subject: [PATCH 0739/3725] Combat mechanic fixes --- apps/openmw/mwclass/creature.cpp | 6 ++---- apps/openmw/mwclass/npc.cpp | 8 ++------ apps/openmw/mwclass/npc.hpp | 2 -- apps/openmw/mwmechanics/combat.cpp | 27 ++++++++++++++------------- apps/openmw/mwmechanics/combat.hpp | 2 +- 5 files changed, 19 insertions(+), 26 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 9a3c6c218..908de02d8 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -249,7 +249,7 @@ namespace MWClass float hitchance = MWMechanics::getHitChance(ptr, victim, ref->mBase->mData.mCombat); - if((::rand()/(RAND_MAX+1.0)) > hitchance/100.0f) + if((::rand()/(RAND_MAX+1.0)) >= hitchance/100.0f) { victim.getClass().onHit(victim, 0.0f, false, MWWorld::Ptr(), ptr, false); MWMechanics::reduceWeaponCondition(0.f, false, weapon, ptr); @@ -288,9 +288,7 @@ namespace MWClass if(attack) { damage = attack[0] + ((attack[1]-attack[0])*stats.getAttackStrength()); - damage *= gmst.find("fDamageStrengthBase")->getFloat() + - (stats.getAttribute(ESM::Attribute::Strength).getModified() * gmst.find("fDamageStrengthMult")->getFloat() * 0.1f); - MWMechanics::adjustWeaponDamage(damage, weapon); + MWMechanics::adjustWeaponDamage(damage, weapon, ptr); MWMechanics::reduceWeaponCondition(damage, true, weapon, ptr); } diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index deb4b90cd..ea506ff9e 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -279,8 +279,6 @@ namespace MWClass gmst.fKnockDownMult = store.find("fKnockDownMult"); gmst.iKnockDownOddsMult = store.find("iKnockDownOddsMult"); gmst.iKnockDownOddsBase = store.find("iKnockDownOddsBase"); - gmst.fDamageStrengthBase = store.find("fDamageStrengthBase"); - gmst.fDamageStrengthMult = store.find("fDamageStrengthMult"); gmst.fCombatArmorMinMult = store.find("fCombatArmorMinMult"); inited = true; @@ -516,7 +514,7 @@ namespace MWClass float hitchance = MWMechanics::getHitChance(ptr, victim, ptr.getClass().getSkill(ptr, weapskill)); - if((::rand()/(RAND_MAX+1.0)) > hitchance/100.0f) + if((::rand()/(RAND_MAX+1.0)) >= hitchance/100.0f) { othercls.onHit(victim, 0.0f, false, weapon, ptr, false); MWMechanics::reduceWeaponCondition(0.f, false, weapon, ptr); @@ -538,10 +536,8 @@ namespace MWClass if(attack) { damage = attack[0] + ((attack[1]-attack[0])*stats.getAttackStrength()); - damage *= gmst.fDamageStrengthBase->getFloat() + - (stats.getAttribute(ESM::Attribute::Strength).getModified() * gmst.fDamageStrengthMult->getFloat() * 0.1f); } - MWMechanics::adjustWeaponDamage(damage, weapon); + MWMechanics::adjustWeaponDamage(damage, weapon, ptr); MWMechanics::reduceWeaponCondition(damage, true, weapon, ptr); healthdmg = true; } diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index c00665eb3..27beeb626 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -38,8 +38,6 @@ namespace MWClass const ESM::GameSetting *fKnockDownMult; const ESM::GameSetting *iKnockDownOddsMult; const ESM::GameSetting *iKnockDownOddsBase; - const ESM::GameSetting *fDamageStrengthBase; - const ESM::GameSetting *fDamageStrengthMult; const ESM::GameSetting *fCombatArmorMinMult; }; diff --git a/apps/openmw/mwmechanics/combat.cpp b/apps/openmw/mwmechanics/combat.cpp index 9d61b2eac..fdb375846 100644 --- a/apps/openmw/mwmechanics/combat.cpp +++ b/apps/openmw/mwmechanics/combat.cpp @@ -186,29 +186,23 @@ namespace MWMechanics int skillValue = attacker.getClass().getSkill(attacker, weapon.getClass().getEquipmentSkill(weapon)); - if((::rand()/(RAND_MAX+1.0)) > getHitChance(attacker, victim, skillValue)/100.0f) + if((::rand()/(RAND_MAX+1.0)) >= getHitChance(attacker, victim, skillValue)/100.0f) { victim.getClass().onHit(victim, 0.0f, false, projectile, attacker, false); MWMechanics::reduceWeaponCondition(0.f, false, weapon, attacker); return; } - float fDamageStrengthBase = gmst.find("fDamageStrengthBase")->getFloat(); - float fDamageStrengthMult = gmst.find("fDamageStrengthMult")->getFloat(); const unsigned char* attack = weapon.get()->mBase->mData.mChop; float damage = attack[0] + ((attack[1]-attack[0])*attackerStats.getAttackStrength()); // Bow/crossbow damage - if (weapon != projectile) - { - // Arrow/bolt damage - attack = projectile.get()->mBase->mData.mChop; - damage += attack[0] + ((attack[1]-attack[0])*attackerStats.getAttackStrength()); - } - damage *= fDamageStrengthBase + - (attackerStats.getAttribute(ESM::Attribute::Strength).getModified() * fDamageStrengthMult * 0.1f); + // Arrow/bolt damage + // NB in case of thrown weapons, we are applying the damage twice since projectile == weapon + attack = projectile.get()->mBase->mData.mChop; + damage += attack[0] + ((attack[1]-attack[0])*attackerStats.getAttackStrength()); - adjustWeaponDamage(damage, weapon); + adjustWeaponDamage(damage, weapon, attacker); reduceWeaponCondition(damage, true, weapon, attacker); if(attacker == MWBase::Environment::get().getWorld()->getPlayerPtr()) @@ -347,7 +341,7 @@ namespace MWMechanics } } - void adjustWeaponDamage(float &damage, const MWWorld::Ptr &weapon) + void adjustWeaponDamage(float &damage, const MWWorld::Ptr &weapon, const MWWorld::Ptr& attacker) { if (weapon.isEmpty()) return; @@ -359,6 +353,13 @@ namespace MWMechanics int weapmaxhealth = weapon.getClass().getItemMaxHealth(weapon); damage *= (float(weaphealth) / weapmaxhealth); } + + static const float fDamageStrengthBase = MWBase::Environment::get().getWorld()->getStore().get() + .find("fDamageStrengthBase")->getFloat(); + static const float fDamageStrengthMult = MWBase::Environment::get().getWorld()->getStore().get() + .find("fDamageStrengthMult")->getFloat(); + damage *= fDamageStrengthBase + + (attacker.getClass().getCreatureStats(attacker).getAttribute(ESM::Attribute::Strength).getModified() * fDamageStrengthMult * 0.1f); } void getHandToHandDamage(const MWWorld::Ptr &attacker, const MWWorld::Ptr &victim, float &damage, bool &healthdmg) diff --git a/apps/openmw/mwmechanics/combat.hpp b/apps/openmw/mwmechanics/combat.hpp index a48dcf72a..a2fd8b006 100644 --- a/apps/openmw/mwmechanics/combat.hpp +++ b/apps/openmw/mwmechanics/combat.hpp @@ -30,7 +30,7 @@ void applyElementalShields(const MWWorld::Ptr& attacker, const MWWorld::Ptr& vic void reduceWeaponCondition (float damage, bool hit, MWWorld::Ptr& weapon, const MWWorld::Ptr& attacker); /// Adjust weapon damage based on its condition. A used weapon will be less effective. -void adjustWeaponDamage (float& damage, const MWWorld::Ptr& weapon); +void adjustWeaponDamage (float& damage, const MWWorld::Ptr& weapon, const MWWorld::Ptr& attacker); void getHandToHandDamage (const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim, float& damage, bool& healthdmg); From 418025e0a29394c87501ae64e6993d03c114b05b Mon Sep 17 00:00:00 2001 From: cc9cii Date: Thu, 12 Mar 2015 13:10:25 +1100 Subject: [PATCH 0740/3725] Add missing editor type to the dialogue. Should resolve Bug #2437. --- apps/opencs/view/world/dialoguesubview.cpp | 7 ++++++- apps/opencs/view/world/util.cpp | 2 ++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 8790601ea..48009da8d 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -266,6 +267,8 @@ QWidget* CSVWorld::DialogueDelegateDispatcher::makeEditor(CSMWorld::ColumnBase:: editor = delegateIt->second->createEditor(qobject_cast(mParent), QStyleOptionViewItem(), index, display); DialogueDelegateDispatcherProxy* proxy = new DialogueDelegateDispatcherProxy(editor, display); + // NOTE: For each entry in CSVWorld::CommandDelegate::createEditor() a corresponding entry + // is required here if (qobject_cast(editor)) { connect(editor, SIGNAL(editingFinished()), proxy, SLOT(editorDataCommited())); @@ -286,10 +289,12 @@ QWidget* CSVWorld::DialogueDelegateDispatcher::makeEditor(CSMWorld::ColumnBase:: { connect(editor, SIGNAL(currentIndexChanged (int)), proxy, SLOT(editorDataCommited())); } - else if (qobject_cast(editor)) + else if (qobject_cast(editor) || qobject_cast(editor)) { connect(editor, SIGNAL(editingFinished()), proxy, SLOT(editorDataCommited())); } + else // throw an exception because this is a coding error + throw std::logic_error ("Dialogue editor type missing"); connect(proxy, SIGNAL(editorDataCommited(QWidget*, const QModelIndex&, CSMWorld::ColumnBase::Display)), this, SLOT(editorDataCommited(QWidget*, const QModelIndex&, CSMWorld::ColumnBase::Display))); mProxys.push_back(proxy); //deleted in the destructor diff --git a/apps/opencs/view/world/util.cpp b/apps/opencs/view/world/util.cpp index c65e12c60..91460c3df 100644 --- a/apps/opencs/view/world/util.cpp +++ b/apps/opencs/view/world/util.cpp @@ -152,6 +152,8 @@ QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleO } } + // NOTE: for each editor type (e.g. QLineEdit) there needs to be a corresponding + // entry in CSVWorld::DialogueDelegateDispatcher::makeEditor() switch (display) { case CSMWorld::ColumnBase::Display_Colour: From 8e37e9a14af3cc03176d53f662c47741345b0a52 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 12 Mar 2015 10:51:50 +0100 Subject: [PATCH 0741/3725] removed redundant functions --- apps/opencs/model/world/record.hpp | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/apps/opencs/model/world/record.hpp b/apps/opencs/model/world/record.hpp index 6ff33f0c2..3362f9f96 100644 --- a/apps/opencs/model/world/record.hpp +++ b/apps/opencs/model/world/record.hpp @@ -41,8 +41,6 @@ namespace CSMWorld ESXRecordT mModified; Record(); - Record(const Record& record); - Record& operator= (const Record& record); Record(State state, const ESXRecordT *base = 0, const ESXRecordT *modified = 0); @@ -74,26 +72,6 @@ namespace CSMWorld : mBase(), mModified() { } - template - Record::Record(const Record& record) - : mBase(record.mBase), mModified(record.mModified) - { - mState = record.mState; - } - - template - Record& Record::operator= (const Record& record) - { - if(this != &record) - { - mBase = record.mBase; - mModified = record.mModified; - mState = record.mState; - } - - return *this; - } - template Record::Record(State state, const ESXRecordT *base, const ESXRecordT *modified) { From d10f073bf8f51973b8ff914e9022397820da78f3 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 12 Mar 2015 12:05:36 +0100 Subject: [PATCH 0742/3725] updated changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8bbee6fe0..1766aa21d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ Bug #2334: Drag-and-drop on a content file in the launcher creates duplicate items Bug #2338: Arrows reclaimed from corpses do not stack sometimes Bug #2344: Launcher - Settings importer running correctly? + Bug #2346: Launcher - Importing plugins into content list screws up the load order Bug #2348: Mod: H.E.L.L.U.V.A. Handy Holdables does not appear in the content list Bug #2353: Detect Animal detects dead creatures Bug #2354: Cmake does not respect LIB_SUFFIX From 589b0b91713888ab0364841d6d0e712e080d2785 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Fri, 13 Mar 2015 08:01:48 +1100 Subject: [PATCH 0743/3725] Add saving land and land textures. Should resolve Bug #2447. --- apps/opencs/model/doc/saving.cpp | 4 ++ apps/opencs/model/doc/savingstages.cpp | 66 ++++++++++++++++++++++++++ apps/opencs/model/doc/savingstages.hpp | 34 +++++++++++++ 3 files changed, 104 insertions(+) diff --git a/apps/opencs/model/doc/saving.cpp b/apps/opencs/model/doc/saving.cpp index 04d61ed1b..9f6e469b8 100644 --- a/apps/opencs/model/doc/saving.cpp +++ b/apps/opencs/model/doc/saving.cpp @@ -93,6 +93,10 @@ CSMDoc::Saving::Saving (Document& document, const boost::filesystem::path& proje appendStage (new WritePathgridCollectionStage (mDocument, mState)); + appendStage (new WriteLandCollectionStage (mDocument, mState)); + + appendStage (new WriteLandTextureCollectionStage (mDocument, mState)); + // close file and clean up appendStage (new CloseSaveStage (mState)); diff --git a/apps/opencs/model/doc/savingstages.cpp b/apps/opencs/model/doc/savingstages.cpp index 08f8c9eaa..11aa8a7d1 100644 --- a/apps/opencs/model/doc/savingstages.cpp +++ b/apps/opencs/model/doc/savingstages.cpp @@ -353,6 +353,72 @@ void CSMDoc::WritePathgridCollectionStage::perform (int stage, Messages& message } +CSMDoc::WriteLandCollectionStage::WriteLandCollectionStage (Document& document, + SavingState& state) +: mDocument (document), mState (state) +{} + +int CSMDoc::WriteLandCollectionStage::setup() +{ + return mDocument.getData().getLand().getSize(); +} + +void CSMDoc::WriteLandCollectionStage::perform (int stage, Messages& messages) +{ + const CSMWorld::Record& land = + mDocument.getData().getLand().getRecord (stage); + + if (land.mState==CSMWorld::RecordBase::State_Modified || + land.mState==CSMWorld::RecordBase::State_ModifiedOnly) + { + CSMWorld::Land record = land.get(); + + mState.getWriter().startRecord (record.mLand->sRecordId); + + record.mLand->save (mState.getWriter()); + + mState.getWriter().endRecord (record.mLand->sRecordId); + } + else if (land.mState==CSMWorld::RecordBase::State_Deleted) + { + /// \todo write record with delete flag + } +} + + +CSMDoc::WriteLandTextureCollectionStage::WriteLandTextureCollectionStage (Document& document, + SavingState& state) +: mDocument (document), mState (state) +{} + +int CSMDoc::WriteLandTextureCollectionStage::setup() +{ + return mDocument.getData().getLandTextures().getSize(); +} + +void CSMDoc::WriteLandTextureCollectionStage::perform (int stage, Messages& messages) +{ + const CSMWorld::Record& landTexture = + mDocument.getData().getLandTextures().getRecord (stage); + + if (landTexture.mState==CSMWorld::RecordBase::State_Modified || + landTexture.mState==CSMWorld::RecordBase::State_ModifiedOnly) + { + CSMWorld::LandTexture record = landTexture.get(); + + mState.getWriter().startRecord (record.sRecordId); + + record.save (mState.getWriter()); + + mState.getWriter().endRecord (record.sRecordId); + } + else if (landTexture.mState==CSMWorld::RecordBase::State_Deleted) + { + /// \todo write record with delete flag + } +} + + CSMDoc::CloseSaveStage::CloseSaveStage (SavingState& state) : mState (state) {} diff --git a/apps/opencs/model/doc/savingstages.hpp b/apps/opencs/model/doc/savingstages.hpp index 907041114..4b16581dc 100644 --- a/apps/opencs/model/doc/savingstages.hpp +++ b/apps/opencs/model/doc/savingstages.hpp @@ -209,6 +209,40 @@ namespace CSMDoc ///< Messages resulting from this stage will be appended to \a messages. }; + + class WriteLandCollectionStage : public Stage + { + Document& mDocument; + SavingState& mState; + + public: + + WriteLandCollectionStage (Document& document, SavingState& state); + + virtual int setup(); + ///< \return number of steps + + virtual void perform (int stage, Messages& messages); + ///< Messages resulting from this stage will be appended to \a messages. + }; + + + class WriteLandTextureCollectionStage : public Stage + { + Document& mDocument; + SavingState& mState; + + public: + + WriteLandTextureCollectionStage (Document& document, SavingState& state); + + virtual int setup(); + ///< \return number of steps + + virtual void perform (int stage, Messages& messages); + ///< Messages resulting from this stage will be appended to \a messages. + }; + class CloseSaveStage : public Stage { SavingState& mState; From 488bc76da5b33f8ac935a946134d7c24f77e8841 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Fri, 13 Mar 2015 22:06:55 +1100 Subject: [PATCH 0744/3725] Fix saving land data. --- apps/opencs/model/doc/savingstages.cpp | 2 ++ apps/opencs/model/world/data.cpp | 2 +- components/esm/loadland.cpp | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/doc/savingstages.cpp b/apps/opencs/model/doc/savingstages.cpp index 11aa8a7d1..485ad094b 100644 --- a/apps/opencs/model/doc/savingstages.cpp +++ b/apps/opencs/model/doc/savingstages.cpp @@ -376,6 +376,8 @@ void CSMDoc::WriteLandCollectionStage::perform (int stage, Messages& messages) mState.getWriter().startRecord (record.mLand->sRecordId); record.mLand->save (mState.getWriter()); + if(record.mLand->mLandData) + record.mLand->mLandData->save (mState.getWriter()); mState.getWriter().endRecord (record.mLand->sRecordId); } diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 313518091..39cff3db6 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -745,7 +745,7 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Messages& messages) if (index!=-1 && !mBase) mLand.getRecord (index).mModified.mLand->loadData ( ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML | ESM::Land::DATA_VCLR | - ESM::Land::DATA_VTEX); + ESM::Land::DATA_VTEX | ESM::Land::DATA_WNAM); break; } diff --git a/components/esm/loadland.cpp b/components/esm/loadland.cpp index ae73eee52..b1c01fcba 100644 --- a/components/esm/loadland.cpp +++ b/components/esm/loadland.cpp @@ -11,7 +11,7 @@ namespace ESM void Land::LandData::save(ESMWriter &esm) { if (mDataTypes & Land::DATA_VNML) { - esm.writeHNT("VNML", mNormals, sizeof(VNML)); + esm.writeHNT("VNML", mNormals, sizeof(mNormals)); } if (mDataTypes & Land::DATA_VHGT) { VHGT offsets; From 4d46d7ba72b261d3eb5aab6762702e44543bbe73 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 14 Mar 2015 06:07:12 +1100 Subject: [PATCH 0745/3725] Fix some compiler warnings. --- apps/openmw/mwworld/store.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index a887272c5..56f16377b 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -29,7 +29,7 @@ namespace MWWorld virtual bool eraseStatic(const std::string &id) {return false;} virtual void clearDynamic() {} - virtual void write (ESM::ESMWriter& writer) const {} + virtual void write (ESM::ESMWriter& writer, Loading::Listener& progress) const {} virtual void read (ESM::ESMReader& reader, const std::string& id) {} ///< Read into dynamic storage @@ -234,7 +234,7 @@ namespace MWWorld int getDynamicSize() const { - return mDynamic.size(); + return static_cast (mDynamic.size()); // truncated from unsigned __int64 if _MSC_VER && _WIN64 } void listIdentifier(std::vector &list) const { From 4f6c772437228dda02de2ef62d8f36aa4ff707b4 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 14 Mar 2015 06:36:35 +1100 Subject: [PATCH 0746/3725] Fix more warnings. --- apps/opencs/model/world/refcollection.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/world/refcollection.hpp b/apps/opencs/model/world/refcollection.hpp index 4ecc32b2f..46572752e 100644 --- a/apps/opencs/model/world/refcollection.hpp +++ b/apps/opencs/model/world/refcollection.hpp @@ -12,7 +12,7 @@ namespace CSMWorld { struct Cell; - struct UniversalId; + class UniversalId; /// \brief References in cells class RefCollection : public Collection From fd86076db3608ca6d7d3533bf2ab51ec651d308f Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 14 Mar 2015 08:09:19 +1100 Subject: [PATCH 0747/3725] More warning fixes. --- apps/opencs/model/doc/document.hpp | 2 +- apps/opencs/model/doc/documentmanager.hpp | 6 +++--- apps/opencs/model/doc/savingstages.cpp | 2 +- apps/opencs/model/doc/savingstages.hpp | 1 - apps/opencs/model/world/infocollection.cpp | 6 +++--- apps/opencs/model/world/infocollection.hpp | 4 ++-- apps/opencs/model/world/ref.hpp | 2 -- 7 files changed, 10 insertions(+), 13 deletions(-) diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp index f3aef6db6..19866c18d 100644 --- a/apps/opencs/model/doc/document.hpp +++ b/apps/opencs/model/doc/document.hpp @@ -32,7 +32,7 @@ namespace ESM namespace Files { - class ConfigurationManager; + struct ConfigurationManager; } namespace CSMWorld diff --git a/apps/opencs/model/doc/documentmanager.hpp b/apps/opencs/model/doc/documentmanager.hpp index 3202c4fe1..0ae73e70c 100644 --- a/apps/opencs/model/doc/documentmanager.hpp +++ b/apps/opencs/model/doc/documentmanager.hpp @@ -17,7 +17,7 @@ namespace Files { - class ConfigurationManager; + struct ConfigurationManager; } namespace CSMDoc @@ -50,7 +50,7 @@ namespace CSMDoc ///< \param new_ Do not load the last content file in \a files and instead create in an /// appropriate way. - void setResourceDir (const boost::filesystem::path& parResDir); + void setResourceDir (const boost::filesystem::path& parResDir); void setEncoding (ToUTF8::FromType encoding); @@ -61,7 +61,7 @@ namespace CSMDoc private: - boost::filesystem::path mResDir; + boost::filesystem::path mResDir; private slots: diff --git a/apps/opencs/model/doc/savingstages.cpp b/apps/opencs/model/doc/savingstages.cpp index 485ad094b..ef7d1d3af 100644 --- a/apps/opencs/model/doc/savingstages.cpp +++ b/apps/opencs/model/doc/savingstages.cpp @@ -90,7 +90,7 @@ void CSMDoc::WriteHeaderStage::perform (int stage, Messages& messages) CSMDoc::WriteDialogueCollectionStage::WriteDialogueCollectionStage (Document& document, SavingState& state, bool journal) -: mDocument (document), mState (state), +: mState (state), mTopics (journal ? document.getData().getJournals() : document.getData().getTopics()), mInfos (journal ? document.getData().getJournalInfos() : document.getData().getTopicInfos()) {} diff --git a/apps/opencs/model/doc/savingstages.hpp b/apps/opencs/model/doc/savingstages.hpp index 4b16581dc..188f22f96 100644 --- a/apps/opencs/model/doc/savingstages.hpp +++ b/apps/opencs/model/doc/savingstages.hpp @@ -126,7 +126,6 @@ namespace CSMDoc class WriteDialogueCollectionStage : public Stage { - Document& mDocument; SavingState& mState; const CSMWorld::IdCollection& mTopics; CSMWorld::InfoCollection& mInfos; diff --git a/apps/opencs/model/world/infocollection.cpp b/apps/opencs/model/world/infocollection.cpp index 50d09f313..f2d81823c 100644 --- a/apps/opencs/model/world/infocollection.cpp +++ b/apps/opencs/model/world/infocollection.cpp @@ -26,7 +26,7 @@ void CSMWorld::InfoCollection::load (const Info& record, bool base) if (!record2.get().mPrev.empty()) { - index = getIndex (record2.get().mPrev, topic); + index = getInfoIndex (record2.get().mPrev, topic); if (index!=-1) ++index; @@ -34,7 +34,7 @@ void CSMWorld::InfoCollection::load (const Info& record, bool base) if (index==-1 && !record2.get().mNext.empty()) { - index = getIndex (record2.get().mNext, topic); + index = getInfoIndex (record2.get().mNext, topic); } if (index==-1) @@ -60,7 +60,7 @@ void CSMWorld::InfoCollection::load (const Info& record, bool base) } } -int CSMWorld::InfoCollection::getIndex (const std::string& id, const std::string& topic) const +int CSMWorld::InfoCollection::getInfoIndex (const std::string& id, const std::string& topic) const { std::string fullId = Misc::StringUtils::lowerCase (topic) + "#" + id; diff --git a/apps/opencs/model/world/infocollection.hpp b/apps/opencs/model/world/infocollection.hpp index e953effa8..6db47373d 100644 --- a/apps/opencs/model/world/infocollection.hpp +++ b/apps/opencs/model/world/infocollection.hpp @@ -6,7 +6,7 @@ namespace ESM { - class Dialogue; + struct Dialogue; } namespace CSMWorld @@ -22,7 +22,7 @@ namespace CSMWorld void load (const Info& record, bool base); - int getIndex (const std::string& id, const std::string& topic) const; + int getInfoIndex (const std::string& id, const std::string& topic) const; ///< Return index for record \a id or -1 (if not present; deleted records are considered) /// /// \param id info ID without topic prefix diff --git a/apps/opencs/model/world/ref.hpp b/apps/opencs/model/world/ref.hpp index eb62434cf..8ab901a6f 100644 --- a/apps/opencs/model/world/ref.hpp +++ b/apps/opencs/model/world/ref.hpp @@ -5,8 +5,6 @@ namespace CSMWorld { - class Cell; - /// \brief Wrapper for CellRef sub record struct CellRef : public ESM::CellRef { From 2540a901d5387d1fbef7fbc6bb19692b7a45b987 Mon Sep 17 00:00:00 2001 From: Rohit Nirmal Date: Fri, 13 Mar 2015 20:04:47 -0500 Subject: [PATCH 0748/3725] Remove unused variable. --- apps/openmw/mwclass/npc.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index ea506ff9e..d5055fcb2 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -473,7 +473,6 @@ namespace MWClass void Npc::hit(const MWWorld::Ptr& ptr, int type) const { MWBase::World *world = MWBase::Environment::get().getWorld(); - const GMST& gmst = getGmst(); const MWWorld::Store &store = world->getStore().get(); From 17e6244bd6ac594346b0cb23dd6fea62bc9ff7a2 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 14 Mar 2015 12:42:46 +1100 Subject: [PATCH 0749/3725] Yet more warnings suppressed. --- apps/opencs/model/world/commands.hpp | 2 +- apps/opencs/model/world/idtable.hpp | 2 +- apps/opencs/model/world/refidadapter.hpp | 2 +- apps/opencs/view/render/object.hpp | 2 +- apps/opencs/view/tools/reporttable.cpp | 2 +- apps/opencs/view/world/dialoguesubview.cpp | 25 +++++++++++++++------- apps/opencs/view/world/dialoguesubview.hpp | 9 ++++---- apps/opencs/view/world/dragrecordtable.cpp | 2 +- apps/opencs/view/world/dragrecordtable.hpp | 2 +- apps/opencs/view/world/enumdelegate.cpp | 1 - apps/opencs/view/world/regionmap.cpp | 4 ++-- apps/opencs/view/world/table.cpp | 2 +- apps/opencs/view/world/util.cpp | 11 ++++++++++ apps/opencs/view/world/util.hpp | 9 ++++++-- 14 files changed, 50 insertions(+), 25 deletions(-) diff --git a/apps/opencs/model/world/commands.hpp b/apps/opencs/model/world/commands.hpp index 7267c9c8b..3c24b64a5 100644 --- a/apps/opencs/model/world/commands.hpp +++ b/apps/opencs/model/world/commands.hpp @@ -20,7 +20,7 @@ namespace CSMWorld { class IdTable; class IdTable; - class RecordBase; + struct RecordBase; class ModifyCommand : public QUndoCommand { diff --git a/apps/opencs/model/world/idtable.hpp b/apps/opencs/model/world/idtable.hpp index 707d7133b..ea8ab80f9 100644 --- a/apps/opencs/model/world/idtable.hpp +++ b/apps/opencs/model/world/idtable.hpp @@ -10,7 +10,7 @@ namespace CSMWorld { class CollectionBase; - class RecordBase; + struct RecordBase; class IdTable : public IdTableBase { diff --git a/apps/opencs/model/world/refidadapter.hpp b/apps/opencs/model/world/refidadapter.hpp index 3320af190..74c5dfe58 100644 --- a/apps/opencs/model/world/refidadapter.hpp +++ b/apps/opencs/model/world/refidadapter.hpp @@ -9,7 +9,7 @@ namespace CSMWorld { class RefIdColumn; class RefIdData; - class RecordBase; + struct RecordBase; class RefIdAdapter { diff --git a/apps/opencs/view/render/object.hpp b/apps/opencs/view/render/object.hpp index 3ed4fa793..c5a2b73c2 100644 --- a/apps/opencs/view/render/object.hpp +++ b/apps/opencs/view/render/object.hpp @@ -17,7 +17,7 @@ namespace Ogre namespace CSMWorld { class Data; - class CellRef; + struct CellRef; } namespace CSVWorld diff --git a/apps/opencs/view/tools/reporttable.cpp b/apps/opencs/view/tools/reporttable.cpp index da15b4acc..da39c1983 100644 --- a/apps/opencs/view/tools/reporttable.cpp +++ b/apps/opencs/view/tools/reporttable.cpp @@ -30,7 +30,7 @@ void CSVTools::ReportTable::contextMenuEvent (QContextMenuEvent *event) void CSVTools::ReportTable::mouseMoveEvent (QMouseEvent *event) { if (event->buttons() & Qt::LeftButton) - startDrag (*this); + startDragToTable (*this); } void CSVTools::ReportTable::mouseDoubleClickEvent (QMouseEvent *event) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 48009da8d..e383f5e9a 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -40,8 +40,12 @@ QAbstractItemDelegate(parent), mTable(table) {} -void CSVWorld::NotEditableSubDelegate::setEditorData (QLabel* editor, const QModelIndex& index) const +void CSVWorld::NotEditableSubDelegate::setEditorData (QWidget* editor, const QModelIndex& index) const { + QLabel* label = qobject_cast(editor); + if(!label) + return; + QVariant v = index.data(Qt::EditRole); if (!v.isValid()) { @@ -54,16 +58,17 @@ void CSVWorld::NotEditableSubDelegate::setEditorData (QLabel* editor, const QMod if (QVariant::String == v.type()) { - editor->setText(v.toString()); - } else //else we are facing enums + label->setText(v.toString()); + } + else //else we are facing enums { int data = v.toInt(); std::vector enumNames (CSMWorld::Columns::getEnums (static_cast (mTable->getColumnId (index.column())))); - editor->setText(QString::fromUtf8(enumNames.at(data).c_str())); + label->setText(QString::fromUtf8(enumNames.at(data).c_str())); } } -void CSVWorld::NotEditableSubDelegate::setModelData (QWidget* editor, QAbstractItemModel* model, const QModelIndex& index, CSMWorld::ColumnBase::Display display) const +void CSVWorld::NotEditableSubDelegate::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const { //not editable widgets will not save model data } @@ -80,8 +85,7 @@ QSize CSVWorld::NotEditableSubDelegate::sizeHint (const QStyleOptionViewItem& op QWidget* CSVWorld::NotEditableSubDelegate::createEditor (QWidget *parent, const QStyleOptionViewItem& option, - const QModelIndex& index, - CSMWorld::ColumnBase::Display display) const + const QModelIndex& index) const { return new QLabel(parent); } @@ -224,6 +228,11 @@ void CSVWorld::DialogueDelegateDispatcher::setEditorData (QWidget* editor, const } } +void CSVWorld::DialogueDelegateDispatcher::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const +{ + setModelData(editor, model, index, CSMWorld::ColumnBase::Display_None); +} + void CSVWorld::DialogueDelegateDispatcher::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index, CSMWorld::ColumnBase::Display display) const { std::map::const_iterator delegateIt(mDelegates.find(display)); @@ -258,7 +267,7 @@ QWidget* CSVWorld::DialogueDelegateDispatcher::makeEditor(CSMWorld::ColumnBase:: QWidget* editor = NULL; if (! (mTable->flags (index) & Qt::ItemIsEditable)) { - return mNotEditableDelegate.createEditor(qobject_cast(mParent), QStyleOptionViewItem(), index, display); + return mNotEditableDelegate.createEditor(qobject_cast(mParent), QStyleOptionViewItem(), index); } std::map::iterator delegateIt(mDelegates.find(display)); diff --git a/apps/opencs/view/world/dialoguesubview.hpp b/apps/opencs/view/world/dialoguesubview.hpp index 5de2c3ad2..5bd226960 100644 --- a/apps/opencs/view/world/dialoguesubview.hpp +++ b/apps/opencs/view/world/dialoguesubview.hpp @@ -40,9 +40,9 @@ namespace CSVWorld public: NotEditableSubDelegate(const CSMWorld::IdTable* table, QObject * parent = 0); - virtual void setEditorData (QLabel* editor, const QModelIndex& index) const; + virtual void setEditorData (QWidget* editor, const QModelIndex& index) const; - virtual void setModelData (QWidget* editor, QAbstractItemModel* model, const QModelIndex& index, CSMWorld::ColumnBase::Display display) const; + virtual void setModelData (QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const; virtual void paint (QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const; ///< does nothing @@ -52,8 +52,7 @@ namespace CSVWorld virtual QWidget *createEditor (QWidget *parent, const QStyleOptionViewItem& option, - const QModelIndex& index, - CSMWorld::ColumnBase::Display display = CSMWorld::ColumnBase::Display_None) const; + const QModelIndex& index) const; }; //this can't be nested into the DialogueDelegateDispatcher, because it needs to emit signals @@ -119,6 +118,8 @@ namespace CSVWorld virtual void setEditorData (QWidget* editor, const QModelIndex& index) const; + virtual void setModelData (QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const; + virtual void setModelData (QWidget* editor, QAbstractItemModel* model, const QModelIndex& index, CSMWorld::ColumnBase::Display display) const; virtual void paint (QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const; diff --git a/apps/opencs/view/world/dragrecordtable.cpp b/apps/opencs/view/world/dragrecordtable.cpp index c33fa58ad..f9cc4b530 100644 --- a/apps/opencs/view/world/dragrecordtable.cpp +++ b/apps/opencs/view/world/dragrecordtable.cpp @@ -3,7 +3,7 @@ #include "../../model/world/tablemimedata.hpp" #include "dragrecordtable.hpp" -void CSVWorld::DragRecordTable::startDrag (const CSVWorld::DragRecordTable& table) +void CSVWorld::DragRecordTable::startDragToTable (const CSVWorld::DragRecordTable& table) { CSMWorld::TableMimeData* mime = new CSMWorld::TableMimeData (table.getDraggedRecords(), mDocument); diff --git a/apps/opencs/view/world/dragrecordtable.hpp b/apps/opencs/view/world/dragrecordtable.hpp index 8c5f1b841..5b7e68490 100644 --- a/apps/opencs/view/world/dragrecordtable.hpp +++ b/apps/opencs/view/world/dragrecordtable.hpp @@ -33,7 +33,7 @@ namespace CSVWorld void setEditLock(bool locked); protected: - void startDrag(const DragRecordTable& table); + void startDragToTable(const DragRecordTable& table); void dragEnterEvent(QDragEnterEvent *event); diff --git a/apps/opencs/view/world/enumdelegate.cpp b/apps/opencs/view/world/enumdelegate.cpp index 168e5cb0a..7c305b1b6 100644 --- a/apps/opencs/view/world/enumdelegate.cpp +++ b/apps/opencs/view/world/enumdelegate.cpp @@ -46,7 +46,6 @@ QWidget *CSVWorld::EnumDelegate::createEditor(QWidget *parent, const QModelIndex& index) const { return createEditor(parent, option, index, CSMWorld::ColumnBase::Display_None); - //overloading virtual functions is HARD } QWidget *CSVWorld::EnumDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem& option, diff --git a/apps/opencs/view/world/regionmap.cpp b/apps/opencs/view/world/regionmap.cpp index 9497e4054..316c61a88 100644 --- a/apps/opencs/view/world/regionmap.cpp +++ b/apps/opencs/view/world/regionmap.cpp @@ -345,7 +345,7 @@ void CSVWorld::RegionMap::viewInTable() void CSVWorld::RegionMap::mouseMoveEvent (QMouseEvent* event) { - startDrag(*this); + startDragToTable(*this); } std::vector< CSMWorld::UniversalId > CSVWorld::RegionMap::getDraggedRecords() const @@ -400,7 +400,7 @@ void CSVWorld::RegionMap::dropEvent (QDropEvent* event) QModelIndex index2(cellsModel->getModelIndex (cellId, cellsModel->findColumnIndex (CSMWorld::Columns::ColumnId_Region))); - mDocument.getUndoStack().push(new CSMWorld::ModifyCommand + mDocument.getUndoStack().push(new CSMWorld::ModifyCommand (*cellsModel, index2, QString::fromUtf8(record.getId().c_str()))); mRegionId = record.getId(); diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index e864e4ed2..7b8b97bc8 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -635,7 +635,7 @@ void CSVWorld::Table::mouseMoveEvent (QMouseEvent* event) { if (event->buttons() & Qt::LeftButton) { - startDrag(*this); + startDragToTable(*this); } } diff --git a/apps/opencs/view/world/util.cpp b/apps/opencs/view/world/util.cpp index 91460c3df..b0f8a035a 100644 --- a/apps/opencs/view/world/util.cpp +++ b/apps/opencs/view/world/util.cpp @@ -139,6 +139,12 @@ void CSVWorld::CommandDelegate::setModelData (QWidget *editor, QAbstractItemMode ///< \todo provide some kind of feedback to the user, indicating that editing is currently not possible. } +QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleOptionViewItem& option, + const QModelIndex& index) const +{ + return createEditor (parent, option, index, CSMWorld::ColumnBase::Display_None); +} + QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleOptionViewItem& option, const QModelIndex& index, CSMWorld::ColumnBase::Display display) const { @@ -230,6 +236,11 @@ bool CSVWorld::CommandDelegate::isEditLocked() const return mEditLock; } +void CSVWorld::CommandDelegate::setEditorData (QWidget *editor, const QModelIndex& index) const +{ + setEditorData (editor, index, false); +} + void CSVWorld::CommandDelegate::setEditorData (QWidget *editor, const QModelIndex& index, bool tryDisplay) const { QVariant v = index.data(Qt::EditRole); diff --git a/apps/opencs/view/world/util.hpp b/apps/opencs/view/world/util.hpp index b4d972bf3..10011798d 100644 --- a/apps/opencs/view/world/util.hpp +++ b/apps/opencs/view/world/util.hpp @@ -130,10 +130,14 @@ namespace CSVWorld virtual void setModelData (QWidget *editor, QAbstractItemModel *model, const QModelIndex& index) const; + virtual QWidget *createEditor (QWidget *parent, + const QStyleOptionViewItem& option, + const QModelIndex& index) const; + virtual QWidget *createEditor (QWidget *parent, const QStyleOptionViewItem& option, const QModelIndex& index, - CSMWorld::ColumnBase::Display display = CSMWorld::ColumnBase::Display_None) const; + CSMWorld::ColumnBase::Display display) const; void setEditLock (bool locked); @@ -141,8 +145,9 @@ namespace CSVWorld ///< \return Does column require update? - virtual void setEditorData (QWidget *editor, const QModelIndex& index, bool tryDisplay = false) const; + virtual void setEditorData (QWidget *editor, const QModelIndex& index) const; + virtual void setEditorData (QWidget *editor, const QModelIndex& index, bool tryDisplay) const; public slots: From 15b9a628ac4729258d1ad93a94aae0a1e4889961 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 14 Mar 2015 19:41:55 +1100 Subject: [PATCH 0750/3725] Fix the name of DragRecordTable::startDrag method. Make the compiler be quiet about BulletShapeLoader's hidden overloaded methods. --- apps/opencs/view/tools/reporttable.cpp | 2 +- apps/opencs/view/world/dragrecordtable.cpp | 2 +- apps/opencs/view/world/dragrecordtable.hpp | 2 +- apps/opencs/view/world/regionmap.cpp | 2 +- apps/opencs/view/world/table.cpp | 2 +- libs/openengine/bullet/BulletShapeLoader.cpp | 7 +++++++ libs/openengine/bullet/BulletShapeLoader.h | 8 +++++++- libs/openengine/bullet/physic.cpp | 2 +- 8 files changed, 20 insertions(+), 7 deletions(-) diff --git a/apps/opencs/view/tools/reporttable.cpp b/apps/opencs/view/tools/reporttable.cpp index da39c1983..809a39fa4 100644 --- a/apps/opencs/view/tools/reporttable.cpp +++ b/apps/opencs/view/tools/reporttable.cpp @@ -30,7 +30,7 @@ void CSVTools::ReportTable::contextMenuEvent (QContextMenuEvent *event) void CSVTools::ReportTable::mouseMoveEvent (QMouseEvent *event) { if (event->buttons() & Qt::LeftButton) - startDragToTable (*this); + startDragFromTable (*this); } void CSVTools::ReportTable::mouseDoubleClickEvent (QMouseEvent *event) diff --git a/apps/opencs/view/world/dragrecordtable.cpp b/apps/opencs/view/world/dragrecordtable.cpp index f9cc4b530..f45c45809 100644 --- a/apps/opencs/view/world/dragrecordtable.cpp +++ b/apps/opencs/view/world/dragrecordtable.cpp @@ -3,7 +3,7 @@ #include "../../model/world/tablemimedata.hpp" #include "dragrecordtable.hpp" -void CSVWorld::DragRecordTable::startDragToTable (const CSVWorld::DragRecordTable& table) +void CSVWorld::DragRecordTable::startDragFromTable (const CSVWorld::DragRecordTable& table) { CSMWorld::TableMimeData* mime = new CSMWorld::TableMimeData (table.getDraggedRecords(), mDocument); diff --git a/apps/opencs/view/world/dragrecordtable.hpp b/apps/opencs/view/world/dragrecordtable.hpp index 5b7e68490..4996c03ac 100644 --- a/apps/opencs/view/world/dragrecordtable.hpp +++ b/apps/opencs/view/world/dragrecordtable.hpp @@ -33,7 +33,7 @@ namespace CSVWorld void setEditLock(bool locked); protected: - void startDragToTable(const DragRecordTable& table); + void startDragFromTable(const DragRecordTable& table); void dragEnterEvent(QDragEnterEvent *event); diff --git a/apps/opencs/view/world/regionmap.cpp b/apps/opencs/view/world/regionmap.cpp index 316c61a88..bc96b0952 100644 --- a/apps/opencs/view/world/regionmap.cpp +++ b/apps/opencs/view/world/regionmap.cpp @@ -345,7 +345,7 @@ void CSVWorld::RegionMap::viewInTable() void CSVWorld::RegionMap::mouseMoveEvent (QMouseEvent* event) { - startDragToTable(*this); + startDragFromTable(*this); } std::vector< CSMWorld::UniversalId > CSVWorld::RegionMap::getDraggedRecords() const diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index 7b8b97bc8..97a3bc2e3 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -635,7 +635,7 @@ void CSVWorld::Table::mouseMoveEvent (QMouseEvent* event) { if (event->buttons() & Qt::LeftButton) { - startDragToTable(*this); + startDragFromTable(*this); } } diff --git a/libs/openengine/bullet/BulletShapeLoader.cpp b/libs/openengine/bullet/BulletShapeLoader.cpp index fd9204b44..92d56b42c 100644 --- a/libs/openengine/bullet/BulletShapeLoader.cpp +++ b/libs/openengine/bullet/BulletShapeLoader.cpp @@ -117,6 +117,13 @@ BulletShapePtr BulletShapeManager::create (const Ogre::String& name, const Ogre: return createResource(name,group,isManual,loader,createParams).staticCast(); } +Ogre::ResourcePtr BulletShapeManager::load(const Ogre::String &name, const Ogre::String &group, + bool isManual, Ogre::ManualResourceLoader *loader, const Ogre::NameValuePairList *loadParams, + bool backgroundThread) +{ + return this->load(name, group); +} + 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 31ee3cc7d..907ff8bfe 100644 --- a/libs/openengine/bullet/BulletShapeLoader.h +++ b/libs/openengine/bullet/BulletShapeLoader.h @@ -92,6 +92,11 @@ private: /** \brief Private operator= . This is a forbidden operation. */ BulletShapeManager& operator=(const BulletShapeManager &); + // Not intended to be used, declared here to keep the compiler from complaining + // about hidden virtual methods. + virtual Ogre::ResourcePtr load(const Ogre::String &name, const Ogre::String &group, + bool isManual, Ogre::ManualResourceLoader *loader, const Ogre::NameValuePairList *loadParams, + bool backgroundThread); public: @@ -101,7 +106,8 @@ public: /// Get a resource by name /// @see ResourceManager::getByName - BulletShapePtr getByName(const Ogre::String& name, const Ogre::String& groupName = Ogre::ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME); + BulletShapePtr getByName(const Ogre::String& name, + const Ogre::String& groupName = Ogre::ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME); /// Create a new shape /// @see ResourceManager::createResource diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index 81a2eb043..013ef1003 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -828,7 +828,7 @@ namespace Physic if (callback.hasHit()) return std::make_pair(true, callback.m_closestHitFraction); else - return std::make_pair(false, 1); + return std::make_pair(false, 1.0f); } std::vector< std::pair > PhysicEngine::rayTest2(const btVector3& from, const btVector3& to, int filterGroup) From c0dfad23b355dda2d2f530001868fb1eff98ba0e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 14 Mar 2015 12:00:24 +0100 Subject: [PATCH 0751/3725] Fixed editor operation multi-threading (Fixes #923) --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/doc/document.cpp | 3 +- apps/opencs/model/doc/document.hpp | 4 +- apps/opencs/model/doc/operation.cpp | 25 +++++---- apps/opencs/model/doc/operation.hpp | 13 +++-- apps/opencs/model/doc/operationholder.cpp | 65 +++++++++++++++++++++++ apps/opencs/model/doc/operationholder.hpp | 56 +++++++++++++++++++ apps/opencs/model/doc/runner.cpp | 4 +- apps/opencs/model/doc/runner.hpp | 4 +- apps/opencs/model/tools/tools.cpp | 62 +++++++++++---------- apps/opencs/model/tools/tools.hpp | 11 ++-- 11 files changed, 195 insertions(+), 54 deletions(-) create mode 100644 apps/opencs/model/doc/operationholder.cpp create mode 100644 apps/opencs/model/doc/operationholder.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 7eacfd7ef..e618d2961 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -5,7 +5,7 @@ set (OPENCS_SRC main.cpp opencs_units (. editor) opencs_units (model/doc - document operation saving documentmanager loader runner + document operation saving documentmanager loader runner operationholder ) opencs_units_noqt (model/doc diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index e688a9474..7d27143b4 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -2254,7 +2254,8 @@ CSMDoc::Document::Document (const Files::ConfigurationManager& configuration, mTools (*this), mResDir(resDir), mProjectPath ((configuration.getUserDataPath() / "projects") / (savePath.filename().string() + ".project")), - mSaving (*this, mProjectPath, encoding), + mSavingOperation (*this, mProjectPath, encoding), + mSaving (&mSavingOperation), mRunner (mProjectPath), mPhysics(boost::shared_ptr()) { if (mContentFiles.empty()) diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp index f3aef6db6..a0905e5ad 100644 --- a/apps/opencs/model/doc/document.hpp +++ b/apps/opencs/model/doc/document.hpp @@ -20,6 +20,7 @@ #include "saving.hpp" #include "blacklist.hpp" #include "runner.hpp" +#include "operationholder.hpp" class QAbstractItemModel; @@ -59,7 +60,8 @@ namespace CSMDoc CSMWorld::Data mData; CSMTools::Tools mTools; boost::filesystem::path mProjectPath; - Saving mSaving; + Saving mSavingOperation; + OperationHolder mSaving; boost::filesystem::path mResDir; Blacklist mBlacklist; Runner mRunner; diff --git a/apps/opencs/model/doc/operation.cpp b/apps/opencs/model/doc/operation.cpp index e728050f4..3f1674f50 100644 --- a/apps/opencs/model/doc/operation.cpp +++ b/apps/opencs/model/doc/operation.cpp @@ -29,9 +29,9 @@ void CSMDoc::Operation::prepareStages() CSMDoc::Operation::Operation (int type, bool ordered, bool finalAlways) : mType (type), mStages(std::vector >()), mCurrentStage(mStages.begin()), mCurrentStep(0), mCurrentStepTotal(0), mTotalSteps(0), mOrdered (ordered), - mFinalAlways (finalAlways), mError(false) + mFinalAlways (finalAlways), mError(false), mConnected (false) { - connect (this, SIGNAL (finished()), this, SLOT (operationDone())); + mTimer = new QTimer (this); } CSMDoc::Operation::~Operation() @@ -42,15 +42,17 @@ CSMDoc::Operation::~Operation() void CSMDoc::Operation::run() { + mTimer->stop(); + + if (!mConnected) + { + connect (mTimer, SIGNAL (timeout()), this, SLOT (executeStage())); + mConnected = true; + } + prepareStages(); - QTimer timer; - - timer.connect (&timer, SIGNAL (timeout()), this, SLOT (executeStage())); - - timer.start (0); - - exec(); + mTimer->start (0); } void CSMDoc::Operation::appendStage (Stage *stage) @@ -65,7 +67,7 @@ bool CSMDoc::Operation::hasError() const void CSMDoc::Operation::abort() { - if (!isRunning()) + if (!mTimer->isActive()) return; mError = true; @@ -116,10 +118,11 @@ void CSMDoc::Operation::executeStage() emit reportMessage (iter->mId, iter->mMessage, iter->mHint, mType); if (mCurrentStage==mStages.end()) - exit(); + operationDone(); } void CSMDoc::Operation::operationDone() { + mTimer->stop(); emit done (mType, mError); } diff --git a/apps/opencs/model/doc/operation.hpp b/apps/opencs/model/doc/operation.hpp index 3c9467754..a6217fe2d 100644 --- a/apps/opencs/model/doc/operation.hpp +++ b/apps/opencs/model/doc/operation.hpp @@ -3,7 +3,8 @@ #include -#include +#include +#include namespace CSMWorld { @@ -14,7 +15,7 @@ namespace CSMDoc { class Stage; - class Operation : public QThread + class Operation : public QObject { Q_OBJECT @@ -27,6 +28,8 @@ namespace CSMDoc int mOrdered; bool mFinalAlways; bool mError; + bool mConnected; + QTimer *mTimer; void prepareStages(); @@ -38,8 +41,6 @@ namespace CSMDoc virtual ~Operation(); - virtual void run(); - void appendStage (Stage *stage); ///< The ownership of \a stage is transferred to *this. /// @@ -60,6 +61,8 @@ namespace CSMDoc void abort(); + void run(); + private slots: void executeStage(); @@ -68,4 +71,4 @@ namespace CSMDoc }; } -#endif \ No newline at end of file +#endif diff --git a/apps/opencs/model/doc/operationholder.cpp b/apps/opencs/model/doc/operationholder.cpp new file mode 100644 index 000000000..d79e14023 --- /dev/null +++ b/apps/opencs/model/doc/operationholder.cpp @@ -0,0 +1,65 @@ + +#include "operationholder.hpp" + +#include "operation.hpp" + +CSMDoc::OperationHolder::OperationHolder (Operation *operation) : mRunning (false) +{ + if (operation) + setOperation (operation); +} + +void CSMDoc::OperationHolder::setOperation (Operation *operation) +{ + mOperation = operation; + mOperation->moveToThread (&mThread); + + connect ( + mOperation, SIGNAL (progress (int, int, int)), + this, SIGNAL (progress (int, int, int))); + + connect ( + mOperation, SIGNAL (reportMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int)), + this, SIGNAL (reportMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int))); + + connect ( + mOperation, SIGNAL (done (int, bool)), + this, SLOT (doneSlot (int, bool))); + + connect (this, SIGNAL (abortSignal()), mOperation, SLOT (abort())); + + connect (&mThread, SIGNAL (started()), mOperation, SLOT (run())); +} + +bool CSMDoc::OperationHolder::isRunning() const +{ + return mRunning; +} + +void CSMDoc::OperationHolder::start() +{ + mRunning = true; + mThread.start(); +} + +void CSMDoc::OperationHolder::abort() +{ + mRunning = false; + emit abortSignal(); +} + +void CSMDoc::OperationHolder::abortAndWait() +{ + if (mRunning) + { + mThread.quit(); + mThread.wait(); + } +} + +void CSMDoc::OperationHolder::doneSlot (int type, bool failed) +{ + mRunning = false; + mThread.quit(); + emit done (type, failed); +} diff --git a/apps/opencs/model/doc/operationholder.hpp b/apps/opencs/model/doc/operationholder.hpp new file mode 100644 index 000000000..6fe6df053 --- /dev/null +++ b/apps/opencs/model/doc/operationholder.hpp @@ -0,0 +1,56 @@ +#ifndef CSM_DOC_OPERATIONHOLDER_H +#define CSM_DOC_OPERATIONHOLDER_H + +#include +#include + +namespace CSMWorld +{ + class UniversalId; +} + +namespace CSMDoc +{ + class Operation; + + class OperationHolder : public QObject + { + Q_OBJECT + + QThread mThread; + Operation *mOperation; + bool mRunning; + + public: + + OperationHolder (Operation *operation = 0); + + void setOperation (Operation *operation); + + bool isRunning() const; + + void start(); + + void abort(); + + // Abort and wait until thread has finished. + void abortAndWait(); + + private slots: + + void doneSlot (int type, bool failed); + + signals: + + void progress (int current, int max, int type); + + void reportMessage (const CSMWorld::UniversalId& id, const std::string& message, + const std::string& hint, int type); + + void done (int type, bool failed); + + void abortSignal(); + }; +} + +#endif diff --git a/apps/opencs/model/doc/runner.cpp b/apps/opencs/model/doc/runner.cpp index d679c1890..14fe0cda8 100644 --- a/apps/opencs/model/doc/runner.cpp +++ b/apps/opencs/model/doc/runner.cpp @@ -6,7 +6,7 @@ #include #include -#include "operation.hpp" +#include "operationholder.hpp" CSMDoc::Runner::Runner (const boost::filesystem::path& projectPath) : mRunning (false), mStartup (0), mProjectPath (projectPath) @@ -145,7 +145,7 @@ void CSMDoc::Runner::readyReadStandardOutput() } -CSMDoc::SaveWatcher::SaveWatcher (Runner *runner, Operation *operation) +CSMDoc::SaveWatcher::SaveWatcher (Runner *runner, OperationHolder *operation) : QObject (runner), mRunner (runner) { connect (operation, SIGNAL (done (int, bool)), this, SLOT (saveDone (int, bool))); diff --git a/apps/opencs/model/doc/runner.hpp b/apps/opencs/model/doc/runner.hpp index 38b52a73b..517122492 100644 --- a/apps/opencs/model/doc/runner.hpp +++ b/apps/opencs/model/doc/runner.hpp @@ -16,6 +16,8 @@ class QTemporaryFile; namespace CSMDoc { + class OperationHolder; + class Runner : public QObject { Q_OBJECT @@ -74,7 +76,7 @@ namespace CSMDoc public: /// *this attaches itself to runner - SaveWatcher (Runner *runner, Operation *operation); + SaveWatcher (Runner *runner, OperationHolder *operation); private slots: diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index 2139f890f..170ea8ccd 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -26,30 +26,30 @@ #include "referencecheck.hpp" #include "startscriptcheck.hpp" -CSMDoc::Operation *CSMTools::Tools::get (int type) +CSMDoc::OperationHolder *CSMTools::Tools::get (int type) { switch (type) { - case CSMDoc::State_Verifying: return mVerifier; + case CSMDoc::State_Verifying: return &mVerifier; } return 0; } -const CSMDoc::Operation *CSMTools::Tools::get (int type) const +const CSMDoc::OperationHolder *CSMTools::Tools::get (int type) const { return const_cast (this)->get (type); } -CSMDoc::Operation *CSMTools::Tools::getVerifier() +CSMDoc::OperationHolder *CSMTools::Tools::getVerifier() { - if (!mVerifier) + if (!mVerifierOperation) { - mVerifier = new CSMDoc::Operation (CSMDoc::State_Verifying, false); + mVerifierOperation = new CSMDoc::Operation (CSMDoc::State_Verifying, false); - connect (mVerifier, SIGNAL (progress (int, int, int)), this, SIGNAL (progress (int, int, int))); - connect (mVerifier, SIGNAL (done (int, bool)), this, SIGNAL (done (int, bool))); - connect (mVerifier, + connect (&mVerifier, SIGNAL (progress (int, int, int)), this, SIGNAL (progress (int, int, int))); + connect (&mVerifier, SIGNAL (done (int, bool)), this, SIGNAL (done (int, bool))); + connect (&mVerifier, SIGNAL (reportMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int)), this, SLOT (verifierMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int))); @@ -60,46 +60,48 @@ CSMDoc::Operation *CSMTools::Tools::getVerifier() mandatoryIds.push_back ("Month"); mandatoryIds.push_back ("PCRace"); - mVerifier->appendStage (new MandatoryIdStage (mData.getGlobals(), + mVerifierOperation->appendStage (new MandatoryIdStage (mData.getGlobals(), CSMWorld::UniversalId (CSMWorld::UniversalId::Type_Globals), mandatoryIds)); - mVerifier->appendStage (new SkillCheckStage (mData.getSkills())); + mVerifierOperation->appendStage (new SkillCheckStage (mData.getSkills())); - mVerifier->appendStage (new ClassCheckStage (mData.getClasses())); + mVerifierOperation->appendStage (new ClassCheckStage (mData.getClasses())); - mVerifier->appendStage (new FactionCheckStage (mData.getFactions())); + mVerifierOperation->appendStage (new FactionCheckStage (mData.getFactions())); - mVerifier->appendStage (new RaceCheckStage (mData.getRaces())); + mVerifierOperation->appendStage (new RaceCheckStage (mData.getRaces())); - mVerifier->appendStage (new SoundCheckStage (mData.getSounds())); + mVerifierOperation->appendStage (new SoundCheckStage (mData.getSounds())); - mVerifier->appendStage (new RegionCheckStage (mData.getRegions())); + mVerifierOperation->appendStage (new RegionCheckStage (mData.getRegions())); - mVerifier->appendStage (new BirthsignCheckStage (mData.getBirthsigns())); + mVerifierOperation->appendStage (new BirthsignCheckStage (mData.getBirthsigns())); - mVerifier->appendStage (new SpellCheckStage (mData.getSpells())); + mVerifierOperation->appendStage (new SpellCheckStage (mData.getSpells())); - mVerifier->appendStage (new ReferenceableCheckStage (mData.getReferenceables().getDataSet(), mData.getRaces(), mData.getClasses(), mData.getFactions())); + mVerifierOperation->appendStage (new ReferenceableCheckStage (mData.getReferenceables().getDataSet(), mData.getRaces(), mData.getClasses(), mData.getFactions())); - mVerifier->appendStage (new ReferenceCheckStage(mData.getReferences(), mData.getReferenceables(), mData.getCells(), mData.getFactions())); + mVerifierOperation->appendStage (new ReferenceCheckStage(mData.getReferences(), mData.getReferenceables(), mData.getCells(), mData.getFactions())); - mVerifier->appendStage (new ScriptCheckStage (mDocument)); + mVerifierOperation->appendStage (new ScriptCheckStage (mDocument)); - mVerifier->appendStage (new StartScriptCheckStage (mData.getStartScripts(), mData.getScripts())); + mVerifierOperation->appendStage (new StartScriptCheckStage (mData.getStartScripts(), mData.getScripts())); - mVerifier->appendStage( + mVerifierOperation->appendStage( new BodyPartCheckStage( mData.getBodyParts(), mData.getResources( CSMWorld::UniversalId( CSMWorld::UniversalId::Type_Meshes )), mData.getRaces() )); + + mVerifier.setOperation (mVerifierOperation); } - return mVerifier; + return &mVerifier; } CSMTools::Tools::Tools (CSMDoc::Document& document) -: mDocument (document), mData (document.getData()), mVerifier (0), mNextReportNumber (0) +: mDocument (document), mData (document.getData()), mVerifierOperation (0), mNextReportNumber (0) { // index 0: load error log mReports.insert (std::make_pair (mNextReportNumber++, new ReportModel)); @@ -108,7 +110,11 @@ CSMTools::Tools::Tools (CSMDoc::Document& document) CSMTools::Tools::~Tools() { - delete mVerifier; + if (mVerifierOperation) + { + mVerifier.abortAndWait(); + delete mVerifierOperation; + } for (std::map::iterator iter (mReports.begin()); iter!=mReports.end(); ++iter) delete iter->second; @@ -126,7 +132,7 @@ CSMWorld::UniversalId CSMTools::Tools::runVerifier() void CSMTools::Tools::abortOperation (int type) { - if (CSMDoc::Operation *operation = get (type)) + if (CSMDoc::OperationHolder *operation = get (type)) operation->abort(); } @@ -141,7 +147,7 @@ int CSMTools::Tools::getRunningOperations() const int result = 0; for (int i=0; sOperations[i]!=-1; ++i) - if (const CSMDoc::Operation *operation = get (sOperations[i])) + if (const CSMDoc::OperationHolder *operation = get (sOperations[i])) if (operation->isRunning()) result |= sOperations[i]; diff --git a/apps/opencs/model/tools/tools.hpp b/apps/opencs/model/tools/tools.hpp index 5125a3638..b8ded8a83 100644 --- a/apps/opencs/model/tools/tools.hpp +++ b/apps/opencs/model/tools/tools.hpp @@ -5,6 +5,8 @@ #include +#include "../doc/operationholder.hpp" + namespace CSMWorld { class Data; @@ -27,7 +29,8 @@ namespace CSMTools CSMDoc::Document& mDocument; CSMWorld::Data& mData; - CSMDoc::Operation *mVerifier; + CSMDoc::Operation *mVerifierOperation; + CSMDoc::OperationHolder mVerifier; std::map mReports; int mNextReportNumber; std::map mActiveReports; // type, report number @@ -36,12 +39,12 @@ namespace CSMTools Tools (const Tools&); Tools& operator= (const Tools&); - CSMDoc::Operation *getVerifier(); + CSMDoc::OperationHolder *getVerifier(); - CSMDoc::Operation *get (int type); + CSMDoc::OperationHolder *get (int type); ///< Returns a 0-pointer, if operation hasn't been used yet. - const CSMDoc::Operation *get (int type) const; + const CSMDoc::OperationHolder *get (int type) const; ///< Returns a 0-pointer, if operation hasn't been used yet. public: From 2ef7fc4e2c4c5e0ecf3f15bbec027b796a452a78 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 15 Mar 2015 08:08:55 +1300 Subject: [PATCH 0752/3725] Installer work for Windows (Fixes #1621) 1. Correctly reads Windows registry for vanilla MW install location. 2. Populates existing installation page with location of vanilla, when found. 3. On Windows, installer wizard now gets to Import page. --- apps/wizard/componentselectionpage.cpp | 4 ++++ apps/wizard/existinginstallationpage.cpp | 6 +----- apps/wizard/mainwizard.cpp | 25 +++++++++++++++++------- apps/wizard/mainwizard.hpp | 2 ++ components/files/windowspath.cpp | 15 +++----------- 5 files changed, 28 insertions(+), 24 deletions(-) diff --git a/apps/wizard/componentselectionpage.cpp b/apps/wizard/componentselectionpage.cpp index 1fcde7857..21a5c58d9 100644 --- a/apps/wizard/componentselectionpage.cpp +++ b/apps/wizard/componentselectionpage.cpp @@ -156,9 +156,13 @@ bool Wizard::ComponentSelectionPage::validatePage() int Wizard::ComponentSelectionPage::nextId() const { +#ifdef OPENMW_USE_UNSHIELD if (isCommitPage()) { return MainWizard::Page_Installation; } else { return MainWizard::Page_Import; } +#else + return MainWizard::Page_Import; +#endif } diff --git a/apps/wizard/existinginstallationpage.cpp b/apps/wizard/existinginstallationpage.cpp index 83ea20f5a..f821b38ba 100644 --- a/apps/wizard/existinginstallationpage.cpp +++ b/apps/wizard/existinginstallationpage.cpp @@ -29,11 +29,7 @@ void Wizard::ExistingInstallationPage::initializePage() QStringList paths(mWizard->mInstallations.keys()); // Hide the default item if there are installations to choose from - if (paths.isEmpty()) { - installationsList->item(0)->setHidden(false); - } else { - installationsList->item(0)->setHidden(true); - } + installationsList->item(0)->setHidden(!paths.isEmpty()); foreach (const QString &path, paths) { QListWidgetItem *item = new QListWidgetItem(path); diff --git a/apps/wizard/mainwizard.cpp b/apps/wizard/mainwizard.cpp index a1370b125..a61daa5a4 100644 --- a/apps/wizard/mainwizard.cpp +++ b/apps/wizard/mainwizard.cpp @@ -62,6 +62,12 @@ Wizard::MainWizard::MainWizard(QWidget *parent) : setupLauncherSettings(); setupInstallations(); setupPages(); + + const boost::filesystem::path& installedPath = mCfgMgr.getInstallPath(); + if (!installedPath.empty()) + { + addInstallation(toQString(installedPath)); + } } Wizard::MainWizard::~MainWizard() @@ -71,7 +77,7 @@ Wizard::MainWizard::~MainWizard() void Wizard::MainWizard::setupLog() { - QString logPath(QString::fromUtf8(mCfgMgr.getLogPath().string().c_str())); + QString logPath(toQString(mCfgMgr.getLogPath())); logPath.append(QLatin1String("wizard.log")); QFile file(logPath); @@ -93,7 +99,7 @@ void Wizard::MainWizard::setupLog() void Wizard::MainWizard::addLogText(const QString &text) { - QString logPath(QString::fromUtf8(mCfgMgr.getLogPath().string().c_str())); + QString logPath(toQString(mCfgMgr.getLogPath())); logPath.append(QLatin1String("wizard.log")); QFile file(logPath); @@ -121,8 +127,8 @@ void Wizard::MainWizard::addLogText(const QString &text) void Wizard::MainWizard::setupGameSettings() { - QString userPath(QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str())); - QString globalPath(QString::fromUtf8(mCfgMgr.getGlobalPath().string().c_str())); + QString userPath(toQString(mCfgMgr.getUserConfigPath())); + QString globalPath(toQString(mCfgMgr.getGlobalPath())); QString message(tr("

Could not open %1 for reading

\

Please make sure you have the right permissions \ and try again.

")); @@ -181,7 +187,7 @@ void Wizard::MainWizard::setupGameSettings() void Wizard::MainWizard::setupLauncherSettings() { - QString path(QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str())); + QString path(toQString(mCfgMgr.getUserConfigPath())); path.append(QLatin1String(Config::LauncherSettings::sLauncherConfigFileName)); QString message(tr("

Could not open %1 for reading

\ @@ -228,7 +234,7 @@ void Wizard::MainWizard::runSettingsImporter() QString path(field(QLatin1String("installation.path")).toString()); // Create the file if it doesn't already exist, else the importer will fail - QString userPath(QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str())); + QString userPath(toQString(mCfgMgr.getUserConfigPath())); QFile file(userPath + QLatin1String("openmw.cfg")); if (!file.exists()) { @@ -387,7 +393,7 @@ void Wizard::MainWizard::writeSettings() mGameSettings.removeDataDir(path); mGameSettings.addDataDir(path); - QString userPath(QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str())); + QString userPath(toQString(mCfgMgr.getUserConfigPath())); QDir dir(userPath); if (!dir.exists()) { @@ -460,3 +466,8 @@ bool Wizard::MainWizard::findFiles(const QString &name, const QString &path) return (dir.entryList().contains(name + QLatin1String(".esm"), Qt::CaseInsensitive) && dir.entryList().contains(name + QLatin1String(".bsa"), Qt::CaseInsensitive)); } + +QString Wizard::MainWizard::toQString(const boost::filesystem::path& path) +{ + return QString::fromUtf8(path.string().c_str()); +} diff --git a/apps/wizard/mainwizard.hpp b/apps/wizard/mainwizard.hpp index c22f20c25..7f6e48a87 100644 --- a/apps/wizard/mainwizard.hpp +++ b/apps/wizard/mainwizard.hpp @@ -59,6 +59,8 @@ namespace Wizard void addLogText(const QString &text); private: + /// convert boost::filesystem::path to QString + QString toQString(const boost::filesystem::path& path); void setupLog(); void setupGameSettings(); diff --git a/components/files/windowspath.cpp b/components/files/windowspath.cpp index 6b58304a0..0df782702 100644 --- a/components/files/windowspath.cpp +++ b/components/files/windowspath.cpp @@ -94,18 +94,8 @@ boost::filesystem::path WindowsPath::getInstallPath() const HKEY hKey; - BOOL f64 = FALSE; - LPCTSTR regkey; - if ((IsWow64Process(GetCurrentProcess(), &f64) && f64) || sizeof(void*) == 8) - { - regkey = "SOFTWARE\\Wow6432Node\\Bethesda Softworks\\Morrowind"; - } - else - { - regkey = "SOFTWARE\\Bethesda Softworks\\Morrowind"; - } - - if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT(regkey), 0, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS) + LPCTSTR regkey = TEXT("SOFTWARE\\Bethesda Softworks\\Morrowind"); + if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, regkey, 0, KEY_READ | KEY_WOW64_32KEY, &hKey) == ERROR_SUCCESS) { //Key existed, let's try to read the install dir std::vector buf(512); @@ -115,6 +105,7 @@ boost::filesystem::path WindowsPath::getInstallPath() const { installPath = &buf[0]; } + RegCloseKey(hKey); } return installPath; From 1d7f3474fa139a013e0255be468333d842fd4ceb Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 15 Mar 2015 08:49:03 +1300 Subject: [PATCH 0753/3725] Fixed more MSVC 2013 warnings. --- apps/openmw/main.cpp | 2 +- apps/openmw/mwgui/tradewindow.cpp | 2 +- apps/openmw/mwmechanics/actors.cpp | 8 ++++---- apps/openmw/mwmechanics/combat.cpp | 2 +- apps/openmw/mwsound/ffmpeg_decoder.cpp | 10 +++++----- components/bsa/bsa_file.cpp | 2 +- components/compiler/exprparser.cpp | 2 +- extern/ogre-ffmpeg-videoplayer/videostate.cpp | 16 ++++++++-------- extern/shiny/Platforms/Ogre/OgrePass.cpp | 2 +- libs/openengine/bullet/BtOgre.cpp | 2 +- libs/openengine/bullet/BtOgreGP.h | 1 - 11 files changed, 24 insertions(+), 25 deletions(-) diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 82fda060e..070136dfd 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -290,7 +290,7 @@ public: std::streamsize write(const char *str, std::streamsize size) { // Make a copy for null termination - std::string tmp (str, size); + std::string tmp (str, static_cast(size)); // Write string to Visual Studio Debug output OutputDebugString (tmp.c_str ()); return size; diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 841e2e185..dc6e2de5a 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -343,7 +343,7 @@ namespace MWGui else d = int(100 * (b - a) / a); - float clampedDisposition = std::max(0,std::min(MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mPtr) + int clampedDisposition = std::max(0, std::min(MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mPtr) + MWBase::Environment::get().getDialogueManager()->getTemporaryDispositionChange(),100)); const MWMechanics::CreatureStats &sellerStats = mPtr.getClass().getCreatureStats(mPtr); diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index c25e207c6..c6df24154 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -524,9 +524,9 @@ namespace MWMechanics for(int i = 0;i < ESM::Attribute::Length;++i) { AttributeValue stat = creatureStats.getAttribute(i); - stat.setModifier(effects.get(EffectKey(ESM::MagicEffect::FortifyAttribute, i)).getMagnitude() - + stat.setModifier(static_cast(effects.get(EffectKey(ESM::MagicEffect::FortifyAttribute, i)).getMagnitude() - effects.get(EffectKey(ESM::MagicEffect::DrainAttribute, i)).getMagnitude() - - effects.get(EffectKey(ESM::MagicEffect::AbsorbAttribute, i)).getMagnitude()); + effects.get(EffectKey(ESM::MagicEffect::AbsorbAttribute, i)).getMagnitude())); stat.damage(effects.get(EffectKey(ESM::MagicEffect::DamageAttribute, i)).getMagnitude() * duration); stat.restore(effects.get(EffectKey(ESM::MagicEffect::RestoreAttribute, i)).getMagnitude() * duration); @@ -793,9 +793,9 @@ namespace MWMechanics for(int i = 0;i < ESM::Skill::Length;++i) { SkillValue& skill = npcStats.getSkill(i); - skill.setModifier(effects.get(EffectKey(ESM::MagicEffect::FortifySkill, i)).getMagnitude() - + skill.setModifier(static_cast(effects.get(EffectKey(ESM::MagicEffect::FortifySkill, i)).getMagnitude() - effects.get(EffectKey(ESM::MagicEffect::DrainSkill, i)).getMagnitude() - - effects.get(EffectKey(ESM::MagicEffect::AbsorbSkill, i)).getMagnitude()); + effects.get(EffectKey(ESM::MagicEffect::AbsorbSkill, i)).getMagnitude())); skill.damage(effects.get(EffectKey(ESM::MagicEffect::DamageSkill, i)).getMagnitude() * duration); skill.restore(effects.get(EffectKey(ESM::MagicEffect::RestoreSkill, i)).getMagnitude() * duration); diff --git a/apps/openmw/mwmechanics/combat.cpp b/apps/openmw/mwmechanics/combat.cpp index fdb375846..bfc542cda 100644 --- a/apps/openmw/mwmechanics/combat.cpp +++ b/apps/openmw/mwmechanics/combat.cpp @@ -267,7 +267,7 @@ namespace MWMechanics attackTerm += mageffects.get(ESM::MagicEffect::FortifyAttack).getMagnitude() - mageffects.get(ESM::MagicEffect::Blind).getMagnitude(); - return static_cast((attackTerm - defenseTerm) + 0.5f); + return round(attackTerm - defenseTerm); } void applyElementalShields(const MWWorld::Ptr &attacker, const MWWorld::Ptr &victim) diff --git a/apps/openmw/mwsound/ffmpeg_decoder.cpp b/apps/openmw/mwsound/ffmpeg_decoder.cpp index bc467acff..0185d3ecc 100644 --- a/apps/openmw/mwsound/ffmpeg_decoder.cpp +++ b/apps/openmw/mwsound/ffmpeg_decoder.cpp @@ -30,7 +30,7 @@ int FFmpeg_Decoder::readPacket(void *user_data, uint8_t *buf, int buf_size) Ogre::DataStreamPtr stream = static_cast(user_data)->mDataStream; return stream->read(buf, buf_size); } - catch (std::exception& e) + catch (std::exception& ) { return 0; } @@ -43,7 +43,7 @@ int FFmpeg_Decoder::writePacket(void *user_data, uint8_t *buf, int buf_size) Ogre::DataStreamPtr stream = static_cast(user_data)->mDataStream; return stream->write(buf, buf_size); } - catch (std::exception& e) + catch (std::exception& ) { return 0; } @@ -57,11 +57,11 @@ int64_t FFmpeg_Decoder::seek(void *user_data, int64_t offset, int whence) if(whence == AVSEEK_SIZE) return stream->size(); if(whence == SEEK_SET) - stream->seek(offset); + stream->seek(static_cast(offset)); else if(whence == SEEK_CUR) - stream->seek(stream->tell()+offset); + stream->seek(static_cast(stream->tell()+offset)); else if(whence == SEEK_END) - stream->seek(stream->size()+offset); + stream->seek(static_cast(stream->size()+offset)); else return -1; diff --git a/components/bsa/bsa_file.cpp b/components/bsa/bsa_file.cpp index 0958c8f0c..0d60f4cf0 100644 --- a/components/bsa/bsa_file.cpp +++ b/components/bsa/bsa_file.cpp @@ -79,7 +79,7 @@ void BSAFile::readHeader() bfs::ifstream input(bfs::path(filename), std::ios_base::binary); // Total archive size - size_t fsize = 0; + std::streamoff fsize = 0; if(input.seekg(0, std::ios_base::end)) { fsize = input.tellg(); diff --git a/components/compiler/exprparser.cpp b/components/compiler/exprparser.cpp index 7eaca5c02..dc36b58d8 100644 --- a/components/compiler/exprparser.cpp +++ b/components/compiler/exprparser.cpp @@ -324,7 +324,7 @@ namespace Compiler mNextOperand = false; mOperands.push_back ('l'); - return 2; + return true; } } diff --git a/extern/ogre-ffmpeg-videoplayer/videostate.cpp b/extern/ogre-ffmpeg-videoplayer/videostate.cpp index 0894499b2..66c7c2ad5 100644 --- a/extern/ogre-ffmpeg-videoplayer/videostate.cpp +++ b/extern/ogre-ffmpeg-videoplayer/videostate.cpp @@ -179,7 +179,7 @@ int VideoState::OgreResource_Read(void *user_data, uint8_t *buf, int buf_size) { return stream->read(buf, buf_size); } - catch (std::exception& e) + catch (std::exception& ) { return 0; } @@ -192,7 +192,7 @@ int VideoState::OgreResource_Write(void *user_data, uint8_t *buf, int buf_size) { return stream->write(buf, buf_size); } - catch (std::exception& e) + catch (std::exception& ) { return 0; } @@ -206,11 +206,11 @@ int64_t VideoState::OgreResource_Seek(void *user_data, int64_t offset, int whenc if(whence == AVSEEK_SIZE) return stream->size(); if(whence == SEEK_SET) - stream->seek(offset); + stream->seek(static_cast(offset)); else if(whence == SEEK_CUR) - stream->seek(stream->tell()+offset); + stream->seek(static_cast(stream->tell()+offset)); else if(whence == SEEK_END) - stream->seek(stream->size()+offset); + stream->seek(static_cast(stream->size() + offset)); else return -1; @@ -400,7 +400,7 @@ void VideoState::video_thread_loop(VideoState *self) self->pictq_mutex.unlock(); self->frame_last_pts = packet->pts * av_q2d((*self->video_st)->time_base); - global_video_pkt_pts = self->frame_last_pts; + global_video_pkt_pts = static_cast(self->frame_last_pts); continue; } @@ -412,9 +412,9 @@ void VideoState::video_thread_loop(VideoState *self) double pts = 0; if(packet->dts != AV_NOPTS_VALUE) - pts = packet->dts; + pts = static_cast(packet->dts); else if(pFrame->opaque && *(int64_t*)pFrame->opaque != AV_NOPTS_VALUE) - pts = *(int64_t*)pFrame->opaque; + pts = static_cast(*(int64_t*)pFrame->opaque); pts *= av_q2d((*self->video_st)->time_base); av_free_packet(packet); diff --git a/extern/shiny/Platforms/Ogre/OgrePass.cpp b/extern/shiny/Platforms/Ogre/OgrePass.cpp index 3a25c5c74..5cd501094 100644 --- a/extern/shiny/Platforms/Ogre/OgrePass.cpp +++ b/extern/shiny/Platforms/Ogre/OgrePass.cpp @@ -109,7 +109,7 @@ namespace sh { params->addSharedParameters (name); } - catch (Ogre::Exception& e) + catch (Ogre::Exception& ) { std::stringstream msg; msg << "Could not create a shared parameter instance for '" diff --git a/libs/openengine/bullet/BtOgre.cpp b/libs/openengine/bullet/BtOgre.cpp index 88619b7fc..0af173adc 100644 --- a/libs/openengine/bullet/BtOgre.cpp +++ b/libs/openengine/bullet/BtOgre.cpp @@ -150,7 +150,7 @@ namespace BtOgre { if (i == mBoneIndex->end()) { l = new Vector3Array; - mBoneIndex->insert(BoneKeyIndex(currBone, l)); + mBoneIndex->insert(std::make_pair(currBone, l)); } else { diff --git a/libs/openengine/bullet/BtOgreGP.h b/libs/openengine/bullet/BtOgreGP.h index dde606a4f..7e497b535 100644 --- a/libs/openengine/bullet/BtOgreGP.h +++ b/libs/openengine/bullet/BtOgreGP.h @@ -27,7 +27,6 @@ namespace BtOgre { typedef std::map BoneIndex; -typedef std::pair BoneKeyIndex; class VertexIndexToShape { From 3f28634d1f617691c672e41a3ee950e6daec8c77 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 15 Mar 2015 14:07:47 +1300 Subject: [PATCH 0754/3725] consolidate random number logic Note, I suspect Rng::rollClosedProbability() is not needed. The only difference between it and rollProbability() is that one time in 37k (on Windows), it will give an output of 1.0. On some versions of Linux, the value of 1.0 will occur about 1 time in 4 billion. --- apps/openmw/engine.cpp | 3 ++ apps/openmw/mwclass/creature.cpp | 9 ++--- apps/openmw/mwclass/npc.cpp | 12 +++---- apps/openmw/mwgui/jailscreen.cpp | 4 ++- apps/openmw/mwgui/loadingscreen.cpp | 4 ++- apps/openmw/mwgui/pickpocketitemmodel.cpp | 6 +++- apps/openmw/mwgui/recharge.cpp | 4 ++- apps/openmw/mwgui/tradewindow.cpp | 4 ++- apps/openmw/mwgui/waitdialog.cpp | 7 ++-- apps/openmw/mwmechanics/activespells.cpp | 5 +-- apps/openmw/mwmechanics/aicombat.cpp | 25 ++++++------- apps/openmw/mwmechanics/aiwander.cpp | 10 +++--- apps/openmw/mwmechanics/alchemy.cpp | 6 ++-- apps/openmw/mwmechanics/character.cpp | 8 +++-- apps/openmw/mwmechanics/combat.cpp | 12 +++---- apps/openmw/mwmechanics/disease.hpp | 6 ++-- apps/openmw/mwmechanics/enchanting.cpp | 5 ++- apps/openmw/mwmechanics/levelledlist.hpp | 7 ++-- .../mwmechanics/mechanicsmanagerimp.cpp | 7 ++-- apps/openmw/mwmechanics/pickpocket.cpp | 4 ++- apps/openmw/mwmechanics/repair.cpp | 4 ++- apps/openmw/mwmechanics/security.cpp | 8 ++--- apps/openmw/mwmechanics/spellcasting.cpp | 20 +++++------ apps/openmw/mwmechanics/spells.cpp | 2 +- apps/openmw/mwrender/npcanimation.cpp | 4 ++- apps/openmw/mwrender/sky.cpp | 6 ++-- apps/openmw/mwsound/soundmanagerimp.cpp | 8 +++-- apps/openmw/mwworld/inventorystore.cpp | 2 +- apps/openmw/mwworld/store.hpp | 4 ++- apps/openmw/mwworld/weather.cpp | 8 +++-- apps/openmw/mwworld/worldimp.cpp | 6 ++-- components/CMakeLists.txt | 6 +++- components/nifogre/particles.cpp | 4 ++- libs/openengine/CMakeLists.txt | 7 +++- libs/openengine/misc/rng.cpp | 29 +++++++++++++++ libs/openengine/misc/rng.hpp | 36 +++++++++++++++++++ libs/openengine/ogre/selectionbuffer.cpp | 4 ++- 37 files changed, 214 insertions(+), 92 deletions(-) create mode 100644 libs/openengine/misc/rng.cpp create mode 100644 libs/openengine/misc/rng.hpp diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 92731ee1a..a4bb8c538 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -10,6 +10,8 @@ #include +#include + #include #include @@ -191,6 +193,7 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) , mExportFonts(false) , mNewGame (false) { + OEngine::Misc::Rng::init(); std::srand ( static_cast(std::time(NULL)) ); MWClass::registerClasses(); diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 908de02d8..8404b9523 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -1,6 +1,8 @@ #include "creature.hpp" +#include + #include #include @@ -249,7 +251,7 @@ namespace MWClass float hitchance = MWMechanics::getHitChance(ptr, victim, ref->mBase->mData.mCombat); - if((::rand()/(RAND_MAX+1.0)) >= hitchance/100.0f) + if(OEngine::Misc::Rng::rollProbability() >= hitchance/100.0f) { victim.getClass().onHit(victim, 0.0f, false, MWWorld::Ptr(), ptr, false); MWMechanics::reduceWeaponCondition(0.f, false, weapon, ptr); @@ -375,8 +377,7 @@ namespace MWClass float agilityTerm = getCreatureStats(ptr).getAttribute(ESM::Attribute::Agility).getModified() * getGmst().fKnockDownMult->getFloat(); float knockdownTerm = getCreatureStats(ptr).getAttribute(ESM::Attribute::Agility).getModified() * getGmst().iKnockDownOddsMult->getInt() * 0.01f + getGmst().iKnockDownOddsBase->getInt(); - int roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 100); // [0, 99] - if (ishealth && agilityTerm <= damage && knockdownTerm <= roll) + if (ishealth && agilityTerm <= damage && knockdownTerm <= OEngine::Misc::Rng::roll0to99()) { getCreatureStats(ptr).setKnockedDown(true); @@ -680,7 +681,7 @@ namespace MWClass ++sound; } if(!sounds.empty()) - return sounds[(int)(rand()/(RAND_MAX+1.0)*sounds.size())]->mSound; + return sounds[OEngine::Misc::Rng::rollDice(sounds.size())]->mSound; } if (type == ESM::SoundGenerator::Land) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index d5055fcb2..1d58dc87e 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -5,6 +5,8 @@ #include +#include + #include #include #include @@ -513,7 +515,7 @@ namespace MWClass float hitchance = MWMechanics::getHitChance(ptr, victim, ptr.getClass().getSkill(ptr, weapskill)); - if((::rand()/(RAND_MAX+1.0)) >= hitchance/100.0f) + if (OEngine::Misc::Rng::rollProbability() >= hitchance / 100.0f) { othercls.onHit(victim, 0.0f, false, weapon, ptr, false); MWMechanics::reduceWeaponCondition(0.f, false, weapon, ptr); @@ -643,8 +645,7 @@ namespace MWClass const GMST& gmst = getGmst(); int chance = store.get().find("iVoiceHitOdds")->getInt(); - int roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 100); // [0, 99] - if (roll < chance) + if (OEngine::Misc::Rng::roll0to99() < chance) { MWBase::Environment::get().getDialogueManager()->say(ptr, "hit"); } @@ -653,8 +654,7 @@ namespace MWClass float agilityTerm = getCreatureStats(ptr).getAttribute(ESM::Attribute::Agility).getModified() * gmst.fKnockDownMult->getFloat(); float knockdownTerm = getCreatureStats(ptr).getAttribute(ESM::Attribute::Agility).getModified() * gmst.iKnockDownOddsMult->getInt() * 0.01f + gmst.iKnockDownOddsBase->getInt(); - roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 100); // [0, 99] - if (ishealth && agilityTerm <= damage && knockdownTerm <= roll) + if (ishealth && agilityTerm <= damage && knockdownTerm <= OEngine::Misc::Rng::roll0to99()) { getCreatureStats(ptr).setKnockedDown(true); @@ -680,7 +680,7 @@ namespace MWClass MWWorld::InventoryStore::Slot_RightPauldron, MWWorld::InventoryStore::Slot_RightPauldron, MWWorld::InventoryStore::Slot_LeftGauntlet, MWWorld::InventoryStore::Slot_RightGauntlet }; - int hitslot = hitslots[(int)(::rand()/(RAND_MAX+1.0)*20.0)]; + int hitslot = hitslots[OEngine::Misc::Rng::rollDice(20)]; float unmitigatedDamage = damage; float x = damage / (damage + getArmorRating(ptr)); diff --git a/apps/openmw/mwgui/jailscreen.cpp b/apps/openmw/mwgui/jailscreen.cpp index 728c46023..5c0a6ec5f 100644 --- a/apps/openmw/mwgui/jailscreen.cpp +++ b/apps/openmw/mwgui/jailscreen.cpp @@ -1,5 +1,7 @@ #include +#include + #include "../mwbase/windowmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/world.hpp" @@ -83,7 +85,7 @@ namespace MWGui std::set skills; for (int day=0; day(std::rand() / (static_cast (RAND_MAX)+1) * ESM::Skill::Length); + int skill = OEngine::Misc::Rng::rollDice(ESM::Skill::Length); skills.insert(skill); MWMechanics::SkillValue& value = player.getClass().getNpcStats(player).getSkill(skill); diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index f920acf1a..3204c6548 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -15,6 +15,8 @@ #include #include +#include + #include #include "../mwbase/environment.hpp" @@ -146,7 +148,7 @@ namespace MWGui if (!mResources.empty()) { - std::string const & randomSplash = mResources.at (rand() % mResources.size()); + std::string const & randomSplash = mResources.at(OEngine::Misc::Rng::rollDice(mResources.size())); Ogre::TextureManager::getSingleton ().load (randomSplash, Ogre::ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME); diff --git a/apps/openmw/mwgui/pickpocketitemmodel.cpp b/apps/openmw/mwgui/pickpocketitemmodel.cpp index f6882ada6..bc7c5528e 100644 --- a/apps/openmw/mwgui/pickpocketitemmodel.cpp +++ b/apps/openmw/mwgui/pickpocketitemmodel.cpp @@ -1,5 +1,7 @@ #include "pickpocketitemmodel.hpp" +#include + #include "../mwmechanics/npcstats.hpp" #include "../mwworld/class.hpp" @@ -12,11 +14,13 @@ namespace MWGui int chance = thief.getClass().getSkill(thief, ESM::Skill::Sneak); mSourceModel->update(); + + // build list of items that player is unable to find when attempts to pickpocket. if (hideItems) { for (size_t i = 0; igetItemCount(); ++i) { - if (std::rand() / static_cast(RAND_MAX) * 100 > chance) + if (chance <= OEngine::Misc::Rng::roll0to99()) mHiddenItems.push_back(mSourceModel->getItem(i)); } } diff --git a/apps/openmw/mwgui/recharge.cpp b/apps/openmw/mwgui/recharge.cpp index 1af31373c..a0e5991b4 100644 --- a/apps/openmw/mwgui/recharge.cpp +++ b/apps/openmw/mwgui/recharge.cpp @@ -5,6 +5,8 @@ #include #include +#include + #include #include "../mwbase/world.hpp" @@ -161,7 +163,7 @@ void Recharge::onItemClicked(MyGUI::Widget *sender) intelligenceTerm = 1; float x = (npcStats.getSkill(ESM::Skill::Enchant).getModified() + intelligenceTerm + luckTerm) * stats.getFatigueTerm(); - int roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 100); // [0, 99] + int roll = OEngine::Misc::Rng::roll0to99(); if (roll < x) { std::string soul = gem.getCellRef().getSoul(); diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 841e2e185..e14642fe7 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -4,6 +4,8 @@ #include #include +#include + #include #include "../mwbase/environment.hpp" @@ -365,7 +367,7 @@ namespace MWGui else x += abs(int(npcTerm - pcTerm)); - int roll = std::rand()%100 + 1; + int roll = OEngine::Misc::Rng::rollDice(100) + 1; if(roll > x || (mCurrentMerchantOffer < 0) != (mCurrentBalance < 0)) //trade refused { MWBase::Environment::get().getWindowManager()-> diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index b73ab38f2..f74b06891 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -2,6 +2,8 @@ #include +#include + #include #include @@ -152,10 +154,9 @@ namespace MWGui const ESM::Region *region = world->getStore().get().find (regionstr); if (!region->mSleepList.empty()) { + // figure out if player will be woken while sleeping float fSleepRandMod = world->getStore().get().find("fSleepRandMod")->getFloat(); - int x = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * hoursToWait); // [0, hoursRested] - float y = fSleepRandMod * hoursToWait; - if (x > y) + if (OEngine::Misc::Rng::rollProbability() > fSleepRandMod) { float fSleepRestMod = world->getStore().get().find("fSleepRestMod")->getFloat(); mInterruptAt = hoursToWait - int(fSleepRestMod * hoursToWait); diff --git a/apps/openmw/mwmechanics/activespells.cpp b/apps/openmw/mwmechanics/activespells.cpp index 5eea08caa..a6cc9af8e 100644 --- a/apps/openmw/mwmechanics/activespells.cpp +++ b/apps/openmw/mwmechanics/activespells.cpp @@ -1,5 +1,7 @@ #include "activespells.hpp" +#include + #include #include @@ -229,8 +231,7 @@ namespace MWMechanics { for (TContainer::iterator it = mSpells.begin(); it != mSpells.end(); ) { - int roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 100); // [0, 99] - if (roll < chance) + if (OEngine::Misc::Rng::roll0to99() < chance) mSpells.erase(it++); else ++it; diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index c16baefaa..bac7d7286 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -2,6 +2,8 @@ #include +#include + #include #include "../mwworld/class.hpp" @@ -393,7 +395,7 @@ namespace MWMechanics if (!distantCombat) attackType = chooseBestAttack(weapon, movement); else attackType = ESM::Weapon::AT_Chop; // cause it's =0 - strength = static_cast(rand()) / RAND_MAX; + strength = OEngine::Misc::Rng::rollClosedProbability(); // Note: may be 0 for some animations timerAttack = minMaxAttackDuration[attackType][0] + @@ -404,8 +406,7 @@ namespace MWMechanics { const MWWorld::ESMStore &store = world->getStore(); int chance = store.get().find("iVoiceAttackOdds")->getInt(); - int roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 100); // [0, 99] - if (roll < chance) + if (OEngine::Misc::Rng::roll0to99() < chance) { MWBase::Environment::get().getDialogueManager()->say(actor, "attack"); } @@ -512,17 +513,17 @@ namespace MWMechanics { if(movement.mPosition[0] || movement.mPosition[1]) { - timerCombatMove = 0.1f + 0.1f * static_cast(rand())/RAND_MAX; + timerCombatMove = 0.1f + 0.1f * OEngine::Misc::Rng::rollClosedProbability(); combatMove = true; } // only NPCs are smart enough to use dodge movements else if(actorClass.isNpc() && (!distantCombat || (distantCombat && distToTarget < rangeAttack/2))) { //apply sideway movement (kind of dodging) with some probability - if(static_cast(rand())/RAND_MAX < 0.25) + if (OEngine::Misc::Rng::rollClosedProbability() < 0.25) { - movement.mPosition[0] = static_cast(rand())/RAND_MAX < 0.5? 1.0f : -1.0f; - timerCombatMove = 0.05f + 0.15f * static_cast(rand())/RAND_MAX; + movement.mPosition[0] = OEngine::Misc::Rng::rollProbability() < 0.5 ? 1.0f : -1.0f; + timerCombatMove = 0.05f + 0.15f * OEngine::Misc::Rng::rollClosedProbability(); combatMove = true; } } @@ -637,7 +638,7 @@ namespace MWMechanics float s2 = speed2 * t; float t_swing = minMaxAttackDuration[ESM::Weapon::AT_Thrust][0] + - (minMaxAttackDuration[ESM::Weapon::AT_Thrust][1] - minMaxAttackDuration[ESM::Weapon::AT_Thrust][0]) * static_cast(rand()) / RAND_MAX; + (minMaxAttackDuration[ESM::Weapon::AT_Thrust][1] - minMaxAttackDuration[ESM::Weapon::AT_Thrust][0]) * OEngine::Misc::Rng::rollClosedProbability(); if (t + s2/speed1 <= t_swing) { @@ -761,10 +762,10 @@ ESM::Weapon::AttackType chooseBestAttack(const ESM::Weapon* weapon, MWMechanics: if (weapon == NULL) { //hand-to-hand deal equal damage for each type - float roll = static_cast(rand())/RAND_MAX; + float roll = OEngine::Misc::Rng::rollClosedProbability(); if(roll <= 0.333f) //side punch { - movement.mPosition[0] = (static_cast(rand())/RAND_MAX < 0.5f)? 1.0f : -1.0f; + movement.mPosition[0] = OEngine::Misc::Rng::rollClosedProbability() ? 1.0f : -1.0f; movement.mPosition[1] = 0; attackType = ESM::Weapon::AT_Slash; } @@ -788,10 +789,10 @@ ESM::Weapon::AttackType chooseBestAttack(const ESM::Weapon* weapon, MWMechanics: float total = static_cast(slash + chop + thrust); - float roll = static_cast(rand())/RAND_MAX; + float roll = OEngine::Misc::Rng::rollClosedProbability(); if(roll <= (slash/total)) { - movement.mPosition[0] = (static_cast(rand())/RAND_MAX < 0.5f)? 1.0f : -1.0f; + movement.mPosition[0] = (OEngine::Misc::Rng::rollClosedProbability() < 0.5f) ? 1.0f : -1.0f; movement.mPosition[1] = 0; attackType = ESM::Weapon::AT_Slash; } diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 842f03edf..b791ff3a9 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -3,6 +3,8 @@ #include #include +#include + #include #include "../mwbase/world.hpp" @@ -315,7 +317,7 @@ namespace MWMechanics static float fVoiceIdleOdds = MWBase::Environment::get().getWorld()->getStore() .get().find("fVoiceIdleOdds")->getFloat(); - float roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 10000; + float roll = OEngine::Misc::Rng::rollProbability() * 10000.0f; // In vanilla MW the chance was FPS dependent, and did not allow proper changing of fVoiceIdleOdds // due to the roll being an integer. @@ -490,7 +492,7 @@ namespace MWMechanics if(!storage.mPathFinder.isPathConstructed()) { assert(mAllowedNodes.size()); - unsigned int randNode = (int)(rand() / ((double)RAND_MAX + 1) * mAllowedNodes.size()); + unsigned int randNode = OEngine::Misc::Rng::rollDice(mAllowedNodes.size()); // NOTE: initially constructed with local (i.e. cell) co-ordinates Ogre::Vector3 destNodePos(PathFinder::MakeOgreVector3(mAllowedNodes[randNode])); @@ -637,7 +639,7 @@ namespace MWMechanics .get().find("fIdleChanceMultiplier")->getFloat(); unsigned short idleChance = static_cast(fIdleChanceMultiplier * mIdle[counter]); - unsigned short randSelect = (int)(rand() / ((double)RAND_MAX + 1) * int(100 / fIdleChanceMultiplier)); + unsigned short randSelect = (int)(OEngine::Misc::Rng::rollProbability() * int(100 / fIdleChanceMultiplier)); if(randSelect < idleChance && randSelect > idleRoll) { playedIdle = counter+2; @@ -659,7 +661,7 @@ namespace MWMechanics state.moveIn(new AiWanderStorage()); - int index = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * mAllowedNodes.size()); + int index = OEngine::Misc::Rng::rollDice(mAllowedNodes.size()); ESM::Pathgrid::Point dest = mAllowedNodes[index]; // apply a slight offset to prevent overcrowding diff --git a/apps/openmw/mwmechanics/alchemy.cpp b/apps/openmw/mwmechanics/alchemy.cpp index a833e28d9..58c42ddb8 100644 --- a/apps/openmw/mwmechanics/alchemy.cpp +++ b/apps/openmw/mwmechanics/alchemy.cpp @@ -8,6 +8,8 @@ #include #include +#include + #include #include #include @@ -294,7 +296,7 @@ void MWMechanics::Alchemy::addPotion (const std::string& name) newRecord.mName = name; - int index = static_cast (std::rand()/(static_cast (RAND_MAX)+1)*6); + int index = OEngine::Misc::Rng::rollDice(6); assert (index>=0 && index<6); static const char *meshes[] = { "standard", "bargain", "cheap", "fresh", "exclusive", "quality" }; @@ -467,7 +469,7 @@ MWMechanics::Alchemy::Result MWMechanics::Alchemy::create (const std::string& na return Result_RandomFailure; } - if (getAlchemyFactor() (RAND_MAX)*100) + if (getAlchemyFactor() < OEngine::Misc::Rng::roll0to99()) { removeIngredients(); return Result_RandomFailure; diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 28028500a..ffde59aee 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -27,6 +27,8 @@ #include "creaturestats.hpp" #include "security.hpp" +#include + #include #include "../mwrender/animation.hpp" @@ -220,7 +222,7 @@ std::string CharacterController::chooseRandomGroup (const std::string& prefix, i while (mAnimation->hasAnimation(prefix + Ogre::StringConverter::toString(numAnims+1))) ++numAnims; - int roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * numAnims) + 1; // [1, numAnims] + int roll = OEngine::Misc::Rng::rollDice(numAnims) + 1; // [1, numAnims] if (num) *num = roll; return prefix + Ogre::StringConverter::toString(roll); @@ -829,7 +831,7 @@ bool CharacterController::updateCreatureState() } if (weapType != WeapType_Spell || !mAnimation->hasAnimation("spellcast")) // Not all creatures have a dedicated spellcast animation { - int roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 3); // [0, 2] + int roll = OEngine::Misc::Rng::rollDice(3); // [0, 2] if (roll == 0) mCurrentWeapon = "attack1"; else if (roll == 1) @@ -1125,7 +1127,7 @@ bool CharacterController::updateWeaponState() // most creatures don't actually have an attack wind-up animation, so use a uniform random value // (even some creatures that can use weapons don't have a wind-up animation either, e.g. Rieklings) // Note: vanilla MW uses a random value for *all* non-player actors, but we probably don't need to go that far. - attackStrength = std::min(1.f, 0.1f + std::rand() / float(RAND_MAX)); + attackStrength = std::min(1.f, 0.1f + OEngine::Misc::Rng::rollClosedProbability()); } if(mWeaponType != WeapType_Crossbow && mWeaponType != WeapType_BowAndArrow) diff --git a/apps/openmw/mwmechanics/combat.cpp b/apps/openmw/mwmechanics/combat.cpp index fdb375846..6a1e08df8 100644 --- a/apps/openmw/mwmechanics/combat.cpp +++ b/apps/openmw/mwmechanics/combat.cpp @@ -2,6 +2,8 @@ #include +#include + #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/mechanicsmanager.hpp" @@ -107,8 +109,7 @@ namespace MWMechanics int iBlockMinChance = gmst.find("iBlockMinChance")->getInt(); x = std::min(iBlockMaxChance, std::max(iBlockMinChance, x)); - int roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 100); // [0, 99] - if (roll < x) + if (OEngine::Misc::Rng::roll0to99() < x) { // Reduce shield durability by incoming damage int shieldhealth = shield->getClass().getItemHealth(*shield); @@ -186,7 +187,7 @@ namespace MWMechanics int skillValue = attacker.getClass().getSkill(attacker, weapon.getClass().getEquipmentSkill(weapon)); - if((::rand()/(RAND_MAX+1.0)) >= getHitChance(attacker, victim, skillValue)/100.0f) + if (OEngine::Misc::Rng::rollProbability() >= getHitChance(attacker, victim, skillValue) / 100.0f) { victim.getClass().onHit(victim, 0.0f, false, projectile, attacker, false); MWMechanics::reduceWeaponCondition(0.f, false, weapon, attacker); @@ -224,7 +225,7 @@ namespace MWMechanics && !appliedEnchantment) { float fProjectileThrownStoreChance = gmst.find("fProjectileThrownStoreChance")->getFloat(); - if ((::rand()/(RAND_MAX+1.0)) < fProjectileThrownStoreChance/100.f) + if (OEngine::Misc::Rng::rollProbability() < fProjectileThrownStoreChance / 100.f) victim.getClass().getContainerStore(victim).add(projectile, 1, victim); } @@ -291,8 +292,7 @@ namespace MWMechanics saveTerm *= 1.25f * normalisedFatigue; - float roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 100; // [0, 99] - float x = std::max(0.f, saveTerm - roll); + float x = std::max(0.f, saveTerm - OEngine::Misc::Rng::roll0to99()); int element = ESM::MagicEffect::FireDamage; if (i == 1) diff --git a/apps/openmw/mwmechanics/disease.hpp b/apps/openmw/mwmechanics/disease.hpp index 2f7d65dfd..0153be3dc 100644 --- a/apps/openmw/mwmechanics/disease.hpp +++ b/apps/openmw/mwmechanics/disease.hpp @@ -1,6 +1,8 @@ #ifndef OPENMW_MECHANICS_DISEASE_H #define OPENMW_MECHANICS_DISEASE_H +#include + #include "../mwbase/windowmanager.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -49,9 +51,7 @@ namespace MWMechanics continue; int x = static_cast(fDiseaseXferChance * 100 * resist); - float roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 10000); // [0, 9999] - - if (roll < x) + if (OEngine::Misc::Rng::rollDice(10000) < x) { // Contracted disease! actor.getClass().getCreatureStats(actor).getSpells().add(it->first); diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp index d99b337d5..bb02fb41d 100644 --- a/apps/openmw/mwmechanics/enchanting.cpp +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -1,4 +1,7 @@ #include "enchanting.hpp" + +#include + #include "../mwworld/manualref.hpp" #include "../mwworld/class.hpp" #include "../mwworld/containerstore.hpp" @@ -67,7 +70,7 @@ namespace MWMechanics if(mSelfEnchanting) { - if(getEnchantChance() (RAND_MAX)*100) + if(getEnchantChance() <= (OEngine::Misc::Rng::roll0to99())) return false; mEnchanter.getClass().skillUsageSucceeded (mEnchanter, ESM::Skill::Enchant, 2); diff --git a/apps/openmw/mwmechanics/levelledlist.hpp b/apps/openmw/mwmechanics/levelledlist.hpp index cd1276038..20b87a3a9 100644 --- a/apps/openmw/mwmechanics/levelledlist.hpp +++ b/apps/openmw/mwmechanics/levelledlist.hpp @@ -1,6 +1,8 @@ #ifndef OPENMW_MECHANICS_LEVELLEDLIST_H #define OPENMW_MECHANICS_LEVELLEDLIST_H +#include + #include "../mwworld/ptr.hpp" #include "../mwworld/esmstore.hpp" #include "../mwworld/manualref.hpp" @@ -22,8 +24,7 @@ namespace MWMechanics failChance += levItem->mChanceNone; - int random = static_cast(static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 100)); // [0, 99] - if (random < failChance) + if (OEngine::Misc::Rng::roll0to99() < failChance) return std::string(); std::vector candidates; @@ -52,7 +53,7 @@ namespace MWMechanics } if (candidates.empty()) return std::string(); - std::string item = candidates[std::rand()%candidates.size()]; + std::string item = candidates[OEngine::Misc::Rng::rollDice(candidates.size())]; // Vanilla doesn't fail on nonexistent items in levelled lists if (!MWBase::Environment::get().getWorld()->getStore().find(Misc::StringUtils::lowerCase(item))) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index bf1d3ec19..0d4518f87 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -2,6 +2,8 @@ #include "mechanicsmanagerimp.hpp" #include "npcstats.hpp" +#include + #include #include "../mwworld/esmstore.hpp" @@ -723,7 +725,7 @@ namespace MWMechanics float x = 0; float y = 0; - float roll = static_cast (std::rand()) / RAND_MAX * 100; + float roll = OEngine::Misc::Rng::rollClosedProbability() * 100; if (type == PT_Admire) { @@ -1378,9 +1380,8 @@ namespace MWMechanics y = obsTerm * observerStats.getFatigueTerm() * fSneakViewMult; float target = x - y; - int roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 100); // [0, 99] - return (roll >= target); + return (OEngine::Misc::Rng::roll0to99() >= target); } void MechanicsManager::startCombat(const MWWorld::Ptr &ptr, const MWWorld::Ptr &target) diff --git a/apps/openmw/mwmechanics/pickpocket.cpp b/apps/openmw/mwmechanics/pickpocket.cpp index 12db9d6f5..561011df3 100644 --- a/apps/openmw/mwmechanics/pickpocket.cpp +++ b/apps/openmw/mwmechanics/pickpocket.cpp @@ -1,5 +1,7 @@ #include "pickpocket.hpp" +#include + #include "../mwworld/class.hpp" #include "../mwworld/esmstore.hpp" @@ -39,7 +41,7 @@ namespace MWMechanics int iPickMaxChance = MWBase::Environment::get().getWorld()->getStore().get() .find("iPickMaxChance")->getInt(); - int roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 100); // [0, 99] + int roll = OEngine::Misc::Rng::roll0to99(); if (t < pcSneak / iPickMinChance) { return (roll > int(pcSneak / iPickMinChance)); diff --git a/apps/openmw/mwmechanics/repair.cpp b/apps/openmw/mwmechanics/repair.cpp index 486a9183d..b5058fb88 100644 --- a/apps/openmw/mwmechanics/repair.cpp +++ b/apps/openmw/mwmechanics/repair.cpp @@ -2,6 +2,8 @@ #include +#include + #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/mechanicsmanager.hpp" @@ -46,7 +48,7 @@ void Repair::repair(const MWWorld::Ptr &itemToRepair) float x = (0.1f * pcStrength + 0.1f * pcLuck + armorerSkill) * fatigueTerm; - int roll = static_cast(static_cast (std::rand()) / RAND_MAX * 100); + int roll = OEngine::Misc::Rng::roll0to99(); if (roll <= x) { int y = static_cast(fRepairAmountMult * toolQuality * roll); diff --git a/apps/openmw/mwmechanics/security.cpp b/apps/openmw/mwmechanics/security.cpp index d987814e5..3f72f1b66 100644 --- a/apps/openmw/mwmechanics/security.cpp +++ b/apps/openmw/mwmechanics/security.cpp @@ -1,5 +1,7 @@ #include "security.hpp" +#include + #include "../mwworld/class.hpp" #include "../mwworld/containerstore.hpp" #include "../mwworld/esmstore.hpp" @@ -48,8 +50,7 @@ namespace MWMechanics else { MWBase::Environment::get().getMechanicsManager()->objectOpened(mActor, lock); - int roll = static_cast(static_cast (std::rand()) / RAND_MAX * 100); - if (roll <= x) + if (OEngine::Misc::Rng::roll0to99() <= x) { lock.getClass().unlock(lock); resultMessage = "#{sLockSuccess}"; @@ -90,8 +91,7 @@ namespace MWMechanics else { MWBase::Environment::get().getMechanicsManager()->objectOpened(mActor, trap); - int roll = static_cast(static_cast (std::rand()) / RAND_MAX * 100); - if (roll <= x) + if (OEngine::Misc::Rng::roll0to99() <= x) { trap.getCellRef().setTrap(""); diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 590c8fe83..8a43cc932 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -4,6 +4,8 @@ #include +#include + #include "../mwbase/windowmanager.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" @@ -280,7 +282,7 @@ namespace MWMechanics if (castChance > 0) x *= 50 / castChance; - float roll = static_cast(std::rand()) / RAND_MAX * 100; + float roll = OEngine::Misc::Rng::rollClosedProbability() * 100; if (magicEffect->mData.mFlags & ESM::MagicEffect::NoMagnitude) roll -= resistance; @@ -383,8 +385,7 @@ namespace MWMechanics target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::ResistCommonDisease).getMagnitude() : target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::ResistBlightDisease).getMagnitude(); - int roll = static_cast(std::rand()/ (static_cast (RAND_MAX) + 1) * 100); // [0, 99] - if (roll <= x) + if (OEngine::Misc::Rng::roll0to99() <= x) { // Fully resisted, show message if (target == MWBase::Environment::get().getWorld()->getPlayerPtr()) @@ -414,8 +415,7 @@ namespace MWMechanics if (spell && caster != target && target.getClass().isActor()) { float absorb = target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::SpellAbsorption).getMagnitude(); - int roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 100); // [0, 99] - absorbed = (roll < absorb); + absorbed = (OEngine::Misc::Rng::roll0to99() < absorb); if (absorbed) { const ESM::Static* absorbStatic = MWBase::Environment::get().getWorld()->getStore().get().find ("VFX_Absorb"); @@ -463,8 +463,7 @@ namespace MWMechanics if (!reflected && magnitudeMult > 0 && !caster.isEmpty() && caster != target && !(magicEffect->mData.mFlags & ESM::MagicEffect::Unreflectable)) { float reflect = target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::Reflect).getMagnitude(); - int roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 100); // [0, 99] - bool isReflected = (roll < reflect); + bool isReflected = (OEngine::Misc::Rng::roll0to99() < reflect); if (isReflected) { const ESM::Static* reflectStatic = MWBase::Environment::get().getWorld()->getStore().get().find ("VFX_Reflect"); @@ -492,7 +491,7 @@ namespace MWMechanics if (magnitudeMult > 0 && !absorbed) { - float random = std::rand() / static_cast(RAND_MAX); + float random = OEngine::Misc::Rng::rollClosedProbability(); float magnitude = effectIt->mMagnMin + (effectIt->mMagnMax - effectIt->mMagnMin) * random; magnitude *= magnitudeMult; @@ -824,8 +823,7 @@ namespace MWMechanics // Check success float successChance = getSpellSuccessChance(spell, mCaster); - int roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 100); // [0, 99] - if (!fail && roll >= successChance) + if (OEngine::Misc::Rng::roll0to99() >= successChance) { if (mCaster == MWBase::Environment::get().getWorld()->getPlayerPtr()) MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicSkillFail}"); @@ -903,7 +901,7 @@ namespace MWMechanics + 0.1f * creatureStats.getAttribute (ESM::Attribute::Luck).getModified()) * creatureStats.getFatigueTerm(); - int roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 100); // [0, 99] + int roll = OEngine::Misc::Rng::roll0to99(); if (roll > x) { // "X has no effect on you" diff --git a/apps/openmw/mwmechanics/spells.cpp b/apps/openmw/mwmechanics/spells.cpp index dcbd3f09f..04225b43e 100644 --- a/apps/openmw/mwmechanics/spells.cpp +++ b/apps/openmw/mwmechanics/spells.cpp @@ -38,7 +38,7 @@ namespace MWMechanics for (unsigned int i=0; imEffects.mList.size();++i) { if (spell->mEffects.mList[i].mMagnMin != spell->mEffects.mList[i].mMagnMax) - random[i] = static_cast (std::rand()) / RAND_MAX; + random[i] = OEngine::Misc::Rng::rollClosedProbability(); } } diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 284788522..a724644a7 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -12,6 +12,8 @@ #include +#include + #include #include "../mwworld/esmstore.hpp" @@ -101,7 +103,7 @@ void HeadAnimationTime::setEnabled(bool enabled) void HeadAnimationTime::resetBlinkTimer() { - mBlinkTimer = -(2 + (std::rand() / static_cast(RAND_MAX)) * 6); + mBlinkTimer = -(2.0f + OEngine::Misc::Rng::rollDice(6)); } void HeadAnimationTime::update(float dt) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 6e9684475..d591cca2e 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -19,6 +19,8 @@ #include +#include + #include #include @@ -464,8 +466,8 @@ void SkyManager::updateRain(float dt) // TODO: handle rain settings from Morrowind.ini const float rangeRandom = 100; - float xOffs = (std::rand()/(RAND_MAX+1.0f)) * rangeRandom - (rangeRandom/2); - float yOffs = (std::rand()/(RAND_MAX+1.0f)) * rangeRandom - (rangeRandom/2); + float xOffs = OEngine::Misc::Rng::rollProbability() * rangeRandom - (rangeRandom / 2); + float yOffs = OEngine::Misc::Rng::rollProbability() * rangeRandom - (rangeRandom / 2); // Create a separate node to control the offset, since a node with setInheritOrientation(false) will still // consider the orientation of the parent node for its position, just not for its orientation diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 998cc460b..06c40dd8e 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -4,6 +4,8 @@ #include #include +#include + #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/statemanager.hpp" @@ -224,7 +226,7 @@ namespace MWSound if(!filelist.size()) return; - int i = rand()%filelist.size(); + int i = OEngine::Misc::Rng::rollDice(filelist.size()); // Don't play the same music track twice in a row if (filelist[i] == mLastPlayedMusic) @@ -559,7 +561,7 @@ namespace MWSound if(!cell->isExterior() || sTimePassed < sTimeToNextEnvSound) return; - float a = std::rand() / static_cast(RAND_MAX); + float a = OEngine::Misc::Rng::rollClosedProbability(); // 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); @@ -588,7 +590,7 @@ namespace MWSound return; } - int r = (int)(rand()/((double)RAND_MAX+1) * total); + int r = OEngine::Misc::Rng::rollDice(total); int pos = 0; soundIter = regn->mSoundList.begin(); diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index da43df513..4503e66f5 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -364,7 +364,7 @@ void MWWorld::InventoryStore::updateMagicEffects(const Ptr& actor) // Roll some dice, one for each effect params.resize(enchantment.mEffects.mList.size()); for (unsigned int i=0; i (std::rand()) / RAND_MAX; + params[i].mRandom = OEngine::Misc::Rng::rollClosedProbability(); // Try resisting each effect int i=0; diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index 56f16377b..d6aeeb51e 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -7,6 +7,8 @@ #include #include +#include + #include #include @@ -178,7 +180,7 @@ namespace MWWorld std::vector results; std::for_each(mShared.begin(), mShared.end(), GetRecords(id, &results)); if(!results.empty()) - return results[int(std::rand()/((double)RAND_MAX+1)*results.size())]; + return results[OEngine::Misc::Rng::rollDice(results.size())]; return NULL; } diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 69495cdd2..a9ca8e72b 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -3,6 +3,8 @@ #include "weather.hpp" +#include + #include #include "../mwbase/environment.hpp" @@ -526,7 +528,7 @@ void WeatherManager::update(float duration, bool paused) if (mThunderSoundDelay <= 0) { // pick a random sound - int sound = rand() % 4; + int sound = OEngine::Misc::Rng::rollDice(4); std::string* soundName = NULL; if (sound == 0) soundName = &mThunderSoundID0; else if (sound == 1) soundName = &mThunderSoundID1; @@ -542,7 +544,7 @@ void WeatherManager::update(float duration, bool paused) mRendering->getSkyManager()->setLightningStrength( mThunderFlash / mThunderThreshold ); else { - mThunderChanceNeeded = static_cast(rand() % 100); + mThunderChanceNeeded = static_cast(OEngine::Misc::Rng::rollDice(100)); mThunderChance = 0; mRendering->getSkyManager()->setLightningStrength( 0.f ); } @@ -624,7 +626,7 @@ std::string WeatherManager::nextWeather(const ESM::Region* region) const * 70% will be greater than 30 (in theory). */ - int chance = (rand() % 100) + 1; // 1..100 + int chance = OEngine::Misc::Rng::rollDice(100) + 1; // 1..100 int sum = 0; unsigned int i = 0; for (; i < probability.size(); ++i) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index ce4b10dfc..013386f8f 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -14,6 +14,8 @@ #include #include +#include + #include #include #include @@ -3133,7 +3135,7 @@ namespace MWWorld const ESM::CreatureLevList* list = getStore().get().find(creatureList); int iNumberCreatures = getStore().get().find("iNumberCreatures")->getInt(); - int numCreatures = static_cast(1 + std::rand() / (static_cast (RAND_MAX)+1) * iNumberCreatures); // [1, iNumberCreatures] + int numCreatures = 1 + OEngine::Misc::Rng::rollDice(iNumberCreatures); // [1, iNumberCreatures] for (int i=0; i(std::rand() / (static_cast (RAND_MAX)+1) * 3); // [0, 2] + int roll = OEngine::Misc::Rng::rollDice(3); // [0, 2] modelName << roll; std::string model = "meshes\\" + getFallback()->getFallbackString(modelName.str()); diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 971897619..38fcd88e3 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -160,7 +160,11 @@ include_directories(${BULLET_INCLUDE_DIRS} ${CMAKE_CURRENT_BINARY_DIR}) add_library(components STATIC ${COMPONENT_FILES} ${MOC_SRCS} ${ESM_UI_HDR}) -target_link_libraries(components ${Boost_LIBRARIES} ${OGRE_LIBRARIES}) +target_link_libraries(components + ${Boost_LIBRARIES} + ${OGRE_LIBRARIES} + ${OENGINE_LIBRARY} +) if (GIT_CHECKOUT) add_dependencies (components git-version) diff --git a/components/nifogre/particles.cpp b/components/nifogre/particles.cpp index 4fec2d29e..936bfb435 100644 --- a/components/nifogre/particles.cpp +++ b/components/nifogre/particles.cpp @@ -12,6 +12,8 @@ #include #include +#include + /* FIXME: "Nif" isn't really an appropriate emitter name. */ class NifEmitter : public Ogre::ParticleEmitter { @@ -171,7 +173,7 @@ public: Ogre::Real& timeToLive = particle->timeToLive; #endif - Ogre::Node* emitterBone = mEmitterBones.at((int)(::rand()/(RAND_MAX+1.0)*mEmitterBones.size())); + Ogre::Node* emitterBone = mEmitterBones.at(OEngine::Misc::Rng::rollDice(mEmitterBones.size())); position = xOff + yOff + zOff + mParticleBone->_getDerivedOrientation().Inverse() * (emitterBone->_getDerivedPosition() diff --git a/libs/openengine/CMakeLists.txt b/libs/openengine/CMakeLists.txt index 7a0a791d1..3542becf6 100644 --- a/libs/openengine/CMakeLists.txt +++ b/libs/openengine/CMakeLists.txt @@ -23,7 +23,12 @@ set(OENGINE_BULLET bullet/trace.h ) -set(OENGINE_ALL ${OENGINE_OGRE} ${OENGINE_GUI} ${OENGINE_BULLET}) +set(OENGINE_MISC + misc/rng.cpp + misc/rng.hpp +) + +set(OENGINE_ALL ${OENGINE_OGRE} ${OENGINE_GUI} ${OENGINE_BULLET} ${OENGINE_MISC}) set(OENGINE_LIBRARY "oengine") set(OENGINE_LIBRARY ${OENGINE_LIBRARY} PARENT_SCOPE) diff --git a/libs/openengine/misc/rng.cpp b/libs/openengine/misc/rng.cpp new file mode 100644 index 000000000..140aa337e --- /dev/null +++ b/libs/openengine/misc/rng.cpp @@ -0,0 +1,29 @@ +#include "rng.hpp" +#include +#include + +namespace OEngine { +namespace Misc { + + void Rng::init() + { + std::srand(static_cast(std::time(NULL))); + } + + float Rng::rollProbability() + { + return static_cast(std::rand() / (static_cast(RAND_MAX)+1.0)); + } + + float Rng::rollClosedProbability() + { + return static_cast(std::rand() / static_cast(RAND_MAX)); + } + + int Rng::rollDice(int max) + { + return static_cast((std::rand() / (static_cast(RAND_MAX)+1.0)) * (max)); + } + +} +} \ No newline at end of file diff --git a/libs/openengine/misc/rng.hpp b/libs/openengine/misc/rng.hpp new file mode 100644 index 000000000..4e1da17e1 --- /dev/null +++ b/libs/openengine/misc/rng.hpp @@ -0,0 +1,36 @@ +#ifndef MISC_RNG_H +#define MISC_RNG_H + +#include + +namespace OEngine { +namespace Misc +{ + +/* + Provides central implementation of the RNG logic +*/ +class Rng +{ +public: + + /// seed the RNG + static void init(); + + /// return value in range [0.0f, 1.0f) <- note open upper range. + static float rollProbability(); + + /// return value in range [0.0f, 1.0f] <- note closed upper range. + static float rollClosedProbability(); + + /// return value in range [0, max) <- note open upper range. + static int rollDice(int max); + + /// return value in range [0, 99] + static int roll0to99() { return rollDice(100); } +}; + +} +} + +#endif diff --git a/libs/openengine/ogre/selectionbuffer.cpp b/libs/openengine/ogre/selectionbuffer.cpp index 87b85732b..741b672ff 100644 --- a/libs/openengine/ogre/selectionbuffer.cpp +++ b/libs/openengine/ogre/selectionbuffer.cpp @@ -10,6 +10,8 @@ #include +#include + #include namespace OEngine @@ -145,7 +147,7 @@ namespace Render void SelectionBuffer::getNextColour () { - Ogre::ARGB color = static_cast((float(rand()) / float(RAND_MAX)) * std::numeric_limits::max()); + Ogre::ARGB color = static_cast(OEngine::Misc::Rng::rollClosedProbability() * std::numeric_limits::max()); if (mCurrentColour.getAsARGB () == color) { From a418b709370e23df0d3b0612ff93a666032387eb Mon Sep 17 00:00:00 2001 From: sylar Date: Sun, 15 Mar 2015 21:15:58 +0400 Subject: [PATCH 0755/3725] command line support for Android --- apps/openmw/CMakeLists.txt | 1 + apps/openmw/android_commandLine.cpp | 18 +++++++++++++ apps/openmw/android_commandLine.h | 16 ++++++++++++ apps/openmw/android_main.c | 40 ++++++++++++----------------- 4 files changed, 52 insertions(+), 23 deletions(-) create mode 100644 apps/openmw/android_commandLine.cpp create mode 100644 apps/openmw/android_commandLine.h diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 860cc2fcb..a183d172d 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -7,6 +7,7 @@ set(GAME ) if (ANDROID) + set(GAME ${GAME} android_commandLine.cpp) set(GAME ${GAME} android_main.c) endif() diff --git a/apps/openmw/android_commandLine.cpp b/apps/openmw/android_commandLine.cpp new file mode 100644 index 000000000..bb95a0534 --- /dev/null +++ b/apps/openmw/android_commandLine.cpp @@ -0,0 +1,18 @@ +#include "android_commandLine.h" +#include "string.h" + + const char *argvData[15]; + int argcData; + +JNIEXPORT void JNICALL Java_ui_activity_GameActivity_commandLine(JNIEnv *env, + jobject obj, jint argc, jobjectArray stringArray) { + jboolean iscopy; + argcData = (int) argc; + argvData[0]="openmw"; + for (int i = 0; i < argcData; i++) { + jstring string = (jstring) (*env).GetObjectArrayElement(stringArray, i); + argvData[i+1] = (env)->GetStringUTFChars(string, &iscopy); + } + +} + diff --git a/apps/openmw/android_commandLine.h b/apps/openmw/android_commandLine.h new file mode 100644 index 000000000..21d1064c6 --- /dev/null +++ b/apps/openmw/android_commandLine.h @@ -0,0 +1,16 @@ + + +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +#ifndef _Included_ui_activity_GameActivity_commandLine +#define _Included_ui_activity_GameActivity_commandLine +#ifdef __cplusplus +extern "C" { +#endif + +JNIEXPORT void JNICALL Java_ui_activity_GameActivity_commandLine(JNIEnv *env, jobject obj,jint argcData, jobjectArray stringArray); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/apps/openmw/android_main.c b/apps/openmw/android_main.c index 76da91c4f..0cfb8dcfa 100644 --- a/apps/openmw/android_main.c +++ b/apps/openmw/android_main.c @@ -1,42 +1,36 @@ - #include "../../SDL_internal.h" #ifdef __ANDROID__ #include "SDL_main.h" - /******************************************************************************* - Functions called by JNI -*******************************************************************************/ + Functions called by JNI + *******************************************************************************/ #include /* Called before to initialize JNI bindings */ - - extern void SDL_Android_Init(JNIEnv* env, jclass cls); +extern int argcData; +extern const char *argvData[15]; + +int Java_org_libsdl_app_SDLActivity_nativeInit(JNIEnv* env, jclass cls, + jobject obj) { + + SDL_Android_Init(env, cls); + + SDL_SetMainReady(); + /* Run the application code! */ -int Java_org_libsdl_app_SDLActivity_nativeInit(JNIEnv* env, jclass cls, jobject obj) -{ - - SDL_Android_Init(env, cls); - - SDL_SetMainReady(); + int status; - -/* Run the application code! */ - - int status; - char *argv[2]; - argv[0] = SDL_strdup("openmw"); - argv[1] = NULL; - status = main(1, argv); + status = main(argcData+1, argvData); - /* Do not issue an exit or the whole application will terminate instead of just the SDL thread */ - /* exit(status); */ + /* Do not issue an exit or the whole application will terminate instead of just the SDL thread */ + /* exit(status); */ - return status; + return status; } #endif /* __ANDROID__ */ From 48e2ec2840a1f3d16fa5e90d9b70bae95f770aaa Mon Sep 17 00:00:00 2001 From: Nathan Aclander Date: Sun, 15 Mar 2015 16:20:17 -0700 Subject: [PATCH 0756/3725] Fix comparison of integers of different signs Clang reported comparison of unsigned long with long. This cast should fix it. --- components/bsa/bsa_file.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bsa/bsa_file.cpp b/components/bsa/bsa_file.cpp index 0d60f4cf0..3bf73ede2 100644 --- a/components/bsa/bsa_file.cpp +++ b/components/bsa/bsa_file.cpp @@ -111,7 +111,7 @@ void BSAFile::readHeader() // Each file must take up at least 21 bytes of data in the bsa. So // if files*21 overflows the file size then we are guaranteed that // the archive is corrupt. - if((filenum*21 > fsize -12) || (dirsize+8*filenum > fsize -12) ) + if((filenum*21 > unsigned(fsize -12)) || (dirsize+8*filenum > unsigned(fsize -12)) ) fail("Directory information larger than entire archive"); // Read the offset info into a temporary buffer From 4d0bb6329a17d0f3d66ae885342d00be842a6221 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 16 Mar 2015 01:50:57 +0100 Subject: [PATCH 0757/3725] Fix incorrect reference check This check was broken for exterior cells (empty cell id). It was superfluous anyway. A CellRef is owned by the cell it is in, so the cell must always exist. --- apps/opencs/model/tools/referencecheck.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/apps/opencs/model/tools/referencecheck.cpp b/apps/opencs/model/tools/referencecheck.cpp index 68de87d80..198c3627f 100644 --- a/apps/opencs/model/tools/referencecheck.cpp +++ b/apps/opencs/model/tools/referencecheck.cpp @@ -48,10 +48,6 @@ void CSMTools::ReferenceCheckStage::perform(int stage, CSMDoc::Messages &message } } - // Check if referenced object is in valid cell - if (mCells.searchId(cellRef.mCell) == -1) - messages.push_back(std::make_pair(id, " is referencing object from non existing cell " + cellRef.mCell)); - // If object have owner, check if that owner reference is valid if (!cellRef.mOwner.empty() && mReferencables.searchId(cellRef.mOwner) == -1) messages.push_back(std::make_pair(id, " has non existing owner " + cellRef.mOwner)); From 295ca86ac1f28414186d6785713d8fa7c283f519 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 16 Mar 2015 02:43:02 +0100 Subject: [PATCH 0758/3725] OpenCS FileDialog crash fix The file dialog would crash when no game file is selected and an addon file with no dependency is checked, then unchecked. --- apps/opencs/view/doc/filedialog.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/opencs/view/doc/filedialog.cpp b/apps/opencs/view/doc/filedialog.cpp index 8dd83f24a..1b3196112 100644 --- a/apps/opencs/view/doc/filedialog.cpp +++ b/apps/opencs/view/doc/filedialog.cpp @@ -153,11 +153,13 @@ void CSVDoc::FileDialog::slotUpdateAcceptButton(const QString &name, bool) if (isNew) success = success && !(name.isEmpty()); - else + else if (success) { ContentSelectorModel::EsmFile *file = mSelector->selectedFiles().back(); mAdjusterWidget->setName (file->filePath(), !file->isGameFile()); } + else + mAdjusterWidget->setName ("", true); ui.projectButtonBox->button (QDialogButtonBox::Ok)->setEnabled (success); } From 6ff2523d8ada97b45333a30831817a674fe915e4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 16 Mar 2015 03:07:37 +0100 Subject: [PATCH 0759/3725] Fix for line focus when clicking on a verifier script error - setFocus() on the script editor, otherwise setting the text cursor has no effect. - setFocus() must be done after the widgets are created/shown, or the newly created widgets will "steal" the focus again. - Missing useHint in case subviews are reused. --- apps/opencs/view/doc/view.cpp | 7 +++++-- apps/opencs/view/world/scriptsubview.cpp | 1 + 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 211f74187..5d42902e8 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -485,6 +485,8 @@ void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id, const std::strin (!isReferenceable && id == sb->getUniversalId())) { sb->setFocus(); + if (!hint.empty()) + sb->useHint (hint); return; } } @@ -515,8 +517,6 @@ void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id, const std::strin assert(view); view->setParent(this); mSubViews.append(view); // only after assert - if (!hint.empty()) - view->useHint (hint); int minWidth = userSettings.setting ("window/minimum-width", QString("325")).toInt(); view->setMinimumWidth(minWidth); @@ -538,6 +538,9 @@ void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id, const std::strin this, SLOT (updateSubViewIndicies (SubView *))); view->show(); + + if (!hint.empty()) + view->useHint (hint); } void CSVDoc::View::newView() diff --git a/apps/opencs/view/world/scriptsubview.cpp b/apps/opencs/view/world/scriptsubview.cpp index 9b50a61f8..211462a26 100644 --- a/apps/opencs/view/world/scriptsubview.cpp +++ b/apps/opencs/view/world/scriptsubview.cpp @@ -68,6 +68,7 @@ void CSVWorld::ScriptSubView::useHint (const std::string& hint) if (cursor.movePosition (QTextCursor::Down, QTextCursor::MoveAnchor, line)) cursor.movePosition (QTextCursor::Right, QTextCursor::MoveAnchor, column); + mEditor->setFocus(); mEditor->setTextCursor (cursor); } } From 76adb64e20f90d58d53e43aa2d2587ea89992924 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 16 Mar 2015 13:21:02 +1100 Subject: [PATCH 0760/3725] Compilation fix after merging commt e30f24 --- apps/opencs/model/world/nestedadaptors.hpp | 134 ++++++++++----------- 1 file changed, 66 insertions(+), 68 deletions(-) diff --git a/apps/opencs/model/world/nestedadaptors.hpp b/apps/opencs/model/world/nestedadaptors.hpp index 6e3d447b2..cc062e827 100644 --- a/apps/opencs/model/world/nestedadaptors.hpp +++ b/apps/opencs/model/world/nestedadaptors.hpp @@ -34,16 +34,16 @@ namespace CSMWorld public: HelperBase(CSMWorld::UniversalId::Type type); - + virtual ~HelperBase(); - + virtual void setNestedTable(RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) = 0; - + virtual NestedTableWrapperBase* nestedTable(const RefIdData& data, int index) const = 0; - + virtual QVariant getNestedData(const CSMWorld::RefIdData& data, int index, int subRowIndex, @@ -58,7 +58,7 @@ namespace CSMWorld const QVariant& value, int subRowIndex, int subColIndex) const = 0; - + virtual void addNestedRow (RefIdData& data, int index, int position) const = 0; @@ -72,7 +72,7 @@ namespace CSMWorld template class CastableHelper : public HelperBase { - + public: CastableHelper(CSMWorld::UniversalId::Type type) : HelperBase(type) {} @@ -96,23 +96,23 @@ namespace CSMWorld { public: - SpellsHelper(CSMWorld::UniversalId::Type type) + SpellsHelper(CSMWorld::UniversalId::Type type) : CastableHelper(type) {} virtual void setNestedTable(RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) { - CastableHelper::getRecord(data, index).get().mSpells.mList = + CastableHelper::getRecord(data, index).get().mSpells.mList = (static_cast >&>(nestedTable)).mNestedTable; } - + virtual NestedTableWrapperBase* nestedTable(const RefIdData& data, int index) const { return new NestedTableWrapper >(CastableHelper::getRecord(data, index).get().mSpells.mList); } - + virtual QVariant getNestedData(const CSMWorld::RefIdData& data, int index, int subRowIndex, @@ -124,7 +124,7 @@ namespace CSMWorld { return QString::fromUtf8(content.c_str()); } - + throw std::logic_error("Trying to access non-existing column in the nested table!"); } @@ -144,11 +144,11 @@ namespace CSMWorld if (subColIndex == 0) { CastableHelper::getRecord(data, index).get().mSpells.mList.at(subRowIndex) = std::string(value.toString().toUtf8()); - } + } throw std::logic_error("Trying to access non-existing column in the nested table!"); } - + virtual void addNestedRow (RefIdData& data, int index, int position) const { std::vector& list = CastableHelper::getRecord(data, index).get().mSpells.mList; @@ -159,15 +159,15 @@ namespace CSMWorld list.push_back(newString); return; } - + list.insert(list.begin()+position, newString); } - + virtual int getNestedColumnsCount(const RefIdData& data) const { return 1; } - + virtual int getNestedRowsCount(const RefIdData& data, int index) const @@ -183,23 +183,23 @@ namespace CSMWorld { public: - MagicEffectsHelper(CSMWorld::UniversalId::Type type) + MagicEffectsHelper(CSMWorld::UniversalId::Type type) : CastableHelper(type) {} virtual void setNestedTable(RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) { - CastableHelper::getRecord(data, index).get().mEffects = + CastableHelper::getRecord(data, index).get().mEffects = (static_cast&>(nestedTable)).mNestedTable; } - + virtual NestedTableWrapperBase* nestedTable(const RefIdData& data, int index) const { return new NestedTableWrapper(CastableHelper::getRecord(data, index).get().mEffects); } - + virtual QVariant getNestedData(const CSMWorld::RefIdData& data, int index, int subRowIndex, @@ -211,7 +211,7 @@ namespace CSMWorld { case 0: return content.at(subRowIndex).mEffectID; - + case 1: return content.at(subRowIndex).mRange; @@ -226,13 +226,13 @@ namespace CSMWorld case 5: return content.at(subRowIndex).mMagMax; - + case 6: return (int)content.at(rubRowIndex).mSkill; case 7: return (int)content.at(subRowIndex).mAttribute; - + default: throw std::logic_error("Trying to access non-existing column in the nested table!"); } @@ -261,10 +261,10 @@ namespace CSMWorld throw std::logic_error("Trying to access non-existing column in the nested table!"); } } - + virtual void addNestedRow (RefIdData& data, int index, int position) const { - std::vector& list = CastableHelper::getRecord(data, index).get().mTransport; + std::vector& list = CastableHelper::getRecord(data, index).get().mTransport.mList; ESM::Position newPos; for (unsigned i = 0; i < 3; ++i) @@ -273,7 +273,7 @@ namespace CSMWorld newPos.rot[i] = 0; } - ESM::NPC::Dest newRow; + ESM::Transport::Dest newRow; newRow.mPos = newPos; newRow.mCellName = ""; @@ -282,20 +282,20 @@ namespace CSMWorld list.push_back(newRow); return; } - + list.insert(list.begin()+position, newRow); } - + virtual int getNestedColumnsCount(const RefIdData& data) const { return 7; } - + virtual int getNestedRowsCount(const RefIdData& data, int index) const { - return CastableHelper::getRecord(data, index).get().mTransport.size(); + return CastableHelper::getRecord(data, index).get().mTransport.mList.size(); } }; @@ -305,35 +305,35 @@ namespace CSMWorld { public: - DestinationsHelper(CSMWorld::UniversalId::Type type) + DestinationsHelper(CSMWorld::UniversalId::Type type) : CastableHelper(type) {} virtual void setNestedTable(RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) { - CastableHelper::getRecord(data, index).get().mTransport = - (static_cast >&>(nestedTable)).mNestedTable; + CastableHelper::getRecord(data, index).get().mTransport.mList = + (static_cast >&>(nestedTable)).mNestedTable; } - + virtual NestedTableWrapperBase* nestedTable(const RefIdData& data, int index) const { - return new NestedTableWrapper >(CastableHelper::getRecord(data, index).get().mTransport); + return new NestedTableWrapper >(CastableHelper::getRecord(data, index).get().mTransport.mList); } - + virtual QVariant getNestedData(const CSMWorld::RefIdData& data, int index, int subRowIndex, int subColIndex) const { - const ESM::NPC::Dest& content = CastableHelper::getRecord(data, index).get().mTransport.at(subRowIndex); + const ESM::Transport::Dest& content = CastableHelper::getRecord(data, index).get().mTransport.mList.at(subRowIndex); switch (subColIndex) { case 0: return QString::fromUtf8(content.mCellName.c_str()); - + case 1: return content.mPos.pos[0]; @@ -351,7 +351,7 @@ namespace CSMWorld case 6: return content.mPos.rot[2]; - + default: throw std::logic_error("Trying to access non-existing column in the nested table!"); } @@ -359,7 +359,7 @@ namespace CSMWorld virtual void removeNestedRow (RefIdData& data, int index, int rowToRemove) const { - std::vector& list = CastableHelper::getRecord(data, index).get().mTransport; + std::vector& list = CastableHelper::getRecord(data, index).get().mTransport.mList; list.erase (list.begin () + rowToRemove); } @@ -373,41 +373,41 @@ namespace CSMWorld switch(subColIndex) { case 0: - CastableHelper::getRecord(data, index).get().mTransport.at(subRowIndex).mCellName = std::string(value.toString().toUtf8().constData()); + CastableHelper::getRecord(data, index).get().mTransport.mList.at(subRowIndex).mCellName = std::string(value.toString().toUtf8().constData()); break; case 1: - CastableHelper::getRecord(data, index).get().mTransport.at(subRowIndex).mPos.pos[0] = value.toFloat(); + CastableHelper::getRecord(data, index).get().mTransport.mList.at(subRowIndex).mPos.pos[0] = value.toFloat(); break; - + case 2: - CastableHelper::getRecord(data, index).get().mTransport.at(subRowIndex).mPos.pos[1] = value.toFloat(); + CastableHelper::getRecord(data, index).get().mTransport.mList.at(subRowIndex).mPos.pos[1] = value.toFloat(); break; - + case 3: - CastableHelper::getRecord(data, index).get().mTransport.at(subRowIndex).mPos.pos[2] = value.toFloat(); + CastableHelper::getRecord(data, index).get().mTransport.mList.at(subRowIndex).mPos.pos[2] = value.toFloat(); break; - + case 4: - CastableHelper::getRecord(data, index).get().mTransport.at(subRowIndex).mPos.rot[0] = value.toFloat(); + CastableHelper::getRecord(data, index).get().mTransport.mList.at(subRowIndex).mPos.rot[0] = value.toFloat(); break; case 5: - CastableHelper::getRecord(data, index).get().mTransport.at(subRowIndex).mPos.rot[1] = value.toFloat(); + CastableHelper::getRecord(data, index).get().mTransport.mList.at(subRowIndex).mPos.rot[1] = value.toFloat(); break; case 6: - CastableHelper::getRecord(data, index).get().mTransport.at(subRowIndex).mPos.rot[2] = value.toFloat(); + CastableHelper::getRecord(data, index).get().mTransport.mList.at(subRowIndex).mPos.rot[2] = value.toFloat(); break; default: throw std::logic_error("Trying to access non-existing column in the nested table!"); } } - + virtual void addNestedRow (RefIdData& data, int index, int position) const { - std::vector& list = CastableHelper::getRecord(data, index).get().mTransport; + std::vector& list = CastableHelper::getRecord(data, index).get().mTransport.mList; ESM::Position newPos; for (unsigned i = 0; i < 3; ++i) @@ -416,7 +416,7 @@ namespace CSMWorld newPos.rot[i] = 0; } - ESM::NPC::Dest newRow; + ESM::Transport::Dest newRow; newRow.mPos = newPos; newRow.mCellName = ""; @@ -425,20 +425,19 @@ namespace CSMWorld list.push_back(newRow); return; } - + list.insert(list.begin()+position, newRow); } - + virtual int getNestedColumnsCount(const RefIdData& data) const { return 7; } - virtual int getNestedRowsCount(const RefIdData& data, int index) const { - return CastableHelper::getRecord(data, index).get().mTransport.size(); + return CastableHelper::getRecord(data, index).get().mTransport.mList.size(); } }; @@ -448,23 +447,23 @@ namespace CSMWorld { public: - InventoryHelper(CSMWorld::UniversalId::Type type) + InventoryHelper(CSMWorld::UniversalId::Type type) : CastableHelper(type) {} virtual void setNestedTable(RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) { - CastableHelper::getRecord(data, index).get().mInventory.mList = + CastableHelper::getRecord(data, index).get().mInventory.mList = (static_cast >&>(nestedTable)).mNestedTable; } - + virtual NestedTableWrapperBase* nestedTable(const RefIdData& data, int index) const { return new NestedTableWrapper >(CastableHelper::getRecord(data, index).get().mInventory.mList); } - + virtual QVariant getNestedData(const CSMWorld::RefIdData& data, int index, int subRowIndex, @@ -476,10 +475,10 @@ namespace CSMWorld { case 0: return QString::fromUtf8(content.mItem.toString().c_str()); - + case 1: return content.mCount; - + default: throw std::logic_error("Trying to access non-existing column in the nested table!"); } @@ -507,12 +506,12 @@ namespace CSMWorld case 1: CastableHelper::getRecord(data, index).get().mInventory.mList.at(subRowIndex).mCount = value.toInt(); break; - + default: throw std::logic_error("Trying to access non-existing column in the nested table!"); } } - + virtual void addNestedRow (RefIdData& data, int index, int position) const { std::vector& list = CastableHelper::getRecord(data, index).get().mInventory.mList; @@ -523,15 +522,14 @@ namespace CSMWorld list.push_back(newRow); return; } - + list.insert(list.begin()+position, newRow); } - + virtual int getNestedColumnsCount(const RefIdData& data) const { return 2; } - virtual int getNestedRowsCount(const RefIdData& data, int index) const From bd4e832cf3c691ad027df5326b91226cfcedbe17 Mon Sep 17 00:00:00 2001 From: sylar Date: Mon, 16 Mar 2015 07:41:51 +0400 Subject: [PATCH 0761/3725] fix memory leaks in emulating command line --- apps/openmw/android_commandLine.cpp | 16 +++++++++------- apps/openmw/android_main.c | 3 ++- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/apps/openmw/android_commandLine.cpp b/apps/openmw/android_commandLine.cpp index bb95a0534..129e63797 100644 --- a/apps/openmw/android_commandLine.cpp +++ b/apps/openmw/android_commandLine.cpp @@ -1,18 +1,20 @@ #include "android_commandLine.h" #include "string.h" - const char *argvData[15]; - int argcData; + + +const char **argvData; +int argcData; JNIEXPORT void JNICALL Java_ui_activity_GameActivity_commandLine(JNIEnv *env, jobject obj, jint argc, jobjectArray stringArray) { jboolean iscopy; argcData = (int) argc; - argvData[0]="openmw"; - for (int i = 0; i < argcData; i++) { - jstring string = (jstring) (*env).GetObjectArrayElement(stringArray, i); - argvData[i+1] = (env)->GetStringUTFChars(string, &iscopy); + argvData= new const char * [argcData+1]; + argvData[0] = "openmw"; + for (int i = 1; i < argcData+1; i++) { + jstring string = (jstring) (*env).GetObjectArrayElement(stringArray, i-1); + argvData[i] = (env)->GetStringUTFChars(string, &iscopy); } - } diff --git a/apps/openmw/android_main.c b/apps/openmw/android_main.c index 0cfb8dcfa..d3a6ca63a 100644 --- a/apps/openmw/android_main.c +++ b/apps/openmw/android_main.c @@ -12,7 +12,7 @@ extern void SDL_Android_Init(JNIEnv* env, jclass cls); extern int argcData; -extern const char *argvData[15]; +extern const char **argvData; int Java_org_libsdl_app_SDLActivity_nativeInit(JNIEnv* env, jclass cls, jobject obj) { @@ -26,6 +26,7 @@ int Java_org_libsdl_app_SDLActivity_nativeInit(JNIEnv* env, jclass cls, int status; status = main(argcData+1, argvData); + free (argvData); /* Do not issue an exit or the whole application will terminate instead of just the SDL thread */ /* exit(status); */ From db10c87b8961779ea76f930d1738b36c729cb9de Mon Sep 17 00:00:00 2001 From: sylar Date: Mon, 16 Mar 2015 18:21:38 +0400 Subject: [PATCH 0762/3725] release jni memory --- apps/openmw/android_commandLine.cpp | 17 ++++++++++++----- apps/openmw/android_main.c | 4 ++-- components/files/androidpath.cpp | 1 + 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/apps/openmw/android_commandLine.cpp b/apps/openmw/android_commandLine.cpp index 129e63797..ebfff28ca 100644 --- a/apps/openmw/android_commandLine.cpp +++ b/apps/openmw/android_commandLine.cpp @@ -1,20 +1,27 @@ #include "android_commandLine.h" #include "string.h" - - const char **argvData; int argcData; +extern "C" void releaseArgv(); + +void releaseArgv() { + delete[] argvData; +} + JNIEXPORT void JNICALL Java_ui_activity_GameActivity_commandLine(JNIEnv *env, jobject obj, jint argc, jobjectArray stringArray) { jboolean iscopy; argcData = (int) argc; - argvData= new const char * [argcData+1]; + argvData = new const char *[argcData + 1]; argvData[0] = "openmw"; - for (int i = 1; i < argcData+1; i++) { - jstring string = (jstring) (*env).GetObjectArrayElement(stringArray, i-1); + for (int i = 1; i < argcData + 1; i++) { + jstring string = (jstring) (env)->GetObjectArrayElement(stringArray, + i - 1); argvData[i] = (env)->GetStringUTFChars(string, &iscopy); + (env)->DeleteLocalRef(string); } + (env)->DeleteLocalRef(stringArray); } diff --git a/apps/openmw/android_main.c b/apps/openmw/android_main.c index d3a6ca63a..1b2839519 100644 --- a/apps/openmw/android_main.c +++ b/apps/openmw/android_main.c @@ -13,6 +13,7 @@ extern void SDL_Android_Init(JNIEnv* env, jclass cls); extern int argcData; extern const char **argvData; +void releaseArgv(); int Java_org_libsdl_app_SDLActivity_nativeInit(JNIEnv* env, jclass cls, jobject obj) { @@ -26,8 +27,7 @@ int Java_org_libsdl_app_SDLActivity_nativeInit(JNIEnv* env, jclass cls, int status; status = main(argcData+1, argvData); - free (argvData); - + releaseArgv(); /* Do not issue an exit or the whole application will terminate instead of just the SDL thread */ /* exit(status); */ diff --git a/components/files/androidpath.cpp b/components/files/androidpath.cpp index 009bd98a2..84886f473 100644 --- a/components/files/androidpath.cpp +++ b/components/files/androidpath.cpp @@ -31,6 +31,7 @@ JNIEXPORT void JNICALL Java_ui_activity_GameActivity_getPathToJni(JNIEnv *env, j { jboolean iscopy; Buffer::setData((env)->GetStringUTFChars(prompt, &iscopy)); + (env)->DeleteLocalRef(prompt); } namespace From f7ecda68c92e48779f376f27fb30738ec617dd25 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 16 Mar 2015 15:33:12 +0100 Subject: [PATCH 0763/3725] Fix for unicode filenames in ContentModel (Fixes #2451) --- components/contentselector/model/contentmodel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/contentselector/model/contentmodel.cpp b/components/contentselector/model/contentmodel.cpp index 3dc02af21..62f6d9014 100644 --- a/components/contentselector/model/contentmodel.cpp +++ b/components/contentselector/model/contentmodel.cpp @@ -449,7 +449,7 @@ void ContentSelectorModel::ContentModel::addFiles(const QString &path) ToUTF8::Utf8Encoder encoder = ToUTF8::calculateEncoding(mEncoding.toStdString()); fileReader.setEncoder(&encoder); - fileReader.open(dir.absoluteFilePath(path).toStdString()); + fileReader.open(std::string(dir.absoluteFilePath(path).toUtf8().constData())); EsmFile *file = new EsmFile(path); From 19e8280f4550b1c3d14ca94c9fcccd7ae90fd1e8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 16 Mar 2015 15:45:41 +0100 Subject: [PATCH 0764/3725] OpenCS window title unicode fixes --- apps/opencs/view/doc/loader.cpp | 2 +- apps/opencs/view/doc/subview.cpp | 2 +- apps/opencs/view/doc/view.cpp | 2 +- apps/opencs/view/doc/viewmanager.cpp | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/opencs/view/doc/loader.cpp b/apps/opencs/view/doc/loader.cpp index 046eb5229..30235d0f5 100644 --- a/apps/opencs/view/doc/loader.cpp +++ b/apps/opencs/view/doc/loader.cpp @@ -20,7 +20,7 @@ void CSVDoc::LoadingDocument::closeEvent (QCloseEvent *event) CSVDoc::LoadingDocument::LoadingDocument (CSMDoc::Document *document) : mDocument (document), mAborted (false), mMessages (0), mTotalRecords (0) { - setWindowTitle (("Opening " + document->getSavePath().filename().string()).c_str()); + setWindowTitle (QString::fromUtf8((std::string("Opening ") + document->getSavePath().filename().string()).c_str())); setMinimumWidth (400); diff --git a/apps/opencs/view/doc/subview.cpp b/apps/opencs/view/doc/subview.cpp index a399b5b5b..df1e7ee49 100644 --- a/apps/opencs/view/doc/subview.cpp +++ b/apps/opencs/view/doc/subview.cpp @@ -26,7 +26,7 @@ void CSVDoc::SubView::updateUserSetting (const QString &, const QStringList &) void CSVDoc::SubView::setUniversalId (const CSMWorld::UniversalId& id) { mUniversalId = id; - setWindowTitle (mUniversalId.toString().c_str()); + setWindowTitle (QString::fromUtf8(mUniversalId.toString().c_str())); } void CSVDoc::SubView::closeEvent (QCloseEvent *event) diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 5d42902e8..cf2940b99 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -324,7 +324,7 @@ void CSVDoc::View::updateTitle() if (hideTitle) stream << " - " << mSubViews.at (0)->getTitle(); - setWindowTitle (stream.str().c_str()); + setWindowTitle (QString::fromUtf8(stream.str().c_str())); } void CSVDoc::View::updateSubViewIndicies(SubView *view) diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 5f6b6b46a..9fee26078 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -248,7 +248,7 @@ bool CSVDoc::ViewManager::showModifiedDocumentMessageBox (CSVDoc::View *view) QMessageBox messageBox(view); CSMDoc::Document *document = view->getDocument(); - messageBox.setWindowTitle (document->getSavePath().filename().string().c_str()); + messageBox.setWindowTitle (QString::fromUtf8(document->getSavePath().filename().string().c_str())); messageBox.setText ("The document has been modified."); messageBox.setInformativeText ("Do you want to save your changes?"); messageBox.setStandardButtons (QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel); From d5734588964d9d8d7e99142ed72e7c8f60cc819f Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 16 Mar 2015 17:37:54 +0100 Subject: [PATCH 0765/3725] Fix case sensitivity bug in default head/hair selection (Fixes #2453) --- apps/openmw/mwgui/race.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index 97dbfbafc..f908a9dd0 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -142,13 +142,13 @@ namespace MWGui for (unsigned int i=0; i Date: Tue, 17 Mar 2015 12:30:47 +0100 Subject: [PATCH 0766/3725] setting up global search operation and subview --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/doc/document.cpp | 6 +++++ apps/opencs/model/doc/document.hpp | 2 ++ apps/opencs/model/doc/state.hpp | 2 +- apps/opencs/model/tools/tools.cpp | 23 +++++++++++++--- apps/opencs/model/tools/tools.hpp | 5 ++++ apps/opencs/model/world/universalid.cpp | 1 + apps/opencs/model/world/universalid.hpp | 1 + apps/opencs/view/doc/view.cpp | 9 +++++++ apps/opencs/view/doc/view.hpp | 2 ++ apps/opencs/view/tools/searchsubview.cpp | 23 ++++++++++++++++ apps/opencs/view/tools/searchsubview.hpp | 34 ++++++++++++++++++++++++ apps/opencs/view/tools/subviews.cpp | 3 +++ 13 files changed, 108 insertions(+), 5 deletions(-) create mode 100644 apps/opencs/view/tools/searchsubview.cpp create mode 100644 apps/opencs/view/tools/searchsubview.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index e618d2961..e3b44ac91 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -91,7 +91,7 @@ opencs_hdrs_noqt (view/render opencs_units (view/tools - reportsubview reporttable + reportsubview reporttable searchsubview ) opencs_units_noqt (view/tools diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 7d27143b4..a06eb0ebf 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -2374,6 +2374,12 @@ CSMWorld::UniversalId CSMDoc::Document::verify() return id; } + +CSMWorld::UniversalId CSMDoc::Document::newSearch() +{ + return mTools.newSearch(); +} + void CSMDoc::Document::abortOperation (int type) { if (type==State_Saving) diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp index 1f96b44a1..4300a9c64 100644 --- a/apps/opencs/model/doc/document.hpp +++ b/apps/opencs/model/doc/document.hpp @@ -120,6 +120,8 @@ namespace CSMDoc CSMWorld::UniversalId verify(); + CSMWorld::UniversalId newSearch(); + void abortOperation (int type); const CSMWorld::Data& getData() const; diff --git a/apps/opencs/model/doc/state.hpp b/apps/opencs/model/doc/state.hpp index 287439a8b..78f468101 100644 --- a/apps/opencs/model/doc/state.hpp +++ b/apps/opencs/model/doc/state.hpp @@ -13,7 +13,7 @@ namespace CSMDoc State_Saving = 16, State_Verifying = 32, State_Compiling = 64, // not implemented yet - State_Searching = 128, // not implemented yet + State_Searching = 128, State_Loading = 256 // pseudo-state; can not be encountered in a loaded document }; } diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index 170ea8ccd..07bd4205b 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -31,6 +31,7 @@ CSMDoc::OperationHolder *CSMTools::Tools::get (int type) switch (type) { case CSMDoc::State_Verifying: return &mVerifier; + case CSMDoc::State_Searching: return &mSearch; } return 0; @@ -101,7 +102,8 @@ CSMDoc::OperationHolder *CSMTools::Tools::getVerifier() } CSMTools::Tools::Tools (CSMDoc::Document& document) -: mDocument (document), mData (document.getData()), mVerifierOperation (0), mNextReportNumber (0) +: mDocument (document), mData (document.getData()), mVerifierOperation (0), mNextReportNumber (0), + mSearchOperation (0) { // index 0: load error log mReports.insert (std::make_pair (mNextReportNumber++, new ReportModel)); @@ -116,6 +118,12 @@ CSMTools::Tools::~Tools() delete mVerifierOperation; } + if (mSearchOperation) + { + mSearch.abortAndWait(); + delete mSearchOperation; + } + for (std::map::iterator iter (mReports.begin()); iter!=mReports.end(); ++iter) delete iter->second; } @@ -130,6 +138,13 @@ CSMWorld::UniversalId CSMTools::Tools::runVerifier() return CSMWorld::UniversalId (CSMWorld::UniversalId::Type_VerificationResults, mNextReportNumber-1); } +CSMWorld::UniversalId CSMTools::Tools::newSearch() +{ + mReports.insert (std::make_pair (mNextReportNumber++, new ReportModel)); + + return CSMWorld::UniversalId (CSMWorld::UniversalId::Type_Search, mNextReportNumber-1); +} + void CSMTools::Tools::abortOperation (int type) { if (CSMDoc::OperationHolder *operation = get (type)) @@ -141,6 +156,7 @@ int CSMTools::Tools::getRunningOperations() const static const int sOperations[] = { CSMDoc::State_Verifying, + CSMDoc::State_Searching, -1 }; @@ -157,9 +173,10 @@ int CSMTools::Tools::getRunningOperations() const CSMTools::ReportModel *CSMTools::Tools::getReport (const CSMWorld::UniversalId& id) { if (id.getType()!=CSMWorld::UniversalId::Type_VerificationResults && - id.getType()!=CSMWorld::UniversalId::Type_LoadErrorLog) + id.getType()!=CSMWorld::UniversalId::Type_LoadErrorLog && + id.getType()!=CSMWorld::UniversalId::Type_Search) throw std::logic_error ("invalid request for report model: " + id.toString()); - + return mReports.at (id.getIndex()); } diff --git a/apps/opencs/model/tools/tools.hpp b/apps/opencs/model/tools/tools.hpp index b8ded8a83..bd27767a6 100644 --- a/apps/opencs/model/tools/tools.hpp +++ b/apps/opencs/model/tools/tools.hpp @@ -31,6 +31,8 @@ namespace CSMTools CSMWorld::Data& mData; CSMDoc::Operation *mVerifierOperation; CSMDoc::OperationHolder mVerifier; + CSMDoc::Operation *mSearchOperation; + CSMDoc::OperationHolder mSearch; std::map mReports; int mNextReportNumber; std::map mActiveReports; // type, report number @@ -56,6 +58,9 @@ namespace CSMTools CSMWorld::UniversalId runVerifier(); ///< \return ID of the report for this verification run + /// Return ID of the report for this search. + CSMWorld::UniversalId newSearch(); + void abortOperation (int type); ///< \attention The operation is not aborted immediately. diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index 50ac846db..6aa129f25 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -128,6 +128,7 @@ namespace { { CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_VerificationResults, "Verification Results", 0 }, { CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_LoadErrorLog, "Load Error Log", 0 }, + { CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_Search, "Global Search", 0 }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0, 0 } // end marker }; } diff --git a/apps/opencs/model/world/universalid.hpp b/apps/opencs/model/world/universalid.hpp index a716aec03..f01e811ca 100644 --- a/apps/opencs/model/world/universalid.hpp +++ b/apps/opencs/model/world/universalid.hpp @@ -130,6 +130,7 @@ namespace CSMWorld Type_Pathgrid, Type_StartScripts, Type_StartScript, + Type_Search, Type_RunLog }; diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 211f74187..3cabd8737 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -113,6 +113,10 @@ void CSVDoc::View::setupViewMenu() QAction *filters = new QAction (tr ("Filters"), this); connect (filters, SIGNAL (triggered()), this, SLOT (addFiltersSubView())); view->addAction (filters); + + QAction *search = new QAction (tr ("Search"), this); + connect (search, SIGNAL (triggered()), this, SLOT (addSearchSubView())); + view->addAction (search); } void CSVDoc::View::setupWorldMenu() @@ -725,6 +729,11 @@ void CSVDoc::View::addStartScriptsSubView() addSubView (CSMWorld::UniversalId::Type_StartScripts); } +void CSVDoc::View::addSearchSubView() +{ + addSubView (mDocument->newSearch()); +} + void CSVDoc::View::abortOperation (int type) { mDocument->abortOperation (type); diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index baadca85c..32d7159c2 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -217,6 +217,8 @@ namespace CSVDoc void addStartScriptsSubView(); + void addSearchSubView(); + void toggleShowStatusBar (bool show); void loadErrorLog(); diff --git a/apps/opencs/view/tools/searchsubview.cpp b/apps/opencs/view/tools/searchsubview.cpp new file mode 100644 index 000000000..7173a6634 --- /dev/null +++ b/apps/opencs/view/tools/searchsubview.cpp @@ -0,0 +1,23 @@ + +#include "searchsubview.hpp" + +#include "reporttable.hpp" + +CSVTools::SearchSubView::SearchSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) +: CSVDoc::SubView (id) +{ + setWidget (mTable = new ReportTable (document, id, this)); + + connect (mTable, SIGNAL (editRequest (const CSMWorld::UniversalId&, const std::string&)), + SIGNAL (focusId (const CSMWorld::UniversalId&, const std::string&))); +} + +void CSVTools::SearchSubView::setEditLock (bool locked) +{ + // ignored. We don't change document state anyway. +} + +void CSVTools::SearchSubView::updateUserSetting (const QString &name, const QStringList &list) +{ + mTable->updateUserSetting (name, list); +} diff --git a/apps/opencs/view/tools/searchsubview.hpp b/apps/opencs/view/tools/searchsubview.hpp new file mode 100644 index 000000000..abedd5e6d --- /dev/null +++ b/apps/opencs/view/tools/searchsubview.hpp @@ -0,0 +1,34 @@ +#ifndef CSV_TOOLS_SEARCHSUBVIEW_H +#define CSV_TOOLS_SEARCHSUBVIEW_H + +#include "../doc/subview.hpp" + +class QTableView; +class QModelIndex; + +namespace CSMDoc +{ + class Document; +} + +namespace CSVTools +{ + class ReportTable; + + class SearchSubView : public CSVDoc::SubView + { + Q_OBJECT + + ReportTable *mTable; + + public: + + SearchSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document); + + virtual void setEditLock (bool locked); + + virtual void updateUserSetting (const QString &, const QStringList &); + }; +} + +#endif diff --git a/apps/opencs/view/tools/subviews.cpp b/apps/opencs/view/tools/subviews.cpp index a50b5724a..8a343ebe8 100644 --- a/apps/opencs/view/tools/subviews.cpp +++ b/apps/opencs/view/tools/subviews.cpp @@ -4,6 +4,7 @@ #include "../doc/subviewfactoryimp.hpp" #include "reportsubview.hpp" +#include "searchsubview.hpp" void CSVTools::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) { @@ -11,4 +12,6 @@ void CSVTools::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) new CSVDoc::SubViewFactory); manager.add (CSMWorld::UniversalId::Type_LoadErrorLog, new CSVDoc::SubViewFactory); + manager.add (CSMWorld::UniversalId::Type_Search, + new CSVDoc::SubViewFactory); } From 31a0bbcb23101bbf3b916bc1f5100e6c4f31bf65 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 17 Mar 2015 18:53:56 +0100 Subject: [PATCH 0767/3725] Seems to fix wireframe crashes --- apps/nifosgtest/test.cpp | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/apps/nifosgtest/test.cpp b/apps/nifosgtest/test.cpp index 668bda373..16d1d58a3 100644 --- a/apps/nifosgtest/test.cpp +++ b/apps/nifosgtest/test.cpp @@ -17,9 +17,8 @@ class WireframeKeyHandler : public osgGA::GUIEventHandler { public: - WireframeKeyHandler(osg::Node* node) + WireframeKeyHandler() : mWireframe(false) - , mNode(node) { } @@ -32,12 +31,7 @@ public: if (adapter.getKey() == osgGA::GUIEventAdapter::KEY_W) { mWireframe = !mWireframe; - osg::PolygonMode* mode = new osg::PolygonMode; - mode->setMode(osg::PolygonMode::FRONT_AND_BACK, - mWireframe ? osg::PolygonMode::LINE : osg::PolygonMode::FILL); - mNode->getOrCreateStateSet()->setAttributeAndModes(mode, osg::StateAttribute::ON); - mNode->getOrCreateStateSet()->setMode(GL_CULL_FACE, mWireframe ? osg::StateAttribute::OFF - : osg::StateAttribute::ON); + // applying state from an event handler doesn't appear to be safe, so do it in the frame update return true; } default: @@ -46,9 +40,13 @@ public: return false; } + bool getWireframe() const + { + return mWireframe; + } + private: bool mWireframe; - osg::Node* mNode; }; int main(int argc, char** argv) @@ -93,11 +91,28 @@ int main(int argc, char** argv) viewer.setUpViewInWindow(0, 0, 800, 600); viewer.realize(); viewer.setCameraManipulator(new osgGA::TrackballManipulator()); - viewer.addEventHandler(new WireframeKeyHandler(root)); + + WireframeKeyHandler* keyHandler = new WireframeKeyHandler; + + viewer.addEventHandler(keyHandler); viewer.addEventHandler(new osgViewer::StatsHandler); + bool wireframe = false; + while (!viewer.done()) { + + if (wireframe != keyHandler->getWireframe()) + { + wireframe = keyHandler->getWireframe(); + osg::PolygonMode* mode = new osg::PolygonMode; + mode->setMode(osg::PolygonMode::FRONT_AND_BACK, + wireframe ? osg::PolygonMode::LINE : osg::PolygonMode::FILL); + root->getOrCreateStateSet()->setAttributeAndModes(mode, osg::StateAttribute::ON); + root->getOrCreateStateSet()->setMode(GL_CULL_FACE, wireframe ? osg::StateAttribute::OFF + : osg::StateAttribute::ON); + } + viewer.frame(); for (unsigned int i=0; i Date: Tue, 17 Mar 2015 21:59:39 +0100 Subject: [PATCH 0768/3725] Add virtual file system (VFS) replacing the low level parts of the old resource system --- apps/nifosgtest/test.cpp | 12 +++-- components/CMakeLists.txt | 4 ++ components/bsa/bsa_file.cpp | 5 ++ components/bsa/bsa_file.hpp | 2 + components/nifosg/nifloader.cpp | 4 +- components/nifosg/nifloader.hpp | 9 ++-- components/vfs/archive.hpp | 30 +++++++++++ components/vfs/bsaarchive.cpp | 43 ++++++++++++++++ components/vfs/bsaarchive.hpp | 32 ++++++++++++ components/vfs/filesystemarchive.cpp | 65 ++++++++++++++++++++++++ components/vfs/filesystemarchive.hpp | 40 +++++++++++++++ components/vfs/manager.cpp | 76 ++++++++++++++++++++++++++++ components/vfs/manager.hpp | 52 +++++++++++++++++++ 13 files changed, 362 insertions(+), 12 deletions(-) create mode 100644 components/vfs/archive.hpp create mode 100644 components/vfs/bsaarchive.cpp create mode 100644 components/vfs/bsaarchive.hpp create mode 100644 components/vfs/filesystemarchive.cpp create mode 100644 components/vfs/filesystemarchive.hpp create mode 100644 components/vfs/manager.cpp create mode 100644 components/vfs/manager.hpp diff --git a/apps/nifosgtest/test.cpp b/apps/nifosgtest/test.cpp index 16d1d58a3..ef2ddd6b4 100644 --- a/apps/nifosgtest/test.cpp +++ b/apps/nifosgtest/test.cpp @@ -6,6 +6,9 @@ #include +#include +#include + #include #include @@ -57,10 +60,11 @@ int main(int argc, char** argv) return 1; } - Bsa::BSAFile bsa; - bsa.open(argv[1]); + VFS::Manager resourceMgr (false); + resourceMgr.addArchive(new VFS::BsaArchive(argv[1])); + resourceMgr.buildIndex(); - Nif::NIFFilePtr nif(new Nif::NIFFile(bsa.getFile(argv[2]), std::string(argv[2]))); + Nif::NIFFilePtr nif(new Nif::NIFFile(resourceMgr.get(argv[2]), std::string(argv[2]))); osgViewer::Viewer viewer; @@ -75,7 +79,7 @@ int main(int argc, char** argv) std::vector controllers; osg::Group* newNode = new osg::Group; NifOsg::Loader loader; - loader.resourceManager = &bsa; + loader.resourceManager = &resourceMgr; loader.loadAsSkeleton(nif, newNode); for (unsigned int i=0; ioffset, file->fileSize); +} diff --git a/components/bsa/bsa_file.hpp b/components/bsa/bsa_file.hpp index 3024cb610..8a7576f92 100644 --- a/components/bsa/bsa_file.hpp +++ b/components/bsa/bsa_file.hpp @@ -120,6 +120,8 @@ public: */ Files::IStreamPtr getFile(const char *file); + Files::IStreamPtr getFile(const FileStruct* file); + /// Get a list of all files const FileList &getList() const { return files; } diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index feffe2cba..88c944e14 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -465,7 +465,7 @@ namespace NifOsg osgDB::Options* opts = new osgDB::Options; opts->setOptionString("dds_dxt1_detect_rgba"); osgDB::ReaderWriter* reader = osgDB::Registry::instance()->getReaderWriterForExtension("dds"); - osgDB::ReaderWriter::ReadResult result = reader->readImage(*resourceManager->getFile(filename.c_str()), opts); + osgDB::ReaderWriter::ReadResult result = reader->readImage(*resourceManager->get(filename.c_str()), opts); textures.push_back(osg::ref_ptr(result.getImage())); } boost::shared_ptr dest(new FlipControllerValue(stateset, flipctrl, textures)); @@ -843,7 +843,7 @@ namespace NifOsg osgDB::Options* opts = new osgDB::Options; opts->setOptionString("dds_dxt1_detect_rgba"); osgDB::ReaderWriter* reader = osgDB::Registry::instance()->getReaderWriterForExtension("dds"); - osgDB::ReaderWriter::ReadResult result = reader->readImage(*resourceManager->getFile(filename.c_str()), opts); + osgDB::ReaderWriter::ReadResult result = reader->readImage(*resourceManager->get(filename.c_str()), opts); osg::Image* image = result.getImage(); osg::Texture2D* texture2d = new osg::Texture2D; texture2d->setImage(image); diff --git a/components/nifosg/nifloader.hpp b/components/nifosg/nifloader.hpp index 0535aa838..e52101525 100644 --- a/components/nifosg/nifloader.hpp +++ b/components/nifosg/nifloader.hpp @@ -5,6 +5,8 @@ #include // NIFFilePtr +#include + #include #include "controller.hpp" @@ -24,10 +26,6 @@ namespace Nif class NiTriShape; class Property; } -namespace Bsa -{ - class BSAFile; -} namespace NifOsg { @@ -41,8 +39,7 @@ namespace NifOsg void loadAsSkeleton(Nif::NIFFilePtr file, osg::Group* parentNode); - // FIXME replace with resource system - Bsa::BSAFile* resourceManager; + VFS::Manager* resourceManager; // FIXME move std::vector mControllers; diff --git a/components/vfs/archive.hpp b/components/vfs/archive.hpp new file mode 100644 index 000000000..b36c7117b --- /dev/null +++ b/components/vfs/archive.hpp @@ -0,0 +1,30 @@ +#ifndef OPENMW_COMPONENTS_RESOURCE_ARCHIVE_H +#define OPENMW_COMPONENTS_RESOURCE_ARCHIVE_H + +#include + +#include + +namespace VFS +{ + + class File + { + public: + virtual ~File() {} + + virtual Files::IStreamPtr open() = 0; + }; + + class Archive + { + public: + virtual ~Archive() {} + + /// List all resources contained in this archive, and run the resource names through the given normalize function. + virtual void listResources(std::map& out, char (*normalize_function) (char)) = 0; + }; + +} + +#endif diff --git a/components/vfs/bsaarchive.cpp b/components/vfs/bsaarchive.cpp new file mode 100644 index 000000000..a527a6ad9 --- /dev/null +++ b/components/vfs/bsaarchive.cpp @@ -0,0 +1,43 @@ +#include "bsaarchive.hpp" + +namespace VFS +{ + + +BsaArchive::BsaArchive(const std::string &filename) +{ + mFile.open(filename); + + const Bsa::BSAFile::FileList &filelist = mFile.getList(); + for(Bsa::BSAFile::FileList::const_iterator it = filelist.begin();it != filelist.end();++it) + { + mResources.push_back(BsaArchiveFile(&*it, &mFile)); + } +} + +void BsaArchive::listResources(std::map &out, char (*normalize_function)(char)) +{ + for (std::vector::iterator it = mResources.begin(); it != mResources.end(); ++it) + { + std::string ent = it->mInfo->name; + std::transform(ent.begin(), ent.end(), ent.begin(), normalize_function); + + out[ent] = &*it; + } +} + +// ------------------------------------------------------------------------------ + +BsaArchiveFile::BsaArchiveFile(const Bsa::BSAFile::FileStruct *info, Bsa::BSAFile* bsa) + : mInfo(info) + , mFile(bsa) +{ + +} + +Files::IStreamPtr BsaArchiveFile::open() +{ + return mFile->getFile(mInfo); +} + +} diff --git a/components/vfs/bsaarchive.hpp b/components/vfs/bsaarchive.hpp new file mode 100644 index 000000000..961746947 --- /dev/null +++ b/components/vfs/bsaarchive.hpp @@ -0,0 +1,32 @@ +#include "archive.hpp" + +#include + +namespace VFS +{ + + class BsaArchiveFile : public File + { + public: + BsaArchiveFile(const Bsa::BSAFile::FileStruct* info, Bsa::BSAFile* bsa); + + virtual Files::IStreamPtr open(); + + const Bsa::BSAFile::FileStruct* mInfo; + Bsa::BSAFile* mFile; + }; + + class BsaArchive : public Archive + { + public: + BsaArchive(const std::string& filename); + + virtual void listResources(std::map& out, char (*normalize_function) (char)); + + private: + Bsa::BSAFile mFile; + + std::vector mResources; + }; + +} diff --git a/components/vfs/filesystemarchive.cpp b/components/vfs/filesystemarchive.cpp new file mode 100644 index 000000000..ad5150a44 --- /dev/null +++ b/components/vfs/filesystemarchive.cpp @@ -0,0 +1,65 @@ +#include "filesystemarchive.hpp" + +#include + +namespace VFS +{ + + FileSystemArchive::FileSystemArchive(const std::string &path) + : mBuiltIndex(false) + , mPath(path) + { + + } + + void FileSystemArchive::listResources(std::map &out, char (*normalize_function)(char)) + { + if (!mBuiltIndex) + { + typedef boost::filesystem::recursive_directory_iterator directory_iterator; + + directory_iterator end; + + size_t prefix = mPath.size (); + + if (mPath.size () > 0 && mPath [prefix - 1] != '\\' && mPath [prefix - 1] != '/') + ++prefix; + + for (directory_iterator i (mPath); i != end; ++i) + { + if(boost::filesystem::is_directory (*i)) + continue; + + std::string proper = i->path ().string (); + + FileSystemArchiveFile file(proper); + + std::string searchable; + + std::transform(proper.begin() + prefix, proper.end(), std::back_inserter(searchable), normalize_function); + + mIndex.insert (std::make_pair (searchable, file)); + } + + mBuiltIndex = true; + } + + for (index::iterator it = mIndex.begin(); it != mIndex.end(); ++it) + { + out[it->first] = &it->second; + } + } + + // ---------------------------------------------------------------------------------- + + FileSystemArchiveFile::FileSystemArchiveFile(const std::string &path) + : mPath(path) + { + } + + Files::IStreamPtr FileSystemArchiveFile::open() + { + return Files::openConstrainedFileStream(mPath.c_str()); + } + +} diff --git a/components/vfs/filesystemarchive.hpp b/components/vfs/filesystemarchive.hpp new file mode 100644 index 000000000..6c8e1b82b --- /dev/null +++ b/components/vfs/filesystemarchive.hpp @@ -0,0 +1,40 @@ +#ifndef OPENMW_COMPONENTS_RESOURCE_FILESYSTEMARCHIVE_H +#define OPENMW_COMPONENTS_RESOURCE_FILESYSTEMARCHIVE_H + +#include "archive.hpp" + +namespace VFS +{ + + class FileSystemArchiveFile : public File + { + public: + FileSystemArchiveFile(const std::string& path); + + virtual Files::IStreamPtr open(); + + private: + std::string mPath; + + }; + + class FileSystemArchive : public Archive + { + public: + FileSystemArchive(const std::string& path); + + virtual void listResources(std::map& out, char (*normalize_function) (char)); + + + private: + typedef std::map index; + index mIndex; + + bool mBuiltIndex; + std::string mPath; + + }; + +} + +#endif diff --git a/components/vfs/manager.cpp b/components/vfs/manager.cpp new file mode 100644 index 000000000..82f4cd7be --- /dev/null +++ b/components/vfs/manager.cpp @@ -0,0 +1,76 @@ +#include "manager.hpp" + +#include + +#include "archive.hpp" + +namespace +{ + + char strict_normalize_char(char ch) + { + return ch == '\\' ? '/' : ch; + } + + char nonstrict_normalize_char(char ch) + { + return ch == '\\' ? '/' : std::tolower(ch,std::locale::classic()); + } + + void normalize_path(std::string& path, bool strict) + { + char (*normalize_char)(char) = strict ? &strict_normalize_char : &nonstrict_normalize_char; + std::transform(path.begin(), path.end(), path.begin(), normalize_char); + } + +} + +namespace VFS +{ + + Manager::Manager(bool strict) + : mStrict(strict) + { + + } + + Manager::~Manager() + { + for (std::vector::iterator it = mArchives.begin(); it != mArchives.end(); ++it) + delete *it; + mArchives.clear(); + } + + void Manager::addArchive(Archive *archive) + { + mArchives.push_back(archive); + } + + void Manager::buildIndex() + { + mIndex.clear(); + + for (std::vector::const_iterator it = mArchives.begin(); it != mArchives.end(); ++it) + (*it)->listResources(mIndex, mStrict ? &strict_normalize_char : &nonstrict_normalize_char); + } + + Files::IStreamPtr Manager::get(const std::string &name) const + { + std::string normalized = name; + normalize_path(normalized, mStrict); + + std::map::const_iterator found = mIndex.find(normalized); + if (found == mIndex.end()) + throw std::runtime_error("Resource '" + name + "' not found"); + return found->second->open(); + } + + bool Manager::exists(const std::string &name) const + { + std::string normalized = name; + normalize_path(normalized, mStrict); + + return mIndex.find(normalized) != mIndex.end(); + } + +} diff --git a/components/vfs/manager.hpp b/components/vfs/manager.hpp new file mode 100644 index 000000000..31538cc99 --- /dev/null +++ b/components/vfs/manager.hpp @@ -0,0 +1,52 @@ +#ifndef OPENMW_COMPONENTS_RESOURCEMANAGER_H +#define OPENMW_COMPONENTS_RESOURCEMANAGER_H + +#include + +#include +#include + +namespace VFS +{ + + class Archive; + class File; + + /// @brief The main class responsible for loading files from a virtual file system. + /// @par Various archive types (e.g. directories on the filesystem, or compressed archives) + /// can be registered, and will be merged into a single file tree. If the same filename is + /// contained in multiple archives, the last added archive will have priority. + class Manager + { + public: + /// @param strict Use strict path handling? If enabled, no case folding will + /// be done, but slash/backslash conversions are always done. + Manager(bool strict); + + ~Manager(); + + /// Register the given archive. All files contained in it will be added to the index on the next buildIndex() call. + /// @note Takes ownership of the given pointer. + void addArchive(Archive* archive); + + /// Build the file index. Should be called when all archives have been registered. + void buildIndex(); + + /// Does a file with this name exist? + bool exists(const std::string& name) const; + + /// Retrieve a file by name. + /// @note Throws an exception if the file can not be found. + Files::IStreamPtr get(const std::string& name) const; + + private: + bool mStrict; + + std::vector mArchives; + + std::map mIndex; + }; + +} + +#endif From f843e1253880d551e84504f1c6a184dd1e950815 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 17 Mar 2015 22:34:30 +0100 Subject: [PATCH 0769/3725] Add world space particle systems, will need more changes when emitters are added --- apps/nifosgtest/test.cpp | 1 - components/nifosg/nifloader.cpp | 47 ++++++++++++++++++++++++++++++--- 2 files changed, 43 insertions(+), 5 deletions(-) diff --git a/apps/nifosgtest/test.cpp b/apps/nifosgtest/test.cpp index ef2ddd6b4..05ed2408e 100644 --- a/apps/nifosgtest/test.cpp +++ b/apps/nifosgtest/test.cpp @@ -11,7 +11,6 @@ #include -#include #include #include diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 88c944e14..a1fcbcbc9 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -192,11 +192,37 @@ namespace } }; + // Node callback used to set the inverse of the parent's world matrix on the MatrixTransform + // that the callback is attached to. Used for certain particle systems, + // so that the particles do not move with the node they are attached to. + class InverseWorldMatrix : public osg::NodeCallback + { + public: + InverseWorldMatrix() + { + } + + void operator()(osg::Node* node, osg::NodeVisitor* nv) + { + if (nv && nv->getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR) + { + osg::NodePath path = nv->getNodePath(); + path.pop_back(); + + osg::MatrixTransform* trans = dynamic_cast(node); + + osg::Matrix worldMat = osg::computeLocalToWorld( path ); + trans->setMatrix(osg::Matrix::inverse(worldMat)); + } + traverse(node,nv); + } + }; + osg::ref_ptr handleMorphGeometry(const Nif::NiGeomMorpherController* morpher) { osg::ref_ptr morphGeom = new osgAnimation::MorphGeometry; morphGeom->setMethod(osgAnimation::MorphGeometry::RELATIVE); - // NIF format doesn't specify morphed normals + // No normals available in the MorphData morphGeom->setMorphNormals(false); const std::vector& morphs = morpher->data.getPtr()->mMorphs; @@ -499,6 +525,10 @@ namespace NifOsg if (!partctrl) return; + osg::Matrix particletransform; + if (!(particleflags & Nif::NiNode::ParticleFlag_LocalSpace)) + particletransform = getWorldTransform(nifNode); + int i=0; for (std::vector::const_iterator it = partctrl->particles.begin(); iactiveCount && it != partctrl->particles.end(); ++it, ++i) @@ -509,8 +539,8 @@ namespace NifOsg osgParticle::Particle* created = partsys->createParticle(&particletemplate); created->setLifeTime(500);//std::max(0.f, particle.lifespan)); - created->setVelocity(particle.velocity); - created->setPosition(particledata->vertices.at(particle.vertex)); + created->setVelocity(particle.velocity * particletransform); + created->setPosition(particledata->vertices.at(particle.vertex) * particletransform); osg::Vec4f partcolor (1.f,1.f,1.f,1.f); if (particle.vertex < int(particledata->colors.size())) @@ -534,7 +564,16 @@ namespace NifOsg partsys->getOrCreateStateSet()->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); osg::ref_ptr geode (new osg::Geode); geode->addDrawable(partsys); - parentNode->addChild(geode); + + if (particleflags & Nif::NiNode::ParticleFlag_LocalSpace) + parentNode->addChild(geode); + else + { + osg::MatrixTransform* trans = new osg::MatrixTransform; + trans->setUpdateCallback(new InverseWorldMatrix); + trans->addChild(geode); + parentNode->addChild(trans); + } osgParticle::ParticleSystemUpdater* updater = new osgParticle::ParticleSystemUpdater; updater->addParticleSystem(partsys); From 7c1386b62b5ca7c1aad362b98f8ff865f11007db Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 18 Mar 2015 20:12:44 +0100 Subject: [PATCH 0770/3725] Read BSA and data dirs from openmw.cfg --- apps/nifosgtest/test.cpp | 44 +++++++++++++++++++++++++++++++++++----- 1 file changed, 39 insertions(+), 5 deletions(-) diff --git a/apps/nifosgtest/test.cpp b/apps/nifosgtest/test.cpp index 05ed2408e..7f9649e2e 100644 --- a/apps/nifosgtest/test.cpp +++ b/apps/nifosgtest/test.cpp @@ -8,6 +8,9 @@ #include #include +#include + +#include #include @@ -53,17 +56,48 @@ private: int main(int argc, char** argv) { - if (argc < 3) + if (argc < 2) { - std::cout << "Usage: " << argv[0] << " " << std::endl; + std::cout << "Usage: " << argv[0] << " " << std::endl; return 1; } - VFS::Manager resourceMgr (false); - resourceMgr.addArchive(new VFS::BsaArchive(argv[1])); + Files::ConfigurationManager cfgMgr; + boost::program_options::options_description desc(""); + desc.add_options() + ("data", boost::program_options::value()->default_value(Files::PathContainer(), "data")->multitoken()->composing()) + ("fs-strict", boost::program_options::value()->implicit_value(true)->default_value(false)) + ("fallback-archive", boost::program_options::value >()-> + default_value(std::vector(), "fallback-archive")->multitoken()); + + boost::program_options::variables_map variables; + cfgMgr.readConfiguration(variables, desc); + + std::vector archives = variables["fallback-archive"].as >(); + bool fsStrict = variables["fs-strict"].as(); + Files::PathContainer dataDirs; + if (!variables["data"].empty()) { + dataDirs = Files::PathContainer(variables["data"].as()); + } + + cfgMgr.processPaths(dataDirs); + + VFS::Manager resourceMgr (fsStrict); + Files::Collections collections (dataDirs, !fsStrict); + + for (std::vector::const_iterator it = archives.begin(); it != archives.end(); ++it) + { + std::string filepath = collections.getPath(*it).string(); + resourceMgr.addArchive(new VFS::BsaArchive(filepath)); + } + for (Files::PathContainer::const_iterator it = dataDirs.begin(); it != dataDirs.end(); ++it) + { + resourceMgr.addArchive(new VFS::FileSystemArchive(it->string())); + } + resourceMgr.buildIndex(); - Nif::NIFFilePtr nif(new Nif::NIFFile(resourceMgr.get(argv[2]), std::string(argv[2]))); + Nif::NIFFilePtr nif(new Nif::NIFFile(resourceMgr.get(argv[1]), std::string(argv[1]))); osgViewer::Viewer viewer; From 3e45e9a48a196d3199d54a949c663b2349b6e58c Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Wed, 18 Mar 2015 23:37:54 +0200 Subject: [PATCH 0771/3725] Remove no longer required strnlen wrapper It was used for MinGW & OS X < 10.7. Minimal OS X version was bumped to 10.7 and MinGW support was recently dropped (see 1eaa64c49caeb753facf36c5173d5236c1f969e0). --- components/esm/esmcommon.hpp | 2 +- components/esm/esmreader.hpp | 2 +- libs/platform/string.h | 34 ---------------------------------- 3 files changed, 2 insertions(+), 36 deletions(-) delete mode 100644 libs/platform/string.h diff --git a/components/esm/esmcommon.hpp b/components/esm/esmcommon.hpp index 54b18aeaf..d90a3444d 100644 --- a/components/esm/esmcommon.hpp +++ b/components/esm/esmcommon.hpp @@ -5,7 +5,7 @@ #include #include -#include +#include namespace ESM { diff --git a/components/esm/esmreader.hpp b/components/esm/esmreader.hpp index ebbc935f6..2df2a86b3 100644 --- a/components/esm/esmreader.hpp +++ b/components/esm/esmreader.hpp @@ -2,7 +2,7 @@ #define OPENMW_ESM_READER_H #include -#include +#include #include #include #include diff --git a/libs/platform/string.h b/libs/platform/string.h deleted file mode 100644 index 5368d757c..000000000 --- a/libs/platform/string.h +++ /dev/null @@ -1,34 +0,0 @@ -// Wrapper for string.h on Mac and MinGW -#ifndef _STRING_WRAPPER_H -#define _STRING_WRAPPER_H - -#ifdef __APPLE__ -#include -#endif - -#include -#if (defined(__APPLE__) && __MAC_OS_X_VERSION_MIN_REQUIRED < 1070) || defined(__MINGW32__) -// need our own implementation of strnlen -#ifdef __MINGW32__ -static size_t strnlen(const char *s, size_t n) -{ - const char *p = (const char *)memchr(s, 0, n); - return(p ? p-s : n); -} -#elif (defined(__APPLE__) && __MAC_OS_X_VERSION_MIN_REQUIRED < 1070) -static size_t mw_strnlen(const char *s, size_t n) -{ - if (strnlen != NULL) { - return strnlen(s, n); - } - else { - const char *p = (const char *)memchr(s, 0, n); - return(p ? p-s : n); - } -} -#define strnlen mw_strnlen -#endif - -#endif - -#endif From af2b08214bacc528b66fa6047ef941a7f7208668 Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Wed, 18 Mar 2015 23:48:03 +0200 Subject: [PATCH 0772/3725] #2460: use Application Support as user data path on OS X --- components/files/macospath.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/components/files/macospath.cpp b/components/files/macospath.cpp index 3e53f5306..6e794796f 100644 --- a/components/files/macospath.cpp +++ b/components/files/macospath.cpp @@ -7,10 +7,6 @@ #include #include -/** - * FIXME: Someone with MacOS system should check this and correct if necessary - */ - namespace { boost::filesystem::path getUserHome() @@ -49,9 +45,8 @@ boost::filesystem::path MacOsPath::getUserConfigPath() const boost::filesystem::path MacOsPath::getUserDataPath() const { - // TODO: probably wrong? boost::filesystem::path userPath (getUserHome()); - userPath /= "Library/Preferences/"; + userPath /= "Library/Application Support/"; return userPath / mName; } From 0b4e7e59bc57978598df8e71d5b9f43a10a3fc6b Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 19 Mar 2015 00:35:05 +0100 Subject: [PATCH 0773/3725] Revert "Seems to fix wireframe crashes" This reverts commit 31a0bbcb23101bbf3b916bc1f5100e6c4f31bf65. Better fix coming up --- apps/nifosgtest/test.cpp | 35 ++++++++++------------------------- 1 file changed, 10 insertions(+), 25 deletions(-) diff --git a/apps/nifosgtest/test.cpp b/apps/nifosgtest/test.cpp index 7f9649e2e..4593217c8 100644 --- a/apps/nifosgtest/test.cpp +++ b/apps/nifosgtest/test.cpp @@ -22,8 +22,9 @@ class WireframeKeyHandler : public osgGA::GUIEventHandler { public: - WireframeKeyHandler() + WireframeKeyHandler(osg::Node* node) : mWireframe(false) + , mNode(node) { } @@ -36,7 +37,12 @@ public: if (adapter.getKey() == osgGA::GUIEventAdapter::KEY_W) { mWireframe = !mWireframe; - // applying state from an event handler doesn't appear to be safe, so do it in the frame update + osg::PolygonMode* mode = new osg::PolygonMode; + mode->setMode(osg::PolygonMode::FRONT_AND_BACK, + mWireframe ? osg::PolygonMode::LINE : osg::PolygonMode::FILL); + mNode->getOrCreateStateSet()->setAttributeAndModes(mode, osg::StateAttribute::ON); + mNode->getOrCreateStateSet()->setMode(GL_CULL_FACE, mWireframe ? osg::StateAttribute::OFF + : osg::StateAttribute::ON); return true; } default: @@ -45,13 +51,9 @@ public: return false; } - bool getWireframe() const - { - return mWireframe; - } - private: bool mWireframe; + osg::Node* mNode; }; int main(int argc, char** argv) @@ -128,28 +130,11 @@ int main(int argc, char** argv) viewer.setUpViewInWindow(0, 0, 800, 600); viewer.realize(); viewer.setCameraManipulator(new osgGA::TrackballManipulator()); - - WireframeKeyHandler* keyHandler = new WireframeKeyHandler; - - viewer.addEventHandler(keyHandler); + viewer.addEventHandler(new WireframeKeyHandler(root)); viewer.addEventHandler(new osgViewer::StatsHandler); - bool wireframe = false; - while (!viewer.done()) { - - if (wireframe != keyHandler->getWireframe()) - { - wireframe = keyHandler->getWireframe(); - osg::PolygonMode* mode = new osg::PolygonMode; - mode->setMode(osg::PolygonMode::FRONT_AND_BACK, - wireframe ? osg::PolygonMode::LINE : osg::PolygonMode::FILL); - root->getOrCreateStateSet()->setAttributeAndModes(mode, osg::StateAttribute::ON); - root->getOrCreateStateSet()->setMode(GL_CULL_FACE, wireframe ? osg::StateAttribute::OFF - : osg::StateAttribute::ON); - } - viewer.frame(); for (unsigned int i=0; i Date: Thu, 19 Mar 2015 00:37:33 +0100 Subject: [PATCH 0774/3725] Better fix for wireframe crashes --- apps/nifosgtest/test.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/nifosgtest/test.cpp b/apps/nifosgtest/test.cpp index 4593217c8..1c34afbc4 100644 --- a/apps/nifosgtest/test.cpp +++ b/apps/nifosgtest/test.cpp @@ -131,6 +131,11 @@ int main(int argc, char** argv) viewer.realize(); viewer.setCameraManipulator(new osgGA::TrackballManipulator()); viewer.addEventHandler(new WireframeKeyHandler(root)); + + // We're going to change this from the event callback, set the variance to DYNAMIC so that + // we don't interfere with the draw thread. + root->getOrCreateStateSet()->setDataVariance(osg::Node::DYNAMIC); + viewer.addEventHandler(new osgViewer::StatsHandler); while (!viewer.done()) From 79c2138e53a6f62739db0260358f189bee45e130 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 19 Mar 2015 01:45:01 +0100 Subject: [PATCH 0775/3725] Port ResourceHelpers to new VFS --- components/esmterrain/storage.cpp | 3 ++- components/misc/resourcehelpers.cpp | 42 +++++++++++++++-------------- components/misc/resourcehelpers.hpp | 17 +++++++----- components/nifosg/nifloader.cpp | 21 +++------------ 4 files changed, 38 insertions(+), 45 deletions(-) diff --git a/components/esmterrain/storage.cpp b/components/esmterrain/storage.cpp index d4a0a0df2..84a7ef568 100644 --- a/components/esmterrain/storage.cpp +++ b/components/esmterrain/storage.cpp @@ -282,7 +282,8 @@ namespace ESMTerrain const ESM::LandTexture* ltex = getLandTexture(id.first-1, id.second); //TODO this is needed due to MWs messed up texture handling - std::string texture = Misc::ResourceHelpers::correctTexturePath(ltex->mTexture); + assert(0 && "no vfs here yet"); + std::string texture = ltex->mTexture; //Misc::ResourceHelpers::correctTexturePath(ltex->mTexture); return texture; } diff --git a/components/misc/resourcehelpers.cpp b/components/misc/resourcehelpers.cpp index dc08b352a..0c2635752 100644 --- a/components/misc/resourcehelpers.cpp +++ b/components/misc/resourcehelpers.cpp @@ -1,8 +1,10 @@ #include "resourcehelpers.hpp" +#include + #include -#include +#include namespace { @@ -29,8 +31,8 @@ namespace bool Misc::ResourceHelpers::changeExtensionToDds(std::string &path) { - Ogre::String::size_type pos = path.rfind('.'); - if(pos != Ogre::String::npos && path.compare(pos, path.length() - pos, ".dds") != 0) + std::string::size_type pos = path.rfind('.'); + if(pos != std::string::npos && path.compare(pos, path.length() - pos, ".dds") != 0) { path.replace(pos, path.length(), ".dds"); return true; @@ -38,7 +40,7 @@ bool Misc::ResourceHelpers::changeExtensionToDds(std::string &path) return false; } -std::string Misc::ResourceHelpers::correctResourcePath(const std::string &topLevelDirectory, const std::string &resPath) +std::string Misc::ResourceHelpers::correctResourcePath(const std::string &topLevelDirectory, const std::string &resPath, const VFS::Manager* vfs) { /* Bethesda at some point converted all their BSA * textures from tga to dds for increased load speed, but all @@ -64,65 +66,65 @@ std::string Misc::ResourceHelpers::correctResourcePath(const std::string &topLev // since we know all (GOTY edition or less) textures end // in .dds, we change the extension bool changedToDds = changeExtensionToDds(correctedPath); - if (Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(correctedPath)) + if (vfs->exists(correctedPath)) return correctedPath; // if it turns out that the above wasn't true in all cases (not for vanilla, but maybe mods) // verify, and revert if false (this call succeeds quickly, but fails slowly) - if (changedToDds && Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(origExt)) + if (changedToDds && vfs->exists(origExt)) return origExt; // fall back to a resource in the top level directory if it exists std::string fallback = topLevelDirectory + "\\" + getBasename(correctedPath); - if (Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(fallback)) + if (vfs->exists(fallback)) return fallback; if (changedToDds) { fallback = topLevelDirectory + "\\" + getBasename(origExt); - if (Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(fallback)) + if (vfs->exists(fallback)) return fallback; } return correctedPath; } -std::string Misc::ResourceHelpers::correctTexturePath(const std::string &resPath) +std::string Misc::ResourceHelpers::correctTexturePath(const std::string &resPath, const VFS::Manager* vfs) { static const std::string dir = "textures"; - return correctResourcePath(dir, resPath); + return correctResourcePath(dir, resPath, vfs); } -std::string Misc::ResourceHelpers::correctIconPath(const std::string &resPath) +std::string Misc::ResourceHelpers::correctIconPath(const std::string &resPath, const VFS::Manager* vfs) { static const std::string dir = "icons"; - return correctResourcePath(dir, resPath); + return correctResourcePath(dir, resPath, vfs); } -std::string Misc::ResourceHelpers::correctBookartPath(const std::string &resPath) +std::string Misc::ResourceHelpers::correctBookartPath(const std::string &resPath, const VFS::Manager* vfs) { static const std::string dir = "bookart"; - std::string image = correctResourcePath(dir, resPath); + std::string image = correctResourcePath(dir, resPath, vfs); return image; } -std::string Misc::ResourceHelpers::correctBookartPath(const std::string &resPath, int width, int height) +std::string Misc::ResourceHelpers::correctBookartPath(const std::string &resPath, int width, int height, const VFS::Manager* vfs) { - std::string image = correctBookartPath(resPath); + std::string image = correctBookartPath(resPath, vfs); // Apparently a bug with some morrowind versions, they reference the image without the size suffix. // So if the image isn't found, try appending the size. - if (!Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(image)) + if (!vfs->exists(image)) { std::stringstream str; str << image.substr(0, image.rfind('.')) << "_" << width << "_" << height << image.substr(image.rfind('.')); - image = Misc::ResourceHelpers::correctBookartPath(str.str()); + image = Misc::ResourceHelpers::correctBookartPath(str.str(), vfs); } return image; } -std::string Misc::ResourceHelpers::correctActorModelPath(const std::string &resPath) +std::string Misc::ResourceHelpers::correctActorModelPath(const std::string &resPath, const VFS::Manager* vfs) { std::string mdlname = resPath; std::string::size_type p = mdlname.rfind('\\'); @@ -132,7 +134,7 @@ std::string Misc::ResourceHelpers::correctActorModelPath(const std::string &resP mdlname.insert(mdlname.begin()+p+1, 'x'); else mdlname.insert(mdlname.begin(), 'x'); - if(!Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(mdlname)) + if(!vfs->exists(mdlname)) { return resPath; } diff --git a/components/misc/resourcehelpers.hpp b/components/misc/resourcehelpers.hpp index 2ce3dce1e..1763f7777 100644 --- a/components/misc/resourcehelpers.hpp +++ b/components/misc/resourcehelpers.hpp @@ -3,18 +3,23 @@ #include +namespace VFS +{ + class Manager; +} + namespace Misc { namespace ResourceHelpers { bool changeExtensionToDds(std::string &path); - std::string correctResourcePath(const std::string &topLevelDirectory, const std::string &resPath); - std::string correctTexturePath(const std::string &resPath); - std::string correctIconPath(const std::string &resPath); - std::string correctBookartPath(const std::string &resPath); - std::string correctBookartPath(const std::string &resPath, int width, int height); + std::string correctResourcePath(const std::string &topLevelDirectory, const std::string &resPath, const VFS::Manager* vfs); + std::string correctTexturePath(const std::string &resPath, const VFS::Manager* vfs); + std::string correctIconPath(const std::string &resPath, const VFS::Manager* vfs); + std::string correctBookartPath(const std::string &resPath, const VFS::Manager* vfs); + std::string correctBookartPath(const std::string &resPath, int width, int height, const VFS::Manager* vfs); /// Uses "xfoo.nif" instead of "foo.nif" if available - std::string correctActorModelPath(const std::string &resPath); + std::string correctActorModelPath(const std::string &resPath, const VFS::Manager* vfs); } } diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index a1fcbcbc9..1220bb258 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -11,6 +11,7 @@ #include #include #include +#include // skel #include @@ -477,15 +478,7 @@ namespace NifOsg if (st.empty()) continue; - // FIXME: replace by ResourceHelpers - std::string filename (st->filename); - Misc::StringUtils::toLower(filename); - filename = "textures\\" + filename; - size_t found = filename.find(".tga"); - if (found == std::string::npos) - found = filename.find(".bmp"); - if (found != std::string::npos) - filename.replace(found, 4, ".dds"); + std::string filename = Misc::ResourceHelpers::correctTexturePath(st->filename, resourceManager); // tx_creature_werewolf.dds isn't loading in the correct format without this option osgDB::Options* opts = new osgDB::Options; @@ -868,15 +861,7 @@ namespace NifOsg continue; } - // FIXME: replace by ResourceHelpers - std::string filename (st->filename); - Misc::StringUtils::toLower(filename); - filename = "textures\\" + filename; - size_t found = filename.find(".tga"); - if (found == std::string::npos) - found = filename.find(".bmp"); - if (found != std::string::npos) - filename.replace(found, 4, ".dds"); + std::string filename = Misc::ResourceHelpers::correctTexturePath(st->filename, resourceManager); // tx_creature_werewolf.dds isn't loading in the correct format without this option osgDB::Options* opts = new osgDB::Options; From f8422c3ed493ad42bf68f6f6493bbecf8e5cc3aa Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 19 Mar 2015 03:01:11 +0100 Subject: [PATCH 0776/3725] Particles mostly completed, still need to attach emitters to the correct node and handle NiBSPArrayController --- apps/nifosgtest/test.cpp | 9 +- components/CMakeLists.txt | 2 +- components/nif/nifkey.hpp | 2 + components/nifosg/controller.cpp | 13 +++ components/nifosg/controller.hpp | 18 +++ components/nifosg/nifloader.cpp | 164 ++++++++++++++++++-------- components/nifosg/nifloader.hpp | 2 +- components/nifosg/particle.cpp | 192 +++++++++++++++++++++++++++++++ components/nifosg/particle.hpp | 137 ++++++++++++++++++++++ 9 files changed, 488 insertions(+), 51 deletions(-) create mode 100644 components/nifosg/particle.cpp create mode 100644 components/nifosg/particle.hpp diff --git a/apps/nifosgtest/test.cpp b/apps/nifosgtest/test.cpp index 1c34afbc4..7f9a7ce3f 100644 --- a/apps/nifosgtest/test.cpp +++ b/apps/nifosgtest/test.cpp @@ -13,6 +13,7 @@ #include #include +#include #include @@ -120,9 +121,13 @@ int main(int argc, char** argv) for (unsigned int i=0; iaddChild(trans); + for (int x=0; x<1;++x) { - root->addChild(newNode); + //root->addChild(newNode); + trans->addChild(newNode); } viewer.setSceneData(root); @@ -140,6 +145,8 @@ int main(int argc, char** argv) while (!viewer.done()) { + //trans->setAttitude(osg::Quat(viewer.getFrameStamp()->getSimulationTime()*5, osg::Vec3f(0,0,1))); + viewer.frame(); for (unsigned int i=0; i #include +#include "niffile.hpp" + namespace Nif { diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index 041036e5b..f6841ee61 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -4,8 +4,11 @@ #include #include #include + #include +#include + #include #include @@ -331,5 +334,15 @@ void FlipControllerValue::setValue(float time) tex->setImage(mTextures[curTexture].get()); } +ParticleSystemControllerValue::ParticleSystemControllerValue(osgParticle::Emitter *emitter, const Nif::NiParticleSystemController *ctrl) + : mEmitter(emitter), mEmitStart(ctrl->startTime), mEmitStop(ctrl->stopTime) +{ +} + +void ParticleSystemControllerValue::setValue(float time) +{ + mEmitter->setEnabled(time >= mEmitStart && time < mEmitStop); +} + } diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index 421f00277..e82f49ec8 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -25,6 +25,11 @@ namespace osg class StateSet; } +namespace osgParticle +{ + class Emitter; +} + namespace osgAnimation { class MorphGeometry; @@ -236,6 +241,19 @@ namespace NifOsg virtual void setValue(float time); }; + class ParticleSystemControllerValue : public ControllerValue + { + public: + ParticleSystemControllerValue(osgParticle::Emitter* emitter, const Nif::NiParticleSystemController* ctrl); + + virtual void setValue(float time); + + private: + osgParticle::Emitter* mEmitter; + float mEmitStart; + float mEmitStop; + }; + } #endif diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 1220bb258..5cdaf13ce 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -22,6 +22,11 @@ // particle #include #include +#include +#include +#include +#include +#include #include #include @@ -36,6 +41,8 @@ #include +#include "particle.hpp" + namespace { osg::Matrixf toMatrix(const Nif::Transformation& nifTrafo) @@ -124,6 +131,14 @@ namespace class UpdateBone : public osg::NodeCallback { public: + UpdateBone() {} + UpdateBone(const UpdateBone& copy, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY) + : osg::Object(copy, copyop), osg::NodeCallback(copy, copyop) + { + } + + META_Object(NifOsg, UpdateBone) + // Callback method called by the NodeVisitor when visiting a node. void operator()(osg::Node* node, osg::NodeVisitor* nv) { @@ -157,6 +172,7 @@ namespace : mSkelRoot(skelRootNode) { } + // TODO: add copy constructor void operator()(osg::Node* node, osg::NodeVisitor* nv) { @@ -179,44 +195,9 @@ namespace traverse(node,nv); } private: - osg::Node* mSkelRoot; - }; - - // HACK: Particle doesn't allow setting the initial age, but we need this for loading the particle system state - class ParticleAgeSetter : public osgParticle::Particle - { - public: - ParticleAgeSetter(float age) - : Particle() - { - _t0 = age; - } - }; - - // Node callback used to set the inverse of the parent's world matrix on the MatrixTransform - // that the callback is attached to. Used for certain particle systems, - // so that the particles do not move with the node they are attached to. - class InverseWorldMatrix : public osg::NodeCallback - { - public: - InverseWorldMatrix() - { - } - - void operator()(osg::Node* node, osg::NodeVisitor* nv) - { - if (nv && nv->getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR) - { - osg::NodePath path = nv->getNodePath(); - path.pop_back(); - - osg::MatrixTransform* trans = dynamic_cast(node); - osg::Matrix worldMat = osg::computeLocalToWorld( path ); - trans->setMatrix(osg::Matrix::inverse(worldMat)); - } - traverse(node,nv); - } + // TODO: keeping this pointer will break when copying the scene graph; maybe retrieve it while visiting if it's NULL? + osg::Node* mSkelRoot; }; osg::ref_ptr handleMorphGeometry(const Nif::NiGeomMorpherController* morpher) @@ -338,6 +319,8 @@ namespace NifOsg if (nifNode->recType == Nif::RC_NiBSAnimationNode) animflags |= nifNode->flags; + if (nifNode->recType == Nif::RC_NiBSParticleNode) + particleflags |= nifNode->flags; // Hide collision shapes, but don't skip the subgraph // We still need to animate the hidden bones so the physics system can access them @@ -370,7 +353,7 @@ namespace NifOsg } if(nifNode->recType == Nif::RC_NiAutoNormalParticles || nifNode->recType == Nif::RC_NiRotatingParticles) - handleParticleSystem(nifNode, transformNode, particleflags, animflags); + handleParticleSystem(nifNode, transformNode, animflags, particleflags); if (!nifNode->controller.empty()) handleNodeControllers(nifNode, transformNode, animflags); @@ -495,9 +478,10 @@ namespace NifOsg } } - void Loader::handleParticleSystem(const Nif::Node *nifNode, osg::Group *parentNode, int particleflags, int animflags) + void Loader::handleParticleSystem(const Nif::Node *nifNode, osg::Group *parentNode, int animflags, int particleflags) { osg::ref_ptr partsys (new osgParticle::ParticleSystem); + partsys->setSortMode(osgParticle::ParticleSystem::SORT_BACK_TO_FRONT); const Nif::NiAutoNormalParticlesData *particledata = NULL; if(nifNode->recType == Nif::RC_NiAutoNormalParticles) @@ -507,6 +491,8 @@ namespace NifOsg else return; + // TODO: add special handling for NiBSPArrayController + const Nif::NiParticleSystemController* partctrl = NULL; for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next) { @@ -516,10 +502,18 @@ namespace NifOsg partctrl = static_cast(ctrl.getPtr()); } if (!partctrl) + { + std::cerr << "No particle controller found " << std::endl; return; + } + + osgParticle::ParticleProcessor::ReferenceFrame rf = (particleflags & Nif::NiNode::ParticleFlag_LocalSpace) + ? osgParticle::ParticleProcessor::RELATIVE_RF + : osgParticle::ParticleProcessor::ABSOLUTE_RF; + // TODO: also take into account the transform by placement in the scene osg::Matrix particletransform; - if (!(particleflags & Nif::NiNode::ParticleFlag_LocalSpace)) + if (rf == osgParticle::ParticleProcessor::ABSOLUTE_RF) particletransform = getWorldTransform(nifNode); int i=0; @@ -528,11 +522,12 @@ namespace NifOsg { const Nif::NiParticleSystemController::Particle& particle = *it; - ParticleAgeSetter particletemplate(std::max(0.f, particle.lifespan - particle.lifetime)); + ParticleAgeSetter particletemplate(std::max(0.f, particle.lifetime)); osgParticle::Particle* created = partsys->createParticle(&particletemplate); - created->setLifeTime(500);//std::max(0.f, particle.lifespan)); - created->setVelocity(particle.velocity * particletransform); + created->setLifeTime(std::max(0.f, particle.lifespan)); + osg::Vec4f adjustedVelocity = osg::Vec4f(particle.velocity, 0.f) * particletransform; + created->setVelocity(osg::Vec3f(adjustedVelocity.x(), adjustedVelocity.y(), adjustedVelocity.z())); created->setPosition(particledata->vertices.at(particle.vertex) * particletransform); osg::Vec4f partcolor (1.f,1.f,1.f,1.f); @@ -544,10 +539,81 @@ namespace NifOsg created->setSizeRange(osgParticle::rangef(size, size)); } - osg::NodeVisitor visitor; - partsys->update(0.f, visitor); - partsys->setFrozen(true); - partsys->setSortMode(osgParticle::ParticleSystem::SORT_BACK_TO_FRONT); + partsys->getDefaultParticleTemplate().setSizeRange(osgParticle::rangef(partctrl->size, partctrl->size)); + partsys->getDefaultParticleTemplate().setColorRange(osgParticle::rangev4(osg::Vec4f(1.f,1.f,1.f,1.f), osg::Vec4f(1.f,1.f,1.f,1.f))); + partsys->getDefaultParticleTemplate().setAlphaRange(osgParticle::rangef(1.f, 1.f)); + + // ---- emitter + + osgParticle::ModularEmitter* emitter = new osgParticle::ModularEmitter; + emitter->setParticleSystem(partsys); + emitter->setReferenceFrame(osgParticle::ParticleProcessor::RELATIVE_RF); + + osgParticle::ConstantRateCounter* counter = new osgParticle::ConstantRateCounter; + if (partctrl->emitFlags & Nif::NiParticleSystemController::NoAutoAdjust) + counter->setNumberOfParticlesPerSecondToCreate(partctrl->emitRate); + else + counter->setNumberOfParticlesPerSecondToCreate(partctrl->numParticles / (partctrl->lifetime + partctrl->lifetimeRandom/2)); + + emitter->setCounter(counter); + + ParticleShooter* shooter = new ParticleShooter(partctrl->velocity - partctrl->velocityRandom*0.5f, + partctrl->velocity + partctrl->velocityRandom*0.5f, + partctrl->horizontalDir, partctrl->horizontalAngle, + partctrl->verticalDir, partctrl->verticalAngle, + partctrl->lifetime, partctrl->lifetimeRandom); + emitter->setShooter(shooter); + + osgParticle::BoxPlacer* placer = new osgParticle::BoxPlacer; + placer->setXRange(-partctrl->offsetRandom.x(), partctrl->offsetRandom.x()); + placer->setYRange(-partctrl->offsetRandom.y(), partctrl->offsetRandom.y()); + placer->setZRange(-partctrl->offsetRandom.z(), partctrl->offsetRandom.z()); + + emitter->setPlacer(placer); + + // TODO: attach to the emitter node + // Note: we also assume that the Emitter node is placed *before* the Particle node in the scene graph. + // This seems to be true for all NIF files in the game that I've checked, suggesting that NIFs work similar to OSG with regards to update order. + // If something ever violates this assumption, the worst that could happen is the culling being one frame late, which wouldn't be a disaster. + parentNode->addChild(emitter); + + createController(partctrl, boost::shared_ptr(new ParticleSystemControllerValue(emitter, partctrl)), animflags); + + // ----------- affector (must be after emitters in the scene graph) + osgParticle::ModularProgram* program = new osgParticle::ModularProgram; + program->setParticleSystem(partsys); + program->setReferenceFrame(rf); + parentNode->addChild(program); + for (Nif::ExtraPtr e = partctrl->extra; !e.empty(); e = e->extra) + { + if (e->recType == Nif::RC_NiParticleGrowFade) + { + const Nif::NiParticleGrowFade *gf = static_cast(e.getPtr()); + GrowFadeAffector* affector = new GrowFadeAffector(gf->growTime, gf->fadeTime); + program->addOperator(affector); + } + else if (e->recType == Nif::RC_NiGravity) + { + const Nif::NiGravity* gr = static_cast(e.getPtr()); + GravityAffector* affector = new GravityAffector(gr); + program->addOperator(affector); + } + else if (e->recType == Nif::RC_NiParticleColorModifier) + { + const Nif::NiParticleColorModifier *cl = static_cast(e.getPtr()); + const Nif::NiColorData *clrdata = cl->data.getPtr(); + ParticleColorAffector* affector = new ParticleColorAffector(clrdata); + program->addOperator(affector); + } + else if (e->recType == Nif::RC_NiParticleRotation) + { + // TODO: Implement? + } + else + std::cerr << "Unhandled particle modifier " << e->recName << std::endl; + } + + // ----------- std::vector materialProps; collectMaterialProperties(nifNode, materialProps); @@ -558,7 +624,7 @@ namespace NifOsg osg::ref_ptr geode (new osg::Geode); geode->addDrawable(partsys); - if (particleflags & Nif::NiNode::ParticleFlag_LocalSpace) + if (rf == osgParticle::ParticleProcessor::RELATIVE_RF) parentNode->addChild(geode); else { @@ -568,6 +634,7 @@ namespace NifOsg parentNode->addChild(trans); } + // particle system updater (after the emitters and affectors in the scene graph) osgParticle::ParticleSystemUpdater* updater = new osgParticle::ParticleSystemUpdater; updater->addParticleSystem(partsys); parentNode->addChild(updater); @@ -870,6 +937,7 @@ namespace NifOsg osgDB::ReaderWriter::ReadResult result = reader->readImage(*resourceManager->get(filename.c_str()), opts); osg::Image* image = result.getImage(); osg::Texture2D* texture2d = new osg::Texture2D; + texture2d->setUnRefImageDataAfterApply(true); texture2d->setImage(image); unsigned int clamp = static_cast(tex.clamp); diff --git a/components/nifosg/nifloader.hpp b/components/nifosg/nifloader.hpp index e52101525..5a0c901c1 100644 --- a/components/nifosg/nifloader.hpp +++ b/components/nifosg/nifloader.hpp @@ -61,7 +61,7 @@ namespace NifOsg void handleProperty (const Nif::Property* property, const Nif::Node* nifNode, osg::Node* node, std::map& boundTextures, int animflags); - void handleParticleSystem(const Nif::Node* nifNode, osg::Group* parentNode, int particleflags, int animflags); + void handleParticleSystem(const Nif::Node* nifNode, osg::Group* parentNode, int animflags, int particleflags); // Creates an osg::Geometry object for the given TriShape, populates it, and attaches it to the given node. void handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, const std::map& boundTextures, int animflags); diff --git a/components/nifosg/particle.cpp b/components/nifosg/particle.cpp new file mode 100644 index 000000000..3fcc02bcf --- /dev/null +++ b/components/nifosg/particle.cpp @@ -0,0 +1,192 @@ +#include "particle.hpp" + +#include + +#include + +#include + +namespace NifOsg +{ + +void InverseWorldMatrix::operator()(osg::Node *node, osg::NodeVisitor *nv) +{ + if (nv && nv->getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR) + { + osg::NodePath path = nv->getNodePath(); + path.pop_back(); + + osg::MatrixTransform* trans = dynamic_cast(node); + + osg::Matrix worldMat = osg::computeLocalToWorld( path ); + trans->setMatrix(osg::Matrix::inverse(worldMat)); + } + traverse(node,nv); +} + +ParticleShooter::ParticleShooter(float minSpeed, float maxSpeed, float horizontalDir, float horizontalAngle, float verticalDir, float verticalAngle, float lifetime, float lifetimeRandom) + : mMinSpeed(minSpeed), mMaxSpeed(maxSpeed), mHorizontalDir(horizontalDir) + , mHorizontalAngle(horizontalAngle), mVerticalDir(verticalDir), mVerticalAngle(verticalAngle) + , mLifetime(lifetime), mLifetimeRandom(lifetimeRandom) +{ +} + +ParticleShooter::ParticleShooter() + : mMinSpeed(0.f), mMaxSpeed(0.f), mHorizontalDir(0.f) + , mHorizontalAngle(0.f), mVerticalDir(0.f), mVerticalAngle(0.f) + , mLifetime(0.f), mLifetimeRandom(0.f) +{ +} + +ParticleShooter::ParticleShooter(const osgParticle::Shooter ©, const osg::CopyOp ©op) +{ + *this = copy; +} + +void ParticleShooter::shoot(osgParticle::Particle *particle) const +{ + // NOTE: We do not use mDirection/mAngle for the initial direction. + float hdir = mHorizontalDir + mHorizontalAngle * (2.f * (std::rand() / static_cast(RAND_MAX)) - 1.f); + float vdir = mVerticalDir + mVerticalAngle * (2.f * (std::rand() / static_cast(RAND_MAX)) - 1.f); + osg::Vec3f dir = osg::Quat(hdir, osg::Vec3f(0,0,1)) * osg::Quat(vdir, osg::Vec3f(1,0,0)) + // ^ Vec3f(0,1,0) according to nifskope, TODO: test in mw + * osg::Vec3f(0,0,1); + + float vel = mMinSpeed + (mMaxSpeed - mMinSpeed) * std::rand() / static_cast(RAND_MAX); + particle->setVelocity(dir * vel); + + // Not supposed to set this here, but there doesn't seem to be a better way of doing it + particle->setLifeTime(mLifetime + mLifetimeRandom * std::rand() / static_cast(RAND_MAX)); +} + +GrowFadeAffector::GrowFadeAffector(float growTime, float fadeTime) + : mGrowTime(growTime) + , mFadeTime(fadeTime) + , mCachedDefaultSize(0.f) +{ +} + +GrowFadeAffector::GrowFadeAffector() + : mGrowTime(0.f) + , mFadeTime(0.f) + , mCachedDefaultSize(0.f) +{ + +} + +GrowFadeAffector::GrowFadeAffector(const GrowFadeAffector& copy, const osg::CopyOp& copyop) + : osgParticle::Operator(copy, copyop) +{ + *this = copy; +} + +void GrowFadeAffector::beginOperate(osgParticle::Program *program) +{ + mCachedDefaultSize = program->getParticleSystem()->getDefaultParticleTemplate().getSizeRange().minimum; +} + +void GrowFadeAffector::operate(osgParticle::Particle* particle, double /* dt */) +{ + float size = mCachedDefaultSize; + if (particle->getAge() < mGrowTime && mGrowTime != 0.f) + size *= particle->getAge() / mGrowTime; + if (particle->getLifeTime() - particle->getAge() < mFadeTime && mFadeTime != 0.f) + size *= (particle->getLifeTime() - particle->getAge()) / mFadeTime; + particle->setSizeRange(osgParticle::rangef(size, size)); +} + +ParticleColorAffector::ParticleColorAffector(const Nif::NiColorData *clrdata) + : mData(*clrdata) +{ +} + +ParticleColorAffector::ParticleColorAffector() +{ + +} + +ParticleColorAffector::ParticleColorAffector(const ParticleColorAffector ©, const osg::CopyOp ©op) + : osgParticle::Operator(copy, copyop) +{ + *this = copy; +} + +osg::Vec4f ParticleColorAffector::interpolate(const float time, const Nif::Vector4KeyMap::MapType &keys) +{ + if(time <= keys.begin()->first) + return keys.begin()->second.mValue; + + Nif::Vector4KeyMap::MapType::const_iterator it = keys.lower_bound(time); + if (it != keys.end()) + { + float aTime = it->first; + const Nif::KeyT* aKey = &it->second; + + assert (it != keys.begin()); // Shouldn't happen, was checked at beginning of this function + + Nif::Vector4KeyMap::MapType::const_iterator last = --it; + float aLastTime = last->first; + const Nif::KeyT* aLastKey = &last->second; + + float a = (time - aLastTime) / (aTime - aLastTime); + return aLastKey->mValue + ((aKey->mValue - aLastKey->mValue) * a); + } + else + return keys.rbegin()->second.mValue; +} + +void ParticleColorAffector::operate(osgParticle::Particle* particle, double /* dt */) +{ + float time = static_cast(particle->getAge()/particle->getLifeTime()); + osg::Vec4f color = interpolate(time, mData.mKeyMap.mKeys); + + particle->setColorRange(osgParticle::rangev4(color, color)); +} + +GravityAffector::GravityAffector(const Nif::NiGravity *gravity) + : mForce(gravity->mForce) + , mType(static_cast(gravity->mType)) + , mPosition(gravity->mPosition) + , mDirection(gravity->mDirection) +{ +} + +GravityAffector::GravityAffector() + : mForce(0), mType(Type_Wind) +{ + +} + +GravityAffector::GravityAffector(const GravityAffector ©, const osg::CopyOp ©op) + : osgParticle::Operator(copy, copyop) +{ + *this = copy; +} + +void GravityAffector::beginOperate(osgParticle::Program* program) +{ + bool absolute = (program->getReferenceFrame() == osgParticle::ParticleProcessor::ABSOLUTE_RF); + if (mType == Type_Wind) + mCachedWorldPositionDirection = absolute ? program->rotateLocalToWorld(mDirection) : mDirection; + else // Type_Point + mCachedWorldPositionDirection = absolute ? program->transformLocalToWorld(mPosition) : mPosition; +} + +void GravityAffector::operate(osgParticle::Particle *particle, double dt) +{ + switch (mType) + { + case Type_Wind: + particle->addVelocity(mCachedWorldPositionDirection * mForce * dt); + break; + case Type_Point: + { + osg::Vec3f diff = mCachedWorldPositionDirection - particle->getPosition(); + diff.normalize(); + particle->addVelocity(diff * mForce * dt); + break; + } + } +} + +} diff --git a/components/nifosg/particle.hpp b/components/nifosg/particle.hpp new file mode 100644 index 000000000..0336d3392 --- /dev/null +++ b/components/nifosg/particle.hpp @@ -0,0 +1,137 @@ +#ifndef OPENMW_COMPONENTS_NIFOSG_PARTICLE_H +#define OPENMW_COMPONENTS_NIFOSG_PARTICLE_H + +#include +#include +#include + +#include + +#include +#include + +namespace Nif +{ + class NiGravity; +} + +namespace NifOsg +{ + + // HACK: Particle doesn't allow setting the initial age, but we need this for loading the particle system state + class ParticleAgeSetter : public osgParticle::Particle + { + public: + ParticleAgeSetter(float age) + : Particle() + { + _t0 = age; + } + }; + + // Node callback used to set the inverse of the parent's world matrix on the MatrixTransform + // that the callback is attached to. Used for certain particle systems, + // so that the particles do not move with the node they are attached to. + class InverseWorldMatrix : public osg::NodeCallback + { + public: + InverseWorldMatrix() + { + } + InverseWorldMatrix(const InverseWorldMatrix& copy, const osg::CopyOp& op = osg::CopyOp::SHALLOW_COPY) + : osg::NodeCallback(), osg::Object() + { + } + + META_Object(NifOsg, InverseWorldMatrix) + + void operator()(osg::Node* node, osg::NodeVisitor* nv); + }; + + class ParticleShooter : public osgParticle::Shooter + { + public: + ParticleShooter(float minSpeed, float maxSpeed, float horizontalDir, float horizontalAngle, float verticalDir, float verticalAngle, + float lifetime, float lifetimeRandom); + ParticleShooter(); + ParticleShooter(const Shooter& copy, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY); + + META_Object(NifOsg, ParticleShooter) + + virtual void shoot(osgParticle::Particle* particle) const; + + private: + float mMinSpeed; + float mMaxSpeed; + float mHorizontalDir; + float mHorizontalAngle; + float mVerticalDir; + float mVerticalAngle; + float mLifetime; + float mLifetimeRandom; + }; + + class GrowFadeAffector : public osgParticle::Operator + { + public: + GrowFadeAffector(float growTime, float fadeTime); + GrowFadeAffector(); + GrowFadeAffector(const GrowFadeAffector& copy, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY); + + META_Object(NifOsg, GrowFadeAffector) + + virtual void beginOperate(osgParticle::Program* program); + virtual void operate(osgParticle::Particle* particle, double dt); + + private: + float mGrowTime; + float mFadeTime; + + float mCachedDefaultSize; + }; + + class ParticleColorAffector : public osgParticle::Operator + { + public: + ParticleColorAffector(const Nif::NiColorData* clrdata); + ParticleColorAffector(); + ParticleColorAffector(const ParticleColorAffector& copy, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY); + + META_Object(NifOsg, ParticleColorAffector) + + // TODO: very similar to vec3 version, refactor to a template + osg::Vec4f interpolate(const float time, const Nif::Vector4KeyMap::MapType& keys); + + virtual void operate(osgParticle::Particle* particle, double dt); + + private: + Nif::NiColorData mData; + }; + + class GravityAffector : public osgParticle::Operator + { + public: + GravityAffector(const Nif::NiGravity* gravity); + GravityAffector(); + GravityAffector(const GravityAffector& copy, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY); + + META_Object(NifOsg, GravityAffector) + + virtual void operate(osgParticle::Particle* particle, double dt); + virtual void beginOperate(osgParticle::Program *); + + private: + float mForce; + enum ForceType { + Type_Wind, + Type_Point + }; + ForceType mType; + osg::Vec3f mPosition; + osg::Vec3f mDirection; + osg::Vec3f mCachedWorldPositionDirection; + }; + +} + +#endif From 7bc0d41bb060f59e5356244119ca2f32406dbf9d Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 19 Mar 2015 15:51:45 +0100 Subject: [PATCH 0777/3725] Marker collision fix (Fixes #2461) --- components/nifbullet/bulletnifloader.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/nifbullet/bulletnifloader.cpp b/components/nifbullet/bulletnifloader.cpp index cdc06f985..93c9797b2 100644 --- a/components/nifbullet/bulletnifloader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -274,9 +274,9 @@ void ManualBulletShapeLoader::handleNode(const Nif::Node *node, int flags, // No collision. Use an internal flag setting to mark this. flags |= 0x800; } - else if (sd->string == "MRK" && !mShowMarkers && raycasting) + else if (sd->string == "MRK" && !mShowMarkers && (raycasting || mShape->mAutogenerated)) { - // Marker objects should be invisible, but still have collision. + // Marker objects should be invisible, but can still have collision if the model explicitely specifies it via a RootCollisionNode. // Except in the editor, the marker objects are visible. return; } From 00ab47418865d5aba482af96f291ae77dc29b161 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 19 Mar 2015 16:22:01 +0100 Subject: [PATCH 0778/3725] More work on copy constructors --- components/nifosg/controller.hpp | 2 ++ components/nifosg/nifloader.cpp | 32 ++++++++++++++++---------------- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index e82f49ec8..cc176e76e 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -111,6 +111,8 @@ namespace NifOsg class NodeTargetValue : public ControllerValue { protected: + // TODO: get rid of target pointers, which are incompatible with a copy constructor we will need later + // instead, controllers can be a Node added as child of their target osg::Node *mNode; public: diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 5cdaf13ce..a92baee79 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -168,11 +168,12 @@ namespace class InvertBoneMatrix : public osg::NodeCallback { public: - InvertBoneMatrix(osg::Node* skelRootNode) - : mSkelRoot(skelRootNode) - { - } - // TODO: add copy constructor + InvertBoneMatrix() {} + + InvertBoneMatrix(const InvertBoneMatrix& copy, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY) + : osg::Object(copy, copyop), osg::NodeCallback(copy, copyop) {} + + META_Object(NifOsg, InvertBoneMatrix) void operator()(osg::Node* node, osg::NodeVisitor* nv) { @@ -183,21 +184,20 @@ namespace osg::MatrixTransform* trans = dynamic_cast(node); - osg::NodePath::iterator found = std::find(path.begin(), path.end(), mSkelRoot); - if (found != path.end()) + for (osg::NodePath::iterator it = path.begin(); it != path.end(); ++it) { - path.erase(path.begin(),found+1); - - osg::Matrix worldMat = osg::computeLocalToWorld( path ); - trans->setMatrix(osg::Matrix::inverse(worldMat)); + if (dynamic_cast(*it)) + { + path.erase(path.begin(), it+1); + // the bone's transform in skeleton space + osg::Matrix boneMat = osg::computeLocalToWorld( path ); + trans->setMatrix(osg::Matrix::inverse(boneMat)); + break; + } } } traverse(node,nv); } - private: - - // TODO: keeping this pointer will break when copying the scene graph; maybe retrieve it while visiting if it's NULL? - osg::Node* mSkelRoot; }; osg::ref_ptr handleMorphGeometry(const Nif::NiGeomMorpherController* morpher) @@ -793,7 +793,7 @@ namespace NifOsg rig->setInfluenceMap(map); osg::ref_ptr trans(new osg::MatrixTransform); - trans->setUpdateCallback(new InvertBoneMatrix(mSkeleton)); + trans->setUpdateCallback(new InvertBoneMatrix()); osg::ref_ptr geode (new osg::Geode); geode->addDrawable(rig); From ab3c28eb96e0cc6b11562641792a9eda8c960757 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 19 Mar 2015 17:00:16 +0100 Subject: [PATCH 0779/3725] Use template function for interpolation --- components/nifosg/controller.cpp | 51 -------------------------------- components/nifosg/controller.hpp | 28 ++++++++++++++++-- components/nifosg/particle.cpp | 31 ++----------------- components/nifosg/particle.hpp | 4 ++- 4 files changed, 32 insertions(+), 82 deletions(-) diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index f6841ee61..bbb2f57fe 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -16,57 +16,6 @@ namespace NifOsg { -float ValueInterpolator::interpKey(const Nif::FloatKeyMap::MapType &keys, float time, float def) const -{ - if (keys.size() == 0) - return def; - - if(time <= keys.begin()->first) - return keys.begin()->second.mValue; - - Nif::FloatKeyMap::MapType::const_iterator it = keys.lower_bound(time); - if (it != keys.end()) - { - float aTime = it->first; - const Nif::FloatKey* aKey = &it->second; - - assert (it != keys.begin()); // Shouldn't happen, was checked at beginning of this function - - Nif::FloatKeyMap::MapType::const_iterator last = --it; - float aLastTime = last->first; - const Nif::FloatKey* aLastKey = &last->second; - - float a = (time - aLastTime) / (aTime - aLastTime); - return aLastKey->mValue + ((aKey->mValue - aLastKey->mValue) * a); - } - else - return keys.rbegin()->second.mValue; -} - -osg::Vec3f ValueInterpolator::interpKey(const Nif::Vector3KeyMap::MapType &keys, float time) const -{ - if(time <= keys.begin()->first) - return keys.begin()->second.mValue; - - Nif::Vector3KeyMap::MapType::const_iterator it = keys.lower_bound(time); - if (it != keys.end()) - { - float aTime = it->first; - const Nif::KeyT* aKey = &it->second; - - assert (it != keys.begin()); // Shouldn't happen, was checked at beginning of this function - - Nif::Vector3KeyMap::MapType::const_iterator last = --it; - float aLastTime = last->first; - const Nif::KeyT* aLastKey = &last->second; - - float a = (time - aLastTime) / (aTime - aLastTime); - return aLastKey->mValue + ((aKey->mValue - aLastKey->mValue) * a); - } - else - return keys.rbegin()->second.mValue; -} - ControllerFunction::ControllerFunction(const Nif::Controller *ctrl, bool deltaInput) : mDeltaInput(deltaInput) , mFrequency(ctrl->frequency) diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index cc176e76e..c92a77816 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -42,9 +42,33 @@ namespace NifOsg class ValueInterpolator { protected: - float interpKey(const Nif::FloatKeyMap::MapType &keys, float time, float def=0.f) const; + template + T interpKey (const std::map< float, Nif::KeyT >& keys, float time, T defaultValue = T()) const + { + if (keys.size() == 0) + return defaultValue; + + if(time <= keys.begin()->first) + return keys.begin()->second.mValue; + + typename std::map< float, Nif::KeyT >::const_iterator it = keys.lower_bound(time); + if (it != keys.end()) + { + float aTime = it->first; + const Nif::KeyT* aKey = &it->second; - osg::Vec3f interpKey(const Nif::Vector3KeyMap::MapType &keys, float time) const; + assert (it != keys.begin()); // Shouldn't happen, was checked at beginning of this function + + typename std::map< float, Nif::KeyT >::const_iterator last = --it; + float aLastTime = last->first; + const Nif::KeyT* aLastKey = &last->second; + + float a = (time - aLastTime) / (aTime - aLastTime); + return aLastKey->mValue + ((aKey->mValue - aLastKey->mValue) * a); + } + else + return keys.rbegin()->second.mValue; + } }; // FIXME: Should not be here. We might also want to use this for non-NIF model formats diff --git a/components/nifosg/particle.cpp b/components/nifosg/particle.cpp index 3fcc02bcf..58501763b 100644 --- a/components/nifosg/particle.cpp +++ b/components/nifosg/particle.cpp @@ -45,11 +45,10 @@ ParticleShooter::ParticleShooter(const osgParticle::Shooter ©, const osg::Co void ParticleShooter::shoot(osgParticle::Particle *particle) const { - // NOTE: We do not use mDirection/mAngle for the initial direction. float hdir = mHorizontalDir + mHorizontalAngle * (2.f * (std::rand() / static_cast(RAND_MAX)) - 1.f); float vdir = mVerticalDir + mVerticalAngle * (2.f * (std::rand() / static_cast(RAND_MAX)) - 1.f); - osg::Vec3f dir = osg::Quat(hdir, osg::Vec3f(0,0,1)) * osg::Quat(vdir, osg::Vec3f(1,0,0)) - // ^ Vec3f(0,1,0) according to nifskope, TODO: test in mw + float vdir2 = mVerticalDir + mVerticalAngle * (2.f * (std::rand() / static_cast(RAND_MAX)) - 1.f); + osg::Vec3f dir = osg::Quat(hdir, osg::Vec3f(0,0,1)) * osg::Quat(vdir, osg::Vec3f(0,1,0)) * osg::Quat(vdir2, osg::Vec3f(1,0,0)) * osg::Vec3f(0,0,1); float vel = mMinSpeed + (mMaxSpeed - mMinSpeed) * std::rand() / static_cast(RAND_MAX); @@ -111,34 +110,10 @@ ParticleColorAffector::ParticleColorAffector(const ParticleColorAffector ©, *this = copy; } -osg::Vec4f ParticleColorAffector::interpolate(const float time, const Nif::Vector4KeyMap::MapType &keys) -{ - if(time <= keys.begin()->first) - return keys.begin()->second.mValue; - - Nif::Vector4KeyMap::MapType::const_iterator it = keys.lower_bound(time); - if (it != keys.end()) - { - float aTime = it->first; - const Nif::KeyT* aKey = &it->second; - - assert (it != keys.begin()); // Shouldn't happen, was checked at beginning of this function - - Nif::Vector4KeyMap::MapType::const_iterator last = --it; - float aLastTime = last->first; - const Nif::KeyT* aLastKey = &last->second; - - float a = (time - aLastTime) / (aTime - aLastTime); - return aLastKey->mValue + ((aKey->mValue - aLastKey->mValue) * a); - } - else - return keys.rbegin()->second.mValue; -} - void ParticleColorAffector::operate(osgParticle::Particle* particle, double /* dt */) { float time = static_cast(particle->getAge()/particle->getLifeTime()); - osg::Vec4f color = interpolate(time, mData.mKeyMap.mKeys); + osg::Vec4f color = interpKey(mData.mKeyMap.mKeys, time, osg::Vec4f(1,1,1,1)); particle->setColorRange(osgParticle::rangev4(color, color)); } diff --git a/components/nifosg/particle.hpp b/components/nifosg/particle.hpp index 0336d3392..13010fbac 100644 --- a/components/nifosg/particle.hpp +++ b/components/nifosg/particle.hpp @@ -10,6 +10,8 @@ #include #include +#include "controller.hpp" // ValueInterpolator + namespace Nif { class NiGravity; @@ -90,7 +92,7 @@ namespace NifOsg float mCachedDefaultSize; }; - class ParticleColorAffector : public osgParticle::Operator + class ParticleColorAffector : public osgParticle::Operator, public ValueInterpolator { public: ParticleColorAffector(const Nif::NiColorData* clrdata); From 49c2da27b386a9f4cecfe36cff5039f3be17a227 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 19 Mar 2015 17:21:15 +0100 Subject: [PATCH 0780/3725] OpenCS compiles and runs again (no rendering) --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/editor.cpp | 122 +----------------- apps/opencs/editor.hpp | 17 +-- apps/opencs/main.cpp | 12 +- apps/opencs/model/settings/usersettings.cpp | 4 +- apps/opencs/model/world/resources.cpp | 4 +- apps/opencs/view/render/object.cpp | 4 +- apps/opencs/view/render/overlaymask.cpp | 52 -------- apps/opencs/view/render/overlaymask.hpp | 42 ------ apps/opencs/view/render/overlaysystem.cpp | 34 ----- apps/opencs/view/render/overlaysystem.hpp | 26 ---- .../view/render/pagedworldspacewidget.cpp | 7 +- .../view/render/pagedworldspacewidget.hpp | 1 - apps/opencs/view/render/scenewidget.cpp | 8 -- apps/opencs/view/render/scenewidget.hpp | 2 - apps/opencs/view/world/physicssystem.cpp | 5 +- apps/opencs/view/world/subviews.cpp | 2 +- components/CMakeLists.txt | 3 +- libs/openengine/bullet/physic.cpp | 2 + 19 files changed, 30 insertions(+), 319 deletions(-) delete mode 100644 apps/opencs/view/render/overlaymask.cpp delete mode 100644 apps/opencs/view/render/overlaymask.hpp delete mode 100644 apps/opencs/view/render/overlaysystem.cpp delete mode 100644 apps/opencs/view/render/overlaysystem.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 1d6b40d5f..3548c175a 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -81,7 +81,7 @@ opencs_units (view/render opencs_units_noqt (view/render navigation navigation1st navigationfree navigationorbit lighting lightingday lightingnight - lightingbright object cell terrainstorage textoverlay overlaymask overlaysystem mousestate + lightingbright object cell terrainstorage textoverlay mousestate ) opencs_hdrs_noqt (view/render diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 1d31c8396..92fd40492 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -16,13 +16,12 @@ #include #include -#include #include "model/doc/document.hpp" #include "model/world/data.hpp" -CS::Editor::Editor (OgreInit::OgreInit& ogreInit) -: mUserSettings (mCfgMgr), mOverlaySystem (0), mDocumentManager (mCfgMgr), +CS::Editor::Editor () +: mUserSettings (mCfgMgr), mDocumentManager (mCfgMgr), mViewManager (mDocumentManager), mIpcServerName ("org.openmw.OpenCS"), mServer(NULL), mClientSocket(NULL), mPid(""), mLock() { @@ -33,14 +32,10 @@ CS::Editor::Editor (OgreInit::OgreInit& ogreInit) CSMSettings::UserSettings::instance().loadSettings ("opencs.ini"); mSettings.setModel (CSMSettings::UserSettings::instance()); - ogreInit.init ((mCfgMgr.getUserConfigPath() / "opencsOgre.log").string()); + //NifOgre::Loader::setShowMarkers(true); - NifOgre::Loader::setShowMarkers(true); - - mOverlaySystem.reset (new CSVRender::OverlaySystem); - - Bsa::registerResources (Files::Collections (config.first, !mFsStrict), config.second, true, - mFsStrict); + //Bsa::registerResources (Files::Collections (config.first, !mFsStrict), config.second, true, + // mFsStrict); mDocumentManager.listResources(); @@ -324,113 +319,10 @@ int CS::Editor::run() return QApplication::exec(); } -std::auto_ptr CS::Editor::setupGraphics() -{ - std::string renderer = -#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32 - "Direct3D9 Rendering Subsystem"; -#else - "OpenGL Rendering Subsystem"; -#endif - std::string renderSystem = mUserSettings.setting("Video/render system", renderer.c_str()).toStdString(); - - Ogre::Root::getSingleton().setRenderSystem(Ogre::Root::getSingleton().getRenderSystemByName(renderSystem)); - - // Initialise Ogre::OverlaySystem after Ogre::Root but before initialisation - mOverlaySystem.get(); - - Ogre::Root::getSingleton().initialise(false); - - // Create a hidden background window to keep resources - Ogre::NameValuePairList params; - params.insert(std::make_pair("title", "")); - - std::string antialiasing = mUserSettings.settingValue("Video/antialiasing").toStdString(); - if(antialiasing == "MSAA 16") antialiasing = "16"; - else if(antialiasing == "MSAA 8") antialiasing = "8"; - else if(antialiasing == "MSAA 4") antialiasing = "4"; - else if(antialiasing == "MSAA 2") antialiasing = "2"; - else antialiasing = "0"; - params.insert(std::make_pair("FSAA", antialiasing)); - - params.insert(std::make_pair("vsync", "false")); - params.insert(std::make_pair("hidden", "true")); -#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE - params.insert(std::make_pair("macAPI", "cocoa")); -#endif - // NOTE: fullscreen mode not supported (doesn't really make sense for opencs) - Ogre::RenderWindow* hiddenWindow = Ogre::Root::getSingleton().createRenderWindow("InactiveHidden", 1, 1, false, ¶ms); - hiddenWindow->setActive(false); - - sh::OgrePlatform* platform = - new sh::OgrePlatform ("General", (mResources / "materials").string()); - // for font used in overlays - Ogre::Root::getSingleton().addResourceLocation ((mResources / "mygui").string(), - "FileSystem", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, true); - - if (!boost::filesystem::exists (mCfgMgr.getCachePath())) - boost::filesystem::create_directories (mCfgMgr.getCachePath()); - - platform->setCacheFolder (mCfgMgr.getCachePath().string()); - - std::auto_ptr factory (new sh::Factory (platform)); + //Ogre::Root::getSingleton().addResourceLocation ((mResources / "mygui").string(), + // "FileSystem", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, true); - QString shLang = mUserSettings.settingValue("General/shader mode"); - QString rend = renderSystem.c_str(); - bool openGL = rend.contains(QRegExp("^OpenGL", Qt::CaseInsensitive)); - bool glES = rend.contains(QRegExp("^OpenGL ES", Qt::CaseInsensitive)); - - // force shader language based on render system - if(shLang == "" - || (openGL && shLang == "hlsl") - || (!openGL && shLang == "glsl") - || (glES && shLang != "glsles")) - { - shLang = openGL ? (glES ? "glsles" : "glsl") : "hlsl"; - //no group means "General" group in the "ini" file standard - mUserSettings.setDefinitions("shader mode", (QStringList() << shLang)); - } - enum sh::Language lang; - if(shLang == "glsl") lang = sh::Language_GLSL; - else if(shLang == "glsles") lang = sh::Language_GLSLES; - else if(shLang == "hlsl") lang = sh::Language_HLSL; - else lang = sh::Language_CG; - - factory->setCurrentLanguage (lang); - factory->setWriteSourceCache (true); - factory->setReadSourceCache (true); - factory->setReadMicrocodeCache (true); - factory->setWriteMicrocodeCache (true); - - factory->loadAllFiles(); - - bool shaders = mUserSettings.setting("3d-render/shaders", QString("true")) == "true" ? true : false; - sh::Factory::getInstance ().setShadersEnabled (shaders); - - std::string fog = mUserSettings.setting("Shader/fog", QString("true")).toStdString(); - sh::Factory::getInstance().setGlobalSetting ("fog", fog); - - - std::string shadows = mUserSettings.setting("Shader/shadows", QString("false")).toStdString(); - sh::Factory::getInstance().setGlobalSetting ("shadows", shadows); - - std::string shadows_pssm = mUserSettings.setting("Shader/shadows_pssm", QString("false")).toStdString(); - sh::Factory::getInstance().setGlobalSetting ("shadows_pssm", shadows_pssm); - - std::string render_refraction = mUserSettings.setting("Shader/render_refraction", QString("false")).toStdString(); - sh::Factory::getInstance ().setGlobalSetting ("render_refraction", render_refraction); - - // internal setting - may be switched on or off by the use of shader configurations - sh::Factory::getInstance ().setGlobalSetting ("viewproj_fix", "false"); - - std::string num_lights = mUserSettings.setting("3d-render-adv/num_lights", QString("8")).toStdString(); - sh::Factory::getInstance ().setGlobalSetting ("num_lights", num_lights); - - /// \todo add more configurable shiny settings - - return factory; -} void CS::Editor::documentAdded (CSMDoc::Document *document) { diff --git a/apps/opencs/editor.hpp b/apps/opencs/editor.hpp index 273f0825b..da4d63985 100644 --- a/apps/opencs/editor.hpp +++ b/apps/opencs/editor.hpp @@ -11,16 +11,12 @@ #include #include -#include - #ifndef Q_MOC_RUN #include #endif #include -#include - #include "model/settings/usersettings.hpp" #include "model/doc/documentmanager.hpp" @@ -30,12 +26,6 @@ #include "view/doc/newgame.hpp" #include "view/settings/dialog.hpp" -#include "view/render/overlaysystem.hpp" - -namespace OgreInit -{ - class OgreInit; -} namespace CS { @@ -43,10 +33,8 @@ namespace CS { Q_OBJECT - Nif::Cache mNifCache; Files::ConfigurationManager mCfgMgr; CSMSettings::UserSettings mUserSettings; - std::auto_ptr mOverlaySystem; CSMDoc::DocumentManager mDocumentManager; CSVDoc::ViewManager mViewManager; CSVDoc::StartupDialogue mStartup; @@ -71,7 +59,7 @@ namespace CS public: - Editor (OgreInit::OgreInit& ogreInit); + Editor (); ~Editor (); bool makeIPCServer(); @@ -80,9 +68,6 @@ namespace CS int run(); ///< \return error status - std::auto_ptr setupGraphics(); - ///< The returned factory must persist at least as long as *this. - private slots: void createGame(); diff --git a/apps/opencs/main.cpp b/apps/opencs/main.cpp index b11561c13..eb5dcc64e 100644 --- a/apps/opencs/main.cpp +++ b/apps/opencs/main.cpp @@ -9,10 +9,6 @@ #include #include -#include - -#include - #include "model/world/universalid.hpp" #ifdef Q_OS_MAC @@ -53,10 +49,6 @@ int main(int argc, char *argv[]) qRegisterMetaType ("std::string"); qRegisterMetaType ("CSMWorld::UniversalId"); - OgreInit::OgreInit ogreInit; - - std::auto_ptr shinyFactory; - Application application (argc, argv); #ifdef Q_OS_MAC @@ -80,15 +72,13 @@ int main(int argc, char *argv[]) application.setWindowIcon (QIcon (":./openmw-cs.png")); - CS::Editor editor (ogreInit); + CS::Editor editor; if(!editor.makeIPCServer()) { editor.connectToIPCServer(); return 0; } - - shinyFactory = editor.setupGraphics(); return editor.run(); } catch (std::exception& e) diff --git a/apps/opencs/model/settings/usersettings.cpp b/apps/opencs/model/settings/usersettings.cpp index 7dac660c3..0aa1cb4ad 100644 --- a/apps/opencs/model/settings/usersettings.cpp +++ b/apps/opencs/model/settings/usersettings.cpp @@ -472,11 +472,11 @@ void CSMSettings::UserSettings::updateUserSetting(const QString &settingKey, if(settingKey == "3d-render-adv/num_lights" && !list.empty()) { - sh::Factory::getInstance ().setGlobalSetting ("num_lights", list.at(0).toStdString()); + //sh::Factory::getInstance ().setGlobalSetting ("num_lights", list.at(0).toStdString()); } else if(settingKey == "3d-render/shaders" && !list.empty()) { - sh::Factory::getInstance ().setShadersEnabled (list.at(0).toStdString() == "true" ? true : false); + //sh::Factory::getInstance ().setShadersEnabled (list.at(0).toStdString() == "true" ? true : false); } emit userSettingUpdated (settingKey, list); diff --git a/apps/opencs/model/world/resources.cpp b/apps/opencs/model/world/resources.cpp index 13c8df84d..25fada93a 100644 --- a/apps/opencs/model/world/resources.cpp +++ b/apps/opencs/model/world/resources.cpp @@ -15,6 +15,7 @@ CSMWorld::Resources::Resources (const std::string& baseDirectory, UniversalId::T { int baseSize = mBaseDirectory.size(); + /* Ogre::StringVector resourcesGroups = Ogre::ResourceGroupManager::getSingleton().getResourceGroups(); @@ -61,6 +62,7 @@ CSMWorld::Resources::Resources (const std::string& baseDirectory, UniversalId::T Misc::StringUtils::lowerCase (file), static_cast (mFiles.size())-1)); } } + */ } int CSMWorld::Resources::getSize() const @@ -105,4 +107,4 @@ int CSMWorld::Resources::searchId (const std::string& id) const CSMWorld::UniversalId::Type CSMWorld::Resources::getType() const { return mType; -} \ No newline at end of file +} diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index 3607fb415..b54551c96 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -77,8 +77,8 @@ void CSVRender::Object::update() } else { - mObject = NifOgre::Loader::createObjects (mBase, "Meshes\\" + model); - mObject->setVisibilityFlags (Element_Reference); + //mObject = NifOgre::Loader::createObjects (mBase, "Meshes\\" + model); + //mObject->setVisibilityFlags (Element_Reference); if (mPhysics && !mReferenceId.empty()) { diff --git a/apps/opencs/view/render/overlaymask.cpp b/apps/opencs/view/render/overlaymask.cpp deleted file mode 100644 index 09f020354..000000000 --- a/apps/opencs/view/render/overlaymask.cpp +++ /dev/null @@ -1,52 +0,0 @@ -#include "overlaymask.hpp" - -#include -#include - -#include "textoverlay.hpp" -#include "../../model/world/cellcoordinates.hpp" - -namespace CSVRender -{ - -// ideas from http://www.ogre3d.org/forums/viewtopic.php?f=5&t=44828#p486334 -OverlayMask::OverlayMask(std::map &overlays, Ogre::Viewport* viewport) - : mTextOverlays(overlays), mViewport(viewport) -{ -} - -OverlayMask::~OverlayMask() -{ -} - -void OverlayMask::setViewport(Ogre::Viewport *viewport) -{ - mViewport = viewport; -} - -void OverlayMask::preViewportUpdate(const Ogre::RenderTargetViewportEvent &event) -{ - if(event.source == mViewport) - { - Ogre::OverlayManager &overlayMgr = Ogre::OverlayManager::getSingleton(); - for(Ogre::OverlayManager::OverlayMapIterator iter = overlayMgr.getOverlayIterator(); - iter.hasMoreElements();) - { - Ogre::Overlay* item = iter.getNext(); - for(Ogre::Overlay::Overlay2DElementsIterator it = item->get2DElementsIterator(); - it.hasMoreElements();) - { - Ogre::OverlayContainer* container = it.getNext(); - if(container) container->hide(); - } - } - - std::map::iterator it = mTextOverlays.begin(); - for(; it != mTextOverlays.end(); ++it) - { - it->second->show(true); - } - } -} - -} diff --git a/apps/opencs/view/render/overlaymask.hpp b/apps/opencs/view/render/overlaymask.hpp deleted file mode 100644 index ec050cac4..000000000 --- a/apps/opencs/view/render/overlaymask.hpp +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef OPENCS_VIEW_OVERLAYMASK_H -#define OPENCS_VIEW_OVERLAYMASK_H - -#include - -namespace Ogre -{ - class Viewport; - class RendertargetViewportEvent; -} - -namespace CSMWorld -{ - class CellCoordinates; -} - -namespace CSVRender -{ - class TextOverlay; - - class OverlayMask : public Ogre::RenderTargetListener - { - - std::map &mTextOverlays; - Ogre::Viewport* mViewport; - - public: - - OverlayMask(std::map &overlays, - Ogre::Viewport* viewport); - - virtual ~OverlayMask(); - - void setViewport(Ogre::Viewport *viewport); - - protected: - - virtual void preViewportUpdate(const Ogre::RenderTargetViewportEvent &event); - }; -} - -#endif // OPENCS_VIEW_OVERLAYMASK_H diff --git a/apps/opencs/view/render/overlaysystem.cpp b/apps/opencs/view/render/overlaysystem.cpp deleted file mode 100644 index f565f5af0..000000000 --- a/apps/opencs/view/render/overlaysystem.cpp +++ /dev/null @@ -1,34 +0,0 @@ -#include "overlaysystem.hpp" - -#include - -#include - -namespace CSVRender -{ - OverlaySystem *OverlaySystem::mOverlaySystemInstance = 0; - - OverlaySystem::OverlaySystem() - { - assert(!mOverlaySystemInstance); - mOverlaySystemInstance = this; - mOverlaySystem = new Ogre::OverlaySystem(); - } - - OverlaySystem::~OverlaySystem() - { - delete mOverlaySystem; - } - - OverlaySystem &OverlaySystem::instance() - { - assert(mOverlaySystemInstance); - return *mOverlaySystemInstance; - } - - Ogre::OverlaySystem *OverlaySystem::get() - { - return mOverlaySystem; - } -} - diff --git a/apps/opencs/view/render/overlaysystem.hpp b/apps/opencs/view/render/overlaysystem.hpp deleted file mode 100644 index f8a78f329..000000000 --- a/apps/opencs/view/render/overlaysystem.hpp +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef OPENCS_VIEW_OVERLAYSYSTEM_H -#define OPENCS_VIEW_OVERLAYSYSTEM_H - -namespace Ogre -{ - class OverlaySystem; -} - -namespace CSVRender -{ - class OverlaySystem - { - Ogre::OverlaySystem *mOverlaySystem; - static OverlaySystem *mOverlaySystemInstance; - - public: - - OverlaySystem(); - ~OverlaySystem(); - static OverlaySystem &instance(); - - Ogre::OverlaySystem *get(); - }; -} - -#endif // OPENCS_VIEW_OVERLAYSYSTEM_H diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index cf9edb548..90181a367 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -15,7 +15,6 @@ #include #include "textoverlay.hpp" -#include "overlaymask.hpp" #include "../../model/world/tablemimedata.hpp" #include "../../model/world/idtable.hpp" @@ -160,11 +159,13 @@ bool CSVRender::PagedWorldspaceWidget::adjustCells() textDisp->setDesc(desc); // FIXME: config setting textDisp->update(); mTextOverlays.insert(std::make_pair(*iter, textDisp)); + /* if(!mOverlayMask) { mOverlayMask = new OverlayMask(mTextOverlays, getViewport()); addRenderTargetListener(mOverlayMask); } + */ modified = true; } @@ -342,7 +343,7 @@ std::string CSVRender::PagedWorldspaceWidget::getStartupInstruction() CSVRender::PagedWorldspaceWidget::PagedWorldspaceWidget (QWidget* parent, CSMDoc::Document& document) : WorldspaceWidget (document, parent), mDocument (document), mWorldspace ("std::default"), - mControlElements(NULL), mDisplayCellCoord(true), mOverlayMask(NULL) + mControlElements(NULL), mDisplayCellCoord(true) { QAbstractItemModel *cells = document.getData().getTableModel (CSMWorld::UniversalId::Type_Cells); @@ -371,11 +372,13 @@ CSVRender::PagedWorldspaceWidget::~PagedWorldspaceWidget() delete iter->second; } + /* if(mOverlayMask) { removeRenderTargetListener(mOverlayMask); delete mOverlayMask; } + */ } void CSVRender::PagedWorldspaceWidget::useViewHint (const std::string& hint) diff --git a/apps/opencs/view/render/pagedworldspacewidget.hpp b/apps/opencs/view/render/pagedworldspacewidget.hpp index 3db6ee4ed..22c6ed478 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.hpp +++ b/apps/opencs/view/render/pagedworldspacewidget.hpp @@ -29,7 +29,6 @@ namespace CSVRender CSVWidget::SceneToolToggle *mControlElements; bool mDisplayCellCoord; std::map mTextOverlays; - OverlayMask *mOverlayMask; private: diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index 55cf039fc..3a660b5fd 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -11,14 +11,12 @@ #include #include #include -#include #include "../widget/scenetoolmode.hpp" #include "../../model/settings/usersettings.hpp" #include "navigation.hpp" #include "lighting.hpp" -#include "overlaysystem.hpp" namespace CSVRender { @@ -61,9 +59,6 @@ namespace CSVRender setLighting (&mLightingDay); - mOverlaySystem = OverlaySystem::instance().get(); - mSceneMgr->addRenderQueueListener(mOverlaySystem); - QTimer *timer = new QTimer (this); connect (timer, SIGNAL (timeout()), this, SLOT (update())); @@ -165,9 +160,6 @@ namespace CSVRender if (mWindow) Ogre::Root::getSingleton().destroyRenderTarget (mWindow); - if (mSceneMgr) - mSceneMgr->removeRenderQueueListener (mOverlaySystem); - if (mSceneMgr) Ogre::Root::getSingleton().destroySceneManager (mSceneMgr); diff --git a/apps/opencs/view/render/scenewidget.hpp b/apps/opencs/view/render/scenewidget.hpp index 699d6a7a5..c57038869 100644 --- a/apps/opencs/view/render/scenewidget.hpp +++ b/apps/opencs/view/render/scenewidget.hpp @@ -15,7 +15,6 @@ namespace Ogre class SceneManager; class RenderWindow; class Viewport; - class OverlaySystem; class RenderTargetListener; } @@ -99,7 +98,6 @@ namespace CSVRender Ogre::SceneManager* mSceneMgr; Ogre::RenderWindow* mWindow; Ogre::Viewport *mViewport; - Ogre::OverlaySystem *mOverlaySystem; Navigation *mNavigation; Lighting *mLighting; diff --git a/apps/opencs/view/world/physicssystem.cpp b/apps/opencs/view/world/physicssystem.cpp index 2cbe17dcf..4e23c185a 100644 --- a/apps/opencs/view/world/physicssystem.cpp +++ b/apps/opencs/view/world/physicssystem.cpp @@ -16,8 +16,9 @@ namespace CSVWorld PhysicsSystem::PhysicsSystem() { // Create physics. shapeLoader is deleted by the physic engine - NifBullet::ManualBulletShapeLoader* shapeLoader = new NifBullet::ManualBulletShapeLoader(true); - mEngine = new OEngine::Physic::PhysicEngine(shapeLoader); + //NifBullet::ManualBulletShapeLoader* shapeLoader = new NifBullet::ManualBulletShapeLoader(true); + //mEngine = new OEngine::Physic::PhysicEngine(shapeLoader); + mEngine = 0; } PhysicsSystem::~PhysicsSystem() diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp index c5d969d0d..d0b52a9ff 100644 --- a/apps/opencs/view/world/subviews.cpp +++ b/apps/opencs/view/world/subviews.cpp @@ -170,4 +170,4 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) //preview manager.add (CSMWorld::UniversalId::Type_Preview, new CSVDoc::SubViewFactory); -} \ No newline at end of file +} diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 475f9d01f..311b98039 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -106,7 +106,8 @@ add_component_dir (translation translation ) -add_definitions(-DTERRAIN_USE_SHADER=1) +#add_definitions(-DTERRAIN_USE_SHADER=1) +add_definitions(-DTERRAIN_USE_SHADER=0) add_component_dir (terrain quadtreenode chunk world defaultworld terraingrid storage material buffercache defs ) diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index 1ef00a0e1..a0259a11f 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -82,12 +82,14 @@ namespace Physic , mWalkingOnWater(false) , mCanWaterWalk(false) { + /* if (!NifBullet::getBoundingBox(mMesh, mHalfExtents, mMeshTranslation, mMeshOrientation)) { mHalfExtents = Ogre::Vector3(0.f); mMeshTranslation = Ogre::Vector3(0.f); mMeshOrientation = Ogre::Quaternion::IDENTITY; } + */ // Use capsule shape only if base is square (nonuniform scaling apparently doesn't work on it) if (std::abs(mHalfExtents.x-mHalfExtents.y)= mHalfExtents.x) From 413b35de6c8ab3cfccc13965aaef2c20bf3b7f01 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 19 Mar 2015 21:03:24 +0100 Subject: [PATCH 0781/3725] moved search menu item from view to edit --- apps/opencs/view/doc/view.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 3cabd8737..533cab049 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -91,6 +91,10 @@ void CSVDoc::View::setupEditMenu() QAction *userSettings = new QAction (tr ("&Preferences"), this); connect (userSettings, SIGNAL (triggered()), this, SIGNAL (editSettingsRequest())); edit->addAction (userSettings); + + QAction *search = new QAction (tr ("Search"), this); + connect (search, SIGNAL (triggered()), this, SLOT (addSearchSubView())); + edit->addAction (search); } void CSVDoc::View::setupViewMenu() @@ -113,10 +117,6 @@ void CSVDoc::View::setupViewMenu() QAction *filters = new QAction (tr ("Filters"), this); connect (filters, SIGNAL (triggered()), this, SLOT (addFiltersSubView())); view->addAction (filters); - - QAction *search = new QAction (tr ("Search"), this); - connect (search, SIGNAL (triggered()), this, SLOT (addSearchSubView())); - view->addAction (search); } void CSVDoc::View::setupWorldMenu() From 40fc09772290dc16ab5026bb8d42b499a0e59a1b Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 19 Mar 2015 17:49:41 +0100 Subject: [PATCH 0782/3725] OpenCS: use the new VFS, restored resource tables --- apps/opencs/editor.cpp | 22 ++----- apps/opencs/editor.hpp | 8 +++ apps/opencs/model/doc/documentmanager.cpp | 12 ++-- apps/opencs/model/doc/documentmanager.hpp | 11 +++- apps/opencs/model/world/resources.cpp | 64 ++++++++------------ apps/opencs/model/world/resources.hpp | 7 ++- apps/opencs/model/world/resourcesmanager.cpp | 18 +++--- apps/opencs/model/world/resourcesmanager.hpp | 10 ++- components/CMakeLists.txt | 2 +- components/vfs/manager.cpp | 5 ++ components/vfs/manager.hpp | 3 + components/vfs/registerarchives.cpp | 42 +++++++++++++ components/vfs/registerarchives.hpp | 15 +++++ 13 files changed, 143 insertions(+), 76 deletions(-) create mode 100644 components/vfs/registerarchives.cpp create mode 100644 components/vfs/registerarchives.hpp diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 92fd40492..3c4ce6868 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -1,21 +1,13 @@ #include "editor.hpp" -#include - #include #include #include #include -#include -#include - -#include -#include - -#include -#include +#include +#include #include "model/doc/document.hpp" #include "model/world/data.hpp" @@ -34,10 +26,11 @@ CS::Editor::Editor () //NifOgre::Loader::setShowMarkers(true); - //Bsa::registerResources (Files::Collections (config.first, !mFsStrict), config.second, true, - // mFsStrict); + mVFS.reset(new VFS::Manager(mFsStrict)); - mDocumentManager.listResources(); + VFS::registerArchives(mVFS.get(), Files::Collections(config.first, !mFsStrict), config.second, true); + + mDocumentManager.setVFS(mVFS.get()); mNewGame.setLocalData (mLocal); mFileDialog.setLocalData (mLocal); @@ -74,9 +67,6 @@ CS::Editor::~Editor () if(mServer && boost::filesystem::exists(mPid)) static_cast ( // silence coverity warning remove(mPid.string().c_str())); // ignore any error - - // cleanup global resources used by OEngine - delete OEngine::Physic::BulletShapeManager::getSingletonPtr(); } void CS::Editor::setupDataFiles (const Files::PathContainer& dataDirs) diff --git a/apps/opencs/editor.hpp b/apps/opencs/editor.hpp index da4d63985..e973b9c55 100644 --- a/apps/opencs/editor.hpp +++ b/apps/opencs/editor.hpp @@ -27,12 +27,20 @@ #include "view/settings/dialog.hpp" +namespace VFS +{ + class Manager; +} + namespace CS { class Editor : public QObject { Q_OBJECT + // FIXME: should be moved to document, so we can have different resources for each opened project + std::auto_ptr mVFS; + Files::ConfigurationManager mCfgMgr; CSMSettings::UserSettings mUserSettings; CSMDoc::DocumentManager mDocumentManager; diff --git a/apps/opencs/model/doc/documentmanager.cpp b/apps/opencs/model/doc/documentmanager.cpp index 9b807225c..ecff4bbed 100644 --- a/apps/opencs/model/doc/documentmanager.cpp +++ b/apps/opencs/model/doc/documentmanager.cpp @@ -90,11 +90,6 @@ void CSMDoc::DocumentManager::setBlacklistedScripts (const std::vector mBlacklistedScripts; + VFS::Manager* mVFS; DocumentManager (const DocumentManager&); DocumentManager& operator= (const DocumentManager&); @@ -56,8 +62,7 @@ namespace CSMDoc void setBlacklistedScripts (const std::vector& scriptIds); - /// Ask OGRE for a list of available resources. - void listResources(); + void setVFS(const VFS::Manager* vfs); private: @@ -99,4 +104,4 @@ namespace CSMDoc }; } -#endif \ No newline at end of file +#endif diff --git a/apps/opencs/model/world/resources.cpp b/apps/opencs/model/world/resources.cpp index 25fada93a..158793173 100644 --- a/apps/opencs/model/world/resources.cpp +++ b/apps/opencs/model/world/resources.cpp @@ -7,62 +7,50 @@ #include +#include + #include -CSMWorld::Resources::Resources (const std::string& baseDirectory, UniversalId::Type type, +CSMWorld::Resources::Resources (const VFS::Manager* vfs, const std::string& baseDirectory, UniversalId::Type type, const char * const *extensions) : mBaseDirectory (baseDirectory), mType (type) { int baseSize = mBaseDirectory.size(); - /* - Ogre::StringVector resourcesGroups = - Ogre::ResourceGroupManager::getSingleton().getResourceGroups(); - - for (Ogre::StringVector::iterator iter (resourcesGroups.begin()); - iter!=resourcesGroups.end(); ++iter) + const std::map& index = vfs->getIndex(); + for (std::map::const_iterator it = index.begin(); it != index.end(); ++it) { - if (*iter=="General" || *iter=="Internal" || *iter=="Autodetect") + std::string filepath = it->first; + if (static_cast (filepath.size())begin()); - iter!=resources->end(); ++iter) + if (extensions) { - if (static_cast (iter->size())substr (0, baseSize)!=mBaseDirectory || - ((*iter)[baseSize]!='/' && (*iter)[baseSize]!='\\')) - continue; - - if (extensions) - { - std::string::size_type index = iter->find_last_of ('.'); + std::string::size_type index = filepath.find_last_of ('.'); - if (index==std::string::npos) - continue; - - std::string extension = iter->substr (index+1); + if (index==std::string::npos) + continue; - int i = 0; + std::string extension = filepath.substr (index+1); - for (; extensions[i]; ++i) - if (extensions[i]==extension) - break; + int i = 0; - if (!extensions[i]) - continue; - } + for (; extensions[i]; ++i) + if (extensions[i]==extension) + break; - std::string file = iter->substr (baseSize+1); - mFiles.push_back (file); - std::replace (file.begin(), file.end(), '\\', '/'); - mIndex.insert (std::make_pair ( - Misc::StringUtils::lowerCase (file), static_cast (mFiles.size())-1)); + if (!extensions[i]) + continue; } + + std::string file = filepath.substr (baseSize+1); + mFiles.push_back (file); + std::replace (file.begin(), file.end(), '\\', '/'); + mIndex.insert (std::make_pair ( + Misc::StringUtils::lowerCase (file), static_cast (mFiles.size())-1)); } - */ } int CSMWorld::Resources::getSize() const diff --git a/apps/opencs/model/world/resources.hpp b/apps/opencs/model/world/resources.hpp index 9c1c76b6f..d6998da9f 100644 --- a/apps/opencs/model/world/resources.hpp +++ b/apps/opencs/model/world/resources.hpp @@ -7,6 +7,11 @@ #include "universalid.hpp" +namespace VFS +{ + class Manager; +} + namespace CSMWorld { class Resources @@ -19,7 +24,7 @@ namespace CSMWorld public: /// \param type Type of resources in this table. - Resources (const std::string& baseDirectory, UniversalId::Type type, + Resources (const VFS::Manager* vfs, const std::string& baseDirectory, UniversalId::Type type, const char * const *extensions = 0); int getSize() const; diff --git a/apps/opencs/model/world/resourcesmanager.cpp b/apps/opencs/model/world/resourcesmanager.cpp index 50014f4b5..218937924 100644 --- a/apps/opencs/model/world/resourcesmanager.cpp +++ b/apps/opencs/model/world/resourcesmanager.cpp @@ -10,16 +10,18 @@ void CSMWorld::ResourcesManager::addResources (const Resources& resources) resources)); } -void CSMWorld::ResourcesManager::listResources() +void CSMWorld::ResourcesManager::setVFS(const VFS::Manager *vfs) { + mResources.clear(); + static const char * const sMeshTypes[] = { "nif", 0 }; - addResources (Resources ("meshes", UniversalId::Type_Mesh, sMeshTypes)); - addResources (Resources ("icons", UniversalId::Type_Icon)); - addResources (Resources ("music", UniversalId::Type_Music)); - addResources (Resources ("sound", UniversalId::Type_SoundRes)); - addResources (Resources ("textures", UniversalId::Type_Texture)); - addResources (Resources ("videos", UniversalId::Type_Video)); + addResources (Resources (vfs, "meshes", UniversalId::Type_Mesh, sMeshTypes)); + addResources (Resources (vfs, "icons", UniversalId::Type_Icon)); + addResources (Resources (vfs, "music", UniversalId::Type_Music)); + addResources (Resources (vfs, "sound", UniversalId::Type_SoundRes)); + addResources (Resources (vfs, "textures", UniversalId::Type_Texture)); + addResources (Resources (vfs, "videos", UniversalId::Type_Video)); } const CSMWorld::Resources& CSMWorld::ResourcesManager::get (UniversalId::Type type) const @@ -30,4 +32,4 @@ const CSMWorld::Resources& CSMWorld::ResourcesManager::get (UniversalId::Type ty throw std::logic_error ("Unknown resource type"); return iter->second; -} \ No newline at end of file +} diff --git a/apps/opencs/model/world/resourcesmanager.hpp b/apps/opencs/model/world/resourcesmanager.hpp index 77f210c47..ee939389f 100644 --- a/apps/opencs/model/world/resourcesmanager.hpp +++ b/apps/opencs/model/world/resourcesmanager.hpp @@ -6,6 +6,11 @@ #include "universalid.hpp" #include "resources.hpp" +namespace VFS +{ + class Manager; +} + namespace CSMWorld { class ResourcesManager @@ -18,11 +23,10 @@ namespace CSMWorld public: - /// Ask OGRE for a list of available resources. - void listResources(); + void setVFS(const VFS::Manager* vfs); const Resources& get (UniversalId::Type type) const; }; } -#endif \ No newline at end of file +#endif diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 311b98039..a78f164a6 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -35,7 +35,7 @@ add_component_dir (bsa ) add_component_dir (vfs - manager archive bsaarchive filesystemarchive + manager archive bsaarchive filesystemarchive registerarchives ) add_component_dir (nif diff --git a/components/vfs/manager.cpp b/components/vfs/manager.cpp index 82f4cd7be..d0e0cf586 100644 --- a/components/vfs/manager.cpp +++ b/components/vfs/manager.cpp @@ -73,4 +73,9 @@ namespace VFS return mIndex.find(normalized) != mIndex.end(); } + const std::map& Manager::getIndex() const + { + return mIndex; + } + } diff --git a/components/vfs/manager.hpp b/components/vfs/manager.hpp index 31538cc99..ebbec7d15 100644 --- a/components/vfs/manager.hpp +++ b/components/vfs/manager.hpp @@ -35,6 +35,9 @@ namespace VFS /// Does a file with this name exist? bool exists(const std::string& name) const; + /// Get a complete list of files from all archives + const std::map& getIndex() const; + /// Retrieve a file by name. /// @note Throws an exception if the file can not be found. Files::IStreamPtr get(const std::string& name) const; diff --git a/components/vfs/registerarchives.cpp b/components/vfs/registerarchives.cpp new file mode 100644 index 000000000..cd077356f --- /dev/null +++ b/components/vfs/registerarchives.cpp @@ -0,0 +1,42 @@ +#include "registerarchives.hpp" + +#include +#include +#include + +namespace VFS +{ + + void registerArchives(VFS::Manager *vfs, const Files::Collections &collections, const std::vector &archives, bool useLooseFiles) + { + const Files::PathContainer& dataDirs = collections.getPaths(); + + if (useLooseFiles) + for (Files::PathContainer::const_iterator iter = dataDirs.begin(); iter != dataDirs.end(); ++iter) + { + // Last data dir has the highest priority + vfs->addArchive(new FileSystemArchive(iter->string())); + } + + for (std::vector::const_iterator archive = archives.begin(); archive != archives.end(); ++archive) + { + if (collections.doesExist(*archive)) + { + // Last BSA has the highest priority + const std::string archivePath = collections.getPath(*archive).string(); + std::cout << "Adding BSA archive " << archivePath << std::endl; + + vfs->addArchive(new BsaArchive(archivePath)); + } + else + { + std::stringstream message; + message << "Archive '" << *archive << "' not found"; + throw std::runtime_error(message.str()); + } + } + + vfs->buildIndex(); + } + +} diff --git a/components/vfs/registerarchives.hpp b/components/vfs/registerarchives.hpp new file mode 100644 index 000000000..1ef13f0f9 --- /dev/null +++ b/components/vfs/registerarchives.hpp @@ -0,0 +1,15 @@ +#ifndef OPENMW_COMPONENTS_VFS_REGISTER_ARCHIVES_H +#define OPENMW_COMPONENTS_VFS_REGISTER_ARCHIVES_H + +#include + +namespace VFS +{ + class Manager; + + /// @brief Register BSA and file system archives based on the given OpenMW configuration. + void registerArchives (VFS::Manager* vfs, const Files::Collections& collections, + const std::vector& archives, bool useLooseFiles); +} + +#endif From 34d503017adda4e9c6366a7262759dc8c198ba83 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 19 Mar 2015 23:27:14 +0100 Subject: [PATCH 0783/3725] OpenCS: Set up an osgQt GraphicsWindow in SceneWidget --- CMakeLists.txt | 2 +- apps/opencs/CMakeLists.txt | 3 +- apps/opencs/main.cpp | 3 + apps/opencs/view/render/mousestate.cpp | 8 +- .../view/render/pagedworldspacewidget.cpp | 38 +- .../view/render/pagedworldspacewidget.hpp | 2 - apps/opencs/view/render/previewwidget.cpp | 13 +- apps/opencs/view/render/previewwidget.hpp | 2 +- apps/opencs/view/render/scenewidget.cpp | 482 ++---------------- apps/opencs/view/render/scenewidget.hpp | 116 +---- .../view/render/unpagedworldspacewidget.cpp | 11 +- apps/opencs/view/render/worldspacewidget.cpp | 12 +- apps/opencs/view/world/previewsubview.cpp | 6 +- apps/opencs/view/world/scenesubview.cpp | 4 +- 14 files changed, 115 insertions(+), 587 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1059b1c3a..17abedb4c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -221,7 +221,7 @@ if (${OGRE_VERSION} VERSION_LESS "1.9") message(FATAL_ERROR "OpenMW requires Ogre 1.9 or later, please install the latest stable version from http://ogre3d.org") endif() -find_package(OpenSceneGraph 3.2.0 REQUIRED osgDB osgViewer osgGA osgAnimation osgParticle) +find_package(OpenSceneGraph 3.2.0 REQUIRED osgDB osgViewer osgGA osgAnimation osgParticle osgQt) include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS}) find_package(MyGUI REQUIRED) diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 3548c175a..6976aec42 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -157,7 +157,7 @@ endif(WIN32) find_package(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS}) -find_package(Qt4 COMPONENTS QtCore QtGui QtNetwork REQUIRED) +find_package(Qt4 COMPONENTS QtCore QtGui QtNetwork QtOpenGL REQUIRED) include(${QT_USE_FILE}) qt4_wrap_ui(OPENCS_UI_HDR ${OPENCS_UI}) @@ -201,6 +201,7 @@ target_link_libraries(openmw-cs ${OGRE_LIBRARIES} ${OGRE_Overlay_LIBRARIES} ${OGRE_STATIC_PLUGINS} + ${OPENSCENEGRAPH_LIBRARIES} ${SHINY_LIBRARIES} ${Boost_LIBRARIES} ${BULLET_LIBRARIES} diff --git a/apps/opencs/main.cpp b/apps/opencs/main.cpp index eb5dcc64e..e3d5d3cdd 100644 --- a/apps/opencs/main.cpp +++ b/apps/opencs/main.cpp @@ -44,6 +44,9 @@ int main(int argc, char *argv[]) { try { + // To allow background thread drawing in OSG + QApplication::setAttribute(Qt::AA_X11InitThreads, true); + Q_INIT_RESOURCE (resources); qRegisterMetaType ("std::string"); diff --git a/apps/opencs/view/render/mousestate.cpp b/apps/opencs/view/render/mousestate.cpp index a94f4f8ab..8edd9d58f 100644 --- a/apps/opencs/view/render/mousestate.cpp +++ b/apps/opencs/view/render/mousestate.cpp @@ -56,7 +56,7 @@ namespace CSVRender // MouseState::MouseState(WorldspaceWidget *parent) - : mParent(parent), mPhysics(parent->mDocument.getPhysics()), mSceneManager(parent->getSceneManager()) + : mParent(parent), mPhysics(parent->mDocument.getPhysics()), mSceneManager(0/*parent->getSceneManager()*/) , mCurrentObj(""), mMouseState(Mouse_Default), mOldPos(0,0), mMouseEventTimer(0), mPlane(0) , mGrabbedSceneNode(""), mOrigObjPos(Ogre::Vector3()), mOrigMousePos(Ogre::Vector3()) , mCurrentMousePos(Ogre::Vector3()), mOffset(0.0f) @@ -447,17 +447,17 @@ namespace CSVRender std::map::iterator iter = sceneWidgets.begin(); for(; iter != sceneWidgets.end(); ++iter) { - (*iter).second->updateScene(); + //(*iter).second->updateScene(); } } Ogre::Camera *MouseState::getCamera() { - return mParent->getCamera(); + return 0;//mParent->getCamera(); } Ogre::Viewport *MouseState::getViewport() { - return mParent->getCamera()->getViewport(); + return 0;//mParent->getCamera()->getViewport(); } } diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index 90181a367..84a5a5665 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -29,7 +29,7 @@ bool CSVRender::PagedWorldspaceWidget::adjustCells() { bool modified = false; - bool setCamera = false; + //bool setCamera = false; const CSMWorld::IdCollection& cells = mDocument.getData().getCells(); @@ -53,7 +53,7 @@ bool CSVRender::PagedWorldspaceWidget::adjustCells() } // destroy manual objects - getSceneManager()->destroyManualObject("manual"+iter->first.getId(mWorldspace)); + //getSceneManager()->destroyManualObject("manual"+iter->first.getId(mWorldspace)); delete iter->second; mCells.erase (iter++); @@ -98,8 +98,8 @@ bool CSVRender::PagedWorldspaceWidget::adjustCells() } } - if (mCells.begin()==mCells.end()) - setCamera = true; + //if (mCells.begin()==mCells.end()) + //setCamera = true; // add for (CSMWorld::CellSelection::Iterator iter (mSelection.begin()); iter!=mSelection.end(); @@ -110,6 +110,7 @@ bool CSVRender::PagedWorldspaceWidget::adjustCells() if (index > 0 && cells.getRecord (index).mState!=CSMWorld::RecordBase::State_Deleted && mCells.find (*iter)==mCells.end()) { +#if 0 Cell *cell = new Cell (mDocument.getData(), getSceneManager(), iter->getId (mWorldspace), mDocument.getPhysics()); mCells.insert (std::make_pair (*iter, cell)); @@ -167,6 +168,8 @@ bool CSVRender::PagedWorldspaceWidget::adjustCells() } */ +#endif + modified = true; } } @@ -242,28 +245,6 @@ void CSVRender::PagedWorldspaceWidget::addEditModeSelectorButtons ( "terrain-move"); } -void CSVRender::PagedWorldspaceWidget::updateOverlay() -{ - if(getCamera()->getViewport()) - { - if((uint32_t)getCamera()->getViewport()->getVisibilityMask() - & (uint32_t)CSVRender::Element_CellMarker) - mDisplayCellCoord = true; - else - mDisplayCellCoord = false; - } - - if(!mTextOverlays.empty()) - { - std::map::iterator it = mTextOverlays.begin(); - for(; it != mTextOverlays.end(); ++it) - { - it->second->enable(mDisplayCellCoord); - it->second->update(); - } - } -} - void CSVRender::PagedWorldspaceWidget::referenceableDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) { @@ -329,6 +310,7 @@ void CSVRender::PagedWorldspaceWidget::referenceAdded (const QModelIndex& parent std::string CSVRender::PagedWorldspaceWidget::getStartupInstruction() { + /* Ogre::Vector3 position = getCamera()->getPosition(); std::ostringstream stream; @@ -339,6 +321,8 @@ std::string CSVRender::PagedWorldspaceWidget::getStartupInstruction() << ", 0"; return stream.str(); + */ + return ""; } CSVRender::PagedWorldspaceWidget::PagedWorldspaceWidget (QWidget* parent, CSMDoc::Document& document) @@ -363,7 +347,7 @@ CSVRender::PagedWorldspaceWidget::~PagedWorldspaceWidget() { delete iter->second; - getSceneManager()->destroyManualObject("manual"+iter->first.getId(mWorldspace)); + //getSceneManager()->destroyManualObject("manual"+iter->first.getId(mWorldspace)); } for (std::map::iterator iter (mTextOverlays.begin()); diff --git a/apps/opencs/view/render/pagedworldspacewidget.hpp b/apps/opencs/view/render/pagedworldspacewidget.hpp index 22c6ed478..1bc9c3c5c 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.hpp +++ b/apps/opencs/view/render/pagedworldspacewidget.hpp @@ -86,8 +86,6 @@ namespace CSVRender virtual void addEditModeSelectorButtons (CSVWidget::SceneToolMode *tool); - virtual void updateOverlay(); - virtual void mousePressEvent (QMouseEvent *event); virtual void mouseReleaseEvent (QMouseEvent *event); diff --git a/apps/opencs/view/render/previewwidget.cpp b/apps/opencs/view/render/previewwidget.cpp index da18e7c89..6982cad52 100644 --- a/apps/opencs/view/render/previewwidget.cpp +++ b/apps/opencs/view/render/previewwidget.cpp @@ -9,10 +9,9 @@ CSVRender::PreviewWidget::PreviewWidget (CSMWorld::Data& data, const std::string& id, bool referenceable, QWidget *parent) -: SceneWidget (parent), mData (data), - mObject (data, getSceneManager()->getRootSceneNode(), id, referenceable, boost::shared_ptr(), true) +: SceneWidget (parent), mData (data) { - setNavigation (&mOrbit); + //setNavigation (&mOrbit); QAbstractItemModel *referenceables = mData.getTableModel (CSMWorld::UniversalId::Type_Referenceables); @@ -37,6 +36,7 @@ CSVRender::PreviewWidget::PreviewWidget (CSMWorld::Data& data, void CSVRender::PreviewWidget::referenceableDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) { +#if 0 if (mObject.referenceableDataChanged (topLeft, bottomRight)) flagAsModified(); @@ -51,11 +51,13 @@ void CSVRender::PreviewWidget::referenceableDataChanged (const QModelIndex& topL if (referenceables.data (index).toInt()==CSMWorld::RecordBase::State_Deleted) emit closeRequest(); } +#endif } void CSVRender::PreviewWidget::referenceableAboutToBeRemoved (const QModelIndex& parent, int start, int end) { +#if 0 if (mObject.referenceableAboutToBeRemoved (parent, start, end)) flagAsModified(); @@ -75,11 +77,13 @@ void CSVRender::PreviewWidget::referenceableAboutToBeRemoved (const QModelIndex& emit closeRequest(); } } +#endif } void CSVRender::PreviewWidget::referenceDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) { +#if 0 if (mObject.referenceDataChanged (topLeft, bottomRight)) flagAsModified(); @@ -108,11 +112,13 @@ void CSVRender::PreviewWidget::referenceDataChanged (const QModelIndex& topLeft, if (index.row()>=topLeft.row() && index.row()<=bottomRight.row()) if (index.column()>=topLeft.column() && index.column()<=bottomRight.row()) emit referenceableIdChanged (mObject.getReferenceableId()); +#endif } void CSVRender::PreviewWidget::referenceAboutToBeRemoved (const QModelIndex& parent, int start, int end) { +#if 0 if (mObject.getReferenceId().empty()) return; @@ -123,4 +129,5 @@ void CSVRender::PreviewWidget::referenceAboutToBeRemoved (const QModelIndex& par if (index.row()>=start && index.row()<=end) emit closeRequest(); +#endif } diff --git a/apps/opencs/view/render/previewwidget.hpp b/apps/opencs/view/render/previewwidget.hpp index dd6a99c0f..7260ee242 100644 --- a/apps/opencs/view/render/previewwidget.hpp +++ b/apps/opencs/view/render/previewwidget.hpp @@ -21,7 +21,7 @@ namespace CSVRender CSMWorld::Data& mData; CSVRender::NavigationOrbit mOrbit; - Object mObject; + //Object mObject; public: diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index 3a660b5fd..82dc4c211 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -4,13 +4,7 @@ #include #include #include - -#include -#include -#include -#include -#include -#include +#include #include "../widget/scenetoolmode.hpp" #include "../../model/settings/usersettings.hpp" @@ -18,445 +12,75 @@ #include "navigation.hpp" #include "lighting.hpp" -namespace CSVRender -{ - SceneWidget::SceneWidget(QWidget *parent) - : QWidget(parent) - , mCamera(NULL) - , mSceneMgr(NULL) - , mWindow(NULL) - , mViewport(NULL) - , mNavigation (0), mLighting (0), mUpdate (false), mKeyForward (false) - , mKeyBackward (false), mKeyLeft (false), mKeyRight (false) - , mKeyRollLeft (false), mKeyRollRight (false) - , mFast (false), mDragging (false), mMod1 (false) - , mFastFactor (4) - , mDefaultAmbient (0, 0, 0, 0), mHasDefaultAmbient (false) - { - setAttribute(Qt::WA_PaintOnScreen); - setAttribute(Qt::WA_NoSystemBackground); - - setFocusPolicy (Qt::StrongFocus); - - mSceneMgr = Ogre::Root::getSingleton().createSceneManager(Ogre::ST_GENERIC); - - mSceneMgr->setAmbientLight (Ogre::ColourValue (0,0,0,1)); - - mCamera = mSceneMgr->createCamera("foo"); - - mCamera->setPosition (300, 0, 0); - mCamera->lookAt (0, 0, 0); - mCamera->setNearClipDistance (0.1); - - CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); - - float farClipDist = userSettings.setting("3d-render/far-clip-distance", QString("300000")).toFloat(); - mCamera->setFarClipDistance (farClipDist); - - mFastFactor = userSettings.setting("scene-input/fast-factor", QString("4")).toInt(); - - mCamera->roll (Ogre::Degree (90)); - - setLighting (&mLightingDay); - - QTimer *timer = new QTimer (this); - - connect (timer, SIGNAL (timeout()), this, SLOT (update())); - - int timerStart = userSettings.setting("scene-input/timer", QString("20")).toInt(); - timer->start (timerStart); - - /// \todo make shortcut configurable - QShortcut *focusToolbar = new QShortcut (Qt::Key_T, this, 0, 0, Qt::WidgetWithChildrenShortcut); - connect (focusToolbar, SIGNAL (activated()), this, SIGNAL (focusToolbarRequest())); - } - - CSVWidget::SceneToolMode *SceneWidget::makeLightingSelector (CSVWidget::SceneToolbar *parent) - { - CSVWidget::SceneToolMode *tool = new CSVWidget::SceneToolMode (parent, "Lighting Mode"); - - /// \todo replace icons - tool->addButton (":scenetoolbar/day", "day", - "Day" - "
  • Cell specific ambient in interiors
  • " - "
  • Low ambient in exteriors
  • " - "
  • Strong directional light source/lir>" - "
  • This mode closely resembles day time in-game
"); - tool->addButton (":scenetoolbar/night", "night", - "Night" - "
  • Cell specific ambient in interiors
  • " - "
  • Low ambient in exteriors
  • " - "
  • Weak directional light source
  • " - "
  • This mode closely resembles night time in-game
"); - tool->addButton (":scenetoolbar/bright", "bright", - "Bright" - "
  • Maximum ambient
  • " - "
  • Strong directional light source
"); - - connect (tool, SIGNAL (modeChanged (const std::string&)), - this, SLOT (selectLightingMode (const std::string&))); - - return tool; - } - - void SceneWidget::setDefaultAmbient (const Ogre::ColourValue& colour) - { - mDefaultAmbient = colour; - mHasDefaultAmbient = true; - - if (mLighting) - mLighting->setDefaultAmbient (colour); - } - - void SceneWidget::updateOgreWindow() - { - if (mWindow) - { - Ogre::Root::getSingleton().destroyRenderTarget(mWindow); - mWindow = NULL; - } - - std::stringstream windowHandle; -#ifdef WIN32 - windowHandle << Ogre::StringConverter::toString((uintptr_t)(this->winId())); -#else - windowHandle << this->winId(); -#endif - std::stringstream windowTitle; - static int count=0; - windowTitle << ++count; - - Ogre::NameValuePairList params; - - params.insert(std::make_pair("externalWindowHandle", windowHandle.str())); - params.insert(std::make_pair("title", windowTitle.str())); - - std::string antialiasing = - CSMSettings::UserSettings::instance().settingValue("3d-render/antialiasing").toStdString(); - if(antialiasing == "MSAA 16") antialiasing = "16"; - else if(antialiasing == "MSAA 8") antialiasing = "8"; - else if(antialiasing == "MSAA 4") antialiasing = "4"; - else if(antialiasing == "MSAA 2") antialiasing = "2"; - else antialiasing = "0"; - params.insert(std::make_pair("FSAA", antialiasing)); - - params.insert(std::make_pair("vsync", "false")); // TODO setting -#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE - params.insert(std::make_pair("macAPI", "cocoa")); - params.insert(std::make_pair("macAPICocoaUseNSView", "true")); -#endif - - mWindow = Ogre::Root::getSingleton().createRenderWindow(windowTitle.str(), this->width(), this->height(), false, ¶ms); - - mViewport = mWindow->addViewport (mCamera); - mViewport->setBackgroundColour (Ogre::ColourValue (0.3,0.3,0.3,1)); - - Ogre::Real aspectRatio = Ogre::Real(width()) / Ogre::Real(height()); - mCamera->setAspectRatio(aspectRatio); - } - - SceneWidget::~SceneWidget() - { - if (mWindow) - Ogre::Root::getSingleton().destroyRenderTarget (mWindow); - - if (mSceneMgr) - Ogre::Root::getSingleton().destroySceneManager (mSceneMgr); - - } - - void SceneWidget::setVisibilityMask (unsigned int mask) - { - mViewport->setVisibilityMask (mask); - } - - void SceneWidget::setNavigation (Navigation *navigation) - { - if ((mNavigation = navigation)) - { - mNavigation->setFastModeFactor (mFast ? mFastFactor : 1); - if (mNavigation->activate (mCamera)) - mUpdate = true; - } - } - - void SceneWidget::addRenderTargetListener(Ogre::RenderTargetListener *listener) - { - mWindow->addListener(listener); - } - - void SceneWidget::removeRenderTargetListener(Ogre::RenderTargetListener *listener) - { - mWindow->removeListener(listener); - } +#include +#include - Ogre::Viewport *SceneWidget::getViewport() - { - if (!mWindow) - updateOgreWindow(); +#include - return mViewport; - } - - Ogre::SceneManager *SceneWidget::getSceneManager() - { - return mSceneMgr; - } - - Ogre::Camera *SceneWidget::getCamera() - { - return mCamera; - } - - void SceneWidget::flagAsModified() - { - mUpdate = true; - } - - void SceneWidget::paintEvent(QPaintEvent* e) - { - if (!mWindow) - updateOgreWindow(); - - mWindow->update(); - e->accept(); - } - - QPaintEngine* SceneWidget::paintEngine() const - { - // We don't want another paint engine to get in the way. - // So we return nothing. - return NULL; - } - - void SceneWidget::resizeEvent(QResizeEvent *e) - { - if (!mWindow) - return; +namespace CSVRender +{ - const QSize &newSize = e->size(); +SceneWidget::SceneWidget(QWidget *parent, Qt::WindowFlags f) + : QWidget(parent, f) +{ - // TODO: Fix Ogre to handle this more consistently (fixed in 1.9) -#if OGRE_PLATFORM == OGRE_PLATFORM_LINUX - mWindow->resize(newSize.width(), newSize.height()); +#if QT_VERSION >= 0x050000 + // Qt5 is currently crashing and reporting "Cannot make QOpenGLContext current in a different thread" when the viewer is run multi-threaded, this is regression from Qt4 + osgViewer::ViewerBase::ThreadingModel threadingModel = osgViewer::ViewerBase::SingleThreaded; #else - mWindow->windowMovedOrResized(); + osgViewer::ViewerBase::ThreadingModel threadingModel = osgViewer::ViewerBase::CullDrawThreadPerContext; #endif - Ogre::Real aspectRatio = Ogre::Real(newSize.width()) / Ogre::Real(newSize.height()); - mCamera->setAspectRatio(aspectRatio); - } - - bool SceneWidget::event(QEvent *e) - { - if (e->type() == QEvent::WinIdChange) - { - // I haven't actually seen this happen yet. - if (mWindow) - updateOgreWindow(); - } - return QWidget::event(e); - } - - void SceneWidget::keyPressEvent (QKeyEvent *event) - { - switch (event->key()) - { - case Qt::Key_W: mKeyForward = true; break; - case Qt::Key_S: mKeyBackward = true; break; - case Qt::Key_A: mKeyLeft = true; break; - case Qt::Key_D: mKeyRight = true; break; - case Qt::Key_Q: mKeyRollLeft = true; break; - case Qt::Key_E: mKeyRollRight = true; break; - case Qt::Key_Control: mMod1 = true; break; - - case Qt::Key_Shift: - - mFast = true; - - if (mNavigation) - mNavigation->setFastModeFactor (mFastFactor); - - break; - - default: QWidget::keyPressEvent (event); - } - } - - void SceneWidget::keyReleaseEvent (QKeyEvent *event) - { - switch (event->key()) - { - case Qt::Key_W: mKeyForward = false; break; - case Qt::Key_S: mKeyBackward = false; break; - case Qt::Key_A: mKeyLeft = false; break; - case Qt::Key_D: mKeyRight = false; break; - case Qt::Key_Q: mKeyRollLeft = false; break; - case Qt::Key_E: mKeyRollRight = false; break; - case Qt::Key_Control: mMod1 = false; break; - - case Qt::Key_Shift: - - mFast = false; - - if (mNavigation) - mNavigation->setFastModeFactor (1); + setThreadingModel(threadingModel); - break; + // disable the default setting of viewer.done() by pressing Escape. + setKeyEventSetsDone(0); - default: QWidget::keyReleaseEvent (event); - } - } + osg::DisplaySettings* ds = osg::DisplaySettings::instance().get(); + osg::ref_ptr traits = new osg::GraphicsContext::Traits; + traits->windowName = ""; + traits->windowDecoration = true; + traits->x = 0; + traits->y = 0; + traits->width = width(); + traits->height = height(); + traits->doubleBuffer = true; + traits->alpha = ds->getMinimumNumAlphaBits(); + traits->stencil = ds->getMinimumNumStencilBits(); + traits->sampleBuffers = ds->getMultiSamples(); + traits->samples = ds->getNumMultiSamples(); - void SceneWidget::wheelEvent (QWheelEvent *event) - { - if (mNavigation) - if (event->delta()) - if (mNavigation->wheelMoved (event->delta())) - mUpdate = true; - } + osgQt::GraphicsWindowQt* window = new osgQt::GraphicsWindowQt(traits.get()); + QLayout* layout = new QHBoxLayout(this); + layout->addWidget(window->getGLWidget()); + setLayout(layout); - void SceneWidget::leaveEvent (QEvent *event) - { - mDragging = false; - } + getCamera()->setGraphicsContext(window); - void SceneWidget::mouseMoveEvent (QMouseEvent *event) - { - if (event->buttons() & Qt::LeftButton) - { - if (mDragging) - { - QPoint diff = mOldPos-event->pos(); - mOldPos = event->pos(); + getCamera()->setClearColor( osg::Vec4(0.2, 0.2, 0.6, 1.0) ); + getCamera()->setViewport( new osg::Viewport(0, 0, traits->width, traits->height) ); + //getCamera()->setProjectionMatrixAsPerspective(30.0f, static_cast(traits->width)/static_cast(traits->height), 1.0f, 10000.0f ); - if (mNavigation) - if (mNavigation->mouseMoved (diff, mMod1 ? 1 : 0)) - mUpdate = true; - } - else - { - mDragging = true; - mOldPos = event->pos(); - } - } - } + osg::Node* root = new osg::Node; + setSceneData(root); - void SceneWidget::mouseReleaseEvent (QMouseEvent *event) - { - if (!(event->buttons() & Qt::LeftButton)) - mDragging = false; - } + setCameraManipulator(new osgGA::TrackballManipulator); - void SceneWidget::focusOutEvent (QFocusEvent *event) - { - mKeyForward = false; - mKeyBackward = false; - mKeyLeft = false; - mKeyRight = false; - mFast = false; - mMod1 = false; + // Only render when the camera position changed, or content flagged dirty + //setRunFrameScheme(osgViewer::ViewerBase::ON_DEMAND); - QWidget::focusOutEvent (event); - } - - void SceneWidget::update() - { - if (mNavigation) - { - int horizontal = 0; - int vertical = 0; - - if (mKeyForward && !mKeyBackward) - vertical = 1; - else if (!mKeyForward && mKeyBackward) - vertical = -1; - - if (mKeyLeft && !mKeyRight) - horizontal = -1; - else if (!mKeyLeft && mKeyRight) - horizontal = 1; - - if (horizontal || vertical) - if (mNavigation->handleMovementKeys (vertical, horizontal)) - mUpdate = true; - - int roll = 0; - - if (mKeyRollLeft && !mKeyRollRight) - roll = 1; - else if (!mKeyRollLeft && mKeyRollRight) - roll = -1; - - if (roll) - if (mNavigation->handleRollKeys (roll)) - mUpdate = true; - - } - - if (mUpdate && mWindow) - { - mUpdate = false; - mWindow->update(); - updateOverlay(); - } - } - - void SceneWidget::updateScene() - { - flagAsModified(); - } - - void SceneWidget::updateOverlay() - { } - - void SceneWidget::setLighting (Lighting *lighting) - { - if (mLighting) - mLighting->deactivate(); - - mLighting = lighting; - mLighting->activate (mSceneMgr, mHasDefaultAmbient ? &mDefaultAmbient : 0); - - if (mWindow) - mWindow->update(); - } - - void SceneWidget::selectLightingMode (const std::string& mode) - { - if (mode=="day") - setLighting (&mLightingDay); - else if (mode=="night") - setLighting (&mLightingNight); - else if (mode=="bright") - setLighting (&mLightingBright); - } + connect( &mTimer, SIGNAL(timeout()), this, SLOT(update()) ); + mTimer.start( 10 ); +} - void SceneWidget::updateUserSetting (const QString &key, const QStringList &list) - { - if(key.contains(QRegExp("^\\b(Objects|Shader|Scene)", Qt::CaseInsensitive))) - flagAsModified(); +void SceneWidget::paintEvent(QPaintEvent *event) +{ + frame(); +} - if(key == "3d-render/far-clip-distance" && !list.empty()) - { - if(mCamera->getFarClipDistance() != list.at(0).toFloat()) - mCamera->setFarClipDistance(list.at(0).toFloat()); - } +void SceneWidget::flagAsModified() +{ + _requestRedraw = true; +} - // minimise unnecessary ogre window creation by updating only when there is a change - if(key == "3d-render/antialiasing") - { - unsigned int aa = mWindow->getFSAA(); - unsigned int antialiasing = 0; - if(!list.empty()) - { - if(list.at(0) == "MSAA 16") antialiasing = 16; - else if(list.at(0) == "MSAA 8") antialiasing = 8; - else if(list.at(0) == "MSAA 4") antialiasing = 4; - else if(list.at(0) == "MSAA 2") antialiasing = 2; - } - if(aa != antialiasing) - updateOgreWindow(); - } - } } diff --git a/apps/opencs/view/render/scenewidget.hpp b/apps/opencs/view/render/scenewidget.hpp index c57038869..0cdf1ef99 100644 --- a/apps/opencs/view/render/scenewidget.hpp +++ b/apps/opencs/view/render/scenewidget.hpp @@ -2,21 +2,13 @@ #define OPENCS_VIEW_SCENEWIDGET_H #include - -#include +#include #include "lightingday.hpp" #include "lightingnight.hpp" #include "lightingbright.hpp" -namespace Ogre -{ - class Camera; - class SceneManager; - class RenderWindow; - class Viewport; - class RenderTargetListener; -} +#include namespace CSVWidget { @@ -29,110 +21,22 @@ namespace CSVRender class Navigation; class Lighting; - class SceneWidget : public QWidget + class SceneWidget : public QWidget, public osgViewer::Viewer { Q_OBJECT - public: - - SceneWidget(QWidget *parent); - virtual ~SceneWidget(); - - QPaintEngine* paintEngine() const; - - CSVWidget::SceneToolMode *makeLightingSelector (CSVWidget::SceneToolbar *parent); - ///< \attention The created tool is not added to the toolbar (via addTool). Doing that - /// is the responsibility of the calling function. - - virtual void setVisibilityMask (unsigned int mask); - - virtual void updateScene(); - - protected: - - void setNavigation (Navigation *navigation); - ///< \attention The ownership of \a navigation is not transferred to *this. - - void addRenderTargetListener(Ogre::RenderTargetListener *listener); - - void removeRenderTargetListener(Ogre::RenderTargetListener *listener); - - Ogre::Viewport *getViewport(); - - Ogre::SceneManager *getSceneManager(); - - Ogre::Camera *getCamera(); - - void flagAsModified(); - - void setDefaultAmbient (const Ogre::ColourValue& colour); - ///< \note The actual ambient colour may differ based on lighting settings. + public: + SceneWidget(QWidget* parent = 0, Qt::WindowFlags f = 0); - virtual void updateOverlay(); + virtual void paintEvent( QPaintEvent* event ); - virtual void mouseReleaseEvent (QMouseEvent *event); + void flagAsModified(); - virtual void mouseMoveEvent (QMouseEvent *event); + protected: - void wheelEvent (QWheelEvent *event); - - void keyPressEvent (QKeyEvent *event); - - private: - void paintEvent(QPaintEvent* e); - void resizeEvent(QResizeEvent* e); - bool event(QEvent* e); - - void keyReleaseEvent (QKeyEvent *event); - - void focusOutEvent (QFocusEvent *event); - - void leaveEvent (QEvent *event); - - void updateOgreWindow(); - - void setLighting (Lighting *lighting); - ///< \attention The ownership of \a lighting is not transferred to *this. - - Ogre::Camera* mCamera; - Ogre::SceneManager* mSceneMgr; - Ogre::RenderWindow* mWindow; - Ogre::Viewport *mViewport; - - Navigation *mNavigation; - Lighting *mLighting; - bool mUpdate; - bool mKeyForward; - bool mKeyBackward; - bool mKeyLeft; - bool mKeyRight; - bool mKeyRollLeft; - bool mKeyRollRight; - bool mFast; - bool mDragging; - bool mMod1; - QPoint mOldPos; - int mFastFactor; - Ogre::ColourValue mDefaultAmbient; - bool mHasDefaultAmbient; - LightingDay mLightingDay; - LightingNight mLightingNight; - LightingBright mLightingBright; - - public slots: - - void updateUserSetting (const QString &key, const QStringList &list); - - private slots: - - void update(); - - void selectLightingMode (const std::string& mode); - - signals: - - void focusToolbarRequest(); + QTimer mTimer; }; + } #endif diff --git a/apps/opencs/view/render/unpagedworldspacewidget.cpp b/apps/opencs/view/render/unpagedworldspacewidget.cpp index 462b62b7a..a269fab45 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.cpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.cpp @@ -26,11 +26,11 @@ void CSVRender::UnpagedWorldspaceWidget::update() Ogre::ColourValue colour; colour.setAsABGR (record.get().mAmbi.mAmbient); - setDefaultAmbient (colour); + //setDefaultAmbient (colour); /// \todo deal with mSunlight and mFog/mForDensity - flagAsModified(); + //flagAsModified(); } CSVRender::UnpagedWorldspaceWidget::UnpagedWorldspaceWidget (const std::string& cellId, CSMDoc::Document& document, QWidget* parent) @@ -49,7 +49,7 @@ CSVRender::UnpagedWorldspaceWidget::UnpagedWorldspaceWidget (const std::string& update(); - mCell.reset (new Cell (document.getData(), getSceneManager(), mCellId, document.getPhysics())); + //mCell.reset (new Cell (document.getData(), getSceneManager(), mCellId, document.getPhysics())); } void CSVRender::UnpagedWorldspaceWidget::cellDataChanged (const QModelIndex& topLeft, @@ -91,7 +91,7 @@ bool CSVRender::UnpagedWorldspaceWidget::handleDrop (const std::vectorgetId(); - mCell.reset (new Cell (getDocument().getData(), getSceneManager(), mCellId, getDocument().getPhysics())); + //mCell.reset (new Cell (getDocument().getData(), getSceneManager(), mCellId, getDocument().getPhysics())); update(); emit cellChanged(*data.begin()); @@ -163,6 +163,7 @@ void CSVRender::UnpagedWorldspaceWidget::addVisibilitySelectorButtons ( std::string CSVRender::UnpagedWorldspaceWidget::getStartupInstruction() { + /* Ogre::Vector3 position = getCamera()->getPosition(); std::ostringstream stream; @@ -173,6 +174,8 @@ std::string CSVRender::UnpagedWorldspaceWidget::getStartupInstruction() << ", 0, \"" << mCellId << "\""; return stream.str(); + */ + return ""; } CSVRender::WorldspaceWidget::dropRequirments CSVRender::UnpagedWorldspaceWidget::getDropRequirements (CSVRender::WorldspaceWidget::DropType type) const diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 582ccea64..5ae5c8177 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -56,31 +56,33 @@ CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidg this, SLOT (debugProfileAboutToBeRemoved (const QModelIndex&, int, int))); mPhysics = document.getPhysics(); // create physics if one doesn't exist - mPhysics->addSceneManager(getSceneManager(), this); + //mPhysics->addSceneManager(getSceneManager(), this); mMouse = new MouseState(this); } CSVRender::WorldspaceWidget::~WorldspaceWidget () { delete mMouse; - mPhysics->removeSceneManager(getSceneManager()); + //mPhysics->removeSceneManager(getSceneManager()); } void CSVRender::WorldspaceWidget::selectNavigationMode (const std::string& mode) { + /* if (mode=="1st") setNavigation (&m1st); else if (mode=="free") setNavigation (&mFree); else if (mode=="orbit") setNavigation (&mOrbit); + */ } void CSVRender::WorldspaceWidget::useViewHint (const std::string& hint) {} void CSVRender::WorldspaceWidget::selectDefaultNavigationMode() { - setNavigation (&m1st); + //setNavigation (&m1st); } CSVWidget::SceneToolMode *CSVRender::WorldspaceWidget::makeNavigationSelector ( @@ -355,7 +357,7 @@ void CSVRender::WorldspaceWidget::debugProfileAboutToBeRemoved (const QModelInde void CSVRender::WorldspaceWidget::elementSelectionChanged() { - setVisibilityMask (getVisibilityMask()); + //setVisibilityMask (getVisibilityMask()); flagAsModified(); updateOverlay(); } @@ -386,11 +388,13 @@ void CSVRender::WorldspaceWidget::mouseReleaseEvent (QMouseEvent *event) { if(event->button() == Qt::RightButton) { + /* if(!getViewport()) { SceneWidget::mouseReleaseEvent(event); return; } + */ mMouse->mouseReleaseEvent(event); } SceneWidget::mouseReleaseEvent(event); diff --git a/apps/opencs/view/world/previewsubview.cpp b/apps/opencs/view/world/previewsubview.cpp index 1ae466f42..0c9823c44 100644 --- a/apps/opencs/view/world/previewsubview.cpp +++ b/apps/opencs/view/world/previewsubview.cpp @@ -30,8 +30,8 @@ CSVWorld::PreviewSubView::PreviewSubView (const CSMWorld::UniversalId& id, CSMDo CSVWidget::SceneToolbar *toolbar = new CSVWidget::SceneToolbar (48+6, this); - CSVWidget::SceneToolMode *lightingTool = mScene->makeLightingSelector (toolbar); - toolbar->addTool (lightingTool); + //CSVWidget::SceneToolMode *lightingTool = mScene->makeLightingSelector (toolbar); + //toolbar->addTool (lightingTool); layout->addWidget (toolbar, 0); @@ -67,4 +67,4 @@ void CSVWorld::PreviewSubView::referenceableIdChanged (const std::string& id) setWindowTitle (QString::fromUtf8 (mTitle.c_str())); emit updateTitle(); -} \ No newline at end of file +} diff --git a/apps/opencs/view/world/scenesubview.cpp b/apps/opencs/view/world/scenesubview.cpp index 3fdf2f6e5..c59236ee5 100644 --- a/apps/opencs/view/world/scenesubview.cpp +++ b/apps/opencs/view/world/scenesubview.cpp @@ -107,8 +107,8 @@ CSVWidget::SceneToolbar* CSVWorld::SceneSubView::makeToolbar (CSVRender::Worldsp CSVWidget::SceneToolMode *navigationTool = widget->makeNavigationSelector (toolbar); toolbar->addTool (navigationTool); - CSVWidget::SceneToolMode *lightingTool = widget->makeLightingSelector (toolbar); - toolbar->addTool (lightingTool); + //CSVWidget::SceneToolMode *lightingTool = widget->makeLightingSelector (toolbar); + //toolbar->addTool (lightingTool); CSVWidget::SceneToolToggle2 *sceneVisibilityTool = widget->makeSceneVisibilitySelector (toolbar); From af27a10b0cc541cfc16d465ff12d0f164edfa04b Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 20 Mar 2015 00:39:24 +0100 Subject: [PATCH 0784/3725] OpenCS: preliminary port of PreviewWidget to OSG --- apps/opencs/model/doc/document.cpp | 9 +++- apps/opencs/model/doc/document.hpp | 11 +++- apps/opencs/model/doc/documentmanager.cpp | 5 +- apps/opencs/model/doc/documentmanager.hpp | 2 +- apps/opencs/view/render/cell.cpp | 6 +-- apps/opencs/view/render/object.cpp | 65 +++++++++-------------- apps/opencs/view/render/object.hpp | 24 +++++---- apps/opencs/view/render/previewwidget.cpp | 12 +---- apps/opencs/view/render/previewwidget.hpp | 9 +++- apps/opencs/view/render/scenewidget.cpp | 15 ++++-- apps/opencs/view/render/scenewidget.hpp | 7 +++ apps/opencs/view/world/previewsubview.cpp | 4 +- components/nifosg/nifloader.hpp | 2 +- 13 files changed, 92 insertions(+), 79 deletions(-) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index e688a9474..2a5fa7746 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -2245,12 +2245,12 @@ void CSMDoc::Document::createBase() } } -CSMDoc::Document::Document (const Files::ConfigurationManager& configuration, +CSMDoc::Document::Document (const VFS::Manager* vfs, const Files::ConfigurationManager& configuration, const std::vector< boost::filesystem::path >& files, bool new_, const boost::filesystem::path& savePath, const boost::filesystem::path& resDir, ToUTF8::FromType encoding, const CSMWorld::ResourcesManager& resourcesManager, const std::vector& blacklistedScripts) -: mSavePath (savePath), mContentFiles (files), mNew (new_), mData (encoding, resourcesManager), +: mVFS(vfs), mSavePath (savePath), mContentFiles (files), mNew (new_), mData (encoding, resourcesManager), mTools (*this), mResDir(resDir), mProjectPath ((configuration.getUserDataPath() / "projects") / (savePath.filename().string() + ".project")), @@ -2311,6 +2311,11 @@ CSMDoc::Document::~Document() { } +const VFS::Manager *CSMDoc::Document::getVFS() const +{ + return mVFS; +} + QUndoStack& CSMDoc::Document::getUndoStack() { return mUndoStack; diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp index f3aef6db6..2d42e9903 100644 --- a/apps/opencs/model/doc/document.hpp +++ b/apps/opencs/model/doc/document.hpp @@ -23,6 +23,12 @@ class QAbstractItemModel; +namespace VFS +{ + + class Manager; +} + namespace ESM { struct GameSetting; @@ -53,6 +59,7 @@ namespace CSMDoc private: + const VFS::Manager* mVFS; boost::filesystem::path mSavePath; std::vector mContentFiles; bool mNew; @@ -91,7 +98,7 @@ namespace CSMDoc public: - Document (const Files::ConfigurationManager& configuration, + Document (const VFS::Manager* vfs, const Files::ConfigurationManager& configuration, const std::vector< boost::filesystem::path >& files, bool new_, const boost::filesystem::path& savePath, const boost::filesystem::path& resDir, ToUTF8::FromType encoding, const CSMWorld::ResourcesManager& resourcesManager, @@ -99,6 +106,8 @@ namespace CSMDoc ~Document(); + const VFS::Manager* getVFS() const; + QUndoStack& getUndoStack(); int getState() const; diff --git a/apps/opencs/model/doc/documentmanager.cpp b/apps/opencs/model/doc/documentmanager.cpp index ecff4bbed..edce6e613 100644 --- a/apps/opencs/model/doc/documentmanager.cpp +++ b/apps/opencs/model/doc/documentmanager.cpp @@ -13,7 +13,7 @@ #include "document.hpp" CSMDoc::DocumentManager::DocumentManager (const Files::ConfigurationManager& configuration) -: mConfiguration (configuration), mEncoding (ToUTF8::WINDOWS_1252) +: mConfiguration (configuration), mEncoding (ToUTF8::WINDOWS_1252), mVFS(NULL) { boost::filesystem::path projectPath = configuration.getUserDataPath() / "projects"; @@ -52,7 +52,7 @@ CSMDoc::DocumentManager::~DocumentManager() void CSMDoc::DocumentManager::addDocument (const std::vector& files, const boost::filesystem::path& savePath, bool new_) { - Document *document = new Document (mConfiguration, files, new_, savePath, mResDir, mEncoding, mResourcesManager, mBlacklistedScripts); + Document *document = new Document (mVFS, mConfiguration, files, new_, savePath, mResDir, mEncoding, mResourcesManager, mBlacklistedScripts); mDocuments.push_back (document); @@ -107,4 +107,5 @@ void CSMDoc::DocumentManager::documentNotLoaded (Document *document, const std:: void CSMDoc::DocumentManager::setVFS(const VFS::Manager *vfs) { mResourcesManager.setVFS(vfs); + mVFS = vfs; } diff --git a/apps/opencs/model/doc/documentmanager.hpp b/apps/opencs/model/doc/documentmanager.hpp index a12d22c4e..8dc4f338a 100644 --- a/apps/opencs/model/doc/documentmanager.hpp +++ b/apps/opencs/model/doc/documentmanager.hpp @@ -40,7 +40,7 @@ namespace CSMDoc ToUTF8::FromType mEncoding; CSMWorld::ResourcesManager mResourcesManager; std::vector mBlacklistedScripts; - VFS::Manager* mVFS; + const VFS::Manager* mVFS; DocumentManager (const DocumentManager&); DocumentManager& operator= (const DocumentManager&); diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index a0d0f6e71..72ceb654a 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -51,7 +51,7 @@ bool CSVRender::Cell::addObjects (int start, int end) std::string id = Misc::StringUtils::lowerCase (references.data ( references.index (i, idColumn)).toString().toUtf8().constData()); - mObjects.insert (std::make_pair (id, new Object (mData, mCellNode, id, false, mPhysics))); + //mObjects.insert (std::make_pair (id, new Object (mData, mCellNode, id, false, mPhysics))); modified = true; } } @@ -191,8 +191,8 @@ bool CSVRender::Cell::referenceDataChanged (const QModelIndex& topLeft, // add new objects for (std::map::iterator iter (ids.begin()); iter!=ids.end(); ++iter) { - mObjects.insert (std::make_pair ( - iter->first, new Object (mData, mCellNode, iter->first, false, mPhysics))); + //mObjects.insert (std::make_pair ( + // iter->first, new Object (mData, mCellNode, iter->first, false, mPhysics))); modified = true; } diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index b54551c96..2434343c9 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -1,9 +1,6 @@ - #include "object.hpp" -#include -#include -#include +#include #include "../../model/world/data.hpp" #include "../../model/world/ref.hpp" @@ -11,43 +8,20 @@ #include "../world/physicssystem.hpp" -#include "elements.hpp" +#include -void CSVRender::Object::clearSceneNode (Ogre::SceneNode *node) -{ - for (Ogre::SceneNode::ObjectIterator iter = node->getAttachedObjectIterator(); - iter.hasMoreElements(); ) - { - Ogre::MovableObject* object = dynamic_cast (iter.getNext()); - node->getCreator()->destroyMovableObject (object); - } - - for (Ogre::SceneNode::ChildNodeIterator iter = node->getChildIterator(); - iter.hasMoreElements(); ) - { - Ogre::SceneNode* childNode = dynamic_cast (iter.getNext()); - clearSceneNode (childNode); - node->getCreator()->destroySceneNode (childNode); - } -} +#include "elements.hpp" void CSVRender::Object::clear() { - mObject.setNull(); - - if (mBase) - clearSceneNode (mBase); } void CSVRender::Object::update() { - if(!mObject.isNull()) - mPhysics->removePhysicsObject(mBase->getName()); - clear(); std::string model; - int error = 0; // 1 referemceanöe does not exist, 2 referenceable does not specify a mesh + int error = 0; // 1 referenceable does not exist, 2 referenceable does not specify a mesh const CSMWorld::RefIdCollection& referenceables = mData.getReferenceables(); @@ -69,17 +43,28 @@ void CSVRender::Object::update() if (error) { + /* Ogre::Entity* entity = mBase->getCreator()->createEntity (Ogre::SceneManager::PT_CUBE); entity->setMaterialName("BaseWhite"); /// \todo adjust material according to error entity->setVisibilityFlags (Element_Reference); mBase->attachObject (entity); + */ } else { - //mObject = NifOgre::Loader::createObjects (mBase, "Meshes\\" + model); + NifOsg::Loader loader; + loader.resourceManager = mVFS; + + std::string path = "meshes\\" + model; + + Nif::NIFFilePtr file(new Nif::NIFFile(mVFS->get(path), path)); + + loader.load(file, mBaseNode); + //mObject->setVisibilityFlags (Element_Reference); + /* if (mPhysics && !mReferenceId.empty()) { const CSMWorld::CellRef& reference = getReference(); @@ -96,11 +81,13 @@ void CSVRender::Object::update() mPhysics->addObject("meshes\\" + model, mBase->getName(), mReferenceId, reference.mScale, position, xr*yr*zr); } + */ } } void CSVRender::Object::adjust() { + /* if (mReferenceId.empty()) return; @@ -122,6 +109,7 @@ void CSVRender::Object::adjust() // scale mBase->setScale (reference.mScale, reference.mScale, reference.mScale); + */ } const CSMWorld::CellRef& CSVRender::Object::getReference() const @@ -132,12 +120,13 @@ const CSMWorld::CellRef& CSVRender::Object::getReference() const return mData.getReferences().getRecord (mReferenceId).get(); } -CSVRender::Object::Object (const CSMWorld::Data& data, Ogre::SceneNode *cellNode, +CSVRender::Object::Object (const VFS::Manager* vfs, const CSMWorld::Data& data, osg::Group* parentNode, const std::string& id, bool referenceable, boost::shared_ptr physics, bool forceBaseToZero) -: mData (data), mBase (0), mForceBaseToZero (forceBaseToZero), mPhysics(physics) +: mVFS(vfs), mData (data), mBaseNode(0), mParentNode(parentNode), mForceBaseToZero (forceBaseToZero), mPhysics(physics) { - mBase = cellNode->createChildSceneNode(); + mBaseNode = new osg::Group; + parentNode->addChild(mBaseNode); if (referenceable) { @@ -157,13 +146,7 @@ CSVRender::Object::~Object() { clear(); - if (mBase) - { - if(mPhysics) // preview may not have physics enabled - mPhysics->removeObject(mBase->getName()); - - mBase->getCreator()->destroySceneNode (mBase); - } + mParentNode->removeChild(mBaseNode); } bool CSVRender::Object::referenceableDataChanged (const QModelIndex& topLeft, diff --git a/apps/opencs/view/render/object.hpp b/apps/opencs/view/render/object.hpp index 3ed4fa793..8e9598bbf 100644 --- a/apps/opencs/view/render/object.hpp +++ b/apps/opencs/view/render/object.hpp @@ -3,15 +3,19 @@ #include -#ifndef Q_MOC_RUN -#include -#endif +#include class QModelIndex; -namespace Ogre + +namespace osg +{ + class Group; +} + +namespace VFS { - class SceneNode; + class Manager; } namespace CSMWorld @@ -32,8 +36,9 @@ namespace CSVRender const CSMWorld::Data& mData; std::string mReferenceId; std::string mReferenceableId; - Ogre::SceneNode *mBase; - NifOgre::ObjectScenePtr mObject; + osg::ref_ptr mBaseNode; + osg::Group* mParentNode; + const VFS::Manager* mVFS; bool mForceBaseToZero; boost::shared_ptr mPhysics; @@ -43,9 +48,6 @@ namespace CSVRender /// Not implemented Object& operator= (const Object&); - /// Destroy all scene nodes and movable objects attached to node. - static void clearSceneNode (Ogre::SceneNode *node); - /// Remove object from node (includes deleting) void clear(); @@ -60,7 +62,7 @@ namespace CSVRender public: - Object (const CSMWorld::Data& data, Ogre::SceneNode *cellNode, + Object (const VFS::Manager* vfs, const CSMWorld::Data& data, osg::Group *cellNode, const std::string& id, bool referenceable, boost::shared_ptr physics = boost::shared_ptr (), bool forceBaseToZero = false); diff --git a/apps/opencs/view/render/previewwidget.cpp b/apps/opencs/view/render/previewwidget.cpp index 6982cad52..ee43ac13c 100644 --- a/apps/opencs/view/render/previewwidget.cpp +++ b/apps/opencs/view/render/previewwidget.cpp @@ -7,9 +7,9 @@ #include "../../model/world/data.hpp" #include "../../model/world/idtable.hpp" -CSVRender::PreviewWidget::PreviewWidget (CSMWorld::Data& data, +CSVRender::PreviewWidget::PreviewWidget (const VFS::Manager* vfs, CSMWorld::Data& data, const std::string& id, bool referenceable, QWidget *parent) -: SceneWidget (parent), mData (data) +: SceneWidget (parent), mData (data), mObject(vfs, data, mRootNode, id, referenceable) { //setNavigation (&mOrbit); @@ -36,7 +36,6 @@ CSVRender::PreviewWidget::PreviewWidget (CSMWorld::Data& data, void CSVRender::PreviewWidget::referenceableDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) { -#if 0 if (mObject.referenceableDataChanged (topLeft, bottomRight)) flagAsModified(); @@ -51,13 +50,11 @@ void CSVRender::PreviewWidget::referenceableDataChanged (const QModelIndex& topL if (referenceables.data (index).toInt()==CSMWorld::RecordBase::State_Deleted) emit closeRequest(); } -#endif } void CSVRender::PreviewWidget::referenceableAboutToBeRemoved (const QModelIndex& parent, int start, int end) { -#if 0 if (mObject.referenceableAboutToBeRemoved (parent, start, end)) flagAsModified(); @@ -77,13 +74,11 @@ void CSVRender::PreviewWidget::referenceableAboutToBeRemoved (const QModelIndex& emit closeRequest(); } } -#endif } void CSVRender::PreviewWidget::referenceDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) { -#if 0 if (mObject.referenceDataChanged (topLeft, bottomRight)) flagAsModified(); @@ -112,13 +107,11 @@ void CSVRender::PreviewWidget::referenceDataChanged (const QModelIndex& topLeft, if (index.row()>=topLeft.row() && index.row()<=bottomRight.row()) if (index.column()>=topLeft.column() && index.column()<=bottomRight.row()) emit referenceableIdChanged (mObject.getReferenceableId()); -#endif } void CSVRender::PreviewWidget::referenceAboutToBeRemoved (const QModelIndex& parent, int start, int end) { -#if 0 if (mObject.getReferenceId().empty()) return; @@ -129,5 +122,4 @@ void CSVRender::PreviewWidget::referenceAboutToBeRemoved (const QModelIndex& par if (index.row()>=start && index.row()<=end) emit closeRequest(); -#endif } diff --git a/apps/opencs/view/render/previewwidget.hpp b/apps/opencs/view/render/previewwidget.hpp index 7260ee242..dfe05b484 100644 --- a/apps/opencs/view/render/previewwidget.hpp +++ b/apps/opencs/view/render/previewwidget.hpp @@ -8,6 +8,11 @@ class QModelIndex; +namespace VFS +{ + class Manager; +} + namespace CSMWorld { class Data; @@ -21,11 +26,11 @@ namespace CSVRender CSMWorld::Data& mData; CSVRender::NavigationOrbit mOrbit; - //Object mObject; + CSVRender::Object mObject; public: - PreviewWidget (CSMWorld::Data& data, const std::string& id, bool referenceable, + PreviewWidget (const VFS::Manager* vfs, CSMWorld::Data& data, const std::string& id, bool referenceable, QWidget *parent = 0); signals: diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index 82dc4c211..2f28c06df 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -16,12 +16,14 @@ #include #include +#include namespace CSVRender { SceneWidget::SceneWidget(QWidget *parent, Qt::WindowFlags f) : QWidget(parent, f) + , mRootNode(0) { #if QT_VERSION >= 0x050000 @@ -37,6 +39,7 @@ SceneWidget::SceneWidget(QWidget *parent, Qt::WindowFlags f) setKeyEventSetsDone(0); osg::DisplaySettings* ds = osg::DisplaySettings::instance().get(); + //ds->setNumMultiSamples(8); osg::ref_ptr traits = new osg::GraphicsContext::Traits; traits->windowName = ""; traits->windowDecoration = true; @@ -49,6 +52,8 @@ SceneWidget::SceneWidget(QWidget *parent, Qt::WindowFlags f) traits->stencil = ds->getMinimumNumStencilBits(); traits->sampleBuffers = ds->getMultiSamples(); traits->samples = ds->getNumMultiSamples(); + // Doesn't make much sense as we're running on demand updates, and there seems to be a bug with the refresh rate when running multiple QGLWidgets + traits->vsync = false; osgQt::GraphicsWindowQt* window = new osgQt::GraphicsWindowQt(traits.get()); QLayout* layout = new QHBoxLayout(this); @@ -59,15 +64,19 @@ SceneWidget::SceneWidget(QWidget *parent, Qt::WindowFlags f) getCamera()->setClearColor( osg::Vec4(0.2, 0.2, 0.6, 1.0) ); getCamera()->setViewport( new osg::Viewport(0, 0, traits->width, traits->height) ); - //getCamera()->setProjectionMatrixAsPerspective(30.0f, static_cast(traits->width)/static_cast(traits->height), 1.0f, 10000.0f ); + getCamera()->setProjectionMatrixAsPerspective(30.0f, static_cast(traits->width)/static_cast(traits->height), 1.0f, 10000.0f ); - osg::Node* root = new osg::Node; - setSceneData(root); + mRootNode = new osg::Group; + setSceneData(mRootNode); + + // Press S to reveal profiling stats + addEventHandler(new osgViewer::StatsHandler); setCameraManipulator(new osgGA::TrackballManipulator); // Only render when the camera position changed, or content flagged dirty //setRunFrameScheme(osgViewer::ViewerBase::ON_DEMAND); + setRunFrameScheme(osgViewer::ViewerBase::CONTINUOUS); connect( &mTimer, SIGNAL(timeout()), this, SLOT(update()) ); mTimer.start( 10 ); diff --git a/apps/opencs/view/render/scenewidget.hpp b/apps/opencs/view/render/scenewidget.hpp index 0cdf1ef99..3784a5c59 100644 --- a/apps/opencs/view/render/scenewidget.hpp +++ b/apps/opencs/view/render/scenewidget.hpp @@ -10,6 +10,11 @@ #include +namespace osg +{ + class Group; +} + namespace CSVWidget { class SceneToolMode; @@ -34,6 +39,8 @@ namespace CSVRender protected: + osg::Group* mRootNode; + QTimer mTimer; }; diff --git a/apps/opencs/view/world/previewsubview.cpp b/apps/opencs/view/world/previewsubview.cpp index 0c9823c44..c82d1b82e 100644 --- a/apps/opencs/view/world/previewsubview.cpp +++ b/apps/opencs/view/world/previewsubview.cpp @@ -23,10 +23,10 @@ CSVWorld::PreviewSubView::PreviewSubView (const CSMWorld::UniversalId& id, CSMDo referenceableIdChanged (referenceableId); mScene = - new CSVRender::PreviewWidget (document.getData(), id.getId(), false, this); + new CSVRender::PreviewWidget (document.getVFS(), document.getData(), id.getId(), false, this); } else - mScene = new CSVRender::PreviewWidget (document.getData(), id.getId(), true, this); + mScene = new CSVRender::PreviewWidget (document.getVFS(), document.getData(), id.getId(), true, this); CSVWidget::SceneToolbar *toolbar = new CSVWidget::SceneToolbar (48+6, this); diff --git a/components/nifosg/nifloader.hpp b/components/nifosg/nifloader.hpp index 5a0c901c1..7b38ce560 100644 --- a/components/nifosg/nifloader.hpp +++ b/components/nifosg/nifloader.hpp @@ -39,7 +39,7 @@ namespace NifOsg void loadAsSkeleton(Nif::NIFFilePtr file, osg::Group* parentNode); - VFS::Manager* resourceManager; + const VFS::Manager* resourceManager; // FIXME move std::vector mControllers; From 4957ceeb1d25bf359c341bcd551a2f536a8d7418 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 20 Mar 2015 19:51:54 +0100 Subject: [PATCH 0785/3725] Refactor controllers, now part of the scene graph as UpdateCallbacks Practical benefits: - The controller update is now run automatically - Creating an instance of a scene graph should now work properly using the defined copy constructors --- apps/nifosgtest/test.cpp | 9 +- .../view/render/unpagedworldspacewidget.cpp | 2 +- components/nifosg/controller.cpp | 391 ++++++++++++------ components/nifosg/controller.hpp | 144 ++++--- components/nifosg/nifloader.cpp | 103 +++-- components/nifosg/nifloader.hpp | 18 +- components/nifosg/particle.cpp | 1 + 7 files changed, 415 insertions(+), 253 deletions(-) diff --git a/apps/nifosgtest/test.cpp b/apps/nifosgtest/test.cpp index 7f9a7ce3f..fee919787 100644 --- a/apps/nifosgtest/test.cpp +++ b/apps/nifosgtest/test.cpp @@ -112,15 +112,11 @@ int main(int argc, char** argv) //osgDB::writeNodeFile(*newNode, "out.osg"); - std::vector controllers; osg::Group* newNode = new osg::Group; NifOsg::Loader loader; loader.resourceManager = &resourceMgr; loader.loadAsSkeleton(nif, newNode); - for (unsigned int i=0; iaddChild(trans); @@ -137,6 +133,8 @@ int main(int argc, char** argv) viewer.setCameraManipulator(new osgGA::TrackballManipulator()); viewer.addEventHandler(new WireframeKeyHandler(root)); + //viewer.getCamera()->setCullMask() + // We're going to change this from the event callback, set the variance to DYNAMIC so that // we don't interfere with the draw thread. root->getOrCreateStateSet()->setDataVariance(osg::Node::DYNAMIC); @@ -148,9 +146,6 @@ int main(int argc, char** argv) //trans->setAttitude(osg::Quat(viewer.getFrameStamp()->getSimulationTime()*5, osg::Vec3f(0,0,1))); viewer.frame(); - - for (unsigned int i=0; igetFrameStamp()->getReferenceTime(); + float dt = static_cast(time - mLastTime); + mLastTime = time; + return dt; +} + +KeyframeController::KeyframeController() +{ +} + +KeyframeController::KeyframeController(const KeyframeController ©, const osg::CopyOp ©op) + : osg::NodeCallback(copy, copyop) + , Controller(copy) + , mRotations(copy.mRotations) + , mXRotations(copy.mXRotations) + , mYRotations(copy.mYRotations) + , mZRotations(copy.mZRotations) + , mTranslations(copy.mTranslations) + , mScales(copy.mScales) + , mNif(copy.mNif) + , mInitialQuat(copy.mInitialQuat) + , mInitialScale(copy.mInitialScale) +{ +} + +KeyframeController::KeyframeController(const Nif::NIFFilePtr &nif, const Nif::NiKeyframeData *data, + osg::Quat initialQuat, float initialScale) + : mRotations(&data->mRotations) + , mXRotations(&data->mXRotations) + , mYRotations(&data->mYRotations) + , mZRotations(&data->mZRotations) + , mTranslations(&data->mTranslations) + , mScales(&data->mScales) + , mNif(nif) + , mInitialQuat(initialQuat) + , mInitialScale(initialScale) +{ } + +osg::Quat KeyframeController::interpKey(const Nif::QuaternionKeyMap::MapType &keys, float time) { if(time <= keys.begin()->first) return keys.begin()->second.mValue; @@ -81,7 +127,7 @@ osg::Quat KeyframeControllerValue::interpKey(const Nif::QuaternionKeyMap::MapTyp return keys.rbegin()->second.mValue; } -osg::Quat KeyframeControllerValue::getXYZRotation(float time) const +osg::Quat KeyframeController::getXYZRotation(float time) const { float xrot = interpKey(mXRotations->mKeys, time); float yrot = interpKey(mYRotations->mKeys, time); @@ -92,96 +138,108 @@ osg::Quat KeyframeControllerValue::getXYZRotation(float time) const return (zr*yr*xr); } -KeyframeControllerValue::KeyframeControllerValue(osg::Node *target, const Nif::NIFFilePtr &nif, const Nif::NiKeyframeData *data, - osg::Quat initialQuat, float initialScale) - : NodeTargetValue(target) - , mRotations(&data->mRotations) - , mXRotations(&data->mXRotations) - , mYRotations(&data->mYRotations) - , mZRotations(&data->mZRotations) - , mTranslations(&data->mTranslations) - , mScales(&data->mScales) - , mNif(nif) - , mInitialQuat(initialQuat) - , mInitialScale(initialScale) -{ } - -osg::Vec3f KeyframeControllerValue::getTranslation(float time) const +osg::Vec3f KeyframeController::getTranslation(float time) const { if(mTranslations->mKeys.size() > 0) return interpKey(mTranslations->mKeys, time); - osg::MatrixTransform* trans = static_cast(mNode); - return trans->getMatrix().getTrans(); + return osg::Vec3f(); } -void KeyframeControllerValue::setValue(float time) +void KeyframeController::operator() (osg::Node* node, osg::NodeVisitor* nv) { - osg::MatrixTransform* trans = static_cast(mNode); - osg::Matrix mat = trans->getMatrix(); - - if(mRotations->mKeys.size() > 0) - mat.setRotate(interpKey(mRotations->mKeys, time)); - else if (!mXRotations->mKeys.empty() || !mYRotations->mKeys.empty() || !mZRotations->mKeys.empty()) - mat.setRotate(getXYZRotation(time)); - else - mat.setRotate(mInitialQuat); - - // let's hope no one's using multiple KeyframeControllers on the same node (not that would make any sense...) - float scale = mInitialScale; - if(mScales->mKeys.size() > 0) - scale = interpKey(mScales->mKeys, time); + if (hasInput()) + { + osg::MatrixTransform* trans = static_cast(node); + osg::Matrix mat = trans->getMatrix(); + + float time = getInputValue(nv); + + if(mRotations->mKeys.size() > 0) + mat.setRotate(interpKey(mRotations->mKeys, time)); + else if (!mXRotations->mKeys.empty() || !mYRotations->mKeys.empty() || !mZRotations->mKeys.empty()) + mat.setRotate(getXYZRotation(time)); + else + mat.setRotate(mInitialQuat); + + // let's hope no one's using multiple KeyframeControllers on the same node (not that would make any sense...) + float scale = mInitialScale; + if(mScales->mKeys.size() > 0) + scale = interpKey(mScales->mKeys, time); + + for (int i=0;i<3;++i) + for (int j=0;j<3;++j) + mat(i,j) *= scale; + + if(mTranslations->mKeys.size() > 0) + mat.setTrans(interpKey(mTranslations->mKeys, time)); + trans->setMatrix(mat); + } - for (int i=0;i<3;++i) - for (int j=0;j<3;++j) - mat(i,j) *= scale; + traverse(node, nv); +} - if(mTranslations->mKeys.size() > 0) - mat.setTrans(interpKey(mTranslations->mKeys, time)); - trans->setMatrix(mat); +Controller::Controller() +{ } -Controller::Controller(boost::shared_ptr src, boost::shared_ptr dest, boost::shared_ptr function) - : mSource(src) - , mDestValue(dest) - , mFunction(function) +bool Controller::hasInput() const { + return mSource.get() != NULL; +} +float Controller::getInputValue(osg::NodeVisitor* nv) +{ + return mFunction->calculate(mSource->getValue(nv)); } -void Controller::update() +GeomMorpherController::GeomMorpherController() { - if (mSource.get()) - { - mDestValue->setValue(mFunction->calculate(mSource->getValue())); - } } -GeomMorpherControllerValue::GeomMorpherControllerValue(osgAnimation::MorphGeometry *geom, const Nif::NiMorphData* morphData) - : mGeom(geom) - , mMorphs(morphData->mMorphs) +GeomMorpherController::GeomMorpherController(const GeomMorpherController ©, const osg::CopyOp ©op) + : osg::Drawable::UpdateCallback(copy, copyop) + , Controller(copy) + , mMorphs(copy.mMorphs) { +} +GeomMorpherController::GeomMorpherController(const Nif::NiMorphData *data) + : mMorphs(data->mMorphs) +{ } -void GeomMorpherControllerValue::setValue(float time) +void GeomMorpherController::update(osg::NodeVisitor *nv, osg::Drawable *drawable) { - if (mMorphs.size() <= 1) - return; - int i = 0; - for (std::vector::iterator it = mMorphs.begin()+1; it != mMorphs.end(); ++it,++i) + osgAnimation::MorphGeometry* morphGeom = dynamic_cast(drawable); + if (morphGeom) { - float val = 0; - if (!it->mData.mKeys.empty()) - val = interpKey(it->mData.mKeys, time); - val = std::max(0.f, std::min(1.f, val)); - - mGeom->setWeight(i, val); + if (hasInput()) + { + if (mMorphs.size() <= 1) + return; + float input = getInputValue(nv); + int i = 0; + for (std::vector::iterator it = mMorphs.begin()+1; it != mMorphs.end(); ++it,++i) + { + float val = 0; + if (!it->mData.mKeys.empty()) + val = interpKey(it->mData.mKeys, input); + val = std::max(0.f, std::min(1.f, val)); + + morphGeom->setWeight(i, val); + } + } + + morphGeom->transformSoftwareMethod(); } } -UVControllerValue::UVControllerValue(osg::StateSet *target, const Nif::NiUVData *data, std::set textureUnits) - : mStateSet(target) - , mUTrans(data->mKeyList[0]) +UVController::UVController() +{ +} + +UVController::UVController(const Nif::NiUVData *data, std::set textureUnits) + : mUTrans(data->mKeyList[0]) , mVTrans(data->mKeyList[1]) , mUScale(data->mKeyList[2]) , mVScale(data->mKeyList[3]) @@ -189,26 +247,58 @@ UVControllerValue::UVControllerValue(osg::StateSet *target, const Nif::NiUVData { } -void UVControllerValue::setValue(float value) +UVController::UVController(const UVController& copy, const osg::CopyOp& copyop) + : osg::Object(copy, copyop), osg::NodeCallback(copy, copyop), Controller(copy) + , mUTrans(copy.mUTrans) + , mVTrans(copy.mVTrans) + , mUScale(copy.mUScale) + , mVScale(copy.mVScale) + , mTextureUnits(copy.mTextureUnits) { - float uTrans = interpKey(mUTrans.mKeys, value, 0.0f); - float vTrans = interpKey(mVTrans.mKeys, value, 0.0f); - float uScale = interpKey(mUScale.mKeys, value, 1.0f); - float vScale = interpKey(mVScale.mKeys, value, 1.0f); - - osg::Matrixf mat = osg::Matrixf::scale(uScale, vScale, 1); - mat.setTrans(uTrans, vTrans, 0); - - osg::TexMat* texMat = new osg::TexMat; - texMat->setMatrix(mat); +} - for (std::set::const_iterator it = mTextureUnits.begin(); it != mTextureUnits.end(); ++it) +void UVController::operator()(osg::Node* node, osg::NodeVisitor* nv) +{ + if (hasInput()) { - mStateSet->setTextureAttributeAndModes(*it, texMat, osg::StateAttribute::ON); + osg::StateSet* stateset = node->getStateSet(); + float value = getInputValue(nv); + float uTrans = interpKey(mUTrans.mKeys, value, 0.0f); + float vTrans = interpKey(mVTrans.mKeys, value, 0.0f); + float uScale = interpKey(mUScale.mKeys, value, 1.0f); + float vScale = interpKey(mVScale.mKeys, value, 1.0f); + + osg::Matrixf mat = osg::Matrixf::scale(uScale, vScale, 1); + mat.setTrans(uTrans, vTrans, 0); + + osg::TexMat* texMat = new osg::TexMat; + texMat->setMatrix(mat); + + for (std::set::const_iterator it = mTextureUnits.begin(); it != mTextureUnits.end(); ++it) + { + stateset->setTextureAttributeAndModes(*it, texMat, osg::StateAttribute::ON); + } } + traverse(node, nv); +} + +VisController::VisController(const Nif::NiVisData *data) + : mData(data->mVis) +{ +} + +VisController::VisController() +{ +} + +VisController::VisController(const VisController ©, const osg::CopyOp ©op) + : osg::NodeCallback(copy, copyop) + , Controller(copy) + , mData(copy.mData) +{ } -bool VisControllerValue::calculate(float time) const +bool VisController::calculate(float time) const { if(mData.size() == 0) return true; @@ -221,77 +311,140 @@ bool VisControllerValue::calculate(float time) const return mData.back().isSet; } -void VisControllerValue::setValue(float time) +void VisController::operator() (osg::Node* node, osg::NodeVisitor* nv) +{ + if (hasInput()) + { + bool vis = calculate(getInputValue(nv)); + node->setNodeMask(vis ? ~0 : 0); + } + traverse(node, nv); +} + +AlphaController::AlphaController(const Nif::NiFloatData *data) + : mData(data->mKeyList) { - bool vis = calculate(time); - mNode->setNodeMask(vis ? ~0 : 0); + } -AlphaControllerValue::AlphaControllerValue(osg::StateSet *target, const Nif::NiFloatData *data) - : mTarget(target) - , mData(data->mKeyList) +AlphaController::AlphaController() { } -void AlphaControllerValue::setValue(float time) +AlphaController::AlphaController(const AlphaController ©, const osg::CopyOp ©op) + : osg::NodeCallback(copy, copyop), ValueInterpolator(), Controller(copy) { - float value = interpKey(mData.mKeys, time); - osg::Material* mat = dynamic_cast(mTarget->getAttribute(osg::StateAttribute::MATERIAL)); - if (!mat) - return; +} - osg::Vec4f diffuse = mat->getDiffuse(osg::Material::FRONT_AND_BACK); - diffuse.a() = value; - mat->setDiffuse(osg::Material::FRONT_AND_BACK, diffuse); +void AlphaController::operator () (osg::Node* node, osg::NodeVisitor* nv) +{ + if (hasInput()) + { + osg::StateSet* stateset = node->getStateSet(); + float value = interpKey(mData.mKeys, getInputValue(nv)); + osg::Material* mat = dynamic_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); + if (mat) + { + osg::Vec4f diffuse = mat->getDiffuse(osg::Material::FRONT_AND_BACK); + diffuse.a() = value; + mat->setDiffuse(osg::Material::FRONT_AND_BACK, diffuse); + } + } + traverse(node, nv); } -MaterialColorControllerValue::MaterialColorControllerValue(osg::StateSet *target, const Nif::NiPosData *data) - : mTarget(target), mData(data->mKeyList) +MaterialColorController::MaterialColorController(const Nif::NiPosData *data) + : mData(data->mKeyList) { +} +MaterialColorController::MaterialColorController() +{ } -void MaterialColorControllerValue::setValue(float time) +MaterialColorController::MaterialColorController(const MaterialColorController ©, const osg::CopyOp ©op) + : osg::NodeCallback(copy, copyop), Controller(copy) + , mData(copy.mData) { - osg::Vec3f value = interpKey(mData.mKeys, time); - osg::Material* mat = dynamic_cast(mTarget->getAttribute(osg::StateAttribute::MATERIAL)); - if (!mat) - return; +} - osg::Vec4f diffuse = mat->getDiffuse(osg::Material::FRONT_AND_BACK); - diffuse.set(value.x(), value.y(), value.z(), diffuse.a()); - mat->setDiffuse(osg::Material::FRONT_AND_BACK, diffuse); +void MaterialColorController::operator() (osg::Node* node, osg::NodeVisitor* nv) +{ + if (hasInput()) + { + osg::StateSet* stateset = node->getStateSet(); + osg::Vec3f value = interpKey(mData.mKeys, getInputValue(nv)); + osg::Material* mat = dynamic_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); + if (mat) + { + osg::Vec4f diffuse = mat->getDiffuse(osg::Material::FRONT_AND_BACK); + diffuse.set(value.x(), value.y(), value.z(), diffuse.a()); + mat->setDiffuse(osg::Material::FRONT_AND_BACK, diffuse); + } + } + traverse(node, nv); } -FlipControllerValue::FlipControllerValue(osg::StateSet* target, const Nif::NiFlipController *ctrl, - std::vector > textures) +FlipController::FlipController(const Nif::NiFlipController *ctrl, std::vector > textures) : mTexSlot(ctrl->mTexSlot) , mDelta(ctrl->mDelta) , mTextures(textures) - , mTarget(target) { } -void FlipControllerValue::setValue(float time) +FlipController::FlipController() +{ +} + +FlipController::FlipController(const FlipController ©, const osg::CopyOp ©op) + : osg::NodeCallback(copy, copyop) + , Controller(copy) + , mTexSlot(copy.mTexSlot) + , mDelta(copy.mDelta) + , mTextures(copy.mTextures) { - if (mDelta == 0) - return; - int curTexture = int(time / mDelta) % mTextures.size(); - osg::Texture2D* tex = dynamic_cast(mTarget->getAttribute(osg::StateAttribute::TEXTURE)); - if (!tex) - return; - tex->setImage(mTextures[curTexture].get()); } -ParticleSystemControllerValue::ParticleSystemControllerValue(osgParticle::Emitter *emitter, const Nif::NiParticleSystemController *ctrl) - : mEmitter(emitter), mEmitStart(ctrl->startTime), mEmitStop(ctrl->stopTime) +void FlipController::operator() (osg::Node* node, osg::NodeVisitor* nv) +{ + if (hasInput() && mDelta != 0) + { + osg::StateSet* stateset = node->getStateSet(); + int curTexture = int(getInputValue(nv) / mDelta) % mTextures.size(); + osg::Texture2D* tex = dynamic_cast(stateset->getAttribute(osg::StateAttribute::TEXTURE)); + if (tex) + tex->setImage(mTextures[curTexture].get()); + } + traverse(node, nv); +} + +ParticleSystemController::ParticleSystemController(const Nif::NiParticleSystemController *ctrl) + : mEmitStart(ctrl->startTime), mEmitStop(ctrl->stopTime) +{ +} + +ParticleSystemController::ParticleSystemController() { } -void ParticleSystemControllerValue::setValue(float time) +ParticleSystemController::ParticleSystemController(const ParticleSystemController ©, const osg::CopyOp ©op) + : osg::NodeCallback(copy, copyop) + , Controller(copy) + , mEmitStart(copy.mEmitStart) + , mEmitStop(copy.mEmitStop) { - mEmitter->setEnabled(time >= mEmitStart && time < mEmitStop); } +void ParticleSystemController::operator() (osg::Node* node, osg::NodeVisitor* nv) +{ + if (hasInput()) + { + osgParticle::ParticleProcessor* emitter = dynamic_cast(node); + float time = getInputValue(nv); + if (emitter) + emitter->setEnabled(time >= mEmitStart && time < mEmitStop); + } + traverse(node, nv); +} } diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index c92a77816..5a9af6324 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -17,6 +17,9 @@ #include #include +#include +#include +#include namespace osg @@ -93,76 +96,49 @@ namespace NifOsg class ControllerSource { public: - virtual float getValue() const = 0; + virtual float getValue(osg::NodeVisitor* nv) = 0; }; - // FIXME: Should return a dt instead of time class FrameTimeSource : public ControllerSource { public: - - virtual float getValue() const - { - return mTimer.time_s(); - } - + FrameTimeSource(); + virtual float getValue(osg::NodeVisitor* nv); private: - osg::Timer mTimer; - }; - - class ControllerValue - { - public: - virtual void setValue(float value) = 0; + double mLastTime; }; class Controller { public: - Controller (boost::shared_ptr src, boost::shared_ptr dest, - boost::shared_ptr function); + Controller(); + + bool hasInput() const; - virtual void update(); + float getInputValue(osg::NodeVisitor* nv); boost::shared_ptr mSource; - boost::shared_ptr mDestValue; // The source value gets passed through this function before it's passed on to the DestValue. boost::shared_ptr mFunction; }; - // FIXME: Should be with other general extensions. - class NodeTargetValue : public ControllerValue + class GeomMorpherController : public osg::Drawable::UpdateCallback, public Controller, public ValueInterpolator { - protected: - // TODO: get rid of target pointers, which are incompatible with a copy constructor we will need later - // instead, controllers can be a Node added as child of their target - osg::Node *mNode; - public: - NodeTargetValue(osg::Node *target) : mNode(target) - { } - - virtual osg::Vec3f getTranslation(float value) const = 0; - - osg::Node *getNode() const - { return mNode; } - }; + GeomMorpherController(const Nif::NiMorphData* data); + GeomMorpherController(); + GeomMorpherController(const GeomMorpherController& copy, const osg::CopyOp& copyop); - class GeomMorpherControllerValue : public ControllerValue, public ValueInterpolator - { - public: - // FIXME: don't copy the morph data? - GeomMorpherControllerValue(osgAnimation::MorphGeometry* geom, const Nif::NiMorphData *data); + META_Object(NifOsg, GeomMorpherController) - virtual void setValue(float time); + virtual void update(osg::NodeVisitor* nv, osg::Drawable* drawable); private: - osgAnimation::MorphGeometry* mGeom; std::vector mMorphs; }; - class KeyframeControllerValue : public NodeTargetValue, public ValueInterpolator + class KeyframeController : public osg::NodeCallback, public Controller, public ValueInterpolator { private: const Nif::QuaternionKeyMap* mRotations; @@ -185,31 +161,39 @@ namespace NifOsg public: /// @note The NiKeyFrameData must be valid as long as this KeyframeController exists. - KeyframeControllerValue(osg::Node *target, const Nif::NIFFilePtr& nif, const Nif::NiKeyframeData *data, + KeyframeController(const Nif::NIFFilePtr& nif, const Nif::NiKeyframeData *data, osg::Quat initialQuat, float initialScale); + KeyframeController(); + KeyframeController(const KeyframeController& copy, const osg::CopyOp& copyop); + + META_Object(NifOsg, KeyframeController) virtual osg::Vec3f getTranslation(float time) const; - virtual void setValue(float time); + virtual void operator() (osg::Node*, osg::NodeVisitor*); }; - class UVControllerValue : public ControllerValue, ValueInterpolator + // Note we're using NodeCallback instead of StateSet::Callback because the StateSet callback doesn't support nesting + struct UVController : public osg::NodeCallback, public Controller, public ValueInterpolator { + public: + UVController(); + UVController(const UVController&,const osg::CopyOp& = osg::CopyOp::SHALLOW_COPY); + UVController(const Nif::NiUVData *data, std::set textureUnits); + + META_Object(NifOsg,UVController) + + virtual void operator() (osg::Node*, osg::NodeVisitor*); + private: - osg::StateSet* mStateSet; Nif::FloatKeyMap mUTrans; Nif::FloatKeyMap mVTrans; Nif::FloatKeyMap mUScale; Nif::FloatKeyMap mVScale; std::set mTextureUnits; - - public: - UVControllerValue(osg::StateSet* target, const Nif::NiUVData *data, std::set textureUnits); - - virtual void setValue(float value); }; - class VisControllerValue : public NodeTargetValue + class VisController : public osg::NodeCallback, public Controller { private: std::vector mData; @@ -217,65 +201,75 @@ namespace NifOsg bool calculate(float time) const; public: - VisControllerValue(osg::Node *target, const Nif::NiVisData *data) - : NodeTargetValue(target) - , mData(data->mVis) - { } + VisController(const Nif::NiVisData *data); + VisController(); + VisController(const VisController& copy, const osg::CopyOp& copyop); - virtual osg::Vec3f getTranslation(float time) const - { return osg::Vec3f(); } + META_Object(NifOsg, VisController) - virtual void setValue(float time); + virtual void operator() (osg::Node* node, osg::NodeVisitor* nv); }; - class AlphaControllerValue : public ControllerValue, public ValueInterpolator + class AlphaController : public osg::NodeCallback, public Controller, public ValueInterpolator { private: - osg::StateSet* mTarget; Nif::FloatKeyMap mData; public: - AlphaControllerValue(osg::StateSet* target, const Nif::NiFloatData *data); + AlphaController(const Nif::NiFloatData *data); + AlphaController(); + AlphaController(const AlphaController& copy, const osg::CopyOp& copyop); + + virtual void operator() (osg::Node* node, osg::NodeVisitor* nv); - virtual void setValue(float time); + META_Object(NifOsg, AlphaController) }; - class MaterialColorControllerValue : public ControllerValue, public ValueInterpolator + class MaterialColorController : public osg::NodeCallback, public Controller, public ValueInterpolator { private: - osg::StateSet* mTarget; Nif::Vector3KeyMap mData; public: - MaterialColorControllerValue(osg::StateSet* target, const Nif::NiPosData *data); + MaterialColorController(const Nif::NiPosData *data); + MaterialColorController(); + MaterialColorController(const MaterialColorController& copy, const osg::CopyOp& copyop); - virtual void setValue(float time); + META_Object(NifOsg, MaterialColorController) + + virtual void operator() (osg::Node* node, osg::NodeVisitor* nv); }; // untested - class FlipControllerValue : public ControllerValue + class FlipController : public osg::NodeCallback, public Controller { private: - osg::StateSet* mTarget; int mTexSlot; float mDelta; std::vector > mTextures; public: - FlipControllerValue(osg::StateSet* target, const Nif::NiFlipController* ctrl, std::vector > textures); + FlipController(const Nif::NiFlipController* ctrl, std::vector > textures); + FlipController(); + FlipController(const FlipController& copy, const osg::CopyOp& copyop); + + META_Object(NifOsg, FlipController) - virtual void setValue(float time); + virtual void operator() (osg::Node* node, osg::NodeVisitor* nv); }; - class ParticleSystemControllerValue : public ControllerValue + class ParticleSystemController : public osg::NodeCallback, public Controller { public: - ParticleSystemControllerValue(osgParticle::Emitter* emitter, const Nif::NiParticleSystemController* ctrl); + ParticleSystemController(const Nif::NiParticleSystemController* ctrl); + ParticleSystemController(); + ParticleSystemController(const ParticleSystemController& copy, const osg::CopyOp& copyop); + + META_Object(NifOsg, ParticleSystemController) - virtual void setValue(float time); + virtual void operator() (osg::Node* node, osg::NodeVisitor* nv); private: - osgParticle::Emitter* mEmitter; float mEmitStart; float mEmitStop; }; diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index a92baee79..26f0927b5 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -285,17 +285,13 @@ namespace NifOsg } } - void Loader::createController(const Nif::Controller *ctrl, boost::shared_ptr value, int animflags) + void Loader::setupController(const Nif::Controller* ctrl, Controller* toSetup, int animflags) { - // FIXME animflags currently not passed to this function //bool autoPlay = animflags & Nif::NiNode::AnimFlag_AutoPlay; - boost::shared_ptr src(new FrameTimeSource); // if autoPlay + //if (autoPlay) + toSetup->mSource = boost::shared_ptr(new FrameTimeSource); - boost::shared_ptr function (new ControllerFunction(ctrl - , 0/*autoPlay*/)); - //scene->mMaxControllerLength = std::max(function->mStopTime, scene->mMaxControllerLength); - - mControllers.push_back(Controller(src, value, function)); + toSetup->mFunction = boost::shared_ptr(new ControllerFunction(ctrl, 1 /*autoPlay*/)); } void Loader::handleNode(const Nif::Node* nifNode, osg::Group* parentNode, bool createSkeleton, @@ -308,7 +304,6 @@ namespace NifOsg transformNode = bone; bone->setMatrix(toMatrix(nifNode->trafo)); bone->setName(nifNode->name); - bone->setUpdateCallback(new UpdateBone); bone->setInvBindMatrixInSkeletonSpace(osg::Matrixf::inverse(getWorldTransform(nifNode))); } else @@ -332,6 +327,7 @@ namespace NifOsg // We could probably skip hidden nodes entirely if they don't have a VisController that // might make them visible later + // FIXME: this disables update callbacks, so VisController no longer works if (nifNode->flags & Nif::NiNode::Flag_Hidden) transformNode->setNodeMask(0); @@ -358,6 +354,10 @@ namespace NifOsg if (!nifNode->controller.empty()) handleNodeControllers(nifNode, transformNode, animflags); + // Added last so the changes from KeyframeControllers are taken into account + if (osgAnimation::Bone* bone = dynamic_cast(transformNode.get())) + bone->addUpdateCallback(new UpdateBone); + const Nif::NiNode *ninode = dynamic_cast(nifNode); if(ninode) { @@ -382,9 +382,12 @@ namespace NifOsg std::set texUnits; for (std::map::const_iterator it = boundTextures.begin(); it != boundTextures.end(); ++it) texUnits.insert(it->first); - boost::shared_ptr dest(new UVControllerValue(transformNode->getOrCreateStateSet() - , uvctrl->data.getPtr(), texUnits)); - createController(uvctrl, dest, animflags); + + osg::ref_ptr ctrl = new UVController(uvctrl->data.getPtr(), texUnits); + setupController(uvctrl, ctrl, animflags); + transformNode->getOrCreateStateSet()->setDataVariance(osg::StateSet::DYNAMIC); + + transformNode->addUpdateCallback(ctrl); } } } @@ -406,23 +409,27 @@ namespace NifOsg std::cerr << "Warning: multiple KeyframeControllers on the same node" << std::endl; continue; } - boost::shared_ptr dest(new KeyframeControllerValue(transformNode, mNif, key->data.getPtr(), - transformNode->getMatrix().getRotate(), nifNode->trafo.scale)); + osg::ref_ptr callback(new KeyframeController(mNif, key->data.getPtr(), + transformNode->getMatrix().getRotate(), nifNode->trafo.scale)); + + setupController(key, callback, animflags); + transformNode->addUpdateCallback(callback); - createController(key, dest, animflags); seenKeyframeCtrl = true; } } else if (ctrl->recType == Nif::RC_NiVisController) { const Nif::NiVisController* visctrl = static_cast(ctrl.getPtr()); - boost::shared_ptr dest(new VisControllerValue(transformNode, visctrl->data.getPtr())); - createController(visctrl, dest, animflags); + + osg::ref_ptr callback(new VisController(visctrl->data.getPtr())); + setupController(visctrl, callback, animflags); + transformNode->addUpdateCallback(callback); } } } - void Loader::handleMaterialControllers(const Nif::Property *materialProperty, osg::StateSet *stateset, int animflags) + void Loader::handleMaterialControllers(const Nif::Property *materialProperty, osg::Node* node, osg::StateSet *stateset, int animflags) { for (Nif::ControllerPtr ctrl = materialProperty->controller; !ctrl.empty(); ctrl = ctrl->next) { @@ -431,21 +438,25 @@ namespace NifOsg if (ctrl->recType == Nif::RC_NiAlphaController) { const Nif::NiAlphaController* alphactrl = static_cast(ctrl.getPtr()); - boost::shared_ptr dest(new AlphaControllerValue(stateset, alphactrl->data.getPtr())); - createController(alphactrl, dest, animflags); + osg::ref_ptr ctrl(new AlphaController(alphactrl->data.getPtr())); + setupController(alphactrl, ctrl, animflags); + stateset->setDataVariance(osg::StateSet::DYNAMIC); + node->addUpdateCallback(ctrl); } else if (ctrl->recType == Nif::RC_NiMaterialColorController) { const Nif::NiMaterialColorController* matctrl = static_cast(ctrl.getPtr()); - boost::shared_ptr dest(new MaterialColorControllerValue(stateset, matctrl->data.getPtr())); - createController(matctrl, dest, animflags); + osg::ref_ptr ctrl(new MaterialColorController(matctrl->data.getPtr())); + setupController(matctrl, ctrl, animflags); + stateset->setDataVariance(osg::StateSet::DYNAMIC); + node->addUpdateCallback(ctrl); } else std::cerr << "Unexpected material controller " << ctrl->recType << std::endl; } } - void Loader::handleTextureControllers(const Nif::Property *texProperty, osg::StateSet *stateset, int animflags) + void Loader::handleTextureControllers(const Nif::Property *texProperty, osg::Node* node, osg::StateSet *stateset, int animflags) { for (Nif::ControllerPtr ctrl = texProperty->controller; !ctrl.empty(); ctrl = ctrl->next) { @@ -470,8 +481,10 @@ namespace NifOsg osgDB::ReaderWriter::ReadResult result = reader->readImage(*resourceManager->get(filename.c_str()), opts); textures.push_back(osg::ref_ptr(result.getImage())); } - boost::shared_ptr dest(new FlipControllerValue(stateset, flipctrl, textures)); - createController(flipctrl, dest, animflags); + osg::ref_ptr callback(new FlipController(flipctrl, textures)); + setupController(ctrl.getPtr(), callback, animflags); + stateset->setDataVariance(osg::StateSet::DYNAMIC); + node->addUpdateCallback(callback); } else std::cerr << "Unexpected texture controller " << ctrl->recName << std::endl; @@ -577,7 +590,9 @@ namespace NifOsg // If something ever violates this assumption, the worst that could happen is the culling being one frame late, which wouldn't be a disaster. parentNode->addChild(emitter); - createController(partctrl, boost::shared_ptr(new ParticleSystemControllerValue(emitter, partctrl)), animflags); + osg::ref_ptr callback(new ParticleSystemController(partctrl)); + setupController(partctrl, callback, animflags); + emitter->setUpdateCallback(callback); // ----------- affector (must be after emitters in the scene graph) osgParticle::ModularProgram* program = new osgParticle::ModularProgram; @@ -615,14 +630,16 @@ namespace NifOsg // ----------- + osg::ref_ptr geode (new osg::Geode); + geode->addDrawable(partsys); + std::vector materialProps; collectMaterialProperties(nifNode, materialProps); - applyMaterialProperties(partsys->getOrCreateStateSet(), materialProps, true, animflags); + applyMaterialProperties(geode, materialProps, true, animflags); partsys->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF); partsys->getOrCreateStateSet()->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); - osg::ref_ptr geode (new osg::Geode); - geode->addDrawable(partsys); + if (rf == osgParticle::ParticleProcessor::RELATIVE_RF) parentNode->addChild(geode); @@ -640,7 +657,7 @@ namespace NifOsg parentNode->addChild(updater); } - void Loader::triShapeToGeometry(const Nif::NiTriShape *triShape, osg::Geometry *geometry, const std::map& boundTextures, int animflags) + void Loader::triShapeToGeometry(const Nif::NiTriShape *triShape, osg::Geometry *geometry, osg::Geode* parentGeode, const std::map& boundTextures, int animflags) { const Nif::NiTriShapeData* data = triShape->data.getPtr(); @@ -720,7 +737,7 @@ namespace NifOsg // above the actual renderable would be tedious. std::vector materialProps; collectMaterialProperties(triShape, materialProps); - applyMaterialProperties(geometry->getOrCreateStateSet(), materialProps, !data->colors.empty(), animflags); + applyMaterialProperties(parentGeode, materialProps, !data->colors.empty(), animflags); } void Loader::handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, const std::map& boundTextures, int animflags) @@ -733,10 +750,11 @@ namespace NifOsg if(ctrl->recType == Nif::RC_NiGeomMorpherController && ctrl->flags & Nif::NiNode::ControllerFlag_Active) { geometry = handleMorphGeometry(static_cast(ctrl.getPtr())); - boost::shared_ptr value( - new GeomMorpherControllerValue(static_cast(geometry.get()), - static_cast(ctrl.getPtr())->data.getPtr())); - createController(ctrl.getPtr(), value, 0); + + osg::ref_ptr morphctrl = new GeomMorpherController( + static_cast(ctrl.getPtr())->data.getPtr()); + setupController(ctrl.getPtr(), morphctrl, animflags); + geometry->setUpdateCallback(morphctrl); break; } } while(!(ctrl=ctrl->next).empty()); @@ -744,9 +762,10 @@ namespace NifOsg if (!geometry.get()) geometry = new osg::Geometry; - triShapeToGeometry(triShape, geometry, boundTextures, animflags); osg::ref_ptr geode (new osg::Geode); + triShapeToGeometry(triShape, geometry, geode, boundTextures, animflags); + geode->addDrawable(geometry); parentNode->addChild(geode); @@ -754,8 +773,9 @@ namespace NifOsg void Loader::handleSkinnedTriShape(const Nif::NiTriShape *triShape, osg::Group *parentNode, const std::map& boundTextures, int animflags) { + osg::ref_ptr geode (new osg::Geode); osg::ref_ptr geometry (new osg::Geometry); - triShapeToGeometry(triShape, geometry, boundTextures, animflags); + triShapeToGeometry(triShape, geometry, geode, boundTextures, animflags); osg::ref_ptr rig(new osgAnimation::RigGeometry); rig->setSourceGeometry(geometry); @@ -795,7 +815,6 @@ namespace NifOsg osg::ref_ptr trans(new osg::MatrixTransform); trans->setUpdateCallback(new InvertBoneMatrix()); - osg::ref_ptr geode (new osg::Geode); geode->addDrawable(rig); trans->addChild(geode); @@ -987,7 +1006,7 @@ namespace NifOsg stateset->setTextureAttributeAndModes(i, new osg::Texture2D, osg::StateAttribute::OFF); boundTextures.erase(i); } - handleTextureControllers(texprop, stateset, animflags); + handleTextureControllers(texprop, node, stateset, animflags); } break; } @@ -1003,9 +1022,11 @@ namespace NifOsg } } - void Loader::applyMaterialProperties(osg::StateSet* stateset, const std::vector& properties, + void Loader::applyMaterialProperties(osg::Node* node, const std::vector& properties, bool hasVertexColors, int animflags) { + osg::StateSet* stateset = node->getOrCreateStateSet(); + int specFlags = 0; // Specular is disabled by default, even if there's a specular color in the NiMaterialProperty osg::Material* mat = new osg::Material; mat->setColorMode(hasVertexColors ? osg::Material::AMBIENT_AND_DIFFUSE : osg::Material::OFF); @@ -1032,7 +1053,7 @@ namespace NifOsg mat->setShininess(osg::Material::FRONT_AND_BACK, matprop->data.glossiness); if (!matprop->controller.empty()) - handleMaterialControllers(matprop, stateset, animflags); + handleMaterialControllers(matprop, node, stateset, animflags); break; } diff --git a/components/nifosg/nifloader.hpp b/components/nifosg/nifloader.hpp index 7b38ce560..5bd25f6ca 100644 --- a/components/nifosg/nifloader.hpp +++ b/components/nifosg/nifloader.hpp @@ -9,8 +9,6 @@ #include -#include "controller.hpp" - namespace osg { class Geometry; @@ -25,10 +23,12 @@ namespace Nif class Node; class NiTriShape; class Property; + class Controller; } namespace NifOsg { + class Controller; /// The main class responsible for loading NIF files into an OSG-Scenegraph. class Loader @@ -41,9 +41,6 @@ namespace NifOsg const VFS::Manager* resourceManager; - // FIXME move - std::vector mControllers; - private: /// @param createSkeleton If true, use an osgAnimation::Bone for NIF nodes, otherwise an osg::MatrixTransform. @@ -54,9 +51,9 @@ namespace NifOsg void handleNodeControllers(const Nif::Node* nifNode, osg::MatrixTransform* transformNode, int animflags); - void handleMaterialControllers(const Nif::Property* materialProperty, osg::StateSet* stateset, int animflags); + void handleMaterialControllers(const Nif::Property* materialProperty, osg::Node* node, osg::StateSet* stateset, int animflags); - void handleTextureControllers(const Nif::Property* texProperty, osg::StateSet* stateset, int animflags); + void handleTextureControllers(const Nif::Property* texProperty, osg::Node* node, osg::StateSet* stateset, int animflags); void handleProperty (const Nif::Property* property, const Nif::Node* nifNode, osg::Node* node, std::map& boundTextures, int animflags); @@ -67,7 +64,7 @@ namespace NifOsg void handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, const std::map& boundTextures, int animflags); // Fills the vertex data for the given TriShape into the given Geometry. - void triShapeToGeometry(const Nif::NiTriShape* triShape, osg::Geometry* geom, const std::map& boundTextures, int animflags); + void triShapeToGeometry(const Nif::NiTriShape* triShape, osg::Geometry* geom, osg::Geode* parentGeode, const std::map& boundTextures, int animflags); // Creates a skinned osg::Geometry object for the given TriShape, populates it, and attaches it to the given node. void handleSkinnedTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, const std::map& boundTextures, int animflags); @@ -75,10 +72,11 @@ namespace NifOsg // Applies the Properties of the given nifNode onto the StateSet of the given OSG node. void applyNodeProperties(const Nif::Node* nifNode, osg::Node* applyTo, std::map& boundTextures, int animflags); - void applyMaterialProperties(osg::StateSet* stateset, const std::vector& properties, + void applyMaterialProperties(osg::Node* node, const std::vector& properties, bool hasVertexColors, int animflags); - void createController(const Nif::Controller* ctrl, boost::shared_ptr value, int animflags); + // Set up the default input and controller function for the given controller. + void setupController(const Nif::Controller* ctrl, Controller* toSetup, int animflags); Nif::NIFFilePtr mNif; diff --git a/components/nifosg/particle.cpp b/components/nifosg/particle.cpp index 58501763b..f2f59195c 100644 --- a/components/nifosg/particle.cpp +++ b/components/nifosg/particle.cpp @@ -39,6 +39,7 @@ ParticleShooter::ParticleShooter() } ParticleShooter::ParticleShooter(const osgParticle::Shooter ©, const osg::CopyOp ©op) + : osgParticle::Shooter(copy, copyop) { *this = copy; } From d486cde330e5797ed484ac66e8b27ab413ee7f6a Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 20 Mar 2015 21:32:26 +0100 Subject: [PATCH 0786/3725] Fix broken VisControllers --- apps/nifosgtest/test.cpp | 3 ++- components/nifosg/controller.cpp | 3 ++- components/nifosg/nifloader.cpp | 6 +++--- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/apps/nifosgtest/test.cpp b/apps/nifosgtest/test.cpp index fee919787..3e70c8cd2 100644 --- a/apps/nifosgtest/test.cpp +++ b/apps/nifosgtest/test.cpp @@ -133,7 +133,8 @@ int main(int argc, char** argv) viewer.setCameraManipulator(new osgGA::TrackballManipulator()); viewer.addEventHandler(new WireframeKeyHandler(root)); - //viewer.getCamera()->setCullMask() + // Mask to separate cull visitors from update visitors + viewer.getCamera()->setCullMask(~(0x1)); // We're going to change this from the event callback, set the variance to DYNAMIC so that // we don't interfere with the draw thread. diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index 509d20bbf..01671dbd8 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -316,7 +316,8 @@ void VisController::operator() (osg::Node* node, osg::NodeVisitor* nv) if (hasInput()) { bool vis = calculate(getInputValue(nv)); - node->setNodeMask(vis ? ~0 : 0); + // Leave 0x1 enabled for UpdateVisitor, so we can make ourselves visible again in the future from this update callback + node->setNodeMask(vis ? ~0 : 0x1); } traverse(node, nv); } diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 26f0927b5..2fb60280b 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -322,14 +322,14 @@ namespace NifOsg if (nifNode->recType == Nif::RC_RootCollisionNode) { collisionNode = true; - transformNode->setNodeMask(0); + // Leave mask for UpdateVisitor enabled + transformNode->setNodeMask(0x1); } // We could probably skip hidden nodes entirely if they don't have a VisController that // might make them visible later - // FIXME: this disables update callbacks, so VisController no longer works if (nifNode->flags & Nif::NiNode::Flag_Hidden) - transformNode->setNodeMask(0); + transformNode->setNodeMask(0x1); // Leave mask for UpdateVisitor enabled // Insert bones at position 0 to prevent update order problems (see comment in osg Skeleton.cpp) parentNode->insertChild(0, transformNode); From 32bb202290ecde69c3fbc491f6eb0ae32baabacb Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 20 Mar 2015 23:14:01 +0100 Subject: [PATCH 0787/3725] Implement BillboardNode --- components/nifosg/nifloader.cpp | 39 ++++++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 2fb60280b..5666fe07f 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -128,6 +128,7 @@ namespace } // NodeCallback used to update the bone matrices in skeleton space as needed for skinning. + // Must be set on a Bone. class UpdateBone : public osg::NodeCallback { public: @@ -161,10 +162,39 @@ namespace } }; + // Custom node used to have a transform always oriented towards the camera. Can have translation and scale + // set just like a regular MatrixTransform, but the rotation set will be overridden in order to face the camera. + class BillboardNode : public osg::MatrixTransform + { + public: + BillboardNode() : osg::MatrixTransform() {} + BillboardNode(const BillboardNode& copy, const osg::CopyOp& copyop) + : osg::MatrixTransform(copy, copyop) {} + BillboardNode(const osg::Matrix& matrix) + : osg::MatrixTransform(matrix) {} + + META_Node(NifOsg, BillboardNode) + + virtual bool computeLocalToWorldMatrix(osg::Matrix& matrix, osg::NodeVisitor*) const + { + if (_referenceFrame==RELATIVE_RF) + { + matrix.preMult(_matrix); + matrix.setRotate(osg::Quat()); + } + else // absolute + { + matrix = _matrix; + } + return true; + } + }; + // NodeCallback used to set the inverse of the parent bone's matrix in skeleton space // on the MatrixTransform that the NodeCallback is attached to. This is used so we can // attach skinned meshes to their actual parent node, while still having the skinning // work in skeleton space as expected. + // Must be set on a MatrixTransform. class InvertBoneMatrix : public osg::NodeCallback { public: @@ -298,7 +328,11 @@ namespace NifOsg std::map boundTextures, int animflags, int particleflags, bool collisionNode) { osg::ref_ptr transformNode; - if (createSkeleton) + if (nifNode->recType == Nif::RC_NiBillboardNode) + { + transformNode = new BillboardNode(toMatrix(nifNode->trafo)); + } + else if (createSkeleton) { osgAnimation::Bone* bone = new osgAnimation::Bone; transformNode = bone; @@ -308,8 +342,7 @@ namespace NifOsg } else { - transformNode = new osg::MatrixTransform; - transformNode->setMatrix(toMatrix(nifNode->trafo)); + transformNode = new osg::MatrixTransform(toMatrix(nifNode->trafo)); } if (nifNode->recType == Nif::RC_NiBSAnimationNode) From a9aee389c0e0551593ba995b2867e4cb833adca9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 21 Mar 2015 03:50:50 +0100 Subject: [PATCH 0788/3725] Emitters attached to correct node, a bit ugly --- components/nifosg/nifloader.cpp | 63 +++++++++++++++++++++++++++++---- 1 file changed, 56 insertions(+), 7 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 5666fe07f..099288b4f 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -324,6 +324,13 @@ namespace NifOsg toSetup->mFunction = boost::shared_ptr(new ControllerFunction(ctrl, 1 /*autoPlay*/)); } + class RecIndexHolder : public osg::Referenced + { + public: + RecIndexHolder(int index) : mIndex(index) {} + int mIndex; + }; + void Loader::handleNode(const Nif::Node* nifNode, osg::Group* parentNode, bool createSkeleton, std::map boundTextures, int animflags, int particleflags, bool collisionNode) { @@ -345,6 +352,8 @@ namespace NifOsg transformNode = new osg::MatrixTransform(toMatrix(nifNode->trafo)); } + transformNode->setUserData(new RecIndexHolder(nifNode->recIndex)); + if (nifNode->recType == Nif::RC_NiBSAnimationNode) animflags |= nifNode->flags; if (nifNode->recType == Nif::RC_NiBSParticleNode) @@ -442,8 +451,14 @@ namespace NifOsg std::cerr << "Warning: multiple KeyframeControllers on the same node" << std::endl; continue; } - osg::ref_ptr callback(new KeyframeController(mNif, key->data.getPtr(), - transformNode->getMatrix().getRotate(), nifNode->trafo.scale)); + + // build the rotation part manually to avoid issues caused by scaling + osg::Matrixf mat; + for (int i=0;i<3;++i) + for (int j=0;j<3;++j) + mat(j,i) = nifNode->trafo.rotation.mValues[i][j]; + + osg::ref_ptr callback(new KeyframeController(mNif, key->data.getPtr(), mat.getRotate(), nifNode->trafo.scale)); setupController(key, callback, animflags); transformNode->addUpdateCallback(callback); @@ -524,6 +539,32 @@ namespace NifOsg } } + class FindEmitterNode : public osg::NodeVisitor + { + public: + FindEmitterNode(int recIndex) + : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) + , mFound(NULL) + , mRecIndex(recIndex) + { + } + + virtual void apply(osg::Node &searchNode) + { + if (searchNode.getUserData()) + { + RecIndexHolder* holder = static_cast(searchNode.getUserData()); + if (holder->mIndex == mRecIndex) + mFound = static_cast(&searchNode); + } + traverse(searchNode); + } + + osg::Group* mFound; + private: + int mRecIndex; + }; + void Loader::handleParticleSystem(const Nif::Node *nifNode, osg::Group *parentNode, int animflags, int particleflags) { osg::ref_ptr partsys (new osgParticle::ParticleSystem); @@ -591,7 +632,7 @@ namespace NifOsg // ---- emitter - osgParticle::ModularEmitter* emitter = new osgParticle::ModularEmitter; + osg::ref_ptr emitter = new osgParticle::ModularEmitter; emitter->setParticleSystem(partsys); emitter->setReferenceFrame(osgParticle::ParticleProcessor::RELATIVE_RF); @@ -617,11 +658,19 @@ namespace NifOsg emitter->setPlacer(placer); - // TODO: attach to the emitter node - // Note: we also assume that the Emitter node is placed *before* the Particle node in the scene graph. + // Note: we assume that the Emitter node is placed *before* the Particle node in the scene graph. // This seems to be true for all NIF files in the game that I've checked, suggesting that NIFs work similar to OSG with regards to update order. // If something ever violates this assumption, the worst that could happen is the culling being one frame late, which wouldn't be a disaster. - parentNode->addChild(emitter); + + FindEmitterNode find (partctrl->emitter->recIndex); + mRootNode->accept(find); + if (!find.mFound) + { + std::cerr << "can't find emitter node, wrong node order?" << std::endl; + return; + } + osg::Group* emitterNode = find.mFound; + emitterNode->addChild(emitter); osg::ref_ptr callback(new ParticleSystemController(partctrl)); setupController(partctrl, callback, animflags); @@ -631,7 +680,7 @@ namespace NifOsg osgParticle::ModularProgram* program = new osgParticle::ModularProgram; program->setParticleSystem(partsys); program->setReferenceFrame(rf); - parentNode->addChild(program); + emitterNode->addChild(program); for (Nif::ExtraPtr e = partctrl->extra; !e.empty(); e = e->extra) { if (e->recType == Nif::RC_NiParticleGrowFade) From 154bb04a77f259e09af65022fa76e3b69bf0595a Mon Sep 17 00:00:00 2001 From: Scott Howard Date: Tue, 17 Mar 2015 09:45:31 -0400 Subject: [PATCH 0789/3725] add scan-build to travis matrix --- .travis.yml | 10 +++++++++- CI/before_install.linux.sh | 10 ++++++++-- CI/before_script.linux.sh | 4 +++- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1be8aa59c..1fc85dca3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,6 +21,14 @@ addons: build_command_prepend: "cmake ." build_command: "make -j3" branch_pattern: coverity_scan +matrix: + include: + - os: linux + env: + ANALYZE="scan-build-3.6 --use-cc clang-3.6 --use-c++ clang++-3.6 " + compiler: clang + allow_failures: + - env: ANALYZE="scan-build-3.6 --use-cc clang-3.6 --use-c++ clang++-3.6 " before_install: - if [ "${TRAVIS_OS_NAME}" = "linux" ]; then ./CI/before_install.linux.sh; fi @@ -30,7 +38,7 @@ before_script: - if [ "${TRAVIS_OS_NAME}" = "osx" ]; then ./CI/before_script.osx.sh; fi script: - cd ./build - - if [ "$COVERITY_SCAN_BRANCH" != 1 ]; then make -j4; fi + - if [ "$COVERITY_SCAN_BRANCH" != 1 ]; then ${ANALYZE}make -j4; fi - if [ "$COVERITY_SCAN_BRANCH" != 1 ] && [ "${TRAVIS_OS_NAME}" = "osx" ]; then make package; fi after_script: - if [ "${TRAVIS_OS_NAME}" = "linux" ]; then ./openmw_test_suite; fi diff --git a/CI/before_install.linux.sh b/CI/before_install.linux.sh index 998c285db..27cb71463 100755 --- a/CI/before_install.linux.sh +++ b/CI/before_install.linux.sh @@ -1,7 +1,12 @@ #!/bin/sh -export CXX=g++ -export CC=gcc +if [ "${ANALYZE}" ]; then + if [ $(lsb_release -sc) = "precise" ]; then + echo "yes" | sudo apt-add-repository ppa:ubuntu-toolchain-r/test + fi + echo "yes" | sudo add-apt-repository "deb http://llvm.org/apt/`lsb_release -sc`/ llvm-toolchain-`lsb_release -sc`-3.6 main" + wget -O - http://llvm.org/apt/llvm-snapshot.gpg.key|sudo apt-key add - +fi echo "yes" | sudo add-apt-repository "deb http://archive.ubuntu.com/ubuntu `lsb_release -sc` main universe restricted multiverse" echo "yes" | sudo apt-add-repository ppa:openmw/openmw @@ -10,6 +15,7 @@ sudo apt-get install -qq libgtest-dev google-mock sudo apt-get install -qq libboost-filesystem-dev libboost-program-options-dev libboost-system-dev libboost-thread-dev libboost-wave-dev sudo apt-get install -qq libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libavresample-dev sudo apt-get install -qq libbullet-dev libogre-1.9-dev libmygui-dev libsdl2-dev libunshield-dev libtinyxml-dev libopenal-dev libqt4-dev +if [ "${ANALYZE}" ]; then sudo apt-get install -qq clang-3.6; fi sudo mkdir /usr/src/gtest/build cd /usr/src/gtest/build sudo cmake .. -DBUILD_SHARED_LIBS=1 diff --git a/CI/before_script.linux.sh b/CI/before_script.linux.sh index b4889c9e1..71ddd2040 100755 --- a/CI/before_script.linux.sh +++ b/CI/before_script.linux.sh @@ -2,4 +2,6 @@ mkdir build cd build -cmake .. -DBUILD_WITH_CODE_COVERAGE=1 -DBUILD_UNITTESTS=1 -DCMAKE_INSTALL_PREFIX=/usr -DBINDIR=/usr/games -DCMAKE_BUILD_TYPE="RelWithDebInfo" -DUSE_SYSTEM_TINYXML=TRUE +export CODE_COVERAGE=1 +if [ "${CC}" = "clang" ]; then export CODE_COVERAGE=0; fi +${ANALYZE}cmake .. -DBUILD_WITH_CODE_COVERAGE=${CODE_COVERAGE} -DBUILD_UNITTESTS=1 -DCMAKE_INSTALL_PREFIX=/usr -DBINDIR=/usr/games -DCMAKE_BUILD_TYPE="RelWithDebInfo" -DUSE_SYSTEM_TINYXML=TRUE From 2e11642273fa218f34524cdc1dca2bd02657550a Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 21 Mar 2015 04:10:50 +0100 Subject: [PATCH 0790/3725] Fix BillboardNode overriding scale --- components/nifosg/nifloader.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 099288b4f..30b3c6537 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -180,7 +180,11 @@ namespace if (_referenceFrame==RELATIVE_RF) { matrix.preMult(_matrix); + osg::Vec3 scale = matrix.getScale(); matrix.setRotate(osg::Quat()); + matrix(0,0) = scale.x(); + matrix(1,1) = scale.y(); + matrix(2,2) = scale.z(); } else // absolute { From 71782462b73231bf088f51058b31fb3703949e5d Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 21 Mar 2015 04:28:26 +0100 Subject: [PATCH 0791/3725] Subclass ParticleSystem to support limit on the number of particles --- components/nifosg/nifloader.cpp | 4 +++- components/nifosg/particle.cpp | 26 ++++++++++++++++++++++++++ components/nifosg/particle.hpp | 17 +++++++++++++++++ 3 files changed, 46 insertions(+), 1 deletion(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 30b3c6537..dcab80707 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -571,7 +571,7 @@ namespace NifOsg void Loader::handleParticleSystem(const Nif::Node *nifNode, osg::Group *parentNode, int animflags, int particleflags) { - osg::ref_ptr partsys (new osgParticle::ParticleSystem); + osg::ref_ptr partsys (new ParticleSystem); partsys->setSortMode(osgParticle::ParticleSystem::SORT_BACK_TO_FRONT); const Nif::NiAutoNormalParticlesData *particledata = NULL; @@ -630,6 +630,8 @@ namespace NifOsg created->setSizeRange(osgParticle::rangef(size, size)); } + partsys->setQuota(partctrl->numParticles); + partsys->getDefaultParticleTemplate().setSizeRange(osgParticle::rangef(partctrl->size, partctrl->size)); partsys->getDefaultParticleTemplate().setColorRange(osgParticle::rangev4(osg::Vec4f(1.f,1.f,1.f,1.f), osg::Vec4f(1.f,1.f,1.f,1.f))); partsys->getDefaultParticleTemplate().setAlphaRange(osgParticle::rangef(1.f, 1.f)); diff --git a/components/nifosg/particle.cpp b/components/nifosg/particle.cpp index f2f59195c..77e5f16df 100644 --- a/components/nifosg/particle.cpp +++ b/components/nifosg/particle.cpp @@ -1,5 +1,7 @@ #include "particle.hpp" +#include + #include #include @@ -9,6 +11,30 @@ namespace NifOsg { +ParticleSystem::ParticleSystem() + : osgParticle::ParticleSystem() + , mQuota(std::numeric_limits::max()) +{ +} + +ParticleSystem::ParticleSystem(const ParticleSystem ©, const osg::CopyOp ©op) + : osgParticle::ParticleSystem(copy, copyop) + , mQuota(copy.mQuota) +{ +} + +void ParticleSystem::setQuota(int quota) +{ + mQuota = quota; +} + +osgParticle::Particle* ParticleSystem::createParticle(const osgParticle::Particle *ptemplate) +{ + if (numParticles()-numDeadParticles() < mQuota) + return osgParticle::ParticleSystem::createParticle(ptemplate); + return NULL; +} + void InverseWorldMatrix::operator()(osg::Node *node, osg::NodeVisitor *nv) { if (nv && nv->getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR) diff --git a/components/nifosg/particle.hpp b/components/nifosg/particle.hpp index 13010fbac..1f3905089 100644 --- a/components/nifosg/particle.hpp +++ b/components/nifosg/particle.hpp @@ -20,6 +20,23 @@ namespace Nif namespace NifOsg { + // Subclass ParticleSystem to support a limit on the number of active particles. + class ParticleSystem : public osgParticle::ParticleSystem + { + public: + ParticleSystem(); + ParticleSystem(const ParticleSystem& copy, const osg::CopyOp& copyop); + + META_Object(NifOsg, NifOsg::ParticleSystem) + + virtual osgParticle::Particle* createParticle(const osgParticle::Particle *ptemplate); + + void setQuota(int quota); + + private: + int mQuota; + }; + // HACK: Particle doesn't allow setting the initial age, but we need this for loading the particle system state class ParticleAgeSetter : public osgParticle::Particle { From 2cfc4c02866bf36ebf874ff12075ec85e685a724 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sat, 21 Mar 2015 18:21:01 +1300 Subject: [PATCH 0792/3725] script Random() command now returns correct range. --- components/interpreter/miscopcodes.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/interpreter/miscopcodes.hpp b/components/interpreter/miscopcodes.hpp index 1da8cf695..f566a5499 100644 --- a/components/interpreter/miscopcodes.hpp +++ b/components/interpreter/miscopcodes.hpp @@ -12,6 +12,8 @@ #include "runtime.hpp" #include "defines.hpp" +#include + namespace Interpreter { inline std::string formatMessage (const std::string& message, Runtime& runtime) @@ -140,15 +142,13 @@ namespace Interpreter virtual void execute (Runtime& runtime) { - double r = static_cast (std::rand()) / RAND_MAX; // [0, 1) - Type_Integer limit = runtime[0].mInteger; if (limit<0) throw std::runtime_error ( "random: argument out of range (Don't be so negative!)"); - Type_Integer value = static_cast (r*limit); // [o, limit) + Type_Integer value = OEngine::Misc::Rng::rollDice(limit); // [o, limit) runtime[0].mInteger = value; } From 15f9c1ddcf25e3ec705b7a65b8d01ceecf4d069f Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 21 Mar 2015 23:10:52 +0100 Subject: [PATCH 0793/3725] NiBSPArrayController works --- apps/opencs/view/render/object.cpp | 2 +- apps/opencs/view/render/previewwidget.cpp | 4 ++ apps/opencs/view/render/scenewidget.cpp | 7 +- components/nifosg/nifloader.cpp | 68 ++++++++---------- components/nifosg/particle.cpp | 88 +++++++++++++++++++++++ components/nifosg/particle.hpp | 66 +++++++++++++++++ 6 files changed, 193 insertions(+), 42 deletions(-) diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index 2434343c9..f21e8dd4d 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -60,7 +60,7 @@ void CSVRender::Object::update() Nif::NIFFilePtr file(new Nif::NIFFile(mVFS->get(path), path)); - loader.load(file, mBaseNode); + loader.loadAsSkeleton(file, mBaseNode); //mObject->setVisibilityFlags (Element_Reference); diff --git a/apps/opencs/view/render/previewwidget.cpp b/apps/opencs/view/render/previewwidget.cpp index ee43ac13c..8802b5cf3 100644 --- a/apps/opencs/view/render/previewwidget.cpp +++ b/apps/opencs/view/render/previewwidget.cpp @@ -4,6 +4,8 @@ #include #include +#include + #include "../../model/world/data.hpp" #include "../../model/world/idtable.hpp" @@ -13,6 +15,8 @@ CSVRender::PreviewWidget::PreviewWidget (const VFS::Manager* vfs, CSMWorld::Data { //setNavigation (&mOrbit); + setCameraManipulator(new osgGA::TrackballManipulator); + QAbstractItemModel *referenceables = mData.getTableModel (CSMWorld::UniversalId::Type_Referenceables); diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index 2f28c06df..2dc5bdbc6 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -15,7 +15,6 @@ #include #include -#include #include namespace CSVRender @@ -72,14 +71,16 @@ SceneWidget::SceneWidget(QWidget *parent, Qt::WindowFlags f) // Press S to reveal profiling stats addEventHandler(new osgViewer::StatsHandler); - setCameraManipulator(new osgGA::TrackballManipulator); - // Only render when the camera position changed, or content flagged dirty //setRunFrameScheme(osgViewer::ViewerBase::ON_DEMAND); setRunFrameScheme(osgViewer::ViewerBase::CONTINUOUS); + getCamera()->setCullMask(~(0x1)); + connect( &mTimer, SIGNAL(timeout()), this, SLOT(update()) ); mTimer.start( 10 ); + + realize(); } void SceneWidget::paintEvent(QPaintEvent *event) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index dcab80707..27cce16fd 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -64,6 +64,18 @@ namespace return toMatrix(node->trafo); } + void getAllNiNodes(const Nif::Node* node, std::vector& outIndices) + { + const Nif::NiNode* ninode = dynamic_cast(node); + if (ninode) + { + outIndices.push_back(ninode->recIndex); + for (unsigned int i=0; ichildren.length(); ++i) + if (!ninode->children[i].empty()) + getAllNiNodes(ninode->children[i].getPtr(), outIndices); + } + } + osg::BlendFunc::BlendFuncMode getBlendMode(int mode) { switch(mode) @@ -328,13 +340,6 @@ namespace NifOsg toSetup->mFunction = boost::shared_ptr(new ControllerFunction(ctrl, 1 /*autoPlay*/)); } - class RecIndexHolder : public osg::Referenced - { - public: - RecIndexHolder(int index) : mIndex(index) {} - int mIndex; - }; - void Loader::handleNode(const Nif::Node* nifNode, osg::Group* parentNode, bool createSkeleton, std::map boundTextures, int animflags, int particleflags, bool collisionNode) { @@ -356,6 +361,10 @@ namespace NifOsg transformNode = new osg::MatrixTransform(toMatrix(nifNode->trafo)); } + // UserData used for a variety of features: + // - finding the correct emitter node for a particle system + // - establishing connections to the animated collision shapes, which are handled in a separate loader + // - finding a random child NiNode in NiBspArrayController transformNode->setUserData(new RecIndexHolder(nifNode->recIndex)); if (nifNode->recType == Nif::RC_NiBSAnimationNode) @@ -543,32 +552,6 @@ namespace NifOsg } } - class FindEmitterNode : public osg::NodeVisitor - { - public: - FindEmitterNode(int recIndex) - : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) - , mFound(NULL) - , mRecIndex(recIndex) - { - } - - virtual void apply(osg::Node &searchNode) - { - if (searchNode.getUserData()) - { - RecIndexHolder* holder = static_cast(searchNode.getUserData()); - if (holder->mIndex == mRecIndex) - mFound = static_cast(&searchNode); - } - traverse(searchNode); - } - - osg::Group* mFound; - private: - int mRecIndex; - }; - void Loader::handleParticleSystem(const Nif::Node *nifNode, osg::Group *parentNode, int animflags, int particleflags) { osg::ref_ptr partsys (new ParticleSystem); @@ -582,8 +565,6 @@ namespace NifOsg else return; - // TODO: add special handling for NiBSPArrayController - const Nif::NiParticleSystemController* partctrl = NULL; for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next) { @@ -598,6 +579,12 @@ namespace NifOsg return; } + std::vector targets; + if (partctrl->recType == Nif::RC_NiBSPArrayController) + { + getAllNiNodes(partctrl->emitter.getPtr(), targets); + } + osgParticle::ParticleProcessor::ReferenceFrame rf = (particleflags & Nif::NiNode::ParticleFlag_LocalSpace) ? osgParticle::ParticleProcessor::RELATIVE_RF : osgParticle::ParticleProcessor::ABSOLUTE_RF; @@ -638,7 +625,7 @@ namespace NifOsg // ---- emitter - osg::ref_ptr emitter = new osgParticle::ModularEmitter; + osg::ref_ptr emitter = new Emitter(targets); emitter->setParticleSystem(partsys); emitter->setReferenceFrame(osgParticle::ParticleProcessor::RELATIVE_RF); @@ -668,7 +655,7 @@ namespace NifOsg // This seems to be true for all NIF files in the game that I've checked, suggesting that NIFs work similar to OSG with regards to update order. // If something ever violates this assumption, the worst that could happen is the culling being one frame late, which wouldn't be a disaster. - FindEmitterNode find (partctrl->emitter->recIndex); + FindRecIndexVisitor find (partctrl->emitter->recIndex); mRootNode->accept(find); if (!find.mFound) { @@ -676,6 +663,9 @@ namespace NifOsg return; } osg::Group* emitterNode = find.mFound; + + // Emitter attached to the emitter node. Note one side effect of the emitter using the CullVisitor is that hiding its node + // actually causes the emitter to stop firing. Convenient, because MW behaves this way too! emitterNode->addChild(emitter); osg::ref_ptr callback(new ParticleSystemController(partctrl)); @@ -852,6 +842,7 @@ namespace NifOsg geometry = new osg::Geometry; osg::ref_ptr geode (new osg::Geode); + geode->setName(triShape->name); // name will be used for part filtering triShapeToGeometry(triShape, geometry, geode, boundTextures, animflags); geode->addDrawable(geometry); @@ -862,6 +853,7 @@ namespace NifOsg void Loader::handleSkinnedTriShape(const Nif::NiTriShape *triShape, osg::Group *parentNode, const std::map& boundTextures, int animflags) { osg::ref_ptr geode (new osg::Geode); + geode->setName(triShape->name); // name will be used for part filtering osg::ref_ptr geometry (new osg::Geometry); triShapeToGeometry(triShape, geometry, geode, boundTextures, animflags); @@ -969,7 +961,7 @@ namespace NifOsg case Nif::RC_NiVertexColorProperty: case Nif::RC_NiSpecularProperty: { - // TODO: handle these in handleTriShape so we know whether vertex colors are available + // Handled in handleTriShape so we know whether vertex colors are available break; } case Nif::RC_NiAlphaProperty: diff --git a/components/nifosg/particle.cpp b/components/nifosg/particle.cpp index 77e5f16df..934ef51eb 100644 --- a/components/nifosg/particle.cpp +++ b/components/nifosg/particle.cpp @@ -191,4 +191,92 @@ void GravityAffector::operate(osgParticle::Particle *particle, double dt) } } +Emitter::Emitter() + : osgParticle::Emitter() +{ +} + +Emitter::Emitter(const Emitter ©, const osg::CopyOp ©op) + : osgParticle::Emitter(copy, copyop) + , mTargets(copy.mTargets) +{ +} + +Emitter::Emitter(const std::vector &targets) + : mTargets(targets) +{ +} + +void Emitter::setShooter(osgParticle::Shooter *shooter) +{ + mShooter = shooter; +} + +void Emitter::setPlacer(osgParticle::Placer *placer) +{ + mPlacer = placer; +} + +void Emitter::setCounter(osgParticle::Counter *counter) +{ + mCounter = counter; +} + +void Emitter::emitParticles(double dt) +{ + osg::Matrix worldToPs; + osg::MatrixList worldMats = getParticleSystem()->getWorldMatrices(); + if (!worldMats.empty()) + { + const osg::Matrix psToWorld = worldMats[0]; + worldToPs = osg::Matrix::inverse(psToWorld); + } + + const osg::Matrix& ltw = getLocalToWorldMatrix(); + const osg::Matrix& previous_ltw = getPreviousLocalToWorldMatrix(); + const osg::Matrix emitterToPs = ltw * worldToPs; + const osg::Matrix prevEmitterToPs = previous_ltw * worldToPs; + + int n = mCounter->numParticlesToCreate(dt); + + osg::Matrix transform; + if (!mTargets.empty()) + { + int randomRecIndex = mTargets[(std::rand() / (static_cast(RAND_MAX)+1.0)) * mTargets.size()]; + + // we could use a map here for faster lookup + FindRecIndexVisitor visitor(randomRecIndex); + getParent(0)->accept(visitor); + + if (!visitor.mFound) + { + std::cerr << "Emitter: Can't find emitter node" << randomRecIndex << std::endl; + return; + } + + osg::NodePath path = visitor.mFoundPath; + path.erase(path.begin()); + transform = osg::computeLocalToWorld(path); + } + + for (int i=0; icreateParticle(0); + if (P) + { + mPlacer->place(P); + + P->transformPositionVelocity(transform); + + mShooter->shoot(P); + + // Now need to transform the position and velocity because we having a moving model. + // (is this actually how MW works?) + float r = ((float)rand()/(float)RAND_MAX); + P->transformPositionVelocity(emitterToPs, prevEmitterToPs, r); + //P->transformPositionVelocity(ltw); + } + } +} + } diff --git a/components/nifosg/particle.hpp b/components/nifosg/particle.hpp index 1f3905089..1c8174e8a 100644 --- a/components/nifosg/particle.hpp +++ b/components/nifosg/particle.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include @@ -151,6 +152,71 @@ namespace NifOsg osg::Vec3f mCachedWorldPositionDirection; }; + + class RecIndexHolder : public osg::Referenced + { + public: + RecIndexHolder(int index) : mIndex(index) {} + int mIndex; + }; + + // NodeVisitor to find a child node with the given record index, stored in the node's user data. + class FindRecIndexVisitor : public osg::NodeVisitor + { + public: + FindRecIndexVisitor(int recIndex) + : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) + , mFound(NULL) + , mRecIndex(recIndex) + { + } + + virtual void apply(osg::Node &searchNode) + { + if (searchNode.getUserData()) + { + RecIndexHolder* holder = static_cast(searchNode.getUserData()); + if (holder->mIndex == mRecIndex) + { + mFound = static_cast(&searchNode); + mFoundPath = getNodePath(); + return; + } + } + traverse(searchNode); + } + + osg::Group* mFound; + osg::NodePath mFoundPath; + private: + int mRecIndex; + }; + + // Subclass emitter to support randomly choosing one of the child node's transforms for the emit position of new particles. + class Emitter : public osgParticle::Emitter + { + public: + Emitter(const std::vector& targets); + Emitter(); + Emitter(const Emitter& copy, const osg::CopyOp& copyop); + + META_Object(NifOsg, NifOsg::Emitter) + + virtual void emitParticles(double dt); + + void setShooter(osgParticle::Shooter* shooter); + void setPlacer(osgParticle::Placer* placer); + void setCounter(osgParticle::Counter* counter); + + private: + // NIF Record indices + std::vector mTargets; + + osg::ref_ptr mPlacer; + osg::ref_ptr mShooter; + osg::ref_ptr mCounter; + }; + } #endif From 5cb61fa01cc8cbaacec8f348f473bff7d3781619 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 22 Mar 2015 17:25:23 +0100 Subject: [PATCH 0794/3725] Don't mark gold as stolen, adjust stolen tooltip (Fixes #2465) --- apps/openmw/mwgui/tooltips.cpp | 5 ++++- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 4 +++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 4e03b788a..4e83c25db 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -593,7 +593,10 @@ namespace MWGui for (std::vector >::const_iterator it = itemOwners.begin(); it != itemOwners.end(); ++it) { - ret += std::string("\nStolen from ") + it->first; + if (it->second == std::numeric_limits::max()) + ret += std::string("\nStolen from ") + it->first; // for legacy (ESS) savegames + else + ret += std::string("\nStolen ") + MyGUI::utility::toString(it->second) + " from " + it->first; } ret += getMiscString(cellref.getGlobalVariable(), "Global"); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 0d4518f87..617f38daf 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1030,7 +1030,9 @@ namespace MWMechanics owner.second = true; } Misc::StringUtils::toLower(owner.first); - mStolenItems[Misc::StringUtils::lowerCase(item.getClass().getId(item))][owner] += count; + + if (!Misc::StringUtils::ciEqual(item.getCellRef().getRefId(), MWWorld::ContainerStore::sGoldId)) + mStolenItems[Misc::StringUtils::lowerCase(item.getClass().getId(item))][owner] += count; commitCrime(ptr, victim, OT_Theft, item.getClass().getValue(item) * count); } From 2db5df77f030ef053a008ea682be6e950a106474 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 22 Mar 2015 22:52:44 +0100 Subject: [PATCH 0795/3725] Change rotation/scale workaround in preparation for loading .kf controllers --- components/CMakeLists.txt | 2 +- components/nif/niftypes.hpp | 2 +- components/nifosg/controller.cpp | 40 +++++++++++++++++++------- components/nifosg/controller.hpp | 7 ++--- components/nifosg/nifloader.cpp | 17 +++++++---- components/nifosg/particle.cpp | 24 ++++++++++++++++ components/nifosg/particle.hpp | 33 +++------------------ components/nifosg/userdata.hpp | 49 ++++++++++++++++++++++++++++++++ 8 files changed, 121 insertions(+), 53 deletions(-) create mode 100644 components/nifosg/userdata.hpp diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index a78f164a6..e0ddeb254 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -43,7 +43,7 @@ add_component_dir (nif ) add_component_dir (nifosg - nifloader controller particle + nifloader controller particle userdata ) #add_component_dir (nifcache diff --git a/components/nif/niftypes.hpp b/components/nif/niftypes.hpp index 4f6998200..7fefb92a2 100644 --- a/components/nif/niftypes.hpp +++ b/components/nif/niftypes.hpp @@ -46,7 +46,7 @@ struct Matrix3 struct Transformation { osg::Vec3f pos; - Matrix3 rotation; + Matrix3 rotation; // this can contain scale components too, including negative and nonuniform scales float scale; static const Transformation& getIdentity() diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index 01671dbd8..d61a8937a 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -4,15 +4,17 @@ #include #include #include +#include +#include #include #include -#include - #include +#include "userdata.hpp" + namespace NifOsg { @@ -76,13 +78,10 @@ KeyframeController::KeyframeController(const KeyframeController ©, const osg , mTranslations(copy.mTranslations) , mScales(copy.mScales) , mNif(copy.mNif) - , mInitialQuat(copy.mInitialQuat) - , mInitialScale(copy.mInitialScale) { } -KeyframeController::KeyframeController(const Nif::NIFFilePtr &nif, const Nif::NiKeyframeData *data, - osg::Quat initialQuat, float initialScale) +KeyframeController::KeyframeController(const Nif::NIFFilePtr &nif, const Nif::NiKeyframeData *data) : mRotations(&data->mRotations) , mXRotations(&data->mXRotations) , mYRotations(&data->mYRotations) @@ -90,9 +89,8 @@ KeyframeController::KeyframeController(const Nif::NIFFilePtr &nif, const Nif::Ni , mTranslations(&data->mTranslations) , mScales(&data->mScales) , mNif(nif) - , mInitialQuat(initialQuat) - , mInitialScale(initialScale) -{ } +{ +} osg::Quat KeyframeController::interpKey(const Nif::QuaternionKeyMap::MapType &keys, float time) { @@ -154,15 +152,35 @@ void KeyframeController::operator() (osg::Node* node, osg::NodeVisitor* nv) float time = getInputValue(nv); + NodeUserData* userdata = static_cast(trans->getUserDataContainer()->getUserObject(0)); + Nif::Matrix3& rot = userdata->mRotationScale; + + bool setRot = false; if(mRotations->mKeys.size() > 0) + { mat.setRotate(interpKey(mRotations->mKeys, time)); + setRot = true; + } else if (!mXRotations->mKeys.empty() || !mYRotations->mKeys.empty() || !mZRotations->mKeys.empty()) + { mat.setRotate(getXYZRotation(time)); + setRot = true; + } else - mat.setRotate(mInitialQuat); + { + // no rotation specified, use the previous value from the UserData + for (int i=0;i<3;++i) + for (int j=0;j<3;++j) + mat(j,i) = rot.mValues[i][j]; // NB column/row major difference + } + + if (setRot) // copy the new values back to the UserData + for (int i=0;i<3;++i) + for (int j=0;j<3;++j) + rot.mValues[i][j] = mat(j,i); // NB column/row major difference // let's hope no one's using multiple KeyframeControllers on the same node (not that would make any sense...) - float scale = mInitialScale; + float& scale = userdata->mScale; if(mScales->mKeys.size() > 0) scale = interpKey(mScales->mKeys, time); diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index 5a9af6324..fb24fb518 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -147,11 +147,9 @@ namespace NifOsg const Nif::FloatKeyMap* mZRotations; const Nif::Vector3KeyMap* mTranslations; const Nif::FloatKeyMap* mScales; + // TODO: we don't need to keep the whole NIF around, just change the key maps to Referenced Nif::NIFFilePtr mNif; // Hold a SharedPtr to make sure key lists stay valid - osg::Quat mInitialQuat; - float mInitialScale; - using ValueInterpolator::interpKey; @@ -161,8 +159,7 @@ namespace NifOsg public: /// @note The NiKeyFrameData must be valid as long as this KeyframeController exists. - KeyframeController(const Nif::NIFFilePtr& nif, const Nif::NiKeyframeData *data, - osg::Quat initialQuat, float initialScale); + KeyframeController(const Nif::NIFFilePtr& nif, const Nif::NiKeyframeData *data); KeyframeController(); KeyframeController(const KeyframeController& copy, const osg::CopyOp& copyop); diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 27cce16fd..edc011c54 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -42,6 +42,7 @@ #include #include "particle.hpp" +#include "userdata.hpp" namespace { @@ -191,12 +192,13 @@ namespace { if (_referenceFrame==RELATIVE_RF) { + const NifOsg::NodeUserData* userdata = static_cast(getUserDataContainer()->getUserObject(0)); + matrix.preMult(_matrix); - osg::Vec3 scale = matrix.getScale(); matrix.setRotate(osg::Quat()); - matrix(0,0) = scale.x(); - matrix(1,1) = scale.y(); - matrix(2,2) = scale.z(); + matrix(0,0) = userdata->mScale; + matrix(1,1) = userdata->mScale; + matrix(2,2) = userdata->mScale; } else // absolute { @@ -365,7 +367,10 @@ namespace NifOsg // - finding the correct emitter node for a particle system // - establishing connections to the animated collision shapes, which are handled in a separate loader // - finding a random child NiNode in NiBspArrayController - transformNode->setUserData(new RecIndexHolder(nifNode->recIndex)); + // - storing the previous 3x3 rotation and scale values for when a KeyframeController wants to + // change only certain elements of the 4x4 transform + transformNode->getOrCreateUserDataContainer()->addUserObject( + new NodeUserData(nifNode->recIndex, nifNode->trafo.scale, nifNode->trafo.rotation)); if (nifNode->recType == Nif::RC_NiBSAnimationNode) animflags |= nifNode->flags; @@ -471,7 +476,7 @@ namespace NifOsg for (int j=0;j<3;++j) mat(j,i) = nifNode->trafo.rotation.mValues[i][j]; - osg::ref_ptr callback(new KeyframeController(mNif, key->data.getPtr(), mat.getRotate(), nifNode->trafo.scale)); + osg::ref_ptr callback(new KeyframeController(mNif, key->data.getPtr())); setupController(key, callback, animflags); transformNode->addUpdateCallback(callback); diff --git a/components/nifosg/particle.cpp b/components/nifosg/particle.cpp index 934ef51eb..16c2b692c 100644 --- a/components/nifosg/particle.cpp +++ b/components/nifosg/particle.cpp @@ -8,6 +8,8 @@ #include +#include "userdata.hpp" + namespace NifOsg { @@ -279,4 +281,26 @@ void Emitter::emitParticles(double dt) } } +FindRecIndexVisitor::FindRecIndexVisitor(int recIndex) + : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) + , mFound(NULL) + , mRecIndex(recIndex) +{ +} + +void FindRecIndexVisitor::apply(osg::Node &searchNode) +{ + if (searchNode.getUserDataContainer() && searchNode.getUserDataContainer()->getNumUserObjects()) + { + NodeUserData* holder = dynamic_cast(searchNode.getUserDataContainer()->getUserObject(0)); + if (holder && holder->mIndex == mRecIndex) + { + mFound = static_cast(&searchNode); + mFoundPath = getNodePath(); + return; + } + } + traverse(searchNode); +} + } diff --git a/components/nifosg/particle.hpp b/components/nifosg/particle.hpp index 1c8174e8a..01e06f471 100644 --- a/components/nifosg/particle.hpp +++ b/components/nifosg/particle.hpp @@ -7,6 +7,7 @@ #include #include +#include #include #include @@ -152,39 +153,13 @@ namespace NifOsg osg::Vec3f mCachedWorldPositionDirection; }; - - class RecIndexHolder : public osg::Referenced - { - public: - RecIndexHolder(int index) : mIndex(index) {} - int mIndex; - }; - - // NodeVisitor to find a child node with the given record index, stored in the node's user data. + // NodeVisitor to find a child node with the given record index, stored in the node's user data container. class FindRecIndexVisitor : public osg::NodeVisitor { public: - FindRecIndexVisitor(int recIndex) - : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) - , mFound(NULL) - , mRecIndex(recIndex) - { - } + FindRecIndexVisitor(int recIndex); - virtual void apply(osg::Node &searchNode) - { - if (searchNode.getUserData()) - { - RecIndexHolder* holder = static_cast(searchNode.getUserData()); - if (holder->mIndex == mRecIndex) - { - mFound = static_cast(&searchNode); - mFoundPath = getNodePath(); - return; - } - } - traverse(searchNode); - } + virtual void apply(osg::Node &searchNode); osg::Group* mFound; osg::NodePath mFoundPath; diff --git a/components/nifosg/userdata.hpp b/components/nifosg/userdata.hpp new file mode 100644 index 000000000..9770890b0 --- /dev/null +++ b/components/nifosg/userdata.hpp @@ -0,0 +1,49 @@ +#ifndef OPENMW_COMPONENTS_NIFOSG_USERDATA_H +#define OPENMW_COMPONENTS_NIFOSG_USERDATA_H + +#include + +#include + +namespace NifOsg +{ + + // Note if you are copying a scene graph with this user data you should use the DEEP_COPY_USERDATA copyop. + class NodeUserData : public osg::Object + { + public: + NodeUserData(int index, float scale, const Nif::Matrix3& rotationScale) + : mIndex(index), mScale(scale), mRotationScale(rotationScale) + { + } + NodeUserData() + : mIndex(0), mScale(0) + { + } + NodeUserData(const NodeUserData& copy, const osg::CopyOp& copyop) + : Object(copy, copyop) + , mIndex(copy.mIndex) + , mScale(copy.mScale) + , mRotationScale(copy.mRotationScale) + { + } + + META_Object(NifOsg, NodeUserData) + + // NIF record index + int mIndex; + + // Hack: account for Transform differences between OSG and NIFs. + // OSG uses a 4x4 matrix, NIF's use a 3x3 rotationScale, float scale, and vec3 position. + // Decomposing the original components from the 4x4 matrix isn't possible, which causes + // problems when a KeyframeController wants to change only one of these components. So + // we store the scale and rotation components separately here. + // Note for a cleaner solution it would be possible to write a custom Transform node, + // but then we have to fork osgAnimation :/ + float mScale; + Nif::Matrix3 mRotationScale; + }; + +} + +#endif From 9242e6d256601c220597ed9851e1eeac26e81001 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 22 Mar 2015 23:47:49 +0100 Subject: [PATCH 0796/3725] Avoid copying keyframes in controller instances --- components/nif/data.cpp | 37 +++++++++++++------ components/nif/data.hpp | 23 ++++++------ components/nif/nifkey.hpp | 7 ++++ components/nifosg/controller.cpp | 63 +++++++++++++++++--------------- components/nifosg/controller.hpp | 33 ++++++++--------- components/nifosg/nifloader.cpp | 17 +-------- components/nifosg/particle.cpp | 2 +- 7 files changed, 95 insertions(+), 87 deletions(-) diff --git a/components/nif/data.cpp b/components/nif/data.cpp index c4de1e1bf..1fef8d56f 100644 --- a/components/nif/data.cpp +++ b/components/nif/data.cpp @@ -115,18 +115,23 @@ void NiRotatingParticlesData::read(NIFStream *nif) void NiPosData::read(NIFStream *nif) { - mKeyList.read(nif); + mKeyList.reset(new Vector3KeyMap); + mKeyList->read(nif); } void NiUVData::read(NIFStream *nif) { for(int i = 0;i < 4;i++) - mKeyList[i].read(nif); + { + mKeyList[i].reset(new FloatKeyMap); + mKeyList[i]->read(nif); + } } void NiFloatData::read(NIFStream *nif) { - mKeyList.read(nif); + mKeyList.reset(new FloatKeyMap); + mKeyList->read(nif); } void NiPixelData::read(NIFStream *nif) @@ -163,7 +168,8 @@ void NiPixelData::read(NIFStream *nif) void NiColorData::read(NIFStream *nif) { - mKeyMap.read(nif); + mKeyMap.reset(new Vector4KeyMap); + mKeyMap->read(nif); } void NiVisData::read(NIFStream *nif) @@ -215,24 +221,31 @@ void NiMorphData::read(NIFStream *nif) mMorphs.resize(morphCount); for(int i = 0;i < morphCount;i++) { - mMorphs[i].mData.read(nif, true); + mMorphs[i].mKeyFrames.reset(new FloatKeyMap); + mMorphs[i].mKeyFrames->read(nif, true); nif->getVector3s(mMorphs[i].mVertices, vertCount); } } void NiKeyframeData::read(NIFStream *nif) { - mRotations.read(nif); - if(mRotations.mInterpolationType == mRotations.sXYZInterpolation) + mRotations.reset(new QuaternionKeyMap); + mRotations->read(nif); + if(mRotations->mInterpolationType == Vector3KeyMap::sXYZInterpolation) { //Chomp unused float nif->getFloat(); - mXRotations.read(nif, true); - mYRotations.read(nif, true); - mZRotations.read(nif, true); + mXRotations.reset(new FloatKeyMap); + mYRotations.reset(new FloatKeyMap); + mZRotations.reset(new FloatKeyMap); + mXRotations->read(nif, true); + mYRotations->read(nif, true); + mZRotations->read(nif, true); } - mTranslations.read(nif); - mScales.read(nif); + mTranslations.reset(new Vector3KeyMap); + mTranslations->read(nif); + mScales.reset(new FloatKeyMap); + mScales->read(nif); } } // Namespace diff --git a/components/nif/data.hpp b/components/nif/data.hpp index 3b1244831..702fbf313 100644 --- a/components/nif/data.hpp +++ b/components/nif/data.hpp @@ -78,7 +78,7 @@ public: class NiPosData : public Record { public: - Vector3KeyMap mKeyList; + Vector3KeyMapPtr mKeyList; void read(NIFStream *nif); }; @@ -86,7 +86,7 @@ public: class NiUVData : public Record { public: - FloatKeyMap mKeyList[4]; + FloatKeyMapPtr mKeyList[4]; void read(NIFStream *nif); }; @@ -94,7 +94,7 @@ public: class NiFloatData : public Record { public: - FloatKeyMap mKeyList; + FloatKeyMapPtr mKeyList; void read(NIFStream *nif); }; @@ -111,7 +111,7 @@ public: class NiColorData : public Record { public: - Vector4KeyMap mKeyMap; + Vector4KeyMapPtr mKeyMap; void read(NIFStream *nif); }; @@ -164,7 +164,7 @@ public: struct NiMorphData : public Record { struct MorphData { - FloatKeyMap mData; + FloatKeyMapPtr mKeyFrames; std::vector mVertices; }; std::vector mMorphs; @@ -175,14 +175,15 @@ struct NiMorphData : public Record struct NiKeyframeData : public Record { - QuaternionKeyMap mRotations; + QuaternionKeyMapPtr mRotations; - FloatKeyMap mXRotations; - FloatKeyMap mYRotations; - FloatKeyMap mZRotations; + // may be NULL + FloatKeyMapPtr mXRotations; + FloatKeyMapPtr mYRotations; + FloatKeyMapPtr mZRotations; - Vector3KeyMap mTranslations; - FloatKeyMap mScales; + Vector3KeyMapPtr mTranslations; + FloatKeyMapPtr mScales; void read(NIFStream *nif); }; diff --git a/components/nif/nifkey.hpp b/components/nif/nifkey.hpp index 98687a2f9..d702d0292 100644 --- a/components/nif/nifkey.hpp +++ b/components/nif/nifkey.hpp @@ -8,6 +8,8 @@ #include #include +#include + #include "niffile.hpp" namespace Nif @@ -146,5 +148,10 @@ typedef KeyMapT Vector3KeyMap; typedef KeyMapT Vector4KeyMap; typedef KeyMapT QuaternionKeyMap; +typedef boost::shared_ptr FloatKeyMapPtr; +typedef boost::shared_ptr Vector3KeyMapPtr; +typedef boost::shared_ptr Vector4KeyMapPtr; +typedef boost::shared_ptr QuaternionKeyMapPtr; + } // Namespace #endif //#ifndef OPENMW_COMPONENTS_NIF_NIFKEY_HPP diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index d61a8937a..88802f81e 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -77,18 +77,16 @@ KeyframeController::KeyframeController(const KeyframeController ©, const osg , mZRotations(copy.mZRotations) , mTranslations(copy.mTranslations) , mScales(copy.mScales) - , mNif(copy.mNif) { } -KeyframeController::KeyframeController(const Nif::NIFFilePtr &nif, const Nif::NiKeyframeData *data) - : mRotations(&data->mRotations) - , mXRotations(&data->mXRotations) - , mYRotations(&data->mYRotations) - , mZRotations(&data->mZRotations) - , mTranslations(&data->mTranslations) - , mScales(&data->mScales) - , mNif(nif) +KeyframeController::KeyframeController(const Nif::NiKeyframeData *data) + : mRotations(data->mRotations) + , mXRotations(data->mXRotations) + , mYRotations(data->mYRotations) + , mZRotations(data->mZRotations) + , mTranslations(data->mTranslations) + , mScales(data->mScales) { } @@ -127,9 +125,13 @@ osg::Quat KeyframeController::interpKey(const Nif::QuaternionKeyMap::MapType &ke osg::Quat KeyframeController::getXYZRotation(float time) const { - float xrot = interpKey(mXRotations->mKeys, time); - float yrot = interpKey(mYRotations->mKeys, time); - float zrot = interpKey(mZRotations->mKeys, time); + float xrot = 0, yrot = 0, zrot = 0; + if (mXRotations.get()) + xrot = interpKey(mXRotations->mKeys, time); + if (mYRotations.get()) + yrot = interpKey(mYRotations->mKeys, time); + if (mZRotations.get()) + zrot = interpKey(mZRotations->mKeys, time); osg::Quat xr(xrot, osg::Vec3f(1,0,0)); osg::Quat yr(yrot, osg::Vec3f(0,1,0)); osg::Quat zr(zrot, osg::Vec3f(0,0,1)); @@ -138,7 +140,7 @@ osg::Quat KeyframeController::getXYZRotation(float time) const osg::Vec3f KeyframeController::getTranslation(float time) const { - if(mTranslations->mKeys.size() > 0) + if(mTranslations.get() && mTranslations->mKeys.size() > 0) return interpKey(mTranslations->mKeys, time); return osg::Vec3f(); } @@ -156,12 +158,12 @@ void KeyframeController::operator() (osg::Node* node, osg::NodeVisitor* nv) Nif::Matrix3& rot = userdata->mRotationScale; bool setRot = false; - if(mRotations->mKeys.size() > 0) + if(mRotations.get() && !mRotations->mKeys.empty()) { mat.setRotate(interpKey(mRotations->mKeys, time)); setRot = true; } - else if (!mXRotations->mKeys.empty() || !mYRotations->mKeys.empty() || !mZRotations->mKeys.empty()) + else if (mXRotations.get() || mYRotations.get() || mZRotations.get()) { mat.setRotate(getXYZRotation(time)); setRot = true; @@ -179,17 +181,17 @@ void KeyframeController::operator() (osg::Node* node, osg::NodeVisitor* nv) for (int j=0;j<3;++j) rot.mValues[i][j] = mat(j,i); // NB column/row major difference - // let's hope no one's using multiple KeyframeControllers on the same node (not that would make any sense...) float& scale = userdata->mScale; - if(mScales->mKeys.size() > 0) + if(mScales.get() && !mScales->mKeys.empty()) scale = interpKey(mScales->mKeys, time); for (int i=0;i<3;++i) for (int j=0;j<3;++j) mat(i,j) *= scale; - if(mTranslations->mKeys.size() > 0) + if(mTranslations.get() && !mTranslations->mKeys.empty()) mat.setTrans(interpKey(mTranslations->mKeys, time)); + trans->setMatrix(mat); } @@ -217,13 +219,14 @@ GeomMorpherController::GeomMorpherController() GeomMorpherController::GeomMorpherController(const GeomMorpherController ©, const osg::CopyOp ©op) : osg::Drawable::UpdateCallback(copy, copyop) , Controller(copy) - , mMorphs(copy.mMorphs) + , mKeyFrames(copy.mKeyFrames) { } GeomMorpherController::GeomMorpherController(const Nif::NiMorphData *data) - : mMorphs(data->mMorphs) { + for (unsigned int i=0; imMorphs.size(); ++i) + mKeyFrames.push_back(data->mMorphs[i].mKeyFrames); } void GeomMorpherController::update(osg::NodeVisitor *nv, osg::Drawable *drawable) @@ -233,15 +236,15 @@ void GeomMorpherController::update(osg::NodeVisitor *nv, osg::Drawable *drawable { if (hasInput()) { - if (mMorphs.size() <= 1) + if (mKeyFrames.size() <= 1) return; float input = getInputValue(nv); int i = 0; - for (std::vector::iterator it = mMorphs.begin()+1; it != mMorphs.end(); ++it,++i) + for (std::vector::iterator it = mKeyFrames.begin()+1; it != mKeyFrames.end(); ++it,++i) { float val = 0; - if (!it->mData.mKeys.empty()) - val = interpKey(it->mData.mKeys, input); + if (!(*it)->mKeys.empty()) + val = interpKey((*it)->mKeys, input); val = std::max(0.f, std::min(1.f, val)); morphGeom->setWeight(i, val); @@ -281,10 +284,10 @@ void UVController::operator()(osg::Node* node, osg::NodeVisitor* nv) { osg::StateSet* stateset = node->getStateSet(); float value = getInputValue(nv); - float uTrans = interpKey(mUTrans.mKeys, value, 0.0f); - float vTrans = interpKey(mVTrans.mKeys, value, 0.0f); - float uScale = interpKey(mUScale.mKeys, value, 1.0f); - float vScale = interpKey(mVScale.mKeys, value, 1.0f); + float uTrans = interpKey(mUTrans->mKeys, value, 0.0f); + float vTrans = interpKey(mVTrans->mKeys, value, 0.0f); + float uScale = interpKey(mUScale->mKeys, value, 1.0f); + float vScale = interpKey(mVScale->mKeys, value, 1.0f); osg::Matrixf mat = osg::Matrixf::scale(uScale, vScale, 1); mat.setTrans(uTrans, vTrans, 0); @@ -360,7 +363,7 @@ void AlphaController::operator () (osg::Node* node, osg::NodeVisitor* nv) if (hasInput()) { osg::StateSet* stateset = node->getStateSet(); - float value = interpKey(mData.mKeys, getInputValue(nv)); + float value = interpKey(mData->mKeys, getInputValue(nv)); osg::Material* mat = dynamic_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); if (mat) { @@ -392,7 +395,7 @@ void MaterialColorController::operator() (osg::Node* node, osg::NodeVisitor* nv) if (hasInput()) { osg::StateSet* stateset = node->getStateSet(); - osg::Vec3f value = interpKey(mData.mKeys, getInputValue(nv)); + osg::Vec3f value = interpKey(mData->mKeys, getInputValue(nv)); osg::Material* mat = dynamic_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); if (mat) { diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index fb24fb518..eb9b95a81 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -135,20 +135,20 @@ namespace NifOsg virtual void update(osg::NodeVisitor* nv, osg::Drawable* drawable); private: - std::vector mMorphs; + std::vector mKeyFrames; }; class KeyframeController : public osg::NodeCallback, public Controller, public ValueInterpolator { private: - const Nif::QuaternionKeyMap* mRotations; - const Nif::FloatKeyMap* mXRotations; - const Nif::FloatKeyMap* mYRotations; - const Nif::FloatKeyMap* mZRotations; - const Nif::Vector3KeyMap* mTranslations; - const Nif::FloatKeyMap* mScales; - // TODO: we don't need to keep the whole NIF around, just change the key maps to Referenced - Nif::NIFFilePtr mNif; // Hold a SharedPtr to make sure key lists stay valid + Nif::QuaternionKeyMapPtr mRotations; + + Nif::FloatKeyMapPtr mXRotations; + Nif::FloatKeyMapPtr mYRotations; + Nif::FloatKeyMapPtr mZRotations; + + Nif::Vector3KeyMapPtr mTranslations; + Nif::FloatKeyMapPtr mScales; using ValueInterpolator::interpKey; @@ -158,8 +158,7 @@ namespace NifOsg osg::Quat getXYZRotation(float time) const; public: - /// @note The NiKeyFrameData must be valid as long as this KeyframeController exists. - KeyframeController(const Nif::NIFFilePtr& nif, const Nif::NiKeyframeData *data); + KeyframeController(const Nif::NiKeyframeData *data); KeyframeController(); KeyframeController(const KeyframeController& copy, const osg::CopyOp& copyop); @@ -183,10 +182,10 @@ namespace NifOsg virtual void operator() (osg::Node*, osg::NodeVisitor*); private: - Nif::FloatKeyMap mUTrans; - Nif::FloatKeyMap mVTrans; - Nif::FloatKeyMap mUScale; - Nif::FloatKeyMap mVScale; + Nif::FloatKeyMapPtr mUTrans; + Nif::FloatKeyMapPtr mVTrans; + Nif::FloatKeyMapPtr mUScale; + Nif::FloatKeyMapPtr mVScale; std::set mTextureUnits; }; @@ -210,7 +209,7 @@ namespace NifOsg class AlphaController : public osg::NodeCallback, public Controller, public ValueInterpolator { private: - Nif::FloatKeyMap mData; + Nif::FloatKeyMapPtr mData; public: AlphaController(const Nif::NiFloatData *data); @@ -225,7 +224,7 @@ namespace NifOsg class MaterialColorController : public osg::NodeCallback, public Controller, public ValueInterpolator { private: - Nif::Vector3KeyMap mData; + Nif::Vector3KeyMapPtr mData; public: MaterialColorController(const Nif::NiPosData *data); diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index edc011c54..1e69ee4f5 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -454,7 +454,6 @@ namespace NifOsg void Loader::handleNodeControllers(const Nif::Node* nifNode, osg::MatrixTransform* transformNode, int animflags) { - bool seenKeyframeCtrl = false; for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next) { if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active)) @@ -464,24 +463,10 @@ namespace NifOsg const Nif::NiKeyframeController *key = static_cast(ctrl.getPtr()); if(!key->data.empty()) { - if (seenKeyframeCtrl) - { - std::cerr << "Warning: multiple KeyframeControllers on the same node" << std::endl; - continue; - } - - // build the rotation part manually to avoid issues caused by scaling - osg::Matrixf mat; - for (int i=0;i<3;++i) - for (int j=0;j<3;++j) - mat(j,i) = nifNode->trafo.rotation.mValues[i][j]; - - osg::ref_ptr callback(new KeyframeController(mNif, key->data.getPtr())); + osg::ref_ptr callback(new KeyframeController(key->data.getPtr())); setupController(key, callback, animflags); transformNode->addUpdateCallback(callback); - - seenKeyframeCtrl = true; } } else if (ctrl->recType == Nif::RC_NiVisController) diff --git a/components/nifosg/particle.cpp b/components/nifosg/particle.cpp index 16c2b692c..25970c862 100644 --- a/components/nifosg/particle.cpp +++ b/components/nifosg/particle.cpp @@ -142,7 +142,7 @@ ParticleColorAffector::ParticleColorAffector(const ParticleColorAffector ©, void ParticleColorAffector::operate(osgParticle::Particle* particle, double /* dt */) { float time = static_cast(particle->getAge()/particle->getLifeTime()); - osg::Vec4f color = interpKey(mData.mKeyMap.mKeys, time, osg::Vec4f(1,1,1,1)); + osg::Vec4f color = interpKey(mData.mKeyMap->mKeys, time, osg::Vec4f(1,1,1,1)); particle->setColorRange(osgParticle::rangev4(color, color)); } From 6219a7bbfc6e9c4c611f5eac349dbcb8d684de63 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 23 Mar 2015 01:31:16 +0100 Subject: [PATCH 0797/3725] Add .kf loader --- components/nifosg/controller.cpp | 33 ++++++++ components/nifosg/controller.hpp | 37 +++++++-- components/nifosg/nifloader.cpp | 132 +++++++++++++++++++++++++++---- components/nifosg/nifloader.hpp | 20 +++-- 4 files changed, 193 insertions(+), 29 deletions(-) diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index 88802f81e..ef3157773 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -469,4 +469,37 @@ void ParticleSystemController::operator() (osg::Node* node, osg::NodeVisitor* nv traverse(node, nv); } +SourcedKeyframeController::SourcedKeyframeController(const Nif::NiKeyframeData *data, int sourceIndex) + : KeyframeController(data) + , mSourceIndex(sourceIndex) + , mEnabled(false) +{ +} + +SourcedKeyframeController::SourcedKeyframeController() + : mSourceIndex(0) + , mEnabled(false) +{ +} + +SourcedKeyframeController::SourcedKeyframeController(const SourcedKeyframeController ©, const osg::CopyOp ©op) + : KeyframeController(copy, copyop) + , mSourceIndex(copy.mSourceIndex) + , mEnabled(copy.mEnabled) +{ +} + +void SourcedKeyframeController::setEnabled(bool enabled) +{ + mEnabled = enabled; +} + +void SourcedKeyframeController::operator ()(osg::Node* node, osg::NodeVisitor* nv) +{ + if (mEnabled) + KeyframeController::operator()(node, nv); // calls traverse + else + traverse(node, nv); +} + } diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index eb9b95a81..17bf3ae75 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -140,6 +140,17 @@ namespace NifOsg class KeyframeController : public osg::NodeCallback, public Controller, public ValueInterpolator { + public: + KeyframeController(const Nif::NiKeyframeData *data); + KeyframeController(); + KeyframeController(const KeyframeController& copy, const osg::CopyOp& copyop); + + META_Object(NifOsg, KeyframeController) + + virtual osg::Vec3f getTranslation(float time) const; + + virtual void operator() (osg::Node*, osg::NodeVisitor*); + private: Nif::QuaternionKeyMapPtr mRotations; @@ -152,21 +163,33 @@ namespace NifOsg using ValueInterpolator::interpKey; - osg::Quat interpKey(const Nif::QuaternionKeyMap::MapType &keys, float time); osg::Quat getXYZRotation(float time) const; + }; + // Specialization of KeyframeController that remembers a "source index" for the animation source + // it came from, and can be enabled/disabled. Used for multiple animation sources support, i.e. .kf files. + // A SourcedKeyframeController is disabled by default and should be manually enabled when playing an animation from + // the relevant animation source. + class SourcedKeyframeController : public KeyframeController + { public: - KeyframeController(const Nif::NiKeyframeData *data); - KeyframeController(); - KeyframeController(const KeyframeController& copy, const osg::CopyOp& copyop); - - META_Object(NifOsg, KeyframeController) + SourcedKeyframeController(const Nif::NiKeyframeData* data, int sourceIndex); + SourcedKeyframeController(); + SourcedKeyframeController(const SourcedKeyframeController& copy, const osg::CopyOp& copyop); - virtual osg::Vec3f getTranslation(float time) const; + META_Object(NifOsg, SourcedKeyframeController) virtual void operator() (osg::Node*, osg::NodeVisitor*); + + int getSourceIndex() const; + + void setEnabled(bool enabled); + + private: + int mSourceIndex; + bool mEnabled; }; // Note we're using NodeCallback instead of StateSet::Callback because the StateSet callback doesn't support nesting diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 1e69ee4f5..c73bcbc96 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -248,6 +248,43 @@ namespace } }; + + // NodeVisitor that adds keyframe controllers to an existing scene graph, used when loading .kf files + class LoadKfVisitor : public osg::NodeVisitor + { + public: + LoadKfVisitor(std::map map, int sourceIndex) + : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) + , mMap(map) + , mSourceIndex(sourceIndex) + { + } + + void apply(osg::Node &node) + { + std::map::const_iterator found = mMap.find(node.getName()); + if (found != mMap.end()) + { + const Nif::NiKeyframeController* keyframectrl = found->second; + + osg::ref_ptr callback(new NifOsg::SourcedKeyframeController(keyframectrl->data.getPtr(), mSourceIndex)); + callback->mFunction = boost::shared_ptr(new NifOsg::ControllerFunction(keyframectrl, false)); + + // Insert in front of the callback list, to make sure UpdateBone is last. + // The order of SourcedKeyframeControllers doesn't matter since only one of them should be enabled at a time. + osg::ref_ptr old = node.getUpdateCallback(); + node.setUpdateCallback(callback); + callback->setNestedCallback(old); + } + + traverse(node); + } + + private: + std::map mMap; + int mSourceIndex; + }; + osg::ref_ptr handleMorphGeometry(const Nif::NiGeomMorpherController* morpher) { osg::ref_ptr morphGeom = new osgAnimation::MorphGeometry; @@ -270,38 +307,94 @@ namespace namespace NifOsg { - void Loader::load(Nif::NIFFilePtr nif, osg::Group *parentNode) + void Loader::loadKf(Nif::NIFFilePtr nif, osg::Node *rootNode, int sourceIndex) + { + if(nif->numRoots() < 1) + { + nif->warn("Found no root nodes"); + return; + } + + const Nif::Record *r = nif->getRoot(0); + assert(r != NULL); + + if(r->recType != Nif::RC_NiSequenceStreamHelper) + { + nif->warn("First root was not a NiSequenceStreamHelper, but a "+ + r->recName+"."); + return; + } + const Nif::NiSequenceStreamHelper *seq = static_cast(r); + + Nif::ExtraPtr extra = seq->extra; + if(extra.empty() || extra->recType != Nif::RC_NiTextKeyExtraData) + { + nif->warn("First extra data was not a NiTextKeyExtraData, but a "+ + (extra.empty() ? std::string("nil") : extra->recName)+"."); + return; + } + + //extractTextKeys(static_cast(extra.getPtr()), textKeys); + + std::map controllerMap; + + extra = extra->extra; + Nif::ControllerPtr ctrl = seq->controller; + for(;!extra.empty() && !ctrl.empty();(extra=extra->extra),(ctrl=ctrl->next)) + { + if(extra->recType != Nif::RC_NiStringExtraData || ctrl->recType != Nif::RC_NiKeyframeController) + { + nif->warn("Unexpected extra data "+extra->recName+" with controller "+ctrl->recName); + continue; + } + + if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active)) + continue; + + const Nif::NiStringExtraData *strdata = static_cast(extra.getPtr()); + const Nif::NiKeyframeController *key = static_cast(ctrl.getPtr()); + + if(key->data.empty()) + continue; + + controllerMap[strdata->string] = key; + } + + LoadKfVisitor visitor(controllerMap, sourceIndex); + rootNode->accept(visitor); + } + + osg::Node* Loader::load(Nif::NIFFilePtr nif, osg::Group *parentNode) { mNif = nif; if (nif->numRoots() < 1) { - nif->warn("Found no root nodes"); - return; + nif->fail("Found no root nodes"); } const Nif::Record* r = nif->getRoot(0); - assert(r != NULL); const Nif::Node* nifNode = dynamic_cast(r); if (nifNode == NULL) { - nif->warn("First root was not a node, but a " + r->recName); - return; + nif->fail("First root was not a node, but a " + r->recName); } mRootNode = parentNode; - handleNode(nifNode, parentNode, false, std::map(), 0, 0); + + osg::Node* created = handleNode(nifNode, parentNode, false, std::map(), 0, 0); + return created; } - void Loader::loadAsSkeleton(Nif::NIFFilePtr nif, osg::Group *parentNode) + osg::Node* Loader::loadAsSkeleton(Nif::NIFFilePtr nif, osg::Group *parentNode) { mNif = nif; if (nif->numRoots() < 1) { - nif->warn("Found no root nodes"); - return; + //nif->warn("Found no root nodes"); + nif->fail("Found no root nodes"); } const Nif::Record* r = nif->getRoot(0); @@ -310,17 +403,18 @@ namespace NifOsg const Nif::Node* nifNode = dynamic_cast(r); if (nifNode == NULL) { - nif->warn("First root was not a node, but a " + r->recName); - return; + //nif->warn("First root was not a node, but a " + r->recName); + nif->fail("First root was not a node, but a " + r->recName); } + osg::ref_ptr skel = new osgAnimation::Skeleton; + parentNode->addChild(skel); + mRootNode = parentNode; - osgAnimation::Skeleton* skel = new osgAnimation::Skeleton; - mSkeleton = skel; - mRootNode->addChild(mSkeleton); + handleNode(nifNode, skel, true, std::map(), 0, 0); - handleNode(nifNode, mSkeleton, true, std::map(), 0, 0); + return skel; } void Loader::applyNodeProperties(const Nif::Node *nifNode, osg::Node *applyTo, std::map& boundTextures, int animflags) @@ -342,7 +436,7 @@ namespace NifOsg toSetup->mFunction = boost::shared_ptr(new ControllerFunction(ctrl, 1 /*autoPlay*/)); } - void Loader::handleNode(const Nif::Node* nifNode, osg::Group* parentNode, bool createSkeleton, + osg::Node* Loader::handleNode(const Nif::Node* nifNode, osg::Group* parentNode, bool createSkeleton, std::map boundTextures, int animflags, int particleflags, bool collisionNode) { osg::ref_ptr transformNode; @@ -362,6 +456,7 @@ namespace NifOsg { transformNode = new osg::MatrixTransform(toMatrix(nifNode->trafo)); } + // Ignoring name for non-bone nodes for now. We might need it later in isolated cases, e.g. AttachLight. // UserData used for a variety of features: // - finding the correct emitter node for a particle system @@ -428,6 +523,8 @@ namespace NifOsg handleNode(children[i].getPtr(), transformNode, createSkeleton, boundTextures, animflags, particleflags, collisionNode); } } + + return transformNode; } void Loader::handleMeshControllers(const Nif::Node *nifNode, osg::MatrixTransform *transformNode, const std::map &boundTextures, int animflags) @@ -645,6 +742,7 @@ namespace NifOsg // This seems to be true for all NIF files in the game that I've checked, suggesting that NIFs work similar to OSG with regards to update order. // If something ever violates this assumption, the worst that could happen is the culling being one frame late, which wouldn't be a disaster. + // Creating emitters will need to be changed when cloning a scenegraph is implemented, the particleSystem pointer would become invalid FindRecIndexVisitor find (partctrl->emitter->recIndex); mRootNode->accept(find); if (!find.mFound) diff --git a/components/nifosg/nifloader.hpp b/components/nifosg/nifloader.hpp index 5bd25f6ca..18e3e7db8 100644 --- a/components/nifosg/nifloader.hpp +++ b/components/nifosg/nifloader.hpp @@ -30,21 +30,32 @@ namespace NifOsg { class Controller; + typedef std::multimap TextKeyMap; + /// The main class responsible for loading NIF files into an OSG-Scenegraph. class Loader { public: - /// @param node The parent of the root node for the created NIF file. - void load(Nif::NIFFilePtr file, osg::Group* parentNode); + // TODO: add auto-detection for skinning. We will still need a "force skeleton" parameter + // though, when assembling from several files, i.e. equipment parts + /// Create a scene graph for the given NIF. Assumes no skinning is used. + /// @param node The parent of the new root node for the created scene graph. + osg::Node* load(Nif::NIFFilePtr file, osg::Group* parentNode); + + /// Create a scene graph for the given NIF. Assumes skinning will be used. + osg::Node* loadAsSkeleton(Nif::NIFFilePtr file, osg::Group* parentNode); - void loadAsSkeleton(Nif::NIFFilePtr file, osg::Group* parentNode); + /// Load keyframe controllers from the given kf file onto the given scene graph. + /// @param sourceIndex The source index for this animation source, used for identifying + /// which animation source a keyframe controller came from. + void loadKf(Nif::NIFFilePtr kf, osg::Node* rootNode, int sourceIndex); const VFS::Manager* resourceManager; private: /// @param createSkeleton If true, use an osgAnimation::Bone for NIF nodes, otherwise an osg::MatrixTransform. - void handleNode(const Nif::Node* nifNode, osg::Group* parentNode, bool createSkeleton, + osg::Node* handleNode(const Nif::Node* nifNode, osg::Group* parentNode, bool createSkeleton, std::map boundTextures, int animflags, int particleflags, bool collisionNode=false); void handleMeshControllers(const Nif::Node* nifNode, osg::MatrixTransform* transformNode, const std::map& boundTextures, int animflags); @@ -81,7 +92,6 @@ namespace NifOsg Nif::NIFFilePtr mNif; osg::Group* mRootNode; - osg::Group* mSkeleton; }; } From 6d85444d2664d66da75252f342c016e007e967a0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 23 Mar 2015 01:51:44 +0100 Subject: [PATCH 0798/3725] Add text key loading --- apps/nifosgtest/test.cpp | 1 - components/nifosg/nifloader.cpp | 95 +++++++++++++++++++++++++-------- components/nifosg/nifloader.hpp | 8 +-- 3 files changed, 76 insertions(+), 28 deletions(-) diff --git a/apps/nifosgtest/test.cpp b/apps/nifosgtest/test.cpp index 3e70c8cd2..c21f423bf 100644 --- a/apps/nifosgtest/test.cpp +++ b/apps/nifosgtest/test.cpp @@ -111,7 +111,6 @@ int main(int argc, char** argv) //osgDB::writeNodeFile(*newNode, "out.osg"); - osg::Group* newNode = new osg::Group; NifOsg::Loader loader; loader.resourceManager = &resourceMgr; diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index c73bcbc96..c05bad5ae 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -302,12 +302,50 @@ namespace } return morphGeom; } + + void extractTextKeys(const Nif::NiTextKeyExtraData *tk, NifOsg::TextKeyMap &textkeys) + { + for(size_t i = 0;i < tk->list.size();i++) + { + const std::string &str = tk->list[i].text; + std::string::size_type pos = 0; + while(pos < str.length()) + { + if(::isspace(str[pos])) + { + pos++; + continue; + } + + std::string::size_type nextpos = std::min(str.find('\r', pos), str.find('\n', pos)); + if(nextpos != std::string::npos) + { + do { + nextpos--; + } while(nextpos > pos && ::isspace(str[nextpos])); + nextpos++; + } + else if(::isspace(*str.rbegin())) + { + std::string::const_iterator last = str.end(); + do { + --last; + } while(last != str.begin() && ::isspace(*last)); + nextpos = std::distance(str.begin(), ++last); + } + std::string result = str.substr(pos, nextpos-pos); + textkeys.insert(std::make_pair(tk->list[i].time, Misc::StringUtils::toLower(result))); + + pos = nextpos; + } + } + } } namespace NifOsg { - void Loader::loadKf(Nif::NIFFilePtr nif, osg::Node *rootNode, int sourceIndex) + void Loader::loadKf(Nif::NIFFilePtr nif, osg::Node *rootNode, int sourceIndex, TextKeyMap& textKeys) { if(nif->numRoots() < 1) { @@ -334,7 +372,7 @@ namespace NifOsg return; } - //extractTextKeys(static_cast(extra.getPtr()), textKeys); + extractTextKeys(static_cast(extra.getPtr()), textKeys); std::map controllerMap; @@ -364,55 +402,45 @@ namespace NifOsg rootNode->accept(visitor); } - osg::Node* Loader::load(Nif::NIFFilePtr nif, osg::Group *parentNode) + osg::Node* Loader::load(Nif::NIFFilePtr nif, osg::Group *parentNode, TextKeyMap* textKeys) { mNif = nif; if (nif->numRoots() < 1) - { nif->fail("Found no root nodes"); - } const Nif::Record* r = nif->getRoot(0); const Nif::Node* nifNode = dynamic_cast(r); if (nifNode == NULL) - { nif->fail("First root was not a node, but a " + r->recName); - } mRootNode = parentNode; - osg::Node* created = handleNode(nifNode, parentNode, false, std::map(), 0, 0); + osg::Node* created = handleNode(nifNode, parentNode, false, std::map(), 0, 0, false, textKeys); return created; } - osg::Node* Loader::loadAsSkeleton(Nif::NIFFilePtr nif, osg::Group *parentNode) + osg::Node* Loader::loadAsSkeleton(Nif::NIFFilePtr nif, osg::Group *parentNode, TextKeyMap* textKeys) { mNif = nif; if (nif->numRoots() < 1) - { - //nif->warn("Found no root nodes"); nif->fail("Found no root nodes"); - } const Nif::Record* r = nif->getRoot(0); assert(r != NULL); const Nif::Node* nifNode = dynamic_cast(r); if (nifNode == NULL) - { - //nif->warn("First root was not a node, but a " + r->recName); nif->fail("First root was not a node, but a " + r->recName); - } osg::ref_ptr skel = new osgAnimation::Skeleton; parentNode->addChild(skel); mRootNode = parentNode; - handleNode(nifNode, skel, true, std::map(), 0, 0); + handleNode(nifNode, skel, true, std::map(), 0, 0, false, textKeys); return skel; } @@ -437,7 +465,7 @@ namespace NifOsg } osg::Node* Loader::handleNode(const Nif::Node* nifNode, osg::Group* parentNode, bool createSkeleton, - std::map boundTextures, int animflags, int particleflags, bool collisionNode) + std::map boundTextures, int animflags, int particleflags, bool skipMeshes, TextKeyMap* textKeys) { osg::ref_ptr transformNode; if (nifNode->recType == Nif::RC_NiBillboardNode) @@ -458,6 +486,9 @@ namespace NifOsg } // Ignoring name for non-bone nodes for now. We might need it later in isolated cases, e.g. AttachLight. + // Insert bones at position 0 to prevent update order problems (see comment in osg Skeleton.cpp) + parentNode->insertChild(0, transformNode); + // UserData used for a variety of features: // - finding the correct emitter node for a particle system // - establishing connections to the animated collision shapes, which are handled in a separate loader @@ -467,6 +498,27 @@ namespace NifOsg transformNode->getOrCreateUserDataContainer()->addUserObject( new NodeUserData(nifNode->recIndex, nifNode->trafo.scale, nifNode->trafo.rotation)); + for (Nif::ExtraPtr e = nifNode->extra; !e.empty(); e = e->extra) + { + if(e->recType == Nif::RC_NiTextKeyExtraData && textKeys) + { + const Nif::NiTextKeyExtraData *tk = static_cast(e.getPtr()); + extractTextKeys(tk, *textKeys); + } + else if(e->recType == Nif::RC_NiStringExtraData) + { + const Nif::NiStringExtraData *sd = static_cast(e.getPtr()); + // String markers may contain important information + // affecting the entire subtree of this obj + // TODO: implement show markers flag + if(sd->string == "MRK" /*&& !sShowMarkers*/) + { + // Marker objects. These meshes are only visible in the editor. + skipMeshes = true; + } + } + } + if (nifNode->recType == Nif::RC_NiBSAnimationNode) animflags |= nifNode->flags; if (nifNode->recType == Nif::RC_NiBSParticleNode) @@ -476,7 +528,7 @@ namespace NifOsg // We still need to animate the hidden bones so the physics system can access them if (nifNode->recType == Nif::RC_RootCollisionNode) { - collisionNode = true; + skipMeshes = true; // Leave mask for UpdateVisitor enabled transformNode->setNodeMask(0x1); } @@ -486,12 +538,9 @@ namespace NifOsg if (nifNode->flags & Nif::NiNode::Flag_Hidden) transformNode->setNodeMask(0x1); // Leave mask for UpdateVisitor enabled - // Insert bones at position 0 to prevent update order problems (see comment in osg Skeleton.cpp) - parentNode->insertChild(0, transformNode); - applyNodeProperties(nifNode, transformNode, boundTextures, animflags); - if (nifNode->recType == Nif::RC_NiTriShape && !collisionNode) + if (nifNode->recType == Nif::RC_NiTriShape && !skipMeshes) { const Nif::NiTriShape* triShape = static_cast(nifNode); if (!createSkeleton || triShape->skin.empty()) @@ -520,7 +569,7 @@ namespace NifOsg for(size_t i = 0;i < children.length();++i) { if(!children[i].empty()) - handleNode(children[i].getPtr(), transformNode, createSkeleton, boundTextures, animflags, particleflags, collisionNode); + handleNode(children[i].getPtr(), transformNode, createSkeleton, boundTextures, animflags, particleflags, skipMeshes, textKeys); } } diff --git a/components/nifosg/nifloader.hpp b/components/nifosg/nifloader.hpp index 18e3e7db8..9fc262c70 100644 --- a/components/nifosg/nifloader.hpp +++ b/components/nifosg/nifloader.hpp @@ -40,15 +40,15 @@ namespace NifOsg // though, when assembling from several files, i.e. equipment parts /// Create a scene graph for the given NIF. Assumes no skinning is used. /// @param node The parent of the new root node for the created scene graph. - osg::Node* load(Nif::NIFFilePtr file, osg::Group* parentNode); + osg::Node* load(Nif::NIFFilePtr file, osg::Group* parentNode, TextKeyMap* textKeys = NULL); /// Create a scene graph for the given NIF. Assumes skinning will be used. - osg::Node* loadAsSkeleton(Nif::NIFFilePtr file, osg::Group* parentNode); + osg::Node* loadAsSkeleton(Nif::NIFFilePtr file, osg::Group* parentNode, TextKeyMap* textKeys = NULL); /// Load keyframe controllers from the given kf file onto the given scene graph. /// @param sourceIndex The source index for this animation source, used for identifying /// which animation source a keyframe controller came from. - void loadKf(Nif::NIFFilePtr kf, osg::Node* rootNode, int sourceIndex); + void loadKf(Nif::NIFFilePtr kf, osg::Node* rootNode, int sourceIndex, TextKeyMap &textKeys); const VFS::Manager* resourceManager; @@ -56,7 +56,7 @@ namespace NifOsg /// @param createSkeleton If true, use an osgAnimation::Bone for NIF nodes, otherwise an osg::MatrixTransform. osg::Node* handleNode(const Nif::Node* nifNode, osg::Group* parentNode, bool createSkeleton, - std::map boundTextures, int animflags, int particleflags, bool collisionNode=false); + std::map boundTextures, int animflags, int particleflags, bool skipMeshes, TextKeyMap* textKeys); void handleMeshControllers(const Nif::Node* nifNode, osg::MatrixTransform* transformNode, const std::map& boundTextures, int animflags); From 5a582e7eb76c2be68c792b0c05811dfbd6af750c Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 23 Mar 2015 01:57:03 +0100 Subject: [PATCH 0799/3725] Reintroduce showMarkers flag --- apps/opencs/editor.cpp | 4 +++- components/nifosg/nifloader.cpp | 9 ++++++++- components/nifosg/nifloader.hpp | 14 ++++++++++++-- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 3c4ce6868..83fcb3e37 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -9,6 +9,8 @@ #include #include +#include + #include "model/doc/document.hpp" #include "model/world/data.hpp" @@ -24,7 +26,7 @@ CS::Editor::Editor () CSMSettings::UserSettings::instance().loadSettings ("opencs.ini"); mSettings.setModel (CSMSettings::UserSettings::instance()); - //NifOgre::Loader::setShowMarkers(true); + NifOsg::Loader::setShowMarkers(true); mVFS.reset(new VFS::Manager(mFsStrict)); diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index c05bad5ae..a37a13261 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -345,6 +345,13 @@ namespace namespace NifOsg { + bool Loader::sShowMarkers = false; + + void Loader::setShowMarkers(bool show) + { + sShowMarkers = show; + } + void Loader::loadKf(Nif::NIFFilePtr nif, osg::Node *rootNode, int sourceIndex, TextKeyMap& textKeys) { if(nif->numRoots() < 1) @@ -511,7 +518,7 @@ namespace NifOsg // String markers may contain important information // affecting the entire subtree of this obj // TODO: implement show markers flag - if(sd->string == "MRK" /*&& !sShowMarkers*/) + if(sd->string == "MRK" && !sShowMarkers) { // Marker objects. These meshes are only visible in the editor. skipMeshes = true; diff --git a/components/nifosg/nifloader.hpp b/components/nifosg/nifloader.hpp index 9fc262c70..8f9efe6b3 100644 --- a/components/nifosg/nifloader.hpp +++ b/components/nifosg/nifloader.hpp @@ -7,11 +7,14 @@ #include -#include - namespace osg { class Geometry; + class Group; + class Node; + class MatrixTransform; + class StateSet; + class Geode; } namespace osgAnimation { @@ -50,6 +53,11 @@ namespace NifOsg /// which animation source a keyframe controller came from. void loadKf(Nif::NIFFilePtr kf, osg::Node* rootNode, int sourceIndex, TextKeyMap &textKeys); + /// Set whether or not nodes marked as "MRK" should be shown. + /// These should be hidden ingame, but visible in the editior. + /// Default: false. + static void setShowMarkers(bool show); + const VFS::Manager* resourceManager; private: @@ -92,6 +100,8 @@ namespace NifOsg Nif::NIFFilePtr mNif; osg::Group* mRootNode; + + static bool sShowMarkers; }; } From eb1090a1b68999d00df3778cffb59d2a933a9f81 Mon Sep 17 00:00:00 2001 From: dteviot Date: Mon, 23 Mar 2015 20:09:46 +1300 Subject: [PATCH 0800/3725] Waypoint check only considers X & Y distance (Fixes #2423) When pathfinder checks if actor has reached a waypoint, ignore actor's altitude. --- apps/openmw/mwmechanics/aicombat.cpp | 2 +- apps/openmw/mwmechanics/aipackage.cpp | 2 +- apps/openmw/mwmechanics/aitravel.cpp | 2 +- apps/openmw/mwmechanics/aiwander.cpp | 2 +- apps/openmw/mwmechanics/pathfinding.cpp | 9 ++++----- apps/openmw/mwmechanics/pathfinding.hpp | 2 +- 6 files changed, 9 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index bac7d7286..2f68087e5 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -581,7 +581,7 @@ namespace MWMechanics buildNewPath(actor, target); //may fail to build a path, check before use //delete visited path node - mPathFinder.checkPathCompleted(pos.pos[0],pos.pos[1],pos.pos[2]); + mPathFinder.checkPathCompleted(pos.pos[0],pos.pos[1]); // This works on the borders between the path grid and areas with no waypoints. if(inLOS && mPathFinder.getPath().size() > 1) diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index f93376779..52a975320 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -86,7 +86,7 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, ESM::Pathgrid::Po //************************ /// Checks if you aren't moving; attempts to unstick you //************************ - if(mPathFinder.checkPathCompleted(pos.pos[0],pos.pos[1],pos.pos[2])) //Path finished? + if(mPathFinder.checkPathCompleted(pos.pos[0],pos.pos[1])) //Path finished? return true; else if(mStuckTimer>0.5) //Every half second see if we need to take action to avoid something { diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index a46fe7296..2824e2c6c 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -100,7 +100,7 @@ namespace MWMechanics mPathFinder.buildPath(start, dest, actor.getCell(), true); } - if(mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], pos.pos[2])) + if(mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1])) { movement.mPosition[1] = 0; return true; diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index b791ff3a9..2bd2cfe5d 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -205,7 +205,7 @@ namespace MWMechanics // Are we there yet? bool& chooseAction = storage.mChooseAction; if(walking && - storage.mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], pos.pos[2], 64.f)) + storage.mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], 64.f)) { stopWalking(actor, storage); moveNow = false; diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index e8abb9e98..5795f818a 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -90,12 +90,11 @@ namespace namespace MWMechanics { - float sqrDistanceZCorrected(ESM::Pathgrid::Point point, float x, float y, float z) + float sqrDistanceIgnoreZ(ESM::Pathgrid::Point point, float x, float y) { x -= point.mX; y -= point.mY; - z -= point.mZ; - return (x * x + y * y + 0.1f * z * z); + return (x * x + y * y); } float distance(ESM::Pathgrid::Point point, float x, float y, float z) @@ -283,13 +282,13 @@ namespace MWMechanics return Ogre::Math::ATan2(directionX,directionY).valueDegrees(); } - bool PathFinder::checkPathCompleted(float x, float y, float z, float tolerance) + bool PathFinder::checkPathCompleted(float x, float y, float tolerance) { if(mPath.empty()) return true; ESM::Pathgrid::Point nextPoint = *mPath.begin(); - if(sqrDistanceZCorrected(nextPoint, x, y, z) < tolerance*tolerance) + if (sqrDistanceIgnoreZ(nextPoint, x, y) < tolerance*tolerance) { mPath.pop_front(); if(mPath.empty()) diff --git a/apps/openmw/mwmechanics/pathfinding.hpp b/apps/openmw/mwmechanics/pathfinding.hpp index 490cf9b88..f48de6624 100644 --- a/apps/openmw/mwmechanics/pathfinding.hpp +++ b/apps/openmw/mwmechanics/pathfinding.hpp @@ -41,7 +41,7 @@ namespace MWMechanics void buildPath(const ESM::Pathgrid::Point &startPoint, const ESM::Pathgrid::Point &endPoint, const MWWorld::CellStore* cell, bool allowShortcuts = true); - bool checkPathCompleted(float x, float y, float z, float tolerance=32.f); + bool checkPathCompleted(float x, float y, float tolerance=32.f); ///< \Returns true if we are within \a tolerance units of the last path point. float getZAngleToNext(float x, float y) const; From 63ab856024abb36401da58744f9f5fe40063c908 Mon Sep 17 00:00:00 2001 From: dteviot Date: Mon, 23 Mar 2015 20:57:36 +1300 Subject: [PATCH 0801/3725] Removed duplicated code. --- apps/openmw/mwmechanics/aiwander.cpp | 56 ++++++++++++---------------- apps/openmw/mwmechanics/aiwander.hpp | 8 ++++ 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 2bd2cfe5d..d277b1249 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -31,6 +31,18 @@ namespace MWMechanics static const int GREETING_SHOULD_START = 4; //how many reaction intervals should pass before NPC can greet player static const int GREETING_SHOULD_END = 10; + const std::string AiWander::sIdleSelectToGroupName[GroupIndex_MaxIdle - GroupIndex_MinIdle + 1] = + { + std::string("idle2"), + std::string("idle3"), + std::string("idle4"), + std::string("idle5"), + std::string("idle6"), + std::string("idle7"), + std::string("idle8"), + std::string("idle9"), + }; + /// \brief This class holds the variables AiWander needs which are deleted if the package becomes inactive. struct AiWanderStorage : AiTemporaryBase { @@ -580,44 +592,24 @@ namespace MWMechanics void AiWander::playIdle(const MWWorld::Ptr& actor, unsigned short idleSelect) { - if(idleSelect == 2) - MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle2", 0, 1); - else if(idleSelect == 3) - MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle3", 0, 1); - else if(idleSelect == 4) - MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle4", 0, 1); - else if(idleSelect == 5) - MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle5", 0, 1); - else if(idleSelect == 6) - MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle6", 0, 1); - else if(idleSelect == 7) - MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle7", 0, 1); - else if(idleSelect == 8) - MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle8", 0, 1); - else if(idleSelect == 9) - MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle9", 0, 1); + if ((GroupIndex_MinIdle <= idleSelect) && (idleSelect <= GroupIndex_MaxIdle)) + { + const std::string& groupName = sIdleSelectToGroupName[idleSelect - GroupIndex_MinIdle]; + MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, groupName, 0, 1); + } } bool AiWander::checkIdle(const MWWorld::Ptr& actor, unsigned short idleSelect) { - if(idleSelect == 2) - return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle2"); - else if(idleSelect == 3) - return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle3"); - else if(idleSelect == 4) - return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle4"); - else if(idleSelect == 5) - return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle5"); - else if(idleSelect == 6) - return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle6"); - else if(idleSelect == 7) - return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle7"); - else if(idleSelect == 8) - return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle8"); - else if(idleSelect == 9) - return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle9"); + if ((GroupIndex_MinIdle <= idleSelect) && (idleSelect <= GroupIndex_MaxIdle)) + { + const std::string& groupName = sIdleSelectToGroupName[idleSelect - GroupIndex_MinIdle]; + return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, groupName); + } else + { return false; + } } void AiWander::setReturnPosition(const Ogre::Vector3& position) diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 54e215cb9..7e138c001 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -113,7 +113,15 @@ namespace MWMechanics float mDoorCheckDuration; int mStuckCount; + // constants for converting idleSelect values into groupNames + enum GroupIndex + { + GroupIndex_MinIdle = 2, + GroupIndex_MaxIdle = 9 + }; + /// lookup table for converting idleSelect value to groupName + static const std::string sIdleSelectToGroupName[GroupIndex_MaxIdle - GroupIndex_MinIdle + 1]; }; From d6dea31b883a1fc6883ad8164d626439d72b6b55 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 23 Mar 2015 15:55:57 +0100 Subject: [PATCH 0802/3725] OpenCS: Use a CompositeViewer with multiple views instead of multiple viewers Fixes the rendering glitches, turns out that multiple osgViewers were never an intended use case. --- apps/opencs/view/render/previewwidget.cpp | 2 +- apps/opencs/view/render/scenewidget.cpp | 76 ++++++++++++++--------- apps/opencs/view/render/scenewidget.hpp | 27 ++++++-- 3 files changed, 72 insertions(+), 33 deletions(-) diff --git a/apps/opencs/view/render/previewwidget.cpp b/apps/opencs/view/render/previewwidget.cpp index 8802b5cf3..c3f838435 100644 --- a/apps/opencs/view/render/previewwidget.cpp +++ b/apps/opencs/view/render/previewwidget.cpp @@ -15,7 +15,7 @@ CSVRender::PreviewWidget::PreviewWidget (const VFS::Manager* vfs, CSMWorld::Data { //setNavigation (&mOrbit); - setCameraManipulator(new osgGA::TrackballManipulator); + mView->setCameraManipulator(new osgGA::TrackballManipulator); QAbstractItemModel *referenceables = mData.getTableModel (CSMWorld::UniversalId::Type_Referenceables); diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index 2dc5bdbc6..195e550a3 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -14,7 +14,7 @@ #include #include - +#include #include namespace CSVRender @@ -25,20 +25,11 @@ SceneWidget::SceneWidget(QWidget *parent, Qt::WindowFlags f) , mRootNode(0) { -#if QT_VERSION >= 0x050000 - // Qt5 is currently crashing and reporting "Cannot make QOpenGLContext current in a different thread" when the viewer is run multi-threaded, this is regression from Qt4 - osgViewer::ViewerBase::ThreadingModel threadingModel = osgViewer::ViewerBase::SingleThreaded; -#else - osgViewer::ViewerBase::ThreadingModel threadingModel = osgViewer::ViewerBase::CullDrawThreadPerContext; -#endif - - setThreadingModel(threadingModel); - - // disable the default setting of viewer.done() by pressing Escape. - setKeyEventSetsDone(0); + osgViewer::CompositeViewer& viewer = CompositeViewer::get(); osg::DisplaySettings* ds = osg::DisplaySettings::instance().get(); //ds->setNumMultiSamples(8); + osg::ref_ptr traits = new osg::GraphicsContext::Traits; traits->windowName = ""; traits->windowDecoration = true; @@ -54,43 +45,72 @@ SceneWidget::SceneWidget(QWidget *parent, Qt::WindowFlags f) // Doesn't make much sense as we're running on demand updates, and there seems to be a bug with the refresh rate when running multiple QGLWidgets traits->vsync = false; - osgQt::GraphicsWindowQt* window = new osgQt::GraphicsWindowQt(traits.get()); + mView = new osgViewer::View; + + osg::ref_ptr window = new osgQt::GraphicsWindowQt(traits.get()); QLayout* layout = new QHBoxLayout(this); layout->addWidget(window->getGLWidget()); setLayout(layout); - getCamera()->setGraphicsContext(window); - - getCamera()->setClearColor( osg::Vec4(0.2, 0.2, 0.6, 1.0) ); - getCamera()->setViewport( new osg::Viewport(0, 0, traits->width, traits->height) ); - getCamera()->setProjectionMatrixAsPerspective(30.0f, static_cast(traits->width)/static_cast(traits->height), 1.0f, 10000.0f ); + mView->getCamera()->setGraphicsContext(window); + mView->getCamera()->setClearColor( osg::Vec4(0.2, 0.2, 0.6, 1.0) ); + mView->getCamera()->setViewport( new osg::Viewport(0, 0, traits->width, traits->height) ); + mView->getCamera()->setProjectionMatrixAsPerspective(30.0f, static_cast(traits->width)/static_cast(traits->height), 1.0f, 10000.0f ); mRootNode = new osg::Group; - setSceneData(mRootNode); + mView->setSceneData(mRootNode); // Press S to reveal profiling stats - addEventHandler(new osgViewer::StatsHandler); + mView->addEventHandler(new osgViewer::StatsHandler); + + mView->getCamera()->setCullMask(~(0x1)); + + viewer.addView(mView); + viewer.setDone(false); + viewer.realize(); +} + +SceneWidget::~SceneWidget() +{ + CompositeViewer::get().removeView(mView); +} + +void SceneWidget::flagAsModified() +{ + mView->requestRedraw(); +} + +CompositeViewer::CompositeViewer() +{ +#if QT_VERSION >= 0x050000 + // Qt5 is currently crashing and reporting "Cannot make QOpenGLContext current in a different thread" when the viewer is run multi-threaded, this is regression from Qt4 + osgViewer::ViewerBase::ThreadingModel threadingModel = osgViewer::ViewerBase::SingleThreaded; +#else + osgViewer::ViewerBase::ThreadingModel threadingModel = osgViewer::ViewerBase::CullDrawThreadPerContext; +#endif + + setThreadingModel(threadingModel); + + // disable the default setting of viewer.done() by pressing Escape. + setKeyEventSetsDone(0); // Only render when the camera position changed, or content flagged dirty //setRunFrameScheme(osgViewer::ViewerBase::ON_DEMAND); setRunFrameScheme(osgViewer::ViewerBase::CONTINUOUS); - getCamera()->setCullMask(~(0x1)); - connect( &mTimer, SIGNAL(timeout()), this, SLOT(update()) ); mTimer.start( 10 ); - - realize(); } -void SceneWidget::paintEvent(QPaintEvent *event) +CompositeViewer &CompositeViewer::get() { - frame(); + static CompositeViewer sThis; + return sThis; } -void SceneWidget::flagAsModified() +void CompositeViewer::update() { - _requestRedraw = true; + frame(); } } diff --git a/apps/opencs/view/render/scenewidget.hpp b/apps/opencs/view/render/scenewidget.hpp index 3784a5c59..adb10b10a 100644 --- a/apps/opencs/view/render/scenewidget.hpp +++ b/apps/opencs/view/render/scenewidget.hpp @@ -8,7 +8,8 @@ #include "lightingnight.hpp" #include "lightingbright.hpp" -#include +#include +#include namespace osg { @@ -26,24 +27,42 @@ namespace CSVRender class Navigation; class Lighting; - class SceneWidget : public QWidget, public osgViewer::Viewer + class SceneWidget : public QWidget { Q_OBJECT public: SceneWidget(QWidget* parent = 0, Qt::WindowFlags f = 0); - - virtual void paintEvent( QPaintEvent* event ); + ~SceneWidget(); void flagAsModified(); protected: + osg::ref_ptr mView; + osg::Group* mRootNode; QTimer mTimer; }; + + + // There are rendering glitches when using multiple Viewer instances, work around using CompositeViewer with multiple views + class CompositeViewer : public QObject, public osgViewer::CompositeViewer + { + Q_OBJECT + public: + CompositeViewer(); + + static CompositeViewer& get(); + + QTimer mTimer; + + public slots: + void update(); + }; + } #endif From ff9e2b03a07dae636833f14855bb4e30092d3345 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 23 Mar 2015 16:10:18 +0100 Subject: [PATCH 0803/3725] Hide NIF loader details in the implementation file --- components/nifosg/nifloader.cpp | 1601 ++++++++++++++++--------------- components/nifosg/nifloader.hpp | 55 -- 2 files changed, 820 insertions(+), 836 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index a37a13261..c00b4abe1 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -285,24 +285,6 @@ namespace int mSourceIndex; }; - osg::ref_ptr handleMorphGeometry(const Nif::NiGeomMorpherController* morpher) - { - osg::ref_ptr morphGeom = new osgAnimation::MorphGeometry; - morphGeom->setMethod(osgAnimation::MorphGeometry::RELATIVE); - // No normals available in the MorphData - morphGeom->setMorphNormals(false); - - const std::vector& morphs = morpher->data.getPtr()->mMorphs; - // Note we are not interested in morph 0, which just contains the original vertices - for (unsigned int i = 1; i < morphs.size(); ++i) - { - osg::ref_ptr morphTarget = new osg::Geometry; - morphTarget->setVertexArray(new osg::Vec3Array(morphs[i].mVertices.size(), &morphs[i].mVertices[0])); - morphGeom->addMorphTarget(morphTarget, 0.f); - } - return morphGeom; - } - void extractTextKeys(const Nif::NiTextKeyExtraData *tk, NifOsg::TextKeyMap &textkeys) { for(size_t i = 0;i < tk->list.size();i++) @@ -352,959 +334,1016 @@ namespace NifOsg sShowMarkers = show; } - void Loader::loadKf(Nif::NIFFilePtr nif, osg::Node *rootNode, int sourceIndex, TextKeyMap& textKeys) + class LoaderImpl { - if(nif->numRoots() < 1) - { - nif->warn("Found no root nodes"); - return; - } - - const Nif::Record *r = nif->getRoot(0); - assert(r != NULL); + public: + const VFS::Manager* mResourceManager; + bool mShowMarkers; - if(r->recType != Nif::RC_NiSequenceStreamHelper) + LoaderImpl(const VFS::Manager* resourceManager, bool showMarkers) + : mResourceManager(resourceManager) + , mShowMarkers(showMarkers) { - nif->warn("First root was not a NiSequenceStreamHelper, but a "+ - r->recName+"."); - return; } - const Nif::NiSequenceStreamHelper *seq = static_cast(r); - Nif::ExtraPtr extra = seq->extra; - if(extra.empty() || extra->recType != Nif::RC_NiTextKeyExtraData) + void loadKf(Nif::NIFFilePtr nif, osg::Node *rootNode, int sourceIndex, TextKeyMap& textKeys) { - nif->warn("First extra data was not a NiTextKeyExtraData, but a "+ - (extra.empty() ? std::string("nil") : extra->recName)+"."); - return; - } - - extractTextKeys(static_cast(extra.getPtr()), textKeys); + if(nif->numRoots() < 1) + { + nif->warn("Found no root nodes"); + return; + } - std::map controllerMap; + const Nif::Record *r = nif->getRoot(0); + assert(r != NULL); - extra = extra->extra; - Nif::ControllerPtr ctrl = seq->controller; - for(;!extra.empty() && !ctrl.empty();(extra=extra->extra),(ctrl=ctrl->next)) - { - if(extra->recType != Nif::RC_NiStringExtraData || ctrl->recType != Nif::RC_NiKeyframeController) + if(r->recType != Nif::RC_NiSequenceStreamHelper) { - nif->warn("Unexpected extra data "+extra->recName+" with controller "+ctrl->recName); - continue; + nif->warn("First root was not a NiSequenceStreamHelper, but a "+ + r->recName+"."); + return; } + const Nif::NiSequenceStreamHelper *seq = static_cast(r); - if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active)) - continue; + Nif::ExtraPtr extra = seq->extra; + if(extra.empty() || extra->recType != Nif::RC_NiTextKeyExtraData) + { + nif->warn("First extra data was not a NiTextKeyExtraData, but a "+ + (extra.empty() ? std::string("nil") : extra->recName)+"."); + return; + } - const Nif::NiStringExtraData *strdata = static_cast(extra.getPtr()); - const Nif::NiKeyframeController *key = static_cast(ctrl.getPtr()); + extractTextKeys(static_cast(extra.getPtr()), textKeys); - if(key->data.empty()) - continue; + std::map controllerMap; - controllerMap[strdata->string] = key; - } - - LoadKfVisitor visitor(controllerMap, sourceIndex); - rootNode->accept(visitor); - } + extra = extra->extra; + Nif::ControllerPtr ctrl = seq->controller; + for(;!extra.empty() && !ctrl.empty();(extra=extra->extra),(ctrl=ctrl->next)) + { + if(extra->recType != Nif::RC_NiStringExtraData || ctrl->recType != Nif::RC_NiKeyframeController) + { + nif->warn("Unexpected extra data "+extra->recName+" with controller "+ctrl->recName); + continue; + } - osg::Node* Loader::load(Nif::NIFFilePtr nif, osg::Group *parentNode, TextKeyMap* textKeys) - { - mNif = nif; + if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active)) + continue; - if (nif->numRoots() < 1) - nif->fail("Found no root nodes"); + const Nif::NiStringExtraData *strdata = static_cast(extra.getPtr()); + const Nif::NiKeyframeController *key = static_cast(ctrl.getPtr()); - const Nif::Record* r = nif->getRoot(0); + if(key->data.empty()) + continue; - const Nif::Node* nifNode = dynamic_cast(r); - if (nifNode == NULL) - nif->fail("First root was not a node, but a " + r->recName); + controllerMap[strdata->string] = key; + } - mRootNode = parentNode; + LoadKfVisitor visitor(controllerMap, sourceIndex); + rootNode->accept(visitor); + } - osg::Node* created = handleNode(nifNode, parentNode, false, std::map(), 0, 0, false, textKeys); - return created; - } + osg::Node* load(Nif::NIFFilePtr nif, osg::Group *parentNode, TextKeyMap* textKeys) + { + if (nif->numRoots() < 1) + nif->fail("Found no root nodes"); - osg::Node* Loader::loadAsSkeleton(Nif::NIFFilePtr nif, osg::Group *parentNode, TextKeyMap* textKeys) - { - mNif = nif; + const Nif::Record* r = nif->getRoot(0); - if (nif->numRoots() < 1) - nif->fail("Found no root nodes"); + const Nif::Node* nifNode = dynamic_cast(r); + if (nifNode == NULL) + nif->fail("First root was not a node, but a " + r->recName); - const Nif::Record* r = nif->getRoot(0); - assert(r != NULL); + osg::Node* created = handleNode(nifNode, parentNode, false, std::map(), 0, 0, false, textKeys); + return created; + } - const Nif::Node* nifNode = dynamic_cast(r); - if (nifNode == NULL) - nif->fail("First root was not a node, but a " + r->recName); + osg::Node* loadAsSkeleton(Nif::NIFFilePtr nif, osg::Group *parentNode, TextKeyMap* textKeys) + { + if (nif->numRoots() < 1) + nif->fail("Found no root nodes"); - osg::ref_ptr skel = new osgAnimation::Skeleton; - parentNode->addChild(skel); + const Nif::Record* r = nif->getRoot(0); + assert(r != NULL); - mRootNode = parentNode; + const Nif::Node* nifNode = dynamic_cast(r); + if (nifNode == NULL) + nif->fail("First root was not a node, but a " + r->recName); - handleNode(nifNode, skel, true, std::map(), 0, 0, false, textKeys); + osg::ref_ptr skel = new osgAnimation::Skeleton; + parentNode->addChild(skel); - return skel; - } + handleNode(nifNode, skel, true, std::map(), 0, 0, false, textKeys); - void Loader::applyNodeProperties(const Nif::Node *nifNode, osg::Node *applyTo, std::map& boundTextures, int animflags) - { - const Nif::PropertyList& props = nifNode->props; - for (size_t i = 0; i mSource = boost::shared_ptr(new FrameTimeSource); - - toSetup->mFunction = boost::shared_ptr(new ControllerFunction(ctrl, 1 /*autoPlay*/)); - } - osg::Node* Loader::handleNode(const Nif::Node* nifNode, osg::Group* parentNode, bool createSkeleton, - std::map boundTextures, int animflags, int particleflags, bool skipMeshes, TextKeyMap* textKeys) - { - osg::ref_ptr transformNode; - if (nifNode->recType == Nif::RC_NiBillboardNode) - { - transformNode = new BillboardNode(toMatrix(nifNode->trafo)); - } - else if (createSkeleton) + void applyNodeProperties(const Nif::Node *nifNode, osg::Node *applyTo, std::map& boundTextures, int animflags) { - osgAnimation::Bone* bone = new osgAnimation::Bone; - transformNode = bone; - bone->setMatrix(toMatrix(nifNode->trafo)); - bone->setName(nifNode->name); - bone->setInvBindMatrixInSkeletonSpace(osg::Matrixf::inverse(getWorldTransform(nifNode))); + const Nif::PropertyList& props = nifNode->props; + for (size_t i = 0; i trafo)); - } - // Ignoring name for non-bone nodes for now. We might need it later in isolated cases, e.g. AttachLight. + //bool autoPlay = animflags & Nif::NiNode::AnimFlag_AutoPlay; + //if (autoPlay) + toSetup->mSource = boost::shared_ptr(new FrameTimeSource); - // Insert bones at position 0 to prevent update order problems (see comment in osg Skeleton.cpp) - parentNode->insertChild(0, transformNode); + toSetup->mFunction = boost::shared_ptr(new ControllerFunction(ctrl, 1 /*autoPlay*/)); + } - // UserData used for a variety of features: - // - finding the correct emitter node for a particle system - // - establishing connections to the animated collision shapes, which are handled in a separate loader - // - finding a random child NiNode in NiBspArrayController - // - storing the previous 3x3 rotation and scale values for when a KeyframeController wants to - // change only certain elements of the 4x4 transform - transformNode->getOrCreateUserDataContainer()->addUserObject( - new NodeUserData(nifNode->recIndex, nifNode->trafo.scale, nifNode->trafo.rotation)); - for (Nif::ExtraPtr e = nifNode->extra; !e.empty(); e = e->extra) + osg::Node* handleNode(const Nif::Node* nifNode, osg::Group* parentNode, bool createSkeleton, + std::map boundTextures, int animflags, int particleflags, bool skipMeshes, TextKeyMap* textKeys, osg::Node* rootNode=NULL) { - if(e->recType == Nif::RC_NiTextKeyExtraData && textKeys) + osg::ref_ptr transformNode; + if (nifNode->recType == Nif::RC_NiBillboardNode) + { + transformNode = new BillboardNode(toMatrix(nifNode->trafo)); + } + else if (createSkeleton) { - const Nif::NiTextKeyExtraData *tk = static_cast(e.getPtr()); - extractTextKeys(tk, *textKeys); + osgAnimation::Bone* bone = new osgAnimation::Bone; + transformNode = bone; + bone->setMatrix(toMatrix(nifNode->trafo)); + bone->setName(nifNode->name); + bone->setInvBindMatrixInSkeletonSpace(osg::Matrixf::inverse(getWorldTransform(nifNode))); } - else if(e->recType == Nif::RC_NiStringExtraData) + else { - const Nif::NiStringExtraData *sd = static_cast(e.getPtr()); - // String markers may contain important information - // affecting the entire subtree of this obj - // TODO: implement show markers flag - if(sd->string == "MRK" && !sShowMarkers) + transformNode = new osg::MatrixTransform(toMatrix(nifNode->trafo)); + } + + if (!rootNode) + rootNode = transformNode; + + // Ignoring name for non-bone nodes for now. We might need it later in isolated cases, e.g. AttachLight. + + // Insert bones at position 0 to prevent update order problems (see comment in osg Skeleton.cpp) + parentNode->insertChild(0, transformNode); + + // UserData used for a variety of features: + // - finding the correct emitter node for a particle system + // - establishing connections to the animated collision shapes, which are handled in a separate loader + // - finding a random child NiNode in NiBspArrayController + // - storing the previous 3x3 rotation and scale values for when a KeyframeController wants to + // change only certain elements of the 4x4 transform + transformNode->getOrCreateUserDataContainer()->addUserObject( + new NodeUserData(nifNode->recIndex, nifNode->trafo.scale, nifNode->trafo.rotation)); + + for (Nif::ExtraPtr e = nifNode->extra; !e.empty(); e = e->extra) + { + if(e->recType == Nif::RC_NiTextKeyExtraData && textKeys) { - // Marker objects. These meshes are only visible in the editor. - skipMeshes = true; + const Nif::NiTextKeyExtraData *tk = static_cast(e.getPtr()); + extractTextKeys(tk, *textKeys); + } + else if(e->recType == Nif::RC_NiStringExtraData) + { + const Nif::NiStringExtraData *sd = static_cast(e.getPtr()); + // String markers may contain important information + // affecting the entire subtree of this obj + // TODO: implement show markers flag + if(sd->string == "MRK" && !mShowMarkers) + { + // Marker objects. These meshes are only visible in the editor. + skipMeshes = true; + } } } - } - if (nifNode->recType == Nif::RC_NiBSAnimationNode) - animflags |= nifNode->flags; - if (nifNode->recType == Nif::RC_NiBSParticleNode) - particleflags |= nifNode->flags; + if (nifNode->recType == Nif::RC_NiBSAnimationNode) + animflags |= nifNode->flags; + if (nifNode->recType == Nif::RC_NiBSParticleNode) + particleflags |= nifNode->flags; - // Hide collision shapes, but don't skip the subgraph - // We still need to animate the hidden bones so the physics system can access them - if (nifNode->recType == Nif::RC_RootCollisionNode) - { - skipMeshes = true; - // Leave mask for UpdateVisitor enabled - transformNode->setNodeMask(0x1); - } + // Hide collision shapes, but don't skip the subgraph + // We still need to animate the hidden bones so the physics system can access them + if (nifNode->recType == Nif::RC_RootCollisionNode) + { + skipMeshes = true; + // Leave mask for UpdateVisitor enabled + transformNode->setNodeMask(0x1); + } - // We could probably skip hidden nodes entirely if they don't have a VisController that - // might make them visible later - if (nifNode->flags & Nif::NiNode::Flag_Hidden) - transformNode->setNodeMask(0x1); // Leave mask for UpdateVisitor enabled + // We could probably skip hidden nodes entirely if they don't have a VisController that + // might make them visible later + if (nifNode->flags & Nif::NiNode::Flag_Hidden) + transformNode->setNodeMask(0x1); // Leave mask for UpdateVisitor enabled - applyNodeProperties(nifNode, transformNode, boundTextures, animflags); + applyNodeProperties(nifNode, transformNode, boundTextures, animflags); - if (nifNode->recType == Nif::RC_NiTriShape && !skipMeshes) - { - const Nif::NiTriShape* triShape = static_cast(nifNode); - if (!createSkeleton || triShape->skin.empty()) - handleTriShape(triShape, transformNode, boundTextures, animflags); - else - handleSkinnedTriShape(triShape, transformNode, boundTextures, animflags); + if (nifNode->recType == Nif::RC_NiTriShape && !skipMeshes) + { + const Nif::NiTriShape* triShape = static_cast(nifNode); + if (!createSkeleton || triShape->skin.empty()) + handleTriShape(triShape, transformNode, boundTextures, animflags); + else + handleSkinnedTriShape(triShape, transformNode, boundTextures, animflags); - if (!nifNode->controller.empty()) - handleMeshControllers(nifNode, transformNode, boundTextures, animflags); - } + if (!nifNode->controller.empty()) + handleMeshControllers(nifNode, transformNode, boundTextures, animflags); + } - if(nifNode->recType == Nif::RC_NiAutoNormalParticles || nifNode->recType == Nif::RC_NiRotatingParticles) - handleParticleSystem(nifNode, transformNode, animflags, particleflags); + if(nifNode->recType == Nif::RC_NiAutoNormalParticles || nifNode->recType == Nif::RC_NiRotatingParticles) + handleParticleSystem(nifNode, transformNode, animflags, particleflags, rootNode); - if (!nifNode->controller.empty()) - handleNodeControllers(nifNode, transformNode, animflags); + if (!nifNode->controller.empty()) + handleNodeControllers(nifNode, transformNode, animflags); - // Added last so the changes from KeyframeControllers are taken into account - if (osgAnimation::Bone* bone = dynamic_cast(transformNode.get())) - bone->addUpdateCallback(new UpdateBone); + // Added last so the changes from KeyframeControllers are taken into account + if (osgAnimation::Bone* bone = dynamic_cast(transformNode.get())) + bone->addUpdateCallback(new UpdateBone); - const Nif::NiNode *ninode = dynamic_cast(nifNode); - if(ninode) - { - const Nif::NodeList &children = ninode->children; - for(size_t i = 0;i < children.length();++i) + const Nif::NiNode *ninode = dynamic_cast(nifNode); + if(ninode) { - if(!children[i].empty()) - handleNode(children[i].getPtr(), transformNode, createSkeleton, boundTextures, animflags, particleflags, skipMeshes, textKeys); + const Nif::NodeList &children = ninode->children; + for(size_t i = 0;i < children.length();++i) + { + if(!children[i].empty()) + handleNode(children[i].getPtr(), transformNode, createSkeleton, boundTextures, animflags, particleflags, skipMeshes, textKeys, rootNode); + } } - } - return transformNode; - } + return transformNode; + } - void Loader::handleMeshControllers(const Nif::Node *nifNode, osg::MatrixTransform *transformNode, const std::map &boundTextures, int animflags) - { - for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next) + void handleMeshControllers(const Nif::Node *nifNode, osg::MatrixTransform *transformNode, const std::map &boundTextures, int animflags) { - if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active)) - continue; - if (ctrl->recType == Nif::RC_NiUVController) + for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next) { - const Nif::NiUVController *uvctrl = static_cast(ctrl.getPtr()); - std::set texUnits; - for (std::map::const_iterator it = boundTextures.begin(); it != boundTextures.end(); ++it) - texUnits.insert(it->first); + if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active)) + continue; + if (ctrl->recType == Nif::RC_NiUVController) + { + const Nif::NiUVController *uvctrl = static_cast(ctrl.getPtr()); + std::set texUnits; + for (std::map::const_iterator it = boundTextures.begin(); it != boundTextures.end(); ++it) + texUnits.insert(it->first); - osg::ref_ptr ctrl = new UVController(uvctrl->data.getPtr(), texUnits); - setupController(uvctrl, ctrl, animflags); - transformNode->getOrCreateStateSet()->setDataVariance(osg::StateSet::DYNAMIC); + osg::ref_ptr ctrl = new UVController(uvctrl->data.getPtr(), texUnits); + setupController(uvctrl, ctrl, animflags); + transformNode->getOrCreateStateSet()->setDataVariance(osg::StateSet::DYNAMIC); - transformNode->addUpdateCallback(ctrl); + transformNode->addUpdateCallback(ctrl); + } } } - } - void Loader::handleNodeControllers(const Nif::Node* nifNode, osg::MatrixTransform* transformNode, int animflags) - { - for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next) + void handleNodeControllers(const Nif::Node* nifNode, osg::MatrixTransform* transformNode, int animflags) { - if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active)) - continue; - if (ctrl->recType == Nif::RC_NiKeyframeController) + for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next) { - const Nif::NiKeyframeController *key = static_cast(ctrl.getPtr()); - if(!key->data.empty()) + if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active)) + continue; + if (ctrl->recType == Nif::RC_NiKeyframeController) { - osg::ref_ptr callback(new KeyframeController(key->data.getPtr())); + const Nif::NiKeyframeController *key = static_cast(ctrl.getPtr()); + if(!key->data.empty()) + { + osg::ref_ptr callback(new KeyframeController(key->data.getPtr())); - setupController(key, callback, animflags); - transformNode->addUpdateCallback(callback); + setupController(key, callback, animflags); + transformNode->addUpdateCallback(callback); + } } - } - else if (ctrl->recType == Nif::RC_NiVisController) - { - const Nif::NiVisController* visctrl = static_cast(ctrl.getPtr()); + else if (ctrl->recType == Nif::RC_NiVisController) + { + const Nif::NiVisController* visctrl = static_cast(ctrl.getPtr()); - osg::ref_ptr callback(new VisController(visctrl->data.getPtr())); - setupController(visctrl, callback, animflags); - transformNode->addUpdateCallback(callback); + osg::ref_ptr callback(new VisController(visctrl->data.getPtr())); + setupController(visctrl, callback, animflags); + transformNode->addUpdateCallback(callback); + } } } - } - void Loader::handleMaterialControllers(const Nif::Property *materialProperty, osg::Node* node, osg::StateSet *stateset, int animflags) - { - for (Nif::ControllerPtr ctrl = materialProperty->controller; !ctrl.empty(); ctrl = ctrl->next) + + void handleMaterialControllers(const Nif::Property *materialProperty, osg::Node* node, osg::StateSet *stateset, int animflags) { - if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active)) - continue; - if (ctrl->recType == Nif::RC_NiAlphaController) + for (Nif::ControllerPtr ctrl = materialProperty->controller; !ctrl.empty(); ctrl = ctrl->next) { - const Nif::NiAlphaController* alphactrl = static_cast(ctrl.getPtr()); - osg::ref_ptr ctrl(new AlphaController(alphactrl->data.getPtr())); - setupController(alphactrl, ctrl, animflags); - stateset->setDataVariance(osg::StateSet::DYNAMIC); - node->addUpdateCallback(ctrl); - } - else if (ctrl->recType == Nif::RC_NiMaterialColorController) - { - const Nif::NiMaterialColorController* matctrl = static_cast(ctrl.getPtr()); - osg::ref_ptr ctrl(new MaterialColorController(matctrl->data.getPtr())); - setupController(matctrl, ctrl, animflags); - stateset->setDataVariance(osg::StateSet::DYNAMIC); - node->addUpdateCallback(ctrl); + if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active)) + continue; + if (ctrl->recType == Nif::RC_NiAlphaController) + { + const Nif::NiAlphaController* alphactrl = static_cast(ctrl.getPtr()); + osg::ref_ptr ctrl(new AlphaController(alphactrl->data.getPtr())); + setupController(alphactrl, ctrl, animflags); + stateset->setDataVariance(osg::StateSet::DYNAMIC); + node->addUpdateCallback(ctrl); + } + else if (ctrl->recType == Nif::RC_NiMaterialColorController) + { + const Nif::NiMaterialColorController* matctrl = static_cast(ctrl.getPtr()); + osg::ref_ptr ctrl(new MaterialColorController(matctrl->data.getPtr())); + setupController(matctrl, ctrl, animflags); + stateset->setDataVariance(osg::StateSet::DYNAMIC); + node->addUpdateCallback(ctrl); + } + else + std::cerr << "Unexpected material controller " << ctrl->recType << std::endl; } - else - std::cerr << "Unexpected material controller " << ctrl->recType << std::endl; } - } - void Loader::handleTextureControllers(const Nif::Property *texProperty, osg::Node* node, osg::StateSet *stateset, int animflags) - { - for (Nif::ControllerPtr ctrl = texProperty->controller; !ctrl.empty(); ctrl = ctrl->next) + + void handleTextureControllers(const Nif::Property *texProperty, osg::Node* node, osg::StateSet *stateset, int animflags) { - if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active)) - continue; - if (ctrl->recType == Nif::RC_NiFlipController) + for (Nif::ControllerPtr ctrl = texProperty->controller; !ctrl.empty(); ctrl = ctrl->next) { - const Nif::NiFlipController* flipctrl = static_cast(ctrl.getPtr()); - std::vector > textures; - for (unsigned int i=0; imSources.length(); ++i) + if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active)) + continue; + if (ctrl->recType == Nif::RC_NiFlipController) { - Nif::NiSourceTexturePtr st = flipctrl->mSources[i]; - if (st.empty()) - continue; - - std::string filename = Misc::ResourceHelpers::correctTexturePath(st->filename, resourceManager); - - // tx_creature_werewolf.dds isn't loading in the correct format without this option - osgDB::Options* opts = new osgDB::Options; - opts->setOptionString("dds_dxt1_detect_rgba"); - osgDB::ReaderWriter* reader = osgDB::Registry::instance()->getReaderWriterForExtension("dds"); - osgDB::ReaderWriter::ReadResult result = reader->readImage(*resourceManager->get(filename.c_str()), opts); - textures.push_back(osg::ref_ptr(result.getImage())); + const Nif::NiFlipController* flipctrl = static_cast(ctrl.getPtr()); + std::vector > textures; + for (unsigned int i=0; imSources.length(); ++i) + { + Nif::NiSourceTexturePtr st = flipctrl->mSources[i]; + if (st.empty()) + continue; + + std::string filename = Misc::ResourceHelpers::correctTexturePath(st->filename, mResourceManager); + + // TODO: replace with texture manager + // tx_creature_werewolf.dds isn't loading in the correct format without this option + osgDB::Options* opts = new osgDB::Options; + opts->setOptionString("dds_dxt1_detect_rgba"); + osgDB::ReaderWriter* reader = osgDB::Registry::instance()->getReaderWriterForExtension("dds"); + osgDB::ReaderWriter::ReadResult result = reader->readImage(*mResourceManager->get(filename.c_str()), opts); + textures.push_back(osg::ref_ptr(result.getImage())); + } + osg::ref_ptr callback(new FlipController(flipctrl, textures)); + setupController(ctrl.getPtr(), callback, animflags); + stateset->setDataVariance(osg::StateSet::DYNAMIC); + node->addUpdateCallback(callback); } - osg::ref_ptr callback(new FlipController(flipctrl, textures)); - setupController(ctrl.getPtr(), callback, animflags); - stateset->setDataVariance(osg::StateSet::DYNAMIC); - node->addUpdateCallback(callback); + else + std::cerr << "Unexpected texture controller " << ctrl->recName << std::endl; } - else - std::cerr << "Unexpected texture controller " << ctrl->recName << std::endl; } - } - void Loader::handleParticleSystem(const Nif::Node *nifNode, osg::Group *parentNode, int animflags, int particleflags) - { - osg::ref_ptr partsys (new ParticleSystem); - partsys->setSortMode(osgParticle::ParticleSystem::SORT_BACK_TO_FRONT); - - const Nif::NiAutoNormalParticlesData *particledata = NULL; - if(nifNode->recType == Nif::RC_NiAutoNormalParticles) - particledata = static_cast(nifNode)->data.getPtr(); - else if(nifNode->recType == Nif::RC_NiRotatingParticles) - particledata = static_cast(nifNode)->data.getPtr(); - else - return; - - const Nif::NiParticleSystemController* partctrl = NULL; - for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next) + void handleParticleAffectors(Nif::ExtraPtr e, osg::Group *attachTo, osgParticle::ParticleSystem* partsys, osgParticle::ParticleProcessor::ReferenceFrame rf) { - if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active)) - continue; - if(ctrl->recType == Nif::RC_NiParticleSystemController || ctrl->recType == Nif::RC_NiBSPArrayController) - partctrl = static_cast(ctrl.getPtr()); - } - if (!partctrl) - { - std::cerr << "No particle controller found " << std::endl; - return; + osgParticle::ModularProgram* program = new osgParticle::ModularProgram; + attachTo->addChild(program); + program->setParticleSystem(partsys); + program->setReferenceFrame(rf); + for (; !e.empty(); e = e->extra) + { + if (e->recType == Nif::RC_NiParticleGrowFade) + { + const Nif::NiParticleGrowFade *gf = static_cast(e.getPtr()); + GrowFadeAffector* affector = new GrowFadeAffector(gf->growTime, gf->fadeTime); + program->addOperator(affector); + } + else if (e->recType == Nif::RC_NiGravity) + { + const Nif::NiGravity* gr = static_cast(e.getPtr()); + GravityAffector* affector = new GravityAffector(gr); + program->addOperator(affector); + } + else if (e->recType == Nif::RC_NiParticleColorModifier) + { + const Nif::NiParticleColorModifier *cl = static_cast(e.getPtr()); + const Nif::NiColorData *clrdata = cl->data.getPtr(); + ParticleColorAffector* affector = new ParticleColorAffector(clrdata); + program->addOperator(affector); + } + else if (e->recType == Nif::RC_NiParticleRotation) + { + // TODO: Implement? + } + else + std::cerr << "Unhandled particle modifier " << e->recName << std::endl; + } } - std::vector targets; - if (partctrl->recType == Nif::RC_NiBSPArrayController) + + void handleParticleSystem(const Nif::Node *nifNode, osg::Group *parentNode, int animflags, int particleflags, osg::Node* rootNode) { - getAllNiNodes(partctrl->emitter.getPtr(), targets); - } + osg::ref_ptr partsys (new ParticleSystem); + partsys->setSortMode(osgParticle::ParticleSystem::SORT_BACK_TO_FRONT); + + const Nif::NiAutoNormalParticlesData *particledata = NULL; + if(nifNode->recType == Nif::RC_NiAutoNormalParticles) + particledata = static_cast(nifNode)->data.getPtr(); + else if(nifNode->recType == Nif::RC_NiRotatingParticles) + particledata = static_cast(nifNode)->data.getPtr(); + else + return; - osgParticle::ParticleProcessor::ReferenceFrame rf = (particleflags & Nif::NiNode::ParticleFlag_LocalSpace) - ? osgParticle::ParticleProcessor::RELATIVE_RF - : osgParticle::ParticleProcessor::ABSOLUTE_RF; + const Nif::NiParticleSystemController* partctrl = NULL; + for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next) + { + if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active)) + continue; + if(ctrl->recType == Nif::RC_NiParticleSystemController || ctrl->recType == Nif::RC_NiBSPArrayController) + partctrl = static_cast(ctrl.getPtr()); + } + if (!partctrl) + { + std::cerr << "No particle controller found " << std::endl; + return; + } - // TODO: also take into account the transform by placement in the scene - osg::Matrix particletransform; - if (rf == osgParticle::ParticleProcessor::ABSOLUTE_RF) - particletransform = getWorldTransform(nifNode); + std::vector targets; + if (partctrl->recType == Nif::RC_NiBSPArrayController) + { + getAllNiNodes(partctrl->emitter.getPtr(), targets); + } - int i=0; - for (std::vector::const_iterator it = partctrl->particles.begin(); - iactiveCount && it != partctrl->particles.end(); ++it, ++i) - { - const Nif::NiParticleSystemController::Particle& particle = *it; + osgParticle::ParticleProcessor::ReferenceFrame rf = (particleflags & Nif::NiNode::ParticleFlag_LocalSpace) + ? osgParticle::ParticleProcessor::RELATIVE_RF + : osgParticle::ParticleProcessor::ABSOLUTE_RF; - ParticleAgeSetter particletemplate(std::max(0.f, particle.lifetime)); + // TODO: also take into account the transform by placement in the scene + osg::Matrix particletransform; + if (rf == osgParticle::ParticleProcessor::ABSOLUTE_RF) + particletransform = getWorldTransform(nifNode); - osgParticle::Particle* created = partsys->createParticle(&particletemplate); - created->setLifeTime(std::max(0.f, particle.lifespan)); - osg::Vec4f adjustedVelocity = osg::Vec4f(particle.velocity, 0.f) * particletransform; - created->setVelocity(osg::Vec3f(adjustedVelocity.x(), adjustedVelocity.y(), adjustedVelocity.z())); - created->setPosition(particledata->vertices.at(particle.vertex) * particletransform); + int i=0; + for (std::vector::const_iterator it = partctrl->particles.begin(); + iactiveCount && it != partctrl->particles.end(); ++it, ++i) + { + const Nif::NiParticleSystemController::Particle& particle = *it; - osg::Vec4f partcolor (1.f,1.f,1.f,1.f); - if (particle.vertex < int(particledata->colors.size())) - partcolor = particledata->colors.at(particle.vertex); + ParticleAgeSetter particletemplate(std::max(0.f, particle.lifetime)); - float size = particledata->sizes.at(particle.vertex) * partctrl->size; + osgParticle::Particle* created = partsys->createParticle(&particletemplate); + created->setLifeTime(std::max(0.f, particle.lifespan)); + osg::Vec4f adjustedVelocity = osg::Vec4f(particle.velocity, 0.f) * particletransform; + created->setVelocity(osg::Vec3f(adjustedVelocity.x(), adjustedVelocity.y(), adjustedVelocity.z())); + created->setPosition(particledata->vertices.at(particle.vertex) * particletransform); - created->setSizeRange(osgParticle::rangef(size, size)); - } + osg::Vec4f partcolor (1.f,1.f,1.f,1.f); + if (particle.vertex < int(particledata->colors.size())) + partcolor = particledata->colors.at(particle.vertex); - partsys->setQuota(partctrl->numParticles); + float size = particledata->sizes.at(particle.vertex) * partctrl->size; - partsys->getDefaultParticleTemplate().setSizeRange(osgParticle::rangef(partctrl->size, partctrl->size)); - partsys->getDefaultParticleTemplate().setColorRange(osgParticle::rangev4(osg::Vec4f(1.f,1.f,1.f,1.f), osg::Vec4f(1.f,1.f,1.f,1.f))); - partsys->getDefaultParticleTemplate().setAlphaRange(osgParticle::rangef(1.f, 1.f)); + created->setSizeRange(osgParticle::rangef(size, size)); + } - // ---- emitter + partsys->setQuota(partctrl->numParticles); - osg::ref_ptr emitter = new Emitter(targets); - emitter->setParticleSystem(partsys); - emitter->setReferenceFrame(osgParticle::ParticleProcessor::RELATIVE_RF); + partsys->getDefaultParticleTemplate().setSizeRange(osgParticle::rangef(partctrl->size, partctrl->size)); + partsys->getDefaultParticleTemplate().setColorRange(osgParticle::rangev4(osg::Vec4f(1.f,1.f,1.f,1.f), osg::Vec4f(1.f,1.f,1.f,1.f))); + partsys->getDefaultParticleTemplate().setAlphaRange(osgParticle::rangef(1.f, 1.f)); - osgParticle::ConstantRateCounter* counter = new osgParticle::ConstantRateCounter; - if (partctrl->emitFlags & Nif::NiParticleSystemController::NoAutoAdjust) - counter->setNumberOfParticlesPerSecondToCreate(partctrl->emitRate); - else - counter->setNumberOfParticlesPerSecondToCreate(partctrl->numParticles / (partctrl->lifetime + partctrl->lifetimeRandom/2)); + // ---- emitter - emitter->setCounter(counter); + osg::ref_ptr emitter = new Emitter(targets); + emitter->setParticleSystem(partsys); + emitter->setReferenceFrame(osgParticle::ParticleProcessor::RELATIVE_RF); - ParticleShooter* shooter = new ParticleShooter(partctrl->velocity - partctrl->velocityRandom*0.5f, - partctrl->velocity + partctrl->velocityRandom*0.5f, - partctrl->horizontalDir, partctrl->horizontalAngle, - partctrl->verticalDir, partctrl->verticalAngle, - partctrl->lifetime, partctrl->lifetimeRandom); - emitter->setShooter(shooter); + osgParticle::ConstantRateCounter* counter = new osgParticle::ConstantRateCounter; + if (partctrl->emitFlags & Nif::NiParticleSystemController::NoAutoAdjust) + counter->setNumberOfParticlesPerSecondToCreate(partctrl->emitRate); + else + counter->setNumberOfParticlesPerSecondToCreate(partctrl->numParticles / (partctrl->lifetime + partctrl->lifetimeRandom/2)); - osgParticle::BoxPlacer* placer = new osgParticle::BoxPlacer; - placer->setXRange(-partctrl->offsetRandom.x(), partctrl->offsetRandom.x()); - placer->setYRange(-partctrl->offsetRandom.y(), partctrl->offsetRandom.y()); - placer->setZRange(-partctrl->offsetRandom.z(), partctrl->offsetRandom.z()); + emitter->setCounter(counter); - emitter->setPlacer(placer); + ParticleShooter* shooter = new ParticleShooter(partctrl->velocity - partctrl->velocityRandom*0.5f, + partctrl->velocity + partctrl->velocityRandom*0.5f, + partctrl->horizontalDir, partctrl->horizontalAngle, + partctrl->verticalDir, partctrl->verticalAngle, + partctrl->lifetime, partctrl->lifetimeRandom); + emitter->setShooter(shooter); - // Note: we assume that the Emitter node is placed *before* the Particle node in the scene graph. - // This seems to be true for all NIF files in the game that I've checked, suggesting that NIFs work similar to OSG with regards to update order. - // If something ever violates this assumption, the worst that could happen is the culling being one frame late, which wouldn't be a disaster. + osgParticle::BoxPlacer* placer = new osgParticle::BoxPlacer; + placer->setXRange(-partctrl->offsetRandom.x(), partctrl->offsetRandom.x()); + placer->setYRange(-partctrl->offsetRandom.y(), partctrl->offsetRandom.y()); + placer->setZRange(-partctrl->offsetRandom.z(), partctrl->offsetRandom.z()); - // Creating emitters will need to be changed when cloning a scenegraph is implemented, the particleSystem pointer would become invalid - FindRecIndexVisitor find (partctrl->emitter->recIndex); - mRootNode->accept(find); - if (!find.mFound) - { - std::cerr << "can't find emitter node, wrong node order?" << std::endl; - return; - } - osg::Group* emitterNode = find.mFound; - - // Emitter attached to the emitter node. Note one side effect of the emitter using the CullVisitor is that hiding its node - // actually causes the emitter to stop firing. Convenient, because MW behaves this way too! - emitterNode->addChild(emitter); - - osg::ref_ptr callback(new ParticleSystemController(partctrl)); - setupController(partctrl, callback, animflags); - emitter->setUpdateCallback(callback); - - // ----------- affector (must be after emitters in the scene graph) - osgParticle::ModularProgram* program = new osgParticle::ModularProgram; - program->setParticleSystem(partsys); - program->setReferenceFrame(rf); - emitterNode->addChild(program); - for (Nif::ExtraPtr e = partctrl->extra; !e.empty(); e = e->extra) - { - if (e->recType == Nif::RC_NiParticleGrowFade) - { - const Nif::NiParticleGrowFade *gf = static_cast(e.getPtr()); - GrowFadeAffector* affector = new GrowFadeAffector(gf->growTime, gf->fadeTime); - program->addOperator(affector); - } - else if (e->recType == Nif::RC_NiGravity) - { - const Nif::NiGravity* gr = static_cast(e.getPtr()); - GravityAffector* affector = new GravityAffector(gr); - program->addOperator(affector); - } - else if (e->recType == Nif::RC_NiParticleColorModifier) - { - const Nif::NiParticleColorModifier *cl = static_cast(e.getPtr()); - const Nif::NiColorData *clrdata = cl->data.getPtr(); - ParticleColorAffector* affector = new ParticleColorAffector(clrdata); - program->addOperator(affector); - } - else if (e->recType == Nif::RC_NiParticleRotation) + emitter->setPlacer(placer); + + // Note: we assume that the Emitter node is placed *before* the Particle node in the scene graph. + // This seems to be true for all NIF files in the game that I've checked, suggesting that NIFs work similar to OSG with regards to update order. + // If something ever violates this assumption, the worst that could happen is the culling being one frame late, which wouldn't be a disaster. + + // Creating emitters will need to be changed when cloning a scenegraph is implemented, the particleSystem pointer would become invalid + FindRecIndexVisitor find (partctrl->emitter->recIndex); + rootNode->accept(find); + if (!find.mFound) { - // TODO: Implement? + std::cerr << "can't find emitter node, wrong node order?" << std::endl; + return; } - else - std::cerr << "Unhandled particle modifier " << e->recName << std::endl; - } + osg::Group* emitterNode = find.mFound; - // ----------- + // Emitter attached to the emitter node. Note one side effect of the emitter using the CullVisitor is that hiding its node + // actually causes the emitter to stop firing. Convenient, because MW behaves this way too! + emitterNode->addChild(emitter); - osg::ref_ptr geode (new osg::Geode); - geode->addDrawable(partsys); + osg::ref_ptr callback(new ParticleSystemController(partctrl)); + setupController(partctrl, callback, animflags); + emitter->setUpdateCallback(callback); - std::vector materialProps; - collectMaterialProperties(nifNode, materialProps); - applyMaterialProperties(geode, materialProps, true, animflags); + // affectors must be attached *after* the emitter in the scene graph for correct update order + handleParticleAffectors(partctrl->extra, emitterNode, partsys.get(), rf); - partsys->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF); - partsys->getOrCreateStateSet()->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); + osg::ref_ptr geode (new osg::Geode); + geode->addDrawable(partsys); + std::vector materialProps; + collectMaterialProperties(nifNode, materialProps); + applyMaterialProperties(geode, materialProps, true, animflags); - if (rf == osgParticle::ParticleProcessor::RELATIVE_RF) - parentNode->addChild(geode); - else - { - osg::MatrixTransform* trans = new osg::MatrixTransform; - trans->setUpdateCallback(new InverseWorldMatrix); - trans->addChild(geode); - parentNode->addChild(trans); - } + partsys->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF); + partsys->getOrCreateStateSet()->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); - // particle system updater (after the emitters and affectors in the scene graph) - osgParticle::ParticleSystemUpdater* updater = new osgParticle::ParticleSystemUpdater; - updater->addParticleSystem(partsys); - parentNode->addChild(updater); - } - void Loader::triShapeToGeometry(const Nif::NiTriShape *triShape, osg::Geometry *geometry, osg::Geode* parentGeode, const std::map& boundTextures, int animflags) - { - const Nif::NiTriShapeData* data = triShape->data.getPtr(); + if (rf == osgParticle::ParticleProcessor::RELATIVE_RF) + parentNode->addChild(geode); + else + { + osg::MatrixTransform* trans = new osg::MatrixTransform; + trans->setUpdateCallback(new InverseWorldMatrix); + trans->addChild(geode); + parentNode->addChild(trans); + } - const Nif::NiSkinInstance *skin = (triShape->skin.empty() ? NULL : triShape->skin.getPtr()); - if (skin) + // particle system updater (after the emitters and affectors in the scene graph) + osgParticle::ParticleSystemUpdater* updater = new osgParticle::ParticleSystemUpdater; + updater->addParticleSystem(partsys); + parentNode->addChild(updater); + } + + void triShapeToGeometry(const Nif::NiTriShape *triShape, osg::Geometry *geometry, osg::Geode* parentGeode, const std::map& boundTextures, int animflags) { - // Convert vertices and normals to bone space from bind position. It would be - // better to transform the bones into bind position, but there doesn't seem to - // be a reliable way to do that. - osg::ref_ptr newVerts (new osg::Vec3Array(data->vertices.size())); - osg::ref_ptr newNormals (new osg::Vec3Array(data->normals.size())); + const Nif::NiTriShapeData* data = triShape->data.getPtr(); - const Nif::NiSkinData *skinData = skin->data.getPtr(); - const Nif::NodeList &bones = skin->bones; - for(size_t b = 0;b < bones.length();b++) + const Nif::NiSkinInstance *skin = (triShape->skin.empty() ? NULL : triShape->skin.getPtr()); + if (skin) { - osg::Matrixf mat = toMatrix(skinData->bones[b].trafo); - - mat = mat * getWorldTransform(bones[b].getPtr()); - - const std::vector &weights = skinData->bones[b].weights; - for(size_t i = 0;i < weights.size();i++) + // Convert vertices and normals to bone space from bind position. It would be + // better to transform the bones into bind position, but there doesn't seem to + // be a reliable way to do that. + osg::ref_ptr newVerts (new osg::Vec3Array(data->vertices.size())); + osg::ref_ptr newNormals (new osg::Vec3Array(data->normals.size())); + + const Nif::NiSkinData *skinData = skin->data.getPtr(); + const Nif::NodeList &bones = skin->bones; + for(size_t b = 0;b < bones.length();b++) { - size_t index = weights[i].vertex; - float weight = weights[i].weight; + osg::Matrixf mat = toMatrix(skinData->bones[b].trafo); + + mat = mat * getWorldTransform(bones[b].getPtr()); - osg::Vec4f mult = (osg::Vec4f(data->vertices.at(index),1.f) * mat) * weight; - (*newVerts)[index] += osg::Vec3f(mult.x(),mult.y(),mult.z()); - if(newNormals->size() > index) + const std::vector &weights = skinData->bones[b].weights; + for(size_t i = 0;i < weights.size();i++) { - osg::Vec4 normal(data->normals[index].x(), data->normals[index].y(), data->normals[index].z(), 0.f); - normal = (normal * mat) * weight; - (*newNormals)[index] += osg::Vec3f(normal.x(),normal.y(),normal.z()); + size_t index = weights[i].vertex; + float weight = weights[i].weight; + + osg::Vec4f mult = (osg::Vec4f(data->vertices.at(index),1.f) * mat) * weight; + (*newVerts)[index] += osg::Vec3f(mult.x(),mult.y(),mult.z()); + if(newNormals->size() > index) + { + osg::Vec4 normal(data->normals[index].x(), data->normals[index].y(), data->normals[index].z(), 0.f); + normal = (normal * mat) * weight; + (*newNormals)[index] += osg::Vec3f(normal.x(),normal.y(),normal.z()); + } } } + // Interpolating normalized normals doesn't necessarily give you a normalized result + // Currently we're using GL_NORMALIZE, so this isn't needed + //for (unsigned int i=0;isize();++i) + // (*newNormals)[i].normalize(); + + geometry->setVertexArray(newVerts); + if (!data->normals.empty()) + geometry->setNormalArray(newNormals, osg::Array::BIND_PER_VERTEX); } - // Interpolating normalized normals doesn't necessarily give you a normalized result - // Currently we're using GL_NORMALIZE, so this isn't needed - //for (unsigned int i=0;isize();++i) - // (*newNormals)[i].normalize(); - - geometry->setVertexArray(newVerts); - if (!data->normals.empty()) - geometry->setNormalArray(newNormals, osg::Array::BIND_PER_VERTEX); - } - else - { - geometry->setVertexArray(new osg::Vec3Array(data->vertices.size(), &data->vertices[0])); - if (!data->normals.empty()) - geometry->setNormalArray(new osg::Vec3Array(data->normals.size(), &data->normals[0]), osg::Array::BIND_PER_VERTEX); - } - - for (std::map::const_iterator it = boundTextures.begin(); it != boundTextures.end(); ++it) - { - int textureStage = it->first; - int uvSet = it->second; - if (uvSet >= (int)data->uvlist.size()) + else { - // Occurred in "ascendedsleeper.nif", but only for hidden Shadow nodes, apparently - //std::cerr << "Warning: using an undefined UV set " << uvSet << " on TriShape " << triShape->name << std::endl; - continue; + geometry->setVertexArray(new osg::Vec3Array(data->vertices.size(), &data->vertices[0])); + if (!data->normals.empty()) + geometry->setNormalArray(new osg::Vec3Array(data->normals.size(), &data->normals[0]), osg::Array::BIND_PER_VERTEX); } - geometry->setTexCoordArray(textureStage, new osg::Vec2Array(data->uvlist[uvSet].size(), &data->uvlist[uvSet][0]), osg::Array::BIND_PER_VERTEX); - } - - if (!data->colors.empty()) - geometry->setColorArray(new osg::Vec4Array(data->colors.size(), &data->colors[0]), osg::Array::BIND_PER_VERTEX); - - geometry->addPrimitiveSet(new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLES, - data->triangles.size(), - (unsigned short*)&data->triangles[0])); - - // osg::Material properties are handled here for two reasons: - // - if there are no vertex colors, we need to disable colorMode. - // - there are 3 "overlapping" nif properties that all affect the osg::Material, handling them - // above the actual renderable would be tedious. - std::vector materialProps; - collectMaterialProperties(triShape, materialProps); - applyMaterialProperties(parentGeode, materialProps, !data->colors.empty(), animflags); - } - - void Loader::handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, const std::map& boundTextures, int animflags) - { - osg::ref_ptr geometry; - if(!triShape->controller.empty()) - { - Nif::ControllerPtr ctrl = triShape->controller; - do { - if(ctrl->recType == Nif::RC_NiGeomMorpherController && ctrl->flags & Nif::NiNode::ControllerFlag_Active) + for (std::map::const_iterator it = boundTextures.begin(); it != boundTextures.end(); ++it) + { + int textureStage = it->first; + int uvSet = it->second; + if (uvSet >= (int)data->uvlist.size()) { - geometry = handleMorphGeometry(static_cast(ctrl.getPtr())); - - osg::ref_ptr morphctrl = new GeomMorpherController( - static_cast(ctrl.getPtr())->data.getPtr()); - setupController(ctrl.getPtr(), morphctrl, animflags); - geometry->setUpdateCallback(morphctrl); - break; + // Occurred in "ascendedsleeper.nif", but only for hidden Shadow nodes, apparently + //std::cerr << "Warning: using an undefined UV set " << uvSet << " on TriShape " << triShape->name << std::endl; + continue; } - } while(!(ctrl=ctrl->next).empty()); - } - if (!geometry.get()) - geometry = new osg::Geometry; + geometry->setTexCoordArray(textureStage, new osg::Vec2Array(data->uvlist[uvSet].size(), &data->uvlist[uvSet][0]), osg::Array::BIND_PER_VERTEX); + } - osg::ref_ptr geode (new osg::Geode); - geode->setName(triShape->name); // name will be used for part filtering - triShapeToGeometry(triShape, geometry, geode, boundTextures, animflags); + if (!data->colors.empty()) + geometry->setColorArray(new osg::Vec4Array(data->colors.size(), &data->colors[0]), osg::Array::BIND_PER_VERTEX); - geode->addDrawable(geometry); + geometry->addPrimitiveSet(new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLES, + data->triangles.size(), + (unsigned short*)&data->triangles[0])); - parentNode->addChild(geode); - } + // osg::Material properties are handled here for two reasons: + // - if there are no vertex colors, we need to disable colorMode. + // - there are 3 "overlapping" nif properties that all affect the osg::Material, handling them + // above the actual renderable would be tedious. + std::vector materialProps; + collectMaterialProperties(triShape, materialProps); + applyMaterialProperties(parentGeode, materialProps, !data->colors.empty(), animflags); + } - void Loader::handleSkinnedTriShape(const Nif::NiTriShape *triShape, osg::Group *parentNode, const std::map& boundTextures, int animflags) - { - osg::ref_ptr geode (new osg::Geode); - geode->setName(triShape->name); // name will be used for part filtering - osg::ref_ptr geometry (new osg::Geometry); - triShapeToGeometry(triShape, geometry, geode, boundTextures, animflags); - - osg::ref_ptr rig(new osgAnimation::RigGeometry); - rig->setSourceGeometry(geometry); - // Slightly expand the bounding box to account for movement of the bones - // For more accuracy the skinning should be relative to the parent of the first skinned bone, - // rather than the root bone. - osg::BoundingBox box = geometry->getBound(); - box.expandBy(box._min-(box._max-box._min)/2); - box.expandBy(box._max+(box._max-box._min)/2); - rig->setInitialBound(box); - - const Nif::NiSkinInstance *skin = triShape->skin.getPtr(); - - // Assign bone weights - osg::ref_ptr map (new osgAnimation::VertexInfluenceMap); - - const Nif::NiSkinData *data = skin->data.getPtr(); - const Nif::NodeList &bones = skin->bones; - for(size_t i = 0;i < bones.length();i++) + void handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, const std::map& boundTextures, int animflags) { - std::string boneName = bones[i].getPtr()->name; - - osgAnimation::VertexInfluence influence; - influence.setName(boneName); - const std::vector &weights = data->bones[i].weights; - influence.reserve(weights.size()); - for(size_t j = 0;j < weights.size();j++) + osg::ref_ptr geometry; + if(!triShape->controller.empty()) { - osgAnimation::VertexIndexWeight indexWeight = std::make_pair(weights[j].vertex, weights[j].weight); - influence.push_back(indexWeight); - } + Nif::ControllerPtr ctrl = triShape->controller; + do { + if(ctrl->recType == Nif::RC_NiGeomMorpherController && ctrl->flags & Nif::NiNode::ControllerFlag_Active) + { + geometry = handleMorphGeometry(static_cast(ctrl.getPtr())); - map->insert(std::make_pair(boneName, influence)); - } - rig->setInfluenceMap(map); + osg::ref_ptr morphctrl = new GeomMorpherController( + static_cast(ctrl.getPtr())->data.getPtr()); + setupController(ctrl.getPtr(), morphctrl, animflags); + geometry->setUpdateCallback(morphctrl); + break; + } + } while(!(ctrl=ctrl->next).empty()); + } - osg::ref_ptr trans(new osg::MatrixTransform); - trans->setUpdateCallback(new InvertBoneMatrix()); + if (!geometry.get()) + geometry = new osg::Geometry; - geode->addDrawable(rig); + osg::ref_ptr geode (new osg::Geode); + geode->setName(triShape->name); // name will be used for part filtering + triShapeToGeometry(triShape, geometry, geode, boundTextures, animflags); - trans->addChild(geode); - parentNode->addChild(trans); - } + geode->addDrawable(geometry); - void Loader::handleProperty(const Nif::Property *property, const Nif::Node* nifNode, - osg::Node *node, std::map& boundTextures, int animflags) - { - osg::StateSet* stateset = node->getOrCreateStateSet(); + parentNode->addChild(geode); + } - switch (property->recType) + osg::ref_ptr handleMorphGeometry(const Nif::NiGeomMorpherController* morpher) { - case Nif::RC_NiStencilProperty: + osg::ref_ptr morphGeom = new osgAnimation::MorphGeometry; + morphGeom->setMethod(osgAnimation::MorphGeometry::RELATIVE); + // No normals available in the MorphData + morphGeom->setMorphNormals(false); + + const std::vector& morphs = morpher->data.getPtr()->mMorphs; + // Note we are not interested in morph 0, which just contains the original vertices + for (unsigned int i = 1; i < morphs.size(); ++i) + { + osg::ref_ptr morphTarget = new osg::Geometry; + morphTarget->setVertexArray(new osg::Vec3Array(morphs[i].mVertices.size(), &morphs[i].mVertices[0])); + morphGeom->addMorphTarget(morphTarget, 0.f); + } + return morphGeom; + } + + void handleSkinnedTriShape(const Nif::NiTriShape *triShape, osg::Group *parentNode, const std::map& boundTextures, int animflags) { - const Nif::NiStencilProperty* stencilprop = static_cast(property); - osg::FrontFace* frontFace = new osg::FrontFace; - switch (stencilprop->data.drawMode) + osg::ref_ptr geode (new osg::Geode); + geode->setName(triShape->name); // name will be used for part filtering + osg::ref_ptr geometry (new osg::Geometry); + triShapeToGeometry(triShape, geometry, geode, boundTextures, animflags); + + osg::ref_ptr rig(new osgAnimation::RigGeometry); + rig->setSourceGeometry(geometry); + // Slightly expand the bounding box to account for movement of the bones + // For more accuracy the skinning should be relative to the parent of the first skinned bone, + // rather than the root bone. + osg::BoundingBox box = geometry->getBound(); + box.expandBy(box._min-(box._max-box._min)/2); + box.expandBy(box._max+(box._max-box._min)/2); + rig->setInitialBound(box); + + const Nif::NiSkinInstance *skin = triShape->skin.getPtr(); + + // Assign bone weights + osg::ref_ptr map (new osgAnimation::VertexInfluenceMap); + + const Nif::NiSkinData *data = skin->data.getPtr(); + const Nif::NodeList &bones = skin->bones; + for(size_t i = 0;i < bones.length();i++) { - case 1: - frontFace->setMode(osg::FrontFace::CLOCKWISE); - break; - case 0: - case 2: - default: - frontFace->setMode(osg::FrontFace::COUNTER_CLOCKWISE); - break; + std::string boneName = bones[i].getPtr()->name; + + osgAnimation::VertexInfluence influence; + influence.setName(boneName); + const std::vector &weights = data->bones[i].weights; + influence.reserve(weights.size()); + for(size_t j = 0;j < weights.size();j++) + { + osgAnimation::VertexIndexWeight indexWeight = std::make_pair(weights[j].vertex, weights[j].weight); + influence.push_back(indexWeight); + } + + map->insert(std::make_pair(boneName, influence)); } + rig->setInfluenceMap(map); - stateset->setAttribute(frontFace, osg::StateAttribute::ON); - stateset->setMode(GL_CULL_FACE, stencilprop->data.drawMode == 3 ? osg::StateAttribute::OFF - : osg::StateAttribute::ON); + osg::ref_ptr trans(new osg::MatrixTransform); + trans->setUpdateCallback(new InvertBoneMatrix()); - // Stencil settings not enabled yet, not sure if the original engine is actually using them, - // since they might conflict with Morrowind's stencil shadows. - /* - osg::Stencil* stencil = new osg::Stencil; - stencil->setFunction(func, stencilprop->data.stencilRef, stencilprop->data.stencilMask); + geode->addDrawable(rig); - stateset->setMode(GL_STENCIL_TEST, stencilprop->data.enabled != 0 ? osg::StateAttribute::ON - : osg::StateAttribute::OFF); - */ - } - case Nif::RC_NiWireframeProperty: - { - const Nif::NiWireframeProperty* wireprop = static_cast(property); - osg::PolygonMode* mode = new osg::PolygonMode; - mode->setMode(osg::PolygonMode::FRONT_AND_BACK, wireprop->flags == 0 ? osg::PolygonMode::FILL - : osg::PolygonMode::LINE); - stateset->setAttributeAndModes(mode, osg::StateAttribute::ON); - break; - } - case Nif::RC_NiZBufferProperty: - { - const Nif::NiZBufferProperty* zprop = static_cast(property); - // VER_MW doesn't support a DepthFunction according to NifSkope - osg::Depth* depth = new osg::Depth; - depth->setWriteMask((zprop->flags>>1)&1); - stateset->setAttributeAndModes(depth, osg::StateAttribute::ON); - break; - } - // OSG groups the material properties that NIFs have separate, so we have to parse them all again when one changed - case Nif::RC_NiMaterialProperty: - case Nif::RC_NiVertexColorProperty: - case Nif::RC_NiSpecularProperty: - { - // Handled in handleTriShape so we know whether vertex colors are available - break; + trans->addChild(geode); + parentNode->addChild(trans); } - case Nif::RC_NiAlphaProperty: + + + void handleProperty(const Nif::Property *property, const Nif::Node* nifNode, + osg::Node *node, std::map& boundTextures, int animflags) { - const Nif::NiAlphaProperty* alphaprop = static_cast(property); - osg::BlendFunc* blendfunc = new osg::BlendFunc; - if (alphaprop->flags&1) - { - blendfunc->setFunction(getBlendMode((alphaprop->flags>>1)&0xf), - getBlendMode((alphaprop->flags>>5)&0xf)); - stateset->setAttributeAndModes(blendfunc, osg::StateAttribute::ON); + osg::StateSet* stateset = node->getOrCreateStateSet(); - bool noSort = (alphaprop->flags>>13)&1; - if (!noSort) + switch (property->recType) + { + case Nif::RC_NiStencilProperty: + { + const Nif::NiStencilProperty* stencilprop = static_cast(property); + osg::FrontFace* frontFace = new osg::FrontFace; + switch (stencilprop->data.drawMode) { - stateset->setNestRenderBins(false); - stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); + case 1: + frontFace->setMode(osg::FrontFace::CLOCKWISE); + break; + case 0: + case 2: + default: + frontFace->setMode(osg::FrontFace::COUNTER_CLOCKWISE); + break; } + + stateset->setAttribute(frontFace, osg::StateAttribute::ON); + stateset->setMode(GL_CULL_FACE, stencilprop->data.drawMode == 3 ? osg::StateAttribute::OFF + : osg::StateAttribute::ON); + + // Stencil settings not enabled yet, not sure if the original engine is actually using them, + // since they might conflict with Morrowind's stencil shadows. + /* + osg::Stencil* stencil = new osg::Stencil; + stencil->setFunction(func, stencilprop->data.stencilRef, stencilprop->data.stencilMask); + + stateset->setMode(GL_STENCIL_TEST, stencilprop->data.enabled != 0 ? osg::StateAttribute::ON + : osg::StateAttribute::OFF); + */ } - else + case Nif::RC_NiWireframeProperty: { - stateset->setAttributeAndModes(blendfunc, osg::StateAttribute::OFF); - stateset->setNestRenderBins(false); - stateset->setRenderingHint(osg::StateSet::OPAQUE_BIN); + const Nif::NiWireframeProperty* wireprop = static_cast(property); + osg::PolygonMode* mode = new osg::PolygonMode; + mode->setMode(osg::PolygonMode::FRONT_AND_BACK, wireprop->flags == 0 ? osg::PolygonMode::FILL + : osg::PolygonMode::LINE); + stateset->setAttributeAndModes(mode, osg::StateAttribute::ON); + break; } - - osg::AlphaFunc* alphafunc = new osg::AlphaFunc; - if((alphaprop->flags>>9)&1) + case Nif::RC_NiZBufferProperty: { - alphafunc->setFunction(getTestMode((alphaprop->flags>>10)&0x7), alphaprop->data.threshold/255.f); - stateset->setAttributeAndModes(alphafunc, osg::StateAttribute::ON); + const Nif::NiZBufferProperty* zprop = static_cast(property); + // VER_MW doesn't support a DepthFunction according to NifSkope + osg::Depth* depth = new osg::Depth; + depth->setWriteMask((zprop->flags>>1)&1); + stateset->setAttributeAndModes(depth, osg::StateAttribute::ON); + break; } - else - stateset->setAttributeAndModes(alphafunc, osg::StateAttribute::OFF); - break; - } - case Nif::RC_NiTexturingProperty: - { - const Nif::NiTexturingProperty* texprop = static_cast(property); - for (int i=0; itextures[i].inUse) + // Handled in handleTriShape so we know whether vertex colors are available + break; + } + case Nif::RC_NiAlphaProperty: + { + const Nif::NiAlphaProperty* alphaprop = static_cast(property); + osg::BlendFunc* blendfunc = new osg::BlendFunc; + if (alphaprop->flags&1) { - if (i != Nif::NiTexturingProperty::BaseTexture - && i != Nif::NiTexturingProperty::GlowTexture - && i != Nif::NiTexturingProperty::DarkTexture - && i != Nif::NiTexturingProperty::DetailTexture) - { - std::cerr << "Warning: unhandled texture stage " << i << std::endl; - continue; - } + blendfunc->setFunction(getBlendMode((alphaprop->flags>>1)&0xf), + getBlendMode((alphaprop->flags>>5)&0xf)); + stateset->setAttributeAndModes(blendfunc, osg::StateAttribute::ON); - const Nif::NiTexturingProperty::Texture& tex = texprop->textures[i]; - if(tex.texture.empty()) + bool noSort = (alphaprop->flags>>13)&1; + if (!noSort) { - std::cerr << "Warning: texture layer " << i << " is in use but empty " << std::endl; - continue; + stateset->setNestRenderBins(false); + stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); } - const Nif::NiSourceTexture *st = tex.texture.getPtr(); - if (!st->external) - { - std::cerr << "Warning: unhandled internal texture " << std::endl; - continue; - } - - std::string filename = Misc::ResourceHelpers::correctTexturePath(st->filename, resourceManager); - - // tx_creature_werewolf.dds isn't loading in the correct format without this option - osgDB::Options* opts = new osgDB::Options; - opts->setOptionString("dds_dxt1_detect_rgba"); - osgDB::ReaderWriter* reader = osgDB::Registry::instance()->getReaderWriterForExtension("dds"); - osgDB::ReaderWriter::ReadResult result = reader->readImage(*resourceManager->get(filename.c_str()), opts); - osg::Image* image = result.getImage(); - osg::Texture2D* texture2d = new osg::Texture2D; - texture2d->setUnRefImageDataAfterApply(true); - texture2d->setImage(image); - - unsigned int clamp = static_cast(tex.clamp); - int wrapT = (clamp) & 0x1; - int wrapS = (clamp >> 1) & 0x1; - - texture2d->setWrap(osg::Texture::WRAP_S, wrapS ? osg::Texture::REPEAT : osg::Texture::CLAMP); - texture2d->setWrap(osg::Texture::WRAP_T, wrapT ? osg::Texture::REPEAT : osg::Texture::CLAMP); - - stateset->setTextureAttributeAndModes(i, texture2d, osg::StateAttribute::ON); + } + else + { + stateset->setAttributeAndModes(blendfunc, osg::StateAttribute::OFF); + stateset->setNestRenderBins(false); + stateset->setRenderingHint(osg::StateSet::OPAQUE_BIN); + } - if (i == Nif::NiTexturingProperty::GlowTexture) - { - osg::TexEnv* texEnv = new osg::TexEnv; - texEnv->setMode(osg::TexEnv::ADD); - stateset->setTextureAttributeAndModes(i, texEnv, osg::StateAttribute::ON); - } - else if (i == Nif::NiTexturingProperty::DarkTexture) + osg::AlphaFunc* alphafunc = new osg::AlphaFunc; + if((alphaprop->flags>>9)&1) + { + alphafunc->setFunction(getTestMode((alphaprop->flags>>10)&0x7), alphaprop->data.threshold/255.f); + stateset->setAttributeAndModes(alphafunc, osg::StateAttribute::ON); + } + else + stateset->setAttributeAndModes(alphafunc, osg::StateAttribute::OFF); + break; + } + case Nif::RC_NiTexturingProperty: + { + const Nif::NiTexturingProperty* texprop = static_cast(property); + for (int i=0; itextures[i].inUse) { - // untested - osg::TexEnv* texEnv = new osg::TexEnv; - texEnv->setMode(osg::TexEnv::MODULATE); - stateset->setTextureAttributeAndModes(i, texEnv, osg::StateAttribute::ON); + if (i != Nif::NiTexturingProperty::BaseTexture + && i != Nif::NiTexturingProperty::GlowTexture + && i != Nif::NiTexturingProperty::DarkTexture + && i != Nif::NiTexturingProperty::DetailTexture) + { + std::cerr << "Warning: unhandled texture stage " << i << std::endl; + continue; + } + + const Nif::NiTexturingProperty::Texture& tex = texprop->textures[i]; + if(tex.texture.empty()) + { + std::cerr << "Warning: texture layer " << i << " is in use but empty " << std::endl; + continue; + } + const Nif::NiSourceTexture *st = tex.texture.getPtr(); + if (!st->external) + { + std::cerr << "Warning: unhandled internal texture " << std::endl; + continue; + } + + std::string filename = Misc::ResourceHelpers::correctTexturePath(st->filename, mResourceManager); + + // TODO: replace with texture manager + // tx_creature_werewolf.dds isn't loading in the correct format without this option + osgDB::Options* opts = new osgDB::Options; + opts->setOptionString("dds_dxt1_detect_rgba"); + osgDB::ReaderWriter* reader = osgDB::Registry::instance()->getReaderWriterForExtension("dds"); + osgDB::ReaderWriter::ReadResult result = reader->readImage(*mResourceManager->get(filename.c_str()), opts); + osg::Image* image = result.getImage(); + osg::Texture2D* texture2d = new osg::Texture2D; + texture2d->setUnRefImageDataAfterApply(true); + texture2d->setImage(image); + + unsigned int clamp = static_cast(tex.clamp); + int wrapT = (clamp) & 0x1; + int wrapS = (clamp >> 1) & 0x1; + + texture2d->setWrap(osg::Texture::WRAP_S, wrapS ? osg::Texture::REPEAT : osg::Texture::CLAMP); + texture2d->setWrap(osg::Texture::WRAP_T, wrapT ? osg::Texture::REPEAT : osg::Texture::CLAMP); + + stateset->setTextureAttributeAndModes(i, texture2d, osg::StateAttribute::ON); + + if (i == Nif::NiTexturingProperty::GlowTexture) + { + osg::TexEnv* texEnv = new osg::TexEnv; + texEnv->setMode(osg::TexEnv::ADD); + stateset->setTextureAttributeAndModes(i, texEnv, osg::StateAttribute::ON); + } + else if (i == Nif::NiTexturingProperty::DarkTexture) + { + // untested + osg::TexEnv* texEnv = new osg::TexEnv; + texEnv->setMode(osg::TexEnv::MODULATE); + stateset->setTextureAttributeAndModes(i, texEnv, osg::StateAttribute::ON); + } + else if (i == Nif::NiTexturingProperty::DetailTexture) + { + // untested + osg::TexEnvCombine* texEnv = new osg::TexEnvCombine; + texEnv->setScale_RGB(2.f); + texEnv->setCombine_Alpha(GL_MODULATE); + texEnv->setOperand0_Alpha(GL_SRC_ALPHA); + texEnv->setOperand1_Alpha(GL_SRC_ALPHA); + texEnv->setSource0_Alpha(GL_PREVIOUS); + texEnv->setSource1_Alpha(GL_TEXTURE); + texEnv->setCombine_RGB(GL_MODULATE); + texEnv->setOperand0_RGB(GL_SRC_COLOR); + texEnv->setOperand1_RGB(GL_SRC_COLOR); + texEnv->setSource0_RGB(GL_PREVIOUS); + texEnv->setSource1_RGB(GL_TEXTURE); + stateset->setTextureAttributeAndModes(i, texEnv, osg::StateAttribute::ON); + } + + boundTextures[i] = tex.uvSet; } - else if (i == Nif::NiTexturingProperty::DetailTexture) + else if (boundTextures.find(i) != boundTextures.end()) { - // untested - osg::TexEnvCombine* texEnv = new osg::TexEnvCombine; - texEnv->setScale_RGB(2.f); - texEnv->setCombine_Alpha(GL_MODULATE); - texEnv->setOperand0_Alpha(GL_SRC_ALPHA); - texEnv->setOperand1_Alpha(GL_SRC_ALPHA); - texEnv->setSource0_Alpha(GL_PREVIOUS); - texEnv->setSource1_Alpha(GL_TEXTURE); - texEnv->setCombine_RGB(GL_MODULATE); - texEnv->setOperand0_RGB(GL_SRC_COLOR); - texEnv->setOperand1_RGB(GL_SRC_COLOR); - texEnv->setSource0_RGB(GL_PREVIOUS); - texEnv->setSource1_RGB(GL_TEXTURE); - stateset->setTextureAttributeAndModes(i, texEnv, osg::StateAttribute::ON); + stateset->setTextureAttributeAndModes(i, new osg::Texture2D, osg::StateAttribute::OFF); + boundTextures.erase(i); } - - boundTextures[i] = tex.uvSet; + handleTextureControllers(texprop, node, stateset, animflags); } - else if (boundTextures.find(i) != boundTextures.end()) - { - stateset->setTextureAttributeAndModes(i, new osg::Texture2D, osg::StateAttribute::OFF); - boundTextures.erase(i); - } - handleTextureControllers(texprop, node, stateset, animflags); + break; } - break; - } - case Nif::RC_NiDitherProperty: - { - stateset->setMode(GL_DITHER, property->flags != 0 ? osg::StateAttribute::ON - : osg::StateAttribute::OFF); - break; - } - default: - std::cerr << "Unhandled " << property->recName << std::endl; - break; - } - } - - void Loader::applyMaterialProperties(osg::Node* node, const std::vector& properties, - bool hasVertexColors, int animflags) - { - osg::StateSet* stateset = node->getOrCreateStateSet(); - - int specFlags = 0; // Specular is disabled by default, even if there's a specular color in the NiMaterialProperty - osg::Material* mat = new osg::Material; - mat->setColorMode(hasVertexColors ? osg::Material::AMBIENT_AND_DIFFUSE : osg::Material::OFF); - // TODO: check if the OpenGL default material values are actually the default NIF material values, for when there's no NiMaterialProperty - for (std::vector::const_reverse_iterator it = properties.rbegin(); it != properties.rend(); ++it) - { - const Nif::Property* property = *it; - switch (property->recType) + case Nif::RC_NiDitherProperty: { - case Nif::RC_NiSpecularProperty: - { - specFlags = property->flags; + stateset->setMode(GL_DITHER, property->flags != 0 ? osg::StateAttribute::ON + : osg::StateAttribute::OFF); break; } - case Nif::RC_NiMaterialProperty: + default: + std::cerr << "Unhandled " << property->recName << std::endl; + break; + } + } + + void applyMaterialProperties(osg::Node* node, const std::vector& properties, + bool hasVertexColors, int animflags) + { + osg::StateSet* stateset = node->getOrCreateStateSet(); + + int specFlags = 0; // Specular is disabled by default, even if there's a specular color in the NiMaterialProperty + osg::Material* mat = new osg::Material; + mat->setColorMode(hasVertexColors ? osg::Material::AMBIENT_AND_DIFFUSE : osg::Material::OFF); + // TODO: check if the OpenGL default material values are actually the default NIF material values, for when there's no NiMaterialProperty + for (std::vector::const_reverse_iterator it = properties.rbegin(); it != properties.rend(); ++it) { - const Nif::NiMaterialProperty* matprop = static_cast(property); + const Nif::Property* property = *it; + switch (property->recType) + { + case Nif::RC_NiSpecularProperty: + { + specFlags = property->flags; + break; + } + case Nif::RC_NiMaterialProperty: + { + const Nif::NiMaterialProperty* matprop = static_cast(property); - mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(matprop->data.diffuse, matprop->data.alpha)); - mat->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(matprop->data.ambient, 1.f)); - mat->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(matprop->data.emissive, 1.f)); + mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(matprop->data.diffuse, matprop->data.alpha)); + mat->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(matprop->data.ambient, 1.f)); + mat->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(matprop->data.emissive, 1.f)); - mat->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4f(matprop->data.specular, 1.f)); - mat->setShininess(osg::Material::FRONT_AND_BACK, matprop->data.glossiness); + mat->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4f(matprop->data.specular, 1.f)); + mat->setShininess(osg::Material::FRONT_AND_BACK, matprop->data.glossiness); - if (!matprop->controller.empty()) - handleMaterialControllers(matprop, node, stateset, animflags); + if (!matprop->controller.empty()) + handleMaterialControllers(matprop, node, stateset, animflags); - break; - } - case Nif::RC_NiVertexColorProperty: - { - const Nif::NiVertexColorProperty* vertprop = static_cast(property); - if (!hasVertexColors) break; - switch (vertprop->flags) + } + case Nif::RC_NiVertexColorProperty: { - case 0: - mat->setColorMode(osg::Material::OFF); - break; - case 1: - mat->setColorMode(osg::Material::EMISSION); - break; - case 2: - mat->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE); - break; + const Nif::NiVertexColorProperty* vertprop = static_cast(property); + if (!hasVertexColors) + break; + switch (vertprop->flags) + { + case 0: + mat->setColorMode(osg::Material::OFF); + break; + case 1: + mat->setColorMode(osg::Material::EMISSION); + break; + case 2: + mat->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE); + break; + } + } } } - } + + if (specFlags == 0) + mat->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f,0.f,0.f,0.f)); + + stateset->setAttributeAndModes(mat, osg::StateAttribute::ON); } - if (specFlags == 0) - mat->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f,0.f,0.f,0.f)); + }; + + osg::Node* Loader::load(Nif::NIFFilePtr file, osg::Group *parentNode, TextKeyMap *textKeys) + { + LoaderImpl loader(resourceManager, sShowMarkers); + return loader.load(file, parentNode, textKeys); + } + + osg::Node* Loader::loadAsSkeleton(Nif::NIFFilePtr file, osg::Group *parentNode, TextKeyMap *textKeys) + { + LoaderImpl loader(resourceManager, sShowMarkers); + return loader.loadAsSkeleton(file, parentNode, textKeys); + } - stateset->setAttributeAndModes(mat, osg::StateAttribute::ON); + void Loader::loadKf(Nif::NIFFilePtr kf, osg::Node *rootNode, int sourceIndex, TextKeyMap &textKeys) + { + LoaderImpl loader(resourceManager, sShowMarkers); + loader.loadKf(kf, rootNode, sourceIndex, textKeys); } + } diff --git a/components/nifosg/nifloader.hpp b/components/nifosg/nifloader.hpp index 8f9efe6b3..7ccbbfd2c 100644 --- a/components/nifosg/nifloader.hpp +++ b/components/nifosg/nifloader.hpp @@ -9,24 +9,8 @@ namespace osg { - class Geometry; class Group; class Node; - class MatrixTransform; - class StateSet; - class Geode; -} -namespace osgAnimation -{ - class Bone; -} - -namespace Nif -{ - class Node; - class NiTriShape; - class Property; - class Controller; } namespace NifOsg @@ -62,45 +46,6 @@ namespace NifOsg private: - /// @param createSkeleton If true, use an osgAnimation::Bone for NIF nodes, otherwise an osg::MatrixTransform. - osg::Node* handleNode(const Nif::Node* nifNode, osg::Group* parentNode, bool createSkeleton, - std::map boundTextures, int animflags, int particleflags, bool skipMeshes, TextKeyMap* textKeys); - - void handleMeshControllers(const Nif::Node* nifNode, osg::MatrixTransform* transformNode, const std::map& boundTextures, int animflags); - - void handleNodeControllers(const Nif::Node* nifNode, osg::MatrixTransform* transformNode, int animflags); - - void handleMaterialControllers(const Nif::Property* materialProperty, osg::Node* node, osg::StateSet* stateset, int animflags); - - void handleTextureControllers(const Nif::Property* texProperty, osg::Node* node, osg::StateSet* stateset, int animflags); - - void handleProperty (const Nif::Property* property, const Nif::Node* nifNode, - osg::Node* node, std::map& boundTextures, int animflags); - - void handleParticleSystem(const Nif::Node* nifNode, osg::Group* parentNode, int animflags, int particleflags); - - // Creates an osg::Geometry object for the given TriShape, populates it, and attaches it to the given node. - void handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, const std::map& boundTextures, int animflags); - - // Fills the vertex data for the given TriShape into the given Geometry. - void triShapeToGeometry(const Nif::NiTriShape* triShape, osg::Geometry* geom, osg::Geode* parentGeode, const std::map& boundTextures, int animflags); - - // Creates a skinned osg::Geometry object for the given TriShape, populates it, and attaches it to the given node. - void handleSkinnedTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, const std::map& boundTextures, int animflags); - - // Applies the Properties of the given nifNode onto the StateSet of the given OSG node. - void applyNodeProperties(const Nif::Node* nifNode, osg::Node* applyTo, std::map& boundTextures, int animflags); - - void applyMaterialProperties(osg::Node* node, const std::vector& properties, - bool hasVertexColors, int animflags); - - // Set up the default input and controller function for the given controller. - void setupController(const Nif::Controller* ctrl, Controller* toSetup, int animflags); - - Nif::NIFFilePtr mNif; - - osg::Group* mRootNode; - static bool sShowMarkers; }; From 36ad40827b43d233162ab9c63e5a03e1dbdad64c Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 23 Mar 2015 16:17:40 +0100 Subject: [PATCH 0804/3725] Move parent node attachment out of nifloader --- apps/nifosgtest/test.cpp | 2 +- apps/opencs/view/render/object.cpp | 2 +- components/nifosg/nifloader.cpp | 29 ++++++++++++++--------------- components/nifosg/nifloader.hpp | 9 ++++----- 4 files changed, 20 insertions(+), 22 deletions(-) diff --git a/apps/nifosgtest/test.cpp b/apps/nifosgtest/test.cpp index c21f423bf..0da95d13d 100644 --- a/apps/nifosgtest/test.cpp +++ b/apps/nifosgtest/test.cpp @@ -114,7 +114,7 @@ int main(int argc, char** argv) osg::Group* newNode = new osg::Group; NifOsg::Loader loader; loader.resourceManager = &resourceMgr; - loader.loadAsSkeleton(nif, newNode); + newNode->addChild(loader.loadAsSkeleton(nif)); osg::PositionAttitudeTransform* trans = new osg::PositionAttitudeTransform; root->addChild(trans); diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index f21e8dd4d..f48fcc440 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -60,7 +60,7 @@ void CSVRender::Object::update() Nif::NIFFilePtr file(new Nif::NIFFile(mVFS->get(path), path)); - loader.loadAsSkeleton(file, mBaseNode); + mBaseNode->addChild(loader.loadAsSkeleton(file)); //mObject->setVisibilityFlags (Element_Reference); diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index c00b4abe1..60e94c67a 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -403,7 +403,7 @@ namespace NifOsg rootNode->accept(visitor); } - osg::Node* load(Nif::NIFFilePtr nif, osg::Group *parentNode, TextKeyMap* textKeys) + osg::ref_ptr load(Nif::NIFFilePtr nif, TextKeyMap* textKeys) { if (nif->numRoots() < 1) nif->fail("Found no root nodes"); @@ -414,11 +414,11 @@ namespace NifOsg if (nifNode == NULL) nif->fail("First root was not a node, but a " + r->recName); - osg::Node* created = handleNode(nifNode, parentNode, false, std::map(), 0, 0, false, textKeys); + osg::Node* created = handleNode(nifNode, false, std::map(), 0, 0, false, textKeys); return created; } - osg::Node* loadAsSkeleton(Nif::NIFFilePtr nif, osg::Group *parentNode, TextKeyMap* textKeys) + osg::ref_ptr loadAsSkeleton(Nif::NIFFilePtr nif, TextKeyMap* textKeys) { if (nif->numRoots() < 1) nif->fail("Found no root nodes"); @@ -431,9 +431,7 @@ namespace NifOsg nif->fail("First root was not a node, but a " + r->recName); osg::ref_ptr skel = new osgAnimation::Skeleton; - parentNode->addChild(skel); - - handleNode(nifNode, skel, true, std::map(), 0, 0, false, textKeys); + skel->addChild(handleNode(nifNode, true, std::map(), 0, 0, false, textKeys)); return skel; } @@ -458,7 +456,7 @@ namespace NifOsg } - osg::Node* handleNode(const Nif::Node* nifNode, osg::Group* parentNode, bool createSkeleton, + osg::ref_ptr handleNode(const Nif::Node* nifNode, bool createSkeleton, std::map boundTextures, int animflags, int particleflags, bool skipMeshes, TextKeyMap* textKeys, osg::Node* rootNode=NULL) { osg::ref_ptr transformNode; @@ -484,9 +482,6 @@ namespace NifOsg // Ignoring name for non-bone nodes for now. We might need it later in isolated cases, e.g. AttachLight. - // Insert bones at position 0 to prevent update order problems (see comment in osg Skeleton.cpp) - parentNode->insertChild(0, transformNode); - // UserData used for a variety of features: // - finding the correct emitter node for a particle system // - establishing connections to the animated collision shapes, which are handled in a separate loader @@ -567,7 +562,11 @@ namespace NifOsg for(size_t i = 0;i < children.length();++i) { if(!children[i].empty()) - handleNode(children[i].getPtr(), transformNode, createSkeleton, boundTextures, animflags, particleflags, skipMeshes, textKeys, rootNode); + { + // Insert bones at position 0 to prevent update order problems (see comment in osg Skeleton.cpp) + transformNode->insertChild(0, + handleNode(children[i].getPtr(), createSkeleton, boundTextures, animflags, particleflags, skipMeshes, textKeys, rootNode)); + } } } @@ -1328,16 +1327,16 @@ namespace NifOsg }; - osg::Node* Loader::load(Nif::NIFFilePtr file, osg::Group *parentNode, TextKeyMap *textKeys) + osg::ref_ptr Loader::load(Nif::NIFFilePtr file, TextKeyMap *textKeys) { LoaderImpl loader(resourceManager, sShowMarkers); - return loader.load(file, parentNode, textKeys); + return loader.load(file, textKeys); } - osg::Node* Loader::loadAsSkeleton(Nif::NIFFilePtr file, osg::Group *parentNode, TextKeyMap *textKeys) + osg::ref_ptr Loader::loadAsSkeleton(Nif::NIFFilePtr file, TextKeyMap *textKeys) { LoaderImpl loader(resourceManager, sShowMarkers); - return loader.loadAsSkeleton(file, parentNode, textKeys); + return loader.loadAsSkeleton(file, textKeys); } void Loader::loadKf(Nif::NIFFilePtr kf, osg::Node *rootNode, int sourceIndex, TextKeyMap &textKeys) diff --git a/components/nifosg/nifloader.hpp b/components/nifosg/nifloader.hpp index 7ccbbfd2c..d38b88f97 100644 --- a/components/nifosg/nifloader.hpp +++ b/components/nifosg/nifloader.hpp @@ -7,16 +7,15 @@ #include +#include + namespace osg { - class Group; class Node; } namespace NifOsg { - class Controller; - typedef std::multimap TextKeyMap; /// The main class responsible for loading NIF files into an OSG-Scenegraph. @@ -27,10 +26,10 @@ namespace NifOsg // though, when assembling from several files, i.e. equipment parts /// Create a scene graph for the given NIF. Assumes no skinning is used. /// @param node The parent of the new root node for the created scene graph. - osg::Node* load(Nif::NIFFilePtr file, osg::Group* parentNode, TextKeyMap* textKeys = NULL); + osg::ref_ptr load(Nif::NIFFilePtr file, TextKeyMap* textKeys = NULL); /// Create a scene graph for the given NIF. Assumes skinning will be used. - osg::Node* loadAsSkeleton(Nif::NIFFilePtr file, osg::Group* parentNode, TextKeyMap* textKeys = NULL); + osg::ref_ptr loadAsSkeleton(Nif::NIFFilePtr file, TextKeyMap* textKeys = NULL); /// Load keyframe controllers from the given kf file onto the given scene graph. /// @param sourceIndex The source index for this animation source, used for identifying From 018115601af6f9149d48c73ecc90a80d86ca4d0b Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 23 Mar 2015 16:49:33 +0100 Subject: [PATCH 0805/3725] Move particle emitter/affector handling to separate functions --- components/nifosg/nifloader.cpp | 113 +++++++++++++++++--------------- 1 file changed, 61 insertions(+), 52 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 60e94c67a..b41bc075f 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -442,12 +442,13 @@ namespace NifOsg for (size_t i = 0; i mSource = boost::shared_ptr(new FrameTimeSource); @@ -455,7 +456,6 @@ namespace NifOsg toSetup->mFunction = boost::shared_ptr(new ControllerFunction(ctrl, 1 /*autoPlay*/)); } - osg::ref_ptr handleNode(const Nif::Node* nifNode, bool createSkeleton, std::map boundTextures, int animflags, int particleflags, bool skipMeshes, TextKeyMap* textKeys, osg::Node* rootNode=NULL) { @@ -623,7 +623,6 @@ namespace NifOsg } } - void handleMaterialControllers(const Nif::Property *materialProperty, osg::Node* node, osg::StateSet *stateset, int animflags) { for (Nif::ControllerPtr ctrl = materialProperty->controller; !ctrl.empty(); ctrl = ctrl->next) @@ -651,7 +650,6 @@ namespace NifOsg } } - void handleTextureControllers(const Nif::Property *texProperty, osg::Node* node, osg::StateSet *stateset, int animflags) { for (Nif::ControllerPtr ctrl = texProperty->controller; !ctrl.empty(); ctrl = ctrl->next) @@ -724,11 +722,14 @@ namespace NifOsg } } - - void handleParticleSystem(const Nif::Node *nifNode, osg::Group *parentNode, int animflags, int particleflags, osg::Node* rootNode) + // Load the initial state of the particle system, i.e. the initial particles and their positions, velocity and colors. + void handleParticleInitialState(const Nif::Node* nifNode, osgParticle::ParticleSystem* partsys, const Nif::NiParticleSystemController* partctrl, + osgParticle::ParticleProcessor::ReferenceFrame rf) { - osg::ref_ptr partsys (new ParticleSystem); - partsys->setSortMode(osgParticle::ParticleSystem::SORT_BACK_TO_FRONT); + // TODO: also take into account the transform by placement in the scene (should be done post-load) + osg::Matrix particletransform; + if (rf == osgParticle::ParticleProcessor::ABSOLUTE_RF) + particletransform = getWorldTransform(nifNode); const Nif::NiAutoNormalParticlesData *particledata = NULL; if(nifNode->recType == Nif::RC_NiAutoNormalParticles) @@ -738,35 +739,6 @@ namespace NifOsg else return; - const Nif::NiParticleSystemController* partctrl = NULL; - for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next) - { - if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active)) - continue; - if(ctrl->recType == Nif::RC_NiParticleSystemController || ctrl->recType == Nif::RC_NiBSPArrayController) - partctrl = static_cast(ctrl.getPtr()); - } - if (!partctrl) - { - std::cerr << "No particle controller found " << std::endl; - return; - } - - std::vector targets; - if (partctrl->recType == Nif::RC_NiBSPArrayController) - { - getAllNiNodes(partctrl->emitter.getPtr(), targets); - } - - osgParticle::ParticleProcessor::ReferenceFrame rf = (particleflags & Nif::NiNode::ParticleFlag_LocalSpace) - ? osgParticle::ParticleProcessor::RELATIVE_RF - : osgParticle::ParticleProcessor::ABSOLUTE_RF; - - // TODO: also take into account the transform by placement in the scene - osg::Matrix particletransform; - if (rf == osgParticle::ParticleProcessor::ABSOLUTE_RF) - particletransform = getWorldTransform(nifNode); - int i=0; for (std::vector::const_iterator it = partctrl->particles.begin(); iactiveCount && it != partctrl->particles.end(); ++it, ++i) @@ -789,18 +761,17 @@ namespace NifOsg created->setSizeRange(osgParticle::rangef(size, size)); } + } - partsys->setQuota(partctrl->numParticles); - - partsys->getDefaultParticleTemplate().setSizeRange(osgParticle::rangef(partctrl->size, partctrl->size)); - partsys->getDefaultParticleTemplate().setColorRange(osgParticle::rangev4(osg::Vec4f(1.f,1.f,1.f,1.f), osg::Vec4f(1.f,1.f,1.f,1.f))); - partsys->getDefaultParticleTemplate().setAlphaRange(osgParticle::rangef(1.f, 1.f)); - - // ---- emitter + osg::ref_ptr handleParticleEmitter(const Nif::NiParticleSystemController* partctrl) + { + std::vector targets; + if (partctrl->recType == Nif::RC_NiBSPArrayController) + { + getAllNiNodes(partctrl->emitter.getPtr(), targets); + } osg::ref_ptr emitter = new Emitter(targets); - emitter->setParticleSystem(partsys); - emitter->setReferenceFrame(osgParticle::ParticleProcessor::RELATIVE_RF); osgParticle::ConstantRateCounter* counter = new osgParticle::ConstantRateCounter; if (partctrl->emitFlags & Nif::NiParticleSystemController::NoAutoAdjust) @@ -823,6 +794,43 @@ namespace NifOsg placer->setZRange(-partctrl->offsetRandom.z(), partctrl->offsetRandom.z()); emitter->setPlacer(placer); + return emitter; + } + + void handleParticleSystem(const Nif::Node *nifNode, osg::Group *parentNode, int animflags, int particleflags, osg::Node* rootNode) + { + osg::ref_ptr partsys (new ParticleSystem); + partsys->setSortMode(osgParticle::ParticleSystem::SORT_BACK_TO_FRONT); + + const Nif::NiParticleSystemController* partctrl = NULL; + for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next) + { + if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active)) + continue; + if(ctrl->recType == Nif::RC_NiParticleSystemController || ctrl->recType == Nif::RC_NiBSPArrayController) + partctrl = static_cast(ctrl.getPtr()); + } + if (!partctrl) + { + std::cerr << "No particle controller found " << std::endl; + return; + } + + osgParticle::ParticleProcessor::ReferenceFrame rf = (particleflags & Nif::NiNode::ParticleFlag_LocalSpace) + ? osgParticle::ParticleProcessor::RELATIVE_RF + : osgParticle::ParticleProcessor::ABSOLUTE_RF; + + handleParticleInitialState(nifNode, partsys, partctrl, rf); + + partsys->setQuota(partctrl->numParticles); + + partsys->getDefaultParticleTemplate().setSizeRange(osgParticle::rangef(partctrl->size, partctrl->size)); + partsys->getDefaultParticleTemplate().setColorRange(osgParticle::rangev4(osg::Vec4f(1.f,1.f,1.f,1.f), osg::Vec4f(1.f,1.f,1.f,1.f))); + partsys->getDefaultParticleTemplate().setAlphaRange(osgParticle::rangef(1.f, 1.f)); + + osg::ref_ptr emitter = handleParticleEmitter(partctrl); + emitter->setParticleSystem(partsys); + emitter->setReferenceFrame(osgParticle::ParticleProcessor::RELATIVE_RF); // Note: we assume that the Emitter node is placed *before* the Particle node in the scene graph. // This seems to be true for all NIF files in the game that I've checked, suggesting that NIFs work similar to OSG with regards to update order. @@ -859,6 +867,11 @@ namespace NifOsg partsys->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF); partsys->getOrCreateStateSet()->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); + // particle system updater (after the emitters and affectors in the scene graph) + // I think for correct culling needs to be *before* the ParticleSystem, though osg examples do it the other way + osg::ref_ptr updater = new osgParticle::ParticleSystemUpdater; + updater->addParticleSystem(partsys); + parentNode->addChild(updater); if (rf == osgParticle::ParticleProcessor::RELATIVE_RF) parentNode->addChild(geode); @@ -869,11 +882,6 @@ namespace NifOsg trans->addChild(geode); parentNode->addChild(trans); } - - // particle system updater (after the emitters and affectors in the scene graph) - osgParticle::ParticleSystemUpdater* updater = new osgParticle::ParticleSystemUpdater; - updater->addParticleSystem(partsys); - parentNode->addChild(updater); } void triShapeToGeometry(const Nif::NiTriShape *triShape, osg::Geometry *geometry, osg::Geode* parentGeode, const std::map& boundTextures, int animflags) @@ -1061,7 +1069,7 @@ namespace NifOsg } - void handleProperty(const Nif::Property *property, const Nif::Node* nifNode, + void handleProperty(const Nif::Property *property, osg::Node *node, std::map& boundTextures, int animflags) { osg::StateSet* stateset = node->getOrCreateStateSet(); @@ -1088,6 +1096,7 @@ namespace NifOsg stateset->setMode(GL_CULL_FACE, stencilprop->data.drawMode == 3 ? osg::StateAttribute::OFF : osg::StateAttribute::ON); + // TODO: // Stencil settings not enabled yet, not sure if the original engine is actually using them, // since they might conflict with Morrowind's stencil shadows. /* From 376f0f3ac1e5f1c48d05060ea2d00dc12b95f3fb Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 23 Mar 2015 17:49:06 +0100 Subject: [PATCH 0806/3725] Small cleanup --- components/nifosg/nifloader.cpp | 1 - components/nifosg/nifloader.hpp | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index b41bc075f..6a2523120 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -503,7 +503,6 @@ namespace NifOsg const Nif::NiStringExtraData *sd = static_cast(e.getPtr()); // String markers may contain important information // affecting the entire subtree of this obj - // TODO: implement show markers flag if(sd->string == "MRK" && !mShowMarkers) { // Marker objects. These meshes are only visible in the editor. diff --git a/components/nifosg/nifloader.hpp b/components/nifosg/nifloader.hpp index d38b88f97..43eb8da78 100644 --- a/components/nifosg/nifloader.hpp +++ b/components/nifosg/nifloader.hpp @@ -19,6 +19,8 @@ namespace NifOsg typedef std::multimap TextKeyMap; /// The main class responsible for loading NIF files into an OSG-Scenegraph. + /// @par This scene graph is self-contained and can be cloned using osg::clone if desired. Particle emitters + /// and programs hold a pointer to their ParticleSystem, which would need to be manually updated when cloning. class Loader { public: From 1affa497d55da9a9f35804517b36f45dac8f72ab Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 23 Mar 2015 19:18:48 +0100 Subject: [PATCH 0807/3725] Delete the old nifogre loader --- components/CMakeLists.txt | 4 - components/nifogre/controller.hpp | 111 -- components/nifogre/material.cpp | 442 -------- components/nifogre/material.hpp | 51 - components/nifogre/mesh.cpp | 412 ------- components/nifogre/mesh.hpp | 55 - components/nifogre/ogrenifloader.cpp | 1492 -------------------------- components/nifogre/ogrenifloader.hpp | 151 --- components/nifogre/particles.cpp | 773 ------------- components/nifogre/particles.hpp | 50 - components/nifogre/skeleton.cpp | 179 --- components/nifogre/skeleton.hpp | 62 -- components/ogreinit/ogreinit.cpp | 32 - components/ogreinit/ogreinit.hpp | 3 - 14 files changed, 3817 deletions(-) delete mode 100644 components/nifogre/controller.hpp delete mode 100644 components/nifogre/material.cpp delete mode 100644 components/nifogre/material.hpp delete mode 100644 components/nifogre/mesh.cpp delete mode 100644 components/nifogre/mesh.hpp delete mode 100644 components/nifogre/ogrenifloader.cpp delete mode 100644 components/nifogre/ogrenifloader.hpp delete mode 100644 components/nifogre/particles.cpp delete mode 100644 components/nifogre/particles.hpp delete mode 100644 components/nifogre/skeleton.cpp delete mode 100644 components/nifogre/skeleton.hpp diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index e0ddeb254..48de580bc 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -50,10 +50,6 @@ add_component_dir (nifosg # nifcache # ) -#add_component_dir (nifogre -# ogrenifloader skeleton material mesh particles controller -# ) - #add_component_dir (nifbullet # bulletnifloader # ) diff --git a/components/nifogre/controller.hpp b/components/nifogre/controller.hpp deleted file mode 100644 index cc750ea65..000000000 --- a/components/nifogre/controller.hpp +++ /dev/null @@ -1,111 +0,0 @@ -#ifndef COMPONENTS_NIFOGRE_CONTROLLER_H -#define COMPONENTS_NIFOGRE_CONTROLLER_H - -#include -#include -#include - -namespace NifOgre -{ - - class ValueInterpolator - { - protected: - float interpKey(const Nif::FloatKeyMap::MapType &keys, float time, float def=0.f) const - { - if (keys.size() == 0) - return def; - - if(time <= keys.begin()->first) - return keys.begin()->second.mValue; - - Nif::FloatKeyMap::MapType::const_iterator it = keys.lower_bound(time); - if (it != keys.end()) - { - float aTime = it->first; - const Nif::FloatKey* aKey = &it->second; - - assert (it != keys.begin()); // Shouldn't happen, was checked at beginning of this function - - Nif::FloatKeyMap::MapType::const_iterator last = --it; - float aLastTime = last->first; - const Nif::FloatKey* aLastKey = &last->second; - - float a = (time - aLastTime) / (aTime - aLastTime); - return aLastKey->mValue + ((aKey->mValue - aLastKey->mValue) * a); - } - else - return keys.rbegin()->second.mValue; - } - - Ogre::Vector3 interpKey(const Nif::Vector3KeyMap::MapType &keys, float time) const - { - if(time <= keys.begin()->first) - return keys.begin()->second.mValue; - - Nif::Vector3KeyMap::MapType::const_iterator it = keys.lower_bound(time); - if (it != keys.end()) - { - float aTime = it->first; - const Nif::Vector3Key* aKey = &it->second; - - assert (it != keys.begin()); // Shouldn't happen, was checked at beginning of this function - - Nif::Vector3KeyMap::MapType::const_iterator last = --it; - float aLastTime = last->first; - const Nif::Vector3Key* aLastKey = &last->second; - - float a = (time - aLastTime) / (aTime - aLastTime); - return aLastKey->mValue + ((aKey->mValue - aLastKey->mValue) * a); - } - else - return keys.rbegin()->second.mValue; - } - }; - - // FIXME: Should not be here. - class DefaultFunction : public Ogre::ControllerFunction - { - private: - float mFrequency; - float mPhase; - float mStartTime; - public: - float mStopTime; - - public: - DefaultFunction(const Nif::Controller *ctrl, bool deltaInput) - : Ogre::ControllerFunction(deltaInput) - , mFrequency(ctrl->frequency) - , mPhase(ctrl->phase) - , mStartTime(ctrl->timeStart) - , mStopTime(ctrl->timeStop) - { - if(mDeltaInput) - mDeltaCount = mPhase; - } - - virtual Ogre::Real calculate(Ogre::Real value) - { - if(mDeltaInput) - { - if (mStopTime - mStartTime == 0.f) - return 0.f; - - mDeltaCount += value*mFrequency; - if(mDeltaCount < mStartTime) - mDeltaCount = mStopTime - std::fmod(mStartTime - mDeltaCount, - mStopTime - mStartTime); - mDeltaCount = std::fmod(mDeltaCount - mStartTime, - mStopTime - mStartTime) + mStartTime; - return mDeltaCount; - } - - value = std::min(mStopTime, std::max(mStartTime, value+mPhase)); - return value; - } - }; - -} - -#endif diff --git a/components/nifogre/material.cpp b/components/nifogre/material.cpp deleted file mode 100644 index 90930bca8..000000000 --- a/components/nifogre/material.cpp +++ /dev/null @@ -1,442 +0,0 @@ -#include "material.hpp" - -#include -#include -#include -#include - -#include - -#include -#include - -#include - - -namespace NifOgre -{ - -// Conversion of blend / test mode from NIF -static const char *getBlendFactor(int mode) -{ - switch(mode) - { - case 0: return "one"; - case 1: return "zero"; - case 2: return "src_colour"; - case 3: return "one_minus_src_colour"; - case 4: return "dest_colour"; - case 5: return "one_minus_dest_colour"; - case 6: return "src_alpha"; - case 7: return "one_minus_src_alpha"; - case 8: return "dest_alpha"; - case 9: return "one_minus_dest_alpha"; - case 10: return "src_alpha_saturate"; - } - std::cerr<< "Unexpected blend mode: "<setProperty(textureSlotName + "UVSet", sh::makeProperty(new sh::IntValue(tex.uvSet))); - const std::string clampMode = textureSlotName + "ClampMode"; - switch (tex.clamp) - { - case 0: - material->setProperty(clampMode, sh::makeProperty(new sh::StringValue("clamp clamp"))); - break; - case 1: - material->setProperty(clampMode, sh::makeProperty(new sh::StringValue("clamp wrap"))); - break; - case 2: - material->setProperty(clampMode, sh::makeProperty(new sh::StringValue("wrap clamp"))); - break; - case 3: - default: - material->setProperty(clampMode, sh::makeProperty(new sh::StringValue("wrap wrap"))); - break; - } -} - -Ogre::String NIFMaterialLoader::getMaterial(const Nif::ShapeData *shapedata, - const Ogre::String &name, const Ogre::String &group, - const Nif::NiTexturingProperty *texprop, - const Nif::NiMaterialProperty *matprop, - const Nif::NiAlphaProperty *alphaprop, - const Nif::NiVertexColorProperty *vertprop, - const Nif::NiZBufferProperty *zprop, - const Nif::NiSpecularProperty *specprop, - const Nif::NiWireframeProperty *wireprop, - const Nif::NiStencilProperty *stencilprop, - bool &needTangents, bool particleMaterial) -{ - Ogre::MaterialManager &matMgr = Ogre::MaterialManager::getSingleton(); - Ogre::MaterialPtr material = matMgr.getByName(name); - if(!material.isNull()) - return name; - - Ogre::Vector3 ambient(1.0f); - Ogre::Vector3 diffuse(1.0f); - Ogre::Vector3 specular(0.0f); - Ogre::Vector3 emissive(0.0f); - float glossiness = 0.0f; - float alpha = 1.0f; - int alphaFlags = 0; - int alphaTest = 0; - int vertMode = 2; - //int lightMode = 1; - int depthFlags = 3; - // Default should be 1, but Bloodmoon's models are broken - int specFlags = 0; - int wireFlags = 0; - int drawMode = 1; - Ogre::String texName[7]; - - bool vertexColour = (shapedata->colors.size() != 0); - - // Texture - if(texprop) - { - for(int i = 0;i < 7;i++) - { - if(!texprop->textures[i].inUse) - continue; - if(texprop->textures[i].texture.empty()) - { - warn("Texture layer "+Ogre::StringConverter::toString(i)+" is in use but empty in "+name); - continue; - } - - const Nif::NiSourceTexture *st = texprop->textures[i].texture.getPtr(); - if(st->external) - texName[i] = Misc::ResourceHelpers::correctTexturePath(st->filename); - else - warn("Found internal texture, ignoring."); - } - - Nif::ControllerPtr ctrls = texprop->controller; - while(!ctrls.empty()) - { - if (ctrls->recType != Nif::RC_NiFlipController) // Handled in ogrenifloader - warn("Unhandled texture controller "+ctrls->recName+" in "+name); - ctrls = ctrls->next; - } - } - - // Alpha modifiers - if(alphaprop) - { - alphaFlags = alphaprop->flags; - alphaTest = alphaprop->data.threshold; - - Nif::ControllerPtr ctrls = alphaprop->controller; - while(!ctrls.empty()) - { - warn("Unhandled alpha controller "+ctrls->recName+" in "+name); - ctrls = ctrls->next; - } - } - - // Vertex color handling - if(vertprop) - { - vertMode = vertprop->data.vertmode; - // FIXME: Handle lightmode? - //lightMode = vertprop->data.lightmode; - - Nif::ControllerPtr ctrls = vertprop->controller; - while(!ctrls.empty()) - { - warn("Unhandled vertex color controller "+ctrls->recName+" in "+name); - ctrls = ctrls->next; - } - } - - if(zprop) - { - depthFlags = zprop->flags; - // Depth function??? - - Nif::ControllerPtr ctrls = zprop->controller; - while(!ctrls.empty()) - { - warn("Unhandled depth controller "+ctrls->recName+" in "+name); - ctrls = ctrls->next; - } - } - - if(specprop) - { - specFlags = specprop->flags; - - Nif::ControllerPtr ctrls = specprop->controller; - while(!ctrls.empty()) - { - warn("Unhandled specular controller "+ctrls->recName+" in "+name); - ctrls = ctrls->next; - } - } - - if(wireprop) - { - wireFlags = wireprop->flags; - - Nif::ControllerPtr ctrls = wireprop->controller; - while(!ctrls.empty()) - { - warn("Unhandled wireframe controller "+ctrls->recName+" in "+name); - ctrls = ctrls->next; - } - } - - if(stencilprop) - { - drawMode = stencilprop->data.drawMode; - if (stencilprop->data.enabled) - warn("Unhandled stencil test in "+name); - - Nif::ControllerPtr ctrls = stencilprop->controller; - while(!ctrls.empty()) - { - warn("Unhandled stencil controller "+ctrls->recName+" in "+name); - ctrls = ctrls->next; - } - } - - // Material - if(matprop) - { - ambient = matprop->data.ambient; - diffuse = matprop->data.diffuse; - specular = matprop->data.specular; - emissive = matprop->data.emissive; - glossiness = matprop->data.glossiness; - alpha = matprop->data.alpha; - - Nif::ControllerPtr ctrls = matprop->controller; - while(!ctrls.empty()) - { - if (ctrls->recType != Nif::RC_NiAlphaController && ctrls->recType != Nif::RC_NiMaterialColorController) - warn("Unhandled material controller "+ctrls->recName+" in "+name); - ctrls = ctrls->next; - } - } - - if (particleMaterial) - { - alpha = 1.f; // Apparently ignored, might be overridden by particle vertex colors? - } - - { - // Generate a hash out of all properties that can affect the material. - size_t h = 0; - boost::hash_combine(h, ambient.x); - boost::hash_combine(h, ambient.y); - boost::hash_combine(h, ambient.z); - boost::hash_combine(h, diffuse.x); - boost::hash_combine(h, diffuse.y); - boost::hash_combine(h, diffuse.z); - boost::hash_combine(h, alpha); - boost::hash_combine(h, specular.x); - boost::hash_combine(h, specular.y); - boost::hash_combine(h, specular.z); - boost::hash_combine(h, glossiness); - boost::hash_combine(h, emissive.x); - boost::hash_combine(h, emissive.y); - boost::hash_combine(h, emissive.z); - for(int i = 0;i < 7;i++) - { - if(!texName[i].empty()) - { - boost::hash_combine(h, texName[i]); - boost::hash_combine(h, texprop->textures[i].clamp); - boost::hash_combine(h, texprop->textures[i].uvSet); - } - } - boost::hash_combine(h, drawMode); - boost::hash_combine(h, vertexColour); - boost::hash_combine(h, alphaFlags); - boost::hash_combine(h, alphaTest); - boost::hash_combine(h, vertMode); - boost::hash_combine(h, depthFlags); - boost::hash_combine(h, specFlags); - boost::hash_combine(h, wireFlags); - - std::map::iterator itr = sMaterialMap.find(h); - if (itr != sMaterialMap.end()) - { - // a suitable material exists already - use it - sh::MaterialInstance* instance = sh::Factory::getInstance().getMaterialInstance(itr->second); - needTangents = !sh::retrieveValue(instance->getProperty("normalMap"), instance).get().empty(); - return itr->second; - } - // not found, create a new one - sMaterialMap.insert(std::make_pair(h, name)); - } - - // No existing material like this. Create a new one. - sh::MaterialInstance *instance = sh::Factory::getInstance().createMaterialInstance(name, "openmw_objects_base"); - if(vertMode == 0 || !vertexColour) - { - instance->setProperty("ambient", sh::makeProperty(new sh::Vector4(ambient.x, ambient.y, ambient.z, 1))); - instance->setProperty("diffuse", sh::makeProperty(new sh::Vector4(diffuse.x, diffuse.y, diffuse.z, alpha))); - instance->setProperty("emissive", sh::makeProperty(new sh::Vector4(emissive.x, emissive.y, emissive.z, 1))); - instance->setProperty("vertmode", sh::makeProperty(new sh::StringValue("0"))); - } - else if(vertMode == 1) - { - instance->setProperty("ambient", sh::makeProperty(new sh::Vector4(ambient.x, ambient.y, ambient.z, 1))); - instance->setProperty("diffuse", sh::makeProperty(new sh::Vector4(diffuse.x, diffuse.y, diffuse.z, alpha))); - instance->setProperty("emissive", sh::makeProperty(new sh::StringValue("vertexcolour"))); - instance->setProperty("vertmode", sh::makeProperty(new sh::StringValue("1"))); - } - else if(vertMode == 2) - { - instance->setProperty("ambient", sh::makeProperty(new sh::StringValue("vertexcolour"))); - instance->setProperty("diffuse", sh::makeProperty(new sh::StringValue("vertexcolour"))); - instance->setProperty("emissive", sh::makeProperty(new sh::Vector4(emissive.x, emissive.y, emissive.z, 1))); - instance->setProperty("vertmode", sh::makeProperty(new sh::StringValue("2"))); - } - else - std::cerr<< "Unhandled vertex mode: "<setProperty("specular", sh::makeProperty( - new sh::Vector4(specular.x, specular.y, specular.z, glossiness))); - } - - if(wireFlags) - { - instance->setProperty("polygon_mode", sh::makeProperty(new sh::StringValue("wireframe"))); - } - - if (drawMode == 1) - instance->setProperty("cullmode", sh::makeProperty(new sh::StringValue("clockwise"))); - else if (drawMode == 2) - instance->setProperty("cullmode", sh::makeProperty(new sh::StringValue("anticlockwise"))); - else if (drawMode == 3) - instance->setProperty("cullmode", sh::makeProperty(new sh::StringValue("none"))); - - instance->setProperty("diffuseMap", sh::makeProperty(texName[Nif::NiTexturingProperty::BaseTexture])); - instance->setProperty("normalMap", sh::makeProperty(texName[Nif::NiTexturingProperty::BumpTexture])); - instance->setProperty("detailMap", sh::makeProperty(texName[Nif::NiTexturingProperty::DetailTexture])); - instance->setProperty("emissiveMap", sh::makeProperty(texName[Nif::NiTexturingProperty::GlowTexture])); - instance->setProperty("darkMap", sh::makeProperty(texName[Nif::NiTexturingProperty::DarkTexture])); - if (!texName[Nif::NiTexturingProperty::BaseTexture].empty()) - { - instance->setProperty("use_diffuse_map", sh::makeProperty(new sh::BooleanValue(true))); - setTextureProperties(instance, "diffuseMap", texprop->textures[Nif::NiTexturingProperty::BaseTexture]); - } - if (!texName[Nif::NiTexturingProperty::GlowTexture].empty()) - { - instance->setProperty("use_emissive_map", sh::makeProperty(new sh::BooleanValue(true))); - setTextureProperties(instance, "emissiveMap", texprop->textures[Nif::NiTexturingProperty::GlowTexture]); - } - if (!texName[Nif::NiTexturingProperty::DetailTexture].empty()) - { - instance->setProperty("use_detail_map", sh::makeProperty(new sh::BooleanValue(true))); - setTextureProperties(instance, "detailMap", texprop->textures[Nif::NiTexturingProperty::DetailTexture]); - } - if (!texName[Nif::NiTexturingProperty::DarkTexture].empty()) - { - instance->setProperty("use_dark_map", sh::makeProperty(new sh::BooleanValue(true))); - setTextureProperties(instance, "darkMap", texprop->textures[Nif::NiTexturingProperty::DarkTexture]); - } - - bool useParallax = !texName[Nif::NiTexturingProperty::BumpTexture].empty() - && texName[Nif::NiTexturingProperty::BumpTexture].find("_nh.") != std::string::npos; - instance->setProperty("use_parallax", sh::makeProperty(new sh::BooleanValue(useParallax))); - - for(int i = 0;i < 7;i++) - { - if(i == Nif::NiTexturingProperty::BaseTexture || - i == Nif::NiTexturingProperty::DetailTexture || - i == Nif::NiTexturingProperty::DarkTexture || - i == Nif::NiTexturingProperty::BumpTexture || - i == Nif::NiTexturingProperty::GlowTexture) - continue; - if(!texName[i].empty()) - warn("Ignored texture "+texName[i]+" on layer "+Ogre::StringConverter::toString(i) + " in " + name); - } - - if (vertexColour) - instance->setProperty("has_vertex_colour", sh::makeProperty(new sh::BooleanValue(true))); - - // Override alpha flags based on our override list (transparency-overrides.cfg) - if ((alphaFlags&1) && !texName[0].empty()) - { - NifOverrides::TransparencyResult result = NifOverrides::Overrides::getTransparencyOverride(texName[0]); - if (result.first) - { - alphaFlags = (1<<9) | (6<<10); /* alpha_rejection enabled, greater_equal */ - alphaTest = result.second; - depthFlags = (1<<0) | (1<<1); // depth_write on, depth_check on - } - } - - // Add transparency if NiAlphaProperty was present - if((alphaFlags&1)) - { - std::string blend_mode; - blend_mode += getBlendFactor((alphaFlags>>1)&0xf); - blend_mode += " "; - blend_mode += getBlendFactor((alphaFlags>>5)&0xf); - instance->setProperty("scene_blend", sh::makeProperty(new sh::StringValue(blend_mode))); - } - - if((alphaFlags>>9)&1) - { -#ifndef ANDROID - std::string reject; - reject += getTestMode((alphaFlags>>10)&0x7); - reject += " "; - reject += Ogre::StringConverter::toString(alphaTest); - instance->setProperty("alpha_rejection", sh::makeProperty(new sh::StringValue(reject))); -#else - // alpha test not supported in OpenGL ES 2, use manual implementation in shader - instance->setProperty("alphaTestMode", sh::makeProperty(new sh::IntValue((alphaFlags>>10)&0x7))); - instance->setProperty("alphaTestValue", sh::makeProperty(new sh::FloatValue(alphaTest/255.f))); -#endif - } - else - instance->getMaterial()->setShadowCasterMaterial("openmw_shadowcaster_noalpha"); - - // Ogre usually only sorts if depth write is disabled, so we want "force" instead of "on" - instance->setProperty("transparent_sorting", sh::makeProperty(new sh::StringValue( - ((alphaFlags&1) && !((alphaFlags>>13)&1)) ? "force" : "off"))); - - instance->setProperty("depth_check", sh::makeProperty(new sh::StringValue((depthFlags&1) ? "on" : "off"))); - instance->setProperty("depth_write", sh::makeProperty(new sh::StringValue(((depthFlags>>1)&1) ? "on" : "off"))); - // depth_func??? - - if (!texName[0].empty()) - NifOverrides::Overrides::getMaterialOverrides(texName[0], instance); - - // Don't use texName, as it may be overridden - needTangents = !sh::retrieveValue(instance->getProperty("normalMap"), instance).get().empty(); - - return name; -} - -std::map NIFMaterialLoader::sMaterialMap; - -} diff --git a/components/nifogre/material.hpp b/components/nifogre/material.hpp deleted file mode 100644 index 6be52d1a5..000000000 --- a/components/nifogre/material.hpp +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef COMPONENTS_NIFOGRE_MATERIAL_HPP -#define COMPONENTS_NIFOGRE_MATERIAL_HPP - -#include -#include -#include -#include - -#include - -namespace Nif -{ - class ShapeData; - class NiTexturingProperty; - class NiMaterialProperty; - class NiAlphaProperty; - class NiVertexColorProperty; - class NiZBufferProperty; - class NiSpecularProperty; - class NiWireframeProperty; - class NiStencilProperty; -} - -namespace NifOgre -{ - -class NIFMaterialLoader { - static void warn(const std::string &msg) - { - std::cerr << "NIFMaterialLoader: Warn: " << msg << std::endl; - } - - static std::map sMaterialMap; - -public: - static Ogre::String getMaterial(const Nif::ShapeData *shapedata, - const Ogre::String &name, const Ogre::String &group, - const Nif::NiTexturingProperty *texprop, - const Nif::NiMaterialProperty *matprop, - const Nif::NiAlphaProperty *alphaprop, - const Nif::NiVertexColorProperty *vertprop, - const Nif::NiZBufferProperty *zprop, - const Nif::NiSpecularProperty *specprop, - const Nif::NiWireframeProperty *wireprop, - const Nif::NiStencilProperty *stencilprop, - bool &needTangents, bool particleMaterial=false); -}; - -} - -#endif diff --git a/components/nifogre/mesh.cpp b/components/nifogre/mesh.cpp deleted file mode 100644 index 85c3a7b65..000000000 --- a/components/nifogre/mesh.cpp +++ /dev/null @@ -1,412 +0,0 @@ -#include "mesh.hpp" - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "material.hpp" - -namespace NifOgre -{ - -// Helper class that computes the bounding box and of a mesh -class BoundsFinder -{ - struct MaxMinFinder - { - float max, min; - - MaxMinFinder() - { - min = std::numeric_limits::infinity(); - max = -min; - } - - void add(float f) - { - if (f > max) max = f; - if (f < min) min = f; - } - - // Return Max(max**2, min**2) - float getMaxSquared() - { - float m1 = max*max; - float m2 = min*min; - if (m1 >= m2) return m1; - return m2; - } - }; - - MaxMinFinder X, Y, Z; - -public: - // Add 'verts' vertices to the calculation. The 'data' pointer is - // expected to point to 3*verts floats representing x,y,z for each - // point. - void add(float *data, int verts) - { - for (int i=0;idata.getPtr(); - const Nif::NiSkinInstance *skin = (shape->skin.empty() ? NULL : shape->skin.getPtr()); - std::vector srcVerts = data->vertices; - std::vector srcNorms = data->normals; - Ogre::HardwareBuffer::Usage vertUsage = Ogre::HardwareBuffer::HBU_STATIC; - bool vertShadowBuffer = false; - - if(skin != NULL) - { - vertUsage = Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY; - vertShadowBuffer = true; - - // Only set a skeleton when skinning. Unskinned meshes with a skeleton will be - // explicitly attached later. - mesh->setSkeletonName(mName); - - // Convert vertices and normals to bone space from bind position. It would be - // better to transform the bones into bind position, but there doesn't seem to - // be a reliable way to do that. - std::vector newVerts(srcVerts.size(), Ogre::Vector3(0.0f)); - std::vector newNorms(srcNorms.size(), Ogre::Vector3(0.0f)); - - const Nif::NiSkinData *data = skin->data.getPtr(); - const Nif::NodeList &bones = skin->bones; - for(size_t b = 0;b < bones.length();b++) - { - Ogre::Matrix4 mat; - mat.makeTransform(data->bones[b].trafo.trans, Ogre::Vector3(data->bones[b].trafo.scale), - Ogre::Quaternion(data->bones[b].trafo.rotation)); - mat = bones[b]->getWorldTransform() * mat; - - const std::vector &weights = data->bones[b].weights; - for(size_t i = 0;i < weights.size();i++) - { - size_t index = weights[i].vertex; - float weight = weights[i].weight; - - newVerts.at(index) += (mat*srcVerts[index]) * weight; - if(newNorms.size() > index) - { - Ogre::Vector4 vec4(srcNorms[index][0], srcNorms[index][1], srcNorms[index][2], 0.0f); - vec4 = mat*vec4 * weight; - newNorms[index] += Ogre::Vector3(&vec4[0]); - } - } - } - - srcVerts = newVerts; - srcNorms = newNorms; - } - else - { - Ogre::SkeletonManager *skelMgr = Ogre::SkeletonManager::getSingletonPtr(); - if(skelMgr->getByName(mName).isNull()) - { - // No skinning and no skeleton, so just transform the vertices and - // normals into position. - Ogre::Matrix4 mat4 = shape->getWorldTransform(); - for(size_t i = 0;i < srcVerts.size();i++) - { - Ogre::Vector4 vec4(srcVerts[i].x, srcVerts[i].y, srcVerts[i].z, 1.0f); - vec4 = mat4*vec4; - srcVerts[i] = Ogre::Vector3(&vec4[0]); - } - for(size_t i = 0;i < srcNorms.size();i++) - { - Ogre::Vector4 vec4(srcNorms[i].x, srcNorms[i].y, srcNorms[i].z, 0.0f); - vec4 = mat4*vec4; - srcNorms[i] = Ogre::Vector3(&vec4[0]); - } - } - } - - // Set the bounding box first - BoundsFinder bounds; - bounds.add(&srcVerts[0][0], srcVerts.size()); - if(!bounds.isValid()) - { - float v[3] = { 0.0f, 0.0f, 0.0f }; - bounds.add(&v[0], 1); - } - - mesh->_setBounds(Ogre::AxisAlignedBox(bounds.minX()-0.5f, bounds.minY()-0.5f, bounds.minZ()-0.5f, - bounds.maxX()+0.5f, bounds.maxY()+0.5f, bounds.maxZ()+0.5f)); - mesh->_setBoundingSphereRadius(bounds.getRadius()); - - // This function is just one long stream of Ogre-barf, but it works - // great. - Ogre::HardwareBufferManager *hwBufMgr = Ogre::HardwareBufferManager::getSingletonPtr(); - Ogre::HardwareVertexBufferSharedPtr vbuf; - Ogre::HardwareIndexBufferSharedPtr ibuf; - Ogre::VertexBufferBinding *bind; - Ogre::VertexDeclaration *decl; - int nextBuf = 0; - - Ogre::SubMesh *sub = mesh->createSubMesh(); - - // Add vertices - sub->useSharedVertices = false; - sub->vertexData = new Ogre::VertexData(); - sub->vertexData->vertexStart = 0; - sub->vertexData->vertexCount = srcVerts.size(); - - decl = sub->vertexData->vertexDeclaration; - bind = sub->vertexData->vertexBufferBinding; - if(srcVerts.size()) - { - vbuf = hwBufMgr->createVertexBuffer(Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3), - srcVerts.size(), vertUsage, vertShadowBuffer); - vbuf->writeData(0, vbuf->getSizeInBytes(), &srcVerts[0][0], true); - - decl->addElement(nextBuf, 0, Ogre::VET_FLOAT3, Ogre::VES_POSITION); - bind->setBinding(nextBuf++, vbuf); - } - - // Vertex normals - if(srcNorms.size()) - { - vbuf = hwBufMgr->createVertexBuffer(Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3), - srcNorms.size(), vertUsage, vertShadowBuffer); - vbuf->writeData(0, vbuf->getSizeInBytes(), &srcNorms[0][0], true); - - decl->addElement(nextBuf, 0, Ogre::VET_FLOAT3, Ogre::VES_NORMAL); - bind->setBinding(nextBuf++, vbuf); - } - - // Vertex colors - const std::vector &colors = data->colors; - if(colors.size()) - { - Ogre::RenderSystem *rs = Ogre::Root::getSingleton().getRenderSystem(); - std::vector colorsRGB(colors.size()); - for(size_t i = 0;i < colorsRGB.size();i++) - { - Ogre::ColourValue clr(colors[i][0], colors[i][1], colors[i][2], colors[i][3]); - rs->convertColourValue(clr, &colorsRGB[i]); - } - vbuf = hwBufMgr->createVertexBuffer(Ogre::VertexElement::getTypeSize(Ogre::VET_COLOUR), - colorsRGB.size(), Ogre::HardwareBuffer::HBU_STATIC); - vbuf->writeData(0, vbuf->getSizeInBytes(), &colorsRGB[0], true); - decl->addElement(nextBuf, 0, Ogre::VET_COLOUR, Ogre::VES_DIFFUSE); - bind->setBinding(nextBuf++, vbuf); - } - - // Texture UV coordinates - size_t numUVs = data->uvlist.size(); - if (numUVs) - { - size_t elemSize = Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT2); - - for(size_t i = 0; i < numUVs; i++) - decl->addElement(nextBuf, elemSize*i, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES, i); - - vbuf = hwBufMgr->createVertexBuffer(decl->getVertexSize(nextBuf), srcVerts.size(), - Ogre::HardwareBuffer::HBU_STATIC); - - std::vector allUVs; - allUVs.reserve(srcVerts.size()*numUVs); - for (size_t vert = 0; vertuvlist[i][vert]); - - vbuf->writeData(0, elemSize*srcVerts.size()*numUVs, &allUVs[0], true); - - bind->setBinding(nextBuf++, vbuf); - } - - // Triangle faces - const std::vector &srcIdx = data->triangles; - if(srcIdx.size()) - { - ibuf = hwBufMgr->createIndexBuffer(Ogre::HardwareIndexBuffer::IT_16BIT, srcIdx.size(), - Ogre::HardwareBuffer::HBU_STATIC); - ibuf->writeData(0, ibuf->getSizeInBytes(), &srcIdx[0], true); - sub->indexData->indexBuffer = ibuf; - sub->indexData->indexCount = srcIdx.size(); - sub->indexData->indexStart = 0; - } - - // Assign bone weights for this TriShape - if(skin != NULL) - { - Ogre::SkeletonPtr skel = Ogre::SkeletonManager::getSingleton().getByName(mName); - - const Nif::NiSkinData *data = skin->data.getPtr(); - const Nif::NodeList &bones = skin->bones; - for(size_t i = 0;i < bones.length();i++) - { - Ogre::VertexBoneAssignment boneInf; - boneInf.boneIndex = skel->getBone(bones[i]->name)->getHandle(); - - const std::vector &weights = data->bones[i].weights; - for(size_t j = 0;j < weights.size();j++) - { - boneInf.vertexIndex = weights[j].vertex; - boneInf.weight = weights[j].weight; - sub->addBoneAssignment(boneInf); - } - } - } - - const Nif::NiTexturingProperty *texprop = NULL; - const Nif::NiMaterialProperty *matprop = NULL; - const Nif::NiAlphaProperty *alphaprop = NULL; - const Nif::NiVertexColorProperty *vertprop = NULL; - const Nif::NiZBufferProperty *zprop = NULL; - const Nif::NiSpecularProperty *specprop = NULL; - const Nif::NiWireframeProperty *wireprop = NULL; - const Nif::NiStencilProperty *stencilprop = NULL; - bool needTangents = false; - - shape->getProperties(texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop, stencilprop); - std::string matname = NIFMaterialLoader::getMaterial(data, mesh->getName(), mGroup, - texprop, matprop, alphaprop, - vertprop, zprop, specprop, - wireprop, stencilprop, needTangents); - if(matname.length() > 0) - sub->setMaterialName(matname); - - // build tangents if the material needs them - if (needTangents) - { - unsigned short src,dest; - if (!mesh->suggestTangentVectorBuildParams(Ogre::VES_TANGENT, src,dest)) - mesh->buildTangentVectors(Ogre::VES_TANGENT, src,dest); - } - - - if(!shape->controller.empty()) - { - Nif::ControllerPtr ctrl = shape->controller; - do { - // Load GeomMorpherController into an Ogre::Pose and Animation - if(ctrl->recType == Nif::RC_NiGeomMorpherController && ctrl->flags & Nif::NiNode::ControllerFlag_Active) - { - const Nif::NiGeomMorpherController *geom = - static_cast(ctrl.getPtr()); - - const std::vector& morphs = geom->data.getPtr()->mMorphs; - // Note we are not interested in morph 0, which just contains the original vertices - for (unsigned int i = 1; i < morphs.size(); ++i) - { - Ogre::Pose* pose = mesh->createPose(i); - const Nif::NiMorphData::MorphData& data = morphs[i]; - for (unsigned int v = 0; v < data.mVertices.size(); ++v) - pose->addVertex(v, data.mVertices[v]); - - Ogre::String animationID = Ogre::StringConverter::toString(ctrl->recIndex) - + "_" + Ogre::StringConverter::toString(i); - Ogre::VertexAnimationTrack* track = - mesh->createAnimation(animationID, 0) - ->createVertexTrack(1, Ogre::VAT_POSE); - Ogre::VertexPoseKeyFrame* keyframe = track->createVertexPoseKeyFrame(0); - keyframe->addPoseReference(i-1, 1); - } - - break; - } - } while(!(ctrl=ctrl->next).empty()); - } -} - - -NIFMeshLoader::NIFMeshLoader(const std::string &name, const std::string &group, size_t idx) - : mName(name), mGroup(group), mShapeIndex(idx) -{ -} - -void NIFMeshLoader::loadResource(Ogre::Resource *resource) -{ - Ogre::Mesh *mesh = static_cast(resource); - OgreAssert(mesh, "Attempting to load a mesh into a non-mesh resource!"); - - Nif::NIFFilePtr nif = Nif::Cache::getInstance().load(mName); - if(mShapeIndex >= nif->numRecords()) - { - Ogre::SkeletonManager *skelMgr = Ogre::SkeletonManager::getSingletonPtr(); - if(!skelMgr->getByName(mName).isNull()) - mesh->setSkeletonName(mName); - return; - } - - const Nif::Record *record = nif->getRecord(mShapeIndex); - createSubMesh(mesh, static_cast(record)); -} - - -void NIFMeshLoader::createMesh(const std::string &name, const std::string &fullname, const std::string &group, size_t idx) -{ - NIFMeshLoader::LoaderMap::iterator loader; - loader = sLoaders.insert(std::make_pair(fullname, NIFMeshLoader(name, group, idx))).first; - - Ogre::MeshManager &meshMgr = Ogre::MeshManager::getSingleton(); - Ogre::MeshPtr mesh = meshMgr.createManual(fullname, group, &loader->second); - mesh->setAutoBuildEdgeLists(false); -} - -} diff --git a/components/nifogre/mesh.hpp b/components/nifogre/mesh.hpp deleted file mode 100644 index 731e49c90..000000000 --- a/components/nifogre/mesh.hpp +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef COMPONENTS_NIFOGRE_MESH_HPP -#define COMPONENTS_NIFOGRE_MESH_HPP - -#include -#include -#include -#include - -#include - -namespace Nif -{ - class NiTriShape; -} - -namespace NifOgre -{ - -/** Manual resource loader for NiTriShapes. This is the main class responsible - * for translating the internal NIF meshes into something Ogre can use. - */ -class NIFMeshLoader : Ogre::ManualResourceLoader -{ - static void warn(const std::string &msg) - { - std::cerr << "NIFMeshLoader: Warn: " << msg << std::endl; - } - - static void fail(const std::string &msg) - { - std::cerr << "NIFMeshLoader: Fail: "<< msg << std::endl; - abort(); - } - - std::string mName; - std::string mGroup; - size_t mShapeIndex; - - // Convert NiTriShape to Ogre::SubMesh - void createSubMesh(Ogre::Mesh *mesh, const Nif::NiTriShape *shape); - - typedef std::map LoaderMap; - static LoaderMap sLoaders; - - NIFMeshLoader(const std::string &name, const std::string &group, size_t idx); - - virtual void loadResource(Ogre::Resource *resource); - -public: - static void createMesh(const std::string &name, const std::string &fullname, const std::string &group, size_t idx); -}; - -} - -#endif diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp deleted file mode 100644 index 17df7a3cd..000000000 --- a/components/nifogre/ogrenifloader.cpp +++ /dev/null @@ -1,1492 +0,0 @@ -/* - OpenMW - The completely unofficial reimplementation of Morrowind - Copyright (C) 2008-2010 Nicolay Korslund - Email: < korslund@gmail.com > - WWW: http://openmw.sourceforge.net/ - - This file (ogre_nif_loader.cpp) is part of the OpenMW package. - - OpenMW is distributed as free software: you can redistribute it - and/or modify it under the terms of the GNU General Public License - version 3, as published by the Free Software Foundation. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - version 3 along with this program. If not, see - http://www.gnu.org/licenses/ . - - */ - -#include "ogrenifloader.hpp" - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include - -#include "skeleton.hpp" -#include "material.hpp" -#include "mesh.hpp" -#include "controller.hpp" -#include "particles.hpp" - -namespace -{ - - void getAllNiNodes(const Nif::Node* node, std::vector& out) - { - const Nif::NiNode* ninode = dynamic_cast(node); - if (ninode) - { - out.push_back(ninode); - for (unsigned int i=0; ichildren.length(); ++i) - if (!ninode->children[i].empty()) - getAllNiNodes(ninode->children[i].getPtr(), out); - } - } - -} - -namespace NifOgre -{ - -Ogre::MaterialPtr MaterialControllerManager::getWritableMaterial(Ogre::MovableObject *movable) -{ - if (mClonedMaterials.find(movable) != mClonedMaterials.end()) - return mClonedMaterials[movable]; - - else - { - Ogre::MaterialPtr mat; - if (Ogre::Entity* ent = dynamic_cast(movable)) - mat = ent->getSubEntity(0)->getMaterial(); - else if (Ogre::ParticleSystem* partSys = dynamic_cast(movable)) - mat = Ogre::MaterialManager::getSingleton().getByName(partSys->getMaterialName()); - - static int count=0; - Ogre::String newName = mat->getName() + Ogre::StringConverter::toString(count++); - sh::Factory::getInstance().createMaterialInstance(newName, mat->getName()); - // Make sure techniques are created - sh::Factory::getInstance()._ensureMaterial(newName, "Default"); - mat = Ogre::MaterialManager::getSingleton().getByName(newName); - - mClonedMaterials[movable] = mat; - - if (Ogre::Entity* ent = dynamic_cast(movable)) - ent->getSubEntity(0)->setMaterial(mat); - else if (Ogre::ParticleSystem* partSys = dynamic_cast(movable)) - partSys->setMaterialName(mat->getName()); - - return mat; - } -} - -MaterialControllerManager::~MaterialControllerManager() -{ - for (std::map::iterator it = mClonedMaterials.begin(); it != mClonedMaterials.end(); ++it) - { - sh::Factory::getInstance().destroyMaterialInstance(it->second->getName()); - } -} - -ObjectScene::~ObjectScene() -{ - for(size_t i = 0;i < mLights.size();i++) - { - Ogre::Light *light = mLights[i]; - // If parent is a scene node, it was created specifically for this light. Destroy it now. - if(light->isAttached() && !light->isParentTagPoint()) - mSceneMgr->destroySceneNode(light->getParentSceneNode()); - mSceneMgr->destroyLight(light); - } - for(size_t i = 0;i < mParticles.size();i++) - mSceneMgr->destroyParticleSystem(mParticles[i]); - for(size_t i = 0;i < mEntities.size();i++) - mSceneMgr->destroyEntity(mEntities[i]); - mControllers.clear(); - mLights.clear(); - mParticles.clear(); - mEntities.clear(); - mSkelBase = NULL; -} - -void ObjectScene::setVisibilityFlags (unsigned int flags) -{ - for (std::vector::iterator iter (mEntities.begin()); iter!=mEntities.end(); - ++iter) - (*iter)->setVisibilityFlags (flags); - - for (std::vector::iterator iter (mParticles.begin()); - iter!=mParticles.end(); ++iter) - (*iter)->setVisibilityFlags (flags); - - for (std::vector::iterator iter (mLights.begin()); iter!=mLights.end(); - ++iter) - (*iter)->setVisibilityFlags (flags); -} - -void ObjectScene::rotateBillboardNodes(Ogre::Camera *camera) -{ - for (std::vector::iterator it = mBillboardNodes.begin(); it != mBillboardNodes.end(); ++it) - { - assert(mSkelBase); - Ogre::Node* node = *it; - node->_setDerivedOrientation(mSkelBase->getParentNode()->_getDerivedOrientation().Inverse() * - camera->getRealOrientation()); - } -} - -void ObjectScene::_notifyAttached() -{ - // convert initial particle positions to world space for world-space particle systems - // this can't be done on creation because the particle system is not in its correct world space position yet - for (std::vector::iterator it = mParticles.begin(); it != mParticles.end(); ++it) - { - Ogre::ParticleSystem* psys = *it; - if (psys->getKeepParticlesInLocalSpace()) - continue; - Ogre::ParticleIterator pi = psys->_getIterator(); - while (!pi.end()) - { - Ogre::Particle *p = pi.getNext(); - -#if OGRE_VERSION >= (1 << 16 | 10 << 8 | 0) - Ogre::Vector3& position = p->mPosition; - Ogre::Vector3& direction = p->mDirection; -#else - Ogre::Vector3& position = p->position; - Ogre::Vector3& direction = p->direction; -#endif - - position = - (psys->getParentNode()->_getDerivedOrientation() * - (psys->getParentNode()->_getDerivedScale() * position)) - + psys->getParentNode()->_getDerivedPosition(); - direction = - (psys->getParentNode()->_getDerivedOrientation() * direction); - } - } -} - -// Animates a texture -class FlipController -{ -public: - class Value : public Ogre::ControllerValue - { - private: - Ogre::MovableObject* mMovable; - int mTexSlot; - float mDelta; - std::vector mTextures; - MaterialControllerManager* mMaterialControllerMgr; - - public: - Value(Ogre::MovableObject *movable, const Nif::NiFlipController *ctrl, MaterialControllerManager* materialControllerMgr) - : mMovable(movable) - , mMaterialControllerMgr(materialControllerMgr) - { - mTexSlot = ctrl->mTexSlot; - mDelta = ctrl->mDelta; - for (unsigned int i=0; imSources.length(); ++i) - { - const Nif::NiSourceTexture* tex = ctrl->mSources[i].getPtr(); - if (!tex->external) - std::cerr << "Warning: Found internal texture, ignoring." << std::endl; - mTextures.push_back(Misc::ResourceHelpers::correctTexturePath(tex->filename)); - } - } - - virtual Ogre::Real getValue() const - { - // Should not be called - return 0.0f; - } - - virtual void setValue(Ogre::Real time) - { - if (mDelta == 0) - return; - int curTexture = int(time / mDelta) % mTextures.size(); - - Ogre::MaterialPtr mat = mMaterialControllerMgr->getWritableMaterial(mMovable); - Ogre::Material::TechniqueIterator techs = mat->getTechniqueIterator(); - while(techs.hasMoreElements()) - { - Ogre::Technique *tech = techs.getNext(); - Ogre::Technique::PassIterator passes = tech->getPassIterator(); - while(passes.hasMoreElements()) - { - Ogre::Pass *pass = passes.getNext(); - Ogre::Pass::TextureUnitStateIterator textures = pass->getTextureUnitStateIterator(); - while (textures.hasMoreElements()) - { - Ogre::TextureUnitState *texture = textures.getNext(); - if ((texture->getName() == "diffuseMap" && mTexSlot == Nif::NiTexturingProperty::BaseTexture) - || (texture->getName() == "normalMap" && mTexSlot == Nif::NiTexturingProperty::BumpTexture) - || (texture->getName() == "detailMap" && mTexSlot == Nif::NiTexturingProperty::DetailTexture) - || (texture->getName() == "darkMap" && mTexSlot == Nif::NiTexturingProperty::DarkTexture) - || (texture->getName() == "emissiveMap" && mTexSlot == Nif::NiTexturingProperty::GlowTexture)) - texture->setTextureName(mTextures[curTexture]); - } - } - } - } - }; - - typedef DefaultFunction Function; -}; - -class AlphaController -{ -public: - class Value : public Ogre::ControllerValue, public ValueInterpolator - { - private: - Ogre::MovableObject* mMovable; - Nif::FloatKeyMap mData; - MaterialControllerManager* mMaterialControllerMgr; - - public: - Value(Ogre::MovableObject *movable, const Nif::NiFloatData *data, MaterialControllerManager* materialControllerMgr) - : mMovable(movable) - , mData(data->mKeyList) - , mMaterialControllerMgr(materialControllerMgr) - { - } - - virtual Ogre::Real getValue() const - { - // Should not be called - return 0.0f; - } - - virtual void setValue(Ogre::Real time) - { - float value = interpKey(mData.mKeys, time); - Ogre::MaterialPtr mat = mMaterialControllerMgr->getWritableMaterial(mMovable); - Ogre::Material::TechniqueIterator techs = mat->getTechniqueIterator(); - while(techs.hasMoreElements()) - { - Ogre::Technique *tech = techs.getNext(); - Ogre::Technique::PassIterator passes = tech->getPassIterator(); - while(passes.hasMoreElements()) - { - Ogre::Pass *pass = passes.getNext(); - Ogre::ColourValue diffuse = pass->getDiffuse(); - diffuse.a = value; - pass->setDiffuse(diffuse); - } - } - } - }; - - typedef DefaultFunction Function; -}; - -class MaterialColorController -{ -public: - class Value : public Ogre::ControllerValue, public ValueInterpolator - { - private: - Ogre::MovableObject* mMovable; - Nif::Vector3KeyMap mData; - MaterialControllerManager* mMaterialControllerMgr; - - public: - Value(Ogre::MovableObject *movable, const Nif::NiPosData *data, MaterialControllerManager* materialControllerMgr) - : mMovable(movable) - , mData(data->mKeyList) - , mMaterialControllerMgr(materialControllerMgr) - { - } - - virtual Ogre::Real getValue() const - { - // Should not be called - return 0.0f; - } - - virtual void setValue(Ogre::Real time) - { - Ogre::Vector3 value = interpKey(mData.mKeys, time); - Ogre::MaterialPtr mat = mMaterialControllerMgr->getWritableMaterial(mMovable); - Ogre::Material::TechniqueIterator techs = mat->getTechniqueIterator(); - while(techs.hasMoreElements()) - { - Ogre::Technique *tech = techs.getNext(); - Ogre::Technique::PassIterator passes = tech->getPassIterator(); - while(passes.hasMoreElements()) - { - Ogre::Pass *pass = passes.getNext(); - Ogre::ColourValue diffuse = pass->getDiffuse(); - diffuse.r = value.x; - diffuse.g = value.y; - diffuse.b = value.z; - pass->setDiffuse(diffuse); - } - } - } - }; - - typedef DefaultFunction Function; -}; - -class VisController -{ -public: - class Value : public NodeTargetValue - { - private: - std::vector mData; - - bool calculate(Ogre::Real time) const - { - if(mData.size() == 0) - return true; - - for(size_t i = 1;i < mData.size();i++) - { - if(mData[i].time > time) - return mData[i-1].isSet; - } - return mData.back().isSet; - } - - static void setVisible(Ogre::Node *node, int vis) - { - // Skinned meshes are attached to the scene node, not the bone. - // We use the Node's user data to connect it with the mesh. - Ogre::Any customData = node->getUserObjectBindings().getUserAny(); - - if (!customData.isEmpty()) - Ogre::any_cast(customData)->setVisible(vis); - - Ogre::TagPoint *tag = dynamic_cast(node); - if(tag != NULL) - { - Ogre::MovableObject *obj = tag->getChildObject(); - if(obj != NULL) - obj->setVisible(vis); - } - - Ogre::Node::ChildNodeIterator iter = node->getChildIterator(); - while(iter.hasMoreElements()) - { - node = iter.getNext(); - setVisible(node, vis); - } - } - - public: - Value(Ogre::Node *target, const Nif::NiVisData *data) - : NodeTargetValue(target) - , mData(data->mVis) - { } - - virtual Ogre::Quaternion getRotation(float time) const - { return Ogre::Quaternion(); } - - virtual Ogre::Vector3 getTranslation(float time) const - { return Ogre::Vector3(0.0f); } - - virtual Ogre::Vector3 getScale(float time) const - { return Ogre::Vector3(1.0f); } - - virtual Ogre::Real getValue() const - { - // Should not be called - return 0.0f; - } - - virtual void setValue(Ogre::Real time) - { - bool vis = calculate(time); - setVisible(mNode, vis); - } - }; - - typedef DefaultFunction Function; -}; - -class KeyframeController -{ -public: - class Value : public NodeTargetValue, public ValueInterpolator - { - private: - const Nif::QuaternionKeyMap* mRotations; - const Nif::FloatKeyMap* mXRotations; - const Nif::FloatKeyMap* mYRotations; - const Nif::FloatKeyMap* mZRotations; - const Nif::Vector3KeyMap* mTranslations; - const Nif::FloatKeyMap* mScales; - Nif::NIFFilePtr mNif; // Hold a SharedPtr to make sure key lists stay valid - - using ValueInterpolator::interpKey; - - static Ogre::Quaternion interpKey(const Nif::QuaternionKeyMap::MapType &keys, float time) - { - if(time <= keys.begin()->first) - return keys.begin()->second.mValue; - - Nif::QuaternionKeyMap::MapType::const_iterator it = keys.lower_bound(time); - if (it != keys.end()) - { - float aTime = it->first; - const Nif::QuaternionKey* aKey = &it->second; - - assert (it != keys.begin()); // Shouldn't happen, was checked at beginning of this function - - Nif::QuaternionKeyMap::MapType::const_iterator last = --it; - float aLastTime = last->first; - const Nif::QuaternionKey* aLastKey = &last->second; - - float a = (time - aLastTime) / (aTime - aLastTime); - return Ogre::Quaternion::nlerp(a, aLastKey->mValue, aKey->mValue); - } - else - return keys.rbegin()->second.mValue; - } - - Ogre::Quaternion getXYZRotation(float time) const - { - float xrot = interpKey(mXRotations->mKeys, time); - float yrot = interpKey(mYRotations->mKeys, time); - float zrot = interpKey(mZRotations->mKeys, time); - Ogre::Quaternion xr(Ogre::Radian(xrot), Ogre::Vector3::UNIT_X); - Ogre::Quaternion yr(Ogre::Radian(yrot), Ogre::Vector3::UNIT_Y); - Ogre::Quaternion zr(Ogre::Radian(zrot), Ogre::Vector3::UNIT_Z); - return (zr*yr*xr); - } - - public: - /// @note The NiKeyFrameData must be valid as long as this KeyframeController exists. - Value(Ogre::Node *target, const Nif::NIFFilePtr& nif, const Nif::NiKeyframeData *data) - : NodeTargetValue(target) - , mRotations(&data->mRotations) - , mXRotations(&data->mXRotations) - , mYRotations(&data->mYRotations) - , mZRotations(&data->mZRotations) - , mTranslations(&data->mTranslations) - , mScales(&data->mScales) - , mNif(nif) - { } - - virtual Ogre::Quaternion getRotation(float time) const - { - if(mRotations->mKeys.size() > 0) - return interpKey(mRotations->mKeys, time); - else if (!mXRotations->mKeys.empty() || !mYRotations->mKeys.empty() || !mZRotations->mKeys.empty()) - return getXYZRotation(time); - return mNode->getOrientation(); - } - - virtual Ogre::Vector3 getTranslation(float time) const - { - if(mTranslations->mKeys.size() > 0) - return interpKey(mTranslations->mKeys, time); - return mNode->getPosition(); - } - - virtual Ogre::Vector3 getScale(float time) const - { - if(mScales->mKeys.size() > 0) - return Ogre::Vector3(interpKey(mScales->mKeys, time)); - return mNode->getScale(); - } - - virtual Ogre::Real getValue() const - { - // Should not be called - return 0.0f; - } - - virtual void setValue(Ogre::Real time) - { - if(mRotations->mKeys.size() > 0) - mNode->setOrientation(interpKey(mRotations->mKeys, time)); - else if (!mXRotations->mKeys.empty() || !mYRotations->mKeys.empty() || !mZRotations->mKeys.empty()) - mNode->setOrientation(getXYZRotation(time)); - if(mTranslations->mKeys.size() > 0) - mNode->setPosition(interpKey(mTranslations->mKeys, time)); - if(mScales->mKeys.size() > 0) - mNode->setScale(Ogre::Vector3(interpKey(mScales->mKeys, time))); - } - }; - - typedef DefaultFunction Function; -}; - -class UVController -{ -public: - class Value : public Ogre::ControllerValue, public ValueInterpolator - { - private: - Ogre::MovableObject* mMovable; - Nif::FloatKeyMap mUTrans; - Nif::FloatKeyMap mVTrans; - Nif::FloatKeyMap mUScale; - Nif::FloatKeyMap mVScale; - MaterialControllerManager* mMaterialControllerMgr; - - public: - Value(Ogre::MovableObject* movable, const Nif::NiUVData *data, MaterialControllerManager* materialControllerMgr) - : mMovable(movable) - , mUTrans(data->mKeyList[0]) - , mVTrans(data->mKeyList[1]) - , mUScale(data->mKeyList[2]) - , mVScale(data->mKeyList[3]) - , mMaterialControllerMgr(materialControllerMgr) - { } - - virtual Ogre::Real getValue() const - { - // Should not be called - return 1.0f; - } - - virtual void setValue(Ogre::Real value) - { - float uTrans = interpKey(mUTrans.mKeys, value, 0.0f); - float vTrans = interpKey(mVTrans.mKeys, value, 0.0f); - float uScale = interpKey(mUScale.mKeys, value, 1.0f); - float vScale = interpKey(mVScale.mKeys, value, 1.0f); - - Ogre::MaterialPtr material = mMaterialControllerMgr->getWritableMaterial(mMovable); - - Ogre::Material::TechniqueIterator techs = material->getTechniqueIterator(); - while(techs.hasMoreElements()) - { - Ogre::Technique *tech = techs.getNext(); - Ogre::Technique::PassIterator passes = tech->getPassIterator(); - while(passes.hasMoreElements()) - { - Ogre::Pass *pass = passes.getNext(); - Ogre::TextureUnitState *tex = pass->getTextureUnitState(0); - tex->setTextureScroll(uTrans, vTrans); - tex->setTextureScale(uScale, vScale); - } - } - } - }; - - typedef DefaultFunction Function; -}; - -class ParticleSystemController -{ -public: - class Value : public Ogre::ControllerValue - { - private: - Ogre::ParticleSystem *mParticleSys; - float mEmitStart; - float mEmitStop; - - public: - Value(Ogre::ParticleSystem *psys, const Nif::NiParticleSystemController *pctrl) - : mParticleSys(psys) - , mEmitStart(pctrl->startTime) - , mEmitStop(pctrl->stopTime) - { - } - - Ogre::Real getValue() const - { return 0.0f; } - - void setValue(Ogre::Real value) - { - mParticleSys->setEmitting(value >= mEmitStart && value < mEmitStop); - } - }; - - typedef DefaultFunction Function; -}; - -class GeomMorpherController -{ -public: - class Value : public Ogre::ControllerValue, public ValueInterpolator - { - private: - Ogre::Entity *mEntity; - std::vector mMorphs; - size_t mControllerIndex; - - std::vector mVertices; - - public: - Value(Ogre::Entity *ent, const Nif::NiMorphData *data, size_t controllerIndex) - : mEntity(ent) - , mMorphs(data->mMorphs) - , mControllerIndex(controllerIndex) - { - } - - virtual Ogre::Real getValue() const - { - // Should not be called - return 0.0f; - } - - virtual void setValue(Ogre::Real time) - { - if (mMorphs.size() <= 1) - return; - int i = 1; - for (std::vector::iterator it = mMorphs.begin()+1; it != mMorphs.end(); ++it,++i) - { - float val = 0; - if (!it->mData.mKeys.empty()) - val = interpKey(it->mData.mKeys, time); - val = std::max(0.f, std::min(1.f, val)); - - Ogre::String animationID = Ogre::StringConverter::toString(mControllerIndex) - + "_" + Ogre::StringConverter::toString(i); - - Ogre::AnimationState* state = mEntity->getAnimationState(animationID); - state->setEnabled(val > 0); - state->setWeight(val); - } - } - }; - - typedef DefaultFunction Function; -}; - - -/** Object creator for NIFs. This is the main class responsible for creating - * "live" Ogre objects (entities, particle systems, controllers, etc) from - * their NIF equivalents. - */ -class NIFObjectLoader -{ - static bool sShowMarkers; -public: - static void setShowMarkers(bool show) - { - sShowMarkers = show; - } -private: - - static void warn(const std::string &msg) - { - std::cerr << "NIFObjectLoader: Warn: " << msg << std::endl; - } - - static void createEntity(const std::string &name, const std::string &group, - Ogre::SceneManager *sceneMgr, ObjectScenePtr scene, - const Nif::Node *node, int flags, int animflags) - { - const Nif::NiTriShape *shape = static_cast(node); - - std::string fullname = name+"@index="+Ogre::StringConverter::toString(shape->recIndex); - if(shape->name.length() > 0) - fullname += "@shape="+shape->name; - Misc::StringUtils::toLower(fullname); - - Ogre::MeshManager &meshMgr = Ogre::MeshManager::getSingleton(); - if(meshMgr.getByName(fullname).isNull()) - NIFMeshLoader::createMesh(name, fullname, group, shape->recIndex); - - Ogre::Entity *entity = sceneMgr->createEntity(fullname); - -#if OGRE_VERSION >= (1 << 16 | 10 << 8 | 0) - // Enable skeleton-based bounding boxes. With the static bounding box, - // the animation may cause parts to go outside the box and cause culling problems. - if (entity->hasSkeleton()) - entity->setUpdateBoundingBoxFromSkeleton(true); -#endif - - entity->setVisible(!(flags&Nif::NiNode::Flag_Hidden)); - - scene->mEntities.push_back(entity); - if(scene->mSkelBase) - { - int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, shape->recIndex); - Ogre::Bone *trgtbone = scene->mSkelBase->getSkeleton()->getBone(trgtid); - trgtbone->getUserObjectBindings().setUserAny(Ogre::Any(static_cast(entity))); - - if(entity->hasSkeleton()) - entity->shareSkeletonInstanceWith(scene->mSkelBase); - else - scene->mSkelBase->attachObjectToBone(trgtbone->getName(), entity); - } - - Nif::ControllerPtr ctrl = node->controller; - while(!ctrl.empty()) - { - if (ctrl->flags & Nif::NiNode::ControllerFlag_Active) - { - if(ctrl->recType == Nif::RC_NiUVController) - { - const Nif::NiUVController *uv = static_cast(ctrl.getPtr()); - - Ogre::ControllerValueRealPtr srcval((animflags&Nif::NiNode::AnimFlag_AutoPlay) ? - Ogre::ControllerManager::getSingleton().getFrameTimeSource() : - Ogre::ControllerValueRealPtr()); - Ogre::ControllerValueRealPtr dstval(OGRE_NEW UVController::Value(entity, uv->data.getPtr(), &scene->mMaterialControllerMgr)); - - UVController::Function* function = OGRE_NEW UVController::Function(uv, (animflags&Nif::NiNode::AnimFlag_AutoPlay)); - scene->mMaxControllerLength = std::max(function->mStopTime, scene->mMaxControllerLength); - Ogre::ControllerFunctionRealPtr func(function); - - scene->mControllers.push_back(Ogre::Controller(srcval, dstval, func)); - } - else if(ctrl->recType == Nif::RC_NiGeomMorpherController) - { - const Nif::NiGeomMorpherController *geom = static_cast(ctrl.getPtr()); - - Ogre::ControllerValueRealPtr srcval((animflags&Nif::NiNode::AnimFlag_AutoPlay) ? - Ogre::ControllerManager::getSingleton().getFrameTimeSource() : - Ogre::ControllerValueRealPtr()); - Ogre::ControllerValueRealPtr dstval(OGRE_NEW GeomMorpherController::Value( - entity, geom->data.getPtr(), geom->recIndex)); - - GeomMorpherController::Function* function = OGRE_NEW GeomMorpherController::Function(geom, (animflags&Nif::NiNode::AnimFlag_AutoPlay)); - scene->mMaxControllerLength = std::max(function->mStopTime, scene->mMaxControllerLength); - Ogre::ControllerFunctionRealPtr func(function); - - scene->mControllers.push_back(Ogre::Controller(srcval, dstval, func)); - } - } - ctrl = ctrl->next; - } - - createMaterialControllers(shape, entity, animflags, scene); - } - - static void createMaterialControllers (const Nif::Node* node, Ogre::MovableObject* movable, int animflags, ObjectScenePtr scene) - { - const Nif::NiTexturingProperty *texprop = NULL; - const Nif::NiMaterialProperty *matprop = NULL; - const Nif::NiAlphaProperty *alphaprop = NULL; - const Nif::NiVertexColorProperty *vertprop = NULL; - const Nif::NiZBufferProperty *zprop = NULL; - const Nif::NiSpecularProperty *specprop = NULL; - const Nif::NiWireframeProperty *wireprop = NULL; - const Nif::NiStencilProperty *stencilprop = NULL; - node->getProperties(texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop, stencilprop); - - Ogre::ControllerValueRealPtr srcval((animflags&Nif::NiNode::AnimFlag_AutoPlay) ? - Ogre::ControllerManager::getSingleton().getFrameTimeSource() : - Ogre::ControllerValueRealPtr()); - - if(matprop) - { - Nif::ControllerPtr ctrls = matprop->controller; - while(!ctrls.empty()) - { - if (ctrls->recType == Nif::RC_NiAlphaController) - { - const Nif::NiAlphaController *alphaCtrl = static_cast(ctrls.getPtr()); - Ogre::ControllerValueRealPtr dstval(OGRE_NEW AlphaController::Value(movable, alphaCtrl->data.getPtr(), &scene->mMaterialControllerMgr)); - AlphaController::Function* function = OGRE_NEW AlphaController::Function(alphaCtrl, (animflags&Nif::NiNode::AnimFlag_AutoPlay)); - scene->mMaxControllerLength = std::max(function->mStopTime, scene->mMaxControllerLength); - Ogre::ControllerFunctionRealPtr func(function); - scene->mControllers.push_back(Ogre::Controller(srcval, dstval, func)); - } - else if (ctrls->recType == Nif::RC_NiMaterialColorController) - { - const Nif::NiMaterialColorController *matCtrl = static_cast(ctrls.getPtr()); - Ogre::ControllerValueRealPtr dstval(OGRE_NEW MaterialColorController::Value(movable, matCtrl->data.getPtr(), &scene->mMaterialControllerMgr)); - MaterialColorController::Function* function = OGRE_NEW MaterialColorController::Function(matCtrl, (animflags&Nif::NiNode::AnimFlag_AutoPlay)); - scene->mMaxControllerLength = std::max(function->mStopTime, scene->mMaxControllerLength); - Ogre::ControllerFunctionRealPtr func(function); - scene->mControllers.push_back(Ogre::Controller(srcval, dstval, func)); - } - - ctrls = ctrls->next; - } - } - if (texprop) - { - Nif::ControllerPtr ctrls = texprop->controller; - while(!ctrls.empty()) - { - if (ctrls->recType == Nif::RC_NiFlipController) - { - const Nif::NiFlipController *flipCtrl = static_cast(ctrls.getPtr()); - - - Ogre::ControllerValueRealPtr dstval(OGRE_NEW FlipController::Value( - movable, flipCtrl, &scene->mMaterialControllerMgr)); - FlipController::Function* function = OGRE_NEW FlipController::Function(flipCtrl, (animflags&Nif::NiNode::AnimFlag_AutoPlay)); - scene->mMaxControllerLength = std::max(function->mStopTime, scene->mMaxControllerLength); - Ogre::ControllerFunctionRealPtr func(function); - scene->mControllers.push_back(Ogre::Controller(srcval, dstval, func)); - } - - ctrls = ctrls->next; - } - } - } - - static void createParticleEmitterAffectors(Ogre::ParticleSystem *partsys, - const Nif::NiParticleSystemController *partctrl, Ogre::Bone* bone, - const std::string& skelBaseName) - { - Ogre::ParticleEmitter *emitter = partsys->addEmitter("Nif"); - emitter->setParticleVelocity(partctrl->velocity - partctrl->velocityRandom*0.5f, - partctrl->velocity + partctrl->velocityRandom*0.5f); - - if (partctrl->emitFlags & Nif::NiParticleSystemController::NoAutoAdjust) - emitter->setEmissionRate(partctrl->emitRate); - else - emitter->setEmissionRate(partctrl->numParticles / (partctrl->lifetime + partctrl->lifetimeRandom/2)); - - emitter->setTimeToLive(std::max(0.f, partctrl->lifetime), - std::max(0.f, partctrl->lifetime + partctrl->lifetimeRandom)); - emitter->setParameter("width", Ogre::StringConverter::toString(partctrl->offsetRandom.x)); - emitter->setParameter("height", Ogre::StringConverter::toString(partctrl->offsetRandom.y)); - emitter->setParameter("depth", Ogre::StringConverter::toString(partctrl->offsetRandom.z)); - emitter->setParameter("vertical_direction", Ogre::StringConverter::toString(Ogre::Radian(partctrl->verticalDir).valueDegrees())); - emitter->setParameter("vertical_angle", Ogre::StringConverter::toString(Ogre::Radian(partctrl->verticalAngle).valueDegrees())); - emitter->setParameter("horizontal_direction", Ogre::StringConverter::toString(Ogre::Radian(partctrl->horizontalDir).valueDegrees())); - emitter->setParameter("horizontal_angle", Ogre::StringConverter::toString(Ogre::Radian(partctrl->horizontalAngle).valueDegrees())); - - Nif::ExtraPtr e = partctrl->extra; - while(!e.empty()) - { - if(e->recType == Nif::RC_NiParticleGrowFade) - { - const Nif::NiParticleGrowFade *gf = static_cast(e.getPtr()); - - Ogre::ParticleAffector *affector = partsys->addAffector("GrowFade"); - affector->setParameter("grow_time", Ogre::StringConverter::toString(gf->growTime)); - affector->setParameter("fade_time", Ogre::StringConverter::toString(gf->fadeTime)); - } - else if(e->recType == Nif::RC_NiGravity) - { - const Nif::NiGravity *gr = static_cast(e.getPtr()); - - Ogre::ParticleAffector *affector = partsys->addAffector("Gravity"); - affector->setParameter("force", Ogre::StringConverter::toString(gr->mForce)); - affector->setParameter("force_type", (gr->mType==0) ? "wind" : "point"); - affector->setParameter("direction", Ogre::StringConverter::toString(gr->mDirection)); - affector->setParameter("position", Ogre::StringConverter::toString(gr->mPosition)); - affector->setParameter("skelbase", skelBaseName); - affector->setParameter("bone", bone->getName()); - } - else if(e->recType == Nif::RC_NiParticleColorModifier) - { - const Nif::NiParticleColorModifier *cl = static_cast(e.getPtr()); - const Nif::NiColorData *clrdata = cl->data.getPtr(); - - Ogre::ParticleAffector *affector = partsys->addAffector("ColourInterpolator"); - size_t num_colors = std::min(6, clrdata->mKeyMap.mKeys.size()); - unsigned int i=0; - for (Nif::Vector4KeyMap::MapType::const_iterator it = clrdata->mKeyMap.mKeys.begin(); it != clrdata->mKeyMap.mKeys.end() && i < num_colors; ++it,++i) - { - Ogre::ColourValue color; - color.r = it->second.mValue[0]; - color.g = it->second.mValue[1]; - color.b = it->second.mValue[2]; - color.a = it->second.mValue[3]; - affector->setParameter("colour"+Ogre::StringConverter::toString(i), - Ogre::StringConverter::toString(color)); - affector->setParameter("time"+Ogre::StringConverter::toString(i), - Ogre::StringConverter::toString(it->first)); - } - } - else if(e->recType == Nif::RC_NiParticleRotation) - { - // TODO: Implement (Ogre::RotationAffector?) - } - else - warn("Unhandled particle modifier "+e->recName); - e = e->extra; - } - } - - static void createParticleSystem(const std::string &name, const std::string &group, - Ogre::SceneNode *sceneNode, ObjectScenePtr scene, - const Nif::Node *partnode, int flags, int partflags, int animflags) - { - const Nif::NiAutoNormalParticlesData *particledata = NULL; - if(partnode->recType == Nif::RC_NiAutoNormalParticles) - particledata = static_cast(partnode)->data.getPtr(); - else if(partnode->recType == Nif::RC_NiRotatingParticles) - particledata = static_cast(partnode)->data.getPtr(); - else - throw std::runtime_error("Unexpected particle node type"); - - std::string fullname = name+"@index="+Ogre::StringConverter::toString(partnode->recIndex); - if(partnode->name.length() > 0) - fullname += "@type="+partnode->name; - Misc::StringUtils::toLower(fullname); - - Ogre::ParticleSystem *partsys = sceneNode->getCreator()->createParticleSystem(); - - const Nif::NiTexturingProperty *texprop = NULL; - const Nif::NiMaterialProperty *matprop = NULL; - const Nif::NiAlphaProperty *alphaprop = NULL; - const Nif::NiVertexColorProperty *vertprop = NULL; - const Nif::NiZBufferProperty *zprop = NULL; - const Nif::NiSpecularProperty *specprop = NULL; - const Nif::NiWireframeProperty *wireprop = NULL; - const Nif::NiStencilProperty *stencilprop = NULL; - bool needTangents = false; - - partnode->getProperties(texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop, stencilprop); - partsys->setMaterialName(NIFMaterialLoader::getMaterial(particledata, fullname, group, - texprop, matprop, alphaprop, - vertprop, zprop, specprop, - wireprop, stencilprop, needTangents, - // MW doesn't light particles, but the MaterialProperty - // used still has lighting, so that must be ignored. - true)); - - partsys->setCullIndividually(false); - partsys->setParticleQuota(particledata->numParticles); - partsys->setKeepParticlesInLocalSpace(partflags & (Nif::NiNode::ParticleFlag_LocalSpace)); - - int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, partnode->recIndex); - Ogre::Bone *trgtbone = scene->mSkelBase->getSkeleton()->getBone(trgtid); - scene->mSkelBase->attachObjectToBone(trgtbone->getName(), partsys); - - Nif::ControllerPtr ctrl = partnode->controller; - while(!ctrl.empty()) - { - if((ctrl->recType == Nif::RC_NiParticleSystemController || ctrl->recType == Nif::RC_NiBSPArrayController) - && ctrl->flags & Nif::NiNode::ControllerFlag_Active) - { - const Nif::NiParticleSystemController *partctrl = static_cast(ctrl.getPtr()); - - float size = partctrl->size*2; - // HACK: don't allow zero-sized particles which can rarely cause an AABB assertion in Ogre to fail - size = std::max(size, 0.00001f); - partsys->setDefaultDimensions(size, size); - - if(!partctrl->emitter.empty()) - { - int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, partctrl->emitter->recIndex); - Ogre::Bone *trgtbone = scene->mSkelBase->getSkeleton()->getBone(trgtid); - // Set the emitter bone(s) as user data on the particle system - // so the emitters/affectors can access it easily. - std::vector bones; - if (partctrl->recType == Nif::RC_NiBSPArrayController) - { - std::vector nodes; - getAllNiNodes(partctrl->emitter.getPtr(), nodes); - if (nodes.empty()) - throw std::runtime_error("Emitter for NiBSPArrayController must be a NiNode"); - for (unsigned int i=0; imSkelBase->getSkeleton()->getBone( - NIFSkeletonLoader::lookupOgreBoneHandle(name, nodes[i]->recIndex))); - } - } - else - { - bones.push_back(trgtbone); - } - NiNodeHolder holder; - holder.mBones = bones; - partsys->getUserObjectBindings().setUserAny(Ogre::Any(holder)); - createParticleEmitterAffectors(partsys, partctrl, trgtbone, scene->mSkelBase->getName()); - } - - createParticleInitialState(partsys, particledata, partctrl); - - Ogre::ControllerValueRealPtr srcval((partflags&Nif::NiNode::ParticleFlag_AutoPlay) ? - Ogre::ControllerManager::getSingleton().getFrameTimeSource() : - Ogre::ControllerValueRealPtr()); - Ogre::ControllerValueRealPtr dstval(OGRE_NEW ParticleSystemController::Value(partsys, partctrl)); - - ParticleSystemController::Function* function = - OGRE_NEW ParticleSystemController::Function(partctrl, (partflags&Nif::NiNode::ParticleFlag_AutoPlay)); - scene->mMaxControllerLength = std::max(function->mStopTime, scene->mMaxControllerLength); - Ogre::ControllerFunctionRealPtr func(function); - - scene->mControllers.push_back(Ogre::Controller(srcval, dstval, func)); - - // Emitting state will be overwritten on frame update by the ParticleSystemController, - // but set up an initial value anyway so the user can fast-forward particle systems - // immediately after creation if desired. - partsys->setEmitting(partflags&Nif::NiNode::ParticleFlag_AutoPlay); - } - ctrl = ctrl->next; - } - - partsys->setVisible(!(flags&Nif::NiNode::Flag_Hidden)); - scene->mParticles.push_back(partsys); - - createMaterialControllers(partnode, partsys, animflags, scene); - } - - static void createParticleInitialState(Ogre::ParticleSystem* partsys, const Nif::NiAutoNormalParticlesData* particledata, - const Nif::NiParticleSystemController* partctrl) - { - partsys->_update(0.f); // seems to be required to allocate mFreeParticles. TODO: patch Ogre to handle this better - int i=0; - for (std::vector::const_iterator it = partctrl->particles.begin(); - iactiveCount && it != partctrl->particles.end(); ++it, ++i) - { - const Nif::NiParticleSystemController::Particle& particle = *it; - - Ogre::Particle* created = partsys->createParticle(); - if (!created) - break; - -#if OGRE_VERSION >= (1 << 16 | 10 << 8 | 0) - Ogre::Vector3& position = created->mPosition; - Ogre::Vector3& direction = created->mDirection; - Ogre::ColourValue& colour = created->mColour; - float& totalTimeToLive = created->mTotalTimeToLive; - float& timeToLive = created->mTimeToLive; -#else - Ogre::Vector3& position = created->position; - Ogre::Vector3& direction = created->direction; - Ogre::ColourValue& colour = created->colour; - float& totalTimeToLive = created->totalTimeToLive; - float& timeToLive = created->timeToLive; -#endif - - direction = particle.velocity; - position = particledata->vertices.at(particle.vertex); - - if (particle.vertex < int(particledata->colors.size())) - { - Ogre::Vector4 partcolour = particledata->colors.at(particle.vertex); - colour = Ogre::ColourValue(partcolour.x, partcolour.y, partcolour.z, partcolour.w); - } - else - colour = Ogre::ColourValue(1.f, 1.f, 1.f, 1.f); - float size = particledata->sizes.at(particle.vertex); - created->setDimensions(size, size); - totalTimeToLive = std::max(0.f, particle.lifespan); - timeToLive = std::max(0.f, particle.lifespan - particle.lifetime); - } - partsys->_update(0.f); // now apparently needs another update, otherwise it won't render in the first frame. TODO: patch Ogre to handle this better - } - - static void createNodeControllers(const Nif::NIFFilePtr& nif, const std::string &name, Nif::ControllerPtr ctrl, ObjectScenePtr scene, int animflags) - { - do { - if (ctrl->flags & Nif::NiNode::ControllerFlag_Active) - { - if(ctrl->recType == Nif::RC_NiVisController) - { - const Nif::NiVisController *vis = static_cast(ctrl.getPtr()); - - int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, ctrl->target->recIndex); - Ogre::Bone *trgtbone = scene->mSkelBase->getSkeleton()->getBone(trgtid); - Ogre::ControllerValueRealPtr srcval((animflags&Nif::NiNode::AnimFlag_AutoPlay) ? - Ogre::ControllerManager::getSingleton().getFrameTimeSource() : - Ogre::ControllerValueRealPtr()); - Ogre::ControllerValueRealPtr dstval(OGRE_NEW VisController::Value(trgtbone, vis->data.getPtr())); - - VisController::Function* function = OGRE_NEW VisController::Function(vis, (animflags&Nif::NiNode::AnimFlag_AutoPlay)); - scene->mMaxControllerLength = std::max(function->mStopTime, scene->mMaxControllerLength); - Ogre::ControllerFunctionRealPtr func(function); - - scene->mControllers.push_back(Ogre::Controller(srcval, dstval, func)); - } - else if(ctrl->recType == Nif::RC_NiKeyframeController) - { - const Nif::NiKeyframeController *key = static_cast(ctrl.getPtr()); - if(!key->data.empty()) - { - int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, ctrl->target->recIndex); - Ogre::Bone *trgtbone = scene->mSkelBase->getSkeleton()->getBone(trgtid); - // The keyframe controller will control this bone manually - trgtbone->setManuallyControlled(true); - Ogre::ControllerValueRealPtr srcval((animflags&Nif::NiNode::AnimFlag_AutoPlay) ? - Ogre::ControllerManager::getSingleton().getFrameTimeSource() : - Ogre::ControllerValueRealPtr()); - Ogre::ControllerValueRealPtr dstval(OGRE_NEW KeyframeController::Value(trgtbone, nif, key->data.getPtr())); - KeyframeController::Function* function = OGRE_NEW KeyframeController::Function(key, (animflags&Nif::NiNode::AnimFlag_AutoPlay)); - scene->mMaxControllerLength = std::max(function->mStopTime, scene->mMaxControllerLength); - Ogre::ControllerFunctionRealPtr func(function); - - scene->mControllers.push_back(Ogre::Controller(srcval, dstval, func)); - } - } - } - ctrl = ctrl->next; - } while(!ctrl.empty()); - } - - - static void extractTextKeys(const Nif::NiTextKeyExtraData *tk, TextKeyMap &textkeys) - { - for(size_t i = 0;i < tk->list.size();i++) - { - const std::string &str = tk->list[i].text; - std::string::size_type pos = 0; - while(pos < str.length()) - { - if(::isspace(str[pos])) - { - pos++; - continue; - } - - std::string::size_type nextpos = std::min(str.find('\r', pos), str.find('\n', pos)); - if(nextpos != std::string::npos) - { - do { - nextpos--; - } while(nextpos > pos && ::isspace(str[nextpos])); - nextpos++; - } - else if(::isspace(*str.rbegin())) - { - std::string::const_iterator last = str.end(); - do { - --last; - } while(last != str.begin() && ::isspace(*last)); - nextpos = std::distance(str.begin(), ++last); - } - std::string result = str.substr(pos, nextpos-pos); - textkeys.insert(std::make_pair(tk->list[i].time, Misc::StringUtils::toLower(result))); - - pos = nextpos; - } - } - } - - - static void createObjects(const Nif::NIFFilePtr& nif, const std::string &name, const std::string &group, - Ogre::SceneNode *sceneNode, const Nif::Node *node, - ObjectScenePtr scene, int flags, int animflags, int partflags, bool isRootCollisionNode=false) - { - // Do not create objects for the collision shape (includes all children) - if(node->recType == Nif::RC_RootCollisionNode) - isRootCollisionNode = true; - - if(node->recType == Nif::RC_NiBSAnimationNode) - animflags |= node->flags; - else if(node->recType == Nif::RC_NiBSParticleNode) - partflags |= node->flags; - else - flags |= node->flags; - - if (node->recType == Nif::RC_NiBillboardNode) - { - // TODO: figure out what the flags mean. - // NifSkope has names for them, but doesn't implement them. - // Change mBillboardNodes to map - int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, node->recIndex); - Ogre::Bone* bone = scene->mSkelBase->getSkeleton()->getBone(trgtid); - bone->setManuallyControlled(true); - scene->mBillboardNodes.push_back(bone); - } - - Nif::ExtraPtr e = node->extra; - while(!e.empty()) - { - if(e->recType == Nif::RC_NiTextKeyExtraData) - { - const Nif::NiTextKeyExtraData *tk = static_cast(e.getPtr()); - - extractTextKeys(tk, scene->mTextKeys); - } - else if(e->recType == Nif::RC_NiStringExtraData) - { - const Nif::NiStringExtraData *sd = static_cast(e.getPtr()); - // String markers may contain important information - // affecting the entire subtree of this obj - if(sd->string == "MRK" && !sShowMarkers) - { - // Marker objects. These meshes are only visible in the - // editor. - flags |= 0x80000000; - } - } - - e = e->extra; - } - - if(!node->controller.empty()) - createNodeControllers(nif, name, node->controller, scene, animflags); - - if (!isRootCollisionNode) - { - if(node->recType == Nif::RC_NiCamera) - { - /* Ignored */ - } - - if(node->recType == Nif::RC_NiTriShape && !(flags&0x80000000)) - { - createEntity(name, group, sceneNode->getCreator(), scene, node, flags, animflags); - } - - if((node->recType == Nif::RC_NiAutoNormalParticles || - node->recType == Nif::RC_NiRotatingParticles) && !(flags&0x40000000)) - { - createParticleSystem(name, group, sceneNode, scene, node, flags, partflags, animflags); - } - } - - const Nif::NiNode *ninode = dynamic_cast(node); - if(ninode) - { - const Nif::NodeList &children = ninode->children; - for(size_t i = 0;i < children.length();i++) - { - if(!children[i].empty()) - createObjects(nif, name, group, sceneNode, children[i].getPtr(), scene, flags, animflags, partflags, isRootCollisionNode); - } - } - } - - static void createSkelBase(const std::string &name, const std::string &group, - Ogre::SceneManager *sceneMgr, const Nif::Node *node, - ObjectScenePtr scene) - { - /* This creates an empty mesh to which a skeleton gets attached. This - * is to ensure we have an entity with a skeleton instance, even if all - * other entities are attached to bones and not skinned. */ - Ogre::MeshManager &meshMgr = Ogre::MeshManager::getSingleton(); - if(meshMgr.getByName(name).isNull()) - NIFMeshLoader::createMesh(name, name, group, ~(size_t)0); - - scene->mSkelBase = sceneMgr->createEntity(name); - scene->mEntities.push_back(scene->mSkelBase); - } - -public: - static void load(Ogre::SceneNode *sceneNode, ObjectScenePtr scene, const std::string &name, const std::string &group, int flags=0) - { - Nif::NIFFilePtr nif = Nif::Cache::getInstance().load(name); - if(nif->numRoots() < 1) - { - nif->warn("Found no root nodes in "+name+"."); - return; - } - - const Nif::Record *r = nif->getRoot(0); - assert(r != NULL); - - const Nif::Node *node = dynamic_cast(r); - if(node == NULL) - { - nif->warn("First root in "+name+" was not a node, but a "+ - r->recName+"."); - return; - } - - if(Ogre::SkeletonManager::getSingleton().resourceExists(name) || - !NIFSkeletonLoader::createSkeleton(name, group, node).isNull()) - { - // Create a base skeleton entity if this NIF needs one - createSkelBase(name, group, sceneNode->getCreator(), node, scene); - } - createObjects(nif, name, group, sceneNode, node, scene, flags, 0, 0); - } - - static void loadKf(Ogre::Skeleton *skel, const std::string &name, - TextKeyMap &textKeys, std::vector > &ctrls) - { - Nif::NIFFilePtr nif = Nif::Cache::getInstance().load(name); - if(nif->numRoots() < 1) - { - nif->warn("Found no root nodes in "+name+"."); - return; - } - - const Nif::Record *r = nif->getRoot(0); - assert(r != NULL); - - if(r->recType != Nif::RC_NiSequenceStreamHelper) - { - nif->warn("First root was not a NiSequenceStreamHelper, but a "+ - r->recName+"."); - return; - } - const Nif::NiSequenceStreamHelper *seq = static_cast(r); - - Nif::ExtraPtr extra = seq->extra; - if(extra.empty() || extra->recType != Nif::RC_NiTextKeyExtraData) - { - nif->warn("First extra data was not a NiTextKeyExtraData, but a "+ - (extra.empty() ? std::string("nil") : extra->recName)+"."); - return; - } - - extractTextKeys(static_cast(extra.getPtr()), textKeys); - - extra = extra->extra; - Nif::ControllerPtr ctrl = seq->controller; - for(;!extra.empty() && !ctrl.empty();(extra=extra->extra),(ctrl=ctrl->next)) - { - if(extra->recType != Nif::RC_NiStringExtraData || ctrl->recType != Nif::RC_NiKeyframeController) - { - nif->warn("Unexpected extra data "+extra->recName+" with controller "+ctrl->recName); - continue; - } - - if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active)) - continue; - - const Nif::NiStringExtraData *strdata = static_cast(extra.getPtr()); - const Nif::NiKeyframeController *key = static_cast(ctrl.getPtr()); - - if(key->data.empty()) - continue; - if(!skel->hasBone(strdata->string)) - continue; - - Ogre::Bone *trgtbone = skel->getBone(strdata->string); - Ogre::ControllerValueRealPtr srcval; - Ogre::ControllerValueRealPtr dstval(OGRE_NEW KeyframeController::Value(trgtbone, nif, key->data.getPtr())); - Ogre::ControllerFunctionRealPtr func(OGRE_NEW KeyframeController::Function(key, false)); - - ctrls.push_back(Ogre::Controller(srcval, dstval, func)); - } - } -}; - - -ObjectScenePtr Loader::createObjects(Ogre::SceneNode *parentNode, std::string name, const std::string &group) -{ - ObjectScenePtr scene = ObjectScenePtr (new ObjectScene(parentNode->getCreator())); - - Misc::StringUtils::toLower(name); - NIFObjectLoader::load(parentNode, scene, name, group); - - for(size_t i = 0;i < scene->mEntities.size();i++) - { - Ogre::Entity *entity = scene->mEntities[i]; - if(!entity->isAttached()) - parentNode->attachObject(entity); - } - - scene->_notifyAttached(); - - return scene; -} - -ObjectScenePtr Loader::createObjects(Ogre::Entity *parent, const std::string &bonename, - const std::string& bonefilter, - Ogre::SceneNode *parentNode, - std::string name, const std::string &group) -{ - ObjectScenePtr scene = ObjectScenePtr (new ObjectScene(parentNode->getCreator())); - - Misc::StringUtils::toLower(name); - NIFObjectLoader::load(parentNode, scene, name, group); - - bool isskinned = false; - for(size_t i = 0;i < scene->mEntities.size();i++) - { - Ogre::Entity *ent = scene->mEntities[i]; - if(scene->mSkelBase != ent && ent->hasSkeleton()) - { - isskinned = true; - break; - } - } - - Ogre::Vector3 scale(1.0f); - if(bonename.find("Left") != std::string::npos) - scale.x *= -1.0f; - - if(isskinned) - { - // accepts anything named "filter*" or "tri filter*" - std::string filter = "@shape=tri "+bonefilter; - std::string filter2 = "@shape="+bonefilter; - Misc::StringUtils::toLower(filter); - Misc::StringUtils::toLower(filter2); - for(size_t i = 0;i < scene->mEntities.size();i++) - { - Ogre::Entity *entity = scene->mEntities[i]; - if(entity->hasSkeleton()) - { - if(entity == scene->mSkelBase || - entity->getMesh()->getName().find(filter) != std::string::npos - || entity->getMesh()->getName().find(filter2) != std::string::npos) - parentNode->attachObject(entity); - } - else - { - if(entity->getMesh()->getName().find(filter) == std::string::npos - || entity->getMesh()->getName().find(filter2) == std::string::npos) - entity->detachFromParent(); - } - } - } - else - { - for(size_t i = 0;i < scene->mEntities.size();i++) - { - Ogre::Entity *entity = scene->mEntities[i]; - if(!entity->isAttached()) - { - Ogre::TagPoint *tag = parent->attachObjectToBone(bonename, entity); - tag->setScale(scale); - } - } - } - - scene->_notifyAttached(); - - return scene; -} - - -ObjectScenePtr Loader::createObjectBase(Ogre::SceneNode *parentNode, std::string name, const std::string &group) -{ - ObjectScenePtr scene = ObjectScenePtr (new ObjectScene(parentNode->getCreator())); - - Misc::StringUtils::toLower(name); - NIFObjectLoader::load(parentNode, scene, name, group, 0xC0000000); - - if(scene->mSkelBase) - parentNode->attachObject(scene->mSkelBase); - - return scene; -} - - -void Loader::createKfControllers(Ogre::Entity *skelBase, - const std::string &name, - TextKeyMap &textKeys, - std::vector > &ctrls) -{ - NIFObjectLoader::loadKf(skelBase->getSkeleton(), name, textKeys, ctrls); -} - -bool Loader::sShowMarkers = false; -bool NIFObjectLoader::sShowMarkers = false; - -void Loader::setShowMarkers(bool show) -{ - sShowMarkers = show; - NIFObjectLoader::setShowMarkers(show); -} - - -} // namespace NifOgre diff --git a/components/nifogre/ogrenifloader.hpp b/components/nifogre/ogrenifloader.hpp deleted file mode 100644 index c13532644..000000000 --- a/components/nifogre/ogrenifloader.hpp +++ /dev/null @@ -1,151 +0,0 @@ -/* - OpenMW - The completely unofficial reimplementation of Morrowind - Copyright (C) 2008-2010 Nicolay Korslund - Email: < korslund@gmail.com > - WWW: http://openmw.sourceforge.net/ - - This file (ogre_nif_loader.h) is part of the OpenMW package. - - OpenMW is distributed as free software: you can redistribute it - and/or modify it under the terms of the GNU General Public License - version 3, as published by the Free Software Foundation. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - version 3 along with this program. If not, see - http://www.gnu.org/licenses/ . - - */ - -#ifndef OPENMW_COMPONENTS_NIFOGRE_OGRENIFLOADER_HPP -#define OPENMW_COMPONENTS_NIFOGRE_OGRENIFLOADER_HPP - -#include -#include -#include - -#include -#include -#include - - -// FIXME: This namespace really doesn't do anything Nif-specific. Any supportable -// model format should go through this. -namespace NifOgre -{ - -/** - * @brief Clones materials as necessary to not make controllers affect other objects (that share the original material). - */ -class MaterialControllerManager -{ -public: - ~MaterialControllerManager(); - - /// @attention if \a movable is an Entity, it needs to have *one* SubEntity - Ogre::MaterialPtr getWritableMaterial (Ogre::MovableObject* movable); - -private: - std::map mClonedMaterials; -}; - -typedef std::multimap TextKeyMap; -static const char sTextKeyExtraDataID[] = "TextKeyExtraData"; -struct ObjectScene { - Ogre::Entity *mSkelBase; - std::vector mEntities; - std::vector mParticles; - std::vector mLights; - - // Nodes that should always face the camera when rendering - std::vector mBillboardNodes; - - Ogre::SceneManager* mSceneMgr; - - // The maximum length on any of the controllers. For animations with controllers, but no text keys, consider this the animation length. - float mMaxControllerLength; - - TextKeyMap mTextKeys; - - MaterialControllerManager mMaterialControllerMgr; - - std::vector > mControllers; - - ObjectScene(Ogre::SceneManager* sceneMgr) : mSkelBase(0), mMaxControllerLength(0), mSceneMgr(sceneMgr) - { } - - ~ObjectScene(); - - // Rotate nodes in mBillboardNodes so they face the given camera - void rotateBillboardNodes(Ogre::Camera* camera); - - void setVisibilityFlags (unsigned int flags); - - // This is called internally by the OgreNifLoader once all elements of the - // scene have been attached to their respective nodes. - void _notifyAttached(); -}; - -typedef Ogre::SharedPtr ObjectScenePtr; - - -class Loader -{ -public: - static ObjectScenePtr createObjects(Ogre::Entity *parent, const std::string &bonename, - const std::string& filter, - Ogre::SceneNode *parentNode, - std::string name, - const std::string &group="General"); - - static ObjectScenePtr createObjects(Ogre::SceneNode *parentNode, - std::string name, - const std::string &group="General"); - - static ObjectScenePtr createObjectBase(Ogre::SceneNode *parentNode, - std::string name, - const std::string &group="General"); - - /// Set whether or not nodes marked as "MRK" should be shown. - /// These should be hidden ingame, but visible in the editior. - /// Default: false. - static void setShowMarkers(bool show); - - static void createKfControllers(Ogre::Entity *skelBase, - const std::string &name, - TextKeyMap &textKeys, - std::vector > &ctrls); - -private: - static bool sShowMarkers; -}; - -// FIXME: Should be with other general Ogre extensions. -template -class NodeTargetValue : public Ogre::ControllerValue -{ -protected: - Ogre::Node *mNode; - -public: - NodeTargetValue(Ogre::Node *target) : mNode(target) - { } - - virtual Ogre::Quaternion getRotation(T value) const = 0; - virtual Ogre::Vector3 getTranslation(T value) const = 0; - virtual Ogre::Vector3 getScale(T value) const = 0; - - void setNode(Ogre::Node *target) - { mNode = target; } - Ogre::Node *getNode() const - { return mNode; } -}; -typedef Ogre::SharedPtr > NodeTargetValueRealPtr; - -} - -#endif diff --git a/components/nifogre/particles.cpp b/components/nifogre/particles.cpp deleted file mode 100644 index 4fec2d29e..000000000 --- a/components/nifogre/particles.cpp +++ /dev/null @@ -1,773 +0,0 @@ -#include "particles.hpp" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* FIXME: "Nif" isn't really an appropriate emitter name. */ -class NifEmitter : public Ogre::ParticleEmitter -{ -public: - std::vector mEmitterBones; - Ogre::Bone* mParticleBone; - - Ogre::ParticleSystem* getPartSys() { return mParent; } - - /** Command object for the emitter width (see Ogre::ParamCommand).*/ - class CmdWidth : public Ogre::ParamCommand - { - public: - Ogre::String doGet(const void *target) const - { - return Ogre::StringConverter::toString(static_cast(target)->getWidth()); - } - void doSet(void *target, const Ogre::String &val) - { - static_cast(target)->setWidth(Ogre::StringConverter::parseReal(val)); - } - }; - - /** Command object for the emitter height (see Ogre::ParamCommand).*/ - class CmdHeight : public Ogre::ParamCommand - { - public: - Ogre::String doGet(const void *target) const - { - return Ogre::StringConverter::toString(static_cast(target)->getHeight()); - } - void doSet(void *target, const Ogre::String &val) - { - static_cast(target)->setHeight(Ogre::StringConverter::parseReal(val)); - } - }; - - /** Command object for the emitter depth (see Ogre::ParamCommand).*/ - class CmdDepth : public Ogre::ParamCommand - { - public: - Ogre::String doGet(const void *target) const - { - return Ogre::StringConverter::toString(static_cast(target)->getDepth()); - } - void doSet(void *target, const Ogre::String &val) - { - static_cast(target)->setDepth(Ogre::StringConverter::parseReal(val)); - } - }; - - /** Command object for the emitter vertical_direction (see Ogre::ParamCommand).*/ - class CmdVerticalDir : public Ogre::ParamCommand - { - public: - Ogre::String doGet(const void *target) const - { - const NifEmitter *self = static_cast(target); - return Ogre::StringConverter::toString(self->getVerticalDirection().valueDegrees()); - } - void doSet(void *target, const Ogre::String &val) - { - NifEmitter *self = static_cast(target); - self->setVerticalDirection(Ogre::Degree(Ogre::StringConverter::parseReal(val))); - } - }; - - /** Command object for the emitter vertical_angle (see Ogre::ParamCommand).*/ - class CmdVerticalAngle : public Ogre::ParamCommand - { - public: - Ogre::String doGet(const void *target) const - { - const NifEmitter *self = static_cast(target); - return Ogre::StringConverter::toString(self->getVerticalAngle().valueDegrees()); - } - void doSet(void *target, const Ogre::String &val) - { - NifEmitter *self = static_cast(target); - self->setVerticalAngle(Ogre::Degree(Ogre::StringConverter::parseReal(val))); - } - }; - - /** Command object for the emitter horizontal_direction (see Ogre::ParamCommand).*/ - class CmdHorizontalDir : public Ogre::ParamCommand - { - public: - Ogre::String doGet(const void *target) const - { - const NifEmitter *self = static_cast(target); - return Ogre::StringConverter::toString(self->getHorizontalDirection().valueDegrees()); - } - void doSet(void *target, const Ogre::String &val) - { - NifEmitter *self = static_cast(target); - self->setHorizontalDirection(Ogre::Degree(Ogre::StringConverter::parseReal(val))); - } - }; - - /** Command object for the emitter horizontal_angle (see Ogre::ParamCommand).*/ - class CmdHorizontalAngle : public Ogre::ParamCommand - { - public: - Ogre::String doGet(const void *target) const - { - const NifEmitter *self = static_cast(target); - return Ogre::StringConverter::toString(self->getHorizontalAngle().valueDegrees()); - } - void doSet(void *target, const Ogre::String &val) - { - NifEmitter *self = static_cast(target); - self->setHorizontalAngle(Ogre::Degree(Ogre::StringConverter::parseReal(val))); - } - }; - - - NifEmitter(Ogre::ParticleSystem *psys) - : Ogre::ParticleEmitter(psys) - , mEmitterBones(Ogre::any_cast(psys->getUserObjectBindings().getUserAny()).mBones) - { - assert (!mEmitterBones.empty()); - Ogre::TagPoint* tag = static_cast(mParent->getParentNode()); - mParticleBone = static_cast(tag->getParent()); - initDefaults("Nif"); - } - - /** See Ogre::ParticleEmitter. */ - unsigned short _getEmissionCount(Ogre::Real timeElapsed) - { - // Use basic constant emission - return genConstantEmissionCount(timeElapsed); - } - - /** See Ogre::ParticleEmitter. */ - void _initParticle(Ogre::Particle *particle) - { - Ogre::Vector3 xOff, yOff, zOff; - - // Call superclass - ParticleEmitter::_initParticle(particle); - - xOff = Ogre::Math::SymmetricRandom() * mXRange; - yOff = Ogre::Math::SymmetricRandom() * mYRange; - zOff = Ogre::Math::SymmetricRandom() * mZRange; - -#if OGRE_VERSION >= (1 << 16 | 10 << 8 | 0) - Ogre::Vector3& position = particle->mPosition; - Ogre::Vector3& direction = particle->mDirection; - Ogre::ColourValue& colour = particle->mColour; - Ogre::Real& totalTimeToLive = particle->mTotalTimeToLive; - Ogre::Real& timeToLive = particle->mTimeToLive; -#else - Ogre::Vector3& position = particle->position; - Ogre::Vector3& direction = particle->direction; - Ogre::ColourValue& colour = particle->colour; - Ogre::Real& totalTimeToLive = particle->totalTimeToLive; - Ogre::Real& timeToLive = particle->timeToLive; -#endif - - Ogre::Node* emitterBone = mEmitterBones.at((int)(::rand()/(RAND_MAX+1.0)*mEmitterBones.size())); - - position = xOff + yOff + zOff + - mParticleBone->_getDerivedOrientation().Inverse() * (emitterBone->_getDerivedPosition() - - mParticleBone->_getDerivedPosition()); - - // Generate complex data by reference - genEmissionColour(colour); - - // NOTE: We do not use mDirection/mAngle for the initial direction. - Ogre::Radian hdir = mHorizontalDir + mHorizontalAngle*Ogre::Math::SymmetricRandom(); - Ogre::Radian vdir = mVerticalDir + mVerticalAngle*Ogre::Math::SymmetricRandom(); - direction = (mParticleBone->_getDerivedOrientation().Inverse() - * emitterBone->_getDerivedOrientation() * - Ogre::Quaternion(hdir, Ogre::Vector3::UNIT_Z) * - Ogre::Quaternion(vdir, Ogre::Vector3::UNIT_X)) * - Ogre::Vector3::UNIT_Z; - - genEmissionVelocity(direction); - - // Generate simpler data - timeToLive = totalTimeToLive = genEmissionTTL(); - } - - /** Overloaded to update the trans. matrix */ - void setDirection(const Ogre::Vector3 &dir) - { - ParticleEmitter::setDirection(dir); - genAreaAxes(); - } - - /** Sets the size of the area from which particles are emitted. - @param - size Vector describing the size of the area. The area extends - around the center point by half the x, y and z components of - this vector. The box is aligned such that it's local Z axis points - along it's direction (see setDirection) - */ - void setSize(const Ogre::Vector3 &size) - { - mSize = size; - genAreaAxes(); - } - - /** Sets the size of the area from which particles are emitted. - @param x,y,z - Individual axis lengths describing the size of the area. The area - extends around the center point by half the x, y and z components - of this vector. The box is aligned such that it's local Z axis - points along it's direction (see setDirection) - */ - void setSize(Ogre::Real x, Ogre::Real y, Ogre::Real z) - { - mSize.x = x; - mSize.y = y; - mSize.z = z; - genAreaAxes(); - } - - /** Sets the width (local x size) of the emitter. */ - void setWidth(Ogre::Real width) - { - mSize.x = width; - genAreaAxes(); - } - /** Gets the width (local x size) of the emitter. */ - Ogre::Real getWidth(void) const - { return mSize.x; } - /** Sets the height (local y size) of the emitter. */ - void setHeight(Ogre::Real height) - { - mSize.y = height; - genAreaAxes(); - } - /** Gets the height (local y size) of the emitter. */ - Ogre::Real getHeight(void) const - { return mSize.y; } - /** Sets the depth (local y size) of the emitter. */ - void setDepth(Ogre::Real depth) - { - mSize.z = depth; - genAreaAxes(); - } - /** Gets the depth (local y size) of the emitter. */ - Ogre::Real getDepth(void) const - { return mSize.z; } - - void setVerticalDirection(Ogre::Radian vdir) - { mVerticalDir = vdir; } - Ogre::Radian getVerticalDirection(void) const - { return mVerticalDir; } - - void setVerticalAngle(Ogre::Radian vangle) - { mVerticalAngle = vangle; } - Ogre::Radian getVerticalAngle(void) const - { return mVerticalAngle; } - - void setHorizontalDirection(Ogre::Radian hdir) - { mHorizontalDir = hdir; } - Ogre::Radian getHorizontalDirection(void) const - { return mHorizontalDir; } - - void setHorizontalAngle(Ogre::Radian hangle) - { mHorizontalAngle = hangle; } - Ogre::Radian getHorizontalAngle(void) const - { return mHorizontalAngle; } - - -protected: - /// Size of the area - Ogre::Vector3 mSize; - - Ogre::Radian mVerticalDir; - Ogre::Radian mVerticalAngle; - Ogre::Radian mHorizontalDir; - Ogre::Radian mHorizontalAngle; - - /// Local axes, not normalised, their magnitude reflects area size - Ogre::Vector3 mXRange, mYRange, mZRange; - - /// Internal method for generating the area axes - void genAreaAxes(void) - { - Ogre::Vector3 mLeft = mUp.crossProduct(mDirection); - mXRange = mLeft * (mSize.x * 0.5f); - mYRange = mUp * (mSize.y * 0.5f); - mZRange = mDirection * (mSize.z * 0.5f); - } - - /** Internal for initializing some defaults and parameters - @return True if custom parameters need initialising - */ - bool initDefaults(const Ogre::String &t) - { - // Defaults - mDirection = Ogre::Vector3::UNIT_Z; - mUp = Ogre::Vector3::UNIT_Y; - setSize(100.0f, 100.0f, 100.0f); - mType = t; - - // Set up parameters - if(createParamDictionary(mType + "Emitter")) - { - addBaseParameters(); - Ogre::ParamDictionary *dict = getParamDictionary(); - - // Custom params - dict->addParameter(Ogre::ParameterDef("width", - "Width of the shape in world coordinates.", - Ogre::PT_REAL), - &msWidthCmd); - dict->addParameter(Ogre::ParameterDef("height", - "Height of the shape in world coordinates.", - Ogre::PT_REAL), - &msHeightCmd); - dict->addParameter(Ogre::ParameterDef("depth", - "Depth of the shape in world coordinates.", - Ogre::PT_REAL), - &msDepthCmd); - - dict->addParameter(Ogre::ParameterDef("vertical_direction", - "Vertical direction of emitted particles (in degrees).", - Ogre::PT_REAL), - &msVerticalDirCmd); - dict->addParameter(Ogre::ParameterDef("vertical_angle", - "Vertical direction variance of emitted particles (in degrees).", - Ogre::PT_REAL), - &msVerticalAngleCmd); - dict->addParameter(Ogre::ParameterDef("horizontal_direction", - "Horizontal direction of emitted particles (in degrees).", - Ogre::PT_REAL), - &msHorizontalDirCmd); - dict->addParameter(Ogre::ParameterDef("horizontal_angle", - "Horizontal direction variance of emitted particles (in degrees).", - Ogre::PT_REAL), - &msHorizontalAngleCmd); - - return true; - } - return false; - } - - /// Command objects - static CmdWidth msWidthCmd; - static CmdHeight msHeightCmd; - static CmdDepth msDepthCmd; - static CmdVerticalDir msVerticalDirCmd; - static CmdVerticalAngle msVerticalAngleCmd; - static CmdHorizontalDir msHorizontalDirCmd; - static CmdHorizontalAngle msHorizontalAngleCmd; -}; -NifEmitter::CmdWidth NifEmitter::msWidthCmd; -NifEmitter::CmdHeight NifEmitter::msHeightCmd; -NifEmitter::CmdDepth NifEmitter::msDepthCmd; -NifEmitter::CmdVerticalDir NifEmitter::msVerticalDirCmd; -NifEmitter::CmdVerticalAngle NifEmitter::msVerticalAngleCmd; -NifEmitter::CmdHorizontalDir NifEmitter::msHorizontalDirCmd; -NifEmitter::CmdHorizontalAngle NifEmitter::msHorizontalAngleCmd; - -Ogre::ParticleEmitter* NifEmitterFactory::createEmitter(Ogre::ParticleSystem *psys) -{ - Ogre::ParticleEmitter *emitter = OGRE_NEW NifEmitter(psys); - mEmitters.push_back(emitter); - return emitter; -} - - -class GrowFadeAffector : public Ogre::ParticleAffector -{ -public: - /** Command object for grow_time (see Ogre::ParamCommand).*/ - class CmdGrowTime : public Ogre::ParamCommand - { - public: - Ogre::String doGet(const void *target) const - { - const GrowFadeAffector *self = static_cast(target); - return Ogre::StringConverter::toString(self->getGrowTime()); - } - void doSet(void *target, const Ogre::String &val) - { - GrowFadeAffector *self = static_cast(target); - self->setGrowTime(Ogre::StringConverter::parseReal(val)); - } - }; - - /** Command object for fade_time (see Ogre::ParamCommand).*/ - class CmdFadeTime : public Ogre::ParamCommand - { - public: - Ogre::String doGet(const void *target) const - { - const GrowFadeAffector *self = static_cast(target); - return Ogre::StringConverter::toString(self->getFadeTime()); - } - void doSet(void *target, const Ogre::String &val) - { - GrowFadeAffector *self = static_cast(target); - self->setFadeTime(Ogre::StringConverter::parseReal(val)); - } - }; - - /** Default constructor. */ - GrowFadeAffector(Ogre::ParticleSystem *psys) : ParticleAffector(psys) - { - mGrowTime = 0.0f; - mFadeTime = 0.0f; - - mType = "GrowFade"; - - // Init parameters - if(createParamDictionary("GrowFadeAffector")) - { - Ogre::ParamDictionary *dict = getParamDictionary(); - - Ogre::String grow_title("grow_time"); - Ogre::String fade_title("fade_time"); - Ogre::String grow_descr("Time from begin to reach full size."); - Ogre::String fade_descr("Time from end to shrink."); - - dict->addParameter(Ogre::ParameterDef(grow_title, grow_descr, Ogre::PT_REAL), &msGrowCmd); - dict->addParameter(Ogre::ParameterDef(fade_title, fade_descr, Ogre::PT_REAL), &msFadeCmd); - } - } - - /** See Ogre::ParticleAffector. */ - void _initParticle(Ogre::Particle *particle) - { -#if OGRE_VERSION >= (1 << 16 | 10 << 8 | 0) - const Ogre::Real life_time = particle->mTotalTimeToLive; - Ogre::Real particle_time = particle->mTimeToLive; -#else - const Ogre::Real life_time = particle->totalTimeToLive; - Ogre::Real particle_time = particle->timeToLive; -#endif - Ogre::Real width = mParent->getDefaultWidth(); - Ogre::Real height = mParent->getDefaultHeight(); - if(life_time-particle_time < mGrowTime) - { - Ogre::Real scale = (life_time-particle_time) / mGrowTime; - assert (scale >= 0); - // HACK: don't allow zero-sized particles which can rarely cause an AABB assertion in Ogre to fail - scale = std::max(scale, 0.00001f); - width *= scale; - height *= scale; - } - if(particle_time < mFadeTime) - { - Ogre::Real scale = particle_time / mFadeTime; - assert (scale >= 0); - // HACK: don't allow zero-sized particles which can rarely cause an AABB assertion in Ogre to fail - scale = std::max(scale, 0.00001f); - width *= scale; - height *= scale; - } - particle->setDimensions(width, height); - } - - /** See Ogre::ParticleAffector. */ - void _affectParticles(Ogre::ParticleSystem *psys, Ogre::Real timeElapsed) - { - Ogre::ParticleIterator pi = psys->_getIterator(); - while (!pi.end()) - { - Ogre::Particle *p = pi.getNext(); -#if OGRE_VERSION >= (1 << 16 | 10 << 8 | 0) - const Ogre::Real life_time = p->mTotalTimeToLive; - Ogre::Real particle_time = p->mTimeToLive; -#else - const Ogre::Real life_time = p->totalTimeToLive; - Ogre::Real particle_time = p->timeToLive; -#endif - Ogre::Real width = mParent->getDefaultWidth(); - Ogre::Real height = mParent->getDefaultHeight(); - if(life_time-particle_time < mGrowTime) - { - Ogre::Real scale = (life_time-particle_time) / mGrowTime; - assert (scale >= 0); - // HACK: don't allow zero-sized particles which can rarely cause an AABB assertion in Ogre to fail - scale = std::max(scale, 0.00001f); - width *= scale; - height *= scale; - } - if(particle_time < mFadeTime) - { - Ogre::Real scale = particle_time / mFadeTime; - assert (scale >= 0); - // HACK: don't allow zero-sized particles which can rarely cause an AABB assertion in Ogre to fail - scale = std::max(scale, 0.00001f); - width *= scale; - height *= scale; - } - p->setDimensions(width, height); - } - } - - void setGrowTime(Ogre::Real time) - { - mGrowTime = time; - } - Ogre::Real getGrowTime() const - { return mGrowTime; } - - void setFadeTime(Ogre::Real time) - { - mFadeTime = time; - } - Ogre::Real getFadeTime() const - { return mFadeTime; } - - static CmdGrowTime msGrowCmd; - static CmdFadeTime msFadeCmd; - -protected: - Ogre::Real mGrowTime; - Ogre::Real mFadeTime; -}; -GrowFadeAffector::CmdGrowTime GrowFadeAffector::msGrowCmd; -GrowFadeAffector::CmdFadeTime GrowFadeAffector::msFadeCmd; - -Ogre::ParticleAffector *GrowFadeAffectorFactory::createAffector(Ogre::ParticleSystem *psys) -{ - Ogre::ParticleAffector *p = new GrowFadeAffector(psys); - mAffectors.push_back(p); - return p; -} - - -class GravityAffector : public Ogre::ParticleAffector -{ - enum ForceType { - Type_Wind, - Type_Point - }; - -public: - Ogre::Bone* mEmitterBone; - Ogre::Bone* mParticleBone; - - Ogre::ParticleSystem* getPartSys() { return mParent; } - - /** Command object for force (see Ogre::ParamCommand).*/ - class CmdForce : public Ogre::ParamCommand - { - public: - Ogre::String doGet(const void *target) const - { - const GravityAffector *self = static_cast(target); - return Ogre::StringConverter::toString(self->getForce()); - } - void doSet(void *target, const Ogre::String &val) - { - GravityAffector *self = static_cast(target); - self->setForce(Ogre::StringConverter::parseReal(val)); - } - }; - - /** Command object for force_type (see Ogre::ParamCommand).*/ - class CmdForceType : public Ogre::ParamCommand - { - static ForceType getTypeFromString(const Ogre::String &type) - { - if(type == "wind") - return Type_Wind; - if(type == "point") - return Type_Point; - OGRE_EXCEPT(Ogre::Exception::ERR_INVALIDPARAMS, "Invalid force type string: "+type, - "CmdForceType::getTypeFromString"); - } - - static Ogre::String getStringFromType(ForceType type) - { - switch(type) - { - case Type_Wind: return "wind"; - case Type_Point: return "point"; - } - OGRE_EXCEPT(Ogre::Exception::ERR_INVALIDPARAMS, "Invalid force type enum: "+Ogre::StringConverter::toString(type), - "CmdForceType::getStringFromType"); - } - - public: - Ogre::String doGet(const void *target) const - { - const GravityAffector *self = static_cast(target); - return getStringFromType(self->getForceType()); - } - void doSet(void *target, const Ogre::String &val) - { - GravityAffector *self = static_cast(target); - self->setForceType(getTypeFromString(val)); - } - }; - - /** Command object for direction (see Ogre::ParamCommand).*/ - class CmdDirection : public Ogre::ParamCommand - { - public: - Ogre::String doGet(const void *target) const - { - const GravityAffector *self = static_cast(target); - return Ogre::StringConverter::toString(self->getDirection()); - } - void doSet(void *target, const Ogre::String &val) - { - GravityAffector *self = static_cast(target); - self->setDirection(Ogre::StringConverter::parseVector3(val)); - } - }; - - /** Command object for position (see Ogre::ParamCommand).*/ - class CmdPosition : public Ogre::ParamCommand - { - public: - Ogre::String doGet(const void *target) const - { - const GravityAffector *self = static_cast(target); - return Ogre::StringConverter::toString(self->getPosition()); - } - void doSet(void *target, const Ogre::String &val) - { - GravityAffector *self = static_cast(target); - self->setPosition(Ogre::StringConverter::parseVector3(val)); - } - }; - - - /** Default constructor. */ - GravityAffector(Ogre::ParticleSystem *psys) - : ParticleAffector(psys) - , mForce(0.0f) - , mForceType(Type_Wind) - , mPosition(0.0f) - , mDirection(0.0f) - { - std::vector bones = Ogre::any_cast(psys->getUserObjectBindings().getUserAny()).mBones; - assert (!bones.empty()); - mEmitterBone = bones[0]; - Ogre::TagPoint* tag = static_cast(mParent->getParentNode()); - mParticleBone = static_cast(tag->getParent()); - - mType = "Gravity"; - - // Init parameters - if(createParamDictionary("GravityAffector")) - { - Ogre::ParamDictionary *dict = getParamDictionary(); - - Ogre::String force_title("force"); - Ogre::String force_descr("Amount of force applied to particles."); - Ogre::String force_type_title("force_type"); - Ogre::String force_type_descr("Type of force applied to particles (point or wind)."); - Ogre::String direction_title("direction"); - Ogre::String direction_descr("Direction of wind forces."); - Ogre::String position_title("position"); - Ogre::String position_descr("Position of point forces."); - - dict->addParameter(Ogre::ParameterDef(force_title, force_descr, Ogre::PT_REAL), &msForceCmd); - dict->addParameter(Ogre::ParameterDef(force_type_title, force_type_descr, Ogre::PT_STRING), &msForceTypeCmd); - dict->addParameter(Ogre::ParameterDef(direction_title, direction_descr, Ogre::PT_VECTOR3), &msDirectionCmd); - dict->addParameter(Ogre::ParameterDef(position_title, position_descr, Ogre::PT_VECTOR3), &msPositionCmd); - } - } - - /** See Ogre::ParticleAffector. */ - void _affectParticles(Ogre::ParticleSystem *psys, Ogre::Real timeElapsed) - { - switch(mForceType) - { - case Type_Wind: - applyWindForce(psys, timeElapsed); - break; - case Type_Point: - applyPointForce(psys, timeElapsed); - break; - } - } - - void setForce(Ogre::Real force) - { mForce = force; } - Ogre::Real getForce() const - { return mForce; } - - void setForceType(ForceType type) - { mForceType = type; } - ForceType getForceType() const - { return mForceType; } - - void setDirection(const Ogre::Vector3 &dir) - { mDirection = dir; } - const Ogre::Vector3 &getDirection() const - { return mDirection; } - - void setPosition(const Ogre::Vector3 &pos) - { mPosition = pos; } - const Ogre::Vector3 &getPosition() const - { return mPosition; } - - static CmdForce msForceCmd; - static CmdForceType msForceTypeCmd; - static CmdDirection msDirectionCmd; - static CmdPosition msPositionCmd; - -protected: - void applyWindForce(Ogre::ParticleSystem *psys, Ogre::Real timeElapsed) - { - const Ogre::Vector3 vec = mDirection * mForce * timeElapsed; - Ogre::ParticleIterator pi = psys->_getIterator(); - while (!pi.end()) - { - Ogre::Particle *p = pi.getNext(); -#if OGRE_VERSION >= (1 << 16 | 10 << 8 | 0) - p->mDirection += vec; -#else - p->direction += vec; -#endif - } - } - - void applyPointForce(Ogre::ParticleSystem *psys, Ogre::Real timeElapsed) - { - const Ogre::Real force = mForce * timeElapsed; - Ogre::ParticleIterator pi = psys->_getIterator(); - while (!pi.end()) - { - Ogre::Particle *p = pi.getNext(); -#if OGRE_VERSION >= (1 << 16 | 10 << 8 | 0) - Ogre::Vector3 position = p->mPosition; -#else - Ogre::Vector3 position = p->position; -#endif - - Ogre::Vector3 vec = (mPosition - position).normalisedCopy() * force; -#if OGRE_VERSION >= (1 << 16 | 10 << 8 | 0) - p->mDirection += vec; -#else - p->direction += vec; -#endif - } - } - - - float mForce; - - ForceType mForceType; - - Ogre::Vector3 mPosition; - Ogre::Vector3 mDirection; -}; -GravityAffector::CmdForce GravityAffector::msForceCmd; -GravityAffector::CmdForceType GravityAffector::msForceTypeCmd; -GravityAffector::CmdDirection GravityAffector::msDirectionCmd; -GravityAffector::CmdPosition GravityAffector::msPositionCmd; - -Ogre::ParticleAffector *GravityAffectorFactory::createAffector(Ogre::ParticleSystem *psys) -{ - Ogre::ParticleAffector *p = new GravityAffector(psys); - mAffectors.push_back(p); - return p; -} diff --git a/components/nifogre/particles.hpp b/components/nifogre/particles.hpp deleted file mode 100644 index 6efc669fe..000000000 --- a/components/nifogre/particles.hpp +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef OENGINE_OGRE_PARTICLES_H -#define OENGINE_OGRE_PARTICLES_H - -#include -#include - -/** Factory class for NifEmitter. */ -class NifEmitterFactory : public Ogre::ParticleEmitterFactory -{ -public: - /** See ParticleEmitterFactory */ - Ogre::String getName() const - { return "Nif"; } - - /** See ParticleEmitterFactory */ - Ogre::ParticleEmitter* createEmitter(Ogre::ParticleSystem *psys); -}; - -/** Factory class for GrowFadeAffector. */ -class GrowFadeAffectorFactory : public Ogre::ParticleAffectorFactory -{ - /** See Ogre::ParticleAffectorFactory */ - Ogre::String getName() const - { return "GrowFade"; } - - /** See Ogre::ParticleAffectorFactory */ - Ogre::ParticleAffector *createAffector(Ogre::ParticleSystem *psys); -}; - -/** Factory class for GravityAffector. */ -class GravityAffectorFactory : public Ogre::ParticleAffectorFactory -{ - /** See Ogre::ParticleAffectorFactory */ - Ogre::String getName() const - { return "Gravity"; } - - /** See Ogre::ParticleAffectorFactory */ - Ogre::ParticleAffector *createAffector(Ogre::ParticleSystem *psys); -}; - -struct NiNodeHolder -{ - std::vector mBones; - - // Ogre::Any needs this for some reason - friend std::ostream& operator<<(std::ostream& o, const NiNodeHolder& r) - { return o; } -}; - -#endif /* OENGINE_OGRE_PARTICLES_H */ diff --git a/components/nifogre/skeleton.cpp b/components/nifogre/skeleton.cpp deleted file mode 100644 index db6a753c5..000000000 --- a/components/nifogre/skeleton.cpp +++ /dev/null @@ -1,179 +0,0 @@ -#include "skeleton.hpp" - -#include -#include -#include -#include - -#include -#include -#include - -namespace NifOgre -{ - -void NIFSkeletonLoader::buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *parent) -{ - Ogre::Bone *bone; - if (node->name.empty()) - { - // HACK: use " " instead of empty name, otherwise Ogre will replace it with an auto-generated - // name in SkeletonInstance::cloneBoneAndChildren. - static const char* emptyname = " "; - if (!skel->hasBone(emptyname)) - bone = skel->createBone(emptyname); - else - bone = skel->createBone(); - } - else - { - if(!skel->hasBone(node->name)) - bone = skel->createBone(node->name); - else - bone = skel->createBone(); - } - - if(parent) parent->addChild(bone); - mNifToOgreHandleMap[node->recIndex] = bone->getHandle(); - - bone->setOrientation(node->trafo.rotation); - bone->setPosition(node->trafo.pos); - bone->setScale(Ogre::Vector3(node->trafo.scale)); - bone->setBindingPose(); - - if(!(node->recType == Nif::RC_NiNode || /* Nothing special; children traversed below */ - node->recType == Nif::RC_RootCollisionNode || /* handled in nifbullet (hopefully) */ - node->recType == Nif::RC_NiTriShape || /* Handled in the mesh loader */ - node->recType == Nif::RC_NiBSAnimationNode || /* Handled in the object loader */ - node->recType == Nif::RC_NiBillboardNode || /* Handled in the object loader */ - node->recType == Nif::RC_NiBSParticleNode || - node->recType == Nif::RC_NiCamera || - node->recType == Nif::RC_NiAutoNormalParticles || - node->recType == Nif::RC_NiRotatingParticles - )) - warn("Unhandled "+node->recName+" "+node->name+" in "+skel->getName()); - - Nif::ControllerPtr ctrl = node->controller; - while(!ctrl.empty()) - { - if(!(ctrl->recType == Nif::RC_NiParticleSystemController || - ctrl->recType == Nif::RC_NiBSPArrayController || - ctrl->recType == Nif::RC_NiVisController || - ctrl->recType == Nif::RC_NiUVController || - ctrl->recType == Nif::RC_NiKeyframeController || - ctrl->recType == Nif::RC_NiGeomMorpherController - )) - warn("Unhandled "+ctrl->recName+" from node "+node->name+" in "+skel->getName()); - ctrl = ctrl->next; - } - - const Nif::NiNode *ninode = dynamic_cast(node); - if(ninode) - { - const Nif::NodeList &children = ninode->children; - for(size_t i = 0;i < children.length();i++) - { - if(!children[i].empty()) - buildBones(skel, children[i].getPtr(), bone); - } - } -} - -void NIFSkeletonLoader::loadResource(Ogre::Resource *resource) -{ - Ogre::Skeleton *skel = dynamic_cast(resource); - OgreAssert(skel, "Attempting to load a skeleton into a non-skeleton resource!"); - - Nif::NIFFilePtr nif(Nif::Cache::getInstance().load(skel->getName())); - const Nif::Node *node = static_cast(nif->getRoot(0)); - - try { - buildBones(skel, node); - } - catch(std::exception &e) { - std::cerr<< "Exception while loading "<getName() <boneTrafo) - return true; - - if(!node->controller.empty()) - { - Nif::ControllerPtr ctrl = node->controller; - do { - if(ctrl->recType == Nif::RC_NiKeyframeController && ctrl->flags & Nif::NiNode::ControllerFlag_Active) - return true; - } while(!(ctrl=ctrl->next).empty()); - } - - if (node->name == "AttachLight" || node->name == "ArrowBone") - return true; - - if(node->recType == Nif::RC_NiNode || node->recType == Nif::RC_RootCollisionNode) - { - const Nif::NiNode *ninode = static_cast(node); - const Nif::NodeList &children = ninode->children; - for(size_t i = 0;i < children.length();i++) - { - if(!children[i].empty()) - { - if(needSkeleton(children[i].getPtr())) - return true; - } - } - return false; - } - if(node->recType == Nif::RC_NiTriShape) - return false; - - return true; -} - -Ogre::SkeletonPtr NIFSkeletonLoader::createSkeleton(const std::string &name, const std::string &group, const Nif::Node *node) -{ - bool forceskel = false; - std::string::size_type extpos = name.rfind('.'); - if(extpos != std::string::npos && name.compare(extpos, name.size()-extpos, ".nif") == 0) - { - Ogre::ResourceGroupManager &resMgr = Ogre::ResourceGroupManager::getSingleton(); - forceskel = resMgr.resourceExistsInAnyGroup(name.substr(0, extpos)+".kf"); - } - - if(forceskel || needSkeleton(node)) - { - Ogre::SkeletonManager &skelMgr = Ogre::SkeletonManager::getSingleton(); - return skelMgr.create(name, group, true, &sLoaders[name]); - } - - return Ogre::SkeletonPtr(); -} - -// Looks up an Ogre Bone handle ID from a NIF's record index. Should only be -// used when the bone name is insufficient as this is a relatively slow lookup -int NIFSkeletonLoader::lookupOgreBoneHandle(const std::string &nifname, int idx) -{ - LoaderMap::const_iterator loader = sLoaders.find(nifname); - if(loader != sLoaders.end()) - { - std::map::const_iterator entry = loader->second.mNifToOgreHandleMap.find(idx); - if(entry != loader->second.mNifToOgreHandleMap.end()) - return entry->second; - } - throw std::runtime_error("Invalid NIF record lookup ("+nifname+", index "+Ogre::StringConverter::toString(idx)+")"); -} - -NIFSkeletonLoader::LoaderMap NIFSkeletonLoader::sLoaders; - -} diff --git a/components/nifogre/skeleton.hpp b/components/nifogre/skeleton.hpp deleted file mode 100644 index 9ec3a0c82..000000000 --- a/components/nifogre/skeleton.hpp +++ /dev/null @@ -1,62 +0,0 @@ -#ifndef COMPONENTS_NIFOGRE_SKELETON_HPP -#define COMPONENTS_NIFOGRE_SKELETON_HPP - -#include -#include -#include - -#include - -#include "ogrenifloader.hpp" - -namespace Nif -{ - class NiTextKeyExtraData; - class Node; - class NiKeyframeController; -} - -namespace NifOgre -{ - -/** Manual resource loader for NIF skeletons. This is the main class - responsible for translating the internal NIF skeleton structure into - something Ogre can use (includes animations and node TextKeyData). - */ -class NIFSkeletonLoader : public Ogre::ManualResourceLoader -{ - static void warn(const std::string &msg) - { - std::cerr << "NIFSkeletonLoader: Warn: " << msg << std::endl; - } - - static void fail(const std::string &msg) - { - std::cerr << "NIFSkeletonLoader: Fail: "<< msg << std::endl; - abort(); - } - - void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *parent=NULL); - - static bool needSkeleton(const Nif::Node *node); - - // Lookup to retrieve an Ogre bone handle for a given Nif record index - std::map mNifToOgreHandleMap; - - typedef std::map LoaderMap; - static LoaderMap sLoaders; - -public: - void loadResource(Ogre::Resource *resource); - - static Ogre::SkeletonPtr createSkeleton(const std::string &name, const std::string &group, const Nif::Node *node); - - // Looks up an Ogre Bone handle ID from a NIF's record index. Should only - // be used when the bone name is insufficient as this is a relatively slow - // lookup - static int lookupOgreBoneHandle(const std::string &nifname, int idx); -}; - -} - -#endif diff --git a/components/ogreinit/ogreinit.cpp b/components/ogreinit/ogreinit.cpp index 574b67f19..e8ca2e8bd 100644 --- a/components/ogreinit/ogreinit.cpp +++ b/components/ogreinit/ogreinit.cpp @@ -15,8 +15,6 @@ #include #endif -#include - #include #include @@ -118,8 +116,6 @@ namespace OgreInit loadPlugins(); #endif - loadParticleFactories(); - return mRoot; } @@ -128,16 +124,6 @@ namespace OgreInit delete mRoot; delete Ogre::LogManager::getSingletonPtr(); - std::vector::iterator ei; - for(ei = mEmitterFactories.begin();ei != mEmitterFactories.end();++ei) - OGRE_DELETE (*ei); - mEmitterFactories.clear(); - - std::vector::iterator ai; - for(ai = mAffectorFactories.begin();ai != mAffectorFactories.end();++ai) - OGRE_DELETE (*ai); - mAffectorFactories.clear(); - #ifdef ENABLE_PLUGIN_GL delete mGLPlugin; mGLPlugin = NULL; @@ -221,22 +207,4 @@ namespace OgreInit if (!Files::loadOgrePlugin(pluginDir, "Plugin_ParticleFX", *mRoot)) throw std::runtime_error("Required Plugin_ParticleFX for Ogre not found!"); } - - void OgreInit::loadParticleFactories() - { - Ogre::ParticleEmitterFactory *emitter; - emitter = OGRE_NEW NifEmitterFactory(); - Ogre::ParticleSystemManager::getSingleton().addEmitterFactory(emitter); - mEmitterFactories.push_back(emitter); - - Ogre::ParticleAffectorFactory *affector; - affector = OGRE_NEW GrowFadeAffectorFactory(); - Ogre::ParticleSystemManager::getSingleton().addAffectorFactory(affector); - mAffectorFactories.push_back(affector); - - affector = OGRE_NEW GravityAffectorFactory(); - Ogre::ParticleSystemManager::getSingleton().addAffectorFactory(affector); - mAffectorFactories.push_back(affector); - } - } diff --git a/components/ogreinit/ogreinit.hpp b/components/ogreinit/ogreinit.hpp index 9613421f7..d1743950f 100644 --- a/components/ogreinit/ogreinit.hpp +++ b/components/ogreinit/ogreinit.hpp @@ -48,13 +48,10 @@ namespace OgreInit ~OgreInit(); private: - std::vector mEmitterFactories; - std::vector mAffectorFactories; Ogre::Root* mRoot; void loadStaticPlugins(); void loadPlugins(); - void loadParticleFactories(); #ifdef ENABLE_PLUGIN_CgProgramManager Ogre::CgPlugin* mCgPlugin; From baa152328a8ad8efe3a2e3499a7c412e827c2642 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 24 Mar 2015 01:32:36 +0100 Subject: [PATCH 0808/3725] Crash fix --- components/nifosg/nifloader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 6a2523120..2ed91d467 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -414,7 +414,7 @@ namespace NifOsg if (nifNode == NULL) nif->fail("First root was not a node, but a " + r->recName); - osg::Node* created = handleNode(nifNode, false, std::map(), 0, 0, false, textKeys); + osg::ref_ptr created = handleNode(nifNode, false, std::map(), 0, 0, false, textKeys); return created; } From 9141a8d8014a236eec3c2e557bf71731ef05deb8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 24 Mar 2015 22:52:20 +0100 Subject: [PATCH 0809/3725] Fully implement NiStencilProperty (Feature #1057) --- apps/nifosgtest/test.cpp | 3 ++ components/nif/property.hpp | 2 +- components/nifosg/nifloader.cpp | 53 +++++++++++++++++++++++++++------ 3 files changed, 48 insertions(+), 10 deletions(-) diff --git a/apps/nifosgtest/test.cpp b/apps/nifosgtest/test.cpp index 0da95d13d..253b5f99d 100644 --- a/apps/nifosgtest/test.cpp +++ b/apps/nifosgtest/test.cpp @@ -102,6 +102,9 @@ int main(int argc, char** argv) Nif::NIFFilePtr nif(new Nif::NIFFile(resourceMgr.get(argv[1]), std::string(argv[1]))); + // For NiStencilProperty + osg::DisplaySettings::instance()->setMinimumNumStencilBits(8); + osgViewer::Viewer viewer; osg::ref_ptr root(new osg::Group()); diff --git a/components/nif/property.hpp b/components/nif/property.hpp index 2633b16c5..96156c6d8 100644 --- a/components/nif/property.hpp +++ b/components/nif/property.hpp @@ -221,7 +221,7 @@ struct S_StencilProperty 4 TEST_GREATER 5 TEST_NOT_EQUAL 6 TEST_GREATER_EQUAL - 7 TEST_ALWAYS + 7 TEST_NEVER (though nifskope comment says TEST_ALWAYS, but ingame it is TEST_NEVER) */ int compareFunc; unsigned stencilRef; diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 2ed91d467..45619b21b 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -116,6 +116,40 @@ namespace } } + osg::Stencil::Function getStencilFunction(int func) + { + switch (func) + { + case 0: return osg::Stencil::NEVER; + case 1: return osg::Stencil::LESS; + case 2: return osg::Stencil::EQUAL; + case 3: return osg::Stencil::LEQUAL; + case 4: return osg::Stencil::GREATER; + case 5: return osg::Stencil::NOTEQUAL; + case 6: return osg::Stencil::GEQUAL; + case 7: return osg::Stencil::NEVER; // NifSkope says this is GL_ALWAYS, but in MW it's GL_NEVER + default: + std::cerr << "Unexpected stencil function: " << func << std::endl; + return osg::Stencil::NEVER; + } + } + + osg::Stencil::Operation getStencilOperation(int op) + { + switch (op) + { + case 0: return osg::Stencil::KEEP; + case 1: return osg::Stencil::ZERO; + case 2: return osg::Stencil::REPLACE; + case 3: return osg::Stencil::INCR; + case 4: return osg::Stencil::DECR; + case 5: return osg::Stencil::INVERT; + default: + std::cerr << "Unexpected stencil operation: " << op << std::endl; + return osg::Stencil::KEEP; + } + } + // Collect all properties affecting the given node that should be applied to an osg::Material. void collectMaterialProperties(const Nif::Node* nifNode, std::vector& out) { @@ -1095,16 +1129,17 @@ namespace NifOsg stateset->setMode(GL_CULL_FACE, stencilprop->data.drawMode == 3 ? osg::StateAttribute::OFF : osg::StateAttribute::ON); - // TODO: - // Stencil settings not enabled yet, not sure if the original engine is actually using them, - // since they might conflict with Morrowind's stencil shadows. - /* - osg::Stencil* stencil = new osg::Stencil; - stencil->setFunction(func, stencilprop->data.stencilRef, stencilprop->data.stencilMask); + if (stencilprop->data.enabled != 0) + { + osg::Stencil* stencil = new osg::Stencil; + stencil->setFunction(getStencilFunction(stencilprop->data.compareFunc), stencilprop->data.stencilRef, stencilprop->data.stencilMask); + stencil->setStencilFailOperation(getStencilOperation(stencilprop->data.failAction)); + stencil->setStencilPassAndDepthFailOperation(getStencilOperation(stencilprop->data.zFailAction)); + stencil->setStencilPassAndDepthPassOperation(getStencilOperation(stencilprop->data.zPassAction)); - stateset->setMode(GL_STENCIL_TEST, stencilprop->data.enabled != 0 ? osg::StateAttribute::ON - : osg::StateAttribute::OFF); - */ + stateset->setAttributeAndModes(stencil, osg::StateAttribute::ON); + } + break; } case Nif::RC_NiWireframeProperty: { From 9ee99a751c21d84c8bee7211ed25bd62a8a5ca3a Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 24 Mar 2015 23:40:37 +0100 Subject: [PATCH 0810/3725] Stop warning about NiDitherProperty, ignore NiShadeProperty (unused) --- components/nifosg/nifloader.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 45619b21b..199fdb984 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -1294,10 +1294,10 @@ namespace NifOsg } break; } + // unused by mw + case Nif::RC_NiShadeProperty: case Nif::RC_NiDitherProperty: { - stateset->setMode(GL_DITHER, property->flags != 0 ? osg::StateAttribute::ON - : osg::StateAttribute::OFF); break; } default: From b072e803ce10b6e777cfffddcacdc453235e7513 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 24 Mar 2015 23:54:48 +0100 Subject: [PATCH 0811/3725] Use correct ambient/diffuse default values when no NiMaterialProperty exists --- components/nifosg/nifloader.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 199fdb984..ea59b9bd2 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -1314,7 +1314,11 @@ namespace NifOsg int specFlags = 0; // Specular is disabled by default, even if there's a specular color in the NiMaterialProperty osg::Material* mat = new osg::Material; mat->setColorMode(hasVertexColors ? osg::Material::AMBIENT_AND_DIFFUSE : osg::Material::OFF); - // TODO: check if the OpenGL default material values are actually the default NIF material values, for when there's no NiMaterialProperty + + // NIF material defaults don't match OpenGL defaults + mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(1,1,1,1)); + mat->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(1,1,1,1)); + for (std::vector::const_reverse_iterator it = properties.rbegin(); it != properties.rend(); ++it) { const Nif::Property* property = *it; From 20866b44f7a3074e90b0b40e18cc5e3372ee71dc Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 25 Mar 2015 00:54:45 +0100 Subject: [PATCH 0812/3725] FlipController fix, DetailTexture & DarkTexture tested --- components/nifosg/controller.cpp | 5 ++++- components/nifosg/controller.hpp | 1 - components/nifosg/nifloader.cpp | 2 -- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index ef3157773..0e1f15f0f 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -433,9 +433,12 @@ void FlipController::operator() (osg::Node* node, osg::NodeVisitor* nv) { osg::StateSet* stateset = node->getStateSet(); int curTexture = int(getInputValue(nv) / mDelta) % mTextures.size(); - osg::Texture2D* tex = dynamic_cast(stateset->getAttribute(osg::StateAttribute::TEXTURE)); + osg::Texture2D* tex = dynamic_cast(stateset->getTextureAttribute(mTexSlot, osg::StateAttribute::TEXTURE)); if (tex) tex->setImage(mTextures[curTexture].get()); + else + std::cout << "FlipController: can't find target slot" << std::endl; + } traverse(node, nv); } diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index 17bf3ae75..c6ef74d2a 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -259,7 +259,6 @@ namespace NifOsg virtual void operator() (osg::Node* node, osg::NodeVisitor* nv); }; - // untested class FlipController : public osg::NodeCallback, public Controller { private: diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index ea59b9bd2..d05758f2e 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -1260,14 +1260,12 @@ namespace NifOsg } else if (i == Nif::NiTexturingProperty::DarkTexture) { - // untested osg::TexEnv* texEnv = new osg::TexEnv; texEnv->setMode(osg::TexEnv::MODULATE); stateset->setTextureAttributeAndModes(i, texEnv, osg::StateAttribute::ON); } else if (i == Nif::NiTexturingProperty::DetailTexture) { - // untested osg::TexEnvCombine* texEnv = new osg::TexEnvCombine; texEnv->setScale_RGB(2.f); texEnv->setCombine_Alpha(GL_MODULATE); From c179977f206b35fef854dbfdf8d4b8cd2a4df9d6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 25 Mar 2015 01:58:41 +0100 Subject: [PATCH 0813/3725] Fix quaternion rotation order --- components/nifosg/controller.cpp | 2 +- components/nifosg/particle.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index 0e1f15f0f..a31263d8b 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -135,7 +135,7 @@ osg::Quat KeyframeController::getXYZRotation(float time) const osg::Quat xr(xrot, osg::Vec3f(1,0,0)); osg::Quat yr(yrot, osg::Vec3f(0,1,0)); osg::Quat zr(zrot, osg::Vec3f(0,0,1)); - return (zr*yr*xr); + return (xr*yr*zr); } osg::Vec3f KeyframeController::getTranslation(float time) const diff --git a/components/nifosg/particle.cpp b/components/nifosg/particle.cpp index 25970c862..899ce7537 100644 --- a/components/nifosg/particle.cpp +++ b/components/nifosg/particle.cpp @@ -77,7 +77,7 @@ void ParticleShooter::shoot(osgParticle::Particle *particle) const float hdir = mHorizontalDir + mHorizontalAngle * (2.f * (std::rand() / static_cast(RAND_MAX)) - 1.f); float vdir = mVerticalDir + mVerticalAngle * (2.f * (std::rand() / static_cast(RAND_MAX)) - 1.f); float vdir2 = mVerticalDir + mVerticalAngle * (2.f * (std::rand() / static_cast(RAND_MAX)) - 1.f); - osg::Vec3f dir = osg::Quat(hdir, osg::Vec3f(0,0,1)) * osg::Quat(vdir, osg::Vec3f(0,1,0)) * osg::Quat(vdir2, osg::Vec3f(1,0,0)) + osg::Vec3f dir = (osg::Quat(vdir2, osg::Vec3f(1,0,0)) * osg::Quat(vdir, osg::Vec3f(0,1,0)) * osg::Quat(hdir, osg::Vec3f(0,0,1))) * osg::Vec3f(0,0,1); float vel = mMinSpeed + (mMaxSpeed - mMinSpeed) * std::rand() / static_cast(RAND_MAX); From 6d9deaa38643586b18dd35aa6ebd5096bef2c120 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 25 Mar 2015 04:57:01 +0100 Subject: [PATCH 0814/3725] Implement planar collider for particles (Fixes #2149) --- components/nif/controlled.cpp | 10 ++++++-- components/nif/controlled.hpp | 5 ++++ components/nif/controller.cpp | 7 +++--- components/nif/controller.hpp | 3 ++- components/nifosg/nifloader.cpp | 41 +++++++++++++++++++------------- components/nifosg/particle.cpp | 42 +++++++++++++++++++++++++++++++++ components/nifosg/particle.hpp | 19 +++++++++++++++ 7 files changed, 104 insertions(+), 23 deletions(-) diff --git a/components/nif/controlled.cpp b/components/nif/controlled.cpp index 526b2eca3..9db0c4a6f 100644 --- a/components/nif/controlled.cpp +++ b/components/nif/controlled.cpp @@ -65,8 +65,14 @@ namespace Nif { Controlled::read(nif); - // (I think) 4 floats + 4 vectors - nif->skip(4*16); + mBounceFactor = nif->getFloat(); + /*unknown*/nif->getFloat(); + + for (int i=0;i<10;++i) + /*unknown*/nif->getFloat(); + + mPlaneNormal = nif->getVector3(); + mPlaneDistance = nif->getFloat(); } void NiParticleRotation::read(NIFStream *nif) diff --git a/components/nif/controlled.hpp b/components/nif/controlled.hpp index ac75c3508..36d90b03d 100644 --- a/components/nif/controlled.hpp +++ b/components/nif/controlled.hpp @@ -103,6 +103,11 @@ class NiPlanarCollider : public Controlled { public: void read(NIFStream *nif); + + float mBounceFactor; + + osg::Vec3f mPlaneNormal; + float mPlaneDistance; }; class NiParticleRotation : public Controlled diff --git a/components/nif/controller.cpp b/components/nif/controller.cpp index 376a1fe12..f39132543 100644 --- a/components/nif/controller.cpp +++ b/components/nif/controller.cpp @@ -76,8 +76,8 @@ namespace Nif } nif->getUInt(); /* -1? */ - extra.read(nif); - nif->getUInt(); /* -1? */ + affectors.read(nif); + colliders.read(nif); nif->getChar(); } @@ -85,7 +85,8 @@ namespace Nif { Controller::post(nif); emitter.post(nif); - extra.post(nif); + affectors.post(nif); + colliders.post(nif); } void NiMaterialColorController::read(NIFStream *nif) diff --git a/components/nif/controller.hpp b/components/nif/controller.hpp index 73344e77b..0861dfa6b 100644 --- a/components/nif/controller.hpp +++ b/components/nif/controller.hpp @@ -72,7 +72,8 @@ public: int activeCount; std::vector particles; - ExtraPtr extra; + ExtraPtr affectors; + ExtraPtr colliders; void read(NIFStream *nif); void post(NIFFile *nif); diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index d05758f2e..a2fd8e39a 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -719,39 +719,44 @@ namespace NifOsg } } - void handleParticleAffectors(Nif::ExtraPtr e, osg::Group *attachTo, osgParticle::ParticleSystem* partsys, osgParticle::ParticleProcessor::ReferenceFrame rf) + void handleParticlePrograms(Nif::ExtraPtr affectors, Nif::ExtraPtr colliders, osg::Group *attachTo, osgParticle::ParticleSystem* partsys, osgParticle::ParticleProcessor::ReferenceFrame rf) { osgParticle::ModularProgram* program = new osgParticle::ModularProgram; attachTo->addChild(program); program->setParticleSystem(partsys); program->setReferenceFrame(rf); - for (; !e.empty(); e = e->extra) + for (; !affectors.empty(); affectors = affectors->extra) { - if (e->recType == Nif::RC_NiParticleGrowFade) + if (affectors->recType == Nif::RC_NiParticleGrowFade) { - const Nif::NiParticleGrowFade *gf = static_cast(e.getPtr()); - GrowFadeAffector* affector = new GrowFadeAffector(gf->growTime, gf->fadeTime); - program->addOperator(affector); + const Nif::NiParticleGrowFade *gf = static_cast(affectors.getPtr()); + program->addOperator(new GrowFadeAffector(gf->growTime, gf->fadeTime)); } - else if (e->recType == Nif::RC_NiGravity) + else if (affectors->recType == Nif::RC_NiGravity) { - const Nif::NiGravity* gr = static_cast(e.getPtr()); - GravityAffector* affector = new GravityAffector(gr); - program->addOperator(affector); + const Nif::NiGravity* gr = static_cast(affectors.getPtr()); + program->addOperator(new GravityAffector(gr)); } - else if (e->recType == Nif::RC_NiParticleColorModifier) + else if (affectors->recType == Nif::RC_NiParticleColorModifier) { - const Nif::NiParticleColorModifier *cl = static_cast(e.getPtr()); + const Nif::NiParticleColorModifier *cl = static_cast(affectors.getPtr()); const Nif::NiColorData *clrdata = cl->data.getPtr(); - ParticleColorAffector* affector = new ParticleColorAffector(clrdata); - program->addOperator(affector); + program->addOperator(new ParticleColorAffector(clrdata)); } - else if (e->recType == Nif::RC_NiParticleRotation) + else if (affectors->recType == Nif::RC_NiParticleRotation) { // TODO: Implement? } else - std::cerr << "Unhandled particle modifier " << e->recName << std::endl; + std::cerr << "Unhandled particle modifier " << affectors->recName << std::endl; + } + for (; !colliders.empty(); colliders = colliders->extra) + { + if (colliders->recType == Nif::RC_NiPlanarCollider) + { + const Nif::NiPlanarCollider* planarcollider = static_cast(colliders.getPtr()); + program->addOperator(new PlanarCollider(planarcollider)); + } } } @@ -888,7 +893,9 @@ namespace NifOsg emitter->setUpdateCallback(callback); // affectors must be attached *after* the emitter in the scene graph for correct update order - handleParticleAffectors(partctrl->extra, emitterNode, partsys.get(), rf); + // attach to same node as the ParticleSystem, we need osgParticle Operators to get the correct + // localToWorldMatrix for transforming to particle space + handleParticlePrograms(partctrl->affectors, partctrl->colliders, parentNode, partsys.get(), rf); osg::ref_ptr geode (new osg::Geode); geode->addDrawable(partsys); diff --git a/components/nifosg/particle.cpp b/components/nifosg/particle.cpp index 899ce7537..0afbf5e95 100644 --- a/components/nifosg/particle.cpp +++ b/components/nifosg/particle.cpp @@ -303,4 +303,46 @@ void FindRecIndexVisitor::apply(osg::Node &searchNode) traverse(searchNode); } +PlanarCollider::PlanarCollider(const Nif::NiPlanarCollider *collider) + : mBounceFactor(collider->mBounceFactor) + , mPlane(-collider->mPlaneNormal, collider->mPlaneDistance) +{ +} + +PlanarCollider::PlanarCollider() + : mBounceFactor(0.f) +{ +} + +PlanarCollider::PlanarCollider(const PlanarCollider ©, const osg::CopyOp ©op) + : osgParticle::Operator(copy, copyop) + , mBounceFactor(copy.mBounceFactor) + , mPlane(copy.mPlane) + , mPlaneInParticleSpace(copy.mPlaneInParticleSpace) +{ +} + +void PlanarCollider::beginOperate(osgParticle::Program *program) +{ + mPlaneInParticleSpace = mPlane; + if (program->getReferenceFrame() == osgParticle::ParticleProcessor::ABSOLUTE_RF) + mPlaneInParticleSpace.transform(program->getLocalToWorldMatrix()); +} + +void PlanarCollider::operate(osgParticle::Particle *particle, double dt) +{ + float dotproduct = particle->getVelocity() * mPlaneInParticleSpace.getNormal(); + + if (dotproduct > 0) + { + osg::BoundingSphere bs(particle->getPosition(), 0.f); + if (mPlaneInParticleSpace.intersect(bs) == 1) + { + osg::Vec3 reflectedVelocity = particle->getVelocity() - mPlaneInParticleSpace.getNormal() * (2 * dotproduct); + reflectedVelocity *= mBounceFactor; + particle->setVelocity(reflectedVelocity); + } + } +} + } diff --git a/components/nifosg/particle.hpp b/components/nifosg/particle.hpp index 01e06f471..99db3c83a 100644 --- a/components/nifosg/particle.hpp +++ b/components/nifosg/particle.hpp @@ -17,6 +17,7 @@ namespace Nif { class NiGravity; + class NiPlanarCollider; } namespace NifOsg @@ -92,6 +93,24 @@ namespace NifOsg float mLifetimeRandom; }; + class PlanarCollider : public osgParticle::Operator + { + public: + PlanarCollider(const Nif::NiPlanarCollider* collider); + PlanarCollider(); + PlanarCollider(const PlanarCollider& copy, const osg::CopyOp& copyop); + + META_Object(NifOsg, PlanarCollider) + + virtual void beginOperate(osgParticle::Program* program); + virtual void operate(osgParticle::Particle* particle, double dt); + + private: + float mBounceFactor; + osg::Plane mPlane; + osg::Plane mPlaneInParticleSpace; + }; + class GrowFadeAffector : public osgParticle::Operator { public: From 60ede8dede80328492e072fb5814690ef06961d6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 25 Mar 2015 05:14:07 +0100 Subject: [PATCH 0815/3725] Stop warning about NiFogProperty (unused in MW) --- components/nifosg/nifloader.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index a2fd8e39a..c6927cfad 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -1302,6 +1302,7 @@ namespace NifOsg // unused by mw case Nif::RC_NiShadeProperty: case Nif::RC_NiDitherProperty: + case Nif::RC_NiFogProperty: { break; } From b7867d6f0acf2a167581d8478816823f7a85371b Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 25 Mar 2015 05:29:00 +0100 Subject: [PATCH 0816/3725] Stop warning about unused nif properties --- components/nif/node.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/components/nif/node.cpp b/components/nif/node.cpp index fb68da548..d99d157ae 100644 --- a/components/nif/node.cpp +++ b/components/nif/node.cpp @@ -38,7 +38,10 @@ void Node::getProperties(const Nif::NiTexturingProperty *&texprop, wireprop = static_cast(pr); else if (pr->recType == Nif::RC_NiStencilProperty) stencilprop = static_cast(pr); - else + // the following are unused by the MW engine + else if (pr->recType != Nif::RC_NiFogProperty + && pr->recType != Nif::RC_NiDitherProperty + && pr->recType != Nif::RC_NiShadeProperty) std::cerr<< "Unhandled property type: "<recName < Date: Wed, 25 Mar 2015 11:56:14 +0100 Subject: [PATCH 0817/3725] added search class and search box widget --- apps/opencs/CMakeLists.txt | 4 +- apps/opencs/model/tools/search.cpp | 213 +++++++++++++++++++++++ apps/opencs/model/tools/search.hpp | 82 +++++++++ apps/opencs/model/world/columnbase.cpp | 72 +++++++- apps/opencs/model/world/columnbase.hpp | 6 + apps/opencs/view/tools/searchbox.cpp | 145 +++++++++++++++ apps/opencs/view/tools/searchbox.hpp | 57 ++++++ apps/opencs/view/tools/searchsubview.cpp | 29 ++- apps/opencs/view/tools/searchsubview.hpp | 7 + 9 files changed, 611 insertions(+), 4 deletions(-) create mode 100644 apps/opencs/model/tools/search.cpp create mode 100644 apps/opencs/model/tools/search.hpp create mode 100644 apps/opencs/view/tools/searchbox.cpp create mode 100644 apps/opencs/view/tools/searchbox.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index e3b44ac91..eb83b14d5 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -40,7 +40,7 @@ opencs_units (model/tools opencs_units_noqt (model/tools mandatoryid skillcheck classcheck factioncheck racecheck soundcheck regioncheck birthsigncheck spellcheck referencecheck referenceablecheck scriptcheck bodypartcheck - startscriptcheck + startscriptcheck search ) @@ -91,7 +91,7 @@ opencs_hdrs_noqt (view/render opencs_units (view/tools - reportsubview reporttable searchsubview + reportsubview reporttable searchsubview searchbox ) opencs_units_noqt (view/tools diff --git a/apps/opencs/model/tools/search.cpp b/apps/opencs/model/tools/search.cpp new file mode 100644 index 000000000..1b7be6fbf --- /dev/null +++ b/apps/opencs/model/tools/search.cpp @@ -0,0 +1,213 @@ + +#include "search.hpp" + +#include +#include + +#include "../../model/doc/messages.hpp" + +#include "../../model/world/idtablebase.hpp" +#include "../../model/world/columnbase.hpp" +#include "../../model/world/universalid.hpp" + +void CSMTools::Search::searchTextCell (const CSMWorld::IdTableBase *model, + const QModelIndex& index, const CSMWorld::UniversalId& id, bool multiple, + CSMDoc::Messages& messages) const +{ + // using QString here for easier handling of case folding. + + QString search = QString::fromUtf8 (mText.c_str()); + QString text = model->data (index).toString(); + + int pos = 0; + + while ((pos = text.indexOf (search, pos, Qt::CaseInsensitive))!=-1) + { + std::ostringstream message; + message << text.mid (pos).toUtf8().data(); + + std::ostringstream hint; + message << "r: " << index.column() << " " << pos << " " << search.length(); + + messages.add (id, message.str(), hint.str()); + + if (!multiple) + break; + + pos += search.length(); + } +} + +void CSMTools::Search::searchRegExCell (const CSMWorld::IdTableBase *model, + const QModelIndex& index, const CSMWorld::UniversalId& id, bool multiple, + CSMDoc::Messages& messages) const +{ + QString text = model->data (index).toString(); + + int pos = 0; + + while ((pos = mRegExp.indexIn (text, pos))!=-1) + { + std::ostringstream message; + message << text.mid (pos).toUtf8().data(); + + int length = mRegExp.matchedLength(); + + std::ostringstream hint; + message << "r: " << index.column() << " " << pos << " " << length; + + messages.add (id, message.str(), hint.str()); + + if (!multiple) + break; + + pos += length; + } +} + +void CSMTools::Search::searchRecordStateCell (const CSMWorld::IdTableBase *model, + const QModelIndex& index, const CSMWorld::UniversalId& id, CSMDoc::Messages& messages) const +{ + int data = model->data (index).toInt(); + + if (data==mValue) + { + std::vector states = + CSMWorld::Columns::getEnums (CSMWorld::Columns::ColumnId_Modification); + + std::ostringstream message; + message << id.getId() << " " << states.at (data); + + std::ostringstream hint; + message << "r: " << index.column(); + + messages.add (id, message.str(), hint.str()); + } +} + +CSMTools::Search::Search() : mType (Type_None) {} + +CSMTools::Search::Search (Type type, const std::string& value) +: mType (type), mText (value) +{ + if (type!=Type_Text && type!=Type_Reference) + throw std::logic_error ("Invalid search parameter (string)"); +} + +CSMTools::Search::Search (Type type, const QRegExp& value) +: mType (type), mRegExp (value) +{ + if (type!=Type_TextRegEx && type!=Type_ReferenceRegEx) + throw std::logic_error ("Invalid search parameter (RegExp)"); +} + +CSMTools::Search::Search (Type type, int value) +: mType (type), mValue (value) +{ + if (type!=Type_RecordState) + throw std::logic_error ("invalid search parameter (int)"); +} + +void CSMTools::Search::configure (const CSMWorld::IdTableBase *model) +{ + mColumns.clear(); + + int columns = model->columnCount(); + + for (int i=0; i ( + model->headerData ( + i, Qt::Horizontal, static_cast (CSMWorld::ColumnBase::Role_Display)).toInt()); + + bool consider = false; + bool multiple = false; + + switch (mType) + { + case Type_Text: + case Type_TextRegEx: + + if (CSMWorld::ColumnBase::isText (display) || + CSMWorld::ColumnBase::isScript (display)) + { + consider = true; + multiple = true; + } + + break; + + case Type_Reference: + case Type_ReferenceRegEx: + + if (CSMWorld::ColumnBase::isId (display)) + { + consider = true; + } + else if (CSMWorld::ColumnBase::isScript (display)) + { + consider = true; + multiple = true; + } + + break; + + case Type_RecordState: + + if (display==CSMWorld::ColumnBase::Display_RecordState) + consider = true; + + break; + + case Type_None: + + break; + } + + if (consider) + mColumns.insert (std::make_pair (i, multiple)); + } + + mIdColumn = model->findColumnIndex (CSMWorld::Columns::ColumnId_Id); + mTypeColumn = model->findColumnIndex (CSMWorld::Columns::ColumnId_RecordType); +} + +void CSMTools::Search::searchRow (const CSMWorld::IdTableBase *model, int row, + CSMDoc::Messages& messages) const +{ + for (std::map::const_iterator iter (mColumns.begin()); iter!=mColumns.end(); + ++iter) + { + QModelIndex index = model->index (row, iter->first); + + CSMWorld::UniversalId::Type type = static_cast ( + model->data (model->index (row, mTypeColumn)).toInt()); + + CSMWorld::UniversalId id ( + type, model->data (model->index (row, mIdColumn)).toString().toUtf8().data()); + + switch (mType) + { + case Type_Text: + case Type_Reference: + + searchTextCell (model, index, id, iter->second, messages); + break; + + case Type_TextRegEx: + case Type_ReferenceRegEx: + + searchRegExCell (model, index, id, iter->second, messages); + break; + + case Type_RecordState: + + searchRecordStateCell (model, index, id, messages); + break; + + case Type_None: + + break; + } + } +} diff --git a/apps/opencs/model/tools/search.hpp b/apps/opencs/model/tools/search.hpp new file mode 100644 index 000000000..3683f9c9b --- /dev/null +++ b/apps/opencs/model/tools/search.hpp @@ -0,0 +1,82 @@ +#ifndef CSM_TOOLS_SEARCH_H +#define CSM_TOOLS_SEARCH_H + +#include +#include + +#include +#include + +class QModelIndex; + +namespace CSMDoc +{ + class Messages; +} + +namespace CSMWorld +{ + class IdTableBase; + class UniversalId; +} + +namespace CSMTools +{ + class Search + { + public: + + enum Type + { + Type_Text = 0, + Type_TextRegEx = 1, + Type_Reference = 2, + Type_ReferenceRegEx = 3, + Type_RecordState = 4, + Type_None + }; + + private: + + Type mType; + std::string mText; + QRegExp mRegExp; + int mValue; + std::map mColumns; // column, multiple finds per cell + int mIdColumn; + int mTypeColumn; + + void searchTextCell (const CSMWorld::IdTableBase *model, const QModelIndex& index, + const CSMWorld::UniversalId& id, bool multiple, CSMDoc::Messages& messages) const; + + void searchRegExCell (const CSMWorld::IdTableBase *model, const QModelIndex& index, + const CSMWorld::UniversalId& id, bool multiple, CSMDoc::Messages& messages) const; + + void searchRecordStateCell (const CSMWorld::IdTableBase *model, + const QModelIndex& index, const CSMWorld::UniversalId& id, + CSMDoc::Messages& messages) const; + + public: + + Search(); + + Search (Type type, const std::string& value); + + Search (Type type, const QRegExp& value); + + Search (Type type, int value); + + // Configure search for the specified model. + void configure (const CSMWorld::IdTableBase *model); + + // Search row in \a model and store results in \a messages. + // + // \attention *this needs to be configured for \a model. + void searchRow (const CSMWorld::IdTableBase *model, int row, + CSMDoc::Messages& messages) const; + }; +} + +Q_DECLARE_METATYPE (CSMTools::Search) + +#endif diff --git a/apps/opencs/model/world/columnbase.cpp b/apps/opencs/model/world/columnbase.cpp index 665ab9354..f4f2310b6 100644 --- a/apps/opencs/model/world/columnbase.cpp +++ b/apps/opencs/model/world/columnbase.cpp @@ -19,7 +19,77 @@ std::string CSMWorld::ColumnBase::getTitle() const return Columns::getName (static_cast (mColumnId)); } -int CSMWorld::ColumnBase::getId() const +int CSMWorld::ColumnBase::getId() const { return mColumnId; } + +bool CSMWorld::ColumnBase::isId (Display display) +{ + static const Display ids[] = + { + Display_Skill, + Display_Class, + Display_Faction, + Display_Race, + Display_Sound, + Display_Region, + Display_Birthsign, + Display_Spell, + Display_Cell, + Display_Referenceable, + Display_Activator, + Display_Potion, + Display_Apparatus, + Display_Armor, + Display_Book, + Display_Clothing, + Display_Container, + Display_Creature, + Display_Door, + Display_Ingredient, + Display_CreatureLevelledList, + Display_ItemLevelledList, + Display_Light, + Display_Lockpick, + Display_Miscellaneous, + Display_Npc, + Display_Probe, + Display_Repair, + Display_Static, + Display_Weapon, + Display_Reference, + Display_Filter, + Display_Topic, + Display_Journal, + Display_TopicInfo, + Display_JournalInfo, + Display_Scene, + Display_GlobalVariable, + + Display_Mesh, + Display_Icon, + Display_Music, + Display_SoundRes, + Display_Texture, + Display_Video, + + Display_None + }; + + for (int i=0; ids[i]!=Display_None; ++i) + if (ids[i]==display) + return true; + + return false; +} + +bool CSMWorld::ColumnBase::isText (Display display) +{ + return display==Display_String || display==Display_LongString; +} + +bool CSMWorld::ColumnBase::isScript (Display display) +{ + return display==Display_Script || display==Display_ScriptLines; +} diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index db9b8b3c6..c49785154 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -122,6 +122,12 @@ namespace CSMWorld virtual std::string getTitle() const; virtual int getId() const; + + static bool isId (Display display); + + static bool isText (Display display); + + static bool isScript (Display display); }; template diff --git a/apps/opencs/view/tools/searchbox.cpp b/apps/opencs/view/tools/searchbox.cpp new file mode 100644 index 000000000..1b11d8a4d --- /dev/null +++ b/apps/opencs/view/tools/searchbox.cpp @@ -0,0 +1,145 @@ + +#include "searchbox.hpp" + +#include + +#include +#include +#include + +#include "../../model/world/columns.hpp" + +#include "../../model/tools/search.hpp" + +void CSVTools::SearchBox::updateSearchButton() +{ + if (!mSearchEnabled) + mSearch.setEnabled (false); + else + { + switch (mMode.currentIndex()) + { + case 0: + case 1: + case 2: + case 3: + + mSearch.setEnabled (!mText.text().isEmpty()); + break; + + case 4: + + mSearch.setEnabled (true); + break; + } + } +} + +CSVTools::SearchBox::SearchBox (QWidget *parent) +: QWidget (parent), mSearch ("Search"), mSearchEnabled (false) +{ + std::vector states = + CSMWorld::Columns::getEnums (CSMWorld::Columns::ColumnId_Modification); + states.resize (states.size()-1); // ignore erased state + + for (std::vector::const_iterator iter (states.begin()); iter!=states.end(); + ++iter) + mRecordState.addItem (QString::fromUtf8 (iter->c_str())); + + mLayout = new QGridLayout (this); + + mMode.addItem ("Text"); + mMode.addItem ("Text (RegEx)"); + mMode.addItem ("Reference"); + mMode.addItem ("Reference (RegEx)"); + mMode.addItem ("Record State"); + + mLayout->addWidget (&mMode, 0, 0); + + mLayout->addWidget (&mSearch, 0, 3); + + mInput.insertWidget (0, &mText); + mInput.insertWidget (1, &mRecordState); + + mLayout->addWidget (&mInput, 0, 1); + + mLayout->setColumnMinimumWidth (2, 50); + mLayout->setColumnStretch (1, 1); + + mLayout->setContentsMargins (0, 0, 0, 0); + + connect (&mMode, SIGNAL (activated (int)), this, SLOT (modeSelected (int))); + + connect (&mText, SIGNAL (textChanged (const QString&)), + this, SLOT (textChanged (const QString&))); + + connect (&mSearch, SIGNAL (clicked (bool)), this, SLOT (startSearch (bool))); + + modeSelected (0); + + updateSearchButton(); +} + +void CSVTools::SearchBox::setSearchMode (bool enabled) +{ + mSearchEnabled = enabled; + updateSearchButton(); +} + +CSMTools::Search CSVTools::SearchBox::getSearch() const +{ + CSMTools::Search::Type type = static_cast (mMode.currentIndex()); + + switch (type) + { + case CSMTools::Search::Type_Text: + case CSMTools::Search::Type_Reference: + + return CSMTools::Search (type, std::string (mText.text().toUtf8().data())); + + case CSMTools::Search::Type_TextRegEx: + case CSMTools::Search::Type_ReferenceRegEx: + + return CSMTools::Search (type, QRegExp (mText.text().toUtf8().data(), Qt::CaseInsensitive)); + + case CSMTools::Search::Type_RecordState: + + return CSMTools::Search (type, mRecordState.currentIndex()); + + case CSMTools::Search::Type_None: + + break; + } + + throw std::logic_error ("invalid search mode index"); +} + +void CSVTools::SearchBox::modeSelected (int index) +{ + switch (index) + { + case CSMTools::Search::Type_Text: + case CSMTools::Search::Type_TextRegEx: + case CSMTools::Search::Type_Reference: + case CSMTools::Search::Type_ReferenceRegEx: + + mInput.setCurrentIndex (0); + break; + + case CSMTools::Search::Type_RecordState: + mInput.setCurrentIndex (1); + break; + } + + updateSearchButton(); +} + +void CSVTools::SearchBox::textChanged (const QString& text) +{ + updateSearchButton(); +} + +void CSVTools::SearchBox::startSearch (bool checked) +{ + emit startSearch (getSearch()); +} diff --git a/apps/opencs/view/tools/searchbox.hpp b/apps/opencs/view/tools/searchbox.hpp new file mode 100644 index 000000000..dc975cac9 --- /dev/null +++ b/apps/opencs/view/tools/searchbox.hpp @@ -0,0 +1,57 @@ +#ifndef CSV_TOOLS_SEARCHBOX_H +#define CSV_TOOLS_SEARCHBOX_H + +#include +#include +#include +#include +#include + +class QGridLayout; + +namespace CSMTools +{ + class Search; +} + +namespace CSVTools +{ + class SearchBox : public QWidget + { + Q_OBJECT + + QStackedWidget mInput; + QLineEdit mText; + QComboBox mRecordState; + QPushButton mSearch; + QGridLayout *mLayout; + QComboBox mMode; + bool mSearchEnabled; + + private: + + void updateSearchButton(); + + public: + + SearchBox (QWidget *parent = 0); + + void setSearchMode (bool enabled); + + CSMTools::Search getSearch() const; + + private slots: + + void modeSelected (int index); + + void textChanged (const QString& text); + + void startSearch (bool checked); + + signals: + + void startSearch (const CSMTools::Search& search); + }; +} + +#endif diff --git a/apps/opencs/view/tools/searchsubview.cpp b/apps/opencs/view/tools/searchsubview.cpp index 7173a6634..bc818df07 100644 --- a/apps/opencs/view/tools/searchsubview.cpp +++ b/apps/opencs/view/tools/searchsubview.cpp @@ -1,15 +1,37 @@ #include "searchsubview.hpp" +#include + +#include "../../model/doc/document.hpp" + #include "reporttable.hpp" +#include "searchbox.hpp" CSVTools::SearchSubView::SearchSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) : CSVDoc::SubView (id) { - setWidget (mTable = new ReportTable (document, id, this)); + QVBoxLayout *layout = new QVBoxLayout; + + layout->setContentsMargins (QMargins (0, 0, 0, 0)); + + layout->addWidget (&mSearchBox); + + layout->addWidget (mTable = new ReportTable (document, id), 2); + + QWidget *widget = new QWidget; + + widget->setLayout (layout); + setWidget (widget); + + stateChanged (document.getState(), &document); + connect (mTable, SIGNAL (editRequest (const CSMWorld::UniversalId&, const std::string&)), SIGNAL (focusId (const CSMWorld::UniversalId&, const std::string&))); + + connect (&document, SIGNAL (stateChanged (int, CSMDoc::Document *)), + this, SLOT (stateChanged (int, CSMDoc::Document *))); } void CSVTools::SearchSubView::setEditLock (bool locked) @@ -21,3 +43,8 @@ void CSVTools::SearchSubView::updateUserSetting (const QString &name, const QStr { mTable->updateUserSetting (name, list); } + +void CSVTools::SearchSubView::stateChanged (int state, CSMDoc::Document *document) +{ + mSearchBox.setSearchMode (!(state & CSMDoc::State_Searching)); +} diff --git a/apps/opencs/view/tools/searchsubview.hpp b/apps/opencs/view/tools/searchsubview.hpp index abedd5e6d..b389805bb 100644 --- a/apps/opencs/view/tools/searchsubview.hpp +++ b/apps/opencs/view/tools/searchsubview.hpp @@ -3,6 +3,8 @@ #include "../doc/subview.hpp" +#include "searchbox.hpp" + class QTableView; class QModelIndex; @@ -20,6 +22,7 @@ namespace CSVTools Q_OBJECT ReportTable *mTable; + SearchBox mSearchBox; public: @@ -28,6 +31,10 @@ namespace CSVTools virtual void setEditLock (bool locked); virtual void updateUserSetting (const QString &, const QStringList &); + + private slots: + + void stateChanged (int state, CSMDoc::Document *document); }; } From 46cbec9a4a406904a80905fe2209c92b15ecb70c Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 25 Mar 2015 15:39:41 +0100 Subject: [PATCH 0818/3725] Add skinning auto-detection in nifosg loader --- apps/nifosgtest/test.cpp | 2 +- apps/opencs/view/render/object.cpp | 2 +- components/nif/niffile.cpp | 11 +++++++++++ components/nif/niffile.hpp | 8 ++++++++ components/nif/node.hpp | 2 ++ components/nifosg/nifloader.cpp | 5 ++++- components/nifosg/nifloader.hpp | 6 ++---- 7 files changed, 29 insertions(+), 7 deletions(-) diff --git a/apps/nifosgtest/test.cpp b/apps/nifosgtest/test.cpp index 253b5f99d..0f2e43a56 100644 --- a/apps/nifosgtest/test.cpp +++ b/apps/nifosgtest/test.cpp @@ -117,7 +117,7 @@ int main(int argc, char** argv) osg::Group* newNode = new osg::Group; NifOsg::Loader loader; loader.resourceManager = &resourceMgr; - newNode->addChild(loader.loadAsSkeleton(nif)); + newNode->addChild(loader.load(nif)); osg::PositionAttitudeTransform* trans = new osg::PositionAttitudeTransform; root->addChild(trans); diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index f48fcc440..bd44ba577 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -60,7 +60,7 @@ void CSVRender::Object::update() Nif::NIFFilePtr file(new Nif::NIFFile(mVFS->get(path), path)); - mBaseNode->addChild(loader.loadAsSkeleton(file)); + mBaseNode->addChild(loader.load(file)); //mObject->setVisibilityFlags (Element_Reference); diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index f7d864198..a73985cfb 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -12,6 +12,7 @@ NIFFile::NIFFile(Files::IStreamPtr stream, const std::string &name) : ver(0) , filename(name) , mStream(stream) + , mUseSkinning(false) { parse(); } @@ -208,4 +209,14 @@ void NIFFile::parse() records[i]->post(this); } +void NIFFile::setUseSkinning(bool skinning) +{ + mUseSkinning = skinning; +} + +bool NIFFile::getUseSkinning() const +{ + return mUseSkinning; +} + } diff --git a/components/nif/niffile.hpp b/components/nif/niffile.hpp index 9f08f3f1d..ae5aca5ac 100644 --- a/components/nif/niffile.hpp +++ b/components/nif/niffile.hpp @@ -32,6 +32,8 @@ class NIFFile /// Root list. This is a select portion of the pointers from records std::vector roots; + bool mUseSkinning; + /// Parse the file void parse(); @@ -83,6 +85,12 @@ public: /// Number of roots size_t numRoots() const { return roots.size(); } + /// Set whether there is skinning contained in this NIF file. + /// @note This is just a hint for users of the NIF file and has no effect on the loading procedure. + void setUseSkinning(bool skinning); + + bool getUseSkinning() const; + /// Get the name of the file std::string getFilename(){ return filename; } }; diff --git a/components/nif/node.hpp b/components/nif/node.hpp index 7f94c0d05..b47c05281 100644 --- a/components/nif/node.hpp +++ b/components/nif/node.hpp @@ -166,6 +166,8 @@ struct NiTriShape : Node Node::post(nif); data.post(nif); skin.post(nif); + if (!skin.empty()) + nif->setUseSkinning(true); } }; diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index c6927cfad..3c15b57ae 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -297,7 +297,7 @@ namespace void apply(osg::Node &node) { std::map::const_iterator found = mMap.find(node.getName()); - if (found != mMap.end()) + if (node.asTransform() && found != mMap.end()) { const Nif::NiKeyframeController* keyframectrl = found->second; @@ -439,6 +439,9 @@ namespace NifOsg osg::ref_ptr load(Nif::NIFFilePtr nif, TextKeyMap* textKeys) { + if (nif->getUseSkinning()) + return loadAsSkeleton(nif, textKeys); + if (nif->numRoots() < 1) nif->fail("Found no root nodes"); diff --git a/components/nifosg/nifloader.hpp b/components/nifosg/nifloader.hpp index 43eb8da78..87d1a0a99 100644 --- a/components/nifosg/nifloader.hpp +++ b/components/nifosg/nifloader.hpp @@ -24,13 +24,11 @@ namespace NifOsg class Loader { public: - // TODO: add auto-detection for skinning. We will still need a "force skeleton" parameter - // though, when assembling from several files, i.e. equipment parts - /// Create a scene graph for the given NIF. Assumes no skinning is used. + /// Create a scene graph for the given NIF. Auto-detects when skinning is used and calls loadAsSkeleton instead. /// @param node The parent of the new root node for the created scene graph. osg::ref_ptr load(Nif::NIFFilePtr file, TextKeyMap* textKeys = NULL); - /// Create a scene graph for the given NIF. Assumes skinning will be used. + /// Create a scene graph for the given NIF. Always creates a skeleton so that rigs can be attached on the created scene. osg::ref_ptr loadAsSkeleton(Nif::NIFFilePtr file, TextKeyMap* textKeys = NULL); /// Load keyframe controllers from the given kf file onto the given scene graph. From 96d51f0bb70f9583635891d72905048a723c6d00 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 25 Mar 2015 16:34:51 +0100 Subject: [PATCH 0819/3725] NiParticleRotation seems to be unused --- components/nifosg/nifloader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 3c15b57ae..a15ad7416 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -748,7 +748,7 @@ namespace NifOsg } else if (affectors->recType == Nif::RC_NiParticleRotation) { - // TODO: Implement? + // unused? } else std::cerr << "Unhandled particle modifier " << affectors->recName << std::endl; From e938fa4a9d832cffd69003fbb7f0d43a49c554f0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 25 Mar 2015 18:12:04 +0100 Subject: [PATCH 0820/3725] Implement extrapolation mode in ControllerFunction (Bug #1871) --- components/nifosg/controller.cpp | 59 ++++++++++++++++++-------------- components/nifosg/controller.hpp | 15 ++++---- components/nifosg/nifloader.cpp | 4 +-- 3 files changed, 44 insertions(+), 34 deletions(-) diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index a31263d8b..6aa920553 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -18,50 +18,59 @@ namespace NifOsg { -ControllerFunction::ControllerFunction(const Nif::Controller *ctrl, bool deltaInput) - : mDeltaInput(deltaInput) - , mFrequency(ctrl->frequency) +ControllerFunction::ControllerFunction(const Nif::Controller *ctrl) + : mFrequency(ctrl->frequency) , mPhase(ctrl->phase) , mStartTime(ctrl->timeStart) , mStopTime(ctrl->timeStop) - , mDeltaCount(0.f) + , mExtrapolationMode(static_cast((ctrl->flags&0x6) >> 1)) { - if(mDeltaInput) - mDeltaCount = mPhase; } float ControllerFunction::calculate(float value) { - if(mDeltaInput) + float time = mFrequency * value + mPhase; + if (time >= mStartTime && time <= mStopTime) + return time; + switch (mExtrapolationMode) { - if (mStopTime - mStartTime == 0.f) - return 0.f; - - mDeltaCount += value*mFrequency; - if(mDeltaCount < mStartTime) - mDeltaCount = mStopTime - std::fmod(mStartTime - mDeltaCount, - mStopTime - mStartTime); - mDeltaCount = std::fmod(mDeltaCount - mStartTime, - mStopTime - mStartTime) + mStartTime; - return mDeltaCount; + case Cycle: + { + float delta = mStopTime - mStartTime; + if ( delta <= 0 ) + return mStartTime; + float cycles = ( time - mStartTime ) / delta; + float remainder = ( cycles - std::floor( cycles ) ) * delta; + return mStartTime + remainder; } + case Reverse: + { + float delta = mStopTime - mStartTime; + if ( delta <= 0 ) + return mStartTime; + + float cycles = ( time - mStartTime ) / delta; + float remainder = ( cycles - std::floor( cycles ) ) * delta; - value = std::min(mStopTime, std::max(mStartTime, value+mPhase)); - return value; + // Even number of cycles? + if ( ( static_cast(std::fabs( std::floor( cycles ) )) % 2 ) == 0 ) + return mStartTime + remainder; + + return mStopTime - remainder; + } + case Constant: + default: + return std::min(mStopTime, std::max(mStartTime, time)); + } } FrameTimeSource::FrameTimeSource() - : mLastTime(0.0) { } float FrameTimeSource::getValue(osg::NodeVisitor *nv) { - // TODO: dt could be computed globally instead of once per instance - double time = nv->getFrameStamp()->getReferenceTime(); - float dt = static_cast(time - mLastTime); - mLastTime = time; - return dt; + return nv->getFrameStamp()->getReferenceTime(); } KeyframeController::KeyframeController() diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index c6ef74d2a..7579735ca 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -81,17 +81,20 @@ namespace NifOsg float mFrequency; float mPhase; float mStartTime; - bool mDeltaInput; - float mDeltaCount; - public: float mStopTime; + enum ExtrapolationMode + { + Cycle = 0, + Reverse = 1, + Constant = 2 + }; + ExtrapolationMode mExtrapolationMode; public: - ControllerFunction(const Nif::Controller *ctrl, bool deltaInput); + ControllerFunction(const Nif::Controller *ctrl); float calculate(float value); }; - typedef ControllerFunction DefaultFunction; class ControllerSource { @@ -104,8 +107,6 @@ namespace NifOsg public: FrameTimeSource(); virtual float getValue(osg::NodeVisitor* nv); - private: - double mLastTime; }; class Controller diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index a15ad7416..17a669312 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -302,7 +302,7 @@ namespace const Nif::NiKeyframeController* keyframectrl = found->second; osg::ref_ptr callback(new NifOsg::SourcedKeyframeController(keyframectrl->data.getPtr(), mSourceIndex)); - callback->mFunction = boost::shared_ptr(new NifOsg::ControllerFunction(keyframectrl, false)); + callback->mFunction = boost::shared_ptr(new NifOsg::ControllerFunction(keyframectrl)); // Insert in front of the callback list, to make sure UpdateBone is last. // The order of SourcedKeyframeControllers doesn't matter since only one of them should be enabled at a time. @@ -490,7 +490,7 @@ namespace NifOsg //if (autoPlay) toSetup->mSource = boost::shared_ptr(new FrameTimeSource); - toSetup->mFunction = boost::shared_ptr(new ControllerFunction(ctrl, 1 /*autoPlay*/)); + toSetup->mFunction = boost::shared_ptr(new ControllerFunction(ctrl)); } osg::ref_ptr handleNode(const Nif::Node* nifNode, bool createSkeleton, From caa93f767b18731285d7d29d34319b0a3e9d0b5f Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 25 Mar 2015 18:41:37 +0100 Subject: [PATCH 0821/3725] Skip creating meshes for hidden nodes with no VisControllers There's quite a bit of garbage in base_anim.nif, so this change should result in a much leaner scene graph. --- components/nifosg/nifloader.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 17a669312..bdd40e245 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -562,10 +562,20 @@ namespace NifOsg transformNode->setNodeMask(0x1); } - // We could probably skip hidden nodes entirely if they don't have a VisController that + // We can skip creating meshes for hidden nodes if they don't have a VisController that // might make them visible later if (nifNode->flags & Nif::NiNode::Flag_Hidden) - transformNode->setNodeMask(0x1); // Leave mask for UpdateVisitor enabled + { + bool hasVisController = false; + for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next) + hasVisController = (ctrl->recType == Nif::RC_NiVisController); + + if (!hasVisController) + skipMeshes = true; // skip child meshes, but still create the child node hierarchy for animating collision shapes + + // now hide this node, but leave the mask for UpdateVisitor enabled so that KeyframeController works + transformNode->setNodeMask(0x1); + } applyNodeProperties(nifNode, transformNode, boundTextures, animflags); From aedafe651a52701d44de32b9cf52a857a39c0d2d Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 25 Mar 2015 19:08:09 +0100 Subject: [PATCH 0822/3725] OpenCS: delete physicssystem, will be replaced with OSG picking --- apps/opencs/CMakeLists.txt | 4 +- apps/opencs/model/doc/document.cpp | 12 +- apps/opencs/model/doc/document.hpp | 8 - apps/opencs/view/render/cell.cpp | 13 +- apps/opencs/view/render/cell.hpp | 9 +- apps/opencs/view/render/mousestate.cpp | 463 ------------------ apps/opencs/view/render/mousestate.hpp | 91 ---- apps/opencs/view/render/object.cpp | 26 +- apps/opencs/view/render/object.hpp | 2 - .../view/render/pagedworldspacewidget.cpp | 2 +- .../view/render/unpagedworldspacewidget.cpp | 4 +- apps/opencs/view/render/worldspacewidget.cpp | 23 +- apps/opencs/view/render/worldspacewidget.hpp | 9 +- apps/opencs/view/world/physicssystem.cpp | 325 ------------ apps/opencs/view/world/physicssystem.hpp | 94 ---- 15 files changed, 26 insertions(+), 1059 deletions(-) delete mode 100644 apps/opencs/view/render/mousestate.cpp delete mode 100644 apps/opencs/view/render/mousestate.hpp delete mode 100644 apps/opencs/view/world/physicssystem.cpp delete mode 100644 apps/opencs/view/world/physicssystem.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 6976aec42..4f6b2a875 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -66,7 +66,7 @@ opencs_units (view/world opencs_units_noqt (view/world subviews enumdelegate vartypedelegate recordstatusdelegate idtypedelegate datadisplaydelegate - scripthighlighter idvalidator dialoguecreator physicssystem + scripthighlighter idvalidator dialoguecreator ) opencs_units (view/widget @@ -81,7 +81,7 @@ opencs_units (view/render opencs_units_noqt (view/render navigation navigation1st navigationfree navigationorbit lighting lightingday lightingnight - lightingbright object cell terrainstorage textoverlay mousestate + lightingbright object cell terrainstorage textoverlay ) opencs_hdrs_noqt (view/render diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 2a5fa7746..7f3d98d0c 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -9,8 +9,6 @@ #include #endif -#include "../../view/world/physicssystem.hpp" - void CSMDoc::Document::addGmsts() { static const char *gmstFloats[] = @@ -2255,7 +2253,7 @@ CSMDoc::Document::Document (const VFS::Manager* vfs, const Files::ConfigurationM mProjectPath ((configuration.getUserDataPath() / "projects") / (savePath.filename().string() + ".project")), mSaving (*this, mProjectPath, encoding), - mRunner (mProjectPath), mPhysics(boost::shared_ptr()) + mRunner (mProjectPath) { if (mContentFiles.empty()) throw std::runtime_error ("Empty content file sequence"); @@ -2471,11 +2469,3 @@ void CSMDoc::Document::progress (int current, int max, int type) { emit progress (current, max, type, 1, this); } - -boost::shared_ptr CSMDoc::Document::getPhysics () -{ - if(!mPhysics) - mPhysics = boost::shared_ptr (new CSVWorld::PhysicsSystem()); - - return mPhysics; -} diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp index 2d42e9903..292b292df 100644 --- a/apps/opencs/model/doc/document.hpp +++ b/apps/opencs/model/doc/document.hpp @@ -46,11 +46,6 @@ namespace CSMWorld class ResourcesManager; } -namespace CSVWorld -{ - class PhysicsSystem; -} - namespace CSMDoc { class Document : public QObject @@ -70,7 +65,6 @@ namespace CSMDoc boost::filesystem::path mResDir; Blacklist mBlacklist; Runner mRunner; - boost::shared_ptr mPhysics; // It is important that the undo stack is declared last, because on desctruction it fires a signal, that is connected to a slot, that is // using other member variables. Unfortunately this connection is cut only in the QObject destructor, which is way too late. @@ -145,8 +139,6 @@ namespace CSMDoc QTextDocument *getRunLog(); - boost::shared_ptr getPhysics(); - signals: void stateChanged (int state, CSMDoc::Document *document); diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index 72ceb654a..28ce1dd6c 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -10,7 +10,6 @@ #include "../../model/world/idtable.hpp" #include "../../model/world/columns.hpp" #include "../../model/world/data.hpp" -#include "../world/physicssystem.hpp" #include "elements.hpp" #include "terrainstorage.hpp" @@ -60,8 +59,8 @@ bool CSVRender::Cell::addObjects (int start, int end) } CSVRender::Cell::Cell (CSMWorld::Data& data, Ogre::SceneManager *sceneManager, - const std::string& id, boost::shared_ptr physics, const Ogre::Vector3& origin) -: mData (data), mId (Misc::StringUtils::lowerCase (id)), mSceneMgr(sceneManager), mPhysics(physics), mX(0), mY(0) + const std::string& id, const Ogre::Vector3& origin) +: mData (data), mId (Misc::StringUtils::lowerCase (id)), mSceneMgr(sceneManager), mX(0), mY(0) { mCellNode = sceneManager->getRootSceneNode()->createChildSceneNode(); mCellNode->setPosition (origin); @@ -89,16 +88,16 @@ CSVRender::Cell::Cell (CSMWorld::Data& data, Ogre::SceneManager *sceneManager, float worldsize = ESM::Land::REAL_SIZE; mX = esmLand->mX; mY = esmLand->mY; - mPhysics->addHeightField(sceneManager, - esmLand->mLandData->mHeights, mX, mY, 0, worldsize / (verts-1), verts); + //mPhysics->addHeightField(sceneManager, + // esmLand->mLandData->mHeights, mX, mY, 0, worldsize / (verts-1), verts); } } } CSVRender::Cell::~Cell() { - if (mTerrain.get()) - mPhysics->removeHeightField(mSceneMgr, mX, mY); + //if (mTerrain.get()) + // mPhysics->removeHeightField(mSceneMgr, mX, mY); for (std::map::iterator iter (mObjects.begin()); iter!=mObjects.end(); ++iter) diff --git a/apps/opencs/view/render/cell.hpp b/apps/opencs/view/render/cell.hpp index 73d794948..8c7d7e23a 100644 --- a/apps/opencs/view/render/cell.hpp +++ b/apps/opencs/view/render/cell.hpp @@ -28,11 +28,6 @@ namespace CSMWorld class Data; } -namespace CSVWorld -{ - class PhysicsSystem; -} - namespace CSVRender { class Cell @@ -42,7 +37,6 @@ namespace CSVRender Ogre::SceneNode *mCellNode; std::map mObjects; std::auto_ptr mTerrain; - boost::shared_ptr mPhysics; Ogre::SceneManager *mSceneMgr; int mX; int mY; @@ -59,8 +53,7 @@ namespace CSVRender public: - Cell (CSMWorld::Data& data, Ogre::SceneManager *sceneManager, const std::string& id, - boost::shared_ptr physics, const Ogre::Vector3& origin = Ogre::Vector3 (0, 0, 0)); + Cell (CSMWorld::Data& data, Ogre::SceneManager *sceneManager, const std::string& id, const Ogre::Vector3& origin = Ogre::Vector3 (0, 0, 0)); ~Cell(); diff --git a/apps/opencs/view/render/mousestate.cpp b/apps/opencs/view/render/mousestate.cpp deleted file mode 100644 index 8edd9d58f..000000000 --- a/apps/opencs/view/render/mousestate.cpp +++ /dev/null @@ -1,463 +0,0 @@ -#include "mousestate.hpp" - -#include -#include -#include -#include - -#include -#include -#include - -#include "../../model/settings/usersettings.hpp" -#include "../../model/world/commands.hpp" -#include "../../model/world/idtable.hpp" -#include "../../model/world/universalid.hpp" -#include "../world/physicssystem.hpp" - -#include "elements.hpp" -#include "worldspacewidget.hpp" - -namespace CSVRender -{ - // mouse picking - // FIXME: need to virtualise mouse buttons - // - // State machine: - // - // [default] mousePressEvent->check if the mouse is pointing at an object - // if yes, create collision planes then go to [grab] - // else check for terrain - // - // [grab] mouseReleaseEvent->if same button and new obj, go to [edit] - // mouseMoveEvent->if same button, go to [drag] - // other mouse events or buttons, go back to [default] (i.e. like 'cancel') - // - // [drag] mouseReleaseEvent->if same button, place the object at the new - // location, update the document then go to [edit] - // mouseMoveEvent->update position to the user based on ray to the collision - // planes and render the object at the new location, but do not update - // the document yet - // - // [edit] TODO, probably fine positional adjustments or rotations; clone/delete? - // - // - // press press (obj) - // [default] --------> [grab] <-------------------- [edit] - // ^ (obj) | | ------> [drag] -----> ^ - // | | | move ^ | release | - // | | | | | | - // | | | +-+ | - // | | | move | - // +----------------+ +--------------------------+ - // release release - // (same obj) (new obj) - // - // - - MouseState::MouseState(WorldspaceWidget *parent) - : mParent(parent), mPhysics(parent->mDocument.getPhysics()), mSceneManager(0/*parent->getSceneManager()*/) - , mCurrentObj(""), mMouseState(Mouse_Default), mOldPos(0,0), mMouseEventTimer(0), mPlane(0) - , mGrabbedSceneNode(""), mOrigObjPos(Ogre::Vector3()), mOrigMousePos(Ogre::Vector3()) - , mCurrentMousePos(Ogre::Vector3()), mOffset(0.0f) - , mColIndexPosX(0), mColIndexPosY(0), mColIndexPosZ(0), mIdTableModel(0) - { - const CSMWorld::RefCollection& references = mParent->mDocument.getData().getReferences(); - - mColIndexPosX = references.findColumnIndex(CSMWorld::Columns::ColumnId_PositionXPos); - mColIndexPosY = references.findColumnIndex(CSMWorld::Columns::ColumnId_PositionYPos); - mColIndexPosZ = references.findColumnIndex(CSMWorld::Columns::ColumnId_PositionZPos); - - mIdTableModel = static_cast( - mParent->mDocument.getData().getTableModel(CSMWorld::UniversalId::Type_Reference)); - - mMouseEventTimer = new QElapsedTimer(); - mMouseEventTimer->invalidate(); - - std::pair planeRes = planeAxis(); - mPlane = new Ogre::Plane(planeRes.first, 0); - Ogre::MeshPtr mesh = Ogre::MeshManager::getSingleton().createPlane("mouse", - Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - *mPlane, - 300000,300000, // FIXME: use far clip dist? - 1,1, // segments - true, // normals - 1, // numTexCoordSets - 1,1, // uTile, vTile - planeRes.second // upVector - ); - } - - MouseState::~MouseState () - { - delete mMouseEventTimer; - delete mPlane; - } - - void MouseState::mouseMoveEvent (QMouseEvent *event) - { - switch(mMouseState) - { - case Mouse_Grab: - { - // check if min elapsed time to stop false detection of drag - if(!mMouseEventTimer->isValid() || !mMouseEventTimer->hasExpired(100)) // ms - break; - - mMouseEventTimer->invalidate(); - mMouseState = Mouse_Drag; - - /* FALL_THROUGH */ - } - case Mouse_Drag: - { - if(event->pos() != mOldPos) // TODO: maybe don't update less than a quantum? - { - mOldPos = event->pos(); - - // ray test against the plane to provide feedback to the user the - // relative movement of the object on the x-y plane - std::pair planeResult = mousePositionOnPlane(event->pos(), *mPlane); - if(planeResult.first) - { - if(mGrabbedSceneNode != "") - { - std::pair planeRes = planeAxis(); - Ogre::Vector3 pos = mOrigObjPos + planeRes.first*mOffset; - mSceneManager->getSceneNode(mGrabbedSceneNode)->setPosition(pos+planeResult.second-mOrigMousePos); - mCurrentMousePos = planeResult.second; - mPhysics->moveSceneNodes(mGrabbedSceneNode, pos+planeResult.second-mOrigMousePos); - updateSceneWidgets(); - } - } - } - break; - } - case Mouse_Edit: - case Mouse_Default: - { - break; // error event, ignore - } - /* NO_DEFAULT_CASE */ - } - } - - void MouseState::mousePressEvent (QMouseEvent *event) - { - switch(mMouseState) - { - case Mouse_Grab: - case Mouse_Drag: - { - break; - } - case Mouse_Edit: - case Mouse_Default: - { - if(event->buttons() & Qt::RightButton) - { - std::pair result = objectUnderCursor(event->x(), event->y()); - if(result.first == "") - break; - - mGrabbedSceneNode = result.first; - // ray test agaist the plane to get a starting position of the - // mouse in relation to the object position - std::pair planeRes = planeAxis(); - mPlane->redefine(planeRes.first, result.second); - std::pair planeResult = mousePositionOnPlane(event->pos(), *mPlane); - if(planeResult.first) - { - mOrigMousePos = planeResult.second; - mCurrentMousePos = planeResult.second; - mOffset = 0.0f; - } - - mOrigObjPos = mSceneManager->getSceneNode(mGrabbedSceneNode)->getPosition(); - mMouseEventTimer->start(); - - mMouseState = Mouse_Grab; - } - break; - } - /* NO_DEFAULT_CASE */ - } - } - - void MouseState::mouseReleaseEvent (QMouseEvent *event) - { - switch(mMouseState) - { - case Mouse_Grab: - { - std::pair result = objectUnderCursor(event->x(), event->y()); - if(result.first != "") - { - if(result.first == mCurrentObj) - { - // unselect object - mMouseState = Mouse_Default; - mCurrentObj = ""; - } - else - { - // select object - mMouseState = Mouse_Edit; - mCurrentObj = result.first; - - } - } - break; - } - case Mouse_Drag: - { - // final placement - std::pair planeResult = mousePositionOnPlane(event->pos(), *mPlane); - if(planeResult.first) - { - if(mGrabbedSceneNode != "") - { - std::pair planeRes = planeAxis(); - Ogre::Vector3 pos = mOrigObjPos+planeRes.first*mOffset+planeResult.second-mOrigMousePos; - // use the saved scene node name since the physics model has not moved yet - std::string referenceId = mPhysics->sceneNodeToRefId(mGrabbedSceneNode); - - mParent->mDocument.getUndoStack().beginMacro (QObject::tr("Move Object")); - mParent->mDocument.getUndoStack().push(new CSMWorld::ModifyCommand(*mIdTableModel, - mIdTableModel->getModelIndex(referenceId, mColIndexPosX), pos.x)); - mParent->mDocument.getUndoStack().push(new CSMWorld::ModifyCommand(*mIdTableModel, - mIdTableModel->getModelIndex(referenceId, mColIndexPosY), pos.y)); - mParent->mDocument.getUndoStack().push(new CSMWorld::ModifyCommand(*mIdTableModel, - mIdTableModel->getModelIndex(referenceId, mColIndexPosZ), pos.z)); - mParent->mDocument.getUndoStack().endMacro(); - - // FIXME: highlight current object? - //mCurrentObj = mGrabbedSceneNode; // FIXME: doesn't work? - mCurrentObj = ""; // whether the object is selected - - mMouseState = Mouse_Edit; - - // reset states - mCurrentMousePos = Ogre::Vector3(); // mouse pos to use in wheel event - mOrigMousePos = Ogre::Vector3(); // starting pos of mouse in world space - mOrigObjPos = Ogre::Vector3(); // starting pos of object in world space - mGrabbedSceneNode = ""; // id of the object - mOffset = 0.0f; // used for z-axis movement - mOldPos = QPoint(0, 0); // to calculate relative movement of mouse - } - } - break; - } - case Mouse_Edit: - case Mouse_Default: - { - // probably terrain, check - std::pair result = terrainUnderCursor(event->x(), event->y()); - if(result.first != "") - { - // FIXME: terrain editing goes here - } - break; - } - /* NO_DEFAULT_CASE */ - } - mMouseEventTimer->invalidate(); - } - - void MouseState::mouseDoubleClickEvent (QMouseEvent *event) - { - event->ignore(); - //mPhysics->toggleDebugRendering(mSceneManager); - //mParent->flagAsModified(); - } - - bool MouseState::wheelEvent (QWheelEvent *event) - { - switch(mMouseState) - { - case Mouse_Grab: - mMouseState = Mouse_Drag; - - /* FALL_THROUGH */ - case Mouse_Drag: - { - // move the object along the z axis during Mouse_Drag or Mouse_Grab - if (event->delta()) - { - // seems positive is up and negative is down - mOffset += (event->delta()/1); // FIXME: arbitrary number, make config option? - - std::pair planeRes = planeAxis(); - Ogre::Vector3 pos = mOrigObjPos + planeRes.first*mOffset; - mSceneManager->getSceneNode(mGrabbedSceneNode)->setPosition(pos+mCurrentMousePos-mOrigMousePos); - mPhysics->moveSceneNodes(mGrabbedSceneNode, pos+mCurrentMousePos-mOrigMousePos); - updateSceneWidgets(); - } - break; - } - case Mouse_Edit: - case Mouse_Default: - { - return false; - } - /* NO_DEFAULT_CASE */ - } - - return true; - } - - void MouseState::cancelDrag() - { - switch(mMouseState) - { - case Mouse_Grab: - case Mouse_Drag: - { - // cancel operation & return the object to the original position - mSceneManager->getSceneNode(mGrabbedSceneNode)->setPosition(mOrigObjPos); - // update all SceneWidgets and their SceneManagers - mPhysics->moveSceneNodes(mGrabbedSceneNode, mOrigObjPos); - updateSceneWidgets(); - - // reset states - mMouseState = Mouse_Default; - mCurrentMousePos = Ogre::Vector3(); - mOrigMousePos = Ogre::Vector3(); - mOrigObjPos = Ogre::Vector3(); - mGrabbedSceneNode = ""; - mCurrentObj = ""; - mOldPos = QPoint(0, 0); - mMouseEventTimer->invalidate(); - mOffset = 0.0f; - - break; - } - case Mouse_Edit: - case Mouse_Default: - { - break; - } - /* NO_DEFAULT_CASE */ - } - } - - //plane Z, upvector Y, mOffset z : x-y plane, wheel up/down - //plane Y, upvector X, mOffset y : y-z plane, wheel left/right - //plane X, upvector Y, mOffset x : x-z plane, wheel closer/further - std::pair MouseState::planeAxis() - { - const bool screenCoord = true; - Ogre::Vector3 dir = getCamera()->getDerivedDirection(); - - QString wheelDir = "Closer/Further"; - if(wheelDir == "Left/Right") - { - if(screenCoord) - return std::make_pair(getCamera()->getDerivedRight(), getCamera()->getDerivedUp()); - else - return std::make_pair(Ogre::Vector3::UNIT_Y, Ogre::Vector3::UNIT_Z); - } - else if(wheelDir == "Up/Down") - { - if(screenCoord) - return std::make_pair(getCamera()->getDerivedUp(), Ogre::Vector3(-dir.x, -dir.y, -dir.z)); - else - return std::make_pair(Ogre::Vector3::UNIT_Z, Ogre::Vector3::UNIT_X); - } - else - { - if(screenCoord) - return std::make_pair(Ogre::Vector3(-dir.x, -dir.y, -dir.z), getCamera()->getDerivedRight()); - else - return std::make_pair(Ogre::Vector3::UNIT_X, Ogre::Vector3::UNIT_Y); - } - } - - std::pair MouseState::mousePositionOnPlane(const QPoint &pos, const Ogre::Plane &plane) - { - // using a really small value seems to mess up with the projections - float nearClipDistance = getCamera()->getNearClipDistance(); // save existing - getCamera()->setNearClipDistance(10.0f); // arbitrary number - Ogre::Ray mouseRay = getCamera()->getCameraToViewportRay( - (float) pos.x() / getViewport()->getActualWidth(), - (float) pos.y() / getViewport()->getActualHeight()); - getCamera()->setNearClipDistance(nearClipDistance); // restore - std::pair planeResult = mouseRay.intersects(plane); - - if(planeResult.first) - return std::make_pair(true, mouseRay.getPoint(planeResult.second)); - else - return std::make_pair(false, Ogre::Vector3()); // should only happen if the plane is too small - } - - std::pair MouseState::terrainUnderCursor(const int mouseX, const int mouseY) - { - if(!getViewport()) - return std::make_pair("", Ogre::Vector3()); - - float x = (float) mouseX / getViewport()->getActualWidth(); - float y = (float) mouseY / getViewport()->getActualHeight(); - - std::pair result = mPhysics->castRay(x, y, mSceneManager, getCamera()); - if(result.first != "") - { - // FIXME: is there a better way to distinguish terrain from objects? - QString name = QString(result.first.c_str()); - if(name.contains(QRegExp("^HeightField"))) - { - return result; - } - } - - return std::make_pair("", Ogre::Vector3()); - } - - std::pair MouseState::objectUnderCursor(const int mouseX, const int mouseY) - { - if(!getViewport()) - return std::make_pair("", Ogre::Vector3()); - - float x = (float) mouseX / getViewport()->getActualWidth(); - float y = (float) mouseY / getViewport()->getActualHeight(); - - std::pair result = mPhysics->castRay(x, y, mSceneManager, getCamera()); - if(result.first != "") - { - // NOTE: anything not terrain is assumed to be an object - QString name = QString(result.first.c_str()); - if(!name.contains(QRegExp("^HeightField"))) - { - uint32_t visibilityMask = getViewport()->getVisibilityMask(); - bool ignoreObjects = !(visibilityMask & (uint32_t)CSVRender::Element_Reference); - - if(!ignoreObjects && mSceneManager->hasSceneNode(result.first)) - { - return result; - } - } - } - - return std::make_pair("", Ogre::Vector3()); - } - - void MouseState::updateSceneWidgets() - { - std::map sceneWidgets = mPhysics->sceneWidgets(); - - std::map::iterator iter = sceneWidgets.begin(); - for(; iter != sceneWidgets.end(); ++iter) - { - //(*iter).second->updateScene(); - } - } - - Ogre::Camera *MouseState::getCamera() - { - return 0;//mParent->getCamera(); - } - - Ogre::Viewport *MouseState::getViewport() - { - return 0;//mParent->getCamera()->getViewport(); - } -} diff --git a/apps/opencs/view/render/mousestate.hpp b/apps/opencs/view/render/mousestate.hpp deleted file mode 100644 index 70e18427f..000000000 --- a/apps/opencs/view/render/mousestate.hpp +++ /dev/null @@ -1,91 +0,0 @@ -#ifndef OPENCS_VIEW_MOUSESTATE_H -#define OPENCS_VIEW_MOUSESTATE_H - -#include -#include -#include -#include - -class QElapsedTimer; -class QMouseEvent; -class QWheelEvent; - -namespace Ogre -{ - class Plane; - class SceneManager; - class Camera; - class Viewport; -} - -namespace CSVWorld -{ - class PhysicsSystem; -} - -namespace CSMWorld -{ - class IdTable; -} - -namespace CSVRender -{ - class WorldspaceWidget; - - class MouseState - { - enum MouseStates - { - Mouse_Grab, - Mouse_Drag, - Mouse_Edit, - Mouse_Default - }; - MouseStates mMouseState; - - WorldspaceWidget *mParent; - boost::shared_ptr mPhysics; - Ogre::SceneManager *mSceneManager; // local copy - - QPoint mOldPos; - std::string mCurrentObj; - std::string mGrabbedSceneNode; - QElapsedTimer *mMouseEventTimer; - Ogre::Plane *mPlane; - Ogre::Vector3 mOrigObjPos; - Ogre::Vector3 mOrigMousePos; - Ogre::Vector3 mCurrentMousePos; - float mOffset; - - CSMWorld::IdTable *mIdTableModel; - int mColIndexPosX; - int mColIndexPosY; - int mColIndexPosZ; - - public: - - MouseState(WorldspaceWidget *parent); - ~MouseState(); - - void mouseMoveEvent (QMouseEvent *event); - void mousePressEvent (QMouseEvent *event); - void mouseReleaseEvent (QMouseEvent *event); - void mouseDoubleClickEvent (QMouseEvent *event); - bool wheelEvent (QWheelEvent *event); - - void cancelDrag(); - - private: - - std::pair mousePositionOnPlane(const QPoint &pos, const Ogre::Plane &plane); - std::pair terrainUnderCursor(const int mouseX, const int mouseY); - std::pair objectUnderCursor(const int mouseX, const int mouseY); - std::pair planeAxis(); - void updateSceneWidgets(); - - Ogre::Camera *getCamera(); // friend access - Ogre::Viewport *getViewport(); // friend access - }; -} - -#endif // OPENCS_VIEW_MOUSESTATE_H diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index bd44ba577..9bc7aa260 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -6,8 +6,6 @@ #include "../../model/world/ref.hpp" #include "../../model/world/refidcollection.hpp" -#include "../world/physicssystem.hpp" - #include #include "elements.hpp" @@ -63,25 +61,6 @@ void CSVRender::Object::update() mBaseNode->addChild(loader.load(file)); //mObject->setVisibilityFlags (Element_Reference); - - /* - if (mPhysics && !mReferenceId.empty()) - { - const CSMWorld::CellRef& reference = getReference(); - - // position - Ogre::Vector3 position; - if (!mForceBaseToZero) - position = Ogre::Vector3(reference.mPos.pos[0], reference.mPos.pos[1], reference.mPos.pos[2]); - - // orientation - Ogre::Quaternion xr (Ogre::Radian (-reference.mPos.rot[0]), Ogre::Vector3::UNIT_X); - Ogre::Quaternion yr (Ogre::Radian (-reference.mPos.rot[1]), Ogre::Vector3::UNIT_Y); - Ogre::Quaternion zr (Ogre::Radian (-reference.mPos.rot[2]), Ogre::Vector3::UNIT_Z); - - mPhysics->addObject("meshes\\" + model, mBase->getName(), mReferenceId, reference.mScale, position, xr*yr*zr); - } - */ } } @@ -121,9 +100,8 @@ const CSMWorld::CellRef& CSVRender::Object::getReference() const } CSVRender::Object::Object (const VFS::Manager* vfs, const CSMWorld::Data& data, osg::Group* parentNode, - const std::string& id, bool referenceable, boost::shared_ptr physics, - bool forceBaseToZero) -: mVFS(vfs), mData (data), mBaseNode(0), mParentNode(parentNode), mForceBaseToZero (forceBaseToZero), mPhysics(physics) + const std::string& id, bool referenceable, bool forceBaseToZero) +: mVFS(vfs), mData (data), mBaseNode(0), mParentNode(parentNode), mForceBaseToZero (forceBaseToZero) { mBaseNode = new osg::Group; parentNode->addChild(mBaseNode); diff --git a/apps/opencs/view/render/object.hpp b/apps/opencs/view/render/object.hpp index 8e9598bbf..431867d6b 100644 --- a/apps/opencs/view/render/object.hpp +++ b/apps/opencs/view/render/object.hpp @@ -40,7 +40,6 @@ namespace CSVRender osg::Group* mParentNode; const VFS::Manager* mVFS; bool mForceBaseToZero; - boost::shared_ptr mPhysics; /// Not implemented Object (const Object&); @@ -64,7 +63,6 @@ namespace CSVRender Object (const VFS::Manager* vfs, const CSMWorld::Data& data, osg::Group *cellNode, const std::string& id, bool referenceable, - boost::shared_ptr physics = boost::shared_ptr (), bool forceBaseToZero = false); /// \param forceBaseToZero If this is a reference ignore the coordinates and place /// it at 0, 0, 0 instead. diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index 84a5a5665..ca4678d49 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -112,7 +112,7 @@ bool CSVRender::PagedWorldspaceWidget::adjustCells() { #if 0 Cell *cell = new Cell (mDocument.getData(), getSceneManager(), - iter->getId (mWorldspace), mDocument.getPhysics()); + iter->getId (mWorldspace)); mCells.insert (std::make_pair (*iter, cell)); float height = cell->getTerrainHeightAt(Ogre::Vector3( diff --git a/apps/opencs/view/render/unpagedworldspacewidget.cpp b/apps/opencs/view/render/unpagedworldspacewidget.cpp index 3be791f23..fd63567c7 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.cpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.cpp @@ -49,7 +49,7 @@ CSVRender::UnpagedWorldspaceWidget::UnpagedWorldspaceWidget (const std::string& update(); - //mCell.reset (new Cell (document.getData(), getSceneManager(), mCellId, document.getPhysics())); + //mCell.reset (new Cell (document.getData(), getSceneManager(), mCellId)); } void CSVRender::UnpagedWorldspaceWidget::cellDataChanged (const QModelIndex& topLeft, @@ -91,7 +91,7 @@ bool CSVRender::UnpagedWorldspaceWidget::handleDrop (const std::vectorgetId(); - //mCell.reset (new Cell (getDocument().getData(), getSceneManager(), mCellId, getDocument().getPhysics())); + //mCell.reset (new Cell (getDocument().getData(), getSceneManager(), mCellId)); update(); emit cellChanged(*data.begin()); diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 5ae5c8177..68a3acdb9 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -16,13 +16,11 @@ #include "../widget/scenetooltoggle2.hpp" #include "../widget/scenetoolrun.hpp" -#include "../world/physicssystem.hpp" - #include "elements.hpp" #include "editmode.hpp" CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidget* parent) -: SceneWidget (parent), mDocument(document), mSceneElements(0), mRun(0), mPhysics(boost::shared_ptr()), mMouse(0), +: SceneWidget (parent), mDocument(document), mSceneElements(0), mRun(0), mMouse(0), mInteractionMask (0) { setAcceptDrops(true); @@ -55,15 +53,12 @@ CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidg connect (debugProfiles, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)), this, SLOT (debugProfileAboutToBeRemoved (const QModelIndex&, int, int))); - mPhysics = document.getPhysics(); // create physics if one doesn't exist - //mPhysics->addSceneManager(getSceneManager(), this); - mMouse = new MouseState(this); + //mMouse = new MouseState(this); } CSVRender::WorldspaceWidget::~WorldspaceWidget () { - delete mMouse; - //mPhysics->removeSceneManager(getSceneManager()); + //delete mMouse; } void CSVRender::WorldspaceWidget::selectNavigationMode (const std::string& mode) @@ -370,7 +365,7 @@ void CSVRender::WorldspaceWidget::mouseMoveEvent (QMouseEvent *event) { if(event->buttons() & Qt::RightButton) { - mMouse->mouseMoveEvent(event); + //mMouse->mouseMoveEvent(event); } SceneWidget::mouseMoveEvent(event); } @@ -379,7 +374,7 @@ void CSVRender::WorldspaceWidget::mousePressEvent (QMouseEvent *event) { if(event->buttons() & Qt::RightButton) { - mMouse->mousePressEvent(event); + //mMouse->mousePressEvent(event); } //SceneWidget::mousePressEvent(event); } @@ -395,7 +390,7 @@ void CSVRender::WorldspaceWidget::mouseReleaseEvent (QMouseEvent *event) return; } */ - mMouse->mouseReleaseEvent(event); + //mMouse->mouseReleaseEvent(event); } SceneWidget::mouseReleaseEvent(event); } @@ -404,14 +399,14 @@ void CSVRender::WorldspaceWidget::mouseDoubleClickEvent (QMouseEvent *event) { if(event->button() == Qt::RightButton) { - mMouse->mouseDoubleClickEvent(event); + //mMouse->mouseDoubleClickEvent(event); } //SceneWidget::mouseDoubleClickEvent(event); } void CSVRender::WorldspaceWidget::wheelEvent (QWheelEvent *event) { - if(!mMouse->wheelEvent(event)) + //if(!mMouse->wheelEvent(event)) SceneWidget::wheelEvent(event); } @@ -419,7 +414,7 @@ void CSVRender::WorldspaceWidget::keyPressEvent (QKeyEvent *event) { if(event->key() == Qt::Key_Escape) { - mMouse->cancelDrag(); + //mMouse->cancelDrag(); } else SceneWidget::keyPressEvent(event); diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp index b19197e36..ea344f04a 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -4,7 +4,6 @@ #include #include "scenewidget.hpp" -#include "mousestate.hpp" #include "navigation1st.hpp" #include "navigationfree.hpp" @@ -25,13 +24,10 @@ namespace CSVWidget class SceneToolRun; } -namespace CSVWorld -{ - class PhysicsSystem; -} - namespace CSVRender { + class MouseState; + class WorldspaceWidget : public SceneWidget { Q_OBJECT @@ -42,7 +38,6 @@ namespace CSVRender CSVWidget::SceneToolToggle2 *mSceneElements; CSVWidget::SceneToolRun *mRun; CSMDoc::Document& mDocument; - boost::shared_ptr mPhysics; MouseState *mMouse; unsigned int mInteractionMask; diff --git a/apps/opencs/view/world/physicssystem.cpp b/apps/opencs/view/world/physicssystem.cpp deleted file mode 100644 index 4e23c185a..000000000 --- a/apps/opencs/view/world/physicssystem.cpp +++ /dev/null @@ -1,325 +0,0 @@ -#include "physicssystem.hpp" - -#include - -#include -#include -#include - -#include -#include -#include "../../model/settings/usersettings.hpp" -#include "../render/elements.hpp" - -namespace CSVWorld -{ - PhysicsSystem::PhysicsSystem() - { - // Create physics. shapeLoader is deleted by the physic engine - //NifBullet::ManualBulletShapeLoader* shapeLoader = new NifBullet::ManualBulletShapeLoader(true); - //mEngine = new OEngine::Physic::PhysicEngine(shapeLoader); - mEngine = 0; - } - - PhysicsSystem::~PhysicsSystem() - { - delete mEngine; - } - - // looks up the scene manager based on the scene node name (inefficient) - // NOTE: referenceId is assumed to be unique per document - // NOTE: searching is done here rather than after rayTest, hence slower to load but - // faster to find (guessing, not verified w/ perf test) - void PhysicsSystem::addObject(const std::string &mesh, - const std::string &sceneNodeName, const std::string &referenceId, float scale, - const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, bool placeable) - { - Ogre::SceneManager *sceneManager = findSceneManager(sceneNodeName); - if(sceneManager) - { - // update maps (NOTE: sometimes replaced) - mSceneNodeToRefId[sceneNodeName] = referenceId; - mSceneNodeToMesh[sceneNodeName] = mesh; - mRefIdToSceneNode[referenceId][sceneManager] = sceneNodeName; - } - else - { - std::cerr << "Attempt to add an object without a corresponding SceneManager: " - + referenceId + " : " + sceneNodeName << std::endl; - return; - } - - // update physics, only one physics model per referenceId - if(mEngine->getRigidBody(referenceId, true) == NULL) - { - mEngine->createAndAdjustRigidBody(mesh, - referenceId, scale, position, rotation, - 0, // scaledBoxTranslation - 0, // boxRotation - true, // raycasting - placeable); - } - } - - // normal delete (e.g closing a scene subview or ~Object()) - // the scene node is destroyed so the mappings should be removed - // - // TODO: should think about using some kind of reference counting within RigidBody - void PhysicsSystem::removeObject(const std::string &sceneNodeName) - { - std::string referenceId = mSceneNodeToRefId[sceneNodeName]; - - if(referenceId != "") - { - mSceneNodeToRefId.erase(sceneNodeName); - mSceneNodeToMesh.erase(sceneNodeName); - - // find which SceneManager has this object - Ogre::SceneManager *sceneManager = findSceneManager(sceneNodeName); - if(!sceneManager) - { - std::cerr << "Attempt to remove an object without a corresponding SceneManager: " - + sceneNodeName << std::endl; - return; - } - - // illustration: erase the object "K" from the object map - // - // RidigBody SubView Ogre - // --------------- -------------- ------------- - // ReferenceId "A" (SceneManager X SceneNode "J") - // (SceneManager Y SceneNode "K") <--- erase - // (SceneManager Z SceneNode "L") - // - // ReferenceId "B" (SceneManager X SceneNode "M") - // (SceneManager Y SceneNode "N") <--- notice not deleted - // (SceneManager Z SceneNode "O") - std::map >::iterator itRef = - mRefIdToSceneNode.begin(); - for(; itRef != mRefIdToSceneNode.end(); ++itRef) - { - if((*itRef).second.find(sceneManager) != (*itRef).second.end()) - { - (*itRef).second.erase(sceneManager); - break; - } - } - - // check whether the physics model should be deleted - if(mRefIdToSceneNode.find(referenceId) == mRefIdToSceneNode.end()) - { - mEngine->removeRigidBody(referenceId); - mEngine->deleteRigidBody(referenceId); - } - } - } - - // Object::clear() is called when reference data is changed. It clears all - // contents of the SceneNode and removes the physics object - // - // A new physics object will be created and assigned to this sceneNodeName by - // Object::update() - void PhysicsSystem::removePhysicsObject(const std::string &sceneNodeName) - { - std::string referenceId = mSceneNodeToRefId[sceneNodeName]; - - if(referenceId != "") - { - mEngine->removeRigidBody(referenceId); - mEngine->deleteRigidBody(referenceId); - } - } - - void PhysicsSystem::replaceObject(const std::string &sceneNodeName, float scale, - const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, bool placeable) - { - std::string referenceId = mSceneNodeToRefId[sceneNodeName]; - std::string mesh = mSceneNodeToMesh[sceneNodeName]; - - if(referenceId != "") - { - // delete the physics object - mEngine->removeRigidBody(referenceId); - mEngine->deleteRigidBody(referenceId); - - // create a new physics object - mEngine->createAndAdjustRigidBody(mesh, referenceId, scale, position, rotation, - 0, 0, true, placeable); - - // update other scene managers if they have the referenceId - // FIXME: rotation or scale not updated - moveSceneNodeImpl(sceneNodeName, referenceId, position); - } - } - - // FIXME: adjustRigidBody() seems to lose objects, work around by deleting and recreating objects - void PhysicsSystem::moveObject(const std::string &sceneNodeName, - const Ogre::Vector3 &position, const Ogre::Quaternion &rotation) - { - mEngine->adjustRigidBody(mEngine->getRigidBody(sceneNodeName, true /*raycasting*/), - position, rotation); - } - - void PhysicsSystem::moveSceneNodeImpl(const std::string sceneNodeName, - const std::string referenceId, const Ogre::Vector3 &position) - { - std::map::const_iterator iter = mSceneWidgets.begin(); - for(; iter != mSceneWidgets.end(); ++iter) - { - std::string name = refIdToSceneNode(referenceId, (*iter).first); - if(name != sceneNodeName && (*iter).first->hasSceneNode(name)) - { - (*iter).first->getSceneNode(name)->setPosition(position); - } - } - } - - void PhysicsSystem::moveSceneNodes(const std::string sceneNodeName, const Ogre::Vector3 &position) - { - moveSceneNodeImpl(sceneNodeName, sceneNodeToRefId(sceneNodeName), position); - } - - void PhysicsSystem::addHeightField(Ogre::SceneManager *sceneManager, - float* heights, int x, int y, float yoffset, float triSize, float sqrtVerts) - { - std::string name = "HeightField_" - + QString::number(x).toStdString() + "_" + QString::number(y).toStdString(); - - if(mTerrain.find(name) == mTerrain.end()) - mEngine->addHeightField(heights, x, y, yoffset, triSize, sqrtVerts); - - mTerrain.insert(std::pair(name, sceneManager)); - } - - void PhysicsSystem::removeHeightField(Ogre::SceneManager *sceneManager, int x, int y) - { - std::string name = "HeightField_" - + QString::number(x).toStdString() + "_" + QString::number(y).toStdString(); - - if(mTerrain.count(name) == 1) - mEngine->removeHeightField(x, y); - - std::multimap::iterator iter = mTerrain.begin(); - for(; iter != mTerrain.end(); ++iter) - { - if((*iter).second == sceneManager) - { - mTerrain.erase(iter); - break; - } - } - } - - // sceneMgr: to lookup the scene node name from the object's referenceId - // camera: primarily used to get the visibility mask for the viewport - // - // returns the found object's scene node name and its position in the world space - // - // WARNING: far clip distance is a global setting, if it changes in future - // this method will need to be updated - std::pair PhysicsSystem::castRay(float mouseX, - float mouseY, Ogre::SceneManager *sceneMgr, Ogre::Camera *camera) - { - // NOTE: there could be more than one camera for the scene manager - // TODO: check whether camera belongs to sceneMgr - if(!sceneMgr || !camera || !camera->getViewport()) - return std::make_pair("", Ogre::Vector3(0,0,0)); // FIXME: this should be an exception - - // using a really small value seems to mess up with the projections - float nearClipDistance = camera->getNearClipDistance(); // save existing - camera->setNearClipDistance(10.0f); // arbitrary number - Ogre::Ray ray = camera->getCameraToViewportRay(mouseX, mouseY); - camera->setNearClipDistance(nearClipDistance); // restore - - Ogre::Vector3 from = ray.getOrigin(); - CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); - float farClipDist = userSettings.setting("Scene/far clip distance", QString("300000")).toFloat(); - Ogre::Vector3 to = ray.getPoint(farClipDist); - - btVector3 _from, _to; - _from = btVector3(from.x, from.y, from.z); - _to = btVector3(to.x, to.y, to.z); - - uint32_t visibilityMask = camera->getViewport()->getVisibilityMask(); - bool ignoreHeightMap = !(visibilityMask & (uint32_t)CSVRender::Element_Terrain); - bool ignoreObjects = !(visibilityMask & (uint32_t)CSVRender::Element_Reference); - - Ogre::Vector3 norm; // not used - std::pair result = - mEngine->rayTest(_from, _to, !ignoreObjects, ignoreHeightMap, &norm); - - // result.first is the object's referenceId - if(result.first == "") - return std::make_pair("", Ogre::Vector3(0,0,0)); - else - { - std::string name = refIdToSceneNode(result.first, sceneMgr); - if(name == "") - name = result.first; - else - name = refIdToSceneNode(result.first, sceneMgr); - - return std::make_pair(name, ray.getPoint(farClipDist*result.second)); - } - } - - std::string PhysicsSystem::refIdToSceneNode(std::string referenceId, Ogre::SceneManager *sceneMgr) - { - return mRefIdToSceneNode[referenceId][sceneMgr]; - } - - std::string PhysicsSystem::sceneNodeToRefId(std::string sceneNodeName) - { - return mSceneNodeToRefId[sceneNodeName]; - } - - void PhysicsSystem::addSceneManager(Ogre::SceneManager *sceneMgr, CSVRender::SceneWidget *sceneWidget) - { - mSceneWidgets[sceneMgr] = sceneWidget; - - mEngine->createDebugDraw(sceneMgr); - } - - std::map PhysicsSystem::sceneWidgets() - { - return mSceneWidgets; - } - - void PhysicsSystem::removeSceneManager(Ogre::SceneManager *sceneMgr) - { - mEngine->removeDebugDraw(sceneMgr); - - mSceneWidgets.erase(sceneMgr); - } - - Ogre::SceneManager *PhysicsSystem::findSceneManager(std::string sceneNodeName) - { - std::map::const_iterator iter = mSceneWidgets.begin(); - for(; iter != mSceneWidgets.end(); ++iter) - { - if((*iter).first->hasSceneNode(sceneNodeName)) - { - return (*iter).first; - } - } - - return NULL; - } - - void PhysicsSystem::toggleDebugRendering(Ogre::SceneManager *sceneMgr) - { - // FIXME: should check if sceneMgr is in the list - if(!sceneMgr) - return; - - CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); - if(!(userSettings.setting("debug/mouse-picking", QString("false")) == "true" ? true : false)) - { - std::cerr << "Turn on mouse-picking debug option to see collision shapes." << std::endl; - return; - } - - mEngine->toggleDebugRendering(sceneMgr); - mEngine->stepDebug(sceneMgr); - } -} diff --git a/apps/opencs/view/world/physicssystem.hpp b/apps/opencs/view/world/physicssystem.hpp deleted file mode 100644 index 0036bf769..000000000 --- a/apps/opencs/view/world/physicssystem.hpp +++ /dev/null @@ -1,94 +0,0 @@ -#ifndef CSV_WORLD_PHYSICSSYSTEM_H -#define CSV_WORLD_PHYSICSSYSTEM_H - -#include -#include - -namespace Ogre -{ - class Vector3; - class Quaternion; - class SceneManager; - class Camera; -} - -namespace OEngine -{ - namespace Physic - { - class PhysicEngine; - } -} - -namespace CSVRender -{ - class SceneWidget; -} - -namespace CSVWorld -{ - class PhysicsSystem - { - std::map mSceneNodeToRefId; - std::map > mRefIdToSceneNode; - std::map mSceneNodeToMesh; - std::map mSceneWidgets; - OEngine::Physic::PhysicEngine* mEngine; - std::multimap mTerrain; - - public: - - PhysicsSystem(); - ~PhysicsSystem(); - - void addSceneManager(Ogre::SceneManager *sceneMgr, CSVRender::SceneWidget * scene); - - void removeSceneManager(Ogre::SceneManager *sceneMgr); - - void addObject(const std::string &mesh, - const std::string &sceneNodeName, const std::string &referenceId, float scale, - const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, - bool placeable=false); - - void removeObject(const std::string &sceneNodeName); - void removePhysicsObject(const std::string &sceneNodeName); - - void replaceObject(const std::string &sceneNodeName, - float scale, const Ogre::Vector3 &position, - const Ogre::Quaternion &rotation, bool placeable=false); - - void moveObject(const std::string &sceneNodeName, - const Ogre::Vector3 &position, const Ogre::Quaternion &rotation); - - void moveSceneNodes(const std::string sceneNodeName, const Ogre::Vector3 &position); - - void addHeightField(Ogre::SceneManager *sceneManager, - float* heights, int x, int y, float yoffset, float triSize, float sqrtVerts); - - void removeHeightField(Ogre::SceneManager *sceneManager, int x, int y); - - void toggleDebugRendering(Ogre::SceneManager *sceneMgr); - - // return the object's SceneNode name and position for the given SceneManager - std::pair castRay(float mouseX, - float mouseY, Ogre::SceneManager *sceneMgr, Ogre::Camera *camera); - - std::string sceneNodeToRefId(std::string sceneNodeName); - - // for multi-scene manager per physics engine - std::map sceneWidgets(); - - private: - - void moveSceneNodeImpl(const std::string sceneNodeName, - const std::string referenceId, const Ogre::Vector3 &position); - - void updateSelectionHighlight(std::string sceneNode, const Ogre::Vector3 &position); - - std::string refIdToSceneNode(std::string referenceId, Ogre::SceneManager *sceneMgr); - - Ogre::SceneManager *findSceneManager(std::string sceneNodeName); - }; -} - -#endif // CSV_WORLD_PHYSICSSYSTEM_H From 72400747f24722a2f05fb9015f23b40cf107da69 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 25 Mar 2015 23:35:10 +0100 Subject: [PATCH 0823/3725] OpenCS: preliminary port of cell rendering to OSG --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/world/data.cpp | 5 + apps/opencs/model/world/data.hpp | 7 + apps/opencs/model/world/resources.cpp | 2 - apps/opencs/model/world/resourcesmanager.cpp | 11 + apps/opencs/model/world/resourcesmanager.hpp | 5 + apps/opencs/view/render/cell.cpp | 26 +- apps/opencs/view/render/cell.hpp | 12 +- apps/opencs/view/render/object.cpp | 48 +-- apps/opencs/view/render/object.hpp | 5 +- .../view/render/pagedworldspacewidget.cpp | 175 +-------- .../view/render/pagedworldspacewidget.hpp | 7 - apps/opencs/view/render/previewwidget.cpp | 5 +- apps/opencs/view/render/scenewidget.cpp | 4 + apps/opencs/view/render/textoverlay.cpp | 359 ------------------ apps/opencs/view/render/textoverlay.hpp | 66 ---- .../view/render/unpagedworldspacewidget.cpp | 11 +- apps/opencs/view/render/worldspacewidget.cpp | 4 - 18 files changed, 98 insertions(+), 656 deletions(-) delete mode 100644 apps/opencs/view/render/textoverlay.cpp delete mode 100644 apps/opencs/view/render/textoverlay.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 4f6b2a875..4e360f6eb 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -81,7 +81,7 @@ opencs_units (view/render opencs_units_noqt (view/render navigation navigation1st navigationfree navigationorbit lighting lightingday lightingnight - lightingbright object cell terrainstorage textoverlay + lightingbright object cell terrainstorage ) opencs_hdrs_noqt (view/render diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 67f6822c7..07b18cc23 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -970,3 +970,8 @@ void CSMWorld::Data::rowsChanged (const QModelIndex& parent, int start, int end) { emit idListChanged(); } + +const VFS::Manager* CSMWorld::Data::getVFS() const +{ + return mResourcesManager.getVFS(); +} diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 02f7bc452..bb4c9a4a8 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -45,6 +45,11 @@ class QAbstractItemModel; +namespace VFS +{ + class Manager; +} + namespace ESM { class ESMReader; @@ -121,6 +126,8 @@ namespace CSMWorld virtual ~Data(); + const VFS::Manager* getVFS() const; + const IdCollection& getGlobals() const; IdCollection& getGlobals(); diff --git a/apps/opencs/model/world/resources.cpp b/apps/opencs/model/world/resources.cpp index 158793173..4dd480e77 100644 --- a/apps/opencs/model/world/resources.cpp +++ b/apps/opencs/model/world/resources.cpp @@ -5,8 +5,6 @@ #include #include -#include - #include #include diff --git a/apps/opencs/model/world/resourcesmanager.cpp b/apps/opencs/model/world/resourcesmanager.cpp index 218937924..3e2f72d93 100644 --- a/apps/opencs/model/world/resourcesmanager.cpp +++ b/apps/opencs/model/world/resourcesmanager.cpp @@ -3,6 +3,11 @@ #include +CSMWorld::ResourcesManager::ResourcesManager() + : mVFS(NULL) +{ +} + void CSMWorld::ResourcesManager::addResources (const Resources& resources) { mResources.insert (std::make_pair (resources.getType(), resources)); @@ -12,6 +17,7 @@ void CSMWorld::ResourcesManager::addResources (const Resources& resources) void CSMWorld::ResourcesManager::setVFS(const VFS::Manager *vfs) { + mVFS = vfs; mResources.clear(); static const char * const sMeshTypes[] = { "nif", 0 }; @@ -24,6 +30,11 @@ void CSMWorld::ResourcesManager::setVFS(const VFS::Manager *vfs) addResources (Resources (vfs, "videos", UniversalId::Type_Video)); } +const VFS::Manager* CSMWorld::ResourcesManager::getVFS() const +{ + return mVFS; +} + const CSMWorld::Resources& CSMWorld::ResourcesManager::get (UniversalId::Type type) const { std::map::const_iterator iter = mResources.find (type); diff --git a/apps/opencs/model/world/resourcesmanager.hpp b/apps/opencs/model/world/resourcesmanager.hpp index ee939389f..1ce06f2d3 100644 --- a/apps/opencs/model/world/resourcesmanager.hpp +++ b/apps/opencs/model/world/resourcesmanager.hpp @@ -16,6 +16,7 @@ namespace CSMWorld class ResourcesManager { std::map mResources; + const VFS::Manager* mVFS; private: @@ -23,6 +24,10 @@ namespace CSMWorld public: + ResourcesManager(); + + const VFS::Manager* getVFS() const; + void setVFS(const VFS::Manager* vfs); const Resources& get (UniversalId::Type type) const; diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index 28ce1dd6c..2c540dee6 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -1,8 +1,7 @@ #include "cell.hpp" -#include -#include +#include #include #include @@ -50,7 +49,7 @@ bool CSVRender::Cell::addObjects (int start, int end) std::string id = Misc::StringUtils::lowerCase (references.data ( references.index (i, idColumn)).toString().toUtf8().constData()); - //mObjects.insert (std::make_pair (id, new Object (mData, mCellNode, id, false, mPhysics))); + mObjects.insert (std::make_pair (id, new Object (mData, mCellNode, id, false))); modified = true; } } @@ -58,12 +57,11 @@ bool CSVRender::Cell::addObjects (int start, int end) return modified; } -CSVRender::Cell::Cell (CSMWorld::Data& data, Ogre::SceneManager *sceneManager, - const std::string& id, const Ogre::Vector3& origin) -: mData (data), mId (Misc::StringUtils::lowerCase (id)), mSceneMgr(sceneManager), mX(0), mY(0) +CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::string& id) +: mData (data), mId (Misc::StringUtils::lowerCase (id)), mX(0), mY(0) { - mCellNode = sceneManager->getRootSceneNode()->createChildSceneNode(); - mCellNode->setPosition (origin); + mCellNode = new osg::Group; + rootNode->addChild(mCellNode); CSMWorld::IdTable& references = dynamic_cast ( *mData.getTableModel (CSMWorld::UniversalId::Type_References)); @@ -72,6 +70,7 @@ CSVRender::Cell::Cell (CSMWorld::Data& data, Ogre::SceneManager *sceneManager, addObjects (0, rows-1); + /* const CSMWorld::IdCollection& land = mData.getLand(); int landIndex = land.searchId(mId); if (landIndex != -1) @@ -84,14 +83,15 @@ CSVRender::Cell::Cell (CSMWorld::Data& data, Ogre::SceneManager *sceneManager, mTerrain->loadCell(esmLand->mX, esmLand->mY); - float verts = ESM::Land::LAND_SIZE; - float worldsize = ESM::Land::REAL_SIZE; + //float verts = ESM::Land::LAND_SIZE; + //float worldsize = ESM::Land::REAL_SIZE; mX = esmLand->mX; mY = esmLand->mY; //mPhysics->addHeightField(sceneManager, // esmLand->mLandData->mHeights, mX, mY, 0, worldsize / (verts-1), verts); } } + */ } CSVRender::Cell::~Cell() @@ -103,7 +103,7 @@ CSVRender::Cell::~Cell() iter!=mObjects.end(); ++iter) delete iter->second; - mCellNode->getCreator()->destroySceneNode (mCellNode); + mCellNode->getParent(0)->removeChild(mCellNode); } bool CSVRender::Cell::referenceableDataChanged (const QModelIndex& topLeft, @@ -190,8 +190,8 @@ bool CSVRender::Cell::referenceDataChanged (const QModelIndex& topLeft, // add new objects for (std::map::iterator iter (ids.begin()); iter!=ids.end(); ++iter) { - //mObjects.insert (std::make_pair ( - // iter->first, new Object (mData, mCellNode, iter->first, false, mPhysics))); + mObjects.insert (std::make_pair ( + iter->first, new Object (mData, mCellNode, iter->first, false))); modified = true; } diff --git a/apps/opencs/view/render/cell.hpp b/apps/opencs/view/render/cell.hpp index 8c7d7e23a..259ab1779 100644 --- a/apps/opencs/view/render/cell.hpp +++ b/apps/opencs/view/render/cell.hpp @@ -7,7 +7,7 @@ #include -#include +#include #ifndef Q_MOC_RUN #include @@ -17,10 +17,9 @@ class QModelIndex; -namespace Ogre +namespace osg { - class SceneManager; - class SceneNode; + class Group; } namespace CSMWorld @@ -34,10 +33,9 @@ namespace CSVRender { CSMWorld::Data& mData; std::string mId; - Ogre::SceneNode *mCellNode; + osg::ref_ptr mCellNode; std::map mObjects; std::auto_ptr mTerrain; - Ogre::SceneManager *mSceneMgr; int mX; int mY; @@ -53,7 +51,7 @@ namespace CSVRender public: - Cell (CSMWorld::Data& data, Ogre::SceneManager *sceneManager, const std::string& id, const Ogre::Vector3& origin = Ogre::Vector3 (0, 0, 0)); + Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::string& id); ~Cell(); diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index 9bc7aa260..50c227d49 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -1,6 +1,9 @@ #include "object.hpp" +#include + #include +#include #include "../../model/world/data.hpp" #include "../../model/world/ref.hpp" @@ -51,14 +54,23 @@ void CSVRender::Object::update() } else { - NifOsg::Loader loader; - loader.resourceManager = mVFS; + try + { + NifOsg::Loader loader; + loader.resourceManager = mVFS; - std::string path = "meshes\\" + model; + std::string path = "meshes\\" + model; - Nif::NIFFilePtr file(new Nif::NIFFile(mVFS->get(path), path)); + Nif::NIFFilePtr file(new Nif::NIFFile(mVFS->get(path), path)); - mBaseNode->addChild(loader.load(file)); + mBaseNode->removeChildren(0, mBaseNode->getNumChildren()); + mBaseNode->addChild(loader.load(file)); + } + catch (std::exception& e) + { + // TODO: use error marker mesh + std::cerr << e.what() << std::endl; + } //mObject->setVisibilityFlags (Element_Reference); } @@ -66,29 +78,21 @@ void CSVRender::Object::update() void CSVRender::Object::adjust() { - /* if (mReferenceId.empty()) return; const CSMWorld::CellRef& reference = getReference(); // position - if (!mForceBaseToZero) - mBase->setPosition (Ogre::Vector3 ( - reference.mPos.pos[0], reference.mPos.pos[1], reference.mPos.pos[2])); + mBaseNode->setPosition(mForceBaseToZero ? osg::Vec3() : osg::Vec3f(reference.mPos.pos[0], reference.mPos.pos[1], reference.mPos.pos[2])); // orientation - Ogre::Quaternion xr (Ogre::Radian (-reference.mPos.rot[0]), Ogre::Vector3::UNIT_X); - - Ogre::Quaternion yr (Ogre::Radian (-reference.mPos.rot[1]), Ogre::Vector3::UNIT_Y); - - Ogre::Quaternion zr (Ogre::Radian (-reference.mPos.rot[2]), Ogre::Vector3::UNIT_Z); - - mBase->setOrientation (xr*yr*zr); + osg::Quat xr (-reference.mPos.rot[0], osg::Vec3f(1,0,0)); + osg::Quat yr (-reference.mPos.rot[1], osg::Vec3f(0,1,0)); + osg::Quat zr (-reference.mPos.rot[2], osg::Vec3f(0,0,1)); + mBaseNode->setAttitude(zr*yr*xr); - // scale - mBase->setScale (reference.mScale, reference.mScale, reference.mScale); - */ + mBaseNode->setScale(osg::Vec3(reference.mScale, reference.mScale, reference.mScale)); } const CSMWorld::CellRef& CSVRender::Object::getReference() const @@ -99,11 +103,11 @@ const CSMWorld::CellRef& CSVRender::Object::getReference() const return mData.getReferences().getRecord (mReferenceId).get(); } -CSVRender::Object::Object (const VFS::Manager* vfs, const CSMWorld::Data& data, osg::Group* parentNode, +CSVRender::Object::Object (const CSMWorld::Data& data, osg::Group* parentNode, const std::string& id, bool referenceable, bool forceBaseToZero) -: mVFS(vfs), mData (data), mBaseNode(0), mParentNode(parentNode), mForceBaseToZero (forceBaseToZero) +: mVFS(data.getVFS()), mData (data), mBaseNode(0), mParentNode(parentNode), mForceBaseToZero (forceBaseToZero) { - mBaseNode = new osg::Group; + mBaseNode = new osg::PositionAttitudeTransform; parentNode->addChild(mBaseNode); if (referenceable) diff --git a/apps/opencs/view/render/object.hpp b/apps/opencs/view/render/object.hpp index 431867d6b..9efbcf5dc 100644 --- a/apps/opencs/view/render/object.hpp +++ b/apps/opencs/view/render/object.hpp @@ -10,6 +10,7 @@ class QModelIndex; namespace osg { + class PositionAttitudeTransform; class Group; } @@ -36,7 +37,7 @@ namespace CSVRender const CSMWorld::Data& mData; std::string mReferenceId; std::string mReferenceableId; - osg::ref_ptr mBaseNode; + osg::ref_ptr mBaseNode; osg::Group* mParentNode; const VFS::Manager* mVFS; bool mForceBaseToZero; @@ -61,7 +62,7 @@ namespace CSVRender public: - Object (const VFS::Manager* vfs, const CSMWorld::Data& data, osg::Group *cellNode, + Object (const CSMWorld::Data& data, osg::Group *cellNode, const std::string& id, bool referenceable, bool forceBaseToZero = false); /// \param forceBaseToZero If this is a reference ignore the coordinates and place diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index ca4678d49..737a64efa 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -5,16 +5,9 @@ #include -#include -#include -#include -#include -#include -#include -#include +#include #include -#include "textoverlay.hpp" #include "../../model/world/tablemimedata.hpp" #include "../../model/world/idtable.hpp" @@ -29,7 +22,6 @@ bool CSVRender::PagedWorldspaceWidget::adjustCells() { bool modified = false; - //bool setCamera = false; const CSMWorld::IdCollection& cells = mDocument.getData().getCells(); @@ -44,17 +36,6 @@ bool CSVRender::PagedWorldspaceWidget::adjustCells() if (!mSelection.has (iter->first) || index==-1 || cells.getRecord (index).mState==CSMWorld::RecordBase::State_Deleted) { - // delete overlays - std::map::iterator itOverlay = mTextOverlays.find(iter->first); - if(itOverlay != mTextOverlays.end()) - { - delete itOverlay->second; - mTextOverlays.erase(itOverlay); - } - - // destroy manual objects - //getSceneManager()->destroyManualObject("manual"+iter->first.getId(mWorldspace)); - delete iter->second; mCells.erase (iter++); @@ -64,43 +45,16 @@ bool CSVRender::PagedWorldspaceWidget::adjustCells() { // check if name or region field has changed // FIXME: config setting - std::string name = cells.getRecord(index).get().mName; - std::string region = cells.getRecord(index).get().mRegion; - - std::map::iterator it = mTextOverlays.find(iter->first); - if(it != mTextOverlays.end()) - { - if(it->second->getDesc() != "") // previously had name - { - if(name != it->second->getDesc()) // new name - { - if(name != "") - it->second->setDesc(name); - else // name deleted, use region - it->second->setDesc(region); - it->second->update(); - } - } - else if(name != "") // name added - { - it->second->setDesc(name); - it->second->update(); - } - else if(region != it->second->getDesc()) // new region - { - it->second->setDesc(region); - it->second->update(); - } - modified = true; - } + //std::string name = cells.getRecord(index).get().mName; + //std::string region = cells.getRecord(index).get().mRegion; + + // cell marker update goes here + ++iter; } } } - //if (mCells.begin()==mCells.end()) - //setCamera = true; - // add for (CSMWorld::CellSelection::Iterator iter (mSelection.begin()); iter!=mSelection.end(); ++iter) @@ -110,111 +64,18 @@ bool CSVRender::PagedWorldspaceWidget::adjustCells() if (index > 0 && cells.getRecord (index).mState!=CSMWorld::RecordBase::State_Deleted && mCells.find (*iter)==mCells.end()) { -#if 0 - Cell *cell = new Cell (mDocument.getData(), getSceneManager(), + Cell *cell = new Cell (mDocument.getData(), mRootNode, iter->getId (mWorldspace)); mCells.insert (std::make_pair (*iter, cell)); - float height = cell->getTerrainHeightAt(Ogre::Vector3( - ESM::Land::REAL_SIZE * iter->getX() + ESM::Land::REAL_SIZE/2, - ESM::Land::REAL_SIZE * iter->getY() + ESM::Land::REAL_SIZE/2, - 0)); - if (setCamera) - { - setCamera = false; - getCamera()->setPosition ( - ESM::Land::REAL_SIZE * iter->getX() + ESM::Land::REAL_SIZE/2, - ESM::Land::REAL_SIZE * iter->getY() + ESM::Land::REAL_SIZE/2, - height); - // better camera position at the start - getCamera()->move(getCamera()->getDirection() * -6000); // FIXME: config setting - } - - Ogre::ManualObject* manual = - getSceneManager()->createManualObject("manual" + iter->getId(mWorldspace)); - manual->begin("BaseWhite", Ogre::RenderOperation::OT_LINE_LIST); - // define start and end point (x, y, z) - manual-> position(ESM::Land::REAL_SIZE * iter->getX() + ESM::Land::REAL_SIZE/2, - ESM::Land::REAL_SIZE * iter->getY() + ESM::Land::REAL_SIZE/2, - height); - manual-> position(ESM::Land::REAL_SIZE * iter->getX() + ESM::Land::REAL_SIZE/2, - ESM::Land::REAL_SIZE * iter->getY() + ESM::Land::REAL_SIZE/2, - height+200); // FIXME: config setting - manual->end(); - manual->setBoundingBox(Ogre::AxisAlignedBox( - ESM::Land::REAL_SIZE * iter->getX() + ESM::Land::REAL_SIZE/2, - ESM::Land::REAL_SIZE * iter->getY() + ESM::Land::REAL_SIZE/2, - height, - ESM::Land::REAL_SIZE * iter->getX() + ESM::Land::REAL_SIZE/2, - ESM::Land::REAL_SIZE * iter->getY() + ESM::Land::REAL_SIZE/2, - height+200)); - getSceneManager()->getRootSceneNode()->createChildSceneNode()->attachObject(manual); - manual->setVisible(false); - - CSVRender::TextOverlay *textDisp = - new CSVRender::TextOverlay(manual, getCamera(), iter->getId(mWorldspace)); - textDisp->enable(true); - textDisp->setCaption(iter->getId(mWorldspace)); - std::string desc = cells.getRecord(index).get().mName; - if(desc == "") desc = cells.getRecord(index).get().mRegion; - textDisp->setDesc(desc); // FIXME: config setting - textDisp->update(); - mTextOverlays.insert(std::make_pair(*iter, textDisp)); - /* - if(!mOverlayMask) - { - mOverlayMask = new OverlayMask(mTextOverlays, getViewport()); - addRenderTargetListener(mOverlayMask); - } - */ - -#endif - modified = true; } } - return modified; -} - -void CSVRender::PagedWorldspaceWidget::mousePressEvent (QMouseEvent *event) -{ - if(event->button() == Qt::RightButton) - { - std::map::iterator iter = mTextOverlays.begin(); - for(; iter != mTextOverlays.end(); ++iter) - { - if(mDisplayCellCoord && - iter->second->isEnabled() && iter->second->container().contains(event->x(), event->y())) - { - return; - } - } - } - WorldspaceWidget::mousePressEvent(event); -} - -void CSVRender::PagedWorldspaceWidget::mouseReleaseEvent (QMouseEvent *event) -{ - if(event->button() == Qt::RightButton) - { - std::map::iterator iter = mTextOverlays.begin(); - for(; iter != mTextOverlays.end(); ++iter) - { - if(mDisplayCellCoord && - iter->second->isEnabled() && iter->second->container().contains(event->x(), event->y())) - { - std::cout << "clicked: " << iter->second->getCaption() << std::endl; - return; - } - } - } - WorldspaceWidget::mouseReleaseEvent(event); -} + if (modified) + mView->setCameraManipulator(new osgGA::TrackballManipulator); -void CSVRender::PagedWorldspaceWidget::mouseDoubleClickEvent (QMouseEvent *event) -{ - WorldspaceWidget::mouseDoubleClickEvent(event); + return modified; } void CSVRender::PagedWorldspaceWidget::addVisibilitySelectorButtons ( @@ -344,25 +205,9 @@ CSVRender::PagedWorldspaceWidget::~PagedWorldspaceWidget() { for (std::map::iterator iter (mCells.begin()); iter!=mCells.end(); ++iter) - { - delete iter->second; - - //getSceneManager()->destroyManualObject("manual"+iter->first.getId(mWorldspace)); - } - - for (std::map::iterator iter (mTextOverlays.begin()); - iter != mTextOverlays.end(); ++iter) { delete iter->second; } - - /* - if(mOverlayMask) - { - removeRenderTargetListener(mOverlayMask); - delete mOverlayMask; - } - */ } void CSVRender::PagedWorldspaceWidget::useViewHint (const std::string& hint) diff --git a/apps/opencs/view/render/pagedworldspacewidget.hpp b/apps/opencs/view/render/pagedworldspacewidget.hpp index 1bc9c3c5c..64a0bccd1 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.hpp +++ b/apps/opencs/view/render/pagedworldspacewidget.hpp @@ -28,7 +28,6 @@ namespace CSVRender std::string mWorldspace; CSVWidget::SceneToolToggle *mControlElements; bool mDisplayCellCoord; - std::map mTextOverlays; private: @@ -86,12 +85,6 @@ namespace CSVRender virtual void addEditModeSelectorButtons (CSVWidget::SceneToolMode *tool); - virtual void mousePressEvent (QMouseEvent *event); - - virtual void mouseReleaseEvent (QMouseEvent *event); - - virtual void mouseDoubleClickEvent (QMouseEvent *event); - signals: void cellSelectionChanged (const CSMWorld::CellSelection& selection); diff --git a/apps/opencs/view/render/previewwidget.cpp b/apps/opencs/view/render/previewwidget.cpp index c3f838435..22185effc 100644 --- a/apps/opencs/view/render/previewwidget.cpp +++ b/apps/opencs/view/render/previewwidget.cpp @@ -1,9 +1,6 @@ #include "previewwidget.hpp" -#include -#include - #include #include "../../model/world/data.hpp" @@ -11,7 +8,7 @@ CSVRender::PreviewWidget::PreviewWidget (const VFS::Manager* vfs, CSMWorld::Data& data, const std::string& id, bool referenceable, QWidget *parent) -: SceneWidget (parent), mData (data), mObject(vfs, data, mRootNode, id, referenceable) +: SceneWidget (parent), mData (data), mObject(data, mRootNode, id, referenceable) { //setNavigation (&mOrbit); diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index 195e550a3..98ddf67c3 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -58,6 +58,10 @@ SceneWidget::SceneWidget(QWidget *parent, Qt::WindowFlags f) mView->getCamera()->setProjectionMatrixAsPerspective(30.0f, static_cast(traits->width)/static_cast(traits->height), 1.0f, 10000.0f ); mRootNode = new osg::Group; + // TODO: move to utility file + mRootNode->getOrCreateStateSet()->setMode(GL_NORMALIZE, osg::StateAttribute::ON); + mRootNode->getOrCreateStateSet()->setMode(GL_CULL_FACE, osg::StateAttribute::ON); + mView->setSceneData(mRootNode); // Press S to reveal profiling stats diff --git a/apps/opencs/view/render/textoverlay.cpp b/apps/opencs/view/render/textoverlay.cpp deleted file mode 100644 index 656ea959c..000000000 --- a/apps/opencs/view/render/textoverlay.cpp +++ /dev/null @@ -1,359 +0,0 @@ -#include "textoverlay.hpp" - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace CSVRender -{ - -// Things to do: -// - configurable font size in pixels (automatically calulate everything else from it) -// - configurable texture to use -// - try material script -// - decide whether to use QPaint (http://www.ogre3d.org/tikiwiki/Ogre+overlays+using+Qt) - -// http://www.ogre3d.org/tikiwiki/ObjectTextDisplay -// http://www.ogre3d.org/tikiwiki/MovableTextOverlay -// http://www.ogre3d.org/tikiwiki/Creating+dynamic+textures -// http://www.ogre3d.org/tikiwiki/ManualObject -TextOverlay::TextOverlay(const Ogre::MovableObject* obj, const Ogre::Camera* camera, const Ogre::String& id) - : mOverlay(0), mCaption(""), mDesc(""), mEnabled(true), mCamera(camera), mObj(obj), mId(id) - , mOnScreen(false) , mInstance(0), mFontHeight(16) // FIXME: make font height configurable -{ - if(id == "" || !camera || !obj) - throw std::runtime_error("TextOverlay could not be created."); - - // setup font - Ogre::FontManager &fontMgr = Ogre::FontManager::getSingleton(); - if (fontMgr.resourceExists("DejaVuLGC")) - mFont = fontMgr.getByName("DejaVuLGC","General"); - else - { - mFont = fontMgr.create("DejaVuLGC","General"); - mFont->setType(Ogre::FT_TRUETYPE); - mFont->setSource("DejaVuLGCSansMono.ttf"); - mFont->setTrueTypeSize(mFontHeight); - mFont->setTrueTypeResolution(96); - } - if(!mFont.isNull()) - mFont->load(); - else - throw std::runtime_error("TextOverlay font not loaded."); - - // setup overlay - Ogre::OverlayManager &overlayMgr = Ogre::OverlayManager::getSingleton(); - mOverlay = overlayMgr.getByName("CellIDPanel"+mId+Ogre::StringConverter::toString(mInstance)); - // FIXME: this logic is badly broken as it is possible to delete an earlier instance - while(mOverlay != NULL) - { - mInstance++; - mOverlay = overlayMgr.getByName("CellIDPanel"+mId+Ogre::StringConverter::toString(mInstance)); - } - mOverlay = overlayMgr.create("CellIDPanel"+mId+Ogre::StringConverter::toString(mInstance)); - - // create texture - Ogre::TexturePtr texture = Ogre::TextureManager::getSingleton().getByName("DynamicTransBlue"); - if(texture.isNull()) - { - texture = Ogre::TextureManager::getSingleton().createManual( - "DynamicTransBlue", // name - Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - Ogre::TEX_TYPE_2D, // type - 8, 8, // width & height - 0, // number of mipmaps - Ogre::PF_BYTE_BGRA, // pixel format - Ogre::TU_DEFAULT); // usage; should be TU_DYNAMIC_WRITE_ONLY_DISCARDABLE for - // textures updated very often (e.g. each frame) - - Ogre::HardwarePixelBufferSharedPtr pixelBuffer = texture->getBuffer(); - pixelBuffer->lock(Ogre::HardwareBuffer::HBL_NORMAL); - const Ogre::PixelBox& pixelBox = pixelBuffer->getCurrentLock(); - - Ogre::uint8* pDest = static_cast(pixelBox.data); - - // Fill in some pixel data. This will give a semi-transparent blue, - // but this is of course dependent on the chosen pixel format. - for (size_t j = 0; j < 8; j++) - { - for(size_t i = 0; i < 8; i++) - { - *pDest++ = 255; // B - *pDest++ = 0; // G - *pDest++ = 0; // R - *pDest++ = 63; // A - } - - pDest += pixelBox.getRowSkip() * Ogre::PixelUtil::getNumElemBytes(pixelBox.format); - } - pixelBuffer->unlock(); - } - - // setup material for containers - Ogre::MaterialPtr mQuadMaterial = Ogre::MaterialManager::getSingleton().getByName( - "TransOverlayMaterial"); - if(mQuadMaterial.isNull()) - { - Ogre::MaterialPtr mQuadMaterial = Ogre::MaterialManager::getSingleton().create( - "TransOverlayMaterial", - Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, true ); - Ogre::Pass *pass = mQuadMaterial->getTechnique( 0 )->getPass( 0 ); - pass->setLightingEnabled( false ); - pass->setDepthWriteEnabled( false ); - pass->setSceneBlending( Ogre::SBT_TRANSPARENT_ALPHA ); - - Ogre::TextureUnitState *tex = pass->createTextureUnitState("MyCustomState", 0); - tex->setTextureName("DynamicTransBlue"); - tex->setTextureFiltering( Ogre::TFO_ANISOTROPIC ); - mQuadMaterial->load(); - } - - mContainer = static_cast(overlayMgr.createOverlayElement( - "Panel", "container"+mId +"#"+Ogre::StringConverter::toString(mInstance))); - mContainer->setMaterialName("TransOverlayMaterial"); - mOverlay->add2D(mContainer); - - // setup text area overlay element - mElement = static_cast(overlayMgr.createOverlayElement( - "TextArea", "text"+mId +"#"+Ogre::StringConverter::toString(mInstance))); - mElement->setMetricsMode(Ogre::GMM_RELATIVE); - mElement->setDimensions(1.0, 1.0); - mElement->setMetricsMode(Ogre::GMM_PIXELS); - mElement->setPosition(2*fontHeight()/3, 1.3*fontHeight()/3); // 1.3 & 2 = fudge factor - - mElement->setFontName("DejaVuLGC"); - mElement->setCharHeight(fontHeight()); // NOTE: seems that this is required as well as font->setTrueTypeSize() - mElement->setHorizontalAlignment(Ogre::GHA_LEFT); - //mElement->setColour(Ogre::ColourValue(1.0, 1.0, 1.0)); // R, G, B - mElement->setColour(Ogre::ColourValue(1.0, 1.0, 0)); // yellow - - mContainer->addChild(mElement); - mOverlay->show(); -} - -void TextOverlay::getScreenCoordinates(const Ogre::Vector3& position, Ogre::Real& x, Ogre::Real& y) -{ - Ogre::Vector3 hcsPosition = mCamera->getProjectionMatrix() * (mCamera->getViewMatrix() * position); - - x = 1.0f - ((hcsPosition.x * 0.5f) + 0.5f); // 0 <= x <= 1 // left := 0,right := 1 - y = ((hcsPosition.y * 0.5f) + 0.5f); // 0 <= y <= 1 // bottom := 0,top := 1 -} - -void TextOverlay::getMinMaxEdgesOfAABBIn2D(float& MinX, float& MinY, float& MaxX, float& MaxY, - bool top) -{ - MinX = 0, MinY = 0, MaxX = 0, MaxY = 0; - float X[4]; // the 2D dots of the AABB in screencoordinates - float Y[4]; - - if(!mObj->isInScene()) - return; - - const Ogre::AxisAlignedBox &AABB = mObj->getWorldBoundingBox(true); // the AABB of the target - Ogre::Vector3 cornersOfAABB[4]; - if(top) - { - cornersOfAABB[0] = AABB.getCorner(Ogre::AxisAlignedBox::FAR_LEFT_TOP); - cornersOfAABB[1] = AABB.getCorner(Ogre::AxisAlignedBox::FAR_RIGHT_TOP); - cornersOfAABB[2] = AABB.getCorner(Ogre::AxisAlignedBox::NEAR_LEFT_TOP); - cornersOfAABB[3] = AABB.getCorner(Ogre::AxisAlignedBox::NEAR_RIGHT_TOP); - } - else - { - cornersOfAABB[0] = AABB.getCorner(Ogre::AxisAlignedBox::FAR_LEFT_BOTTOM); - cornersOfAABB[1] = AABB.getCorner(Ogre::AxisAlignedBox::FAR_RIGHT_BOTTOM); - cornersOfAABB[2] = AABB.getCorner(Ogre::AxisAlignedBox::NEAR_LEFT_BOTTOM); - cornersOfAABB[3] = AABB.getCorner(Ogre::AxisAlignedBox::NEAR_RIGHT_BOTTOM); - } - - //The normal vector of the plane. This points directly infront of the camera. - Ogre::Vector3 cameraPlainNormal = mCamera->getDerivedOrientation().zAxis(); - - //the plane that devides the space before and behind the camera. - Ogre::Plane CameraPlane = Ogre::Plane(cameraPlainNormal, mCamera->getDerivedPosition()); - - for (int i = 0; i < 4; i++) - { - X[i] = 0; - Y[i] = 0; - - getScreenCoordinates(cornersOfAABB[i],X[i],Y[i]); // transfor into 2d dots - - if (CameraPlane.getSide(cornersOfAABB[i]) == Ogre::Plane::NEGATIVE_SIDE) - { - if (i == 0) // accept the first set of values, no matter how bad it might be. - { - MinX = X[i]; - MinY = Y[i]; - MaxX = X[i]; - MaxY = Y[i]; - } - else // now compare if you get "better" values - { - if (MinX > X[i]) MinX = X[i]; - if (MinY > Y[i]) MinY = Y[i]; - if (MaxX < X[i]) MaxX = X[i]; - if (MaxY < Y[i]) MaxY = Y[i]; - } - } - else - { - MinX = 0; - MinY = 0; - MaxX = 0; - MaxY = 0; - break; - } - } -} - -TextOverlay::~TextOverlay() -{ - Ogre::OverlayManager::OverlayMapIterator iter = Ogre::OverlayManager::getSingleton().getOverlayIterator(); - if(!iter.hasMoreElements()) - mOverlay->hide(); - - Ogre::OverlayManager *overlayMgr = Ogre::OverlayManager::getSingletonPtr(); - mContainer->removeChild("text"+mId+"#"+Ogre::StringConverter::toString(mInstance)); - mOverlay->remove2D(mContainer); - - if(!iter.hasMoreElements()) - overlayMgr->destroy(mOverlay); -} - -void TextOverlay::show(bool show) -{ - if(show && mOnScreen) - mContainer->show(); - else - mContainer->hide(); -} - -void TextOverlay::enable(bool enable) -{ - if(enable == mOverlay->isVisible()) - return; - - mEnabled = enable; - if(enable) - mOverlay->show(); - else - mOverlay->hide(); -} - -bool TextOverlay::isEnabled() -{ - return mEnabled; -} - -void TextOverlay::setCaption(const Ogre::String& text) -{ - if(mCaption == text) - return; - - mCaption = text; - mElement->setCaption(text); -} - -void TextOverlay::setDesc(const Ogre::String& text) -{ - if(mDesc == text) - return; - - mDesc = text; - mElement->setCaption(mCaption + ((text == "") ? "" : ("\n" + text))); -} - -Ogre::FontPtr TextOverlay::getFont() -{ - return mFont; -} - -int TextOverlay::textWidth() -{ - float captionWidth = 0; - float descWidth = 0; - - for(Ogre::String::const_iterator i = mCaption.begin(); i < mCaption.end(); ++i) - { - if(*i == 0x0020) - captionWidth += getFont()->getGlyphAspectRatio(0x0030); - else - captionWidth += getFont()->getGlyphAspectRatio(*i); - } - - for(Ogre::String::const_iterator i = mDesc.begin(); i < mDesc.end(); ++i) - { - if(*i == 0x0020) - descWidth += getFont()->getGlyphAspectRatio(0x0030); - else - descWidth += getFont()->getGlyphAspectRatio(*i); - } - - captionWidth *= fontHeight(); - descWidth *= fontHeight(); - - return (int) std::max(captionWidth, descWidth); -} - -int TextOverlay::fontHeight() -{ - return mFontHeight; -} - -void TextOverlay::update() -{ - float min_x, max_x, min_y, max_y; - getMinMaxEdgesOfAABBIn2D(min_x, min_y, max_x, max_y, false); - - if ((min_x>0.0) && (max_x<1.0) && (min_y>0.0) && (max_y<1.0)) - { - mOnScreen = true; - mContainer->show(); - } - else - { - mOnScreen = false; - mContainer->hide(); - return; - } - - getMinMaxEdgesOfAABBIn2D(min_x, min_y, max_x, max_y); - - Ogre::OverlayManager &overlayMgr = Ogre::OverlayManager::getSingleton(); - float viewportWidth = std::max(overlayMgr.getViewportWidth(), 1); // zero at the start - float viewportHeight = std::max(overlayMgr.getViewportHeight(), 1); // zero at the start - - int width = fontHeight()*2/3 + textWidth() + fontHeight()*2/3; // add margins - int height = fontHeight()/3 + fontHeight() + fontHeight()/3; - if(mDesc != "") - height = fontHeight()/3 + 2*fontHeight() + fontHeight()/3; - - float relTextWidth = width / viewportWidth; - float relTextHeight = height / viewportHeight; - - float posX = 1 - (min_x + max_x + relTextWidth)/2; - float posY = 1 - max_y - (relTextHeight-fontHeight()/3/viewportHeight); - - mContainer->setMetricsMode(Ogre::GMM_RELATIVE); - mContainer->setPosition(posX, posY); - mContainer->setDimensions(relTextWidth, relTextHeight); - - mPos = QRect(posX*viewportWidth, posY*viewportHeight, width, height); -} - -QRect TextOverlay::container() -{ - return mPos; -} - -} diff --git a/apps/opencs/view/render/textoverlay.hpp b/apps/opencs/view/render/textoverlay.hpp deleted file mode 100644 index dbb347e56..000000000 --- a/apps/opencs/view/render/textoverlay.hpp +++ /dev/null @@ -1,66 +0,0 @@ -#ifndef OPENCS_VIEW_TEXTOVERLAY_H -#define OPENCS_VIEW_TEXTOVERLAY_H - -#include - -#include -#include - -namespace Ogre -{ - class MovableObject; - class Camera; - class Font; - class Overlay; - class OverlayContainer; - class TextAreaOverlayElement; -} - -namespace CSVRender -{ - - class TextOverlay - { - Ogre::Overlay* mOverlay; - Ogre::OverlayContainer* mContainer; - Ogre::TextAreaOverlayElement* mElement; - Ogre::String mCaption; - Ogre::String mDesc; - - const Ogre::MovableObject* mObj; - const Ogre::Camera* mCamera; - Ogre::FontPtr mFont; - int mFontHeight; // in pixels - Ogre::String mId; - QRect mPos; - - bool mEnabled; - bool mOnScreen; - int mInstance; - - Ogre::FontPtr getFont(); - int textWidth(); - int fontHeight(); - void getScreenCoordinates(const Ogre::Vector3& position, Ogre::Real& x, Ogre::Real& y); - void getMinMaxEdgesOfAABBIn2D(float& MinX, float& MinY, float& MaxX, float& MaxY, - bool top = true); - - public: - - TextOverlay(const Ogre::MovableObject* obj, const Ogre::Camera* camera, const Ogre::String &id); - virtual ~TextOverlay(); - - void enable(bool enable); // controlled from scene widget toolbar visibility mask - void show(bool show); // for updating from render target listener - bool isEnabled(); - void setCaption(const Ogre::String& text); - void setDesc(const Ogre::String& text); - void update(); - QRect container(); // for detection of mouse click on the overlay - Ogre::String getCaption() { return mCaption; } // FIXME: debug - Ogre::String getDesc() { return mDesc; } - }; - -} - -#endif // OPENCS_VIEW_TEXTOVERLAY_H diff --git a/apps/opencs/view/render/unpagedworldspacewidget.cpp b/apps/opencs/view/render/unpagedworldspacewidget.cpp index fd63567c7..46c010fd2 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.cpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.cpp @@ -3,8 +3,7 @@ #include -#include -#include +#include #include @@ -49,7 +48,10 @@ CSVRender::UnpagedWorldspaceWidget::UnpagedWorldspaceWidget (const std::string& update(); - //mCell.reset (new Cell (document.getData(), getSceneManager(), mCellId)); + mCell.reset (new Cell (document.getData(), mRootNode, mCellId)); + + mView->setCameraManipulator(new osgGA::TrackballManipulator); + //mView->setCameraManipulator(new osgGA::FirstPersonManipulator); } void CSVRender::UnpagedWorldspaceWidget::cellDataChanged (const QModelIndex& topLeft, @@ -91,7 +93,8 @@ bool CSVRender::UnpagedWorldspaceWidget::handleDrop (const std::vectorgetId(); - //mCell.reset (new Cell (getDocument().getData(), getSceneManager(), mCellId)); + // FIXME: we shouldn't need to rebuild the whole cell + mCell.reset (new Cell (getDocument().getData(), mRootNode, mCellId)); update(); emit cellChanged(*data.begin()); diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 68a3acdb9..f5068bb47 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -3,10 +3,6 @@ #include -#include -#include -#include - #include #include "../../model/world/universalid.hpp" From 5fb8877746541e1ed79bbc259802515281cca3f3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 26 Mar 2015 00:11:23 +0100 Subject: [PATCH 0824/3725] Don't set the root node to dynamic --- apps/nifosgtest/test.cpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/apps/nifosgtest/test.cpp b/apps/nifosgtest/test.cpp index 0f2e43a56..dec038825 100644 --- a/apps/nifosgtest/test.cpp +++ b/apps/nifosgtest/test.cpp @@ -41,9 +41,17 @@ public: osg::PolygonMode* mode = new osg::PolygonMode; mode->setMode(osg::PolygonMode::FRONT_AND_BACK, mWireframe ? osg::PolygonMode::LINE : osg::PolygonMode::FILL); - mNode->getOrCreateStateSet()->setAttributeAndModes(mode, osg::StateAttribute::ON); - mNode->getOrCreateStateSet()->setMode(GL_CULL_FACE, mWireframe ? osg::StateAttribute::OFF - : osg::StateAttribute::ON); + + // Create a new stateset instead of changing the old one, this alleviates the need to set + // the StateSet to DYNAMIC DataVariance, which would have a performance impact. + + osg::StateSet* stateset = new osg::StateSet; + stateset->setAttributeAndModes(mode, osg::StateAttribute::ON); + stateset->setMode(GL_CULL_FACE, mWireframe ? osg::StateAttribute::OFF + : osg::StateAttribute::ON); + + mNode->setStateSet(stateset); + return true; } default: @@ -138,10 +146,6 @@ int main(int argc, char** argv) // Mask to separate cull visitors from update visitors viewer.getCamera()->setCullMask(~(0x1)); - // We're going to change this from the event callback, set the variance to DYNAMIC so that - // we don't interfere with the draw thread. - root->getOrCreateStateSet()->setDataVariance(osg::Node::DYNAMIC); - viewer.addEventHandler(new osgViewer::StatsHandler); while (!viewer.done()) From 1edccdbe5573e1049c1ca8409d550d17bf180bc9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 26 Mar 2015 00:27:39 +0100 Subject: [PATCH 0825/3725] OpenCS: apply visibility flags to osg node --- apps/opencs/view/render/object.cpp | 5 +++-- apps/opencs/view/render/scenewidget.cpp | 6 ++++++ apps/opencs/view/render/scenewidget.hpp | 2 ++ apps/opencs/view/render/worldspacewidget.cpp | 2 +- 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index 50c227d49..f8e91e463 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -71,8 +71,6 @@ void CSVRender::Object::update() // TODO: use error marker mesh std::cerr << e.what() << std::endl; } - - //mObject->setVisibilityFlags (Element_Reference); } } @@ -110,6 +108,9 @@ CSVRender::Object::Object (const CSMWorld::Data& data, osg::Group* parentNode, mBaseNode = new osg::PositionAttitudeTransform; parentNode->addChild(mBaseNode); + // 0x1 reserved for separating cull and update visitors + mBaseNode->setNodeMask(Element_Reference<<1); + if (referenceable) { mReferenceableId = id; diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index 98ddf67c3..16ad2e68a 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -84,6 +84,12 @@ void SceneWidget::flagAsModified() mView->requestRedraw(); } +void SceneWidget::setVisibilityMask(int mask) +{ + // 0x1 reserved for separating cull and update visitors + mView->getCamera()->setCullMask(mask<<1); +} + CompositeViewer::CompositeViewer() { #if QT_VERSION >= 0x050000 diff --git a/apps/opencs/view/render/scenewidget.hpp b/apps/opencs/view/render/scenewidget.hpp index adb10b10a..04025340d 100644 --- a/apps/opencs/view/render/scenewidget.hpp +++ b/apps/opencs/view/render/scenewidget.hpp @@ -37,6 +37,8 @@ namespace CSVRender void flagAsModified(); + void setVisibilityMask(int mask); + protected: osg::ref_ptr mView; diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index f5068bb47..1026aab58 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -348,7 +348,7 @@ void CSVRender::WorldspaceWidget::debugProfileAboutToBeRemoved (const QModelInde void CSVRender::WorldspaceWidget::elementSelectionChanged() { - //setVisibilityMask (getVisibilityMask()); + setVisibilityMask (getVisibilityMask()); flagAsModified(); updateOverlay(); } From e3bfbcb44b7f09686f9365cd38cd9cdada9c2db5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 26 Mar 2015 00:55:58 +0100 Subject: [PATCH 0826/3725] OpenCS: connect navigation button to OSG camera manipulators --- .../view/render/pagedworldspacewidget.cpp | 8 ++------ apps/opencs/view/render/previewwidget.cpp | 4 +--- apps/opencs/view/render/previewwidget.hpp | 2 +- .../view/render/unpagedworldspacewidget.cpp | 7 ++----- apps/opencs/view/render/worldspacewidget.cpp | 18 ++++++++---------- apps/opencs/view/render/worldspacewidget.hpp | 3 --- apps/opencs/view/world/previewsubview.cpp | 4 ++-- 7 files changed, 16 insertions(+), 30 deletions(-) diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index 737a64efa..2b53483ad 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -171,19 +171,15 @@ void CSVRender::PagedWorldspaceWidget::referenceAdded (const QModelIndex& parent std::string CSVRender::PagedWorldspaceWidget::getStartupInstruction() { - /* - Ogre::Vector3 position = getCamera()->getPosition(); - + osg::Vec3d position = mView->getCamera()->getViewMatrix().getTrans(); std::ostringstream stream; stream << "player->position " - << position.x << ", " << position.y << ", " << position.z + << position.x() << ", " << position.y() << ", " << position.z() << ", 0"; return stream.str(); - */ - return ""; } CSVRender::PagedWorldspaceWidget::PagedWorldspaceWidget (QWidget* parent, CSMDoc::Document& document) diff --git a/apps/opencs/view/render/previewwidget.cpp b/apps/opencs/view/render/previewwidget.cpp index 22185effc..02fcd9f06 100644 --- a/apps/opencs/view/render/previewwidget.cpp +++ b/apps/opencs/view/render/previewwidget.cpp @@ -6,12 +6,10 @@ #include "../../model/world/data.hpp" #include "../../model/world/idtable.hpp" -CSVRender::PreviewWidget::PreviewWidget (const VFS::Manager* vfs, CSMWorld::Data& data, +CSVRender::PreviewWidget::PreviewWidget (CSMWorld::Data& data, const std::string& id, bool referenceable, QWidget *parent) : SceneWidget (parent), mData (data), mObject(data, mRootNode, id, referenceable) { - //setNavigation (&mOrbit); - mView->setCameraManipulator(new osgGA::TrackballManipulator); QAbstractItemModel *referenceables = diff --git a/apps/opencs/view/render/previewwidget.hpp b/apps/opencs/view/render/previewwidget.hpp index dfe05b484..58a7d8552 100644 --- a/apps/opencs/view/render/previewwidget.hpp +++ b/apps/opencs/view/render/previewwidget.hpp @@ -30,7 +30,7 @@ namespace CSVRender public: - PreviewWidget (const VFS::Manager* vfs, CSMWorld::Data& data, const std::string& id, bool referenceable, + PreviewWidget (CSMWorld::Data& data, const std::string& id, bool referenceable, QWidget *parent = 0); signals: diff --git a/apps/opencs/view/render/unpagedworldspacewidget.cpp b/apps/opencs/view/render/unpagedworldspacewidget.cpp index 46c010fd2..e48b84cff 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.cpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.cpp @@ -166,19 +166,16 @@ void CSVRender::UnpagedWorldspaceWidget::addVisibilitySelectorButtons ( std::string CSVRender::UnpagedWorldspaceWidget::getStartupInstruction() { - /* - Ogre::Vector3 position = getCamera()->getPosition(); + osg::Vec3d position = mView->getCamera()->getViewMatrix().getTrans(); std::ostringstream stream; stream << "player->positionCell " - << position.x << ", " << position.y << ", " << position.z + << position.x() << ", " << position.y() << ", " << position.z() << ", 0, \"" << mCellId << "\""; return stream.str(); - */ - return ""; } CSVRender::WorldspaceWidget::dropRequirments CSVRender::UnpagedWorldspaceWidget::getDropRequirements (CSVRender::WorldspaceWidget::DropType type) const diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 1026aab58..4bbfd5bcd 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -5,6 +5,9 @@ #include +#include +#include + #include "../../model/world/universalid.hpp" #include "../../model/world/idtable.hpp" @@ -16,7 +19,7 @@ #include "editmode.hpp" CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidget* parent) -: SceneWidget (parent), mDocument(document), mSceneElements(0), mRun(0), mMouse(0), +: SceneWidget (parent), mDocument(document), mSceneElements(0), mRun(0), mInteractionMask (0) { setAcceptDrops(true); @@ -48,32 +51,27 @@ CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidg this, SLOT (debugProfileDataChanged (const QModelIndex&, const QModelIndex&))); connect (debugProfiles, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)), this, SLOT (debugProfileAboutToBeRemoved (const QModelIndex&, int, int))); - - //mMouse = new MouseState(this); } CSVRender::WorldspaceWidget::~WorldspaceWidget () { - //delete mMouse; } void CSVRender::WorldspaceWidget::selectNavigationMode (const std::string& mode) { - /* if (mode=="1st") - setNavigation (&m1st); + mView->setCameraManipulator(new osgGA::FirstPersonManipulator); else if (mode=="free") - setNavigation (&mFree); + mView->setCameraManipulator(new osgGA::FirstPersonManipulator); else if (mode=="orbit") - setNavigation (&mOrbit); - */ + mView->setCameraManipulator(new osgGA::OrbitManipulator); } void CSVRender::WorldspaceWidget::useViewHint (const std::string& hint) {} void CSVRender::WorldspaceWidget::selectDefaultNavigationMode() { - //setNavigation (&m1st); + mView->setCameraManipulator(new osgGA::FirstPersonManipulator); } CSVWidget::SceneToolMode *CSVRender::WorldspaceWidget::makeNavigationSelector ( diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp index ea344f04a..e935daae2 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -26,8 +26,6 @@ namespace CSVWidget namespace CSVRender { - class MouseState; - class WorldspaceWidget : public SceneWidget { Q_OBJECT @@ -38,7 +36,6 @@ namespace CSVRender CSVWidget::SceneToolToggle2 *mSceneElements; CSVWidget::SceneToolRun *mRun; CSMDoc::Document& mDocument; - MouseState *mMouse; unsigned int mInteractionMask; public: diff --git a/apps/opencs/view/world/previewsubview.cpp b/apps/opencs/view/world/previewsubview.cpp index c82d1b82e..0c9823c44 100644 --- a/apps/opencs/view/world/previewsubview.cpp +++ b/apps/opencs/view/world/previewsubview.cpp @@ -23,10 +23,10 @@ CSVWorld::PreviewSubView::PreviewSubView (const CSMWorld::UniversalId& id, CSMDo referenceableIdChanged (referenceableId); mScene = - new CSVRender::PreviewWidget (document.getVFS(), document.getData(), id.getId(), false, this); + new CSVRender::PreviewWidget (document.getData(), id.getId(), false, this); } else - mScene = new CSVRender::PreviewWidget (document.getVFS(), document.getData(), id.getId(), true, this); + mScene = new CSVRender::PreviewWidget (document.getData(), id.getId(), true, this); CSVWidget::SceneToolbar *toolbar = new CSVWidget::SceneToolbar (48+6, this); From 99c9907ff397f0901b45b955f4e46a77b4b65867 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 26 Mar 2015 17:38:17 +0100 Subject: [PATCH 0827/3725] Fix emitter/particlesystem scene graph order problems --- components/nifosg/nifloader.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index bdd40e245..df912728b 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -468,6 +468,7 @@ namespace NifOsg nif->fail("First root was not a node, but a " + r->recName); osg::ref_ptr skel = new osgAnimation::Skeleton; + skel->setDefaultUpdateCallback(); // validates the skeleton hierarchy skel->addChild(handleNode(nifNode, true, std::map(), 0, 0, false, textKeys)); return skel; @@ -609,8 +610,7 @@ namespace NifOsg { if(!children[i].empty()) { - // Insert bones at position 0 to prevent update order problems (see comment in osg Skeleton.cpp) - transformNode->insertChild(0, + transformNode->addChild( handleNode(children[i].getPtr(), createSkeleton, boundTextures, animflags, particleflags, skipMeshes, textKeys, rootNode)); } } @@ -1077,11 +1077,18 @@ namespace NifOsg osg::ref_ptr geometry (new osg::Geometry); triShapeToGeometry(triShape, geometry, geode, boundTextures, animflags); + // Note the RigGeometry's UpdateCallback uses the skeleton space bone matrix, so the bone UpdateCallback has to be fired first. + // For this to work properly, all bones used for skinning a RigGeometry need to be created before that RigGeometry. + // All NIFs I've checked seem to conform to this restriction, perhaps Gamebryo update method works similarly. + // If a file violates this assumption, the worst that could happen is the bone position being a frame late. + // If this happens, we should get a warning from the Skeleton's validation update callback on the error log. osg::ref_ptr rig(new osgAnimation::RigGeometry); rig->setSourceGeometry(geometry); + // Slightly expand the bounding box to account for movement of the bones // For more accuracy the skinning should be relative to the parent of the first skinned bone, // rather than the root bone. + // TODO: calculate a correct bounding box based on the bone positions every frame in a ComputeBoundingBoxCallback osg::BoundingBox box = geometry->getBound(); box.expandBy(box._min-(box._max-box._min)/2); box.expandBy(box._max+(box._max-box._min)/2); From 60f288195fcbe2214f548aecb152c252b03cebf9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 26 Mar 2015 17:39:33 +0100 Subject: [PATCH 0828/3725] Fix for copy construction of particle system templates --- components/nifosg/particle.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/components/nifosg/particle.cpp b/components/nifosg/particle.cpp index 0afbf5e95..791847cd6 100644 --- a/components/nifosg/particle.cpp +++ b/components/nifosg/particle.cpp @@ -23,6 +23,9 @@ ParticleSystem::ParticleSystem(const ParticleSystem ©, const osg::CopyOp &co : osgParticle::ParticleSystem(copy, copyop) , mQuota(copy.mQuota) { + // For some reason the osgParticle constructor doesn't copy the particles + for (int i=0;i Date: Thu, 26 Mar 2015 18:02:51 +0100 Subject: [PATCH 0829/3725] Add SceneManager and clone utility --- apps/opencs/model/world/data.cpp | 7 ++- apps/opencs/model/world/data.hpp | 6 ++ apps/opencs/view/render/object.cpp | 15 +++-- apps/opencs/view/render/object.hpp | 8 +-- components/CMakeLists.txt | 8 +++ components/resource/resourcesystem.cpp | 24 ++++++++ components/resource/resourcesystem.hpp | 34 +++++++++++ components/resource/scenemanager.cpp | 49 +++++++++++++++ components/resource/scenemanager.hpp | 40 ++++++++++++ components/sceneutil/clone.cpp | 85 ++++++++++++++++++++++++++ components/sceneutil/clone.hpp | 45 ++++++++++++++ components/vfs/manager.cpp | 14 ++++- components/vfs/manager.hpp | 7 +++ 13 files changed, 327 insertions(+), 15 deletions(-) create mode 100644 components/resource/resourcesystem.cpp create mode 100644 components/resource/resourcesystem.hpp create mode 100644 components/resource/scenemanager.cpp create mode 100644 components/resource/scenemanager.hpp create mode 100644 components/sceneutil/clone.cpp create mode 100644 components/sceneutil/clone.hpp diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 07b18cc23..77724c997 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -60,7 +60,7 @@ int CSMWorld::Data::count (RecordBase::State state, const CollectionBase& collec CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourcesManager) : mEncoder (encoding), mPathgrids (mCells), mRefs (mCells), - mResourcesManager (resourcesManager), mReader (0), mDialogue (0), mReaderIndex(0) + mResourcesManager (resourcesManager), mReader (0), mDialogue (0), mReaderIndex(0), mResourceSystem(resourcesManager.getVFS()) { mGlobals.addColumn (new StringIdColumn); mGlobals.addColumn (new RecordStateColumn); @@ -354,6 +354,11 @@ CSMWorld::Data::~Data() delete mReader; } +Resource::ResourceSystem* CSMWorld::Data::getResourceSystem() +{ + return &mResourceSystem; +} + const CSMWorld::IdCollection& CSMWorld::Data::getGlobals() const { return mGlobals; diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index bb4c9a4a8..ce8776104 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -28,6 +28,8 @@ #include #include +#include + #include #include "../doc/stage.hpp" @@ -105,6 +107,8 @@ namespace CSMWorld std::map > mRefLoadCache; int mReaderIndex; + Resource::ResourceSystem mResourceSystem; + std::vector > mReaders; // not implemented @@ -128,6 +132,8 @@ namespace CSMWorld const VFS::Manager* getVFS() const; + Resource::ResourceSystem* getResourceSystem(); + const IdCollection& getGlobals() const; IdCollection& getGlobals(); diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index f8e91e463..afed837f8 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -9,10 +9,12 @@ #include "../../model/world/ref.hpp" #include "../../model/world/refidcollection.hpp" -#include +#include +#include #include "elements.hpp" + void CSVRender::Object::clear() { } @@ -56,15 +58,12 @@ void CSVRender::Object::update() { try { - NifOsg::Loader loader; - loader.resourceManager = mVFS; - std::string path = "meshes\\" + model; - Nif::NIFFilePtr file(new Nif::NIFFile(mVFS->get(path), path)); + osg::ref_ptr loaded = mResourceSystem->getSceneManager()->getInstance(path); mBaseNode->removeChildren(0, mBaseNode->getNumChildren()); - mBaseNode->addChild(loader.load(file)); + mBaseNode->addChild(loaded); } catch (std::exception& e) { @@ -101,9 +100,9 @@ const CSMWorld::CellRef& CSVRender::Object::getReference() const return mData.getReferences().getRecord (mReferenceId).get(); } -CSVRender::Object::Object (const CSMWorld::Data& data, osg::Group* parentNode, +CSVRender::Object::Object (CSMWorld::Data& data, osg::Group* parentNode, const std::string& id, bool referenceable, bool forceBaseToZero) -: mVFS(data.getVFS()), mData (data), mBaseNode(0), mParentNode(parentNode), mForceBaseToZero (forceBaseToZero) +: mResourceSystem(data.getResourceSystem()), mData (data), mBaseNode(0), mParentNode(parentNode), mForceBaseToZero (forceBaseToZero) { mBaseNode = new osg::PositionAttitudeTransform; parentNode->addChild(mBaseNode); diff --git a/apps/opencs/view/render/object.hpp b/apps/opencs/view/render/object.hpp index 9efbcf5dc..23a652792 100644 --- a/apps/opencs/view/render/object.hpp +++ b/apps/opencs/view/render/object.hpp @@ -14,9 +14,9 @@ namespace osg class Group; } -namespace VFS +namespace Resource { - class Manager; + class ResourceSystem; } namespace CSMWorld @@ -39,7 +39,7 @@ namespace CSVRender std::string mReferenceableId; osg::ref_ptr mBaseNode; osg::Group* mParentNode; - const VFS::Manager* mVFS; + Resource::ResourceSystem* mResourceSystem; bool mForceBaseToZero; /// Not implemented @@ -62,7 +62,7 @@ namespace CSVRender public: - Object (const CSMWorld::Data& data, osg::Group *cellNode, + Object (CSMWorld::Data& data, osg::Group *cellNode, const std::string& id, bool referenceable, bool forceBaseToZero = false); /// \param forceBaseToZero If this is a reference ignore the coordinates and place diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 48de580bc..70c9daa8b 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -38,6 +38,14 @@ add_component_dir (vfs manager archive bsaarchive filesystemarchive registerarchives ) +add_component_dir (resource + scenemanager resourcesystem + ) + +add_component_dir (sceneutil + clone + ) + add_component_dir (nif controlled effect niftypes record controller extra node record_ptr data niffile property nifkey data node base nifstream ) diff --git a/components/resource/resourcesystem.cpp b/components/resource/resourcesystem.cpp new file mode 100644 index 000000000..e87ef6f10 --- /dev/null +++ b/components/resource/resourcesystem.cpp @@ -0,0 +1,24 @@ +#include "resourcesystem.hpp" + +#include "scenemanager.hpp" + +namespace Resource +{ + + ResourceSystem::ResourceSystem(const VFS::Manager *vfs) + : mVFS(vfs) + { + mSceneManager.reset(new SceneManager(vfs)); + } + + SceneManager* ResourceSystem::getSceneManager() + { + return mSceneManager.get(); + } + + const VFS::Manager* ResourceSystem::getVFS() const + { + return mVFS; + } + +} diff --git a/components/resource/resourcesystem.hpp b/components/resource/resourcesystem.hpp new file mode 100644 index 000000000..b696a2376 --- /dev/null +++ b/components/resource/resourcesystem.hpp @@ -0,0 +1,34 @@ +#ifndef OPENMW_COMPONENTS_RESOURCE_RESOURCESYSTEM_H +#define OPENMW_COMPONENTS_RESOURCE_RESOURCESYSTEM_H + +#include + +namespace VFS +{ + class Manager; +} + +namespace Resource +{ + + class SceneManager; + + /// @brief Wrapper class that constructs and provides access to the various resource subsystems. + class ResourceSystem + { + public: + ResourceSystem(const VFS::Manager* vfs); + + SceneManager* getSceneManager(); + + const VFS::Manager* getVFS() const; + + private: + std::auto_ptr mSceneManager; + + const VFS::Manager* mVFS; + }; + +} + +#endif diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp new file mode 100644 index 000000000..b6a09f3a7 --- /dev/null +++ b/components/resource/scenemanager.cpp @@ -0,0 +1,49 @@ +#include "scenemanager.hpp" + +#include + +#include +#include + +#include + +namespace Resource +{ + + SceneManager::SceneManager(const VFS::Manager *vfs) + : mVFS(vfs) + { + } + + osg::ref_ptr SceneManager::getTemplate(const std::string &name) + { + std::string normalized = name; + mVFS->normalizeFilename(normalized); + + Index::iterator it = mIndex.find(normalized); + if (it == mIndex.end()) + { + Files::IStreamPtr file = mVFS->get(normalized); + + // TODO: add support for non-NIF formats + + NifOsg::Loader loader; + loader.resourceManager = mVFS; + osg::ref_ptr loaded = loader.load(Nif::NIFFilePtr(new Nif::NIFFile(file, normalized))); + + // TODO: provide way for the user to get textKeys (attach to the node?) + + mIndex[normalized] = loaded; + return loaded; + } + else + return it->second; + } + + osg::ref_ptr SceneManager::getInstance(const std::string &name) + { + osg::ref_ptr scene = getTemplate(name); + return osg::clone(scene.get(), SceneUtil::CopyOp()); + } + +} diff --git a/components/resource/scenemanager.hpp b/components/resource/scenemanager.hpp new file mode 100644 index 000000000..7922f3a49 --- /dev/null +++ b/components/resource/scenemanager.hpp @@ -0,0 +1,40 @@ +#ifndef OPENMW_COMPONENTS_RESOURCE_SCENEMANAGER_H +#define OPENMW_COMPONENTS_RESOURCE_SCENEMANAGER_H + +#include +#include + +#include +#include + +namespace VFS +{ + class Manager; +} + +namespace Resource +{ + + /// @brief Handles loading and caching of scenes, e.g. NIF files + class SceneManager + { + public: + SceneManager(const VFS::Manager* vfs); + + /// Get a read-only copy of this scene "template" + osg::ref_ptr getTemplate(const std::string& name); + + /// Create an instance of the given scene template + osg::ref_ptr getInstance(const std::string& name); + + private: + const VFS::Manager* mVFS; + + // observer_ptr? + typedef std::map > Index; + Index mIndex; + }; + +} + +#endif diff --git a/components/sceneutil/clone.cpp b/components/sceneutil/clone.cpp new file mode 100644 index 000000000..f124d7de7 --- /dev/null +++ b/components/sceneutil/clone.cpp @@ -0,0 +1,85 @@ +#include "clone.hpp" + +#include + +#include +#include +#include +#include +#include +#include + +namespace SceneUtil +{ + + CopyOp::CopyOp() + { + setCopyFlags(osg::CopyOp::DEEP_COPY_NODES + // Controller might need different inputs per scene instance + | osg::CopyOp::DEEP_COPY_CALLBACKS); + } + + osg::StateSet* CopyOp::operator ()(const osg::StateSet* stateset) const + { + if (!stateset) + return NULL; + if (stateset->getDataVariance() == osg::StateSet::DYNAMIC) + return osg::clone(stateset, osg::CopyOp::DEEP_COPY_STATESETS); + return const_cast(stateset); + } + + osg::Node* CopyOp::operator ()(const osg::Node* node) const + { + if (const osgParticle::ParticleProcessor* processor = dynamic_cast(node)) + return operator()(processor); + if (const osgParticle::ParticleSystemUpdater* updater = dynamic_cast(node)) + { + osgParticle::ParticleSystemUpdater* cloned = osg::clone(updater, osg::CopyOp::DEEP_COPY_NODES); + mMap2[cloned] = updater->getParticleSystem(0); + return cloned; + } + return osg::CopyOp::operator()(node); + } + + osg::Drawable* CopyOp::operator ()(const osg::Drawable* drawable) const + { + if (const osgParticle::ParticleSystem* partsys = dynamic_cast(drawable)) + return operator()(partsys); + if (dynamic_cast(drawable) + || dynamic_cast(drawable)) + return osg::clone(drawable, osg::CopyOp::DEEP_COPY_DRAWABLES); + + return osg::CopyOp::operator()(drawable); + } + + osgParticle::ParticleProcessor* CopyOp::operator() (const osgParticle::ParticleProcessor* processor) const + { + osgParticle::ParticleProcessor* cloned = osg::clone(processor, osg::CopyOp::DEEP_COPY_NODES); + mMap[cloned] = processor->getParticleSystem(); + return cloned; + } + + osgParticle::ParticleSystem* CopyOp::operator ()(const osgParticle::ParticleSystem* partsys) const + { + osgParticle::ParticleSystem* cloned = osg::clone(partsys, osg::CopyOp::DEEP_COPY_DRAWABLES); + + for (std::map::const_iterator it = mMap.begin(); it != mMap.end(); ++it) + { + if (it->second == partsys) + { + it->first->setParticleSystem(cloned); + } + } + for (std::map::const_iterator it = mMap2.begin(); it != mMap2.end(); ++it) + { + if (it->second == partsys) + { + osgParticle::ParticleSystemUpdater* updater = it->first; + updater->removeParticleSystem(updater->getParticleSystem(0)); + updater->addParticleSystem(cloned); + } + } + return cloned; + } + +} diff --git a/components/sceneutil/clone.hpp b/components/sceneutil/clone.hpp new file mode 100644 index 000000000..662dad543 --- /dev/null +++ b/components/sceneutil/clone.hpp @@ -0,0 +1,45 @@ +#ifndef OPENMW_COMPONENTS_SCENEUTIL_CLONE_H +#define OPENMW_COMPONENTS_SCENEUTIL_CLONE_H + +#include + +#include + +namespace osgParticle +{ + class ParticleProcessor; + class ParticleSystem; + class ParticleSystemUpdater; +} + +namespace SceneUtil +{ + + /// @par Defines the cloning behaviour we need: + /// * Assigns updated ParticleSystem pointers on cloned emitters and programs. + /// * Creates deep copy of StateSets if they have a DYNAMIC data variance. + /// * Deep copies RigGeometry and MorphGeometry so they can animate without affecting clones. + /// @warning Do not use an object of this class for more than one copy operation. + class CopyOp : public osg::CopyOp + { + public: + CopyOp(); + + virtual osgParticle::ParticleSystem* operator() (const osgParticle::ParticleSystem* partsys) const; + virtual osgParticle::ParticleProcessor* operator() (const osgParticle::ParticleProcessor* processor) const; + + virtual osg::Node* operator() (const osg::Node* node) const; + virtual osg::Drawable* operator() (const osg::Drawable* drawable) const; + + virtual osg::StateSet* operator() (const osg::StateSet* stateset) const; + + private: + // maps new ParticleProcessor to their old ParticleSystem pointer + // a little messy, but I think this should be the most efficient way + mutable std::map mMap; + mutable std::map mMap2; + }; + +} + +#endif diff --git a/components/vfs/manager.cpp b/components/vfs/manager.cpp index d0e0cf586..829e08978 100644 --- a/components/vfs/manager.cpp +++ b/components/vfs/manager.cpp @@ -59,9 +59,14 @@ namespace VFS std::string normalized = name; normalize_path(normalized, mStrict); - std::map::const_iterator found = mIndex.find(normalized); + return getNormalized(normalized); + } + + Files::IStreamPtr Manager::getNormalized(const std::string &normalizedName) const + { + std::map::const_iterator found = mIndex.find(normalizedName); if (found == mIndex.end()) - throw std::runtime_error("Resource '" + name + "' not found"); + throw std::runtime_error("Resource '" + normalizedName + "' not found"); return found->second->open(); } @@ -78,4 +83,9 @@ namespace VFS return mIndex; } + void Manager::normalizeFilename(std::string &name) const + { + normalize_path(name, mStrict); + } + } diff --git a/components/vfs/manager.hpp b/components/vfs/manager.hpp index ebbec7d15..f74914977 100644 --- a/components/vfs/manager.hpp +++ b/components/vfs/manager.hpp @@ -38,10 +38,17 @@ namespace VFS /// Get a complete list of files from all archives const std::map& getIndex() const; + /// Normalize the given filename, making slashes/backslashes consistent, and lower-casing if mStrict is false. + void normalizeFilename(std::string& name) const; + /// Retrieve a file by name. /// @note Throws an exception if the file can not be found. Files::IStreamPtr get(const std::string& name) const; + /// Retrieve a file by name (name is already normalized). + /// @note Throws an exception if the file can not be found. + Files::IStreamPtr getNormalized(const std::string& normalizedName) const; + private: bool mStrict; From c10c146ad1b49e4bec6f914fde82e59f8cda3563 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 26 Mar 2015 23:15:46 +0100 Subject: [PATCH 0830/3725] Skeleton based bounding box callback for RigGeometry (Bug #455) --- components/nif/data.cpp | 3 +- components/nif/data.hpp | 3 +- components/nifosg/nifloader.cpp | 166 +++++++++++++++++++++++++++++--- 3 files changed, 156 insertions(+), 16 deletions(-) diff --git a/components/nif/data.cpp b/components/nif/data.cpp index 1fef8d56f..4c9373029 100644 --- a/components/nif/data.cpp +++ b/components/nif/data.cpp @@ -200,7 +200,8 @@ void NiSkinData::read(NIFStream *nif) bi.trafo.rotation = nif->getMatrix3(); bi.trafo.pos = nif->getVector3(); bi.trafo.scale = nif->getFloat(); - bi.unknown = nif->getVector4(); + bi.boundSphereCenter = nif->getVector3(); + bi.boundSphereRadius = nif->getFloat(); // Number of vertex weights bi.weights.resize(nif->getUShort()); diff --git a/components/nif/data.hpp b/components/nif/data.hpp index 702fbf313..e3f1e2770 100644 --- a/components/nif/data.hpp +++ b/components/nif/data.hpp @@ -151,7 +151,8 @@ public: struct BoneInfo { Transformation trafo; - osg::Vec4f unknown; + osg::Vec3f boundSphereCenter; + float boundSphereRadius; std::vector weights; }; diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index df912728b..6e9de08f8 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -18,6 +18,7 @@ #include #include #include +#include // particle #include @@ -319,6 +320,144 @@ namespace int mSourceIndex; }; + // Node callback used to dirty a RigGeometry's bounding box every frame, so that RigBoundingBoxCallback updates. + // This has to be attached to the geode, because the RigGeometry's Drawable::UpdateCallback is already used internally and not extensible. + // Kind of awful, not sure of a better way to do this. + class DirtyBoundCallback : public osg::NodeCallback + { + public: + DirtyBoundCallback() + { + } + DirtyBoundCallback(const DirtyBoundCallback& copy, const osg::CopyOp& copyop) + : osg::NodeCallback(copy, copyop) + { + } + + void operator()(osg::Node* node, osg::NodeVisitor* nv) + { + osg::Geode* geode = node->asGeode(); + if (geode && geode->getNumDrawables()) + { + geode->getDrawable(0)->dirtyBound(); + } + traverse(node, nv); + } + }; + + class RigBoundingBoxCallback : public osg::Drawable::ComputeBoundingBoxCallback + { + public: + RigBoundingBoxCallback() + : mBoneMapInit(false) + { + } + RigBoundingBoxCallback(const RigBoundingBoxCallback& copy, const osg::CopyOp& copyop) + : osg::Drawable::ComputeBoundingBoxCallback(copy, copyop) + , mBoneMapInit(false) + , mBoundSpheres(copy.mBoundSpheres) + { + } + + META_Object(NifOsg, RigBoundingBoxCallback) + + void addBoundSphere(const std::string& bonename, const osg::BoundingSphere& sphere) + { + mBoundSpheres[bonename] = sphere; + } + + // based off code in osg::Transform + void transformBoundingSphere (const osg::Matrix& matrix, osg::BoundingSphere& bsphere) const + { + osg::BoundingSphere::vec_type xdash = bsphere._center; + xdash.x() += bsphere._radius; + xdash = xdash*matrix; + + osg::BoundingSphere::vec_type ydash = bsphere._center; + ydash.y() += bsphere._radius; + ydash = ydash*matrix; + + osg::BoundingSphere::vec_type zdash = bsphere._center; + zdash.z() += bsphere._radius; + zdash = zdash*matrix; + + bsphere._center = bsphere._center*matrix; + + xdash -= bsphere._center; + osg::BoundingSphere::value_type len_xdash = xdash.length(); + + ydash -= bsphere._center; + osg::BoundingSphere::value_type len_ydash = ydash.length(); + + zdash -= bsphere._center; + osg::BoundingSphere::value_type len_zdash = zdash.length(); + + bsphere._radius = len_xdash; + if (bsphere._radius(&drawable); + if (!rig) + { + std::cerr << "Warning: RigBoundingBoxCallback set on non-rig" << std::endl; + return box; + } + + if (!mBoneMapInit) + { + initBoneMap(rig); + } + + for (std::map::const_iterator it = mBoneMap.begin(); + it != mBoneMap.end(); ++it) + { + osgAnimation::Bone* bone = it->first; + osg::BoundingSphere bs = it->second; + transformBoundingSphere(bone->getMatrixInSkeletonSpace(), bs); + box.expandBy(bs); + } + + return box; + } + + void initBoneMap(const osgAnimation::RigGeometry* rig) const + { + if (!rig->getSkeleton()) + { + // may happen before the first frame update, but we're not animating yet, so no need for a bounding box + return; + } + + osgAnimation::BoneMapVisitor mapVisitor; + { + // const_cast necessary because there does not seem to be a const variant of NodeVisitor. + // Don't worry, we're not actually changing the skeleton. + osgAnimation::Skeleton* skel = const_cast(rig->getSkeleton()); + skel->accept(mapVisitor); + } + + for (osgAnimation::BoneMap::const_iterator it = mapVisitor.getBoneMap().begin(); it != mapVisitor.getBoneMap().end(); ++it) + { + std::map::const_iterator found = mBoundSpheres.find(it->first); + if (found != mBoundSpheres.end()) // not all bones have to be used for skinning + mBoneMap[it->second.get()] = found->second; + } + + mBoneMapInit = true; + } + + private: + mutable bool mBoneMapInit; + mutable std::map mBoneMap; + + std::map mBoundSpheres; + }; + void extractTextKeys(const Nif::NiTextKeyExtraData *tk, NifOsg::TextKeyMap &textkeys) { for(size_t i = 0;i < tk->list.size();i++) @@ -451,7 +590,7 @@ namespace NifOsg if (nifNode == NULL) nif->fail("First root was not a node, but a " + r->recName); - osg::ref_ptr created = handleNode(nifNode, false, std::map(), 0, 0, false, textKeys); + osg::ref_ptr created = handleNode(nifNode, NULL, false, std::map(), 0, 0, false, textKeys); return created; } @@ -469,7 +608,7 @@ namespace NifOsg osg::ref_ptr skel = new osgAnimation::Skeleton; skel->setDefaultUpdateCallback(); // validates the skeleton hierarchy - skel->addChild(handleNode(nifNode, true, std::map(), 0, 0, false, textKeys)); + handleNode(nifNode, skel, true, std::map(), 0, 0, false, textKeys); return skel; } @@ -494,7 +633,7 @@ namespace NifOsg toSetup->mFunction = boost::shared_ptr(new ControllerFunction(ctrl)); } - osg::ref_ptr handleNode(const Nif::Node* nifNode, bool createSkeleton, + osg::ref_ptr handleNode(const Nif::Node* nifNode, osg::Group* parentNode, bool createSkeleton, std::map boundTextures, int animflags, int particleflags, bool skipMeshes, TextKeyMap* textKeys, osg::Node* rootNode=NULL) { osg::ref_ptr transformNode; @@ -515,6 +654,9 @@ namespace NifOsg transformNode = new osg::MatrixTransform(toMatrix(nifNode->trafo)); } + if (parentNode) + parentNode->addChild(transformNode); + if (!rootNode) rootNode = transformNode; @@ -610,8 +752,7 @@ namespace NifOsg { if(!children[i].empty()) { - transformNode->addChild( - handleNode(children[i].getPtr(), createSkeleton, boundTextures, animflags, particleflags, skipMeshes, textKeys, rootNode)); + handleNode(children[i].getPtr(), transformNode, createSkeleton, boundTextures, animflags, particleflags, skipMeshes, textKeys, rootNode); } } } @@ -1085,17 +1226,11 @@ namespace NifOsg osg::ref_ptr rig(new osgAnimation::RigGeometry); rig->setSourceGeometry(geometry); - // Slightly expand the bounding box to account for movement of the bones - // For more accuracy the skinning should be relative to the parent of the first skinned bone, - // rather than the root bone. - // TODO: calculate a correct bounding box based on the bone positions every frame in a ComputeBoundingBoxCallback - osg::BoundingBox box = geometry->getBound(); - box.expandBy(box._min-(box._max-box._min)/2); - box.expandBy(box._max+(box._max-box._min)/2); - rig->setInitialBound(box); - const Nif::NiSkinInstance *skin = triShape->skin.getPtr(); + RigBoundingBoxCallback* callback = new RigBoundingBoxCallback; + rig->setComputeBoundingBoxCallback(callback); + // Assign bone weights osg::ref_ptr map (new osgAnimation::VertexInfluenceMap); @@ -1105,6 +1240,8 @@ namespace NifOsg { std::string boneName = bones[i].getPtr()->name; + callback->addBoundSphere(boneName, osg::BoundingSphere(data->bones[i].boundSphereCenter, data->bones[i].boundSphereRadius)); + osgAnimation::VertexInfluence influence; influence.setName(boneName); const std::vector &weights = data->bones[i].weights; @@ -1123,6 +1260,7 @@ namespace NifOsg trans->setUpdateCallback(new InvertBoneMatrix()); geode->addDrawable(rig); + geode->addUpdateCallback(new DirtyBoundCallback); trans->addChild(geode); parentNode->addChild(trans); From 23cf859fee045877d7a6cc64fea023939f9ab4f2 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 27 Mar 2015 16:33:54 +0100 Subject: [PATCH 0831/3725] added search stages (cell table only for now) --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/doc/document.cpp | 5 +++ apps/opencs/model/doc/document.hpp | 2 ++ apps/opencs/model/tools/searchoperation.cpp | 33 ++++++++++++++++++ apps/opencs/model/tools/searchoperation.hpp | 38 +++++++++++++++++++++ apps/opencs/model/tools/searchstage.cpp | 30 ++++++++++++++++ apps/opencs/model/tools/searchstage.hpp | 37 ++++++++++++++++++++ apps/opencs/model/tools/tools.cpp | 22 ++++++++++++ apps/opencs/model/tools/tools.hpp | 6 +++- apps/opencs/view/doc/operation.cpp | 1 + apps/opencs/view/doc/view.cpp | 2 +- apps/opencs/view/tools/searchsubview.cpp | 10 +++++- apps/opencs/view/tools/searchsubview.hpp | 3 ++ 13 files changed, 187 insertions(+), 4 deletions(-) create mode 100644 apps/opencs/model/tools/searchoperation.cpp create mode 100644 apps/opencs/model/tools/searchoperation.hpp create mode 100644 apps/opencs/model/tools/searchstage.cpp create mode 100644 apps/opencs/model/tools/searchstage.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index eb83b14d5..f27231c5a 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -40,7 +40,7 @@ opencs_units (model/tools opencs_units_noqt (model/tools mandatoryid skillcheck classcheck factioncheck racecheck soundcheck regioncheck birthsigncheck spellcheck referencecheck referenceablecheck scriptcheck bodypartcheck - startscriptcheck search + startscriptcheck search searchoperation searchstage ) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index a06eb0ebf..cb3b4ba18 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -2380,6 +2380,11 @@ CSMWorld::UniversalId CSMDoc::Document::newSearch() return mTools.newSearch(); } +void CSMDoc::Document::runSearch (const CSMWorld::UniversalId& searchId, const CSMTools::Search& search) +{ + return mTools.runSearch (searchId, search); +} + void CSMDoc::Document::abortOperation (int type) { if (type==State_Saving) diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp index 4300a9c64..6b1a1fc1e 100644 --- a/apps/opencs/model/doc/document.hpp +++ b/apps/opencs/model/doc/document.hpp @@ -121,6 +121,8 @@ namespace CSMDoc CSMWorld::UniversalId verify(); CSMWorld::UniversalId newSearch(); + + void runSearch (const CSMWorld::UniversalId& searchId, const CSMTools::Search& search); void abortOperation (int type); diff --git a/apps/opencs/model/tools/searchoperation.cpp b/apps/opencs/model/tools/searchoperation.cpp new file mode 100644 index 000000000..134b83b72 --- /dev/null +++ b/apps/opencs/model/tools/searchoperation.cpp @@ -0,0 +1,33 @@ + +#include "searchoperation.hpp" + +#include "../doc/state.hpp" +#include "../doc/document.hpp" + +#include "../world/data.hpp" +#include "../world/idtablebase.hpp" + +#include "searchstage.hpp" + +CSMTools::SearchOperation::SearchOperation (CSMDoc::Document& document) +: CSMDoc::Operation (CSMDoc::State_Searching, false) +{ +appendStage (new SearchStage (&dynamic_cast (*document.getData().getTableModel (CSMWorld::UniversalId::Type_Cells)))); + +} + +void CSMTools::SearchOperation::configure (const Search& search) +{ + mSearch = search; +} + +void CSMTools::SearchOperation::appendStage (SearchStage *stage) +{ + CSMDoc::Operation::appendStage (stage); + stage->setOperation (this); +} + +const CSMTools::Search& CSMTools::SearchOperation::getSearch() const +{ + return mSearch; +} diff --git a/apps/opencs/model/tools/searchoperation.hpp b/apps/opencs/model/tools/searchoperation.hpp new file mode 100644 index 000000000..fbbb38898 --- /dev/null +++ b/apps/opencs/model/tools/searchoperation.hpp @@ -0,0 +1,38 @@ +#ifndef CSM_TOOLS_SEARCHOPERATION_H +#define CSM_TOOLS_SEARCHOPERATION_H + +#include "../doc/operation.hpp" + +#include "search.hpp" + +namespace CSMDoc +{ + class Document; +} + +namespace CSMTools +{ + class SearchStage; + + class SearchOperation : public CSMDoc::Operation + { + Search mSearch; + + public: + + SearchOperation (CSMDoc::Document& document); + + /// \attention Do not call this function while a search is running. + void configure (const Search& search); + + void appendStage (SearchStage *stage); + ///< The ownership of \a stage is transferred to *this. + /// + /// \attention Do no call this function while this Operation is running. + + const Search& getSearch() const; + + }; +} + +#endif diff --git a/apps/opencs/model/tools/searchstage.cpp b/apps/opencs/model/tools/searchstage.cpp new file mode 100644 index 000000000..17859d930 --- /dev/null +++ b/apps/opencs/model/tools/searchstage.cpp @@ -0,0 +1,30 @@ + +#include "searchstage.hpp" + +#include "../world/idtablebase.hpp" + +#include "searchoperation.hpp" + +CSMTools::SearchStage::SearchStage (const CSMWorld::IdTableBase *model) +: mModel (model), mOperation (0) +{} + +int CSMTools::SearchStage::setup() +{ + if (mOperation) + mSearch = mOperation->getSearch(); + + mSearch.configure (mModel); + + return mModel->rowCount(); +} + +void CSMTools::SearchStage::perform (int stage, CSMDoc::Messages& messages) +{ + mSearch.searchRow (mModel, stage, messages); +} + +void CSMTools::SearchStage::setOperation (const SearchOperation *operation) +{ + mOperation = operation; +} diff --git a/apps/opencs/model/tools/searchstage.hpp b/apps/opencs/model/tools/searchstage.hpp new file mode 100644 index 000000000..073487c0d --- /dev/null +++ b/apps/opencs/model/tools/searchstage.hpp @@ -0,0 +1,37 @@ +#ifndef CSM_TOOLS_SEARCHSTAGE_H +#define CSM_TOOLS_SEARCHSTAGE_H + +#include "../doc/stage.hpp" + +#include "search.hpp" + +namespace CSMWorld +{ + class IdTableBase; +} + +namespace CSMTools +{ + class SearchOperation; + + class SearchStage : public CSMDoc::Stage + { + const CSMWorld::IdTableBase *mModel; + Search mSearch; + const SearchOperation *mOperation; + + public: + + SearchStage (const CSMWorld::IdTableBase *model); + + virtual int setup(); + ///< \return number of steps + + virtual void perform (int stage, CSMDoc::Messages& messages); + ///< Messages resulting from this stage will be appended to \a messages. + + void setOperation (const SearchOperation *operation); + }; +} + +#endif diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index 07bd4205b..957e20296 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -25,6 +25,7 @@ #include "bodypartcheck.hpp" #include "referencecheck.hpp" #include "startscriptcheck.hpp" +#include "searchoperation.hpp" CSMDoc::OperationHolder *CSMTools::Tools::get (int type) { @@ -108,6 +109,12 @@ CSMTools::Tools::Tools (CSMDoc::Document& document) // index 0: load error log mReports.insert (std::make_pair (mNextReportNumber++, new ReportModel)); mActiveReports.insert (std::make_pair (CSMDoc::State_Loading, 0)); + + connect (&mSearch, SIGNAL (progress (int, int, int)), this, SIGNAL (progress (int, int, int))); + connect (&mSearch, SIGNAL (done (int, bool)), this, SIGNAL (done (int, bool))); + connect (&mSearch, + SIGNAL (reportMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int)), + this, SLOT (verifierMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int))); } CSMTools::Tools::~Tools() @@ -145,6 +152,21 @@ CSMWorld::UniversalId CSMTools::Tools::newSearch() return CSMWorld::UniversalId (CSMWorld::UniversalId::Type_Search, mNextReportNumber-1); } +void CSMTools::Tools::runSearch (const CSMWorld::UniversalId& searchId, const Search& search) +{ + mActiveReports[CSMDoc::State_Searching] = searchId.getIndex(); + + if (!mSearchOperation) + { + mSearchOperation = new SearchOperation (mDocument); + mSearch.setOperation (mSearchOperation); + } + + mSearchOperation->configure (search); + + mSearch.start(); +} + void CSMTools::Tools::abortOperation (int type) { if (CSMDoc::OperationHolder *operation = get (type)) diff --git a/apps/opencs/model/tools/tools.hpp b/apps/opencs/model/tools/tools.hpp index bd27767a6..0f9e57044 100644 --- a/apps/opencs/model/tools/tools.hpp +++ b/apps/opencs/model/tools/tools.hpp @@ -22,6 +22,8 @@ namespace CSMDoc namespace CSMTools { class ReportModel; + class Search; + class SearchOperation; class Tools : public QObject { @@ -31,7 +33,7 @@ namespace CSMTools CSMWorld::Data& mData; CSMDoc::Operation *mVerifierOperation; CSMDoc::OperationHolder mVerifier; - CSMDoc::Operation *mSearchOperation; + SearchOperation *mSearchOperation; CSMDoc::OperationHolder mSearch; std::map mReports; int mNextReportNumber; @@ -60,6 +62,8 @@ namespace CSMTools /// Return ID of the report for this search. CSMWorld::UniversalId newSearch(); + + void runSearch (const CSMWorld::UniversalId& searchId, const Search& search); void abortOperation (int type); ///< \attention The operation is not aborted immediately. diff --git a/apps/opencs/view/doc/operation.cpp b/apps/opencs/view/doc/operation.cpp index 6977d7953..95cbf012d 100644 --- a/apps/opencs/view/doc/operation.cpp +++ b/apps/opencs/view/doc/operation.cpp @@ -18,6 +18,7 @@ void CSVDoc::Operation::updateLabel (int threads) { case CSMDoc::State_Saving: name = "saving"; break; case CSMDoc::State_Verifying: name = "verifying"; break; + case CSMDoc::State_Searching: name = "searching"; break; } std::ostringstream stream; diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 533cab049..e7eb28337 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -447,7 +447,7 @@ void CSVDoc::View::updateDocumentState() static const int operations[] = { - CSMDoc::State_Saving, CSMDoc::State_Verifying, + CSMDoc::State_Saving, CSMDoc::State_Verifying, CSMDoc::State_Searching, -1 // end marker }; diff --git a/apps/opencs/view/tools/searchsubview.cpp b/apps/opencs/view/tools/searchsubview.cpp index bc818df07..b4a0f893a 100644 --- a/apps/opencs/view/tools/searchsubview.cpp +++ b/apps/opencs/view/tools/searchsubview.cpp @@ -9,7 +9,7 @@ #include "searchbox.hpp" CSVTools::SearchSubView::SearchSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) -: CSVDoc::SubView (id) +: CSVDoc::SubView (id), mDocument (document) { QVBoxLayout *layout = new QVBoxLayout; @@ -32,6 +32,9 @@ CSVTools::SearchSubView::SearchSubView (const CSMWorld::UniversalId& id, CSMDoc: connect (&document, SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (stateChanged (int, CSMDoc::Document *))); + + connect (&mSearchBox, SIGNAL (startSearch (const CSMTools::Search&)), + this, SLOT (startSearch (const CSMTools::Search&))); } void CSVTools::SearchSubView::setEditLock (bool locked) @@ -48,3 +51,8 @@ void CSVTools::SearchSubView::stateChanged (int state, CSMDoc::Document *documen { mSearchBox.setSearchMode (!(state & CSMDoc::State_Searching)); } + +void CSVTools::SearchSubView::startSearch (const CSMTools::Search& search) +{ + mDocument.runSearch (getUniversalId(), search); +} diff --git a/apps/opencs/view/tools/searchsubview.hpp b/apps/opencs/view/tools/searchsubview.hpp index b389805bb..d17f7a340 100644 --- a/apps/opencs/view/tools/searchsubview.hpp +++ b/apps/opencs/view/tools/searchsubview.hpp @@ -23,6 +23,7 @@ namespace CSVTools ReportTable *mTable; SearchBox mSearchBox; + CSMDoc::Document& mDocument; public: @@ -35,6 +36,8 @@ namespace CSVTools private slots: void stateChanged (int state, CSMDoc::Document *document); + + void startSearch (const CSMTools::Search& search); }; } From e91d9d090365742bf916f4802b933f866dc5ce3a Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 27 Mar 2015 17:00:10 +0100 Subject: [PATCH 0832/3725] Fix for behaviour of scaled particle nodes Not sure if used in vanilla assets so may be low priority, but couldn't help looking into this. --- components/nifosg/nifloader.cpp | 2 ++ components/nifosg/particle.cpp | 22 ++++++++++------------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 6e9de08f8..1a36af4c4 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -993,6 +993,8 @@ namespace NifOsg { osg::ref_ptr partsys (new ParticleSystem); partsys->setSortMode(osgParticle::ParticleSystem::SORT_BACK_TO_FRONT); + // Scaling the particle node should also scale particles, even when the worldspace flag is enabled + partsys->setParticleScaleReferenceFrame(osgParticle::ParticleSystem::LOCAL_COORDINATES); const Nif::NiParticleSystemController* partctrl = NULL; for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next) diff --git a/components/nifosg/particle.cpp b/components/nifosg/particle.cpp index 791847cd6..afa76468a 100644 --- a/components/nifosg/particle.cpp +++ b/components/nifosg/particle.cpp @@ -49,8 +49,10 @@ void InverseWorldMatrix::operator()(osg::Node *node, osg::NodeVisitor *nv) osg::MatrixTransform* trans = dynamic_cast(node); - osg::Matrix worldMat = osg::computeLocalToWorld( path ); - trans->setMatrix(osg::Matrix::inverse(worldMat)); + osg::Matrix mat = osg::computeLocalToWorld( path ); + mat = osg::Matrix::inverse(mat); + mat.orthoNormalize(mat); // don't undo the scale + trans->setMatrix(mat); } traverse(node,nv); } @@ -174,7 +176,7 @@ void GravityAffector::beginOperate(osgParticle::Program* program) { bool absolute = (program->getReferenceFrame() == osgParticle::ParticleProcessor::ABSOLUTE_RF); if (mType == Type_Wind) - mCachedWorldPositionDirection = absolute ? program->rotateLocalToWorld(mDirection) : mDirection; + mCachedWorldPositionDirection = absolute ? osg::Matrix::transform3x3(program->getLocalToWorldMatrix(), mDirection) : mDirection; else // Type_Point mCachedWorldPositionDirection = absolute ? program->transformLocalToWorld(mPosition) : mPosition; } @@ -241,10 +243,10 @@ void Emitter::emitParticles(double dt) worldToPs = osg::Matrix::inverse(psToWorld); } + worldToPs.orthoNormalize(worldToPs); + const osg::Matrix& ltw = getLocalToWorldMatrix(); - const osg::Matrix& previous_ltw = getPreviousLocalToWorldMatrix(); const osg::Matrix emitterToPs = ltw * worldToPs; - const osg::Matrix prevEmitterToPs = previous_ltw * worldToPs; int n = mCounter->numParticlesToCreate(dt); @@ -275,15 +277,11 @@ void Emitter::emitParticles(double dt) { mPlacer->place(P); - P->transformPositionVelocity(transform); - mShooter->shoot(P); - // Now need to transform the position and velocity because we having a moving model. - // (is this actually how MW works?) - float r = ((float)rand()/(float)RAND_MAX); - P->transformPositionVelocity(emitterToPs, prevEmitterToPs, r); - //P->transformPositionVelocity(ltw); + P->transformPositionVelocity(transform); + + P->transformPositionVelocity(emitterToPs); } } } From 705ee67265ca1028bba2adb143e2219f0c6aab54 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 27 Mar 2015 18:55:48 +0100 Subject: [PATCH 0833/3725] fixed hints getting mixed up with message text --- apps/opencs/model/tools/search.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/tools/search.cpp b/apps/opencs/model/tools/search.cpp index 1b7be6fbf..f37425ea8 100644 --- a/apps/opencs/model/tools/search.cpp +++ b/apps/opencs/model/tools/search.cpp @@ -27,7 +27,7 @@ void CSMTools::Search::searchTextCell (const CSMWorld::IdTableBase *model, message << text.mid (pos).toUtf8().data(); std::ostringstream hint; - message << "r: " << index.column() << " " << pos << " " << search.length(); + hint << "r: " << index.column() << " " << pos << " " << search.length(); messages.add (id, message.str(), hint.str()); @@ -54,7 +54,7 @@ void CSMTools::Search::searchRegExCell (const CSMWorld::IdTableBase *model, int length = mRegExp.matchedLength(); std::ostringstream hint; - message << "r: " << index.column() << " " << pos << " " << length; + hint << "r: " << index.column() << " " << pos << " " << length; messages.add (id, message.str(), hint.str()); @@ -79,7 +79,7 @@ void CSMTools::Search::searchRecordStateCell (const CSMWorld::IdTableBase *model message << id.getId() << " " << states.at (data); std::ostringstream hint; - message << "r: " << index.column(); + hint << "r: " << index.column(); messages.add (id, message.str(), hint.str()); } From babefacbfac1a2411469620a518632ae9cf05a82 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 27 Mar 2015 19:10:45 +0100 Subject: [PATCH 0834/3725] improved message text in search results --- apps/opencs/model/tools/search.cpp | 19 ++++++++++++++++--- apps/opencs/model/tools/search.hpp | 2 ++ 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/tools/search.cpp b/apps/opencs/model/tools/search.cpp index f37425ea8..9e22f82dd 100644 --- a/apps/opencs/model/tools/search.cpp +++ b/apps/opencs/model/tools/search.cpp @@ -24,7 +24,7 @@ void CSMTools::Search::searchTextCell (const CSMWorld::IdTableBase *model, while ((pos = text.indexOf (search, pos, Qt::CaseInsensitive))!=-1) { std::ostringstream message; - message << text.mid (pos).toUtf8().data(); + message << getLocation (model, index, id) << text.mid (pos).toUtf8().data(); std::ostringstream hint; hint << "r: " << index.column() << " " << pos << " " << search.length(); @@ -49,7 +49,7 @@ void CSMTools::Search::searchRegExCell (const CSMWorld::IdTableBase *model, while ((pos = mRegExp.indexIn (text, pos))!=-1) { std::ostringstream message; - message << text.mid (pos).toUtf8().data(); + message << getLocation (model, index, id) << text.mid (pos).toUtf8().data(); int length = mRegExp.matchedLength(); @@ -76,7 +76,7 @@ void CSMTools::Search::searchRecordStateCell (const CSMWorld::IdTableBase *model CSMWorld::Columns::getEnums (CSMWorld::Columns::ColumnId_Modification); std::ostringstream message; - message << id.getId() << " " << states.at (data); + message << getLocation (model, index, id) << states.at (data); std::ostringstream hint; hint << "r: " << index.column(); @@ -85,6 +85,19 @@ void CSMTools::Search::searchRecordStateCell (const CSMWorld::IdTableBase *model } } +std::string CSMTools::Search::getLocation (const CSMWorld::IdTableBase *model, const QModelIndex& index, const CSMWorld::UniversalId& id) const +{ + std::ostringstream stream; + + stream + << id.getId() + << ", " + << model->headerData (index.column(), Qt::Horizontal).toString().toUtf8().data() + << ": "; + + return stream.str(); +} + CSMTools::Search::Search() : mType (Type_None) {} CSMTools::Search::Search (Type type, const std::string& value) diff --git a/apps/opencs/model/tools/search.hpp b/apps/opencs/model/tools/search.hpp index 3683f9c9b..7e95a2846 100644 --- a/apps/opencs/model/tools/search.hpp +++ b/apps/opencs/model/tools/search.hpp @@ -55,6 +55,8 @@ namespace CSMTools void searchRecordStateCell (const CSMWorld::IdTableBase *model, const QModelIndex& index, const CSMWorld::UniversalId& id, CSMDoc::Messages& messages) const; + + std::string getLocation (const CSMWorld::IdTableBase *model, const QModelIndex& index, const CSMWorld::UniversalId& id) const; public: From ac2612926ee61d2f5d4bcb3226cb783b567ecdc8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 27 Mar 2015 23:25:15 +0100 Subject: [PATCH 0835/3725] Disable unRefImageDataAfterApply --- components/nifosg/nifloader.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 1a36af4c4..3b68df562 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -1407,7 +1407,8 @@ namespace NifOsg osgDB::ReaderWriter::ReadResult result = reader->readImage(*mResourceManager->get(filename.c_str()), opts); osg::Image* image = result.getImage(); osg::Texture2D* texture2d = new osg::Texture2D; - texture2d->setUnRefImageDataAfterApply(true); + // Can be enabled for single-context, i.e. in openmw + //texture2d->setUnRefImageDataAfterApply(true); texture2d->setImage(image); unsigned int clamp = static_cast(tex.clamp); From 961aba5e2bd6aaa1dff0a765527512d3401b8093 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 28 Mar 2015 00:11:25 +0100 Subject: [PATCH 0836/3725] Revert part of e91d9d090365 --- components/nifosg/particle.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/nifosg/particle.cpp b/components/nifosg/particle.cpp index afa76468a..c6e5fa9a8 100644 --- a/components/nifosg/particle.cpp +++ b/components/nifosg/particle.cpp @@ -176,7 +176,7 @@ void GravityAffector::beginOperate(osgParticle::Program* program) { bool absolute = (program->getReferenceFrame() == osgParticle::ParticleProcessor::ABSOLUTE_RF); if (mType == Type_Wind) - mCachedWorldPositionDirection = absolute ? osg::Matrix::transform3x3(program->getLocalToWorldMatrix(), mDirection) : mDirection; + mCachedWorldPositionDirection = absolute ? program->rotateLocalToWorld(mDirection) : mDirection; else // Type_Point mCachedWorldPositionDirection = absolute ? program->transformLocalToWorld(mPosition) : mPosition; } From 322fcdc2d318a1c9c0325d2b7cb7dd5be2359ed3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 28 Mar 2015 00:30:49 +0100 Subject: [PATCH 0837/3725] Transform world space particles when attaching to a node --- apps/opencs/view/render/object.cpp | 47 ++++++++++++------- apps/opencs/view/render/object.hpp | 3 +- components/nifosg/nifloader.cpp | 25 +++++----- components/resource/scenemanager.cpp | 70 +++++++++++++++++++++++++++- components/resource/scenemanager.hpp | 11 ++++- 5 files changed, 123 insertions(+), 33 deletions(-) diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index afed837f8..ec184a563 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -5,6 +5,10 @@ #include #include +#include +#include +#include + #include "../../model/world/data.hpp" #include "../../model/world/ref.hpp" #include "../../model/world/refidcollection.hpp" @@ -14,6 +18,22 @@ #include "elements.hpp" +namespace +{ + + osg::ref_ptr createErrorCube() + { + osg::ref_ptr shape(new osg::Box(osg::Vec3f(0,0,0), 50.f)); + osg::ref_ptr shapedrawable(new osg::ShapeDrawable); + shapedrawable->setShape(shape); + + osg::ref_ptr geode (new osg::Geode); + geode->addDrawable(shapedrawable); + return geode; + } + +} + void CSVRender::Object::clear() { @@ -44,15 +64,11 @@ void CSVRender::Object::update() error = 2; } + mBaseNode->removeChildren(0, mBaseNode->getNumChildren()); + if (error) { - /* - Ogre::Entity* entity = mBase->getCreator()->createEntity (Ogre::SceneManager::PT_CUBE); - entity->setMaterialName("BaseWhite"); /// \todo adjust material according to error - entity->setVisibilityFlags (Element_Reference); - - mBase->attachObject (entity); - */ + mBaseNode->addChild(createErrorCube()); } else { @@ -60,10 +76,7 @@ void CSVRender::Object::update() { std::string path = "meshes\\" + model; - osg::ref_ptr loaded = mResourceSystem->getSceneManager()->getInstance(path); - - mBaseNode->removeChildren(0, mBaseNode->getNumChildren()); - mBaseNode->addChild(loaded); + mResourceSystem->getSceneManager()->createInstance(path, mBaseNode); } catch (std::exception& e) { @@ -73,7 +86,7 @@ void CSVRender::Object::update() } } -void CSVRender::Object::adjust() +void CSVRender::Object::adjustTransform() { if (mReferenceId.empty()) return; @@ -120,8 +133,8 @@ CSVRender::Object::Object (CSMWorld::Data& data, osg::Group* parentNode, mReferenceableId = getReference().mRefID; } + adjustTransform(); update(); - adjust(); } CSVRender::Object::~Object() @@ -140,8 +153,8 @@ bool CSVRender::Object::referenceableDataChanged (const QModelIndex& topLeft, if (index!=-1 && index>=topLeft.row() && index<=bottomRight.row()) { + adjustTransform(); update(); - adjust(); return true; } @@ -160,8 +173,8 @@ bool CSVRender::Object::referenceableAboutToBeRemoved (const QModelIndex& parent // Deletion of referenceable-type objects is handled outside of Object. if (!mReferenceId.empty()) { + adjustTransform(); update(); - adjust(); return true; } } @@ -184,6 +197,8 @@ bool CSVRender::Object::referenceDataChanged (const QModelIndex& topLeft, int columnIndex = references.findColumnIndex (CSMWorld::Columns::ColumnId_ReferenceableId); + adjustTransform(); + if (columnIndex>=topLeft.column() && columnIndex<=bottomRight.row()) { mReferenceableId = @@ -192,8 +207,6 @@ bool CSVRender::Object::referenceDataChanged (const QModelIndex& topLeft, update(); } - adjust(); - return true; } diff --git a/apps/opencs/view/render/object.hpp b/apps/opencs/view/render/object.hpp index e40253a60..4cea62133 100644 --- a/apps/opencs/view/render/object.hpp +++ b/apps/opencs/view/render/object.hpp @@ -52,10 +52,11 @@ namespace CSVRender void clear(); /// Update model + /// @note Make sure adjustTransform() was called first so world space particles get positioned correctly void update(); /// Adjust position, orientation and scale - void adjust(); + void adjustTransform(); /// Throws an exception if *this was constructed with referenceable const CSMWorld::CellRef& getReference() const; diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 3b68df562..7e1c27b0e 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -915,14 +915,8 @@ namespace NifOsg } // Load the initial state of the particle system, i.e. the initial particles and their positions, velocity and colors. - void handleParticleInitialState(const Nif::Node* nifNode, osgParticle::ParticleSystem* partsys, const Nif::NiParticleSystemController* partctrl, - osgParticle::ParticleProcessor::ReferenceFrame rf) + void handleParticleInitialState(const Nif::Node* nifNode, osgParticle::ParticleSystem* partsys, const Nif::NiParticleSystemController* partctrl) { - // TODO: also take into account the transform by placement in the scene (should be done post-load) - osg::Matrix particletransform; - if (rf == osgParticle::ParticleProcessor::ABSOLUTE_RF) - particletransform = getWorldTransform(nifNode); - const Nif::NiAutoNormalParticlesData *particledata = NULL; if(nifNode->recType == Nif::RC_NiAutoNormalParticles) particledata = static_cast(nifNode)->data.getPtr(); @@ -941,9 +935,11 @@ namespace NifOsg osgParticle::Particle* created = partsys->createParticle(&particletemplate); created->setLifeTime(std::max(0.f, particle.lifespan)); - osg::Vec4f adjustedVelocity = osg::Vec4f(particle.velocity, 0.f) * particletransform; - created->setVelocity(osg::Vec3f(adjustedVelocity.x(), adjustedVelocity.y(), adjustedVelocity.z())); - created->setPosition(particledata->vertices.at(particle.vertex) * particletransform); + + // Note this position and velocity is not correct for a particle system with absolute reference frame, + // which can not be done in this loader since we are not attached to the scene yet. Will be fixed up post-load in the SceneManager. + created->setVelocity(particle.velocity); + created->setPosition(particledata->vertices.at(particle.vertex)); osg::Vec4f partcolor (1.f,1.f,1.f,1.f); if (particle.vertex < int(particledata->colors.size())) @@ -1014,7 +1010,13 @@ namespace NifOsg ? osgParticle::ParticleProcessor::RELATIVE_RF : osgParticle::ParticleProcessor::ABSOLUTE_RF; - handleParticleInitialState(nifNode, partsys, partctrl, rf); + // HACK: ParticleSystem has no setReferenceFrame method + if (rf == osgParticle::ParticleProcessor::ABSOLUTE_RF) + { + partsys->getOrCreateUserDataContainer()->addDescription("worldspace"); + } + + handleParticleInitialState(nifNode, partsys, partctrl); partsys->setQuota(partctrl->numParticles); @@ -1030,7 +1032,6 @@ namespace NifOsg // This seems to be true for all NIF files in the game that I've checked, suggesting that NIFs work similar to OSG with regards to update order. // If something ever violates this assumption, the worst that could happen is the culling being one frame late, which wouldn't be a disaster. - // Creating emitters will need to be changed when cloning a scenegraph is implemented, the particleSystem pointer would become invalid FindRecIndexVisitor find (partctrl->emitter->recIndex); rootNode->accept(find); if (!find.mFound) diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index b6a09f3a7..c7fd5065e 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -1,12 +1,63 @@ #include "scenemanager.hpp" #include +#include +#include + +#include #include #include #include +namespace +{ + + class InitWorldSpaceParticlesVisitor : public osg::NodeVisitor + { + public: + InitWorldSpaceParticlesVisitor() + : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) + { + } + + void apply(osg::Node& node) + { + if (osg::Geode* geode = node.asGeode()) + { + for (unsigned int i=0;igetNumDrawables();++i) + { + if (osgParticle::ParticleSystem* partsys = dynamic_cast(geode->getDrawable(i))) + { + // HACK: ParticleSystem has no getReferenceFrame() + if (partsys->getUserDataContainer() + && partsys->getUserDataContainer()->getNumDescriptions() > 0 + && partsys->getUserDataContainer()->getDescriptions()[0] == "worldspace") + { + // HACK: Ignore the InverseWorldMatrix transform the geode is attached to + if (geode->getNumParents() && geode->getParent(0)->getNumParents()) + transformInitialParticles(partsys, geode->getParent(0)->getParent(0)); + } + } + } + } + + traverse(node); + } + + void transformInitialParticles(osgParticle::ParticleSystem* partsys, osg::Node* node) + { + osg::Matrix worldMat = node->getWorldMatrices()[0]; + for (int i=0; inumParticles(); ++i) + { + partsys->getParticle(i)->transformPositionVelocity(worldMat); + } + } + }; + +} + namespace Resource { @@ -40,10 +91,25 @@ namespace Resource return it->second; } - osg::ref_ptr SceneManager::getInstance(const std::string &name) + osg::ref_ptr SceneManager::createInstance(const std::string &name) { osg::ref_ptr scene = getTemplate(name); - return osg::clone(scene.get(), SceneUtil::CopyOp()); + osg::ref_ptr cloned = osg::clone(scene.get(), SceneUtil::CopyOp()); + return cloned; + } + + osg::ref_ptr SceneManager::createInstance(const std::string &name, osg::Group* parentNode) + { + osg::ref_ptr cloned = createInstance(name); + attachTo(cloned, parentNode); + return cloned; + } + + void SceneManager::attachTo(osg::Node *instance, osg::Group *parentNode) const + { + parentNode->addChild(instance); + InitWorldSpaceParticlesVisitor visitor; + instance->accept(visitor); } } diff --git a/components/resource/scenemanager.hpp b/components/resource/scenemanager.hpp index 7922f3a49..76b69be6e 100644 --- a/components/resource/scenemanager.hpp +++ b/components/resource/scenemanager.hpp @@ -25,7 +25,16 @@ namespace Resource osg::ref_ptr getTemplate(const std::string& name); /// Create an instance of the given scene template - osg::ref_ptr getInstance(const std::string& name); + osg::ref_ptr createInstance(const std::string& name); + + /// Create an instance of the given scene template and immediately attach it to a parent node + osg::ref_ptr createInstance(const std::string& name, osg::Group* parentNode); + + /// Attach the given scene instance to the given parent node + /// @note You should have the parentNode in its intended position before calling this method, + /// so that world space particles of the \a instance get transformed correctly. + /// @note Assumes the given instance was not attached to any parents before. + void attachTo(osg::Node* instance, osg::Group* parentNode) const; private: const VFS::Manager* mVFS; From bb32c761df2d08e65128998e6dd68bcfe7737bca Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 28 Mar 2015 02:20:20 +0100 Subject: [PATCH 0838/3725] *very* early texture manager, need a lot more thought to design this properly --- apps/nifosgtest/test.cpp | 5 +- apps/opencs/view/render/scenewidget.cpp | 2 +- components/CMakeLists.txt | 2 +- components/nifosg/controller.cpp | 9 +--- components/nifosg/controller.hpp | 6 +-- components/nifosg/nifloader.cpp | 59 ++++++++++------------ components/nifosg/nifloader.hpp | 9 ++-- components/resource/resourcesystem.cpp | 4 +- components/resource/resourcesystem.hpp | 4 ++ components/resource/scenemanager.cpp | 7 ++- components/resource/scenemanager.hpp | 8 ++- components/resource/texturemanager.cpp | 66 +++++++++++++++++++++++++ components/resource/texturemanager.hpp | 48 ++++++++++++++++++ 13 files changed, 176 insertions(+), 53 deletions(-) create mode 100644 components/resource/texturemanager.cpp create mode 100644 components/resource/texturemanager.hpp diff --git a/apps/nifosgtest/test.cpp b/apps/nifosgtest/test.cpp index dec038825..332867be5 100644 --- a/apps/nifosgtest/test.cpp +++ b/apps/nifosgtest/test.cpp @@ -10,6 +10,8 @@ #include #include +#include + #include #include @@ -124,7 +126,8 @@ int main(int argc, char** argv) //osgDB::writeNodeFile(*newNode, "out.osg"); osg::Group* newNode = new osg::Group; NifOsg::Loader loader; - loader.resourceManager = &resourceMgr; + Resource::TextureManager texMgr(&resourceMgr); + loader.mTextureManager = &texMgr; newNode->addChild(loader.load(nif)); osg::PositionAttitudeTransform* trans = new osg::PositionAttitudeTransform; diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index 16ad2e68a..d7a85410b 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -109,7 +109,7 @@ CompositeViewer::CompositeViewer() setRunFrameScheme(osgViewer::ViewerBase::CONTINUOUS); connect( &mTimer, SIGNAL(timeout()), this, SLOT(update()) ); - mTimer.start( 10 ); + mTimer.start( 0 ); } CompositeViewer &CompositeViewer::get() diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 161c9ce4a..47fcf2499 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -39,7 +39,7 @@ add_component_dir (vfs ) add_component_dir (resource - scenemanager resourcesystem + scenemanager texturemanager resourcesystem ) add_component_dir (sceneutil diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index 6aa920553..eca5a7d79 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -416,7 +416,7 @@ void MaterialColorController::operator() (osg::Node* node, osg::NodeVisitor* nv) traverse(node, nv); } -FlipController::FlipController(const Nif::NiFlipController *ctrl, std::vector > textures) +FlipController::FlipController(const Nif::NiFlipController *ctrl, std::vector > textures) : mTexSlot(ctrl->mTexSlot) , mDelta(ctrl->mDelta) , mTextures(textures) @@ -442,12 +442,7 @@ void FlipController::operator() (osg::Node* node, osg::NodeVisitor* nv) { osg::StateSet* stateset = node->getStateSet(); int curTexture = int(getInputValue(nv) / mDelta) % mTextures.size(); - osg::Texture2D* tex = dynamic_cast(stateset->getTextureAttribute(mTexSlot, osg::StateAttribute::TEXTURE)); - if (tex) - tex->setImage(mTextures[curTexture].get()); - else - std::cout << "FlipController: can't find target slot" << std::endl; - + stateset->setTextureAttribute(mTexSlot, mTextures[curTexture]); } traverse(node, nv); } diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index 7579735ca..0e5885333 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -13,7 +13,7 @@ #include //UVController // FlipController -#include +#include #include #include @@ -265,10 +265,10 @@ namespace NifOsg private: int mTexSlot; float mDelta; - std::vector > mTextures; + std::vector > mTextures; public: - FlipController(const Nif::NiFlipController* ctrl, std::vector > textures); + FlipController(const Nif::NiFlipController* ctrl, std::vector > textures); FlipController(); FlipController(const FlipController& copy, const osg::CopyOp& copyop); diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 7e1c27b0e..ace14c669 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -6,12 +6,12 @@ #include #include -// resource -#include -#include #include + +// resource #include #include +#include // skel #include @@ -510,11 +510,11 @@ namespace NifOsg class LoaderImpl { public: - const VFS::Manager* mResourceManager; + Resource::TextureManager* mTextureManager; bool mShowMarkers; - LoaderImpl(const VFS::Manager* resourceManager, bool showMarkers) - : mResourceManager(resourceManager) + LoaderImpl(Resource::TextureManager* textureManager, bool showMarkers) + : mTextureManager(textureManager) , mShowMarkers(showMarkers) { } @@ -846,22 +846,26 @@ namespace NifOsg if (ctrl->recType == Nif::RC_NiFlipController) { const Nif::NiFlipController* flipctrl = static_cast(ctrl.getPtr()); - std::vector > textures; + std::vector > textures; for (unsigned int i=0; imSources.length(); ++i) { Nif::NiSourceTexturePtr st = flipctrl->mSources[i]; if (st.empty()) continue; - std::string filename = Misc::ResourceHelpers::correctTexturePath(st->filename, mResourceManager); + // inherit wrap settings from the target slot + osg::Texture2D* inherit = dynamic_cast(stateset->getTextureAttribute(flipctrl->mTexSlot, osg::StateAttribute::TEXTURE)); + osg::Texture2D::WrapMode wrapS = osg::Texture2D::CLAMP; + osg::Texture2D::WrapMode wrapT = osg::Texture2D::CLAMP; + if (inherit) + { + wrapS = inherit->getWrap(osg::Texture2D::WRAP_S); + wrapT = inherit->getWrap(osg::Texture2D::WRAP_T); + } - // TODO: replace with texture manager - // tx_creature_werewolf.dds isn't loading in the correct format without this option - osgDB::Options* opts = new osgDB::Options; - opts->setOptionString("dds_dxt1_detect_rgba"); - osgDB::ReaderWriter* reader = osgDB::Registry::instance()->getReaderWriterForExtension("dds"); - osgDB::ReaderWriter::ReadResult result = reader->readImage(*mResourceManager->get(filename.c_str()), opts); - textures.push_back(osg::ref_ptr(result.getImage())); + std::string filename = Misc::ResourceHelpers::correctTexturePath(st->filename, mTextureManager->getVFS()); + osg::ref_ptr texture = mTextureManager->getTexture2D(filename, wrapS, wrapT); + textures.push_back(texture); } osg::ref_ptr callback(new FlipController(flipctrl, textures)); setupController(ctrl.getPtr(), callback, animflags); @@ -1398,26 +1402,15 @@ namespace NifOsg continue; } - std::string filename = Misc::ResourceHelpers::correctTexturePath(st->filename, mResourceManager); - - // TODO: replace with texture manager - // tx_creature_werewolf.dds isn't loading in the correct format without this option - osgDB::Options* opts = new osgDB::Options; - opts->setOptionString("dds_dxt1_detect_rgba"); - osgDB::ReaderWriter* reader = osgDB::Registry::instance()->getReaderWriterForExtension("dds"); - osgDB::ReaderWriter::ReadResult result = reader->readImage(*mResourceManager->get(filename.c_str()), opts); - osg::Image* image = result.getImage(); - osg::Texture2D* texture2d = new osg::Texture2D; - // Can be enabled for single-context, i.e. in openmw - //texture2d->setUnRefImageDataAfterApply(true); - texture2d->setImage(image); + std::string filename = Misc::ResourceHelpers::correctTexturePath(st->filename, mTextureManager->getVFS()); unsigned int clamp = static_cast(tex.clamp); int wrapT = (clamp) & 0x1; int wrapS = (clamp >> 1) & 0x1; - texture2d->setWrap(osg::Texture::WRAP_S, wrapS ? osg::Texture::REPEAT : osg::Texture::CLAMP); - texture2d->setWrap(osg::Texture::WRAP_T, wrapT ? osg::Texture::REPEAT : osg::Texture::CLAMP); + osg::Texture2D* texture2d = mTextureManager->getTexture2D(filename, + wrapS ? osg::Texture::REPEAT : osg::Texture::CLAMP, + wrapT ? osg::Texture::REPEAT : osg::Texture::CLAMP); stateset->setTextureAttributeAndModes(i, texture2d, osg::StateAttribute::ON); @@ -1544,19 +1537,19 @@ namespace NifOsg osg::ref_ptr Loader::load(Nif::NIFFilePtr file, TextKeyMap *textKeys) { - LoaderImpl loader(resourceManager, sShowMarkers); + LoaderImpl loader(mTextureManager, sShowMarkers); return loader.load(file, textKeys); } osg::ref_ptr Loader::loadAsSkeleton(Nif::NIFFilePtr file, TextKeyMap *textKeys) { - LoaderImpl loader(resourceManager, sShowMarkers); + LoaderImpl loader(mTextureManager, sShowMarkers); return loader.loadAsSkeleton(file, textKeys); } void Loader::loadKf(Nif::NIFFilePtr kf, osg::Node *rootNode, int sourceIndex, TextKeyMap &textKeys) { - LoaderImpl loader(resourceManager, sShowMarkers); + LoaderImpl loader(mTextureManager, sShowMarkers); loader.loadKf(kf, rootNode, sourceIndex, textKeys); } diff --git a/components/nifosg/nifloader.hpp b/components/nifosg/nifloader.hpp index 87d1a0a99..716cd1957 100644 --- a/components/nifosg/nifloader.hpp +++ b/components/nifosg/nifloader.hpp @@ -5,8 +5,6 @@ #include // NIFFilePtr -#include - #include namespace osg @@ -14,6 +12,11 @@ namespace osg class Node; } +namespace Resource +{ + class TextureManager; +} + namespace NifOsg { typedef std::multimap TextKeyMap; @@ -41,7 +44,7 @@ namespace NifOsg /// Default: false. static void setShowMarkers(bool show); - const VFS::Manager* resourceManager; + Resource::TextureManager* mTextureManager; private: diff --git a/components/resource/resourcesystem.cpp b/components/resource/resourcesystem.cpp index e87ef6f10..215b1a67c 100644 --- a/components/resource/resourcesystem.cpp +++ b/components/resource/resourcesystem.cpp @@ -1,6 +1,7 @@ #include "resourcesystem.hpp" #include "scenemanager.hpp" +#include "texturemanager.hpp" namespace Resource { @@ -8,7 +9,8 @@ namespace Resource ResourceSystem::ResourceSystem(const VFS::Manager *vfs) : mVFS(vfs) { - mSceneManager.reset(new SceneManager(vfs)); + mTextureManager.reset(new TextureManager(vfs)); + mSceneManager.reset(new SceneManager(vfs, mTextureManager.get())); } SceneManager* ResourceSystem::getSceneManager() diff --git a/components/resource/resourcesystem.hpp b/components/resource/resourcesystem.hpp index b696a2376..a91f3cab3 100644 --- a/components/resource/resourcesystem.hpp +++ b/components/resource/resourcesystem.hpp @@ -12,8 +12,11 @@ namespace Resource { class SceneManager; + class TextureManager; /// @brief Wrapper class that constructs and provides access to the various resource subsystems. + /// @par Resource subsystems can be used with multiple OpenGL contexts, just like the OSG equivalents, but + /// are built around the use of a single virtual file system. class ResourceSystem { public: @@ -25,6 +28,7 @@ namespace Resource private: std::auto_ptr mSceneManager; + std::auto_ptr mTextureManager; const VFS::Manager* mVFS; }; diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index c7fd5065e..c44cbd2ae 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -9,6 +9,8 @@ #include #include +#include + #include namespace @@ -61,8 +63,9 @@ namespace namespace Resource { - SceneManager::SceneManager(const VFS::Manager *vfs) + SceneManager::SceneManager(const VFS::Manager *vfs, Resource::TextureManager* textureManager) : mVFS(vfs) + , mTextureManager(textureManager) { } @@ -79,7 +82,7 @@ namespace Resource // TODO: add support for non-NIF formats NifOsg::Loader loader; - loader.resourceManager = mVFS; + loader.mTextureManager = mTextureManager; osg::ref_ptr loaded = loader.load(Nif::NIFFilePtr(new Nif::NIFFile(file, normalized))); // TODO: provide way for the user to get textKeys (attach to the node?) diff --git a/components/resource/scenemanager.hpp b/components/resource/scenemanager.hpp index 76b69be6e..3d439c186 100644 --- a/components/resource/scenemanager.hpp +++ b/components/resource/scenemanager.hpp @@ -7,6 +7,11 @@ #include #include +namespace Resource +{ + class TextureManager; +} + namespace VFS { class Manager; @@ -19,7 +24,7 @@ namespace Resource class SceneManager { public: - SceneManager(const VFS::Manager* vfs); + SceneManager(const VFS::Manager* vfs, Resource::TextureManager* textureManager); /// Get a read-only copy of this scene "template" osg::ref_ptr getTemplate(const std::string& name); @@ -38,6 +43,7 @@ namespace Resource private: const VFS::Manager* mVFS; + Resource::TextureManager* mTextureManager; // observer_ptr? typedef std::map > Index; diff --git a/components/resource/texturemanager.cpp b/components/resource/texturemanager.cpp new file mode 100644 index 000000000..8347d5f04 --- /dev/null +++ b/components/resource/texturemanager.cpp @@ -0,0 +1,66 @@ +#include "texturemanager.hpp" + +#include + +#include + +#include + +namespace Resource +{ + + TextureManager::TextureManager(const VFS::Manager *vfs) + : mVFS(vfs) + { + + } + + /* + osg::ref_ptr TextureManager::getImage(const std::string &filename) + { + + } + */ + + osg::ref_ptr TextureManager::getTexture2D(const std::string &filename, osg::Texture::WrapMode wrapS, osg::Texture::WrapMode wrapT) + { + std::string normalized = filename; + mVFS->normalizeFilename(normalized); + MapKey key = std::make_pair(std::make_pair(wrapS, wrapT), normalized); + std::map >::iterator found = mTextures.find(key); + if (found != mTextures.end()) + { + return found->second; + } + else + { + osg::ref_ptr opts (new osgDB::Options); + opts->setOptionString("dds_dxt1_detect_rgba"); // tx_creature_werewolf.dds isn't loading in the correct format without this option + size_t extPos = normalized.find_last_of('.'); + std::string ext; + if (extPos != std::string::npos && extPos+1 < normalized.size()) + ext = normalized.substr(extPos+1); + osgDB::ReaderWriter* reader = osgDB::Registry::instance()->getReaderWriterForExtension(ext); + osgDB::ReaderWriter::ReadResult result = reader->readImage(*mVFS->get(normalized.c_str()), opts); + if (!result.success()) + { + // TODO: use "notfound" default texture + throw std::runtime_error("Error loading"); + //std::cerr << "Error loading " << filename << ": " << result.message() << std::endl; + } + + osg::Image* image = result.getImage(); + osg::ref_ptr texture(new osg::Texture2D); + texture->setImage(image); + texture->setWrap(osg::Texture::WRAP_S, wrapS); + texture->setWrap(osg::Texture::WRAP_T, wrapT); + + // Can be enabled for single-context, i.e. in openmw + //texture->setUnRefImageDataAfterApply(true); + + mTextures.insert(std::make_pair(key, texture)); + return texture; + } + } + +} diff --git a/components/resource/texturemanager.hpp b/components/resource/texturemanager.hpp new file mode 100644 index 000000000..c0b36f7cf --- /dev/null +++ b/components/resource/texturemanager.hpp @@ -0,0 +1,48 @@ +#ifndef OPENMW_COMPONENTS_RESOURCE_TEXTUREMANAGER_H +#define OPENMW_COMPONENTS_RESOURCE_TEXTUREMANAGER_H + +#include +#include + +#include +#include +#include + +namespace VFS +{ + class Manager; +} + +namespace Resource +{ + + /// @brief Handles loading/caching of Images and Texture StateAttributes. + class TextureManager + { + public: + TextureManager(const VFS::Manager* vfs); + + // TODO: texture filtering settings + + /// Create or retrieve a Texture2D using the specified image filename, and wrap parameters. + osg::ref_ptr getTexture2D(const std::string& filename, osg::Texture::WrapMode wrapS, osg::Texture::WrapMode wrapT); + + /// Create or retrieve an Image + //osg::ref_ptr getImage(const std::string& filename); + + const VFS::Manager* getVFS() { return mVFS; } + + private: + const VFS::Manager* mVFS; + + typedef std::pair, std::string> MapKey; + + std::map > mImages; + + std::map > mTextures; + + }; + +} + +#endif From c5fd92fde1e357c54102cfb8726aad86cd539311 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 28 Mar 2015 02:57:39 +0100 Subject: [PATCH 0839/3725] Show a default warning texture for not found textures --- components/resource/texturemanager.cpp | 43 +++++++++++++++++++++++--- components/resource/texturemanager.hpp | 2 ++ 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/components/resource/texturemanager.cpp b/components/resource/texturemanager.cpp index 8347d5f04..d0d32a40e 100644 --- a/components/resource/texturemanager.cpp +++ b/components/resource/texturemanager.cpp @@ -6,11 +6,36 @@ #include +namespace +{ + + osg::ref_ptr createWarningTexture() + { + osg::ref_ptr warningImage = new osg::Image; + + int width=8, height=8; + unsigned char* bytes = (unsigned char*)calloc(width*height*3, sizeof(unsigned char)); + for (int i=0;isetImage(width, height, 1, GL_RGB, GL_RGB, GL_UNSIGNED_BYTE, bytes, osg::Image::USE_MALLOC_FREE); + + osg::ref_ptr warningTexture = new osg::Texture2D; + warningTexture->setImage(warningImage); + return warningTexture; + } + +} + namespace Resource { TextureManager::TextureManager(const VFS::Manager *vfs) : mVFS(vfs) + , mWarningTexture(createWarningTexture()) { } @@ -34,6 +59,17 @@ namespace Resource } else { + Files::IStreamPtr stream; + try + { + stream = mVFS->get(normalized.c_str()); + } + catch (std::exception& e) + { + std::cerr << "Failed to open texture: " << e.what() << std::endl; + return mWarningTexture; + } + osg::ref_ptr opts (new osgDB::Options); opts->setOptionString("dds_dxt1_detect_rgba"); // tx_creature_werewolf.dds isn't loading in the correct format without this option size_t extPos = normalized.find_last_of('.'); @@ -41,12 +77,11 @@ namespace Resource if (extPos != std::string::npos && extPos+1 < normalized.size()) ext = normalized.substr(extPos+1); osgDB::ReaderWriter* reader = osgDB::Registry::instance()->getReaderWriterForExtension(ext); - osgDB::ReaderWriter::ReadResult result = reader->readImage(*mVFS->get(normalized.c_str()), opts); + osgDB::ReaderWriter::ReadResult result = reader->readImage(*stream, opts); if (!result.success()) { - // TODO: use "notfound" default texture - throw std::runtime_error("Error loading"); - //std::cerr << "Error loading " << filename << ": " << result.message() << std::endl; + std::cerr << "Error loading " << filename << ": " << result.message() << std::endl; + return mWarningTexture; } osg::Image* image = result.getImage(); diff --git a/components/resource/texturemanager.hpp b/components/resource/texturemanager.hpp index c0b36f7cf..f4ade515d 100644 --- a/components/resource/texturemanager.hpp +++ b/components/resource/texturemanager.hpp @@ -41,6 +41,8 @@ namespace Resource std::map > mTextures; + osg::ref_ptr mWarningTexture; + }; } From be6ee927b906313cc7a19ed4298da725c22aebbd Mon Sep 17 00:00:00 2001 From: dteviot Date: Sat, 28 Mar 2015 20:05:54 +1300 Subject: [PATCH 0840/3725] AiWander, use closest two points if distance is too small (Fixes #1317) In AiWander, if wander distance is set too small to get two points, take the closest two points. --- apps/openmw/mwmechanics/aiwander.cpp | 30 ++++++++++++++++++++++++++-- apps/openmw/mwmechanics/aiwander.hpp | 7 +++++++ 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index d277b1249..560e756ce 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -686,7 +686,8 @@ namespace MWMechanics // If there is no path this actor doesn't go anywhere. See: // https://forum.openmw.org/viewtopic.php?t=1556 // http://www.fliggerty.com/phpBB3/viewtopic.php?f=30&t=5833 - if(!pathgrid || pathgrid->mPoints.empty()) + // Note: In order to wander, need at least two points. + if(!pathgrid || (pathgrid->mPoints.size() < 2)) mDistance = 0; // A distance value passed into the constructor indicates how far the @@ -730,12 +731,37 @@ namespace MWMechanics } mCurrentNode = mAllowedNodes[index]; mAllowedNodes.erase(mAllowedNodes.begin() + index); + } + + // In vanilla Morrowind, sometimes distance is too small to include at least two points, + // in which case, we will take the two closest points regardless of the wander distance + // This is a backup option, as std::sort is potentially O(n^2) in time. + if (mAllowedNodes.empty()) + { + // Start with list of PathGrid nodes, sorted by distance from actor + std::vector nodeDistances; + for (unsigned int counter = 0; counter < pathgrid->mPoints.size(); counter++) + { + float distance = npcPos.squaredDistance(PathFinder::MakeOgreVector3(pathgrid->mPoints[counter])); + nodeDistances.push_back(std::make_pair(distance, &pathgrid->mPoints.at(counter))); + } + std::sort(nodeDistances.begin(), nodeDistances.end(), sortByDistance); - mStoredAvailableNodes = true; // set only if successful in finding allowed nodes + // make closest node the current node + mCurrentNode = *nodeDistances[0].second; + + // give Actor a 2nd node to walk to + mAllowedNodes.push_back(*nodeDistances[1].second); } + mStoredAvailableNodes = true; // set only if successful in finding allowed nodes } } + bool AiWander::sortByDistance(const PathDistance& left, const PathDistance& right) + { + return left.first < right.first; + } + void AiWander::writeState(ESM::AiSequence::AiSequence &sequence) const { std::auto_ptr wander(new ESM::AiSequence::AiWander()); diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 7e138c001..7f8fc5088 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -122,6 +122,13 @@ namespace MWMechanics /// lookup table for converting idleSelect value to groupName static const std::string sIdleSelectToGroupName[GroupIndex_MaxIdle - GroupIndex_MinIdle + 1]; + + /// record distances of pathgrid point nodes to actor + /// first value is distance between actor and node, second value is PathGrid node + typedef std::pair PathDistance; + + /// used to sort array of PathDistance objects into ascending order + static bool sortByDistance(const PathDistance& left, const PathDistance& right); }; From 128ccd81510ab7c216162672801fce24ef9602e1 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 28 Mar 2015 11:54:32 +0100 Subject: [PATCH 0841/3725] improved search type naming --- apps/opencs/model/tools/search.cpp | 12 ++++++------ apps/opencs/model/tools/search.hpp | 4 ++-- apps/opencs/view/tools/searchbox.cpp | 12 ++++++------ 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/apps/opencs/model/tools/search.cpp b/apps/opencs/model/tools/search.cpp index 9e22f82dd..b873088de 100644 --- a/apps/opencs/model/tools/search.cpp +++ b/apps/opencs/model/tools/search.cpp @@ -103,14 +103,14 @@ CSMTools::Search::Search() : mType (Type_None) {} CSMTools::Search::Search (Type type, const std::string& value) : mType (type), mText (value) { - if (type!=Type_Text && type!=Type_Reference) + if (type!=Type_Text && type!=Type_Id) throw std::logic_error ("Invalid search parameter (string)"); } CSMTools::Search::Search (Type type, const QRegExp& value) : mType (type), mRegExp (value) { - if (type!=Type_TextRegEx && type!=Type_ReferenceRegEx) + if (type!=Type_TextRegEx && type!=Type_IdRegEx) throw std::logic_error ("Invalid search parameter (RegExp)"); } @@ -150,8 +150,8 @@ void CSMTools::Search::configure (const CSMWorld::IdTableBase *model) break; - case Type_Reference: - case Type_ReferenceRegEx: + case Type_Id: + case Type_IdRegEx: if (CSMWorld::ColumnBase::isId (display)) { @@ -202,13 +202,13 @@ void CSMTools::Search::searchRow (const CSMWorld::IdTableBase *model, int row, switch (mType) { case Type_Text: - case Type_Reference: + case Type_Id: searchTextCell (model, index, id, iter->second, messages); break; case Type_TextRegEx: - case Type_ReferenceRegEx: + case Type_IdRegEx: searchRegExCell (model, index, id, iter->second, messages); break; diff --git a/apps/opencs/model/tools/search.hpp b/apps/opencs/model/tools/search.hpp index 7e95a2846..46ea99686 100644 --- a/apps/opencs/model/tools/search.hpp +++ b/apps/opencs/model/tools/search.hpp @@ -30,8 +30,8 @@ namespace CSMTools { Type_Text = 0, Type_TextRegEx = 1, - Type_Reference = 2, - Type_ReferenceRegEx = 3, + Type_Id = 2, + Type_IdRegEx = 3, Type_RecordState = 4, Type_None }; diff --git a/apps/opencs/view/tools/searchbox.cpp b/apps/opencs/view/tools/searchbox.cpp index 1b11d8a4d..bfae6f50d 100644 --- a/apps/opencs/view/tools/searchbox.cpp +++ b/apps/opencs/view/tools/searchbox.cpp @@ -50,8 +50,8 @@ CSVTools::SearchBox::SearchBox (QWidget *parent) mMode.addItem ("Text"); mMode.addItem ("Text (RegEx)"); - mMode.addItem ("Reference"); - mMode.addItem ("Reference (RegEx)"); + mMode.addItem ("ID"); + mMode.addItem ("ID (RegEx)"); mMode.addItem ("Record State"); mLayout->addWidget (&mMode, 0, 0); @@ -93,12 +93,12 @@ CSMTools::Search CSVTools::SearchBox::getSearch() const switch (type) { case CSMTools::Search::Type_Text: - case CSMTools::Search::Type_Reference: + case CSMTools::Search::Type_Id: return CSMTools::Search (type, std::string (mText.text().toUtf8().data())); case CSMTools::Search::Type_TextRegEx: - case CSMTools::Search::Type_ReferenceRegEx: + case CSMTools::Search::Type_IdRegEx: return CSMTools::Search (type, QRegExp (mText.text().toUtf8().data(), Qt::CaseInsensitive)); @@ -120,8 +120,8 @@ void CSVTools::SearchBox::modeSelected (int index) { case CSMTools::Search::Type_Text: case CSMTools::Search::Type_TextRegEx: - case CSMTools::Search::Type_Reference: - case CSMTools::Search::Type_ReferenceRegEx: + case CSMTools::Search::Type_Id: + case CSMTools::Search::Type_IdRegEx: mInput.setCurrentIndex (0); break; From eaaf816dd3a9d48fb785954188211cb9b5cddda3 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 28 Mar 2015 12:05:49 +0100 Subject: [PATCH 0842/3725] simplified search rules --- apps/opencs/model/tools/search.cpp | 31 +++++++++--------------------- apps/opencs/model/tools/search.hpp | 8 ++++---- 2 files changed, 13 insertions(+), 26 deletions(-) diff --git a/apps/opencs/model/tools/search.cpp b/apps/opencs/model/tools/search.cpp index b873088de..2d3e4f952 100644 --- a/apps/opencs/model/tools/search.cpp +++ b/apps/opencs/model/tools/search.cpp @@ -11,7 +11,7 @@ #include "../../model/world/universalid.hpp" void CSMTools::Search::searchTextCell (const CSMWorld::IdTableBase *model, - const QModelIndex& index, const CSMWorld::UniversalId& id, bool multiple, + const QModelIndex& index, const CSMWorld::UniversalId& id, CSMDoc::Messages& messages) const { // using QString here for easier handling of case folding. @@ -31,15 +31,12 @@ void CSMTools::Search::searchTextCell (const CSMWorld::IdTableBase *model, messages.add (id, message.str(), hint.str()); - if (!multiple) - break; - pos += search.length(); } } void CSMTools::Search::searchRegExCell (const CSMWorld::IdTableBase *model, - const QModelIndex& index, const CSMWorld::UniversalId& id, bool multiple, + const QModelIndex& index, const CSMWorld::UniversalId& id, CSMDoc::Messages& messages) const { QString text = model->data (index).toString(); @@ -58,9 +55,6 @@ void CSMTools::Search::searchRegExCell (const CSMWorld::IdTableBase *model, messages.add (id, message.str(), hint.str()); - if (!multiple) - break; - pos += length; } } @@ -134,7 +128,6 @@ void CSMTools::Search::configure (const CSMWorld::IdTableBase *model) i, Qt::Horizontal, static_cast (CSMWorld::ColumnBase::Role_Display)).toInt()); bool consider = false; - bool multiple = false; switch (mType) { @@ -145,7 +138,6 @@ void CSMTools::Search::configure (const CSMWorld::IdTableBase *model) CSMWorld::ColumnBase::isScript (display)) { consider = true; - multiple = true; } break; @@ -153,14 +145,10 @@ void CSMTools::Search::configure (const CSMWorld::IdTableBase *model) case Type_Id: case Type_IdRegEx: - if (CSMWorld::ColumnBase::isId (display)) - { - consider = true; - } - else if (CSMWorld::ColumnBase::isScript (display)) + if (CSMWorld::ColumnBase::isId (display) || + CSMWorld::ColumnBase::isScript (display)) { consider = true; - multiple = true; } break; @@ -178,7 +166,7 @@ void CSMTools::Search::configure (const CSMWorld::IdTableBase *model) } if (consider) - mColumns.insert (std::make_pair (i, multiple)); + mColumns.insert (i); } mIdColumn = model->findColumnIndex (CSMWorld::Columns::ColumnId_Id); @@ -188,10 +176,9 @@ void CSMTools::Search::configure (const CSMWorld::IdTableBase *model) void CSMTools::Search::searchRow (const CSMWorld::IdTableBase *model, int row, CSMDoc::Messages& messages) const { - for (std::map::const_iterator iter (mColumns.begin()); iter!=mColumns.end(); - ++iter) + for (std::set::const_iterator iter (mColumns.begin()); iter!=mColumns.end(); ++iter) { - QModelIndex index = model->index (row, iter->first); + QModelIndex index = model->index (row, *iter); CSMWorld::UniversalId::Type type = static_cast ( model->data (model->index (row, mTypeColumn)).toInt()); @@ -204,13 +191,13 @@ void CSMTools::Search::searchRow (const CSMWorld::IdTableBase *model, int row, case Type_Text: case Type_Id: - searchTextCell (model, index, id, iter->second, messages); + searchTextCell (model, index, id, messages); break; case Type_TextRegEx: case Type_IdRegEx: - searchRegExCell (model, index, id, iter->second, messages); + searchRegExCell (model, index, id, messages); break; case Type_RecordState: diff --git a/apps/opencs/model/tools/search.hpp b/apps/opencs/model/tools/search.hpp index 46ea99686..81b8840bf 100644 --- a/apps/opencs/model/tools/search.hpp +++ b/apps/opencs/model/tools/search.hpp @@ -2,7 +2,7 @@ #define CSM_TOOLS_SEARCH_H #include -#include +#include #include #include @@ -42,15 +42,15 @@ namespace CSMTools std::string mText; QRegExp mRegExp; int mValue; - std::map mColumns; // column, multiple finds per cell + std::set mColumns; int mIdColumn; int mTypeColumn; void searchTextCell (const CSMWorld::IdTableBase *model, const QModelIndex& index, - const CSMWorld::UniversalId& id, bool multiple, CSMDoc::Messages& messages) const; + const CSMWorld::UniversalId& id, CSMDoc::Messages& messages) const; void searchRegExCell (const CSMWorld::IdTableBase *model, const QModelIndex& index, - const CSMWorld::UniversalId& id, bool multiple, CSMDoc::Messages& messages) const; + const CSMWorld::UniversalId& id, CSMDoc::Messages& messages) const; void searchRecordStateCell (const CSMWorld::IdTableBase *model, const QModelIndex& index, const CSMWorld::UniversalId& id, From 8e9365741f448aa1ab04867fbc7a789d02d795d2 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 28 Mar 2015 12:53:01 +0100 Subject: [PATCH 0843/3725] make search sub-views re-usable (clear before starting a new search) --- apps/opencs/model/tools/reportmodel.cpp | 10 ++++++++++ apps/opencs/model/tools/reportmodel.hpp | 2 ++ apps/opencs/view/tools/reporttable.cpp | 5 +++++ apps/opencs/view/tools/reporttable.hpp | 2 ++ apps/opencs/view/tools/searchsubview.cpp | 1 + 5 files changed, 20 insertions(+) diff --git a/apps/opencs/model/tools/reportmodel.cpp b/apps/opencs/model/tools/reportmodel.cpp index ac9dabb25..acd4728c6 100644 --- a/apps/opencs/model/tools/reportmodel.cpp +++ b/apps/opencs/model/tools/reportmodel.cpp @@ -79,3 +79,13 @@ std::string CSMTools::ReportModel::getHint (int row) const { return mRows.at (row).second.second; } + +void CSMTools::ReportModel::clear() +{ + if (!mRows.empty()) + { + beginRemoveRows (QModelIndex(), 0, mRows.size()-1); + mRows.clear(); + endRemoveRows(); + } +} diff --git a/apps/opencs/model/tools/reportmodel.hpp b/apps/opencs/model/tools/reportmodel.hpp index 709e024a7..71f5bdf73 100644 --- a/apps/opencs/model/tools/reportmodel.hpp +++ b/apps/opencs/model/tools/reportmodel.hpp @@ -34,6 +34,8 @@ namespace CSMTools const CSMWorld::UniversalId& getUniversalId (int row) const; std::string getHint (int row) const; + + void clear(); }; } diff --git a/apps/opencs/view/tools/reporttable.cpp b/apps/opencs/view/tools/reporttable.cpp index 809a39fa4..5eb375f46 100644 --- a/apps/opencs/view/tools/reporttable.cpp +++ b/apps/opencs/view/tools/reporttable.cpp @@ -134,3 +134,8 @@ void CSVTools::ReportTable::removeSelection() selectionModel()->clear(); } + +void CSVTools::ReportTable::clear() +{ + mModel->clear(); +} diff --git a/apps/opencs/view/tools/reporttable.hpp b/apps/opencs/view/tools/reporttable.hpp index 7a5b232f9..4b686f2d4 100644 --- a/apps/opencs/view/tools/reporttable.hpp +++ b/apps/opencs/view/tools/reporttable.hpp @@ -43,6 +43,8 @@ namespace CSVTools void updateUserSetting (const QString& name, const QStringList& list); + void clear(); + private slots: void showSelection(); diff --git a/apps/opencs/view/tools/searchsubview.cpp b/apps/opencs/view/tools/searchsubview.cpp index b4a0f893a..4afed2c90 100644 --- a/apps/opencs/view/tools/searchsubview.cpp +++ b/apps/opencs/view/tools/searchsubview.cpp @@ -54,5 +54,6 @@ void CSVTools::SearchSubView::stateChanged (int state, CSMDoc::Document *documen void CSVTools::SearchSubView::startSearch (const CSMTools::Search& search) { + mTable->clear(); mDocument.runSearch (getUniversalId(), search); } From 13a4fb3fdca30bce5cd7d76f7a7c56e55ff7be1a Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 28 Mar 2015 13:05:18 +0100 Subject: [PATCH 0844/3725] make return key press in search input trigger a new search --- apps/opencs/view/tools/searchbox.cpp | 7 +++++-- apps/opencs/view/tools/searchbox.hpp | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/apps/opencs/view/tools/searchbox.cpp b/apps/opencs/view/tools/searchbox.cpp index bfae6f50d..178dd1f04 100644 --- a/apps/opencs/view/tools/searchbox.cpp +++ b/apps/opencs/view/tools/searchbox.cpp @@ -74,7 +74,9 @@ CSVTools::SearchBox::SearchBox (QWidget *parent) this, SLOT (textChanged (const QString&))); connect (&mSearch, SIGNAL (clicked (bool)), this, SLOT (startSearch (bool))); - + + connect (&mText, SIGNAL (returnPressed()), this, SLOT (startSearch())); + modeSelected (0); updateSearchButton(); @@ -141,5 +143,6 @@ void CSVTools::SearchBox::textChanged (const QString& text) void CSVTools::SearchBox::startSearch (bool checked) { - emit startSearch (getSearch()); + if (mSearch.isEnabled()) + emit startSearch (getSearch()); } diff --git a/apps/opencs/view/tools/searchbox.hpp b/apps/opencs/view/tools/searchbox.hpp index dc975cac9..35c656d16 100644 --- a/apps/opencs/view/tools/searchbox.hpp +++ b/apps/opencs/view/tools/searchbox.hpp @@ -46,7 +46,7 @@ namespace CSVTools void textChanged (const QString& text); - void startSearch (bool checked); + void startSearch (bool checked = true); signals: From c5f1c2127d51fc7252e72ccbe5be6e902c8d19c2 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 28 Mar 2015 14:36:28 +0100 Subject: [PATCH 0845/3725] extend global search to all record and reference tables --- apps/opencs/model/tools/searchoperation.cpp | 11 +++++++++-- apps/opencs/model/world/universalid.cpp | 19 +++++++++++++++++++ apps/opencs/model/world/universalid.hpp | 20 +++++++++++--------- 3 files changed, 39 insertions(+), 11 deletions(-) diff --git a/apps/opencs/model/tools/searchoperation.cpp b/apps/opencs/model/tools/searchoperation.cpp index 134b83b72..4512de582 100644 --- a/apps/opencs/model/tools/searchoperation.cpp +++ b/apps/opencs/model/tools/searchoperation.cpp @@ -12,8 +12,15 @@ CSMTools::SearchOperation::SearchOperation (CSMDoc::Document& document) : CSMDoc::Operation (CSMDoc::State_Searching, false) { -appendStage (new SearchStage (&dynamic_cast (*document.getData().getTableModel (CSMWorld::UniversalId::Type_Cells)))); - + std::vector types = CSMWorld::UniversalId::listTypes ( + CSMWorld::UniversalId::Class_RecordList | + CSMWorld::UniversalId::Class_ResourceList + ); + + for (std::vector::const_iterator iter (types.begin()); + iter!=types.end(); ++iter) + appendStage (new SearchStage (&dynamic_cast ( + *document.getData().getTableModel (*iter)))); } void CSMTools::SearchOperation::configure (const Search& search) diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index 6aa129f25..fbc942f8e 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -348,6 +348,25 @@ std::vector CSMWorld::UniversalId::listReferenceabl return list; } +std::vector CSMWorld::UniversalId::listTypes (int classes) +{ + std::vector list; + + for (int i=0; sNoArg[i].mName; ++i) + if (sNoArg[i].mClass & classes) + list.push_back (sNoArg[i].mType); + + for (int i=0; sIdArg[i].mName; ++i) + if (sIdArg[i].mClass & classes) + list.push_back (sIdArg[i].mType); + + for (int i=0; sIndexArg[i].mName; ++i) + if (sIndexArg[i].mClass & classes) + list.push_back (sIndexArg[i].mType); + + return list; +} + CSMWorld::UniversalId::Type CSMWorld::UniversalId::getParentType (Type type) { for (int i=0; sIdArg[i].mType; ++i) diff --git a/apps/opencs/model/world/universalid.hpp b/apps/opencs/model/world/universalid.hpp index f01e811ca..0a9fa3847 100644 --- a/apps/opencs/model/world/universalid.hpp +++ b/apps/opencs/model/world/universalid.hpp @@ -16,16 +16,16 @@ namespace CSMWorld enum Class { Class_None = 0, - Class_Record, - Class_RefRecord, // referenceable record - Class_SubRecord, - Class_RecordList, - Class_Collection, // multiple types of records combined - Class_Transient, // not part of the world data or the project data - Class_NonRecord, // record like data that is not part of the world - Class_Resource, ///< \attention Resource IDs are unique only within the + Class_Record = 1, + Class_RefRecord = 2, // referenceable record + Class_SubRecord = 4, + Class_RecordList = 8, + Class_Collection = 16, // multiple types of records combined + Class_Transient = 32, // not part of the world data or the project data + Class_NonRecord = 64, // record like data that is not part of the world + Class_Resource = 128, ///< \attention Resource IDs are unique only within the /// respective collection - Class_ResourceList + Class_ResourceList = 256 }; enum ArgumentType @@ -181,6 +181,8 @@ namespace CSMWorld static std::vector listReferenceableTypes(); + static std::vector listTypes (int classes); + /// If \a type is a SubRecord, RefRecord or Record type return the type of the table /// that contains records of type \a type. /// Otherwise return Type_None. From 1ec0db231c4d824683c8fd63485f3d50073e5b0f Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 28 Mar 2015 14:48:06 +0100 Subject: [PATCH 0846/3725] add a separate display type for ID column --- apps/opencs/model/world/columnbase.cpp | 2 ++ apps/opencs/model/world/columnbase.hpp | 3 ++- apps/opencs/model/world/columnimp.hpp | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/world/columnbase.cpp b/apps/opencs/model/world/columnbase.cpp index f4f2310b6..a736c0155 100644 --- a/apps/opencs/model/world/columnbase.cpp +++ b/apps/opencs/model/world/columnbase.cpp @@ -73,6 +73,8 @@ bool CSMWorld::ColumnBase::isId (Display display) Display_SoundRes, Display_Texture, Display_Video, + + Display_Id, Display_None }; diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index c49785154..38039c27c 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -103,7 +103,8 @@ namespace CSMWorld Display_Colour, Display_ScriptLines, // console context Display_SoundGeneratorType, - Display_School + Display_School, + Display_Id }; int mColumnId; diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index da14bb495..47b744b7f 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -43,7 +43,7 @@ namespace CSMWorld struct StringIdColumn : public Column { StringIdColumn (bool hidden = false) - : Column (Columns::ColumnId_Id, ColumnBase::Display_String, + : Column (Columns::ColumnId_Id, ColumnBase::Display_Id, hidden ? 0 : ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue) {} From 232e34bddd7f5bf0bd48d1292a5f94128dc45f46 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 28 Mar 2015 20:15:17 +0100 Subject: [PATCH 0847/3725] OpenCS: port lighting toolbar, fix multiple context GL objects issue --- apps/opencs/view/render/lighting.hpp | 15 ++- apps/opencs/view/render/lightingbright.cpp | 30 ++--- apps/opencs/view/render/lightingbright.hpp | 9 +- apps/opencs/view/render/lightingday.cpp | 35 +++--- apps/opencs/view/render/lightingday.hpp | 9 +- apps/opencs/view/render/lightingnight.cpp | 35 +++--- apps/opencs/view/render/lightingnight.hpp | 9 +- apps/opencs/view/render/previewwidget.cpp | 2 +- apps/opencs/view/render/scenewidget.cpp | 111 ++++++++++++++++-- apps/opencs/view/render/scenewidget.hpp | 46 +++++++- .../view/render/unpagedworldspacewidget.cpp | 12 +- apps/opencs/view/render/worldspacewidget.cpp | 10 +- apps/opencs/view/world/previewsubview.cpp | 4 +- apps/opencs/view/world/scenesubview.cpp | 4 +- components/esm/defs.hpp | 2 +- components/resource/scenemanager.cpp | 8 ++ components/resource/scenemanager.hpp | 2 + 17 files changed, 237 insertions(+), 106 deletions(-) diff --git a/apps/opencs/view/render/lighting.hpp b/apps/opencs/view/render/lighting.hpp index a1da9f7e3..eb8c97b12 100644 --- a/apps/opencs/view/render/lighting.hpp +++ b/apps/opencs/view/render/lighting.hpp @@ -1,10 +1,13 @@ #ifndef OPENCS_VIEW_LIGHTING_H #define OPENCS_VIEW_LIGHTING_H -namespace Ogre +namespace osgViewer { - class SceneManager; - class ColourValue; + class View; +} +namespace osg +{ + class Vec4f; } namespace CSVRender @@ -15,12 +18,12 @@ namespace CSVRender virtual ~Lighting(); - virtual void activate (Ogre::SceneManager *sceneManager, - const Ogre::ColourValue *defaultAmbient = 0) = 0; + virtual void activate (osgViewer::View* view, + const osg::Vec4f *defaultAmbient = 0) = 0; virtual void deactivate() = 0; - virtual void setDefaultAmbient (const Ogre::ColourValue& colour) = 0; + virtual void setDefaultAmbient (const osg::Vec4f& colour) = 0; }; } diff --git a/apps/opencs/view/render/lightingbright.cpp b/apps/opencs/view/render/lightingbright.cpp index a342ab093..6d3d4d790 100644 --- a/apps/opencs/view/render/lightingbright.cpp +++ b/apps/opencs/view/render/lightingbright.cpp @@ -3,28 +3,28 @@ #include -CSVRender::LightingBright::LightingBright() : mSceneManager (0), mLight (0) {} +#include -void CSVRender::LightingBright::activate (Ogre::SceneManager *sceneManager, - const Ogre::ColourValue *defaultAmbient) +CSVRender::LightingBright::LightingBright() : mView(NULL) {} + +void CSVRender::LightingBright::activate (osgViewer::View* view, + const osg::Vec4f* /*defaultAmbient*/) { - mSceneManager = sceneManager; + mView = view; + + // FIXME: ambient should be applied to LightModel instead of the light - mSceneManager->setAmbientLight (Ogre::ColourValue (1.0, 1.0, 1.0, 1)); + osg::ref_ptr light (new osg::Light); + light->setConstantAttenuation(1.f); + light->setDirection(osg::Vec3f(0.f, 0.f, -1.f)); + light->setDiffuse(osg::Vec4f(1.f, 1.f, 1.f, 1.f)); + light->setAmbient(osg::Vec4f(1.f, 1.f, 1.f, 1.f)); - mLight = mSceneManager->createLight(); - mLight->setType (Ogre::Light::LT_DIRECTIONAL); - mLight->setDirection (Ogre::Vector3 (0, 0, -1)); - mLight->setDiffuseColour (Ogre::ColourValue (1.0, 1.0, 1.0)); + mView->setLight(light); } void CSVRender::LightingBright::deactivate() { - if (mLight) - { - mSceneManager->destroyLight (mLight); - mLight = 0; - } } -void CSVRender::LightingBright::setDefaultAmbient (const Ogre::ColourValue& colour) {} +void CSVRender::LightingBright::setDefaultAmbient (const osg::Vec4f& colour) {} diff --git a/apps/opencs/view/render/lightingbright.hpp b/apps/opencs/view/render/lightingbright.hpp index bc01899cb..e7ef63f0a 100644 --- a/apps/opencs/view/render/lightingbright.hpp +++ b/apps/opencs/view/render/lightingbright.hpp @@ -12,19 +12,18 @@ namespace CSVRender { class LightingBright : public Lighting { - Ogre::SceneManager *mSceneManager; - Ogre::Light *mLight; + osgViewer::View* mView; public: LightingBright(); - virtual void activate (Ogre::SceneManager *sceneManager, - const Ogre::ColourValue *defaultAmbient = 0); + virtual void activate (osgViewer::View* view, + const osg::Vec4f *defaultAmbient = 0); virtual void deactivate(); - virtual void setDefaultAmbient (const Ogre::ColourValue& colour); + virtual void setDefaultAmbient (const osg::Vec4f& colour); }; } diff --git a/apps/opencs/view/render/lightingday.cpp b/apps/opencs/view/render/lightingday.cpp index c5189ccfd..1d8444bc3 100644 --- a/apps/opencs/view/render/lightingday.cpp +++ b/apps/opencs/view/render/lightingday.cpp @@ -1,36 +1,33 @@ - #include "lightingday.hpp" -#include +#include -CSVRender::LightingDay::LightingDay() : mSceneManager (0), mLight (0) {} +CSVRender::LightingDay::LightingDay() : mView(NULL) {} -void CSVRender::LightingDay::activate (Ogre::SceneManager *sceneManager, - const Ogre::ColourValue *defaultAmbient) +void CSVRender::LightingDay::activate (osgViewer::View* view, + const osg::Vec4f *defaultAmbient) { - mSceneManager = sceneManager; + mView = view; + + osg::ref_ptr light (new osg::Light); + light->setDirection(osg::Vec3f(0.f, 0.f, -1.f)); + light->setDiffuse(osg::Vec4f(1.f, 1.f, 1.f, 1.f)); + light->setConstantAttenuation(1.f); if (defaultAmbient) - mSceneManager->setAmbientLight (*defaultAmbient); + light->setAmbient(*defaultAmbient); else - mSceneManager->setAmbientLight (Ogre::ColourValue (0.7, 0.7, 0.7, 1)); + light->setAmbient(osg::Vec4f(0.7f, 0.7f, 0.7f, 1.f)); - mLight = mSceneManager->createLight(); - mLight->setType (Ogre::Light::LT_DIRECTIONAL); - mLight->setDirection (Ogre::Vector3 (0, 0, -1)); - mLight->setDiffuseColour (Ogre::ColourValue (1, 1, 1)); + mView->setLight(light); } void CSVRender::LightingDay::deactivate() { - if (mLight) - { - mSceneManager->destroyLight (mLight); - mLight = 0; - } } -void CSVRender::LightingDay::setDefaultAmbient (const Ogre::ColourValue& colour) +void CSVRender::LightingDay::setDefaultAmbient (const osg::Vec4f& colour) { - mSceneManager->setAmbientLight (colour); + if (mView) + mView->getLight()->setAmbient(colour); } diff --git a/apps/opencs/view/render/lightingday.hpp b/apps/opencs/view/render/lightingday.hpp index 8638146e2..a0f39b866 100644 --- a/apps/opencs/view/render/lightingday.hpp +++ b/apps/opencs/view/render/lightingday.hpp @@ -12,19 +12,18 @@ namespace CSVRender { class LightingDay : public Lighting { - Ogre::SceneManager *mSceneManager; - Ogre::Light *mLight; + osgViewer::View* mView; public: LightingDay(); - virtual void activate (Ogre::SceneManager *sceneManager, - const Ogre::ColourValue *defaultAmbient = 0); + virtual void activate (osgViewer::View* view, + const osg::Vec4f *defaultAmbient = 0); virtual void deactivate(); - virtual void setDefaultAmbient (const Ogre::ColourValue& colour); + virtual void setDefaultAmbient (const osg::Vec4f& colour); }; } diff --git a/apps/opencs/view/render/lightingnight.cpp b/apps/opencs/view/render/lightingnight.cpp index 7d94dc964..81236ec13 100644 --- a/apps/opencs/view/render/lightingnight.cpp +++ b/apps/opencs/view/render/lightingnight.cpp @@ -1,36 +1,33 @@ - #include "lightingnight.hpp" -#include +#include -CSVRender::LightingNight::LightingNight() : mSceneManager (0), mLight (0) {} +CSVRender::LightingNight::LightingNight() : mView(NULL) {} -void CSVRender::LightingNight::activate (Ogre::SceneManager *sceneManager, - const Ogre::ColourValue *defaultAmbient) +void CSVRender::LightingNight::activate (osgViewer::View* view, + const osg::Vec4f *defaultAmbient) { - mSceneManager = sceneManager; + mView = view; + + osg::ref_ptr light (new osg::Light); + light->setDirection(osg::Vec3f(0.f, 0.f, -1.f)); + light->setDiffuse(osg::Vec4f(0.2f, 0.2f, 0.2f, 1.f)); + light->setConstantAttenuation(1.f); if (defaultAmbient) - mSceneManager->setAmbientLight (*defaultAmbient); + light->setAmbient(*defaultAmbient); else - mSceneManager->setAmbientLight (Ogre::ColourValue (0.2, 0.2, 0.2, 1)); + light->setAmbient(osg::Vec4f(0.2f, 0.2f, 0.2f, 1.f)); - mLight = mSceneManager->createLight(); - mLight->setType (Ogre::Light::LT_DIRECTIONAL); - mLight->setDirection (Ogre::Vector3 (0, 0, -1)); - mLight->setDiffuseColour (Ogre::ColourValue (0.2, 0.2, 0.2)); + mView->setLight(light); } void CSVRender::LightingNight::deactivate() { - if (mLight) - { - mSceneManager->destroyLight (mLight); - mLight = 0; - } } -void CSVRender::LightingNight::setDefaultAmbient (const Ogre::ColourValue& colour) +void CSVRender::LightingNight::setDefaultAmbient (const osg::Vec4f& colour) { - mSceneManager->setAmbientLight (colour); + if (mView) + mView->getLight()->setAmbient(colour); } diff --git a/apps/opencs/view/render/lightingnight.hpp b/apps/opencs/view/render/lightingnight.hpp index 47d1d7ce8..b2fd17893 100644 --- a/apps/opencs/view/render/lightingnight.hpp +++ b/apps/opencs/view/render/lightingnight.hpp @@ -12,19 +12,18 @@ namespace CSVRender { class LightingNight : public Lighting { - Ogre::SceneManager *mSceneManager; - Ogre::Light *mLight; + osgViewer::View* mView; public: LightingNight(); - virtual void activate (Ogre::SceneManager *sceneManager, - const Ogre::ColourValue *defaultAmbient = 0); + virtual void activate (osgViewer::View* view, + const osg::Vec4f *defaultAmbient = 0); virtual void deactivate(); - virtual void setDefaultAmbient (const Ogre::ColourValue& colour); + virtual void setDefaultAmbient (const osg::Vec4f& colour); }; } diff --git a/apps/opencs/view/render/previewwidget.cpp b/apps/opencs/view/render/previewwidget.cpp index 02fcd9f06..f0cbc939a 100644 --- a/apps/opencs/view/render/previewwidget.cpp +++ b/apps/opencs/view/render/previewwidget.cpp @@ -8,7 +8,7 @@ CSVRender::PreviewWidget::PreviewWidget (CSMWorld::Data& data, const std::string& id, bool referenceable, QWidget *parent) -: SceneWidget (parent), mData (data), mObject(data, mRootNode, id, referenceable) +: SceneWidget (data.getResourceSystem()->getSceneManager(), parent), mData (data), mObject(data, mRootNode, id, referenceable) { mView->setCameraManipulator(new osgGA::TrackballManipulator); diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index d7a85410b..ef2d701c6 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -6,21 +6,23 @@ #include #include +#include +#include +#include +#include + +#include + #include "../widget/scenetoolmode.hpp" #include "../../model/settings/usersettings.hpp" #include "navigation.hpp" #include "lighting.hpp" -#include -#include -#include -#include - namespace CSVRender { -SceneWidget::SceneWidget(QWidget *parent, Qt::WindowFlags f) +RenderWidget::RenderWidget(QWidget *parent, Qt::WindowFlags f) : QWidget(parent, f) , mRootNode(0) { @@ -58,9 +60,8 @@ SceneWidget::SceneWidget(QWidget *parent, Qt::WindowFlags f) mView->getCamera()->setProjectionMatrixAsPerspective(30.0f, static_cast(traits->width)/static_cast(traits->height), 1.0f, 10000.0f ); mRootNode = new osg::Group; - // TODO: move to utility file - mRootNode->getOrCreateStateSet()->setMode(GL_NORMALIZE, osg::StateAttribute::ON); - mRootNode->getOrCreateStateSet()->setMode(GL_CULL_FACE, osg::StateAttribute::ON); + + addDefaultRootState(mRootNode->getOrCreateStateSet()); mView->setSceneData(mRootNode); @@ -74,22 +75,30 @@ SceneWidget::SceneWidget(QWidget *parent, Qt::WindowFlags f) viewer.realize(); } -SceneWidget::~SceneWidget() +void RenderWidget::addDefaultRootState(osg::StateSet* stateset) +{ + stateset->setMode(GL_NORMALIZE, osg::StateAttribute::ON); + stateset->setMode(GL_CULL_FACE, osg::StateAttribute::ON); +} + +RenderWidget::~RenderWidget() { CompositeViewer::get().removeView(mView); } -void SceneWidget::flagAsModified() +void RenderWidget::flagAsModified() { mView->requestRedraw(); } -void SceneWidget::setVisibilityMask(int mask) +void RenderWidget::setVisibilityMask(int mask) { // 0x1 reserved for separating cull and update visitors mView->getCamera()->setCullMask(mask<<1); } +// -------------------------------------------------- + CompositeViewer::CompositeViewer() { #if QT_VERSION >= 0x050000 @@ -109,7 +118,7 @@ CompositeViewer::CompositeViewer() setRunFrameScheme(osgViewer::ViewerBase::CONTINUOUS); connect( &mTimer, SIGNAL(timeout()), this, SLOT(update()) ); - mTimer.start( 0 ); + mTimer.start( 10 ); } CompositeViewer &CompositeViewer::get() @@ -123,4 +132,80 @@ void CompositeViewer::update() frame(); } +// --------------------------------------------------- + +SceneWidget::SceneWidget(Resource::SceneManager* sceneManager, QWidget *parent, Qt::WindowFlags f) + : RenderWidget(parent, f) + , mSceneManager(sceneManager) + , mLighting(NULL) +{ + //mView->setLightingMode(osgViewer::View::NO_LIGHT); + + setLighting(&mLightingDay); +} + +SceneWidget::~SceneWidget() +{ + // Since we're holding on to the scene templates past the existance of this graphics context, we'll need to manually release the created objects + mSceneManager->releaseGLObjects(mView->getCamera()->getGraphicsContext()->getState()); +} + +void SceneWidget::setLighting(Lighting *lighting) +{ + if (mLighting) + mLighting->deactivate(); + + mLighting = lighting; + mLighting->activate (mView.get(), mHasDefaultAmbient ? &mDefaultAmbient : 0); + + flagAsModified(); +} + +void SceneWidget::selectLightingMode (const std::string& mode) +{ + if (mode=="day") + setLighting (&mLightingDay); + else if (mode=="night") + setLighting (&mLightingNight); + else if (mode=="bright") + setLighting (&mLightingBright); +} + +CSVWidget::SceneToolMode *SceneWidget::makeLightingSelector (CSVWidget::SceneToolbar *parent) +{ + CSVWidget::SceneToolMode *tool = new CSVWidget::SceneToolMode (parent, "Lighting Mode"); + + /// \todo replace icons + tool->addButton (":scenetoolbar/day", "day", + "Day" + "
  • Cell specific ambient in interiors
  • " + "
  • Low ambient in exteriors
  • " + "
  • Strong directional light source
  • " + "
  • This mode closely resembles day time in-game
"); + tool->addButton (":scenetoolbar/night", "night", + "Night" + "
  • Cell specific ambient in interiors
  • " + "
  • Low ambient in exteriors
  • " + "
  • Weak directional light source
  • " + "
  • This mode closely resembles night time in-game
"); + tool->addButton (":scenetoolbar/bright", "bright", + "Bright" + "
  • Maximum ambient
  • " + "
  • Strong directional light source
"); + + connect (tool, SIGNAL (modeChanged (const std::string&)), + this, SLOT (selectLightingMode (const std::string&))); + + return tool; +} + +void SceneWidget::setDefaultAmbient (const osg::Vec4f& colour) +{ + mDefaultAmbient = colour; + mHasDefaultAmbient = true; + + if (mLighting) + mLighting->setDefaultAmbient (colour); +} + } diff --git a/apps/opencs/view/render/scenewidget.hpp b/apps/opencs/view/render/scenewidget.hpp index 04025340d..8580a2bb1 100644 --- a/apps/opencs/view/render/scenewidget.hpp +++ b/apps/opencs/view/render/scenewidget.hpp @@ -11,6 +11,11 @@ #include #include +namespace Resource +{ + class SceneManager; +} + namespace osg { class Group; @@ -27,13 +32,13 @@ namespace CSVRender class Navigation; class Lighting; - class SceneWidget : public QWidget + class RenderWidget : public QWidget { Q_OBJECT public: - SceneWidget(QWidget* parent = 0, Qt::WindowFlags f = 0); - ~SceneWidget(); + RenderWidget(QWidget* parent = 0, Qt::WindowFlags f = 0); + virtual ~RenderWidget(); void flagAsModified(); @@ -41,6 +46,8 @@ namespace CSVRender protected: + void addDefaultRootState(osg::StateSet* stateset); + osg::ref_ptr mView; osg::Group* mRootNode; @@ -48,6 +55,39 @@ namespace CSVRender QTimer mTimer; }; + // Extension of RenderWidget to support lighting mode selection & toolbar + class SceneWidget : public RenderWidget + { + Q_OBJECT + public: + SceneWidget(Resource::SceneManager* sceneManager, QWidget* parent = 0, Qt::WindowFlags f = 0); + virtual ~SceneWidget(); + + CSVWidget::SceneToolMode *makeLightingSelector (CSVWidget::SceneToolbar *parent); + ///< \attention The created tool is not added to the toolbar (via addTool). Doing that + /// is the responsibility of the calling function. + + void setDefaultAmbient (const osg::Vec4f& colour); + ///< \note The actual ambient colour may differ based on lighting settings. + + protected: + void setLighting (Lighting *lighting); + ///< \attention The ownership of \a lighting is not transferred to *this. + + Resource::SceneManager* mSceneManager; + + Lighting* mLighting; + + osg::Vec4f mDefaultAmbient; + bool mHasDefaultAmbient; + LightingDay mLightingDay; + LightingNight mLightingNight; + LightingBright mLightingBright; + + private slots: + + void selectLightingMode (const std::string& mode); + }; // There are rendering glitches when using multiple Viewer instances, work around using CompositeViewer with multiple views diff --git a/apps/opencs/view/render/unpagedworldspacewidget.cpp b/apps/opencs/view/render/unpagedworldspacewidget.cpp index e48b84cff..a6d18a0f2 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.cpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.cpp @@ -23,9 +23,12 @@ void CSVRender::UnpagedWorldspaceWidget::update() const CSMWorld::Record& record = dynamic_cast&> (mCellsModel->getRecord (mCellId)); - Ogre::ColourValue colour; - colour.setAsABGR (record.get().mAmbi.mAmbient); - //setDefaultAmbient (colour); + ESM::Color clr = record.get().mAmbi.mAmbient; + osg::Vec4f colour(((clr >> 0) & 0xFF) / 255.0f, + ((clr >> 8) & 0xFF) / 255.0f, + ((clr >> 16) & 0xFF) / 255.0f, 1.f); + + setDefaultAmbient (colour); /// \todo deal with mSunlight and mFog/mForDensity @@ -51,7 +54,6 @@ CSVRender::UnpagedWorldspaceWidget::UnpagedWorldspaceWidget (const std::string& mCell.reset (new Cell (document.getData(), mRootNode, mCellId)); mView->setCameraManipulator(new osgGA::TrackballManipulator); - //mView->setCameraManipulator(new osgGA::FirstPersonManipulator); } void CSVRender::UnpagedWorldspaceWidget::cellDataChanged (const QModelIndex& topLeft, @@ -93,7 +95,7 @@ bool CSVRender::UnpagedWorldspaceWidget::handleDrop (const std::vectorgetId(); - // FIXME: we shouldn't need to rebuild the whole cell + mCell.reset (new Cell (getDocument().getData(), mRootNode, mCellId)); update(); diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 4bbfd5bcd..2d7a0a0f8 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -19,7 +19,7 @@ #include "editmode.hpp" CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidget* parent) -: SceneWidget (parent), mDocument(document), mSceneElements(0), mRun(0), +: SceneWidget (document.getData().getResourceSystem()->getSceneManager(), parent), mDocument(document), mSceneElements(0), mRun(0), mInteractionMask (0) { setAcceptDrops(true); @@ -361,7 +361,7 @@ void CSVRender::WorldspaceWidget::mouseMoveEvent (QMouseEvent *event) { //mMouse->mouseMoveEvent(event); } - SceneWidget::mouseMoveEvent(event); + RenderWidget::mouseMoveEvent(event); } void CSVRender::WorldspaceWidget::mousePressEvent (QMouseEvent *event) @@ -386,7 +386,7 @@ void CSVRender::WorldspaceWidget::mouseReleaseEvent (QMouseEvent *event) */ //mMouse->mouseReleaseEvent(event); } - SceneWidget::mouseReleaseEvent(event); + RenderWidget::mouseReleaseEvent(event); } void CSVRender::WorldspaceWidget::mouseDoubleClickEvent (QMouseEvent *event) @@ -401,7 +401,7 @@ void CSVRender::WorldspaceWidget::mouseDoubleClickEvent (QMouseEvent *event) void CSVRender::WorldspaceWidget::wheelEvent (QWheelEvent *event) { //if(!mMouse->wheelEvent(event)) - SceneWidget::wheelEvent(event); + RenderWidget::wheelEvent(event); } void CSVRender::WorldspaceWidget::keyPressEvent (QKeyEvent *event) @@ -411,5 +411,5 @@ void CSVRender::WorldspaceWidget::keyPressEvent (QKeyEvent *event) //mMouse->cancelDrag(); } else - SceneWidget::keyPressEvent(event); + RenderWidget::keyPressEvent(event); } diff --git a/apps/opencs/view/world/previewsubview.cpp b/apps/opencs/view/world/previewsubview.cpp index 0c9823c44..1c2d6b95c 100644 --- a/apps/opencs/view/world/previewsubview.cpp +++ b/apps/opencs/view/world/previewsubview.cpp @@ -30,8 +30,8 @@ CSVWorld::PreviewSubView::PreviewSubView (const CSMWorld::UniversalId& id, CSMDo CSVWidget::SceneToolbar *toolbar = new CSVWidget::SceneToolbar (48+6, this); - //CSVWidget::SceneToolMode *lightingTool = mScene->makeLightingSelector (toolbar); - //toolbar->addTool (lightingTool); + CSVWidget::SceneToolMode *lightingTool = mScene->makeLightingSelector (toolbar); + toolbar->addTool (lightingTool); layout->addWidget (toolbar, 0); diff --git a/apps/opencs/view/world/scenesubview.cpp b/apps/opencs/view/world/scenesubview.cpp index c59236ee5..3fdf2f6e5 100644 --- a/apps/opencs/view/world/scenesubview.cpp +++ b/apps/opencs/view/world/scenesubview.cpp @@ -107,8 +107,8 @@ CSVWidget::SceneToolbar* CSVWorld::SceneSubView::makeToolbar (CSVRender::Worldsp CSVWidget::SceneToolMode *navigationTool = widget->makeNavigationSelector (toolbar); toolbar->addTool (navigationTool); - //CSVWidget::SceneToolMode *lightingTool = widget->makeLightingSelector (toolbar); - //toolbar->addTool (lightingTool); + CSVWidget::SceneToolMode *lightingTool = widget->makeLightingSelector (toolbar); + toolbar->addTool (lightingTool); CSVWidget::SceneToolToggle2 *sceneVisibilityTool = widget->makeSceneVisibilitySelector (toolbar); diff --git a/components/esm/defs.hpp b/components/esm/defs.hpp index 7ef8102c2..d261d7247 100644 --- a/components/esm/defs.hpp +++ b/components/esm/defs.hpp @@ -13,7 +13,7 @@ struct TimeStamp }; // Pixel color value. Standard four-byte rr,gg,bb,aa format. -typedef int32_t Color; +typedef uint32_t Color; enum Specialization { diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index c44cbd2ae..3f38762ca 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -115,4 +115,12 @@ namespace Resource instance->accept(visitor); } + void SceneManager::releaseGLObjects(osg::State *state) + { + for (Index::iterator it = mIndex.begin(); it != mIndex.end(); ++it) + { + it->second->releaseGLObjects(state); + } + } + } diff --git a/components/resource/scenemanager.hpp b/components/resource/scenemanager.hpp index 3d439c186..7b3bcb2d5 100644 --- a/components/resource/scenemanager.hpp +++ b/components/resource/scenemanager.hpp @@ -41,6 +41,8 @@ namespace Resource /// @note Assumes the given instance was not attached to any parents before. void attachTo(osg::Node* instance, osg::Group* parentNode) const; + void releaseGLObjects(osg::State* state); + private: const VFS::Manager* mVFS; Resource::TextureManager* mTextureManager; From 173887c2d9a856dbb213ced2f7e3cb51385906a9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 28 Mar 2015 21:19:16 +0100 Subject: [PATCH 0848/3725] AlphaController copy fix --- components/nifosg/controller.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index eca5a7d79..76d3c5e62 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -364,6 +364,7 @@ AlphaController::AlphaController() AlphaController::AlphaController(const AlphaController ©, const osg::CopyOp ©op) : osg::NodeCallback(copy, copyop), ValueInterpolator(), Controller(copy) + , mData(copy.mData) { } From 00deacc27e13a5fcd6cb4d3b859d2ed64a971ca7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 28 Mar 2015 21:26:16 +0100 Subject: [PATCH 0849/3725] OpenCS: lighting modes --- apps/opencs/view/render/lighting.cpp | 3 +- apps/opencs/view/render/lighting.hpp | 19 +++++++----- apps/opencs/view/render/lightingbright.cpp | 29 ++++++++++-------- apps/opencs/view/render/lightingbright.hpp | 10 +++---- apps/opencs/view/render/lightingday.cpp | 31 +++++++++++--------- apps/opencs/view/render/lightingday.hpp | 7 ++--- apps/opencs/view/render/lightingnight.cpp | 30 ++++++++++--------- apps/opencs/view/render/lightingnight.hpp | 8 ++--- apps/opencs/view/render/scenewidget.cpp | 34 +++++++++++++++------- apps/opencs/view/render/scenewidget.hpp | 4 +-- 10 files changed, 98 insertions(+), 77 deletions(-) diff --git a/apps/opencs/view/render/lighting.cpp b/apps/opencs/view/render/lighting.cpp index 3553ef58c..8e068168f 100644 --- a/apps/opencs/view/render/lighting.cpp +++ b/apps/opencs/view/render/lighting.cpp @@ -1,4 +1,5 @@ - #include "lighting.hpp" +#include + CSVRender::Lighting::~Lighting() {} diff --git a/apps/opencs/view/render/lighting.hpp b/apps/opencs/view/render/lighting.hpp index eb8c97b12..a4315d02f 100644 --- a/apps/opencs/view/render/lighting.hpp +++ b/apps/opencs/view/render/lighting.hpp @@ -1,13 +1,13 @@ #ifndef OPENCS_VIEW_LIGHTING_H #define OPENCS_VIEW_LIGHTING_H -namespace osgViewer -{ - class View; -} +#include + namespace osg { class Vec4f; + class LightSource; + class Group; } namespace CSVRender @@ -16,14 +16,19 @@ namespace CSVRender { public: + Lighting() : mRootNode(0) {} virtual ~Lighting(); - virtual void activate (osgViewer::View* view, - const osg::Vec4f *defaultAmbient = 0) = 0; + virtual void activate (osg::Group* rootNode) = 0; virtual void deactivate() = 0; - virtual void setDefaultAmbient (const osg::Vec4f& colour) = 0; + virtual osg::Vec4f getAmbientColour(osg::Vec4f* defaultAmbient) = 0; + + protected: + + osg::ref_ptr mLightSource; + osg::Group* mRootNode; }; } diff --git a/apps/opencs/view/render/lightingbright.cpp b/apps/opencs/view/render/lightingbright.cpp index 6d3d4d790..035e57c56 100644 --- a/apps/opencs/view/render/lightingbright.cpp +++ b/apps/opencs/view/render/lightingbright.cpp @@ -1,30 +1,35 @@ #include "lightingbright.hpp" -#include +#include -#include +CSVRender::LightingBright::LightingBright() {} -CSVRender::LightingBright::LightingBright() : mView(NULL) {} - -void CSVRender::LightingBright::activate (osgViewer::View* view, - const osg::Vec4f* /*defaultAmbient*/) +void CSVRender::LightingBright::activate (osg::Group* rootNode) { - mView = view; + mRootNode = rootNode; - // FIXME: ambient should be applied to LightModel instead of the light + mLightSource = (new osg::LightSource); osg::ref_ptr light (new osg::Light); - light->setConstantAttenuation(1.f); + light->setAmbient(osg::Vec4f(0.f, 0.f, 0.f, 1.f)); light->setDirection(osg::Vec3f(0.f, 0.f, -1.f)); light->setDiffuse(osg::Vec4f(1.f, 1.f, 1.f, 1.f)); - light->setAmbient(osg::Vec4f(1.f, 1.f, 1.f, 1.f)); + light->setSpecular(osg::Vec4f(0.f, 0.f, 0.f, 0.f)); + light->setConstantAttenuation(1.f); - mView->setLight(light); + mLightSource->setLight(light); + + mRootNode->addChild(mLightSource); } void CSVRender::LightingBright::deactivate() { + if (mRootNode && mLightSource.get()) + mRootNode->removeChild(mLightSource); } -void CSVRender::LightingBright::setDefaultAmbient (const osg::Vec4f& colour) {} +osg::Vec4f CSVRender::LightingBright::getAmbientColour(osg::Vec4f* /*defaultAmbient*/) +{ + return osg::Vec4f(1.f, 1.f, 1.f, 1.f); +} diff --git a/apps/opencs/view/render/lightingbright.hpp b/apps/opencs/view/render/lightingbright.hpp index e7ef63f0a..bc6422814 100644 --- a/apps/opencs/view/render/lightingbright.hpp +++ b/apps/opencs/view/render/lightingbright.hpp @@ -3,27 +3,25 @@ #include "lighting.hpp" -namespace Ogre +namespace osg { class Light; + class Group; } namespace CSVRender { class LightingBright : public Lighting { - osgViewer::View* mView; - public: LightingBright(); - virtual void activate (osgViewer::View* view, - const osg::Vec4f *defaultAmbient = 0); + virtual void activate (osg::Group* rootNode); virtual void deactivate(); - virtual void setDefaultAmbient (const osg::Vec4f& colour); + virtual osg::Vec4f getAmbientColour(osg::Vec4f* defaultAmbient); }; } diff --git a/apps/opencs/view/render/lightingday.cpp b/apps/opencs/view/render/lightingday.cpp index 1d8444bc3..376f3e432 100644 --- a/apps/opencs/view/render/lightingday.cpp +++ b/apps/opencs/view/render/lightingday.cpp @@ -1,33 +1,36 @@ #include "lightingday.hpp" -#include +#include -CSVRender::LightingDay::LightingDay() : mView(NULL) {} +CSVRender::LightingDay::LightingDay(){} -void CSVRender::LightingDay::activate (osgViewer::View* view, - const osg::Vec4f *defaultAmbient) +void CSVRender::LightingDay::activate (osg::Group* rootNode) { - mView = view; + mRootNode = rootNode; + + mLightSource = new osg::LightSource; osg::ref_ptr light (new osg::Light); light->setDirection(osg::Vec3f(0.f, 0.f, -1.f)); + light->setAmbient(osg::Vec4f(0.f, 0.f, 0.f, 1.f)); light->setDiffuse(osg::Vec4f(1.f, 1.f, 1.f, 1.f)); + light->setSpecular(osg::Vec4f(0.f, 0.f, 0.f, 0.f)); light->setConstantAttenuation(1.f); - if (defaultAmbient) - light->setAmbient(*defaultAmbient); - else - light->setAmbient(osg::Vec4f(0.7f, 0.7f, 0.7f, 1.f)); - - mView->setLight(light); + mLightSource->setLight(light); + mRootNode->addChild(mLightSource); } void CSVRender::LightingDay::deactivate() { + if (mRootNode && mLightSource.get()) + mRootNode->removeChild(mLightSource); } -void CSVRender::LightingDay::setDefaultAmbient (const osg::Vec4f& colour) +osg::Vec4f CSVRender::LightingDay::getAmbientColour(osg::Vec4f *defaultAmbient) { - if (mView) - mView->getLight()->setAmbient(colour); + if (defaultAmbient) + return *defaultAmbient; + else + return osg::Vec4f(0.7f, 0.7f, 0.7f, 1.f); } diff --git a/apps/opencs/view/render/lightingday.hpp b/apps/opencs/view/render/lightingday.hpp index a0f39b866..407933ec6 100644 --- a/apps/opencs/view/render/lightingday.hpp +++ b/apps/opencs/view/render/lightingday.hpp @@ -12,18 +12,15 @@ namespace CSVRender { class LightingDay : public Lighting { - osgViewer::View* mView; - public: LightingDay(); - virtual void activate (osgViewer::View* view, - const osg::Vec4f *defaultAmbient = 0); + virtual void activate (osg::Group* rootNode); virtual void deactivate(); - virtual void setDefaultAmbient (const osg::Vec4f& colour); + virtual osg::Vec4f getAmbientColour(osg::Vec4f *defaultAmbient); }; } diff --git a/apps/opencs/view/render/lightingnight.cpp b/apps/opencs/view/render/lightingnight.cpp index 81236ec13..18a12d63d 100644 --- a/apps/opencs/view/render/lightingnight.cpp +++ b/apps/opencs/view/render/lightingnight.cpp @@ -1,33 +1,37 @@ #include "lightingnight.hpp" -#include +#include -CSVRender::LightingNight::LightingNight() : mView(NULL) {} +CSVRender::LightingNight::LightingNight() {} -void CSVRender::LightingNight::activate (osgViewer::View* view, - const osg::Vec4f *defaultAmbient) +void CSVRender::LightingNight::activate (osg::Group* rootNode) { - mView = view; + mRootNode = rootNode; + + mLightSource = new osg::LightSource; osg::ref_ptr light (new osg::Light); light->setDirection(osg::Vec3f(0.f, 0.f, -1.f)); + light->setAmbient(osg::Vec4f(0.f, 0.f, 0.f, 1.f)); light->setDiffuse(osg::Vec4f(0.2f, 0.2f, 0.2f, 1.f)); + light->setSpecular(osg::Vec4f(0.f, 0.f, 0.f, 0.f)); light->setConstantAttenuation(1.f); - if (defaultAmbient) - light->setAmbient(*defaultAmbient); - else - light->setAmbient(osg::Vec4f(0.2f, 0.2f, 0.2f, 1.f)); + mLightSource->setLight(light); - mView->setLight(light); + mRootNode->addChild(mLightSource); } void CSVRender::LightingNight::deactivate() { + if (mRootNode && mLightSource.get()) + mRootNode->removeChild(mLightSource); } -void CSVRender::LightingNight::setDefaultAmbient (const osg::Vec4f& colour) +osg::Vec4f CSVRender::LightingNight::getAmbientColour(osg::Vec4f *defaultAmbient) { - if (mView) - mView->getLight()->setAmbient(colour); + if (defaultAmbient) + return *defaultAmbient; + else + return osg::Vec4f(0.2f, 0.2f, 0.2f, 1.f); } diff --git a/apps/opencs/view/render/lightingnight.hpp b/apps/opencs/view/render/lightingnight.hpp index b2fd17893..8743cc438 100644 --- a/apps/opencs/view/render/lightingnight.hpp +++ b/apps/opencs/view/render/lightingnight.hpp @@ -12,18 +12,14 @@ namespace CSVRender { class LightingNight : public Lighting { - osgViewer::View* mView; - public: LightingNight(); - virtual void activate (osgViewer::View* view, - const osg::Vec4f *defaultAmbient = 0); - + virtual void activate (osg::Group* rootNode); virtual void deactivate(); - virtual void setDefaultAmbient (const osg::Vec4f& colour); + virtual osg::Vec4f getAmbientColour(osg::Vec4f *defaultAmbient); }; } diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index ef2d701c6..593775970 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -10,6 +10,8 @@ #include #include #include +#include +#include #include @@ -61,7 +63,8 @@ RenderWidget::RenderWidget(QWidget *parent, Qt::WindowFlags f) mRootNode = new osg::Group; - addDefaultRootState(mRootNode->getOrCreateStateSet()); + mView->getCamera()->getOrCreateStateSet()->setMode(GL_NORMALIZE, osg::StateAttribute::ON); + mView->getCamera()->getOrCreateStateSet()->setMode(GL_CULL_FACE, osg::StateAttribute::ON); mView->setSceneData(mRootNode); @@ -75,12 +78,6 @@ RenderWidget::RenderWidget(QWidget *parent, Qt::WindowFlags f) viewer.realize(); } -void RenderWidget::addDefaultRootState(osg::StateSet* stateset) -{ - stateset->setMode(GL_NORMALIZE, osg::StateAttribute::ON); - stateset->setMode(GL_CULL_FACE, osg::StateAttribute::ON); -} - RenderWidget::~RenderWidget() { CompositeViewer::get().removeView(mView); @@ -138,8 +135,10 @@ SceneWidget::SceneWidget(Resource::SceneManager* sceneManager, QWidget *parent, : RenderWidget(parent, f) , mSceneManager(sceneManager) , mLighting(NULL) + , mHasDefaultAmbient(false) { - //mView->setLightingMode(osgViewer::View::NO_LIGHT); + // we handle lighting manually + mView->setLightingMode(osgViewer::View::NO_LIGHT); setLighting(&mLightingDay); } @@ -156,11 +155,25 @@ void SceneWidget::setLighting(Lighting *lighting) mLighting->deactivate(); mLighting = lighting; - mLighting->activate (mView.get(), mHasDefaultAmbient ? &mDefaultAmbient : 0); + mLighting->activate (mRootNode); + + osg::Vec4f ambient = mLighting->getAmbientColour(mHasDefaultAmbient ? &mDefaultAmbient : 0); + setAmbient(ambient); flagAsModified(); } +void SceneWidget::setAmbient(const osg::Vec4f& ambient) +{ + osg::ref_ptr stateset = new osg::StateSet; + osg::ref_ptr lightmodel = new osg::LightModel; + lightmodel->setAmbientIntensity(ambient); + stateset->setMode(GL_LIGHTING, osg::StateAttribute::ON); + stateset->setMode(GL_LIGHT0, osg::StateAttribute::ON); + stateset->setAttributeAndModes(lightmodel, osg::StateAttribute::ON); + mRootNode->setStateSet(stateset); +} + void SceneWidget::selectLightingMode (const std::string& mode) { if (mode=="day") @@ -204,8 +217,7 @@ void SceneWidget::setDefaultAmbient (const osg::Vec4f& colour) mDefaultAmbient = colour; mHasDefaultAmbient = true; - if (mLighting) - mLighting->setDefaultAmbient (colour); + setAmbient(mLighting->getAmbientColour(&mDefaultAmbient)); } } diff --git a/apps/opencs/view/render/scenewidget.hpp b/apps/opencs/view/render/scenewidget.hpp index 8580a2bb1..acfc0bbd4 100644 --- a/apps/opencs/view/render/scenewidget.hpp +++ b/apps/opencs/view/render/scenewidget.hpp @@ -46,8 +46,6 @@ namespace CSVRender protected: - void addDefaultRootState(osg::StateSet* stateset); - osg::ref_ptr mView; osg::Group* mRootNode; @@ -74,6 +72,8 @@ namespace CSVRender void setLighting (Lighting *lighting); ///< \attention The ownership of \a lighting is not transferred to *this. + void setAmbient(const osg::Vec4f& ambient); + Resource::SceneManager* mSceneManager; Lighting* mLighting; From 6183926732771d401b257fc64653be27ef5b07ce Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 28 Mar 2015 22:21:16 +0100 Subject: [PATCH 0850/3725] Particle fix --- components/nifosg/particle.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/nifosg/particle.cpp b/components/nifosg/particle.cpp index c6e5fa9a8..c86a79af8 100644 --- a/components/nifosg/particle.cpp +++ b/components/nifosg/particle.cpp @@ -81,8 +81,8 @@ void ParticleShooter::shoot(osgParticle::Particle *particle) const { float hdir = mHorizontalDir + mHorizontalAngle * (2.f * (std::rand() / static_cast(RAND_MAX)) - 1.f); float vdir = mVerticalDir + mVerticalAngle * (2.f * (std::rand() / static_cast(RAND_MAX)) - 1.f); - float vdir2 = mVerticalDir + mVerticalAngle * (2.f * (std::rand() / static_cast(RAND_MAX)) - 1.f); - osg::Vec3f dir = (osg::Quat(vdir2, osg::Vec3f(1,0,0)) * osg::Quat(vdir, osg::Vec3f(0,1,0)) * osg::Quat(hdir, osg::Vec3f(0,0,1))) + + osg::Vec3f dir = (osg::Quat(vdir, osg::Vec3f(0,1,0)) * osg::Quat(hdir, osg::Vec3f(0,0,1))) * osg::Vec3f(0,0,1); float vel = mMinSpeed + (mMaxSpeed - mMinSpeed) * std::rand() / static_cast(RAND_MAX); From 4042b120130a971e234b08a6a9826d4c15b56d0b Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 29 Mar 2015 13:43:11 +0200 Subject: [PATCH 0851/3725] changed data structure for report model --- apps/opencs/model/tools/reportmodel.cpp | 20 +++++++++++++------- apps/opencs/model/tools/reportmodel.hpp | 12 +++++++++++- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/apps/opencs/model/tools/reportmodel.cpp b/apps/opencs/model/tools/reportmodel.cpp index acd4728c6..cc6c5a44c 100644 --- a/apps/opencs/model/tools/reportmodel.cpp +++ b/apps/opencs/model/tools/reportmodel.cpp @@ -3,6 +3,12 @@ #include +CSMTools::ReportModel::Line::Line (const CSMWorld::UniversalId& id, const std::string& message, + const std::string& hint) +: mId (id), mMessage (message), mHint (hint) +{} + + int CSMTools::ReportModel::rowCount (const QModelIndex & parent) const { if (parent.isValid()) @@ -25,12 +31,12 @@ QVariant CSMTools::ReportModel::data (const QModelIndex & index, int role) const return QVariant(); if (index.column()==0) - return static_cast (mRows.at (index.row()).first.getType()); + return static_cast (mRows.at (index.row()).mId.getType()); if (index.column()==1) - return QString::fromUtf8 (mRows.at (index.row()).second.first.c_str()); + return QString::fromUtf8 (mRows.at (index.row()).mMessage.c_str()); - return QString::fromUtf8 (mRows.at (index.row()).second.second.c_str()); + return QString::fromUtf8 (mRows.at (index.row()).mHint.c_str()); } QVariant CSMTools::ReportModel::headerData (int section, Qt::Orientation orientation, int role) const @@ -64,20 +70,20 @@ void CSMTools::ReportModel::add (const CSMWorld::UniversalId& id, const std::str const std::string& hint) { beginInsertRows (QModelIndex(), mRows.size(), mRows.size()); - - mRows.push_back (std::make_pair (id, std::make_pair (message, hint))); + + mRows.push_back (Line (id, message, hint)); endInsertRows(); } const CSMWorld::UniversalId& CSMTools::ReportModel::getUniversalId (int row) const { - return mRows.at (row).first; + return mRows.at (row).mId; } std::string CSMTools::ReportModel::getHint (int row) const { - return mRows.at (row).second.second; + return mRows.at (row).mHint; } void CSMTools::ReportModel::clear() diff --git a/apps/opencs/model/tools/reportmodel.hpp b/apps/opencs/model/tools/reportmodel.hpp index 71f5bdf73..64a477b6c 100644 --- a/apps/opencs/model/tools/reportmodel.hpp +++ b/apps/opencs/model/tools/reportmodel.hpp @@ -14,7 +14,17 @@ namespace CSMTools { Q_OBJECT - std::vector > > mRows; + struct Line + { + Line (const CSMWorld::UniversalId& id, const std::string& message, + const std::string& hint); + + CSMWorld::UniversalId mId; + std::string mMessage; + std::string mHint; + }; + + std::vector mRows; public: From a8cdd30124669136d360be0c869c9f1182ea8655 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 29 Mar 2015 13:55:31 +0200 Subject: [PATCH 0852/3725] added ID column to report table --- apps/opencs/model/tools/reportmodel.cpp | 44 ++++++++++++++++++------- apps/opencs/model/tools/reportmodel.hpp | 5 +++ 2 files changed, 37 insertions(+), 12 deletions(-) diff --git a/apps/opencs/model/tools/reportmodel.cpp b/apps/opencs/model/tools/reportmodel.cpp index cc6c5a44c..218f391c9 100644 --- a/apps/opencs/model/tools/reportmodel.cpp +++ b/apps/opencs/model/tools/reportmodel.cpp @@ -22,7 +22,7 @@ int CSMTools::ReportModel::columnCount (const QModelIndex & parent) const if (parent.isValid()) return 0; - return 3; + return 4; } QVariant CSMTools::ReportModel::data (const QModelIndex & index, int role) const @@ -30,13 +30,32 @@ QVariant CSMTools::ReportModel::data (const QModelIndex & index, int role) const if (role!=Qt::DisplayRole) return QVariant(); - if (index.column()==0) - return static_cast (mRows.at (index.row()).mId.getType()); + switch (index.column()) + { + case Column_Type: + + return static_cast (mRows.at (index.row()).mId.getType()); + + case Column_Id: + { + CSMWorld::UniversalId id = mRows.at (index.row()).mId; + + if (id.getArgumentType()==CSMWorld::UniversalId::ArgumentType_Id) + return QString::fromUtf8 (id.getId().c_str()); - if (index.column()==1) - return QString::fromUtf8 (mRows.at (index.row()).mMessage.c_str()); + return QString ("-"); + } + + case Column_Description: - return QString::fromUtf8 (mRows.at (index.row()).mHint.c_str()); + return QString::fromUtf8 (mRows.at (index.row()).mMessage.c_str()); + + case Column_Hint: + + return QString::fromUtf8 (mRows.at (index.row()).mHint.c_str()); + } + + return QVariant(); } QVariant CSMTools::ReportModel::headerData (int section, Qt::Orientation orientation, int role) const @@ -47,13 +66,14 @@ QVariant CSMTools::ReportModel::headerData (int section, Qt::Orientation orienta if (orientation==Qt::Vertical) return QVariant(); - if (section==0) - return "Type"; - - if (section==1) - return "Description"; + switch (section) + { + case Column_Type: return "Type"; + case Column_Id: return "ID"; + case Column_Description: return "Description"; + } - return "Hint"; + return "-"; } bool CSMTools::ReportModel::removeRows (int row, int count, const QModelIndex& parent) diff --git a/apps/opencs/model/tools/reportmodel.hpp b/apps/opencs/model/tools/reportmodel.hpp index 64a477b6c..5f39316aa 100644 --- a/apps/opencs/model/tools/reportmodel.hpp +++ b/apps/opencs/model/tools/reportmodel.hpp @@ -26,6 +26,11 @@ namespace CSMTools std::vector mRows; + enum Columns + { + Column_Type = 0, Column_Id = 1, Column_Hint = 2, Column_Description = 3 + }; + public: virtual int rowCount (const QModelIndex & parent = QModelIndex()) const; From 416b8165cdbd694a8a6690361ef585a2a5adfa52 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 29 Mar 2015 15:28:11 +0200 Subject: [PATCH 0853/3725] moved getColumnId function from IdTable to IdTable base and made it virtual --- apps/opencs/model/world/idtable.hpp | 2 +- apps/opencs/model/world/idtablebase.hpp | 2 ++ apps/opencs/model/world/resourcetable.cpp | 11 +++++++++++ apps/opencs/model/world/resourcetable.hpp | 2 ++ 4 files changed, 16 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/world/idtable.hpp b/apps/opencs/model/world/idtable.hpp index ea8ab80f9..6f4be7178 100644 --- a/apps/opencs/model/world/idtable.hpp +++ b/apps/opencs/model/world/idtable.hpp @@ -82,7 +82,7 @@ namespace CSMWorld /// Is \a id flagged as deleted? virtual bool isDeleted (const std::string& id) const; - int getColumnId(int column) const; + virtual int getColumnId(int column) const; }; } diff --git a/apps/opencs/model/world/idtablebase.hpp b/apps/opencs/model/world/idtablebase.hpp index ef5a9c42e..0d77d48ef 100644 --- a/apps/opencs/model/world/idtablebase.hpp +++ b/apps/opencs/model/world/idtablebase.hpp @@ -60,6 +60,8 @@ namespace CSMWorld /// Is \a id flagged as deleted? virtual bool isDeleted (const std::string& id) const = 0; + virtual int getColumnId (int column) const = 0; + unsigned int getFeatures() const; }; } diff --git a/apps/opencs/model/world/resourcetable.cpp b/apps/opencs/model/world/resourcetable.cpp index 9257b9d2a..36e2b3f3d 100644 --- a/apps/opencs/model/world/resourcetable.cpp +++ b/apps/opencs/model/world/resourcetable.cpp @@ -144,3 +144,14 @@ bool CSMWorld::ResourceTable::isDeleted (const std::string& id) const { return false; } + +int CSMWorld::ResourceTable::getColumnId (int column) const +{ + switch (column) + { + case 0: return Columns::ColumnId_Id; + case 1: return Columns::ColumnId_RecordType; + } + + return -1; +} diff --git a/apps/opencs/model/world/resourcetable.hpp b/apps/opencs/model/world/resourcetable.hpp index f5011ab2b..88dcc24b0 100644 --- a/apps/opencs/model/world/resourcetable.hpp +++ b/apps/opencs/model/world/resourcetable.hpp @@ -51,6 +51,8 @@ namespace CSMWorld /// Is \a id flagged as deleted? virtual bool isDeleted (const std::string& id) const; + + virtual int getColumnId (int column) const; }; } From e8091c4e7e21964187d8edd50c5d45685629c7bb Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 29 Mar 2015 15:28:31 +0200 Subject: [PATCH 0854/3725] added field column to report table --- apps/opencs/model/tools/reportmodel.cpp | 51 ++++++++++++++++++++++--- apps/opencs/model/tools/reportmodel.hpp | 9 ++++- apps/opencs/model/tools/search.cpp | 6 ++- apps/opencs/model/tools/tools.cpp | 2 +- 4 files changed, 59 insertions(+), 9 deletions(-) diff --git a/apps/opencs/model/tools/reportmodel.cpp b/apps/opencs/model/tools/reportmodel.cpp index 218f391c9..627199c22 100644 --- a/apps/opencs/model/tools/reportmodel.cpp +++ b/apps/opencs/model/tools/reportmodel.cpp @@ -2,12 +2,29 @@ #include "reportmodel.hpp" #include +#include + +#include "../world/columns.hpp" CSMTools::ReportModel::Line::Line (const CSMWorld::UniversalId& id, const std::string& message, const std::string& hint) : mId (id), mMessage (message), mHint (hint) {} +CSMTools::ReportModel::ReportModel (bool fieldColumn) +{ + if (fieldColumn) + { + mColumnField = 3; + mColumnDescription = 4; + } + else + { + mColumnDescription = 3; + + mColumnField = -1; + } +} int CSMTools::ReportModel::rowCount (const QModelIndex & parent) const { @@ -22,7 +39,7 @@ int CSMTools::ReportModel::columnCount (const QModelIndex & parent) const if (parent.isValid()) return 0; - return 4; + return mColumnDescription+1; } QVariant CSMTools::ReportModel::data (const QModelIndex & index, int role) const @@ -46,15 +63,32 @@ QVariant CSMTools::ReportModel::data (const QModelIndex & index, int role) const return QString ("-"); } - case Column_Description: - - return QString::fromUtf8 (mRows.at (index.row()).mMessage.c_str()); - case Column_Hint: return QString::fromUtf8 (mRows.at (index.row()).mHint.c_str()); } + if (index.column()==mColumnDescription) + return QString::fromUtf8 (mRows.at (index.row()).mMessage.c_str()); + + if (index.column()==mColumnField) + { + std::string field; + + std::istringstream stream (mRows.at (index.row()).mHint); + + char type, ignore; + int fieldIndex; + + if ((stream >> type >> ignore >> fieldIndex) && type=='r') + { + field = CSMWorld::Columns::getName ( + static_cast (fieldIndex)); + } + + return QString::fromUtf8 (field.c_str()); + } + return QVariant(); } @@ -70,9 +104,14 @@ QVariant CSMTools::ReportModel::headerData (int section, Qt::Orientation orienta { case Column_Type: return "Type"; case Column_Id: return "ID"; - case Column_Description: return "Description"; } + if (section==mColumnDescription) + return "Description"; + + if (section==mColumnField) + return "Field"; + return "-"; } diff --git a/apps/opencs/model/tools/reportmodel.hpp b/apps/opencs/model/tools/reportmodel.hpp index 5f39316aa..7e733fab6 100644 --- a/apps/opencs/model/tools/reportmodel.hpp +++ b/apps/opencs/model/tools/reportmodel.hpp @@ -26,13 +26,20 @@ namespace CSMTools std::vector mRows; + // Fixed columns enum Columns { - Column_Type = 0, Column_Id = 1, Column_Hint = 2, Column_Description = 3 + Column_Type = 0, Column_Id = 1, Column_Hint = 2 }; + // Configurable columns + int mColumnDescription; + int mColumnField; + public: + ReportModel (bool fieldColumn = false); + virtual int rowCount (const QModelIndex & parent = QModelIndex()) const; virtual int columnCount (const QModelIndex & parent = QModelIndex()) const; diff --git a/apps/opencs/model/tools/search.cpp b/apps/opencs/model/tools/search.cpp index 2d3e4f952..a0eb429b0 100644 --- a/apps/opencs/model/tools/search.cpp +++ b/apps/opencs/model/tools/search.cpp @@ -27,7 +27,11 @@ void CSMTools::Search::searchTextCell (const CSMWorld::IdTableBase *model, message << getLocation (model, index, id) << text.mid (pos).toUtf8().data(); std::ostringstream hint; - hint << "r: " << index.column() << " " << pos << " " << search.length(); + hint + << "r: " + << model->getColumnId (index.column()) + << " " << pos + << " " << search.length(); messages.add (id, message.str(), hint.str()); diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index 957e20296..970a8ac4f 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -147,7 +147,7 @@ CSMWorld::UniversalId CSMTools::Tools::runVerifier() CSMWorld::UniversalId CSMTools::Tools::newSearch() { - mReports.insert (std::make_pair (mNextReportNumber++, new ReportModel)); + mReports.insert (std::make_pair (mNextReportNumber++, new ReportModel (true))); return CSMWorld::UniversalId (CSMWorld::UniversalId::Type_Search, mNextReportNumber-1); } From 46ccd27a6de028a4e7459a850f26f413289d9011 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 29 Mar 2015 18:16:43 +0200 Subject: [PATCH 0855/3725] improved find result text --- apps/opencs/model/tools/search.cpp | 48 ++++++++++++++++++------------ apps/opencs/model/tools/search.hpp | 2 +- 2 files changed, 30 insertions(+), 20 deletions(-) diff --git a/apps/opencs/model/tools/search.cpp b/apps/opencs/model/tools/search.cpp index a0eb429b0..9f1beb064 100644 --- a/apps/opencs/model/tools/search.cpp +++ b/apps/opencs/model/tools/search.cpp @@ -23,9 +23,6 @@ void CSMTools::Search::searchTextCell (const CSMWorld::IdTableBase *model, while ((pos = text.indexOf (search, pos, Qt::CaseInsensitive))!=-1) { - std::ostringstream message; - message << getLocation (model, index, id) << text.mid (pos).toUtf8().data(); - std::ostringstream hint; hint << "r: " @@ -33,7 +30,7 @@ void CSMTools::Search::searchTextCell (const CSMWorld::IdTableBase *model, << " " << pos << " " << search.length(); - messages.add (id, message.str(), hint.str()); + messages.add (id, formatDescription (text, pos, search.length()).toUtf8().data(), hint.str()); pos += search.length(); } @@ -49,15 +46,12 @@ void CSMTools::Search::searchRegExCell (const CSMWorld::IdTableBase *model, while ((pos = mRegExp.indexIn (text, pos))!=-1) { - std::ostringstream message; - message << getLocation (model, index, id) << text.mid (pos).toUtf8().data(); - int length = mRegExp.matchedLength(); std::ostringstream hint; - hint << "r: " << index.column() << " " << pos << " " << length; + hint << "r: " << model->getColumnId (index.column()) << " " << pos << " " << length; - messages.add (id, message.str(), hint.str()); + messages.add (id, formatDescription (text, pos, length).toUtf8().data(), hint.str()); pos += length; } @@ -74,26 +68,42 @@ void CSMTools::Search::searchRecordStateCell (const CSMWorld::IdTableBase *model CSMWorld::Columns::getEnums (CSMWorld::Columns::ColumnId_Modification); std::ostringstream message; - message << getLocation (model, index, id) << states.at (data); + message << states.at (data); std::ostringstream hint; - hint << "r: " << index.column(); + hint << "r: " << model->getColumnId (index.column()); messages.add (id, message.str(), hint.str()); } } -std::string CSMTools::Search::getLocation (const CSMWorld::IdTableBase *model, const QModelIndex& index, const CSMWorld::UniversalId& id) const +QString CSMTools::Search::formatDescription (const QString& description, int pos, int length) const { - std::ostringstream stream; + int padding = 10; ///< \todo make this configurable + + if (posheaderData (index.column(), Qt::Horizontal).toString().toUtf8().data() - << ": "; + QString text = description.mid (pos, length); + + // compensate for Windows nonsense + text.remove ('\r'); - return stream.str(); + // improve layout for single line display + text.replace ("\n", ""); + text.replace ('\t', ' '); + + return text; } CSMTools::Search::Search() : mType (Type_None) {} diff --git a/apps/opencs/model/tools/search.hpp b/apps/opencs/model/tools/search.hpp index 81b8840bf..320323f03 100644 --- a/apps/opencs/model/tools/search.hpp +++ b/apps/opencs/model/tools/search.hpp @@ -56,7 +56,7 @@ namespace CSMTools const QModelIndex& index, const CSMWorld::UniversalId& id, CSMDoc::Messages& messages) const; - std::string getLocation (const CSMWorld::IdTableBase *model, const QModelIndex& index, const CSMWorld::UniversalId& id) const; + QString formatDescription (const QString& description, int pos, int length) const; public: From 6d165dabb64ab1475cdec15c99435019530b5622 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 29 Mar 2015 18:21:18 +0200 Subject: [PATCH 0856/3725] improved layout of report table --- apps/opencs/view/tools/reporttable.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/opencs/view/tools/reporttable.cpp b/apps/opencs/view/tools/reporttable.cpp index 5eb375f46..5bf1fa848 100644 --- a/apps/opencs/view/tools/reporttable.cpp +++ b/apps/opencs/view/tools/reporttable.cpp @@ -71,6 +71,7 @@ CSVTools::ReportTable::ReportTable (CSMDoc::Document& document, : CSVWorld::DragRecordTable (document, parent), mModel (document.getReport (id)) { horizontalHeader()->setResizeMode (QHeaderView::Interactive); + horizontalHeader()->setStretchLastSection (true); verticalHeader()->hide(); setSortingEnabled (true); setSelectionBehavior (QAbstractItemView::SelectRows); From a7272b73d07de539bf0ed2c0181a198546becd98 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 29 Mar 2015 04:12:54 +0200 Subject: [PATCH 0857/3725] Add utility for assembling body parts / equipment --- components/CMakeLists.txt | 2 +- components/sceneutil/attach.cpp | 185 ++++++++++++++++++++++++++++++++ components/sceneutil/attach.hpp | 25 +++++ 3 files changed, 211 insertions(+), 1 deletion(-) create mode 100644 components/sceneutil/attach.cpp create mode 100644 components/sceneutil/attach.hpp diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 47fcf2499..9d9ae4f31 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -43,7 +43,7 @@ add_component_dir (resource ) add_component_dir (sceneutil - clone + clone attach ) add_component_dir (nif diff --git a/components/sceneutil/attach.cpp b/components/sceneutil/attach.cpp new file mode 100644 index 000000000..7cfb80b5c --- /dev/null +++ b/components/sceneutil/attach.cpp @@ -0,0 +1,185 @@ +#include "attach.hpp" + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +namespace SceneUtil +{ + + class FindByNameVisitor : public osg::NodeVisitor + { + public: + FindByNameVisitor(const std::string& nameToFind) + : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) + , mNameToFind(nameToFind) + , mFoundNode(NULL) + { + } + + virtual void apply(osg::Node &node) + { + osg::Group* group = node.asGroup(); + if (group && node.getName() == mNameToFind) + { + mFoundNode = group; + return; + } + traverse(node); + } + + const std::string& mNameToFind; + osg::Group* mFoundNode; + }; + + /// Copy the skeleton-space matrix of a "source" bone to a "dest" bone (the bone that the callback is attached to). + /// Must be set on a Bone. + class CopyController : public osg::NodeCallback + { + public: + CopyController(osgAnimation::Bone* copyFrom) + : mCopyFrom(copyFrom) + { + } + CopyController(const CopyController& copy, const osg::CopyOp& copyop) + : osg::NodeCallback(copy, copyop) + , mCopyFrom(copy.mCopyFrom) + { + } + CopyController() + : mCopyFrom(NULL) + { + } + + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) + { + osgAnimation::Bone* bone = static_cast(node); + + if (mCopyFrom) + { + bone->setMatrix(mCopyFrom->getMatrix()); + bone->setMatrixInSkeletonSpace(mCopyFrom->getMatrixInSkeletonSpace()); + } + + traverse(node, nv); + } + + private: + const osgAnimation::Bone* mCopyFrom; + }; + + class AddCopyControllerVisitor : public osg::NodeVisitor + { + public: + AddCopyControllerVisitor(const osgAnimation::BoneMap& boneMap) + : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) + , mBoneMap(boneMap) + { + } + + virtual void apply(osg::MatrixTransform &node) + { + if (osgAnimation::Bone* bone = dynamic_cast(&node)) + { + osgAnimation::BoneMap::const_iterator found = mBoneMap.find(bone->getName()); + if (found != mBoneMap.end()) + { + bone->setUpdateCallback(new CopyController(found->second.get())); + } + } + } + + private: + const osgAnimation::BoneMap& mBoneMap; + }; + + // FIXME: would be more efficient to copy only the wanted nodes instead of deleting unwanted ones later + class FilterVisitor : public osg::NodeVisitor + { + public: + FilterVisitor(const std::string& filter) + : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) + , mFilter(filter) + { + } + + virtual void apply(osg::Geode &node) + { + if (node.getName().find(mFilter) == std::string::npos) + { + mToRemove.push_back(&node); + } + } + + void removeFilteredParts() + { + for (std::vector::iterator it = mToRemove.begin(); it != mToRemove.end(); ++it) + { + osg::Geode* geode = *it; + geode->getParent(0)->removeChild(geode); + } + } + + private: + std::vector mToRemove; + const std::string& mFilter; + }; + + osg::ref_ptr attach(osg::ref_ptr toAttach, osg::Node *master, const std::string &filter, const std::string &attachNode) + { + if (osgAnimation::Skeleton* skel = dynamic_cast(toAttach.get())) + { + osgAnimation::Skeleton* masterSkel = dynamic_cast(master); + osgAnimation::BoneMapVisitor boneMapVisitor; + masterSkel->accept(boneMapVisitor); + + AddCopyControllerVisitor visitor(boneMapVisitor.getBoneMap()); + toAttach->accept(visitor); + + FilterVisitor filterVisitor(filter); + toAttach->accept(filterVisitor); + filterVisitor.removeFilteredParts(); + + master->asGroup()->addChild(skel); + return skel; + } + else + { + FindByNameVisitor find(attachNode); + master->accept(find); + if (!find.mFoundNode) + throw std::runtime_error(std::string("Can't find attachment node ") + attachNode); + + if (attachNode.find("Left") != std::string::npos) + { + osg::ref_ptr trans = new osg::PositionAttitudeTransform; + trans->setScale(osg::Vec3f(-1.f, 1.f, 1.f)); + + // Need to invert culling because of the negative scale + // Note: for absolute correctness we would need to check the current front face for every mesh then invert it + // However MW isn't doing this either, so don't. Assuming all meshes are using backface culling is more efficient. + osg::FrontFace* frontFace = new osg::FrontFace; + frontFace->setMode(osg::FrontFace::CLOCKWISE); + toAttach->getOrCreateStateSet()->setAttributeAndModes(frontFace, osg::StateAttribute::ON); + + find.mFoundNode->addChild(trans); + trans->addChild(toAttach); + return trans; + } + else + { + find.mFoundNode->addChild(toAttach); + return toAttach; + } + } + } + +} diff --git a/components/sceneutil/attach.hpp b/components/sceneutil/attach.hpp new file mode 100644 index 000000000..72f7809e9 --- /dev/null +++ b/components/sceneutil/attach.hpp @@ -0,0 +1,25 @@ +#ifndef OPENMW_COMPONENTS_SCENEUTIL_ATTACH_H +#define OPENMW_COMPONENTS_SCENEUTIL_ATTACH_H + +#include + +#include + +namespace osg +{ + class Node; +} + +namespace SceneUtil +{ + + /// Attach parts of the \a toAttach scenegraph to the \a master scenegraph, using the specified filter and attachment node. + /// If the \a toAttach scene graph contains skinned objects, we will attach only those (filtered by the \a filter). + /// Otherwise, just attach all of the toAttach scenegraph to the attachment node on the master scenegraph, with no filtering. + /// @note The master scene graph is expected to include a skeleton. + /// @return A newly created node that is directly attached to the master scene graph + osg::ref_ptr attach(osg::ref_ptr toAttach, osg::Node* master, const std::string& filter, const std::string& attachNode); + +} + +#endif From 5162e9c09efbc5158dea0f6750b52f96a3a1f8bc Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 29 Mar 2015 18:44:46 +0200 Subject: [PATCH 0858/3725] Add comment --- components/sceneutil/attach.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/sceneutil/attach.cpp b/components/sceneutil/attach.cpp index 7cfb80b5c..6208d0152 100644 --- a/components/sceneutil/attach.cpp +++ b/components/sceneutil/attach.cpp @@ -141,6 +141,8 @@ namespace SceneUtil osgAnimation::BoneMapVisitor boneMapVisitor; masterSkel->accept(boneMapVisitor); + // would be more efficient if we could attach the RigGeometry directly to the master skeleton, but currently not possible + // due to a difference in binding pose of the two skeletons AddCopyControllerVisitor visitor(boneMapVisitor.getBoneMap()); toAttach->accept(visitor); From 9975ec1678a011e4b04fb7cad9c9296f04981e80 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 29 Mar 2015 19:32:55 +0200 Subject: [PATCH 0859/3725] Missing clone function --- components/nifosg/nifloader.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index ace14c669..9006c16ef 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -334,6 +334,8 @@ namespace { } + META_Object(NifOsg, DirtyBoundCallback) + void operator()(osg::Node* node, osg::NodeVisitor* nv) { osg::Geode* geode = node->asGeode(); From 34934f016ad0b8d92dc9f77ff6492252a2c584b9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 30 Mar 2015 01:51:50 +0200 Subject: [PATCH 0860/3725] Remove obsoleted OpenCS settings and comment non-ported settings --- apps/opencs/model/settings/usersettings.cpp | 34 +++------------------ 1 file changed, 4 insertions(+), 30 deletions(-) diff --git a/apps/opencs/model/settings/usersettings.cpp b/apps/opencs/model/settings/usersettings.cpp index 0aa1cb4ad..ed8fbf6d0 100644 --- a/apps/opencs/model/settings/usersettings.cpp +++ b/apps/opencs/model/settings/usersettings.cpp @@ -12,8 +12,6 @@ #include #include -#include - /** * Workaround for problems with whitespaces in paths in older versions of Boost library */ @@ -44,13 +42,9 @@ CSMSettings::UserSettings *CSMSettings::UserSettings::sUserSettingsInstance = 0; void CSMSettings::UserSettings::buildSettingModelDefaults() { - QString section; - + /* declareSection ("3d-render", "3D Rendering"); { - Setting *shaders = createSetting (Type_CheckBox, "shaders", "Enable Shaders"); - shaders->setDefaultValue ("true"); - Setting *farClipDist = createSetting (Type_DoubleSpinBox, "far-clip-distance", "Far clipping distance"); farClipDist->setDefaultValue (300000); farClipDist->setRange (0, 1000000); @@ -62,23 +56,11 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() << defaultValue << "MSAA 2" << "MSAA 4" << "MSAA 8" << "MSAA 16"); antialiasing->setDefaultValue (defaultValue); } + */ - declareSection ("3d-render-adv", "3D Rendering (Advanced)"); - { - Setting *numLights = createSetting (Type_SpinBox, "num_lights", - "Number of lights per pass"); - numLights->setDefaultValue (8); - numLights->setRange (1, 100); - } - + /* declareSection ("scene-input", "Scene Input"); { - Setting *timer = createSetting (Type_SpinBox, "timer", "Input responsiveness"); - timer->setDefaultValue (20); - timer->setRange (1, 100); - timer->setToolTip ("The time between two checks for user input in milliseconds.

" - "Lower value result in higher responsiveness."); - Setting *fastFactor = createSetting (Type_SpinBox, "fast-factor", "Fast movement factor"); fastFactor->setDefaultValue (4); @@ -86,6 +68,7 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() fastFactor->setToolTip ( "Factor by which movement is speed up while the shift key is held down."); } + */ declareSection ("window", "Window"); { @@ -470,15 +453,6 @@ void CSMSettings::UserSettings::updateUserSetting(const QString &settingKey, { mSettingDefinitions->setValue (settingKey ,list); - if(settingKey == "3d-render-adv/num_lights" && !list.empty()) - { - //sh::Factory::getInstance ().setGlobalSetting ("num_lights", list.at(0).toStdString()); - } - else if(settingKey == "3d-render/shaders" && !list.empty()) - { - //sh::Factory::getInstance ().setShadersEnabled (list.at(0).toStdString() == "true" ? true : false); - } - emit userSettingUpdated (settingKey, list); } From 3d280a6ba54c192ae6a3e9ebaef7621985dc0f3d Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 30 Mar 2015 11:19:37 +1100 Subject: [PATCH 0861/3725] Fixed the display issues of the nested tables in the dialogue subview. Needs further work but usable for now. --- apps/opencs/model/world/columns.cpp | 32 +++++---- apps/opencs/model/world/columns.hpp | 76 +++++++++++----------- apps/opencs/view/world/dialoguesubview.cpp | 75 ++++++++++++++------- 3 files changed, 109 insertions(+), 74 deletions(-) diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index c8bf8ad64..1d3bc7641 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -24,7 +24,6 @@ namespace CSMWorld { ColumnId_ValueType, "Value Type" }, { ColumnId_Description, "Description" }, { ColumnId_Specialisation, "Specialisation" }, - { ColumnId_Skill, "Skill" }, { ColumnId_Attribute, "Attribute" }, { ColumnId_Name, "Name" }, { ColumnId_Playable, "Playable" }, @@ -174,10 +173,11 @@ namespace CSMWorld { ColumnId_Gender, "Gender" }, { ColumnId_PcRank, "PC Rank" }, { ColumnId_ReferenceableId, "Referenceable ID" }, - { ColumnId_NpcDestinations, "Destinations" }, + + { ColumnId_ContainerContent, "Content" }, + { ColumnId_ItemCount, "Count" }, { ColumnId_InventoryItemId, "ID"}, - { ColumnId_SpellId, "ID"}, - { ColumnId_ItemCount, "Count"}, + { ColumnId_CombatState, "Combat" }, { ColumnId_MagicState, "Magic" }, { ColumnId_StealthState, "Stealth" }, @@ -185,6 +185,22 @@ namespace CSMWorld { ColumnId_Vampire, "Vampire" }, { ColumnId_BodyPartType, "Bodypart Type" }, { ColumnId_MeshType, "Mesh Type" }, + + { ColumnId_ActorInventory, "Inventory" }, + { ColumnId_ActorSpells, "Spells" }, + { ColumnId_SpellId, "ID"}, + + { ColumnId_NpcDestinations, "Destinations" }, + { ColumnId_DestinationCell, "Cell"}, + { ColumnId_PosX, "X"}, + { ColumnId_PosY, "Y"}, + { ColumnId_PosZ, "Z"}, + { ColumnId_RotX, "Rotation X"}, + { ColumnId_RotY, "Rotation Y"}, + { ColumnId_RotZ, "Rotation Z"}, + + { ColumnId_Skill, "Skill" }, + { ColumnId_OwnerGlobal, "Owner Global" }, { ColumnId_DefaultProfile, "Default Profile" }, { ColumnId_BypassNewGame, "Bypass New Game" }, @@ -206,14 +222,6 @@ namespace CSMWorld { ColumnId_HitSound, "Hit Sound" }, { ColumnId_AreaSound, "Area Sound" }, { ColumnId_BoltSound, "Bolt Sound" }, - - { ColumnId_NpcDestinations, "Cell"}, - { ColumnId_PosX, "X"}, - { ColumnId_PosY, "Y"}, - { ColumnId_PosZ, "Z"}, - { ColumnId_RotX, "Rotation X"}, - { ColumnId_RotY, "Rotation Y"}, - { ColumnId_RotZ, "Rotation Z"}, { ColumnId_UseValue1, "Use value 1" }, { ColumnId_UseValue2, "Use value 2" }, diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 69bbfa39f..1c0af217b 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -167,50 +167,50 @@ namespace CSMWorld ColumnId_Rank = 152, ColumnId_Gender = 153, ColumnId_PcRank = 154, - ColumnId_ReferenceableId = 156, - ColumnId_ContainerContent = 157, - ColumnId_ItemCount = 158, - ColumnId_InventoryItemId = 159, - ColumnId_CombatState = 160, - ColumnId_MagicState = 161, - ColumnId_StealthState = 162, - ColumnId_EnchantmentType = 163, - ColumnId_Vampire = 164, - ColumnId_BodyPartType = 165, - ColumnId_MeshType = 166, - ColumnId_ActorInventory = 167, - ColumnId_ActorSpells = 168, - ColumnId_SpellId = 169, - ColumnId_NpcDestinations = 170, + ColumnId_ReferenceableId = 155, + ColumnId_ContainerContent = 156, + ColumnId_ItemCount = 157, + ColumnId_InventoryItemId = 158, + ColumnId_CombatState = 159, + ColumnId_MagicState = 160, + ColumnId_StealthState = 161, + ColumnId_EnchantmentType = 162, + ColumnId_Vampire = 163, + ColumnId_BodyPartType = 164, + ColumnId_MeshType = 165, + ColumnId_ActorInventory = 166, + ColumnId_ActorSpells = 167, + ColumnId_SpellId = 168, + ColumnId_NpcDestinations = 169, + ColumnId_DestinationCell = 170, ColumnId_PosX = 171, ColumnId_PosY = 172, ColumnId_PosZ = 173, ColumnId_RotX = 174, ColumnId_RotY = 175, ColumnId_RotZ = 176, - ColumnId_DestinationCell = 177, - ColumnId_Skill = 178, - ColumnId_OwnerGlobal = 164, - ColumnId_DefaultProfile = 165, - ColumnId_BypassNewGame = 166, - ColumnId_GlobalProfile = 167, - ColumnId_RefNumCounter = 168, - ColumnId_RefNum = 169, - ColumnId_Creature = 170, - ColumnId_SoundGeneratorType = 171, - ColumnId_AllowSpellmaking = 172, - ColumnId_AllowEnchanting = 173, - ColumnId_BaseCost = 174, - ColumnId_School = 175, - ColumnId_Particle = 176, - ColumnId_CastingObject = 177, - ColumnId_HitObject = 178, - ColumnId_AreaObject = 179, - ColumnId_BoltObject = 180, - ColumnId_CastingSound = 177, - ColumnId_HitSound = 178, - ColumnId_AreaSound = 179, - ColumnId_BoltSound = 180, + ColumnId_Skill = 177, + ColumnId_OwnerGlobal = 178, + ColumnId_DefaultProfile = 179, + ColumnId_BypassNewGame = 180, + ColumnId_GlobalProfile = 181, + ColumnId_RefNumCounter = 182, + ColumnId_RefNum = 183, + ColumnId_Creature = 184, + ColumnId_SoundGeneratorType = 185, + ColumnId_AllowSpellmaking = 186, + ColumnId_AllowEnchanting = 187, + ColumnId_BaseCost = 188, + ColumnId_School = 189, + ColumnId_Particle = 190, + ColumnId_CastingObject = 191, + ColumnId_HitObject = 192, + ColumnId_AreaObject = 193, + ColumnId_BoltObject = 194, + ColumnId_CastingSound = 195, + ColumnId_HitSound = 196, + ColumnId_AreaSound = 197, + ColumnId_BoltSound = 198, // Allocated to a separate value range, so we don't get a collision should we ever need // to extend the number of use values. ColumnId_UseValue1 = 0x10000, diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 8d51bbf7e..421e12c13 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include "../../model/world/nestedtablemodel.hpp" @@ -139,26 +140,26 @@ void CSVWorld::DialogueDelegateDispatcherProxy::tableMimeDataDropped(const std:: CSMWorld::UniversalId::Type type = data[i].getType(); if (mDisplay == CSMWorld::ColumnBase::Display_Referenceable) { - if ( type == CSMWorld::UniversalId::Type_Activator - || type == CSMWorld::UniversalId::Type_Potion - || type == CSMWorld::UniversalId::Type_Apparatus - || type == CSMWorld::UniversalId::Type_Armor - || type == CSMWorld::UniversalId::Type_Book - || type == CSMWorld::UniversalId::Type_Clothing - || type == CSMWorld::UniversalId::Type_Container - || type == CSMWorld::UniversalId::Type_Creature - || type == CSMWorld::UniversalId::Type_Door - || type == CSMWorld::UniversalId::Type_Ingredient - || type == CSMWorld::UniversalId::Type_CreatureLevelledList - || type == CSMWorld::UniversalId::Type_ItemLevelledList - || type == CSMWorld::UniversalId::Type_Light - || type == CSMWorld::UniversalId::Type_Lockpick - || type == CSMWorld::UniversalId::Type_Miscellaneous - || type == CSMWorld::UniversalId::Type_Npc - || type == CSMWorld::UniversalId::Type_Probe - || type == CSMWorld::UniversalId::Type_Repair - || type == CSMWorld::UniversalId::Type_Static - || type == CSMWorld::UniversalId::Type_Weapon) + if (type == CSMWorld::UniversalId::Type_Activator + || type == CSMWorld::UniversalId::Type_Potion + || type == CSMWorld::UniversalId::Type_Apparatus + || type == CSMWorld::UniversalId::Type_Armor + || type == CSMWorld::UniversalId::Type_Book + || type == CSMWorld::UniversalId::Type_Clothing + || type == CSMWorld::UniversalId::Type_Container + || type == CSMWorld::UniversalId::Type_Creature + || type == CSMWorld::UniversalId::Type_Door + || type == CSMWorld::UniversalId::Type_Ingredient + || type == CSMWorld::UniversalId::Type_CreatureLevelledList + || type == CSMWorld::UniversalId::Type_ItemLevelledList + || type == CSMWorld::UniversalId::Type_Light + || type == CSMWorld::UniversalId::Type_Lockpick + || type == CSMWorld::UniversalId::Type_Miscellaneous + || type == CSMWorld::UniversalId::Type_Npc + || type == CSMWorld::UniversalId::Type_Probe + || type == CSMWorld::UniversalId::Type_Repair + || type == CSMWorld::UniversalId::Type_Static + || type == CSMWorld::UniversalId::Type_Weapon) { type = CSMWorld::UniversalId::Type_Referenceable; } @@ -388,6 +389,12 @@ void CSVWorld::EditWidget::remake(int row) line->setFrameShape(QFrame::HLine); line->setFrameShadow(QFrame::Sunken); + QFrame* line2 = new QFrame(mMainWidget); + line2->setObjectName(QString::fromUtf8("line2")); + line2->setGeometry(QRect(320, 150, 118, 3)); + line2->setFrameShape(QFrame::HLine); + line2->setFrameShadow(QFrame::Sunken); + QVBoxLayout *mainLayout = new QVBoxLayout(mMainWidget); QGridLayout *unlockedLayout = new QGridLayout(); QGridLayout *lockedLayout = new QGridLayout(); @@ -396,7 +403,8 @@ void CSVWorld::EditWidget::remake(int row) mainLayout->addLayout(lockedLayout, 0); mainLayout->addWidget(line, 1); mainLayout->addLayout(unlockedLayout, 2); - mainLayout->addLayout(tablesLayout, 3); + mainLayout->addWidget(line2, 1); + mainLayout->addLayout(tablesLayout, 0); mainLayout->addStretch(1); int unlocked = 0; @@ -416,10 +424,28 @@ void CSVWorld::EditWidget::remake(int row) { mNestedModels.push_back(new CSMWorld::NestedTableModel (mTable->index(row, i), display, mTable)); - NestedTable* table = new NestedTable(mDocument, *(mNestedModels.rbegin()), this); + NestedTable* table = new NestedTable(mDocument, mNestedModels.back(), this); + + int rows = mNestedModels.back()->rowCount(mTable->index(row, i)); + if (rows == 0) rows = 1; // FIXME: quick hack + int rowHeight = table->rowHeight(0); + int tableHeight = (rows * rowHeight) + + table->horizontalHeader()->height() + 2 * table->frameWidth(); + int tableMaxHeight = (5 * rowHeight) + + table->horizontalHeader()->height() + 2 * table->frameWidth(); + if (rows > 1 && rows < 5) + table->setMinimumHeight(tableHeight); + else if (rows > 1) + table->setMinimumHeight(tableMaxHeight); + + QLabel* label = new QLabel (mTable->headerData (i, Qt::Horizontal, Qt::DisplayRole).toString(), mMainWidget); + label->setSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed); + + tablesLayout->addWidget(label); tablesLayout->addWidget(table); - } else + } + else { mDispatcher.makeDelegate (display); QWidget* editor = mDispatcher.makeEditor (display, (mTable->index (row, i))); @@ -438,7 +464,8 @@ void CSVWorld::EditWidget::remake(int row) lockedLayout->addWidget (label, locked, 0); lockedLayout->addWidget (editor, locked, 1); ++locked; - } else + } + else { unlockedLayout->addWidget (label, unlocked, 0); unlockedLayout->addWidget (editor, unlocked, 1); From 29ef08bb7545e62f15325ad79abce4ece3e5792c Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 30 Mar 2015 11:53:33 +1100 Subject: [PATCH 0862/3725] Spelling and other consistencies nit pick. --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/world/collectionbase.hpp | 23 ------------ apps/opencs/model/world/idtable.cpp | 1 + ...{nestedadaptors.cpp => nestedadapters.cpp} | 2 +- ...{nestedadaptors.hpp => nestedadapters.hpp} | 4 +-- apps/opencs/model/world/nestedcollection.hpp | 35 +++++++++++++++++++ apps/opencs/model/world/refidadapter.hpp | 30 ++++++++-------- apps/opencs/model/world/refidadapterimp.hpp | 8 ++--- apps/opencs/model/world/refidcollection.cpp | 24 ++++++------- apps/opencs/model/world/refidcollection.hpp | 5 +-- 10 files changed, 74 insertions(+), 60 deletions(-) rename apps/opencs/model/world/{nestedadaptors.cpp => nestedadapters.cpp} (81%) rename apps/opencs/model/world/{nestedadaptors.hpp => nestedadapters.hpp} (99%) create mode 100644 apps/opencs/model/world/nestedcollection.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 82d9f6977..c9ca60b33 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -26,7 +26,7 @@ opencs_units (model/world opencs_units_noqt (model/world universalid record commands columnbase scriptcontext cell refidcollection refidadapter refiddata refidadapterimp ref collectionbase refcollection columns infocollection tablemimedata cellcoordinates cellselection resources resourcesmanager scope - pathgrid landtexture land nestedtablewrapper nestedadaptors + pathgrid landtexture land nestedtablewrapper nestedadapters ) opencs_hdrs_noqt (model/world diff --git a/apps/opencs/model/world/collectionbase.hpp b/apps/opencs/model/world/collectionbase.hpp index 29ac33bc8..ef826e31c 100644 --- a/apps/opencs/model/world/collectionbase.hpp +++ b/apps/opencs/model/world/collectionbase.hpp @@ -13,7 +13,6 @@ namespace CSMWorld { struct ColumnBase; struct RecordBase; - class NestedTableWrapperBase; /// \brief Base class for record collections /// @@ -105,28 +104,6 @@ namespace CSMWorld ///< Return index of column with the given \a id. If no such column exists, an exception is /// thrown. }; - - class NestedCollection : public CollectionBase - { - public: - virtual void addNestedRow(int row, int col, int position) = 0; - - virtual QVariant getNestedData(int row, int column, int subRow, int subColumn) const = 0; - - virtual NestedTableWrapperBase* nestedTable(int row, int column) const = 0; - - virtual void setNestedTable(int row, int column, const NestedTableWrapperBase& nestedTable) = 0; - - virtual void setNestedData(int row, int column, const QVariant& data, int subRow, int subColumn) = 0; - - virtual int getNestedRowsCount(int row, int column) const = 0; - - virtual int getNestedColumnsCount(int row, int column) const = 0; - - virtual void removeNestedRows(int row, int column, int subRow) = 0; - - - }; } #endif diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index fc8ac66b7..964b68cd1 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -6,6 +6,7 @@ #include "nestedtablewrapper.hpp" #include "collectionbase.hpp" +#include "nestedcollection.hpp" #include "columnbase.hpp" CSMWorld::IdTable::IdTable (CollectionBase *idCollection, unsigned int features) diff --git a/apps/opencs/model/world/nestedadaptors.cpp b/apps/opencs/model/world/nestedadapters.cpp similarity index 81% rename from apps/opencs/model/world/nestedadaptors.cpp rename to apps/opencs/model/world/nestedadapters.cpp index 1e8425229..1c8b1eff1 100644 --- a/apps/opencs/model/world/nestedadaptors.cpp +++ b/apps/opencs/model/world/nestedadapters.cpp @@ -1,4 +1,4 @@ -#include "nestedadaptors.hpp" +#include "nestedadapters.hpp" CSMWorld::HelperBase::HelperBase(CSMWorld::UniversalId::Type type) : mType(type) diff --git a/apps/opencs/model/world/nestedadaptors.hpp b/apps/opencs/model/world/nestedadapters.hpp similarity index 99% rename from apps/opencs/model/world/nestedadaptors.hpp rename to apps/opencs/model/world/nestedadapters.hpp index cc062e827..ac2a650d4 100644 --- a/apps/opencs/model/world/nestedadaptors.hpp +++ b/apps/opencs/model/world/nestedadapters.hpp @@ -1,5 +1,5 @@ -#ifndef CSM_WORLD_NESTEDADAPTORS_H -#define CSM_WORLD_NESTEDADAPTORS_H +#ifndef CSM_WORLD_NESTEDADAPTERS_H +#define CSM_WORLD_NESTEDADAPTERS_H #include #include diff --git a/apps/opencs/model/world/nestedcollection.hpp b/apps/opencs/model/world/nestedcollection.hpp new file mode 100644 index 000000000..dffa29573 --- /dev/null +++ b/apps/opencs/model/world/nestedcollection.hpp @@ -0,0 +1,35 @@ +#ifndef CSM_WOLRD_NESTEDCOLLECTION_H +#define CSM_WOLRD_NESTEDCOLLECTION_H + +#include "collectionbase.hpp" + +class QVariant; + +namespace CSMWorld +{ + class NestedTableWrapperBase; + + class NestedCollection : public CollectionBase + { + public: + virtual void addNestedRow(int row, int col, int position) = 0; + + virtual QVariant getNestedData(int row, int column, int subRow, int subColumn) const = 0; + + virtual NestedTableWrapperBase* nestedTable(int row, int column) const = 0; + + virtual void setNestedTable(int row, int column, const NestedTableWrapperBase& nestedTable) = 0; + + virtual void setNestedData(int row, int column, const QVariant& data, int subRow, int subColumn) = 0; + + virtual int getNestedRowsCount(int row, int column) const = 0; + + virtual int getNestedColumnsCount(int row, int column) const = 0; + + virtual void removeNestedRows(int row, int column, int subRow) = 0; + + + }; +} + +#endif diff --git a/apps/opencs/model/world/refidadapter.hpp b/apps/opencs/model/world/refidadapter.hpp index 387ee8606..af7469637 100644 --- a/apps/opencs/model/world/refidadapter.hpp +++ b/apps/opencs/model/world/refidadapter.hpp @@ -4,10 +4,10 @@ #include #include -#include "nestedadaptors.hpp" +#include "nestedadapters.hpp" /*! \brief - * Adaptors acts as indirection layer, abstracting details of the record types (in the wrappers) from the higher levels of model. + * Adapters acts as indirection layer, abstracting details of the record types (in the wrappers) from the higher levels of model. * Please notice that nested adaptor uses helper classes for actually performing any actions. Different record types require different helpers (needs to be created in the subclass and then fetched via member function). * Important point: don't forget to make sure that getData on the nestedColumn returns true (otherwise code will not treat the index pointing to the column as having childs! */ @@ -79,25 +79,25 @@ namespace CSMWorld public: NestedRefIdAdapter(); - + virtual ~NestedRefIdAdapter(); - + virtual void setNestedData (const RefIdColumn *column, RefIdData& data, int row, const QVariant& value, int subRowIndex, int subColIndex) const; - + virtual QVariant getNestedData (const RefIdColumn *column, const RefIdData& data, int index, int subRowIndex, int subColIndex) const; - + virtual int getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const; - + virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const; - + virtual void removeNestedRow (const RefIdColumn *column, RefIdData& data, int index, int rowToRemove) const; - + virtual void addNestedRow (const RefIdColumn *column, RefIdData& data, int index, int position) const; - + virtual void setNestedTable (const RefIdColumn* column, RefIdData& data, int index, const NestedTableWrapperBase& nestedTable); - + virtual NestedTableWrapperBase* nestedTable (const RefIdColumn* column, const RefIdData& data, int index) const; protected: @@ -105,12 +105,12 @@ namespace CSMWorld ///The ownership of the Helper pointers is transfered. ///The ownership of the column pointers it not transfered (it is not surprising, since columns are created by collection). ///You MUST call this method to setup the nested adaptor! - - void addAssocColumn(const std::pair & assocColumn); + + void addAssocColumn(const std::pair & assocColumn); ///Like setAssocColumn, when it is impossible to set all columns at once - + private: - + HelperBase* getHelper(const RefIdColumn *column) const; }; } diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index 11befaeec..acc6c40c1 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -12,7 +12,7 @@ #include "refiddata.hpp" #include "universalid.hpp" #include "refidadapter.hpp" -#include "nestedadaptors.hpp" +#include "nestedadapters.hpp" namespace CSMWorld { @@ -509,7 +509,7 @@ namespace CSMWorld assoCol.push_back(std::make_pair(mActors.mInventory, new InventoryHelper(type))); assoCol.push_back(std::make_pair(mActors.mSpells, new SpellsHelper(type))); - + setAssocColumns(assoCol); } @@ -540,7 +540,7 @@ namespace CSMWorld if (column==mActors.mSpells) return true; - + std::map::const_iterator iter = mActors.mServices.find (column); @@ -666,7 +666,7 @@ namespace CSMWorld const RefIdColumn *mOrganic; const RefIdColumn *mRespawn; const RefIdColumn *mContent; - + public: ContainerRefIdAdapter (const NameColumns& columns, const RefIdColumn *weight, diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index ee09cafa1..c48896435 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -27,7 +27,7 @@ bool CSMWorld::RefIdColumn::isUserEditable() const } -CSMWorld::RefIdAdapter& CSMWorld::RefIdCollection::findAdaptor (UniversalId::Type type) const +CSMWorld::RefIdAdapter& CSMWorld::RefIdCollection::findAdapter (UniversalId::Type type) const { std::map::const_iterator iter = mAdapters.find (type); @@ -452,7 +452,7 @@ QVariant CSMWorld::RefIdCollection::getData (int index, int column) const { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (index); - const RefIdAdapter& adaptor = findAdaptor (localIndex.second); + const RefIdAdapter& adaptor = findAdapter (localIndex.second); return adaptor.getData (&mColumns.at (column), mData, localIndex.first); } @@ -461,7 +461,7 @@ QVariant CSMWorld::RefIdCollection::getNestedData (int row, int column, int subR { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex(row); - const CSMWorld::NestedRefIdAdapter& adaptor = dynamic_cast(findAdaptor (localIndex.second)); + const CSMWorld::NestedRefIdAdapter& adaptor = dynamic_cast(findAdapter (localIndex.second)); return adaptor.getNestedData (&mColumns.at (column), mData, localIndex.first, subRow, subColumn); } @@ -470,7 +470,7 @@ void CSMWorld::RefIdCollection::setData (int index, int column, const QVariant& { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (index); - const RefIdAdapter& adaptor = findAdaptor (localIndex.second); + const RefIdAdapter& adaptor = findAdapter (localIndex.second); adaptor.setData (&mColumns.at (column), mData, localIndex.first, data); } @@ -479,7 +479,7 @@ void CSMWorld::RefIdCollection::setNestedData(int row, int column, const QVarian { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); - const RefIdAdapter& adaptor = findAdaptor (localIndex.second); + const RefIdAdapter& adaptor = findAdapter (localIndex.second); dynamic_cast(adaptor).setNestedData (&mColumns.at (column), mData, localIndex.first, data, subRow, subColumn); } @@ -493,7 +493,7 @@ void CSMWorld::RefIdCollection::removeNestedRows(int row, int column, int subRow { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); - const RefIdAdapter& adaptor = findAdaptor (localIndex.second); + const RefIdAdapter& adaptor = findAdapter (localIndex.second); dynamic_cast(adaptor).removeNestedRow(&mColumns.at (column), mData, localIndex.first, subRow); } @@ -530,7 +530,7 @@ void CSMWorld::RefIdCollection::cloneRecord(const std::string& origin, void CSMWorld::RefIdCollection::appendRecord (const RecordBase& record, UniversalId::Type type) { - std::string id = findAdaptor (type).getId (record); + std::string id = findAdapter (type).getId (record); int index = mData.getAppendIndex (type); @@ -637,7 +637,7 @@ int CSMWorld::RefIdCollection::getNestedRowsCount(int row, int column) const { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); - const CSMWorld::NestedRefIdAdapter& adaptor = dynamic_cast(findAdaptor (localIndex.second)); + const CSMWorld::NestedRefIdAdapter& adaptor = dynamic_cast(findAdapter (localIndex.second)); return adaptor.getNestedRowsCount(&mColumns.at(column), mData, localIndex.first); } @@ -646,7 +646,7 @@ int CSMWorld::RefIdCollection::getNestedColumnsCount(int row, int column) const { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); - const CSMWorld::NestedRefIdAdapter& adaptor = dynamic_cast(findAdaptor (localIndex.second)); + const CSMWorld::NestedRefIdAdapter& adaptor = dynamic_cast(findAdapter (localIndex.second)); return adaptor.getNestedColumnsCount(&mColumns.at(column), mData); } @@ -655,7 +655,7 @@ void CSMWorld::RefIdCollection::addNestedRow(int row, int col, int position) { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); - const CSMWorld::NestedRefIdAdapter& adaptor = dynamic_cast(findAdaptor (localIndex.second)); + const CSMWorld::NestedRefIdAdapter& adaptor = dynamic_cast(findAdapter (localIndex.second)); adaptor.addNestedRow(&mColumns.at(col), mData, localIndex.first, position); } @@ -664,7 +664,7 @@ void CSMWorld::RefIdCollection::setNestedTable(int row, int column, const CSMWor { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); - CSMWorld::NestedRefIdAdapter& adaptor = dynamic_cast(findAdaptor (localIndex.second)); + CSMWorld::NestedRefIdAdapter& adaptor = dynamic_cast(findAdapter (localIndex.second)); adaptor.setNestedTable(&mColumns.at(column), mData, localIndex.first, nestedTable); } @@ -673,7 +673,7 @@ CSMWorld::NestedTableWrapperBase* CSMWorld::RefIdCollection::nestedTable(int row { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); - const CSMWorld::NestedRefIdAdapter& adaptor = dynamic_cast(findAdaptor (localIndex.second)); + const CSMWorld::NestedRefIdAdapter& adaptor = dynamic_cast(findAdapter (localIndex.second)); return adaptor.nestedTable(&mColumns.at(column), mData, localIndex.first); } diff --git a/apps/opencs/model/world/refidcollection.hpp b/apps/opencs/model/world/refidcollection.hpp index 62616d369..ab25c93fa 100644 --- a/apps/opencs/model/world/refidcollection.hpp +++ b/apps/opencs/model/world/refidcollection.hpp @@ -7,6 +7,7 @@ #include "columnbase.hpp" #include "collectionbase.hpp" +#include "nestedcollection.hpp" #include "refiddata.hpp" namespace ESM @@ -45,7 +46,7 @@ namespace CSMWorld private: - RefIdAdapter& findAdaptor (UniversalId::Type) const; + RefIdAdapter& findAdapter (UniversalId::Type) const; ///< Throws an exception if no adaptor for \a Type can be found. public: @@ -71,7 +72,7 @@ namespace CSMWorld virtual QVariant getData (int index, int column) const; virtual QVariant getNestedData(int row, int column, int subRow, int subColumn) const; - + virtual NestedTableWrapperBase* nestedTable(int row, int column) const; virtual void setNestedTable(int row, int column, const NestedTableWrapperBase& nestedTable); From 619b5206cdedfb75a1ecadf5754de129c46211e2 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 30 Mar 2015 16:41:55 +1100 Subject: [PATCH 0863/3725] More consistency nit pick. --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/world/idtable.cpp | 10 ++-- ...blemodel.cpp => nestedtableproxymodel.cpp} | 49 +++++++++---------- ...blemodel.hpp => nestedtableproxymodel.hpp} | 26 +++++----- apps/opencs/view/world/dialoguesubview.cpp | 4 +- apps/opencs/view/world/dialoguesubview.hpp | 4 +- apps/opencs/view/world/nestedtable.cpp | 4 +- apps/opencs/view/world/nestedtable.hpp | 6 +-- 8 files changed, 54 insertions(+), 51 deletions(-) rename apps/opencs/model/world/{nestedtablemodel.cpp => nestedtableproxymodel.cpp} (66%) rename apps/opencs/model/world/{nestedtablemodel.hpp => nestedtableproxymodel.hpp} (89%) diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index c9ca60b33..5f9559257 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -19,7 +19,7 @@ opencs_hdrs_noqt (model/doc opencs_units (model/world idtable idtableproxymodel regionmap data commanddispatcher - idtablebase resourcetable nestedtablemodel + idtablebase resourcetable nestedtableproxymodel ) diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 964b68cd1..c5061b93d 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -51,7 +51,9 @@ QVariant CSMWorld::IdTable::data (const QModelIndex & index, int role) const parentAdress.second, index.row(), index.column()); - } else { + } + else + { return mIdCollection->getData (index.row(), index.column()); } } @@ -110,7 +112,8 @@ bool CSMWorld::IdTable::setData (const QModelIndex &index, const QVariant &value CSMWorld::IdTable::index (parentAdress.second, mIdCollection->getColumns()-1)); return true; - } else + } + else { return false; } @@ -149,7 +152,8 @@ bool CSMWorld::IdTable::removeRows (int row, int count, const QModelIndex& paren { dynamic_cast(mIdCollection)->removeNestedRows(parent.row(), parent.column(), row+i); } - } else + } + else { beginRemoveRows (parent, row, row+count-1); diff --git a/apps/opencs/model/world/nestedtablemodel.cpp b/apps/opencs/model/world/nestedtableproxymodel.cpp similarity index 66% rename from apps/opencs/model/world/nestedtablemodel.cpp rename to apps/opencs/model/world/nestedtableproxymodel.cpp index 734047b8d..c098e0316 100644 --- a/apps/opencs/model/world/nestedtablemodel.cpp +++ b/apps/opencs/model/world/nestedtableproxymodel.cpp @@ -1,9 +1,9 @@ -#include "nestedtablemodel.hpp" +#include "nestedtableproxymodel.hpp" #include #include "idtable.hpp" -CSMWorld::NestedTableModel::NestedTableModel(const QModelIndex& parent, +CSMWorld::NestedTableProxyModel::NestedTableProxyModel(const QModelIndex& parent, ColumnBase::Display columnId, CSMWorld::IdTable* parentModel) : mParentColumn(parent.column()), @@ -14,10 +14,10 @@ CSMWorld::NestedTableModel::NestedTableModel(const QModelIndex& parent, mId = std::string(parentModel->index(parentRow, 0).data().toString().toUtf8()); QAbstractProxyModel::setSourceModel(parentModel); - + connect(mMainModel, SIGNAL(rowsAboutToBeInserted(const QModelIndex &, int, int)), this, SLOT(forwardRowsAboutToInserted(const QModelIndex &, int, int))); - + connect(mMainModel, SIGNAL(rowsInserted(const QModelIndex &, int, int)), this, SLOT(forwardRowsInserted(const QModelIndex &, int, int))); @@ -26,7 +26,7 @@ CSMWorld::NestedTableModel::NestedTableModel(const QModelIndex& parent, connect(mMainModel, SIGNAL(rowsRemoved(const QModelIndex &, int, int)), this, SLOT(forwardRowsRemoved(const QModelIndex &, int, int))); - + connect(mMainModel, SIGNAL(resetStart(const QString&)), this, SLOT(forwardResetStart(const QString&))); @@ -34,7 +34,7 @@ CSMWorld::NestedTableModel::NestedTableModel(const QModelIndex& parent, this, SLOT(forwardResetEnd(const QString&))); } -QModelIndex CSMWorld::NestedTableModel::mapFromSource(const QModelIndex& sourceIndex) const +QModelIndex CSMWorld::NestedTableProxyModel::mapFromSource(const QModelIndex& sourceIndex) const { const QModelIndex& testedParent = mMainModel->parent(sourceIndex); const QModelIndex& parent = mMainModel->getModelIndex (mId, mParentColumn); @@ -46,30 +46,29 @@ QModelIndex CSMWorld::NestedTableModel::mapFromSource(const QModelIndex& sourceI { return QModelIndex(); } - } -QModelIndex CSMWorld::NestedTableModel::mapToSource(const QModelIndex& proxyIndex) const +QModelIndex CSMWorld::NestedTableProxyModel::mapToSource(const QModelIndex& proxyIndex) const { const QModelIndex& parent = mMainModel->getModelIndex (mId, mParentColumn); return mMainModel->index(proxyIndex.row(), proxyIndex.column(), parent); } -int CSMWorld::NestedTableModel::rowCount(const QModelIndex& index) const +int CSMWorld::NestedTableProxyModel::rowCount(const QModelIndex& index) const { assert (!index.isValid()); return mMainModel->rowCount(mMainModel->getModelIndex(mId, mParentColumn)); } -int CSMWorld::NestedTableModel::columnCount(const QModelIndex& parent) const +int CSMWorld::NestedTableProxyModel::columnCount(const QModelIndex& parent) const { assert (!parent.isValid()); return mMainModel->columnCount(mMainModel->getModelIndex(mId, mParentColumn)); } -QModelIndex CSMWorld::NestedTableModel::index(int row, int column, const QModelIndex& parent) const +QModelIndex CSMWorld::NestedTableProxyModel::index(int row, int column, const QModelIndex& parent) const { assert (!parent.isValid()); @@ -87,12 +86,12 @@ QModelIndex CSMWorld::NestedTableModel::index(int row, int column, const QModelI return createIndex(row, column); } -QModelIndex CSMWorld::NestedTableModel::parent(const QModelIndex& index) const +QModelIndex CSMWorld::NestedTableProxyModel::parent(const QModelIndex& index) const { return QModelIndex(); } -QVariant CSMWorld::NestedTableModel::headerData(int section, +QVariant CSMWorld::NestedTableProxyModel::headerData(int section, Qt::Orientation orientation, int role) const { @@ -100,32 +99,32 @@ QVariant CSMWorld::NestedTableModel::headerData(int section, } -bool CSMWorld::NestedTableModel::setData ( const QModelIndex & index, const QVariant & value, int role) +bool CSMWorld::NestedTableProxyModel::setData ( const QModelIndex & index, const QVariant & value, int role) { return mMainModel->setData(mapToSource(index), value, role); } -Qt::ItemFlags CSMWorld::NestedTableModel::flags(const QModelIndex& index) const +Qt::ItemFlags CSMWorld::NestedTableProxyModel::flags(const QModelIndex& index) const { return mMainModel->flags(mMainModel->index(0, mParentColumn)); } -std::string CSMWorld::NestedTableModel::getParentId() const +std::string CSMWorld::NestedTableProxyModel::getParentId() const { return mId; } -int CSMWorld::NestedTableModel::getParentColumn() const +int CSMWorld::NestedTableProxyModel::getParentColumn() const { return mParentColumn; } -CSMWorld::IdTable* CSMWorld::NestedTableModel::model() const +CSMWorld::IdTable* CSMWorld::NestedTableProxyModel::model() const { return mMainModel; } -void CSMWorld::NestedTableModel::forwardRowsAboutToInserted(const QModelIndex& parent, int first, int last) +void CSMWorld::NestedTableProxyModel::forwardRowsAboutToInserted(const QModelIndex& parent, int first, int last) { if (indexIsParent(parent)) { @@ -133,7 +132,7 @@ void CSMWorld::NestedTableModel::forwardRowsAboutToInserted(const QModelIndex& p } } -void CSMWorld::NestedTableModel::forwardRowsInserted(const QModelIndex& parent, int first, int last) +void CSMWorld::NestedTableProxyModel::forwardRowsInserted(const QModelIndex& parent, int first, int last) { if (indexIsParent(parent)) { @@ -141,14 +140,14 @@ void CSMWorld::NestedTableModel::forwardRowsInserted(const QModelIndex& parent, } } -bool CSMWorld::NestedTableModel::indexIsParent(const QModelIndex& index) +bool CSMWorld::NestedTableProxyModel::indexIsParent(const QModelIndex& index) { return (index.isValid() && index.column() == mParentColumn && mMainModel->data(mMainModel->index(index.row(), 0)).toString().toUtf8().constData() == mId); } -void CSMWorld::NestedTableModel::forwardRowsAboutToRemoved(const QModelIndex& parent, int first, int last) +void CSMWorld::NestedTableProxyModel::forwardRowsAboutToRemoved(const QModelIndex& parent, int first, int last) { if (indexIsParent(parent)) { @@ -156,7 +155,7 @@ void CSMWorld::NestedTableModel::forwardRowsAboutToRemoved(const QModelIndex& pa } } -void CSMWorld::NestedTableModel::forwardRowsRemoved(const QModelIndex& parent, int first, int last) +void CSMWorld::NestedTableProxyModel::forwardRowsRemoved(const QModelIndex& parent, int first, int last) { if (indexIsParent(parent)) { @@ -164,13 +163,13 @@ void CSMWorld::NestedTableModel::forwardRowsRemoved(const QModelIndex& parent, i } } -void CSMWorld::NestedTableModel::forwardResetStart(const QString& id) +void CSMWorld::NestedTableProxyModel::forwardResetStart(const QString& id) { if (id.toUtf8() == mId.c_str()) beginResetModel(); } -void CSMWorld::NestedTableModel::forwardResetEnd(const QString& id) +void CSMWorld::NestedTableProxyModel::forwardResetEnd(const QString& id) { if (id.toUtf8() == mId.c_str()) endResetModel(); diff --git a/apps/opencs/model/world/nestedtablemodel.hpp b/apps/opencs/model/world/nestedtableproxymodel.hpp similarity index 89% rename from apps/opencs/model/world/nestedtablemodel.hpp rename to apps/opencs/model/world/nestedtableproxymodel.hpp index 5fea5c006..7ad8fc0c2 100644 --- a/apps/opencs/model/world/nestedtablemodel.hpp +++ b/apps/opencs/model/world/nestedtableproxymodel.hpp @@ -1,5 +1,5 @@ -#ifndef CSM_WOLRD_NESTEDTABLEMODEL_H -#define CSM_WOLRD_NESTEDTABLEMODEL_H +#ifndef CSM_WOLRD_NESTEDTABLEPROXYMODEL_H +#define CSM_WOLRD_NESTEDTABLEPROXYMODEL_H #include @@ -19,7 +19,7 @@ namespace CSMWorld class RecordBase; class IdTable; - class NestedTableModel : public QAbstractProxyModel + class NestedTableProxyModel : public QAbstractProxyModel { Q_OBJECT @@ -28,15 +28,15 @@ namespace CSMWorld std::string mId; public: - NestedTableModel(const QModelIndex& parent, + NestedTableProxyModel(const QModelIndex& parent, ColumnBase::Display displayType, IdTable* parentModel); //parent is the parent of columns to work with. Columnid provides information about the column std::string getParentId() const; - + int getParentColumn() const; - + CSMWorld::IdTable* model() const; virtual QModelIndex mapFromSource(const QModelIndex& sourceIndex) const; @@ -52,27 +52,27 @@ namespace CSMWorld virtual QModelIndex parent(const QModelIndex& index) const; virtual QVariant headerData ( int section, Qt::Orientation orientation, int role ) const; - + virtual bool setData ( const QModelIndex & index, const QVariant & value, int role = Qt::EditRole ); - + virtual Qt::ItemFlags flags(const QModelIndex& index) const; - + private: void setupHeaderVectors(ColumnBase::Display columnId); bool indexIsParent(const QModelIndex& index); - + private slots: void forwardRowsAboutToInserted(const QModelIndex & parent, int first, int last); - + void forwardRowsInserted(const QModelIndex & parent, int first, int last); void forwardRowsAboutToRemoved(const QModelIndex & parent, int first, int last); void forwardRowsRemoved(const QModelIndex & parent, int first, int last); - + void forwardResetStart(const QString& id); - + void forwardResetEnd(const QString& id); }; } diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 421e12c13..e26dcdc9b 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -23,7 +23,7 @@ #include #include -#include "../../model/world/nestedtablemodel.hpp" +#include "../../model/world/nestedtableproxymodel.hpp" #include "../../model/world/columnbase.hpp" #include "../../model/world/idtable.hpp" #include "../../model/world/columns.hpp" @@ -422,7 +422,7 @@ void CSVWorld::EditWidget::remake(int row) if (mTable->hasChildren(mTable->index(row, i))) { - mNestedModels.push_back(new CSMWorld::NestedTableModel (mTable->index(row, i), display, mTable)); + mNestedModels.push_back(new CSMWorld::NestedTableProxyModel (mTable->index(row, i), display, mTable)); NestedTable* table = new NestedTable(mDocument, mNestedModels.back(), this); diff --git a/apps/opencs/view/world/dialoguesubview.hpp b/apps/opencs/view/world/dialoguesubview.hpp index 6ea79aa95..72acb1966 100644 --- a/apps/opencs/view/world/dialoguesubview.hpp +++ b/apps/opencs/view/world/dialoguesubview.hpp @@ -21,7 +21,7 @@ class QVBoxLayout; namespace CSMWorld { class IdTable; - class NestedTableModel; + class NestedTableProxyModel; } namespace CSMDoc @@ -165,7 +165,7 @@ namespace CSVWorld QWidget* mMainWidget; CSMWorld::IdTable* mTable; CSMDoc::Document& mDocument; - std::vector mNestedModels; //Plain, raw C pointers, deleted in the dtor + std::vector mNestedModels; //Plain, raw C pointers, deleted in the dtor public: diff --git a/apps/opencs/view/world/nestedtable.cpp b/apps/opencs/view/world/nestedtable.cpp index 14e079c98..1597c81a3 100644 --- a/apps/opencs/view/world/nestedtable.cpp +++ b/apps/opencs/view/world/nestedtable.cpp @@ -1,5 +1,5 @@ #include "nestedtable.hpp" -#include "../../model/world/nestedtablemodel.hpp" +#include "../../model/world/nestedtableproxymodel.hpp" #include "../../model/world/universalid.hpp" #include "../../model/world/commands.hpp" #include "util.hpp" @@ -10,7 +10,7 @@ #include CSVWorld::NestedTable::NestedTable(CSMDoc::Document& document, - CSMWorld::NestedTableModel* model, + CSMWorld::NestedTableProxyModel* model, QWidget* parent) : QTableView(parent), mUndoStack(document.getUndoStack()), diff --git a/apps/opencs/view/world/nestedtable.hpp b/apps/opencs/view/world/nestedtable.hpp index 6b6b6aaba..f41ba4345 100644 --- a/apps/opencs/view/world/nestedtable.hpp +++ b/apps/opencs/view/world/nestedtable.hpp @@ -10,7 +10,7 @@ class QContextMenuEvent; namespace CSMWorld { - class NestedTableModel; + class NestedTableProxyModel; class UniversalId; } @@ -28,11 +28,11 @@ namespace CSVWorld QAction *mAddNewRowAction; QAction *mRemoveRowAction; QUndoStack& mUndoStack; - CSMWorld::NestedTableModel* mModel; + CSMWorld::NestedTableProxyModel* mModel; public: NestedTable(CSMDoc::Document& document, - CSMWorld::NestedTableModel* model, + CSMWorld::NestedTableProxyModel* model, QWidget* parent = NULL); protected: From ece34a1baa2c963d7f5429126c75891c0addd1b4 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 30 Mar 2015 18:14:07 +1100 Subject: [PATCH 0864/3725] Workaround for crash while exiting the application. --- apps/opencs/model/world/idtable.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index c5061b93d..1c21e64c3 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -14,7 +14,9 @@ CSMWorld::IdTable::IdTable (CollectionBase *idCollection, unsigned int features) {} CSMWorld::IdTable::~IdTable() -{} +{ + mIdCollection = 0; // FIXME: workaround only, should stop QHideEvent calling after destruction +} int CSMWorld::IdTable::rowCount (const QModelIndex & parent) const { @@ -81,6 +83,10 @@ QVariant CSMWorld::IdTable::headerData (int section, QVariant CSMWorld::IdTable::nestedHeaderData(int section, int subSection, Qt::Orientation orientation, int role) const { + // FIXME: workaround only, should stop QHideEvent calling after destruction + if (section < 0 || !mIdCollection || section >= mIdCollection->getColumns()) + return QVariant(); + const NestColumn& parentColumn = dynamic_cast(mIdCollection->getColumn(section)); if (orientation==Qt::Vertical) From 4928e3705f7695199efa18406306e25fa04a9c0e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 30 Mar 2015 12:52:08 +0200 Subject: [PATCH 0865/3725] highlight (bold) search string in results --- apps/opencs/model/tools/search.cpp | 41 +++++++++++++----------- apps/opencs/model/tools/search.hpp | 4 ++- apps/opencs/view/tools/reportsubview.cpp | 2 +- apps/opencs/view/tools/reporttable.cpp | 39 +++++++++++++++++++++- apps/opencs/view/tools/reporttable.hpp | 3 +- apps/opencs/view/tools/searchsubview.cpp | 2 +- 6 files changed, 68 insertions(+), 23 deletions(-) diff --git a/apps/opencs/model/tools/search.cpp b/apps/opencs/model/tools/search.cpp index 9f1beb064..e2bab3866 100644 --- a/apps/opencs/model/tools/search.cpp +++ b/apps/opencs/model/tools/search.cpp @@ -79,31 +79,36 @@ void CSMTools::Search::searchRecordStateCell (const CSMWorld::IdTableBase *model QString CSMTools::Search::formatDescription (const QString& description, int pos, int length) const { - int padding = 10; ///< \todo make this configurable - - if (pos" + highlight + "" + after; + // improve layout for single line display - text.replace ("\n", ""); + text.replace ("\n", "<CR>"); text.replace ('\t', ' '); - return text; + return text; +} + +QString CSMTools::Search::flatten (const QString& text) const +{ + QString flat (text); + + flat.replace ("&", "&"); + flat.replace ("<", "<"); + + return flat; } CSMTools::Search::Search() : mType (Type_None) {} diff --git a/apps/opencs/model/tools/search.hpp b/apps/opencs/model/tools/search.hpp index 320323f03..0148beab3 100644 --- a/apps/opencs/model/tools/search.hpp +++ b/apps/opencs/model/tools/search.hpp @@ -57,7 +57,9 @@ namespace CSMTools CSMDoc::Messages& messages) const; QString formatDescription (const QString& description, int pos, int length) const; - + + QString flatten (const QString& text) const; + public: Search(); diff --git a/apps/opencs/view/tools/reportsubview.cpp b/apps/opencs/view/tools/reportsubview.cpp index df1a5298c..492874c01 100644 --- a/apps/opencs/view/tools/reportsubview.cpp +++ b/apps/opencs/view/tools/reportsubview.cpp @@ -6,7 +6,7 @@ CSVTools::ReportSubView::ReportSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) : CSVDoc::SubView (id) { - setWidget (mTable = new ReportTable (document, id, this)); + setWidget (mTable = new ReportTable (document, id, false, this)); connect (mTable, SIGNAL (editRequest (const CSMWorld::UniversalId&, const std::string&)), SIGNAL (focusId (const CSMWorld::UniversalId&, const std::string&))); diff --git a/apps/opencs/view/tools/reporttable.cpp b/apps/opencs/view/tools/reporttable.cpp index 5bf1fa848..73fee2362 100644 --- a/apps/opencs/view/tools/reporttable.cpp +++ b/apps/opencs/view/tools/reporttable.cpp @@ -6,11 +6,45 @@ #include #include #include +#include +#include +#include #include "../../model/tools/reportmodel.hpp" #include "../../view/world/idtypedelegate.hpp" +namespace CSVTools +{ + class RichTextDelegate : public QStyledItemDelegate + { + public: + + RichTextDelegate (QObject *parent = 0); + + virtual void paint(QPainter *painter, const QStyleOptionViewItem& option, + const QModelIndex& index) const; + }; +} + +CSVTools::RichTextDelegate::RichTextDelegate (QObject *parent) : QStyledItemDelegate (parent) +{} + +void CSVTools::RichTextDelegate::paint(QPainter *painter, const QStyleOptionViewItem& option, + const QModelIndex& index) const +{ + QTextDocument document; + QVariant value = index.data (Qt::DisplayRole); + if (value.isValid() && !value.isNull()) + { + document.setHtml (value.toString()); + painter->translate (option.rect.topLeft()); + document.drawContents (painter); + painter->translate (-option.rect.topLeft()); + } +} + + void CSVTools::ReportTable::contextMenuEvent (QContextMenuEvent *event) { QModelIndexList selectedRows = selectionModel()->selectedRows(); @@ -67,7 +101,7 @@ void CSVTools::ReportTable::mouseDoubleClickEvent (QMouseEvent *event) } CSVTools::ReportTable::ReportTable (CSMDoc::Document& document, - const CSMWorld::UniversalId& id, QWidget *parent) + const CSMWorld::UniversalId& id, bool richTextDescription, QWidget *parent) : CSVWorld::DragRecordTable (document, parent), mModel (document.getReport (id)) { horizontalHeader()->setResizeMode (QHeaderView::Interactive); @@ -85,6 +119,9 @@ CSVTools::ReportTable::ReportTable (CSMDoc::Document& document, setItemDelegateForColumn (0, mIdTypeDelegate); + if (richTextDescription) + setItemDelegateForColumn (mModel->columnCount()-1, new RichTextDelegate (this)); + mShowAction = new QAction (tr ("Show"), this); connect (mShowAction, SIGNAL (triggered()), this, SLOT (showSelection())); addAction (mShowAction); diff --git a/apps/opencs/view/tools/reporttable.hpp b/apps/opencs/view/tools/reporttable.hpp index 4b686f2d4..dde6cc634 100644 --- a/apps/opencs/view/tools/reporttable.hpp +++ b/apps/opencs/view/tools/reporttable.hpp @@ -36,8 +36,9 @@ namespace CSVTools public: + /// \param richTextDescription Use rich text in the description column. ReportTable (CSMDoc::Document& document, const CSMWorld::UniversalId& id, - QWidget *parent = 0); + bool richTextDescription, QWidget *parent = 0); virtual std::vector getDraggedRecords() const; diff --git a/apps/opencs/view/tools/searchsubview.cpp b/apps/opencs/view/tools/searchsubview.cpp index 4afed2c90..146b94ef4 100644 --- a/apps/opencs/view/tools/searchsubview.cpp +++ b/apps/opencs/view/tools/searchsubview.cpp @@ -17,7 +17,7 @@ CSVTools::SearchSubView::SearchSubView (const CSMWorld::UniversalId& id, CSMDoc: layout->addWidget (&mSearchBox); - layout->addWidget (mTable = new ReportTable (document, id), 2); + layout->addWidget (mTable = new ReportTable (document, id, true), 2); QWidget *widget = new QWidget; From a474c7202623da429cbf535868de48bf87bc0b91 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 30 Mar 2015 17:11:15 +0200 Subject: [PATCH 0866/3725] Archive priority fix --- components/vfs/registerarchives.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/components/vfs/registerarchives.cpp b/components/vfs/registerarchives.cpp index cd077356f..69d4498bb 100644 --- a/components/vfs/registerarchives.cpp +++ b/components/vfs/registerarchives.cpp @@ -11,13 +11,6 @@ namespace VFS { const Files::PathContainer& dataDirs = collections.getPaths(); - if (useLooseFiles) - for (Files::PathContainer::const_iterator iter = dataDirs.begin(); iter != dataDirs.end(); ++iter) - { - // Last data dir has the highest priority - vfs->addArchive(new FileSystemArchive(iter->string())); - } - for (std::vector::const_iterator archive = archives.begin(); archive != archives.end(); ++archive) { if (collections.doesExist(*archive)) @@ -36,6 +29,13 @@ namespace VFS } } + if (useLooseFiles) + for (Files::PathContainer::const_iterator iter = dataDirs.begin(); iter != dataDirs.end(); ++iter) + { + // Last data dir has the highest priority + vfs->addArchive(new FileSystemArchive(iter->string())); + } + vfs->buildIndex(); } From 12f27123f2b3796d0dd02228da63bfa503ca9b6b Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 30 Mar 2015 17:11:27 +0200 Subject: [PATCH 0867/3725] Billboard scaling fix and culling bug fix --- CMakeLists.txt | 2 +- components/nifosg/nifloader.cpp | 65 ++++++++++++++++++++------------- 2 files changed, 40 insertions(+), 27 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0785ef28c..cde53f27a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -184,7 +184,7 @@ if (${OGRE_VERSION} VERSION_LESS "1.9") message(FATAL_ERROR "OpenMW requires Ogre 1.9 or later, please install the latest stable version from http://ogre3d.org") endif() -find_package(OpenSceneGraph 3.2.0 REQUIRED osgDB osgViewer osgGA osgAnimation osgParticle osgQt) +find_package(OpenSceneGraph 3.2.0 REQUIRED osgDB osgViewer osgGA osgAnimation osgParticle osgQt osgUtil) include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS}) find_package(MyGUI REQUIRED) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 9006c16ef..555105e35 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -210,36 +210,49 @@ namespace } }; - // Custom node used to have a transform always oriented towards the camera. Can have translation and scale + // NodeCallback used to have a transform always oriented towards the camera. Can have translation and scale // set just like a regular MatrixTransform, but the rotation set will be overridden in order to face the camera. - class BillboardNode : public osg::MatrixTransform + class BillboardCallback : public osg::NodeCallback { public: - BillboardNode() : osg::MatrixTransform() {} - BillboardNode(const BillboardNode& copy, const osg::CopyOp& copyop) - : osg::MatrixTransform(copy, copyop) {} - BillboardNode(const osg::Matrix& matrix) - : osg::MatrixTransform(matrix) {} + BillboardCallback() + { + } + BillboardCallback(const BillboardCallback& copy, const osg::CopyOp& copyop) + : osg::NodeCallback(copy, copyop) + { + } - META_Node(NifOsg, BillboardNode) + META_Object(NifOsg, BillboardCallback) - virtual bool computeLocalToWorldMatrix(osg::Matrix& matrix, osg::NodeVisitor*) const + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) { - if (_referenceFrame==RELATIVE_RF) + osgUtil::CullVisitor* cv = dynamic_cast(nv); + osg::MatrixTransform* billboardNode = dynamic_cast(node); + if (billboardNode && cv) { - const NifOsg::NodeUserData* userdata = static_cast(getUserDataContainer()->getUserObject(0)); + osg::Matrix modelView = *cv->getModelViewMatrix(); - matrix.preMult(_matrix); - matrix.setRotate(osg::Quat()); - matrix(0,0) = userdata->mScale; - matrix(1,1) = userdata->mScale; - matrix(2,2) = userdata->mScale; - } - else // absolute - { - matrix = _matrix; + // attempt to preserve scale + float mag[3]; + for (int i=0;i<3;++i) + { + mag[i] = std::sqrt(modelView(0,i) * modelView(0,i) + modelView(1,i) * modelView(1,i) + modelView(2,i) * modelView(2,i)); + } + + modelView.setRotate(osg::Quat()); + modelView(0,0) = mag[0]; + modelView(1,1) = mag[1]; + modelView(2,2) = mag[2]; + + cv->pushModelViewMatrix(new osg::RefMatrix(modelView), osg::Transform::RELATIVE_RF); + + traverse(node, nv); + + cv->popModelViewMatrix(); } - return true; + else + traverse(node, nv); } }; @@ -639,11 +652,7 @@ namespace NifOsg std::map boundTextures, int animflags, int particleflags, bool skipMeshes, TextKeyMap* textKeys, osg::Node* rootNode=NULL) { osg::ref_ptr transformNode; - if (nifNode->recType == Nif::RC_NiBillboardNode) - { - transformNode = new BillboardNode(toMatrix(nifNode->trafo)); - } - else if (createSkeleton) + if (createSkeleton) { osgAnimation::Bone* bone = new osgAnimation::Bone; transformNode = bone; @@ -655,6 +664,10 @@ namespace NifOsg { transformNode = new osg::MatrixTransform(toMatrix(nifNode->trafo)); } + if (nifNode->recType == Nif::RC_NiBillboardNode) + { + transformNode->addCullCallback(new BillboardCallback); + } if (parentNode) parentNode->addChild(transformNode); From cb6caf5e39da6b42fb46ab25edf58ebe1eb5c704 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 30 Mar 2015 22:30:33 +0200 Subject: [PATCH 0868/3725] added search-related user settings --- apps/opencs/model/settings/usersettings.cpp | 15 +++++++++++++++ apps/opencs/model/tools/search.cpp | 21 +++++++++++++-------- apps/opencs/model/tools/search.hpp | 4 ++++ apps/opencs/view/tools/searchsubview.cpp | 16 ++++++++++++++-- apps/opencs/view/tools/searchsubview.hpp | 2 ++ 5 files changed, 48 insertions(+), 10 deletions(-) diff --git a/apps/opencs/model/settings/usersettings.cpp b/apps/opencs/model/settings/usersettings.cpp index 7dac660c3..7a975c99c 100644 --- a/apps/opencs/model/settings/usersettings.cpp +++ b/apps/opencs/model/settings/usersettings.cpp @@ -208,6 +208,21 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() shiftCtrlDoubleClick->setToolTip ("Action on shift control double click in table:

" + toolTip); } + declareSection ("search", "Search & Replace"); + { + Setting *before = createSetting (Type_SpinBox, "char-before", + "Characters before search string"); + before->setDefaultValue (10); + before->setRange (0, 1000); + before->setToolTip ("Maximum number of character to display in search result before the searched text"); + + Setting *after = createSetting (Type_SpinBox, "char-after", + "Characters after search string"); + after->setDefaultValue (10); + after->setRange (0, 1000); + after->setToolTip ("Maximum number of character to display in search result after the searched text"); + } + { /****************************************************************** * There are three types of values: diff --git a/apps/opencs/model/tools/search.cpp b/apps/opencs/model/tools/search.cpp index e2bab3866..28d92f06a 100644 --- a/apps/opencs/model/tools/search.cpp +++ b/apps/opencs/model/tools/search.cpp @@ -85,11 +85,10 @@ QString CSMTools::Search::formatDescription (const QString& description, int pos text.remove ('\r'); // split - int padding = 10; ///< \todo make this configurable - QString highlight = flatten (text.mid (pos, length)); - QString before = flatten (padding<=pos ? text.mid (0, pos) : text.mid (pos-padding, padding)); - QString after = flatten (text.mid (pos+length, padding)); + QString before = flatten (mPaddingBefore<=pos ? + text.mid (0, pos) : text.mid (pos-mPaddingBefore, mPaddingBefore)); + QString after = flatten (text.mid (pos+length, mPaddingAfter)); // join text = before + "" + highlight + "" + after; @@ -111,24 +110,24 @@ QString CSMTools::Search::flatten (const QString& text) const return flat; } -CSMTools::Search::Search() : mType (Type_None) {} +CSMTools::Search::Search() : mType (Type_None), mPaddingBefore (10), mPaddingAfter (10) {} CSMTools::Search::Search (Type type, const std::string& value) -: mType (type), mText (value) +: mType (type), mText (value), mPaddingBefore (10), mPaddingAfter (10) { if (type!=Type_Text && type!=Type_Id) throw std::logic_error ("Invalid search parameter (string)"); } CSMTools::Search::Search (Type type, const QRegExp& value) -: mType (type), mRegExp (value) +: mType (type), mRegExp (value), mPaddingBefore (10), mPaddingAfter (10) { if (type!=Type_TextRegEx && type!=Type_IdRegEx) throw std::logic_error ("Invalid search parameter (RegExp)"); } CSMTools::Search::Search (Type type, int value) -: mType (type), mValue (value) +: mType (type), mValue (value), mPaddingBefore (10), mPaddingAfter (10) { if (type!=Type_RecordState) throw std::logic_error ("invalid search parameter (int)"); @@ -230,3 +229,9 @@ void CSMTools::Search::searchRow (const CSMWorld::IdTableBase *model, int row, } } } + +void CSMTools::Search::setPadding (int before, int after) +{ + mPaddingBefore = before; + mPaddingAfter = after; +} diff --git a/apps/opencs/model/tools/search.hpp b/apps/opencs/model/tools/search.hpp index 0148beab3..452b3cad2 100644 --- a/apps/opencs/model/tools/search.hpp +++ b/apps/opencs/model/tools/search.hpp @@ -45,6 +45,8 @@ namespace CSMTools std::set mColumns; int mIdColumn; int mTypeColumn; + int mPaddingBefore; + int mPaddingAfter; void searchTextCell (const CSMWorld::IdTableBase *model, const QModelIndex& index, const CSMWorld::UniversalId& id, CSMDoc::Messages& messages) const; @@ -78,6 +80,8 @@ namespace CSMTools // \attention *this needs to be configured for \a model. void searchRow (const CSMWorld::IdTableBase *model, int row, CSMDoc::Messages& messages) const; + + void setPadding (int before, int after); }; } diff --git a/apps/opencs/view/tools/searchsubview.cpp b/apps/opencs/view/tools/searchsubview.cpp index 146b94ef4..36fd65a2b 100644 --- a/apps/opencs/view/tools/searchsubview.cpp +++ b/apps/opencs/view/tools/searchsubview.cpp @@ -4,12 +4,13 @@ #include #include "../../model/doc/document.hpp" +#include "../../model/tools/search.hpp" #include "reporttable.hpp" #include "searchbox.hpp" CSVTools::SearchSubView::SearchSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) -: CSVDoc::SubView (id), mDocument (document) +: CSVDoc::SubView (id), mDocument (document), mPaddingBefore (10), mPaddingAfter (10) { QVBoxLayout *layout = new QVBoxLayout; @@ -45,6 +46,14 @@ void CSVTools::SearchSubView::setEditLock (bool locked) void CSVTools::SearchSubView::updateUserSetting (const QString &name, const QStringList &list) { mTable->updateUserSetting (name, list); + + if (!list.empty()) + { + if (name=="search/char-before") + mPaddingBefore = list.at (0).toInt(); + else if (name=="search/char-after") + mPaddingAfter = list.at (0).toInt(); + } } void CSVTools::SearchSubView::stateChanged (int state, CSMDoc::Document *document) @@ -54,6 +63,9 @@ void CSVTools::SearchSubView::stateChanged (int state, CSMDoc::Document *documen void CSVTools::SearchSubView::startSearch (const CSMTools::Search& search) { + CSMTools::Search search2 (search); + search2.setPadding (mPaddingBefore, mPaddingAfter); + mTable->clear(); - mDocument.runSearch (getUniversalId(), search); + mDocument.runSearch (getUniversalId(), search2); } diff --git a/apps/opencs/view/tools/searchsubview.hpp b/apps/opencs/view/tools/searchsubview.hpp index d17f7a340..b9b24f774 100644 --- a/apps/opencs/view/tools/searchsubview.hpp +++ b/apps/opencs/view/tools/searchsubview.hpp @@ -24,6 +24,8 @@ namespace CSVTools ReportTable *mTable; SearchBox mSearchBox; CSMDoc::Document& mDocument; + int mPaddingBefore; + int mPaddingAfter; public: From 66c866aec945b0c74939d1c1a317407e9c0bff11 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 31 Mar 2015 13:02:12 +0200 Subject: [PATCH 0869/3725] fixed search result formatting --- apps/opencs/model/tools/search.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/opencs/model/tools/search.cpp b/apps/opencs/model/tools/search.cpp index 28d92f06a..db495be11 100644 --- a/apps/opencs/model/tools/search.cpp +++ b/apps/opencs/model/tools/search.cpp @@ -81,15 +81,15 @@ QString CSMTools::Search::formatDescription (const QString& description, int pos { QString text (description); - // compensate for Windows nonsense - text.remove ('\r'); - // split QString highlight = flatten (text.mid (pos, length)); - QString before = flatten (mPaddingBefore<=pos ? + QString before = flatten (mPaddingBefore>=pos ? text.mid (0, pos) : text.mid (pos-mPaddingBefore, mPaddingBefore)); QString after = flatten (text.mid (pos+length, mPaddingAfter)); + // compensate for Windows nonsense + text.remove ('\r'); + // join text = before + "" + highlight + "" + after; From a9a8b5ad475bfbd80e0f5a390f849083d8507168 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 31 Mar 2015 14:25:27 +0200 Subject: [PATCH 0870/3725] improved performance of CSVRender::Cell::addObjects by bypassing Qt model --- apps/opencs/view/render/cell.cpp | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index ae2fad95a..a030ea11f 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -10,6 +10,7 @@ #include "../../model/world/idtable.hpp" #include "../../model/world/columns.hpp" #include "../../model/world/data.hpp" +#include "../../model/world/refcollection.hpp" #include "../world/physicssystem.hpp" #include "elements.hpp" @@ -30,26 +31,19 @@ bool CSVRender::Cell::removeObject (const std::string& id) bool CSVRender::Cell::addObjects (int start, int end) { - CSMWorld::IdTable& references = dynamic_cast ( - *mData.getTableModel (CSMWorld::UniversalId::Type_References)); - - int idColumn = references.findColumnIndex (CSMWorld::Columns::ColumnId_Id); - int cellColumn = references.findColumnIndex (CSMWorld::Columns::ColumnId_Cell); - int stateColumn = references.findColumnIndex (CSMWorld::Columns::ColumnId_Modification); - bool modified = false; + const CSMWorld::RefCollection& collection = mData.getReferences(); + for (int i=start; i<=end; ++i) { - std::string cell = Misc::StringUtils::lowerCase (references.data ( - references.index (i, cellColumn)).toString().toUtf8().constData()); + std::string cell = Misc::StringUtils::lowerCase (collection.getRecord (i).get().mCell); - int state = references.data (references.index (i, stateColumn)).toInt(); + CSMWorld::RecordBase::State state = collection.getRecord (i).mState; if (cell==mId && state!=CSMWorld::RecordBase::State_Deleted) { - std::string id = Misc::StringUtils::lowerCase (references.data ( - references.index (i, idColumn)).toString().toUtf8().constData()); + std::string id = Misc::StringUtils::lowerCase (collection.getRecord (i).get().mId); mObjects.insert (std::make_pair (id, new Object (mData, mCellNode, id, false, mPhysics))); modified = true; From 4e69e7cc0f0271f3185953683efd9201252ddc24 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 1 Apr 2015 17:02:15 +0200 Subject: [PATCH 0871/3725] OpenMW compiles and runs w/o render window --- CMakeLists.txt | 8 +- apps/openmw/CMakeLists.txt | 30 +- apps/openmw/engine.cpp | 66 +- apps/openmw/engine.hpp | 2 +- apps/openmw/mwclass/creature.cpp | 8 +- apps/openmw/mwclass/npc.cpp | 8 +- apps/openmw/mwgui/birth.cpp | 2 +- apps/openmw/mwgui/cursor.cpp | 2 - apps/openmw/mwgui/formatting.cpp | 5 +- apps/openmw/mwgui/hud.cpp | 2 +- apps/openmw/mwgui/inventorywindow.cpp | 13 +- apps/openmw/mwgui/itemwidget.cpp | 2 +- apps/openmw/mwgui/mapwindow.cpp | 27 +- apps/openmw/mwgui/mapwindow.hpp | 2 +- apps/openmw/mwgui/quickkeysmenu.cpp | 2 +- apps/openmw/mwgui/race.cpp | 29 +- apps/openmw/mwgui/race.hpp | 2 +- apps/openmw/mwgui/savegamedialog.cpp | 3 +- apps/openmw/mwgui/spellcreationdialog.cpp | 2 +- apps/openmw/mwgui/spellicons.cpp | 2 +- apps/openmw/mwgui/tooltips.cpp | 6 +- apps/openmw/mwgui/videowidget.cpp | 22 +- apps/openmw/mwgui/videowidget.hpp | 2 +- apps/openmw/mwgui/widgets.cpp | 2 +- apps/openmw/mwgui/windowmanagerimp.cpp | 66 +- apps/openmw/mwmechanics/actor.cpp | 8 +- apps/openmw/mwmechanics/aicombat.cpp | 10 +- apps/openmw/mwmechanics/alchemy.cpp | 1 + .../mwmechanics/mechanicsmanagerimp.cpp | 72 +- .../mwmechanics/mechanicsmanagerimp.hpp | 8 +- apps/openmw/mwmechanics/spellcasting.cpp | 16 +- apps/openmw/mwmechanics/summoning.cpp | 6 +- apps/openmw/mwrender/actors.cpp | 50 +- apps/openmw/mwrender/actors.hpp | 31 +- apps/openmw/mwrender/objects.cpp | 108 +-- apps/openmw/mwrender/objects.hpp | 1 - apps/openmw/mwrender/renderingmanager.cpp | 36 +- apps/openmw/mwrender/renderingmanager.hpp | 7 - apps/openmw/mwscript/interpretercontext.cpp | 2 + apps/openmw/mwsound/soundmanagerimp.cpp | 3 + apps/openmw/mwworld/physicssystem.cpp | 28 +- apps/openmw/mwworld/scene.cpp | 57 +- apps/openmw/mwworld/scene.hpp | 9 +- apps/openmw/mwworld/weather.cpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 259 ++++---- apps/openmw/mwworld/worldimp.hpp | 22 +- cmake/FindMyGUI.cmake | 10 +- components/CMakeLists.txt | 4 - components/esm/esmreader.cpp | 3 +- components/esm/esmreader.hpp | 5 + components/fontloader/fontloader.cpp | 2 + components/nifoverrides/nifoverrides.cpp | 80 --- components/nifoverrides/nifoverrides.hpp | 38 -- files/transparency-overrides.cfg | 623 ------------------ libs/openengine/CMakeLists.txt | 4 +- 55 files changed, 534 insertions(+), 1286 deletions(-) delete mode 100644 components/nifoverrides/nifoverrides.cpp delete mode 100644 components/nifoverrides/nifoverrides.hpp delete mode 100644 files/transparency-overrides.cfg diff --git a/CMakeLists.txt b/CMakeLists.txt index cde53f27a..bf525646d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -328,9 +328,6 @@ endif (APPLE) configure_file(${OpenMW_SOURCE_DIR}/files/settings-default.cfg "${OpenMW_BINARY_DIR}/settings-default.cfg") -configure_file(${OpenMW_SOURCE_DIR}/files/transparency-overrides.cfg - "${OpenMW_BINARY_DIR}/transparency-overrides.cfg") - configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg.local "${OpenMW_BINARY_DIR}/openmw.cfg") @@ -433,7 +430,6 @@ IF(NOT WIN32 AND NOT APPLE) # Install global configuration files INSTALL(FILES "${OpenMW_BINARY_DIR}/settings-default.cfg" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw") - INSTALL(FILES "${OpenMW_BINARY_DIR}/transparency-overrides.cfg" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw") INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" DESTINATION "${SYSCONFDIR}" RENAME "openmw.cfg" COMPONENT "openmw") INSTALL(FILES "${OpenMW_BINARY_DIR}/gamecontrollerdb.txt" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw") @@ -456,7 +452,6 @@ if(WIN32) "${OpenMW_SOURCE_DIR}/Docs/license/GPL3.txt" "${OpenMW_SOURCE_DIR}/Docs/license/DejaVu Font License.txt" "${OpenMW_BINARY_DIR}/settings-default.cfg" - "${OpenMW_BINARY_DIR}/transparency-overrides.cfg" "${OpenMW_BINARY_DIR}/gamecontrollerdb.txt" "${OpenMW_BINARY_DIR}/Release/openmw.exe" DESTINATION ".") @@ -549,7 +544,7 @@ add_subdirectory(libs/openengine) # Extern #add_subdirectory (extern/shiny) #add_subdirectory (extern/ogre-ffmpeg-videoplayer) -#add_subdirectory (extern/oics) +add_subdirectory (extern/oics) #add_subdirectory (extern/sdl4ogre) # Components @@ -714,7 +709,6 @@ if (APPLE) install(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" RENAME "openmw.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) install(FILES "${OpenMW_BINARY_DIR}/settings-default.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) install(FILES "${OpenMW_BINARY_DIR}/gamecontrollerdb.txt" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) - install(FILES "${OpenMW_BINARY_DIR}/transparency-overrides.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) install(FILES "${OpenMW_BINARY_DIR}/opencs.ini" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) set(CPACK_GENERATOR "DragNDrop") diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index a183d172d..56ee82d7d 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -20,15 +20,16 @@ set(GAME_HEADER source_group(game FILES ${GAME} ${GAME_HEADER}) add_openmw_dir (mwrender - renderingmanager debugging sky camera animation npcanimation creatureanimation activatoranimation - actors objects renderinginterface localmap occlusionquery water shadows - characterpreview globalmap ripplesimulation refraction - terrainstorage renderconst effectmanager weaponanimation +actors objects +# renderingmanager debugging sky camera animation npcanimation creatureanimation activatoranimation +# renderinginterface localmap occlusionquery water shadows +# characterpreview globalmap ripplesimulation refraction +# terrainstorage renderconst effectmanager weaponanimation ) -add_openmw_dir (mwinput - inputmanagerimp - ) +#add_openmw_dir (mwinput +# inputmanagerimp +# ) add_openmw_dir (mwgui textinput widgets race class birth review windowmanagerimp console dialogue @@ -57,16 +58,18 @@ add_openmw_dir (mwscript ) add_openmw_dir (mwsound - soundmanagerimp openal_output ffmpeg_decoder sound sound_decoder sound_output loudness libavwrapper movieaudiofactory + soundmanagerimp openal_output ffmpeg_decoder sound sound_decoder sound_output loudness libavwrapper +# movieaudiofactory ) add_openmw_dir (mwworld - refdata worldimp physicssystem scene globals class action nullaction actionteleport + refdata worldimp scene globals class action nullaction actionteleport containerstore actiontalk actiontake manualref player cellfunctors failedaction - cells localscripts customdata weather inventorystore ptr actionopen actionread + cells localscripts customdata inventorystore ptr actionopen actionread actionequip timestamp actionalchemy cellstore actionapply actioneat esmstore store recordcmp fallback actionrepair actionsoulgem livecellref actiondoor - contentloader esmloader actiontrap cellreflist projectilemanager cellref + contentloader esmloader actiontrap cellreflist cellref physicssystem +# weather projectilemanager ) add_openmw_dir (mwclass @@ -75,10 +78,11 @@ add_openmw_dir (mwclass ) add_openmw_dir (mwmechanics - mechanicsmanagerimp stat character creaturestats magiceffects movement actors objects + mechanicsmanagerimp stat creaturestats magiceffects movement drawstate spells activespells npcstats aipackage aisequence aipursue alchemy aiwander aitravel aifollow aiavoiddoor aiescort aiactivate aicombat repair enchanting pathfinding pathgrid security spellsuccess spellcasting disease pickpocket levelledlist combat steering obstacle autocalcspell difficultyscaling aicombataction actor summoning +# character actors objects ) add_openmw_dir (mwstate @@ -133,9 +137,7 @@ target_link_libraries(openmw ${MYGUI_LIBRARIES} ${SDL2_LIBRARY} ${MYGUI_PLATFORM_LIBRARIES} - "ogre-ffmpeg-videoplayer" "oics" - "sdl4ogre" components ) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index a4bb8c538..c7a92e52e 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -14,17 +14,14 @@ #include -#include #include #include -#include #include -#include #include -#include "mwinput/inputmanagerimp.hpp" +//#include "mwinput/inputmanagerimp.hpp" #include "mwgui/windowmanagerimp.hpp" @@ -86,12 +83,12 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) mEnvironment.setFrameDuration (frametime); // update input - MWBase::Environment::get().getInputManager()->update(frametime, false); + //MWBase::Environment::get().getInputManager()->update(frametime, false); // When the window is minimized, pause everything. Currently this *has* to be here to work around a MyGUI bug. // If we are not currently rendering, then RenderItems will not be reused resulting in a memory leak upon changing widget textures. - if (!mOgre->getWindow()->isActive() || !mOgre->getWindow()->isVisible()) - return true; + //if (!mOgre->getWindow()->isActive() || !mOgre->getWindow()->isVisible()) + // return true; // sound if (mUseSound) @@ -157,11 +154,12 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) if (MWBase::Environment::get().getStateManager()->getState()!= MWBase::StateManager::State_NoGame) { +#if 0 Ogre::RenderWindow* window = mOgre->getWindow(); unsigned int tri, batch; MWBase::Environment::get().getWorld()->getTriangleBatchCount(tri, batch); MWBase::Environment::get().getWindowManager()->wmUpdateFps(window->getLastFPS(), tri, batch); - +#endif MWBase::Environment::get().getWindowManager()->update(); } } @@ -210,11 +208,8 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) OMW::Engine::~Engine() { - if (mOgre) - mOgre->restoreWindowGammaRamp(); mEnvironment.cleanup(); delete mScriptContext; - delete mOgre; SDL_Quit(); } @@ -223,14 +218,10 @@ OMW::Engine::~Engine() void OMW::Engine::addResourcesDirectory (const boost::filesystem::path& path) { - mOgre->getRoot()->addResourceLocation (path.string(), "FileSystem", - Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, true); } void OMW::Engine::addZipResource (const boost::filesystem::path& path) { - mOgre->getRoot()->addResourceLocation (path.string(), "Zip", - Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, false); } void OMW::Engine::enableFSStrict(bool fsStrict) @@ -299,19 +290,6 @@ std::string OMW::Engine::loadSettings (Settings::Manager & settings) if (boost::filesystem::exists(settingspath)) settings.loadUser(settingspath); - // load nif overrides - NifOverrides::Overrides nifOverrides; - std::string transparencyOverrides = "/transparency-overrides.cfg"; - std::string materialOverrides = "/material-overrides.cfg"; - if (boost::filesystem::exists(mCfgMgr.getLocalPath().string() + transparencyOverrides)) - nifOverrides.loadTransparencyOverrides(mCfgMgr.getLocalPath().string() + transparencyOverrides); - else if (boost::filesystem::exists(mCfgMgr.getGlobalPath().string() + transparencyOverrides)) - nifOverrides.loadTransparencyOverrides(mCfgMgr.getGlobalPath().string() + transparencyOverrides); - if (boost::filesystem::exists(mCfgMgr.getLocalPath().string() + materialOverrides)) - nifOverrides.loadMaterialOverrides(mCfgMgr.getLocalPath().string() + materialOverrides); - else if (boost::filesystem::exists(mCfgMgr.getGlobalPath().string() + materialOverrides)) - nifOverrides.loadMaterialOverrides(mCfgMgr.getGlobalPath().string() + materialOverrides); - return settingspath; } @@ -330,13 +308,6 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) #endif } - mOgre = new OEngine::Render::OgreRenderer; - - mOgre->configure( - mCfgMgr.getLogPath().string(), - renderSystem, - Settings::Manager::getString("opengl rtt mode", "Video")); - // This has to be added BEFORE MyGUI is initialized, as it needs // to find core.xml here. @@ -361,9 +332,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, settings.getBool("minimize on focus loss", "Video") ? "1" : "0"); - mOgre->createWindow("OpenMW", windowSettings); - - Bsa::registerResources (mFileCollections, mArchives, true, mFSStrict); + //Bsa::registerResources (mFileCollections, mArchives, true, mFSStrict); // Create input and UI first to set up a bootstrapping environment for // showing a loading screen and keeping the window responsive while doing so @@ -390,19 +359,17 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) else gameControllerdb = ""; //if it doesn't exist, pass in an empty string - MWInput::InputManager* input = new MWInput::InputManager (*mOgre, *this, keybinderUser, keybinderUserExists, gameControllerdb, mGrab); - mEnvironment.setInputManager (input); + //MWInput::InputManager* input = new MWInput::InputManager (*mOgre, *this, keybinderUser, keybinderUserExists, gameControllerdb, mGrab); + //mEnvironment.setInputManager (input); MWGui::WindowManager* window = new MWGui::WindowManager( - mExtensions, mOgre, mCfgMgr.getLogPath().string() + std::string("/"), + mExtensions, NULL, mCfgMgr.getLogPath().string() + std::string("/"), mCfgMgr.getCachePath ().string(), mScriptConsoleMode, mTranslationDataStorage, mEncoding, mExportFonts, mFallbackMap); mEnvironment.setWindowManager (window); // Create sound system mEnvironment.setSoundManager (new MWSound::SoundManager(mUseSound)); - mOgre->setWindowGammaContrast(Settings::Manager::getFloat("gamma", "General"), Settings::Manager::getFloat("contrast", "General")); - if (!mSkipMenu) { std::string logo = mFallbackMap["Movies_Company_Logo"]; @@ -411,11 +378,11 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) } // Create the world - mEnvironment.setWorld( new MWWorld::World (*mOgre, mFileCollections, mContentFiles, + mEnvironment.setWorld( new MWWorld::World (mFileCollections, mContentFiles, mResDir, mCfgMgr.getCachePath(), mEncoder, mFallbackMap, mActivationDistanceOverride, mCellName, mStartupScript)); MWBase::Environment::get().getWorld()->setupPlayer(); - input->setPlayer(&mEnvironment.getWorld()->getPlayer()); + //input->setPlayer(&mEnvironment.getWorld()->getPlayer()); window->initUI(); window->renderWorldMap(); @@ -443,7 +410,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) mEnvironment.setJournal (new MWDialogue::Journal); mEnvironment.setDialogueManager (new MWDialogue::DialogueManager (mExtensions, mVerboseScripts, mTranslationDataStorage)); - mOgre->getRoot()->addFrameListener (this); + //mOgre->getRoot()->addFrameListener (this); // scripts if (mCompileAll) @@ -473,7 +440,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) void OMW::Engine::go() { assert (!mContentFiles.empty()); - assert (!mOgre); + //assert (!mOgre); Settings::Manager settings; std::string settingspath; @@ -514,6 +481,7 @@ void OMW::Engine::go() } // Start the main rendering loop + /* Ogre::Timer timer; while (!MWBase::Environment::get().getStateManager()->hasQuitRequest()) { @@ -523,6 +491,8 @@ void OMW::Engine::go() timer.reset(); Ogre::Root::getSingleton().renderOneFrame(dt); } + */ + // Save user settings settings.saveUser(settingspath); @@ -577,7 +547,7 @@ void OMW::Engine::screenshot() } while (boost::filesystem::exists(stream.str())); - mOgre->screenshot(stream.str(), format); + //mOgre->screenshot(stream.str(), format); } void OMW::Engine::setCompileAll (bool all) diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index 3b088595c..ef26ceb3a 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -98,7 +98,7 @@ namespace OMW bool mScriptBlacklistUse; bool mNewGame; - Nif::Cache mNifCache; + //Nif::Cache mNifCache; // not implemented Engine (const Engine&); diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 8404b9523..ac99fa4b4 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -163,17 +163,17 @@ namespace MWClass void Creature::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { - MWWorld::LiveCellRef *ref = ptr.get(); + //MWWorld::LiveCellRef *ref = ptr.get(); - MWRender::Actors& actors = renderingInterface.getActors(); - actors.insertCreature(ptr, model, (ref->mBase->mFlags & ESM::Creature::Weapon) != 0); + //MWRender::Actors& actors = renderingInterface.getActors(); + //actors.insertCreature(ptr, model, (ref->mBase->mFlags & ESM::Creature::Weapon) != 0); } void Creature::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const { if(!model.empty()) { - physics.addActor(ptr, model); + //physics.addActor(ptr, model); if (getCreatureStats(ptr).isDead()) MWBase::Environment::get().getWorld()->enableActorCollision(ptr, false); } diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 1d58dc87e..3dcb57fbb 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -3,8 +3,6 @@ #include -#include - #include #include @@ -1151,9 +1149,9 @@ namespace MWClass if (ptr.getClass().getNpcStats(ptr).isWerewolf() && ptr.getClass().getCreatureStats(ptr).getStance(MWMechanics::CreatureStats::Stance_Run)) { - MWMechanics::WeaponType weaponType = MWMechanics::WeapType_None; - MWMechanics::getActiveWeapon(ptr.getClass().getCreatureStats(ptr), ptr.getClass().getInventoryStore(ptr), &weaponType); - if (weaponType == MWMechanics::WeapType_None) + //MWMechanics::WeaponType weaponType = MWMechanics::WeapType_None; + //MWMechanics::getActiveWeapon(ptr.getClass().getCreatureStats(ptr), ptr.getClass().getInventoryStore(ptr), &weaponType); + //if (weaponType == MWMechanics::WeapType_None) return ""; } diff --git a/apps/openmw/mwgui/birth.cpp b/apps/openmw/mwgui/birth.cpp index 668253712..475428f33 100644 --- a/apps/openmw/mwgui/birth.cpp +++ b/apps/openmw/mwgui/birth.cpp @@ -183,7 +183,7 @@ namespace MWGui const ESM::BirthSign *birth = store.get().find(mCurrentBirthId); - mBirthImage->setImageTexture(Misc::ResourceHelpers::correctTexturePath(birth->mTexture)); + //mBirthImage->setImageTexture(Misc::ResourceHelpers::correctTexturePath(birth->mTexture)); std::vector abilities, powers, spells; diff --git a/apps/openmw/mwgui/cursor.cpp b/apps/openmw/mwgui/cursor.cpp index 9c64f94ca..82e0b9699 100644 --- a/apps/openmw/mwgui/cursor.cpp +++ b/apps/openmw/mwgui/cursor.cpp @@ -5,8 +5,6 @@ #include #include -#include - namespace MWGui { diff --git a/apps/openmw/mwgui/formatting.cpp b/apps/openmw/mwgui/formatting.cpp index 761a89ca6..d96255c85 100644 --- a/apps/openmw/mwgui/formatting.cpp +++ b/apps/openmw/mwgui/formatting.cpp @@ -1,8 +1,5 @@ #include "formatting.hpp" -#include -#include - #include #include #include @@ -466,7 +463,7 @@ namespace MWGui MyGUI::IntCoord(left, pag.getCurrentTop(), width, mImageHeight), MyGUI::Align::Left | MyGUI::Align::Top, parent->getName() + MyGUI::utility::toString(parent->getChildCount())); - std::string image = Misc::ResourceHelpers::correctBookartPath(src, width, mImageHeight); + std::string image;// = Misc::ResourceHelpers::correctBookartPath(src, width, mImageHeight); mImageBox->setImageTexture(image); mImageBox->setProperty("NeedMouse", "false"); } diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index eb458be50..2323d39e7 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -448,7 +448,7 @@ namespace MWGui std::string icon = effect->mIcon; int slashPos = icon.rfind('\\'); icon.insert(slashPos+1, "b_"); - icon = Misc::ResourceHelpers::correctIconPath(icon); + //icon = Misc::ResourceHelpers::correctIconPath(icon); mSpellImage->setItem(MWWorld::Ptr()); mSpellImage->setIcon(icon); diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 80b246e84..c3932d388 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -53,7 +53,9 @@ namespace MWGui , mTrading(false) , mLastXSize(0) , mLastYSize(0) + #if 0 , mPreview(new MWRender::InventoryPreview(MWBase::Environment::get().getWorld ()->getPlayerPtr())) + #endif , mPreviewDirty(true) , mPreviewResize(true) , mDragAndDrop(dragAndDrop) @@ -118,10 +120,10 @@ namespace MWGui MyGUI::ITexture* tex = MyGUI::RenderManager::getInstance().getTexture("CharacterPreview"); if (tex) MyGUI::RenderManager::getInstance().destroyTexture(tex); - +#if 0 mPreview.reset(new MWRender::InventoryPreview(mPtr)); mPreview->setup(); - +#endif mPreviewDirty = true; mPreviewResize = true; } @@ -481,6 +483,8 @@ namespace MWGui MWWorld::Ptr InventoryWindow::getAvatarSelectedItem(int x, int y) { + return MWWorld::Ptr(); +#if 0 int slot = mPreview->getSlotSelected (x, y); if (slot == -1) @@ -499,6 +503,7 @@ namespace MWGui } return MWWorld::Ptr(); +#endif } void InventoryWindow::updateEncumbranceBar() @@ -526,6 +531,7 @@ namespace MWGui void InventoryWindow::doRenderUpdate () { +#if 0 mPreview->onFrame(); if (mPreviewResize || mPreviewDirty) @@ -552,6 +558,7 @@ namespace MWGui mAvatarImage->setImageTexture("CharacterPreview"); } +#endif } void InventoryWindow::notifyContentChanged() @@ -668,6 +675,8 @@ namespace MWGui void InventoryWindow::rebuildAvatar() { +#if 0 mPreview->rebuild(); +#endif } } diff --git a/apps/openmw/mwgui/itemwidget.cpp b/apps/openmw/mwgui/itemwidget.cpp index 36940113e..1da2ab879 100644 --- a/apps/openmw/mwgui/itemwidget.cpp +++ b/apps/openmw/mwgui/itemwidget.cpp @@ -77,7 +77,7 @@ namespace MWGui void ItemWidget::setIcon(const MWWorld::Ptr &ptr) { - setIcon(Misc::ResourceHelpers::correctIconPath(ptr.getClass().getInventoryIcon(ptr))); + //setIcon(Misc::ResourceHelpers::correctIconPath(ptr.getClass().getInventoryIcon(ptr))); } diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 02e8ffdfe..d65e242de 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -212,6 +212,7 @@ namespace MWGui void LocalMapBase::applyFogOfWar() { +#if 0 for (int mx=0; mx<3; ++mx) { for (int my=0; my<3; ++my) @@ -225,6 +226,7 @@ namespace MWGui : ""); } } +#endif redraw(); } @@ -338,6 +340,7 @@ namespace MWGui mDoorMarkerWidgets.clear(); // Update the map textures +#if 0 for (int mx=0; mx<3; ++mx) { for (int my=0; my<3; ++my) @@ -354,7 +357,7 @@ namespace MWGui box->setImageTexture("black.png"); } } - +#endif MWBase::World* world = MWBase::Environment::get().getWorld(); // Retrieve the door markers we want to show @@ -558,7 +561,7 @@ namespace MWGui , LocalMapBase(customMarkers) , mGlobal(false) , mGlobalMap(0) - , mGlobalMapRender(0) + //, mGlobalMapRender(0) , mEditNoteDialog() , mEventBoxGlobal(NULL) , mEventBoxLocal(NULL) @@ -705,18 +708,19 @@ namespace MWGui void MapWindow::renderGlobalMap(Loading::Listener* loadingListener) { +#if 0 mGlobalMapRender = new MWRender::GlobalMap(""); mGlobalMapRender->render(loadingListener); mGlobalMap->setCanvasSize (mGlobalMapRender->getWidth(), mGlobalMapRender->getHeight()); mGlobalMapImage->setSize(mGlobalMapRender->getWidth(), mGlobalMapRender->getHeight()); - mGlobalMapImage->setImageTexture("GlobalMap.png"); mGlobalMapOverlay->setImageTexture("GlobalMapOverlay"); +#endif } MapWindow::~MapWindow() { - delete mGlobalMapRender; + //delete mGlobalMapRender; } void MapWindow::setCellName(const std::string& cellName) @@ -726,6 +730,7 @@ namespace MWGui void MapWindow::addVisitedLocation(const std::string& name, int x, int y) { +#if 0 CellId cell; cell.first = x; cell.second = y; @@ -752,6 +757,7 @@ namespace MWGui markerWidget->eventMouseDrag += MyGUI::newDelegate(this, &MapWindow::onMouseDrag); markerWidget->eventMouseButtonPressed += MyGUI::newDelegate(this, &MapWindow::onDragStart); } +#endif } void MapWindow::cellExplored(int x, int y) @@ -763,10 +769,12 @@ namespace MWGui { LocalMapBase::onFrame(dt); +#if 0 for (std::vector::iterator it = mQueuedToExplore.begin(); it != mQueuedToExplore.end(); ++it) { mGlobalMapRender->exploreCell(it->first, it->second); } +#endif mQueuedToExplore.clear(); NoDrop::onFrame(dt); @@ -823,12 +831,14 @@ namespace MWGui void MapWindow::globalMapUpdatePlayer () { +#if 0 // For interiors, position is set by WindowManager via setGlobalMapPlayerPosition if (MWBase::Environment::get().getWorld ()->isCellExterior ()) { Ogre::Vector3 pos = MWBase::Environment::get().getWorld ()->getPlayerPtr().getRefData ().getBaseNode ()->_getDerivedPosition (); setGlobalMapPlayerPosition(pos.x, pos.y); } +#endif } void MapWindow::notifyPlayerUpdate () @@ -838,6 +848,7 @@ namespace MWGui void MapWindow::setGlobalMapPlayerPosition(float worldX, float worldY) { +#if 0 float x, y; mGlobalMapRender->worldPosToImageSpace (worldX, worldY, x, y); x *= mGlobalMapRender->getWidth(); @@ -849,6 +860,7 @@ namespace MWGui MyGUI::IntSize viewsize = mGlobalMap->getSize(); MyGUI::IntPoint viewoffs(static_cast(viewsize.width * 0.5f - x), static_cast(viewsize.height *0.5 - y)); mGlobalMap->setViewOffset(viewoffs); +#endif } void MapWindow::setGlobalMapPlayerDir(const float x, const float y) @@ -863,7 +875,8 @@ namespace MWGui void MapWindow::clear() { mMarkers.clear(); - mGlobalMapRender->clear(); + + //mGlobalMapRender->clear(); mChanged = true; while (mEventBoxGlobal->getChildCount()) @@ -872,6 +885,7 @@ namespace MWGui void MapWindow::write(ESM::ESMWriter &writer, Loading::Listener& progress) { +#if 0 ESM::GlobalMap map; mGlobalMapRender->write(map); @@ -880,10 +894,12 @@ namespace MWGui writer.startRecord(ESM::REC_GMAP); map.save(writer); writer.endRecord(ESM::REC_GMAP); +#endif } void MapWindow::readRecord(ESM::ESMReader &reader, uint32_t type) { +#if 0 if (type == ESM::REC_GMAP) { ESM::GlobalMap map; @@ -898,6 +914,7 @@ namespace MWGui addVisitedLocation(cell->mName, it->first, it->second); } } +#endif } void MapWindow::setAlpha(float alpha) diff --git a/apps/openmw/mwgui/mapwindow.hpp b/apps/openmw/mwgui/mapwindow.hpp index a80b3e4c5..68d2e28de 100644 --- a/apps/openmw/mwgui/mapwindow.hpp +++ b/apps/openmw/mwgui/mapwindow.hpp @@ -216,7 +216,7 @@ namespace MWGui MyGUI::Button* mEventBoxGlobal; MyGUI::Button* mEventBoxLocal; - MWRender::GlobalMap* mGlobalMapRender; + //MWRender::GlobalMap* mGlobalMapRender; EditNoteDialog mEditNoteDialog; ESM::CustomMarker mEditingMarker; diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index 8f595df80..5c0fd773d 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -245,7 +245,7 @@ namespace MWGui std::string path = effect->mIcon; int slashPos = path.rfind('\\'); path.insert(slashPos+1, "b_"); - path = Misc::ResourceHelpers::correctIconPath(path); + //path = Misc::ResourceHelpers::correctIconPath(path); button->setFrame("textures\\menu_icon_select_magic.dds", MyGUI::IntCoord(2, 2, 40, 40)); button->setIcon(path); diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index f908a9dd0..af4332c7c 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -125,18 +125,19 @@ namespace MWGui updateSkills(); updateSpellPowers(); - mPreview.reset(NULL); + //mPreview.reset(NULL); mPreviewImage->setImageTexture(""); const std::string textureName = "CharacterHeadPreview"; MyGUI::RenderManager::getInstance().destroyTexture(MyGUI::RenderManager::getInstance().getTexture(textureName)); - mPreview.reset(new MWRender::RaceSelectionPreview()); - mPreview->setup(); - mPreview->update (mCurrentAngle); + //mPreview.reset(new MWRender::RaceSelectionPreview()); + //mPreview->setup(); + //mPreview->update (mCurrentAngle); - const ESM::NPC proto = mPreview->getPrototype(); + //const ESM::NPC& proto = mPreview->getPrototype(); + ESM::NPC proto; setRaceId(proto.mRace); recountParts(); @@ -184,7 +185,7 @@ namespace MWGui mPreviewImage->setImageTexture(""); const std::string textureName = "CharacterHeadPreview"; MyGUI::RenderManager::getInstance().destroyTexture(MyGUI::RenderManager::getInstance().getTexture(textureName)); - mPreview.reset(NULL); + //mPreview.reset(NULL); } // widget controls @@ -204,7 +205,7 @@ namespace MWGui void RaceDialog::onHeadRotate(MyGUI::ScrollBar* scroll, size_t _position) { float angle = (float(_position) / (scroll->getScrollRange()-1) - 0.5f) * 3.14f * 2; - mPreview->update (angle); + //mPreview->update (angle); mPreviewDirty = true; mCurrentAngle = angle; } @@ -316,7 +317,7 @@ namespace MWGui void RaceDialog::updatePreview() { - ESM::NPC record = mPreview->getPrototype(); + ESM::NPC record;// = mPreview->getPrototype(); record.mRace = mCurrentRaceId; record.setIsMale(mGenderIndex == 0); @@ -325,7 +326,7 @@ namespace MWGui try { - mPreview->setPrototype(record); + //mPreview->setPrototype(record); } catch (std::exception& e) { @@ -337,13 +338,13 @@ namespace MWGui void RaceDialog::doRenderUpdate() { - if (!mPreview.get()) + //if (!mPreview.get()) return; - mPreview->onFrame(); + //mPreview->onFrame(); if (mPreviewDirty) { - mPreview->render(); + //mPreview->render(); mPreviewDirty = false; } } @@ -450,6 +451,8 @@ namespace MWGui const ESM::NPC& RaceDialog::getResult() const { - return mPreview->getPrototype(); + static ESM::NPC result; + return result; + //return mPreview->getPrototype(); } } diff --git a/apps/openmw/mwgui/race.hpp b/apps/openmw/mwgui/race.hpp index be16af5d1..f188af2b3 100644 --- a/apps/openmw/mwgui/race.hpp +++ b/apps/openmw/mwgui/race.hpp @@ -108,7 +108,7 @@ namespace MWGui float mCurrentAngle; - std::auto_ptr mPreview; + //std::auto_ptr mPreview; bool mPreviewDirty; }; diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index d022c8e25..980afdfae 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -358,7 +358,7 @@ namespace MWGui << " " << hour << " " << (pm ? "#{sSaveMenuHelp05}" : "#{sSaveMenuHelp04}"); mInfoText->setCaptionWithReplacing(text.str()); - +#if 0 // Decode screenshot std::vector data = mCurrentSlot->mProfile.mScreenshot; // MemoryDataStream doesn't work with const data :( Ogre::DataStreamPtr stream(new Ogre::MemoryDataStream(&data[0], data.size())); @@ -382,5 +382,6 @@ namespace MWGui texture->loadImage(image); mScreenshot->setImageTexture(textureName); +#endif } } diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index c744d3ed6..80806941c 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -180,7 +180,7 @@ namespace MWGui void EditEffectDialog::setMagicEffect (const ESM::MagicEffect *effect) { - mEffectImage->setImageTexture(Misc::ResourceHelpers::correctIconPath(effect->mIcon)); + //mEffectImage->setImageTexture(Misc::ResourceHelpers::correctIconPath(effect->mIcon)); mEffectName->setCaptionWithReplacing("#{"+ESM::MagicEffect::effectIdToString (effect->mIndex)+"}"); diff --git a/apps/openmw/mwgui/spellicons.cpp b/apps/openmw/mwgui/spellicons.cpp index c597cfaeb..8770bab38 100644 --- a/apps/openmw/mwgui/spellicons.cpp +++ b/apps/openmw/mwgui/spellicons.cpp @@ -145,7 +145,7 @@ namespace MWGui ("ImageBox", MyGUI::IntCoord(w,2,16,16), MyGUI::Align::Default); mWidgetMap[it->first] = image; - image->setImageTexture(Misc::ResourceHelpers::correctIconPath(effect->mIcon)); + //image->setImageTexture(Misc::ResourceHelpers::correctIconPath(effect->mIcon)); std::string name = ESM::MagicEffect::effectIdToString (it->first); diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 4e03b788a..8b63ab541 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -388,7 +388,7 @@ namespace MWGui const int imageCaptionHPadding = (caption != "" ? 8 : 0); const int imageCaptionVPadding = (caption != "" ? 4 : 0); - std::string realImage = Misc::ResourceHelpers::correctIconPath(image); + std::string realImage;// = Misc::ResourceHelpers::correctIconPath(image); MyGUI::EditBox* captionWidget = mDynamicToolTipBox->createWidget("NormalText", MyGUI::IntCoord(0, 0, 300, 300), MyGUI::Align::Left | MyGUI::Align::Top, "ToolTipCaption"); captionWidget->setProperty("Static", "true"); @@ -686,7 +686,7 @@ namespace MWGui widget->setUserString("ToolTipType", "Layout"); widget->setUserString("ToolTipLayout", "BirthSignToolTip"); - widget->setUserString("ImageTexture_BirthSignImage", Misc::ResourceHelpers::correctTexturePath(sign->mTexture)); + widget->setUserString("ImageTexture_BirthSignImage", "");//Misc::ResourceHelpers::correctTexturePath(sign->mTexture)); std::string text; text += sign->mName; @@ -781,7 +781,7 @@ namespace MWGui std::string icon = effect->mIcon; int slashPos = icon.rfind('\\'); icon.insert(slashPos+1, "b_"); - icon = Misc::ResourceHelpers::correctIconPath(icon); + //icon = Misc::ResourceHelpers::correctIconPath(icon); widget->setUserString("ToolTipType", "Layout"); widget->setUserString("ToolTipLayout", "MagicEffectToolTip"); diff --git a/apps/openmw/mwgui/videowidget.cpp b/apps/openmw/mwgui/videowidget.cpp index f865de377..4ead16c5b 100644 --- a/apps/openmw/mwgui/videowidget.cpp +++ b/apps/openmw/mwgui/videowidget.cpp @@ -1,51 +1,51 @@ #include "videowidget.hpp" -#include +//#include #include -#include "../mwsound/movieaudiofactory.hpp" +//#include "../mwsound/movieaudiofactory.hpp" namespace MWGui { VideoWidget::VideoWidget() { - mPlayer.reset(new Video::VideoPlayer()); + //mPlayer.reset(new Video::VideoPlayer()); setNeedKeyFocus(true); } void VideoWidget::playVideo(const std::string &video) { - mPlayer->setAudioFactory(new MWSound::MovieAudioFactory()); - mPlayer->playVideo(video); + //mPlayer->setAudioFactory(new MWSound::MovieAudioFactory()); + //mPlayer->playVideo(video); - setImageTexture(mPlayer->getTextureName()); + //setImageTexture(mPlayer->getTextureName()); } int VideoWidget::getVideoWidth() { - return mPlayer->getVideoWidth(); + return 0;//mPlayer->getVideoWidth(); } int VideoWidget::getVideoHeight() { - return mPlayer->getVideoHeight(); + return 0;//mPlayer->getVideoHeight(); } bool VideoWidget::update() { - return mPlayer->update(); + return 0;//mPlayer->update(); } void VideoWidget::stop() { - mPlayer->close(); + //mPlayer->close(); } bool VideoWidget::hasAudioStream() { - return mPlayer->hasAudioStream(); + return 0;//mPlayer->hasAudioStream(); } void VideoWidget::autoResize(bool stretch) diff --git a/apps/openmw/mwgui/videowidget.hpp b/apps/openmw/mwgui/videowidget.hpp index ee44328eb..75aa6e98a 100644 --- a/apps/openmw/mwgui/videowidget.hpp +++ b/apps/openmw/mwgui/videowidget.hpp @@ -42,7 +42,7 @@ namespace MWGui void autoResize (bool stretch); private: - std::auto_ptr mPlayer; + //std::auto_ptr mPlayer; }; } diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index 718624a16..888955391 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -474,7 +474,7 @@ namespace MWGui mTextWidget->setCaptionWithReplacing(spellLine); mRequestedWidth = mTextWidget->getTextSize().width + 24; - mImageWidget->setImageTexture(Misc::ResourceHelpers::correctIconPath(magicEffect->mIcon)); + //mImageWidget->setImageTexture(Misc::ResourceHelpers::correctIconPath(magicEffect->mIcon)); } MWSpellEffect::~MWSpellEffect() diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 279c2f22e..bc7bb0bb5 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -19,11 +19,12 @@ #include #include +#include + #include #include #include -#include #include @@ -102,7 +103,7 @@ namespace MWGui const std::string& logpath, const std::string& cacheDir, bool consoleOnlyScripts, Translation::Storage& translationDataStorage, ToUTF8::FromType encoding, bool exportFonts, const std::map& fallbackMap) : mConsoleOnlyScripts(consoleOnlyScripts) - , mGuiManager(NULL) + //, mGuiManager(NULL) , mRendering(ogre) , mHud(NULL) , mMap(NULL) @@ -177,7 +178,13 @@ namespace MWGui , mFallbackMap(fallbackMap) { // Set up the GUI system - mGuiManager = new OEngine::GUI::MyGUIManager(mRendering->getWindow(), mRendering->getScene(), false, logpath); + //mGuiManager = new OEngine::GUI::MyGUIManager(mRendering->getWindow(), mRendering->getScene(), false, logpath); + + MyGUI::DummyPlatform* platform = new MyGUI::DummyPlatform; + platform->initialise(logpath); + + MyGUI::Gui* gui = new MyGUI::Gui; + gui->initialise(""); MyGUI::LanguageManager::getInstance().eventRequestTag = MyGUI::newDelegate(this, &WindowManager::onRetrieveTag); @@ -207,11 +214,11 @@ namespace MWGui MyGUI::FactoryManager::getInstance().registerFactory("Resource", "ResourceImageSetPointer"); MyGUI::ResourceManager::getInstance().load("core.xml"); - +#if 0 mLoadingScreen = new LoadingScreen(mRendering->getScene (), mRendering->getWindow ()); - +#endif //set up the hardware cursor manager - mCursorManager = new SFO::SDLCursorManager(); + //mCursorManager = new SFO::SDLCursorManager(); MyGUI::PointerManager::getInstance().eventChangeMousePointer += MyGUI::newDelegate(this, &WindowManager::onCursorChange); @@ -219,7 +226,7 @@ namespace MWGui onCursorChange(MyGUI::PointerManager::getInstance().getDefaultPointer()); - mCursorManager->setEnabled(true); + //mCursorManager->setEnabled(true); // hide mygui's pointer MyGUI::PointerManager::getInstance().setVisible(false); @@ -245,6 +252,7 @@ namespace MWGui void WindowManager::initUI() { + /* // Get size info from the Gui object int w = MyGUI::RenderManager::getInstance().getViewSize().width; int h = MyGUI::RenderManager::getInstance().getViewSize().height; @@ -328,6 +336,7 @@ namespace MWGui updateVisible(); MWBase::Environment::get().getInputManager()->changeInputMode(false); + */ } void WindowManager::renderWorldMap() @@ -408,11 +417,11 @@ namespace MWGui delete mDebugWindow; delete mJailScreen; - delete mCursorManager; + //delete mCursorManager; cleanupGarbage(); - delete mGuiManager; + //delete mGuiManager; } void WindowManager::cleanupGarbage() @@ -923,6 +932,7 @@ namespace MWGui void WindowManager::changeCell(MWWorld::CellStore* cell) { + /* std::string name = MWBase::Environment::get().getWorld()->getCellName (cell); mMap->setCellName( name ); @@ -947,10 +957,12 @@ namespace MWGui MWBase::Environment::get().getWorld()->getPlayer().setLastKnownExteriorPosition(worldPos); mMap->setGlobalMapPlayerPosition(worldPos.x, worldPos.y); } + */ } void WindowManager::setActiveMap(int x, int y, bool interior) { + /* if (!interior) { mMap->setCellPrefix("Cell"); @@ -959,19 +971,22 @@ namespace MWGui mMap->setActiveCell(x,y, interior); mHud->setActiveCell(x,y, interior); + */ } void WindowManager::setPlayerPos(int cellX, int cellY, const float x, const float y) { - mMap->setPlayerPos(cellX, cellY, x, y); - mHud->setPlayerPos(cellX, cellY, x, y); + //mMap->setPlayerPos(cellX, cellY, x, y); + //mHud->setPlayerPos(cellX, cellY, x, y); } void WindowManager::setPlayerDir(const float x, const float y) { + /* mMap->setPlayerDir(x,y); mMap->setGlobalMapPlayerDir(x, y); mHud->setPlayerDir(x,y); + */ } void WindowManager::setDrowningBarVisibility(bool visible) @@ -1087,7 +1102,7 @@ namespace MWGui void WindowManager::windowResized(int x, int y) { sizeVideo(x, y); - mGuiManager->windowResized(); + //mGuiManager->windowResized(); if (!mHud) return; // UI not initialized yet @@ -1133,6 +1148,7 @@ namespace MWGui void WindowManager::onCursorChange(const std::string &name) { + /* if(!mCursorManager->cursorChanged(name)) return; //the cursor manager doesn't want any more info about this cursor //See if we can get the information we need out of the cursor resource @@ -1157,6 +1173,7 @@ namespace MWGui mCursorManager->receiveCursorInfo(name, rotation, tex, size_x, size_y, hotspot_x, hotspot_y); } } + */ } void WindowManager::popGuiMode() @@ -1266,7 +1283,7 @@ namespace MWGui void WindowManager::executeInConsole (const std::string& path) { - mConsole->executeFile (path); + //mConsole->executeFile (path); } void WindowManager::wmUpdateFps(float fps, unsigned int triangleCount, unsigned int batchCount) @@ -1507,7 +1524,7 @@ namespace MWGui void WindowManager::updatePlayer() { - mInventoryWindow->updatePlayer(); + //mInventoryWindow->updatePlayer(); const MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); if (player.getClass().getNpcStats(player).isWerewolf()) @@ -1540,9 +1557,22 @@ namespace MWGui mHud->setEnemy(enemy); } + class DummyListener : public Loading::Listener + { + public: + virtual void setLabel (const std::string& label){} + virtual void loadingOn(){} + virtual void loadingOff(){} + virtual void indicateProgress (){} + virtual void setProgressRange (size_t range){} + virtual void setProgress (size_t value){} + virtual void increaseProgress (size_t increase = 1){} + }; + Loading::Listener* WindowManager::getLoadingScreen() { - return mLoadingScreen; + static DummyListener listener; + return &listener; } void WindowManager::startRecharge(MWWorld::Ptr soulgem) @@ -1779,23 +1809,29 @@ namespace MWGui void WindowManager::fadeScreenIn(const float time, bool clearQueue) { + /* if (clearQueue) mScreenFader->clearQueue(); mScreenFader->fadeOut(time); + */ } void WindowManager::fadeScreenOut(const float time, bool clearQueue) { + /* if (clearQueue) mScreenFader->clearQueue(); mScreenFader->fadeIn(time); + */ } void WindowManager::fadeScreenTo(const int percent, const float time, bool clearQueue) { + /* if (clearQueue) mScreenFader->clearQueue(); mScreenFader->fadeTo(percent, time); + */ } void WindowManager::setBlindness(const int percent) diff --git a/apps/openmw/mwmechanics/actor.cpp b/apps/openmw/mwmechanics/actor.cpp index 675bd160a..3161bb413 100644 --- a/apps/openmw/mwmechanics/actor.cpp +++ b/apps/openmw/mwmechanics/actor.cpp @@ -1,23 +1,23 @@ #include "actor.hpp" -#include "character.hpp" +//#include "character.hpp" namespace MWMechanics { Actor::Actor(const MWWorld::Ptr &ptr, MWRender::Animation *animation) { - mCharacterController.reset(new CharacterController(ptr, animation)); + //mCharacterController.reset(new CharacterController(ptr, animation)); } void Actor::updatePtr(const MWWorld::Ptr &newPtr) { - mCharacterController->updatePtr(newPtr); + //mCharacterController->updatePtr(newPtr); } CharacterController* Actor::getCharacterController() { - return mCharacterController.get(); + return 0;//mCharacterController.get(); } AiState& Actor::getAiState() diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 2f68087e5..e570d1c33 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -16,13 +16,13 @@ #include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/dialoguemanager.hpp" -#include "../mwrender/animation.hpp" +//#include "../mwrender/animation.hpp" #include "creaturestats.hpp" #include "steering.hpp" #include "movement.hpp" -#include "character.hpp" // fixme: for getActiveWeapon +//#include "character.hpp" // fixme: for getActiveWeapon #include "aicombataction.hpp" #include "combat.hpp" @@ -188,6 +188,7 @@ namespace MWMechanics */ bool AiCombat::execute (const MWWorld::Ptr& actor, AiState& state, float duration) { +#if 0 // get or create temporary storage AiCombatStorage& storage = state.get(); @@ -673,7 +674,7 @@ namespace MWMechanics // FIXME: can fool actors to stay behind doors, etc. // Related to Bug#1102 and to some degree #1155 as well } - +#endif return false; } @@ -811,6 +812,7 @@ ESM::Weapon::AttackType chooseBestAttack(const ESM::Weapon* weapon, MWMechanics: return attackType; } +#if 0 void getMinMaxAttackDuration(const MWWorld::Ptr& actor, float (*fMinMaxDurations)[2]) { if (!actor.getClass().hasInventoryStore(actor)) // creatures @@ -873,8 +875,8 @@ void getMinMaxAttackDuration(const MWWorld::Ptr& actor, float (*fMinMaxDurations fMinMaxDurations[i][1] = fMinMaxDurations[i][0] + (start1 - start2) / weapSpeed; } - } +#endif Ogre::Vector3 AimDirToMovingTarget(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, const Ogre::Vector3& vLastTargetPos, float duration, int weapType, float strength) diff --git a/apps/openmw/mwmechanics/alchemy.cpp b/apps/openmw/mwmechanics/alchemy.cpp index 58c42ddb8..319d01495 100644 --- a/apps/openmw/mwmechanics/alchemy.cpp +++ b/apps/openmw/mwmechanics/alchemy.cpp @@ -3,6 +3,7 @@ #include #include +#include #include #include diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 0d4518f87..abfc793de 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -269,7 +269,7 @@ namespace MWMechanics creatureStats.getSpells().add(*it); // forced update and current value adjustments - mActors.updateActor (ptr, 0); + //mActors.updateActor (ptr, 0); for (int i=0; i<3; ++i) { @@ -294,22 +294,27 @@ namespace MWMechanics void MechanicsManager::add(const MWWorld::Ptr& ptr) { + /* if(ptr.getClass().isActor()) mActors.addActor(ptr); else mObjects.addObject(ptr); + */ } void MechanicsManager::remove(const MWWorld::Ptr& ptr) { + /* if(ptr == mWatched) mWatched = MWWorld::Ptr(); mActors.removeActor(ptr); mObjects.removeObject(ptr); + */ } void MechanicsManager::updateCell(const MWWorld::Ptr &old, const MWWorld::Ptr &ptr) { + /* if(old == mWatched) mWatched = ptr; @@ -317,13 +322,16 @@ namespace MWMechanics mActors.updateActor(old, ptr); else mObjects.updateObject(old, ptr); + */ } void MechanicsManager::drop(const MWWorld::CellStore *cellStore) { + /* mActors.dropActors(cellStore, mWatched); mObjects.dropObjects(cellStore); + */ } @@ -464,24 +472,24 @@ namespace MWMechanics // HACK? The player has been changed, so a new Animation object may // have been made for them. Make sure they're properly updated. - MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr(); - mActors.removeActor(ptr); - mActors.addActor(ptr, true); + //MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr(); + //mActors.removeActor(ptr); + //mActors.addActor(ptr, true); } - mActors.update(duration, paused); - mObjects.update(duration, paused); + //mActors.update(duration, paused); + //mObjects.update(duration, paused); } void MechanicsManager::rest(bool sleep) { - mActors.restoreDynamicStats (sleep); - mActors.fastForwardAi(); + //mActors.restoreDynamicStats (sleep); + //mActors.fastForwardAi(); } int MechanicsManager::getHoursToRest() const { - return mActors.getHoursToRest(mWatched); + return 0;//mActors.getHoursToRest(mWatched); } void MechanicsManager::setPlayerName (const std::string& name) @@ -671,7 +679,7 @@ namespace MWMechanics int MechanicsManager::countDeaths (const std::string& id) const { - return mActors.countDeaths (id); + return 0;//mActors.countDeaths (id); } void MechanicsManager::getPersuasionDispositionChange (const MWWorld::Ptr& npc, PersuasionType type, @@ -827,35 +835,39 @@ namespace MWMechanics void MechanicsManager::forceStateUpdate(const MWWorld::Ptr &ptr) { - if(ptr.getClass().isActor()) - mActors.forceStateUpdate(ptr); + //if(ptr.getClass().isActor()) + //mActors.forceStateUpdate(ptr); } void MechanicsManager::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number) { + /* if(ptr.getClass().isActor()) mActors.playAnimationGroup(ptr, groupName, mode, number); else mObjects.playAnimationGroup(ptr, groupName, mode, number); + */ } void MechanicsManager::skipAnimation(const MWWorld::Ptr& ptr) { + /* if(ptr.getClass().isActor()) mActors.skipAnimation(ptr); else mObjects.skipAnimation(ptr); + */ } bool MechanicsManager::checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string &groupName) { - if(ptr.getClass().isActor()) - return mActors.checkAnimationPlaying(ptr, groupName); - else + //if(ptr.getClass().isActor()) + // return mActors.checkAnimationPlaying(ptr, groupName); + //else return false; } void MechanicsManager::updateMagicEffects(const MWWorld::Ptr &ptr) { - mActors.updateMagicEffects(ptr); + //mActors.updateMagicEffects(ptr); } bool MechanicsManager::toggleAI() @@ -1050,7 +1062,7 @@ namespace MWMechanics const MWWorld::ESMStore& esmStore = MWBase::Environment::get().getWorld()->getStore(); float radius = esmStore.get().find("fAlarmRadius")->getFloat(); - mActors.getObjectsInRange(from, radius, neighbors); + //mActors.getObjectsInRange(from, radius, neighbors); // victim should be considered even beyond alarm radius if (!victim.isEmpty() && from.squaredDistance(Ogre::Vector3(victim.getRefData().getPosition().pos)) > radius*radius) @@ -1139,7 +1151,7 @@ namespace MWMechanics Ogre::Vector3 from = Ogre::Vector3(player.getRefData().getPosition().pos); float radius = esmStore.get().find("fAlarmRadius")->getFloat(); - mActors.getObjectsInRange(from, radius, neighbors); + //mActors.getObjectsInRange(from, radius, neighbors); // victim should be considered even beyond alarm radius if (!victim.isEmpty() && from.squaredDistance(Ogre::Vector3(victim.getRefData().getPosition().pos)) > radius*radius) @@ -1394,6 +1406,7 @@ namespace MWMechanics // if guard starts combat with player, guards pursuing player should do the same if (ptr.getClass().isClass(ptr, "Guard")) { + /* for (Actors::PtrActorMap::const_iterator iter = mActors.begin(); iter != mActors.end(); ++iter) { if (iter->first.getClass().isClass(iter->first, "Guard")) @@ -1406,6 +1419,7 @@ namespace MWMechanics } } } + */ } } @@ -1416,27 +1430,27 @@ namespace MWMechanics void MechanicsManager::getObjectsInRange(const Ogre::Vector3 &position, float radius, std::vector &objects) { - mActors.getObjectsInRange(position, radius, objects); - mObjects.getObjectsInRange(position, radius, objects); + //mActors.getObjectsInRange(position, radius, objects); + //mObjects.getObjectsInRange(position, radius, objects); } void MechanicsManager::getActorsInRange(const Ogre::Vector3 &position, float radius, std::vector &objects) { - mActors.getObjectsInRange(position, radius, objects); + //mActors.getObjectsInRange(position, radius, objects); } std::list MechanicsManager::getActorsFollowing(const MWWorld::Ptr& actor) { - return mActors.getActorsFollowing(actor); + return std::list();//mActors.getActorsFollowing(actor); } std::list MechanicsManager::getActorsFollowingIndices(const MWWorld::Ptr& actor) { - return mActors.getActorsFollowingIndices(actor); + return std::list(); //mActors.getActorsFollowingIndices(actor); } std::list MechanicsManager::getActorsFighting(const MWWorld::Ptr& actor) { - return mActors.getActorsFighting(actor); + return std::list();// mActors.getActorsFighting(actor); } int MechanicsManager::countSavedGameRecords() const @@ -1447,7 +1461,7 @@ namespace MWMechanics void MechanicsManager::write(ESM::ESMWriter &writer, Loading::Listener &listener) const { - mActors.write(writer, listener); + //mActors.write(writer, listener); ESM::StolenItems items; items.mStolenItems = mStolenItems; @@ -1464,13 +1478,13 @@ namespace MWMechanics items.load(reader); mStolenItems = items.mStolenItems; } - else - mActors.readRecord(reader, type); + //else + //mActors.readRecord(reader, type); } void MechanicsManager::clear() { - mActors.clear(); + //mActors.clear(); mStolenItems.clear(); } @@ -1516,6 +1530,6 @@ namespace MWMechanics bool MechanicsManager::isReadyToBlock(const MWWorld::Ptr &ptr) const { - return mActors.isReadyToBlock(ptr); + return 0;//mActors.isReadyToBlock(ptr); } } diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index d08334ae8..30cc207f7 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -7,8 +7,8 @@ #include "creaturestats.hpp" #include "npcstats.hpp" -#include "objects.hpp" -#include "actors.hpp" +//#include "objects.hpp" +//#include "actors.hpp" namespace Ogre { @@ -32,8 +32,8 @@ namespace MWMechanics bool mRaceSelected; bool mAI;///< is AI active? - Objects mObjects; - Actors mActors; + //Objects mObjects; + //Actors mActors; typedef std::pair Owner; // < Owner id, bool isFaction > typedef std::map OwnerMap; // < Owner, number of stolen items with this id from this owner > diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 8a43cc932..a7d3545b3 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -19,7 +19,7 @@ #include "../mwworld/cellstore.hpp" #include "../mwworld/esmstore.hpp" -#include "../mwrender/animation.hpp" +//#include "../mwrender/animation.hpp" #include "magiceffects.hpp" #include "npcstats.hpp" @@ -419,8 +419,8 @@ namespace MWMechanics if (absorbed) { const ESM::Static* absorbStatic = MWBase::Environment::get().getWorld()->getStore().get().find ("VFX_Absorb"); - MWBase::Environment::get().getWorld()->getAnimation(target)->addEffect( - "meshes\\" + absorbStatic->mModel, ESM::MagicEffect::SpellAbsorption, false, ""); + //MWBase::Environment::get().getWorld()->getAnimation(target)->addEffect( + // "meshes\\" + absorbStatic->mModel, ESM::MagicEffect::SpellAbsorption, false, ""); // Magicka is increased by cost of spell DynamicStat magicka = target.getClass().getCreatureStats(target).getMagicka(); magicka.setCurrent(magicka.getCurrent() + spell->mData.mCost); @@ -467,8 +467,8 @@ namespace MWMechanics if (isReflected) { const ESM::Static* reflectStatic = MWBase::Environment::get().getWorld()->getStore().get().find ("VFX_Reflect"); - MWBase::Environment::get().getWorld()->getAnimation(target)->addEffect( - "meshes\\" + reflectStatic->mModel, ESM::MagicEffect::Reflect, false, ""); + //MWBase::Environment::get().getWorld()->getAnimation(target)->addEffect( + // "meshes\\" + reflectStatic->mModel, ESM::MagicEffect::Reflect, false, ""); reflectedEffects.mList.push_back(*effectIt); magnitudeMult = 0; } @@ -574,9 +574,9 @@ namespace MWMechanics // TODO: VFX are no longer active after saving/reloading the game bool loop = (magicEffect->mData.mFlags & ESM::MagicEffect::ContinuousVfx) != 0; // Note: in case of non actor, a free effect should be fine as well - MWRender::Animation* anim = MWBase::Environment::get().getWorld()->getAnimation(target); - if (anim) - anim->addEffect("meshes\\" + castStatic->mModel, magicEffect->mIndex, loop, ""); + //MWRender::Animation* anim = MWBase::Environment::get().getWorld()->getAnimation(target); + //if (anim) + // anim->addEffect("meshes\\" + castStatic->mModel, magicEffect->mIndex, loop, ""); } } } diff --git a/apps/openmw/mwmechanics/summoning.cpp b/apps/openmw/mwmechanics/summoning.cpp index 668031141..daf4424c5 100644 --- a/apps/openmw/mwmechanics/summoning.cpp +++ b/apps/openmw/mwmechanics/summoning.cpp @@ -12,7 +12,7 @@ #include "../mwworld/manualref.hpp" #include "../mwworld/inventorystore.hpp" -#include "../mwrender/animation.hpp" +//#include "../mwrender/animation.hpp" #include "creaturestats.hpp" #include "aifollow.hpp" @@ -143,8 +143,9 @@ namespace MWMechanics summonedCreatureStats.getAiSequence().stack(package, ref.getPtr()); int creatureActorId = summonedCreatureStats.getActorId(); - MWWorld::Ptr placed = MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),store,ipos); + /*MWWorld::Ptr placed = */MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),store,ipos); + /* MWRender::Animation* anim = MWBase::Environment::get().getWorld()->getAnimation(placed); if (anim) { @@ -153,6 +154,7 @@ namespace MWMechanics if (fx) anim->addEffect("meshes\\" + fx->mModel, -1, false); } + */ creatureMap.insert(std::make_pair(*it, creatureActorId)); } diff --git a/apps/openmw/mwrender/actors.cpp b/apps/openmw/mwrender/actors.cpp index 3da6c40c8..878712ecc 100644 --- a/apps/openmw/mwrender/actors.cpp +++ b/apps/openmw/mwrender/actors.cpp @@ -6,13 +6,14 @@ #include "../mwworld/ptr.hpp" #include "../mwworld/class.hpp" -#include "../mwrender/renderingmanager.hpp" +//#include "../mwrender/renderingmanager.hpp" +/* #include "animation.hpp" #include "activatoranimation.hpp" #include "creatureanimation.hpp" #include "npcanimation.hpp" - +*/ #include "renderconst.hpp" @@ -22,19 +23,22 @@ using namespace Ogre; Actors::~Actors() { + /* PtrAnimationMap::iterator it = mAllActors.begin(); for(;it != mAllActors.end();++it) { delete it->second; it->second = NULL; } + */ } -void Actors::setRootNode(Ogre::SceneNode* root) -{ mRootNode = root; } +//void Actors::setRootNode(Ogre::SceneNode* root) +//{ mRootNode = root; } void Actors::insertBegin(const MWWorld::Ptr &ptr) { + /* Ogre::SceneNode* cellnode; CellSceneNodeMap::const_iterator celliter = mCellSceneNodes.find(ptr.getCell()); if(celliter != mCellSceneNodes.end()) @@ -61,18 +65,22 @@ void Actors::insertBegin(const MWWorld::Ptr &ptr) insert->setOrientation(zr); ptr.getRefData().setBaseNode(insert); + */ } void Actors::insertNPC(const MWWorld::Ptr& ptr) { + /* insertBegin(ptr); NpcAnimation* anim = new NpcAnimation(ptr, ptr.getRefData().getBaseNode(), RV_Actors); delete mAllActors[ptr]; mAllActors[ptr] = anim; mRendering->addWaterRippleEmitter (ptr); + */ } void Actors::insertCreature (const MWWorld::Ptr& ptr, const std::string &model, bool weaponsShields) { + /* insertBegin(ptr); Animation* anim = NULL; if (weaponsShields) @@ -82,9 +90,11 @@ void Actors::insertCreature (const MWWorld::Ptr& ptr, const std::string &model, delete mAllActors[ptr]; mAllActors[ptr] = anim; mRendering->addWaterRippleEmitter (ptr); + */ } void Actors::insertActivator (const MWWorld::Ptr& ptr, const std::string &model, bool addLight) { + /* insertBegin(ptr); ActivatorAnimation* anim = new ActivatorAnimation(ptr, model); @@ -98,10 +108,12 @@ void Actors::insertActivator (const MWWorld::Ptr& ptr, const std::string &model, delete mAllActors[ptr]; mAllActors[ptr] = anim; + */ } bool Actors::deleteObject (const MWWorld::Ptr& ptr) { + /* if (mAllActors.find(ptr) == mAllActors.end()) return false; @@ -127,12 +139,13 @@ bool Actors::deleteObject (const MWWorld::Ptr& ptr) return false; } - +*/ return true; } void Actors::removeCell(MWWorld::CellStore* store) { + /* for(PtrAnimationMap::iterator iter = mAllActors.begin();iter != mAllActors.end();) { if(iter->first.getCell() == store) @@ -153,26 +166,22 @@ void Actors::removeCell(MWWorld::CellStore* store) mCellSceneNodes.erase(celliter); } -} - -void Actors::update (Ogre::Camera* camera) -{ - for(PtrAnimationMap::iterator iter = mAllActors.begin();iter != mAllActors.end(); ++iter) - { - iter->second->preRender(camera); - } + */ } Animation* Actors::getAnimation(const MWWorld::Ptr &ptr) { + /* PtrAnimationMap::const_iterator iter = mAllActors.find(ptr); if(iter != mAllActors.end()) return iter->second; + */ return NULL; } void Actors::updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur) { + /* Ogre::SceneNode *node; MWWorld::CellStore *newCell = cur.getCell(); @@ -196,20 +205,7 @@ void Actors::updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur) } mRendering->updateWaterRippleEmitterPtr (old, cur); -} - -void Actors::enableLights() -{ - PtrAnimationMap::const_iterator it = mAllActors.begin(); - for(;it != mAllActors.end();++it) - it->second->enableLights(true); -} - -void Actors::disableLights() -{ - PtrAnimationMap::const_iterator it = mAllActors.begin(); - for(;it != mAllActors.end();++it) - it->second->enableLights(false); + */ } } diff --git a/apps/openmw/mwrender/actors.hpp b/apps/openmw/mwrender/actors.hpp index 4f6c1bec2..887ea68d1 100644 --- a/apps/openmw/mwrender/actors.hpp +++ b/apps/openmw/mwrender/actors.hpp @@ -1,7 +1,17 @@ #ifndef GAME_RENDER_ACTORS_H #define GAME_RENDER_ACTORS_H -#include +//#include + +#include + +namespace OEngine +{ + namespace Render + { + class OgreRenderer; + } +} namespace MWWorld { @@ -17,15 +27,15 @@ namespace MWRender class Actors { - typedef std::map CellSceneNodeMap; - typedef std::map PtrAnimationMap; + //typedef std::map CellSceneNodeMap; + //typedef std::map PtrAnimationMap; OEngine::Render::OgreRenderer &mRend; MWRender::RenderingManager* mRendering; - Ogre::SceneNode* mRootNode; + //Ogre::SceneNode* mRootNode; - CellSceneNodeMap mCellSceneNodes; - PtrAnimationMap mAllActors; + //CellSceneNodeMap mCellSceneNodes; + //PtrAnimationMap mAllActors; void insertBegin(const MWWorld::Ptr &ptr); @@ -33,11 +43,11 @@ namespace MWRender Actors(OEngine::Render::OgreRenderer& _rend, MWRender::RenderingManager* rendering) : mRend(_rend) , mRendering(rendering) - , mRootNode(NULL) + //, mRootNode(NULL) {} ~Actors(); - void setRootNode(Ogre::SceneNode* root); + //void setRootNode(Ogre::SceneNode* root); void insertNPC(const MWWorld::Ptr& ptr); void insertCreature (const MWWorld::Ptr& ptr, const std::string& model, bool weaponsShields); @@ -45,13 +55,8 @@ namespace MWRender bool deleteObject (const MWWorld::Ptr& ptr); ///< \return found? - void enableLights(); - void disableLights(); - void removeCell(MWWorld::CellStore* store); - void update (Ogre::Camera* camera); - /// Updates containing cell for object rendering data void updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur); diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index bdaa2d515..3c6a507e7 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -14,7 +14,7 @@ #include #include -#include +//#include #include #include "../mwworld/ptr.hpp" @@ -22,7 +22,7 @@ #include "../mwworld/cellstore.hpp" #include "renderconst.hpp" -#include "animation.hpp" +//#include "animation.hpp" using namespace MWRender; @@ -76,7 +76,7 @@ void Objects::insertBegin(const MWWorld::Ptr& ptr) void Objects::insertModel(const MWWorld::Ptr &ptr, const std::string &mesh, bool batch) { insertBegin(ptr); - +/* std::auto_ptr anim(new ObjectAnimation(ptr, mesh)); if (!mesh.empty()) @@ -96,70 +96,16 @@ void Objects::insertModel(const MWWorld::Ptr &ptr, const std::string &mesh, bool mBounds[ptr.getCell()] = Ogre::AxisAlignedBox::BOX_NULL; mBounds[ptr.getCell()].merge(bounds); - if(batch && - Settings::Manager::getBool("use static geometry", "Objects") && - anim->canBatch()) - { - Ogre::StaticGeometry* sg = 0; - - if (small) - { - if(mStaticGeometrySmall.find(ptr.getCell()) == mStaticGeometrySmall.end()) - { - uniqueID = uniqueID+1; - sg = mRenderer.getScene()->createStaticGeometry("sg" + Ogre::StringConverter::toString(uniqueID)); - sg->setOrigin(ptr.getRefData().getBaseNode()->getPosition()); - mStaticGeometrySmall[ptr.getCell()] = sg; - - sg->setRenderingDistance(static_cast(Settings::Manager::getInt("small object distance", "Viewing distance"))); - } - else - sg = mStaticGeometrySmall[ptr.getCell()]; - } - else - { - if(mStaticGeometry.find(ptr.getCell()) == mStaticGeometry.end()) - { - uniqueID = uniqueID+1; - sg = mRenderer.getScene()->createStaticGeometry("sg" + Ogre::StringConverter::toString(uniqueID)); - sg->setOrigin(ptr.getRefData().getBaseNode()->getPosition()); - mStaticGeometry[ptr.getCell()] = sg; - } - else - sg = mStaticGeometry[ptr.getCell()]; - } - - // This specifies the size of a single batch region. - // If it is set too high: - // - there will be problems choosing the correct lights - // - the culling will be more inefficient - // If it is set too low: - // - there will be too many batches. - if(ptr.getCell()->isExterior()) - sg->setRegionDimensions(Ogre::Vector3(2048,2048,2048)); - else - sg->setRegionDimensions(Ogre::Vector3(1024,1024,1024)); - - sg->setVisibilityFlags(small ? RV_StaticsSmall : RV_Statics); - - sg->setCastShadows(true); - - sg->setRenderQueueGroup(RQG_Main); - - anim->fillBatch(sg); - /* TODO: We could hold on to this and just detach it from the scene graph, so if the Ptr - * ever needs to modify we can reattach it and rebuild the StaticGeometry object without - * it. Would require associating the Ptr with the StaticGeometry. */ - anim.reset(); - } } if(anim.get() != NULL) mObjects.insert(std::make_pair(ptr, anim.release())); + */ } bool Objects::deleteObject (const MWWorld::Ptr& ptr) { + /* if(!ptr.getRefData().getBaseNode()) return true; @@ -173,13 +119,14 @@ bool Objects::deleteObject (const MWWorld::Ptr& ptr) ptr.getRefData().setBaseNode(0); return true; } - +*/ return false; } void Objects::removeCell(MWWorld::CellStore* store) { + /* for(PtrAnimationMap::iterator iter = mObjects.begin();iter != mObjects.end();) { if(iter->first.getCell() == store) @@ -216,20 +163,7 @@ void Objects::removeCell(MWWorld::CellStore* store) mRenderer.getScene()->destroySceneNode(cell->second); mCellSceneNodes.erase(cell); } -} - -void Objects::buildStaticGeometry(MWWorld::CellStore& cell) -{ - if(mStaticGeometry.find(&cell) != mStaticGeometry.end()) - { - Ogre::StaticGeometry* sg = mStaticGeometry[&cell]; - sg->build(); - } - if(mStaticGeometrySmall.find(&cell) != mStaticGeometrySmall.end()) - { - Ogre::StaticGeometry* sg = mStaticGeometrySmall[&cell]; - sg->build(); - } + */ } Ogre::AxisAlignedBox Objects::getDimensions(MWWorld::CellStore* cell) @@ -239,33 +173,16 @@ Ogre::AxisAlignedBox Objects::getDimensions(MWWorld::CellStore* cell) void Objects::update(float dt, Ogre::Camera* camera) { + /* PtrAnimationMap::const_iterator it = mObjects.begin(); for(;it != mObjects.end();++it) it->second->runAnimation(dt); - - it = mObjects.begin(); - for(;it != mObjects.end();++it) - it->second->preRender(camera); - -} - -void Objects::rebuildStaticGeometry() -{ - for (std::map::iterator it = mStaticGeometry.begin(); it != mStaticGeometry.end(); ++it) - { - it->second->destroy(); - it->second->build(); - } - - for (std::map::iterator it = mStaticGeometrySmall.begin(); it != mStaticGeometrySmall.end(); ++it) - { - it->second->destroy(); - it->second->build(); - } + */ } void Objects::updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur) { + /* Ogre::SceneNode *node; MWWorld::CellStore *newCell = cur.getCell(); @@ -286,13 +203,16 @@ void Objects::updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur) anim->updatePtr(cur); mObjects[cur] = anim; } + */ } ObjectAnimation* Objects::getAnimation(const MWWorld::Ptr &ptr) { + /* PtrAnimationMap::const_iterator iter = mObjects.find(ptr); if(iter != mObjects.end()) return iter->second; + */ return NULL; } diff --git a/apps/openmw/mwrender/objects.hpp b/apps/openmw/mwrender/objects.hpp index adfe5ca26..b2f07ab0f 100644 --- a/apps/openmw/mwrender/objects.hpp +++ b/apps/openmw/mwrender/objects.hpp @@ -55,7 +55,6 @@ public: ///< \return found? void removeCell(MWWorld::CellStore* store); - void buildStaticGeometry(MWWorld::CellStore &cell); void setRootNode(Ogre::SceneNode* root); void rebuildStaticGeometry(); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 8fb1ee53c..c64a265ac 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -31,7 +31,6 @@ #include "../mwbase/world.hpp" // these includes can be removed once the static-hack is gone #include "../mwbase/environment.hpp" -#include "../mwbase/inputmanager.hpp" // FIXME #include "../mwbase/windowmanager.hpp" // FIXME #include "../mwbase/statemanager.hpp" @@ -40,7 +39,6 @@ #include "../mwworld/ptr.hpp" -#include "shadows.hpp" #include "localmap.hpp" #include "water.hpp" #include "npcanimation.hpp" @@ -59,7 +57,6 @@ RenderingManager::RenderingManager(OEngine::Render::OgreRenderer& _rend, const b : mRendering(_rend) , mFallback(fallback) , mPlayerAnimation(NULL) - , mAmbientMode(0) , mSunEnabled(0) , mPhysicsEngine(engine) , mTerrain(NULL) @@ -162,15 +159,12 @@ RenderingManager::RenderingManager(OEngine::Render::OgreRenderer& _rend, const b mCamera = new MWRender::Camera(mRendering.getCamera()); - mShadows = new Shadows(&mRendering); - mSkyManager = new SkyManager(mRootNode, mRendering.getCamera()); mOcclusionQuery = new OcclusionQuery(&mRendering, mSkyManager->getSunNode()); mSun = 0; - mDebugging = new Debugging(mRootNode, engine); mLocalMap = new MWRender::LocalMap(&mRendering, this); mWater = new MWRender::Water(mRendering.getCamera(), this, mFallback); @@ -185,8 +179,6 @@ RenderingManager::~RenderingManager () delete mPlayerAnimation; delete mCamera; delete mSkyManager; - delete mDebugging; - delete mShadows; delete mTerrain; delete mLocalMap; delete mOcclusionQuery; @@ -222,7 +214,6 @@ void RenderingManager::removeCell (MWWorld::CellStore *store) mLocalMap->saveFogOfWar(store); mObjects->removeCell(store); mActors->removeCell(store); - mDebugging->cellRemoved(store); } void RenderingManager::removeWater () @@ -251,7 +242,6 @@ void RenderingManager::cellAdded (MWWorld::CellStore *store) mObjects->buildStaticGeometry (*store); sh::Factory::getInstance().unloadUnreferencedMaterials(); - mDebugging->cellAdded(store); } void RenderingManager::addObject (const MWWorld::Ptr& ptr, const std::string& model){ @@ -477,9 +467,10 @@ void RenderingManager::skySetMoonColour (bool red){ bool RenderingManager::toggleRenderMode(int mode) { +#if 0 if (mode == MWBase::World::Render_CollisionDebug || mode == MWBase::World::Render_Pathgrid) return mDebugging->toggleRenderMode(mode); - else if (mode == MWBase::World::Render_Wireframe) + if (mode == MWBase::World::Render_Wireframe) { if (mRendering.getCamera()->getPolygonMode() == PM_SOLID) { @@ -498,6 +489,8 @@ bool RenderingManager::toggleRenderMode(int mode) mRendering.getScene()->showBoundingBoxes(show); return show; } +#endif + return 0; } void RenderingManager::configureFog(const MWWorld::CellStore &mCell) @@ -547,20 +540,7 @@ void RenderingManager::applyFog (bool underwater) void RenderingManager::setAmbientMode() { - switch (mAmbientMode) - { - case 0: - setAmbientColour(mAmbientColor); - break; - - case 1: - setAmbientColour(0.7f*mAmbientColor + 0.3f*ColourValue(1,1,1)); - break; - - case 2: - setAmbientColour(ColourValue(1,1,1)); - break; - } + setAmbientColour(mAmbientColor); } void RenderingManager::configureAmbient(MWWorld::CellStore &mCell) @@ -805,12 +785,6 @@ void RenderingManager::processChangedSettings(const Settings::CategorySettingVec sh::Factory::getInstance ().setCurrentLanguage (lang); rebuild = true; } - else if (it->first == "Shadows") - { - mShadows->recreate (); - - rebuild = true; - } } if (changeRes) diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 9f029c1b9..5bfd8ae77 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -248,9 +248,6 @@ private: MWRender::NpcAnimation *mPlayerAnimation; - // 0 normal, 1 more bright, 2 max - int mAmbientMode; - Ogre::ColourValue mAmbientColor; Ogre::Light* mSun; @@ -264,12 +261,8 @@ private: MWRender::Camera *mCamera; - MWRender::Debugging *mDebugging; - MWRender::LocalMap* mLocalMap; - MWRender::Shadows* mShadows; - bool mRenderWorld; }; diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index a8c04aa4b..fab65b152 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -270,6 +270,7 @@ namespace MWScript std::string InterpreterContext::getActionBinding(const std::string& action) const { + /* MWBase::InputManager* input = MWBase::Environment::get().getInputManager(); std::vector actions = input->getActionKeySorting (); for (std::vector::const_iterator it = actions.begin(); it != actions.end(); ++it) @@ -286,6 +287,7 @@ namespace MWScript return input->getActionKeyBindingName (*it); } } + */ return "None"; } diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 06c40dd8e..5fc39f03e 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -211,6 +211,7 @@ namespace MWSound Ogre::StringVector filelist; if (mMusicFiles.find(mCurrentPlaylist) == mMusicFiles.end()) { +#if 0 Ogre::StringVector groups = Ogre::ResourceGroupManager::getSingleton().getResourceGroups (); for (Ogre::StringVector::iterator it = groups.begin(); it != groups.end(); ++it) { @@ -219,6 +220,8 @@ namespace MWSound filelist.insert(filelist.end(), resourcesInThisGroup->begin(), resourcesInThisGroup->end()); } mMusicFiles[mCurrentPlaylist] = filelist; + +#endif } else filelist = mMusicFiles[mCurrentPlaylist]; diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index d31ae520b..a59efecfe 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -14,10 +14,9 @@ #include #include #include -#include +//#include #include -#include #include #include @@ -31,7 +30,7 @@ #include "../mwworld/esmstore.hpp" #include "../mwworld/cellstore.hpp" -#include "../apps/openmw/mwrender/animation.hpp" +//#include "../apps/openmw/mwrender/animation.hpp" #include "../apps/openmw/mwbase/world.hpp" #include "../apps/openmw/mwbase/environment.hpp" @@ -45,6 +44,7 @@ namespace void animateCollisionShapes (std::map& map, btDynamicsWorld* dynamicsWorld) { + /* for (std::map::iterator it = map.begin(); it != map.end(); ++it) { @@ -85,6 +85,7 @@ void animateCollisionShapes (std::mapupdateSingleAabb(it->first); } + */ } } @@ -502,8 +503,8 @@ namespace MWWorld mRender(_rend), mEngine(0), mTimeAccum(0.0f), mWaterEnabled(false), mWaterHeight(0) { // Create physics. shapeLoader is deleted by the physic engine - NifBullet::ManualBulletShapeLoader* shapeLoader = new NifBullet::ManualBulletShapeLoader(); - mEngine = new OEngine::Physic::PhysicEngine(shapeLoader); + //NifBullet::ManualBulletShapeLoader* shapeLoader = new NifBullet::ManualBulletShapeLoader(); + mEngine = new OEngine::Physic::PhysicEngine(0);//shapeLoader); } PhysicsSystem::~PhysicsSystem() @@ -521,7 +522,7 @@ namespace MWWorld std::pair PhysicsSystem::getFacedHandle(float queryDistance) { - Ray ray = mRender.getCamera()->getCameraToViewportRay(0.5, 0.5); + Ray ray;// = mRender.getCamera()->getCameraToViewportRay(0.5, 0.5); Ogre::Vector3 origin_ = ray.getOrigin(); btVector3 origin(origin_.x, origin_.y, origin_.z); @@ -537,7 +538,7 @@ namespace MWWorld std::vector < std::pair > PhysicsSystem::getFacedHandles (float queryDistance) { - Ray ray = mRender.getCamera()->getCameraToViewportRay(0.5, 0.5); + Ray ray;// = mRender.getCamera()->getCameraToViewportRay(0.5, 0.5); Ogre::Vector3 origin_ = ray.getOrigin(); btVector3 origin(origin_.x, origin_.y, origin_.z); @@ -555,7 +556,7 @@ namespace MWWorld std::vector < std::pair > PhysicsSystem::getFacedHandles (float mouseX, float mouseY, float queryDistance) { - Ray ray = mRender.getCamera()->getCameraToViewportRay(mouseX, mouseY); + Ray ray;// = mRender.getCamera()->getCameraToViewportRay(mouseX, mouseY); Ogre::Vector3 from = ray.getOrigin(); Ogre::Vector3 to = ray.getPoint(queryDistance); @@ -628,9 +629,9 @@ namespace MWWorld std::pair PhysicsSystem::castRay(float mouseX, float mouseY, Ogre::Vector3* normal, std::string* hit) { - Ogre::Ray ray = mRender.getCamera()->getCameraToViewportRay( - mouseX, - mouseY); + Ogre::Ray ray;// = mRender.getCamera()->getCameraToViewportRay( + //mouseX, + //mouseY); Ogre::Vector3 from = ray.getOrigin(); Ogre::Vector3 to = ray.getPoint(200); /// \todo make this distance (ray length) configurable @@ -755,7 +756,7 @@ namespace MWWorld if(handleToMesh.find(handle) != handleToMesh.end()) { std::string model = ptr.getClass().getModel(ptr); - model = Misc::ResourceHelpers::correctActorModelPath(model); // FIXME: scaling shouldn't require model + //model = Misc::ResourceHelpers::correctActorModelPath(model); // FIXME: scaling shouldn't require model bool placeable = false; if (OEngine::Physic::RigidBody* body = mEngine->getRigidBody(handle,true)) @@ -803,8 +804,9 @@ namespace MWWorld bool PhysicsSystem::getObjectAABB(const MWWorld::Ptr &ptr, Ogre::Vector3 &min, Ogre::Vector3 &max) { + // FIXME: since raycasting shapes are going away, this should use the osg ComputeBoundingBoxVisitor std::string model = ptr.getClass().getModel(ptr); - model = Misc::ResourceHelpers::correctActorModelPath(model); + //model = Misc::ResourceHelpers::correctActorModelPath(model); if (model.empty()) { return false; } diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 8d689240b..6d7408607 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -4,6 +4,7 @@ #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -11,7 +12,7 @@ #include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/windowmanager.hpp" -#include "physicssystem.hpp" +//#include "physicssystem.hpp" #include "player.hpp" #include "localscripts.hpp" #include "esmstore.hpp" @@ -22,6 +23,7 @@ namespace { +#if 0 void addObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics, MWRender::RenderingManager& rendering) { @@ -113,6 +115,7 @@ namespace return true; } +#endif } @@ -121,15 +124,15 @@ namespace MWWorld void Scene::updateObjectLocalRotation (const Ptr& ptr) { - ::updateObjectLocalRotation(ptr, *mPhysics, mRendering); + //::updateObjectLocalRotation(ptr, *mPhysics, mRendering); } void Scene::updateObjectRotation (const Ptr& ptr) { if(ptr.getRefData().getBaseNode() != 0) { - mRendering.rotateObject(ptr); - mPhysics->rotateObject(ptr); + //mRendering.rotateObject(ptr); + //mPhysics->rotateObject(ptr); } } @@ -161,8 +164,8 @@ namespace MWWorld { // Note: exterior cell maps must be updated, even if they were visited before, because the set of surrounding cells might be different // (and objects in a different cell can "bleed" into another cells map if they cross the border) - for (CellStoreCollection::iterator active = mActiveCells.begin(); active!=mActiveCells.end(); ++active) - mRendering.requestMap(*active); + //for (CellStoreCollection::iterator active = mActiveCells.begin(); active!=mActiveCells.end(); ++active) + //mRendering.requestMap(*active); mNeedMapUpdate = false; if (mCurrentCell->isExterior()) @@ -173,7 +176,7 @@ namespace MWWorld } } - mRendering.update (duration, paused); + //mRendering.update (duration, paused); } void Scene::unloadCell (CellStoreCollection::iterator iter) @@ -188,7 +191,7 @@ namespace MWWorld iter2!=functor.mHandles.end(); ++iter2) { Ogre::SceneNode* node = *iter2; - mPhysics->removeObject (node->getName()); + //mPhysics->removeObject (node->getName()); } } @@ -199,11 +202,11 @@ namespace MWWorld (*iter)->getCell()->getGridX(), (*iter)->getCell()->getGridY() ); - if (land && land->mDataTypes&ESM::Land::DATA_VHGT) - mPhysics->removeHeightField ((*iter)->getCell()->getGridX(), (*iter)->getCell()->getGridY()); + //if (land && land->mDataTypes&ESM::Land::DATA_VHGT) + //mPhysics->removeHeightField ((*iter)->getCell()->getGridX(), (*iter)->getCell()->getGridY()); } - mRendering.removeCell(*iter); + //mRendering.removeCell(*iter); MWBase::Environment::get().getWorld()->getLocalScripts().clearCell (*iter); @@ -224,6 +227,7 @@ namespace MWWorld float verts = ESM::Land::LAND_SIZE; float worldsize = ESM::Land::REAL_SIZE; +#if 0 // Load terrain physics first... if (cell->getCell()->isExterior()) { @@ -248,6 +252,7 @@ namespace MWWorld ; } } +#endif cell->respawn(); @@ -255,6 +260,7 @@ namespace MWWorld /// \todo rescale depending on the state of a new GMST insertCell (*cell, true, loadingListener); +#if 0 mRendering.cellAdded (cell); bool waterEnabled = cell->getCell()->hasWater(); mRendering.setWaterEnabled(waterEnabled); @@ -267,6 +273,7 @@ namespace MWWorld mPhysics->disableWater(); mRendering.configureAmbient(*cell); +#endif } // register local scripts @@ -300,7 +307,7 @@ namespace MWWorld int newX, newY; MWBase::Environment::get().getWorld()->positionToIndex(pos.x, pos.y, newX, newY); changeCellGrid(newX, newY); - mRendering.updateTerrain(); + //mRendering.updateTerrain(); } } @@ -309,7 +316,7 @@ namespace MWWorld Loading::Listener* loadingListener = MWBase::Environment::get().getWindowManager()->getLoadingScreen(); Loading::ScopedLoad load(loadingListener); - mRendering.enableTerrain(true); + //mRendering.enableTerrain(true); std::string loadingExteriorText = "#{sLoadingMessage3}"; loadingListener->setLabel(loadingExteriorText); @@ -404,7 +411,7 @@ namespace MWWorld world->getPlayer().setCell(cell); MWWorld::Ptr player = world->getPlayerPtr(); - mRendering.updatePlayerPtr(player); + //mRendering.updatePlayerPtr(player); if (adjustPlayerPos) { world->moveObject(player, pos.pos[0], pos.pos[1], pos.pos[2]); @@ -428,7 +435,7 @@ namespace MWWorld //We need the ogre renderer and a scene node. Scene::Scene (MWRender::RenderingManager& rendering, PhysicsSystem *physics) - : mCurrentCell (0), mCellChanged (false), mPhysics(physics), mRendering(rendering), mNeedMapUpdate(false) + : mCurrentCell (0), mCellChanged (false), /*mPhysics(physics), mRendering(rendering),*/ mNeedMapUpdate(false) { } @@ -460,7 +467,7 @@ namespace MWWorld loadingListener->setLabel(loadingInteriorText); Loading::ScopedLoad load(loadingListener); - mRendering.enableTerrain(false); + //mRendering.enableTerrain(false); if(!loadcell) { @@ -497,7 +504,7 @@ namespace MWWorld changePlayerCell(cell, position, true); // adjust fog - mRendering.configureFog(*mCurrentCell); + //mRendering.configureFog(*mCurrentCell); // Sky system MWBase::Environment::get().getWorld()->adjustSky(); @@ -523,7 +530,7 @@ namespace MWWorld CellStore* current = MWBase::Environment::get().getWorld()->getExterior(x, y); changePlayerCell(current, position, adjustPlayerPos); - mRendering.updateTerrain(); + //mRendering.updateTerrain(); } CellStore* Scene::getCurrentCell () @@ -538,17 +545,17 @@ namespace MWWorld void Scene::insertCell (CellStore &cell, bool rescale, Loading::Listener* loadingListener) { - InsertFunctor functor (cell, rescale, *loadingListener, *mPhysics, mRendering); - cell.forEach (functor); + //InsertFunctor functor (cell, rescale, *loadingListener, *mPhysics, mRendering); + //cell.forEach (functor); } void Scene::addObjectToScene (const Ptr& ptr) { try { - addObject(ptr, *mPhysics, mRendering); - MWBase::Environment::get().getWorld()->rotateObject(ptr, 0, 0, 0, true); - MWBase::Environment::get().getWorld()->scaleObject(ptr, ptr.getCellRef().getScale()); + //addObject(ptr, *mPhysics, mRendering); + //MWBase::Environment::get().getWorld()->rotateObject(ptr, 0, 0, 0, true); + //MWBase::Environment::get().getWorld()->scaleObject(ptr, ptr.getCellRef().getScale()); } catch (std::exception& e) { @@ -560,8 +567,8 @@ namespace MWWorld { MWBase::Environment::get().getMechanicsManager()->remove (ptr); MWBase::Environment::get().getSoundManager()->stopSound3D (ptr); - mPhysics->removeObject (ptr.getRefData().getHandle()); - mRendering.removeObject (ptr); + //mPhysics->removeObject (ptr.getRefData().getHandle()); + //mRendering.removeObject (ptr); } bool Scene::isCellActive(const CellStore &cell) diff --git a/apps/openmw/mwworld/scene.hpp b/apps/openmw/mwworld/scene.hpp index a9d80bf17..341a89a78 100644 --- a/apps/openmw/mwworld/scene.hpp +++ b/apps/openmw/mwworld/scene.hpp @@ -1,11 +1,13 @@ #ifndef GAME_MWWORLD_SCENE_H #define GAME_MWWORLD_SCENE_H -#include "../mwrender/renderingmanager.hpp" +//#include "../mwrender/renderingmanager.hpp" #include "ptr.hpp" #include "globals.hpp" +#include + namespace Ogre { class Vector3; @@ -35,6 +37,7 @@ namespace MWRender { class SkyManager; class CellRender; + class RenderingManager; } namespace MWWorld @@ -55,8 +58,8 @@ namespace MWWorld CellStore* mCurrentCell; // the cell the player is in CellStoreCollection mActiveCells; bool mCellChanged; - PhysicsSystem *mPhysics; - MWRender::RenderingManager& mRendering; + //PhysicsSystem *mPhysics; + //MWRender::RenderingManager& mRendering; bool mNeedMapUpdate; diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index a9ca8e72b..82814b623 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -13,7 +13,7 @@ #include "../mwsound/sound.hpp" -#include "../mwrender/renderingmanager.hpp" +//#include "../mwrender/renderingmanager.hpp" #include "player.hpp" #include "esmstore.hpp" diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 013386f8f..8b2035fe9 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -16,7 +16,6 @@ #include -#include #include #include #include @@ -37,8 +36,7 @@ #include "../mwmechanics/combat.hpp" #include "../mwmechanics/aiavoiddoor.hpp" //Used to tell actors to avoid doors -#include "../mwrender/sky.hpp" -#include "../mwrender/animation.hpp" +//#include "../mwrender/animation.hpp" #include "../mwscript/interpretercontext.hpp" @@ -51,7 +49,8 @@ #include "containerstore.hpp" #include "inventorystore.hpp" #include "actionteleport.hpp" -#include "projectilemanager.hpp" +//#include "projectilemanager.hpp" +#include "weather.hpp" #include "contentloader.hpp" #include "esmloader.hpp" @@ -129,6 +128,7 @@ namespace MWWorld void World::adjustSky() { +#if 0 if (mSky && (isCellExterior() || isCellQuasiExterior())) { mRendering->skySetHour (mGlobalVariables["gamehour"].getFloat()); @@ -139,9 +139,10 @@ namespace MWWorld } else mRendering->skyDisable(); +#endif } - World::World (OEngine::Render::OgreRenderer& renderer, + World::World ( const Files::Collections& fileCollections, const std::vector& contentFiles, const boost::filesystem::path& resDir, const boost::filesystem::path& cacheDir, @@ -156,16 +157,16 @@ namespace MWWorld mStartCell (startCell), mStartupScript(startupScript), mScriptsEnabled(true) { - mPhysics = new PhysicsSystem(renderer); - mPhysEngine = mPhysics->getEngine(); - + //mPhysics = new PhysicsSystem(renderer); + //mPhysEngine = mPhysics->getEngine(); +#if 0 mProjectileManager.reset(new ProjectileManager(renderer.getScene(), *mPhysEngine)); +#endif + //mRendering = new MWRender::RenderingManager(renderer, resDir, cacheDir, mPhysEngine,&mFallback); - mRendering = new MWRender::RenderingManager(renderer, resDir, cacheDir, mPhysEngine,&mFallback); - - mPhysEngine->setSceneManager(renderer.getScene()); + //mPhysEngine->setSceneManager(renderer.getScene()); - mWeatherManager = new MWWorld::WeatherManager(mRendering,&mFallback); + //mWeatherManager = new MWWorld::WeatherManager(mRendering,&mFallback); mEsm.resize(contentFiles.size()); Loading::Listener* listener = MWBase::Environment::get().getWindowManager()->getLoadingScreen(); @@ -195,7 +196,7 @@ namespace MWWorld mGlobalVariables.fill (mStore); - mWorldScene = new Scene(*mRendering, mPhysics); + mWorldScene = new Scene(*mRendering, NULL/*mPhysics*/); } void World::startNewGame (bool bypass) @@ -208,7 +209,7 @@ namespace MWWorld setupPlayer(); renderPlayer(); - mRendering->resetCamera(); + //mRendering->resetCamera(); MWBase::Environment::get().getWindowManager()->updatePlayer(); @@ -257,13 +258,13 @@ namespace MWWorld MWBase::Environment::get().getWindowManager()->playVideo(mFallback.getFallbackString("Movies_New_Game"), true); // enable collision - if (!mPhysics->toggleCollisionMode()) - mPhysics->toggleCollisionMode(); + //if (!mPhysics->toggleCollisionMode()) + // mPhysics->toggleCollisionMode(); // we don't want old weather to persist on a new game - delete mWeatherManager; - mWeatherManager = 0; - mWeatherManager = new MWWorld::WeatherManager(mRendering,&mFallback); + //delete mWeatherManager; + //mWeatherManager = 0; + //mWeatherManager = new MWWorld::WeatherManager(mRendering,&mFallback); if (!mStartupScript.empty()) MWBase::Environment::get().getWindowManager()->executeInConsole(mStartupScript); @@ -271,11 +272,11 @@ namespace MWWorld void World::clear() { - mWeatherManager->clear(); - mRendering->clear(); - + //mWeatherManager->clear(); + //mRendering->clear(); +#if 0 mProjectileManager->clear(); - +#endif mLocalScripts.clear(); mWorldScene->changeToVoid(); @@ -310,7 +311,9 @@ namespace MWWorld mCells.countSavedGameRecords() +mStore.countSavedGameRecords() +mGlobalVariables.countSavedGameRecords() + #if 0 +mProjectileManager->countSavedGameRecords() + #endif +1 // player record +1 // weather record +1 // actorId counter @@ -329,8 +332,8 @@ namespace MWWorld for (Scene::CellStoreCollection::const_iterator iter (mWorldScene->getActiveCells().begin()); iter!=mWorldScene->getActiveCells().end(); ++iter) { - CellStore* cellstore = *iter; - mRendering->writeFog(cellstore); + //CellStore* cellstore = *iter; + //mRendering->writeFog(cellstore); } MWMechanics::CreatureStats::writeActorIdCounter(writer); @@ -340,9 +343,10 @@ namespace MWWorld mCells.write (writer, progress); mGlobalVariables.write (writer, progress); mPlayer->write (writer, progress); - mWeatherManager->write (writer, progress); + //mWeatherManager->write (writer, progress); +#if 0 mProjectileManager->write (writer, progress); - +#endif writer.startRecord(ESM::REC_ENAB); writer.writeHNT("TELE", mTeleportEnabled); writer.writeHNT("LEVT", mLevitationEnabled); @@ -369,9 +373,12 @@ namespace MWWorld if (!mStore.readRecord (reader, type) && !mGlobalVariables.readRecord (reader, type) && !mPlayer->readRecord (reader, type) && - !mWeatherManager->readRecord (reader, type) && - !mCells.readRecord (reader, type, contentFileMap) && - !mProjectileManager->readRecord (reader, type)) + //!mWeatherManager->readRecord (reader, type) && + !mCells.readRecord (reader, type, contentFileMap) + #if 0 + && !mProjectileManager->readRecord (reader, type) + #endif + ) { throw std::runtime_error ("unknown record in saved game"); } @@ -463,13 +470,14 @@ namespace MWWorld World::~World() { +#if 0 // Must be cleared before mRendering is destroyed mProjectileManager->clear(); - - delete mWeatherManager; +#endif + //delete mWeatherManager; delete mWorldScene; - delete mRendering; - delete mPhysics; + //delete mRendering; + //delete mPhysics; delete mPlayer; } @@ -521,6 +529,7 @@ namespace MWWorld void World::useDeathCamera() { +#if 0 if(mRendering->getCamera()->isVanityOrPreviewModeEnabled() ) { mRendering->getCamera()->togglePreviewMode(false); @@ -528,6 +537,7 @@ namespace MWWorld } if(mRendering->getCamera()->isFirstPerson()) mRendering->getCamera()->toggleViewMode(true); +#endif } MWWorld::Player& World::getPlayer() @@ -804,7 +814,7 @@ namespace MWWorld { MWBase::Environment::get().getMechanicsManager()->advanceTime(static_cast(hours * 3600)); - mWeatherManager->advanceTime (hours); + //mWeatherManager->advanceTime (hours); hours += mGlobalVariables["gamehour"].getFloat(); @@ -828,9 +838,9 @@ namespace MWWorld mGlobalVariables["gamehour"].setFloat(static_cast(hour)); - mRendering->skySetHour (hour); + //mRendering->skySetHour (hour); - mWeatherManager->setHour(static_cast(hour)); + //mWeatherManager->setHour(static_cast(hour)); if (days>0) setDay (days + mGlobalVariables["day"].getInteger()); @@ -865,7 +875,7 @@ namespace MWWorld mGlobalVariables["day"].setInteger (day); mGlobalVariables["month"].setInteger (month); - mRendering->skySetDate (day, month); + //mRendering->skySetDate (day, month); } void World::setMonth (int month) @@ -886,7 +896,7 @@ namespace MWWorld if (years>0) mGlobalVariables["year"].setInteger (years+mGlobalVariables["year"].getInteger()); - mRendering->skySetDate (mGlobalVariables["day"].getInteger(), month); + //mRendering->skySetDate (mGlobalVariables["day"].getInteger(), month); } int World::getDay() const @@ -932,6 +942,7 @@ namespace MWWorld bool World::toggleSky() { +#if 0 if (mSky) { mSky = false; @@ -944,21 +955,23 @@ namespace MWWorld mRendering->skyEnable(); return true; } +#endif + return 0; } int World::getMasserPhase() const { - return mRendering->skyGetMasserPhase(); + return 0;//mRendering->skyGetMasserPhase(); } int World::getSecundaPhase() const { - return mRendering->skyGetSecundaPhase(); + return 0;//mRendering->skyGetSecundaPhase(); } void World::setMoonColour (bool red) { - mRendering->skySetMoonColour (red); + //mRendering->skySetMoonColour (red); } float World::getTimeScaleFactor() const @@ -968,13 +981,15 @@ namespace MWWorld void World::changeToInteriorCell (const std::string& cellName, const ESM::Position& position) { - mPhysics->clearQueuedMovement(); + //mPhysics->clearQueuedMovement(); if (mCurrentWorldSpace != cellName) { // changed worldspace +#if 0 mProjectileManager->clear(); mRendering->notifyWorldSpaceChanged(); +#endif mCurrentWorldSpace = cellName; } @@ -985,13 +1000,15 @@ namespace MWWorld void World::changeToExteriorCell (const ESM::Position& position) { - mPhysics->clearQueuedMovement(); + //mPhysics->clearQueuedMovement(); if (mCurrentWorldSpace != "sys::default") // FIXME { // changed worldspace +#if 0 mProjectileManager->clear(); mRendering->notifyWorldSpaceChanged(); +#endif } removeContainerScripts(getPlayerPtr()); mWorldScene->changeToExteriorCell(position, true); @@ -1049,6 +1066,7 @@ namespace MWWorld std::pair World::getHitContact(const MWWorld::Ptr &ptr, float distance) { + /* const ESM::Position &posdata = ptr.getRefData().getPosition(); Ogre::Vector3 pos(posdata.pos); Ogre::Quaternion rot = Ogre::Quaternion(Ogre::Radian(posdata.rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z) * @@ -1063,9 +1081,10 @@ namespace MWWorld if(node != NULL) pos += node->_getDerivedPosition(); } + */ - std::pair result = mPhysics->getHitContact(ptr.getRefData().getHandle(), - pos, rot, distance); + std::pair result;// = mPhysics->getHitContact(ptr.getRefData().getHandle(), + // pos, rot, distance); if(result.first.empty()) return std::make_pair(MWWorld::Ptr(), Ogre::Vector3(0.0f)); @@ -1174,7 +1193,7 @@ namespace MWWorld MWWorld::Ptr copy = ptr.getClass().copyToCell(ptr, *newCell, pos); - mRendering->updateObjectCell(ptr, copy); + //mRendering->updateObjectCell(ptr, copy); ptr.getRefData().setBaseNode(NULL); MWBase::Environment::get().getSoundManager()->updatePtr (ptr, copy); @@ -1196,8 +1215,8 @@ namespace MWWorld } if (haveToMove && ptr.getRefData().getBaseNode()) { - mRendering->moveObject(ptr, vec); - mPhysics->moveObject (ptr); + //mRendering->moveObject(ptr, vec); + //mPhysics->moveObject (ptr); } if (isPlayer) { @@ -1235,8 +1254,8 @@ namespace MWWorld if(ptr.getRefData().getBaseNode() == 0) return; - mRendering->scaleObject(ptr, Vector3(scale,scale,scale)); - mPhysics->scaleObject(ptr); + //mRendering->scaleObject(ptr, Vector3(scale,scale,scale)); + //mPhysics->scaleObject(ptr); } void World::rotateObjectImp (const Ptr& ptr, Ogre::Vector3 rot, bool adjust) @@ -1322,7 +1341,7 @@ namespace MWWorld return; } - float terrainHeight = mRendering->getTerrainHeightAt(Ogre::Vector3(pos.pos)); + float terrainHeight = 0;//mRendering->getTerrainHeightAt(Ogre::Vector3(pos.pos)); if (pos.pos[2] < terrainHeight) pos.pos[2] = terrainHeight; @@ -1333,7 +1352,7 @@ namespace MWWorld if (force || !isFlying(ptr)) { - Ogre::Vector3 traced = mPhysics->traceDown(ptr, 500); + Ogre::Vector3 traced;// = mPhysics->traceDown(ptr, 500); if (traced.z < pos.pos[2]) pos.pos[2] = traced.z; } @@ -1348,7 +1367,7 @@ namespace MWWorld pos.pos[2] += dist; actor.getRefData().setPosition(pos); - Ogre::Vector3 traced = mPhysics->traceDown(actor, dist*1.1f); + Ogre::Vector3 traced;// = mPhysics->traceDown(actor, dist*1.1f); moveObject(actor, actor.getCell(), traced.x, traced.y, traced.z); } @@ -1389,12 +1408,13 @@ namespace MWWorld void World::queueMovement(const Ptr &ptr, const Vector3 &velocity) { - mPhysics->queueObjectMovement(ptr, velocity); + //mPhysics->queueObjectMovement(ptr, velocity); } void World::doPhysics(float duration) { - mPhysics->stepSimulation(duration); +#if 0 + //mPhysics->stepSimulation(duration); processDoors(duration); @@ -1414,17 +1434,19 @@ namespace MWWorld } if(player != results.end()) moveObjectImp(player->first, player->second.x, player->second.y, player->second.z); +#endif } bool World::castRay (float x1, float y1, float z1, float x2, float y2, float z2) { Ogre::Vector3 a(x1,y1,z1); Ogre::Vector3 b(x2,y2,z2); - return mPhysics->castRay(a,b,false,true); + return 0;//mPhysics->castRay(a,b,false,true); } void World::processDoors(float duration) { +#if 0 std::map::iterator it = mDoorStates.begin(); while (it != mDoorStates.end()) { @@ -1475,16 +1497,17 @@ namespace MWWorld ++it; } } +#endif } bool World::toggleCollisionMode() { - return mPhysics->toggleCollisionMode(); + return 0;//mPhysics->toggleCollisionMode(); } bool World::toggleRenderMode (RenderMode mode) { - return mRendering->toggleRenderMode (mode); + return 0;//mRendering->toggleRenderMode (mode); } const ESM::Potion *World::createRecord (const ESM::Potion& record) @@ -1544,7 +1567,7 @@ namespace MWWorld } const ESM::NPC *ret = mStore.insert(record); if (update) { - mRendering->renderPlayer(mPlayer->getPlayer()); + //mRendering->renderPlayer(mPlayer->getPlayer()); } return ret; } @@ -1581,8 +1604,8 @@ namespace MWWorld updateWeather(duration, paused); - if (!paused) - doPhysics (duration); + //if (!paused) + // doPhysics (duration); mWorldScene->update (duration, paused); @@ -1625,7 +1648,7 @@ namespace MWWorld Ogre::AxisAlignedBox bounds = node->_getWorldAABB(); if (bounds.isFinite()) { - Vector4 screenCoords = mRendering->boundingBoxToScreen(bounds); + Vector4 screenCoords;// = mRendering->boundingBoxToScreen(bounds); MWBase::Environment::get().getWindowManager()->setFocusObjectScreenCoords( screenCoords[0], screenCoords[1], screenCoords[2], screenCoords[3]); } @@ -1634,6 +1657,7 @@ namespace MWWorld void World::performUpdateSceneQueries () { +#if 0 if (!mRendering->occlusionQuerySupported()) { // cast a ray from player to sun to detect if the sun is visible @@ -1643,22 +1667,23 @@ namespace MWWorld Vector3 sun = mRendering->getSkyManager()->getRealSunPos(); mRendering->getSkyManager()->setGlare(!mPhysics->castRay(Ogre::Vector3(p[0], p[1], p[2]), sun)); } +#endif } void World::getFacedHandle(std::string& facedHandle, float maxDistance, bool ignorePlayer) { - maxDistance += mRendering->getCameraDistance(); + //maxDistance += mRendering->getCameraDistance(); std::vector < std::pair < float, std::string > > results; if (MWBase::Environment::get().getWindowManager()->isGuiMode()) { float x, y; MWBase::Environment::get().getWindowManager()->getMousePosition(x, y); - results = mPhysics->getFacedHandles(x, y, maxDistance); + //results = mPhysics->getFacedHandles(x, y, maxDistance); } else { - results = mPhysics->getFacedHandles(maxDistance); + //results = mPhysics->getFacedHandles(maxDistance); } if (ignorePlayer && @@ -1697,17 +1722,17 @@ namespace MWWorld int World::getCurrentWeather() const { - return mWeatherManager->getWeatherID(); + return 0;//mWeatherManager->getWeatherID(); } void World::changeWeather(const std::string& region, const unsigned int id) { - mWeatherManager->changeWeather(region, id); + //mWeatherManager->changeWeather(region, id); } void World::modRegion(const std::string ®ionid, const std::vector &chances) { - mWeatherManager->modRegion(regionid, chances); + //mWeatherManager->modRegion(regionid, chances); } Ogre::Vector2 World::getNorthVector (CellStore* cell) @@ -1767,33 +1792,33 @@ namespace MWWorld void World::worldToInteriorMapPosition (Ogre::Vector2 position, float& nX, float& nY, int &x, int& y) { - mRendering->worldToInteriorMapPosition(position, nX, nY, x, y); + //mRendering->worldToInteriorMapPosition(position, nX, nY, x, y); } Ogre::Vector2 World::interiorMapToWorldPosition(float nX, float nY, int x, int y) { - return mRendering->interiorMapToWorldPosition(nX, nY, x, y); + return Ogre::Vector2();//mRendering->interiorMapToWorldPosition(nX, nY, x, y); } bool World::isPositionExplored (float nX, float nY, int x, int y, bool interior) { - return mRendering->isPositionExplored(nX, nY, x, y, interior); + return 0;//mRendering->isPositionExplored(nX, nY, x, y, interior); } void World::setWaterHeight(const float height) { - mPhysics->setWaterHeight(height); - mRendering->setWaterHeight(height); + //mPhysics->setWaterHeight(height); + //mRendering->setWaterHeight(height); } bool World::toggleWater() { - return mRendering->toggleWater(); + return 0;//mRendering->toggleWater(); } bool World::toggleWorld() { - return mRendering->toggleWorld(); + return 0;//mRendering->toggleWorld(); } void World::PCDropped (const Ptr& item) @@ -1807,7 +1832,7 @@ namespace MWWorld MWWorld::Ptr World::placeObject (const MWWorld::Ptr& object, float cursorX, float cursorY, int amount) { - std::pair result = mPhysics->castRay(cursorX, cursorY); + std::pair result;// = mPhysics->castRay(cursorX, cursorY); if (!result.first) return MWWorld::Ptr(); @@ -1838,7 +1863,7 @@ namespace MWWorld { Ogre::Vector3 normal(0,0,0); std::string handle; - std::pair result = mPhysics->castRay(cursorX, cursorY, &normal, &handle); + std::pair result;// = mPhysics->castRay(cursorX, cursorY, &normal, &handle); if (result.first) { @@ -1859,6 +1884,7 @@ namespace MWWorld Ptr World::copyObjectToCell(const Ptr &object, CellStore* cell, ESM::Position pos, bool adjustPos) { +#if 0 if (!object.getClass().isActor() && adjustPos) { // Adjust position so the location we wanted ends up in the middle of the object bounding box @@ -1879,6 +1905,7 @@ namespace MWWorld pos.pos[2] -= adjust.z; } } +#endif if (cell->isExterior()) { @@ -1926,12 +1953,12 @@ namespace MWWorld Ogre::Vector3 orig = Ogre::Vector3(pos.pos); orig.z += 20; - Ogre::Vector3 dir = Ogre::Vector3(0, 0, -1); + //Ogre::Vector3 dir = Ogre::Vector3(0, 0, -1); - float len = 100.0; + //float len = 100.0; - std::pair hit = - mPhysics->castRay(orig, dir, len); + std::pair hit;// = + //mPhysics->castRay(orig, dir, len); if (hit.first) pos.pos[2] = hit.second.z; @@ -1948,12 +1975,12 @@ namespace MWWorld void World::processChangedSettings(const Settings::CategorySettingVector& settings) { - mRendering->processChangedSettings(settings); + //mRendering->processChangedSettings(settings); } void World::getTriangleBatchCount(unsigned int &triangles, unsigned int &batches) { - mRendering->getTriangleBatchCount(triangles, batches); + //mRendering->getTriangleBatchCount(triangles, batches); } bool World::isFlying(const MWWorld::Ptr &ptr) const @@ -2072,12 +2099,12 @@ namespace MWWorld bool World::vanityRotateCamera(float * rot) { - return mRendering->vanityRotateCamera(rot); + return 0;//mRendering->vanityRotateCamera(rot); } void World::setCameraDistance(float dist, bool adjust, bool override_) { - return mRendering->setCameraDistance(dist, adjust, override_); + //mRendering->setCameraDistance(dist, adjust, override_); } void World::setupPlayer() @@ -2093,13 +2120,13 @@ namespace MWWorld mPlayer->set(player); } - Ptr ptr = mPlayer->getPlayer(); - mRendering->setupPlayer(ptr); + //Ptr ptr = mPlayer->getPlayer(); + //mRendering->setupPlayer(ptr); } void World::renderPlayer() { - mRendering->renderPlayer(mPlayer->getPlayer()); + //mRendering->renderPlayer(mPlayer->getPlayer()); // At this point the Animation object is live, and the CharacterController associated with it must be created. // It has to be done at this point: resetCamera below does animation->setViewMode -> CharacterController::forceStateUpdate @@ -2107,8 +2134,8 @@ namespace MWWorld MWBase::Environment::get().getMechanicsManager()->add(mPlayer->getPlayer()); std::string model = getPlayerPtr().getClass().getModel(getPlayerPtr()); - model = Misc::ResourceHelpers::correctActorModelPath(model); - mPhysics->addActor(mPlayer->getPlayer(), model); + //model = Misc::ResourceHelpers::correctActorModelPath(model); + //mPhysics->addActor(mPlayer->getPlayer(), model); } int World::canRest () @@ -2134,17 +2161,17 @@ namespace MWWorld MWRender::Animation* World::getAnimation(const MWWorld::Ptr &ptr) { - return mRendering->getAnimation(ptr); + return 0;//return mRendering->getAnimation(ptr); } void World::frameStarted (float dt, bool paused) { - mRendering->frameStarted(dt, paused); + //mRendering->frameStarted(dt, paused); } void World::screenshot(Ogre::Image &image, int w, int h) { - mRendering->screenshot(image, w, h); + //mRendering->screenshot(image, w, h); } void World::activateDoor(const MWWorld::Ptr& door) @@ -2180,27 +2207,27 @@ namespace MWWorld bool World::getPlayerStandingOn (const MWWorld::Ptr& object) { - MWWorld::Ptr player = getPlayerPtr(); - return mPhysics->isActorStandingOn(player, object); + //MWWorld::Ptr player = getPlayerPtr(); + return 0;//mPhysics->isActorStandingOn(player, object); } bool World::getActorStandingOn (const MWWorld::Ptr& object) { std::vector actors; - mPhysics->getActorsStandingOn(object, actors); + //mPhysics->getActorsStandingOn(object, actors); return !actors.empty(); } bool World::getPlayerCollidingWith (const MWWorld::Ptr& object) { - MWWorld::Ptr player = getPlayerPtr(); - return mPhysics->isActorCollidingWith(player, object); + //MWWorld::Ptr player = getPlayerPtr(); + return 0;//mPhysics->isActorCollidingWith(player, object); } bool World::getActorCollidingWith (const MWWorld::Ptr& object) { std::vector actors; - mPhysics->getActorsCollidingWith(object, actors); + //mPhysics->getActorsCollidingWith(object, actors); return !actors.empty(); } @@ -2210,7 +2237,7 @@ namespace MWWorld return; std::vector actors; - mPhysics->getActorsStandingOn(object, actors); + //mPhysics->getActorsStandingOn(object, actors); for (std::vector::iterator it = actors.begin(); it != actors.end(); ++it) { MWWorld::Ptr actor = searchPtrViaHandle(*it); // Collision events are from the last frame, actor might no longer exist @@ -2241,7 +2268,7 @@ namespace MWWorld return; std::vector actors; - mPhysics->getActorsCollidingWith(object, actors); + //mPhysics->getActorsCollidingWith(object, actors); for (std::vector::iterator it = actors.begin(); it != actors.end(); ++it) { MWWorld::Ptr actor = searchPtrViaHandle(*it); // Collision events are from the last frame, actor might no longer exist @@ -2269,7 +2296,7 @@ namespace MWWorld float World::getWindSpeed() { if (isCellExterior() || isCellQuasiExterior()) - return mWeatherManager->getWindSpeed(); + return 0;//mWeatherManager->getWindSpeed(); else return 0.f; } @@ -2277,7 +2304,7 @@ namespace MWWorld bool World::isInStorm() const { if (isCellExterior() || isCellQuasiExterior()) - return mWeatherManager->isInStorm(); + return 0;//mWeatherManager->isInStorm(); else return false; } @@ -2285,7 +2312,7 @@ namespace MWWorld Ogre::Vector3 World::getStormDirection() const { if (isCellExterior() || isCellQuasiExterior()) - return mWeatherManager->getStormDirection(); + return Ogre::Vector3();//mWeatherManager->getStormDirection(); else return Ogre::Vector3(0,1,0); } @@ -2479,7 +2506,7 @@ namespace MWWorld void World::reattachPlayerCamera() { - mRendering->rebuildPtr(getPlayerPtr()); + //mRendering->rebuildPtr(getPlayerPtr()); } void World::setWerewolf(const MWWorld::Ptr& actor, bool werewolf) @@ -2512,7 +2539,7 @@ namespace MWWorld // NpcAnimation::updateParts will already rebuild the animation when it detects change of Npc type. // the following is just for reattaching the camera properly. - mRendering->rebuildPtr(actor); + //mRendering->rebuildPtr(actor); if(actor == getPlayerPtr()) { @@ -2684,6 +2711,7 @@ namespace MWWorld { // For NPCs use facing direction from Head node Ogre::Vector3 origin(actor.getRefData().getPosition().pos); +#if 0 MWRender::Animation *anim = mRendering->getAnimation(actor); if(anim != NULL) { @@ -2693,6 +2721,7 @@ namespace MWWorld if(node != NULL) origin += node->_getDerivedPosition(); } +#endif Ogre::Quaternion orient; orient = Ogre::Quaternion(Ogre::Radian(actor.getRefData().getPosition().rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z) * Ogre::Quaternion(Ogre::Radian(actor.getRefData().getPosition().rot[0]), Ogre::Vector3::NEGATIVE_UNIT_X); @@ -2739,14 +2768,18 @@ namespace MWWorld void World::launchProjectile (MWWorld::Ptr actor, MWWorld::Ptr projectile, const Ogre::Vector3& worldPos, const Ogre::Quaternion& orient, MWWorld::Ptr bow, float speed) { +#if 0 mProjectileManager->launchProjectile(actor, projectile, worldPos, orient, bow, speed); +#endif } void World::launchMagicBolt (const std::string& model, const std::string &sound, const std::string &spellId, float speed, bool stack, const ESM::EffectList& effects, const MWWorld::Ptr& caster, const std::string& sourceName, const Ogre::Vector3& fallbackDirection) { +#if 0 mProjectileManager->launchMagicBolt(model, sound, spellId, speed, stack, effects, caster, sourceName, fallbackDirection); +#endif } const std::vector& World::getContentFiles() const @@ -2768,7 +2801,7 @@ namespace MWWorld { MWWorld::CellStore* cell = mPlayer->getPlayer().getCell(); if (cell->isExterior()) - return mWeatherManager->isDark(); + return 0;//mWeatherManager->isDark(); else { uint32_t ambient = cell->getCell()->mAmbi.mAmbient; @@ -2933,10 +2966,10 @@ namespace MWWorld if (mPlayer->wasTeleported()) { mPlayer->setTeleported(false); - mWeatherManager->switchToNextWeather(true); + //mWeatherManager->switchToNextWeather(true); } - mWeatherManager->update(duration, paused); + //mWeatherManager->update(duration, paused); } struct AddDetectedReference @@ -3190,12 +3223,12 @@ namespace MWWorld modelName << roll; std::string model = "meshes\\" + getFallback()->getFallbackString(modelName.str()); - mRendering->spawnEffect(model, texture, worldPosition); + //mRendering->spawnEffect(model, texture, worldPosition); } void World::spawnEffect(const std::string &model, const std::string &textureOverride, const Vector3 &worldPos) { - mRendering->spawnEffect(model, textureOverride, worldPos); + //mRendering->spawnEffect(model, textureOverride, worldPos); } void World::explodeSpell(const Vector3 &origin, const ESM::EffectList &effects, const Ptr &caster, ESM::RangeType rangeType, @@ -3211,6 +3244,7 @@ namespace MWWorld continue; // Not an area effect // Spawn the explosion orb effect + /* const ESM::Static* areaStatic; if (!effect->mCasting.empty()) areaStatic = getStore().get().find (effect->mArea); @@ -3218,6 +3252,7 @@ namespace MWWorld areaStatic = getStore().get().find ("VFX_DefaultArea"); mRendering->spawnEffect("meshes\\" + areaStatic->mModel, "", origin, static_cast(effectIt->mArea)); + */ // Play explosion sound (make sure to use NoTrack, since we will delete the projectile now) static const std::string schools[] = { diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 63d6506de..07698aae5 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -8,7 +8,7 @@ #include "ptr.hpp" #include "scene.hpp" #include "esmstore.hpp" -#include "physicssystem.hpp" +//#include "physicssystem.hpp" #include "cells.hpp" #include "localscripts.hpp" #include "timestamp.hpp" @@ -19,6 +19,8 @@ #include "contentloader.hpp" +#include + namespace Ogre { class Vector3; @@ -62,7 +64,7 @@ namespace MWWorld MWWorld::Fallback mFallback; MWRender::RenderingManager* mRendering; - MWWorld::WeatherManager* mWeatherManager; + //MWWorld::WeatherManager* mWeatherManager; MWWorld::Scene *mWorldScene; MWWorld::Player *mPlayer; @@ -152,7 +154,7 @@ namespace MWWorld public: - World (OEngine::Render::OgreRenderer& renderer, + World ( const Files::Collections& fileCollections, const std::vector& contentFiles, const boost::filesystem::path& resDir, const boost::filesystem::path& cacheDir, @@ -465,31 +467,31 @@ namespace MWWorld virtual bool isOnGround(const MWWorld::Ptr &ptr) const; virtual void togglePOV() { - mRendering->togglePOV(); + //mRendering->togglePOV(); } virtual bool isFirstPerson() const { - return mRendering->getCamera()->isFirstPerson(); + return 0;//mRendering->getCamera()->isFirstPerson(); } virtual void togglePreviewMode(bool enable) { - mRendering->togglePreviewMode(enable); + //mRendering->togglePreviewMode(enable); } virtual bool toggleVanityMode(bool enable) { - return mRendering->toggleVanityMode(enable); + return 0;//mRendering->toggleVanityMode(enable); } virtual void allowVanityMode(bool allow) { - mRendering->allowVanityMode(allow); + //mRendering->allowVanityMode(allow); } virtual void togglePlayerLooking(bool enable) { - mRendering->togglePlayerLooking(enable); + //mRendering->togglePlayerLooking(enable); } virtual void changeVanityModeScale(float factor) { - mRendering->changeVanityModeScale(factor); + //mRendering->changeVanityModeScale(factor); } virtual bool vanityRotateCamera(float * rot); diff --git a/cmake/FindMyGUI.cmake b/cmake/FindMyGUI.cmake index 40fa2373f..b5c4e8ade 100644 --- a/cmake/FindMyGUI.cmake +++ b/cmake/FindMyGUI.cmake @@ -67,11 +67,11 @@ ELSE (WIN32) #Unix SET(MYGUI_INCLUDE_DIRS ${MYGUI_INCLUDE_DIRS}) SET(MYGUI_LIB_DIR ${MYGUI_LIBDIR}) SET(MYGUI_LIBRARIES ${MYGUI_LIBRARIES} CACHE STRING "") - SET(MYGUI_PLATFORM_LIBRARIES "MyGUI.OgrePlatform") + SET(MYGUI_PLATFORM_LIBRARIES "MyGUI.DummyPlatform") ELSE (MYGUI_INCLUDE_DIRS) FIND_PATH(MYGUI_INCLUDE_DIRS MyGUI.h PATHS /usr/local/include /usr/include PATH_SUFFIXES MyGUI MYGUI) FIND_LIBRARY(MYGUI_LIBRARIES myguistatic PATHS /usr/lib /usr/local/lib) - SET(MYGUI_PLATFORM_LIBRARIES "MyGUI.OgrePlatform") + SET(MYGUI_PLATFORM_LIBRARIES "MyGUI.DummyPlatform") SET(MYGUI_LIB_DIR ${MYGUI_LIBRARIES}) STRING(REGEX REPLACE "(.*)/.*" "\\1" MYGUI_LIB_DIR "${MYGUI_LIB_DIR}") STRING(REGEX REPLACE ".*/" "" MYGUI_LIBRARIES "${MYGUI_LIBRARIES}") @@ -81,7 +81,7 @@ ELSE (WIN32) #Unix FIND_PACKAGE(freetype) FIND_PATH(MYGUI_INCLUDE_DIRS MyGUI.h PATHS /usr/local/include /usr/include PATH_SUFFIXES MyGUI MYGUI) FIND_LIBRARY(MYGUI_LIBRARIES MyGUIEngineStatic PATHS /usr/lib /usr/local/lib) - SET(MYGUI_PLATFORM_LIBRARIES "MyGUI.OgrePlatform") + SET(MYGUI_PLATFORM_LIBRARIES "MyGUI.DummyPlatform") SET(MYGUI_LIB_DIR ${MYGUI_LIBRARIES}) STRING(REGEX REPLACE "(.*)/.*" "\\1" MYGUI_LIB_DIR "${MYGUI_LIB_DIR}") STRING(REGEX REPLACE ".*/" "" MYGUI_LIBRARIES "${MYGUI_LIBRARIES}") @@ -92,11 +92,11 @@ ELSE (WIN32) #Unix SET(MYGUI_INCLUDE_DIRS ${MYGUI_INCLUDE_DIRS}) SET(MYGUI_LIB_DIR ${MYGUI_LIBDIR}) SET(MYGUI_LIBRARIES ${MYGUI_LIBRARIES} CACHE STRING "") - SET(MYGUI_PLATFORM_LIBRARIES "MyGUI.OgrePlatform") + SET(MYGUI_PLATFORM_LIBRARIES "MyGUI.DummyPlatform") ELSE (MYGUI_INCLUDE_DIRS) FIND_PATH(MYGUI_INCLUDE_DIRS MyGUI.h PATHS /usr/local/include /usr/include PATH_SUFFIXES MyGUI MYGUI) FIND_LIBRARY(MYGUI_LIBRARIES mygui PATHS /usr/lib /usr/local/lib) - SET(MYGUI_PLATFORM_LIBRARIES "MyGUI.OgrePlatform") + SET(MYGUI_PLATFORM_LIBRARIES "MyGUI.DummyPlatform") SET(MYGUI_LIB_DIR ${MYGUI_LIBRARIES}) STRING(REGEX REPLACE "(.*)/.*" "\\1" MYGUI_LIB_DIR "${MYGUI_LIB_DIR}") STRING(REGEX REPLACE ".*/" "" MYGUI_LIBRARIES "${MYGUI_LIBRARIES}") diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 9d9ae4f31..1debf3495 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -26,10 +26,6 @@ add_component_dir (settings settings ) -add_component_dir (nifoverrides - nifoverrides - ) - add_component_dir (bsa bsa_file ) diff --git a/components/esm/esmreader.cpp b/components/esm/esmreader.cpp index 933d89099..87c000d9a 100644 --- a/components/esm/esmreader.cpp +++ b/components/esm/esmreader.cpp @@ -25,6 +25,7 @@ ESMReader::ESMReader() , mIdx(0) , mGlobalReaderList(NULL) , mEncoder(NULL) + , mFileSize(0) { } @@ -64,7 +65,7 @@ void ESMReader::openRaw(Files::IStreamPtr _esm, const std::string& name) mEsm = _esm; mCtx.filename = name; mEsm->seekg(0, mEsm->end); - mCtx.leftFile = mEsm->tellg(); + mCtx.leftFile = mFileSize = mEsm->tellg(); mEsm->seekg(0, mEsm->beg); } diff --git a/components/esm/esmreader.hpp b/components/esm/esmreader.hpp index 89062bd27..709008a90 100644 --- a/components/esm/esmreader.hpp +++ b/components/esm/esmreader.hpp @@ -261,6 +261,8 @@ public: /// Get record flags of last record unsigned int getRecordFlags() { return mRecordFlags; } + size_t getFileSize() const { return mFileSize; } + private: Files::IStreamPtr mEsm; @@ -277,6 +279,9 @@ private: std::vector *mGlobalReaderList; ToUTF8::Utf8Encoder* mEncoder; + + size_t mFileSize; + }; } #endif diff --git a/components/fontloader/fontloader.cpp b/components/fontloader/fontloader.cpp index eb7dd901d..1b61aea90 100644 --- a/components/fontloader/fontloader.cpp +++ b/components/fontloader/fontloader.cpp @@ -147,6 +147,7 @@ namespace Gui void FontLoader::loadAllFonts(bool exportToFile) { + /* Ogre::StringVector groups = Ogre::ResourceGroupManager::getSingleton().getResourceGroups (); for (Ogre::StringVector::iterator it = groups.begin(); it != groups.end(); ++it) { @@ -156,6 +157,7 @@ namespace Gui loadFont(*resource, exportToFile); } } + */ } diff --git a/components/nifoverrides/nifoverrides.cpp b/components/nifoverrides/nifoverrides.cpp deleted file mode 100644 index 972cf1b84..000000000 --- a/components/nifoverrides/nifoverrides.cpp +++ /dev/null @@ -1,80 +0,0 @@ -#include "nifoverrides.hpp" - -#include - -#include <../components/misc/stringops.hpp> - -#include "../extern/shiny/Main/MaterialInstance.hpp" - -#include - - -using namespace NifOverrides; - -Overrides::TransparencyOverrideMap Overrides::mTransparencyOverrides = Overrides::TransparencyOverrideMap(); -Overrides::MaterialOverrideMap Overrides::mMaterialOverrides = Overrides::MaterialOverrideMap(); - -void Overrides::loadTransparencyOverrides (const std::string& file) -{ - Ogre::ConfigFile cf; - cf.load(file); - - Ogre::ConfigFile::SectionIterator seci = cf.getSectionIterator(); - while (seci.hasMoreElements()) - { - Ogre::String sectionName = seci.peekNextKey(); - mTransparencyOverrides[sectionName] = - Ogre::StringConverter::parseInt(cf.getSetting("alphaRejectValue", sectionName)); - seci.getNext(); - } -} - -void Overrides::loadMaterialOverrides(const std::string &file) -{ - Ogre::ConfigFile cf; - cf.load(file); - - Ogre::ConfigFile::SectionIterator seci = cf.getSectionIterator(); - while (seci.hasMoreElements()) - { - Ogre::String sectionName = seci.peekNextKey(); - - Ogre::ConfigFile::SettingsMultiMap *settings = seci.getNext(); - Ogre::ConfigFile::SettingsMultiMap::iterator i; - std::map overrides; - for (i = settings->begin(); i != settings->end(); ++i) - { - overrides[i->first] = i->second; - } - mMaterialOverrides[sectionName] = overrides; - } - -} - -TransparencyResult Overrides::getTransparencyOverride(const std::string& texture) -{ - TransparencyResult result; - result.first = false; - - TransparencyOverrideMap::iterator it = mTransparencyOverrides.find(Misc::StringUtils::lowerCase(texture)); - if (it != mTransparencyOverrides.end()) - { - result.first = true; - result.second = it->second; - } - - return result; -} - -void Overrides::getMaterialOverrides(const std::string &texture, sh::MaterialInstance* material) -{ - MaterialOverrideMap::iterator it = mMaterialOverrides.find(Misc::StringUtils::lowerCase(texture)); - if (it != mMaterialOverrides.end()) - { - const std::map& overrides = it->second; - for (std::map::const_iterator it = overrides.begin(); it != overrides.end(); ++it) - { - material->setProperty(it->first, sh::makeProperty(it->second)); - } - } -} diff --git a/components/nifoverrides/nifoverrides.hpp b/components/nifoverrides/nifoverrides.hpp deleted file mode 100644 index edff876d4..000000000 --- a/components/nifoverrides/nifoverrides.hpp +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef OPENMW_COMPONENTS_NIFOVERRIDES_NIFOVERRIDES_HPP -#define OPENMW_COMPONENTS_NIFOVERRIDES_NIFOVERRIDES_HPP - -#include - -namespace sh -{ - class MaterialInstance; -} - -namespace NifOverrides -{ - - typedef std::pair TransparencyResult; - - /// Allows to provide overrides for some material properties in NIF files. - /// NIFs are a bit limited in that they don't allow specifying a material externally, which is - /// painful for texture modding. - /// We also use this to patch up transparency settings in certain NIFs that bethesda has chosen poorly. - class Overrides - { - public: - typedef std::map TransparencyOverrideMap; - static TransparencyOverrideMap mTransparencyOverrides; - - typedef std::map > MaterialOverrideMap; - static MaterialOverrideMap mMaterialOverrides; - - void loadTransparencyOverrides (const std::string& file); - void loadMaterialOverrides (const std::string& file); - - static TransparencyResult getTransparencyOverride(const std::string& texture); - static void getMaterialOverrides (const std::string& texture, sh::MaterialInstance* instance); - }; - -} - -#endif diff --git a/files/transparency-overrides.cfg b/files/transparency-overrides.cfg deleted file mode 100644 index 65f9b477a..000000000 --- a/files/transparency-overrides.cfg +++ /dev/null @@ -1,623 +0,0 @@ -# Bethesda has used wrong transparency settings for many textures -# (who would have guessed) -# This is very unfortunate because objects with real transparency: -# - cannot cast shadows -# - cannot receive advanced framebuffer effects like depth of field or ambient occlusion -# - cannot cover lens flare effects (the lens flare will just shine through) - -# This file lists textures that should be using alpha rejection instead of transparency -# basically these are textures that are not translucent (i.e. at one spot on the texture, either transparent or opaque) - -# Note: all the texture names here have to be lowercase - -# fauna -[textures\tx_wickwheat_01.dds] - alphaRejectValue = 128 - -[textures\tx_wickwheat_03.dds] - alphaRejectValue = 128 - -[textures\tx_red_lichen_01.dds] - alphaRejectValue = 128 - -[textures\tx_stone_flower_01.dds] - alphaRejectValue = 128 - -[textures\tx_ivy_02.dds] - alphaRejectValue = 128 - -[textures\tx_ivy_01.dds] - alphaRejectValue = 128 - -[textures\tx_saltrice_04.dds] - alphaRejectValue = 128 - -[textures\tx_black_lichen_01.dds] - alphaRejectValue = 128 - -[textures\tx_leaves_01.dds] - alphaRejectValue = 128 - -[textures\tx_leaves_02.dds] - alphaRejectValue = 128 - -[textures\tx_leaves_03.dds] - alphaRejectValue = 128 - -[textures\tx_leaves_04.dds] - alphaRejectValue = 128 - -[textures\tx_leaves_06.dds] - alphaRejectValue = 128 - -[textures\tx_leaves_07.dds] - alphaRejectValue = 128 - -[textures\tx_ai_heather_01.dds] - alphaRejectValue = 96 - -[textures\tx_goldkanet_01.dds] - alphaRejectValue = 128 - -[textures\tx_goldkanet_02.dds] - alphaRejectValue = 128 - -[textures\tx_plant_tails00.dds] - alphaRejectValue = 128 - -[textures\tx_vine_01.dds] - alphaRejectValue = 128 - -[textures\tx_comberry_01.dds] - alphaRejectValue = 128 - -[textures\tx_willow_flower_02.dds] - alphaRejectValue = 128 - -[textures\tx_cork_bulb_02.dds] - alphaRejectValue = 128 - -[textures\tx_green_lichen_01.dds] - alphaRejectValue = 128 - -[textures\tx_roobrush_01.dds] - alphaRejectValue = 128 - -[textures\tx_bittergreen_02.dds] - alphaRejectValue = 128 - -[textures\tx_chokeweed_01.dds] - alphaRejectValue = 128 - -[textures\tx_branches_01.dds] - alphaRejectValue = 128 - -[textures\tx_branches_02.dds] - alphaRejectValue = 128 - -[textures\tx_guarskin_hut_03.dds] - alphaRejectValue = 128 - -[textures\tx_hackle-lo_02.dds] - alphaRejectValue = 128 - -[textures\tx_bc_fern_01.dds] - alphaRejectValue = 128 - -[textures\tx_bc_fern_02.dds] - alphaRejectValue = 128 - -[textures\tx_bc_leaves_02.dds] - alphaRejectValue = 128 - -[textures\tx_marshmerrow_03.dds] - alphaRejectValue = 128 - -[textures\tx_bc_moss_01.dds] - alphaRejectValue = 128 - -[textures\tx_bc_moss_02.dds] - alphaRejectValue = 128 - -[textures\tx_bc_lilypad_01.dds] - alphaRejectValue = 128 - -[textures\tx_bc_lilypad_02.dds] - alphaRejectValue = 128 - -[textures\tx_bc_lilypad_03.dds] - alphaRejectValue = 128 - -[textures\tx_fire_fern_01.dds] - alphaRejectValue = 128 - -# banners and flags -[textures\tx_flag_imp_01.dds] - alphaRejectValue = 128 - -[textures\tx_v_b_arena_01.dds] - alphaRejectValue = 128 - -[textures\tx_v_b_comfort_01.dds] - alphaRejectValue = 128 - -[textures\tx_v_b_child_01.dds] - alphaRejectValue = 128 - -[textures\tx_v_b_count_01.dds] - alphaRejectValue = 128 - -[textures\tx_v_b_faith_01.dds] - alphaRejectValue = 128 - -[textures\tx_v_b_walk_01.dds] - alphaRejectValue = 128 - -[textures\tx_v_b_imp_01.dds] - alphaRejectValue = 128 - -[textures\tx_v_b_redoran_01.dds] - alphaRejectValue = 128 - -[textures\tx_v_b_avs_01.dds] - alphaRejectValue = 128 - -[textures\tx_v_b_serving_01.dds] - alphaRejectValue = 128 - -[textures\tx_v_b_speak_01.dds] - alphaRejectValue = 128 - -[textures\tx_v_b_stdeyln_01.dds] - alphaRejectValue = 128 - -[textures\tx_v_b_stolms_01.dds] - alphaRejectValue = 128 - -[textures\tx_v_b_thin_01.dds] - alphaRejectValue = 128 - -[textures\tx_v_b_vivec_01.dds] - alphaRejectValue = 128 - -[textures\tx_v_b_vivec_02.dds] - alphaRejectValue = 128 - -[textures\tx_ashl_banner_01.dds] - alphaRejectValue = 128 - -[textures\tx_ashl_banner_02.dds] - alphaRejectValue = 128 - -[textures\tx_ashl_banner_04.dds] - alphaRejectValue = 128 - -[textures\tx_ashl_banner_05.dds] - alphaRejectValue = 128 - -[textures\tx_ashl_banner_06.dds] - alphaRejectValue = 128 - -[textures\tx_ashl_banner_07.dds] - alphaRejectValue = 128 - -[textures\tx_ashl_a_banner.dds] - alphaRejectValue = 128 - -[textures\tx_ashl_e_banner.dds] - alphaRejectValue = 128 - -[textures\tx_ashl_u_banner.dds] - alphaRejectValue = 128 - -[textures\tx_ashl_z_banner.dds] - alphaRejectValue = 128 - -[textures\tx_banner_6th.dds] - alphaRejectValue = 128 - -[textures\tx_banner_6th_tall.dds] - alphaRejectValue = 128 - -[textures\tx_banner_gnisis_01.dds] - alphaRejectValue = 128 - -[textures\tx_banner_gnisis_02.dds] - alphaRejectValue = 128 - -[textures\tx_de_tapestry_bhm_01.dds] - alphaRejectValue = 128 - -[textures\tx_de_tapestry_02.dds] - alphaRejectValue = 128 - -[textures\tx_de_tapestry_03.dds] - alphaRejectValue = 128 - -[textures\tx_de_tapestry_04.dds] - alphaRejectValue = 128 - -[textures\tx_de_tapestry_05.dds] - alphaRejectValue = 128 - -[textures\tx_de_tapestry_06.dds] - alphaRejectValue = 128 - -[textures\tx_de_tapestry_07.dds] - alphaRejectValue = 128 - -[textures\tx_de_tapestry_08.dds] - alphaRejectValue = 128 - -[textures\tx_de_tapestry_08.dds] - alphaRejectValue = 128 - -[textures\tx_de_tapestry_09.dds] - alphaRejectValue = 128 - -[textures\tx_de_tapestry_10.dds] - alphaRejectValue = 128 - -[textures\tx_de_tapestry_11.dds] - alphaRejectValue = 128 - -[textures\tx_de_tapestry_12.dds] - alphaRejectValue = 128 - -[textures\tx_de_tapestry_13.dds] - alphaRejectValue = 128 - -[textures\tx_de_lutestrings_01.dds] - alphaRejectValue = 128 - -[textures\tx_fabric_imp_altar_01.dds] - alphaRejectValue = 128 - -[textures\tx_c_t_akatosh_01.dds] - alphaRejectValue = 128 - -[textures\tx_c_t_apprentice_01.dds] - alphaRejectValue = 128 - -[textures\tx_c_t_arkay_01.dds] - alphaRejectValue = 128 - -[textures\tx_c_t_dibella_01.dds] - alphaRejectValue = 128 - -[textures\tx_c_t_golem_01.dds] - alphaRejectValue = 128 - -[textures\tx_c_t_julianos_01.dds] - alphaRejectValue = 128 - -[textures\tx_c_t_kynareth_01.dds] - alphaRejectValue = 128 - -[textures\tx_c_t_lady_01.dds] - alphaRejectValue = 128 - -[textures\tx_c_t_lord_01.dds] - alphaRejectValue = 128 - -[textures\tx_c_t_lover_01.dds] - alphaRejectValue = 128 - -[textures\tx_c_t_mara_01.dds] - alphaRejectValue = 128 - -[textures\tx_c_t_ritual_01.dds] - alphaRejectValue = 128 - -[textures\tx_c_t_shadow_01.dds] - alphaRejectValue = 128 - -[textures\tx_c_t_steed_01.dds] - alphaRejectValue = 128 - -[textures\tx_c_t_stendarr_01.dds] - alphaRejectValue = 128 - -[textures\tx_c_t_thief_01.dds] - alphaRejectValue = 128 - -[textures\tx_c_t_tower_01.dds] - alphaRejectValue = 128 - -[textures\tx_c_t_warrior_01.dds] - alphaRejectValue = 128 - -[textures\tx_c_t_wizard_01.dds] - alphaRejectValue = 128 - -[textures\tx_c_t_zenithar_01.dds] - alphaRejectValue = 128 - -[textures\tx_banner_dagoth_01.dds] - alphaRejectValue = 128 - -[textures\tx_bannerd_tavern_01.dds] - alphaRejectValue = 128 - -[textures\tx_bannerd_goods_01.dds] - alphaRejectValue = 128 - -[textures\tx_bannerd_danger_01.dds] - alphaRejectValue = 128 - -[textures\tx_bannerd_welcome_01.dds] - alphaRejectValue = 128 - -[textures\tx_bannerd_clothing_01.dds] - alphaRejectValue = 128 - -[textures\tx_bannerd_alchemy_01.dds] - alphaRejectValue = 128 - -[textures\tx_banner_hlaalu_01.dds] - alphaRejectValue = 128 - -[textures\tx_banner_redoran_01.dds] - alphaRejectValue = 128 - -[textures\tx_banner_temple_01.dds] - alphaRejectValue = 128 - -[textures\tx_banner_temple_03.dds] - alphaRejectValue = 128 - -[textures\tx_de_banner_book_01.dds] - alphaRejectValue = 128 - -[textures\tx_de_banner_ald_velothi.dds] - alphaRejectValue = 128 - -[textures\tx_de_banner_gnaar_mok.dds] - alphaRejectValue = 128 - -[textures\tx_de_banner_hla_oad.dds] - alphaRejectValue = 128 - -[textures\tx_de_banner_khull.dds] - alphaRejectValue = 128 - -[textures\tx_de_banner_pawn_01.dds] - alphaRejectValue = 128 - -[textures\tx_de_banner_sadrith_mora.dds] - alphaRejectValue = 128 - -[textures\tx_de_banner_tel_aruhn.dds] - alphaRejectValue = 128 - -[textures\tx_de_banner_tel_branora.dds] - alphaRejectValue = 128 - -[textures\tx_de_banner_tel_fyr.dds] - alphaRejectValue = 128 - -[textures\tx_de_banner_tel_mora.dds] - alphaRejectValue = 128 - -[textures\tx_de_banner_telvani_01.dds] - alphaRejectValue = 128 - -[textures\tx_de_banner_tel_vos.dds] - alphaRejectValue = 128 - -[textures\tx_de_banner_vos.dds] - alphaRejectValue = 128 - -[textures\tx_bannerd_w_a_shop_01.dds] - alphaRejectValue = 128 - -[textures\tx_banner_temple_02.dds] - alphaRejectValue = 128 - -[textures\tx_mural1_00.dds] - alphaRejectValue = 128 - -[textures\tx_mural1_01.dds] - alphaRejectValue = 128 - -[textures\tx_mural4_00.dds] - alphaRejectValue = 128 - -[textures\tx_mural4_01.dds] - alphaRejectValue = 128 - -[textures\tx_mural5_00.dds] - alphaRejectValue = 128 - -[textures\tx_v_b_telvanni_01.dds] - alphaRejectValue = 128 - -[textures\tx_v_b_hlaalu_01.dds] - alphaRejectValue = 128 - -[textures\tx_fabric_tapestry.dds] - alphaRejectValue = 128 - -[textures\tx_fabric_tapestry_01.dds] - alphaRejectValue = 128 - -[textures\tx_fabric_tapestry_02.dds] - alphaRejectValue = 128 - -[textures\tx_fabric_tapestry_03.dds] - alphaRejectValue = 128 - -[textures\tx_fabric_tapestry_04.dds] - alphaRejectValue = 128 - -# characters -[textures\tx_netchgod00.dds] - alphaRejectValue = 128 - -[textures\tx_b_n_argonian_f_hair02.dds] - alphaRejectValue = 128 - -[textures\tx_b_n_argonian_f_hair03.dds] - alphaRejectValue = 128 - -[textures\tx_b_n_argonian_m_hair01.dds] - alphaRejectValue = 128 - -[textures\tx_b_n_argonian_m_hair04.dds] - alphaRejectValue = 128 - -[textures\tx_b_n_argonian_m_hair05.dds] - alphaRejectValue = 128 - -[textures\tx_b_n_khajiit_f_hair01.dds] - alphaRejectValue = 128 - -[textures\tx_b_n_khajiit_f_hair02.dds] - alphaRejectValue = 128 - -[textures\tx_b_n_khajiit_m_hair01.dds] - alphaRejectValue = 128 - -[textures\tx_corprus_stalker12.dds] - alphaRejectValue = 128 - -[textures\tx_a_clavicus02.dds] - alphaRejectValue = 128 - -[textures\tx_b_n_dark elf_m_hair11.dds] - alphaRejectValue = 128 - -[textures\tx_b_n_dark elf_f_hair10.dds] - alphaRejectValue = 128 - -# misc items -[textures\tx_sail.dds] - alphaRejectValue = 128 - -[textures\tx_longboatsail01.dds] - alphaRejectValue = 128 - -[textures\tx_longboatsail01a.dds] - alphaRejectValue = 128 - -[textures\tx_longboatsail01b.dds] - alphaRejectValue = 128 - -[textures\tx_longboatsail02.dds] - alphaRejectValue = 128 - -[textures\tx_quill.dds] - alphaRejectValue = 128 - -[textures\tx_note_01.dds] - alphaRejectValue = 128 - -[textures\tx_note_02.dds] - alphaRejectValue = 128 - -[textures\tx_parchment_02.dds] - alphaRejectValue = 128 - -[textures\tx_parchment_03.dds] - alphaRejectValue = 128 - -[textures\tx_scroll_01.dds] - alphaRejectValue = 128 - -[textures\tx_scroll_02.dds] - alphaRejectValue = 128 - -[textures\tx_scroll_03.dds] - alphaRejectValue = 128 - -[textures\tx_alpha_small_edge.dds] - alphaRejectValue = 128 - -[textures\tx_alpha_shadow_circular.dds] - alphaRejectValue = 128 - -# building materials -[textures\tx_shack_thatch_strip.dds] - alphaRejectValue = 128 - -[textures\tx_rug00.dds] - alphaRejectValue = 128 - -[textures\tx_rug_02.dds] - alphaRejectValue = 128 - -[textures\tx_rug_edge_01.dds] - alphaRejectValue = 128 - -[textures\tx_awning_thatch_02.dds] - alphaRejectValue = 128 - -[textures\tx_awning_woven_01.dds] - alphaRejectValue = 128 - -[textures\tx_bridgeropes.dds] - alphaRejectValue = 128 - -[textures\tx_rope_woven_01.dds] - alphaRejectValue = 128 - -[textures\tx_rope_woven_02.dds] - alphaRejectValue = 128 - -[textures\tx_ashl_tent_06.dds] - alphaRejectValue = 128 - -[textures\tx_guar_tarp.dds] - alphaRejectValue = 128 - -[textures\tx_velothi_glyph00.dds] - alphaRejectValue = 128 - - - -# Bloodmoon - -[textures\tx_bm_holly_01.dds] - alphaRejectValue = 128 - -[textures\tx_bm_holly_snow_01.dds] - alphaRejectValue = 128 - -[textures\tx_bm_pine_04a.dds] - alphaRejectValue = 128 - -[textures\tx_bm_pine_03a.dds] - alphaRejectValue = 128 - -[textures\tx_bm_pine_02a.dds] - alphaRejectValue = 128 - -[textures\tx_bm_pine_01a.dds] - alphaRejectValue = 128 - -[textures\tx_bm_shrub_02.dds] - alphaRejectValue = 128 - -[textures\tx_bm_shrub_01.dds] - alphaRejectValue = 128 - -[textures\tx_bm_snow_pine_01a.dds] - alphaRejectValue = 128 - -[textures\tx_bm_snow_pine_02a.dds] - alphaRejectValue = 128 - -[textures\tx_bm_snow_pine_03a.dds] - alphaRejectValue = 128 - -[textures\tx_bm_snow_pine_04a.dds] - alphaRejectValue = 128 - -[textures\tx_bm_deadpine_01.dds] - alphaRejectValue = 128 - -[textures\tx_bm_shrub_snow_02.dds] - alphaRejectValue = 128 - -[textures\tx_bm_s_deadpine_01.dds] - alphaRejectValue = 128 diff --git a/libs/openengine/CMakeLists.txt b/libs/openengine/CMakeLists.txt index 3542becf6..492a6323b 100644 --- a/libs/openengine/CMakeLists.txt +++ b/libs/openengine/CMakeLists.txt @@ -1,12 +1,12 @@ set(OENGINE_OGRE - ogre/renderer.cpp + #ogre/renderer.cpp ogre/lights.cpp ogre/selectionbuffer.cpp ) set(OENGINE_GUI gui/loglistener.cpp - gui/manager.cpp + #gui/manager.cpp gui/layout.cpp ) From af67de73a5b75cb4f95e0cd3de64ba2020d6b0b0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 1 Apr 2015 17:06:31 +0200 Subject: [PATCH 0872/3725] Delete shiny --- CMakeLists.txt | 6 - apps/opencs/CMakeLists.txt | 1 - apps/openmw/CMakeLists.txt | 1 - components/terrain/chunk.cpp | 2 - extern/shiny/CMakeLists.txt | 54 - extern/shiny/Docs/Configurations.dox | 32 - extern/shiny/Docs/Doxyfile | 1826 ----------------- extern/shiny/Docs/GettingStarted.dox | 65 - extern/shiny/Docs/Lod.dox | 49 - extern/shiny/Docs/Macros.dox | 283 --- extern/shiny/Docs/Mainpage.dox | 13 - extern/shiny/Docs/Materials.dox | 131 -- extern/shiny/Editor/Actions.cpp | 195 -- extern/shiny/Editor/Actions.hpp | 307 --- extern/shiny/Editor/AddPropertyDialog.cpp | 31 - extern/shiny/Editor/AddPropertyDialog.h | 22 - extern/shiny/Editor/AddPropertyDialog.hpp | 29 - extern/shiny/Editor/CMakeLists.txt | 61 - extern/shiny/Editor/ColoredTabWidget.hpp | 24 - extern/shiny/Editor/Editor.cpp | 117 -- extern/shiny/Editor/Editor.hpp | 73 - extern/shiny/Editor/MainWindow.cpp | 952 --------- extern/shiny/Editor/MainWindow.hpp | 139 -- extern/shiny/Editor/NewMaterialDialog.cpp | 14 - extern/shiny/Editor/NewMaterialDialog.hpp | 22 - extern/shiny/Editor/PropertySortModel.cpp | 35 - extern/shiny/Editor/PropertySortModel.hpp | 21 - extern/shiny/Editor/Query.cpp | 134 -- extern/shiny/Editor/Query.hpp | 121 -- extern/shiny/Editor/addpropertydialog.ui | 118 -- extern/shiny/Editor/mainwindow.ui | 420 ---- extern/shiny/Editor/newmaterialdialog.ui | 98 - extern/shiny/Extra/core.h | 174 -- extern/shiny/License.txt | 9 - extern/shiny/Main/Factory.cpp | 817 -------- extern/shiny/Main/Factory.hpp | 271 --- extern/shiny/Main/Language.hpp | 17 - extern/shiny/Main/MaterialInstance.cpp | 261 --- extern/shiny/Main/MaterialInstance.hpp | 109 - extern/shiny/Main/MaterialInstancePass.cpp | 35 - extern/shiny/Main/MaterialInstancePass.hpp | 29 - .../Main/MaterialInstanceTextureUnit.cpp | 14 - .../Main/MaterialInstanceTextureUnit.hpp | 27 - extern/shiny/Main/Platform.cpp | 89 - extern/shiny/Main/Platform.hpp | 147 -- extern/shiny/Main/Preprocessor.cpp | 151 -- extern/shiny/Main/Preprocessor.hpp | 69 - extern/shiny/Main/PropertyBase.cpp | 302 --- extern/shiny/Main/PropertyBase.hpp | 244 --- extern/shiny/Main/ScriptLoader.cpp | 414 ---- extern/shiny/Main/ScriptLoader.hpp | 134 -- extern/shiny/Main/ShaderInstance.cpp | 698 ------- extern/shiny/Main/ShaderInstance.hpp | 71 - extern/shiny/Main/ShaderSet.cpp | 195 -- extern/shiny/Main/ShaderSet.hpp | 69 - .../shiny/Platforms/Ogre/OgreGpuProgram.cpp | 69 - .../shiny/Platforms/Ogre/OgreGpuProgram.hpp | 31 - extern/shiny/Platforms/Ogre/OgreMaterial.cpp | 120 -- extern/shiny/Platforms/Ogre/OgreMaterial.hpp | 43 - .../Platforms/Ogre/OgreMaterialSerializer.cpp | 85 - .../Platforms/Ogre/OgreMaterialSerializer.hpp | 29 - extern/shiny/Platforms/Ogre/OgrePass.cpp | 131 -- extern/shiny/Platforms/Ogre/OgrePass.hpp | 35 - extern/shiny/Platforms/Ogre/OgrePlatform.cpp | 193 -- extern/shiny/Platforms/Ogre/OgrePlatform.hpp | 74 - .../Platforms/Ogre/OgreTextureUnitState.cpp | 72 - .../Platforms/Ogre/OgreTextureUnitState.hpp | 27 - extern/shiny/Readme.txt | 33 - libs/openengine/CMakeLists.txt | 1 - libs/openengine/ogre/selectionbuffer.cpp | 164 -- libs/openengine/ogre/selectionbuffer.hpp | 62 - 71 files changed, 10911 deletions(-) delete mode 100644 extern/shiny/CMakeLists.txt delete mode 100644 extern/shiny/Docs/Configurations.dox delete mode 100644 extern/shiny/Docs/Doxyfile delete mode 100644 extern/shiny/Docs/GettingStarted.dox delete mode 100644 extern/shiny/Docs/Lod.dox delete mode 100644 extern/shiny/Docs/Macros.dox delete mode 100644 extern/shiny/Docs/Mainpage.dox delete mode 100644 extern/shiny/Docs/Materials.dox delete mode 100644 extern/shiny/Editor/Actions.cpp delete mode 100644 extern/shiny/Editor/Actions.hpp delete mode 100644 extern/shiny/Editor/AddPropertyDialog.cpp delete mode 100644 extern/shiny/Editor/AddPropertyDialog.h delete mode 100644 extern/shiny/Editor/AddPropertyDialog.hpp delete mode 100644 extern/shiny/Editor/CMakeLists.txt delete mode 100644 extern/shiny/Editor/ColoredTabWidget.hpp delete mode 100644 extern/shiny/Editor/Editor.cpp delete mode 100644 extern/shiny/Editor/Editor.hpp delete mode 100644 extern/shiny/Editor/MainWindow.cpp delete mode 100644 extern/shiny/Editor/MainWindow.hpp delete mode 100644 extern/shiny/Editor/NewMaterialDialog.cpp delete mode 100644 extern/shiny/Editor/NewMaterialDialog.hpp delete mode 100644 extern/shiny/Editor/PropertySortModel.cpp delete mode 100644 extern/shiny/Editor/PropertySortModel.hpp delete mode 100644 extern/shiny/Editor/Query.cpp delete mode 100644 extern/shiny/Editor/Query.hpp delete mode 100644 extern/shiny/Editor/addpropertydialog.ui delete mode 100644 extern/shiny/Editor/mainwindow.ui delete mode 100644 extern/shiny/Editor/newmaterialdialog.ui delete mode 100644 extern/shiny/Extra/core.h delete mode 100644 extern/shiny/License.txt delete mode 100644 extern/shiny/Main/Factory.cpp delete mode 100644 extern/shiny/Main/Factory.hpp delete mode 100644 extern/shiny/Main/Language.hpp delete mode 100644 extern/shiny/Main/MaterialInstance.cpp delete mode 100644 extern/shiny/Main/MaterialInstance.hpp delete mode 100644 extern/shiny/Main/MaterialInstancePass.cpp delete mode 100644 extern/shiny/Main/MaterialInstancePass.hpp delete mode 100644 extern/shiny/Main/MaterialInstanceTextureUnit.cpp delete mode 100644 extern/shiny/Main/MaterialInstanceTextureUnit.hpp delete mode 100644 extern/shiny/Main/Platform.cpp delete mode 100644 extern/shiny/Main/Platform.hpp delete mode 100644 extern/shiny/Main/Preprocessor.cpp delete mode 100644 extern/shiny/Main/Preprocessor.hpp delete mode 100644 extern/shiny/Main/PropertyBase.cpp delete mode 100644 extern/shiny/Main/PropertyBase.hpp delete mode 100644 extern/shiny/Main/ScriptLoader.cpp delete mode 100644 extern/shiny/Main/ScriptLoader.hpp delete mode 100644 extern/shiny/Main/ShaderInstance.cpp delete mode 100644 extern/shiny/Main/ShaderInstance.hpp delete mode 100644 extern/shiny/Main/ShaderSet.cpp delete mode 100644 extern/shiny/Main/ShaderSet.hpp delete mode 100644 extern/shiny/Platforms/Ogre/OgreGpuProgram.cpp delete mode 100644 extern/shiny/Platforms/Ogre/OgreGpuProgram.hpp delete mode 100644 extern/shiny/Platforms/Ogre/OgreMaterial.cpp delete mode 100644 extern/shiny/Platforms/Ogre/OgreMaterial.hpp delete mode 100644 extern/shiny/Platforms/Ogre/OgreMaterialSerializer.cpp delete mode 100644 extern/shiny/Platforms/Ogre/OgreMaterialSerializer.hpp delete mode 100644 extern/shiny/Platforms/Ogre/OgrePass.cpp delete mode 100644 extern/shiny/Platforms/Ogre/OgrePass.hpp delete mode 100644 extern/shiny/Platforms/Ogre/OgrePlatform.cpp delete mode 100644 extern/shiny/Platforms/Ogre/OgrePlatform.hpp delete mode 100644 extern/shiny/Platforms/Ogre/OgreTextureUnitState.cpp delete mode 100644 extern/shiny/Platforms/Ogre/OgreTextureUnitState.hpp delete mode 100644 extern/shiny/Readme.txt delete mode 100644 libs/openengine/ogre/selectionbuffer.cpp delete mode 100644 libs/openengine/ogre/selectionbuffer.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index bf525646d..77bea373f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -418,7 +418,6 @@ IF(NOT WIN32 AND NOT APPLE) # Install licenses INSTALL(FILES "docs/license/DejaVu Font License.txt" DESTINATION "${LICDIR}" ) - INSTALL(FILES "extern/shiny/License.txt" DESTINATION "${LICDIR}" RENAME "Shiny License.txt" ) # Install icon and desktop file INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.desktop" DESTINATION "${DATAROOTDIR}/applications" COMPONENT "openmw") @@ -542,7 +541,6 @@ include_directories(libs) add_subdirectory(libs/openengine) # Extern -#add_subdirectory (extern/shiny) #add_subdirectory (extern/ogre-ffmpeg-videoplayer) add_subdirectory (extern/oics) #add_subdirectory (extern/sdl4ogre) @@ -680,10 +678,6 @@ if (WIN32) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WARNINGS} ${MT_BUILD}") - # boost::wave has a few issues with signed / unsigned conversions, so we suppress those here - set(SHINY_WARNINGS "${WARNINGS} /wd4245") - set_target_properties(shiny PROPERTIES COMPILE_FLAGS "${SHINY_WARNINGS} ${MT_BUILD}") - # oics uses tinyxml, which has an initialized but unused variable set(OICS_WARNINGS "${WARNINGS} /wd4189") set_target_properties(oics PROPERTIES COMPILE_FLAGS "${OICS_WARNINGS} ${MT_BUILD}") diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 103a56ecc..bae1ec4d4 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -204,7 +204,6 @@ target_link_libraries(openmw-cs ${OGRE_Overlay_LIBRARIES} ${OGRE_STATIC_PLUGINS} ${OPENSCENEGRAPH_LIBRARIES} - ${SHINY_LIBRARIES} ${Boost_LIBRARIES} ${BULLET_LIBRARIES} ${QT_LIBRARIES} diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 56ee82d7d..50aeafc2a 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -129,7 +129,6 @@ target_link_libraries(openmw ${OENGINE_LIBRARY} ${OGRE_LIBRARIES} ${OGRE_STATIC_PLUGINS} - ${SHINY_LIBRARIES} ${Boost_LIBRARIES} ${OPENAL_LIBRARY} ${SOUND_INPUT_LIBRARY} diff --git a/components/terrain/chunk.cpp b/components/terrain/chunk.cpp index cce5abd36..e3bae1173 100644 --- a/components/terrain/chunk.cpp +++ b/components/terrain/chunk.cpp @@ -27,8 +27,6 @@ #include #include -#include - namespace Terrain { diff --git a/extern/shiny/CMakeLists.txt b/extern/shiny/CMakeLists.txt deleted file mode 100644 index daf2a9df8..000000000 --- a/extern/shiny/CMakeLists.txt +++ /dev/null @@ -1,54 +0,0 @@ -cmake_minimum_required(VERSION 2.8) - -# This is NOT intended as a stand-alone build system! Instead, you should include this from the main CMakeLists of your project. -# Make sure to link against Ogre and boost::filesystem. - -option(SHINY_BUILD_OGRE_PLATFORM "build the Ogre platform" ON) - -set(SHINY_LIBRARY "shiny") -set(SHINY_OGREPLATFORM_LIBRARY "shiny.OgrePlatform") - -# Sources -set(SOURCE_FILES - Main/Factory.cpp - Main/MaterialInstance.cpp - Main/MaterialInstancePass.cpp - Main/MaterialInstanceTextureUnit.cpp - Main/Platform.cpp - Main/Preprocessor.cpp - Main/PropertyBase.cpp - Main/ScriptLoader.cpp - Main/ShaderInstance.cpp - Main/ShaderSet.cpp -) - -set(OGRE_PLATFORM_SOURCE_FILES - Platforms/Ogre/OgreGpuProgram.cpp - Platforms/Ogre/OgreMaterial.cpp - Platforms/Ogre/OgreMaterialSerializer.cpp - Platforms/Ogre/OgrePass.cpp - Platforms/Ogre/OgrePlatform.cpp - Platforms/Ogre/OgreTextureUnitState.cpp -) - -file(GLOB OGRE_PLATFORM_SOURCE_FILES Platforms/Ogre/*.cpp) - -add_library(${SHINY_LIBRARY} STATIC ${SOURCE_FILES}) - -set(SHINY_LIBRARIES ${SHINY_LIBRARY}) - -if (SHINY_BUILD_OGRE_PLATFORM) - add_library(${SHINY_OGREPLATFORM_LIBRARY} STATIC ${OGRE_PLATFORM_SOURCE_FILES}) - set(SHINY_LIBRARIES ${SHINY_LIBRARIES} ${SHINY_OGREPLATFORM_LIBRARY}) -endif() - -set(SHINY_LIBRARY ${SHINY_LIBRARY} PARENT_SCOPE) - -if (DEFINED SHINY_BUILD_MATERIAL_EDITOR) - add_subdirectory(Editor) - - set(SHINY_BUILD_EDITOR_FLAG ${SHINY_BUILD_EDITOR_FLAG} PARENT_SCOPE) -endif() - -link_directories(${CMAKE_CURRENT_BINARY_DIR}) -set(SHINY_LIBRARIES ${SHINY_LIBRARIES} PARENT_SCOPE) diff --git a/extern/shiny/Docs/Configurations.dox b/extern/shiny/Docs/Configurations.dox deleted file mode 100644 index 570e81d4a..000000000 --- a/extern/shiny/Docs/Configurations.dox +++ /dev/null @@ -1,32 +0,0 @@ -/*! - - \page configurations Configurations - - A common task in shader development is to provide a different set of simpler shaders for all your materials. Some examples: - - When rendering cubic or planar reflection maps in real-time, you will want to disable shadows. - - For an in-game minimap render target, you don't want to have fog. - - For this task, the library provides a \a Configuration concept. - - A Configuration is a set of properties that can override global settings, as long as this Configuration is active. - - Here's an example. Say you have a global setting with the name 'shadows' that controls if your materials receive shadows. - - Now, lets create a configuration for our reflection render targets that disables shadows for all materials. Paste the following in a new file with the extension '.configuration': - - \code - configuration reflection_targets - { - shadows false - } - \endcode - - \note You may also create configurations using sh::Factory::createConfiguration. - - The active Configuration is controlled by the active material scheme in Ogre. So, in order to use the configuration "reflection_targets" for your reflection renders, simply call - \code - viewport->setMaterialScheme ("reflection_targets"); - \endcode - on the Ogre viewport of your reflection render! - -*/ diff --git a/extern/shiny/Docs/Doxyfile b/extern/shiny/Docs/Doxyfile deleted file mode 100644 index 3564c45f6..000000000 --- a/extern/shiny/Docs/Doxyfile +++ /dev/null @@ -1,1826 +0,0 @@ -# Doxyfile 1.8.1.1 - -# This file describes the settings to be used by the documentation system -# doxygen (www.doxygen.org) for a project -# -# All text after a hash (#) is considered a comment and will be ignored -# The format is: -# TAG = value [value, ...] -# For lists items can also be appended using: -# TAG += value [value, ...] -# Values that contain spaces should be placed between quotes (" ") - -#--------------------------------------------------------------------------- -# Project related configuration options -#--------------------------------------------------------------------------- - -# This tag specifies the encoding used for all characters in the config file -# that follow. The default is UTF-8 which is also the encoding used for all -# text before the first occurrence of this tag. Doxygen uses libiconv (or the -# iconv built into libc) for the transcoding. See -# http://www.gnu.org/software/libiconv for the list of possible encodings. - -DOXYFILE_ENCODING = UTF-8 - -# The PROJECT_NAME tag is a single word (or sequence of words) that should -# identify the project. Note that if you do not use Doxywizard you need -# to put quotes around the project name if it contains spaces. - -PROJECT_NAME = shiny - -# The PROJECT_NUMBER tag can be used to enter a project or revision number. -# This could be handy for archiving the generated documentation or -# if some version control system is used. - -PROJECT_NUMBER = - -# Using the PROJECT_BRIEF tag one can provide an optional one line description -# for a project that appears at the top of each page and should give viewer -# a quick idea about the purpose of the project. Keep the description short. - -PROJECT_BRIEF = - -# With the PROJECT_LOGO tag one can specify an logo or icon that is -# included in the documentation. The maximum height of the logo should not -# exceed 55 pixels and the maximum width should not exceed 200 pixels. -# Doxygen will copy the logo to the output directory. - -PROJECT_LOGO = - -# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) -# base path where the generated documentation will be put. -# If a relative path is entered, it will be relative to the location -# where doxygen was started. If left blank the current directory will be used. - -OUTPUT_DIRECTORY = /home/scrawl/sh_doxy/generated - -# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create -# 4096 sub-directories (in 2 levels) under the output directory of each output -# format and will distribute the generated files over these directories. -# Enabling this option can be useful when feeding doxygen a huge amount of -# source files, where putting all generated files in the same directory would -# otherwise cause performance problems for the file system. - -CREATE_SUBDIRS = NO - -# The OUTPUT_LANGUAGE tag is used to specify the language in which all -# documentation generated by doxygen is written. Doxygen will use this -# information to generate all constant output in the proper language. -# The default language is English, other supported languages are: -# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, -# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, -# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English -# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, -# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, -# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. - -OUTPUT_LANGUAGE = English - -# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will -# include brief member descriptions after the members that are listed in -# the file and class documentation (similar to JavaDoc). -# Set to NO to disable this. - -BRIEF_MEMBER_DESC = YES - -# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend -# the brief description of a member or function before the detailed description. -# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the -# brief descriptions will be completely suppressed. - -REPEAT_BRIEF = YES - -# This tag implements a quasi-intelligent brief description abbreviator -# that is used to form the text in various listings. Each string -# in this list, if found as the leading text of the brief description, will be -# stripped from the text and the result after processing the whole list, is -# used as the annotated text. Otherwise, the brief description is used as-is. -# If left blank, the following values are used ("$name" is automatically -# replaced with the name of the entity): "The $name class" "The $name widget" -# "The $name file" "is" "provides" "specifies" "contains" -# "represents" "a" "an" "the" - -ABBREVIATE_BRIEF = "The $name class" \ - "The $name widget" \ - "The $name file" \ - is \ - provides \ - specifies \ - contains \ - represents \ - a \ - an \ - the - -# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then -# Doxygen will generate a detailed section even if there is only a brief -# description. - -ALWAYS_DETAILED_SEC = NO - -# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all -# inherited members of a class in the documentation of that class as if those -# members were ordinary class members. Constructors, destructors and assignment -# operators of the base classes will not be shown. - -INLINE_INHERITED_MEMB = NO - -# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full -# path before files name in the file list and in the header files. If set -# to NO the shortest path that makes the file name unique will be used. - -FULL_PATH_NAMES = YES - -# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag -# can be used to strip a user-defined part of the path. Stripping is -# only done if one of the specified strings matches the left-hand part of -# the path. The tag can be used to show relative paths in the file list. -# If left blank the directory from which doxygen is run is used as the -# path to strip. - -STRIP_FROM_PATH = - -# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of -# the path mentioned in the documentation of a class, which tells -# the reader which header file to include in order to use a class. -# If left blank only the name of the header file containing the class -# definition is used. Otherwise one should specify the include paths that -# are normally passed to the compiler using the -I flag. - -STRIP_FROM_INC_PATH = - -# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter -# (but less readable) file names. This can be useful if your file system -# doesn't support long names like on DOS, Mac, or CD-ROM. - -SHORT_NAMES = NO - -# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen -# will interpret the first line (until the first dot) of a JavaDoc-style -# comment as the brief description. If set to NO, the JavaDoc -# comments will behave just like regular Qt-style comments -# (thus requiring an explicit @brief command for a brief description.) - -JAVADOC_AUTOBRIEF = NO - -# If the QT_AUTOBRIEF tag is set to YES then Doxygen will -# interpret the first line (until the first dot) of a Qt-style -# comment as the brief description. If set to NO, the comments -# will behave just like regular Qt-style comments (thus requiring -# an explicit \brief command for a brief description.) - -QT_AUTOBRIEF = NO - -# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen -# treat a multi-line C++ special comment block (i.e. a block of //! or /// -# comments) as a brief description. This used to be the default behaviour. -# The new default is to treat a multi-line C++ comment block as a detailed -# description. Set this tag to YES if you prefer the old behaviour instead. - -MULTILINE_CPP_IS_BRIEF = NO - -# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented -# member inherits the documentation from any documented member that it -# re-implements. - -INHERIT_DOCS = YES - -# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce -# a new page for each member. If set to NO, the documentation of a member will -# be part of the file/class/namespace that contains it. - -SEPARATE_MEMBER_PAGES = NO - -# The TAB_SIZE tag can be used to set the number of spaces in a tab. -# Doxygen uses this value to replace tabs by spaces in code fragments. - -TAB_SIZE = 8 - -# This tag can be used to specify a number of aliases that acts -# as commands in the documentation. An alias has the form "name=value". -# For example adding "sideeffect=\par Side Effects:\n" will allow you to -# put the command \sideeffect (or @sideeffect) in the documentation, which -# will result in a user-defined paragraph with heading "Side Effects:". -# You can put \n's in the value part of an alias to insert newlines. - -ALIASES = - -# This tag can be used to specify a number of word-keyword mappings (TCL only). -# A mapping has the form "name=value". For example adding -# "class=itcl::class" will allow you to use the command class in the -# itcl::class meaning. - -TCL_SUBST = - -# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C -# sources only. Doxygen will then generate output that is more tailored for C. -# For instance, some of the names that are used will be different. The list -# of all members will be omitted, etc. - -OPTIMIZE_OUTPUT_FOR_C = NO - -# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java -# sources only. Doxygen will then generate output that is more tailored for -# Java. For instance, namespaces will be presented as packages, qualified -# scopes will look different, etc. - -OPTIMIZE_OUTPUT_JAVA = NO - -# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran -# sources only. Doxygen will then generate output that is more tailored for -# Fortran. - -OPTIMIZE_FOR_FORTRAN = NO - -# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL -# sources. Doxygen will then generate output that is tailored for -# VHDL. - -OPTIMIZE_OUTPUT_VHDL = NO - -# Doxygen selects the parser to use depending on the extension of the files it -# parses. With this tag you can assign which parser to use for a given extension. -# Doxygen has a built-in mapping, but you can override or extend it using this -# tag. The format is ext=language, where ext is a file extension, and language -# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C, -# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make -# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C -# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions -# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. - -EXTENSION_MAPPING = - -# If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all -# comments according to the Markdown format, which allows for more readable -# documentation. See http://daringfireball.net/projects/markdown/ for details. -# The output of markdown processing is further processed by doxygen, so you -# can mix doxygen, HTML, and XML commands with Markdown formatting. -# Disable only in case of backward compatibilities issues. - -MARKDOWN_SUPPORT = YES - -# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want -# to include (a tag file for) the STL sources as input, then you should -# set this tag to YES in order to let doxygen match functions declarations and -# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. -# func(std::string) {}). This also makes the inheritance and collaboration -# diagrams that involve STL classes more complete and accurate. - -BUILTIN_STL_SUPPORT = NO - -# If you use Microsoft's C++/CLI language, you should set this option to YES to -# enable parsing support. - -CPP_CLI_SUPPORT = NO - -# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. -# Doxygen will parse them like normal C++ but will assume all classes use public -# instead of private inheritance when no explicit protection keyword is present. - -SIP_SUPPORT = NO - -# For Microsoft's IDL there are propget and propput attributes to indicate getter -# and setter methods for a property. Setting this option to YES (the default) -# will make doxygen replace the get and set methods by a property in the -# documentation. This will only work if the methods are indeed getting or -# setting a simple type. If this is not the case, or you want to show the -# methods anyway, you should set this option to NO. - -IDL_PROPERTY_SUPPORT = YES - -# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC -# tag is set to YES, then doxygen will reuse the documentation of the first -# member in the group (if any) for the other members of the group. By default -# all members of a group must be documented explicitly. - -DISTRIBUTE_GROUP_DOC = NO - -# Set the SUBGROUPING tag to YES (the default) to allow class member groups of -# the same type (for instance a group of public functions) to be put as a -# subgroup of that type (e.g. under the Public Functions section). Set it to -# NO to prevent subgrouping. Alternatively, this can be done per class using -# the \nosubgrouping command. - -SUBGROUPING = YES - -# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and -# unions are shown inside the group in which they are included (e.g. using -# @ingroup) instead of on a separate page (for HTML and Man pages) or -# section (for LaTeX and RTF). - -INLINE_GROUPED_CLASSES = NO - -# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and -# unions with only public data fields will be shown inline in the documentation -# of the scope in which they are defined (i.e. file, namespace, or group -# documentation), provided this scope is documented. If set to NO (the default), -# structs, classes, and unions are shown on a separate page (for HTML and Man -# pages) or section (for LaTeX and RTF). - -INLINE_SIMPLE_STRUCTS = NO - -# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum -# is documented as struct, union, or enum with the name of the typedef. So -# typedef struct TypeS {} TypeT, will appear in the documentation as a struct -# with name TypeT. When disabled the typedef will appear as a member of a file, -# namespace, or class. And the struct will be named TypeS. This can typically -# be useful for C code in case the coding convention dictates that all compound -# types are typedef'ed and only the typedef is referenced, never the tag name. - -TYPEDEF_HIDES_STRUCT = NO - -# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to -# determine which symbols to keep in memory and which to flush to disk. -# When the cache is full, less often used symbols will be written to disk. -# For small to medium size projects (<1000 input files) the default value is -# probably good enough. For larger projects a too small cache size can cause -# doxygen to be busy swapping symbols to and from disk most of the time -# causing a significant performance penalty. -# If the system has enough physical memory increasing the cache will improve the -# performance by keeping more symbols in memory. Note that the value works on -# a logarithmic scale so increasing the size by one will roughly double the -# memory usage. The cache size is given by this formula: -# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, -# corresponding to a cache size of 2^16 = 65536 symbols. - -SYMBOL_CACHE_SIZE = 0 - -# Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be -# set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given -# their name and scope. Since this can be an expensive process and often the -# same symbol appear multiple times in the code, doxygen keeps a cache of -# pre-resolved symbols. If the cache is too small doxygen will become slower. -# If the cache is too large, memory is wasted. The cache size is given by this -# formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0, -# corresponding to a cache size of 2^16 = 65536 symbols. - -LOOKUP_CACHE_SIZE = 0 - -#--------------------------------------------------------------------------- -# Build related configuration options -#--------------------------------------------------------------------------- - -# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in -# documentation are documented, even if no documentation was available. -# Private class members and static file members will be hidden unless -# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES - -EXTRACT_ALL = NO - -# If the EXTRACT_PRIVATE tag is set to YES all private members of a class -# will be included in the documentation. - -EXTRACT_PRIVATE = NO - -# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal -# scope will be included in the documentation. - -EXTRACT_PACKAGE = NO - -# If the EXTRACT_STATIC tag is set to YES all static members of a file -# will be included in the documentation. - -EXTRACT_STATIC = NO - -# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) -# defined locally in source files will be included in the documentation. -# If set to NO only classes defined in header files are included. - -EXTRACT_LOCAL_CLASSES = YES - -# This flag is only useful for Objective-C code. When set to YES local -# methods, which are defined in the implementation section but not in -# the interface are included in the documentation. -# If set to NO (the default) only methods in the interface are included. - -EXTRACT_LOCAL_METHODS = NO - -# If this flag is set to YES, the members of anonymous namespaces will be -# extracted and appear in the documentation as a namespace called -# 'anonymous_namespace{file}', where file will be replaced with the base -# name of the file that contains the anonymous namespace. By default -# anonymous namespaces are hidden. - -EXTRACT_ANON_NSPACES = NO - -# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all -# undocumented members of documented classes, files or namespaces. -# If set to NO (the default) these members will be included in the -# various overviews, but no documentation section is generated. -# This option has no effect if EXTRACT_ALL is enabled. - -HIDE_UNDOC_MEMBERS = NO - -# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all -# undocumented classes that are normally visible in the class hierarchy. -# If set to NO (the default) these classes will be included in the various -# overviews. This option has no effect if EXTRACT_ALL is enabled. - -HIDE_UNDOC_CLASSES = NO - -# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all -# friend (class|struct|union) declarations. -# If set to NO (the default) these declarations will be included in the -# documentation. - -HIDE_FRIEND_COMPOUNDS = NO - -# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any -# documentation blocks found inside the body of a function. -# If set to NO (the default) these blocks will be appended to the -# function's detailed documentation block. - -HIDE_IN_BODY_DOCS = NO - -# The INTERNAL_DOCS tag determines if documentation -# that is typed after a \internal command is included. If the tag is set -# to NO (the default) then the documentation will be excluded. -# Set it to YES to include the internal documentation. - -INTERNAL_DOCS = NO - -# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate -# file names in lower-case letters. If set to YES upper-case letters are also -# allowed. This is useful if you have classes or files whose names only differ -# in case and if your file system supports case sensitive file names. Windows -# and Mac users are advised to set this option to NO. - -CASE_SENSE_NAMES = NO - -# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen -# will show members with their full class and namespace scopes in the -# documentation. If set to YES the scope will be hidden. - -HIDE_SCOPE_NAMES = NO - -# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen -# will put a list of the files that are included by a file in the documentation -# of that file. - -SHOW_INCLUDE_FILES = YES - -# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen -# will list include files with double quotes in the documentation -# rather than with sharp brackets. - -FORCE_LOCAL_INCLUDES = NO - -# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] -# is inserted in the documentation for inline members. - -INLINE_INFO = YES - -# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen -# will sort the (detailed) documentation of file and class members -# alphabetically by member name. If set to NO the members will appear in -# declaration order. - -SORT_MEMBER_DOCS = YES - -# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the -# brief documentation of file, namespace and class members alphabetically -# by member name. If set to NO (the default) the members will appear in -# declaration order. - -SORT_BRIEF_DOCS = NO - -# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen -# will sort the (brief and detailed) documentation of class members so that -# constructors and destructors are listed first. If set to NO (the default) -# the constructors will appear in the respective orders defined by -# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. -# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO -# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. - -SORT_MEMBERS_CTORS_1ST = NO - -# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the -# hierarchy of group names into alphabetical order. If set to NO (the default) -# the group names will appear in their defined order. - -SORT_GROUP_NAMES = NO - -# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be -# sorted by fully-qualified names, including namespaces. If set to -# NO (the default), the class list will be sorted only by class name, -# not including the namespace part. -# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. -# Note: This option applies only to the class list, not to the -# alphabetical list. - -SORT_BY_SCOPE_NAME = NO - -# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to -# do proper type resolution of all parameters of a function it will reject a -# match between the prototype and the implementation of a member function even -# if there is only one candidate or it is obvious which candidate to choose -# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen -# will still accept a match between prototype and implementation in such cases. - -STRICT_PROTO_MATCHING = NO - -# The GENERATE_TODOLIST tag can be used to enable (YES) or -# disable (NO) the todo list. This list is created by putting \todo -# commands in the documentation. - -GENERATE_TODOLIST = YES - -# The GENERATE_TESTLIST tag can be used to enable (YES) or -# disable (NO) the test list. This list is created by putting \test -# commands in the documentation. - -GENERATE_TESTLIST = YES - -# The GENERATE_BUGLIST tag can be used to enable (YES) or -# disable (NO) the bug list. This list is created by putting \bug -# commands in the documentation. - -GENERATE_BUGLIST = YES - -# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or -# disable (NO) the deprecated list. This list is created by putting -# \deprecated commands in the documentation. - -GENERATE_DEPRECATEDLIST= YES - -# The ENABLED_SECTIONS tag can be used to enable conditional -# documentation sections, marked by \if sectionname ... \endif. - -ENABLED_SECTIONS = - -# The MAX_INITIALIZER_LINES tag determines the maximum number of lines -# the initial value of a variable or macro consists of for it to appear in -# the documentation. If the initializer consists of more lines than specified -# here it will be hidden. Use a value of 0 to hide initializers completely. -# The appearance of the initializer of individual variables and macros in the -# documentation can be controlled using \showinitializer or \hideinitializer -# command in the documentation regardless of this setting. - -MAX_INITIALIZER_LINES = 30 - -# Set the SHOW_USED_FILES tag to NO to disable the list of files generated -# at the bottom of the documentation of classes and structs. If set to YES the -# list will mention the files that were used to generate the documentation. - -SHOW_USED_FILES = YES - -# Set the SHOW_FILES tag to NO to disable the generation of the Files page. -# This will remove the Files entry from the Quick Index and from the -# Folder Tree View (if specified). The default is YES. - -SHOW_FILES = YES - -# Set the SHOW_NAMESPACES tag to NO to disable the generation of the -# Namespaces page. This will remove the Namespaces entry from the Quick Index -# and from the Folder Tree View (if specified). The default is YES. - -SHOW_NAMESPACES = YES - -# The FILE_VERSION_FILTER tag can be used to specify a program or script that -# doxygen should invoke to get the current version for each file (typically from -# the version control system). Doxygen will invoke the program by executing (via -# popen()) the command , where is the value of -# the FILE_VERSION_FILTER tag, and is the name of an input file -# provided by doxygen. Whatever the program writes to standard output -# is used as the file version. See the manual for examples. - -FILE_VERSION_FILTER = - -# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed -# by doxygen. The layout file controls the global structure of the generated -# output files in an output format independent way. To create the layout file -# that represents doxygen's defaults, run doxygen with the -l option. -# You can optionally specify a file name after the option, if omitted -# DoxygenLayout.xml will be used as the name of the layout file. - -LAYOUT_FILE = - -# The CITE_BIB_FILES tag can be used to specify one or more bib files -# containing the references data. This must be a list of .bib files. The -# .bib extension is automatically appended if omitted. Using this command -# requires the bibtex tool to be installed. See also -# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style -# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this -# feature you need bibtex and perl available in the search path. - -CITE_BIB_FILES = - -#--------------------------------------------------------------------------- -# configuration options related to warning and progress messages -#--------------------------------------------------------------------------- - -# The QUIET tag can be used to turn on/off the messages that are generated -# by doxygen. Possible values are YES and NO. If left blank NO is used. - -QUIET = NO - -# The WARNINGS tag can be used to turn on/off the warning messages that are -# generated by doxygen. Possible values are YES and NO. If left blank -# NO is used. - -WARNINGS = YES - -# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings -# for undocumented members. If EXTRACT_ALL is set to YES then this flag will -# automatically be disabled. - -WARN_IF_UNDOCUMENTED = YES - -# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for -# potential errors in the documentation, such as not documenting some -# parameters in a documented function, or documenting parameters that -# don't exist or using markup commands wrongly. - -WARN_IF_DOC_ERROR = YES - -# The WARN_NO_PARAMDOC option can be enabled to get warnings for -# functions that are documented, but have no documentation for their parameters -# or return value. If set to NO (the default) doxygen will only warn about -# wrong or incomplete parameter documentation, but not about the absence of -# documentation. - -WARN_NO_PARAMDOC = NO - -# The WARN_FORMAT tag determines the format of the warning messages that -# doxygen can produce. The string should contain the $file, $line, and $text -# tags, which will be replaced by the file and line number from which the -# warning originated and the warning text. Optionally the format may contain -# $version, which will be replaced by the version of the file (if it could -# be obtained via FILE_VERSION_FILTER) - -WARN_FORMAT = "$file:$line: $text" - -# The WARN_LOGFILE tag can be used to specify a file to which warning -# and error messages should be written. If left blank the output is written -# to stderr. - -WARN_LOGFILE = - -#--------------------------------------------------------------------------- -# configuration options related to the input files -#--------------------------------------------------------------------------- - -# The INPUT tag can be used to specify the files and/or directories that contain -# documented source files. You may enter file names like "myfile.cpp" or -# directories like "/usr/src/myproject". Separate the files or directories -# with spaces. - -INPUT = ../ - -# This tag can be used to specify the character encoding of the source files -# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is -# also the default input encoding. Doxygen uses libiconv (or the iconv built -# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for -# the list of possible encodings. - -INPUT_ENCODING = UTF-8 - -# If the value of the INPUT tag contains directories, you can use the -# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left -# blank the following patterns are tested: -# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh -# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py -# *.f90 *.f *.for *.vhd *.vhdl - -FILE_PATTERNS = *.c \ - *.cc \ - *.cxx \ - *.cpp \ - *.c++ \ - *.d \ - *.java \ - *.ii \ - *.ixx \ - *.ipp \ - *.i++ \ - *.inl \ - *.h \ - *.hh \ - *.hxx \ - *.hpp \ - *.h++ \ - *.idl \ - *.odl \ - *.cs \ - *.php \ - *.php3 \ - *.inc \ - *.m \ - *.markdown \ - *.md \ - *.mm \ - *.dox \ - *.py \ - *.f90 \ - *.f \ - *.for \ - *.vhd \ - *.vhdl - -# The RECURSIVE tag can be used to turn specify whether or not subdirectories -# should be searched for input files as well. Possible values are YES and NO. -# If left blank NO is used. - -RECURSIVE = YES - -# The EXCLUDE tag can be used to specify files and/or directories that should be -# excluded from the INPUT source files. This way you can easily exclude a -# subdirectory from a directory tree whose root is specified with the INPUT tag. -# Note that relative paths are relative to the directory from which doxygen is -# run. - -EXCLUDE = - -# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or -# directories that are symbolic links (a Unix file system feature) are excluded -# from the input. - -EXCLUDE_SYMLINKS = NO - -# If the value of the INPUT tag contains directories, you can use the -# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude -# certain files from those directories. Note that the wildcards are matched -# against the file with absolute path, so to exclude all test directories -# for example use the pattern */test/* - -EXCLUDE_PATTERNS = - -# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names -# (namespaces, classes, functions, etc.) that should be excluded from the -# output. The symbol name can be a fully qualified name, a word, or if the -# wildcard * is used, a substring. Examples: ANamespace, AClass, -# AClass::ANamespace, ANamespace::*Test - -EXCLUDE_SYMBOLS = - -# The EXAMPLE_PATH tag can be used to specify one or more files or -# directories that contain example code fragments that are included (see -# the \include command). - -EXAMPLE_PATH = - -# If the value of the EXAMPLE_PATH tag contains directories, you can use the -# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left -# blank all files are included. - -EXAMPLE_PATTERNS = * - -# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be -# searched for input files to be used with the \include or \dontinclude -# commands irrespective of the value of the RECURSIVE tag. -# Possible values are YES and NO. If left blank NO is used. - -EXAMPLE_RECURSIVE = NO - -# The IMAGE_PATH tag can be used to specify one or more files or -# directories that contain image that are included in the documentation (see -# the \image command). - -IMAGE_PATH = - -# The INPUT_FILTER tag can be used to specify a program that doxygen should -# invoke to filter for each input file. Doxygen will invoke the filter program -# by executing (via popen()) the command , where -# is the value of the INPUT_FILTER tag, and is the name of an -# input file. Doxygen will then use the output that the filter program writes -# to standard output. If FILTER_PATTERNS is specified, this tag will be -# ignored. - -INPUT_FILTER = - -# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern -# basis. Doxygen will compare the file name with each pattern and apply the -# filter if there is a match. The filters are a list of the form: -# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further -# info on how filters are used. If FILTER_PATTERNS is empty or if -# non of the patterns match the file name, INPUT_FILTER is applied. - -FILTER_PATTERNS = - -# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using -# INPUT_FILTER) will be used to filter the input files when producing source -# files to browse (i.e. when SOURCE_BROWSER is set to YES). - -FILTER_SOURCE_FILES = NO - -# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file -# pattern. A pattern will override the setting for FILTER_PATTERN (if any) -# and it is also possible to disable source filtering for a specific pattern -# using *.ext= (so without naming a filter). This option only has effect when -# FILTER_SOURCE_FILES is enabled. - -FILTER_SOURCE_PATTERNS = - -#--------------------------------------------------------------------------- -# configuration options related to source browsing -#--------------------------------------------------------------------------- - -# If the SOURCE_BROWSER tag is set to YES then a list of source files will -# be generated. Documented entities will be cross-referenced with these sources. -# Note: To get rid of all source code in the generated output, make sure also -# VERBATIM_HEADERS is set to NO. - -SOURCE_BROWSER = NO - -# Setting the INLINE_SOURCES tag to YES will include the body -# of functions and classes directly in the documentation. - -INLINE_SOURCES = NO - -# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct -# doxygen to hide any special comment blocks from generated source code -# fragments. Normal C, C++ and Fortran comments will always remain visible. - -STRIP_CODE_COMMENTS = YES - -# If the REFERENCED_BY_RELATION tag is set to YES -# then for each documented function all documented -# functions referencing it will be listed. - -REFERENCED_BY_RELATION = NO - -# If the REFERENCES_RELATION tag is set to YES -# then for each documented function all documented entities -# called/used by that function will be listed. - -REFERENCES_RELATION = NO - -# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) -# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from -# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will -# link to the source code. Otherwise they will link to the documentation. - -REFERENCES_LINK_SOURCE = YES - -# If the USE_HTAGS tag is set to YES then the references to source code -# will point to the HTML generated by the htags(1) tool instead of doxygen -# built-in source browser. The htags tool is part of GNU's global source -# tagging system (see http://www.gnu.org/software/global/global.html). You -# will need version 4.8.6 or higher. - -USE_HTAGS = NO - -# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen -# will generate a verbatim copy of the header file for each class for -# which an include is specified. Set to NO to disable this. - -VERBATIM_HEADERS = YES - -#--------------------------------------------------------------------------- -# configuration options related to the alphabetical class index -#--------------------------------------------------------------------------- - -# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index -# of all compounds will be generated. Enable this if the project -# contains a lot of classes, structs, unions or interfaces. - -ALPHABETICAL_INDEX = YES - -# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then -# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns -# in which this list will be split (can be a number in the range [1..20]) - -COLS_IN_ALPHA_INDEX = 5 - -# In case all classes in a project start with a common prefix, all -# classes will be put under the same header in the alphabetical index. -# The IGNORE_PREFIX tag can be used to specify one or more prefixes that -# should be ignored while generating the index headers. - -IGNORE_PREFIX = - -#--------------------------------------------------------------------------- -# configuration options related to the HTML output -#--------------------------------------------------------------------------- - -# If the GENERATE_HTML tag is set to YES (the default) Doxygen will -# generate HTML output. - -GENERATE_HTML = YES - -# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `html' will be used as the default path. - -HTML_OUTPUT = html - -# The HTML_FILE_EXTENSION tag can be used to specify the file extension for -# each generated HTML page (for example: .htm,.php,.asp). If it is left blank -# doxygen will generate files with .html extension. - -HTML_FILE_EXTENSION = .html - -# The HTML_HEADER tag can be used to specify a personal HTML header for -# each generated HTML page. If it is left blank doxygen will generate a -# standard header. Note that when using a custom header you are responsible -# for the proper inclusion of any scripts and style sheets that doxygen -# needs, which is dependent on the configuration options used. -# It is advised to generate a default header using "doxygen -w html -# header.html footer.html stylesheet.css YourConfigFile" and then modify -# that header. Note that the header is subject to change so you typically -# have to redo this when upgrading to a newer version of doxygen or when -# changing the value of configuration settings such as GENERATE_TREEVIEW! - -HTML_HEADER = - -# The HTML_FOOTER tag can be used to specify a personal HTML footer for -# each generated HTML page. If it is left blank doxygen will generate a -# standard footer. - -HTML_FOOTER = - -# The HTML_STYLESHEET tag can be used to specify a user-defined cascading -# style sheet that is used by each HTML page. It can be used to -# fine-tune the look of the HTML output. If the tag is left blank doxygen -# will generate a default style sheet. Note that doxygen will try to copy -# the style sheet file to the HTML output directory, so don't put your own -# style sheet in the HTML output directory as well, or it will be erased! - -HTML_STYLESHEET = - -# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or -# other source files which should be copied to the HTML output directory. Note -# that these files will be copied to the base HTML output directory. Use the -# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these -# files. In the HTML_STYLESHEET file, use the file name only. Also note that -# the files will be copied as-is; there are no commands or markers available. - -HTML_EXTRA_FILES = - -# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. -# Doxygen will adjust the colors in the style sheet and background images -# according to this color. Hue is specified as an angle on a colorwheel, -# see http://en.wikipedia.org/wiki/Hue for more information. -# For instance the value 0 represents red, 60 is yellow, 120 is green, -# 180 is cyan, 240 is blue, 300 purple, and 360 is red again. -# The allowed range is 0 to 359. - -HTML_COLORSTYLE_HUE = 220 - -# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of -# the colors in the HTML output. For a value of 0 the output will use -# grayscales only. A value of 255 will produce the most vivid colors. - -HTML_COLORSTYLE_SAT = 100 - -# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to -# the luminance component of the colors in the HTML output. Values below -# 100 gradually make the output lighter, whereas values above 100 make -# the output darker. The value divided by 100 is the actual gamma applied, -# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, -# and 100 does not change the gamma. - -HTML_COLORSTYLE_GAMMA = 80 - -# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML -# page will contain the date and time when the page was generated. Setting -# this to NO can help when comparing the output of multiple runs. - -HTML_TIMESTAMP = YES - -# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML -# documentation will contain sections that can be hidden and shown after the -# page has loaded. - -HTML_DYNAMIC_SECTIONS = NO - -# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of -# entries shown in the various tree structured indices initially; the user -# can expand and collapse entries dynamically later on. Doxygen will expand -# the tree to such a level that at most the specified number of entries are -# visible (unless a fully collapsed tree already exceeds this amount). -# So setting the number of entries 1 will produce a full collapsed tree by -# default. 0 is a special value representing an infinite number of entries -# and will result in a full expanded tree by default. - -HTML_INDEX_NUM_ENTRIES = 100 - -# If the GENERATE_DOCSET tag is set to YES, additional index files -# will be generated that can be used as input for Apple's Xcode 3 -# integrated development environment, introduced with OSX 10.5 (Leopard). -# To create a documentation set, doxygen will generate a Makefile in the -# HTML output directory. Running make will produce the docset in that -# directory and running "make install" will install the docset in -# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find -# it at startup. -# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html -# for more information. - -GENERATE_DOCSET = NO - -# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the -# feed. A documentation feed provides an umbrella under which multiple -# documentation sets from a single provider (such as a company or product suite) -# can be grouped. - -DOCSET_FEEDNAME = "Doxygen generated docs" - -# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that -# should uniquely identify the documentation set bundle. This should be a -# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen -# will append .docset to the name. - -DOCSET_BUNDLE_ID = org.doxygen.Project - -# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify -# the documentation publisher. This should be a reverse domain-name style -# string, e.g. com.mycompany.MyDocSet.documentation. - -DOCSET_PUBLISHER_ID = org.doxygen.Publisher - -# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. - -DOCSET_PUBLISHER_NAME = Publisher - -# If the GENERATE_HTMLHELP tag is set to YES, additional index files -# will be generated that can be used as input for tools like the -# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) -# of the generated HTML documentation. - -GENERATE_HTMLHELP = NO - -# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can -# be used to specify the file name of the resulting .chm file. You -# can add a path in front of the file if the result should not be -# written to the html output directory. - -CHM_FILE = - -# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can -# be used to specify the location (absolute path including file name) of -# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run -# the HTML help compiler on the generated index.hhp. - -HHC_LOCATION = - -# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag -# controls if a separate .chi index file is generated (YES) or that -# it should be included in the master .chm file (NO). - -GENERATE_CHI = NO - -# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING -# is used to encode HtmlHelp index (hhk), content (hhc) and project file -# content. - -CHM_INDEX_ENCODING = - -# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag -# controls whether a binary table of contents is generated (YES) or a -# normal table of contents (NO) in the .chm file. - -BINARY_TOC = NO - -# The TOC_EXPAND flag can be set to YES to add extra items for group members -# to the contents of the HTML help documentation and to the tree view. - -TOC_EXPAND = NO - -# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and -# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated -# that can be used as input for Qt's qhelpgenerator to generate a -# Qt Compressed Help (.qch) of the generated HTML documentation. - -GENERATE_QHP = NO - -# If the QHG_LOCATION tag is specified, the QCH_FILE tag can -# be used to specify the file name of the resulting .qch file. -# The path specified is relative to the HTML output folder. - -QCH_FILE = - -# The QHP_NAMESPACE tag specifies the namespace to use when generating -# Qt Help Project output. For more information please see -# http://doc.trolltech.com/qthelpproject.html#namespace - -QHP_NAMESPACE = org.doxygen.Project - -# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating -# Qt Help Project output. For more information please see -# http://doc.trolltech.com/qthelpproject.html#virtual-folders - -QHP_VIRTUAL_FOLDER = doc - -# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to -# add. For more information please see -# http://doc.trolltech.com/qthelpproject.html#custom-filters - -QHP_CUST_FILTER_NAME = - -# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the -# custom filter to add. For more information please see -# -# Qt Help Project / Custom Filters. - -QHP_CUST_FILTER_ATTRS = - -# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this -# project's -# filter section matches. -# -# Qt Help Project / Filter Attributes. - -QHP_SECT_FILTER_ATTRS = - -# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can -# be used to specify the location of Qt's qhelpgenerator. -# If non-empty doxygen will try to run qhelpgenerator on the generated -# .qhp file. - -QHG_LOCATION = - -# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files -# will be generated, which together with the HTML files, form an Eclipse help -# plugin. To install this plugin and make it available under the help contents -# menu in Eclipse, the contents of the directory containing the HTML and XML -# files needs to be copied into the plugins directory of eclipse. The name of -# the directory within the plugins directory should be the same as -# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before -# the help appears. - -GENERATE_ECLIPSEHELP = NO - -# A unique identifier for the eclipse help plugin. When installing the plugin -# the directory name containing the HTML and XML files should also have -# this name. - -ECLIPSE_DOC_ID = org.doxygen.Project - -# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) -# at top of each HTML page. The value NO (the default) enables the index and -# the value YES disables it. Since the tabs have the same information as the -# navigation tree you can set this option to NO if you already set -# GENERATE_TREEVIEW to YES. - -DISABLE_INDEX = NO - -# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index -# structure should be generated to display hierarchical information. -# If the tag value is set to YES, a side panel will be generated -# containing a tree-like index structure (just like the one that -# is generated for HTML Help). For this to work a browser that supports -# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). -# Windows users are probably better off using the HTML help feature. -# Since the tree basically has the same information as the tab index you -# could consider to set DISABLE_INDEX to NO when enabling this option. - -GENERATE_TREEVIEW = NO - -# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values -# (range [0,1..20]) that doxygen will group on one line in the generated HTML -# documentation. Note that a value of 0 will completely suppress the enum -# values from appearing in the overview section. - -ENUM_VALUES_PER_LINE = 4 - -# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be -# used to set the initial width (in pixels) of the frame in which the tree -# is shown. - -TREEVIEW_WIDTH = 250 - -# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open -# links to external symbols imported via tag files in a separate window. - -EXT_LINKS_IN_WINDOW = NO - -# Use this tag to change the font size of Latex formulas included -# as images in the HTML documentation. The default is 10. Note that -# when you change the font size after a successful doxygen run you need -# to manually remove any form_*.png images from the HTML output directory -# to force them to be regenerated. - -FORMULA_FONTSIZE = 10 - -# Use the FORMULA_TRANPARENT tag to determine whether or not the images -# generated for formulas are transparent PNGs. Transparent PNGs are -# not supported properly for IE 6.0, but are supported on all modern browsers. -# Note that when changing this option you need to delete any form_*.png files -# in the HTML output before the changes have effect. - -FORMULA_TRANSPARENT = YES - -# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax -# (see http://www.mathjax.org) which uses client side Javascript for the -# rendering instead of using prerendered bitmaps. Use this if you do not -# have LaTeX installed or if you want to formulas look prettier in the HTML -# output. When enabled you may also need to install MathJax separately and -# configure the path to it using the MATHJAX_RELPATH option. - -USE_MATHJAX = NO - -# When MathJax is enabled you need to specify the location relative to the -# HTML output directory using the MATHJAX_RELPATH option. The destination -# directory should contain the MathJax.js script. For instance, if the mathjax -# directory is located at the same level as the HTML output directory, then -# MATHJAX_RELPATH should be ../mathjax. The default value points to -# the MathJax Content Delivery Network so you can quickly see the result without -# installing MathJax. However, it is strongly recommended to install a local -# copy of MathJax from http://www.mathjax.org before deployment. - -MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest - -# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension -# names that should be enabled during MathJax rendering. - -MATHJAX_EXTENSIONS = - -# When the SEARCHENGINE tag is enabled doxygen will generate a search box -# for the HTML output. The underlying search engine uses javascript -# and DHTML and should work on any modern browser. Note that when using -# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets -# (GENERATE_DOCSET) there is already a search function so this one should -# typically be disabled. For large projects the javascript based search engine -# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. - -SEARCHENGINE = YES - -# When the SERVER_BASED_SEARCH tag is enabled the search engine will be -# implemented using a PHP enabled web server instead of at the web client -# using Javascript. Doxygen will generate the search PHP script and index -# file to put on the web server. The advantage of the server -# based approach is that it scales better to large projects and allows -# full text search. The disadvantages are that it is more difficult to setup -# and does not have live searching capabilities. - -SERVER_BASED_SEARCH = NO - -#--------------------------------------------------------------------------- -# configuration options related to the LaTeX output -#--------------------------------------------------------------------------- - -# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will -# generate Latex output. - -GENERATE_LATEX = YES - -# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `latex' will be used as the default path. - -LATEX_OUTPUT = latex - -# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be -# invoked. If left blank `latex' will be used as the default command name. -# Note that when enabling USE_PDFLATEX this option is only used for -# generating bitmaps for formulas in the HTML output, but not in the -# Makefile that is written to the output directory. - -LATEX_CMD_NAME = latex - -# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to -# generate index for LaTeX. If left blank `makeindex' will be used as the -# default command name. - -MAKEINDEX_CMD_NAME = makeindex - -# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact -# LaTeX documents. This may be useful for small projects and may help to -# save some trees in general. - -COMPACT_LATEX = NO - -# The PAPER_TYPE tag can be used to set the paper type that is used -# by the printer. Possible values are: a4, letter, legal and -# executive. If left blank a4wide will be used. - -PAPER_TYPE = a4 - -# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX -# packages that should be included in the LaTeX output. - -EXTRA_PACKAGES = - -# The LATEX_HEADER tag can be used to specify a personal LaTeX header for -# the generated latex document. The header should contain everything until -# the first chapter. If it is left blank doxygen will generate a -# standard header. Notice: only use this tag if you know what you are doing! - -LATEX_HEADER = - -# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for -# the generated latex document. The footer should contain everything after -# the last chapter. If it is left blank doxygen will generate a -# standard footer. Notice: only use this tag if you know what you are doing! - -LATEX_FOOTER = - -# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated -# is prepared for conversion to pdf (using ps2pdf). The pdf file will -# contain links (just like the HTML output) instead of page references -# This makes the output suitable for online browsing using a pdf viewer. - -PDF_HYPERLINKS = YES - -# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of -# plain latex in the generated Makefile. Set this option to YES to get a -# higher quality PDF documentation. - -USE_PDFLATEX = YES - -# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. -# command to the generated LaTeX files. This will instruct LaTeX to keep -# running if errors occur, instead of asking the user for help. -# This option is also used when generating formulas in HTML. - -LATEX_BATCHMODE = NO - -# If LATEX_HIDE_INDICES is set to YES then doxygen will not -# include the index chapters (such as File Index, Compound Index, etc.) -# in the output. - -LATEX_HIDE_INDICES = NO - -# If LATEX_SOURCE_CODE is set to YES then doxygen will include -# source code with syntax highlighting in the LaTeX output. -# Note that which sources are shown also depends on other settings -# such as SOURCE_BROWSER. - -LATEX_SOURCE_CODE = NO - -# The LATEX_BIB_STYLE tag can be used to specify the style to use for the -# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See -# http://en.wikipedia.org/wiki/BibTeX for more info. - -LATEX_BIB_STYLE = plain - -#--------------------------------------------------------------------------- -# configuration options related to the RTF output -#--------------------------------------------------------------------------- - -# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output -# The RTF output is optimized for Word 97 and may not look very pretty with -# other RTF readers or editors. - -GENERATE_RTF = NO - -# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `rtf' will be used as the default path. - -RTF_OUTPUT = rtf - -# If the COMPACT_RTF tag is set to YES Doxygen generates more compact -# RTF documents. This may be useful for small projects and may help to -# save some trees in general. - -COMPACT_RTF = NO - -# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated -# will contain hyperlink fields. The RTF file will -# contain links (just like the HTML output) instead of page references. -# This makes the output suitable for online browsing using WORD or other -# programs which support those fields. -# Note: wordpad (write) and others do not support links. - -RTF_HYPERLINKS = NO - -# Load style sheet definitions from file. Syntax is similar to doxygen's -# config file, i.e. a series of assignments. You only have to provide -# replacements, missing definitions are set to their default value. - -RTF_STYLESHEET_FILE = - -# Set optional variables used in the generation of an rtf document. -# Syntax is similar to doxygen's config file. - -RTF_EXTENSIONS_FILE = - -#--------------------------------------------------------------------------- -# configuration options related to the man page output -#--------------------------------------------------------------------------- - -# If the GENERATE_MAN tag is set to YES (the default) Doxygen will -# generate man pages - -GENERATE_MAN = NO - -# The MAN_OUTPUT tag is used to specify where the man pages will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `man' will be used as the default path. - -MAN_OUTPUT = man - -# The MAN_EXTENSION tag determines the extension that is added to -# the generated man pages (default is the subroutine's section .3) - -MAN_EXTENSION = .3 - -# If the MAN_LINKS tag is set to YES and Doxygen generates man output, -# then it will generate one additional man file for each entity -# documented in the real man page(s). These additional files -# only source the real man page, but without them the man command -# would be unable to find the correct page. The default is NO. - -MAN_LINKS = NO - -#--------------------------------------------------------------------------- -# configuration options related to the XML output -#--------------------------------------------------------------------------- - -# If the GENERATE_XML tag is set to YES Doxygen will -# generate an XML file that captures the structure of -# the code including all documentation. - -GENERATE_XML = NO - -# The XML_OUTPUT tag is used to specify where the XML pages will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `xml' will be used as the default path. - -XML_OUTPUT = xml - -# The XML_SCHEMA tag can be used to specify an XML schema, -# which can be used by a validating XML parser to check the -# syntax of the XML files. - -XML_SCHEMA = - -# The XML_DTD tag can be used to specify an XML DTD, -# which can be used by a validating XML parser to check the -# syntax of the XML files. - -XML_DTD = - -# If the XML_PROGRAMLISTING tag is set to YES Doxygen will -# dump the program listings (including syntax highlighting -# and cross-referencing information) to the XML output. Note that -# enabling this will significantly increase the size of the XML output. - -XML_PROGRAMLISTING = YES - -#--------------------------------------------------------------------------- -# configuration options for the AutoGen Definitions output -#--------------------------------------------------------------------------- - -# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will -# generate an AutoGen Definitions (see autogen.sf.net) file -# that captures the structure of the code including all -# documentation. Note that this feature is still experimental -# and incomplete at the moment. - -GENERATE_AUTOGEN_DEF = NO - -#--------------------------------------------------------------------------- -# configuration options related to the Perl module output -#--------------------------------------------------------------------------- - -# If the GENERATE_PERLMOD tag is set to YES Doxygen will -# generate a Perl module file that captures the structure of -# the code including all documentation. Note that this -# feature is still experimental and incomplete at the -# moment. - -GENERATE_PERLMOD = NO - -# If the PERLMOD_LATEX tag is set to YES Doxygen will generate -# the necessary Makefile rules, Perl scripts and LaTeX code to be able -# to generate PDF and DVI output from the Perl module output. - -PERLMOD_LATEX = NO - -# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be -# nicely formatted so it can be parsed by a human reader. This is useful -# if you want to understand what is going on. On the other hand, if this -# tag is set to NO the size of the Perl module output will be much smaller -# and Perl will parse it just the same. - -PERLMOD_PRETTY = YES - -# The names of the make variables in the generated doxyrules.make file -# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. -# This is useful so different doxyrules.make files included by the same -# Makefile don't overwrite each other's variables. - -PERLMOD_MAKEVAR_PREFIX = - -#--------------------------------------------------------------------------- -# Configuration options related to the preprocessor -#--------------------------------------------------------------------------- - -# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will -# evaluate all C-preprocessor directives found in the sources and include -# files. - -ENABLE_PREPROCESSING = YES - -# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro -# names in the source code. If set to NO (the default) only conditional -# compilation will be performed. Macro expansion can be done in a controlled -# way by setting EXPAND_ONLY_PREDEF to YES. - -MACRO_EXPANSION = NO - -# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES -# then the macro expansion is limited to the macros specified with the -# PREDEFINED and EXPAND_AS_DEFINED tags. - -EXPAND_ONLY_PREDEF = NO - -# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files -# pointed to by INCLUDE_PATH will be searched when a #include is found. - -SEARCH_INCLUDES = YES - -# The INCLUDE_PATH tag can be used to specify one or more directories that -# contain include files that are not input files but should be processed by -# the preprocessor. - -INCLUDE_PATH = - -# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard -# patterns (like *.h and *.hpp) to filter out the header-files in the -# directories. If left blank, the patterns specified with FILE_PATTERNS will -# be used. - -INCLUDE_FILE_PATTERNS = - -# The PREDEFINED tag can be used to specify one or more macro names that -# are defined before the preprocessor is started (similar to the -D option of -# gcc). The argument of the tag is a list of macros of the form: name -# or name=definition (no spaces). If the definition and the = are -# omitted =1 is assumed. To prevent a macro definition from being -# undefined via #undef or recursively expanded use the := operator -# instead of the = operator. - -PREDEFINED = - -# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then -# this tag can be used to specify a list of macro names that should be expanded. -# The macro definition that is found in the sources will be used. -# Use the PREDEFINED tag if you want to use a different macro definition that -# overrules the definition found in the source code. - -EXPAND_AS_DEFINED = - -# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then -# doxygen's preprocessor will remove all references to function-like macros -# that are alone on a line, have an all uppercase name, and do not end with a -# semicolon, because these will confuse the parser if not removed. - -SKIP_FUNCTION_MACROS = YES - -#--------------------------------------------------------------------------- -# Configuration::additions related to external references -#--------------------------------------------------------------------------- - -# The TAGFILES option can be used to specify one or more tagfiles. For each -# tag file the location of the external documentation should be added. The -# format of a tag file without this location is as follows: -# TAGFILES = file1 file2 ... -# Adding location for the tag files is done as follows: -# TAGFILES = file1=loc1 "file2 = loc2" ... -# where "loc1" and "loc2" can be relative or absolute paths -# or URLs. Note that each tag file must have a unique name (where the name does -# NOT include the path). If a tag file is not located in the directory in which -# doxygen is run, you must also specify the path to the tagfile here. - -TAGFILES = - -# When a file name is specified after GENERATE_TAGFILE, doxygen will create -# a tag file that is based on the input files it reads. - -GENERATE_TAGFILE = - -# If the ALLEXTERNALS tag is set to YES all external classes will be listed -# in the class index. If set to NO only the inherited external classes -# will be listed. - -ALLEXTERNALS = NO - -# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed -# in the modules index. If set to NO, only the current project's groups will -# be listed. - -EXTERNAL_GROUPS = YES - -# The PERL_PATH should be the absolute path and name of the perl script -# interpreter (i.e. the result of `which perl'). - -PERL_PATH = /usr/bin/perl - -#--------------------------------------------------------------------------- -# Configuration options related to the dot tool -#--------------------------------------------------------------------------- - -# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will -# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base -# or super classes. Setting the tag to NO turns the diagrams off. Note that -# this option also works with HAVE_DOT disabled, but it is recommended to -# install and use dot, since it yields more powerful graphs. - -CLASS_DIAGRAMS = YES - -# You can define message sequence charts within doxygen comments using the \msc -# command. Doxygen will then run the mscgen tool (see -# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the -# documentation. The MSCGEN_PATH tag allows you to specify the directory where -# the mscgen tool resides. If left empty the tool is assumed to be found in the -# default search path. - -MSCGEN_PATH = - -# If set to YES, the inheritance and collaboration graphs will hide -# inheritance and usage relations if the target is undocumented -# or is not a class. - -HIDE_UNDOC_RELATIONS = YES - -# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is -# available from the path. This tool is part of Graphviz, a graph visualization -# toolkit from AT&T and Lucent Bell Labs. The other options in this section -# have no effect if this option is set to NO (the default) - -HAVE_DOT = NO - -# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is -# allowed to run in parallel. When set to 0 (the default) doxygen will -# base this on the number of processors available in the system. You can set it -# explicitly to a value larger than 0 to get control over the balance -# between CPU load and processing speed. - -DOT_NUM_THREADS = 0 - -# By default doxygen will use the Helvetica font for all dot files that -# doxygen generates. When you want a differently looking font you can specify -# the font name using DOT_FONTNAME. You need to make sure dot is able to find -# the font, which can be done by putting it in a standard location or by setting -# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the -# directory containing the font. - -DOT_FONTNAME = Helvetica - -# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. -# The default size is 10pt. - -DOT_FONTSIZE = 10 - -# By default doxygen will tell dot to use the Helvetica font. -# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to -# set the path where dot can find it. - -DOT_FONTPATH = - -# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for each documented class showing the direct and -# indirect inheritance relations. Setting this tag to YES will force the -# CLASS_DIAGRAMS tag to NO. - -CLASS_GRAPH = YES - -# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for each documented class showing the direct and -# indirect implementation dependencies (inheritance, containment, and -# class references variables) of the class with other documented classes. - -COLLABORATION_GRAPH = YES - -# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for groups, showing the direct groups dependencies - -GROUP_GRAPHS = YES - -# If the UML_LOOK tag is set to YES doxygen will generate inheritance and -# collaboration diagrams in a style similar to the OMG's Unified Modeling -# Language. - -UML_LOOK = NO - -# If the UML_LOOK tag is enabled, the fields and methods are shown inside -# the class node. If there are many fields or methods and many nodes the -# graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS -# threshold limits the number of items for each type to make the size more -# managable. Set this to 0 for no limit. Note that the threshold may be -# exceeded by 50% before the limit is enforced. - -UML_LIMIT_NUM_FIELDS = 10 - -# If set to YES, the inheritance and collaboration graphs will show the -# relations between templates and their instances. - -TEMPLATE_RELATIONS = NO - -# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT -# tags are set to YES then doxygen will generate a graph for each documented -# file showing the direct and indirect include dependencies of the file with -# other documented files. - -INCLUDE_GRAPH = YES - -# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and -# HAVE_DOT tags are set to YES then doxygen will generate a graph for each -# documented header file showing the documented files that directly or -# indirectly include this file. - -INCLUDED_BY_GRAPH = YES - -# If the CALL_GRAPH and HAVE_DOT options are set to YES then -# doxygen will generate a call dependency graph for every global function -# or class method. Note that enabling this option will significantly increase -# the time of a run. So in most cases it will be better to enable call graphs -# for selected functions only using the \callgraph command. - -CALL_GRAPH = NO - -# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then -# doxygen will generate a caller dependency graph for every global function -# or class method. Note that enabling this option will significantly increase -# the time of a run. So in most cases it will be better to enable caller -# graphs for selected functions only using the \callergraph command. - -CALLER_GRAPH = NO - -# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen -# will generate a graphical hierarchy of all classes instead of a textual one. - -GRAPHICAL_HIERARCHY = YES - -# If the DIRECTORY_GRAPH and HAVE_DOT tags are set to YES -# then doxygen will show the dependencies a directory has on other directories -# in a graphical way. The dependency relations are determined by the #include -# relations between the files in the directories. - -DIRECTORY_GRAPH = YES - -# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images -# generated by dot. Possible values are svg, png, jpg, or gif. -# If left blank png will be used. If you choose svg you need to set -# HTML_FILE_EXTENSION to xhtml in order to make the SVG files -# visible in IE 9+ (other browsers do not have this requirement). - -DOT_IMAGE_FORMAT = png - -# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to -# enable generation of interactive SVG images that allow zooming and panning. -# Note that this requires a modern browser other than Internet Explorer. -# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you -# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files -# visible. Older versions of IE do not have SVG support. - -INTERACTIVE_SVG = NO - -# The tag DOT_PATH can be used to specify the path where the dot tool can be -# found. If left blank, it is assumed the dot tool can be found in the path. - -DOT_PATH = - -# The DOTFILE_DIRS tag can be used to specify one or more directories that -# contain dot files that are included in the documentation (see the -# \dotfile command). - -DOTFILE_DIRS = - -# The MSCFILE_DIRS tag can be used to specify one or more directories that -# contain msc files that are included in the documentation (see the -# \mscfile command). - -MSCFILE_DIRS = - -# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of -# nodes that will be shown in the graph. If the number of nodes in a graph -# becomes larger than this value, doxygen will truncate the graph, which is -# visualized by representing a node as a red box. Note that doxygen if the -# number of direct children of the root node in a graph is already larger than -# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note -# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. - -DOT_GRAPH_MAX_NODES = 50 - -# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the -# graphs generated by dot. A depth value of 3 means that only nodes reachable -# from the root by following a path via at most 3 edges will be shown. Nodes -# that lay further from the root node will be omitted. Note that setting this -# option to 1 or 2 may greatly reduce the computation time needed for large -# code bases. Also note that the size of a graph can be further restricted by -# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. - -MAX_DOT_GRAPH_DEPTH = 0 - -# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent -# background. This is disabled by default, because dot on Windows does not -# seem to support this out of the box. Warning: Depending on the platform used, -# enabling this option may lead to badly anti-aliased labels on the edges of -# a graph (i.e. they become hard to read). - -DOT_TRANSPARENT = NO - -# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output -# files in one run (i.e. multiple -o and -T options on the command line). This -# makes dot run faster, but since only newer versions of dot (>1.8.10) -# support this, this feature is disabled by default. - -DOT_MULTI_TARGETS = NO - -# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will -# generate a legend page explaining the meaning of the various boxes and -# arrows in the dot generated graphs. - -GENERATE_LEGEND = YES - -# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will -# remove the intermediate dot files that are used to generate -# the various graphs. - -DOT_CLEANUP = YES diff --git a/extern/shiny/Docs/GettingStarted.dox b/extern/shiny/Docs/GettingStarted.dox deleted file mode 100644 index b9cf58e23..000000000 --- a/extern/shiny/Docs/GettingStarted.dox +++ /dev/null @@ -1,65 +0,0 @@ -/*! - \page getting-started Getting started - - \section download Download the source - - \code - git clone git@github.com:scrawl/shiny.git - \endcode - - \section building Build the source - - The source files you want to build are: - - Main/*.cpp - - Preprocessor/*.cpp (unless you are using the system install of boost::wave, more below) - - Platforms/Ogre/*.cpp - - You can either build the sources as a static library, or simply add the sources to the source tree of your project. - - If you use CMake, you might find the included CMakeLists.txt useful. It builds static libraries with the names "shiny" and "shiny.OgrePlatform". - - \note The CMakeLists.txt is not intended as a stand-alone build system! Instead, you should include this from the main CMakeLists of your project. - - Make sure to link against OGRE and the boost filesystem library. - - If your boost version is older than 1.49, you must set the SHINY_USE_WAVE_SYSTEM_INSTALL variable and additionally link against the boost wave library. - - \code - set(SHINY_USE_WAVE_SYSTEM_INSTALL "TRUE") - \endcode - - \section code Basic initialisation code - - Add the following code to your application: - - \code{cpp} - - #include - #include - - .... - - sh::OgrePlatform* platform = new sh::OgrePlatform( - "General", // OGRE Resource group to use for creating materials. - myApplication.getDataPath() + "/" + "materials" // Path to look for materials and shaders. NOTE: This does NOT use the Ogre resource system, so you have to specify an absolute path. - ); - - sh::Factory* factory = new sh::Factory(platform); - - // Set a language. Valid options: CG, HLSL, GLSL - factory->setCurrentLanguage(sh::Language_GLSL); - - factory->loadAllFiles(); - - .... - your application runs here - .... - - // don't forget to delete on exit - delete factory; - - \endcode - - That's it! Now you can start defining materials. Refer to the page \ref defining-materials-shaders . - -*/ diff --git a/extern/shiny/Docs/Lod.dox b/extern/shiny/Docs/Lod.dox deleted file mode 100644 index 37d004638..000000000 --- a/extern/shiny/Docs/Lod.dox +++ /dev/null @@ -1,49 +0,0 @@ -/*! - - \page lod Material LOD - - \section howitworks How it works - - When Ogre requests a technique for a specific LOD index, the Factory selects the appropriate LOD configuration which then temporarily overrides the global settings in the shaders. We can use this to disable shader features one by one at a lower LOD, resulting in simpler and faster techniques for distant objects. - - \section howtouseit How to use it - - - Create a file with the extension '.lod'. There you can specify shader features to disable at a specific LOD level. Higher LOD index refers to a lower LOD. Example contents: - - \code - lod_configuration 1 - { - specular_mapping false - } - - lod_configuration 2 - { - specular_mapping false - normal_mapping false - } - - lod_configuration 3 - { - terrain_composite_map true - specular_mapping false - normal_mapping false - } - \endcode - - \note You can also add LOD configurations by calling \a sh::Factory::registerLodConfiguration. - - \note Do not use an index of 0. LOD 0 refers to the highest LOD, and you will never want to disable features at the highest LOD level. - - - - In your materials, specify the distances at which a lower LOD kicks in. Note that the actual distance might also be affected by the viewport and current entity LOD bias. In this example, the first LOD level (lod index 1) would normally be applied at a distance of 100 units, the next after 300, and the last after 1000 units. - - \code - material sample_material - { - lod_values 100 300 1000 - - ... your passes, texture units etc ... - } - \endcode - -*/ diff --git a/extern/shiny/Docs/Macros.dox b/extern/shiny/Docs/Macros.dox deleted file mode 100644 index c04ebd374..000000000 --- a/extern/shiny/Docs/Macros.dox +++ /dev/null @@ -1,283 +0,0 @@ -/*! - \page macros Shader Macros - - \tableofcontents - - \section Shader Language - - These macros are automatically defined, depending on the shader language that has been set by the application using sh::Factory::setCurrentLanguage. - - - SH_GLSL - - SH_HLSL - - SH_CG - - Example: - - \code - #if SH_GLSL == 1 - // glsl porting code - #endif - - #if SH_CG == 1 || SH_HLSL == 1 - // cg / hlsl porting code (similiar syntax) - #endif - \endcode - - \note It is encouraged to use the shipped porting header (extra/core.h) by #include-ing it in your shaders. If you do that, you should not have to use the above macros directly. - - \section vertex-fragment Vertex / fragment shader - - These macros are automatically defined, depending on the type of shader that is currently being compiled. - - - SH_VERTEX_SHADER - - SH_FRAGMENT_SHADER - - If you use the same source file for both vertex and fragment shader, then it is advised to use these macros for blending out the unused source. This will reduce your compile time. - - \section passthrough Vertex -> Fragment passthrough - - In shader development, a common task is to pass variables from the vertex to the fragment shader. This is no problem if you have a deterministic shader source (i.e. no #ifdefs). - - However, as soon as you begin to have lots of permutations of the same shader source, a problem arises. All current GPUs have a limit of 8 vertex to fragment passthroughs (with 4 components each, for example a float4). - - A common optimization is to put several individual float values together in a float4 (so-called "Packing"). But if your shader has lots of permutations and the passthrough elements you actually need are not known beforehand, it can be very tedious to pack manually. With the following macros, packing can become easier. - - \subsection shAllocatePassthrough shAllocatePassthrough - - Usage: \@shAllocatePassthrough(num_components, name) - - Example: - \code - #if FRAGMENT_NEED_DEPTH - @shAllocatePassthrough(1, depth) - #endif - \endcode - - This is the first thing you should do before using any of the macros below. - - \subsection shPassthroughVertexOutputs shPassthroughVertexOutputs - - Usage: \@shPassthroughVertexOutputs - - Use this in the inputs/outputs section of your vertex shader, in order to declare all the outputs that are needed for packing the variables that you want passed to the fragment. - - \subsection shPassthroughFragmentInputs shPassthroughFragmentInputs - - Usage: \@shPassthroughFragmentInputs - - Use this in the inputs/outputs section of your fragment shader, in order to declare all the inputs that are needed for receiving the variables that you want passed to the fragment. - - \subsection shPassthroughAssign shPassthroughAssign - - Usage: \@shPassthroughAssign(name, value) - - Use this in the vertex shader for assigning a value to the variable you want passed to the fragment. - - Example: - \code - #if FRAGMENT_NEED_DEPTH - @shPassthroughAssign(depth, shOutputPosition.z); - #endif - - \endcode - - \subsection shPassthroughReceive shPassthroughReceive - - Usage: \@shPassthroughReceive(name) - - Use this in the fragment shader to receive the passed value. - - Example: - - \code - #if FRAGMENT_NEED_DEPTH - float depth = @shPassthroughReceive(depth); - #endif - \endcode - - \section texUnits Texture units - - \subsection shUseSampler shUseSampler - - Usage: \@shUseSampler(samplerName) - - Requests the texture unit with name \a samplerName to be available for use in this pass. - - Why is this necessary? If you have a derived material that does not use all of the texture units that its parent defines (for example, if an optional asset such as a normal map is not available), there would be no way to know which texture units are actually needed and which can be skipped in the creation process (those that are never referenced in the shader). - - \section properties Property retrieval / binding - - \subsection shPropertyHasValue shPropertyHasValue - - Usage: \@shPropertyHasValue(property) - - Gets replaced by 1 if the property's value is not empty, or 0 if it is empty. - Useful for checking whether an optional texture is present or not. - - Example: - \code - #if @shPropertyHasValue(specularMap) - // specular mapping code - #endif - #if @shPropertyHasValue(normalMap) - // normal mapping code - #endif - \endcode - - \subsection shUniformProperty shUniformProperty - - Usage: \@shUniformProperty<4f|3f|2f|1f|int> (uniformName, property) - - Binds the value of \a property (from the shader_properties of the pass this shader belongs to) to the uniform with name \a uniformName. - - The following variants are available, depending on the type of your uniform variable: - - \@shUniformProperty4f - - \@shUniformProperty3f - - \@shUniformProperty2f - - \@shUniformProperty1f - - \@shUniformPropertyInt - - Example: \@shUniformProperty1f (uFresnelScale, fresnelScale) - - \subsection shPropertyBool shPropertyBool - - Retrieve a boolean property of the pass that this shader belongs to, gets replaced with either 0 or 1. - - Usage: \@shPropertyBool(propertyName) - - Example: - \code - #if @shPropertyBool(has_vertex_colors) - ... - #endif - \endcode - - \subsection shPropertyString shPropertyString - - Retrieve a string property of the pass that this shader belongs to - - Usage: \@shPropertyString(propertyName) - - \subsection shPropertyEqual shPropertyEqual - - Check if the value of a property equals a specific value, gets replaced with either 0 or 1. This is useful because the preprocessor cannot compare strings, only numbers. - - Usage: \@shPropertyEqual(propertyName, value) - - Example: - \code - #if @shPropertyEqual(lighting_mode, phong) - ... - #endif - \endcode - - \section globalSettings Global settings - - \subsection shGlobalSettingBool shGlobalSettingBool - - Retrieves the boolean value of a specific global setting, gets replaced with either 0 or 1. The value can be set using sh::Factory::setGlobalSetting. - - Usage: \@shGlobalSettingBool(settingName) - - \subsection shGlobalSettingEqual shGlobalSettingEqual - - Check if the value of a global setting equals a specific value, gets replaced with either 0 or 1. This is useful because the preprocessor cannot compare strings, only numbers. - - Usage: \@shGlobalSettingEqual(settingName, value) - - \subsection shGlobalSettingString shGlobalSettingString - - Gets replaced with the current value of a given global setting. The value can be set using sh::Factory::setGlobalSetting. - - Usage: \@shGlobalSettingString(settingName) - - \section sharedParams Shared parameters - - \subsection shSharedParameter shSharedParameter - - Allows you to bind a custom value to a uniform parameter. - - Usage: \@shSharedParameter(sharedParameterName) - - Example: \@shSharedParameter(pssmSplitPoints) - now the uniform parameter 'pssmSplitPoints' can be altered in all shaders that use it by executing sh::Factory::setSharedParameter("pssmSplitPoints", value) - - \note You may use the same shared parameter in as many shaders as you want. But don't forget to add the \@shSharedParameter macro to every shader that uses this shared parameter. - - \section autoconstants Auto constants - - \subsection shAutoConstant shAutoConstant - - Usage: \@shAutoConstant(uniformName, autoConstantName, [extraData]) - - Example: \@shAutoConstant(uModelViewMatrix, worldviewproj_matrix) - - Example: \@shAutoConstant(uLightPosition4, light_position, 4) - - Binds auto constant with name \a autoConstantName to the uniform \a uniformName. Optionally, you may specify extra data (for example the light index), as required by some auto constants. - - The auto constant names are the same as Ogre's. Read the section "3.1.9 Using Vertex/Geometry/Fragment Programs in a Pass" of the Ogre manual for a list of all auto constant names. - - \section misc Misc - - \subsection shForeach shForeach - - Usage: \@shForeach(n) - - Repeats the content of this foreach block \a n times. The end of the block is marked via \@shEndForeach, and the current iteration number can be retrieved via \@shIterator. - - \note Nested foreach blocks are currently \a not supported. - - \note For technical reasons, you can only use constant numbers, properties (\@shPropertyString) or global settings (\@shGlobalSettingString) as \a n parameter. - - Example: - - \code - @shForeach(3) - this is iteration number @shIterator - @shEndForeach - - Gets replaced with: - - this is iteration number 0 - this is iteration number 1 - this is iteration number 2 - \endcode - - Optionally, you can pass a constant offset to \@shIterator. Example: - - \code - @shForeach(3) - this is iteration number @shIterator(7) - @shEndForeach - - Gets replaced with: - - this is iteration number 7 - this is iteration number 8 - this is iteration number 9 - \endcode - - \subsection shCounter shCounter - - Gets replaced after the preprocessing step with the number that equals the n-th occurence of counters of the same ID. - - Usage: \@shCounter(ID) - - Example: - \code - @shCounter(0) - @shCounter(0) - @shCounter(1) - @shCounter(0) - \endcode - - Gets replaced with: - - \code - 0 - 1 - 0 - 2 - \endcode - -*/ diff --git a/extern/shiny/Docs/Mainpage.dox b/extern/shiny/Docs/Mainpage.dox deleted file mode 100644 index fb8f596dc..000000000 --- a/extern/shiny/Docs/Mainpage.dox +++ /dev/null @@ -1,13 +0,0 @@ -/*! - - \mainpage - - - \ref getting-started - - \ref defining-materials-shaders - - \ref macros - - \ref configurations - - \ref lod - - - sh::Factory - the main interface class - -*/ diff --git a/extern/shiny/Docs/Materials.dox b/extern/shiny/Docs/Materials.dox deleted file mode 100644 index d08599a04..000000000 --- a/extern/shiny/Docs/Materials.dox +++ /dev/null @@ -1,131 +0,0 @@ -/*! - - \page defining-materials-shaders Defining materials and shaders - - \section first-material Your first material - - Create a file called "myFirstMaterial.mat" and place it in the path you have used in your initialisation code (see \ref getting-started). Paste the following: - - \code - - material my_first_material - { - diffuse 1.0 1.0 1.0 1.0 - specular 0.4 0.4 0.4 32 - ambient 1.0 1.0 1.0 - emissive 0.0 0.0 0.0 - diffuseMap black.png - - pass - { - diffuse $diffuse - specular $specular - ambient $ambient - emissive $emissive - - texture_unit diffuseMap - { - texture $diffuseMap - create_in_ffp true // use this texture unit for fixed function pipeline - } - } - } - - material material1 - { - parent my_first_material - diffuseMap texture1.png - } - - material material2 - { - parent my_first_material - diffuseMap texture2.png - } - - \endcode - - \section first-shader The first shader - - Change the 'pass' section to include some shaders: - - \code - pass - { - vertex_program my_first_shader_vertex - fragment_program my_first_shader_fragment - ... - } - \endcode - - \note This does \a not refer to a single shader with a fixed source code, but in fact will automatically create a new \a instance of this shader (if necessary), which can have its own uniform variables, compile-time macros and much more! - - Next, we're going to define our shaders. Paste this in a new file called 'myfirstshader.shaderset' - - \code - shader_set my_first_shader_vertex - { - source example.shader - type vertex - profiles_cg vs_2_0 arbvp1 - profiles_hlsl vs_2_0 - } - - shader_set my_first_shader_fragment - { - source example.shader - type fragment - profiles_cg ps_2_x ps_2_0 ps arbfp1 - profiles_hlsl ps_2_0 - } - \endcode - - Some notes: - - There is no entry_point property because the entry point is always \a main. - - Both profiles_cg and profiles_hlsl are a list of shader profiles. The first profile that is supported is automatically picked. GLSL does not have shader profiles. - - Now, let's get into writing our shader! As you can guess from above, the filename should be 'example.shader'. - Make sure to also copy the 'core.h' file to the same location. It is included in shiny's source tree under 'Extra/'. - - Important: a newline at the end of the file is required. Many editors do this automatically or can be configured to do so. If there is no newline at the end of the file, and the last line is '#endif', you will get the rather cryptic error message " ill formed preprocessor directive: #endif" from boost::wave. - - \code - #include "core.h" - - #ifdef SH_VERTEX_SHADER - - SH_BEGIN_PROGRAM - shUniform(float4x4, wvp) @shAutoConstant(wvp, worldviewproj_matrix) - shVertexInput(float2, uv0) - shOutput(float2, UV) - SH_START_PROGRAM - { - shOutputPosition = shMatrixMult(wvp, shInputPosition); - UV = uv0; - } - - #else - - SH_BEGIN_PROGRAM - // NOTE: It is important that the sampler name here (diffuseMap) matches - // the name of the texture unit in the material. This is necessary because the system - // skips texture units that are never "referenced" in the shader. This can be the case - // when your base material has optional assets (for example a normal map) that are not - // used by some derived materials. - shSampler2D(diffuseMap) - shInput(float2, UV) - SH_START_PROGRAM - { - shOutputColour(0) = shSample(diffuseMap, UV); - } - - #endif - - \endcode - - There you have it! This shader will compile in several languages thanks to the porting defines in "core.h". If you need more defines, feel free to add them and don't forget to send them to me! - - For a full list of macros available when writing your shaders, refer to the page \ref macros - - In the future, some more in-depth shader examples might follow. -*/ diff --git a/extern/shiny/Editor/Actions.cpp b/extern/shiny/Editor/Actions.cpp deleted file mode 100644 index 135e81987..000000000 --- a/extern/shiny/Editor/Actions.cpp +++ /dev/null @@ -1,195 +0,0 @@ -#include "Actions.hpp" - -#include "../Main/Factory.hpp" - -namespace sh -{ - - void ActionDeleteMaterial::execute() - { - sh::Factory::getInstance().destroyMaterialInstance(mName); - } - - void ActionCloneMaterial::execute() - { - sh::MaterialInstance* sourceMaterial = sh::Factory::getInstance().getMaterialInstance(mSourceName); - std::string sourceMaterialParent = static_cast(sourceMaterial->getParent())->getName(); - sh::MaterialInstance* material = sh::Factory::getInstance().createMaterialInstance( - mDestName, sourceMaterialParent); - sourceMaterial->copyAll(material, sourceMaterial, false); - - material->setSourceFile(sourceMaterial->getSourceFile()); - } - - void ActionSaveAll::execute() - { - sh::Factory::getInstance().saveAll(); - } - - void ActionChangeGlobalSetting::execute() - { - sh::Factory::getInstance().setGlobalSetting(mName, mNewValue); - } - - void ActionCreateConfiguration::execute() - { - sh::Configuration newConfiguration; - sh::Factory::getInstance().createConfiguration(mName); - } - - void ActionDeleteConfiguration::execute() - { - sh::Factory::getInstance().destroyConfiguration(mName); - } - - void ActionChangeConfiguration::execute() - { - sh::Configuration* c = sh::Factory::getInstance().getConfiguration(mName); - c->setProperty(mKey, sh::makeProperty(new sh::StringValue(mValue))); - sh::Factory::getInstance().notifyConfigurationChanged(); - } - - void ActionDeleteConfigurationProperty::execute() - { - sh::Configuration* c = sh::Factory::getInstance().getConfiguration(mName); - c->deleteProperty(mKey); - sh::Factory::getInstance().notifyConfigurationChanged(); - } - - void ActionSetMaterialProperty::execute() - { - sh::MaterialInstance* m = sh::Factory::getInstance().getMaterialInstance(mName); - m->setProperty(mKey, sh::makeProperty(mValue)); - - sh::Factory::getInstance().notifyConfigurationChanged(); - } - - void ActionDeleteMaterialProperty::execute() - { - sh::MaterialInstance* m = sh::Factory::getInstance().getMaterialInstance(mName); - m->deleteProperty(mKey); - - sh::Factory::getInstance().notifyConfigurationChanged(); - } - - void ActionCreatePass::execute() - { - sh::MaterialInstance* m = sh::Factory::getInstance().getMaterialInstance(mName); - m->createPass(); - - sh::Factory::getInstance().notifyConfigurationChanged(); - } - - void ActionDeletePass::execute() - { - sh::MaterialInstance* m = sh::Factory::getInstance().getMaterialInstance(mName); - m->deletePass(mPassIndex); - - sh::Factory::getInstance().notifyConfigurationChanged(); - } - - void ActionSetPassProperty::execute() - { - sh::MaterialInstance* m = sh::Factory::getInstance().getMaterialInstance(mName); - assert (m->getPasses()->size() > mPassIndex); - m->getPasses()->at(mPassIndex).setProperty (mKey, sh::makeProperty(mValue)); - - sh::Factory::getInstance().notifyConfigurationChanged(); - } - - void ActionDeletePassProperty::execute() - { - sh::MaterialInstance* m = sh::Factory::getInstance().getMaterialInstance(mName); - assert (m->getPasses()->size() > mPassIndex); - m->getPasses()->at(mPassIndex).deleteProperty(mKey); - - sh::Factory::getInstance().notifyConfigurationChanged(); - } - - void ActionSetShaderProperty::execute() - { - sh::MaterialInstance* m = sh::Factory::getInstance().getMaterialInstance(mName); - assert (m->getPasses()->size() > mPassIndex); - m->getPasses()->at(mPassIndex).mShaderProperties.setProperty (mKey, sh::makeProperty(mValue)); - - sh::Factory::getInstance().notifyConfigurationChanged(); - } - - void ActionDeleteShaderProperty::execute() - { - sh::MaterialInstance* m = sh::Factory::getInstance().getMaterialInstance(mName); - assert (m->getPasses()->size() > mPassIndex); - m->getPasses()->at(mPassIndex).mShaderProperties.deleteProperty (mKey); - - sh::Factory::getInstance().notifyConfigurationChanged(); - } - - void ActionSetTextureProperty::execute() - { - sh::MaterialInstance* m = sh::Factory::getInstance().getMaterialInstance(mName); - assert (m->getPasses()->size() > mPassIndex); - assert (m->getPasses()->at(mPassIndex).mTexUnits.size() > mTextureIndex); - m->getPasses()->at(mPassIndex).mTexUnits.at(mTextureIndex).setProperty(mKey, sh::makeProperty(mValue)); - - sh::Factory::getInstance().notifyConfigurationChanged(); - } - - void ActionDeleteTextureProperty::execute() - { - sh::MaterialInstance* m = sh::Factory::getInstance().getMaterialInstance(mName); - assert (m->getPasses()->size() > mPassIndex); - assert (m->getPasses()->at(mPassIndex).mTexUnits.size() > mTextureIndex); - m->getPasses()->at(mPassIndex).mTexUnits.at(mTextureIndex).deleteProperty(mKey); - - sh::Factory::getInstance().notifyConfigurationChanged(); - } - - void ActionCreateTextureUnit::execute() - { - sh::MaterialInstance* m = sh::Factory::getInstance().getMaterialInstance(mName); - assert (m->getPasses()->size() > mPassIndex); - m->getPasses()->at(mPassIndex).createTextureUnit(mTexUnitName); - - sh::Factory::getInstance().notifyConfigurationChanged(); - } - - void ActionDeleteTextureUnit::execute() - { - sh::MaterialInstance* m = sh::Factory::getInstance().getMaterialInstance(mName); - assert (m->getPasses()->size() > mPassIndex); - assert (m->getPasses()->at(mPassIndex).mTexUnits.size() > mTextureIndex); - - m->getPasses()->at(mPassIndex).mTexUnits.erase(m->getPasses()->at(mPassIndex).mTexUnits.begin() + mTextureIndex); - - sh::Factory::getInstance().notifyConfigurationChanged(); - } - - void ActionMoveTextureUnit::execute() - { - sh::MaterialInstance* m = sh::Factory::getInstance().getMaterialInstance(mName); - assert (m->getPasses()->size() > mPassIndex); - assert (m->getPasses()->at(mPassIndex).mTexUnits.size() > mTextureIndex); - if (!mMoveUp) - assert (m->getPasses()->at(mPassIndex).mTexUnits.size() > mTextureIndex+1); - - std::vector textures = m->getPasses()->at(mPassIndex).mTexUnits; - if (mMoveUp) - std::swap(textures[mTextureIndex-1], textures[mTextureIndex]); - else - std::swap(textures[mTextureIndex+1], textures[mTextureIndex]); - m->getPasses()->at(mPassIndex).mTexUnits = textures; - - sh::Factory::getInstance().notifyConfigurationChanged(); - } - - void ActionChangeTextureUnitName::execute() - { - sh::MaterialInstance* m = sh::Factory::getInstance().getMaterialInstance(mName); - assert (m->getPasses()->size() > mPassIndex); - assert (m->getPasses()->at(mPassIndex).mTexUnits.size() > mTextureIndex); - - m->getPasses()->at(mPassIndex).mTexUnits[mTextureIndex].setName(mTexUnitName); - - sh::Factory::getInstance().notifyConfigurationChanged(); - } -} diff --git a/extern/shiny/Editor/Actions.hpp b/extern/shiny/Editor/Actions.hpp deleted file mode 100644 index 1bbdbe5a9..000000000 --- a/extern/shiny/Editor/Actions.hpp +++ /dev/null @@ -1,307 +0,0 @@ -#ifndef SH_ACTIONS_H -#define SH_ACTIONS_H - -#include - -namespace sh -{ - - class Action - { - public: - virtual void execute() = 0; - virtual ~Action() {} - }; - - class ActionDeleteMaterial : public Action - { - public: - ActionDeleteMaterial(const std::string& name) - : mName(name) {} - - virtual void execute(); - private: - std::string mName; - }; - - class ActionCloneMaterial : public Action - { - public: - ActionCloneMaterial(const std::string& sourceName, const std::string& destName) - : mSourceName(sourceName), mDestName(destName) {} - - virtual void execute(); - private: - std::string mSourceName; - std::string mDestName; - }; - - class ActionSaveAll : public Action - { - public: - virtual void execute(); - }; - - class ActionChangeGlobalSetting : public Action - { - public: - ActionChangeGlobalSetting(const std::string& name, const std::string& newValue) - : mName(name), mNewValue(newValue) {} - - virtual void execute(); - private: - std::string mName; - std::string mNewValue; - }; - - // configuration - - class ActionCreateConfiguration : public Action - { - public: - ActionCreateConfiguration(const std::string& name) - : mName(name) {} - - virtual void execute(); - private: - std::string mName; - - }; - - class ActionDeleteConfiguration : public Action - { - public: - ActionDeleteConfiguration(const std::string& name) - : mName(name) {} - - virtual void execute(); - private: - std::string mName; - - }; - - class ActionChangeConfiguration : public Action - { - public: - ActionChangeConfiguration (const std::string& name, const std::string& key, const std::string& value) - : mName(name), mKey(key), mValue(value) {} - - virtual void execute(); - private: - std::string mName; - std::string mKey; - std::string mValue; - }; - - class ActionDeleteConfigurationProperty : public Action - { - public: - ActionDeleteConfigurationProperty (const std::string& name, const std::string& key) - : mName(name), mKey(key) {} - - virtual void execute(); - private: - std::string mName; - std::string mKey; - }; - - // material - - class ActionSetMaterialProperty : public Action - { - public: - ActionSetMaterialProperty (const std::string& name, const std::string& key, const std::string& value) - : mName(name), mKey(key), mValue(value) {} - - virtual void execute(); - private: - std::string mName; - std::string mKey; - std::string mValue; - }; - - class ActionDeleteMaterialProperty : public Action - { - public: - ActionDeleteMaterialProperty (const std::string& name, const std::string& key) - : mName(name), mKey(key) {} - - virtual void execute(); - private: - std::string mName; - std::string mKey; - }; - - // pass - - class ActionCreatePass : public Action - { - public: - ActionCreatePass (const std::string& name) - : mName(name) {} - - virtual void execute(); - private: - std::string mName; - }; - - class ActionDeletePass : public Action - { - public: - ActionDeletePass (const std::string& name, int passIndex) - : mName(name), mPassIndex(passIndex) {} - - virtual void execute(); - private: - std::string mName; - int mPassIndex; - }; - - class ActionSetPassProperty : public Action - { - public: - ActionSetPassProperty (const std::string& name, int passIndex, const std::string& key, const std::string& value) - : mName(name), mPassIndex(passIndex), mKey(key), mValue(value) {} - - virtual void execute(); - private: - std::string mName; - int mPassIndex; - std::string mKey; - std::string mValue; - }; - - class ActionDeletePassProperty : public Action - { - public: - ActionDeletePassProperty (const std::string& name, int passIndex, const std::string& key) - : mName(name), mPassIndex(passIndex), mKey(key) {} - - virtual void execute(); - private: - std::string mName; - int mPassIndex; - std::string mKey; - }; - - // shader - - class ActionSetShaderProperty : public Action - { - public: - ActionSetShaderProperty (const std::string& name, int passIndex, const std::string& key, const std::string& value) - : mName(name), mPassIndex(passIndex), mKey(key), mValue(value) {} - - virtual void execute(); - private: - std::string mName; - int mPassIndex; - std::string mKey; - std::string mValue; - }; - - class ActionDeleteShaderProperty : public Action - { - public: - ActionDeleteShaderProperty (const std::string& name, int passIndex, const std::string& key) - : mName(name), mPassIndex(passIndex), mKey(key) {} - - virtual void execute(); - private: - std::string mName; - int mPassIndex; - std::string mKey; - }; - - // texture unit - - class ActionChangeTextureUnitName : public Action - { - public: - ActionChangeTextureUnitName (const std::string& name, int passIndex, int textureIndex, const std::string& texUnitName) - : mName(name), mPassIndex(passIndex), mTextureIndex(textureIndex), mTexUnitName(texUnitName) {} - - virtual void execute(); - - private: - std::string mName; - int mPassIndex; - int mTextureIndex; - std::string mTexUnitName; - }; - - class ActionCreateTextureUnit : public Action - { - public: - ActionCreateTextureUnit (const std::string& name, int passIndex, const std::string& texUnitName) - : mName(name), mPassIndex(passIndex), mTexUnitName(texUnitName) {} - - virtual void execute(); - - private: - std::string mName; - int mPassIndex; - std::string mTexUnitName; - }; - - class ActionDeleteTextureUnit : public Action - { - public: - ActionDeleteTextureUnit (const std::string& name, int passIndex, int textureIndex) - : mName(name), mPassIndex(passIndex), mTextureIndex(textureIndex) {} - - virtual void execute(); - - private: - std::string mName; - int mPassIndex; - int mTextureIndex; - }; - - class ActionMoveTextureUnit : public Action - { - public: - ActionMoveTextureUnit (const std::string& name, int passIndex, int textureIndex, bool moveUp) - : mName(name), mPassIndex(passIndex), mTextureIndex(textureIndex), mMoveUp(moveUp) {} - - virtual void execute(); - - private: - std::string mName; - int mPassIndex; - int mTextureIndex; - bool mMoveUp; - }; - - class ActionSetTextureProperty : public Action - { - public: - ActionSetTextureProperty (const std::string& name, int passIndex, int textureIndex, const std::string& key, const std::string& value) - : mName(name), mPassIndex(passIndex), mTextureIndex(textureIndex), mKey(key), mValue(value) {} - - virtual void execute(); - private: - std::string mName; - int mPassIndex; - int mTextureIndex; - std::string mKey; - std::string mValue; - }; - - class ActionDeleteTextureProperty : public Action - { - public: - ActionDeleteTextureProperty (const std::string& name, int passIndex, int textureIndex, const std::string& key) - : mName(name), mPassIndex(passIndex), mTextureIndex(textureIndex), mKey(key) {} - - virtual void execute(); - private: - std::string mName; - int mPassIndex; - int mTextureIndex; - std::string mKey; - }; - -} - -#endif diff --git a/extern/shiny/Editor/AddPropertyDialog.cpp b/extern/shiny/Editor/AddPropertyDialog.cpp deleted file mode 100644 index 71b47feb1..000000000 --- a/extern/shiny/Editor/AddPropertyDialog.cpp +++ /dev/null @@ -1,31 +0,0 @@ -#include "AddPropertyDialog.hpp" -#include "ui_addpropertydialog.h" - -AddPropertyDialog::AddPropertyDialog(QWidget *parent) - : QDialog(parent) - , ui(new Ui::AddPropertyDialog) - , mType(0) -{ - ui->setupUi(this); - - connect(ui->buttonBox, SIGNAL(accepted()), - this, SLOT(accepted())); - connect(ui->buttonBox, SIGNAL(rejected()), - this, SLOT(rejected())); -} - -void AddPropertyDialog::accepted() -{ - mName = ui->lineEdit->text(); - mType = ui->comboBox->currentIndex(); -} - -void AddPropertyDialog::rejected() -{ - mName = ""; -} - -AddPropertyDialog::~AddPropertyDialog() -{ - delete ui; -} diff --git a/extern/shiny/Editor/AddPropertyDialog.h b/extern/shiny/Editor/AddPropertyDialog.h deleted file mode 100644 index c1d2c960b..000000000 --- a/extern/shiny/Editor/AddPropertyDialog.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef ADDPROPERTYDIALOG_H -#define ADDPROPERTYDIALOG_H - -#include - -namespace Ui { -class AddPropertyDialog; -} - -class AddPropertyDialog : public QDialog -{ - Q_OBJECT - -public: - explicit AddPropertyDialog(QWidget *parent = 0); - ~AddPropertyDialog(); - -private: - Ui::AddPropertyDialog *ui; -}; - -#endif // ADDPROPERTYDIALOG_H diff --git a/extern/shiny/Editor/AddPropertyDialog.hpp b/extern/shiny/Editor/AddPropertyDialog.hpp deleted file mode 100644 index b4e19b087..000000000 --- a/extern/shiny/Editor/AddPropertyDialog.hpp +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef ADDPROPERTYDIALOG_H -#define ADDPROPERTYDIALOG_H - -#include - -namespace Ui { -class AddPropertyDialog; -} - -class AddPropertyDialog : public QDialog -{ - Q_OBJECT - -public: - explicit AddPropertyDialog(QWidget *parent = 0); - ~AddPropertyDialog(); - - int mType; - QString mName; - -public slots: - void accepted(); - void rejected(); - -private: - Ui::AddPropertyDialog *ui; -}; - -#endif // ADDPROPERTYDIALOG_H diff --git a/extern/shiny/Editor/CMakeLists.txt b/extern/shiny/Editor/CMakeLists.txt deleted file mode 100644 index eead159f0..000000000 --- a/extern/shiny/Editor/CMakeLists.txt +++ /dev/null @@ -1,61 +0,0 @@ -set(SHINY_EDITOR_LIBRARY "shiny.Editor") - -find_package(Qt4) - -if (QT_FOUND) - - add_definitions(-DSHINY_BUILD_MATERIAL_EDITOR=1) - set (SHINY_BUILD_EDITOR_FLAG -DSHINY_BUILD_MATERIAL_EDITOR=1 PARENT_SCOPE) - - set(QT_USE_QTGUI 1) - - # Headers that must be preprocessed - set(SHINY_EDITOR_HEADER_MOC - MainWindow.hpp - NewMaterialDialog.hpp - AddPropertyDialog.hpp - PropertySortModel.hpp - ) - - set(SHINY_EDITOR_UI - mainwindow.ui - newmaterialdialog.ui - addpropertydialog.ui - ) - - QT4_WRAP_CPP(MOC_SRCS ${SHINY_EDITOR_HEADER_MOC}) - QT4_WRAP_UI(UI_HDRS ${SHINY_EDITOR_UI}) - - set(SOURCE_FILES - NewMaterialDialog.cpp - AddPropertyDialog.cpp - ColoredTabWidget.hpp - MainWindow.cpp - Editor.cpp - Actions.cpp - Query.cpp - PropertySortModel.cpp - ${SHINY_EDITOR_UI} # Just to have them in the IDE's file explorer - ) - - include(${QT_USE_FILE}) - - set (CMAKE_INCLUDE_CURRENT_DIR "true") - - include_directories(${CMAKE_CURRENT_BINARY_DIR}) - - add_library(${SHINY_EDITOR_LIBRARY} STATIC ${SOURCE_FILES} ${MOC_SRCS} ${UI_HDRS}) - - set(SHINY_LIBRARIES ${SHINY_LIBRARIES} - ${SHINY_EDITOR_LIBRARY} - ${QT_LIBRARIES} - ) - set(SHINY_LIBRARIES ${SHINY_LIBRARIES} PARENT_SCOPE) - -else (QT_FOUND) - - add_definitions(-DSHINY_BUILD_MATERIAL_EDITOR=0) - set (SHINY_BUILD_EDITOR_FLAG -DSHINY_BUILD_MATERIAL_EDITOR=0 PARENT_SCOPE) - message(STATUS "QT4 was not found. You will not be able to use the material editor.") - -endif(QT_FOUND) diff --git a/extern/shiny/Editor/ColoredTabWidget.hpp b/extern/shiny/Editor/ColoredTabWidget.hpp deleted file mode 100644 index 0bf30f6dd..000000000 --- a/extern/shiny/Editor/ColoredTabWidget.hpp +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef SHINY_EDITOR_COLOREDTABWIDGET_H -#define SHINY_EDITOR_COLOREDTABWIDGET_H - -#include - -namespace sh -{ - -/// Makes tabBar() public to allow changing tab title colors. -class ColoredTabWidget : public QTabWidget -{ -public: - ColoredTabWidget(QWidget* parent = 0) - : QTabWidget(parent) {} - - QTabBar* tabBar() - { - return QTabWidget::tabBar(); - } -}; - -} - -#endif diff --git a/extern/shiny/Editor/Editor.cpp b/extern/shiny/Editor/Editor.cpp deleted file mode 100644 index 8c58d0e66..000000000 --- a/extern/shiny/Editor/Editor.cpp +++ /dev/null @@ -1,117 +0,0 @@ -#include "Editor.hpp" - - -#include -#include - -#include - -#include "../Main/Factory.hpp" - -#include "MainWindow.hpp" - -namespace sh -{ - - Editor::Editor() - : mMainWindow(NULL) - , mApplication(NULL) - , mInitialized(false) - , mThread(NULL) - { - } - - Editor::~Editor() - { - if (mMainWindow) - mMainWindow->mRequestExit = true; - - if (mThread) - mThread->join(); - delete mThread; - } - - void Editor::show() - { - if (!mInitialized) - { - mInitialized = true; - - mThread = new boost::thread(boost::bind(&Editor::runThread, this)); - } - else - { - if (mMainWindow) - mMainWindow->mRequestShowWindow = true; - } - } - - void Editor::runThread() - { - int argc = 0; - char** argv = NULL; - mApplication = new QApplication(argc, argv); - mApplication->setQuitOnLastWindowClosed(false); - mMainWindow = new MainWindow(); - mMainWindow->mSync = &mSync; - mMainWindow->show(); - - mApplication->exec(); - - delete mApplication; - } - - void Editor::update() - { - sh::Factory::getInstance().doMonitorShaderFiles(); - - if (!mMainWindow) - return; - - - { - boost::mutex::scoped_lock lock(mSync.mActionMutex); - - // execute pending actions - while (mMainWindow->mActionQueue.size()) - { - Action* action = mMainWindow->mActionQueue.front(); - action->execute(); - delete action; - mMainWindow->mActionQueue.pop(); - } - } - { - boost::mutex::scoped_lock lock(mSync.mQueryMutex); - - // execute pending queries - for (std::vector::iterator it = mMainWindow->mQueries.begin(); it != mMainWindow->mQueries.end(); ++it) - { - Query* query = *it; - if (!query->mDone) - query->execute(); - } - } - - boost::mutex::scoped_lock lock2(mSync.mUpdateMutex); - - // update the list of materials - mMainWindow->mState.mMaterialList.clear(); - sh::Factory::getInstance().listMaterials(mMainWindow->mState.mMaterialList); - - // update global settings - mMainWindow->mState.mGlobalSettingsMap.clear(); - sh::Factory::getInstance().listGlobalSettings(mMainWindow->mState.mGlobalSettingsMap); - - // update configuration list - mMainWindow->mState.mConfigurationList.clear(); - sh::Factory::getInstance().listConfigurationNames(mMainWindow->mState.mConfigurationList); - - // update shader list - mMainWindow->mState.mShaderSets.clear(); - sh::Factory::getInstance().listShaderSets(mMainWindow->mState.mShaderSets); - - mMainWindow->mState.mErrors += sh::Factory::getInstance().getErrorLog(); - } - -} diff --git a/extern/shiny/Editor/Editor.hpp b/extern/shiny/Editor/Editor.hpp deleted file mode 100644 index 2b1e8040d..000000000 --- a/extern/shiny/Editor/Editor.hpp +++ /dev/null @@ -1,73 +0,0 @@ -#ifndef SH_EDITOR_H -#define SH_EDITOR_H - -#if SHINY_BUILD_MATERIAL_EDITOR -class QApplication; - -#include -#include - -namespace boost -{ - class thread; -} - -namespace sh -{ - class MainWindow; - - struct SynchronizationState - { - boost::mutex mUpdateMutex; - boost::mutex mActionMutex; - boost::mutex mQueryMutex; - }; - - class Editor - { - public: - - Editor(); - ~Editor(); - - void show(); - void update(); - - - private: - bool mInitialized; - - MainWindow* mMainWindow; - QApplication* mApplication; - - SynchronizationState mSync; - - boost::thread* mThread; - - void runThread(); - - void processShowWindow(); - }; - -} - -#else - -// Dummy implementation, so that the user's code does not have to be polluted with #ifdefs -namespace sh -{ - - class Editor - { - public: - Editor() {} - ~Editor() {} - void show() {} - void update() {} - - }; -} - -#endif - -#endif diff --git a/extern/shiny/Editor/MainWindow.cpp b/extern/shiny/Editor/MainWindow.cpp deleted file mode 100644 index a2c52dc2f..000000000 --- a/extern/shiny/Editor/MainWindow.cpp +++ /dev/null @@ -1,952 +0,0 @@ -#include "MainWindow.hpp" -#include "ui_mainwindow.h" - -#include - -#include -#include - -#include -#include - -#include "Editor.hpp" -#include "ColoredTabWidget.hpp" -#include "AddPropertyDialog.hpp" - -sh::MainWindow::MainWindow(QWidget *parent) - : QMainWindow(parent) - , ui(new Ui::MainWindow) - , mRequestShowWindow(false) - , mRequestExit(false) - , mIgnoreGlobalSettingChange(false) - , mIgnoreConfigurationChange(false) - , mIgnoreMaterialChange(false) - , mIgnoreMaterialPropertyChange(false) -{ - ui->setupUi(this); - - QTimer *timer = new QTimer(this); - connect(timer, SIGNAL(timeout()), this, SLOT(onIdle())); - timer->start(50); - - QList sizes; - sizes << 250; - sizes << 550; - ui->splitter->setSizes(sizes); - - mMaterialModel = new QStringListModel(this); - - mMaterialProxyModel = new QSortFilterProxyModel(this); - mMaterialProxyModel->setSourceModel(mMaterialModel); - mMaterialProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive); - mMaterialProxyModel->setDynamicSortFilter(true); - mMaterialProxyModel->setSortCaseSensitivity(Qt::CaseInsensitive); - - ui->materialList->setModel(mMaterialProxyModel); - ui->materialList->setSelectionMode(QAbstractItemView::SingleSelection); - ui->materialList->setEditTriggers(QAbstractItemView::NoEditTriggers); - ui->materialList->setAlternatingRowColors(true); - - connect(ui->materialList->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), - this, SLOT(onMaterialSelectionChanged(QModelIndex,QModelIndex))); - - mMaterialPropertyModel = new QStandardItemModel(0, 2, this); - mMaterialPropertyModel->setHorizontalHeaderItem(0, new QStandardItem(QString("Name"))); - mMaterialPropertyModel->setHorizontalHeaderItem(1, new QStandardItem(QString("Value"))); - connect(mMaterialPropertyModel, SIGNAL(itemChanged(QStandardItem*)), - this, SLOT(onMaterialPropertyChanged(QStandardItem*))); - - mMaterialSortModel = new PropertySortModel(this); - mMaterialSortModel->setSourceModel(mMaterialPropertyModel); - mMaterialSortModel->setDynamicSortFilter(true); - mMaterialSortModel->setSortCaseSensitivity(Qt::CaseInsensitive); - - ui->materialView->setModel(mMaterialSortModel); - ui->materialView->setContextMenuPolicy(Qt::CustomContextMenu); - ui->materialView->setAlternatingRowColors(true); - ui->materialView->setSortingEnabled(true); - connect(ui->materialView, SIGNAL(customContextMenuRequested(QPoint)), - this, SLOT(onContextMenuRequested(QPoint))); - - mGlobalSettingsModel = new QStandardItemModel(0, 2, this); - mGlobalSettingsModel->setHorizontalHeaderItem(0, new QStandardItem(QString("Name"))); - mGlobalSettingsModel->setHorizontalHeaderItem(1, new QStandardItem(QString("Value"))); - connect(mGlobalSettingsModel, SIGNAL(itemChanged(QStandardItem*)), - this, SLOT(onGlobalSettingChanged(QStandardItem*))); - - ui->globalSettingsView->setModel(mGlobalSettingsModel); - ui->globalSettingsView->verticalHeader()->setResizeMode(QHeaderView::ResizeToContents); - ui->globalSettingsView->verticalHeader()->hide(); - ui->globalSettingsView->horizontalHeader()->setResizeMode(QHeaderView::Stretch); - ui->globalSettingsView->setSelectionMode(QAbstractItemView::SingleSelection); - - ui->configurationList->setSelectionMode(QAbstractItemView::SingleSelection); - ui->configurationList->setEditTriggers(QAbstractItemView::NoEditTriggers); - connect(ui->configurationList, SIGNAL(currentTextChanged(QString)), - this, SLOT(onConfigurationSelectionChanged(QString))); - - mConfigurationModel = new QStandardItemModel(0, 2, this); - mConfigurationModel->setHorizontalHeaderItem(0, new QStandardItem(QString("Name"))); - mConfigurationModel->setHorizontalHeaderItem(1, new QStandardItem(QString("Value"))); - connect(mConfigurationModel, SIGNAL(itemChanged(QStandardItem*)), - this, SLOT(onConfigurationChanged(QStandardItem*))); - - ui->configurationView->setModel(mConfigurationModel); - ui->configurationView->verticalHeader()->setResizeMode(QHeaderView::ResizeToContents); - ui->configurationView->verticalHeader()->hide(); - ui->configurationView->horizontalHeader()->setResizeMode(QHeaderView::Stretch); - ui->configurationView->setSelectionMode(QAbstractItemView::SingleSelection); -} - -sh::MainWindow::~MainWindow() -{ - delete ui; -} - -void sh::MainWindow::closeEvent(QCloseEvent *event) -{ - this->hide(); - event->ignore(); -} - -void sh::MainWindow::onIdle() -{ - if (mRequestShowWindow) - { - mRequestShowWindow = false; - show(); - } - - if (mRequestExit) - { - QApplication::exit(); - return; - } - - boost::mutex::scoped_lock lock(mSync->mUpdateMutex); - - - mIgnoreMaterialChange = true; - QString selected; - - QModelIndex selectedIndex = ui->materialList->selectionModel()->currentIndex(); - if (selectedIndex.isValid()) - selected = mMaterialModel->data(selectedIndex, Qt::DisplayRole).toString(); - - QStringList list; - - for (std::vector::const_iterator it = mState.mMaterialList.begin(); it != mState.mMaterialList.end(); ++it) - { - list.push_back(QString::fromStdString(*it)); - } - - if (mMaterialModel->stringList() != list) - { - mMaterialModel->setStringList(list); - - // quick hack to keep our selection when the model has changed - if (!selected.isEmpty()) - for (int i=0; irowCount(); ++i) - { - const QModelIndex& index = mMaterialModel->index(i,0); - if (mMaterialModel->data(index, Qt::DisplayRole).toString() == selected) - { - ui->materialList->setCurrentIndex(index); - break; - } - } - } - mIgnoreMaterialChange = false; - - mIgnoreGlobalSettingChange = true; - for (std::map::const_iterator it = mState.mGlobalSettingsMap.begin(); - it != mState.mGlobalSettingsMap.end(); ++it) - { - QList list = mGlobalSettingsModel->findItems(QString::fromStdString(it->first)); - if (!list.empty()) // item was already there - { - // if it changed, set the value column - if (mGlobalSettingsModel->data(mGlobalSettingsModel->index(list.front()->row(), 1)).toString() - != QString::fromStdString(it->second)) - { - mGlobalSettingsModel->setItem(list.front()->row(), 1, new QStandardItem(QString::fromStdString(it->second))); - } - } - else // item wasn't there; insert new row - { - QList toAdd; - QStandardItem* name = new QStandardItem(QString::fromStdString(it->first)); - name->setFlags(name->flags() &= ~Qt::ItemIsEditable); - QStandardItem* value = new QStandardItem(QString::fromStdString(it->second)); - toAdd.push_back(name); - toAdd.push_back(value); - mGlobalSettingsModel->appendRow(toAdd); - } - } - mIgnoreGlobalSettingChange = false; - - - mIgnoreConfigurationChange = true; - QList selected_ = ui->configurationList->selectedItems(); - QString selectedStr; - if (selected_.size()) - selectedStr = selected_.front()->text(); - - ui->configurationList->clear(); - - for (std::vector::const_iterator it = mState.mConfigurationList.begin(); it != mState.mConfigurationList.end(); ++it) - ui->configurationList->addItem(QString::fromStdString(*it)); - - if (!selectedStr.isEmpty()) - for (int i=0; iconfigurationList->count(); ++i) - { - if (ui->configurationList->item(i)->text() == selectedStr) - { - ui->configurationList->setCurrentItem(ui->configurationList->item(i), QItemSelectionModel::ClearAndSelect); - } - } - - mIgnoreConfigurationChange = false; - - if (!mState.mErrors.empty()) - { - ui->errorLog->append(QString::fromStdString(mState.mErrors)); - mState.mErrors = ""; - QColor color = ui->tabWidget->palette().color(QPalette::Normal, QPalette::Link); - ui->tabWidget->tabBar()->setTabTextColor(3, color); - } - - - // process query results - boost::mutex::scoped_lock lock2(mSync->mQueryMutex); - for (std::vector::iterator it = mQueries.begin(); it != mQueries.end();) - { - if ((*it)->mDone) - { - if (typeid(**it) == typeid(ConfigurationQuery)) - buildConfigurationModel(static_cast(*it)); - else if (typeid(**it) == typeid(MaterialQuery)) - buildMaterialModel(static_cast(*it)); - else if (typeid(**it) == typeid(MaterialPropertyQuery)) - { - MaterialPropertyQuery* q = static_cast(*it); - mIgnoreMaterialPropertyChange = true; - if (getSelectedMaterial().toStdString() == q->mName) - { - for (int i=0; irowCount(); ++i) - { - if (mMaterialPropertyModel->item(i,0)->text() == QString::fromStdString(q->mPropertyName)) - { - mMaterialPropertyModel->item(i,1)->setText(QString::fromStdString(q->mValue)); - if (mMaterialPropertyModel->item(i,1)->isCheckable()) - mMaterialPropertyModel->item(i,1)->setCheckState ((q->mValue == "true") - ? Qt::Checked : Qt::Unchecked); - } - } - } - mIgnoreMaterialPropertyChange = false; - } - - delete *it; - it = mQueries.erase(it); - } - else - ++it; - } -} - -void sh::MainWindow::onMaterialSelectionChanged (const QModelIndex & current, const QModelIndex & previous) -{ - if (mIgnoreMaterialChange) - return; - - QString name = getSelectedMaterial(); - if (!name.isEmpty()) - requestQuery(new sh::MaterialQuery(name.toStdString())); -} - -QString sh::MainWindow::getSelectedMaterial() -{ - QModelIndex selectedIndex = ui->materialList->selectionModel()->currentIndex(); - if (!selectedIndex.isValid()) - return QString(""); - - return mMaterialProxyModel->data(selectedIndex, Qt::DisplayRole).toString(); -} - -void sh::MainWindow::onConfigurationSelectionChanged (const QString& current) -{ - if (mIgnoreConfigurationChange) - return; - requestQuery(new sh::ConfigurationQuery(current.toStdString())); -} - -void sh::MainWindow::onGlobalSettingChanged(QStandardItem *item) -{ - if (mIgnoreGlobalSettingChange) - return; // we are only interested in changes by the user, not by the backend. - - std::string name = mGlobalSettingsModel->data(mGlobalSettingsModel->index(item->row(), 0)).toString().toStdString(); - std::string value = mGlobalSettingsModel->data(mGlobalSettingsModel->index(item->row(), 1)).toString().toStdString(); - - queueAction(new sh::ActionChangeGlobalSetting(name, value)); -} - -void sh::MainWindow::onConfigurationChanged (QStandardItem* item) -{ - QList items = ui->configurationList->selectedItems(); - if (items.size()) - { - std::string name = items.front()->text().toStdString(); - std::string key = mConfigurationModel->data(mConfigurationModel->index(item->row(), 0)).toString().toStdString(); - std::string value = mConfigurationModel->data(mConfigurationModel->index(item->row(), 1)).toString().toStdString(); - - queueAction(new sh::ActionChangeConfiguration(name, key, value)); - - requestQuery(new sh::ConfigurationQuery(name)); - } -} - -void sh::MainWindow::on_lineEdit_textEdited(const QString &arg1) -{ - mMaterialProxyModel->setFilterFixedString(arg1); -} - -void sh::MainWindow::on_actionSave_triggered() -{ - queueAction (new sh::ActionSaveAll()); -} - -void sh::MainWindow::on_actionNewMaterial_triggered() -{ - -} - -void sh::MainWindow::on_actionDeleteMaterial_triggered() -{ - QModelIndex selectedIndex = ui->materialList->selectionModel()->currentIndex(); - QString name = mMaterialProxyModel->data(selectedIndex, Qt::DisplayRole).toString(); - - queueAction (new sh::ActionDeleteMaterial(name.toStdString())); -} - -void sh::MainWindow::queueAction(Action* action) -{ - boost::mutex::scoped_lock lock(mSync->mActionMutex); - mActionQueue.push(action); -} - -void sh::MainWindow::requestQuery(Query *query) -{ - boost::mutex::scoped_lock lock(mSync->mActionMutex); - mQueries.push_back(query); -} - -void sh::MainWindow::on_actionQuit_triggered() -{ - hide(); -} - -void sh::MainWindow::on_actionNewConfiguration_triggered() -{ - QInputDialog dialog(this); - - QString text = QInputDialog::getText(this, tr("New Configuration"), - tr("Configuration name:")); - - if (!text.isEmpty()) - { - queueAction(new ActionCreateConfiguration(text.toStdString())); - } -} - -void sh::MainWindow::on_actionDeleteConfiguration_triggered() -{ - QList items = ui->configurationList->selectedItems(); - if (items.size()) - queueAction(new ActionDeleteConfiguration(items.front()->text().toStdString())); -} - -void sh::MainWindow::on_actionDeleteConfigurationProperty_triggered() -{ - QList items = ui->configurationList->selectedItems(); - if (items.empty()) - return; - std::string configurationName = items.front()->text().toStdString(); - - QModelIndex current = ui->configurationView->currentIndex(); - if (!current.isValid()) - return; - - std::string propertyName = mConfigurationModel->data(mConfigurationModel->index(current.row(), 0)).toString().toStdString(); - - queueAction(new sh::ActionDeleteConfigurationProperty(configurationName, propertyName)); - requestQuery(new sh::ConfigurationQuery(configurationName)); -} - -void sh::MainWindow::on_actionCloneMaterial_triggered() -{ - QModelIndex selectedIndex = ui->materialList->selectionModel()->currentIndex(); - QString name = mMaterialProxyModel->data(selectedIndex, Qt::DisplayRole).toString(); - if (name.isEmpty()) - return; - - QInputDialog dialog(this); - - QString text = QInputDialog::getText(this, tr("Clone material"), - tr("Name:")); - - if (!text.isEmpty()) - { - queueAction(new ActionCloneMaterial(name.toStdString(), text.toStdString())); - } -} - -void sh::MainWindow::onContextMenuRequested(const QPoint &point) -{ - QPoint globalPos = ui->materialView->viewport()->mapToGlobal(point); - - QMenu menu; - - QList actions; - actions.push_back(ui->actionNewProperty); - actions.push_back(ui->actionDeleteProperty); - actions.push_back(ui->actionCreatePass); - actions.push_back(ui->actionCreateTextureUnit); - menu.addActions(actions); - - menu.exec(globalPos); -} - -void sh::MainWindow::getContext(QModelIndex index, int* passIndex, int* textureIndex, bool* isInPass, bool* isInTextureUnit) -{ - if (passIndex) - { - *passIndex = 0; - if (isInPass) - *isInPass = false; - QModelIndex passModelIndex = index; - // go up until we find the pass item. - while (getPropertyKey(passModelIndex) != "pass" && passModelIndex.isValid()) - passModelIndex = passModelIndex.parent(); - - if (passModelIndex.isValid()) - { - if (passModelIndex.column() != 0) - passModelIndex = passModelIndex.parent().child(passModelIndex.row(), 0); - for (int i=0; irowCount(); ++i) - { - if (mMaterialPropertyModel->data(mMaterialPropertyModel->index(i, 0)).toString() == QString("pass")) - { - if (mMaterialPropertyModel->index(i, 0) == passModelIndex) - { - if (isInPass) - *isInPass = true; - break; - } - ++(*passIndex); - } - } - } - } - if (textureIndex) - { - *textureIndex = 0; - if (isInTextureUnit) - *isInTextureUnit = false; - QModelIndex texModelIndex = index; - // go up until we find the texture_unit item. - while (getPropertyKey(texModelIndex) != "texture_unit" && texModelIndex.isValid()) - texModelIndex = texModelIndex.parent(); - if (texModelIndex.isValid()) - { - if (texModelIndex.column() != 0) - texModelIndex = texModelIndex.parent().child(texModelIndex.row(), 0); - for (int i=0; irowCount(texModelIndex.parent()); ++i) - { - if (texModelIndex.parent().child(i, 0).data().toString() == QString("texture_unit")) - { - if (texModelIndex.parent().child(i, 0) == texModelIndex) - { - if (isInTextureUnit) - *isInTextureUnit = true; - break; - } - ++(*textureIndex); - } - } - } - } -} - -std::string sh::MainWindow::getPropertyKey(QModelIndex index) -{ - if (!index.parent().isValid()) - return mMaterialPropertyModel->data(mMaterialPropertyModel->index(index.row(), 0)).toString().toStdString(); - else - return index.parent().child(index.row(), 0).data().toString().toStdString(); -} - -std::string sh::MainWindow::getPropertyValue(QModelIndex index) -{ - if (!index.parent().isValid()) - return mMaterialPropertyModel->data(mMaterialPropertyModel->index(index.row(), 1)).toString().toStdString(); - else - return index.parent().child(index.row(), 1).data().toString().toStdString(); -} - -void sh::MainWindow::onMaterialPropertyChanged(QStandardItem *item) -{ - if (mIgnoreMaterialPropertyChange) - return; - - QString material = getSelectedMaterial(); - if (material.isEmpty()) - return; - - // handle checkboxes being checked/unchecked - std::string value = getPropertyValue(item->index()); - if (item->data(Qt::UserRole).toInt() == MaterialProperty::Boolean) - { - if (item->checkState() == Qt::Checked && value != "true") - value = "true"; - else if (item->checkState() == Qt::Unchecked && value == "true") - value = "false"; - item->setText(QString::fromStdString(value)); - } - - // handle inherited properties being changed, i.e. overridden by the current (derived) material - if (item->data(Qt::UserRole+1).toInt() == MaterialProperty::Inherited_Unchanged) - { - QColor normalColor = ui->materialView->palette().color(QPalette::Normal, QPalette::WindowText); - mIgnoreMaterialPropertyChange = true; - mMaterialPropertyModel->item(item->index().row(), 0) - ->setData(QVariant(MaterialProperty::Inherited_Changed), Qt::UserRole+1); - mMaterialPropertyModel->item(item->index().row(), 0) - ->setData(normalColor, Qt::ForegroundRole); - mMaterialPropertyModel->item(item->index().row(), 1) - ->setData(QVariant(MaterialProperty::Inherited_Changed), Qt::UserRole+1); - mMaterialPropertyModel->item(item->index().row(), 1) - ->setData(normalColor, Qt::ForegroundRole); - mIgnoreMaterialPropertyChange = false; - - ui->materialView->scrollTo(mMaterialSortModel->mapFromSource(item->index())); - } - - if (!item->index().parent().isValid()) - { - // top level material property - queueAction(new ActionSetMaterialProperty( - material.toStdString(), getPropertyKey(item->index()), value)); - } - else if (getPropertyKey(item->index()) == "texture_unit") - { - // texture unit name changed - int passIndex, textureIndex; - getContext(item->index(), &passIndex, &textureIndex); - std::cout << "passIndex " << passIndex << " " << textureIndex << std::endl; - - queueAction(new ActionChangeTextureUnitName( - material.toStdString(), passIndex, textureIndex, value)); - - } - else if (item->index().parent().data().toString() == "pass") - { - // pass property - int passIndex; - getContext(item->index(), &passIndex, NULL); - /// \todo if shaders are changed, check that the material provides all properties needed by the shader - queueAction(new ActionSetPassProperty( - material.toStdString(), passIndex, getPropertyKey(item->index()), value)); - } - else if (item->index().parent().data().toString() == "shader_properties") - { - // shader property - int passIndex; - getContext(item->index(), &passIndex, NULL); - queueAction(new ActionSetShaderProperty( - material.toStdString(), passIndex, getPropertyKey(item->index()), value)); - } - else if (item->index().parent().data().toString() == "texture_unit") - { - // texture property - int passIndex, textureIndex; - getContext(item->index(), &passIndex, &textureIndex); - queueAction(new ActionSetTextureProperty( - material.toStdString(), passIndex, textureIndex, getPropertyKey(item->index()), value)); - } -} - -void sh::MainWindow::buildMaterialModel(MaterialQuery *data) -{ - mMaterialPropertyModel->clear(); - - mMaterialPropertyModel->setHorizontalHeaderItem(0, new QStandardItem(QString("Name"))); - mMaterialPropertyModel->setHorizontalHeaderItem(1, new QStandardItem(QString("Value"))); - - for (std::map::const_iterator it = data->mProperties.begin(); - it != data->mProperties.end(); ++it) - { - addProperty(mMaterialPropertyModel->invisibleRootItem(), it->first, it->second); - } - - for (std::vector::iterator it = data->mPasses.begin(); - it != data->mPasses.end(); ++it) - { - QStandardItem* passItem = new QStandardItem (QString("pass")); - passItem->setFlags(passItem->flags() &= ~Qt::ItemIsEditable); - passItem->setData(QVariant(static_cast(MaterialProperty::Object)), Qt::UserRole); - - if (it->mShaderProperties.size()) - { - QStandardItem* shaderPropertiesItem = new QStandardItem (QString("shader_properties")); - shaderPropertiesItem->setFlags(shaderPropertiesItem->flags() &= ~Qt::ItemIsEditable); - shaderPropertiesItem->setData(QVariant(static_cast(MaterialProperty::Object)), Qt::UserRole); - - for (std::map::iterator pit = it->mShaderProperties.begin(); - pit != it->mShaderProperties.end(); ++pit) - { - addProperty(shaderPropertiesItem, pit->first, pit->second); - } - passItem->appendRow(shaderPropertiesItem); - } - - for (std::map::iterator pit = it->mProperties.begin(); - pit != it->mProperties.end(); ++pit) - { - addProperty(passItem, pit->first, pit->second); - } - - for (std::vector::iterator tIt = it->mTextureUnits.begin(); - tIt != it->mTextureUnits.end(); ++tIt) - { - QStandardItem* unitItem = new QStandardItem (QString("texture_unit")); - unitItem->setFlags(unitItem->flags() &= ~Qt::ItemIsEditable); - unitItem->setData(QVariant(static_cast(MaterialProperty::Object)), Qt::UserRole); - QStandardItem* nameItem = new QStandardItem (QString::fromStdString(tIt->mName)); - nameItem->setData(QVariant(static_cast(MaterialProperty::Object)), Qt::UserRole); - - QList texUnit; - texUnit << unitItem << nameItem; - - for (std::map::iterator pit = tIt->mProperties.begin(); - pit != tIt->mProperties.end(); ++pit) - { - addProperty(unitItem, pit->first, pit->second); - } - - passItem->appendRow(texUnit); - } - - QList toAdd; - toAdd << passItem; - toAdd << new QStandardItem(QString("")); - mMaterialPropertyModel->appendRow(toAdd); - } - - ui->materialView->expandAll(); - ui->materialView->resizeColumnToContents(0); - ui->materialView->resizeColumnToContents(1); -} - -void sh::MainWindow::addProperty(QStandardItem *parent, const std::string &key, MaterialProperty value, bool scrollTo) -{ - QList toAdd; - QStandardItem* keyItem = new QStandardItem(QString::fromStdString(key)); - keyItem->setFlags(keyItem->flags() &= ~Qt::ItemIsEditable); - keyItem->setData(QVariant(value.mType), Qt::UserRole); - keyItem->setData(QVariant(value.mSource), Qt::UserRole+1); - toAdd.push_back(keyItem); - - QStandardItem* valueItem = NULL; - if (value.mSource != MaterialProperty::None) - { - valueItem = new QStandardItem(QString::fromStdString(value.mValue)); - valueItem->setData(QVariant(value.mType), Qt::UserRole); - valueItem->setData(QVariant(value.mSource), Qt::UserRole+1); - toAdd.push_back(valueItem); - } - - - if (value.mSource == MaterialProperty::Inherited_Unchanged) - { - QColor color = ui->configurationView->palette().color(QPalette::Disabled, QPalette::WindowText); - keyItem->setData(color, Qt::ForegroundRole); - if (valueItem) - valueItem->setData(color, Qt::ForegroundRole); - } - if (value.mType == MaterialProperty::Boolean && valueItem) - { - valueItem->setCheckable(true); - valueItem->setCheckState((value.mValue == "true") ? Qt::Checked : Qt::Unchecked); - } - - parent->appendRow(toAdd); - - if (scrollTo) - ui->materialView->scrollTo(mMaterialSortModel->mapFromSource(keyItem->index())); -} - -void sh::MainWindow::buildConfigurationModel(ConfigurationQuery *data) -{ - while (mConfigurationModel->rowCount()) - mConfigurationModel->removeRow(0); - for (std::map::iterator it = data->mProperties.begin(); - it != data->mProperties.end(); ++it) - { - QList toAdd; - QStandardItem* name = new QStandardItem(QString::fromStdString(it->first)); - name->setFlags(name->flags() &= ~Qt::ItemIsEditable); - QStandardItem* value = new QStandardItem(QString::fromStdString(it->second)); - toAdd.push_back(name); - toAdd.push_back(value); - mConfigurationModel->appendRow(toAdd); - } - - // add items that are in global settings, but not in this configuration (with a "inactive" color) - for (std::map::const_iterator it = mState.mGlobalSettingsMap.begin(); - it != mState.mGlobalSettingsMap.end(); ++it) - { - if (data->mProperties.find(it->first) == data->mProperties.end()) - { - QColor color = ui->configurationView->palette().color(QPalette::Disabled, QPalette::WindowText); - QList toAdd; - QStandardItem* name = new QStandardItem(QString::fromStdString(it->first)); - name->setFlags(name->flags() &= ~Qt::ItemIsEditable); - name->setData(color, Qt::ForegroundRole); - QStandardItem* value = new QStandardItem(QString::fromStdString(it->second)); - value->setData(color, Qt::ForegroundRole); - toAdd.push_back(name); - toAdd.push_back(value); - mConfigurationModel->appendRow(toAdd); - } - } -} - -void sh::MainWindow::on_actionCreatePass_triggered() -{ - QString material = getSelectedMaterial(); - if (!material.isEmpty()) - { - addProperty(mMaterialPropertyModel->invisibleRootItem(), - "pass", MaterialProperty("", MaterialProperty::Object, MaterialProperty::None), true); - - queueAction (new ActionCreatePass(material.toStdString())); - } -} - -void sh::MainWindow::on_actionDeleteProperty_triggered() -{ - QModelIndex selectedIndex = mMaterialSortModel->mapToSource(ui->materialView->selectionModel()->currentIndex()); - QString material = getSelectedMaterial(); - if (material.isEmpty()) - return; - - mIgnoreMaterialPropertyChange = true; - - if (getPropertyKey(selectedIndex) == "pass") - { - // delete whole pass - int passIndex; - getContext(selectedIndex, &passIndex, NULL); - if (passIndex == 0) - { - QMessageBox msgBox; - msgBox.setText("The first pass can not be deleted."); - msgBox.exec(); - } - else - { - queueAction(new ActionDeletePass(material.toStdString(), passIndex)); - mMaterialPropertyModel->removeRow(selectedIndex.row(), selectedIndex.parent()); - } - } - else if (getPropertyKey(selectedIndex) == "texture_unit") - { - // delete whole texture unit - int passIndex, textureIndex; - getContext(selectedIndex, &passIndex, &textureIndex); - queueAction(new ActionDeleteTextureUnit(material.toStdString(), passIndex, textureIndex)); - mMaterialPropertyModel->removeRow(selectedIndex.row(), selectedIndex.parent()); - } - else if (!selectedIndex.parent().isValid()) - { - // top level material property - MaterialProperty::Source source = static_cast( - mMaterialPropertyModel->itemFromIndex(selectedIndex)->data(Qt::UserRole+1).toInt()); - if (source == MaterialProperty::Inherited_Unchanged) - { - QMessageBox msgBox; - msgBox.setText("Inherited properties can not be deleted."); - msgBox.exec(); - } - else - { - queueAction(new ActionDeleteMaterialProperty( - material.toStdString(), getPropertyKey(selectedIndex))); - std::cout << "source is " << source << std::endl; - if (source == MaterialProperty::Inherited_Changed) - { - QColor inactiveColor = ui->materialView->palette().color(QPalette::Disabled, QPalette::WindowText); - mMaterialPropertyModel->item(selectedIndex.row(), 0) - ->setData(QVariant(MaterialProperty::Inherited_Unchanged), Qt::UserRole+1); - mMaterialPropertyModel->item(selectedIndex.row(), 0) - ->setData(inactiveColor, Qt::ForegroundRole); - mMaterialPropertyModel->item(selectedIndex.row(), 1) - ->setData(QVariant(MaterialProperty::Inherited_Unchanged), Qt::UserRole+1); - mMaterialPropertyModel->item(selectedIndex.row(), 1) - ->setData(inactiveColor, Qt::ForegroundRole); - - // make sure to update the property's value - requestQuery(new sh::MaterialPropertyQuery(material.toStdString(), getPropertyKey(selectedIndex))); - } - else - mMaterialPropertyModel->removeRow(selectedIndex.row()); - } - } - else if (selectedIndex.parent().data().toString() == "pass") - { - // pass property - int passIndex; - getContext(selectedIndex, &passIndex, NULL); - queueAction(new ActionDeletePassProperty( - material.toStdString(), passIndex, getPropertyKey(selectedIndex))); - mMaterialPropertyModel->removeRow(selectedIndex.row(), selectedIndex.parent()); - } - else if (selectedIndex.parent().data().toString() == "shader_properties") - { - // shader property - int passIndex; - getContext(selectedIndex, &passIndex, NULL); - queueAction(new ActionDeleteShaderProperty( - material.toStdString(), passIndex, getPropertyKey(selectedIndex))); - mMaterialPropertyModel->removeRow(selectedIndex.row(), selectedIndex.parent()); - } - else if (selectedIndex.parent().data().toString() == "texture_unit") - { - // texture property - int passIndex, textureIndex; - getContext(selectedIndex, &passIndex, &textureIndex); - queueAction(new ActionDeleteTextureProperty( - material.toStdString(), passIndex, textureIndex, getPropertyKey(selectedIndex))); - mMaterialPropertyModel->removeRow(selectedIndex.row(), selectedIndex.parent()); - } - mIgnoreMaterialPropertyChange = false; -} - -void sh::MainWindow::on_actionNewProperty_triggered() -{ - QModelIndex selectedIndex = mMaterialSortModel->mapToSource(ui->materialView->selectionModel()->currentIndex()); - QString material = getSelectedMaterial(); - if (material.isEmpty()) - return; - - AddPropertyDialog* dialog = new AddPropertyDialog(this); - dialog->exec(); - QString propertyName = dialog->mName; - QString defaultValue = ""; - - /// \todo check if this property name exists already - - if (!propertyName.isEmpty()) - { - int passIndex, textureIndex; - bool isInPass, isInTextureUnit; - getContext(selectedIndex, &passIndex, &textureIndex, &isInPass, &isInTextureUnit); - - QList items; - QStandardItem* keyItem = new QStandardItem(propertyName); - keyItem->setFlags(keyItem->flags() &= ~Qt::ItemIsEditable); - items << keyItem; - items << new QStandardItem(defaultValue); - - // figure out which item the new property should be a child of - QModelIndex parentIndex = selectedIndex; - if (selectedIndex.data(Qt::UserRole) != MaterialProperty::Object) - parentIndex = selectedIndex.parent(); - QStandardItem* parentItem; - if (!parentIndex.isValid()) - parentItem = mMaterialPropertyModel->invisibleRootItem(); - else - parentItem = mMaterialPropertyModel->itemFromIndex(parentIndex); - - if (isInTextureUnit) - { - queueAction(new ActionSetTextureProperty( - material.toStdString(), passIndex, textureIndex, propertyName.toStdString(), defaultValue.toStdString())); - } - else if (isInPass) - { - if (selectedIndex.parent().child(selectedIndex.row(),0).data().toString() == "shader_properties" - || selectedIndex.parent().data().toString() == "shader_properties") - { - queueAction(new ActionSetShaderProperty( - material.toStdString(), passIndex, propertyName.toStdString(), defaultValue.toStdString())); - } - else - { - queueAction(new ActionSetPassProperty( - material.toStdString(), passIndex, propertyName.toStdString(), defaultValue.toStdString())); - } - } - else - { - queueAction(new ActionSetMaterialProperty( - material.toStdString(), propertyName.toStdString(), defaultValue.toStdString())); - } - - addProperty(parentItem, propertyName.toStdString(), - MaterialProperty (defaultValue.toStdString(), MaterialProperty::Misc, MaterialProperty::Normal), true); - - /// \todo scroll to newly added property - } -} - -void sh::MainWindow::on_actionCreateTextureUnit_triggered() -{ - QString material = getSelectedMaterial(); - if (material.isEmpty()) - return; - - QInputDialog dialog(this); - - QString text = QInputDialog::getText(this, tr("New texture unit"), - tr("Texture unit name (for referencing in shaders):")); - if (!text.isEmpty()) - { - QModelIndex selectedIndex = mMaterialSortModel->mapToSource(ui->materialView->selectionModel()->currentIndex()); - int passIndex; - getContext(selectedIndex, &passIndex, NULL); - queueAction(new ActionCreateTextureUnit(material.toStdString(), passIndex, text.toStdString())); - - // add to model - int index = 0; - for (int i=0; irowCount(); ++i) - { - if (mMaterialPropertyModel->data(mMaterialPropertyModel->index(i, 0)).toString() == QString("pass")) - { - if (index == passIndex) - { - addProperty(mMaterialPropertyModel->itemFromIndex(mMaterialPropertyModel->index(i, 0)), - "texture_unit", MaterialProperty(text.toStdString(), MaterialProperty::Object), true); - break; - } - - ++index; - } - } - } -} - -void sh::MainWindow::on_clearButton_clicked() -{ - ui->errorLog->clear(); -} - -void sh::MainWindow::on_tabWidget_currentChanged(int index) -{ - QColor color = ui->tabWidget->palette().color(QPalette::Normal, QPalette::WindowText); - - if (index == 3) - ui->tabWidget->tabBar()->setTabTextColor(3, color); -} diff --git a/extern/shiny/Editor/MainWindow.hpp b/extern/shiny/Editor/MainWindow.hpp deleted file mode 100644 index 3f0dc295c..000000000 --- a/extern/shiny/Editor/MainWindow.hpp +++ /dev/null @@ -1,139 +0,0 @@ -#ifndef SHINY_EDITOR_MAINWINDOW_HPP -#define SHINY_EDITOR_MAINWINDOW_HPP - -#include - -#include -#include -#include - -#include - -#include "Actions.hpp" -#include "Query.hpp" - -#include "PropertySortModel.hpp" - -namespace Ui { -class MainWindow; -} - -namespace sh -{ - -struct SynchronizationState; - - -/** - * @brief A snapshot of the material system's state. Lock the mUpdateMutex before accessing. - */ -struct MaterialSystemState -{ - std::vector mMaterialList; - - std::map mGlobalSettingsMap; - - std::vector mConfigurationList; - - std::vector mMaterialFiles; - std::vector mConfigurationFiles; - - std::vector mShaderSets; - - std::string mErrors; -}; - -class MainWindow : public QMainWindow -{ - Q_OBJECT - -public: - explicit MainWindow(QWidget *parent = 0); - ~MainWindow(); - - // really should be an std::atomic - volatile bool mRequestShowWindow; - // dito - volatile bool mRequestExit; - - SynchronizationState* mSync; - - /// \todo Is there a better way to ignore manual model changes? - bool mIgnoreGlobalSettingChange; - bool mIgnoreConfigurationChange; - bool mIgnoreMaterialChange; - bool mIgnoreMaterialPropertyChange; - - std::queue mActionQueue; - std::vector mQueries; - - MaterialSystemState mState; - -private: - Ui::MainWindow *ui; - - // material tab - QStringListModel* mMaterialModel; - QSortFilterProxyModel* mMaterialProxyModel; - - QStandardItemModel* mMaterialPropertyModel; - PropertySortModel* mMaterialSortModel; - - // global settings tab - QStandardItemModel* mGlobalSettingsModel; - - // configuration tab - QStandardItemModel* mConfigurationModel; - - void queueAction(Action* action); - void requestQuery(Query* query); - - void buildMaterialModel (MaterialQuery* data); - void buildConfigurationModel (ConfigurationQuery* data); - - QString getSelectedMaterial(); - - /// get the context of an index in the material property model - void getContext(QModelIndex index, int* passIndex, int* textureIndex, bool* isInPass=NULL, bool* isInTextureUnit=NULL); - - std::string getPropertyKey(QModelIndex index); - std::string getPropertyValue(QModelIndex index); - - void addProperty (QStandardItem* parent, const std::string& key, MaterialProperty value, bool scrollTo=false); - -protected: - void closeEvent(QCloseEvent *event); - -public slots: - void onIdle(); - - void onMaterialSelectionChanged (const QModelIndex & current, const QModelIndex & previous); - void onConfigurationSelectionChanged (const QString& current); - - void onGlobalSettingChanged (QStandardItem* item); - void onConfigurationChanged (QStandardItem* item); - void onMaterialPropertyChanged (QStandardItem* item); - - void onContextMenuRequested(const QPoint& point); - -private slots: - void on_lineEdit_textEdited(const QString &arg1); - void on_actionSave_triggered(); - void on_actionNewMaterial_triggered(); - void on_actionDeleteMaterial_triggered(); - void on_actionQuit_triggered(); - void on_actionNewConfiguration_triggered(); - void on_actionDeleteConfiguration_triggered(); - void on_actionDeleteConfigurationProperty_triggered(); - void on_actionCloneMaterial_triggered(); - void on_actionCreatePass_triggered(); - void on_actionDeleteProperty_triggered(); - void on_actionNewProperty_triggered(); - void on_actionCreateTextureUnit_triggered(); - void on_clearButton_clicked(); - void on_tabWidget_currentChanged(int index); -}; - -} - -#endif // MAINWINDOW_HPP diff --git a/extern/shiny/Editor/NewMaterialDialog.cpp b/extern/shiny/Editor/NewMaterialDialog.cpp deleted file mode 100644 index f1a716a9f..000000000 --- a/extern/shiny/Editor/NewMaterialDialog.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include "NewMaterialDialog.hpp" -#include "ui_newmaterialdialog.h" - -NewMaterialDialog::NewMaterialDialog(QWidget *parent) : - QDialog(parent), - ui(new Ui::NewMaterialDialog) -{ - ui->setupUi(this); -} - -NewMaterialDialog::~NewMaterialDialog() -{ - delete ui; -} diff --git a/extern/shiny/Editor/NewMaterialDialog.hpp b/extern/shiny/Editor/NewMaterialDialog.hpp deleted file mode 100644 index 2a20bbb39..000000000 --- a/extern/shiny/Editor/NewMaterialDialog.hpp +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef NEWMATERIALDIALOG_HPP -#define NEWMATERIALDIALOG_HPP - -#include - -namespace Ui { -class NewMaterialDialog; -} - -class NewMaterialDialog : public QDialog -{ - Q_OBJECT - -public: - explicit NewMaterialDialog(QWidget *parent = 0); - ~NewMaterialDialog(); - -private: - Ui::NewMaterialDialog *ui; -}; - -#endif // NEWMATERIALDIALOG_HPP diff --git a/extern/shiny/Editor/PropertySortModel.cpp b/extern/shiny/Editor/PropertySortModel.cpp deleted file mode 100644 index 637fe11b0..000000000 --- a/extern/shiny/Editor/PropertySortModel.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include "PropertySortModel.hpp" - -#include "Query.hpp" - -#include -sh::PropertySortModel::PropertySortModel(QObject *parent) - : QSortFilterProxyModel(parent) -{ -} - -bool sh::PropertySortModel::lessThan(const QModelIndex &left, const QModelIndex &right) const -{ - if (left.data(Qt::UserRole+1).toInt() != 0 && right.data(Qt::UserRole+1).toInt() != 0) - { - int sourceL = left.data(Qt::UserRole+1).toInt(); - int sourceR = right.data(Qt::UserRole+1).toInt(); - - if (sourceL > sourceR) - return true; - else if (sourceR > sourceL) - return false; - } - - int typeL = left.data(Qt::UserRole).toInt(); - int typeR = right.data(Qt::UserRole).toInt(); - - if (typeL > typeR) - return true; - else if (typeR > typeL) - return false; - - QString nameL = left.data().toString(); - QString nameR = right.data().toString(); - return nameL > nameR; -} diff --git a/extern/shiny/Editor/PropertySortModel.hpp b/extern/shiny/Editor/PropertySortModel.hpp deleted file mode 100644 index f96927764..000000000 --- a/extern/shiny/Editor/PropertySortModel.hpp +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef SHINY_EDITOR_PROPERTYSORTMODEL_H -#define SHINY_EDITOR_PROPERTYSORTMODEL_H - -#include - -namespace sh -{ - - class PropertySortModel : public QSortFilterProxyModel - { - Q_OBJECT - - public: - PropertySortModel(QObject* parent); - protected: - bool lessThan(const QModelIndex &left, const QModelIndex &right) const; - }; - -} - -#endif diff --git a/extern/shiny/Editor/Query.cpp b/extern/shiny/Editor/Query.cpp deleted file mode 100644 index ccf07b62b..000000000 --- a/extern/shiny/Editor/Query.cpp +++ /dev/null @@ -1,134 +0,0 @@ -#include "Query.hpp" - -#include "../Main/Factory.hpp" - -namespace sh -{ - -void Query::execute() -{ - executeImpl(); - mDone = true; -} - -ConfigurationQuery::ConfigurationQuery(const std::string &name) - : mName(name) -{ -} - -void ConfigurationQuery::executeImpl() -{ - sh::Factory::getInstance().listConfigurationSettings(mName, mProperties); -} - -void MaterialQuery::executeImpl() -{ - sh::MaterialInstance* instance = sh::Factory::getInstance().getMaterialInstance(mName); - - if (instance->getParent()) - mParent = static_cast(instance->getParent())->getName(); - - // add the inherited properties - sh::PropertySetGet* parent = instance; - std::vector inheritedPropertiesVector; - while (parent->getParent()) - { - parent = parent->getParent(); - const sh::PropertyMap& parentProperties = parent->listProperties(); - - for (PropertyMap::const_iterator it = parentProperties.begin(); it != parentProperties.end(); ++it) - { - MaterialProperty::Source source = MaterialProperty::Inherited_Unchanged; - MaterialProperty::Type type = getType(it->first, parent->getProperty(it->first)); - mProperties[it->first] = MaterialProperty ( - retrieveValue(parent->getProperty(it->first), NULL).get(), - type, source); - inheritedPropertiesVector.push_back(it->first); - } - } - - // add our properties - const sh::PropertyMap& ourProperties = instance->listProperties(); - for (PropertyMap::const_iterator it = ourProperties.begin(); it != ourProperties.end(); ++it) - { - MaterialProperty::Source source = - (std::find(inheritedPropertiesVector.begin(), inheritedPropertiesVector.end(), it->first) - != inheritedPropertiesVector.end()) ? - MaterialProperty::Inherited_Changed : MaterialProperty::Normal; - MaterialProperty::Type type = getType(it->first, instance->getProperty(it->first)); - mProperties[it->first] = MaterialProperty ( - retrieveValue(instance->getProperty(it->first), NULL).get(), - type, source); - } - - std::vector* passes = instance->getPasses(); - for (std::vector::iterator it = passes->begin(); it != passes->end(); ++it) - { - mPasses.push_back(PassInfo()); - - const sh::PropertyMap& passProperties = it->listProperties(); - for (PropertyMap::const_iterator pit = passProperties.begin(); pit != passProperties.end(); ++pit) - { - PropertyValuePtr property = it->getProperty(pit->first); - MaterialProperty::Type type = getType(pit->first, property); - if (typeid(*property).name() == typeid(sh::LinkedValue).name()) - mPasses.back().mProperties[pit->first] = MaterialProperty("$" + property->_getStringValue(), type); - else - mPasses.back().mProperties[pit->first] = MaterialProperty( - retrieveValue(property, NULL).get(), type); - } - - const sh::PropertyMap& shaderProperties = it->mShaderProperties.listProperties(); - for (PropertyMap::const_iterator pit = shaderProperties.begin(); pit != shaderProperties.end(); ++pit) - { - PropertyValuePtr property = it->mShaderProperties.getProperty(pit->first); - MaterialProperty::Type type = getType(pit->first, property); - if (typeid(*property).name() == typeid(sh::LinkedValue).name()) - mPasses.back().mShaderProperties[pit->first] = MaterialProperty("$" + property->_getStringValue(), type); - else - mPasses.back().mShaderProperties[pit->first] = MaterialProperty( - retrieveValue(property, NULL).get(), type); - } - - std::vector* texUnits = &it->mTexUnits; - for (std::vector::iterator tIt = texUnits->begin(); tIt != texUnits->end(); ++tIt) - { - mPasses.back().mTextureUnits.push_back(TextureUnitInfo()); - mPasses.back().mTextureUnits.back().mName = tIt->getName(); - const sh::PropertyMap& unitProperties = tIt->listProperties(); - for (PropertyMap::const_iterator pit = unitProperties.begin(); pit != unitProperties.end(); ++pit) - { - PropertyValuePtr property = tIt->getProperty(pit->first); - MaterialProperty::Type type = getType(pit->first, property); - if (typeid(*property).name() == typeid(sh::LinkedValue).name()) - mPasses.back().mTextureUnits.back().mProperties[pit->first] = MaterialProperty( - "$" + property->_getStringValue(), MaterialProperty::Linked); - else - mPasses.back().mTextureUnits.back().mProperties[pit->first] = MaterialProperty( - retrieveValue(property, NULL).get(), type); - } - } - } -} - -MaterialProperty::Type MaterialQuery::getType(const std::string &key, PropertyValuePtr value) -{ - if (typeid(*value).name() == typeid(sh::LinkedValue).name()) - return MaterialProperty::Linked; - - if (key == "vertex_program" || key == "fragment_program") - return MaterialProperty::Shader; - - std::string valueStr = retrieveValue(value, NULL).get(); - - if (valueStr == "false" || valueStr == "true") - return MaterialProperty::Boolean; -} - -void MaterialPropertyQuery::executeImpl() -{ - sh::MaterialInstance* m = sh::Factory::getInstance().getMaterialInstance(mName); - mValue = retrieveValue(m->getProperty(mPropertyName), m).get(); -} - -} diff --git a/extern/shiny/Editor/Query.hpp b/extern/shiny/Editor/Query.hpp deleted file mode 100644 index d98c8c9b2..000000000 --- a/extern/shiny/Editor/Query.hpp +++ /dev/null @@ -1,121 +0,0 @@ -#ifndef SH_QUERY_H -#define SH_QUERY_H - -#include -#include -#include - -#include "../Main/PropertyBase.hpp" - -namespace sh -{ - -class Query -{ -public: - Query() - : mDone(false) {} - virtual ~Query() {} - - void execute(); - - bool mDone; - -protected: - virtual void executeImpl() = 0; -}; - -class ConfigurationQuery : public Query -{ -public: - ConfigurationQuery(const std::string& name); - - std::map mProperties; -protected: - std::string mName; - virtual void executeImpl(); -}; - - -struct MaterialProperty -{ - - enum Type - { - Texture, - Color, - Boolean, - Shader, - Misc, - Linked, - Object // child object, i.e. pass, texture unit, shader properties - }; - - enum Source - { - Normal, - Inherited_Changed, - Inherited_Unchanged, - None // there is no property source (e.g. a pass, which does not have a name) - }; - - MaterialProperty() {} - MaterialProperty (const std::string& value, Type type, Source source=Normal) - : mValue(value), mType(type), mSource(source) {} - - std::string mValue; - Type mType; - Source mSource; -}; - - -struct TextureUnitInfo -{ - std::string mName; - std::map mProperties; -}; - -struct PassInfo -{ - std::map mShaderProperties; - - std::map mProperties; - std::vector mTextureUnits; -}; - -class MaterialQuery : public Query -{ -public: - MaterialQuery(const std::string& name) - : mName(name) {} - - std::string mParent; - std::vector mPasses; - std::map mProperties; - -protected: - std::string mName; - virtual void executeImpl(); - - MaterialProperty::Type getType (const std::string& key, PropertyValuePtr value); -}; - -class MaterialPropertyQuery : public Query -{ -public: - MaterialPropertyQuery(const std::string& name, const std::string& propertyName) - : mName(name), mPropertyName(propertyName) - { - } - - std::string mValue; - - std::string mName; - std::string mPropertyName; -protected: - virtual void executeImpl(); -}; - -} - -#endif diff --git a/extern/shiny/Editor/addpropertydialog.ui b/extern/shiny/Editor/addpropertydialog.ui deleted file mode 100644 index 63de7d141..000000000 --- a/extern/shiny/Editor/addpropertydialog.ui +++ /dev/null @@ -1,118 +0,0 @@ - - - AddPropertyDialog - - - - 0 - 0 - 257 - 133 - - - - Dialog - - - - - - - - - - - - - Property name - - - - - - - Editing widget - - - - - - - - Checkbox - - - - - Shader - - - - - Color - - - - - Texture - - - - - Other - - - - - - - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - - - - - - buttonBox - accepted() - AddPropertyDialog - accept() - - - 248 - 254 - - - 157 - 274 - - - - - buttonBox - rejected() - AddPropertyDialog - reject() - - - 316 - 260 - - - 286 - 274 - - - - - diff --git a/extern/shiny/Editor/mainwindow.ui b/extern/shiny/Editor/mainwindow.ui deleted file mode 100644 index b27c8357d..000000000 --- a/extern/shiny/Editor/mainwindow.ui +++ /dev/null @@ -1,420 +0,0 @@ - - - MainWindow - - - - 0 - 0 - 647 - 512 - - - - MainWindow - - - - - - - 0 - - - - - - - Materials - - - - - - Qt::Horizontal - - - - - - - - - - Search - - - - - - - - 0 - 0 - - - - - - - - - 0 - 0 - - - - - 16 - 16 - - - - - - - - - - - - - - - - 1 - 0 - - - - - - - - - 1 - 0 - - - - - 16 - 16 - - - - Qt::ToolButtonIconOnly - - - - - - - - - - - - - - Global settings - - - - - - - - - - Configurations - - - - - - Qt::Horizontal - - - - - - - - - - - 16 - 16 - - - - - - - - - - - - - - - - - - 16 - 16 - - - - - - - - - - - - - - Errors - - - - - - - - true - - - - - - - - 0 - 0 - - - - Clear - - - - - - - - - - - - - - - - - - - - - 0 - 0 - 647 - 25 - - - - false - - - - File - - - - - - - Material - - - - - - - - - History - - - - - - - - - - - - - - Quit - - - - - - - - - - Save - - - Save all - - - - - - - - - - Delete - - - Delete selected material - - - - - Change parent... - - - - - - - - - - New - - - Create a new material - - - - - - - - - - Clone - - - Clone selected material - - - - - - - - - - Delete - - - Delete selected configuration - - - Del - - - - - - - - - - New - - - Create a new configuration - - - - - - - - - - Delete - - - Delete property - - - - - - - - - - Delete - - - Delete item - - - - - - - - - - New property - - - - - - - - - - Create pass - - - - - - - - - - Create texture unit - - - - - - sh::ColoredTabWidget - QTabWidget -

ColoredTabWidget.hpp
- 1 - - - - - diff --git a/extern/shiny/Editor/newmaterialdialog.ui b/extern/shiny/Editor/newmaterialdialog.ui deleted file mode 100644 index f24561cf7..000000000 --- a/extern/shiny/Editor/newmaterialdialog.ui +++ /dev/null @@ -1,98 +0,0 @@ - - - NewMaterialDialog - - - - 0 - 0 - 385 - 198 - - - - Dialog - - - - - - - - Name - - - - - - - Parent material - - - - - - - - - - - - - File - - - - - - - - - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - - - - buttonBox - accepted() - NewMaterialDialog - accept() - - - 248 - 254 - - - 157 - 274 - - - - - buttonBox - rejected() - NewMaterialDialog - reject() - - - 316 - 260 - - - 286 - 274 - - - - - diff --git a/extern/shiny/Extra/core.h b/extern/shiny/Extra/core.h deleted file mode 100644 index 1687d5ed1..000000000 --- a/extern/shiny/Extra/core.h +++ /dev/null @@ -1,174 +0,0 @@ -#if SH_HLSL == 1 || SH_CG == 1 - - #define shTexture2D sampler2D - #define shTexture3D sampler3D - #define shSample(tex, coord) tex2D(tex, coord) - #define shCubicSample(tex, coord) texCUBE(tex, coord) - #define shLerp(a, b, t) lerp(a, b, t) - #define shSaturate(a) saturate(a) - - #define shSampler2D(name) , uniform sampler2D name : register(s@shCounter(0)) @shUseSampler(name) - - #define shSampler3D(name) , uniform sampler3D name : register(s@shCounter(0)) @shUseSampler(name) - - #define shSamplerCube(name) , uniform samplerCUBE name : register(s@shCounter(0)) @shUseSampler(name) - - #define shMatrixMult(m, v) mul(m, v) - - #define shUniform(type, name) , uniform type name - - #define shTangentInput(type) , in type tangent : TANGENT - #define shVertexInput(type, name) , in type name : TEXCOORD@shCounter(1) - #define shInput(type, name) , in type name : TEXCOORD@shCounter(1) - #define shOutput(type, name) , out type name : TEXCOORD@shCounter(2) - - #define shNormalInput(type) , in type normal : NORMAL - - #define shColourInput(type) , in type colour : COLOR - - #ifdef SH_VERTEX_SHADER - - #define shOutputPosition oPosition - #define shInputPosition iPosition - - - #define SH_BEGIN_PROGRAM \ - void main( \ - float4 iPosition : POSITION \ - , out float4 oPosition : POSITION - - #define SH_START_PROGRAM \ - ) \ - - #endif - - #ifdef SH_FRAGMENT_SHADER - - #define shOutputColour(num) oColor##num - - #define shDeclareMrtOutput(num) , out float4 oColor##num : COLOR##num - - #define SH_BEGIN_PROGRAM \ - void main( \ - out float4 oColor0 : COLOR - - #define SH_START_PROGRAM \ - ) \ - - #endif - -#endif - -#if SH_GLSL == 1 - - @version 120 - - #define float2 vec2 - #define float3 vec3 - #define float4 vec4 - #define int2 ivec2 - #define int3 ivec3 - #define int4 ivec4 - #define shTexture2D sampler2D - #define shTexture3D sampler3D - #define shSample(tex, coord) texture2D(tex, coord) - #define shCubicSample(tex, coord) textureCube(tex, coord) - #define shLerp(a, b, t) mix(a, b, t) - #define shSaturate(a) clamp(a, 0.0, 1.0) - - #define shUniform(type, name) uniform type name; - - #define shSampler2D(name) uniform sampler2D name; @shUseSampler(name) - - #define shSampler3D(name) uniform sampler3D name; @shUseSampler(name) - - #define shSamplerCube(name) uniform samplerCube name; @shUseSampler(name) - - #define shMatrixMult(m, v) (m * v) - - #define shOutputPosition gl_Position - - #define float4x4 mat4 - #define float3x3 mat3 - - // GLSL 1.3 - #if 0 - - // automatically recognized by ogre when the input name equals this - #define shInputPosition vertex - - #define shOutputColour(num) oColor##num - - #define shTangentInput(type) in type tangent; - #define shVertexInput(type, name) in type name; - #define shInput(type, name) in type name; - #define shOutput(type, name) out type name; - - // automatically recognized by ogre when the input name equals this - #define shNormalInput(type) in type normal; - #define shColourInput(type) in type colour; - - #ifdef SH_VERTEX_SHADER - - #define SH_BEGIN_PROGRAM \ - in float4 vertex; - #define SH_START_PROGRAM \ - void main(void) - - #endif - - #ifdef SH_FRAGMENT_SHADER - - #define shDeclareMrtOutput(num) out vec4 oColor##num; - - #define SH_BEGIN_PROGRAM \ - out float4 oColor0; - #define SH_START_PROGRAM \ - void main(void) - - - #endif - - #endif - - // GLSL 1.2 - - #if 1 - - // automatically recognized by ogre when the input name equals this - #define shInputPosition vertex - - #define shOutputColour(num) gl_FragData[num] - - #define shTangentInput(type) attribute type tangent; - #define shVertexInput(type, name) attribute type name; - #define shInput(type, name) varying type name; - #define shOutput(type, name) varying type name; - - // automatically recognized by ogre when the input name equals this - #define shNormalInput(type) attribute type normal; - #define shColourInput(type) attribute type colour; - - #ifdef SH_VERTEX_SHADER - - #define SH_BEGIN_PROGRAM \ - attribute vec4 vertex; - #define SH_START_PROGRAM \ - void main(void) - - #endif - - #ifdef SH_FRAGMENT_SHADER - - #define shDeclareMrtOutput(num) - - #define SH_BEGIN_PROGRAM - - #define SH_START_PROGRAM \ - void main(void) - - - #endif - - #endif -#endif diff --git a/extern/shiny/License.txt b/extern/shiny/License.txt deleted file mode 100644 index d89bcf3ad..000000000 --- a/extern/shiny/License.txt +++ /dev/null @@ -1,9 +0,0 @@ -Copyright (c) 2012 - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - diff --git a/extern/shiny/Main/Factory.cpp b/extern/shiny/Main/Factory.cpp deleted file mode 100644 index d7c4234cb..000000000 --- a/extern/shiny/Main/Factory.cpp +++ /dev/null @@ -1,817 +0,0 @@ -#include "Factory.hpp" - -#include -#include - -#include -#include -#include - -#include "Platform.hpp" -#include "ScriptLoader.hpp" -#include "ShaderSet.hpp" -#include "MaterialInstanceTextureUnit.hpp" - -namespace sh -{ - Factory* Factory::sThis = 0; - const std::string Factory::mBinaryCacheName = "binaryCache"; - - Factory& Factory::getInstance() - { - assert (sThis); - return *sThis; - } - - Factory* Factory::getInstancePtr() - { - return sThis; - } - - Factory::Factory (Platform* platform) - : mPlatform(platform) - , mShadersEnabled(true) - , mShaderDebugOutputEnabled(false) - , mCurrentLanguage(Language_None) - , mListener(NULL) - , mCurrentConfiguration(NULL) - , mCurrentLodConfiguration(NULL) - , mReadMicrocodeCache(false) - , mWriteMicrocodeCache(false) - , mReadSourceCache(false) - , mWriteSourceCache(false) - { - assert (!sThis); - sThis = this; - - mPlatform->setFactory(this); - } - - void Factory::loadAllFiles() - { - assert(mCurrentLanguage != Language_None); - - try - { - if (boost::filesystem::exists (mPlatform->getCacheFolder () + "/lastModified.txt")) - { - std::ifstream file; - file.open(std::string(mPlatform->getCacheFolder () + "/lastModified.txt").c_str()); - - std::string line; - while (getline(file, line)) - { - std::string sourceFile = line; - - if (!getline(file, line)) - assert(0); - - int modified = boost::lexical_cast(line); - - mShadersLastModified[sourceFile] = modified; - } - } - } - catch (std::exception& e) - { - std::cerr << "Failed to load shader modification index: " << e.what() << std::endl; - mShadersLastModified.clear(); - } - - // load configurations - { - ScriptLoader shaderSetLoader(".configuration"); - ScriptLoader::loadAllFiles (&shaderSetLoader, mPlatform->getBasePath()); - std::map nodes = shaderSetLoader.getAllConfigScripts(); - for (std::map ::const_iterator it = nodes.begin(); - it != nodes.end(); ++it) - { - if (!(it->second->getName() == "configuration")) - { - std::cerr << "sh::Factory: Warning: Unsupported root node type \"" << it->second->getName() << "\" for file type .configuration" << std::endl; - break; - } - - Configuration newConfiguration; - newConfiguration.setParent(&mGlobalSettings); - newConfiguration.setSourceFile (it->second->mFileName); - - std::vector props = it->second->getChildren(); - for (std::vector::const_iterator propIt = props.begin(); propIt != props.end(); ++propIt) - { - std::string name = (*propIt)->getName(); - std::string val = (*propIt)->getValue(); - - newConfiguration.setProperty (name, makeProperty(val)); - } - - mConfigurations[it->first] = newConfiguration; - } - } - - // load lod configurations - { - ScriptLoader lodLoader(".lod"); - ScriptLoader::loadAllFiles (&lodLoader, mPlatform->getBasePath()); - std::map nodes = lodLoader.getAllConfigScripts(); - for (std::map ::const_iterator it = nodes.begin(); - it != nodes.end(); ++it) - { - if (!(it->second->getName() == "lod_configuration")) - { - std::cerr << "sh::Factory: Warning: Unsupported root node type \"" << it->second->getName() << "\" for file type .lod" << std::endl; - break; - } - - if (it->first == "0") - { - throw std::runtime_error("lod level 0 (max lod) can't have a configuration"); - } - - PropertySetGet newLod; - - std::vector props = it->second->getChildren(); - for (std::vector::const_iterator propIt = props.begin(); propIt != props.end(); ++propIt) - { - std::string name = (*propIt)->getName(); - std::string val = (*propIt)->getValue(); - - newLod.setProperty (name, makeProperty(val)); - } - - mLodConfigurations[boost::lexical_cast(it->first)] = newLod; - } - } - - // load shader sets - bool removeBinaryCache = reloadShaders(); - - // load materials - { - ScriptLoader materialLoader(".mat"); - ScriptLoader::loadAllFiles (&materialLoader, mPlatform->getBasePath()); - - std::map nodes = materialLoader.getAllConfigScripts(); - for (std::map ::const_iterator it = nodes.begin(); - it != nodes.end(); ++it) - { - if (!(it->second->getName() == "material")) - { - std::cerr << "sh::Factory: Warning: Unsupported root node type \"" << it->second->getName() << "\" for file type .mat" << std::endl; - break; - } - - MaterialInstance newInstance(it->first, this); - newInstance.create(mPlatform); - if (!mShadersEnabled) - newInstance.setShadersEnabled (false); - - newInstance.setSourceFile (it->second->mFileName); - - std::vector props = it->second->getChildren(); - for (std::vector::const_iterator propIt = props.begin(); propIt != props.end(); ++propIt) - { - std::string name = (*propIt)->getName(); - - std::string val = (*propIt)->getValue(); - - if (name == "pass") - { - MaterialInstancePass* newPass = newInstance.createPass(); - std::vector props2 = (*propIt)->getChildren(); - for (std::vector::const_iterator propIt2 = props2.begin(); propIt2 != props2.end(); ++propIt2) - { - std::string name2 = (*propIt2)->getName(); - std::string val2 = (*propIt2)->getValue(); - - if (name2 == "shader_properties") - { - std::vector shaderProps = (*propIt2)->getChildren(); - for (std::vector::const_iterator shaderPropIt = shaderProps.begin(); shaderPropIt != shaderProps.end(); ++shaderPropIt) - { - std::string val = (*shaderPropIt)->getValue(); - newPass->mShaderProperties.setProperty((*shaderPropIt)->getName(), makeProperty(val)); - } - } - else if (name2 == "texture_unit") - { - MaterialInstanceTextureUnit* newTex = newPass->createTextureUnit(val2); - std::vector texProps = (*propIt2)->getChildren(); - for (std::vector::const_iterator texPropIt = texProps.begin(); texPropIt != texProps.end(); ++texPropIt) - { - std::string val = (*texPropIt)->getValue(); - newTex->setProperty((*texPropIt)->getName(), makeProperty(val)); - } - } - else - newPass->setProperty((*propIt2)->getName(), makeProperty(val2)); - } - } - else if (name == "parent") - newInstance.setParentInstance(val); - else - newInstance.setProperty((*propIt)->getName(), makeProperty(val)); - } - - if (newInstance.hasProperty("create_configuration")) - { - std::string config = retrieveValue(newInstance.getProperty("create_configuration"), NULL).get(); - newInstance.createForConfiguration (config, 0); - } - - mMaterials.insert (std::make_pair(it->first, newInstance)); - } - - // now that all materials are loaded, replace the parent names with the actual pointers to parent - for (MaterialMap::iterator it = mMaterials.begin(); it != mMaterials.end(); ++it) - { - std::string parent = it->second.getParentInstance(); - if (parent != "") - { - if (mMaterials.find (it->second.getParentInstance()) == mMaterials.end()) - throw std::runtime_error ("Unable to find parent for material instance \"" + it->first + "\""); - it->second.setParent(&mMaterials.find(parent)->second); - } - } - } - - if (mPlatform->supportsShaderSerialization () && mReadMicrocodeCache && !removeBinaryCache) - { - std::string file = mPlatform->getCacheFolder () + "/" + mBinaryCacheName; - if (boost::filesystem::exists(file)) - { - mPlatform->deserializeShaders (file); - } - } - } - - Factory::~Factory () - { - mShaderSets.clear(); - - if (mPlatform->supportsShaderSerialization () && mWriteMicrocodeCache) - { - std::string file = mPlatform->getCacheFolder () + "/" + mBinaryCacheName; - mPlatform->serializeShaders (file); - } - - if (mReadSourceCache) - { - // save the last modified time of shader sources (as of when they were loaded) - std::ofstream file; - file.open(std::string(mPlatform->getCacheFolder () + "/lastModified.txt").c_str()); - - for (LastModifiedMap::const_iterator it = mShadersLastModifiedNew.begin(); it != mShadersLastModifiedNew.end(); ++it) - { - file << it->first << "\n" << it->second << std::endl; - } - - file.close(); - } - - delete mPlatform; - sThis = 0; - } - - MaterialInstance* Factory::searchInstance (const std::string& name) - { - MaterialMap::iterator it = mMaterials.find(name); - if (it != mMaterials.end()) - return &(it->second); - else - return NULL; - } - - MaterialInstance* Factory::findInstance (const std::string& name) - { - MaterialInstance* m = searchInstance(name); - assert (m); - return m; - } - - MaterialInstance* Factory::requestMaterial (const std::string& name, const std::string& configuration, unsigned short lodIndex) - { - MaterialInstance* m = searchInstance (name); - - if (configuration != "Default" && mConfigurations.find(configuration) == mConfigurations.end()) - return NULL; - - if (m) - { - if (m->createForConfiguration (configuration, 0)) - { - if (mListener) - mListener->materialCreated (m, configuration, 0); - } - else - return NULL; - - for (LodConfigurationMap::iterator it = mLodConfigurations.begin(); it != mLodConfigurations.end(); ++it) - { - if (m->createForConfiguration (configuration, it->first)) - { - if (mListener) - mListener->materialCreated (m, configuration, it->first); - } - else - return NULL; - } - } - return m; - } - - MaterialInstance* Factory::createMaterialInstance (const std::string& name, const std::string& parentInstance) - { - if (parentInstance != "" && mMaterials.find(parentInstance) == mMaterials.end()) - throw std::runtime_error ("trying to clone material that does not exist"); - - MaterialInstance newInstance(name, this); - - if (!mShadersEnabled) - newInstance.setShadersEnabled(false); - - if (parentInstance != "") - newInstance.setParent (&mMaterials.find(parentInstance)->second); - - newInstance.create(mPlatform); - - mMaterials.insert (std::make_pair(name, newInstance)); - - return &mMaterials.find(name)->second; - } - - void Factory::destroyMaterialInstance (const std::string& name) - { - if (mMaterials.find(name) != mMaterials.end()) - mMaterials.erase(name); - } - - void Factory::setShadersEnabled (bool enabled) - { - mShadersEnabled = enabled; - for (MaterialMap::iterator it = mMaterials.begin(); it != mMaterials.end(); ++it) - { - it->second.setShadersEnabled(enabled); - } - } - - void Factory::setGlobalSetting (const std::string& name, const std::string& value) - { - bool changed = true; - if (mGlobalSettings.hasProperty(name)) - changed = (retrieveValue(mGlobalSettings.getProperty(name), NULL).get() != value); - - mGlobalSettings.setProperty (name, makeProperty(new StringValue(value))); - - if (changed) - { - for (MaterialMap::iterator it = mMaterials.begin(); it != mMaterials.end(); ++it) - { - it->second.destroyAll(); - } - } - } - - void Factory::setSharedParameter (const std::string& name, PropertyValuePtr value) - { - mPlatform->setSharedParameter(name, value); - } - - ShaderSet* Factory::getShaderSet (const std::string& name) - { - if (mShaderSets.find(name) == mShaderSets.end()) - { - std::stringstream msg; - msg << "Shader '" << name << "' not found"; - throw std::runtime_error(msg.str()); - } - return &mShaderSets.find(name)->second; - } - - Platform* Factory::getPlatform () - { - return mPlatform; - } - - Language Factory::getCurrentLanguage () - { - return mCurrentLanguage; - } - - void Factory::setCurrentLanguage (Language lang) - { - bool changed = (mCurrentLanguage != lang); - mCurrentLanguage = lang; - - if (changed) - { - for (MaterialMap::iterator it = mMaterials.begin(); it != mMaterials.end(); ++it) - { - it->second.destroyAll(); - } - } - } - - void Factory::notifyConfigurationChanged() - { - for (MaterialMap::iterator it = mMaterials.begin(); it != mMaterials.end(); ++it) - { - it->second.destroyAll(); - } - } - - MaterialInstance* Factory::getMaterialInstance (const std::string& name) - { - return findInstance(name); - } - - void Factory::setTextureAlias (const std::string& alias, const std::string& realName) - { - mTextureAliases[alias] = realName; - - // update the already existing texture units - for (std::map::iterator it = mTextureAliasInstances.begin(); it != mTextureAliasInstances.end(); ++it) - { - if (it->second == alias) - { - it->first->setTextureName(realName); - } - } - } - - std::string Factory::retrieveTextureAlias (const std::string& name) - { - TextureAliasMap::iterator it = mTextureAliases.find(name); - if (it != mTextureAliases.end()) - return it->second; - else - return ""; - } - - Configuration* Factory::getConfiguration (const std::string& name) - { - return &mConfigurations[name]; - } - - void Factory::createConfiguration (const std::string& name) - { - mConfigurations[name].setParent (&mGlobalSettings); - } - - void Factory::destroyConfiguration(const std::string &name) - { - mConfigurations.erase(name); - } - - void Factory::registerLodConfiguration (int index, PropertySetGet configuration) - { - mLodConfigurations[index] = configuration; - } - - void Factory::setMaterialListener (MaterialListener* listener) - { - mListener = listener; - } - - void Factory::addTextureAliasInstance (const std::string& name, TextureUnitState* t) - { - mTextureAliasInstances[t] = name; - } - - void Factory::removeTextureAliasInstances (TextureUnitState* t) - { - mTextureAliasInstances.erase(t); - } - - void Factory::setActiveConfiguration (const std::string& configuration) - { - if (configuration == "Default") - mCurrentConfiguration = 0; - else - { - assert (mConfigurations.find(configuration) != mConfigurations.end()); - mCurrentConfiguration = &mConfigurations[configuration]; - } - } - - void Factory::setActiveLodLevel (int level) - { - if (level == 0) - mCurrentLodConfiguration = 0; - else - { - assert (mLodConfigurations.find(level) != mLodConfigurations.end()); - mCurrentLodConfiguration = &mLodConfigurations[level]; - } - } - - void Factory::setShaderDebugOutputEnabled (bool enabled) - { - mShaderDebugOutputEnabled = enabled; - } - - PropertySetGet* Factory::getCurrentGlobalSettings() - { - PropertySetGet* p = &mGlobalSettings; - - // current global settings are affected by active configuration & active lod configuration - - if (mCurrentConfiguration) - { - p = mCurrentConfiguration; - } - - if (mCurrentLodConfiguration) - { - mCurrentLodConfiguration->setParent(p); - p = mCurrentLodConfiguration; - } - - return p; - } - - void Factory::saveAll () - { - std::map files; - for (MaterialMap::iterator it = mMaterials.begin(); it != mMaterials.end(); ++it) - { - if (it->second.getSourceFile().empty()) - continue; - if (files.find(it->second.getSourceFile()) == files.end()) - { - /// \todo check if this is actually the same file, since there can be different paths to the same file - std::ofstream* stream = new std::ofstream(); - stream->open (it->second.getSourceFile().c_str()); - - files[it->second.getSourceFile()] = stream; - } - it->second.save (*files[it->second.getSourceFile()]); - } - - for (std::map::iterator it = files.begin(); it != files.end(); ++it) - { - delete it->second; - } - files.clear(); - - for (ConfigurationMap::iterator it = mConfigurations.begin(); it != mConfigurations.end(); ++it) - { - if (it->second.getSourceFile().empty()) - continue; - if (files.find(it->second.getSourceFile()) == files.end()) - { - /// \todo check if this is actually the same file, since there can be different paths to the same file - std::ofstream* stream = new std::ofstream(); - stream->open (it->second.getSourceFile().c_str()); - - files[it->second.getSourceFile()] = stream; - } - it->second.save (it->first, *files[it->second.getSourceFile()]); - } - - for (std::map::iterator it = files.begin(); it != files.end(); ++it) - { - delete it->second; - } - } - - void Factory::listMaterials(std::vector &out) - { - for (MaterialMap::iterator it = mMaterials.begin(); it != mMaterials.end(); ++it) - { - out.push_back(it->first); - } - } - - void Factory::listGlobalSettings(std::map &out) - { - const PropertyMap& properties = mGlobalSettings.listProperties(); - - for (PropertyMap::const_iterator it = properties.begin(); it != properties.end(); ++it) - { - out[it->first] = retrieveValue(mGlobalSettings.getProperty(it->first), NULL).get(); - } - } - - void Factory::listConfigurationSettings(const std::string& name, std::map &out) - { - const PropertyMap& properties = mConfigurations[name].listProperties(); - - for (PropertyMap::const_iterator it = properties.begin(); it != properties.end(); ++it) - { - out[it->first] = retrieveValue(mConfigurations[name].getProperty(it->first), NULL).get(); - } - } - - void Factory::listConfigurationNames(std::vector &out) - { - for (ConfigurationMap::const_iterator it = mConfigurations.begin(); it != mConfigurations.end(); ++it) - { - out.push_back(it->first); - } - } - - void Factory::listShaderSets(std::vector &out) - { - for (ShaderSetMap::const_iterator it = mShaderSets.begin(); it != mShaderSets.end(); ++it) - { - out.push_back(it->first); - } - } - - void Factory::_ensureMaterial(const std::string& name, const std::string& configuration) - { - MaterialInstance* m = searchInstance (name); - assert(m); - - m->createForConfiguration (configuration, 0); - - for (LodConfigurationMap::iterator it = mLodConfigurations.begin(); it != mLodConfigurations.end(); ++it) - { - m->createForConfiguration (configuration, it->first); - } - } - - bool Factory::removeCache(const std::string& pattern) - { - bool ret = false; - if ( boost::filesystem::exists(mPlatform->getCacheFolder()) - && boost::filesystem::is_directory(mPlatform->getCacheFolder())) - { - boost::filesystem::directory_iterator end_iter; - for( boost::filesystem::directory_iterator dir_iter(mPlatform->getCacheFolder()) ; dir_iter != end_iter ; ++dir_iter) - { - if (boost::filesystem::is_regular_file(dir_iter->status()) ) - { - boost::filesystem::path file = dir_iter->path(); - - std::string pathname = file.filename().string(); - - // get first part of filename, e.g. main_fragment_546457654 -> main_fragment - // there is probably a better method for this... - std::vector tokens; - boost::split(tokens, pathname, boost::is_any_of("_")); - tokens.erase(--tokens.end()); - std::string shaderName; - for (std::vector::const_iterator vector_iter = tokens.begin(); vector_iter != tokens.end();) - { - shaderName += *(vector_iter++); - if (vector_iter != tokens.end()) - shaderName += "_"; - } - - if (shaderName == pattern) - { - boost::filesystem::remove(file); - ret = true; - std::cout << "Removing outdated shader: " << file << std::endl; - } - } - } - } - return ret; - } - - bool Factory::reloadShaders() - { - mShaderSets.clear(); - notifyConfigurationChanged(); - - bool removeBinaryCache = false; - ScriptLoader shaderSetLoader(".shaderset"); - ScriptLoader::loadAllFiles (&shaderSetLoader, mPlatform->getBasePath()); - std::map nodes = shaderSetLoader.getAllConfigScripts(); - for (std::map ::const_iterator it = nodes.begin(); - it != nodes.end(); ++it) - { - if (!(it->second->getName() == "shader_set")) - { - std::cerr << "sh::Factory: Warning: Unsupported root node type \"" << it->second->getName() << "\" for file type .shaderset" << std::endl; - break; - } - - if (!it->second->findChild("profiles_cg")) - throw std::runtime_error ("missing \"profiles_cg\" field for \"" + it->first + "\""); - if (!it->second->findChild("profiles_hlsl")) - throw std::runtime_error ("missing \"profiles_hlsl\" field for \"" + it->first + "\""); - if (!it->second->findChild("source")) - throw std::runtime_error ("missing \"source\" field for \"" + it->first + "\""); - if (!it->second->findChild("type")) - throw std::runtime_error ("missing \"type\" field for \"" + it->first + "\""); - - std::vector profiles_cg; - boost::split (profiles_cg, it->second->findChild("profiles_cg")->getValue(), boost::is_any_of(" ")); - std::string cg_profile; - for (std::vector::iterator it2 = profiles_cg.begin(); it2 != profiles_cg.end(); ++it2) - { - if (mPlatform->isProfileSupported(*it2)) - { - cg_profile = *it2; - break; - } - } - - std::vector profiles_hlsl; - boost::split (profiles_hlsl, it->second->findChild("profiles_hlsl")->getValue(), boost::is_any_of(" ")); - std::string hlsl_profile; - for (std::vector::iterator it2 = profiles_hlsl.begin(); it2 != profiles_hlsl.end(); ++it2) - { - if (mPlatform->isProfileSupported(*it2)) - { - hlsl_profile = *it2; - break; - } - } - - std::string sourceAbsolute = mPlatform->getBasePath() + "/" + it->second->findChild("source")->getValue(); - std::string sourceRelative = it->second->findChild("source")->getValue(); - - ShaderSet newSet (it->second->findChild("type")->getValue(), cg_profile, hlsl_profile, - sourceAbsolute, - mPlatform->getBasePath(), - it->first, - &mGlobalSettings); - - int lastModified = boost::filesystem::last_write_time (boost::filesystem::path(sourceAbsolute)); - mShadersLastModifiedNew[sourceRelative] = lastModified; - if (mShadersLastModified.find(sourceRelative) != mShadersLastModified.end()) - { - if (mShadersLastModified[sourceRelative] != lastModified) - { - // delete any outdated shaders based on this shader set - if (removeCache (it->first)) - removeBinaryCache = true; - } - } - else - { - // if we get here, this is either the first run or a new shader file was added - // in both cases we can safely delete - if (removeCache (it->first)) - removeBinaryCache = true; - } - mShaderSets.insert(std::make_pair(it->first, newSet)); - } - - // new is now current - mShadersLastModified = mShadersLastModifiedNew; - - return removeBinaryCache; - } - - void Factory::doMonitorShaderFiles() - { - bool reload=false; - ScriptLoader shaderSetLoader(".shaderset"); - ScriptLoader::loadAllFiles (&shaderSetLoader, mPlatform->getBasePath()); - std::map nodes = shaderSetLoader.getAllConfigScripts(); - for (std::map ::const_iterator it = nodes.begin(); - it != nodes.end(); ++it) - { - - std::string sourceAbsolute = mPlatform->getBasePath() + "/" + it->second->findChild("source")->getValue(); - std::string sourceRelative = it->second->findChild("source")->getValue(); - - int lastModified = boost::filesystem::last_write_time (boost::filesystem::path(sourceAbsolute)); - if (mShadersLastModified.find(sourceRelative) != mShadersLastModified.end()) - { - if (mShadersLastModified[sourceRelative] != lastModified) - { - reload=true; - break; - } - } - } - if (reload) - reloadShaders(); - } - - void Factory::logError(const std::string &msg) - { - mErrorLog << msg << '\n'; - } - - std::string Factory::getErrorLog() - { - std::string errors = mErrorLog.str(); - mErrorLog.str(""); - return errors; - } - - void Factory::unloadUnreferencedMaterials() - { - for (MaterialMap::iterator it = mMaterials.begin(); it != mMaterials.end(); ++it) - { - if (it->second.getMaterial()->isUnreferenced()) - it->second.getMaterial()->unreferenceTextures(); - } - } - - void Configuration::save(const std::string& name, std::ofstream &stream) - { - stream << "configuration " << name << '\n'; - stream << "{\n"; - PropertySetGet::save(stream, "\t"); - stream << "}\n"; - } -} diff --git a/extern/shiny/Main/Factory.hpp b/extern/shiny/Main/Factory.hpp deleted file mode 100644 index 721b4af7d..000000000 --- a/extern/shiny/Main/Factory.hpp +++ /dev/null @@ -1,271 +0,0 @@ -#ifndef SH_FACTORY_H -#define SH_FACTORY_H - -#include -#include -#include - -#include "MaterialInstance.hpp" -#include "ShaderSet.hpp" -#include "Language.hpp" - -namespace sh -{ - class Platform; - - class Configuration : public PropertySetGet - { - public: - void setSourceFile (const std::string& file) { mSourceFile = file ; } - std::string getSourceFile () { return mSourceFile; } - - void save(const std::string& name, std::ofstream &stream); - - private: - std::string mSourceFile; - }; - - typedef std::map MaterialMap; - typedef std::map ShaderSetMap; - typedef std::map ConfigurationMap; - typedef std::map LodConfigurationMap; - typedef std::map LastModifiedMap; - - typedef std::map TextureAliasMap; - - /** - * @brief - * Allows you to be notified when a certain material was just created. Useful for changing material properties that you can't - * do in a .mat script (for example a series of animated textures) \n - * When receiving the event, you can get the platform material by calling m->getMaterial() - * and casting that to the platform specific material (e.g. for Ogre, sh::OgreMaterial) - */ - class MaterialListener - { - public: - virtual void materialCreated (MaterialInstance* m, const std::string& configuration, unsigned short lodIndex) = 0; - }; - - /** - * @brief - * The main interface class - */ - class Factory - { - public: - Factory(Platform* platform); - ///< @note Ownership of \a platform is transferred to this class, so you don't have to delete it. - - ~Factory(); - - /** - * Create a MaterialInstance, optionally copying all properties from \a parentInstance - * @param name name of the new instance - * @param name of the parent (optional) - * @return newly created instance - */ - MaterialInstance* createMaterialInstance (const std::string& name, const std::string& parentInstance = ""); - - /// @note It is safe to call this if the instance does not exist - void destroyMaterialInstance (const std::string& name); - - /// Use this to enable or disable shaders on-the-fly - void setShadersEnabled (bool enabled); - - /// write generated shaders to current directory, useful for debugging - void setShaderDebugOutputEnabled (bool enabled); - - /// Use this to manage user settings. \n - /// Global settings can be retrieved in shaders through a macro. \n - /// When a global setting is changed, the shaders that depend on them are recompiled automatically. - void setGlobalSetting (const std::string& name, const std::string& value); - - /// Adjusts the given shared parameter. \n - /// Internally, this will change all uniform parameters of this name marked with the macro \@shSharedParameter \n - /// @param name of the shared parameter - /// @param value of the parameter, use sh::makeProperty to construct this value - void setSharedParameter (const std::string& name, PropertyValuePtr value); - - Language getCurrentLanguage (); - - /// Switch between different shader languages (cg, glsl, hlsl) - void setCurrentLanguage (Language lang); - - /// Get a MaterialInstance by name - MaterialInstance* getMaterialInstance (const std::string& name); - - /// Create a configuration, which can then be altered by using Factory::getConfiguration - void createConfiguration (const std::string& name); - - /// Register a lod configuration, which can then be used by setting up lod distance values for the material \n - /// 0 refers to highest lod, so use 1 or higher as index parameter - void registerLodConfiguration (int index, PropertySetGet configuration); - - /// Set an alias name for a texture, the real name can then be retrieved with the "texture_alias" - /// property in a texture unit - this is useful if you don't know the name of your texture beforehand. \n - /// Example: \n - /// - In the material definition: texture_alias ReflectionMap \n - /// - At runtime: factory->setTextureAlias("ReflectionMap", "rtt_654654"); \n - /// You can call factory->setTextureAlias as many times as you want, and if the material was already created, its texture will be updated! - void setTextureAlias (const std::string& alias, const std::string& realName); - - /// Retrieve the real texture name for a texture alias (the real name is set by the user) - std::string retrieveTextureAlias (const std::string& name); - - /// Attach a listener for material created events - void setMaterialListener (MaterialListener* listener); - - /// Call this after you have set up basic stuff, like the shader language. - void loadAllFiles (); - - /// Controls writing of generated shader source code to the cache folder, so that the - /// (rather expensive) preprocessing step can be skipped on the next run. See Factory::setReadSourceCache \n - /// \note The default is off (no cache writing) - void setWriteSourceCache(bool write) { mWriteSourceCache = write; } - - /// Controls reading of generated shader sources from the cache folder - /// \note The default is off (no cache reading) - /// \note Even if microcode caching is enabled, generating (or caching) the source is still required due to the macros. - void setReadSourceCache(bool read) { mReadSourceCache = read; } - - /// Controls writing the microcode of the generated shaders to the cache folder. Microcode is machine independent - /// and loads very fast compared to regular compilation. Note that the availability of this feature depends on the \a Platform. - /// \note The default is off (no cache writing) - void setWriteMicrocodeCache(bool write) { mWriteMicrocodeCache = write; } - - /// Controls reading of shader microcode from the cache folder. Microcode is machine independent - /// and loads very fast compared to regular compilation. Note that the availability of this feature depends on the \a Platform. - /// \note The default is off (no cache reading) - void setReadMicrocodeCache(bool read) { mReadMicrocodeCache = read; } - - /// Lists all materials currently registered with the factory. Whether they are - /// loaded or not does not matter. - void listMaterials (std::vector& out); - - /// Lists current name & value of all global settings. - void listGlobalSettings (std::map& out); - - /// Lists configuration names. - void listConfigurationNames (std::vector& out); - - /// Lists current name & value of settings for a given configuration. - void listConfigurationSettings (const std::string& name, std::map& out); - - /// Lists shader sets. - void listShaderSets (std::vector& out); - - /// \note This only works if microcode caching is disabled, as there is currently no way to remove the cache - /// through the Ogre API. Luckily, this is already fixed in Ogre 1.9. - bool reloadShaders(); - - /// Calls reloadShaders() if shader files have been modified since the last reload. - /// \note This only works if microcode caching is disabled, as there is currently no way to remove the cache - /// through the Ogre API. Luckily, this is already fixed in Ogre 1.9. - void doMonitorShaderFiles(); - - /// Unloads all materials that are currently not referenced. This will not unload the textures themselves, - /// but it will let go of the SharedPtr's to the textures, so that you may unload them if you so desire. \n - /// A good time to call this would be after a new level has been loaded, but just calling it occasionally after a period - /// of time should work just fine too. - void unloadUnreferencedMaterials(); - - void destroyConfiguration (const std::string& name); - - void notifyConfigurationChanged(); - - /// Saves all materials and configurations, by default to the file they were loaded from. - /// If you wish to save them elsewhere, use setSourceFile first. - void saveAll (); - - /// Returns the error log as a string, then clears it. - /// Note: Errors are also written to the standard error output, or thrown if they are fatal. - std::string getErrorLog (); - - static Factory& getInstance(); - ///< Return instance of this class. - - static Factory* getInstancePtr(); - - /// Make sure a material technique is loaded.\n - /// You will probably never have to use this. - void _ensureMaterial(const std::string& name, const std::string& configuration); - - - Configuration* getConfiguration (const std::string& name); - - private: - - MaterialInstance* requestMaterial (const std::string& name, const std::string& configuration, unsigned short lodIndex); - ShaderSet* getShaderSet (const std::string& name); - Platform* getPlatform (); - - PropertySetGet* getCurrentGlobalSettings(); - - void addTextureAliasInstance (const std::string& name, TextureUnitState* t); - void removeTextureAliasInstances (TextureUnitState* t); - - std::string getCacheFolder () { return mPlatform->getCacheFolder (); } - bool getReadSourceCache() { return mReadSourceCache; } - bool getWriteSourceCache() { return mWriteSourceCache; } - public: - bool getWriteMicrocodeCache() { return mWriteMicrocodeCache; } // Fixme - - private: - void setActiveConfiguration (const std::string& configuration); - void setActiveLodLevel (int level); - - bool getShaderDebugOutputEnabled() { return mShaderDebugOutputEnabled; } - - std::map mTextureAliasInstances; - - void logError (const std::string& msg); - - friend class Platform; - friend class MaterialInstance; - friend class ShaderInstance; - friend class ShaderSet; - friend class TextureUnitState; - - private: - static Factory* sThis; - - bool mShadersEnabled; - bool mShaderDebugOutputEnabled; - - bool mReadMicrocodeCache; - bool mWriteMicrocodeCache; - bool mReadSourceCache; - bool mWriteSourceCache; - std::stringstream mErrorLog; - - MaterialMap mMaterials; - ShaderSetMap mShaderSets; - ConfigurationMap mConfigurations; - LodConfigurationMap mLodConfigurations; - LastModifiedMap mShadersLastModified; - LastModifiedMap mShadersLastModifiedNew; - - PropertySetGet mGlobalSettings; - - PropertySetGet* mCurrentConfiguration; - PropertySetGet* mCurrentLodConfiguration; - - TextureAliasMap mTextureAliases; - - Language mCurrentLanguage; - - MaterialListener* mListener; - - Platform* mPlatform; - - MaterialInstance* findInstance (const std::string& name); - MaterialInstance* searchInstance (const std::string& name); - - /// @return was anything removed? - bool removeCache (const std::string& pattern); - - static const std::string mBinaryCacheName; - }; -} - -#endif diff --git a/extern/shiny/Main/Language.hpp b/extern/shiny/Main/Language.hpp deleted file mode 100644 index 6b271cb86..000000000 --- a/extern/shiny/Main/Language.hpp +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef SH_LANGUAGE_H -#define SH_LANGUAGE_H - -namespace sh -{ - enum Language - { - Language_CG, - Language_HLSL, - Language_GLSL, - Language_GLSLES, - Language_Count, - Language_None - }; -} - -#endif diff --git a/extern/shiny/Main/MaterialInstance.cpp b/extern/shiny/Main/MaterialInstance.cpp deleted file mode 100644 index c69d13401..000000000 --- a/extern/shiny/Main/MaterialInstance.cpp +++ /dev/null @@ -1,261 +0,0 @@ -#include "MaterialInstance.hpp" - -#include -#include - -#include "Factory.hpp" -#include "ShaderSet.hpp" - -namespace sh -{ - MaterialInstance::MaterialInstance (const std::string& name, Factory* f) - : mName(name) - , mShadersEnabled(true) - , mFactory(f) - , mListener(NULL) - , mFailedToCreate(false) - { - } - - MaterialInstance::~MaterialInstance () - { - } - - void MaterialInstance::setParentInstance (const std::string& name) - { - mParentInstance = name; - } - - std::string MaterialInstance::getParentInstance () - { - return mParentInstance; - } - - void MaterialInstance::create (Platform* platform) - { - mMaterial = platform->createMaterial(mName); - - if (hasProperty ("shadow_caster_material")) - mMaterial->setShadowCasterMaterial (retrieveValue(getProperty("shadow_caster_material"), NULL).get()); - - if (hasProperty ("lod_values")) - mMaterial->setLodLevels (retrieveValue(getProperty("lod_values"), NULL).get()); - } - - void MaterialInstance::destroyAll () - { - if (hasProperty("create_configuration")) - return; - mMaterial->removeAll(); - mTexUnits.clear(); - mFailedToCreate = false; - } - - void MaterialInstance::setProperty (const std::string& name, PropertyValuePtr value) - { - PropertySetGet::setProperty (name, value); - destroyAll(); // trigger updates - } - - bool MaterialInstance::createForConfiguration (const std::string& configuration, unsigned short lodIndex) - { - if (mFailedToCreate) - return false; - try{ - mMaterial->ensureLoaded(); - bool res = mMaterial->createConfiguration(configuration, lodIndex); - if (!res) - return false; // listener was false positive - - if (mListener) - mListener->requestedConfiguration (this, configuration); - - mFactory->setActiveConfiguration (configuration); - mFactory->setActiveLodLevel (lodIndex); - - bool allowFixedFunction = true; - if (!mShadersEnabled && hasProperty("allow_fixed_function")) - { - allowFixedFunction = retrieveValue(getProperty("allow_fixed_function"), NULL).get(); - } - - bool useShaders = mShadersEnabled || !allowFixedFunction; - - // get passes of the top-most parent - PassVector* passes = getParentPasses(); - if (passes->empty()) - throw std::runtime_error ("material \"" + mName + "\" does not have any passes"); - - for (PassVector::iterator it = passes->begin(); it != passes->end(); ++it) - { - boost::shared_ptr pass = mMaterial->createPass (configuration, lodIndex); - it->copyAll (pass.get(), this); - - // texture samplers used in the shaders - std::vector usedTextureSamplersVertex; - std::vector usedTextureSamplersFragment; - - PropertySetGet* context = this; - - // create or retrieve shaders - bool hasVertex = it->hasProperty("vertex_program") - && !retrieveValue(it->getProperty("vertex_program"), context).get().empty(); - bool hasFragment = it->hasProperty("fragment_program") - && !retrieveValue(it->getProperty("fragment_program"), context).get().empty(); - if (useShaders) - { - it->setContext(context); - it->mShaderProperties.setContext(context); - if (hasVertex) - { - ShaderSet* vertex = mFactory->getShaderSet(retrieveValue(it->getProperty("vertex_program"), context).get()); - ShaderInstance* v = vertex->getInstance(&it->mShaderProperties); - if (v) - { - pass->assignProgram (GPT_Vertex, v->getName()); - v->setUniformParameters (pass, &it->mShaderProperties); - - std::vector sharedParams = v->getSharedParameters (); - for (std::vector::iterator it2 = sharedParams.begin(); it2 != sharedParams.end(); ++it2) - { - pass->addSharedParameter (GPT_Vertex, *it2); - } - - std::vector vector = v->getUsedSamplers (); - usedTextureSamplersVertex.insert(usedTextureSamplersVertex.end(), vector.begin(), vector.end()); - } - } - if (hasFragment) - { - ShaderSet* fragment = mFactory->getShaderSet(retrieveValue(it->getProperty("fragment_program"), context).get()); - ShaderInstance* f = fragment->getInstance(&it->mShaderProperties); - if (f) - { - pass->assignProgram (GPT_Fragment, f->getName()); - f->setUniformParameters (pass, &it->mShaderProperties); - - std::vector sharedParams = f->getSharedParameters (); - for (std::vector::iterator it2 = sharedParams.begin(); it2 != sharedParams.end(); ++it2) - { - pass->addSharedParameter (GPT_Fragment, *it2); - } - - std::vector vector = f->getUsedSamplers (); - usedTextureSamplersFragment.insert(usedTextureSamplersFragment.end(), vector.begin(), vector.end()); - } - } - } - - // create texture units - std::vector* texUnits = &it->mTexUnits; - int i=0; - for (std::vector::iterator texIt = texUnits->begin(); texIt != texUnits->end(); ++texIt ) - { - // only create those that are needed by the shader, OR those marked to be created in fixed function pipeline if shaders are disabled - bool foundVertex = std::find(usedTextureSamplersVertex.begin(), usedTextureSamplersVertex.end(), texIt->getName()) != usedTextureSamplersVertex.end(); - bool foundFragment = std::find(usedTextureSamplersFragment.begin(), usedTextureSamplersFragment.end(), texIt->getName()) != usedTextureSamplersFragment.end(); - if ( (foundVertex || foundFragment) - || (((!useShaders || (!hasVertex || !hasFragment)) && allowFixedFunction) && texIt->hasProperty("create_in_ffp") && retrieveValue(texIt->getProperty("create_in_ffp"), this).get())) - { - boost::shared_ptr texUnit = pass->createTextureUnitState (texIt->getName()); - texIt->copyAll (texUnit.get(), context); - - mTexUnits.push_back(texUnit); - - // set texture unit indices (required by GLSL) - if (useShaders && ((hasVertex && foundVertex) || (hasFragment && foundFragment)) && (mFactory->getCurrentLanguage () == Language_GLSL - || mFactory->getCurrentLanguage() == Language_GLSLES)) - { - pass->setTextureUnitIndex (foundVertex ? GPT_Vertex : GPT_Fragment, texIt->getName(), i); - - ++i; - } - } - } - } - - if (mListener) - mListener->createdConfiguration (this, configuration); - return true; - - } catch (std::runtime_error& e) - { - destroyAll(); - mFailedToCreate = true; - std::stringstream msg; - msg << "Error while creating material " << mName << ": " << e.what(); - std::cerr << msg.str() << std::endl; - mFactory->logError(msg.str()); - return false; - } - } - - Material* MaterialInstance::getMaterial () - { - return mMaterial.get(); - } - - MaterialInstancePass* MaterialInstance::createPass () - { - mPasses.push_back (MaterialInstancePass()); - mPasses.back().setContext(this); - return &mPasses.back(); - } - - void MaterialInstance::deletePass(unsigned int index) - { - assert(mPasses.size() > index); - mPasses.erase(mPasses.begin()+index); - } - - PassVector* MaterialInstance::getParentPasses() - { - if (mParent) - return static_cast(mParent)->getParentPasses(); - else - return &mPasses; - } - - PassVector* MaterialInstance::getPasses() - { - return &mPasses; - } - - void MaterialInstance::setShadersEnabled (bool enabled) - { - if (enabled == mShadersEnabled) - return; - mShadersEnabled = enabled; - - // trigger updates - if (mMaterial.get()) - destroyAll(); - } - - void MaterialInstance::save (std::ofstream& stream) - { - stream << "material " << mName << "\n" - << "{\n"; - - if (mParent) - { - stream << "\t" << "parent " << static_cast(mParent)->getName() << "\n"; - } - - const PropertyMap& properties = listProperties (); - for (PropertyMap::const_iterator it = properties.begin(); it != properties.end(); ++it) - { - stream << "\t" << it->first << " " << retrieveValue(getProperty(it->first), NULL).get() << "\n"; - } - - for (PassVector::iterator it = mPasses.begin(); it != mPasses.end(); ++it) - { - stream << "\tpass" << '\n'; - stream << "\t{" << '\n'; - it->save(stream); - stream << "\t}" << '\n'; - } - - stream << "}\n"; - } -} diff --git a/extern/shiny/Main/MaterialInstance.hpp b/extern/shiny/Main/MaterialInstance.hpp deleted file mode 100644 index 72c78c7b7..000000000 --- a/extern/shiny/Main/MaterialInstance.hpp +++ /dev/null @@ -1,109 +0,0 @@ -#ifndef SH_MATERIALINSTANCE_H -#define SH_MATERIALINSTANCE_H - -#include -#include - -#include "PropertyBase.hpp" -#include "Platform.hpp" -#include "MaterialInstancePass.hpp" - -namespace sh -{ - class Factory; - - typedef std::vector PassVector; - - /** - * @brief - * Allows you to be notified when a certain configuration for a material was just about to be created. \n - * Useful for adjusting some properties prior to the material being created (Or you could also re-create - * the whole material from scratch, i.e. use this as a method to create this material entirely in code) - */ - class MaterialInstanceListener - { - public: - virtual void requestedConfiguration (MaterialInstance* m, const std::string& configuration) = 0; ///< called before creating - virtual void createdConfiguration (MaterialInstance* m, const std::string& configuration) = 0; ///< called after creating - virtual ~MaterialInstanceListener(){} - }; - - /** - * @brief - * A specific material instance, which has all required properties set - * (for example the diffuse & normal map, ambient/diffuse/specular values). \n - * Depending on these properties, the system will automatically select a shader permutation - * that suits these and create the backend materials / passes (provided by the \a Platform class). - */ - class MaterialInstance : public PropertySetGet - { - public: - MaterialInstance (const std::string& name, Factory* f); - virtual ~MaterialInstance (); - - PassVector* getParentPasses(); ///< gets the passes of the top-most parent - - PassVector* getPasses(); ///< get our passes (for derived materials, none) - - MaterialInstancePass* createPass (); - void deletePass (unsigned int index); - - /// @attention Because the backend material passes are created on demand, the returned material here might not contain anything yet! - /// The only place where you should use this method, is for the MaterialInstance given by the MaterialListener::materialCreated event! - Material* getMaterial(); - - /// attach a \a MaterialInstanceListener to this specific material (as opposed to \a MaterialListener, which listens to all materials) - void setListener (MaterialInstanceListener* l) { mListener = l; } - - std::string getName() { return mName; } - - virtual void setProperty (const std::string& name, PropertyValuePtr value); - - void setSourceFile(const std::string& sourceFile) { mSourceFile = sourceFile; } - - std::string getSourceFile() { return mSourceFile; } - ///< get the name of the file this material was read from, or empty if it was created dynamically by code - - private: - void setParentInstance (const std::string& name); - std::string getParentInstance (); - - void create (Platform* platform); - bool createForConfiguration (const std::string& configuration, unsigned short lodIndex); - - void destroyAll (); - - void setShadersEnabled (bool enabled); - - void save (std::ofstream& stream); - - bool mFailedToCreate; - - friend class Factory; - - - private: - std::string mParentInstance; - ///< this is only used during the file-loading phase. an instance could be loaded before its parent is loaded, - /// so initially only the parent's name is written to this member. - /// once all instances are loaded, the actual mParent pointer (from PropertySetGet class) can be set - - std::vector< boost::shared_ptr > mTexUnits; - - MaterialInstanceListener* mListener; - - PassVector mPasses; - - std::string mName; - - std::string mSourceFile; - - boost::shared_ptr mMaterial; - - bool mShadersEnabled; - - Factory* mFactory; - }; -} - -#endif diff --git a/extern/shiny/Main/MaterialInstancePass.cpp b/extern/shiny/Main/MaterialInstancePass.cpp deleted file mode 100644 index a628cd64c..000000000 --- a/extern/shiny/Main/MaterialInstancePass.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include "MaterialInstancePass.hpp" - -#include - -namespace sh -{ - - MaterialInstanceTextureUnit* MaterialInstancePass::createTextureUnit (const std::string& name) - { - mTexUnits.push_back(MaterialInstanceTextureUnit(name)); - return &mTexUnits.back(); - } - - void MaterialInstancePass::save(std::ofstream &stream) - { - if (mShaderProperties.listProperties().size()) - { - stream << "\t\t" << "shader_properties" << '\n'; - stream << "\t\t{\n"; - mShaderProperties.save(stream, "\t\t\t"); - stream << "\t\t}\n"; - } - - PropertySetGet::save(stream, "\t\t"); - - for (std::vector ::iterator it = mTexUnits.begin(); - it != mTexUnits.end(); ++it) - { - stream << "\t\ttexture_unit " << it->getName() << '\n'; - stream << "\t\t{\n"; - it->save(stream, "\t\t\t"); - stream << "\t\t}\n"; - } - } -} diff --git a/extern/shiny/Main/MaterialInstancePass.hpp b/extern/shiny/Main/MaterialInstancePass.hpp deleted file mode 100644 index 3d83d8fa3..000000000 --- a/extern/shiny/Main/MaterialInstancePass.hpp +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef SH_MATERIALINSTANCEPASS_H -#define SH_MATERIALINSTANCEPASS_H - -#include - -#include "PropertyBase.hpp" -#include "MaterialInstanceTextureUnit.hpp" - -namespace sh -{ - /** - * @brief - * Holds properties of a single texture unit in a \a MaterialInstancePass. \n - * No inheritance here for now. - */ - class MaterialInstancePass : public PropertySetGet - { - public: - MaterialInstanceTextureUnit* createTextureUnit (const std::string& name); - - void save (std::ofstream& stream); - - PropertySetGet mShaderProperties; - - std::vector mTexUnits; - }; -} - -#endif diff --git a/extern/shiny/Main/MaterialInstanceTextureUnit.cpp b/extern/shiny/Main/MaterialInstanceTextureUnit.cpp deleted file mode 100644 index 0e3078af3..000000000 --- a/extern/shiny/Main/MaterialInstanceTextureUnit.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include "MaterialInstanceTextureUnit.hpp" - -namespace sh -{ - MaterialInstanceTextureUnit::MaterialInstanceTextureUnit (const std::string& name) - : mName(name) - { - } - - std::string MaterialInstanceTextureUnit::getName() const - { - return mName; - } -} diff --git a/extern/shiny/Main/MaterialInstanceTextureUnit.hpp b/extern/shiny/Main/MaterialInstanceTextureUnit.hpp deleted file mode 100644 index 5ca400fd4..000000000 --- a/extern/shiny/Main/MaterialInstanceTextureUnit.hpp +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef SH_MATERIALINSTANCETEXTUREUNIT_H -#define SH_MATERIALINSTANCETEXTUREUNIT_H - -#include "PropertyBase.hpp" - -namespace sh -{ - /** - * @brief - * A single texture unit state that belongs to a \a MaterialInstancePass \n - * this is not the real "backend" \a TextureUnitState (provided by \a Platform), - * it is merely a placeholder for properties. \n - * @note The backend \a TextureUnitState will only be created if this texture unit is - * actually used (i.e. referenced in the shader, or marked with property create_in_ffp = true). - */ - class MaterialInstanceTextureUnit : public PropertySetGet - { - public: - MaterialInstanceTextureUnit (const std::string& name); - std::string getName() const; - void setName (const std::string& name) { mName = name; } - private: - std::string mName; - }; -} - -#endif diff --git a/extern/shiny/Main/Platform.cpp b/extern/shiny/Main/Platform.cpp deleted file mode 100644 index 3eb7f4ad3..000000000 --- a/extern/shiny/Main/Platform.cpp +++ /dev/null @@ -1,89 +0,0 @@ -#include "Platform.hpp" - -#include - -#include "Factory.hpp" - -namespace sh -{ - Platform::Platform (const std::string& basePath) - : mBasePath(basePath) - , mCacheFolder("./") - , mFactory(NULL) - { - } - - Platform::~Platform () - { - } - - void Platform::setFactory (Factory* factory) - { - mFactory = factory; - } - - std::string Platform::getBasePath () - { - return mBasePath; - } - - bool Platform::supportsMaterialQueuedListener () - { - return false; - } - - bool Platform::supportsShaderSerialization () - { - return false; - } - - MaterialInstance* Platform::fireMaterialRequested (const std::string& name, const std::string& configuration, unsigned short lodIndex) - { - return mFactory->requestMaterial (name, configuration, lodIndex); - } - - void Platform::serializeShaders (const std::string& file) - { - throw std::runtime_error ("Shader serialization not supported by this platform"); - } - - void Platform::deserializeShaders (const std::string& file) - { - throw std::runtime_error ("Shader serialization not supported by this platform"); - } - - void Platform::setCacheFolder (const std::string& folder) - { - mCacheFolder = folder; - } - - std::string Platform::getCacheFolder() const - { - return mCacheFolder; - } - - // ------------------------------------------------------------------------------ - - bool TextureUnitState::setPropertyOverride (const std::string& name, PropertyValuePtr& value, PropertySetGet *context) - { - if (name == "texture_alias") - { - std::string aliasName = retrieveValue(value, context).get(); - - Factory::getInstance().addTextureAliasInstance (aliasName, this); - - setTextureName (Factory::getInstance().retrieveTextureAlias (aliasName)); - - return true; - } - else - return false; - } - - TextureUnitState::~TextureUnitState() - { - Factory* f = Factory::getInstancePtr (); - if (f) - f->removeTextureAliasInstances (this); - } -} diff --git a/extern/shiny/Main/Platform.hpp b/extern/shiny/Main/Platform.hpp deleted file mode 100644 index d3156e680..000000000 --- a/extern/shiny/Main/Platform.hpp +++ /dev/null @@ -1,147 +0,0 @@ -#ifndef SH_PLATFORM_H -#define SH_PLATFORM_H - -#include - -#include - -#include "Language.hpp" -#include "PropertyBase.hpp" - -namespace sh -{ - class Factory; - class MaterialInstance; - - enum GpuProgramType - { - GPT_Vertex, - GPT_Fragment - // GPT_Geometry - }; - - // These classes are supposed to be filled by the platform implementation - class GpuProgram - { - public: - virtual ~GpuProgram() {} - virtual bool getSupported () = 0; ///< @return true if the compilation was successful - - /// @param name name of the uniform in the shader - /// @param autoConstantName name of the auto constant (for example world_viewproj_matrix) - /// @param extraInfo if any extra info is needed (e.g. light index), put it here - virtual void setAutoConstant (const std::string& name, const std::string& autoConstantName, const std::string& extraInfo = "") = 0; - }; - - class TextureUnitState : public PropertySet - { - public: - virtual ~TextureUnitState(); - virtual void setTextureName (const std::string& textureName) = 0; - - protected: - virtual bool setPropertyOverride (const std::string& name, PropertyValuePtr& value, PropertySetGet *context); - }; - - class Pass : public PropertySet - { - public: - virtual boost::shared_ptr createTextureUnitState (const std::string& name) = 0; - virtual void assignProgram (GpuProgramType type, const std::string& name) = 0; - - /// @param type gpu program type - /// @param name name of the uniform in the shader - /// @param vt type of value, e.g. vector4 - /// @param value value to set - /// @param context used for retrieving linked values - virtual void setGpuConstant (int type, const std::string& name, ValueType vt, PropertyValuePtr value, PropertySetGet* context) = 0; - - virtual void setTextureUnitIndex (int programType, const std::string& name, int index) = 0; - - virtual void addSharedParameter (int type, const std::string& name) = 0; - }; - - class Material : public PropertySet - { - public: - virtual boost::shared_ptr createPass (const std::string& configuration, unsigned short lodIndex) = 0; - virtual bool createConfiguration (const std::string& name, unsigned short lodIndex) = 0; ///< @return false if already exists - virtual void removeAll () = 0; ///< remove all configurations - - virtual bool isUnreferenced() = 0; - virtual void unreferenceTextures() = 0; - virtual void ensureLoaded() = 0; - - virtual void setLodLevels (const std::string& lodLevels) = 0; - - virtual void setShadowCasterMaterial (const std::string& name) = 0; - }; - - class Platform - { - public: - Platform (const std::string& basePath); - virtual ~Platform (); - - /// set the folder to use for shader caching - void setCacheFolder (const std::string& folder); - - private: - virtual boost::shared_ptr createMaterial (const std::string& name) = 0; - - virtual boost::shared_ptr createGpuProgram ( - GpuProgramType type, - const std::string& compileArguments, - const std::string& name, const std::string& profile, - const std::string& source, Language lang) = 0; - - virtual void destroyGpuProgram (const std::string& name) = 0; - - virtual void setSharedParameter (const std::string& name, PropertyValuePtr value) = 0; - - virtual bool isProfileSupported (const std::string& profile) = 0; - - virtual void serializeShaders (const std::string& file); - virtual void deserializeShaders (const std::string& file); - - std::string getCacheFolder () const; - - friend class Factory; - friend class MaterialInstance; - friend class ShaderInstance; - friend class ShaderSet; - - protected: - /** - * this will be \a true if the platform supports serialization (writing shader microcode - * to disk) and deserialization (create gpu program from saved microcode) - */ - virtual bool supportsShaderSerialization (); - - /** - * this will be \a true if the platform supports a listener that notifies the system - * whenever a material is requested for rendering. if this is supported, shaders can be - * compiled on-demand when needed (and not earlier) - * @todo the Factory is not designed yet to handle the case where this method returns false - */ - virtual bool supportsMaterialQueuedListener (); - - /** - * fire event: material requested for rendering - * @param name material name - * @param configuration requested configuration - */ - MaterialInstance* fireMaterialRequested (const std::string& name, const std::string& configuration, unsigned short lodIndex); - - std::string mCacheFolder; - Factory* mFactory; - - private: - void setFactory (Factory* factory); - - std::string mBasePath; - std::string getBasePath(); - }; -} - -#endif diff --git a/extern/shiny/Main/Preprocessor.cpp b/extern/shiny/Main/Preprocessor.cpp deleted file mode 100644 index 26481aa03..000000000 --- a/extern/shiny/Main/Preprocessor.cpp +++ /dev/null @@ -1,151 +0,0 @@ -#include "Preprocessor.hpp" - -#include -#include -#include - -#include - -/* - Almost exact copy of load_file_to_string policy found in - boost::wave headers with the only change that it uses - boost::filesystem facility to handle UTF-8 paths properly on windows. - - Original namespace is used due to required bost::wave - internal symbols. -*/ -namespace boost { -namespace wave { -namespace iteration_context_policies { - - struct load_utf8_path_to_string - { - template - class inner - { - public: - template - static void init_iterators(IterContextT &iter_ctx, - PositionT const &act_pos, language_support language) - { - typedef typename IterContextT::iterator_type iterator_type; - namespace bfs = boost::filesystem; - - // read in the file - bfs::ifstream instream(bfs::path(iter_ctx.filename.c_str())); - if (!instream.is_open()) { - BOOST_WAVE_THROW_CTX(iter_ctx.ctx, preprocess_exception, - bad_include_file, iter_ctx.filename.c_str(), act_pos); - return; - } - instream.unsetf(std::ios::skipws); - - iter_ctx.instring.assign( - std::istreambuf_iterator(instream.rdbuf()), - std::istreambuf_iterator()); - - iter_ctx.first = iterator_type( - iter_ctx.instring.begin(), iter_ctx.instring.end(), - PositionT(iter_ctx.filename), language); - iter_ctx.last = iterator_type(); - } - - private: - std::string instring; - }; - }; -} } } - -namespace sh -{ - std::string Preprocessor::preprocess (std::string source, const std::string& includePath, std::vector definitions, const std::string& name) - { - std::stringstream returnString; - - // current file position is saved for exception handling - boost::wave::util::file_position_type current_position; - - try - { - // This token type is one of the central types used throughout the library. - // It is a template parameter to some of the public classes and instances - // of this type are returned from the iterators. - typedef boost::wave::cpplexer::lex_token<> token_type; - - // The template boost::wave::cpplexer::lex_iterator<> is the lexer type to - // to use as the token source for the preprocessing engine. It is - // parametrized with the token type. - typedef boost::wave::cpplexer::lex_iterator lex_iterator_type; - - // This is the resulting context type. The first template parameter should - // match the iterator type used during construction of the context - // instance (see below). It is the type of the underlying input stream. - typedef boost::wave::context - context_type; - - // The preprocessor iterator shouldn't be constructed directly. It is - // generated through a wave::context<> object. This wave:context<> object - // is additionally used to initialize and define different parameters of - // the actual preprocessing. - // - // The preprocessing of the input stream is done on the fly behind the - // scenes during iteration over the range of context_type::iterator_type - // instances. - context_type ctx (source.begin(), source.end(), name.c_str()); - ctx.add_include_path(includePath.c_str()); - for (std::vector::iterator it = definitions.begin(); it != definitions.end(); ++it) - { - ctx.add_macro_definition(*it); - } - - // Get the preprocessor iterators and use them to generate the token - // sequence. - context_type::iterator_type first = ctx.begin(); - context_type::iterator_type last = ctx.end(); - - // The input stream is preprocessed for you while iterating over the range - // [first, last). The dereferenced iterator returns tokens holding - // information about the preprocessed input stream, such as token type, - // token value, and position. - while (first != last) - { - current_position = (*first).get_position(); - returnString << (*first).get_value(); - ++first; - } - } - catch (boost::wave::cpp_exception const& e) - { - // some preprocessing error - std::stringstream error; - error - << e.file_name() << "(" << e.line_no() << "): " - << e.description(); - throw std::runtime_error(error.str()); - } - catch (std::exception const& e) - { - // use last recognized token to retrieve the error position - std::stringstream error; - error - << current_position.get_file() - << "(" << current_position.get_line() << "): " - << "exception caught: " << e.what(); - throw std::runtime_error(error.str()); - } - catch (...) - { - // use last recognized token to retrieve the error position - std::stringstream error; - error - << current_position.get_file() - << "(" << current_position.get_line() << "): " - << "unexpected exception caught."; - throw std::runtime_error(error.str()); - } - - return returnString.str(); - } -} diff --git a/extern/shiny/Main/Preprocessor.hpp b/extern/shiny/Main/Preprocessor.hpp deleted file mode 100644 index 7ee30ae7f..000000000 --- a/extern/shiny/Main/Preprocessor.hpp +++ /dev/null @@ -1,69 +0,0 @@ -#ifndef SH_PREPROCESSOR_H -#define SH_PREPROCESSOR_H - -#include -#include - -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include - -namespace sh -{ - /** - * @brief A simple interface for the boost::wave preprocessor - */ - class Preprocessor - { - public: - /** - * @brief Run a shader source string through the preprocessor - * @param source source string - * @param includePath path to search for includes (that are included with #include) - * @param definitions macros to predefine (vector of strings of the format MACRO=value, or just MACRO to define it as 1) - * @param name name to use for error messages - * @return processed string - */ - static std::string preprocess (std::string source, const std::string& includePath, std::vector definitions, const std::string& name); - }; - - - - class emit_custom_line_directives_hooks - : public boost::wave::context_policies::default_preprocessing_hooks - { - public: - - template - bool - emit_line_directive(ContextT const& ctx, ContainerT &pending, - typename ContextT::token_type const& act_token) - { - // emit a #line directive showing the relative filename instead - typename ContextT::position_type pos = act_token.get_position(); - unsigned int column = 1; - - typedef typename ContextT::token_type result_type; - - // no line directives for now - pos.set_column(column); - pending.push_back(result_type(boost::wave::T_GENERATEDNEWLINE, "\n", pos)); - - return true; - } - }; - - -} - -#endif diff --git a/extern/shiny/Main/PropertyBase.cpp b/extern/shiny/Main/PropertyBase.cpp deleted file mode 100644 index 8592712fa..000000000 --- a/extern/shiny/Main/PropertyBase.cpp +++ /dev/null @@ -1,302 +0,0 @@ -#include "PropertyBase.hpp" - -#include -#include - -#include -#include - -#include - -namespace sh -{ - - IntValue::IntValue(int in) - : mValue(in) - { - } - - IntValue::IntValue(const std::string& in) - { - mValue = boost::lexical_cast(in); - } - - std::string IntValue::serialize() - { - return boost::lexical_cast(mValue); - } - - // ------------------------------------------------------------------------------ - - BooleanValue::BooleanValue (bool in) - : mValue(in) - { - } - - BooleanValue::BooleanValue (const std::string& in) - { - if (in == "true") - mValue = true; - else if (in == "false") - mValue = false; - else - { - std::stringstream msg; - msg << "sh::BooleanValue: Warning: Unrecognized value \"" << in << "\" for property value of type BooleanValue"; - throw std::runtime_error(msg.str()); - } - } - - std::string BooleanValue::serialize () - { - if (mValue) - return "true"; - else - return "false"; - } - - // ------------------------------------------------------------------------------ - - StringValue::StringValue (const std::string& in) - { - mStringValue = in; - } - - std::string StringValue::serialize() - { - return mStringValue; - } - - // ------------------------------------------------------------------------------ - - LinkedValue::LinkedValue (const std::string& in) - { - mStringValue = in; - mStringValue.erase(0, 1); - } - - std::string LinkedValue::serialize() - { - throw std::runtime_error ("can't directly get a linked value"); - } - - std::string LinkedValue::get(PropertySetGet* context) const - { - PropertyValuePtr p = context->getProperty(mStringValue); - return retrieveValue(p, NULL).get(); - } - - // ------------------------------------------------------------------------------ - - FloatValue::FloatValue (float in) - { - mValue = in; - } - - FloatValue::FloatValue (const std::string& in) - { - mValue = boost::lexical_cast(in); - } - - std::string FloatValue::serialize () - { - return boost::lexical_cast(mValue); - } - - // ------------------------------------------------------------------------------ - - Vector2::Vector2 (float x, float y) - : mX(x) - , mY(y) - { - } - - Vector2::Vector2 (const std::string& in) - { - std::vector tokens; - boost::split(tokens, in, boost::is_any_of(" ")); - assert ((tokens.size() == 2) && "Invalid Vector2 conversion"); - mX = boost::lexical_cast (tokens[0]); - mY = boost::lexical_cast (tokens[1]); - } - - std::string Vector2::serialize () - { - return boost::lexical_cast(mX) + " " - + boost::lexical_cast(mY); - } - - // ------------------------------------------------------------------------------ - - Vector3::Vector3 (float x, float y, float z) - : mX(x) - , mY(y) - , mZ(z) - { - } - - Vector3::Vector3 (const std::string& in) - { - std::vector tokens; - boost::split(tokens, in, boost::is_any_of(" ")); - assert ((tokens.size() == 3) && "Invalid Vector3 conversion"); - mX = boost::lexical_cast (tokens[0]); - mY = boost::lexical_cast (tokens[1]); - mZ = boost::lexical_cast (tokens[2]); - } - - std::string Vector3::serialize () - { - return boost::lexical_cast(mX) + " " - + boost::lexical_cast(mY) + " " - + boost::lexical_cast(mZ); - } - - // ------------------------------------------------------------------------------ - - Vector4::Vector4 (float x, float y, float z, float w) - : mX(x) - , mY(y) - , mZ(z) - , mW(w) - { - } - - Vector4::Vector4 (const std::string& in) - { - std::vector tokens; - boost::split(tokens, in, boost::is_any_of(" ")); - assert ((tokens.size() == 4) && "Invalid Vector4 conversion"); - mX = boost::lexical_cast (tokens[0]); - mY = boost::lexical_cast (tokens[1]); - mZ = boost::lexical_cast (tokens[2]); - mW = boost::lexical_cast (tokens[3]); - } - - std::string Vector4::serialize () - { - return boost::lexical_cast(mX) + " " - + boost::lexical_cast(mY) + " " - + boost::lexical_cast(mZ) + " " - + boost::lexical_cast(mW); - } - - // ------------------------------------------------------------------------------ - - void PropertySet::setProperty (const std::string& name, PropertyValuePtr &value, PropertySetGet* context) - { - if (!setPropertyOverride (name, value, context)) - { - std::stringstream msg; - msg << "sh::PropertySet: Warning: No match for property with name '" << name << "'"; - throw std::runtime_error(msg.str()); - } - } - - bool PropertySet::setPropertyOverride (const std::string& name, PropertyValuePtr &value, PropertySetGet* context) - { - // if we got here, none of the sub-classes were able to make use of the property - return false; - } - - // ------------------------------------------------------------------------------ - - PropertySetGet::PropertySetGet (PropertySetGet* parent) - : mParent(parent) - , mContext(NULL) - { - } - - PropertySetGet::PropertySetGet () - : mParent(NULL) - , mContext(NULL) - { - } - - void PropertySetGet::setParent (PropertySetGet* parent) - { - mParent = parent; - } - - void PropertySetGet::setContext (PropertySetGet* context) - { - mContext = context; - } - - PropertySetGet* PropertySetGet::getContext() - { - return mContext; - } - - void PropertySetGet::setProperty (const std::string& name, PropertyValuePtr value) - { - mProperties [name] = value; - } - - void PropertySetGet::deleteProperty(const std::string &name) - { - mProperties.erase(name); - } - - PropertyValuePtr& PropertySetGet::getProperty (const std::string& name) - { - bool found = (mProperties.find(name) != mProperties.end()); - - if (!found) - { - if (!mParent) - throw std::runtime_error ("Trying to retrieve property \"" + name + "\" that does not exist"); - else - return mParent->getProperty (name); - } - else - return mProperties[name]; - } - - bool PropertySetGet::hasProperty (const std::string& name) const - { - bool found = (mProperties.find(name) != mProperties.end()); - - if (!found) - { - if (!mParent) - return false; - else - return mParent->hasProperty (name); - } - else - return true; - } - - void PropertySetGet::copyAll (PropertySet* target, PropertySetGet* context, bool copyParent) - { - if (mParent && copyParent) - mParent->copyAll (target, context); - for (PropertyMap::iterator it = mProperties.begin(); it != mProperties.end(); ++it) - { - target->setProperty(it->first, it->second, context); - } - } - - void PropertySetGet::copyAll (PropertySetGet* target, PropertySetGet* context, bool copyParent) - { - if (mParent && copyParent) - mParent->copyAll (target, context); - for (PropertyMap::iterator it = mProperties.begin(); it != mProperties.end(); ++it) - { - std::string val = retrieveValue(it->second, this).get(); - target->setProperty(it->first, sh::makeProperty(new sh::StringValue(val))); - } - } - - void PropertySetGet::save(std::ofstream &stream, const std::string& indentation) - { - for (PropertyMap::iterator it = mProperties.begin(); it != mProperties.end(); ++it) - { - if (typeid( *(it->second) ) == typeid(LinkedValue)) - stream << indentation << it->first << " " << "$" + static_cast(&*(it->second))->_getStringValue() << '\n'; - else - stream << indentation << it->first << " " << retrieveValue(it->second, this).get() << '\n'; - } - } -} diff --git a/extern/shiny/Main/PropertyBase.hpp b/extern/shiny/Main/PropertyBase.hpp deleted file mode 100644 index 13809443e..000000000 --- a/extern/shiny/Main/PropertyBase.hpp +++ /dev/null @@ -1,244 +0,0 @@ -#ifndef SH_PROPERTYBASE_H -#define SH_PROPERTYBASE_H - -#include -#include - -#include - -namespace sh -{ - class StringValue; - class PropertySetGet; - class LinkedValue; - - enum ValueType - { - VT_String, - VT_Int, - VT_Float, - VT_Vector2, - VT_Vector3, - VT_Vector4 - }; - - class PropertyValue - { - public: - PropertyValue() {} - - virtual ~PropertyValue() {} - - std::string _getStringValue() { return mStringValue; } - - virtual std::string serialize() = 0; - - protected: - std::string mStringValue; ///< this will possibly not contain anything in the specialised classes - }; - typedef boost::shared_ptr PropertyValuePtr; - - class StringValue : public PropertyValue - { - public: - StringValue (const std::string& in); - std::string get() const { return mStringValue; } - - virtual std::string serialize(); - }; - - /** - * @brief Used for retrieving a named property from a context - */ - class LinkedValue : public PropertyValue - { - public: - LinkedValue (const std::string& in); - - std::string get(PropertySetGet* context) const; - - virtual std::string serialize(); - }; - - class FloatValue : public PropertyValue - { - public: - FloatValue (float in); - FloatValue (const std::string& in); - float get() const { return mValue; } - - virtual std::string serialize(); - private: - float mValue; - }; - - class IntValue : public PropertyValue - { - public: - IntValue (int in); - IntValue (const std::string& in); - int get() const { return mValue; } - - virtual std::string serialize(); - private: - int mValue; - }; - - class BooleanValue : public PropertyValue - { - public: - BooleanValue (bool in); - BooleanValue (const std::string& in); - bool get() const { return mValue; } - - virtual std::string serialize(); - private: - bool mValue; - }; - - class Vector2 : public PropertyValue - { - public: - Vector2 (float x, float y); - Vector2 (const std::string& in); - - float mX, mY; - - virtual std::string serialize(); - }; - - class Vector3 : public PropertyValue - { - public: - Vector3 (float x, float y, float z); - Vector3 (const std::string& in); - - float mX, mY, mZ; - - virtual std::string serialize(); - }; - - class Vector4 : public PropertyValue - { - public: - Vector4 (float x, float y, float z, float w); - Vector4 (const std::string& in); - - float mX, mY, mZ, mW; - - virtual std::string serialize(); - }; - - /// \brief base class that allows setting properties with any kind of value-type - class PropertySet - { - public: - virtual ~PropertySet() {} - void setProperty (const std::string& name, PropertyValuePtr& value, PropertySetGet* context); - - protected: - virtual bool setPropertyOverride (const std::string& name, PropertyValuePtr& value, PropertySetGet* context); - ///< @return \a true if the specified property was found, or false otherwise - }; - - typedef std::map PropertyMap; - - /// \brief base class that allows setting properties with any kind of value-type and retrieving them - class PropertySetGet - { - public: - PropertySetGet (PropertySetGet* parent); - PropertySetGet (); - - virtual ~PropertySetGet() {} - - void save (std::ofstream& stream, const std::string& indentation); - - void copyAll (PropertySet* target, PropertySetGet* context, bool copyParent=true); - ///< call setProperty for each property/value pair stored in \a this - void copyAll (PropertySetGet* target, PropertySetGet* context, bool copyParent=true); - ///< call setProperty for each property/value pair stored in \a this - - void setParent (PropertySetGet* parent); - PropertySetGet* getParent () { return mParent; } - void setContext (PropertySetGet* context); - PropertySetGet* getContext(); - - virtual void setProperty (const std::string& name, PropertyValuePtr value); - PropertyValuePtr& getProperty (const std::string& name); - - void deleteProperty (const std::string& name); - - const PropertyMap& listProperties() { return mProperties; } - - bool hasProperty (const std::string& name) const; - - private: - PropertyMap mProperties; - - protected: - PropertySetGet* mParent; - ///< the parent can provide properties as well (when they are retrieved via getProperty) \n - /// multiple levels of inheritance are also supported \n - /// children can override properties of their parents - - PropertySetGet* mContext; - ///< used to retrieve linked property values - }; - - template - static T retrieveValue (boost::shared_ptr& value, PropertySetGet* context) - { - if (typeid(*value).name() == typeid(LinkedValue).name()) - { - std::string v = static_cast(value.get())->get(context); - PropertyValuePtr newVal = PropertyValuePtr (new StringValue(v)); - return retrieveValue(newVal, NULL); - } - if (typeid(T).name() == typeid(*value).name()) - { - // requested type is the same as source type, only have to cast it - return *static_cast(value.get()); - } - - if ((typeid(T).name() == typeid(StringValue).name()) - && typeid(*value).name() != typeid(StringValue).name()) - { - // if string type is requested and value is not string, use serialize method to convert to string - T* ptr = new T (value->serialize()); // note that T is always StringValue here, but we can't use it here - value = boost::shared_ptr (static_cast(ptr)); - return *ptr; - } - - { - // remaining case: deserialization from string by passing the string to constructor of class T - T* ptr = new T(value->_getStringValue()); - PropertyValuePtr newVal (static_cast(ptr)); - value = newVal; - return *ptr; - } - } - ///< - /// @brief alternate version that supports linked values (use of $variables in parent material) - /// @note \a value is changed in-place to the converted object - /// @return converted object \n - - /// Create a property from a string - inline PropertyValuePtr makeProperty (const std::string& prop) - { - if (prop.size() > 1 && prop[0] == '$') - return PropertyValuePtr (static_cast(new LinkedValue(prop))); - else - return PropertyValuePtr (static_cast (new StringValue(prop))); - } - - template - /// Create a property of any type - /// Example: sh::makeProperty (new sh::Vector4(1, 1, 1, 1)) - inline PropertyValuePtr makeProperty (T* p) - { - return PropertyValuePtr ( static_cast(p) ); - } -} - -#endif diff --git a/extern/shiny/Main/ScriptLoader.cpp b/extern/shiny/Main/ScriptLoader.cpp deleted file mode 100644 index bafe07fc8..000000000 --- a/extern/shiny/Main/ScriptLoader.cpp +++ /dev/null @@ -1,414 +0,0 @@ -#include "ScriptLoader.hpp" - -#include -#include -#include -#include - -#include - -namespace sh -{ - void ScriptLoader::loadAllFiles(ScriptLoader* c, const std::string& path) - { - for ( boost::filesystem::recursive_directory_iterator end, dir(path); dir != end; ++dir ) - { - boost::filesystem::path p(*dir); - if(p.extension() == c->mFileEnding) - { - c->mCurrentFileName = (*dir).path().string(); - std::ifstream in((*dir).path().string().c_str(), std::ios::binary); - c->parseScript(in); - } - } - } - - ScriptLoader::ScriptLoader(const std::string& fileEnding) - : mLoadOrder(0) - , mToken(TOKEN_NewLine) - , mLastToken(TOKEN_NewLine) - - { - mFileEnding = fileEnding; - } - - ScriptLoader::~ScriptLoader() - { - clearScriptList(); - } - - void ScriptLoader::clearScriptList() - { - std::map ::iterator i; - for (i = m_scriptList.begin(); i != m_scriptList.end(); ++i) - { - delete i->second; - } - m_scriptList.clear(); - } - - ScriptNode *ScriptLoader::getConfigScript(const std::string &name) - { - std::map ::iterator i; - - std::string key = name; - i = m_scriptList.find(key); - - //If found.. - if (i != m_scriptList.end()) - { - return i->second; - } - else - { - return NULL; - } - } - - std::map ScriptLoader::getAllConfigScripts () - { - return m_scriptList; - } - - void ScriptLoader::parseScript(std::ifstream &stream) - { - //Get first token - _nextToken(stream); - if (mToken == TOKEN_EOF) - { - stream.close(); - return; - } - - //Parse the script - _parseNodes(stream, 0); - - stream.close(); - } - - void ScriptLoader::_nextToken(std::ifstream &stream) - { - //EOF token - if (!stream.good()) - { - mToken = TOKEN_EOF; - return; - } - - //(Get next character) - int ch = stream.get(); - - while ((ch == ' ' || ch == 9) && !stream.eof()) - { //Skip leading spaces / tabs - ch = stream.get(); - } - - if (!stream.good()) - { - mToken = TOKEN_EOF; - return; - } - - //Newline token - if (ch == '\r' || ch == '\n') - { - do - { - ch = stream.get(); - } while ((ch == '\r' || ch == '\n') && !stream.eof()); - - stream.unget(); - - mToken = TOKEN_NewLine; - return; - } - - //Open brace token - else if (ch == '{') - { - mToken = TOKEN_OpenBrace; - return; - } - - //Close brace token - else if (ch == '}') - { - mToken = TOKEN_CloseBrace; - return; - } - - //Text token - if (ch < 32 || ch > 122) //Verify valid char - { - throw std::runtime_error("Parse Error: Invalid character, ConfigLoader::load()"); - } - - mTokenValue = ""; - mToken = TOKEN_Text; - do - { - //Skip comments - if (ch == '/') - { - int ch2 = stream.peek(); - - //C++ style comment (//) - if (ch2 == '/') - { - stream.get(); - do - { - ch = stream.get(); - } while (ch != '\r' && ch != '\n' && !stream.eof()); - - mToken = TOKEN_NewLine; - return; - } - } - - //Add valid char to tokVal - mTokenValue += (char)ch; - - //Next char - ch = stream.get(); - - } while (ch > 32 && ch <= 122 && !stream.eof()); - - stream.unget(); - - return; - } - - void ScriptLoader::_skipNewLines(std::ifstream &stream) - { - while (mToken == TOKEN_NewLine) - { - _nextToken(stream); - } - } - - void ScriptLoader::_parseNodes(std::ifstream &stream, ScriptNode *parent) - { - typedef std::pair ScriptItem; - - while (true) - { - switch (mToken) - { - //Node - case TOKEN_Text: - { - //Add the new node - ScriptNode *newNode; - if (parent) - { - newNode = parent->addChild(mTokenValue); - } - else - { - newNode = new ScriptNode(0, mTokenValue); - } - - //Get values - _nextToken(stream); - std::string valueStr; - int i=0; - while (mToken == TOKEN_Text) - { - if (i == 0) - valueStr += mTokenValue; - else - valueStr += " " + mTokenValue; - _nextToken(stream); - ++i; - } - newNode->setValue(valueStr); - - //Add root nodes to scriptList - if (!parent) - { - std::string key; - - if (newNode->getValue() == "") - throw std::runtime_error("Root node must have a name (\"" + newNode->getName() + "\")"); - key = newNode->getValue(); - - m_scriptList.insert(ScriptItem(key, newNode)); - } - - _skipNewLines(stream); - - //Add any sub-nodes - if (mToken == TOKEN_OpenBrace) - { - //Parse nodes - _nextToken(stream); - _parseNodes(stream, newNode); - //Check for matching closing brace - if (mToken != TOKEN_CloseBrace) - { - throw std::runtime_error("Parse Error: Expecting closing brace"); - } - _nextToken(stream); - _skipNewLines(stream); - } - - newNode->mFileName = mCurrentFileName; - - break; - } - - //Out of place brace - case TOKEN_OpenBrace: - throw std::runtime_error("Parse Error: Opening brace out of plane"); - break; - - //Return if end of nodes have been reached - case TOKEN_CloseBrace: - return; - - //Return if reached end of file - case TOKEN_EOF: - return; - - case TOKEN_NewLine: - _nextToken(stream); - break; - } - }; - } - - ScriptNode::ScriptNode(ScriptNode *parent, const std::string &name) - { - mName = name; - mParent = parent; - mRemoveSelf = true; //For proper destruction - mLastChildFound = -1; - - //Add self to parent's child list (unless this is the root node being created) - if (parent != NULL) - { - mParent->mChildren.push_back(this); - mIter = --(mParent->mChildren.end()); - } - } - - ScriptNode::~ScriptNode() - { - //Delete all children - std::vector::iterator i; - for (i = mChildren.begin(); i != mChildren.end(); ++i) - { - ScriptNode *node = *i; - node->mRemoveSelf = false; - delete node; - } - mChildren.clear(); - - //Remove self from parent's child list - if (mRemoveSelf && mParent != NULL) - { - mParent->mChildren.erase(mIter); - } - } - - ScriptNode *ScriptNode::addChild(const std::string &name, bool replaceExisting) - { - if (replaceExisting) - { - ScriptNode *node = findChild(name, false); - if (node) - { - return node; - } - } - return new ScriptNode(this, name); - } - - ScriptNode *ScriptNode::findChild(const std::string &name, bool recursive) - { - int indx; - int childCount = (int)mChildren.size(); - - if (mLastChildFound != -1) - { - //If possible, try checking the nodes neighboring the last successful search - //(often nodes searched for in sequence, so this will boost search speeds). - int prevC = mLastChildFound-1; - if (prevC < 0) - prevC = 0; - else if (prevC >= childCount) - prevC = childCount-1; - int nextC = mLastChildFound+1; - if (nextC < 0) - nextC = 0; - else if (nextC >= childCount) - nextC = childCount-1; - - for (indx = prevC; indx <= nextC; ++indx) - { - ScriptNode *node = mChildren[indx]; - if (node->mName == name) - { - mLastChildFound = indx; - return node; - } - } - - //If not found that way, search for the node from start to finish, avoiding the - //already searched area above. - for (indx = nextC + 1; indx < childCount; ++indx) - { - ScriptNode *node = mChildren[indx]; - if (node->mName == name) { - mLastChildFound = indx; - return node; - } - } - for (indx = 0; indx < prevC; ++indx) - { - ScriptNode *node = mChildren[indx]; - if (node->mName == name) { - mLastChildFound = indx; - return node; - } - } - } - else - { - //Search for the node from start to finish - for (indx = 0; indx < childCount; ++indx){ - ScriptNode *node = mChildren[indx]; - if (node->mName == name) { - mLastChildFound = indx; - return node; - } - } - } - - //If not found, search child nodes (if recursive == true) - if (recursive) - { - for (indx = 0; indx < childCount; ++indx) - { - mChildren[indx]->findChild(name, recursive); - } - } - - //Not found anywhere - return NULL; - } - - void ScriptNode::setParent(ScriptNode *newParent) - { - //Remove self from current parent - mParent->mChildren.erase(mIter); - - //Set new parent - mParent = newParent; - - //Add self to new parent - mParent->mChildren.push_back(this); - mIter = --(mParent->mChildren.end()); - } -} diff --git a/extern/shiny/Main/ScriptLoader.hpp b/extern/shiny/Main/ScriptLoader.hpp deleted file mode 100644 index 89720fb5d..000000000 --- a/extern/shiny/Main/ScriptLoader.hpp +++ /dev/null @@ -1,134 +0,0 @@ -#ifndef SH_CONFIG_LOADER_H__ -#define SH_CONFIG_LOADER_H__ - -#include -#include -#include -#include - -namespace sh -{ - class ScriptNode; - - /** - * @brief The base class of loaders that read Ogre style script files to get configuration and settings. - * Heavily inspired by: http://www.ogre3d.org/tikiwiki/All-purpose+script+parser - * ( "Non-ogre version") - */ - class ScriptLoader - { - public: - static void loadAllFiles(ScriptLoader* c, const std::string& path); - - ScriptLoader(const std::string& fileEnding); - virtual ~ScriptLoader(); - - std::string mFileEnding; - - // For a line like - // entity animals/dog - // { - // ... - // } - // The type is "entity" and the name is "animals/dog" - // Or if animal/dog was not there then name is "" - ScriptNode *getConfigScript (const std::string &name); - - std::map getAllConfigScripts (); - - void parseScript(std::ifstream &stream); - - std::string mCurrentFileName; - - protected: - - float mLoadOrder; - // like "*.object" - - std::map m_scriptList; - - enum Token - { - TOKEN_Text, - TOKEN_NewLine, - TOKEN_OpenBrace, - TOKEN_CloseBrace, - TOKEN_EOF - }; - - Token mToken, mLastToken; - std::string mTokenValue; - - void _parseNodes(std::ifstream &stream, ScriptNode *parent); - void _nextToken(std::ifstream &stream); - void _skipNewLines(std::ifstream &stream); - - void clearScriptList(); - }; - - class ScriptNode - { - public: - ScriptNode(ScriptNode *parent, const std::string &name = "untitled"); - ~ScriptNode(); - - inline void setName(const std::string &name) - { - this->mName = name; - } - - inline std::string &getName() - { - return mName; - } - - inline void setValue(const std::string &value) - { - mValue = value; - } - - inline std::string &getValue() - { - return mValue; - } - - ScriptNode *addChild(const std::string &name = "untitled", bool replaceExisting = false); - ScriptNode *findChild(const std::string &name, bool recursive = false); - - inline std::vector &getChildren() - { - return mChildren; - } - - inline ScriptNode *getChild(unsigned int index = 0) - { - assert(index < mChildren.size()); - return mChildren[index]; - } - - void setParent(ScriptNode *newParent); - - inline ScriptNode *getParent() - { - return mParent; - } - - std::string mFileName; - - - private: - std::string mName; - std::string mValue; - std::vector mChildren; - ScriptNode *mParent; - - - int mLastChildFound; //The last child node's index found with a call to findChild() - - std::vector::iterator mIter; - bool mRemoveSelf; - }; - -} - -#endif diff --git a/extern/shiny/Main/ShaderInstance.cpp b/extern/shiny/Main/ShaderInstance.cpp deleted file mode 100644 index 270aaba68..000000000 --- a/extern/shiny/Main/ShaderInstance.cpp +++ /dev/null @@ -1,698 +0,0 @@ -#include "ShaderInstance.hpp" - -#include -#include -#include - -#include -#include -#include - -#include - -#include "Preprocessor.hpp" -#include "Factory.hpp" -#include "ShaderSet.hpp" - -namespace -{ - std::string convertLang (sh::Language lang) - { - if (lang == sh::Language_CG) - return "SH_CG"; - else if (lang == sh::Language_HLSL) - return "SH_HLSL"; - else if (lang == sh::Language_GLSL) - return "SH_GLSL"; - else if (lang == sh::Language_GLSLES) - return "SH_GLSLES"; - throw std::runtime_error("invalid language"); - } - - char getComponent(int num) - { - if (num == 0) - return 'x'; - else if (num == 1) - return 'y'; - else if (num == 2) - return 'z'; - else if (num == 3) - return 'w'; - else - throw std::runtime_error("invalid component"); - } - - std::string getFloat(sh::Language lang, int num_components) - { - if (lang == sh::Language_CG || lang == sh::Language_HLSL) - return (num_components == 1) ? "float" : "float" + boost::lexical_cast(num_components); - else - return (num_components == 1) ? "float" : "vec" + boost::lexical_cast(num_components); - } - - bool isCmd (const std::string& source, size_t pos, const std::string& cmd) - { - return (source.size() >= pos + cmd.size() && source.substr(pos, cmd.size()) == cmd); - } - - void writeDebugFile (const std::string& content, const std::string& filename) - { - boost::filesystem::path full_path(boost::filesystem::current_path()); - std::ofstream of ((full_path / filename ).string().c_str() , std::ios_base::out); - of.write(content.c_str(), content.size()); - of.close(); - } -} - -namespace sh -{ - std::string Passthrough::expand_assign(std::string toAssign) - { - std::string res; - - int i = 0; - int current_passthrough = passthrough_number; - int current_component_left = component_start; - int current_component_right = 0; - int components_left = num_components; - int components_at_once; - while (i < num_components) - { - if (components_left + current_component_left <= 4) - components_at_once = components_left; - else - components_at_once = 4 - current_component_left; - - std::string componentStr = "."; - for (int j = 0; j < components_at_once; ++j) - componentStr += getComponent(j + current_component_left); - std::string componentStr2 = "."; - for (int j = 0; j < components_at_once; ++j) - componentStr2 += getComponent(j + current_component_right); - if (num_components == 1) - { - componentStr2 = ""; - } - res += "passthrough" + boost::lexical_cast(current_passthrough) + componentStr + " = " + toAssign + componentStr2; - - current_component_left += components_at_once; - current_component_right += components_at_once; - components_left -= components_at_once; - - i += components_at_once; - - if (components_left == 0) - { - // finished - return res; - } - else - { - // add semicolon to every instruction but the last - res += "; "; - } - - if (current_component_left == 4) - { - current_passthrough++; - current_component_left = 0; - } - } - throw std::runtime_error("expand_assign error"); // this should never happen, but gets us rid of the "control reaches end of non-void function" warning - } - - std::string Passthrough::expand_receive() - { - std::string res; - - res += getFloat(lang, num_components) + "("; - - int i = 0; - int current_passthrough = passthrough_number; - int current_component = component_start; - int components_left = num_components; - while (i < num_components) - { - int components_at_once = std::min(components_left, 4 - current_component); - - std::string componentStr; - for (int j = 0; j < components_at_once; ++j) - componentStr += getComponent(j + current_component); - - res += "passthrough" + boost::lexical_cast(current_passthrough) + "." + componentStr; - - current_component += components_at_once; - - components_left -= components_at_once; - - i += components_at_once; - - if (components_left == 0) - { - // finished - return res + ")"; -; - } - else - { - // add comma to every variable but the last - res += ", "; - } - - if (current_component == 4) - { - current_passthrough++; - current_component = 0; - } - } - - throw std::runtime_error("expand_receive error"); // this should never happen, but gets us rid of the "control reaches end of non-void function" warning - } - - // ------------------------------------------------------------------------------ - - void ShaderInstance::parse (std::string& source, PropertySetGet* properties) - { - size_t pos = 0; - while (true) - { - pos = source.find("@", pos); - if (pos == std::string::npos) - break; - - if (isCmd(source, pos, "@shProperty")) - { - std::vector args = extractMacroArguments (pos, source); - - size_t start = source.find("(", pos); - size_t end = source.find(")", pos); - std::string cmd = source.substr(pos+1, start-(pos+1)); - - std::string replaceValue; - if (cmd == "shPropertyBool") - { - std::string propertyName = args[0]; - PropertyValuePtr value = properties->getProperty(propertyName); - bool val = retrieveValue(value, properties->getContext()).get(); - replaceValue = val ? "1" : "0"; - } - else if (cmd == "shPropertyString") - { - std::string propertyName = args[0]; - PropertyValuePtr value = properties->getProperty(propertyName); - replaceValue = retrieveValue(value, properties->getContext()).get(); - } - else if (cmd == "shPropertyEqual") - { - std::string propertyName = args[0]; - std::string comparedAgainst = args[1]; - std::string value = retrieveValue(properties->getProperty(propertyName), properties->getContext()).get(); - replaceValue = (value == comparedAgainst) ? "1" : "0"; - } - else if (isCmd(source, pos, "@shPropertyHasValue")) - { - assert(args.size() == 1); - std::string propertyName = args[0]; - PropertyValuePtr value = properties->getProperty(propertyName); - std::string val = retrieveValue(value, properties->getContext()).get(); - replaceValue = (val.empty() ? "0" : "1"); - } - else - throw std::runtime_error ("unknown command \"" + cmd + "\""); - source.replace(pos, (end+1)-pos, replaceValue); - } - else if (isCmd(source, pos, "@shGlobalSetting")) - { - std::vector args = extractMacroArguments (pos, source); - - std::string cmd = source.substr(pos+1, source.find("(", pos)-(pos+1)); - std::string replaceValue; - if (cmd == "shGlobalSettingBool") - { - std::string settingName = args[0]; - std::string value = retrieveValue(mParent->getCurrentGlobalSettings()->getProperty(settingName), NULL).get(); - replaceValue = (value == "true" || value == "1") ? "1" : "0"; - } - else if (cmd == "shGlobalSettingEqual") - { - std::string settingName = args[0]; - std::string comparedAgainst = args[1]; - std::string value = retrieveValue(mParent->getCurrentGlobalSettings()->getProperty(settingName), NULL).get(); - replaceValue = (value == comparedAgainst) ? "1" : "0"; - } - else if (cmd == "shGlobalSettingString") - { - std::string settingName = args[0]; - replaceValue = retrieveValue(mParent->getCurrentGlobalSettings()->getProperty(settingName), NULL).get(); - } - else - throw std::runtime_error ("unknown command \"" + cmd + "\""); - - source.replace(pos, (source.find(")", pos)+1)-pos, replaceValue); - } - else if (isCmd(source, pos, "@shForeach")) - { - - assert(source.find("@shEndForeach", pos) != std::string::npos); - size_t block_end = source.find("@shEndForeach", pos); - - // get the argument for parsing - size_t start = source.find("(", pos); - size_t end = start; - int brace_depth = 1; - while (brace_depth > 0) - { - ++end; - if (source[end] == '(') - ++brace_depth; - else if (source[end] == ')') - --brace_depth; - } - std::string arg = source.substr(start+1, end-(start+1)); - parse(arg, properties); - - int num = boost::lexical_cast(arg); - - // get the content of the inner block - std::string content = source.substr(end+1, block_end - (end+1)); - - // replace both outer and inner block with content of inner block num times - std::string replaceStr; - for (int i=0; i 0) - { - ++_end; - if (addStr[_end] == '(') - ++_brace_depth; - else if (addStr[_end] == ')') - --_brace_depth; - } - std::string arg = addStr.substr(_start+1, _end-(_start+1)); - parse(arg, properties); - - int offset = boost::lexical_cast (arg); - addStr.replace(pos2, (_end+1)-pos2, boost::lexical_cast(i+offset)); - } - else - { - addStr.replace(pos2, std::string("@shIterator").length(), boost::lexical_cast(i)); - } - } - - replaceStr += addStr; - } - source.replace(pos, (block_end+std::string("@shEndForeach").length())-pos, replaceStr); - } - else if (source.size() > pos+1) - ++pos; // skip - } - - } - - ShaderInstance::ShaderInstance (ShaderSet* parent, const std::string& name, PropertySetGet* properties) - : mName(name) - , mParent(parent) - , mSupported(true) - , mCurrentPassthrough(0) - , mCurrentComponent(0) - { - std::string source = mParent->getSource(); - int type = mParent->getType(); - std::string basePath = mParent->getBasePath(); - size_t pos; - - bool readCache = Factory::getInstance ().getReadSourceCache () && boost::filesystem::exists( - Factory::getInstance ().getCacheFolder () + "/" + mName); - bool writeCache = Factory::getInstance ().getWriteSourceCache (); - - - if (readCache) - { - std::ifstream ifs( std::string(Factory::getInstance ().getCacheFolder () + "/" + mName).c_str() ); - std::stringstream ss; - ss << ifs.rdbuf(); - source = ss.str(); - } - else - { - std::vector definitions; - - if (mParent->getType() == GPT_Vertex) - definitions.push_back("SH_VERTEX_SHADER"); - else - definitions.push_back("SH_FRAGMENT_SHADER"); - definitions.push_back(convertLang(Factory::getInstance().getCurrentLanguage())); - - parse(source, properties); - - if (Factory::getInstance ().getShaderDebugOutputEnabled ()) - writeDebugFile(source, name + ".pre"); - - // why do we need our own preprocessor? there are several custom commands available in the shader files - // (for example for binding uniforms to properties or auto constants) - more below. it is important that these - // commands are _only executed if the specific code path actually "survives" the compilation. - // thus, we run the code through a preprocessor first to remove the parts that are unused because of - // unmet #if conditions (or other preprocessor directives). - source = Preprocessor::preprocess(source, basePath, definitions, name); - - // parse counter - std::map counters; - while (true) - { - pos = source.find("@shCounter"); - if (pos == std::string::npos) - break; - - size_t end = source.find(")", pos); - - std::vector args = extractMacroArguments (pos, source); - assert(args.size()); - - int index = boost::lexical_cast(args[0]); - - if (counters.find(index) == counters.end()) - counters[index] = 0; - - source.replace(pos, (end+1)-pos, boost::lexical_cast(counters[index]++)); - } - - // parse passthrough declarations - while (true) - { - pos = source.find("@shAllocatePassthrough"); - if (pos == std::string::npos) - break; - - if (mCurrentPassthrough > 7) - throw std::runtime_error ("too many passthrough's requested (max 8)"); - - std::vector args = extractMacroArguments (pos, source); - assert(args.size() == 2); - - size_t end = source.find(")", pos); - - Passthrough passthrough; - - passthrough.num_components = boost::lexical_cast(args[0]); - assert (passthrough.num_components != 0); - - std::string passthroughName = args[1]; - passthrough.lang = Factory::getInstance().getCurrentLanguage (); - passthrough.component_start = mCurrentComponent; - passthrough.passthrough_number = mCurrentPassthrough; - - mPassthroughMap[passthroughName] = passthrough; - - mCurrentComponent += passthrough.num_components; - if (mCurrentComponent > 3) - { - mCurrentComponent -= 4; - ++mCurrentPassthrough; - } - - source.erase(pos, (end+1)-pos); - } - - // passthrough assign - while (true) - { - pos = source.find("@shPassthroughAssign"); - if (pos == std::string::npos) - break; - - std::vector args = extractMacroArguments (pos, source); - assert(args.size() == 2); - - size_t end = source.find(")", pos); - - std::string passthroughName = args[0]; - std::string assignTo = args[1]; - - assert(mPassthroughMap.find(passthroughName) != mPassthroughMap.end()); - Passthrough& p = mPassthroughMap[passthroughName]; - - source.replace(pos, (end+1)-pos, p.expand_assign(assignTo)); - } - - // passthrough receive - while (true) - { - pos = source.find("@shPassthroughReceive"); - if (pos == std::string::npos) - break; - - std::vector args = extractMacroArguments (pos, source); - assert(args.size() == 1); - - size_t end = source.find(")", pos); - std::string passthroughName = args[0]; - - assert(mPassthroughMap.find(passthroughName) != mPassthroughMap.end()); - Passthrough& p = mPassthroughMap[passthroughName]; - - source.replace(pos, (end+1)-pos, p.expand_receive()); - } - - // passthrough vertex outputs - while (true) - { - pos = source.find("@shPassthroughVertexOutputs"); - if (pos == std::string::npos) - break; - - std::string result; - for (int i = 0; i < mCurrentPassthrough+1; ++i) - { - // not using newlines here, otherwise the line numbers reported by compiler would be messed up.. - if (Factory::getInstance().getCurrentLanguage () == Language_CG || Factory::getInstance().getCurrentLanguage () == Language_HLSL) - result += ", out float4 passthrough" + boost::lexical_cast(i) + " : TEXCOORD" + boost::lexical_cast(i); - - /* - else - result += "out vec4 passthrough" + boost::lexical_cast(i) + "; "; - */ - else - result += "varying vec4 passthrough" + boost::lexical_cast(i) + "; "; - } - - source.replace(pos, std::string("@shPassthroughVertexOutputs").length(), result); - } - - // passthrough fragment inputs - while (true) - { - pos = source.find("@shPassthroughFragmentInputs"); - if (pos == std::string::npos) - break; - - std::string result; - for (int i = 0; i < mCurrentPassthrough+1; ++i) - { - // not using newlines here, otherwise the line numbers reported by compiler would be messed up.. - if (Factory::getInstance().getCurrentLanguage () == Language_CG || Factory::getInstance().getCurrentLanguage () == Language_HLSL) - result += ", in float4 passthrough" + boost::lexical_cast(i) + " : TEXCOORD" + boost::lexical_cast(i); - /* - else - result += "in vec4 passthrough" + boost::lexical_cast(i) + "; "; - */ - else - result += "varying vec4 passthrough" + boost::lexical_cast(i) + "; "; - } - - source.replace(pos, std::string("@shPassthroughFragmentInputs").length(), result); - } - } - - // save to cache _here_ - we want to preserve some macros - if (writeCache && !readCache) - { - std::ofstream of (std::string(Factory::getInstance ().getCacheFolder () + "/" + mName).c_str(), std::ios_base::out); - of.write(source.c_str(), source.size()); - of.close(); - } - - - // parse shared parameters - while (true) - { - pos = source.find("@shSharedParameter"); - if (pos == std::string::npos) - break; - - std::vector args = extractMacroArguments (pos, source); - assert(args.size()); - - size_t end = source.find(")", pos); - - mSharedParameters.push_back(args[0]); - - source.erase(pos, (end+1)-pos); - } - - // parse auto constants - typedef std::map< std::string, std::pair > AutoConstantMap; - AutoConstantMap autoConstants; - while (true) - { - pos = source.find("@shAutoConstant"); - if (pos == std::string::npos) - break; - - std::vector args = extractMacroArguments (pos, source); - assert(args.size() >= 2); - - size_t end = source.find(")", pos); - - std::string autoConstantName, uniformName; - std::string extraData; - - uniformName = args[0]; - autoConstantName = args[1]; - if (args.size() > 2) - extraData = args[2]; - - autoConstants[uniformName] = std::make_pair(autoConstantName, extraData); - - source.erase(pos, (end+1)-pos); - } - - // parse uniform properties - while (true) - { - pos = source.find("@shUniformProperty"); - if (pos == std::string::npos) - break; - - std::vector args = extractMacroArguments (pos, source); - assert(args.size() == 2); - - size_t start = source.find("(", pos); - size_t end = source.find(")", pos); - std::string cmd = source.substr(pos, start-pos); - - ValueType vt; - if (cmd == "@shUniformProperty4f") - vt = VT_Vector4; - else if (cmd == "@shUniformProperty3f") - vt = VT_Vector3; - else if (cmd == "@shUniformProperty2f") - vt = VT_Vector2; - else if (cmd == "@shUniformProperty1f") - vt = VT_Float; - else if (cmd == "@shUniformPropertyInt") - vt = VT_Int; - else - throw std::runtime_error ("unsupported command \"" + cmd + "\""); - - - std::string propertyName, uniformName; - uniformName = args[0]; - propertyName = args[1]; - mUniformProperties[uniformName] = std::make_pair(propertyName, vt); - - source.erase(pos, (end+1)-pos); - } - - // parse texture samplers used - while (true) - { - pos = source.find("@shUseSampler"); - if (pos == std::string::npos) - break; - - size_t end = source.find(")", pos); - - mUsedSamplers.push_back(extractMacroArguments (pos, source)[0]); - source.erase(pos, (end+1)-pos); - } - - // convert any left-over @'s to # - boost::algorithm::replace_all(source, "@", "#"); - - Platform* platform = Factory::getInstance().getPlatform(); - - std::string profile; - if (Factory::getInstance ().getCurrentLanguage () == Language_CG) - profile = mParent->getCgProfile (); - else if (Factory::getInstance ().getCurrentLanguage () == Language_HLSL) - profile = mParent->getHlslProfile (); - - - if (type == GPT_Vertex) - mProgram = boost::shared_ptr(platform->createGpuProgram(GPT_Vertex, "", mName, profile, source, Factory::getInstance().getCurrentLanguage())); - else if (type == GPT_Fragment) - mProgram = boost::shared_ptr(platform->createGpuProgram(GPT_Fragment, "", mName, profile, source, Factory::getInstance().getCurrentLanguage())); - - - if (Factory::getInstance ().getShaderDebugOutputEnabled ()) - writeDebugFile(source, name); - - if (!mProgram->getSupported()) - { - std::cerr << " Full source code below: \n" << source << std::endl; - mSupported = false; - return; - } - - // set auto constants - for (AutoConstantMap::iterator it = autoConstants.begin(); it != autoConstants.end(); ++it) - { - mProgram->setAutoConstant(it->first, it->second.first, it->second.second); - } - } - - std::string ShaderInstance::getName () - { - return mName; - } - - bool ShaderInstance::getSupported () const - { - return mSupported; - } - - std::vector ShaderInstance::getUsedSamplers() - { - return mUsedSamplers; - } - - void ShaderInstance::setUniformParameters (boost::shared_ptr pass, PropertySetGet* properties) - { - for (UniformMap::iterator it = mUniformProperties.begin(); it != mUniformProperties.end(); ++it) - { - pass->setGpuConstant(mParent->getType(), it->first, it->second.second, properties->getProperty(it->second.first), properties->getContext()); - } - } - - std::vector ShaderInstance::extractMacroArguments (size_t pos, const std::string& source) - { - size_t start = source.find("(", pos); - size_t end = source.find(")", pos); - std::string args = source.substr(start+1, end-(start+1)); - std::vector results; - boost::algorithm::split(results, args, boost::is_any_of(",")); - std::for_each(results.begin(), results.end(), - boost::bind(&boost::trim, - _1, std::locale() )); - return results; - } -} diff --git a/extern/shiny/Main/ShaderInstance.hpp b/extern/shiny/Main/ShaderInstance.hpp deleted file mode 100644 index 76326ce0c..000000000 --- a/extern/shiny/Main/ShaderInstance.hpp +++ /dev/null @@ -1,71 +0,0 @@ -#ifndef SH_SHADERINSTANCE_H -#define SH_SHADERINSTANCE_H - -#include - -#include "Platform.hpp" - -namespace sh -{ - class ShaderSet; - - typedef std::map< std::string, std::pair > UniformMap; - - struct Passthrough - { - Language lang; ///< language to generate for - - int num_components; ///< e.g. 4 for a float4 - - int passthrough_number; - int component_start; ///< 0 = x - - std::string expand_assign(std::string assignTo); - std::string expand_receive(); - }; - typedef std::map PassthroughMap; - - /** - * @brief A specific instance of a \a ShaderSet with a deterministic shader source - */ - class ShaderInstance - { - public: - ShaderInstance (ShaderSet* parent, const std::string& name, PropertySetGet* properties); - - std::string getName(); - - bool getSupported () const; - - std::vector getUsedSamplers(); - std::vector getSharedParameters() { return mSharedParameters; } - - void setUniformParameters (boost::shared_ptr pass, PropertySetGet* properties); - - private: - boost::shared_ptr mProgram; - std::string mName; - ShaderSet* mParent; - bool mSupported; ///< shader compilation was sucessful? - - std::vector mUsedSamplers; - ///< names of the texture samplers that are used by this shader - - std::vector mSharedParameters; - - UniformMap mUniformProperties; - ///< uniforms that this depends on, and their property names / value-types - /// @note this lists shared uniform parameters as well - - int mCurrentPassthrough; ///< 0 - x - int mCurrentComponent; ///< 0:x, 1:y, 2:z, 3:w - - PassthroughMap mPassthroughMap; - - std::vector extractMacroArguments (size_t pos, const std::string& source); ///< take a macro invocation and return vector of arguments - - void parse (std::string& source, PropertySetGet* properties); - }; -} - -#endif diff --git a/extern/shiny/Main/ShaderSet.cpp b/extern/shiny/Main/ShaderSet.cpp deleted file mode 100644 index 8fb530d39..000000000 --- a/extern/shiny/Main/ShaderSet.cpp +++ /dev/null @@ -1,195 +0,0 @@ -#include "ShaderSet.hpp" - -#include -#include - -#include -#include -#include -#include - -#include "Factory.hpp" - -namespace sh -{ - ShaderSet::ShaderSet (const std::string& type, const std::string& cgProfile, const std::string& hlslProfile, const std::string& sourceFile, const std::string& basePath, - const std::string& name, PropertySetGet* globalSettingsPtr) - : mBasePath(basePath) - , mName(name) - , mCgProfile(cgProfile) - , mHlslProfile(hlslProfile) - { - if (type == "vertex") - mType = GPT_Vertex; - else // if (type == "fragment") - mType = GPT_Fragment; - - std::ifstream stream(sourceFile.c_str(), std::ifstream::in); - std::stringstream buffer; - - boost::filesystem::path p (sourceFile); - p = p.branch_path(); - mBasePath = p.string(); - - buffer << stream.rdbuf(); - stream.close(); - mSource = buffer.str(); - parse(); - } - - ShaderSet::~ShaderSet() - { - for (ShaderInstanceMap::iterator it = mInstances.begin(); it != mInstances.end(); ++it) - { - sh::Factory::getInstance().getPlatform()->destroyGpuProgram(it->second.getName()); - } - } - - void ShaderSet::parse() - { - std::string currentToken; - bool tokenIsRecognized = false; - bool isInBraces = false; - for (std::string::const_iterator it = mSource.begin(); it != mSource.end(); ++it) - { - char c = *it; - if (((c == ' ') && !isInBraces) || (c == '\n') || - ( ((c == '(') || (c == ')')) - && !tokenIsRecognized)) - { - if (tokenIsRecognized) - { - if (boost::starts_with(currentToken, "@shGlobalSetting")) - { - assert ((currentToken.find('(') != std::string::npos) && (currentToken.find(')') != std::string::npos)); - size_t start = currentToken.find('(')+1; - mGlobalSettings.push_back(currentToken.substr(start, currentToken.find(')')-start)); - } - else if (boost::starts_with(currentToken, "@shPropertyHasValue")) - { - assert ((currentToken.find('(') != std::string::npos) && (currentToken.find(')') != std::string::npos)); - size_t start = currentToken.find('(')+1; - mPropertiesToExist.push_back(currentToken.substr(start, currentToken.find(')')-start)); - } - else if (boost::starts_with(currentToken, "@shPropertyEqual")) - { - assert ((currentToken.find('(') != std::string::npos) && (currentToken.find(')') != std::string::npos) - && (currentToken.find(',') != std::string::npos)); - size_t start = currentToken.find('(')+1; - size_t end = currentToken.find(','); - mProperties.push_back(currentToken.substr(start, end-start)); - } - else if (boost::starts_with(currentToken, "@shProperty")) - { - assert ((currentToken.find('(') != std::string::npos) && (currentToken.find(')') != std::string::npos)); - size_t start = currentToken.find('(')+1; - std::string propertyName = currentToken.substr(start, currentToken.find(')')-start); - // if the property name is constructed dynamically (e.g. through an iterator) then there is nothing we can do - if (propertyName.find("@") == std::string::npos) - mProperties.push_back(propertyName); - } - } - - currentToken = ""; - } - else - { - if (currentToken == "") - { - if (c == '@') - tokenIsRecognized = true; - else - tokenIsRecognized = false; - } - else - { - if (c == '@') - { - // ouch, there are nested macros - // ( for example @shForeach(@shPropertyString(foobar)) ) - currentToken = ""; - } - } - - if (c == '(' && tokenIsRecognized) - isInBraces = true; - else if (c == ')' && tokenIsRecognized) - isInBraces = false; - - currentToken += c; - - } - } - } - - ShaderInstance* ShaderSet::getInstance (PropertySetGet* properties) - { - size_t h = buildHash (properties); - if (std::find(mFailedToCompile.begin(), mFailedToCompile.end(), h) != mFailedToCompile.end()) - return NULL; - if (mInstances.find(h) == mInstances.end()) - { - ShaderInstance newInstance(this, mName + "_" + boost::lexical_cast(h), properties); - if (!newInstance.getSupported()) - { - mFailedToCompile.push_back(h); - return NULL; - } - mInstances.insert(std::make_pair(h, newInstance)); - } - return &mInstances.find(h)->second; - } - - size_t ShaderSet::buildHash (PropertySetGet* properties) - { - size_t seed = 0; - PropertySetGet* currentGlobalSettings = getCurrentGlobalSettings (); - - for (std::vector::iterator it = mProperties.begin(); it != mProperties.end(); ++it) - { - std::string v = retrieveValue(properties->getProperty(*it), properties->getContext()).get(); - boost::hash_combine(seed, v); - } - for (std::vector ::iterator it = mGlobalSettings.begin(); it != mGlobalSettings.end(); ++it) - { - boost::hash_combine(seed, retrieveValue(currentGlobalSettings->getProperty(*it), NULL).get()); - } - for (std::vector::iterator it = mPropertiesToExist.begin(); it != mPropertiesToExist.end(); ++it) - { - std::string v = retrieveValue(properties->getProperty(*it), properties->getContext()).get(); - boost::hash_combine(seed, static_cast(v != "")); - } - boost::hash_combine(seed, static_cast(Factory::getInstance().getCurrentLanguage())); - return seed; - } - - PropertySetGet* ShaderSet::getCurrentGlobalSettings() const - { - return Factory::getInstance ().getCurrentGlobalSettings (); - } - - std::string ShaderSet::getBasePath() const - { - return mBasePath; - } - - std::string ShaderSet::getSource() const - { - return mSource; - } - - std::string ShaderSet::getCgProfile() const - { - return mCgProfile; - } - - std::string ShaderSet::getHlslProfile() const - { - return mHlslProfile; - } - - int ShaderSet::getType() const - { - return mType; - } -} diff --git a/extern/shiny/Main/ShaderSet.hpp b/extern/shiny/Main/ShaderSet.hpp deleted file mode 100644 index 988c6769f..000000000 --- a/extern/shiny/Main/ShaderSet.hpp +++ /dev/null @@ -1,69 +0,0 @@ -#ifndef SH_SHADERSET_H -#define SH_SHADERSET_H - -#include -#include -#include - -#include "ShaderInstance.hpp" - -namespace sh -{ - class PropertySetGet; - - typedef std::map ShaderInstanceMap; - - /** - * @brief Contains possible shader permutations of a single uber-shader (represented by one source file) - */ - class ShaderSet - { - public: - ShaderSet (const std::string& type, const std::string& cgProfile, const std::string& hlslProfile, const std::string& sourceFile, const std::string& basePath, - const std::string& name, PropertySetGet* globalSettingsPtr); - ~ShaderSet(); - - /// Retrieve a shader instance for the given properties. \n - /// If a \a ShaderInstance with the same properties exists already, simply returns this instance. \n - /// Otherwise, creates a new \a ShaderInstance (i.e. compiles a new shader). \n - /// Might also return NULL if the shader failed to compile. \n - /// @note Only the properties that actually affect the shader source are taken into consideration here, - /// so it does not matter if you pass any extra properties that the shader does not care about. - ShaderInstance* getInstance (PropertySetGet* properties); - - private: - PropertySetGet* getCurrentGlobalSettings() const; - std::string getBasePath() const; - std::string getSource() const; - std::string getCgProfile() const; - std::string getHlslProfile() const; - int getType() const; - - friend class ShaderInstance; - - private: - GpuProgramType mType; - std::string mSource; - std::string mBasePath; - std::string mCgProfile; - std::string mHlslProfile; - std::string mName; - - std::vector mFailedToCompile; - - std::vector mGlobalSettings; ///< names of the global settings that affect the shader source - std::vector mProperties; ///< names of the per-material properties that affect the shader source - - std::vector mPropertiesToExist; - ///< same as mProperties, however in this case, it is only relevant if the property is empty or not - /// (we don't care about the value) - - ShaderInstanceMap mInstances; ///< maps permutation ID (generated from the properties) to \a ShaderInstance - - void parse(); ///< find out which properties and global settings affect the shader source - - size_t buildHash (PropertySetGet* properties); - }; -} - -#endif diff --git a/extern/shiny/Platforms/Ogre/OgreGpuProgram.cpp b/extern/shiny/Platforms/Ogre/OgreGpuProgram.cpp deleted file mode 100644 index e71854019..000000000 --- a/extern/shiny/Platforms/Ogre/OgreGpuProgram.cpp +++ /dev/null @@ -1,69 +0,0 @@ -#include - -#include "OgreGpuProgram.hpp" - -#include - -#include -#include -#include - -namespace sh -{ - OgreGpuProgram::OgreGpuProgram( - GpuProgramType type, - const std::string& compileArguments, - const std::string& name, const std::string& profile, - const std::string& source, const std::string& lang, - const std::string& resourceGroup) - : GpuProgram() - { - Ogre::HighLevelGpuProgramManager& mgr = Ogre::HighLevelGpuProgramManager::getSingleton(); - assert (mgr.getByName(name).isNull() && "Vertex program already exists"); - - Ogre::GpuProgramType t; - if (type == GPT_Vertex) - t = Ogre::GPT_VERTEX_PROGRAM; - else - t = Ogre::GPT_FRAGMENT_PROGRAM; - - mProgram = mgr.createProgram(name, resourceGroup, lang, t); - if (lang != "glsl" && lang != "glsles") - mProgram->setParameter("entry_point", "main"); - if (lang == "hlsl") - mProgram->setParameter("target", profile); - else if (lang == "cg") - mProgram->setParameter("profiles", profile); - - mProgram->setSource(source); - mProgram->load(); - - if (mProgram.isNull() || !mProgram->isSupported()) - std::cerr << "Failed to compile shader \"" << name << "\". Consider the OGRE log for more information." << std::endl; - } - - bool OgreGpuProgram::getSupported() - { - return (!mProgram.isNull() && mProgram->isSupported()); - } - - void OgreGpuProgram::setAutoConstant (const std::string& name, const std::string& autoConstantName, const std::string& extraInfo) - { - assert (!mProgram.isNull() && mProgram->isSupported()); - const Ogre::GpuProgramParameters::AutoConstantDefinition* d = Ogre::GpuProgramParameters::getAutoConstantDefinition(autoConstantName); - - if (!d) - throw std::runtime_error ("can't find auto constant with name \"" + autoConstantName + "\""); - Ogre::GpuProgramParameters::AutoConstantType t = d->acType; - - // this simplifies debugging for CG a lot. - mProgram->getDefaultParameters()->setIgnoreMissingParams(true); - - if (d->dataType == Ogre::GpuProgramParameters::ACDT_NONE) - mProgram->getDefaultParameters()->setNamedAutoConstant (name, t, 0); - else if (d->dataType == Ogre::GpuProgramParameters::ACDT_INT) - mProgram->getDefaultParameters()->setNamedAutoConstant (name, t, extraInfo == "" ? 0 : boost::lexical_cast(extraInfo)); - else if (d->dataType == Ogre::GpuProgramParameters::ACDT_REAL) - mProgram->getDefaultParameters()->setNamedAutoConstantReal (name, t, extraInfo == "" ? 0.f : boost::lexical_cast(extraInfo)); - } -} diff --git a/extern/shiny/Platforms/Ogre/OgreGpuProgram.hpp b/extern/shiny/Platforms/Ogre/OgreGpuProgram.hpp deleted file mode 100644 index 42673ed9b..000000000 --- a/extern/shiny/Platforms/Ogre/OgreGpuProgram.hpp +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef SH_OGREGPUPROGRAM_H -#define SH_OGREGPUPROGRAM_H - -#include - -#include - -#include "../../Main/Platform.hpp" - -namespace sh -{ - class OgreGpuProgram : public GpuProgram - { - public: - OgreGpuProgram ( - GpuProgramType type, - const std::string& compileArguments, - const std::string& name, const std::string& profile, - const std::string& source, const std::string& lang, - const std::string& resourceGroup); - - virtual bool getSupported(); - - virtual void setAutoConstant (const std::string& name, const std::string& autoConstantName, const std::string& extraInfo = ""); - - private: - Ogre::HighLevelGpuProgramPtr mProgram; - }; -} - -#endif diff --git a/extern/shiny/Platforms/Ogre/OgreMaterial.cpp b/extern/shiny/Platforms/Ogre/OgreMaterial.cpp deleted file mode 100644 index 04560e1f9..000000000 --- a/extern/shiny/Platforms/Ogre/OgreMaterial.cpp +++ /dev/null @@ -1,120 +0,0 @@ -#include "OgreMaterial.hpp" - -#include -#include -#include - -#include "OgrePass.hpp" -#include "OgreMaterialSerializer.hpp" -#include "OgrePlatform.hpp" - -namespace sh -{ - static const std::string sDefaultTechniqueName = "SH_DefaultTechnique"; - - OgreMaterial::OgreMaterial (const std::string& name, const std::string& resourceGroup) - : Material() - { - mName = name; - assert (Ogre::MaterialManager::getSingleton().getByName(name).isNull() && "Material already exists"); - mMaterial = Ogre::MaterialManager::getSingleton().create (name, resourceGroup); - mMaterial->removeAllTechniques(); - mMaterial->createTechnique()->setSchemeName (sDefaultTechniqueName); - mMaterial->compile(); - } - - void OgreMaterial::ensureLoaded() - { - if (mMaterial.isNull()) - mMaterial = Ogre::MaterialManager::getSingleton().getByName(mName); - } - - bool OgreMaterial::isUnreferenced() - { - // Resource system internals hold 3 shared pointers, we hold one, so usecount of 4 means unused - return (!mMaterial.isNull() && mMaterial.useCount() <= Ogre::ResourceGroupManager::RESOURCE_SYSTEM_NUM_REFERENCE_COUNTS+1); - } - - void OgreMaterial::unreferenceTextures() - { - mMaterial->unload(); - } - - OgreMaterial::~OgreMaterial() - { - if (!mMaterial.isNull()) - Ogre::MaterialManager::getSingleton().remove(mMaterial->getName()); - } - - boost::shared_ptr OgreMaterial::createPass (const std::string& configuration, unsigned short lodIndex) - { - return boost::shared_ptr (new OgrePass (this, configuration, lodIndex)); - } - - void OgreMaterial::removeAll () - { - if (mMaterial.isNull()) - return; - mMaterial->removeAllTechniques(); - mMaterial->createTechnique()->setSchemeName (sDefaultTechniqueName); - mMaterial->compile(); - } - - void OgreMaterial::setLodLevels (const std::string& lodLevels) - { - OgreMaterialSerializer& s = OgrePlatform::getSerializer(); - - s.setMaterialProperty ("lod_values", lodLevels, mMaterial); - } - - bool OgreMaterial::createConfiguration (const std::string& name, unsigned short lodIndex) - { - for (int i=0; igetNumTechniques(); ++i) - { - if (mMaterial->getTechnique(i)->getSchemeName() == name && mMaterial->getTechnique(i)->getLodIndex() == lodIndex) - return false; - } - - Ogre::Technique* t = mMaterial->createTechnique(); - t->setSchemeName (name); - t->setLodIndex (lodIndex); - if (mShadowCasterMaterial != "") - t->setShadowCasterMaterial(mShadowCasterMaterial); - - mMaterial->compile(); - - return true; - } - - Ogre::MaterialPtr OgreMaterial::getOgreMaterial () - { - return mMaterial; - } - - Ogre::Technique* OgreMaterial::getOgreTechniqueForConfiguration (const std::string& configurationName, unsigned short lodIndex) - { - for (int i=0; igetNumTechniques(); ++i) - { - if (mMaterial->getTechnique(i)->getSchemeName() == configurationName && mMaterial->getTechnique(i)->getLodIndex() == lodIndex) - { - return mMaterial->getTechnique(i); - } - } - - // Prepare and throw error message - std::stringstream message; - message << "Could not find configurationName '" << configurationName - << "' and lodIndex " << lodIndex; - - throw std::runtime_error(message.str()); - } - - void OgreMaterial::setShadowCasterMaterial (const std::string& name) - { - mShadowCasterMaterial = name; - for (int i=0; igetNumTechniques(); ++i) - { - mMaterial->getTechnique(i)->setShadowCasterMaterial(mShadowCasterMaterial); - } - } -} diff --git a/extern/shiny/Platforms/Ogre/OgreMaterial.hpp b/extern/shiny/Platforms/Ogre/OgreMaterial.hpp deleted file mode 100644 index 67a2c26e8..000000000 --- a/extern/shiny/Platforms/Ogre/OgreMaterial.hpp +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef SH_OGREMATERIAL_H -#define SH_OGREMATERIAL_H - -#include - -#include - -#include "../../Main/Platform.hpp" - -namespace sh -{ - class OgreMaterial : public Material - { - public: - OgreMaterial (const std::string& name, const std::string& resourceGroup); - virtual ~OgreMaterial(); - - virtual boost::shared_ptr createPass (const std::string& configuration, unsigned short lodIndex); - virtual bool createConfiguration (const std::string& name, unsigned short lodIndex); - - virtual bool isUnreferenced(); - virtual void unreferenceTextures(); - virtual void ensureLoaded(); - - virtual void removeAll (); - - Ogre::MaterialPtr getOgreMaterial(); - - virtual void setLodLevels (const std::string& lodLevels); - - Ogre::Technique* getOgreTechniqueForConfiguration (const std::string& configurationName, unsigned short lodIndex = 0); - - virtual void setShadowCasterMaterial (const std::string& name); - - private: - Ogre::MaterialPtr mMaterial; - std::string mName; - - std::string mShadowCasterMaterial; - }; -} - -#endif diff --git a/extern/shiny/Platforms/Ogre/OgreMaterialSerializer.cpp b/extern/shiny/Platforms/Ogre/OgreMaterialSerializer.cpp deleted file mode 100644 index f45e64155..000000000 --- a/extern/shiny/Platforms/Ogre/OgreMaterialSerializer.cpp +++ /dev/null @@ -1,85 +0,0 @@ -#include "OgreMaterialSerializer.hpp" - -#include - -#include - -namespace sh -{ - void OgreMaterialSerializer::reset() - { - mScriptContext.section = Ogre::MSS_NONE; - mScriptContext.material.setNull(); - mScriptContext.technique = 0; - mScriptContext.pass = 0; - mScriptContext.textureUnit = 0; - mScriptContext.program.setNull(); - mScriptContext.lineNo = 0; - mScriptContext.filename.clear(); - mScriptContext.techLev = -1; - mScriptContext.passLev = -1; - mScriptContext.stateLev = -1; - } - - bool OgreMaterialSerializer::setPassProperty (const std::string& param, std::string value, Ogre::Pass* pass) - { - // workaround https://ogre3d.atlassian.net/browse/OGRE-158 - if (param == "transparent_sorting" && value == "force") - { - pass->setTransparentSortingForced(true); - return true; - } - - reset(); - - mScriptContext.section = Ogre::MSS_PASS; - mScriptContext.pass = pass; - - if (mPassAttribParsers.find (param) == mPassAttribParsers.end()) - return false; - else - { - mPassAttribParsers.find(param)->second(value, mScriptContext); - return true; - } - } - - bool OgreMaterialSerializer::setTextureUnitProperty (const std::string& param, std::string value, Ogre::TextureUnitState* t) - { - // quick access to automip setting, without having to use 'texture' which doesn't like spaces in filenames - if (param == "num_mipmaps") - { - t->setNumMipmaps(Ogre::StringConverter::parseInt(value)); - return true; - } - - reset(); - - mScriptContext.section = Ogre::MSS_TEXTUREUNIT; - mScriptContext.textureUnit = t; - - if (mTextureUnitAttribParsers.find (param) == mTextureUnitAttribParsers.end()) - return false; - else - { - mTextureUnitAttribParsers.find(param)->second(value, mScriptContext); - return true; - } - } - - bool OgreMaterialSerializer::setMaterialProperty (const std::string& param, std::string value, Ogre::MaterialPtr m) - { - reset(); - - mScriptContext.section = Ogre::MSS_MATERIAL; - mScriptContext.material = m; - - if (mMaterialAttribParsers.find (param) == mMaterialAttribParsers.end()) - return false; - else - { - mMaterialAttribParsers.find(param)->second(value, mScriptContext); - return true; - } - } -} diff --git a/extern/shiny/Platforms/Ogre/OgreMaterialSerializer.hpp b/extern/shiny/Platforms/Ogre/OgreMaterialSerializer.hpp deleted file mode 100644 index acfc5a362..000000000 --- a/extern/shiny/Platforms/Ogre/OgreMaterialSerializer.hpp +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef SH_OGREMATERIALSERIALIZER_H -#define SH_OGREMATERIALSERIALIZER_H - -#include - -namespace Ogre -{ - class Pass; -} - -namespace sh -{ - /** - * @brief This class allows me to let Ogre handle the pass & texture unit properties - */ - class OgreMaterialSerializer : public Ogre::MaterialSerializer - { - public: - bool setPassProperty (const std::string& param, std::string value, Ogre::Pass* pass); - bool setTextureUnitProperty (const std::string& param, std::string value, Ogre::TextureUnitState* t); - bool setMaterialProperty (const std::string& param, std::string value, Ogre::MaterialPtr m); - - private: - void reset(); - }; - -} - -#endif diff --git a/extern/shiny/Platforms/Ogre/OgrePass.cpp b/extern/shiny/Platforms/Ogre/OgrePass.cpp deleted file mode 100644 index 5cd501094..000000000 --- a/extern/shiny/Platforms/Ogre/OgrePass.cpp +++ /dev/null @@ -1,131 +0,0 @@ -#include - -#include "OgrePass.hpp" - -#include -#include - -#include "OgreTextureUnitState.hpp" -#include "OgreGpuProgram.hpp" -#include "OgreMaterial.hpp" -#include "OgreMaterialSerializer.hpp" -#include "OgrePlatform.hpp" - -namespace sh -{ - OgrePass::OgrePass (OgreMaterial* parent, const std::string& configuration, unsigned short lodIndex) - : Pass() - { - Ogre::Technique* t = parent->getOgreTechniqueForConfiguration(configuration, lodIndex); - mPass = t->createPass(); - } - - boost::shared_ptr OgrePass::createTextureUnitState (const std::string& name) - { - return boost::shared_ptr (new OgreTextureUnitState (this, name)); - } - - void OgrePass::assignProgram (GpuProgramType type, const std::string& name) - { - if (type == GPT_Vertex) - mPass->setVertexProgram (name); - else if (type == GPT_Fragment) - mPass->setFragmentProgram (name); - else - throw std::runtime_error("unsupported GpuProgramType"); - } - - Ogre::Pass* OgrePass::getOgrePass () - { - return mPass; - } - - bool OgrePass::setPropertyOverride (const std::string &name, PropertyValuePtr& value, PropertySetGet* context) - { - if (((typeid(*value) == typeid(StringValue)) || typeid(*value) == typeid(LinkedValue)) - && retrieveValue(value, context).get() == "default") - return true; - - if (name == "vertex_program") - return true; // handled already - else if (name == "fragment_program") - return true; // handled already - else - { - OgreMaterialSerializer& s = OgrePlatform::getSerializer(); - - return s.setPassProperty (name, retrieveValue(value, context).get(), mPass); - } - } - - void OgrePass::setGpuConstant (int type, const std::string& name, ValueType vt, PropertyValuePtr value, PropertySetGet* context) - { - Ogre::GpuProgramParametersSharedPtr params; - if (type == GPT_Vertex) - { - if (!mPass->hasVertexProgram ()) - return; - params = mPass->getVertexProgramParameters(); - } - else if (type == GPT_Fragment) - { - if (!mPass->hasFragmentProgram ()) - return; - params = mPass->getFragmentProgramParameters(); - } - - if (vt == VT_Float) - params->setNamedConstant (name, retrieveValue(value, context).get()); - else if (vt == VT_Int) - params->setNamedConstant (name, retrieveValue(value, context).get()); - else if (vt == VT_Vector4) - { - Vector4 v = retrieveValue(value, context); - params->setNamedConstant (name, Ogre::Vector4(v.mX, v.mY, v.mZ, v.mW)); - } - else if (vt == VT_Vector3) - { - Vector3 v = retrieveValue(value, context); - params->setNamedConstant (name, Ogre::Vector4(v.mX, v.mY, v.mZ, 1.0)); - } - else if (vt == VT_Vector2) - { - Vector2 v = retrieveValue(value, context); - params->setNamedConstant (name, Ogre::Vector4(v.mX, v.mY, 1.0, 1.0)); - } - else - throw std::runtime_error ("unsupported constant type"); - } - - void OgrePass::addSharedParameter (int type, const std::string& name) - { - Ogre::GpuProgramParametersSharedPtr params; - if (type == GPT_Vertex) - params = mPass->getVertexProgramParameters(); - else if (type == GPT_Fragment) - params = mPass->getFragmentProgramParameters(); - - try - { - params->addSharedParameters (name); - } - catch (Ogre::Exception& ) - { - std::stringstream msg; - msg << "Could not create a shared parameter instance for '" - << name << "'. Make sure this shared parameter has a value set (via Factory::setSharedParameter)!"; - throw std::runtime_error(msg.str()); - } - } - - void OgrePass::setTextureUnitIndex (int programType, const std::string& name, int index) - { - Ogre::GpuProgramParametersSharedPtr params; - if (programType == GPT_Vertex) - params = mPass->getVertexProgramParameters(); - else if (programType == GPT_Fragment) - params = mPass->getFragmentProgramParameters(); - - params->setNamedConstant(name, index); - } -} diff --git a/extern/shiny/Platforms/Ogre/OgrePass.hpp b/extern/shiny/Platforms/Ogre/OgrePass.hpp deleted file mode 100644 index e7cfd4e33..000000000 --- a/extern/shiny/Platforms/Ogre/OgrePass.hpp +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef SH_OGREPASS_H -#define SH_OGREPASS_H - -#include - -#include "../../Main/Platform.hpp" - -namespace sh -{ - class OgreMaterial; - - class OgrePass : public Pass - { - public: - OgrePass (OgreMaterial* parent, const std::string& configuration, unsigned short lodIndex); - - virtual boost::shared_ptr createTextureUnitState (const std::string& name); - virtual void assignProgram (GpuProgramType type, const std::string& name); - - Ogre::Pass* getOgrePass(); - - virtual void setGpuConstant (int type, const std::string& name, ValueType vt, PropertyValuePtr value, PropertySetGet* context); - - virtual void addSharedParameter (int type, const std::string& name); - virtual void setTextureUnitIndex (int programType, const std::string& name, int index); - - private: - Ogre::Pass* mPass; - - protected: - virtual bool setPropertyOverride (const std::string &name, PropertyValuePtr& value, PropertySetGet* context); - }; -} - -#endif diff --git a/extern/shiny/Platforms/Ogre/OgrePlatform.cpp b/extern/shiny/Platforms/Ogre/OgrePlatform.cpp deleted file mode 100644 index aa01c8ba1..000000000 --- a/extern/shiny/Platforms/Ogre/OgrePlatform.cpp +++ /dev/null @@ -1,193 +0,0 @@ -#include - -#include "OgrePlatform.hpp" - -#include -#include -#include -#include - -#include "OgreMaterial.hpp" -#include "OgreGpuProgram.hpp" -#include "OgreMaterialSerializer.hpp" - -#include "../../Main/MaterialInstance.hpp" -#include "../../Main/Factory.hpp" - -namespace -{ - std::string convertLang (sh::Language lang) - { - if (lang == sh::Language_CG) - return "cg"; - else if (lang == sh::Language_HLSL) - return "hlsl"; - else if (lang == sh::Language_GLSL) - return "glsl"; - else if (lang == sh::Language_GLSLES) - return "glsles"; - throw std::runtime_error ("invalid language, valid are: cg, hlsl, glsl, glsles"); - } -} - -namespace sh -{ - OgreMaterialSerializer* OgrePlatform::sSerializer = 0; - - OgrePlatform::OgrePlatform(const std::string& resourceGroupName, const std::string& basePath) - : Platform(basePath) - , mResourceGroup(resourceGroupName) - { - Ogre::MaterialManager::getSingleton().addListener(this); - - if (supportsShaderSerialization()) - Ogre::GpuProgramManager::getSingletonPtr()->setSaveMicrocodesToCache(true); - - sSerializer = new OgreMaterialSerializer(); - } - - OgreMaterialSerializer& OgrePlatform::getSerializer() - { - assert(sSerializer); - return *sSerializer; - } - - OgrePlatform::~OgrePlatform () - { - Ogre::MaterialManager::getSingleton().removeListener(this); - - delete sSerializer; - } - - bool OgrePlatform::isProfileSupported (const std::string& profile) - { - return Ogre::GpuProgramManager::getSingleton().isSyntaxSupported(profile); - } - - bool OgrePlatform::supportsShaderSerialization () - { - #if OGRE_VERSION >= (1 << 16 | 9 << 8 | 0) - return true; - #else - return Ogre::Root::getSingleton ().getRenderSystem ()->getName ().find("OpenGL") == std::string::npos; - #endif - } - - bool OgrePlatform::supportsMaterialQueuedListener () - { - return true; - } - - boost::shared_ptr OgrePlatform::createMaterial (const std::string& name) - { - OgreMaterial* material = new OgreMaterial(name, mResourceGroup); - return boost::shared_ptr (material); - } - - void OgrePlatform::destroyGpuProgram(const std::string &name) - { - Ogre::HighLevelGpuProgramManager::getSingleton().remove(name); - } - - boost::shared_ptr OgrePlatform::createGpuProgram ( - GpuProgramType type, - const std::string& compileArguments, - const std::string& name, const std::string& profile, - const std::string& source, Language lang) - { - OgreGpuProgram* prog = new OgreGpuProgram (type, compileArguments, name, profile, source, convertLang(lang), mResourceGroup); - return boost::shared_ptr (static_cast(prog)); - } - - Ogre::Technique* OgrePlatform::handleSchemeNotFound ( - unsigned short schemeIndex, const Ogre::String &schemeName, Ogre::Material *originalMaterial, - unsigned short lodIndex, const Ogre::Renderable *rend) - { - MaterialInstance* m = fireMaterialRequested(originalMaterial->getName(), schemeName, lodIndex); - if (m) - { - OgreMaterial* _m = static_cast(m->getMaterial()); - return _m->getOgreTechniqueForConfiguration (schemeName, lodIndex); - } - else - return 0; // material does not belong to us - } - - void OgrePlatform::serializeShaders (const std::string& file) - { - #if OGRE_VERSION >= (1 << 16 | 9 << 8 | 0) - if (Ogre::GpuProgramManager::getSingleton().isCacheDirty()) - #endif - { - std::fstream output; - output.open(file.c_str(), std::ios::out | std::ios::binary); - Ogre::DataStreamPtr shaderCache (OGRE_NEW Ogre::FileStreamDataStream(file, &output, false)); - Ogre::GpuProgramManager::getSingleton().saveMicrocodeCache(shaderCache); - } - } - - void OgrePlatform::deserializeShaders (const std::string& file) - { - std::ifstream inp; - inp.open(file.c_str(), std::ios::in | std::ios::binary); - Ogre::DataStreamPtr shaderCache(OGRE_NEW Ogre::FileStreamDataStream(file, &inp, false)); - Ogre::GpuProgramManager::getSingleton().loadMicrocodeCache(shaderCache); - } - - void OgrePlatform::setSharedParameter (const std::string& name, PropertyValuePtr value) - { - Ogre::GpuSharedParametersPtr params; - if (mSharedParameters.find(name) == mSharedParameters.end()) - { - params = Ogre::GpuProgramManager::getSingleton().createSharedParameters(name); - - Ogre::GpuConstantType type; - if (typeid(*value) == typeid(Vector4)) - type = Ogre::GCT_FLOAT4; - else if (typeid(*value) == typeid(Vector3)) - type = Ogre::GCT_FLOAT3; - else if (typeid(*value) == typeid(Vector2)) - type = Ogre::GCT_FLOAT2; - else if (typeid(*value) == typeid(FloatValue)) - type = Ogre::GCT_FLOAT1; - else if (typeid(*value) == typeid(IntValue)) - type = Ogre::GCT_INT1; - else - throw std::runtime_error("unexpected type"); - params->addConstantDefinition(name, type); - mSharedParameters[name] = params; - } - else - params = mSharedParameters.find(name)->second; - - Ogre::Vector4 v (1.0, 1.0, 1.0, 1.0); - if (typeid(*value) == typeid(Vector4)) - { - Vector4 vec = retrieveValue(value, NULL); - v.x = vec.mX; - v.y = vec.mY; - v.z = vec.mZ; - v.w = vec.mW; - } - else if (typeid(*value) == typeid(Vector3)) - { - Vector3 vec = retrieveValue(value, NULL); - v.x = vec.mX; - v.y = vec.mY; - v.z = vec.mZ; - } - else if (typeid(*value) == typeid(Vector2)) - { - Vector2 vec = retrieveValue(value, NULL); - v.x = vec.mX; - v.y = vec.mY; - } - else if (typeid(*value) == typeid(FloatValue)) - v.x = retrieveValue(value, NULL).get(); - else if (typeid(*value) == typeid(IntValue)) - v.x = static_cast(retrieveValue(value, NULL).get()); - else - throw std::runtime_error ("unsupported property type for shared parameter \"" + name + "\""); - params->setNamedConstant(name, v); - } -} diff --git a/extern/shiny/Platforms/Ogre/OgrePlatform.hpp b/extern/shiny/Platforms/Ogre/OgrePlatform.hpp deleted file mode 100644 index d3a1a8360..000000000 --- a/extern/shiny/Platforms/Ogre/OgrePlatform.hpp +++ /dev/null @@ -1,74 +0,0 @@ -#ifndef SH_OGREPLATFORM_H -#define SH_OGREPLATFORM_H - -/** - * @addtogroup Platforms - * @{ - */ - -/** - * @addtogroup Ogre - * A set of classes to interact with Ogre's material system - * @{ - */ - -#include "../../Main/Platform.hpp" - -#include -#include - -namespace sh -{ - class OgreMaterialSerializer; - - class OgrePlatform : public Platform, public Ogre::MaterialManager::Listener - { - public: - OgrePlatform (const std::string& resourceGroupName, const std::string& basePath); - virtual ~OgrePlatform (); - - virtual Ogre::Technique* handleSchemeNotFound ( - unsigned short schemeIndex, const Ogre::String &schemeName, Ogre::Material *originalMaterial, - unsigned short lodIndex, const Ogre::Renderable *rend); - - static OgreMaterialSerializer& getSerializer(); - - private: - virtual bool isProfileSupported (const std::string& profile); - - virtual void serializeShaders (const std::string& file); - virtual void deserializeShaders (const std::string& file); - - virtual boost::shared_ptr createMaterial (const std::string& name); - - virtual boost::shared_ptr createGpuProgram ( - GpuProgramType type, - const std::string& compileArguments, - const std::string& name, const std::string& profile, - const std::string& source, Language lang); - - virtual void destroyGpuProgram (const std::string& name); - - virtual void setSharedParameter (const std::string& name, PropertyValuePtr value); - - friend class ShaderInstance; - friend class Factory; - - protected: - virtual bool supportsShaderSerialization (); - virtual bool supportsMaterialQueuedListener (); - - std::string mResourceGroup; - - static OgreMaterialSerializer* sSerializer; - - std::map mSharedParameters; - }; -} - -/** - * @} - * @} - */ - -#endif diff --git a/extern/shiny/Platforms/Ogre/OgreTextureUnitState.cpp b/extern/shiny/Platforms/Ogre/OgreTextureUnitState.cpp deleted file mode 100644 index ad8e6d2b0..000000000 --- a/extern/shiny/Platforms/Ogre/OgreTextureUnitState.cpp +++ /dev/null @@ -1,72 +0,0 @@ -#include "OgreTextureUnitState.hpp" - -#include - -#include -#include - -#include "OgrePass.hpp" -#include "OgrePlatform.hpp" -#include "OgreMaterialSerializer.hpp" - -namespace sh -{ - OgreTextureUnitState::OgreTextureUnitState (OgrePass* parent, const std::string& name) - : TextureUnitState() - { - mTextureUnitState = parent->getOgrePass()->createTextureUnitState(""); - mTextureUnitState->setName(name); - } - - bool OgreTextureUnitState::setPropertyOverride (const std::string &name, PropertyValuePtr& value, PropertySetGet* context) - { - OgreMaterialSerializer& s = OgrePlatform::getSerializer(); - - if (name == "texture_alias") - { - // texture alias in this library refers to something else than in ogre - // delegate up - return TextureUnitState::setPropertyOverride (name, value, context); - } - else if (name == "direct_texture") - { - setTextureName (retrieveValue(value, context).get()); - return true; - } - else if (name == "anim_texture2") - { - std::string val = retrieveValue(value, context).get(); - std::vector tokens; - boost::split(tokens, val, boost::is_any_of(" ")); - assert(tokens.size() == 3); - std::string texture = tokens[0]; - int frames = boost::lexical_cast(tokens[1]); - float duration = boost::lexical_cast(tokens[2]); - - std::vector frameTextures; - for (int i=0; isetAnimatedTextureName(&frameTextures[0], frames, duration); - return true; - } - else if (name == "create_in_ffp") - return true; // handled elsewhere - - return s.setTextureUnitProperty (name, retrieveValue(value, context).get(), mTextureUnitState); - } - - void OgreTextureUnitState::setTextureName (const std::string& textureName) - { - mTextureUnitState->setTextureName(textureName); - } -} diff --git a/extern/shiny/Platforms/Ogre/OgreTextureUnitState.hpp b/extern/shiny/Platforms/Ogre/OgreTextureUnitState.hpp deleted file mode 100644 index 0f1914f62..000000000 --- a/extern/shiny/Platforms/Ogre/OgreTextureUnitState.hpp +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef SH_OGRETEXTUREUNITSTATE_H -#define SH_OGRETEXTUREUNITSTATE_H - -#include - -#include "../../Main/Platform.hpp" - -namespace sh -{ - class OgrePass; - - class OgreTextureUnitState : public TextureUnitState - { - public: - OgreTextureUnitState (OgrePass* parent, const std::string& name); - - virtual void setTextureName (const std::string& textureName); - - private: - Ogre::TextureUnitState* mTextureUnitState; - - protected: - virtual bool setPropertyOverride (const std::string &name, PropertyValuePtr& value, PropertySetGet* context); - }; -} - -#endif diff --git a/extern/shiny/Readme.txt b/extern/shiny/Readme.txt deleted file mode 100644 index 613321990..000000000 --- a/extern/shiny/Readme.txt +++ /dev/null @@ -1,33 +0,0 @@ -shiny - a shader and material management library for OGRE - -FEATURES - -- High-level layer on top of OGRE's material system. It allows you to generate multiple techniques for all your materials from a set of high-level per-material properties. - -- Several available Macros in shader source files. Just a few examples of the possibilities: binding OGRE auto constants, binding uniforms to material properties, foreach loops (repeat shader source a given number of times), retrieving per-material properties in an #if condition, automatic packing for vertex to fragment passthroughs. These macros allow you to generate even very complex shaders (for example the Ogre::Terrain shader) without assembling them in C++ code. - -- Integrated preprocessor (no, I didn't reinvent the wheel, I used boost::wave which turned out to be an excellent choice) that allows me to blend out macros that shouldn't be in use because e.g. the shader permutation doesn't need this specific feature. - -- User settings integration. They can be set by a C++ interface and retrieved through a macro in shader files. - -- Automatic handling of shader permutations, i.e. shaders are shared between materials in a smart way. - -- An optional "meta-language" (well, actually it's just a small header with some conditional defines) that you may use to compile the same shader source for different target languages. If you don't like it, you can still code in GLSL / CG etc separately. You can also switch between the languages at runtime. - -- On-demand material and shader creation. It uses Ogre's material listener to compile the shaders as soon as they are needed for rendering, and not earlier. - -- Shader changes are fully dynamic and real-time. Changing a user setting will recompile all shaders affected by this setting when they are next needed. - -- Serialization system that extends Ogre's material script system, it uses Ogre's script parser, but also adds some additional properties that are not available in Ogre's material system. - -- A concept called "Configuration" allowing you to create a different set of your shaders, doing the same thing except for some minor differences: the properties that are overridden by the active configuration. Possible uses for this are using simpler shaders (no shadows, no fog etc) when rendering for example realtime reflections or a minimap. You can easily switch between configurations by changing the active Ogre material scheme (for example on a viewport level). - -- Fixed function support. You can globally enable or disable shaders at any time, and for texture units you can specify if they're only needed for the shader-based path (e.g. normal maps) or if they should also be created in the fixed function path. - -LICENSE - -see License.txt - -AUTHOR - -scrawl diff --git a/libs/openengine/CMakeLists.txt b/libs/openengine/CMakeLists.txt index 492a6323b..eaf92c673 100644 --- a/libs/openengine/CMakeLists.txt +++ b/libs/openengine/CMakeLists.txt @@ -1,7 +1,6 @@ set(OENGINE_OGRE #ogre/renderer.cpp ogre/lights.cpp - ogre/selectionbuffer.cpp ) set(OENGINE_GUI diff --git a/libs/openengine/ogre/selectionbuffer.cpp b/libs/openengine/ogre/selectionbuffer.cpp deleted file mode 100644 index 741b672ff..000000000 --- a/libs/openengine/ogre/selectionbuffer.cpp +++ /dev/null @@ -1,164 +0,0 @@ -#include "selectionbuffer.hpp" - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -#include - -namespace OEngine -{ -namespace Render -{ - - SelectionBuffer::SelectionBuffer(Ogre::Camera *camera, int sizeX, int sizeY, int visibilityFlags) - : mCamera(camera) - , mVisibilityFlags(visibilityFlags) - { - mTexture = Ogre::TextureManager::getSingleton().createManual("SelectionBuffer", - Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::TEX_TYPE_2D, sizeX, sizeY, 0, Ogre::PF_R8G8B8, Ogre::TU_RENDERTARGET, this); - - setupRenderTarget(); - - mCurrentColour = Ogre::ColourValue(0.3f, 0.3f, 0.3f); - } - - void SelectionBuffer::setupRenderTarget() - { - mRenderTarget = mTexture->getBuffer()->getRenderTarget(); - mRenderTarget->removeAllViewports(); - Ogre::Viewport* vp = mRenderTarget->addViewport(mCamera); - vp->setOverlaysEnabled(false); - vp->setBackgroundColour(Ogre::ColourValue(0, 0, 0, 0)); - vp->setShadowsEnabled(false); - vp->setMaterialScheme("selectionbuffer"); - if (mVisibilityFlags != 0) - vp->setVisibilityMask (mVisibilityFlags); - mRenderTarget->setActive(true); - mRenderTarget->setAutoUpdated (false); - } - - void SelectionBuffer::loadResource(Ogre::Resource *resource) - { - Ogre::Texture* tex = dynamic_cast(resource); - if (!tex) - return; - - tex->createInternalResources(); - - mRenderTarget = NULL; - - // Don't need to re-render texture, because we have a copy in system memory (mBuffer) - } - - SelectionBuffer::~SelectionBuffer() - { - Ogre::TextureManager::getSingleton ().remove("SelectionBuffer"); - } - - void SelectionBuffer::update () - { - Ogre::MaterialManager::getSingleton ().addListener (this); - - mTexture->load(); - if (mRenderTarget == NULL) - setupRenderTarget(); - - mRenderTarget->update(); - - Ogre::MaterialManager::getSingleton ().removeListener (this); - - mTexture->convertToImage(mBuffer); - } - - int SelectionBuffer::getSelected(int xPos, int yPos) - { - Ogre::ColourValue clr = mBuffer.getColourAt (xPos, yPos, 0); - clr.a = 1; - if (mColourMap.find(clr) != mColourMap.end()) - return mColourMap[clr]; - else - return -1; // nothing selected - } - - Ogre::Technique* SelectionBuffer::handleSchemeNotFound ( - unsigned short schemeIndex, const Ogre::String &schemeName, Ogre::Material *originalMaterial, - unsigned short lodIndex, const Ogre::Renderable *rend) - { - if (schemeName == "selectionbuffer") - { - sh::Factory::getInstance ()._ensureMaterial ("SelectionColour", "Default"); - - Ogre::MaterialPtr m = Ogre::MaterialManager::getSingleton ().getByName("SelectionColour"); - - - if(typeid(*rend) == typeid(Ogre::SubEntity)) - { - const Ogre::SubEntity *subEntity = static_cast(rend); - int id = Ogre::any_cast(subEntity->getParent ()->getUserObjectBindings().getUserAny()); - bool found = false; - Ogre::ColourValue colour; - for (std::map::iterator it = mColourMap.begin(); it != mColourMap.end(); ++it) - { - if (it->second == id) - { - found = true; - colour = it->first; - } - } - - - if (!found) - { - getNextColour(); - const_cast(subEntity)->setCustomParameter(1, Ogre::Vector4(mCurrentColour.r, mCurrentColour.g, mCurrentColour.b, 1.0)); - mColourMap[mCurrentColour] = id; - } - else - { - const_cast(subEntity)->setCustomParameter(1, Ogre::Vector4(colour.r, colour.g, colour.b, 1.0)); - } - - assert(m->getTechnique(1)); - return m->getTechnique(1); - } - else - { - m = Ogre::MaterialManager::getSingleton().getByName("NullMaterial"); - if(m.isNull()) - { - m = Ogre::MaterialManager::getSingleton().create("NullMaterial", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); - m->getTechnique(0)->getPass(0)->setDepthCheckEnabled(true); - m->getTechnique(0)->getPass(0)->setDepthFunction(Ogre::CMPF_ALWAYS_FAIL); - } - return m->getTechnique(0); - } - } - return NULL; - } - - void SelectionBuffer::getNextColour () - { - Ogre::ARGB color = static_cast(OEngine::Misc::Rng::rollClosedProbability() * std::numeric_limits::max()); - - if (mCurrentColour.getAsARGB () == color) - { - getNextColour(); - return; - } - - mCurrentColour.setAsARGB(color); - mCurrentColour.a = 1; - } - - -} -} diff --git a/libs/openengine/ogre/selectionbuffer.hpp b/libs/openengine/ogre/selectionbuffer.hpp deleted file mode 100644 index 9bdc4c137..000000000 --- a/libs/openengine/ogre/selectionbuffer.hpp +++ /dev/null @@ -1,62 +0,0 @@ -#ifndef OENGINE_SELECTIONBUFFER_H -#define OENGINE_SELECTIONBUFFER_H - - -#include -#include -#include -#include - -namespace OEngine -{ -namespace Render -{ - - struct cmp_ColourValue - { - bool operator()(const Ogre::ColourValue &a, const Ogre::ColourValue &b) const - { - return a.getAsBGRA() < b.getAsBGRA(); - } - }; - - class SelectionBuffer : public Ogre::MaterialManager::Listener, public Ogre::ManualResourceLoader - { - public: - SelectionBuffer(Ogre::Camera* camera, int sizeX, int sizeY, int visibilityFlags); - virtual ~SelectionBuffer(); - - int getSelected(int xPos, int yPos); - ///< @return ID of the selected object - - void update(); - - virtual void loadResource(Ogre::Resource* resource); - - virtual Ogre::Technique* handleSchemeNotFound ( - unsigned short schemeIndex, const Ogre::String &schemeName, Ogre::Material *originalMaterial, - unsigned short lodIndex, const Ogre::Renderable *rend); - - - private: - Ogre::TexturePtr mTexture; - Ogre::RenderTexture* mRenderTarget; - - Ogre::Image mBuffer; - - std::map mColourMap; - - Ogre::ColourValue mCurrentColour; - - Ogre::Camera* mCamera; - int mVisibilityFlags; - - void getNextColour(); - - void setupRenderTarget(); - }; - -} -} - -#endif From 7c9104a29123a428138b7315ac2db3ef43f6d1f7 Mon Sep 17 00:00:00 2001 From: Scott Howard Date: Tue, 31 Mar 2015 22:02:08 -0400 Subject: [PATCH 0873/3725] fix -Wnewline-eof --- libs/openengine/misc/rng.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/openengine/misc/rng.cpp b/libs/openengine/misc/rng.cpp index 140aa337e..3d50400df 100644 --- a/libs/openengine/misc/rng.cpp +++ b/libs/openengine/misc/rng.cpp @@ -26,4 +26,4 @@ namespace Misc { } } -} \ No newline at end of file +} From d646836cddf54624fa14ce7ace4b1b050b3f2a23 Mon Sep 17 00:00:00 2001 From: Scott Howard Date: Wed, 1 Apr 2015 21:44:41 -0400 Subject: [PATCH 0874/3725] turn on -Wno-potentially-evaluated-expression on clang --- CMakeLists.txt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 342fb7e39..07fffd577 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -353,6 +353,14 @@ endif() if (CMAKE_CXX_COMPILER_ID STREQUAL GNU OR CMAKE_CXX_COMPILER_ID STREQUAL Clang) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wno-unused-parameter -Wno-reorder -std=c++98 -pedantic -Wno-long-long") + if (CMAKE_CXX_COMPILER_ID STREQUAL Clang AND NOT APPLE) + execute_process(COMMAND ${CMAKE_C_COMPILER} --version OUTPUT_VARIABLE CLANG_VERSION) + string(REGEX REPLACE ".*version ([0-9\\.]*).*" "\\1" CLANG_VERSION ${CLANG_VERSION}) + if ("${CLANG_VERSION}" VERSION_GREATER 3.6 OR "${CLANG_VERSION}" VERSION_EQUAL 3.6) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-potentially-evaluated-expression") + endif ("${CLANG_VERSION}" VERSION_GREATER 3.6 OR "${CLANG_VERSION}" VERSION_EQUAL 3.6) + endif(CMAKE_CXX_COMPILER_ID STREQUAL Clang AND NOT APPLE) + execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION) if (CMAKE_CXX_COMPILER_ID STREQUAL GNU AND "${GCC_VERSION}" VERSION_GREATER 4.6 OR "${GCC_VERSION}" VERSION_EQUAL 4.6) From 83bcc8d4512c4571421d9602fb0e367c440dc9f1 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Thu, 2 Apr 2015 20:19:15 +1100 Subject: [PATCH 0875/3725] Reorganised class inheritance structure of collections, columns and idtable model. --- apps/opencs/CMakeLists.txt | 5 +- apps/opencs/model/world/columnbase.cpp | 45 +-- apps/opencs/model/world/columnbase.hpp | 39 +-- apps/opencs/model/world/commands.cpp | 13 +- apps/opencs/model/world/commands.hpp | 21 +- apps/opencs/model/world/data.cpp | 3 +- apps/opencs/model/world/idtable.cpp | 206 +----------- apps/opencs/model/world/idtable.hpp | 27 -- apps/opencs/model/world/idtree.cpp | 296 ++++++++++++++++++ apps/opencs/model/world/idtree.hpp | 88 ++++++ apps/opencs/model/world/nestablecolumn.cpp | 44 +++ apps/opencs/model/world/nestablecolumn.hpp | 33 ++ apps/opencs/model/world/nestedcollection.hpp | 10 + .../model/world/nestedtableproxymodel.cpp | 6 +- .../model/world/nestedtableproxymodel.hpp | 8 +- apps/opencs/model/world/refidcollection.cpp | 62 ++-- apps/opencs/model/world/refidcollection.hpp | 45 +-- apps/opencs/model/world/refiddata.hpp | 6 +- apps/opencs/view/world/dialoguesubview.cpp | 3 +- 19 files changed, 589 insertions(+), 371 deletions(-) create mode 100644 apps/opencs/model/world/idtree.cpp create mode 100644 apps/opencs/model/world/idtree.hpp create mode 100644 apps/opencs/model/world/nestablecolumn.cpp create mode 100644 apps/opencs/model/world/nestablecolumn.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 5f9559257..39b4c486b 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -18,15 +18,14 @@ opencs_hdrs_noqt (model/doc opencs_units (model/world - idtable idtableproxymodel regionmap data commanddispatcher - idtablebase resourcetable nestedtableproxymodel + idtable idtableproxymodel regionmap data commanddispatcher idtablebase resourcetable nestedtableproxymodel idtree ) opencs_units_noqt (model/world universalid record commands columnbase scriptcontext cell refidcollection refidadapter refiddata refidadapterimp ref collectionbase refcollection columns infocollection tablemimedata cellcoordinates cellselection resources resourcesmanager scope - pathgrid landtexture land nestedtablewrapper nestedadapters + pathgrid landtexture land nestedtablewrapper nestedadapters nestedcollection nestablecolumn ) opencs_hdrs_noqt (model/world diff --git a/apps/opencs/model/world/columnbase.cpp b/apps/opencs/model/world/columnbase.cpp index 60e201ba4..665ab9354 100644 --- a/apps/opencs/model/world/columnbase.cpp +++ b/apps/opencs/model/world/columnbase.cpp @@ -1,9 +1,10 @@ + #include "columnbase.hpp" #include "columns.hpp" -CSMWorld::ColumnBase::ColumnBase (int columnId, Display displayType, int flags, bool canNest) - : mColumnId (columnId), mDisplayType (displayType), mFlags (flags), mCanNest(canNest) +CSMWorld::ColumnBase::ColumnBase (int columnId, Display displayType, int flags) +: mColumnId (columnId), mDisplayType (displayType), mFlags (flags) {} CSMWorld::ColumnBase::~ColumnBase() {} @@ -22,43 +23,3 @@ int CSMWorld::ColumnBase::getId() const { return mColumnId; } - -bool CSMWorld::NestColumn::canHaveNestedColumns() const -{ - return mCanNest; -} - -void CSMWorld::NestColumn::addNestedColumn(int columnId, Display displayType) -{ - if (!mCanNest) - throw std::logic_error("Tried to nest inside of the non-nest column"); - - mNestedColumns.push_back(CSMWorld::NestedColumn(columnId, displayType, mFlags, this)); -} - -const CSMWorld::ColumnBase& CSMWorld::NestColumn::nestedColumn(int subColumn) const -{ - if (!mCanNest) - throw std::logic_error("Tried to access nested column of the non-nest column"); - - return mNestedColumns.at(subColumn); -} - -int CSMWorld::NestColumn::nestedColumnCount() const -{ - if (!mCanNest) - throw std::logic_error("Tried to access number of the subcolumns in the non-nest column"); - - return mNestedColumns.size(); -} - -CSMWorld::NestColumn::NestColumn(int columnId, Display displayType, int flags, bool canNest) - : CSMWorld::ColumnBase(columnId, displayType, flags, canNest) {} - -CSMWorld::NestedColumn::NestedColumn(int columnId, Display displayType, int flag, const CSMWorld::NestColumn* parent) - : mParent(parent), CSMWorld::ColumnBase(columnId, displayType, flag) {} - -bool CSMWorld::NestedColumn::isEditable() const -{ - return mParent->isEditable(); -} diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index 607f585b7..b717f3a52 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include @@ -117,9 +117,8 @@ namespace CSMWorld int mColumnId; int mFlags; Display mDisplayType; - bool mCanNest; - ColumnBase (int columnId, Display displayType, int flag, bool canNest = false); + ColumnBase (int columnId, Display displayType, int flag); virtual ~ColumnBase(); @@ -133,39 +132,11 @@ namespace CSMWorld virtual int getId() const; }; - class NestedColumn; - - class NestColumn : public ColumnBase - { - std::vector mNestedColumns; - - public: - NestColumn(int columnId, Display displayType, int flags, bool canNest); - - void addNestedColumn(int columnId, Display displayType); - - bool canHaveNestedColumns() const; - - const ColumnBase& nestedColumn(int subColumn) const; - - int nestedColumnCount() const; - }; - - class NestedColumn : public ColumnBase - { - const ColumnBase* mParent; - - public: - NestedColumn(int columnId, Display displayType, int flag, const NestColumn* parent); - - virtual bool isEditable() const; - }; - template - struct Column : public NestColumn + struct Column : public ColumnBase { - Column (int columnId, Display displayType, int flags = Flag_Table | Flag_Dialogue, bool canNest = false) - : NestColumn (columnId, displayType, flags, canNest) {} + Column (int columnId, Display displayType, int flags = Flag_Table | Flag_Dialogue) + : ColumnBase (columnId, displayType, flags) {} virtual QVariant get (const Record& record) const = 0; diff --git a/apps/opencs/model/world/commands.cpp b/apps/opencs/model/world/commands.cpp index 959f6b345..7acc6058e 100644 --- a/apps/opencs/model/world/commands.cpp +++ b/apps/opencs/model/world/commands.cpp @@ -3,6 +3,7 @@ #include #include "idtable.hpp" +#include "idtree.hpp" #include #include "nestedtablewrapper.hpp" @@ -172,10 +173,10 @@ void CSMWorld::CloneCommand::undo() mModel.removeRow (mModel.getModelIndex (mId, 0).row()); } -CSMWorld::DeleteNestedCommand::DeleteNestedCommand (IdTable& model, +CSMWorld::DeleteNestedCommand::DeleteNestedCommand (IdTree& model, const std::string& id, - int nestedRow, - int parentColumn, + int nestedRow, + int parentColumn, QUndoCommand* parent) : mId(id), mModel(model), @@ -192,7 +193,7 @@ void CSMWorld::DeleteNestedCommand::redo() const QModelIndex& parentIndex = mModel.getModelIndex(mId, mParentColumn); mModel.removeRows (mNestedRow, 1, parentIndex); -} +} void CSMWorld::DeleteNestedCommand::undo() @@ -202,7 +203,7 @@ void CSMWorld::DeleteNestedCommand::undo() mModel.setNestedTable(parentIndex, getOld()); } -CSMWorld::AddNestedCommand::AddNestedCommand(IdTable& model, const std::string& id, int nestedRow, int parentColumn, QUndoCommand* parent) +CSMWorld::AddNestedCommand::AddNestedCommand(IdTree& model, const std::string& id, int nestedRow, int parentColumn, QUndoCommand* parent) : mModel(model), mId(id), mNewRow(nestedRow), @@ -227,7 +228,7 @@ void CSMWorld::AddNestedCommand::undo() mModel.setNestedTable(parentIndex, getOld()); } -CSMWorld::NestedTableStoring::NestedTableStoring(const IdTable& model, const std::string& id, int parentColumn) +CSMWorld::NestedTableStoring::NestedTableStoring(const IdTree& model, const std::string& id, int parentColumn) : mOld(model.nestedTable(model.getModelIndex(id, parentColumn))) {} CSMWorld::NestedTableStoring::~NestedTableStoring() diff --git a/apps/opencs/model/world/commands.hpp b/apps/opencs/model/world/commands.hpp index c194e2779..42405a2f9 100644 --- a/apps/opencs/model/world/commands.hpp +++ b/apps/opencs/model/world/commands.hpp @@ -10,7 +10,6 @@ #include #include #include -#include #include "universalid.hpp" #include "nestedtablewrapper.hpp" @@ -21,7 +20,7 @@ class QAbstractItemModel; namespace CSMWorld { class IdTable; - class IdTable; + class IdTree; struct RecordBase; class NestedTableWrapperBase; @@ -148,18 +147,18 @@ namespace CSMWorld NestedTableWrapperBase* mOld; public: - NestedTableStoring(const IdTable& model, const std::string& id, int parentColumn); - + NestedTableStoring(const IdTree& model, const std::string& id, int parentColumn); + ~NestedTableStoring(); - + protected: const NestedTableWrapperBase& getOld() const; }; - + class DeleteNestedCommand : public QUndoCommand, private NestedTableStoring { - IdTable& mModel; + IdTree& mModel; std::string mId; @@ -169,16 +168,16 @@ namespace CSMWorld public: - DeleteNestedCommand (IdTable& model, const std::string& id, int nestedRow, int parentColumn, QUndoCommand* parent = 0); + DeleteNestedCommand (IdTree& model, const std::string& id, int nestedRow, int parentColumn, QUndoCommand* parent = 0); virtual void redo(); virtual void undo(); }; - + class AddNestedCommand : public QUndoCommand, private NestedTableStoring { - IdTable& mModel; + IdTree& mModel; std::string mId; @@ -188,7 +187,7 @@ namespace CSMWorld public: - AddNestedCommand(IdTable& model, const std::string& id, int nestedRow, int parentColumn, QUndoCommand* parent = 0); + AddNestedCommand(IdTree& model, const std::string& id, int nestedRow, int parentColumn, QUndoCommand* parent = 0); virtual void redo(); diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 39cff3db6..a5ef439a7 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -12,6 +12,7 @@ #include #include "idtable.hpp" +#include "idtree.hpp" #include "columnimp.hpp" #include "regionmap.hpp" #include "columns.hpp" @@ -332,7 +333,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc addModel (new IdTable (&mMagicEffects), UniversalId::Type_MagicEffect); addModel (new IdTable (&mPathgrids), UniversalId::Type_Pathgrid); addModel (new IdTable (&mStartScripts), UniversalId::Type_StartScript); - addModel (new IdTable (&mReferenceables, IdTable::Feature_Preview), + addModel (new IdTree (&mReferenceables, IdTable::Feature_Preview), UniversalId::Type_Referenceable); addModel (new IdTable (&mRefs, IdTable::Feature_ViewCell | IdTable::Feature_Preview), UniversalId::Type_Reference); addModel (new IdTable (&mFilters), UniversalId::Type_Filter); diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 1c21e64c3..7618a073a 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -1,12 +1,6 @@ #include "idtable.hpp" -#include - -#include -#include -#include "nestedtablewrapper.hpp" #include "collectionbase.hpp" -#include "nestedcollection.hpp" #include "columnbase.hpp" CSMWorld::IdTable::IdTable (CollectionBase *idCollection, unsigned int features) @@ -14,26 +8,20 @@ CSMWorld::IdTable::IdTable (CollectionBase *idCollection, unsigned int features) {} CSMWorld::IdTable::~IdTable() -{ - mIdCollection = 0; // FIXME: workaround only, should stop QHideEvent calling after destruction -} +{} int CSMWorld::IdTable::rowCount (const QModelIndex & parent) const { - if (hasChildren(parent)) - { - return dynamic_cast(mIdCollection)->getNestedRowsCount(parent.row(), parent.column()); - } + if (parent.isValid()) + return 0; return mIdCollection->getSize(); } int CSMWorld::IdTable::columnCount (const QModelIndex & parent) const { - if (hasChildren(parent)) - { - return dynamic_cast(mIdCollection)->getNestedColumnsCount(parent.row(), parent.column()); - } + if (parent.isValid()) + return 0; return mIdCollection->getColumns(); } @@ -46,23 +34,10 @@ QVariant CSMWorld::IdTable::data (const QModelIndex & index, int role) const if (role==Qt::EditRole && !mIdCollection->getColumn (index.column()).isEditable()) return QVariant(); - if (index.internalId() != 0) - { - std::pair parentAdress(unfoldIndexAdress(index.internalId())); - return dynamic_cast(mIdCollection)->getNestedData(parentAdress.first, - parentAdress.second, - index.row(), - index.column()); - } - else - { - return mIdCollection->getData (index.row(), index.column()); - } + return mIdCollection->getData (index.row(), index.column()); } -QVariant CSMWorld::IdTable::headerData (int section, - Qt::Orientation orientation, - int role) const +QVariant CSMWorld::IdTable::headerData (int section, Qt::Orientation orientation, int role) const { if (orientation==Qt::Vertical) return QVariant(); @@ -74,63 +49,19 @@ QVariant CSMWorld::IdTable::headerData (int section, return mIdCollection->getColumn (section).mFlags; if (role==ColumnBase::Role_Display) - { return mIdCollection->getColumn (section).mDisplayType; - } - - return QVariant(); -} - -QVariant CSMWorld::IdTable::nestedHeaderData(int section, int subSection, Qt::Orientation orientation, int role) const -{ - // FIXME: workaround only, should stop QHideEvent calling after destruction - if (section < 0 || !mIdCollection || section >= mIdCollection->getColumns()) - return QVariant(); - - const NestColumn& parentColumn = dynamic_cast(mIdCollection->getColumn(section)); - - if (orientation==Qt::Vertical) - return QVariant(); - - if (role==Qt::DisplayRole) - return tr(parentColumn.nestedColumn(subSection).getTitle().c_str()); - - if (role==ColumnBase::Role_Flags) - return mIdCollection->getColumn (section).mFlags; - - if (role==ColumnBase::Role_Display) - return parentColumn.nestedColumn(subSection).mDisplayType; return QVariant(); } bool CSMWorld::IdTable::setData (const QModelIndex &index, const QVariant &value, int role) { - if (index.internalId() != 0) - { - if (mIdCollection->getColumn(parent(index).column()).isEditable() && role==Qt::EditRole) - { - const std::pair& parentAdress(unfoldIndexAdress(index.internalId())); - - dynamic_cast(mIdCollection)->setNestedData(parentAdress.first, parentAdress.second, value, index.row(), index.column()); - - emit dataChanged (CSMWorld::IdTable::index (parentAdress.first, 0), - CSMWorld::IdTable::index (parentAdress.second, mIdCollection->getColumns()-1)); - - return true; - } - else - { - return false; - } - } - if (mIdCollection->getColumn (index.column()).isEditable() && role==Qt::EditRole) { mIdCollection->setData (index.row(), index.column(), value); emit dataChanged (CSMWorld::IdTable::index (index.row(), 0), - CSMWorld::IdTable::index (index.row(), mIdCollection->getColumns()-1)); + CSMWorld::IdTable::index (index.row(), mIdCollection->getColumns()-1)); return true; } @@ -150,56 +81,22 @@ Qt::ItemFlags CSMWorld::IdTable::flags (const QModelIndex & index) const bool CSMWorld::IdTable::removeRows (int row, int count, const QModelIndex& parent) { - beginRemoveRows (parent, row, row+count-1); - if (parent.isValid()) - { - for (int i = 0; i < count; ++i) - { - dynamic_cast(mIdCollection)->removeNestedRows(parent.row(), parent.column(), row+i); - } - } - else - { + return false; - beginRemoveRows (parent, row, row+count-1); + beginRemoveRows (parent, row, row+count-1); - mIdCollection->removeRows (row, count); - } + mIdCollection->removeRows (row, count); endRemoveRows(); - emit dataChanged (CSMWorld::IdTable::index (parent.row(), 0), - CSMWorld::IdTable::index (parent.row(), mIdCollection->getColumns()-1)); - return true; } -void CSMWorld::IdTable::addNestedRow(const QModelIndex& parent, int position) -{ - if (!hasChildren(parent)) - { - throw std::logic_error("Tried to set nested table, but index has no children"); - } - - int row = parent.row(); - - beginInsertRows(parent, position, position); - dynamic_cast(mIdCollection)->addNestedRow(row, parent.column(), position); - - endInsertRows(); - - emit dataChanged (CSMWorld::IdTable::index (row, 0), - CSMWorld::IdTable::index (row, mIdCollection->getColumns()-1)); -} - QModelIndex CSMWorld::IdTable::index (int row, int column, const QModelIndex& parent) const { - unsigned int encodedId = 0; if (parent.isValid()) - { - encodedId = this->foldIndexAdress(parent); - } + return QModelIndex(); if (row<0 || row>=mIdCollection->getSize()) return QModelIndex(); @@ -207,24 +104,12 @@ QModelIndex CSMWorld::IdTable::index (int row, int column, const QModelIndex& pa if (column<0 || column>=mIdCollection->getColumns()) return QModelIndex(); - return createIndex(row, column, encodedId); + return createIndex (row, column); } QModelIndex CSMWorld::IdTable::parent (const QModelIndex& index) const { - if (index.internalId() == 0) //0 is used for indexs with invalid parent (top level data) - { - return QModelIndex(); - } - - unsigned int id = index.internalId(); - const std::pair& adress(unfoldIndexAdress(id)); - - if (adress.first >= this->rowCount() || adress.second >= this->columnCount()) - { - throw "Parent index is not present in the model"; - } - return createIndex(adress.first, adress.second); + return QModelIndex(); } void CSMWorld::IdTable::addRecord (const std::string& id, UniversalId::Type type) @@ -346,66 +231,3 @@ int CSMWorld::IdTable::getColumnId(int column) const { return mIdCollection->getColumn(column).getId(); } - -unsigned int CSMWorld::IdTable::foldIndexAdress (const QModelIndex& index) const -{ - unsigned int out = index.row() * this->columnCount(); - out += index.column(); - return ++out; -} - -std::pair< int, int > CSMWorld::IdTable::unfoldIndexAdress (unsigned int id) const -{ - if (id == 0) - { - throw "Attempt to unfold index id of the top level data cell"; - } - - --id; - int row = id / this->columnCount(); - int column = id - row * this->columnCount(); - return std::make_pair (row, column); -} - -bool CSMWorld::IdTable::hasChildren(const QModelIndex& index) const -{ - return (index.isValid() && - index.internalId() == 0 && - mIdCollection->getColumn(index.column()).mCanNest && - index.data().isValid()); -} - -void CSMWorld::IdTable::setNestedTable(const QModelIndex& index, const CSMWorld::NestedTableWrapperBase& nestedTable) -{ - if (!hasChildren(index)) - { - throw std::logic_error("Tried to set nested table, but index has no children"); - } - - bool removeRowsMode = false; - if (nestedTable.size() != this->nestedTable(index)->size()) - { - emit resetStart(this->index(index.row(), 0).data().toString()); - removeRowsMode = true; - } - - dynamic_cast(mIdCollection)->setNestedTable(index.row(), index.column(), nestedTable); - - emit dataChanged (CSMWorld::IdTable::index (index.row(), 0), - CSMWorld::IdTable::index (index.row(), mIdCollection->getColumns()-1)); - - if (removeRowsMode) - { - emit resetEnd(this->index(index.row(), 0).data().toString()); - } -} - -CSMWorld::NestedTableWrapperBase* CSMWorld::IdTable::nestedTable(const QModelIndex& index) const -{ - if (!hasChildren(index)) - { - throw std::logic_error("Tried to retrive nested table, but index has no children"); - } - - return dynamic_cast(mIdCollection)->nestedTable(index.row(), index.column()); -} diff --git a/apps/opencs/model/world/idtable.hpp b/apps/opencs/model/world/idtable.hpp index 05c523ccb..ea8ab80f9 100644 --- a/apps/opencs/model/world/idtable.hpp +++ b/apps/opencs/model/world/idtable.hpp @@ -7,20 +7,10 @@ #include "universalid.hpp" #include "columns.hpp" -/*! \brief - * Clas for holding the model. Uses typical qt table abstraction/interface for granting access to the individiual fields of the records, - * Some records are holding nested data (for instance inventory list of the npc). In casses like this, table model offers interface - * to access nested data in the qt way that is specify parent. Since some of those nested data require multiple columns to - * represent informations, single int (default way to index model in the qmodelindex) is not sufficiant. Therefore tablemodelindex class - * can hold two ints for the sake of indexing two dimensions of the table. This model does not support multiple levels of the nested - * data. Vast majority of methods makes sense only for the top level data. - */ - namespace CSMWorld { class CollectionBase; struct RecordBase; - class NestedTableWrapperBase; class IdTable : public IdTableBase { @@ -33,8 +23,6 @@ namespace CSMWorld // not implemented IdTable (const IdTable&); IdTable& operator= (const IdTable&); - unsigned int foldIndexAdress(const QModelIndex& index) const; - std::pair unfoldIndexAdress(unsigned int id) const; public: @@ -51,27 +39,17 @@ namespace CSMWorld virtual QVariant headerData (int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; - QVariant nestedHeaderData(int section, int subSection, Qt::Orientation orientation, int role = Qt::DisplayRole) const; - - NestedTableWrapperBase* nestedTable(const QModelIndex &index) const; - - void setNestedTable(const QModelIndex &index, const NestedTableWrapperBase& nestedTable); - virtual bool setData ( const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); virtual Qt::ItemFlags flags (const QModelIndex & index) const; virtual bool removeRows (int row, int count, const QModelIndex& parent = QModelIndex()); - void addNestedRow (const QModelIndex& parent, int position); - virtual QModelIndex index (int row, int column, const QModelIndex& parent = QModelIndex()) const; virtual QModelIndex parent (const QModelIndex& index) const; - virtual bool hasChildren (const QModelIndex& index) const; - void addRecord (const std::string& id, UniversalId::Type type = UniversalId::Type_None); ///< \param type Will be ignored, unless the collection supports multiple record types @@ -105,11 +83,6 @@ namespace CSMWorld virtual bool isDeleted (const std::string& id) const; int getColumnId(int column) const; - - signals: - void resetStart(const QString& id); - - void resetEnd(const QString& id); }; } diff --git a/apps/opencs/model/world/idtree.cpp b/apps/opencs/model/world/idtree.cpp new file mode 100644 index 000000000..595b0ac51 --- /dev/null +++ b/apps/opencs/model/world/idtree.cpp @@ -0,0 +1,296 @@ +#include "idtree.hpp" + +#include "nestedtablewrapper.hpp" // FIXME: is this necessary? + +#include "nestedcollection.hpp" +#include "nestablecolumn.hpp" + +CSMWorld::IdTree::IdTree (NestedCollection *idCollection, unsigned int features) +: IdTable (idCollection, features), mIdCollection (idCollection) +{} + +CSMWorld::IdTree::~IdTree() +{ + // FIXME: workaround only, a proper fix should stop QHideEvent calls after destruction + mIdCollection = 0; +} + +int CSMWorld::IdTree::rowCount (const QModelIndex & parent) const +{ + if (hasChildren(parent)) + return mIdCollection->getNestedRowsCount(parent.row(), parent.column()); + + return mIdCollection->getSize(); +} + +int CSMWorld::IdTree::columnCount (const QModelIndex & parent) const +{ + if (hasChildren(parent)) + return mIdCollection->getNestedColumnsCount(parent.row(), parent.column()); + + return mIdCollection->getColumns(); +} + +QVariant CSMWorld::IdTree::data (const QModelIndex & index, int role) const +{ + if (!index.isValid()) + return QVariant(); + + if ((role!=Qt::DisplayRole && role!=Qt::EditRole) || index.row() < 0 || index.column() < 0) + return QVariant(); + + if (role==Qt::EditRole && !mIdCollection->getColumn (index.column()).isEditable()) + return QVariant(); + + if (index.internalId() != 0) + { + std::pair parentAdress(unfoldIndexAdress(index.internalId())); + + return mIdCollection->getNestedData(parentAdress.first, + parentAdress.second, index.row(), index.column()); + } + else + return mIdCollection->getData (index.row(), index.column()); +} + +QVariant CSMWorld::IdTree::headerData (int section, Qt::Orientation orientation, int role) const +{ + if (orientation==Qt::Vertical) + return QVariant(); + + if (orientation != Qt::Horizontal) + throw std::logic_error("Unknown header orientation specified"); + + if (role == Qt::DisplayRole) + return tr (mIdCollection->getColumn (section).getTitle().c_str()); + + if (role == ColumnBase::Role_Flags) + return mIdCollection->getColumn (section).mFlags; + + if (role == ColumnBase::Role_Display) + return mIdCollection->getColumn (section).mDisplayType; + + return QVariant(); +} + +QVariant CSMWorld::IdTree::nestedHeaderData(int section, int subSection, Qt::Orientation orientation, int role) const +{ + // FIXME: workaround only, a proper fix should stop QHideEvent calls after destruction + if (section < 0 || !mIdCollection || section >= mIdCollection->getColumns()) + return QVariant(); + + // FIXME: dynamic cast + const NestableColumn& parentColumn = dynamic_cast(mIdCollection->getColumn(section)); + + if (orientation==Qt::Vertical) + return QVariant(); + + if (role==Qt::DisplayRole) + return tr(parentColumn.nestedColumn(subSection).getTitle().c_str()); + + if (role==ColumnBase::Role_Flags) + return mIdCollection->getColumn (section).mFlags; + + if (role==ColumnBase::Role_Display) + return parentColumn.nestedColumn(subSection).mDisplayType; + + return QVariant(); +} + +bool CSMWorld::IdTree::setData (const QModelIndex &index, const QVariant &value, int role) +{ + if (index.internalId() != 0) + { + if (mIdCollection->getColumn(parent(index).column()).isEditable() && role==Qt::EditRole) + { + const std::pair& parentAdress(unfoldIndexAdress(index.internalId())); + + mIdCollection->setNestedData(parentAdress.first, parentAdress.second, value, index.row(), index.column()); + + emit dataChanged (CSMWorld::IdTree::index (parentAdress.first, 0), + CSMWorld::IdTree::index (parentAdress.second, mIdCollection->getColumns()-1)); + + return true; + } + else + return false; + } + + if (mIdCollection->getColumn (index.column()).isEditable() && role==Qt::EditRole) + { + mIdCollection->setData (index.row(), index.column(), value); + + emit dataChanged (CSMWorld::IdTree::index (index.row(), 0), + CSMWorld::IdTree::index (index.row(), mIdCollection->getColumns()-1)); + + return true; + } + + return false; +} + +Qt::ItemFlags CSMWorld::IdTree::flags (const QModelIndex & index) const +{ + if (!index.isValid()) + return 0; + + Qt::ItemFlags flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled; + + if (mIdCollection->getColumn (index.column()).isUserEditable()) + flags |= Qt::ItemIsEditable; + + return flags; +} + +bool CSMWorld::IdTree::removeRows (int row, int count, const QModelIndex& parent) +{ + beginRemoveRows (parent, row, row+count-1); + + if (parent.isValid()) + { + for (int i = 0; i < count; ++i) + { + mIdCollection->removeNestedRows(parent.row(), parent.column(), row+i); + } + } + else + { + + beginRemoveRows (parent, row, row+count-1); + + mIdCollection->removeRows (row, count); + } + + endRemoveRows(); + + emit dataChanged (CSMWorld::IdTree::index (parent.row(), 0), + CSMWorld::IdTree::index (parent.row(), mIdCollection->getColumns()-1)); + + return true; +} + +void CSMWorld::IdTree::addNestedRow(const QModelIndex& parent, int position) +{ + if (!hasChildren(parent)) + throw std::logic_error("Tried to set nested table, but index has no children"); + + int row = parent.row(); + + beginInsertRows(parent, position, position); + mIdCollection->addNestedRow(row, parent.column(), position); + endInsertRows(); + + emit dataChanged (CSMWorld::IdTree::index (row, 0), + CSMWorld::IdTree::index (row, mIdCollection->getColumns()-1)); +} + +QModelIndex CSMWorld::IdTree::index (int row, int column, const QModelIndex& parent) const +{ + unsigned int encodedId = 0; + if (parent.isValid()) + { + encodedId = this->foldIndexAdress(parent); + } + + if (row<0 || row>=mIdCollection->getSize()) + return QModelIndex(); + + if (column<0 || column>=mIdCollection->getColumns()) + return QModelIndex(); + + return createIndex(row, column, encodedId); // store internal id +} + +QModelIndex CSMWorld::IdTree::parent (const QModelIndex& index) const +{ + if (index.internalId() == 0) // 0 is used for indexs with invalid parent (top level data) + return QModelIndex(); + + unsigned int id = index.internalId(); + const std::pair& adress(unfoldIndexAdress(id)); + + if (adress.first >= this->rowCount() || adress.second >= this->columnCount()) + throw "Parent index is not present in the model"; + + return createIndex(adress.first, adress.second); +} + +void CSMWorld::IdTree::setRecord (const std::string& id, const RecordBase& record) +{ + int index = mIdCollection->searchId (id); + + if (index==-1) + { + int index = mIdCollection->getAppendIndex (id); + + beginInsertRows (QModelIndex(), index, index); + + mIdCollection->appendRecord (record); + + endInsertRows(); + } + else + { + mIdCollection->replace (index, record); + emit dataChanged (CSMWorld::IdTree::index (index, 0), + CSMWorld::IdTree::index (index, mIdCollection->getColumns()-1)); + } +} + +unsigned int CSMWorld::IdTree::foldIndexAdress (const QModelIndex& index) const +{ + unsigned int out = index.row() * this->columnCount(); + out += index.column(); + return ++out; +} + +std::pair< int, int > CSMWorld::IdTree::unfoldIndexAdress (unsigned int id) const +{ + if (id == 0) + throw "Attempt to unfold index id of the top level data cell"; + + --id; + int row = id / this->columnCount(); + int column = id - row * this->columnCount(); + return std::make_pair (row, column); +} + +bool CSMWorld::IdTree::hasChildren(const QModelIndex& index) const +{ + // FIXME: dynamic cast + return (index.isValid() && + index.internalId() == 0 && + dynamic_cast(mIdCollection->getColumn(index.column())).hasChildren() && + index.data().isValid()); +} + +void CSMWorld::IdTree::setNestedTable(const QModelIndex& index, const CSMWorld::NestedTableWrapperBase& nestedTable) +{ + if (!hasChildren(index)) + throw std::logic_error("Tried to set nested table, but index has no children"); + + bool removeRowsMode = false; + if (nestedTable.size() != this->nestedTable(index)->size()) + { + emit resetStart(this->index(index.row(), 0).data().toString()); + removeRowsMode = true; + } + + mIdCollection->setNestedTable(index.row(), index.column(), nestedTable); + + emit dataChanged (CSMWorld::IdTree::index (index.row(), 0), + CSMWorld::IdTree::index (index.row(), mIdCollection->getColumns()-1)); + + if (removeRowsMode) + { + emit resetEnd(this->index(index.row(), 0).data().toString()); + } +} + +CSMWorld::NestedTableWrapperBase* CSMWorld::IdTree::nestedTable(const QModelIndex& index) const +{ + if (!hasChildren(index)) + throw std::logic_error("Tried to retrive nested table, but index has no children"); + + return mIdCollection->nestedTable(index.row(), index.column()); +} diff --git a/apps/opencs/model/world/idtree.hpp b/apps/opencs/model/world/idtree.hpp new file mode 100644 index 000000000..6a3d7423c --- /dev/null +++ b/apps/opencs/model/world/idtree.hpp @@ -0,0 +1,88 @@ +#ifndef CSM_WOLRD_IDTREE_H +#define CSM_WOLRD_IDTREE_H + +#include "idtable.hpp" +#include "universalid.hpp" +#include "columns.hpp" + +/*! \brief + * Class for holding the model. Uses typical qt table abstraction/interface for granting access + * to the individiual fields of the records, Some records are holding nested data (for instance + * inventory list of the npc). In casses like this, table model offers interface to access + * nested data in the qt way - that is specify parent. Since some of those nested data require + * multiple columns to represent informations, single int (default way to index model in the + * qmodelindex) is not sufficiant. Therefore tablemodelindex class can hold two ints for the + * sake of indexing two dimensions of the table. This model does not support multiple levels of + * the nested data. Vast majority of methods makes sense only for the top level data. + */ + +namespace CSMWorld +{ + class NestedCollection; + struct RecordBase; + class NestedTableWrapperBase; // FIXME: is this necessary? + + class IdTree : public IdTable // IdTable is derived from QAbstractItemModel + { + Q_OBJECT + + private: + + NestedCollection *mIdCollection; + + // not implemented + IdTree (const IdTree&); + IdTree& operator= (const IdTree&); + + unsigned int foldIndexAdress(const QModelIndex& index) const; + std::pair unfoldIndexAdress(unsigned int id) const; + + public: + + IdTree (NestedCollection *idCollection, unsigned int features = 0); + ///< The ownership of \a idCollection is not transferred. + + virtual ~IdTree(); + + virtual int rowCount (const QModelIndex & parent = QModelIndex()) const; + + virtual int columnCount (const QModelIndex & parent = QModelIndex()) const; + + virtual QVariant data (const QModelIndex & index, int role = Qt::DisplayRole) const; + + virtual QVariant headerData (int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; + + virtual bool setData ( const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); + + virtual Qt::ItemFlags flags (const QModelIndex & index) const; + + virtual bool removeRows (int row, int count, const QModelIndex& parent = QModelIndex()); + + virtual QModelIndex index (int row, int column, const QModelIndex& parent = QModelIndex()) + const; + + virtual QModelIndex parent (const QModelIndex& index) const; + + void setRecord (const std::string& id, const RecordBase& record); + ///< Add record or overwrite existing recrod. + + // TODO: check if below methods are really needed + QVariant nestedHeaderData(int section, int subSection, Qt::Orientation orientation, int role = Qt::DisplayRole) const; + + NestedTableWrapperBase* nestedTable(const QModelIndex &index) const; + + void setNestedTable(const QModelIndex &index, const NestedTableWrapperBase& nestedTable); + + void addNestedRow (const QModelIndex& parent, int position); + + virtual bool hasChildren (const QModelIndex& index) const; + + signals: + + void resetStart(const QString& id); + + void resetEnd(const QString& id); + }; +} + +#endif diff --git a/apps/opencs/model/world/nestablecolumn.cpp b/apps/opencs/model/world/nestablecolumn.cpp new file mode 100644 index 000000000..4ade75b33 --- /dev/null +++ b/apps/opencs/model/world/nestablecolumn.cpp @@ -0,0 +1,44 @@ +#include "nestablecolumn.hpp" + +#include + +void CSMWorld::NestableColumn::addColumn(CSMWorld::NestableColumn *column) +{ + mNestedColumns.push_back(column); + mHasChildren = true; +} + +const CSMWorld::ColumnBase& CSMWorld::NestableColumn::nestedColumn(int subColumn) const +{ + if (!mHasChildren) + throw std::logic_error("Tried to access nested column of the non-nest column"); + + return *mNestedColumns.at(subColumn); +} + +int CSMWorld::NestableColumn::nestedColumnCount() const +{ + if (!mHasChildren) + throw std::logic_error("Tried to access number of the subcolumns in the non-nest column"); + + return mNestedColumns.size(); +} + +CSMWorld::NestableColumn::NestableColumn(int columnId, CSMWorld::ColumnBase::Display displayType, + int flag, const CSMWorld::NestableColumn* parent) + : mParent(parent), mHasChildren(false), CSMWorld::ColumnBase(columnId, displayType, flag) +{ +} + +CSMWorld::NestableColumn::~NestableColumn() +{ + for (unsigned int i = 0; i < mNestedColumns.size(); ++i) + { + delete mNestedColumns[i]; + } +} + +bool CSMWorld::NestableColumn::hasChildren() const +{ + return mHasChildren; +} diff --git a/apps/opencs/model/world/nestablecolumn.hpp b/apps/opencs/model/world/nestablecolumn.hpp new file mode 100644 index 000000000..28ced85e9 --- /dev/null +++ b/apps/opencs/model/world/nestablecolumn.hpp @@ -0,0 +1,33 @@ +#ifndef CSM_WOLRD_NESTABLECOLUMN_H +#define CSM_WOLRD_NESTABLECOLUMN_H + +#include + +#include "columnbase.hpp" + +namespace CSMWorld +{ + class NestableColumn : public ColumnBase + { + std::vector mNestedColumns; + const NestableColumn* mParent; + bool mHasChildren; // cached + + public: + + NestableColumn(int columnId, + Display displayType, int flag, const NestableColumn* parent = 0); + + ~NestableColumn(); + + void addColumn(CSMWorld::NestableColumn *column); + + const ColumnBase& nestedColumn(int subColumn) const; + + int nestedColumnCount() const; + + bool hasChildren() const; + }; +} + +#endif diff --git a/apps/opencs/model/world/nestedcollection.hpp b/apps/opencs/model/world/nestedcollection.hpp index dffa29573..5ec50b423 100644 --- a/apps/opencs/model/world/nestedcollection.hpp +++ b/apps/opencs/model/world/nestedcollection.hpp @@ -1,6 +1,8 @@ #ifndef CSM_WOLRD_NESTEDCOLLECTION_H #define CSM_WOLRD_NESTEDCOLLECTION_H +#include + #include "collectionbase.hpp" class QVariant; @@ -11,7 +13,12 @@ namespace CSMWorld class NestedCollection : public CollectionBase { + public: + + NestedCollection(); + virtual ~NestedCollection(); + virtual void addNestedRow(int row, int col, int position) = 0; virtual QVariant getNestedData(int row, int column, int subRow, int subColumn) const = 0; @@ -28,7 +35,10 @@ namespace CSMWorld virtual void removeNestedRows(int row, int column, int subRow) = 0; + private: + std::vector mChildren; + NestedCollection *mParent; // currently unused }; } diff --git a/apps/opencs/model/world/nestedtableproxymodel.cpp b/apps/opencs/model/world/nestedtableproxymodel.cpp index c098e0316..fede8383b 100644 --- a/apps/opencs/model/world/nestedtableproxymodel.cpp +++ b/apps/opencs/model/world/nestedtableproxymodel.cpp @@ -1,11 +1,11 @@ #include "nestedtableproxymodel.hpp" #include -#include "idtable.hpp" +#include "idtree.hpp" CSMWorld::NestedTableProxyModel::NestedTableProxyModel(const QModelIndex& parent, ColumnBase::Display columnId, - CSMWorld::IdTable* parentModel) + CSMWorld::IdTree* parentModel) : mParentColumn(parent.column()), mMainModel(parentModel) { @@ -119,7 +119,7 @@ int CSMWorld::NestedTableProxyModel::getParentColumn() const return mParentColumn; } -CSMWorld::IdTable* CSMWorld::NestedTableProxyModel::model() const +CSMWorld::IdTree* CSMWorld::NestedTableProxyModel::model() const { return mMainModel; } diff --git a/apps/opencs/model/world/nestedtableproxymodel.hpp b/apps/opencs/model/world/nestedtableproxymodel.hpp index 7ad8fc0c2..7dc66989c 100644 --- a/apps/opencs/model/world/nestedtableproxymodel.hpp +++ b/apps/opencs/model/world/nestedtableproxymodel.hpp @@ -17,27 +17,27 @@ namespace CSMWorld { class CollectionBase; class RecordBase; - class IdTable; + class IdTree; class NestedTableProxyModel : public QAbstractProxyModel { Q_OBJECT const int mParentColumn; - IdTable* mMainModel; + IdTree* mMainModel; std::string mId; public: NestedTableProxyModel(const QModelIndex& parent, ColumnBase::Display displayType, - IdTable* parentModel); + IdTree* parentModel); //parent is the parent of columns to work with. Columnid provides information about the column std::string getParentId() const; int getParentColumn() const; - CSMWorld::IdTable* model() const; + CSMWorld::IdTree* model() const; virtual QModelIndex mapFromSource(const QModelIndex& sourceIndex) const; diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index c48896435..ca5efcdd9 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -2,18 +2,17 @@ #include #include -#include #include #include "refidadapter.hpp" #include "refidadapterimp.hpp" #include "columns.hpp" -#include "nestedtablewrapper.hpp" +#include "nestedtablewrapper.hpp" // FIXME: is this really necessary? CSMWorld::RefIdColumn::RefIdColumn (int columnId, Display displayType, int flag, - bool editable, bool userEditable, bool canNest) - : NestColumn (columnId, displayType, flag, canNest), mEditable (editable), mUserEditable (userEditable) + bool editable, bool userEditable) + : NestableColumn (columnId, displayType, flag), mEditable (editable), mUserEditable (userEditable) {} bool CSMWorld::RefIdColumn::isEditable() const @@ -27,7 +26,8 @@ bool CSMWorld::RefIdColumn::isUserEditable() const } -CSMWorld::RefIdAdapter& CSMWorld::RefIdCollection::findAdapter (UniversalId::Type type) const +// FIXME: const problem +/*const*/ CSMWorld::RefIdAdapter& CSMWorld::RefIdCollection::findAdapter (UniversalId::Type type) const { std::map::const_iterator iter = mAdapters.find (type); @@ -99,14 +99,19 @@ CSMWorld::RefIdCollection::RefIdCollection() mColumns.push_back (RefIdColumn (Columns::ColumnId_AiAlarm, ColumnBase::Display_Integer)); actorsColumns.mAlarm = &mColumns.back(); - mColumns.push_back(RefIdColumn (Columns::ColumnId_ActorInventory, ColumnBase::Display_NestedItemList, ColumnBase::Flag_Dialogue, true, true, true)); + // Nested table + mColumns.push_back(RefIdColumn (Columns::ColumnId_ActorInventory, ColumnBase::Display_NestedItemList, ColumnBase::Flag_Dialogue)); actorsColumns.mInventory = &mColumns.back(); - mColumns.back().addNestedColumn(Columns::ColumnId_InventoryItemId, CSMWorld::ColumnBase::Display_String); - mColumns.back().addNestedColumn(Columns::ColumnId_ItemCount, CSMWorld::ColumnBase::Display_Integer); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_InventoryItemId, CSMWorld::ColumnBase::Display_String)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_ItemCount, CSMWorld::ColumnBase::Display_Integer)); - mColumns.push_back(RefIdColumn (Columns::ColumnId_ActorSpells, ColumnBase::Display_NestedSpellList, ColumnBase::Flag_Dialogue, true, true, true)); + // Nested table + mColumns.push_back(RefIdColumn (Columns::ColumnId_ActorSpells, ColumnBase::Display_NestedSpellList, ColumnBase::Flag_Dialogue)); actorsColumns.mSpells = &mColumns.back(); - mColumns.back().addNestedColumn(Columns::ColumnId_SpellId, CSMWorld::ColumnBase::Display_String); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_SpellId, CSMWorld::ColumnBase::Display_String)); static const struct { @@ -175,10 +180,13 @@ CSMWorld::RefIdCollection::RefIdCollection() mColumns.push_back (RefIdColumn (Columns::ColumnId_Respawn, ColumnBase::Display_Boolean)); const RefIdColumn *respawn = &mColumns.back(); - mColumns.push_back(RefIdColumn (Columns::ColumnId_ContainerContent, ColumnBase::Display_NestedItemList, ColumnBase::Flag_Dialogue, true, true, true)); + // Nested table + mColumns.push_back(RefIdColumn (Columns::ColumnId_ContainerContent, ColumnBase::Display_NestedItemList, ColumnBase::Flag_Dialogue)); const RefIdColumn *content = &mColumns.back(); - mColumns.back().addNestedColumn(Columns::ColumnId_InventoryItemId, CSMWorld::ColumnBase::Display_String); - mColumns.back().addNestedColumn(Columns::ColumnId_ItemCount, CSMWorld::ColumnBase::Display_Integer); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_InventoryItemId, CSMWorld::ColumnBase::Display_String)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_ItemCount, CSMWorld::ColumnBase::Display_Integer)); CreatureColumns creatureColumns (actorsColumns); @@ -315,16 +323,24 @@ CSMWorld::RefIdCollection::RefIdCollection() npcColumns.mFlags.insert (std::make_pair (metalBlood, ESM::NPC::Metal)); - mColumns.push_back(RefIdColumn (Columns::ColumnId_NpcDestinations, ColumnBase::Display_NestedDestinationsList, ColumnBase::Flag_Dialogue, true, true, true)); + // Nested table + mColumns.push_back(RefIdColumn (Columns::ColumnId_NpcDestinations, ColumnBase::Display_NestedDestinationsList, ColumnBase::Flag_Dialogue)); npcColumns.mDestinations = &mColumns.back(); - mColumns.back().addNestedColumn(Columns::ColumnId_DestinationCell, CSMWorld::ColumnBase::Display_String); - mColumns.back().addNestedColumn(Columns::ColumnId_PosX, CSMWorld::ColumnBase::Display_Float); - mColumns.back().addNestedColumn(Columns::ColumnId_PosY, CSMWorld::ColumnBase::Display_Float); - mColumns.back().addNestedColumn(Columns::ColumnId_PosZ, CSMWorld::ColumnBase::Display_Float); - mColumns.back().addNestedColumn(Columns::ColumnId_RotX, CSMWorld::ColumnBase::Display_Float); - mColumns.back().addNestedColumn(Columns::ColumnId_RotY, CSMWorld::ColumnBase::Display_Float); - mColumns.back().addNestedColumn(Columns::ColumnId_RotZ, CSMWorld::ColumnBase::Display_Float); - + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_DestinationCell, CSMWorld::ColumnBase::Display_String)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_PosX, CSMWorld::ColumnBase::Display_Float)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_PosY, CSMWorld::ColumnBase::Display_Float)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_PosZ, CSMWorld::ColumnBase::Display_Float)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_RotX, CSMWorld::ColumnBase::Display_Float)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_RotY, CSMWorld::ColumnBase::Display_Float)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_RotZ, CSMWorld::ColumnBase::Display_Float)); + WeaponColumns weaponColumns (enchantableColumns); mColumns.push_back (RefIdColumn (Columns::ColumnId_WeaponType, ColumnBase::Display_WeaponType)); @@ -664,8 +680,10 @@ void CSMWorld::RefIdCollection::setNestedTable(int row, int column, const CSMWor { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); + // FIXME: const problem CSMWorld::NestedRefIdAdapter& adaptor = dynamic_cast(findAdapter (localIndex.second)); + // FIXME: const problem adaptor.setNestedTable(&mColumns.at(column), mData, localIndex.first, nestedTable); } diff --git a/apps/opencs/model/world/refidcollection.hpp b/apps/opencs/model/world/refidcollection.hpp index ab25c93fa..dd432c5a9 100644 --- a/apps/opencs/model/world/refidcollection.hpp +++ b/apps/opencs/model/world/refidcollection.hpp @@ -5,8 +5,7 @@ #include #include -#include "columnbase.hpp" -#include "collectionbase.hpp" +#include "nestablecolumn.hpp" #include "nestedcollection.hpp" #include "refiddata.hpp" @@ -18,9 +17,9 @@ namespace ESM namespace CSMWorld { class RefIdAdapter; - class NestedTableWrapperBase; + class NestedTableWrapperBase; // FIXME: is this really needed? - class RefIdColumn : public NestColumn + class RefIdColumn : public NestableColumn { bool mEditable; bool mUserEditable; @@ -29,7 +28,7 @@ namespace CSMWorld RefIdColumn (int columnId, Display displayType, int flag = Flag_Table | Flag_Dialogue, bool editable = true, - bool userEditable = true, bool canNest = false); + bool userEditable = true); virtual bool isEditable() const; @@ -46,7 +45,7 @@ namespace CSMWorld private: - RefIdAdapter& findAdapter (UniversalId::Type) const; + /*const*/ RefIdAdapter& findAdapter (UniversalId::Type) const; ///< Throws an exception if no adaptor for \a Type can be found. public: @@ -57,10 +56,6 @@ namespace CSMWorld virtual int getSize() const; - virtual int getNestedRowsCount(int row, int column) const; - - virtual int getNestedColumnsCount(int row, int column) const; - virtual std::string getId (int index) const; virtual int getIndex (const std::string& id) const; @@ -71,22 +66,10 @@ namespace CSMWorld virtual QVariant getData (int index, int column) const; - virtual QVariant getNestedData(int row, int column, int subRow, int subColumn) const; - - virtual NestedTableWrapperBase* nestedTable(int row, int column) const; - - virtual void setNestedTable(int row, int column, const NestedTableWrapperBase& nestedTable); - virtual void setData (int index, int column, const QVariant& data); - virtual void setNestedData(int row, int column, const QVariant& data, int subRow, int subColumn); - virtual void removeRows (int index, int count); - virtual void removeNestedRows(int row, int column, int subRow); - - virtual void addNestedRow(int row, int col, int position); - virtual void cloneRecord(const std::string& origin, const std::string& destination, const UniversalId::Type type); @@ -128,6 +111,24 @@ namespace CSMWorld /// /// \return Success? + virtual QVariant getNestedData(int row, int column, int subRow, int subColumn) const; + + virtual NestedTableWrapperBase* nestedTable(int row, int column) const; + + virtual void setNestedTable(int row, int column, const NestedTableWrapperBase& nestedTable); + + // FIXME + virtual int getNestedRowsCount(int row, int column) const; + + // FIXME + virtual int getNestedColumnsCount(int row, int column) const; + + virtual void setNestedData(int row, int column, const QVariant& data, int subRow, int subColumn); + + virtual void removeNestedRows(int row, int column, int subRow); + + virtual void addNestedRow(int row, int col, int position); + void save (int index, ESM::ESMWriter& writer) const; const RefIdData& getDataSet() const; //I can't figure out a better name for this one :( diff --git a/apps/opencs/model/world/refiddata.hpp b/apps/opencs/model/world/refiddata.hpp index bfdd4f9ee..eaa7b115d 100644 --- a/apps/opencs/model/world/refiddata.hpp +++ b/apps/opencs/model/world/refiddata.hpp @@ -52,7 +52,7 @@ namespace CSMWorld virtual void load (int index, ESM::ESMReader& reader, bool base) = 0; virtual void erase (int index, int count) = 0; - + virtual std::string getId (int index) const = 0; virtual void save (int index, ESM::ESMWriter& writer) const = 0; @@ -134,7 +134,7 @@ namespace CSMWorld throw std::runtime_error ("invalid RefIdDataContainer index"); mContainer.erase (mContainer.begin()+index, mContainer.begin()+index+count); - } + } template std::string RefIdDataContainer::getId (int index) const @@ -231,7 +231,7 @@ namespace CSMWorld void save (int index, ESM::ESMWriter& writer) const; - //RECORD CONTAINERS ACCESS METHODS + //RECORD CONTAINERS ACCESS METHODS const RefIdDataContainer& getBooks() const; const RefIdDataContainer& getActivators() const; const RefIdDataContainer& getPotions() const; diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index e26dcdc9b..0aa83eb92 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -26,6 +26,7 @@ #include "../../model/world/nestedtableproxymodel.hpp" #include "../../model/world/columnbase.hpp" #include "../../model/world/idtable.hpp" +#include "../../model/world/idtree.hpp" #include "../../model/world/columns.hpp" #include "../../model/world/record.hpp" #include "../../model/world/tablemimedata.hpp" @@ -422,7 +423,7 @@ void CSVWorld::EditWidget::remake(int row) if (mTable->hasChildren(mTable->index(row, i))) { - mNestedModels.push_back(new CSMWorld::NestedTableProxyModel (mTable->index(row, i), display, mTable)); + mNestedModels.push_back(new CSMWorld::NestedTableProxyModel (mTable->index(row, i), display, dynamic_cast(mTable))); NestedTable* table = new NestedTable(mDocument, mNestedModels.back(), this); From 8eaf6b068cf6f91e0493a0e1673c691e0fbd7b55 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Thu, 2 Apr 2015 21:02:17 +1100 Subject: [PATCH 0876/3725] Adding missing file. --- apps/opencs/model/world/nestedcollection.cpp | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 apps/opencs/model/world/nestedcollection.cpp diff --git a/apps/opencs/model/world/nestedcollection.cpp b/apps/opencs/model/world/nestedcollection.cpp new file mode 100644 index 000000000..f557c3ba1 --- /dev/null +++ b/apps/opencs/model/world/nestedcollection.cpp @@ -0,0 +1,7 @@ +#include "nestedcollection.hpp" + +CSMWorld::NestedCollection::NestedCollection() : mParent(0) +{} + +CSMWorld::NestedCollection::~NestedCollection() +{} From ba3075dc110b5da47ab5e1b3aa069d54fecd444b Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 2 Apr 2015 16:28:16 +0200 Subject: [PATCH 0877/3725] Delete nifosgtest --- CMakeLists.txt | 2 - apps/nifosgtest/CMakeLists.txt | 7 -- apps/nifosgtest/test.cpp | 162 --------------------------------- 3 files changed, 171 deletions(-) delete mode 100644 apps/nifosgtest/CMakeLists.txt delete mode 100644 apps/nifosgtest/test.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 77bea373f..5e510b29d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -559,8 +559,6 @@ if (BUILD_NIFTEST) endif(BUILD_NIFTEST) # Apps and tools -add_subdirectory( apps/nifosgtest ) - if (BUILD_OPENMW) add_subdirectory( apps/openmw ) endif() diff --git a/apps/nifosgtest/CMakeLists.txt b/apps/nifosgtest/CMakeLists.txt deleted file mode 100644 index 265577d98..000000000 --- a/apps/nifosgtest/CMakeLists.txt +++ /dev/null @@ -1,7 +0,0 @@ -set (FILES - test.cpp -) - -add_executable (test ${FILES}) - -target_link_libraries (test ${OPENSCENEGRAPH_LIBRARIES} "components") diff --git a/apps/nifosgtest/test.cpp b/apps/nifosgtest/test.cpp deleted file mode 100644 index 332867be5..000000000 --- a/apps/nifosgtest/test.cpp +++ /dev/null @@ -1,162 +0,0 @@ -#include -#include - -#include -#include - -#include - -#include -#include -#include - -#include - -#include - -#include -#include - -#include - -#include - -// EventHandler to toggle wireframe when 'w' key is pressed -class WireframeKeyHandler : public osgGA::GUIEventHandler -{ -public: - WireframeKeyHandler(osg::Node* node) - : mWireframe(false) - , mNode(node) - { - - } - - virtual bool handle(const osgGA::GUIEventAdapter& adapter,osgGA::GUIActionAdapter& action) - { - switch (adapter.getEventType()) - { - case osgGA::GUIEventAdapter::KEYDOWN: - if (adapter.getKey() == osgGA::GUIEventAdapter::KEY_W) - { - mWireframe = !mWireframe; - osg::PolygonMode* mode = new osg::PolygonMode; - mode->setMode(osg::PolygonMode::FRONT_AND_BACK, - mWireframe ? osg::PolygonMode::LINE : osg::PolygonMode::FILL); - - // Create a new stateset instead of changing the old one, this alleviates the need to set - // the StateSet to DYNAMIC DataVariance, which would have a performance impact. - - osg::StateSet* stateset = new osg::StateSet; - stateset->setAttributeAndModes(mode, osg::StateAttribute::ON); - stateset->setMode(GL_CULL_FACE, mWireframe ? osg::StateAttribute::OFF - : osg::StateAttribute::ON); - - mNode->setStateSet(stateset); - - return true; - } - default: - break; - } - return false; - } - -private: - bool mWireframe; - osg::Node* mNode; -}; - -int main(int argc, char** argv) -{ - if (argc < 2) - { - std::cout << "Usage: " << argv[0] << " " << std::endl; - return 1; - } - - Files::ConfigurationManager cfgMgr; - boost::program_options::options_description desc(""); - desc.add_options() - ("data", boost::program_options::value()->default_value(Files::PathContainer(), "data")->multitoken()->composing()) - ("fs-strict", boost::program_options::value()->implicit_value(true)->default_value(false)) - ("fallback-archive", boost::program_options::value >()-> - default_value(std::vector(), "fallback-archive")->multitoken()); - - boost::program_options::variables_map variables; - cfgMgr.readConfiguration(variables, desc); - - std::vector archives = variables["fallback-archive"].as >(); - bool fsStrict = variables["fs-strict"].as(); - Files::PathContainer dataDirs; - if (!variables["data"].empty()) { - dataDirs = Files::PathContainer(variables["data"].as()); - } - - cfgMgr.processPaths(dataDirs); - - VFS::Manager resourceMgr (fsStrict); - Files::Collections collections (dataDirs, !fsStrict); - - for (std::vector::const_iterator it = archives.begin(); it != archives.end(); ++it) - { - std::string filepath = collections.getPath(*it).string(); - resourceMgr.addArchive(new VFS::BsaArchive(filepath)); - } - for (Files::PathContainer::const_iterator it = dataDirs.begin(); it != dataDirs.end(); ++it) - { - resourceMgr.addArchive(new VFS::FileSystemArchive(it->string())); - } - - resourceMgr.buildIndex(); - - Nif::NIFFilePtr nif(new Nif::NIFFile(resourceMgr.get(argv[1]), std::string(argv[1]))); - - // For NiStencilProperty - osg::DisplaySettings::instance()->setMinimumNumStencilBits(8); - - osgViewer::Viewer viewer; - - osg::ref_ptr root(new osg::Group()); - root->getOrCreateStateSet()->setMode(GL_CULL_FACE, osg::StateAttribute::ON); - // To prevent lighting issues with scaled meshes - root->getOrCreateStateSet()->setMode(GL_NORMALIZE, osg::StateAttribute::ON); - - - //osgDB::writeNodeFile(*newNode, "out.osg"); - osg::Group* newNode = new osg::Group; - NifOsg::Loader loader; - Resource::TextureManager texMgr(&resourceMgr); - loader.mTextureManager = &texMgr; - newNode->addChild(loader.load(nif)); - - osg::PositionAttitudeTransform* trans = new osg::PositionAttitudeTransform; - root->addChild(trans); - - for (int x=0; x<1;++x) - { - //root->addChild(newNode); - trans->addChild(newNode); - } - - viewer.setSceneData(root); - - viewer.setUpViewInWindow(0, 0, 800, 600); - viewer.realize(); - viewer.setCameraManipulator(new osgGA::TrackballManipulator()); - viewer.addEventHandler(new WireframeKeyHandler(root)); - - // Mask to separate cull visitors from update visitors - viewer.getCamera()->setCullMask(~(0x1)); - - viewer.addEventHandler(new osgViewer::StatsHandler); - - while (!viewer.done()) - { - //trans->setAttitude(osg::Quat(viewer.getFrameStamp()->getSimulationTime()*5, osg::Vec3f(0,0,1))); - - viewer.frame(); - } - - return 0; -} From 31adaf24950dfd4b2d6069e2ef5cb52410bb4c01 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 2 Apr 2015 17:32:52 +0200 Subject: [PATCH 0878/3725] Use simulationTime instead of referenceTime --- components/nifosg/controller.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index 76d3c5e62..463eb9e45 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -70,7 +70,7 @@ FrameTimeSource::FrameTimeSource() float FrameTimeSource::getValue(osg::NodeVisitor *nv) { - return nv->getFrameStamp()->getReferenceTime(); + return nv->getFrameStamp()->getSimulationTime(); } KeyframeController::KeyframeController() From 25f1c1ae764dc93cfc974b75bc2e8330e691d31e Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 2 Apr 2015 17:33:24 +0200 Subject: [PATCH 0879/3725] Remove persistent flag which will be unused --- components/esm/loadstat.cpp | 2 -- components/esm/loadstat.hpp | 2 -- 2 files changed, 4 deletions(-) diff --git a/components/esm/loadstat.cpp b/components/esm/loadstat.cpp index ed90b0475..b0ab89bed 100644 --- a/components/esm/loadstat.cpp +++ b/components/esm/loadstat.cpp @@ -10,8 +10,6 @@ namespace ESM void Static::load(ESMReader &esm) { - mPersistent = (esm.getRecordFlags() & 0x0400) != 0; - mModel = esm.getHNString("MODL"); } void Static::save(ESMWriter &esm) const diff --git a/components/esm/loadstat.hpp b/components/esm/loadstat.hpp index 45b05136a..d912d1058 100644 --- a/components/esm/loadstat.hpp +++ b/components/esm/loadstat.hpp @@ -26,8 +26,6 @@ struct Static std::string mId, mModel; - bool mPersistent; - void load(ESMReader &esm); void save(ESMWriter &esm) const; From e5e1013c519a297aec6c09347c5878b9fae3823c Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 2 Apr 2015 17:34:44 +0200 Subject: [PATCH 0880/3725] TextKeys attached to root node as user data, add .kf loading to scenemanager --- components/nifosg/controller.cpp | 7 +- components/nifosg/controller.hpp | 8 +- components/nifosg/nifloader.cpp | 119 ++++++++++++++------------- components/nifosg/nifloader.hpp | 39 +++++++-- components/resource/scenemanager.cpp | 26 +++++- components/resource/scenemanager.hpp | 15 ++++ 6 files changed, 134 insertions(+), 80 deletions(-) diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index 463eb9e45..5916359c8 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -477,22 +477,19 @@ void ParticleSystemController::operator() (osg::Node* node, osg::NodeVisitor* nv traverse(node, nv); } -SourcedKeyframeController::SourcedKeyframeController(const Nif::NiKeyframeData *data, int sourceIndex) +SourcedKeyframeController::SourcedKeyframeController(const Nif::NiKeyframeData *data) : KeyframeController(data) - , mSourceIndex(sourceIndex) , mEnabled(false) { } SourcedKeyframeController::SourcedKeyframeController() - : mSourceIndex(0) - , mEnabled(false) + : mEnabled(false) { } SourcedKeyframeController::SourcedKeyframeController(const SourcedKeyframeController ©, const osg::CopyOp ©op) : KeyframeController(copy, copyop) - , mSourceIndex(copy.mSourceIndex) , mEnabled(copy.mEnabled) { } diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index 0e5885333..80e6090e4 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -169,14 +169,13 @@ namespace NifOsg osg::Quat getXYZRotation(float time) const; }; - // Specialization of KeyframeController that remembers a "source index" for the animation source - // it came from, and can be enabled/disabled. Used for multiple animation sources support, i.e. .kf files. + // Specialization that can be enabled/disabled. Used for multiple animation sources support, i.e. .kf files. // A SourcedKeyframeController is disabled by default and should be manually enabled when playing an animation from // the relevant animation source. class SourcedKeyframeController : public KeyframeController { public: - SourcedKeyframeController(const Nif::NiKeyframeData* data, int sourceIndex); + SourcedKeyframeController(const Nif::NiKeyframeData* data); SourcedKeyframeController(); SourcedKeyframeController(const SourcedKeyframeController& copy, const osg::CopyOp& copyop); @@ -184,12 +183,9 @@ namespace NifOsg virtual void operator() (osg::Node*, osg::NodeVisitor*); - int getSourceIndex() const; - void setEnabled(bool enabled); private: - int mSourceIndex; bool mEnabled; }; diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 555105e35..94885a11b 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -298,6 +298,7 @@ namespace // NodeVisitor that adds keyframe controllers to an existing scene graph, used when loading .kf files + /* class LoadKfVisitor : public osg::NodeVisitor { public: @@ -332,6 +333,7 @@ namespace std::map mMap; int mSourceIndex; }; + */ // Node callback used to dirty a RigGeometry's bounding box every frame, so that RigBoundingBoxCallback updates. // This has to be attached to the geode, because the RigGeometry's Drawable::UpdateCallback is already used internally and not extensible. @@ -522,19 +524,15 @@ namespace NifOsg sShowMarkers = show; } + bool Loader::getShowMarkers() + { + return sShowMarkers; + } + class LoaderImpl { public: - Resource::TextureManager* mTextureManager; - bool mShowMarkers; - - LoaderImpl(Resource::TextureManager* textureManager, bool showMarkers) - : mTextureManager(textureManager) - , mShowMarkers(showMarkers) - { - } - - void loadKf(Nif::NIFFilePtr nif, osg::Node *rootNode, int sourceIndex, TextKeyMap& textKeys) + static void loadKf(Nif::NIFFilePtr nif, KeyframeHolder& target) { if(nif->numRoots() < 1) { @@ -561,9 +559,7 @@ namespace NifOsg return; } - extractTextKeys(static_cast(extra.getPtr()), textKeys); - - std::map controllerMap; + extractTextKeys(static_cast(extra.getPtr()), target.mTextKeys); extra = extra->extra; Nif::ControllerPtr ctrl = seq->controller; @@ -584,17 +580,17 @@ namespace NifOsg if(key->data.empty()) continue; - controllerMap[strdata->string] = key; - } + osg::ref_ptr callback(new NifOsg::SourcedKeyframeController(key->data.getPtr())); + callback->mFunction = boost::shared_ptr(new NifOsg::ControllerFunction(key)); - LoadKfVisitor visitor(controllerMap, sourceIndex); - rootNode->accept(visitor); + target.mKeyframeControllers[strdata->string] = callback; + } } - osg::ref_ptr load(Nif::NIFFilePtr nif, TextKeyMap* textKeys) + static osg::ref_ptr load(Nif::NIFFilePtr nif, Resource::TextureManager* textureManager) { if (nif->getUseSkinning()) - return loadAsSkeleton(nif, textKeys); + return loadAsSkeleton(nif, textureManager); if (nif->numRoots() < 1) nif->fail("Found no root nodes"); @@ -605,11 +601,16 @@ namespace NifOsg if (nifNode == NULL) nif->fail("First root was not a node, but a " + r->recName); - osg::ref_ptr created = handleNode(nifNode, NULL, false, std::map(), 0, 0, false, textKeys); + osg::ref_ptr textkeys (new TextKeyMapHolder); + + osg::ref_ptr created = handleNode(nifNode, NULL, textureManager, false, std::map(), 0, 0, false, &textkeys->mTextKeys); + + created->getOrCreateUserDataContainer()->addUserObject(textkeys); + return created; } - osg::ref_ptr loadAsSkeleton(Nif::NIFFilePtr nif, TextKeyMap* textKeys) + static osg::ref_ptr loadAsSkeleton(Nif::NIFFilePtr nif, Resource::TextureManager* textureManager) { if (nif->numRoots() < 1) nif->fail("Found no root nodes"); @@ -621,24 +622,28 @@ namespace NifOsg if (nifNode == NULL) nif->fail("First root was not a node, but a " + r->recName); + osg::ref_ptr textkeys (new TextKeyMapHolder); + osg::ref_ptr skel = new osgAnimation::Skeleton; skel->setDefaultUpdateCallback(); // validates the skeleton hierarchy - handleNode(nifNode, skel, true, std::map(), 0, 0, false, textKeys); + handleNode(nifNode, skel, textureManager, true, std::map(), 0, 0, false, &textkeys->mTextKeys); + + skel->getOrCreateUserDataContainer()->addUserObject(textkeys); return skel; } - void applyNodeProperties(const Nif::Node *nifNode, osg::Node *applyTo, std::map& boundTextures, int animflags) + static void applyNodeProperties(const Nif::Node *nifNode, osg::Node *applyTo, Resource::TextureManager* textureManager, std::map& boundTextures, int animflags) { const Nif::PropertyList& props = nifNode->props; for (size_t i = 0; i mFunction = boost::shared_ptr(new ControllerFunction(ctrl)); } - osg::ref_ptr handleNode(const Nif::Node* nifNode, osg::Group* parentNode, bool createSkeleton, + static osg::ref_ptr handleNode(const Nif::Node* nifNode, osg::Group* parentNode, Resource::TextureManager* textureManager, bool createSkeleton, std::map boundTextures, int animflags, int particleflags, bool skipMeshes, TextKeyMap* textKeys, osg::Node* rootNode=NULL) { osg::ref_ptr transformNode; @@ -698,7 +703,7 @@ namespace NifOsg const Nif::NiStringExtraData *sd = static_cast(e.getPtr()); // String markers may contain important information // affecting the entire subtree of this obj - if(sd->string == "MRK" && !mShowMarkers) + if(sd->string == "MRK" && !Loader::getShowMarkers()) { // Marker objects. These meshes are only visible in the editor. skipMeshes = true; @@ -735,7 +740,7 @@ namespace NifOsg transformNode->setNodeMask(0x1); } - applyNodeProperties(nifNode, transformNode, boundTextures, animflags); + applyNodeProperties(nifNode, transformNode, textureManager, boundTextures, animflags); if (nifNode->recType == Nif::RC_NiTriShape && !skipMeshes) { @@ -767,7 +772,8 @@ namespace NifOsg { if(!children[i].empty()) { - handleNode(children[i].getPtr(), transformNode, createSkeleton, boundTextures, animflags, particleflags, skipMeshes, textKeys, rootNode); + handleNode(children[i].getPtr(), transformNode, textureManager, + createSkeleton, boundTextures, animflags, particleflags, skipMeshes, textKeys, rootNode); } } } @@ -775,7 +781,7 @@ namespace NifOsg return transformNode; } - void handleMeshControllers(const Nif::Node *nifNode, osg::MatrixTransform *transformNode, const std::map &boundTextures, int animflags) + static void handleMeshControllers(const Nif::Node *nifNode, osg::MatrixTransform *transformNode, const std::map &boundTextures, int animflags) { for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next) { @@ -797,7 +803,7 @@ namespace NifOsg } } - void handleNodeControllers(const Nif::Node* nifNode, osg::MatrixTransform* transformNode, int animflags) + static void handleNodeControllers(const Nif::Node* nifNode, osg::MatrixTransform* transformNode, int animflags) { for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next) { @@ -825,7 +831,7 @@ namespace NifOsg } } - void handleMaterialControllers(const Nif::Property *materialProperty, osg::Node* node, osg::StateSet *stateset, int animflags) + static void handleMaterialControllers(const Nif::Property *materialProperty, osg::Node* node, osg::StateSet *stateset, int animflags) { for (Nif::ControllerPtr ctrl = materialProperty->controller; !ctrl.empty(); ctrl = ctrl->next) { @@ -852,7 +858,7 @@ namespace NifOsg } } - void handleTextureControllers(const Nif::Property *texProperty, osg::Node* node, osg::StateSet *stateset, int animflags) + static void handleTextureControllers(const Nif::Property *texProperty, osg::Node* node, Resource::TextureManager* textureManager, osg::StateSet *stateset, int animflags) { for (Nif::ControllerPtr ctrl = texProperty->controller; !ctrl.empty(); ctrl = ctrl->next) { @@ -878,8 +884,8 @@ namespace NifOsg wrapT = inherit->getWrap(osg::Texture2D::WRAP_T); } - std::string filename = Misc::ResourceHelpers::correctTexturePath(st->filename, mTextureManager->getVFS()); - osg::ref_ptr texture = mTextureManager->getTexture2D(filename, wrapS, wrapT); + std::string filename = Misc::ResourceHelpers::correctTexturePath(st->filename, textureManager->getVFS()); + osg::ref_ptr texture = textureManager->getTexture2D(filename, wrapS, wrapT); textures.push_back(texture); } osg::ref_ptr callback(new FlipController(flipctrl, textures)); @@ -892,7 +898,7 @@ namespace NifOsg } } - void handleParticlePrograms(Nif::ExtraPtr affectors, Nif::ExtraPtr colliders, osg::Group *attachTo, osgParticle::ParticleSystem* partsys, osgParticle::ParticleProcessor::ReferenceFrame rf) + static void handleParticlePrograms(Nif::ExtraPtr affectors, Nif::ExtraPtr colliders, osg::Group *attachTo, osgParticle::ParticleSystem* partsys, osgParticle::ParticleProcessor::ReferenceFrame rf) { osgParticle::ModularProgram* program = new osgParticle::ModularProgram; attachTo->addChild(program); @@ -934,7 +940,7 @@ namespace NifOsg } // Load the initial state of the particle system, i.e. the initial particles and their positions, velocity and colors. - void handleParticleInitialState(const Nif::Node* nifNode, osgParticle::ParticleSystem* partsys, const Nif::NiParticleSystemController* partctrl) + static void handleParticleInitialState(const Nif::Node* nifNode, osgParticle::ParticleSystem* partsys, const Nif::NiParticleSystemController* partctrl) { const Nif::NiAutoNormalParticlesData *particledata = NULL; if(nifNode->recType == Nif::RC_NiAutoNormalParticles) @@ -970,7 +976,7 @@ namespace NifOsg } } - osg::ref_ptr handleParticleEmitter(const Nif::NiParticleSystemController* partctrl) + static osg::ref_ptr handleParticleEmitter(const Nif::NiParticleSystemController* partctrl) { std::vector targets; if (partctrl->recType == Nif::RC_NiBSPArrayController) @@ -1004,7 +1010,7 @@ namespace NifOsg return emitter; } - void handleParticleSystem(const Nif::Node *nifNode, osg::Group *parentNode, int animflags, int particleflags, osg::Node* rootNode) + static void handleParticleSystem(const Nif::Node *nifNode, osg::Group *parentNode, int animflags, int particleflags, osg::Node* rootNode) { osg::ref_ptr partsys (new ParticleSystem); partsys->setSortMode(osgParticle::ParticleSystem::SORT_BACK_TO_FRONT); @@ -1100,7 +1106,7 @@ namespace NifOsg } } - void triShapeToGeometry(const Nif::NiTriShape *triShape, osg::Geometry *geometry, osg::Geode* parentGeode, const std::map& boundTextures, int animflags) + static void triShapeToGeometry(const Nif::NiTriShape *triShape, osg::Geometry *geometry, osg::Geode* parentGeode, const std::map& boundTextures, int animflags) { const Nif::NiTriShapeData* data = triShape->data.getPtr(); @@ -1183,7 +1189,7 @@ namespace NifOsg applyMaterialProperties(parentGeode, materialProps, !data->colors.empty(), animflags); } - void handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, const std::map& boundTextures, int animflags) + static void handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, const std::map& boundTextures, int animflags) { osg::ref_ptr geometry; if(!triShape->controller.empty()) @@ -1215,7 +1221,7 @@ namespace NifOsg parentNode->addChild(geode); } - osg::ref_ptr handleMorphGeometry(const Nif::NiGeomMorpherController* morpher) + static osg::ref_ptr handleMorphGeometry(const Nif::NiGeomMorpherController* morpher) { osg::ref_ptr morphGeom = new osgAnimation::MorphGeometry; morphGeom->setMethod(osgAnimation::MorphGeometry::RELATIVE); @@ -1233,7 +1239,7 @@ namespace NifOsg return morphGeom; } - void handleSkinnedTriShape(const Nif::NiTriShape *triShape, osg::Group *parentNode, const std::map& boundTextures, int animflags) + static void handleSkinnedTriShape(const Nif::NiTriShape *triShape, osg::Group *parentNode, const std::map& boundTextures, int animflags) { osg::ref_ptr geode (new osg::Geode); geode->setName(triShape->name); // name will be used for part filtering @@ -1289,8 +1295,8 @@ namespace NifOsg } - void handleProperty(const Nif::Property *property, - osg::Node *node, std::map& boundTextures, int animflags) + static void handleProperty(const Nif::Property *property, + osg::Node *node, Resource::TextureManager* textureManager, std::map& boundTextures, int animflags) { osg::StateSet* stateset = node->getOrCreateStateSet(); @@ -1417,13 +1423,13 @@ namespace NifOsg continue; } - std::string filename = Misc::ResourceHelpers::correctTexturePath(st->filename, mTextureManager->getVFS()); + std::string filename = Misc::ResourceHelpers::correctTexturePath(st->filename, textureManager->getVFS()); unsigned int clamp = static_cast(tex.clamp); int wrapT = (clamp) & 0x1; int wrapS = (clamp >> 1) & 0x1; - osg::Texture2D* texture2d = mTextureManager->getTexture2D(filename, + osg::Texture2D* texture2d = textureManager->getTexture2D(filename, wrapS ? osg::Texture::REPEAT : osg::Texture::CLAMP, wrapT ? osg::Texture::REPEAT : osg::Texture::CLAMP); @@ -1465,7 +1471,7 @@ namespace NifOsg stateset->setTextureAttributeAndModes(i, new osg::Texture2D, osg::StateAttribute::OFF); boundTextures.erase(i); } - handleTextureControllers(texprop, node, stateset, animflags); + handleTextureControllers(texprop, node, textureManager, stateset, animflags); } break; } @@ -1482,7 +1488,7 @@ namespace NifOsg } } - void applyMaterialProperties(osg::Node* node, const std::vector& properties, + static void applyMaterialProperties(osg::Node* node, const std::vector& properties, bool hasVertexColors, int animflags) { osg::StateSet* stateset = node->getOrCreateStateSet(); @@ -1550,22 +1556,19 @@ namespace NifOsg }; - osg::ref_ptr Loader::load(Nif::NIFFilePtr file, TextKeyMap *textKeys) + osg::ref_ptr Loader::load(Nif::NIFFilePtr file, Resource::TextureManager* textureManager) { - LoaderImpl loader(mTextureManager, sShowMarkers); - return loader.load(file, textKeys); + return LoaderImpl::load(file, textureManager); } - osg::ref_ptr Loader::loadAsSkeleton(Nif::NIFFilePtr file, TextKeyMap *textKeys) + osg::ref_ptr Loader::loadAsSkeleton(Nif::NIFFilePtr file, Resource::TextureManager* textureManager) { - LoaderImpl loader(mTextureManager, sShowMarkers); - return loader.loadAsSkeleton(file, textKeys); + return LoaderImpl::loadAsSkeleton(file, textureManager); } - void Loader::loadKf(Nif::NIFFilePtr kf, osg::Node *rootNode, int sourceIndex, TextKeyMap &textKeys) + void Loader::loadKf(Nif::NIFFilePtr kf, KeyframeHolder& target) { - LoaderImpl loader(mTextureManager, sShowMarkers); - loader.loadKf(kf, rootNode, sourceIndex, textKeys); + LoaderImpl::loadKf(kf, target); } } diff --git a/components/nifosg/nifloader.hpp b/components/nifosg/nifloader.hpp index 716cd1957..1c403a4fe 100644 --- a/components/nifosg/nifloader.hpp +++ b/components/nifosg/nifloader.hpp @@ -6,6 +6,9 @@ #include // NIFFilePtr #include +#include + +#include "controller.hpp" namespace osg { @@ -21,30 +24,52 @@ namespace NifOsg { typedef std::multimap TextKeyMap; + struct TextKeyMapHolder : public osg::Object + { + public: + TextKeyMapHolder() {} + TextKeyMapHolder(const TextKeyMapHolder& copy, const osg::CopyOp& copyop) + : osg::Object(copy, copyop) + , mTextKeys(copy.mTextKeys) + {} + + TextKeyMap mTextKeys; + + META_Object(NifOsg, TextKeyMapHolder) + + }; + + class KeyframeHolder : public osg::Referenced + { + public: + TextKeyMap mTextKeys; + + std::map > mKeyframeControllers; + }; + /// The main class responsible for loading NIF files into an OSG-Scenegraph. /// @par This scene graph is self-contained and can be cloned using osg::clone if desired. Particle emitters /// and programs hold a pointer to their ParticleSystem, which would need to be manually updated when cloning. class Loader { public: + // TODO: add text keys as user data on the node /// Create a scene graph for the given NIF. Auto-detects when skinning is used and calls loadAsSkeleton instead. /// @param node The parent of the new root node for the created scene graph. - osg::ref_ptr load(Nif::NIFFilePtr file, TextKeyMap* textKeys = NULL); + static osg::ref_ptr load(Nif::NIFFilePtr file, Resource::TextureManager* textureManager); /// Create a scene graph for the given NIF. Always creates a skeleton so that rigs can be attached on the created scene. - osg::ref_ptr loadAsSkeleton(Nif::NIFFilePtr file, TextKeyMap* textKeys = NULL); + static osg::ref_ptr loadAsSkeleton(Nif::NIFFilePtr file, Resource::TextureManager* textureManager); - /// Load keyframe controllers from the given kf file onto the given scene graph. - /// @param sourceIndex The source index for this animation source, used for identifying - /// which animation source a keyframe controller came from. - void loadKf(Nif::NIFFilePtr kf, osg::Node* rootNode, int sourceIndex, TextKeyMap &textKeys); + /// Load keyframe controllers from the given kf file. + static void loadKf(Nif::NIFFilePtr kf, KeyframeHolder& target); /// Set whether or not nodes marked as "MRK" should be shown. /// These should be hidden ingame, but visible in the editior. /// Default: false. static void setShowMarkers(bool show); - Resource::TextureManager* mTextureManager; + static bool getShowMarkers(); private: diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index 3f38762ca..e626a9f08 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -82,10 +82,7 @@ namespace Resource // TODO: add support for non-NIF formats NifOsg::Loader loader; - loader.mTextureManager = mTextureManager; - osg::ref_ptr loaded = loader.load(Nif::NIFFilePtr(new Nif::NIFFile(file, normalized))); - - // TODO: provide way for the user to get textKeys (attach to the node?) + osg::ref_ptr loaded = loader.load(Nif::NIFFilePtr(new Nif::NIFFile(file, normalized)), mTextureManager); mIndex[normalized] = loaded; return loaded; @@ -108,6 +105,27 @@ namespace Resource return cloned; } + osg::ref_ptr SceneManager::getKeyframes(const std::string &name) + { + std::string normalized = name; + mVFS->normalizeFilename(normalized); + + KeyframeIndex::iterator it = mKeyframeIndex.find(normalized); + if (it == mKeyframeIndex.end()) + { + Files::IStreamPtr file = mVFS->get(normalized); + + NifOsg::Loader loader; + osg::ref_ptr loaded (new NifOsg::KeyframeHolder); + loader.loadKf(Nif::NIFFilePtr(new Nif::NIFFile(file, normalized)), *loaded.get()); + + mKeyframeIndex[normalized] = loaded; + return loaded; + } + else + return it->second; + } + void SceneManager::attachTo(osg::Node *instance, osg::Group *parentNode) const { parentNode->addChild(instance); diff --git a/components/resource/scenemanager.hpp b/components/resource/scenemanager.hpp index 7b3bcb2d5..4d6ad4855 100644 --- a/components/resource/scenemanager.hpp +++ b/components/resource/scenemanager.hpp @@ -7,6 +7,8 @@ #include #include +#include + namespace Resource { class TextureManager; @@ -17,6 +19,11 @@ namespace VFS class Manager; } +namespace NifOsg +{ + class KeyframeHolder; +} + namespace Resource { @@ -41,6 +48,11 @@ namespace Resource /// @note Assumes the given instance was not attached to any parents before. void attachTo(osg::Node* instance, osg::Group* parentNode) const; + /// Get a read-only copy of the given keyframe file. + osg::ref_ptr getKeyframes(const std::string& name); + + /// Manually release created OpenGL objects for the given graphics context. This may be required + /// in cases where multiple contexts are used over the lifetime of the application. void releaseGLObjects(osg::State* state); private: @@ -50,6 +62,9 @@ namespace Resource // observer_ptr? typedef std::map > Index; Index mIndex; + + typedef std::map > KeyframeIndex; + KeyframeIndex mKeyframeIndex; }; } From 6b6bed520d82061c1b401e9aabf617db9d17d309 Mon Sep 17 00:00:00 2001 From: dteviot Date: Fri, 3 Apr 2015 13:45:13 +1300 Subject: [PATCH 0881/3725] removed redundant calls. --- apps/openmw/mwgui/quickkeysmenu.cpp | 1 - apps/openmw/mwgui/spellwindow.cpp | 2 -- 2 files changed, 3 deletions(-) diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index 8f595df80..834c156f9 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -548,7 +548,6 @@ namespace MWGui WindowModal::open(); mMagicList->setModel(new SpellModel(MWBase::Environment::get().getWorld()->getPlayerPtr())); - mMagicList->update(); } void MagicSelectionDialog::onModelIndexSelected(SpellModel::ModelIndex index) diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index cc032691e..4fdeb91cf 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -65,7 +65,6 @@ namespace MWGui mSpellIcons->updateWidgets(mEffectBox, false); mSpellView->setModel(new SpellModel(MWBase::Environment::get().getWorld()->getPlayerPtr())); - mSpellView->update(); } void SpellWindow::onEnchantedItemSelected(MWWorld::Ptr item, bool alreadyEquipped) @@ -170,7 +169,6 @@ namespace MWGui void SpellWindow::cycle(bool next) { mSpellView->setModel(new SpellModel(MWBase::Environment::get().getWorld()->getPlayerPtr())); - mSpellView->getModel()->update(); SpellModel::ModelIndex selected = 0; for (SpellModel::ModelIndex i = 0; igetModel()->getItemCount()); ++i) From 745eae9c10b01885a6245df2f87f366867123b96 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Fri, 3 Apr 2015 12:44:32 +1100 Subject: [PATCH 0882/3725] Tweak DialogueSubView layout for nested tables. --- apps/opencs/view/world/dialoguesubview.cpp | 39 ++++++---------------- 1 file changed, 10 insertions(+), 29 deletions(-) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 0aa83eb92..d0b53a206 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -17,11 +17,9 @@ #include #include #include -#include #include #include #include -#include #include "../../model/world/nestedtableproxymodel.hpp" #include "../../model/world/columnbase.hpp" @@ -384,27 +382,17 @@ void CSVWorld::EditWidget::remake(int row) mWidgetMapper->setModel(mTable); mWidgetMapper->setItemDelegate(&mDispatcher); - QFrame* line = new QFrame(mMainWidget); - line->setObjectName(QString::fromUtf8("line")); - line->setGeometry(QRect(320, 150, 118, 3)); - line->setFrameShape(QFrame::HLine); - line->setFrameShadow(QFrame::Sunken); - - QFrame* line2 = new QFrame(mMainWidget); - line2->setObjectName(QString::fromUtf8("line2")); - line2->setGeometry(QRect(320, 150, 118, 3)); - line2->setFrameShape(QFrame::HLine); - line2->setFrameShadow(QFrame::Sunken); - QVBoxLayout *mainLayout = new QVBoxLayout(mMainWidget); - QGridLayout *unlockedLayout = new QGridLayout(); + QScrollArea *scroll = new QScrollArea(mMainWidget); + QWidget *unlockedWidget = new QWidget(scroll); + QGridLayout *unlockedLayout = new QGridLayout(unlockedWidget); QGridLayout *lockedLayout = new QGridLayout(); QVBoxLayout *tablesLayout = new QVBoxLayout(); mainLayout->addLayout(lockedLayout, 0); - mainLayout->addWidget(line, 1); - mainLayout->addLayout(unlockedLayout, 2); - mainLayout->addWidget(line2, 1); + mainLayout->addSpacing(5); // FIXME: arbitrary number + mainLayout->addWidget(scroll, 2); + mainLayout->addSpacing(5); // FIXME: arbitrary number mainLayout->addLayout(tablesLayout, 0); mainLayout->addStretch(1); @@ -426,18 +414,8 @@ void CSVWorld::EditWidget::remake(int row) mNestedModels.push_back(new CSMWorld::NestedTableProxyModel (mTable->index(row, i), display, dynamic_cast(mTable))); NestedTable* table = new NestedTable(mDocument, mNestedModels.back(), this); + table->resizeColumnsToContents(); - int rows = mNestedModels.back()->rowCount(mTable->index(row, i)); - if (rows == 0) rows = 1; // FIXME: quick hack - int rowHeight = table->rowHeight(0); - int tableHeight = (rows * rowHeight) - + table->horizontalHeader()->height() + 2 * table->frameWidth(); - int tableMaxHeight = (5 * rowHeight) - + table->horizontalHeader()->height() + 2 * table->frameWidth(); - if (rows > 1 && rows < 5) - table->setMinimumHeight(tableHeight); - else if (rows > 1) - table->setMinimumHeight(tableMaxHeight); QLabel* label = new QLabel (mTable->headerData (i, Qt::Horizontal, Qt::DisplayRole).toString(), mMainWidget); @@ -479,6 +457,9 @@ void CSVWorld::EditWidget::remake(int row) mWidgetMapper->setCurrentModelIndex(mTable->index(row, 0)); + scroll->setWidget(unlockedWidget); + scroll->setSizePolicy (QSizePolicy::Expanding, QSizePolicy::Fixed); + scroll->setWidgetResizable(true); this->setWidget(mMainWidget); this->setWidgetResizable(true); } From 52de622e9732d6dd3c36e22f0cd3562f52221f2d Mon Sep 17 00:00:00 2001 From: dteviot Date: Fri, 3 Apr 2015 17:59:13 +1300 Subject: [PATCH 0883/3725] provide incremental update of SpellWindow (Fixes #2411) When SpellWindow is visible, every 0.5 seconds update the cost/changes for spells/enchanted items shown. Also, check to see if more substantial update of the window is required. --- apps/openmw/mwgui/spellview.cpp | 95 +++++++++++++++++++++++++------ apps/openmw/mwgui/spellview.hpp | 17 +++++- apps/openmw/mwgui/spellwindow.cpp | 15 +++++ apps/openmw/mwgui/spellwindow.hpp | 5 +- 4 files changed, 113 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwgui/spellview.cpp b/apps/openmw/mwgui/spellview.cpp index 668b239bc..eeadc1d81 100644 --- a/apps/openmw/mwgui/spellview.cpp +++ b/apps/openmw/mwgui/spellview.cpp @@ -10,6 +10,8 @@ namespace MWGui { + const char* SpellView::sSpellModelIndex = "SpellModelIndex"; + SpellView::SpellView() : mShowCostColumn(true) , mHighlightSelected(true) @@ -113,10 +115,10 @@ namespace MWGui group.push_back(costChance); Gui::SharedStateButton::createButtonGroup(group); - mLines.push_back(std::make_pair(t, costChance)); + mLines.push_back(boost::make_tuple(t, costChance, true)); } else - mLines.push_back(std::make_pair(t, (MyGUI::Widget*)NULL)); + mLines.push_back(boost::make_tuple(t, (MyGUI::Widget*)NULL, true)); t->setStateSelected(spell.mSelected); } @@ -124,30 +126,85 @@ namespace MWGui layoutWidgets(); } + void SpellView::incrementalUpdate() + { + if (!mModel.get()) + { + return; + } + + mModel->update(); + bool fullUpdateRequired = false; + SpellModel::ModelIndex maxSpellIndexFound = -1; + for (std::vector< LineInfo >::iterator it = mLines.begin(); it != mLines.end(); ++it) + { + // only update the lines that are "updateable" + if (it->get<2>()) + { + Gui::SharedStateButton* nameButton = reinterpret_cast(it->get<0>()); + + // match model against line + // if don't match, then major change has happened, so do a full update + SpellModel::ModelIndex spellIndex = getSpellModelIndex(nameButton); + if (mModel->getItemCount() <= static_cast(spellIndex)) + { + fullUpdateRequired = true; + break; + } + + // more checking for major change. + const Spell& spell = mModel->getItem(spellIndex); + if (nameButton->getCaption() != spell.mName) + { + fullUpdateRequired = true; + break; + } + else + { + maxSpellIndexFound = spellIndex; + Gui::SharedStateButton* costButton = reinterpret_cast(it->get<1>()); + if ((costButton != NULL) && (costButton->getCaption() != spell.mCostColumn)) + { + costButton->setCaption(spell.mCostColumn); + } + } + } + } + + // special case, look for spells added to model that are beyond last updatable item + SpellModel::ModelIndex topSpellIndex = mModel->getItemCount() - 1; + if (fullUpdateRequired || + ((0 <= topSpellIndex) && (maxSpellIndexFound < topSpellIndex))) + { + update(); + } + } + + void SpellView::layoutWidgets() { int height = 0; - for (std::vector< std::pair >::iterator it = mLines.begin(); + for (std::vector< LineInfo >::iterator it = mLines.begin(); it != mLines.end(); ++it) { - height += (it->first)->getHeight(); + height += (it->get<0>())->getHeight(); } bool scrollVisible = height > mScrollView->getHeight(); int width = mScrollView->getWidth() - (scrollVisible ? 18 : 0); height = 0; - for (std::vector< std::pair >::iterator it = mLines.begin(); + for (std::vector< LineInfo >::iterator it = mLines.begin(); it != mLines.end(); ++it) { - int lineHeight = (it->first)->getHeight(); - (it->first)->setCoord(4, height, width-8, lineHeight); - if (it->second) + int lineHeight = (it->get<0>())->getHeight(); + (it->get<0>())->setCoord(4, height, width - 8, lineHeight); + if (it->get<1>()) { - (it->second)->setCoord(4, height, width-8, lineHeight); - MyGUI::TextBox* second = (it->second)->castType(false); + (it->get<1>())->setCoord(4, height, width - 8, lineHeight); + MyGUI::TextBox* second = (it->get<1>())->castType(false); if (second) - (it->first)->setSize(width-8-second->getTextSize().width, lineHeight); + (it->get<0>())->setSize(width - 8 - second->getTextSize().width, lineHeight); } height += lineHeight; @@ -167,7 +224,7 @@ namespace MWGui MyGUI::IntCoord(0, 0, mScrollView->getWidth(), 18), MyGUI::Align::Left | MyGUI::Align::Top); separator->setNeedMouseFocus(false); - mLines.push_back(std::make_pair(separator, (MyGUI::Widget*)NULL)); + mLines.push_back(boost::make_tuple(separator, (MyGUI::Widget*)NULL, false)); } MyGUI::TextBox* groupWidget = mScrollView->createWidget("SandBrightText", @@ -186,10 +243,10 @@ namespace MWGui groupWidget2->setTextAlign(MyGUI::Align::Right); groupWidget2->setNeedMouseFocus(false); - mLines.push_back(std::make_pair(groupWidget, groupWidget2)); + mLines.push_back(boost::make_tuple(groupWidget, groupWidget2, false)); } else - mLines.push_back(std::make_pair(groupWidget, (MyGUI::Widget*)NULL)); + mLines.push_back(boost::make_tuple(groupWidget, (MyGUI::Widget*)NULL, false)); } @@ -222,16 +279,20 @@ namespace MWGui widget->setUserString("Spell", spell.mId); } - widget->setUserString("SpellModelIndex", MyGUI::utility::toString(index)); + widget->setUserString(sSpellModelIndex, MyGUI::utility::toString(index)); widget->eventMouseWheel += MyGUI::newDelegate(this, &SpellView::onMouseWheel); widget->eventMouseButtonClick += MyGUI::newDelegate(this, &SpellView::onSpellSelected); } + SpellModel::ModelIndex SpellView::getSpellModelIndex(MyGUI::Widget* widget) + { + return MyGUI::utility::parseInt(widget->getUserString(sSpellModelIndex)); + } + void SpellView::onSpellSelected(MyGUI::Widget* _sender) { - SpellModel::ModelIndex i = MyGUI::utility::parseInt(_sender->getUserString("SpellModelIndex")); - eventSpellClicked(i); + eventSpellClicked(getSpellModelIndex(_sender)); } void SpellView::onMouseWheel(MyGUI::Widget* _sender, int _rel) diff --git a/apps/openmw/mwgui/spellview.hpp b/apps/openmw/mwgui/spellview.hpp index 005d206f4..2f6ff2624 100644 --- a/apps/openmw/mwgui/spellview.hpp +++ b/apps/openmw/mwgui/spellview.hpp @@ -1,6 +1,8 @@ #ifndef OPENMW_GUI_SPELLVIEW_H #define OPENMW_GUI_SPELLVIEW_H +#include + #include #include "spellmodel.hpp" @@ -37,6 +39,9 @@ namespace MWGui void update(); + /// simplified update called each frame + void incrementalUpdate(); + typedef MyGUI::delegates::CMultiDelegate1 EventHandle_ModelIndex; /// Fired when a spell was clicked EventHandle_ModelIndex eventSpellClicked; @@ -51,7 +56,13 @@ namespace MWGui std::auto_ptr mModel; - std::vector< std::pair > mLines; + /// tracks an item in the spell view + /// element<0> is the left column GUI object (usually holds the name) + /// element<1> is the right column (charge or cost info) + /// element<2> is if line needs to be checked during incremental update + typedef boost::tuple LineInfo; + + std::vector< LineInfo > mLines; bool mShowCostColumn; bool mHighlightSelected; @@ -62,6 +73,10 @@ namespace MWGui void onSpellSelected(MyGUI::Widget* _sender); void onMouseWheel(MyGUI::Widget* _sender, int _rel); + + SpellModel::ModelIndex getSpellModelIndex(MyGUI::Widget* _sender); + + static const char* sSpellModelIndex; }; } diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index 4fdeb91cf..ca5ec20bd 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -28,6 +28,7 @@ namespace MWGui : WindowPinnableBase("openmw_spell_window.layout") , NoDrop(drag, mMainWidget) , mSpellView(NULL) + , mUpdateTimer(0.0f) { mSpellIcons = new SpellIcons(); @@ -60,6 +61,20 @@ namespace MWGui updateSpells(); } + void SpellWindow::onFrame(float dt) + { + if (mMainWidget->getVisible()) + { + NoDrop::onFrame(dt); + mUpdateTimer += dt; + if (0.5f < mUpdateTimer) + { + mUpdateTimer = 0; + mSpellView->incrementalUpdate(); + } + } + } + void SpellWindow::updateSpells() { mSpellIcons->updateWidgets(mEffectBox, false); diff --git a/apps/openmw/mwgui/spellwindow.hpp b/apps/openmw/mwgui/spellwindow.hpp index 8b5474f58..dcce10f9d 100644 --- a/apps/openmw/mwgui/spellwindow.hpp +++ b/apps/openmw/mwgui/spellwindow.hpp @@ -19,7 +19,7 @@ namespace MWGui void updateSpells(); - void onFrame(float dt) { NoDrop::onFrame(dt); } + void onFrame(float dt); /// Cycle to next/previous spell void cycle(bool next); @@ -41,6 +41,9 @@ namespace MWGui SpellView* mSpellView; SpellIcons* mSpellIcons; + + private: + float mUpdateTimer; }; } From 304d7e544f80e05f992facf6d78d743649c25ba3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 4 Apr 2015 19:19:01 +0200 Subject: [PATCH 0884/3725] Optimize RigGeometry to update skinning in CullCallback --- components/nifosg/nifloader.cpp | 54 +++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 94885a11b..dd9dbc328 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -362,6 +362,56 @@ namespace } }; + struct FindNearestParentSkeleton : public osg::NodeVisitor + { + osg::ref_ptr _root; + FindNearestParentSkeleton() : osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_PARENTS) {} + void apply(osg::Transform& node) + { + if (_root.valid()) + return; + _root = dynamic_cast(&node); + traverse(node); + } + }; + + // RigGeometry is skinned from a CullCallback to prevent unnecessary updates of culled rig geometries. + // Note: this assumes only one cull thread is using the given RigGeometry, there would be a race condition otherwise. + struct UpdateRigGeometry : public osg::Drawable::CullCallback + { + virtual bool cull(osg::NodeVisitor *, osg::Drawable * drw, osg::State *) const + { + osgAnimation::RigGeometry* geom = static_cast(drw); + if (!geom) + return false; + if (!geom->getSkeleton() && !geom->getParents().empty()) + { + FindNearestParentSkeleton finder; + if (geom->getParents().size() > 1) + osg::notify(osg::WARN) << "A RigGeometry should not have multi parent ( " << geom->getName() << " )" << std::endl; + geom->getParents()[0]->accept(finder); + + if (!finder._root.valid()) + { + osg::notify(osg::WARN) << "A RigGeometry did not find a parent skeleton for RigGeometry ( " << geom->getName() << " )" << std::endl; + return false; + } + geom->buildVertexInfluenceSet(); + geom->setSkeleton(finder._root.get()); + } + + if (!geom->getSkeleton()) + return false; + + if (geom->getNeedToComputeMatrix()) + geom->computeMatrixFromRootSkeleton(); + + geom->update(); + + return false; + } + }; + class RigBoundingBoxCallback : public osg::Drawable::ComputeBoundingBoxCallback { public: @@ -1284,6 +1334,10 @@ namespace NifOsg } rig->setInfluenceMap(map); + // Override default update using cull callback instead for efficiency. + rig->setUpdateCallback(NULL); + rig->setCullCallback(new UpdateRigGeometry); + osg::ref_ptr trans(new osg::MatrixTransform); trans->setUpdateCallback(new InvertBoneMatrix()); From 3b408b64276ffdb1dcad81112d3c8fe17b0da710 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 4 Apr 2015 19:55:53 +0200 Subject: [PATCH 0885/3725] sorting out some Display enum mixup --- apps/opencs/model/world/columnbase.cpp | 5 ++--- apps/opencs/model/world/columnbase.hpp | 1 + apps/opencs/model/world/columnimp.hpp | 2 +- apps/opencs/model/world/refidcollection.cpp | 2 +- apps/opencs/model/world/resourcetable.cpp | 2 +- apps/opencs/view/world/scriptsubview.cpp | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/opencs/model/world/columnbase.cpp b/apps/opencs/model/world/columnbase.cpp index a736c0155..4f51fcad6 100644 --- a/apps/opencs/model/world/columnbase.cpp +++ b/apps/opencs/model/world/columnbase.cpp @@ -66,6 +66,7 @@ bool CSMWorld::ColumnBase::isId (Display display) Display_JournalInfo, Display_Scene, Display_GlobalVariable, + Display_Script, Display_Mesh, Display_Icon, @@ -74,8 +75,6 @@ bool CSMWorld::ColumnBase::isId (Display display) Display_Texture, Display_Video, - Display_Id, - Display_None }; @@ -93,5 +92,5 @@ bool CSMWorld::ColumnBase::isText (Display display) bool CSMWorld::ColumnBase::isScript (Display display) { - return display==Display_Script || display==Display_ScriptLines; + return display==Display_ScriptFile || display==Display_ScriptLines; } diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index 38039c27c..6f67898f6 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -101,6 +101,7 @@ namespace CSMWorld Display_Texture, Display_Video, Display_Colour, + Display_ScriptFile, Display_ScriptLines, // console context Display_SoundGeneratorType, Display_School, diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index 47b744b7f..e67fdd59c 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -818,7 +818,7 @@ namespace CSMWorld ScriptColumn (Type type) : Column (Columns::ColumnId_ScriptText, - type==Type_File ? ColumnBase::Display_Script : ColumnBase::Display_ScriptLines, + type==Type_File ? ColumnBase::Display_ScriptFile : ColumnBase::Display_ScriptLines, type==Type_File ? 0 : ColumnBase::Flag_Dialogue) {} diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 14a8890ad..6963c1331 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -40,7 +40,7 @@ CSMWorld::RefIdCollection::RefIdCollection() { BaseColumns baseColumns; - mColumns.push_back (RefIdColumn (Columns::ColumnId_Id, ColumnBase::Display_String, + mColumns.push_back (RefIdColumn (Columns::ColumnId_Id, ColumnBase::Display_Id, ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue, false, false)); baseColumns.mId = &mColumns.back(); mColumns.push_back (RefIdColumn (Columns::ColumnId_Modification, ColumnBase::Display_RecordState, diff --git a/apps/opencs/model/world/resourcetable.cpp b/apps/opencs/model/world/resourcetable.cpp index 36e2b3f3d..2cd44781a 100644 --- a/apps/opencs/model/world/resourcetable.cpp +++ b/apps/opencs/model/world/resourcetable.cpp @@ -60,7 +60,7 @@ QVariant CSMWorld::ResourceTable::headerData (int section, Qt::Orientation orien return Columns::getName (Columns::ColumnId_Id).c_str(); if (role==ColumnBase::Role_Display) - return ColumnBase::Display_String; + return ColumnBase::Display_Id; break; diff --git a/apps/opencs/view/world/scriptsubview.cpp b/apps/opencs/view/world/scriptsubview.cpp index 9b50a61f8..d0c3c2559 100644 --- a/apps/opencs/view/world/scriptsubview.cpp +++ b/apps/opencs/view/world/scriptsubview.cpp @@ -22,7 +22,7 @@ CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc: for (int i=0; icolumnCount(); ++i) if (mModel->headerData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Display)== - CSMWorld::ColumnBase::Display_Script) + CSMWorld::ColumnBase::Display_ScriptFile) { mColumn = i; break; From 1eafecd30c99c2a84e48139d5515a65265477114 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 5 Apr 2015 00:02:35 +0200 Subject: [PATCH 0886/3725] Add magic factor as in vanilla MW to gravity affector (Bug #2147) --- components/nifosg/particle.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/components/nifosg/particle.cpp b/components/nifosg/particle.cpp index c86a79af8..143a73e08 100644 --- a/components/nifosg/particle.cpp +++ b/components/nifosg/particle.cpp @@ -183,19 +183,22 @@ void GravityAffector::beginOperate(osgParticle::Program* program) void GravityAffector::operate(osgParticle::Particle *particle, double dt) { + const float magic = 1.6f; switch (mType) { case Type_Wind: - particle->addVelocity(mCachedWorldPositionDirection * mForce * dt); + particle->addVelocity(mCachedWorldPositionDirection * mForce * dt * magic); break; case Type_Point: { osg::Vec3f diff = mCachedWorldPositionDirection - particle->getPosition(); diff.normalize(); - particle->addVelocity(diff * mForce * dt); + particle->addVelocity(diff * mForce * dt * magic); break; } } + + // velocity *= e^-[(dist/decay)^2] } Emitter::Emitter() From c4738b11b1afcb4e9374bbeb8c191deb7e1b02bd Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 5 Apr 2015 00:09:05 +0200 Subject: [PATCH 0887/3725] Identify unknown float in NiGravity --- components/nif/controlled.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/components/nif/controlled.cpp b/components/nif/controlled.cpp index 9db0c4a6f..bf391d388 100644 --- a/components/nif/controlled.cpp +++ b/components/nif/controlled.cpp @@ -54,7 +54,10 @@ namespace Nif { Controlled::read(nif); - /*unknown*/nif->getFloat(); + float decay = nif->getFloat(); + if (decay != 0.f) + nif->file->warn("Unhandled gravity decay factor"); + mForce = nif->getFloat(); mType = nif->getUInt(); mPosition = nif->getVector3(); From fe69dc28637e0cc2e61f6bbcbaba5b5c82a1d912 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 5 Apr 2015 14:56:29 +1200 Subject: [PATCH 0888/3725] Made LineInfo a struct, as requested by Scrawl. --- apps/openmw/mwgui/spellview.cpp | 40 ++++++++++++++++++++------------- apps/openmw/mwgui/spellview.hpp | 22 +++++++++++++----- 2 files changed, 41 insertions(+), 21 deletions(-) diff --git a/apps/openmw/mwgui/spellview.cpp b/apps/openmw/mwgui/spellview.cpp index eeadc1d81..a7c1d781b 100644 --- a/apps/openmw/mwgui/spellview.cpp +++ b/apps/openmw/mwgui/spellview.cpp @@ -12,6 +12,14 @@ namespace MWGui const char* SpellView::sSpellModelIndex = "SpellModelIndex"; + SpellView::LineInfo::LineInfo(MyGUI::Widget* leftWidget, MyGUI::Widget* rightWidget, SpellModel::ModelIndex spellIndex) + : mLeftWidget(leftWidget) + , mRightWidget(rightWidget) + , mSpellIndex(spellIndex) + { + + } + SpellView::SpellView() : mShowCostColumn(true) , mHighlightSelected(true) @@ -115,10 +123,10 @@ namespace MWGui group.push_back(costChance); Gui::SharedStateButton::createButtonGroup(group); - mLines.push_back(boost::make_tuple(t, costChance, true)); + mLines.push_back(LineInfo(t, costChance, i)); } else - mLines.push_back(boost::make_tuple(t, (MyGUI::Widget*)NULL, true)); + mLines.push_back(LineInfo(t, (MyGUI::Widget*)NULL, i)); t->setStateSelected(spell.mSelected); } @@ -139,13 +147,13 @@ namespace MWGui for (std::vector< LineInfo >::iterator it = mLines.begin(); it != mLines.end(); ++it) { // only update the lines that are "updateable" - if (it->get<2>()) + SpellModel::ModelIndex spellIndex(it->mSpellIndex); + if (spellIndex != NoSpellIndex) { - Gui::SharedStateButton* nameButton = reinterpret_cast(it->get<0>()); + Gui::SharedStateButton* nameButton = reinterpret_cast(it->mLeftWidget); // match model against line // if don't match, then major change has happened, so do a full update - SpellModel::ModelIndex spellIndex = getSpellModelIndex(nameButton); if (mModel->getItemCount() <= static_cast(spellIndex)) { fullUpdateRequired = true; @@ -162,7 +170,7 @@ namespace MWGui else { maxSpellIndexFound = spellIndex; - Gui::SharedStateButton* costButton = reinterpret_cast(it->get<1>()); + Gui::SharedStateButton* costButton = reinterpret_cast(it->mRightWidget); if ((costButton != NULL) && (costButton->getCaption() != spell.mCostColumn)) { costButton->setCaption(spell.mCostColumn); @@ -187,7 +195,7 @@ namespace MWGui for (std::vector< LineInfo >::iterator it = mLines.begin(); it != mLines.end(); ++it) { - height += (it->get<0>())->getHeight(); + height += (it->mLeftWidget)->getHeight(); } bool scrollVisible = height > mScrollView->getHeight(); @@ -197,14 +205,14 @@ namespace MWGui for (std::vector< LineInfo >::iterator it = mLines.begin(); it != mLines.end(); ++it) { - int lineHeight = (it->get<0>())->getHeight(); - (it->get<0>())->setCoord(4, height, width - 8, lineHeight); - if (it->get<1>()) + int lineHeight = (it->mLeftWidget)->getHeight(); + (it->mLeftWidget)->setCoord(4, height, width - 8, lineHeight); + if (it->mRightWidget) { - (it->get<1>())->setCoord(4, height, width - 8, lineHeight); - MyGUI::TextBox* second = (it->get<1>())->castType(false); + (it->mRightWidget)->setCoord(4, height, width - 8, lineHeight); + MyGUI::TextBox* second = (it->mRightWidget)->castType(false); if (second) - (it->get<0>())->setSize(width - 8 - second->getTextSize().width, lineHeight); + (it->mLeftWidget)->setSize(width - 8 - second->getTextSize().width, lineHeight); } height += lineHeight; @@ -224,7 +232,7 @@ namespace MWGui MyGUI::IntCoord(0, 0, mScrollView->getWidth(), 18), MyGUI::Align::Left | MyGUI::Align::Top); separator->setNeedMouseFocus(false); - mLines.push_back(boost::make_tuple(separator, (MyGUI::Widget*)NULL, false)); + mLines.push_back(LineInfo(separator, (MyGUI::Widget*)NULL, NoSpellIndex)); } MyGUI::TextBox* groupWidget = mScrollView->createWidget("SandBrightText", @@ -243,10 +251,10 @@ namespace MWGui groupWidget2->setTextAlign(MyGUI::Align::Right); groupWidget2->setNeedMouseFocus(false); - mLines.push_back(boost::make_tuple(groupWidget, groupWidget2, false)); + mLines.push_back(LineInfo(groupWidget, groupWidget2, NoSpellIndex)); } else - mLines.push_back(boost::make_tuple(groupWidget, (MyGUI::Widget*)NULL, false)); + mLines.push_back(LineInfo(groupWidget, (MyGUI::Widget*)NULL, NoSpellIndex)); } diff --git a/apps/openmw/mwgui/spellview.hpp b/apps/openmw/mwgui/spellview.hpp index 2f6ff2624..7af1bda7a 100644 --- a/apps/openmw/mwgui/spellview.hpp +++ b/apps/openmw/mwgui/spellview.hpp @@ -56,11 +56,23 @@ namespace MWGui std::auto_ptr mModel; - /// tracks an item in the spell view - /// element<0> is the left column GUI object (usually holds the name) - /// element<1> is the right column (charge or cost info) - /// element<2> is if line needs to be checked during incremental update - typedef boost::tuple LineInfo; + /// tracks a row in the spell view + struct LineInfo + { + /// the widget on the left side of the row + MyGUI::Widget* mLeftWidget; + + /// the widget on the left side of the row (if there is one) + MyGUI::Widget* mRightWidget; + + /// index to item in mModel that row is showing information for + SpellModel::ModelIndex mSpellIndex; + + LineInfo(MyGUI::Widget* leftWidget, MyGUI::Widget* rightWidget, SpellModel::ModelIndex spellIndex); + }; + + /// magic number indicating LineInfo does not correspond to an item in mModel + enum { NoSpellIndex = -1 }; std::vector< LineInfo > mLines; From 74c56556cc474d205757b1f8111c19f6a80d299d Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 5 Apr 2015 14:10:05 +0200 Subject: [PATCH 0889/3725] More fixes for scaled particle systems --- components/nifosg/nifloader.cpp | 4 +--- components/nifosg/particle.cpp | 18 ++++++++---------- components/resource/scenemanager.cpp | 1 + 3 files changed, 10 insertions(+), 13 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index dd9dbc328..2a3d0322d 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -974,7 +974,7 @@ namespace NifOsg } else if (affectors->recType == Nif::RC_NiParticleRotation) { - // unused? + // unused } else std::cerr << "Unhandled particle modifier " << affectors->recName << std::endl; @@ -1064,8 +1064,6 @@ namespace NifOsg { osg::ref_ptr partsys (new ParticleSystem); partsys->setSortMode(osgParticle::ParticleSystem::SORT_BACK_TO_FRONT); - // Scaling the particle node should also scale particles, even when the worldspace flag is enabled - partsys->setParticleScaleReferenceFrame(osgParticle::ParticleSystem::LOCAL_COORDINATES); const Nif::NiParticleSystemController* partctrl = NULL; for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next) diff --git a/components/nifosg/particle.cpp b/components/nifosg/particle.cpp index 143a73e08..c4bf69579 100644 --- a/components/nifosg/particle.cpp +++ b/components/nifosg/particle.cpp @@ -50,8 +50,8 @@ void InverseWorldMatrix::operator()(osg::Node *node, osg::NodeVisitor *nv) osg::MatrixTransform* trans = dynamic_cast(node); osg::Matrix mat = osg::computeLocalToWorld( path ); - mat = osg::Matrix::inverse(mat); mat.orthoNormalize(mat); // don't undo the scale + mat = osg::Matrix::inverse(mat); trans->setMatrix(mat); } traverse(node,nv); @@ -239,6 +239,7 @@ void Emitter::setCounter(osgParticle::Counter *counter) void Emitter::emitParticles(double dt) { osg::Matrix worldToPs; + // maybe this could be optimized by halting at the lowest common ancestor of the particle and emitter nodes osg::MatrixList worldMats = getParticleSystem()->getWorldMatrices(); if (!worldMats.empty()) { @@ -246,14 +247,9 @@ void Emitter::emitParticles(double dt) worldToPs = osg::Matrix::inverse(psToWorld); } - worldToPs.orthoNormalize(worldToPs); - const osg::Matrix& ltw = getLocalToWorldMatrix(); - const osg::Matrix emitterToPs = ltw * worldToPs; - - int n = mCounter->numParticlesToCreate(dt); + osg::Matrix emitterToPs = ltw * worldToPs; - osg::Matrix transform; if (!mTargets.empty()) { int randomRecIndex = mTargets[(std::rand() / (static_cast(RAND_MAX)+1.0)) * mTargets.size()]; @@ -270,9 +266,13 @@ void Emitter::emitParticles(double dt) osg::NodePath path = visitor.mFoundPath; path.erase(path.begin()); - transform = osg::computeLocalToWorld(path); + emitterToPs = osg::computeLocalToWorld(path) * emitterToPs; } + emitterToPs.orthoNormalize(emitterToPs); + + int n = mCounter->numParticlesToCreate(dt); + for (int i=0; icreateParticle(0); @@ -282,8 +282,6 @@ void Emitter::emitParticles(double dt) mShooter->shoot(P); - P->transformPositionVelocity(transform); - P->transformPositionVelocity(emitterToPs); } } diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index e626a9f08..ead6a9669 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -51,6 +51,7 @@ namespace void transformInitialParticles(osgParticle::ParticleSystem* partsys, osg::Node* node) { osg::Matrix worldMat = node->getWorldMatrices()[0]; + worldMat.orthoNormalize(worldMat); // scale is already applied on the particle node for (int i=0; inumParticles(); ++i) { partsys->getParticle(i)->transformPositionVelocity(worldMat); From 0a5de33a1a6e7bd2ddd0848677e7f9827a2fe60b Mon Sep 17 00:00:00 2001 From: dteviot Date: Mon, 6 Apr 2015 15:13:09 +1200 Subject: [PATCH 0890/3725] fireEquipmentChangedEvent() updates the InventoryWindow. (Fixes #2424) --- apps/openmw/mwworld/inventorystore.cpp | 19 ++++++++++++++----- apps/openmw/mwworld/inventorystore.hpp | 2 +- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 4503e66f5..2de3abc75 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -10,6 +10,9 @@ #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/mechanicsmanager.hpp" +#include "../mwbase/windowmanager.hpp" + +#include "../mwgui/inventorywindow.hpp" #include "../mwmechanics/npcstats.hpp" #include "../mwmechanics/spellcasting.hpp" @@ -175,7 +178,7 @@ void MWWorld::InventoryStore::equip (int slot, const ContainerStoreIterator& ite flagAsModified(); - fireEquipmentChangedEvent(); + fireEquipmentChangedEvent(actor); updateMagicEffects(actor); } @@ -188,7 +191,7 @@ void MWWorld::InventoryStore::unequipAll(const MWWorld::Ptr& actor) mUpdatesEnabled = true; - fireEquipmentChangedEvent(); + fireEquipmentChangedEvent(actor); updateMagicEffects(actor); } @@ -318,7 +321,7 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor) if (changed) { mSlots.swap (slots_); - fireEquipmentChangedEvent(); + fireEquipmentChangedEvent(actor); updateMagicEffects(actor); flagAsModified(); } @@ -549,7 +552,7 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::unequipSlot(int slot, c } } - fireEquipmentChangedEvent(); + fireEquipmentChangedEvent(actor); updateMagicEffects(actor); return retval; @@ -576,12 +579,18 @@ void MWWorld::InventoryStore::setListener(InventoryStoreListener *listener, cons updateMagicEffects(actor); } -void MWWorld::InventoryStore::fireEquipmentChangedEvent() +void MWWorld::InventoryStore::fireEquipmentChangedEvent(const Ptr& actor) { if (!mUpdatesEnabled) return; if (mListener) mListener->equipmentChanged(); + + // if player, update inventory window + if (actor == MWBase::Environment::get().getWorld()->getPlayerPtr()) + { + MWBase::Environment::get().getWindowManager()->getInventoryWindow()->updateItemView(); + } } void MWWorld::InventoryStore::visitEffectSources(MWMechanics::EffectSourceVisitor &visitor) diff --git a/apps/openmw/mwworld/inventorystore.hpp b/apps/openmw/mwworld/inventorystore.hpp index 9a154373a..6b906207e 100644 --- a/apps/openmw/mwworld/inventorystore.hpp +++ b/apps/openmw/mwworld/inventorystore.hpp @@ -111,7 +111,7 @@ namespace MWWorld void updateMagicEffects(const Ptr& actor); void updateRechargingItems(); - void fireEquipmentChangedEvent(); + void fireEquipmentChangedEvent(const Ptr& actor); virtual void storeEquipmentState (const MWWorld::LiveCellRefBase& ref, int index, ESM::InventoryState& inventory) const; virtual void readEquipmentState (const MWWorld::ContainerStoreIterator& iter, int index, const ESM::InventoryState& inventory); From df9ea917dd3849d615f1a5a2eb268872a4a14041 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 8 Apr 2015 16:14:52 +0200 Subject: [PATCH 0891/3725] Delete some unused crap --- libs/openengine/misc/list.hpp | 178 ---------------------------------- 1 file changed, 178 deletions(-) delete mode 100644 libs/openengine/misc/list.hpp diff --git a/libs/openengine/misc/list.hpp b/libs/openengine/misc/list.hpp deleted file mode 100644 index bda9cb8de..000000000 --- a/libs/openengine/misc/list.hpp +++ /dev/null @@ -1,178 +0,0 @@ -#ifndef MISC_LIST_H -#define MISC_LIST_H - -#include - -namespace Misc{ - -/* - A simple and completely allocation-less doubly linked list. The - class only manages pointers to and between elements. It leaving all - memory management to the user. -*/ -template -struct List -{ - List() : head(0), tail(0), totalNum(0) {} - - // Empty the list. - void reset() - { - head = 0; - tail = 0; - totalNum = 0; - } - - // Insert an element at the end of the list. The element cannot be - // part of any other list when this is called. - void insert(Elem *p) - { - if(tail) - { - // There are existing elements. Insert the node at the end of - // the list. - assert(head && totalNum > 0); - tail->next = p; - } - else - { - // This is the first element - assert(head == 0 && totalNum == 0); - head = p; - } - - // These have to be done in either case - p->prev = tail; - p->next = 0; - tail = p; - - totalNum++; - } - - // Remove element from the list. The element MUST be part of the - // list when this is called. - void remove(Elem *p) - { - assert(totalNum > 0); - - if(p->next) - { - // There's an element following us. Set it up correctly. - p->next->prev = p->prev; - assert(tail && tail != p); - } - else - { - // We're the tail - assert(tail == p); - tail = p->prev; - } - - // Now do exactly the same for the previous element - if(p->prev) - { - p->prev->next = p->next; - assert(head && head != p); - } - else - { - assert(head == p); - head = p->next; - } - - totalNum--; - } - - // Pop the first element off the list - Elem *pop() - { - Elem *res = getHead(); - if(res) remove(res); - return res; - } - - // Swap the contents of this list with another of the same type - void swap(List &other) - { - Elem *tmp; - - tmp = head; - head = other.head; - other.head = tmp; - - tmp = tail; - tail = other.tail; - other.tail = tmp; - - unsigned int tmp2 = totalNum; - totalNum = other.totalNum; - other.totalNum = tmp2; - } - - /* Absorb the contents of another list. All the elements from the - list are moved to the end of this list, and the other list is - cleared. - */ - void absorb(List &other) - { - assert(&other != this); - if(other.totalNum) - { - absorb(other.head, other.tail, other.totalNum); - other.reset(); - } - assert(other.totalNum == 0); - } - - /* Absorb a range of elements, endpoints included. The elements are - assumed NOT to belong to any list, but they ARE assumed to be - connected with a chain between them. - - The connection MUST run all the way from 'first' to 'last' - through the ->next pointers, and vice versa through ->prev - pointers. - - The parameter 'num' must give the exact number of elements in the - chain. - - Passing first == last, num == 1 is allowed and is equivalent to - calling insert(). - */ - void absorb(Elem* first, Elem *last, int num) - { - assert(first && last && num>=1); - if(tail) - { - // There are existing elements. Insert the first node at the - // end of the list. - assert(head && totalNum > 0); - tail->next = first; - } - else - { - // This is the first element - assert(head == 0 && totalNum == 0); - head = first; - } - - // These have to be done in either case - first->prev = tail; - last->next = 0; - tail = last; - - totalNum += num; - } - - Elem* getHead() const { return head; } - Elem* getTail() const { return tail; } - unsigned int getNum() const { return totalNum; } - -private: - - Elem *head; - Elem *tail; - unsigned int totalNum; -}; - -} -#endif From bdf0d8db22c2a766e1774b2649b1e91cc69da24b Mon Sep 17 00:00:00 2001 From: cc9cii Date: Thu, 9 Apr 2015 19:11:19 +1000 Subject: [PATCH 0892/3725] Re-organise the inheritance structure once more in preparation for adding Pathgrid tables. --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/world/collection.hpp | 11 ++ apps/opencs/model/world/columnbase.cpp | 33 ++++ apps/opencs/model/world/columnbase.hpp | 24 ++- apps/opencs/model/world/data.cpp | 2 +- apps/opencs/model/world/idtable.cpp | 10 ++ apps/opencs/model/world/idtable.hpp | 4 + apps/opencs/model/world/idtree.cpp | 156 ++++++------------- apps/opencs/model/world/idtree.hpp | 13 +- apps/opencs/model/world/nestablecolumn.cpp | 44 ------ apps/opencs/model/world/nestablecolumn.hpp | 33 ---- apps/opencs/model/world/nestedcollection.cpp | 12 +- apps/opencs/model/world/nestedcollection.hpp | 26 ++-- apps/opencs/model/world/refidcollection.cpp | 8 +- apps/opencs/model/world/refidcollection.hpp | 11 +- 15 files changed, 165 insertions(+), 224 deletions(-) delete mode 100644 apps/opencs/model/world/nestablecolumn.cpp delete mode 100644 apps/opencs/model/world/nestablecolumn.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 39b4c486b..8cf37da1d 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -25,7 +25,7 @@ opencs_units (model/world opencs_units_noqt (model/world universalid record commands columnbase scriptcontext cell refidcollection refidadapter refiddata refidadapterimp ref collectionbase refcollection columns infocollection tablemimedata cellcoordinates cellselection resources resourcesmanager scope - pathgrid landtexture land nestedtablewrapper nestedadapters nestedcollection nestablecolumn + pathgrid landtexture land nestedtablewrapper nestedadapters nestedcollection ) opencs_hdrs_noqt (model/world diff --git a/apps/opencs/model/world/collection.hpp b/apps/opencs/model/world/collection.hpp index 1fb3e1f1d..dc52ae663 100644 --- a/apps/opencs/model/world/collection.hpp +++ b/apps/opencs/model/world/collection.hpp @@ -148,6 +148,8 @@ namespace CSMWorld void setRecord (int index, const Record& record); ///< \attention This function must not change the ID. + + NestableColumn *getNestableColumn (int column); }; template @@ -289,6 +291,15 @@ namespace CSMWorld return *mColumns.at (column); } + template + NestableColumn *Collection::getNestableColumn (int column) + { + if (column < 0 || column >= static_cast(mColumns.size())) + throw std::runtime_error("column index out of range"); + + return mColumns.at (column); + } + template void Collection::addColumn (Column *column) { diff --git a/apps/opencs/model/world/columnbase.cpp b/apps/opencs/model/world/columnbase.cpp index 665ab9354..94c5afb83 100644 --- a/apps/opencs/model/world/columnbase.cpp +++ b/apps/opencs/model/world/columnbase.cpp @@ -23,3 +23,36 @@ int CSMWorld::ColumnBase::getId() const { return mColumnId; } + +void CSMWorld::NestableColumn::addColumn(CSMWorld::NestableColumn *column) +{ + mNestedColumns.push_back(column); + mHasChildren = true; +} + +const CSMWorld::ColumnBase& CSMWorld::NestableColumn::nestedColumn(int subColumn) const +{ + if (!mHasChildren) + throw std::logic_error("Tried to access nested column of the non-nest column"); + + return *mNestedColumns.at(subColumn); +} + +CSMWorld::NestableColumn::NestableColumn(int columnId, CSMWorld::ColumnBase::Display displayType, + int flag) + : mHasChildren(false), CSMWorld::ColumnBase(columnId, displayType, flag) +{ +} + +CSMWorld::NestableColumn::~NestableColumn() +{ + for (unsigned int i = 0; i < mNestedColumns.size(); ++i) + { + delete mNestedColumns[i]; + } +} + +bool CSMWorld::NestableColumn::hasChildren() const +{ + return mHasChildren; +} diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index b717f3a52..da1d8f0df 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -129,14 +129,32 @@ namespace CSMWorld virtual std::string getTitle() const; - virtual int getId() const; + virtual int getId() const; // FIXME: why have an accessor for a public member? + }; + + class NestableColumn : public ColumnBase + { + std::vector mNestedColumns; + bool mHasChildren; + + public: + + NestableColumn(int columnId, Display displayType, int flag); + + ~NestableColumn(); + + void addColumn(CSMWorld::NestableColumn *column); + + const ColumnBase& nestedColumn(int subColumn) const; + + bool hasChildren() const; }; template - struct Column : public ColumnBase + struct Column : public NestableColumn { Column (int columnId, Display displayType, int flags = Flag_Table | Flag_Dialogue) - : ColumnBase (columnId, displayType, flags) {} + : NestableColumn (columnId, displayType, flags) {} virtual QVariant get (const Record& record) const = 0; diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index a5ef439a7..0cfc890ea 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -333,7 +333,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc addModel (new IdTable (&mMagicEffects), UniversalId::Type_MagicEffect); addModel (new IdTable (&mPathgrids), UniversalId::Type_Pathgrid); addModel (new IdTable (&mStartScripts), UniversalId::Type_StartScript); - addModel (new IdTree (&mReferenceables, IdTable::Feature_Preview), + addModel (new IdTree (&mReferenceables, &mReferenceables, IdTable::Feature_Preview), UniversalId::Type_Referenceable); addModel (new IdTable (&mRefs, IdTable::Feature_ViewCell | IdTable::Feature_Preview), UniversalId::Type_Reference); addModel (new IdTable (&mFilters), UniversalId::Type_Filter); diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 7618a073a..28742c8f2 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -1,5 +1,7 @@ #include "idtable.hpp" +#include + #include "collectionbase.hpp" #include "columnbase.hpp" @@ -42,6 +44,9 @@ QVariant CSMWorld::IdTable::headerData (int section, Qt::Orientation orientation if (orientation==Qt::Vertical) return QVariant(); + if (orientation != Qt::Horizontal) + throw std::logic_error("Unknown header orientation specified"); + if (role==Qt::DisplayRole) return tr (mIdCollection->getColumn (section).getTitle().c_str()); @@ -231,3 +236,8 @@ int CSMWorld::IdTable::getColumnId(int column) const { return mIdCollection->getColumn(column).getId(); } + +CSMWorld::CollectionBase *CSMWorld::IdTable::idCollection() const +{ + return mIdCollection; +} diff --git a/apps/opencs/model/world/idtable.hpp b/apps/opencs/model/world/idtable.hpp index ea8ab80f9..914b01cf9 100644 --- a/apps/opencs/model/world/idtable.hpp +++ b/apps/opencs/model/world/idtable.hpp @@ -83,6 +83,10 @@ namespace CSMWorld virtual bool isDeleted (const std::string& id) const; int getColumnId(int column) const; + + protected: + + virtual CollectionBase *idCollection() const; }; } diff --git a/apps/opencs/model/world/idtree.cpp b/apps/opencs/model/world/idtree.cpp index 595b0ac51..4befd1eee 100644 --- a/apps/opencs/model/world/idtree.cpp +++ b/apps/opencs/model/world/idtree.cpp @@ -1,34 +1,33 @@ #include "idtree.hpp" -#include "nestedtablewrapper.hpp" // FIXME: is this necessary? +#include "nestedtablewrapper.hpp" +#include "collectionbase.hpp" #include "nestedcollection.hpp" -#include "nestablecolumn.hpp" +#include "columnbase.hpp" -CSMWorld::IdTree::IdTree (NestedCollection *idCollection, unsigned int features) -: IdTable (idCollection, features), mIdCollection (idCollection) +// NOTE: parent class still needs idCollection +CSMWorld::IdTree::IdTree (NestedCollection *nestedCollection, CollectionBase *idCollection, unsigned int features) +: IdTable (idCollection, features), mNestedCollection (nestedCollection) {} CSMWorld::IdTree::~IdTree() -{ - // FIXME: workaround only, a proper fix should stop QHideEvent calls after destruction - mIdCollection = 0; -} +{} int CSMWorld::IdTree::rowCount (const QModelIndex & parent) const { if (hasChildren(parent)) - return mIdCollection->getNestedRowsCount(parent.row(), parent.column()); + return mNestedCollection->getNestedRowsCount(parent.row(), parent.column()); - return mIdCollection->getSize(); + return IdTable::rowCount(parent); } int CSMWorld::IdTree::columnCount (const QModelIndex & parent) const { if (hasChildren(parent)) - return mIdCollection->getNestedColumnsCount(parent.row(), parent.column()); + return mNestedCollection->getNestedColumnsCount(parent.row(), parent.column()); - return mIdCollection->getColumns(); + return IdTable::columnCount(parent); } QVariant CSMWorld::IdTree::data (const QModelIndex & index, int role) const @@ -39,60 +38,39 @@ QVariant CSMWorld::IdTree::data (const QModelIndex & index, int role) const if ((role!=Qt::DisplayRole && role!=Qt::EditRole) || index.row() < 0 || index.column() < 0) return QVariant(); - if (role==Qt::EditRole && !mIdCollection->getColumn (index.column()).isEditable()) + if (role==Qt::EditRole && !idCollection()->getColumn (index.column()).isEditable()) return QVariant(); if (index.internalId() != 0) { std::pair parentAdress(unfoldIndexAdress(index.internalId())); - return mIdCollection->getNestedData(parentAdress.first, + return mNestedCollection->getNestedData(parentAdress.first, parentAdress.second, index.row(), index.column()); } else - return mIdCollection->getData (index.row(), index.column()); -} - -QVariant CSMWorld::IdTree::headerData (int section, Qt::Orientation orientation, int role) const -{ - if (orientation==Qt::Vertical) - return QVariant(); - - if (orientation != Qt::Horizontal) - throw std::logic_error("Unknown header orientation specified"); - - if (role == Qt::DisplayRole) - return tr (mIdCollection->getColumn (section).getTitle().c_str()); - - if (role == ColumnBase::Role_Flags) - return mIdCollection->getColumn (section).mFlags; - - if (role == ColumnBase::Role_Display) - return mIdCollection->getColumn (section).mDisplayType; - - return QVariant(); + return idCollection()->getData (index.row(), index.column()); } QVariant CSMWorld::IdTree::nestedHeaderData(int section, int subSection, Qt::Orientation orientation, int role) const { // FIXME: workaround only, a proper fix should stop QHideEvent calls after destruction - if (section < 0 || !mIdCollection || section >= mIdCollection->getColumns()) + if (section < 0 || !idCollection() || section >= idCollection()->getColumns()) return QVariant(); - // FIXME: dynamic cast - const NestableColumn& parentColumn = dynamic_cast(mIdCollection->getColumn(section)); + const NestableColumn *parentColumn = mNestedCollection->getNestableColumn(section); if (orientation==Qt::Vertical) return QVariant(); if (role==Qt::DisplayRole) - return tr(parentColumn.nestedColumn(subSection).getTitle().c_str()); + return tr(parentColumn->nestedColumn(subSection).getTitle().c_str()); if (role==ColumnBase::Role_Flags) - return mIdCollection->getColumn (section).mFlags; + return idCollection()->getColumn (section).mFlags; if (role==ColumnBase::Role_Display) - return parentColumn.nestedColumn(subSection).mDisplayType; + return parentColumn->nestedColumn(subSection).mDisplayType; return QVariant(); } @@ -101,32 +79,21 @@ bool CSMWorld::IdTree::setData (const QModelIndex &index, const QVariant &value, { if (index.internalId() != 0) { - if (mIdCollection->getColumn(parent(index).column()).isEditable() && role==Qt::EditRole) + if (idCollection()->getColumn(parent(index).column()).isEditable() && role==Qt::EditRole) { const std::pair& parentAdress(unfoldIndexAdress(index.internalId())); - mIdCollection->setNestedData(parentAdress.first, parentAdress.second, value, index.row(), index.column()); + mNestedCollection->setNestedData(parentAdress.first, parentAdress.second, value, index.row(), index.column()); emit dataChanged (CSMWorld::IdTree::index (parentAdress.first, 0), - CSMWorld::IdTree::index (parentAdress.second, mIdCollection->getColumns()-1)); + CSMWorld::IdTree::index (parentAdress.second, idCollection()->getColumns()-1)); return true; } else return false; } - - if (mIdCollection->getColumn (index.column()).isEditable() && role==Qt::EditRole) - { - mIdCollection->setData (index.row(), index.column(), value); - - emit dataChanged (CSMWorld::IdTree::index (index.row(), 0), - CSMWorld::IdTree::index (index.row(), mIdCollection->getColumns()-1)); - - return true; - } - - return false; + return IdTable::setData(index, value, role); } Qt::ItemFlags CSMWorld::IdTree::flags (const QModelIndex & index) const @@ -134,39 +101,29 @@ Qt::ItemFlags CSMWorld::IdTree::flags (const QModelIndex & index) const if (!index.isValid()) return 0; - Qt::ItemFlags flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled; - - if (mIdCollection->getColumn (index.column()).isUserEditable()) - flags |= Qt::ItemIsEditable; - - return flags; + return IdTable::flags(index); } bool CSMWorld::IdTree::removeRows (int row, int count, const QModelIndex& parent) { - beginRemoveRows (parent, row, row+count-1); - if (parent.isValid()) { + beginRemoveRows (parent, row, row+count-1); + for (int i = 0; i < count; ++i) { - mIdCollection->removeNestedRows(parent.row(), parent.column(), row+i); + mNestedCollection->removeNestedRows(parent.row(), parent.column(), row+i); } - } - else - { - - beginRemoveRows (parent, row, row+count-1); - - mIdCollection->removeRows (row, count); - } - endRemoveRows(); + endRemoveRows(); - emit dataChanged (CSMWorld::IdTree::index (parent.row(), 0), - CSMWorld::IdTree::index (parent.row(), mIdCollection->getColumns()-1)); + emit dataChanged (CSMWorld::IdTree::index (parent.row(), 0), + CSMWorld::IdTree::index (parent.row(), idCollection()->getColumns()-1)); - return true; + return true; + } + else + return IdTable::removeRows(row, count, parent); } void CSMWorld::IdTree::addNestedRow(const QModelIndex& parent, int position) @@ -177,11 +134,11 @@ void CSMWorld::IdTree::addNestedRow(const QModelIndex& parent, int position) int row = parent.row(); beginInsertRows(parent, position, position); - mIdCollection->addNestedRow(row, parent.column(), position); + mNestedCollection->addNestedRow(row, parent.column(), position); endInsertRows(); emit dataChanged (CSMWorld::IdTree::index (row, 0), - CSMWorld::IdTree::index (row, mIdCollection->getColumns()-1)); + CSMWorld::IdTree::index (row, idCollection()->getColumns()-1)); } QModelIndex CSMWorld::IdTree::index (int row, int column, const QModelIndex& parent) const @@ -192,10 +149,10 @@ QModelIndex CSMWorld::IdTree::index (int row, int column, const QModelIndex& par encodedId = this->foldIndexAdress(parent); } - if (row<0 || row>=mIdCollection->getSize()) + if (row<0 || row>=idCollection()->getSize()) return QModelIndex(); - if (column<0 || column>=mIdCollection->getColumns()) + if (column<0 || column>=idCollection()->getColumns()) return QModelIndex(); return createIndex(row, column, encodedId); // store internal id @@ -215,28 +172,6 @@ QModelIndex CSMWorld::IdTree::parent (const QModelIndex& index) const return createIndex(adress.first, adress.second); } -void CSMWorld::IdTree::setRecord (const std::string& id, const RecordBase& record) -{ - int index = mIdCollection->searchId (id); - - if (index==-1) - { - int index = mIdCollection->getAppendIndex (id); - - beginInsertRows (QModelIndex(), index, index); - - mIdCollection->appendRecord (record); - - endInsertRows(); - } - else - { - mIdCollection->replace (index, record); - emit dataChanged (CSMWorld::IdTree::index (index, 0), - CSMWorld::IdTree::index (index, mIdCollection->getColumns()-1)); - } -} - unsigned int CSMWorld::IdTree::foldIndexAdress (const QModelIndex& index) const { unsigned int out = index.row() * this->columnCount(); @@ -255,13 +190,16 @@ std::pair< int, int > CSMWorld::IdTree::unfoldIndexAdress (unsigned int id) cons return std::make_pair (row, column); } +// index.data().isValid() requires RefIdAdapter::getData() to return a valid QVariant for +// nested columns (refidadapterimp.hpp) +// +// Also see comments in refidadapter.hpp and refidadapterimp.hpp. bool CSMWorld::IdTree::hasChildren(const QModelIndex& index) const { - // FIXME: dynamic cast return (index.isValid() && index.internalId() == 0 && - dynamic_cast(mIdCollection->getColumn(index.column())).hasChildren() && - index.data().isValid()); + mNestedCollection->getNestableColumn(index.column())->hasChildren() && + index.data().isValid()); // FIXME: not sure why this check is also needed } void CSMWorld::IdTree::setNestedTable(const QModelIndex& index, const CSMWorld::NestedTableWrapperBase& nestedTable) @@ -276,10 +214,10 @@ void CSMWorld::IdTree::setNestedTable(const QModelIndex& index, const CSMWorld:: removeRowsMode = true; } - mIdCollection->setNestedTable(index.row(), index.column(), nestedTable); + mNestedCollection->setNestedTable(index.row(), index.column(), nestedTable); emit dataChanged (CSMWorld::IdTree::index (index.row(), 0), - CSMWorld::IdTree::index (index.row(), mIdCollection->getColumns()-1)); + CSMWorld::IdTree::index (index.row(), idCollection()->getColumns()-1)); if (removeRowsMode) { @@ -292,5 +230,5 @@ CSMWorld::NestedTableWrapperBase* CSMWorld::IdTree::nestedTable(const QModelInde if (!hasChildren(index)) throw std::logic_error("Tried to retrive nested table, but index has no children"); - return mIdCollection->nestedTable(index.row(), index.column()); + return mNestedCollection->nestedTable(index.row(), index.column()); } diff --git a/apps/opencs/model/world/idtree.hpp b/apps/opencs/model/world/idtree.hpp index 6a3d7423c..80b44d241 100644 --- a/apps/opencs/model/world/idtree.hpp +++ b/apps/opencs/model/world/idtree.hpp @@ -22,13 +22,13 @@ namespace CSMWorld struct RecordBase; class NestedTableWrapperBase; // FIXME: is this necessary? - class IdTree : public IdTable // IdTable is derived from QAbstractItemModel + class IdTree : public IdTable { Q_OBJECT private: - NestedCollection *mIdCollection; + NestedCollection *mNestedCollection; // not implemented IdTree (const IdTree&); @@ -39,8 +39,8 @@ namespace CSMWorld public: - IdTree (NestedCollection *idCollection, unsigned int features = 0); - ///< The ownership of \a idCollection is not transferred. + IdTree (NestedCollection *nestedCollection, CollectionBase *idCollection, unsigned int features = 0); + ///< The ownerships of \a nestedCollecton and \a idCollection are not transferred. virtual ~IdTree(); @@ -50,8 +50,6 @@ namespace CSMWorld virtual QVariant data (const QModelIndex & index, int role = Qt::DisplayRole) const; - virtual QVariant headerData (int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; - virtual bool setData ( const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); virtual Qt::ItemFlags flags (const QModelIndex & index) const; @@ -63,9 +61,6 @@ namespace CSMWorld virtual QModelIndex parent (const QModelIndex& index) const; - void setRecord (const std::string& id, const RecordBase& record); - ///< Add record or overwrite existing recrod. - // TODO: check if below methods are really needed QVariant nestedHeaderData(int section, int subSection, Qt::Orientation orientation, int role = Qt::DisplayRole) const; diff --git a/apps/opencs/model/world/nestablecolumn.cpp b/apps/opencs/model/world/nestablecolumn.cpp deleted file mode 100644 index 4ade75b33..000000000 --- a/apps/opencs/model/world/nestablecolumn.cpp +++ /dev/null @@ -1,44 +0,0 @@ -#include "nestablecolumn.hpp" - -#include - -void CSMWorld::NestableColumn::addColumn(CSMWorld::NestableColumn *column) -{ - mNestedColumns.push_back(column); - mHasChildren = true; -} - -const CSMWorld::ColumnBase& CSMWorld::NestableColumn::nestedColumn(int subColumn) const -{ - if (!mHasChildren) - throw std::logic_error("Tried to access nested column of the non-nest column"); - - return *mNestedColumns.at(subColumn); -} - -int CSMWorld::NestableColumn::nestedColumnCount() const -{ - if (!mHasChildren) - throw std::logic_error("Tried to access number of the subcolumns in the non-nest column"); - - return mNestedColumns.size(); -} - -CSMWorld::NestableColumn::NestableColumn(int columnId, CSMWorld::ColumnBase::Display displayType, - int flag, const CSMWorld::NestableColumn* parent) - : mParent(parent), mHasChildren(false), CSMWorld::ColumnBase(columnId, displayType, flag) -{ -} - -CSMWorld::NestableColumn::~NestableColumn() -{ - for (unsigned int i = 0; i < mNestedColumns.size(); ++i) - { - delete mNestedColumns[i]; - } -} - -bool CSMWorld::NestableColumn::hasChildren() const -{ - return mHasChildren; -} diff --git a/apps/opencs/model/world/nestablecolumn.hpp b/apps/opencs/model/world/nestablecolumn.hpp deleted file mode 100644 index 28ced85e9..000000000 --- a/apps/opencs/model/world/nestablecolumn.hpp +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef CSM_WOLRD_NESTABLECOLUMN_H -#define CSM_WOLRD_NESTABLECOLUMN_H - -#include - -#include "columnbase.hpp" - -namespace CSMWorld -{ - class NestableColumn : public ColumnBase - { - std::vector mNestedColumns; - const NestableColumn* mParent; - bool mHasChildren; // cached - - public: - - NestableColumn(int columnId, - Display displayType, int flag, const NestableColumn* parent = 0); - - ~NestableColumn(); - - void addColumn(CSMWorld::NestableColumn *column); - - const ColumnBase& nestedColumn(int subColumn) const; - - int nestedColumnCount() const; - - bool hasChildren() const; - }; -} - -#endif diff --git a/apps/opencs/model/world/nestedcollection.cpp b/apps/opencs/model/world/nestedcollection.cpp index f557c3ba1..937ad6ad6 100644 --- a/apps/opencs/model/world/nestedcollection.cpp +++ b/apps/opencs/model/world/nestedcollection.cpp @@ -1,7 +1,17 @@ #include "nestedcollection.hpp" -CSMWorld::NestedCollection::NestedCollection() : mParent(0) +CSMWorld::NestedCollection::NestedCollection() {} CSMWorld::NestedCollection::~NestedCollection() {} + +int CSMWorld::NestedCollection::getNestedRowsCount(int row, int column) const +{ + return 0; +} + +int CSMWorld::NestedCollection::getNestedColumnsCount(int row, int column) const +{ + return 0; +} diff --git a/apps/opencs/model/world/nestedcollection.hpp b/apps/opencs/model/world/nestedcollection.hpp index 5ec50b423..8046f9a09 100644 --- a/apps/opencs/model/world/nestedcollection.hpp +++ b/apps/opencs/model/world/nestedcollection.hpp @@ -1,17 +1,14 @@ #ifndef CSM_WOLRD_NESTEDCOLLECTION_H #define CSM_WOLRD_NESTEDCOLLECTION_H -#include - -#include "collectionbase.hpp" - class QVariant; namespace CSMWorld { + class NestableColumn; class NestedTableWrapperBase; - class NestedCollection : public CollectionBase + class NestedCollection { public: @@ -21,25 +18,22 @@ namespace CSMWorld virtual void addNestedRow(int row, int col, int position) = 0; - virtual QVariant getNestedData(int row, int column, int subRow, int subColumn) const = 0; - - virtual NestedTableWrapperBase* nestedTable(int row, int column) const = 0; + virtual void removeNestedRows(int row, int column, int subRow) = 0; - virtual void setNestedTable(int row, int column, const NestedTableWrapperBase& nestedTable) = 0; + virtual QVariant getNestedData(int row, int column, int subRow, int subColumn) const = 0; virtual void setNestedData(int row, int column, const QVariant& data, int subRow, int subColumn) = 0; - virtual int getNestedRowsCount(int row, int column) const = 0; + virtual NestedTableWrapperBase* nestedTable(int row, int column) const = 0; - virtual int getNestedColumnsCount(int row, int column) const = 0; + virtual void setNestedTable(int row, int column, const NestedTableWrapperBase& nestedTable) = 0; - virtual void removeNestedRows(int row, int column, int subRow) = 0; + virtual int getNestedRowsCount(int row, int column) const; - private: + virtual int getNestedColumnsCount(int row, int column) const; - std::vector mChildren; - NestedCollection *mParent; // currently unused + virtual NestableColumn *getNestableColumn(int column) = 0; }; } -#endif +#endif // CSM_WOLRD_NESTEDCOLLECTION_H diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index ca5efcdd9..41ca7e440 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -8,7 +8,7 @@ #include "refidadapter.hpp" #include "refidadapterimp.hpp" #include "columns.hpp" -#include "nestedtablewrapper.hpp" // FIXME: is this really necessary? +#include "nestedtablewrapper.hpp" CSMWorld::RefIdColumn::RefIdColumn (int columnId, Display displayType, int flag, bool editable, bool userEditable) @@ -25,7 +25,6 @@ bool CSMWorld::RefIdColumn::isUserEditable() const return mUserEditable; } - // FIXME: const problem /*const*/ CSMWorld::RefIdAdapter& CSMWorld::RefIdCollection::findAdapter (UniversalId::Type type) const { @@ -667,6 +666,11 @@ int CSMWorld::RefIdCollection::getNestedColumnsCount(int row, int column) const return adaptor.getNestedColumnsCount(&mColumns.at(column), mData); } +CSMWorld::NestableColumn *CSMWorld::RefIdCollection::getNestableColumn(int column) +{ + return &mColumns.at(column); +} + void CSMWorld::RefIdCollection::addNestedRow(int row, int col, int position) { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); diff --git a/apps/opencs/model/world/refidcollection.hpp b/apps/opencs/model/world/refidcollection.hpp index dd432c5a9..2a271a846 100644 --- a/apps/opencs/model/world/refidcollection.hpp +++ b/apps/opencs/model/world/refidcollection.hpp @@ -5,7 +5,8 @@ #include #include -#include "nestablecolumn.hpp" +#include "columnbase.hpp" +#include "collectionbase.hpp" #include "nestedcollection.hpp" #include "refiddata.hpp" @@ -17,7 +18,7 @@ namespace ESM namespace CSMWorld { class RefIdAdapter; - class NestedTableWrapperBase; // FIXME: is this really needed? + class NestedTableWrapperBase; class RefIdColumn : public NestableColumn { @@ -35,7 +36,7 @@ namespace CSMWorld virtual bool isUserEditable() const; }; - class RefIdCollection : public NestedCollection + class RefIdCollection : public CollectionBase, public NestedCollection { private: @@ -117,12 +118,12 @@ namespace CSMWorld virtual void setNestedTable(int row, int column, const NestedTableWrapperBase& nestedTable); - // FIXME virtual int getNestedRowsCount(int row, int column) const; - // FIXME virtual int getNestedColumnsCount(int row, int column) const; + NestableColumn *getNestableColumn(int column); + virtual void setNestedData(int row, int column, const QVariant& data, int subRow, int subColumn); virtual void removeNestedRows(int row, int column, int subRow); From 05210d7f2133387cdd8b581c1ea30dba3b15449a Mon Sep 17 00:00:00 2001 From: cc9cii Date: Thu, 9 Apr 2015 19:29:03 +1000 Subject: [PATCH 0893/3725] Nested table support for Pathgrids. --- apps/opencs/model/world/collection.hpp | 8 + apps/opencs/model/world/columnbase.cpp | 1 - apps/opencs/model/world/columnbase.hpp | 2 + apps/opencs/model/world/columnimp.hpp | 99 ++++++++- apps/opencs/model/world/columns.cpp | 8 + apps/opencs/model/world/columns.hpp | 9 + apps/opencs/model/world/data.cpp | 19 +- apps/opencs/model/world/idadapter.hpp | 39 ++++ apps/opencs/model/world/idadapterimp.hpp | 202 ++++++++++++++++++ apps/opencs/model/world/subcellcollection.hpp | 122 ++++++++++- 10 files changed, 503 insertions(+), 6 deletions(-) create mode 100644 apps/opencs/model/world/idadapter.hpp create mode 100644 apps/opencs/model/world/idadapterimp.hpp diff --git a/apps/opencs/model/world/collection.hpp b/apps/opencs/model/world/collection.hpp index dc52ae663..4bc9632a8 100644 --- a/apps/opencs/model/world/collection.hpp +++ b/apps/opencs/model/world/collection.hpp @@ -120,6 +120,8 @@ namespace CSMWorld virtual const Record& getRecord (int index) const; + virtual Record& getRecord (int index); + virtual int getAppendIndex (const std::string& id, UniversalId::Type type = UniversalId::Type_None) const; ///< \param type Will be ignored, unless the collection supports multiple record types @@ -433,6 +435,12 @@ namespace CSMWorld return mRecords.at (index); } + template + Record& Collection::getRecord (int index) + { + return mRecords.at (index); + } + template void Collection::insertRecord (const RecordBase& record, int index, UniversalId::Type type) diff --git a/apps/opencs/model/world/columnbase.cpp b/apps/opencs/model/world/columnbase.cpp index 94c5afb83..e4d2195be 100644 --- a/apps/opencs/model/world/columnbase.cpp +++ b/apps/opencs/model/world/columnbase.cpp @@ -1,4 +1,3 @@ - #include "columnbase.hpp" #include "columns.hpp" diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index da1d8f0df..aef68fdbd 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -97,6 +97,8 @@ namespace CSMWorld Display_NestedItemList, Display_NestedSpellList, Display_NestedDestinationsList, + Display_PathgridPointList, + Display_PathgridEdgeList, Display_EnchantmentType, Display_BodyPartType, diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index da14bb495..27fc3ad04 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -1277,7 +1277,6 @@ namespace CSMWorld } }; - template struct PosColumn : public Column { @@ -2265,6 +2264,104 @@ namespace CSMWorld return true; } }; + + template + struct PathgridPointListColumn : public Column + { + PathgridPointListColumn () + : Column (Columns::ColumnId_PathgridPoints, + ColumnBase::Display_PathgridPointList, ColumnBase::Flag_Dialogue) + { + } + + virtual QVariant get (const Record& record) const + { + return true; // required by IdTree::hasChildren() + } + + virtual void set (Record& record, const QVariant& data) + { + } + + virtual bool isEditable() const + { + return true; + } + }; + + template + struct PathgridPointColumn : public Column + { + int mIndex; // 0=PosX, 1=PosY, 2=PosZ + + PathgridPointColumn(int index) + : Column (Columns::ColumnId_PathgridPosX+index, ColumnBase::Display_Integer), mIndex(index) + {} + + virtual QVariant get (const Record& record) const + { + return QVariant(); // FIXME + } + + virtual void set (Record& record, const QVariant& data) + { + } + + virtual bool isEditable() const + { + return true; + } + }; + + template + struct PathgridEdgeListColumn : public Column + { + PathgridEdgeListColumn () + : Column (Columns::ColumnId_PathgridEdges, + ColumnBase::Display_PathgridEdgeList, ColumnBase::Flag_Dialogue) + { + } + + virtual QVariant get (const Record& record) const + { + return true; // required by IdTree::hasChildren() + } + + virtual void set (Record& record, const QVariant& data) + { + } + + virtual bool isEditable() const + { + return true; + } + + }; + + template + struct PathgridEdgeColumn : public Column + { + int mIndex; + + PathgridEdgeColumn (int index) + : Column (Columns::ColumnId_PathgridEdge0+index, ColumnBase::Display_Integer), mIndex(index) + { + } + + virtual QVariant get (const Record& record) const + { + return QVariant(); // FIXME + } + + virtual void set (Record& record, const QVariant& data) + { + } + + virtual bool isEditable() const + { + return true; + } + }; } #endif diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 1d3bc7641..db0ebfd86 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -223,6 +223,14 @@ namespace CSMWorld { ColumnId_AreaSound, "Area Sound" }, { ColumnId_BoltSound, "Bolt Sound" }, + { ColumnId_PathgridPoints, "Points"}, + { ColumnId_PathgridPosX, "X"}, + { ColumnId_PathgridPosY, "Y"}, + { ColumnId_PathgridPosZ, "Z"}, + { ColumnId_PathgridEdges, "Edges"}, + { ColumnId_PathgridEdge0, "Edge 0"}, + { ColumnId_PathgridEdge1, "Edge 1"}, + { ColumnId_UseValue1, "Use value 1" }, { ColumnId_UseValue2, "Use value 2" }, { ColumnId_UseValue3, "Use value 3" }, diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 1c0af217b..e36e29b3b 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -211,6 +211,15 @@ namespace CSMWorld ColumnId_HitSound = 196, ColumnId_AreaSound = 197, ColumnId_BoltSound = 198, + + ColumnId_PathgridPoints = 199, + ColumnId_PathgridPosX = 200, + ColumnId_PathgridPosY = 201, + ColumnId_PathgridPosZ = 202, + ColumnId_PathgridEdges = 203, + ColumnId_PathgridEdge0 = 204, + ColumnId_PathgridEdge1 = 205, + // Allocated to a separate value range, so we don't get a collision should we ever need // to extend the number of use values. ColumnId_UseValue1 = 0x10000, diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 0cfc890ea..ea94fe905 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -18,6 +18,7 @@ #include "columns.hpp" #include "resourcesmanager.hpp" #include "resourcetable.hpp" +#include "idadapterimp.hpp" void CSMWorld::Data::addModel (QAbstractItemModel *model, UniversalId::Type type, bool update) { @@ -255,6 +256,22 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mPathgrids.addColumn (new RecordStateColumn); mPathgrids.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Pathgrid)); + // new object deleted in dtor of Collection + PathgridPointListColumn *pointList = new PathgridPointListColumn (); + mPathgrids.addColumn (pointList); + // new object deleted in dtor of SubCellCollection + mPathgrids.addAdapter (std::make_pair(pointList, new PathgridPointListAdapter ())); + // new objects deleted in dtor of NestableColumn + mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn(new PathgridPointColumn (0)); + mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn(new PathgridPointColumn (1)); + mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn(new PathgridPointColumn (2)); + + PathgridEdgeListColumn *edgeList = new PathgridEdgeListColumn (); + mPathgrids.addColumn (edgeList); + mPathgrids.addAdapter (std::make_pair(edgeList, new PathgridEdgeListAdapter ())); + mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn(new PathgridEdgeColumn (0)); + mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn(new PathgridEdgeColumn (1)); + mStartScripts.addColumn (new StringIdColumn); mStartScripts.addColumn (new RecordStateColumn); mStartScripts.addColumn (new FixedRecordTypeColumn (UniversalId::Type_StartScript)); @@ -331,7 +348,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc addModel (new IdTable (&mBodyParts), UniversalId::Type_BodyPart); addModel (new IdTable (&mSoundGens), UniversalId::Type_SoundGen); addModel (new IdTable (&mMagicEffects), UniversalId::Type_MagicEffect); - addModel (new IdTable (&mPathgrids), UniversalId::Type_Pathgrid); + addModel (new IdTree (&mPathgrids, &mPathgrids), UniversalId::Type_Pathgrid); addModel (new IdTable (&mStartScripts), UniversalId::Type_StartScript); addModel (new IdTree (&mReferenceables, &mReferenceables, IdTable::Feature_Preview), UniversalId::Type_Referenceable); diff --git a/apps/opencs/model/world/idadapter.hpp b/apps/opencs/model/world/idadapter.hpp new file mode 100644 index 000000000..bec21a0f3 --- /dev/null +++ b/apps/opencs/model/world/idadapter.hpp @@ -0,0 +1,39 @@ +#ifndef CSM_WOLRD_IDADAPTER_H +#define CSM_WOLRD_IDADAPTER_H + +#include "record.hpp" + +class QVariant; + +namespace CSMWorld +{ + class NestedTableWrapperBase; + + template + class NestedIdAdapter + { + public: + + NestedIdAdapter() {} + + virtual ~NestedIdAdapter() {} + + virtual void addNestedRow(Record& record, int position) const = 0; + + virtual void removeNestedRow(Record& record, int rowToRemove) const = 0; + + virtual void setNestedTable(Record& record, const NestedTableWrapperBase& nestedTable) = 0; + + virtual NestedTableWrapperBase* nestedTable(const Record& record) const = 0; + + virtual QVariant getNestedData(const Record& record, int subRowIndex, int subColIndex) const = 0; + + virtual void setNestedData(Record& record, const QVariant& value, int subRowIndex, int subColIndex) const = 0; + + virtual int getNestedColumnsCount(const Record& record) const = 0; + + virtual int getNestedRowsCount(const Record& record) const = 0; + }; +} + +#endif // CSM_WOLRD_IDADAPTER_H diff --git a/apps/opencs/model/world/idadapterimp.hpp b/apps/opencs/model/world/idadapterimp.hpp new file mode 100644 index 000000000..fa7c55bd3 --- /dev/null +++ b/apps/opencs/model/world/idadapterimp.hpp @@ -0,0 +1,202 @@ +#ifndef CSM_WOLRD_IDADAPTERIMP_H +#define CSM_WOLRD_IDADAPTERIMP_H + +#include + +#include + +#include "idadapter.hpp" + +namespace CSMWorld +{ + class NestedTableWrapperBase; + + template + class PathgridPointListAdapter : public NestedIdAdapter + { + public: + PathgridPointListAdapter () {} + + virtual void addNestedRow(Record& record, int position) const + { + ESXRecordT pathgrid = record.get(); + + ESXRecordT::PointList& points = pathgrid.mPoints; + + // blank row + ESM::Pathgrid::Point point; + point.mX = 0; + point.mY = 0; + point.mZ = 0; + point.mAutogenerated = 0; + point.mConnectionNum = 0; + point.mUnknown = 0; + + // FIXME: inserting a point should trigger re-indexing of the edges + points.insert(points.begin()+position, point); + pathgrid.mData.mS2 += 1; // increment the number of points + + record.setModified (pathgrid); + } + + virtual void removeNestedRow(Record& record, int rowToRemove) const + { + ESXRecordT pathgrid = record.get(); + + ESXRecordT::PointList& points = pathgrid.mPoints; + + if (rowToRemove < 0 || rowToRemove >= static_cast (points.size())) + throw std::runtime_error ("index out of range"); + + // FIXME: deleting a point should trigger re-indexing of the edges + points.erase(points.begin()+rowToRemove); + pathgrid.mData.mS2 -= 1; // decrement the number of points + + record.setModified (pathgrid); + } + + virtual void setNestedTable(Record& record, const NestedTableWrapperBase& nestedTable) + { + record.get().mPoints = + static_cast &>(nestedTable).mNestedTable; + } + + virtual NestedTableWrapperBase* nestedTable(const Record& record) const + { + // deleted by dtor of NestedTableStoring + return new NestedTableWrapper(record.get().mPoints); + } + + virtual QVariant getNestedData(const Record& record, int subRowIndex, int subColIndex) const + { + ESM::Pathgrid::Point point = record.get().mPoints[subRowIndex]; + switch (subColIndex) + { + case 0: return point.mX; + case 1: return point.mY; + case 2: return point.mZ; + default: throw std::logic_error("Pathgrid point subcolumn index out of range"); + } + } + + virtual void setNestedData(Record& record, const QVariant& value, + int subRowIndex, int subColIndex) const + { + ESXRecordT pathgrid = record.get(); + ESM::Pathgrid::Point point = pathgrid.mPoints[subRowIndex]; + switch (subColIndex) + { + case 0: point.mX = value.toInt(); break; + case 1: point.mY = value.toInt(); break; + case 2: point.mZ = value.toInt(); break; + default: throw std::logic_error("Pathgrid point subcolumn index out of range"); + } + + pathgrid.mPoints[subRowIndex] = point; + + record.setModified (pathgrid); + } + + virtual int getNestedColumnsCount(const Record& record) const + { + return 3; + } + + virtual int getNestedRowsCount(const Record& record) const + { + return static_cast(record.get().mPoints.size()); + } + }; + + template + class PathgridEdgeListAdapter : public NestedIdAdapter + { + public: + PathgridEdgeListAdapter () {} + + // FIXME: seems to be auto-sorted in the dialog table display after insertion + virtual void addNestedRow(Record& record, int position) const + { + ESXRecordT pathgrid = record.get(); + + ESXRecordT::EdgeList& edges = pathgrid.mEdges; + + // blank row + ESM::Pathgrid::Edge edge; + edge.mV0 = 0; + edge.mV1 = 0; + + // FIXME: inserting a blank edge does not really make sense, perhaps this should be a + // logic_error exception + edges.insert(edges.begin()+position, edge); + + record.setModified (pathgrid); + } + + virtual void removeNestedRow(Record& record, int rowToRemove) const + { + ESXRecordT pathgrid = record.get(); + + ESXRecordT::EdgeList& edges = pathgrid.mEdges; + + if (rowToRemove < 0 || rowToRemove >= static_cast (edges.size())) + throw std::runtime_error ("index out of range"); + + edges.erase(edges.begin()+rowToRemove); + + record.setModified (pathgrid); + } + + virtual void setNestedTable(Record& record, const NestedTableWrapperBase& nestedTable) + { + record.get().mEdges = + static_cast &>(nestedTable).mNestedTable; + } + + virtual NestedTableWrapperBase* nestedTable(const Record& record) const + { + // deleted by dtor of NestedTableStoring + return new NestedTableWrapper(record.get().mEdges); + } + + virtual QVariant getNestedData(const Record& record, int subRowIndex, int subColIndex) const + { + ESM::Pathgrid::Edge edge = record.get().mEdges[subRowIndex]; + switch (subColIndex) + { + case 0: return edge.mV0; + case 1: return edge.mV1; + default: throw std::logic_error("Pathgrid edge subcolumn index out of range"); + } + } + + virtual void setNestedData(Record& record, const QVariant& value, + int subRowIndex, int subColIndex) const + { + ESXRecordT pathgrid = record.get(); + ESM::Pathgrid::Edge edge = pathgrid.mEdges[subRowIndex]; + switch (subColIndex) + { + case 0: edge.mV0 = value.toInt(); break; + case 1: edge.mV1 = value.toInt(); break; + default: throw std::logic_error("Pathgrid edge subcolumn index out of range"); + } + + pathgrid.mEdges[subRowIndex] = edge; + + record.setModified (pathgrid); + } + + virtual int getNestedColumnsCount(const Record& record) const + { + return 2; + } + + virtual int getNestedRowsCount(const Record& record) const + { + return static_cast(record.get().mEdges.size()); + } + }; +} + +#endif // CSM_WOLRD_IDADAPTERIMP_H diff --git a/apps/opencs/model/world/subcellcollection.hpp b/apps/opencs/model/world/subcellcollection.hpp index 74bb6c955..f2aeb5aaf 100644 --- a/apps/opencs/model/world/subcellcollection.hpp +++ b/apps/opencs/model/world/subcellcollection.hpp @@ -1,6 +1,17 @@ #ifndef CSM_WOLRD_SUBCOLLECTION_H #define CSM_WOLRD_SUBCOLLECTION_H +#include +#include + +#include + +#include "columnimp.hpp" +#include "idcollection.hpp" +#include "nestedcollection.hpp" +#include "nestedtablewrapper.hpp" +#include "idadapterimp.hpp" + namespace ESM { class ESMReader; @@ -14,17 +25,40 @@ namespace CSMWorld /// \brief Single type collection of top level records that are associated with cells template > - class SubCellCollection : public IdCollection + class SubCellCollection : public IdCollection, public NestedCollection { const IdCollection& mCells; + std::map* > mAdapters; virtual void loadRecord (ESXRecordT& record, ESM::ESMReader& reader); + NestedIdAdapter* getAdapter(const ColumnBase &column) const; + public: SubCellCollection (const IdCollection& cells); + ~SubCellCollection(); + + virtual void addNestedRow(int row, int column, int position); + + virtual void removeNestedRows(int row, int column, int subRow); + + virtual QVariant getNestedData(int row, int column, int subRow, int subColumn) const; + + virtual void setNestedData(int row, int column, const QVariant& data, int subRow, int subColumn); + virtual NestedTableWrapperBase* nestedTable(int row, int column) const; + virtual void setNestedTable(int row, int column, const NestedTableWrapperBase& nestedTable); + + virtual int getNestedRowsCount(int row, int column) const; + + virtual int getNestedColumnsCount(int row, int column) const; + + // this method is inherited from NestedCollection, not from Collection + virtual NestableColumn *getNestableColumn(int column); + + void addAdapter(std::pair* > adapter); }; template @@ -35,11 +69,93 @@ namespace CSMWorld } template - SubCellCollection::SubCellCollection ( - const IdCollection& cells) + SubCellCollection::SubCellCollection (const IdCollection& cells) : mCells (cells) {} + template + SubCellCollection::~SubCellCollection() + { + for (std::map* >::iterator iter (mAdapters.begin()); + iter!=mAdapters.end(); ++iter) + delete (*iter).second; + } + + template + void SubCellCollection::addAdapter(std::pair* > adapter) + { + mAdapters.insert(adapter); + } + + template + NestedIdAdapter* SubCellCollection::getAdapter(const ColumnBase &column) const + { + std::map* >::const_iterator iter = + mAdapters.find (&column); + + if (iter==mAdapters.end()) + throw std::logic_error("No such column in the nestedidadapter"); + + return iter->second; + } + + template + void SubCellCollection::addNestedRow(int row, int column, int position) + { + getAdapter(getColumn(column))->addNestedRow(getRecord(row), position); + } + + template + void SubCellCollection::removeNestedRows(int row, int column, int subRow) + { + getAdapter(getColumn(column))->removeNestedRow(getRecord(row), subRow); + } + + template + QVariant SubCellCollection::getNestedData (int row, + int column, int subRow, int subColumn) const + { + return getAdapter(getColumn(column))->getNestedData(getRecord(row), subRow, subColumn); + } + + template + void SubCellCollection::setNestedData(int row, + int column, const QVariant& data, int subRow, int subColumn) + { + getAdapter(getColumn(column))->setNestedData(getRecord(row), data, subRow, subColumn); + } + + template + CSMWorld::NestedTableWrapperBase* SubCellCollection::nestedTable(int row, + int column) const + { + return getAdapter(getColumn(column))->nestedTable(getRecord(row)); + } + + template + void SubCellCollection::setNestedTable(int row, + int column, const CSMWorld::NestedTableWrapperBase& nestedTable) + { + getAdapter(getColumn(column))->setNestedTable(getRecord(row), nestedTable); + } + + template + int SubCellCollection::getNestedRowsCount(int row, int column) const + { + return getAdapter(getColumn(column))->getNestedRowsCount(getRecord(row)); + } + + template + int SubCellCollection::getNestedColumnsCount(int row, int column) const + { + return getAdapter(getColumn(column))->getNestedColumnsCount(getRecord(row)); + } + + template + CSMWorld::NestableColumn *SubCellCollection::getNestableColumn(int column) + { + return Collection::getNestableColumn(column); + } } #endif From 860754e460523abad2a865d99b0e8ab68ada65cb Mon Sep 17 00:00:00 2001 From: cc9cii Date: Thu, 9 Apr 2015 19:33:42 +1000 Subject: [PATCH 0894/3725] Minor formatting cleanup and comments. --- apps/opencs/model/world/nestedadapters.hpp | 123 ------------------ .../model/world/nestedtableproxymodel.cpp | 2 +- .../model/world/nestedtableproxymodel.hpp | 6 +- apps/opencs/model/world/refidadapter.hpp | 5 +- apps/opencs/model/world/refidadapterimp.cpp | 13 +- apps/opencs/model/world/refidadapterimp.hpp | 4 +- 6 files changed, 15 insertions(+), 138 deletions(-) diff --git a/apps/opencs/model/world/nestedadapters.hpp b/apps/opencs/model/world/nestedadapters.hpp index ac2a650d4..a2cbea1a6 100644 --- a/apps/opencs/model/world/nestedadapters.hpp +++ b/apps/opencs/model/world/nestedadapters.hpp @@ -177,129 +177,6 @@ namespace CSMWorld }; - /* - template - class MagicEffectsHelper : public CastableHelper - { - public: - - MagicEffectsHelper(CSMWorld::UniversalId::Type type) - : CastableHelper(type) {} - - virtual void setNestedTable(RefIdData& data, - int index, - const NestedTableWrapperBase& nestedTable) - { - CastableHelper::getRecord(data, index).get().mEffects = - (static_cast&>(nestedTable)).mNestedTable; - } - - virtual NestedTableWrapperBase* nestedTable(const RefIdData& data, - int index) const - { - return new NestedTableWrapper(CastableHelper::getRecord(data, index).get().mEffects); - } - - virtual QVariant getNestedData(const CSMWorld::RefIdData& data, - int index, - int subRowIndex, - int subColIndex) const - { - const ESM::EffectList& content = CastableHelper::getRecord(data, index).get().mEffects; - - switch (subColIndex) - { - case 0: - return content.at(subRowIndex).mEffectID; - - case 1: - return content.at(subRowIndex).mRange; - - case 2: - return content.at(subRowIndex).mDuration; - - case 3: - return content.at(subRowIndex).mArea; - - case 4: - return content.at(subRowIndex).mMagMin; - - case 5: - return content.at(subRowIndex).mMagMax; - - case 6: - return (int)content.at(rubRowIndex).mSkill; - - case 7: - return (int)content.at(subRowIndex).mAttribute; - - default: - throw std::logic_error("Trying to access non-existing column in the nested table!"); - } - } - - virtual void removeNestedRow (RefIdData& data, int index, int rowToRemove) const - { - ESM::EffectList& list = CastableHelper::getRecord(data, index).get().mEffects; - - list.erase (list.begin () + rowToRemove); - } - - void setNestedData (RefIdData& data, - int index, - const QVariant& value, - int subRowIndex, - int subColIndex) const - { - switch(subColIndex) - { - case 0: - CastableHelper::getRecord(data, index).get().mEffects.at(subRowIndex).mEffectID = value.toInt(); - break; - - default: - throw std::logic_error("Trying to access non-existing column in the nested table!"); - } - } - - virtual void addNestedRow (RefIdData& data, int index, int position) const - { - std::vector& list = CastableHelper::getRecord(data, index).get().mTransport.mList; - - ESM::Position newPos; - for (unsigned i = 0; i < 3; ++i) - { - newPos.pos[i] = 0; - newPos.rot[i] = 0; - } - - ESM::Transport::Dest newRow; - newRow.mPos = newPos; - newRow.mCellName = ""; - - if (position >= (int)list.size()) - { - list.push_back(newRow); - return; - } - - list.insert(list.begin()+position, newRow); - } - - virtual int getNestedColumnsCount(const RefIdData& data) const - { - return 7; - } - - - virtual int getNestedRowsCount(const RefIdData& data, - int index) const - { - return CastableHelper::getRecord(data, index).get().mTransport.mList.size(); - } - - }; - */ template class DestinationsHelper : public CastableHelper { diff --git a/apps/opencs/model/world/nestedtableproxymodel.cpp b/apps/opencs/model/world/nestedtableproxymodel.cpp index fede8383b..182ed11ab 100644 --- a/apps/opencs/model/world/nestedtableproxymodel.cpp +++ b/apps/opencs/model/world/nestedtableproxymodel.cpp @@ -99,7 +99,7 @@ QVariant CSMWorld::NestedTableProxyModel::headerData(int section, } -bool CSMWorld::NestedTableProxyModel::setData ( const QModelIndex & index, const QVariant & value, int role) +bool CSMWorld::NestedTableProxyModel::setData (const QModelIndex & index, const QVariant & value, int role) { return mMainModel->setData(mapToSource(index), value, role); } diff --git a/apps/opencs/model/world/nestedtableproxymodel.hpp b/apps/opencs/model/world/nestedtableproxymodel.hpp index 7dc66989c..177a25d28 100644 --- a/apps/opencs/model/world/nestedtableproxymodel.hpp +++ b/apps/opencs/model/world/nestedtableproxymodel.hpp @@ -27,7 +27,7 @@ namespace CSMWorld IdTree* mMainModel; std::string mId; - public: + public: NestedTableProxyModel(const QModelIndex& parent, ColumnBase::Display displayType, IdTree* parentModel); @@ -51,9 +51,9 @@ namespace CSMWorld virtual QModelIndex parent(const QModelIndex& index) const; - virtual QVariant headerData ( int section, Qt::Orientation orientation, int role ) const; + virtual QVariant headerData (int section, Qt::Orientation orientation, int role) const; - virtual bool setData ( const QModelIndex & index, const QVariant & value, int role = Qt::EditRole ); + virtual bool setData (const QModelIndex & index, const QVariant & value, int role = Qt::EditRole); virtual Qt::ItemFlags flags(const QModelIndex& index) const; diff --git a/apps/opencs/model/world/refidadapter.hpp b/apps/opencs/model/world/refidadapter.hpp index af7469637..7f7d00413 100644 --- a/apps/opencs/model/world/refidadapter.hpp +++ b/apps/opencs/model/world/refidadapter.hpp @@ -9,6 +9,7 @@ /*! \brief * Adapters acts as indirection layer, abstracting details of the record types (in the wrappers) from the higher levels of model. * Please notice that nested adaptor uses helper classes for actually performing any actions. Different record types require different helpers (needs to be created in the subclass and then fetched via member function). + * * Important point: don't forget to make sure that getData on the nestedColumn returns true (otherwise code will not treat the index pointing to the column as having childs! */ @@ -44,7 +45,7 @@ namespace CSMWorld virtual std::string getId (const RecordBase& record) const = 0; - virtual void setId(RecordBase& record, const std::string& id) = 0; + virtual void setId(RecordBase& record, const std::string& id) = 0; // FIXME: used by RefIdCollection::cloneRecord() }; class NestedRefIdAdapterBase @@ -75,7 +76,7 @@ namespace CSMWorld class NestedRefIdAdapter : public NestedRefIdAdapterBase { - std::vector > mAssociatedColumns; //basicly, i wanted map, but with pointer key + std::vector > mAssociatedColumns; //basically, i wanted a map, but with pointer key public: NestedRefIdAdapter(); diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index 99117cc7f..b2a08e71c 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -186,11 +186,11 @@ CSMWorld::ContainerRefIdAdapter::ContainerRefIdAdapter (const NameColumns& colum std::vector > assoCol; assoCol.push_back(std::make_pair(content, new InventoryHelper(UniversalId::Type_Container))); - + setAssocColumns(assoCol); } -QVariant CSMWorld::ContainerRefIdAdapter::getData (const RefIdColumn *column, +QVariant CSMWorld::ContainerRefIdAdapter::getData (const RefIdColumn *column, const RefIdData& data, int index) const { @@ -207,12 +207,11 @@ QVariant CSMWorld::ContainerRefIdAdapter::getData (const RefIdColumn *column, return (record.get().mFlags & ESM::Container::Respawn)!=0; if (column==mContent) - return true; + return true; // required by IdTree::hasChildren() return NameRefIdAdapter::getData (column, data, index); } - void CSMWorld::ContainerRefIdAdapter::setData (const RefIdColumn *column, RefIdData& data, int index, const QVariant& value) const { @@ -490,16 +489,16 @@ QVariant CSMWorld::NpcRefIdAdapter::getData (const RefIdColumn *column, const Re if (column==mColumns.mHead) return QString::fromUtf8 (record.get().mHead.c_str()); - + if (column==mColumns.mDestinations) - return true; + return true; // required by IdTree::hasChildren() std::map::const_iterator iter = mColumns.mFlags.find (column); if (iter!=mColumns.mFlags.end()) return (record.get().mFlags & iter->second)!=0; - + return ActorRefIdAdapter::getData (column, data, index); } diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index acc6c40c1..f72c0d196 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -536,10 +536,10 @@ namespace CSMWorld return record.get().mAiData.mAlarm; if (column==mActors.mInventory) - return true; + return true; // required by IdTree::hasChildren() if (column==mActors.mSpells) - return true; + return true; // required by IdTree::hasChildren() std::map::const_iterator iter = mActors.mServices.find (column); From 787cef1386d52abe04b28fafa35882de67054027 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Thu, 9 Apr 2015 19:39:09 +1000 Subject: [PATCH 0895/3725] DialogueSubView layout update for dialogues with nested tables only. --- apps/opencs/view/world/dialoguesubview.cpp | 36 ++++++++++++++++------ 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index d0b53a206..79eb48534 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -293,7 +293,6 @@ QWidget* CSVWorld::DialogueDelegateDispatcher::makeEditor(CSMWorld::ColumnBase:: connect(proxy, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*)), this, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*))); - //skip = true; } else if (qobject_cast(editor)) { @@ -382,18 +381,27 @@ void CSVWorld::EditWidget::remake(int row) mWidgetMapper->setModel(mTable); mWidgetMapper->setItemDelegate(&mDispatcher); + QFrame* line = new QFrame(mMainWidget); + line->setObjectName(QString::fromUtf8("line")); + line->setGeometry(QRect(320, 150, 118, 3)); + line->setFrameShape(QFrame::HLine); + line->setFrameShadow(QFrame::Sunken); QVBoxLayout *mainLayout = new QVBoxLayout(mMainWidget); + QGridLayout *lockedLayout = new QGridLayout(); QScrollArea *scroll = new QScrollArea(mMainWidget); QWidget *unlockedWidget = new QWidget(scroll); - QGridLayout *unlockedLayout = new QGridLayout(unlockedWidget); - QGridLayout *lockedLayout = new QGridLayout(); + QVBoxLayout *overLayout = new QVBoxLayout(unlockedWidget); + QGridLayout *unlockedLayout = new QGridLayout(); QVBoxLayout *tablesLayout = new QVBoxLayout(); - mainLayout->addLayout(lockedLayout, 0); + mainLayout->addLayout(lockedLayout, QSizePolicy::Fixed); mainLayout->addSpacing(5); // FIXME: arbitrary number - mainLayout->addWidget(scroll, 2); + mainLayout->addWidget(line, 1); + mainLayout->addWidget(scroll, QSizePolicy::Preferred); + overLayout->addLayout(unlockedLayout, QSizePolicy::Preferred); + overLayout->addStretch(1); mainLayout->addSpacing(5); // FIXME: arbitrary number - mainLayout->addLayout(tablesLayout, 0); + mainLayout->addLayout(tablesLayout, QSizePolicy::Preferred); mainLayout->addStretch(1); int unlocked = 0; @@ -457,9 +465,19 @@ void CSVWorld::EditWidget::remake(int row) mWidgetMapper->setCurrentModelIndex(mTable->index(row, 0)); - scroll->setWidget(unlockedWidget); - scroll->setSizePolicy (QSizePolicy::Expanding, QSizePolicy::Fixed); - scroll->setWidgetResizable(true); + if (unlocked != 0) + { + mainLayout->removeWidget(line); + scroll->setWidget(unlockedWidget); + scroll->setSizePolicy (QSizePolicy::Expanding, QSizePolicy::Minimum); + scroll->setWidgetResizable(true); + } + else + { + delete unlockedWidget; + delete scroll; + } + this->setWidget(mMainWidget); this->setWidgetResizable(true); } From 3a46512b7f22b52bc8e276b86c6f8102ae48c1cc Mon Sep 17 00:00:00 2001 From: cc9cii Date: Thu, 9 Apr 2015 20:15:38 +1000 Subject: [PATCH 0896/3725] Attempt to account for gcc differences. --- apps/opencs/model/world/data.hpp | 2 ++ apps/opencs/model/world/idadapterimp.hpp | 16 +++++++------- apps/opencs/model/world/subcellcollection.hpp | 22 +++++++++---------- 3 files changed, 21 insertions(+), 19 deletions(-) diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 298a9be1f..b9e060002 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -42,7 +42,9 @@ #include "refcollection.hpp" #include "infocollection.hpp" #include "pathgrid.hpp" +#ifndef Q_MOC_RUN #include "subcellcollection.hpp" +#endif class QAbstractItemModel; diff --git a/apps/opencs/model/world/idadapterimp.hpp b/apps/opencs/model/world/idadapterimp.hpp index fa7c55bd3..025c2e137 100644 --- a/apps/opencs/model/world/idadapterimp.hpp +++ b/apps/opencs/model/world/idadapterimp.hpp @@ -21,7 +21,7 @@ namespace CSMWorld { ESXRecordT pathgrid = record.get(); - ESXRecordT::PointList& points = pathgrid.mPoints; + ESM::Pathgrid::PointList& points = pathgrid.mPoints; // blank row ESM::Pathgrid::Point point; @@ -43,7 +43,7 @@ namespace CSMWorld { ESXRecordT pathgrid = record.get(); - ESXRecordT::PointList& points = pathgrid.mPoints; + ESM::Pathgrid::PointList& points = pathgrid.mPoints; if (rowToRemove < 0 || rowToRemove >= static_cast (points.size())) throw std::runtime_error ("index out of range"); @@ -58,13 +58,13 @@ namespace CSMWorld virtual void setNestedTable(Record& record, const NestedTableWrapperBase& nestedTable) { record.get().mPoints = - static_cast &>(nestedTable).mNestedTable; + static_cast &>(nestedTable).mNestedTable; } virtual NestedTableWrapperBase* nestedTable(const Record& record) const { // deleted by dtor of NestedTableStoring - return new NestedTableWrapper(record.get().mPoints); + return new NestedTableWrapper(record.get().mPoints); } virtual QVariant getNestedData(const Record& record, int subRowIndex, int subColIndex) const @@ -119,7 +119,7 @@ namespace CSMWorld { ESXRecordT pathgrid = record.get(); - ESXRecordT::EdgeList& edges = pathgrid.mEdges; + ESM::Pathgrid::EdgeList& edges = pathgrid.mEdges; // blank row ESM::Pathgrid::Edge edge; @@ -137,7 +137,7 @@ namespace CSMWorld { ESXRecordT pathgrid = record.get(); - ESXRecordT::EdgeList& edges = pathgrid.mEdges; + ESM::Pathgrid::EdgeList& edges = pathgrid.mEdges; if (rowToRemove < 0 || rowToRemove >= static_cast (edges.size())) throw std::runtime_error ("index out of range"); @@ -150,13 +150,13 @@ namespace CSMWorld virtual void setNestedTable(Record& record, const NestedTableWrapperBase& nestedTable) { record.get().mEdges = - static_cast &>(nestedTable).mNestedTable; + static_cast &>(nestedTable).mNestedTable; } virtual NestedTableWrapperBase* nestedTable(const Record& record) const { // deleted by dtor of NestedTableStoring - return new NestedTableWrapper(record.get().mEdges); + return new NestedTableWrapper(record.get().mEdges); } virtual QVariant getNestedData(const Record& record, int subRowIndex, int subColIndex) const diff --git a/apps/opencs/model/world/subcellcollection.hpp b/apps/opencs/model/world/subcellcollection.hpp index f2aeb5aaf..919a0a604 100644 --- a/apps/opencs/model/world/subcellcollection.hpp +++ b/apps/opencs/model/world/subcellcollection.hpp @@ -76,7 +76,7 @@ namespace CSMWorld template SubCellCollection::~SubCellCollection() { - for (std::map* >::iterator iter (mAdapters.begin()); + for (typename std::map* >::iterator iter (mAdapters.begin()); iter!=mAdapters.end(); ++iter) delete (*iter).second; } @@ -90,7 +90,7 @@ namespace CSMWorld template NestedIdAdapter* SubCellCollection::getAdapter(const ColumnBase &column) const { - std::map* >::const_iterator iter = + typename std::map* >::const_iterator iter = mAdapters.find (&column); if (iter==mAdapters.end()) @@ -102,59 +102,59 @@ namespace CSMWorld template void SubCellCollection::addNestedRow(int row, int column, int position) { - getAdapter(getColumn(column))->addNestedRow(getRecord(row), position); + getAdapter(Collection::getColumn(column))->addNestedRow(getRecord(row), position); } template void SubCellCollection::removeNestedRows(int row, int column, int subRow) { - getAdapter(getColumn(column))->removeNestedRow(getRecord(row), subRow); + getAdapter(Collection::getColumn(column))->removeNestedRow(getRecord(row), subRow); } template QVariant SubCellCollection::getNestedData (int row, int column, int subRow, int subColumn) const { - return getAdapter(getColumn(column))->getNestedData(getRecord(row), subRow, subColumn); + return getAdapter(Collection::getColumn(column))->getNestedData(getRecord(row), subRow, subColumn); } template void SubCellCollection::setNestedData(int row, int column, const QVariant& data, int subRow, int subColumn) { - getAdapter(getColumn(column))->setNestedData(getRecord(row), data, subRow, subColumn); + getAdapter(Collection::getColumn(column))->setNestedData(getRecord(row), data, subRow, subColumn); } template CSMWorld::NestedTableWrapperBase* SubCellCollection::nestedTable(int row, int column) const { - return getAdapter(getColumn(column))->nestedTable(getRecord(row)); + return getAdapter(Collection::getColumn(column))->nestedTable(getRecord(row)); } template void SubCellCollection::setNestedTable(int row, int column, const CSMWorld::NestedTableWrapperBase& nestedTable) { - getAdapter(getColumn(column))->setNestedTable(getRecord(row), nestedTable); + getAdapter(Collection::getColumn(column))->setNestedTable(getRecord(row), nestedTable); } template int SubCellCollection::getNestedRowsCount(int row, int column) const { - return getAdapter(getColumn(column))->getNestedRowsCount(getRecord(row)); + return getAdapter(Collection::getColumn(column))->getNestedRowsCount(getRecord(row)); } template int SubCellCollection::getNestedColumnsCount(int row, int column) const { - return getAdapter(getColumn(column))->getNestedColumnsCount(getRecord(row)); + return getAdapter(Collection::getColumn(column))->getNestedColumnsCount(getRecord(row)); } template CSMWorld::NestableColumn *SubCellCollection::getNestableColumn(int column) { - return Collection::getNestableColumn(column); + return Collection::getNestableColumn(column); } } From 23db79ebab328298a8a39783299c3ca7e01a0dc7 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Thu, 9 Apr 2015 20:53:41 +1000 Subject: [PATCH 0897/3725] Fix for more gcc differences. --- apps/opencs/model/world/commands.hpp | 2 +- apps/opencs/model/world/idadapter.hpp | 2 +- apps/opencs/model/world/idtree.hpp | 2 +- apps/opencs/model/world/nestedcollection.hpp | 2 +- apps/opencs/model/world/refidadapter.hpp | 2 +- apps/opencs/model/world/refidadapterimp.hpp | 2 +- apps/opencs/model/world/refidcollection.hpp | 2 +- apps/opencs/model/world/subcellcollection.hpp | 24 ++++++++++++------- 8 files changed, 23 insertions(+), 15 deletions(-) diff --git a/apps/opencs/model/world/commands.hpp b/apps/opencs/model/world/commands.hpp index 42405a2f9..a70b36178 100644 --- a/apps/opencs/model/world/commands.hpp +++ b/apps/opencs/model/world/commands.hpp @@ -22,7 +22,7 @@ namespace CSMWorld class IdTable; class IdTree; struct RecordBase; - class NestedTableWrapperBase; + struct NestedTableWrapperBase; class ModifyCommand : public QUndoCommand { diff --git a/apps/opencs/model/world/idadapter.hpp b/apps/opencs/model/world/idadapter.hpp index bec21a0f3..753ac01f0 100644 --- a/apps/opencs/model/world/idadapter.hpp +++ b/apps/opencs/model/world/idadapter.hpp @@ -7,7 +7,7 @@ class QVariant; namespace CSMWorld { - class NestedTableWrapperBase; + struct NestedTableWrapperBase; template class NestedIdAdapter diff --git a/apps/opencs/model/world/idtree.hpp b/apps/opencs/model/world/idtree.hpp index 80b44d241..d06d86a4f 100644 --- a/apps/opencs/model/world/idtree.hpp +++ b/apps/opencs/model/world/idtree.hpp @@ -20,7 +20,7 @@ namespace CSMWorld { class NestedCollection; struct RecordBase; - class NestedTableWrapperBase; // FIXME: is this necessary? + struct NestedTableWrapperBase; class IdTree : public IdTable { diff --git a/apps/opencs/model/world/nestedcollection.hpp b/apps/opencs/model/world/nestedcollection.hpp index 8046f9a09..b075f53c4 100644 --- a/apps/opencs/model/world/nestedcollection.hpp +++ b/apps/opencs/model/world/nestedcollection.hpp @@ -6,7 +6,7 @@ class QVariant; namespace CSMWorld { class NestableColumn; - class NestedTableWrapperBase; + struct NestedTableWrapperBase; class NestedCollection { diff --git a/apps/opencs/model/world/refidadapter.hpp b/apps/opencs/model/world/refidadapter.hpp index 7f7d00413..91f19577b 100644 --- a/apps/opencs/model/world/refidadapter.hpp +++ b/apps/opencs/model/world/refidadapter.hpp @@ -20,7 +20,7 @@ namespace CSMWorld class RefIdColumn; class RefIdData; struct RecordBase; - class NestedTableWrapperBase; + struct NestedTableWrapperBase; class HelperBase; class RefIdAdapter diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index f72c0d196..7296b6c68 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -16,7 +16,7 @@ namespace CSMWorld { - class NestedTableWrapperBase; + struct NestedTableWrapperBase; struct BaseColumns { diff --git a/apps/opencs/model/world/refidcollection.hpp b/apps/opencs/model/world/refidcollection.hpp index 2a271a846..5bf7c177e 100644 --- a/apps/opencs/model/world/refidcollection.hpp +++ b/apps/opencs/model/world/refidcollection.hpp @@ -18,7 +18,7 @@ namespace ESM namespace CSMWorld { class RefIdAdapter; - class NestedTableWrapperBase; + struct NestedTableWrapperBase; class RefIdColumn : public NestableColumn { diff --git a/apps/opencs/model/world/subcellcollection.hpp b/apps/opencs/model/world/subcellcollection.hpp index 919a0a604..92091cf57 100644 --- a/apps/opencs/model/world/subcellcollection.hpp +++ b/apps/opencs/model/world/subcellcollection.hpp @@ -102,53 +102,61 @@ namespace CSMWorld template void SubCellCollection::addNestedRow(int row, int column, int position) { - getAdapter(Collection::getColumn(column))->addNestedRow(getRecord(row), position); + getAdapter(Collection::getColumn(column))->addNestedRow( + Collection::getRecord(row), position); } template void SubCellCollection::removeNestedRows(int row, int column, int subRow) { - getAdapter(Collection::getColumn(column))->removeNestedRow(getRecord(row), subRow); + getAdapter(Collection::getColumn(column))->removeNestedRow( + Collection::getRecord(row), subRow); } template QVariant SubCellCollection::getNestedData (int row, int column, int subRow, int subColumn) const { - return getAdapter(Collection::getColumn(column))->getNestedData(getRecord(row), subRow, subColumn); + return getAdapter(Collection::getColumn(column))->getNestedData( + Collection::getRecord(row), subRow, subColumn); } template void SubCellCollection::setNestedData(int row, int column, const QVariant& data, int subRow, int subColumn) { - getAdapter(Collection::getColumn(column))->setNestedData(getRecord(row), data, subRow, subColumn); + getAdapter(Collection::getColumn(column))->setNestedData( + Collection::getRecord(row), data, subRow, subColumn); } template CSMWorld::NestedTableWrapperBase* SubCellCollection::nestedTable(int row, int column) const { - return getAdapter(Collection::getColumn(column))->nestedTable(getRecord(row)); + return getAdapter(Collection::getColumn(column))->nestedTable( + Collection::getRecord(row)); } template void SubCellCollection::setNestedTable(int row, int column, const CSMWorld::NestedTableWrapperBase& nestedTable) { - getAdapter(Collection::getColumn(column))->setNestedTable(getRecord(row), nestedTable); + getAdapter(Collection::getColumn(column))->setNestedTable( + Collection::getRecord(row), nestedTable); } template int SubCellCollection::getNestedRowsCount(int row, int column) const { - return getAdapter(Collection::getColumn(column))->getNestedRowsCount(getRecord(row)); + return getAdapter(Collection::getColumn(column))->getNestedRowsCount( + Collection::getRecord(row)); } template int SubCellCollection::getNestedColumnsCount(int row, int column) const { - return getAdapter(Collection::getColumn(column))->getNestedColumnsCount(getRecord(row)); + return getAdapter(Collection::getColumn(column))->getNestedColumnsCount( + Collection::getRecord(row)); } template From be9f94b7663940010a4ff1bc8748aab4ac3b57a2 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Thu, 9 Apr 2015 21:23:02 +1000 Subject: [PATCH 0898/3725] Adjust edge indexes when adding/removing points. Fix some travis warnings. --- apps/opencs/model/world/idadapterimp.hpp | 29 +++++++++++++++++-- apps/opencs/model/world/nestedadapters.hpp | 2 +- .../model/world/nestedtableproxymodel.hpp | 2 +- 3 files changed, 28 insertions(+), 5 deletions(-) diff --git a/apps/opencs/model/world/idadapterimp.hpp b/apps/opencs/model/world/idadapterimp.hpp index 025c2e137..aed847909 100644 --- a/apps/opencs/model/world/idadapterimp.hpp +++ b/apps/opencs/model/world/idadapterimp.hpp @@ -9,7 +9,7 @@ namespace CSMWorld { - class NestedTableWrapperBase; + struct NestedTableWrapperBase; template class PathgridPointListAdapter : public NestedIdAdapter @@ -32,7 +32,16 @@ namespace CSMWorld point.mConnectionNum = 0; point.mUnknown = 0; - // FIXME: inserting a point should trigger re-indexing of the edges + // inserting a point should trigger re-indexing of the edges + std::vector::iterator iter = pathgrid.mEdges.begin(); + for (;iter != pathgrid.mEdges.end(); ++iter) + { + if ((*iter).mV0 > position) + (*iter).mV0++; + if ((*iter).mV1 > position) + (*iter).mV1++; + } + points.insert(points.begin()+position, point); pathgrid.mData.mS2 += 1; // increment the number of points @@ -48,7 +57,21 @@ namespace CSMWorld if (rowToRemove < 0 || rowToRemove >= static_cast (points.size())) throw std::runtime_error ("index out of range"); - // FIXME: deleting a point should trigger re-indexing of the edges + // deleting a point should trigger re-indexing of the edges + // dangling edges are not allowed and hence removed + std::vector::iterator iter = pathgrid.mEdges.begin(); + for (;iter != pathgrid.mEdges.end(); ++iter) + { + if (((*iter).mV0 == rowToRemove) || ((*iter).mV1 == rowToRemove)) + pathgrid.mEdges.erase(iter); + + if ((*iter).mV0 > rowToRemove) + (*iter).mV0--; + + if ((*iter).mV1 > rowToRemove) + (*iter).mV1--; + } + points.erase(points.begin()+rowToRemove); pathgrid.mData.mS2 -= 1; // decrement the number of points diff --git a/apps/opencs/model/world/nestedadapters.hpp b/apps/opencs/model/world/nestedadapters.hpp index a2cbea1a6..015765380 100644 --- a/apps/opencs/model/world/nestedadapters.hpp +++ b/apps/opencs/model/world/nestedadapters.hpp @@ -393,7 +393,7 @@ namespace CSMWorld { std::vector& list = CastableHelper::getRecord(data, index).get().mInventory.mList; - ESM::ContItem newRow = {0, ""}; + ESM::ContItem newRow = {0, {""}}; if (position >= (int)list.size()) { list.push_back(newRow); diff --git a/apps/opencs/model/world/nestedtableproxymodel.hpp b/apps/opencs/model/world/nestedtableproxymodel.hpp index 177a25d28..2ab04a584 100644 --- a/apps/opencs/model/world/nestedtableproxymodel.hpp +++ b/apps/opencs/model/world/nestedtableproxymodel.hpp @@ -16,7 +16,7 @@ namespace CSMWorld { class CollectionBase; - class RecordBase; + struct RecordBase; class IdTree; class NestedTableProxyModel : public QAbstractProxyModel From 330920daa8df5e8294f5e2982de94eb8d2835f36 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Thu, 9 Apr 2015 21:41:46 +1000 Subject: [PATCH 0899/3725] Fix off by one error(s). --- apps/opencs/model/world/idadapterimp.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/opencs/model/world/idadapterimp.hpp b/apps/opencs/model/world/idadapterimp.hpp index aed847909..510a14f12 100644 --- a/apps/opencs/model/world/idadapterimp.hpp +++ b/apps/opencs/model/world/idadapterimp.hpp @@ -36,9 +36,9 @@ namespace CSMWorld std::vector::iterator iter = pathgrid.mEdges.begin(); for (;iter != pathgrid.mEdges.end(); ++iter) { - if ((*iter).mV0 > position) + if ((*iter).mV0 >= position) (*iter).mV0++; - if ((*iter).mV1 > position) + if ((*iter).mV1 >= position) (*iter).mV1++; } @@ -65,10 +65,10 @@ namespace CSMWorld if (((*iter).mV0 == rowToRemove) || ((*iter).mV1 == rowToRemove)) pathgrid.mEdges.erase(iter); - if ((*iter).mV0 > rowToRemove) + if ((*iter).mV0 >= rowToRemove) (*iter).mV0--; - if ((*iter).mV1 > rowToRemove) + if ((*iter).mV1 >= rowToRemove) (*iter).mV1--; } From 0b77ae43a4ca39e42f8244374e47b11554c4a185 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 9 Apr 2015 16:51:57 +0200 Subject: [PATCH 0900/3725] Minor optimization for particle emitters --- components/nifosg/particle.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/components/nifosg/particle.cpp b/components/nifosg/particle.cpp index c4bf69579..59a4a981b 100644 --- a/components/nifosg/particle.cpp +++ b/components/nifosg/particle.cpp @@ -238,7 +238,12 @@ void Emitter::setCounter(osgParticle::Counter *counter) void Emitter::emitParticles(double dt) { + int n = mCounter->numParticlesToCreate(dt); + if (n == 0) + return; + osg::Matrix worldToPs; + // maybe this could be optimized by halting at the lowest common ancestor of the particle and emitter nodes osg::MatrixList worldMats = getParticleSystem()->getWorldMatrices(); if (!worldMats.empty()) @@ -271,8 +276,6 @@ void Emitter::emitParticles(double dt) emitterToPs.orthoNormalize(emitterToPs); - int n = mCounter->numParticlesToCreate(dt); - for (int i=0; icreateParticle(0); From 8b206e0aeda6feee2470a61aa363a79dbe3ba25f Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 9 Apr 2015 16:52:38 +0200 Subject: [PATCH 0901/3725] Enable culling for particle emitters & programs Big speedup, though might cause timing inconsistencies that we should fix at some point. --- components/nifosg/nifloader.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 2a3d0322d..b077c32ff 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -954,6 +954,7 @@ namespace NifOsg attachTo->addChild(program); program->setParticleSystem(partsys); program->setReferenceFrame(rf); + program->setCullingActive(true); for (; !affectors.empty(); affectors = affectors->extra) { if (affectors->recType == Nif::RC_NiParticleGrowFade) @@ -1100,6 +1101,7 @@ namespace NifOsg osg::ref_ptr emitter = handleParticleEmitter(partctrl); emitter->setParticleSystem(partsys); emitter->setReferenceFrame(osgParticle::ParticleProcessor::RELATIVE_RF); + emitter->setCullingActive(true); // Note: we assume that the Emitter node is placed *before* the Particle node in the scene graph. // This seems to be true for all NIF files in the game that I've checked, suggesting that NIFs work similar to OSG with regards to update order. @@ -1140,6 +1142,7 @@ namespace NifOsg // particle system updater (after the emitters and affectors in the scene graph) // I think for correct culling needs to be *before* the ParticleSystem, though osg examples do it the other way osg::ref_ptr updater = new osgParticle::ParticleSystemUpdater; + updater->setCullingActive(true); updater->addParticleSystem(partsys); parentNode->addChild(updater); From bc9dad3ff2a776b084c00065da7529ac170091b0 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Fri, 10 Apr 2015 07:31:01 +1000 Subject: [PATCH 0902/3725] Add index columns and fix edge indexing for point deletion. --- apps/opencs/model/world/columnimp.hpp | 44 ++++++++++++++++++ apps/opencs/model/world/columns.cpp | 6 ++- apps/opencs/model/world/columns.hpp | 14 +++--- apps/opencs/model/world/data.cpp | 3 ++ apps/opencs/model/world/idadapterimp.hpp | 57 +++++++++++++++--------- 5 files changed, 96 insertions(+), 28 deletions(-) diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index 27fc3ad04..70c134e01 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -2289,6 +2289,28 @@ namespace CSMWorld } }; + template + struct PathgridIndexColumn : public Column + { + PathgridIndexColumn() + : Column (Columns::ColumnId_PathgridIndex, ColumnBase::Display_Integer) + {} + + virtual QVariant get (const Record& record) const + { + return QVariant(); // FIXME + } + + virtual void set (Record& record, const QVariant& data) + { + } + + virtual bool isEditable() const + { + return false; + } + }; + template struct PathgridPointColumn : public Column { @@ -2338,6 +2360,28 @@ namespace CSMWorld }; + template + struct PathgridEdgeIndexColumn : public Column + { + PathgridEdgeIndexColumn() + : Column (Columns::ColumnId_PathgridEdgeIndex, ColumnBase::Display_Integer) + {} + + virtual QVariant get (const Record& record) const + { + return QVariant(); // FIXME + } + + virtual void set (Record& record, const QVariant& data) + { + } + + virtual bool isEditable() const + { + return false; + } + }; + template struct PathgridEdgeColumn : public Column { diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index db0ebfd86..e6a27138f 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -224,12 +224,14 @@ namespace CSMWorld { ColumnId_BoltSound, "Bolt Sound" }, { ColumnId_PathgridPoints, "Points"}, + { ColumnId_PathgridIndex, "Index"}, { ColumnId_PathgridPosX, "X"}, { ColumnId_PathgridPosY, "Y"}, { ColumnId_PathgridPosZ, "Z"}, { ColumnId_PathgridEdges, "Edges"}, - { ColumnId_PathgridEdge0, "Edge 0"}, - { ColumnId_PathgridEdge1, "Edge 1"}, + { ColumnId_PathgridEdgeIndex, "Index"}, + { ColumnId_PathgridEdge0, "Point 0"}, + { ColumnId_PathgridEdge1, "Point 1"}, { ColumnId_UseValue1, "Use value 1" }, { ColumnId_UseValue2, "Use value 2" }, diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index e36e29b3b..2cb7101b0 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -213,12 +213,14 @@ namespace CSMWorld ColumnId_BoltSound = 198, ColumnId_PathgridPoints = 199, - ColumnId_PathgridPosX = 200, - ColumnId_PathgridPosY = 201, - ColumnId_PathgridPosZ = 202, - ColumnId_PathgridEdges = 203, - ColumnId_PathgridEdge0 = 204, - ColumnId_PathgridEdge1 = 205, + ColumnId_PathgridIndex = 200, + ColumnId_PathgridPosX = 201, + ColumnId_PathgridPosY = 202, + ColumnId_PathgridPosZ = 203, + ColumnId_PathgridEdges = 204, + ColumnId_PathgridEdgeIndex = 205, + ColumnId_PathgridEdge0 = 206, + ColumnId_PathgridEdge1 = 207, // Allocated to a separate value range, so we don't get a collision should we ever need // to extend the number of use values. diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index ea94fe905..76e34961f 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -262,6 +262,8 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc // new object deleted in dtor of SubCellCollection mPathgrids.addAdapter (std::make_pair(pointList, new PathgridPointListAdapter ())); // new objects deleted in dtor of NestableColumn + // WARNING: The order of the columns below are assumed in PathgridPointListAdapter + mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn(new PathgridIndexColumn ()); mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn(new PathgridPointColumn (0)); mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn(new PathgridPointColumn (1)); mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn(new PathgridPointColumn (2)); @@ -269,6 +271,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc PathgridEdgeListColumn *edgeList = new PathgridEdgeListColumn (); mPathgrids.addColumn (edgeList); mPathgrids.addAdapter (std::make_pair(edgeList, new PathgridEdgeListAdapter ())); + mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn(new PathgridEdgeIndexColumn ()); mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn(new PathgridEdgeColumn (0)); mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn(new PathgridEdgeColumn (1)); diff --git a/apps/opencs/model/world/idadapterimp.hpp b/apps/opencs/model/world/idadapterimp.hpp index 510a14f12..f5ed2e6e1 100644 --- a/apps/opencs/model/world/idadapterimp.hpp +++ b/apps/opencs/model/world/idadapterimp.hpp @@ -33,6 +33,9 @@ namespace CSMWorld point.mUnknown = 0; // inserting a point should trigger re-indexing of the edges + // + // FIXME: undo does not restore edges table view + // FIXME: does not auto refresh edges table view std::vector::iterator iter = pathgrid.mEdges.begin(); for (;iter != pathgrid.mEdges.end(); ++iter) { @@ -59,19 +62,25 @@ namespace CSMWorld // deleting a point should trigger re-indexing of the edges // dangling edges are not allowed and hence removed + // + // FIXME: undo does not restore edges table view + // FIXME: does not auto refresh edges table view std::vector::iterator iter = pathgrid.mEdges.begin(); - for (;iter != pathgrid.mEdges.end(); ++iter) + for (; iter != pathgrid.mEdges.end();) { if (((*iter).mV0 == rowToRemove) || ((*iter).mV1 == rowToRemove)) - pathgrid.mEdges.erase(iter); + iter = pathgrid.mEdges.erase(iter); + else + { + if ((*iter).mV0 > rowToRemove) + (*iter).mV0--; - if ((*iter).mV0 >= rowToRemove) - (*iter).mV0--; + if ((*iter).mV1 > rowToRemove) + (*iter).mV1--; - if ((*iter).mV1 >= rowToRemove) - (*iter).mV1--; + ++iter; + } } - points.erase(points.begin()+rowToRemove); pathgrid.mData.mS2 -= 1; // decrement the number of points @@ -95,9 +104,10 @@ namespace CSMWorld ESM::Pathgrid::Point point = record.get().mPoints[subRowIndex]; switch (subColIndex) { - case 0: return point.mX; - case 1: return point.mY; - case 2: return point.mZ; + case 0: return subRowIndex; + case 1: return point.mX; + case 2: return point.mY; + case 3: return point.mZ; default: throw std::logic_error("Pathgrid point subcolumn index out of range"); } } @@ -109,9 +119,10 @@ namespace CSMWorld ESM::Pathgrid::Point point = pathgrid.mPoints[subRowIndex]; switch (subColIndex) { - case 0: point.mX = value.toInt(); break; - case 1: point.mY = value.toInt(); break; - case 2: point.mZ = value.toInt(); break; + case 0: break; + case 1: point.mX = value.toInt(); break; + case 2: point.mY = value.toInt(); break; + case 3: point.mZ = value.toInt(); break; default: throw std::logic_error("Pathgrid point subcolumn index out of range"); } @@ -122,7 +133,7 @@ namespace CSMWorld virtual int getNestedColumnsCount(const Record& record) const { - return 3; + return 4; } virtual int getNestedRowsCount(const Record& record) const @@ -149,8 +160,11 @@ namespace CSMWorld edge.mV0 = 0; edge.mV1 = 0; - // FIXME: inserting a blank edge does not really make sense, perhaps this should be a + // NOTE: inserting a blank edge does not really make sense, perhaps this should be a // logic_error exception + // + // Currently the code assumes that the end user to know what he/she is doing. + // e.g. Edges come in pairs, from points a->b and b->a edges.insert(edges.begin()+position, edge); record.setModified (pathgrid); @@ -187,12 +201,14 @@ namespace CSMWorld ESM::Pathgrid::Edge edge = record.get().mEdges[subRowIndex]; switch (subColIndex) { - case 0: return edge.mV0; - case 1: return edge.mV1; + case 0: return subRowIndex; + case 1: return edge.mV0; + case 2: return edge.mV1; default: throw std::logic_error("Pathgrid edge subcolumn index out of range"); } } + // FIXME: detect duplicates in mEdges virtual void setNestedData(Record& record, const QVariant& value, int subRowIndex, int subColIndex) const { @@ -200,8 +216,9 @@ namespace CSMWorld ESM::Pathgrid::Edge edge = pathgrid.mEdges[subRowIndex]; switch (subColIndex) { - case 0: edge.mV0 = value.toInt(); break; - case 1: edge.mV1 = value.toInt(); break; + case 0: break; + case 1: edge.mV0 = value.toInt(); break; + case 2: edge.mV1 = value.toInt(); break; default: throw std::logic_error("Pathgrid edge subcolumn index out of range"); } @@ -212,7 +229,7 @@ namespace CSMWorld virtual int getNestedColumnsCount(const Record& record) const { - return 2; + return 3; } virtual int getNestedRowsCount(const Record& record) const From 9a564f50628f5c29ce8ea4913d4082c5b92823ec Mon Sep 17 00:00:00 2001 From: cc9cii Date: Fri, 10 Apr 2015 15:28:09 +1000 Subject: [PATCH 0903/3725] Fix undo for pathgrid points add/remove. --- apps/opencs/model/world/idadapterimp.hpp | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/world/idadapterimp.hpp b/apps/opencs/model/world/idadapterimp.hpp index f5ed2e6e1..746815414 100644 --- a/apps/opencs/model/world/idadapterimp.hpp +++ b/apps/opencs/model/world/idadapterimp.hpp @@ -87,16 +87,36 @@ namespace CSMWorld record.setModified (pathgrid); } + struct PathgridPointsWrap : public NestedTableWrapperBase + { + ESM::Pathgrid mRecord; + + PathgridPointsWrap(ESM::Pathgrid pathgrid) + : mRecord(pathgrid) {} + + virtual ~PathgridPointsWrap() {} + + virtual int size() const + { + return mRecord.mPoints.size(); // used in IdTree::setNestedTable() + } + }; + virtual void setNestedTable(Record& record, const NestedTableWrapperBase& nestedTable) { record.get().mPoints = - static_cast &>(nestedTable).mNestedTable; + static_cast(nestedTable).mRecord.mPoints; + record.get().mData.mS2 = + static_cast(nestedTable).mRecord.mData.mS2; + // also update edges in case points were added/removed + record.get().mEdges = + static_cast(nestedTable).mRecord.mEdges; } virtual NestedTableWrapperBase* nestedTable(const Record& record) const { // deleted by dtor of NestedTableStoring - return new NestedTableWrapper(record.get().mPoints); + return new PathgridPointsWrap(record.get()); } virtual QVariant getNestedData(const Record& record, int subRowIndex, int subColIndex) const From 7990fab708c153545ffef6a5af3be49905b9d705 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Fri, 10 Apr 2015 18:09:33 +1000 Subject: [PATCH 0904/3725] Fix crash when exiting via window manager on some systems. --- apps/opencs/model/world/idtree.cpp | 3 +-- apps/opencs/model/world/idtree.hpp | 1 - apps/opencs/view/doc/view.cpp | 4 ++++ 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/world/idtree.cpp b/apps/opencs/model/world/idtree.cpp index 4befd1eee..952c9e329 100644 --- a/apps/opencs/model/world/idtree.cpp +++ b/apps/opencs/model/world/idtree.cpp @@ -54,8 +54,7 @@ QVariant CSMWorld::IdTree::data (const QModelIndex & index, int role) const QVariant CSMWorld::IdTree::nestedHeaderData(int section, int subSection, Qt::Orientation orientation, int role) const { - // FIXME: workaround only, a proper fix should stop QHideEvent calls after destruction - if (section < 0 || !idCollection() || section >= idCollection()->getColumns()) + if (section < 0 || section >= idCollection()->getColumns()) return QVariant(); const NestableColumn *parentColumn = mNestedCollection->getNestableColumn(section); diff --git a/apps/opencs/model/world/idtree.hpp b/apps/opencs/model/world/idtree.hpp index d06d86a4f..5f005c4d3 100644 --- a/apps/opencs/model/world/idtree.hpp +++ b/apps/opencs/model/world/idtree.hpp @@ -61,7 +61,6 @@ namespace CSMWorld virtual QModelIndex parent (const QModelIndex& index) const; - // TODO: check if below methods are really needed QVariant nestedHeaderData(int section, int subSection, Qt::Orientation orientation, int role = Qt::DisplayRole) const; NestedTableWrapperBase* nestedTable(const QModelIndex &index) const; diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index cf2940b99..f9fe613ef 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -32,6 +32,10 @@ void CSVDoc::View::closeEvent (QCloseEvent *event) event->ignore(); else { + // delete the subviews first + for (QList::iterator iter = mSubViews.begin(); iter != mSubViews.end(); ++iter) + delete *iter; + // closeRequest() returns true if last document mViewManager.removeDocAndView(mDocument); } From 3f4f008c5132689974b4085238311224eba34beb Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 10 Apr 2015 13:27:34 +0200 Subject: [PATCH 0905/3725] another fix to display type handling --- apps/opencs/model/world/columnbase.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/opencs/model/world/columnbase.cpp b/apps/opencs/model/world/columnbase.cpp index 4f51fcad6..17e4def2f 100644 --- a/apps/opencs/model/world/columnbase.cpp +++ b/apps/opencs/model/world/columnbase.cpp @@ -75,6 +75,8 @@ bool CSMWorld::ColumnBase::isId (Display display) Display_Texture, Display_Video, + Display_Id, + Display_None }; From 433e29f297adf6c34ccf3e1883583b6297789f23 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 10 Apr 2015 14:34:57 +0200 Subject: [PATCH 0906/3725] MorphGeometry optimizations: static bounding box and vertices updated during cull traversal --- components/nifosg/nifloader.cpp | 101 ++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index b077c32ff..9df27df32 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -379,6 +379,17 @@ namespace // Note: this assumes only one cull thread is using the given RigGeometry, there would be a race condition otherwise. struct UpdateRigGeometry : public osg::Drawable::CullCallback { + UpdateRigGeometry() + { + } + + UpdateRigGeometry(const UpdateRigGeometry& copy, const osg::CopyOp& copyop) + : osg::Drawable::CullCallback(copy, copyop) + { + } + + META_Object(NifOsg, UpdateRigGeometry) + virtual bool cull(osg::NodeVisitor *, osg::Drawable * drw, osg::State *) const { osgAnimation::RigGeometry* geom = static_cast(drw); @@ -412,6 +423,59 @@ namespace } }; + // Same for MorphGeometry + struct UpdateMorphGeometry : public osg::Drawable::CullCallback + { + UpdateMorphGeometry() + { + } + + UpdateMorphGeometry(const UpdateMorphGeometry& copy, const osg::CopyOp& copyop) + : osg::Drawable::CullCallback(copy, copyop) + { + } + + META_Object(NifOsg, UpdateMorphGeometry) + + virtual bool cull(osg::NodeVisitor *, osg::Drawable * drw, osg::State *) const + { + osgAnimation::MorphGeometry* geom = static_cast(drw); + if (!geom) + return false; + geom->transformSoftwareMethod(); + return false; + } + }; + + // Callback to return a static bounding box for a MorphGeometry. The idea is to not recalculate the bounding box + // every time the morph weights change. To do so we return a maximum containing box that is big enough for all possible combinations of morph targets. + class StaticBoundingBoxCallback : public osg::Drawable::ComputeBoundingBoxCallback + { + public: + StaticBoundingBoxCallback() + { + } + + StaticBoundingBoxCallback(const osg::BoundingBox& bounds) + : mBoundingBox(bounds) + { + } + + StaticBoundingBoxCallback(const StaticBoundingBoxCallback& copy, const osg::CopyOp& copyop) + : osg::Drawable::ComputeBoundingBoxCallback(copy, copyop) + , mBoundingBox(copy.mBoundingBox) + { + } + + virtual osg::BoundingBox computeBound(const osg::Drawable& drawable) const + { + return mBoundingBox; + } + + private: + osg::BoundingBox mBoundingBox; + }; + class RigBoundingBoxCallback : public osg::Drawable::ComputeBoundingBoxCallback { public: @@ -1279,7 +1343,12 @@ namespace NifOsg // No normals available in the MorphData morphGeom->setMorphNormals(false); + morphGeom->setUpdateCallback(NULL); + morphGeom->setCullCallback(new UpdateMorphGeometry); + const std::vector& morphs = morpher->data.getPtr()->mMorphs; + if (!morphs.size()) + return morphGeom; // Note we are not interested in morph 0, which just contains the original vertices for (unsigned int i = 1; i < morphs.size(); ++i) { @@ -1287,6 +1356,38 @@ namespace NifOsg morphTarget->setVertexArray(new osg::Vec3Array(morphs[i].mVertices.size(), &morphs[i].mVertices[0])); morphGeom->addMorphTarget(morphTarget, 0.f); } + + // build the bounding box containing all possible morph combinations + + std::vector vertBounds(morphs[0].mVertices.size()); + + // Since we don't know what combinations of morphs are being applied we need to keep track of a bounding box for each vertex. + // The minimum/maximum of the box is the minimum/maximum offset the vertex can have from its starting position. + + // Start with zero offsets which will happen when no morphs are applied. + for (unsigned int i=0; isetComputeBoundingBoxCallback(new StaticBoundingBoxCallback(box)); + return morphGeom; } From 642c1d2d3627ab7d29f959d6e09f4b7448254987 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 10 Apr 2015 15:31:19 +0200 Subject: [PATCH 0907/3725] Build fix --- apps/openmw/mwclass/static.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/apps/openmw/mwclass/static.cpp b/apps/openmw/mwclass/static.cpp index dbbe7e43a..834ce129e 100644 --- a/apps/openmw/mwclass/static.cpp +++ b/apps/openmw/mwclass/static.cpp @@ -19,11 +19,8 @@ namespace MWClass void Static::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { - MWWorld::LiveCellRef *ref = - ptr.get(); - if (!model.empty()) { - renderingInterface.getObjects().insertModel(ptr, model, !ref->mBase->mPersistent); + renderingInterface.getObjects().insertModel(ptr, model); } } From 591a35b8d717161bd1974ecc57eb63146efaee05 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 10 Apr 2015 23:16:17 +0200 Subject: [PATCH 0908/3725] *very* early version of the LightManager --- components/CMakeLists.txt | 2 +- components/nifosg/nifloader.cpp | 43 +--- components/sceneutil/attach.cpp | 59 ++--- components/sceneutil/lightmanager.cpp | 309 ++++++++++++++++++++++++++ components/sceneutil/lightmanager.hpp | 105 +++++++++ components/sceneutil/util.cpp | 36 +++ components/sceneutil/util.hpp | 17 ++ components/sceneutil/visitor.hpp | 37 +++ 8 files changed, 542 insertions(+), 66 deletions(-) create mode 100644 components/sceneutil/lightmanager.cpp create mode 100644 components/sceneutil/lightmanager.hpp create mode 100644 components/sceneutil/util.cpp create mode 100644 components/sceneutil/util.hpp create mode 100644 components/sceneutil/visitor.hpp diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 1debf3495..abce7020c 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -39,7 +39,7 @@ add_component_dir (resource ) add_component_dir (sceneutil - clone attach + clone attach lightmanager visitor util ) add_component_dir (nif diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 9df27df32..a5c9b6e2a 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -41,6 +41,7 @@ #include #include +#include #include "particle.hpp" #include "userdata.hpp" @@ -467,7 +468,9 @@ namespace { } - virtual osg::BoundingBox computeBound(const osg::Drawable& drawable) const + META_Object(NifOsg, StaticBoundingBoxCallback) + + virtual osg::BoundingBox computeBound(const osg::Drawable&) const { return mBoundingBox; } @@ -497,37 +500,6 @@ namespace mBoundSpheres[bonename] = sphere; } - // based off code in osg::Transform - void transformBoundingSphere (const osg::Matrix& matrix, osg::BoundingSphere& bsphere) const - { - osg::BoundingSphere::vec_type xdash = bsphere._center; - xdash.x() += bsphere._radius; - xdash = xdash*matrix; - - osg::BoundingSphere::vec_type ydash = bsphere._center; - ydash.y() += bsphere._radius; - ydash = ydash*matrix; - - osg::BoundingSphere::vec_type zdash = bsphere._center; - zdash.z() += bsphere._radius; - zdash = zdash*matrix; - - bsphere._center = bsphere._center*matrix; - - xdash -= bsphere._center; - osg::BoundingSphere::value_type len_xdash = xdash.length(); - - ydash -= bsphere._center; - osg::BoundingSphere::value_type len_ydash = ydash.length(); - - zdash -= bsphere._center; - osg::BoundingSphere::value_type len_zdash = zdash.length(); - - bsphere._radius = len_xdash; - if (bsphere._radiusfirst; osg::BoundingSphere bs = it->second; - transformBoundingSphere(bone->getMatrixInSkeletonSpace(), bs); + SceneUtil::transformBoundingSphere(bone->getMatrixInSkeletonSpace(), bs); box.expandBy(bs); } @@ -776,7 +748,6 @@ namespace NifOsg osgAnimation::Bone* bone = new osgAnimation::Bone; transformNode = bone; bone->setMatrix(toMatrix(nifNode->trafo)); - bone->setName(nifNode->name); bone->setInvBindMatrixInSkeletonSpace(osg::Matrixf::inverse(getWorldTransform(nifNode))); } else @@ -788,14 +759,14 @@ namespace NifOsg transformNode->addCullCallback(new BillboardCallback); } + transformNode->setName(nifNode->name); + if (parentNode) parentNode->addChild(transformNode); if (!rootNode) rootNode = transformNode; - // Ignoring name for non-bone nodes for now. We might need it later in isolated cases, e.g. AttachLight. - // UserData used for a variety of features: // - finding the correct emitter node for a particle system // - establishing connections to the animated collision shapes, which are handled in a separate loader diff --git a/components/sceneutil/attach.cpp b/components/sceneutil/attach.cpp index 6208d0152..47efe986c 100644 --- a/components/sceneutil/attach.cpp +++ b/components/sceneutil/attach.cpp @@ -12,40 +12,39 @@ #include #include +#include "visitor.hpp" + namespace SceneUtil { - class FindByNameVisitor : public osg::NodeVisitor + class NodeMapVisitor : public osg::NodeVisitor { public: - FindByNameVisitor(const std::string& nameToFind) - : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) - , mNameToFind(nameToFind) - , mFoundNode(NULL) + NodeMapVisitor() : osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {} + + void apply(osg::MatrixTransform& trans) { + mMap[trans.getName()] = &trans; + traverse(trans); } - virtual void apply(osg::Node &node) + typedef std::map > NodeMap; + + const NodeMap& getNodeMap() const { - osg::Group* group = node.asGroup(); - if (group && node.getName() == mNameToFind) - { - mFoundNode = group; - return; - } - traverse(node); + return mMap; } - const std::string& mNameToFind; - osg::Group* mFoundNode; + private: + NodeMap mMap; }; - /// Copy the skeleton-space matrix of a "source" bone to a "dest" bone (the bone that the callback is attached to). - /// Must be set on a Bone. + /// Copy the matrix of a "source" node to a "dest" node (the node that the callback is attached to). + /// Must be set on a MatrixTransform. class CopyController : public osg::NodeCallback { public: - CopyController(osgAnimation::Bone* copyFrom) + CopyController(osg::MatrixTransform* copyFrom) : mCopyFrom(copyFrom) { } @@ -66,22 +65,21 @@ namespace SceneUtil if (mCopyFrom) { bone->setMatrix(mCopyFrom->getMatrix()); - bone->setMatrixInSkeletonSpace(mCopyFrom->getMatrixInSkeletonSpace()); } traverse(node, nv); } private: - const osgAnimation::Bone* mCopyFrom; + const osg::MatrixTransform* mCopyFrom; }; class AddCopyControllerVisitor : public osg::NodeVisitor { public: - AddCopyControllerVisitor(const osgAnimation::BoneMap& boneMap) + AddCopyControllerVisitor(const NodeMapVisitor::NodeMap& boneMap) : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) - , mBoneMap(boneMap) + , mNodeMap(boneMap) { } @@ -89,19 +87,23 @@ namespace SceneUtil { if (osgAnimation::Bone* bone = dynamic_cast(&node)) { - osgAnimation::BoneMap::const_iterator found = mBoneMap.find(bone->getName()); - if (found != mBoneMap.end()) + NodeMapVisitor::NodeMap::const_iterator found = mNodeMap.find(bone->getName()); + if (found != mNodeMap.end()) { + // add the CopyController at position 0 so it's executed before UpdateBone + osg::ref_ptr old = bone->getUpdateCallback(); bone->setUpdateCallback(new CopyController(found->second.get())); + bone->addUpdateCallback(old); } } } private: - const osgAnimation::BoneMap& mBoneMap; + const NodeMapVisitor::NodeMap& mNodeMap; }; // FIXME: would be more efficient to copy only the wanted nodes instead of deleting unwanted ones later + // copying is kinda cheap though, so don't bother for now class FilterVisitor : public osg::NodeVisitor { public: @@ -137,13 +139,12 @@ namespace SceneUtil { if (osgAnimation::Skeleton* skel = dynamic_cast(toAttach.get())) { - osgAnimation::Skeleton* masterSkel = dynamic_cast(master); - osgAnimation::BoneMapVisitor boneMapVisitor; - masterSkel->accept(boneMapVisitor); + NodeMapVisitor nodeMapVisitor; + master->accept(nodeMapVisitor); // would be more efficient if we could attach the RigGeometry directly to the master skeleton, but currently not possible // due to a difference in binding pose of the two skeletons - AddCopyControllerVisitor visitor(boneMapVisitor.getBoneMap()); + AddCopyControllerVisitor visitor(nodeMapVisitor.getNodeMap()); toAttach->accept(visitor); FilterVisitor filterVisitor(filter); diff --git a/components/sceneutil/lightmanager.cpp b/components/sceneutil/lightmanager.cpp new file mode 100644 index 000000000..c49cf77b8 --- /dev/null +++ b/components/sceneutil/lightmanager.cpp @@ -0,0 +1,309 @@ +#include "lightmanager.hpp" + +#include +#include + +#include + +#include + +#include + +#include +#include + +namespace SceneUtil +{ + + class LightStateAttribute : public osg::Light + { + public: + LightStateAttribute() {} + + LightStateAttribute(const LightStateAttribute& light,const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY) + : osg::Light(light,copyop) {} + + LightStateAttribute(const osg::Light& light,const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY) + : osg::Light(light,copyop) {} + + + META_StateAttribute(NifOsg, LightStateAttribute, osg::StateAttribute::LIGHT) + + virtual void apply(osg::State& state) const + { + osg::Matrix modelViewMatrix = state.getModelViewMatrix(); + + // FIXME: we shouldn't have to apply the modelview matrix after every light + // this could be solvable by having the LightStateAttribute contain all lights instead of just one. + state.applyModelViewMatrix(state.getInitialViewMatrix()); + + osg::Light::apply(state); + + state.setGlobalDefaultAttribute(this); + + state.applyModelViewMatrix(modelViewMatrix); + } + }; + + class CullCallback : public osg::NodeCallback + { + public: + CullCallback() + : mLightManager(NULL) + {} + CullCallback(const CullCallback& copy, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY) + : osg::Object(copy, copyop), osg::NodeCallback(copy, copyop), mLightManager(copy.mLightManager) + {} + CullCallback(LightManager* lightManager) + : mLightManager(lightManager) + {} + + META_Object(NifOsg, CullCallback) + + void operator()(osg::Node* node, osg::NodeVisitor* nv) + { + osgUtil::CullVisitor* cv = static_cast(nv); + + mLightManager->prepareForCamera(cv->getCurrentCamera()); + + // Possible optimizations: + // - cull list of lights by the camera frustum + // - organize lights in a quad tree + + const std::vector& lights = mLightManager->getLights(); + + if (lights.size()) + { + // we do the intersections in view space + osg::BoundingSphere nodeBound = node->getBound(); + osg::Matrixf mat = *cv->getModelViewMatrix(); + transformBoundingSphere(mat, nodeBound); + + std::vector lightList; + for (unsigned int i=0; i 8) + { + //std::cerr << "More than 8 lights!" << std::endl; + + // TODO: sort lights by certain criteria + + while (lightList.size() > 8) + lightList.pop_back(); + } + + osg::ref_ptr stateset = mLightManager->getLightListStateSet(lightList); + + cv->pushStateSet(stateset); + + traverse(node, nv); + + cv->popStateSet(); + } + else + traverse(node, nv); + } + + private: + LightManager* mLightManager; + }; + + class AttachCullCallbackVisitor : public osg::NodeVisitor + { + public: + AttachCullCallbackVisitor(LightManager* lightManager) + : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) + , mLightManager(lightManager) + { + } + + virtual void apply(osg::Geode &geode) + { + if (!geode.getNumParents()) + return; + + // Not working on a Geode. Drawables are not normal children of the Geode, the traverse() call + // does not traverse the drawables, so the push/pop in the CullCallback has no effect + // Should be no longer an issue with osg trunk + osg::Node* parent = geode.getParent(0); + parent->addCullCallback(new CullCallback(mLightManager)); + } + + private: + LightManager* mLightManager; + }; + + // Set on a LightSource. Adds the light source to its light manager for the current frame. + // This allows us to keep track of the current lights in the scene graph without tying creation & destruction to the manager. + class CollectLightCallback : public osg::NodeCallback + { + public: + CollectLightCallback() + : mLightManager(0) { } + + CollectLightCallback(const CollectLightCallback& copy, const osg::CopyOp& copyop) + : osg::NodeCallback(copy, copyop) + , mLightManager(0) { } + + META_Object(SceneUtil, SceneUtil::CollectLightCallback) + + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) + { + if (!mLightManager) + { + for (unsigned int i=0;igetNodePath().size(); ++i) + { + if (LightManager* lightManager = dynamic_cast(nv->getNodePath()[i])) + { + mLightManager = lightManager; + break; + } + } + if (!mLightManager) + throw std::runtime_error("can't find parent LightManager"); + } + + mLightManager->addLight(static_cast(node), osg::computeLocalToWorld(nv->getNodePath())); + + traverse(node, nv); + } + + private: + LightManager* mLightManager; + }; + + // Set on a LightManager. Clears the data from the previous frame. + class LightManagerUpdateCallback : public osg::NodeCallback + { + public: + LightManagerUpdateCallback() + { } + + LightManagerUpdateCallback(const LightManagerUpdateCallback& copy, const osg::CopyOp& copyop) + : osg::NodeCallback(copy, copyop) + { } + + META_Object(SceneUtil, SceneUtil::LightManagerUpdateCallback) + + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) + { + LightManager* lightManager = static_cast(node); + lightManager->update(); + + traverse(node, nv); + } + }; + + LightManager::LightManager() + : mLightsInViewSpace(false) + , mDecorated(false) + { + setUpdateCallback(new LightManagerUpdateCallback); + } + + LightManager::LightManager(const LightManager ©, const osg::CopyOp ©op) + : osg::Group(copy, copyop) + , mLightsInViewSpace(false) + , mDecorated(copy.mDecorated) + { + + } + + void LightManager::decorateGeodes() + { + AttachCullCallbackVisitor visitor(this); + accept(visitor); + } + + void LightManager::update() + { + mLightsInViewSpace = false; + mLights.clear(); + mStateSetCache.clear(); + + if (!mDecorated) + { + decorateGeodes(); + mDecorated = true; + } + } + + void LightManager::addLight(LightSource* lightSource, osg::Matrix worldMat) + { + LightSourceTransform l; + l.mLightSource = lightSource; + l.mWorldMatrix = worldMat; + mLights.push_back(l); + } + + void LightManager::prepareForCamera(osg::Camera *cam) + { + // later on we need to store this per camera + if (!mLightsInViewSpace) + { + for (std::vector::iterator it = mLights.begin(); it != mLights.end(); ++it) + { + LightSourceTransform& l = *it; + osg::Matrix worldViewMat = l.mWorldMatrix * cam->getViewMatrix(); + l.mViewBound = osg::BoundingSphere(osg::Vec3f(0,0,0), l.mLightSource->getRadius()); + transformBoundingSphere(worldViewMat, l.mViewBound); + } + mLightsInViewSpace = true; + } + } + + osg::ref_ptr LightManager::getLightListStateSet(const LightList &lightList) + { + // possible optimization: return a StateSet containing all requested lights plus some extra lights (if a suitable one exists) + size_t hash = 0; + for (unsigned int i=0; isecond; + else + { + osg::ref_ptr stateset (new osg::StateSet); + for (unsigned int i=0; igetLight(); + + osg::ref_ptr clonedLight = new LightStateAttribute(*light, osg::CopyOp::DEEP_COPY_ALL); + clonedLight->setPosition(mLights[lightIndex].mWorldMatrix.preMult(light->getPosition())); + + clonedLight->setLightNum(i); + + // don't use setAttributeAndModes, that does not support light indices! + stateset->setAttribute(clonedLight, osg::StateAttribute::ON); + stateset->setAssociatedModes(clonedLight, osg::StateAttribute::ON); + } + mStateSetCache.insert(std::make_pair(hash, stateset)); + return stateset; + } + } + + const std::vector& LightManager::getLights() const + { + return mLights; + } + + LightSource::LightSource() + : mRadius(0.f) + { + setUpdateCallback(new CollectLightCallback); + } + +} diff --git a/components/sceneutil/lightmanager.hpp b/components/sceneutil/lightmanager.hpp new file mode 100644 index 000000000..ccb6603a6 --- /dev/null +++ b/components/sceneutil/lightmanager.hpp @@ -0,0 +1,105 @@ +#ifndef OPENMW_COMPONENTS_SCENEUTIL_LIGHTMANAGER_H +#define OPENMW_COMPONENTS_SCENEUTIL_LIGHTMANAGER_H + +#include + +#include +#include + +namespace SceneUtil +{ + + /// LightSource managed by a LightManager. + class LightSource : public osg::Node + { + osg::ref_ptr mLight; + + // The activation radius + float mRadius; + + public: + + META_Node(SceneUtil, SceneUtil::LightSource) + + LightSource(); + + LightSource(const LightSource& copy, const osg::CopyOp& copyop) + : osg::Node(copy, copyop) + , mLight(copy.mLight) + , mRadius(copy.mRadius) + { + } + + float getRadius() const + { + return mRadius; + } + + void setRadius(float radius) + { + mRadius = radius; + } + + osg::Light* getLight() + { + return mLight; + } + + void setLight(osg::Light* light) + { + mLight = light; + } + }; + + /// All light sources must be a child of the LightManager node. The LightManager can be anywhere in the scene graph, + /// but would be typically somewhere near the top. + class LightManager : public osg::Group + { + public: + + META_Node(SceneUtil, SceneUtil::LightManager) + + LightManager(); + + LightManager(const LightManager& copy, const osg::CopyOp& copyop); + + // Called automatically by the UpdateCallback + void update(); + + // Called automatically by the LightSource's UpdateCallback + void addLight(LightSource* lightSource, osg::Matrix worldMat); + + void prepareForCamera(osg::Camera* cam); + + void decorateGeodes(); + + struct LightSourceTransform + { + LightSource* mLightSource; + osg::Matrix mWorldMatrix; + osg::BoundingSphere mViewBound; + }; + + const std::vector& getLights() const; + + // Stores indices into the mLights vector + typedef std::vector LightList; + + osg::ref_ptr getLightListStateSet(const LightList& lightList); + + private: + // Lights collected from the scene graph. Only valid during the cull traversal. + std::vector mLights; + + bool mLightsInViewSpace; + + // < Light list hash , StateSet > + typedef std::map > LightStateSetMap; + LightStateSetMap mStateSetCache; + + bool mDecorated; + }; + +} + +#endif diff --git a/components/sceneutil/util.cpp b/components/sceneutil/util.cpp new file mode 100644 index 000000000..0d99e762d --- /dev/null +++ b/components/sceneutil/util.cpp @@ -0,0 +1,36 @@ +#include "util.hpp" + +namespace SceneUtil +{ + +void transformBoundingSphere (const osg::Matrix& matrix, osg::BoundingSphere& bsphere) +{ + osg::BoundingSphere::vec_type xdash = bsphere._center; + xdash.x() += bsphere._radius; + xdash = xdash*matrix; + + osg::BoundingSphere::vec_type ydash = bsphere._center; + ydash.y() += bsphere._radius; + ydash = ydash*matrix; + + osg::BoundingSphere::vec_type zdash = bsphere._center; + zdash.z() += bsphere._radius; + zdash = zdash*matrix; + + bsphere._center = bsphere._center*matrix; + + xdash -= bsphere._center; + osg::BoundingSphere::value_type len_xdash = xdash.length(); + + ydash -= bsphere._center; + osg::BoundingSphere::value_type len_ydash = ydash.length(); + + zdash -= bsphere._center; + osg::BoundingSphere::value_type len_zdash = zdash.length(); + + bsphere._radius = len_xdash; + if (bsphere._radius +#include + +namespace SceneUtil +{ + + // Transform a bounding sphere by a matrix + // based off private code in osg::Transform + // TODO: patch osg to make public + void transformBoundingSphere (const osg::Matrix& matrix, osg::BoundingSphere& bsphere); + +} + +#endif diff --git a/components/sceneutil/visitor.hpp b/components/sceneutil/visitor.hpp new file mode 100644 index 000000000..59c706f11 --- /dev/null +++ b/components/sceneutil/visitor.hpp @@ -0,0 +1,37 @@ +#ifndef OPENMW_COMPONENTS_SCENEUTIL_VISITOR_H +#define OPENMW_COMPONENTS_SCENEUTIL_VISITOR_H + +#include + +// Commonly used scene graph visitors +namespace SceneUtil +{ + + class FindByNameVisitor : public osg::NodeVisitor + { + public: + FindByNameVisitor(const std::string& nameToFind) + : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) + , mNameToFind(nameToFind) + , mFoundNode(NULL) + { + } + + virtual void apply(osg::Node &node) + { + osg::Group* group = node.asGroup(); + if (group && node.getName() == mNameToFind) + { + mFoundNode = group; + return; + } + traverse(node); + } + + const std::string& mNameToFind; + osg::Group* mFoundNode; + }; + +} + +#endif From 1220369da3abb6ed4f065908de6fa42df5df51e4 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 11 Apr 2015 11:26:29 +1000 Subject: [PATCH 0909/3725] Changes as per feedback comments. --- apps/opencs/model/world/collection.hpp | 12 +-- apps/opencs/model/world/columnbase.cpp | 7 +- apps/opencs/model/world/columnbase.hpp | 1 - apps/opencs/model/world/columnimp.hpp | 81 ++++--------------- apps/opencs/model/world/columns.cpp | 6 -- apps/opencs/model/world/commands.cpp | 8 +- apps/opencs/model/world/data.cpp | 14 ++-- apps/opencs/model/world/idadapter.hpp | 2 +- apps/opencs/model/world/idadapterimp.hpp | 4 +- apps/opencs/model/world/nestedadapters.hpp | 4 +- apps/opencs/model/world/refidadapter.cpp | 2 +- apps/opencs/model/world/refidadapter.hpp | 4 +- apps/opencs/model/world/refidcollection.cpp | 7 +- apps/opencs/model/world/refidcollection.hpp | 2 +- apps/opencs/model/world/subcellcollection.hpp | 48 +++++++---- 15 files changed, 77 insertions(+), 125 deletions(-) diff --git a/apps/opencs/model/world/collection.hpp b/apps/opencs/model/world/collection.hpp index 4bc9632a8..b0571bbed 100644 --- a/apps/opencs/model/world/collection.hpp +++ b/apps/opencs/model/world/collection.hpp @@ -120,8 +120,6 @@ namespace CSMWorld virtual const Record& getRecord (int index) const; - virtual Record& getRecord (int index); - virtual int getAppendIndex (const std::string& id, UniversalId::Type type = UniversalId::Type_None) const; ///< \param type Will be ignored, unless the collection supports multiple record types @@ -151,7 +149,7 @@ namespace CSMWorld void setRecord (int index, const Record& record); ///< \attention This function must not change the ID. - NestableColumn *getNestableColumn (int column); + NestableColumn *getNestableColumn (int column) const; }; template @@ -294,7 +292,7 @@ namespace CSMWorld } template - NestableColumn *Collection::getNestableColumn (int column) + NestableColumn *Collection::getNestableColumn (int column) const { if (column < 0 || column >= static_cast(mColumns.size())) throw std::runtime_error("column index out of range"); @@ -435,12 +433,6 @@ namespace CSMWorld return mRecords.at (index); } - template - Record& Collection::getRecord (int index) - { - return mRecords.at (index); - } - template void Collection::insertRecord (const RecordBase& record, int index, UniversalId::Type type) diff --git a/apps/opencs/model/world/columnbase.cpp b/apps/opencs/model/world/columnbase.cpp index e4d2195be..8d1985ff2 100644 --- a/apps/opencs/model/world/columnbase.cpp +++ b/apps/opencs/model/world/columnbase.cpp @@ -26,12 +26,11 @@ int CSMWorld::ColumnBase::getId() const void CSMWorld::NestableColumn::addColumn(CSMWorld::NestableColumn *column) { mNestedColumns.push_back(column); - mHasChildren = true; } const CSMWorld::ColumnBase& CSMWorld::NestableColumn::nestedColumn(int subColumn) const { - if (!mHasChildren) + if (mNestedColumns.empty()) throw std::logic_error("Tried to access nested column of the non-nest column"); return *mNestedColumns.at(subColumn); @@ -39,7 +38,7 @@ const CSMWorld::ColumnBase& CSMWorld::NestableColumn::nestedColumn(int subColumn CSMWorld::NestableColumn::NestableColumn(int columnId, CSMWorld::ColumnBase::Display displayType, int flag) - : mHasChildren(false), CSMWorld::ColumnBase(columnId, displayType, flag) + : CSMWorld::ColumnBase(columnId, displayType, flag) { } @@ -53,5 +52,5 @@ CSMWorld::NestableColumn::~NestableColumn() bool CSMWorld::NestableColumn::hasChildren() const { - return mHasChildren; + return !mNestedColumns.empty(); } diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index aef68fdbd..e6799cf56 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -137,7 +137,6 @@ namespace CSMWorld class NestableColumn : public ColumnBase { std::vector mNestedColumns; - bool mHasChildren; public: diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index 70c134e01..3fb9a4685 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -2271,64 +2271,39 @@ namespace CSMWorld PathgridPointListColumn () : Column (Columns::ColumnId_PathgridPoints, ColumnBase::Display_PathgridPointList, ColumnBase::Flag_Dialogue) - { - } + {} virtual QVariant get (const Record& record) const { return true; // required by IdTree::hasChildren() } - virtual void set (Record& record, const QVariant& data) - { - } - virtual bool isEditable() const { return true; } }; - template - struct PathgridIndexColumn : public Column + struct PathgridIndexColumn : public NestableColumn { PathgridIndexColumn() - : Column (Columns::ColumnId_PathgridIndex, ColumnBase::Display_Integer) + : NestableColumn (Columns::ColumnId_PathgridIndex, + ColumnBase::Display_Integer, ColumnBase::Flag_Dialogue) {} - virtual QVariant get (const Record& record) const - { - return QVariant(); // FIXME - } - - virtual void set (Record& record, const QVariant& data) - { - } - virtual bool isEditable() const { return false; } }; - template - struct PathgridPointColumn : public Column + struct PathgridPointColumn : public NestableColumn { - int mIndex; // 0=PosX, 1=PosY, 2=PosZ - PathgridPointColumn(int index) - : Column (Columns::ColumnId_PathgridPosX+index, ColumnBase::Display_Integer), mIndex(index) + : NestableColumn (Columns::ColumnId_PathgridPosX+index, + ColumnBase::Display_Integer, ColumnBase::Flag_Dialogue) {} - virtual QVariant get (const Record& record) const - { - return QVariant(); // FIXME - } - - virtual void set (Record& record, const QVariant& data) - { - } - virtual bool isEditable() const { return true; @@ -2341,18 +2316,13 @@ namespace CSMWorld PathgridEdgeListColumn () : Column (Columns::ColumnId_PathgridEdges, ColumnBase::Display_PathgridEdgeList, ColumnBase::Flag_Dialogue) - { - } + {} virtual QVariant get (const Record& record) const { return true; // required by IdTree::hasChildren() } - virtual void set (Record& record, const QVariant& data) - { - } - virtual bool isEditable() const { return true; @@ -2360,46 +2330,25 @@ namespace CSMWorld }; - template - struct PathgridEdgeIndexColumn : public Column + struct PathgridEdgeIndexColumn : public NestableColumn { PathgridEdgeIndexColumn() - : Column (Columns::ColumnId_PathgridEdgeIndex, ColumnBase::Display_Integer) + : NestableColumn (Columns::ColumnId_PathgridEdgeIndex, + ColumnBase::Display_Integer, ColumnBase::Flag_Dialogue) {} - virtual QVariant get (const Record& record) const - { - return QVariant(); // FIXME - } - - virtual void set (Record& record, const QVariant& data) - { - } - virtual bool isEditable() const { return false; } }; - template - struct PathgridEdgeColumn : public Column + struct PathgridEdgeColumn : public NestableColumn { - int mIndex; - PathgridEdgeColumn (int index) - : Column (Columns::ColumnId_PathgridEdge0+index, ColumnBase::Display_Integer), mIndex(index) - { - } - - virtual QVariant get (const Record& record) const - { - return QVariant(); // FIXME - } - - virtual void set (Record& record, const QVariant& data) - { - } + : NestableColumn (Columns::ColumnId_PathgridEdge0+index, + ColumnBase::Display_Integer, ColumnBase::Flag_Dialogue) + {} virtual bool isEditable() const { diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index e6a27138f..b65cf7f96 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -287,11 +287,6 @@ int CSMWorld::Columns::getId (const std::string& name) namespace { - static const char *sSkills[] = - { - "Long Blade" - }; - static const char *sSpecialisations[] = { "Combat", "Magic", "Stealth", 0 @@ -394,7 +389,6 @@ namespace switch (column) { case CSMWorld::Columns::ColumnId_Specialisation: return sSpecialisations; - case CSMWorld::Columns::ColumnId_Skill: return sSkills; case CSMWorld::Columns::ColumnId_Attribute: return sAttributes; case CSMWorld::Columns::ColumnId_SpellType: return sSpellTypes; case CSMWorld::Columns::ColumnId_ApparatusType: return sApparatusTypes; diff --git a/apps/opencs/model/world/commands.cpp b/apps/opencs/model/world/commands.cpp index 7acc6058e..d12c5d228 100644 --- a/apps/opencs/model/world/commands.cpp +++ b/apps/opencs/model/world/commands.cpp @@ -185,7 +185,9 @@ CSMWorld::DeleteNestedCommand::DeleteNestedCommand (IdTree& model, mNestedRow(nestedRow), NestedTableStoring(model, id, parentColumn) { - setText (("Delete nested row in " + mId).c_str()); + std::string title = + model.headerData(parentColumn, Qt::Horizontal, Qt::DisplayRole).toString().toUtf8().constData(); + setText (("Delete row in " + title + " sub-table of " + mId).c_str()); } void CSMWorld::DeleteNestedCommand::redo() @@ -211,7 +213,9 @@ CSMWorld::AddNestedCommand::AddNestedCommand(IdTree& model, const std::string& i QUndoCommand(parent), NestedTableStoring(model, id, parentColumn) { - setText (("Added nested row in " + mId).c_str()); + std::string title = + model.headerData(parentColumn, Qt::Horizontal, Qt::DisplayRole).toString().toUtf8().constData(); + setText (("Add row in " + title + " sub-table of " + mId).c_str()); } void CSMWorld::AddNestedCommand::redo() diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 76e34961f..87d5116f1 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -263,17 +263,17 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mPathgrids.addAdapter (std::make_pair(pointList, new PathgridPointListAdapter ())); // new objects deleted in dtor of NestableColumn // WARNING: The order of the columns below are assumed in PathgridPointListAdapter - mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn(new PathgridIndexColumn ()); - mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn(new PathgridPointColumn (0)); - mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn(new PathgridPointColumn (1)); - mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn(new PathgridPointColumn (2)); + mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn(new PathgridIndexColumn ()); + mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn(new PathgridPointColumn (0)); + mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn(new PathgridPointColumn (1)); + mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn(new PathgridPointColumn (2)); PathgridEdgeListColumn *edgeList = new PathgridEdgeListColumn (); mPathgrids.addColumn (edgeList); mPathgrids.addAdapter (std::make_pair(edgeList, new PathgridEdgeListAdapter ())); - mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn(new PathgridEdgeIndexColumn ()); - mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn(new PathgridEdgeColumn (0)); - mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn(new PathgridEdgeColumn (1)); + mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn(new PathgridEdgeIndexColumn ()); + mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn(new PathgridEdgeColumn (0)); + mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn(new PathgridEdgeColumn (1)); mStartScripts.addColumn (new StringIdColumn); mStartScripts.addColumn (new RecordStateColumn); diff --git a/apps/opencs/model/world/idadapter.hpp b/apps/opencs/model/world/idadapter.hpp index 753ac01f0..84ef2d1f8 100644 --- a/apps/opencs/model/world/idadapter.hpp +++ b/apps/opencs/model/world/idadapter.hpp @@ -22,7 +22,7 @@ namespace CSMWorld virtual void removeNestedRow(Record& record, int rowToRemove) const = 0; - virtual void setNestedTable(Record& record, const NestedTableWrapperBase& nestedTable) = 0; + virtual void setNestedTable(Record& record, const NestedTableWrapperBase& nestedTable) const = 0; virtual NestedTableWrapperBase* nestedTable(const Record& record) const = 0; diff --git a/apps/opencs/model/world/idadapterimp.hpp b/apps/opencs/model/world/idadapterimp.hpp index 746815414..2ce0777ac 100644 --- a/apps/opencs/model/world/idadapterimp.hpp +++ b/apps/opencs/model/world/idadapterimp.hpp @@ -102,7 +102,7 @@ namespace CSMWorld } }; - virtual void setNestedTable(Record& record, const NestedTableWrapperBase& nestedTable) + virtual void setNestedTable(Record& record, const NestedTableWrapperBase& nestedTable) const { record.get().mPoints = static_cast(nestedTable).mRecord.mPoints; @@ -204,7 +204,7 @@ namespace CSMWorld record.setModified (pathgrid); } - virtual void setNestedTable(Record& record, const NestedTableWrapperBase& nestedTable) + virtual void setNestedTable(Record& record, const NestedTableWrapperBase& nestedTable) const { record.get().mEdges = static_cast &>(nestedTable).mNestedTable; diff --git a/apps/opencs/model/world/nestedadapters.hpp b/apps/opencs/model/world/nestedadapters.hpp index 015765380..97046276f 100644 --- a/apps/opencs/model/world/nestedadapters.hpp +++ b/apps/opencs/model/world/nestedadapters.hpp @@ -145,8 +145,8 @@ namespace CSMWorld { CastableHelper::getRecord(data, index).get().mSpells.mList.at(subRowIndex) = std::string(value.toString().toUtf8()); } - - throw std::logic_error("Trying to access non-existing column in the nested table!"); + else + throw std::logic_error("Trying to access non-existing column in the nested table!"); } virtual void addNestedRow (RefIdData& data, int index, int position) const diff --git a/apps/opencs/model/world/refidadapter.cpp b/apps/opencs/model/world/refidadapter.cpp index 58b775f47..a12a95196 100644 --- a/apps/opencs/model/world/refidadapter.cpp +++ b/apps/opencs/model/world/refidadapter.cpp @@ -57,7 +57,7 @@ void CSMWorld::NestedRefIdAdapter::addNestedRow (const RefIdColumn *column, RefI getHelper(column)->addNestedRow(data, index, position); //This code grows more boring and boring. I would love some macros. } -void CSMWorld::NestedRefIdAdapter::setNestedTable (const RefIdColumn* column, RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) +void CSMWorld::NestedRefIdAdapter::setNestedTable (const RefIdColumn* column, RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const { getHelper(column)->setNestedTable(data, index, nestedTable); } diff --git a/apps/opencs/model/world/refidadapter.hpp b/apps/opencs/model/world/refidadapter.hpp index 91f19577b..1a3f2700e 100644 --- a/apps/opencs/model/world/refidadapter.hpp +++ b/apps/opencs/model/world/refidadapter.hpp @@ -69,7 +69,7 @@ namespace CSMWorld virtual void addNestedRow (const RefIdColumn *column, RefIdData& data, int index, int position) const = 0; - virtual void setNestedTable (const RefIdColumn* column, RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) = 0; + virtual void setNestedTable (const RefIdColumn* column, RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const = 0; virtual NestedTableWrapperBase* nestedTable (const RefIdColumn* column, const RefIdData& data, int index) const = 0; }; @@ -97,7 +97,7 @@ namespace CSMWorld virtual void addNestedRow (const RefIdColumn *column, RefIdData& data, int index, int position) const; - virtual void setNestedTable (const RefIdColumn* column, RefIdData& data, int index, const NestedTableWrapperBase& nestedTable); + virtual void setNestedTable (const RefIdColumn* column, RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const; virtual NestedTableWrapperBase* nestedTable (const RefIdColumn* column, const RefIdData& data, int index) const; diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 41ca7e440..b85deef4e 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -25,8 +25,7 @@ bool CSMWorld::RefIdColumn::isUserEditable() const return mUserEditable; } -// FIXME: const problem -/*const*/ CSMWorld::RefIdAdapter& CSMWorld::RefIdCollection::findAdapter (UniversalId::Type type) const +const CSMWorld::RefIdAdapter& CSMWorld::RefIdCollection::findAdapter (UniversalId::Type type) const { std::map::const_iterator iter = mAdapters.find (type); @@ -684,10 +683,8 @@ void CSMWorld::RefIdCollection::setNestedTable(int row, int column, const CSMWor { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); - // FIXME: const problem - CSMWorld::NestedRefIdAdapter& adaptor = dynamic_cast(findAdapter (localIndex.second)); + const CSMWorld::NestedRefIdAdapter& adaptor = dynamic_cast(findAdapter (localIndex.second)); - // FIXME: const problem adaptor.setNestedTable(&mColumns.at(column), mData, localIndex.first, nestedTable); } diff --git a/apps/opencs/model/world/refidcollection.hpp b/apps/opencs/model/world/refidcollection.hpp index 5bf7c177e..3315212c1 100644 --- a/apps/opencs/model/world/refidcollection.hpp +++ b/apps/opencs/model/world/refidcollection.hpp @@ -46,7 +46,7 @@ namespace CSMWorld private: - /*const*/ RefIdAdapter& findAdapter (UniversalId::Type) const; + const RefIdAdapter& findAdapter (UniversalId::Type) const; ///< Throws an exception if no adaptor for \a Type can be found. public: diff --git a/apps/opencs/model/world/subcellcollection.hpp b/apps/opencs/model/world/subcellcollection.hpp index 92091cf57..c53c7006a 100644 --- a/apps/opencs/model/world/subcellcollection.hpp +++ b/apps/opencs/model/world/subcellcollection.hpp @@ -32,7 +32,7 @@ namespace CSMWorld virtual void loadRecord (ESXRecordT& record, ESM::ESMReader& reader); - NestedIdAdapter* getAdapter(const ColumnBase &column) const; + const NestedIdAdapter& getAdapter(const ColumnBase &column) const; public: @@ -88,7 +88,7 @@ namespace CSMWorld } template - NestedIdAdapter* SubCellCollection::getAdapter(const ColumnBase &column) const + const NestedIdAdapter& SubCellCollection::getAdapter(const ColumnBase &column) const { typename std::map* >::const_iterator iter = mAdapters.find (&column); @@ -96,28 +96,36 @@ namespace CSMWorld if (iter==mAdapters.end()) throw std::logic_error("No such column in the nestedidadapter"); - return iter->second; + return *iter->second; } template void SubCellCollection::addNestedRow(int row, int column, int position) { - getAdapter(Collection::getColumn(column))->addNestedRow( - Collection::getRecord(row), position); + Record record; + record.assign(Collection::getRecord(row)); + + getAdapter(Collection::getColumn(column)).addNestedRow(record, position); + + Collection::setRecord(row, record); } template void SubCellCollection::removeNestedRows(int row, int column, int subRow) { - getAdapter(Collection::getColumn(column))->removeNestedRow( - Collection::getRecord(row), subRow); + Record record; + record.assign(Collection::getRecord(row)); + + getAdapter(Collection::getColumn(column)).removeNestedRow(record, subRow); + + Collection::setRecord(row, record); } template QVariant SubCellCollection::getNestedData (int row, int column, int subRow, int subColumn) const { - return getAdapter(Collection::getColumn(column))->getNestedData( + return getAdapter(Collection::getColumn(column)).getNestedData( Collection::getRecord(row), subRow, subColumn); } @@ -125,15 +133,20 @@ namespace CSMWorld void SubCellCollection::setNestedData(int row, int column, const QVariant& data, int subRow, int subColumn) { - getAdapter(Collection::getColumn(column))->setNestedData( - Collection::getRecord(row), data, subRow, subColumn); + Record record; + record.assign(Collection::getRecord(row)); + + getAdapter(Collection::getColumn(column)).setNestedData( + record, data, subRow, subColumn); + + Collection::setRecord(row, record); } template CSMWorld::NestedTableWrapperBase* SubCellCollection::nestedTable(int row, int column) const { - return getAdapter(Collection::getColumn(column))->nestedTable( + return getAdapter(Collection::getColumn(column)).nestedTable( Collection::getRecord(row)); } @@ -141,21 +154,26 @@ namespace CSMWorld void SubCellCollection::setNestedTable(int row, int column, const CSMWorld::NestedTableWrapperBase& nestedTable) { - getAdapter(Collection::getColumn(column))->setNestedTable( - Collection::getRecord(row), nestedTable); + Record record; + record.assign(Collection::getRecord(row)); + + getAdapter(Collection::getColumn(column)).setNestedTable( + record, nestedTable); + + Collection::setRecord(row, record); } template int SubCellCollection::getNestedRowsCount(int row, int column) const { - return getAdapter(Collection::getColumn(column))->getNestedRowsCount( + return getAdapter(Collection::getColumn(column)).getNestedRowsCount( Collection::getRecord(row)); } template int SubCellCollection::getNestedColumnsCount(int row, int column) const { - return getAdapter(Collection::getColumn(column))->getNestedColumnsCount( + return getAdapter(Collection::getColumn(column)).getNestedColumnsCount( Collection::getRecord(row)); } From a632b2cfebd8e71e223f74d06dc0cee1d9ff60d9 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 11 Apr 2015 11:27:48 +1000 Subject: [PATCH 0910/3725] Fix editing "ID" column within nested tables in dialogue subview. --- apps/opencs/model/world/idtree.cpp | 45 ++++++++++++------- apps/opencs/model/world/idtree.hpp | 6 ++- .../model/world/nestedtableproxymodel.cpp | 6 ++- .../model/world/nestedtableproxymodel.hpp | 2 + 4 files changed, 41 insertions(+), 18 deletions(-) diff --git a/apps/opencs/model/world/idtree.cpp b/apps/opencs/model/world/idtree.cpp index 952c9e329..49ceced2c 100644 --- a/apps/opencs/model/world/idtree.cpp +++ b/apps/opencs/model/world/idtree.cpp @@ -38,18 +38,26 @@ QVariant CSMWorld::IdTree::data (const QModelIndex & index, int role) const if ((role!=Qt::DisplayRole && role!=Qt::EditRole) || index.row() < 0 || index.column() < 0) return QVariant(); - if (role==Qt::EditRole && !idCollection()->getColumn (index.column()).isEditable()) - return QVariant(); - if (index.internalId() != 0) { - std::pair parentAdress(unfoldIndexAdress(index.internalId())); + std::pair parentAddress(unfoldIndexAddress(index.internalId())); + + if (role == Qt::EditRole && + !mNestedCollection->getNestableColumn(parentAddress.second)->nestedColumn(index.column()).isEditable()) + { + return QVariant(); + } - return mNestedCollection->getNestedData(parentAdress.first, - parentAdress.second, index.row(), index.column()); + return mNestedCollection->getNestedData(parentAddress.first, + parentAddress.second, index.row(), index.column()); } else + { + if (role==Qt::EditRole && !idCollection()->getColumn (index.column()).isEditable()) + return QVariant(); + return idCollection()->getData (index.row(), index.column()); + } } QVariant CSMWorld::IdTree::nestedHeaderData(int section, int subSection, Qt::Orientation orientation, int role) const @@ -80,12 +88,12 @@ bool CSMWorld::IdTree::setData (const QModelIndex &index, const QVariant &value, { if (idCollection()->getColumn(parent(index).column()).isEditable() && role==Qt::EditRole) { - const std::pair& parentAdress(unfoldIndexAdress(index.internalId())); + const std::pair& parentAddress(unfoldIndexAddress(index.internalId())); - mNestedCollection->setNestedData(parentAdress.first, parentAdress.second, value, index.row(), index.column()); + mNestedCollection->setNestedData(parentAddress.first, parentAddress.second, value, index.row(), index.column()); - emit dataChanged (CSMWorld::IdTree::index (parentAdress.first, 0), - CSMWorld::IdTree::index (parentAdress.second, idCollection()->getColumns()-1)); + emit dataChanged (CSMWorld::IdTree::index (parentAddress.first, 0), + CSMWorld::IdTree::index (parentAddress.second, idCollection()->getColumns()-1)); return true; } @@ -145,7 +153,7 @@ QModelIndex CSMWorld::IdTree::index (int row, int column, const QModelIndex& par unsigned int encodedId = 0; if (parent.isValid()) { - encodedId = this->foldIndexAdress(parent); + encodedId = this->foldIndexAddress(parent); } if (row<0 || row>=idCollection()->getSize()) @@ -157,13 +165,18 @@ QModelIndex CSMWorld::IdTree::index (int row, int column, const QModelIndex& par return createIndex(row, column, encodedId); // store internal id } +QModelIndex CSMWorld::IdTree::getNestedModelIndex (const std::string& id, int column) const +{ + return CSMWorld::IdTable::index(idCollection()->getIndex (id), column); +} + QModelIndex CSMWorld::IdTree::parent (const QModelIndex& index) const { if (index.internalId() == 0) // 0 is used for indexs with invalid parent (top level data) return QModelIndex(); unsigned int id = index.internalId(); - const std::pair& adress(unfoldIndexAdress(id)); + const std::pair& adress(unfoldIndexAddress(id)); if (adress.first >= this->rowCount() || adress.second >= this->columnCount()) throw "Parent index is not present in the model"; @@ -171,14 +184,14 @@ QModelIndex CSMWorld::IdTree::parent (const QModelIndex& index) const return createIndex(adress.first, adress.second); } -unsigned int CSMWorld::IdTree::foldIndexAdress (const QModelIndex& index) const +unsigned int CSMWorld::IdTree::foldIndexAddress (const QModelIndex& index) const { unsigned int out = index.row() * this->columnCount(); out += index.column(); return ++out; } -std::pair< int, int > CSMWorld::IdTree::unfoldIndexAdress (unsigned int id) const +std::pair< int, int > CSMWorld::IdTree::unfoldIndexAddress (unsigned int id) const { if (id == 0) throw "Attempt to unfold index id of the top level data cell"; @@ -189,6 +202,8 @@ std::pair< int, int > CSMWorld::IdTree::unfoldIndexAdress (unsigned int id) cons return std::make_pair (row, column); } +// FIXME: Not sure why this check is also needed? +// // index.data().isValid() requires RefIdAdapter::getData() to return a valid QVariant for // nested columns (refidadapterimp.hpp) // @@ -198,7 +213,7 @@ bool CSMWorld::IdTree::hasChildren(const QModelIndex& index) const return (index.isValid() && index.internalId() == 0 && mNestedCollection->getNestableColumn(index.column())->hasChildren() && - index.data().isValid()); // FIXME: not sure why this check is also needed + index.data().isValid()); } void CSMWorld::IdTree::setNestedTable(const QModelIndex& index, const CSMWorld::NestedTableWrapperBase& nestedTable) diff --git a/apps/opencs/model/world/idtree.hpp b/apps/opencs/model/world/idtree.hpp index 5f005c4d3..5337ed82b 100644 --- a/apps/opencs/model/world/idtree.hpp +++ b/apps/opencs/model/world/idtree.hpp @@ -34,8 +34,8 @@ namespace CSMWorld IdTree (const IdTree&); IdTree& operator= (const IdTree&); - unsigned int foldIndexAdress(const QModelIndex& index) const; - std::pair unfoldIndexAdress(unsigned int id) const; + unsigned int foldIndexAddress(const QModelIndex& index) const; + std::pair unfoldIndexAddress(unsigned int id) const; public: @@ -61,6 +61,8 @@ namespace CSMWorld virtual QModelIndex parent (const QModelIndex& index) const; + QModelIndex getNestedModelIndex (const std::string& id, int column) const; + QVariant nestedHeaderData(int section, int subSection, Qt::Orientation orientation, int role = Qt::DisplayRole) const; NestedTableWrapperBase* nestedTable(const QModelIndex &index) const; diff --git a/apps/opencs/model/world/nestedtableproxymodel.cpp b/apps/opencs/model/world/nestedtableproxymodel.cpp index 182ed11ab..7b35c88e4 100644 --- a/apps/opencs/model/world/nestedtableproxymodel.cpp +++ b/apps/opencs/model/world/nestedtableproxymodel.cpp @@ -50,7 +50,7 @@ QModelIndex CSMWorld::NestedTableProxyModel::mapFromSource(const QModelIndex& so QModelIndex CSMWorld::NestedTableProxyModel::mapToSource(const QModelIndex& proxyIndex) const { - const QModelIndex& parent = mMainModel->getModelIndex (mId, mParentColumn); + const QModelIndex& parent = mMainModel->getNestedModelIndex (mId, mParentColumn); return mMainModel->index(proxyIndex.row(), proxyIndex.column(), parent); } @@ -98,6 +98,10 @@ QVariant CSMWorld::NestedTableProxyModel::headerData(int section, return mMainModel->nestedHeaderData(mParentColumn, section, orientation, role); } +QVariant CSMWorld::NestedTableProxyModel::data(const QModelIndex& index, int role) const +{ + return mMainModel->data(mapToSource(index), role); +} bool CSMWorld::NestedTableProxyModel::setData (const QModelIndex & index, const QVariant & value, int role) { diff --git a/apps/opencs/model/world/nestedtableproxymodel.hpp b/apps/opencs/model/world/nestedtableproxymodel.hpp index 2ab04a584..f5cbdb10b 100644 --- a/apps/opencs/model/world/nestedtableproxymodel.hpp +++ b/apps/opencs/model/world/nestedtableproxymodel.hpp @@ -53,6 +53,8 @@ namespace CSMWorld virtual QVariant headerData (int section, Qt::Orientation orientation, int role) const; + virtual QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const; + virtual bool setData (const QModelIndex & index, const QVariant & value, int role = Qt::EditRole); virtual Qt::ItemFlags flags(const QModelIndex& index) const; From ce7e2e06c15baaebad91a4be4472c75e24af0292 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 11 Apr 2015 13:11:20 +1000 Subject: [PATCH 0911/3725] Fix editor being created for a non-editable item. --- apps/opencs/model/world/idtree.cpp | 14 +++++++++++++- apps/opencs/model/world/nestedtableproxymodel.cpp | 2 +- apps/opencs/view/world/util.cpp | 2 +- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/world/idtree.cpp b/apps/opencs/model/world/idtree.cpp index 49ceced2c..eddde5a89 100644 --- a/apps/opencs/model/world/idtree.cpp +++ b/apps/opencs/model/world/idtree.cpp @@ -108,7 +108,19 @@ Qt::ItemFlags CSMWorld::IdTree::flags (const QModelIndex & index) const if (!index.isValid()) return 0; - return IdTable::flags(index); + if (index.internalId() != 0) + { + std::pair parentAddress(unfoldIndexAddress(index.internalId())); + + Qt::ItemFlags flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled; + + if (mNestedCollection->getNestableColumn(parentAddress.second)->nestedColumn(index.column()).isEditable()) + flags |= Qt::ItemIsEditable; + + return flags; + } + else + return IdTable::flags(index); } bool CSMWorld::IdTree::removeRows (int row, int count, const QModelIndex& parent) diff --git a/apps/opencs/model/world/nestedtableproxymodel.cpp b/apps/opencs/model/world/nestedtableproxymodel.cpp index 7b35c88e4..0f137d78f 100644 --- a/apps/opencs/model/world/nestedtableproxymodel.cpp +++ b/apps/opencs/model/world/nestedtableproxymodel.cpp @@ -110,7 +110,7 @@ bool CSMWorld::NestedTableProxyModel::setData (const QModelIndex & index, const Qt::ItemFlags CSMWorld::NestedTableProxyModel::flags(const QModelIndex& index) const { - return mMainModel->flags(mMainModel->index(0, mParentColumn)); + return mMainModel->flags(mapToSource(index)); } std::string CSMWorld::NestedTableProxyModel::getParentId() const diff --git a/apps/opencs/view/world/util.cpp b/apps/opencs/view/world/util.cpp index b0f8a035a..f3b23100a 100644 --- a/apps/opencs/view/world/util.cpp +++ b/apps/opencs/view/world/util.cpp @@ -120,7 +120,7 @@ void CSVWorld::CommandDelegate::setModelDataImp (QWidget *editor, QAbstractItemM QVariant new_ = hack.getData(); - if (model->data (index)!=new_) + if ((model->data (index)!=new_) && (model->flags(index) & Qt::ItemIsEditable)) getUndoStack().push (new CSMWorld::ModifyCommand (*model, index, new_)); } From 5da2f53bec3f6bc7910f7c12e6f46b09f358ceda Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 11 Apr 2015 13:54:05 +1000 Subject: [PATCH 0912/3725] Code reorganisation to prepare for nested sound table in regions. --- apps/opencs/model/world/idadapterimp.hpp | 3 +- .../opencs/model/world/nestedidcollection.hpp | 172 ++++++++++++++++++ apps/opencs/model/world/subcellcollection.hpp | 151 +-------------- 3 files changed, 177 insertions(+), 149 deletions(-) create mode 100644 apps/opencs/model/world/nestedidcollection.hpp diff --git a/apps/opencs/model/world/idadapterimp.hpp b/apps/opencs/model/world/idadapterimp.hpp index 2ce0777ac..7df653059 100644 --- a/apps/opencs/model/world/idadapterimp.hpp +++ b/apps/opencs/model/world/idadapterimp.hpp @@ -6,11 +6,10 @@ #include #include "idadapter.hpp" +#include "nestedtablewrapper.hpp" namespace CSMWorld { - struct NestedTableWrapperBase; - template class PathgridPointListAdapter : public NestedIdAdapter { diff --git a/apps/opencs/model/world/nestedidcollection.hpp b/apps/opencs/model/world/nestedidcollection.hpp new file mode 100644 index 000000000..c7e840955 --- /dev/null +++ b/apps/opencs/model/world/nestedidcollection.hpp @@ -0,0 +1,172 @@ +#ifndef CSM_WOLRD_NESTEDIDCOLLECTION_H +#define CSM_WOLRD_NESTEDIDCOLLECTION_H + +#include +#include + +#include "nestedcollection.hpp" +#include "idadapterimp.hpp" + +namespace ESM +{ + class ESMReader; +} + +namespace CSMWorld +{ + struct NestedTableWrapperBase; + struct Cell; + + template + class IdCollection; + + template > + class NestedIdCollection : public IdCollection, public NestedCollection + { + std::map* > mAdapters; + + const NestedIdAdapter& getAdapter(const ColumnBase &column) const; + + public: + + NestedIdCollection (); + ~NestedIdCollection(); + + virtual void addNestedRow(int row, int column, int position); + + virtual void removeNestedRows(int row, int column, int subRow); + + virtual QVariant getNestedData(int row, int column, int subRow, int subColumn) const; + + virtual void setNestedData(int row, int column, const QVariant& data, int subRow, int subColumn); + + virtual NestedTableWrapperBase* nestedTable(int row, int column) const; + + virtual void setNestedTable(int row, int column, const NestedTableWrapperBase& nestedTable); + + virtual int getNestedRowsCount(int row, int column) const; + + virtual int getNestedColumnsCount(int row, int column) const; + + // this method is inherited from NestedCollection, not from Collection + virtual NestableColumn *getNestableColumn(int column); + + void addAdapter(std::pair* > adapter); + }; + + template + NestedIdCollection::NestedIdCollection () + {} + + template + NestedIdCollection::~NestedIdCollection() + { + for (typename std::map* >::iterator iter (mAdapters.begin()); + iter!=mAdapters.end(); ++iter) + delete (*iter).second; + } + + template + void NestedIdCollection::addAdapter(std::pair* > adapter) + { + mAdapters.insert(adapter); + } + + template + const NestedIdAdapter& NestedIdCollection::getAdapter(const ColumnBase &column) const + { + typename std::map* >::const_iterator iter = + mAdapters.find (&column); + + if (iter==mAdapters.end()) + throw std::logic_error("No such column in the nestedidadapter"); + + return *iter->second; + } + + template + void NestedIdCollection::addNestedRow(int row, int column, int position) + { + Record record; + record.assign(Collection::getRecord(row)); + + getAdapter(Collection::getColumn(column)).addNestedRow(record, position); + + Collection::setRecord(row, record); + } + + template + void NestedIdCollection::removeNestedRows(int row, int column, int subRow) + { + Record record; + record.assign(Collection::getRecord(row)); + + getAdapter(Collection::getColumn(column)).removeNestedRow(record, subRow); + + Collection::setRecord(row, record); + } + + template + QVariant NestedIdCollection::getNestedData (int row, + int column, int subRow, int subColumn) const + { + return getAdapter(Collection::getColumn(column)).getNestedData( + Collection::getRecord(row), subRow, subColumn); + } + + template + void NestedIdCollection::setNestedData(int row, + int column, const QVariant& data, int subRow, int subColumn) + { + Record record; + record.assign(Collection::getRecord(row)); + + getAdapter(Collection::getColumn(column)).setNestedData( + record, data, subRow, subColumn); + + Collection::setRecord(row, record); + } + + template + CSMWorld::NestedTableWrapperBase* NestedIdCollection::nestedTable(int row, + int column) const + { + return getAdapter(Collection::getColumn(column)).nestedTable( + Collection::getRecord(row)); + } + + template + void NestedIdCollection::setNestedTable(int row, + int column, const CSMWorld::NestedTableWrapperBase& nestedTable) + { + Record record; + record.assign(Collection::getRecord(row)); + + getAdapter(Collection::getColumn(column)).setNestedTable( + record, nestedTable); + + Collection::setRecord(row, record); + } + + template + int NestedIdCollection::getNestedRowsCount(int row, int column) const + { + return getAdapter(Collection::getColumn(column)).getNestedRowsCount( + Collection::getRecord(row)); + } + + template + int NestedIdCollection::getNestedColumnsCount(int row, int column) const + { + return getAdapter(Collection::getColumn(column)).getNestedColumnsCount( + Collection::getRecord(row)); + } + + template + CSMWorld::NestableColumn *NestedIdCollection::getNestableColumn(int column) + { + return Collection::getNestableColumn(column); + } +} + +#endif // CSM_WOLRD_NESTEDIDCOLLECTION_H diff --git a/apps/opencs/model/world/subcellcollection.hpp b/apps/opencs/model/world/subcellcollection.hpp index c53c7006a..df1f8a12e 100644 --- a/apps/opencs/model/world/subcellcollection.hpp +++ b/apps/opencs/model/world/subcellcollection.hpp @@ -1,16 +1,7 @@ #ifndef CSM_WOLRD_SUBCOLLECTION_H #define CSM_WOLRD_SUBCOLLECTION_H -#include -#include - -#include - -#include "columnimp.hpp" -#include "idcollection.hpp" -#include "nestedcollection.hpp" -#include "nestedtablewrapper.hpp" -#include "idadapterimp.hpp" +#include "nestedidcollection.hpp" namespace ESM { @@ -25,40 +16,15 @@ namespace CSMWorld /// \brief Single type collection of top level records that are associated with cells template > - class SubCellCollection : public IdCollection, public NestedCollection + class SubCellCollection : public NestedIdCollection { const IdCollection& mCells; - std::map* > mAdapters; virtual void loadRecord (ESXRecordT& record, ESM::ESMReader& reader); - const NestedIdAdapter& getAdapter(const ColumnBase &column) const; - public: SubCellCollection (const IdCollection& cells); - ~SubCellCollection(); - - virtual void addNestedRow(int row, int column, int position); - - virtual void removeNestedRows(int row, int column, int subRow); - - virtual QVariant getNestedData(int row, int column, int subRow, int subColumn) const; - - virtual void setNestedData(int row, int column, const QVariant& data, int subRow, int subColumn); - - virtual NestedTableWrapperBase* nestedTable(int row, int column) const; - - virtual void setNestedTable(int row, int column, const NestedTableWrapperBase& nestedTable); - - virtual int getNestedRowsCount(int row, int column) const; - - virtual int getNestedColumnsCount(int row, int column) const; - - // this method is inherited from NestedCollection, not from Collection - virtual NestableColumn *getNestableColumn(int column); - - void addAdapter(std::pair* > adapter); }; template @@ -69,119 +35,10 @@ namespace CSMWorld } template - SubCellCollection::SubCellCollection (const IdCollection& cells) + SubCellCollection::SubCellCollection ( + const IdCollection& cells) : mCells (cells) {} - - template - SubCellCollection::~SubCellCollection() - { - for (typename std::map* >::iterator iter (mAdapters.begin()); - iter!=mAdapters.end(); ++iter) - delete (*iter).second; - } - - template - void SubCellCollection::addAdapter(std::pair* > adapter) - { - mAdapters.insert(adapter); - } - - template - const NestedIdAdapter& SubCellCollection::getAdapter(const ColumnBase &column) const - { - typename std::map* >::const_iterator iter = - mAdapters.find (&column); - - if (iter==mAdapters.end()) - throw std::logic_error("No such column in the nestedidadapter"); - - return *iter->second; - } - - template - void SubCellCollection::addNestedRow(int row, int column, int position) - { - Record record; - record.assign(Collection::getRecord(row)); - - getAdapter(Collection::getColumn(column)).addNestedRow(record, position); - - Collection::setRecord(row, record); - } - - template - void SubCellCollection::removeNestedRows(int row, int column, int subRow) - { - Record record; - record.assign(Collection::getRecord(row)); - - getAdapter(Collection::getColumn(column)).removeNestedRow(record, subRow); - - Collection::setRecord(row, record); - } - - template - QVariant SubCellCollection::getNestedData (int row, - int column, int subRow, int subColumn) const - { - return getAdapter(Collection::getColumn(column)).getNestedData( - Collection::getRecord(row), subRow, subColumn); - } - - template - void SubCellCollection::setNestedData(int row, - int column, const QVariant& data, int subRow, int subColumn) - { - Record record; - record.assign(Collection::getRecord(row)); - - getAdapter(Collection::getColumn(column)).setNestedData( - record, data, subRow, subColumn); - - Collection::setRecord(row, record); - } - - template - CSMWorld::NestedTableWrapperBase* SubCellCollection::nestedTable(int row, - int column) const - { - return getAdapter(Collection::getColumn(column)).nestedTable( - Collection::getRecord(row)); - } - - template - void SubCellCollection::setNestedTable(int row, - int column, const CSMWorld::NestedTableWrapperBase& nestedTable) - { - Record record; - record.assign(Collection::getRecord(row)); - - getAdapter(Collection::getColumn(column)).setNestedTable( - record, nestedTable); - - Collection::setRecord(row, record); - } - - template - int SubCellCollection::getNestedRowsCount(int row, int column) const - { - return getAdapter(Collection::getColumn(column)).getNestedRowsCount( - Collection::getRecord(row)); - } - - template - int SubCellCollection::getNestedColumnsCount(int row, int column) const - { - return getAdapter(Collection::getColumn(column)).getNestedColumnsCount( - Collection::getRecord(row)); - } - - template - CSMWorld::NestableColumn *SubCellCollection::getNestableColumn(int column) - { - return Collection::getNestableColumn(column); - } } #endif From 88bc62e05450fbd5b35a9beb76c0cccb50122e15 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 11 Apr 2015 15:55:26 +1000 Subject: [PATCH 0913/3725] Add Region sounds table to dialogue subview. --- apps/opencs/model/world/columnbase.hpp | 1 + apps/opencs/model/world/columnimp.hpp | 46 ++++++++++++ apps/opencs/model/world/columns.cpp | 4 + apps/opencs/model/world/columns.hpp | 4 + apps/opencs/model/world/data.cpp | 8 +- apps/opencs/model/world/data.hpp | 3 +- apps/opencs/model/world/idadapterimp.hpp | 96 +++++++++++++++++++++++- 7 files changed, 156 insertions(+), 6 deletions(-) diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index e6799cf56..3902a009b 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -99,6 +99,7 @@ namespace CSMWorld Display_NestedDestinationsList, Display_PathgridPointList, Display_PathgridEdgeList, + Display_RegionSoundList, Display_EnchantmentType, Display_BodyPartType, diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index 3fb9a4685..06467a632 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -2355,6 +2355,52 @@ namespace CSMWorld return true; } }; + + template + struct RegionSoundListColumn : public Column + { + RegionSoundListColumn () + : Column (Columns::ColumnId_RegionSounds, + ColumnBase::Display_RegionSoundList, ColumnBase::Flag_Dialogue) + {} + + virtual QVariant get (const Record& record) const + { + return true; // required by IdTree::hasChildren() + } + + virtual bool isEditable() const + { + return true; + } + + }; + + struct RegionSoundNameColumn : public NestableColumn + { + RegionSoundNameColumn () + : NestableColumn (Columns::ColumnId_SoundName, + ColumnBase::Display_String, ColumnBase::Flag_Dialogue) + {} + + virtual bool isEditable() const + { + return true; + } + }; + + struct RegionSoundChanceColumn : public NestableColumn + { + RegionSoundChanceColumn () + : NestableColumn (Columns::ColumnId_SoundChance, + ColumnBase::Display_Integer, ColumnBase::Flag_Dialogue) + {} + + virtual bool isEditable() const + { + return true; + } + }; } #endif diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index b65cf7f96..39b3ea2e3 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -233,6 +233,10 @@ namespace CSMWorld { ColumnId_PathgridEdge0, "Point 0"}, { ColumnId_PathgridEdge1, "Point 1"}, + { ColumnId_RegionSounds, "Sounds"}, + { ColumnId_SoundName, "Name"}, + { ColumnId_SoundChance, "Chance"}, + { ColumnId_UseValue1, "Use value 1" }, { ColumnId_UseValue2, "Use value 2" }, { ColumnId_UseValue3, "Use value 3" }, diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 2cb7101b0..49a9208b0 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -222,6 +222,10 @@ namespace CSMWorld ColumnId_PathgridEdge0 = 206, ColumnId_PathgridEdge1 = 207, + ColumnId_RegionSounds = 208, + ColumnId_SoundName = 209, + ColumnId_SoundChance = 210, + // Allocated to a separate value range, so we don't get a collision should we ever need // to extend the number of use values. ColumnId_UseValue1 = 0x10000, diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 87d5116f1..c387298d2 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -140,6 +140,12 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mRegions.addColumn (new NameColumn); mRegions.addColumn (new MapColourColumn); mRegions.addColumn (new SleepListColumn); + // see idadapterimpl.hpp and columnimp.hpp + RegionSoundListColumn *soundList = new RegionSoundListColumn (); + mRegions.addColumn (soundList); + mRegions.addAdapter (std::make_pair(soundList, new RegionSoundListAdapter ())); + mRegions.getNestableColumn(mRegions.getColumns()-1)->addColumn(new RegionSoundNameColumn ()); + mRegions.getNestableColumn(mRegions.getColumns()-1)->addColumn(new RegionSoundChanceColumn ()); mBirthsigns.addColumn (new StringIdColumn); mBirthsigns.addColumn (new RecordStateColumn); @@ -339,7 +345,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc addModel (new IdTable (&mRaces), UniversalId::Type_Race); addModel (new IdTable (&mSounds), UniversalId::Type_Sound); addModel (new IdTable (&mScripts), UniversalId::Type_Script); - addModel (new IdTable (&mRegions), UniversalId::Type_Region); + addModel (new IdTree (&mRegions, &mRegions), UniversalId::Type_Region); addModel (new IdTable (&mBirthsigns), UniversalId::Type_Birthsign); addModel (new IdTable (&mSpells), UniversalId::Type_Spell); addModel (new IdTable (&mTopics), UniversalId::Type_Topic); diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index b9e060002..329aceaf7 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -34,6 +34,7 @@ #include "../doc/stage.hpp" #include "idcollection.hpp" +#include "nestedidcollection.hpp" #include "universalid.hpp" #include "cell.hpp" #include "land.hpp" @@ -72,7 +73,7 @@ namespace CSMWorld IdCollection mRaces; IdCollection mSounds; IdCollection mScripts; - IdCollection mRegions; + NestedIdCollection mRegions; IdCollection mBirthsigns; IdCollection mSpells; IdCollection mTopics; diff --git a/apps/opencs/model/world/idadapterimp.hpp b/apps/opencs/model/world/idadapterimp.hpp index 7df653059..d5a44aea2 100644 --- a/apps/opencs/model/world/idadapterimp.hpp +++ b/apps/opencs/model/world/idadapterimp.hpp @@ -4,6 +4,7 @@ #include #include +#include #include "idadapter.hpp" #include "nestedtablewrapper.hpp" @@ -127,7 +128,7 @@ namespace CSMWorld case 1: return point.mX; case 2: return point.mY; case 3: return point.mZ; - default: throw std::logic_error("Pathgrid point subcolumn index out of range"); + default: throw std::runtime_error("Pathgrid point subcolumn index out of range"); } } @@ -142,7 +143,7 @@ namespace CSMWorld case 1: point.mX = value.toInt(); break; case 2: point.mY = value.toInt(); break; case 3: point.mZ = value.toInt(); break; - default: throw std::logic_error("Pathgrid point subcolumn index out of range"); + default: throw std::runtime_error("Pathgrid point subcolumn index out of range"); } pathgrid.mPoints[subRowIndex] = point; @@ -223,7 +224,7 @@ namespace CSMWorld case 0: return subRowIndex; case 1: return edge.mV0; case 2: return edge.mV1; - default: throw std::logic_error("Pathgrid edge subcolumn index out of range"); + default: throw std::runtime_error("Pathgrid edge subcolumn index out of range"); } } @@ -238,7 +239,7 @@ namespace CSMWorld case 0: break; case 1: edge.mV0 = value.toInt(); break; case 2: edge.mV1 = value.toInt(); break; - default: throw std::logic_error("Pathgrid edge subcolumn index out of range"); + default: throw std::runtime_error("Pathgrid edge subcolumn index out of range"); } pathgrid.mEdges[subRowIndex] = edge; @@ -256,6 +257,93 @@ namespace CSMWorld return static_cast(record.get().mEdges.size()); } }; + + template + class RegionSoundListAdapter : public NestedIdAdapter + { + public: + RegionSoundListAdapter () {} + + virtual void addNestedRow(Record& record, int position) const + { + ESXRecordT region = record.get(); + + std::vector& soundList = region.mSoundList; + + // blank row + ESXRecordT::SoundRef soundRef; + soundRef.mSound.assign(""); + soundRef.mChance = 0; + + soundList.insert(soundList.begin()+position, soundRef); + + record.setModified (region); + } + + virtual void removeNestedRow(Record& record, int rowToRemove) const + { + ESXRecordT region = record.get(); + + std::vector& soundList = region.mSoundList; + + if (rowToRemove < 0 || rowToRemove >= static_cast (soundList.size())) + throw std::runtime_error ("index out of range"); + + soundList.erase(soundList.begin()+rowToRemove); + + record.setModified (region); + } + + virtual void setNestedTable(Record& record, const NestedTableWrapperBase& nestedTable) const + { + record.get().mSoundList = + static_cast >&>(nestedTable).mNestedTable; + } + + virtual NestedTableWrapperBase* nestedTable(const Record& record) const + { + // deleted by dtor of NestedTableStoring + return new NestedTableWrapper >(record.get().mSoundList); + } + + virtual QVariant getNestedData(const Record& record, int subRowIndex, int subColIndex) const + { + ESXRecordT::SoundRef soundRef = record.get().mSoundList[subRowIndex]; + switch (subColIndex) + { + case 0: return QString(soundRef.mSound.toString().c_str()); + case 1: return soundRef.mChance; + default: throw std::runtime_error("Region sounds subcolumn index out of range"); + } + } + + virtual void setNestedData(Record& record, const QVariant& value, + int subRowIndex, int subColIndex) const + { + ESXRecordT region = record.get(); + ESXRecordT::SoundRef soundRef = region.mSoundList[subRowIndex]; + switch (subColIndex) + { + case 0: soundRef.mSound.assign(value.toString().toUtf8().constData()); break; + case 1: soundRef.mChance = static_cast(value.toInt()); break; + default: throw std::runtime_error("Region sounds subcolumn index out of range"); + } + + region.mSoundList[subRowIndex] = soundRef; + + record.setModified (region); + } + + virtual int getNestedColumnsCount(const Record& record) const + { + return 2; + } + + virtual int getNestedRowsCount(const Record& record) const + { + return static_cast(record.get().mSoundList.size()); + } + }; } #endif // CSM_WOLRD_IDADAPTERIMP_H From ea9563ad92c13397497846afad39fcc5d4cafb2d Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 11 Apr 2015 17:51:30 +1000 Subject: [PATCH 0914/3725] Add faction reactions table to dialogue subview. Fix gcc compile issues. Change nested columns to generic ones where possible. --- apps/opencs/model/world/columnbase.hpp | 2 +- apps/opencs/model/world/columnimp.hpp | 21 ++- apps/opencs/model/world/columns.cpp | 5 + apps/opencs/model/world/columns.hpp | 7 +- apps/opencs/model/world/data.cpp | 22 +++- apps/opencs/model/world/data.hpp | 2 +- apps/opencs/model/world/idadapterimp.hpp | 159 +++++++++++++++++++++-- 7 files changed, 190 insertions(+), 28 deletions(-) diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index 3902a009b..c994ced15 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -99,7 +99,7 @@ namespace CSMWorld Display_NestedDestinationsList, Display_PathgridPointList, Display_PathgridEdgeList, - Display_RegionSoundList, + Display_NestedHeader, Display_EnchantmentType, Display_BodyPartType, diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index 06467a632..675352d35 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -2357,11 +2357,10 @@ namespace CSMWorld }; template - struct RegionSoundListColumn : public Column + struct NestedParentColumn : public Column { - RegionSoundListColumn () - : Column (Columns::ColumnId_RegionSounds, - ColumnBase::Display_RegionSoundList, ColumnBase::Flag_Dialogue) + NestedParentColumn (Columns::ColumnId id) + : Column (id, ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue) {} virtual QVariant get (const Record& record) const @@ -2376,11 +2375,10 @@ namespace CSMWorld }; - struct RegionSoundNameColumn : public NestableColumn + struct NestedStringColumn : public NestableColumn { - RegionSoundNameColumn () - : NestableColumn (Columns::ColumnId_SoundName, - ColumnBase::Display_String, ColumnBase::Flag_Dialogue) + NestedStringColumn (Columns::ColumnId id) + : NestableColumn (id, ColumnBase::Display_String, ColumnBase::Flag_Dialogue) {} virtual bool isEditable() const @@ -2389,11 +2387,10 @@ namespace CSMWorld } }; - struct RegionSoundChanceColumn : public NestableColumn + struct NestedIntegerColumn : public NestableColumn { - RegionSoundChanceColumn () - : NestableColumn (Columns::ColumnId_SoundChance, - ColumnBase::Display_Integer, ColumnBase::Flag_Dialogue) + NestedIntegerColumn (Columns::ColumnId id) + : NestableColumn (id, ColumnBase::Display_Integer, ColumnBase::Flag_Dialogue) {} virtual bool isEditable() const diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 39b3ea2e3..c9155a5ad 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -237,6 +237,10 @@ namespace CSMWorld { ColumnId_SoundName, "Name"}, { ColumnId_SoundChance, "Chance"}, + { ColumnId_FactionReactions, "Reactions"}, + //{ ColumnId_FactionID, "Faction ID"}, + { ColumnId_FactionReaction, "Reaction"}, + { ColumnId_UseValue1, "Use value 1" }, { ColumnId_UseValue2, "Use value 2" }, { ColumnId_UseValue3, "Use value 3" }, @@ -263,6 +267,7 @@ namespace CSMWorld { ColumnId_Skill4, "Skill 4" }, { ColumnId_Skill5, "Skill 5" }, { ColumnId_Skill6, "Skill 6" }, + { ColumnId_Skill7, "Skill 7" }, { -1, 0 } // end marker }; diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 49a9208b0..531cf9972 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -226,6 +226,10 @@ namespace CSMWorld ColumnId_SoundName = 209, ColumnId_SoundChance = 210, + ColumnId_FactionReactions = 211, + //ColumnId_FactionID = 212, + ColumnId_FactionReaction = 213, + // Allocated to a separate value range, so we don't get a collision should we ever need // to extend the number of use values. ColumnId_UseValue1 = 0x10000, @@ -259,7 +263,8 @@ namespace CSMWorld ColumnId_Skill3 = 0x50002, ColumnId_Skill4 = 0x50003, ColumnId_Skill5 = 0x50004, - ColumnId_Skill6 = 0x50005 + ColumnId_Skill6 = 0x50005, + ColumnId_Skill7 = 0x50006 }; std::string getName (ColumnId column); diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index c387298d2..3352dd30e 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -108,6 +108,15 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mFactions.addColumn (new HiddenColumn); for (int i=0; i<7; ++i) mFactions.addColumn (new SkillsColumn (i)); + // Faction Reactions + NestedParentColumn *reactions = + new NestedParentColumn (Columns::ColumnId_FactionReactions); + mFactions.addColumn (reactions); + mFactions.addAdapter (std::make_pair(reactions, new FactionReactionsAdapter ())); + mFactions.getNestableColumn(mFactions.getColumns()-1)->addColumn( + new NestedStringColumn (Columns::ColumnId_Faction)); + mFactions.getNestableColumn(mFactions.getColumns()-1)->addColumn( + new NestedIntegerColumn (Columns::ColumnId_FactionReaction)); mRaces.addColumn (new StringIdColumn); mRaces.addColumn (new RecordStateColumn); @@ -140,12 +149,15 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mRegions.addColumn (new NameColumn); mRegions.addColumn (new MapColourColumn); mRegions.addColumn (new SleepListColumn); - // see idadapterimpl.hpp and columnimp.hpp - RegionSoundListColumn *soundList = new RegionSoundListColumn (); + // Region Sounds + NestedParentColumn *soundList = + new NestedParentColumn (Columns::ColumnId_RegionSounds); mRegions.addColumn (soundList); mRegions.addAdapter (std::make_pair(soundList, new RegionSoundListAdapter ())); - mRegions.getNestableColumn(mRegions.getColumns()-1)->addColumn(new RegionSoundNameColumn ()); - mRegions.getNestableColumn(mRegions.getColumns()-1)->addColumn(new RegionSoundChanceColumn ()); + mRegions.getNestableColumn(mRegions.getColumns()-1)->addColumn( + new NestedStringColumn (Columns::ColumnId_SoundName)); + mRegions.getNestableColumn(mRegions.getColumns()-1)->addColumn( + new NestedIntegerColumn (Columns::ColumnId_SoundChance)); mBirthsigns.addColumn (new StringIdColumn); mBirthsigns.addColumn (new RecordStateColumn); @@ -341,7 +353,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc addModel (new IdTable (&mGmsts), UniversalId::Type_Gmst); addModel (new IdTable (&mSkills), UniversalId::Type_Skill); addModel (new IdTable (&mClasses), UniversalId::Type_Class); - addModel (new IdTable (&mFactions), UniversalId::Type_Faction); + addModel (new IdTree (&mFactions, &mFactions), UniversalId::Type_Faction); addModel (new IdTable (&mRaces), UniversalId::Type_Race); addModel (new IdTable (&mSounds), UniversalId::Type_Sound); addModel (new IdTable (&mScripts), UniversalId::Type_Script); diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 329aceaf7..858f82639 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -69,7 +69,7 @@ namespace CSMWorld IdCollection mGmsts; IdCollection mSkills; IdCollection mClasses; - IdCollection mFactions; + NestedIdCollection mFactions; IdCollection mRaces; IdCollection mSounds; IdCollection mScripts; diff --git a/apps/opencs/model/world/idadapterimp.hpp b/apps/opencs/model/world/idadapterimp.hpp index d5a44aea2..00f7b1831 100644 --- a/apps/opencs/model/world/idadapterimp.hpp +++ b/apps/opencs/model/world/idadapterimp.hpp @@ -5,6 +5,7 @@ #include #include +#include #include "idadapter.hpp" #include "nestedtablewrapper.hpp" @@ -218,7 +219,12 @@ namespace CSMWorld virtual QVariant getNestedData(const Record& record, int subRowIndex, int subColIndex) const { - ESM::Pathgrid::Edge edge = record.get().mEdges[subRowIndex]; + ESXRecordT pathgrid = record.get(); + + if (subRowIndex < 0 || subRowIndex >= static_cast (pathgrid.mEdges.size())) + throw std::runtime_error ("index out of range"); + + ESM::Pathgrid::Edge edge = pathgrid.mEdges[subRowIndex]; switch (subColIndex) { case 0: return subRowIndex; @@ -233,6 +239,10 @@ namespace CSMWorld int subRowIndex, int subColIndex) const { ESXRecordT pathgrid = record.get(); + + if (subRowIndex < 0 || subRowIndex >= static_cast (pathgrid.mEdges.size())) + throw std::runtime_error ("index out of range"); + ESM::Pathgrid::Edge edge = pathgrid.mEdges[subRowIndex]; switch (subColIndex) { @@ -258,6 +268,126 @@ namespace CSMWorld } }; + template + class FactionReactionsAdapter : public NestedIdAdapter + { + public: + FactionReactionsAdapter () {} + + virtual void addNestedRow(Record& record, int position) const + { + ESXRecordT faction = record.get(); + + std::map& reactions = faction.mReactions; + + // blank row + reactions.insert(std::make_pair("", 0)); + + record.setModified (faction); + } + + virtual void removeNestedRow(Record& record, int rowToRemove) const + { + ESXRecordT faction = record.get(); + + std::map& reactions = faction.mReactions; + + if (rowToRemove < 0 || rowToRemove >= static_cast (reactions.size())) + throw std::runtime_error ("index out of range"); + + // FIXME: how to ensure that the map entries correspond to table indicies? + // WARNING: Assumed that the table view has the same order as std::map + std::map::const_iterator iter = reactions.begin(); + for(int i = 0; i < rowToRemove; ++i) + iter++; + reactions.erase(iter); + + record.setModified (faction); + } + + virtual void setNestedTable(Record& record, const NestedTableWrapperBase& nestedTable) const + { + record.get().mReactions = + static_cast >&>(nestedTable).mNestedTable; + } + + virtual NestedTableWrapperBase* nestedTable(const Record& record) const + { + // deleted by dtor of NestedTableStoring + return new NestedTableWrapper >(record.get().mReactions); + } + + virtual QVariant getNestedData(const Record& record, int subRowIndex, int subColIndex) const + { + ESXRecordT faction = record.get(); + + std::map& reactions = faction.mReactions; + + if (subRowIndex < 0 || subRowIndex >= static_cast (reactions.size())) + throw std::runtime_error ("index out of range"); + + // FIXME: how to ensure that the map entries correspond to table indicies? + // WARNING: Assumed that the table view has the same order as std::map + std::map::const_iterator iter = reactions.begin(); + for(int i = 0; i < subRowIndex; ++i) + iter++; + switch (subColIndex) + { + case 0: return QString((*iter).first.c_str()); + case 1: return (*iter).second; + default: throw std::runtime_error("Faction reactions subcolumn index out of range"); + } + } + + virtual void setNestedData(Record& record, const QVariant& value, + int subRowIndex, int subColIndex) const + { + ESXRecordT faction = record.get(); + + std::map& reactions = faction.mReactions; + + if (subRowIndex < 0 || subRowIndex >= static_cast (reactions.size())) + throw std::runtime_error ("index out of range"); + + // FIXME: how to ensure that the map entries correspond to table indicies? + // WARNING: Assumed that the table view has the same order as std::map + std::map::const_iterator iter = reactions.begin(); + for(int i = 0; i < subRowIndex; ++i) + iter++; + + std::string factionId = (*iter).first; + int reaction = (*iter).second; + + switch (subColIndex) + { + case 0: + { + reactions.erase(iter); + reactions.insert(std::make_pair(value.toString().toUtf8().constData(), reaction)); + break; + } + case 1: + { + reactions[factionId] = value.toInt(); + break; + } + default: throw std::runtime_error("Faction reactions subcolumn index out of range"); + } + + record.setModified (faction); + } + + virtual int getNestedColumnsCount(const Record& record) const + { + return 2; + } + + virtual int getNestedRowsCount(const Record& record) const + { + return static_cast(record.get().mReactions.size()); + } + }; + template class RegionSoundListAdapter : public NestedIdAdapter { @@ -268,10 +398,10 @@ namespace CSMWorld { ESXRecordT region = record.get(); - std::vector& soundList = region.mSoundList; + std::vector& soundList = region.mSoundList; // blank row - ESXRecordT::SoundRef soundRef; + typename ESXRecordT::SoundRef soundRef; soundRef.mSound.assign(""); soundRef.mChance = 0; @@ -284,7 +414,7 @@ namespace CSMWorld { ESXRecordT region = record.get(); - std::vector& soundList = region.mSoundList; + std::vector& soundList = region.mSoundList; if (rowToRemove < 0 || rowToRemove >= static_cast (soundList.size())) throw std::runtime_error ("index out of range"); @@ -297,18 +427,25 @@ namespace CSMWorld virtual void setNestedTable(Record& record, const NestedTableWrapperBase& nestedTable) const { record.get().mSoundList = - static_cast >&>(nestedTable).mNestedTable; + static_cast >&>(nestedTable).mNestedTable; } virtual NestedTableWrapperBase* nestedTable(const Record& record) const { // deleted by dtor of NestedTableStoring - return new NestedTableWrapper >(record.get().mSoundList); + return new NestedTableWrapper >(record.get().mSoundList); } virtual QVariant getNestedData(const Record& record, int subRowIndex, int subColIndex) const { - ESXRecordT::SoundRef soundRef = record.get().mSoundList[subRowIndex]; + ESXRecordT region = record.get(); + + std::vector& soundList = region.mSoundList; + + if (subRowIndex < 0 || subRowIndex >= static_cast (soundList.size())) + throw std::runtime_error ("index out of range"); + + typename ESXRecordT::SoundRef soundRef = soundList[subRowIndex]; switch (subColIndex) { case 0: return QString(soundRef.mSound.toString().c_str()); @@ -321,7 +458,13 @@ namespace CSMWorld int subRowIndex, int subColIndex) const { ESXRecordT region = record.get(); - ESXRecordT::SoundRef soundRef = region.mSoundList[subRowIndex]; + + std::vector& soundList = region.mSoundList; + + if (subRowIndex < 0 || subRowIndex >= static_cast (soundList.size())) + throw std::runtime_error ("index out of range"); + + typename ESXRecordT::SoundRef soundRef = soundList[subRowIndex]; switch (subColIndex) { case 0: soundRef.mSound.assign(value.toString().toUtf8().constData()); break; From 9c75dad1acca2d48f26c97123875fc4ed5c60a3c Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 11 Apr 2015 18:21:08 +1000 Subject: [PATCH 0915/3725] Why is gcc so unkind? --- apps/opencs/model/world/idadapterimp.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/world/idadapterimp.hpp b/apps/opencs/model/world/idadapterimp.hpp index 00f7b1831..9c4686f4e 100644 --- a/apps/opencs/model/world/idadapterimp.hpp +++ b/apps/opencs/model/world/idadapterimp.hpp @@ -297,7 +297,7 @@ namespace CSMWorld // FIXME: how to ensure that the map entries correspond to table indicies? // WARNING: Assumed that the table view has the same order as std::map - std::map::const_iterator iter = reactions.begin(); + std::map::iterator iter = reactions.begin(); for(int i = 0; i < rowToRemove; ++i) iter++; reactions.erase(iter); @@ -351,7 +351,7 @@ namespace CSMWorld // FIXME: how to ensure that the map entries correspond to table indicies? // WARNING: Assumed that the table view has the same order as std::map - std::map::const_iterator iter = reactions.begin(); + std::map::iterator iter = reactions.begin(); for(int i = 0; i < subRowIndex; ++i) iter++; From f939648736ccf09a4d93699b2f8f3d7ea26ed6e7 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 11 Apr 2015 19:05:03 +1000 Subject: [PATCH 0916/3725] Add race spells table to dialogue subview. --- apps/opencs/model/world/columns.cpp | 2 +- apps/opencs/model/world/columns.hpp | 2 +- apps/opencs/model/world/data.cpp | 13 ++- apps/opencs/model/world/data.hpp | 2 +- apps/opencs/model/world/idadapterimp.hpp | 96 +++++++++++++++++++++ apps/opencs/model/world/refidcollection.cpp | 2 +- 6 files changed, 110 insertions(+), 7 deletions(-) diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index c9155a5ad..a2843d3e8 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -187,7 +187,7 @@ namespace CSMWorld { ColumnId_MeshType, "Mesh Type" }, { ColumnId_ActorInventory, "Inventory" }, - { ColumnId_ActorSpells, "Spells" }, + { ColumnId_SpellList, "Spells" }, { ColumnId_SpellId, "ID"}, { ColumnId_NpcDestinations, "Destinations" }, diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 531cf9972..a1dc89393 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -179,7 +179,7 @@ namespace CSMWorld ColumnId_BodyPartType = 164, ColumnId_MeshType = 165, ColumnId_ActorInventory = 166, - ColumnId_ActorSpells = 167, + ColumnId_SpellList = 167, ColumnId_SpellId = 168, ColumnId_NpcDestinations = 169, ColumnId_DestinationCell = 170, diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 3352dd30e..87ba44001 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -110,7 +110,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mFactions.addColumn (new SkillsColumn (i)); // Faction Reactions NestedParentColumn *reactions = - new NestedParentColumn (Columns::ColumnId_FactionReactions); + new NestedParentColumn (Columns::ColumnId_FactionReactions); mFactions.addColumn (reactions); mFactions.addAdapter (std::make_pair(reactions, new FactionReactionsAdapter ())); mFactions.getNestableColumn(mFactions.getColumns()-1)->addColumn( @@ -129,6 +129,13 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mRaces.addColumn (new WeightHeightColumn (true, false)); mRaces.addColumn (new WeightHeightColumn (false, true)); mRaces.addColumn (new WeightHeightColumn (false, false)); + // Race spells + NestedParentColumn *raceSpells = + new NestedParentColumn (Columns::ColumnId_SpellList); + mRaces.addColumn (raceSpells); + mRaces.addAdapter (std::make_pair(raceSpells, new SpellListAdapter ())); + mRaces.getNestableColumn(mRaces.getColumns()-1)->addColumn( + new NestedStringColumn (Columns::ColumnId_SpellId)); mSounds.addColumn (new StringIdColumn); mSounds.addColumn (new RecordStateColumn); @@ -151,7 +158,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mRegions.addColumn (new SleepListColumn); // Region Sounds NestedParentColumn *soundList = - new NestedParentColumn (Columns::ColumnId_RegionSounds); + new NestedParentColumn (Columns::ColumnId_RegionSounds); mRegions.addColumn (soundList); mRegions.addAdapter (std::make_pair(soundList, new RegionSoundListAdapter ())); mRegions.getNestableColumn(mRegions.getColumns()-1)->addColumn( @@ -354,7 +361,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc addModel (new IdTable (&mSkills), UniversalId::Type_Skill); addModel (new IdTable (&mClasses), UniversalId::Type_Class); addModel (new IdTree (&mFactions, &mFactions), UniversalId::Type_Faction); - addModel (new IdTable (&mRaces), UniversalId::Type_Race); + addModel (new IdTree (&mRaces, &mRaces), UniversalId::Type_Race); addModel (new IdTable (&mSounds), UniversalId::Type_Sound); addModel (new IdTable (&mScripts), UniversalId::Type_Script); addModel (new IdTree (&mRegions, &mRegions), UniversalId::Type_Region); diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 858f82639..172a194be 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -70,7 +70,7 @@ namespace CSMWorld IdCollection mSkills; IdCollection mClasses; NestedIdCollection mFactions; - IdCollection mRaces; + NestedIdCollection mRaces; IdCollection mSounds; IdCollection mScripts; NestedIdCollection mRegions; diff --git a/apps/opencs/model/world/idadapterimp.hpp b/apps/opencs/model/world/idadapterimp.hpp index 9c4686f4e..c49435f1c 100644 --- a/apps/opencs/model/world/idadapterimp.hpp +++ b/apps/opencs/model/world/idadapterimp.hpp @@ -487,6 +487,102 @@ namespace CSMWorld return static_cast(record.get().mSoundList.size()); } }; + + template + class SpellListAdapter : public NestedIdAdapter + { + public: + SpellListAdapter () {} + + virtual void addNestedRow(Record& record, int position) const + { + ESXRecordT raceOrBthSgn = record.get(); + + std::vector& spells = raceOrBthSgn.mPowers.mList; + + // blank row + std::string spell = ""; + + spells.insert(spells.begin()+position, spell); + + record.setModified (raceOrBthSgn); + } + + virtual void removeNestedRow(Record& record, int rowToRemove) const + { + ESXRecordT raceOrBthSgn = record.get(); + + std::vector& spells = raceOrBthSgn.mPowers.mList; + + if (rowToRemove < 0 || rowToRemove >= static_cast (spells.size())) + throw std::runtime_error ("index out of range"); + + spells.erase(spells.begin()+rowToRemove); + + record.setModified (raceOrBthSgn); + } + + virtual void setNestedTable(Record& record, const NestedTableWrapperBase& nestedTable) const + { + record.get().mPowers.mList = + static_cast >&>(nestedTable).mNestedTable; + } + + virtual NestedTableWrapperBase* nestedTable(const Record& record) const + { + // deleted by dtor of NestedTableStoring + return new NestedTableWrapper >(record.get().mPowers.mList); + } + + virtual QVariant getNestedData(const Record& record, int subRowIndex, int subColIndex) const + { + ESXRecordT raceOrBthSgn = record.get(); + + std::vector& spells = raceOrBthSgn.mPowers.mList; + + if (subRowIndex < 0 || subRowIndex >= static_cast (spells.size())) + throw std::runtime_error ("index out of range"); + + std::string spell = spells[subRowIndex]; + switch (subColIndex) + { + case 0: return QString(spell.c_str()); + default: throw std::runtime_error("Spells subcolumn index out of range"); + } + } + + virtual void setNestedData(Record& record, const QVariant& value, + int subRowIndex, int subColIndex) const + { + ESXRecordT raceOrBthSgn = record.get(); + + std::vector& spells = raceOrBthSgn.mPowers.mList; + + if (subRowIndex < 0 || subRowIndex >= static_cast (spells.size())) + throw std::runtime_error ("index out of range"); + + std::string spell = spells[subRowIndex]; + switch (subColIndex) + { + case 0: spell = value.toString().toUtf8().constData(); break; + default: throw std::runtime_error("Spells subcolumn index out of range"); + } + + raceOrBthSgn.mPowers.mList[subRowIndex] = spell; + + record.setModified (raceOrBthSgn); + } + + virtual int getNestedColumnsCount(const Record& record) const + { + return 1; + } + + virtual int getNestedRowsCount(const Record& record) const + { + return static_cast(record.get().mPowers.mList.size()); + } + }; } #endif // CSM_WOLRD_IDADAPTERIMP_H diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index b85deef4e..392a1677e 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -106,7 +106,7 @@ CSMWorld::RefIdCollection::RefIdCollection() new RefIdColumn (Columns::ColumnId_ItemCount, CSMWorld::ColumnBase::Display_Integer)); // Nested table - mColumns.push_back(RefIdColumn (Columns::ColumnId_ActorSpells, ColumnBase::Display_NestedSpellList, ColumnBase::Flag_Dialogue)); + mColumns.push_back(RefIdColumn (Columns::ColumnId_SpellList, ColumnBase::Display_NestedSpellList, ColumnBase::Flag_Dialogue)); actorsColumns.mSpells = &mColumns.back(); mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_SpellId, CSMWorld::ColumnBase::Display_String)); From 49fd5afdf650243a93e0a276fe665b2c7a6272c4 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 11 Apr 2015 19:17:17 +1000 Subject: [PATCH 0917/3725] Add birthsign spells table to dialogue subview. --- apps/opencs/model/world/data.cpp | 9 ++++++++- apps/opencs/model/world/data.hpp | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 87ba44001..74b418b30 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -172,6 +172,13 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mBirthsigns.addColumn (new NameColumn); mBirthsigns.addColumn (new TextureColumn); mBirthsigns.addColumn (new DescriptionColumn); + // Birthsign spells + NestedParentColumn *birthSpells = + new NestedParentColumn (Columns::ColumnId_SpellList); + mBirthsigns.addColumn (birthSpells); + mBirthsigns.addAdapter (std::make_pair(birthSpells, new SpellListAdapter ())); + mBirthsigns.getNestableColumn(mBirthsigns.getColumns()-1)->addColumn( + new NestedStringColumn (Columns::ColumnId_SpellId)); mSpells.addColumn (new StringIdColumn); mSpells.addColumn (new RecordStateColumn); @@ -365,7 +372,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc addModel (new IdTable (&mSounds), UniversalId::Type_Sound); addModel (new IdTable (&mScripts), UniversalId::Type_Script); addModel (new IdTree (&mRegions, &mRegions), UniversalId::Type_Region); - addModel (new IdTable (&mBirthsigns), UniversalId::Type_Birthsign); + addModel (new IdTree (&mBirthsigns, &mBirthsigns), UniversalId::Type_Birthsign); addModel (new IdTable (&mSpells), UniversalId::Type_Spell); addModel (new IdTable (&mTopics), UniversalId::Type_Topic); addModel (new IdTable (&mJournals), UniversalId::Type_Journal); diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 172a194be..2d2fd974c 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -74,7 +74,7 @@ namespace CSMWorld IdCollection mSounds; IdCollection mScripts; NestedIdCollection mRegions; - IdCollection mBirthsigns; + NestedIdCollection mBirthsigns; IdCollection mSpells; IdCollection mTopics; IdCollection mJournals; From a460409555b1edc0fa7f8b1a8bb2217fea771ecb Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 11 Apr 2015 21:43:25 +1000 Subject: [PATCH 0918/3725] Add Spells and Enchantment magic effects table to dialogue subview. The numbers are not yet converted to strings. --- apps/opencs/model/world/columnimp.hpp | 98 +------------------ apps/opencs/model/world/columns.cpp | 6 ++ apps/opencs/model/world/columns.hpp | 6 ++ apps/opencs/model/world/data.cpp | 75 +++++++++++--- apps/opencs/model/world/data.hpp | 4 +- apps/opencs/model/world/idadapterimp.hpp | 119 +++++++++++++++++++++++ 6 files changed, 201 insertions(+), 107 deletions(-) diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index 675352d35..0ab33065b 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -2265,97 +2265,6 @@ namespace CSMWorld } }; - template - struct PathgridPointListColumn : public Column - { - PathgridPointListColumn () - : Column (Columns::ColumnId_PathgridPoints, - ColumnBase::Display_PathgridPointList, ColumnBase::Flag_Dialogue) - {} - - virtual QVariant get (const Record& record) const - { - return true; // required by IdTree::hasChildren() - } - - virtual bool isEditable() const - { - return true; - } - }; - - struct PathgridIndexColumn : public NestableColumn - { - PathgridIndexColumn() - : NestableColumn (Columns::ColumnId_PathgridIndex, - ColumnBase::Display_Integer, ColumnBase::Flag_Dialogue) - {} - - virtual bool isEditable() const - { - return false; - } - }; - - struct PathgridPointColumn : public NestableColumn - { - PathgridPointColumn(int index) - : NestableColumn (Columns::ColumnId_PathgridPosX+index, - ColumnBase::Display_Integer, ColumnBase::Flag_Dialogue) - {} - - virtual bool isEditable() const - { - return true; - } - }; - - template - struct PathgridEdgeListColumn : public Column - { - PathgridEdgeListColumn () - : Column (Columns::ColumnId_PathgridEdges, - ColumnBase::Display_PathgridEdgeList, ColumnBase::Flag_Dialogue) - {} - - virtual QVariant get (const Record& record) const - { - return true; // required by IdTree::hasChildren() - } - - virtual bool isEditable() const - { - return true; - } - - }; - - struct PathgridEdgeIndexColumn : public NestableColumn - { - PathgridEdgeIndexColumn() - : NestableColumn (Columns::ColumnId_PathgridEdgeIndex, - ColumnBase::Display_Integer, ColumnBase::Flag_Dialogue) - {} - - virtual bool isEditable() const - { - return false; - } - }; - - struct PathgridEdgeColumn : public NestableColumn - { - PathgridEdgeColumn (int index) - : NestableColumn (Columns::ColumnId_PathgridEdge0+index, - ColumnBase::Display_Integer, ColumnBase::Flag_Dialogue) - {} - - virtual bool isEditable() const - { - return true; - } - }; - template struct NestedParentColumn : public Column { @@ -2389,13 +2298,16 @@ namespace CSMWorld struct NestedIntegerColumn : public NestableColumn { - NestedIntegerColumn (Columns::ColumnId id) + bool mIsEditable; + + NestedIntegerColumn (Columns::ColumnId id, bool isEditable = true) : NestableColumn (id, ColumnBase::Display_Integer, ColumnBase::Flag_Dialogue) + , mIsEditable(isEditable) {} virtual bool isEditable() const { - return true; + return mIsEditable; } }; } diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index a2843d3e8..efe9a5116 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -241,6 +241,12 @@ namespace CSMWorld //{ ColumnId_FactionID, "Faction ID"}, { ColumnId_FactionReaction, "Reaction"}, + { ColumnId_EffectList, "Effects"}, + { ColumnId_EffectId, "ID"}, + { ColumnId_EffectAttribute, "Attrib"}, + { ColumnId_EffectRange, "Range"}, + { ColumnId_EffectArea, "Area"}, + { ColumnId_UseValue1, "Use value 1" }, { ColumnId_UseValue2, "Use value 2" }, { ColumnId_UseValue3, "Use value 3" }, diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index a1dc89393..6b3791042 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -230,6 +230,12 @@ namespace CSMWorld //ColumnId_FactionID = 212, ColumnId_FactionReaction = 213, + ColumnId_EffectList = 214, + ColumnId_EffectId = 215, + ColumnId_EffectAttribute = 216, + ColumnId_EffectRange = 217, + ColumnId_EffectArea = 218, + // Allocated to a separate value range, so we don't get a collision should we ever need // to extend the number of use values. ColumnId_UseValue1 = 0x10000, diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 74b418b30..86cf3bb44 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -189,6 +189,27 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mSpells.addColumn (new FlagColumn (Columns::ColumnId_AutoCalc, 0x1)); mSpells.addColumn (new FlagColumn (Columns::ColumnId_StarterSpell, 0x2)); mSpells.addColumn (new FlagColumn (Columns::ColumnId_AlwaysSucceeds, 0x4)); + // Spell effects + NestedParentColumn *spellEffect = + new NestedParentColumn (Columns::ColumnId_EffectList); + mSpells.addColumn (spellEffect); + mSpells.addAdapter (std::make_pair(spellEffect, new EffectsListAdapter ())); + mSpells.getNestableColumn(mSpells.getColumns()-1)->addColumn( + new NestedIntegerColumn (Columns::ColumnId_EffectId)); + mSpells.getNestableColumn(mSpells.getColumns()-1)->addColumn( + new NestedIntegerColumn (Columns::ColumnId_Skill)); + mSpells.getNestableColumn(mSpells.getColumns()-1)->addColumn( + new NestedIntegerColumn (Columns::ColumnId_EffectAttribute)); + mSpells.getNestableColumn(mSpells.getColumns()-1)->addColumn( + new NestedIntegerColumn (Columns::ColumnId_EffectRange)); + mSpells.getNestableColumn(mSpells.getColumns()-1)->addColumn( + new NestedIntegerColumn (Columns::ColumnId_EffectArea)); + mSpells.getNestableColumn(mSpells.getColumns()-1)->addColumn( + new NestedIntegerColumn (Columns::ColumnId_Duration)); // reuse from light + mSpells.getNestableColumn(mSpells.getColumns()-1)->addColumn( + new NestedIntegerColumn (Columns::ColumnId_MinRange)); // reuse from sound + mSpells.getNestableColumn(mSpells.getColumns()-1)->addColumn( + new NestedIntegerColumn (Columns::ColumnId_MaxRange)); // reuse from sound mTopics.addColumn (new StringIdColumn); mTopics.addColumn (new RecordStateColumn); @@ -242,6 +263,27 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mEnchantments.addColumn (new CostColumn); mEnchantments.addColumn (new ChargesColumn2); mEnchantments.addColumn (new AutoCalcColumn); + // Enchantment effects + NestedParentColumn *enchantmentEffect = + new NestedParentColumn (Columns::ColumnId_EffectList); + mEnchantments.addColumn (enchantmentEffect); + mEnchantments.addAdapter (std::make_pair(enchantmentEffect, new EffectsListAdapter ())); + mEnchantments.getNestableColumn(mEnchantments.getColumns()-1)->addColumn( + new NestedIntegerColumn (Columns::ColumnId_EffectId)); + mEnchantments.getNestableColumn(mEnchantments.getColumns()-1)->addColumn( + new NestedIntegerColumn (Columns::ColumnId_Skill)); + mEnchantments.getNestableColumn(mEnchantments.getColumns()-1)->addColumn( + new NestedIntegerColumn (Columns::ColumnId_EffectAttribute)); + mEnchantments.getNestableColumn(mEnchantments.getColumns()-1)->addColumn( + new NestedIntegerColumn (Columns::ColumnId_EffectRange)); + mEnchantments.getNestableColumn(mEnchantments.getColumns()-1)->addColumn( + new NestedIntegerColumn (Columns::ColumnId_EffectArea)); + mEnchantments.getNestableColumn(mEnchantments.getColumns()-1)->addColumn( + new NestedIntegerColumn (Columns::ColumnId_Duration)); // reuse from light + mEnchantments.getNestableColumn(mEnchantments.getColumns()-1)->addColumn( + new NestedIntegerColumn (Columns::ColumnId_MinRange)); // reuse from sound + mEnchantments.getNestableColumn(mEnchantments.getColumns()-1)->addColumn( + new NestedIntegerColumn (Columns::ColumnId_MaxRange)); // reuse from sound mBodyParts.addColumn (new StringIdColumn); mBodyParts.addColumn (new RecordStateColumn); @@ -289,23 +331,32 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mPathgrids.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Pathgrid)); // new object deleted in dtor of Collection - PathgridPointListColumn *pointList = new PathgridPointListColumn (); + NestedParentColumn *pointList = + new NestedParentColumn (Columns::ColumnId_PathgridPoints); mPathgrids.addColumn (pointList); // new object deleted in dtor of SubCellCollection mPathgrids.addAdapter (std::make_pair(pointList, new PathgridPointListAdapter ())); // new objects deleted in dtor of NestableColumn // WARNING: The order of the columns below are assumed in PathgridPointListAdapter - mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn(new PathgridIndexColumn ()); - mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn(new PathgridPointColumn (0)); - mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn(new PathgridPointColumn (1)); - mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn(new PathgridPointColumn (2)); - - PathgridEdgeListColumn *edgeList = new PathgridEdgeListColumn (); + mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn( + new NestedIntegerColumn (Columns::ColumnId_PathgridIndex, false)); + mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn( + new NestedIntegerColumn (Columns::ColumnId_PathgridPosX)); + mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn( + new NestedIntegerColumn (Columns::ColumnId_PathgridPosY)); + mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn( + new NestedIntegerColumn (Columns::ColumnId_PathgridPosZ)); + + NestedParentColumn *edgeList = + new NestedParentColumn (Columns::ColumnId_PathgridEdges); mPathgrids.addColumn (edgeList); mPathgrids.addAdapter (std::make_pair(edgeList, new PathgridEdgeListAdapter ())); - mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn(new PathgridEdgeIndexColumn ()); - mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn(new PathgridEdgeColumn (0)); - mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn(new PathgridEdgeColumn (1)); + mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn( + new NestedIntegerColumn (Columns::ColumnId_PathgridEdgeIndex, false)); + mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn( + new NestedIntegerColumn (Columns::ColumnId_PathgridEdge0)); + mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn( + new NestedIntegerColumn (Columns::ColumnId_PathgridEdge1)); mStartScripts.addColumn (new StringIdColumn); mStartScripts.addColumn (new RecordStateColumn); @@ -373,13 +424,13 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc addModel (new IdTable (&mScripts), UniversalId::Type_Script); addModel (new IdTree (&mRegions, &mRegions), UniversalId::Type_Region); addModel (new IdTree (&mBirthsigns, &mBirthsigns), UniversalId::Type_Birthsign); - addModel (new IdTable (&mSpells), UniversalId::Type_Spell); + addModel (new IdTree (&mSpells, &mSpells), UniversalId::Type_Spell); addModel (new IdTable (&mTopics), UniversalId::Type_Topic); addModel (new IdTable (&mJournals), UniversalId::Type_Journal); addModel (new IdTable (&mTopicInfos, IdTable::Feature_ReorderWithinTopic), UniversalId::Type_TopicInfo); addModel (new IdTable (&mJournalInfos, IdTable::Feature_ReorderWithinTopic), UniversalId::Type_JournalInfo); addModel (new IdTable (&mCells, IdTable::Feature_ViewId), UniversalId::Type_Cell); - addModel (new IdTable (&mEnchantments), UniversalId::Type_Enchantment); + addModel (new IdTree (&mEnchantments, &mEnchantments), UniversalId::Type_Enchantment); addModel (new IdTable (&mBodyParts), UniversalId::Type_BodyPart); addModel (new IdTable (&mSoundGens), UniversalId::Type_SoundGen); addModel (new IdTable (&mMagicEffects), UniversalId::Type_MagicEffect); diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 2d2fd974c..5ab69ac10 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -75,10 +75,10 @@ namespace CSMWorld IdCollection mScripts; NestedIdCollection mRegions; NestedIdCollection mBirthsigns; - IdCollection mSpells; + NestedIdCollection mSpells; IdCollection mTopics; IdCollection mJournals; - IdCollection mEnchantments; + NestedIdCollection mEnchantments; IdCollection mBodyParts; IdCollection mMagicEffects; SubCellCollection mPathgrids; diff --git a/apps/opencs/model/world/idadapterimp.hpp b/apps/opencs/model/world/idadapterimp.hpp index c49435f1c..219032dd3 100644 --- a/apps/opencs/model/world/idadapterimp.hpp +++ b/apps/opencs/model/world/idadapterimp.hpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "idadapter.hpp" #include "nestedtablewrapper.hpp" @@ -583,6 +584,124 @@ namespace CSMWorld return static_cast(record.get().mPowers.mList.size()); } }; + + template + class EffectsListAdapter : public NestedIdAdapter + { + public: + EffectsListAdapter () {} + + virtual void addNestedRow(Record& record, int position) const + { + ESXRecordT magic = record.get(); + + std::vector& effectsList = magic.mEffects.mList; + + // blank row + ESM::ENAMstruct effect; + effect.mEffectID = 0; + effect.mSkill = 0; + effect.mAttribute = 0; + effect.mRange = 0; + effect.mArea = 0; + effect.mDuration = 0; + effect.mMagnMin = 0; + effect.mMagnMax = 0; + + effectsList.insert(effectsList.begin()+position, effect); + + record.setModified (magic); + } + + virtual void removeNestedRow(Record& record, int rowToRemove) const + { + ESXRecordT magic = record.get(); + + std::vector& effectsList = magic.mEffects.mList; + + if (rowToRemove < 0 || rowToRemove >= static_cast (effectsList.size())) + throw std::runtime_error ("index out of range"); + + effectsList.erase(effectsList.begin()+rowToRemove); + + record.setModified (magic); + } + + virtual void setNestedTable(Record& record, const NestedTableWrapperBase& nestedTable) const + { + record.get().mEffects.mList = + static_cast >&>(nestedTable).mNestedTable; + } + + virtual NestedTableWrapperBase* nestedTable(const Record& record) const + { + // deleted by dtor of NestedTableStoring + return new NestedTableWrapper >(record.get().mEffects.mList); + } + + virtual QVariant getNestedData(const Record& record, int subRowIndex, int subColIndex) const + { + ESXRecordT magic = record.get(); + + std::vector& effectsList = magic.mEffects.mList; + + if (subRowIndex < 0 || subRowIndex >= static_cast (effectsList.size())) + throw std::runtime_error ("index out of range"); + + ESM::ENAMstruct effect = effectsList[subRowIndex]; + switch (subColIndex) + { + case 0: return effect.mEffectID; + case 1: return effect.mSkill; + case 2: return effect.mAttribute; + case 3: return effect.mRange; + case 4: return effect.mArea; + case 5: return effect.mDuration; + case 6: return effect.mMagnMin; + case 7: return effect.mMagnMax; + default: throw std::runtime_error("Magic Effects subcolumn index out of range"); + } + } + + virtual void setNestedData(Record& record, const QVariant& value, + int subRowIndex, int subColIndex) const + { + ESXRecordT magic = record.get(); + + std::vector& effectsList = magic.mEffects.mList; + + if (subRowIndex < 0 || subRowIndex >= static_cast (effectsList.size())) + throw std::runtime_error ("index out of range"); + + ESM::ENAMstruct effect = effectsList[subRowIndex]; + switch (subColIndex) + { + case 0: effect.mEffectID = static_cast(value.toInt()); break; + case 1: effect.mSkill = static_cast(value.toInt()); break; + case 2: effect.mAttribute = static_cast(value.toInt()); break; + case 3: effect.mRange = value.toInt(); break; + case 4: effect.mArea = value.toInt(); break; + case 5: effect.mDuration = value.toInt(); break; + case 6: effect.mMagnMin = value.toInt(); break; + case 7: effect.mMagnMax = value.toInt(); break; + default: throw std::runtime_error("Magic Effects subcolumn index out of range"); + } + + magic.mEffects.mList[subRowIndex] = effect; + + record.setModified (magic); + } + + virtual int getNestedColumnsCount(const Record& record) const + { + return 8; + } + + virtual int getNestedRowsCount(const Record& record) const + { + return static_cast(record.get().mEffects.mList.size()); + } + }; } #endif // CSM_WOLRD_IDADAPTERIMP_H From e6cf959134d34dcc0cb727dc849848c391d91c95 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 11 Apr 2015 14:46:52 +0200 Subject: [PATCH 0919/3725] Revert "Delete nifosgtest" This reverts commit ba3075dc110b5da47ab5e1b3aa069d54fecd444b. --- CMakeLists.txt | 2 + apps/nifosgtest/CMakeLists.txt | 7 ++ apps/nifosgtest/test.cpp | 162 +++++++++++++++++++++++++++++++++ 3 files changed, 171 insertions(+) create mode 100644 apps/nifosgtest/CMakeLists.txt create mode 100644 apps/nifosgtest/test.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 5e510b29d..77bea373f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -559,6 +559,8 @@ if (BUILD_NIFTEST) endif(BUILD_NIFTEST) # Apps and tools +add_subdirectory( apps/nifosgtest ) + if (BUILD_OPENMW) add_subdirectory( apps/openmw ) endif() diff --git a/apps/nifosgtest/CMakeLists.txt b/apps/nifosgtest/CMakeLists.txt new file mode 100644 index 000000000..265577d98 --- /dev/null +++ b/apps/nifosgtest/CMakeLists.txt @@ -0,0 +1,7 @@ +set (FILES + test.cpp +) + +add_executable (test ${FILES}) + +target_link_libraries (test ${OPENSCENEGRAPH_LIBRARIES} "components") diff --git a/apps/nifosgtest/test.cpp b/apps/nifosgtest/test.cpp new file mode 100644 index 000000000..332867be5 --- /dev/null +++ b/apps/nifosgtest/test.cpp @@ -0,0 +1,162 @@ +#include +#include + +#include +#include + +#include + +#include +#include +#include + +#include + +#include + +#include +#include + +#include + +#include + +// EventHandler to toggle wireframe when 'w' key is pressed +class WireframeKeyHandler : public osgGA::GUIEventHandler +{ +public: + WireframeKeyHandler(osg::Node* node) + : mWireframe(false) + , mNode(node) + { + + } + + virtual bool handle(const osgGA::GUIEventAdapter& adapter,osgGA::GUIActionAdapter& action) + { + switch (adapter.getEventType()) + { + case osgGA::GUIEventAdapter::KEYDOWN: + if (adapter.getKey() == osgGA::GUIEventAdapter::KEY_W) + { + mWireframe = !mWireframe; + osg::PolygonMode* mode = new osg::PolygonMode; + mode->setMode(osg::PolygonMode::FRONT_AND_BACK, + mWireframe ? osg::PolygonMode::LINE : osg::PolygonMode::FILL); + + // Create a new stateset instead of changing the old one, this alleviates the need to set + // the StateSet to DYNAMIC DataVariance, which would have a performance impact. + + osg::StateSet* stateset = new osg::StateSet; + stateset->setAttributeAndModes(mode, osg::StateAttribute::ON); + stateset->setMode(GL_CULL_FACE, mWireframe ? osg::StateAttribute::OFF + : osg::StateAttribute::ON); + + mNode->setStateSet(stateset); + + return true; + } + default: + break; + } + return false; + } + +private: + bool mWireframe; + osg::Node* mNode; +}; + +int main(int argc, char** argv) +{ + if (argc < 2) + { + std::cout << "Usage: " << argv[0] << " " << std::endl; + return 1; + } + + Files::ConfigurationManager cfgMgr; + boost::program_options::options_description desc(""); + desc.add_options() + ("data", boost::program_options::value()->default_value(Files::PathContainer(), "data")->multitoken()->composing()) + ("fs-strict", boost::program_options::value()->implicit_value(true)->default_value(false)) + ("fallback-archive", boost::program_options::value >()-> + default_value(std::vector(), "fallback-archive")->multitoken()); + + boost::program_options::variables_map variables; + cfgMgr.readConfiguration(variables, desc); + + std::vector archives = variables["fallback-archive"].as >(); + bool fsStrict = variables["fs-strict"].as(); + Files::PathContainer dataDirs; + if (!variables["data"].empty()) { + dataDirs = Files::PathContainer(variables["data"].as()); + } + + cfgMgr.processPaths(dataDirs); + + VFS::Manager resourceMgr (fsStrict); + Files::Collections collections (dataDirs, !fsStrict); + + for (std::vector::const_iterator it = archives.begin(); it != archives.end(); ++it) + { + std::string filepath = collections.getPath(*it).string(); + resourceMgr.addArchive(new VFS::BsaArchive(filepath)); + } + for (Files::PathContainer::const_iterator it = dataDirs.begin(); it != dataDirs.end(); ++it) + { + resourceMgr.addArchive(new VFS::FileSystemArchive(it->string())); + } + + resourceMgr.buildIndex(); + + Nif::NIFFilePtr nif(new Nif::NIFFile(resourceMgr.get(argv[1]), std::string(argv[1]))); + + // For NiStencilProperty + osg::DisplaySettings::instance()->setMinimumNumStencilBits(8); + + osgViewer::Viewer viewer; + + osg::ref_ptr root(new osg::Group()); + root->getOrCreateStateSet()->setMode(GL_CULL_FACE, osg::StateAttribute::ON); + // To prevent lighting issues with scaled meshes + root->getOrCreateStateSet()->setMode(GL_NORMALIZE, osg::StateAttribute::ON); + + + //osgDB::writeNodeFile(*newNode, "out.osg"); + osg::Group* newNode = new osg::Group; + NifOsg::Loader loader; + Resource::TextureManager texMgr(&resourceMgr); + loader.mTextureManager = &texMgr; + newNode->addChild(loader.load(nif)); + + osg::PositionAttitudeTransform* trans = new osg::PositionAttitudeTransform; + root->addChild(trans); + + for (int x=0; x<1;++x) + { + //root->addChild(newNode); + trans->addChild(newNode); + } + + viewer.setSceneData(root); + + viewer.setUpViewInWindow(0, 0, 800, 600); + viewer.realize(); + viewer.setCameraManipulator(new osgGA::TrackballManipulator()); + viewer.addEventHandler(new WireframeKeyHandler(root)); + + // Mask to separate cull visitors from update visitors + viewer.getCamera()->setCullMask(~(0x1)); + + viewer.addEventHandler(new osgViewer::StatsHandler); + + while (!viewer.done()) + { + //trans->setAttitude(osg::Quat(viewer.getFrameStamp()->getSimulationTime()*5, osg::Vec3f(0,0,1))); + + viewer.frame(); + } + + return 0; +} From b0ea51a5c8ffb8922e71c124d09719025fb3eb40 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 11 Apr 2015 20:09:40 +0200 Subject: [PATCH 0920/3725] Colour conversion utility --- .../view/render/unpagedworldspacewidget.cpp | 7 +++---- components/sceneutil/util.cpp | 17 +++++++++++++++++ components/sceneutil/util.hpp | 5 +++++ 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/apps/opencs/view/render/unpagedworldspacewidget.cpp b/apps/opencs/view/render/unpagedworldspacewidget.cpp index a6d18a0f2..dec7d493e 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.cpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.cpp @@ -7,6 +7,8 @@ #include +#include + #include "../../model/doc/document.hpp" #include "../../model/world/data.hpp" @@ -23,10 +25,7 @@ void CSVRender::UnpagedWorldspaceWidget::update() const CSMWorld::Record& record = dynamic_cast&> (mCellsModel->getRecord (mCellId)); - ESM::Color clr = record.get().mAmbi.mAmbient; - osg::Vec4f colour(((clr >> 0) & 0xFF) / 255.0f, - ((clr >> 8) & 0xFF) / 255.0f, - ((clr >> 16) & 0xFF) / 255.0f, 1.f); + osg::Vec4f colour = SceneUtil::colourFromRGB(record.get().mAmbi.mAmbient); setDefaultAmbient (colour); diff --git a/components/sceneutil/util.cpp b/components/sceneutil/util.cpp index 0d99e762d..a41c6b74b 100644 --- a/components/sceneutil/util.cpp +++ b/components/sceneutil/util.cpp @@ -33,4 +33,21 @@ void transformBoundingSphere (const osg::Matrix& matrix, osg::BoundingSphere& bs if (bsphere._radius> 0) & 0xFF) / 255.0f, + ((clr >> 8) & 0xFF) / 255.0f, + ((clr >> 16) & 0xFF) / 255.0f, 1.f); + return colour; +} + +osg::Vec4f colourFromRGBA(unsigned int clr) +{ + osg::Vec4f colour(((clr >> 0) & 0xFF) / 255.0f, + ((clr >> 8) & 0xFF) / 255.0f, + ((clr >> 16) & 0xFF) / 255.0f, + ((clr >> 24) & 0xFF) / 255.0f); + return colour; +} + } diff --git a/components/sceneutil/util.hpp b/components/sceneutil/util.hpp index a8d970df1..c99771c5e 100644 --- a/components/sceneutil/util.hpp +++ b/components/sceneutil/util.hpp @@ -3,6 +3,7 @@ #include #include +#include namespace SceneUtil { @@ -12,6 +13,10 @@ namespace SceneUtil // TODO: patch osg to make public void transformBoundingSphere (const osg::Matrix& matrix, osg::BoundingSphere& bsphere); + osg::Vec4f colourFromRGB (unsigned int clr); + + osg::Vec4f colourFromRGBA (unsigned int clr); + } #endif From a0b43f426e2861bd4c4f554c0e53dadc8d62c3ae Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 11 Apr 2015 23:01:37 +0200 Subject: [PATCH 0921/3725] Avoid setting DYNAMIC DataVariance on StateSets --- components/nifosg/controller.cpp | 16 ++++++++++++---- components/nifosg/controller.hpp | 19 +++++++++++++++---- components/nifosg/nifloader.cpp | 4 ---- 3 files changed, 27 insertions(+), 12 deletions(-) diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index 5916359c8..59ba9ad4f 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -291,7 +291,7 @@ void UVController::operator()(osg::Node* node, osg::NodeVisitor* nv) { if (hasInput()) { - osg::StateSet* stateset = node->getStateSet(); + osg::StateSet* stateset = getWritableStateSet(node); float value = getInputValue(nv); float uTrans = interpKey(mUTrans->mKeys, value, 0.0f); float vTrans = interpKey(mVTrans->mKeys, value, 0.0f); @@ -372,7 +372,7 @@ void AlphaController::operator () (osg::Node* node, osg::NodeVisitor* nv) { if (hasInput()) { - osg::StateSet* stateset = node->getStateSet(); + osg::StateSet* stateset = getWritableStateSet(node); float value = interpKey(mData->mKeys, getInputValue(nv)); osg::Material* mat = dynamic_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); if (mat) @@ -404,7 +404,7 @@ void MaterialColorController::operator() (osg::Node* node, osg::NodeVisitor* nv) { if (hasInput()) { - osg::StateSet* stateset = node->getStateSet(); + osg::StateSet* stateset = getWritableStateSet(node); osg::Vec3f value = interpKey(mData->mKeys, getInputValue(nv)); osg::Material* mat = dynamic_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); if (mat) @@ -441,7 +441,7 @@ void FlipController::operator() (osg::Node* node, osg::NodeVisitor* nv) { if (hasInput() && mDelta != 0) { - osg::StateSet* stateset = node->getStateSet(); + osg::StateSet* stateset = getWritableStateSet(node); int curTexture = int(getInputValue(nv) / mDelta) % mTextures.size(); stateset->setTextureAttribute(mTexSlot, mTextures[curTexture]); } @@ -507,4 +507,12 @@ void SourcedKeyframeController::operator ()(osg::Node* node, osg::NodeVisitor* n traverse(node, nv); } +osg::StateSet *StateSetController::getWritableStateSet(osg::Node *node) +{ + osg::StateSet* orig = node->getOrCreateStateSet(); + osg::StateSet* cloned = new osg::StateSet(*orig, osg::CopyOp::SHALLOW_COPY); + node->setStateSet(cloned); + return cloned; +} + } diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index 80e6090e4..1a90b8759 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -189,8 +189,19 @@ namespace NifOsg bool mEnabled; }; + class StateSetController + { + protected: + // Clones a StateSet to make it "writable". This is to prevent race conditions when the OSG draw thread of the last frame + // queues up a StateSet that we want to modify. Note, we could also set the StateSet to DYNAMIC data variance but that would + // undo all the benefits of the threading model - having the cull and draw traversals run in parallel can yield up to 200% framerates. + // If the StateSet allocations per frame are proving too much of an overhead we could "reuse" StateSets from previous frames, + // kind of like a double buffering scheme. + osg::StateSet* getWritableStateSet(osg::Node* node); + }; + // Note we're using NodeCallback instead of StateSet::Callback because the StateSet callback doesn't support nesting - struct UVController : public osg::NodeCallback, public Controller, public ValueInterpolator + class UVController : public osg::NodeCallback, public Controller, public StateSetController, public ValueInterpolator { public: UVController(); @@ -226,7 +237,7 @@ namespace NifOsg virtual void operator() (osg::Node* node, osg::NodeVisitor* nv); }; - class AlphaController : public osg::NodeCallback, public Controller, public ValueInterpolator + class AlphaController : public osg::NodeCallback, public Controller, public StateSetController, public ValueInterpolator { private: Nif::FloatKeyMapPtr mData; @@ -241,7 +252,7 @@ namespace NifOsg META_Object(NifOsg, AlphaController) }; - class MaterialColorController : public osg::NodeCallback, public Controller, public ValueInterpolator + class MaterialColorController : public osg::NodeCallback, public Controller, public StateSetController, public ValueInterpolator { private: Nif::Vector3KeyMapPtr mData; @@ -256,7 +267,7 @@ namespace NifOsg virtual void operator() (osg::Node* node, osg::NodeVisitor* nv); }; - class FlipController : public osg::NodeCallback, public Controller + class FlipController : public osg::NodeCallback, public Controller, public StateSetController { private: int mTexSlot; diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index a5c9b6e2a..a85847351 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -881,7 +881,6 @@ namespace NifOsg osg::ref_ptr ctrl = new UVController(uvctrl->data.getPtr(), texUnits); setupController(uvctrl, ctrl, animflags); - transformNode->getOrCreateStateSet()->setDataVariance(osg::StateSet::DYNAMIC); transformNode->addUpdateCallback(ctrl); } @@ -927,7 +926,6 @@ namespace NifOsg const Nif::NiAlphaController* alphactrl = static_cast(ctrl.getPtr()); osg::ref_ptr ctrl(new AlphaController(alphactrl->data.getPtr())); setupController(alphactrl, ctrl, animflags); - stateset->setDataVariance(osg::StateSet::DYNAMIC); node->addUpdateCallback(ctrl); } else if (ctrl->recType == Nif::RC_NiMaterialColorController) @@ -935,7 +933,6 @@ namespace NifOsg const Nif::NiMaterialColorController* matctrl = static_cast(ctrl.getPtr()); osg::ref_ptr ctrl(new MaterialColorController(matctrl->data.getPtr())); setupController(matctrl, ctrl, animflags); - stateset->setDataVariance(osg::StateSet::DYNAMIC); node->addUpdateCallback(ctrl); } else @@ -975,7 +972,6 @@ namespace NifOsg } osg::ref_ptr callback(new FlipController(flipctrl, textures)); setupController(ctrl.getPtr(), callback, animflags); - stateset->setDataVariance(osg::StateSet::DYNAMIC); node->addUpdateCallback(callback); } else From 8dab2f9b14f93509f9c54d1572bb983f372c0546 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 12 Apr 2015 07:46:32 +1000 Subject: [PATCH 0922/3725] Use human friendly strings in magic effects subtable. --- apps/opencs/model/world/columnimp.hpp | 7 +- apps/opencs/model/world/columns.cpp | 4 +- apps/opencs/model/world/columns.hpp | 2 +- apps/opencs/model/world/data.cpp | 16 +-- apps/opencs/model/world/idadapterimp.hpp | 143 +++++++++++++++++++++-- 5 files changed, 151 insertions(+), 21 deletions(-) diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index 0ab33065b..210d63803 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -2286,13 +2286,16 @@ namespace CSMWorld struct NestedStringColumn : public NestableColumn { - NestedStringColumn (Columns::ColumnId id) + bool mIsEditable; + + NestedStringColumn (Columns::ColumnId id, bool isEditable = true) : NestableColumn (id, ColumnBase::Display_String, ColumnBase::Flag_Dialogue) + , mIsEditable(isEditable) {} virtual bool isEditable() const { - return true; + return mIsEditable; } }; diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index efe9a5116..fca16ec0b 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -242,8 +242,8 @@ namespace CSMWorld { ColumnId_FactionReaction, "Reaction"}, { ColumnId_EffectList, "Effects"}, - { ColumnId_EffectId, "ID"}, - { ColumnId_EffectAttribute, "Attrib"}, + { ColumnId_EffectId, "Effect"}, + //{ ColumnId_EffectAttribute, "Attrib"}, { ColumnId_EffectRange, "Range"}, { ColumnId_EffectArea, "Area"}, diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 6b3791042..4f77ee23a 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -232,7 +232,7 @@ namespace CSMWorld ColumnId_EffectList = 214, ColumnId_EffectId = 215, - ColumnId_EffectAttribute = 216, + //ColumnId_EffectAttribute = 216, ColumnId_EffectRange = 217, ColumnId_EffectArea = 218, diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 86cf3bb44..538b240dc 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -195,15 +195,15 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mSpells.addColumn (spellEffect); mSpells.addAdapter (std::make_pair(spellEffect, new EffectsListAdapter ())); mSpells.getNestableColumn(mSpells.getColumns()-1)->addColumn( - new NestedIntegerColumn (Columns::ColumnId_EffectId)); + new NestedStringColumn (Columns::ColumnId_EffectId/*, false*/)); // false means no edit mSpells.getNestableColumn(mSpells.getColumns()-1)->addColumn( - new NestedIntegerColumn (Columns::ColumnId_Skill)); + new NestedStringColumn (Columns::ColumnId_Skill)); mSpells.getNestableColumn(mSpells.getColumns()-1)->addColumn( - new NestedIntegerColumn (Columns::ColumnId_EffectAttribute)); + new NestedStringColumn (Columns::ColumnId_Attribute)); // reuse attribute mSpells.getNestableColumn(mSpells.getColumns()-1)->addColumn( new NestedIntegerColumn (Columns::ColumnId_EffectRange)); mSpells.getNestableColumn(mSpells.getColumns()-1)->addColumn( - new NestedIntegerColumn (Columns::ColumnId_EffectArea)); + new NestedStringColumn (Columns::ColumnId_EffectArea)); mSpells.getNestableColumn(mSpells.getColumns()-1)->addColumn( new NestedIntegerColumn (Columns::ColumnId_Duration)); // reuse from light mSpells.getNestableColumn(mSpells.getColumns()-1)->addColumn( @@ -269,15 +269,15 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mEnchantments.addColumn (enchantmentEffect); mEnchantments.addAdapter (std::make_pair(enchantmentEffect, new EffectsListAdapter ())); mEnchantments.getNestableColumn(mEnchantments.getColumns()-1)->addColumn( - new NestedIntegerColumn (Columns::ColumnId_EffectId)); + new NestedStringColumn (Columns::ColumnId_EffectId/*, false*/)); mEnchantments.getNestableColumn(mEnchantments.getColumns()-1)->addColumn( - new NestedIntegerColumn (Columns::ColumnId_Skill)); + new NestedStringColumn (Columns::ColumnId_Skill)); mEnchantments.getNestableColumn(mEnchantments.getColumns()-1)->addColumn( - new NestedIntegerColumn (Columns::ColumnId_EffectAttribute)); + new NestedStringColumn (Columns::ColumnId_Attribute)); // reuse attribute mEnchantments.getNestableColumn(mEnchantments.getColumns()-1)->addColumn( new NestedIntegerColumn (Columns::ColumnId_EffectRange)); mEnchantments.getNestableColumn(mEnchantments.getColumns()-1)->addColumn( - new NestedIntegerColumn (Columns::ColumnId_EffectArea)); + new NestedStringColumn (Columns::ColumnId_EffectArea)); mEnchantments.getNestableColumn(mEnchantments.getColumns()-1)->addColumn( new NestedIntegerColumn (Columns::ColumnId_Duration)); // reuse from light mEnchantments.getNestableColumn(mEnchantments.getColumns()-1)->addColumn( diff --git a/apps/opencs/model/world/idadapterimp.hpp b/apps/opencs/model/world/idadapterimp.hpp index 219032dd3..d5bf83a2d 100644 --- a/apps/opencs/model/world/idadapterimp.hpp +++ b/apps/opencs/model/world/idadapterimp.hpp @@ -7,6 +7,9 @@ #include #include #include +#include // for converting magic effect id to string & back +#include // for converting skill names +#include // for converting attributes #include "idadapter.hpp" #include "nestedtablewrapper.hpp" @@ -651,10 +654,82 @@ namespace CSMWorld ESM::ENAMstruct effect = effectsList[subRowIndex]; switch (subColIndex) { - case 0: return effect.mEffectID; - case 1: return effect.mSkill; - case 2: return effect.mAttribute; - case 3: return effect.mRange; + case 0: + { + // indexToId() prepends "#d+" hence not so user friendly + QString effectId(ESM::MagicEffect::effectIdToString(effect.mEffectID).c_str()); + return effectId.remove(0, 7); // 7 == sizeof("sEffect") - 1 + } + case 1: + { + switch (effect.mSkill) + { + // see ESM::Skill::SkillEnum in + case ESM::Skill::Block: + case ESM::Skill::Armorer: + case ESM::Skill::MediumArmor: + case ESM::Skill::HeavyArmor: + case ESM::Skill::BluntWeapon: + case ESM::Skill::LongBlade: + case ESM::Skill::Axe: + case ESM::Skill::Spear: + case ESM::Skill::Athletics: + case ESM::Skill::Enchant: + case ESM::Skill::Destruction: + case ESM::Skill::Alteration: + case ESM::Skill::Illusion: + case ESM::Skill::Conjuration: + case ESM::Skill::Mysticism: + case ESM::Skill::Restoration: + case ESM::Skill::Alchemy: + case ESM::Skill::Unarmored: + case ESM::Skill::Security: + case ESM::Skill::Sneak: + case ESM::Skill::Acrobatics: + case ESM::Skill::LightArmor: + case ESM::Skill::ShortBlade: + case ESM::Skill::Marksman: + case ESM::Skill::Mercantile: + case ESM::Skill::Speechcraft: + case ESM::Skill::HandToHand: + { + return QString(ESM::Skill::sSkillNames[effect.mSkill].c_str()); + } + case -1: return QString("N/A"); + default: return QVariant(); + } + } + case 2: + { + switch (effect.mAttribute) + { + // see ESM::Attribute::AttributeID in + case ESM::Attribute::Strength: + case ESM::Attribute::Intelligence: + case ESM::Attribute::Willpower: + case ESM::Attribute::Agility: + case ESM::Attribute::Speed: + case ESM::Attribute::Endurance: + case ESM::Attribute::Personality: + case ESM::Attribute::Luck: + { + return QString(ESM::Attribute::sAttributeNames[effect.mAttribute].c_str()); + } + case -1: return QString("N/A"); + default: return QVariant(); + } + } + case 3: + { + switch (effect.mRange) + { + // see ESM::RangeType in + case ESM::RT_Self: return QString("Self"); + case ESM::RT_Touch: return QString("Touch"); + case ESM::RT_Target: return QString("Target"); + default: return QVariant(); + } + } case 4: return effect.mArea; case 5: return effect.mDuration; case 6: return effect.mMagnMin; @@ -676,10 +751,62 @@ namespace CSMWorld ESM::ENAMstruct effect = effectsList[subRowIndex]; switch (subColIndex) { - case 0: effect.mEffectID = static_cast(value.toInt()); break; - case 1: effect.mSkill = static_cast(value.toInt()); break; - case 2: effect.mAttribute = static_cast(value.toInt()); break; - case 3: effect.mRange = value.toInt(); break; + case 0: + { + effect.mEffectID = + ESM::MagicEffect::effectStringToId("sEffect"+value.toString().toStdString()); + break; + } + case 1: + { + std::string skillName = value.toString().toStdString(); + if ("N/A" == skillName) + { + effect.mSkill = -1; + break; + } + + for (unsigned int i = 0; i < ESM::Skill::Length; ++i) + { + if (ESM::Skill::sSkillNames[i] == skillName) + { + effect.mSkill = static_cast(i); + break; + } + } + break; + } + case 2: + { + std::string attr = value.toString().toStdString(); + if ("N/A" == attr) + { + effect.mAttribute = -1; + break; + } + + for (unsigned int i = 0; i < ESM::Attribute::Length; ++i) + { + if (ESM::Attribute::sAttributeNames[i] == attr) + { + effect.mAttribute = static_cast(i); + break; + } + } + break; + } + case 3: + { + std::string effectId = value.toString().toStdString(); + if (effectId == "Self") + effect.mRange = ESM::RT_Self; + else if (effectId == "Touch") + effect.mRange = ESM::RT_Touch; + else if (effectId == "Target") + effect.mRange = ESM::RT_Target; + // else leave unchanged + break; + } case 4: effect.mArea = value.toInt(); break; case 5: effect.mDuration = value.toInt(); break; case 6: effect.mMagnMin = value.toInt(); break; From 4b9c9bf09510b89aff9926522037252daafa9c28 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 12 Apr 2015 08:52:09 +1000 Subject: [PATCH 0923/3725] Simplify and relocate nested column definitions. --- apps/opencs/model/world/columnbase.cpp | 15 +++++-- apps/opencs/model/world/columnbase.hpp | 27 ++++++++++++ apps/opencs/model/world/columnimp.hpp | 49 ---------------------- apps/opencs/model/world/data.cpp | 58 +++++++++++++------------- 4 files changed, 68 insertions(+), 81 deletions(-) diff --git a/apps/opencs/model/world/columnbase.cpp b/apps/opencs/model/world/columnbase.cpp index 8d1985ff2..0d9eb1664 100644 --- a/apps/opencs/model/world/columnbase.cpp +++ b/apps/opencs/model/world/columnbase.cpp @@ -3,7 +3,7 @@ #include "columns.hpp" CSMWorld::ColumnBase::ColumnBase (int columnId, Display displayType, int flags) -: mColumnId (columnId), mDisplayType (displayType), mFlags (flags) + : mColumnId (columnId), mDisplayType (displayType), mFlags (flags) {} CSMWorld::ColumnBase::~ColumnBase() {} @@ -39,8 +39,7 @@ const CSMWorld::ColumnBase& CSMWorld::NestableColumn::nestedColumn(int subColumn CSMWorld::NestableColumn::NestableColumn(int columnId, CSMWorld::ColumnBase::Display displayType, int flag) : CSMWorld::ColumnBase(columnId, displayType, flag) -{ -} +{} CSMWorld::NestableColumn::~NestableColumn() { @@ -54,3 +53,13 @@ bool CSMWorld::NestableColumn::hasChildren() const { return !mNestedColumns.empty(); } + +CSMWorld::NestedChildColumn::NestedChildColumn (int id, + CSMWorld::ColumnBase::Display display, bool isEditable) + : NestableColumn (id, display, CSMWorld::ColumnBase::Flag_Dialogue) , mIsEditable(isEditable) +{} + +bool CSMWorld::NestedChildColumn::isEditable () const +{ + return mIsEditable; +} diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index c994ced15..dc3aae11a 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -165,6 +165,33 @@ namespace CSMWorld throw std::logic_error ("Column " + getTitle() + " is not editable"); } }; + + template + struct NestedParentColumn : public Column + { + NestedParentColumn (int id) : Column (id, Display_NestedHeader, Flag_Dialogue) + {} + + virtual QVariant get (const Record& record) const + { + return true; // required by IdTree::hasChildren() + } + + virtual bool isEditable() const + { + return true; + } + }; + + struct NestedChildColumn : public NestableColumn + { + NestedChildColumn (int id, Display display, bool isEditable = true); + + virtual bool isEditable() const; + + private: + bool mIsEditable; + }; } #endif diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index 210d63803..68e7dd7b5 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -2264,55 +2264,6 @@ namespace CSMWorld return true; } }; - - template - struct NestedParentColumn : public Column - { - NestedParentColumn (Columns::ColumnId id) - : Column (id, ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue) - {} - - virtual QVariant get (const Record& record) const - { - return true; // required by IdTree::hasChildren() - } - - virtual bool isEditable() const - { - return true; - } - - }; - - struct NestedStringColumn : public NestableColumn - { - bool mIsEditable; - - NestedStringColumn (Columns::ColumnId id, bool isEditable = true) - : NestableColumn (id, ColumnBase::Display_String, ColumnBase::Flag_Dialogue) - , mIsEditable(isEditable) - {} - - virtual bool isEditable() const - { - return mIsEditable; - } - }; - - struct NestedIntegerColumn : public NestableColumn - { - bool mIsEditable; - - NestedIntegerColumn (Columns::ColumnId id, bool isEditable = true) - : NestableColumn (id, ColumnBase::Display_Integer, ColumnBase::Flag_Dialogue) - , mIsEditable(isEditable) - {} - - virtual bool isEditable() const - { - return mIsEditable; - } - }; } #endif diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 538b240dc..69e2b5aa8 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -114,9 +114,9 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mFactions.addColumn (reactions); mFactions.addAdapter (std::make_pair(reactions, new FactionReactionsAdapter ())); mFactions.getNestableColumn(mFactions.getColumns()-1)->addColumn( - new NestedStringColumn (Columns::ColumnId_Faction)); + new NestedChildColumn (Columns::ColumnId_Faction, ColumnBase::Display_String)); mFactions.getNestableColumn(mFactions.getColumns()-1)->addColumn( - new NestedIntegerColumn (Columns::ColumnId_FactionReaction)); + new NestedChildColumn (Columns::ColumnId_FactionReaction, ColumnBase::Display_Integer)); mRaces.addColumn (new StringIdColumn); mRaces.addColumn (new RecordStateColumn); @@ -135,7 +135,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mRaces.addColumn (raceSpells); mRaces.addAdapter (std::make_pair(raceSpells, new SpellListAdapter ())); mRaces.getNestableColumn(mRaces.getColumns()-1)->addColumn( - new NestedStringColumn (Columns::ColumnId_SpellId)); + new NestedChildColumn (Columns::ColumnId_SpellId, ColumnBase::Display_String)); mSounds.addColumn (new StringIdColumn); mSounds.addColumn (new RecordStateColumn); @@ -162,9 +162,9 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mRegions.addColumn (soundList); mRegions.addAdapter (std::make_pair(soundList, new RegionSoundListAdapter ())); mRegions.getNestableColumn(mRegions.getColumns()-1)->addColumn( - new NestedStringColumn (Columns::ColumnId_SoundName)); + new NestedChildColumn (Columns::ColumnId_SoundName, ColumnBase::Display_String)); mRegions.getNestableColumn(mRegions.getColumns()-1)->addColumn( - new NestedIntegerColumn (Columns::ColumnId_SoundChance)); + new NestedChildColumn (Columns::ColumnId_SoundChance, ColumnBase::Display_Integer)); mBirthsigns.addColumn (new StringIdColumn); mBirthsigns.addColumn (new RecordStateColumn); @@ -178,7 +178,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mBirthsigns.addColumn (birthSpells); mBirthsigns.addAdapter (std::make_pair(birthSpells, new SpellListAdapter ())); mBirthsigns.getNestableColumn(mBirthsigns.getColumns()-1)->addColumn( - new NestedStringColumn (Columns::ColumnId_SpellId)); + new NestedChildColumn (Columns::ColumnId_SpellId, ColumnBase::Display_String)); mSpells.addColumn (new StringIdColumn); mSpells.addColumn (new RecordStateColumn); @@ -195,21 +195,21 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mSpells.addColumn (spellEffect); mSpells.addAdapter (std::make_pair(spellEffect, new EffectsListAdapter ())); mSpells.getNestableColumn(mSpells.getColumns()-1)->addColumn( - new NestedStringColumn (Columns::ColumnId_EffectId/*, false*/)); // false means no edit + new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_String/*, false*/)); // false means no edit mSpells.getNestableColumn(mSpells.getColumns()-1)->addColumn( - new NestedStringColumn (Columns::ColumnId_Skill)); + new NestedChildColumn (Columns::ColumnId_Skill, ColumnBase::Display_String)); mSpells.getNestableColumn(mSpells.getColumns()-1)->addColumn( - new NestedStringColumn (Columns::ColumnId_Attribute)); // reuse attribute + new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_String)); // reuse attribute mSpells.getNestableColumn(mSpells.getColumns()-1)->addColumn( - new NestedIntegerColumn (Columns::ColumnId_EffectRange)); + new NestedChildColumn (Columns::ColumnId_EffectRange, ColumnBase::Display_Integer)); mSpells.getNestableColumn(mSpells.getColumns()-1)->addColumn( - new NestedStringColumn (Columns::ColumnId_EffectArea)); + new NestedChildColumn (Columns::ColumnId_EffectArea, ColumnBase::Display_String)); mSpells.getNestableColumn(mSpells.getColumns()-1)->addColumn( - new NestedIntegerColumn (Columns::ColumnId_Duration)); // reuse from light + new NestedChildColumn (Columns::ColumnId_Duration, ColumnBase::Display_Integer)); // reuse from light mSpells.getNestableColumn(mSpells.getColumns()-1)->addColumn( - new NestedIntegerColumn (Columns::ColumnId_MinRange)); // reuse from sound + new NestedChildColumn (Columns::ColumnId_MinRange, ColumnBase::Display_Integer)); // reuse from sound mSpells.getNestableColumn(mSpells.getColumns()-1)->addColumn( - new NestedIntegerColumn (Columns::ColumnId_MaxRange)); // reuse from sound + new NestedChildColumn (Columns::ColumnId_MaxRange, ColumnBase::Display_Integer)); // reuse from sound mTopics.addColumn (new StringIdColumn); mTopics.addColumn (new RecordStateColumn); @@ -269,21 +269,21 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mEnchantments.addColumn (enchantmentEffect); mEnchantments.addAdapter (std::make_pair(enchantmentEffect, new EffectsListAdapter ())); mEnchantments.getNestableColumn(mEnchantments.getColumns()-1)->addColumn( - new NestedStringColumn (Columns::ColumnId_EffectId/*, false*/)); + new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_String/*, false*/)); mEnchantments.getNestableColumn(mEnchantments.getColumns()-1)->addColumn( - new NestedStringColumn (Columns::ColumnId_Skill)); + new NestedChildColumn (Columns::ColumnId_Skill, ColumnBase::Display_String)); mEnchantments.getNestableColumn(mEnchantments.getColumns()-1)->addColumn( - new NestedStringColumn (Columns::ColumnId_Attribute)); // reuse attribute + new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_String)); // reuse attribute mEnchantments.getNestableColumn(mEnchantments.getColumns()-1)->addColumn( - new NestedIntegerColumn (Columns::ColumnId_EffectRange)); + new NestedChildColumn (Columns::ColumnId_EffectRange, ColumnBase::Display_Integer)); mEnchantments.getNestableColumn(mEnchantments.getColumns()-1)->addColumn( - new NestedStringColumn (Columns::ColumnId_EffectArea)); + new NestedChildColumn (Columns::ColumnId_EffectArea, ColumnBase::Display_String)); mEnchantments.getNestableColumn(mEnchantments.getColumns()-1)->addColumn( - new NestedIntegerColumn (Columns::ColumnId_Duration)); // reuse from light + new NestedChildColumn (Columns::ColumnId_Duration, ColumnBase::Display_Integer)); // reuse from light mEnchantments.getNestableColumn(mEnchantments.getColumns()-1)->addColumn( - new NestedIntegerColumn (Columns::ColumnId_MinRange)); // reuse from sound + new NestedChildColumn (Columns::ColumnId_MinRange, ColumnBase::Display_Integer)); // reuse from sound mEnchantments.getNestableColumn(mEnchantments.getColumns()-1)->addColumn( - new NestedIntegerColumn (Columns::ColumnId_MaxRange)); // reuse from sound + new NestedChildColumn (Columns::ColumnId_MaxRange, ColumnBase::Display_Integer)); // reuse from sound mBodyParts.addColumn (new StringIdColumn); mBodyParts.addColumn (new RecordStateColumn); @@ -339,24 +339,24 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc // new objects deleted in dtor of NestableColumn // WARNING: The order of the columns below are assumed in PathgridPointListAdapter mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn( - new NestedIntegerColumn (Columns::ColumnId_PathgridIndex, false)); + new NestedChildColumn (Columns::ColumnId_PathgridIndex, ColumnBase::Display_Integer, false)); mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn( - new NestedIntegerColumn (Columns::ColumnId_PathgridPosX)); + new NestedChildColumn (Columns::ColumnId_PathgridPosX, ColumnBase::Display_Integer)); mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn( - new NestedIntegerColumn (Columns::ColumnId_PathgridPosY)); + new NestedChildColumn (Columns::ColumnId_PathgridPosY, ColumnBase::Display_Integer)); mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn( - new NestedIntegerColumn (Columns::ColumnId_PathgridPosZ)); + new NestedChildColumn (Columns::ColumnId_PathgridPosZ, ColumnBase::Display_Integer)); NestedParentColumn *edgeList = new NestedParentColumn (Columns::ColumnId_PathgridEdges); mPathgrids.addColumn (edgeList); mPathgrids.addAdapter (std::make_pair(edgeList, new PathgridEdgeListAdapter ())); mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn( - new NestedIntegerColumn (Columns::ColumnId_PathgridEdgeIndex, false)); + new NestedChildColumn (Columns::ColumnId_PathgridEdgeIndex, ColumnBase::Display_Integer, false)); mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn( - new NestedIntegerColumn (Columns::ColumnId_PathgridEdge0)); + new NestedChildColumn (Columns::ColumnId_PathgridEdge0, ColumnBase::Display_Integer)); mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn( - new NestedIntegerColumn (Columns::ColumnId_PathgridEdge1)); + new NestedChildColumn (Columns::ColumnId_PathgridEdge1, ColumnBase::Display_Integer)); mStartScripts.addColumn (new StringIdColumn); mStartScripts.addColumn (new RecordStateColumn); From 41b368a759ca70405ed7f7d4bdf9e6112393699b Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 12 Apr 2015 10:52:01 +1000 Subject: [PATCH 0924/3725] Moved templated code around a bit. --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/world/columnbase.hpp | 3 +- apps/opencs/model/world/data.cpp | 8 +- apps/opencs/model/world/idadapterimp.cpp | 457 +++++++++++++++++++++ apps/opencs/model/world/idadapterimp.hpp | 495 ++++------------------- 5 files changed, 534 insertions(+), 431 deletions(-) create mode 100644 apps/opencs/model/world/idadapterimp.cpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 8cf37da1d..bc0b964ae 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -25,7 +25,7 @@ opencs_units (model/world opencs_units_noqt (model/world universalid record commands columnbase scriptcontext cell refidcollection refidadapter refiddata refidadapterimp ref collectionbase refcollection columns infocollection tablemimedata cellcoordinates cellselection resources resourcesmanager scope - pathgrid landtexture land nestedtablewrapper nestedadapters nestedcollection + pathgrid landtexture land nestedtablewrapper nestedadapters nestedcollection idadapterimp ) opencs_hdrs_noqt (model/world diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index dc3aae11a..c7c8d3cd8 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -169,7 +169,8 @@ namespace CSMWorld template struct NestedParentColumn : public Column { - NestedParentColumn (int id) : Column (id, Display_NestedHeader, Flag_Dialogue) + NestedParentColumn (int id) : Column (id, + ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue) {} virtual QVariant get (const Record& record) const diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 69e2b5aa8..db644affa 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -112,7 +112,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc NestedParentColumn *reactions = new NestedParentColumn (Columns::ColumnId_FactionReactions); mFactions.addColumn (reactions); - mFactions.addAdapter (std::make_pair(reactions, new FactionReactionsAdapter ())); + mFactions.addAdapter (std::make_pair(reactions, new FactionReactionsAdapter ())); mFactions.getNestableColumn(mFactions.getColumns()-1)->addColumn( new NestedChildColumn (Columns::ColumnId_Faction, ColumnBase::Display_String)); mFactions.getNestableColumn(mFactions.getColumns()-1)->addColumn( @@ -160,7 +160,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc NestedParentColumn *soundList = new NestedParentColumn (Columns::ColumnId_RegionSounds); mRegions.addColumn (soundList); - mRegions.addAdapter (std::make_pair(soundList, new RegionSoundListAdapter ())); + mRegions.addAdapter (std::make_pair(soundList, new RegionSoundListAdapter ())); mRegions.getNestableColumn(mRegions.getColumns()-1)->addColumn( new NestedChildColumn (Columns::ColumnId_SoundName, ColumnBase::Display_String)); mRegions.getNestableColumn(mRegions.getColumns()-1)->addColumn( @@ -335,7 +335,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc new NestedParentColumn (Columns::ColumnId_PathgridPoints); mPathgrids.addColumn (pointList); // new object deleted in dtor of SubCellCollection - mPathgrids.addAdapter (std::make_pair(pointList, new PathgridPointListAdapter ())); + mPathgrids.addAdapter (std::make_pair(pointList, new PathgridPointListAdapter ())); // new objects deleted in dtor of NestableColumn // WARNING: The order of the columns below are assumed in PathgridPointListAdapter mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn( @@ -350,7 +350,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc NestedParentColumn *edgeList = new NestedParentColumn (Columns::ColumnId_PathgridEdges); mPathgrids.addColumn (edgeList); - mPathgrids.addAdapter (std::make_pair(edgeList, new PathgridEdgeListAdapter ())); + mPathgrids.addAdapter (std::make_pair(edgeList, new PathgridEdgeListAdapter ())); mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn( new NestedChildColumn (Columns::ColumnId_PathgridEdgeIndex, ColumnBase::Display_Integer, false)); mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn( diff --git a/apps/opencs/model/world/idadapterimp.cpp b/apps/opencs/model/world/idadapterimp.cpp new file mode 100644 index 000000000..95e68e09e --- /dev/null +++ b/apps/opencs/model/world/idadapterimp.cpp @@ -0,0 +1,457 @@ +#include "idadapterimp.hpp" + +#include +#include + +#include "idcollection.hpp" +#include "pathgrid.hpp" + +namespace CSMWorld +{ + PathgridPointListAdapter::PathgridPointListAdapter () {} + + void PathgridPointListAdapter::addNestedRow(Record& record, int position) const + { + Pathgrid pathgrid = record.get(); + + ESM::Pathgrid::PointList& points = pathgrid.mPoints; + + // blank row + ESM::Pathgrid::Point point; + point.mX = 0; + point.mY = 0; + point.mZ = 0; + point.mAutogenerated = 0; + point.mConnectionNum = 0; + point.mUnknown = 0; + + // inserting a point should trigger re-indexing of the edges + // + // FIXME: does not auto refresh edges table view + std::vector::iterator iter = pathgrid.mEdges.begin(); + for (;iter != pathgrid.mEdges.end(); ++iter) + { + if ((*iter).mV0 >= position) + (*iter).mV0++; + if ((*iter).mV1 >= position) + (*iter).mV1++; + } + + points.insert(points.begin()+position, point); + pathgrid.mData.mS2 += 1; // increment the number of points + + record.setModified (pathgrid); + } + + void PathgridPointListAdapter::removeNestedRow(Record& record, int rowToRemove) const + { + Pathgrid pathgrid = record.get(); + + ESM::Pathgrid::PointList& points = pathgrid.mPoints; + + if (rowToRemove < 0 || rowToRemove >= static_cast (points.size())) + throw std::runtime_error ("index out of range"); + + // deleting a point should trigger re-indexing of the edges + // dangling edges are not allowed and hence removed + // + // FIXME: does not auto refresh edges table view + std::vector::iterator iter = pathgrid.mEdges.begin(); + for (; iter != pathgrid.mEdges.end();) + { + if (((*iter).mV0 == rowToRemove) || ((*iter).mV1 == rowToRemove)) + iter = pathgrid.mEdges.erase(iter); + else + { + if ((*iter).mV0 > rowToRemove) + (*iter).mV0--; + + if ((*iter).mV1 > rowToRemove) + (*iter).mV1--; + + ++iter; + } + } + points.erase(points.begin()+rowToRemove); + pathgrid.mData.mS2 -= 1; // decrement the number of points + + record.setModified (pathgrid); + } + + void PathgridPointListAdapter::setNestedTable(Record& record, + const NestedTableWrapperBase& nestedTable) const + { + record.get().mPoints = + static_cast(nestedTable).mRecord.mPoints; + record.get().mData.mS2 = + static_cast(nestedTable).mRecord.mData.mS2; + // also update edges in case points were added/removed + record.get().mEdges = + static_cast(nestedTable).mRecord.mEdges; + } + + NestedTableWrapperBase* PathgridPointListAdapter::nestedTable(const Record& record) const + { + // deleted by dtor of NestedTableStoring + return new PathgridPointsWrap(record.get()); + } + + QVariant PathgridPointListAdapter::getNestedData(const Record& record, + int subRowIndex, int subColIndex) const + { + ESM::Pathgrid::Point point = record.get().mPoints[subRowIndex]; + switch (subColIndex) + { + case 0: return subRowIndex; + case 1: return point.mX; + case 2: return point.mY; + case 3: return point.mZ; + default: throw std::runtime_error("Pathgrid point subcolumn index out of range"); + } + } + + void PathgridPointListAdapter::setNestedData(Record& record, + const QVariant& value, int subRowIndex, int subColIndex) const + { + Pathgrid pathgrid = record.get(); + ESM::Pathgrid::Point point = pathgrid.mPoints[subRowIndex]; + switch (subColIndex) + { + case 0: break; + case 1: point.mX = value.toInt(); break; + case 2: point.mY = value.toInt(); break; + case 3: point.mZ = value.toInt(); break; + default: throw std::runtime_error("Pathgrid point subcolumn index out of range"); + } + + pathgrid.mPoints[subRowIndex] = point; + + record.setModified (pathgrid); + } + + int PathgridPointListAdapter::getNestedColumnsCount(const Record& record) const + { + return 4; + } + + int PathgridPointListAdapter::getNestedRowsCount(const Record& record) const + { + return static_cast(record.get().mPoints.size()); + } + + PathgridEdgeListAdapter::PathgridEdgeListAdapter () {} + + // ToDo: seems to be auto-sorted in the dialog table display after insertion + void PathgridEdgeListAdapter::addNestedRow(Record& record, int position) const + { + Pathgrid pathgrid = record.get(); + + ESM::Pathgrid::EdgeList& edges = pathgrid.mEdges; + + // blank row + ESM::Pathgrid::Edge edge; + edge.mV0 = 0; + edge.mV1 = 0; + + // NOTE: inserting a blank edge does not really make sense, perhaps this should be a + // logic_error exception + // + // Currently the code assumes that the end user to know what he/she is doing. + // e.g. Edges come in pairs, from points a->b and b->a + edges.insert(edges.begin()+position, edge); + + record.setModified (pathgrid); + } + + void PathgridEdgeListAdapter::removeNestedRow(Record& record, int rowToRemove) const + { + Pathgrid pathgrid = record.get(); + + ESM::Pathgrid::EdgeList& edges = pathgrid.mEdges; + + if (rowToRemove < 0 || rowToRemove >= static_cast (edges.size())) + throw std::runtime_error ("index out of range"); + + edges.erase(edges.begin()+rowToRemove); + + record.setModified (pathgrid); + } + + void PathgridEdgeListAdapter::setNestedTable(Record& record, + const NestedTableWrapperBase& nestedTable) const + { + record.get().mEdges = + static_cast &>(nestedTable).mNestedTable; + } + + NestedTableWrapperBase* PathgridEdgeListAdapter::nestedTable(const Record& record) const + { + // deleted by dtor of NestedTableStoring + return new NestedTableWrapper(record.get().mEdges); + } + + QVariant PathgridEdgeListAdapter::getNestedData(const Record& record, + int subRowIndex, int subColIndex) const + { + Pathgrid pathgrid = record.get(); + + if (subRowIndex < 0 || subRowIndex >= static_cast (pathgrid.mEdges.size())) + throw std::runtime_error ("index out of range"); + + ESM::Pathgrid::Edge edge = pathgrid.mEdges[subRowIndex]; + switch (subColIndex) + { + case 0: return subRowIndex; + case 1: return edge.mV0; + case 2: return edge.mV1; + default: throw std::runtime_error("Pathgrid edge subcolumn index out of range"); + } + } + + // ToDo: detect duplicates in mEdges + void PathgridEdgeListAdapter::setNestedData(Record& record, + const QVariant& value, int subRowIndex, int subColIndex) const + { + Pathgrid pathgrid = record.get(); + + if (subRowIndex < 0 || subRowIndex >= static_cast (pathgrid.mEdges.size())) + throw std::runtime_error ("index out of range"); + + ESM::Pathgrid::Edge edge = pathgrid.mEdges[subRowIndex]; + switch (subColIndex) + { + case 0: break; + case 1: edge.mV0 = value.toInt(); break; + case 2: edge.mV1 = value.toInt(); break; + default: throw std::runtime_error("Pathgrid edge subcolumn index out of range"); + } + + pathgrid.mEdges[subRowIndex] = edge; + + record.setModified (pathgrid); + } + + int PathgridEdgeListAdapter::getNestedColumnsCount(const Record& record) const + { + return 3; + } + + int PathgridEdgeListAdapter::getNestedRowsCount(const Record& record) const + { + return static_cast(record.get().mEdges.size()); + } + + FactionReactionsAdapter::FactionReactionsAdapter () {} + + void FactionReactionsAdapter::addNestedRow(Record& record, int position) const + { + ESM::Faction faction = record.get(); + + std::map& reactions = faction.mReactions; + + // blank row + reactions.insert(std::make_pair("", 0)); + + record.setModified (faction); + } + + void FactionReactionsAdapter::removeNestedRow(Record& record, int rowToRemove) const + { + ESM::Faction faction = record.get(); + + std::map& reactions = faction.mReactions; + + if (rowToRemove < 0 || rowToRemove >= static_cast (reactions.size())) + throw std::runtime_error ("index out of range"); + + // FIXME: how to ensure that the map entries correspond to table indicies? + // WARNING: Assumed that the table view has the same order as std::map + std::map::iterator iter = reactions.begin(); + for(int i = 0; i < rowToRemove; ++i) + iter++; + reactions.erase(iter); + + record.setModified (faction); + } + + void FactionReactionsAdapter::setNestedTable(Record& record, + const NestedTableWrapperBase& nestedTable) const + { + record.get().mReactions = + static_cast >&>(nestedTable).mNestedTable; + } + + NestedTableWrapperBase* FactionReactionsAdapter::nestedTable(const Record& record) const + { + // deleted by dtor of NestedTableStoring + return new NestedTableWrapper >(record.get().mReactions); + } + + QVariant FactionReactionsAdapter::getNestedData(const Record& record, + int subRowIndex, int subColIndex) const + { + ESM::Faction faction = record.get(); + + std::map& reactions = faction.mReactions; + + if (subRowIndex < 0 || subRowIndex >= static_cast (reactions.size())) + throw std::runtime_error ("index out of range"); + + // FIXME: how to ensure that the map entries correspond to table indicies? + // WARNING: Assumed that the table view has the same order as std::map + std::map::const_iterator iter = reactions.begin(); + for(int i = 0; i < subRowIndex; ++i) + iter++; + switch (subColIndex) + { + case 0: return QString((*iter).first.c_str()); + case 1: return (*iter).second; + default: throw std::runtime_error("Faction reactions subcolumn index out of range"); + } + } + + void FactionReactionsAdapter::setNestedData(Record& record, + const QVariant& value, int subRowIndex, int subColIndex) const + { + ESM::Faction faction = record.get(); + + std::map& reactions = faction.mReactions; + + if (subRowIndex < 0 || subRowIndex >= static_cast (reactions.size())) + throw std::runtime_error ("index out of range"); + + // FIXME: how to ensure that the map entries correspond to table indicies? + // WARNING: Assumed that the table view has the same order as std::map + std::map::iterator iter = reactions.begin(); + for(int i = 0; i < subRowIndex; ++i) + iter++; + + std::string factionId = (*iter).first; + int reaction = (*iter).second; + + switch (subColIndex) + { + case 0: + { + reactions.erase(iter); + reactions.insert(std::make_pair(value.toString().toUtf8().constData(), reaction)); + break; + } + case 1: + { + reactions[factionId] = value.toInt(); + break; + } + default: throw std::runtime_error("Faction reactions subcolumn index out of range"); + } + + record.setModified (faction); + } + + int FactionReactionsAdapter::getNestedColumnsCount(const Record& record) const + { + return 2; + } + + int FactionReactionsAdapter::getNestedRowsCount(const Record& record) const + { + return static_cast(record.get().mReactions.size()); + } + + RegionSoundListAdapter::RegionSoundListAdapter () {} + + void RegionSoundListAdapter::addNestedRow(Record& record, int position) const + { + ESM::Region region = record.get(); + + std::vector& soundList = region.mSoundList; + + // blank row + ESM::Region::SoundRef soundRef; + soundRef.mSound.assign(""); + soundRef.mChance = 0; + + soundList.insert(soundList.begin()+position, soundRef); + + record.setModified (region); + } + + void RegionSoundListAdapter::removeNestedRow(Record& record, int rowToRemove) const + { + ESM::Region region = record.get(); + + std::vector& soundList = region.mSoundList; + + if (rowToRemove < 0 || rowToRemove >= static_cast (soundList.size())) + throw std::runtime_error ("index out of range"); + + soundList.erase(soundList.begin()+rowToRemove); + + record.setModified (region); + } + + void RegionSoundListAdapter::setNestedTable(Record& record, + const NestedTableWrapperBase& nestedTable) const + { + record.get().mSoundList = + static_cast >&>(nestedTable).mNestedTable; + } + + NestedTableWrapperBase* RegionSoundListAdapter::nestedTable(const Record& record) const + { + // deleted by dtor of NestedTableStoring + return new NestedTableWrapper >(record.get().mSoundList); + } + + QVariant RegionSoundListAdapter::getNestedData(const Record& record, + int subRowIndex, int subColIndex) const + { + ESM::Region region = record.get(); + + std::vector& soundList = region.mSoundList; + + if (subRowIndex < 0 || subRowIndex >= static_cast (soundList.size())) + throw std::runtime_error ("index out of range"); + + ESM::Region::SoundRef soundRef = soundList[subRowIndex]; + switch (subColIndex) + { + case 0: return QString(soundRef.mSound.toString().c_str()); + case 1: return soundRef.mChance; + default: throw std::runtime_error("Region sounds subcolumn index out of range"); + } + } + + void RegionSoundListAdapter::setNestedData(Record& record, + const QVariant& value, int subRowIndex, int subColIndex) const + { + ESM::Region region = record.get(); + + std::vector& soundList = region.mSoundList; + + if (subRowIndex < 0 || subRowIndex >= static_cast (soundList.size())) + throw std::runtime_error ("index out of range"); + + ESM::Region::SoundRef soundRef = soundList[subRowIndex]; + switch (subColIndex) + { + case 0: soundRef.mSound.assign(value.toString().toUtf8().constData()); break; + case 1: soundRef.mChance = static_cast(value.toInt()); break; + default: throw std::runtime_error("Region sounds subcolumn index out of range"); + } + + region.mSoundList[subRowIndex] = soundRef; + + record.setModified (region); + } + + int RegionSoundListAdapter::getNestedColumnsCount(const Record& record) const + { + return 2; + } + + int RegionSoundListAdapter::getNestedRowsCount(const Record& record) const + { + return static_cast(record.get().mSoundList.size()); + } +} diff --git a/apps/opencs/model/world/idadapterimp.hpp b/apps/opencs/model/world/idadapterimp.hpp index d5bf83a2d..effa0011c 100644 --- a/apps/opencs/model/world/idadapterimp.hpp +++ b/apps/opencs/model/world/idadapterimp.hpp @@ -4,8 +4,6 @@ #include #include -#include -#include #include #include // for converting magic effect id to string & back #include // for converting skill names @@ -14,482 +12,129 @@ #include "idadapter.hpp" #include "nestedtablewrapper.hpp" -namespace CSMWorld +namespace ESM { - template - class PathgridPointListAdapter : public NestedIdAdapter - { - public: - PathgridPointListAdapter () {} - - virtual void addNestedRow(Record& record, int position) const - { - ESXRecordT pathgrid = record.get(); - - ESM::Pathgrid::PointList& points = pathgrid.mPoints; - - // blank row - ESM::Pathgrid::Point point; - point.mX = 0; - point.mY = 0; - point.mZ = 0; - point.mAutogenerated = 0; - point.mConnectionNum = 0; - point.mUnknown = 0; - - // inserting a point should trigger re-indexing of the edges - // - // FIXME: undo does not restore edges table view - // FIXME: does not auto refresh edges table view - std::vector::iterator iter = pathgrid.mEdges.begin(); - for (;iter != pathgrid.mEdges.end(); ++iter) - { - if ((*iter).mV0 >= position) - (*iter).mV0++; - if ((*iter).mV1 >= position) - (*iter).mV1++; - } - - points.insert(points.begin()+position, point); - pathgrid.mData.mS2 += 1; // increment the number of points - - record.setModified (pathgrid); - } - - virtual void removeNestedRow(Record& record, int rowToRemove) const - { - ESXRecordT pathgrid = record.get(); - - ESM::Pathgrid::PointList& points = pathgrid.mPoints; - - if (rowToRemove < 0 || rowToRemove >= static_cast (points.size())) - throw std::runtime_error ("index out of range"); - - // deleting a point should trigger re-indexing of the edges - // dangling edges are not allowed and hence removed - // - // FIXME: undo does not restore edges table view - // FIXME: does not auto refresh edges table view - std::vector::iterator iter = pathgrid.mEdges.begin(); - for (; iter != pathgrid.mEdges.end();) - { - if (((*iter).mV0 == rowToRemove) || ((*iter).mV1 == rowToRemove)) - iter = pathgrid.mEdges.erase(iter); - else - { - if ((*iter).mV0 > rowToRemove) - (*iter).mV0--; - - if ((*iter).mV1 > rowToRemove) - (*iter).mV1--; - - ++iter; - } - } - points.erase(points.begin()+rowToRemove); - pathgrid.mData.mS2 -= 1; // decrement the number of points - - record.setModified (pathgrid); - } - - struct PathgridPointsWrap : public NestedTableWrapperBase - { - ESM::Pathgrid mRecord; - - PathgridPointsWrap(ESM::Pathgrid pathgrid) - : mRecord(pathgrid) {} - - virtual ~PathgridPointsWrap() {} - - virtual int size() const - { - return mRecord.mPoints.size(); // used in IdTree::setNestedTable() - } - }; - - virtual void setNestedTable(Record& record, const NestedTableWrapperBase& nestedTable) const - { - record.get().mPoints = - static_cast(nestedTable).mRecord.mPoints; - record.get().mData.mS2 = - static_cast(nestedTable).mRecord.mData.mS2; - // also update edges in case points were added/removed - record.get().mEdges = - static_cast(nestedTable).mRecord.mEdges; - } - - virtual NestedTableWrapperBase* nestedTable(const Record& record) const - { - // deleted by dtor of NestedTableStoring - return new PathgridPointsWrap(record.get()); - } - - virtual QVariant getNestedData(const Record& record, int subRowIndex, int subColIndex) const - { - ESM::Pathgrid::Point point = record.get().mPoints[subRowIndex]; - switch (subColIndex) - { - case 0: return subRowIndex; - case 1: return point.mX; - case 2: return point.mY; - case 3: return point.mZ; - default: throw std::runtime_error("Pathgrid point subcolumn index out of range"); - } - } + struct Faction; + struct Region; +} - virtual void setNestedData(Record& record, const QVariant& value, - int subRowIndex, int subColIndex) const - { - ESXRecordT pathgrid = record.get(); - ESM::Pathgrid::Point point = pathgrid.mPoints[subRowIndex]; - switch (subColIndex) - { - case 0: break; - case 1: point.mX = value.toInt(); break; - case 2: point.mY = value.toInt(); break; - case 3: point.mZ = value.toInt(); break; - default: throw std::runtime_error("Pathgrid point subcolumn index out of range"); - } +namespace CSMWorld +{ + struct Pathgrid; - pathgrid.mPoints[subRowIndex] = point; + struct PathgridPointsWrap : public NestedTableWrapperBase + { + ESM::Pathgrid mRecord; - record.setModified (pathgrid); - } + PathgridPointsWrap(ESM::Pathgrid pathgrid) + : mRecord(pathgrid) {} - virtual int getNestedColumnsCount(const Record& record) const - { - return 4; - } + virtual ~PathgridPointsWrap() {} - virtual int getNestedRowsCount(const Record& record) const + virtual int size() const { - return static_cast(record.get().mPoints.size()); + return mRecord.mPoints.size(); // used in IdTree::setNestedTable() } }; - template - class PathgridEdgeListAdapter : public NestedIdAdapter + class PathgridPointListAdapter : public NestedIdAdapter { public: - PathgridEdgeListAdapter () {} - - // FIXME: seems to be auto-sorted in the dialog table display after insertion - virtual void addNestedRow(Record& record, int position) const - { - ESXRecordT pathgrid = record.get(); - - ESM::Pathgrid::EdgeList& edges = pathgrid.mEdges; - - // blank row - ESM::Pathgrid::Edge edge; - edge.mV0 = 0; - edge.mV1 = 0; - - // NOTE: inserting a blank edge does not really make sense, perhaps this should be a - // logic_error exception - // - // Currently the code assumes that the end user to know what he/she is doing. - // e.g. Edges come in pairs, from points a->b and b->a - edges.insert(edges.begin()+position, edge); - - record.setModified (pathgrid); - } - - virtual void removeNestedRow(Record& record, int rowToRemove) const - { - ESXRecordT pathgrid = record.get(); - - ESM::Pathgrid::EdgeList& edges = pathgrid.mEdges; - - if (rowToRemove < 0 || rowToRemove >= static_cast (edges.size())) - throw std::runtime_error ("index out of range"); - - edges.erase(edges.begin()+rowToRemove); - - record.setModified (pathgrid); - } + PathgridPointListAdapter (); - virtual void setNestedTable(Record& record, const NestedTableWrapperBase& nestedTable) const - { - record.get().mEdges = - static_cast &>(nestedTable).mNestedTable; - } - - virtual NestedTableWrapperBase* nestedTable(const Record& record) const - { - // deleted by dtor of NestedTableStoring - return new NestedTableWrapper(record.get().mEdges); - } - - virtual QVariant getNestedData(const Record& record, int subRowIndex, int subColIndex) const - { - ESXRecordT pathgrid = record.get(); + virtual void addNestedRow(Record& record, int position) const; - if (subRowIndex < 0 || subRowIndex >= static_cast (pathgrid.mEdges.size())) - throw std::runtime_error ("index out of range"); - - ESM::Pathgrid::Edge edge = pathgrid.mEdges[subRowIndex]; - switch (subColIndex) - { - case 0: return subRowIndex; - case 1: return edge.mV0; - case 2: return edge.mV1; - default: throw std::runtime_error("Pathgrid edge subcolumn index out of range"); - } - } + virtual void removeNestedRow(Record& record, int rowToRemove) const; - // FIXME: detect duplicates in mEdges - virtual void setNestedData(Record& record, const QVariant& value, - int subRowIndex, int subColIndex) const - { - ESXRecordT pathgrid = record.get(); + virtual void setNestedTable(Record& record, + const NestedTableWrapperBase& nestedTable) const; - if (subRowIndex < 0 || subRowIndex >= static_cast (pathgrid.mEdges.size())) - throw std::runtime_error ("index out of range"); + virtual NestedTableWrapperBase* nestedTable(const Record& record) const; - ESM::Pathgrid::Edge edge = pathgrid.mEdges[subRowIndex]; - switch (subColIndex) - { - case 0: break; - case 1: edge.mV0 = value.toInt(); break; - case 2: edge.mV1 = value.toInt(); break; - default: throw std::runtime_error("Pathgrid edge subcolumn index out of range"); - } + virtual QVariant getNestedData(const Record& record, + int subRowIndex, int subColIndex) const; - pathgrid.mEdges[subRowIndex] = edge; + virtual void setNestedData(Record& record, + const QVariant& value, int subRowIndex, int subColIndex) const; - record.setModified (pathgrid); - } + virtual int getNestedColumnsCount(const Record& record) const; - virtual int getNestedColumnsCount(const Record& record) const - { - return 3; - } - - virtual int getNestedRowsCount(const Record& record) const - { - return static_cast(record.get().mEdges.size()); - } + virtual int getNestedRowsCount(const Record& record) const; }; - template - class FactionReactionsAdapter : public NestedIdAdapter + class PathgridEdgeListAdapter : public NestedIdAdapter { public: - FactionReactionsAdapter () {} - - virtual void addNestedRow(Record& record, int position) const - { - ESXRecordT faction = record.get(); - - std::map& reactions = faction.mReactions; - - // blank row - reactions.insert(std::make_pair("", 0)); - - record.setModified (faction); - } - - virtual void removeNestedRow(Record& record, int rowToRemove) const - { - ESXRecordT faction = record.get(); - - std::map& reactions = faction.mReactions; - - if (rowToRemove < 0 || rowToRemove >= static_cast (reactions.size())) - throw std::runtime_error ("index out of range"); - - // FIXME: how to ensure that the map entries correspond to table indicies? - // WARNING: Assumed that the table view has the same order as std::map - std::map::iterator iter = reactions.begin(); - for(int i = 0; i < rowToRemove; ++i) - iter++; - reactions.erase(iter); - - record.setModified (faction); - } - - virtual void setNestedTable(Record& record, const NestedTableWrapperBase& nestedTable) const - { - record.get().mReactions = - static_cast >&>(nestedTable).mNestedTable; - } - - virtual NestedTableWrapperBase* nestedTable(const Record& record) const - { - // deleted by dtor of NestedTableStoring - return new NestedTableWrapper >(record.get().mReactions); - } - - virtual QVariant getNestedData(const Record& record, int subRowIndex, int subColIndex) const - { - ESXRecordT faction = record.get(); - - std::map& reactions = faction.mReactions; - - if (subRowIndex < 0 || subRowIndex >= static_cast (reactions.size())) - throw std::runtime_error ("index out of range"); - - // FIXME: how to ensure that the map entries correspond to table indicies? - // WARNING: Assumed that the table view has the same order as std::map - std::map::const_iterator iter = reactions.begin(); - for(int i = 0; i < subRowIndex; ++i) - iter++; - switch (subColIndex) - { - case 0: return QString((*iter).first.c_str()); - case 1: return (*iter).second; - default: throw std::runtime_error("Faction reactions subcolumn index out of range"); - } - } + PathgridEdgeListAdapter (); - virtual void setNestedData(Record& record, const QVariant& value, - int subRowIndex, int subColIndex) const - { - ESXRecordT faction = record.get(); + virtual void addNestedRow(Record& record, int position) const; - std::map& reactions = faction.mReactions; + virtual void removeNestedRow(Record& record, int rowToRemove) const; - if (subRowIndex < 0 || subRowIndex >= static_cast (reactions.size())) - throw std::runtime_error ("index out of range"); + virtual void setNestedTable(Record& record, + const NestedTableWrapperBase& nestedTable) const; - // FIXME: how to ensure that the map entries correspond to table indicies? - // WARNING: Assumed that the table view has the same order as std::map - std::map::iterator iter = reactions.begin(); - for(int i = 0; i < subRowIndex; ++i) - iter++; + virtual NestedTableWrapperBase* nestedTable(const Record& record) const; - std::string factionId = (*iter).first; - int reaction = (*iter).second; - - switch (subColIndex) - { - case 0: - { - reactions.erase(iter); - reactions.insert(std::make_pair(value.toString().toUtf8().constData(), reaction)); - break; - } - case 1: - { - reactions[factionId] = value.toInt(); - break; - } - default: throw std::runtime_error("Faction reactions subcolumn index out of range"); - } + virtual QVariant getNestedData(const Record& record, + int subRowIndex, int subColIndex) const; - record.setModified (faction); - } + virtual void setNestedData(Record& record, + const QVariant& value, int subRowIndex, int subColIndex) const; - virtual int getNestedColumnsCount(const Record& record) const - { - return 2; - } + virtual int getNestedColumnsCount(const Record& record) const; - virtual int getNestedRowsCount(const Record& record) const - { - return static_cast(record.get().mReactions.size()); - } + virtual int getNestedRowsCount(const Record& record) const; }; - template - class RegionSoundListAdapter : public NestedIdAdapter + class FactionReactionsAdapter : public NestedIdAdapter { public: - RegionSoundListAdapter () {} - - virtual void addNestedRow(Record& record, int position) const - { - ESXRecordT region = record.get(); - - std::vector& soundList = region.mSoundList; + FactionReactionsAdapter (); - // blank row - typename ESXRecordT::SoundRef soundRef; - soundRef.mSound.assign(""); - soundRef.mChance = 0; - - soundList.insert(soundList.begin()+position, soundRef); - - record.setModified (region); - } - - virtual void removeNestedRow(Record& record, int rowToRemove) const - { - ESXRecordT region = record.get(); + virtual void addNestedRow(Record& record, int position) const; - std::vector& soundList = region.mSoundList; + virtual void removeNestedRow(Record& record, int rowToRemove) const; - if (rowToRemove < 0 || rowToRemove >= static_cast (soundList.size())) - throw std::runtime_error ("index out of range"); - - soundList.erase(soundList.begin()+rowToRemove); - - record.setModified (region); - } + virtual void setNestedTable(Record& record, + const NestedTableWrapperBase& nestedTable) const; - virtual void setNestedTable(Record& record, const NestedTableWrapperBase& nestedTable) const - { - record.get().mSoundList = - static_cast >&>(nestedTable).mNestedTable; - } + virtual NestedTableWrapperBase* nestedTable(const Record& record) const; - virtual NestedTableWrapperBase* nestedTable(const Record& record) const - { - // deleted by dtor of NestedTableStoring - return new NestedTableWrapper >(record.get().mSoundList); - } + virtual QVariant getNestedData(const Record& record, + int subRowIndex, int subColIndex) const; - virtual QVariant getNestedData(const Record& record, int subRowIndex, int subColIndex) const - { - ESXRecordT region = record.get(); + virtual void setNestedData(Record& record, + const QVariant& value, int subRowIndex, int subColIndex) const; - std::vector& soundList = region.mSoundList; + virtual int getNestedColumnsCount(const Record& record) const; - if (subRowIndex < 0 || subRowIndex >= static_cast (soundList.size())) - throw std::runtime_error ("index out of range"); + virtual int getNestedRowsCount(const Record& record) const; + }; - typename ESXRecordT::SoundRef soundRef = soundList[subRowIndex]; - switch (subColIndex) - { - case 0: return QString(soundRef.mSound.toString().c_str()); - case 1: return soundRef.mChance; - default: throw std::runtime_error("Region sounds subcolumn index out of range"); - } - } + class RegionSoundListAdapter : public NestedIdAdapter + { + public: + RegionSoundListAdapter (); - virtual void setNestedData(Record& record, const QVariant& value, - int subRowIndex, int subColIndex) const - { - ESXRecordT region = record.get(); + virtual void addNestedRow(Record& record, int position) const; - std::vector& soundList = region.mSoundList; + virtual void removeNestedRow(Record& record, int rowToRemove) const; - if (subRowIndex < 0 || subRowIndex >= static_cast (soundList.size())) - throw std::runtime_error ("index out of range"); + virtual void setNestedTable(Record& record, + const NestedTableWrapperBase& nestedTable) const; - typename ESXRecordT::SoundRef soundRef = soundList[subRowIndex]; - switch (subColIndex) - { - case 0: soundRef.mSound.assign(value.toString().toUtf8().constData()); break; - case 1: soundRef.mChance = static_cast(value.toInt()); break; - default: throw std::runtime_error("Region sounds subcolumn index out of range"); - } + virtual NestedTableWrapperBase* nestedTable(const Record& record) const; - region.mSoundList[subRowIndex] = soundRef; + virtual QVariant getNestedData(const Record& record, + int subRowIndex, int subColIndex) const; - record.setModified (region); - } + virtual void setNestedData(Record& record, + const QVariant& value, int subRowIndex, int subColIndex) const; - virtual int getNestedColumnsCount(const Record& record) const - { - return 2; - } + virtual int getNestedColumnsCount(const Record& record) const; - virtual int getNestedRowsCount(const Record& record) const - { - return static_cast(record.get().mSoundList.size()); - } + virtual int getNestedRowsCount(const Record& record) const; }; template From ef84e553beb94cd6ee56ff270dca6a182cc34331 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 12 Apr 2015 13:48:23 +1000 Subject: [PATCH 0925/3725] Renamed some stuff. --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/world/data.cpp | 166 +++++++++--------- ...adapterimp.cpp => nestedcoladapterimp.cpp} | 2 +- ...adapterimp.hpp => nestedcoladapterimp.hpp} | 20 +-- ...{idadapter.hpp => nestedcolumnadapter.hpp} | 17 +- .../opencs/model/world/nestedidcollection.hpp | 21 ++- 6 files changed, 114 insertions(+), 114 deletions(-) rename apps/opencs/model/world/{idadapterimp.cpp => nestedcoladapterimp.cpp} (99%) rename apps/opencs/model/world/{idadapterimp.hpp => nestedcoladapterimp.hpp} (96%) rename apps/opencs/model/world/{idadapter.hpp => nestedcolumnadapter.hpp} (77%) diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index bc0b964ae..babd3363f 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -25,7 +25,7 @@ opencs_units (model/world opencs_units_noqt (model/world universalid record commands columnbase scriptcontext cell refidcollection refidadapter refiddata refidadapterimp ref collectionbase refcollection columns infocollection tablemimedata cellcoordinates cellselection resources resourcesmanager scope - pathgrid landtexture land nestedtablewrapper nestedadapters nestedcollection idadapterimp + pathgrid landtexture land nestedtablewrapper nestedadapters nestedcollection nestedcoladapterimp ) opencs_hdrs_noqt (model/world diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index db644affa..d7280e354 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -18,7 +18,7 @@ #include "columns.hpp" #include "resourcesmanager.hpp" #include "resourcetable.hpp" -#include "idadapterimp.hpp" +#include "nestedcoladapterimp.hpp" void CSMWorld::Data::addModel (QAbstractItemModel *model, UniversalId::Type type, bool update) { @@ -64,6 +64,8 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc : mEncoder (encoding), mPathgrids (mCells), mRefs (mCells), mResourcesManager (resourcesManager), mReader (0), mDialogue (0), mReaderIndex(0) { + int index = 0; + mGlobals.addColumn (new StringIdColumn); mGlobals.addColumn (new RecordStateColumn); mGlobals.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Global)); @@ -109,14 +111,13 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc for (int i=0; i<7; ++i) mFactions.addColumn (new SkillsColumn (i)); // Faction Reactions - NestedParentColumn *reactions = - new NestedParentColumn (Columns::ColumnId_FactionReactions); - mFactions.addColumn (reactions); - mFactions.addAdapter (std::make_pair(reactions, new FactionReactionsAdapter ())); - mFactions.getNestableColumn(mFactions.getColumns()-1)->addColumn( - new NestedChildColumn (Columns::ColumnId_Faction, ColumnBase::Display_String)); - mFactions.getNestableColumn(mFactions.getColumns()-1)->addColumn( - new NestedChildColumn (Columns::ColumnId_FactionReaction, ColumnBase::Display_Integer)); + mFactions.addColumn (new NestedParentColumn (Columns::ColumnId_FactionReactions)); + index = mFactions.getColumns()-1; + mFactions.addAdapter (std::make_pair(&mFactions.getColumn(index), new FactionReactionsAdapter ())); + mFactions.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_Faction, ColumnBase::Display_String)); + mFactions.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_FactionReaction, ColumnBase::Display_Integer)); mRaces.addColumn (new StringIdColumn); mRaces.addColumn (new RecordStateColumn); @@ -130,12 +131,11 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mRaces.addColumn (new WeightHeightColumn (false, true)); mRaces.addColumn (new WeightHeightColumn (false, false)); // Race spells - NestedParentColumn *raceSpells = - new NestedParentColumn (Columns::ColumnId_SpellList); - mRaces.addColumn (raceSpells); - mRaces.addAdapter (std::make_pair(raceSpells, new SpellListAdapter ())); - mRaces.getNestableColumn(mRaces.getColumns()-1)->addColumn( - new NestedChildColumn (Columns::ColumnId_SpellId, ColumnBase::Display_String)); + mRaces.addColumn (new NestedParentColumn (Columns::ColumnId_SpellList)); + index = mRaces.getColumns()-1; + mRaces.addAdapter (std::make_pair(&mRaces.getColumn(index), new SpellListAdapter ())); + mRaces.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_SpellId, ColumnBase::Display_String)); mSounds.addColumn (new StringIdColumn); mSounds.addColumn (new RecordStateColumn); @@ -157,14 +157,13 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mRegions.addColumn (new MapColourColumn); mRegions.addColumn (new SleepListColumn); // Region Sounds - NestedParentColumn *soundList = - new NestedParentColumn (Columns::ColumnId_RegionSounds); - mRegions.addColumn (soundList); - mRegions.addAdapter (std::make_pair(soundList, new RegionSoundListAdapter ())); - mRegions.getNestableColumn(mRegions.getColumns()-1)->addColumn( - new NestedChildColumn (Columns::ColumnId_SoundName, ColumnBase::Display_String)); - mRegions.getNestableColumn(mRegions.getColumns()-1)->addColumn( - new NestedChildColumn (Columns::ColumnId_SoundChance, ColumnBase::Display_Integer)); + mRegions.addColumn (new NestedParentColumn (Columns::ColumnId_RegionSounds)); + index = mRegions.getColumns()-1; + mRegions.addAdapter (std::make_pair(&mRegions.getColumn(index), new RegionSoundListAdapter ())); + mRegions.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_SoundName, ColumnBase::Display_String)); + mRegions.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_SoundChance, ColumnBase::Display_Integer)); mBirthsigns.addColumn (new StringIdColumn); mBirthsigns.addColumn (new RecordStateColumn); @@ -173,12 +172,12 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mBirthsigns.addColumn (new TextureColumn); mBirthsigns.addColumn (new DescriptionColumn); // Birthsign spells - NestedParentColumn *birthSpells = - new NestedParentColumn (Columns::ColumnId_SpellList); - mBirthsigns.addColumn (birthSpells); - mBirthsigns.addAdapter (std::make_pair(birthSpells, new SpellListAdapter ())); - mBirthsigns.getNestableColumn(mBirthsigns.getColumns()-1)->addColumn( - new NestedChildColumn (Columns::ColumnId_SpellId, ColumnBase::Display_String)); + mBirthsigns.addColumn (new NestedParentColumn (Columns::ColumnId_SpellList)); + index = mBirthsigns.getColumns()-1; + mBirthsigns.addAdapter (std::make_pair(&mBirthsigns.getColumn(index), + new SpellListAdapter ())); + mBirthsigns.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_SpellId, ColumnBase::Display_String)); mSpells.addColumn (new StringIdColumn); mSpells.addColumn (new RecordStateColumn); @@ -190,26 +189,25 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mSpells.addColumn (new FlagColumn (Columns::ColumnId_StarterSpell, 0x2)); mSpells.addColumn (new FlagColumn (Columns::ColumnId_AlwaysSucceeds, 0x4)); // Spell effects - NestedParentColumn *spellEffect = - new NestedParentColumn (Columns::ColumnId_EffectList); - mSpells.addColumn (spellEffect); - mSpells.addAdapter (std::make_pair(spellEffect, new EffectsListAdapter ())); - mSpells.getNestableColumn(mSpells.getColumns()-1)->addColumn( - new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_String/*, false*/)); // false means no edit - mSpells.getNestableColumn(mSpells.getColumns()-1)->addColumn( - new NestedChildColumn (Columns::ColumnId_Skill, ColumnBase::Display_String)); - mSpells.getNestableColumn(mSpells.getColumns()-1)->addColumn( - new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_String)); // reuse attribute - mSpells.getNestableColumn(mSpells.getColumns()-1)->addColumn( - new NestedChildColumn (Columns::ColumnId_EffectRange, ColumnBase::Display_Integer)); - mSpells.getNestableColumn(mSpells.getColumns()-1)->addColumn( - new NestedChildColumn (Columns::ColumnId_EffectArea, ColumnBase::Display_String)); - mSpells.getNestableColumn(mSpells.getColumns()-1)->addColumn( - new NestedChildColumn (Columns::ColumnId_Duration, ColumnBase::Display_Integer)); // reuse from light - mSpells.getNestableColumn(mSpells.getColumns()-1)->addColumn( - new NestedChildColumn (Columns::ColumnId_MinRange, ColumnBase::Display_Integer)); // reuse from sound - mSpells.getNestableColumn(mSpells.getColumns()-1)->addColumn( - new NestedChildColumn (Columns::ColumnId_MaxRange, ColumnBase::Display_Integer)); // reuse from sound + mSpells.addColumn (new NestedParentColumn (Columns::ColumnId_EffectList)); + index = mSpells.getColumns()-1; + mSpells.addAdapter (std::make_pair(&mSpells.getColumn(index), new EffectsListAdapter ())); + mSpells.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_String/*, false*/)); // false means no edit + mSpells.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_Skill, ColumnBase::Display_String)); + mSpells.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_String)); // reuse attribute + mSpells.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_EffectRange, ColumnBase::Display_Integer)); + mSpells.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_EffectArea, ColumnBase::Display_String)); + mSpells.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_Duration, ColumnBase::Display_Integer)); // reuse from light + mSpells.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_MinRange, ColumnBase::Display_Integer)); // reuse from sound + mSpells.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_MaxRange, ColumnBase::Display_Integer)); // reuse from sound mTopics.addColumn (new StringIdColumn); mTopics.addColumn (new RecordStateColumn); @@ -264,26 +262,26 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mEnchantments.addColumn (new ChargesColumn2); mEnchantments.addColumn (new AutoCalcColumn); // Enchantment effects - NestedParentColumn *enchantmentEffect = - new NestedParentColumn (Columns::ColumnId_EffectList); - mEnchantments.addColumn (enchantmentEffect); - mEnchantments.addAdapter (std::make_pair(enchantmentEffect, new EffectsListAdapter ())); - mEnchantments.getNestableColumn(mEnchantments.getColumns()-1)->addColumn( - new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_String/*, false*/)); - mEnchantments.getNestableColumn(mEnchantments.getColumns()-1)->addColumn( - new NestedChildColumn (Columns::ColumnId_Skill, ColumnBase::Display_String)); - mEnchantments.getNestableColumn(mEnchantments.getColumns()-1)->addColumn( - new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_String)); // reuse attribute - mEnchantments.getNestableColumn(mEnchantments.getColumns()-1)->addColumn( - new NestedChildColumn (Columns::ColumnId_EffectRange, ColumnBase::Display_Integer)); - mEnchantments.getNestableColumn(mEnchantments.getColumns()-1)->addColumn( - new NestedChildColumn (Columns::ColumnId_EffectArea, ColumnBase::Display_String)); - mEnchantments.getNestableColumn(mEnchantments.getColumns()-1)->addColumn( - new NestedChildColumn (Columns::ColumnId_Duration, ColumnBase::Display_Integer)); // reuse from light - mEnchantments.getNestableColumn(mEnchantments.getColumns()-1)->addColumn( - new NestedChildColumn (Columns::ColumnId_MinRange, ColumnBase::Display_Integer)); // reuse from sound - mEnchantments.getNestableColumn(mEnchantments.getColumns()-1)->addColumn( - new NestedChildColumn (Columns::ColumnId_MaxRange, ColumnBase::Display_Integer)); // reuse from sound + mEnchantments.addColumn (new NestedParentColumn (Columns::ColumnId_EffectList)); + index = mEnchantments.getColumns()-1; + mEnchantments.addAdapter (std::make_pair(&mEnchantments.getColumn(index), + new EffectsListAdapter ())); + mEnchantments.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_String/*, false*/)); + mEnchantments.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_Skill, ColumnBase::Display_String)); + mEnchantments.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_String)); // reuse attribute + mEnchantments.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_EffectRange, ColumnBase::Display_Integer)); + mEnchantments.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_EffectArea, ColumnBase::Display_String)); + mEnchantments.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_Duration, ColumnBase::Display_Integer)); // reuse from light + mEnchantments.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_MinRange, ColumnBase::Display_Integer)); // reuse from sound + mEnchantments.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_MaxRange, ColumnBase::Display_Integer)); // reuse from sound mBodyParts.addColumn (new StringIdColumn); mBodyParts.addColumn (new RecordStateColumn); @@ -331,31 +329,29 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mPathgrids.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Pathgrid)); // new object deleted in dtor of Collection - NestedParentColumn *pointList = - new NestedParentColumn (Columns::ColumnId_PathgridPoints); - mPathgrids.addColumn (pointList); - // new object deleted in dtor of SubCellCollection - mPathgrids.addAdapter (std::make_pair(pointList, new PathgridPointListAdapter ())); + mPathgrids.addColumn (new NestedParentColumn (Columns::ColumnId_PathgridPoints)); + index = mPathgrids.getColumns()-1; + // new object deleted in dtor of NestedCollection + mPathgrids.addAdapter (std::make_pair(&mPathgrids.getColumn(index), new PathgridPointListAdapter ())); // new objects deleted in dtor of NestableColumn // WARNING: The order of the columns below are assumed in PathgridPointListAdapter - mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn( + mPathgrids.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_PathgridIndex, ColumnBase::Display_Integer, false)); - mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn( + mPathgrids.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_PathgridPosX, ColumnBase::Display_Integer)); - mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn( + mPathgrids.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_PathgridPosY, ColumnBase::Display_Integer)); - mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn( + mPathgrids.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_PathgridPosZ, ColumnBase::Display_Integer)); - NestedParentColumn *edgeList = - new NestedParentColumn (Columns::ColumnId_PathgridEdges); - mPathgrids.addColumn (edgeList); - mPathgrids.addAdapter (std::make_pair(edgeList, new PathgridEdgeListAdapter ())); - mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn( + mPathgrids.addColumn (new NestedParentColumn (Columns::ColumnId_PathgridEdges)); + index = mPathgrids.getColumns()-1; + mPathgrids.addAdapter (std::make_pair(&mPathgrids.getColumn(index), new PathgridEdgeListAdapter ())); + mPathgrids.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_PathgridEdgeIndex, ColumnBase::Display_Integer, false)); - mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn( + mPathgrids.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_PathgridEdge0, ColumnBase::Display_Integer)); - mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn( + mPathgrids.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_PathgridEdge1, ColumnBase::Display_Integer)); mStartScripts.addColumn (new StringIdColumn); diff --git a/apps/opencs/model/world/idadapterimp.cpp b/apps/opencs/model/world/nestedcoladapterimp.cpp similarity index 99% rename from apps/opencs/model/world/idadapterimp.cpp rename to apps/opencs/model/world/nestedcoladapterimp.cpp index 95e68e09e..2bf1ffadd 100644 --- a/apps/opencs/model/world/idadapterimp.cpp +++ b/apps/opencs/model/world/nestedcoladapterimp.cpp @@ -1,4 +1,4 @@ -#include "idadapterimp.hpp" +#include "nestedcoladapterimp.hpp" #include #include diff --git a/apps/opencs/model/world/idadapterimp.hpp b/apps/opencs/model/world/nestedcoladapterimp.hpp similarity index 96% rename from apps/opencs/model/world/idadapterimp.hpp rename to apps/opencs/model/world/nestedcoladapterimp.hpp index effa0011c..7fed74868 100644 --- a/apps/opencs/model/world/idadapterimp.hpp +++ b/apps/opencs/model/world/nestedcoladapterimp.hpp @@ -1,5 +1,5 @@ -#ifndef CSM_WOLRD_IDADAPTERIMP_H -#define CSM_WOLRD_IDADAPTERIMP_H +#ifndef CSM_WOLRD_NESTEDCOLADAPTERIMP_H +#define CSM_WOLRD_NESTEDCOLADAPTERIMP_H #include @@ -9,7 +9,7 @@ #include // for converting skill names #include // for converting attributes -#include "idadapter.hpp" +#include "nestedcolumnadapter.hpp" #include "nestedtablewrapper.hpp" namespace ESM @@ -37,7 +37,7 @@ namespace CSMWorld } }; - class PathgridPointListAdapter : public NestedIdAdapter + class PathgridPointListAdapter : public NestedColumnAdapter { public: PathgridPointListAdapter (); @@ -62,7 +62,7 @@ namespace CSMWorld virtual int getNestedRowsCount(const Record& record) const; }; - class PathgridEdgeListAdapter : public NestedIdAdapter + class PathgridEdgeListAdapter : public NestedColumnAdapter { public: PathgridEdgeListAdapter (); @@ -87,7 +87,7 @@ namespace CSMWorld virtual int getNestedRowsCount(const Record& record) const; }; - class FactionReactionsAdapter : public NestedIdAdapter + class FactionReactionsAdapter : public NestedColumnAdapter { public: FactionReactionsAdapter (); @@ -112,7 +112,7 @@ namespace CSMWorld virtual int getNestedRowsCount(const Record& record) const; }; - class RegionSoundListAdapter : public NestedIdAdapter + class RegionSoundListAdapter : public NestedColumnAdapter { public: RegionSoundListAdapter (); @@ -138,7 +138,7 @@ namespace CSMWorld }; template - class SpellListAdapter : public NestedIdAdapter + class SpellListAdapter : public NestedColumnAdapter { public: SpellListAdapter () {} @@ -234,7 +234,7 @@ namespace CSMWorld }; template - class EffectsListAdapter : public NestedIdAdapter + class EffectsListAdapter : public NestedColumnAdapter { public: EffectsListAdapter () {} @@ -476,4 +476,4 @@ namespace CSMWorld }; } -#endif // CSM_WOLRD_IDADAPTERIMP_H +#endif // CSM_WOLRD_NESTEDCOLADAPTERIMP_H diff --git a/apps/opencs/model/world/idadapter.hpp b/apps/opencs/model/world/nestedcolumnadapter.hpp similarity index 77% rename from apps/opencs/model/world/idadapter.hpp rename to apps/opencs/model/world/nestedcolumnadapter.hpp index 84ef2d1f8..e7e66ed4d 100644 --- a/apps/opencs/model/world/idadapter.hpp +++ b/apps/opencs/model/world/nestedcolumnadapter.hpp @@ -1,7 +1,5 @@ -#ifndef CSM_WOLRD_IDADAPTER_H -#define CSM_WOLRD_IDADAPTER_H - -#include "record.hpp" +#ifndef CSM_WOLRD_NESTEDCOLUMNADAPTER_H +#define CSM_WOLRD_NESTEDCOLUMNADAPTER_H class QVariant; @@ -9,14 +7,17 @@ namespace CSMWorld { struct NestedTableWrapperBase; + template + struct Record; + template - class NestedIdAdapter + class NestedColumnAdapter { public: - NestedIdAdapter() {} + NestedColumnAdapter() {} - virtual ~NestedIdAdapter() {} + virtual ~NestedColumnAdapter() {} virtual void addNestedRow(Record& record, int position) const = 0; @@ -36,4 +37,4 @@ namespace CSMWorld }; } -#endif // CSM_WOLRD_IDADAPTER_H +#endif // CSM_WOLRD_NESTEDCOLUMNADAPTER_H diff --git a/apps/opencs/model/world/nestedidcollection.hpp b/apps/opencs/model/world/nestedidcollection.hpp index c7e840955..0cf51b9d8 100644 --- a/apps/opencs/model/world/nestedidcollection.hpp +++ b/apps/opencs/model/world/nestedidcollection.hpp @@ -5,7 +5,7 @@ #include #include "nestedcollection.hpp" -#include "idadapterimp.hpp" +#include "nestedcoladapterimp.hpp" namespace ESM { @@ -23,9 +23,9 @@ namespace CSMWorld template > class NestedIdCollection : public IdCollection, public NestedCollection { - std::map* > mAdapters; + std::map* > mAdapters; - const NestedIdAdapter& getAdapter(const ColumnBase &column) const; + const NestedColumnAdapter& getAdapter(const ColumnBase &column) const; public: @@ -51,7 +51,7 @@ namespace CSMWorld // this method is inherited from NestedCollection, not from Collection virtual NestableColumn *getNestableColumn(int column); - void addAdapter(std::pair* > adapter); + void addAdapter(std::pair* > adapter); }; template @@ -61,21 +61,24 @@ namespace CSMWorld template NestedIdCollection::~NestedIdCollection() { - for (typename std::map* >::iterator iter (mAdapters.begin()); - iter!=mAdapters.end(); ++iter) + for (typename std::map* >::iterator + iter (mAdapters.begin()); iter!=mAdapters.end(); ++iter) + { delete (*iter).second; + } } template - void NestedIdCollection::addAdapter(std::pair* > adapter) + void NestedIdCollection::addAdapter(std::pair* > adapter) { mAdapters.insert(adapter); } template - const NestedIdAdapter& NestedIdCollection::getAdapter(const ColumnBase &column) const + const NestedColumnAdapter& NestedIdCollection::getAdapter(const ColumnBase &column) const { - typename std::map* >::const_iterator iter = + typename std::map* >::const_iterator iter = mAdapters.find (&column); if (iter==mAdapters.end()) From 25261a60e58557c8beb749550008bda42edcad1a Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 12 Apr 2015 18:29:42 +1000 Subject: [PATCH 0926/3725] Add potion magic effects table to dialogue subview. Integration of the adapters to RefIdCollection is incomplete. --- apps/opencs/model/world/refidadapter.hpp | 22 +++-- apps/opencs/model/world/refidadapterimp.cpp | 10 ++- apps/opencs/model/world/refidadapterimp.hpp | 93 +++++++++++++++++++- apps/opencs/model/world/refidcollection.cpp | 95 ++++++++++++++++++++- apps/opencs/model/world/refidcollection.hpp | 6 ++ 5 files changed, 213 insertions(+), 13 deletions(-) diff --git a/apps/opencs/model/world/refidadapter.hpp b/apps/opencs/model/world/refidadapter.hpp index 1a3f2700e..f80ce7ab3 100644 --- a/apps/opencs/model/world/refidadapter.hpp +++ b/apps/opencs/model/world/refidadapter.hpp @@ -45,7 +45,7 @@ namespace CSMWorld virtual std::string getId (const RecordBase& record) const = 0; - virtual void setId(RecordBase& record, const std::string& id) = 0; // FIXME: used by RefIdCollection::cloneRecord() + virtual void setId(RecordBase& record, const std::string& id) = 0; // used by RefIdCollection::cloneRecord() }; class NestedRefIdAdapterBase @@ -55,23 +55,27 @@ namespace CSMWorld virtual ~NestedRefIdAdapterBase(); - virtual void setNestedData (const RefIdColumn *column, RefIdData& data, int row, - const QVariant& value, int subRowIndex, int subColIndex) const = 0; + virtual void setNestedData (const RefIdColumn *column, + RefIdData& data, int row, const QVariant& value, int subRowIndex, int subColIndex) const = 0; - virtual QVariant getNestedData (const RefIdColumn *column, const RefIdData& data, - int index, int subRowIndex, int subColIndex) const = 0; + virtual QVariant getNestedData (const RefIdColumn *column, + const RefIdData& data, int index, int subRowIndex, int subColIndex) const = 0; virtual int getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const = 0; virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const = 0; - virtual void removeNestedRow (const RefIdColumn *column, RefIdData& data, int index, int rowToRemove) const = 0; + virtual void removeNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int rowToRemove) const = 0; - virtual void addNestedRow (const RefIdColumn *column, RefIdData& data, int index, int position) const = 0; + virtual void addNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int position) const = 0; - virtual void setNestedTable (const RefIdColumn* column, RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const = 0; + virtual void setNestedTable (const RefIdColumn* column, + RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const = 0; - virtual NestedTableWrapperBase* nestedTable (const RefIdColumn* column, const RefIdData& data, int index) const = 0; + virtual NestedTableWrapperBase* nestedTable (const RefIdColumn* column, + const RefIdData& data, int index) const = 0; }; class NestedRefIdAdapter : public NestedRefIdAdapterBase diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index b2a08e71c..426bfe3d1 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -7,10 +7,13 @@ #include #include "nestedtablewrapper.hpp" -CSMWorld::PotionRefIdAdapter::PotionRefIdAdapter (const InventoryColumns& columns, +CSMWorld::PotionColumns::PotionColumns (const InventoryColumns& columns) +: InventoryColumns (columns) {} + +CSMWorld::PotionRefIdAdapter::PotionRefIdAdapter (const PotionColumns& columns, const RefIdColumn *autoCalc) : InventoryRefIdAdapter (UniversalId::Type_Potion, columns), - mAutoCalc (autoCalc) + mAutoCalc (autoCalc), mColumns(columns) {} QVariant CSMWorld::PotionRefIdAdapter::getData (const RefIdColumn *column, const RefIdData& data, @@ -22,6 +25,9 @@ QVariant CSMWorld::PotionRefIdAdapter::getData (const RefIdColumn *column, const if (column==mAutoCalc) return record.get().mData.mAutoCalc!=0; + if (column==mColumns.mEffects) + return true; // Required to show nested tables in dialogue subview + return InventoryRefIdAdapter::getData (column, data, index); } diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index 7296b6c68..b12d0cb6f 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -6,6 +6,7 @@ #include #include +#include #include #include "record.hpp" @@ -315,13 +316,21 @@ namespace CSMWorld record.setModified(record2); } + struct PotionColumns : public InventoryColumns + { + const RefIdColumn *mEffects; + + PotionColumns (const InventoryColumns& columns); + }; + class PotionRefIdAdapter : public InventoryRefIdAdapter { + PotionColumns mColumns; const RefIdColumn *mAutoCalc; public: - PotionRefIdAdapter (const InventoryColumns& columns, const RefIdColumn *autoCalc); + PotionRefIdAdapter (const PotionColumns& columns, const RefIdColumn *autoCalc); virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index) const; @@ -828,6 +837,88 @@ namespace CSMWorld const QVariant& value) const; ///< If the data type does not match an exception is thrown. }; + + class NestedRefIdAdapterBase; + + template + class EffectsListAdapter; + + template + class EffectsRefIdAdapter : public EffectsListAdapter, public NestedRefIdAdapterBase + { + UniversalId::Type mType; + + // not implemented + EffectsRefIdAdapter (const EffectsRefIdAdapter&); + EffectsRefIdAdapter& operator= (const EffectsRefIdAdapter&); + + public: + + EffectsRefIdAdapter(UniversalId::Type type) :mType(type) {} + + virtual ~EffectsRefIdAdapter() {} + + virtual void addNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int position) const + { + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + EffectsListAdapter::addNestedRow(record, position); + } + + virtual void removeNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int rowToRemove) const + { + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + EffectsListAdapter::removeNestedRow(record, rowToRemove); + } + + virtual void setNestedTable (const RefIdColumn* column, + RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const + { + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + EffectsListAdapter::setNestedTable(record, nestedTable); + } + + virtual NestedTableWrapperBase* nestedTable (const RefIdColumn* column, + const RefIdData& data, int index) const + { + const Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + return EffectsListAdapter::nestedTable(record); + } + + virtual QVariant getNestedData (const RefIdColumn *column, + const RefIdData& data, int index, int subRowIndex, int subColIndex) const + { + const Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + return EffectsListAdapter::getNestedData(record, subRowIndex, subColIndex); + } + + virtual void setNestedData (const RefIdColumn *column, + RefIdData& data, int row, const QVariant& value, int subRowIndex, int subColIndex) const + { + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (row, mType))); + EffectsListAdapter::setNestedData(record, value, subRowIndex, subColIndex); + } + + virtual int getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const + { + const Record record; + return EffectsListAdapter::getNestedColumnsCount(record); + } + + virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const + { + const Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + return EffectsListAdapter::getNestedRowsCount(record); + } + }; } #endif diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 392a1677e..929a3b245 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -9,6 +9,7 @@ #include "refidadapterimp.hpp" #include "columns.hpp" #include "nestedtablewrapper.hpp" +#include "nestedcoladapterimp.hpp" CSMWorld::RefIdColumn::RefIdColumn (int columnId, Display displayType, int flag, bool editable, bool userEditable) @@ -70,6 +71,29 @@ CSMWorld::RefIdCollection::RefIdCollection() mColumns.push_back (RefIdColumn (Columns::ColumnId_CoinValue, ColumnBase::Display_Integer)); inventoryColumns.mValue = &mColumns.back(); + // nested table + PotionColumns potionColumns (inventoryColumns); + mColumns.push_back (RefIdColumn (Columns::ColumnId_EffectList, ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue)); + potionColumns.mEffects = &mColumns.back(); // see refidadapterimp.hpp + mNestedAdapters.insert (std::make_pair(&mColumns.back(), + new EffectsRefIdAdapter (UniversalId::Type_Potion))); + mColumns.back().addColumn( + new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_String/*, false*/)); + mColumns.back().addColumn( + new NestedChildColumn (Columns::ColumnId_Skill, ColumnBase::Display_String)); + mColumns.back().addColumn( + new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_String)); // reuse attribute + mColumns.back().addColumn( + new NestedChildColumn (Columns::ColumnId_EffectRange, ColumnBase::Display_Integer)); + mColumns.back().addColumn( + new NestedChildColumn (Columns::ColumnId_EffectArea, ColumnBase::Display_String)); + mColumns.back().addColumn( + new NestedChildColumn (Columns::ColumnId_Duration, ColumnBase::Display_Integer)); // reuse from light + mColumns.back().addColumn( + new NestedChildColumn (Columns::ColumnId_MinRange, ColumnBase::Display_Integer)); // reuse from sound + mColumns.back().addColumn( + new NestedChildColumn (Columns::ColumnId_MaxRange, ColumnBase::Display_Integer)); // reuse from sound + EnchantableColumns enchantableColumns (inventoryColumns); mColumns.push_back (RefIdColumn (Columns::ColumnId_Enchantment, ColumnBase::Display_String)); @@ -385,7 +409,7 @@ CSMWorld::RefIdCollection::RefIdCollection() mAdapters.insert (std::make_pair (UniversalId::Type_Activator, new NameRefIdAdapter (UniversalId::Type_Activator, nameColumns))); mAdapters.insert (std::make_pair (UniversalId::Type_Potion, - new PotionRefIdAdapter (inventoryColumns, autoCalc))); + new PotionRefIdAdapter (potionColumns, autoCalc))); mAdapters.insert (std::make_pair (UniversalId::Type_Apparatus, new ApparatusRefIdAdapter (inventoryColumns, apparatusType, toolsColumns.mQuality))); mAdapters.insert (std::make_pair (UniversalId::Type_Armor, @@ -430,6 +454,10 @@ CSMWorld::RefIdCollection::~RefIdCollection() for (std::map::iterator iter (mAdapters.begin()); iter!=mAdapters.end(); ++iter) delete iter->second; + + for (std::map::iterator iter (mNestedAdapters.begin()); + iter!=mNestedAdapters.end(); ++iter) + delete iter->second; } int CSMWorld::RefIdCollection::getSize() const @@ -475,6 +503,12 @@ QVariant CSMWorld::RefIdCollection::getNestedData (int row, int column, int subR { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex(row); + const CSMWorld::NestedRefIdAdapterBase* nestedAdapter = getNestedAdapter(mColumns.at(column)); + if (nestedAdapter) + { + return nestedAdapter->getNestedData(&mColumns.at (column), mData, localIndex.first, subRow, subColumn); + } + const CSMWorld::NestedRefIdAdapter& adaptor = dynamic_cast(findAdapter (localIndex.second)); return adaptor.getNestedData (&mColumns.at (column), mData, localIndex.first, subRow, subColumn); @@ -493,6 +527,13 @@ void CSMWorld::RefIdCollection::setNestedData(int row, int column, const QVarian { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); + const CSMWorld::NestedRefIdAdapterBase* nestedAdapter = getNestedAdapter(mColumns.at(column)); + if (nestedAdapter) + { + nestedAdapter->setNestedData(&mColumns.at (column), mData, localIndex.first, data, subRow, subColumn); + return; + } + const RefIdAdapter& adaptor = findAdapter (localIndex.second); dynamic_cast(adaptor).setNestedData (&mColumns.at (column), mData, localIndex.first, data, subRow, subColumn); @@ -507,6 +548,13 @@ void CSMWorld::RefIdCollection::removeNestedRows(int row, int column, int subRow { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); + const CSMWorld::NestedRefIdAdapterBase* nestedAdapter = getNestedAdapter(mColumns.at(column)); + if (nestedAdapter) + { + nestedAdapter->removeNestedRow(&mColumns.at (column), mData, localIndex.first, subRow); + return; + } + const RefIdAdapter& adaptor = findAdapter (localIndex.second); dynamic_cast(adaptor).removeNestedRow(&mColumns.at (column), mData, localIndex.first, subRow); @@ -651,6 +699,12 @@ int CSMWorld::RefIdCollection::getNestedRowsCount(int row, int column) const { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); + const CSMWorld::NestedRefIdAdapterBase* nestedAdapter = getNestedAdapter(mColumns.at(column)); + if (nestedAdapter) + { + return nestedAdapter->getNestedRowsCount(&mColumns.at(column), mData, localIndex.first); + } + const CSMWorld::NestedRefIdAdapter& adaptor = dynamic_cast(findAdapter (localIndex.second)); return adaptor.getNestedRowsCount(&mColumns.at(column), mData, localIndex.first); @@ -660,6 +714,12 @@ int CSMWorld::RefIdCollection::getNestedColumnsCount(int row, int column) const { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); + const CSMWorld::NestedRefIdAdapterBase* nestedAdapter = getNestedAdapter(mColumns.at(column)); + if (nestedAdapter) + { + return nestedAdapter->getNestedColumnsCount(&mColumns.at(column), mData); + } + const CSMWorld::NestedRefIdAdapter& adaptor = dynamic_cast(findAdapter (localIndex.second)); return adaptor.getNestedColumnsCount(&mColumns.at(column), mData); @@ -674,6 +734,13 @@ void CSMWorld::RefIdCollection::addNestedRow(int row, int col, int position) { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); + const CSMWorld::NestedRefIdAdapterBase* nestedAdapter = getNestedAdapter(mColumns.at(col)); + if (nestedAdapter) + { + nestedAdapter->addNestedRow(&mColumns.at(col), mData, localIndex.first, position); + return; + } + const CSMWorld::NestedRefIdAdapter& adaptor = dynamic_cast(findAdapter (localIndex.second)); adaptor.addNestedRow(&mColumns.at(col), mData, localIndex.first, position); @@ -683,6 +750,13 @@ void CSMWorld::RefIdCollection::setNestedTable(int row, int column, const CSMWor { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); + const CSMWorld::NestedRefIdAdapterBase* nestedAdapter = getNestedAdapter(mColumns.at(column)); + if (nestedAdapter) + { + nestedAdapter->setNestedTable(&mColumns.at(column), mData, localIndex.first, nestedTable); + return; + } + const CSMWorld::NestedRefIdAdapter& adaptor = dynamic_cast(findAdapter (localIndex.second)); adaptor.setNestedTable(&mColumns.at(column), mData, localIndex.first, nestedTable); @@ -692,7 +766,26 @@ CSMWorld::NestedTableWrapperBase* CSMWorld::RefIdCollection::nestedTable(int row { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); + const CSMWorld::NestedRefIdAdapterBase* nestedAdapter = getNestedAdapter(mColumns.at(column)); + if (nestedAdapter) + { + return nestedAdapter->nestedTable(&mColumns.at(column), mData, localIndex.first); + } + const CSMWorld::NestedRefIdAdapter& adaptor = dynamic_cast(findAdapter (localIndex.second)); return adaptor.nestedTable(&mColumns.at(column), mData, localIndex.first); } + +const CSMWorld::NestedRefIdAdapterBase* CSMWorld::RefIdCollection::getNestedAdapter(const CSMWorld::ColumnBase &column) const +{ + std::map::const_iterator iter = + mNestedAdapters.find (&column); + + if (iter==mNestedAdapters.end()) + return 0; // FIXME: testing only + //throw std::runtime_error("No such column in the nestedadapters"); + + //return *iter->second; + return iter->second; +} diff --git a/apps/opencs/model/world/refidcollection.hpp b/apps/opencs/model/world/refidcollection.hpp index 3315212c1..70651b78d 100644 --- a/apps/opencs/model/world/refidcollection.hpp +++ b/apps/opencs/model/world/refidcollection.hpp @@ -19,6 +19,7 @@ namespace CSMWorld { class RefIdAdapter; struct NestedTableWrapperBase; + class NestedRefIdAdapterBase; class RefIdColumn : public NestableColumn { @@ -44,11 +45,16 @@ namespace CSMWorld std::deque mColumns; std::map mAdapters; + std::map mNestedAdapters; + private: const RefIdAdapter& findAdapter (UniversalId::Type) const; ///< Throws an exception if no adaptor for \a Type can be found. + //const NestedRefIdAdapterBase& getNestedAdapter(const ColumnBase &column) const; + const NestedRefIdAdapterBase* getNestedAdapter(const ColumnBase &column) const; + public: RefIdCollection(); From 7ccf53e750781476e256cdb0ed1e6919edc6e9be Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 12 Apr 2015 20:03:55 +1000 Subject: [PATCH 0927/3725] Changed over inventory adapters. Fixed a few places where modified records were not set properly. --- .../model/world/nestedcoladapterimp.cpp | 28 +++- .../model/world/nestedcoladapterimp.hpp | 12 +- apps/opencs/model/world/refidadapterimp.cpp | 6 +- apps/opencs/model/world/refidadapterimp.hpp | 147 +++++++++++++++++- apps/opencs/model/world/refidcollection.cpp | 8 +- 5 files changed, 186 insertions(+), 15 deletions(-) diff --git a/apps/opencs/model/world/nestedcoladapterimp.cpp b/apps/opencs/model/world/nestedcoladapterimp.cpp index 2bf1ffadd..785817d33 100644 --- a/apps/opencs/model/world/nestedcoladapterimp.cpp +++ b/apps/opencs/model/world/nestedcoladapterimp.cpp @@ -81,13 +81,17 @@ namespace CSMWorld void PathgridPointListAdapter::setNestedTable(Record& record, const NestedTableWrapperBase& nestedTable) const { - record.get().mPoints = + Pathgrid pathgrid = record.get(); + + pathgrid.mPoints = static_cast(nestedTable).mRecord.mPoints; - record.get().mData.mS2 = + pathgrid.mData.mS2 = static_cast(nestedTable).mRecord.mData.mS2; // also update edges in case points were added/removed - record.get().mEdges = + pathgrid.mEdges = static_cast(nestedTable).mRecord.mEdges; + + record.setModified (pathgrid); } NestedTableWrapperBase* PathgridPointListAdapter::nestedTable(const Record& record) const @@ -180,8 +184,12 @@ namespace CSMWorld void PathgridEdgeListAdapter::setNestedTable(Record& record, const NestedTableWrapperBase& nestedTable) const { - record.get().mEdges = + Pathgrid pathgrid = record.get(); + + pathgrid.mEdges = static_cast &>(nestedTable).mNestedTable; + + record.setModified (pathgrid); } NestedTableWrapperBase* PathgridEdgeListAdapter::nestedTable(const Record& record) const @@ -277,8 +285,12 @@ namespace CSMWorld void FactionReactionsAdapter::setNestedTable(Record& record, const NestedTableWrapperBase& nestedTable) const { - record.get().mReactions = + ESM::Faction faction = record.get(); + + faction.mReactions = static_cast >&>(nestedTable).mNestedTable; + + record.setModified (faction); } NestedTableWrapperBase* FactionReactionsAdapter::nestedTable(const Record& record) const @@ -393,8 +405,12 @@ namespace CSMWorld void RegionSoundListAdapter::setNestedTable(Record& record, const NestedTableWrapperBase& nestedTable) const { - record.get().mSoundList = + ESM::Region region = record.get(); + + region.mSoundList = static_cast >&>(nestedTable).mNestedTable; + + record.setModified (region); } NestedTableWrapperBase* RegionSoundListAdapter::nestedTable(const Record& record) const diff --git a/apps/opencs/model/world/nestedcoladapterimp.hpp b/apps/opencs/model/world/nestedcoladapterimp.hpp index 7fed74868..387b07e5c 100644 --- a/apps/opencs/model/world/nestedcoladapterimp.hpp +++ b/apps/opencs/model/world/nestedcoladapterimp.hpp @@ -173,8 +173,12 @@ namespace CSMWorld virtual void setNestedTable(Record& record, const NestedTableWrapperBase& nestedTable) const { - record.get().mPowers.mList = + ESXRecordT raceOrBthSgn = record.get(); + + raceOrBthSgn.mPowers.mList = static_cast >&>(nestedTable).mNestedTable; + + record.setModified (raceOrBthSgn); } virtual NestedTableWrapperBase* nestedTable(const Record& record) const @@ -277,8 +281,12 @@ namespace CSMWorld virtual void setNestedTable(Record& record, const NestedTableWrapperBase& nestedTable) const { - record.get().mEffects.mList = + ESXRecordT magic = record.get(); + + magic.mEffects.mList = static_cast >&>(nestedTable).mNestedTable; + + record.setModified (magic); } virtual NestedTableWrapperBase* nestedTable(const Record& record) const diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index 426bfe3d1..42d1aa52e 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -26,7 +26,7 @@ QVariant CSMWorld::PotionRefIdAdapter::getData (const RefIdColumn *column, const return record.get().mData.mAutoCalc!=0; if (column==mColumns.mEffects) - return true; // Required to show nested tables in dialogue subview + return true; // to show nested tables in dialogue subview, see IdTree::hasChildren() return InventoryRefIdAdapter::getData (column, data, index); } @@ -213,7 +213,7 @@ QVariant CSMWorld::ContainerRefIdAdapter::getData (const RefIdColumn *column, return (record.get().mFlags & ESM::Container::Respawn)!=0; if (column==mContent) - return true; // required by IdTree::hasChildren() + return true; // Required to show nested tables in dialogue subview return NameRefIdAdapter::getData (column, data, index); } @@ -497,7 +497,7 @@ QVariant CSMWorld::NpcRefIdAdapter::getData (const RefIdColumn *column, const Re return QString::fromUtf8 (record.get().mHead.c_str()); if (column==mColumns.mDestinations) - return true; // required by IdTree::hasChildren() + return true; // to show nested tables in dialogue subview, see IdTree::hasChildren() std::map::const_iterator iter = mColumns.mFlags.find (column); diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index b12d0cb6f..08e2e7493 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -8,6 +8,9 @@ #include #include #include +#include +#include +#include #include "record.hpp" #include "refiddata.hpp" @@ -545,10 +548,10 @@ namespace CSMWorld return record.get().mAiData.mAlarm; if (column==mActors.mInventory) - return true; // required by IdTree::hasChildren() + return true; // to show nested tables in dialogue subview, see IdTree::hasChildren() if (column==mActors.mSpells) - return true; // required by IdTree::hasChildren() + return true; // to show nested tables in dialogue subview, see IdTree::hasChildren() std::map::const_iterator iter = mActors.mServices.find (column); @@ -908,7 +911,7 @@ namespace CSMWorld virtual int getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const { - const Record record; + const Record record; // not used, just a dummy return EffectsListAdapter::getNestedColumnsCount(record); } @@ -919,6 +922,144 @@ namespace CSMWorld return EffectsListAdapter::getNestedRowsCount(record); } }; + + template + class NestedInventoryRefIdAdapter : public NestedRefIdAdapterBase + { + UniversalId::Type mType; + + // not implemented + NestedInventoryRefIdAdapter (const NestedInventoryRefIdAdapter&); + NestedInventoryRefIdAdapter& operator= (const NestedInventoryRefIdAdapter&); + + public: + + NestedInventoryRefIdAdapter(UniversalId::Type type) :mType(type) {} + + virtual ~NestedInventoryRefIdAdapter() {} + + virtual void addNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int position) const + { + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + ESXRecordT container = record.get(); + + std::vector& list = container.mInventory.mList; + + ESM::ContItem newRow = {0, {""}}; + + if (position >= (int)list.size()) + list.push_back(newRow); + else + list.insert(list.begin()+position, newRow); + + record.setModified (container); + } + + virtual void removeNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int rowToRemove) const + { + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + ESXRecordT container = record.get(); + + std::vector& list = container.mInventory.mList; + + if (rowToRemove < 0 || rowToRemove >= static_cast (list.size())) + throw std::runtime_error ("index out of range"); + + list.erase (list.begin () + rowToRemove); + + record.setModified (container); + } + + virtual void setNestedTable (const RefIdColumn* column, + RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const + { + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + ESXRecordT container = record.get(); + + container.mInventory.mList = + static_cast >&>(nestedTable).mNestedTable; + + record.setModified (container); + } + + virtual NestedTableWrapperBase* nestedTable (const RefIdColumn* column, + const RefIdData& data, int index) const + { + const Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + + // deleted by dtor of NestedTableStoring + return new NestedTableWrapper >(record.get().mInventory.mList); + } + + virtual QVariant getNestedData (const RefIdColumn *column, + const RefIdData& data, int index, int subRowIndex, int subColIndex) const + { + const Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + + const std::vector& list = record.get().mInventory.mList; + + if (subRowIndex < 0 || subRowIndex >= static_cast (list.size())) + throw std::runtime_error ("index out of range"); + + const ESM::ContItem& content = list.at(subRowIndex); + + switch (subColIndex) + { + case 0: return QString::fromUtf8(content.mItem.toString().c_str()); + case 1: return content.mCount; + default: + throw std::runtime_error("Trying to access non-existing column in the nested table!"); + } + } + + virtual void setNestedData (const RefIdColumn *column, + RefIdData& data, int row, const QVariant& value, int subRowIndex, int subColIndex) const + { + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (row, mType))); + ESXRecordT container = record.get(); + std::vector& list = container.mInventory.mList; + + if (subRowIndex < 0 || subRowIndex >= static_cast (list.size())) + throw std::runtime_error ("index out of range"); + + switch(subColIndex) + { + case 0: + list.at(subRowIndex).mItem.assign(std::string(value.toString().toUtf8().constData())); + break; + + case 1: + list.at(subRowIndex).mCount = value.toInt(); + break; + + default: + throw std::runtime_error("Trying to access non-existing column in the nested table!"); + } + + record.setModified (container); + } + + virtual int getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const + { + return 2; + } + + virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const + { + const Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + + return static_cast(record.get().mInventory.mList.size()); + } + }; } #endif diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 929a3b245..755a1f56f 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -76,7 +76,7 @@ CSMWorld::RefIdCollection::RefIdCollection() mColumns.push_back (RefIdColumn (Columns::ColumnId_EffectList, ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue)); potionColumns.mEffects = &mColumns.back(); // see refidadapterimp.hpp mNestedAdapters.insert (std::make_pair(&mColumns.back(), - new EffectsRefIdAdapter (UniversalId::Type_Potion))); + new EffectsRefIdAdapter (UniversalId::Type_Potion))); mColumns.back().addColumn( new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_String/*, false*/)); mColumns.back().addColumn( @@ -124,6 +124,10 @@ CSMWorld::RefIdCollection::RefIdCollection() // Nested table mColumns.push_back(RefIdColumn (Columns::ColumnId_ActorInventory, ColumnBase::Display_NestedItemList, ColumnBase::Flag_Dialogue)); actorsColumns.mInventory = &mColumns.back(); + mNestedAdapters.insert (std::make_pair(&mColumns.back(), + new NestedInventoryRefIdAdapter (UniversalId::Type_Npc))); + mNestedAdapters.insert (std::make_pair(&mColumns.back(), + new NestedInventoryRefIdAdapter (UniversalId::Type_Creature))); mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_InventoryItemId, CSMWorld::ColumnBase::Display_String)); mColumns.back().addColumn( @@ -205,6 +209,8 @@ CSMWorld::RefIdCollection::RefIdCollection() // Nested table mColumns.push_back(RefIdColumn (Columns::ColumnId_ContainerContent, ColumnBase::Display_NestedItemList, ColumnBase::Flag_Dialogue)); const RefIdColumn *content = &mColumns.back(); + mNestedAdapters.insert (std::make_pair(&mColumns.back(), + new NestedInventoryRefIdAdapter (UniversalId::Type_Container))); mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_InventoryItemId, CSMWorld::ColumnBase::Display_String)); mColumns.back().addColumn( From c92592493ed8cf454a83034eb100181f0d7865a2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 12 Apr 2015 15:34:50 +0200 Subject: [PATCH 0928/3725] OpenMW: create a window and render the starting cell(s) --- apps/nifosgtest/test.cpp | 3 +- apps/openmw/CMakeLists.txt | 5 +- apps/openmw/engine.cpp | 69 +- apps/openmw/engine.hpp | 32 +- apps/openmw/mwclass/activator.cpp | 5 +- apps/openmw/mwclass/container.cpp | 5 +- apps/openmw/mwclass/creature.cpp | 8 +- apps/openmw/mwclass/door.cpp | 5 +- apps/openmw/mwclass/light.cpp | 4 +- apps/openmw/mwclass/npc.cpp | 4 +- apps/openmw/mwgui/windowmanagerimp.cpp | 1 + apps/openmw/mwmechanics/aiwander.cpp | 2 +- apps/openmw/mwmechanics/combat.cpp | 2 +- apps/openmw/mwmechanics/levelledlist.hpp | 2 + .../mwmechanics/mechanicsmanagerimp.cpp | 2 +- apps/openmw/mwmechanics/spellcasting.cpp | 13 +- apps/openmw/mwrender/actors.hpp | 2 - apps/openmw/mwrender/animation.cpp | 1542 +---------------- apps/openmw/mwrender/animation.hpp | 198 +-- apps/openmw/mwrender/objects.cpp | 245 ++- apps/openmw/mwrender/objects.hpp | 57 +- apps/openmw/mwrender/renderingmanager.cpp | 1060 +---------- apps/openmw/mwrender/renderingmanager.hpp | 267 +-- .../mwscript/transformationextensions.cpp | 4 +- apps/openmw/mwworld/cellfunctors.hpp | 4 +- apps/openmw/mwworld/containerstore.cpp | 2 +- apps/openmw/mwworld/physicssystem.cpp | 12 +- apps/openmw/mwworld/refdata.cpp | 15 +- apps/openmw/mwworld/refdata.hpp | 19 +- apps/openmw/mwworld/scene.cpp | 83 +- apps/openmw/mwworld/scene.hpp | 9 +- apps/openmw/mwworld/worldimp.cpp | 49 +- apps/openmw/mwworld/worldimp.hpp | 21 +- components/sceneutil/lightmanager.cpp | 42 +- components/sceneutil/lightmanager.hpp | 7 + files/settings-default.cfg | 9 - 36 files changed, 636 insertions(+), 3173 deletions(-) diff --git a/apps/nifosgtest/test.cpp b/apps/nifosgtest/test.cpp index 332867be5..487a91890 100644 --- a/apps/nifosgtest/test.cpp +++ b/apps/nifosgtest/test.cpp @@ -127,8 +127,7 @@ int main(int argc, char** argv) osg::Group* newNode = new osg::Group; NifOsg::Loader loader; Resource::TextureManager texMgr(&resourceMgr); - loader.mTextureManager = &texMgr; - newNode->addChild(loader.load(nif)); + newNode->addChild(loader.load(nif, &texMgr)); osg::PositionAttitudeTransform* trans = new osg::PositionAttitudeTransform; root->addChild(trans); diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 50aeafc2a..e10688149 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -20,8 +20,8 @@ set(GAME_HEADER source_group(game FILES ${GAME} ${GAME_HEADER}) add_openmw_dir (mwrender -actors objects -# renderingmanager debugging sky camera animation npcanimation creatureanimation activatoranimation + actors objects renderingmanager animation +# debugging sky camera npcanimation creatureanimation activatoranimation # renderinginterface localmap occlusionquery water shadows # characterpreview globalmap ripplesimulation refraction # terrainstorage renderconst effectmanager weaponanimation @@ -129,6 +129,7 @@ target_link_libraries(openmw ${OENGINE_LIBRARY} ${OGRE_LIBRARIES} ${OGRE_STATIC_PLUGINS} + ${OPENSCENEGRAPH_LIBRARIES} ${Boost_LIBRARIES} ${OPENAL_LIBRARY} ${SOUND_INPUT_LIBRARY} diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index c7a92e52e..0d0294fa7 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -3,15 +3,23 @@ #include #include -#include -#include +#include +#include + +#include #include #include +// TODO: move to component #include +#include +#include + +#include + #include #include @@ -172,8 +180,7 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) } OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) - : mOgre (0) - , mVerboseScripts (false) + : mVerboseScripts (false) , mSkipMenu (false) , mUseSound (true) , mCompileAll (false) @@ -220,10 +227,6 @@ void OMW::Engine::addResourcesDirectory (const boost::filesystem::path& path) { } -void OMW::Engine::addZipResource (const boost::filesystem::path& path) -{ -} - void OMW::Engine::enableFSStrict(bool fsStrict) { mFSStrict = fsStrict; @@ -318,21 +321,27 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) addResourcesDirectory(mResDir / "shadows"); addResourcesDirectory(mResDir / "materials"); - OEngine::Render::WindowSettings windowSettings; - windowSettings.fullscreen = settings.getBool("fullscreen", "Video"); - windowSettings.window_border = settings.getBool("window border", "Video"); - windowSettings.window_x = settings.getInt("resolution x", "Video"); - windowSettings.window_y = settings.getInt("resolution y", "Video"); - windowSettings.screen = settings.getInt("screen", "Video"); - windowSettings.vsync = settings.getBool("vsync", "Video"); - windowSettings.icon = "openmw.png"; - std::string aa = settings.getString("antialiasing", "Video"); - windowSettings.fsaa = (aa.substr(0, 4) == "MSAA") ? aa.substr(5, aa.size()-5) : "0"; + //OEngine::Render::WindowSettings windowSettings; + //windowSettings.fullscreen = settings.getBool("fullscreen", "Video"); + //windowSettings.window_border = settings.getBool("window border", "Video"); + //windowSettings.vsync = settings.getBool("vsync", "Video"); + //windowSettings.icon = "openmw.png"; + //std::string aa = settings.getString("antialiasing", "Video"); + //windowSettings.fsaa = (aa.substr(0, 4) == "MSAA") ? aa.substr(5, aa.size()-5) : "0"; SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, settings.getBool("minimize on focus loss", "Video") ? "1" : "0"); - //Bsa::registerResources (mFileCollections, mArchives, true, mFSStrict); + // not handling fullscreen yet, we should figure this out when adding SDL to the mix + mViewer.setUpViewInWindow(0, 0, settings.getInt("resolution x", "Video"), settings.getInt("resolution y", "Video"), settings.getInt("screen", "Video")); + osg::ref_ptr rootNode (new osg::Group); + mViewer.setSceneData(rootNode); + + mVFS.reset(new VFS::Manager(mFSStrict)); + + VFS::registerArchives(mVFS.get(), mFileCollections, mArchives, true); + + mResourceSystem.reset(new Resource::ResourceSystem(mVFS.get())); // Create input and UI first to set up a bootstrapping environment for // showing a loading screen and keeping the window responsive while doing so @@ -378,8 +387,8 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) } // Create the world - mEnvironment.setWorld( new MWWorld::World (mFileCollections, mContentFiles, - mResDir, mCfgMgr.getCachePath(), mEncoder, mFallbackMap, + mEnvironment.setWorld( new MWWorld::World (mViewer, rootNode, mResourceSystem.get(), + mFileCollections, mContentFiles, mEncoder, mFallbackMap, mActivationDistanceOverride, mCellName, mStartupScript)); MWBase::Environment::get().getWorld()->setupPlayer(); //input->setPlayer(&mEnvironment.getWorld()->getPlayer()); @@ -460,7 +469,7 @@ void OMW::Engine::go() { MWBase::Environment::get().getStateManager()->loadGame(mSaveGameFile); } - else if (!mSkipMenu) + else if (0)// !mSkipMenu) { // start in main menu MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_MainMenu); @@ -481,6 +490,22 @@ void OMW::Engine::go() } // Start the main rendering loop + mViewer.setCameraManipulator(new osgGA::TrackballManipulator); + mViewer.addEventHandler(new osgViewer::StatsHandler); + + osg::Timer timer; + //osgUtil::IncrementalCompileOperation* ico = new osgUtil::IncrementalCompileOperation; + //ico->compileAllForNextFrame(1); + //mViewer.setRealizeOperation(ico); + mViewer.realize(); + std::cout << "realize took " << timer.time_m() << std::endl; + while (!mViewer.done()) + { + MWBase::Environment::get().getWorld()->update(0.f, false); + + mViewer.frame(/*simulationTime*/); + } + /* Ogre::Timer timer; while (!MWBase::Environment::get().getStateManager()->hasQuitRequest()) diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index ef26ceb3a..de09082d8 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -9,11 +9,23 @@ #include #include +#include + #include "mwbase/environment.hpp" #include "mwworld/ptr.hpp" +namespace Resource +{ + class ResourceSystem; +} + +namespace VFS +{ + class Manager; +} + namespace Compiler { class Context; @@ -39,19 +51,6 @@ namespace MWGui class WindowManager; } -namespace OEngine -{ - namespace GUI - { - class MyGUIManager; - } - - namespace Render - { - class OgreRenderer; - } -} - namespace Files { struct ConfigurationManager; @@ -62,13 +61,15 @@ namespace OMW /// \brief Main engine class, that brings together all the components of OpenMW class Engine : private Ogre::FrameListener { + std::auto_ptr mVFS; + std::auto_ptr mResourceSystem; MWBase::Environment mEnvironment; ToUTF8::FromType mEncoding; ToUTF8::Utf8Encoder* mEncoder; Files::PathContainer mDataDirs; std::vector mArchives; boost::filesystem::path mResDir; - OEngine::Render::OgreRenderer *mOgre; + osgViewer::Viewer mViewer; std::string mCellName; std::vector mContentFiles; bool mVerboseScripts; @@ -108,9 +109,6 @@ namespace OMW /// \note This function works recursively. void addResourcesDirectory (const boost::filesystem::path& path); - /// add a .zip resource - void addZipResource (const boost::filesystem::path& path); - void executeLocalScripts(); virtual bool frameRenderingQueued (const Ogre::FrameEvent& evt); diff --git a/apps/openmw/mwclass/activator.cpp b/apps/openmw/mwclass/activator.cpp index 457b0cec1..2621f5e52 100644 --- a/apps/openmw/mwclass/activator.cpp +++ b/apps/openmw/mwclass/activator.cpp @@ -16,7 +16,7 @@ #include "../mwworld/failedaction.hpp" #include "../mwworld/nullaction.hpp" -#include "../mwrender/actors.hpp" +#include "../mwrender/objects.hpp" #include "../mwrender/renderinginterface.hpp" #include "../mwgui/tooltips.hpp" @@ -34,8 +34,7 @@ namespace MWClass void Activator::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { if (!model.empty()) { - MWRender::Actors& actors = renderingInterface.getActors(); - actors.insertActivator(ptr, model); + renderingInterface.getObjects().insertModel(ptr, model, true); } } diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index 5f49a74b6..ac23744e8 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -23,7 +23,7 @@ #include "../mwgui/tooltips.hpp" -#include "../mwrender/actors.hpp" +#include "../mwrender/objects.hpp" #include "../mwrender/renderinginterface.hpp" #include "../mwmechanics/npcstats.hpp" @@ -93,8 +93,7 @@ namespace MWClass void Container::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { if (!model.empty()) { - MWRender::Actors& actors = renderingInterface.getActors(); - actors.insertActivator(ptr, model); + renderingInterface.getObjects().insertModel(ptr, model, true); } } diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index ac99fa4b4..c1b8177f7 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -29,7 +29,7 @@ #include "../mwworld/cellstore.hpp" #include "../mwrender/renderinginterface.hpp" -#include "../mwrender/actors.hpp" +#include "../mwrender/objects.hpp" #include "../mwgui/tooltips.hpp" @@ -163,10 +163,10 @@ namespace MWClass void Creature::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { - //MWWorld::LiveCellRef *ref = ptr.get(); + MWWorld::LiveCellRef *ref = ptr.get(); - //MWRender::Actors& actors = renderingInterface.getActors(); - //actors.insertCreature(ptr, model, (ref->mBase->mFlags & ESM::Creature::Weapon) != 0); + MWRender::Objects& objects = renderingInterface.getObjects(); + objects.insertCreature(ptr, model, (ref->mBase->mFlags & ESM::Creature::Weapon) != 0); } void Creature::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 2d39881b1..f46ede730 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -24,7 +24,7 @@ #include "../mwgui/tooltips.hpp" -#include "../mwrender/actors.hpp" +#include "../mwrender/objects.hpp" #include "../mwrender/renderinginterface.hpp" namespace @@ -52,8 +52,7 @@ namespace MWClass void Door::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { if (!model.empty()) { - MWRender::Actors& actors = renderingInterface.getActors(); - actors.insertActivator(ptr, model); + renderingInterface.getObjects().insertModel(ptr, model, true); } } diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 90c708f97..2cf31d996 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -23,7 +23,6 @@ #include "../mwgui/tooltips.hpp" #include "../mwrender/objects.hpp" -#include "../mwrender/actors.hpp" #include "../mwrender/renderinginterface.hpp" namespace MWClass @@ -39,8 +38,7 @@ namespace MWClass ptr.get(); // Insert even if model is empty, so that the light is added - MWRender::Actors& actors = renderingInterface.getActors(); - actors.insertActivator(ptr, model, !(ref->mBase->mData.mFlags & ESM::Light::OffDefault)); + renderingInterface.getObjects().insertModel(ptr, model, true, !(ref->mBase->mData.mFlags & ESM::Light::OffDefault)); } void Light::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 3dcb57fbb..506852a90 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -35,7 +35,7 @@ #include "../mwworld/physicssystem.hpp" #include "../mwworld/cellstore.hpp" -#include "../mwrender/actors.hpp" +#include "../mwrender/objects.hpp" #include "../mwrender/renderinginterface.hpp" #include "../mwgui/tooltips.hpp" @@ -409,7 +409,7 @@ namespace MWClass void Npc::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { - renderingInterface.getActors().insertNPC(ptr); + renderingInterface.getObjects().insertNPC(ptr); } void Npc::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index bc7bb0bb5..319e1d7ec 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1702,6 +1702,7 @@ namespace MWGui void WindowManager::playVideo(const std::string &name, bool allowSkipping) { + return; mVideoWidget->playVideo("video\\" + name); mVideoWidget->eventKeyButtonPressed.clear(); diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index d277b1249..685051860 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -474,7 +474,7 @@ namespace MWMechanics Ogre::Vector3 dir = playerPos - actorPos; Ogre::Radian faceAngle = Ogre::Math::ATan2(dir.x,dir.y); - Ogre::Radian actorAngle = actor.getRefData().getBaseNode()->getOrientation().getRoll(); + Ogre::Radian actorAngle = actor.getRefData().getBaseNodeOld()->getOrientation().getRoll(); // an attempt at reducing the turning animation glitch if( Ogre::Math::Abs( faceAngle - actorAngle ) >= Ogre::Degree(5) ) // TODO: is there a better way? { diff --git a/apps/openmw/mwmechanics/combat.cpp b/apps/openmw/mwmechanics/combat.cpp index c5fc34507..64456dd11 100644 --- a/apps/openmw/mwmechanics/combat.cpp +++ b/apps/openmw/mwmechanics/combat.cpp @@ -75,7 +75,7 @@ namespace MWMechanics return false; Ogre::Degree angle = signedAngle (Ogre::Vector3(attacker.getRefData().getPosition().pos) - Ogre::Vector3(blocker.getRefData().getPosition().pos), - blocker.getRefData().getBaseNode()->getOrientation().yAxis(), Ogre::Vector3(0,0,1)); + blocker.getRefData().getBaseNodeOld()->getOrientation().yAxis(), Ogre::Vector3(0,0,1)); const MWWorld::Store& gmst = MWBase::Environment::get().getWorld()->getStore().get(); if (angle.valueDegrees() < gmst.find("fCombatBlockLeftAngle")->getFloat()) diff --git a/apps/openmw/mwmechanics/levelledlist.hpp b/apps/openmw/mwmechanics/levelledlist.hpp index 20b87a3a9..76c472001 100644 --- a/apps/openmw/mwmechanics/levelledlist.hpp +++ b/apps/openmw/mwmechanics/levelledlist.hpp @@ -3,6 +3,8 @@ #include +#include + #include "../mwworld/ptr.hpp" #include "../mwworld/esmstore.hpp" #include "../mwworld/manualref.hpp" diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index abfc793de..0b3390271 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1385,7 +1385,7 @@ namespace MWMechanics static float fSneakViewMult = store.find("fSneakViewMult")->getFloat(); float y = 0; Ogre::Vector3 vec = pos1 - pos2; - Ogre::Radian angle = observer.getRefData().getBaseNode()->getOrientation().yAxis().angleBetween(vec); + Ogre::Radian angle = observer.getRefData().getBaseNodeOld()->getOrientation().yAxis().angleBetween(vec); if (angle < Ogre::Degree(90)) y = obsTerm * observerStats.getFatigueTerm() * fSneakNoViewMult; else diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index a7d3545b3..5f4d986b4 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -418,7 +418,7 @@ namespace MWMechanics absorbed = (OEngine::Misc::Rng::roll0to99() < absorb); if (absorbed) { - const ESM::Static* absorbStatic = MWBase::Environment::get().getWorld()->getStore().get().find ("VFX_Absorb"); + //const ESM::Static* absorbStatic = MWBase::Environment::get().getWorld()->getStore().get().find ("VFX_Absorb"); //MWBase::Environment::get().getWorld()->getAnimation(target)->addEffect( // "meshes\\" + absorbStatic->mModel, ESM::MagicEffect::SpellAbsorption, false, ""); // Magicka is increased by cost of spell @@ -466,7 +466,7 @@ namespace MWMechanics bool isReflected = (OEngine::Misc::Rng::roll0to99() < reflect); if (isReflected) { - const ESM::Static* reflectStatic = MWBase::Environment::get().getWorld()->getStore().get().find ("VFX_Reflect"); + //const ESM::Static* reflectStatic = MWBase::Environment::get().getWorld()->getStore().get().find ("VFX_Reflect"); //MWBase::Environment::get().getWorld()->getAnimation(target)->addEffect( // "meshes\\" + reflectStatic->mModel, ESM::MagicEffect::Reflect, false, ""); reflectedEffects.mList.push_back(*effectIt); @@ -565,7 +565,7 @@ namespace MWMechanics } // Add VFX - const ESM::Static* castStatic; + /*const ESM::Static* castStatic; if (!magicEffect->mHit.empty()) castStatic = MWBase::Environment::get().getWorld()->getStore().get().find (magicEffect->mHit); else @@ -574,9 +574,10 @@ namespace MWMechanics // TODO: VFX are no longer active after saving/reloading the game bool loop = (magicEffect->mData.mFlags & ESM::MagicEffect::ContinuousVfx) != 0; // Note: in case of non actor, a free effect should be fine as well - //MWRender::Animation* anim = MWBase::Environment::get().getWorld()->getAnimation(target); - //if (anim) - // anim->addEffect("meshes\\" + castStatic->mModel, magicEffect->mIndex, loop, ""); + MWRender::Animation* anim = MWBase::Environment::get().getWorld()->getAnimation(target); + if (anim) + anim->addEffect("meshes\\" + castStatic->mModel, magicEffect->mIndex, loop, ""); + */ } } } diff --git a/apps/openmw/mwrender/actors.hpp b/apps/openmw/mwrender/actors.hpp index 887ea68d1..931c5bbd5 100644 --- a/apps/openmw/mwrender/actors.hpp +++ b/apps/openmw/mwrender/actors.hpp @@ -1,8 +1,6 @@ #ifndef GAME_RENDER_ACTORS_H #define GAME_RENDER_ACTORS_H -//#include - #include namespace OEngine diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 871561bdc..85d9546aa 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1,1551 +1,73 @@ #include "animation.hpp" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -#include "../mwbase/environment.hpp" -#include "../mwbase/soundmanager.hpp" -#include "../mwbase/world.hpp" - -#include "../mwmechanics/character.hpp" -#include "../mwmechanics/creaturestats.hpp" - -#include "../mwworld/class.hpp" -#include "../mwworld/fallback.hpp" -#include "../mwworld/cellstore.hpp" -#include "../mwworld/esmstore.hpp" - -#include "renderconst.hpp" +#include +#include +#include namespace MWRender { -Ogre::Real Animation::AnimationTime::getValue() const -{ - AnimStateMap::const_iterator iter = mAnimation->mStates.find(mAnimationName); - if(iter != mAnimation->mStates.end()) - return iter->second.mTime; - return 0.0f; -} - -void Animation::AnimationTime::setValue(Ogre::Real) -{ -} - -Ogre::Real Animation::EffectAnimationTime::getValue() const -{ - return mTime; -} - -void Animation::EffectAnimationTime::setValue(Ogre::Real) -{ -} - -Animation::Animation(const MWWorld::Ptr &ptr, Ogre::SceneNode *node) - : mPtr(ptr) - , mInsert(node) - , mSkelBase(NULL) - , mAccumRoot(NULL) - , mNonAccumRoot(NULL) - , mNonAccumCtrl(NULL) - , mAccumulate(0.0f) - , mNullAnimationTimePtr(OGRE_NEW NullAnimationTime) - , mGlowLight(NULL) -{ - for(size_t i = 0;i < sNumGroups;i++) - mAnimationTimePtr[i].bind(OGRE_NEW AnimationTime(this)); -} - -Animation::~Animation() -{ - setLightEffect(0); - - mEffects.clear(); - - mAnimSources.clear(); -} - -std::string Animation::getObjectRootName() const -{ - if (mSkelBase) - return mSkelBase->getMesh()->getName(); - return std::string(); -} - -void Animation::setObjectRoot(const std::string &model, bool baseonly) -{ - OgreAssert(mAnimSources.empty(), "Setting object root while animation sources are set!"); - - mSkelBase = NULL; - mObjectRoot.setNull(); - - if(model.empty()) - return; - - mObjectRoot = (!baseonly ? NifOgre::Loader::createObjects(mInsert, model) : - NifOgre::Loader::createObjectBase(mInsert, model)); - - if(mObjectRoot->mSkelBase) - { - mSkelBase = mObjectRoot->mSkelBase; - - Ogre::AnimationStateSet *aset = mObjectRoot->mSkelBase->getAllAnimationStates(); - Ogre::AnimationStateIterator asiter = aset->getAnimationStateIterator(); - while(asiter.hasMoreElements()) - { - Ogre::AnimationState *state = asiter.getNext(); - state->setEnabled(false); - state->setLoop(false); - } - - // Set the bones as manually controlled since we're applying the - // transformations manually - Ogre::SkeletonInstance *skelinst = mObjectRoot->mSkelBase->getSkeleton(); - Ogre::Skeleton::BoneIterator boneiter = skelinst->getBoneIterator(); - while(boneiter.hasMoreElements()) - boneiter.getNext()->setManuallyControlled(true); - - // Reattach any objects that have been attached to this one - ObjectAttachMap::iterator iter = mAttachedObjects.begin(); - while(iter != mAttachedObjects.end()) - { - if(!skelinst->hasBone(iter->second)) - mAttachedObjects.erase(iter++); - else - { - mSkelBase->attachObjectToBone(iter->second, iter->first); - ++iter; - } - } - } - else - mAttachedObjects.clear(); -} - -struct AddGlow -{ - Ogre::Vector3* mColor; - NifOgre::MaterialControllerManager* mMaterialControllerMgr; - AddGlow(Ogre::Vector3* col, NifOgre::MaterialControllerManager* materialControllerMgr) - : mColor(col) - , mMaterialControllerMgr(materialControllerMgr) - {} - - void operator()(Ogre::Entity* entity) const - { - if (!entity->getNumSubEntities()) - return; - Ogre::MaterialPtr writableMaterial = mMaterialControllerMgr->getWritableMaterial(entity); - sh::MaterialInstance* instance = sh::Factory::getInstance().getMaterialInstance(writableMaterial->getName()); - - instance->setProperty("env_map", sh::makeProperty(new sh::BooleanValue(true))); - instance->setProperty("env_map_color", sh::makeProperty(new sh::Vector3(mColor->x, mColor->y, mColor->z))); - // Workaround for crash in Ogre (https://bitbucket.org/sinbad/ogre/pull-request/447/fix-shadows-crash-for-textureunitstates/diff) - // Remove when the fix is merged - instance->getMaterial()->setShadowCasterMaterial("openmw_shadowcaster_noalpha"); - } -}; - -class VisQueueSet -{ - Ogre::uint32 mVisFlags; - Ogre::uint8 mSolidQueue, mTransQueue; - Ogre::Real mDist; - -public: - VisQueueSet(Ogre::uint32 visflags, Ogre::uint8 solidqueue, Ogre::uint8 transqueue, Ogre::Real dist) - : mVisFlags(visflags), mSolidQueue(solidqueue), mTransQueue(transqueue), mDist(dist) - { } - - void operator()(Ogre::Entity *entity) const - { - if(mVisFlags != 0) - entity->setVisibilityFlags(mVisFlags); - entity->setRenderingDistance(mDist); - - unsigned int numsubs = entity->getNumSubEntities(); - for(unsigned int i = 0;i < numsubs;++i) - { - Ogre::SubEntity* subEnt = entity->getSubEntity(i); - sh::Factory::getInstance()._ensureMaterial(subEnt->getMaterial()->getName(), "Default"); - subEnt->setRenderQueueGroup(subEnt->getMaterial()->isTransparent() ? mTransQueue : mSolidQueue); - } - } - - void operator()(Ogre::ParticleSystem *psys) const - { - if(mVisFlags != 0) - psys->setVisibilityFlags(mVisFlags); - psys->setRenderingDistance(mDist); - // TODO: Check particle material for actual transparency - psys->setRenderQueueGroup(mTransQueue); - } -}; - -void Animation::setRenderProperties(NifOgre::ObjectScenePtr objlist, Ogre::uint32 visflags, Ogre::uint8 solidqueue, Ogre::uint8 transqueue, Ogre::Real dist, bool enchantedGlow, Ogre::Vector3* glowColor) -{ - std::for_each(objlist->mEntities.begin(), objlist->mEntities.end(), - VisQueueSet(visflags, solidqueue, transqueue, dist)); - std::for_each(objlist->mParticles.begin(), objlist->mParticles.end(), - VisQueueSet(visflags, solidqueue, transqueue, dist)); - - if (enchantedGlow) - std::for_each(objlist->mEntities.begin(), objlist->mEntities.end(), - AddGlow(glowColor, &objlist->mMaterialControllerMgr)); -} - - -size_t Animation::detectAnimGroup(const Ogre::Node *node) -{ - static const char sGroupRoots[sNumGroups][32] = { - "", /* Lower body / character root */ - "Bip01 Spine1", /* Torso */ - "Bip01 L Clavicle", /* Left arm */ - "Bip01 R Clavicle", /* Right arm */ - }; - - while(node) - { - const Ogre::String &name = node->getName(); - for(size_t i = 1;i < sNumGroups;i++) - { - if(name == sGroupRoots[i]) - return i; - } - - node = node->getParent(); - } - - return 0; -} - - -void Animation::addAnimSource(const std::string &model) -{ - OgreAssert(mInsert, "Object is missing a root!"); - if(!mSkelBase) - return; - - std::string kfname = model; - Misc::StringUtils::toLower(kfname); - - if(kfname.size() > 4 && kfname.compare(kfname.size()-4, 4, ".nif") == 0) - kfname.replace(kfname.size()-4, 4, ".kf"); - - if(!Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(kfname)) - return; - - std::vector > ctrls; - Ogre::SharedPtr animsrc(OGRE_NEW AnimSource); - NifOgre::Loader::createKfControllers(mSkelBase, kfname, animsrc->mTextKeys, ctrls); - if(animsrc->mTextKeys.empty() || ctrls.empty()) - return; - - mAnimSources.push_back(animsrc); - - std::vector > *grpctrls = animsrc->mControllers; - for(size_t i = 0;i < ctrls.size();i++) - { - NifOgre::NodeTargetValue *dstval; - dstval = static_cast*>(ctrls[i].getDestination().getPointer()); - - size_t grp = detectAnimGroup(dstval->getNode()); - - if(!mAccumRoot && grp == 0) - { - mNonAccumRoot = dstval->getNode(); - mAccumRoot = mNonAccumRoot->getParent(); - if(!mAccumRoot) - { - std::cerr<< "Non-Accum root for "<getNode()->getName() == "Bip01" || dstval->getNode()->getName() == "Root Bone")) - { - mNonAccumRoot = dstval->getNode(); - mAccumRoot = mNonAccumRoot->getParent(); - if(!mAccumRoot) - { - std::cerr<< "Non-Accum root for "<mControllers.size(); ++i) - { - if (mObjectRoot->mControllers[i].getSource().isNull()) - mObjectRoot->mControllers[i].setSource(mAnimationTimePtr[0]); - } -} - -void Animation::clearAnimSources() -{ - mStates.clear(); - - for(size_t i = 0;i < sNumGroups;i++) - mAnimationTimePtr[i]->setAnimName(std::string()); - - mNonAccumCtrl = NULL; - - mAccumRoot = NULL; - mNonAccumRoot = NULL; - - mAnimSources.clear(); -} - - -void Animation::addExtraLight(Ogre::SceneManager *sceneMgr, NifOgre::ObjectScenePtr objlist, const ESM::Light *light) -{ - const MWWorld::Fallback *fallback = MWBase::Environment::get().getWorld()->getFallback(); - - const unsigned int clr = light->mData.mColor; - Ogre::ColourValue color(((clr >> 0) & 0xFF) / 255.0f, - ((clr >> 8) & 0xFF) / 255.0f, - ((clr >> 16) & 0xFF) / 255.0f); - const float radius = float(light->mData.mRadius); - - if((light->mData.mFlags&ESM::Light::Negative)) - color *= -1; - - objlist->mLights.push_back(sceneMgr->createLight()); - Ogre::Light *olight = objlist->mLights.back(); - olight->setDiffuseColour(color); - - Ogre::ControllerValueRealPtr src(Ogre::ControllerManager::getSingleton().getFrameTimeSource()); - Ogre::ControllerValueRealPtr dest(OGRE_NEW OEngine::Render::LightValue(olight, color)); - Ogre::ControllerFunctionRealPtr func(OGRE_NEW OEngine::Render::LightFunction( - (light->mData.mFlags&ESM::Light::Flicker) ? OEngine::Render::LT_Flicker : - (light->mData.mFlags&ESM::Light::FlickerSlow) ? OEngine::Render::LT_FlickerSlow : - (light->mData.mFlags&ESM::Light::Pulse) ? OEngine::Render::LT_Pulse : - (light->mData.mFlags&ESM::Light::PulseSlow) ? OEngine::Render::LT_PulseSlow : - OEngine::Render::LT_Normal - )); - objlist->mControllers.push_back(Ogre::Controller(src, dest, func)); - - bool interior = !(mPtr.isInCell() && mPtr.getCell()->getCell()->isExterior()); - - static bool outQuadInLin = fallback->getFallbackBool("LightAttenuation_OutQuadInLin"); - static bool useQuadratic = fallback->getFallbackBool("LightAttenuation_UseQuadratic"); - static float quadraticValue = fallback->getFallbackFloat("LightAttenuation_QuadraticValue"); - static float quadraticRadiusMult = fallback->getFallbackFloat("LightAttenuation_QuadraticRadiusMult"); - static bool useLinear = fallback->getFallbackBool("LightAttenuation_UseLinear"); - static float linearRadiusMult = fallback->getFallbackFloat("LightAttenuation_LinearRadiusMult"); - static float linearValue = fallback->getFallbackFloat("LightAttenuation_LinearValue"); - - bool quadratic = useQuadratic && (!outQuadInLin || !interior); - - - // with the standard 1 / (c + d*l + d*d*q) equation the attenuation factor never becomes zero, - // so we ignore lights if their attenuation falls below this factor. - const float threshold = 0.03f; - - float quadraticAttenuation = 0; - float linearAttenuation = 0; - float activationRange = 0; - if (quadratic) - { - float r = radius * quadraticRadiusMult; - quadraticAttenuation = quadraticValue / std::pow(r, 2); - activationRange = std::sqrt(1.0f / (threshold * quadraticAttenuation)); - } - if (useLinear) - { - float r = radius * linearRadiusMult; - linearAttenuation = linearValue / r; - activationRange = std::max(activationRange, 1.0f / (threshold * linearAttenuation)); - } - - olight->setAttenuation(activationRange, 0, linearAttenuation, quadraticAttenuation); - - // If there's an AttachLight bone, attach the light to that, otherwise put it in the center, - if(objlist->mSkelBase && objlist->mSkelBase->getSkeleton()->hasBone("AttachLight")) - objlist->mSkelBase->attachObjectToBone("AttachLight", olight); - else - { - Ogre::AxisAlignedBox bounds = Ogre::AxisAlignedBox::BOX_NULL; - for(size_t i = 0;i < objlist->mEntities.size();i++) - { - Ogre::Entity *ent = objlist->mEntities[i]; - bounds.merge(ent->getBoundingBox()); - } - - Ogre::SceneNode *node = bounds.isFinite() ? mInsert->createChildSceneNode(bounds.getCenter()) - : mInsert->createChildSceneNode(); - node->attachObject(olight); - } -} - - -Ogre::Node* Animation::getNode(const std::string &name) -{ - if(mSkelBase) - { - Ogre::SkeletonInstance *skel = mSkelBase->getSkeleton(); - if(skel->hasBone(name)) - return skel->getBone(name); - } - return NULL; -} - -Ogre::Node* Animation::getNode(int handle) -{ - if (mSkelBase) - { - Ogre::SkeletonInstance *skel = mSkelBase->getSkeleton(); - return skel->getBone(handle); - } - return NULL; -} - -NifOgre::TextKeyMap::const_iterator Animation::findGroupStart(const NifOgre::TextKeyMap &keys, const std::string &groupname) -{ - NifOgre::TextKeyMap::const_iterator iter(keys.begin()); - for(;iter != keys.end();++iter) - { - if(iter->second.compare(0, groupname.size(), groupname) == 0 && - iter->second.compare(groupname.size(), 2, ": ") == 0) - break; - } - return iter; -} - - -bool Animation::hasAnimation(const std::string &anim) -{ - AnimSourceList::const_iterator iter(mAnimSources.begin()); - for(;iter != mAnimSources.end();++iter) - { - const NifOgre::TextKeyMap &keys = (*iter)->mTextKeys; - if(findGroupStart(keys, anim) != keys.end()) - return true; - } - - return false; -} - - -void Animation::setAccumulation(const Ogre::Vector3 &accum) -{ - mAccumulate = accum; -} - - -void Animation::updatePtr(const MWWorld::Ptr &ptr) -{ - mPtr = ptr; -} - - -float Animation::calcAnimVelocity(const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue *nonaccumctrl, const Ogre::Vector3 &accum, const std::string &groupname) -{ - const std::string start = groupname+": start"; - const std::string loopstart = groupname+": loop start"; - const std::string loopstop = groupname+": loop stop"; - const std::string stop = groupname+": stop"; - float starttime = std::numeric_limits::max(); - float stoptime = 0.0f; - - // Pick the last Loop Stop key and the last Loop Start key. - // This is required because of broken text keys in AshVampire.nif. - // It has *two* WalkForward: Loop Stop keys at different times, the first one is used for stopping playback - // but the animation velocity calculation uses the second one. - // As result the animation velocity calculation is not correct, and this incorrect velocity must be replicated, - // because otherwise the Creature's Speed (dagoth uthol) would not be sufficient to move fast enough. - NifOgre::TextKeyMap::const_reverse_iterator keyiter(keys.rbegin()); - while(keyiter != keys.rend()) - { - if(keyiter->second == start || keyiter->second == loopstart) - { - starttime = keyiter->first; - break; - } - ++keyiter; - } - keyiter = keys.rbegin(); - while(keyiter != keys.rend()) - { - if (keyiter->second == stop) - stoptime = keyiter->first; - else if (keyiter->second == loopstop) - { - stoptime = keyiter->first; - break; - } - ++keyiter; - } - - if(stoptime > starttime) - { - Ogre::Vector3 startpos = nonaccumctrl->getTranslation(starttime) * accum; - Ogre::Vector3 endpos = nonaccumctrl->getTranslation(stoptime) * accum; - - return startpos.distance(endpos) / (stoptime - starttime); - } - - return 0.0f; -} - -float Animation::getVelocity(const std::string &groupname) const -{ - /* Look in reverse; last-inserted source has priority. */ - AnimSourceList::const_reverse_iterator animsrc(mAnimSources.rbegin()); - for(;animsrc != mAnimSources.rend();++animsrc) - { - const NifOgre::TextKeyMap &keys = (*animsrc)->mTextKeys; - if(findGroupStart(keys, groupname) != keys.end()) - break; - } - if(animsrc == mAnimSources.rend()) - return 0.0f; - - float velocity = 0.0f; - const NifOgre::TextKeyMap &keys = (*animsrc)->mTextKeys; - const std::vector >&ctrls = (*animsrc)->mControllers[0]; - for(size_t i = 0;i < ctrls.size();i++) - { - NifOgre::NodeTargetValue *dstval; - dstval = static_cast*>(ctrls[i].getDestination().getPointer()); - if(dstval->getNode() == mNonAccumRoot) - { - velocity = calcAnimVelocity(keys, dstval, mAccumulate, groupname); - break; - } - } - - // If there's no velocity, keep looking - if(!(velocity > 1.0f)) - { - AnimSourceList::const_reverse_iterator animiter = mAnimSources.rbegin(); - while(*animiter != *animsrc) - ++animiter; - - while(!(velocity > 1.0f) && ++animiter != mAnimSources.rend()) - { - const NifOgre::TextKeyMap &keys = (*animiter)->mTextKeys; - const std::vector >&ctrls = (*animiter)->mControllers[0]; - for(size_t i = 0;i < ctrls.size();i++) - { - NifOgre::NodeTargetValue *dstval; - dstval = static_cast*>(ctrls[i].getDestination().getPointer()); - if(dstval->getNode() == mNonAccumRoot) - { - velocity = calcAnimVelocity(keys, dstval, mAccumulate, groupname); - break; - } - } - } - } - - return velocity; -} - - -static void updateBoneTree(const Ogre::SkeletonInstance *skelsrc, Ogre::Bone *bone) -{ - if(bone->getName() != " " // really should be != "", but see workaround in skeleton.cpp for empty node names - && skelsrc->hasBone(bone->getName())) - { - Ogre::Bone *srcbone = skelsrc->getBone(bone->getName()); - if(!srcbone->getParent() || !bone->getParent()) - { - bone->setOrientation(srcbone->getOrientation()); - bone->setPosition(srcbone->getPosition()); - bone->setScale(srcbone->getScale()); - } - else - { - bone->_setDerivedOrientation(srcbone->_getDerivedOrientation()); - bone->_setDerivedPosition(srcbone->_getDerivedPosition()); - bone->setScale(Ogre::Vector3::UNIT_SCALE); - } - } - - Ogre::Node::ChildNodeIterator boneiter = bone->getChildIterator(); - while(boneiter.hasMoreElements()) - updateBoneTree(skelsrc, static_cast(boneiter.getNext())); -} - -void Animation::updateSkeletonInstance(const Ogre::SkeletonInstance *skelsrc, Ogre::SkeletonInstance *skel) -{ - Ogre::Skeleton::BoneIterator boneiter = skel->getRootBoneIterator(); - while(boneiter.hasMoreElements()) - updateBoneTree(skelsrc, boneiter.getNext()); -} - - -void Animation::updatePosition(float oldtime, float newtime, Ogre::Vector3 &position) -{ - /* Get the non-accumulation root's difference from the last update, and move the position - * accordingly. - */ - Ogre::Vector3 off = mNonAccumCtrl->getTranslation(newtime)*mAccumulate; - position += off - mNonAccumCtrl->getTranslation(oldtime)*mAccumulate; - - /* Translate the accumulation root back to compensate for the move. */ - mAccumRoot->setPosition(-off); -} - -bool Animation::reset(AnimState &state, const NifOgre::TextKeyMap &keys, const std::string &groupname, const std::string &start, const std::string &stop, float startpoint, bool loopfallback) -{ - // Look for text keys in reverse. This normally wouldn't matter, but for some reason undeadwolf_2.nif has two - // separate walkforward keys, and the last one is supposed to be used. - NifOgre::TextKeyMap::const_reverse_iterator groupend(keys.rbegin()); - for(;groupend != keys.rend();++groupend) - { - if(groupend->second.compare(0, groupname.size(), groupname) == 0 && - groupend->second.compare(groupname.size(), 2, ": ") == 0) - break; - } - - std::string starttag = groupname+": "+start; - NifOgre::TextKeyMap::const_reverse_iterator startkey(groupend); - while(startkey != keys.rend() && startkey->second != starttag) - ++startkey; - if(startkey == keys.rend() && start == "loop start") - { - starttag = groupname+": start"; - startkey = groupend; - while(startkey != keys.rend() && startkey->second != starttag) - ++startkey; - } - if(startkey == keys.rend()) - return false; - - const std::string stoptag = groupname+": "+stop; - NifOgre::TextKeyMap::const_reverse_iterator stopkey(groupend); - while(stopkey != keys.rend() - // We have to ignore extra garbage at the end. - // The Scrib's idle3 animation has "Idle3: Stop." instead of "Idle3: Stop". - // Why, just why? :( - && (stopkey->second.size() < stoptag.size() || stopkey->second.substr(0,stoptag.size()) != stoptag)) - ++stopkey; - if(stopkey == keys.rend()) - return false; - - if(startkey->first > stopkey->first) - return false; - - state.mStartTime = startkey->first; - if (loopfallback) - { - state.mLoopStartTime = startkey->first; - state.mLoopStopTime = stopkey->first; - } - else - { - state.mLoopStartTime = startkey->first; - state.mLoopStopTime = std::numeric_limits::max(); - } - state.mStopTime = stopkey->first; - - state.mTime = state.mStartTime + ((state.mStopTime - state.mStartTime) * startpoint); - - // mLoopStartTime and mLoopStopTime normally get assigned when encountering these keys while playing the animation - // (see handleTextKey). But if startpoint is already past these keys, we need to assign them now. - if(state.mTime > state.mStartTime) - { - const std::string loopstarttag = groupname+": loop start"; - const std::string loopstoptag = groupname+": loop stop"; - - NifOgre::TextKeyMap::const_reverse_iterator key(groupend); - for (; key != startkey && key != keys.rend(); ++key) - { - if (key->first > state.mTime) - continue; - - if (key->second == loopstarttag) - state.mLoopStartTime = key->first; - else if (key->second == loopstoptag) - state.mLoopStopTime = key->first; - } - } - - return true; -} - -void split(const std::string &s, char delim, std::vector &elems) { - std::stringstream ss(s); - std::string item; - while (std::getline(ss, item, delim)) { - elems.push_back(item); - } -} - -void Animation::handleTextKey(AnimState &state, const std::string &groupname, const NifOgre::TextKeyMap::const_iterator &key, - const NifOgre::TextKeyMap& textkeys) -{ - //float time = key->first; - const std::string &evt = key->second; - - if(evt.compare(0, 7, "sound: ") == 0) - { - MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); - sndMgr->playSound3D(mPtr, evt.substr(7), 1.0f, 1.0f); - return; - } - if(evt.compare(0, 10, "soundgen: ") == 0) - { - std::string soundgen = evt.substr(10); - - // The event can optionally contain volume and pitch modifiers - float volume=1.f, pitch=1.f; - if (soundgen.find(" ") != std::string::npos) - { - std::vector tokens; - split(soundgen, ' ', tokens); - soundgen = tokens[0]; - if (tokens.size() >= 2) - volume = Ogre::StringConverter::parseReal(tokens[1]); - if (tokens.size() >= 3) - pitch = Ogre::StringConverter::parseReal(tokens[2]); - } - - std::string sound = mPtr.getClass().getSoundIdFromSndGen(mPtr, soundgen); - if(!sound.empty()) - { - MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); - MWBase::SoundManager::PlayType type = MWBase::SoundManager::Play_TypeSfx; - if(evt.compare(10, evt.size()-10, "left") == 0 || evt.compare(10, evt.size()-10, "right") == 0 || evt.compare(10, evt.size()-10, "land") == 0) - type = MWBase::SoundManager::Play_TypeFoot; - sndMgr->playSound3D(mPtr, sound, volume, pitch, type); - } - return; - } - - if(evt.compare(0, groupname.size(), groupname) != 0 || - evt.compare(groupname.size(), 2, ": ") != 0) - { - // Not ours, skip it - return; - } - size_t off = groupname.size()+2; - size_t len = evt.size() - off; - - if(evt.compare(off, len, "loop start") == 0) - state.mLoopStartTime = key->first; - else if(evt.compare(off, len, "loop stop") == 0) - state.mLoopStopTime = key->first; - else if(evt.compare(off, len, "equip attach") == 0) - showWeapons(true); - else if(evt.compare(off, len, "unequip detach") == 0) - showWeapons(false); - else if(evt.compare(off, len, "chop hit") == 0) - mPtr.getClass().hit(mPtr, ESM::Weapon::AT_Chop); - else if(evt.compare(off, len, "slash hit") == 0) - mPtr.getClass().hit(mPtr, ESM::Weapon::AT_Slash); - else if(evt.compare(off, len, "thrust hit") == 0) - mPtr.getClass().hit(mPtr, ESM::Weapon::AT_Thrust); - else if(evt.compare(off, len, "hit") == 0) - { - if (groupname == "attack1") - mPtr.getClass().hit(mPtr, ESM::Weapon::AT_Chop); - else if (groupname == "attack2") - mPtr.getClass().hit(mPtr, ESM::Weapon::AT_Slash); - else if (groupname == "attack3") - mPtr.getClass().hit(mPtr, ESM::Weapon::AT_Thrust); - else - mPtr.getClass().hit(mPtr); - } - else if (!groupname.empty() && groupname.compare(0, groupname.size()-1, "attack") == 0 - && evt.compare(off, len, "start") == 0) - { - NifOgre::TextKeyMap::const_iterator hitKey = key; - - // Not all animations have a hit key defined. If there is none, the hit happens with the start key. - bool hasHitKey = false; - while (hitKey != textkeys.end()) - { - if (hitKey->second == groupname + ": hit") - { - hasHitKey = true; - break; - } - if (hitKey->second == groupname + ": stop") - break; - ++hitKey; - } - if (!hasHitKey) - { - if (groupname == "attack1") - mPtr.getClass().hit(mPtr, ESM::Weapon::AT_Chop); - else if (groupname == "attack2") - mPtr.getClass().hit(mPtr, ESM::Weapon::AT_Slash); - else if (groupname == "attack3") - mPtr.getClass().hit(mPtr, ESM::Weapon::AT_Thrust); - } - } - else if (evt.compare(off, len, "shoot attach") == 0) - attachArrow(); - else if (evt.compare(off, len, "shoot release") == 0) - releaseArrow(); - else if (evt.compare(off, len, "shoot follow attach") == 0) - attachArrow(); - - else if (groupname == "spellcast" && evt.substr(evt.size()-7, 7) == "release") - { - // Make sure this key is actually for the RangeType we are casting. The flame atronach has - // the same animation for all range types, so there are 3 "release" keys on the same time, one for each range type. - // FIXME: This logic should really be in the CharacterController - const std::string& spellid = mPtr.getClass().getCreatureStats(mPtr).getSpells().getSelectedSpell(); - const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get().find(spellid); - const ESM::ENAMstruct &effectentry = spell->mEffects.mList.at(0); - int range = 0; - if (evt.compare(off, len, "self release") == 0) - range = 0; - else if (evt.compare(off, len, "touch release") == 0) - range = 1; - else if (evt.compare(off, len, "target release") == 0) - range = 2; - if (effectentry.mRange == range) - { - MWBase::Environment::get().getWorld()->castSpell(mPtr); - } - } - - else if (groupname == "shield" && evt.compare(off, len, "block hit") == 0) - mPtr.getClass().block(mPtr); -} - -void Animation::changeGroups(const std::string &groupname, int groups) -{ - AnimStateMap::iterator stateiter = mStates.find(groupname); - if(stateiter != mStates.end()) - { - if(stateiter->second.mGroups != groups) - { - stateiter->second.mGroups = groups; - resetActiveGroups(); - } - return; - } -} - -void Animation::stopLooping(const std::string& groupname) -{ - AnimStateMap::iterator stateiter = mStates.find(groupname); - if(stateiter != mStates.end()) - { - stateiter->second.mLoopCount = 0; - return; - } -} - -void Animation::play(const std::string &groupname, int priority, int groups, bool autodisable, float speedmult, const std::string &start, const std::string &stop, float startpoint, size_t loops, bool loopfallback) -{ - if(!mSkelBase || mAnimSources.empty()) - return; - - if(groupname.empty()) - { - resetActiveGroups(); - return; - } - - priority = std::max(0, priority); - - AnimStateMap::iterator stateiter = mStates.begin(); - while(stateiter != mStates.end()) - { - if(stateiter->second.mPriority == priority) - mStates.erase(stateiter++); - else - ++stateiter; - } - - stateiter = mStates.find(groupname); - if(stateiter != mStates.end()) - { - stateiter->second.mPriority = priority; - resetActiveGroups(); - return; - } - - /* Look in reverse; last-inserted source has priority. */ - AnimState state; - AnimSourceList::reverse_iterator iter(mAnimSources.rbegin()); - for(;iter != mAnimSources.rend();++iter) + Animation::Animation(const MWWorld::Ptr &ptr, osg::ref_ptr node, Resource::ResourceSystem* resourceSystem) + : mPtr(ptr) + , mInsert(node) + , mResourceSystem(resourceSystem) { - const NifOgre::TextKeyMap &textkeys = (*iter)->mTextKeys; - if(reset(state, textkeys, groupname, start, stop, startpoint, loopfallback)) - { - state.mSource = *iter; - state.mSpeedMult = speedmult; - state.mLoopCount = loops; - state.mPlaying = (state.mTime < state.mStopTime); - state.mPriority = priority; - state.mGroups = groups; - state.mAutoDisable = autodisable; - mStates[groupname] = state; - - NifOgre::TextKeyMap::const_iterator textkey(textkeys.lower_bound(state.mTime)); - if (state.mPlaying) - { - while(textkey != textkeys.end() && textkey->first <= state.mTime) - { - handleTextKey(state, groupname, textkey, textkeys); - ++textkey; - } - } - - if(state.mTime >= state.mLoopStopTime && state.mLoopCount > 0) - { - state.mLoopCount--; - state.mTime = state.mLoopStartTime; - state.mPlaying = true; - if(state.mTime >= state.mLoopStopTime) - break; - - NifOgre::TextKeyMap::const_iterator textkey(textkeys.lower_bound(state.mTime)); - while(textkey != textkeys.end() && textkey->first <= state.mTime) - { - handleTextKey(state, groupname, textkey, textkeys); - ++textkey; - } - } - - break; - } - } - if(iter == mAnimSources.rend()) - std::cerr<< "Failed to find animation "<setPosition(-mNonAccumCtrl->getTranslation(state.mTime)*mAccumulate); } -} - -void Animation::adjustSpeedMult(const std::string &groupname, float speedmult) -{ - AnimStateMap::iterator state(mStates.find(groupname)); - if(state != mStates.end()) - state->second.mSpeedMult = speedmult; -} - -bool Animation::isPlaying(const std::string &groupname) const -{ - AnimStateMap::const_iterator state(mStates.find(groupname)); - if(state != mStates.end()) - return state->second.mPlaying; - return false; -} -void Animation::resetActiveGroups() -{ - for(size_t grp = 0;grp < sNumGroups;grp++) + Animation::~Animation() { - AnimStateMap::const_iterator active = mStates.end(); - - AnimStateMap::const_iterator state = mStates.begin(); - for(;state != mStates.end();++state) - { - if(!(state->second.mGroups&(1<second.mPriority < state->second.mPriority) - active = state; - } - - mAnimationTimePtr[grp]->setAnimName((active == mStates.end()) ? - std::string() : active->first); + if (mObjectRoot) + mInsert->removeChild(mObjectRoot); } - mNonAccumCtrl = NULL; - - if(!mNonAccumRoot || mAccumulate == Ogre::Vector3(0.0f)) - return; - AnimStateMap::const_iterator state = mStates.find(mAnimationTimePtr[0]->getAnimName()); - if(state == mStates.end()) + osg::Vec3f Animation::runAnimation(float duration) { - if (mAccumRoot && mNonAccumRoot) - mAccumRoot->setPosition(-mNonAccumRoot->getPosition()*mAccumulate); - return; + return osg::Vec3f(); } - const Ogre::SharedPtr &animsrc = state->second.mSource; - const std::vector >&ctrls = animsrc->mControllers[0]; - for(size_t i = 0;i < ctrls.size();i++) + void Animation::setObjectRoot(const std::string &model) { - NifOgre::NodeTargetValue *dstval; - dstval = static_cast*>(ctrls[i].getDestination().getPointer()); - if(dstval->getNode() == mNonAccumRoot) + if (mObjectRoot) { - mNonAccumCtrl = dstval; - break; + mObjectRoot->getParent(0)->removeChild(mObjectRoot); } - } - - if (mAccumRoot && mNonAccumCtrl) - mAccumRoot->setPosition(-mNonAccumCtrl->getTranslation(state->second.mTime)*mAccumulate); -} - - -bool Animation::getInfo(const std::string &groupname, float *complete, float *speedmult) const -{ - AnimStateMap::const_iterator iter = mStates.find(groupname); - if(iter == mStates.end()) - { - if(complete) *complete = 0.0f; - if(speedmult) *speedmult = 0.0f; - return false; - } - if(complete) - { - if(iter->second.mStopTime > iter->second.mStartTime) - *complete = (iter->second.mTime - iter->second.mStartTime) / - (iter->second.mStopTime - iter->second.mStartTime); - else - *complete = (iter->second.mPlaying ? 0.0f : 1.0f); + mObjectRoot = mResourceSystem->getSceneManager()->createInstance(model, mInsert); } - if(speedmult) *speedmult = iter->second.mSpeedMult; - return true; -} -float Animation::getStartTime(const std::string &groupname) const -{ - for(AnimSourceList::const_iterator iter(mAnimSources.begin()); iter != mAnimSources.end(); ++iter) + osg::Group* Animation::getObjectRoot() { - const NifOgre::TextKeyMap &keys = (*iter)->mTextKeys; - - NifOgre::TextKeyMap::const_iterator found = findGroupStart(keys, groupname); - if(found != keys.end()) - return found->first; + return static_cast(mObjectRoot.get()); } - return -1.f; -} -float Animation::getTextKeyTime(const std::string &textKey) const -{ - for(AnimSourceList::const_iterator iter(mAnimSources.begin()); iter != mAnimSources.end(); ++iter) + osg::Group* Animation::getOrCreateObjectRoot() { - const NifOgre::TextKeyMap &keys = (*iter)->mTextKeys; + if (mObjectRoot) + return static_cast(mObjectRoot.get()); - for(NifOgre::TextKeyMap::const_iterator iterKey(keys.begin()); iterKey != keys.end(); ++iterKey) - { - if(iterKey->second.compare(0, textKey.size(), textKey) == 0) - return iterKey->first; - } + mObjectRoot = new osg::Group; + mInsert->addChild(mObjectRoot); + return static_cast(mObjectRoot.get()); } - return -1.f; -} - -float Animation::getCurrentTime(const std::string &groupname) const -{ - AnimStateMap::const_iterator iter = mStates.find(groupname); - if(iter == mStates.end()) - return -1.f; - - return iter->second.mTime; -} - -void Animation::disable(const std::string &groupname) -{ - AnimStateMap::iterator iter = mStates.find(groupname); - if(iter != mStates.end()) - mStates.erase(iter); - resetActiveGroups(); -} - + // -------------------------------------------------------------------------------- -Ogre::Vector3 Animation::runAnimation(float duration) -{ - Ogre::Vector3 movement(0.0f); - AnimStateMap::iterator stateiter = mStates.begin(); - while(stateiter != mStates.end()) + ObjectAnimation::ObjectAnimation(const MWWorld::Ptr &ptr, const std::string &model, Resource::ResourceSystem* resourceSystem) + : Animation(ptr, osg::ref_ptr(ptr.getRefData().getBaseNode()), resourceSystem) { - AnimState &state = stateiter->second; - const NifOgre::TextKeyMap &textkeys = state.mSource->mTextKeys; - NifOgre::TextKeyMap::const_iterator textkey(textkeys.upper_bound(state.mTime)); - - float timepassed = duration * state.mSpeedMult; - while(state.mPlaying) - { - float targetTime; - - if(state.mTime >= state.mLoopStopTime && state.mLoopCount > 0) - goto handle_loop; - - targetTime = state.mTime + timepassed; - if(textkey == textkeys.end() || textkey->first > targetTime) - { - if(mNonAccumCtrl && stateiter->first == mAnimationTimePtr[0]->getAnimName()) - updatePosition(state.mTime, targetTime, movement); - state.mTime = std::min(targetTime, state.mStopTime); - } - else - { - if(mNonAccumCtrl && stateiter->first == mAnimationTimePtr[0]->getAnimName()) - updatePosition(state.mTime, textkey->first, movement); - state.mTime = textkey->first; - } - - state.mPlaying = (state.mTime < state.mStopTime); - timepassed = targetTime - state.mTime; - - while(textkey != textkeys.end() && textkey->first <= state.mTime) - { - handleTextKey(state, stateiter->first, textkey, textkeys); - ++textkey; - } - - if(state.mTime >= state.mLoopStopTime && state.mLoopCount > 0) - { - handle_loop: - state.mLoopCount--; - state.mTime = state.mLoopStartTime; - state.mPlaying = true; - - textkey = textkeys.lower_bound(state.mTime); - while(textkey != textkeys.end() && textkey->first <= state.mTime) - { - handleTextKey(state, stateiter->first, textkey, textkeys); - ++textkey; - } - - if(state.mTime >= state.mLoopStopTime) - break; - } - - if(timepassed <= 0.0f) - break; - } - - if(!state.mPlaying && state.mAutoDisable) + if (!model.empty()) { - mStates.erase(stateiter++); - - resetActiveGroups(); + setObjectRoot(model); } else - ++stateiter; - } - - for(size_t i = 0;i < mObjectRoot->mControllers.size();i++) - { - if(!mObjectRoot->mControllers[i].getSource().isNull()) - mObjectRoot->mControllers[i].update(); - } - - // Apply group controllers - for(size_t grp = 0;grp < sNumGroups;grp++) - { - const std::string &name = mAnimationTimePtr[grp]->getAnimName(); - if(!name.empty() && (stateiter=mStates.find(name)) != mStates.end()) - { - const Ogre::SharedPtr &src = stateiter->second.mSource; - for(size_t i = 0;i < src->mControllers[grp].size();i++) - src->mControllers[grp][i].update(); - } - } - - if(mSkelBase) - { - // HACK: Dirty the animation state set so that Ogre will apply the - // transformations to entities this skeleton instance is shared with. - mSkelBase->getAllAnimationStates()->_notifyDirty(); - } - - updateEffects(duration); - - return movement; -} - -void Animation::showWeapons(bool showWeapon) -{ -} - - -class ToggleLight { - bool mEnable; - -public: - ToggleLight(bool enable) : mEnable(enable) { } - - void operator()(Ogre::Light *light) const - { light->setVisible(mEnable); } -}; - -void Animation::enableLights(bool enable) -{ - std::for_each(mObjectRoot->mLights.begin(), mObjectRoot->mLights.end(), ToggleLight(enable)); -} - - -class MergeBounds { - Ogre::AxisAlignedBox *mBounds; - -public: - MergeBounds(Ogre::AxisAlignedBox *bounds) : mBounds(bounds) { } - - void operator()(Ogre::MovableObject *obj) - { - mBounds->merge(obj->getWorldBoundingBox(true)); - } -}; - -Ogre::AxisAlignedBox Animation::getWorldBounds() -{ - Ogre::AxisAlignedBox bounds = Ogre::AxisAlignedBox::BOX_NULL; - std::for_each(mObjectRoot->mEntities.begin(), mObjectRoot->mEntities.end(), MergeBounds(&bounds)); - return bounds; -} - - -Ogre::TagPoint *Animation::attachObjectToBone(const Ogre::String &bonename, Ogre::MovableObject *obj) -{ - Ogre::TagPoint *tag = NULL; - Ogre::SkeletonInstance *skel = (mSkelBase ? mSkelBase->getSkeleton() : NULL); - if(skel && skel->hasBone(bonename)) - { - tag = mSkelBase->attachObjectToBone(bonename, obj); - mAttachedObjects[obj] = bonename; - } - return tag; -} - -void Animation::detachObjectFromBone(Ogre::MovableObject *obj) -{ - ObjectAttachMap::iterator iter = mAttachedObjects.find(obj); - if(iter != mAttachedObjects.end()) - mAttachedObjects.erase(iter); - mSkelBase->detachObjectFromBone(obj); -} - -bool Animation::upperBodyReady() const -{ - for (AnimStateMap::const_iterator stateiter = mStates.begin(); stateiter != mStates.end(); ++stateiter) - { - if((stateiter->second.mPriority > MWMechanics::Priority_Movement - && stateiter->second.mPriority < MWMechanics::Priority_Torch) - || stateiter->second.mPriority == MWMechanics::Priority_Death) - return false; - } - return true; -} - -void Animation::addEffect(const std::string &model, int effectId, bool loop, const std::string &bonename, std::string texture) -{ - // Early out if we already have this effect - for (std::vector::iterator it = mEffects.begin(); it != mEffects.end(); ++it) - if (it->mLoop && loop && it->mEffectId == effectId && it->mBoneName == bonename) - return; - - std::string correctedTexture = Misc::ResourceHelpers::correctTexturePath(texture); - - EffectParams params; - params.mModelName = model; - if (bonename.empty()) - params.mObjects = NifOgre::Loader::createObjects(mInsert, model); - else - { - if (!mSkelBase) - return; - params.mObjects = NifOgre::Loader::createObjects(mSkelBase, bonename, "", mInsert, model); - } - - setRenderProperties(params.mObjects, RV_Effects, - RQG_Main, RQG_Alpha, 0.f, false, NULL); - - params.mLoop = loop; - params.mEffectId = effectId; - params.mBoneName = bonename; - - for(size_t i = 0;i < params.mObjects->mControllers.size();i++) - { - if(params.mObjects->mControllers[i].getSource().isNull()) - params.mObjects->mControllers[i].setSource(Ogre::SharedPtr (new EffectAnimationTime())); - } - - - // Do some manual adjustments on the created entities/particle systems - - // It looks like vanilla MW totally ignores lighting settings for effects attached to characters. - // If we don't do this, some effects will look way too dark depending on the environment - // (e.g. magic_cast_dst.nif). They were clearly meant to use emissive lighting. - // We used to have this hack in the NIF material loader, but for effects not attached to characters - // (e.g. ash storms) the lighting settings do seem to be in use. Is there maybe a flag we have missed? - Ogre::ColourValue ambient = Ogre::ColourValue(0.f, 0.f, 0.f); - Ogre::ColourValue diffuse = Ogre::ColourValue(0.f, 0.f, 0.f); - Ogre::ColourValue specular = Ogre::ColourValue(0.f, 0.f, 0.f); - Ogre::ColourValue emissive = Ogre::ColourValue(1.f, 1.f, 1.f); - for(size_t i = 0;i < params.mObjects->mParticles.size(); ++i) - { - Ogre::ParticleSystem* partSys = params.mObjects->mParticles[i]; - - Ogre::MaterialPtr mat = params.mObjects->mMaterialControllerMgr.getWritableMaterial(partSys); - - for (int t=0; tgetNumTechniques(); ++t) - { - Ogre::Technique* tech = mat->getTechnique(t); - for (int p=0; pgetNumPasses(); ++p) - { - Ogre::Pass* pass = tech->getPass(p); - - pass->setAmbient(ambient); - pass->setDiffuse(diffuse); - pass->setSpecular(specular); - pass->setEmissive(emissive); - - if (!texture.empty()) - { - for (int tex=0; texgetNumTextureUnitStates(); ++tex) - { - Ogre::TextureUnitState* tus = pass->getTextureUnitState(tex); - tus->setTextureName(correctedTexture); - } - } - } - } - } - for(size_t i = 0;i < params.mObjects->mEntities.size(); ++i) - { - Ogre::Entity* ent = params.mObjects->mEntities[i]; - if (ent == params.mObjects->mSkelBase) - continue; - Ogre::MaterialPtr mat = params.mObjects->mMaterialControllerMgr.getWritableMaterial(ent); - - for (int t=0; tgetNumTechniques(); ++t) - { - Ogre::Technique* tech = mat->getTechnique(t); - for (int p=0; pgetNumPasses(); ++p) - { - Ogre::Pass* pass = tech->getPass(p); - - pass->setAmbient(ambient); - pass->setDiffuse(diffuse); - pass->setSpecular(specular); - pass->setEmissive(emissive); - - if (!texture.empty()) - { - for (int tex=0; texgetNumTextureUnitStates(); ++tex) - { - Ogre::TextureUnitState* tus = pass->getTextureUnitState(tex); - tus->setTextureName(correctedTexture); - } - } - } - } - } - - mEffects.push_back(params); -} - -void Animation::removeEffect(int effectId) -{ - for (std::vector::iterator it = mEffects.begin(); it != mEffects.end(); ++it) - { - if (it->mEffectId == effectId) - { - mEffects.erase(it); - return; - } - } -} - -void Animation::getLoopingEffects(std::vector &out) -{ - for (std::vector::iterator it = mEffects.begin(); it != mEffects.end(); ++it) - { - if (it->mLoop) - out.push_back(it->mEffectId); - } -} - -void Animation::updateEffects(float duration) -{ - for (std::vector::iterator it = mEffects.begin(); it != mEffects.end(); ) - { - NifOgre::ObjectScenePtr objects = it->mObjects; - for(size_t i = 0; i < objects->mControllers.size() ;i++) - { - EffectAnimationTime* value = dynamic_cast(objects->mControllers[i].getSource().get()); - if (value) - value->addTime(duration); - - objects->mControllers[i].update(); - } - - if (objects->mControllers[0].getSource()->getValue() >= objects->mMaxControllerLength) - { - if (it->mLoop) - { - // Start from the beginning again; carry over the remainder - float remainder = objects->mControllers[0].getSource()->getValue() - objects->mMaxControllerLength; - for(size_t i = 0; i < objects->mControllers.size() ;i++) - { - EffectAnimationTime* value = dynamic_cast(objects->mControllers[i].getSource().get()); - if (value) - value->resetTime(remainder); - } - } - else - { - it = mEffects.erase(it); - continue; - } - } - ++it; - } -} - -void Animation::preRender(Ogre::Camera *camera) -{ - for (std::vector::iterator it = mEffects.begin(); it != mEffects.end(); ++it) - { - NifOgre::ObjectScenePtr objects = it->mObjects; - objects->rotateBillboardNodes(camera); - } - mObjectRoot->rotateBillboardNodes(camera); -} - -// TODO: Should not be here -Ogre::Vector3 Animation::getEnchantmentColor(MWWorld::Ptr item) -{ - Ogre::Vector3 result(1,1,1); - std::string enchantmentName = item.getClass().getEnchantment(item); - if (enchantmentName.empty()) - return result; - const ESM::Enchantment* enchantment = MWBase::Environment::get().getWorld()->getStore().get().find(enchantmentName); - assert (enchantment->mEffects.mList.size()); - const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get().find( - enchantment->mEffects.mList.front().mEffectID); - result.x = magicEffect->mData.mRed / 255.f; - result.y = magicEffect->mData.mGreen / 255.f; - result.z = magicEffect->mData.mBlue / 255.f; - return result; -} - -void Animation::setLightEffect(float effect) -{ - if (effect == 0) - { - if (mGlowLight) - { - mInsert->getCreator()->destroySceneNode(mGlowLight->getParentSceneNode()); - mInsert->getCreator()->destroyLight(mGlowLight); - mGlowLight = NULL; - } - } - else - { - if (!mGlowLight) - { - mGlowLight = mInsert->getCreator()->createLight(); - - Ogre::AxisAlignedBox bounds = Ogre::AxisAlignedBox::BOX_NULL; - for(size_t i = 0;i < mObjectRoot->mEntities.size();i++) - { - Ogre::Entity *ent = mObjectRoot->mEntities[i]; - bounds.merge(ent->getBoundingBox()); - } - mInsert->createChildSceneNode(bounds.getCenter())->attachObject(mGlowLight); - } - mGlowLight->setType(Ogre::Light::LT_POINT); - effect += 3; - mGlowLight->setAttenuation(1.0f / (0.03f * (0.5f/effect)), 0, 0.5f/effect, 0); - } -} - - -ObjectAnimation::ObjectAnimation(const MWWorld::Ptr& ptr, const std::string &model) - : Animation(ptr, ptr.getRefData().getBaseNode()) -{ - if (!model.empty()) - { - setObjectRoot(model, false); - - Ogre::Vector3 extents = getWorldBounds().getSize(); - float size = std::max(std::max(extents.x, extents.y), extents.z); - - bool small = (size < Settings::Manager::getInt("small object size", "Viewing distance")) && - Settings::Manager::getBool("limit small object distance", "Viewing distance"); - // do not fade out doors. that will cause holes and look stupid - if(ptr.getTypeName().find("Door") != std::string::npos) - small = false; - - float dist = small ? Settings::Manager::getInt("small object distance", "Viewing distance") : 0.0f; - Ogre::Vector3 col = getEnchantmentColor(ptr); - setRenderProperties(mObjectRoot, (mPtr.getTypeName() == typeid(ESM::Static).name()) ? - (small ? RV_StaticsSmall : RV_Statics) : RV_Misc, - RQG_Main, RQG_Alpha, dist, !ptr.getClass().getEnchantment(ptr).empty(), &col); - } - else - { - // No model given. Create an object root anyway, so that lights can be added to it if needed. - mObjectRoot = NifOgre::ObjectScenePtr (new NifOgre::ObjectScene(mInsert->getCreator())); - } -} - - -class FindEntityTransparency { -public: - bool operator()(Ogre::Entity *ent) const - { - unsigned int numsubs = ent->getNumSubEntities(); - for(unsigned int i = 0;i < numsubs;++i) { - sh::Factory::getInstance()._ensureMaterial(ent->getSubEntity(i)->getMaterial()->getName(), "Default"); - if(ent->getSubEntity(i)->getMaterial()->isTransparent()) - return true; + // No model given. Create an object root anyway, so that lights can be added to it if needed. + //mObjectRoot = NifOgre::ObjectScenePtr (new NifOgre::ObjectScene(mInsert->getCreator())); } - return false; } -}; - -bool ObjectAnimation::canBatch() const -{ - if(!mObjectRoot->mParticles.empty() || !mObjectRoot->mLights.empty() || !mObjectRoot->mControllers.empty()) - return false; - if (!mObjectRoot->mBillboardNodes.empty()) - return false; - return std::find_if(mObjectRoot->mEntities.begin(), mObjectRoot->mEntities.end(), - FindEntityTransparency()) == mObjectRoot->mEntities.end(); -} - -void ObjectAnimation::fillBatch(Ogre::StaticGeometry *sg) -{ - std::vector::reverse_iterator iter = mObjectRoot->mEntities.rbegin(); - for(;iter != mObjectRoot->mEntities.rend();++iter) - { - Ogre::Node *node = (*iter)->getParentNode(); - if ((*iter)->isVisible()) - sg->addEntity(*iter, node->_getDerivedPosition(), node->_getDerivedOrientation(), node->_getDerivedScale()); - } -} } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index dab8cfebb..cbded364a 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -4,15 +4,20 @@ #include #include -#include - #include "../mwworld/ptr.hpp" +#include + namespace ESM { struct Light; } +namespace Resource +{ + class ResourceSystem; +} + namespace MWRender { class Camera; @@ -69,20 +74,18 @@ protected: virtual void setValue(Ogre::Real value); }; - - - class NullAnimationTime : public Ogre::ControllerValue + class NullAnimationTime : public NifOsg::ControllerSource { public: - virtual Ogre::Real getValue() const - { return 0.0f; } - virtual void setValue(Ogre::Real value) - { } + virtual float getValue(osg::NodeVisitor *nv) + { + return 0.f; + } }; struct AnimSource : public Ogre::AnimationAlloc { - NifOgre::TextKeyMap mTextKeys; + //NifOgre::TextKeyMap mTextKeys; std::vector > mControllers[sNumGroups]; }; typedef std::vector< Ogre::SharedPtr > AnimSourceList; @@ -113,106 +116,71 @@ protected: typedef std::map ObjectAttachMap; - struct EffectParams - { - std::string mModelName; // Just here so we don't add the same effect twice - NifOgre::ObjectScenePtr mObjects; - int mEffectId; - bool mLoop; - std::string mBoneName; - }; + osg::ref_ptr mInsert; - std::vector mEffects; + osg::ref_ptr mObjectRoot; MWWorld::Ptr mPtr; - Ogre::Light* mGlowLight; - - Ogre::SceneNode *mInsert; - Ogre::Entity *mSkelBase; - NifOgre::ObjectScenePtr mObjectRoot; - AnimSourceList mAnimSources; - Ogre::Node *mAccumRoot; - Ogre::Node *mNonAccumRoot; - NifOgre::NodeTargetValue *mNonAccumCtrl; - Ogre::Vector3 mAccumulate; - - AnimStateMap mStates; - - Ogre::SharedPtr mAnimationTimePtr[sNumGroups]; - Ogre::SharedPtr mNullAnimationTimePtr; - - ObjectAttachMap mAttachedObjects; - + Resource::ResourceSystem* mResourceSystem; /* Sets the appropriate animations on the bone groups based on priority. */ - void resetActiveGroups(); + //void resetActiveGroups(); - static size_t detectAnimGroup(const Ogre::Node *node); + //static size_t detectAnimGroup(const Ogre::Node *node); + /* static float calcAnimVelocity(const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue *nonaccumctrl, const Ogre::Vector3 &accum, const std::string &groupname); - - /* Updates a skeleton instance so that all bones matching the source skeleton (based on - * bone names) are positioned identically. */ - void updateSkeletonInstance(const Ogre::SkeletonInstance *skelsrc, Ogre::SkeletonInstance *skel); + */ /* Updates the position of the accum root node for the given time, and * returns the wanted movement vector from the previous time. */ - void updatePosition(float oldtime, float newtime, Ogre::Vector3 &position); + //void updatePosition(float oldtime, float newtime, Ogre::Vector3 &position); - static NifOgre::TextKeyMap::const_iterator findGroupStart(const NifOgre::TextKeyMap &keys, const std::string &groupname); + //static NifOgre::TextKeyMap::const_iterator findGroupStart(const NifOgre::TextKeyMap &keys, const std::string &groupname); /* Resets the animation to the time of the specified start marker, without * moving anything, and set the end time to the specified stop marker. If * the marker is not found, or if the markers are the same, it returns * false. */ - bool reset(AnimState &state, const NifOgre::TextKeyMap &keys, - const std::string &groupname, const std::string &start, const std::string &stop, - float startpoint, bool loopfallback); + //bool reset(AnimState &state, const NifOgre::TextKeyMap &keys, + // const std::string &groupname, const std::string &start, const std::string &stop, + // float startpoint, bool loopfallback); - void handleTextKey(AnimState &state, const std::string &groupname, const NifOgre::TextKeyMap::const_iterator &key, - const NifOgre::TextKeyMap& map); + //void handleTextKey(AnimState &state, const std::string &groupname, const NifOgre::TextKeyMap::const_iterator &key, + // const NifOgre::TextKeyMap& map); - /* Sets the root model of the object. If 'baseonly' is true, then any meshes or particle - * systems in the model are ignored (useful for NPCs, where only the skeleton is needed for - * the root). + /* Sets the root model of the object. * * Note that you must make sure all animation sources are cleared before reseting the object * root. All nodes previously retrieved with getNode will also become invalidated. */ - void setObjectRoot(const std::string &model, bool baseonly); + void setObjectRoot(const std::string &model); /* Adds the keyframe controllers in the specified model as a new animation source. Note that * the filename portion of the provided model name will be prepended with 'x', and the .nif * extension will be replaced with .kf. */ - void addAnimSource(const std::string &model); + //void addAnimSource(const std::string &model); /** Adds an additional light to the given object list using the specified ESM record. */ - void addExtraLight(Ogre::SceneManager *sceneMgr, NifOgre::ObjectScenePtr objlist, const ESM::Light *light); - - void clearAnimSources(); + //void addExtraLight(Ogre::SceneManager *sceneMgr, NifOgre::ObjectScenePtr objlist, const ESM::Light *light); - // TODO: Should not be here - Ogre::Vector3 getEnchantmentColor(MWWorld::Ptr item); + //void clearAnimSources(); public: - // FIXME: Move outside of this class - static void setRenderProperties(NifOgre::ObjectScenePtr objlist, Ogre::uint32 visflags, Ogre::uint8 solidqueue, - Ogre::uint8 transqueue, Ogre::Real dist=0.0f, - bool enchantedGlow=false, Ogre::Vector3* glowColor=NULL); - /// Returns the name of the .nif file that makes up this animation's base skeleton. - /// If there is no skeleton, returns "". - std::string getObjectRootName() const; - - Animation(const MWWorld::Ptr &ptr, Ogre::SceneNode *node); + Animation(const MWWorld::Ptr &ptr, osg::ref_ptr node, Resource::ResourceSystem* resourceSystem); virtual ~Animation(); + osg::Group* getOrCreateObjectRoot(); + + osg::Group* getObjectRoot(); + /** * @brief Add an effect mesh attached to a bone or the insert scene node * @param model @@ -223,25 +191,18 @@ public: * @param texture override the texture specified in the model's materials * @note Will not add an effect twice. */ - void addEffect (const std::string& model, int effectId, bool loop = false, const std::string& bonename = "", std::string texture = ""); - void removeEffect (int effectId); - void getLoopingEffects (std::vector& out); + //void addEffect (const std::string& model, int effectId, bool loop = false, const std::string& bonename = "", std::string texture = ""); + //void removeEffect (int effectId); + //void getLoopingEffects (std::vector& out); - /// Prepare this animation for being rendered with \a camera (rotates billboard nodes) - virtual void preRender (Ogre::Camera* camera); + //void updatePtr(const MWWorld::Ptr &ptr); - virtual void setAlpha(float alpha) {} - virtual void setVampire(bool vampire) {} - -public: - void updatePtr(const MWWorld::Ptr &ptr); - - bool hasAnimation(const std::string &anim); + //bool hasAnimation(const std::string &anim); // Specifies the axis' to accumulate on. Non-accumulated axis will just // move visually, but not affect the actual movement. Each x/y/z value // should be on the scale of 0 to 1. - void setAccumulation(const Ogre::Vector3 &accum); + //void setAccumulation(const Ogre::Vector3 &accum); /** Plays an animation. * \param groupname Name of the animation group to play. @@ -263,23 +224,23 @@ public: * \param loopFallback Allow looping an animation that has no loop keys, i.e. fall back to use * the "start" and "stop" keys for looping? */ - void play(const std::string &groupname, int priority, int groups, bool autodisable, - float speedmult, const std::string &start, const std::string &stop, - float startpoint, size_t loops, bool loopfallback=false); + //void play(const std::string &groupname, int priority, int groups, bool autodisable, + // float speedmult, const std::string &start, const std::string &stop, + // float startpoint, size_t loops, bool loopfallback=false); /** If the given animation group is currently playing, set its remaining loop count to '0'. */ - void stopLooping(const std::string& groupName); + //void stopLooping(const std::string& groupName); /** Adjust the speed multiplier of an already playing animation. */ - void adjustSpeedMult (const std::string& groupname, float speedmult); + //void adjustSpeedMult (const std::string& groupname, float speedmult); /** Returns true if the named animation group is playing. */ - bool isPlaying(const std::string &groupname) const; + //bool isPlaying(const std::string &groupname) const; /// Returns true if no important animations are currently playing on the upper body. - bool upperBodyReady() const; + //bool upperBodyReady() const; /** Gets info about the given animation group. * \param groupname Animation group to check. @@ -287,71 +248,32 @@ public: * \param speedmult Stores the animation speed multiplier * \return True if the animation is active, false otherwise. */ - bool getInfo(const std::string &groupname, float *complete=NULL, float *speedmult=NULL) const; + //bool getInfo(const std::string &groupname, float *complete=NULL, float *speedmult=NULL) const; /// Get the absolute position in the animation track of the first text key with the given group. - float getStartTime(const std::string &groupname) const; + //float getStartTime(const std::string &groupname) const; /// Get the absolute position in the animation track of the text key - float getTextKeyTime(const std::string &textKey) const; + //float getTextKeyTime(const std::string &textKey) const; /// Get the current absolute position in the animation track for the animation that is currently playing from the given group. - float getCurrentTime(const std::string& groupname) const; + //float getCurrentTime(const std::string& groupname) const; /** Disables the specified animation group; * \param groupname Animation group to disable. */ - void disable(const std::string &groupname); - void changeGroups(const std::string &groupname, int group); - - virtual void setWeaponGroup(const std::string& group) {} + //void disable(const std::string &groupname); + //void changeGroups(const std::string &groupname, int group); /** Retrieves the velocity (in units per second) that the animation will move. */ - float getVelocity(const std::string &groupname) const; - - /// A relative factor (0-1) that decides if and how much the skeleton should be pitched - /// to indicate the facing orientation of the character. - virtual void setPitchFactor(float factor) {} - virtual void setHeadPitch(Ogre::Radian factor) {} - virtual void setHeadYaw(Ogre::Radian factor) {} - virtual Ogre::Radian getHeadPitch() const { return Ogre::Radian(0.f); } - virtual Ogre::Radian getHeadYaw() const { return Ogre::Radian(0.f); } - - virtual Ogre::Vector3 runAnimation(float duration); - - /// This is typically called as part of runAnimation, but may be called manually if needed. - void updateEffects(float duration); - - // TODO: move outside of this class - /// Makes this object glow, by placing a Light in its center. - /// @param effect Controls the radius and intensity of the light. - void setLightEffect(float effect); - - virtual void showWeapons(bool showWeapon); - virtual void showCarriedLeft(bool show) {} - virtual void attachArrow() {} - virtual void releaseArrow() {} - void enableLights(bool enable); - virtual void enableHeadAnimation(bool enable) {} - - Ogre::AxisAlignedBox getWorldBounds(); - - Ogre::Node *getNode(const std::string &name); - Ogre::Node *getNode(int handle); - - // Attaches the given object to a bone on this object's base skeleton. If the bone doesn't - // exist, the object isn't attached and NULL is returned. The returned TagPoint is only - // valid until the next setObjectRoot call. - Ogre::TagPoint *attachObjectToBone(const Ogre::String &bonename, Ogre::MovableObject *obj); - void detachObjectFromBone(Ogre::MovableObject *obj); + //float getVelocity(const std::string &groupname) const; + + virtual osg::Vec3f runAnimation(float duration); }; class ObjectAnimation : public Animation { public: - ObjectAnimation(const MWWorld::Ptr& ptr, const std::string &model); - - bool canBatch() const; - void fillBatch(Ogre::StaticGeometry *sg); + ObjectAnimation(const MWWorld::Ptr& ptr, const std::string &model, Resource::ResourceSystem* resourceSystem); }; } diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 3c6a507e7..6d37fa1e8 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -2,110 +2,204 @@ #include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include -#include -#include +#include +#include -//#include -#include +// light +#include + +#include + +#include +#include #include "../mwworld/ptr.hpp" #include "../mwworld/class.hpp" #include "../mwworld/cellstore.hpp" #include "renderconst.hpp" -//#include "animation.hpp" +#include "animation.hpp" + +namespace +{ + + /// Removes all particle systems and related nodes in a subgraph. + class RemoveParticlesVisitor : public osg::NodeVisitor + { + public: + RemoveParticlesVisitor() + : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) + { } + + virtual void apply(osg::Node &node) + { + if (dynamic_cast(&node) || dynamic_cast(&node)) + mToRemove.push_back(&node); + + traverse(node); + } -using namespace MWRender; + void remove() + { + for (std::vector >::iterator it = mToRemove.begin(); it != mToRemove.end(); ++it) + { + osg::Node* node = *it; + if (node->getNumParents()) + node->getParent(0)->removeChild(node); + } + mToRemove.clear(); + } -int Objects::uniqueID = 0; + private: + std::vector > mToRemove; + }; + +} -void Objects::setRootNode(Ogre::SceneNode* root) + +namespace MWRender +{ + +Objects::Objects(Resource::ResourceSystem* resourceSystem, osg::ref_ptr rootNode) + : mResourceSystem(resourceSystem) + , mRootNode(rootNode) { - mRootNode = root; +} + +Objects::~Objects() +{ + for(PtrAnimationMap::iterator iter = mObjects.begin();iter != mObjects.end();++iter) + delete iter->second; + mObjects.clear(); + + for (CellMap::iterator iter = mCellSceneNodes.begin(); iter != mCellSceneNodes.end(); ++iter) + iter->second->getParent(0)->removeChild(iter->second); + mCellSceneNodes.clear(); } void Objects::insertBegin(const MWWorld::Ptr& ptr) { - Ogre::SceneNode* root = mRootNode; - Ogre::SceneNode* cellnode; - if(mCellSceneNodes.find(ptr.getCell()) == mCellSceneNodes.end()) + osg::ref_ptr cellnode; + + CellMap::iterator found = mCellSceneNodes.find(ptr.getCell()); + if (found == mCellSceneNodes.end()) { - //Create the scenenode and put it in the map - cellnode = root->createChildSceneNode(); + cellnode = new osg::Group; + mRootNode->addChild(cellnode); mCellSceneNodes[ptr.getCell()] = cellnode; } else - { - cellnode = mCellSceneNodes[ptr.getCell()]; - } + cellnode = found->second; - Ogre::SceneNode* insert = cellnode->createChildSceneNode(); - const float *f = ptr.getRefData().getPosition().pos; + osg::ref_ptr insert (new osg::PositionAttitudeTransform); + cellnode->addChild(insert); - insert->setPosition(f[0], f[1], f[2]); - insert->setScale(ptr.getCellRef().getScale(), ptr.getCellRef().getScale(), ptr.getCellRef().getScale()); + const float *f = ptr.getRefData().getPosition().pos; + insert->setPosition(osg::Vec3(f[0], f[1], f[2])); + insert->setScale(osg::Vec3(ptr.getCellRef().getScale(), ptr.getCellRef().getScale(), ptr.getCellRef().getScale())); // Convert MW rotation to a quaternion: f = ptr.getCellRef().getPosition().rot; // Rotate around X axis - Ogre::Quaternion xr(Ogre::Radian(-f[0]), Ogre::Vector3::UNIT_X); + osg::Quat xr(-f[0], osg::Vec3(1,0,0)); // Rotate around Y axis - Ogre::Quaternion yr(Ogre::Radian(-f[1]), Ogre::Vector3::UNIT_Y); + osg::Quat yr(-f[1], osg::Vec3(0,1,0)); // Rotate around Z axis - Ogre::Quaternion zr(Ogre::Radian(-f[2]), Ogre::Vector3::UNIT_Z); + osg::Quat zr(-f[2], osg::Vec3(0,0,1)); // Rotates first around z, then y, then x - insert->setOrientation(xr*yr*zr); + insert->setAttitude(zr*yr*xr); + + // TODO: actors rotate around z only ptr.getRefData().setBaseNode(insert); } -void Objects::insertModel(const MWWorld::Ptr &ptr, const std::string &mesh, bool batch) +void Objects::insertModel(const MWWorld::Ptr &ptr, const std::string &mesh, bool animated, bool allowLight) { insertBegin(ptr); -/* - std::auto_ptr anim(new ObjectAnimation(ptr, mesh)); - if (!mesh.empty()) + std::auto_ptr anim (new ObjectAnimation(ptr, mesh, mResourceSystem)); + + if (ptr.getTypeName() == typeid(ESM::Light).name() && allowLight) { - Ogre::AxisAlignedBox bounds = anim->getWorldBounds(); - Ogre::Vector3 extents = bounds.getSize(); - extents *= ptr.getRefData().getBaseNode()->getScale(); - float size = std::max(std::max(extents.x, extents.y), extents.z); + SceneUtil::FindByNameVisitor visitor("AttachLight"); + ptr.getRefData().getBaseNode()->accept(visitor); + + osg::Vec3f lightOffset (0.f, 0.f, 0.f); + + osg::Group* attachTo = NULL; + if (visitor.mFoundNode) + { + attachTo = visitor.mFoundNode; + } + else + { + osg::ComputeBoundsVisitor computeBound; + osg::Group* objectRoot = anim->getOrCreateObjectRoot(); + objectRoot->accept(computeBound); - bool small = (size < Settings::Manager::getInt("small object size", "Viewing distance")) && - Settings::Manager::getBool("limit small object distance", "Viewing distance"); - // do not fade out doors. that will cause holes and look stupid - if(ptr.getTypeName().find("Door") != std::string::npos) - small = false; + lightOffset = computeBound.getBoundingBox().center(); - if (mBounds.find(ptr.getCell()) == mBounds.end()) - mBounds[ptr.getCell()] = Ogre::AxisAlignedBox::BOX_NULL; - mBounds[ptr.getCell()].merge(bounds); + attachTo = objectRoot; + } + + const ESM::Light* esmLight = ptr.get()->mBase; + + osg::ref_ptr lightSource = new SceneUtil::LightSource; + osg::Light* light = new osg::Light; + lightSource->setLight(light); + light->setPosition(osg::Vec4f(lightOffset.x(), lightOffset.y(), lightOffset.z(), 1.f)); + + float realRadius = esmLight->mData.mRadius * 2; + + lightSource->setRadius(realRadius); + light->setLinearAttenuation(10.f/realRadius); + //light->setLinearAttenuation(0.05); + light->setConstantAttenuation(0.f); + light->setDiffuse(SceneUtil::colourFromRGB(esmLight->mData.mColor)); + light->setAmbient(osg::Vec4f(0,0,0,1)); + light->setSpecular(osg::Vec4f(0,0,0,0)); + + attachTo->addChild(lightSource); + } + if (!allowLight) + { + RemoveParticlesVisitor visitor; + anim->getObjectRoot()->accept(visitor); + visitor.remove(); } - if(anim.get() != NULL) - mObjects.insert(std::make_pair(ptr, anim.release())); - */ + mObjects.insert(std::make_pair(ptr, anim.release())); +} + +void Objects::insertCreature(const MWWorld::Ptr &ptr, const std::string &mesh, bool weaponsShields) +{ + insertBegin(ptr); + + // CreatureAnimation + std::auto_ptr anim (new ObjectAnimation(ptr, mesh, mResourceSystem)); + mObjects.insert(std::make_pair(ptr, anim.release())); +} + +void Objects::insertNPC(const MWWorld::Ptr &ptr) +{ + } bool Objects::deleteObject (const MWWorld::Ptr& ptr) { - /* if(!ptr.getRefData().getBaseNode()) return true; @@ -115,18 +209,16 @@ bool Objects::deleteObject (const MWWorld::Ptr& ptr) delete iter->second; mObjects.erase(iter); - mRenderer.getScene()->destroySceneNode(ptr.getRefData().getBaseNode()); - ptr.getRefData().setBaseNode(0); + ptr.getRefData().getBaseNode()->getParent(0)->removeChild(ptr.getRefData().getBaseNode()); + ptr.getRefData().setBaseNode(NULL); return true; } -*/ return false; } -void Objects::removeCell(MWWorld::CellStore* store) +void Objects::removeCell(const MWWorld::CellStore* store) { - /* for(PtrAnimationMap::iterator iter = mObjects.begin();iter != mObjects.end();) { if(iter->first.getCell() == store) @@ -138,46 +230,19 @@ void Objects::removeCell(MWWorld::CellStore* store) ++iter; } - std::map::iterator geom = mStaticGeometry.find(store); - if(geom != mStaticGeometry.end()) - { - Ogre::StaticGeometry *sg = geom->second; - mStaticGeometry.erase(geom); - mRenderer.getScene()->destroyStaticGeometry(sg); - } - - geom = mStaticGeometrySmall.find(store); - if(geom != mStaticGeometrySmall.end()) - { - Ogre::StaticGeometry *sg = geom->second; - mStaticGeometrySmall.erase(store); - mRenderer.getScene()->destroyStaticGeometry(sg); - } - - mBounds.erase(store); - - std::map::iterator cell = mCellSceneNodes.find(store); + CellMap::iterator cell = mCellSceneNodes.find(store); if(cell != mCellSceneNodes.end()) { - cell->second->removeAndDestroyAllChildren(); - mRenderer.getScene()->destroySceneNode(cell->second); + cell->second->getParent(0)->removeChild(cell->second); mCellSceneNodes.erase(cell); } - */ -} - -Ogre::AxisAlignedBox Objects::getDimensions(MWWorld::CellStore* cell) -{ - return mBounds[cell]; } void Objects::update(float dt, Ogre::Camera* camera) { - /* PtrAnimationMap::const_iterator it = mObjects.begin(); for(;it != mObjects.end();++it) it->second->runAnimation(dt); - */ } void Objects::updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur) @@ -206,13 +271,13 @@ void Objects::updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur) */ } -ObjectAnimation* Objects::getAnimation(const MWWorld::Ptr &ptr) +Animation* Objects::getAnimation(const MWWorld::Ptr &ptr) { - /* PtrAnimationMap::const_iterator iter = mObjects.find(ptr); if(iter != mObjects.end()) return iter->second; - */ + return NULL; } +} diff --git a/apps/openmw/mwrender/objects.hpp b/apps/openmw/mwrender/objects.hpp index b2f07ab0f..44334e444 100644 --- a/apps/openmw/mwrender/objects.hpp +++ b/apps/openmw/mwrender/objects.hpp @@ -1,10 +1,16 @@ #ifndef GAME_RENDER_OBJECTS_H #define GAME_RENDER_OBJECTS_H -#include #include -#include +#include + +#include + +namespace osg +{ + class Group; +} namespace MWWorld { @@ -14,53 +20,52 @@ namespace MWWorld namespace MWRender{ -class ObjectAnimation; +class Animation; -class Objects{ - typedef std::map PtrAnimationMap; - OEngine::Render::OgreRenderer &mRenderer; +class Objects{ + typedef std::map PtrAnimationMap; - std::map mCellSceneNodes; - std::map mStaticGeometry; - std::map mStaticGeometrySmall; - std::map mBounds; + typedef std::map > CellMap; + CellMap mCellSceneNodes; PtrAnimationMap mObjects; - Ogre::SceneNode* mRootNode; - - static int uniqueID; + osg::ref_ptr mRootNode; void insertBegin(const MWWorld::Ptr& ptr); - + Resource::ResourceSystem* mResourceSystem; public: - Objects(OEngine::Render::OgreRenderer &renderer) - : mRenderer(renderer) - , mRootNode(NULL) - {} - ~Objects(){} - void insertModel(const MWWorld::Ptr& ptr, const std::string &model, bool batch=false); + Objects(Resource::ResourceSystem* resourceSystem, osg::ref_ptr rootNode); + ~Objects(); + + /// @param animated Attempt to load separate keyframes from a .kf file matching the model file? + /// @param allowLight If false, no lights will be created, and particles systems will be cleared then frozen. + void insertModel(const MWWorld::Ptr& ptr, const std::string &model, bool animated=false, bool allowLight=true); - ObjectAnimation* getAnimation(const MWWorld::Ptr &ptr); + void insertNPC(const MWWorld::Ptr& ptr); + void insertCreature (const MWWorld::Ptr& ptr, const std::string& model, bool weaponsShields); + + Animation* getAnimation(const MWWorld::Ptr &ptr); void update (float dt, Ogre::Camera* camera); ///< per-frame update - Ogre::AxisAlignedBox getDimensions(MWWorld::CellStore*); + //Ogre::AxisAlignedBox getDimensions(MWWorld::CellStore*); ///< get a bounding box that encloses all objects in the specified cell bool deleteObject (const MWWorld::Ptr& ptr); ///< \return found? - void removeCell(MWWorld::CellStore* store); - void setRootNode(Ogre::SceneNode* root); - - void rebuildStaticGeometry(); + void removeCell(const MWWorld::CellStore* store); /// Updates containing cell for object rendering data void updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur); + +private: + void operator = (const Objects&); + Objects(const Objects&); }; } #endif diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index c64a265ac..4e5b33c64 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -1,1046 +1,92 @@ #include "renderingmanager.hpp" -#include +#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include -#include +#include -#include -#include +#include -#include +#include -#include -#include -#include +#include -#include "../mwworld/esmstore.hpp" -#include "../mwworld/class.hpp" -#include "../mwworld/cellstore.hpp" - -#include "../mwbase/world.hpp" // these includes can be removed once the static-hack is gone -#include "../mwbase/environment.hpp" -#include "../mwbase/windowmanager.hpp" // FIXME -#include "../mwbase/statemanager.hpp" - -#include "../mwmechanics/creaturestats.hpp" -#include "../mwmechanics/npcstats.hpp" - -#include "../mwworld/ptr.hpp" - -#include "localmap.hpp" -#include "water.hpp" -#include "npcanimation.hpp" -#include "globalmap.hpp" -#include "terrainstorage.hpp" -#include "effectmanager.hpp" - -using namespace MWRender; -using namespace Ogre; - -namespace MWRender { - -RenderingManager::RenderingManager(OEngine::Render::OgreRenderer& _rend, const boost::filesystem::path& resDir, - const boost::filesystem::path& cacheDir, OEngine::Physic::PhysicEngine* engine, - MWWorld::Fallback* fallback) - : mRendering(_rend) - , mFallback(fallback) - , mPlayerAnimation(NULL) - , mSunEnabled(0) - , mPhysicsEngine(engine) - , mTerrain(NULL) - , mEffectManager(NULL) - , mRenderWorld(true) -{ - mActors = new MWRender::Actors(mRendering, this); - mObjects = new MWRender::Objects(mRendering); - mEffectManager = new EffectManager(mRendering.getScene()); - // select best shader mode - bool openGL = (Ogre::Root::getSingleton ().getRenderSystem ()->getName().find("OpenGL") != std::string::npos); - bool glES = (Ogre::Root::getSingleton ().getRenderSystem ()->getName().find("OpenGL ES") != std::string::npos); - - // glsl is only supported in opengl mode and hlsl only in direct3d mode. - std::string currentMode = Settings::Manager::getString("shader mode", "General"); - if (currentMode == "" - || (openGL && currentMode == "hlsl") - || (!openGL && currentMode == "glsl") - || (glES && currentMode != "glsles")) - { - Settings::Manager::setString("shader mode", "General", openGL ? (glES ? "glsles" : "glsl") : "hlsl"); - } - - mRendering.adjustCamera(Settings::Manager::getFloat("field of view", "General"), 5); - - mRendering.getWindow()->addListener(this); - mRendering.setWindowListener(this); - - mWater = 0; - - // material system - sh::OgrePlatform* platform = new sh::OgrePlatform("General", (resDir / "materials").string()); - if (!boost::filesystem::exists (cacheDir)) - boost::filesystem::create_directories (cacheDir); - platform->setCacheFolder (cacheDir.string()); - mFactory = new sh::Factory(platform); - - sh::Language lang; - std::string l = Settings::Manager::getString("shader mode", "General"); - if (l == "glsl") - lang = sh::Language_GLSL; - else if (l == "glsles") - lang = sh::Language_GLSLES; - else if (l == "hlsl") - lang = sh::Language_HLSL; - else - lang = sh::Language_CG; - mFactory->setCurrentLanguage (lang); - mFactory->setWriteSourceCache (true); - mFactory->setReadSourceCache (true); - mFactory->setReadMicrocodeCache (true); - mFactory->setWriteMicrocodeCache (true); - - mFactory->loadAllFiles(); - - TextureManager::getSingleton().setDefaultNumMipmaps(Settings::Manager::getInt("num mipmaps", "General")); - - // Set default texture filtering options - TextureFilterOptions tfo; - std::string filter = Settings::Manager::getString("texture filtering", "General"); - - if (filter == "anisotropic") tfo = TFO_ANISOTROPIC; - else if (filter == "trilinear") tfo = TFO_TRILINEAR; - else if (filter == "bilinear") tfo = TFO_BILINEAR; - else /*if (filter == "none")*/ tfo = TFO_NONE; - - MaterialManager::getSingleton().setDefaultTextureFiltering(tfo); - MaterialManager::getSingleton().setDefaultAnisotropy( (filter == "anisotropic") ? Settings::Manager::getInt("anisotropy", "General") : 1 ); - - Ogre::TextureManager::getSingleton().setMemoryBudget(126*1024*1024); - Ogre::MeshManager::getSingleton().setMemoryBudget(64*1024*1024); - - Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups(); - - // disable unsupported effects - if (!Settings::Manager::getBool("shaders", "Objects")) - Settings::Manager::setBool("enabled", "Shadows", false); - - sh::Factory::getInstance ().setShadersEnabled (Settings::Manager::getBool("shaders", "Objects")); - - sh::Factory::getInstance ().setGlobalSetting ("fog", "true"); - sh::Factory::getInstance ().setGlobalSetting ("num_lights", Settings::Manager::getString ("num lights", "Objects")); - sh::Factory::getInstance ().setGlobalSetting ("simple_water", Settings::Manager::getBool("shader", "Water") ? "false" : "true"); - sh::Factory::getInstance ().setGlobalSetting ("render_refraction", "false"); - - sh::Factory::getInstance ().setSharedParameter ("waterEnabled", sh::makeProperty (new sh::FloatValue(0.0))); - sh::Factory::getInstance ().setSharedParameter ("waterLevel", sh::makeProperty(new sh::FloatValue(0))); - sh::Factory::getInstance ().setSharedParameter ("waterTimer", sh::makeProperty(new sh::FloatValue(0))); - sh::Factory::getInstance ().setSharedParameter ("windDir_windSpeed", sh::makeProperty(new sh::Vector3(0.5f, -0.8f, 0.2f))); - sh::Factory::getInstance ().setSharedParameter ("waterSunFade_sunHeight", sh::makeProperty(new sh::Vector2(1, 0.6f))); - sh::Factory::getInstance ().setGlobalSetting ("refraction", Settings::Manager::getBool("refraction", "Water") ? "true" : "false"); - sh::Factory::getInstance ().setGlobalSetting ("viewproj_fix", "false"); - sh::Factory::getInstance ().setSharedParameter ("vpRow2Fix", sh::makeProperty (new sh::Vector4(0,0,0,0))); - - mRootNode = mRendering.getScene()->getRootSceneNode(); - mRootNode->createChildSceneNode("player"); - - mObjects->setRootNode(mRootNode); - mActors->setRootNode(mRootNode); - - mCamera = new MWRender::Camera(mRendering.getCamera()); - - mSkyManager = new SkyManager(mRootNode, mRendering.getCamera()); - - mOcclusionQuery = new OcclusionQuery(&mRendering, mSkyManager->getSunNode()); - - mSun = 0; - - mLocalMap = new MWRender::LocalMap(&mRendering, this); - - mWater = new MWRender::Water(mRendering.getCamera(), this, mFallback); - - setMenuTransparency(Settings::Manager::getFloat("menu transparency", "GUI")); -} - -RenderingManager::~RenderingManager () -{ - mRendering.getWindow()->removeListener(this); - - delete mPlayerAnimation; - delete mCamera; - delete mSkyManager; - delete mTerrain; - delete mLocalMap; - delete mOcclusionQuery; - delete mWater; - delete mActors; - delete mObjects; - delete mEffectManager; - delete mFactory; -} - -MWRender::SkyManager* RenderingManager::getSkyManager() -{ - return mSkyManager; -} - -MWRender::Objects& RenderingManager::getObjects(){ - return *mObjects; -} -MWRender::Actors& RenderingManager::getActors(){ - return *mActors; -} - -MWRender::Camera* RenderingManager::getCamera() const -{ - return mCamera; -} - -void RenderingManager::removeCell (MWWorld::CellStore *store) -{ - if (store->isExterior()) - mTerrain->unloadCell(store->getCell()->getGridX(), store->getCell()->getGridY()); - - mLocalMap->saveFogOfWar(store); - mObjects->removeCell(store); - mActors->removeCell(store); -} - -void RenderingManager::removeWater () -{ - mWater->setActive(false); -} - -bool RenderingManager::toggleWater() -{ - return mWater->toggle(); -} - -bool RenderingManager::toggleWorld() -{ - mRenderWorld = !mRenderWorld; - - int visibilityMask = mRenderWorld ? ~int(0) : 0; - mRendering.getViewport()->setVisibilityMask(visibilityMask); - return mRenderWorld; -} - -void RenderingManager::cellAdded (MWWorld::CellStore *store) -{ - if (store->isExterior()) - mTerrain->loadCell(store->getCell()->getGridX(), store->getCell()->getGridY()); - - mObjects->buildStaticGeometry (*store); - sh::Factory::getInstance().unloadUnreferencedMaterials(); -} - -void RenderingManager::addObject (const MWWorld::Ptr& ptr, const std::string& model){ - const MWWorld::Class& class_ = - ptr.getClass(); - class_.insertObjectRendering(ptr, model, *this); -} - -void RenderingManager::removeObject (const MWWorld::Ptr& ptr) -{ - if (!mObjects->deleteObject (ptr)) - mActors->deleteObject (ptr); -} - -void RenderingManager::moveObject (const MWWorld::Ptr& ptr, const Ogre::Vector3& position) -{ - /// \todo move this to the rendering-subsystems - ptr.getRefData().getBaseNode()->setPosition(position); -} - -void RenderingManager::scaleObject (const MWWorld::Ptr& ptr, const Ogre::Vector3& scale) -{ - ptr.getRefData().getBaseNode()->setScale(scale); -} - -void RenderingManager::rotateObject(const MWWorld::Ptr &ptr) -{ - Ogre::Vector3 rot(ptr.getRefData().getPosition().rot); - - if(ptr.getRefData().getHandle() == mCamera->getHandle() && - !mCamera->isVanityOrPreviewModeEnabled()) - mCamera->rotateCamera(-rot, false); - - Ogre::Quaternion newo = Ogre::Quaternion(Ogre::Radian(rot.z), Ogre::Vector3::NEGATIVE_UNIT_Z); - if(!ptr.getClass().isActor()) - newo = Ogre::Quaternion(Ogre::Radian(rot.x), Ogre::Vector3::NEGATIVE_UNIT_X) * - Ogre::Quaternion(Ogre::Radian(rot.y), Ogre::Vector3::NEGATIVE_UNIT_Y) * newo; - ptr.getRefData().getBaseNode()->setOrientation(newo); -} - -void -RenderingManager::updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur) -{ - if (!old.getRefData().getBaseNode()) - return; - Ogre::SceneNode *child = - mRendering.getScene()->getSceneNode(old.getRefData().getHandle()); - - Ogre::SceneNode *parent = child->getParentSceneNode(); - parent->removeChild(child); - - if (old.getClass().isActor()) { - mActors->updateObjectCell(old, cur); - } else { - mObjects->updateObjectCell(old, cur); - } -} - -void RenderingManager::updatePlayerPtr(const MWWorld::Ptr &ptr) -{ - if(mPlayerAnimation) - mPlayerAnimation->updatePtr(ptr); - if(mCamera->getHandle() == ptr.getRefData().getHandle()) - attachCameraTo(ptr); -} - -void RenderingManager::rebuildPtr(const MWWorld::Ptr &ptr) -{ - NpcAnimation *anim = NULL; - if(ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) - anim = mPlayerAnimation; - else if(ptr.getClass().isActor()) - anim = dynamic_cast(mActors->getAnimation(ptr)); - if(anim) - { - anim->rebuild(); - if(mCamera->getHandle() == ptr.getRefData().getHandle()) - { - attachCameraTo(ptr); - mCamera->setAnimation(anim); - } - } -} - -void RenderingManager::update (float duration, bool paused) -{ - if (MWBase::Environment::get().getStateManager()->getState()== - MWBase::StateManager::State_NoGame) - return; - - MWBase::World *world = MWBase::Environment::get().getWorld(); - - MWWorld::Ptr player = world->getPlayerPtr(); - - int blind = static_cast(player.getClass().getCreatureStats(player).getMagicEffects().get(ESM::MagicEffect::Blind).getMagnitude()); - MWBase::Environment::get().getWindowManager()->setBlindness(std::max(0, std::min(100, blind))); - setAmbientMode(); - - if (player.getClass().getNpcStats(player).isWerewolf()) - MWBase::Environment::get().getWindowManager()->setWerewolfOverlay(mCamera->isFirstPerson()); - - // player position - MWWorld::RefData &data = player.getRefData(); - Ogre::Vector3 playerPos(data.getPosition().pos); - - mCamera->setCameraDistance(); - if(!mCamera->isFirstPerson()) - { - Ogre::Vector3 orig, dest; - mCamera->getPosition(orig, dest); - - btVector3 btOrig(orig.x, orig.y, orig.z); - btVector3 btDest(dest.x, dest.y, dest.z); - std::pair test = mPhysicsEngine->sphereCast(mRendering.getCamera()->getNearClipDistance()*2.5f, btOrig, btDest); - if(test.first) - mCamera->setCameraDistance(test.second * orig.distance(dest), false, false); - } - - // Sink the camera while sneaking - bool isSneaking = player.getClass().getCreatureStats(player).getStance(MWMechanics::CreatureStats::Stance_Sneak); - bool isInAir = !world->isOnGround(player); - bool isSwimming = world->isSwimming(player); - - static const float i1stPersonSneakDelta = MWBase::Environment::get().getWorld()->getStore().get() - .find("i1stPersonSneakDelta")->getFloat(); - if(!paused && isSneaking && !(isSwimming || isInAir)) - mCamera->setSneakOffset(i1stPersonSneakDelta); - - mOcclusionQuery->update(duration); - - mRendering.update(duration); - - Ogre::ControllerManager::getSingleton().setTimeFactor(paused ? 0.f : 1.f); - - Ogre::Vector3 cam = mRendering.getCamera()->getRealPosition(); - - applyFog(world->isUnderwater(player.getCell(), cam)); - - mCamera->update(duration, paused); - - Ogre::SceneNode *node = data.getBaseNode(); - Ogre::Quaternion orient = node->_getDerivedOrientation(); - mLocalMap->updatePlayer(playerPos, orient); - - if(paused) - return; - - mEffectManager->update(duration, mRendering.getCamera()); - - mActors->update (mRendering.getCamera()); - mPlayerAnimation->preRender(mRendering.getCamera()); - mObjects->update (duration, mRendering.getCamera()); - - mSkyManager->update(duration); - - mSkyManager->setGlare(mOcclusionQuery->getSunVisibility()); - - mWater->changeCell(player.getCell()->getCell()); - - mWater->updateUnderwater(world->isUnderwater(player.getCell(), cam)); - - mWater->update(duration, playerPos); -} - -void RenderingManager::preRenderTargetUpdate(const RenderTargetEvent &evt) -{ - mOcclusionQuery->setActive(true); -} - -void RenderingManager::postRenderTargetUpdate(const RenderTargetEvent &evt) -{ - // deactivate queries to make sure we aren't getting false results from several misc render targets - // (will be reactivated at the bottom of this method) - mOcclusionQuery->setActive(false); -} - -void RenderingManager::setWaterEnabled(bool enable) -{ - mWater->setActive(enable); -} - -void RenderingManager::setWaterHeight(float height) -{ - mWater->setHeight(height); -} - -void RenderingManager::skyEnable () -{ - mSkyManager->enable(); - mOcclusionQuery->setSunNode(mSkyManager->getSunNode()); -} - -void RenderingManager::skyDisable () -{ - mSkyManager->disable(); -} - -void RenderingManager::skySetHour (double hour) -{ - mSkyManager->setHour(hour); -} - - -void RenderingManager::skySetDate (int day, int month) -{ - mSkyManager->setDate(day, month); -} - -int RenderingManager::skyGetMasserPhase() const -{ - - return mSkyManager->getMasserPhase(); -} - -int RenderingManager::skyGetSecundaPhase() const -{ - return mSkyManager->getSecundaPhase(); -} - -void RenderingManager::skySetMoonColour (bool red){ - mSkyManager->setMoonColour(red); -} - -bool RenderingManager::toggleRenderMode(int mode) -{ -#if 0 - if (mode == MWBase::World::Render_CollisionDebug || mode == MWBase::World::Render_Pathgrid) - return mDebugging->toggleRenderMode(mode); - if (mode == MWBase::World::Render_Wireframe) - { - if (mRendering.getCamera()->getPolygonMode() == PM_SOLID) - { - mRendering.getCamera()->setPolygonMode(PM_WIREFRAME); - return true; - } - else - { - mRendering.getCamera()->setPolygonMode(PM_SOLID); - return false; - } - } - else //if (mode == MWBase::World::Render_BoundingBoxes) - { - bool show = !mRendering.getScene()->getShowBoundingBoxes(); - mRendering.getScene()->showBoundingBoxes(show); - return show; - } -#endif - return 0; -} - -void RenderingManager::configureFog(const MWWorld::CellStore &mCell) -{ - Ogre::ColourValue color; - color.setAsABGR (mCell.getCell()->mAmbi.mFog); - - configureFog (mCell.getCell()->mAmbi.mFogDensity, color); -} - -void RenderingManager::configureFog(const float density, const Ogre::ColourValue& colour) +namespace MWRender { - mFogColour = colour; - float max = Settings::Manager::getFloat("viewing distance", "Viewing distance"); - if (density == 0) - { - mFogStart = 0; - mFogEnd = std::numeric_limits::max(); - mRendering.getCamera()->setFarClipDistance (max); - } - else + RenderingManager::RenderingManager(osgViewer::Viewer &viewer, osg::ref_ptr rootNode, Resource::ResourceSystem* resourceSystem) + : mViewer(viewer) + , mRootNode(rootNode) + , mResourceSystem(resourceSystem) { - mFogStart = max / (density) * Settings::Manager::getFloat("fog start factor", "Viewing distance"); - mFogEnd = max / (density) * Settings::Manager::getFloat("fog end factor", "Viewing distance"); - mRendering.getCamera()->setFarClipDistance (max / density); - } + osg::ref_ptr lightRoot = new SceneUtil::LightManager; + lightRoot->setStartLight(1); -} + mRootNode->addChild(lightRoot); -void RenderingManager::applyFog (bool underwater) -{ - if (!underwater) - { - mRendering.getScene()->setFog (FOG_LINEAR, mFogColour, 0, mFogStart, mFogEnd); - mRendering.getViewport()->setBackgroundColour (mFogColour); - mWater->setViewportBackground (mFogColour); - } - else - { - Ogre::ColourValue clv(0.090195f, 0.115685f, 0.12745f); - mRendering.getScene()->setFog (FOG_LINEAR, Ogre::ColourValue(clv), 0, 0, 1000); - mRendering.getViewport()->setBackgroundColour (Ogre::ColourValue(clv)); - mWater->setViewportBackground (Ogre::ColourValue(clv)); - } -} + mObjects.reset(new Objects(mResourceSystem, lightRoot)); -void RenderingManager::setAmbientMode() -{ - setAmbientColour(mAmbientColor); -} + mViewer.setLightingMode(osgViewer::View::NO_LIGHT); -void RenderingManager::configureAmbient(MWWorld::CellStore &mCell) -{ - if (mCell.getCell()->mData.mFlags & ESM::Cell::Interior) - mAmbientColor.setAsABGR (mCell.getCell()->mAmbi.mAmbient); - setAmbientMode(); + osg::ref_ptr source = new osg::LightSource; + mSunLight = new osg::Light; + source->setLight(mSunLight); + mSunLight->setDiffuse(osg::Vec4f(0,0,0,1)); + mSunLight->setAmbient(osg::Vec4f(0,0,0,1)); + mSunLight->setConstantAttenuation(1.f); + source->setStateSetModes(*rootNode->getOrCreateStateSet(), osg::StateAttribute::ON); + lightRoot->addChild(source); - // Create a "sun" that shines light downwards. It doesn't look - // completely right, but leave it for now. - if(!mSun) - { - mSun = mRendering.getScene()->createLight(); - mSun->setType(Ogre::Light::LT_DIRECTIONAL); - } - if (mCell.getCell()->mData.mFlags & ESM::Cell::Interior) - { - Ogre::ColourValue colour; - colour.setAsABGR (mCell.getCell()->mAmbi.mSunlight); - mSun->setDiffuseColour (colour); - mSun->setDirection(1,-1,-1); - sunEnable(false); - } -} + rootNode->getOrCreateStateSet()->setMode(GL_CULL_FACE, osg::StateAttribute::ON); + rootNode->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::ON); + rootNode->getOrCreateStateSet()->setMode(GL_NORMALIZE, osg::StateAttribute::ON); -void RenderingManager::setSunColour(const Ogre::ColourValue& colour) -{ - if (!mSunEnabled) return; - mSun->setDiffuseColour(colour); - mSun->setSpecularColour(colour); -} - -void RenderingManager::setAmbientColour(const Ogre::ColourValue& colour) -{ - mAmbientColor = colour; - - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); - int nightEye = static_cast(player.getClass().getCreatureStats(player).getMagicEffects().get(ESM::MagicEffect::NightEye).getMagnitude()); - Ogre::ColourValue final = colour; - final += Ogre::ColourValue(0.7f,0.7f,0.7f,0) * std::min(1.f, (nightEye/100.f)); - - mRendering.getScene()->setAmbientLight(final); -} - -void RenderingManager::sunEnable(bool real) -{ - if (real && mSun) mSun->setVisible(true); - else - { - // Don't disable the light, as the shaders assume the first light to be directional. - mSunEnabled = true; + // for consistent benchmarks against the ogre branch. remove later + osg::CullStack::CullingMode cullingMode = viewer.getCamera()->getCullingMode(); + cullingMode &= ~(osg::CullStack::SMALL_FEATURE_CULLING); + viewer.getCamera()->setCullingMode( cullingMode ); } -} - -void RenderingManager::sunDisable(bool real) -{ - if (real && mSun) mSun->setVisible(false); - else - { - // Don't disable the light, as the shaders assume the first light to be directional. - mSunEnabled = false; - if (mSun) - { - mSun->setDiffuseColour(ColourValue(0,0,0)); - mSun->setSpecularColour(ColourValue(0,0,0)); - } - } -} - -void RenderingManager::setSunDirection(const Ogre::Vector3& direction, bool is_night) -{ - // direction * -1 (because 'direction' is camera to sun vector and not sun to camera), - if (mSun) mSun->setDirection(Vector3(-direction.x, -direction.y, -direction.z)); - - mSkyManager->setSunDirection(direction, is_night); -} - -void RenderingManager::setGlare(bool glare) -{ - mSkyManager->setGlare(glare); -} -void RenderingManager::updateTerrain() -{ - if (mTerrain) + MWRender::Objects& RenderingManager::getObjects() { - // Avoid updating with dims.getCenter for each cell. Player position should be good enough - mTerrain->update(mRendering.getCamera()->getRealPosition()); - mTerrain->syncLoad(); - // need to update again so the chunks that were just loaded can be made visible - mTerrain->update(mRendering.getCamera()->getRealPosition()); + return *mObjects.get(); } -} -void RenderingManager::requestMap(MWWorld::CellStore* cell) -{ - if (cell->getCell()->isExterior()) + MWRender::Actors& RenderingManager::getActors() { - assert(mTerrain); - - Ogre::AxisAlignedBox dims = mObjects->getDimensions(cell); - Ogre::Vector2 center (cell->getCell()->getGridX() + 0.5f, cell->getCell()->getGridY() + 0.5f); - dims.merge(mTerrain->getWorldBoundingBox(center)); - - mLocalMap->requestMap(cell, dims.getMinimum().z, dims.getMaximum().z); + throw std::runtime_error("unimplemented"); } - else - mLocalMap->requestMap(cell, mObjects->getDimensions(cell)); -} - -void RenderingManager::writeFog(MWWorld::CellStore* cell) -{ - mLocalMap->saveFogOfWar(cell); -} - -void RenderingManager::disableLights(bool sun) -{ - mActors->disableLights(); - sunDisable(sun); -} - -void RenderingManager::enableLights(bool sun) -{ - mActors->enableLights(); - sunEnable(sun); -} - -void RenderingManager::notifyWorldSpaceChanged() -{ - mEffectManager->clear(); - mWater->clearRipples(); -} - -Ogre::Vector4 RenderingManager::boundingBoxToScreen(Ogre::AxisAlignedBox bounds) -{ - Ogre::Matrix4 mat = mRendering.getCamera()->getViewMatrix(); - - const Ogre::Vector3* corners = bounds.getAllCorners(); - - float min_x = 1.0f, max_x = 0.0f, min_y = 1.0f, max_y = 0.0f; - // expand the screen-space bounding-box so that it completely encloses - // the object's AABB - for (int i=0; i<8; i++) + Resource::ResourceSystem* RenderingManager::getResourceSystem() { - Ogre::Vector3 corner = corners[i]; - - // multiply the AABB corner vertex by the view matrix to - // get a camera-space vertex - corner = mat * corner; - - // make 2D relative/normalized coords from the view-space vertex - // by dividing out the Z (depth) factor -- this is an approximation - float x = corner.x / corner.z + 0.5f; - float y = corner.y / corner.z + 0.5f; - - if (x < min_x) - min_x = x; - - if (x > max_x) - max_x = x; - - if (y < min_y) - min_y = y; - - if (y > max_y) - max_y = y; + return mResourceSystem; } - return Vector4(min_x, min_y, max_x, max_y); -} - -void RenderingManager::processChangedSettings(const Settings::CategorySettingVector& settings) -{ - bool changeRes = false; - bool rebuild = false; // rebuild static geometry (necessary after any material changes) - for (Settings::CategorySettingVector::const_iterator it=settings.begin(); - it != settings.end(); ++it) + void RenderingManager::configureAmbient(const ESM::Cell *cell) { - if (it->second == "menu transparency" && it->first == "GUI") - { - setMenuTransparency(Settings::Manager::getFloat("menu transparency", "GUI")); - } - else if (it->second == "viewing distance" && it->first == "Viewing distance") - { - if (!MWBase::Environment::get().getWorld()->isCellExterior() && !MWBase::Environment::get().getWorld()->isCellQuasiExterior() - && MWBase::Environment::get().getWorld()->getPlayerPtr().mCell) - configureFog(*MWBase::Environment::get().getWorld()->getPlayerPtr().getCell()); - } - else if (it->first == "Video" && ( - it->second == "resolution x" - || it->second == "resolution y" - || it->second == "fullscreen")) - changeRes = true; - else if (it->first == "Video" && it->second == "window border") - changeRes = true; - else if (it->second == "field of view" && it->first == "General") - mRendering.setFov(Settings::Manager::getFloat("field of view", "General")); - else if (it->second == "gamma" && it->first == "General") - { - mRendering.setWindowGammaContrast(Settings::Manager::getFloat("gamma", "General"), Settings::Manager::getFloat("contrast", "General")); - } - else if ((it->second == "texture filtering" && it->first == "General") - || (it->second == "anisotropy" && it->first == "General")) - { - TextureFilterOptions tfo; - std::string filter = Settings::Manager::getString("texture filtering", "General"); - if (filter == "anisotropic") tfo = TFO_ANISOTROPIC; - else if (filter == "trilinear") tfo = TFO_TRILINEAR; - else if (filter == "bilinear") tfo = TFO_BILINEAR; - else /*if (filter == "none")*/ tfo = TFO_NONE; + osg::ref_ptr lightmodel = new osg::LightModel; + lightmodel->setAmbientIntensity(SceneUtil::colourFromRGB(cell->mAmbi.mAmbient)); + mRootNode->getOrCreateStateSet()->setAttributeAndModes(lightmodel, osg::StateAttribute::ON); - MaterialManager::getSingleton().setDefaultTextureFiltering(tfo); - MaterialManager::getSingleton().setDefaultAnisotropy( (filter == "anisotropic") ? Settings::Manager::getInt("anisotropy", "General") : 1 ); - } - else if (it->second == "shader" && it->first == "Water") - { - sh::Factory::getInstance ().setGlobalSetting ("simple_water", Settings::Manager::getBool("shader", "Water") ? "false" : "true"); - rebuild = true; - mRendering.getViewport ()->setClearEveryFrame (true); - } - else if (it->second == "refraction" && it->first == "Water") - { - sh::Factory::getInstance ().setGlobalSetting ("refraction", Settings::Manager::getBool("refraction", "Water") ? "true" : "false"); - rebuild = true; - } - else if (it->second == "shaders" && it->first == "Objects") - { - sh::Factory::getInstance ().setShadersEnabled (Settings::Manager::getBool("shaders", "Objects")); - rebuild = true; - } - else if (it->second == "shader mode" && it->first == "General") - { - sh::Language lang; - std::string l = Settings::Manager::getString("shader mode", "General"); - if (l == "glsl") - lang = sh::Language_GLSL; - else if (l == "hlsl") - lang = sh::Language_HLSL; - else - lang = sh::Language_CG; - sh::Factory::getInstance ().setCurrentLanguage (lang); - rebuild = true; - } + mSunLight->setDiffuse(SceneUtil::colourFromRGB(cell->mAmbi.mSunlight)); + mSunLight->setDirection(osg::Vec3f(1.f,-1.f,-1.f)); } - if (changeRes) + osg::Vec3f RenderingManager::getEyePos() { - unsigned int x = Settings::Manager::getInt("resolution x", "Video"); - unsigned int y = Settings::Manager::getInt("resolution y", "Video"); - bool fullscreen = Settings::Manager::getBool("fullscreen", "Video"); - bool windowBorder = Settings::Manager::getBool("window border", "Video"); - - SDL_Window* window = mRendering.getSDLWindow(); - - SDL_SetWindowFullscreen(window, 0); - - if (SDL_GetWindowFlags(window) & SDL_WINDOW_MAXIMIZED) - SDL_RestoreWindow(window); - - if (fullscreen) - { - SDL_DisplayMode mode; - SDL_GetWindowDisplayMode(window, &mode); - mode.w = x; - mode.h = y; - SDL_SetWindowDisplayMode(window, &mode); - SDL_SetWindowFullscreen(window, fullscreen); - } - else - { - SDL_SetWindowSize(window, x, y); - SDL_SetWindowBordered(window, windowBorder ? SDL_TRUE : SDL_FALSE); - } + osg::Vec3d eye; + //mViewer.getCamera()->getViewMatrixAsLookAt(eye, center, up); + eye = mViewer.getCameraManipulator()->getMatrix().getTrans(); + return eye; } - mWater->processChangedSettings(settings); - - if (rebuild) + void RenderingManager::removeCell(const MWWorld::CellStore *store) { - mObjects->rebuildStaticGeometry(); - if (mTerrain) - mTerrain->applyMaterials(Settings::Manager::getBool("enabled", "Shadows"), - Settings::Manager::getBool("split", "Shadows")); + mObjects->removeCell(store); } -} - -void RenderingManager::setMenuTransparency(float val) -{ - Ogre::TexturePtr tex = Ogre::TextureManager::getSingleton().getByName("transparent.png"); std::vector buffer; - buffer.resize(1); - buffer[0] = (int(255*val) << 24) | (255 << 16) | (255 << 8) | 255; - memcpy(tex->getBuffer()->lock(Ogre::HardwareBuffer::HBL_DISCARD), &buffer[0], 1*4); - tex->getBuffer()->unlock(); -} -void RenderingManager::windowResized(int x, int y) -{ - Settings::Manager::setInt("resolution x", "Video", x); - Settings::Manager::setInt("resolution y", "Video", y); - mRendering.adjustViewport(); - - MWBase::Environment::get().getWindowManager()->windowResized(x,y); } - -void RenderingManager::getTriangleBatchCount(unsigned int &triangles, unsigned int &batches) -{ - batches = mRendering.getWindow()->getBatchCount(); - triangles = mRendering.getWindow()->getTriangleCount(); -} - -void RenderingManager::setupPlayer(const MWWorld::Ptr &ptr) -{ - ptr.getRefData().setBaseNode(mRendering.getScene()->getSceneNode("player")); - attachCameraTo(ptr); -} - -void RenderingManager::attachCameraTo(const MWWorld::Ptr &ptr) -{ - Ogre::SceneNode* cameraNode = mCamera->attachTo(ptr); - mSkyManager->attachToNode(cameraNode); -} - -void RenderingManager::renderPlayer(const MWWorld::Ptr &ptr) -{ - if(!mPlayerAnimation) - { - mPlayerAnimation = new NpcAnimation(ptr, ptr.getRefData().getBaseNode(), RV_Actors); - } - else - { - // Reconstruct the NpcAnimation in-place - mPlayerAnimation->~NpcAnimation(); - new(mPlayerAnimation) NpcAnimation(ptr, ptr.getRefData().getBaseNode(), RV_Actors); - } - - mCamera->setAnimation(mPlayerAnimation); - mWater->removeEmitter(ptr); - mWater->addEmitter(ptr); - // apply race height - MWBase::Environment::get().getWorld()->scaleObject(ptr, 1.f); -} - -bool RenderingManager::vanityRotateCamera(const float *rot) -{ - if(!mCamera->isVanityOrPreviewModeEnabled()) - return false; - - Ogre::Vector3 vRot(rot); - mCamera->rotateCamera(vRot, true); - return true; -} - -void RenderingManager::setCameraDistance(float dist, bool adjust, bool override) -{ - if(!mCamera->isVanityOrPreviewModeEnabled() && !mCamera->isFirstPerson()) - { - if(mCamera->isNearest() && dist > 0.f) - mCamera->toggleViewMode(); - else - mCamera->setCameraDistance(-dist / 120.f * 10, adjust, override); - } - else if(mCamera->isFirstPerson() && dist < 0.f) - { - mCamera->toggleViewMode(); - mCamera->setCameraDistance(0.f, false, override); - } -} - -void RenderingManager::worldToInteriorMapPosition (Ogre::Vector2 position, float& nX, float& nY, int &x, int& y) -{ - return mLocalMap->worldToInteriorMapPosition (position, nX, nY, x, y); -} - -Ogre::Vector2 RenderingManager::interiorMapToWorldPosition(float nX, float nY, int x, int y) -{ - return mLocalMap->interiorMapToWorldPosition(nX, nY, x, y); -} - -bool RenderingManager::isPositionExplored (float nX, float nY, int x, int y, bool interior) -{ - return mLocalMap->isPositionExplored(nX, nY, x, y, interior); -} - -Animation* RenderingManager::getAnimation(const MWWorld::Ptr &ptr) -{ - Animation *anim = mActors->getAnimation(ptr); - - if(!anim && ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) - anim = mPlayerAnimation; - - if (!anim) - anim = mObjects->getAnimation(ptr); - - return anim; -} - -void RenderingManager::screenshot(Image &image, int w, int h) -{ - // Create a temporary render target. We do not use the RenderWindow since we want a specific size. - // Also, the GUI should not be visible (and it is only rendered on the RenderWindow's primary viewport) - const std::string tempName = "@temp"; - Ogre::TexturePtr texture = Ogre::TextureManager::getSingleton().createManual(tempName, - Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::TEX_TYPE_2D, w, h, 0, Ogre::PF_R8G8B8, Ogre::TU_RENDERTARGET); - - float oldAspect = mRendering.getCamera()->getAspectRatio(); - - mRendering.getCamera()->setAspectRatio(w / static_cast(h)); - - Ogre::RenderTarget* rt = texture->getBuffer()->getRenderTarget(); - Ogre::Viewport* vp = rt->addViewport(mRendering.getCamera()); - vp->setBackgroundColour(mRendering.getViewport()->getBackgroundColour()); - vp->setOverlaysEnabled(false); - vp->setVisibilityMask(mRendering.getViewport()->getVisibilityMask()); - rt->update(); - - Ogre::PixelFormat pf = rt->suggestPixelFormat(); - - image.loadDynamicImage( - OGRE_ALLOC_T(Ogre::uchar, w * h * Ogre::PixelUtil::getNumElemBytes(pf), Ogre::MEMCATEGORY_GENERAL), - w, h, 1, pf, true // autoDelete=true, frees memory we allocate - ); - rt->copyContentsToMemory(image.getPixelBox()); // getPixelBox returns a box sharing the same memory as the image - - Ogre::TextureManager::getSingleton().remove(tempName); - mRendering.getCamera()->setAspectRatio(oldAspect); -} - -void RenderingManager::addWaterRippleEmitter (const MWWorld::Ptr& ptr, float scale, float force) -{ - mWater->addEmitter (ptr, scale, force); -} - -void RenderingManager::removeWaterRippleEmitter (const MWWorld::Ptr& ptr) -{ - mWater->removeEmitter (ptr); -} - -void RenderingManager::updateWaterRippleEmitterPtr (const MWWorld::Ptr& old, const MWWorld::Ptr& ptr) -{ - mWater->updateEmitterPtr(old, ptr); -} - -void RenderingManager::frameStarted(float dt, bool paused) -{ - if (mTerrain) - mTerrain->update(mRendering.getCamera()->getRealPosition()); - - if (!paused) - mWater->frameStarted(dt); -} - -void RenderingManager::resetCamera() -{ - mCamera->reset(); -} - -float RenderingManager::getTerrainHeightAt(Ogre::Vector3 worldPos) -{ - if (!mTerrain || !mTerrain->getVisible()) - return -std::numeric_limits::max(); - return mTerrain->getHeightAt(worldPos); -} - -void RenderingManager::enableTerrain(bool enable) -{ - if (enable) - { - if (!mTerrain) - { - if (Settings::Manager::getBool("distant land", "Terrain")) - mTerrain = new Terrain::DefaultWorld(mRendering.getScene(), new MWRender::TerrainStorage(true), RV_Terrain, - Settings::Manager::getBool("shader", "Terrain"), Terrain::Align_XY, 1, 64); - else - mTerrain = new Terrain::TerrainGrid(mRendering.getScene(), new MWRender::TerrainStorage(false), RV_Terrain, - Settings::Manager::getBool("shader", "Terrain"), Terrain::Align_XY); - mTerrain->applyMaterials(Settings::Manager::getBool("enabled", "Shadows"), - Settings::Manager::getBool("split", "Shadows")); - mTerrain->update(mRendering.getCamera()->getRealPosition()); - } - mTerrain->setVisible(true); - } - else if (mTerrain) - mTerrain->setVisible(false); -} - -float RenderingManager::getCameraDistance() const -{ - return mCamera->getCameraDistance(); -} - -void RenderingManager::spawnEffect(const std::string &model, const std::string &texture, const Vector3 &worldPosition, float scale) -{ - mEffectManager->addEffect(model, texture, worldPosition, scale); -} - -void RenderingManager::clear() -{ - mLocalMap->clear(); - notifyWorldSpaceChanged(); -} - -} // namespace diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 5bfd8ae77..f0c5040f2 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -1,270 +1,61 @@ -#ifndef GAME_RENDERING_MANAGER_H -#define GAME_RENDERING_MANAGER_H +#ifndef OPENMW_MWRENDER_RENDERINGMANAGER_H +#define OPENMW_MWRENDER_RENDERINGMANAGER_H -#include "sky.hpp" -#include "debugging.hpp" +#include +#include -#include - -#include - -#include +#include "objects.hpp" #include "renderinginterface.hpp" -#include "objects.hpp" -#include "actors.hpp" -#include "camera.hpp" -#include "occlusionquery.hpp" - -namespace Ogre +namespace osg { - class SceneNode; + class Group; } -namespace MWWorld +namespace Resource { - class Ptr; - class CellStore; + class ResourceSystem; } -namespace sh +namespace osgViewer { - class Factory; + class Viewer; } -namespace Terrain +namespace ESM { - class World; + struct Cell; } namespace MWRender { - class Shadows; - class LocalMap; - class Water; - class GlobalMap; - class Animation; - class EffectManager; - -class RenderingManager: private RenderingInterface, public Ogre::RenderTargetListener, public OEngine::Render::WindowSizeListener -{ -private: - virtual MWRender::Objects& getObjects(); - virtual MWRender::Actors& getActors(); - -public: - RenderingManager(OEngine::Render::OgreRenderer& _rend, const boost::filesystem::path& resDir, - const boost::filesystem::path& cacheDir, OEngine::Physic::PhysicEngine* engine, - MWWorld::Fallback* fallback); - virtual ~RenderingManager(); - - void togglePOV() - { mCamera->toggleViewMode(); } - void togglePreviewMode(bool enable) - { mCamera->togglePreviewMode(enable); } - - bool toggleVanityMode(bool enable) - { return mCamera->toggleVanityMode(enable); } - - void allowVanityMode(bool allow) - { mCamera->allowVanityMode(allow); } - - void togglePlayerLooking(bool enable) - { mCamera->togglePlayerLooking(enable); } - - void changeVanityModeScale(float factor) + class RenderingManager : public MWRender::RenderingInterface { - if(mCamera->isVanityOrPreviewModeEnabled()) - mCamera->setCameraDistance(-factor/120.f*10, true, true); - } - - void resetCamera(); - - bool vanityRotateCamera(const float *rot); - void setCameraDistance(float dist, bool adjust = false, bool override = true); - float getCameraDistance() const; - - void setupPlayer(const MWWorld::Ptr &ptr); - void renderPlayer(const MWWorld::Ptr &ptr); - - SkyManager* getSkyManager(); - - MWRender::Camera* getCamera() const; - - bool toggleRenderMode(int mode); - - void removeCell (MWWorld::CellStore *store); - - /// \todo this function should be removed later. Instead the rendering subsystems should track - /// when rebatching is needed and update automatically at the end of each frame. - void cellAdded (MWWorld::CellStore *store); - - /// Clear all savegame-specific data (i.e. fog of war textures) - void clear(); - - void enableTerrain(bool enable); - - void removeWater(); - - /// Write current fog of war for this cell to the CellStore - void writeFog (MWWorld::CellStore* store); - - void addObject (const MWWorld::Ptr& ptr, const std::string& model); - void removeObject (const MWWorld::Ptr& ptr); - - void moveObject (const MWWorld::Ptr& ptr, const Ogre::Vector3& position); - void scaleObject (const MWWorld::Ptr& ptr, const Ogre::Vector3& scale); - - /// Updates an object's rotation - void rotateObject (const MWWorld::Ptr& ptr); - - void setWaterHeight(float height); - void setWaterEnabled(bool enabled); - bool toggleWater(); - bool toggleWorld(); - - /// Updates object rendering after cell change - /// \param old Object reference in previous cell - /// \param cur Object reference in new cell - void updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur); - - /// Specifies an updated Ptr object for the player (used on cell change). - void updatePlayerPtr(const MWWorld::Ptr &ptr); - - /// Currently for NPCs only. Rebuilds the NPC, updating their root model, animation sources, - /// and equipment. - void rebuildPtr(const MWWorld::Ptr &ptr); - - void update (float duration, bool paused); - - void setAmbientColour(const Ogre::ColourValue& colour); - void setSunColour(const Ogre::ColourValue& colour); - void setSunDirection(const Ogre::Vector3& direction, bool is_night); - void sunEnable(bool real); ///< @param real whether or not to really disable the sunlight (otherwise just set diffuse to 0) - void sunDisable(bool real); - - void disableLights(bool sun); ///< @param sun whether or not to really disable the sunlight (otherwise just set diffuse to 0) - void enableLights(bool sun); - - - void preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt); - void postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt); - - bool occlusionQuerySupported() { return mOcclusionQuery->supported(); } - OcclusionQuery* getOcclusionQuery() { return mOcclusionQuery; } - - float getTerrainHeightAt (Ogre::Vector3 worldPos); - - void notifyWorldSpaceChanged(); - - void getTriangleBatchCount(unsigned int &triangles, unsigned int &batches); - - void setGlare(bool glare); - void skyEnable (); - void skyDisable (); - void skySetHour (double hour); - void skySetDate (int day, int month); - int skyGetMasserPhase() const; - int skyGetSecundaPhase() const; - void skySetMoonColour (bool red); - void configureAmbient(MWWorld::CellStore &mCell); - - void addWaterRippleEmitter (const MWWorld::Ptr& ptr, float scale = 1.f, float force = 1.f); - void removeWaterRippleEmitter (const MWWorld::Ptr& ptr); - void updateWaterRippleEmitterPtr (const MWWorld::Ptr& old, const MWWorld::Ptr& ptr); - - void updateTerrain (); - ///< update the terrain according to the player position. Usually done automatically, but should be done manually - /// before calling requestMap - - void requestMap (MWWorld::CellStore* cell); - ///< request the local map for a cell - - /// configure fog according to cell - void configureFog(const MWWorld::CellStore &mCell); - - /// configure fog manually - void configureFog(const float density, const Ogre::ColourValue& colour); - - Ogre::Vector4 boundingBoxToScreen(Ogre::AxisAlignedBox bounds); - ///< transform the specified bounding box (in world coordinates) into screen coordinates. - /// @return packed vector4 (min_x, min_y, max_x, max_y) - - void processChangedSettings(const Settings::CategorySettingVector& settings); - - Ogre::Viewport* getViewport() { return mRendering.getViewport(); } - - void worldToInteriorMapPosition (Ogre::Vector2 position, float& nX, float& nY, int &x, int& y); - ///< see MWRender::LocalMap::worldToInteriorMapPosition - - Ogre::Vector2 interiorMapToWorldPosition (float nX, float nY, int x, int y); - ///< see MWRender::LocalMap::interiorMapToWorldPosition - - bool isPositionExplored (float nX, float nY, int x, int y, bool interior); - ///< see MWRender::LocalMap::isPositionExplored - - Animation* getAnimation(const MWWorld::Ptr &ptr); - - void frameStarted(float dt, bool paused); - void screenshot(Ogre::Image& image, int w, int h); - - void spawnEffect (const std::string& model, const std::string& texture, const Ogre::Vector3& worldPosition, float scale=1.f); - -protected: - virtual void windowResized(int x, int y); - -private: - sh::Factory* mFactory; - - void setAmbientMode(); - void applyFog(bool underwater); - - void attachCameraTo(const MWWorld::Ptr& ptr); - - void setMenuTransparency(float val); - - bool mSunEnabled; - - MWWorld::Fallback* mFallback; - - SkyManager* mSkyManager; - - OcclusionQuery* mOcclusionQuery; - - Terrain::World* mTerrain; - - MWRender::Water *mWater; - - GlobalMap* mGlobalMap; - - OEngine::Render::OgreRenderer &mRendering; - - MWRender::Objects* mObjects; - MWRender::Actors* mActors; - - MWRender::EffectManager* mEffectManager; + public: + RenderingManager(osgViewer::Viewer& viewer, osg::ref_ptr rootNode, Resource::ResourceSystem* resourceSystem); - MWRender::NpcAnimation *mPlayerAnimation; + MWRender::Objects& getObjects(); + MWRender::Actors& getActors(); - Ogre::ColourValue mAmbientColor; - Ogre::Light* mSun; + Resource::ResourceSystem* getResourceSystem(); - Ogre::SceneNode *mRootNode; + void configureAmbient(const ESM::Cell* cell); - Ogre::ColourValue mFogColour; - float mFogStart; - float mFogEnd; + void removeCell(const MWWorld::CellStore* store); - OEngine::Physic::PhysicEngine* mPhysicsEngine; + osg::Vec3f getEyePos(); - MWRender::Camera *mCamera; + private: + osgViewer::Viewer& mViewer; + osg::ref_ptr mRootNode; + Resource::ResourceSystem* mResourceSystem; - MWRender::LocalMap* mLocalMap; + osg::ref_ptr mSunLight; - bool mRenderWorld; -}; + std::auto_ptr mObjects; + }; } diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index f87983ce8..e71a4a34b 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -686,10 +686,10 @@ namespace MWScript else throw std::runtime_error ("invalid movement axis: " + axis); - if (!ptr.getRefData().getBaseNode()) + if (!ptr.getRefData().getBaseNodeOld()) return; - Ogre::Vector3 diff = ptr.getRefData().getBaseNode()->getOrientation() * posChange; + Ogre::Vector3 diff = ptr.getRefData().getBaseNodeOld()->getOrientation() * posChange; Ogre::Vector3 worldPos(ptr.getRefData().getPosition().pos); worldPos += diff; MWBase::Environment::get().getWorld()->moveObject(ptr, worldPos.x, worldPos.y, worldPos.z); diff --git a/apps/openmw/mwworld/cellfunctors.hpp b/apps/openmw/mwworld/cellfunctors.hpp index 5115fa02d..cf6f7bf56 100644 --- a/apps/openmw/mwworld/cellfunctors.hpp +++ b/apps/openmw/mwworld/cellfunctors.hpp @@ -20,11 +20,11 @@ namespace MWWorld bool operator() (MWWorld::Ptr ptr) { - Ogre::SceneNode* handle = ptr.getRefData().getBaseNode(); + Ogre::SceneNode* handle = ptr.getRefData().getBaseNodeOld(); if (handle) mHandles.push_back (handle); - ptr.getRefData().setBaseNode(0); + ptr.getRefData().setBaseNodeOld(0); return true; } }; diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index d4aadc6c7..371543f2e 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -242,7 +242,7 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& itemPtr MWWorld::Ptr item = *it; // we may have copied an item from the world, so reset a few things first - item.getRefData().setBaseNode(NULL); // Especially important, otherwise scripts on the item could think that it's actually in a cell + item.getRefData().setBaseNodeOld(NULL); // Especially important, otherwise scripts on the item could think that it's actually in a cell ESM::Position pos; pos.rot[0] = 0; pos.rot[1] = 0; diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index a59efecfe..b8e4a06a8 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -653,7 +653,7 @@ namespace MWWorld std::vector PhysicsSystem::getCollisions(const Ptr &ptr, int collisionGroup, int collisionMask) { - return mEngine->getCollisions(ptr.getRefData().getBaseNode()->getName(), collisionGroup, collisionMask); + return mEngine->getCollisions(ptr.getRefData().getBaseNodeOld()->getName(), collisionGroup, collisionMask); } Ogre::Vector3 PhysicsSystem::traceDown(const MWWorld::Ptr &ptr, float maxHeight) @@ -675,7 +675,7 @@ namespace MWWorld void PhysicsSystem::addObject (const Ptr& ptr, const std::string& mesh, bool placeable) { - Ogre::SceneNode* node = ptr.getRefData().getBaseNode(); + Ogre::SceneNode* node = ptr.getRefData().getBaseNodeOld(); handleToMesh[node->getName()] = mesh; mEngine->createAndAdjustRigidBody( mesh, node->getName(), ptr.getCellRef().getScale(), node->getPosition(), node->getOrientation(), 0, 0, false, placeable); @@ -685,7 +685,7 @@ namespace MWWorld void PhysicsSystem::addActor (const Ptr& ptr, const std::string& mesh) { - Ogre::SceneNode* node = ptr.getRefData().getBaseNode(); + Ogre::SceneNode* node = ptr.getRefData().getBaseNodeOld(); //TODO:optimize this. Searching the std::map isn't very efficient i think. mEngine->addCharacter(node->getName(), mesh, node->getPosition(), node->getScale().x, node->getOrientation()); } @@ -699,7 +699,7 @@ namespace MWWorld void PhysicsSystem::moveObject (const Ptr& ptr) { - Ogre::SceneNode *node = ptr.getRefData().getBaseNode(); + Ogre::SceneNode *node = ptr.getRefData().getBaseNodeOld(); const std::string &handle = node->getName(); const Ogre::Vector3 &position = node->getPosition(); @@ -722,7 +722,7 @@ namespace MWWorld void PhysicsSystem::rotateObject (const Ptr& ptr) { - Ogre::SceneNode* node = ptr.getRefData().getBaseNode(); + Ogre::SceneNode* node = ptr.getRefData().getBaseNodeOld(); const std::string &handle = node->getName(); const Ogre::Quaternion &rotation = node->getOrientation(); @@ -751,7 +751,7 @@ namespace MWWorld void PhysicsSystem::scaleObject (const Ptr& ptr) { - Ogre::SceneNode* node = ptr.getRefData().getBaseNode(); + Ogre::SceneNode* node = ptr.getRefData().getBaseNodeOld(); const std::string &handle = node->getName(); if(handleToMesh.find(handle) != handleToMesh.end()) { diff --git a/apps/openmw/mwworld/refdata.cpp b/apps/openmw/mwworld/refdata.cpp index 14a315a81..7e83fda5e 100644 --- a/apps/openmw/mwworld/refdata.cpp +++ b/apps/openmw/mwworld/refdata.cpp @@ -134,14 +134,23 @@ namespace MWWorld return mBaseNode->getName(); } - Ogre::SceneNode* RefData::getBaseNode() + Ogre::SceneNode* RefData::getBaseNodeOld() { return mBaseNode; } - void RefData::setBaseNode(Ogre::SceneNode* base) + void RefData::setBaseNodeOld(Ogre::SceneNode* base) { - mBaseNode = base; + } + + void RefData::setBaseNode(osg::PositionAttitudeTransform *base) + { + mBase = base; + } + + osg::PositionAttitudeTransform* RefData::getBaseNode() + { + return mBase; } int RefData::getCount() const diff --git a/apps/openmw/mwworld/refdata.hpp b/apps/openmw/mwworld/refdata.hpp index e90b44f9c..2099b859f 100644 --- a/apps/openmw/mwworld/refdata.hpp +++ b/apps/openmw/mwworld/refdata.hpp @@ -10,6 +10,11 @@ namespace Ogre class SceneNode; } +namespace osg +{ + class PositionAttitudeTransform; +} + namespace ESM { class Script; @@ -28,7 +33,7 @@ namespace MWWorld class RefData { Ogre::SceneNode* mBaseNode; - + osg::PositionAttitudeTransform* mBase; MWScript::Locals mLocals; // if we find the overhead of heaving a locals // object in the refdata of refs without a script, @@ -78,10 +83,18 @@ namespace MWWorld const std::string &getHandle(); /// Return OGRE base node (can be a null pointer). - Ogre::SceneNode* getBaseNode(); + /// obsolete + Ogre::SceneNode* getBaseNodeOld(); + + /// Return base node (can be a null pointer). + osg::PositionAttitudeTransform* getBaseNode(); /// Set OGRE base node (can be a null pointer). - void setBaseNode (Ogre::SceneNode* base); + /// obsolete + void setBaseNodeOld (Ogre::SceneNode* base); + + /// Set base node (can be a null pointer). + void setBaseNode (osg::PositionAttitudeTransform* base); int getCount() const; diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 6d7408607..1084ae03a 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -6,12 +6,16 @@ #include #include +#include + #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwrender/renderingmanager.hpp" + //#include "physicssystem.hpp" #include "player.hpp" #include "localscripts.hpp" @@ -20,19 +24,20 @@ #include "cellfunctors.hpp" #include "cellstore.hpp" +#include + namespace { -#if 0 - void addObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics, + void addObject(const MWWorld::Ptr& ptr, //MWWorld::PhysicsSystem& physics, MWRender::RenderingManager& rendering) { - std::string model = Misc::ResourceHelpers::correctActorModelPath(ptr.getClass().getModel(ptr)); + std::string model = Misc::ResourceHelpers::correctActorModelPath(ptr.getClass().getModel(ptr), rendering.getResourceSystem()->getVFS()); std::string id = ptr.getClass().getId(ptr); if (id == "prisonmarker" || id == "divinemarker" || id == "templemarker" || id == "northmarker") model = ""; // marker objects that have a hardcoded function in the game logic, should be hidden from the player - rendering.addObject(ptr, model); - ptr.getClass().insertObject (ptr, model, physics); + ptr.getClass().insertObjectRendering(ptr, model, rendering); + //ptr.getClass().insertObject (ptr, model, physics); } void updateObjectLocalRotation (const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics, @@ -40,22 +45,21 @@ namespace { if (ptr.getRefData().getBaseNode() != NULL) { - Ogre::Quaternion worldRotQuat(Ogre::Radian(ptr.getRefData().getPosition().rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z); + osg::Quat worldRotQuat(ptr.getRefData().getPosition().rot[2], osg::Vec3(0,0,-1)); if (!ptr.getClass().isActor()) - worldRotQuat = Ogre::Quaternion(Ogre::Radian(ptr.getRefData().getPosition().rot[0]), Ogre::Vector3::NEGATIVE_UNIT_X)* - Ogre::Quaternion(Ogre::Radian(ptr.getRefData().getPosition().rot[1]), Ogre::Vector3::NEGATIVE_UNIT_Y)* worldRotQuat; + worldRotQuat = worldRotQuat * osg::Quat(ptr.getRefData().getPosition().rot[1], osg::Vec3(0,-1,0)) * + osg::Quat(ptr.getRefData().getPosition().rot[0], osg::Vec3(-1,0,0)); float x = ptr.getRefData().getLocalRotation().rot[0]; float y = ptr.getRefData().getLocalRotation().rot[1]; float z = ptr.getRefData().getLocalRotation().rot[2]; - Ogre::Quaternion rot(Ogre::Radian(z), Ogre::Vector3::NEGATIVE_UNIT_Z); + osg::Quat rot(z, osg::Vec3(0,0,-1)); if (!ptr.getClass().isActor()) - rot = Ogre::Quaternion(Ogre::Radian(x), Ogre::Vector3::NEGATIVE_UNIT_X)* - Ogre::Quaternion(Ogre::Radian(y), Ogre::Vector3::NEGATIVE_UNIT_Y)*rot; + rot = rot * osg::Quat(y, osg::Vec3(0,-1,0)) * osg::Quat(x, osg::Vec3(-1,0,0)); - ptr.getRefData().getBaseNode()->setOrientation(worldRotQuat*rot); - physics.rotateObject(ptr); + ptr.getRefData().getBaseNode()->setAttitude(rot * worldRotQuat); + //physics.rotateObject(ptr); } } @@ -64,20 +68,21 @@ namespace MWWorld::CellStore& mCell; bool mRescale; Loading::Listener& mLoadingListener; - MWWorld::PhysicsSystem& mPhysics; + //MWWorld::PhysicsSystem& mPhysics; MWRender::RenderingManager& mRendering; InsertFunctor (MWWorld::CellStore& cell, bool rescale, Loading::Listener& loadingListener, - MWWorld::PhysicsSystem& physics, MWRender::RenderingManager& rendering); + /*MWWorld::PhysicsSystem& physics, */MWRender::RenderingManager& rendering); bool operator() (const MWWorld::Ptr& ptr); }; InsertFunctor::InsertFunctor (MWWorld::CellStore& cell, bool rescale, - Loading::Listener& loadingListener, MWWorld::PhysicsSystem& physics, + Loading::Listener& loadingListener, /*MWWorld::PhysicsSystem& physics,*/ MWRender::RenderingManager& rendering) : mCell (cell), mRescale (rescale), mLoadingListener (loadingListener), - mPhysics (physics), mRendering (rendering) + //mPhysics (physics), + mRendering (rendering) {} bool InsertFunctor::operator() (const MWWorld::Ptr& ptr) @@ -94,13 +99,13 @@ namespace { try { - addObject(ptr, mPhysics, mRendering); - updateObjectLocalRotation(ptr, mPhysics, mRendering); + addObject(ptr, /*mPhysics, */mRendering); + //updateObjectLocalRotation(ptr, mPhysics, mRendering); if (ptr.getRefData().getBaseNode()) { float scale = ptr.getCellRef().getScale(); ptr.getClass().adjustScale(ptr, scale); - mRendering.scaleObject(ptr, Ogre::Vector3(scale)); + //mRendering.scaleObject(ptr, Ogre::Vector3(scale)); } ptr.getClass().adjustPosition (ptr, false); } @@ -115,7 +120,6 @@ namespace return true; } -#endif } @@ -129,7 +133,7 @@ namespace MWWorld void Scene::updateObjectRotation (const Ptr& ptr) { - if(ptr.getRefData().getBaseNode() != 0) + if(ptr.getRefData().getBaseNodeOld() != 0) { //mRendering.rotateObject(ptr); //mPhysics->rotateObject(ptr); @@ -190,23 +194,24 @@ namespace MWWorld for (std::vector::const_iterator iter2 (functor.mHandles.begin()); iter2!=functor.mHandles.end(); ++iter2) { - Ogre::SceneNode* node = *iter2; + //Ogre::SceneNode* node = *iter2; //mPhysics->removeObject (node->getName()); } } if ((*iter)->getCell()->isExterior()) { - ESM::Land* land = + /*ESM::Land* land = MWBase::Environment::get().getWorld()->getStore().get().search( (*iter)->getCell()->getGridX(), (*iter)->getCell()->getGridY() ); - //if (land && land->mDataTypes&ESM::Land::DATA_VHGT) - //mPhysics->removeHeightField ((*iter)->getCell()->getGridX(), (*iter)->getCell()->getGridY()); + if (land && land->mDataTypes&ESM::Land::DATA_VHGT) + mPhysics->removeHeightField ((*iter)->getCell()->getGridX(), (*iter)->getCell()->getGridY()); + */ } - //mRendering.removeCell(*iter); + mRendering.removeCell(*iter); MWBase::Environment::get().getWorld()->getLocalScripts().clearCell (*iter); @@ -224,8 +229,8 @@ namespace MWWorld { std::cout << "loading cell " << cell->getCell()->getDescription() << std::endl; - float verts = ESM::Land::LAND_SIZE; - float worldsize = ESM::Land::REAL_SIZE; + //float verts = ESM::Land::LAND_SIZE; + //float worldsize = ESM::Land::REAL_SIZE; #if 0 // Load terrain physics first... @@ -271,9 +276,9 @@ namespace MWWorld } else mPhysics->disableWater(); - - mRendering.configureAmbient(*cell); #endif + if (!cell->isExterior() && !(cell->getCell()->mData.mFlags & ESM::Cell::QuasiEx)) + mRendering.configureAmbient(cell->getCell()); } // register local scripts @@ -290,7 +295,7 @@ namespace MWWorld mCurrentCell = NULL; } - void Scene::playerMoved(const Ogre::Vector3 &pos) + void Scene::playerMoved(const osg::Vec3f &pos) { if (!mCurrentCell || !mCurrentCell->isExterior()) return; @@ -301,12 +306,14 @@ namespace MWWorld float centerX, centerY; MWBase::Environment::get().getWorld()->indexToPosition(cellX, cellY, centerX, centerY, true); const float maxDistance = 8192/2 + 1024; // 1/2 cell size + threshold - float distance = std::max(std::abs(centerX-pos.x), std::abs(centerY-pos.y)); + float distance = std::max(std::abs(centerX-pos.x()), std::abs(centerY-pos.y())); if (distance > maxDistance) { int newX, newY; - MWBase::Environment::get().getWorld()->positionToIndex(pos.x, pos.y, newX, newY); + MWBase::Environment::get().getWorld()->positionToIndex(pos.x(), pos.y(), newX, newY); + osg::Timer timer; changeCellGrid(newX, newY); + std::cout << "changeCellGrid took " << timer.time_m() << std::endl; //mRendering.updateTerrain(); } } @@ -435,7 +442,7 @@ namespace MWWorld //We need the ogre renderer and a scene node. Scene::Scene (MWRender::RenderingManager& rendering, PhysicsSystem *physics) - : mCurrentCell (0), mCellChanged (false), /*mPhysics(physics), mRendering(rendering),*/ mNeedMapUpdate(false) + : mCurrentCell (0), mCellChanged (false), /*mPhysics(physics),*/ mRendering(rendering), mNeedMapUpdate(false) { } @@ -545,15 +552,15 @@ namespace MWWorld void Scene::insertCell (CellStore &cell, bool rescale, Loading::Listener* loadingListener) { - //InsertFunctor functor (cell, rescale, *loadingListener, *mPhysics, mRendering); - //cell.forEach (functor); + InsertFunctor functor (cell, rescale, *loadingListener, /* *mPhysics, */mRendering); + cell.forEach (functor); } void Scene::addObjectToScene (const Ptr& ptr) { try { - //addObject(ptr, *mPhysics, mRendering); + addObject(ptr, /* *mPhysics, */mRendering); //MWBase::Environment::get().getWorld()->rotateObject(ptr, 0, 0, 0, true); //MWBase::Environment::get().getWorld()->scaleObject(ptr, ptr.getCellRef().getScale()); } diff --git a/apps/openmw/mwworld/scene.hpp b/apps/openmw/mwworld/scene.hpp index 341a89a78..4e8f6a11b 100644 --- a/apps/openmw/mwworld/scene.hpp +++ b/apps/openmw/mwworld/scene.hpp @@ -8,6 +8,11 @@ #include +namespace osg +{ + class Vec3f; +} + namespace Ogre { class Vector3; @@ -59,7 +64,7 @@ namespace MWWorld CellStoreCollection mActiveCells; bool mCellChanged; //PhysicsSystem *mPhysics; - //MWRender::RenderingManager& mRendering; + MWRender::RenderingManager& mRendering; bool mNeedMapUpdate; @@ -80,7 +85,7 @@ namespace MWWorld void loadCell (CellStore *cell, Loading::Listener* loadingListener); - void playerMoved (const Ogre::Vector3& pos); + void playerMoved (const osg::Vec3f& pos); void changePlayerCell (CellStore* newCell, const ESM::Position& position, bool adjustPlayerPos); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 8b2035fe9..994a0c9dd 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -11,6 +11,8 @@ #include "../mwscript/globalscripts.hpp" #include +#include + #include #include @@ -37,6 +39,7 @@ #include "../mwmechanics/aiavoiddoor.hpp" //Used to tell actors to avoid doors //#include "../mwrender/animation.hpp" +#include "../mwrender/renderingmanager.hpp" #include "../mwscript/interpretercontext.hpp" @@ -143,9 +146,11 @@ namespace MWWorld } World::World ( + osgViewer::Viewer& viewer, + osg::ref_ptr rootNode, + Resource::ResourceSystem* resourceSystem, const Files::Collections& fileCollections, const std::vector& contentFiles, - const boost::filesystem::path& resDir, const boost::filesystem::path& cacheDir, ToUTF8::Utf8Encoder* encoder, const std::map& fallbackMap, int activationDistanceOverride, const std::string& startCell, const std::string& startupScript) : mPlayer (0), mLocalScripts (mStore), @@ -162,7 +167,7 @@ namespace MWWorld #if 0 mProjectileManager.reset(new ProjectileManager(renderer.getScene(), *mPhysEngine)); #endif - //mRendering = new MWRender::RenderingManager(renderer, resDir, cacheDir, mPhysEngine,&mFallback); + mRendering = new MWRender::RenderingManager(viewer, rootNode, resourceSystem); //mPhysEngine->setSceneManager(renderer.getScene()); @@ -476,7 +481,7 @@ namespace MWWorld #endif //delete mWeatherManager; delete mWorldScene; - //delete mRendering; + delete mRendering; //delete mPhysics; delete mPlayer; @@ -1184,7 +1189,7 @@ namespace MWWorld MWWorld::Ptr newPtr = ptr.getClass() .copyToCell(ptr, *newCell); - newPtr.getRefData().setBaseNode(0); + newPtr.getRefData().setBaseNodeOld(0); } else if (!currCellActive && !newCellActive) ptr.getClass().copyToCell(ptr, *newCell); @@ -1194,7 +1199,7 @@ namespace MWWorld ptr.getClass().copyToCell(ptr, *newCell, pos); //mRendering->updateObjectCell(ptr, copy); - ptr.getRefData().setBaseNode(NULL); + ptr.getRefData().setBaseNodeOld(NULL); MWBase::Environment::get().getSoundManager()->updatePtr (ptr, copy); MWBase::MechanicsManager *mechMgr = MWBase::Environment::get().getMechanicsManager(); @@ -1213,14 +1218,14 @@ namespace MWWorld ptr.getRefData().setCount(0); } } - if (haveToMove && ptr.getRefData().getBaseNode()) + if (haveToMove && ptr.getRefData().getBaseNodeOld()) { //mRendering->moveObject(ptr, vec); //mPhysics->moveObject (ptr); } if (isPlayer) { - mWorldScene->playerMoved (vec); + //mWorldScene->playerMoved (vec); } } @@ -1252,7 +1257,7 @@ namespace MWWorld ptr.getCellRef().setScale(scale); ptr.getClass().adjustScale(ptr,scale); - if(ptr.getRefData().getBaseNode() == 0) + if(ptr.getRefData().getBaseNodeOld() == 0) return; //mRendering->scaleObject(ptr, Vector3(scale,scale,scale)); //mPhysics->scaleObject(ptr); @@ -1303,7 +1308,7 @@ namespace MWWorld ptr.getRefData().setPosition(pos); - if(ptr.getRefData().getBaseNode() == 0) + if(ptr.getRefData().getBaseNodeOld() == 0) return; if (ptr.getClass().isActor()) @@ -1325,7 +1330,7 @@ namespace MWWorld ptr.getRefData().setLocalRotation(rot); - if (ptr.getRefData().getBaseNode() != 0) + if (ptr.getRefData().getBaseNodeOld() != 0) { mWorldScene->updateObjectLocalRotation(ptr); } @@ -1335,7 +1340,7 @@ namespace MWWorld { ESM::Position pos (ptr.getRefData().getPosition()); - if(!ptr.getRefData().getBaseNode()) + if(!ptr.getRefData().getBaseNodeOld()) { // will be adjusted when Ptr's cell becomes active return; @@ -1352,9 +1357,9 @@ namespace MWWorld if (force || !isFlying(ptr)) { - Ogre::Vector3 traced;// = mPhysics->traceDown(ptr, 500); - if (traced.z < pos.pos[2]) - pos.pos[2] = traced.z; + //Ogre::Vector3 traced = mPhysics->traceDown(ptr, 500); + //if (traced.z < pos.pos[2]) + // pos.pos[2] = traced.z; } moveObject(ptr, ptr.getCell(), pos.pos[0], pos.pos[1], pos.pos[2]); @@ -1599,13 +1604,14 @@ namespace MWWorld void World::update (float duration, bool paused) { + /* if (mGoToJail && !paused) goToJail(); updateWeather(duration, paused); - //if (!paused) - // doPhysics (duration); + if (!paused) + doPhysics (duration); mWorldScene->update (duration, paused); @@ -1620,11 +1626,14 @@ namespace MWWorld ESM::Position pos = mPlayer->getPlayer().getRefData().getPosition(); mPlayer->setLastKnownExteriorPosition(Ogre::Vector3(pos.pos)); } + */ + + //mWorldScene->playerMoved(mRendering->getEyePos()); } void World::updateSoundListener() { - Ogre::Vector3 playerPos = mPlayer->getPlayer().getRefData().getBaseNode()->getPosition(); + Ogre::Vector3 playerPos = mPlayer->getPlayer().getRefData().getBaseNodeOld()->getPosition(); const OEngine::Physic::PhysicActor *actor = mPhysEngine->getCharacter(getPlayerPtr().getRefData().getHandle()); if(actor) playerPos.z += 1.85f * actor->getHalfExtents().z; Ogre::Quaternion playerOrient = Ogre::Quaternion(Ogre::Radian(getPlayerPtr().getRefData().getPosition().rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z) * @@ -1644,7 +1653,7 @@ namespace MWWorld // retrieve object dimensions so we know where to place the floating label if (!object.isEmpty ()) { - Ogre::SceneNode* node = object.getRefData().getBaseNode(); + Ogre::SceneNode* node = object.getRefData().getBaseNodeOld(); Ogre::AxisAlignedBox bounds = node->_getWorldAABB(); if (bounds.isFinite()) { @@ -2341,7 +2350,7 @@ namespace MWWorld bool operator() (Ptr ptr) { - Ogre::SceneNode* handle = ptr.getRefData().getBaseNode(); + Ogre::SceneNode* handle = ptr.getRefData().getBaseNodeOld(); if (handle) mHandles.push_back(handle->getName()); return true; @@ -2366,7 +2375,7 @@ namespace MWWorld { if (!targetActor.getRefData().isEnabled() || !actor.getRefData().isEnabled()) return false; // cannot get LOS unless both NPC's are enabled - if (!targetActor.getRefData().getBaseNode() || !targetActor.getRefData().getBaseNode()) + if (!targetActor.getRefData().getBaseNodeOld() || !targetActor.getRefData().getBaseNodeOld()) return false; // not in active cell OEngine::Physic::PhysicActor* actor1 = mPhysEngine->getCharacter(actor.getRefData().getHandle()); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 07698aae5..f77bb4760 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -5,6 +5,8 @@ #include +#include + #include "ptr.hpp" #include "scene.hpp" #include "esmstore.hpp" @@ -21,6 +23,21 @@ #include +namespace osg +{ + class Group; +} + +namespace osgViewer +{ + class Viewer; +} + +namespace Resource +{ + class ResourceSystem; +} + namespace Ogre { class Vector3; @@ -155,9 +172,11 @@ namespace MWWorld public: World ( + osgViewer::Viewer& viewer, + osg::ref_ptr rootNode, + Resource::ResourceSystem* resourceSystem, const Files::Collections& fileCollections, const std::vector& contentFiles, - const boost::filesystem::path& resDir, const boost::filesystem::path& cacheDir, ToUTF8::Utf8Encoder* encoder, const std::map& fallbackMap, int activationDistanceOverride, const std::string& startCell, const std::string& startupScript); diff --git a/components/sceneutil/lightmanager.cpp b/components/sceneutil/lightmanager.cpp index c49cf77b8..60315ba7d 100644 --- a/components/sceneutil/lightmanager.cpp +++ b/components/sceneutil/lightmanager.cpp @@ -74,6 +74,16 @@ namespace SceneUtil if (lights.size()) { + + static std::map > statesets; + std::map >::iterator found = statesets.find(node); + osg::ref_ptr stateset; + if (found != statesets.end()) + { + stateset = found->second; + } + else{ + // we do the intersections in view space osg::BoundingSphere nodeBound = node->getBound(); osg::Matrixf mat = *cv->getModelViewMatrix(); @@ -89,26 +99,33 @@ namespace SceneUtil if (lightList.empty()) { + statesets[node] = NULL; traverse(node, nv); return; } - if (lightList.size() > 8) + unsigned int maxLights = static_cast (8 - mLightManager->getStartLight()); + + if (lightList.size() > maxLights) { //std::cerr << "More than 8 lights!" << std::endl; // TODO: sort lights by certain criteria - while (lightList.size() > 8) + while (lightList.size() > maxLights) lightList.pop_back(); } - osg::ref_ptr stateset = mLightManager->getLightListStateSet(lightList); + stateset = mLightManager->getLightListStateSet(lightList); + statesets[node] = stateset; + } + if (stateset) cv->pushStateSet(stateset); traverse(node, nv); + if (stateset) cv->popStateSet(); } else @@ -174,7 +191,7 @@ namespace SceneUtil throw std::runtime_error("can't find parent LightManager"); } - mLightManager->addLight(static_cast(node), osg::computeLocalToWorld(nv->getNodePath())); + //mLightManager->addLight(static_cast(node), osg::computeLocalToWorld(nv->getNodePath())); traverse(node, nv); } @@ -208,6 +225,7 @@ namespace SceneUtil LightManager::LightManager() : mLightsInViewSpace(false) , mDecorated(false) + , mStartLight(0) { setUpdateCallback(new LightManagerUpdateCallback); } @@ -216,6 +234,7 @@ namespace SceneUtil : osg::Group(copy, copyop) , mLightsInViewSpace(false) , mDecorated(copy.mDecorated) + , mStartLight(copy.mStartLight) { } @@ -284,11 +303,14 @@ namespace SceneUtil osg::ref_ptr clonedLight = new LightStateAttribute(*light, osg::CopyOp::DEEP_COPY_ALL); clonedLight->setPosition(mLights[lightIndex].mWorldMatrix.preMult(light->getPosition())); - clonedLight->setLightNum(i); + clonedLight->setLightNum(i+mStartLight); // don't use setAttributeAndModes, that does not support light indices! stateset->setAttribute(clonedLight, osg::StateAttribute::ON); stateset->setAssociatedModes(clonedLight, osg::StateAttribute::ON); + + //stateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF); + } mStateSetCache.insert(std::make_pair(hash, stateset)); return stateset; @@ -300,6 +322,16 @@ namespace SceneUtil return mLights; } + void LightManager::setStartLight(int start) + { + mStartLight = start; + } + + int LightManager::getStartLight() const + { + return mStartLight; + } + LightSource::LightSource() : mRadius(0.f) { diff --git a/components/sceneutil/lightmanager.hpp b/components/sceneutil/lightmanager.hpp index ccb6603a6..fe5dc5082 100644 --- a/components/sceneutil/lightmanager.hpp +++ b/components/sceneutil/lightmanager.hpp @@ -87,6 +87,11 @@ namespace SceneUtil osg::ref_ptr getLightListStateSet(const LightList& lightList); + /// Set the first light index that should be used by this manager, typically the number of directional lights in the scene. + void setStartLight(int start); + + int getStartLight() const; + private: // Lights collected from the scene graph. Only valid during the cull traversal. std::vector mLights; @@ -98,6 +103,8 @@ namespace SceneUtil LightStateSetMap mStateSetCache; bool mDecorated; + + int mStartLight; }; } diff --git a/files/settings-default.cfg b/files/settings-default.cfg index de22e1b56..32c3861c0 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -129,15 +129,6 @@ local map hud widget size = 256 exterior grid size = 3 [Viewing distance] -# Limit the rendering distance of small objects -limit small object distance = false - -# Size below which an object is considered as small -small object size = 250 - -# Rendering distance for small objects -small object distance = 3500 - # Viewing distance at normal weather conditions # The maximum distance with no pop-in will be: (see RenderingManager::configureFog) # viewing distance / minimum weather fog depth (.69) * view frustum factor <= cell size (8192) - loading threshold (1024) From 61aaf0cf70f12411d3da47ad65155d5314079528 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 12 Apr 2015 18:02:29 +0200 Subject: [PATCH 0929/3725] Attach light lists to the object base nodes instead of each renderable Apparently that is how Ogre worked (on the SceneNode) so let's roll with it for now. Have not tested yet what MW does. --- apps/openmw/mwrender/objects.cpp | 3 + components/sceneutil/lightmanager.cpp | 218 ++++++++++---------------- components/sceneutil/lightmanager.hpp | 23 ++- 3 files changed, 109 insertions(+), 135 deletions(-) diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 6d37fa1e8..764aa13c6 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -131,6 +131,9 @@ void Objects::insertModel(const MWWorld::Ptr &ptr, const std::string &mesh, bool std::auto_ptr anim (new ObjectAnimation(ptr, mesh, mResourceSystem)); + if (anim->getObjectRoot()) + anim->getObjectRoot()->addCullCallback(new SceneUtil::LightListCallback); + if (ptr.getTypeName() == typeid(ESM::Light).name() && allowLight) { SceneUtil::FindByNameVisitor visitor("AttachLight"); diff --git a/components/sceneutil/lightmanager.cpp b/components/sceneutil/lightmanager.cpp index 60315ba7d..5bccd53b3 100644 --- a/components/sceneutil/lightmanager.cpp +++ b/components/sceneutil/lightmanager.cpp @@ -45,122 +45,6 @@ namespace SceneUtil } }; - class CullCallback : public osg::NodeCallback - { - public: - CullCallback() - : mLightManager(NULL) - {} - CullCallback(const CullCallback& copy, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY) - : osg::Object(copy, copyop), osg::NodeCallback(copy, copyop), mLightManager(copy.mLightManager) - {} - CullCallback(LightManager* lightManager) - : mLightManager(lightManager) - {} - - META_Object(NifOsg, CullCallback) - - void operator()(osg::Node* node, osg::NodeVisitor* nv) - { - osgUtil::CullVisitor* cv = static_cast(nv); - - mLightManager->prepareForCamera(cv->getCurrentCamera()); - - // Possible optimizations: - // - cull list of lights by the camera frustum - // - organize lights in a quad tree - - const std::vector& lights = mLightManager->getLights(); - - if (lights.size()) - { - - static std::map > statesets; - std::map >::iterator found = statesets.find(node); - osg::ref_ptr stateset; - if (found != statesets.end()) - { - stateset = found->second; - } - else{ - - // we do the intersections in view space - osg::BoundingSphere nodeBound = node->getBound(); - osg::Matrixf mat = *cv->getModelViewMatrix(); - transformBoundingSphere(mat, nodeBound); - - std::vector lightList; - for (unsigned int i=0; i (8 - mLightManager->getStartLight()); - - if (lightList.size() > maxLights) - { - //std::cerr << "More than 8 lights!" << std::endl; - - // TODO: sort lights by certain criteria - - while (lightList.size() > maxLights) - lightList.pop_back(); - } - - stateset = mLightManager->getLightListStateSet(lightList); - statesets[node] = stateset; - } - - if (stateset) - cv->pushStateSet(stateset); - - traverse(node, nv); - - if (stateset) - cv->popStateSet(); - } - else - traverse(node, nv); - } - - private: - LightManager* mLightManager; - }; - - class AttachCullCallbackVisitor : public osg::NodeVisitor - { - public: - AttachCullCallbackVisitor(LightManager* lightManager) - : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) - , mLightManager(lightManager) - { - } - - virtual void apply(osg::Geode &geode) - { - if (!geode.getNumParents()) - return; - - // Not working on a Geode. Drawables are not normal children of the Geode, the traverse() call - // does not traverse the drawables, so the push/pop in the CullCallback has no effect - // Should be no longer an issue with osg trunk - osg::Node* parent = geode.getParent(0); - parent->addCullCallback(new CullCallback(mLightManager)); - } - - private: - LightManager* mLightManager; - }; - // Set on a LightSource. Adds the light source to its light manager for the current frame. // This allows us to keep track of the current lights in the scene graph without tying creation & destruction to the manager. class CollectLightCallback : public osg::NodeCallback @@ -191,7 +75,7 @@ namespace SceneUtil throw std::runtime_error("can't find parent LightManager"); } - //mLightManager->addLight(static_cast(node), osg::computeLocalToWorld(nv->getNodePath())); + mLightManager->addLight(static_cast(node), osg::computeLocalToWorld(nv->getNodePath())); traverse(node, nv); } @@ -224,7 +108,6 @@ namespace SceneUtil LightManager::LightManager() : mLightsInViewSpace(false) - , mDecorated(false) , mStartLight(0) { setUpdateCallback(new LightManagerUpdateCallback); @@ -233,29 +116,16 @@ namespace SceneUtil LightManager::LightManager(const LightManager ©, const osg::CopyOp ©op) : osg::Group(copy, copyop) , mLightsInViewSpace(false) - , mDecorated(copy.mDecorated) , mStartLight(copy.mStartLight) { } - void LightManager::decorateGeodes() - { - AttachCullCallbackVisitor visitor(this); - accept(visitor); - } - void LightManager::update() { mLightsInViewSpace = false; mLights.clear(); mStateSetCache.clear(); - - if (!mDecorated) - { - decorateGeodes(); - mDecorated = true; - } } void LightManager::addLight(LightSource* lightSource, osg::Matrix worldMat) @@ -338,4 +208,90 @@ namespace SceneUtil setUpdateCallback(new CollectLightCallback); } + void LightListCallback::operator()(osg::Node *node, osg::NodeVisitor *nv) + { + osgUtil::CullVisitor* cv = static_cast(nv); + + if (!mLightManager) + { + for (unsigned int i=0;igetNodePath().size(); ++i) + { + if (LightManager* lightManager = dynamic_cast(nv->getNodePath()[i])) + { + mLightManager = lightManager; + break; + } + } + if (!mLightManager) + return; + } + + mLightManager->prepareForCamera(cv->getCurrentCamera()); + + // Possible optimizations: + // - cull list of lights by the camera frustum + // - organize lights in a quad tree + + const std::vector& lights = mLightManager->getLights(); + + if (lights.size()) + { + + static std::map > statesets; + std::map >::iterator found = statesets.find(node); + osg::ref_ptr stateset; + if (found != statesets.end()) + { + stateset = found->second; + } + else{ + + // we do the intersections in view space + osg::BoundingSphere nodeBound = node->getBound(); + osg::Matrixf mat = *cv->getModelViewMatrix(); + transformBoundingSphere(mat, nodeBound); + + std::vector lightList; + for (unsigned int i=0; i (8 - mLightManager->getStartLight()); + + if (lightList.size() > maxLights) + { + //std::cerr << "More than 8 lights!" << std::endl; + + // TODO: sort lights by certain criteria + + while (lightList.size() > maxLights) + lightList.pop_back(); + } + + stateset = mLightManager->getLightListStateSet(lightList); + statesets[node] = stateset; + } + + if (stateset) + cv->pushStateSet(stateset); + + traverse(node, nv); + + if (stateset) + cv->popStateSet(); + } + else + traverse(node, nv); + } + } diff --git a/components/sceneutil/lightmanager.hpp b/components/sceneutil/lightmanager.hpp index fe5dc5082..1cd73589a 100644 --- a/components/sceneutil/lightmanager.hpp +++ b/components/sceneutil/lightmanager.hpp @@ -71,8 +71,6 @@ namespace SceneUtil void prepareForCamera(osg::Camera* cam); - void decorateGeodes(); - struct LightSourceTransform { LightSource* mLightSource; @@ -102,11 +100,28 @@ namespace SceneUtil typedef std::map > LightStateSetMap; LightStateSetMap mStateSetCache; - bool mDecorated; - int mStartLight; }; + class LightListCallback : public osg::NodeCallback + { + public: + LightListCallback() + : mLightManager(NULL) + {} + LightListCallback(const LightListCallback& copy, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY) + : osg::Object(copy, copyop), osg::NodeCallback(copy, copyop), mLightManager(copy.mLightManager) + {} + + META_Object(NifOsg, LightListCallback) + + void operator()(osg::Node* node, osg::NodeVisitor* nv); + + private: + LightManager* mLightManager; + }; + + } #endif From 987e923790f91ef1e62a9464409a5d1c6d351ee1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 12 Apr 2015 19:44:48 +0200 Subject: [PATCH 0930/3725] LightManager optimization --- components/sceneutil/lightmanager.cpp | 67 ++++++++++++++++++--------- 1 file changed, 44 insertions(+), 23 deletions(-) diff --git a/components/sceneutil/lightmanager.cpp b/components/sceneutil/lightmanager.cpp index 5bccd53b3..1aaf7ab40 100644 --- a/components/sceneutil/lightmanager.cpp +++ b/components/sceneutil/lightmanager.cpp @@ -15,17 +15,32 @@ namespace SceneUtil { - class LightStateAttribute : public osg::Light + // Resets the modelview matrix to just the view matrix before applying lights. + class LightStateAttribute : public osg::StateAttribute { public: - LightStateAttribute() {} + LightStateAttribute() : mIndex(0) {} + LightStateAttribute(unsigned int index, const std::vector >& lights) : mIndex(index), mLights(lights) {} - LightStateAttribute(const LightStateAttribute& light,const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY) - : osg::Light(light,copyop) {} + LightStateAttribute(const LightStateAttribute& copy,const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY) + : osg::StateAttribute(copy,copyop), mIndex(copy.mIndex), mLights(copy.mLights) {} - LightStateAttribute(const osg::Light& light,const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY) - : osg::Light(light,copyop) {} + unsigned int getMember() const + { + return mIndex; + } + virtual bool getModeUsage(ModeUsage & usage) const + { + for (unsigned int i=0; isetLightNum(i+mIndex); + mLights[i]->apply(state); + } state.applyModelViewMatrix(modelViewMatrix); } + + private: + unsigned int mIndex; + + std::vector > mLights; }; // Set on a LightSource. Adds the light source to its light manager for the current frame. @@ -133,6 +153,9 @@ namespace SceneUtil LightSourceTransform l; l.mLightSource = lightSource; l.mWorldMatrix = worldMat; + lightSource->getLight()->setPosition(osg::Vec4f(worldMat.getTrans().x(), + worldMat.getTrans().y(), + worldMat.getTrans().z(), 1.f)); mLights.push_back(l); } @@ -164,24 +187,22 @@ namespace SceneUtil return found->second; else { - osg::ref_ptr stateset (new osg::StateSet); + + std::vector > lights; for (unsigned int i=0; igetLight(); - - osg::ref_ptr clonedLight = new LightStateAttribute(*light, osg::CopyOp::DEEP_COPY_ALL); - clonedLight->setPosition(mLights[lightIndex].mWorldMatrix.preMult(light->getPosition())); + const LightSourceTransform& l = mLights[lightList[i]]; + lights.push_back(l.mLightSource->getLight()); + } - clonedLight->setLightNum(i+mStartLight); + osg::ref_ptr attr = new LightStateAttribute(mStartLight, lights); - // don't use setAttributeAndModes, that does not support light indices! - stateset->setAttribute(clonedLight, osg::StateAttribute::ON); - stateset->setAssociatedModes(clonedLight, osg::StateAttribute::ON); + osg::ref_ptr stateset = new osg::StateSet; - //stateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF); + // don't use setAttributeAndModes, that does not support light indices! + stateset->setAttribute(attr, osg::StateAttribute::ON); + stateset->setAssociatedModes(attr, osg::StateAttribute::ON); - } mStateSetCache.insert(std::make_pair(hash, stateset)); return stateset; } From a976dca27bb7d0c0b3a8a6e476501d4dc4a649c8 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 13 Apr 2015 06:39:38 +1000 Subject: [PATCH 0931/3725] Changed over the remaining RefId adapters. Fixed issue where map entries were overwriting the same key... --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/world/nestedadapters.cpp | 8 - apps/opencs/model/world/nestedadapters.hpp | 420 -------------------- apps/opencs/model/world/refidadapter.cpp | 85 ---- apps/opencs/model/world/refidadapter.hpp | 43 -- apps/opencs/model/world/refidadapterimp.cpp | 15 +- apps/opencs/model/world/refidadapterimp.hpp | 332 +++++++++++++++- apps/opencs/model/world/refidcollection.cpp | 181 +++++---- apps/opencs/model/world/refidcollection.hpp | 5 +- 9 files changed, 422 insertions(+), 669 deletions(-) delete mode 100644 apps/opencs/model/world/nestedadapters.cpp delete mode 100644 apps/opencs/model/world/nestedadapters.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index babd3363f..cfe084e2c 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -25,7 +25,7 @@ opencs_units (model/world opencs_units_noqt (model/world universalid record commands columnbase scriptcontext cell refidcollection refidadapter refiddata refidadapterimp ref collectionbase refcollection columns infocollection tablemimedata cellcoordinates cellselection resources resourcesmanager scope - pathgrid landtexture land nestedtablewrapper nestedadapters nestedcollection nestedcoladapterimp + pathgrid landtexture land nestedtablewrapper nestedcollection nestedcoladapterimp ) opencs_hdrs_noqt (model/world diff --git a/apps/opencs/model/world/nestedadapters.cpp b/apps/opencs/model/world/nestedadapters.cpp deleted file mode 100644 index 1c8b1eff1..000000000 --- a/apps/opencs/model/world/nestedadapters.cpp +++ /dev/null @@ -1,8 +0,0 @@ -#include "nestedadapters.hpp" - -CSMWorld::HelperBase::HelperBase(CSMWorld::UniversalId::Type type) - : mType(type) -{} - -CSMWorld::HelperBase::~HelperBase() -{} diff --git a/apps/opencs/model/world/nestedadapters.hpp b/apps/opencs/model/world/nestedadapters.hpp deleted file mode 100644 index 97046276f..000000000 --- a/apps/opencs/model/world/nestedadapters.hpp +++ /dev/null @@ -1,420 +0,0 @@ -#ifndef CSM_WORLD_NESTEDADAPTERS_H -#define CSM_WORLD_NESTEDADAPTERS_H - -#include -#include -#include - -#include "universalid.hpp" -#include "nestedtablewrapper.hpp" -#include "record.hpp" -#include "refiddata.hpp" -#include "refidadapter.hpp" -#include -#include -#include -#include -#include -#include - -#include - -/*! \brief - * Nested adapter redirects responsibility to the helper class. Helper classes are polymorhpic (vide HelperBase and CastableHelper) and most likely templates. - */ - -namespace CSMWorld -{ - class RefIdColumn; - - class HelperBase - { - protected: - const CSMWorld::UniversalId::Type mType; - - public: - HelperBase(CSMWorld::UniversalId::Type type); - - virtual ~HelperBase(); - - virtual void setNestedTable(RefIdData& data, - int index, - const NestedTableWrapperBase& nestedTable) = 0; - - virtual NestedTableWrapperBase* nestedTable(const RefIdData& data, - int index) const = 0; - - virtual QVariant getNestedData(const CSMWorld::RefIdData& data, - int index, - int subRowIndex, - int subColIndex) const = 0; - - virtual void removeNestedRow (RefIdData& data, - int index, - int rowToRemove) const = 0; - - virtual void setNestedData (RefIdData& data, - int index, - const QVariant& value, - int subRowIndex, - int subColIndex) const = 0; - - virtual void addNestedRow (RefIdData& data, - int index, - int position) const = 0; - - virtual int getNestedColumnsCount(const RefIdData& data) const = 0; - - virtual int getNestedRowsCount(const RefIdData& data, - int index) const = 0; - }; - - template - class CastableHelper : public HelperBase - { - - public: - CastableHelper(CSMWorld::UniversalId::Type type) - : HelperBase(type) {} - - protected: - const Record& getRecord(const RefIdData& data, int index) const - { - return dynamic_cast&> ( - data.getRecord (RefIdData::LocalIndex (index, mType))); - } - - Record& getRecord(RefIdData& data, int index) const - { - return dynamic_cast&> ( - data.getRecord (RefIdData::LocalIndex (index, mType))); - } - }; - - template - class SpellsHelper : public CastableHelper - { - public: - - SpellsHelper(CSMWorld::UniversalId::Type type) - : CastableHelper(type) {} - - virtual void setNestedTable(RefIdData& data, - int index, - const NestedTableWrapperBase& nestedTable) - { - CastableHelper::getRecord(data, index).get().mSpells.mList = - (static_cast >&>(nestedTable)).mNestedTable; - } - - virtual NestedTableWrapperBase* nestedTable(const RefIdData& data, - int index) const - { - return new NestedTableWrapper >(CastableHelper::getRecord(data, index).get().mSpells.mList); - } - - virtual QVariant getNestedData(const CSMWorld::RefIdData& data, - int index, - int subRowIndex, - int subColIndex) const - { - const std::string& content = CastableHelper::getRecord(data, index).get().mSpells.mList.at(subRowIndex); - - if (subColIndex == 0) - { - return QString::fromUtf8(content.c_str()); - } - - throw std::logic_error("Trying to access non-existing column in the nested table!"); - } - - virtual void removeNestedRow (RefIdData& data, int index, int rowToRemove) const - { - std::vector& list = CastableHelper::getRecord(data, index).get().mSpells.mList; - - list.erase (list.begin () + rowToRemove); - } - - void setNestedData (RefIdData& data, - int index, - const QVariant& value, - int subRowIndex, - int subColIndex) const - { - if (subColIndex == 0) - { - CastableHelper::getRecord(data, index).get().mSpells.mList.at(subRowIndex) = std::string(value.toString().toUtf8()); - } - else - throw std::logic_error("Trying to access non-existing column in the nested table!"); - } - - virtual void addNestedRow (RefIdData& data, int index, int position) const - { - std::vector& list = CastableHelper::getRecord(data, index).get().mSpells.mList; - - std::string newString; - if (position >= (int)list.size()) - { - list.push_back(newString); - return; - } - - list.insert(list.begin()+position, newString); - } - - virtual int getNestedColumnsCount(const RefIdData& data) const - { - return 1; - } - - - virtual int getNestedRowsCount(const RefIdData& data, - int index) const - { - return CastableHelper::getRecord(data, index).get().mSpells.mList.size(); - } - - }; - - template - class DestinationsHelper : public CastableHelper - { - public: - - DestinationsHelper(CSMWorld::UniversalId::Type type) - : CastableHelper(type) {} - - virtual void setNestedTable(RefIdData& data, - int index, - const NestedTableWrapperBase& nestedTable) - { - CastableHelper::getRecord(data, index).get().mTransport.mList = - (static_cast >&>(nestedTable)).mNestedTable; - } - - virtual NestedTableWrapperBase* nestedTable(const RefIdData& data, - int index) const - { - return new NestedTableWrapper >(CastableHelper::getRecord(data, index).get().mTransport.mList); - } - - virtual QVariant getNestedData(const CSMWorld::RefIdData& data, - int index, - int subRowIndex, - int subColIndex) const - { - const ESM::Transport::Dest& content = CastableHelper::getRecord(data, index).get().mTransport.mList.at(subRowIndex); - - switch (subColIndex) - { - case 0: - return QString::fromUtf8(content.mCellName.c_str()); - - case 1: - return content.mPos.pos[0]; - - case 2: - return content.mPos.pos[1]; - - case 3: - return content.mPos.pos[2]; - - case 4: - return content.mPos.rot[0]; - - case 5: - return content.mPos.rot[1]; - - case 6: - return content.mPos.rot[2]; - - default: - throw std::logic_error("Trying to access non-existing column in the nested table!"); - } - } - - virtual void removeNestedRow (RefIdData& data, int index, int rowToRemove) const - { - std::vector& list = CastableHelper::getRecord(data, index).get().mTransport.mList; - - list.erase (list.begin () + rowToRemove); - } - - void setNestedData (RefIdData& data, - int index, - const QVariant& value, - int subRowIndex, - int subColIndex) const - { - switch(subColIndex) - { - case 0: - CastableHelper::getRecord(data, index).get().mTransport.mList.at(subRowIndex).mCellName = std::string(value.toString().toUtf8().constData()); - break; - - case 1: - CastableHelper::getRecord(data, index).get().mTransport.mList.at(subRowIndex).mPos.pos[0] = value.toFloat(); - break; - - case 2: - CastableHelper::getRecord(data, index).get().mTransport.mList.at(subRowIndex).mPos.pos[1] = value.toFloat(); - break; - - case 3: - CastableHelper::getRecord(data, index).get().mTransport.mList.at(subRowIndex).mPos.pos[2] = value.toFloat(); - break; - - case 4: - CastableHelper::getRecord(data, index).get().mTransport.mList.at(subRowIndex).mPos.rot[0] = value.toFloat(); - break; - - case 5: - CastableHelper::getRecord(data, index).get().mTransport.mList.at(subRowIndex).mPos.rot[1] = value.toFloat(); - break; - - case 6: - CastableHelper::getRecord(data, index).get().mTransport.mList.at(subRowIndex).mPos.rot[2] = value.toFloat(); - break; - - default: - throw std::logic_error("Trying to access non-existing column in the nested table!"); - } - } - - virtual void addNestedRow (RefIdData& data, int index, int position) const - { - std::vector& list = CastableHelper::getRecord(data, index).get().mTransport.mList; - - ESM::Position newPos; - for (unsigned i = 0; i < 3; ++i) - { - newPos.pos[i] = 0; - newPos.rot[i] = 0; - } - - ESM::Transport::Dest newRow; - newRow.mPos = newPos; - newRow.mCellName = ""; - - if (position >= (int)list.size()) - { - list.push_back(newRow); - return; - } - - list.insert(list.begin()+position, newRow); - } - - virtual int getNestedColumnsCount(const RefIdData& data) const - { - return 7; - } - - virtual int getNestedRowsCount(const RefIdData& data, - int index) const - { - return CastableHelper::getRecord(data, index).get().mTransport.mList.size(); - } - - }; - - template - class InventoryHelper : public CastableHelper - { - public: - - InventoryHelper(CSMWorld::UniversalId::Type type) - : CastableHelper(type) {} - - virtual void setNestedTable(RefIdData& data, - int index, - const NestedTableWrapperBase& nestedTable) - { - CastableHelper::getRecord(data, index).get().mInventory.mList = - (static_cast >&>(nestedTable)).mNestedTable; - } - - virtual NestedTableWrapperBase* nestedTable(const RefIdData& data, - int index) const - { - return new NestedTableWrapper >(CastableHelper::getRecord(data, index).get().mInventory.mList); - } - - virtual QVariant getNestedData(const CSMWorld::RefIdData& data, - int index, - int subRowIndex, - int subColIndex) const - { - const ESM::ContItem& content = CastableHelper::getRecord(data, index).get().mInventory.mList.at(subRowIndex); - - switch (subColIndex) - { - case 0: - return QString::fromUtf8(content.mItem.toString().c_str()); - - case 1: - return content.mCount; - - default: - throw std::logic_error("Trying to access non-existing column in the nested table!"); - } - } - - virtual void removeNestedRow (RefIdData& data, int index, int rowToRemove) const - { - std::vector& list = CastableHelper::getRecord(data, index).get().mInventory.mList; - - list.erase (list.begin () + rowToRemove); - } - - void setNestedData (RefIdData& data, - int index, - const QVariant& value, - int subRowIndex, - int subColIndex) const - { - switch(subColIndex) - { - case 0: - CastableHelper::getRecord(data, index).get().mInventory.mList.at(subRowIndex).mItem.assign(std::string(value.toString().toUtf8().constData())); - break; - - case 1: - CastableHelper::getRecord(data, index).get().mInventory.mList.at(subRowIndex).mCount = value.toInt(); - break; - - default: - throw std::logic_error("Trying to access non-existing column in the nested table!"); - } - } - - virtual void addNestedRow (RefIdData& data, int index, int position) const - { - std::vector& list = CastableHelper::getRecord(data, index).get().mInventory.mList; - - ESM::ContItem newRow = {0, {""}}; - if (position >= (int)list.size()) - { - list.push_back(newRow); - return; - } - - list.insert(list.begin()+position, newRow); - } - - virtual int getNestedColumnsCount(const RefIdData& data) const - { - return 2; - } - - virtual int getNestedRowsCount(const RefIdData& data, - int index) const - { - return CastableHelper::getRecord(data, index).get().mInventory.mList.size(); - } - - }; -} - -#endif diff --git a/apps/opencs/model/world/refidadapter.cpp b/apps/opencs/model/world/refidadapter.cpp index a12a95196..37cb67bca 100644 --- a/apps/opencs/model/world/refidadapter.cpp +++ b/apps/opencs/model/world/refidadapter.cpp @@ -1,9 +1,5 @@ #include "refidadapter.hpp" -#include "nestedtablewrapper.hpp" - -#include - CSMWorld::RefIdAdapter::RefIdAdapter() {} CSMWorld::RefIdAdapter::~RefIdAdapter() {} @@ -11,84 +7,3 @@ CSMWorld::RefIdAdapter::~RefIdAdapter() {} CSMWorld::NestedRefIdAdapterBase::NestedRefIdAdapterBase() {} CSMWorld::NestedRefIdAdapterBase::~NestedRefIdAdapterBase() {} - -CSMWorld::NestedRefIdAdapter::NestedRefIdAdapter() -{} - -CSMWorld::NestedRefIdAdapter::~NestedRefIdAdapter() -{ - for (unsigned i = 0; i < mAssociatedColumns.size(); ++i) - { - delete mAssociatedColumns[i].second; - } -} - -void CSMWorld::NestedRefIdAdapter::setNestedData (const RefIdColumn *column, RefIdData& data, int row, - const QVariant& value, int subRowIndex, int subColIndex) const -{ - getHelper(column)->setNestedData(data, row, value, subRowIndex, subColIndex); -} - -QVariant CSMWorld::NestedRefIdAdapter::getNestedData(const RefIdColumn *column, const RefIdData& data, - int index, int subRowIndex, int subColIndex) const -{ - return getHelper(column)->getNestedData(data, index, subRowIndex, subColIndex); -} - -int CSMWorld::NestedRefIdAdapter::getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const -{ - return getHelper(column)->getNestedColumnsCount(data); -} - - -int CSMWorld::NestedRefIdAdapter::getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const -{ - return getHelper(column)->getNestedRowsCount(data, index); -} - - -void CSMWorld::NestedRefIdAdapter::removeNestedRow (const RefIdColumn *column, RefIdData& data, int index, int rowToRemove) const -{ - getHelper(column)->removeNestedRow(data, index, rowToRemove); -} - -void CSMWorld::NestedRefIdAdapter::addNestedRow (const RefIdColumn *column, RefIdData& data, int index, int position) const -{ - getHelper(column)->addNestedRow(data, index, position); //This code grows more boring and boring. I would love some macros. -} - -void CSMWorld::NestedRefIdAdapter::setNestedTable (const RefIdColumn* column, RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const -{ - getHelper(column)->setNestedTable(data, index, nestedTable); -} - - -CSMWorld::NestedTableWrapperBase* CSMWorld::NestedRefIdAdapter::nestedTable (const RefIdColumn* column, const RefIdData& data, int index) const -{ - return getHelper(column)->nestedTable(data, index); -} - -CSMWorld::HelperBase* CSMWorld::NestedRefIdAdapter::getHelper(const RefIdColumn *column) const -{ - for (unsigned i = 0; i < mAssociatedColumns.size(); ++i) - { - if (mAssociatedColumns[i].first == column) - { - return mAssociatedColumns[i].second; - } - } - - throw std::logic_error("No such column in the nestedrefidadapter"); - - return NULL; -} - -void CSMWorld::NestedRefIdAdapter::setAssocColumns(const std::vector >& assocColumns) -{ - mAssociatedColumns = assocColumns; -} - -void CSMWorld::NestedRefIdAdapter::addAssocColumn(const std::pair & assocColumn) -{ - mAssociatedColumns.push_back(assocColumn); -} diff --git a/apps/opencs/model/world/refidadapter.hpp b/apps/opencs/model/world/refidadapter.hpp index f80ce7ab3..ba9da577d 100644 --- a/apps/opencs/model/world/refidadapter.hpp +++ b/apps/opencs/model/world/refidadapter.hpp @@ -4,8 +4,6 @@ #include #include -#include "nestedadapters.hpp" - /*! \brief * Adapters acts as indirection layer, abstracting details of the record types (in the wrappers) from the higher levels of model. * Please notice that nested adaptor uses helper classes for actually performing any actions. Different record types require different helpers (needs to be created in the subclass and then fetched via member function). @@ -77,47 +75,6 @@ namespace CSMWorld virtual NestedTableWrapperBase* nestedTable (const RefIdColumn* column, const RefIdData& data, int index) const = 0; }; - - class NestedRefIdAdapter : public NestedRefIdAdapterBase - { - std::vector > mAssociatedColumns; //basically, i wanted a map, but with pointer key - - public: - NestedRefIdAdapter(); - - virtual ~NestedRefIdAdapter(); - - virtual void setNestedData (const RefIdColumn *column, RefIdData& data, int row, - const QVariant& value, int subRowIndex, int subColIndex) const; - - virtual QVariant getNestedData (const RefIdColumn *column, const RefIdData& data, - int index, int subRowIndex, int subColIndex) const; - - virtual int getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const; - - virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const; - - virtual void removeNestedRow (const RefIdColumn *column, RefIdData& data, int index, int rowToRemove) const; - - virtual void addNestedRow (const RefIdColumn *column, RefIdData& data, int index, int position) const; - - virtual void setNestedTable (const RefIdColumn* column, RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const; - - virtual NestedTableWrapperBase* nestedTable (const RefIdColumn* column, const RefIdData& data, int index) const; - - protected: - void setAssocColumns(const std::vector >& assocColumns); - ///The ownership of the Helper pointers is transfered. - ///The ownership of the column pointers it not transfered (it is not surprising, since columns are created by collection). - ///You MUST call this method to setup the nested adaptor! - - void addAssocColumn(const std::pair & assocColumn); - ///Like setAssocColumn, when it is impossible to set all columns at once - - private: - - HelperBase* getHelper(const RefIdColumn *column) const; - }; } #endif diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index 42d1aa52e..cd3a20327 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -188,13 +188,7 @@ CSMWorld::ContainerRefIdAdapter::ContainerRefIdAdapter (const NameColumns& colum const RefIdColumn *weight, const RefIdColumn *organic, const RefIdColumn *respawn, const RefIdColumn *content) : NameRefIdAdapter (UniversalId::Type_Container, columns), mWeight (weight), mOrganic (organic), mRespawn (respawn), mContent(content) -{ - std::vector > assoCol; - - assoCol.push_back(std::make_pair(content, new InventoryHelper(UniversalId::Type_Container))); - - setAssocColumns(assoCol); -} +{} QVariant CSMWorld::ContainerRefIdAdapter::getData (const RefIdColumn *column, const RefIdData& data, @@ -471,9 +465,7 @@ CSMWorld::NpcColumns::NpcColumns (const ActorColumns& actorColumns) CSMWorld::NpcRefIdAdapter::NpcRefIdAdapter (const NpcColumns& columns) : ActorRefIdAdapter (UniversalId::Type_Npc, columns), mColumns (columns) -{ - NestedRefIdAdapter::addAssocColumn(std::make_pair(columns.mDestinations, new DestinationsHelper(UniversalId::Type_Npc))); -} +{} QVariant CSMWorld::NpcRefIdAdapter::getData (const RefIdColumn *column, const RefIdData& data, int index) const @@ -496,9 +488,6 @@ QVariant CSMWorld::NpcRefIdAdapter::getData (const RefIdColumn *column, const Re if (column==mColumns.mHead) return QString::fromUtf8 (record.get().mHead.c_str()); - if (column==mColumns.mDestinations) - return true; // to show nested tables in dialogue subview, see IdTree::hasChildren() - std::map::const_iterator iter = mColumns.mFlags.find (column); diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index 08e2e7493..32e9148c7 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -11,12 +11,12 @@ #include #include #include +#include #include "record.hpp" #include "refiddata.hpp" #include "universalid.hpp" #include "refidadapter.hpp" -#include "nestedadapters.hpp" namespace CSMWorld { @@ -489,6 +489,7 @@ namespace CSMWorld const RefIdColumn *mAlarm; const RefIdColumn *mInventory; const RefIdColumn *mSpells; + const RefIdColumn *mDestinations; std::map mServices; ActorColumns (const NameColumns& base) : NameColumns (base) {} @@ -496,7 +497,7 @@ namespace CSMWorld /// \brief Adapter for actor IDs (handles common AI functionality) template - class ActorRefIdAdapter : public NameRefIdAdapter, public NestedRefIdAdapter + class ActorRefIdAdapter : public NameRefIdAdapter { ActorColumns mActors; @@ -516,14 +517,7 @@ namespace CSMWorld ActorRefIdAdapter::ActorRefIdAdapter (UniversalId::Type type, const ActorColumns& columns) : NameRefIdAdapter (type, columns), mActors (columns) - { - std::vector > assoCol; - - assoCol.push_back(std::make_pair(mActors.mInventory, new InventoryHelper(type))); - assoCol.push_back(std::make_pair(mActors.mSpells, new SpellsHelper(type))); - - setAssocColumns(assoCol); - } + {} template QVariant ActorRefIdAdapter::getData (const RefIdColumn *column, const RefIdData& data, @@ -553,6 +547,9 @@ namespace CSMWorld if (column==mActors.mSpells) return true; // to show nested tables in dialogue subview, see IdTree::hasChildren() + if (column==mActors.mDestinations) + return true; // to show nested tables in dialogue subview, see IdTree::hasChildren() + std::map::const_iterator iter = mActors.mServices.find (column); @@ -672,7 +669,7 @@ namespace CSMWorld ///< If the data type does not match an exception is thrown. }; - class ContainerRefIdAdapter : public NameRefIdAdapter, public NestedRefIdAdapter + class ContainerRefIdAdapter : public NameRefIdAdapter { const RefIdColumn *mWeight; const RefIdColumn *mOrganic; @@ -790,7 +787,6 @@ namespace CSMWorld const RefIdColumn *mFaction; const RefIdColumn *mHair; const RefIdColumn *mHead; - const RefIdColumn *mDestinations; NpcColumns (const ActorColumns& actorColumns); }; @@ -1060,6 +1056,318 @@ namespace CSMWorld return static_cast(record.get().mInventory.mList.size()); } }; + + template + class NestedSpellRefIdAdapter : public NestedRefIdAdapterBase + { + UniversalId::Type mType; + + // not implemented + NestedSpellRefIdAdapter (const NestedSpellRefIdAdapter&); + NestedSpellRefIdAdapter& operator= (const NestedSpellRefIdAdapter&); + + public: + + NestedSpellRefIdAdapter(UniversalId::Type type) :mType(type) {} + + virtual ~NestedSpellRefIdAdapter() {} + + virtual void addNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int position) const + { + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + ESXRecordT caster = record.get(); + + std::vector& list = caster.mSpells.mList; + + std::string newString; + + if (position >= (int)list.size()) + list.push_back(newString); + else + list.insert(list.begin()+position, newString); + + record.setModified (caster); + } + + virtual void removeNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int rowToRemove) const + { + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + ESXRecordT caster = record.get(); + + std::vector& list = caster.mSpells.mList; + + if (rowToRemove < 0 || rowToRemove >= static_cast (list.size())) + throw std::runtime_error ("index out of range"); + + list.erase (list.begin () + rowToRemove); + + record.setModified (caster); + } + + virtual void setNestedTable (const RefIdColumn* column, + RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const + { + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + ESXRecordT caster = record.get(); + + caster.mSpells.mList = + static_cast >&>(nestedTable).mNestedTable; + + record.setModified (caster); + } + + virtual NestedTableWrapperBase* nestedTable (const RefIdColumn* column, + const RefIdData& data, int index) const + { + const Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + + // deleted by dtor of NestedTableStoring + return new NestedTableWrapper >(record.get().mSpells.mList); + } + + virtual QVariant getNestedData (const RefIdColumn *column, + const RefIdData& data, int index, int subRowIndex, int subColIndex) const + { + const Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + + const std::vector& list = record.get().mSpells.mList; + + if (subRowIndex < 0 || subRowIndex >= static_cast (list.size())) + throw std::runtime_error ("index out of range"); + + const std::string& content = list.at(subRowIndex); + + if (subColIndex == 0) + return QString::fromUtf8(content.c_str()); + else + throw std::runtime_error("Trying to access non-existing column in the nested table!"); + } + + virtual void setNestedData (const RefIdColumn *column, + RefIdData& data, int row, const QVariant& value, int subRowIndex, int subColIndex) const + { + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (row, mType))); + ESXRecordT caster = record.get(); + std::vector& list = caster.mSpells.mList; + + if (subRowIndex < 0 || subRowIndex >= static_cast (list.size())) + throw std::runtime_error ("index out of range"); + + if (subColIndex == 0) + list.at(subRowIndex) = std::string(value.toString().toUtf8()); + else + throw std::runtime_error("Trying to access non-existing column in the nested table!"); + + record.setModified (caster); + } + + virtual int getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const + { + return 1; + } + + virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const + { + const Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + + return static_cast(record.get().mSpells.mList.size()); + } + }; + + template + class NestedTravelRefIdAdapter : public NestedRefIdAdapterBase + { + UniversalId::Type mType; + + // not implemented + NestedTravelRefIdAdapter (const NestedTravelRefIdAdapter&); + NestedTravelRefIdAdapter& operator= (const NestedTravelRefIdAdapter&); + + public: + + NestedTravelRefIdAdapter(UniversalId::Type type) :mType(type) {} + + virtual ~NestedTravelRefIdAdapter() {} + + virtual void addNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int position) const + { + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + ESXRecordT traveller = record.get(); + + std::vector& list = traveller.mTransport.mList; + + ESM::Position newPos; + for (unsigned i = 0; i < 3; ++i) + { + newPos.pos[i] = 0; + newPos.rot[i] = 0; + } + + ESM::Transport::Dest newRow; + newRow.mPos = newPos; + newRow.mCellName = ""; + + if (position >= (int)list.size()) + list.push_back(newRow); + else + list.insert(list.begin()+position, newRow); + + record.setModified (traveller); + } + + virtual void removeNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int rowToRemove) const + { + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + ESXRecordT traveller = record.get(); + + std::vector& list = traveller.mTransport.mList; + + if (rowToRemove < 0 || rowToRemove >= static_cast (list.size())) + throw std::runtime_error ("index out of range"); + + list.erase (list.begin () + rowToRemove); + + record.setModified (traveller); + } + + virtual void setNestedTable (const RefIdColumn* column, + RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const + { + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + ESXRecordT traveller = record.get(); + + traveller.mTransport.mList = + static_cast >&>(nestedTable).mNestedTable; + + record.setModified (traveller); + } + + virtual NestedTableWrapperBase* nestedTable (const RefIdColumn* column, + const RefIdData& data, int index) const + { + const Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + + // deleted by dtor of NestedTableStoring + return new NestedTableWrapper >(record.get().mTransport.mList); + } + + virtual QVariant getNestedData (const RefIdColumn *column, + const RefIdData& data, int index, int subRowIndex, int subColIndex) const + { + const Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + + const std::vector& list = record.get().mTransport.mList; + + if (subRowIndex < 0 || subRowIndex >= static_cast (list.size())) + throw std::runtime_error ("index out of range"); + + const ESM::Transport::Dest& content = list.at(subRowIndex); + + switch (subColIndex) + { + case 0: + return QString::fromUtf8(content.mCellName.c_str()); + + case 1: + return content.mPos.pos[0]; + + case 2: + return content.mPos.pos[1]; + + case 3: + return content.mPos.pos[2]; + + case 4: + return content.mPos.rot[0]; + + case 5: + return content.mPos.rot[1]; + + case 6: + return content.mPos.rot[2]; + + default: + throw std::runtime_error("Trying to access non-existing column in the nested table!"); + } + } + + virtual void setNestedData (const RefIdColumn *column, + RefIdData& data, int row, const QVariant& value, int subRowIndex, int subColIndex) const + { + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (row, mType))); + ESXRecordT traveller = record.get(); + std::vector& list = traveller.mTransport.mList; + + if (subRowIndex < 0 || subRowIndex >= static_cast (list.size())) + throw std::runtime_error ("index out of range"); + + switch(subColIndex) + { + case 0: + list.at(subRowIndex).mCellName = std::string(value.toString().toUtf8().constData()); + break; + + case 1: + list.at(subRowIndex).mPos.pos[0] = value.toFloat(); + break; + + case 2: + list.at(subRowIndex).mPos.pos[1] = value.toFloat(); + break; + + case 3: + list.at(subRowIndex).mPos.pos[2] = value.toFloat(); + break; + + case 4: + list.at(subRowIndex).mPos.rot[0] = value.toFloat(); + break; + + case 5: + list.at(subRowIndex).mPos.rot[1] = value.toFloat(); + break; + + case 6: + list.at(subRowIndex).mPos.rot[2] = value.toFloat(); + break; + + default: + throw std::runtime_error("Trying to access non-existing column in the nested table!"); + } + + record.setModified (traveller); + } + + virtual int getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const + { + return 7; + } + + virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const + { + const Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + + return static_cast(record.get().mTransport.mList.size()); + } + }; } #endif diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 755a1f56f..92cd37d0d 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -75,8 +75,12 @@ CSMWorld::RefIdCollection::RefIdCollection() PotionColumns potionColumns (inventoryColumns); mColumns.push_back (RefIdColumn (Columns::ColumnId_EffectList, ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue)); potionColumns.mEffects = &mColumns.back(); // see refidadapterimp.hpp - mNestedAdapters.insert (std::make_pair(&mColumns.back(), - new EffectsRefIdAdapter (UniversalId::Type_Potion))); + + std::map effectsMap; + effectsMap.insert( + std::make_pair(UniversalId::Type_Potion, new EffectsRefIdAdapter (UniversalId::Type_Potion))); + mNestedAdapters.push_back (std::make_pair(&mColumns.back(), effectsMap)); + mColumns.back().addColumn( new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_String/*, false*/)); mColumns.back().addColumn( @@ -124,10 +128,14 @@ CSMWorld::RefIdCollection::RefIdCollection() // Nested table mColumns.push_back(RefIdColumn (Columns::ColumnId_ActorInventory, ColumnBase::Display_NestedItemList, ColumnBase::Flag_Dialogue)); actorsColumns.mInventory = &mColumns.back(); - mNestedAdapters.insert (std::make_pair(&mColumns.back(), - new NestedInventoryRefIdAdapter (UniversalId::Type_Npc))); - mNestedAdapters.insert (std::make_pair(&mColumns.back(), - new NestedInventoryRefIdAdapter (UniversalId::Type_Creature))); + + std::map inventoryMap; + inventoryMap.insert( + std::make_pair(UniversalId::Type_Npc, new NestedInventoryRefIdAdapter (UniversalId::Type_Npc))); + inventoryMap.insert( + std::make_pair(UniversalId::Type_Creature, new NestedInventoryRefIdAdapter (UniversalId::Type_Creature))); + + mNestedAdapters.push_back (std::make_pair(&mColumns.back(), inventoryMap)); mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_InventoryItemId, CSMWorld::ColumnBase::Display_String)); mColumns.back().addColumn( @@ -136,9 +144,42 @@ CSMWorld::RefIdCollection::RefIdCollection() // Nested table mColumns.push_back(RefIdColumn (Columns::ColumnId_SpellList, ColumnBase::Display_NestedSpellList, ColumnBase::Flag_Dialogue)); actorsColumns.mSpells = &mColumns.back(); + + std::map spellsMap; + spellsMap.insert( + std::make_pair(UniversalId::Type_Npc, new NestedSpellRefIdAdapter (UniversalId::Type_Npc))); + spellsMap.insert( + std::make_pair(UniversalId::Type_Creature, new NestedSpellRefIdAdapter (UniversalId::Type_Creature))); + + mNestedAdapters.push_back (std::make_pair(&mColumns.back(), spellsMap)); mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_SpellId, CSMWorld::ColumnBase::Display_String)); + // Nested table + mColumns.push_back(RefIdColumn (Columns::ColumnId_NpcDestinations, ColumnBase::Display_NestedDestinationsList, ColumnBase::Flag_Dialogue)); + actorsColumns.mDestinations = &mColumns.back(); + + std::map destMap; + destMap.insert( + std::make_pair(UniversalId::Type_Npc, new NestedTravelRefIdAdapter (UniversalId::Type_Npc))); + destMap.insert( + std::make_pair(UniversalId::Type_Creature, new NestedTravelRefIdAdapter (UniversalId::Type_Creature))); + mNestedAdapters.push_back (std::make_pair(&mColumns.back(), destMap)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_DestinationCell, CSMWorld::ColumnBase::Display_String)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_PosX, CSMWorld::ColumnBase::Display_Float)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_PosY, CSMWorld::ColumnBase::Display_Float)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_PosZ, CSMWorld::ColumnBase::Display_Float)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_RotX, CSMWorld::ColumnBase::Display_Float)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_RotY, CSMWorld::ColumnBase::Display_Float)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_RotZ, CSMWorld::ColumnBase::Display_Float)); + static const struct { int mName; @@ -209,8 +250,12 @@ CSMWorld::RefIdCollection::RefIdCollection() // Nested table mColumns.push_back(RefIdColumn (Columns::ColumnId_ContainerContent, ColumnBase::Display_NestedItemList, ColumnBase::Flag_Dialogue)); const RefIdColumn *content = &mColumns.back(); - mNestedAdapters.insert (std::make_pair(&mColumns.back(), - new NestedInventoryRefIdAdapter (UniversalId::Type_Container))); + + std::map contMap; + contMap.insert( + std::make_pair(UniversalId::Type_Container, new NestedInventoryRefIdAdapter (UniversalId::Type_Container))); + mNestedAdapters.push_back (std::make_pair(&mColumns.back(), contMap)); + mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_InventoryItemId, CSMWorld::ColumnBase::Display_String)); mColumns.back().addColumn( @@ -351,24 +396,6 @@ CSMWorld::RefIdCollection::RefIdCollection() npcColumns.mFlags.insert (std::make_pair (metalBlood, ESM::NPC::Metal)); - // Nested table - mColumns.push_back(RefIdColumn (Columns::ColumnId_NpcDestinations, ColumnBase::Display_NestedDestinationsList, ColumnBase::Flag_Dialogue)); - npcColumns.mDestinations = &mColumns.back(); - mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_DestinationCell, CSMWorld::ColumnBase::Display_String)); - mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_PosX, CSMWorld::ColumnBase::Display_Float)); - mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_PosY, CSMWorld::ColumnBase::Display_Float)); - mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_PosZ, CSMWorld::ColumnBase::Display_Float)); - mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_RotX, CSMWorld::ColumnBase::Display_Float)); - mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_RotY, CSMWorld::ColumnBase::Display_Float)); - mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_RotZ, CSMWorld::ColumnBase::Display_Float)); - WeaponColumns weaponColumns (enchantableColumns); mColumns.push_back (RefIdColumn (Columns::ColumnId_WeaponType, ColumnBase::Display_WeaponType)); @@ -461,9 +488,13 @@ CSMWorld::RefIdCollection::~RefIdCollection() iter!=mAdapters.end(); ++iter) delete iter->second; - for (std::map::iterator iter (mNestedAdapters.begin()); + for (std::vector > >::iterator iter (mNestedAdapters.begin()); iter!=mNestedAdapters.end(); ++iter) - delete iter->second; + { + for (std::map::iterator it ((iter->second).begin()); + it!=(iter->second).end(); ++it) + delete it->second; + } } int CSMWorld::RefIdCollection::getSize() const @@ -509,15 +540,11 @@ QVariant CSMWorld::RefIdCollection::getNestedData (int row, int column, int subR { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex(row); - const CSMWorld::NestedRefIdAdapterBase* nestedAdapter = getNestedAdapter(mColumns.at(column)); + const CSMWorld::NestedRefIdAdapterBase* nestedAdapter = getNestedAdapter(mColumns.at(column), localIndex.second); if (nestedAdapter) - { return nestedAdapter->getNestedData(&mColumns.at (column), mData, localIndex.first, subRow, subColumn); - } - - const CSMWorld::NestedRefIdAdapter& adaptor = dynamic_cast(findAdapter (localIndex.second)); - - return adaptor.getNestedData (&mColumns.at (column), mData, localIndex.first, subRow, subColumn); + else + throw std::runtime_error("Could not find a nestedadapter"); } void CSMWorld::RefIdCollection::setData (int index, int column, const QVariant& data) @@ -533,16 +560,14 @@ void CSMWorld::RefIdCollection::setNestedData(int row, int column, const QVarian { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); - const CSMWorld::NestedRefIdAdapterBase* nestedAdapter = getNestedAdapter(mColumns.at(column)); + const CSMWorld::NestedRefIdAdapterBase* nestedAdapter = getNestedAdapter(mColumns.at(column), localIndex.second); if (nestedAdapter) { nestedAdapter->setNestedData(&mColumns.at (column), mData, localIndex.first, data, subRow, subColumn); return; } - - const RefIdAdapter& adaptor = findAdapter (localIndex.second); - - dynamic_cast(adaptor).setNestedData (&mColumns.at (column), mData, localIndex.first, data, subRow, subColumn); + else + throw std::runtime_error("Could not find a nestedadapter"); } void CSMWorld::RefIdCollection::removeRows (int index, int count) @@ -554,16 +579,14 @@ void CSMWorld::RefIdCollection::removeNestedRows(int row, int column, int subRow { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); - const CSMWorld::NestedRefIdAdapterBase* nestedAdapter = getNestedAdapter(mColumns.at(column)); + const CSMWorld::NestedRefIdAdapterBase* nestedAdapter = getNestedAdapter(mColumns.at(column), localIndex.second); if (nestedAdapter) { nestedAdapter->removeNestedRow(&mColumns.at (column), mData, localIndex.first, subRow); return; } - - const RefIdAdapter& adaptor = findAdapter (localIndex.second); - - dynamic_cast(adaptor).removeNestedRow(&mColumns.at (column), mData, localIndex.first, subRow); + else + throw std::runtime_error("Could not find a nestedadapter"); } void CSMWorld::RefIdCollection::appendBlankRecord (const std::string& id, UniversalId::Type type) @@ -705,30 +728,22 @@ int CSMWorld::RefIdCollection::getNestedRowsCount(int row, int column) const { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); - const CSMWorld::NestedRefIdAdapterBase* nestedAdapter = getNestedAdapter(mColumns.at(column)); + const CSMWorld::NestedRefIdAdapterBase* nestedAdapter = getNestedAdapter(mColumns.at(column), localIndex.second); if (nestedAdapter) - { return nestedAdapter->getNestedRowsCount(&mColumns.at(column), mData, localIndex.first); - } - - const CSMWorld::NestedRefIdAdapter& adaptor = dynamic_cast(findAdapter (localIndex.second)); - - return adaptor.getNestedRowsCount(&mColumns.at(column), mData, localIndex.first); + else + throw std::runtime_error("Could not find a nestedadapter"); } int CSMWorld::RefIdCollection::getNestedColumnsCount(int row, int column) const { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); - const CSMWorld::NestedRefIdAdapterBase* nestedAdapter = getNestedAdapter(mColumns.at(column)); + const CSMWorld::NestedRefIdAdapterBase* nestedAdapter = getNestedAdapter(mColumns.at(column), localIndex.second); if (nestedAdapter) - { return nestedAdapter->getNestedColumnsCount(&mColumns.at(column), mData); - } - - const CSMWorld::NestedRefIdAdapter& adaptor = dynamic_cast(findAdapter (localIndex.second)); - - return adaptor.getNestedColumnsCount(&mColumns.at(column), mData); + else + throw std::runtime_error("Could not find a nestedadapter"); } CSMWorld::NestableColumn *CSMWorld::RefIdCollection::getNestableColumn(int column) @@ -740,58 +755,56 @@ void CSMWorld::RefIdCollection::addNestedRow(int row, int col, int position) { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); - const CSMWorld::NestedRefIdAdapterBase* nestedAdapter = getNestedAdapter(mColumns.at(col)); + const CSMWorld::NestedRefIdAdapterBase* nestedAdapter = getNestedAdapter(mColumns.at(col), localIndex.second); if (nestedAdapter) { nestedAdapter->addNestedRow(&mColumns.at(col), mData, localIndex.first, position); return; } - - const CSMWorld::NestedRefIdAdapter& adaptor = dynamic_cast(findAdapter (localIndex.second)); - - adaptor.addNestedRow(&mColumns.at(col), mData, localIndex.first, position); + else + throw std::runtime_error("Could not find a nestedadapter"); } void CSMWorld::RefIdCollection::setNestedTable(int row, int column, const CSMWorld::NestedTableWrapperBase& nestedTable) { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); - const CSMWorld::NestedRefIdAdapterBase* nestedAdapter = getNestedAdapter(mColumns.at(column)); + const CSMWorld::NestedRefIdAdapterBase* nestedAdapter = getNestedAdapter(mColumns.at(column), localIndex.second); if (nestedAdapter) { nestedAdapter->setNestedTable(&mColumns.at(column), mData, localIndex.first, nestedTable); return; } - - const CSMWorld::NestedRefIdAdapter& adaptor = dynamic_cast(findAdapter (localIndex.second)); - - adaptor.setNestedTable(&mColumns.at(column), mData, localIndex.first, nestedTable); + else + throw std::runtime_error("Could not find a nestedadapter"); } CSMWorld::NestedTableWrapperBase* CSMWorld::RefIdCollection::nestedTable(int row, int column) const { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); - const CSMWorld::NestedRefIdAdapterBase* nestedAdapter = getNestedAdapter(mColumns.at(column)); + const CSMWorld::NestedRefIdAdapterBase* nestedAdapter = getNestedAdapter(mColumns.at(column), localIndex.second); if (nestedAdapter) - { return nestedAdapter->nestedTable(&mColumns.at(column), mData, localIndex.first); - } - - const CSMWorld::NestedRefIdAdapter& adaptor = dynamic_cast(findAdapter (localIndex.second)); - - return adaptor.nestedTable(&mColumns.at(column), mData, localIndex.first); + else + throw std::runtime_error("Could not find a nestedadapter"); } -const CSMWorld::NestedRefIdAdapterBase* CSMWorld::RefIdCollection::getNestedAdapter(const CSMWorld::ColumnBase &column) const +const CSMWorld::NestedRefIdAdapterBase* CSMWorld::RefIdCollection::getNestedAdapter(const CSMWorld::ColumnBase &column, UniversalId::Type type) const { - std::map::const_iterator iter = - mNestedAdapters.find (&column); + for (std::vector > >::const_iterator iter (mNestedAdapters.begin()); + iter!=mNestedAdapters.end(); ++iter) + { + if ((iter->first) == &column) + { + std::map::const_iterator it = + (iter->second).find(type); - if (iter==mNestedAdapters.end()) - return 0; // FIXME: testing only - //throw std::runtime_error("No such column in the nestedadapters"); + if (it == (iter->second).end()) + throw std::runtime_error("No such type in the nestedadapters"); - //return *iter->second; - return iter->second; + return it->second; + } + } + throw std::runtime_error("No such column in the nestedadapters"); } diff --git a/apps/opencs/model/world/refidcollection.hpp b/apps/opencs/model/world/refidcollection.hpp index 70651b78d..f183dc7a0 100644 --- a/apps/opencs/model/world/refidcollection.hpp +++ b/apps/opencs/model/world/refidcollection.hpp @@ -45,15 +45,14 @@ namespace CSMWorld std::deque mColumns; std::map mAdapters; - std::map mNestedAdapters; + std::vector > > mNestedAdapters; private: const RefIdAdapter& findAdapter (UniversalId::Type) const; ///< Throws an exception if no adaptor for \a Type can be found. - //const NestedRefIdAdapterBase& getNestedAdapter(const ColumnBase &column) const; - const NestedRefIdAdapterBase* getNestedAdapter(const ColumnBase &column) const; + const NestedRefIdAdapterBase* getNestedAdapter(const ColumnBase &column, UniversalId::Type type) const; public: From 221c57adee071d63f79ca86cda55e5974d335be3 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 13 Apr 2015 07:05:06 +1000 Subject: [PATCH 0932/3725] Fix template syntax and travis warnings. --- apps/opencs/model/world/refidadapterimp.hpp | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index 32e9148c7..2599dc960 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -17,11 +17,10 @@ #include "refiddata.hpp" #include "universalid.hpp" #include "refidadapter.hpp" +#include "nestedtablewrapper.hpp" namespace CSMWorld { - struct NestedTableWrapperBase; - struct BaseColumns { const RefIdColumn *mId; @@ -857,6 +856,7 @@ namespace CSMWorld virtual ~EffectsRefIdAdapter() {} + using NestedRefIdAdapterBase::addNestedRow; virtual void addNestedRow (const RefIdColumn *column, RefIdData& data, int index, int position) const { @@ -865,6 +865,7 @@ namespace CSMWorld EffectsListAdapter::addNestedRow(record, position); } + using NestedRefIdAdapterBase::removeNestedRow; virtual void removeNestedRow (const RefIdColumn *column, RefIdData& data, int index, int rowToRemove) const { @@ -873,6 +874,7 @@ namespace CSMWorld EffectsListAdapter::removeNestedRow(record, rowToRemove); } + using NestedRefIdAdapterBase::setNestedTable; virtual void setNestedTable (const RefIdColumn* column, RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const { @@ -881,6 +883,7 @@ namespace CSMWorld EffectsListAdapter::setNestedTable(record, nestedTable); } + using NestedRefIdAdapterBase::nestedTable; virtual NestedTableWrapperBase* nestedTable (const RefIdColumn* column, const RefIdData& data, int index) const { @@ -889,6 +892,7 @@ namespace CSMWorld return EffectsListAdapter::nestedTable(record); } + using NestedRefIdAdapterBase::getNestedData; virtual QVariant getNestedData (const RefIdColumn *column, const RefIdData& data, int index, int subRowIndex, int subColIndex) const { @@ -897,6 +901,7 @@ namespace CSMWorld return EffectsListAdapter::getNestedData(record, subRowIndex, subColIndex); } + using NestedRefIdAdapterBase::setNestedData; virtual void setNestedData (const RefIdColumn *column, RefIdData& data, int row, const QVariant& value, int subRowIndex, int subColIndex) const { @@ -905,12 +910,14 @@ namespace CSMWorld EffectsListAdapter::setNestedData(record, value, subRowIndex, subColIndex); } + using NestedRefIdAdapterBase::getNestedColumnsCount; virtual int getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const { const Record record; // not used, just a dummy return EffectsListAdapter::getNestedColumnsCount(record); } + using NestedRefIdAdapterBase::getNestedRowsCount; virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const { const Record& record = @@ -978,7 +985,7 @@ namespace CSMWorld ESXRecordT container = record.get(); container.mInventory.mList = - static_cast >&>(nestedTable).mNestedTable; + static_cast >&>(nestedTable).mNestedTable; record.setModified (container); } @@ -1116,7 +1123,7 @@ namespace CSMWorld ESXRecordT caster = record.get(); caster.mSpells.mList = - static_cast >&>(nestedTable).mNestedTable; + static_cast >&>(nestedTable).mNestedTable; record.setModified (caster); } @@ -1128,7 +1135,7 @@ namespace CSMWorld static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); // deleted by dtor of NestedTableStoring - return new NestedTableWrapper >(record.get().mSpells.mList); + return new NestedTableWrapper >(record.get().mSpells.mList); } virtual QVariant getNestedData (const RefIdColumn *column, @@ -1251,7 +1258,7 @@ namespace CSMWorld ESXRecordT traveller = record.get(); traveller.mTransport.mList = - static_cast >&>(nestedTable).mNestedTable; + static_cast >&>(nestedTable).mNestedTable; record.setModified (traveller); } @@ -1263,7 +1270,7 @@ namespace CSMWorld static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); // deleted by dtor of NestedTableStoring - return new NestedTableWrapper >(record.get().mTransport.mList); + return new NestedTableWrapper >(record.get().mTransport.mList); } virtual QVariant getNestedData (const RefIdColumn *column, From 60e5ff8811e84951a9bd160a4a2969fc50b55a92 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 13 Apr 2015 08:03:30 +1000 Subject: [PATCH 0933/3725] Remove duplicated checks and exceptions. --- apps/opencs/model/world/refidadapterimp.hpp | 2 +- apps/opencs/model/world/refidcollection.cpp | 76 ++++++--------------- apps/opencs/model/world/refidcollection.hpp | 2 +- 3 files changed, 24 insertions(+), 56 deletions(-) diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index 2599dc960..a3007d415 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -997,7 +997,7 @@ namespace CSMWorld static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); // deleted by dtor of NestedTableStoring - return new NestedTableWrapper >(record.get().mInventory.mList); + return new NestedTableWrapper >(record.get().mInventory.mList); } virtual QVariant getNestedData (const RefIdColumn *column, diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 92cd37d0d..3f14ba4ac 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -539,12 +539,9 @@ QVariant CSMWorld::RefIdCollection::getData (int index, int column) const QVariant CSMWorld::RefIdCollection::getNestedData (int row, int column, int subRow, int subColumn) const { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex(row); + const CSMWorld::NestedRefIdAdapterBase& nestedAdapter = getNestedAdapter(mColumns.at(column), localIndex.second); - const CSMWorld::NestedRefIdAdapterBase* nestedAdapter = getNestedAdapter(mColumns.at(column), localIndex.second); - if (nestedAdapter) - return nestedAdapter->getNestedData(&mColumns.at (column), mData, localIndex.first, subRow, subColumn); - else - throw std::runtime_error("Could not find a nestedadapter"); + return nestedAdapter.getNestedData(&mColumns.at (column), mData, localIndex.first, subRow, subColumn); } void CSMWorld::RefIdCollection::setData (int index, int column, const QVariant& data) @@ -559,15 +556,10 @@ void CSMWorld::RefIdCollection::setData (int index, int column, const QVariant& void CSMWorld::RefIdCollection::setNestedData(int row, int column, const QVariant& data, int subRow, int subColumn) { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); + const CSMWorld::NestedRefIdAdapterBase& nestedAdapter = getNestedAdapter(mColumns.at(column), localIndex.second); - const CSMWorld::NestedRefIdAdapterBase* nestedAdapter = getNestedAdapter(mColumns.at(column), localIndex.second); - if (nestedAdapter) - { - nestedAdapter->setNestedData(&mColumns.at (column), mData, localIndex.first, data, subRow, subColumn); - return; - } - else - throw std::runtime_error("Could not find a nestedadapter"); + nestedAdapter.setNestedData(&mColumns.at (column), mData, localIndex.first, data, subRow, subColumn); + return; } void CSMWorld::RefIdCollection::removeRows (int index, int count) @@ -578,15 +570,10 @@ void CSMWorld::RefIdCollection::removeRows (int index, int count) void CSMWorld::RefIdCollection::removeNestedRows(int row, int column, int subRow) { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); + const CSMWorld::NestedRefIdAdapterBase& nestedAdapter = getNestedAdapter(mColumns.at(column), localIndex.second); - const CSMWorld::NestedRefIdAdapterBase* nestedAdapter = getNestedAdapter(mColumns.at(column), localIndex.second); - if (nestedAdapter) - { - nestedAdapter->removeNestedRow(&mColumns.at (column), mData, localIndex.first, subRow); - return; - } - else - throw std::runtime_error("Could not find a nestedadapter"); + nestedAdapter.removeNestedRow(&mColumns.at (column), mData, localIndex.first, subRow); + return; } void CSMWorld::RefIdCollection::appendBlankRecord (const std::string& id, UniversalId::Type type) @@ -727,23 +714,17 @@ const CSMWorld::RefIdData& CSMWorld::RefIdCollection::getDataSet() const int CSMWorld::RefIdCollection::getNestedRowsCount(int row, int column) const { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); + const CSMWorld::NestedRefIdAdapterBase& nestedAdapter = getNestedAdapter(mColumns.at(column), localIndex.second); - const CSMWorld::NestedRefIdAdapterBase* nestedAdapter = getNestedAdapter(mColumns.at(column), localIndex.second); - if (nestedAdapter) - return nestedAdapter->getNestedRowsCount(&mColumns.at(column), mData, localIndex.first); - else - throw std::runtime_error("Could not find a nestedadapter"); + return nestedAdapter.getNestedRowsCount(&mColumns.at(column), mData, localIndex.first); } int CSMWorld::RefIdCollection::getNestedColumnsCount(int row, int column) const { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); + const CSMWorld::NestedRefIdAdapterBase& nestedAdapter = getNestedAdapter(mColumns.at(column), localIndex.second); - const CSMWorld::NestedRefIdAdapterBase* nestedAdapter = getNestedAdapter(mColumns.at(column), localIndex.second); - if (nestedAdapter) - return nestedAdapter->getNestedColumnsCount(&mColumns.at(column), mData); - else - throw std::runtime_error("Could not find a nestedadapter"); + return nestedAdapter.getNestedColumnsCount(&mColumns.at(column), mData); } CSMWorld::NestableColumn *CSMWorld::RefIdCollection::getNestableColumn(int column) @@ -754,43 +735,30 @@ CSMWorld::NestableColumn *CSMWorld::RefIdCollection::getNestableColumn(int colum void CSMWorld::RefIdCollection::addNestedRow(int row, int col, int position) { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); + const CSMWorld::NestedRefIdAdapterBase& nestedAdapter = getNestedAdapter(mColumns.at(col), localIndex.second); - const CSMWorld::NestedRefIdAdapterBase* nestedAdapter = getNestedAdapter(mColumns.at(col), localIndex.second); - if (nestedAdapter) - { - nestedAdapter->addNestedRow(&mColumns.at(col), mData, localIndex.first, position); - return; - } - else - throw std::runtime_error("Could not find a nestedadapter"); + nestedAdapter.addNestedRow(&mColumns.at(col), mData, localIndex.first, position); + return; } void CSMWorld::RefIdCollection::setNestedTable(int row, int column, const CSMWorld::NestedTableWrapperBase& nestedTable) { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); + const CSMWorld::NestedRefIdAdapterBase& nestedAdapter = getNestedAdapter(mColumns.at(column), localIndex.second); - const CSMWorld::NestedRefIdAdapterBase* nestedAdapter = getNestedAdapter(mColumns.at(column), localIndex.second); - if (nestedAdapter) - { - nestedAdapter->setNestedTable(&mColumns.at(column), mData, localIndex.first, nestedTable); - return; - } - else - throw std::runtime_error("Could not find a nestedadapter"); + nestedAdapter.setNestedTable(&mColumns.at(column), mData, localIndex.first, nestedTable); + return; } CSMWorld::NestedTableWrapperBase* CSMWorld::RefIdCollection::nestedTable(int row, int column) const { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); + const CSMWorld::NestedRefIdAdapterBase& nestedAdapter = getNestedAdapter(mColumns.at(column), localIndex.second); - const CSMWorld::NestedRefIdAdapterBase* nestedAdapter = getNestedAdapter(mColumns.at(column), localIndex.second); - if (nestedAdapter) - return nestedAdapter->nestedTable(&mColumns.at(column), mData, localIndex.first); - else - throw std::runtime_error("Could not find a nestedadapter"); + return nestedAdapter.nestedTable(&mColumns.at(column), mData, localIndex.first); } -const CSMWorld::NestedRefIdAdapterBase* CSMWorld::RefIdCollection::getNestedAdapter(const CSMWorld::ColumnBase &column, UniversalId::Type type) const +const CSMWorld::NestedRefIdAdapterBase& CSMWorld::RefIdCollection::getNestedAdapter(const CSMWorld::ColumnBase &column, UniversalId::Type type) const { for (std::vector > >::const_iterator iter (mNestedAdapters.begin()); iter!=mNestedAdapters.end(); ++iter) @@ -803,7 +771,7 @@ const CSMWorld::NestedRefIdAdapterBase* CSMWorld::RefIdCollection::getNestedAdap if (it == (iter->second).end()) throw std::runtime_error("No such type in the nestedadapters"); - return it->second; + return *it->second; } } throw std::runtime_error("No such column in the nestedadapters"); diff --git a/apps/opencs/model/world/refidcollection.hpp b/apps/opencs/model/world/refidcollection.hpp index f183dc7a0..4d511d12d 100644 --- a/apps/opencs/model/world/refidcollection.hpp +++ b/apps/opencs/model/world/refidcollection.hpp @@ -52,7 +52,7 @@ namespace CSMWorld const RefIdAdapter& findAdapter (UniversalId::Type) const; ///< Throws an exception if no adaptor for \a Type can be found. - const NestedRefIdAdapterBase* getNestedAdapter(const ColumnBase &column, UniversalId::Type type) const; + const NestedRefIdAdapterBase& getNestedAdapter(const ColumnBase &column, UniversalId::Type type) const; public: From 526b53fce017d154f1a01e5095f4c42d1a271241 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 13 Apr 2015 14:14:00 +1000 Subject: [PATCH 0934/3725] Add AI packages table to dialogue subview. Also minor bug fixes. --- apps/opencs/model/world/columns.cpp | 17 +- apps/opencs/model/world/columns.hpp | 24 +- .../model/world/nestedcoladapterimp.cpp | 4 +- .../model/world/nestedcoladapterimp.hpp | 3 +- apps/opencs/model/world/refidadapterimp.hpp | 316 +++++++++++++++++- apps/opencs/model/world/refidcollection.cpp | 36 ++ 6 files changed, 380 insertions(+), 20 deletions(-) diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index fca16ec0b..92a0d8f8d 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -192,9 +192,9 @@ namespace CSMWorld { ColumnId_NpcDestinations, "Destinations" }, { ColumnId_DestinationCell, "Cell"}, - { ColumnId_PosX, "X"}, - { ColumnId_PosY, "Y"}, - { ColumnId_PosZ, "Z"}, + { ColumnId_PosX, "Dest X"}, + { ColumnId_PosY, "Dest Y"}, + { ColumnId_PosZ, "Dest Z"}, { ColumnId_RotX, "Rotation X"}, { ColumnId_RotY, "Rotation Y"}, { ColumnId_RotZ, "Rotation Z"}, @@ -247,6 +247,17 @@ namespace CSMWorld { ColumnId_EffectRange, "Range"}, { ColumnId_EffectArea, "Area"}, + { ColumnId_AiPackageList, "Ai Packages"}, + { ColumnId_AiPackage, "Package"}, + { ColumnId_AiWanderDist, "Wander Dist"}, + { ColumnId_AiWanderDuration, "Wander Duration"}, + { ColumnId_AiWanderToD, "Wander ToD"}, + { ColumnId_AiWanderIdle, "Wander Idle"}, + { ColumnId_AiWanderRepeat, "Wander Repeat"}, + { ColumnId_AiActivateName, "Activate"}, + { ColumnId_AiTargetId, "Target ID"}, + { ColumnId_AiTargetCell, "Target Cell"}, + { ColumnId_UseValue1, "Use value 1" }, { ColumnId_UseValue2, "Use value 2" }, { ColumnId_UseValue3, "Use value 3" }, diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 4f77ee23a..2788966a7 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -183,9 +183,9 @@ namespace CSMWorld ColumnId_SpellId = 168, ColumnId_NpcDestinations = 169, ColumnId_DestinationCell = 170, - ColumnId_PosX = 171, - ColumnId_PosY = 172, - ColumnId_PosZ = 173, + ColumnId_PosX = 171, // these are float + ColumnId_PosY = 172, // these are float + ColumnId_PosZ = 173, // these are float ColumnId_RotX = 174, ColumnId_RotY = 175, ColumnId_RotZ = 176, @@ -214,9 +214,9 @@ namespace CSMWorld ColumnId_PathgridPoints = 199, ColumnId_PathgridIndex = 200, - ColumnId_PathgridPosX = 201, - ColumnId_PathgridPosY = 202, - ColumnId_PathgridPosZ = 203, + ColumnId_PathgridPosX = 201, // these are int + ColumnId_PathgridPosY = 202, // these are int + ColumnId_PathgridPosZ = 203, // these are int ColumnId_PathgridEdges = 204, ColumnId_PathgridEdgeIndex = 205, ColumnId_PathgridEdge0 = 206, @@ -236,6 +236,18 @@ namespace CSMWorld ColumnId_EffectRange = 217, ColumnId_EffectArea = 218, + ColumnId_AiPackageList = 219, + ColumnId_AiPackage = 220, + ColumnId_AiWanderDist = 221, + ColumnId_AiWanderDuration = 222, + ColumnId_AiWanderToD = 223, + ColumnId_AiWanderIdle = 224, + ColumnId_AiWanderRepeat = 225, + ColumnId_AiActivateName = 226, + // use ColumnId_PosX, etc for AI destinations + ColumnId_AiTargetId = 227, + ColumnId_AiTargetCell = 228, + // Allocated to a separate value range, so we don't get a collision should we ever need // to extend the number of use values. ColumnId_UseValue1 = 0x10000, diff --git a/apps/opencs/model/world/nestedcoladapterimp.cpp b/apps/opencs/model/world/nestedcoladapterimp.cpp index 785817d33..d974a34c7 100644 --- a/apps/opencs/model/world/nestedcoladapterimp.cpp +++ b/apps/opencs/model/world/nestedcoladapterimp.cpp @@ -121,7 +121,7 @@ namespace CSMWorld ESM::Pathgrid::Point point = pathgrid.mPoints[subRowIndex]; switch (subColIndex) { - case 0: break; + case 0: return; // return without saving case 1: point.mX = value.toInt(); break; case 2: point.mY = value.toInt(); break; case 3: point.mZ = value.toInt(); break; @@ -228,7 +228,7 @@ namespace CSMWorld ESM::Pathgrid::Edge edge = pathgrid.mEdges[subRowIndex]; switch (subColIndex) { - case 0: break; + case 0: return; // return without saving case 1: edge.mV0 = value.toInt(); break; case 2: edge.mV1 = value.toInt(); break; default: throw std::runtime_error("Pathgrid edge subcolumn index out of range"); diff --git a/apps/opencs/model/world/nestedcoladapterimp.hpp b/apps/opencs/model/world/nestedcoladapterimp.hpp index 387b07e5c..3328396fb 100644 --- a/apps/opencs/model/world/nestedcoladapterimp.hpp +++ b/apps/opencs/model/world/nestedcoladapterimp.hpp @@ -457,7 +457,8 @@ namespace CSMWorld effect.mRange = ESM::RT_Touch; else if (effectId == "Target") effect.mRange = ESM::RT_Target; - // else leave unchanged + else + return; // leave unchanged break; } case 4: effect.mArea = value.toInt(); break; diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index a3007d415..c0fcba43c 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -10,8 +10,6 @@ #include #include #include -#include -#include #include "record.hpp" #include "refiddata.hpp" @@ -489,6 +487,7 @@ namespace CSMWorld const RefIdColumn *mInventory; const RefIdColumn *mSpells; const RefIdColumn *mDestinations; + const RefIdColumn *mAiPackages; std::map mServices; ActorColumns (const NameColumns& base) : NameColumns (base) {} @@ -549,6 +548,9 @@ namespace CSMWorld if (column==mActors.mDestinations) return true; // to show nested tables in dialogue subview, see IdTree::hasChildren() + if (column==mActors.mAiPackages) + return true; // to show nested tables in dialogue subview, see IdTree::hasChildren() + std::map::const_iterator iter = mActors.mServices.find (column); @@ -985,7 +987,7 @@ namespace CSMWorld ESXRecordT container = record.get(); container.mInventory.mList = - static_cast >&>(nestedTable).mNestedTable; + static_cast >&>(nestedTable).mNestedTable; record.setModified (container); } @@ -997,7 +999,7 @@ namespace CSMWorld static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); // deleted by dtor of NestedTableStoring - return new NestedTableWrapper >(record.get().mInventory.mList); + return new NestedTableWrapper >(record.get().mInventory.mList); } virtual QVariant getNestedData (const RefIdColumn *column, @@ -1123,7 +1125,7 @@ namespace CSMWorld ESXRecordT caster = record.get(); caster.mSpells.mList = - static_cast >&>(nestedTable).mNestedTable; + static_cast >&>(nestedTable).mNestedTable; record.setModified (caster); } @@ -1135,7 +1137,7 @@ namespace CSMWorld static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); // deleted by dtor of NestedTableStoring - return new NestedTableWrapper >(record.get().mSpells.mList); + return new NestedTableWrapper >(record.get().mSpells.mList); } virtual QVariant getNestedData (const RefIdColumn *column, @@ -1258,7 +1260,7 @@ namespace CSMWorld ESXRecordT traveller = record.get(); traveller.mTransport.mList = - static_cast >&>(nestedTable).mNestedTable; + static_cast >&>(nestedTable).mNestedTable; record.setModified (traveller); } @@ -1270,7 +1272,7 @@ namespace CSMWorld static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); // deleted by dtor of NestedTableStoring - return new NestedTableWrapper >(record.get().mTransport.mList); + return new NestedTableWrapper >(record.get().mTransport.mList); } virtual QVariant getNestedData (const RefIdColumn *column, @@ -1375,6 +1377,304 @@ namespace CSMWorld return static_cast(record.get().mTransport.mList.size()); } }; + + template + class ActorAiRefIdAdapter : public NestedRefIdAdapterBase + { + UniversalId::Type mType; + + // not implemented + ActorAiRefIdAdapter (const ActorAiRefIdAdapter&); + ActorAiRefIdAdapter& operator= (const ActorAiRefIdAdapter&); + + public: + + ActorAiRefIdAdapter(UniversalId::Type type) :mType(type) {} + + virtual ~ActorAiRefIdAdapter() {} + + virtual void addNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int position) const + { + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + ESXRecordT actor = record.get(); + + std::vector& list = actor.mAiPackage.mList; + + ESM::AIPackage newRow; + newRow.mType = ESM::AI_CNDT; + newRow.mCellName = ""; + + if (position >= (int)list.size()) + list.push_back(newRow); + else + list.insert(list.begin()+position, newRow); + + record.setModified (actor); + } + + virtual void removeNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int rowToRemove) const + { + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + ESXRecordT actor = record.get(); + + std::vector& list = actor.mAiPackage.mList; + + if (rowToRemove < 0 || rowToRemove >= static_cast (list.size())) + throw std::runtime_error ("index out of range"); + + list.erase (list.begin () + rowToRemove); + + record.setModified (actor); + } + + virtual void setNestedTable (const RefIdColumn* column, + RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const + { + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + ESXRecordT actor = record.get(); + + actor.mAiPackage.mList = + static_cast >&>(nestedTable).mNestedTable; + + record.setModified (actor); + } + + virtual NestedTableWrapperBase* nestedTable (const RefIdColumn* column, + const RefIdData& data, int index) const + { + const Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + + // deleted by dtor of NestedTableStoring + return new NestedTableWrapper >(record.get().mAiPackage.mList); + } + + virtual QVariant getNestedData (const RefIdColumn *column, + const RefIdData& data, int index, int subRowIndex, int subColIndex) const + { + const Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + + const std::vector& list = record.get().mAiPackage.mList; + + if (subRowIndex < 0 || subRowIndex >= static_cast (list.size())) + throw std::runtime_error ("index out of range"); + + const ESM::AIPackage& content = list.at(subRowIndex); + + switch (subColIndex) + { + case 0: + switch (content.mType) + { + case ESM::AI_Wander: return QString("AI Wander"); + case ESM::AI_Travel: return QString("AI Travel"); + case ESM::AI_Follow: return QString("AI Follow"); + case ESM::AI_Escort: return QString("AI Escort"); + case ESM::AI_Activate: return QString("AI Activate"); + case ESM::AI_CNDT: + default: return QString("None"); + } + case 1: // wander dist + if (content.mType == ESM::AI_Wander) + return content.mWander.mDistance; + else + return QVariant(); + case 2: // wander dur + if (content.mType == ESM::AI_Wander || + content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort) + return content.mWander.mDuration; + else + return QVariant(); + case 3: // wander ToD + if (content.mType == ESM::AI_Wander) + return content.mWander.mTimeOfDay; // FIXME: not sure of the format + else + return QVariant(); + case 4: // wander idle + if (content.mType == ESM::AI_Wander) + { + return static_cast(content.mWander.mIdle[0]); // FIXME: + } + else + return QVariant(); + case 5: // wander repeat + if (content.mType == ESM::AI_Wander) + return QString(content.mWander.mShouldRepeat ? "Yes" : "No"); + else + return QVariant(); + case 6: // activate name + if (content.mType == ESM::AI_Activate) + return QString(content.mActivate.mName.toString().c_str()); + else + return QVariant(); + case 7: // target id + if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort) + return QString(content.mTarget.mId.toString().c_str()); + else + return QVariant(); + case 8: // target cell + if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort) + return QString::fromUtf8(content.mCellName.c_str()); + else + return QVariant(); + case 9: + if (content.mType == ESM::AI_Travel) + return content.mTravel.mX; + else if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort) + return content.mTarget.mX; + else + return QVariant(); + case 10: + if (content.mType == ESM::AI_Travel) + return content.mTravel.mY; + else if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort) + return content.mTarget.mY; + else + return QVariant(); + case 11: + if (content.mType == ESM::AI_Travel) + return content.mTravel.mZ; + else if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort) + return content.mTarget.mZ; + else + return QVariant(); + default: + throw std::runtime_error("Trying to access non-existing column in the nested table!"); + } + } + + virtual void setNestedData (const RefIdColumn *column, + RefIdData& data, int row, const QVariant& value, int subRowIndex, int subColIndex) const + { + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (row, mType))); + ESXRecordT actor = record.get(); + std::vector& list = actor.mAiPackage.mList; + + if (subRowIndex < 0 || subRowIndex >= static_cast (list.size())) + throw std::runtime_error ("index out of range"); + + ESM::AIPackage& content = list.at(subRowIndex); + + switch(subColIndex) + { + case 0: // ai package type + if ("AI Wander" == value.toString().toStdString()) + content.mType = ESM::AI_Wander; + else if ("AI Travel" == value.toString().toStdString()) + content.mType = ESM::AI_Travel; + else if ("AI Follow" == value.toString().toStdString()) + content.mType = ESM::AI_Follow; + else if ("AI Escort" == value.toString().toStdString()) + content.mType = ESM::AI_Escort; + else if ("AI Activate" == value.toString().toStdString()) + content.mType = ESM::AI_Activate; + else + content.mType = ESM::AI_CNDT; + break; // always save + + case 1: + if (content.mType == ESM::AI_Wander) + content.mWander.mDistance = static_cast(value.toInt()); + else + return; // return without saving + case 2: + if (content.mType == ESM::AI_Wander || + content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort) + content.mWander.mDuration = static_cast(value.toInt()); + else + return; // return without saving + case 3: + if (content.mType == ESM::AI_Wander) + content.mWander.mTimeOfDay = static_cast(value.toInt()); + else + return; // return without saving + case 4: + if (content.mType == ESM::AI_Wander) + break; // FIXME: idle + else + return; // return without saving + case 5: + if (content.mType == ESM::AI_Wander) + { + if ("Yes" == value.toString().toStdString()) + content.mWander.mShouldRepeat = 1; + if ("No" == value.toString().toStdString()) + content.mWander.mShouldRepeat = 0; + else + return; // return without saving + } + case 6: // NAME32 + if (content.mType == ESM::AI_Activate) + { + content.mActivate.mName.assign(value.toString().toUtf8().constData()); + break; + } + else + return; // return without saving + case 7: // NAME32 + if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort) + { + content.mTarget.mId.assign(value.toString().toUtf8().constData()); + break; + } + else + return; // return without saving + case 8: + if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort) + { + content.mCellName = std::string(value.toString().toUtf8().constData()); + break; + } + else + return; // return without saving + case 9: + if (content.mType == ESM::AI_Travel) + content.mTravel.mZ = value.toFloat(); + else if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort) + content.mTarget.mZ = value.toFloat(); + else + return; // return without saving + case 10: + if (content.mType == ESM::AI_Travel) + content.mTravel.mZ = value.toFloat(); + else if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort) + content.mTarget.mZ = value.toFloat(); + else + return; // return without saving + case 11: + if (content.mType == ESM::AI_Travel) + content.mTravel.mZ = value.toFloat(); + else if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort) + content.mTarget.mZ = value.toFloat(); + else + return; // return without saving + default: + throw std::runtime_error("Trying to access non-existing column in the nested table!"); + } + + record.setModified (actor); + } + + virtual int getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const + { + return 12; + } + + virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const + { + const Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + + return static_cast(record.get().mAiPackage.mList.size()); + } + }; } #endif diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 3f14ba4ac..000426a0b 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -180,6 +180,42 @@ CSMWorld::RefIdCollection::RefIdCollection() mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_RotZ, CSMWorld::ColumnBase::Display_Float)); + // Nested table + mColumns.push_back(RefIdColumn (Columns::ColumnId_AiPackageList, ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue)); + actorsColumns.mAiPackages = &mColumns.back(); + + std::map aiMap; + aiMap.insert( + std::make_pair(UniversalId::Type_Npc, new ActorAiRefIdAdapter (UniversalId::Type_Npc))); + aiMap.insert( + std::make_pair(UniversalId::Type_Creature, new ActorAiRefIdAdapter (UniversalId::Type_Creature))); + + mNestedAdapters.push_back (std::make_pair(&mColumns.back(), aiMap)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_AiPackage, CSMWorld::ColumnBase::Display_String)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_AiWanderDist, CSMWorld::ColumnBase::Display_Integer)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_AiWanderDuration, CSMWorld::ColumnBase::Display_Integer)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_AiWanderToD, CSMWorld::ColumnBase::Display_Integer)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_AiWanderIdle, CSMWorld::ColumnBase::Display_Integer)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_AiWanderRepeat, CSMWorld::ColumnBase::Display_String)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_AiActivateName, CSMWorld::ColumnBase::Display_String)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_AiTargetId, CSMWorld::ColumnBase::Display_String)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_AiTargetCell, CSMWorld::ColumnBase::Display_String)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_PosX, CSMWorld::ColumnBase::Display_Float)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_PosY, CSMWorld::ColumnBase::Display_Float)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_PosZ, CSMWorld::ColumnBase::Display_Float)); + static const struct { int mName; From 513c3a47cb8d54b6dea46bdb5816bde1f5739aa8 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 13 Apr 2015 21:08:23 +1000 Subject: [PATCH 0935/3725] Add clothing/armor part reference table to dialogue subview. --- apps/opencs/model/world/columns.cpp | 7 +- apps/opencs/model/world/columns.hpp | 7 +- .../model/world/nestedcoladapterimp.hpp | 2 +- apps/opencs/model/world/refidadapterimp.cpp | 16 +- apps/opencs/model/world/refidadapterimp.hpp | 199 ++++++++++++++++-- apps/opencs/model/world/refidcollection.cpp | 24 ++- 6 files changed, 222 insertions(+), 33 deletions(-) diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 92a0d8f8d..547efac56 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -250,7 +250,7 @@ namespace CSMWorld { ColumnId_AiPackageList, "Ai Packages"}, { ColumnId_AiPackage, "Package"}, { ColumnId_AiWanderDist, "Wander Dist"}, - { ColumnId_AiWanderDuration, "Wander Duration"}, + { ColumnId_AiDuration, "Duration"}, { ColumnId_AiWanderToD, "Wander ToD"}, { ColumnId_AiWanderIdle, "Wander Idle"}, { ColumnId_AiWanderRepeat, "Wander Repeat"}, @@ -258,6 +258,11 @@ namespace CSMWorld { ColumnId_AiTargetId, "Target ID"}, { ColumnId_AiTargetCell, "Target Cell"}, + { ColumnId_PartRefList, "Part Reference"}, + { ColumnId_PartRefType, "Type"}, + { ColumnId_PartRefMale, "Male"}, + { ColumnId_PartRefFemale, "Female"}, + { ColumnId_UseValue1, "Use value 1" }, { ColumnId_UseValue2, "Use value 2" }, { ColumnId_UseValue3, "Use value 3" }, diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 2788966a7..6068ea6e7 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -239,7 +239,7 @@ namespace CSMWorld ColumnId_AiPackageList = 219, ColumnId_AiPackage = 220, ColumnId_AiWanderDist = 221, - ColumnId_AiWanderDuration = 222, + ColumnId_AiDuration = 222, ColumnId_AiWanderToD = 223, ColumnId_AiWanderIdle = 224, ColumnId_AiWanderRepeat = 225, @@ -248,6 +248,11 @@ namespace CSMWorld ColumnId_AiTargetId = 227, ColumnId_AiTargetCell = 228, + ColumnId_PartRefList = 229, + ColumnId_PartRefType = 230, + ColumnId_PartRefMale = 231, + ColumnId_PartRefFemale = 232, + // Allocated to a separate value range, so we don't get a collision should we ever need // to extend the number of use values. ColumnId_UseValue1 = 0x10000, diff --git a/apps/opencs/model/world/nestedcoladapterimp.hpp b/apps/opencs/model/world/nestedcoladapterimp.hpp index 3328396fb..2aa1123a3 100644 --- a/apps/opencs/model/world/nestedcoladapterimp.hpp +++ b/apps/opencs/model/world/nestedcoladapterimp.hpp @@ -175,7 +175,7 @@ namespace CSMWorld { ESXRecordT raceOrBthSgn = record.get(); - raceOrBthSgn.mPowers.mList = + raceOrBthSgn.mPowers.mList = static_cast >&>(nestedTable).mNestedTable; record.setModified (raceOrBthSgn); diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index cd3a20327..98c1b6f0f 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -81,9 +81,10 @@ void CSMWorld::ApparatusRefIdAdapter::setData (const RefIdColumn *column, RefIdD CSMWorld::ArmorRefIdAdapter::ArmorRefIdAdapter (const EnchantableColumns& columns, - const RefIdColumn *type, const RefIdColumn *health, const RefIdColumn *armor) + const RefIdColumn *type, const RefIdColumn *health, const RefIdColumn *armor, + const RefIdColumn *partRef) : EnchantableRefIdAdapter (UniversalId::Type_Armor, columns), - mType (type), mHealth (health), mArmor (armor) + mType (type), mHealth (health), mArmor (armor), mPartRef(partRef) {} QVariant CSMWorld::ArmorRefIdAdapter::getData (const RefIdColumn *column, @@ -101,6 +102,9 @@ QVariant CSMWorld::ArmorRefIdAdapter::getData (const RefIdColumn *column, if (column==mArmor) return record.get().mData.mArmor; + if (column==mPartRef) + return true; // to show nested tables in dialogue subview, see IdTree::hasChildren() + return EnchantableRefIdAdapter::getData (column, data, index); } @@ -156,8 +160,9 @@ void CSMWorld::BookRefIdAdapter::setData (const RefIdColumn *column, RefIdData& } CSMWorld::ClothingRefIdAdapter::ClothingRefIdAdapter (const EnchantableColumns& columns, - const RefIdColumn *type) -: EnchantableRefIdAdapter (UniversalId::Type_Clothing, columns), mType (type) + const RefIdColumn *type, const RefIdColumn *partRef) +: EnchantableRefIdAdapter (UniversalId::Type_Clothing, columns), mType (type), + mPartRef(partRef) {} QVariant CSMWorld::ClothingRefIdAdapter::getData (const RefIdColumn *column, @@ -169,6 +174,9 @@ QVariant CSMWorld::ClothingRefIdAdapter::getData (const RefIdColumn *column, if (column==mType) return record.get().mData.mType; + if (column==mPartRef) + return true; // to show nested tables in dialogue subview, see IdTree::hasChildren() + return EnchantableRefIdAdapter::getData (column, data, index); } diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index c0fcba43c..bc00d31f9 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -622,11 +622,12 @@ namespace CSMWorld const RefIdColumn *mType; const RefIdColumn *mHealth; const RefIdColumn *mArmor; + const RefIdColumn *mPartRef; public: ArmorRefIdAdapter (const EnchantableColumns& columns, const RefIdColumn *type, - const RefIdColumn *health, const RefIdColumn *armor); + const RefIdColumn *health, const RefIdColumn *armor, const RefIdColumn *partRef); virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index) const; @@ -657,10 +658,12 @@ namespace CSMWorld class ClothingRefIdAdapter : public EnchantableRefIdAdapter { const RefIdColumn *mType; + const RefIdColumn *mPartRef; public: - ClothingRefIdAdapter (const EnchantableColumns& columns, const RefIdColumn *type); + ClothingRefIdAdapter (const EnchantableColumns& columns, + const RefIdColumn *type, const RefIdColumn *partRef); virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index) const; @@ -1290,27 +1293,13 @@ namespace CSMWorld switch (subColIndex) { - case 0: - return QString::fromUtf8(content.mCellName.c_str()); - - case 1: - return content.mPos.pos[0]; - - case 2: - return content.mPos.pos[1]; - - case 3: - return content.mPos.pos[2]; - - case 4: - return content.mPos.rot[0]; - - case 5: - return content.mPos.rot[1]; - - case 6: - return content.mPos.rot[2]; - + case 0: return QString::fromUtf8(content.mCellName.c_str()); + case 1: return content.mPos.pos[0]; + case 2: return content.mPos.pos[1]; + case 3: return content.mPos.pos[2]; + case 4: return content.mPos.rot[0]; + case 5: return content.mPos.rot[1]; + case 6: return content.mPos.rot[2]; default: throw std::runtime_error("Trying to access non-existing column in the nested table!"); } @@ -1675,6 +1664,170 @@ namespace CSMWorld return static_cast(record.get().mAiPackage.mList.size()); } }; + + static const char *sPartRefs[ESM::PRT_Count] = + { + "Head", "Hair", "Neck", "Cuirass", "Groin", + "Skirt", "Right Hand", "Left Hand", "Right Wrist", "Left Wrist", + "Shield", "Right Forearm", "Left Forearm", "Right Upperarm", "Left Upperarm", + "Right Foot", "Left Foot", "Right Ankle", "Left Ankle", "Right Knee", + "Left Knee", "Right Leg", "Left Leg", "Right Pauldron", "Left Pauldron", + "Weapon", "Tail" + }; + + template + class BodyPartRefIdAdapter : public NestedRefIdAdapterBase + { + UniversalId::Type mType; + + // not implemented + BodyPartRefIdAdapter (const BodyPartRefIdAdapter&); + BodyPartRefIdAdapter& operator= (const BodyPartRefIdAdapter&); + + public: + + BodyPartRefIdAdapter(UniversalId::Type type) :mType(type) {} + + virtual ~BodyPartRefIdAdapter() {} + + virtual void addNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int position) const + { + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + ESXRecordT apparel = record.get(); + + std::vector& list = apparel.mParts.mParts; + + ESM::PartReference newPart; + newPart.mPart = 0; // 0 == head + newPart.mMale = ""; + newPart.mFemale = ""; + + if (position >= (int)list.size()) + list.push_back(newPart); + else + list.insert(list.begin()+position, newPart); + + record.setModified (apparel); + } + + virtual void removeNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int rowToRemove) const + { + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + ESXRecordT apparel = record.get(); + + std::vector& list = apparel.mParts.mParts; + + if (rowToRemove < 0 || rowToRemove >= static_cast (list.size())) + throw std::runtime_error ("index out of range"); + + list.erase (list.begin () + rowToRemove); + + record.setModified (apparel); + } + + virtual void setNestedTable (const RefIdColumn* column, + RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const + { + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + ESXRecordT apparel = record.get(); + + apparel.mParts.mParts = + static_cast >&>(nestedTable).mNestedTable; + + record.setModified (apparel); + } + + virtual NestedTableWrapperBase* nestedTable (const RefIdColumn* column, + const RefIdData& data, int index) const + { + const Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + + // deleted by dtor of NestedTableStoring + return new NestedTableWrapper >(record.get().mParts.mParts); + } + + virtual QVariant getNestedData (const RefIdColumn *column, + const RefIdData& data, int index, int subRowIndex, int subColIndex) const + { + const Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + + const std::vector& list = record.get().mParts.mParts; + + if (subRowIndex < 0 || subRowIndex >= static_cast (list.size())) + throw std::runtime_error ("index out of range"); + + const ESM::PartReference& content = list.at(subRowIndex); + + switch (subColIndex) + { + case 0: return QString(sPartRefs[content.mPart]); + case 1: return QString(content.mMale.c_str()); + case 2: return QString(content.mFemale.c_str()); + default: + throw std::runtime_error("Trying to access non-existing column in the nested table!"); + } + } + + virtual void setNestedData (const RefIdColumn *column, + RefIdData& data, int row, const QVariant& value, int subRowIndex, int subColIndex) const + { + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (row, mType))); + ESXRecordT apparel = record.get(); + std::vector& list = apparel.mParts.mParts; + + if (subRowIndex < 0 || subRowIndex >= static_cast (list.size())) + throw std::runtime_error ("index out of range"); + + switch(subColIndex) + { + case 0: + { + std::string part = value.toString().toStdString(); + bool found = false; + for (unsigned int i = 0; i < ESM::PRT_Count; ++i) + { + if (part == sPartRefs[i]) + { + list.at(subRowIndex).mPart = static_cast(i); + found = true; + break; + } + } + if (!found) + return; // return without saving + else + break; + } + case 1: list.at(subRowIndex).mMale = value.toString().toStdString(); break; + case 2: list.at(subRowIndex).mFemale = value.toString().toStdString(); break; + default: + throw std::runtime_error("Trying to access non-existing column in the nested table!"); + } + + record.setModified (apparel); + } + + virtual int getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const + { + return 3; + } + + virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const + { + const Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + + return static_cast(record.get().mParts.mParts.size()); + } + }; } #endif diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 000426a0b..48f95451c 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -196,7 +196,7 @@ CSMWorld::RefIdCollection::RefIdCollection() mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_AiWanderDist, CSMWorld::ColumnBase::Display_Integer)); mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_AiWanderDuration, CSMWorld::ColumnBase::Display_Integer)); + new RefIdColumn (Columns::ColumnId_AiDuration, CSMWorld::ColumnBase::Display_Integer)); mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_AiWanderToD, CSMWorld::ColumnBase::Display_Integer)); mColumns.back().addColumn( @@ -475,6 +475,24 @@ CSMWorld::RefIdCollection::RefIdCollection() weaponColumns.mFlags.insert (std::make_pair (&mColumns.back(), sWeaponFlagTable[i].mFlag)); } + // Nested table + mColumns.push_back(RefIdColumn (Columns::ColumnId_PartRefList, ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue)); + const RefIdColumn *partRef = &mColumns.back(); + + std::map partMap; + partMap.insert( + std::make_pair(UniversalId::Type_Armor, new BodyPartRefIdAdapter (UniversalId::Type_Armor))); + partMap.insert( + std::make_pair(UniversalId::Type_Clothing, new BodyPartRefIdAdapter (UniversalId::Type_Clothing))); + + mNestedAdapters.push_back (std::make_pair(&mColumns.back(), partMap)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_PartRefType, CSMWorld::ColumnBase::Display_String)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_PartRefMale, CSMWorld::ColumnBase::Display_String)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_PartRefFemale, CSMWorld::ColumnBase::Display_String)); + mAdapters.insert (std::make_pair (UniversalId::Type_Activator, new NameRefIdAdapter (UniversalId::Type_Activator, nameColumns))); mAdapters.insert (std::make_pair (UniversalId::Type_Potion, @@ -482,11 +500,11 @@ CSMWorld::RefIdCollection::RefIdCollection() mAdapters.insert (std::make_pair (UniversalId::Type_Apparatus, new ApparatusRefIdAdapter (inventoryColumns, apparatusType, toolsColumns.mQuality))); mAdapters.insert (std::make_pair (UniversalId::Type_Armor, - new ArmorRefIdAdapter (enchantableColumns, armorType, health, armor))); + new ArmorRefIdAdapter (enchantableColumns, armorType, health, armor, partRef))); mAdapters.insert (std::make_pair (UniversalId::Type_Book, new BookRefIdAdapter (enchantableColumns, scroll, attribute))); mAdapters.insert (std::make_pair (UniversalId::Type_Clothing, - new ClothingRefIdAdapter (enchantableColumns, clothingType))); + new ClothingRefIdAdapter (enchantableColumns, clothingType, partRef))); mAdapters.insert (std::make_pair (UniversalId::Type_Container, new ContainerRefIdAdapter (nameColumns, weightCapacity, organic, respawn, content))); mAdapters.insert (std::make_pair (UniversalId::Type_Creature, From 1c7ed795c2c45daa7707bac70be534a811bd691c Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 13 Apr 2015 22:21:27 +1000 Subject: [PATCH 0936/3725] Add creature/item levelled lists to dialogue subview. --- apps/opencs/model/world/columns.cpp | 4 + apps/opencs/model/world/columns.hpp | 4 + apps/opencs/model/world/refidadapterimp.hpp | 182 ++++++++++++++++++++ apps/opencs/model/world/refidcollection.cpp | 109 ++++++------ 4 files changed, 250 insertions(+), 49 deletions(-) diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 547efac56..83d6ceb57 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -263,6 +263,10 @@ namespace CSMWorld { ColumnId_PartRefMale, "Male"}, { ColumnId_PartRefFemale, "Female"}, + { ColumnId_LevelledList,"Levelled List"}, + { ColumnId_LevelledItemId,"Item ID"}, + { ColumnId_LevelledItemLevel,"Level"}, + { ColumnId_UseValue1, "Use value 1" }, { ColumnId_UseValue2, "Use value 2" }, { ColumnId_UseValue3, "Use value 3" }, diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 6068ea6e7..81cae5e36 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -253,6 +253,10 @@ namespace CSMWorld ColumnId_PartRefMale = 231, ColumnId_PartRefFemale = 232, + ColumnId_LevelledList = 233, + ColumnId_LevelledItemId = 234, + ColumnId_LevelledItemLevel = 235, + // Allocated to a separate value range, so we don't get a collision should we ever need // to extend the number of use values. ColumnId_UseValue1 = 0x10000, diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index bc00d31f9..d09aaaa45 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -1828,6 +1828,188 @@ namespace CSMWorld return static_cast(record.get().mParts.mParts.size()); } }; + + struct LevListColumns : public BaseColumns + { + const RefIdColumn *mLevList; + + LevListColumns (const BaseColumns& base) : BaseColumns (base) {} + }; + + template + class LevelledListRefIdAdapter : public BaseRefIdAdapter + { + LevListColumns mLevList; + + public: + + LevelledListRefIdAdapter (UniversalId::Type type, const LevListColumns &columns); + + virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index) + const; + + virtual void setData (const RefIdColumn *column, RefIdData& data, int index, + const QVariant& value) const; + ///< If the data type does not match an exception is thrown. + }; + + template + LevelledListRefIdAdapter::LevelledListRefIdAdapter (UniversalId::Type type, + const LevListColumns &columns) + : BaseRefIdAdapter (type, columns), mLevList (columns) + {} + + template + QVariant LevelledListRefIdAdapter::getData (const RefIdColumn *column, const RefIdData& data, + int index) const + { + if (column==mLevList.mLevList) + return true; // to show nested tables in dialogue subview, see IdTree::hasChildren() + + return BaseRefIdAdapter::getData (column, data, index); + } + + template + void LevelledListRefIdAdapter::setData (const RefIdColumn *column, RefIdData& data, int index, + const QVariant& value) const + { + BaseRefIdAdapter::setData (column, data, index, value); + return; + } + + template + class NestedLevListRefIdAdapter : public NestedRefIdAdapterBase + { + UniversalId::Type mType; + + // not implemented + NestedLevListRefIdAdapter (const NestedLevListRefIdAdapter&); + NestedLevListRefIdAdapter& operator= (const NestedLevListRefIdAdapter&); + + public: + + NestedLevListRefIdAdapter(UniversalId::Type type) :mType(type) {} + + virtual ~NestedLevListRefIdAdapter() {} + + virtual void addNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int position) const + { + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + ESXRecordT leveled = record.get(); + + std::vector& list = leveled.mList; + + ESM::LevelledListBase::LevelItem newItem; + newItem.mId = ""; + newItem.mLevel = 0; + + if (position >= (int)list.size()) + list.push_back(newItem); + else + list.insert(list.begin()+position, newItem); + + record.setModified (leveled); + } + + virtual void removeNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int rowToRemove) const + { + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + ESXRecordT leveled = record.get(); + + std::vector& list = leveled.mList; + + if (rowToRemove < 0 || rowToRemove >= static_cast (list.size())) + throw std::runtime_error ("index out of range"); + + list.erase (list.begin () + rowToRemove); + + record.setModified (leveled); + } + + virtual void setNestedTable (const RefIdColumn* column, + RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const + { + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + ESXRecordT leveled = record.get(); + + leveled.mList = + static_cast >&>(nestedTable).mNestedTable; + + record.setModified (leveled); + } + + virtual NestedTableWrapperBase* nestedTable (const RefIdColumn* column, + const RefIdData& data, int index) const + { + const Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + + // deleted by dtor of NestedTableStoring + return new NestedTableWrapper >(record.get().mList); + } + + virtual QVariant getNestedData (const RefIdColumn *column, + const RefIdData& data, int index, int subRowIndex, int subColIndex) const + { + const Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + + const std::vector& list = record.get().mList; + + if (subRowIndex < 0 || subRowIndex >= static_cast (list.size())) + throw std::runtime_error ("index out of range"); + + const ESM::LevelledListBase::LevelItem& content = list.at(subRowIndex); + + switch (subColIndex) + { + case 0: return QString(content.mId.c_str()); + case 1: return content.mLevel; + default: + throw std::runtime_error("Trying to access non-existing column in the nested table!"); + } + } + + virtual void setNestedData (const RefIdColumn *column, + RefIdData& data, int row, const QVariant& value, int subRowIndex, int subColIndex) const + { + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (row, mType))); + ESXRecordT leveled = record.get(); + std::vector& list = leveled.mList; + + if (subRowIndex < 0 || subRowIndex >= static_cast (list.size())) + throw std::runtime_error ("index out of range"); + + switch(subColIndex) + { + case 0: list.at(subRowIndex).mId = value.toString().toStdString(); break; + case 1: list.at(subRowIndex).mLevel = static_cast(value.toInt()); break; + default: + throw std::runtime_error("Trying to access non-existing column in the nested table!"); + } + + record.setModified (leveled); + } + + virtual int getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const + { + return 2; + } + + virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const + { + const Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + + return static_cast(record.get().mList.size()); + } + }; } #endif diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 48f95451c..be5d67766 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -73,14 +73,13 @@ CSMWorld::RefIdCollection::RefIdCollection() // nested table PotionColumns potionColumns (inventoryColumns); - mColumns.push_back (RefIdColumn (Columns::ColumnId_EffectList, ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue)); + mColumns.push_back (RefIdColumn (Columns::ColumnId_EffectList, + ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue)); potionColumns.mEffects = &mColumns.back(); // see refidadapterimp.hpp - std::map effectsMap; - effectsMap.insert( - std::make_pair(UniversalId::Type_Potion, new EffectsRefIdAdapter (UniversalId::Type_Potion))); + effectsMap.insert(std::make_pair(UniversalId::Type_Potion, + new EffectsRefIdAdapter (UniversalId::Type_Potion))); mNestedAdapters.push_back (std::make_pair(&mColumns.back(), effectsMap)); - mColumns.back().addColumn( new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_String/*, false*/)); mColumns.back().addColumn( @@ -126,15 +125,14 @@ CSMWorld::RefIdCollection::RefIdCollection() actorsColumns.mAlarm = &mColumns.back(); // Nested table - mColumns.push_back(RefIdColumn (Columns::ColumnId_ActorInventory, ColumnBase::Display_NestedItemList, ColumnBase::Flag_Dialogue)); + mColumns.push_back(RefIdColumn (Columns::ColumnId_ActorInventory, + ColumnBase::Display_NestedItemList, ColumnBase::Flag_Dialogue)); actorsColumns.mInventory = &mColumns.back(); - std::map inventoryMap; - inventoryMap.insert( - std::make_pair(UniversalId::Type_Npc, new NestedInventoryRefIdAdapter (UniversalId::Type_Npc))); - inventoryMap.insert( - std::make_pair(UniversalId::Type_Creature, new NestedInventoryRefIdAdapter (UniversalId::Type_Creature))); - + inventoryMap.insert(std::make_pair(UniversalId::Type_Npc, + new NestedInventoryRefIdAdapter (UniversalId::Type_Npc))); + inventoryMap.insert(std::make_pair(UniversalId::Type_Creature, + new NestedInventoryRefIdAdapter (UniversalId::Type_Creature))); mNestedAdapters.push_back (std::make_pair(&mColumns.back(), inventoryMap)); mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_InventoryItemId, CSMWorld::ColumnBase::Display_String)); @@ -142,28 +140,27 @@ CSMWorld::RefIdCollection::RefIdCollection() new RefIdColumn (Columns::ColumnId_ItemCount, CSMWorld::ColumnBase::Display_Integer)); // Nested table - mColumns.push_back(RefIdColumn (Columns::ColumnId_SpellList, ColumnBase::Display_NestedSpellList, ColumnBase::Flag_Dialogue)); + mColumns.push_back(RefIdColumn (Columns::ColumnId_SpellList, + ColumnBase::Display_NestedSpellList, ColumnBase::Flag_Dialogue)); actorsColumns.mSpells = &mColumns.back(); - std::map spellsMap; - spellsMap.insert( - std::make_pair(UniversalId::Type_Npc, new NestedSpellRefIdAdapter (UniversalId::Type_Npc))); - spellsMap.insert( - std::make_pair(UniversalId::Type_Creature, new NestedSpellRefIdAdapter (UniversalId::Type_Creature))); - + spellsMap.insert(std::make_pair(UniversalId::Type_Npc, + new NestedSpellRefIdAdapter (UniversalId::Type_Npc))); + spellsMap.insert(std::make_pair(UniversalId::Type_Creature, + new NestedSpellRefIdAdapter (UniversalId::Type_Creature))); mNestedAdapters.push_back (std::make_pair(&mColumns.back(), spellsMap)); mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_SpellId, CSMWorld::ColumnBase::Display_String)); // Nested table - mColumns.push_back(RefIdColumn (Columns::ColumnId_NpcDestinations, ColumnBase::Display_NestedDestinationsList, ColumnBase::Flag_Dialogue)); + mColumns.push_back(RefIdColumn (Columns::ColumnId_NpcDestinations, + ColumnBase::Display_NestedDestinationsList, ColumnBase::Flag_Dialogue)); actorsColumns.mDestinations = &mColumns.back(); - std::map destMap; - destMap.insert( - std::make_pair(UniversalId::Type_Npc, new NestedTravelRefIdAdapter (UniversalId::Type_Npc))); - destMap.insert( - std::make_pair(UniversalId::Type_Creature, new NestedTravelRefIdAdapter (UniversalId::Type_Creature))); + destMap.insert(std::make_pair(UniversalId::Type_Npc, + new NestedTravelRefIdAdapter (UniversalId::Type_Npc))); + destMap.insert(std::make_pair(UniversalId::Type_Creature, + new NestedTravelRefIdAdapter (UniversalId::Type_Creature))); mNestedAdapters.push_back (std::make_pair(&mColumns.back(), destMap)); mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_DestinationCell, CSMWorld::ColumnBase::Display_String)); @@ -181,15 +178,14 @@ CSMWorld::RefIdCollection::RefIdCollection() new RefIdColumn (Columns::ColumnId_RotZ, CSMWorld::ColumnBase::Display_Float)); // Nested table - mColumns.push_back(RefIdColumn (Columns::ColumnId_AiPackageList, ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue)); + mColumns.push_back(RefIdColumn (Columns::ColumnId_AiPackageList, + ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue)); actorsColumns.mAiPackages = &mColumns.back(); - std::map aiMap; - aiMap.insert( - std::make_pair(UniversalId::Type_Npc, new ActorAiRefIdAdapter (UniversalId::Type_Npc))); - aiMap.insert( - std::make_pair(UniversalId::Type_Creature, new ActorAiRefIdAdapter (UniversalId::Type_Creature))); - + aiMap.insert(std::make_pair(UniversalId::Type_Npc, + new ActorAiRefIdAdapter (UniversalId::Type_Npc))); + aiMap.insert(std::make_pair(UniversalId::Type_Creature, + new ActorAiRefIdAdapter (UniversalId::Type_Creature))); mNestedAdapters.push_back (std::make_pair(&mColumns.back(), aiMap)); mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_AiPackage, CSMWorld::ColumnBase::Display_String)); @@ -284,14 +280,13 @@ CSMWorld::RefIdCollection::RefIdCollection() const RefIdColumn *respawn = &mColumns.back(); // Nested table - mColumns.push_back(RefIdColumn (Columns::ColumnId_ContainerContent, ColumnBase::Display_NestedItemList, ColumnBase::Flag_Dialogue)); + mColumns.push_back(RefIdColumn (Columns::ColumnId_ContainerContent, + ColumnBase::Display_NestedItemList, ColumnBase::Flag_Dialogue)); const RefIdColumn *content = &mColumns.back(); - std::map contMap; - contMap.insert( - std::make_pair(UniversalId::Type_Container, new NestedInventoryRefIdAdapter (UniversalId::Type_Container))); + contMap.insert(std::make_pair(UniversalId::Type_Container, + new NestedInventoryRefIdAdapter (UniversalId::Type_Container))); mNestedAdapters.push_back (std::make_pair(&mColumns.back(), contMap)); - mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_InventoryItemId, CSMWorld::ColumnBase::Display_String)); mColumns.back().addColumn( @@ -478,20 +473,36 @@ CSMWorld::RefIdCollection::RefIdCollection() // Nested table mColumns.push_back(RefIdColumn (Columns::ColumnId_PartRefList, ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue)); const RefIdColumn *partRef = &mColumns.back(); - std::map partMap; - partMap.insert( - std::make_pair(UniversalId::Type_Armor, new BodyPartRefIdAdapter (UniversalId::Type_Armor))); - partMap.insert( - std::make_pair(UniversalId::Type_Clothing, new BodyPartRefIdAdapter (UniversalId::Type_Clothing))); - + partMap.insert(std::make_pair(UniversalId::Type_Armor, + new BodyPartRefIdAdapter (UniversalId::Type_Armor))); + partMap.insert(std::make_pair(UniversalId::Type_Clothing, + new BodyPartRefIdAdapter (UniversalId::Type_Clothing))); mNestedAdapters.push_back (std::make_pair(&mColumns.back(), partMap)); mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_PartRefType, CSMWorld::ColumnBase::Display_String)); + new RefIdColumn (Columns::ColumnId_PartRefType, CSMWorld::ColumnBase::Display_String)); mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_PartRefMale, CSMWorld::ColumnBase::Display_String)); + new RefIdColumn (Columns::ColumnId_PartRefMale, CSMWorld::ColumnBase::Display_String)); mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_PartRefFemale, CSMWorld::ColumnBase::Display_String)); + new RefIdColumn (Columns::ColumnId_PartRefFemale, CSMWorld::ColumnBase::Display_String)); + + LevListColumns levListColumns (baseColumns); + + // Nested table + mColumns.push_back(RefIdColumn (Columns::ColumnId_LevelledList, + ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue)); + levListColumns.mLevList = &mColumns.back(); + std::map levListMap; + levListMap.insert(std::make_pair(UniversalId::Type_CreatureLevelledList, + new NestedLevListRefIdAdapter (UniversalId::Type_CreatureLevelledList))); + levListMap.insert(std::make_pair(UniversalId::Type_ItemLevelledList, + new NestedLevListRefIdAdapter (UniversalId::Type_ItemLevelledList))); + mNestedAdapters.push_back (std::make_pair(&mColumns.back(), levListMap)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_LevelledItemId, CSMWorld::ColumnBase::Display_String)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_LevelledItemLevel, CSMWorld::ColumnBase::Display_Integer)); + mAdapters.insert (std::make_pair (UniversalId::Type_Activator, new NameRefIdAdapter (UniversalId::Type_Activator, nameColumns))); @@ -514,10 +525,10 @@ CSMWorld::RefIdCollection::RefIdCollection() mAdapters.insert (std::make_pair (UniversalId::Type_Ingredient, new InventoryRefIdAdapter (UniversalId::Type_Ingredient, inventoryColumns))); mAdapters.insert (std::make_pair (UniversalId::Type_CreatureLevelledList, - new BaseRefIdAdapter ( - UniversalId::Type_CreatureLevelledList, baseColumns))); + new LevelledListRefIdAdapter ( + UniversalId::Type_CreatureLevelledList, levListColumns))); mAdapters.insert (std::make_pair (UniversalId::Type_ItemLevelledList, - new BaseRefIdAdapter (UniversalId::Type_ItemLevelledList, baseColumns))); + new LevelledListRefIdAdapter (UniversalId::Type_ItemLevelledList, levListColumns))); mAdapters.insert (std::make_pair (UniversalId::Type_Light, new LightRefIdAdapter (lightColumns))); mAdapters.insert (std::make_pair (UniversalId::Type_Lockpick, From 246b06ca279c293ef3f914b391b3935cd16b62d4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 13 Apr 2015 17:30:32 +0200 Subject: [PATCH 0937/3725] Forgot to add --- apps/openmw/mwrender/objects.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 764aa13c6..25d57aba0 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -139,8 +139,6 @@ void Objects::insertModel(const MWWorld::Ptr &ptr, const std::string &mesh, bool SceneUtil::FindByNameVisitor visitor("AttachLight"); ptr.getRefData().getBaseNode()->accept(visitor); - osg::Vec3f lightOffset (0.f, 0.f, 0.f); - osg::Group* attachTo = NULL; if (visitor.mFoundNode) { @@ -152,9 +150,13 @@ void Objects::insertModel(const MWWorld::Ptr &ptr, const std::string &mesh, bool osg::Group* objectRoot = anim->getOrCreateObjectRoot(); objectRoot->accept(computeBound); - lightOffset = computeBound.getBoundingBox().center(); + // PositionAttitudeTransform seems to be slightly faster than MatrixTransform + osg::ref_ptr trans(new osg::PositionAttitudeTransform); + trans->setPosition(computeBound.getBoundingBox().center()); + + objectRoot->addChild(trans); - attachTo = objectRoot; + attachTo = trans; } const ESM::Light* esmLight = ptr.get()->mBase; @@ -162,7 +164,6 @@ void Objects::insertModel(const MWWorld::Ptr &ptr, const std::string &mesh, bool osg::ref_ptr lightSource = new SceneUtil::LightSource; osg::Light* light = new osg::Light; lightSource->setLight(light); - light->setPosition(osg::Vec4f(lightOffset.x(), lightOffset.y(), lightOffset.z(), 1.f)); float realRadius = esmLight->mData.mRadius * 2; From 8c7c89a4aabf8131f4c07a08cc9f03a2e2af819b Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 13 Apr 2015 22:48:37 +0200 Subject: [PATCH 0938/3725] Port SoundManager --- apps/openmw/engine.cpp | 2 +- apps/openmw/mwsound/ffmpeg_decoder.cpp | 50 ++++++++++++++----------- apps/openmw/mwsound/ffmpeg_decoder.hpp | 8 +++- apps/openmw/mwsound/openal_output.cpp | 2 +- apps/openmw/mwsound/sound_decoder.hpp | 10 +++-- apps/openmw/mwsound/soundmanagerimp.cpp | 28 ++++++++------ apps/openmw/mwsound/soundmanagerimp.hpp | 12 ++++-- 7 files changed, 68 insertions(+), 44 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 0d0294fa7..59f9fa692 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -377,7 +377,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) mEnvironment.setWindowManager (window); // Create sound system - mEnvironment.setSoundManager (new MWSound::SoundManager(mUseSound)); + mEnvironment.setSoundManager (new MWSound::SoundManager(mVFS.get(), mUseSound)); if (!mSkipMenu) { diff --git a/apps/openmw/mwsound/ffmpeg_decoder.cpp b/apps/openmw/mwsound/ffmpeg_decoder.cpp index 0185d3ecc..55607b5b7 100644 --- a/apps/openmw/mwsound/ffmpeg_decoder.cpp +++ b/apps/openmw/mwsound/ffmpeg_decoder.cpp @@ -4,6 +4,7 @@ #include #include +#include extern "C" { #ifndef HAVE_LIBSWRESAMPLE @@ -15,6 +16,8 @@ AVAudioResampleContext * swr_alloc_set_opts( AVAudioResampleContext *avr, int64_ #endif } +#include + namespace MWSound { @@ -27,8 +30,10 @@ int FFmpeg_Decoder::readPacket(void *user_data, uint8_t *buf, int buf_size) { try { - Ogre::DataStreamPtr stream = static_cast(user_data)->mDataStream; - return stream->read(buf, buf_size); + std::istream& stream = *static_cast(user_data)->mDataStream; + stream.read((char*)buf, buf_size); + stream.clear(); + return stream.gcount(); } catch (std::exception& ) { @@ -36,36 +41,36 @@ int FFmpeg_Decoder::readPacket(void *user_data, uint8_t *buf, int buf_size) } } -int FFmpeg_Decoder::writePacket(void *user_data, uint8_t *buf, int buf_size) +int FFmpeg_Decoder::writePacket(void *, uint8_t *, int) { - try - { - Ogre::DataStreamPtr stream = static_cast(user_data)->mDataStream; - return stream->write(buf, buf_size); - } - catch (std::exception& ) - { - return 0; - } + throw std::runtime_error("can't write to read-only stream"); } int64_t FFmpeg_Decoder::seek(void *user_data, int64_t offset, int whence) { - Ogre::DataStreamPtr stream = static_cast(user_data)->mDataStream; + std::istream& stream = *static_cast(user_data)->mDataStream; whence &= ~AVSEEK_FORCE; + if(whence == AVSEEK_SIZE) - return stream->size(); + { + size_t prev = stream.tellg(); + stream.seekg(0, std::ios_base::end); + size_t size = stream.tellg(); + stream.seekg(prev, std::ios_base::beg); + return size; + } + if(whence == SEEK_SET) - stream->seek(static_cast(offset)); + stream.seekg(offset, std::ios_base::beg); else if(whence == SEEK_CUR) - stream->seek(static_cast(stream->tell()+offset)); + stream.seekg(offset, std::ios_base::cur); else if(whence == SEEK_END) - stream->seek(static_cast(stream->size()+offset)); + stream.seekg(offset, std::ios_base::end); else return -1; - return stream->tell(); + return stream.tellg(); } @@ -186,7 +191,7 @@ size_t FFmpeg_Decoder::readAVAudioData(void *data, size_t length) void FFmpeg_Decoder::open(const std::string &fname) { close(); - mDataStream = mResourceMgr.openResource(fname); + mDataStream = mResourceMgr->get(fname); if((mFormatCtx=avformat_alloc_context()) == NULL) fail("Failed to allocate context"); @@ -289,7 +294,7 @@ void FFmpeg_Decoder::close() avformat_close_input(&mFormatCtx); } - mDataStream.setNull(); + mDataStream.reset(); } std::string FFmpeg_Decoder::getName() @@ -409,8 +414,9 @@ size_t FFmpeg_Decoder::getSampleOffset() return (int)(mNextPts*(*mStream)->codec->sample_rate) - delay; } -FFmpeg_Decoder::FFmpeg_Decoder() - : mFormatCtx(NULL) +FFmpeg_Decoder::FFmpeg_Decoder(const VFS::Manager* vfs) + : Sound_Decoder(vfs) + , mFormatCtx(NULL) , mStream(NULL) , mFrame(NULL) , mFrameSize(0) diff --git a/apps/openmw/mwsound/ffmpeg_decoder.hpp b/apps/openmw/mwsound/ffmpeg_decoder.hpp index 2cdbbf363..3abf7c474 100644 --- a/apps/openmw/mwsound/ffmpeg_decoder.hpp +++ b/apps/openmw/mwsound/ffmpeg_decoder.hpp @@ -37,7 +37,10 @@ extern "C" #endif } +#include + #include +#include #include "sound_decoder.hpp" @@ -66,7 +69,8 @@ namespace MWSound bool getNextPacket(); - Ogre::DataStreamPtr mDataStream; + Files::IStreamPtr mDataStream; + static int readPacket(void *user_data, uint8_t *buf, int buf_size); static int writePacket(void *user_data, uint8_t *buf, int buf_size); static int64_t seek(void *user_data, int64_t offset, int whence); @@ -90,7 +94,7 @@ namespace MWSound FFmpeg_Decoder& operator=(const FFmpeg_Decoder &rhs); FFmpeg_Decoder(const FFmpeg_Decoder &rhs); - FFmpeg_Decoder(); + FFmpeg_Decoder(const VFS::Manager* vfs); public: virtual ~FFmpeg_Decoder(); diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 1b3dced80..266b97f87 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -786,7 +786,7 @@ const CachedSound& OpenAL_Output::getBuffer(const std::string &fname) { decoder->open(fname); } - catch(Ogre::FileNotFoundException&) + catch(std::exception&) { std::string::size_type pos = fname.rfind('.'); if(pos == std::string::npos) diff --git a/apps/openmw/mwsound/sound_decoder.hpp b/apps/openmw/mwsound/sound_decoder.hpp index 151b58036..1be9dd374 100644 --- a/apps/openmw/mwsound/sound_decoder.hpp +++ b/apps/openmw/mwsound/sound_decoder.hpp @@ -2,8 +2,12 @@ #define GAME_SOUND_SOUND_DECODER_H #include +#include -#include +namespace VFS +{ + class Manager; +} namespace MWSound { @@ -28,7 +32,7 @@ namespace MWSound struct Sound_Decoder { - Ogre::ResourceGroupManager &mResourceMgr; + const VFS::Manager* mResourceMgr; virtual void open(const std::string &fname) = 0; virtual void close() = 0; @@ -41,7 +45,7 @@ namespace MWSound virtual void rewind() = 0; virtual size_t getSampleOffset() = 0; - Sound_Decoder() : mResourceMgr(Ogre::ResourceGroupManager::getSingleton()) + Sound_Decoder(const VFS::Manager* resourceMgr) : mResourceMgr(resourceMgr) { } virtual ~Sound_Decoder() { } diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 5fc39f03e..84f61ddf8 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -6,6 +6,8 @@ #include +#include + #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/statemanager.hpp" @@ -27,8 +29,8 @@ namespace MWSound { - SoundManager::SoundManager(bool useSound) - : mResourceMgr(Ogre::ResourceGroupManager::getSingleton()) + SoundManager::SoundManager(const VFS::Manager* vfs, bool useSound) + : mVFS(vfs) , mOutput(new DEFAULT_OUTPUT(*this)) , mMasterVolume(1.0f) , mSFXVolume(1.0f) @@ -96,7 +98,7 @@ namespace MWSound // Return a new decoder instance, used as needed by the output implementations DecoderPtr SoundManager::getDecoder() { - return DecoderPtr(new DEFAULT_DECODER); + return DecoderPtr(new DEFAULT_DECODER (mVFS)); } // Convert a soundId to file name, and modify the volume @@ -208,20 +210,24 @@ namespace MWSound void SoundManager::startRandomTitle() { - Ogre::StringVector filelist; + std::vector filelist; if (mMusicFiles.find(mCurrentPlaylist) == mMusicFiles.end()) { -#if 0 - Ogre::StringVector groups = Ogre::ResourceGroupManager::getSingleton().getResourceGroups (); - for (Ogre::StringVector::iterator it = groups.begin(); it != groups.end(); ++it) + const std::map& index = mVFS->getIndex(); + + std::string pattern = "Music/" + mCurrentPlaylist; + mVFS->normalizeFilename(pattern); + + std::map::const_iterator found = index.lower_bound(pattern); + while (found != index.end()) { - Ogre::StringVectorPtr resourcesInThisGroup = mResourceMgr.findResourceNames(*it, - "Music/"+mCurrentPlaylist+"/*"); - filelist.insert(filelist.end(), resourcesInThisGroup->begin(), resourcesInThisGroup->end()); + if (found->first.size() >= pattern.size() && found->first.substr(0, pattern.size()) == pattern) + filelist.push_back(found->first); + ++found; } + mMusicFiles[mCurrentPlaylist] = filelist; -#endif } else filelist = mMusicFiles[mCurrentPlaylist]; diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index 250cb0d51..8089a7e6f 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -8,12 +8,16 @@ #include #include -#include #include #include "../mwbase/soundmanager.hpp" +namespace VFS +{ + class Manager; +} + namespace MWSound { class Sound_Output; @@ -27,12 +31,12 @@ namespace MWSound class SoundManager : public MWBase::SoundManager { - Ogre::ResourceGroupManager& mResourceMgr; + const VFS::Manager* mVFS; std::auto_ptr mOutput; // Caches available music tracks by - std::map mMusicFiles; + std::map > mMusicFiles; std::string mLastPlayedMusic; // The music file that was last played float mMasterVolume; @@ -74,7 +78,7 @@ namespace MWSound friend class OpenAL_Output; public: - SoundManager(bool useSound); + SoundManager(const VFS::Manager* vfs, bool useSound); virtual ~SoundManager(); virtual void processChangedSettings(const Settings::CategorySettingVector& settings); From 5dd1ab24fe45afbe43542eeda45a480faf3a4180 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 14 Apr 2015 15:55:56 +0200 Subject: [PATCH 0939/3725] More efficient StateSetController, beginnings of sky rendering --- apps/openmw/CMakeLists.txt | 8 +- apps/openmw/engine.cpp | 10 +- apps/openmw/mwrender/objects.hpp | 2 +- apps/openmw/mwrender/renderingmanager.cpp | 91 ++- apps/openmw/mwrender/renderingmanager.hpp | 22 + apps/openmw/mwrender/sky.cpp | 787 +++++++------------- apps/openmw/mwrender/sky.hpp | 170 +---- apps/openmw/mwworld/fallback.cpp | 10 +- apps/openmw/mwworld/fallback.hpp | 4 +- apps/openmw/mwworld/weather.cpp | 70 +- apps/openmw/mwworld/weather.hpp | 26 +- apps/openmw/mwworld/worldimp.cpp | 44 +- apps/openmw/mwworld/worldimp.hpp | 2 +- components/CMakeLists.txt | 2 +- components/resource/scenemanager.cpp | 10 + components/resource/scenemanager.hpp | 4 + components/sceneutil/statesetcontroller.cpp | 31 + components/sceneutil/statesetcontroller.hpp | 39 + 18 files changed, 590 insertions(+), 742 deletions(-) create mode 100644 components/sceneutil/statesetcontroller.cpp create mode 100644 components/sceneutil/statesetcontroller.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index e10688149..e7ed2d921 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -20,8 +20,8 @@ set(GAME_HEADER source_group(game FILES ${GAME} ${GAME_HEADER}) add_openmw_dir (mwrender - actors objects renderingmanager animation -# debugging sky camera npcanimation creatureanimation activatoranimation + actors objects renderingmanager animation sky +# debugging camera npcanimation creatureanimation activatoranimation # renderinginterface localmap occlusionquery water shadows # characterpreview globalmap ripplesimulation refraction # terrainstorage renderconst effectmanager weaponanimation @@ -68,8 +68,8 @@ add_openmw_dir (mwworld cells localscripts customdata inventorystore ptr actionopen actionread actionequip timestamp actionalchemy cellstore actionapply actioneat esmstore store recordcmp fallback actionrepair actionsoulgem livecellref actiondoor - contentloader esmloader actiontrap cellreflist cellref physicssystem -# weather projectilemanager + contentloader esmloader actiontrap cellreflist cellref physicssystem weather +# projectilemanager ) add_openmw_dir (mwclass diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 59f9fa692..59504048a 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -499,9 +499,17 @@ void OMW::Engine::go() //mViewer.setRealizeOperation(ico); mViewer.realize(); std::cout << "realize took " << timer.time_m() << std::endl; + osg::Timer frameTimer; while (!mViewer.done()) { - MWBase::Environment::get().getWorld()->update(0.f, false); + double dt = frameTimer.time_s(); + frameTimer.setStartTick(); + + // frameRenderingQueued(dt); + MWBase::Environment::get().getWorld()->update(dt, false); + + MWBase::Environment::get().getWorld()->advanceTime( + dt*MWBase::Environment::get().getWorld()->getTimeScaleFactor()/3600); mViewer.frame(/*simulationTime*/); } diff --git a/apps/openmw/mwrender/objects.hpp b/apps/openmw/mwrender/objects.hpp index 44334e444..07328b959 100644 --- a/apps/openmw/mwrender/objects.hpp +++ b/apps/openmw/mwrender/objects.hpp @@ -41,7 +41,7 @@ public: ~Objects(); /// @param animated Attempt to load separate keyframes from a .kf file matching the model file? - /// @param allowLight If false, no lights will be created, and particles systems will be cleared then frozen. + /// @param allowLight If false, no lights will be created, and particles systems will be removed. void insertModel(const MWWorld::Ptr& ptr, const std::string &model, bool animated=false, bool allowLight=true); void insertNPC(const MWWorld::Ptr& ptr); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 4e5b33c64..e9a5d302c 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -13,11 +13,39 @@ #include +#include + #include +#include "sky.hpp" + namespace MWRender { + class StateUpdater : public SceneUtil::StateSetController + { + public: + virtual void setDefaults(osg::StateSet *stateset) + { + osg::LightModel* lightModel = new osg::LightModel; + stateset->setAttribute(lightModel, osg::StateAttribute::ON); + } + + virtual void apply(osg::StateSet* stateset, osg::NodeVisitor*) + { + osg::LightModel* lightModel = static_cast(stateset->getAttribute(osg::StateAttribute::LIGHTMODEL)); + lightModel->setAmbientIntensity(mAmbientColor); + } + + void setAmbientColor(osg::Vec4f col) + { + mAmbientColor = col; + } + + private: + osg::Vec4f mAmbientColor; + }; + RenderingManager::RenderingManager(osgViewer::Viewer &viewer, osg::ref_ptr rootNode, Resource::ResourceSystem* resourceSystem) : mViewer(viewer) , mRootNode(rootNode) @@ -30,6 +58,8 @@ namespace MWRender mObjects.reset(new Objects(mResourceSystem, lightRoot)); + mSky.reset(new SkyManager(mRootNode, resourceSystem->getSceneManager())); + mViewer.setLightingMode(osgViewer::View::NO_LIGHT); osg::ref_ptr source = new osg::LightSource; @@ -38,17 +68,30 @@ namespace MWRender mSunLight->setDiffuse(osg::Vec4f(0,0,0,1)); mSunLight->setAmbient(osg::Vec4f(0,0,0,1)); mSunLight->setConstantAttenuation(1.f); - source->setStateSetModes(*rootNode->getOrCreateStateSet(), osg::StateAttribute::ON); lightRoot->addChild(source); - rootNode->getOrCreateStateSet()->setMode(GL_CULL_FACE, osg::StateAttribute::ON); - rootNode->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::ON); - rootNode->getOrCreateStateSet()->setMode(GL_NORMALIZE, osg::StateAttribute::ON); + mRootNode->getOrCreateStateSet()->setMode(GL_CULL_FACE, osg::StateAttribute::ON); + mRootNode->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::ON); + mRootNode->getOrCreateStateSet()->setMode(GL_NORMALIZE, osg::StateAttribute::ON); + + source->setStateSetModes(*mRootNode->getOrCreateStateSet(), osg::StateAttribute::ON); + + mStateUpdater = new StateUpdater; + mRootNode->addUpdateCallback(mStateUpdater); // for consistent benchmarks against the ogre branch. remove later osg::CullStack::CullingMode cullingMode = viewer.getCamera()->getCullingMode(); cullingMode &= ~(osg::CullStack::SMALL_FEATURE_CULLING); viewer.getCamera()->setCullingMode( cullingMode ); + + double fovy, aspect, zNear, zFar; + mViewer.getCamera()->getProjectionMatrixAsPerspective(fovy, aspect, zNear, zFar); + fovy = 55.f; + mViewer.getCamera()->setProjectionMatrixAsPerspective(fovy, aspect, zNear, zFar); + } + + RenderingManager::~RenderingManager() + { } MWRender::Objects& RenderingManager::getObjects() @@ -66,21 +109,34 @@ namespace MWRender return mResourceSystem; } + void RenderingManager::setAmbientColour(const osg::Vec4f &colour) + { + mStateUpdater->setAmbientColor(colour); + } + void RenderingManager::configureAmbient(const ESM::Cell *cell) { - osg::ref_ptr lightmodel = new osg::LightModel; - lightmodel->setAmbientIntensity(SceneUtil::colourFromRGB(cell->mAmbi.mAmbient)); - mRootNode->getOrCreateStateSet()->setAttributeAndModes(lightmodel, osg::StateAttribute::ON); + setAmbientColour(SceneUtil::colourFromRGB(cell->mAmbi.mAmbient)); mSunLight->setDiffuse(SceneUtil::colourFromRGB(cell->mAmbi.mSunlight)); mSunLight->setDirection(osg::Vec3f(1.f,-1.f,-1.f)); } + void RenderingManager::setSunColour(const osg::Vec4f &colour) + { + mSunLight->setDiffuse(colour); + } + + void RenderingManager::setSunDirection(const osg::Vec3f &direction) + { + mSunLight->setDirection(direction*-1); + + mSky->setSunDirection(direction*-1); + } + osg::Vec3f RenderingManager::getEyePos() { - osg::Vec3d eye; - //mViewer.getCamera()->getViewMatrixAsLookAt(eye, center, up); - eye = mViewer.getCameraManipulator()->getMatrix().getTrans(); + osg::Vec3d eye = mViewer.getCameraManipulator()->getMatrix().getTrans(); return eye; } @@ -89,4 +145,19 @@ namespace MWRender mObjects->removeCell(store); } + void RenderingManager::setSkyEnabled(bool enabled) + { + mSky->setEnabled(enabled); + } + + void RenderingManager::configureFog(float fogDepth, const osg::Vec4f &colour) + { + mViewer.getCamera()->setClearColor(colour); + } + + SkyManager* RenderingManager::getSkyManager() + { + return mSky.get(); + } + } diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index f0c5040f2..1db0467ef 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -31,20 +31,36 @@ namespace ESM namespace MWRender { + class StateUpdater; + + class SkyManager; + class RenderingManager : public MWRender::RenderingInterface { public: RenderingManager(osgViewer::Viewer& viewer, osg::ref_ptr rootNode, Resource::ResourceSystem* resourceSystem); + ~RenderingManager(); MWRender::Objects& getObjects(); MWRender::Actors& getActors(); Resource::ResourceSystem* getResourceSystem(); + void setAmbientColour(const osg::Vec4f& colour); + + void setSunDirection(const osg::Vec3f& direction); + void setSunColour(const osg::Vec4f& colour); + void configureAmbient(const ESM::Cell* cell); + void configureFog(float fogDepth, const osg::Vec4f& colour); + void removeCell(const MWWorld::CellStore* store); + void setSkyEnabled(bool enabled); + + SkyManager* getSkyManager(); + osg::Vec3f getEyePos(); private: @@ -55,6 +71,12 @@ namespace MWRender osg::ref_ptr mSunLight; std::auto_ptr mObjects; + std::auto_ptr mSky; + + osg::ref_ptr mStateUpdater; + + void operator = (const RenderingManager&); + RenderingManager(const RenderingManager&); }; } diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index d591cca2e..be702a221 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1,30 +1,30 @@ #include "sky.hpp" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include #include #include -#include #include -#include +#include +#include + +#include + +#include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -34,239 +34,202 @@ #include "renderconst.hpp" #include "renderingmanager.hpp" -using namespace MWRender; -using namespace Ogre; - namespace { -void setAlpha (NifOgre::ObjectScenePtr scene, Ogre::MovableObject* movable, float alpha) -{ - Ogre::MaterialPtr mat = scene->mMaterialControllerMgr.getWritableMaterial(movable); - Ogre::Material::TechniqueIterator techs = mat->getTechniqueIterator(); - while(techs.hasMoreElements()) + osg::StateSet* getWritableStateSet(osg::Node* node) { - Ogre::Technique *tech = techs.getNext(); - Ogre::Technique::PassIterator passes = tech->getPassIterator(); - while(passes.hasMoreElements()) - { - Ogre::Pass *pass = passes.getNext(); - Ogre::ColourValue diffuse = pass->getDiffuse(); - diffuse.a = alpha; - pass->setDiffuse(diffuse); - } + osg::StateSet* stateset = node->getOrCreateStateSet(); + osg::ref_ptr cloned = static_cast(stateset->clone(osg::CopyOp::SHALLOW_COPY)); + node->setStateSet(cloned); + return cloned; } -} - -void setAlpha (NifOgre::ObjectScenePtr scene, float alpha) -{ - for(size_t i = 0; i < scene->mParticles.size(); ++i) - setAlpha(scene, scene->mParticles[i], alpha); - for(size_t i = 0; i < scene->mEntities.size(); ++i) + osg::ref_ptr createAlphaTrackingUnlitMaterial() { - if (scene->mEntities[i] != scene->mSkelBase) - setAlpha(scene, scene->mEntities[i], alpha); + osg::ref_ptr mat = new osg::Material; + mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 1.f)); + mat->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 1.f)); + mat->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(1.f, 1.f, 1.f, 1.f)); + mat->setColorMode(osg::Material::DIFFUSE); + return mat; } -} - -} - -BillboardObject::BillboardObject( const String& textureName, - const float initialSize, - const Vector3& position, - SceneNode* rootNode, - const std::string& material) -: mVisibility(1.0f) -{ - SceneManager* sceneMgr = rootNode->getCreator(); - Vector3 finalPosition = position.normalisedCopy() * 1000.f; + osg::ref_ptr createUnlitMaterial() + { + osg::ref_ptr mat = new osg::Material; + mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 1.f)); + mat->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 1.f)); + mat->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(1.f, 1.f, 1.f, 1.f)); + mat->setColorMode(osg::Material::OFF); + return mat; + } - static unsigned int bodyCount=0; + osg::ref_ptr createTexturedQuad() + { + osg::ref_ptr geom = new osg::Geometry; - mMaterial = sh::Factory::getInstance().createMaterialInstance ("BillboardMaterial"+StringConverter::toString(bodyCount), material); - mMaterial->setProperty("texture", sh::makeProperty(new sh::StringValue(textureName))); + osg::ref_ptr verts = new osg::Vec3Array; + verts->push_back(osg::Vec3f(-0.5, -0.5, 0)); + verts->push_back(osg::Vec3f(-0.5, 0.5, 0)); + verts->push_back(osg::Vec3f(0.5, 0.5, 0)); + verts->push_back(osg::Vec3f(0.5, -0.5, 0)); - static Ogre::Mesh* plane = MeshManager::getSingleton().createPlane("billboard", - ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::Plane(Ogre::Vector3(0,0,1), 0), 1, 1, 1, 1, true, 1, 1, 1, Vector3::UNIT_Y).get(); - plane->_setBounds(Ogre::AxisAlignedBox::BOX_INFINITE); - mEntity = sceneMgr->createEntity("billboard"); - mEntity->setMaterialName("BillboardMaterial"+StringConverter::toString(bodyCount)); - mEntity->setVisibilityFlags(RV_Sky); - mEntity->setCastShadows(false); + geom->setVertexArray(verts); - mNode = rootNode->createChildSceneNode(); - mNode->setPosition(finalPosition); - mNode->attachObject(mEntity); - mNode->setScale(Ogre::Vector3(450.f*initialSize)); - mNode->setOrientation(Ogre::Vector3::UNIT_Z.getRotationTo(-position.normalisedCopy())); + osg::ref_ptr texcoords = new osg::Vec2Array; + texcoords->push_back(osg::Vec2f(0, 0)); + texcoords->push_back(osg::Vec2f(0, 1)); + texcoords->push_back(osg::Vec2f(1, 1)); + texcoords->push_back(osg::Vec2f(1, 0)); - sh::Factory::getInstance().getMaterialInstance ("BillboardMaterial"+StringConverter::toString(bodyCount))->setListener(this); + geom->setTexCoordArray(0, texcoords, osg::Array::BIND_PER_VERTEX); - bodyCount++; -} + geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,4)); -void BillboardObject::requestedConfiguration (sh::MaterialInstance* m, const std::string& configuration) -{ -} + return geom; + } -void BillboardObject::createdConfiguration (sh::MaterialInstance* m, const std::string& configuration) -{ - setVisibility(mVisibility); - setColour(mColour); } -void BillboardObject::setVisible(const bool visible) +namespace MWRender { - mEntity->setVisible(visible); -} -void BillboardObject::setSize(const float size) +class AtmosphereUpdater : public SceneUtil::StateSetController { - mNode->setScale(450.f*size, 450.f*size, 450.f*size); -} +public: + void setEmissionColor(osg::Vec4f emissionColor) + { + mEmissionColor = emissionColor; + } -void BillboardObject::setVisibility(const float visibility) -{ - mVisibility = visibility; - Ogre::MaterialPtr m = static_cast(mMaterial->getMaterial ())->getOgreMaterial (); - for (int i=0; igetNumTechniques(); ++i) +protected: + virtual void setDefaults(osg::StateSet* stateset) { - Ogre::Technique* t = m->getTechnique(i); - if (t->getNumPasses ()) - t->getPass(0)->setDiffuse (0,0,0, visibility); + stateset->setAttribute(createAlphaTrackingUnlitMaterial(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); } -} -void BillboardObject::setPosition(const Vector3& pPosition) -{ - Vector3 normalised = pPosition.normalisedCopy(); - Vector3 finalPosition = normalised * 1000.f; - mNode->setOrientation(Ogre::Vector3::UNIT_Z.getRotationTo(-normalised)); - mNode->setPosition(finalPosition); -} + virtual void apply(osg::StateSet* stateset, osg::NodeVisitor* /*nv*/) + { + osg::Material* mat = static_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); + mat->setEmission(osg::Material::FRONT_AND_BACK, mEmissionColor); + } -Vector3 BillboardObject::getPosition() const -{ - return mNode->getPosition(); -} +private: + osg::Vec4f mEmissionColor; +}; -void BillboardObject::setVisibilityFlags(int flags) +/// Transform that removes the eyepoint of the modelview matrix, +/// i.e. its children are positioned relative to the camera. +class CameraRelativeTransform : public osg::Transform { - mEntity->setVisibilityFlags(flags); -} +public: + CameraRelativeTransform() + { + } -void BillboardObject::setColour(const ColourValue& pColour) -{ - mColour = pColour; - Ogre::MaterialPtr m = static_cast(mMaterial->getMaterial ())->getOgreMaterial (); - for (int i=0; igetNumTechniques(); ++i) + CameraRelativeTransform(const CameraRelativeTransform& copy, const osg::CopyOp& copyop) + : osg::Transform(copy, copyop) { - Ogre::Technique* t = m->getTechnique(i); - if (t->getNumPasses ()) - t->getPass(0)->setSelfIllumination (pColour); } -} -void BillboardObject::setRenderQueue(unsigned int id) -{ - mEntity->setRenderQueueGroup(id); -} + META_Node(MWRender, CameraRelativeTransform) -SceneNode* BillboardObject::getNode() -{ - return mNode; -} + virtual bool computeLocalToWorldMatrix(osg::Matrix& matrix, osg::NodeVisitor*) const + { + if (_referenceFrame==RELATIVE_RF) + { + matrix.setTrans(osg::Vec3f(0.f,0.f,0.f)); + return false; + } + else // absolute + { + matrix.makeIdentity(); + return true; + } + } -Moon::Moon( const String& textureName, - const float initialSize, - const Vector3& position, - SceneNode* rootNode, - const std::string& material) - : BillboardObject(textureName, initialSize, position, rootNode, material) - , mType(Type_Masser) -{ - setVisibility(1.0); + osg::BoundingSphere computeBound() const + { + return osg::BoundingSphere(osg::Vec3f(0,0,0), 0); + } +}; - mMaterial->setProperty("alphatexture", sh::makeProperty(new sh::StringValue(textureName + "_alpha"))); +class DisableCullingVisitor : public osg::NodeVisitor +{ +public: + DisableCullingVisitor() + : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) + { + } - mPhase = Moon::Phase_Full; -} + void apply(osg::Geode &geode) + { + geode.setCullingActive(false); + } +}; -void Moon::setType(const Moon::Type& type) +class ModVertexAlphaVisitor : public osg::NodeVisitor { - mType = type; -} +public: + ModVertexAlphaVisitor(int meshType) + : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) + , mMeshType(meshType) + { + } -void Moon::setPhase(const Moon::Phase& phase) -{ - // Colour texture - Ogre::String textureName = "textures\\tx_"; + void apply(osg::Geode &geode) + { + for (unsigned int i=0; iasGeometry(); + if (!geom) + continue; - if (phase == Moon::Phase_New) textureName += "new"; - else if (phase == Moon::Phase_WaxingCrescent) textureName += "one_wax"; - else if (phase == Moon::Phase_WaxingHalf) textureName += "half_wax"; - else if (phase == Moon::Phase_WaxingGibbous) textureName += "three_wax"; - else if (phase == Moon::Phase_WaningCrescent) textureName += "one_wan"; - else if (phase == Moon::Phase_WaningHalf) textureName += "half_wan"; - else if (phase == Moon::Phase_WaningGibbous) textureName += "three_wan"; - else if (phase == Moon::Phase_Full) textureName += "full"; + // might want to use fog coordinates instead of vertex colors so we can apply a separate fade to the diffuse alpha + // (that isn't possible now, with the diffuse tracking the vertex colors) - textureName += ".dds"; + osg::ref_ptr colors = new osg::Vec4Array(geom->getVertexArray()->getNumElements()); + for (unsigned int i=0; isize(); ++i) + { + float alpha = 1.f; + if (mMeshType == 0) alpha = i%2 ? 0.f : 1.f; // this is a cylinder, so every second vertex belongs to the bottom-most row + else if (mMeshType == 1) + { + if (i>= 49 && i <= 64) alpha = 0.f; // bottom-most row + else if (i>= 33 && i <= 48) alpha = 0.25098; // second row + else alpha = 1.f; + } + else if (mMeshType == 2) + { + osg::Vec4Array* origColors = static_cast(geom->getColorArray()); + alpha = ((*origColors)[i].x() == 1.f) ? 1.f : 0.f; + } + + (*colors)[i] = osg::Vec4f(alpha, alpha, alpha, alpha); + } - if (mType == Moon::Type_Secunda) - { - sh::Factory::getInstance ().setTextureAlias ("secunda_texture", textureName); - sh::Factory::getInstance ().setTextureAlias ("secunda_texture_alpha", "textures\\tx_mooncircle_full_s.dds"); - } - else - { - sh::Factory::getInstance ().setTextureAlias ("masser_texture", textureName); - sh::Factory::getInstance ().setTextureAlias ("masser_texture_alpha", "textures\\tx_mooncircle_full_m.dds"); + geom->setColorArray(colors, osg::Array::BIND_PER_VERTEX); + } } - mPhase = phase; -} - -unsigned int Moon::getPhaseInt() const -{ - if (mPhase == Moon::Phase_New) return 0; - else if (mPhase == Moon::Phase_WaxingCrescent) return 1; - else if (mPhase == Moon::Phase_WaningCrescent) return 1; - else if (mPhase == Moon::Phase_WaxingHalf) return 2; - else if (mPhase == Moon::Phase_WaningHalf) return 2; - else if (mPhase == Moon::Phase_WaxingGibbous) return 3; - else if (mPhase == Moon::Phase_WaningGibbous) return 3; - else if (mPhase == Moon::Phase_Full) return 4; - - return 0; -} +private: + int mMeshType; +}; -SkyManager::SkyManager(Ogre::SceneNode *root, Ogre::Camera *pCamera) - : mHour(0.0f) +SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneManager) + : mSceneManager(sceneManager) + , mHour(0.0f) , mDay(0) , mMonth(0) - , mSun(NULL) - , mSunGlare(NULL) - , mMasser(NULL) - , mSecunda(NULL) - , mCamera(pCamera) - , mRootNode(NULL) - , mSceneMgr(NULL) - , mAtmosphereDay(NULL) - , mAtmosphereNight(NULL) - , mCloudNode(NULL) , mClouds() , mNextClouds() , mCloudBlendFactor(0.0f) , mCloudOpacity(0.0f) , mCloudSpeed(0.0f) , mStarsOpacity(0.0f) - , mLightning(NULL) , mRemainingTransitionTime(0.0f) , mGlareFade(0.0f) , mGlare(0.0f) @@ -277,7 +240,6 @@ SkyManager::SkyManager(Ogre::SceneNode *root, Ogre::Camera *pCamera) , mCreated(false) , mCloudAnimationTimer(0.f) , mMoonRed(false) - , mParticleNode(NULL) , mRainEnabled(false) , mRainTimer(0) , mRainSpeed(0) @@ -285,118 +247,63 @@ SkyManager::SkyManager(Ogre::SceneNode *root, Ogre::Camera *pCamera) , mStormDirection(0,-1,0) , mIsStorm(false) { - mSceneMgr = root->getCreator(); - mRootNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(); + osg::ref_ptr skyroot (new CameraRelativeTransform); + skyroot->setCullingActive(false); + parentNode->addChild(skyroot); + + mRootNode = skyroot; + + // By default render before the world is rendered + mRootNode->getOrCreateStateSet()->setRenderBinDetails(-1, "RenderBin"); } void SkyManager::create() { assert(!mCreated); - sh::Factory::getInstance().setSharedParameter ("cloudBlendFactor", - sh::makeProperty(new sh::FloatValue(0))); - sh::Factory::getInstance().setSharedParameter ("cloudOpacity", - sh::makeProperty(new sh::FloatValue(1))); - sh::Factory::getInstance().setSharedParameter ("cloudColour", - sh::makeProperty(new sh::Vector3(1,1,1))); - sh::Factory::getInstance().setSharedParameter ("cloudAnimationTimer", - sh::makeProperty(new sh::FloatValue(0))); - sh::Factory::getInstance().setSharedParameter ("nightFade", - sh::makeProperty(new sh::FloatValue(0))); - sh::Factory::getInstance().setSharedParameter ("atmosphereColour", sh::makeProperty(new sh::Vector4(0,0,0,1))); - sh::Factory::getInstance().setSharedParameter ("horizonColour", sh::makeProperty(new sh::Vector4(0,0,0,1))); - - sh::Factory::getInstance().setTextureAlias ("cloud_texture_1", ""); - sh::Factory::getInstance().setTextureAlias ("cloud_texture_2", ""); - - // Create light used for thunderstorm - mLightning = mSceneMgr->createLight(); - mLightning->setType (Ogre::Light::LT_DIRECTIONAL); - mLightning->setDirection (Ogre::Vector3(0.3f, -0.7f, 0.3f)); - mLightning->setVisible (false); - mLightning->setDiffuseColour (ColourValue(3,3,3)); - - const MWWorld::Fallback* fallback=MWBase::Environment::get().getWorld()->getFallback(); - mSecunda = new Moon("secunda_texture", fallback->getFallbackFloat("Moons_Secunda_Size")/100, Vector3(-0.4f, 0.4f, 0.5f), mRootNode, "openmw_moon"); - mSecunda->setType(Moon::Type_Secunda); - mSecunda->setRenderQueue(RQG_SkiesEarly+4); - - mMasser = new Moon("masser_texture", fallback->getFallbackFloat("Moons_Masser_Size")/100, Vector3(-0.4f, 0.4f, 0.5f), mRootNode, "openmw_moon"); - mMasser->setRenderQueue(RQG_SkiesEarly+3); - mMasser->setType(Moon::Type_Masser); - - mSun = new BillboardObject("textures\\tx_sun_05.dds", 1, Vector3(0.4f, 0.4f, 0.4f), mRootNode, "openmw_sun"); - mSun->setRenderQueue(RQG_SkiesEarly+4); - mSunGlare = new BillboardObject("textures\\tx_sun_flash_grey_05.dds", 3, Vector3(0.4f, 0.4f, 0.4f), mRootNode, "openmw_sun"); - mSunGlare->setRenderQueue(RQG_SkiesLate); - mSunGlare->setVisibilityFlags(RV_NoReflection); - - Ogre::AxisAlignedBox aabInf = Ogre::AxisAlignedBox::BOX_INFINITE; - - // Stars - mAtmosphereNight = mRootNode->createChildSceneNode(); - NifOgre::ObjectScenePtr objects; - if (Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup("meshes\\sky_night_02.nif")) - objects = NifOgre::Loader::createObjects(mAtmosphereNight, "meshes\\sky_night_02.nif"); - else - objects = NifOgre::Loader::createObjects(mAtmosphereNight, "meshes\\sky_night_01.nif"); - - for(size_t i = 0, matidx = 0;i < objects->mEntities.size();i++) - { - Entity* night1_ent = objects->mEntities[i]; - night1_ent->setRenderQueueGroup(RQG_SkiesEarly+1); - night1_ent->setVisibilityFlags(RV_Sky); - night1_ent->setCastShadows(false); - night1_ent->getMesh()->_setBounds (aabInf); - - for (unsigned int j=0; jgetNumSubEntities(); ++j) - { - std::string matName = "openmw_stars_" + boost::lexical_cast(matidx++); - sh::MaterialInstance* m = sh::Factory::getInstance().createMaterialInstance(matName, "openmw_stars"); - - std::string textureName = sh::retrieveValue( - sh::Factory::getInstance().getMaterialInstance(night1_ent->getSubEntity(j)->getMaterialName())->getProperty("diffuseMap"), NULL).get(); + mAtmosphereDay = mSceneManager->createInstance("meshes/sky_atmosphere.nif", mRootNode); + ModVertexAlphaVisitor modAtmosphere(0); + mAtmosphereDay->accept(modAtmosphere); - m->setProperty("texture", sh::makeProperty(new sh::StringValue(textureName))); + // osg::Node* alphaBlendedRoot = - night1_ent->getSubEntity(j)->setMaterialName(matName); - } - } - mObjects.push_back(objects); - - // Atmosphere (day) - mAtmosphereDay = mRootNode->createChildSceneNode(); - objects = NifOgre::Loader::createObjects(mAtmosphereDay, "meshes\\sky_atmosphere.nif"); - for(size_t i = 0;i < objects->mEntities.size();i++) - { - Entity* atmosphere_ent = objects->mEntities[i]; - atmosphere_ent->setCastShadows(false); - atmosphere_ent->setRenderQueueGroup(RQG_SkiesEarly); - atmosphere_ent->setVisibilityFlags(RV_Sky); - - for(unsigned int j = 0;j < atmosphere_ent->getNumSubEntities();j++) - atmosphere_ent->getSubEntity (j)->setMaterialName("openmw_atmosphere"); + mAtmosphereUpdater = new AtmosphereUpdater; + mAtmosphereDay->addUpdateCallback(mAtmosphereUpdater); - // Using infinite AAB here to prevent being clipped by the custom near clip plane used for reflections/refractions - atmosphere_ent->getMesh()->_setBounds (aabInf); - } - mObjects.push_back(objects); - - // Clouds - mCloudNode = mRootNode->createChildSceneNode(); - objects = NifOgre::Loader::createObjects(mCloudNode, "meshes\\sky_clouds_01.nif"); - for(size_t i = 0;i < objects->mEntities.size();i++) - { - Entity* clouds_ent = objects->mEntities[i]; - clouds_ent->setVisibilityFlags(RV_Sky); - clouds_ent->setRenderQueueGroup(RQG_SkiesEarly+5); - for(unsigned int j = 0;j < clouds_ent->getNumSubEntities();j++) - clouds_ent->getSubEntity(j)->setMaterialName("openmw_clouds"); - clouds_ent->setCastShadows(false); - // Using infinite AAB here to prevent being clipped by the custom near clip plane used for reflections/refractions - clouds_ent->getMesh()->_setBounds (aabInf); - } - mObjects.push_back(objects); + if (mSceneManager->getVFS()->exists("meshes/sky_night_02.nif")) + mAtmosphereNight = mSceneManager->createInstance("meshes/sky_night_02.nif", mRootNode); + else + mAtmosphereNight = mSceneManager->createInstance("meshes/sky_night_01.nif", mRootNode); + mAtmosphereNight->getOrCreateStateSet()->setAttributeAndModes(createAlphaTrackingUnlitMaterial(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + ModVertexAlphaVisitor modStars(2); + mAtmosphereNight->accept(modStars); + mAtmosphereNight->setNodeMask(0); + + osg::Geode* geode = new osg::Geode; + osg::ref_ptr sun = createTexturedQuad(); + geode->addDrawable(sun); + osg::PositionAttitudeTransform* trans = new osg::PositionAttitudeTransform; + trans->setScale(osg::Vec3f(450,450,450)); + trans->addChild(geode); + mRootNode->addChild(trans); + + mSunTransform = trans; + + mCloudNode = mSceneManager->createInstance("meshes/sky_clouds_01.nif", mRootNode); + ModVertexAlphaVisitor modClouds(1); + mCloudNode->accept(modClouds); + + osg::ref_ptr sunTex = mSceneManager->getTextureManager()->getTexture2D("textures/tx_sun_05.dds", + osg::Texture::CLAMP, osg::Texture::CLAMP); + trans->getOrCreateStateSet()->setTextureAttributeAndModes(0, sunTex, osg::StateAttribute::ON); + trans->getOrCreateStateSet()->setAttributeAndModes(createUnlitMaterial(), osg::StateAttribute::ON); + + mCloudNode->getOrCreateStateSet()->setAttributeAndModes(createAlphaTrackingUnlitMaterial(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + + osg::ref_ptr depth = new osg::Depth; + depth->setWriteMask(false); + mRootNode->getOrCreateStateSet()->setAttributeAndModes(depth, osg::StateAttribute::ON); + mRootNode->getOrCreateStateSet()->setMode(GL_BLEND, osg::StateAttribute::ON); mCreated = true; } @@ -404,158 +311,51 @@ void SkyManager::create() SkyManager::~SkyManager() { clearRain(); - delete mSun; - delete mSunGlare; - delete mMasser; - delete mSecunda; } int SkyManager::getMasserPhase() const { + return 0; if (!mCreated) return 0; - return mMasser->getPhaseInt(); + //return mMasser->getPhaseInt(); } int SkyManager::getSecundaPhase() const { + return 0; if (!mCreated) return 0; - return mSecunda->getPhaseInt(); + //return mSecunda->getPhaseInt(); } void SkyManager::clearRain() { - for (std::map::iterator it = mRainModels.begin(); it != mRainModels.end();) - { - it->second.setNull(); - mSceneMgr->destroySceneNode(it->first); - mRainModels.erase(it++); - } } void SkyManager::updateRain(float dt) { - // Move existing rain - // Note: if rain gets disabled, we let the existing rain drops finish falling down. - float minHeight = 200; - for (std::map::iterator it = mRainModels.begin(); it != mRainModels.end();) - { - Ogre::Vector3 pos = it->first->getPosition(); - pos.z -= mRainSpeed * dt; - it->first->setPosition(pos); - if (pos.z < -minHeight - // Here we might want to add a "splash" effect later - || MWBase::Environment::get().getWorld()->isUnderwater( - MWBase::Environment::get().getWorld()->getPlayerPtr().getCell(), it->first->_getDerivedPosition())) - { - it->second.setNull(); - mSceneMgr->destroySceneNode(it->first); - mRainModels.erase(it++); - } - else - ++it; - } - - // Spawn new rain - float rainFrequency = mRainFrequency; - if (mRainEnabled) - { - mRainTimer += dt; - if (mRainTimer >= 1.f/rainFrequency) - { - mRainTimer = 0; - - // TODO: handle rain settings from Morrowind.ini - const float rangeRandom = 100; - float xOffs = OEngine::Misc::Rng::rollProbability() * rangeRandom - (rangeRandom / 2); - float yOffs = OEngine::Misc::Rng::rollProbability() * rangeRandom - (rangeRandom / 2); - - // Create a separate node to control the offset, since a node with setInheritOrientation(false) will still - // consider the orientation of the parent node for its position, just not for its orientation - float startHeight = 700; - Ogre::Vector3 worldPos = mParticleNode->_getDerivedPosition(); - worldPos += Ogre::Vector3(xOffs, yOffs, startHeight); - if (MWBase::Environment::get().getWorld()->isUnderwater( - MWBase::Environment::get().getWorld()->getPlayerPtr().getCell(), worldPos)) - return; - - Ogre::SceneNode* offsetNode = mParticleNode->createChildSceneNode(Ogre::Vector3(xOffs,yOffs,startHeight)); - - // Spawn a new rain object for each instance. - // TODO: this is inefficient. We could try to use an Ogre::ParticleSystem instead, but then we would need to make assumptions - // about the rain meshes being Quads and their dimensions. - // Or we could clone meshes into one vertex buffer manually. - NifOgre::ObjectScenePtr objects = NifOgre::Loader::createObjects(offsetNode, mRainEffect); - for (unsigned int i=0; imEntities.size(); ++i) - { - objects->mEntities[i]->setRenderQueueGroup(RQG_Alpha); - objects->mEntities[i]->setVisibilityFlags(RV_Sky); - } - for (unsigned int i=0; imParticles.size(); ++i) - { - objects->mParticles[i]->setRenderQueueGroup(RQG_Alpha); - objects->mParticles[i]->setVisibilityFlags(RV_Sky); - } - mRainModels[offsetNode] = objects; - } - } } void SkyManager::update(float duration) { if (!mEnabled) return; - const MWWorld::Fallback* fallback=MWBase::Environment::get().getWorld()->getFallback(); + //const MWWorld::Fallback* fallback=MWBase::Environment::get().getWorld()->getFallback(); - if (!mParticle.isNull()) - { - for (unsigned int i=0; imControllers.size(); ++i) - mParticle->mControllers[i].update(); - - for (unsigned int i=0; imParticles.size(); ++i) - { - Ogre::ParticleSystem* psys = mParticle->mParticles[i]; - Ogre::ParticleIterator pi = psys->_getIterator(); - while (!pi.end()) - { - Ogre::Particle *p = pi.getNext(); - #if OGRE_VERSION >= (1 << 16 | 10 << 8 | 0) - Ogre::Vector3 pos = p->mPosition; - Ogre::Real& timeToLive = p->mTimeToLive; - #else - Ogre::Vector3 pos = p->position; - Ogre::Real& timeToLive = p->timeToLive; - #endif - - if (psys->getKeepParticlesInLocalSpace() && psys->getParentNode()) - pos = psys->getParentNode()->convertLocalToWorldPosition(pos); - - if (MWBase::Environment::get().getWorld()->isUnderwater( - MWBase::Environment::get().getWorld()->getPlayerPtr().getCell(), pos)) - timeToLive = 0; - } - } - - if (mIsStorm) - mParticleNode->setOrientation(Ogre::Vector3::UNIT_Y.getRotationTo(mStormDirection)); - } - - if (mIsStorm) - mCloudNode->setOrientation(Ogre::Vector3::UNIT_Y.getRotationTo(mStormDirection)); - else - mCloudNode->setOrientation(Ogre::Quaternion::IDENTITY); + //if (mIsStorm) + // mCloudNode->setOrientation(Ogre::Vector3::UNIT_Y.getRotationTo(mStormDirection)); + //else + // mCloudNode->setOrientation(Ogre::Quaternion::IDENTITY); updateRain(duration); // UV Scroll the clouds mCloudAnimationTimer += duration * mCloudSpeed; - sh::Factory::getInstance().setSharedParameter ("cloudAnimationTimer", - sh::makeProperty(new sh::FloatValue(mCloudAnimationTimer))); /// \todo improve this - mMasser->setPhase( static_cast( (int) ((mDay % 32)/4.f)) ); - mSecunda->setPhase ( static_cast( (int) ((mDay % 32)/4.f)) ); + //mMasser->setPhase( static_cast( (int) ((mDay % 32)/4.f)) ); + //mSecunda->setPhase ( static_cast( (int) ((mDay % 32)/4.f)) ); - mSecunda->setColour ( mMoonRed ? fallback->getFallbackColour("Moons_Script_Color") : ColourValue(1,1,1,1)); - mMasser->setColour (ColourValue(1,1,1,1)); + //mSecunda->setColour ( mMoonRed ? fallback->getFallbackColour("Moons_Script_Color") : ColourValue(1,1,1,1)); + //mMasser->setColour (ColourValue(1,1,1,1)); if (mSunEnabled) { @@ -573,45 +373,36 @@ void SkyManager::update(float duration) // increase the strength of the sun glare effect depending // on how directly the player is looking at the sun + /* Vector3 sun = mSunGlare->getPosition(); Vector3 cam = mCamera->getRealDirection(); const Degree angle = sun.angleBetween( cam ); float val = 1- (angle.valueDegrees() / 180.f); val = (val*val*val*val)*6; mSunGlare->setSize(val * mGlareFade); + */ } - mSunGlare->setVisible(mSunEnabled); - mSun->setVisible(mSunEnabled); - mMasser->setVisible(mMasserEnabled); - mSecunda->setVisible(mSecundaEnabled); + //mSunGlare->setVisible(mSunEnabled); + //mSun->setVisible(mSunEnabled); + //mMasser->setVisible(mMasserEnabled); + //mSecunda->setVisible(mSecundaEnabled); // rotate the stars by 360 degrees every 4 days - mAtmosphereNight->roll(Degree(MWBase::Environment::get().getWorld()->getTimeScaleFactor()*duration*360 / (3600*96.f))); + //mAtmosphereNight->roll(Degree(MWBase::Environment::get().getWorld()->getTimeScaleFactor()*duration*360 / (3600*96.f))); } -void SkyManager::enable() +void SkyManager::setEnabled(bool enabled) { - if (!mCreated) + if (enabled && !mCreated) create(); - if (mParticleNode) - mParticleNode->setVisible(true); + if (!enabled) + clearRain(); - mRootNode->setVisible(true); - mEnabled = true; -} + mRootNode->setNodeMask(enabled ? ~((unsigned int)(0)) : 0); -void SkyManager::disable() -{ - if (mParticleNode) - mParticleNode->setVisible(false); - - clearRain(); - - mRootNode->setVisible(false); - - mEnabled = false; + mEnabled = enabled; } void SkyManager::setMoonColour (bool red) @@ -635,59 +426,53 @@ void SkyManager::setWeather(const MWWorld::WeatherResult& weather) if (mCurrentParticleEffect.empty()) { - mParticle.setNull(); + if (mParticleEffect) + mRootNode->removeChild(mParticleEffect); + mParticleEffect = NULL; } else { - mParticle = NifOgre::Loader::createObjects(mParticleNode, mCurrentParticleEffect); - for(size_t i = 0; i < mParticle->mParticles.size(); ++i) - { - ParticleSystem* particle = mParticle->mParticles[i]; - particle->setRenderQueueGroup(RQG_Alpha); - particle->setVisibilityFlags(RV_Sky); - } + mParticleEffect = mSceneManager->createInstance(mCurrentParticleEffect, mRootNode); + DisableCullingVisitor visitor; + mParticleEffect->accept(visitor); + + /* for (size_t i = 0; i < mParticle->mControllers.size(); ++i) { if (mParticle->mControllers[i].getSource().isNull()) mParticle->mControllers[i].setSource(Ogre::ControllerManager::getSingleton().getFrameTimeSource()); } + */ } } if (mClouds != weather.mCloudTexture) { - sh::Factory::getInstance().setTextureAlias ("cloud_texture_1", Misc::ResourceHelpers::correctTexturePath(weather.mCloudTexture)); mClouds = weather.mCloudTexture; } if (mNextClouds != weather.mNextCloudTexture) { - sh::Factory::getInstance().setTextureAlias ("cloud_texture_2", Misc::ResourceHelpers::correctTexturePath(weather.mNextCloudTexture)); mNextClouds = weather.mNextCloudTexture; } if (mCloudBlendFactor != weather.mCloudBlendFactor) { mCloudBlendFactor = weather.mCloudBlendFactor; - sh::Factory::getInstance().setSharedParameter ("cloudBlendFactor", - sh::makeProperty(new sh::FloatValue(weather.mCloudBlendFactor))); } if (mCloudOpacity != weather.mCloudOpacity) { mCloudOpacity = weather.mCloudOpacity; - sh::Factory::getInstance().setSharedParameter ("cloudOpacity", - sh::makeProperty(new sh::FloatValue(weather.mCloudOpacity))); } if (mCloudColour != weather.mSunColor) { - ColourValue clr( weather.mSunColor.r*0.7f + weather.mAmbientColor.r*0.7f, - weather.mSunColor.g*0.7f + weather.mAmbientColor.g*0.7f, - weather.mSunColor.b*0.7f + weather.mAmbientColor.b*0.7f); - - sh::Factory::getInstance().setSharedParameter ("cloudColour", - sh::makeProperty(new sh::Vector3(clr.r, clr.g, clr.b))); + /* + osg::Vec4f clr( weather.mSunColor.r()*0.7f + weather.mAmbientColor.r()*0.7f, + weather.mSunColor.g()*0.7f + weather.mAmbientColor.g()*0.7f, + weather.mSunColor.b()*0.7f + weather.mAmbientColor.b()*0.7f, 1.f); + */ mCloudColour = weather.mSunColor; } @@ -695,35 +480,32 @@ void SkyManager::setWeather(const MWWorld::WeatherResult& weather) if (mSkyColour != weather.mSkyColor) { mSkyColour = weather.mSkyColor; - sh::Factory::getInstance().setSharedParameter ("atmosphereColour", sh::makeProperty(new sh::Vector4( - weather.mSkyColor.r, weather.mSkyColor.g, weather.mSkyColor.b, weather.mSkyColor.a))); + + mAtmosphereUpdater->setEmissionColor(mSkyColour); } if (mFogColour != weather.mFogColor) { mFogColour = weather.mFogColor; - sh::Factory::getInstance().setSharedParameter ("horizonColour", sh::makeProperty(new sh::Vector4( - weather.mFogColor.r, weather.mFogColor.g, weather.mFogColor.b, weather.mFogColor.a))); } mCloudSpeed = weather.mCloudSpeed; if (weather.mNight && mStarsOpacity != weather.mNightFade) { - if (weather.mNightFade == 0) - mAtmosphereNight->setVisible(false); - else + if (weather.mNightFade != 0) { - mAtmosphereNight->setVisible(true); - - sh::Factory::getInstance().setSharedParameter ("nightFade", - sh::makeProperty(new sh::FloatValue(weather.mNightFade))); + //sh::Factory::getInstance().setSharedParameter ("nightFade", + // sh::makeProperty(new sh::FloatValue(weather.mNightFade))); - mStarsOpacity = weather.mNightFade; + //mStarsOpacity = weather.mNightFade; } } + mAtmosphereNight->setNodeMask((weather.mNight && mEnabled) ? ~0 : 0); + + /* float strength; float timeofday_angle = std::abs(mSunGlare->getPosition().z/mSunGlare->getPosition().length()); if (timeofday_angle <= 0.44) @@ -735,12 +517,12 @@ void SkyManager::setWeather(const MWWorld::WeatherResult& weather) mSun->setVisibility(weather.mGlareView * strength); - mAtmosphereNight->setVisible(weather.mNight && mEnabled); if (mParticle.get()) setAlpha(mParticle, weather.mEffectFade); for (std::map::iterator it = mRainModels.begin(); it != mRainModels.end(); ++it) setAlpha(it->second, weather.mEffectFade); + */ } void SkyManager::setGlare(const float glare) @@ -748,12 +530,6 @@ void SkyManager::setGlare(const float glare) mGlare = glare; } -Vector3 SkyManager::getRealSunPos() -{ - if (!mCreated) return Vector3(0,0,0); - return mSun->getNode()->getPosition() + mCamera->getRealPosition(); -} - void SkyManager::sunEnable() { mSunEnabled = true; @@ -764,32 +540,34 @@ void SkyManager::sunDisable() mSunEnabled = false; } -void SkyManager::setStormDirection(const Vector3 &direction) +void SkyManager::setStormDirection(const Ogre::Vector3 &direction) { mStormDirection = direction; } -void SkyManager::setSunDirection(const Vector3& direction, bool is_night) +void SkyManager::setSunDirection(const osg::Vec3f& direction) { if (!mCreated) return; - mSun->setPosition(direction); - mSunGlare->setPosition(direction); - float height = direction.z; - float fade = is_night ? 0.0f : (( height > 0.5) ? 1.0f : height * 2); - sh::Factory::getInstance ().setSharedParameter ("waterSunFade_sunHeight", sh::makeProperty(new sh::Vector2(fade, height))); + mSunTransform->setPosition(direction*1000.f); + + osg::Quat quat; + quat.makeRotate(osg::Vec3f(0,0,1), direction); + mSunTransform->setAttitude(quat); + + //mSunGlare->setPosition(direction); } -void SkyManager::setMasserDirection(const Vector3& direction) +void SkyManager::setMasserDirection(const Ogre::Vector3& direction) { if (!mCreated) return; - mMasser->setPosition(direction); + //mMasser->setPosition(direction); } -void SkyManager::setSecundaDirection(const Vector3& direction) +void SkyManager::setSecundaDirection(const Ogre::Vector3& direction) { if (!mCreated) return; - mSecunda->setPosition(direction); + //mSecunda->setPosition(direction); } void SkyManager::masserEnable() @@ -815,6 +593,7 @@ void SkyManager::secundaDisable() void SkyManager::setLightningStrength(const float factor) { if (!mCreated) return; + /* if (factor > 0.f) { mLightning->setDiffuseColour (ColourValue(2*factor, 2*factor, 2*factor)); @@ -822,18 +601,19 @@ void SkyManager::setLightningStrength(const float factor) } else mLightning->setVisible(false); + */ } void SkyManager::setMasserFade(const float fade) { if (!mCreated) return; - mMasser->setVisibility(fade); + //mMasser->setVisibility(fade); } void SkyManager::setSecundaFade(const float fade) { if (!mCreated) return; - mSecunda->setVisibility(fade); + //mSecunda->setVisibility(fade); } void SkyManager::setHour(double hour) @@ -847,28 +627,11 @@ void SkyManager::setDate(int day, int month) mMonth = month; } -Ogre::SceneNode* SkyManager::getSunNode() -{ - if (!mCreated) return 0; - return mSun->getNode(); -} - void SkyManager::setGlareEnabled (bool enabled) { if (!mCreated || !mEnabled) return; - mSunGlare->setVisible (mSunEnabled && enabled); + //mSunGlare->setVisible (mSunEnabled && enabled); } -void SkyManager::attachToNode(SceneNode *sceneNode) -{ - if (!mParticleNode) - { - mParticleNode = sceneNode->createChildSceneNode(); - mParticleNode->setInheritOrientation(false); - } - else - { - sceneNode->addChild(mParticleNode); - } } diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index 6950dbab3..c8403af71 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -1,128 +1,35 @@ -#ifndef GAME_RENDER_SKY_H -#define GAME_RENDER_SKY_H - -#include - -#include -#include -#include -#include -#include - -#include - -#include +#ifndef OPENMW_MWRENDER_SKY_H +#define OPENMW_MWRENDER_SKY_H +#include #include "../mwworld/weather.hpp" -namespace Ogre +namespace osg +{ + class Group; + class Node; + class Material; +} + +namespace Resource { - class RenderWindow; - class SceneNode; - class Camera; - class Viewport; class SceneManager; - class Entity; - class BillboardSet; - class TextureUnitState; } namespace MWRender { - class BillboardObject : public sh::MaterialInstanceListener - { - public: - BillboardObject( const Ogre::String& textureName, - const float size, - const Ogre::Vector3& position, - Ogre::SceneNode* rootNode, - const std::string& material - ); - - void requestedConfiguration (sh::MaterialInstance* m, const std::string& configuration); - void createdConfiguration (sh::MaterialInstance* m, const std::string& configuration); - - virtual ~BillboardObject() {} - - void setColour(const Ogre::ColourValue& pColour); - void setPosition(const Ogre::Vector3& pPosition); - void setVisible(const bool visible); - void setRenderQueue(unsigned int id); - void setVisibilityFlags(int flags); - void setSize(const float size); - Ogre::Vector3 getPosition() const; - - void setVisibility(const float visibility); - - Ogre::SceneNode* getNode(); - - protected: - float mVisibility; - Ogre::ColourValue mColour; - Ogre::SceneNode* mNode; - sh::MaterialInstance* mMaterial; - Ogre::Entity* mEntity; - }; - - - /* - * The moons need a seperate class because of their shader (which allows them to be partially transparent) - */ - class Moon : public BillboardObject - { - public: - Moon( const Ogre::String& textureName, - const float size, - const Ogre::Vector3& position, - Ogre::SceneNode* rootNode, - const std::string& material - ); - - virtual ~Moon() {} - - enum Phase - { - Phase_New = 0, - Phase_WaxingCrescent, - Phase_WaxingHalf, - Phase_WaxingGibbous, - Phase_Full, - Phase_WaningGibbous, - Phase_WaningHalf, - Phase_WaningCrescent - }; - - enum Type - { - Type_Masser = 0, - Type_Secunda - }; - - void setPhase(const Phase& phase); - void setType(const Type& type); - - unsigned int getPhaseInt() const; - - private: - Type mType; - Phase mPhase; - }; + class AtmosphereUpdater; class SkyManager { public: - SkyManager(Ogre::SceneNode* root, Ogre::Camera* pCamera); + SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneManager); ~SkyManager(); - /// Attach weather particle effects to this scene node (should be the Camera's parent node) - void attachToNode(Ogre::SceneNode* sceneNode); - void update(float duration); - void enable(); - - void disable(); + void setEnabled(bool enabled); void setHour (double hour); ///< will be called even when sky is disabled. @@ -143,8 +50,6 @@ namespace MWRender void setWeather(const MWWorld::WeatherResult& weather); - Ogre::SceneNode* getSunNode(); - void sunEnable(); void sunDisable(); @@ -153,7 +58,7 @@ namespace MWRender void setStormDirection(const Ogre::Vector3& direction); - void setSunDirection(const Ogre::Vector3& direction, bool is_night); + void setSunDirection(const osg::Vec3f& direction); void setMasserDirection(const Ogre::Vector3& direction); @@ -173,7 +78,6 @@ namespace MWRender void setGlare(const float glare); void setGlareEnabled(bool enabled); - Ogre::Vector3 getRealSunPos(); private: void create(); @@ -182,6 +86,22 @@ namespace MWRender void updateRain(float dt); void clearRain(); + Resource::SceneManager* mSceneManager; + + osg::ref_ptr mRootNode; + + osg::ref_ptr mParticleEffect; + + osg::ref_ptr mCloudNode; + + osg::ref_ptr mAtmosphereDay; + + osg::ref_ptr mAtmosphereNight; + + osg::ref_ptr mAtmosphereUpdater; + + osg::ref_ptr mSunTransform; + bool mCreated; bool mMoonRed; @@ -194,26 +114,6 @@ namespace MWRender float mCloudAnimationTimer; - BillboardObject* mSun; - BillboardObject* mSunGlare; - Moon* mMasser; - Moon* mSecunda; - - Ogre::Camera* mCamera; - Ogre::SceneNode* mRootNode; - Ogre::SceneManager* mSceneMgr; - - Ogre::SceneNode* mAtmosphereDay; - Ogre::SceneNode* mAtmosphereNight; - - Ogre::SceneNode* mCloudNode; - - std::vector mObjects; - - Ogre::SceneNode* mParticleNode; - NifOgre::ObjectScenePtr mParticle; - - std::map mRainModels; float mRainTimer; Ogre::Vector3 mStormDirection; @@ -225,14 +125,12 @@ namespace MWRender float mCloudOpacity; float mCloudSpeed; float mStarsOpacity; - Ogre::ColourValue mCloudColour; - Ogre::ColourValue mSkyColour; - Ogre::ColourValue mFogColour; + osg::Vec4f mCloudColour; + osg::Vec4f mSkyColour; + osg::Vec4f mFogColour; std::string mCurrentParticleEffect; - Ogre::Light* mLightning; - float mRemainingTransitionTime; float mGlare; // target diff --git a/apps/openmw/mwworld/fallback.cpp b/apps/openmw/mwworld/fallback.cpp index 3a8154ca7..fd6022481 100644 --- a/apps/openmw/mwworld/fallback.cpp +++ b/apps/openmw/mwworld/fallback.cpp @@ -1,5 +1,7 @@ #include "fallback.hpp" -#include "boost/lexical_cast.hpp" + +#include + namespace MWWorld { Fallback::Fallback(const std::map& fallback):mFallbackMap(fallback) @@ -39,11 +41,11 @@ namespace MWWorld else return boost::lexical_cast(fallback); } - Ogre::ColourValue Fallback::getFallbackColour(const std::string& fall) const + osg::Vec4f Fallback::getFallbackColour(const std::string& fall) const { std::string sum=getFallbackString(fall); if(sum.empty()) - return Ogre::ColourValue(0,0,0); + return osg::Vec4f(0.f,0.f,0.f,1.f); else { std::string ret[3]; @@ -53,7 +55,7 @@ namespace MWWorld else if (sum[i] != ' ') ret[j]+=sum[i]; } - return Ogre::ColourValue(boost::lexical_cast(ret[0])/255.f,boost::lexical_cast(ret[1])/255.f,boost::lexical_cast(ret[2])/255.f); + return osg::Vec4f(boost::lexical_cast(ret[0])/255.f,boost::lexical_cast(ret[1])/255.f,boost::lexical_cast(ret[2])/255.f, 1.f); } } } diff --git a/apps/openmw/mwworld/fallback.hpp b/apps/openmw/mwworld/fallback.hpp index f69a5e57b..af47063ee 100644 --- a/apps/openmw/mwworld/fallback.hpp +++ b/apps/openmw/mwworld/fallback.hpp @@ -4,7 +4,7 @@ #include #include -#include +#include namespace MWWorld { @@ -17,7 +17,7 @@ namespace MWWorld float getFallbackFloat(const std::string& fall) const; int getFallbackInt(const std::string& fall) const; bool getFallbackBool(const std::string& fall) const; - Ogre::ColourValue getFallbackColour(const std::string& fall) const; + osg::Vec4f getFallbackColour(const std::string& fall) const; }; } #endif diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 82814b623..fe4f62953 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -13,16 +13,15 @@ #include "../mwsound/sound.hpp" -//#include "../mwrender/renderingmanager.hpp" +#include "../mwrender/renderingmanager.hpp" +#include "../mwrender/sky.hpp" #include "player.hpp" #include "esmstore.hpp" #include "fallback.hpp" #include "cellstore.hpp" -using namespace Ogre; using namespace MWWorld; -using namespace MWSound; namespace { @@ -31,7 +30,7 @@ namespace return x * (1-factor) + y * factor; } - Ogre::ColourValue lerp (const Ogre::ColourValue& x, const Ogre::ColourValue& y, float factor) + osg::Vec4f lerp (const osg::Vec4f& x, const osg::Vec4f& y, float factor) { return x * (1-factor) + y * factor; } @@ -196,7 +195,7 @@ WeatherManager::~WeatherManager() stopSounds(); } -void WeatherManager::setWeather(const String& weather, bool instant) +void WeatherManager::setWeather(const std::string& weather, bool instant) { if (weather == mCurrentWeather && mNextWeather == "") { @@ -224,7 +223,7 @@ void WeatherManager::setWeather(const String& weather, bool instant) mFirstUpdate = false; } -void WeatherManager::setResult(const String& weatherType) +void WeatherManager::setResult(const std::string& weatherType) { const Weather& current = mWeatherSettings[weatherType]; @@ -387,8 +386,8 @@ void WeatherManager::update(float duration, bool paused) const bool exterior = (world->isCellExterior() || world->isCellQuasiExterior()); if (!exterior) { - mRendering->skyDisable(); - mRendering->getSkyManager()->setLightningStrength(0.f); + mRendering->setSkyEnabled(false); + //mRendering->getSkyManager()->setLightningStrength(0.f); stopSounds(); return; } @@ -421,16 +420,16 @@ void WeatherManager::update(float duration, bool paused) mStormDirection = (playerPos - redMountainPos); mStormDirection.z = 0; - mRendering->getSkyManager()->setStormDirection(mStormDirection); + //mRendering->getSkyManager()->setStormDirection(mStormDirection); } mRendering->configureFog(mResult.mFogDepth, mResult.mFogColor); // disable sun during night - if (mHour >= mNightStart || mHour <= mSunriseTime) - mRendering->getSkyManager()->sunDisable(); - else - mRendering->getSkyManager()->sunEnable(); + //if (mHour >= mNightStart || mHour <= mSunriseTime) + //mRendering->getSkyManager()->sunDisable(); + //else + //mRendering->getSkyManager()->sunEnable(); // Update the sun direction. Run it east to west at a fixed angle from overhead. // The sun's speed at day and night may differ, since mSunriseTime and mNightStart @@ -455,11 +454,11 @@ void WeatherManager::update(float duration, bool paused) theta = M_PI * (adjustedHour - adjustedNightStart) / nightDuration; } - Vector3 final( + osg::Vec3f final( static_cast(cos(theta)), -0.268f, // approx tan( -15 degrees ) static_cast(sin(theta))); - mRendering->setSunDirection( final, is_night ); + mRendering->setSunDirection( final * -1 ); } /* @@ -484,20 +483,20 @@ void WeatherManager::update(float duration, bool paused) if (moonHeight != 0) { int facing = (moonHeight <= 1) ? 1 : -1; - Vector3 masser( + osg::Vec3f masser( (moonHeight - 1) * facing, (1 - moonHeight) * facing, moonHeight); - Vector3 secunda( + osg::Vec3f secunda( (moonHeight - 1) * facing * 1.25f, (1 - moonHeight) * facing * 0.8f, moonHeight); - mRendering->getSkyManager()->setMasserDirection(masser); - mRendering->getSkyManager()->setSecundaDirection(secunda); - mRendering->getSkyManager()->masserEnable(); - mRendering->getSkyManager()->secundaEnable(); + //mRendering->getSkyManager()->setMasserDirection(masser); + //mRendering->getSkyManager()->setSecundaDirection(secunda); + //mRendering->getSkyManager()->masserEnable(); + //mRendering->getSkyManager()->secundaEnable(); float angle = (1-moonHeight) * 90.f * facing; float masserHourFade = calculateHourFade("Masser"); @@ -508,13 +507,13 @@ void WeatherManager::update(float duration, bool paused) masserAngleFade *= masserHourFade; secundaAngleFade *= secundaHourFade; - mRendering->getSkyManager()->setMasserFade(masserAngleFade); - mRendering->getSkyManager()->setSecundaFade(secundaAngleFade); + //mRendering->getSkyManager()->setMasserFade(masserAngleFade); + //mRendering->getSkyManager()->setSecundaFade(secundaAngleFade); } else { - mRendering->getSkyManager()->masserDisable(); - mRendering->getSkyManager()->secundaDisable(); + //mRendering->getSkyManager()->masserDisable(); + //mRendering->getSkyManager()->secundaDisable(); } if (!paused) @@ -540,13 +539,13 @@ void WeatherManager::update(float duration, bool paused) } mThunderFlash -= duration; - if (mThunderFlash > 0) - mRendering->getSkyManager()->setLightningStrength( mThunderFlash / mThunderThreshold ); - else + //if (mThunderFlash > 0) + //mRendering->getSkyManager()->setLightningStrength( mThunderFlash / mThunderThreshold ); + //else { mThunderChanceNeeded = static_cast(OEngine::Misc::Rng::rollDice(100)); mThunderChance = 0; - mRendering->getSkyManager()->setLightningStrength( 0.f ); + //mRendering->getSkyManager()->setLightningStrength( 0.f ); } } else @@ -557,19 +556,19 @@ void WeatherManager::update(float duration, bool paused) { mThunderFlash = mThunderThreshold; - mRendering->getSkyManager()->setLightningStrength( mThunderFlash / mThunderThreshold ); + //mRendering->getSkyManager()->setLightningStrength( mThunderFlash / mThunderThreshold ); mThunderSoundDelay = 0.25; } } } - else - mRendering->getSkyManager()->setLightningStrength(0.f); + //else + //mRendering->getSkyManager()->setLightningStrength(0.f); } mRendering->setAmbientColour(mResult.mAmbientColor); - mRendering->sunEnable(false); + //mRendering->sunEnable(false); mRendering->setSunColour(mResult.mSunColor); mRendering->getSkyManager()->setWeather(mResult); @@ -850,3 +849,8 @@ Ogre::Vector3 WeatherManager::getStormDirection() const { return mStormDirection; } + +void WeatherManager::advanceTime(double hours) +{ + mTimePassed += hours*3600; +} diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index a2e668159..002f4355c 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -6,6 +6,7 @@ #include #include +#include #include "../mwbase/soundmanager.hpp" @@ -37,15 +38,15 @@ namespace MWWorld std::string mNextCloudTexture; float mCloudBlendFactor; - Ogre::ColourValue mFogColor; + osg::Vec4f mFogColor; - Ogre::ColourValue mAmbientColor; + osg::Vec4f mAmbientColor; - Ogre::ColourValue mSkyColor; + osg::Vec4f mSkyColor; - Ogre::ColourValue mSunColor; + osg::Vec4f mSunColor; - Ogre::ColourValue mSunDiscColor; + osg::Vec4f mSunDiscColor; float mFogDepth; @@ -80,25 +81,25 @@ namespace MWWorld std::string mCloudTexture; // Sky (atmosphere) colors - Ogre::ColourValue mSkySunriseColor, + osg::Vec4f mSkySunriseColor, mSkyDayColor, mSkySunsetColor, mSkyNightColor; // Fog colors - Ogre::ColourValue mFogSunriseColor, + osg::Vec4f mFogSunriseColor, mFogDayColor, mFogSunsetColor, mFogNightColor; // Ambient lighting colors - Ogre::ColourValue mAmbientSunriseColor, + osg::Vec4f mAmbientSunriseColor, mAmbientDayColor, mAmbientSunsetColor, mAmbientNightColor; // Sun (directional) lighting colors - Ogre::ColourValue mSunSunriseColor, + osg::Vec4f mSunSunriseColor, mSunDayColor, mSunSunsetColor, mSunNightColor; @@ -108,7 +109,7 @@ namespace MWWorld mLandFogNightDepth; // Color modulation for the sun itself during sunset (not completely sure) - Ogre::ColourValue mSunDiscSunsetColor; + osg::Vec4f mSunDiscSunsetColor; // Duration of weather transition (in days) float mTransitionDelta; @@ -185,10 +186,7 @@ namespace MWWorld Ogre::Vector3 getStormDirection() const; - void advanceTime(double hours) - { - mTimePassed += hours*3600; - } + void advanceTime(double hours); unsigned int getWeatherID() const; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 994a0c9dd..20298bd85 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -131,18 +131,16 @@ namespace MWWorld void World::adjustSky() { -#if 0 if (mSky && (isCellExterior() || isCellQuasiExterior())) { - mRendering->skySetHour (mGlobalVariables["gamehour"].getFloat()); - mRendering->skySetDate (mGlobalVariables["day"].getInteger(), - mGlobalVariables["month"].getInteger()); + //mRendering->skySetHour (mGlobalVariables["gamehour"].getFloat()); + //mRendering->skySetDate (mGlobalVariables["day"].getInteger(), + // mGlobalVariables["month"].getInteger()); - mRendering->skyEnable(); + mRendering->setSkyEnabled(true); } else - mRendering->skyDisable(); -#endif + mRendering->setSkyEnabled(false); } World::World ( @@ -171,7 +169,7 @@ namespace MWWorld //mPhysEngine->setSceneManager(renderer.getScene()); - //mWeatherManager = new MWWorld::WeatherManager(mRendering,&mFallback); + mWeatherManager = new MWWorld::WeatherManager(mRendering,&mFallback); mEsm.resize(contentFiles.size()); Loading::Listener* listener = MWBase::Environment::get().getWindowManager()->getLoadingScreen(); @@ -267,9 +265,9 @@ namespace MWWorld // mPhysics->toggleCollisionMode(); // we don't want old weather to persist on a new game - //delete mWeatherManager; - //mWeatherManager = 0; - //mWeatherManager = new MWWorld::WeatherManager(mRendering,&mFallback); + delete mWeatherManager; + mWeatherManager = 0; + mWeatherManager = new MWWorld::WeatherManager(mRendering,&mFallback); if (!mStartupScript.empty()) MWBase::Environment::get().getWindowManager()->executeInConsole(mStartupScript); @@ -277,7 +275,7 @@ namespace MWWorld void World::clear() { - //mWeatherManager->clear(); + mWeatherManager->clear(); //mRendering->clear(); #if 0 mProjectileManager->clear(); @@ -348,7 +346,7 @@ namespace MWWorld mCells.write (writer, progress); mGlobalVariables.write (writer, progress); mPlayer->write (writer, progress); - //mWeatherManager->write (writer, progress); + mWeatherManager->write (writer, progress); #if 0 mProjectileManager->write (writer, progress); #endif @@ -378,7 +376,7 @@ namespace MWWorld if (!mStore.readRecord (reader, type) && !mGlobalVariables.readRecord (reader, type) && !mPlayer->readRecord (reader, type) && - //!mWeatherManager->readRecord (reader, type) && + !mWeatherManager->readRecord (reader, type) && !mCells.readRecord (reader, type, contentFileMap) #if 0 && !mProjectileManager->readRecord (reader, type) @@ -479,7 +477,7 @@ namespace MWWorld // Must be cleared before mRendering is destroyed mProjectileManager->clear(); #endif - //delete mWeatherManager; + delete mWeatherManager; delete mWorldScene; delete mRendering; //delete mPhysics; @@ -819,7 +817,7 @@ namespace MWWorld { MWBase::Environment::get().getMechanicsManager()->advanceTime(static_cast(hours * 3600)); - //mWeatherManager->advanceTime (hours); + mWeatherManager->advanceTime (hours); hours += mGlobalVariables["gamehour"].getFloat(); @@ -845,7 +843,7 @@ namespace MWWorld //mRendering->skySetHour (hour); - //mWeatherManager->setHour(static_cast(hour)); + mWeatherManager->setHour(static_cast(hour)); if (days>0) setDay (days + mGlobalVariables["day"].getInteger()); @@ -1604,11 +1602,11 @@ namespace MWWorld void World::update (float duration, bool paused) { - /* if (mGoToJail && !paused) goToJail(); updateWeather(duration, paused); + /* if (!paused) doPhysics (duration); @@ -1731,17 +1729,17 @@ namespace MWWorld int World::getCurrentWeather() const { - return 0;//mWeatherManager->getWeatherID(); + return mWeatherManager->getWeatherID(); } void World::changeWeather(const std::string& region, const unsigned int id) { - //mWeatherManager->changeWeather(region, id); + mWeatherManager->changeWeather(region, id); } void World::modRegion(const std::string ®ionid, const std::vector &chances) { - //mWeatherManager->modRegion(regionid, chances); + mWeatherManager->modRegion(regionid, chances); } Ogre::Vector2 World::getNorthVector (CellStore* cell) @@ -2975,10 +2973,10 @@ namespace MWWorld if (mPlayer->wasTeleported()) { mPlayer->setTeleported(false); - //mWeatherManager->switchToNextWeather(true); + mWeatherManager->switchToNextWeather(true); } - //mWeatherManager->update(duration, paused); + mWeatherManager->update(duration, paused); } struct AddDetectedReference diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index f77bb4760..9afda480b 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -81,7 +81,7 @@ namespace MWWorld MWWorld::Fallback mFallback; MWRender::RenderingManager* mRendering; - //MWWorld::WeatherManager* mWeatherManager; + MWWorld::WeatherManager* mWeatherManager; MWWorld::Scene *mWorldScene; MWWorld::Player *mPlayer; diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index abce7020c..6b1c01644 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -39,7 +39,7 @@ add_component_dir (resource ) add_component_dir (sceneutil - clone attach lightmanager visitor util + clone attach lightmanager visitor util statesetcontroller ) add_component_dir (nif diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index ead6a9669..393f322d7 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -142,4 +142,14 @@ namespace Resource } } + const VFS::Manager* SceneManager::getVFS() const + { + return mVFS; + } + + Resource::TextureManager* SceneManager::getTextureManager() + { + return mTextureManager; + } + } diff --git a/components/resource/scenemanager.hpp b/components/resource/scenemanager.hpp index 4d6ad4855..6a52dfb21 100644 --- a/components/resource/scenemanager.hpp +++ b/components/resource/scenemanager.hpp @@ -55,6 +55,10 @@ namespace Resource /// in cases where multiple contexts are used over the lifetime of the application. void releaseGLObjects(osg::State* state); + const VFS::Manager* getVFS() const; + + Resource::TextureManager* getTextureManager(); + private: const VFS::Manager* mVFS; Resource::TextureManager* mTextureManager; diff --git a/components/sceneutil/statesetcontroller.cpp b/components/sceneutil/statesetcontroller.cpp new file mode 100644 index 000000000..301e709e4 --- /dev/null +++ b/components/sceneutil/statesetcontroller.cpp @@ -0,0 +1,31 @@ +#include "statesetcontroller.hpp" + +#include + +namespace SceneUtil +{ + + void StateSetController::operator()(osg::Node* node, osg::NodeVisitor* nv) + { + if (!mStateSets[0]) + { + // first time setup + osg::StateSet* src = node->getOrCreateStateSet(); + for (int i=0; i<2; ++i) // Using SHALLOW_COPY for StateAttributes, if users want to modify it is their responsibility to set a non-shared one first + // This can be done conveniently in user implementations of the setDefaults() method + { + mStateSets[i] = static_cast(osg::clone(src, osg::CopyOp::SHALLOW_COPY)); + setDefaults(mStateSets[i]); + } + } + + // Swap to make the StateSet in [0] writable, [1] is now the StateSet that was queued by the last frame + std::swap(mStateSets[0], mStateSets[1]); + node->setStateSet(mStateSets[0]); + + apply(mStateSets[0], nv); + + traverse(node, nv); + } + +} diff --git a/components/sceneutil/statesetcontroller.hpp b/components/sceneutil/statesetcontroller.hpp new file mode 100644 index 000000000..7c6c7e407 --- /dev/null +++ b/components/sceneutil/statesetcontroller.hpp @@ -0,0 +1,39 @@ +#ifndef OPENMW_COMPONENTS_SCENEUTIL_STATESETCONTROLLER_H +#define OPENMW_COMPONENTS_SCENEUTIL_STATESETCONTROLLER_H + +#include + +namespace SceneUtil +{ + + /// @brief Implements efficient pre-frame updating of StateSets. + /// @par With a naive update there would be race conditions when the OSG draw thread of the last frame + /// queues up a StateSet that we want to modify for the next frame. To solve this we could set the StateSet to + /// DYNAMIC data variance but that would undo all the benefits of the threading model - having the cull and draw + /// traversals run in parallel can yield up to 200% framerates. + /// @par Race conditions are prevented using a "double buffering" scheme - we have two StateSets that take turns, + /// the first StateSet is the one we can write to, the second is the one currently in use by the draw traversal of the last frame. + /// After a frame is completed the places are swapped. + /// @par Must be set as UpdateCallback on a Node. + class StateSetController : public osg::NodeCallback + { + public: + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv); + + protected: + /// Apply state - to override in derived classes + /// @note Due to the double buffering approach you *have* to apply all state + /// even if it has not changed since the last frame. + virtual void apply(osg::StateSet* stateset, osg::NodeVisitor* nv) = 0; + + /// Set default state - optionally override in derived classes + /// @par May be used e.g. to allocate StateAttributes. + virtual void setDefaults(osg::StateSet* stateset) {} + + private: + osg::ref_ptr mStateSets[2]; + }; + +} + +#endif From de2c85e0f8b0cb5e6389bae5d0562eba3a54993b Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 14 Apr 2015 16:41:06 +0200 Subject: [PATCH 0940/3725] Port nifloader to the more efficient StateSetController --- components/nifosg/controller.cpp | 70 ++++++++------------- components/nifosg/controller.hpp | 31 ++++----- components/nifosg/nifloader.cpp | 37 ++++++----- components/sceneutil/statesetcontroller.cpp | 43 +++++++++++++ components/sceneutil/statesetcontroller.hpp | 31 ++++++++- 5 files changed, 132 insertions(+), 80 deletions(-) diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index 59ba9ad4f..344cb2323 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -278,7 +278,7 @@ UVController::UVController(const Nif::NiUVData *data, std::set textureUnits } UVController::UVController(const UVController& copy, const osg::CopyOp& copyop) - : osg::Object(copy, copyop), osg::NodeCallback(copy, copyop), Controller(copy) + : osg::Object(copy, copyop), StateSetController(copy, copyop), Controller(copy) , mUTrans(copy.mUTrans) , mVTrans(copy.mVTrans) , mUScale(copy.mUScale) @@ -287,11 +287,17 @@ UVController::UVController(const UVController& copy, const osg::CopyOp& copyop) { } -void UVController::operator()(osg::Node* node, osg::NodeVisitor* nv) +void UVController::setDefaults(osg::StateSet *stateset) +{ + osg::TexMat* texMat = new osg::TexMat; + for (std::set::const_iterator it = mTextureUnits.begin(); it != mTextureUnits.end(); ++it) + stateset->setTextureAttributeAndModes(*it, texMat, osg::StateAttribute::ON); +} + +void UVController::apply(osg::StateSet* stateset, osg::NodeVisitor* nv) { if (hasInput()) { - osg::StateSet* stateset = getWritableStateSet(node); float value = getInputValue(nv); float uTrans = interpKey(mUTrans->mKeys, value, 0.0f); float vTrans = interpKey(mVTrans->mKeys, value, 0.0f); @@ -301,15 +307,13 @@ void UVController::operator()(osg::Node* node, osg::NodeVisitor* nv) osg::Matrixf mat = osg::Matrixf::scale(uScale, vScale, 1); mat.setTrans(uTrans, vTrans, 0); - osg::TexMat* texMat = new osg::TexMat; - texMat->setMatrix(mat); - - for (std::set::const_iterator it = mTextureUnits.begin(); it != mTextureUnits.end(); ++it) + // setting once is enough because all other texture units share the same TexMat (see setDefaults). + if (mTextureUnits.size()) { - stateset->setTextureAttributeAndModes(*it, texMat, osg::StateAttribute::ON); + osg::TexMat* texMat = static_cast(stateset->getTextureAttribute(*mTextureUnits.begin(), osg::StateAttribute::TEXMAT)); + texMat->setMatrix(mat); } } - traverse(node, nv); } VisController::VisController(const Nif::NiVisData *data) @@ -363,26 +367,21 @@ AlphaController::AlphaController() } AlphaController::AlphaController(const AlphaController ©, const osg::CopyOp ©op) - : osg::NodeCallback(copy, copyop), ValueInterpolator(), Controller(copy) + : StateSetController(copy, copyop), ValueInterpolator(), Controller(copy) , mData(copy.mData) { } -void AlphaController::operator () (osg::Node* node, osg::NodeVisitor* nv) +void AlphaController::apply(osg::StateSet *stateset, osg::NodeVisitor *nv) { if (hasInput()) { - osg::StateSet* stateset = getWritableStateSet(node); float value = interpKey(mData->mKeys, getInputValue(nv)); - osg::Material* mat = dynamic_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); - if (mat) - { - osg::Vec4f diffuse = mat->getDiffuse(osg::Material::FRONT_AND_BACK); - diffuse.a() = value; - mat->setDiffuse(osg::Material::FRONT_AND_BACK, diffuse); - } + osg::Material* mat = static_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); + osg::Vec4f diffuse = mat->getDiffuse(osg::Material::FRONT_AND_BACK); + diffuse.a() = value; + mat->setDiffuse(osg::Material::FRONT_AND_BACK, diffuse); } - traverse(node, nv); } MaterialColorController::MaterialColorController(const Nif::NiPosData *data) @@ -395,26 +394,21 @@ MaterialColorController::MaterialColorController() } MaterialColorController::MaterialColorController(const MaterialColorController ©, const osg::CopyOp ©op) - : osg::NodeCallback(copy, copyop), Controller(copy) + : StateSetController(copy, copyop), Controller(copy) , mData(copy.mData) { } -void MaterialColorController::operator() (osg::Node* node, osg::NodeVisitor* nv) +void MaterialColorController::apply(osg::StateSet *stateset, osg::NodeVisitor *nv) { if (hasInput()) { - osg::StateSet* stateset = getWritableStateSet(node); osg::Vec3f value = interpKey(mData->mKeys, getInputValue(nv)); - osg::Material* mat = dynamic_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); - if (mat) - { - osg::Vec4f diffuse = mat->getDiffuse(osg::Material::FRONT_AND_BACK); - diffuse.set(value.x(), value.y(), value.z(), diffuse.a()); - mat->setDiffuse(osg::Material::FRONT_AND_BACK, diffuse); - } + osg::Material* mat = static_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); + osg::Vec4f diffuse = mat->getDiffuse(osg::Material::FRONT_AND_BACK); + diffuse.set(value.x(), value.y(), value.z(), diffuse.a()); + mat->setDiffuse(osg::Material::FRONT_AND_BACK, diffuse); } - traverse(node, nv); } FlipController::FlipController(const Nif::NiFlipController *ctrl, std::vector > textures) @@ -429,7 +423,7 @@ FlipController::FlipController() } FlipController::FlipController(const FlipController ©, const osg::CopyOp ©op) - : osg::NodeCallback(copy, copyop) + : StateSetController(copy, copyop) , Controller(copy) , mTexSlot(copy.mTexSlot) , mDelta(copy.mDelta) @@ -437,15 +431,13 @@ FlipController::FlipController(const FlipController ©, const osg::CopyOp &co { } -void FlipController::operator() (osg::Node* node, osg::NodeVisitor* nv) +void FlipController::apply(osg::StateSet* stateset, osg::NodeVisitor* nv) { if (hasInput() && mDelta != 0) { - osg::StateSet* stateset = getWritableStateSet(node); int curTexture = int(getInputValue(nv) / mDelta) % mTextures.size(); stateset->setTextureAttribute(mTexSlot, mTextures[curTexture]); } - traverse(node, nv); } ParticleSystemController::ParticleSystemController(const Nif::NiParticleSystemController *ctrl) @@ -507,12 +499,4 @@ void SourcedKeyframeController::operator ()(osg::Node* node, osg::NodeVisitor* n traverse(node, nv); } -osg::StateSet *StateSetController::getWritableStateSet(osg::Node *node) -{ - osg::StateSet* orig = node->getOrCreateStateSet(); - osg::StateSet* cloned = new osg::StateSet(*orig, osg::CopyOp::SHALLOW_COPY); - node->setStateSet(cloned); - return cloned; -} - } diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index 1a90b8759..103a72046 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -8,6 +8,8 @@ #include +#include + #include #include //UVController @@ -189,19 +191,7 @@ namespace NifOsg bool mEnabled; }; - class StateSetController - { - protected: - // Clones a StateSet to make it "writable". This is to prevent race conditions when the OSG draw thread of the last frame - // queues up a StateSet that we want to modify. Note, we could also set the StateSet to DYNAMIC data variance but that would - // undo all the benefits of the threading model - having the cull and draw traversals run in parallel can yield up to 200% framerates. - // If the StateSet allocations per frame are proving too much of an overhead we could "reuse" StateSets from previous frames, - // kind of like a double buffering scheme. - osg::StateSet* getWritableStateSet(osg::Node* node); - }; - - // Note we're using NodeCallback instead of StateSet::Callback because the StateSet callback doesn't support nesting - class UVController : public osg::NodeCallback, public Controller, public StateSetController, public ValueInterpolator + class UVController : public SceneUtil::StateSetController, public Controller, public ValueInterpolator { public: UVController(); @@ -210,7 +200,8 @@ namespace NifOsg META_Object(NifOsg,UVController) - virtual void operator() (osg::Node*, osg::NodeVisitor*); + virtual void setDefaults(osg::StateSet* stateset); + virtual void apply(osg::StateSet *stateset, osg::NodeVisitor *nv); private: Nif::FloatKeyMapPtr mUTrans; @@ -237,7 +228,7 @@ namespace NifOsg virtual void operator() (osg::Node* node, osg::NodeVisitor* nv); }; - class AlphaController : public osg::NodeCallback, public Controller, public StateSetController, public ValueInterpolator + class AlphaController : public SceneUtil::StateSetController, public Controller, public ValueInterpolator { private: Nif::FloatKeyMapPtr mData; @@ -247,12 +238,12 @@ namespace NifOsg AlphaController(); AlphaController(const AlphaController& copy, const osg::CopyOp& copyop); - virtual void operator() (osg::Node* node, osg::NodeVisitor* nv); + virtual void apply(osg::StateSet* stateset, osg::NodeVisitor* nv); META_Object(NifOsg, AlphaController) }; - class MaterialColorController : public osg::NodeCallback, public Controller, public StateSetController, public ValueInterpolator + class MaterialColorController : public SceneUtil::StateSetController, public Controller, public ValueInterpolator { private: Nif::Vector3KeyMapPtr mData; @@ -264,10 +255,10 @@ namespace NifOsg META_Object(NifOsg, MaterialColorController) - virtual void operator() (osg::Node* node, osg::NodeVisitor* nv); + virtual void apply(osg::StateSet* stateset, osg::NodeVisitor* nv); }; - class FlipController : public osg::NodeCallback, public Controller, public StateSetController + class FlipController : public SceneUtil::StateSetController, public Controller { private: int mTexSlot; @@ -281,7 +272,7 @@ namespace NifOsg META_Object(NifOsg, FlipController) - virtual void operator() (osg::Node* node, osg::NodeVisitor* nv); + virtual void apply(osg::StateSet *stateset, osg::NodeVisitor *nv); }; class ParticleSystemController : public osg::NodeCallback, public Controller diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index a85847351..8dc286a92 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -719,13 +719,13 @@ namespace NifOsg return skel; } - static void applyNodeProperties(const Nif::Node *nifNode, osg::Node *applyTo, Resource::TextureManager* textureManager, std::map& boundTextures, int animflags) + static void applyNodeProperties(const Nif::Node *nifNode, osg::Node *applyTo, SceneUtil::CompositeStateSetController* composite, Resource::TextureManager* textureManager, std::map& boundTextures, int animflags) { const Nif::PropertyList& props = nifNode->props; for (size_t i = 0; i setNodeMask(0x1); } - applyNodeProperties(nifNode, transformNode, textureManager, boundTextures, animflags); + osg::ref_ptr composite = new SceneUtil::CompositeStateSetController; + + applyNodeProperties(nifNode, transformNode, composite, textureManager, boundTextures, animflags); if (nifNode->recType == Nif::RC_NiTriShape && !skipMeshes) { @@ -836,9 +838,12 @@ namespace NifOsg handleSkinnedTriShape(triShape, transformNode, boundTextures, animflags); if (!nifNode->controller.empty()) - handleMeshControllers(nifNode, transformNode, boundTextures, animflags); + handleMeshControllers(nifNode, composite, boundTextures, animflags); } + if (composite->getNumControllers() > 0) + transformNode->addUpdateCallback(composite); + if(nifNode->recType == Nif::RC_NiAutoNormalParticles || nifNode->recType == Nif::RC_NiRotatingParticles) handleParticleSystem(nifNode, transformNode, animflags, particleflags, rootNode); @@ -866,7 +871,7 @@ namespace NifOsg return transformNode; } - static void handleMeshControllers(const Nif::Node *nifNode, osg::MatrixTransform *transformNode, const std::map &boundTextures, int animflags) + static void handleMeshControllers(const Nif::Node *nifNode, SceneUtil::CompositeStateSetController* composite, const std::map &boundTextures, int animflags) { for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next) { @@ -881,8 +886,7 @@ namespace NifOsg osg::ref_ptr ctrl = new UVController(uvctrl->data.getPtr(), texUnits); setupController(uvctrl, ctrl, animflags); - - transformNode->addUpdateCallback(ctrl); + composite->addController(ctrl); } } } @@ -915,8 +919,9 @@ namespace NifOsg } } - static void handleMaterialControllers(const Nif::Property *materialProperty, osg::Node* node, osg::StateSet *stateset, int animflags) + static void handleMaterialControllers(const Nif::Property *materialProperty, osg::Node* node, int animflags) { + osg::ref_ptr composite = new SceneUtil::CompositeStateSetController; for (Nif::ControllerPtr ctrl = materialProperty->controller; !ctrl.empty(); ctrl = ctrl->next) { if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active)) @@ -926,21 +931,23 @@ namespace NifOsg const Nif::NiAlphaController* alphactrl = static_cast(ctrl.getPtr()); osg::ref_ptr ctrl(new AlphaController(alphactrl->data.getPtr())); setupController(alphactrl, ctrl, animflags); - node->addUpdateCallback(ctrl); + composite->addController(ctrl); } else if (ctrl->recType == Nif::RC_NiMaterialColorController) { const Nif::NiMaterialColorController* matctrl = static_cast(ctrl.getPtr()); osg::ref_ptr ctrl(new MaterialColorController(matctrl->data.getPtr())); setupController(matctrl, ctrl, animflags); - node->addUpdateCallback(ctrl); + composite->addController(ctrl); } else std::cerr << "Unexpected material controller " << ctrl->recType << std::endl; } + if (composite->getNumControllers() > 0) + node->addUpdateCallback(composite); } - static void handleTextureControllers(const Nif::Property *texProperty, osg::Node* node, Resource::TextureManager* textureManager, osg::StateSet *stateset, int animflags) + static void handleTextureControllers(const Nif::Property *texProperty, SceneUtil::CompositeStateSetController* composite, Resource::TextureManager* textureManager, osg::StateSet *stateset, int animflags) { for (Nif::ControllerPtr ctrl = texProperty->controller; !ctrl.empty(); ctrl = ctrl->next) { @@ -972,7 +979,7 @@ namespace NifOsg } osg::ref_ptr callback(new FlipController(flipctrl, textures)); setupController(ctrl.getPtr(), callback, animflags); - node->addUpdateCallback(callback); + composite->addController(callback); } else std::cerr << "Unexpected texture controller " << ctrl->recName << std::endl; @@ -1419,7 +1426,7 @@ namespace NifOsg static void handleProperty(const Nif::Property *property, - osg::Node *node, Resource::TextureManager* textureManager, std::map& boundTextures, int animflags) + osg::Node *node, SceneUtil::CompositeStateSetController* composite, Resource::TextureManager* textureManager, std::map& boundTextures, int animflags) { osg::StateSet* stateset = node->getOrCreateStateSet(); @@ -1594,7 +1601,7 @@ namespace NifOsg stateset->setTextureAttributeAndModes(i, new osg::Texture2D, osg::StateAttribute::OFF); boundTextures.erase(i); } - handleTextureControllers(texprop, node, textureManager, stateset, animflags); + handleTextureControllers(texprop, composite, textureManager, stateset, animflags); } break; } @@ -1646,7 +1653,7 @@ namespace NifOsg mat->setShininess(osg::Material::FRONT_AND_BACK, matprop->data.glossiness); if (!matprop->controller.empty()) - handleMaterialControllers(matprop, node, stateset, animflags); + handleMaterialControllers(matprop, node, animflags); break; } diff --git a/components/sceneutil/statesetcontroller.cpp b/components/sceneutil/statesetcontroller.cpp index 301e709e4..079eaf6aa 100644 --- a/components/sceneutil/statesetcontroller.cpp +++ b/components/sceneutil/statesetcontroller.cpp @@ -28,4 +28,47 @@ namespace SceneUtil traverse(node, nv); } + StateSetController::StateSetController() + { + } + + StateSetController::StateSetController(const StateSetController ©, const osg::CopyOp ©op) + : osg::NodeCallback(copy, copyop) + { + } + + // ---------------------------------------------------------------------------------- + + void CompositeStateSetController::apply(osg::StateSet *stateset, osg::NodeVisitor *nv) + { + for (unsigned int i=0; iapply(stateset, nv); + } + + void CompositeStateSetController::setDefaults(osg::StateSet *stateset) + { + for (unsigned int i=0; isetDefaults(stateset); + } + + CompositeStateSetController::CompositeStateSetController() + { + } + + CompositeStateSetController::CompositeStateSetController(const CompositeStateSetController ©, const osg::CopyOp ©op) + : StateSetController(copy, copyop) + , mCtrls(copy.mCtrls) + { + } + + unsigned int CompositeStateSetController::getNumControllers() + { + return mCtrls.size(); + } + + void CompositeStateSetController::addController(StateSetController *ctrl) + { + mCtrls.push_back(ctrl); + } + } diff --git a/components/sceneutil/statesetcontroller.hpp b/components/sceneutil/statesetcontroller.hpp index 7c6c7e407..e34332e5f 100644 --- a/components/sceneutil/statesetcontroller.hpp +++ b/components/sceneutil/statesetcontroller.hpp @@ -15,16 +15,21 @@ namespace SceneUtil /// the first StateSet is the one we can write to, the second is the one currently in use by the draw traversal of the last frame. /// After a frame is completed the places are swapped. /// @par Must be set as UpdateCallback on a Node. + /// @note Do not add multiple StateSetControllers on the same Node as they will conflict - instead use the CompositeStateSetController. class StateSetController : public osg::NodeCallback { public: + StateSetController(); + StateSetController(const StateSetController& copy, const osg::CopyOp& copyop); + + META_Object(SceneUtil, StateSetController) + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv); - protected: /// Apply state - to override in derived classes /// @note Due to the double buffering approach you *have* to apply all state /// even if it has not changed since the last frame. - virtual void apply(osg::StateSet* stateset, osg::NodeVisitor* nv) = 0; + virtual void apply(osg::StateSet* stateset, osg::NodeVisitor* nv) {} /// Set default state - optionally override in derived classes /// @par May be used e.g. to allocate StateAttributes. @@ -34,6 +39,28 @@ namespace SceneUtil osg::ref_ptr mStateSets[2]; }; + /// @brief A variant of the StateSetController that can be made up of multiple controllers all controlling the same target. + class CompositeStateSetController : public StateSetController + { + public: + CompositeStateSetController(); + CompositeStateSetController(const CompositeStateSetController& copy, const osg::CopyOp& copyop); + + META_Object(SceneUtil, CompositeStateSetController) + + unsigned int getNumControllers(); + + void addController(StateSetController* ctrl); + + virtual void apply(osg::StateSet* stateset, osg::NodeVisitor* nv); + + protected: + + virtual void setDefaults(osg::StateSet *stateset); + + std::vector > mCtrls; + }; + } #endif From c516e897ee7265c59340305e7ae115c79a449e2f Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 14 Apr 2015 17:29:12 +0200 Subject: [PATCH 0941/3725] Move Controller base classes to SceneUtil, add visitor to assign ControllerSources --- apps/openmw/mwrender/animation.hpp | 2 +- apps/openmw/mwrender/renderingmanager.cpp | 4 +- apps/openmw/mwrender/sky.cpp | 12 +-- components/CMakeLists.txt | 2 +- components/nifosg/controller.cpp | 31 +------ components/nifosg/controller.hpp | 51 +++-------- components/nifosg/nifloader.cpp | 21 +++-- components/sceneutil/controller.cpp | 86 +++++++++++++++++++ components/sceneutil/controller.hpp | 64 ++++++++++++++ ...esetcontroller.cpp => statesetupdater.cpp} | 30 ++++--- ...esetcontroller.hpp => statesetupdater.hpp} | 23 ++--- 11 files changed, 211 insertions(+), 115 deletions(-) create mode 100644 components/sceneutil/controller.cpp create mode 100644 components/sceneutil/controller.hpp rename components/sceneutil/{statesetcontroller.cpp => statesetupdater.cpp} (58%) rename components/sceneutil/{statesetcontroller.hpp => statesetupdater.hpp} (77%) diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index cbded364a..754adec92 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -74,7 +74,7 @@ protected: virtual void setValue(Ogre::Real value); }; - class NullAnimationTime : public NifOsg::ControllerSource + class NullAnimationTime : public SceneUtil::ControllerSource { public: virtual float getValue(osg::NodeVisitor *nv) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index e9a5d302c..ba34cf303 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -13,7 +13,7 @@ #include -#include +#include #include @@ -22,7 +22,7 @@ namespace MWRender { - class StateUpdater : public SceneUtil::StateSetController + class StateUpdater : public SceneUtil::StateSetUpdater { public: virtual void setDefaults(osg::StateSet *stateset) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index be702a221..a4fd17172 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -24,7 +24,7 @@ #include #include -#include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -37,14 +37,6 @@ namespace { - osg::StateSet* getWritableStateSet(osg::Node* node) - { - osg::StateSet* stateset = node->getOrCreateStateSet(); - osg::ref_ptr cloned = static_cast(stateset->clone(osg::CopyOp::SHALLOW_COPY)); - node->setStateSet(cloned); - return cloned; - } - osg::ref_ptr createAlphaTrackingUnlitMaterial() { osg::ref_ptr mat = new osg::Material; @@ -95,7 +87,7 @@ namespace namespace MWRender { -class AtmosphereUpdater : public SceneUtil::StateSetController +class AtmosphereUpdater : public SceneUtil::StateSetUpdater { public: void setEmissionColor(osg::Vec4f emissionColor) diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 6b1c01644..f61724eeb 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -39,7 +39,7 @@ add_component_dir (resource ) add_component_dir (sceneutil - clone attach lightmanager visitor util statesetcontroller + clone attach lightmanager visitor util statesetupdater controller ) add_component_dir (nif diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index 344cb2323..ce004dc79 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -64,15 +64,6 @@ float ControllerFunction::calculate(float value) } } -FrameTimeSource::FrameTimeSource() -{ -} - -float FrameTimeSource::getValue(osg::NodeVisitor *nv) -{ - return nv->getFrameStamp()->getSimulationTime(); -} - KeyframeController::KeyframeController() { } @@ -207,20 +198,6 @@ void KeyframeController::operator() (osg::Node* node, osg::NodeVisitor* nv) traverse(node, nv); } -Controller::Controller() -{ -} - -bool Controller::hasInput() const -{ - return mSource.get() != NULL; -} - -float Controller::getInputValue(osg::NodeVisitor* nv) -{ - return mFunction->calculate(mSource->getValue(nv)); -} - GeomMorpherController::GeomMorpherController() { } @@ -278,7 +255,7 @@ UVController::UVController(const Nif::NiUVData *data, std::set textureUnits } UVController::UVController(const UVController& copy, const osg::CopyOp& copyop) - : osg::Object(copy, copyop), StateSetController(copy, copyop), Controller(copy) + : osg::Object(copy, copyop), StateSetUpdater(copy, copyop), Controller(copy) , mUTrans(copy.mUTrans) , mVTrans(copy.mVTrans) , mUScale(copy.mUScale) @@ -367,7 +344,7 @@ AlphaController::AlphaController() } AlphaController::AlphaController(const AlphaController ©, const osg::CopyOp ©op) - : StateSetController(copy, copyop), ValueInterpolator(), Controller(copy) + : StateSetUpdater(copy, copyop), ValueInterpolator(), Controller(copy) , mData(copy.mData) { } @@ -394,7 +371,7 @@ MaterialColorController::MaterialColorController() } MaterialColorController::MaterialColorController(const MaterialColorController ©, const osg::CopyOp ©op) - : StateSetController(copy, copyop), Controller(copy) + : StateSetUpdater(copy, copyop), Controller(copy) , mData(copy.mData) { } @@ -423,7 +400,7 @@ FlipController::FlipController() } FlipController::FlipController(const FlipController ©, const osg::CopyOp ©op) - : StateSetController(copy, copyop) + : StateSetUpdater(copy, copyop) , Controller(copy) , mTexSlot(copy.mTexSlot) , mDelta(copy.mDelta) diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index 103a72046..3136b3118 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -8,7 +8,8 @@ #include -#include +#include +#include #include @@ -43,7 +44,6 @@ namespace osgAnimation namespace NifOsg { - // FIXME: Should not be here. We might also want to use this for non-NIF model formats class ValueInterpolator { protected: @@ -76,8 +76,7 @@ namespace NifOsg } }; - // FIXME: Should not be here. We might also want to use this for non-NIF model formats - class ControllerFunction + class ControllerFunction : public SceneUtil::ControllerFunction { private: float mFrequency; @@ -98,35 +97,7 @@ namespace NifOsg float calculate(float value); }; - class ControllerSource - { - public: - virtual float getValue(osg::NodeVisitor* nv) = 0; - }; - - class FrameTimeSource : public ControllerSource - { - public: - FrameTimeSource(); - virtual float getValue(osg::NodeVisitor* nv); - }; - - class Controller - { - public: - Controller(); - - bool hasInput() const; - - float getInputValue(osg::NodeVisitor* nv); - - boost::shared_ptr mSource; - - // The source value gets passed through this function before it's passed on to the DestValue. - boost::shared_ptr mFunction; - }; - - class GeomMorpherController : public osg::Drawable::UpdateCallback, public Controller, public ValueInterpolator + class GeomMorpherController : public osg::Drawable::UpdateCallback, public SceneUtil::Controller, public ValueInterpolator { public: GeomMorpherController(const Nif::NiMorphData* data); @@ -141,7 +112,7 @@ namespace NifOsg std::vector mKeyFrames; }; - class KeyframeController : public osg::NodeCallback, public Controller, public ValueInterpolator + class KeyframeController : public osg::NodeCallback, public SceneUtil::Controller, public ValueInterpolator { public: KeyframeController(const Nif::NiKeyframeData *data); @@ -191,7 +162,7 @@ namespace NifOsg bool mEnabled; }; - class UVController : public SceneUtil::StateSetController, public Controller, public ValueInterpolator + class UVController : public SceneUtil::StateSetUpdater, public SceneUtil::Controller, public ValueInterpolator { public: UVController(); @@ -211,7 +182,7 @@ namespace NifOsg std::set mTextureUnits; }; - class VisController : public osg::NodeCallback, public Controller + class VisController : public osg::NodeCallback, public SceneUtil::Controller { private: std::vector mData; @@ -228,7 +199,7 @@ namespace NifOsg virtual void operator() (osg::Node* node, osg::NodeVisitor* nv); }; - class AlphaController : public SceneUtil::StateSetController, public Controller, public ValueInterpolator + class AlphaController : public SceneUtil::StateSetUpdater, public SceneUtil::Controller, public ValueInterpolator { private: Nif::FloatKeyMapPtr mData; @@ -243,7 +214,7 @@ namespace NifOsg META_Object(NifOsg, AlphaController) }; - class MaterialColorController : public SceneUtil::StateSetController, public Controller, public ValueInterpolator + class MaterialColorController : public SceneUtil::StateSetUpdater, public SceneUtil::Controller, public ValueInterpolator { private: Nif::Vector3KeyMapPtr mData; @@ -258,7 +229,7 @@ namespace NifOsg virtual void apply(osg::StateSet* stateset, osg::NodeVisitor* nv); }; - class FlipController : public SceneUtil::StateSetController, public Controller + class FlipController : public SceneUtil::StateSetUpdater, public SceneUtil::Controller { private: int mTexSlot; @@ -275,7 +246,7 @@ namespace NifOsg virtual void apply(osg::StateSet *stateset, osg::NodeVisitor *nv); }; - class ParticleSystemController : public osg::NodeCallback, public Controller + class ParticleSystemController : public osg::NodeCallback, public SceneUtil::Controller { public: ParticleSystemController(const Nif::NiParticleSystemController* ctrl); diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 8dc286a92..1d7eaba2c 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -719,7 +719,7 @@ namespace NifOsg return skel; } - static void applyNodeProperties(const Nif::Node *nifNode, osg::Node *applyTo, SceneUtil::CompositeStateSetController* composite, Resource::TextureManager* textureManager, std::map& boundTextures, int animflags) + static void applyNodeProperties(const Nif::Node *nifNode, osg::Node *applyTo, SceneUtil::CompositeStateSetUpdater* composite, Resource::TextureManager* textureManager, std::map& boundTextures, int animflags) { const Nif::PropertyList& props = nifNode->props; for (size_t i = 0; i mSource = boost::shared_ptr(new FrameTimeSource); + bool autoPlay = animflags & Nif::NiNode::AnimFlag_AutoPlay; + if (autoPlay) + toSetup->mSource = boost::shared_ptr(new SceneUtil::FrameTimeSource); toSetup->mFunction = boost::shared_ptr(new ControllerFunction(ctrl)); } @@ -825,7 +824,7 @@ namespace NifOsg transformNode->setNodeMask(0x1); } - osg::ref_ptr composite = new SceneUtil::CompositeStateSetController; + osg::ref_ptr composite = new SceneUtil::CompositeStateSetUpdater; applyNodeProperties(nifNode, transformNode, composite, textureManager, boundTextures, animflags); @@ -871,7 +870,7 @@ namespace NifOsg return transformNode; } - static void handleMeshControllers(const Nif::Node *nifNode, SceneUtil::CompositeStateSetController* composite, const std::map &boundTextures, int animflags) + static void handleMeshControllers(const Nif::Node *nifNode, SceneUtil::CompositeStateSetUpdater* composite, const std::map &boundTextures, int animflags) { for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next) { @@ -921,7 +920,7 @@ namespace NifOsg static void handleMaterialControllers(const Nif::Property *materialProperty, osg::Node* node, int animflags) { - osg::ref_ptr composite = new SceneUtil::CompositeStateSetController; + osg::ref_ptr composite = new SceneUtil::CompositeStateSetUpdater; for (Nif::ControllerPtr ctrl = materialProperty->controller; !ctrl.empty(); ctrl = ctrl->next) { if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active)) @@ -947,7 +946,7 @@ namespace NifOsg node->addUpdateCallback(composite); } - static void handleTextureControllers(const Nif::Property *texProperty, SceneUtil::CompositeStateSetController* composite, Resource::TextureManager* textureManager, osg::StateSet *stateset, int animflags) + static void handleTextureControllers(const Nif::Property *texProperty, SceneUtil::CompositeStateSetUpdater* composite, Resource::TextureManager* textureManager, osg::StateSet *stateset, int animflags) { for (Nif::ControllerPtr ctrl = texProperty->controller; !ctrl.empty(); ctrl = ctrl->next) { @@ -1426,7 +1425,7 @@ namespace NifOsg static void handleProperty(const Nif::Property *property, - osg::Node *node, SceneUtil::CompositeStateSetController* composite, Resource::TextureManager* textureManager, std::map& boundTextures, int animflags) + osg::Node *node, SceneUtil::CompositeStateSetUpdater* composite, Resource::TextureManager* textureManager, std::map& boundTextures, int animflags) { osg::StateSet* stateset = node->getOrCreateStateSet(); diff --git a/components/sceneutil/controller.cpp b/components/sceneutil/controller.cpp new file mode 100644 index 000000000..565d48672 --- /dev/null +++ b/components/sceneutil/controller.cpp @@ -0,0 +1,86 @@ +#include "controller.hpp" + +#include "statesetupdater.hpp" + +#include +#include + +namespace SceneUtil +{ + + + Controller::Controller() + { + } + + bool Controller::hasInput() const + { + return mSource.get() != NULL; + } + + float Controller::getInputValue(osg::NodeVisitor* nv) + { + return mFunction->calculate(mSource->getValue(nv)); + } + + FrameTimeSource::FrameTimeSource() + { + } + + float FrameTimeSource::getValue(osg::NodeVisitor *nv) + { + return nv->getFrameStamp()->getSimulationTime(); + } + + AssignControllerSourcesVisitor::AssignControllerSourcesVisitor() + : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) + { + } + + AssignControllerSourcesVisitor::AssignControllerSourcesVisitor(boost::shared_ptr toAssign) + : mToAssign(toAssign) + , osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) + { + } + + void AssignControllerSourcesVisitor::apply(osg::Node &node) + { + osg::NodeCallback* callback = node.getUpdateCallback(); + while (callback) + { + if (Controller* ctrl = dynamic_cast(callback)) + assign(node, *ctrl); + if (CompositeStateSetUpdater* composite = dynamic_cast(callback)) + { + for (unsigned int i=0; igetNumControllers(); ++i) + { + StateSetUpdater* statesetcontroller = composite->getController(i); + if (Controller* ctrl = dynamic_cast(statesetcontroller)) + assign(node, *ctrl); + } + } + + callback = callback->getNestedCallback(); + } + + traverse(node); + } + + void AssignControllerSourcesVisitor::apply(osg::Geode &geode) + { + for (unsigned int i=0; igetUpdateCallback(); + if (Controller* ctrl = dynamic_cast(callback)) + assign(geode, *ctrl); + } + } + + void AssignControllerSourcesVisitor::assign(osg::Node&, Controller &ctrl) + { + if (!ctrl.mSource.get()) + ctrl.mSource = mToAssign; + } + +} diff --git a/components/sceneutil/controller.hpp b/components/sceneutil/controller.hpp new file mode 100644 index 000000000..de73c7e80 --- /dev/null +++ b/components/sceneutil/controller.hpp @@ -0,0 +1,64 @@ +#ifndef OPENMW_COMPONENTS_SCENEUTIL_CONTROLLER_H +#define OPENMW_COMPONENTS_SCENEUTIL_CONTROLLER_H + +#include + +#include + +namespace SceneUtil +{ + + class ControllerSource + { + public: + virtual float getValue(osg::NodeVisitor* nv) = 0; + }; + + class FrameTimeSource : public ControllerSource + { + public: + FrameTimeSource(); + virtual float getValue(osg::NodeVisitor* nv); + }; + + class ControllerFunction + { + public: + virtual float calculate(float input) = 0; + }; + + class Controller + { + public: + Controller(); + + bool hasInput() const; + + float getInputValue(osg::NodeVisitor* nv); + + boost::shared_ptr mSource; + + // The source value gets passed through this function before it's passed on to the DestValue. + boost::shared_ptr mFunction; + }; + + class AssignControllerSourcesVisitor : public osg::NodeVisitor + { + public: + AssignControllerSourcesVisitor(); + AssignControllerSourcesVisitor(boost::shared_ptr toAssign); + + virtual void apply(osg::Node& node); + virtual void apply(osg::Geode& geode); + + /// Assign the wanted ControllerSource. May be overriden in derived classes. + /// By default assigns the ControllerSource passed to the constructor of this class if no ControllerSource is assigned to that controller yet. + virtual void assign(osg::Node& node, Controller& ctrl); + + private: + boost::shared_ptr mToAssign; + }; + +} + +#endif diff --git a/components/sceneutil/statesetcontroller.cpp b/components/sceneutil/statesetupdater.cpp similarity index 58% rename from components/sceneutil/statesetcontroller.cpp rename to components/sceneutil/statesetupdater.cpp index 079eaf6aa..8ed229aa6 100644 --- a/components/sceneutil/statesetcontroller.cpp +++ b/components/sceneutil/statesetupdater.cpp @@ -1,11 +1,11 @@ -#include "statesetcontroller.hpp" +#include "statesetupdater.hpp" #include namespace SceneUtil { - void StateSetController::operator()(osg::Node* node, osg::NodeVisitor* nv) + void StateSetUpdater::operator()(osg::Node* node, osg::NodeVisitor* nv) { if (!mStateSets[0]) { @@ -28,45 +28,51 @@ namespace SceneUtil traverse(node, nv); } - StateSetController::StateSetController() + StateSetUpdater::StateSetUpdater() { } - StateSetController::StateSetController(const StateSetController ©, const osg::CopyOp ©op) + StateSetUpdater::StateSetUpdater(const StateSetUpdater ©, const osg::CopyOp ©op) : osg::NodeCallback(copy, copyop) { } // ---------------------------------------------------------------------------------- - void CompositeStateSetController::apply(osg::StateSet *stateset, osg::NodeVisitor *nv) + void CompositeStateSetUpdater::apply(osg::StateSet *stateset, osg::NodeVisitor *nv) { for (unsigned int i=0; iapply(stateset, nv); } - void CompositeStateSetController::setDefaults(osg::StateSet *stateset) + void CompositeStateSetUpdater::setDefaults(osg::StateSet *stateset) { for (unsigned int i=0; isetDefaults(stateset); } - CompositeStateSetController::CompositeStateSetController() + CompositeStateSetUpdater::CompositeStateSetUpdater() { } - CompositeStateSetController::CompositeStateSetController(const CompositeStateSetController ©, const osg::CopyOp ©op) - : StateSetController(copy, copyop) - , mCtrls(copy.mCtrls) + CompositeStateSetUpdater::CompositeStateSetUpdater(const CompositeStateSetUpdater ©, const osg::CopyOp ©op) + : StateSetUpdater(copy, copyop) { + for (unsigned int i=0; i(osg::clone(copy.mCtrls[i].get(), copyop))); } - unsigned int CompositeStateSetController::getNumControllers() + unsigned int CompositeStateSetUpdater::getNumControllers() { return mCtrls.size(); } - void CompositeStateSetController::addController(StateSetController *ctrl) + StateSetUpdater* CompositeStateSetUpdater::getController(int i) + { + return mCtrls[i]; + } + + void CompositeStateSetUpdater::addController(StateSetUpdater *ctrl) { mCtrls.push_back(ctrl); } diff --git a/components/sceneutil/statesetcontroller.hpp b/components/sceneutil/statesetupdater.hpp similarity index 77% rename from components/sceneutil/statesetcontroller.hpp rename to components/sceneutil/statesetupdater.hpp index e34332e5f..56f832a08 100644 --- a/components/sceneutil/statesetcontroller.hpp +++ b/components/sceneutil/statesetupdater.hpp @@ -15,14 +15,14 @@ namespace SceneUtil /// the first StateSet is the one we can write to, the second is the one currently in use by the draw traversal of the last frame. /// After a frame is completed the places are swapped. /// @par Must be set as UpdateCallback on a Node. - /// @note Do not add multiple StateSetControllers on the same Node as they will conflict - instead use the CompositeStateSetController. - class StateSetController : public osg::NodeCallback + /// @note Do not add multiple StateSetControllers on the same Node as they will conflict - instead use the CompositeStateSetUpdater. + class StateSetUpdater : public osg::NodeCallback { public: - StateSetController(); - StateSetController(const StateSetController& copy, const osg::CopyOp& copyop); + StateSetUpdater(); + StateSetUpdater(const StateSetUpdater& copy, const osg::CopyOp& copyop); - META_Object(SceneUtil, StateSetController) + META_Object(SceneUtil, StateSetUpdater) virtual void operator()(osg::Node* node, osg::NodeVisitor* nv); @@ -40,17 +40,18 @@ namespace SceneUtil }; /// @brief A variant of the StateSetController that can be made up of multiple controllers all controlling the same target. - class CompositeStateSetController : public StateSetController + class CompositeStateSetUpdater : public StateSetUpdater { public: - CompositeStateSetController(); - CompositeStateSetController(const CompositeStateSetController& copy, const osg::CopyOp& copyop); + CompositeStateSetUpdater(); + CompositeStateSetUpdater(const CompositeStateSetUpdater& copy, const osg::CopyOp& copyop); - META_Object(SceneUtil, CompositeStateSetController) + META_Object(SceneUtil, CompositeStateSetUpdater) unsigned int getNumControllers(); + StateSetUpdater* getController(int i); - void addController(StateSetController* ctrl); + void addController(StateSetUpdater* ctrl); virtual void apply(osg::StateSet* stateset, osg::NodeVisitor* nv); @@ -58,7 +59,7 @@ namespace SceneUtil virtual void setDefaults(osg::StateSet *stateset); - std::vector > mCtrls; + std::vector > mCtrls; }; } From f7da9796692e14c79632cb85fa75a90b082cd863 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 14 Apr 2015 18:56:11 +0200 Subject: [PATCH 0942/3725] Add FrameSwitch (geometry "double buffering") for efficient updates of RigGeometry & MorphGeometry --- components/nifosg/nifloader.cpp | 56 +++++++++++++++++++++++++++++++-- 1 file changed, 54 insertions(+), 2 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 1d7eaba2c..b61e3824b 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -176,6 +176,36 @@ namespace collectMaterialProperties(nifNode->parent, out); } + class FrameSwitch : public osg::Group + { + public: + FrameSwitch() + { + } + + FrameSwitch(const FrameSwitch& copy, const osg::CopyOp& copyop) + : osg::Group(copy, copyop) + { + } + + META_Object(NifOsg, FrameSwitch) + + virtual void traverse(osg::NodeVisitor& nv) + { + const osg::FrameStamp* stamp = nv.getFrameStamp(); + if (!stamp || nv.getTraversalMode() != osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN) + osg::Group::traverse(nv); + else + { + for (unsigned int i=0; igetFrameNumber()%2) + getChild(i)->accept(nv); + } + } + } + }; + // NodeCallback used to update the bone matrices in skeleton space as needed for skinning. // Must be set on a Bone. class UpdateBone : public osg::NodeCallback @@ -1306,7 +1336,19 @@ namespace NifOsg geode->addDrawable(geometry); - parentNode->addChild(geode); + if (geometry->getDataVariance() == osg::Object::DYNAMIC) + { + // Add a copy, we will alternate between the two copies every other frame using the FrameSwitch + // This is so we can set the DataVariance as STATIC, giving a huge performance boost + geometry->setDataVariance(osg::Object::STATIC); + osg::ref_ptr geode2 = static_cast(osg::clone(geode.get(), osg::CopyOp::DEEP_COPY_NODES|osg::CopyOp::DEEP_COPY_DRAWABLES)); + osg::ref_ptr frameswitch = new FrameSwitch; + frameswitch->addChild(geode); + frameswitch->addChild(geode2); + parentNode->addChild(frameswitch); + } + else + parentNode->addChild(geode); } static osg::ref_ptr handleMorphGeometry(const Nif::NiGeomMorpherController* morpher) @@ -1419,7 +1461,17 @@ namespace NifOsg geode->addDrawable(rig); geode->addUpdateCallback(new DirtyBoundCallback); - trans->addChild(geode); + // Add a copy, we will alternate between the two copies every other frame using the FrameSwitch + // This is so we can set the DataVariance as STATIC, giving a huge performance boost + rig->setDataVariance(osg::Object::STATIC); + osg::Geode* geode2 = static_cast(osg::clone(geode.get(), osg::CopyOp::DEEP_COPY_NODES| + osg::CopyOp::DEEP_COPY_DRAWABLES)); + + osg::ref_ptr frameswitch = new FrameSwitch; + frameswitch->addChild(geode); + frameswitch->addChild(geode2); + + trans->addChild(frameswitch); parentNode->addChild(trans); } From 13a1ba0aab499d185b5e275082d6234556bdde4d Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 15 Apr 2015 18:50:50 +0200 Subject: [PATCH 0943/3725] Moon rendering --- apps/openmw/engine.cpp | 6 - apps/openmw/mwrender/sky.cpp | 363 ++++++++++++++++++++++++++++---- apps/openmw/mwrender/sky.hpp | 13 +- apps/openmw/mwworld/weather.cpp | 25 ++- 4 files changed, 342 insertions(+), 65 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 59504048a..f6f2ba9bb 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -6,8 +6,6 @@ #include #include -#include - #include #include @@ -494,11 +492,7 @@ void OMW::Engine::go() mViewer.addEventHandler(new osgViewer::StatsHandler); osg::Timer timer; - //osgUtil::IncrementalCompileOperation* ico = new osgUtil::IncrementalCompileOperation; - //ico->compileAllForNextFrame(1); - //mViewer.setRealizeOperation(ico); mViewer.realize(); - std::cout << "realize took " << timer.time_m() << std::endl; osg::Timer frameTimer; while (!mViewer.done()) { diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index a4fd17172..1ac7ca10b 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -12,6 +12,9 @@ #include +#include +#include + #include #include @@ -57,7 +60,7 @@ namespace return mat; } - osg::ref_ptr createTexturedQuad() + osg::ref_ptr createTexturedQuad(int numUvSets=1) { osg::ref_ptr geom = new osg::Geometry; @@ -75,7 +78,8 @@ namespace texcoords->push_back(osg::Vec2f(1, 1)); texcoords->push_back(osg::Vec2f(1, 0)); - geom->setTexCoordArray(0, texcoords, osg::Array::BIND_PER_VERTEX); + for (int i=0; isetTexCoordArray(i, texcoords, osg::Array::BIND_PER_VERTEX); geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,4)); @@ -111,6 +115,52 @@ private: osg::Vec4f mEmissionColor; }; +class CloudUpdater : public SceneUtil::StateSetUpdater +{ +public: + void setAnimationTimer(float timer); + + void setTexture(osg::ref_ptr texture) + { + mTexture = texture; + } + void setEmissionColor(osg::Vec4f emissionColor) + { + mEmissionColor = emissionColor; + } + void setOpacity(float opacity) + { + mOpacity = opacity; + } + +protected: + virtual void setDefaults(osg::StateSet *stateset) + { + stateset->setTextureAttributeAndModes(0, new osg::TexMat, osg::StateAttribute::ON); + stateset->setAttribute(createAlphaTrackingUnlitMaterial(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + } + + virtual void apply(osg::StateSet *stateset, osg::NodeVisitor *nv) + { + mAnimationTimer = nv->getFrameStamp()->getSimulationTime()*0.05; + osg::TexMat* texMat = static_cast(stateset->getTextureAttribute(0, osg::StateAttribute::TEXMAT)); + texMat->setMatrix(osg::Matrix::translate(osg::Vec3f(mAnimationTimer, mAnimationTimer, 0.f))); + + stateset->setTextureAttributeAndModes(0, mTexture, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + + osg::Material* mat = static_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); + mat->setEmission(osg::Material::FRONT_AND_BACK, mEmissionColor); + + // FIXME: handle opacity, will have to resort to either shaders or multitexturing? diffuse alpha is in use by the vertex colors already + } + +private: + float mAnimationTimer; + osg::ref_ptr mTexture; + osg::Vec4f mEmissionColor; + float mOpacity; +}; + /// Transform that removes the eyepoint of the modelview matrix, /// i.e. its children are positioned relative to the camera. class CameraRelativeTransform : public osg::Transform @@ -118,6 +168,10 @@ class CameraRelativeTransform : public osg::Transform public: CameraRelativeTransform() { + // Culling works in node-local space, not in camera space, so we can't cull this node correctly + // That's not a problem though, children of this node can be culled just fine + // Just make sure you do not place a CameraRelativeTransform deep in the scene graph + setCullingActive(false); } CameraRelativeTransform(const CameraRelativeTransform& copy, const osg::CopyOp& copyop) @@ -211,6 +265,219 @@ private: int mMeshType; }; +class CelestialBody +{ +public: + CelestialBody(osg::Group* parentNode, Resource::SceneManager* sceneManager, float scaleFactor = 1.f, int numUvSets=1) + : mSceneManager(sceneManager) + { + mGeode = new osg::Geode; + osg::ref_ptr geom = createTexturedQuad(numUvSets); + mGeode->addDrawable(geom); + mTransform = new osg::PositionAttitudeTransform; + mTransform->setScale(osg::Vec3f(450,450,450) * scaleFactor); + mTransform->addChild(mGeode); + + parentNode->addChild(mTransform); + } + + void setDirection(const osg::Vec3f& direction) + { + mTransform->setPosition(direction*1000.f); + + osg::Quat quat; + quat.makeRotate(osg::Vec3f(0,0,1), direction); + mTransform->setAttitude(quat); + } + + void setVisible(bool visible) + { + mTransform->setNodeMask(visible ? ~0 : 0); + } + +protected: + osg::ref_ptr mTransform; + osg::ref_ptr mGeode; + Resource::SceneManager* mSceneManager; + +}; + +class Sun : public CelestialBody +{ +public: + Sun(osg::Group* parentNode, Resource::SceneManager* sceneManager) + : CelestialBody(parentNode, sceneManager, 1.f, 1) + { + osg::ref_ptr tex = mSceneManager->getTextureManager()->getTexture2D("textures/tx_sun_05.dds", + osg::Texture::CLAMP, osg::Texture::CLAMP); + + mTransform->getOrCreateStateSet()->setTextureAttributeAndModes(0, tex, osg::StateAttribute::ON); + mTransform->getOrCreateStateSet()->setAttributeAndModes(createUnlitMaterial(), osg::StateAttribute::ON); + } +}; + +class Moon : public CelestialBody +{ +public: + enum Type + { + Type_Masser = 0, + Type_Secunda + }; + + Moon(osg::Group* parentNode, Resource::SceneManager* sceneManager, float scaleFactor, Type type) + : CelestialBody(parentNode, sceneManager, scaleFactor, 2) + , mPhase(Phase_Unspecified) + , mType(type) + { + mUpdater = new MoonUpdater; + mGeode->addUpdateCallback(mUpdater); + + setPhase(Phase_WaxingCrescent); + } + + enum Phase + { + Phase_New = 0, + Phase_WaxingCrescent, + Phase_WaxingHalf, + Phase_WaxingGibbous, + Phase_Full, + Phase_WaningGibbous, + Phase_WaningHalf, + Phase_WaningCrescent, + Phase_Unspecified + }; + + void setTextures(const std::string& phaseTex, const std::string& circleTex) + { + osg::ref_ptr stateset = new osg::StateSet; + + osg::ref_ptr moonTex = mSceneManager->getTextureManager()->getTexture2D(circleTex, + osg::Texture::CLAMP, osg::Texture::CLAMP); + + // stage 0: render the moon circle in atmosphere color + stateset->setTextureAttributeAndModes(0, moonTex, osg::StateAttribute::ON); + + osg::ref_ptr texEnv = new osg::TexEnvCombine; + texEnv->setSource0_RGB(osg::TexEnvCombine::CONSTANT); + texEnv->setConstantColor(osg::Vec4f(0.f, 0.f, 0.f, 1.f)); // atmospherecolor + + stateset->setTextureAttributeAndModes(0, texEnv, osg::StateAttribute::ON); + + // stage 1: render the "lit" side of the moon blended over the circle + osg::ref_ptr moonTex2 = mSceneManager->getTextureManager()->getTexture2D(phaseTex, + osg::Texture::CLAMP, osg::Texture::CLAMP); + + stateset->setTextureAttributeAndModes(1, moonTex2, osg::StateAttribute::ON); + + osg::ref_ptr texEnv2 = new osg::TexEnvCombine; + texEnv2->setCombine_RGB(osg::TexEnvCombine::INTERPOLATE); + texEnv2->setCombine_Alpha(osg::TexEnvCombine::MODULATE); + texEnv2->setSource0_Alpha(osg::TexEnvCombine::CONSTANT); + texEnv2->setConstantColor(osg::Vec4f(1.f, 1.f, 1.f, 1.f)); + texEnv2->setSource2_RGB(osg::TexEnvCombine::TEXTURE); + + stateset->setTextureAttributeAndModes(1, texEnv2, osg::StateAttribute::ON); + + mTransform->setStateSet(stateset); + } + + void setPhase(const Phase& phase) + { + if (mPhase == phase) + return; + mPhase = phase; + + std::string textureName = "textures/tx_"; + + if (mType == Moon::Type_Secunda) textureName += "secunda_"; + else textureName += "masser_"; + + if (phase == Moon::Phase_New) textureName += "new"; + else if (phase == Moon::Phase_WaxingCrescent) textureName += "one_wax"; + else if (phase == Moon::Phase_WaxingHalf) textureName += "half_wax"; + else if (phase == Moon::Phase_WaxingGibbous) textureName += "three_wax"; + else if (phase == Moon::Phase_WaningCrescent) textureName += "one_wan"; + else if (phase == Moon::Phase_WaningHalf) textureName += "half_wan"; + else if (phase == Moon::Phase_WaningGibbous) textureName += "three_wan"; + else if (phase == Moon::Phase_Full) textureName += "full"; + + textureName += ".dds"; + + if (mType == Moon::Type_Secunda) + setTextures(textureName, "textures/tx_mooncircle_full_s.dds"); + else + setTextures(textureName, "textures/tx_mooncircle_full_m.dds"); + } + + void setType(const Type& type) + { + mType = type; + } + + class MoonUpdater : public SceneUtil::StateSetUpdater + { + public: + MoonUpdater() + : mAlpha(1.f) + { + } + + virtual void setDefaults(osg::StateSet *stateset) + { + stateset->setAttributeAndModes(createUnlitMaterial(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + } + + virtual void apply(osg::StateSet *stateset, osg::NodeVisitor*) + { + osg::Material* mat = static_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); + mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, mAlpha)); + } + + void setAlpha(float alpha) + { + mAlpha = alpha; + } + + private: + float mAlpha; + }; + + void setAlpha(float alpha) + { + mUpdater->setAlpha(alpha); + } + + void setAtmosphereColor(const osg::Vec4f& color) + { + // TODO + } + + void setColor(const osg::Vec4f& color) + { + // TODO + } + + unsigned int getPhaseInt() const + { + if (mPhase == Moon::Phase_New) return 0; + else if (mPhase == Moon::Phase_WaxingCrescent) return 1; + else if (mPhase == Moon::Phase_WaningCrescent) return 1; + else if (mPhase == Moon::Phase_WaxingHalf) return 2; + else if (mPhase == Moon::Phase_WaningHalf) return 2; + else if (mPhase == Moon::Phase_WaxingGibbous) return 3; + else if (mPhase == Moon::Phase_WaningGibbous) return 3; + else if (mPhase == Moon::Phase_Full) return 4; + return 0; + } + +private: + Type mType; + Phase mPhase; + osg::ref_ptr mUpdater; +}; + SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneManager) : mSceneManager(sceneManager) , mHour(0.0f) @@ -240,7 +507,6 @@ SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneMana , mIsStorm(false) { osg::ref_ptr skyroot (new CameraRelativeTransform); - skyroot->setCullingActive(false); parentNode->addChild(skyroot); mRootNode = skyroot; @@ -257,8 +523,6 @@ void SkyManager::create() ModVertexAlphaVisitor modAtmosphere(0); mAtmosphereDay->accept(modAtmosphere); - // osg::Node* alphaBlendedRoot = - mAtmosphereUpdater = new AtmosphereUpdater; mAtmosphereDay->addUpdateCallback(mAtmosphereUpdater); @@ -271,27 +535,23 @@ void SkyManager::create() mAtmosphereNight->accept(modStars); mAtmosphereNight->setNodeMask(0); - osg::Geode* geode = new osg::Geode; - osg::ref_ptr sun = createTexturedQuad(); - geode->addDrawable(sun); - osg::PositionAttitudeTransform* trans = new osg::PositionAttitudeTransform; - trans->setScale(osg::Vec3f(450,450,450)); - trans->addChild(geode); - mRootNode->addChild(trans); + mSun.reset(new Sun(mRootNode, mSceneManager)); - mSunTransform = trans; + const MWWorld::Fallback* fallback=MWBase::Environment::get().getWorld()->getFallback(); + mMasser.reset(new Moon(mRootNode, mSceneManager, fallback->getFallbackFloat("Moons_Masser_Size")/100, Moon::Type_Masser)); + mSecunda.reset(new Moon(mRootNode, mSceneManager, fallback->getFallbackFloat("Moons_Secunda_Size")/100, Moon::Type_Secunda)); mCloudNode = mSceneManager->createInstance("meshes/sky_clouds_01.nif", mRootNode); ModVertexAlphaVisitor modClouds(1); mCloudNode->accept(modClouds); - osg::ref_ptr sunTex = mSceneManager->getTextureManager()->getTexture2D("textures/tx_sun_05.dds", - osg::Texture::CLAMP, osg::Texture::CLAMP); - trans->getOrCreateStateSet()->setTextureAttributeAndModes(0, sunTex, osg::StateAttribute::ON); - trans->getOrCreateStateSet()->setAttributeAndModes(createUnlitMaterial(), osg::StateAttribute::ON); + mCloudUpdater = new CloudUpdater; + //mCloudNode->addUpdateCallback(mCloudUpdater); mCloudNode->getOrCreateStateSet()->setAttributeAndModes(createAlphaTrackingUnlitMaterial(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + mCloudNode->setNodeMask(0); + osg::ref_ptr depth = new osg::Depth; depth->setWriteMask(false); mRootNode->getOrCreateStateSet()->setAttributeAndModes(depth, osg::StateAttribute::ON); @@ -307,16 +567,15 @@ SkyManager::~SkyManager() int SkyManager::getMasserPhase() const { - return 0; if (!mCreated) return 0; + return 0; //return mMasser->getPhaseInt(); } int SkyManager::getSecundaPhase() const { - return 0; if (!mCreated) return 0; - //return mSecunda->getPhaseInt(); + return mSecunda->getPhaseInt(); } void SkyManager::clearRain() @@ -376,9 +635,9 @@ void SkyManager::update(float duration) } //mSunGlare->setVisible(mSunEnabled); - //mSun->setVisible(mSunEnabled); - //mMasser->setVisible(mMasserEnabled); - //mSecunda->setVisible(mSecundaEnabled); + mSun->setVisible(mSunEnabled); + mMasser->setVisible(mMasserEnabled); + mSecunda->setVisible(mSecundaEnabled); // rotate the stars by 360 degrees every 4 days //mAtmosphereNight->roll(Degree(MWBase::Environment::get().getWorld()->getTimeScaleFactor()*duration*360 / (3600*96.f))); @@ -441,6 +700,11 @@ void SkyManager::setWeather(const MWWorld::WeatherResult& weather) if (mClouds != weather.mCloudTexture) { mClouds = weather.mCloudTexture; + + std::string texture = Misc::ResourceHelpers::correctTexturePath(mClouds, mSceneManager->getVFS()); + + mCloudUpdater->setTexture(mSceneManager->getTextureManager()->getTexture2D(texture, + osg::Texture::REPEAT, osg::Texture::REPEAT)); } if (mNextClouds != weather.mNextCloudTexture) @@ -456,15 +720,18 @@ void SkyManager::setWeather(const MWWorld::WeatherResult& weather) if (mCloudOpacity != weather.mCloudOpacity) { mCloudOpacity = weather.mCloudOpacity; + + mCloudUpdater->setOpacity(0.3); } if (mCloudColour != weather.mSunColor) { - /* + // FIXME: this doesn't look correct osg::Vec4f clr( weather.mSunColor.r()*0.7f + weather.mAmbientColor.r()*0.7f, weather.mSunColor.g()*0.7f + weather.mAmbientColor.g()*0.7f, weather.mSunColor.b()*0.7f + weather.mAmbientColor.b()*0.7f, 1.f); - */ + + mCloudUpdater->setEmissionColor(clr); mCloudColour = weather.mSunColor; } @@ -494,7 +761,7 @@ void SkyManager::setWeather(const MWWorld::WeatherResult& weather) } } - mAtmosphereNight->setNodeMask((weather.mNight && mEnabled) ? ~0 : 0); + //mAtmosphereNight->setNodeMask((weather.mNight && mEnabled) ? ~0 : 0); /* @@ -524,12 +791,16 @@ void SkyManager::setGlare(const float glare) void SkyManager::sunEnable() { - mSunEnabled = true; + if (!mCreated) return; + + mSun->setVisible(true); } void SkyManager::sunDisable() { - mSunEnabled = false; + if (!mCreated) return; + + mSun->setVisible(false); } void SkyManager::setStormDirection(const Ogre::Vector3 &direction) @@ -541,45 +812,51 @@ void SkyManager::setSunDirection(const osg::Vec3f& direction) { if (!mCreated) return; - mSunTransform->setPosition(direction*1000.f); - - osg::Quat quat; - quat.makeRotate(osg::Vec3f(0,0,1), direction); - mSunTransform->setAttitude(quat); + mSun->setDirection(direction); //mSunGlare->setPosition(direction); } -void SkyManager::setMasserDirection(const Ogre::Vector3& direction) +void SkyManager::setMasserDirection(const osg::Vec3f& direction) { if (!mCreated) return; - //mMasser->setPosition(direction); + + mMasser->setDirection(direction); } -void SkyManager::setSecundaDirection(const Ogre::Vector3& direction) +void SkyManager::setSecundaDirection(const osg::Vec3f& direction) { if (!mCreated) return; - //mSecunda->setPosition(direction); + + mSecunda->setDirection(direction); } void SkyManager::masserEnable() { - mMasserEnabled = true; + if (!mCreated) return; + + mMasser->setVisible(true); } void SkyManager::secundaEnable() { - mSecundaEnabled = true; + if (!mCreated) return; + + mSecunda->setVisible(true); } void SkyManager::masserDisable() { - mMasserEnabled = false; + if (!mCreated) return; + + mMasser->setVisible(false); } void SkyManager::secundaDisable() { - mSecundaEnabled = false; + if (!mCreated) return; + + mSecunda->setVisible(false); } void SkyManager::setLightningStrength(const float factor) @@ -599,13 +876,13 @@ void SkyManager::setLightningStrength(const float factor) void SkyManager::setMasserFade(const float fade) { if (!mCreated) return; - //mMasser->setVisibility(fade); + mMasser->setAlpha(fade); } void SkyManager::setSecundaFade(const float fade) { if (!mCreated) return; - //mSecunda->setVisibility(fade); + mSecunda->setAlpha(fade); } void SkyManager::setHour(double hour) diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index c8403af71..ebf3ee87f 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -20,6 +20,9 @@ namespace Resource namespace MWRender { class AtmosphereUpdater; + class CloudUpdater; + class Sun; + class Moon; class SkyManager { @@ -60,9 +63,9 @@ namespace MWRender void setSunDirection(const osg::Vec3f& direction); - void setMasserDirection(const Ogre::Vector3& direction); + void setMasserDirection(const osg::Vec3f& direction); - void setSecundaDirection(const Ogre::Vector3& direction); + void setSecundaDirection(const osg::Vec3f& direction); void setMasserFade(const float fade); @@ -94,13 +97,17 @@ namespace MWRender osg::ref_ptr mCloudNode; + osg::ref_ptr mCloudUpdater; + osg::ref_ptr mAtmosphereDay; osg::ref_ptr mAtmosphereNight; osg::ref_ptr mAtmosphereUpdater; - osg::ref_ptr mSunTransform; + std::auto_ptr mSun; + std::auto_ptr mMasser; + std::auto_ptr mSecunda; bool mCreated; diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index fe4f62953..90aedda1c 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -426,10 +426,10 @@ void WeatherManager::update(float duration, bool paused) mRendering->configureFog(mResult.mFogDepth, mResult.mFogColor); // disable sun during night - //if (mHour >= mNightStart || mHour <= mSunriseTime) - //mRendering->getSkyManager()->sunDisable(); - //else - //mRendering->getSkyManager()->sunEnable(); + if (mHour >= mNightStart || mHour <= mSunriseTime) + mRendering->getSkyManager()->sunDisable(); + else + mRendering->getSkyManager()->sunEnable(); // Update the sun direction. Run it east to west at a fixed angle from overhead. // The sun's speed at day and night may differ, since mSunriseTime and mNightStart @@ -493,10 +493,10 @@ void WeatherManager::update(float duration, bool paused) (1 - moonHeight) * facing * 0.8f, moonHeight); - //mRendering->getSkyManager()->setMasserDirection(masser); - //mRendering->getSkyManager()->setSecundaDirection(secunda); - //mRendering->getSkyManager()->masserEnable(); - //mRendering->getSkyManager()->secundaEnable(); + mRendering->getSkyManager()->setMasserDirection(masser); + mRendering->getSkyManager()->setSecundaDirection(secunda); + mRendering->getSkyManager()->masserEnable(); + mRendering->getSkyManager()->secundaEnable(); float angle = (1-moonHeight) * 90.f * facing; float masserHourFade = calculateHourFade("Masser"); @@ -507,13 +507,13 @@ void WeatherManager::update(float duration, bool paused) masserAngleFade *= masserHourFade; secundaAngleFade *= secundaHourFade; - //mRendering->getSkyManager()->setMasserFade(masserAngleFade); - //mRendering->getSkyManager()->setSecundaFade(secundaAngleFade); + mRendering->getSkyManager()->setMasserFade(masserAngleFade); + mRendering->getSkyManager()->setSecundaFade(secundaAngleFade); } else { - //mRendering->getSkyManager()->masserDisable(); - //mRendering->getSkyManager()->secundaDisable(); + mRendering->getSkyManager()->masserDisable(); + mRendering->getSkyManager()->secundaDisable(); } if (!paused) @@ -568,7 +568,6 @@ void WeatherManager::update(float duration, bool paused) mRendering->setAmbientColour(mResult.mAmbientColor); - //mRendering->sunEnable(false); mRendering->setSunColour(mResult.mSunColor); mRendering->getSkyManager()->setWeather(mResult); From 5b8c28f641973c40392e08125a29d5ff2d785daf Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 15 Apr 2015 22:11:38 +0200 Subject: [PATCH 0944/3725] NpcAnimation compiles --- apps/openmw/CMakeLists.txt | 4 +- apps/openmw/mwrender/animation.cpp | 4 +- apps/openmw/mwrender/animation.hpp | 2 +- apps/openmw/mwrender/npcanimation.cpp | 159 ++++++++--------------- apps/openmw/mwrender/npcanimation.hpp | 49 ++++--- apps/openmw/mwrender/objects.cpp | 4 + apps/openmw/mwrender/weaponanimation.hpp | 18 ++- 7 files changed, 104 insertions(+), 136 deletions(-) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index e7ed2d921..91b1ab1c5 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -20,8 +20,8 @@ set(GAME_HEADER source_group(game FILES ${GAME} ${GAME_HEADER}) add_openmw_dir (mwrender - actors objects renderingmanager animation sky -# debugging camera npcanimation creatureanimation activatoranimation + actors objects renderingmanager animation sky npcanimation +# debugging camera creatureanimation activatoranimation # renderinginterface localmap occlusionquery water shadows # characterpreview globalmap ripplesimulation refraction # terrainstorage renderconst effectmanager weaponanimation diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 85d9546aa..4352520db 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -10,9 +10,9 @@ namespace MWRender { - Animation::Animation(const MWWorld::Ptr &ptr, osg::ref_ptr node, Resource::ResourceSystem* resourceSystem) + Animation::Animation(const MWWorld::Ptr &ptr, osg::ref_ptr parentNode, Resource::ResourceSystem* resourceSystem) : mPtr(ptr) - , mInsert(node) + , mInsert(parentNode) , mResourceSystem(resourceSystem) { diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 754adec92..34173c29c 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -174,7 +174,7 @@ protected: public: - Animation(const MWWorld::Ptr &ptr, osg::ref_ptr node, Resource::ResourceSystem* resourceSystem); + Animation(const MWWorld::Ptr &ptr, osg::ref_ptr parentNode, Resource::ResourceSystem* resourceSystem); virtual ~Animation(); osg::Group* getOrCreateObjectRoot(); diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index a724644a7..fe16fa06e 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -10,12 +10,14 @@ #include #include -#include - #include #include +#include +#include +#include + #include "../mwworld/esmstore.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwworld/class.hpp" @@ -69,27 +71,13 @@ std::string getVampireHead(const std::string& race, bool female) return "meshes\\" + bodyPart->mModel; } -bool isSkinned (NifOgre::ObjectScenePtr scene) -{ - if (scene->mSkelBase == NULL) - return false; - for(size_t j = 0; j < scene->mEntities.size(); j++) - { - Ogre::Entity *ent = scene->mEntities[j]; - if(scene->mSkelBase != ent && ent->hasSkeleton()) - { - return true; - } - } - return false; -} - } namespace MWRender { +/* HeadAnimationTime::HeadAnimationTime(MWWorld::Ptr reference) : mReference(reference), mTalkStart(0), mTalkStop(0), mBlinkStart(0), mBlinkStop(0), mValue(0), mEnabled(true) { @@ -159,6 +147,7 @@ void HeadAnimationTime::setBlinkStop(float value) { mBlinkStop = value; } +*/ static NpcAnimation::PartBoneMap createPartListMap() { @@ -201,8 +190,8 @@ NpcAnimation::~NpcAnimation() } -NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, int visibilityFlags, bool disableListener, bool disableSounds, ViewMode viewMode) - : Animation(ptr, node), +NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, osg::ref_ptr parentNode, Resource::ResourceSystem* resourceSystem, int visibilityFlags, bool disableListener, bool disableSounds, ViewMode viewMode) + : Animation(ptr, parentNode, resourceSystem), mVisibilityFlags(visibilityFlags), mListenerDisabled(disableListener), mViewMode(viewMode), @@ -217,8 +206,8 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, int v { mNpc = mPtr.get()->mBase; - mHeadAnimationTime = Ogre::SharedPtr(new HeadAnimationTime(mPtr)); - mWeaponAnimationTime = Ogre::SharedPtr(new WeaponAnimationTime(this)); + //mHeadAnimationTime = Ogre::SharedPtr(new HeadAnimationTime(mPtr)); + //mWeaponAnimationTime = Ogre::SharedPtr(new WeaponAnimationTime(this)); for(size_t i = 0;i < ESM::PRT_Count;i++) { @@ -251,7 +240,7 @@ void NpcAnimation::rebuild() void NpcAnimation::updateNpcBase() { - clearAnimSources(); + //clearAnimSources(); const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); const ESM::Race *race = store.get().find(mNpc->mRace); @@ -296,9 +285,10 @@ void NpcAnimation::updateNpcBase() (!isWerewolf ? !isBeast ? "meshes\\base_anim.1st.nif" : "meshes\\base_animkna.1st.nif" : "meshes\\wolf\\skin.1st.nif"); - smodel = Misc::ResourceHelpers::correctActorModelPath(smodel); - setObjectRoot(smodel, true); + smodel = Misc::ResourceHelpers::correctActorModelPath(smodel, mResourceSystem->getVFS()); + setObjectRoot(smodel /*, baseonly = true*/); + /* if(mViewMode != VM_FirstPerson) { addAnimSource(smodel); @@ -318,9 +308,8 @@ void NpcAnimation::updateNpcBase() addAnimSource(smodel); else { - /* A bit counter-intuitive, but unlike third-person anims, it seems - * beast races get both base_anim.1st.nif and base_animkna.1st.nif. - */ + // A bit counter-intuitive, but unlike third-person anims, it seems + // beast races get both base_anim.1st.nif and base_animkna.1st.nif. addAnimSource("meshes\\xbase_anim.1st.nif"); if(isBeast) addAnimSource("meshes\\xbase_animkna.1st.nif"); @@ -328,18 +317,19 @@ void NpcAnimation::updateNpcBase() addAnimSource("meshes\\xbase_anim_female.1st.nif"); } } + */ for(size_t i = 0;i < ESM::PRT_Count;i++) removeIndividualPart((ESM::PartReferenceType)i); updateParts(); - mWeaponAnimationTime->updateStartTime(); + //mWeaponAnimationTime->updateStartTime(); } void NpcAnimation::updateParts() { - if (!mSkelBase) - return; + //if (!mSkelBase) + // return; mAlpha = 1.f; const MWWorld::Class &cls = mPtr.getClass(); @@ -379,7 +369,7 @@ void NpcAnimation::updateParts() }; static const size_t slotlistsize = sizeof(slotlist)/sizeof(slotlist[0]); - bool wasArrowAttached = (mAmmunition.get() != NULL); + bool wasArrowAttached = 0;//(mAmmunition.get() != NULL); MWWorld::InventoryStore& inv = mPtr.getClass().getInventoryStore(mPtr); for(size_t i = 0;i < slotlistsize && mViewMode != VM_HeadOnly;i++) @@ -396,7 +386,8 @@ void NpcAnimation::updateParts() int prio = 1; bool enchantedGlow = !store->getClass().getEnchantment(*store).empty(); - Ogre::Vector3 glowColor = getEnchantmentColor(*store); + //Ogre::Vector3 glowColor = getEnchantmentColor(*store); + Ogre::Vector3 glowColor (1,1,1); if(store->getTypeName() == typeid(ESM::Clothing).name()) { prio = ((slotlist[i].mBasePriority+1)<<1) + 0; @@ -448,7 +439,7 @@ void NpcAnimation::updateParts() const ESM::Light *light = part.get()->mBase; addOrReplaceIndividualPart(ESM::PRT_Shield, MWWorld::InventoryStore::Slot_CarriedLeft, 1, "meshes\\"+light->mModel); - addExtraLight(mInsert->getCreator(), mObjectParts[ESM::PRT_Shield], light); + //addExtraLight(mInsert->getCreator(), mObjectParts[ESM::PRT_Shield], light); } } @@ -597,6 +588,15 @@ public: } }; +PartHolderPtr NpcAnimation::insertBoundedPart(const std::string& model, int group, const std::string& bonename, const std::string& bonefilter, bool enchantedGlow, Ogre::Vector3* glowColor) +{ + osg::ref_ptr instance = mResourceSystem->getSceneManager()->createInstance(model); +std::cout << "inserting " << model << std::endl; + osg::ref_ptr attached = SceneUtil::attach(instance, mObjectRoot, bonefilter, bonename); + return PartHolderPtr(new PartHolder(attached)); +} + +/* NifOgre::ObjectScenePtr NpcAnimation::insertBoundedPart(const std::string &model, int group, const std::string &bonename, const std::string &bonefilter, bool enchantedGlow, Ogre::Vector3* glowColor) { NifOgre::ObjectScenePtr objects = NifOgre::Loader::createObjects(mSkelBase, bonename, bonefilter, mInsert, model); @@ -624,7 +624,9 @@ NifOgre::ObjectScenePtr NpcAnimation::insertBoundedPart(const std::string &model return objects; } +*/ +/* Ogre::Vector3 NpcAnimation::runAnimation(float timepassed) { Ogre::Vector3 ret = Animation::runAnimation(timepassed); @@ -675,13 +677,14 @@ Ogre::Vector3 NpcAnimation::runAnimation(float timepassed) return ret; } +*/ void NpcAnimation::removeIndividualPart(ESM::PartReferenceType type) { mPartPriorities[type] = 0; mPartslots[type] = -1; - mObjectParts[type].setNull(); + //mObjectParts[type].setNull(); if (!mSoundIds[type].empty() && !mSoundsDisabled) { MWBase::Environment::get().getSoundManager()->stopSound3D(mPtr, mSoundIds[type]); @@ -743,6 +746,7 @@ bool NpcAnimation::addOrReplaceIndividualPart(ESM::PartReferenceType type, int g } } } + /* if(mObjectParts[type]->mSkelBase) { Ogre::SkeletonInstance *skel = mObjectParts[type]->mSkelBase->getSkeleton(); @@ -795,6 +799,7 @@ bool NpcAnimation::addOrReplaceIndividualPart(ESM::PartReferenceType type, int g ctrl->setSource(mWeaponAnimationTime); } } + */ return true; } @@ -856,7 +861,7 @@ void NpcAnimation::showWeapons(bool showWeapon) MWWorld::ContainerStoreIterator weapon = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); if(weapon != inv.end()) { - Ogre::Vector3 glowColor = getEnchantmentColor(*weapon); + Ogre::Vector3 glowColor (1,1,1); //= getEnchantmentColor(*weapon); std::string mesh = weapon->getClass().getModel(*weapon); addOrReplaceIndividualPart(ESM::PRT_Weapon, MWWorld::InventoryStore::Slot_CarriedRight, 1, mesh, !weapon->getClass().getEnchantment(*weapon).empty(), &glowColor); @@ -868,11 +873,11 @@ void NpcAnimation::showWeapons(bool showWeapon) MWWorld::ContainerStoreIterator ammo = inv.getSlot(MWWorld::InventoryStore::Slot_Ammunition); if (ammo != inv.end() && ammo->get()->mBase->mData.mType == ESM::Weapon::Bolt) attachArrow(); - else - mAmmunition.setNull(); + //else + //mAmmunition.setNull(); } - else - mAmmunition.setNull(); + //else + //mAmmunition.setNull(); } } else @@ -889,29 +894,19 @@ void NpcAnimation::showCarriedLeft(bool show) MWWorld::ContainerStoreIterator iter = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft); if(show && iter != inv.end()) { - Ogre::Vector3 glowColor = getEnchantmentColor(*iter); + Ogre::Vector3 glowColor(1,1,1);// = getEnchantmentColor(*iter); std::string mesh = iter->getClass().getModel(*iter); if (addOrReplaceIndividualPart(ESM::PRT_Shield, MWWorld::InventoryStore::Slot_CarriedLeft, 1, mesh, !iter->getClass().getEnchantment(*iter).empty(), &glowColor)) { - if (iter->getTypeName() == typeid(ESM::Light).name()) - addExtraLight(mInsert->getCreator(), mObjectParts[ESM::PRT_Shield], iter->get()->mBase); + //if (iter->getTypeName() == typeid(ESM::Light).name()) + //addExtraLight(mInsert->getCreator(), mObjectParts[ESM::PRT_Shield], iter->get()->mBase); } } else removeIndividualPart(ESM::PRT_Shield); } -void NpcAnimation::configureAddedObject(NifOgre::ObjectScenePtr object, MWWorld::Ptr ptr, int slot) -{ - Ogre::Vector3 glowColor = getEnchantmentColor(ptr); - setRenderProperties(object, (mViewMode == VM_FirstPerson) ? RV_FirstPerson : mVisibilityFlags, RQG_Main, RQG_Alpha, 0, - !ptr.getClass().getEnchantment(ptr).empty(), &glowColor); - - std::for_each(object->mEntities.begin(), object->mEntities.end(), SetObjectGroup(slot)); - std::for_each(object->mParticles.begin(), object->mParticles.end(), SetObjectGroup(slot)); -} - void NpcAnimation::attachArrow() { WeaponAnimation::attachArrow(mPtr); @@ -942,11 +937,13 @@ void NpcAnimation::permanentEffectAdded(const ESM::MagicEffect *magicEffect, boo if (!magicEffect->mHit.empty()) { + /* const ESM::Static* castStatic = MWBase::Environment::get().getWorld()->getStore().get().find (magicEffect->mHit); bool loop = (magicEffect->mData.mFlags & ESM::MagicEffect::ContinuousVfx) != 0; // Don't play particle VFX unless the effect is new or it should be looping. if (isNew || loop) addEffect("meshes\\" + castStatic->mModel, magicEffect->mIndex, loop, ""); + */ } } @@ -956,67 +953,17 @@ void NpcAnimation::setAlpha(float alpha) return; mAlpha = alpha; - for (int i=0; imEntities.size(); ++j) - { - Ogre::Entity* ent = mObjectParts[i]->mEntities[j]; - if (ent != mObjectParts[i]->mSkelBase) - applyAlpha(alpha, ent, mObjectParts[i]); - } - } + // TODO } void NpcAnimation::enableHeadAnimation(bool enable) { - mHeadAnimationTime->setEnabled(enable); -} - -void NpcAnimation::preRender(Ogre::Camera *camera) -{ - Animation::preRender(camera); - for (int i=0; irotateBillboardNodes(camera); - } + //mHeadAnimationTime->setEnabled(enable); } -void NpcAnimation::applyAlpha(float alpha, Ogre::Entity *ent, NifOgre::ObjectScenePtr scene) +void NpcAnimation::setWeaponGroup(const std::string &group) { - sh::Factory::getInstance()._ensureMaterial(ent->getSubEntity(0)->getMaterial()->getName(), "Default"); - ent->getSubEntity(0)->setRenderQueueGroup(alpha != 1.f || ent->getSubEntity(0)->getMaterial()->isTransparent() - ? RQG_Alpha : RQG_Main); - - - Ogre::MaterialPtr mat = scene->mMaterialControllerMgr.getWritableMaterial(ent); - if (mAlpha == 1.f) - { - // Don't bother remembering what the original values were. Just remove the techniques and let the factory restore them. - mat->removeAllTechniques(); - sh::Factory::getInstance()._ensureMaterial(mat->getName(), "Default"); - return; - } - - Ogre::Material::TechniqueIterator techs = mat->getTechniqueIterator(); - while(techs.hasMoreElements()) - { - Ogre::Technique *tech = techs.getNext(); - Ogre::Technique::PassIterator passes = tech->getPassIterator(); - while(passes.hasMoreElements()) - { - Ogre::Pass *pass = passes.getNext(); - pass->setSceneBlending(Ogre::SBT_TRANSPARENT_ALPHA); - Ogre::ColourValue diffuse = pass->getDiffuse(); - diffuse.a = alpha; - pass->setDiffuse(diffuse); - pass->setVertexColourTracking(pass->getVertexColourTracking() &~Ogre::TVC_DIFFUSE); - } - } + //mWeaponAnimationTime-> } void NpcAnimation::equipmentChanged() diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 90b1c269b..28ac6509b 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -15,6 +15,7 @@ namespace ESM namespace MWRender { +/* class HeadAnimationTime : public Ogre::ControllerValue { private: @@ -47,6 +48,27 @@ public: virtual void setValue(Ogre::Real value) { } }; +*/ + +/// @brief Detaches the node from its parent when the object goes out of scope. +class PartHolder +{ +public: + PartHolder(osg::ref_ptr node) + : mNode(node) + { + } + + ~PartHolder() + { + if (mNode->getNumParents()) + mNode->getParent(0)->removeChild(mNode); + } + +private: + osg::ref_ptr mNode; +}; +typedef boost::shared_ptr PartHolderPtr; class NpcAnimation : public Animation, public WeaponAnimation, public MWWorld::InventoryStoreListener { @@ -69,7 +91,7 @@ private: bool mListenerDisabled; // Bounded Parts - NifOgre::ObjectScenePtr mObjectParts[ESM::PRT_Count]; + PartHolderPtr mObjectParts[ESM::PRT_Count]; std::string mSoundIds[ESM::PRT_Count]; const ESM::NPC *mNpc; @@ -94,8 +116,8 @@ private: Ogre::Vector3 mFirstPersonOffset; - Ogre::SharedPtr mHeadAnimationTime; - Ogre::SharedPtr mWeaponAnimationTime; + //Ogre::SharedPtr mHeadAnimationTime; + //Ogre::SharedPtr mWeaponAnimationTime; float mAlpha; bool mSoundsDisabled; @@ -105,9 +127,8 @@ private: void updateNpcBase(); - NifOgre::ObjectScenePtr insertBoundedPart(const std::string &model, int group, const std::string &bonename, - const std::string &bonefilter, - bool enchantedGlow, Ogre::Vector3* glowColor=NULL); + PartHolderPtr insertBoundedPart(const std::string &model, int group, const std::string &bonename, + const std::string &bonefilter, bool enchantedGlow, Ogre::Vector3* glowColor=NULL); void removeIndividualPart(ESM::PartReferenceType type); void reserveIndividualPart(ESM::PartReferenceType type, int group, int priority); @@ -118,7 +139,7 @@ private: void addPartGroup(int group, int priority, const std::vector &parts, bool enchantedGlow=false, Ogre::Vector3* glowColor=NULL); - void applyAlpha(float alpha, Ogre::Entity* ent, NifOgre::ObjectScenePtr scene); + //void applyAlpha(float alpha, Ogre::Entity* ent, NifOgre::ObjectScenePtr scene); public: /** @@ -132,15 +153,16 @@ public: * @param disableSounds Same as \a disableListener but for playing items sounds * @param viewMode */ - NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, int visibilityFlags, bool disableListener = false, + NpcAnimation(const MWWorld::Ptr& ptr, osg::ref_ptr parentNode, Resource::ResourceSystem* resourceSystem, + int visibilityFlags, bool disableListener = false, bool disableSounds = false, ViewMode viewMode=VM_Normal); virtual ~NpcAnimation(); virtual void enableHeadAnimation(bool enable); - virtual void setWeaponGroup(const std::string& group) { mWeaponAnimationTime->setGroup(group); } + virtual void setWeaponGroup(const std::string& group); - virtual Ogre::Vector3 runAnimation(float timepassed); + //virtual Ogre::Vector3 runAnimation(float timepassed); /// A relative factor (0-1) that decides if and how much the skeleton should be pitched /// to indicate the facing orientation of the character. @@ -158,9 +180,9 @@ public: virtual void releaseArrow(); // WeaponAnimation - virtual NifOgre::ObjectScenePtr getWeapon() { return mObjectParts[ESM::PRT_Weapon]; } + //virtual NifOgre::ObjectScenePtr getWeapon() { return mObjectParts[ESM::PRT_Weapon]; } virtual void showWeapon(bool show) { showWeapons(show); } - virtual void configureAddedObject(NifOgre::ObjectScenePtr object, MWWorld::Ptr ptr, int slot); + //virtual void configureAddedObject(NifOgre::ObjectScenePtr object, MWWorld::Ptr ptr, int slot); void setViewMode(ViewMode viewMode); @@ -178,9 +200,6 @@ public: virtual void setAlpha(float alpha); virtual void setVampire(bool vampire); - - /// Prepare this animation for being rendered with \a camera (rotates billboard nodes) - virtual void preRender (Ogre::Camera* camera); }; } diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 25d57aba0..322d02e94 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -25,6 +25,7 @@ #include "renderconst.hpp" #include "animation.hpp" +#include "npcanimation.hpp" namespace { @@ -199,7 +200,10 @@ void Objects::insertCreature(const MWWorld::Ptr &ptr, const std::string &mesh, b void Objects::insertNPC(const MWWorld::Ptr &ptr) { + insertBegin(ptr); + std::auto_ptr anim (new NpcAnimation(ptr, osg::ref_ptr(ptr.getRefData().getBaseNode()), mResourceSystem, 0)); + mObjects.insert(std::make_pair(ptr, anim.release())); } bool Objects::deleteObject (const MWWorld::Ptr& ptr) diff --git a/apps/openmw/mwrender/weaponanimation.hpp b/apps/openmw/mwrender/weaponanimation.hpp index e1ccd9465..400962856 100644 --- a/apps/openmw/mwrender/weaponanimation.hpp +++ b/apps/openmw/mwrender/weaponanimation.hpp @@ -1,10 +1,6 @@ #ifndef OPENMW_MWRENDER_WEAPONANIMATION_H #define OPENMW_MWRENDER_WEAPONANIMATION_H -#include - -#include - #include "../mwworld/ptr.hpp" namespace MWRender @@ -12,6 +8,7 @@ namespace MWRender class Animation; + /* class WeaponAnimationTime : public Ogre::ControllerValue { private: @@ -27,6 +24,7 @@ namespace MWRender virtual void setValue(Ogre::Real value) { } }; + */ /// Handles attach & release of projectiles for ranged weapons class WeaponAnimation @@ -36,23 +34,23 @@ namespace MWRender virtual ~WeaponAnimation() {} /// @note If no weapon (or an invalid weapon) is equipped, this function is a no-op. - void attachArrow(MWWorld::Ptr actor); + void attachArrow(MWWorld::Ptr actor) {} /// @note If no weapon (or an invalid weapon) is equipped, this function is a no-op. - void releaseArrow(MWWorld::Ptr actor); + void releaseArrow(MWWorld::Ptr actor) {} protected: - NifOgre::ObjectScenePtr mAmmunition; + //NifOgre::ObjectScenePtr mAmmunition; - virtual NifOgre::ObjectScenePtr getWeapon() = 0; + //virtual NifOgre::ObjectScenePtr getWeapon() = 0; virtual void showWeapon(bool show) = 0; - virtual void configureAddedObject(NifOgre::ObjectScenePtr object, MWWorld::Ptr ptr, int slot) = 0; + //virtual void configureAddedObject(NifOgre::ObjectScenePtr object, MWWorld::Ptr ptr, int slot) = 0; /// A relative factor (0-1) that decides if and how much the skeleton should be pitched /// to indicate the facing orientation of the character, for ranged weapon aiming. float mPitchFactor; - void pitchSkeleton(float xrot, Ogre::SkeletonInstance* skel); + //void pitchSkeleton(float xrot, Ogre::SkeletonInstance* skel); }; } From c334a76a6f41f33ee6544cf6ccdbffde8844f898 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 15 Apr 2015 22:38:43 +0200 Subject: [PATCH 0945/3725] Fix skinning bug --- apps/openmw/mwrender/sky.cpp | 7 ++----- components/nifosg/nifloader.cpp | 21 ++++++--------------- components/sceneutil/attach.cpp | 1 + 3 files changed, 9 insertions(+), 20 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 1ac7ca10b..f843f9a43 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -546,12 +546,10 @@ void SkyManager::create() mCloudNode->accept(modClouds); mCloudUpdater = new CloudUpdater; - //mCloudNode->addUpdateCallback(mCloudUpdater); + mCloudNode->addUpdateCallback(mCloudUpdater); mCloudNode->getOrCreateStateSet()->setAttributeAndModes(createAlphaTrackingUnlitMaterial(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); - mCloudNode->setNodeMask(0); - osg::ref_ptr depth = new osg::Depth; depth->setWriteMask(false); mRootNode->getOrCreateStateSet()->setAttributeAndModes(depth, osg::StateAttribute::ON); @@ -568,8 +566,7 @@ SkyManager::~SkyManager() int SkyManager::getMasserPhase() const { if (!mCreated) return 0; - return 0; - //return mMasser->getPhaseInt(); + return mMasser->getPhaseInt(); } int SkyManager::getSecundaPhase() const diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index b61e3824b..1f0c36839 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -222,21 +222,12 @@ namespace // Callback method called by the NodeVisitor when visiting a node. void operator()(osg::Node* node, osg::NodeVisitor* nv) { - if (nv && nv->getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR) - { - osgAnimation::Bone* b = dynamic_cast(node); - if (!b) - { - OSG_WARN << "Warning: UpdateBone set on non-Bone object." << std::endl; - return; - } - - osgAnimation::Bone* parent = b->getBoneParent(); - if (parent) - b->setMatrixInSkeletonSpace(b->getMatrixInBoneSpace() * parent->getMatrixInSkeletonSpace()); - else - b->setMatrixInSkeletonSpace(b->getMatrixInBoneSpace()); - } + osgAnimation::Bone* b = static_cast(node); + osgAnimation::Bone* parent = b->getBoneParent(); + if (parent) + b->setMatrixInSkeletonSpace(b->getMatrixInBoneSpace() * parent->getMatrixInSkeletonSpace()); + else + b->setMatrixInSkeletonSpace(b->getMatrixInBoneSpace()); traverse(node,nv); } }; diff --git a/components/sceneutil/attach.cpp b/components/sceneutil/attach.cpp index 47efe986c..e06155a61 100644 --- a/components/sceneutil/attach.cpp +++ b/components/sceneutil/attach.cpp @@ -96,6 +96,7 @@ namespace SceneUtil bone->addUpdateCallback(old); } } + traverse(node); } private: From 57fd18b161c4a7298aeb4c768ecbcda9a4320bf0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 15 Apr 2015 22:43:53 +0200 Subject: [PATCH 0946/3725] Fix frontface bug --- components/sceneutil/attach.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/sceneutil/attach.cpp b/components/sceneutil/attach.cpp index e06155a61..882bd66ec 100644 --- a/components/sceneutil/attach.cpp +++ b/components/sceneutil/attach.cpp @@ -172,7 +172,7 @@ namespace SceneUtil // However MW isn't doing this either, so don't. Assuming all meshes are using backface culling is more efficient. osg::FrontFace* frontFace = new osg::FrontFace; frontFace->setMode(osg::FrontFace::CLOCKWISE); - toAttach->getOrCreateStateSet()->setAttributeAndModes(frontFace, osg::StateAttribute::ON); + trans->getOrCreateStateSet()->setAttributeAndModes(frontFace, osg::StateAttribute::ON); find.mFoundNode->addChild(trans); trans->addChild(toAttach); From 8f6d4fb3e0ce53786a8aad5eb75a94d831f45f15 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 16 Apr 2015 01:26:58 +0200 Subject: [PATCH 0947/3725] Fix filtering bug --- components/sceneutil/attach.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/components/sceneutil/attach.cpp b/components/sceneutil/attach.cpp index 882bd66ec..f084704c3 100644 --- a/components/sceneutil/attach.cpp +++ b/components/sceneutil/attach.cpp @@ -12,6 +12,8 @@ #include #include +#include + #include "visitor.hpp" namespace SceneUtil @@ -110,13 +112,14 @@ namespace SceneUtil public: FilterVisitor(const std::string& filter) : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) - , mFilter(filter) + , mFilter(Misc::StringUtils::lowerCase(filter)) { } virtual void apply(osg::Geode &node) { - if (node.getName().find(mFilter) == std::string::npos) + std::string lowerName = Misc::StringUtils::lowerCase(node.getName()); + if (lowerName.find(mFilter) == std::string::npos) { mToRemove.push_back(&node); } @@ -133,7 +136,7 @@ namespace SceneUtil private: std::vector mToRemove; - const std::string& mFilter; + std::string mFilter; }; osg::ref_ptr attach(osg::ref_ptr toAttach, osg::Node *master, const std::string &filter, const std::string &attachNode) From a2d824bfa6a9e4422cc2c754a05b18d01186b45a Mon Sep 17 00:00:00 2001 From: cc9cii Date: Fri, 17 Apr 2015 01:27:36 +1000 Subject: [PATCH 0948/3725] Changes to support dialogue only items but in a list view via QDataWidgetMapper. --- apps/opencs/model/world/columnbase.hpp | 13 +-- apps/opencs/model/world/idtree.cpp | 3 +- .../model/world/nestedtableproxymodel.cpp | 33 +++++-- .../model/world/nestedtableproxymodel.hpp | 4 +- apps/opencs/view/world/dialoguesubview.cpp | 96 ++++++++++++++++--- apps/opencs/view/world/dialoguesubview.hpp | 27 +++--- apps/opencs/view/world/util.cpp | 2 +- 7 files changed, 134 insertions(+), 44 deletions(-) diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index c7c8d3cd8..813de8d96 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -23,7 +23,8 @@ namespace CSMWorld enum Flags { Flag_Table = 1, // column should be displayed in table view - Flag_Dialogue = 2 // column should be displayed in dialogue view + Flag_Dialogue = 2, // column should be displayed in dialogue view + Flag_Dialogue_List = 4 // column should be diaplyed in dialogue view }; enum Display @@ -94,11 +95,11 @@ namespace CSMWorld Display_QuestStatusType, //Those are top level columns that nest other columns - Display_NestedItemList, - Display_NestedSpellList, - Display_NestedDestinationsList, - Display_PathgridPointList, - Display_PathgridEdgeList, + Display_NestedItemList, // delete? + Display_NestedSpellList, // delete? + Display_NestedDestinationsList, // delete? + Display_PathgridPointList, // delete? + Display_PathgridEdgeList, // delete? Display_NestedHeader, Display_EnchantmentType, diff --git a/apps/opencs/model/world/idtree.cpp b/apps/opencs/model/world/idtree.cpp index eddde5a89..06db09a0f 100644 --- a/apps/opencs/model/world/idtree.cpp +++ b/apps/opencs/model/world/idtree.cpp @@ -93,8 +93,7 @@ bool CSMWorld::IdTree::setData (const QModelIndex &index, const QVariant &value, mNestedCollection->setNestedData(parentAddress.first, parentAddress.second, value, index.row(), index.column()); emit dataChanged (CSMWorld::IdTree::index (parentAddress.first, 0), - CSMWorld::IdTree::index (parentAddress.second, idCollection()->getColumns()-1)); - + CSMWorld::IdTree::index (parentAddress.first, idCollection()->getColumns()-1)); return true; } else diff --git a/apps/opencs/model/world/nestedtableproxymodel.cpp b/apps/opencs/model/world/nestedtableproxymodel.cpp index 0f137d78f..acf197716 100644 --- a/apps/opencs/model/world/nestedtableproxymodel.cpp +++ b/apps/opencs/model/world/nestedtableproxymodel.cpp @@ -32,12 +32,15 @@ CSMWorld::NestedTableProxyModel::NestedTableProxyModel(const QModelIndex& parent connect(mMainModel, SIGNAL(resetEnd(const QString&)), this, SLOT(forwardResetEnd(const QString&))); + + connect(mMainModel, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), + this, SLOT(forwardDataChanged(const QModelIndex &, const QModelIndex &))); } QModelIndex CSMWorld::NestedTableProxyModel::mapFromSource(const QModelIndex& sourceIndex) const { const QModelIndex& testedParent = mMainModel->parent(sourceIndex); - const QModelIndex& parent = mMainModel->getModelIndex (mId, mParentColumn); + const QModelIndex& parent = mMainModel->getNestedModelIndex (mId, mParentColumn); if (testedParent == parent) { return createIndex(sourceIndex.row(), sourceIndex.column()); @@ -75,13 +78,8 @@ QModelIndex CSMWorld::NestedTableProxyModel::index(int row, int column, const QM int rows = mMainModel->rowCount(parent); int columns = mMainModel->columnCount(parent); - if (row < 0 || - row >= rows || - column < 0 || - column >= columns) - { + if (row < 0 || row >= rows || column < 0 || column >= columns) return QModelIndex(); - } return createIndex(row, column); } @@ -103,6 +101,9 @@ QVariant CSMWorld::NestedTableProxyModel::data(const QModelIndex& index, int rol return mMainModel->data(mapToSource(index), role); } +// NOTE: Due to mapToSouce(index) the dataChanged() signal resulting from setData() will have the +// source model's index values. The indicies need to be converted to the proxy space values. +// See forwardDataChanged() bool CSMWorld::NestedTableProxyModel::setData (const QModelIndex & index, const QVariant & value, int role) { return mMainModel->setData(mapToSource(index), value, role); @@ -128,7 +129,8 @@ CSMWorld::IdTree* CSMWorld::NestedTableProxyModel::model() const return mMainModel; } -void CSMWorld::NestedTableProxyModel::forwardRowsAboutToInserted(const QModelIndex& parent, int first, int last) +void CSMWorld::NestedTableProxyModel::forwardRowsAboutToInserted(const QModelIndex& parent, + int first, int last) { if (indexIsParent(parent)) { @@ -151,7 +153,8 @@ bool CSMWorld::NestedTableProxyModel::indexIsParent(const QModelIndex& index) mMainModel->data(mMainModel->index(index.row(), 0)).toString().toUtf8().constData() == mId); } -void CSMWorld::NestedTableProxyModel::forwardRowsAboutToRemoved(const QModelIndex& parent, int first, int last) +void CSMWorld::NestedTableProxyModel::forwardRowsAboutToRemoved(const QModelIndex& parent, + int first, int last) { if (indexIsParent(parent)) { @@ -178,3 +181,15 @@ void CSMWorld::NestedTableProxyModel::forwardResetEnd(const QString& id) if (id.toUtf8() == mId.c_str()) endResetModel(); } + +void CSMWorld::NestedTableProxyModel::forwardDataChanged (const QModelIndex& topLeft, + const QModelIndex& bottomRight) +{ + const QModelIndex& parent = mMainModel->getNestedModelIndex (mId, mParentColumn); + + if (topLeft.column() <= parent.column() && bottomRight.column() >= parent.column()) + { + emit dataChanged(index(0,0), + index(mMainModel->rowCount(parent)-1, mMainModel->columnCount(parent)-1)); + } +} diff --git a/apps/opencs/model/world/nestedtableproxymodel.hpp b/apps/opencs/model/world/nestedtableproxymodel.hpp index f5cbdb10b..2d5a46c48 100644 --- a/apps/opencs/model/world/nestedtableproxymodel.hpp +++ b/apps/opencs/model/world/nestedtableproxymodel.hpp @@ -47,7 +47,7 @@ namespace CSMWorld virtual int columnCount(const QModelIndex& parent) const; - virtual QModelIndex index(int row, int column, const QModelIndex& parent) const; + virtual QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const; virtual QModelIndex parent(const QModelIndex& index) const; @@ -76,6 +76,8 @@ namespace CSMWorld void forwardResetStart(const QString& id); void forwardResetEnd(const QString& id); + + void forwardDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight); }; } diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 79eb48534..88791c9cd 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -28,6 +28,7 @@ #include "../../model/world/columns.hpp" #include "../../model/world/record.hpp" #include "../../model/world/tablemimedata.hpp" +#include "../../model/world/idtree.hpp" #include "../../model/doc/document.hpp" #include "../../model/world/commands.hpp" @@ -175,9 +176,10 @@ void CSVWorld::DialogueDelegateDispatcherProxy::tableMimeDataDropped(const std:: ==============================DialogueDelegateDispatcher========================================== */ -CSVWorld::DialogueDelegateDispatcher::DialogueDelegateDispatcher(QObject* parent, CSMWorld::IdTable* table, CSMDoc::Document& document) : +CSVWorld::DialogueDelegateDispatcher::DialogueDelegateDispatcher(QObject* parent, + CSMWorld::IdTable* table, CSMDoc::Document& document, QAbstractItemModel *model) : mParent(parent), -mTable(table), +mTable(model ? model : table), mDocument (document), mNotEditableDelegate(table, parent) { @@ -199,7 +201,8 @@ CSVWorld::CommandDelegate* CSVWorld::DialogueDelegateDispatcher::makeDelegate(CS return delegate; } -void CSVWorld::DialogueDelegateDispatcher::editorDataCommited(QWidget* editor, const QModelIndex& index, CSMWorld::ColumnBase::Display display) +void CSVWorld::DialogueDelegateDispatcher::editorDataCommited(QWidget* editor, + const QModelIndex& index, CSMWorld::ColumnBase::Display display) { setModelData(editor, mTable, index, display); } @@ -231,12 +234,14 @@ void CSVWorld::DialogueDelegateDispatcher::setEditorData (QWidget* editor, const } } -void CSVWorld::DialogueDelegateDispatcher::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const +void CSVWorld::DialogueDelegateDispatcher::setModelData(QWidget* editor, + QAbstractItemModel* model, const QModelIndex& index) const { setModelData(editor, model, index, CSMWorld::ColumnBase::Display_None); } -void CSVWorld::DialogueDelegateDispatcher::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index, CSMWorld::ColumnBase::Display display) const +void CSVWorld::DialogueDelegateDispatcher::setModelData(QWidget* editor, + QAbstractItemModel* model, const QModelIndex& index, CSMWorld::ColumnBase::Display display) const { std::map::const_iterator delegateIt(mDelegates.find(display)); if (delegateIt != mDelegates.end()) @@ -245,17 +250,20 @@ void CSVWorld::DialogueDelegateDispatcher::setModelData(QWidget* editor, QAbstra } } -void CSVWorld::DialogueDelegateDispatcher::paint (QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const +void CSVWorld::DialogueDelegateDispatcher::paint (QPainter* painter, + const QStyleOptionViewItem& option, const QModelIndex& index) const { //Does nothing } -QSize CSVWorld::DialogueDelegateDispatcher::sizeHint (const QStyleOptionViewItem& option, const QModelIndex& index) const +QSize CSVWorld::DialogueDelegateDispatcher::sizeHint (const QStyleOptionViewItem& option, + const QModelIndex& index) const { return QSize(); //silencing warning, otherwise does nothing } -QWidget* CSVWorld::DialogueDelegateDispatcher::makeEditor(CSMWorld::ColumnBase::Display display, const QModelIndex& index) +QWidget* CSVWorld::DialogueDelegateDispatcher::makeEditor(CSMWorld::ColumnBase::Display display, + const QModelIndex& index) { QVariant variant = index.data(); if (!variant.isValid()) @@ -270,14 +278,16 @@ QWidget* CSVWorld::DialogueDelegateDispatcher::makeEditor(CSMWorld::ColumnBase:: QWidget* editor = NULL; if (! (mTable->flags (index) & Qt::ItemIsEditable)) { - return mNotEditableDelegate.createEditor(qobject_cast(mParent), QStyleOptionViewItem(), index); + return mNotEditableDelegate.createEditor(qobject_cast(mParent), + QStyleOptionViewItem(), index); } std::map::iterator delegateIt(mDelegates.find(display)); if (delegateIt != mDelegates.end()) { - editor = delegateIt->second->createEditor(qobject_cast(mParent), QStyleOptionViewItem(), index, display); + editor = delegateIt->second->createEditor(qobject_cast(mParent), + QStyleOptionViewItem(), index, display); DialogueDelegateDispatcherProxy* proxy = new DialogueDelegateDispatcherProxy(editor, display); @@ -339,12 +349,15 @@ CSVWorld::EditWidget::~EditWidget() { delete mNestedModels[i]; } + delete mNestedTableDispatcher; } CSVWorld::EditWidget::EditWidget(QWidget *parent, int row, CSMWorld::IdTable* table, CSMDoc::Document& document, bool createAndDelete) : mDispatcher(this, table, document), +mNestedTableDispatcher(NULL), QScrollArea(parent), mWidgetMapper(NULL), +mNestedTableMapper(NULL), mMainWidget(NULL), mDocument (document), mTable(table) @@ -362,6 +375,7 @@ void CSVWorld::EditWidget::remake(int row) delete mNestedModels[i]; } mNestedModels.clear(); + delete mNestedTableDispatcher; if (mMainWidget) { @@ -376,6 +390,11 @@ void CSVWorld::EditWidget::remake(int row) delete mWidgetMapper; mWidgetMapper = 0; } + if (mNestedTableMapper) + { + delete mNestedTableMapper; + mNestedTableMapper = 0; + } mWidgetMapper = new QDataWidgetMapper (this); mWidgetMapper->setModel(mTable); @@ -417,7 +436,8 @@ void CSVWorld::EditWidget::remake(int row) CSMWorld::ColumnBase::Display display = static_cast (mTable->headerData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Display).toInt()); - if (mTable->hasChildren(mTable->index(row, i))) + if (mTable->hasChildren(mTable->index(row, i)) && + !(flags & CSMWorld::ColumnBase::Flag_Dialogue_List)) { mNestedModels.push_back(new CSMWorld::NestedTableProxyModel (mTable->index(row, i), display, dynamic_cast(mTable))); @@ -425,14 +445,15 @@ void CSVWorld::EditWidget::remake(int row) table->resizeColumnsToContents(); - QLabel* label = new QLabel (mTable->headerData (i, Qt::Horizontal, Qt::DisplayRole).toString(), mMainWidget); + QLabel* label = + new QLabel (mTable->headerData (i, Qt::Horizontal, Qt::DisplayRole).toString(), mMainWidget); label->setSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed); tablesLayout->addWidget(label); tablesLayout->addWidget(table); } - else + else if (!(flags & CSMWorld::ColumnBase::Flag_Dialogue_List)) { mDispatcher.makeDelegate (display); QWidget* editor = mDispatcher.makeEditor (display, (mTable->index (row, i))); @@ -460,6 +481,55 @@ void CSVWorld::EditWidget::remake(int row) } } } + else + { + mNestedModels.push_back(new CSMWorld::NestedTableProxyModel ( + static_cast(mTable)->index(row, i), + display, static_cast(mTable))); + mNestedTableMapper = new QDataWidgetMapper (this); + + mNestedTableMapper->setModel(mNestedModels.back()); + // FIXME: lack MIME support? + mNestedTableDispatcher = + new DialogueDelegateDispatcher (this, mTable, mDocument, mNestedModels.back()); + mNestedTableMapper->setItemDelegate(mNestedTableDispatcher); + + int columnCount = + mTable->columnCount(mTable->getModelIndex (mNestedModels.back()->getParentId(), i)); + for (int col = 0; col < columnCount; ++col) + { + int displayRole = mNestedModels.back()->headerData (col, + Qt::Horizontal, CSMWorld::ColumnBase::Role_Display).toInt(); + + CSMWorld::ColumnBase::Display display = + static_cast (displayRole); + + mNestedTableDispatcher->makeDelegate (display); + + // FIXME: assumed all columns are editable + QWidget* editor = + mNestedTableDispatcher->makeEditor (display, mNestedModels.back()->index (0, col)); + if (editor) + { + mNestedTableMapper->addMapping (editor, col); + + std::string disString = mNestedModels.back()->headerData (col, + Qt::Horizontal, Qt::DisplayRole).toString().toStdString(); + // Need ot use Qt::DisplayRole in order to get the correct string + // from CSMWorld::Columns + QLabel* label = new QLabel (mNestedModels.back()->headerData (col, + Qt::Horizontal, Qt::DisplayRole).toString(), mMainWidget); + + label->setSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed); + editor->setSizePolicy (QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); + + unlockedLayout->addWidget (label, unlocked, 0); + unlockedLayout->addWidget (editor, unlocked, 1); + ++unlocked; + } + } + mNestedTableMapper->setCurrentModelIndex(mNestedModels.back()->index(0, 0)); + } } } diff --git a/apps/opencs/view/world/dialoguesubview.hpp b/apps/opencs/view/world/dialoguesubview.hpp index 72acb1966..067ff95f5 100644 --- a/apps/opencs/view/world/dialoguesubview.hpp +++ b/apps/opencs/view/world/dialoguesubview.hpp @@ -107,9 +107,9 @@ namespace CSVWorld QObject* mParent; - CSMWorld::IdTable* mTable; + QAbstractItemModel* mTable; - CSMDoc::Document& mDocument; + CSMDoc::Document& mDocument; NotEditableSubDelegate mNotEditableDelegate; @@ -119,22 +119,25 @@ namespace CSVWorld public: DialogueDelegateDispatcher(QObject* parent, CSMWorld::IdTable* table, - CSMDoc::Document& document); + CSMDoc::Document& document, + QAbstractItemModel* model = 0); ~DialogueDelegateDispatcher(); CSVWorld::CommandDelegate* makeDelegate(CSMWorld::ColumnBase::Display display); - QWidget* makeEditor(CSMWorld::ColumnBase::Display display, - const QModelIndex& index); - ///< will return null if delegate is not present, parent of the widget is same as for dispatcher itself + QWidget* makeEditor(CSMWorld::ColumnBase::Display display, const QModelIndex& index); + ///< will return null if delegate is not present, parent of the widget is + //same as for dispatcher itself - virtual void setEditorData (QWidget* editor, - const QModelIndex& index) const; + virtual void setEditorData (QWidget* editor, const QModelIndex& index) const; - virtual void setModelData (QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const; + virtual void setModelData (QWidget* editor, QAbstractItemModel* model, + const QModelIndex& index) const; - virtual void setModelData (QWidget* editor, QAbstractItemModel* model, const QModelIndex& index, CSMWorld::ColumnBase::Display display) const; + virtual void setModelData (QWidget* editor, + QAbstractItemModel* model, const QModelIndex& index, + CSMWorld::ColumnBase::Display display) const; virtual void paint (QPainter* painter, const QStyleOptionViewItem& option, @@ -153,15 +156,15 @@ namespace CSVWorld void tableMimeDataDropped(QWidget* editor, const QModelIndex& index, const CSMWorld::UniversalId& id, const CSMDoc::Document* document); - - }; class EditWidget : public QScrollArea { Q_OBJECT QDataWidgetMapper *mWidgetMapper; + QDataWidgetMapper *mNestedTableMapper; DialogueDelegateDispatcher mDispatcher; + DialogueDelegateDispatcher *mNestedTableDispatcher; QWidget* mMainWidget; CSMWorld::IdTable* mTable; CSMDoc::Document& mDocument; diff --git a/apps/opencs/view/world/util.cpp b/apps/opencs/view/world/util.cpp index f3b23100a..5694c6e5a 100644 --- a/apps/opencs/view/world/util.cpp +++ b/apps/opencs/view/world/util.cpp @@ -180,7 +180,7 @@ QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleO case CSMWorld::ColumnBase::Display_Float: { QDoubleSpinBox *dsb = new QDoubleSpinBox(parent); - dsb->setRange(FLT_MIN, FLT_MAX); + dsb->setRange(-FLT_MAX, FLT_MAX); dsb->setSingleStep(0.01f); dsb->setDecimals(3); return dsb; From 4951fc477ca0ee0bee330f280ba613483d80a176 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 16 Apr 2015 18:50:22 +0200 Subject: [PATCH 0949/3725] added replace function --- apps/opencs/model/tools/reportmodel.cpp | 17 +++++- apps/opencs/model/tools/reportmodel.hpp | 4 +- apps/opencs/model/tools/search.cpp | 68 +++++++++++++++++++----- apps/opencs/model/tools/search.hpp | 12 +++-- apps/opencs/view/tools/reporttable.cpp | 59 +++++++++++++++++++- apps/opencs/view/tools/reporttable.hpp | 10 ++++ apps/opencs/view/tools/searchbox.cpp | 46 +++++++++++++--- apps/opencs/view/tools/searchbox.hpp | 6 +++ apps/opencs/view/tools/searchsubview.cpp | 37 +++++++++++-- apps/opencs/view/tools/searchsubview.hpp | 5 ++ 10 files changed, 234 insertions(+), 30 deletions(-) diff --git a/apps/opencs/model/tools/reportmodel.cpp b/apps/opencs/model/tools/reportmodel.cpp index 627199c22..5648ace54 100644 --- a/apps/opencs/model/tools/reportmodel.cpp +++ b/apps/opencs/model/tools/reportmodel.cpp @@ -80,7 +80,7 @@ QVariant CSMTools::ReportModel::data (const QModelIndex & index, int role) const char type, ignore; int fieldIndex; - if ((stream >> type >> ignore >> fieldIndex) && type=='r') + if ((stream >> type >> ignore >> fieldIndex) && (type=='r' || type=='R')) { field = CSMWorld::Columns::getName ( static_cast (fieldIndex)); @@ -135,6 +135,21 @@ void CSMTools::ReportModel::add (const CSMWorld::UniversalId& id, const std::str endInsertRows(); } +void CSMTools::ReportModel::flagAsReplaced (int index) +{ + Line& line = mRows.at (index); + std::string hint = line.mHint; + + if (hint.empty() || hint[0]!='R') + throw std::logic_error ("trying to flag message as replaced that is not replaceable"); + + hint[0] = 'r'; + + line.mHint = hint; + + emit dataChanged (this->index (index, 0), this->index (index, columnCount())); +} + const CSMWorld::UniversalId& CSMTools::ReportModel::getUniversalId (int row) const { return mRows.at (row).mId; diff --git a/apps/opencs/model/tools/reportmodel.hpp b/apps/opencs/model/tools/reportmodel.hpp index 7e733fab6..4d2d0542f 100644 --- a/apps/opencs/model/tools/reportmodel.hpp +++ b/apps/opencs/model/tools/reportmodel.hpp @@ -49,10 +49,12 @@ namespace CSMTools virtual QVariant headerData (int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; virtual bool removeRows (int row, int count, const QModelIndex& parent = QModelIndex()); - + void add (const CSMWorld::UniversalId& id, const std::string& message, const std::string& hint = ""); + void flagAsReplaced (int index); + const CSMWorld::UniversalId& getUniversalId (int row) const; std::string getHint (int row) const; diff --git a/apps/opencs/model/tools/search.cpp b/apps/opencs/model/tools/search.cpp index db495be11..cb8850754 100644 --- a/apps/opencs/model/tools/search.cpp +++ b/apps/opencs/model/tools/search.cpp @@ -4,14 +4,16 @@ #include #include -#include "../../model/doc/messages.hpp" +#include "../doc/messages.hpp" +#include "../doc/document.hpp" -#include "../../model/world/idtablebase.hpp" -#include "../../model/world/columnbase.hpp" -#include "../../model/world/universalid.hpp" +#include "../world/idtablebase.hpp" +#include "../world/columnbase.hpp" +#include "../world/universalid.hpp" +#include "../world/commands.hpp" void CSMTools::Search::searchTextCell (const CSMWorld::IdTableBase *model, - const QModelIndex& index, const CSMWorld::UniversalId& id, + const QModelIndex& index, const CSMWorld::UniversalId& id, bool writable, CSMDoc::Messages& messages) const { // using QString here for easier handling of case folding. @@ -25,7 +27,8 @@ void CSMTools::Search::searchTextCell (const CSMWorld::IdTableBase *model, { std::ostringstream hint; hint - << "r: " + << (writable ? 'R' : 'r') + <<": " << model->getColumnId (index.column()) << " " << pos << " " << search.length(); @@ -37,7 +40,7 @@ void CSMTools::Search::searchTextCell (const CSMWorld::IdTableBase *model, } void CSMTools::Search::searchRegExCell (const CSMWorld::IdTableBase *model, - const QModelIndex& index, const CSMWorld::UniversalId& id, + const QModelIndex& index, const CSMWorld::UniversalId& id, bool writable, CSMDoc::Messages& messages) const { QString text = model->data (index).toString(); @@ -49,7 +52,12 @@ void CSMTools::Search::searchRegExCell (const CSMWorld::IdTableBase *model, int length = mRegExp.matchedLength(); std::ostringstream hint; - hint << "r: " << model->getColumnId (index.column()) << " " << pos << " " << length; + hint + << (writable ? 'R' : 'r') + <<": " + << model->getColumnId (index.column()) + << " " << pos + << " " << length; messages.add (id, formatDescription (text, pos, length).toUtf8().data(), hint.str()); @@ -58,8 +66,11 @@ void CSMTools::Search::searchRegExCell (const CSMWorld::IdTableBase *model, } void CSMTools::Search::searchRecordStateCell (const CSMWorld::IdTableBase *model, - const QModelIndex& index, const CSMWorld::UniversalId& id, CSMDoc::Messages& messages) const + const QModelIndex& index, const CSMWorld::UniversalId& id, bool writable, CSMDoc::Messages& messages) const { + if (writable) + throw std::logic_error ("Record state can not be modified by search and replace"); + int data = model->data (index).toInt(); if (data==mValue) @@ -203,24 +214,26 @@ void CSMTools::Search::searchRow (const CSMWorld::IdTableBase *model, int row, CSMWorld::UniversalId id ( type, model->data (model->index (row, mIdColumn)).toString().toUtf8().data()); - + + bool writable = model->flags (index) & Qt::ItemIsEditable; + switch (mType) { case Type_Text: case Type_Id: - searchTextCell (model, index, id, messages); + searchTextCell (model, index, id, writable, messages); break; case Type_TextRegEx: case Type_IdRegEx: - searchRegExCell (model, index, id, messages); + searchRegExCell (model, index, id, writable, messages); break; case Type_RecordState: - searchRecordStateCell (model, index, id, messages); + searchRecordStateCell (model, index, id, writable, messages); break; case Type_None: @@ -235,3 +248,32 @@ void CSMTools::Search::setPadding (int before, int after) mPaddingBefore = before; mPaddingAfter = after; } + +void CSMTools::Search::replace (CSMDoc::Document& document, CSMWorld::IdTableBase *model, + const CSMWorld::UniversalId& id, const std::string& messageHint, + const std::string& replaceText) const +{ + std::istringstream stream (messageHint.c_str()); + + char hint, ignore; + int columnId, pos, length; + + if (stream >> hint >> ignore >> columnId >> pos >> length) + { + int column = + model->findColumnIndex (static_cast (columnId)); + + QModelIndex index = model->getModelIndex (id.getId(), column); + + std::string text = model->data (index).toString().toUtf8().constData(); + + std::string before = text.substr (0, pos); + std::string after = text.substr (pos+length); + + std::string newText = before + replaceText + after; + + document.getUndoStack().push ( + new CSMWorld::ModifyCommand (*model, index, QString::fromUtf8 (newText.c_str()))); + } +} + diff --git a/apps/opencs/model/tools/search.hpp b/apps/opencs/model/tools/search.hpp index 452b3cad2..c9dfc4c44 100644 --- a/apps/opencs/model/tools/search.hpp +++ b/apps/opencs/model/tools/search.hpp @@ -12,6 +12,7 @@ class QModelIndex; namespace CSMDoc { class Messages; + class Document; } namespace CSMWorld @@ -49,13 +50,13 @@ namespace CSMTools int mPaddingAfter; void searchTextCell (const CSMWorld::IdTableBase *model, const QModelIndex& index, - const CSMWorld::UniversalId& id, CSMDoc::Messages& messages) const; + const CSMWorld::UniversalId& id, bool writable, CSMDoc::Messages& messages) const; void searchRegExCell (const CSMWorld::IdTableBase *model, const QModelIndex& index, - const CSMWorld::UniversalId& id, CSMDoc::Messages& messages) const; + const CSMWorld::UniversalId& id, bool writable, CSMDoc::Messages& messages) const; void searchRecordStateCell (const CSMWorld::IdTableBase *model, - const QModelIndex& index, const CSMWorld::UniversalId& id, + const QModelIndex& index, const CSMWorld::UniversalId& id, bool writable, CSMDoc::Messages& messages) const; QString formatDescription (const QString& description, int pos, int length) const; @@ -82,6 +83,11 @@ namespace CSMTools CSMDoc::Messages& messages) const; void setPadding (int before, int after); + + // Configuring *this for the model is not necessary when calling this function. + void replace (CSMDoc::Document& document, CSMWorld::IdTableBase *model, + const CSMWorld::UniversalId& id, const std::string& messageHint, + const std::string& replaceText) const; }; } diff --git a/apps/opencs/view/tools/reporttable.cpp b/apps/opencs/view/tools/reporttable.cpp index 73fee2362..1b07d3c0f 100644 --- a/apps/opencs/view/tools/reporttable.cpp +++ b/apps/opencs/view/tools/reporttable.cpp @@ -56,8 +56,25 @@ void CSVTools::ReportTable::contextMenuEvent (QContextMenuEvent *event) { menu.addAction (mShowAction); menu.addAction (mRemoveAction); - } + bool found = false; + for (QModelIndexList::const_iterator iter (selectedRows.begin()); + iter!=selectedRows.end(); ++iter) + { + QString hint = mModel->data (mModel->index (iter->row(), 2)).toString(); + + if (!hint.isEmpty() && hint[0]=='R') + { + found = true; + break; + } + } + + if (found) + menu.addAction (mReplaceAction); + + } + menu.exec (event->globalPos()); } @@ -129,6 +146,10 @@ CSVTools::ReportTable::ReportTable (CSMDoc::Document& document, mRemoveAction = new QAction (tr ("Remove from list"), this); connect (mRemoveAction, SIGNAL (triggered()), this, SLOT (removeSelection())); addAction (mRemoveAction); + + mReplaceAction = new QAction (tr ("Replace"), this); + connect (mReplaceAction, SIGNAL (triggered()), this, SIGNAL (replaceRequest())); + addAction (mReplaceAction); } std::vector CSVTools::ReportTable::getDraggedRecords() const @@ -151,6 +172,42 @@ void CSVTools::ReportTable::updateUserSetting (const QString& name, const QStrin mIdTypeDelegate->updateUserSetting (name, list); } +std::vector CSVTools::ReportTable::getReplaceIndices (bool selection) const +{ + std::vector indices; + + if (selection) + { + QModelIndexList selectedRows = selectionModel()->selectedRows(); + + for (QModelIndexList::const_iterator iter (selectedRows.begin()); iter!=selectedRows.end(); + ++iter) + { + QString hint = mModel->data (mModel->index (iter->row(), 2)).toString(); + + if (!hint.isEmpty() && hint[0]=='R') + indices.push_back (iter->row()); + } + } + else + { + for (int i=0; irowCount(); ++i) + { + QString hint = mModel->data (mModel->index (i, 2)).toString(); + + if (!hint.isEmpty() && hint[0]=='R') + indices.push_back (i); + } + } + + return indices; +} + +void CSVTools::ReportTable::flagAsReplaced (int index) +{ + mModel->flagAsReplaced (index); +} + void CSVTools::ReportTable::showSelection() { QModelIndexList selectedRows = selectionModel()->selectedRows(); diff --git a/apps/opencs/view/tools/reporttable.hpp b/apps/opencs/view/tools/reporttable.hpp index dde6cc634..c4d5b414e 100644 --- a/apps/opencs/view/tools/reporttable.hpp +++ b/apps/opencs/view/tools/reporttable.hpp @@ -25,6 +25,7 @@ namespace CSVTools CSVWorld::CommandDelegate *mIdTypeDelegate; QAction *mShowAction; QAction *mRemoveAction; + QAction *mReplaceAction; private: @@ -46,6 +47,13 @@ namespace CSVTools void clear(); + // Return indices of rows that are suitable for replacement. + // + // \param selection Only list selected rows. + std::vector getReplaceIndices (bool selection) const; + + void flagAsReplaced (int index); + private slots: void showSelection(); @@ -55,6 +63,8 @@ namespace CSVTools signals: void editRequest (const CSMWorld::UniversalId& id, const std::string& hint); + + void replaceRequest(); }; } diff --git a/apps/opencs/view/tools/searchbox.cpp b/apps/opencs/view/tools/searchbox.cpp index 178dd1f04..1e92acb75 100644 --- a/apps/opencs/view/tools/searchbox.cpp +++ b/apps/opencs/view/tools/searchbox.cpp @@ -38,6 +38,9 @@ void CSVTools::SearchBox::updateSearchButton() CSVTools::SearchBox::SearchBox (QWidget *parent) : QWidget (parent), mSearch ("Search"), mSearchEnabled (false) { + mLayout = new QGridLayout (this); + + // search panel std::vector states = CSMWorld::Columns::getEnums (CSMWorld::Columns::ColumnId_Modification); states.resize (states.size()-1); // ignore erased state @@ -46,8 +49,6 @@ CSVTools::SearchBox::SearchBox (QWidget *parent) ++iter) mRecordState.addItem (QString::fromUtf8 (iter->c_str())); - mLayout = new QGridLayout (this); - mMode.addItem ("Text"); mMode.addItem ("Text (RegEx)"); mMode.addItem ("ID"); @@ -61,13 +62,8 @@ CSVTools::SearchBox::SearchBox (QWidget *parent) mInput.insertWidget (0, &mText); mInput.insertWidget (1, &mRecordState); - mLayout->addWidget (&mInput, 0, 1); - - mLayout->setColumnMinimumWidth (2, 50); - mLayout->setColumnStretch (1, 1); + mLayout->addWidget (&mInput, 0, 1); - mLayout->setContentsMargins (0, 0, 0, 0); - connect (&mMode, SIGNAL (activated (int)), this, SLOT (modeSelected (int))); connect (&mText, SIGNAL (textChanged (const QString&)), @@ -76,7 +72,20 @@ CSVTools::SearchBox::SearchBox (QWidget *parent) connect (&mSearch, SIGNAL (clicked (bool)), this, SLOT (startSearch (bool))); connect (&mText, SIGNAL (returnPressed()), this, SLOT (startSearch())); + + // replace panel + mReplaceInput.insertWidget (0, &mReplaceText); + mReplaceInput.insertWidget (1, &mReplacePlaceholder); + + mLayout->addWidget (&mReplaceInput, 1, 1); + + // layout adjustments + mLayout->setColumnMinimumWidth (2, 50); + mLayout->setColumnStretch (1, 1); + + mLayout->setContentsMargins (0, 0, 0, 0); + // update modeSelected (0); updateSearchButton(); @@ -116,6 +125,25 @@ CSMTools::Search CSVTools::SearchBox::getSearch() const throw std::logic_error ("invalid search mode index"); } +std::string CSVTools::SearchBox::getReplaceText() const +{ + CSMTools::Search::Type type = static_cast (mMode.currentIndex()); + + switch (type) + { + case CSMTools::Search::Type_Text: + case CSMTools::Search::Type_TextRegEx: + case CSMTools::Search::Type_Id: + case CSMTools::Search::Type_IdRegEx: + + return mReplaceText.text().toUtf8().data(); + + default: + + throw std::logic_error ("Invalid search mode for replace"); + } +} + void CSVTools::SearchBox::modeSelected (int index) { switch (index) @@ -126,10 +154,12 @@ void CSVTools::SearchBox::modeSelected (int index) case CSMTools::Search::Type_IdRegEx: mInput.setCurrentIndex (0); + mReplaceInput.setCurrentIndex (0); break; case CSMTools::Search::Type_RecordState: mInput.setCurrentIndex (1); + mReplaceInput.setCurrentIndex (1); break; } diff --git a/apps/opencs/view/tools/searchbox.hpp b/apps/opencs/view/tools/searchbox.hpp index 35c656d16..594788e6c 100644 --- a/apps/opencs/view/tools/searchbox.hpp +++ b/apps/opencs/view/tools/searchbox.hpp @@ -6,6 +6,7 @@ #include #include #include +#include class QGridLayout; @@ -27,6 +28,9 @@ namespace CSVTools QGridLayout *mLayout; QComboBox mMode; bool mSearchEnabled; + QStackedWidget mReplaceInput; + QLineEdit mReplaceText; + QLabel mReplacePlaceholder; private: @@ -40,6 +44,8 @@ namespace CSVTools CSMTools::Search getSearch() const; + std::string getReplaceText() const; + private slots: void modeSelected (int index); diff --git a/apps/opencs/view/tools/searchsubview.cpp b/apps/opencs/view/tools/searchsubview.cpp index 36fd65a2b..64827b737 100644 --- a/apps/opencs/view/tools/searchsubview.cpp +++ b/apps/opencs/view/tools/searchsubview.cpp @@ -5,6 +5,8 @@ #include "../../model/doc/document.hpp" #include "../../model/tools/search.hpp" +#include "../../model/tools/reportmodel.hpp" +#include "../../model/world/idtablebase.hpp" #include "reporttable.hpp" #include "searchbox.hpp" @@ -31,6 +33,8 @@ CSVTools::SearchSubView::SearchSubView (const CSMWorld::UniversalId& id, CSMDoc: connect (mTable, SIGNAL (editRequest (const CSMWorld::UniversalId&, const std::string&)), SIGNAL (focusId (const CSMWorld::UniversalId&, const std::string&))); + connect (mTable, SIGNAL (replaceRequest()), this, SLOT (replaceRequest())); + connect (&document, SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (stateChanged (int, CSMDoc::Document *))); @@ -63,9 +67,36 @@ void CSVTools::SearchSubView::stateChanged (int state, CSMDoc::Document *documen void CSVTools::SearchSubView::startSearch (const CSMTools::Search& search) { - CSMTools::Search search2 (search); - search2.setPadding (mPaddingBefore, mPaddingAfter); + mSearch = search; + mSearch.setPadding (mPaddingBefore, mPaddingAfter); mTable->clear(); - mDocument.runSearch (getUniversalId(), search2); + mDocument.runSearch (getUniversalId(), mSearch); +} + +void CSVTools::SearchSubView::replaceRequest() +{ + std::vector indices = mTable->getReplaceIndices (true); + + std::string replace = mSearchBox.getReplaceText(); + + const CSMTools::ReportModel& model = + dynamic_cast (*mTable->model()); + + // We are running through the indices in reverse order to avoid messing up multiple results + // in a single string. + for (std::vector::const_reverse_iterator iter (indices.rbegin()); iter!=indices.rend(); ++iter) + { + CSMWorld::UniversalId id = model.getUniversalId (*iter); + + CSMWorld::UniversalId::Type type = CSMWorld::UniversalId::getParentType (id.getType()); + + CSMWorld::IdTableBase *table = &dynamic_cast ( + *mDocument.getData().getTableModel (type)); + + std::string hint = model.getHint (*iter); + + mSearch.replace (mDocument, table, id, hint, replace); + mTable->flagAsReplaced (*iter); + } } diff --git a/apps/opencs/view/tools/searchsubview.hpp b/apps/opencs/view/tools/searchsubview.hpp index b9b24f774..125d0b927 100644 --- a/apps/opencs/view/tools/searchsubview.hpp +++ b/apps/opencs/view/tools/searchsubview.hpp @@ -1,6 +1,8 @@ #ifndef CSV_TOOLS_SEARCHSUBVIEW_H #define CSV_TOOLS_SEARCHSUBVIEW_H +#include "../../model/tools/search.hpp" + #include "../doc/subview.hpp" #include "searchbox.hpp" @@ -26,6 +28,7 @@ namespace CSVTools CSMDoc::Document& mDocument; int mPaddingBefore; int mPaddingAfter; + CSMTools::Search mSearch; public: @@ -40,6 +43,8 @@ namespace CSVTools void stateChanged (int state, CSMDoc::Document *document); void startSearch (const CSMTools::Search& search); + + void replaceRequest(); }; } From 36ce2d61f4aa9afccdceeb9e327ab5393080f37c Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 16 Apr 2015 19:02:03 +0200 Subject: [PATCH 0950/3725] consider lock mode when replacing --- apps/opencs/view/tools/searchsubview.cpp | 8 ++++++-- apps/opencs/view/tools/searchsubview.hpp | 1 + 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/tools/searchsubview.cpp b/apps/opencs/view/tools/searchsubview.cpp index 64827b737..0bdb9d658 100644 --- a/apps/opencs/view/tools/searchsubview.cpp +++ b/apps/opencs/view/tools/searchsubview.cpp @@ -12,7 +12,8 @@ #include "searchbox.hpp" CSVTools::SearchSubView::SearchSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) -: CSVDoc::SubView (id), mDocument (document), mPaddingBefore (10), mPaddingAfter (10) +: CSVDoc::SubView (id), mDocument (document), mPaddingBefore (10), mPaddingAfter (10), + mLocked (false) { QVBoxLayout *layout = new QVBoxLayout; @@ -44,7 +45,7 @@ CSVTools::SearchSubView::SearchSubView (const CSMWorld::UniversalId& id, CSMDoc: void CSVTools::SearchSubView::setEditLock (bool locked) { - // ignored. We don't change document state anyway. + mLocked = false; } void CSVTools::SearchSubView::updateUserSetting (const QString &name, const QStringList &list) @@ -76,6 +77,9 @@ void CSVTools::SearchSubView::startSearch (const CSMTools::Search& search) void CSVTools::SearchSubView::replaceRequest() { + if (mLocked) + return; + std::vector indices = mTable->getReplaceIndices (true); std::string replace = mSearchBox.getReplaceText(); diff --git a/apps/opencs/view/tools/searchsubview.hpp b/apps/opencs/view/tools/searchsubview.hpp index 125d0b927..59fbfe66e 100644 --- a/apps/opencs/view/tools/searchsubview.hpp +++ b/apps/opencs/view/tools/searchsubview.hpp @@ -29,6 +29,7 @@ namespace CSVTools int mPaddingBefore; int mPaddingAfter; CSMTools::Search mSearch; + bool mLocked; public: From b939fd440ee2ac3a4c1d3d91c8733bfb72694fef Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 16 Apr 2015 20:11:14 +0200 Subject: [PATCH 0951/3725] added replace all button --- apps/opencs/view/tools/searchbox.cpp | 16 +++++- apps/opencs/view/tools/searchbox.hpp | 7 +++ apps/opencs/view/tools/searchsubview.cpp | 65 ++++++++++++++---------- apps/opencs/view/tools/searchsubview.hpp | 6 +++ 4 files changed, 67 insertions(+), 27 deletions(-) diff --git a/apps/opencs/view/tools/searchbox.cpp b/apps/opencs/view/tools/searchbox.cpp index 1e92acb75..ca5520787 100644 --- a/apps/opencs/view/tools/searchbox.cpp +++ b/apps/opencs/view/tools/searchbox.cpp @@ -36,7 +36,7 @@ void CSVTools::SearchBox::updateSearchButton() } CSVTools::SearchBox::SearchBox (QWidget *parent) -: QWidget (parent), mSearch ("Search"), mSearchEnabled (false) +: QWidget (parent), mSearch ("Search"), mSearchEnabled (false), mReplace ("Replace All") { mLayout = new QGridLayout (this); @@ -78,12 +78,16 @@ CSVTools::SearchBox::SearchBox (QWidget *parent) mReplaceInput.insertWidget (1, &mReplacePlaceholder); mLayout->addWidget (&mReplaceInput, 1, 1); + + mLayout->addWidget (&mReplace, 1, 3); // layout adjustments mLayout->setColumnMinimumWidth (2, 50); mLayout->setColumnStretch (1, 1); mLayout->setContentsMargins (0, 0, 0, 0); + + connect (&mReplace, (SIGNAL (clicked (bool))), this, SLOT (replaceAll (bool))); // update modeSelected (0); @@ -144,6 +148,11 @@ std::string CSVTools::SearchBox::getReplaceText() const } } +void CSVTools::SearchBox::setEditLock (bool locked) +{ + mReplace.setEnabled (!locked); +} + void CSVTools::SearchBox::modeSelected (int index) { switch (index) @@ -176,3 +185,8 @@ void CSVTools::SearchBox::startSearch (bool checked) if (mSearch.isEnabled()) emit startSearch (getSearch()); } + +void CSVTools::SearchBox::replaceAll (bool checked) +{ + emit replaceAll(); +} diff --git a/apps/opencs/view/tools/searchbox.hpp b/apps/opencs/view/tools/searchbox.hpp index 594788e6c..433c09693 100644 --- a/apps/opencs/view/tools/searchbox.hpp +++ b/apps/opencs/view/tools/searchbox.hpp @@ -31,6 +31,7 @@ namespace CSVTools QStackedWidget mReplaceInput; QLineEdit mReplaceText; QLabel mReplacePlaceholder; + QPushButton mReplace; private: @@ -46,6 +47,8 @@ namespace CSVTools std::string getReplaceText() const; + void setEditLock (bool locked); + private slots: void modeSelected (int index); @@ -54,9 +57,13 @@ namespace CSVTools void startSearch (bool checked = true); + void replaceAll (bool checked); + signals: void startSearch (const CSMTools::Search& search); + + void replaceAll(); }; } diff --git a/apps/opencs/view/tools/searchsubview.cpp b/apps/opencs/view/tools/searchsubview.cpp index 0bdb9d658..5743ad761 100644 --- a/apps/opencs/view/tools/searchsubview.cpp +++ b/apps/opencs/view/tools/searchsubview.cpp @@ -11,6 +11,36 @@ #include "reporttable.hpp" #include "searchbox.hpp" +void CSVTools::SearchSubView::replace (bool selection) +{ + if (mLocked) + return; + + std::vector indices = mTable->getReplaceIndices (selection); + + std::string replace = mSearchBox.getReplaceText(); + + const CSMTools::ReportModel& model = + dynamic_cast (*mTable->model()); + + // We are running through the indices in reverse order to avoid messing up multiple results + // in a single string. + for (std::vector::const_reverse_iterator iter (indices.rbegin()); iter!=indices.rend(); ++iter) + { + CSMWorld::UniversalId id = model.getUniversalId (*iter); + + CSMWorld::UniversalId::Type type = CSMWorld::UniversalId::getParentType (id.getType()); + + CSMWorld::IdTableBase *table = &dynamic_cast ( + *mDocument.getData().getTableModel (type)); + + std::string hint = model.getHint (*iter); + + mSearch.replace (mDocument, table, id, hint, replace); + mTable->flagAsReplaced (*iter); + } +} + CSVTools::SearchSubView::SearchSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) : CSVDoc::SubView (id), mDocument (document), mPaddingBefore (10), mPaddingAfter (10), mLocked (false) @@ -41,11 +71,14 @@ CSVTools::SearchSubView::SearchSubView (const CSMWorld::UniversalId& id, CSMDoc: connect (&mSearchBox, SIGNAL (startSearch (const CSMTools::Search&)), this, SLOT (startSearch (const CSMTools::Search&))); + + connect (&mSearchBox, SIGNAL (replaceAll()), this, SLOT (replaceAllRequest())); } void CSVTools::SearchSubView::setEditLock (bool locked) { - mLocked = false; + mLocked = locked; + mSearchBox.setEditLock (locked); } void CSVTools::SearchSubView::updateUserSetting (const QString &name, const QStringList &list) @@ -77,30 +110,10 @@ void CSVTools::SearchSubView::startSearch (const CSMTools::Search& search) void CSVTools::SearchSubView::replaceRequest() { - if (mLocked) - return; - - std::vector indices = mTable->getReplaceIndices (true); - - std::string replace = mSearchBox.getReplaceText(); - - const CSMTools::ReportModel& model = - dynamic_cast (*mTable->model()); - - // We are running through the indices in reverse order to avoid messing up multiple results - // in a single string. - for (std::vector::const_reverse_iterator iter (indices.rbegin()); iter!=indices.rend(); ++iter) - { - CSMWorld::UniversalId id = model.getUniversalId (*iter); - - CSMWorld::UniversalId::Type type = CSMWorld::UniversalId::getParentType (id.getType()); + replace (true); +} - CSMWorld::IdTableBase *table = &dynamic_cast ( - *mDocument.getData().getTableModel (type)); - - std::string hint = model.getHint (*iter); - - mSearch.replace (mDocument, table, id, hint, replace); - mTable->flagAsReplaced (*iter); - } +void CSVTools::SearchSubView::replaceAllRequest() +{ + replace (false); } diff --git a/apps/opencs/view/tools/searchsubview.hpp b/apps/opencs/view/tools/searchsubview.hpp index 59fbfe66e..eeefa9afb 100644 --- a/apps/opencs/view/tools/searchsubview.hpp +++ b/apps/opencs/view/tools/searchsubview.hpp @@ -31,6 +31,10 @@ namespace CSVTools CSMTools::Search mSearch; bool mLocked; + private: + + void replace (bool selection); + public: SearchSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document); @@ -46,6 +50,8 @@ namespace CSVTools void startSearch (const CSMTools::Search& search); void replaceRequest(); + + void replaceAllRequest(); }; } From 083c41c9503ecf4d75e0a3fd2b02c483c29a4bae Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 17 Apr 2015 01:23:37 +0200 Subject: [PATCH 0952/3725] Environment map for enchanted objects --- apps/openmw/engine.cpp | 1 - apps/openmw/mwrender/animation.cpp | 98 +++++++++++++++++++++++++- apps/openmw/mwrender/animation.hpp | 4 ++ apps/openmw/mwrender/npcanimation.cpp | 52 +++----------- apps/openmw/mwrender/npcanimation.hpp | 6 +- apps/openmw/mwrender/objects.cpp | 4 +- components/resource/resourcesystem.cpp | 5 ++ components/resource/resourcesystem.hpp | 1 + 8 files changed, 123 insertions(+), 48 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index f6f2ba9bb..9a7f023e6 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -491,7 +491,6 @@ void OMW::Engine::go() mViewer.setCameraManipulator(new osgGA::TrackballManipulator); mViewer.addEventHandler(new osgViewer::StatsHandler); - osg::Timer timer; mViewer.realize(); osg::Timer frameTimer; while (!mViewer.done()) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 4352520db..3aeaa2ed1 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1,11 +1,68 @@ #include "animation.hpp" +#include +#include +#include + #include #include #include +#include -#include +#include + +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" +#include "../mwworld/esmstore.hpp" +#include "../mwworld/class.hpp" + +namespace +{ + + class GlowUpdater : public SceneUtil::StateSetUpdater + { + public: + GlowUpdater(osg::Vec4f color, const std::vector >& textures) + : mTexUnit(1) // FIXME: might not always be 1 + , mColor(color) + , mTextures(textures) + { + } + + virtual void setDefaults(osg::StateSet *stateset) + { + stateset->setTextureMode(mTexUnit, GL_TEXTURE_2D, osg::StateAttribute::ON); + + osg::TexGen* texGen = new osg::TexGen; + texGen->setMode(osg::TexGen::SPHERE_MAP); + + stateset->setTextureAttributeAndModes(mTexUnit, texGen, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + + osg::TexEnvCombine* texEnv = new osg::TexEnvCombine; + texEnv->setSource0_RGB(osg::TexEnvCombine::CONSTANT); + texEnv->setConstantColor(mColor); + texEnv->setCombine_RGB(osg::TexEnvCombine::INTERPOLATE); + texEnv->setSource2_RGB(osg::TexEnvCombine::TEXTURE); + texEnv->setOperand2_RGB(osg::TexEnvCombine::SRC_COLOR); + + stateset->setTextureAttributeAndModes(mTexUnit, texEnv, osg::StateAttribute::ON); + } + + virtual void apply(osg::StateSet *stateset, osg::NodeVisitor *nv) + { + float time = nv->getFrameStamp()->getSimulationTime(); + int index = (int)(time*16) % mTextures.size(); + stateset->setTextureAttribute(mTexUnit, mTextures[index], osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + } + + private: + int mTexUnit; + osg::Vec4f mColor; + std::vector > mTextures; + }; + +} namespace MWRender { @@ -54,6 +111,42 @@ namespace MWRender return static_cast(mObjectRoot.get()); } + void Animation::addGlow(osg::ref_ptr node, osg::Vec4f glowColor) + { + std::vector > textures; + for (int i=0; i<32; ++i) + { + std::stringstream stream; + stream << "textures/magicitem/caust"; + stream << std::setw(2); + stream << std::setfill('0'); + stream << i; + stream << ".dds"; + + textures.push_back(mResourceSystem->getTextureManager()->getTexture2D(stream.str(), osg::Texture2D::REPEAT, osg::Texture2D::REPEAT)); + } + + osg::ref_ptr glowupdater (new GlowUpdater(glowColor, textures)); + node->addUpdateCallback(glowupdater); + } + + // TODO: Should not be here + osg::Vec4f Animation::getEnchantmentColor(MWWorld::Ptr item) + { + osg::Vec4f result(1,1,1,1); + std::string enchantmentName = item.getClass().getEnchantment(item); + if (enchantmentName.empty()) + return result; + const ESM::Enchantment* enchantment = MWBase::Environment::get().getWorld()->getStore().get().find(enchantmentName); + assert (enchantment->mEffects.mList.size()); + const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get().find( + enchantment->mEffects.mList.front().mEffectID); + result.x() = magicEffect->mData.mRed / 255.f; + result.y() = magicEffect->mData.mGreen / 255.f; + result.z() = magicEffect->mData.mBlue / 255.f; + return result; + } + // -------------------------------------------------------------------------------- ObjectAnimation::ObjectAnimation(const MWWorld::Ptr &ptr, const std::string &model, Resource::ResourceSystem* resourceSystem) @@ -62,6 +155,9 @@ namespace MWRender if (!model.empty()) { setObjectRoot(model); + + if (!ptr.getClass().getEnchantment(ptr).empty()) + addGlow(mObjectRoot, getEnchantmentColor(ptr)); } else { diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 34173c29c..1feab7bf3 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -172,6 +172,10 @@ protected: //void clearAnimSources(); + osg::Vec4f getEnchantmentColor(MWWorld::Ptr item); + + void addGlow(osg::ref_ptr node, osg::Vec4f glowColor); + public: Animation(const MWWorld::Ptr &ptr, osg::ref_ptr parentNode, Resource::ResourceSystem* resourceSystem); diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index fe16fa06e..e30c701fc 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -328,8 +328,8 @@ void NpcAnimation::updateNpcBase() void NpcAnimation::updateParts() { - //if (!mSkelBase) - // return; + if (!mObjectRoot.get()) + return; mAlpha = 1.f; const MWWorld::Class &cls = mPtr.getClass(); @@ -386,8 +386,7 @@ void NpcAnimation::updateParts() int prio = 1; bool enchantedGlow = !store->getClass().getEnchantment(*store).empty(); - //Ogre::Vector3 glowColor = getEnchantmentColor(*store); - Ogre::Vector3 glowColor (1,1,1); + osg::Vec4f glowColor = getEnchantmentColor(*store); if(store->getTypeName() == typeid(ESM::Clothing).name()) { prio = ((slotlist[i].mBasePriority+1)<<1) + 0; @@ -588,44 +587,15 @@ public: } }; -PartHolderPtr NpcAnimation::insertBoundedPart(const std::string& model, int group, const std::string& bonename, const std::string& bonefilter, bool enchantedGlow, Ogre::Vector3* glowColor) +PartHolderPtr NpcAnimation::insertBoundedPart(const std::string& model, int group, const std::string& bonename, const std::string& bonefilter, bool enchantedGlow, osg::Vec4f* glowColor) { osg::ref_ptr instance = mResourceSystem->getSceneManager()->createInstance(model); -std::cout << "inserting " << model << std::endl; osg::ref_ptr attached = SceneUtil::attach(instance, mObjectRoot, bonefilter, bonename); + if (enchantedGlow) + addGlow(attached, *glowColor); return PartHolderPtr(new PartHolder(attached)); } -/* -NifOgre::ObjectScenePtr NpcAnimation::insertBoundedPart(const std::string &model, int group, const std::string &bonename, const std::string &bonefilter, bool enchantedGlow, Ogre::Vector3* glowColor) -{ - NifOgre::ObjectScenePtr objects = NifOgre::Loader::createObjects(mSkelBase, bonename, bonefilter, mInsert, model); - setRenderProperties(objects, (mViewMode == VM_FirstPerson) ? RV_FirstPerson : mVisibilityFlags, RQG_Main, RQG_Alpha, 0, - enchantedGlow, glowColor); - - std::for_each(objects->mEntities.begin(), objects->mEntities.end(), SetObjectGroup(group)); - std::for_each(objects->mParticles.begin(), objects->mParticles.end(), SetObjectGroup(group)); - - if(objects->mSkelBase) - { - Ogre::AnimationStateSet *aset = objects->mSkelBase->getAllAnimationStates(); - Ogre::AnimationStateIterator asiter = aset->getAnimationStateIterator(); - while(asiter.hasMoreElements()) - { - Ogre::AnimationState *state = asiter.getNext(); - state->setEnabled(false); - state->setLoop(false); - } - Ogre::SkeletonInstance *skelinst = objects->mSkelBase->getSkeleton(); - Ogre::Skeleton::BoneIterator boneiter = skelinst->getBoneIterator(); - while(boneiter.hasMoreElements()) - boneiter.getNext()->setManuallyControlled(true); - } - - return objects; -} -*/ - /* Ogre::Vector3 NpcAnimation::runAnimation(float timepassed) { @@ -684,7 +654,7 @@ void NpcAnimation::removeIndividualPart(ESM::PartReferenceType type) mPartPriorities[type] = 0; mPartslots[type] = -1; - //mObjectParts[type].setNull(); + mObjectParts[type].reset(); if (!mSoundIds[type].empty() && !mSoundsDisabled) { MWBase::Environment::get().getSoundManager()->stopSound3D(mPtr, mSoundIds[type]); @@ -711,7 +681,7 @@ void NpcAnimation::removePartGroup(int group) } } -bool NpcAnimation::addOrReplaceIndividualPart(ESM::PartReferenceType type, int group, int priority, const std::string &mesh, bool enchantedGlow, Ogre::Vector3* glowColor) +bool NpcAnimation::addOrReplaceIndividualPart(ESM::PartReferenceType type, int group, int priority, const std::string &mesh, bool enchantedGlow, osg::Vec4f* glowColor) { if(priority <= mPartPriorities[type]) return false; @@ -804,7 +774,7 @@ bool NpcAnimation::addOrReplaceIndividualPart(ESM::PartReferenceType type, int g return true; } -void NpcAnimation::addPartGroup(int group, int priority, const std::vector &parts, bool enchantedGlow, Ogre::Vector3* glowColor) +void NpcAnimation::addPartGroup(int group, int priority, const std::vector &parts, bool enchantedGlow, osg::Vec4f* glowColor) { const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); const MWWorld::Store &partStore = store.get(); @@ -861,7 +831,7 @@ void NpcAnimation::showWeapons(bool showWeapon) MWWorld::ContainerStoreIterator weapon = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); if(weapon != inv.end()) { - Ogre::Vector3 glowColor (1,1,1); //= getEnchantmentColor(*weapon); + osg::Vec4f glowColor = getEnchantmentColor(*weapon); std::string mesh = weapon->getClass().getModel(*weapon); addOrReplaceIndividualPart(ESM::PRT_Weapon, MWWorld::InventoryStore::Slot_CarriedRight, 1, mesh, !weapon->getClass().getEnchantment(*weapon).empty(), &glowColor); @@ -894,7 +864,7 @@ void NpcAnimation::showCarriedLeft(bool show) MWWorld::ContainerStoreIterator iter = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft); if(show && iter != inv.end()) { - Ogre::Vector3 glowColor(1,1,1);// = getEnchantmentColor(*iter); + osg::Vec4f glowColor = getEnchantmentColor(*iter); std::string mesh = iter->getClass().getModel(*iter); if (addOrReplaceIndividualPart(ESM::PRT_Shield, MWWorld::InventoryStore::Slot_CarriedLeft, 1, mesh, !iter->getClass().getEnchantment(*iter).empty(), &glowColor)) diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 28ac6509b..2605d58e3 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -128,16 +128,16 @@ private: void updateNpcBase(); PartHolderPtr insertBoundedPart(const std::string &model, int group, const std::string &bonename, - const std::string &bonefilter, bool enchantedGlow, Ogre::Vector3* glowColor=NULL); + const std::string &bonefilter, bool enchantedGlow, osg::Vec4f* glowColor=NULL); void removeIndividualPart(ESM::PartReferenceType type); void reserveIndividualPart(ESM::PartReferenceType type, int group, int priority); bool addOrReplaceIndividualPart(ESM::PartReferenceType type, int group, int priority, const std::string &mesh, - bool enchantedGlow=false, Ogre::Vector3* glowColor=NULL); + bool enchantedGlow=false, osg::Vec4f* glowColor=NULL); void removePartGroup(int group); void addPartGroup(int group, int priority, const std::vector &parts, - bool enchantedGlow=false, Ogre::Vector3* glowColor=NULL); + bool enchantedGlow=false, osg::Vec4f* glowColor=NULL); //void applyAlpha(float alpha, Ogre::Entity* ent, NifOgre::ObjectScenePtr scene); diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 322d02e94..21d7c1ab5 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -166,10 +166,10 @@ void Objects::insertModel(const MWWorld::Ptr &ptr, const std::string &mesh, bool osg::Light* light = new osg::Light; lightSource->setLight(light); - float realRadius = esmLight->mData.mRadius * 2; + float realRadius = esmLight->mData.mRadius; lightSource->setRadius(realRadius); - light->setLinearAttenuation(10.f/realRadius); + light->setLinearAttenuation(10.f/(esmLight->mData.mRadius*2.f)); //light->setLinearAttenuation(0.05); light->setConstantAttenuation(0.f); diff --git a/components/resource/resourcesystem.cpp b/components/resource/resourcesystem.cpp index 215b1a67c..acde8f5d2 100644 --- a/components/resource/resourcesystem.cpp +++ b/components/resource/resourcesystem.cpp @@ -18,6 +18,11 @@ namespace Resource return mSceneManager.get(); } + TextureManager* ResourceSystem::getTextureManager() + { + return mTextureManager.get(); + } + const VFS::Manager* ResourceSystem::getVFS() const { return mVFS; diff --git a/components/resource/resourcesystem.hpp b/components/resource/resourcesystem.hpp index a91f3cab3..3bb454785 100644 --- a/components/resource/resourcesystem.hpp +++ b/components/resource/resourcesystem.hpp @@ -23,6 +23,7 @@ namespace Resource ResourceSystem(const VFS::Manager* vfs); SceneManager* getSceneManager(); + TextureManager* getTextureManager(); const VFS::Manager* getVFS() const; From 32e73c3debf67f5cfb64671daca1c32b8d12dd4a Mon Sep 17 00:00:00 2001 From: cc9cii Date: Fri, 17 Apr 2015 11:50:19 +1000 Subject: [PATCH 0953/3725] Add creature/item levelled lists (non table items) to dialogue subview. --- apps/opencs/model/world/columns.cpp | 88 ++++++------- apps/opencs/model/world/columns.hpp | 2 + apps/opencs/model/world/refidadapterimp.hpp | 131 +++++++++++++++++++- apps/opencs/model/world/refidcollection.cpp | 14 +++ 4 files changed, 191 insertions(+), 44 deletions(-) diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 83d6ceb57..81968d114 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -223,49 +223,51 @@ namespace CSMWorld { ColumnId_AreaSound, "Area Sound" }, { ColumnId_BoltSound, "Bolt Sound" }, - { ColumnId_PathgridPoints, "Points"}, - { ColumnId_PathgridIndex, "Index"}, - { ColumnId_PathgridPosX, "X"}, - { ColumnId_PathgridPosY, "Y"}, - { ColumnId_PathgridPosZ, "Z"}, - { ColumnId_PathgridEdges, "Edges"}, - { ColumnId_PathgridEdgeIndex, "Index"}, - { ColumnId_PathgridEdge0, "Point 0"}, - { ColumnId_PathgridEdge1, "Point 1"}, - - { ColumnId_RegionSounds, "Sounds"}, - { ColumnId_SoundName, "Name"}, - { ColumnId_SoundChance, "Chance"}, - - { ColumnId_FactionReactions, "Reactions"}, - //{ ColumnId_FactionID, "Faction ID"}, - { ColumnId_FactionReaction, "Reaction"}, - - { ColumnId_EffectList, "Effects"}, - { ColumnId_EffectId, "Effect"}, - //{ ColumnId_EffectAttribute, "Attrib"}, - { ColumnId_EffectRange, "Range"}, - { ColumnId_EffectArea, "Area"}, - - { ColumnId_AiPackageList, "Ai Packages"}, - { ColumnId_AiPackage, "Package"}, - { ColumnId_AiWanderDist, "Wander Dist"}, - { ColumnId_AiDuration, "Duration"}, - { ColumnId_AiWanderToD, "Wander ToD"}, - { ColumnId_AiWanderIdle, "Wander Idle"}, - { ColumnId_AiWanderRepeat, "Wander Repeat"}, - { ColumnId_AiActivateName, "Activate"}, - { ColumnId_AiTargetId, "Target ID"}, - { ColumnId_AiTargetCell, "Target Cell"}, - - { ColumnId_PartRefList, "Part Reference"}, - { ColumnId_PartRefType, "Type"}, - { ColumnId_PartRefMale, "Male"}, - { ColumnId_PartRefFemale, "Female"}, - - { ColumnId_LevelledList,"Levelled List"}, - { ColumnId_LevelledItemId,"Item ID"}, - { ColumnId_LevelledItemLevel,"Level"}, + { ColumnId_PathgridPoints, "Points" }, + { ColumnId_PathgridIndex, "Index" }, + { ColumnId_PathgridPosX, "X" }, + { ColumnId_PathgridPosY, "Y" }, + { ColumnId_PathgridPosZ, "Z" }, + { ColumnId_PathgridEdges, "Edges" }, + { ColumnId_PathgridEdgeIndex, "Index" }, + { ColumnId_PathgridEdge0, "Point 0" }, + { ColumnId_PathgridEdge1, "Point 1" }, + + { ColumnId_RegionSounds, "Sounds" }, + { ColumnId_SoundName, "Name" }, + { ColumnId_SoundChance, "Chance" }, + + { ColumnId_FactionReactions, "Reactions" }, + //{ ColumnId_FactionID, "Faction ID" }, + { ColumnId_FactionReaction, "Reaction" }, + + { ColumnId_EffectList, "Effects" }, + { ColumnId_EffectId, "Effect" }, + //{ ColumnId_EffectAttribute, "Attrib" }, + { ColumnId_EffectRange, "Range" }, + { ColumnId_EffectArea, "Area" }, + + { ColumnId_AiPackageList, "Ai Packages" }, + { ColumnId_AiPackage, "Package" }, + { ColumnId_AiWanderDist, "Wander Dist" }, + { ColumnId_AiDuration, "Duration" }, + { ColumnId_AiWanderToD, "Wander ToD" }, + { ColumnId_AiWanderIdle, "Wander Idle" }, + { ColumnId_AiWanderRepeat, "Wander Repeat" }, + { ColumnId_AiActivateName, "Activate" }, + { ColumnId_AiTargetId, "Target ID" }, + { ColumnId_AiTargetCell, "Target Cell" }, + + { ColumnId_PartRefList, "Part Reference" }, + { ColumnId_PartRefType, "Type" }, + { ColumnId_PartRefMale, "Male" }, + { ColumnId_PartRefFemale, "Female" }, + + { ColumnId_LevelledList,"Levelled List" }, + { ColumnId_LevelledItemId,"Item ID" }, + { ColumnId_LevelledItemLevel,"Level" }, + { ColumnId_LevelledItemType, "Type" }, + { ColumnId_LevelledItemChanceNone, "Chance None" }, { ColumnId_UseValue1, "Use value 1" }, { ColumnId_UseValue2, "Use value 2" }, diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 81cae5e36..986b90df5 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -256,6 +256,8 @@ namespace CSMWorld ColumnId_LevelledList = 233, ColumnId_LevelledItemId = 234, ColumnId_LevelledItemLevel = 235, + ColumnId_LevelledItemType = 236, + ColumnId_LevelledItemChanceNone = 237, // Allocated to a separate value range, so we don't get a collision should we ever need // to extend the number of use values. diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index d09aaaa45..2b2b189e0 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -1829,9 +1829,11 @@ namespace CSMWorld } }; + struct LevListColumns : public BaseColumns { const RefIdColumn *mLevList; + const RefIdColumn *mNestedListLevList; LevListColumns (const BaseColumns& base) : BaseColumns (base) {} }; @@ -1863,7 +1865,7 @@ namespace CSMWorld QVariant LevelledListRefIdAdapter::getData (const RefIdColumn *column, const RefIdData& data, int index) const { - if (column==mLevList.mLevList) + if (column==mLevList.mLevList || column == mLevList.mNestedListLevList) return true; // to show nested tables in dialogue subview, see IdTree::hasChildren() return BaseRefIdAdapter::getData (column, data, index); @@ -1877,6 +1879,133 @@ namespace CSMWorld return; } + + template + class NestedListLevListRefIdAdapter : public NestedRefIdAdapterBase + { + + UniversalId::Type mType; + + // not implemented + NestedListLevListRefIdAdapter (const NestedListLevListRefIdAdapter&); + NestedListLevListRefIdAdapter& operator= (const NestedListLevListRefIdAdapter&); + + public: + + NestedListLevListRefIdAdapter(UniversalId::Type type) + :mType(type) {} + + virtual ~NestedListLevListRefIdAdapter() {} + + virtual void addNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int position) const + { + throw std::logic_error ("cannot add a row to a fixed table"); + } + + virtual void removeNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int rowToRemove) const + { + throw std::logic_error ("cannot remove a row to a fixed table"); + } + + virtual void setNestedTable (const RefIdColumn* column, + RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const + { + throw std::logic_error ("table operation not supported"); + } + + virtual NestedTableWrapperBase* nestedTable (const RefIdColumn* column, + const RefIdData& data, int index) const + { + throw std::logic_error ("table operation not supported"); + } + + virtual QVariant getNestedData (const RefIdColumn *column, + const RefIdData& data, int index, int subRowIndex, int subColIndex) const + { + const Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + + switch (subColIndex) + { + case 0: + { + if (mType == CSMWorld::UniversalId::Type_CreatureLevelledList && + record.get().mFlags == 0x01) + { + return QString("All Levels"); + } + else if(mType == CSMWorld::UniversalId::Type_ItemLevelledList && + record.get().mFlags == 0x01) + { + return QString("Each"); + } + else if(mType == CSMWorld::UniversalId::Type_ItemLevelledList && + record.get().mFlags == 0x02) + { + return QString("All Levels"); + } + else + throw std::runtime_error("unknown leveled list type"); + } + case 1: return static_cast (record.get().mChanceNone); + default: + throw std::runtime_error("Trying to access non-existing column in the nested table!"); + } + } + + virtual void setNestedData (const RefIdColumn *column, + RefIdData& data, int row, const QVariant& value, int subRowIndex, int subColIndex) const + { + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (row, mType))); + ESXRecordT leveled = record.get(); + + switch(subColIndex) + { + case 0: + { + if (mType == CSMWorld::UniversalId::Type_CreatureLevelledList && + value.toString().toStdString() == "All Levels") + { + leveled.mFlags = 0x01; + break; + } + else if(mType == CSMWorld::UniversalId::Type_ItemLevelledList && + value.toString().toStdString() == "Each") + { + leveled.mFlags = 0x01; + break; + } + else if(mType == CSMWorld::UniversalId::Type_ItemLevelledList && + value.toString().toStdString() == "All Levels") + { + leveled.mFlags = 0x02; + break; + } + else + return; // return without saving + } + case 1: leveled.mChanceNone = static_cast(value.toInt()); break; + default: + throw std::runtime_error("Trying to access non-existing column in the nested table!"); + } + + record.setModified (leveled); + } + + virtual int getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const + { + return 2; + } + + virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const + { + return 1; // fixed at size 1 + } + }; + template class NestedLevListRefIdAdapter : public NestedRefIdAdapterBase { diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index be5d67766..02d876df8 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -503,6 +503,20 @@ CSMWorld::RefIdCollection::RefIdCollection() mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_LevelledItemLevel, CSMWorld::ColumnBase::Display_Integer)); + // Nested list + mColumns.push_back(RefIdColumn (Columns::ColumnId_LevelledList, + ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue | ColumnBase::Flag_Dialogue_List)); + levListColumns.mNestedListLevList = &mColumns.back(); + std::map nestedListLevListMap; + nestedListLevListMap.insert(std::make_pair(UniversalId::Type_CreatureLevelledList, + new NestedListLevListRefIdAdapter (UniversalId::Type_CreatureLevelledList))); + nestedListLevListMap.insert(std::make_pair(UniversalId::Type_ItemLevelledList, + new NestedListLevListRefIdAdapter (UniversalId::Type_ItemLevelledList))); + mNestedAdapters.push_back (std::make_pair(&mColumns.back(), nestedListLevListMap)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_LevelledItemType, CSMWorld::ColumnBase::Display_String)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_LevelledItemChanceNone, CSMWorld::ColumnBase::Display_Integer)); mAdapters.insert (std::make_pair (UniversalId::Type_Activator, new NameRefIdAdapter (UniversalId::Type_Activator, nameColumns))); From c41b4b84a6b9421496cc1a66e34a84e1b9434b31 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Fri, 17 Apr 2015 13:45:45 +1000 Subject: [PATCH 0954/3725] Cleanup post merge. --- apps/opencs/model/world/columnbase.hpp | 16 +++++----------- apps/opencs/model/world/columns.cpp | 2 ++ apps/opencs/model/world/columns.hpp | 2 ++ apps/opencs/model/world/data.cpp | 4 ++-- apps/opencs/model/world/refidcollection.cpp | 8 ++++---- 5 files changed, 15 insertions(+), 17 deletions(-) diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index 197fb5ad3..437d07f97 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -93,15 +93,6 @@ namespace CSMWorld Display_RefRecordType, Display_DialogueType, Display_QuestStatusType, - - //Those are top level columns that nest other columns - Display_NestedItemList, // delete? - Display_NestedSpellList, // delete? - Display_NestedDestinationsList, // delete? - Display_PathgridPointList, // delete? - Display_PathgridEdgeList, // delete? - Display_NestedHeader, - Display_EnchantmentType, Display_BodyPartType, Display_MeshType, @@ -117,7 +108,10 @@ namespace CSMWorld Display_ScriptLines, // console context Display_SoundGeneratorType, Display_School, - Display_Id + Display_Id, + + //top level columns that nest other columns + Display_NestedHeader }; int mColumnId; @@ -135,7 +129,7 @@ namespace CSMWorld virtual std::string getTitle() const; - virtual int getId() const; // FIXME: why have an accessor for a public member? + virtual int getId() const; static bool isId (Display display); diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 81968d114..ff28a1289 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -269,6 +269,8 @@ namespace CSMWorld { ColumnId_LevelledItemType, "Type" }, { ColumnId_LevelledItemChanceNone, "Chance None" }, + { ColumnId_PowerList, "Powers" }, + { ColumnId_UseValue1, "Use value 1" }, { ColumnId_UseValue2, "Use value 2" }, { ColumnId_UseValue3, "Use value 3" }, diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 986b90df5..7c28f9589 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -259,6 +259,8 @@ namespace CSMWorld ColumnId_LevelledItemType = 236, ColumnId_LevelledItemChanceNone = 237, + ColumnId_PowerList = 238, + // Allocated to a separate value range, so we don't get a collision should we ever need // to extend the number of use values. ColumnId_UseValue1 = 0x10000, diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index d7280e354..5733fd83f 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -131,7 +131,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mRaces.addColumn (new WeightHeightColumn (false, true)); mRaces.addColumn (new WeightHeightColumn (false, false)); // Race spells - mRaces.addColumn (new NestedParentColumn (Columns::ColumnId_SpellList)); + mRaces.addColumn (new NestedParentColumn (Columns::ColumnId_PowerList)); index = mRaces.getColumns()-1; mRaces.addAdapter (std::make_pair(&mRaces.getColumn(index), new SpellListAdapter ())); mRaces.getNestableColumn(index)->addColumn( @@ -172,7 +172,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mBirthsigns.addColumn (new TextureColumn); mBirthsigns.addColumn (new DescriptionColumn); // Birthsign spells - mBirthsigns.addColumn (new NestedParentColumn (Columns::ColumnId_SpellList)); + mBirthsigns.addColumn (new NestedParentColumn (Columns::ColumnId_PowerList)); index = mBirthsigns.getColumns()-1; mBirthsigns.addAdapter (std::make_pair(&mBirthsigns.getColumn(index), new SpellListAdapter ())); diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index d133f3ba9..2e53c2b1c 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -126,7 +126,7 @@ CSMWorld::RefIdCollection::RefIdCollection() // Nested table mColumns.push_back(RefIdColumn (Columns::ColumnId_ActorInventory, - ColumnBase::Display_NestedItemList, ColumnBase::Flag_Dialogue)); + ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue)); actorsColumns.mInventory = &mColumns.back(); std::map inventoryMap; inventoryMap.insert(std::make_pair(UniversalId::Type_Npc, @@ -141,7 +141,7 @@ CSMWorld::RefIdCollection::RefIdCollection() // Nested table mColumns.push_back(RefIdColumn (Columns::ColumnId_SpellList, - ColumnBase::Display_NestedSpellList, ColumnBase::Flag_Dialogue)); + ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue)); actorsColumns.mSpells = &mColumns.back(); std::map spellsMap; spellsMap.insert(std::make_pair(UniversalId::Type_Npc, @@ -154,7 +154,7 @@ CSMWorld::RefIdCollection::RefIdCollection() // Nested table mColumns.push_back(RefIdColumn (Columns::ColumnId_NpcDestinations, - ColumnBase::Display_NestedDestinationsList, ColumnBase::Flag_Dialogue)); + ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue)); actorsColumns.mDestinations = &mColumns.back(); std::map destMap; destMap.insert(std::make_pair(UniversalId::Type_Npc, @@ -281,7 +281,7 @@ CSMWorld::RefIdCollection::RefIdCollection() // Nested table mColumns.push_back(RefIdColumn (Columns::ColumnId_ContainerContent, - ColumnBase::Display_NestedItemList, ColumnBase::Flag_Dialogue)); + ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue)); const RefIdColumn *content = &mColumns.back(); std::map contMap; contMap.insert(std::make_pair(UniversalId::Type_Container, From d6c2cff381a356331ed3852d8799967b4fec9196 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Fri, 17 Apr 2015 21:33:25 +1000 Subject: [PATCH 0955/3725] Convert magic effects Attribute column in the nested tables to use enum delegates. --- apps/opencs/model/world/data.cpp | 4 +-- .../model/world/nestedcoladapterimp.hpp | 34 ++----------------- apps/opencs/model/world/refidcollection.cpp | 2 +- 3 files changed, 5 insertions(+), 35 deletions(-) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 5733fd83f..843d08281 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -197,7 +197,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mSpells.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_Skill, ColumnBase::Display_String)); mSpells.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_String)); // reuse attribute + new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_Attribute)); // reuse attribute mSpells.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_EffectRange, ColumnBase::Display_Integer)); mSpells.getNestableColumn(index)->addColumn( @@ -271,7 +271,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mEnchantments.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_Skill, ColumnBase::Display_String)); mEnchantments.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_String)); // reuse attribute + new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_Attribute)); // reuse attribute mEnchantments.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_EffectRange, ColumnBase::Display_Integer)); mEnchantments.getNestableColumn(index)->addColumn( diff --git a/apps/opencs/model/world/nestedcoladapterimp.hpp b/apps/opencs/model/world/nestedcoladapterimp.hpp index 2aa1123a3..951c7a610 100644 --- a/apps/opencs/model/world/nestedcoladapterimp.hpp +++ b/apps/opencs/model/world/nestedcoladapterimp.hpp @@ -354,23 +354,7 @@ namespace CSMWorld } case 2: { - switch (effect.mAttribute) - { - // see ESM::Attribute::AttributeID in - case ESM::Attribute::Strength: - case ESM::Attribute::Intelligence: - case ESM::Attribute::Willpower: - case ESM::Attribute::Agility: - case ESM::Attribute::Speed: - case ESM::Attribute::Endurance: - case ESM::Attribute::Personality: - case ESM::Attribute::Luck: - { - return QString(ESM::Attribute::sAttributeNames[effect.mAttribute].c_str()); - } - case -1: return QString("N/A"); - default: return QVariant(); - } + return effect.mAttribute; } case 3: { @@ -431,21 +415,7 @@ namespace CSMWorld } case 2: { - std::string attr = value.toString().toStdString(); - if ("N/A" == attr) - { - effect.mAttribute = -1; - break; - } - - for (unsigned int i = 0; i < ESM::Attribute::Length; ++i) - { - if (ESM::Attribute::sAttributeNames[i] == attr) - { - effect.mAttribute = static_cast(i); - break; - } - } + effect.mAttribute = static_cast(value.toInt()); break; } case 3: diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 2e53c2b1c..92fbfd08e 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -85,7 +85,7 @@ CSMWorld::RefIdCollection::RefIdCollection() mColumns.back().addColumn( new NestedChildColumn (Columns::ColumnId_Skill, ColumnBase::Display_String)); mColumns.back().addColumn( - new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_String)); // reuse attribute + new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_Attribute)); // reuse attribute mColumns.back().addColumn( new NestedChildColumn (Columns::ColumnId_EffectRange, ColumnBase::Display_Integer)); mColumns.back().addColumn( From 20af2b67a838dbda3fe1e622b0a25d058e813427 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 17 Apr 2015 18:54:14 +0200 Subject: [PATCH 0956/3725] Change the triangle pattern used for terrain (Fixes #2459) --- components/terrain/buffercache.cpp | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/components/terrain/buffercache.cpp b/components/terrain/buffercache.cpp index 01032bcda..1b000fabb 100644 --- a/components/terrain/buffercache.cpp +++ b/components/terrain/buffercache.cpp @@ -59,13 +59,27 @@ Ogre::HardwareIndexBufferSharedPtr createIndexBuffer(unsigned int flags, unsigne { for (size_t col = colStart; col < colEnd; col += increment) { - indices.push_back(verts*col+row); - indices.push_back(verts*(col+increment)+row+increment); - indices.push_back(verts*col+row+increment); + // diamond pattern + if ((row + col%2) % 2 == 1) + { + indices.push_back(verts*(col+increment)+row); + indices.push_back(verts*(col+increment)+row+increment); + indices.push_back(verts*col+row+increment); - indices.push_back(verts*col+row); - indices.push_back(verts*(col+increment)+row); - indices.push_back(verts*(col+increment)+row+increment); + indices.push_back(verts*col+row); + indices.push_back(verts*(col+increment)+row); + indices.push_back(verts*(col)+row+increment); + } + else + { + indices.push_back(verts*col+row); + indices.push_back(verts*(col+increment)+row+increment); + indices.push_back(verts*col+row+increment); + + indices.push_back(verts*col+row); + indices.push_back(verts*(col+increment)+row); + indices.push_back(verts*(col+increment)+row+increment); + } } } From 0aff188d8d0b230e725665bf37dc87d70a0f9398 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 18 Apr 2015 07:13:02 +1000 Subject: [PATCH 0957/3725] Fix enum delegate from adding a command to the undo stack when the value has not changed. --- apps/opencs/view/world/enumdelegate.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/opencs/view/world/enumdelegate.cpp b/apps/opencs/view/world/enumdelegate.cpp index 7c305b1b6..eb523f781 100644 --- a/apps/opencs/view/world/enumdelegate.cpp +++ b/apps/opencs/view/world/enumdelegate.cpp @@ -21,7 +21,9 @@ void CSVWorld::EnumDelegate::setModelDataImp (QWidget *editor, QAbstractItemMode iter!=mValues.end(); ++iter) if (iter->second==value) { - addCommands (model, index, iter->first); + // do nothing if the value has not changed + if (model->data(index).toInt() != iter->first) + addCommands (model, index, iter->first); break; } } From befd6fe658fc6969e111762b7ebd9b76db1fb318 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 18 Apr 2015 07:15:40 +1000 Subject: [PATCH 0958/3725] Convert magic effects Skills column in the nested tables to use enum delegates. --- apps/opencs/model/world/columnbase.cpp | 1 + apps/opencs/model/world/columnbase.hpp | 1 + apps/opencs/model/world/columns.cpp | 13 +++++ apps/opencs/model/world/columns.hpp | 1 + apps/opencs/model/world/data.cpp | 4 +- .../model/world/nestedcoladapterimp.hpp | 53 +------------------ apps/opencs/model/world/refidcollection.cpp | 2 +- apps/opencs/view/doc/viewmanager.cpp | 3 +- apps/opencs/view/world/dialoguesubview.cpp | 3 +- 9 files changed, 25 insertions(+), 56 deletions(-) diff --git a/apps/opencs/model/world/columnbase.cpp b/apps/opencs/model/world/columnbase.cpp index 5ef4aa444..045afe04c 100644 --- a/apps/opencs/model/world/columnbase.cpp +++ b/apps/opencs/model/world/columnbase.cpp @@ -75,6 +75,7 @@ bool CSMWorld::ColumnBase::isId (Display display) Display_Video, Display_Id, + Display_SkillImpact, Display_None }; diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index 437d07f97..f6ebb16b8 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -109,6 +109,7 @@ namespace CSMWorld Display_SoundGeneratorType, Display_School, Display_Id, + Display_SkillImpact, //top level columns that nest other columns Display_NestedHeader diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index ff28a1289..3d15ed4f3 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -270,6 +270,7 @@ namespace CSMWorld { ColumnId_LevelledItemChanceNone, "Chance None" }, { ColumnId_PowerList, "Powers" }, + { ColumnId_SkillImpact, "Skills" }, { ColumnId_UseValue1, "Use value 1" }, { ColumnId_UseValue2, "Use value 2" }, @@ -423,6 +424,17 @@ namespace "Alteration", "Conjuration", "Destruction", "Illusion", "Mysticism", "Restoration", 0 }; + // impact from magic effects + static const char *sSkills[] = + { + "Block", "Armorer", "MediumArmor", "HeavyArmor", "BluntWeapon", + "LongBlade", "Axe", "Spear", "Athletics", "Enchant", + "Destruction", "Alteration", "Illusion", "Conjuration", "Mysticism", + "Restoration", "Alchemy", "Unarmored", "Security", "Sneak", + "Acrobatics", "LightArmor", "ShortBlade", "Marksman", "Mercantile", + "Speechcraft", "HandToHand", 0 + }; + const char **getEnumNames (CSMWorld::Columns::ColumnId column) { switch (column) @@ -445,6 +457,7 @@ namespace case CSMWorld::Columns::ColumnId_MeshType: return sMeshTypes; case CSMWorld::Columns::ColumnId_SoundGeneratorType: return sSoundGeneratorType; case CSMWorld::Columns::ColumnId_School: return sSchools; + case CSMWorld::Columns::ColumnId_SkillImpact: return sSkills; default: return 0; } diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 7c28f9589..7508c9880 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -260,6 +260,7 @@ namespace CSMWorld ColumnId_LevelledItemChanceNone = 237, ColumnId_PowerList = 238, + ColumnId_SkillImpact = 239, // impact from magic effects // Allocated to a separate value range, so we don't get a collision should we ever need // to extend the number of use values. diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 843d08281..f4edb8e57 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -195,7 +195,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mSpells.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_String/*, false*/)); // false means no edit mSpells.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_Skill, ColumnBase::Display_String)); + new NestedChildColumn (Columns::ColumnId_SkillImpact, ColumnBase::Display_SkillImpact)); mSpells.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_Attribute)); // reuse attribute mSpells.getNestableColumn(index)->addColumn( @@ -269,7 +269,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mEnchantments.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_String/*, false*/)); mEnchantments.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_Skill, ColumnBase::Display_String)); + new NestedChildColumn (Columns::ColumnId_SkillImpact, ColumnBase::Display_SkillImpact)); mEnchantments.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_Attribute)); // reuse attribute mEnchantments.getNestableColumn(index)->addColumn( diff --git a/apps/opencs/model/world/nestedcoladapterimp.hpp b/apps/opencs/model/world/nestedcoladapterimp.hpp index 951c7a610..3f8e6d6a9 100644 --- a/apps/opencs/model/world/nestedcoladapterimp.hpp +++ b/apps/opencs/model/world/nestedcoladapterimp.hpp @@ -315,42 +315,7 @@ namespace CSMWorld } case 1: { - switch (effect.mSkill) - { - // see ESM::Skill::SkillEnum in - case ESM::Skill::Block: - case ESM::Skill::Armorer: - case ESM::Skill::MediumArmor: - case ESM::Skill::HeavyArmor: - case ESM::Skill::BluntWeapon: - case ESM::Skill::LongBlade: - case ESM::Skill::Axe: - case ESM::Skill::Spear: - case ESM::Skill::Athletics: - case ESM::Skill::Enchant: - case ESM::Skill::Destruction: - case ESM::Skill::Alteration: - case ESM::Skill::Illusion: - case ESM::Skill::Conjuration: - case ESM::Skill::Mysticism: - case ESM::Skill::Restoration: - case ESM::Skill::Alchemy: - case ESM::Skill::Unarmored: - case ESM::Skill::Security: - case ESM::Skill::Sneak: - case ESM::Skill::Acrobatics: - case ESM::Skill::LightArmor: - case ESM::Skill::ShortBlade: - case ESM::Skill::Marksman: - case ESM::Skill::Mercantile: - case ESM::Skill::Speechcraft: - case ESM::Skill::HandToHand: - { - return QString(ESM::Skill::sSkillNames[effect.mSkill].c_str()); - } - case -1: return QString("N/A"); - default: return QVariant(); - } + return effect.mSkill; } case 2: { @@ -396,21 +361,7 @@ namespace CSMWorld } case 1: { - std::string skillName = value.toString().toStdString(); - if ("N/A" == skillName) - { - effect.mSkill = -1; - break; - } - - for (unsigned int i = 0; i < ESM::Skill::Length; ++i) - { - if (ESM::Skill::sSkillNames[i] == skillName) - { - effect.mSkill = static_cast(i); - break; - } - } + effect.mSkill = static_cast(value.toInt()); break; } case 2: diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 92fbfd08e..a685276f4 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -83,7 +83,7 @@ CSMWorld::RefIdCollection::RefIdCollection() mColumns.back().addColumn( new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_String/*, false*/)); mColumns.back().addColumn( - new NestedChildColumn (Columns::ColumnId_Skill, ColumnBase::Display_String)); + new NestedChildColumn (Columns::ColumnId_SkillImpact, ColumnBase::Display_SkillImpact)); mColumns.back().addColumn( new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_Attribute)); // reuse attribute mColumns.back().addColumn( diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 9fee26078..1dfe3a792 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -84,7 +84,8 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) { CSMWorld::ColumnBase::Display_MeshType, CSMWorld::Columns::ColumnId_MeshType, false }, { CSMWorld::ColumnBase::Display_Gender, CSMWorld::Columns::ColumnId_Gender, true }, { CSMWorld::ColumnBase::Display_SoundGeneratorType, CSMWorld::Columns::ColumnId_SoundGeneratorType, false }, - { CSMWorld::ColumnBase::Display_School, CSMWorld::Columns::ColumnId_School, true } + { CSMWorld::ColumnBase::Display_School, CSMWorld::Columns::ColumnId_School, true }, + { CSMWorld::ColumnBase::Display_SkillImpact, CSMWorld::Columns::ColumnId_SkillImpact, true } }; for (std::size_t i=0; iindex(row, i), display, dynamic_cast(mTable))); NestedTable* table = new NestedTable(mDocument, mNestedModels.back(), this); - table->resizeColumnsToContents(); + // FIXME: does not work well when enum delegates are used + //table->resizeColumnsToContents(); QLabel* label = From e00d7f72ace0366cfbe8487521675761c90a3a87 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 18 Apr 2015 08:09:14 +1000 Subject: [PATCH 0959/3725] Convert magic effects ID and Range columns in the nested tables to use enum delegate --- apps/opencs/model/world/columnbase.cpp | 2 + apps/opencs/model/world/columnbase.hpp | 2 + apps/opencs/model/world/columns.cpp | 45 ++++++++++++++++++- apps/opencs/model/world/data.cpp | 8 ++-- .../model/world/nestedcoladapterimp.hpp | 42 +++++------------ apps/opencs/model/world/refidcollection.cpp | 4 +- apps/opencs/view/doc/viewmanager.cpp | 4 +- 7 files changed, 69 insertions(+), 38 deletions(-) diff --git a/apps/opencs/model/world/columnbase.cpp b/apps/opencs/model/world/columnbase.cpp index 045afe04c..5690d9253 100644 --- a/apps/opencs/model/world/columnbase.cpp +++ b/apps/opencs/model/world/columnbase.cpp @@ -76,6 +76,8 @@ bool CSMWorld::ColumnBase::isId (Display display) Display_Id, Display_SkillImpact, + Display_EffectRange, + Display_EffectId, Display_None }; diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index f6ebb16b8..8dab0602e 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -110,6 +110,8 @@ namespace CSMWorld Display_School, Display_Id, Display_SkillImpact, + Display_EffectRange, + Display_EffectId, //top level columns that nest other columns Display_NestedHeader diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 3d15ed4f3..19efc8177 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -332,6 +332,7 @@ namespace "Combat", "Magic", "Stealth", 0 }; + // see ESM::Attribute::AttributeID in static const char *sAttributes[] = { "Strength", "Intelligence", "Willpower", "Agility", "Speed", "Endurance", "Personality", @@ -424,7 +425,7 @@ namespace "Alteration", "Conjuration", "Destruction", "Illusion", "Mysticism", "Restoration", 0 }; - // impact from magic effects + // impact from magic effects, see ESM::Skill::SkillEnum in static const char *sSkills[] = { "Block", "Armorer", "MediumArmor", "HeavyArmor", "BluntWeapon", @@ -435,6 +436,46 @@ namespace "Speechcraft", "HandToHand", 0 }; + // range of magic effects, see ESM::RangeType in + static const char *sEffectRange[] = + { + "Self", "Touch", "Target", 0 + }; + + // magic effect names, see ESM::MagicEffect::Effects in + static const char *sEffectId[] = + { + "WaterBreathing", "SwiftSwim", "WaterWalking", "Shield", "FireShield", + "LightningShield", "FrostShield", "Burden", "Feather", "Jump", + "Levitate", "SlowFall", "Lock", "Open", "FireDamage", + "ShockDamage", "FrostDamage", "DrainAttribute", "DrainHealth", "DrainMagicka", + "DrainFatigue", "DrainSkill", "DamageAttribute", "DamageHealth", "DamageMagicka", + "DamageFatigue", "DamageSkill", "Poison", "WeaknessToFire", "WeaknessToFrost", + "WeaknessToShock", "WeaknessToMagicka", "WeaknessToCommonDisease", "WeaknessToBlightDisease", "WeaknessToCorprusDisease", + "WeaknessToPoison", "WeaknessToNormalWeapons", "DisintegrateWeapon", "DisintegrateArmor", "Invisibility", + "Chameleon", "Light", "Sanctuary", "NightEye", "Charm", + "Paralyze", "Silence", "Blind", "Sound", "CalmHumanoid", + "CalmCreature", "FrenzyHumanoid", "FrenzyCreature", "DemoralizeHumanoid", "DemoralizeCreature", + "RallyHumanoid", "RallyCreature", "Dispel", "Soultrap", "Telekinesis", + "Mark", "Recall", "DivineIntervention", "AlmsiviIntervention", "DetectAnimal", + "DetectEnchantment", "DetectKey", "SpellAbsorption", "Reflect", "CureCommonDisease", + "CureBlightDisease", "CureCorprusDisease", "CurePoison", "CureParalyzation", "RestoreAttribute", + "RestoreHealth", "RestoreMagicka", "RestoreFatigue", "RestoreSkill", "FortifyAttribute", + "FortifyHealth", "FortifyMagicka", "FortifyFatigue", "FortifySkill", "FortifyMaximumMagicka", + "AbsorbAttribute", "AbsorbHealth", "AbsorbMagicka", "AbsorbFatigue", "AbsorbSkill", + "ResistFire", "ResistFrost", "ResistShock", "ResistMagicka", "ResistCommonDisease", + "ResistBlightDisease", "ResistCorprusDisease", "ResistPoison", "ResistNormalWeapons", "ResistParalysis", + "RemoveCurse", "TurnUndead", "SummonScamp", "SummonClannfear", "SummonDaedroth", + "SummonDremora", "SummonAncestralGhost", "SummonSkeletalMinion", "SummonBonewalker", "SummonGreaterBonewalker", + "SummonBonelord", "SummonWingedTwilight", "SummonHunger", "SummonGoldenSaint", "SummonFlameAtronach", + "SummonFrostAtronach", "SummonStormAtronach", "FortifyAttack", "CommandCreature", "CommandHumanoid", + "BoundDagger", "BoundLongsword", "BoundMace", "BoundBattleAxe", "BoundSpear", + "BoundLongbow", "ExtraSpell", "BoundCuirass", "BoundHelm", "BoundBoots", + "BoundShield", "BoundGloves", "Corprus", "Vampirism", "SummonCenturionSphere", + "SunDamage", "StuntedMagicka", "SummonFabricant", "SummonWolf", "SummonBear", + "SummonBonewolf", "SummonCreature04", "SummonCreature05", 0 + }; + const char **getEnumNames (CSMWorld::Columns::ColumnId column) { switch (column) @@ -458,6 +499,8 @@ namespace case CSMWorld::Columns::ColumnId_SoundGeneratorType: return sSoundGeneratorType; case CSMWorld::Columns::ColumnId_School: return sSchools; case CSMWorld::Columns::ColumnId_SkillImpact: return sSkills; + case CSMWorld::Columns::ColumnId_EffectRange: return sEffectRange; + case CSMWorld::Columns::ColumnId_EffectId: return sEffectId; default: return 0; } diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index f4edb8e57..0490cbe7a 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -193,13 +193,13 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc index = mSpells.getColumns()-1; mSpells.addAdapter (std::make_pair(&mSpells.getColumn(index), new EffectsListAdapter ())); mSpells.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_String/*, false*/)); // false means no edit + new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_EffectId)); // false means no edit mSpells.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_SkillImpact, ColumnBase::Display_SkillImpact)); mSpells.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_Attribute)); // reuse attribute mSpells.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_EffectRange, ColumnBase::Display_Integer)); + new NestedChildColumn (Columns::ColumnId_EffectRange, ColumnBase::Display_EffectRange)); mSpells.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_EffectArea, ColumnBase::Display_String)); mSpells.getNestableColumn(index)->addColumn( @@ -267,13 +267,13 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mEnchantments.addAdapter (std::make_pair(&mEnchantments.getColumn(index), new EffectsListAdapter ())); mEnchantments.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_String/*, false*/)); + new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_EffectId)); mEnchantments.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_SkillImpact, ColumnBase::Display_SkillImpact)); mEnchantments.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_Attribute)); // reuse attribute mEnchantments.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_EffectRange, ColumnBase::Display_Integer)); + new NestedChildColumn (Columns::ColumnId_EffectRange, ColumnBase::Display_EffectRange)); mEnchantments.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_EffectArea, ColumnBase::Display_String)); mEnchantments.getNestableColumn(index)->addColumn( diff --git a/apps/opencs/model/world/nestedcoladapterimp.hpp b/apps/opencs/model/world/nestedcoladapterimp.hpp index 3f8e6d6a9..1ee447f34 100644 --- a/apps/opencs/model/world/nestedcoladapterimp.hpp +++ b/apps/opencs/model/world/nestedcoladapterimp.hpp @@ -309,28 +309,19 @@ namespace CSMWorld { case 0: { - // indexToId() prepends "#d+" hence not so user friendly - QString effectId(ESM::MagicEffect::effectIdToString(effect.mEffectID).c_str()); - return effectId.remove(0, 7); // 7 == sizeof("sEffect") - 1 - } - case 1: - { - return effect.mSkill; - } - case 2: - { - return effect.mAttribute; + if (effect.mEffectID >=0 && effect.mEffectID < ESM::MagicEffect::Length) + return effect.mRange; + else + throw std::runtime_error("Magic effects ID unexpected value"); } + case 1: return effect.mSkill; + case 2: return effect.mAttribute; case 3: { - switch (effect.mRange) - { - // see ESM::RangeType in - case ESM::RT_Self: return QString("Self"); - case ESM::RT_Touch: return QString("Touch"); - case ESM::RT_Target: return QString("Target"); - default: return QVariant(); - } + if (effect.mRange >=0 && effect.mRange <=2) + return effect.mRange; + else + throw std::runtime_error("Magic effects range unexpected value"); } case 4: return effect.mArea; case 5: return effect.mDuration; @@ -355,8 +346,7 @@ namespace CSMWorld { case 0: { - effect.mEffectID = - ESM::MagicEffect::effectStringToId("sEffect"+value.toString().toStdString()); + effect.mEffectID = static_cast(value.toInt()); break; } case 1: @@ -371,15 +361,7 @@ namespace CSMWorld } case 3: { - std::string effectId = value.toString().toStdString(); - if (effectId == "Self") - effect.mRange = ESM::RT_Self; - else if (effectId == "Touch") - effect.mRange = ESM::RT_Touch; - else if (effectId == "Target") - effect.mRange = ESM::RT_Target; - else - return; // leave unchanged + effect.mRange = value.toInt(); break; } case 4: effect.mArea = value.toInt(); break; diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index a685276f4..636f9a57f 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -81,13 +81,13 @@ CSMWorld::RefIdCollection::RefIdCollection() new EffectsRefIdAdapter (UniversalId::Type_Potion))); mNestedAdapters.push_back (std::make_pair(&mColumns.back(), effectsMap)); mColumns.back().addColumn( - new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_String/*, false*/)); + new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_EffectId)); mColumns.back().addColumn( new NestedChildColumn (Columns::ColumnId_SkillImpact, ColumnBase::Display_SkillImpact)); mColumns.back().addColumn( new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_Attribute)); // reuse attribute mColumns.back().addColumn( - new NestedChildColumn (Columns::ColumnId_EffectRange, ColumnBase::Display_Integer)); + new NestedChildColumn (Columns::ColumnId_EffectRange, ColumnBase::Display_EffectRange)); mColumns.back().addColumn( new NestedChildColumn (Columns::ColumnId_EffectArea, ColumnBase::Display_String)); mColumns.back().addColumn( diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 1dfe3a792..1281f89f2 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -85,7 +85,9 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) { CSMWorld::ColumnBase::Display_Gender, CSMWorld::Columns::ColumnId_Gender, true }, { CSMWorld::ColumnBase::Display_SoundGeneratorType, CSMWorld::Columns::ColumnId_SoundGeneratorType, false }, { CSMWorld::ColumnBase::Display_School, CSMWorld::Columns::ColumnId_School, true }, - { CSMWorld::ColumnBase::Display_SkillImpact, CSMWorld::Columns::ColumnId_SkillImpact, true } + { CSMWorld::ColumnBase::Display_SkillImpact, CSMWorld::Columns::ColumnId_SkillImpact, true }, + { CSMWorld::ColumnBase::Display_EffectRange, CSMWorld::Columns::ColumnId_EffectRange, false }, + { CSMWorld::ColumnBase::Display_EffectId, CSMWorld::Columns::ColumnId_EffectId, false } }; for (std::size_t i=0; i Date: Sat, 18 Apr 2015 08:31:08 +1000 Subject: [PATCH 0960/3725] Convert clothing/armour part reference type column in the nested tables to use enum delegates. --- apps/opencs/model/world/columnbase.cpp | 1 + apps/opencs/model/world/columnbase.hpp | 1 + apps/opencs/model/world/columns.cpp | 12 +++++++ apps/opencs/model/world/refidadapterimp.hpp | 36 +++++---------------- apps/opencs/model/world/refidcollection.cpp | 2 +- apps/opencs/view/doc/viewmanager.cpp | 3 +- 6 files changed, 25 insertions(+), 30 deletions(-) diff --git a/apps/opencs/model/world/columnbase.cpp b/apps/opencs/model/world/columnbase.cpp index 5690d9253..cea00b7bc 100644 --- a/apps/opencs/model/world/columnbase.cpp +++ b/apps/opencs/model/world/columnbase.cpp @@ -78,6 +78,7 @@ bool CSMWorld::ColumnBase::isId (Display display) Display_SkillImpact, Display_EffectRange, Display_EffectId, + Display_PartRefType, Display_None }; diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index 8dab0602e..20e3ccce6 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -112,6 +112,7 @@ namespace CSMWorld Display_SkillImpact, Display_EffectRange, Display_EffectId, + Display_PartRefType, //top level columns that nest other columns Display_NestedHeader diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 19efc8177..fd090d181 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -476,6 +476,17 @@ namespace "SummonBonewolf", "SummonCreature04", "SummonCreature05", 0 }; + // see ESM::PartReferenceType in + static const char *sPartRefType[] = + { + "Head", "Hair", "Neck", "Cuirass", "Groin", + "Skirt", "Right Hand", "Left Hand", "Right Wrist", "Left Wrist", + "Shield", "Right Forearm", "Left Forearm", "Right Upperarm", "Left Upperarm", + "Right Foot", "Left Foot", "Right Ankle", "Left Ankle", "Right Knee", + "Left Knee", "Right Leg", "Left Leg", "Right Pauldron", "Left Pauldron", + "Weapon", "Tail", 0 + }; + const char **getEnumNames (CSMWorld::Columns::ColumnId column) { switch (column) @@ -501,6 +512,7 @@ namespace case CSMWorld::Columns::ColumnId_SkillImpact: return sSkills; case CSMWorld::Columns::ColumnId_EffectRange: return sEffectRange; case CSMWorld::Columns::ColumnId_EffectId: return sEffectId; + case CSMWorld::Columns::ColumnId_PartRefType: return sPartRefType; default: return 0; } diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index 2b2b189e0..489808393 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -1665,15 +1665,6 @@ namespace CSMWorld } }; - static const char *sPartRefs[ESM::PRT_Count] = - { - "Head", "Hair", "Neck", "Cuirass", "Groin", - "Skirt", "Right Hand", "Left Hand", "Right Wrist", "Left Wrist", - "Shield", "Right Forearm", "Left Forearm", "Right Upperarm", "Left Upperarm", - "Right Foot", "Left Foot", "Right Ankle", "Left Ankle", "Right Knee", - "Left Knee", "Right Leg", "Left Leg", "Right Pauldron", "Left Pauldron", - "Weapon", "Tail" - }; template class BodyPartRefIdAdapter : public NestedRefIdAdapterBase @@ -1767,7 +1758,13 @@ namespace CSMWorld switch (subColIndex) { - case 0: return QString(sPartRefs[content.mPart]); + case 0: + { + if (content.mPart >=0 && content.mPart < ESM::PRT_Count) + return content.mPart; + else + throw std::runtime_error("Part Reference Type unexpected value"); + } case 1: return QString(content.mMale.c_str()); case 2: return QString(content.mFemale.c_str()); default: @@ -1788,24 +1785,7 @@ namespace CSMWorld switch(subColIndex) { - case 0: - { - std::string part = value.toString().toStdString(); - bool found = false; - for (unsigned int i = 0; i < ESM::PRT_Count; ++i) - { - if (part == sPartRefs[i]) - { - list.at(subRowIndex).mPart = static_cast(i); - found = true; - break; - } - } - if (!found) - return; // return without saving - else - break; - } + case 0: list.at(subRowIndex).mPart = static_cast(value.toInt()); break; case 1: list.at(subRowIndex).mMale = value.toString().toStdString(); break; case 2: list.at(subRowIndex).mFemale = value.toString().toStdString(); break; default: diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 636f9a57f..3bdf8361f 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -480,7 +480,7 @@ CSMWorld::RefIdCollection::RefIdCollection() new BodyPartRefIdAdapter (UniversalId::Type_Clothing))); mNestedAdapters.push_back (std::make_pair(&mColumns.back(), partMap)); mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_PartRefType, CSMWorld::ColumnBase::Display_String)); + new RefIdColumn (Columns::ColumnId_PartRefType, CSMWorld::ColumnBase::Display_PartRefType)); mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_PartRefMale, CSMWorld::ColumnBase::Display_String)); mColumns.back().addColumn( diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 1281f89f2..3f0c10053 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -87,7 +87,8 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) { CSMWorld::ColumnBase::Display_School, CSMWorld::Columns::ColumnId_School, true }, { CSMWorld::ColumnBase::Display_SkillImpact, CSMWorld::Columns::ColumnId_SkillImpact, true }, { CSMWorld::ColumnBase::Display_EffectRange, CSMWorld::Columns::ColumnId_EffectRange, false }, - { CSMWorld::ColumnBase::Display_EffectId, CSMWorld::Columns::ColumnId_EffectId, false } + { CSMWorld::ColumnBase::Display_EffectId, CSMWorld::Columns::ColumnId_EffectId, false }, + { CSMWorld::ColumnBase::Display_PartRefType, CSMWorld::Columns::ColumnId_PartRefType, false } }; for (std::size_t i=0; i Date: Sat, 18 Apr 2015 09:37:19 +1000 Subject: [PATCH 0961/3725] Convert AI package type and AI wander repeat columns in the nested tables to use enum delegate --- apps/opencs/model/world/columnbase.cpp | 2 + apps/opencs/model/world/columnbase.hpp | 2 + apps/opencs/model/world/columns.cpp | 15 +++- apps/opencs/model/world/columns.hpp | 2 +- apps/opencs/model/world/refidadapterimp.hpp | 77 +++++++-------------- apps/opencs/model/world/refidcollection.cpp | 4 +- apps/opencs/view/doc/viewmanager.cpp | 4 +- 7 files changed, 48 insertions(+), 58 deletions(-) diff --git a/apps/opencs/model/world/columnbase.cpp b/apps/opencs/model/world/columnbase.cpp index cea00b7bc..659954f48 100644 --- a/apps/opencs/model/world/columnbase.cpp +++ b/apps/opencs/model/world/columnbase.cpp @@ -79,6 +79,8 @@ bool CSMWorld::ColumnBase::isId (Display display) Display_EffectRange, Display_EffectId, Display_PartRefType, + Display_AiPackageType, + Display_YesNo, Display_None }; diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index 20e3ccce6..4c3f9385a 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -113,6 +113,8 @@ namespace CSMWorld Display_EffectRange, Display_EffectId, Display_PartRefType, + Display_AiPackageType, + Display_YesNo, //top level columns that nest other columns Display_NestedHeader diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index fd090d181..1b5aefee9 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -248,7 +248,7 @@ namespace CSMWorld { ColumnId_EffectArea, "Area" }, { ColumnId_AiPackageList, "Ai Packages" }, - { ColumnId_AiPackage, "Package" }, + { ColumnId_AiPackageType, "Package" }, { ColumnId_AiWanderDist, "Wander Dist" }, { ColumnId_AiDuration, "Duration" }, { ColumnId_AiWanderToD, "Wander ToD" }, @@ -487,6 +487,17 @@ namespace "Weapon", "Tail", 0 }; + // see the enums in + static const char *sAiPackageType[] = + { + "AI Wander", "AI Travel", "AI Follow", "AI Escort", "AI Activate", 0 + }; + + static const char *sAiWanderRepeat[] = + { + "No", "Yes", 0 + }; + const char **getEnumNames (CSMWorld::Columns::ColumnId column) { switch (column) @@ -513,6 +524,8 @@ namespace case CSMWorld::Columns::ColumnId_EffectRange: return sEffectRange; case CSMWorld::Columns::ColumnId_EffectId: return sEffectId; case CSMWorld::Columns::ColumnId_PartRefType: return sPartRefType; + case CSMWorld::Columns::ColumnId_AiPackageType: return sAiPackageType; + case CSMWorld::Columns::ColumnId_AiWanderRepeat: return sAiWanderRepeat; default: return 0; } diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 7508c9880..1760bff30 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -237,7 +237,7 @@ namespace CSMWorld ColumnId_EffectArea = 218, ColumnId_AiPackageList = 219, - ColumnId_AiPackage = 220, + ColumnId_AiPackageType = 220, ColumnId_AiWanderDist = 221, ColumnId_AiDuration = 222, ColumnId_AiWanderToD = 223, diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index 489808393..5fd888441 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -1318,34 +1318,13 @@ namespace CSMWorld switch(subColIndex) { - case 0: - list.at(subRowIndex).mCellName = std::string(value.toString().toUtf8().constData()); - break; - - case 1: - list.at(subRowIndex).mPos.pos[0] = value.toFloat(); - break; - - case 2: - list.at(subRowIndex).mPos.pos[1] = value.toFloat(); - break; - - case 3: - list.at(subRowIndex).mPos.pos[2] = value.toFloat(); - break; - - case 4: - list.at(subRowIndex).mPos.rot[0] = value.toFloat(); - break; - - case 5: - list.at(subRowIndex).mPos.rot[1] = value.toFloat(); - break; - - case 6: - list.at(subRowIndex).mPos.rot[2] = value.toFloat(); - break; - + case 0: list.at(subRowIndex).mCellName = std::string(value.toString().toUtf8().constData()); break; + case 1: list.at(subRowIndex).mPos.pos[0] = value.toFloat(); break; + case 2: list.at(subRowIndex).mPos.pos[1] = value.toFloat(); break; + case 3: list.at(subRowIndex).mPos.pos[2] = value.toFloat(); break; + case 4: list.at(subRowIndex).mPos.rot[0] = value.toFloat(); break; + case 5: list.at(subRowIndex).mPos.rot[1] = value.toFloat(); break; + case 6: list.at(subRowIndex).mPos.rot[2] = value.toFloat(); break; default: throw std::runtime_error("Trying to access non-existing column in the nested table!"); } @@ -1461,13 +1440,13 @@ namespace CSMWorld case 0: switch (content.mType) { - case ESM::AI_Wander: return QString("AI Wander"); - case ESM::AI_Travel: return QString("AI Travel"); - case ESM::AI_Follow: return QString("AI Follow"); - case ESM::AI_Escort: return QString("AI Escort"); - case ESM::AI_Activate: return QString("AI Activate"); + case ESM::AI_Wander: return 0; + case ESM::AI_Travel: return 1; + case ESM::AI_Follow: return 2; + case ESM::AI_Escort: return 3; + case ESM::AI_Activate: return 4; case ESM::AI_CNDT: - default: return QString("None"); + default: return QVariant(); } case 1: // wander dist if (content.mType == ESM::AI_Wander) @@ -1494,7 +1473,7 @@ namespace CSMWorld return QVariant(); case 5: // wander repeat if (content.mType == ESM::AI_Wander) - return QString(content.mWander.mShouldRepeat ? "Yes" : "No"); + return content.mWander.mShouldRepeat; else return QVariant(); case 6: // activate name @@ -1554,18 +1533,14 @@ namespace CSMWorld switch(subColIndex) { case 0: // ai package type - if ("AI Wander" == value.toString().toStdString()) - content.mType = ESM::AI_Wander; - else if ("AI Travel" == value.toString().toStdString()) - content.mType = ESM::AI_Travel; - else if ("AI Follow" == value.toString().toStdString()) - content.mType = ESM::AI_Follow; - else if ("AI Escort" == value.toString().toStdString()) - content.mType = ESM::AI_Escort; - else if ("AI Activate" == value.toString().toStdString()) - content.mType = ESM::AI_Activate; - else - content.mType = ESM::AI_CNDT; + switch (value.toInt()) + { + case 0: content.mType = ESM::AI_Wander; + case 1: content.mType = ESM::AI_Travel; + case 2: content.mType = ESM::AI_Follow; + case 3: content.mType = ESM::AI_Escort; + case 4: content.mType = ESM::AI_Activate; + } break; // always save case 1: @@ -1592,12 +1567,8 @@ namespace CSMWorld case 5: if (content.mType == ESM::AI_Wander) { - if ("Yes" == value.toString().toStdString()) - content.mWander.mShouldRepeat = 1; - if ("No" == value.toString().toStdString()) - content.mWander.mShouldRepeat = 0; - else - return; // return without saving + content.mWander.mShouldRepeat = static_cast(value.toInt()); + break; } case 6: // NAME32 if (content.mType == ESM::AI_Activate) diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 3bdf8361f..caf1041c6 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -188,7 +188,7 @@ CSMWorld::RefIdCollection::RefIdCollection() new ActorAiRefIdAdapter (UniversalId::Type_Creature))); mNestedAdapters.push_back (std::make_pair(&mColumns.back(), aiMap)); mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_AiPackage, CSMWorld::ColumnBase::Display_String)); + new RefIdColumn (Columns::ColumnId_AiPackageType, CSMWorld::ColumnBase::Display_AiPackageType)); mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_AiWanderDist, CSMWorld::ColumnBase::Display_Integer)); mColumns.back().addColumn( @@ -198,7 +198,7 @@ CSMWorld::RefIdCollection::RefIdCollection() mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_AiWanderIdle, CSMWorld::ColumnBase::Display_Integer)); mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_AiWanderRepeat, CSMWorld::ColumnBase::Display_String)); + new RefIdColumn (Columns::ColumnId_AiWanderRepeat, CSMWorld::ColumnBase::Display_YesNo)); mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_AiActivateName, CSMWorld::ColumnBase::Display_String)); mColumns.back().addColumn( diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 3f0c10053..5908c67a1 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -88,7 +88,9 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) { CSMWorld::ColumnBase::Display_SkillImpact, CSMWorld::Columns::ColumnId_SkillImpact, true }, { CSMWorld::ColumnBase::Display_EffectRange, CSMWorld::Columns::ColumnId_EffectRange, false }, { CSMWorld::ColumnBase::Display_EffectId, CSMWorld::Columns::ColumnId_EffectId, false }, - { CSMWorld::ColumnBase::Display_PartRefType, CSMWorld::Columns::ColumnId_PartRefType, false } + { CSMWorld::ColumnBase::Display_PartRefType, CSMWorld::Columns::ColumnId_PartRefType, false }, + { CSMWorld::ColumnBase::Display_AiPackageType, CSMWorld::Columns::ColumnId_AiPackageType, false }, + { CSMWorld::ColumnBase::Display_YesNo, CSMWorld::Columns::ColumnId_AiWanderRepeat, false } }; for (std::size_t i=0; i Date: Sat, 18 Apr 2015 10:07:53 +1000 Subject: [PATCH 0962/3725] Change the cell edit selection behaviour of the nested tables. Also auto-expand the enum delegate selections (both main table as well as nested table in the dialogue subview) --- apps/opencs/view/world/dialoguesubview.cpp | 2 ++ apps/opencs/view/world/enumdelegate.cpp | 1 + 2 files changed, 3 insertions(+) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 10a192668..9d718cf81 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -444,6 +444,8 @@ void CSVWorld::EditWidget::remake(int row) NestedTable* table = new NestedTable(mDocument, mNestedModels.back(), this); // FIXME: does not work well when enum delegates are used //table->resizeColumnsToContents(); + table->setEditTriggers(QAbstractItemView::CurrentChanged); + table->setSelectionBehavior(QAbstractItemView::SelectItems); QLabel* label = diff --git a/apps/opencs/view/world/enumdelegate.cpp b/apps/opencs/view/world/enumdelegate.cpp index eb523f781..c635948a3 100644 --- a/apps/opencs/view/world/enumdelegate.cpp +++ b/apps/opencs/view/world/enumdelegate.cpp @@ -88,6 +88,7 @@ void CSVWorld::EnumDelegate::setEditorData (QWidget *editor, const QModelIndex& if (mValues[i].first==value) { comboBox->setCurrentIndex (i); + comboBox->showPopup(); break; } } From 4607c4b5816e151bca2af6237ed51a682f148c8e Mon Sep 17 00:00:00 2001 From: dteviot Date: Sat, 18 Apr 2015 15:33:49 +1200 Subject: [PATCH 0963/3725] Add Modified DateTime to plug-in tooltip. (Fixes #2479) --- components/contentselector/model/esmfile.cpp | 7 ++++--- components/contentselector/model/esmfile.hpp | 1 + 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/components/contentselector/model/esmfile.cpp b/components/contentselector/model/esmfile.cpp index 1ac1c7500..46a7c9600 100644 --- a/components/contentselector/model/esmfile.cpp +++ b/components/contentselector/model/esmfile.cpp @@ -6,9 +6,10 @@ int ContentSelectorModel::EsmFile::sPropertyCount = 7; QString ContentSelectorModel::EsmFile::sToolTip = QString("Author: %1
\ Version: %2
\ - Path:
%3
\ -
Description:
%4
\ -
Dependencies: %5
"); + Modified: %3
\ + Path:
%4
\ +
Description:
%5
\ +
Dependencies: %6
"); ContentSelectorModel::EsmFile::EsmFile(QString fileName, ModelItem *parent) diff --git a/components/contentselector/model/esmfile.hpp b/components/contentselector/model/esmfile.hpp index d0cebab3c..614eee298 100644 --- a/components/contentselector/model/esmfile.hpp +++ b/components/contentselector/model/esmfile.hpp @@ -59,6 +59,7 @@ namespace ContentSelectorModel inline QString description() const { return mDescription; } inline QString toolTip() const { return sToolTip.arg(mAuthor) .arg(mFormat) + .arg(mModified.toString(Qt::ISODate)) .arg(mPath) .arg(mDescription) .arg(mGameFiles.join(", ")); From 48a6006202a5f8c5c8d006fd616983337b39514e Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 18 Apr 2015 14:16:55 +1000 Subject: [PATCH 0964/3725] Prevent enum delegates from auto expanding when opening a dialogue subview. --- apps/opencs/view/world/dialoguesubview.cpp | 3 +-- apps/opencs/view/world/enumdelegate.cpp | 3 ++- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 9d718cf81..9358bf6c7 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -444,10 +444,9 @@ void CSVWorld::EditWidget::remake(int row) NestedTable* table = new NestedTable(mDocument, mNestedModels.back(), this); // FIXME: does not work well when enum delegates are used //table->resizeColumnsToContents(); - table->setEditTriggers(QAbstractItemView::CurrentChanged); + table->setEditTriggers(QAbstractItemView::SelectedClicked | QAbstractItemView::CurrentChanged); table->setSelectionBehavior(QAbstractItemView::SelectItems); - QLabel* label = new QLabel (mTable->headerData (i, Qt::Horizontal, Qt::DisplayRole).toString(), mMainWidget); diff --git a/apps/opencs/view/world/enumdelegate.cpp b/apps/opencs/view/world/enumdelegate.cpp index c635948a3..bda93678a 100644 --- a/apps/opencs/view/world/enumdelegate.cpp +++ b/apps/opencs/view/world/enumdelegate.cpp @@ -88,7 +88,8 @@ void CSVWorld::EnumDelegate::setEditorData (QWidget *editor, const QModelIndex& if (mValues[i].first==value) { comboBox->setCurrentIndex (i); - comboBox->showPopup(); + if(!tryDisplay) + comboBox->showPopup(); break; } } From 7561b195abd9e6e08b27fcf7c8a4bb3f5723d41a Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 18 Apr 2015 15:28:34 +1000 Subject: [PATCH 0965/3725] Revert auto expansion of enums as it was interfering with row based operations. Fix default values of magic effect skill & attributes. --- apps/opencs/model/world/nestedcoladapterimp.hpp | 4 ++-- apps/opencs/view/world/dialoguesubview.cpp | 5 +++-- apps/opencs/view/world/enumdelegate.cpp | 2 -- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/apps/opencs/model/world/nestedcoladapterimp.hpp b/apps/opencs/model/world/nestedcoladapterimp.hpp index 1ee447f34..841c3955a 100644 --- a/apps/opencs/model/world/nestedcoladapterimp.hpp +++ b/apps/opencs/model/world/nestedcoladapterimp.hpp @@ -252,8 +252,8 @@ namespace CSMWorld // blank row ESM::ENAMstruct effect; effect.mEffectID = 0; - effect.mSkill = 0; - effect.mAttribute = 0; + effect.mSkill = -1; + effect.mAttribute = -1; effect.mRange = 0; effect.mArea = 0; effect.mDuration = 0; diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 9358bf6c7..6626d67c3 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -443,9 +443,10 @@ void CSVWorld::EditWidget::remake(int row) NestedTable* table = new NestedTable(mDocument, mNestedModels.back(), this); // FIXME: does not work well when enum delegates are used - //table->resizeColumnsToContents(); + table->setVisible(false); + table->resizeColumnsToContents(); + table->setVisible(true); table->setEditTriggers(QAbstractItemView::SelectedClicked | QAbstractItemView::CurrentChanged); - table->setSelectionBehavior(QAbstractItemView::SelectItems); QLabel* label = new QLabel (mTable->headerData (i, Qt::Horizontal, Qt::DisplayRole).toString(), mMainWidget); diff --git a/apps/opencs/view/world/enumdelegate.cpp b/apps/opencs/view/world/enumdelegate.cpp index bda93678a..eb523f781 100644 --- a/apps/opencs/view/world/enumdelegate.cpp +++ b/apps/opencs/view/world/enumdelegate.cpp @@ -88,8 +88,6 @@ void CSVWorld::EnumDelegate::setEditorData (QWidget *editor, const QModelIndex& if (mValues[i].first==value) { comboBox->setCurrentIndex (i); - if(!tryDisplay) - comboBox->showPopup(); break; } } From dd1e4e8b691c45669669503033b00c972335767b Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 19 Apr 2015 08:58:52 +1000 Subject: [PATCH 0966/3725] Remove gcc/clang warnings. --- .../model/world/nestedcoladapterimp.cpp | 56 ++++++------- .../model/world/nestedcoladapterimp.hpp | 84 +++++++++---------- .../model/world/nestedcolumnadapter.hpp | 14 ++-- .../opencs/model/world/nestedidcollection.hpp | 14 ++-- apps/opencs/model/world/refidadapterimp.hpp | 16 ++-- 5 files changed, 92 insertions(+), 92 deletions(-) diff --git a/apps/opencs/model/world/nestedcoladapterimp.cpp b/apps/opencs/model/world/nestedcoladapterimp.cpp index d974a34c7..bd6a5c449 100644 --- a/apps/opencs/model/world/nestedcoladapterimp.cpp +++ b/apps/opencs/model/world/nestedcoladapterimp.cpp @@ -10,7 +10,7 @@ namespace CSMWorld { PathgridPointListAdapter::PathgridPointListAdapter () {} - void PathgridPointListAdapter::addNestedRow(Record& record, int position) const + void PathgridPointListAdapter::addRow(Record& record, int position) const { Pathgrid pathgrid = record.get(); @@ -43,7 +43,7 @@ namespace CSMWorld record.setModified (pathgrid); } - void PathgridPointListAdapter::removeNestedRow(Record& record, int rowToRemove) const + void PathgridPointListAdapter::removeRow(Record& record, int rowToRemove) const { Pathgrid pathgrid = record.get(); @@ -78,7 +78,7 @@ namespace CSMWorld record.setModified (pathgrid); } - void PathgridPointListAdapter::setNestedTable(Record& record, + void PathgridPointListAdapter::setTable(Record& record, const NestedTableWrapperBase& nestedTable) const { Pathgrid pathgrid = record.get(); @@ -100,7 +100,7 @@ namespace CSMWorld return new PathgridPointsWrap(record.get()); } - QVariant PathgridPointListAdapter::getNestedData(const Record& record, + QVariant PathgridPointListAdapter::getData(const Record& record, int subRowIndex, int subColIndex) const { ESM::Pathgrid::Point point = record.get().mPoints[subRowIndex]; @@ -114,7 +114,7 @@ namespace CSMWorld } } - void PathgridPointListAdapter::setNestedData(Record& record, + void PathgridPointListAdapter::setData(Record& record, const QVariant& value, int subRowIndex, int subColIndex) const { Pathgrid pathgrid = record.get(); @@ -133,12 +133,12 @@ namespace CSMWorld record.setModified (pathgrid); } - int PathgridPointListAdapter::getNestedColumnsCount(const Record& record) const + int PathgridPointListAdapter::getColumnsCount(const Record& record) const { return 4; } - int PathgridPointListAdapter::getNestedRowsCount(const Record& record) const + int PathgridPointListAdapter::getRowsCount(const Record& record) const { return static_cast(record.get().mPoints.size()); } @@ -146,7 +146,7 @@ namespace CSMWorld PathgridEdgeListAdapter::PathgridEdgeListAdapter () {} // ToDo: seems to be auto-sorted in the dialog table display after insertion - void PathgridEdgeListAdapter::addNestedRow(Record& record, int position) const + void PathgridEdgeListAdapter::addRow(Record& record, int position) const { Pathgrid pathgrid = record.get(); @@ -167,7 +167,7 @@ namespace CSMWorld record.setModified (pathgrid); } - void PathgridEdgeListAdapter::removeNestedRow(Record& record, int rowToRemove) const + void PathgridEdgeListAdapter::removeRow(Record& record, int rowToRemove) const { Pathgrid pathgrid = record.get(); @@ -181,7 +181,7 @@ namespace CSMWorld record.setModified (pathgrid); } - void PathgridEdgeListAdapter::setNestedTable(Record& record, + void PathgridEdgeListAdapter::setTable(Record& record, const NestedTableWrapperBase& nestedTable) const { Pathgrid pathgrid = record.get(); @@ -198,7 +198,7 @@ namespace CSMWorld return new NestedTableWrapper(record.get().mEdges); } - QVariant PathgridEdgeListAdapter::getNestedData(const Record& record, + QVariant PathgridEdgeListAdapter::getData(const Record& record, int subRowIndex, int subColIndex) const { Pathgrid pathgrid = record.get(); @@ -217,7 +217,7 @@ namespace CSMWorld } // ToDo: detect duplicates in mEdges - void PathgridEdgeListAdapter::setNestedData(Record& record, + void PathgridEdgeListAdapter::setData(Record& record, const QVariant& value, int subRowIndex, int subColIndex) const { Pathgrid pathgrid = record.get(); @@ -239,19 +239,19 @@ namespace CSMWorld record.setModified (pathgrid); } - int PathgridEdgeListAdapter::getNestedColumnsCount(const Record& record) const + int PathgridEdgeListAdapter::getColumnsCount(const Record& record) const { return 3; } - int PathgridEdgeListAdapter::getNestedRowsCount(const Record& record) const + int PathgridEdgeListAdapter::getRowsCount(const Record& record) const { return static_cast(record.get().mEdges.size()); } FactionReactionsAdapter::FactionReactionsAdapter () {} - void FactionReactionsAdapter::addNestedRow(Record& record, int position) const + void FactionReactionsAdapter::addRow(Record& record, int position) const { ESM::Faction faction = record.get(); @@ -263,7 +263,7 @@ namespace CSMWorld record.setModified (faction); } - void FactionReactionsAdapter::removeNestedRow(Record& record, int rowToRemove) const + void FactionReactionsAdapter::removeRow(Record& record, int rowToRemove) const { ESM::Faction faction = record.get(); @@ -282,7 +282,7 @@ namespace CSMWorld record.setModified (faction); } - void FactionReactionsAdapter::setNestedTable(Record& record, + void FactionReactionsAdapter::setTable(Record& record, const NestedTableWrapperBase& nestedTable) const { ESM::Faction faction = record.get(); @@ -299,7 +299,7 @@ namespace CSMWorld return new NestedTableWrapper >(record.get().mReactions); } - QVariant FactionReactionsAdapter::getNestedData(const Record& record, + QVariant FactionReactionsAdapter::getData(const Record& record, int subRowIndex, int subColIndex) const { ESM::Faction faction = record.get(); @@ -322,7 +322,7 @@ namespace CSMWorld } } - void FactionReactionsAdapter::setNestedData(Record& record, + void FactionReactionsAdapter::setData(Record& record, const QVariant& value, int subRowIndex, int subColIndex) const { ESM::Faction faction = record.get(); @@ -360,19 +360,19 @@ namespace CSMWorld record.setModified (faction); } - int FactionReactionsAdapter::getNestedColumnsCount(const Record& record) const + int FactionReactionsAdapter::getColumnsCount(const Record& record) const { return 2; } - int FactionReactionsAdapter::getNestedRowsCount(const Record& record) const + int FactionReactionsAdapter::getRowsCount(const Record& record) const { return static_cast(record.get().mReactions.size()); } RegionSoundListAdapter::RegionSoundListAdapter () {} - void RegionSoundListAdapter::addNestedRow(Record& record, int position) const + void RegionSoundListAdapter::addRow(Record& record, int position) const { ESM::Region region = record.get(); @@ -388,7 +388,7 @@ namespace CSMWorld record.setModified (region); } - void RegionSoundListAdapter::removeNestedRow(Record& record, int rowToRemove) const + void RegionSoundListAdapter::removeRow(Record& record, int rowToRemove) const { ESM::Region region = record.get(); @@ -402,7 +402,7 @@ namespace CSMWorld record.setModified (region); } - void RegionSoundListAdapter::setNestedTable(Record& record, + void RegionSoundListAdapter::setTable(Record& record, const NestedTableWrapperBase& nestedTable) const { ESM::Region region = record.get(); @@ -419,7 +419,7 @@ namespace CSMWorld return new NestedTableWrapper >(record.get().mSoundList); } - QVariant RegionSoundListAdapter::getNestedData(const Record& record, + QVariant RegionSoundListAdapter::getData(const Record& record, int subRowIndex, int subColIndex) const { ESM::Region region = record.get(); @@ -438,7 +438,7 @@ namespace CSMWorld } } - void RegionSoundListAdapter::setNestedData(Record& record, + void RegionSoundListAdapter::setData(Record& record, const QVariant& value, int subRowIndex, int subColIndex) const { ESM::Region region = record.get(); @@ -461,12 +461,12 @@ namespace CSMWorld record.setModified (region); } - int RegionSoundListAdapter::getNestedColumnsCount(const Record& record) const + int RegionSoundListAdapter::getColumnsCount(const Record& record) const { return 2; } - int RegionSoundListAdapter::getNestedRowsCount(const Record& record) const + int RegionSoundListAdapter::getRowsCount(const Record& record) const { return static_cast(record.get().mSoundList.size()); } diff --git a/apps/opencs/model/world/nestedcoladapterimp.hpp b/apps/opencs/model/world/nestedcoladapterimp.hpp index 841c3955a..8d0b0ce7a 100644 --- a/apps/opencs/model/world/nestedcoladapterimp.hpp +++ b/apps/opencs/model/world/nestedcoladapterimp.hpp @@ -42,24 +42,24 @@ namespace CSMWorld public: PathgridPointListAdapter (); - virtual void addNestedRow(Record& record, int position) const; + virtual void addRow(Record& record, int position) const; - virtual void removeNestedRow(Record& record, int rowToRemove) const; + virtual void removeRow(Record& record, int rowToRemove) const; - virtual void setNestedTable(Record& record, + virtual void setTable(Record& record, const NestedTableWrapperBase& nestedTable) const; virtual NestedTableWrapperBase* nestedTable(const Record& record) const; - virtual QVariant getNestedData(const Record& record, + virtual QVariant getData(const Record& record, int subRowIndex, int subColIndex) const; - virtual void setNestedData(Record& record, + virtual void setData(Record& record, const QVariant& value, int subRowIndex, int subColIndex) const; - virtual int getNestedColumnsCount(const Record& record) const; + virtual int getColumnsCount(const Record& record) const; - virtual int getNestedRowsCount(const Record& record) const; + virtual int getRowsCount(const Record& record) const; }; class PathgridEdgeListAdapter : public NestedColumnAdapter @@ -67,24 +67,24 @@ namespace CSMWorld public: PathgridEdgeListAdapter (); - virtual void addNestedRow(Record& record, int position) const; + virtual void addRow(Record& record, int position) const; - virtual void removeNestedRow(Record& record, int rowToRemove) const; + virtual void removeRow(Record& record, int rowToRemove) const; - virtual void setNestedTable(Record& record, + virtual void setTable(Record& record, const NestedTableWrapperBase& nestedTable) const; virtual NestedTableWrapperBase* nestedTable(const Record& record) const; - virtual QVariant getNestedData(const Record& record, + virtual QVariant getData(const Record& record, int subRowIndex, int subColIndex) const; - virtual void setNestedData(Record& record, + virtual void setData(Record& record, const QVariant& value, int subRowIndex, int subColIndex) const; - virtual int getNestedColumnsCount(const Record& record) const; + virtual int getColumnsCount(const Record& record) const; - virtual int getNestedRowsCount(const Record& record) const; + virtual int getRowsCount(const Record& record) const; }; class FactionReactionsAdapter : public NestedColumnAdapter @@ -92,24 +92,24 @@ namespace CSMWorld public: FactionReactionsAdapter (); - virtual void addNestedRow(Record& record, int position) const; + virtual void addRow(Record& record, int position) const; - virtual void removeNestedRow(Record& record, int rowToRemove) const; + virtual void removeRow(Record& record, int rowToRemove) const; - virtual void setNestedTable(Record& record, + virtual void setTable(Record& record, const NestedTableWrapperBase& nestedTable) const; virtual NestedTableWrapperBase* nestedTable(const Record& record) const; - virtual QVariant getNestedData(const Record& record, + virtual QVariant getData(const Record& record, int subRowIndex, int subColIndex) const; - virtual void setNestedData(Record& record, + virtual void setData(Record& record, const QVariant& value, int subRowIndex, int subColIndex) const; - virtual int getNestedColumnsCount(const Record& record) const; + virtual int getColumnsCount(const Record& record) const; - virtual int getNestedRowsCount(const Record& record) const; + virtual int getRowsCount(const Record& record) const; }; class RegionSoundListAdapter : public NestedColumnAdapter @@ -117,24 +117,24 @@ namespace CSMWorld public: RegionSoundListAdapter (); - virtual void addNestedRow(Record& record, int position) const; + virtual void addRow(Record& record, int position) const; - virtual void removeNestedRow(Record& record, int rowToRemove) const; + virtual void removeRow(Record& record, int rowToRemove) const; - virtual void setNestedTable(Record& record, + virtual void setTable(Record& record, const NestedTableWrapperBase& nestedTable) const; virtual NestedTableWrapperBase* nestedTable(const Record& record) const; - virtual QVariant getNestedData(const Record& record, + virtual QVariant getData(const Record& record, int subRowIndex, int subColIndex) const; - virtual void setNestedData(Record& record, + virtual void setData(Record& record, const QVariant& value, int subRowIndex, int subColIndex) const; - virtual int getNestedColumnsCount(const Record& record) const; + virtual int getColumnsCount(const Record& record) const; - virtual int getNestedRowsCount(const Record& record) const; + virtual int getRowsCount(const Record& record) const; }; template @@ -143,7 +143,7 @@ namespace CSMWorld public: SpellListAdapter () {} - virtual void addNestedRow(Record& record, int position) const + virtual void addRow(Record& record, int position) const { ESXRecordT raceOrBthSgn = record.get(); @@ -157,7 +157,7 @@ namespace CSMWorld record.setModified (raceOrBthSgn); } - virtual void removeNestedRow(Record& record, int rowToRemove) const + virtual void removeRow(Record& record, int rowToRemove) const { ESXRecordT raceOrBthSgn = record.get(); @@ -171,7 +171,7 @@ namespace CSMWorld record.setModified (raceOrBthSgn); } - virtual void setNestedTable(Record& record, const NestedTableWrapperBase& nestedTable) const + virtual void setTable(Record& record, const NestedTableWrapperBase& nestedTable) const { ESXRecordT raceOrBthSgn = record.get(); @@ -187,7 +187,7 @@ namespace CSMWorld return new NestedTableWrapper >(record.get().mPowers.mList); } - virtual QVariant getNestedData(const Record& record, int subRowIndex, int subColIndex) const + virtual QVariant getData(const Record& record, int subRowIndex, int subColIndex) const { ESXRecordT raceOrBthSgn = record.get(); @@ -204,7 +204,7 @@ namespace CSMWorld } } - virtual void setNestedData(Record& record, const QVariant& value, + virtual void setData(Record& record, const QVariant& value, int subRowIndex, int subColIndex) const { ESXRecordT raceOrBthSgn = record.get(); @@ -226,12 +226,12 @@ namespace CSMWorld record.setModified (raceOrBthSgn); } - virtual int getNestedColumnsCount(const Record& record) const + virtual int getColumnsCount(const Record& record) const { return 1; } - virtual int getNestedRowsCount(const Record& record) const + virtual int getRowsCount(const Record& record) const { return static_cast(record.get().mPowers.mList.size()); } @@ -243,7 +243,7 @@ namespace CSMWorld public: EffectsListAdapter () {} - virtual void addNestedRow(Record& record, int position) const + virtual void addRow(Record& record, int position) const { ESXRecordT magic = record.get(); @@ -265,7 +265,7 @@ namespace CSMWorld record.setModified (magic); } - virtual void removeNestedRow(Record& record, int rowToRemove) const + virtual void removeRow(Record& record, int rowToRemove) const { ESXRecordT magic = record.get(); @@ -279,7 +279,7 @@ namespace CSMWorld record.setModified (magic); } - virtual void setNestedTable(Record& record, const NestedTableWrapperBase& nestedTable) const + virtual void setTable(Record& record, const NestedTableWrapperBase& nestedTable) const { ESXRecordT magic = record.get(); @@ -295,7 +295,7 @@ namespace CSMWorld return new NestedTableWrapper >(record.get().mEffects.mList); } - virtual QVariant getNestedData(const Record& record, int subRowIndex, int subColIndex) const + virtual QVariant getData(const Record& record, int subRowIndex, int subColIndex) const { ESXRecordT magic = record.get(); @@ -331,7 +331,7 @@ namespace CSMWorld } } - virtual void setNestedData(Record& record, const QVariant& value, + virtual void setData(Record& record, const QVariant& value, int subRowIndex, int subColIndex) const { ESXRecordT magic = record.get(); @@ -376,12 +376,12 @@ namespace CSMWorld record.setModified (magic); } - virtual int getNestedColumnsCount(const Record& record) const + virtual int getColumnsCount(const Record& record) const { return 8; } - virtual int getNestedRowsCount(const Record& record) const + virtual int getRowsCount(const Record& record) const { return static_cast(record.get().mEffects.mList.size()); } diff --git a/apps/opencs/model/world/nestedcolumnadapter.hpp b/apps/opencs/model/world/nestedcolumnadapter.hpp index e7e66ed4d..5e7256fa7 100644 --- a/apps/opencs/model/world/nestedcolumnadapter.hpp +++ b/apps/opencs/model/world/nestedcolumnadapter.hpp @@ -19,21 +19,21 @@ namespace CSMWorld virtual ~NestedColumnAdapter() {} - virtual void addNestedRow(Record& record, int position) const = 0; + virtual void addRow(Record& record, int position) const = 0; - virtual void removeNestedRow(Record& record, int rowToRemove) const = 0; + virtual void removeRow(Record& record, int rowToRemove) const = 0; - virtual void setNestedTable(Record& record, const NestedTableWrapperBase& nestedTable) const = 0; + virtual void setTable(Record& record, const NestedTableWrapperBase& nestedTable) const = 0; virtual NestedTableWrapperBase* nestedTable(const Record& record) const = 0; - virtual QVariant getNestedData(const Record& record, int subRowIndex, int subColIndex) const = 0; + virtual QVariant getData(const Record& record, int subRowIndex, int subColIndex) const = 0; - virtual void setNestedData(Record& record, const QVariant& value, int subRowIndex, int subColIndex) const = 0; + virtual void setData(Record& record, const QVariant& value, int subRowIndex, int subColIndex) const = 0; - virtual int getNestedColumnsCount(const Record& record) const = 0; + virtual int getColumnsCount(const Record& record) const = 0; - virtual int getNestedRowsCount(const Record& record) const = 0; + virtual int getRowsCount(const Record& record) const = 0; }; } diff --git a/apps/opencs/model/world/nestedidcollection.hpp b/apps/opencs/model/world/nestedidcollection.hpp index 0cf51b9d8..2b795f9c6 100644 --- a/apps/opencs/model/world/nestedidcollection.hpp +++ b/apps/opencs/model/world/nestedidcollection.hpp @@ -93,7 +93,7 @@ namespace CSMWorld Record record; record.assign(Collection::getRecord(row)); - getAdapter(Collection::getColumn(column)).addNestedRow(record, position); + getAdapter(Collection::getColumn(column)).addRow(record, position); Collection::setRecord(row, record); } @@ -104,7 +104,7 @@ namespace CSMWorld Record record; record.assign(Collection::getRecord(row)); - getAdapter(Collection::getColumn(column)).removeNestedRow(record, subRow); + getAdapter(Collection::getColumn(column)).removeRow(record, subRow); Collection::setRecord(row, record); } @@ -113,7 +113,7 @@ namespace CSMWorld QVariant NestedIdCollection::getNestedData (int row, int column, int subRow, int subColumn) const { - return getAdapter(Collection::getColumn(column)).getNestedData( + return getAdapter(Collection::getColumn(column)).getData( Collection::getRecord(row), subRow, subColumn); } @@ -124,7 +124,7 @@ namespace CSMWorld Record record; record.assign(Collection::getRecord(row)); - getAdapter(Collection::getColumn(column)).setNestedData( + getAdapter(Collection::getColumn(column)).setData( record, data, subRow, subColumn); Collection::setRecord(row, record); @@ -145,7 +145,7 @@ namespace CSMWorld Record record; record.assign(Collection::getRecord(row)); - getAdapter(Collection::getColumn(column)).setNestedTable( + getAdapter(Collection::getColumn(column)).setTable( record, nestedTable); Collection::setRecord(row, record); @@ -154,14 +154,14 @@ namespace CSMWorld template int NestedIdCollection::getNestedRowsCount(int row, int column) const { - return getAdapter(Collection::getColumn(column)).getNestedRowsCount( + return getAdapter(Collection::getColumn(column)).getRowsCount( Collection::getRecord(row)); } template int NestedIdCollection::getNestedColumnsCount(int row, int column) const { - return getAdapter(Collection::getColumn(column)).getNestedColumnsCount( + return getAdapter(Collection::getColumn(column)).getColumnsCount( Collection::getRecord(row)); } diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index 5fd888441..9556c83e3 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -867,7 +867,7 @@ namespace CSMWorld { Record& record = static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); - EffectsListAdapter::addNestedRow(record, position); + EffectsListAdapter::addRow(record, position); } using NestedRefIdAdapterBase::removeNestedRow; @@ -876,7 +876,7 @@ namespace CSMWorld { Record& record = static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); - EffectsListAdapter::removeNestedRow(record, rowToRemove); + EffectsListAdapter::removeRow(record, rowToRemove); } using NestedRefIdAdapterBase::setNestedTable; @@ -885,7 +885,7 @@ namespace CSMWorld { Record& record = static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); - EffectsListAdapter::setNestedTable(record, nestedTable); + EffectsListAdapter::setTable(record, nestedTable); } using NestedRefIdAdapterBase::nestedTable; @@ -903,7 +903,7 @@ namespace CSMWorld { const Record& record = static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); - return EffectsListAdapter::getNestedData(record, subRowIndex, subColIndex); + return EffectsListAdapter::getData(record, subRowIndex, subColIndex); } using NestedRefIdAdapterBase::setNestedData; @@ -912,14 +912,14 @@ namespace CSMWorld { Record& record = static_cast&> (data.getRecord (RefIdData::LocalIndex (row, mType))); - EffectsListAdapter::setNestedData(record, value, subRowIndex, subColIndex); + EffectsListAdapter::setData(record, value, subRowIndex, subColIndex); } using NestedRefIdAdapterBase::getNestedColumnsCount; virtual int getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const { const Record record; // not used, just a dummy - return EffectsListAdapter::getNestedColumnsCount(record); + return EffectsListAdapter::getColumnsCount(record); } using NestedRefIdAdapterBase::getNestedRowsCount; @@ -927,7 +927,7 @@ namespace CSMWorld { const Record& record = static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); - return EffectsListAdapter::getNestedRowsCount(record); + return EffectsListAdapter::getRowsCount(record); } }; @@ -1731,7 +1731,7 @@ namespace CSMWorld { case 0: { - if (content.mPart >=0 && content.mPart < ESM::PRT_Count) + if (content.mPart < ESM::PRT_Count) return content.mPart; else throw std::runtime_error("Part Reference Type unexpected value"); From 8b1ac451acd0b5f3838d0a46e2cd7dd150d25f73 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 19 Apr 2015 09:42:44 +1000 Subject: [PATCH 0967/3725] More warning fixes. --- apps/opencs/model/world/nestedcoladapterimp.cpp | 8 ++++---- apps/opencs/model/world/nestedcoladapterimp.hpp | 12 ++++++------ apps/opencs/model/world/nestedcolumnadapter.hpp | 2 +- apps/opencs/model/world/nestedidcollection.hpp | 2 +- apps/opencs/model/world/refidadapterimp.hpp | 10 +--------- 5 files changed, 13 insertions(+), 21 deletions(-) diff --git a/apps/opencs/model/world/nestedcoladapterimp.cpp b/apps/opencs/model/world/nestedcoladapterimp.cpp index bd6a5c449..bfb2fb578 100644 --- a/apps/opencs/model/world/nestedcoladapterimp.cpp +++ b/apps/opencs/model/world/nestedcoladapterimp.cpp @@ -94,7 +94,7 @@ namespace CSMWorld record.setModified (pathgrid); } - NestedTableWrapperBase* PathgridPointListAdapter::nestedTable(const Record& record) const + NestedTableWrapperBase* PathgridPointListAdapter::table(const Record& record) const { // deleted by dtor of NestedTableStoring return new PathgridPointsWrap(record.get()); @@ -192,7 +192,7 @@ namespace CSMWorld record.setModified (pathgrid); } - NestedTableWrapperBase* PathgridEdgeListAdapter::nestedTable(const Record& record) const + NestedTableWrapperBase* PathgridEdgeListAdapter::table(const Record& record) const { // deleted by dtor of NestedTableStoring return new NestedTableWrapper(record.get().mEdges); @@ -293,7 +293,7 @@ namespace CSMWorld record.setModified (faction); } - NestedTableWrapperBase* FactionReactionsAdapter::nestedTable(const Record& record) const + NestedTableWrapperBase* FactionReactionsAdapter::table(const Record& record) const { // deleted by dtor of NestedTableStoring return new NestedTableWrapper >(record.get().mReactions); @@ -413,7 +413,7 @@ namespace CSMWorld record.setModified (region); } - NestedTableWrapperBase* RegionSoundListAdapter::nestedTable(const Record& record) const + NestedTableWrapperBase* RegionSoundListAdapter::table(const Record& record) const { // deleted by dtor of NestedTableStoring return new NestedTableWrapper >(record.get().mSoundList); diff --git a/apps/opencs/model/world/nestedcoladapterimp.hpp b/apps/opencs/model/world/nestedcoladapterimp.hpp index 8d0b0ce7a..4a7101cba 100644 --- a/apps/opencs/model/world/nestedcoladapterimp.hpp +++ b/apps/opencs/model/world/nestedcoladapterimp.hpp @@ -49,7 +49,7 @@ namespace CSMWorld virtual void setTable(Record& record, const NestedTableWrapperBase& nestedTable) const; - virtual NestedTableWrapperBase* nestedTable(const Record& record) const; + virtual NestedTableWrapperBase* table(const Record& record) const; virtual QVariant getData(const Record& record, int subRowIndex, int subColIndex) const; @@ -74,7 +74,7 @@ namespace CSMWorld virtual void setTable(Record& record, const NestedTableWrapperBase& nestedTable) const; - virtual NestedTableWrapperBase* nestedTable(const Record& record) const; + virtual NestedTableWrapperBase* table(const Record& record) const; virtual QVariant getData(const Record& record, int subRowIndex, int subColIndex) const; @@ -99,7 +99,7 @@ namespace CSMWorld virtual void setTable(Record& record, const NestedTableWrapperBase& nestedTable) const; - virtual NestedTableWrapperBase* nestedTable(const Record& record) const; + virtual NestedTableWrapperBase* table(const Record& record) const; virtual QVariant getData(const Record& record, int subRowIndex, int subColIndex) const; @@ -124,7 +124,7 @@ namespace CSMWorld virtual void setTable(Record& record, const NestedTableWrapperBase& nestedTable) const; - virtual NestedTableWrapperBase* nestedTable(const Record& record) const; + virtual NestedTableWrapperBase* table(const Record& record) const; virtual QVariant getData(const Record& record, int subRowIndex, int subColIndex) const; @@ -181,7 +181,7 @@ namespace CSMWorld record.setModified (raceOrBthSgn); } - virtual NestedTableWrapperBase* nestedTable(const Record& record) const + virtual NestedTableWrapperBase* table(const Record& record) const { // deleted by dtor of NestedTableStoring return new NestedTableWrapper >(record.get().mPowers.mList); @@ -289,7 +289,7 @@ namespace CSMWorld record.setModified (magic); } - virtual NestedTableWrapperBase* nestedTable(const Record& record) const + virtual NestedTableWrapperBase* table(const Record& record) const { // deleted by dtor of NestedTableStoring return new NestedTableWrapper >(record.get().mEffects.mList); diff --git a/apps/opencs/model/world/nestedcolumnadapter.hpp b/apps/opencs/model/world/nestedcolumnadapter.hpp index 5e7256fa7..462b5a5ab 100644 --- a/apps/opencs/model/world/nestedcolumnadapter.hpp +++ b/apps/opencs/model/world/nestedcolumnadapter.hpp @@ -25,7 +25,7 @@ namespace CSMWorld virtual void setTable(Record& record, const NestedTableWrapperBase& nestedTable) const = 0; - virtual NestedTableWrapperBase* nestedTable(const Record& record) const = 0; + virtual NestedTableWrapperBase* table(const Record& record) const = 0; virtual QVariant getData(const Record& record, int subRowIndex, int subColIndex) const = 0; diff --git a/apps/opencs/model/world/nestedidcollection.hpp b/apps/opencs/model/world/nestedidcollection.hpp index 2b795f9c6..792a13b7d 100644 --- a/apps/opencs/model/world/nestedidcollection.hpp +++ b/apps/opencs/model/world/nestedidcollection.hpp @@ -134,7 +134,7 @@ namespace CSMWorld CSMWorld::NestedTableWrapperBase* NestedIdCollection::nestedTable(int row, int column) const { - return getAdapter(Collection::getColumn(column)).nestedTable( + return getAdapter(Collection::getColumn(column)).table( Collection::getRecord(row)); } diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index 9556c83e3..d3d52d2e1 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -861,7 +861,6 @@ namespace CSMWorld virtual ~EffectsRefIdAdapter() {} - using NestedRefIdAdapterBase::addNestedRow; virtual void addNestedRow (const RefIdColumn *column, RefIdData& data, int index, int position) const { @@ -870,7 +869,6 @@ namespace CSMWorld EffectsListAdapter::addRow(record, position); } - using NestedRefIdAdapterBase::removeNestedRow; virtual void removeNestedRow (const RefIdColumn *column, RefIdData& data, int index, int rowToRemove) const { @@ -879,7 +877,6 @@ namespace CSMWorld EffectsListAdapter::removeRow(record, rowToRemove); } - using NestedRefIdAdapterBase::setNestedTable; virtual void setNestedTable (const RefIdColumn* column, RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const { @@ -888,16 +885,14 @@ namespace CSMWorld EffectsListAdapter::setTable(record, nestedTable); } - using NestedRefIdAdapterBase::nestedTable; virtual NestedTableWrapperBase* nestedTable (const RefIdColumn* column, const RefIdData& data, int index) const { const Record& record = static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); - return EffectsListAdapter::nestedTable(record); + return EffectsListAdapter::table(record); } - using NestedRefIdAdapterBase::getNestedData; virtual QVariant getNestedData (const RefIdColumn *column, const RefIdData& data, int index, int subRowIndex, int subColIndex) const { @@ -906,7 +901,6 @@ namespace CSMWorld return EffectsListAdapter::getData(record, subRowIndex, subColIndex); } - using NestedRefIdAdapterBase::setNestedData; virtual void setNestedData (const RefIdColumn *column, RefIdData& data, int row, const QVariant& value, int subRowIndex, int subColIndex) const { @@ -915,14 +909,12 @@ namespace CSMWorld EffectsListAdapter::setData(record, value, subRowIndex, subColIndex); } - using NestedRefIdAdapterBase::getNestedColumnsCount; virtual int getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const { const Record record; // not used, just a dummy return EffectsListAdapter::getColumnsCount(record); } - using NestedRefIdAdapterBase::getNestedRowsCount; virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const { const Record& record = From edc5cad79ebc7222ca2d32bca939f216fad5fe28 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 19 Apr 2015 01:57:52 +0200 Subject: [PATCH 0968/3725] Port Animation::addEffect --- apps/nifosgtest/test.cpp | 5 + apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwrender/animation.cpp | 163 +++++++++++++++++++++- apps/openmw/mwrender/animation.hpp | 62 ++++++-- apps/openmw/mwrender/npcanimation.cpp | 5 +- apps/openmw/mwrender/npcanimation.hpp | 20 --- apps/openmw/mwrender/objects.cpp | 2 +- apps/openmw/mwrender/objects.hpp | 2 +- apps/openmw/mwrender/renderingmanager.cpp | 5 + apps/openmw/mwrender/renderingmanager.hpp | 2 + apps/openmw/mwrender/vismask.hpp | 17 +++ apps/openmw/mwworld/scene.cpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 6 +- components/nifosg/controller.cpp | 5 + components/nifosg/controller.hpp | 2 + components/sceneutil/controller.cpp | 30 ++-- components/sceneutil/controller.hpp | 21 ++- 17 files changed, 292 insertions(+), 59 deletions(-) create mode 100644 apps/openmw/mwrender/vismask.hpp diff --git a/apps/nifosgtest/test.cpp b/apps/nifosgtest/test.cpp index 487a91890..6d0586775 100644 --- a/apps/nifosgtest/test.cpp +++ b/apps/nifosgtest/test.cpp @@ -14,6 +14,8 @@ #include +#include + #include #include @@ -129,6 +131,9 @@ int main(int argc, char** argv) Resource::TextureManager texMgr(&resourceMgr); newNode->addChild(loader.load(nif, &texMgr)); + SceneUtil::AssignControllerSourcesVisitor visitor(boost::shared_ptr(new SceneUtil::FrameTimeSource)); + newNode->accept(visitor); + osg::PositionAttitudeTransform* trans = new osg::PositionAttitudeTransform; root->addChild(trans); diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 91b1ab1c5..03a4181b5 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -20,7 +20,7 @@ set(GAME_HEADER source_group(game FILES ${GAME} ${GAME_HEADER}) add_openmw_dir (mwrender - actors objects renderingmanager animation sky npcanimation + actors objects renderingmanager animation sky npcanimation vismask # debugging camera creatureanimation activatoranimation # renderinginterface localmap occlusionquery water shadows # characterpreview globalmap ripplesimulation refraction diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 3aeaa2ed1..2febf9c9a 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -10,13 +10,18 @@ #include #include +#include + #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwworld/esmstore.hpp" #include "../mwworld/class.hpp" +#include "vismask.hpp" + namespace { @@ -62,6 +67,30 @@ namespace std::vector > mTextures; }; + class FindMaxControllerLengthVisitor : public SceneUtil::ControllerVisitor + { + public: + FindMaxControllerLengthVisitor() + : SceneUtil::ControllerVisitor() + , mMaxLength(0) + { + } + + virtual void visit(osg::Node& , SceneUtil::Controller& ctrl) + { + if (ctrl.mFunction) + mMaxLength = std::max(mMaxLength, ctrl.mFunction->getMaximum()); + } + + float getMaxLength() const + { + return mMaxLength; + } + + private: + float mMaxLength; + }; + } namespace MWRender @@ -83,6 +112,8 @@ namespace MWRender osg::Vec3f Animation::runAnimation(float duration) { + updateEffects(duration); + return osg::Vec3f(); } @@ -147,6 +178,133 @@ namespace MWRender return result; } + void Animation::addEffect (const std::string& model, int effectId, bool loop, const std::string& bonename, std::string texture) + { + // Early out if we already have this effect + for (std::vector::iterator it = mEffects.begin(); it != mEffects.end(); ++it) + if (it->mLoop && loop && it->mEffectId == effectId && it->mBoneName == bonename) + return; + + EffectParams params; + params.mModelName = model; + osg::ref_ptr parentNode; + if (bonename.empty()) + parentNode = mObjectRoot->asGroup(); + else + { + SceneUtil::FindByNameVisitor visitor(bonename); + mObjectRoot->accept(visitor); + if (!visitor.mFoundNode) + throw std::runtime_error("Can't find bone " + bonename); + parentNode = visitor.mFoundNode; + } + osg::ref_ptr node = mResourceSystem->getSceneManager()->createInstance(model, parentNode); + params.mObjects = PartHolderPtr(new PartHolder(node)); + + FindMaxControllerLengthVisitor findMaxLengthVisitor; + node->accept(findMaxLengthVisitor); + + params.mMaxControllerLength = findMaxLengthVisitor.getMaxLength(); + + node->setNodeMask(Mask_Effect); + + params.mLoop = loop; + params.mEffectId = effectId; + params.mBoneName = bonename; + + params.mAnimTime = boost::shared_ptr(new EffectAnimationTime); + + SceneUtil::AssignControllerSourcesVisitor assignVisitor(boost::shared_ptr(params.mAnimTime)); + node->accept(assignVisitor); + + if (!texture.empty()) + { + std::string correctedTexture = Misc::ResourceHelpers::correctTexturePath(texture, mResourceSystem->getVFS()); + // Not sure if wrap settings should be pulled from the overridden texture? + osg::ref_ptr tex = mResourceSystem->getTextureManager()->getTexture2D(correctedTexture, osg::Texture2D::CLAMP, + osg::Texture2D::CLAMP); + osg::ref_ptr stateset; + if (node->getStateSet()) + stateset = static_cast(node->getStateSet()->clone(osg::CopyOp::SHALLOW_COPY)); + else + stateset = new osg::StateSet; + + stateset->setTextureAttribute(0, tex, osg::StateAttribute::OVERRIDE); + + node->setStateSet(stateset); + } + + // TODO: in vanilla morrowind the effect is scaled based on the host object's bounding box. + + mEffects.push_back(params); + } + + void Animation::removeEffect(int effectId) + { + for (std::vector::iterator it = mEffects.begin(); it != mEffects.end(); ++it) + { + if (it->mEffectId == effectId) + { + mEffects.erase(it); + return; + } + } + } + + void Animation::getLoopingEffects(std::vector &out) + { + for (std::vector::iterator it = mEffects.begin(); it != mEffects.end(); ++it) + { + if (it->mLoop) + out.push_back(it->mEffectId); + } + } + + void Animation::updateEffects(float duration) + { + for (std::vector::iterator it = mEffects.begin(); it != mEffects.end(); ) + { + it->mAnimTime->addTime(duration); + + if (it->mAnimTime->getTime() >= it->mMaxControllerLength) + { + if (it->mLoop) + { + // Start from the beginning again; carry over the remainder + // Not sure if this is actually needed, the controller function might already handle loops + float remainder = it->mAnimTime->getTime() - it->mMaxControllerLength; + it->mAnimTime->resetTime(remainder); + } + else + { + it = mEffects.erase(it); + continue; + } + } + ++it; + } + } + + float Animation::EffectAnimationTime::getValue(osg::NodeVisitor*) + { + return mTime; + } + + void Animation::EffectAnimationTime::addTime(float duration) + { + mTime += duration; + } + + void Animation::EffectAnimationTime::resetTime(float time) + { + mTime = time; + } + + float Animation::EffectAnimationTime::getTime() const + { + return mTime; + } + // -------------------------------------------------------------------------------- ObjectAnimation::ObjectAnimation(const MWWorld::Ptr &ptr, const std::string &model, Resource::ResourceSystem* resourceSystem) @@ -159,11 +317,6 @@ namespace MWRender if (!ptr.getClass().getEnchantment(ptr).empty()) addGlow(mObjectRoot, getEnchantmentColor(ptr)); } - else - { - // No model given. Create an object root anyway, so that lights can be added to it if needed. - //mObjectRoot = NifOgre::ObjectScenePtr (new NifOgre::ObjectScene(mInsert->getCreator())); - } } } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 1feab7bf3..ccc4bfa23 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -61,17 +61,18 @@ protected: virtual void setValue(Ogre::Real value); }; - class EffectAnimationTime : public Ogre::ControllerValue + class EffectAnimationTime : public SceneUtil::ControllerSource { private: float mTime; public: - EffectAnimationTime() : mTime(0) { } - void addTime(float time) { mTime += time; } - void resetTime(float value) { mTime = value; } + virtual float getValue(osg::NodeVisitor* nv); - virtual Ogre::Real getValue() const; - virtual void setValue(Ogre::Real value); + void addTime(float duration); + void resetTime(float time); + float getTime() const; + + EffectAnimationTime() : mTime(0) { } }; class NullAnimationTime : public SceneUtil::ControllerSource @@ -124,6 +125,44 @@ protected: Resource::ResourceSystem* mResourceSystem; + /// @brief Detaches the node from its parent when the object goes out of scope. + class PartHolder + { + public: + PartHolder(osg::ref_ptr node) + : mNode(node) + { + } + + ~PartHolder() + { + if (mNode->getNumParents()) + mNode->getParent(0)->removeChild(mNode); + } + + osg::ref_ptr getNode() + { + return mNode; + } + + private: + osg::ref_ptr mNode; + }; + typedef boost::shared_ptr PartHolderPtr; + + struct EffectParams + { + std::string mModelName; // Just here so we don't add the same effect twice + PartHolderPtr mObjects; + boost::shared_ptr mAnimTime; + float mMaxControllerLength; + int mEffectId; + bool mLoop; + std::string mBoneName; + }; + + std::vector mEffects; + /* Sets the appropriate animations on the bone groups based on priority. */ //void resetActiveGroups(); @@ -192,12 +231,12 @@ public: * @param loop Loop the effect. If false, it is removed automatically after it finishes playing. If true, * you need to remove it manually using removeEffect when the effect should end. * @param bonename Bone to attach to, or empty string to use the scene node instead - * @param texture override the texture specified in the model's materials + * @param texture override the texture specified in the model's materials - if empty, do not override * @note Will not add an effect twice. */ - //void addEffect (const std::string& model, int effectId, bool loop = false, const std::string& bonename = "", std::string texture = ""); - //void removeEffect (int effectId); - //void getLoopingEffects (std::vector& out); + void addEffect (const std::string& model, int effectId, bool loop = false, const std::string& bonename = "", std::string texture = ""); + void removeEffect (int effectId); + void getLoopingEffects (std::vector& out); //void updatePtr(const MWWorld::Ptr &ptr); @@ -273,6 +312,9 @@ public: //float getVelocity(const std::string &groupname) const; virtual osg::Vec3f runAnimation(float duration); + + /// This is typically called as part of runAnimation, but may be called manually if needed. + void updateEffects(float duration); }; class ObjectAnimation : public Animation { diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index e30c701fc..c413d9334 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -587,12 +587,15 @@ public: } }; -PartHolderPtr NpcAnimation::insertBoundedPart(const std::string& model, int group, const std::string& bonename, const std::string& bonefilter, bool enchantedGlow, osg::Vec4f* glowColor) +Animation::PartHolderPtr NpcAnimation::insertBoundedPart(const std::string& model, int group, const std::string& bonename, const std::string& bonefilter, bool enchantedGlow, osg::Vec4f* glowColor) { osg::ref_ptr instance = mResourceSystem->getSceneManager()->createInstance(model); osg::ref_ptr attached = SceneUtil::attach(instance, mObjectRoot, bonefilter, bonename); if (enchantedGlow) addGlow(attached, *glowColor); + + // TODO: set group userdata for inventory picking + return PartHolderPtr(new PartHolder(attached)); } diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 2605d58e3..16bd45cc4 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -50,26 +50,6 @@ public: }; */ -/// @brief Detaches the node from its parent when the object goes out of scope. -class PartHolder -{ -public: - PartHolder(osg::ref_ptr node) - : mNode(node) - { - } - - ~PartHolder() - { - if (mNode->getNumParents()) - mNode->getParent(0)->removeChild(mNode); - } - -private: - osg::ref_ptr mNode; -}; -typedef boost::shared_ptr PartHolderPtr; - class NpcAnimation : public Animation, public WeaponAnimation, public MWWorld::InventoryStoreListener { public: diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 21d7c1ab5..4564e3a97 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -246,7 +246,7 @@ void Objects::removeCell(const MWWorld::CellStore* store) } } -void Objects::update(float dt, Ogre::Camera* camera) +void Objects::update(float dt) { PtrAnimationMap::const_iterator it = mObjects.begin(); for(;it != mObjects.end();++it) diff --git a/apps/openmw/mwrender/objects.hpp b/apps/openmw/mwrender/objects.hpp index 07328b959..f4d5675aa 100644 --- a/apps/openmw/mwrender/objects.hpp +++ b/apps/openmw/mwrender/objects.hpp @@ -49,7 +49,7 @@ public: Animation* getAnimation(const MWWorld::Ptr &ptr); - void update (float dt, Ogre::Camera* camera); + void update (float dt); ///< per-frame update //Ogre::AxisAlignedBox getDimensions(MWWorld::CellStore*); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index ba34cf303..26b86d1b2 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -160,4 +160,9 @@ namespace MWRender return mSky.get(); } + void RenderingManager::update(float dt, bool paused) + { + mObjects->update(dt); + } + } diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 1db0467ef..b7aec3786 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -63,6 +63,8 @@ namespace MWRender osg::Vec3f getEyePos(); + void update(float dt, bool paused); + private: osgViewer::Viewer& mViewer; osg::ref_ptr mRootNode; diff --git a/apps/openmw/mwrender/vismask.hpp b/apps/openmw/mwrender/vismask.hpp new file mode 100644 index 000000000..4a064b60f --- /dev/null +++ b/apps/openmw/mwrender/vismask.hpp @@ -0,0 +1,17 @@ +#ifndef OPENMW_MWRENDER_VISMASK_H +#define OPENMW_MWRENDER_VISMASK_H + +namespace MWRender +{ + + /// Node masks used for controlling visibility of game objects. + enum VisMask + { + Mask_UpdateVisitor = 0x1, // reserved for separating UpdateVisitors from CullVisitors + + Mask_Effect = 0x2 + }; + +} + +#endif diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 1084ae03a..c9fd84ee3 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -180,7 +180,7 @@ namespace MWWorld } } - //mRendering.update (duration, paused); + mRendering.update (duration, paused); } void Scene::unloadCell (CellStoreCollection::iterator iter) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 20298bd85..c6a1b5477 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1606,13 +1606,13 @@ namespace MWWorld goToJail(); updateWeather(duration, paused); - /* - if (!paused) - doPhysics (duration); + //if (!paused) + // doPhysics (duration); mWorldScene->update (duration, paused); + /* performUpdateSceneQueries (); updateWindowManager (); diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index ce004dc79..499a74d95 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -64,6 +64,11 @@ float ControllerFunction::calculate(float value) } } +float ControllerFunction::getMaximum() const +{ + return mStopTime; +} + KeyframeController::KeyframeController() { } diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index 3136b3118..e480f4c13 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -95,6 +95,8 @@ namespace NifOsg ControllerFunction(const Nif::Controller *ctrl); float calculate(float value); + + virtual float getMaximum() const; }; class GeomMorpherController : public osg::Drawable::UpdateCallback, public SceneUtil::Controller, public ValueInterpolator diff --git a/components/sceneutil/controller.cpp b/components/sceneutil/controller.cpp index 565d48672..1f1b95ac8 100644 --- a/components/sceneutil/controller.cpp +++ b/components/sceneutil/controller.cpp @@ -32,31 +32,26 @@ namespace SceneUtil return nv->getFrameStamp()->getSimulationTime(); } - AssignControllerSourcesVisitor::AssignControllerSourcesVisitor() + ControllerVisitor::ControllerVisitor() : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) { - } - AssignControllerSourcesVisitor::AssignControllerSourcesVisitor(boost::shared_ptr toAssign) - : mToAssign(toAssign) - , osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) - { } - void AssignControllerSourcesVisitor::apply(osg::Node &node) + void ControllerVisitor::apply(osg::Node &node) { osg::NodeCallback* callback = node.getUpdateCallback(); while (callback) { if (Controller* ctrl = dynamic_cast(callback)) - assign(node, *ctrl); + visit(node, *ctrl); if (CompositeStateSetUpdater* composite = dynamic_cast(callback)) { for (unsigned int i=0; igetNumControllers(); ++i) { StateSetUpdater* statesetcontroller = composite->getController(i); if (Controller* ctrl = dynamic_cast(statesetcontroller)) - assign(node, *ctrl); + visit(node, *ctrl); } } @@ -66,18 +61,29 @@ namespace SceneUtil traverse(node); } - void AssignControllerSourcesVisitor::apply(osg::Geode &geode) + void ControllerVisitor::apply(osg::Geode &geode) { for (unsigned int i=0; igetUpdateCallback(); if (Controller* ctrl = dynamic_cast(callback)) - assign(geode, *ctrl); + visit(geode, *ctrl); } } - void AssignControllerSourcesVisitor::assign(osg::Node&, Controller &ctrl) + AssignControllerSourcesVisitor::AssignControllerSourcesVisitor() + : ControllerVisitor() + { + } + + AssignControllerSourcesVisitor::AssignControllerSourcesVisitor(boost::shared_ptr toAssign) + : ControllerVisitor() + , mToAssign(toAssign) + { + } + + void AssignControllerSourcesVisitor::visit(osg::Node&, Controller &ctrl) { if (!ctrl.mSource.get()) ctrl.mSource = mToAssign; diff --git a/components/sceneutil/controller.hpp b/components/sceneutil/controller.hpp index de73c7e80..655e02164 100644 --- a/components/sceneutil/controller.hpp +++ b/components/sceneutil/controller.hpp @@ -25,6 +25,10 @@ namespace SceneUtil { public: virtual float calculate(float input) = 0; + + /// Get the "stop time" of the controller function, typically the maximum of the calculate() function. + /// May not be meaningful for all types of controller functions. + virtual float getMaximum() const = 0; }; class Controller @@ -42,18 +46,27 @@ namespace SceneUtil boost::shared_ptr mFunction; }; - class AssignControllerSourcesVisitor : public osg::NodeVisitor + /// Pure virtual base class - visit() all controllers that are attached as UpdateCallbacks in a scene graph. + class ControllerVisitor : public osg::NodeVisitor { public: - AssignControllerSourcesVisitor(); - AssignControllerSourcesVisitor(boost::shared_ptr toAssign); + ControllerVisitor(); virtual void apply(osg::Node& node); virtual void apply(osg::Geode& geode); + virtual void visit(osg::Node& node, Controller& ctrl) = 0; + }; + + class AssignControllerSourcesVisitor : public ControllerVisitor + { + public: + AssignControllerSourcesVisitor(); + AssignControllerSourcesVisitor(boost::shared_ptr toAssign); + /// Assign the wanted ControllerSource. May be overriden in derived classes. /// By default assigns the ControllerSource passed to the constructor of this class if no ControllerSource is assigned to that controller yet. - virtual void assign(osg::Node& node, Controller& ctrl); + virtual void visit(osg::Node& node, Controller& ctrl); private: boost::shared_ptr mToAssign; From cb3396643b44d07d95df7d17a396103c1959bf58 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 19 Apr 2015 10:32:06 +1000 Subject: [PATCH 0969/3725] Back to the old layout of dialoguesubview. --- apps/opencs/view/world/dialoguesubview.cpp | 39 ++++++++++------------ 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 6626d67c3..2e800b56f 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -405,21 +405,22 @@ void CSVWorld::EditWidget::remake(int row) line->setGeometry(QRect(320, 150, 118, 3)); line->setFrameShape(QFrame::HLine); line->setFrameShadow(QFrame::Sunken); + + QFrame* line2 = new QFrame(mMainWidget); + line2->setObjectName(QString::fromUtf8("line")); + line2->setGeometry(QRect(320, 150, 118, 3)); + line2->setFrameShape(QFrame::HLine); + line2->setFrameShadow(QFrame::Sunken); + QVBoxLayout *mainLayout = new QVBoxLayout(mMainWidget); QGridLayout *lockedLayout = new QGridLayout(); - QScrollArea *scroll = new QScrollArea(mMainWidget); - QWidget *unlockedWidget = new QWidget(scroll); - QVBoxLayout *overLayout = new QVBoxLayout(unlockedWidget); QGridLayout *unlockedLayout = new QGridLayout(); QVBoxLayout *tablesLayout = new QVBoxLayout(); mainLayout->addLayout(lockedLayout, QSizePolicy::Fixed); - mainLayout->addSpacing(5); // FIXME: arbitrary number mainLayout->addWidget(line, 1); - mainLayout->addWidget(scroll, QSizePolicy::Preferred); - overLayout->addLayout(unlockedLayout, QSizePolicy::Preferred); - overLayout->addStretch(1); - mainLayout->addSpacing(5); // FIXME: arbitrary number + mainLayout->addLayout(unlockedLayout, QSizePolicy::Preferred); + mainLayout->addWidget(line2, 1); mainLayout->addLayout(tablesLayout, QSizePolicy::Preferred); mainLayout->addStretch(1); @@ -443,11 +444,15 @@ void CSVWorld::EditWidget::remake(int row) NestedTable* table = new NestedTable(mDocument, mNestedModels.back(), this); // FIXME: does not work well when enum delegates are used - table->setVisible(false); - table->resizeColumnsToContents(); - table->setVisible(true); + //table->resizeColumnsToContents(); table->setEditTriggers(QAbstractItemView::SelectedClicked | QAbstractItemView::CurrentChanged); + int rows = mNestedModels.back()->rowCount(mTable->index(row, i)); + int rowHeight = (rows == 0) ? table->horizontalHeader()->height() : table->rowHeight(0); + int tableMaxHeight = (5 * rowHeight) + + table->horizontalHeader()->height() + 2 * table->frameWidth(); + table->setMinimumHeight(tableMaxHeight); + QLabel* label = new QLabel (mTable->headerData (i, Qt::Horizontal, Qt::DisplayRole).toString(), mMainWidget); @@ -538,18 +543,8 @@ void CSVWorld::EditWidget::remake(int row) mWidgetMapper->setCurrentModelIndex(mTable->index(row, 0)); - if (unlocked != 0) - { + if (unlocked == 0) mainLayout->removeWidget(line); - scroll->setWidget(unlockedWidget); - scroll->setSizePolicy (QSizePolicy::Expanding, QSizePolicy::Minimum); - scroll->setWidgetResizable(true); - } - else - { - delete unlockedWidget; - delete scroll; - } this->setWidget(mMainWidget); this->setWidgetResizable(true); From 27cfe8fb5892f7795fe0c78cb2200d6e98f16bdc Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 19 Apr 2015 02:39:10 +0200 Subject: [PATCH 0970/3725] Crash fix --- apps/openmw/mwworld/inventorystore.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 2de3abc75..e3254d30a 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -587,10 +587,12 @@ void MWWorld::InventoryStore::fireEquipmentChangedEvent(const Ptr& actor) mListener->equipmentChanged(); // if player, update inventory window + /* if (actor == MWBase::Environment::get().getWorld()->getPlayerPtr()) { MWBase::Environment::get().getWindowManager()->getInventoryWindow()->updateItemView(); } + */ } void MWWorld::InventoryStore::visitEffectSources(MWMechanics::EffectSourceVisitor &visitor) From 9c4b2ea61a5183902200e0de89c8dc4fe69dfff4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 19 Apr 2015 03:05:47 +0200 Subject: [PATCH 0971/3725] CreatureAnimation compiles --- apps/openmw/CMakeLists.txt | 3 +- apps/openmw/engine.cpp | 13 +-- apps/openmw/mwrender/creatureanimation.cpp | 108 +++++++++++---------- apps/openmw/mwrender/creatureanimation.hpp | 26 ++--- apps/openmw/mwrender/npcanimation.cpp | 22 ----- apps/openmw/mwrender/objects.cpp | 9 +- 6 files changed, 80 insertions(+), 101 deletions(-) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 03a4181b5..32ed17c5b 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -21,7 +21,8 @@ source_group(game FILES ${GAME} ${GAME_HEADER}) add_openmw_dir (mwrender actors objects renderingmanager animation sky npcanimation vismask -# debugging camera creatureanimation activatoranimation + creatureanimation +# debugging camera activatoranimation # renderinginterface localmap occlusionquery water shadows # characterpreview globalmap ripplesimulation refraction # terrainstorage renderconst effectmanager weaponanimation diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 9a7f023e6..fe6180299 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -497,6 +497,7 @@ void OMW::Engine::go() { double dt = frameTimer.time_s(); frameTimer.setStartTick(); + //dt = std::min(dt, 0.2f); // frameRenderingQueued(dt); MWBase::Environment::get().getWorld()->update(dt, false); @@ -507,18 +508,6 @@ void OMW::Engine::go() mViewer.frame(/*simulationTime*/); } - /* - Ogre::Timer timer; - while (!MWBase::Environment::get().getStateManager()->hasQuitRequest()) - { - float dt = timer.getMilliseconds()/1000.f; - dt = std::min(dt, 0.2f); - - timer.reset(); - Ogre::Root::getSingleton().renderOneFrame(dt); - } - */ - // Save user settings settings.saveUser(settingspath); diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index 7260fc6d1..9ccdf390e 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -1,11 +1,13 @@ #include "creatureanimation.hpp" -#include -#include -#include - #include +#include + +#include +#include +#include + #include "../mwbase/world.hpp" #include "../mwworld/class.hpp" @@ -16,45 +18,46 @@ namespace MWRender { -CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr, const std::string& model) - : Animation(ptr, ptr.getRefData().getBaseNode()) +CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr, + const std::string& model, Resource::ResourceSystem* resourceSystem) + : Animation(ptr, osg::ref_ptr(ptr.getRefData().getBaseNode()), resourceSystem) { - MWWorld::LiveCellRef *ref = mPtr.get(); + //MWWorld::LiveCellRef *ref = mPtr.get(); if(!model.empty()) { - setObjectRoot(model, false); - setRenderProperties(mObjectRoot, RV_Actors, RQG_Main, RQG_Alpha); + setObjectRoot(model /* , baseonly = false */); + //setRenderProperties(mObjectRoot, RV_Actors, RQG_Main, RQG_Alpha); - if((ref->mBase->mFlags&ESM::Creature::Bipedal)) - addAnimSource("meshes\\xbase_anim.nif"); - addAnimSource(model); + //if((ref->mBase->mFlags&ESM::Creature::Bipedal)) + // addAnimSource("meshes\\xbase_anim.nif"); + //addAnimSource(model); } } -CreatureWeaponAnimation::CreatureWeaponAnimation(const MWWorld::Ptr &ptr, const std::string& model) - : Animation(ptr, ptr.getRefData().getBaseNode()) +CreatureWeaponAnimation::CreatureWeaponAnimation(const MWWorld::Ptr &ptr, const std::string& model, Resource::ResourceSystem* resourceSystem) + : Animation(ptr, osg::ref_ptr(ptr.getRefData().getBaseNode()), resourceSystem) , mShowWeapons(false) , mShowCarriedLeft(false) { - MWWorld::LiveCellRef *ref = mPtr.get(); + //MWWorld::LiveCellRef *ref = mPtr.get(); if(!model.empty()) { - setObjectRoot(model, false); - setRenderProperties(mObjectRoot, RV_Actors, RQG_Main, RQG_Alpha); + setObjectRoot(model /* , baseonly = false*/); + //setRenderProperties(mObjectRoot, RV_Actors, RQG_Main, RQG_Alpha); - if((ref->mBase->mFlags&ESM::Creature::Bipedal)) - addAnimSource("meshes\\xbase_anim.nif"); - addAnimSource(model); + //if((ref->mBase->mFlags&ESM::Creature::Bipedal)) + // addAnimSource("meshes\\xbase_anim.nif"); + //addAnimSource(model); mPtr.getClass().getInventoryStore(mPtr).setListener(this, mPtr); updateParts(); } - mWeaponAnimationTime = Ogre::SharedPtr(new WeaponAnimationTime(this)); + //mWeaponAnimationTime = Ogre::SharedPtr(new WeaponAnimationTime(this)); } void CreatureWeaponAnimation::showWeapons(bool showWeapon) @@ -77,8 +80,8 @@ void CreatureWeaponAnimation::showCarriedLeft(bool show) void CreatureWeaponAnimation::updateParts() { - mWeapon.setNull(); - mShield.setNull(); + mWeapon.reset(); + mShield.reset(); if (mShowWeapons) updatePart(mWeapon, MWWorld::InventoryStore::Slot_CarriedRight); @@ -86,9 +89,9 @@ void CreatureWeaponAnimation::updateParts() updatePart(mShield, MWWorld::InventoryStore::Slot_CarriedLeft); } -void CreatureWeaponAnimation::updatePart(NifOgre::ObjectScenePtr& scene, int slot) +void CreatureWeaponAnimation::updatePart(PartHolderPtr& scene, int slot) { - if (!mSkelBase) + if (!mObjectRoot) return; MWWorld::InventoryStore& inv = mPtr.getClass().getInventoryStore(mPtr); @@ -96,7 +99,7 @@ void CreatureWeaponAnimation::updatePart(NifOgre::ObjectScenePtr& scene, int slo if (it == inv.end()) { - scene.setNull(); + scene.reset(); return; } MWWorld::Ptr item = *it; @@ -107,13 +110,16 @@ void CreatureWeaponAnimation::updatePart(NifOgre::ObjectScenePtr& scene, int slo else bonename = "Shield Bone"; - scene = NifOgre::Loader::createObjects(mSkelBase, bonename, bonename, mInsert, item.getClass().getModel(item)); - Ogre::Vector3 glowColor = getEnchantmentColor(item); + osg::ref_ptr node = mResourceSystem->getSceneManager()->createInstance(item.getClass().getModel(item)); + SceneUtil::attach(node, mObjectRoot, bonename, bonename); - setRenderProperties(scene, RV_Actors, RQG_Main, RQG_Alpha, 0, - !item.getClass().getEnchantment(item).empty(), &glowColor); + scene.reset(new PartHolder(node)); + + if (!item.getClass().getEnchantment(item).empty()) + addGlow(node, getEnchantmentColor(item)); // Crossbows start out with a bolt attached + // FIXME: code duplicated from NpcAnimation if (slot == MWWorld::InventoryStore::Slot_CarriedRight && item.getTypeName() == typeid(ESM::Weapon).name() && item.get()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow) @@ -121,12 +127,14 @@ void CreatureWeaponAnimation::updatePart(NifOgre::ObjectScenePtr& scene, int slo MWWorld::ContainerStoreIterator ammo = inv.getSlot(MWWorld::InventoryStore::Slot_Ammunition); if (ammo != inv.end() && ammo->get()->mBase->mData.mType == ESM::Weapon::Bolt) attachArrow(); - else - mAmmunition.setNull(); + //else + // mAmmunition.setNull(); } - else - mAmmunition.setNull(); + //else + //mAmmunition.setNull(); + // FIXME: code duplicated from NpcAnimation + /* if(scene->mSkelBase) { Ogre::SkeletonInstance *skel = scene->mSkelBase->getSkeleton(); @@ -149,7 +157,9 @@ void CreatureWeaponAnimation::updatePart(NifOgre::ObjectScenePtr& scene, int slo } updateSkeletonInstance(mSkelBase->getSkeleton(), skel); } + */ + /* std::vector >::iterator ctrl(scene->mControllers.begin()); for(;ctrl != scene->mControllers.end();++ctrl) { @@ -161,45 +171,39 @@ void CreatureWeaponAnimation::updatePart(NifOgre::ObjectScenePtr& scene, int slo ctrl->setSource(Ogre::SharedPtr(new NullAnimationTime())); } } + */ } +/* void CreatureWeaponAnimation::configureAddedObject(NifOgre::ObjectScenePtr object, MWWorld::Ptr ptr, int slot) { - Ogre::Vector3 glowColor = getEnchantmentColor(ptr); + //Ogre::Vector3 glowColor = getEnchantmentColor(ptr); - setRenderProperties(object, RV_Actors, RQG_Main, RQG_Alpha, 0, - !ptr.getClass().getEnchantment(ptr).empty(), &glowColor); + //setRenderProperties(object, RV_Actors, RQG_Main, RQG_Alpha, 0, + // !ptr.getClass().getEnchantment(ptr).empty(), &glowColor); } +*/ void CreatureWeaponAnimation::attachArrow() { - WeaponAnimation::attachArrow(mPtr); + //WeaponAnimation::attachArrow(mPtr); } void CreatureWeaponAnimation::releaseArrow() { - WeaponAnimation::releaseArrow(mPtr); + //WeaponAnimation::releaseArrow(mPtr); } -Ogre::Vector3 CreatureWeaponAnimation::runAnimation(float duration) +osg::Vec3f CreatureWeaponAnimation::runAnimation(float duration) { + /* Ogre::Vector3 ret = Animation::runAnimation(duration); if (mSkelBase) pitchSkeleton(mPtr.getRefData().getPosition().rot[0], mSkelBase->getSkeleton()); + */ - if (!mWeapon.isNull()) - { - for (unsigned int i=0; imControllers.size(); ++i) - mWeapon->mControllers[i].update(); - } - if (!mShield.isNull()) - { - for (unsigned int i=0; imControllers.size(); ++i) - mShield->mControllers[i].update(); - } - - return ret; + return osg::Vec3f(); } } diff --git a/apps/openmw/mwrender/creatureanimation.hpp b/apps/openmw/mwrender/creatureanimation.hpp index 6201c7af4..ccb553d99 100644 --- a/apps/openmw/mwrender/creatureanimation.hpp +++ b/apps/openmw/mwrender/creatureanimation.hpp @@ -15,17 +15,17 @@ namespace MWRender class CreatureAnimation : public Animation { public: - CreatureAnimation(const MWWorld::Ptr& ptr, const std::string &model); + CreatureAnimation(const MWWorld::Ptr &ptr, const std::string& model, Resource::ResourceSystem* resourceSystem); virtual ~CreatureAnimation() {} }; // For creatures with weapons and shields // Animation is already virtual anyway, so might as well make a separate class. // Most creatures don't need weapons/shields, so this will save some memory. - class CreatureWeaponAnimation : public Animation, public WeaponAnimation, public MWWorld::InventoryStoreListener + class CreatureWeaponAnimation : public Animation/*, public WeaponAnimation*/, public MWWorld::InventoryStoreListener { public: - CreatureWeaponAnimation(const MWWorld::Ptr& ptr, const std::string &model); + CreatureWeaponAnimation(const MWWorld::Ptr &ptr, const std::string& model, Resource::ResourceSystem* resourceSystem); virtual ~CreatureWeaponAnimation() {} virtual void equipmentChanged() { updateParts(); } @@ -35,31 +35,31 @@ namespace MWRender void updateParts(); - void updatePart(NifOgre::ObjectScenePtr& scene, int slot); + void updatePart(PartHolderPtr& scene, int slot); virtual void attachArrow(); virtual void releaseArrow(); - virtual Ogre::Vector3 runAnimation(float duration); + virtual osg::Vec3f runAnimation(float duration); /// A relative factor (0-1) that decides if and how much the skeleton should be pitched /// to indicate the facing orientation of the character. - virtual void setPitchFactor(float factor) { mPitchFactor = factor; } + //virtual void setPitchFactor(float factor) { mPitchFactor = factor; } - virtual void setWeaponGroup(const std::string& group) { mWeaponAnimationTime->setGroup(group); } + //virtual void setWeaponGroup(const std::string& group) { mWeaponAnimationTime->setGroup(group); } // WeaponAnimation - virtual NifOgre::ObjectScenePtr getWeapon() { return mWeapon; } - virtual void showWeapon(bool show) { showWeapons(show); } - virtual void configureAddedObject(NifOgre::ObjectScenePtr object, MWWorld::Ptr ptr, int slot); + //virtual NifOgre::ObjectScenePtr getWeapon() { return mWeapon; } + //virtual void showWeapon(bool show) { showWeapons(show); } + //virtual void configureAddedObject(NifOgre::ObjectScenePtr object, MWWorld::Ptr ptr, int slot); private: - NifOgre::ObjectScenePtr mWeapon; - NifOgre::ObjectScenePtr mShield; + PartHolderPtr mWeapon; + PartHolderPtr mShield; bool mShowWeapons; bool mShowCarriedLeft; - Ogre::SharedPtr mWeaponAnimationTime; + //Ogre::SharedPtr mWeaponAnimationTime; }; } diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index c413d9334..eeb5298b8 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -1,15 +1,5 @@ #include "npcanimation.hpp" -#include -#include -#include -#include -#include -#include -#include -#include -#include - #include #include @@ -575,18 +565,6 @@ void NpcAnimation::addFirstPersonOffset(const Ogre::Vector3 &offset) mFirstPersonOffset += offset; } -class SetObjectGroup { - int mGroup; - -public: - SetObjectGroup(int group) : mGroup(group) { } - - void operator()(Ogre::MovableObject *obj) const - { - obj->getUserObjectBindings().setUserAny(Ogre::Any(mGroup)); - } -}; - Animation::PartHolderPtr NpcAnimation::insertBoundedPart(const std::string& model, int group, const std::string& bonename, const std::string& bonefilter, bool enchantedGlow, osg::Vec4f* glowColor) { osg::ref_ptr instance = mResourceSystem->getSceneManager()->createInstance(model); diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 4564e3a97..3d11662aa 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -26,6 +26,7 @@ #include "renderconst.hpp" #include "animation.hpp" #include "npcanimation.hpp" +#include "creatureanimation.hpp" namespace { @@ -194,7 +195,13 @@ void Objects::insertCreature(const MWWorld::Ptr &ptr, const std::string &mesh, b insertBegin(ptr); // CreatureAnimation - std::auto_ptr anim (new ObjectAnimation(ptr, mesh, mResourceSystem)); + std::auto_ptr anim; + + if (weaponsShields) + anim.reset(new CreatureWeaponAnimation(ptr, mesh, mResourceSystem)); + else + anim.reset(new CreatureAnimation(ptr, mesh, mResourceSystem)); + mObjects.insert(std::make_pair(ptr, anim.release())); } From 18162557b00c1c72436e0f4746cfc020a8efd3ba Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 19 Apr 2015 13:31:16 +1000 Subject: [PATCH 0972/3725] TopicInfos result script are now displayed in dialogue subviews. --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/world/columnbase.hpp | 4 +- apps/opencs/model/world/columns.cpp | 2 + apps/opencs/model/world/columns.hpp | 2 + apps/opencs/model/world/data.cpp | 16 ++- apps/opencs/model/world/data.hpp | 3 +- .../model/world/nestedcoladapterimp.cpp | 58 +++++++++ .../model/world/nestedcoladapterimp.hpp | 26 +++++ .../model/world/nestedinfocollection.cpp | 110 ++++++++++++++++++ .../model/world/nestedinfocollection.hpp | 50 ++++++++ apps/opencs/model/world/refidcollection.cpp | 2 +- 11 files changed, 266 insertions(+), 9 deletions(-) create mode 100644 apps/opencs/model/world/nestedinfocollection.cpp create mode 100644 apps/opencs/model/world/nestedinfocollection.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 9a5fc1933..9fb80324e 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -25,7 +25,7 @@ opencs_units (model/world opencs_units_noqt (model/world universalid record commands columnbase scriptcontext cell refidcollection refidadapter refiddata refidadapterimp ref collectionbase refcollection columns infocollection tablemimedata cellcoordinates cellselection resources resourcesmanager scope - pathgrid landtexture land nestedtablewrapper nestedcollection nestedcoladapterimp + pathgrid landtexture land nestedtablewrapper nestedcollection nestedcoladapterimp nestedinfocollection ) opencs_hdrs_noqt (model/world diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index 4c3f9385a..0e954ecca 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -178,8 +178,8 @@ namespace CSMWorld template struct NestedParentColumn : public Column { - NestedParentColumn (int id) : Column (id, - ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue) + NestedParentColumn (int id, int flags = ColumnBase::Flag_Dialogue) : Column (id, + ColumnBase::Display_NestedHeader, flags) {} virtual QVariant get (const Record& record) const diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 1b5aefee9..1ea7da647 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -272,6 +272,8 @@ namespace CSMWorld { ColumnId_PowerList, "Powers" }, { ColumnId_SkillImpact, "Skills" }, + { ColumnId_InfoList, "Info List" }, + { ColumnId_UseValue1, "Use value 1" }, { ColumnId_UseValue2, "Use value 2" }, { ColumnId_UseValue3, "Use value 3" }, diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 1760bff30..5a1577ddb 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -262,6 +262,8 @@ namespace CSMWorld ColumnId_PowerList = 238, ColumnId_SkillImpact = 239, // impact from magic effects + ColumnId_InfoList = 240, + // Allocated to a separate value range, so we don't get a collision should we ever need // to extend the number of use values. ColumnId_UseValue1 = 0x10000, diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 0490cbe7a..873d8b78a 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -193,11 +193,11 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc index = mSpells.getColumns()-1; mSpells.addAdapter (std::make_pair(&mSpells.getColumn(index), new EffectsListAdapter ())); mSpells.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_EffectId)); // false means no edit + new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_EffectId)); mSpells.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_SkillImpact, ColumnBase::Display_SkillImpact)); mSpells.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_Attribute)); // reuse attribute + new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_Attribute)); mSpells.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_EffectRange, ColumnBase::Display_EffectRange)); mSpells.getNestableColumn(index)->addColumn( @@ -235,6 +235,13 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mTopicInfos.addColumn (new PcRankColumn); mTopicInfos.addColumn (new SoundFileColumn); mTopicInfos.addColumn (new ResponseColumn); + // Result script + mTopicInfos.addColumn (new NestedParentColumn (Columns::ColumnId_InfoList, + ColumnBase::Flag_Dialogue | ColumnBase::Flag_Dialogue_List)); + index = mTopicInfos.getColumns()-1; + mTopicInfos.addAdapter (std::make_pair(&mTopicInfos.getColumn(index), new InfoListAdapter ())); + mTopicInfos.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_ScriptText, ColumnBase::Display_ScriptLines)); mJournalInfos.addColumn (new StringIdColumn (true)); mJournalInfos.addColumn (new RecordStateColumn); @@ -271,7 +278,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mEnchantments.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_SkillImpact, ColumnBase::Display_SkillImpact)); mEnchantments.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_Attribute)); // reuse attribute + new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_Attribute)); mEnchantments.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_EffectRange, ColumnBase::Display_EffectRange)); mEnchantments.getNestableColumn(index)->addColumn( @@ -423,7 +430,8 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc addModel (new IdTree (&mSpells, &mSpells), UniversalId::Type_Spell); addModel (new IdTable (&mTopics), UniversalId::Type_Topic); addModel (new IdTable (&mJournals), UniversalId::Type_Journal); - addModel (new IdTable (&mTopicInfos, IdTable::Feature_ReorderWithinTopic), UniversalId::Type_TopicInfo); + addModel (new IdTree (&mTopicInfos, &mTopicInfos, IdTable::Feature_ReorderWithinTopic), + UniversalId::Type_TopicInfo); addModel (new IdTable (&mJournalInfos, IdTable::Feature_ReorderWithinTopic), UniversalId::Type_JournalInfo); addModel (new IdTable (&mCells, IdTable::Feature_ViewId), UniversalId::Type_Cell); addModel (new IdTree (&mEnchantments, &mEnchantments), UniversalId::Type_Enchantment); diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 5ab69ac10..8689b98c0 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -42,6 +42,7 @@ #include "refidcollection.hpp" #include "refcollection.hpp" #include "infocollection.hpp" +#include "nestedinfocollection.hpp" #include "pathgrid.hpp" #ifndef Q_MOC_RUN #include "subcellcollection.hpp" @@ -85,7 +86,7 @@ namespace CSMWorld IdCollection mDebugProfiles; IdCollection mSoundGens; IdCollection mStartScripts; - InfoCollection mTopicInfos; + NestedInfoCollection mTopicInfos; InfoCollection mJournalInfos; IdCollection mCells; IdCollection mLandTextures; diff --git a/apps/opencs/model/world/nestedcoladapterimp.cpp b/apps/opencs/model/world/nestedcoladapterimp.cpp index bfb2fb578..d29155a47 100644 --- a/apps/opencs/model/world/nestedcoladapterimp.cpp +++ b/apps/opencs/model/world/nestedcoladapterimp.cpp @@ -5,6 +5,7 @@ #include "idcollection.hpp" #include "pathgrid.hpp" +#include "info.hpp" namespace CSMWorld { @@ -470,4 +471,61 @@ namespace CSMWorld { return static_cast(record.get().mSoundList.size()); } + + InfoListAdapter::InfoListAdapter () {} + + void InfoListAdapter::addRow(Record& record, int position) const + { + throw std::logic_error ("cannot add a row to a fixed table"); + } + + void InfoListAdapter::removeRow(Record& record, int rowToRemove) const + { + throw std::logic_error ("cannot add a row to a fixed table"); + } + + void InfoListAdapter::setTable(Record& record, + const NestedTableWrapperBase& nestedTable) const + { + throw std::logic_error ("table operation not supported"); + } + + NestedTableWrapperBase* InfoListAdapter::table(const Record& record) const + { + throw std::logic_error ("table operation not supported"); + } + + QVariant InfoListAdapter::getData(const Record& record, + int subRowIndex, int subColIndex) const + { + Info info = record.get(); + + if (subColIndex == 0) + return QString(info.mResultScript.c_str()); + else + throw std::runtime_error("Trying to access non-existing column in the nested table!"); + } + + void InfoListAdapter::setData(Record& record, + const QVariant& value, int subRowIndex, int subColIndex) const + { + Info info = record.get(); + + if (subColIndex == 0) + info.mResultScript = value.toString().toStdString(); + else + throw std::runtime_error("Trying to access non-existing column in the nested table!"); + + record.setModified (info); + } + + int InfoListAdapter::getColumnsCount(const Record& record) const + { + return 1; + } + + int InfoListAdapter::getRowsCount(const Record& record) const + { + return 1; // fixed at size 1 + } } diff --git a/apps/opencs/model/world/nestedcoladapterimp.hpp b/apps/opencs/model/world/nestedcoladapterimp.hpp index 4a7101cba..96dcd943d 100644 --- a/apps/opencs/model/world/nestedcoladapterimp.hpp +++ b/apps/opencs/model/world/nestedcoladapterimp.hpp @@ -21,6 +21,7 @@ namespace ESM namespace CSMWorld { struct Pathgrid; + struct Info; struct PathgridPointsWrap : public NestedTableWrapperBase { @@ -386,6 +387,31 @@ namespace CSMWorld return static_cast(record.get().mEffects.mList.size()); } }; + + class InfoListAdapter : public NestedColumnAdapter + { + public: + InfoListAdapter (); + + virtual void addRow(Record& record, int position) const; + + virtual void removeRow(Record& record, int rowToRemove) const; + + virtual void setTable(Record& record, + const NestedTableWrapperBase& nestedTable) const; + + virtual NestedTableWrapperBase* table(const Record& record) const; + + virtual QVariant getData(const Record& record, + int subRowIndex, int subColIndex) const; + + virtual void setData(Record& record, + const QVariant& value, int subRowIndex, int subColIndex) const; + + virtual int getColumnsCount(const Record& record) const; + + virtual int getRowsCount(const Record& record) const; + }; } #endif // CSM_WOLRD_NESTEDCOLADAPTERIMP_H diff --git a/apps/opencs/model/world/nestedinfocollection.cpp b/apps/opencs/model/world/nestedinfocollection.cpp new file mode 100644 index 000000000..4abaaf9c0 --- /dev/null +++ b/apps/opencs/model/world/nestedinfocollection.cpp @@ -0,0 +1,110 @@ +#include "nestedinfocollection.hpp" + +#include "nestedcoladapterimp.hpp" + +namespace CSMWorld +{ + NestedInfoCollection::NestedInfoCollection () + {} + + NestedInfoCollection::~NestedInfoCollection() + { + for (std::map* >::iterator + iter (mAdapters.begin()); iter!=mAdapters.end(); ++iter) + { + delete (*iter).second; + } + } + + void NestedInfoCollection::addAdapter(std::pair* > adapter) + { + mAdapters.insert(adapter); + } + + const NestedColumnAdapter& NestedInfoCollection::getAdapter(const ColumnBase &column) const + { + std::map* >::const_iterator iter = + mAdapters.find (&column); + + if (iter==mAdapters.end()) + throw std::logic_error("No such column in the nestedidadapter"); + + return *iter->second; + } + + void NestedInfoCollection::addNestedRow(int row, int column, int position) + { + Record record; + record.assign(Collection >::getRecord(row)); + + getAdapter(Collection >::getColumn(column)).addRow(record, position); + + Collection >::setRecord(row, record); + } + + void NestedInfoCollection::removeNestedRows(int row, int column, int subRow) + { + Record record; + record.assign(Collection >::getRecord(row)); + + getAdapter(Collection >::getColumn(column)).removeRow(record, subRow); + + Collection >::setRecord(row, record); + } + + QVariant NestedInfoCollection::getNestedData (int row, + int column, int subRow, int subColumn) const + { + return getAdapter(Collection >::getColumn(column)).getData( + Collection >::getRecord(row), subRow, subColumn); + } + + void NestedInfoCollection::setNestedData(int row, + int column, const QVariant& data, int subRow, int subColumn) + { + Record record; + record.assign(Collection >::getRecord(row)); + + getAdapter(Collection >::getColumn(column)).setData( + record, data, subRow, subColumn); + + Collection >::setRecord(row, record); + } + + CSMWorld::NestedTableWrapperBase* NestedInfoCollection::nestedTable(int row, + int column) const + { + return getAdapter(Collection >::getColumn(column)).table( + Collection >::getRecord(row)); + } + + void NestedInfoCollection::setNestedTable(int row, + int column, const CSMWorld::NestedTableWrapperBase& nestedTable) + { + Record record; + record.assign(Collection >::getRecord(row)); + + getAdapter(Collection >::getColumn(column)).setTable( + record, nestedTable); + + Collection >::setRecord(row, record); + } + + int NestedInfoCollection::getNestedRowsCount(int row, int column) const + { + return getAdapter(Collection >::getColumn(column)).getRowsCount( + Collection >::getRecord(row)); + } + + int NestedInfoCollection::getNestedColumnsCount(int row, int column) const + { + return getAdapter(Collection >::getColumn(column)).getColumnsCount( + Collection >::getRecord(row)); + } + + CSMWorld::NestableColumn *NestedInfoCollection::getNestableColumn(int column) + { + return Collection >::getNestableColumn(column); + } +} diff --git a/apps/opencs/model/world/nestedinfocollection.hpp b/apps/opencs/model/world/nestedinfocollection.hpp new file mode 100644 index 000000000..03c0c2349 --- /dev/null +++ b/apps/opencs/model/world/nestedinfocollection.hpp @@ -0,0 +1,50 @@ +#ifndef CSM_WOLRD_NESTEDINFOCOLLECTION_H +#define CSM_WOLRD_NESTEDINFOCOLLECTION_H + +#include + +#include "infocollection.hpp" +#include "nestedcollection.hpp" + +namespace CSMWorld +{ + struct NestedTableWrapperBase; + + template + class NestedColumnAdapter; + + class NestedInfoCollection : public InfoCollection, public NestedCollection + { + std::map* > mAdapters; + + const NestedColumnAdapter& getAdapter(const ColumnBase &column) const; + + public: + + NestedInfoCollection (); + ~NestedInfoCollection(); + + virtual void addNestedRow(int row, int column, int position); + + virtual void removeNestedRows(int row, int column, int subRow); + + virtual QVariant getNestedData(int row, int column, int subRow, int subColumn) const; + + virtual void setNestedData(int row, int column, const QVariant& data, int subRow, int subColumn); + + virtual NestedTableWrapperBase* nestedTable(int row, int column) const; + + virtual void setNestedTable(int row, int column, const NestedTableWrapperBase& nestedTable); + + virtual int getNestedRowsCount(int row, int column) const; + + virtual int getNestedColumnsCount(int row, int column) const; + + // this method is inherited from NestedCollection, not from Collection > + virtual NestableColumn *getNestableColumn(int column); + + void addAdapter(std::pair* > adapter); + }; +} + +#endif // CSM_WOLRD_NESTEDINFOCOLLECTION_H diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index caf1041c6..4a8f398cd 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -85,7 +85,7 @@ CSMWorld::RefIdCollection::RefIdCollection() mColumns.back().addColumn( new NestedChildColumn (Columns::ColumnId_SkillImpact, ColumnBase::Display_SkillImpact)); mColumns.back().addColumn( - new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_Attribute)); // reuse attribute + new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_Attribute)); mColumns.back().addColumn( new NestedChildColumn (Columns::ColumnId_EffectRange, ColumnBase::Display_EffectRange)); mColumns.back().addColumn( From a836446d223462378767ed39730149ceb3f33624 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 19 Apr 2015 21:07:45 +1000 Subject: [PATCH 0973/3725] Fix assert() triggering due to bad index being passed. --- apps/opencs/view/world/dialoguesubview.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 2e800b56f..f067c3225 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -447,7 +447,7 @@ void CSVWorld::EditWidget::remake(int row) //table->resizeColumnsToContents(); table->setEditTriggers(QAbstractItemView::SelectedClicked | QAbstractItemView::CurrentChanged); - int rows = mNestedModels.back()->rowCount(mTable->index(row, i)); + int rows = mTable->rowCount(mTable->index(row, i)); int rowHeight = (rows == 0) ? table->horizontalHeader()->height() : table->rowHeight(0); int tableMaxHeight = (5 * rowHeight) + table->horizontalHeader()->height() + 2 * table->frameWidth(); From f7d2a2893090a9bfb1b7890ca94d0354156b4627 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 19 Apr 2015 14:25:36 +0200 Subject: [PATCH 0974/3725] Port BoneOffset --- apps/openmw/mwrender/creatureanimation.cpp | 26 ---------------------- apps/openmw/mwrender/npcanimation.cpp | 25 --------------------- components/sceneutil/attach.cpp | 23 ++++++++++++++++++- components/sceneutil/visitor.hpp | 2 +- 4 files changed, 23 insertions(+), 53 deletions(-) diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index 9ccdf390e..241ea56a3 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -133,32 +133,6 @@ void CreatureWeaponAnimation::updatePart(PartHolderPtr& scene, int slot) //else //mAmmunition.setNull(); - // FIXME: code duplicated from NpcAnimation - /* - if(scene->mSkelBase) - { - Ogre::SkeletonInstance *skel = scene->mSkelBase->getSkeleton(); - if(scene->mSkelBase->isParentTagPoint()) - { - Ogre::Node *root = scene->mSkelBase->getParentNode(); - if(skel->hasBone("BoneOffset")) - { - Ogre::Bone *offset = skel->getBone("BoneOffset"); - - root->translate(offset->getPosition()); - - // It appears that the BoneOffset rotation is completely bogus, at least for light models. - //root->rotate(offset->getOrientation()); - root->pitch(Ogre::Degree(-90.0f)); - - root->scale(offset->getScale()); - root->setInitialState(); - } - } - updateSkeletonInstance(mSkelBase->getSkeleton(), skel); - } - */ - /* std::vector >::iterator ctrl(scene->mControllers.begin()); for(;ctrl != scene->mControllers.end();++ctrl) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index eeb5298b8..719fb336b 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -698,31 +698,6 @@ bool NpcAnimation::addOrReplaceIndividualPart(ESM::PartReferenceType type, int g } } /* - if(mObjectParts[type]->mSkelBase) - { - Ogre::SkeletonInstance *skel = mObjectParts[type]->mSkelBase->getSkeleton(); - if(mObjectParts[type]->mSkelBase->isParentTagPoint()) - { - Ogre::Node *root = mObjectParts[type]->mSkelBase->getParentNode(); - if(skel->hasBone("BoneOffset")) - { - Ogre::Bone *offset = skel->getBone("BoneOffset"); - - root->translate(offset->getPosition()); - - // It appears that the BoneOffset rotation is completely bogus, at least for light models. - //root->rotate(offset->getOrientation()); - root->pitch(Ogre::Degree(-90.0f)); - - root->scale(offset->getScale()); - root->setInitialState(); - } - } - - if (isSkinned(mObjectParts[type])) - updateSkeletonInstance(mSkelBase->getSkeleton(), skel); - } - std::vector >::iterator ctrl(mObjectParts[type]->mControllers.begin()); for(;ctrl != mObjectParts[type]->mControllers.end();++ctrl) { diff --git a/components/sceneutil/attach.cpp b/components/sceneutil/attach.cpp index f084704c3..26185eb3e 100644 --- a/components/sceneutil/attach.cpp +++ b/components/sceneutil/attach.cpp @@ -165,9 +165,27 @@ namespace SceneUtil if (!find.mFoundNode) throw std::runtime_error(std::string("Can't find attachment node ") + attachNode); + FindByNameVisitor findBoneOffset("BoneOffset"); + toAttach->accept(findBoneOffset); + + osg::ref_ptr trans; + + if (findBoneOffset.mFoundNode) + { + osg::MatrixTransform* boneOffset = dynamic_cast(findBoneOffset.mFoundNode); + if (!boneOffset) + throw std::runtime_error("BoneOffset must be a MatrixTransform"); + + trans = new osg::PositionAttitudeTransform; + trans->setPosition(boneOffset->getMatrix().getTrans()); + // The BoneOffset rotation seems to be incorrect + trans->setAttitude(osg::Quat(-90, osg::Vec3f(1,0,0))); + } + if (attachNode.find("Left") != std::string::npos) { - osg::ref_ptr trans = new osg::PositionAttitudeTransform; + if (!trans) + trans = new osg::PositionAttitudeTransform; trans->setScale(osg::Vec3f(-1.f, 1.f, 1.f)); // Need to invert culling because of the negative scale @@ -176,7 +194,10 @@ namespace SceneUtil osg::FrontFace* frontFace = new osg::FrontFace; frontFace->setMode(osg::FrontFace::CLOCKWISE); trans->getOrCreateStateSet()->setAttributeAndModes(frontFace, osg::StateAttribute::ON); + } + if (trans) + { find.mFoundNode->addChild(trans); trans->addChild(toAttach); return trans; diff --git a/components/sceneutil/visitor.hpp b/components/sceneutil/visitor.hpp index 59c706f11..d26f95116 100644 --- a/components/sceneutil/visitor.hpp +++ b/components/sceneutil/visitor.hpp @@ -28,7 +28,7 @@ namespace SceneUtil traverse(node); } - const std::string& mNameToFind; + std::string mNameToFind; osg::Group* mFoundNode; }; From c924e6404788bb8a875cd1f1907c4d8bb498078f Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 19 Apr 2015 14:42:09 +0200 Subject: [PATCH 0975/3725] Port HeadAnimationTime --- apps/openmw/mwrender/npcanimation.cpp | 75 +++++++++++++++------------ apps/openmw/mwrender/npcanimation.hpp | 12 ++--- 2 files changed, 47 insertions(+), 40 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 719fb336b..6a6b8a315 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -1,5 +1,7 @@ #include "npcanimation.hpp" +#include + #include #include @@ -8,6 +10,8 @@ #include #include +#include // TextKeyMapHolder + #include "../mwworld/esmstore.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwworld/class.hpp" @@ -67,7 +71,6 @@ std::string getVampireHead(const std::string& race, bool female) namespace MWRender { -/* HeadAnimationTime::HeadAnimationTime(MWWorld::Ptr reference) : mReference(reference), mTalkStart(0), mTalkStop(0), mBlinkStart(0), mBlinkStop(0), mValue(0), mEnabled(true) { @@ -107,13 +110,14 @@ void HeadAnimationTime::update(float dt) } else { + // FIXME: would be nice to hold on to the SoundPtr so we don't have to retrieve it every frame mValue = mTalkStart + (mTalkStop - mTalkStart) * std::min(1.f, MWBase::Environment::get().getSoundManager()->getSaySoundLoudness(mReference)*2); // Rescale a bit (most voices are not very loud) } } -float HeadAnimationTime::getValue() const +float HeadAnimationTime::getValue(osg::NodeVisitor*) { return mValue; } @@ -137,7 +141,6 @@ void HeadAnimationTime::setBlinkStop(float value) { mBlinkStop = value; } -*/ static NpcAnimation::PartBoneMap createPartListMap() { @@ -196,7 +199,7 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, osg::ref_ptr par { mNpc = mPtr.get()->mBase; - //mHeadAnimationTime = Ogre::SharedPtr(new HeadAnimationTime(mPtr)); + mHeadAnimationTime = boost::shared_ptr(new HeadAnimationTime(mPtr)); //mWeaponAnimationTime = Ogre::SharedPtr(new WeaponAnimationTime(this)); for(size_t i = 0;i < ESM::PRT_Count;i++) @@ -577,13 +580,13 @@ Animation::PartHolderPtr NpcAnimation::insertBoundedPart(const std::string& mode return PartHolderPtr(new PartHolder(attached)); } -/* -Ogre::Vector3 NpcAnimation::runAnimation(float timepassed) +osg::Vec3f NpcAnimation::runAnimation(float timepassed) { - Ogre::Vector3 ret = Animation::runAnimation(timepassed); + osg::Vec3f ret = Animation::runAnimation(timepassed); mHeadAnimationTime->update(timepassed); + /* if (mSkelBase) { Ogre::SkeletonInstance *baseinst = mSkelBase->getSkeleton(); @@ -625,10 +628,10 @@ Ogre::Vector3 NpcAnimation::runAnimation(float timepassed) mObjectParts[i]->mSkelBase->getAllAnimationStates()->_notifyDirty(); } + */ return ret; } -*/ void NpcAnimation::removeIndividualPart(ESM::PartReferenceType type) { @@ -697,35 +700,44 @@ bool NpcAnimation::addOrReplaceIndividualPart(ESM::PartReferenceType type, int g } } } - /* - std::vector >::iterator ctrl(mObjectParts[type]->mControllers.begin()); - for(;ctrl != mObjectParts[type]->mControllers.end();++ctrl) + + boost::shared_ptr src; + if (type == ESM::PRT_Head) { - if(ctrl->getSource().isNull()) - { - ctrl->setSource(mNullAnimationTimePtr); + src = mHeadAnimationTime; - if (type == ESM::PRT_Head) + osg::Node* node = mObjectParts[type]->getNode(); + if (node->getUserDataContainer()) + { + for (unsigned int i=0; igetUserDataContainer()->getNumUserObjects(); ++i) { - ctrl->setSource(mHeadAnimationTime); - const NifOgre::TextKeyMap& keys = mObjectParts[type]->mTextKeys; - for (NifOgre::TextKeyMap::const_iterator it = keys.begin(); it != keys.end(); ++it) + osg::Object* obj = node->getUserDataContainer()->getUserObject(i); + if (NifOsg::TextKeyMapHolder* keys = dynamic_cast(obj)) { - if (Misc::StringUtils::ciEqual(it->second, "talk: start")) - mHeadAnimationTime->setTalkStart(it->first); - if (Misc::StringUtils::ciEqual(it->second, "talk: stop")) - mHeadAnimationTime->setTalkStop(it->first); - if (Misc::StringUtils::ciEqual(it->second, "blink: start")) - mHeadAnimationTime->setBlinkStart(it->first); - if (Misc::StringUtils::ciEqual(it->second, "blink: stop")) - mHeadAnimationTime->setBlinkStop(it->first); + for (NifOsg::TextKeyMap::const_iterator it = keys->mTextKeys.begin(); it != keys->mTextKeys.end(); ++it) + { + if (Misc::StringUtils::ciEqual(it->second, "talk: start")) + mHeadAnimationTime->setTalkStart(it->first); + if (Misc::StringUtils::ciEqual(it->second, "talk: stop")) + mHeadAnimationTime->setTalkStop(it->first); + if (Misc::StringUtils::ciEqual(it->second, "blink: start")) + mHeadAnimationTime->setBlinkStart(it->first); + if (Misc::StringUtils::ciEqual(it->second, "blink: stop")) + mHeadAnimationTime->setBlinkStop(it->first); + } + + break; } } - else if (type == ESM::PRT_Weapon) - ctrl->setSource(mWeaponAnimationTime); } } - */ + //else if (type == ESM::PRT_Weapon) + // src = mWeaponAnimationTime; + else + src.reset(new NullAnimationTime); + + SceneUtil::AssignControllerSourcesVisitor assignVisitor(src); + mObjectParts[type]->getNode()->accept(assignVisitor); return true; } @@ -825,6 +837,7 @@ void NpcAnimation::showCarriedLeft(bool show) if (addOrReplaceIndividualPart(ESM::PRT_Shield, MWWorld::InventoryStore::Slot_CarriedLeft, 1, mesh, !iter->getClass().getEnchantment(*iter).empty(), &glowColor)) { + // TODO //if (iter->getTypeName() == typeid(ESM::Light).name()) //addExtraLight(mInsert->getCreator(), mObjectParts[ESM::PRT_Shield], iter->get()->mBase); } @@ -863,13 +876,11 @@ void NpcAnimation::permanentEffectAdded(const ESM::MagicEffect *magicEffect, boo if (!magicEffect->mHit.empty()) { - /* const ESM::Static* castStatic = MWBase::Environment::get().getWorld()->getStore().get().find (magicEffect->mHit); bool loop = (magicEffect->mData.mFlags & ESM::MagicEffect::ContinuousVfx) != 0; // Don't play particle VFX unless the effect is new or it should be looping. if (isNew || loop) addEffect("meshes\\" + castStatic->mModel, magicEffect->mIndex, loop, ""); - */ } } @@ -884,7 +895,7 @@ void NpcAnimation::setAlpha(float alpha) void NpcAnimation::enableHeadAnimation(bool enable) { - //mHeadAnimationTime->setEnabled(enable); + mHeadAnimationTime->setEnabled(enable); } void NpcAnimation::setWeaponGroup(const std::string &group) diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 16bd45cc4..309bc5ef5 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -15,8 +15,7 @@ namespace ESM namespace MWRender { -/* -class HeadAnimationTime : public Ogre::ControllerValue +class HeadAnimationTime : public SceneUtil::ControllerSource { private: MWWorld::Ptr mReference; @@ -44,11 +43,8 @@ public: void setBlinkStart(float value); void setBlinkStop(float value); - virtual Ogre::Real getValue() const; - virtual void setValue(Ogre::Real value) - { } + virtual float getValue(osg::NodeVisitor* nv); }; -*/ class NpcAnimation : public Animation, public WeaponAnimation, public MWWorld::InventoryStoreListener { @@ -96,7 +92,7 @@ private: Ogre::Vector3 mFirstPersonOffset; - //Ogre::SharedPtr mHeadAnimationTime; + boost::shared_ptr mHeadAnimationTime; //Ogre::SharedPtr mWeaponAnimationTime; float mAlpha; @@ -142,7 +138,7 @@ public: virtual void setWeaponGroup(const std::string& group); - //virtual Ogre::Vector3 runAnimation(float timepassed); + virtual osg::Vec3f runAnimation(float timepassed); /// A relative factor (0-1) that decides if and how much the skeleton should be pitched /// to indicate the facing orientation of the character. From fcc7aa02abba9858d33e2757681e2dedaf169524 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 19 Apr 2015 15:03:08 +0200 Subject: [PATCH 0976/3725] Port addExtraLight --- apps/openmw/mwrender/animation.cpp | 50 ++++++++++++++++++++- apps/openmw/mwrender/animation.hpp | 6 +-- apps/openmw/mwrender/npcanimation.cpp | 7 ++- apps/openmw/mwrender/objects.cpp | 62 ++++++--------------------- 4 files changed, 67 insertions(+), 58 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 2febf9c9a..e4c05bc1e 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include @@ -14,6 +15,8 @@ #include #include +#include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -178,6 +181,48 @@ namespace MWRender return result; } + void Animation::addExtraLight(osg::ref_ptr parent, const ESM::Light *esmLight) + { + SceneUtil::FindByNameVisitor visitor("AttachLight"); + parent->accept(visitor); + + osg::Group* attachTo = NULL; + if (visitor.mFoundNode) + { + attachTo = visitor.mFoundNode; + } + else + { + osg::ComputeBoundsVisitor computeBound; + parent->accept(computeBound); + + // PositionAttitudeTransform seems to be slightly faster than MatrixTransform + osg::ref_ptr trans(new osg::PositionAttitudeTransform); + trans->setPosition(computeBound.getBoundingBox().center()); + + parent->addChild(trans); + + attachTo = trans; + } + + osg::ref_ptr lightSource = new SceneUtil::LightSource; + osg::Light* light = new osg::Light; + lightSource->setLight(light); + + float realRadius = esmLight->mData.mRadius; + + lightSource->setRadius(realRadius); + light->setLinearAttenuation(10.f/(esmLight->mData.mRadius*2.f)); + //light->setLinearAttenuation(0.05); + light->setConstantAttenuation(0.f); + + light->setDiffuse(SceneUtil::colourFromRGB(esmLight->mData.mColor)); + light->setAmbient(osg::Vec4f(0,0,0,1)); + light->setSpecular(osg::Vec4f(0,0,0,0)); + + attachTo->addChild(lightSource); + } + void Animation::addEffect (const std::string& model, int effectId, bool loop, const std::string& bonename, std::string texture) { // Early out if we already have this effect @@ -307,7 +352,7 @@ namespace MWRender // -------------------------------------------------------------------------------- - ObjectAnimation::ObjectAnimation(const MWWorld::Ptr &ptr, const std::string &model, Resource::ResourceSystem* resourceSystem) + ObjectAnimation::ObjectAnimation(const MWWorld::Ptr &ptr, const std::string &model, Resource::ResourceSystem* resourceSystem, bool allowLight) : Animation(ptr, osg::ref_ptr(ptr.getRefData().getBaseNode()), resourceSystem) { if (!model.empty()) @@ -316,6 +361,9 @@ namespace MWRender if (!ptr.getClass().getEnchantment(ptr).empty()) addGlow(mObjectRoot, getEnchantmentColor(ptr)); + + if (ptr.getTypeName() == typeid(ESM::Light).name() && allowLight) + addExtraLight(getOrCreateObjectRoot(), ptr.get()->mBase); } } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index ccc4bfa23..797c215c5 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -206,8 +206,8 @@ protected: * extension will be replaced with .kf. */ //void addAnimSource(const std::string &model); - /** Adds an additional light to the given object list using the specified ESM record. */ - //void addExtraLight(Ogre::SceneManager *sceneMgr, NifOgre::ObjectScenePtr objlist, const ESM::Light *light); + /** Adds an additional light to the given node using the specified ESM record. */ + void addExtraLight(osg::ref_ptr parent, const ESM::Light *light); //void clearAnimSources(); @@ -319,7 +319,7 @@ public: class ObjectAnimation : public Animation { public: - ObjectAnimation(const MWWorld::Ptr& ptr, const std::string &model, Resource::ResourceSystem* resourceSystem); + ObjectAnimation(const MWWorld::Ptr& ptr, const std::string &model, Resource::ResourceSystem* resourceSystem, bool allowLight); }; } diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 6a6b8a315..56f12da13 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -431,7 +431,7 @@ void NpcAnimation::updateParts() const ESM::Light *light = part.get()->mBase; addOrReplaceIndividualPart(ESM::PRT_Shield, MWWorld::InventoryStore::Slot_CarriedLeft, 1, "meshes\\"+light->mModel); - //addExtraLight(mInsert->getCreator(), mObjectParts[ESM::PRT_Shield], light); + addExtraLight(mObjectParts[ESM::PRT_Shield]->getNode()->asGroup(), light); } } @@ -837,9 +837,8 @@ void NpcAnimation::showCarriedLeft(bool show) if (addOrReplaceIndividualPart(ESM::PRT_Shield, MWWorld::InventoryStore::Slot_CarriedLeft, 1, mesh, !iter->getClass().getEnchantment(*iter).empty(), &glowColor)) { - // TODO - //if (iter->getTypeName() == typeid(ESM::Light).name()) - //addExtraLight(mInsert->getCreator(), mObjectParts[ESM::PRT_Shield], iter->get()->mBase); + if (iter->getTypeName() == typeid(ESM::Light).name()) + addExtraLight(mObjectParts[ESM::PRT_Shield]->getNode()->asGroup(), iter->get()->mBase); } } else diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 3d11662aa..1d28291de 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -6,7 +6,6 @@ #include #include #include -#include #include #include @@ -17,7 +16,6 @@ #include #include -#include #include "../mwworld/ptr.hpp" #include "../mwworld/class.hpp" @@ -120,9 +118,10 @@ void Objects::insertBegin(const MWWorld::Ptr& ptr) osg::Quat zr(-f[2], osg::Vec3(0,0,1)); // Rotates first around z, then y, then x - insert->setAttitude(zr*yr*xr); - - // TODO: actors rotate around z only + if (ptr.getClass().isActor()) + insert->setAttitude(zr); + else + insert->setAttitude(zr*yr*xr); ptr.getRefData().setBaseNode(insert); } @@ -131,55 +130,11 @@ void Objects::insertModel(const MWWorld::Ptr &ptr, const std::string &mesh, bool { insertBegin(ptr); - std::auto_ptr anim (new ObjectAnimation(ptr, mesh, mResourceSystem)); + std::auto_ptr anim (new ObjectAnimation(ptr, mesh, mResourceSystem, allowLight)); if (anim->getObjectRoot()) anim->getObjectRoot()->addCullCallback(new SceneUtil::LightListCallback); - if (ptr.getTypeName() == typeid(ESM::Light).name() && allowLight) - { - SceneUtil::FindByNameVisitor visitor("AttachLight"); - ptr.getRefData().getBaseNode()->accept(visitor); - - osg::Group* attachTo = NULL; - if (visitor.mFoundNode) - { - attachTo = visitor.mFoundNode; - } - else - { - osg::ComputeBoundsVisitor computeBound; - osg::Group* objectRoot = anim->getOrCreateObjectRoot(); - objectRoot->accept(computeBound); - - // PositionAttitudeTransform seems to be slightly faster than MatrixTransform - osg::ref_ptr trans(new osg::PositionAttitudeTransform); - trans->setPosition(computeBound.getBoundingBox().center()); - - objectRoot->addChild(trans); - - attachTo = trans; - } - - const ESM::Light* esmLight = ptr.get()->mBase; - - osg::ref_ptr lightSource = new SceneUtil::LightSource; - osg::Light* light = new osg::Light; - lightSource->setLight(light); - - float realRadius = esmLight->mData.mRadius; - - lightSource->setRadius(realRadius); - light->setLinearAttenuation(10.f/(esmLight->mData.mRadius*2.f)); - //light->setLinearAttenuation(0.05); - light->setConstantAttenuation(0.f); - - light->setDiffuse(SceneUtil::colourFromRGB(esmLight->mData.mColor)); - light->setAmbient(osg::Vec4f(0,0,0,1)); - light->setSpecular(osg::Vec4f(0,0,0,0)); - - attachTo->addChild(lightSource); - } if (!allowLight) { RemoveParticlesVisitor visitor; @@ -202,6 +157,9 @@ void Objects::insertCreature(const MWWorld::Ptr &ptr, const std::string &mesh, b else anim.reset(new CreatureAnimation(ptr, mesh, mResourceSystem)); + if (anim->getObjectRoot()) + anim->getObjectRoot()->addCullCallback(new SceneUtil::LightListCallback); + mObjects.insert(std::make_pair(ptr, anim.release())); } @@ -210,6 +168,10 @@ void Objects::insertNPC(const MWWorld::Ptr &ptr) insertBegin(ptr); std::auto_ptr anim (new NpcAnimation(ptr, osg::ref_ptr(ptr.getRefData().getBaseNode()), mResourceSystem, 0)); + + if (anim->getObjectRoot()) + anim->getObjectRoot()->addCullCallback(new SceneUtil::LightListCallback); + mObjects.insert(std::make_pair(ptr, anim.release())); } From 68f93294da2b286448b2658ea8a067bdcee6a085 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 19 Apr 2015 17:55:56 +0200 Subject: [PATCH 0977/3725] Port EffectManager --- apps/openmw/CMakeLists.txt | 4 +- apps/openmw/mwbase/world.hpp | 9 +- apps/openmw/mwclass/creature.cpp | 2 +- apps/openmw/mwclass/npc.cpp | 2 +- apps/openmw/mwmechanics/combat.cpp | 2 +- apps/openmw/mwmechanics/summoning.cpp | 4 +- apps/openmw/mwrender/animation.cpp | 52 ++-------- apps/openmw/mwrender/animation.hpp | 28 +++--- apps/openmw/mwrender/effectmanager.cpp | 113 +++++++++------------- apps/openmw/mwrender/effectmanager.hpp | 55 +++++++---- apps/openmw/mwrender/objects.cpp | 1 - apps/openmw/mwrender/renderingmanager.cpp | 21 ++++ apps/openmw/mwrender/renderingmanager.hpp | 10 ++ apps/openmw/mwrender/util.cpp | 31 ++++++ apps/openmw/mwrender/util.hpp | 24 +++++ apps/openmw/mwworld/refdata.hpp | 2 + apps/openmw/mwworld/worldimp.cpp | 19 ++-- apps/openmw/mwworld/worldimp.hpp | 4 +- components/esm/defs.hpp | 7 ++ components/sceneutil/controller.cpp | 17 ++++ components/sceneutil/controller.hpp | 14 +++ 21 files changed, 255 insertions(+), 166 deletions(-) create mode 100644 apps/openmw/mwrender/util.cpp create mode 100644 apps/openmw/mwrender/util.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 32ed17c5b..09f2e08fa 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -21,11 +21,11 @@ source_group(game FILES ${GAME} ${GAME_HEADER}) add_openmw_dir (mwrender actors objects renderingmanager animation sky npcanimation vismask - creatureanimation + creatureanimation effectmanager util # debugging camera activatoranimation # renderinginterface localmap occlusionquery water shadows # characterpreview globalmap ripplesimulation refraction -# terrainstorage renderconst effectmanager weaponanimation +# terrainstorage renderconst weaponanimation ) #add_openmw_dir (mwinput diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 9e6c6d9bf..0c1874ce6 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -17,6 +17,11 @@ namespace Ogre class Image; } +namespace osg +{ + class Vec3f; +} + namespace Loading { class Listener; @@ -546,9 +551,9 @@ namespace MWBase virtual void spawnRandomCreature(const std::string& creatureList) = 0; /// Spawn a blood effect for \a ptr at \a worldPosition - virtual void spawnBloodEffect (const MWWorld::Ptr& ptr, const Ogre::Vector3& worldPosition) = 0; + virtual void spawnBloodEffect (const MWWorld::Ptr& ptr, const osg::Vec3f& worldPosition) = 0; - virtual void spawnEffect (const std::string& model, const std::string& textureOverride, const Ogre::Vector3& worldPos) = 0; + virtual void spawnEffect (const std::string& model, const std::string& textureOverride, const osg::Vec3f& worldPos) = 0; virtual void explodeSpell (const Ogre::Vector3& origin, const ESM::EffectList& effects, const MWWorld::Ptr& caster, ESM::RangeType rangeType, const std::string& id, const std::string& sourceName) = 0; diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index c1b8177f7..a2451e1a1 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -319,7 +319,7 @@ namespace MWClass damage = 0; if (damage > 0) - MWBase::Environment::get().getWorld()->spawnBloodEffect(victim, hitPosition); + MWBase::Environment::get().getWorld()->spawnBloodEffect(victim, osg::Vec3f(hitPosition.x, hitPosition.y, hitPosition.z)); MWMechanics::diseaseContact(victim, ptr); diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 506852a90..b5ac8f6c6 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -583,7 +583,7 @@ namespace MWClass damage = 0; if (healthdmg && damage > 0) - MWBase::Environment::get().getWorld()->spawnBloodEffect(victim, hitPosition); + MWBase::Environment::get().getWorld()->spawnBloodEffect(victim, osg::Vec3f(hitPosition.x, hitPosition.y, hitPosition.z)); MWMechanics::diseaseContact(victim, ptr); diff --git a/apps/openmw/mwmechanics/combat.cpp b/apps/openmw/mwmechanics/combat.cpp index 64456dd11..b80ac8cf9 100644 --- a/apps/openmw/mwmechanics/combat.cpp +++ b/apps/openmw/mwmechanics/combat.cpp @@ -218,7 +218,7 @@ namespace MWMechanics appliedEnchantment = applyEnchantment(attacker, victim, projectile, hitPosition); if (damage > 0) - MWBase::Environment::get().getWorld()->spawnBloodEffect(victim, hitPosition); + MWBase::Environment::get().getWorld()->spawnBloodEffect(victim, osg::Vec3f(hitPosition.x, hitPosition.y, hitPosition.z)); // Non-enchanted arrows shot at enemies have a chance to turn up in their inventory if (victim != MWBase::Environment::get().getWorld()->getPlayerPtr() diff --git a/apps/openmw/mwmechanics/summoning.cpp b/apps/openmw/mwmechanics/summoning.cpp index daf4424c5..221c67267 100644 --- a/apps/openmw/mwmechanics/summoning.cpp +++ b/apps/openmw/mwmechanics/summoning.cpp @@ -34,7 +34,7 @@ namespace MWMechanics .search("VFX_Summon_End"); if (fx) MWBase::Environment::get().getWorld()->spawnEffect("meshes\\" + fx->mModel, - "", Ogre::Vector3(ptr.getRefData().getPosition().pos)); + "", ptr.getRefData().getPosition().asVec3()); } else { @@ -190,7 +190,7 @@ namespace MWMechanics .search("VFX_Summon_End"); if (fx) MWBase::Environment::get().getWorld()->spawnEffect("meshes\\" + fx->mModel, - "", Ogre::Vector3(ptr.getRefData().getPosition().pos)); + "", ptr.getRefData().getPosition().asVec3()); MWBase::Environment::get().getWorld()->deleteObject(ptr); } diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index e4c05bc1e..d54e87dc5 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -24,6 +24,7 @@ #include "../mwworld/class.hpp" #include "vismask.hpp" +#include "util.hpp" namespace { @@ -70,30 +71,6 @@ namespace std::vector > mTextures; }; - class FindMaxControllerLengthVisitor : public SceneUtil::ControllerVisitor - { - public: - FindMaxControllerLengthVisitor() - : SceneUtil::ControllerVisitor() - , mMaxLength(0) - { - } - - virtual void visit(osg::Node& , SceneUtil::Controller& ctrl) - { - if (ctrl.mFunction) - mMaxLength = std::max(mMaxLength, ctrl.mFunction->getMaximum()); - } - - float getMaxLength() const - { - return mMaxLength; - } - - private: - float mMaxLength; - }; - } namespace MWRender @@ -246,7 +223,7 @@ namespace MWRender osg::ref_ptr node = mResourceSystem->getSceneManager()->createInstance(model, parentNode); params.mObjects = PartHolderPtr(new PartHolder(node)); - FindMaxControllerLengthVisitor findMaxLengthVisitor; + SceneUtil::FindMaxControllerLengthVisitor findMaxLengthVisitor; node->accept(findMaxLengthVisitor); params.mMaxControllerLength = findMaxLengthVisitor.getMaxLength(); @@ -262,22 +239,7 @@ namespace MWRender SceneUtil::AssignControllerSourcesVisitor assignVisitor(boost::shared_ptr(params.mAnimTime)); node->accept(assignVisitor); - if (!texture.empty()) - { - std::string correctedTexture = Misc::ResourceHelpers::correctTexturePath(texture, mResourceSystem->getVFS()); - // Not sure if wrap settings should be pulled from the overridden texture? - osg::ref_ptr tex = mResourceSystem->getTextureManager()->getTexture2D(correctedTexture, osg::Texture2D::CLAMP, - osg::Texture2D::CLAMP); - osg::ref_ptr stateset; - if (node->getStateSet()) - stateset = static_cast(node->getStateSet()->clone(osg::CopyOp::SHALLOW_COPY)); - else - stateset = new osg::StateSet; - - stateset->setTextureAttribute(0, tex, osg::StateAttribute::OVERRIDE); - - node->setStateSet(stateset); - } + overrideTexture(texture, mResourceSystem, node); // TODO: in vanilla morrowind the effect is scaled based on the host object's bounding box. @@ -330,22 +292,22 @@ namespace MWRender } } - float Animation::EffectAnimationTime::getValue(osg::NodeVisitor*) + float EffectAnimationTime::getValue(osg::NodeVisitor*) { return mTime; } - void Animation::EffectAnimationTime::addTime(float duration) + void EffectAnimationTime::addTime(float duration) { mTime += duration; } - void Animation::EffectAnimationTime::resetTime(float time) + void EffectAnimationTime::resetTime(float time) { mTime = time; } - float Animation::EffectAnimationTime::getTime() const + float EffectAnimationTime::getTime() const { return mTime; } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 797c215c5..aef4d4b80 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -22,6 +22,20 @@ namespace MWRender { class Camera; +class EffectAnimationTime : public SceneUtil::ControllerSource +{ +private: + float mTime; +public: + virtual float getValue(osg::NodeVisitor* nv); + + void addTime(float duration); + void resetTime(float time); + float getTime() const; + + EffectAnimationTime() : mTime(0) { } +}; + class Animation { public: @@ -61,20 +75,6 @@ protected: virtual void setValue(Ogre::Real value); }; - class EffectAnimationTime : public SceneUtil::ControllerSource - { - private: - float mTime; - public: - virtual float getValue(osg::NodeVisitor* nv); - - void addTime(float duration); - void resetTime(float time); - float getTime() const; - - EffectAnimationTime() : mTime(0) { } - }; - class NullAnimationTime : public SceneUtil::ControllerSource { public: diff --git a/apps/openmw/mwrender/effectmanager.cpp b/apps/openmw/mwrender/effectmanager.cpp index 503a0223e..642909cda 100644 --- a/apps/openmw/mwrender/effectmanager.cpp +++ b/apps/openmw/mwrender/effectmanager.cpp @@ -1,102 +1,83 @@ #include "effectmanager.hpp" +#include + #include -#include -#include -#include -#include +#include +#include + +#include #include "animation.hpp" -#include "renderconst.hpp" +#include "vismask.hpp" +#include "util.hpp" namespace MWRender { -EffectManager::EffectManager(Ogre::SceneManager *sceneMgr) - : mSceneMgr(sceneMgr) +EffectManager::EffectManager(osg::ref_ptr parent, Resource::ResourceSystem* resourceSystem) + : mParentNode(parent) + , mResourceSystem(resourceSystem) { } -void EffectManager::addEffect(const std::string &model, std::string textureOverride, const Ogre::Vector3 &worldPosition, float scale) +EffectManager::~EffectManager() { - Ogre::SceneNode* sceneNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(worldPosition); - sceneNode->setScale(scale,scale,scale); + clear(); +} - NifOgre::ObjectScenePtr scene = NifOgre::Loader::createObjects(sceneNode, model); +void EffectManager::addEffect(const std::string &model, const std::string& textureOverride, const osg::Vec3f &worldPosition, float scale) +{ + osg::ref_ptr node = mResourceSystem->getSceneManager()->createInstance(model); - MWRender::Animation::setRenderProperties(scene, RV_Effects, - RQG_Main, RQG_Alpha, 0.f, false, NULL); + node->setNodeMask(Mask_Effect); - for(size_t i = 0;i < scene->mControllers.size();i++) - { - if(scene->mControllers[i].getSource().isNull()) - scene->mControllers[i].setSource(Ogre::SharedPtr (new EffectAnimationTime())); - } + Effect effect; + effect.mAnimTime.reset(new EffectAnimationTime); - if (!textureOverride.empty()) - { - std::string correctedTexture = Misc::ResourceHelpers::correctTexturePath(textureOverride); - for(size_t i = 0;i < scene->mParticles.size(); ++i) - { - Ogre::ParticleSystem* partSys = scene->mParticles[i]; - - Ogre::MaterialPtr mat = scene->mMaterialControllerMgr.getWritableMaterial(partSys); - - for (int t=0; tgetNumTechniques(); ++t) - { - Ogre::Technique* tech = mat->getTechnique(t); - for (int p=0; pgetNumPasses(); ++p) - { - Ogre::Pass* pass = tech->getPass(p); - for (int tex=0; texgetNumTextureUnitStates(); ++tex) - { - Ogre::TextureUnitState* tus = pass->getTextureUnitState(tex); - tus->setTextureName(correctedTexture); - } - } - } - } - } + SceneUtil::FindMaxControllerLengthVisitor findMaxLengthVisitor; + node->accept(findMaxLengthVisitor); + effect.mMaxControllerLength = findMaxLengthVisitor.getMaxLength(); + + osg::ref_ptr trans = new osg::PositionAttitudeTransform; + trans->setPosition(worldPosition); + trans->setScale(osg::Vec3f(scale, scale, scale)); + trans->addChild(node); + + SceneUtil::AssignControllerSourcesVisitor assignVisitor(effect.mAnimTime); + node->accept(assignVisitor); + + overrideTexture(textureOverride, mResourceSystem, node); - mEffects.push_back(std::make_pair(sceneNode, scene)); + mParentNode->addChild(trans); + + mEffects[trans] = effect; } -void EffectManager::update(float dt, Ogre::Camera* camera) +void EffectManager::update(float dt) { - for (std::vector >::iterator it = mEffects.begin(); it != mEffects.end(); ) + for (EffectMap::iterator it = mEffects.begin(); it != mEffects.end(); ) { - NifOgre::ObjectScenePtr objects = it->second; - for(size_t i = 0; i < objects->mControllers.size() ;i++) - { - EffectAnimationTime* value = dynamic_cast(objects->mControllers[i].getSource().get()); - if (value) - value->addTime(dt); - - objects->mControllers[i].update(); - } - objects->rotateBillboardNodes(camera); + it->second.mAnimTime->addTime(dt); - // Finished playing? - if (objects->mControllers[0].getSource()->getValue() >= objects->mMaxControllerLength) + if (it->second.mAnimTime->getTime() >= it->second.mMaxControllerLength) { - Ogre::SceneNode* node = it->first; - it = mEffects.erase(it); - mSceneMgr->destroySceneNode(node); - continue; + mParentNode->removeChild(it->first); + mEffects.erase(it++); } - ++it; + else + ++it; } } void EffectManager::clear() { - for (std::vector >::iterator it = mEffects.begin(); it != mEffects.end(); ) + for (EffectMap::iterator it = mEffects.begin(); it != mEffects.end(); ++it) { - Ogre::SceneNode* node = it->first; - it = mEffects.erase(it); - mSceneMgr->destroySceneNode(node); + mParentNode->removeChild(it->first); } + mEffects.clear(); } } diff --git a/apps/openmw/mwrender/effectmanager.hpp b/apps/openmw/mwrender/effectmanager.hpp index eb6863655..6d7aaaf4f 100644 --- a/apps/openmw/mwrender/effectmanager.hpp +++ b/apps/openmw/mwrender/effectmanager.hpp @@ -1,43 +1,60 @@ #ifndef OPENMW_MWRENDER_EFFECTMANAGER_H #define OPENMW_MWRENDER_EFFECTMANAGER_H -#include +#include +#include -namespace MWRender -{ +#include - class EffectAnimationTime : public Ogre::ControllerValue - { - private: - float mTime; - public: - EffectAnimationTime() : mTime(0) { } - void addTime(float time) { mTime += time; } +#include - virtual Ogre::Real getValue() const { return mTime; } - virtual void setValue(Ogre::Real value) {} - }; +namespace osg +{ + class Group; + class Vec3f; + class PositionAttitudeTransform; +} +namespace Resource +{ + class ResourceSystem; +} + +namespace MWRender +{ + class EffectAnimationTime; // Note: effects attached to another object should be managed by MWRender::Animation::addEffect. // This class manages "free" effects, i.e. attached to a dedicated scene node in the world. class EffectManager { public: - EffectManager(Ogre::SceneManager* sceneMgr); - ~EffectManager() { clear(); } + EffectManager(osg::ref_ptr parent, Resource::ResourceSystem* resourceSystem); + ~EffectManager(); /// Add an effect. When it's finished playing, it will be removed automatically. - void addEffect (const std::string& model, std::string textureOverride, const Ogre::Vector3& worldPosition, float scale); + void addEffect (const std::string& model, const std::string& textureOverride, const osg::Vec3f& worldPosition, float scale); - void update(float dt, Ogre::Camera* camera); + void update(float dt); /// Remove all effects void clear(); private: - std::vector > mEffects; - Ogre::SceneManager* mSceneMgr; + struct Effect + { + float mMaxControllerLength; + boost::shared_ptr mAnimTime; + }; + + typedef std::map, Effect> EffectMap; + EffectMap mEffects; + + osg::ref_ptr mParentNode; + Resource::ResourceSystem* mResourceSystem; + + EffectManager(const EffectManager&); + void operator=(const EffectManager&); }; } diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 1d28291de..4b1fa6d5b 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -19,7 +19,6 @@ #include "../mwworld/ptr.hpp" #include "../mwworld/class.hpp" -#include "../mwworld/cellstore.hpp" #include "renderconst.hpp" #include "animation.hpp" diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 26b86d1b2..becd563b9 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -18,6 +18,7 @@ #include #include "sky.hpp" +#include "effectmanager.hpp" namespace MWRender { @@ -60,6 +61,8 @@ namespace MWRender mSky.reset(new SkyManager(mRootNode, resourceSystem->getSceneManager())); + mEffectManager.reset(new EffectManager(mRootNode, mResourceSystem)); + mViewer.setLightingMode(osgViewer::View::NO_LIGHT); osg::ref_ptr source = new osg::LightSource; @@ -163,6 +166,24 @@ namespace MWRender void RenderingManager::update(float dt, bool paused) { mObjects->update(dt); + mEffectManager->update(dt); + } + + void RenderingManager::spawnEffect(const std::string &model, const std::string &texture, const osg::Vec3f &worldPosition, float scale) + { + mEffectManager->addEffect(model, texture, worldPosition, scale); + } + + void RenderingManager::notifyWorldSpaceChanged() + { + mEffectManager->clear(); + //mWater->clearRipples(); + } + + void RenderingManager::clear() + { + //mLocalMap->clear(); + notifyWorldSpaceChanged(); } } diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index b7aec3786..61f611a8c 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -33,6 +33,7 @@ namespace MWRender class StateUpdater; + class EffectManager; class SkyManager; class RenderingManager : public MWRender::RenderingInterface @@ -63,6 +64,14 @@ namespace MWRender osg::Vec3f getEyePos(); + void spawnEffect(const std::string &model, const std::string &texture, const osg::Vec3f &worldPosition, float scale = 1.f); + + /// Clear all savegame-specific data + void clear(); + + /// Clear all worldspace-specific data + void notifyWorldSpaceChanged(); + void update(float dt, bool paused); private: @@ -74,6 +83,7 @@ namespace MWRender std::auto_ptr mObjects; std::auto_ptr mSky; + std::auto_ptr mEffectManager; osg::ref_ptr mStateUpdater; diff --git a/apps/openmw/mwrender/util.cpp b/apps/openmw/mwrender/util.cpp new file mode 100644 index 000000000..e1af1c339 --- /dev/null +++ b/apps/openmw/mwrender/util.cpp @@ -0,0 +1,31 @@ +#include "util.hpp" + +#include + +#include +#include +#include + +namespace MWRender +{ + +void overrideTexture(const std::string &texture, Resource::ResourceSystem *resourceSystem, osg::ref_ptr node) +{ + if (texture.empty()) + return; + std::string correctedTexture = Misc::ResourceHelpers::correctTexturePath(texture, resourceSystem->getVFS()); + // Not sure if wrap settings should be pulled from the overridden texture? + osg::ref_ptr tex = resourceSystem->getTextureManager()->getTexture2D(correctedTexture, osg::Texture2D::CLAMP, + osg::Texture2D::CLAMP); + osg::ref_ptr stateset; + if (node->getStateSet()) + stateset = static_cast(node->getStateSet()->clone(osg::CopyOp::SHALLOW_COPY)); + else + stateset = new osg::StateSet; + + stateset->setTextureAttribute(0, tex, osg::StateAttribute::OVERRIDE); + + node->setStateSet(stateset); +} + +} diff --git a/apps/openmw/mwrender/util.hpp b/apps/openmw/mwrender/util.hpp new file mode 100644 index 000000000..d078f0d98 --- /dev/null +++ b/apps/openmw/mwrender/util.hpp @@ -0,0 +1,24 @@ +#ifndef OPENMW_MWRENDER_UTIL_H +#define OPENMW_MWRENDER_UTIL_H + +#include +#include + +namespace osg +{ + class Node; +} + +namespace Resource +{ + class ResourceSystem; +} + +namespace MWRender +{ + + void overrideTexture(const std::string& texture, Resource::ResourceSystem* resourceSystem, osg::ref_ptr node); + +} + +#endif diff --git a/apps/openmw/mwworld/refdata.hpp b/apps/openmw/mwworld/refdata.hpp index 2099b859f..955913d9c 100644 --- a/apps/openmw/mwworld/refdata.hpp +++ b/apps/openmw/mwworld/refdata.hpp @@ -5,6 +5,8 @@ #include "../mwscript/locals.hpp" +#include + namespace Ogre { class SceneNode; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index c6a1b5477..0628b42d7 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -276,7 +276,7 @@ namespace MWWorld void World::clear() { mWeatherManager->clear(); - //mRendering->clear(); + mRendering->clear(); #if 0 mProjectileManager->clear(); #endif @@ -991,8 +991,9 @@ namespace MWWorld // changed worldspace #if 0 mProjectileManager->clear(); - mRendering->notifyWorldSpaceChanged(); #endif + mRendering->notifyWorldSpaceChanged(); + mCurrentWorldSpace = cellName; } @@ -1010,8 +1011,8 @@ namespace MWWorld // changed worldspace #if 0 mProjectileManager->clear(); - mRendering->notifyWorldSpaceChanged(); #endif + mRendering->notifyWorldSpaceChanged(); } removeContainerScripts(getPlayerPtr()); mWorldScene->changeToExteriorCell(position, true); @@ -3203,7 +3204,7 @@ namespace MWWorld } } - void World::spawnBloodEffect(const Ptr &ptr, const Vector3 &worldPosition) + void World::spawnBloodEffect(const Ptr &ptr, const osg::Vec3f &worldPosition) { if (ptr == getPlayerPtr() && Settings::Manager::getBool("hit fader", "GUI")) return; @@ -3230,12 +3231,12 @@ namespace MWWorld modelName << roll; std::string model = "meshes\\" + getFallback()->getFallbackString(modelName.str()); - //mRendering->spawnEffect(model, texture, worldPosition); + mRendering->spawnEffect(model, texture, worldPosition); } - void World::spawnEffect(const std::string &model, const std::string &textureOverride, const Vector3 &worldPos) + void World::spawnEffect(const std::string &model, const std::string &textureOverride, const osg::Vec3f &worldPos) { - //mRendering->spawnEffect(model, textureOverride, worldPos); + mRendering->spawnEffect(model, textureOverride, worldPos); } void World::explodeSpell(const Vector3 &origin, const ESM::EffectList &effects, const Ptr &caster, ESM::RangeType rangeType, @@ -3251,15 +3252,13 @@ namespace MWWorld continue; // Not an area effect // Spawn the explosion orb effect - /* const ESM::Static* areaStatic; if (!effect->mCasting.empty()) areaStatic = getStore().get().find (effect->mArea); else areaStatic = getStore().get().find ("VFX_DefaultArea"); - mRendering->spawnEffect("meshes\\" + areaStatic->mModel, "", origin, static_cast(effectIt->mArea)); - */ + mRendering->spawnEffect("meshes\\" + areaStatic->mModel, "", osg::Vec3f(origin.x, origin.y, origin.z), static_cast(effectIt->mArea)); // Play explosion sound (make sure to use NoTrack, since we will delete the projectile now) static const std::string schools[] = { diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 9afda480b..5f79f52dc 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -650,9 +650,9 @@ namespace MWWorld virtual void spawnRandomCreature(const std::string& creatureList); /// Spawn a blood effect for \a ptr at \a worldPosition - virtual void spawnBloodEffect (const MWWorld::Ptr& ptr, const Ogre::Vector3& worldPosition); + virtual void spawnBloodEffect (const MWWorld::Ptr& ptr, const osg::Vec3f& worldPosition); - virtual void spawnEffect (const std::string& model, const std::string& textureOverride, const Ogre::Vector3& worldPos); + virtual void spawnEffect (const std::string& model, const std::string& textureOverride, const osg::Vec3f& worldPos); virtual void explodeSpell (const Ogre::Vector3& origin, const ESM::EffectList& effects, const MWWorld::Ptr& caster, ESM::RangeType rangeType, const std::string& id, const std::string& sourceName); diff --git a/components/esm/defs.hpp b/components/esm/defs.hpp index d261d7247..8ce76a8ea 100644 --- a/components/esm/defs.hpp +++ b/components/esm/defs.hpp @@ -3,6 +3,8 @@ #include +#include + namespace ESM { @@ -37,6 +39,11 @@ struct Position { float pos[3]; float rot[3]; + + osg::Vec3f asVec3() const + { + return osg::Vec3f(pos[0], pos[1], pos[2]); + } }; #pragma pack(pop) diff --git a/components/sceneutil/controller.cpp b/components/sceneutil/controller.cpp index 1f1b95ac8..79a75063a 100644 --- a/components/sceneutil/controller.cpp +++ b/components/sceneutil/controller.cpp @@ -89,4 +89,21 @@ namespace SceneUtil ctrl.mSource = mToAssign; } + FindMaxControllerLengthVisitor::FindMaxControllerLengthVisitor() + : SceneUtil::ControllerVisitor() + , mMaxLength(0) + { + } + + void FindMaxControllerLengthVisitor::visit(osg::Node &, Controller &ctrl) + { + if (ctrl.mFunction) + mMaxLength = std::max(mMaxLength, ctrl.mFunction->getMaximum()); + } + + float FindMaxControllerLengthVisitor::getMaxLength() const + { + return mMaxLength; + } + } diff --git a/components/sceneutil/controller.hpp b/components/sceneutil/controller.hpp index 655e02164..a4e209e8c 100644 --- a/components/sceneutil/controller.hpp +++ b/components/sceneutil/controller.hpp @@ -72,6 +72,20 @@ namespace SceneUtil boost::shared_ptr mToAssign; }; + /// Finds the maximum of all controller functions in the given scene graph + class FindMaxControllerLengthVisitor : public ControllerVisitor + { + public: + FindMaxControllerLengthVisitor(); + + virtual void visit(osg::Node& , Controller& ctrl); + + float getMaxLength() const; + + private: + float mMaxLength; + }; + } #endif From 42f6d9e15b642c69ce7adb745a3304c8a2d7a526 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 19 Apr 2015 20:07:18 +0200 Subject: [PATCH 0978/3725] Port video player --- CMakeLists.txt | 2 +- apps/openmw/CMakeLists.txt | 4 +- apps/openmw/mwrender/renderingmanager.cpp | 1 + apps/openmw/mwrender/sky.cpp | 13 +-- apps/openmw/mwsound/movieaudiofactory.cpp | 5 +- .../ogre-ffmpeg-videoplayer/videoplayer.cpp | 25 ++--- .../ogre-ffmpeg-videoplayer/videoplayer.hpp | 18 +++- extern/ogre-ffmpeg-videoplayer/videostate.cpp | 100 +++++++++--------- extern/ogre-ffmpeg-videoplayer/videostate.hpp | 22 ++-- 9 files changed, 104 insertions(+), 86 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 08d540333..c5319d600 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -549,7 +549,7 @@ include_directories(libs) add_subdirectory(libs/openengine) # Extern -#add_subdirectory (extern/ogre-ffmpeg-videoplayer) +add_subdirectory (extern/ogre-ffmpeg-videoplayer) add_subdirectory (extern/oics) #add_subdirectory (extern/sdl4ogre) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 09f2e08fa..46eb79462 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -59,8 +59,7 @@ add_openmw_dir (mwscript ) add_openmw_dir (mwsound - soundmanagerimp openal_output ffmpeg_decoder sound sound_decoder sound_output loudness libavwrapper -# movieaudiofactory + soundmanagerimp openal_output ffmpeg_decoder sound sound_decoder sound_output loudness libavwrapper movieaudiofactory ) add_openmw_dir (mwworld @@ -138,6 +137,7 @@ target_link_libraries(openmw ${MYGUI_LIBRARIES} ${SDL2_LIBRARY} ${MYGUI_PLATFORM_LIBRARIES} + "ogre-ffmpeg-videoplayer" "oics" components ) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index becd563b9..412d10ba2 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -167,6 +167,7 @@ namespace MWRender { mObjects->update(dt); mEffectManager->update(dt); + mSky->update(dt); } void RenderingManager::spawnEffect(const std::string &model, const std::string &texture, const osg::Vec3f &worldPosition, float scale) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index f843f9a43..f4028caa7 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -599,8 +599,8 @@ void SkyManager::update(float duration) mCloudAnimationTimer += duration * mCloudSpeed; /// \todo improve this - //mMasser->setPhase( static_cast( (int) ((mDay % 32)/4.f)) ); - //mSecunda->setPhase ( static_cast( (int) ((mDay % 32)/4.f)) ); + mMasser->setPhase( static_cast( (int) ((mDay % 32)/4.f)) ); + mSecunda->setPhase ( static_cast( (int) ((mDay % 32)/4.f)) ); //mSecunda->setColour ( mMoonRed ? fallback->getFallbackColour("Moons_Script_Color") : ColourValue(1,1,1,1)); //mMasser->setColour (ColourValue(1,1,1,1)); @@ -684,13 +684,8 @@ void SkyManager::setWeather(const MWWorld::WeatherResult& weather) DisableCullingVisitor visitor; mParticleEffect->accept(visitor); - /* - for (size_t i = 0; i < mParticle->mControllers.size(); ++i) - { - if (mParticle->mControllers[i].getSource().isNull()) - mParticle->mControllers[i].setSource(Ogre::ControllerManager::getSingleton().getFrameTimeSource()); - } - */ + SceneUtil::AssignControllerSourcesVisitor assignVisitor(boost::shared_ptr(new SceneUtil::FrameTimeSource)); + mParticleEffect->accept(assignVisitor); } } diff --git a/apps/openmw/mwsound/movieaudiofactory.cpp b/apps/openmw/mwsound/movieaudiofactory.cpp index 468f8c82c..198a66c53 100644 --- a/apps/openmw/mwsound/movieaudiofactory.cpp +++ b/apps/openmw/mwsound/movieaudiofactory.cpp @@ -17,7 +17,8 @@ namespace MWSound { public: MWSoundDecoderBridge(MWSound::MovieAudioDecoder* decoder) - : mDecoder(decoder) + : Sound_Decoder(NULL) + , mDecoder(decoder) { } @@ -51,7 +52,7 @@ namespace MWSound std::string getStreamName() { - return mVideoState->stream->getName(); + return std::string(); } private: diff --git a/extern/ogre-ffmpeg-videoplayer/videoplayer.cpp b/extern/ogre-ffmpeg-videoplayer/videoplayer.cpp index c2daf3579..8dedeaf64 100644 --- a/extern/ogre-ffmpeg-videoplayer/videoplayer.cpp +++ b/extern/ogre-ffmpeg-videoplayer/videoplayer.cpp @@ -1,5 +1,7 @@ #include "videoplayer.hpp" +#include + #include "audiofactory.hpp" #include "videostate.hpp" @@ -23,7 +25,7 @@ void VideoPlayer::setAudioFactory(MovieAudioFactory *factory) mAudioFactory.reset(factory); } -void VideoPlayer::playVideo(const std::string &resourceName) +void VideoPlayer::playVideo(boost::shared_ptr inputstream) { if(mState) close(); @@ -31,10 +33,10 @@ void VideoPlayer::playVideo(const std::string &resourceName) try { mState = new VideoState; mState->setAudioFactory(mAudioFactory.get()); - mState->init(resourceName); + mState->init(inputstream); // wait until we have the first picture - while (mState->video_st && mState->mTexture.isNull()) + while (mState->video_st && !mState->mTexture.get()) { if (!mState->update()) break; @@ -53,27 +55,26 @@ bool VideoPlayer::update () return false; } -std::string VideoPlayer::getTextureName() +osg::ref_ptr VideoPlayer::getVideoTexture() { - std::string name; - if (mState && !mState->mTexture.isNull()) - name = mState->mTexture->getName(); - return name; + if (mState) + return mState->mTexture; + return osg::ref_ptr(); } int VideoPlayer::getVideoWidth() { int width=0; - if (mState && !mState->mTexture.isNull()) - width = mState->mTexture->getWidth(); + if (mState && mState->mTexture.get()) + width = mState->mTexture->getTextureWidth(); return width; } int VideoPlayer::getVideoHeight() { int height=0; - if (mState && !mState->mTexture.isNull()) - height = mState->mTexture->getHeight(); + if (mState && mState->mTexture.get()) + height = mState->mTexture->getTextureHeight(); return height; } diff --git a/extern/ogre-ffmpeg-videoplayer/videoplayer.hpp b/extern/ogre-ffmpeg-videoplayer/videoplayer.hpp index 2727ac6f0..073dc6be2 100644 --- a/extern/ogre-ffmpeg-videoplayer/videoplayer.hpp +++ b/extern/ogre-ffmpeg-videoplayer/videoplayer.hpp @@ -4,6 +4,17 @@ #include #include +#include + +#include + +#include + +namespace osg +{ + class Texture2D; +} + namespace Video { @@ -30,7 +41,7 @@ namespace Video /// Play the given video. If a video is already playing, the old video is closed first. /// @note The video will be unpaused by default. Use the pause() and play() methods to control pausing. - void playVideo (const std::string& resourceName); + void playVideo (boost::shared_ptr inputstream); /// Get the current playback time position in the video, in seconds double getCurrentTime(); @@ -52,8 +63,9 @@ namespace Video /// Stop the currently playing video, if a video is playing. void close(); - /// Return the texture name of the currently playing video, or "" if no video is playing. - std::string getTextureName(); + /// Return the texture of the currently playing video, or a null pointer if no video is playing. + osg::ref_ptr getVideoTexture(); + /// Return the width of the currently playing video, or 0 if no video is playing. int getVideoWidth(); /// Return the height of the currently playing video, or 0 if no video is playing. diff --git a/extern/ogre-ffmpeg-videoplayer/videostate.cpp b/extern/ogre-ffmpeg-videoplayer/videostate.cpp index 66c7c2ad5..e95a0ca7b 100644 --- a/extern/ogre-ffmpeg-videoplayer/videostate.cpp +++ b/extern/ogre-ffmpeg-videoplayer/videostate.cpp @@ -11,6 +11,8 @@ #include #include +#include + extern "C" { #include @@ -172,12 +174,14 @@ void PacketQueue::clear() this->mutex.unlock (); } -int VideoState::OgreResource_Read(void *user_data, uint8_t *buf, int buf_size) +int VideoState::istream_read(void *user_data, uint8_t *buf, int buf_size) { - Ogre::DataStreamPtr stream = static_cast(user_data)->stream; try { - return stream->read(buf, buf_size); + std::istream& stream = *static_cast(user_data)->stream; + stream.read((char*)buf, buf_size); + stream.clear(); + return stream.gcount(); } catch (std::exception& ) { @@ -185,57 +189,57 @@ int VideoState::OgreResource_Read(void *user_data, uint8_t *buf, int buf_size) } } -int VideoState::OgreResource_Write(void *user_data, uint8_t *buf, int buf_size) +int VideoState::istream_write(void *, uint8_t *, int) { - Ogre::DataStreamPtr stream = static_cast(user_data)->stream; - try - { - return stream->write(buf, buf_size); - } - catch (std::exception& ) - { - return 0; - } + throw std::runtime_error("can't write to read-only stream"); } -int64_t VideoState::OgreResource_Seek(void *user_data, int64_t offset, int whence) +int64_t VideoState::istream_seek(void *user_data, int64_t offset, int whence) { - Ogre::DataStreamPtr stream = static_cast(user_data)->stream; + std::istream& stream = *static_cast(user_data)->stream; whence &= ~AVSEEK_FORCE; + if(whence == AVSEEK_SIZE) - return stream->size(); + { + size_t prev = stream.tellg(); + stream.seekg(0, std::ios_base::end); + size_t size = stream.tellg(); + stream.seekg(prev, std::ios_base::beg); + return size; + } + if(whence == SEEK_SET) - stream->seek(static_cast(offset)); + stream.seekg(offset, std::ios_base::beg); else if(whence == SEEK_CUR) - stream->seek(static_cast(stream->tell()+offset)); + stream.seekg(offset, std::ios_base::cur); else if(whence == SEEK_END) - stream->seek(static_cast(stream->size() + offset)); + stream.seekg(offset, std::ios_base::end); else return -1; - return stream->tell(); + return stream.tellg(); } void VideoState::video_display(VideoPicture *vp) { if((*this->video_st)->codec->width != 0 && (*this->video_st)->codec->height != 0) { - if (mTexture.isNull()) + if (!mTexture.get()) { - static int i = 0; - mTexture = Ogre::TextureManager::getSingleton().createManual( - "ffmpeg/VideoTexture" + Ogre::StringConverter::toString(++i), - Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - Ogre::TEX_TYPE_2D, - (*this->video_st)->codec->width, (*this->video_st)->codec->height, - 0, - Ogre::PF_BYTE_RGBA, - Ogre::TU_DYNAMIC_WRITE_ONLY_DISCARDABLE); + mTexture = new osg::Texture2D; + mTexture->setDataVariance(osg::Object::DYNAMIC); + mTexture->setResizeNonPowerOfTwoHint(false); + mTexture->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT); + mTexture->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT); } - Ogre::PixelBox pb((*this->video_st)->codec->width, (*this->video_st)->codec->height, 1, Ogre::PF_BYTE_RGBA, &vp->data[0]); - Ogre::HardwarePixelBufferSharedPtr buffer = mTexture->getBuffer(); - buffer->blitFromMemory(pb); + + osg::ref_ptr image = new osg::Image; + + image->setImage((*this->video_st)->codec->width, (*this->video_st)->codec->height, + 1, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, &vp->data[0], osg::Image::NO_DELETE); + + mTexture->setImage(image); } } @@ -250,7 +254,7 @@ void VideoState::video_refresh() VideoPicture* vp = &this->pictq[this->pictq_rindex]; this->video_display(vp); - this->pictq_rindex = (pictq_rindex+1) % VIDEO_PICTURE_QUEUE_SIZE; + this->pictq_rindex = (pictq_rindex+1) % VIDEO_PICTURE_ARRAY_SIZE; this->frame_last_pts = vp->pts; this->pictq_size--; this->pictq_cond.notify_one(); @@ -267,12 +271,12 @@ void VideoState::video_refresh() for (; ipictq_size-1; ++i) { if (this->pictq[pictq_rindex].pts + threshold <= this->get_master_clock()) - this->pictq_rindex = (this->pictq_rindex+1) % VIDEO_PICTURE_QUEUE_SIZE; // not enough time to show this picture + this->pictq_rindex = (this->pictq_rindex+1) % VIDEO_PICTURE_ARRAY_SIZE; // not enough time to show this picture else break; } - assert (this->pictq_rindex < VIDEO_PICTURE_QUEUE_SIZE); + assert (this->pictq_rindex < VIDEO_PICTURE_ARRAY_SIZE); VideoPicture* vp = &this->pictq[this->pictq_rindex]; this->video_display(vp); @@ -282,7 +286,7 @@ void VideoState::video_refresh() this->pictq_size -= i; // update queue for next picture this->pictq_size--; - this->pictq_rindex = (this->pictq_rindex+1) % VIDEO_PICTURE_QUEUE_SIZE; + this->pictq_rindex = (this->pictq_rindex+1) % VIDEO_PICTURE_ARRAY_SIZE; this->pictq_cond.notify_one(); } } @@ -328,7 +332,7 @@ int VideoState::queue_picture(AVFrame *pFrame, double pts) 0, (*this->video_st)->codec->height, &dst, this->rgbaFrame->linesize); // now we inform our display thread that we have a pic ready - this->pictq_windex = (this->pictq_windex+1) % VIDEO_PICTURE_QUEUE_SIZE; + this->pictq_windex = (this->pictq_windex+1) % VIDEO_PICTURE_ARRAY_SIZE; this->pictq_size++; this->pictq_mutex.unlock(); @@ -605,7 +609,7 @@ int VideoState::stream_open(int stream_index, AVFormatContext *pFormatCtx) return 0; } -void VideoState::init(const std::string& resourceName) +void VideoState::init(boost::shared_ptr inputstream) { int video_index = -1; int audio_index = -1; @@ -614,17 +618,19 @@ void VideoState::init(const std::string& resourceName) this->av_sync_type = AV_SYNC_DEFAULT; this->mQuit = false; - this->stream = Ogre::ResourceGroupManager::getSingleton().openResource(resourceName); - if(this->stream.isNull()) + this->stream = inputstream; + if(!this->stream.get()) throw std::runtime_error("Failed to open video resource"); - AVIOContext *ioCtx = avio_alloc_context(NULL, 0, 0, this, OgreResource_Read, OgreResource_Write, OgreResource_Seek); + AVIOContext *ioCtx = avio_alloc_context(NULL, 0, 0, this, istream_read, istream_write, istream_seek); if(!ioCtx) throw std::runtime_error("Failed to allocate AVIOContext"); this->format_ctx = avformat_alloc_context(); if(this->format_ctx) this->format_ctx->pb = ioCtx; + std::string videoName; + // Open video file /// /// format_ctx->pb->buffer must be freed by hand, @@ -632,7 +638,7 @@ void VideoState::init(const std::string& resourceName) /// /// https://trac.ffmpeg.org/ticket/1357 /// - if(!this->format_ctx || avformat_open_input(&this->format_ctx, resourceName.c_str(), NULL, NULL)) + if(!this->format_ctx || avformat_open_input(&this->format_ctx, videoName.c_str(), NULL, NULL)) { if (this->format_ctx != NULL) { @@ -656,7 +662,7 @@ void VideoState::init(const std::string& resourceName) throw std::runtime_error("Failed to retrieve stream information"); // Dump information about file onto standard error - av_dump_format(this->format_ctx, 0, resourceName.c_str(), 0); + av_dump_format(this->format_ctx, 0, videoName.c_str(), 0); for(i = 0;i < this->format_ctx->nb_streams;i++) { @@ -724,11 +730,7 @@ void VideoState::deinit() avformat_close_input(&this->format_ctx); } - if (!mTexture.isNull()) - { - Ogre::TextureManager::getSingleton().remove(mTexture->getName()); - mTexture.setNull(); - } + mTexture = NULL; } double VideoState::get_external_clock() diff --git a/extern/ogre-ffmpeg-videoplayer/videostate.hpp b/extern/ogre-ffmpeg-videoplayer/videostate.hpp index cdeb2d0e3..40925e014 100644 --- a/extern/ogre-ffmpeg-videoplayer/videostate.hpp +++ b/extern/ogre-ffmpeg-videoplayer/videostate.hpp @@ -3,11 +3,17 @@ #include -#include +#include +namespace osg +{ + class Texture2D; +} #include "videodefs.hpp" #define VIDEO_PICTURE_QUEUE_SIZE 50 +// allocate one extra to make sure we do not overwrite the osg::Image currently set on the texture +#define VIDEO_PICTURE_ARRAY_SIZE (VIDEO_PICTURE_QUEUE_SIZE+1) extern "C" { @@ -78,7 +84,7 @@ struct VideoState { void setAudioFactory(MovieAudioFactory* factory); - void init(const std::string& resourceName); + void init(boost::shared_ptr inputstream); void deinit(); void setPaused(bool isPaused); @@ -104,18 +110,18 @@ struct VideoState { double get_external_clock(); double get_master_clock(); - static int OgreResource_Read(void *user_data, uint8_t *buf, int buf_size); - static int OgreResource_Write(void *user_data, uint8_t *buf, int buf_size); - static int64_t OgreResource_Seek(void *user_data, int64_t offset, int whence); + static int istream_read(void *user_data, uint8_t *buf, int buf_size); + static int istream_write(void *user_data, uint8_t *buf, int buf_size); + static int64_t istream_seek(void *user_data, int64_t offset, int whence); - Ogre::TexturePtr mTexture; + osg::ref_ptr mTexture; MovieAudioFactory* mAudioFactory; boost::shared_ptr mAudioDecoder; ExternalClock mExternalClock; - Ogre::DataStreamPtr stream; + boost::shared_ptr stream; AVFormatContext* format_ctx; int av_sync_type; @@ -130,7 +136,7 @@ struct VideoState { double video_clock; /// Date: Sun, 19 Apr 2015 20:12:37 +0200 Subject: [PATCH 0979/3725] Dead code removal --- extern/ogre-ffmpeg-videoplayer/videoplayer.hpp | 2 +- extern/ogre-ffmpeg-videoplayer/videostate.cpp | 11 +---------- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/extern/ogre-ffmpeg-videoplayer/videoplayer.hpp b/extern/ogre-ffmpeg-videoplayer/videoplayer.hpp index 073dc6be2..261246f39 100644 --- a/extern/ogre-ffmpeg-videoplayer/videoplayer.hpp +++ b/extern/ogre-ffmpeg-videoplayer/videoplayer.hpp @@ -22,7 +22,7 @@ namespace Video class MovieAudioFactory; /** - * @brief Plays a video on an Ogre texture. + * @brief Plays a video on an osg texture. */ class VideoPlayer { diff --git a/extern/ogre-ffmpeg-videoplayer/videostate.cpp b/extern/ogre-ffmpeg-videoplayer/videostate.cpp index e95a0ca7b..6a054d99e 100644 --- a/extern/ogre-ffmpeg-videoplayer/videostate.cpp +++ b/extern/ogre-ffmpeg-videoplayer/videostate.cpp @@ -5,12 +5,6 @@ #endif #include -// Has to be included *before* ffmpeg, due to a macro collision with ffmpeg (#define PixelFormat in avformat.h - grumble) -#include -#include -#include -#include - #include extern "C" @@ -535,12 +529,9 @@ void VideoState::decode_thread_loop(VideoState *self) av_free_packet(packet); } } - catch(std::runtime_error& e) { + catch(std::exception& e) { std::cerr << "An error occured playing the video: " << e.what () << std::endl; } - catch(Ogre::Exception& e) { - std::cerr << "An error occured playing the video: " << e.getFullDescription () << std::endl; - } self->mQuit = true; } From 92ef9b1c57130698b7882af7d0aa71339089e5b1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 19 Apr 2015 20:14:06 +0200 Subject: [PATCH 0980/3725] Rename to osg-ffmpeg-videoplayer --- CMakeLists.txt | 2 +- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwgui/videowidget.cpp | 2 +- apps/openmw/mwsound/movieaudiofactory.cpp | 4 ++-- apps/openmw/mwsound/movieaudiofactory.hpp | 2 +- .../CMakeLists.txt | 8 ++++---- .../License.txt | 0 .../audiodecoder.cpp | 0 .../audiodecoder.hpp | 0 .../audiofactory.hpp | 0 .../libavwrapper.cpp | 0 .../videodefs.hpp | 0 .../videoplayer.cpp | 0 .../videoplayer.hpp | 0 .../videostate.cpp | 0 .../videostate.hpp | 0 16 files changed, 10 insertions(+), 10 deletions(-) rename extern/{ogre-ffmpeg-videoplayer => osg-ffmpeg-videoplayer}/CMakeLists.txt (78%) rename extern/{ogre-ffmpeg-videoplayer => osg-ffmpeg-videoplayer}/License.txt (100%) rename extern/{ogre-ffmpeg-videoplayer => osg-ffmpeg-videoplayer}/audiodecoder.cpp (100%) rename extern/{ogre-ffmpeg-videoplayer => osg-ffmpeg-videoplayer}/audiodecoder.hpp (100%) rename extern/{ogre-ffmpeg-videoplayer => osg-ffmpeg-videoplayer}/audiofactory.hpp (100%) rename extern/{ogre-ffmpeg-videoplayer => osg-ffmpeg-videoplayer}/libavwrapper.cpp (100%) rename extern/{ogre-ffmpeg-videoplayer => osg-ffmpeg-videoplayer}/videodefs.hpp (100%) rename extern/{ogre-ffmpeg-videoplayer => osg-ffmpeg-videoplayer}/videoplayer.cpp (100%) rename extern/{ogre-ffmpeg-videoplayer => osg-ffmpeg-videoplayer}/videoplayer.hpp (100%) rename extern/{ogre-ffmpeg-videoplayer => osg-ffmpeg-videoplayer}/videostate.cpp (100%) rename extern/{ogre-ffmpeg-videoplayer => osg-ffmpeg-videoplayer}/videostate.hpp (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index c5319d600..e806b2578 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -549,7 +549,7 @@ include_directories(libs) add_subdirectory(libs/openengine) # Extern -add_subdirectory (extern/ogre-ffmpeg-videoplayer) +add_subdirectory (extern/osg-ffmpeg-videoplayer) add_subdirectory (extern/oics) #add_subdirectory (extern/sdl4ogre) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 46eb79462..c8854f84b 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -137,7 +137,7 @@ target_link_libraries(openmw ${MYGUI_LIBRARIES} ${SDL2_LIBRARY} ${MYGUI_PLATFORM_LIBRARIES} - "ogre-ffmpeg-videoplayer" + "osg-ffmpeg-videoplayer" "oics" components ) diff --git a/apps/openmw/mwgui/videowidget.cpp b/apps/openmw/mwgui/videowidget.cpp index 4ead16c5b..28771f14f 100644 --- a/apps/openmw/mwgui/videowidget.cpp +++ b/apps/openmw/mwgui/videowidget.cpp @@ -1,6 +1,6 @@ #include "videowidget.hpp" -//#include +//#include #include diff --git a/apps/openmw/mwsound/movieaudiofactory.cpp b/apps/openmw/mwsound/movieaudiofactory.cpp index 198a66c53..47889051a 100644 --- a/apps/openmw/mwsound/movieaudiofactory.cpp +++ b/apps/openmw/mwsound/movieaudiofactory.cpp @@ -1,7 +1,7 @@ #include "movieaudiofactory.hpp" -#include -#include +#include +#include #include "../mwbase/environment.hpp" #include "../mwbase/soundmanager.hpp" diff --git a/apps/openmw/mwsound/movieaudiofactory.hpp b/apps/openmw/mwsound/movieaudiofactory.hpp index a3c602197..1391a0012 100644 --- a/apps/openmw/mwsound/movieaudiofactory.hpp +++ b/apps/openmw/mwsound/movieaudiofactory.hpp @@ -1,7 +1,7 @@ #ifndef OPENMW_MWSOUND_MOVIEAUDIOFACTORY_H #define OPENMW_MWSOUND_MOVIEAUDIOFACTORY_H -#include +#include namespace MWSound { diff --git a/extern/ogre-ffmpeg-videoplayer/CMakeLists.txt b/extern/osg-ffmpeg-videoplayer/CMakeLists.txt similarity index 78% rename from extern/ogre-ffmpeg-videoplayer/CMakeLists.txt rename to extern/osg-ffmpeg-videoplayer/CMakeLists.txt index 299a57799..92a2f3424 100644 --- a/extern/ogre-ffmpeg-videoplayer/CMakeLists.txt +++ b/extern/osg-ffmpeg-videoplayer/CMakeLists.txt @@ -1,8 +1,8 @@ -set(OGRE_FFMPEG_VIDEOPLAYER_LIBRARY "ogre-ffmpeg-videoplayer") +set(OSG_FFMPEG_VIDEOPLAYER_LIBRARY "osg-ffmpeg-videoplayer") # Sources -set(OGRE_FFMPEG_VIDEOPLAYER_SOURCE_FILES +set(OSG_FFMPEG_VIDEOPLAYER_SOURCE_FILES videoplayer.cpp videostate.cpp videodefs.hpp @@ -36,7 +36,7 @@ set(BOOST_COMPONENTS thread) find_package(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS}) include_directories(${Boost_INCLUDE_DIRS}) -add_library(${OGRE_FFMPEG_VIDEOPLAYER_LIBRARY} STATIC ${OGRE_FFMPEG_VIDEOPLAYER_SOURCE_FILES}) -target_link_libraries(${OGRE_FFMPEG_VIDEOPLAYER_LIBRARY} ${VIDEO_FFMPEG_LIBRARIES} ${Boost_LIBRARIES}) +add_library(${OSG_FFMPEG_VIDEOPLAYER_LIBRARY} STATIC ${OSG_FFMPEG_VIDEOPLAYER_SOURCE_FILES}) +target_link_libraries(${OSG_FFMPEG_VIDEOPLAYER_LIBRARY} ${VIDEO_FFMPEG_LIBRARIES} ${Boost_LIBRARIES}) link_directories(${CMAKE_CURRENT_BINARY_DIR}) diff --git a/extern/ogre-ffmpeg-videoplayer/License.txt b/extern/osg-ffmpeg-videoplayer/License.txt similarity index 100% rename from extern/ogre-ffmpeg-videoplayer/License.txt rename to extern/osg-ffmpeg-videoplayer/License.txt diff --git a/extern/ogre-ffmpeg-videoplayer/audiodecoder.cpp b/extern/osg-ffmpeg-videoplayer/audiodecoder.cpp similarity index 100% rename from extern/ogre-ffmpeg-videoplayer/audiodecoder.cpp rename to extern/osg-ffmpeg-videoplayer/audiodecoder.cpp diff --git a/extern/ogre-ffmpeg-videoplayer/audiodecoder.hpp b/extern/osg-ffmpeg-videoplayer/audiodecoder.hpp similarity index 100% rename from extern/ogre-ffmpeg-videoplayer/audiodecoder.hpp rename to extern/osg-ffmpeg-videoplayer/audiodecoder.hpp diff --git a/extern/ogre-ffmpeg-videoplayer/audiofactory.hpp b/extern/osg-ffmpeg-videoplayer/audiofactory.hpp similarity index 100% rename from extern/ogre-ffmpeg-videoplayer/audiofactory.hpp rename to extern/osg-ffmpeg-videoplayer/audiofactory.hpp diff --git a/extern/ogre-ffmpeg-videoplayer/libavwrapper.cpp b/extern/osg-ffmpeg-videoplayer/libavwrapper.cpp similarity index 100% rename from extern/ogre-ffmpeg-videoplayer/libavwrapper.cpp rename to extern/osg-ffmpeg-videoplayer/libavwrapper.cpp diff --git a/extern/ogre-ffmpeg-videoplayer/videodefs.hpp b/extern/osg-ffmpeg-videoplayer/videodefs.hpp similarity index 100% rename from extern/ogre-ffmpeg-videoplayer/videodefs.hpp rename to extern/osg-ffmpeg-videoplayer/videodefs.hpp diff --git a/extern/ogre-ffmpeg-videoplayer/videoplayer.cpp b/extern/osg-ffmpeg-videoplayer/videoplayer.cpp similarity index 100% rename from extern/ogre-ffmpeg-videoplayer/videoplayer.cpp rename to extern/osg-ffmpeg-videoplayer/videoplayer.cpp diff --git a/extern/ogre-ffmpeg-videoplayer/videoplayer.hpp b/extern/osg-ffmpeg-videoplayer/videoplayer.hpp similarity index 100% rename from extern/ogre-ffmpeg-videoplayer/videoplayer.hpp rename to extern/osg-ffmpeg-videoplayer/videoplayer.hpp diff --git a/extern/ogre-ffmpeg-videoplayer/videostate.cpp b/extern/osg-ffmpeg-videoplayer/videostate.cpp similarity index 100% rename from extern/ogre-ffmpeg-videoplayer/videostate.cpp rename to extern/osg-ffmpeg-videoplayer/videostate.cpp diff --git a/extern/ogre-ffmpeg-videoplayer/videostate.hpp b/extern/osg-ffmpeg-videoplayer/videostate.hpp similarity index 100% rename from extern/ogre-ffmpeg-videoplayer/videostate.hpp rename to extern/osg-ffmpeg-videoplayer/videostate.hpp From 167ae600c5a87b1d0fcbea6570992026d29a31a1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 20 Apr 2015 00:37:17 +0200 Subject: [PATCH 0981/3725] Implement gravity decay (previously unknown float) --- components/nif/controlled.cpp | 5 +---- components/nif/controlled.hpp | 1 + components/nifosg/particle.cpp | 38 +++++++++++++++++++++++++--------- components/nifosg/particle.hpp | 4 +++- 4 files changed, 33 insertions(+), 15 deletions(-) diff --git a/components/nif/controlled.cpp b/components/nif/controlled.cpp index bf391d388..5c63094ce 100644 --- a/components/nif/controlled.cpp +++ b/components/nif/controlled.cpp @@ -54,10 +54,7 @@ namespace Nif { Controlled::read(nif); - float decay = nif->getFloat(); - if (decay != 0.f) - nif->file->warn("Unhandled gravity decay factor"); - + mDecay = nif->getFloat(); mForce = nif->getFloat(); mType = nif->getUInt(); mPosition = nif->getVector3(); diff --git a/components/nif/controlled.hpp b/components/nif/controlled.hpp index 36d90b03d..4bd7ce1f9 100644 --- a/components/nif/controlled.hpp +++ b/components/nif/controlled.hpp @@ -92,6 +92,7 @@ public: * 1 - Point (fixed origin) */ int mType; + float mDecay; osg::Vec3f mPosition; osg::Vec3f mDirection; diff --git a/components/nifosg/particle.cpp b/components/nifosg/particle.cpp index 59a4a981b..3cfd91f1f 100644 --- a/components/nifosg/particle.cpp +++ b/components/nifosg/particle.cpp @@ -155,13 +155,14 @@ void ParticleColorAffector::operate(osgParticle::Particle* particle, double /* d GravityAffector::GravityAffector(const Nif::NiGravity *gravity) : mForce(gravity->mForce) , mType(static_cast(gravity->mType)) + , mDecay(gravity->mDecay) , mPosition(gravity->mPosition) , mDirection(gravity->mDirection) { } GravityAffector::GravityAffector() - : mForce(0), mType(Type_Wind) + : mForce(0), mType(Type_Wind), mDecay(0.f) { } @@ -175,10 +176,12 @@ GravityAffector::GravityAffector(const GravityAffector ©, const osg::CopyOp void GravityAffector::beginOperate(osgParticle::Program* program) { bool absolute = (program->getReferenceFrame() == osgParticle::ParticleProcessor::ABSOLUTE_RF); - if (mType == Type_Wind) - mCachedWorldPositionDirection = absolute ? program->rotateLocalToWorld(mDirection) : mDirection; - else // Type_Point - mCachedWorldPositionDirection = absolute ? program->transformLocalToWorld(mPosition) : mPosition; + + if (mType == Type_Point || mDecay != 0.f) // we don't need the position for Wind gravity, except if decay is being applied + mCachedWorldPosition = absolute ? program->transformLocalToWorld(mPosition) : mPosition; + + mCachedWorldDirection = absolute ? program->rotateLocalToWorld(mDirection) : mDirection; + mCachedWorldDirection.normalize(); } void GravityAffector::operate(osgParticle::Particle *particle, double dt) @@ -187,18 +190,33 @@ void GravityAffector::operate(osgParticle::Particle *particle, double dt) switch (mType) { case Type_Wind: - particle->addVelocity(mCachedWorldPositionDirection * mForce * dt * magic); + { + float decayFactor = 1.f; + if (mDecay != 0.f) + { + osg::Plane gravityPlane(mCachedWorldDirection, mCachedWorldPosition); + float distance = std::abs(gravityPlane.distance(particle->getPosition())); + decayFactor = std::exp(-1.f * mDecay * distance); + } + + particle->addVelocity(mCachedWorldDirection * mForce * dt * decayFactor * magic); + break; + } case Type_Point: { - osg::Vec3f diff = mCachedWorldPositionDirection - particle->getPosition(); + osg::Vec3f diff = mCachedWorldPosition - particle->getPosition(); + + float decayFactor = 1.f; + if (mDecay != 0.f) + decayFactor = std::exp(-1.f * mDecay * diff.length()); + diff.normalize(); - particle->addVelocity(diff * mForce * dt * magic); + + particle->addVelocity(diff * mForce * dt * decayFactor * magic); break; } } - - // velocity *= e^-[(dist/decay)^2] } Emitter::Emitter() diff --git a/components/nifosg/particle.hpp b/components/nifosg/particle.hpp index 99db3c83a..416477cdd 100644 --- a/components/nifosg/particle.hpp +++ b/components/nifosg/particle.hpp @@ -169,7 +169,9 @@ namespace NifOsg ForceType mType; osg::Vec3f mPosition; osg::Vec3f mDirection; - osg::Vec3f mCachedWorldPositionDirection; + float mDecay; + osg::Vec3f mCachedWorldPosition; + osg::Vec3f mCachedWorldDirection; }; // NodeVisitor to find a child node with the given record index, stored in the node's user data container. From f326b14604048b26722966add5d49bf02aa9db4c Mon Sep 17 00:00:00 2001 From: cc9cii Date: Tue, 21 Apr 2015 10:25:19 +1000 Subject: [PATCH 0982/3725] Allow Qt to cleanup its signals. --- apps/opencs/model/doc/documentmanager.cpp | 2 +- apps/opencs/view/doc/view.cpp | 6 +----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/apps/opencs/model/doc/documentmanager.cpp b/apps/opencs/model/doc/documentmanager.cpp index 7a1a86153..2d444f245 100644 --- a/apps/opencs/model/doc/documentmanager.cpp +++ b/apps/opencs/model/doc/documentmanager.cpp @@ -69,7 +69,7 @@ void CSMDoc::DocumentManager::removeDocument (CSMDoc::Document *document) throw std::runtime_error ("removing invalid document"); mDocuments.erase (iter); - delete document; + document->deleteLater(); if (mDocuments.empty()) emit lastDocumentDeleted(); diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index aaf8f2d6a..e430bfa5e 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -32,10 +32,6 @@ void CSVDoc::View::closeEvent (QCloseEvent *event) event->ignore(); else { - // delete the subviews first - for (QList::iterator iter = mSubViews.begin(); iter != mSubViews.end(); ++iter) - delete *iter; - // closeRequest() returns true if last document mViewManager.removeDocAndView(mDocument); } @@ -98,7 +94,7 @@ void CSVDoc::View::setupEditMenu() QAction *search = new QAction (tr ("Search"), this); connect (search, SIGNAL (triggered()), this, SLOT (addSearchSubView())); - edit->addAction (search); + edit->addAction (search); } void CSVDoc::View::setupViewMenu() From f7c7aeecb3c188db6b5274acef45ac717976d966 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 21 Apr 2015 14:44:51 +0200 Subject: [PATCH 0983/3725] fixed missing state update when starting a global search --- apps/opencs/model/doc/document.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index cb3b4ba18..31d0aaccd 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -2382,7 +2382,8 @@ CSMWorld::UniversalId CSMDoc::Document::newSearch() void CSMDoc::Document::runSearch (const CSMWorld::UniversalId& searchId, const CSMTools::Search& search) { - return mTools.runSearch (searchId, search); + mTools.runSearch (searchId, search); + emit stateChanged (getState(), this); } void CSMDoc::Document::abortOperation (int type) From 4ea6d4aa0107b95a0ec0655ba1c3e88458baea9e Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 21 Apr 2015 16:02:40 +0200 Subject: [PATCH 0984/3725] Rewrite of skinning code Goals: - get rid of the mesh pre-transform (this requires supporting different bind matrices for each mesh) - bounding box should be relative to the bone the mesh is attached to, ideally we can then get rid of the expensive skeleton-based bounding boxes - update bone matrices in CullCallback instead of UpdateCallback Works OK, though the bounding boxes are not correct yet. --- components/CMakeLists.txt | 2 +- components/nifosg/nifloader.cpp | 345 +++++------------------------- components/nifosg/riggeometry.cpp | 201 +++++++++++++++++ components/nifosg/riggeometry.hpp | 56 +++++ components/nifosg/skeleton.cpp | 148 +++++++++++++ components/nifosg/skeleton.hpp | 58 +++++ 6 files changed, 520 insertions(+), 290 deletions(-) create mode 100644 components/nifosg/riggeometry.cpp create mode 100644 components/nifosg/riggeometry.hpp create mode 100644 components/nifosg/skeleton.cpp create mode 100644 components/nifosg/skeleton.hpp diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index f61724eeb..b49beea0b 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -47,7 +47,7 @@ add_component_dir (nif ) add_component_dir (nifosg - nifloader controller particle userdata + nifloader controller particle userdata skeleton riggeometry ) #add_component_dir (nifcache diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 1f0c36839..f0bb538f2 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -6,6 +6,9 @@ #include #include +#include +#include + #include // resource @@ -14,11 +17,7 @@ #include // skel -#include -#include -#include #include -#include // particle #include @@ -45,6 +44,8 @@ #include "particle.hpp" #include "userdata.hpp" +#include "skeleton.hpp" +#include "riggeometry.hpp" namespace { @@ -206,32 +207,6 @@ namespace } }; - // NodeCallback used to update the bone matrices in skeleton space as needed for skinning. - // Must be set on a Bone. - class UpdateBone : public osg::NodeCallback - { - public: - UpdateBone() {} - UpdateBone(const UpdateBone& copy, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY) - : osg::Object(copy, copyop), osg::NodeCallback(copy, copyop) - { - } - - META_Object(NifOsg, UpdateBone) - - // Callback method called by the NodeVisitor when visiting a node. - void operator()(osg::Node* node, osg::NodeVisitor* nv) - { - osgAnimation::Bone* b = static_cast(node); - osgAnimation::Bone* parent = b->getBoneParent(); - if (parent) - b->setMatrixInSkeletonSpace(b->getMatrixInBoneSpace() * parent->getMatrixInSkeletonSpace()); - else - b->setMatrixInSkeletonSpace(b->getMatrixInBoneSpace()); - traverse(node,nv); - } - }; - // NodeCallback used to have a transform always oriented towards the camera. Can have translation and scale // set just like a regular MatrixTransform, but the rotation set will be overridden in order to face the camera. class BillboardCallback : public osg::NodeCallback @@ -304,7 +279,7 @@ namespace for (osg::NodePath::iterator it = path.begin(); it != path.end(); ++it) { - if (dynamic_cast(*it)) + if (dynamic_cast(*it)) { path.erase(path.begin(), it+1); // the bone's transform in skeleton space @@ -357,95 +332,6 @@ namespace }; */ - // Node callback used to dirty a RigGeometry's bounding box every frame, so that RigBoundingBoxCallback updates. - // This has to be attached to the geode, because the RigGeometry's Drawable::UpdateCallback is already used internally and not extensible. - // Kind of awful, not sure of a better way to do this. - class DirtyBoundCallback : public osg::NodeCallback - { - public: - DirtyBoundCallback() - { - } - DirtyBoundCallback(const DirtyBoundCallback& copy, const osg::CopyOp& copyop) - : osg::NodeCallback(copy, copyop) - { - } - - META_Object(NifOsg, DirtyBoundCallback) - - void operator()(osg::Node* node, osg::NodeVisitor* nv) - { - osg::Geode* geode = node->asGeode(); - if (geode && geode->getNumDrawables()) - { - geode->getDrawable(0)->dirtyBound(); - } - traverse(node, nv); - } - }; - - struct FindNearestParentSkeleton : public osg::NodeVisitor - { - osg::ref_ptr _root; - FindNearestParentSkeleton() : osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_PARENTS) {} - void apply(osg::Transform& node) - { - if (_root.valid()) - return; - _root = dynamic_cast(&node); - traverse(node); - } - }; - - // RigGeometry is skinned from a CullCallback to prevent unnecessary updates of culled rig geometries. - // Note: this assumes only one cull thread is using the given RigGeometry, there would be a race condition otherwise. - struct UpdateRigGeometry : public osg::Drawable::CullCallback - { - UpdateRigGeometry() - { - } - - UpdateRigGeometry(const UpdateRigGeometry& copy, const osg::CopyOp& copyop) - : osg::Drawable::CullCallback(copy, copyop) - { - } - - META_Object(NifOsg, UpdateRigGeometry) - - virtual bool cull(osg::NodeVisitor *, osg::Drawable * drw, osg::State *) const - { - osgAnimation::RigGeometry* geom = static_cast(drw); - if (!geom) - return false; - if (!geom->getSkeleton() && !geom->getParents().empty()) - { - FindNearestParentSkeleton finder; - if (geom->getParents().size() > 1) - osg::notify(osg::WARN) << "A RigGeometry should not have multi parent ( " << geom->getName() << " )" << std::endl; - geom->getParents()[0]->accept(finder); - - if (!finder._root.valid()) - { - osg::notify(osg::WARN) << "A RigGeometry did not find a parent skeleton for RigGeometry ( " << geom->getName() << " )" << std::endl; - return false; - } - geom->buildVertexInfluenceSet(); - geom->setSkeleton(finder._root.get()); - } - - if (!geom->getSkeleton()) - return false; - - if (geom->getNeedToComputeMatrix()) - geom->computeMatrixFromRootSkeleton(); - - geom->update(); - - return false; - } - }; - - // Same for MorphGeometry struct UpdateMorphGeometry : public osg::Drawable::CullCallback { UpdateMorphGeometry() @@ -500,88 +386,6 @@ namespace osg::BoundingBox mBoundingBox; }; - class RigBoundingBoxCallback : public osg::Drawable::ComputeBoundingBoxCallback - { - public: - RigBoundingBoxCallback() - : mBoneMapInit(false) - { - } - RigBoundingBoxCallback(const RigBoundingBoxCallback& copy, const osg::CopyOp& copyop) - : osg::Drawable::ComputeBoundingBoxCallback(copy, copyop) - , mBoneMapInit(false) - , mBoundSpheres(copy.mBoundSpheres) - { - } - - META_Object(NifOsg, RigBoundingBoxCallback) - - void addBoundSphere(const std::string& bonename, const osg::BoundingSphere& sphere) - { - mBoundSpheres[bonename] = sphere; - } - - virtual osg::BoundingBox computeBound(const osg::Drawable& drawable) const - { - osg::BoundingBox box; - - const osgAnimation::RigGeometry* rig = dynamic_cast(&drawable); - if (!rig) - { - std::cerr << "Warning: RigBoundingBoxCallback set on non-rig" << std::endl; - return box; - } - - if (!mBoneMapInit) - { - initBoneMap(rig); - } - - for (std::map::const_iterator it = mBoneMap.begin(); - it != mBoneMap.end(); ++it) - { - osgAnimation::Bone* bone = it->first; - osg::BoundingSphere bs = it->second; - SceneUtil::transformBoundingSphere(bone->getMatrixInSkeletonSpace(), bs); - box.expandBy(bs); - } - - return box; - } - - void initBoneMap(const osgAnimation::RigGeometry* rig) const - { - if (!rig->getSkeleton()) - { - // may happen before the first frame update, but we're not animating yet, so no need for a bounding box - return; - } - - osgAnimation::BoneMapVisitor mapVisitor; - { - // const_cast necessary because there does not seem to be a const variant of NodeVisitor. - // Don't worry, we're not actually changing the skeleton. - osgAnimation::Skeleton* skel = const_cast(rig->getSkeleton()); - skel->accept(mapVisitor); - } - - for (osgAnimation::BoneMap::const_iterator it = mapVisitor.getBoneMap().begin(); it != mapVisitor.getBoneMap().end(); ++it) - { - std::map::const_iterator found = mBoundSpheres.find(it->first); - if (found != mBoundSpheres.end()) // not all bones have to be used for skinning - mBoneMap[it->second.get()] = found->second; - } - - mBoneMapInit = true; - } - - private: - mutable bool mBoneMapInit; - mutable std::map mBoneMap; - - std::map mBoundSpheres; - }; - void extractTextKeys(const Nif::NiTextKeyExtraData *tk, NifOsg::TextKeyMap &textkeys) { for(size_t i = 0;i < tk->list.size();i++) @@ -731,8 +535,7 @@ namespace NifOsg osg::ref_ptr textkeys (new TextKeyMapHolder); - osg::ref_ptr skel = new osgAnimation::Skeleton; - skel->setDefaultUpdateCallback(); // validates the skeleton hierarchy + osg::ref_ptr skel = new Skeleton; handleNode(nifNode, skel, textureManager, true, std::map(), 0, 0, false, &textkeys->mTextKeys); skel->getOrCreateUserDataContainer()->addUserObject(textkeys); @@ -762,18 +565,8 @@ namespace NifOsg static osg::ref_ptr handleNode(const Nif::Node* nifNode, osg::Group* parentNode, Resource::TextureManager* textureManager, bool createSkeleton, std::map boundTextures, int animflags, int particleflags, bool skipMeshes, TextKeyMap* textKeys, osg::Node* rootNode=NULL) { - osg::ref_ptr transformNode; - if (createSkeleton) - { - osgAnimation::Bone* bone = new osgAnimation::Bone; - transformNode = bone; - bone->setMatrix(toMatrix(nifNode->trafo)); - bone->setInvBindMatrixInSkeletonSpace(osg::Matrixf::inverse(getWorldTransform(nifNode))); - } - else - { - transformNode = new osg::MatrixTransform(toMatrix(nifNode->trafo)); - } + osg::ref_ptr transformNode = new osg::MatrixTransform(toMatrix(nifNode->trafo)); + if (nifNode->recType == Nif::RC_NiBillboardNode) { transformNode->addCullCallback(new BillboardCallback); @@ -870,10 +663,6 @@ namespace NifOsg if (!nifNode->controller.empty()) handleNodeControllers(nifNode, transformNode, animflags); - // Added last so the changes from KeyframeControllers are taken into account - if (osgAnimation::Bone* bone = dynamic_cast(transformNode.get())) - bone->addUpdateCallback(new UpdateBone); - const Nif::NiNode *ninode = dynamic_cast(nifNode); if(ninode) { @@ -1219,49 +1008,6 @@ namespace NifOsg { const Nif::NiTriShapeData* data = triShape->data.getPtr(); - const Nif::NiSkinInstance *skin = (triShape->skin.empty() ? NULL : triShape->skin.getPtr()); - if (skin) - { - // Convert vertices and normals to bone space from bind position. It would be - // better to transform the bones into bind position, but there doesn't seem to - // be a reliable way to do that. - osg::ref_ptr newVerts (new osg::Vec3Array(data->vertices.size())); - osg::ref_ptr newNormals (new osg::Vec3Array(data->normals.size())); - - const Nif::NiSkinData *skinData = skin->data.getPtr(); - const Nif::NodeList &bones = skin->bones; - for(size_t b = 0;b < bones.length();b++) - { - osg::Matrixf mat = toMatrix(skinData->bones[b].trafo); - - mat = mat * getWorldTransform(bones[b].getPtr()); - - const std::vector &weights = skinData->bones[b].weights; - for(size_t i = 0;i < weights.size();i++) - { - size_t index = weights[i].vertex; - float weight = weights[i].weight; - - osg::Vec4f mult = (osg::Vec4f(data->vertices.at(index),1.f) * mat) * weight; - (*newVerts)[index] += osg::Vec3f(mult.x(),mult.y(),mult.z()); - if(newNormals->size() > index) - { - osg::Vec4 normal(data->normals[index].x(), data->normals[index].y(), data->normals[index].z(), 0.f); - normal = (normal * mat) * weight; - (*newNormals)[index] += osg::Vec3f(normal.x(),normal.y(),normal.z()); - } - } - } - // Interpolating normalized normals doesn't necessarily give you a normalized result - // Currently we're using GL_NORMALIZE, so this isn't needed - //for (unsigned int i=0;isize();++i) - // (*newNormals)[i].normalize(); - - geometry->setVertexArray(newVerts); - if (!data->normals.empty()) - geometry->setNormalArray(newNormals, osg::Array::BIND_PER_VERTEX); - } - else { geometry->setVertexArray(new osg::Vec3Array(data->vertices.size(), &data->vertices[0])); if (!data->normals.empty()) @@ -1397,6 +1143,24 @@ namespace NifOsg return morphGeom; } + class BoundingBoxCallback : public osg::NodeCallback + { + public: + virtual void operator()( osg::Node* node, osg::NodeVisitor* nv ) + { + osg::BoundingBox bb = mDrawable->getBound(); + + static_cast(node)->setMatrix( + osg::Matrix::scale(bb.xMax()-bb.xMin(), bb.yMax()-bb.yMin(), bb.zMax()-bb.zMin()) * + osg::Matrix::translate(bb.center()) ); + + traverse(node, nv); + } + + osg::Drawable* mDrawable; + }; + + static void handleSkinnedTriShape(const Nif::NiTriShape *triShape, osg::Group *parentNode, const std::map& boundTextures, int animflags) { osg::ref_ptr geode (new osg::Geode); @@ -1404,21 +1168,13 @@ namespace NifOsg osg::ref_ptr geometry (new osg::Geometry); triShapeToGeometry(triShape, geometry, geode, boundTextures, animflags); - // Note the RigGeometry's UpdateCallback uses the skeleton space bone matrix, so the bone UpdateCallback has to be fired first. - // For this to work properly, all bones used for skinning a RigGeometry need to be created before that RigGeometry. - // All NIFs I've checked seem to conform to this restriction, perhaps Gamebryo update method works similarly. - // If a file violates this assumption, the worst that could happen is the bone position being a frame late. - // If this happens, we should get a warning from the Skeleton's validation update callback on the error log. - osg::ref_ptr rig(new osgAnimation::RigGeometry); + osg::ref_ptr rig(new RigGeometry); rig->setSourceGeometry(geometry); const Nif::NiSkinInstance *skin = triShape->skin.getPtr(); - RigBoundingBoxCallback* callback = new RigBoundingBoxCallback; - rig->setComputeBoundingBoxCallback(callback); - // Assign bone weights - osg::ref_ptr map (new osgAnimation::VertexInfluenceMap); + osg::ref_ptr map (new RigGeometry::InfluenceMap); const Nif::NiSkinData *data = skin->data.getPtr(); const Nif::NodeList &bones = skin->bones; @@ -1426,34 +1182,42 @@ namespace NifOsg { std::string boneName = bones[i].getPtr()->name; - callback->addBoundSphere(boneName, osg::BoundingSphere(data->bones[i].boundSphereCenter, data->bones[i].boundSphereRadius)); - - osgAnimation::VertexInfluence influence; - influence.setName(boneName); + RigGeometry::BoneInfluence influence; const std::vector &weights = data->bones[i].weights; - influence.reserve(weights.size()); + //influence.mWeights.reserve(weights.size()); for(size_t j = 0;j < weights.size();j++) { - osgAnimation::VertexIndexWeight indexWeight = std::make_pair(weights[j].vertex, weights[j].weight); - influence.push_back(indexWeight); + std::pair indexWeight = std::make_pair(weights[j].vertex, weights[j].weight); + influence.mWeights.insert(indexWeight); } + influence.mInvBindMatrix = toMatrix(data->bones[i].trafo); - map->insert(std::make_pair(boneName, influence)); + map->mMap.insert(std::make_pair(boneName, influence)); } rig->setInfluenceMap(map); - // Override default update using cull callback instead for efficiency. - rig->setUpdateCallback(NULL); - rig->setCullCallback(new UpdateRigGeometry); - - osg::ref_ptr trans(new osg::MatrixTransform); - trans->setUpdateCallback(new InvertBoneMatrix()); + rig->setComputeBoundingBoxCallback(new StaticBoundingBoxCallback(geometry->getBound())); geode->addDrawable(rig); - geode->addUpdateCallback(new DirtyBoundCallback); + + // World bounding box callback & node + osg::ref_ptr bbcb = new BoundingBoxCallback; + bbcb->mDrawable = rig; + + osg::ref_ptr geode2 = new osg::Geode; + geode2->addDrawable( new osg::ShapeDrawable(new osg::Box) ); + + osg::ref_ptr boundingBoxNode = new osg::MatrixTransform; + boundingBoxNode->addChild( geode2.get() ); + boundingBoxNode->addUpdateCallback( bbcb.get() ); + boundingBoxNode->getOrCreateStateSet()->setAttributeAndModes( + new osg::PolygonMode(osg::PolygonMode::FRONT_AND_BACK, osg::PolygonMode::LINE) ); + boundingBoxNode->getOrCreateStateSet()->setMode( GL_LIGHTING, osg::StateAttribute::OFF ); + // Add a copy, we will alternate between the two copies every other frame using the FrameSwitch // This is so we can set the DataVariance as STATIC, giving a huge performance boost + /* rig->setDataVariance(osg::Object::STATIC); osg::Geode* geode2 = static_cast(osg::clone(geode.get(), osg::CopyOp::DEEP_COPY_NODES| osg::CopyOp::DEEP_COPY_DRAWABLES)); @@ -1463,7 +1227,10 @@ namespace NifOsg frameswitch->addChild(geode2); trans->addChild(frameswitch); - parentNode->addChild(trans); + */ + + parentNode->addChild(geode); + parentNode->addChild(boundingBoxNode); } diff --git a/components/nifosg/riggeometry.cpp b/components/nifosg/riggeometry.cpp new file mode 100644 index 000000000..8283caa23 --- /dev/null +++ b/components/nifosg/riggeometry.cpp @@ -0,0 +1,201 @@ +#include "riggeometry.hpp" + +#include +#include + +#include + +#include + +#include "skeleton.hpp" + +#include + +namespace NifOsg +{ + +// TODO: make threadsafe for multiple cull threads +class UpdateRigGeometry : public osg::Drawable::CullCallback +{ +public: + UpdateRigGeometry() + { + } + + UpdateRigGeometry(const UpdateRigGeometry& copy, const osg::CopyOp& copyop) + : osg::Drawable::CullCallback(copy, copyop) + { + } + + META_Object(NifOsg, UpdateRigGeometry) + + virtual bool cull(osg::NodeVisitor* nv, osg::Drawable* drw, osg::State*) const + { + RigGeometry* geom = static_cast(drw); + geom->update(nv); + return false; + } +}; + +RigGeometry::RigGeometry() +{ + setCullCallback(new UpdateRigGeometry); + setSupportsDisplayList(false); +} + +RigGeometry::RigGeometry(const RigGeometry ©, const osg::CopyOp ©op) + : osg::Geometry(copy, copyop) + , mInfluenceMap(copy.mInfluenceMap) + , mSourceGeometry(copy.mSourceGeometry) +{ + //setVertexArray(dynamic_cast(from.getVertexArray()->clone(osg::CopyOp::DEEP_COPY_ALL))); + //setNormalArray(dynamic_cast(from.getNormalArray()->clone(osg::CopyOp::DEEP_COPY_ALL)), osg::Array::BIND_PER_VERTEX); +} + +void RigGeometry::setSourceGeometry(osg::ref_ptr sourceGeometry) +{ + mSourceGeometry = sourceGeometry; + + osg::Geometry& from = *sourceGeometry; + + if (from.getStateSet()) + setStateSet(from.getStateSet()); + + // copy over primitive sets. + getPrimitiveSetList() = from.getPrimitiveSetList(); + + if (from.getColorArray()) + setColorArray(from.getColorArray()); + + if (from.getSecondaryColorArray()) + setSecondaryColorArray(from.getSecondaryColorArray()); + + if (from.getFogCoordArray()) + setFogCoordArray(from.getFogCoordArray()); + + for(unsigned int ti=0;ti(from.getVertexArray()->clone(osg::CopyOp::DEEP_COPY_ALL))); + setNormalArray(dynamic_cast(from.getNormalArray()->clone(osg::CopyOp::DEEP_COPY_ALL)), osg::Array::BIND_PER_VERTEX); +} + +bool RigGeometry::initFromParentSkeleton(osg::NodeVisitor* nv) +{ + const osg::NodePath& path = nv->getNodePath(); + for (osg::NodePath::const_reverse_iterator it = path.rbegin(); it != path.rend(); ++it) + { + osg::Node* node = *it; + if (Skeleton* skel = dynamic_cast(node)) + { + mSkeleton = skel; + break; + } + } + + if (!mSkeleton) + { + std::cerr << "A RigGeometry did not find its parent skeleton" << std::endl; + return false; + } + + // geometryToSkel = nv->getNodePath()... + + if (!mInfluenceMap) + { + std::cerr << "No InfluenceMap set on RigGeometry" << std::endl; + return false; + } + + for (std::map::const_iterator it = mInfluenceMap->mMap.begin(); it != mInfluenceMap->mMap.end(); ++it) + { + Bone* b = mSkeleton->getBone(it->first); + if (!b) + { + std::cerr << "RigGeometry did not find bone " << it->first << std::endl; + } + + mResolvedInfluenceMap[b] = it->second; + } + return true; +} + +void RigGeometry::update(osg::NodeVisitor* nv) +{ + if (!mSkeleton) + { + if (!initFromParentSkeleton(nv)) + return; + } + + mSkeleton->updateBoneMatrices(); + + osg::NodePath path; + bool foundSkel = false; + for (osg::NodePath::const_iterator it = nv->getNodePath().begin(); it != nv->getNodePath().end(); ++it) + { + if (!foundSkel) + { + if (*it == mSkeleton) + foundSkel = true; + } + else + path.push_back(*it); + } + osg::Matrix geomToSkel = osg::computeWorldToLocal(path); + + // skinning + osg::Vec3Array* positionSrc = static_cast(mSourceGeometry->getVertexArray()); + osg::Vec3Array* normalSrc = static_cast(mSourceGeometry->getNormalArray()); + + osg::Vec3Array* positionDst = static_cast(getVertexArray()); + osg::Vec3Array* normalDst = static_cast(getNormalArray()); + + for (unsigned int i=0; isize(); ++i) + (*positionDst)[i] = osg::Vec3f(0,0,0); + for (unsigned int i=0; isize(); ++i) + (*normalDst)[i] = osg::Vec3f(0,0,0); + + for (ResolvedInfluenceMap::const_iterator it = mResolvedInfluenceMap.begin(); it != mResolvedInfluenceMap.end(); ++it) + { + const BoneInfluence& bi = it->second; + Bone* bone = it->first; + + // Here we could cache the (weighted) matrix for each combination of bone weights + + osg::Matrixf finalMatrix = bi.mInvBindMatrix * bone->mMatrixInSkeletonSpace * geomToSkel; + + for (std::map::const_iterator weightIt = bi.mWeights.begin(); weightIt != bi.mWeights.end(); ++weightIt) + { + short vertex = weightIt->first; + float weight = weightIt->second; + + osg::Vec3f a = (*positionSrc)[vertex]; + + (*positionDst)[vertex] += finalMatrix.preMult(a) * weight; + (*normalDst)[vertex] += osg::Matrix::transform3x3((*normalSrc)[vertex], finalMatrix) * weight; + } + } + + positionDst->dirty(); + normalDst->dirty(); +} + +void RigGeometry::setInfluenceMap(osg::ref_ptr influenceMap) +{ + mInfluenceMap = influenceMap; +} + + +} diff --git a/components/nifosg/riggeometry.hpp b/components/nifosg/riggeometry.hpp new file mode 100644 index 000000000..7c8ea83bc --- /dev/null +++ b/components/nifosg/riggeometry.hpp @@ -0,0 +1,56 @@ +#ifndef OPENMW_COMPONENTS_NIFOSG_RIGGEOMETRY_H +#define OPENMW_COMPONENTS_NIFOSG_RIGGEOMETRY_H + +#include +#include + +namespace NifOsg +{ + + class Skeleton; + class Bone; + + class RigGeometry : public osg::Geometry + { + public: + RigGeometry(); + RigGeometry(const RigGeometry& copy, const osg::CopyOp& copyop); + + META_Object(NifOsg, RigGeometry) + + struct BoneInfluence + { + osg::Matrixf mInvBindMatrix; + // + std::map mWeights; + }; + + + struct InfluenceMap : public osg::Referenced + { + std::map mMap; + }; + + void setInfluenceMap(osg::ref_ptr influenceMap); + + void setSourceGeometry(osg::ref_ptr sourceGeom); + + // Called automatically by our CullCallback + void update(osg::NodeVisitor* nv); + + + private: + osg::ref_ptr mSourceGeometry; + osg::ref_ptr mSkeleton; + + osg::ref_ptr mInfluenceMap; + + typedef std::map ResolvedInfluenceMap; + ResolvedInfluenceMap mResolvedInfluenceMap; + + bool initFromParentSkeleton(osg::NodeVisitor* nv); + }; + +} + +#endif diff --git a/components/nifosg/skeleton.cpp b/components/nifosg/skeleton.cpp new file mode 100644 index 000000000..26c6e80b3 --- /dev/null +++ b/components/nifosg/skeleton.cpp @@ -0,0 +1,148 @@ +#include "skeleton.hpp" + +#include +#include + +#include + +namespace NifOsg +{ + +class InitBoneCacheVisitor : public osg::NodeVisitor +{ +public: + InitBoneCacheVisitor(std::map >& cache) + : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) + , mCache(cache) + { + } + + void apply(osg::Transform &node) + { + osg::MatrixTransform* bone = node.asMatrixTransform(); + if (!bone) + return; + + mCache[bone->getName()] = std::make_pair(getNodePath(), bone); + + traverse(node); + } +private: + std::map >& mCache; +}; + +Skeleton::Skeleton() + : mBoneCacheInit(false) + , mNeedToUpdateBoneMatrices(true) +{ + +} + +Skeleton::Skeleton(const Skeleton ©, const osg::CopyOp ©op) + : mBoneCacheInit(false) + , mNeedToUpdateBoneMatrices(true) +{ + +} + + + +Bone* Skeleton::getBone(const std::string &name) +{ + if (!mBoneCacheInit) + { + InitBoneCacheVisitor visitor(mBoneCache); + accept(visitor); + mBoneCacheInit = true; + } + + BoneCache::iterator found = mBoneCache.find(name); + if (found == mBoneCache.end()) + return NULL; + + // find or insert in the bone hierarchy + + if (!mRootBone.get()) + { + mRootBone.reset(new Bone); + } + + const osg::NodePath& path = found->second.first; + Bone* bone = mRootBone.get(); + for (osg::NodePath::const_iterator it = path.begin(); it != path.end(); ++it) + { + osg::MatrixTransform* matrixTransform = dynamic_cast(*it); + if (!matrixTransform) + continue; + + Bone* child = NULL; + for (unsigned int i=0; imChildren.size(); ++i) + { + if (bone->mChildren[i]->mNode == *it) + { + child = bone->mChildren[i]; + break; + } + } + + if (!child) + { + child = new Bone; + bone->mChildren.push_back(child); + mNeedToUpdateBoneMatrices = true; + } + bone = child; + + bone->mNode = matrixTransform; + } + + return bone; +} + +void Skeleton::updateBoneMatrices() +{ + //if (mNeedToUpdateBoneMatrices) + { + + if (mRootBone.get()) + { + for (unsigned int i=0; imChildren.size(); ++i) + mRootBone->mChildren[i]->update(NULL); + } + else + std::cerr << "no root bone" << std::endl; + + mNeedToUpdateBoneMatrices = false; + } +} + +Bone::Bone() + : mNode(NULL) +{ +} + +Bone::~Bone() +{ + for (unsigned int i=0; igetMatrix() * (*parentMatrixInSkeletonSpace); + else + mMatrixInSkeletonSpace = mNode->getMatrix(); + + for (unsigned int i=0; iupdate(&mMatrixInSkeletonSpace); + } +} + +} diff --git a/components/nifosg/skeleton.hpp b/components/nifosg/skeleton.hpp new file mode 100644 index 000000000..f006ca84b --- /dev/null +++ b/components/nifosg/skeleton.hpp @@ -0,0 +1,58 @@ +#ifndef OPENMW_COMPONENTS_NIFOSG_SKELETON_H +#define OPENMW_COMPONENTS_NIFOSG_SKELETON_H + +#include + +#include + +namespace NifOsg +{ + + // Defines a Bone hierarchy, used for updating of skeleton-space bone matrices. + // To prevent unnecessary updates, only bones that are used for skinning will be added to this hierarchy. + class Bone + { + public: + Bone(); + ~Bone(); + + osg::Matrix mMatrixInSkeletonSpace; + + osg::MatrixTransform* mNode; + + std::vector mChildren; + + void update(const osg::Matrixf* parentMatrixInSkeletonSpace); + + private: + Bone(const Bone&); + void operator=(const Bone&); + }; + + class Skeleton : public osg::Group + { + public: + Skeleton(); + Skeleton(const Skeleton& copy, const osg::CopyOp& copyop); + + Bone* getBone(const std::string& name); + + META_Node(NifOsg, Skeleton) + + void updateBoneMatrices(); + + private: + // The root bone is not a "real" bone, it has no corresponding node in the scene graph. + // As far as the scene graph goes we support multiple root bones. + std::auto_ptr mRootBone; + + typedef std::map > BoneCache; + BoneCache mBoneCache; + bool mBoneCacheInit; + + bool mNeedToUpdateBoneMatrices; + }; + +} + +#endif From c53a56ed6eac74704c846af834d597997493cfaa Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 21 Apr 2015 16:10:11 +0200 Subject: [PATCH 0985/3725] clear stream errors before attempting the read --- apps/openmw/mwsound/ffmpeg_decoder.cpp | 4 +++- extern/osg-ffmpeg-videoplayer/videostate.cpp | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwsound/ffmpeg_decoder.cpp b/apps/openmw/mwsound/ffmpeg_decoder.cpp index 55607b5b7..6a586e81d 100644 --- a/apps/openmw/mwsound/ffmpeg_decoder.cpp +++ b/apps/openmw/mwsound/ffmpeg_decoder.cpp @@ -31,8 +31,8 @@ int FFmpeg_Decoder::readPacket(void *user_data, uint8_t *buf, int buf_size) try { std::istream& stream = *static_cast(user_data)->mDataStream; - stream.read((char*)buf, buf_size); stream.clear(); + stream.read((char*)buf, buf_size); return stream.gcount(); } catch (std::exception& ) @@ -52,6 +52,8 @@ int64_t FFmpeg_Decoder::seek(void *user_data, int64_t offset, int whence) whence &= ~AVSEEK_FORCE; + stream.clear(); + if(whence == AVSEEK_SIZE) { size_t prev = stream.tellg(); diff --git a/extern/osg-ffmpeg-videoplayer/videostate.cpp b/extern/osg-ffmpeg-videoplayer/videostate.cpp index 6a054d99e..72fc82f86 100644 --- a/extern/osg-ffmpeg-videoplayer/videostate.cpp +++ b/extern/osg-ffmpeg-videoplayer/videostate.cpp @@ -173,8 +173,8 @@ int VideoState::istream_read(void *user_data, uint8_t *buf, int buf_size) try { std::istream& stream = *static_cast(user_data)->stream; - stream.read((char*)buf, buf_size); stream.clear(); + stream.read((char*)buf, buf_size); return stream.gcount(); } catch (std::exception& ) @@ -194,6 +194,8 @@ int64_t VideoState::istream_seek(void *user_data, int64_t offset, int whence) whence &= ~AVSEEK_FORCE; + stream.clear(); + if(whence == AVSEEK_SIZE) { size_t prev = stream.tellg(); From 111e3eb6db5580bc110f83bdfd9852b6244872a6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 21 Apr 2015 18:29:28 +0200 Subject: [PATCH 0986/3725] Slightly improve bounding box for skinned meshes --- components/nifosg/nifloader.cpp | 36 ++++++++++++------------------- components/nifosg/riggeometry.cpp | 6 +----- 2 files changed, 15 insertions(+), 27 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index f0bb538f2..eb78a0632 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -1196,28 +1196,24 @@ namespace NifOsg } rig->setInfluenceMap(map); - rig->setComputeBoundingBoxCallback(new StaticBoundingBoxCallback(geometry->getBound())); + // Compute the bounding box + osg::BoundingBox boundingBox; - geode->addDrawable(rig); - - // World bounding box callback & node - osg::ref_ptr bbcb = new BoundingBoxCallback; - bbcb->mDrawable = rig; - - osg::ref_ptr geode2 = new osg::Geode; - geode2->addDrawable( new osg::ShapeDrawable(new osg::Box) ); - - osg::ref_ptr boundingBoxNode = new osg::MatrixTransform; - boundingBoxNode->addChild( geode2.get() ); - boundingBoxNode->addUpdateCallback( bbcb.get() ); - boundingBoxNode->getOrCreateStateSet()->setAttributeAndModes( - new osg::PolygonMode(osg::PolygonMode::FRONT_AND_BACK, osg::PolygonMode::LINE) ); - boundingBoxNode->getOrCreateStateSet()->setMode( GL_LIGHTING, osg::StateAttribute::OFF ); + osg::Matrix worldTrans = getWorldTransform(triShape); + for(size_t i = 0;i < bones.length();i++) + { + osg::BoundingSphere boneSphere (data->bones[i].boundSphereCenter, data->bones[i].boundSphereRadius); + osg::Matrix boneWorldTrans(getWorldTransform(bones[i].getPtr())); + osg::Matrix mat = boneWorldTrans * worldTrans.inverse(worldTrans); + SceneUtil::transformBoundingSphere(mat, boneSphere); + boundingBox.expandBy(boneSphere); + } + rig->setComputeBoundingBoxCallback(new StaticBoundingBoxCallback(boundingBox)); + geode->addDrawable(rig); // Add a copy, we will alternate between the two copies every other frame using the FrameSwitch // This is so we can set the DataVariance as STATIC, giving a huge performance boost - /* rig->setDataVariance(osg::Object::STATIC); osg::Geode* geode2 = static_cast(osg::clone(geode.get(), osg::CopyOp::DEEP_COPY_NODES| osg::CopyOp::DEEP_COPY_DRAWABLES)); @@ -1226,11 +1222,7 @@ namespace NifOsg frameswitch->addChild(geode); frameswitch->addChild(geode2); - trans->addChild(frameswitch); - */ - - parentNode->addChild(geode); - parentNode->addChild(boundingBoxNode); + parentNode->addChild(frameswitch); } diff --git a/components/nifosg/riggeometry.cpp b/components/nifosg/riggeometry.cpp index 8283caa23..37fee1f51 100644 --- a/components/nifosg/riggeometry.cpp +++ b/components/nifosg/riggeometry.cpp @@ -46,10 +46,8 @@ RigGeometry::RigGeometry() RigGeometry::RigGeometry(const RigGeometry ©, const osg::CopyOp ©op) : osg::Geometry(copy, copyop) , mInfluenceMap(copy.mInfluenceMap) - , mSourceGeometry(copy.mSourceGeometry) { - //setVertexArray(dynamic_cast(from.getVertexArray()->clone(osg::CopyOp::DEEP_COPY_ALL))); - //setNormalArray(dynamic_cast(from.getNormalArray()->clone(osg::CopyOp::DEEP_COPY_ALL)), osg::Array::BIND_PER_VERTEX); + setSourceGeometry(copy.mSourceGeometry); } void RigGeometry::setSourceGeometry(osg::ref_ptr sourceGeometry) @@ -110,8 +108,6 @@ bool RigGeometry::initFromParentSkeleton(osg::NodeVisitor* nv) return false; } - // geometryToSkel = nv->getNodePath()... - if (!mInfluenceMap) { std::cerr << "No InfluenceMap set on RigGeometry" << std::endl; From bd88758962628219f1912a12bd96b52f423e1028 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 21 Apr 2015 18:52:13 +0200 Subject: [PATCH 0987/3725] Use the new skinning system in OpenMW --- components/nifosg/skeleton.cpp | 3 +- components/sceneutil/attach.cpp | 136 ++++--------------------------- components/sceneutil/visitor.hpp | 9 +- 3 files changed, 24 insertions(+), 124 deletions(-) diff --git a/components/nifosg/skeleton.cpp b/components/nifosg/skeleton.cpp index 26c6e80b3..2e00eb76e 100644 --- a/components/nifosg/skeleton.cpp +++ b/components/nifosg/skeleton.cpp @@ -39,7 +39,8 @@ Skeleton::Skeleton() } Skeleton::Skeleton(const Skeleton ©, const osg::CopyOp ©op) - : mBoneCacheInit(false) + : osg::Group(copy, copyop) + , mBoneCacheInit(false) , mNeedToUpdateBoneMatrices(true) { diff --git a/components/sceneutil/attach.cpp b/components/sceneutil/attach.cpp index 26185eb3e..b88bddc8d 100644 --- a/components/sceneutil/attach.cpp +++ b/components/sceneutil/attach.cpp @@ -8,155 +8,55 @@ #include #include #include - -#include -#include +#include #include +#include + #include "visitor.hpp" namespace SceneUtil { - class NodeMapVisitor : public osg::NodeVisitor - { - public: - NodeMapVisitor() : osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {} - - void apply(osg::MatrixTransform& trans) - { - mMap[trans.getName()] = &trans; - traverse(trans); - } - - typedef std::map > NodeMap; - - const NodeMap& getNodeMap() const - { - return mMap; - } - - private: - NodeMap mMap; - }; - - /// Copy the matrix of a "source" node to a "dest" node (the node that the callback is attached to). - /// Must be set on a MatrixTransform. - class CopyController : public osg::NodeCallback - { - public: - CopyController(osg::MatrixTransform* copyFrom) - : mCopyFrom(copyFrom) - { - } - CopyController(const CopyController& copy, const osg::CopyOp& copyop) - : osg::NodeCallback(copy, copyop) - , mCopyFrom(copy.mCopyFrom) - { - } - CopyController() - : mCopyFrom(NULL) - { - } - - virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) - { - osgAnimation::Bone* bone = static_cast(node); - - if (mCopyFrom) - { - bone->setMatrix(mCopyFrom->getMatrix()); - } - - traverse(node, nv); - } - - private: - const osg::MatrixTransform* mCopyFrom; - }; - - class AddCopyControllerVisitor : public osg::NodeVisitor + class CopyRigVisitor : public osg::NodeVisitor { public: - AddCopyControllerVisitor(const NodeMapVisitor::NodeMap& boneMap) - : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) - , mNodeMap(boneMap) - { - } - - virtual void apply(osg::MatrixTransform &node) - { - if (osgAnimation::Bone* bone = dynamic_cast(&node)) - { - NodeMapVisitor::NodeMap::const_iterator found = mNodeMap.find(bone->getName()); - if (found != mNodeMap.end()) - { - // add the CopyController at position 0 so it's executed before UpdateBone - osg::ref_ptr old = bone->getUpdateCallback(); - bone->setUpdateCallback(new CopyController(found->second.get())); - bone->addUpdateCallback(old); - } - } - traverse(node); - } - - private: - const NodeMapVisitor::NodeMap& mNodeMap; - }; - - // FIXME: would be more efficient to copy only the wanted nodes instead of deleting unwanted ones later - // copying is kinda cheap though, so don't bother for now - class FilterVisitor : public osg::NodeVisitor - { - public: - FilterVisitor(const std::string& filter) + CopyRigVisitor(osg::ref_ptr parent, const std::string& filter) : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) + , mParent(parent) , mFilter(Misc::StringUtils::lowerCase(filter)) { } - virtual void apply(osg::Geode &node) + virtual void apply(osg::Node& node) { std::string lowerName = Misc::StringUtils::lowerCase(node.getName()); - if (lowerName.find(mFilter) == std::string::npos) + if (lowerName.find(mFilter) != std::string::npos) { - mToRemove.push_back(&node); - } - } - - void removeFilteredParts() - { - for (std::vector::iterator it = mToRemove.begin(); it != mToRemove.end(); ++it) - { - osg::Geode* geode = *it; - geode->getParent(0)->removeChild(geode); + mParent->addChild(&node); } + else + traverse(node); } private: - std::vector mToRemove; + osg::ref_ptr mParent; std::string mFilter; }; osg::ref_ptr attach(osg::ref_ptr toAttach, osg::Node *master, const std::string &filter, const std::string &attachNode) { - if (osgAnimation::Skeleton* skel = dynamic_cast(toAttach.get())) + if (dynamic_cast(toAttach.get())) { - NodeMapVisitor nodeMapVisitor; - master->accept(nodeMapVisitor); + osg::ref_ptr handle = new osg::Group; - // would be more efficient if we could attach the RigGeometry directly to the master skeleton, but currently not possible - // due to a difference in binding pose of the two skeletons - AddCopyControllerVisitor visitor(nodeMapVisitor.getNodeMap()); - toAttach->accept(visitor); + CopyRigVisitor copyVisitor(handle, filter); + toAttach->accept(copyVisitor); - FilterVisitor filterVisitor(filter); - toAttach->accept(filterVisitor); - filterVisitor.removeFilteredParts(); + master->asGroup()->addChild(handle); - master->asGroup()->addChild(skel); - return skel; + return handle; } else { diff --git a/components/sceneutil/visitor.hpp b/components/sceneutil/visitor.hpp index d26f95116..6bb8b2e35 100644 --- a/components/sceneutil/visitor.hpp +++ b/components/sceneutil/visitor.hpp @@ -17,15 +17,14 @@ namespace SceneUtil { } - virtual void apply(osg::Node &node) + virtual void apply(osg::Group& group) { - osg::Group* group = node.asGroup(); - if (group && node.getName() == mNameToFind) + if (group.getName() == mNameToFind) { - mFoundNode = group; + mFoundNode = &group; return; } - traverse(node); + traverse(group); } std::string mNameToFind; From 9246a668b9932cb3ebd217799c72430b7a3aae5a Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 21 Apr 2015 20:22:32 +0200 Subject: [PATCH 0988/3725] Skeleton update fix --- components/nifosg/riggeometry.cpp | 2 +- components/nifosg/skeleton.cpp | 12 +++++++++--- components/nifosg/skeleton.hpp | 4 +++- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/components/nifosg/riggeometry.cpp b/components/nifosg/riggeometry.cpp index 37fee1f51..0217a7ac0 100644 --- a/components/nifosg/riggeometry.cpp +++ b/components/nifosg/riggeometry.cpp @@ -135,7 +135,7 @@ void RigGeometry::update(osg::NodeVisitor* nv) return; } - mSkeleton->updateBoneMatrices(); + mSkeleton->updateBoneMatrices(nv); osg::NodePath path; bool foundSkel = false; diff --git a/components/nifosg/skeleton.cpp b/components/nifosg/skeleton.cpp index 2e00eb76e..b9d113d34 100644 --- a/components/nifosg/skeleton.cpp +++ b/components/nifosg/skeleton.cpp @@ -34,6 +34,7 @@ private: Skeleton::Skeleton() : mBoneCacheInit(false) , mNeedToUpdateBoneMatrices(true) + , mLastFrameNumber(0) { } @@ -42,6 +43,7 @@ Skeleton::Skeleton(const Skeleton ©, const osg::CopyOp ©op) : osg::Group(copy, copyop) , mBoneCacheInit(false) , mNeedToUpdateBoneMatrices(true) + , mLastFrameNumber(0) { } @@ -100,11 +102,15 @@ Bone* Skeleton::getBone(const std::string &name) return bone; } -void Skeleton::updateBoneMatrices() +void Skeleton::updateBoneMatrices(osg::NodeVisitor* nv) { - //if (mNeedToUpdateBoneMatrices) - { + if (nv->getFrameStamp()->getFrameNumber() != mLastFrameNumber) + mNeedToUpdateBoneMatrices = true; + + mLastFrameNumber = nv->getFrameStamp()->getFrameNumber(); + if (mNeedToUpdateBoneMatrices) + { if (mRootBone.get()) { for (unsigned int i=0; imChildren.size(); ++i) diff --git a/components/nifosg/skeleton.hpp b/components/nifosg/skeleton.hpp index f006ca84b..5344f9f5d 100644 --- a/components/nifosg/skeleton.hpp +++ b/components/nifosg/skeleton.hpp @@ -39,7 +39,7 @@ namespace NifOsg META_Node(NifOsg, Skeleton) - void updateBoneMatrices(); + void updateBoneMatrices(osg::NodeVisitor* nv); private: // The root bone is not a "real" bone, it has no corresponding node in the scene graph. @@ -51,6 +51,8 @@ namespace NifOsg bool mBoneCacheInit; bool mNeedToUpdateBoneMatrices; + + unsigned int mLastFrameNumber; }; } From eaa4316ff86589e5c01ccdc2b4820cf3dfd150e5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 21 Apr 2015 20:30:48 +0200 Subject: [PATCH 0989/3725] Move skinning code to SceneUtil --- components/CMakeLists.txt | 4 ++-- components/nifosg/nifloader.cpp | 14 +++++++------- components/sceneutil/attach.cpp | 4 ++-- components/{nifosg => sceneutil}/riggeometry.cpp | 2 +- components/{nifosg => sceneutil}/riggeometry.hpp | 2 +- components/{nifosg => sceneutil}/skeleton.cpp | 2 +- components/{nifosg => sceneutil}/skeleton.hpp | 2 +- 7 files changed, 15 insertions(+), 15 deletions(-) rename components/{nifosg => sceneutil}/riggeometry.cpp (99%) rename components/{nifosg => sceneutil}/riggeometry.hpp (98%) rename components/{nifosg => sceneutil}/skeleton.cpp (99%) rename components/{nifosg => sceneutil}/skeleton.hpp (98%) diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index b49beea0b..75f6756f8 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -39,7 +39,7 @@ add_component_dir (resource ) add_component_dir (sceneutil - clone attach lightmanager visitor util statesetupdater controller + clone attach lightmanager visitor util statesetupdater controller skeleton riggeometry ) add_component_dir (nif @@ -47,7 +47,7 @@ add_component_dir (nif ) add_component_dir (nifosg - nifloader controller particle userdata skeleton riggeometry + nifloader controller particle userdata ) #add_component_dir (nifcache diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index eb78a0632..301c487da 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -41,11 +41,11 @@ #include #include +#include +#include #include "particle.hpp" #include "userdata.hpp" -#include "skeleton.hpp" -#include "riggeometry.hpp" namespace { @@ -279,7 +279,7 @@ namespace for (osg::NodePath::iterator it = path.begin(); it != path.end(); ++it) { - if (dynamic_cast(*it)) + if (dynamic_cast(*it)) { path.erase(path.begin(), it+1); // the bone's transform in skeleton space @@ -535,7 +535,7 @@ namespace NifOsg osg::ref_ptr textkeys (new TextKeyMapHolder); - osg::ref_ptr skel = new Skeleton; + osg::ref_ptr skel = new SceneUtil::Skeleton; handleNode(nifNode, skel, textureManager, true, std::map(), 0, 0, false, &textkeys->mTextKeys); skel->getOrCreateUserDataContainer()->addUserObject(textkeys); @@ -1168,13 +1168,13 @@ namespace NifOsg osg::ref_ptr geometry (new osg::Geometry); triShapeToGeometry(triShape, geometry, geode, boundTextures, animflags); - osg::ref_ptr rig(new RigGeometry); + osg::ref_ptr rig(new SceneUtil::RigGeometry); rig->setSourceGeometry(geometry); const Nif::NiSkinInstance *skin = triShape->skin.getPtr(); // Assign bone weights - osg::ref_ptr map (new RigGeometry::InfluenceMap); + osg::ref_ptr map (new SceneUtil::RigGeometry::InfluenceMap); const Nif::NiSkinData *data = skin->data.getPtr(); const Nif::NodeList &bones = skin->bones; @@ -1182,7 +1182,7 @@ namespace NifOsg { std::string boneName = bones[i].getPtr()->name; - RigGeometry::BoneInfluence influence; + SceneUtil::RigGeometry::BoneInfluence influence; const std::vector &weights = data->bones[i].weights; //influence.mWeights.reserve(weights.size()); for(size_t j = 0;j < weights.size();j++) diff --git a/components/sceneutil/attach.cpp b/components/sceneutil/attach.cpp index b88bddc8d..9f9d63619 100644 --- a/components/sceneutil/attach.cpp +++ b/components/sceneutil/attach.cpp @@ -12,7 +12,7 @@ #include -#include +#include #include "visitor.hpp" @@ -47,7 +47,7 @@ namespace SceneUtil osg::ref_ptr attach(osg::ref_ptr toAttach, osg::Node *master, const std::string &filter, const std::string &attachNode) { - if (dynamic_cast(toAttach.get())) + if (dynamic_cast(toAttach.get())) { osg::ref_ptr handle = new osg::Group; diff --git a/components/nifosg/riggeometry.cpp b/components/sceneutil/riggeometry.cpp similarity index 99% rename from components/nifosg/riggeometry.cpp rename to components/sceneutil/riggeometry.cpp index 0217a7ac0..00f80c829 100644 --- a/components/nifosg/riggeometry.cpp +++ b/components/sceneutil/riggeometry.cpp @@ -11,7 +11,7 @@ #include -namespace NifOsg +namespace SceneUtil { // TODO: make threadsafe for multiple cull threads diff --git a/components/nifosg/riggeometry.hpp b/components/sceneutil/riggeometry.hpp similarity index 98% rename from components/nifosg/riggeometry.hpp rename to components/sceneutil/riggeometry.hpp index 7c8ea83bc..e99bc757e 100644 --- a/components/nifosg/riggeometry.hpp +++ b/components/sceneutil/riggeometry.hpp @@ -4,7 +4,7 @@ #include #include -namespace NifOsg +namespace SceneUtil { class Skeleton; diff --git a/components/nifosg/skeleton.cpp b/components/sceneutil/skeleton.cpp similarity index 99% rename from components/nifosg/skeleton.cpp rename to components/sceneutil/skeleton.cpp index b9d113d34..c1ab36136 100644 --- a/components/nifosg/skeleton.cpp +++ b/components/sceneutil/skeleton.cpp @@ -5,7 +5,7 @@ #include -namespace NifOsg +namespace SceneUtil { class InitBoneCacheVisitor : public osg::NodeVisitor diff --git a/components/nifosg/skeleton.hpp b/components/sceneutil/skeleton.hpp similarity index 98% rename from components/nifosg/skeleton.hpp rename to components/sceneutil/skeleton.hpp index 5344f9f5d..c241844f1 100644 --- a/components/nifosg/skeleton.hpp +++ b/components/sceneutil/skeleton.hpp @@ -5,7 +5,7 @@ #include -namespace NifOsg +namespace SceneUtil { // Defines a Bone hierarchy, used for updating of skeleton-space bone matrices. From 10644544ab22c433eea6f5e9dcad6ffa862193b8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 21 Apr 2015 20:31:20 +0200 Subject: [PATCH 0990/3725] Dead code removal --- components/nifosg/nifloader.cpp | 41 --------------------------------- 1 file changed, 41 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 301c487da..b28412cb6 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -253,47 +253,6 @@ namespace } }; - // NodeCallback used to set the inverse of the parent bone's matrix in skeleton space - // on the MatrixTransform that the NodeCallback is attached to. This is used so we can - // attach skinned meshes to their actual parent node, while still having the skinning - // work in skeleton space as expected. - // Must be set on a MatrixTransform. - class InvertBoneMatrix : public osg::NodeCallback - { - public: - InvertBoneMatrix() {} - - InvertBoneMatrix(const InvertBoneMatrix& copy, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY) - : osg::Object(copy, copyop), osg::NodeCallback(copy, copyop) {} - - META_Object(NifOsg, InvertBoneMatrix) - - void operator()(osg::Node* node, osg::NodeVisitor* nv) - { - if (nv && nv->getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR) - { - osg::NodePath path = nv->getNodePath(); - path.pop_back(); - - osg::MatrixTransform* trans = dynamic_cast(node); - - for (osg::NodePath::iterator it = path.begin(); it != path.end(); ++it) - { - if (dynamic_cast(*it)) - { - path.erase(path.begin(), it+1); - // the bone's transform in skeleton space - osg::Matrix boneMat = osg::computeLocalToWorld( path ); - trans->setMatrix(osg::Matrix::inverse(boneMat)); - break; - } - } - } - traverse(node,nv); - } - }; - - // NodeVisitor that adds keyframe controllers to an existing scene graph, used when loading .kf files /* class LoadKfVisitor : public osg::NodeVisitor From 102eadf91c103867a6c86f8bb85599cd2edc1fb4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 21 Apr 2015 20:42:50 +0200 Subject: [PATCH 0991/3725] Add some comments --- components/sceneutil/riggeometry.hpp | 4 +++- components/sceneutil/skeleton.hpp | 14 ++++++++++---- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/components/sceneutil/riggeometry.hpp b/components/sceneutil/riggeometry.hpp index e99bc757e..70f2c6e7d 100644 --- a/components/sceneutil/riggeometry.hpp +++ b/components/sceneutil/riggeometry.hpp @@ -10,6 +10,9 @@ namespace SceneUtil class Skeleton; class Bone; + /// @brief Mesh skinning implementation. + /// @note A RigGeometry may be attached directly to a Skeleton, or somewhere below a Skeleton. + /// Note though that the RigGeometry ignores any transforms below the Skeleton, so the attachment point is not that important. class RigGeometry : public osg::Geometry { public: @@ -25,7 +28,6 @@ namespace SceneUtil std::map mWeights; }; - struct InfluenceMap : public osg::Referenced { std::map mMap; diff --git a/components/sceneutil/skeleton.hpp b/components/sceneutil/skeleton.hpp index c241844f1..acb9e6136 100644 --- a/components/sceneutil/skeleton.hpp +++ b/components/sceneutil/skeleton.hpp @@ -8,8 +8,8 @@ namespace SceneUtil { - // Defines a Bone hierarchy, used for updating of skeleton-space bone matrices. - // To prevent unnecessary updates, only bones that are used for skinning will be added to this hierarchy. + /// @brief Defines a Bone hierarchy, used for updating of skeleton-space bone matrices. + /// @note To prevent unnecessary updates, only bones that are used for skinning will be added to this hierarchy. class Bone { public: @@ -22,6 +22,7 @@ namespace SceneUtil std::vector mChildren; + /// Update the skeleton-space matrix of this bone and all its children. void update(const osg::Matrixf* parentMatrixInSkeletonSpace); private: @@ -29,16 +30,21 @@ namespace SceneUtil void operator=(const Bone&); }; + /// @brief Handles the bone matrices for any number of child RigGeometries. + /// @par Bones should be created as osg::MatrixTransform children of the skeleton. + /// To be a referenced by a RigGeometry, a bone needs to have a unique name. class Skeleton : public osg::Group { public: Skeleton(); Skeleton(const Skeleton& copy, const osg::CopyOp& copyop); - Bone* getBone(const std::string& name); - META_Node(NifOsg, Skeleton) + /// Retrieve a bone by name. + Bone* getBone(const std::string& name); + + /// Request an update of bone matrices. May be a no-op if already updated in this frame. void updateBoneMatrices(osg::NodeVisitor* nv); private: From 28643660d3dbfb10c3c8613711606652f31b4263 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 21 Apr 2015 20:56:16 +0200 Subject: [PATCH 0992/3725] Change triangle indices to unsigned --- components/nif/data.cpp | 2 +- components/nif/data.hpp | 4 ++-- components/nif/nifstream.cpp | 4 ++-- components/nif/nifstream.hpp | 2 +- components/nifosg/nifloader.cpp | 2 +- components/sceneutil/riggeometry.cpp | 4 ++-- components/sceneutil/riggeometry.hpp | 2 +- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/components/nif/data.cpp b/components/nif/data.cpp index 3a06e4006..fc0631b84 100644 --- a/components/nif/data.cpp +++ b/components/nif/data.cpp @@ -71,7 +71,7 @@ void NiTriShapeData::read(NIFStream *nif) // We have three times as many vertices as triangles, so this // is always equal to tris*3. int cnt = nif->getInt(); - nif->getShorts(triangles, cnt); + nif->getUShorts(triangles, cnt); // Read the match list, which lists the vertices that are equal to // vertices. We don't actually need need this for anything, so diff --git a/components/nif/data.hpp b/components/nif/data.hpp index 1b4d02f26..63dc42ade 100644 --- a/components/nif/data.hpp +++ b/components/nif/data.hpp @@ -48,7 +48,7 @@ class NiTriShapeData : public ShapeData { public: // Triangles, three vertex indices per triangle - std::vector triangles; + std::vector triangles; void read(NIFStream *nif); }; @@ -144,7 +144,7 @@ class NiSkinData : public Record public: struct VertWeight { - short vertex; + unsigned short vertex; float weight; }; diff --git a/components/nif/nifstream.cpp b/components/nif/nifstream.cpp index 628541933..d0fc9bab0 100644 --- a/components/nif/nifstream.cpp +++ b/components/nif/nifstream.cpp @@ -103,11 +103,11 @@ std::string NIFStream::getVersionString() return result; } -void NIFStream::getShorts(std::vector &vec, size_t size) +void NIFStream::getUShorts(std::vector &vec, size_t size) { vec.resize(size); for(size_t i = 0;i < vec.size();i++) - vec[i] = getShort(); + vec[i] = getUShort(); } void NIFStream::getFloats(std::vector &vec, size_t size) { diff --git a/components/nif/nifstream.hpp b/components/nif/nifstream.hpp index b732c83af..45733f48f 100644 --- a/components/nif/nifstream.hpp +++ b/components/nif/nifstream.hpp @@ -59,7 +59,7 @@ public: ///This is special since the version string doesn't start with a number, and ends with "\n" std::string getVersionString(); - void getShorts(std::vector &vec, size_t size); + void getUShorts(std::vector &vec, size_t size); void getFloats(std::vector &vec, size_t size); void getVector2s(std::vector &vec, size_t size); void getVector3s(std::vector &vec, size_t size); diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index b28412cb6..f7f6af0ae 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -1146,7 +1146,7 @@ namespace NifOsg //influence.mWeights.reserve(weights.size()); for(size_t j = 0;j < weights.size();j++) { - std::pair indexWeight = std::make_pair(weights[j].vertex, weights[j].weight); + std::pair indexWeight = std::make_pair(weights[j].vertex, weights[j].weight); influence.mWeights.insert(indexWeight); } influence.mInvBindMatrix = toMatrix(data->bones[i].trafo); diff --git a/components/sceneutil/riggeometry.cpp b/components/sceneutil/riggeometry.cpp index 00f80c829..4d4ea22d2 100644 --- a/components/sceneutil/riggeometry.cpp +++ b/components/sceneutil/riggeometry.cpp @@ -172,9 +172,9 @@ void RigGeometry::update(osg::NodeVisitor* nv) osg::Matrixf finalMatrix = bi.mInvBindMatrix * bone->mMatrixInSkeletonSpace * geomToSkel; - for (std::map::const_iterator weightIt = bi.mWeights.begin(); weightIt != bi.mWeights.end(); ++weightIt) + for (std::map::const_iterator weightIt = bi.mWeights.begin(); weightIt != bi.mWeights.end(); ++weightIt) { - short vertex = weightIt->first; + unsigned short vertex = weightIt->first; float weight = weightIt->second; osg::Vec3f a = (*positionSrc)[vertex]; diff --git a/components/sceneutil/riggeometry.hpp b/components/sceneutil/riggeometry.hpp index 70f2c6e7d..c77ff7c72 100644 --- a/components/sceneutil/riggeometry.hpp +++ b/components/sceneutil/riggeometry.hpp @@ -25,7 +25,7 @@ namespace SceneUtil { osg::Matrixf mInvBindMatrix; // - std::map mWeights; + std::map mWeights; }; struct InfluenceMap : public osg::Referenced From a254877abe7d51df387bee721524028e070dae39 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 21 Apr 2015 22:53:28 +0200 Subject: [PATCH 0993/3725] Clone fix --- components/sceneutil/clone.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/components/sceneutil/clone.cpp b/components/sceneutil/clone.cpp index f124d7de7..eb7e63587 100644 --- a/components/sceneutil/clone.cpp +++ b/components/sceneutil/clone.cpp @@ -6,9 +6,11 @@ #include #include #include -#include + #include +#include + namespace SceneUtil { @@ -45,7 +47,7 @@ namespace SceneUtil { if (const osgParticle::ParticleSystem* partsys = dynamic_cast(drawable)) return operator()(partsys); - if (dynamic_cast(drawable) + if (dynamic_cast(drawable) || dynamic_cast(drawable)) return osg::clone(drawable, osg::CopyOp::DEEP_COPY_DRAWABLES); From 9e177df61b1fe33140db6200328c32d2530e94c0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 21 Apr 2015 23:27:26 +0200 Subject: [PATCH 0994/3725] Add fog, view distance, and far plane culling --- apps/openmw/mwrender/renderingmanager.cpp | 54 +++++++++++++++++++++-- apps/openmw/mwrender/renderingmanager.hpp | 4 +- apps/openmw/mwworld/scene.cpp | 2 +- 3 files changed, 54 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 412d10ba2..b7265533c 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -5,10 +5,13 @@ #include #include #include +#include #include #include +#include + #include #include @@ -26,25 +29,49 @@ namespace MWRender class StateUpdater : public SceneUtil::StateSetUpdater { public: + StateUpdater() + : mFogEnd(0.f) + { + } + virtual void setDefaults(osg::StateSet *stateset) { osg::LightModel* lightModel = new osg::LightModel; stateset->setAttribute(lightModel, osg::StateAttribute::ON); + osg::Fog* fog = new osg::Fog; + fog->setStart(1); + stateset->setAttributeAndModes(fog, osg::StateAttribute::ON); } virtual void apply(osg::StateSet* stateset, osg::NodeVisitor*) { osg::LightModel* lightModel = static_cast(stateset->getAttribute(osg::StateAttribute::LIGHTMODEL)); lightModel->setAmbientIntensity(mAmbientColor); + osg::Fog* fog = static_cast(stateset->getAttribute(osg::StateAttribute::FOG)); + fog->setColor(mFogColor); + fog->setEnd(mFogEnd); + fog->setMode(osg::Fog::LINEAR); } - void setAmbientColor(osg::Vec4f col) + void setAmbientColor(const osg::Vec4f& col) { mAmbientColor = col; } + void setFogColor(const osg::Vec4f& col) + { + mFogColor = col; + } + + void setFogEnd(float end) + { + mFogEnd = end; + } + private: osg::Vec4f mAmbientColor; + osg::Vec4f mFogColor; + float mFogEnd; }; RenderingManager::RenderingManager(osgViewer::Viewer &viewer, osg::ref_ptr rootNode, Resource::ResourceSystem* resourceSystem) @@ -80,16 +107,25 @@ namespace MWRender source->setStateSetModes(*mRootNode->getOrCreateStateSet(), osg::StateAttribute::ON); mStateUpdater = new StateUpdater; - mRootNode->addUpdateCallback(mStateUpdater); + lightRoot->addUpdateCallback(mStateUpdater); + + osg::Camera::CullingMode cullingMode = osg::Camera::DEFAULT_CULLING|osg::Camera::FAR_PLANE_CULLING; // for consistent benchmarks against the ogre branch. remove later - osg::CullStack::CullingMode cullingMode = viewer.getCamera()->getCullingMode(); cullingMode &= ~(osg::CullStack::SMALL_FEATURE_CULLING); + viewer.getCamera()->setCullingMode( cullingMode ); + mViewer.getCamera()->setComputeNearFarMode(osg::Camera::DO_NOT_COMPUTE_NEAR_FAR); + mViewer.getCamera()->setCullingMode(cullingMode); + + mViewDistance = Settings::Manager::getFloat("viewing distance", "Viewing distance"); + double fovy, aspect, zNear, zFar; mViewer.getCamera()->getProjectionMatrixAsPerspective(fovy, aspect, zNear, zFar); fovy = 55.f; + zNear = 5.f; + zFar = mViewDistance; mViewer.getCamera()->setProjectionMatrixAsPerspective(fovy, aspect, zNear, zFar); } @@ -153,9 +189,19 @@ namespace MWRender mSky->setEnabled(enabled); } - void RenderingManager::configureFog(float fogDepth, const osg::Vec4f &colour) + void RenderingManager::configureFog(const ESM::Cell *cell) + { + osg::Vec4f color = SceneUtil::colourFromRGB(cell->mAmbi.mFog); + + configureFog (cell->mAmbi.mFogDensity, color); + } + + void RenderingManager::configureFog(float /* fogDepth */, const osg::Vec4f &colour) { mViewer.getCamera()->setClearColor(colour); + + mStateUpdater->setFogColor(colour); + mStateUpdater->setFogEnd(mViewDistance); } SkyManager* RenderingManager::getSkyManager() diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 61f611a8c..d8744db4a 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -53,7 +53,7 @@ namespace MWRender void setSunColour(const osg::Vec4f& colour); void configureAmbient(const ESM::Cell* cell); - + void configureFog(const ESM::Cell* cell); void configureFog(float fogDepth, const osg::Vec4f& colour); void removeCell(const MWWorld::CellStore* store); @@ -87,6 +87,8 @@ namespace MWRender osg::ref_ptr mStateUpdater; + float mViewDistance; + void operator = (const RenderingManager&); RenderingManager(const RenderingManager&); }; diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index c9fd84ee3..aabe4d6d8 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -511,7 +511,7 @@ namespace MWWorld changePlayerCell(cell, position, true); // adjust fog - //mRendering.configureFog(*mCurrentCell); + mRendering.configureFog(mCurrentCell->getCell()); // Sky system MWBase::Environment::get().getWorld()->adjustSky(); From 26766b8e0a9b9979a64381fa935d01c336f95ab4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 21 Apr 2015 23:35:35 +0200 Subject: [PATCH 0995/3725] Dead code removal --- apps/openmw/engine.cpp | 2 +- apps/openmw/mwgui/windowmanagerimp.cpp | 16 +- apps/openmw/mwgui/windowmanagerimp.hpp | 4 +- apps/openmw/mwrender/debugging.hpp | 3 +- apps/openmw/mwworld/physicssystem.cpp | 5 +- apps/openmw/mwworld/physicssystem.hpp | 7 +- libs/openengine/CMakeLists.txt | 3 +- libs/openengine/ogre/renderer.cpp | 241 ------------------------- libs/openengine/ogre/renderer.hpp | 147 --------------- 9 files changed, 15 insertions(+), 413 deletions(-) delete mode 100644 libs/openengine/ogre/renderer.cpp delete mode 100644 libs/openengine/ogre/renderer.hpp diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index fe6180299..68f4e8225 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -370,7 +370,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) //mEnvironment.setInputManager (input); MWGui::WindowManager* window = new MWGui::WindowManager( - mExtensions, NULL, mCfgMgr.getLogPath().string() + std::string("/"), + mExtensions, mCfgMgr.getLogPath().string() + std::string("/"), mCfgMgr.getCachePath ().string(), mScriptConsoleMode, mTranslationDataStorage, mEncoding, mExportFonts, mFallbackMap); mEnvironment.setWindowManager (window); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 319e1d7ec..4ae610f51 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -24,8 +24,6 @@ #include #include -#include - #include #include @@ -99,12 +97,10 @@ namespace MWGui { WindowManager::WindowManager( - const Compiler::Extensions& extensions, OEngine::Render::OgreRenderer *ogre, - const std::string& logpath, const std::string& cacheDir, bool consoleOnlyScripts, + const Compiler::Extensions& extensions, const std::string& logpath, const std::string& cacheDir, bool consoleOnlyScripts, Translation::Storage& translationDataStorage, ToUTF8::FromType encoding, bool exportFonts, const std::map& fallbackMap) : mConsoleOnlyScripts(consoleOnlyScripts) //, mGuiManager(NULL) - , mRendering(ogre) , mHud(NULL) , mMap(NULL) , mMenu(NULL) @@ -838,7 +834,7 @@ namespace MWGui mMessageBoxManager->onFrame(0.f); MWBase::Environment::get().getInputManager()->update(0, true, false); - mRendering->getWindow()->update(); + //mRendering->getWindow()->update(); } } } @@ -1714,6 +1710,7 @@ namespace MWGui } // Turn off all rendering except for the GUI + /* mRendering->getScene()->clearSpecialCaseRenderQueues(); // SCRQM_INCLUDE with RENDER_QUEUE_OVERLAY does not work? for(int i = 0;i < Ogre::RENDER_QUEUE_MAX;++i) @@ -1722,6 +1719,7 @@ namespace MWGui mRendering->getScene()->addSpecialCaseRenderQueue(i); } mRendering->getScene()->setSpecialCaseRenderQueueMode(Ogre::SceneManager::SCRQM_EXCLUDE); + */ MyGUI::IntSize screenSize = MyGUI::RenderManager::getInstance().getViewSize(); sizeVideo(screenSize.width, screenSize.height); @@ -1741,7 +1739,7 @@ namespace MWGui { MWBase::Environment::get().getInputManager()->update(0, true, false); - mRendering->getWindow()->update(); + //mRendering->getWindow()->update(); } mVideoWidget->stop(); @@ -1750,8 +1748,8 @@ namespace MWGui setCursorVisible(cursorWasVisible); // Restore normal rendering - mRendering->getScene()->clearSpecialCaseRenderQueues(); - mRendering->getScene()->setSpecialCaseRenderQueueMode(Ogre::SceneManager::SCRQM_EXCLUDE); + //mRendering->getScene()->clearSpecialCaseRenderQueues(); + //mRendering->getScene()->setSpecialCaseRenderQueueMode(Ogre::SceneManager::SCRQM_EXCLUDE); mVideoBackground->setVisible(false); } diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 297480d20..ddb9368c5 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -99,8 +99,7 @@ namespace MWGui typedef std::pair Faction; typedef std::vector FactionList; - WindowManager(const Compiler::Extensions& extensions, - OEngine::Render::OgreRenderer *mOgre, const std::string& logpath, + WindowManager(const Compiler::Extensions& extensions, const std::string& logpath, const std::string& cacheDir, bool consoleOnlyScripts, Translation::Storage& translationDataStorage, ToUTF8::FromType encoding, bool exportFonts, const std::map& fallbackMap); virtual ~WindowManager(); @@ -366,7 +365,6 @@ namespace MWGui CustomMarkerCollection mCustomMarkers; OEngine::GUI::MyGUIManager *mGuiManager; - OEngine::Render::OgreRenderer *mRendering; HUD *mHud; MapWindow *mMap; MainMenu *mMenu; diff --git a/apps/openmw/mwrender/debugging.hpp b/apps/openmw/mwrender/debugging.hpp index 39be34cb0..e24331801 100644 --- a/apps/openmw/mwrender/debugging.hpp +++ b/apps/openmw/mwrender/debugging.hpp @@ -2,10 +2,10 @@ #define GAME_RENDER_MWSCENE_H #include -#include #include #include +#include namespace ESM { @@ -29,6 +29,7 @@ namespace Ogre class RaySceneQuery; class Quaternion; class Vector3; + class ManualObject; } namespace MWWorld diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index b8e4a06a8..ae6cce6c7 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -13,7 +13,6 @@ #include #include #include -#include //#include #include @@ -499,8 +498,8 @@ namespace MWWorld }; - PhysicsSystem::PhysicsSystem(OEngine::Render::OgreRenderer &_rend) : - mRender(_rend), mEngine(0), mTimeAccum(0.0f), mWaterEnabled(false), mWaterHeight(0) + PhysicsSystem::PhysicsSystem() : + mEngine(0), mTimeAccum(0.0f), mWaterEnabled(false), mWaterHeight(0) { // Create physics. shapeLoader is deleted by the physic engine //NifBullet::ManualBulletShapeLoader* shapeLoader = new NifBullet::ManualBulletShapeLoader(); diff --git a/apps/openmw/mwworld/physicssystem.hpp b/apps/openmw/mwworld/physicssystem.hpp index c1046aacb..bc61914bc 100644 --- a/apps/openmw/mwworld/physicssystem.hpp +++ b/apps/openmw/mwworld/physicssystem.hpp @@ -12,10 +12,6 @@ namespace OEngine { - namespace Render - { - class OgreRenderer; - } namespace Physic { class PhysicEngine; @@ -31,7 +27,7 @@ namespace MWWorld class PhysicsSystem { public: - PhysicsSystem (OEngine::Render::OgreRenderer &_rend); + PhysicsSystem (); ~PhysicsSystem (); void enableWater(float height); @@ -116,7 +112,6 @@ namespace MWWorld void updateWater(); - OEngine::Render::OgreRenderer &mRender; OEngine::Physic::PhysicEngine* mEngine; std::map handleToMesh; diff --git a/libs/openengine/CMakeLists.txt b/libs/openengine/CMakeLists.txt index eaf92c673..f3622b2ee 100644 --- a/libs/openengine/CMakeLists.txt +++ b/libs/openengine/CMakeLists.txt @@ -1,6 +1,5 @@ set(OENGINE_OGRE - #ogre/renderer.cpp - ogre/lights.cpp + #ogre/lights.cpp ) set(OENGINE_GUI diff --git a/libs/openengine/ogre/renderer.cpp b/libs/openengine/ogre/renderer.cpp deleted file mode 100644 index bdeeeb8c4..000000000 --- a/libs/openengine/ogre/renderer.cpp +++ /dev/null @@ -1,241 +0,0 @@ -#include "renderer.hpp" - -#include - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -#include -#include - -#include -#include - -using namespace Ogre; -using namespace OEngine::Render; - -OgreRenderer::~OgreRenderer() -{ - cleanup(); - restoreWindowGammaRamp(); -} - -void OgreRenderer::cleanup() -{ - if (mWindow) - Ogre::Root::getSingleton().destroyRenderTarget(mWindow); - mWindow = NULL; - - delete mOgreInit; - mOgreInit = NULL; - - // If we don't do this, the desktop resolution is not restored on exit - SDL_SetWindowFullscreen(mSDLWindow, 0); - - SDL_DestroyWindow(mSDLWindow); - mSDLWindow = NULL; -} - -void OgreRenderer::update(float dt) -{ -} - -void OgreRenderer::screenshot(const std::string &file, const std::string& imageFormat) -{ - /* Since Ogre uses narrow character interfaces, it does not support - Unicode paths on Windows. Therefore we had to implement screenshot - saving manually. - */ - namespace bfs = boost::filesystem; - bfs::ofstream out(bfs::path(file), std::ios::binary); - - Ogre::Image image; - - Ogre::PixelFormat pf = mWindow->suggestPixelFormat(); - int w = mWindow->getWidth(); - int h = mWindow->getHeight(); - - image.loadDynamicImage( - OGRE_ALLOC_T(Ogre::uchar, w * h * Ogre::PixelUtil::getNumElemBytes(pf), Ogre::MEMCATEGORY_GENERAL), - w, h, 1, pf, true - ); - mWindow->copyContentsToMemory(image.getPixelBox()); - - Ogre::DataStreamPtr stream = image.encode(imageFormat); - Ogre::MemoryDataStream *mem = dynamic_cast(stream.get()); - if (mem != 0) { // likely - const char *ptr = reinterpret_cast(mem->getCurrentPtr()); - out.write(ptr, mem->size()); - } - else { - char buf[4096]; - size_t size = stream->size(); - while (size > 0) { - size_t chunk = (size > sizeof(buf)) ? sizeof(buf) : size; - stream->read(buf, chunk); - out.write(buf, chunk); - size -= chunk; - } - } -} - -void OgreRenderer::configure(const std::string &logPath, - const std::string& renderSystem, - const std::string& rttMode - ) -{ - mOgreInit = new OgreInit::OgreInit(); - mRoot = mOgreInit->init(logPath + "/ogre.log"); - - RenderSystem* rs = mRoot->getRenderSystemByName(renderSystem); - if (rs == 0) - throw std::runtime_error ("RenderSystem with name " + renderSystem + " not found, make sure the plugins are loaded"); - mRoot->setRenderSystem(rs); - - if (rs->getName().find("OpenGL") != std::string::npos) - rs->setConfigOption ("RTT Preferred Mode", rttMode); -} - -void OgreRenderer::createWindow(const std::string &title, const WindowSettings& settings) -{ - assert(mRoot); - mRoot->initialise(false); - - NameValuePairList params; - params.insert(std::make_pair("title", title)); - params.insert(std::make_pair("FSAA", settings.fsaa)); - params.insert(std::make_pair("vsync", settings.vsync ? "true" : "false")); - - int pos_x = SDL_WINDOWPOS_CENTERED_DISPLAY(settings.screen), - pos_y = SDL_WINDOWPOS_CENTERED_DISPLAY(settings.screen); - - if(settings.fullscreen) - { - pos_x = SDL_WINDOWPOS_UNDEFINED_DISPLAY(settings.screen); - pos_y = SDL_WINDOWPOS_UNDEFINED_DISPLAY(settings.screen); - } - - - // Create an application window with the following settings: - mSDLWindow = SDL_CreateWindow( - "OpenMW", // window title - pos_x, // initial x position - pos_y, // initial y position - settings.window_x, // width, in pixels - settings.window_y, // height, in pixels - SDL_WINDOW_SHOWN - | SDL_WINDOW_RESIZABLE - | (settings.fullscreen ? SDL_WINDOW_FULLSCREEN : 0) - | (settings.window_border ? 0 : SDL_WINDOW_BORDERLESS) - ); - if (mSDLWindow == 0) - throw std::runtime_error("Failed to create window: " + std::string(SDL_GetError())); - - SFO::SDLWindowHelper helper(mSDLWindow, settings.window_x, settings.window_y, title, settings.fullscreen, params); - if (settings.icon != "") - helper.setWindowIcon(settings.icon); - mWindow = helper.getWindow(); - - SDL_GetWindowGammaRamp(mSDLWindow, mOldSystemGammaRamp, &mOldSystemGammaRamp[256], &mOldSystemGammaRamp[512]); - - // create the semi-transparent black background texture used by the GUI. - // has to be created in code with TU_DYNAMIC_WRITE_ONLY param - // so that it can be modified at runtime. - Ogre::TextureManager::getSingleton().createManual( - "transparent.png", - Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - Ogre::TEX_TYPE_2D, - 1, 1, - 0, - Ogre::PF_A8R8G8B8, - Ogre::TU_WRITE_ONLY); - - mScene = mRoot->createSceneManager(ST_GENERIC); - - 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())); -} - -void OgreRenderer::setWindowGammaContrast(float gamma, float contrast) -{ - if (mSDLWindow == NULL) return; - - Uint16 red[256], green[256], blue[256]; - for (int i = 0; i < 256; i++) - { - float k = i/256.0f; - k = (k - 0.5f) * contrast + 0.5f; - k = pow(k, 1.f/gamma); - k *= 256; - float value = k*256; - if (value > 65535) value = 65535; - else if (value < 0) value = 0; - - red[i] = green[i] = blue[i] = static_cast(value); - } - if (SDL_SetWindowGammaRamp(mSDLWindow, red, green, blue) < 0) - std::cout << "Couldn't set gamma: " << SDL_GetError() << std::endl; -} - -void OgreRenderer::restoreWindowGammaRamp() -{ - if (mSDLWindow != NULL) - { - SDL_SetWindowGammaRamp(mSDLWindow, mOldSystemGammaRamp, &mOldSystemGammaRamp[256], &mOldSystemGammaRamp[512]); - } -} - -void OgreRenderer::adjustCamera(float fov, float nearClip) -{ - mCamera->setNearClipDistance(nearClip); - mCamera->setFOVy(Degree(fov)); -} - -void OgreRenderer::adjustViewport() -{ - // Alter the camera aspect ratio to match the viewport - if(mCamera != NULL) - { - mView->setDimensions(0, 0, 1, 1); - mCamera->setAspectRatio(Real(mView->getActualWidth()) / Real(mView->getActualHeight())); - } -} - -void OgreRenderer::setFov(float fov) -{ - mCamera->setFOVy(Degree(fov)); -} - -void OgreRenderer::windowResized(int x, int y) -{ - if (mWindowListener) { - mWindowListener->windowResized(x,y); - } - else { - mWindowWidth = x; - mWindowHeight = y; - mOutstandingResize = true; - } -} - -void OgreRenderer::setWindowListener(WindowSizeListener* listener) -{ - mWindowListener = listener; - if (mOutstandingResize) { - windowResized(mWindowWidth, mWindowHeight); - mOutstandingResize = false; - } -} diff --git a/libs/openengine/ogre/renderer.hpp b/libs/openengine/ogre/renderer.hpp deleted file mode 100644 index 33a42f8cd..000000000 --- a/libs/openengine/ogre/renderer.hpp +++ /dev/null @@ -1,147 +0,0 @@ -#ifndef OENGINE_OGRE_RENDERER_H -#define OENGINE_OGRE_RENDERER_H - -/* - Ogre renderer class - */ - -#include -#include - -#include - - -struct SDL_Window; -struct SDL_Surface; - -namespace Ogre -{ - class Root; - class RenderWindow; - class SceneManager; - class Camera; - class Viewport; - class ParticleEmitterFactory; - class ParticleAffectorFactory; -} - -namespace OgreInit -{ - class OgreInit; -} - -namespace OEngine -{ - namespace Render - { - struct WindowSettings - { - bool vsync; - bool fullscreen; - bool window_border; - int window_x, window_y; - int screen; - std::string fsaa; - std::string icon; - }; - - class WindowSizeListener - { - public: - virtual void windowResized (int x, int y) = 0; - }; - - class OgreRenderer - { - Ogre::Root *mRoot; - Ogre::RenderWindow *mWindow; - SDL_Window *mSDLWindow; - Ogre::SceneManager *mScene; - Ogre::Camera *mCamera; - Ogre::Viewport *mView; - - OgreInit::OgreInit* mOgreInit; - - WindowSizeListener* mWindowListener; - - int mWindowWidth; - int mWindowHeight; - bool mOutstandingResize; - - // Store system gamma ramp on window creation. Restore system gamma ramp on exit - uint16_t mOldSystemGammaRamp[256*3]; - - public: - OgreRenderer() - : mRoot(NULL) - , mWindow(NULL) - , mSDLWindow(NULL) - , mScene(NULL) - , mCamera(NULL) - , mView(NULL) - , mOgreInit(NULL) - , mWindowListener(NULL) - , mWindowWidth(0) - , mWindowHeight(0) - , mOutstandingResize(false) - { - } - - ~OgreRenderer(); - - /** Configure the renderer. This will load configuration files and - set up the Root and logging classes. */ - void configure( - const std::string &logPath, // Path to directory where to store log files - const std::string &renderSystem, - const std::string &rttMode); // Enable or disable logging - - /// Create a window with the given title - void createWindow(const std::string &title, const WindowSettings& settings); - - void setWindowGammaContrast(float gamma, float contrast); - void restoreWindowGammaRamp(); - - /// Set up the scene manager, camera and viewport - void adjustCamera( - float fov=55, // Field of view angle - float nearClip=5 // Near clip distance - ); - - void setFov(float fov); - - /// Kill the renderer. - void cleanup(); - - void update(float dt); - - /// Write a screenshot to file - void screenshot(const std::string &file, const std::string& imageFormat); - - void windowResized(int x, int y); - - /// Get the Root - Ogre::Root *getRoot() { return mRoot; } - - /// Get the rendering window - Ogre::RenderWindow *getWindow() { return mWindow; } - - /// Get the SDL Window - SDL_Window *getSDLWindow() { return mSDLWindow; } - - /// Get the scene manager - Ogre::SceneManager *getScene() { return mScene; } - - /// Camera - Ogre::Camera *getCamera() { return mCamera; } - - /// Viewport - Ogre::Viewport *getViewport() { return mView; } - - void setWindowListener(WindowSizeListener* listener); - - void adjustViewport(); - }; - } -} -#endif From dfd8e08698ec01be3f8fcd24c4230af265d2094b Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 21 Apr 2015 23:40:10 +0200 Subject: [PATCH 0996/3725] Dead code removal --- apps/openmw/CMakeLists.txt | 4 +- apps/openmw/mwrender/actors.cpp | 211 -------------------- apps/openmw/mwrender/actors.hpp | 64 ------ apps/openmw/mwrender/renderinginterface.hpp | 3 +- apps/openmw/mwrender/renderingmanager.cpp | 5 - apps/openmw/mwrender/renderingmanager.hpp | 1 - 6 files changed, 3 insertions(+), 285 deletions(-) delete mode 100644 apps/openmw/mwrender/actors.cpp delete mode 100644 apps/openmw/mwrender/actors.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index c8854f84b..84dcb60fa 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -21,9 +21,9 @@ source_group(game FILES ${GAME} ${GAME_HEADER}) add_openmw_dir (mwrender actors objects renderingmanager animation sky npcanimation vismask - creatureanimation effectmanager util + creatureanimation effectmanager util renderinginterface # debugging camera activatoranimation -# renderinginterface localmap occlusionquery water shadows +# localmap occlusionquery water shadows # characterpreview globalmap ripplesimulation refraction # terrainstorage renderconst weaponanimation ) diff --git a/apps/openmw/mwrender/actors.cpp b/apps/openmw/mwrender/actors.cpp deleted file mode 100644 index 878712ecc..000000000 --- a/apps/openmw/mwrender/actors.cpp +++ /dev/null @@ -1,211 +0,0 @@ -#include "actors.hpp" - -#include -#include - -#include "../mwworld/ptr.hpp" -#include "../mwworld/class.hpp" - -//#include "../mwrender/renderingmanager.hpp" - -/* -#include "animation.hpp" -#include "activatoranimation.hpp" -#include "creatureanimation.hpp" -#include "npcanimation.hpp" -*/ -#include "renderconst.hpp" - - -namespace MWRender -{ -using namespace Ogre; - -Actors::~Actors() -{ - /* - PtrAnimationMap::iterator it = mAllActors.begin(); - for(;it != mAllActors.end();++it) - { - delete it->second; - it->second = NULL; - } - */ -} - -//void Actors::setRootNode(Ogre::SceneNode* root) -//{ mRootNode = root; } - -void Actors::insertBegin(const MWWorld::Ptr &ptr) -{ - /* - Ogre::SceneNode* cellnode; - CellSceneNodeMap::const_iterator celliter = mCellSceneNodes.find(ptr.getCell()); - if(celliter != mCellSceneNodes.end()) - cellnode = celliter->second; - else - { - //Create the scenenode and put it in the map - cellnode = mRootNode->createChildSceneNode(); - mCellSceneNodes[ptr.getCell()] = cellnode; - } - - Ogre::SceneNode* insert = cellnode->createChildSceneNode(); - const float *f = ptr.getRefData().getPosition().pos; - insert->setPosition(f[0], f[1], f[2]); - insert->setScale(ptr.getCellRef().getScale(), ptr.getCellRef().getScale(), ptr.getCellRef().getScale()); - - // Convert MW rotation to a quaternion: - f = ptr.getCellRef().getPosition().rot; - - // For rendering purposes, actors should only rotate around the Z axis. - // X rotation is used for camera rotation (for the player) and for - // ranged magic / ranged weapon aiming. - Ogre::Quaternion zr(Ogre::Radian(-f[2]), Ogre::Vector3::UNIT_Z); - - insert->setOrientation(zr); - ptr.getRefData().setBaseNode(insert); - */ -} - -void Actors::insertNPC(const MWWorld::Ptr& ptr) -{ - /* - insertBegin(ptr); - NpcAnimation* anim = new NpcAnimation(ptr, ptr.getRefData().getBaseNode(), RV_Actors); - delete mAllActors[ptr]; - mAllActors[ptr] = anim; - mRendering->addWaterRippleEmitter (ptr); - */ -} -void Actors::insertCreature (const MWWorld::Ptr& ptr, const std::string &model, bool weaponsShields) -{ - /* - insertBegin(ptr); - Animation* anim = NULL; - if (weaponsShields) - anim = new CreatureWeaponAnimation(ptr, model); - else - anim = new CreatureAnimation(ptr, model); - delete mAllActors[ptr]; - mAllActors[ptr] = anim; - mRendering->addWaterRippleEmitter (ptr); - */ -} -void Actors::insertActivator (const MWWorld::Ptr& ptr, const std::string &model, bool addLight) -{ - /* - insertBegin(ptr); - ActivatorAnimation* anim = new ActivatorAnimation(ptr, model); - - if(ptr.getTypeName() == typeid(ESM::Light).name()) - { - if (addLight) - anim->addLight(ptr.get()->mBase); - else - anim->removeParticles(); - } - - delete mAllActors[ptr]; - mAllActors[ptr] = anim; - */ -} - -bool Actors::deleteObject (const MWWorld::Ptr& ptr) -{ - /* - if (mAllActors.find(ptr) == mAllActors.end()) - return false; - - mRendering->removeWaterRippleEmitter (ptr); - - delete mAllActors[ptr]; - mAllActors.erase(ptr); - - if(Ogre::SceneNode *base=ptr.getRefData().getBaseNode()) - { - Ogre::SceneNode *parent = base->getParentSceneNode(); - CellSceneNodeMap::const_iterator iter(mCellSceneNodes.begin()); - for(;iter != mCellSceneNodes.end();++iter) - { - if(iter->second == parent) - { - base->removeAndDestroyAllChildren(); - mRend.getScene()->destroySceneNode (base); - ptr.getRefData().setBaseNode (0); - return true; - } - } - - return false; - } -*/ - return true; -} - -void Actors::removeCell(MWWorld::CellStore* store) -{ - /* - for(PtrAnimationMap::iterator iter = mAllActors.begin();iter != mAllActors.end();) - { - if(iter->first.getCell() == store) - { - mRendering->removeWaterRippleEmitter (iter->first); - delete iter->second; - mAllActors.erase(iter++); - } - else - ++iter; - } - CellSceneNodeMap::iterator celliter = mCellSceneNodes.find(store); - if(celliter != mCellSceneNodes.end()) - { - Ogre::SceneNode *base = celliter->second; - base->removeAndDestroyAllChildren(); - mRend.getScene()->destroySceneNode(base); - - mCellSceneNodes.erase(celliter); - } - */ -} - -Animation* Actors::getAnimation(const MWWorld::Ptr &ptr) -{ - /* - PtrAnimationMap::const_iterator iter = mAllActors.find(ptr); - if(iter != mAllActors.end()) - return iter->second; - */ - return NULL; -} - -void Actors::updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur) -{ - /* - Ogre::SceneNode *node; - MWWorld::CellStore *newCell = cur.getCell(); - - CellSceneNodeMap::const_iterator celliter = mCellSceneNodes.find(newCell); - if(celliter != mCellSceneNodes.end()) - node = celliter->second; - else - { - node = mRootNode->createChildSceneNode(); - mCellSceneNodes[newCell] = node; - } - node->addChild(cur.getRefData().getBaseNode()); - - PtrAnimationMap::iterator iter = mAllActors.find(old); - if(iter != mAllActors.end()) - { - Animation *anim = iter->second; - mAllActors.erase(iter); - anim->updatePtr(cur); - mAllActors[cur] = anim; - } - - mRendering->updateWaterRippleEmitterPtr (old, cur); - */ -} - -} diff --git a/apps/openmw/mwrender/actors.hpp b/apps/openmw/mwrender/actors.hpp deleted file mode 100644 index 931c5bbd5..000000000 --- a/apps/openmw/mwrender/actors.hpp +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef GAME_RENDER_ACTORS_H -#define GAME_RENDER_ACTORS_H - -#include - -namespace OEngine -{ - namespace Render - { - class OgreRenderer; - } -} - -namespace MWWorld -{ - class Ptr; - class CellStore; - class InventoryStore; -} - -namespace MWRender -{ - class Animation; - class RenderingManager; - - class Actors - { - //typedef std::map CellSceneNodeMap; - //typedef std::map PtrAnimationMap; - - OEngine::Render::OgreRenderer &mRend; - MWRender::RenderingManager* mRendering; - //Ogre::SceneNode* mRootNode; - - //CellSceneNodeMap mCellSceneNodes; - //PtrAnimationMap mAllActors; - - void insertBegin(const MWWorld::Ptr &ptr); - - public: - Actors(OEngine::Render::OgreRenderer& _rend, MWRender::RenderingManager* rendering) - : mRend(_rend) - , mRendering(rendering) - //, mRootNode(NULL) - {} - ~Actors(); - - //void setRootNode(Ogre::SceneNode* root); - - void insertNPC(const MWWorld::Ptr& ptr); - void insertCreature (const MWWorld::Ptr& ptr, const std::string& model, bool weaponsShields); - void insertActivator (const MWWorld::Ptr& ptr, const std::string& model, bool addLight=false); - bool deleteObject (const MWWorld::Ptr& ptr); - ///< \return found? - - void removeCell(MWWorld::CellStore* store); - - /// Updates containing cell for object rendering data - void updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur); - - Animation* getAnimation(const MWWorld::Ptr &ptr); - }; -} -#endif diff --git a/apps/openmw/mwrender/renderinginterface.hpp b/apps/openmw/mwrender/renderinginterface.hpp index 02f3c804a..63039b612 100644 --- a/apps/openmw/mwrender/renderinginterface.hpp +++ b/apps/openmw/mwrender/renderinginterface.hpp @@ -10,8 +10,7 @@ namespace MWRender { public: virtual MWRender::Objects& getObjects() = 0; - virtual MWRender::Actors& getActors() = 0; - virtual ~RenderingInterface(){}; + virtual ~RenderingInterface(){} }; } #endif diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index b7265533c..dc5b584cc 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -138,11 +138,6 @@ namespace MWRender return *mObjects.get(); } - MWRender::Actors& RenderingManager::getActors() - { - throw std::runtime_error("unimplemented"); - } - Resource::ResourceSystem* RenderingManager::getResourceSystem() { return mResourceSystem; diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index d8744db4a..230885cd3 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -43,7 +43,6 @@ namespace MWRender ~RenderingManager(); MWRender::Objects& getObjects(); - MWRender::Actors& getActors(); Resource::ResourceSystem* getResourceSystem(); From b80f8afab8cd3a99e643ac64623e2624645b7e51 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 22 Apr 2015 00:04:46 +0200 Subject: [PATCH 0997/3725] Readme: Make status badges consistent again --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index aa5af0e6d..811eb8763 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ OpenMW ====== -[![Build Status](https://img.shields.io/travis/OpenMW/openmw.svg?style=plastic)](https://travis-ci.org/OpenMW/openmw) [![Coverity Scan Build Status](https://scan.coverity.com/projects/3740/badge.svg)](https://scan.coverity.com/projects/3740) +[![Build Status](https://img.shields.io/travis/OpenMW/openmw.svg)](https://travis-ci.org/OpenMW/openmw) [![Coverity Scan Build Status](https://scan.coverity.com/projects/3740/badge.svg)](https://scan.coverity.com/projects/3740) 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. From e49b8fe690fa899b72b74844415be46c79e87716 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 22 Apr 2015 01:17:01 +0200 Subject: [PATCH 0998/3725] Fix persuasion mechanics using player stats instead of NPC's (Fixes #2475) --- .../mwmechanics/mechanicsmanagerimp.cpp | 46 ++++++++++++------- 1 file changed, 29 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 617f38daf..da8d49db0 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -52,6 +52,31 @@ namespace return ((50.f - disposition) * fFightDispMult); } + void getPersuasionRatings(const MWMechanics::NpcStats& stats, float& rating1, float& rating2, float& rating3, bool player) + { + const MWWorld::Store &gmst = + MWBase::Environment::get().getWorld()->getStore().get(); + + float persTerm = stats.getAttribute(ESM::Attribute::Personality).getModified() / gmst.find("fPersonalityMod")->getFloat(); + float luckTerm = stats.getAttribute(ESM::Attribute::Luck).getModified() / gmst.find("fLuckMod")->getFloat(); + float repTerm = stats.getReputation() * gmst.find("fReputationMod")->getFloat(); + float fatigueTerm = stats.getFatigueTerm(); + float levelTerm = stats.getLevel() * gmst.find("fLevelMod")->getFloat(); + + rating1 = (repTerm + luckTerm + persTerm + stats.getSkill(ESM::Skill::Speechcraft).getModified()) * fatigueTerm; + + if (player) + { + rating2 = rating1 + levelTerm; + rating3 = (stats.getSkill(ESM::Skill::Mercantile).getModified() + luckTerm + persTerm) * fatigueTerm; + } + else + { + rating2 = (levelTerm + repTerm + luckTerm + persTerm + stats.getSkill(ESM::Skill::Speechcraft).getModified()) * fatigueTerm; + rating3 = (stats.getSkill(ESM::Skill::Mercantile).getModified() + repTerm + luckTerm + persTerm) * fatigueTerm; + } + } + } namespace MWMechanics @@ -685,24 +710,11 @@ namespace MWMechanics MWWorld::Ptr playerPtr = MWBase::Environment::get().getWorld()->getPlayerPtr(); const MWMechanics::NpcStats &playerStats = playerPtr.getClass().getNpcStats(playerPtr); - float persTerm = playerStats.getAttribute(ESM::Attribute::Personality).getModified() - / gmst.find("fPersonalityMod")->getFloat(); - - float luckTerm = playerStats.getAttribute(ESM::Attribute::Luck).getModified() - / gmst.find("fLuckMod")->getFloat(); - - float repTerm = playerStats.getReputation() * gmst.find("fReputationMod")->getFloat(); - float levelTerm = playerStats.getLevel() * gmst.find("fLevelMod")->getFloat(); - - float fatigueTerm = playerStats.getFatigueTerm(); - - float playerRating1 = (repTerm + luckTerm + persTerm + playerStats.getSkill(ESM::Skill::Speechcraft).getModified()) * fatigueTerm; - float playerRating2 = playerRating1 + levelTerm; - float playerRating3 = (playerStats.getSkill(ESM::Skill::Mercantile).getModified() + luckTerm + persTerm) * fatigueTerm; + float npcRating1, npcRating2, npcRating3; + getPersuasionRatings(npcStats, npcRating1, npcRating2, npcRating3, false); - float npcRating1 = (repTerm + luckTerm + persTerm + playerStats.getSkill(ESM::Skill::Speechcraft).getModified()) * fatigueTerm; - float npcRating2 = (levelTerm + repTerm + luckTerm + persTerm + npcStats.getSkill(ESM::Skill::Speechcraft).getModified()) * fatigueTerm; - float npcRating3 = (playerStats.getSkill(ESM::Skill::Mercantile).getModified() + repTerm + luckTerm + persTerm) * fatigueTerm; + float playerRating1, playerRating2, playerRating3; + getPersuasionRatings(playerStats, playerRating1, playerRating2, playerRating3, true); int currentDisposition = std::min(100, std::max(0, int(getDerivedDisposition(npc) + currentTemporaryDispositionDelta))); From 82bc666e002af107a32dbc1f06bce8b4de9cf1b7 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Wed, 22 Apr 2015 09:25:55 +1000 Subject: [PATCH 0999/3725] Make AI package items to be editable when a new row is added. --- apps/opencs/model/world/refidadapterimp.hpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index d3d52d2e1..41d8c65d5 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -1363,7 +1363,13 @@ namespace CSMWorld std::vector& list = actor.mAiPackage.mList; ESM::AIPackage newRow; - newRow.mType = ESM::AI_CNDT; + newRow.mType = ESM::AI_Wander; + newRow.mWander.mDistance = 0; + newRow.mWander.mDuration = 0; + newRow.mWander.mTimeOfDay = 0; + for (int i = 0; i < 8; ++i) + newRow.mWander.mIdle[i] = 0; + newRow.mWander.mShouldRepeat = 0; newRow.mCellName = ""; if (position >= (int)list.size()) From 5fbcf8a85932929ba2be46a9d9c8000c50bf58d3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 22 Apr 2015 16:59:23 +0200 Subject: [PATCH 1000/3725] Mesh filtering fix --- components/sceneutil/attach.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/components/sceneutil/attach.cpp b/components/sceneutil/attach.cpp index 9f9d63619..49e2acbd2 100644 --- a/components/sceneutil/attach.cpp +++ b/components/sceneutil/attach.cpp @@ -27,12 +27,14 @@ namespace SceneUtil , mParent(parent) , mFilter(Misc::StringUtils::lowerCase(filter)) { + mFilter2 = "tri " + mFilter; } virtual void apply(osg::Node& node) { std::string lowerName = Misc::StringUtils::lowerCase(node.getName()); - if (lowerName.find(mFilter) != std::string::npos) + if ((lowerName.size() >= mFilter.size() && lowerName.compare(0, mFilter.size(), mFilter) == 0) + || (lowerName.size() >= mFilter2.size() && lowerName.compare(0, mFilter2.size(), mFilter2) == 0)) { mParent->addChild(&node); } @@ -43,6 +45,7 @@ namespace SceneUtil private: osg::ref_ptr mParent; std::string mFilter; + std::string mFilter2; }; osg::ref_ptr attach(osg::ref_ptr toAttach, osg::Node *master, const std::string &filter, const std::string &attachNode) From 04accb7652d7deb681a71f9407bd4fca77d4a98a Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 22 Apr 2015 17:34:39 +0200 Subject: [PATCH 1001/3725] Add LightController --- apps/openmw/mwrender/animation.cpp | 14 +++ components/CMakeLists.txt | 2 +- components/sceneutil/lightcontroller.cpp | 129 +++++++++++++++++++++++ components/sceneutil/lightcontroller.hpp | 42 ++++++++ components/sceneutil/riggeometry.cpp | 2 +- components/sceneutil/skeleton.hpp | 2 +- libs/openengine/CMakeLists.txt | 6 +- libs/openengine/ogre/.gitignore | 1 - libs/openengine/ogre/lights.cpp | 102 ------------------ libs/openengine/ogre/lights.hpp | 64 ----------- 10 files changed, 189 insertions(+), 175 deletions(-) create mode 100644 components/sceneutil/lightcontroller.cpp create mode 100644 components/sceneutil/lightcontroller.hpp delete mode 100644 libs/openengine/ogre/.gitignore delete mode 100644 libs/openengine/ogre/lights.cpp delete mode 100644 libs/openengine/ogre/lights.hpp diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index d54e87dc5..8a0a85620 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -197,6 +198,19 @@ namespace MWRender light->setAmbient(osg::Vec4f(0,0,0,1)); light->setSpecular(osg::Vec4f(0,0,0,0)); + osg::ref_ptr ctrl (new SceneUtil::LightController); + ctrl->setDiffuse(light->getDiffuse()); + if (esmLight->mData.mFlags & ESM::Light::Flicker) + ctrl->setType(SceneUtil::LightController::LT_Flicker); + if (esmLight->mData.mFlags & ESM::Light::FlickerSlow) + ctrl->setType(SceneUtil::LightController::LT_FlickerSlow); + if (esmLight->mData.mFlags & ESM::Light::Pulse) + ctrl->setType(SceneUtil::LightController::LT_Pulse); + if (esmLight->mData.mFlags & ESM::Light::PulseSlow) + ctrl->setType(SceneUtil::LightController::LT_PulseSlow); + + lightSource->addUpdateCallback(ctrl); + attachTo->addChild(lightSource); } diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 75f6756f8..aa801689a 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -39,7 +39,7 @@ add_component_dir (resource ) add_component_dir (sceneutil - clone attach lightmanager visitor util statesetupdater controller skeleton riggeometry + clone attach lightmanager visitor util statesetupdater controller skeleton riggeometry lightcontroller ) add_component_dir (nif diff --git a/components/sceneutil/lightcontroller.cpp b/components/sceneutil/lightcontroller.cpp new file mode 100644 index 000000000..d0056ecc6 --- /dev/null +++ b/components/sceneutil/lightcontroller.cpp @@ -0,0 +1,129 @@ +#include "lightcontroller.hpp" + +#include + +#include + +#include + +#include + +namespace +{ + + float pulseAmplitude(float time) + { + return std::sin(time); + } + + float flickerAmplitude(float time) + { + static const float fb = 1.17024f; + static const float f[3] = { 1.5708f, 4.18774f, 5.19934f }; + static const float o[3] = { 0.804248f, 2.11115f, 3.46832f }; + static const float m[3] = { 1.0f, 0.785f, 0.876f }; + static const float s = 0.394f; + + float v = 0.0f; + for(int i = 0;i < 3;++i) + v += std::sin(fb*time*f[i] + o[1])*m[i]; + return v * s; + } + + float flickerFrequency(float phase) + { + static const float fa = 0.785398f; + static const float tdo = 0.94f; + static const float tdm = 2.48f; + + return tdo + tdm*std::sin(fa * phase); + } + +} + +namespace SceneUtil +{ + + LightController::LightController() + : mType(LT_Normal) + , mPhase((OEngine::Misc::Rng::rollClosedProbability() * 2.f - 1.f) * 500.f) + , mLastTime(0.0) + , mDeltaCount(0.f) + , mDirection(1.f) + { + } + + void LightController::setType(LightController::LightType type) + { + mType = type; + } + + void LightController::operator ()(osg::Node* node, osg::NodeVisitor* nv) + { + double time = nv->getFrameStamp()->getSimulationTime(); + if (time == mLastTime) + return; + + float dt = static_cast(time - mLastTime); + mLastTime = time; + + float brightness = 1.0f; + float cycle_time; + float time_distortion; + + const float pi = 3.14159265359; + + if(mType == LT_Pulse || mType == LT_PulseSlow) + { + cycle_time = 2.0f * pi; + time_distortion = 20.0f; + } + else + { + static const float fa = 0.785398f; + static const float phase_wavelength = 120.0f * pi / fa; + + cycle_time = 500.0f; + mPhase = std::fmod(mPhase + dt, phase_wavelength); + time_distortion = flickerFrequency(mPhase); + } + + mDeltaCount += mDirection*dt*time_distortion; + if(mDirection > 0 && mDeltaCount > +cycle_time) + { + mDirection = -1.0f; + mDeltaCount = 2.0f*cycle_time - mDeltaCount; + } + if(mDirection < 0 && mDeltaCount < -cycle_time) + { + mDirection = +1.0f; + mDeltaCount = -2.0f*cycle_time - mDeltaCount; + } + + static const float fast = 4.0f/1.0f; + static const float slow = 1.0f/1.0f; + + // These formulas are just guesswork, but they work pretty well + if(mType == LT_Normal) + { + // Less than 1/255 light modifier for a constant light: + brightness = 1.0f + flickerAmplitude(mDeltaCount*slow)/255.0f; + } + else if(mType == LT_Flicker) + brightness = 0.75f + flickerAmplitude(mDeltaCount*fast)*0.25f; + else if(mType == LT_FlickerSlow) + brightness = 0.75f + flickerAmplitude(mDeltaCount*slow)*0.25f; + else if(mType == LT_Pulse) + brightness = 1.0f + pulseAmplitude(mDeltaCount*fast)*0.25f; + else if(mType == LT_PulseSlow) + brightness = 1.0f + pulseAmplitude(mDeltaCount*slow)*0.25f; + + static_cast(node)->getLight()->setDiffuse(mDiffuseColor * brightness); + } + + void LightController::setDiffuse(osg::Vec4f color) + { + mDiffuseColor = color; + } + +} diff --git a/components/sceneutil/lightcontroller.hpp b/components/sceneutil/lightcontroller.hpp new file mode 100644 index 000000000..f6e2fa9fa --- /dev/null +++ b/components/sceneutil/lightcontroller.hpp @@ -0,0 +1,42 @@ +#ifndef OPENMW_COMPONENTS_SCENEUTIL_LIGHTCONTROLLER_H +#define OPENMW_COMPONENTS_SCENEUTIL_LIGHTCONTROLLER_H + +#include +#include + +namespace SceneUtil +{ + + /// @brief Controller class to handle a pulsing and/or flickering light + /// @note Must be set on a SceneUtil::LightSource. + class LightController : public osg::NodeCallback + { + public: + enum LightType { + LT_Normal, + LT_Flicker, + LT_FlickerSlow, + LT_Pulse, + LT_PulseSlow + }; + + LightController(); + + void setType(LightType type); + + void setDiffuse(osg::Vec4f color); + + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv); + + private: + LightType mType; + osg::Vec4f mDiffuseColor; + float mPhase; + float mDeltaCount; + int mDirection; + double mLastTime; + }; + +} + +#endif diff --git a/components/sceneutil/riggeometry.cpp b/components/sceneutil/riggeometry.cpp index 4d4ea22d2..ab9abcdda 100644 --- a/components/sceneutil/riggeometry.cpp +++ b/components/sceneutil/riggeometry.cpp @@ -149,7 +149,7 @@ void RigGeometry::update(osg::NodeVisitor* nv) else path.push_back(*it); } - osg::Matrix geomToSkel = osg::computeWorldToLocal(path); + osg::Matrixf geomToSkel = osg::computeWorldToLocal(path); // skinning osg::Vec3Array* positionSrc = static_cast(mSourceGeometry->getVertexArray()); diff --git a/components/sceneutil/skeleton.hpp b/components/sceneutil/skeleton.hpp index acb9e6136..d710ac61b 100644 --- a/components/sceneutil/skeleton.hpp +++ b/components/sceneutil/skeleton.hpp @@ -16,7 +16,7 @@ namespace SceneUtil Bone(); ~Bone(); - osg::Matrix mMatrixInSkeletonSpace; + osg::Matrixf mMatrixInSkeletonSpace; osg::MatrixTransform* mNode; diff --git a/libs/openengine/CMakeLists.txt b/libs/openengine/CMakeLists.txt index f3622b2ee..0fb39b9d1 100644 --- a/libs/openengine/CMakeLists.txt +++ b/libs/openengine/CMakeLists.txt @@ -1,7 +1,3 @@ -set(OENGINE_OGRE - #ogre/lights.cpp -) - set(OENGINE_GUI gui/loglistener.cpp #gui/manager.cpp @@ -26,7 +22,7 @@ set(OENGINE_MISC misc/rng.hpp ) -set(OENGINE_ALL ${OENGINE_OGRE} ${OENGINE_GUI} ${OENGINE_BULLET} ${OENGINE_MISC}) +set(OENGINE_ALL ${OENGINE_GUI} ${OENGINE_BULLET} ${OENGINE_MISC}) set(OENGINE_LIBRARY "oengine") set(OENGINE_LIBRARY ${OENGINE_LIBRARY} PARENT_SCOPE) diff --git a/libs/openengine/ogre/.gitignore b/libs/openengine/ogre/.gitignore deleted file mode 100644 index 3367afdbb..000000000 --- a/libs/openengine/ogre/.gitignore +++ /dev/null @@ -1 +0,0 @@ -old diff --git a/libs/openengine/ogre/lights.cpp b/libs/openengine/ogre/lights.cpp deleted file mode 100644 index 97fa938da..000000000 --- a/libs/openengine/ogre/lights.cpp +++ /dev/null @@ -1,102 +0,0 @@ -#include "lights.hpp" - -#include - - -namespace OEngine { -namespace Render { - -Ogre::Real LightFunction::pulseAmplitude(Ogre::Real time) -{ - return std::sin(time); -} - -Ogre::Real LightFunction::flickerAmplitude(Ogre::Real time) -{ - static const float fb = 1.17024f; - static const float f[3] = { 1.5708f, 4.18774f, 5.19934f }; - static const float o[3] = { 0.804248f, 2.11115f, 3.46832f }; - static const float m[3] = { 1.0f, 0.785f, 0.876f }; - static const float s = 0.394f; - - float v = 0.0f; - for(int i = 0;i < 3;++i) - v += std::sin(fb*time*f[i] + o[1])*m[i]; - return v * s; -} - -Ogre::Real LightFunction::flickerFrequency(Ogre::Real phase) -{ - static const float fa = 0.785398f; - static const float tdo = 0.94f; - static const float tdm = 2.48f; - - return tdo + tdm*std::sin(fa * phase); -} - -Ogre::Real LightFunction::calculate(Ogre::Real value) -{ - Ogre::Real brightness = 1.0f; - float cycle_time; - float time_distortion; - - if(mType == LT_Pulse || mType == LT_PulseSlow) - { - cycle_time = 2.0f * Ogre::Math::PI; - time_distortion = 20.0f; - } - else - { - static const float fa = 0.785398f; - static const float phase_wavelength = 120.0f * 3.14159265359f / fa; - - cycle_time = 500.0f; - mPhase = std::fmod(mPhase + value, phase_wavelength); - time_distortion = flickerFrequency(mPhase); - } - - mDeltaCount += mDirection*value*time_distortion; - if(mDirection > 0 && mDeltaCount > +cycle_time) - { - mDirection = -1.0f; - mDeltaCount = 2.0f*cycle_time - mDeltaCount; - } - if(mDirection < 0 && mDeltaCount < -cycle_time) - { - mDirection = +1.0f; - mDeltaCount = -2.0f*cycle_time - mDeltaCount; - } - - static const float fast = 4.0f/1.0f; - static const float slow = 1.0f/1.0f; - - // These formulas are just guesswork, but they work pretty well - if(mType == LT_Normal) - { - // Less than 1/255 light modifier for a constant light: - brightness = 1.0f + flickerAmplitude(mDeltaCount*slow)/255.0f; - } - else if(mType == LT_Flicker) - brightness = 0.75f + flickerAmplitude(mDeltaCount*fast)*0.25f; - else if(mType == LT_FlickerSlow) - brightness = 0.75f + flickerAmplitude(mDeltaCount*slow)*0.25f; - else if(mType == LT_Pulse) - brightness = 1.0f + pulseAmplitude(mDeltaCount*fast)*0.25f; - else if(mType == LT_PulseSlow) - brightness = 1.0f + pulseAmplitude(mDeltaCount*slow)*0.25f; - - return brightness; -} - -Ogre::Real LightValue::getValue() const -{ - return 0.0f; -} - -void LightValue::setValue(Ogre::Real value) -{ - mTarget->setDiffuseColour(mColor * value); -} - -} -} diff --git a/libs/openengine/ogre/lights.hpp b/libs/openengine/ogre/lights.hpp deleted file mode 100644 index 61d09a0e6..000000000 --- a/libs/openengine/ogre/lights.hpp +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef OENGINE_OGRE_LIGHTS_H -#define OENGINE_OGRE_LIGHTS_H - -#include -#include -#include - -/* - * Controller classes to handle pulsing and flicker lights - */ - -namespace OEngine { -namespace Render { - enum LightType { - LT_Normal, - LT_Flicker, - LT_FlickerSlow, - LT_Pulse, - LT_PulseSlow - }; - - class LightFunction : public Ogre::ControllerFunction - { - LightType mType; - Ogre::Real mPhase; - Ogre::Real mDirection; - - static Ogre::Real pulseAmplitude(Ogre::Real time); - - static Ogre::Real flickerAmplitude(Ogre::Real time); - static Ogre::Real flickerFrequency(Ogre::Real phase); - - public: - // 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); - }; - - class LightValue : public Ogre::ControllerValue - { - Ogre::Light *mTarget; - Ogre::ColourValue mColor; - - public: - // 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); - }; -} -} - -#endif From 7a46d4f46aabb6cb4fb1f925cf87e0b36e90d74d Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 22 Apr 2015 17:48:06 +0200 Subject: [PATCH 1002/3725] Dead code removal --- apps/openmw/mwrender/npcanimation.cpp | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 56f12da13..740418a01 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -611,23 +611,6 @@ osg::Vec3f NpcAnimation::runAnimation(float timepassed) } } mFirstPersonOffset = 0.f; // reset the X, Y, Z offset for the next frame. - - for(size_t i = 0;i < ESM::PRT_Count;i++) - { - if (mObjectParts[i].isNull()) - continue; - std::vector >::iterator ctrl(mObjectParts[i]->mControllers.begin()); - for(;ctrl != mObjectParts[i]->mControllers.end();++ctrl) - ctrl->update(); - - if (!isSkinned(mObjectParts[i])) - continue; - - if (mSkelBase) - updateSkeletonInstance(mSkelBase->getSkeleton(), mObjectParts[i]->mSkelBase->getSkeleton()); - - mObjectParts[i]->mSkelBase->getAllAnimationStates()->_notifyDirty(); - } */ return ret; From 8c810e36203b93780cae198a3f7e2fb33ee54b5d Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 22 Apr 2015 17:58:55 +0200 Subject: [PATCH 1003/3725] Move rng to components --- apps/openmw/engine.cpp | 4 ++-- apps/openmw/mwclass/creature.cpp | 8 +++---- apps/openmw/mwclass/npc.cpp | 10 ++++---- apps/openmw/mwgui/jailscreen.cpp | 4 ++-- apps/openmw/mwgui/loadingscreen.cpp | 4 ++-- apps/openmw/mwgui/pickpocketitemmodel.cpp | 4 ++-- apps/openmw/mwgui/recharge.cpp | 4 ++-- apps/openmw/mwgui/tradewindow.cpp | 4 ++-- apps/openmw/mwgui/waitdialog.cpp | 4 ++-- apps/openmw/mwmechanics/activespells.cpp | 4 ++-- apps/openmw/mwmechanics/aicombat.cpp | 24 +++++++++---------- apps/openmw/mwmechanics/aiwander.cpp | 10 ++++---- apps/openmw/mwmechanics/alchemy.cpp | 6 ++--- apps/openmw/mwmechanics/combat.cpp | 10 ++++---- apps/openmw/mwmechanics/disease.hpp | 4 ++-- apps/openmw/mwmechanics/enchanting.cpp | 4 ++-- apps/openmw/mwmechanics/levelledlist.hpp | 6 ++--- .../mwmechanics/mechanicsmanagerimp.cpp | 6 ++--- apps/openmw/mwmechanics/pickpocket.cpp | 4 ++-- apps/openmw/mwmechanics/repair.cpp | 4 ++-- apps/openmw/mwmechanics/security.cpp | 6 ++--- apps/openmw/mwmechanics/spellcasting.cpp | 16 ++++++------- apps/openmw/mwmechanics/spells.cpp | 2 +- apps/openmw/mwrender/npcanimation.cpp | 4 ++-- apps/openmw/mwrender/sky.cpp | 2 +- apps/openmw/mwsound/soundmanagerimp.cpp | 8 +++---- apps/openmw/mwworld/inventorystore.cpp | 2 +- apps/openmw/mwworld/store.hpp | 4 ++-- apps/openmw/mwworld/weather.cpp | 8 +++---- apps/openmw/mwworld/worldimp.cpp | 6 ++--- components/CMakeLists.txt | 2 +- components/interpreter/miscopcodes.hpp | 4 ++-- {libs/openengine => components}/misc/rng.cpp | 5 ++-- {libs/openengine => components}/misc/rng.hpp | 6 ++--- components/sceneutil/lightcontroller.cpp | 4 ++-- libs/openengine/CMakeLists.txt | 7 +----- 36 files changed, 103 insertions(+), 111 deletions(-) rename {libs/openengine => components}/misc/rng.cpp (93%) rename {libs/openengine => components}/misc/rng.hpp (88%) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 68f4e8225..64457834c 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -11,7 +11,7 @@ #include // TODO: move to component -#include +#include #include #include @@ -196,7 +196,7 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) , mExportFonts(false) , mNewGame (false) { - OEngine::Misc::Rng::init(); + Misc::Rng::init(); std::srand ( static_cast(std::time(NULL)) ); MWClass::registerClasses(); diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index a2451e1a1..d4a50ce81 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -1,7 +1,7 @@ #include "creature.hpp" -#include +#include #include #include @@ -251,7 +251,7 @@ namespace MWClass float hitchance = MWMechanics::getHitChance(ptr, victim, ref->mBase->mData.mCombat); - if(OEngine::Misc::Rng::rollProbability() >= hitchance/100.0f) + if(Misc::Rng::rollProbability() >= hitchance/100.0f) { victim.getClass().onHit(victim, 0.0f, false, MWWorld::Ptr(), ptr, false); MWMechanics::reduceWeaponCondition(0.f, false, weapon, ptr); @@ -377,7 +377,7 @@ namespace MWClass float agilityTerm = getCreatureStats(ptr).getAttribute(ESM::Attribute::Agility).getModified() * getGmst().fKnockDownMult->getFloat(); float knockdownTerm = getCreatureStats(ptr).getAttribute(ESM::Attribute::Agility).getModified() * getGmst().iKnockDownOddsMult->getInt() * 0.01f + getGmst().iKnockDownOddsBase->getInt(); - if (ishealth && agilityTerm <= damage && knockdownTerm <= OEngine::Misc::Rng::roll0to99()) + if (ishealth && agilityTerm <= damage && knockdownTerm <= Misc::Rng::roll0to99()) { getCreatureStats(ptr).setKnockedDown(true); @@ -681,7 +681,7 @@ namespace MWClass ++sound; } if(!sounds.empty()) - return sounds[OEngine::Misc::Rng::rollDice(sounds.size())]->mSound; + return sounds[Misc::Rng::rollDice(sounds.size())]->mSound; } if (type == ESM::SoundGenerator::Land) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index b5ac8f6c6..b28fb0499 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -3,7 +3,7 @@ #include -#include +#include #include #include @@ -513,7 +513,7 @@ namespace MWClass float hitchance = MWMechanics::getHitChance(ptr, victim, ptr.getClass().getSkill(ptr, weapskill)); - if (OEngine::Misc::Rng::rollProbability() >= hitchance / 100.0f) + if (Misc::Rng::rollProbability() >= hitchance / 100.0f) { othercls.onHit(victim, 0.0f, false, weapon, ptr, false); MWMechanics::reduceWeaponCondition(0.f, false, weapon, ptr); @@ -643,7 +643,7 @@ namespace MWClass const GMST& gmst = getGmst(); int chance = store.get().find("iVoiceHitOdds")->getInt(); - if (OEngine::Misc::Rng::roll0to99() < chance) + if (Misc::Rng::roll0to99() < chance) { MWBase::Environment::get().getDialogueManager()->say(ptr, "hit"); } @@ -652,7 +652,7 @@ namespace MWClass float agilityTerm = getCreatureStats(ptr).getAttribute(ESM::Attribute::Agility).getModified() * gmst.fKnockDownMult->getFloat(); float knockdownTerm = getCreatureStats(ptr).getAttribute(ESM::Attribute::Agility).getModified() * gmst.iKnockDownOddsMult->getInt() * 0.01f + gmst.iKnockDownOddsBase->getInt(); - if (ishealth && agilityTerm <= damage && knockdownTerm <= OEngine::Misc::Rng::roll0to99()) + if (ishealth && agilityTerm <= damage && knockdownTerm <= Misc::Rng::roll0to99()) { getCreatureStats(ptr).setKnockedDown(true); @@ -678,7 +678,7 @@ namespace MWClass MWWorld::InventoryStore::Slot_RightPauldron, MWWorld::InventoryStore::Slot_RightPauldron, MWWorld::InventoryStore::Slot_LeftGauntlet, MWWorld::InventoryStore::Slot_RightGauntlet }; - int hitslot = hitslots[OEngine::Misc::Rng::rollDice(20)]; + int hitslot = hitslots[Misc::Rng::rollDice(20)]; float unmitigatedDamage = damage; float x = damage / (damage + getArmorRating(ptr)); diff --git a/apps/openmw/mwgui/jailscreen.cpp b/apps/openmw/mwgui/jailscreen.cpp index 5c0a6ec5f..2e065c1c2 100644 --- a/apps/openmw/mwgui/jailscreen.cpp +++ b/apps/openmw/mwgui/jailscreen.cpp @@ -1,6 +1,6 @@ #include -#include +#include #include "../mwbase/windowmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" @@ -85,7 +85,7 @@ namespace MWGui std::set skills; for (int day=0; day #include -#include +#include #include @@ -148,7 +148,7 @@ namespace MWGui if (!mResources.empty()) { - std::string const & randomSplash = mResources.at(OEngine::Misc::Rng::rollDice(mResources.size())); + std::string const & randomSplash = mResources.at(Misc::Rng::rollDice(mResources.size())); Ogre::TextureManager::getSingleton ().load (randomSplash, Ogre::ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME); diff --git a/apps/openmw/mwgui/pickpocketitemmodel.cpp b/apps/openmw/mwgui/pickpocketitemmodel.cpp index bc7c5528e..2620e5660 100644 --- a/apps/openmw/mwgui/pickpocketitemmodel.cpp +++ b/apps/openmw/mwgui/pickpocketitemmodel.cpp @@ -1,6 +1,6 @@ #include "pickpocketitemmodel.hpp" -#include +#include #include "../mwmechanics/npcstats.hpp" #include "../mwworld/class.hpp" @@ -20,7 +20,7 @@ namespace MWGui { for (size_t i = 0; igetItemCount(); ++i) { - if (chance <= OEngine::Misc::Rng::roll0to99()) + if (chance <= Misc::Rng::roll0to99()) mHiddenItems.push_back(mSourceModel->getItem(i)); } } diff --git a/apps/openmw/mwgui/recharge.cpp b/apps/openmw/mwgui/recharge.cpp index a0e5991b4..2e6383210 100644 --- a/apps/openmw/mwgui/recharge.cpp +++ b/apps/openmw/mwgui/recharge.cpp @@ -5,7 +5,7 @@ #include #include -#include +#include #include @@ -163,7 +163,7 @@ void Recharge::onItemClicked(MyGUI::Widget *sender) intelligenceTerm = 1; float x = (npcStats.getSkill(ESM::Skill::Enchant).getModified() + intelligenceTerm + luckTerm) * stats.getFatigueTerm(); - int roll = OEngine::Misc::Rng::roll0to99(); + int roll = Misc::Rng::roll0to99(); if (roll < x) { std::string soul = gem.getCellRef().getSoul(); diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 42491a5e8..a879bf21f 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -4,7 +4,7 @@ #include #include -#include +#include #include @@ -367,7 +367,7 @@ namespace MWGui else x += abs(int(npcTerm - pcTerm)); - int roll = OEngine::Misc::Rng::rollDice(100) + 1; + int roll = Misc::Rng::rollDice(100) + 1; if(roll > x || (mCurrentMerchantOffer < 0) != (mCurrentBalance < 0)) //trade refused { MWBase::Environment::get().getWindowManager()-> diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index f74b06891..afbef5b67 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -2,7 +2,7 @@ #include -#include +#include #include #include @@ -156,7 +156,7 @@ namespace MWGui { // figure out if player will be woken while sleeping float fSleepRandMod = world->getStore().get().find("fSleepRandMod")->getFloat(); - if (OEngine::Misc::Rng::rollProbability() > fSleepRandMod) + if (Misc::Rng::rollProbability() > fSleepRandMod) { float fSleepRestMod = world->getStore().get().find("fSleepRestMod")->getFloat(); mInterruptAt = hoursToWait - int(fSleepRestMod * hoursToWait); diff --git a/apps/openmw/mwmechanics/activespells.cpp b/apps/openmw/mwmechanics/activespells.cpp index a6cc9af8e..7068310a0 100644 --- a/apps/openmw/mwmechanics/activespells.cpp +++ b/apps/openmw/mwmechanics/activespells.cpp @@ -1,6 +1,6 @@ #include "activespells.hpp" -#include +#include #include @@ -231,7 +231,7 @@ namespace MWMechanics { for (TContainer::iterator it = mSpells.begin(); it != mSpells.end(); ) { - if (OEngine::Misc::Rng::roll0to99() < chance) + if (Misc::Rng::roll0to99() < chance) mSpells.erase(it++); else ++it; diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index e570d1c33..84cf6f519 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -2,7 +2,7 @@ #include -#include +#include #include @@ -396,7 +396,7 @@ namespace MWMechanics if (!distantCombat) attackType = chooseBestAttack(weapon, movement); else attackType = ESM::Weapon::AT_Chop; // cause it's =0 - strength = OEngine::Misc::Rng::rollClosedProbability(); + strength = Misc::Rng::rollClosedProbability(); // Note: may be 0 for some animations timerAttack = minMaxAttackDuration[attackType][0] + @@ -407,7 +407,7 @@ namespace MWMechanics { const MWWorld::ESMStore &store = world->getStore(); int chance = store.get().find("iVoiceAttackOdds")->getInt(); - if (OEngine::Misc::Rng::roll0to99() < chance) + if (Misc::Rng::roll0to99() < chance) { MWBase::Environment::get().getDialogueManager()->say(actor, "attack"); } @@ -514,17 +514,17 @@ namespace MWMechanics { if(movement.mPosition[0] || movement.mPosition[1]) { - timerCombatMove = 0.1f + 0.1f * OEngine::Misc::Rng::rollClosedProbability(); + timerCombatMove = 0.1f + 0.1f * Misc::Rng::rollClosedProbability(); combatMove = true; } // only NPCs are smart enough to use dodge movements else if(actorClass.isNpc() && (!distantCombat || (distantCombat && distToTarget < rangeAttack/2))) { //apply sideway movement (kind of dodging) with some probability - if (OEngine::Misc::Rng::rollClosedProbability() < 0.25) + if (Misc::Rng::rollClosedProbability() < 0.25) { - movement.mPosition[0] = OEngine::Misc::Rng::rollProbability() < 0.5 ? 1.0f : -1.0f; - timerCombatMove = 0.05f + 0.15f * OEngine::Misc::Rng::rollClosedProbability(); + movement.mPosition[0] = Misc::Rng::rollProbability() < 0.5 ? 1.0f : -1.0f; + timerCombatMove = 0.05f + 0.15f * Misc::Rng::rollClosedProbability(); combatMove = true; } } @@ -639,7 +639,7 @@ namespace MWMechanics float s2 = speed2 * t; float t_swing = minMaxAttackDuration[ESM::Weapon::AT_Thrust][0] + - (minMaxAttackDuration[ESM::Weapon::AT_Thrust][1] - minMaxAttackDuration[ESM::Weapon::AT_Thrust][0]) * OEngine::Misc::Rng::rollClosedProbability(); + (minMaxAttackDuration[ESM::Weapon::AT_Thrust][1] - minMaxAttackDuration[ESM::Weapon::AT_Thrust][0]) * Misc::Rng::rollClosedProbability(); if (t + s2/speed1 <= t_swing) { @@ -763,10 +763,10 @@ ESM::Weapon::AttackType chooseBestAttack(const ESM::Weapon* weapon, MWMechanics: if (weapon == NULL) { //hand-to-hand deal equal damage for each type - float roll = OEngine::Misc::Rng::rollClosedProbability(); + float roll = Misc::Rng::rollClosedProbability(); if(roll <= 0.333f) //side punch { - movement.mPosition[0] = OEngine::Misc::Rng::rollClosedProbability() ? 1.0f : -1.0f; + movement.mPosition[0] = Misc::Rng::rollClosedProbability() ? 1.0f : -1.0f; movement.mPosition[1] = 0; attackType = ESM::Weapon::AT_Slash; } @@ -790,10 +790,10 @@ ESM::Weapon::AttackType chooseBestAttack(const ESM::Weapon* weapon, MWMechanics: float total = static_cast(slash + chop + thrust); - float roll = OEngine::Misc::Rng::rollClosedProbability(); + float roll = Misc::Rng::rollClosedProbability(); if(roll <= (slash/total)) { - movement.mPosition[0] = (OEngine::Misc::Rng::rollClosedProbability() < 0.5f) ? 1.0f : -1.0f; + movement.mPosition[0] = (Misc::Rng::rollClosedProbability() < 0.5f) ? 1.0f : -1.0f; movement.mPosition[1] = 0; attackType = ESM::Weapon::AT_Slash; } diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index b6cb553e8..f6e8c453f 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include @@ -329,7 +329,7 @@ namespace MWMechanics static float fVoiceIdleOdds = MWBase::Environment::get().getWorld()->getStore() .get().find("fVoiceIdleOdds")->getFloat(); - float roll = OEngine::Misc::Rng::rollProbability() * 10000.0f; + float roll = Misc::Rng::rollProbability() * 10000.0f; // In vanilla MW the chance was FPS dependent, and did not allow proper changing of fVoiceIdleOdds // due to the roll being an integer. @@ -504,7 +504,7 @@ namespace MWMechanics if(!storage.mPathFinder.isPathConstructed()) { assert(mAllowedNodes.size()); - unsigned int randNode = OEngine::Misc::Rng::rollDice(mAllowedNodes.size()); + unsigned int randNode = Misc::Rng::rollDice(mAllowedNodes.size()); // NOTE: initially constructed with local (i.e. cell) co-ordinates Ogre::Vector3 destNodePos(PathFinder::MakeOgreVector3(mAllowedNodes[randNode])); @@ -631,7 +631,7 @@ namespace MWMechanics .get().find("fIdleChanceMultiplier")->getFloat(); unsigned short idleChance = static_cast(fIdleChanceMultiplier * mIdle[counter]); - unsigned short randSelect = (int)(OEngine::Misc::Rng::rollProbability() * int(100 / fIdleChanceMultiplier)); + unsigned short randSelect = (int)(Misc::Rng::rollProbability() * int(100 / fIdleChanceMultiplier)); if(randSelect < idleChance && randSelect > idleRoll) { playedIdle = counter+2; @@ -653,7 +653,7 @@ namespace MWMechanics state.moveIn(new AiWanderStorage()); - int index = OEngine::Misc::Rng::rollDice(mAllowedNodes.size()); + int index = Misc::Rng::rollDice(mAllowedNodes.size()); ESM::Pathgrid::Point dest = mAllowedNodes[index]; // apply a slight offset to prevent overcrowding diff --git a/apps/openmw/mwmechanics/alchemy.cpp b/apps/openmw/mwmechanics/alchemy.cpp index 319d01495..ec4580568 100644 --- a/apps/openmw/mwmechanics/alchemy.cpp +++ b/apps/openmw/mwmechanics/alchemy.cpp @@ -9,7 +9,7 @@ #include #include -#include +#include #include #include @@ -297,7 +297,7 @@ void MWMechanics::Alchemy::addPotion (const std::string& name) newRecord.mName = name; - int index = OEngine::Misc::Rng::rollDice(6); + int index = Misc::Rng::rollDice(6); assert (index>=0 && index<6); static const char *meshes[] = { "standard", "bargain", "cheap", "fresh", "exclusive", "quality" }; @@ -470,7 +470,7 @@ MWMechanics::Alchemy::Result MWMechanics::Alchemy::create (const std::string& na return Result_RandomFailure; } - if (getAlchemyFactor() < OEngine::Misc::Rng::roll0to99()) + if (getAlchemyFactor() < Misc::Rng::roll0to99()) { removeIngredients(); return Result_RandomFailure; diff --git a/apps/openmw/mwmechanics/combat.cpp b/apps/openmw/mwmechanics/combat.cpp index b80ac8cf9..9f5d4fc85 100644 --- a/apps/openmw/mwmechanics/combat.cpp +++ b/apps/openmw/mwmechanics/combat.cpp @@ -2,7 +2,7 @@ #include -#include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -109,7 +109,7 @@ namespace MWMechanics int iBlockMinChance = gmst.find("iBlockMinChance")->getInt(); x = std::min(iBlockMaxChance, std::max(iBlockMinChance, x)); - if (OEngine::Misc::Rng::roll0to99() < x) + if (Misc::Rng::roll0to99() < x) { // Reduce shield durability by incoming damage int shieldhealth = shield->getClass().getItemHealth(*shield); @@ -187,7 +187,7 @@ namespace MWMechanics int skillValue = attacker.getClass().getSkill(attacker, weapon.getClass().getEquipmentSkill(weapon)); - if (OEngine::Misc::Rng::rollProbability() >= getHitChance(attacker, victim, skillValue) / 100.0f) + if (Misc::Rng::rollProbability() >= getHitChance(attacker, victim, skillValue) / 100.0f) { victim.getClass().onHit(victim, 0.0f, false, projectile, attacker, false); MWMechanics::reduceWeaponCondition(0.f, false, weapon, attacker); @@ -225,7 +225,7 @@ namespace MWMechanics && !appliedEnchantment) { float fProjectileThrownStoreChance = gmst.find("fProjectileThrownStoreChance")->getFloat(); - if (OEngine::Misc::Rng::rollProbability() < fProjectileThrownStoreChance / 100.f) + if (Misc::Rng::rollProbability() < fProjectileThrownStoreChance / 100.f) victim.getClass().getContainerStore(victim).add(projectile, 1, victim); } @@ -292,7 +292,7 @@ namespace MWMechanics saveTerm *= 1.25f * normalisedFatigue; - float x = std::max(0.f, saveTerm - OEngine::Misc::Rng::roll0to99()); + float x = std::max(0.f, saveTerm - Misc::Rng::roll0to99()); int element = ESM::MagicEffect::FireDamage; if (i == 1) diff --git a/apps/openmw/mwmechanics/disease.hpp b/apps/openmw/mwmechanics/disease.hpp index 0153be3dc..cf21f3806 100644 --- a/apps/openmw/mwmechanics/disease.hpp +++ b/apps/openmw/mwmechanics/disease.hpp @@ -1,7 +1,7 @@ #ifndef OPENMW_MECHANICS_DISEASE_H #define OPENMW_MECHANICS_DISEASE_H -#include +#include #include "../mwbase/windowmanager.hpp" #include "../mwbase/environment.hpp" @@ -51,7 +51,7 @@ namespace MWMechanics continue; int x = static_cast(fDiseaseXferChance * 100 * resist); - if (OEngine::Misc::Rng::rollDice(10000) < x) + if (Misc::Rng::rollDice(10000) < x) { // Contracted disease! actor.getClass().getCreatureStats(actor).getSpells().add(it->first); diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp index bb02fb41d..2cb963e28 100644 --- a/apps/openmw/mwmechanics/enchanting.cpp +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -1,6 +1,6 @@ #include "enchanting.hpp" -#include +#include #include "../mwworld/manualref.hpp" #include "../mwworld/class.hpp" @@ -70,7 +70,7 @@ namespace MWMechanics if(mSelfEnchanting) { - if(getEnchantChance() <= (OEngine::Misc::Rng::roll0to99())) + if(getEnchantChance() <= (Misc::Rng::roll0to99())) return false; mEnchanter.getClass().skillUsageSucceeded (mEnchanter, ESM::Skill::Enchant, 2); diff --git a/apps/openmw/mwmechanics/levelledlist.hpp b/apps/openmw/mwmechanics/levelledlist.hpp index 76c472001..f2f0c7cab 100644 --- a/apps/openmw/mwmechanics/levelledlist.hpp +++ b/apps/openmw/mwmechanics/levelledlist.hpp @@ -1,7 +1,7 @@ #ifndef OPENMW_MECHANICS_LEVELLEDLIST_H #define OPENMW_MECHANICS_LEVELLEDLIST_H -#include +#include #include @@ -26,7 +26,7 @@ namespace MWMechanics failChance += levItem->mChanceNone; - if (OEngine::Misc::Rng::roll0to99() < failChance) + if (Misc::Rng::roll0to99() < failChance) return std::string(); std::vector candidates; @@ -55,7 +55,7 @@ namespace MWMechanics } if (candidates.empty()) return std::string(); - std::string item = candidates[OEngine::Misc::Rng::rollDice(candidates.size())]; + std::string item = candidates[Misc::Rng::rollDice(candidates.size())]; // Vanilla doesn't fail on nonexistent items in levelled lists if (!MWBase::Environment::get().getWorld()->getStore().find(Misc::StringUtils::lowerCase(item))) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 0b3390271..0e3220cf8 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -2,7 +2,7 @@ #include "mechanicsmanagerimp.hpp" #include "npcstats.hpp" -#include +#include #include @@ -733,7 +733,7 @@ namespace MWMechanics float x = 0; float y = 0; - float roll = OEngine::Misc::Rng::rollClosedProbability() * 100; + float roll = Misc::Rng::rollClosedProbability() * 100; if (type == PT_Admire) { @@ -1393,7 +1393,7 @@ namespace MWMechanics float target = x - y; - return (OEngine::Misc::Rng::roll0to99() >= target); + return (Misc::Rng::roll0to99() >= target); } void MechanicsManager::startCombat(const MWWorld::Ptr &ptr, const MWWorld::Ptr &target) diff --git a/apps/openmw/mwmechanics/pickpocket.cpp b/apps/openmw/mwmechanics/pickpocket.cpp index 561011df3..eca24606e 100644 --- a/apps/openmw/mwmechanics/pickpocket.cpp +++ b/apps/openmw/mwmechanics/pickpocket.cpp @@ -1,6 +1,6 @@ #include "pickpocket.hpp" -#include +#include #include "../mwworld/class.hpp" #include "../mwworld/esmstore.hpp" @@ -41,7 +41,7 @@ namespace MWMechanics int iPickMaxChance = MWBase::Environment::get().getWorld()->getStore().get() .find("iPickMaxChance")->getInt(); - int roll = OEngine::Misc::Rng::roll0to99(); + int roll = Misc::Rng::roll0to99(); if (t < pcSneak / iPickMinChance) { return (roll > int(pcSneak / iPickMinChance)); diff --git a/apps/openmw/mwmechanics/repair.cpp b/apps/openmw/mwmechanics/repair.cpp index b5058fb88..fa429bbee 100644 --- a/apps/openmw/mwmechanics/repair.cpp +++ b/apps/openmw/mwmechanics/repair.cpp @@ -2,7 +2,7 @@ #include -#include +#include #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" @@ -48,7 +48,7 @@ void Repair::repair(const MWWorld::Ptr &itemToRepair) float x = (0.1f * pcStrength + 0.1f * pcLuck + armorerSkill) * fatigueTerm; - int roll = OEngine::Misc::Rng::roll0to99(); + int roll = Misc::Rng::roll0to99(); if (roll <= x) { int y = static_cast(fRepairAmountMult * toolQuality * roll); diff --git a/apps/openmw/mwmechanics/security.cpp b/apps/openmw/mwmechanics/security.cpp index 3f72f1b66..9eab5bfef 100644 --- a/apps/openmw/mwmechanics/security.cpp +++ b/apps/openmw/mwmechanics/security.cpp @@ -1,6 +1,6 @@ #include "security.hpp" -#include +#include #include "../mwworld/class.hpp" #include "../mwworld/containerstore.hpp" @@ -50,7 +50,7 @@ namespace MWMechanics else { MWBase::Environment::get().getMechanicsManager()->objectOpened(mActor, lock); - if (OEngine::Misc::Rng::roll0to99() <= x) + if (Misc::Rng::roll0to99() <= x) { lock.getClass().unlock(lock); resultMessage = "#{sLockSuccess}"; @@ -91,7 +91,7 @@ namespace MWMechanics else { MWBase::Environment::get().getMechanicsManager()->objectOpened(mActor, trap); - if (OEngine::Misc::Rng::roll0to99() <= x) + if (Misc::Rng::roll0to99() <= x) { trap.getCellRef().setTrap(""); diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 5f4d986b4..ff3d2fceb 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -4,7 +4,7 @@ #include -#include +#include #include "../mwbase/windowmanager.hpp" #include "../mwbase/soundmanager.hpp" @@ -282,7 +282,7 @@ namespace MWMechanics if (castChance > 0) x *= 50 / castChance; - float roll = OEngine::Misc::Rng::rollClosedProbability() * 100; + float roll = Misc::Rng::rollClosedProbability() * 100; if (magicEffect->mData.mFlags & ESM::MagicEffect::NoMagnitude) roll -= resistance; @@ -385,7 +385,7 @@ namespace MWMechanics target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::ResistCommonDisease).getMagnitude() : target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::ResistBlightDisease).getMagnitude(); - if (OEngine::Misc::Rng::roll0to99() <= x) + if (Misc::Rng::roll0to99() <= x) { // Fully resisted, show message if (target == MWBase::Environment::get().getWorld()->getPlayerPtr()) @@ -415,7 +415,7 @@ namespace MWMechanics if (spell && caster != target && target.getClass().isActor()) { float absorb = target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::SpellAbsorption).getMagnitude(); - absorbed = (OEngine::Misc::Rng::roll0to99() < absorb); + absorbed = (Misc::Rng::roll0to99() < absorb); if (absorbed) { //const ESM::Static* absorbStatic = MWBase::Environment::get().getWorld()->getStore().get().find ("VFX_Absorb"); @@ -463,7 +463,7 @@ namespace MWMechanics if (!reflected && magnitudeMult > 0 && !caster.isEmpty() && caster != target && !(magicEffect->mData.mFlags & ESM::MagicEffect::Unreflectable)) { float reflect = target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::Reflect).getMagnitude(); - bool isReflected = (OEngine::Misc::Rng::roll0to99() < reflect); + bool isReflected = (Misc::Rng::roll0to99() < reflect); if (isReflected) { //const ESM::Static* reflectStatic = MWBase::Environment::get().getWorld()->getStore().get().find ("VFX_Reflect"); @@ -491,7 +491,7 @@ namespace MWMechanics if (magnitudeMult > 0 && !absorbed) { - float random = OEngine::Misc::Rng::rollClosedProbability(); + float random = Misc::Rng::rollClosedProbability(); float magnitude = effectIt->mMagnMin + (effectIt->mMagnMax - effectIt->mMagnMin) * random; magnitude *= magnitudeMult; @@ -824,7 +824,7 @@ namespace MWMechanics // Check success float successChance = getSpellSuccessChance(spell, mCaster); - if (OEngine::Misc::Rng::roll0to99() >= successChance) + if (Misc::Rng::roll0to99() >= successChance) { if (mCaster == MWBase::Environment::get().getWorld()->getPlayerPtr()) MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicSkillFail}"); @@ -902,7 +902,7 @@ namespace MWMechanics + 0.1f * creatureStats.getAttribute (ESM::Attribute::Luck).getModified()) * creatureStats.getFatigueTerm(); - int roll = OEngine::Misc::Rng::roll0to99(); + int roll = Misc::Rng::roll0to99(); if (roll > x) { // "X has no effect on you" diff --git a/apps/openmw/mwmechanics/spells.cpp b/apps/openmw/mwmechanics/spells.cpp index 04225b43e..4d00d39c9 100644 --- a/apps/openmw/mwmechanics/spells.cpp +++ b/apps/openmw/mwmechanics/spells.cpp @@ -38,7 +38,7 @@ namespace MWMechanics for (unsigned int i=0; imEffects.mList.size();++i) { if (spell->mEffects.mList[i].mMagnMin != spell->mEffects.mList[i].mMagnMax) - random[i] = OEngine::Misc::Rng::rollClosedProbability(); + random[i] = Misc::Rng::rollClosedProbability(); } } diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 740418a01..702fd03ae 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -2,7 +2,7 @@ #include -#include +#include #include @@ -84,7 +84,7 @@ void HeadAnimationTime::setEnabled(bool enabled) void HeadAnimationTime::resetBlinkTimer() { - mBlinkTimer = -(2.0f + OEngine::Misc::Rng::rollDice(6)); + mBlinkTimer = -(2.0f + Misc::Rng::rollDice(6)); } void HeadAnimationTime::update(float dt) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index f4028caa7..0529b9a7b 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -17,7 +17,7 @@ #include -#include +#include #include diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 84f61ddf8..a5e18dd49 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -4,7 +4,7 @@ #include #include -#include +#include #include @@ -235,7 +235,7 @@ namespace MWSound if(!filelist.size()) return; - int i = OEngine::Misc::Rng::rollDice(filelist.size()); + int i = Misc::Rng::rollDice(filelist.size()); // Don't play the same music track twice in a row if (filelist[i] == mLastPlayedMusic) @@ -570,7 +570,7 @@ namespace MWSound if(!cell->isExterior() || sTimePassed < sTimeToNextEnvSound) return; - float a = OEngine::Misc::Rng::rollClosedProbability(); + float a = Misc::Rng::rollClosedProbability(); // 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); @@ -599,7 +599,7 @@ namespace MWSound return; } - int r = OEngine::Misc::Rng::rollDice(total); + int r = Misc::Rng::rollDice(total); int pos = 0; soundIter = regn->mSoundList.begin(); diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index e3254d30a..e0fd087fb 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -367,7 +367,7 @@ void MWWorld::InventoryStore::updateMagicEffects(const Ptr& actor) // Roll some dice, one for each effect params.resize(enchantment.mEffects.mList.size()); for (unsigned int i=0; i #include -#include +#include #include @@ -180,7 +180,7 @@ namespace MWWorld std::vector results; std::for_each(mShared.begin(), mShared.end(), GetRecords(id, &results)); if(!results.empty()) - return results[OEngine::Misc::Rng::rollDice(results.size())]; + return results[Misc::Rng::rollDice(results.size())]; return NULL; } diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 90aedda1c..b9d16993f 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -3,7 +3,7 @@ #include "weather.hpp" -#include +#include #include @@ -527,7 +527,7 @@ void WeatherManager::update(float duration, bool paused) if (mThunderSoundDelay <= 0) { // pick a random sound - int sound = OEngine::Misc::Rng::rollDice(4); + int sound = Misc::Rng::rollDice(4); std::string* soundName = NULL; if (sound == 0) soundName = &mThunderSoundID0; else if (sound == 1) soundName = &mThunderSoundID1; @@ -543,7 +543,7 @@ void WeatherManager::update(float duration, bool paused) //mRendering->getSkyManager()->setLightningStrength( mThunderFlash / mThunderThreshold ); //else { - mThunderChanceNeeded = static_cast(OEngine::Misc::Rng::rollDice(100)); + mThunderChanceNeeded = static_cast(Misc::Rng::rollDice(100)); mThunderChance = 0; //mRendering->getSkyManager()->setLightningStrength( 0.f ); } @@ -624,7 +624,7 @@ std::string WeatherManager::nextWeather(const ESM::Region* region) const * 70% will be greater than 30 (in theory). */ - int chance = OEngine::Misc::Rng::rollDice(100) + 1; // 1..100 + int chance = Misc::Rng::rollDice(100) + 1; // 1..100 int sum = 0; unsigned int i = 0; for (; i < probability.size(); ++i) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 0628b42d7..a2d40930b 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -16,7 +16,7 @@ #include #include -#include +#include #include #include @@ -3176,7 +3176,7 @@ namespace MWWorld const ESM::CreatureLevList* list = getStore().get().find(creatureList); int iNumberCreatures = getStore().get().find("iNumberCreatures")->getInt(); - int numCreatures = 1 + OEngine::Misc::Rng::rollDice(iNumberCreatures); // [1, iNumberCreatures] + int numCreatures = 1 + Misc::Rng::rollDice(iNumberCreatures); // [1, iNumberCreatures] for (int i=0; igetFallbackString(modelName.str()); diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index aa801689a..ece1148cb 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -78,7 +78,7 @@ add_component_dir (esmterrain ) add_component_dir (misc - utf8stream stringops resourcehelpers + utf8stream stringops resourcehelpers rng ) IF(NOT WIN32 AND NOT APPLE) diff --git a/components/interpreter/miscopcodes.hpp b/components/interpreter/miscopcodes.hpp index f566a5499..c49bbeb01 100644 --- a/components/interpreter/miscopcodes.hpp +++ b/components/interpreter/miscopcodes.hpp @@ -12,7 +12,7 @@ #include "runtime.hpp" #include "defines.hpp" -#include +#include namespace Interpreter { @@ -148,7 +148,7 @@ namespace Interpreter throw std::runtime_error ( "random: argument out of range (Don't be so negative!)"); - Type_Integer value = OEngine::Misc::Rng::rollDice(limit); // [o, limit) + Type_Integer value = Misc::Rng::rollDice(limit); // [o, limit) runtime[0].mInteger = value; } diff --git a/libs/openengine/misc/rng.cpp b/components/misc/rng.cpp similarity index 93% rename from libs/openengine/misc/rng.cpp rename to components/misc/rng.cpp index 3d50400df..df0fc687e 100644 --- a/libs/openengine/misc/rng.cpp +++ b/components/misc/rng.cpp @@ -2,8 +2,8 @@ #include #include -namespace OEngine { -namespace Misc { +namespace Misc +{ void Rng::init() { @@ -26,4 +26,3 @@ namespace Misc { } } -} diff --git a/libs/openengine/misc/rng.hpp b/components/misc/rng.hpp similarity index 88% rename from libs/openengine/misc/rng.hpp rename to components/misc/rng.hpp index 4e1da17e1..01fcdd763 100644 --- a/libs/openengine/misc/rng.hpp +++ b/components/misc/rng.hpp @@ -1,9 +1,8 @@ -#ifndef MISC_RNG_H -#define MISC_RNG_H +#ifndef OPENMW_COMPONENTS_MISC_RNG_H +#define OPENMW_COMPONENTS_MISC_RNG_H #include -namespace OEngine { namespace Misc { @@ -30,7 +29,6 @@ public: static int roll0to99() { return rollDice(100); } }; -} } #endif diff --git a/components/sceneutil/lightcontroller.cpp b/components/sceneutil/lightcontroller.cpp index d0056ecc6..484cea447 100644 --- a/components/sceneutil/lightcontroller.cpp +++ b/components/sceneutil/lightcontroller.cpp @@ -6,7 +6,7 @@ #include -#include +#include namespace { @@ -46,7 +46,7 @@ namespace SceneUtil LightController::LightController() : mType(LT_Normal) - , mPhase((OEngine::Misc::Rng::rollClosedProbability() * 2.f - 1.f) * 500.f) + , mPhase((Misc::Rng::rollClosedProbability() * 2.f - 1.f) * 500.f) , mLastTime(0.0) , mDeltaCount(0.f) , mDirection(1.f) diff --git a/libs/openengine/CMakeLists.txt b/libs/openengine/CMakeLists.txt index 0fb39b9d1..07ac60bc6 100644 --- a/libs/openengine/CMakeLists.txt +++ b/libs/openengine/CMakeLists.txt @@ -17,12 +17,7 @@ set(OENGINE_BULLET bullet/trace.h ) -set(OENGINE_MISC - misc/rng.cpp - misc/rng.hpp -) - -set(OENGINE_ALL ${OENGINE_GUI} ${OENGINE_BULLET} ${OENGINE_MISC}) +set(OENGINE_ALL ${OENGINE_GUI} ${OENGINE_BULLET}) set(OENGINE_LIBRARY "oengine") set(OENGINE_LIBRARY ${OENGINE_LIBRARY} PARENT_SCOPE) From 8410966753a7f3a52aef765dd603351e9bf94192 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 22 Apr 2015 18:01:55 +0200 Subject: [PATCH 1004/3725] Disable mygui plugin for now --- CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e806b2578..e8a2458b1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -557,9 +557,9 @@ add_subdirectory (extern/oics) add_subdirectory (components) # Plugins -if (BUILD_MYGUI_PLUGIN) - add_subdirectory(plugins/mygui_resource_plugin) -endif() +#if (BUILD_MYGUI_PLUGIN) +# add_subdirectory(plugins/mygui_resource_plugin) +#endif() #Testing if (BUILD_NIFTEST) From 460304b0697b96dc58a75ce7ecaf19de61031364 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 22 Apr 2015 18:06:29 +0200 Subject: [PATCH 1005/3725] Port bsatool --- apps/bsatool/bsatool.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/apps/bsatool/bsatool.cpp b/apps/bsatool/bsatool.cpp index c0a6dcc81..2ea736db7 100644 --- a/apps/bsatool/bsatool.cpp +++ b/apps/bsatool/bsatool.cpp @@ -237,12 +237,14 @@ int extract(Bsa::BSAFile& bsa, Arguments& info) } // Get a stream for the file to extract - Ogre::DataStreamPtr data = bsa.getFile(archivePath.c_str()); + Files::IStreamPtr stream = bsa.getFile(archivePath.c_str()); + bfs::ofstream out(target, std::ios::binary); // Write the file to disk std::cout << "Extracting " << info.extractfile << " to " << target << std::endl; - out.write(data->getAsString().c_str(), data->size()); + + out << stream->rdbuf(); out.close(); return 0; @@ -276,12 +278,12 @@ int extractAll(Bsa::BSAFile& bsa, Arguments& info) // Get a stream for the file to extract // (inefficient because getFile iter on the list again) - Ogre::DataStreamPtr data = bsa.getFile(archivePath); + Files::IStreamPtr data = bsa.getFile(archivePath); bfs::ofstream out(target, std::ios::binary); // Write the file to disk std::cout << "Extracting " << target << std::endl; - out.write(data->getAsString().c_str(), data->size()); + out << data->rdbuf(); out.close(); } From 1a19cd360766a59eadbc41f8fa4357f9c2fadf97 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 22 Apr 2015 19:08:56 +0200 Subject: [PATCH 1006/3725] Some cleanup --- apps/openmw/mwrender/animation.cpp | 12 ++++++++++++ apps/openmw/mwrender/animation.hpp | 19 +++++++------------ apps/openmw/mwrender/npcanimation.cpp | 14 ++++++++------ apps/openmw/mwrender/npcanimation.hpp | 16 ++++++++-------- apps/openmw/mwrender/objects.hpp | 11 ++++++++--- apps/openmw/mwrender/renderingmanager.cpp | 4 ++-- apps/openmw/mwworld/scene.cpp | 2 ++ components/nifosg/nifloader.hpp | 3 +-- 8 files changed, 48 insertions(+), 33 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 8a0a85620..75d409aec 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1,5 +1,7 @@ #include "animation.hpp" +#include + #include #include #include @@ -91,6 +93,16 @@ namespace MWRender mInsert->removeChild(mObjectRoot); } + void Animation::updatePtr(const MWWorld::Ptr &ptr) + { + mPtr = ptr; + } + + void Animation::addAnimSource(const std::string &model) + { + + } + osg::Vec3f Animation::runAnimation(float duration) { updateEffects(duration); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index aef4d4b80..ea47a5b79 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -1,9 +1,6 @@ #ifndef GAME_RENDER_ANIMATION_H #define GAME_RENDER_ANIMATION_H -#include -#include - #include "../mwworld/ptr.hpp" #include @@ -55,7 +52,7 @@ protected: /* This is the number of *discrete* groups. */ static const size_t sNumGroups = 4; - class AnimationTime : public Ogre::ControllerValue + class AnimationTime : public SceneUtil::ControllerSource { private: Animation *mAnimation; @@ -71,8 +68,7 @@ protected: const std::string &getAnimName() const { return mAnimationName; } - virtual Ogre::Real getValue() const; - virtual void setValue(Ogre::Real value); + virtual float getValue(); }; class NullAnimationTime : public SceneUtil::ControllerSource @@ -85,14 +81,15 @@ protected: }; + /* struct AnimSource : public Ogre::AnimationAlloc { //NifOgre::TextKeyMap mTextKeys; std::vector > mControllers[sNumGroups]; }; typedef std::vector< Ogre::SharedPtr > AnimSourceList; - + */ struct AnimState { - Ogre::SharedPtr mSource; + //Ogre::SharedPtr mSource; float mStartTime; float mLoopStartTime; float mLoopStopTime; @@ -115,8 +112,6 @@ protected: }; typedef std::map AnimStateMap; - typedef std::map ObjectAttachMap; - osg::ref_ptr mInsert; osg::ref_ptr mObjectRoot; @@ -204,7 +199,7 @@ protected: /* Adds the keyframe controllers in the specified model as a new animation source. Note that * the filename portion of the provided model name will be prepended with 'x', and the .nif * extension will be replaced with .kf. */ - //void addAnimSource(const std::string &model); + void addAnimSource(const std::string &model); /** Adds an additional light to the given node using the specified ESM record. */ void addExtraLight(osg::ref_ptr parent, const ESM::Light *light); @@ -238,7 +233,7 @@ public: void removeEffect (int effectId); void getLoopingEffects (std::vector& out); - //void updatePtr(const MWWorld::Ptr &ptr); + void updatePtr(const MWWorld::Ptr &ptr); //bool hasAnimation(const std::string &anim); diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 702fd03ae..03af50c71 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -190,12 +190,12 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, osg::ref_ptr par mViewMode(viewMode), mShowWeapons(false), mShowCarriedLeft(true), - mFirstPersonOffset(0.f, 0.f, 0.f), + //mFirstPersonOffset(0.f, 0.f, 0.f), mAlpha(1.f), mNpcType(Type_Normal), - mSoundsDisabled(disableSounds), - mHeadPitch(0.f), - mHeadYaw(0.f) + mSoundsDisabled(disableSounds) + //mHeadPitch(0.f), + //mHeadYaw(0.f) { mNpc = mPtr.get()->mBase; @@ -562,11 +562,11 @@ void NpcAnimation::updateParts() if (wasArrowAttached) attachArrow(); } - +/* void NpcAnimation::addFirstPersonOffset(const Ogre::Vector3 &offset) { mFirstPersonOffset += offset; -} +}*/ Animation::PartHolderPtr NpcAnimation::insertBoundedPart(const std::string& model, int group, const std::string& bonename, const std::string& bonefilter, bool enchantedGlow, osg::Vec4f* glowColor) { @@ -903,6 +903,7 @@ void NpcAnimation::setVampire(bool vampire) } } +/* void NpcAnimation::setHeadPitch(Ogre::Radian pitch) { mHeadPitch = pitch; @@ -922,5 +923,6 @@ Ogre::Radian NpcAnimation::getHeadYaw() const { return mHeadYaw; } +*/ } diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 309bc5ef5..0c91dfe6e 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -90,7 +90,7 @@ private: int mPartslots[ESM::PRT_Count]; //Each part slot is taken by clothing, armor, or is empty int mPartPriorities[ESM::PRT_Count]; - Ogre::Vector3 mFirstPersonOffset; + //Ogre::Vector3 mFirstPersonOffset; boost::shared_ptr mHeadAnimationTime; //Ogre::SharedPtr mWeaponAnimationTime; @@ -98,8 +98,8 @@ private: float mAlpha; bool mSoundsDisabled; - Ogre::Radian mHeadYaw; - Ogre::Radian mHeadPitch; + //Ogre::Radian mHeadYaw; + //Ogre::Radian mHeadPitch; void updateNpcBase(); @@ -144,10 +144,10 @@ public: /// to indicate the facing orientation of the character. virtual void setPitchFactor(float factor) { mPitchFactor = factor; } - virtual void setHeadPitch(Ogre::Radian pitch); - virtual void setHeadYaw(Ogre::Radian yaw); - virtual Ogre::Radian getHeadPitch() const; - virtual Ogre::Radian getHeadYaw() const; + //virtual void setHeadPitch(Ogre::Radian pitch); + //virtual void setHeadYaw(Ogre::Radian yaw); + //virtual Ogre::Radian getHeadPitch() const; + //virtual Ogre::Radian getHeadYaw() const; virtual void showWeapons(bool showWeapon); virtual void showCarriedLeft(bool show); @@ -167,7 +167,7 @@ public: /// \brief Applies a translation to the arms and hands. /// This may be called multiple times before the animation /// is updated to add additional offsets. - void addFirstPersonOffset(const Ogre::Vector3 &offset); + //void addFirstPersonOffset(const Ogre::Vector3 &offset); /// Rebuilds the NPC, updating their root model, animation sources, and equipment. void rebuild(); diff --git a/apps/openmw/mwrender/objects.hpp b/apps/openmw/mwrender/objects.hpp index f4d5675aa..2acf10d10 100644 --- a/apps/openmw/mwrender/objects.hpp +++ b/apps/openmw/mwrender/objects.hpp @@ -1,9 +1,9 @@ #ifndef GAME_RENDER_OBJECTS_H #define GAME_RENDER_OBJECTS_H -#include - -#include +#include +#include +#include #include @@ -12,6 +12,11 @@ namespace osg class Group; } +namespace Resource +{ + class ResourceSystem; +} + namespace MWWorld { class Ptr; diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index dc5b584cc..5199e6e12 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -10,12 +10,12 @@ #include +#include + #include #include - #include - #include #include diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index aabe4d6d8..ef9e5792b 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -5,6 +5,8 @@ #include #include #include +#include +#include #include diff --git a/components/nifosg/nifloader.hpp b/components/nifosg/nifloader.hpp index 1c403a4fe..d1437ff2a 100644 --- a/components/nifosg/nifloader.hpp +++ b/components/nifosg/nifloader.hpp @@ -44,7 +44,7 @@ namespace NifOsg public: TextKeyMap mTextKeys; - std::map > mKeyframeControllers; + std::map > mKeyframeControllers; }; /// The main class responsible for loading NIF files into an OSG-Scenegraph. @@ -53,7 +53,6 @@ namespace NifOsg class Loader { public: - // TODO: add text keys as user data on the node /// Create a scene graph for the given NIF. Auto-detects when skinning is used and calls loadAsSkeleton instead. /// @param node The parent of the new root node for the created scene graph. static osg::ref_ptr load(Nif::NIFFilePtr file, Resource::TextureManager* textureManager); From 148c041a43788d0d3faf1d7c5bc1bce8fe8d81e8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 22 Apr 2015 19:16:49 +0200 Subject: [PATCH 1007/3725] Nif loader cleanup - forcing a skeleton is no longer needed --- components/nifosg/nifloader.cpp | 45 ++++++++------------------------- components/nifosg/nifloader.hpp | 6 +---- 2 files changed, 11 insertions(+), 40 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index f7f6af0ae..63a3ee887 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -459,9 +459,6 @@ namespace NifOsg static osg::ref_ptr load(Nif::NIFFilePtr nif, Resource::TextureManager* textureManager) { - if (nif->getUseSkinning()) - return loadAsSkeleton(nif, textureManager); - if (nif->numRoots() < 1) nif->fail("Found no root nodes"); @@ -473,35 +470,19 @@ namespace NifOsg osg::ref_ptr textkeys (new TextKeyMapHolder); - osg::ref_ptr created = handleNode(nifNode, NULL, textureManager, false, std::map(), 0, 0, false, &textkeys->mTextKeys); + osg::ref_ptr created = handleNode(nifNode, NULL, textureManager, std::map(), 0, 0, false, &textkeys->mTextKeys); + if (nif->getUseSkinning()) + { + osg::ref_ptr skel = new SceneUtil::Skeleton; + skel->addChild(created); + created = skel; + } created->getOrCreateUserDataContainer()->addUserObject(textkeys); return created; } - static osg::ref_ptr loadAsSkeleton(Nif::NIFFilePtr nif, Resource::TextureManager* textureManager) - { - if (nif->numRoots() < 1) - nif->fail("Found no root nodes"); - - const Nif::Record* r = nif->getRoot(0); - assert(r != NULL); - - const Nif::Node* nifNode = dynamic_cast(r); - if (nifNode == NULL) - nif->fail("First root was not a node, but a " + r->recName); - - osg::ref_ptr textkeys (new TextKeyMapHolder); - - osg::ref_ptr skel = new SceneUtil::Skeleton; - handleNode(nifNode, skel, textureManager, true, std::map(), 0, 0, false, &textkeys->mTextKeys); - - skel->getOrCreateUserDataContainer()->addUserObject(textkeys); - - return skel; - } - static void applyNodeProperties(const Nif::Node *nifNode, osg::Node *applyTo, SceneUtil::CompositeStateSetUpdater* composite, Resource::TextureManager* textureManager, std::map& boundTextures, int animflags) { const Nif::PropertyList& props = nifNode->props; @@ -521,7 +502,7 @@ namespace NifOsg toSetup->mFunction = boost::shared_ptr(new ControllerFunction(ctrl)); } - static osg::ref_ptr handleNode(const Nif::Node* nifNode, osg::Group* parentNode, Resource::TextureManager* textureManager, bool createSkeleton, + static osg::ref_ptr handleNode(const Nif::Node* nifNode, osg::Group* parentNode, Resource::TextureManager* textureManager, std::map boundTextures, int animflags, int particleflags, bool skipMeshes, TextKeyMap* textKeys, osg::Node* rootNode=NULL) { osg::ref_ptr transformNode = new osg::MatrixTransform(toMatrix(nifNode->trafo)); @@ -604,7 +585,7 @@ namespace NifOsg if (nifNode->recType == Nif::RC_NiTriShape && !skipMeshes) { const Nif::NiTriShape* triShape = static_cast(nifNode); - if (!createSkeleton || triShape->skin.empty()) + if (triShape->skin.empty()) handleTriShape(triShape, transformNode, boundTextures, animflags); else handleSkinnedTriShape(triShape, transformNode, boundTextures, animflags); @@ -630,8 +611,7 @@ namespace NifOsg { if(!children[i].empty()) { - handleNode(children[i].getPtr(), transformNode, textureManager, - createSkeleton, boundTextures, animflags, particleflags, skipMeshes, textKeys, rootNode); + handleNode(children[i].getPtr(), transformNode, textureManager, boundTextures, animflags, particleflags, skipMeshes, textKeys, rootNode); } } } @@ -1451,11 +1431,6 @@ namespace NifOsg return LoaderImpl::load(file, textureManager); } - osg::ref_ptr Loader::loadAsSkeleton(Nif::NIFFilePtr file, Resource::TextureManager* textureManager) - { - return LoaderImpl::loadAsSkeleton(file, textureManager); - } - void Loader::loadKf(Nif::NIFFilePtr kf, KeyframeHolder& target) { LoaderImpl::loadKf(kf, target); diff --git a/components/nifosg/nifloader.hpp b/components/nifosg/nifloader.hpp index d1437ff2a..678b8cc64 100644 --- a/components/nifosg/nifloader.hpp +++ b/components/nifosg/nifloader.hpp @@ -53,13 +53,9 @@ namespace NifOsg class Loader { public: - /// Create a scene graph for the given NIF. Auto-detects when skinning is used and calls loadAsSkeleton instead. - /// @param node The parent of the new root node for the created scene graph. + /// Create a scene graph for the given NIF. Auto-detects when skinning is used and wraps the graph in a Skeleton if so. static osg::ref_ptr load(Nif::NIFFilePtr file, Resource::TextureManager* textureManager); - /// Create a scene graph for the given NIF. Always creates a skeleton so that rigs can be attached on the created scene. - static osg::ref_ptr loadAsSkeleton(Nif::NIFFilePtr file, Resource::TextureManager* textureManager); - /// Load keyframe controllers from the given kf file. static void loadKf(Nif::NIFFilePtr kf, KeyframeHolder& target); From cd7808fc11dbd38ba0eed772031ce2f5fe1edbfd Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 22 Apr 2015 23:12:58 +0200 Subject: [PATCH 1008/3725] Cleanup in preparation for animation port Scrapped previous idea for multiple animation sources, better approach incoming. --- components/nifosg/controller.cpp | 32 +-------------------- components/nifosg/controller.hpp | 22 +-------------- components/nifosg/nifloader.cpp | 43 ++--------------------------- components/nifosg/nifloader.hpp | 2 +- components/sceneutil/controller.hpp | 3 +- 5 files changed, 7 insertions(+), 95 deletions(-) diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index 499a74d95..27665b6c6 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -27,7 +27,7 @@ ControllerFunction::ControllerFunction(const Nif::Controller *ctrl) { } -float ControllerFunction::calculate(float value) +float ControllerFunction::calculate(float value) const { float time = mFrequency * value + mPhase; if (time >= mStartTime && time <= mStopTime) @@ -451,34 +451,4 @@ void ParticleSystemController::operator() (osg::Node* node, osg::NodeVisitor* nv traverse(node, nv); } -SourcedKeyframeController::SourcedKeyframeController(const Nif::NiKeyframeData *data) - : KeyframeController(data) - , mEnabled(false) -{ -} - -SourcedKeyframeController::SourcedKeyframeController() - : mEnabled(false) -{ -} - -SourcedKeyframeController::SourcedKeyframeController(const SourcedKeyframeController ©, const osg::CopyOp ©op) - : KeyframeController(copy, copyop) - , mEnabled(copy.mEnabled) -{ -} - -void SourcedKeyframeController::setEnabled(bool enabled) -{ - mEnabled = enabled; -} - -void SourcedKeyframeController::operator ()(osg::Node* node, osg::NodeVisitor* nv) -{ - if (mEnabled) - KeyframeController::operator()(node, nv); // calls traverse - else - traverse(node, nv); -} - } diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index e480f4c13..d32c9f977 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -94,7 +94,7 @@ namespace NifOsg public: ControllerFunction(const Nif::Controller *ctrl); - float calculate(float value); + float calculate(float value) const; virtual float getMaximum() const; }; @@ -144,26 +144,6 @@ namespace NifOsg osg::Quat getXYZRotation(float time) const; }; - // Specialization that can be enabled/disabled. Used for multiple animation sources support, i.e. .kf files. - // A SourcedKeyframeController is disabled by default and should be manually enabled when playing an animation from - // the relevant animation source. - class SourcedKeyframeController : public KeyframeController - { - public: - SourcedKeyframeController(const Nif::NiKeyframeData* data); - SourcedKeyframeController(); - SourcedKeyframeController(const SourcedKeyframeController& copy, const osg::CopyOp& copyop); - - META_Object(NifOsg, SourcedKeyframeController) - - virtual void operator() (osg::Node*, osg::NodeVisitor*); - - void setEnabled(bool enabled); - - private: - bool mEnabled; - }; - class UVController : public SceneUtil::StateSetUpdater, public SceneUtil::Controller, public ValueInterpolator { public: diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 63a3ee887..3b3ae4b2c 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -253,44 +253,6 @@ namespace } }; - // NodeVisitor that adds keyframe controllers to an existing scene graph, used when loading .kf files - /* - class LoadKfVisitor : public osg::NodeVisitor - { - public: - LoadKfVisitor(std::map map, int sourceIndex) - : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) - , mMap(map) - , mSourceIndex(sourceIndex) - { - } - - void apply(osg::Node &node) - { - std::map::const_iterator found = mMap.find(node.getName()); - if (node.asTransform() && found != mMap.end()) - { - const Nif::NiKeyframeController* keyframectrl = found->second; - - osg::ref_ptr callback(new NifOsg::SourcedKeyframeController(keyframectrl->data.getPtr(), mSourceIndex)); - callback->mFunction = boost::shared_ptr(new NifOsg::ControllerFunction(keyframectrl)); - - // Insert in front of the callback list, to make sure UpdateBone is last. - // The order of SourcedKeyframeControllers doesn't matter since only one of them should be enabled at a time. - osg::ref_ptr old = node.getUpdateCallback(); - node.setUpdateCallback(callback); - callback->setNestedCallback(old); - } - - traverse(node); - } - - private: - std::map mMap; - int mSourceIndex; - }; - */ - struct UpdateMorphGeometry : public osg::Drawable::CullCallback { UpdateMorphGeometry() @@ -450,7 +412,7 @@ namespace NifOsg if(key->data.empty()) continue; - osg::ref_ptr callback(new NifOsg::SourcedKeyframeController(key->data.getPtr())); + osg::ref_ptr callback(new NifOsg::KeyframeController(key->data.getPtr())); callback->mFunction = boost::shared_ptr(new NifOsg::ControllerFunction(key)); target.mKeyframeControllers[strdata->string] = callback; @@ -1007,7 +969,6 @@ namespace NifOsg geometry = new osg::Geometry; osg::ref_ptr geode (new osg::Geode); - geode->setName(triShape->name); // name will be used for part filtering triShapeToGeometry(triShape, geometry, geode, boundTextures, animflags); geode->addDrawable(geometry); @@ -1103,7 +1064,7 @@ namespace NifOsg static void handleSkinnedTriShape(const Nif::NiTriShape *triShape, osg::Group *parentNode, const std::map& boundTextures, int animflags) { osg::ref_ptr geode (new osg::Geode); - geode->setName(triShape->name); // name will be used for part filtering + osg::ref_ptr geometry (new osg::Geometry); triShapeToGeometry(triShape, geometry, geode, boundTextures, animflags); diff --git a/components/nifosg/nifloader.hpp b/components/nifosg/nifloader.hpp index 678b8cc64..b6e9b1c8f 100644 --- a/components/nifosg/nifloader.hpp +++ b/components/nifosg/nifloader.hpp @@ -44,7 +44,7 @@ namespace NifOsg public: TextKeyMap mTextKeys; - std::map > mKeyframeControllers; + std::map > mKeyframeControllers; }; /// The main class responsible for loading NIF files into an OSG-Scenegraph. diff --git a/components/sceneutil/controller.hpp b/components/sceneutil/controller.hpp index a4e209e8c..378837ad7 100644 --- a/components/sceneutil/controller.hpp +++ b/components/sceneutil/controller.hpp @@ -21,10 +21,11 @@ namespace SceneUtil virtual float getValue(osg::NodeVisitor* nv); }; + /// @note ControllerFunctions may be shared - you should not hold any state in it. That is why all its methods are declared const. class ControllerFunction { public: - virtual float calculate(float input) = 0; + virtual float calculate(float input) const = 0; /// Get the "stop time" of the controller function, typically the maximum of the calculate() function. /// May not be meaningful for all types of controller functions. From 6fcf4ea9e3fdf445ba282a029f63b4d84ac1d8c4 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 23 Apr 2015 14:24:43 +0200 Subject: [PATCH 1009/3725] In ModifyCommand replace proxy model with the source model (Fixes #2498) --- apps/opencs/model/world/commands.cpp | 21 +++++++++++++++------ apps/opencs/model/world/commands.hpp | 2 +- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/apps/opencs/model/world/commands.cpp b/apps/opencs/model/world/commands.cpp index d12c5d228..ce82e07bf 100644 --- a/apps/opencs/model/world/commands.cpp +++ b/apps/opencs/model/world/commands.cpp @@ -1,28 +1,37 @@ #include "commands.hpp" +#include + #include +#include #include "idtable.hpp" #include "idtree.hpp" -#include #include "nestedtablewrapper.hpp" CSMWorld::ModifyCommand::ModifyCommand (QAbstractItemModel& model, const QModelIndex& index, const QVariant& new_, QUndoCommand* parent) -: QUndoCommand (parent), mModel (model), mIndex (index), mNew (new_) +: QUndoCommand (parent), mModel (&model), mIndex (index), mNew (new_) { - setText ("Modify " + mModel.headerData (mIndex.column(), Qt::Horizontal, Qt::DisplayRole).toString()); + if (QAbstractProxyModel *proxy = dynamic_cast (&model)) + { + // Replace proxy with actual model + mIndex = proxy->mapToSource (index); + mModel = proxy->sourceModel(); + } + + setText ("Modify " + mModel->headerData (mIndex.column(), Qt::Horizontal, Qt::DisplayRole).toString()); } void CSMWorld::ModifyCommand::redo() { - mOld = mModel.data (mIndex, Qt::EditRole); - mModel.setData (mIndex, mNew); + mOld = mModel->data (mIndex, Qt::EditRole); + mModel->setData (mIndex, mNew); } void CSMWorld::ModifyCommand::undo() { - mModel.setData (mIndex, mOld); + mModel->setData (mIndex, mOld); } diff --git a/apps/opencs/model/world/commands.hpp b/apps/opencs/model/world/commands.hpp index a70b36178..2bd47ae91 100644 --- a/apps/opencs/model/world/commands.hpp +++ b/apps/opencs/model/world/commands.hpp @@ -26,7 +26,7 @@ namespace CSMWorld class ModifyCommand : public QUndoCommand { - QAbstractItemModel& mModel; + QAbstractItemModel *mModel; QModelIndex mIndex; QVariant mNew; QVariant mOld; From 12f3198f680e3f189b5b0fa37b239dee7a0414a5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 23 Apr 2015 17:15:30 +0200 Subject: [PATCH 1010/3725] Node name lookups should be case insensitive Concerns "AttachLight", "BoneOffset" and equipment part attachment points, that are all case insensitive in vanilla MW. --- components/sceneutil/controller.hpp | 2 +- components/sceneutil/visitor.hpp | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/components/sceneutil/controller.hpp b/components/sceneutil/controller.hpp index 378837ad7..6086663bd 100644 --- a/components/sceneutil/controller.hpp +++ b/components/sceneutil/controller.hpp @@ -65,7 +65,7 @@ namespace SceneUtil AssignControllerSourcesVisitor(); AssignControllerSourcesVisitor(boost::shared_ptr toAssign); - /// Assign the wanted ControllerSource. May be overriden in derived classes. + /// Assign the wanted ControllerSource. May be overridden in derived classes. /// By default assigns the ControllerSource passed to the constructor of this class if no ControllerSource is assigned to that controller yet. virtual void visit(osg::Node& node, Controller& ctrl); diff --git a/components/sceneutil/visitor.hpp b/components/sceneutil/visitor.hpp index 6bb8b2e35..b9342b884 100644 --- a/components/sceneutil/visitor.hpp +++ b/components/sceneutil/visitor.hpp @@ -3,6 +3,8 @@ #include +#include + // Commonly used scene graph visitors namespace SceneUtil { @@ -19,7 +21,7 @@ namespace SceneUtil virtual void apply(osg::Group& group) { - if (group.getName() == mNameToFind) + if (Misc::StringUtils::ciEqual(group.getName(), mNameToFind)) { mFoundNode = &group; return; From 6fada6acf896b4e68bc487e2500c5b53af4be856 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 23 Apr 2015 20:02:18 +0200 Subject: [PATCH 1011/3725] Remove tests for no longer existing code --- components/misc/tests/.gitignore | 1 - components/misc/tests/Makefile | 12 ----- components/misc/tests/output/slice_test.out | 6 --- components/misc/tests/output/strops_test.out | 0 components/misc/tests/slice_test.cpp | 28 ------------ components/misc/tests/strops_test.cpp | 48 -------------------- components/misc/tests/test.sh | 18 -------- 7 files changed, 113 deletions(-) delete mode 100644 components/misc/tests/.gitignore delete mode 100644 components/misc/tests/Makefile delete mode 100644 components/misc/tests/output/slice_test.out delete mode 100644 components/misc/tests/output/strops_test.out delete mode 100644 components/misc/tests/slice_test.cpp delete mode 100644 components/misc/tests/strops_test.cpp delete mode 100755 components/misc/tests/test.sh diff --git a/components/misc/tests/.gitignore b/components/misc/tests/.gitignore deleted file mode 100644 index 814490404..000000000 --- a/components/misc/tests/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*_test diff --git a/components/misc/tests/Makefile b/components/misc/tests/Makefile deleted file mode 100644 index dc1ded5ff..000000000 --- a/components/misc/tests/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -GCC=g++ - -all: strops_test slice_test - -slice_test: slice_test.cpp ../slice_array.hpp - $(GCC) $< -o $@ - -strops_test: strops_test.cpp ../stringops.hpp ../stringops.cpp - $(GCC) $< -o $@ ../stringops.cpp - -clean: - rm *_test diff --git a/components/misc/tests/output/slice_test.out b/components/misc/tests/output/slice_test.out deleted file mode 100644 index 7b054082b..000000000 --- a/components/misc/tests/output/slice_test.out +++ /dev/null @@ -1,6 +0,0 @@ -hello, len=5 -001 -hell, len=4 -010 -01 -4 3 diff --git a/components/misc/tests/output/strops_test.out b/components/misc/tests/output/strops_test.out deleted file mode 100644 index e69de29bb..000000000 diff --git a/components/misc/tests/slice_test.cpp b/components/misc/tests/slice_test.cpp deleted file mode 100644 index 0d9d7b4ab..000000000 --- a/components/misc/tests/slice_test.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#include - -using namespace std; - -#include "../slice_array.hpp" - -int main() -{ - Misc::SString s, t; - s = Misc::SString("hello"); - cout << s.toString() << ", len=" << s.length << endl; - cout << (s=="hel") << (s=="hell") << (s=="hello") << endl; - t = s; - - s = Misc::SString("othello"+2, 4); - cout << s.toString() << ", len=" << s.length << endl; - cout << (s=="hel") << (s=="hell") << (s=="hello") << endl; - - cout << (s==t) << (Misc::SString("hello")==t) << endl; - - const int arr[4] = {1,2,3,4}; - - Misc::IntArray ia(arr,4); - - cout << ia.length << " " << ia.ptr[2] << endl; - - return 0; -} diff --git a/components/misc/tests/strops_test.cpp b/components/misc/tests/strops_test.cpp deleted file mode 100644 index 24ab8a298..000000000 --- a/components/misc/tests/strops_test.cpp +++ /dev/null @@ -1,48 +0,0 @@ -#include - -#include "../stringops.hpp" - -int main() -{ - assert(Misc::begins("abc", "a")); - assert(Misc::begins("abc", "ab")); - assert(Misc::begins("abc", "abc")); - assert(Misc::begins("abcd", "abc")); - - assert(!Misc::begins("abc", "b")); - assert(!Misc::begins("abc", "bc")); - assert(!Misc::begins("abc", "bcd")); - assert(!Misc::begins("abc", "abcd")); - - assert(Misc::ibegins("Abc", "a")); - assert(Misc::ibegins("aBc", "ab")); - assert(Misc::ibegins("abC", "abc")); - assert(Misc::ibegins("abcD", "abc")); - - assert(!Misc::ibegins("abc", "b")); - assert(!Misc::ibegins("abc", "bc")); - assert(!Misc::ibegins("abc", "bcd")); - assert(!Misc::ibegins("abc", "abcd")); - - assert(Misc::ends("abc", "c")); - assert(Misc::ends("abc", "bc")); - assert(Misc::ends("abc", "abc")); - assert(Misc::ends("abcd", "abcd")); - - assert(!Misc::ends("abc", "b")); - assert(!Misc::ends("abc", "ab")); - assert(!Misc::ends("abc", "bcd")); - assert(!Misc::ends("abc", "abcd")); - - assert(Misc::iends("Abc", "c")); - assert(Misc::iends("aBc", "bc")); - assert(Misc::iends("abC", "abc")); - assert(Misc::iends("abcD", "abcd")); - - assert(!Misc::iends("abc", "b")); - assert(!Misc::iends("abc", "ab")); - assert(!Misc::iends("abc", "bcd")); - assert(!Misc::iends("abc", "abcd")); - - return 0; -} diff --git a/components/misc/tests/test.sh b/components/misc/tests/test.sh deleted file mode 100755 index 2d07708ad..000000000 --- a/components/misc/tests/test.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash - -make || exit - -mkdir -p output - -PROGS=*_test - -for a in $PROGS; do - if [ -f "output/$a.out" ]; then - echo "Running $a:" - ./$a | diff output/$a.out - - else - echo "Creating $a.out" - ./$a > "output/$a.out" - git add "output/$a.out" - fi -done From 09742d5b957b656459c9cf2f69e00d6c14236117 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 23 Apr 2015 20:41:31 +0200 Subject: [PATCH 1012/3725] Animation playback works, no movement accumulation yet --- apps/openmw/mwrender/animation.cpp | 683 ++++++++++++++++++++- apps/openmw/mwrender/animation.hpp | 105 ++-- apps/openmw/mwrender/creatureanimation.cpp | 16 +- apps/openmw/mwrender/npcanimation.cpp | 2 - apps/openmw/mwrender/objects.cpp | 1 + components/nifosg/nifloader.cpp | 6 +- components/nifosg/nifloader.hpp | 3 +- components/sceneutil/controller.cpp | 28 +- components/sceneutil/controller.hpp | 7 + 9 files changed, 791 insertions(+), 60 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 75d409aec..d291e0fd0 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1,11 +1,13 @@ #include "animation.hpp" #include +#include #include #include #include #include +#include #include @@ -13,6 +15,10 @@ #include #include +#include // KeyframeHolder + +#include + #include #include @@ -74,6 +80,89 @@ namespace std::vector > mTextures; }; + class NodeMapVisitor : public osg::NodeVisitor + { + public: + NodeMapVisitor() : osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {} + + void apply(osg::MatrixTransform& trans) + { + mMap[Misc::StringUtils::lowerCase(trans.getName())] = &trans; + traverse(trans); + } + + typedef std::map > NodeMap; + + const NodeMap& getNodeMap() const + { + return mMap; + } + + private: + NodeMap mMap; + }; + + NifOsg::TextKeyMap::const_iterator findGroupStart(const NifOsg::TextKeyMap &keys, const std::string &groupname) + { + NifOsg::TextKeyMap::const_iterator iter(keys.begin()); + for(;iter != keys.end();++iter) + { + if(iter->second.compare(0, groupname.size(), groupname) == 0 && + iter->second.compare(groupname.size(), 2, ": ") == 0) + break; + } + return iter; + } + + float calcAnimVelocity(const std::multimap& keys, + NifOsg::KeyframeController *nonaccumctrl, const osg::Vec3f& accum, const std::string &groupname) + { + const std::string start = groupname+": start"; + const std::string loopstart = groupname+": loop start"; + const std::string loopstop = groupname+": loop stop"; + const std::string stop = groupname+": stop"; + float starttime = std::numeric_limits::max(); + float stoptime = 0.0f; + + // Pick the last Loop Stop key and the last Loop Start key. + // This is required because of broken text keys in AshVampire.nif. + // It has *two* WalkForward: Loop Stop keys at different times, the first one is used for stopping playback + // but the animation velocity calculation uses the second one. + // As result the animation velocity calculation is not correct, and this incorrect velocity must be replicated, + // because otherwise the Creature's Speed (dagoth uthol) would not be sufficient to move fast enough. + NifOsg::TextKeyMap::const_reverse_iterator keyiter(keys.rbegin()); + while(keyiter != keys.rend()) + { + if(keyiter->second == start || keyiter->second == loopstart) + { + starttime = keyiter->first; + break; + } + ++keyiter; + } + keyiter = keys.rbegin(); + while(keyiter != keys.rend()) + { + if (keyiter->second == stop) + stoptime = keyiter->first; + else if (keyiter->second == loopstop) + { + stoptime = keyiter->first; + break; + } + ++keyiter; + } + + if(stoptime > starttime) + { + osg::Vec3f startpos = osg::componentMultiply(nonaccumctrl->getTranslation(starttime), accum); + osg::Vec3f endpos = osg::componentMultiply(nonaccumctrl->getTranslation(stoptime), accum); + + return (startpos-endpos).length() / (stoptime - starttime); + } + + return 0.0f; + } } namespace MWRender @@ -84,7 +173,8 @@ namespace MWRender , mInsert(parentNode) , mResourceSystem(resourceSystem) { - + for(size_t i = 0;i < sNumGroups;i++) + mAnimationTimePtr[i].reset(new AnimationTime(this)); } Animation::~Animation() @@ -98,16 +188,589 @@ namespace MWRender mPtr = ptr; } + void Animation::setAccumulation(const osg::Vec3f& accum) + { + mAccumulate = accum; + } + + size_t Animation::detectAnimGroup(osg::Node* node) + { + static const char sGroupRoots[sNumGroups][32] = { + "", /* Lower body / character root */ + "Bip01 Spine1", /* Torso */ + "Bip01 L Clavicle", /* Left arm */ + "Bip01 R Clavicle", /* Right arm */ + }; + + while(node != mObjectRoot) + { + const std::string &name = node->getName(); + for(size_t i = 1;i < sNumGroups;i++) + { + if(name == sGroupRoots[i]) + return i; + } + + assert(node->getNumParents() > 0); + + node = node->getParent(0); + } + + return 0; + } + + const std::multimap &Animation::AnimSource::getTextKeys() + { + return mKeyframes->mTextKeys; + } + void Animation::addAnimSource(const std::string &model) { + std::string kfname = model; + Misc::StringUtils::toLower(kfname); + + if(kfname.size() > 4 && kfname.compare(kfname.size()-4, 4, ".nif") == 0) + kfname.replace(kfname.size()-4, 4, ".kf"); + + if(!mResourceSystem->getVFS()->exists(kfname)) + return; + + boost::shared_ptr animsrc; + animsrc.reset(new AnimSource); + animsrc->mKeyframes = mResourceSystem->getSceneManager()->getKeyframes(kfname); + + if (animsrc->mKeyframes->mTextKeys.empty() || animsrc->mKeyframes->mKeyframeControllers.empty()) + return; + + for (NifOsg::KeyframeHolder::KeyframeControllerMap::const_iterator it = animsrc->mKeyframes->mKeyframeControllers.begin(); + it != animsrc->mKeyframes->mKeyframeControllers.end(); ++it) + { + std::string bonename = Misc::StringUtils::lowerCase(it->first); + NodeMap::const_iterator found = mNodeMap.find(bonename); + if (found == mNodeMap.end()) + throw std::runtime_error("addAnimSource: can't find bone " + bonename); + + osg::Node* node = found->second; + + size_t group = detectAnimGroup(node); + + // clone the controller, because each Animation needs its own ControllerSource + osg::ref_ptr cloned = osg::clone(it->second.get(), osg::CopyOp::DEEP_COPY_ALL); + cloned->setSource(mAnimationTimePtr[group]); + + animsrc->mControllerMap[group].insert(std::make_pair(bonename, cloned)); + } + + mAnimSources.push_back(animsrc); + SceneUtil::AssignControllerSourcesVisitor assignVisitor(mAnimationTimePtr[0]); + mObjectRoot->accept(assignVisitor); + + if (!mAccumRoot) + { + NodeMap::const_iterator found = mNodeMap.find("root bone"); + if (found == mNodeMap.end()) + found = mNodeMap.find("bip01"); + + if (found != mNodeMap.end()) + mAccumRoot = found->second; + } + } + + bool Animation::hasAnimation(const std::string &anim) + { + AnimSourceList::const_iterator iter(mAnimSources.begin()); + for(;iter != mAnimSources.end();++iter) + { + const NifOsg::TextKeyMap &keys = (*iter)->getTextKeys(); + if(findGroupStart(keys, anim) != keys.end()) + return true; + } + + return false; + } + + float Animation::getStartTime(const std::string &groupname) const + { + for(AnimSourceList::const_iterator iter(mAnimSources.begin()); iter != mAnimSources.end(); ++iter) + { + const NifOsg::TextKeyMap &keys = (*iter)->getTextKeys(); + + NifOsg::TextKeyMap::const_iterator found = findGroupStart(keys, groupname); + if(found != keys.end()) + return found->first; + } + return -1.f; + } + + float Animation::getTextKeyTime(const std::string &textKey) const + { + for(AnimSourceList::const_iterator iter(mAnimSources.begin()); iter != mAnimSources.end(); ++iter) + { + const NifOsg::TextKeyMap &keys = (*iter)->getTextKeys(); + + for(NifOsg::TextKeyMap::const_iterator iterKey(keys.begin()); iterKey != keys.end(); ++iterKey) + { + if(iterKey->second.compare(0, textKey.size(), textKey) == 0) + return iterKey->first; + } + } + + return -1.f; + } + + void Animation::handleTextKey(AnimState &state, const std::string &groupname, const std::multimap::const_iterator &key, + const std::multimap& map) + { + // TODO: forward to listener? + } + + void Animation::play(const std::string &groupname, int priority, int groups, bool autodisable, float speedmult, + const std::string &start, const std::string &stop, float startpoint, size_t loops, bool loopfallback) + { + if(!mObjectRoot || mAnimSources.empty()) + return; + + if(groupname.empty()) + { + resetActiveGroups(); + return; + } + + priority = std::max(0, priority); + + AnimStateMap::iterator stateiter = mStates.begin(); + while(stateiter != mStates.end()) + { + if(stateiter->second.mPriority == priority) + mStates.erase(stateiter++); + else + ++stateiter; + } + + stateiter = mStates.find(groupname); + if(stateiter != mStates.end()) + { + stateiter->second.mPriority = priority; + resetActiveGroups(); + return; + } + + /* Look in reverse; last-inserted source has priority. */ + AnimState state; + AnimSourceList::reverse_iterator iter(mAnimSources.rbegin()); + for(;iter != mAnimSources.rend();++iter) + { + const NifOsg::TextKeyMap &textkeys = (*iter)->getTextKeys(); + if(reset(state, textkeys, groupname, start, stop, startpoint, loopfallback)) + { + state.mSource = *iter; + state.mSpeedMult = speedmult; + state.mLoopCount = loops; + state.mPlaying = (state.mTime < state.mStopTime); + state.mPriority = priority; + state.mGroups = groups; + state.mAutoDisable = autodisable; + mStates[groupname] = state; + + NifOsg::TextKeyMap::const_iterator textkey(textkeys.lower_bound(state.mTime)); + if (state.mPlaying) + { + while(textkey != textkeys.end() && textkey->first <= state.mTime) + { + handleTextKey(state, groupname, textkey, textkeys); + ++textkey; + } + } + + if(state.mTime >= state.mLoopStopTime && state.mLoopCount > 0) + { + state.mLoopCount--; + state.mTime = state.mLoopStartTime; + state.mPlaying = true; + if(state.mTime >= state.mLoopStopTime) + break; + + NifOsg::TextKeyMap::const_iterator textkey(textkeys.lower_bound(state.mTime)); + while(textkey != textkeys.end() && textkey->first <= state.mTime) + { + handleTextKey(state, groupname, textkey, textkeys); + ++textkey; + } + } + + break; + } + } + if(iter == mAnimSources.rend()) + std::cerr<< "Failed to find animation "<setPosition(-mNonAccumCtrl->getTranslation(state.mTime)*mAccumulate); + } + */ + } + + bool Animation::reset(AnimState &state, const NifOsg::TextKeyMap &keys, const std::string &groupname, const std::string &start, const std::string &stop, float startpoint, bool loopfallback) + { + // Look for text keys in reverse. This normally wouldn't matter, but for some reason undeadwolf_2.nif has two + // separate walkforward keys, and the last one is supposed to be used. + NifOsg::TextKeyMap::const_reverse_iterator groupend(keys.rbegin()); + for(;groupend != keys.rend();++groupend) + { + if(groupend->second.compare(0, groupname.size(), groupname) == 0 && + groupend->second.compare(groupname.size(), 2, ": ") == 0) + break; + } + + std::string starttag = groupname+": "+start; + NifOsg::TextKeyMap::const_reverse_iterator startkey(groupend); + while(startkey != keys.rend() && startkey->second != starttag) + ++startkey; + if(startkey == keys.rend() && start == "loop start") + { + starttag = groupname+": start"; + startkey = groupend; + while(startkey != keys.rend() && startkey->second != starttag) + ++startkey; + } + if(startkey == keys.rend()) + return false; + + const std::string stoptag = groupname+": "+stop; + NifOsg::TextKeyMap::const_reverse_iterator stopkey(groupend); + while(stopkey != keys.rend() + // We have to ignore extra garbage at the end. + // The Scrib's idle3 animation has "Idle3: Stop." instead of "Idle3: Stop". + // Why, just why? :( + && (stopkey->second.size() < stoptag.size() || stopkey->second.substr(0,stoptag.size()) != stoptag)) + ++stopkey; + if(stopkey == keys.rend()) + return false; + + if(startkey->first > stopkey->first) + return false; + + state.mStartTime = startkey->first; + if (loopfallback) + { + state.mLoopStartTime = startkey->first; + state.mLoopStopTime = stopkey->first; + } + else + { + state.mLoopStartTime = startkey->first; + state.mLoopStopTime = std::numeric_limits::max(); + } + state.mStopTime = stopkey->first; + + state.mTime = state.mStartTime + ((state.mStopTime - state.mStartTime) * startpoint); + + // mLoopStartTime and mLoopStopTime normally get assigned when encountering these keys while playing the animation + // (see handleTextKey). But if startpoint is already past these keys, we need to assign them now. + if(state.mTime > state.mStartTime) + { + const std::string loopstarttag = groupname+": loop start"; + const std::string loopstoptag = groupname+": loop stop"; + + NifOsg::TextKeyMap::const_reverse_iterator key(groupend); + for (; key != startkey && key != keys.rend(); ++key) + { + if (key->first > state.mTime) + continue; + + if (key->second == loopstarttag) + state.mLoopStartTime = key->first; + else if (key->second == loopstoptag) + state.mLoopStopTime = key->first; + } + } + + return true; + } + + void Animation::resetActiveGroups() + { + // remove all previous external controllers from the scene graph + for (AnimSourceControllerMap::iterator it = mAnimSourceControllers.begin(); it != mAnimSourceControllers.end(); ++it) + { + osg::Node* node = it->first; + node->removeUpdateCallback(it->second); + } + mAnimSourceControllers.clear(); + + mAccumCtrl = NULL; + + for(size_t grp = 0;grp < sNumGroups;grp++) + { + AnimStateMap::const_iterator active = mStates.end(); + + AnimStateMap::const_iterator state = mStates.begin(); + for(;state != mStates.end();++state) + { + if(!(state->second.mGroups&(1<second.mPriority < state->second.mPriority) + active = state; + } + + mAnimationTimePtr[grp]->setAnimName((active == mStates.end()) ? + std::string() : active->first); + + // add external controllers for the AnimSource active in this group + if (active != mStates.end()) + { + boost::shared_ptr animsrc = active->second.mSource; + + for (AnimSource::ControllerMap::iterator it = animsrc->mControllerMap[grp].begin(); it != animsrc->mControllerMap[grp].end(); ++it) + { + osg::ref_ptr node = mNodeMap.at(it->first); // this should not throw, we already checked for the node existing in addAnimSource + + node->addUpdateCallback(it->second); + mAnimSourceControllers[node] = it->second; + + if (grp == 0 && node == mAccumRoot) + mAccumCtrl = it->second; + } + } + } + + //if(!mNonAccumRoot || mAccumulate == Ogre::Vector3(0.0f)) + // return; + + /* + AnimStateMap::const_iterator state = mStates.find(mAnimationTimePtr[0]->getAnimName()); + if(state == mStates.end()) + { + //if (mAccumRoot && mNonAccumRoot) + // mAccumRoot->setPosition(-mNonAccumRoot->getPosition()*mAccumulate); + return; + } + */ + + //if (mAccumRoot && mNonAccumCtrl) + // mAccumRoot->setPosition(-mNonAccumCtrl->getTranslation(state->second.mTime)*mAccumulate); + } + + void Animation::changeGroups(const std::string &groupname, int groups) + { + AnimStateMap::iterator stateiter = mStates.find(groupname); + if(stateiter != mStates.end()) + { + if(stateiter->second.mGroups != groups) + { + stateiter->second.mGroups = groups; + resetActiveGroups(); + } + return; + } + } + + void Animation::stopLooping(const std::string& groupname) + { + AnimStateMap::iterator stateiter = mStates.find(groupname); + if(stateiter != mStates.end()) + { + stateiter->second.mLoopCount = 0; + return; + } + } + + void Animation::adjustSpeedMult(const std::string &groupname, float speedmult) + { + AnimStateMap::iterator state(mStates.find(groupname)); + if(state != mStates.end()) + state->second.mSpeedMult = speedmult; + } + + bool Animation::isPlaying(const std::string &groupname) const + { + AnimStateMap::const_iterator state(mStates.find(groupname)); + if(state != mStates.end()) + return state->second.mPlaying; + return false; + } + + bool Animation::getInfo(const std::string &groupname, float *complete, float *speedmult) const + { + AnimStateMap::const_iterator iter = mStates.find(groupname); + if(iter == mStates.end()) + { + if(complete) *complete = 0.0f; + if(speedmult) *speedmult = 0.0f; + return false; + } + + if(complete) + { + if(iter->second.mStopTime > iter->second.mStartTime) + *complete = (iter->second.mTime - iter->second.mStartTime) / + (iter->second.mStopTime - iter->second.mStartTime); + else + *complete = (iter->second.mPlaying ? 0.0f : 1.0f); + } + if(speedmult) *speedmult = iter->second.mSpeedMult; + return true; + } + + float Animation::getCurrentTime(const std::string &groupname) const + { + AnimStateMap::const_iterator iter = mStates.find(groupname); + if(iter == mStates.end()) + return -1.f; + + return iter->second.mTime; + } + + void Animation::disable(const std::string &groupname) + { + AnimStateMap::iterator iter = mStates.find(groupname); + if(iter != mStates.end()) + mStates.erase(iter); + resetActiveGroups(); + } + + float Animation::getVelocity(const std::string &groupname) const + { + return 0.f; + /* + // Look in reverse; last-inserted source has priority. + AnimSourceList::const_reverse_iterator animsrc(mAnimSources.rbegin()); + for(;animsrc != mAnimSources.rend();++animsrc) + { + const NifOsg::TextKeyMap &keys = (*animsrc)->mTextKeys; + if(findGroupStart(keys, groupname) != keys.end()) + break; + } + if(animsrc == mAnimSources.rend()) + return 0.0f; + + float velocity = 0.0f; + const NifOsg::TextKeyMap &keys = (*animsrc)->mTextKeys; + const std::vector >&ctrls = (*animsrc)->mControllers[0]; + for(size_t i = 0;i < ctrls.size();i++) + { + NifOsg::NodeTargetValue *dstval; + dstval = static_cast*>(ctrls[i].getDestination().getPointer()); + if(dstval->getNode() == mNonAccumRoot) + { + velocity = calcAnimVelocity(keys, dstval, mAccumulate, groupname); + break; + } + } + + // If there's no velocity, keep looking + if(!(velocity > 1.0f)) + { + AnimSourceList::const_reverse_iterator animiter = mAnimSources.rbegin(); + while(*animiter != *animsrc) + ++animiter; + + while(!(velocity > 1.0f) && ++animiter != mAnimSources.rend()) + { + const NifOgre::TextKeyMap &keys = (*animiter)->mTextKeys; + const std::vector >&ctrls = (*animiter)->mControllers[0]; + for(size_t i = 0;i < ctrls.size();i++) + { + NifOgre::NodeTargetValue *dstval; + dstval = static_cast*>(ctrls[i].getDestination().getPointer()); + if(dstval->getNode() == mNonAccumRoot) + { + velocity = calcAnimVelocity(keys, dstval, mAccumulate, groupname); + break; + } + } + } + } + + return velocity; + */ } osg::Vec3f Animation::runAnimation(float duration) { + osg::Vec3f movement(0.f, 0.f, 0.f); + AnimStateMap::iterator stateiter = mStates.begin(); + while(stateiter != mStates.end()) + { + AnimState &state = stateiter->second; + const NifOsg::TextKeyMap &textkeys = state.mSource->getTextKeys(); + NifOsg::TextKeyMap::const_iterator textkey(textkeys.upper_bound(state.mTime)); + + float timepassed = duration * state.mSpeedMult; + while(state.mPlaying) + { + float targetTime; + + if(state.mTime >= state.mLoopStopTime && state.mLoopCount > 0) + goto handle_loop; + + targetTime = state.mTime + timepassed; + if(textkey == textkeys.end() || textkey->first > targetTime) + { + //if(mNonAccumCtrl && stateiter->first == mAnimationTimePtr[0]->getAnimName()) + // updatePosition(state.mTime, targetTime, movement); + state.mTime = std::min(targetTime, state.mStopTime); + } + else + { + //if(mNonAccumCtrl && stateiter->first == mAnimationTimePtr[0]->getAnimName()) + // updatePosition(state.mTime, textkey->first, movement); + state.mTime = textkey->first; + } + + state.mPlaying = (state.mTime < state.mStopTime); + timepassed = targetTime - state.mTime; + + while(textkey != textkeys.end() && textkey->first <= state.mTime) + { + handleTextKey(state, stateiter->first, textkey, textkeys); + ++textkey; + } + + if(state.mTime >= state.mLoopStopTime && state.mLoopCount > 0) + { + handle_loop: + state.mLoopCount--; + state.mTime = state.mLoopStartTime; + state.mPlaying = true; + + textkey = textkeys.lower_bound(state.mTime); + while(textkey != textkeys.end() && textkey->first <= state.mTime) + { + handleTextKey(state, stateiter->first, textkey, textkeys); + ++textkey; + } + + if(state.mTime >= state.mLoopStopTime) + break; + } + + if(timepassed <= 0.0f) + break; + } + + if(!state.mPlaying && state.mAutoDisable) + { + mStates.erase(stateiter++); + + resetActiveGroups(); + } + else + ++stateiter; + } + updateEffects(duration); - return osg::Vec3f(); + return movement; } void Animation::setObjectRoot(const std::string &model) @@ -117,7 +780,14 @@ namespace MWRender mObjectRoot->getParent(0)->removeChild(mObjectRoot); } + mNodeMap.clear(); + mAnimSourceControllers.clear(); + mObjectRoot = mResourceSystem->getSceneManager()->createInstance(model, mInsert); + + NodeMapVisitor visitor; + mObjectRoot->accept(visitor); + mNodeMap = visitor.getNodeMap(); } osg::Group* Animation::getObjectRoot() @@ -318,6 +988,15 @@ namespace MWRender } } + float Animation::AnimationTime::getValue(osg::NodeVisitor*) + { + // FIXME: hold a pointer instead of searching every frame + AnimStateMap::const_iterator iter = mAnimation->mStates.find(mAnimationName); + if(iter != mAnimation->mStates.end()) + return iter->second.mTime; + return 0.0f; + } + float EffectAnimationTime::getValue(osg::NodeVisitor*) { return mTime; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index ea47a5b79..a04544ac8 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -15,9 +15,13 @@ namespace Resource class ResourceSystem; } +namespace NifOsg +{ + class KeyframeHolder; +} + namespace MWRender { -class Camera; class EffectAnimationTime : public SceneUtil::ControllerSource { @@ -68,7 +72,7 @@ protected: const std::string &getAnimName() const { return mAnimationName; } - virtual float getValue(); + virtual float getValue(osg::NodeVisitor* nv); }; class NullAnimationTime : public SceneUtil::ControllerSource @@ -80,16 +84,19 @@ protected: } }; + struct AnimSource + { + osg::ref_ptr mKeyframes; + + typedef std::map > ControllerMap; - /* - struct AnimSource : public Ogre::AnimationAlloc { - //NifOgre::TextKeyMap mTextKeys; - std::vector > mControllers[sNumGroups]; + ControllerMap mControllerMap[sNumGroups]; + + const std::multimap& getTextKeys(); }; - typedef std::vector< Ogre::SharedPtr > AnimSourceList; - */ + struct AnimState { - //Ogre::SharedPtr mSource; + boost::shared_ptr mSource; float mStartTime; float mLoopStartTime; float mLoopStopTime; @@ -111,15 +118,38 @@ protected: { } }; typedef std::map AnimStateMap; + AnimStateMap mStates; + + typedef std::vector > AnimSourceList; + AnimSourceList mAnimSources; osg::ref_ptr mInsert; osg::ref_ptr mObjectRoot; + // The node expected to accumulate movement during movement animations. + osg::ref_ptr mAccumRoot; + + // The controller animating that node. + osg::ref_ptr mAccumCtrl; + + // Keep track of keyframe controllers from external files that we added to our scene graph. + // We may need to rebuild these controllers when the active animation groups / sources change. + typedef std::map, osg::ref_ptr > AnimSourceControllerMap; + AnimSourceControllerMap mAnimSourceControllers; + + boost::shared_ptr mAnimationTimePtr[sNumGroups]; + + // Stored in all lowercase for a case-insensitive lookup + typedef std::map > NodeMap; + NodeMap mNodeMap; + MWWorld::Ptr mPtr; Resource::ResourceSystem* mResourceSystem; + osg::Vec3f mAccumulate; + /// @brief Detaches the node from its parent when the object goes out of scope. class PartHolder { @@ -160,34 +190,25 @@ protected: /* Sets the appropriate animations on the bone groups based on priority. */ - //void resetActiveGroups(); + void resetActiveGroups(); - //static size_t detectAnimGroup(const Ogre::Node *node); - - /* - static float calcAnimVelocity(const NifOgre::TextKeyMap &keys, - NifOgre::NodeTargetValue *nonaccumctrl, - const Ogre::Vector3 &accum, - const std::string &groupname); - */ + size_t detectAnimGroup(osg::Node* node); /* Updates the position of the accum root node for the given time, and * returns the wanted movement vector from the previous time. */ //void updatePosition(float oldtime, float newtime, Ogre::Vector3 &position); - //static NifOgre::TextKeyMap::const_iterator findGroupStart(const NifOgre::TextKeyMap &keys, const std::string &groupname); - /* Resets the animation to the time of the specified start marker, without * moving anything, and set the end time to the specified stop marker. If * the marker is not found, or if the markers are the same, it returns * false. */ - //bool reset(AnimState &state, const NifOgre::TextKeyMap &keys, - // const std::string &groupname, const std::string &start, const std::string &stop, - // float startpoint, bool loopfallback); + bool reset(AnimState &state, const std::multimap &keys, + const std::string &groupname, const std::string &start, const std::string &stop, + float startpoint, bool loopfallback); - //void handleTextKey(AnimState &state, const std::string &groupname, const NifOgre::TextKeyMap::const_iterator &key, - // const NifOgre::TextKeyMap& map); + void handleTextKey(AnimState &state, const std::string &groupname, const std::multimap::const_iterator &key, + const std::multimap& map); /* Sets the root model of the object. * @@ -235,12 +256,12 @@ public: void updatePtr(const MWWorld::Ptr &ptr); - //bool hasAnimation(const std::string &anim); + bool hasAnimation(const std::string &anim); // Specifies the axis' to accumulate on. Non-accumulated axis will just // move visually, but not affect the actual movement. Each x/y/z value // should be on the scale of 0 to 1. - //void setAccumulation(const Ogre::Vector3 &accum); + void setAccumulation(const osg::Vec3f& accum); /** Plays an animation. * \param groupname Name of the animation group to play. @@ -262,20 +283,20 @@ public: * \param loopFallback Allow looping an animation that has no loop keys, i.e. fall back to use * the "start" and "stop" keys for looping? */ - //void play(const std::string &groupname, int priority, int groups, bool autodisable, - // float speedmult, const std::string &start, const std::string &stop, - // float startpoint, size_t loops, bool loopfallback=false); + void play(const std::string &groupname, int priority, int groups, bool autodisable, + float speedmult, const std::string &start, const std::string &stop, + float startpoint, size_t loops, bool loopfallback=false); /** If the given animation group is currently playing, set its remaining loop count to '0'. */ - //void stopLooping(const std::string& groupName); + void stopLooping(const std::string& groupName); /** Adjust the speed multiplier of an already playing animation. */ - //void adjustSpeedMult (const std::string& groupname, float speedmult); + void adjustSpeedMult (const std::string& groupname, float speedmult); /** Returns true if the named animation group is playing. */ - //bool isPlaying(const std::string &groupname) const; + bool isPlaying(const std::string &groupname) const; /// Returns true if no important animations are currently playing on the upper body. //bool upperBodyReady() const; @@ -286,30 +307,34 @@ public: * \param speedmult Stores the animation speed multiplier * \return True if the animation is active, false otherwise. */ - //bool getInfo(const std::string &groupname, float *complete=NULL, float *speedmult=NULL) const; + bool getInfo(const std::string &groupname, float *complete=NULL, float *speedmult=NULL) const; /// Get the absolute position in the animation track of the first text key with the given group. - //float getStartTime(const std::string &groupname) const; + float getStartTime(const std::string &groupname) const; /// Get the absolute position in the animation track of the text key - //float getTextKeyTime(const std::string &textKey) const; + float getTextKeyTime(const std::string &textKey) const; /// Get the current absolute position in the animation track for the animation that is currently playing from the given group. - //float getCurrentTime(const std::string& groupname) const; + float getCurrentTime(const std::string& groupname) const; /** Disables the specified animation group; * \param groupname Animation group to disable. */ - //void disable(const std::string &groupname); - //void changeGroups(const std::string &groupname, int group); + void disable(const std::string &groupname); + void changeGroups(const std::string &groupname, int group); /** Retrieves the velocity (in units per second) that the animation will move. */ - //float getVelocity(const std::string &groupname) const; + float getVelocity(const std::string &groupname) const; virtual osg::Vec3f runAnimation(float duration); /// This is typically called as part of runAnimation, but may be called manually if needed. void updateEffects(float duration); + +private: + Animation(const Animation&); + void operator=(Animation&); }; class ObjectAnimation : public Animation { diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index 241ea56a3..721215749 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -22,16 +22,16 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr, const std::string& model, Resource::ResourceSystem* resourceSystem) : Animation(ptr, osg::ref_ptr(ptr.getRefData().getBaseNode()), resourceSystem) { - //MWWorld::LiveCellRef *ref = mPtr.get(); + MWWorld::LiveCellRef *ref = mPtr.get(); if(!model.empty()) { setObjectRoot(model /* , baseonly = false */); //setRenderProperties(mObjectRoot, RV_Actors, RQG_Main, RQG_Alpha); - //if((ref->mBase->mFlags&ESM::Creature::Bipedal)) - // addAnimSource("meshes\\xbase_anim.nif"); - //addAnimSource(model); + if((ref->mBase->mFlags&ESM::Creature::Bipedal)) + addAnimSource("meshes\\xbase_anim.nif"); + addAnimSource(model); } } @@ -41,16 +41,16 @@ CreatureWeaponAnimation::CreatureWeaponAnimation(const MWWorld::Ptr &ptr, const , mShowWeapons(false) , mShowCarriedLeft(false) { - //MWWorld::LiveCellRef *ref = mPtr.get(); + MWWorld::LiveCellRef *ref = mPtr.get(); if(!model.empty()) { setObjectRoot(model /* , baseonly = false*/); //setRenderProperties(mObjectRoot, RV_Actors, RQG_Main, RQG_Alpha); - //if((ref->mBase->mFlags&ESM::Creature::Bipedal)) - // addAnimSource("meshes\\xbase_anim.nif"); - //addAnimSource(model); + if((ref->mBase->mFlags&ESM::Creature::Bipedal)) + addAnimSource("meshes\\xbase_anim.nif"); + addAnimSource(model); mPtr.getClass().getInventoryStore(mPtr).setListener(this, mPtr); diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 03af50c71..ab32864bd 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -281,7 +281,6 @@ void NpcAnimation::updateNpcBase() smodel = Misc::ResourceHelpers::correctActorModelPath(smodel, mResourceSystem->getVFS()); setObjectRoot(smodel /*, baseonly = true*/); - /* if(mViewMode != VM_FirstPerson) { addAnimSource(smodel); @@ -310,7 +309,6 @@ void NpcAnimation::updateNpcBase() addAnimSource("meshes\\xbase_anim_female.1st.nif"); } } - */ for(size_t i = 0;i < ESM::PRT_Count;i++) removeIndividualPart((ESM::PartReferenceType)i); diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 4b1fa6d5b..e278662aa 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -167,6 +167,7 @@ void Objects::insertNPC(const MWWorld::Ptr &ptr) insertBegin(ptr); std::auto_ptr anim (new NpcAnimation(ptr, osg::ref_ptr(ptr.getRefData().getBaseNode()), mResourceSystem, 0)); + anim->play("idle2", 0, Animation::Group_All, false, 1.f, "loop start", "loop stop", 0.f, 50); //testing if (anim->getObjectRoot()) anim->getObjectRoot()->addCullCallback(new SceneUtil::LightListCallback); diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 3b3ae4b2c..38ead0925 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -413,7 +413,7 @@ namespace NifOsg continue; osg::ref_ptr callback(new NifOsg::KeyframeController(key->data.getPtr())); - callback->mFunction = boost::shared_ptr(new NifOsg::ControllerFunction(key)); + callback->setFunction(boost::shared_ptr(new NifOsg::ControllerFunction(key))); target.mKeyframeControllers[strdata->string] = callback; } @@ -459,9 +459,9 @@ namespace NifOsg { bool autoPlay = animflags & Nif::NiNode::AnimFlag_AutoPlay; if (autoPlay) - toSetup->mSource = boost::shared_ptr(new SceneUtil::FrameTimeSource); + toSetup->setSource(boost::shared_ptr(new SceneUtil::FrameTimeSource)); - toSetup->mFunction = boost::shared_ptr(new ControllerFunction(ctrl)); + toSetup->setFunction(boost::shared_ptr(new ControllerFunction(ctrl))); } static osg::ref_ptr handleNode(const Nif::Node* nifNode, osg::Group* parentNode, Resource::TextureManager* textureManager, diff --git a/components/nifosg/nifloader.hpp b/components/nifosg/nifloader.hpp index b6e9b1c8f..f2f3c2534 100644 --- a/components/nifosg/nifloader.hpp +++ b/components/nifosg/nifloader.hpp @@ -44,7 +44,8 @@ namespace NifOsg public: TextKeyMap mTextKeys; - std::map > mKeyframeControllers; + typedef std::map > KeyframeControllerMap; + KeyframeControllerMap mKeyframeControllers; }; /// The main class responsible for loading NIF files into an OSG-Scenegraph. diff --git a/components/sceneutil/controller.cpp b/components/sceneutil/controller.cpp index 79a75063a..6beb1bc80 100644 --- a/components/sceneutil/controller.cpp +++ b/components/sceneutil/controller.cpp @@ -23,6 +23,26 @@ namespace SceneUtil return mFunction->calculate(mSource->getValue(nv)); } + void Controller::setSource(boost::shared_ptr source) + { + mSource = source; + } + + void Controller::setFunction(boost::shared_ptr function) + { + mFunction = function; + } + + boost::shared_ptr Controller::getSource() const + { + return mSource; + } + + boost::shared_ptr Controller::getFunction() const + { + return mFunction; + } + FrameTimeSource::FrameTimeSource() { } @@ -85,8 +105,8 @@ namespace SceneUtil void AssignControllerSourcesVisitor::visit(osg::Node&, Controller &ctrl) { - if (!ctrl.mSource.get()) - ctrl.mSource = mToAssign; + if (!ctrl.getSource()) + ctrl.setSource(mToAssign); } FindMaxControllerLengthVisitor::FindMaxControllerLengthVisitor() @@ -97,8 +117,8 @@ namespace SceneUtil void FindMaxControllerLengthVisitor::visit(osg::Node &, Controller &ctrl) { - if (ctrl.mFunction) - mMaxLength = std::max(mMaxLength, ctrl.mFunction->getMaximum()); + if (ctrl.getFunction()) + mMaxLength = std::max(mMaxLength, ctrl.getFunction()->getMaximum()); } float FindMaxControllerLengthVisitor::getMaxLength() const diff --git a/components/sceneutil/controller.hpp b/components/sceneutil/controller.hpp index 6086663bd..84fe6e896 100644 --- a/components/sceneutil/controller.hpp +++ b/components/sceneutil/controller.hpp @@ -41,6 +41,13 @@ namespace SceneUtil float getInputValue(osg::NodeVisitor* nv); + void setSource(boost::shared_ptr source); + void setFunction(boost::shared_ptr function); + + boost::shared_ptr getSource() const; + boost::shared_ptr getFunction() const; + + private: boost::shared_ptr mSource; // The source value gets passed through this function before it's passed on to the DestValue. From 86b4a610cb54c4910a3eac5492a65c9acee510af Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 23 Apr 2015 22:46:07 +0200 Subject: [PATCH 1013/3725] Movement accumulation works --- apps/openmw/mwrender/animation.cpp | 98 +++++++++++++++++++++--------- apps/openmw/mwrender/animation.hpp | 7 ++- apps/openmw/mwrender/objects.cpp | 1 - 3 files changed, 74 insertions(+), 32 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index d291e0fd0..f490baefe 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include @@ -168,10 +169,39 @@ namespace namespace MWRender { + class ResetAccumRootCallback : public osg::NodeCallback + { + public: + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) + { + osg::MatrixTransform* transform = static_cast(node); + + osg::Matrix mat = transform->getMatrix(); + osg::Vec3f position = mat.getTrans(); + position = osg::componentMultiply(mResetAxes, position); + mat.setTrans(position); + transform->setMatrix(mat); + + traverse(node, nv); + } + + void setAccumulate(const osg::Vec3f& accumulate) + { + // anything that accumulates (1.f) should be reset in the callback to (0.f) + mResetAxes.x() = accumulate.x() != 0.f ? 0.f : 1.f; + mResetAxes.y() = accumulate.y() != 0.f ? 0.f : 1.f; + mResetAxes.z() = accumulate.z() != 0.f ? 0.f : 1.f; + } + + private: + osg::Vec3f mResetAxes; + }; + Animation::Animation(const MWWorld::Ptr &ptr, osg::ref_ptr parentNode, Resource::ResourceSystem* resourceSystem) : mPtr(ptr) , mInsert(parentNode) , mResourceSystem(resourceSystem) + , mAccumulate(1.f, 1.f, 0.f) { for(size_t i = 0;i < sNumGroups;i++) mAnimationTimePtr[i].reset(new AnimationTime(this)); @@ -191,6 +221,9 @@ namespace MWRender void Animation::setAccumulation(const osg::Vec3f& accum) { mAccumulate = accum; + + if (mResetAccumRootCallback) + mResetAccumRootCallback->setAccumulate(mAccumulate); } size_t Animation::detectAnimGroup(osg::Node* node) @@ -322,6 +355,16 @@ namespace MWRender void Animation::handleTextKey(AnimState &state, const std::string &groupname, const std::multimap::const_iterator &key, const std::multimap& map) { + const std::string &evt = key->second; + + size_t off = groupname.size()+2; + size_t len = evt.size() - off; + + if(evt.compare(off, len, "loop start") == 0) + state.mLoopStartTime = key->first; + else if(evt.compare(off, len, "loop stop") == 0) + state.mLoopStopTime = key->first; + // TODO: forward to listener? } @@ -406,16 +449,6 @@ namespace MWRender std::cerr<< "Failed to find animation "<setPosition(-mNonAccumCtrl->getTranslation(state.mTime)*mAccumulate); - } - */ } bool Animation::reset(AnimState &state, const NifOsg::TextKeyMap &keys, const std::string &groupname, const std::string &start, const std::string &stop, float startpoint, bool loopfallback) @@ -504,6 +537,8 @@ namespace MWRender osg::Node* node = it->first; node->removeUpdateCallback(it->second); } + if (mResetAccumRootCallback && mAccumRoot) + mAccumRoot->removeUpdateCallback(mResetAccumRootCallback); mAnimSourceControllers.clear(); mAccumCtrl = NULL; @@ -538,26 +573,19 @@ namespace MWRender mAnimSourceControllers[node] = it->second; if (grp == 0 && node == mAccumRoot) + { mAccumCtrl = it->second; + + if (!mResetAccumRootCallback) + { + mResetAccumRootCallback = new ResetAccumRootCallback; + mResetAccumRootCallback->setAccumulate(mAccumulate); + } + mAccumRoot->addUpdateCallback(mResetAccumRootCallback); + } } } } - - //if(!mNonAccumRoot || mAccumulate == Ogre::Vector3(0.0f)) - // return; - - /* - AnimStateMap::const_iterator state = mStates.find(mAnimationTimePtr[0]->getAnimName()); - if(state == mStates.end()) - { - //if (mAccumRoot && mNonAccumRoot) - // mAccumRoot->setPosition(-mNonAccumRoot->getPosition()*mAccumulate); - return; - } - */ - - //if (mAccumRoot && mNonAccumCtrl) - // mAccumRoot->setPosition(-mNonAccumCtrl->getTranslation(state->second.mTime)*mAccumulate); } void Animation::changeGroups(const std::string &groupname, int groups) @@ -695,6 +723,13 @@ namespace MWRender */ } + void Animation::updatePosition(float oldtime, float newtime, osg::Vec3f& position) + { + // Get the difference from the last update, and move the position + osg::Vec3f off = osg::componentMultiply(mAccumCtrl->getTranslation(newtime), mAccumulate); + position += off - osg::componentMultiply(mAccumCtrl->getTranslation(oldtime), mAccumulate); + } + osg::Vec3f Animation::runAnimation(float duration) { osg::Vec3f movement(0.f, 0.f, 0.f); @@ -716,14 +751,14 @@ namespace MWRender targetTime = state.mTime + timepassed; if(textkey == textkeys.end() || textkey->first > targetTime) { - //if(mNonAccumCtrl && stateiter->first == mAnimationTimePtr[0]->getAnimName()) - // updatePosition(state.mTime, targetTime, movement); + if(mAccumCtrl && stateiter->first == mAnimationTimePtr[0]->getAnimName()) + updatePosition(state.mTime, targetTime, movement); state.mTime = std::min(targetTime, state.mStopTime); } else { - //if(mNonAccumCtrl && stateiter->first == mAnimationTimePtr[0]->getAnimName()) - // updatePosition(state.mTime, textkey->first, movement); + if(mAccumCtrl && stateiter->first == mAnimationTimePtr[0]->getAnimName()) + updatePosition(state.mTime, textkey->first, movement); state.mTime = textkey->first; } @@ -779,9 +814,12 @@ namespace MWRender { mObjectRoot->getParent(0)->removeChild(mObjectRoot); } + mObjectRoot = NULL; mNodeMap.clear(); mAnimSourceControllers.clear(); + mAccumRoot = NULL; + mAccumCtrl = NULL; mObjectRoot = mResourceSystem->getSceneManager()->createInstance(model, mInsert); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index a04544ac8..083213c85 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -23,6 +23,8 @@ namespace NifOsg namespace MWRender { +class ResetAccumRootCallback; + class EffectAnimationTime : public SceneUtil::ControllerSource { private: @@ -133,6 +135,9 @@ protected: // The controller animating that node. osg::ref_ptr mAccumCtrl; + // Used to reset the position of the accumulation root every frame - the movement should be applied to the physics system + osg::ref_ptr mResetAccumRootCallback; + // Keep track of keyframe controllers from external files that we added to our scene graph. // We may need to rebuild these controllers when the active animation groups / sources change. typedef std::map, osg::ref_ptr > AnimSourceControllerMap; @@ -196,7 +201,7 @@ protected: /* Updates the position of the accum root node for the given time, and * returns the wanted movement vector from the previous time. */ - //void updatePosition(float oldtime, float newtime, Ogre::Vector3 &position); + void updatePosition(float oldtime, float newtime, osg::Vec3f& position); /* Resets the animation to the time of the specified start marker, without * moving anything, and set the end time to the specified stop marker. If diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index e278662aa..4b1fa6d5b 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -167,7 +167,6 @@ void Objects::insertNPC(const MWWorld::Ptr &ptr) insertBegin(ptr); std::auto_ptr anim (new NpcAnimation(ptr, osg::ref_ptr(ptr.getRefData().getBaseNode()), mResourceSystem, 0)); - anim->play("idle2", 0, Animation::Group_All, false, 1.f, "loop start", "loop stop", 0.f, 50); //testing if (anim->getObjectRoot()) anim->getObjectRoot()->addCullCallback(new SceneUtil::LightListCallback); From 6f3e920f85c7786db42cea88edb6fad2ab3e78c9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 23 Apr 2015 23:30:06 +0200 Subject: [PATCH 1014/3725] Animation port complete --- apps/openmw/mwrender/animation.cpp | 66 +++++++++++++++------- apps/openmw/mwrender/animation.hpp | 7 ++- apps/openmw/mwrender/creatureanimation.cpp | 4 +- apps/openmw/mwrender/npcanimation.cpp | 5 +- 4 files changed, 54 insertions(+), 28 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index f490baefe..27e54b228 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -310,6 +311,18 @@ namespace MWRender } } + void Animation::clearAnimSources() + { + mStates.clear(); + + for(size_t i = 0;i < sNumGroups;i++) + mAnimationTimePtr[i]->setAnimName(std::string()); + + mAccumCtrl = NULL; + + mAnimSources.clear(); + } + bool Animation::hasAnimation(const std::string &anim) { AnimSourceList::const_iterator iter(mAnimSources.begin()); @@ -668,13 +681,14 @@ namespace MWRender float Animation::getVelocity(const std::string &groupname) const { - return 0.f; - /* + if (!mAccumRoot) + return 0.0f; + // Look in reverse; last-inserted source has priority. AnimSourceList::const_reverse_iterator animsrc(mAnimSources.rbegin()); for(;animsrc != mAnimSources.rend();++animsrc) { - const NifOsg::TextKeyMap &keys = (*animsrc)->mTextKeys; + const NifOsg::TextKeyMap &keys = (*animsrc)->getTextKeys(); if(findGroupStart(keys, groupname) != keys.end()) break; } @@ -682,15 +696,14 @@ namespace MWRender return 0.0f; float velocity = 0.0f; - const NifOsg::TextKeyMap &keys = (*animsrc)->mTextKeys; - const std::vector >&ctrls = (*animsrc)->mControllers[0]; - for(size_t i = 0;i < ctrls.size();i++) + const NifOsg::TextKeyMap &keys = (*animsrc)->getTextKeys(); + + const AnimSource::ControllerMap& ctrls = (*animsrc)->mControllerMap[0]; + for (AnimSource::ControllerMap::const_iterator it = ctrls.begin(); it != ctrls.end(); ++it) { - NifOsg::NodeTargetValue *dstval; - dstval = static_cast*>(ctrls[i].getDestination().getPointer()); - if(dstval->getNode() == mNonAccumRoot) + if (Misc::StringUtils::ciEqual(it->first, mAccumRoot->getName())) { - velocity = calcAnimVelocity(keys, dstval, mAccumulate, groupname); + velocity = calcAnimVelocity(keys, it->second, mAccumulate, groupname); break; } } @@ -704,15 +717,14 @@ namespace MWRender while(!(velocity > 1.0f) && ++animiter != mAnimSources.rend()) { - const NifOgre::TextKeyMap &keys = (*animiter)->mTextKeys; - const std::vector >&ctrls = (*animiter)->mControllers[0]; - for(size_t i = 0;i < ctrls.size();i++) + const NifOsg::TextKeyMap &keys = (*animiter)->getTextKeys(); + + const AnimSource::ControllerMap& ctrls = (*animiter)->mControllerMap[0]; + for (AnimSource::ControllerMap::const_iterator it = ctrls.begin(); it != ctrls.end(); ++it) { - NifOgre::NodeTargetValue *dstval; - dstval = static_cast*>(ctrls[i].getDestination().getPointer()); - if(dstval->getNode() == mNonAccumRoot) + if (Misc::StringUtils::ciEqual(it->first, mAccumRoot->getName())) { - velocity = calcAnimVelocity(keys, dstval, mAccumulate, groupname); + velocity = calcAnimVelocity(keys, it->second, mAccumulate, groupname); break; } } @@ -720,7 +732,6 @@ namespace MWRender } return velocity; - */ } void Animation::updatePosition(float oldtime, float newtime, osg::Vec3f& position) @@ -808,7 +819,7 @@ namespace MWRender return movement; } - void Animation::setObjectRoot(const std::string &model) + void Animation::setObjectRoot(const std::string &model, bool forceskeleton) { if (mObjectRoot) { @@ -821,7 +832,20 @@ namespace MWRender mAccumRoot = NULL; mAccumCtrl = NULL; - mObjectRoot = mResourceSystem->getSceneManager()->createInstance(model, mInsert); + if (!forceskeleton) + mObjectRoot = mResourceSystem->getSceneManager()->createInstance(model, mInsert); + else + { + osg::ref_ptr newObjectRoot = mResourceSystem->getSceneManager()->createInstance(model); + if (!dynamic_cast(newObjectRoot.get())) + { + osg::ref_ptr skel = new SceneUtil::Skeleton; + skel->addChild(newObjectRoot); + newObjectRoot = skel; + } + mInsert->addChild(newObjectRoot); + mObjectRoot = newObjectRoot; + } NodeMapVisitor visitor; mObjectRoot->accept(visitor); @@ -1062,7 +1086,7 @@ namespace MWRender { if (!model.empty()) { - setObjectRoot(model); + setObjectRoot(model, false); if (!ptr.getClass().getEnchantment(ptr).empty()) addGlow(mObjectRoot, getEnchantmentColor(ptr)); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 083213c85..d5b2de81b 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -215,12 +215,13 @@ protected: void handleTextKey(AnimState &state, const std::string &groupname, const std::multimap::const_iterator &key, const std::multimap& map); - /* Sets the root model of the object. + /** Sets the root model of the object. * * Note that you must make sure all animation sources are cleared before reseting the object * root. All nodes previously retrieved with getNode will also become invalidated. + * @param forceskeleton Wrap the object root in a Skeleton, even if it contains no skinned parts. Use this if you intend to add skinned parts manually. */ - void setObjectRoot(const std::string &model); + void setObjectRoot(const std::string &model, bool forceskeleton); /* Adds the keyframe controllers in the specified model as a new animation source. Note that * the filename portion of the provided model name will be prepended with 'x', and the .nif @@ -230,7 +231,7 @@ protected: /** Adds an additional light to the given node using the specified ESM record. */ void addExtraLight(osg::ref_ptr parent, const ESM::Light *light); - //void clearAnimSources(); + void clearAnimSources(); osg::Vec4f getEnchantmentColor(MWWorld::Ptr item); diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index 721215749..d2abf1413 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -26,7 +26,7 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr, if(!model.empty()) { - setObjectRoot(model /* , baseonly = false */); + setObjectRoot(model, false /* , baseonly = false */); //setRenderProperties(mObjectRoot, RV_Actors, RQG_Main, RQG_Alpha); if((ref->mBase->mFlags&ESM::Creature::Bipedal)) @@ -45,7 +45,7 @@ CreatureWeaponAnimation::CreatureWeaponAnimation(const MWWorld::Ptr &ptr, const if(!model.empty()) { - setObjectRoot(model /* , baseonly = false*/); + setObjectRoot(model, true /* , baseonly = false*/); //setRenderProperties(mObjectRoot, RV_Actors, RQG_Main, RQG_Alpha); if((ref->mBase->mFlags&ESM::Creature::Bipedal)) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index ab32864bd..80dbf3c7f 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -233,7 +233,7 @@ void NpcAnimation::rebuild() void NpcAnimation::updateNpcBase() { - //clearAnimSources(); + clearAnimSources(); const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); const ESM::Race *race = store.get().find(mNpc->mRace); @@ -279,7 +279,8 @@ void NpcAnimation::updateNpcBase() : "meshes\\base_animkna.1st.nif" : "meshes\\wolf\\skin.1st.nif"); smodel = Misc::ResourceHelpers::correctActorModelPath(smodel, mResourceSystem->getVFS()); - setObjectRoot(smodel /*, baseonly = true*/); + + setObjectRoot(smodel, true /*, baseonly = true*/); if(mViewMode != VM_FirstPerson) { From 1c0e3a648839bd2121573c6077e9b2652d03cfbb Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 23 Apr 2015 23:50:46 +0200 Subject: [PATCH 1015/3725] rotateObject, scaleObject --- apps/openmw/mwrender/objects.cpp | 19 ------------------- apps/openmw/mwrender/renderingmanager.cpp | 20 ++++++++++++++++++++ apps/openmw/mwrender/renderingmanager.hpp | 5 +++++ apps/openmw/mwworld/scene.cpp | 23 +++++++---------------- apps/openmw/mwworld/scene.hpp | 2 -- apps/openmw/mwworld/worldimp.cpp | 17 +++++++---------- 6 files changed, 39 insertions(+), 47 deletions(-) diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 4b1fa6d5b..be21b2bec 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -102,25 +102,6 @@ void Objects::insertBegin(const MWWorld::Ptr& ptr) const float *f = ptr.getRefData().getPosition().pos; insert->setPosition(osg::Vec3(f[0], f[1], f[2])); - insert->setScale(osg::Vec3(ptr.getCellRef().getScale(), ptr.getCellRef().getScale(), ptr.getCellRef().getScale())); - - // Convert MW rotation to a quaternion: - f = ptr.getCellRef().getPosition().rot; - - // Rotate around X axis - osg::Quat xr(-f[0], osg::Vec3(1,0,0)); - - // Rotate around Y axis - osg::Quat yr(-f[1], osg::Vec3(0,1,0)); - - // Rotate around Z axis - osg::Quat zr(-f[2], osg::Vec3(0,0,1)); - - // Rotates first around z, then y, then x - if (ptr.getClass().isActor()) - insert->setAttitude(zr); - else - insert->setAttitude(zr*yr*xr); ptr.getRefData().setBaseNode(insert); } diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 5199e6e12..be23ebc2f 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include @@ -211,6 +212,25 @@ namespace MWRender mSky->update(dt); } + void RenderingManager::rotateObject(const MWWorld::Ptr &ptr, const osg::Quat& rot) + { + //if(ptr.getRefData().getHandle() == mCamera->getHandle() && + // !mCamera->isVanityOrPreviewModeEnabled()) + // mCamera->rotateCamera(-rot, false); + + ptr.getRefData().getBaseNode()->setAttitude(rot); + } + + void RenderingManager::moveObject(const MWWorld::Ptr &ptr, const osg::Vec3f &pos) + { + ptr.getRefData().getBaseNode()->setPosition(pos); + } + + void RenderingManager::scaleObject(const MWWorld::Ptr &ptr, const osg::Vec3f &scale) + { + ptr.getRefData().getBaseNode()->setScale(scale); + } + void RenderingManager::spawnEffect(const std::string &model, const std::string &texture, const osg::Vec3f &worldPosition, float scale) { mEffectManager->addEffect(model, texture, worldPosition, scale); diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 230885cd3..c47317608 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -57,6 +57,11 @@ namespace MWRender void removeCell(const MWWorld::CellStore* store); + // TODO rename to setRotation/setPosition/setScale, along with the World equivalents + void rotateObject(const MWWorld::Ptr& ptr, const osg::Quat& rot); + void moveObject(const MWWorld::Ptr& ptr, const osg::Vec3f& pos); + void scaleObject(const MWWorld::Ptr& ptr, const osg::Vec3f& scale); + void setSkyEnabled(bool enabled); SkyManager* getSkyManager(); diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index ef9e5792b..4f689ee59 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -42,7 +42,7 @@ namespace //ptr.getClass().insertObject (ptr, model, physics); } - void updateObjectLocalRotation (const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics, + void updateObjectLocalRotation (const MWWorld::Ptr& ptr, /*MWWorld::PhysicsSystem& physics,*/ MWRender::RenderingManager& rendering) { if (ptr.getRefData().getBaseNode() != NULL) @@ -60,7 +60,7 @@ namespace if (!ptr.getClass().isActor()) rot = rot * osg::Quat(y, osg::Vec3(0,-1,0)) * osg::Quat(x, osg::Vec3(-1,0,0)); - ptr.getRefData().getBaseNode()->setAttitude(rot * worldRotQuat); + rendering.rotateObject(ptr, rot * worldRotQuat); //physics.rotateObject(ptr); } } @@ -102,12 +102,12 @@ namespace try { addObject(ptr, /*mPhysics, */mRendering); - //updateObjectLocalRotation(ptr, mPhysics, mRendering); + updateObjectLocalRotation(ptr, /*mPhysics,*/ mRendering); if (ptr.getRefData().getBaseNode()) { float scale = ptr.getCellRef().getScale(); ptr.getClass().adjustScale(ptr, scale); - //mRendering.scaleObject(ptr, Ogre::Vector3(scale)); + mRendering.scaleObject(ptr, osg::Vec3f(scale, scale, scale)); } ptr.getClass().adjustPosition (ptr, false); } @@ -130,16 +130,7 @@ namespace MWWorld void Scene::updateObjectLocalRotation (const Ptr& ptr) { - //::updateObjectLocalRotation(ptr, *mPhysics, mRendering); - } - - void Scene::updateObjectRotation (const Ptr& ptr) - { - if(ptr.getRefData().getBaseNodeOld() != 0) - { - //mRendering.rotateObject(ptr); - //mPhysics->rotateObject(ptr); - } + ::updateObjectLocalRotation(ptr, /* *mPhysics,*/ mRendering); } void Scene::getGridCenter(int &cellX, int &cellY) @@ -563,8 +554,8 @@ namespace MWWorld try { addObject(ptr, /* *mPhysics, */mRendering); - //MWBase::Environment::get().getWorld()->rotateObject(ptr, 0, 0, 0, true); - //MWBase::Environment::get().getWorld()->scaleObject(ptr, ptr.getCellRef().getScale()); + MWBase::Environment::get().getWorld()->rotateObject(ptr, 0, 0, 0, true); + MWBase::Environment::get().getWorld()->scaleObject(ptr, ptr.getCellRef().getScale()); } catch (std::exception& e) { diff --git a/apps/openmw/mwworld/scene.hpp b/apps/openmw/mwworld/scene.hpp index 4e8f6a11b..0ae1ff4da 100644 --- a/apps/openmw/mwworld/scene.hpp +++ b/apps/openmw/mwworld/scene.hpp @@ -117,8 +117,6 @@ namespace MWWorld void updateObjectLocalRotation (const Ptr& ptr); - void updateObjectRotation (const Ptr& ptr); - bool isCellActive(const CellStore &cell); Ptr searchPtrViaHandle (const std::string& handle); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index a2d40930b..07c3b1b16 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1217,9 +1217,9 @@ namespace MWWorld ptr.getRefData().setCount(0); } } - if (haveToMove && ptr.getRefData().getBaseNodeOld()) + if (haveToMove && ptr.getRefData().getBaseNode()) { - //mRendering->moveObject(ptr, vec); + mRendering->moveObject(ptr, osg::Vec3f(vec.x, vec.y, vec.z)); //mPhysics->moveObject (ptr); } if (isPlayer) @@ -1256,9 +1256,9 @@ namespace MWWorld ptr.getCellRef().setScale(scale); ptr.getClass().adjustScale(ptr,scale); - if(ptr.getRefData().getBaseNodeOld() == 0) + if(ptr.getRefData().getBaseNode() == 0) return; - //mRendering->scaleObject(ptr, Vector3(scale,scale,scale)); + mRendering->scaleObject(ptr, osg::Vec3f(scale,scale,scale)); //mPhysics->scaleObject(ptr); } @@ -1307,13 +1307,10 @@ namespace MWWorld ptr.getRefData().setPosition(pos); - if(ptr.getRefData().getBaseNodeOld() == 0) + if(ptr.getRefData().getBaseNode() == 0) return; - if (ptr.getClass().isActor()) - mWorldScene->updateObjectRotation(ptr); - else - mWorldScene->updateObjectLocalRotation(ptr); + mWorldScene->updateObjectLocalRotation(ptr); } void World::localRotateObject (const Ptr& ptr, float x, float y, float z) @@ -1329,7 +1326,7 @@ namespace MWWorld ptr.getRefData().setLocalRotation(rot); - if (ptr.getRefData().getBaseNodeOld() != 0) + if (ptr.getRefData().getBaseNode() != 0) { mWorldScene->updateObjectLocalRotation(ptr); } From 9f12e539565bd71a7b3d196361c11e126ad1d177 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 24 Apr 2015 14:49:20 +0200 Subject: [PATCH 1016/3725] Scale NPCs by their Weight property (Fixes #814) --- apps/openmw/mwclass/creature.cpp | 2 +- apps/openmw/mwclass/creature.hpp | 2 +- apps/openmw/mwclass/npc.cpp | 15 ++++++++++++--- apps/openmw/mwclass/npc.hpp | 2 +- apps/openmw/mwworld/class.cpp | 2 +- apps/openmw/mwworld/class.hpp | 2 +- apps/openmw/mwworld/physicssystem.cpp | 5 +++-- apps/openmw/mwworld/scene.cpp | 24 ++++++++++++++++++------ apps/openmw/mwworld/scene.hpp | 1 + apps/openmw/mwworld/worldimp.cpp | 12 +++--------- 10 files changed, 42 insertions(+), 25 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index d4a50ce81..a85c648f4 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -893,7 +893,7 @@ namespace MWClass return ref->mBase->mAiData.mFight; } - void Creature::adjustScale(const MWWorld::Ptr &ptr, float &scale) const + void Creature::adjustScale(const MWWorld::Ptr &ptr, osg::Vec3f &scale) const { MWWorld::LiveCellRef *ref = ptr.get(); scale *= ref->mBase->mScale; diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index e11529b2e..5585835fd 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -157,7 +157,7 @@ namespace MWClass virtual int getBaseFightRating(const MWWorld::Ptr &ptr) const; - virtual void adjustScale(const MWWorld::Ptr& ptr,float& scale) const; + virtual void adjustScale(const MWWorld::Ptr& ptr, osg::Vec3f& scale) const; }; } diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index b28fb0499..8be551dd2 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -1110,7 +1110,7 @@ namespace MWClass + shield; } - void Npc::adjustScale(const MWWorld::Ptr &ptr, float &scale) const + void Npc::adjustScale(const MWWorld::Ptr &ptr, osg::Vec3f&scale) const { MWWorld::LiveCellRef *ref = ptr.get(); @@ -1119,9 +1119,18 @@ namespace MWClass MWBase::Environment::get().getWorld()->getStore().get().find(ref->mBase->mRace); if (ref->mBase->isMale()) - scale *= race->mData.mHeight.mMale; + { + scale.x() *= race->mData.mWeight.mMale; + scale.y() *= race->mData.mWeight.mMale; + scale.z() *= race->mData.mHeight.mMale; + } else - scale *= race->mData.mHeight.mFemale; + { + scale.x() *= race->mData.mWeight.mFemale; + scale.y() *= race->mData.mWeight.mFemale; + scale.z() *= race->mData.mHeight.mFemale; + } + } int Npc::getServices(const MWWorld::Ptr &actor) const diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index 27beeb626..b74546395 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -129,7 +129,7 @@ namespace MWClass /// \param actor Actor that is resposible for the ID being applied to \a ptr. /// \return Any effect? - virtual void adjustScale (const MWWorld::Ptr &ptr, float &scale) const; + virtual void adjustScale (const MWWorld::Ptr &ptr, osg::Vec3f &scale) const; virtual void skillUsageSucceeded (const MWWorld::Ptr& ptr, int skill, int usageType, float extraFactor=1.f) const; ///< Inform actor \a ptr that a skill use has succeeded. diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 6fa9ba9b6..79444e110 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -295,7 +295,7 @@ namespace MWWorld return ""; } - void Class::adjustScale(const MWWorld::Ptr& ptr,float& scale) const + void Class::adjustScale(const MWWorld::Ptr& ptr, osg::Vec3f& scale) const { } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 782aa7815..3f65af05c 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -266,7 +266,7 @@ namespace MWWorld virtual int getEnchantmentPoints (const MWWorld::Ptr& ptr) const; ///< @return the number of enchantment points available for possible enchanting - virtual void adjustScale(const MWWorld::Ptr& ptr,float& scale) const; + virtual void adjustScale(const MWWorld::Ptr& ptr, osg::Vec3f& scale) const; virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; ///< Determine whether or not \a item can be sold to an npc with the given \a npcServices diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index ae6cce6c7..623a79576 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -769,10 +769,11 @@ namespace MWWorld if (OEngine::Physic::PhysicActor* act = mEngine->getCharacter(handle)) { float scale = ptr.getCellRef().getScale(); + osg::Vec3f scaleVec (scale,scale,scale); if (!ptr.getClass().isNpc()) // NOTE: Ignoring Npc::adjustScale (race height) on purpose. This is a bug in MW and must be replicated for compatibility reasons - ptr.getClass().adjustScale(ptr, scale); - act->setScale(scale); + ptr.getClass().adjustScale(ptr, scaleVec); + act->setScale(scaleVec.x()); } } diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 4f689ee59..191a8ffef 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -65,6 +65,18 @@ namespace } } + void updateObjectScale(const MWWorld::Ptr& ptr, /*MWWorld::PhysicsSystem& physics,*/ + MWRender::RenderingManager& rendering) + { + if (ptr.getRefData().getBaseNode() != NULL) + { + float scale = ptr.getCellRef().getScale(); + osg::Vec3f scaleVec (scale, scale, scale); + ptr.getClass().adjustScale(ptr, scaleVec); + rendering.scaleObject(ptr, scaleVec); + } + } + struct InsertFunctor { MWWorld::CellStore& mCell; @@ -103,12 +115,7 @@ namespace { addObject(ptr, /*mPhysics, */mRendering); updateObjectLocalRotation(ptr, /*mPhysics,*/ mRendering); - if (ptr.getRefData().getBaseNode()) - { - float scale = ptr.getCellRef().getScale(); - ptr.getClass().adjustScale(ptr, scale); - mRendering.scaleObject(ptr, osg::Vec3f(scale, scale, scale)); - } + updateObjectScale(ptr, /*mPhysics,*/ mRendering); ptr.getClass().adjustPosition (ptr, false); } catch (const std::exception& e) @@ -133,6 +140,11 @@ namespace MWWorld ::updateObjectLocalRotation(ptr, /* *mPhysics,*/ mRendering); } + void Scene::updateObjectScale(const Ptr &ptr) + { + ::updateObjectScale(ptr, /* *mPhysics,*/ mRendering); + } + void Scene::getGridCenter(int &cellX, int &cellY) { int maxX = std::numeric_limits::min(); diff --git a/apps/openmw/mwworld/scene.hpp b/apps/openmw/mwworld/scene.hpp index 0ae1ff4da..ea1a56d63 100644 --- a/apps/openmw/mwworld/scene.hpp +++ b/apps/openmw/mwworld/scene.hpp @@ -116,6 +116,7 @@ namespace MWWorld ///< Remove an object from the scene, but not from the world model. void updateObjectLocalRotation (const Ptr& ptr); + void updateObjectScale(const Ptr& ptr); bool isCellActive(const CellStore &cell); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 07c3b1b16..4b1946d1c 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1254,12 +1254,8 @@ namespace MWWorld void World::scaleObject (const Ptr& ptr, float scale) { ptr.getCellRef().setScale(scale); - ptr.getClass().adjustScale(ptr,scale); - if(ptr.getRefData().getBaseNode() == 0) - return; - mRendering->scaleObject(ptr, osg::Vec3f(scale,scale,scale)); - //mPhysics->scaleObject(ptr); + mWorldScene->updateObjectScale(ptr); } void World::rotateObjectImp (const Ptr& ptr, Ogre::Vector3 rot, bool adjust) @@ -1307,10 +1303,8 @@ namespace MWWorld ptr.getRefData().setPosition(pos); - if(ptr.getRefData().getBaseNode() == 0) - return; - - mWorldScene->updateObjectLocalRotation(ptr); + if(ptr.getRefData().getBaseNode() != 0) + mWorldScene->updateObjectLocalRotation(ptr); } void World::localRotateObject (const Ptr& ptr, float x, float y, float z) From 42d6c6140c8d916343ade6ab595c12854a499abc Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 24 Apr 2015 21:55:30 +0200 Subject: [PATCH 1017/3725] Add mygui backend by chris --- apps/openmw/CMakeLists.txt | 6 +- apps/openmw/engine.cpp | 26 +- apps/openmw/engine.hpp | 6 - apps/openmw/mwgui/mainmenu.cpp | 2 +- apps/openmw/mwgui/myguidatamanager.cpp | 64 ++ apps/openmw/mwgui/myguidatamanager.hpp | 50 ++ apps/openmw/mwgui/myguiplatform.cpp | 2 + apps/openmw/mwgui/myguiplatform.hpp | 74 +++ apps/openmw/mwgui/myguirendermanager.cpp | 626 ++++++++++++++++++++ apps/openmw/mwgui/myguirendermanager.hpp | 101 ++++ apps/openmw/mwgui/windowmanagerimp.cpp | 47 +- apps/openmw/mwgui/windowmanagerimp.hpp | 19 +- apps/openmw/mwrender/renderingmanager.cpp | 6 +- libs/openengine/gui/manager.cpp | 680 ---------------------- libs/openengine/gui/manager.hpp | 53 -- 15 files changed, 962 insertions(+), 800 deletions(-) create mode 100644 apps/openmw/mwgui/myguidatamanager.cpp create mode 100644 apps/openmw/mwgui/myguidatamanager.hpp create mode 100644 apps/openmw/mwgui/myguiplatform.cpp create mode 100644 apps/openmw/mwgui/myguiplatform.hpp create mode 100644 apps/openmw/mwgui/myguirendermanager.cpp create mode 100644 apps/openmw/mwgui/myguirendermanager.hpp delete mode 100644 libs/openengine/gui/manager.cpp delete mode 100644 libs/openengine/gui/manager.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 84dcb60fa..3349a1afe 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -44,7 +44,7 @@ add_openmw_dir (mwgui itemmodel containeritemmodel inventoryitemmodel sortfilteritemmodel itemview tradeitemmodel companionitemmodel pickpocketitemmodel controllers savegamedialog recharge mode videowidget backgroundimage itemwidget screenfader debugwindow spellmodel spellview - draganddrop timeadvancer jailscreen + draganddrop timeadvancer jailscreen myguiplatform myguirendermanager myguidatamanager ) add_openmw_dir (mwdialogue @@ -107,6 +107,9 @@ endif(WIN32) find_package(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS}) +# for MyGUI platform +find_package(OpenGL REQUIRED) + if (NOT ANDROID) add_executable(openmw ${OPENMW_FILES} @@ -137,6 +140,7 @@ target_link_libraries(openmw ${MYGUI_LIBRARIES} ${SDL2_LIBRARY} ${MYGUI_PLATFORM_LIBRARIES} + ${OPENGL_gl_LIBRARY} "osg-ffmpeg-videoplayer" "oics" components diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 64457834c..7698c3146 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -218,13 +218,6 @@ OMW::Engine::~Engine() SDL_Quit(); } -// add resources directory -// \note This function works recursively. - -void OMW::Engine::addResourcesDirectory (const boost::filesystem::path& path) -{ -} - void OMW::Engine::enableFSStrict(bool fsStrict) { mFSStrict = fsStrict; @@ -309,16 +302,6 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) #endif } - // This has to be added BEFORE MyGUI is initialized, as it needs - // to find core.xml here. - - addResourcesDirectory(mCfgMgr.getCachePath ().string()); - - addResourcesDirectory(mResDir / "mygui"); - addResourcesDirectory(mResDir / "water"); - addResourcesDirectory(mResDir / "shadows"); - addResourcesDirectory(mResDir / "materials"); - //OEngine::Render::WindowSettings windowSettings; //windowSettings.fullscreen = settings.getBool("fullscreen", "Video"); //windowSettings.window_border = settings.getBool("window border", "Video"); @@ -369,9 +352,12 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) //MWInput::InputManager* input = new MWInput::InputManager (*mOgre, *this, keybinderUser, keybinderUserExists, gameControllerdb, mGrab); //mEnvironment.setInputManager (input); - MWGui::WindowManager* window = new MWGui::WindowManager( - mExtensions, mCfgMgr.getLogPath().string() + std::string("/"), - mCfgMgr.getCachePath ().string(), mScriptConsoleMode, mTranslationDataStorage, mEncoding, mExportFonts, mFallbackMap); + std::string myguiResources = (mResDir / "mygui").string(); + osg::ref_ptr guiRoot = new osg::Group; + rootNode->addChild(guiRoot); + MWGui::WindowManager* window = new MWGui::WindowManager(&mViewer, guiRoot, mResourceSystem->getTextureManager(), + mCfgMgr.getLogPath().string() + std::string("/"), myguiResources, + mScriptConsoleMode, mTranslationDataStorage, mEncoding, mExportFonts, mFallbackMap); mEnvironment.setWindowManager (window); // Create sound system diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index de09082d8..8c73920bd 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -99,16 +99,10 @@ namespace OMW bool mScriptBlacklistUse; bool mNewGame; - //Nif::Cache mNifCache; - // not implemented Engine (const Engine&); Engine& operator= (const Engine&); - /// add resources directory - /// \note This function works recursively. - void addResourcesDirectory (const boost::filesystem::path& path); - void executeLocalScripts(); virtual bool frameRenderingQueued (const Ogre::FrameEvent& evt); diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index 6ad4da3bf..0a8667d80 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -53,7 +53,7 @@ namespace MWGui std::string output = sstream.str(); mVersionText->setCaption(output); - mHasAnimatedMenu = (Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup("video\\menu_background.bik")); + mHasAnimatedMenu = 0;//(Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup("video\\menu_background.bik")); updateMenu(); } diff --git a/apps/openmw/mwgui/myguidatamanager.cpp b/apps/openmw/mwgui/myguidatamanager.cpp new file mode 100644 index 000000000..5ba54b009 --- /dev/null +++ b/apps/openmw/mwgui/myguidatamanager.cpp @@ -0,0 +1,64 @@ +#include "myguidatamanager.hpp" + +#include + +#include +#include + +#include + +namespace MWGui +{ + +void DataManager::setResourcePath(const std::string &path) +{ + mResourcePath = path; +} + +MyGUI::IDataStream *DataManager::getData(const std::string &name) +{ + std::string fullpath = getDataPath(name); + std::auto_ptr stream; + stream.reset(new boost::filesystem::ifstream); + stream->open(fullpath, std::ios::binary); + if (stream->fail()) + { + std::cerr << "DataManager::getData: Failed to open '" << name << "'" << std::endl; + return NULL; + } + return new MyGUI::DataFileStream(stream.release()); +} + +void DataManager::freeData(MyGUI::IDataStream *data) +{ + delete data; +} + +bool DataManager::isDataExist(const std::string &name) +{ + std::string fullpath = mResourcePath + "/" + name; + return boost::filesystem::exists(fullpath); +} + +const MyGUI::VectorString &DataManager::getDataListNames(const std::string &pattern) +{ + // TODO: pattern matching (unused?) + static MyGUI::VectorString strings; + strings.clear(); + strings.push_back(getDataPath(pattern)); + return strings; +} + +const std::string &DataManager::getDataPath(const std::string &name) +{ + static std::string result; + result.clear(); + if (!isDataExist(name)) + { + return result; + } + result = mResourcePath + "/" + name; + return result; +} + +} diff --git a/apps/openmw/mwgui/myguidatamanager.hpp b/apps/openmw/mwgui/myguidatamanager.hpp new file mode 100644 index 000000000..eaf60f8b9 --- /dev/null +++ b/apps/openmw/mwgui/myguidatamanager.hpp @@ -0,0 +1,50 @@ +#ifndef OPENMW_MWGUI_MYGUIDATAMANAGER_H +#define OPENMW_MWGUI_MYGUIDATAMANAGER_H + +#include + +namespace MWGui +{ + + +class DataManager : public MyGUI::DataManager +{ +public: + void initialise() {} + void shutdown() {} + + void setResourcePath(const std::string& path); + + /** Get data stream from specified resource name. + @param _name Resource name (usually file name). + */ + virtual MyGUI::IDataStream* getData(const std::string& _name); + + /** Free data stream. + @param _data Data stream. + */ + virtual void freeData(MyGUI::IDataStream* _data); + + /** Is data with specified name exist. + @param _name Resource name. + */ + virtual bool isDataExist(const std::string& _name); + + /** Get all data names with names that matches pattern. + @param _pattern Pattern to match (for example "*.layout"). + */ + virtual const MyGUI::VectorString& getDataListNames(const std::string& _pattern); + + /** Get full path to data. + @param _name Resource name. + @return Return full path to specified data. + */ + virtual const std::string& getDataPath(const std::string& _name); + +private: + std::string mResourcePath; +}; + +} + +#endif diff --git a/apps/openmw/mwgui/myguiplatform.cpp b/apps/openmw/mwgui/myguiplatform.cpp new file mode 100644 index 000000000..01d6ca567 --- /dev/null +++ b/apps/openmw/mwgui/myguiplatform.cpp @@ -0,0 +1,2 @@ +#include "myguiplatform.hpp" + diff --git a/apps/openmw/mwgui/myguiplatform.hpp b/apps/openmw/mwgui/myguiplatform.hpp new file mode 100644 index 000000000..4c3e70143 --- /dev/null +++ b/apps/openmw/mwgui/myguiplatform.hpp @@ -0,0 +1,74 @@ +#ifndef OPENMW_MWGUI_MYGUIPLATFORM_H +#define OPENMW_MWGUI_MYGUIPLATFORM_H + +#include "MyGUI_Prerequest.h" +#include "MyGUI_DummyRenderManager.h" +#include "MyGUI_DummyDataManager.h" +#include "MyGUI_DummyDiagnostic.h" +#include "MyGUI_LogManager.h" + +#include "myguirendermanager.hpp" +#include "myguidatamanager.hpp" + +namespace MWGui +{ + + class Platform + { + public: + Platform(osgViewer::Viewer* viewer, osg::Group* guiRoot, Resource::TextureManager* textureManager) : + mLogManager(nullptr), + mRenderManager(nullptr), + mDataManager(nullptr) + { + mLogManager = new MyGUI::LogManager(); + mRenderManager = new RenderManager(viewer, guiRoot, textureManager); + mDataManager = new DataManager(); + } + + ~Platform() + { + delete mRenderManager; + mRenderManager = nullptr; + delete mDataManager; + mDataManager = nullptr; + delete mLogManager; + mLogManager = nullptr; + } + + void initialise(const std::string& resourcePath, const std::string& _logName = MYGUI_PLATFORM_LOG_FILENAME) + { + if (!_logName.empty()) + MyGUI::LogManager::getInstance().createDefaultSource(_logName); + + mDataManager->setResourcePath(resourcePath); + + mRenderManager->initialise(); + mDataManager->initialise(); + } + + void shutdown() + { + //mRenderManager->shutdown(); + mDataManager->shutdown(); + } + + RenderManager* getRenderManagerPtr() + { + return mRenderManager; + } + + DataManager* getDataManagerPtr() + { + return mDataManager; + } + + private: + RenderManager* mRenderManager; + DataManager* mDataManager; + MyGUI::LogManager* mLogManager; + }; + +} + +#endif diff --git a/apps/openmw/mwgui/myguirendermanager.cpp b/apps/openmw/mwgui/myguirendermanager.cpp new file mode 100644 index 000000000..53a194c73 --- /dev/null +++ b/apps/openmw/mwgui/myguirendermanager.cpp @@ -0,0 +1,626 @@ +#include "myguirendermanager.hpp" + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include + +#define MYGUI_PLATFORM_LOG_SECTION "Platform" +#define MYGUI_PLATFORM_LOG(level, text) MYGUI_LOGGING(MYGUI_PLATFORM_LOG_SECTION, level, text) + +#define MYGUI_PLATFORM_EXCEPT(dest) do { \ + MYGUI_PLATFORM_LOG(Critical, dest); \ + MYGUI_DBG_BREAK;\ + std::ostringstream stream; \ + stream << dest << "\n"; \ + MYGUI_BASE_EXCEPT(stream.str().c_str(), "MyGUI"); \ +} while(0) + +#define MYGUI_PLATFORM_ASSERT(exp, dest) do { \ + if ( ! (exp) ) \ + { \ + MYGUI_PLATFORM_LOG(Critical, dest); \ + MYGUI_DBG_BREAK;\ + std::ostringstream stream; \ + stream << dest << "\n"; \ + MYGUI_BASE_EXCEPT(stream.str().c_str(), "MyGUI"); \ + } \ +} while(0) + +namespace +{ + +// Proxy to forward a Drawable's draw call to RenderManager::drawFrame +class Renderable : public osg::Drawable { + MWGui::RenderManager *mParent; + + virtual void drawImplementation(osg::RenderInfo &renderInfo) const + { mParent->drawFrame(renderInfo); } + +public: + Renderable(MWGui::RenderManager *parent=nullptr) : mParent(parent) { } + Renderable(const Renderable ©, const osg::CopyOp ©op=osg::CopyOp::SHALLOW_COPY) + : osg::Drawable(copy, copyop) + , mParent(copy.mParent) + { } + + META_Object(MWGui, Renderable) +}; + +// Proxy to forward an OSG resize event to RenderManager::setViewSize +class ResizeHandler : public osgGA::GUIEventHandler { + MWGui::RenderManager *mParent; + + virtual bool handle(const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter &aa) + { + if(ea.getEventType() == osgGA::GUIEventAdapter::RESIZE) + { + int width = ea.getWindowWidth(); + int height = ea.getWindowHeight(); + mParent->setViewSize(width, height); + } + return false; + } + +public: + ResizeHandler(MWGui::RenderManager *parent=nullptr) : mParent(parent) { } + ResizeHandler(const ResizeHandler ©, const osg::CopyOp ©op=osg::CopyOp::SHALLOW_COPY) + : osg::Object(copy, copyop), osgGA::GUIEventHandler(copy, copyop) + , mParent(copy.mParent) + { } + + META_Object(MWGui, ResizeHandler) +}; + +} + + +namespace MWGui +{ + +class OSGVertexBuffer : public MyGUI::IVertexBuffer +{ + osg::ref_ptr mBuffer; + osg::ref_ptr mPositionArray; + osg::ref_ptr mColorArray; + osg::ref_ptr mTexCoordArray; + std::vector mLockedData; + + size_t mNeedVertexCount; + +public: + OSGVertexBuffer(); + virtual ~OSGVertexBuffer(); + + virtual void setVertexCount(size_t count); + virtual size_t getVertexCount(); + + virtual MyGUI::Vertex *lock(); + virtual void unlock(); + +/*internal:*/ + void destroy(); + void create(); + + osg::VertexBufferObject *getBuffer() const { return mBuffer.get(); } +}; + +OSGVertexBuffer::OSGVertexBuffer() + : mNeedVertexCount(0) +{ +} + +OSGVertexBuffer::~OSGVertexBuffer() +{ + destroy(); +} + +void OSGVertexBuffer::setVertexCount(size_t count) +{ + if(count == mNeedVertexCount) + return; + + mNeedVertexCount = count; + destroy(); + create(); +} + +size_t OSGVertexBuffer::getVertexCount() +{ + return mNeedVertexCount; +} + +MyGUI::Vertex *OSGVertexBuffer::lock() +{ + MYGUI_PLATFORM_ASSERT(mBuffer.valid(), "Vertex buffer is not created"); + + // NOTE: Unfortunately, MyGUI wants the VBO data to be interleaved as a + // MyGUI::Vertex structure. However, OSG uses non-interleaved elements, so + // we have to give back a "temporary" structure array then copy it to the + // actual VBO arrays on unlock. This is extra unfortunate since the VBO may + // be backed by VRAM, meaning we could have up to 3 copies of the data + // (which we'll need to keep for VBOs that are continually updated). + mLockedData.resize(mNeedVertexCount, MyGUI::Vertex()); + return mLockedData.data(); +} + +void OSGVertexBuffer::unlock() +{ + osg::Vec3 *vec = &mPositionArray->front(); + for (std::vector::const_iterator it = mLockedData.begin(); it != mLockedData.end(); ++it) + { + const MyGUI::Vertex& elem = *it; + vec->set(elem.x, elem.y, elem.z); + ++vec; + } + osg::Vec4ub *clr = &mColorArray->front(); + for (std::vector::const_iterator it = mLockedData.begin(); it != mLockedData.end(); ++it) + { + const MyGUI::Vertex& elem = *it; + union { + MyGUI::uint32 ui; + unsigned char ub4[4]; + } val = { elem.colour }; + clr->set(val.ub4[0], val.ub4[1], val.ub4[2], val.ub4[3]); + ++clr; + } + osg::Vec2 *crds = &mTexCoordArray->front(); + for (std::vector::const_iterator it = mLockedData.begin(); it != mLockedData.end(); ++it) + { + const MyGUI::Vertex& elem = *it; + crds->set(elem.u, elem.v); + ++crds; + } + + mBuffer->dirty(); +} + +void OSGVertexBuffer::destroy() +{ + mBuffer = nullptr; + mPositionArray = nullptr; + mColorArray = nullptr; + mTexCoordArray = nullptr; + std::vector().swap(mLockedData); +} + +void OSGVertexBuffer::create() +{ + MYGUI_PLATFORM_ASSERT(!mBuffer.valid(), "Vertex buffer already exist"); + + mPositionArray = new osg::Vec3Array(mNeedVertexCount); + mColorArray = new osg::Vec4ubArray(mNeedVertexCount); + mTexCoordArray = new osg::Vec2Array(mNeedVertexCount); + mColorArray->setNormalize(true); + + mBuffer = new osg::VertexBufferObject; + mBuffer->setDataVariance(osg::Object::DYNAMIC); + mBuffer->setUsage(GL_STREAM_DRAW); + mBuffer->setArray(0, mPositionArray.get()); + mBuffer->setArray(1, mColorArray.get()); + mBuffer->setArray(2, mTexCoordArray.get()); +} + +// --------------------------------------------------------------------------- + +class OSGTexture : public MyGUI::ITexture { + std::string mName; + Resource::TextureManager* mTextureManager; + + osg::ref_ptr mLockedImage; + osg::ref_ptr mTexture; + MyGUI::PixelFormat mFormat; + MyGUI::TextureUsage mUsage; + size_t mNumElemBytes; + +public: + OSGTexture(const std::string &name, Resource::TextureManager* textureManager); + virtual ~OSGTexture(); + + virtual const std::string& getName() const { return mName; } + + virtual void createManual(int width, int height, MyGUI::TextureUsage usage, MyGUI::PixelFormat format); + virtual void loadFromFile(const std::string &fname); + virtual void saveToFile(const std::string &fname); + + virtual void destroy(); + + virtual void* lock(MyGUI::TextureUsage access); + virtual void unlock(); + virtual bool isLocked(); + + virtual int getWidth(); + virtual int getHeight(); + + virtual MyGUI::PixelFormat getFormat() { return mFormat; } + virtual MyGUI::TextureUsage getUsage() { return mUsage; } + virtual size_t getNumElemBytes() { return mNumElemBytes; } + + virtual MyGUI::IRenderTarget *getRenderTarget(); + +/*internal:*/ + osg::Texture2D *getTexture() const { return mTexture.get(); } +}; + +OSGTexture::OSGTexture(const std::string &name, Resource::TextureManager* textureManager) + : mName(name) + , mTextureManager(textureManager) + , mFormat(MyGUI::PixelFormat::Unknow) + , mUsage(MyGUI::TextureUsage::Default) + , mNumElemBytes(0) +{ +} + +OSGTexture::~OSGTexture() +{ +} + +void OSGTexture::createManual(int width, int height, MyGUI::TextureUsage usage, MyGUI::PixelFormat format) +{ + GLenum glfmt = GL_NONE; + size_t numelems = 0; + switch(format.getValue()) + { + case MyGUI::PixelFormat::L8: + glfmt = GL_LUMINANCE; + numelems = 1; + break; + case MyGUI::PixelFormat::L8A8: + glfmt = GL_LUMINANCE_ALPHA; + numelems = 2; + break; + case MyGUI::PixelFormat::R8G8B8: + glfmt = GL_RGB; + numelems = 3; + break; + case MyGUI::PixelFormat::R8G8B8A8: + glfmt = GL_RGBA; + numelems = 4; + break; + } + if(glfmt == GL_NONE) + throw std::runtime_error("Texture format not supported"); + + mTexture = new osg::Texture2D(); + mTexture->setTextureSize(width, height); + mTexture->setSourceFormat(glfmt); + mTexture->setSourceType(GL_UNSIGNED_BYTE); + + mTexture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR); + mTexture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); + mTexture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); + mTexture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); + + mFormat = format; + mUsage = usage; + mNumElemBytes = numelems; +} + +void OSGTexture::destroy() +{ + mTexture = nullptr; + mFormat = MyGUI::PixelFormat::Unknow; + mUsage = MyGUI::TextureUsage::Default; + mNumElemBytes = 0; +} + +void OSGTexture::loadFromFile(const std::string &fname) +{ + mTexture = mTextureManager->getTexture2D(fname, osg::Texture2D::CLAMP, osg::Texture2D::CLAMP); + + // FIXME + mFormat = MyGUI::PixelFormat::R8G8B8; + mUsage = MyGUI::TextureUsage::Static | MyGUI::TextureUsage::Write; + mNumElemBytes = 3; // FIXME +} + +void OSGTexture::saveToFile(const std::string &fname) +{ + std::cerr << "Would save image to file " << fname << std::endl; +} + + +int OSGTexture::getWidth() +{ + if(!mTexture.valid()) + return 0; + osg::Image *image = mTexture->getImage(); + if(image) return image->s(); + return mTexture->getTextureWidth(); +} + +int OSGTexture::getHeight() +{ + if(!mTexture.valid()) + return 0; + osg::Image *image = mTexture->getImage(); + if(image) return image->t(); + return mTexture->getTextureHeight(); +} + + +void *OSGTexture::lock(MyGUI::TextureUsage /*access*/) +{ + MYGUI_PLATFORM_ASSERT(mTexture.valid(), "Texture is not created"); + MYGUI_PLATFORM_ASSERT(!mLockedImage.valid(), "Texture already locked"); + + mLockedImage = mTexture->getImage(); + if(!mLockedImage.valid()) + { + mLockedImage = new osg::Image(); + mLockedImage->allocateImage( + mTexture->getTextureWidth(), mTexture->getTextureHeight(), mTexture->getTextureDepth(), + mTexture->getSourceFormat(), mTexture->getSourceType() + ); + } + return mLockedImage->data(); +} + +void OSGTexture::unlock() +{ + MYGUI_PLATFORM_ASSERT(mLockedImage.valid(), "Texture not locked"); + + // Tell the texture it can get rid of the image for static textures (since + // they aren't expected to update much at all). + mTexture->setImage(mLockedImage.get()); + mTexture->setUnRefImageDataAfterApply(mUsage.isValue(MyGUI::TextureUsage::Static) ? true : false); + mTexture->dirtyTextureObject(); + + mLockedImage = nullptr; +} + +bool OSGTexture::isLocked() +{ + return mLockedImage.valid(); +} + + +// FIXME: Render-to-texture not currently implemented. +MyGUI::IRenderTarget* OSGTexture::getRenderTarget() +{ + return nullptr; +} + +// --------------------------------------------------------------------------- + +RenderManager::RenderManager(osgViewer::Viewer *viewer, osg::Group *sceneroot, Resource::TextureManager* textureManager) + : mViewer(viewer) + , mSceneRoot(sceneroot) + , mTextureManager(textureManager) + , mUpdate(false) + , mIsInitialise(false) +{ +} + +RenderManager::~RenderManager() +{ + MYGUI_PLATFORM_LOG(Info, "* Shutdown: "<removeChild(mGuiRoot.get()); + mGuiRoot = nullptr; + mSceneRoot = nullptr; + mViewer = nullptr; + + destroyAllResources(); + + MYGUI_PLATFORM_LOG(Info, getClassTypeName()<<" successfully shutdown"); + mIsInitialise = false; +} + + +void RenderManager::initialise() +{ + MYGUI_PLATFORM_ASSERT(!mIsInitialise, getClassTypeName()<<" initialised twice"); + MYGUI_PLATFORM_LOG(Info, "* Initialise: "< drawable = new Renderable(this); + drawable->setSupportsDisplayList(false); + drawable->setUseVertexBufferObjects(true); + drawable->setDataVariance(osg::Object::DYNAMIC); + + osg::ref_ptr geode = new osg::Geode; + geode->addDrawable(drawable.get()); + + osg::ref_ptr camera = new osg::Camera(); + camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF); + camera->setProjectionResizePolicy(osg::Camera::FIXED); + camera->setProjectionMatrix(osg::Matrix::identity()); + camera->setViewMatrix(osg::Matrix::identity()); + camera->setRenderOrder(osg::Camera::POST_RENDER); + camera->setClearMask(GL_NONE); + osg::StateSet *state = new osg::StateSet; + state->setTextureMode(0, GL_TEXTURE_GEN_S, osg::StateAttribute::OFF); + state->setTextureMode(0, GL_TEXTURE_GEN_T, osg::StateAttribute::OFF); + state->setTextureMode(0, GL_TEXTURE_GEN_R, osg::StateAttribute::OFF); + state->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::ON); + state->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF); + state->setMode(GL_LIGHTING, osg::StateAttribute::OFF); + state->setMode(GL_LIGHT0, osg::StateAttribute::OFF); + state->setMode(GL_BLEND, osg::StateAttribute::ON); + state->setMode(GL_FOG, osg::StateAttribute::OFF); + state->setTextureAttribute(0, new osg::TexEnv(osg::TexEnv::MODULATE)); + state->setAttribute(new osg::PolygonMode(osg::PolygonMode::FRONT, osg::PolygonMode::FILL)); + state->setAttribute(new osg::BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); + state->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); + state->setRenderBinDetails(11, "RenderBin"); + state->setMode(GL_CULL_FACE, osg::StateAttribute::OFF); + geode->setStateSet(state); + geode->setCullingActive(false); + camera->addChild(geode.get()); + + mGuiRoot = camera; + mSceneRoot->addChild(mGuiRoot.get()); + mViewer->addEventHandler(new ResizeHandler(this)); + + osg::ref_ptr vp = mViewer->getCamera()->getViewport(); + setViewSize(vp->width(), vp->height()); + + MYGUI_PLATFORM_LOG(Info, getClassTypeName()<<" successfully initialized"); + mIsInitialise = true; +} + +MyGUI::IVertexBuffer* RenderManager::createVertexBuffer() +{ + return new OSGVertexBuffer(); +} + +void RenderManager::destroyVertexBuffer(MyGUI::IVertexBuffer *buffer) +{ + delete buffer; +} + + +void RenderManager::begin() +{ + osg::State *state = mRenderInfo->getState(); + state->disableAllVertexArrays(); +} + +void RenderManager::doRender(MyGUI::IVertexBuffer *buffer, MyGUI::ITexture *texture, size_t count) +{ + osg::State *state = mRenderInfo->getState(); + osg::VertexBufferObject *vbo = static_cast(buffer)->getBuffer(); + MYGUI_PLATFORM_ASSERT(vbo, "Vertex buffer is not created"); + + if(texture) + { + osg::Texture2D *tex = static_cast(texture)->getTexture(); + MYGUI_PLATFORM_ASSERT(tex, "Texture is not created"); + state->applyTextureAttribute(0, tex); + } + + state->setVertexPointer(vbo->getArray(0)); + state->setColorPointer(vbo->getArray(1)); + state->setTexCoordPointer(0, vbo->getArray(2)); + + glDrawArrays(GL_TRIANGLES, 0, count); +} + +void RenderManager::end() +{ + osg::State *state = mRenderInfo->getState(); + state->disableTexCoordPointer(0); + state->disableColorPointer(); + state->disableVertexPointer(); + state->unbindVertexBufferObject(); +} + +void RenderManager::drawFrame(osg::RenderInfo &renderInfo) +{ + MyGUI::Gui *gui = MyGUI::Gui::getInstancePtr(); + if(gui == nullptr) return; + + mRenderInfo = &renderInfo; + + static MyGUI::Timer timer; + static unsigned long last_time = timer.getMilliseconds(); + unsigned long now_time = timer.getMilliseconds(); + unsigned long time = now_time - last_time; + + onFrameEvent((float)((double)(time) / (double)1000)); + + last_time = now_time; + + begin(); + onRenderToTarget(this, mUpdate); + end(); + + mUpdate = false; +} + +void RenderManager::setViewSize(int width, int height) +{ + if(width < 1) width = 1; + if(height < 1) height = 1; + + mGuiRoot->setViewport(0, 0, width, height); + mViewSize.set(width, height); + + mInfo.maximumDepth = 1; + mInfo.hOffset = 0; + mInfo.vOffset = 0; + mInfo.aspectCoef = float(mViewSize.height) / float(mViewSize.width); + mInfo.pixScaleX = 1.0f / float(mViewSize.width); + mInfo.pixScaleY = 1.0f / float(mViewSize.height); +std::cout << "setviewsize " << width << " " << height << std::endl; + onResizeView(mViewSize); + mUpdate = true; +} + + +bool RenderManager::isFormatSupported(MyGUI::PixelFormat /*format*/, MyGUI::TextureUsage /*usage*/) +{ + return true; +} + +MyGUI::ITexture* RenderManager::createTexture(const std::string &name) +{ + MapTexture::const_iterator item = mTextures.find(name); + MYGUI_PLATFORM_ASSERT(item == mTextures.end(), "Texture '"<getName()); + MYGUI_PLATFORM_ASSERT(item != mTextures.end(), "Texture '"<getName()<<"' not found"); + + mTextures.erase(item); + delete texture; +} + +MyGUI::ITexture* RenderManager::getTexture(const std::string &name) +{ + MapTexture::const_iterator item = mTextures.find(name); + if(item == mTextures.end()) + { + MyGUI::ITexture* tex = createTexture(name); + tex->loadFromFile(name); + return tex; + } + return item->second; +} + +void RenderManager::destroyAllResources() +{ + for (MapTexture::iterator it = mTextures.begin(); it != mTextures.end(); ++it) + delete it->second; + mTextures.clear(); +} + +bool RenderManager::checkTexture(MyGUI::ITexture* _texture) +{ + for (MapTexture::const_iterator item = mTextures.begin(); item != mTextures.end(); ++item) + { + if (item->second == _texture) + return true; + } + return false; +} + +} diff --git a/apps/openmw/mwgui/myguirendermanager.hpp b/apps/openmw/mwgui/myguirendermanager.hpp new file mode 100644 index 000000000..64a5fe07b --- /dev/null +++ b/apps/openmw/mwgui/myguirendermanager.hpp @@ -0,0 +1,101 @@ +#ifndef OPENMW_MWGUI_MYGUIRENDERMANAGER_H +#define OPENMW_MWGUI_MYGUIRENDERMANAGER_H + +#include + +#include + +namespace Resource +{ + class TextureManager; +} + +namespace osgViewer +{ + class Viewer; +} + +namespace osg +{ + class Group; + class Camera; + class RenderInfo; +} + +namespace MWGui +{ + +class RenderManager : public MyGUI::RenderManager, public MyGUI::IRenderTarget +{ + osg::ref_ptr mViewer; + osg::ref_ptr mSceneRoot; + Resource::TextureManager* mTextureManager; + + MyGUI::IntSize mViewSize; + bool mUpdate; + MyGUI::VertexColourType mVertexFormat; + MyGUI::RenderTargetInfo mInfo; + + typedef std::map MapTexture; + MapTexture mTextures; + + bool mIsInitialise; + + osg::ref_ptr mGuiRoot; + + // Only valid during drawFrame()! + osg::RenderInfo *mRenderInfo; + + void destroyAllResources(); + +public: + RenderManager(osgViewer::Viewer *viewer, osg::Group *sceneroot, Resource::TextureManager* textureManager); + virtual ~RenderManager(); + + void initialise(); + + static RenderManager& getInstance() { return *getInstancePtr(); } + static RenderManager* getInstancePtr() + { return static_cast(MyGUI::RenderManager::getInstancePtr()); } + + /** @see RenderManager::getViewSize */ + virtual const MyGUI::IntSize& getViewSize() const { return mViewSize; } + + /** @see RenderManager::getVertexFormat */ + virtual MyGUI::VertexColourType getVertexFormat() { return mVertexFormat; } + + /** @see RenderManager::isFormatSupported */ + virtual bool isFormatSupported(MyGUI::PixelFormat format, MyGUI::TextureUsage usage); + + /** @see RenderManager::createVertexBuffer */ + virtual MyGUI::IVertexBuffer* createVertexBuffer(); + /** @see RenderManager::destroyVertexBuffer */ + virtual void destroyVertexBuffer(MyGUI::IVertexBuffer *buffer); + + /** @see RenderManager::createTexture */ + virtual MyGUI::ITexture* createTexture(const std::string &name); + /** @see RenderManager::destroyTexture */ + virtual void destroyTexture(MyGUI::ITexture* _texture); + /** @see RenderManager::getTexture */ + virtual MyGUI::ITexture* getTexture(const std::string &name); + + + /** @see IRenderTarget::begin */ + virtual void begin(); + /** @see IRenderTarget::end */ + virtual void end(); + /** @see IRenderTarget::doRender */ + virtual void doRender(MyGUI::IVertexBuffer *buffer, MyGUI::ITexture *texture, size_t count); + /** @see IRenderTarget::getInfo */ + virtual const MyGUI::RenderTargetInfo& getInfo() { return mInfo; } + + bool checkTexture(MyGUI::ITexture* _texture); + +/*internal:*/ + void drawFrame(osg::RenderInfo &renderInfo); + void setViewSize(int width, int height); +}; + +} + +#endif diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 4ae610f51..63d74b355 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -19,8 +19,6 @@ #include #include -#include - #include #include @@ -93,14 +91,16 @@ #include "controllers.hpp" #include "jailscreen.hpp" +#include "myguiplatform.hpp" + namespace MWGui { WindowManager::WindowManager( - const Compiler::Extensions& extensions, const std::string& logpath, const std::string& cacheDir, bool consoleOnlyScripts, + osgViewer::Viewer* viewer, osg::Group* guiRoot, Resource::TextureManager* textureManager + , const std::string& logpath, const std::string& resourcePath, bool consoleOnlyScripts, Translation::Storage& translationDataStorage, ToUTF8::FromType encoding, bool exportFonts, const std::map& fallbackMap) : mConsoleOnlyScripts(consoleOnlyScripts) - //, mGuiManager(NULL) , mHud(NULL) , mMap(NULL) , mMenu(NULL) @@ -173,11 +173,8 @@ namespace MWGui , mCurrentModals() , mFallbackMap(fallbackMap) { - // Set up the GUI system - //mGuiManager = new OEngine::GUI::MyGUIManager(mRendering->getWindow(), mRendering->getScene(), false, logpath); - - MyGUI::DummyPlatform* platform = new MyGUI::DummyPlatform; - platform->initialise(logpath); + Platform* platform = new Platform(viewer, guiRoot, textureManager); + platform->initialise(resourcePath, logpath); MyGUI::Gui* gui = new MyGUI::Gui; gui->initialise(""); @@ -248,7 +245,6 @@ namespace MWGui void WindowManager::initUI() { - /* // Get size info from the Gui object int w = MyGUI::RenderManager::getInstance().getViewSize().width; int h = MyGUI::RenderManager::getInstance().getViewSize().height; @@ -304,8 +300,8 @@ namespace MWGui std::string hitFaderTexture = "textures\\bm_player_hit_01.dds"; // fall back to player_hit_01.dds if bm_player_hit_01.dds is not available // TODO: check if non-BM versions actually use player_hit_01.dds - if(!Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(hitFaderTexture)) - hitFaderTexture = "textures\\player_hit_01.dds"; + //if(!Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(hitFaderTexture)) + // hitFaderTexture = "textures\\player_hit_01.dds"; mHitFader = new ScreenFader(hitFaderTexture); mScreenFader = new ScreenFader("black.png"); @@ -331,8 +327,7 @@ namespace MWGui // Set up visibility updateVisible(); - MWBase::Environment::get().getInputManager()->changeInputMode(false); - */ + //MWBase::Environment::get().getInputManager()->changeInputMode(false); } void WindowManager::renderWorldMap() @@ -416,8 +411,6 @@ namespace MWGui //delete mCursorManager; cleanupGarbage(); - - //delete mGuiManager; } void WindowManager::cleanupGarbage() @@ -928,7 +921,6 @@ namespace MWGui void WindowManager::changeCell(MWWorld::CellStore* cell) { - /* std::string name = MWBase::Environment::get().getWorld()->getCellName (cell); mMap->setCellName( name ); @@ -953,12 +945,10 @@ namespace MWGui MWBase::Environment::get().getWorld()->getPlayer().setLastKnownExteriorPosition(worldPos); mMap->setGlobalMapPlayerPosition(worldPos.x, worldPos.y); } - */ } void WindowManager::setActiveMap(int x, int y, bool interior) { - /* if (!interior) { mMap->setCellPrefix("Cell"); @@ -967,22 +957,19 @@ namespace MWGui mMap->setActiveCell(x,y, interior); mHud->setActiveCell(x,y, interior); - */ } void WindowManager::setPlayerPos(int cellX, int cellY, const float x, const float y) { - //mMap->setPlayerPos(cellX, cellY, x, y); - //mHud->setPlayerPos(cellX, cellY, x, y); + mMap->setPlayerPos(cellX, cellY, x, y); + mHud->setPlayerPos(cellX, cellY, x, y); } void WindowManager::setPlayerDir(const float x, const float y) { - /* mMap->setPlayerDir(x,y); mMap->setGlobalMapPlayerDir(x, y); mHud->setPlayerDir(x,y); - */ } void WindowManager::setDrowningBarVisibility(bool visible) @@ -1098,7 +1085,7 @@ namespace MWGui void WindowManager::windowResized(int x, int y) { sizeVideo(x, y); - //mGuiManager->windowResized(); + if (!mHud) return; // UI not initialized yet @@ -1279,7 +1266,7 @@ namespace MWGui void WindowManager::executeInConsole (const std::string& path) { - //mConsole->executeFile (path); + mConsole->executeFile (path); } void WindowManager::wmUpdateFps(float fps, unsigned int triangleCount, unsigned int batchCount) @@ -1520,7 +1507,7 @@ namespace MWGui void WindowManager::updatePlayer() { - //mInventoryWindow->updatePlayer(); + mInventoryWindow->updatePlayer(); const MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); if (player.getClass().getNpcStats(player).isWerewolf()) @@ -1808,29 +1795,23 @@ namespace MWGui void WindowManager::fadeScreenIn(const float time, bool clearQueue) { - /* if (clearQueue) mScreenFader->clearQueue(); mScreenFader->fadeOut(time); - */ } void WindowManager::fadeScreenOut(const float time, bool clearQueue) { - /* if (clearQueue) mScreenFader->clearQueue(); mScreenFader->fadeIn(time); - */ } void WindowManager::fadeScreenTo(const int percent, const float time, bool clearQueue) { - /* if (clearQueue) mScreenFader->clearQueue(); mScreenFader->fadeTo(percent, time); - */ } void WindowManager::setBlindness(const int percent) diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index ddb9368c5..a98fbf7b8 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -52,6 +52,20 @@ namespace OEngine } } +namespace osg +{ + class Group; +} +namespace osgViewer +{ + class Viewer; +} + +namespace Resource +{ + class TextureManager; +} + namespace SFO { class CursorManager; @@ -99,8 +113,8 @@ namespace MWGui typedef std::pair Faction; typedef std::vector FactionList; - WindowManager(const Compiler::Extensions& extensions, const std::string& logpath, - const std::string& cacheDir, bool consoleOnlyScripts, + WindowManager(osgViewer::Viewer* viewer, osg::Group* guiRoot, Resource::TextureManager* textureManager, + const std::string& logpath, const std::string& cacheDir, bool consoleOnlyScripts, Translation::Storage& translationDataStorage, ToUTF8::FromType encoding, bool exportFonts, const std::map& fallbackMap); virtual ~WindowManager(); @@ -364,7 +378,6 @@ namespace MWGui // Markers placed manually by the player. Must be shared between both map views (the HUD map and the map window). CustomMarkerCollection mCustomMarkers; - OEngine::GUI::MyGUIManager *mGuiManager; HUD *mHud; MapWindow *mMap; MainMenu *mMenu; diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index be23ebc2f..32afc73c2 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -101,9 +101,9 @@ namespace MWRender mSunLight->setConstantAttenuation(1.f); lightRoot->addChild(source); - mRootNode->getOrCreateStateSet()->setMode(GL_CULL_FACE, osg::StateAttribute::ON); - mRootNode->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::ON); - mRootNode->getOrCreateStateSet()->setMode(GL_NORMALIZE, osg::StateAttribute::ON); + lightRoot->getOrCreateStateSet()->setMode(GL_CULL_FACE, osg::StateAttribute::ON); + lightRoot->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::ON); + lightRoot->getOrCreateStateSet()->setMode(GL_NORMALIZE, osg::StateAttribute::ON); source->setStateSetModes(*mRootNode->getOrCreateStateSet(), osg::StateAttribute::ON); diff --git a/libs/openengine/gui/manager.cpp b/libs/openengine/gui/manager.cpp deleted file mode 100644 index 349647892..000000000 --- a/libs/openengine/gui/manager.cpp +++ /dev/null @@ -1,680 +0,0 @@ -#include "manager.hpp" -#include "loglistener.hpp" - -#include -#include -#include - -#include -#include -#include - -#include - -#include -#include - -using namespace OEngine::GUI; - -namespace MyGUI -{ - -/* - * As of MyGUI 3.2.0, MyGUI::OgreDataManager::isDataExist is unnecessarily complex - * this override fixes the resulting performance issue. - */ -// Remove for MyGUI 3.2.2 -class FixedOgreDataManager : public MyGUI::OgreDataManager -{ -public: - bool isDataExist(const std::string& _name) - { - return Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup (_name); - } -}; - - -/* - * As of MyGUI 3.2.0, rendering with shaders is not supported. - * We definitely need this though to run in GL3 core / DX11 at all. - * To make matters worse, subclassing OgreRenderManager doesn't seem to be possible here. :/ - */ -class ShaderBasedRenderManager : public RenderManager, - public IRenderTarget, - public Ogre::WindowEventListener, - public Ogre::RenderQueueListener, - public Ogre::RenderSystem::Listener -{ - // флаг для обновления всех и вся - bool mUpdate; - - IntSize mViewSize; - - Ogre::SceneManager* mSceneManager; - - VertexColourType mVertexFormat; - - // окно, на которое мы подписываемся для изменения размеров - Ogre::RenderWindow* mWindow; - - // вьюпорт, с которым работает система - unsigned short mActiveViewport; - - Ogre::RenderSystem* mRenderSystem; - Ogre::TextureUnitState::UVWAddressingMode mTextureAddressMode; - Ogre::LayerBlendModeEx mColorBlendMode, mAlphaBlendMode; - - RenderTargetInfo mInfo; - - typedef std::map MapTexture; - MapTexture mTextures; - - bool mIsInitialise; - bool mManualRender; - size_t mCountBatch; - - // ADDED - Ogre::GpuProgram* mVertexProgramNoTexture; - Ogre::GpuProgram* mVertexProgramOneTexture; - Ogre::GpuProgram* mFragmentProgramNoTexture; - Ogre::GpuProgram* mFragmentProgramOneTexture; - -public: - ShaderBasedRenderManager& getInstance() - { - return *getInstancePtr(); - } - ShaderBasedRenderManager* getInstancePtr() - { - return static_cast(RenderManager::getInstancePtr()); - } - - ShaderBasedRenderManager() : - mUpdate(false), - mSceneManager(nullptr), - mWindow(nullptr), - mActiveViewport(0), - mRenderSystem(nullptr), - mIsInitialise(false), - mManualRender(false), - mCountBatch(0), - mVertexProgramNoTexture(NULL), - mFragmentProgramNoTexture(NULL), - mVertexProgramOneTexture(NULL), - mFragmentProgramOneTexture(NULL) - { - mTextureAddressMode.u = Ogre::TextureUnitState::TAM_CLAMP; - mTextureAddressMode.v = Ogre::TextureUnitState::TAM_CLAMP; - mTextureAddressMode.w = Ogre::TextureUnitState::TAM_CLAMP; - } - - void initialise(Ogre::RenderWindow* _window, Ogre::SceneManager* _scene) - { - MYGUI_PLATFORM_ASSERT(!mIsInitialise, getClassTypeName() << " initialised twice"); - MYGUI_PLATFORM_LOG(Info, "* Initialise: " << getClassTypeName()); - - mColorBlendMode.blendType = Ogre::LBT_COLOUR; - mColorBlendMode.source1 = Ogre::LBS_TEXTURE; - mColorBlendMode.source2 = Ogre::LBS_DIFFUSE; - mColorBlendMode.operation = Ogre::LBX_MODULATE; - - mAlphaBlendMode.blendType = Ogre::LBT_ALPHA; - mAlphaBlendMode.source1 = Ogre::LBS_TEXTURE; - mAlphaBlendMode.source2 = Ogre::LBS_DIFFUSE; - mAlphaBlendMode.operation = Ogre::LBX_MODULATE; - - mTextureAddressMode.u = Ogre::TextureUnitState::TAM_CLAMP; - mTextureAddressMode.v = Ogre::TextureUnitState::TAM_CLAMP; - mTextureAddressMode.w = Ogre::TextureUnitState::TAM_CLAMP; - - mSceneManager = nullptr; - mWindow = nullptr; - mUpdate = false; - mRenderSystem = nullptr; - mActiveViewport = 0; - - Ogre::Root* root = Ogre::Root::getSingletonPtr(); - if (root != nullptr) - setRenderSystem(root->getRenderSystem()); - setRenderWindow(_window); - setSceneManager(_scene); - - - MYGUI_PLATFORM_LOG(Info, getClassTypeName() << " successfully initialized"); - mIsInitialise = true; - } - - void shutdown() - { - MYGUI_PLATFORM_ASSERT(mIsInitialise, getClassTypeName() << " is not initialised"); - MYGUI_PLATFORM_LOG(Info, "* Shutdown: " << getClassTypeName()); - - destroyAllResources(); - - setSceneManager(nullptr); - setRenderWindow(nullptr); - setRenderSystem(nullptr); - - MYGUI_PLATFORM_LOG(Info, getClassTypeName() << " successfully shutdown"); - mIsInitialise = false; - } - - void setRenderSystem(Ogre::RenderSystem* _render) - { - // отписываемся - if (mRenderSystem != nullptr) - { - mRenderSystem->removeListener(this); - mRenderSystem = nullptr; - } - - mRenderSystem = _render; - - // подписываемся на рендер евент - if (mRenderSystem != nullptr) - { - mRenderSystem->addListener(this); - - // формат цвета в вершинах - Ogre::VertexElementType vertex_type = mRenderSystem->getColourVertexElementType(); - if (vertex_type == Ogre::VET_COLOUR_ARGB) - mVertexFormat = VertexColourType::ColourARGB; - else if (vertex_type == Ogre::VET_COLOUR_ABGR) - mVertexFormat = VertexColourType::ColourABGR; - - updateRenderInfo(); - } - } - - Ogre::RenderSystem* getRenderSystem() - { - return mRenderSystem; - } - - void setRenderWindow(Ogre::RenderWindow* _window) - { - // отписываемся - if (mWindow != nullptr) - { - Ogre::WindowEventUtilities::removeWindowEventListener(mWindow, this); - mWindow = nullptr; - } - - mWindow = _window; - - if (mWindow != nullptr) - { - Ogre::WindowEventUtilities::addWindowEventListener(mWindow, this); - windowResized(mWindow); - } - } - - void setSceneManager(Ogre::SceneManager* _scene) - { - if (nullptr != mSceneManager) - { - mSceneManager->removeRenderQueueListener(this); - mSceneManager = nullptr; - } - - mSceneManager = _scene; - - if (nullptr != mSceneManager) - { - mSceneManager->addRenderQueueListener(this); - } - } - - void setActiveViewport(unsigned short _num) - { - mActiveViewport = _num; - - if (mWindow != nullptr) - { - Ogre::WindowEventUtilities::removeWindowEventListener(mWindow, this); - Ogre::WindowEventUtilities::addWindowEventListener(mWindow, this); - - // рассылка обновлений - windowResized(mWindow); - } - } - - void renderQueueStarted(Ogre::uint8 queueGroupId, const Ogre::String& invocation, bool& skipThisInvocation) - { - Gui* gui = Gui::getInstancePtr(); - if (gui == nullptr) - return; - - if (Ogre::RENDER_QUEUE_OVERLAY != queueGroupId) - return; - - Ogre::Viewport* viewport = mSceneManager->getCurrentViewport(); - if (nullptr == viewport - || !viewport->getOverlaysEnabled()) - return; - - if (mWindow->getNumViewports() <= mActiveViewport - || viewport != mWindow->getViewport(mActiveViewport)) - return; - - mCountBatch = 0; - - static Timer timer; - static unsigned long last_time = timer.getMilliseconds(); - unsigned long now_time = timer.getMilliseconds(); - unsigned long time = now_time - last_time; - - onFrameEvent((float)((double)(time) / (double)1000)); - - last_time = now_time; - - //begin(); - setManualRender(true); - onRenderToTarget(this, mUpdate); - //end(); - - // сбрасываем флаг - mUpdate = false; - } - - void renderQueueEnded(Ogre::uint8 queueGroupId, const Ogre::String& invocation, bool& repeatThisInvocation) - { - } - - void eventOccurred(const Ogre::String& eventName, const Ogre::NameValuePairList* parameters) - { - if (eventName == "DeviceLost") - { - } - else if (eventName == "DeviceRestored") - { - // обновить всех - mUpdate = true; - } - } - - IVertexBuffer* createVertexBuffer() - { - return new OgreVertexBuffer(); - } - - void destroyVertexBuffer(IVertexBuffer* _buffer) - { - delete _buffer; - } - - // для оповещений об изменении окна рендера - void windowResized(Ogre::RenderWindow* _window) - { - if (_window->getNumViewports() > mActiveViewport) - { - Ogre::Viewport* port = _window->getViewport(mActiveViewport); -#if OGRE_VERSION >= MYGUI_DEFINE_VERSION(1, 7, 0) && OGRE_NO_VIEWPORT_ORIENTATIONMODE == 0 - Ogre::OrientationMode orient = port->getOrientationMode(); - if (orient == Ogre::OR_DEGREE_90 || orient == Ogre::OR_DEGREE_270) - mViewSize.set(port->getActualHeight(), port->getActualWidth()); - else - mViewSize.set(port->getActualWidth(), port->getActualHeight()); -#else - mViewSize.set(port->getActualWidth(), port->getActualHeight()); -#endif - - // обновить всех - mUpdate = true; - - updateRenderInfo(); - - onResizeView(mViewSize); - } - } - - void updateRenderInfo() - { - if (mRenderSystem != nullptr) - { - mInfo.maximumDepth = mRenderSystem->getMaximumDepthInputValue(); - mInfo.hOffset = mRenderSystem->getHorizontalTexelOffset() / float(mViewSize.width); - mInfo.vOffset = mRenderSystem->getVerticalTexelOffset() / float(mViewSize.height); - mInfo.aspectCoef = float(mViewSize.height) / float(mViewSize.width); - mInfo.pixScaleX = 1.0f / float(mViewSize.width); - mInfo.pixScaleY = 1.0f / float(mViewSize.height); - } - } - - void initShaders() - { - // ADDED - sh::MaterialInstance* mat = sh::Factory::getInstance().getMaterialInstance("MyGUI/NoTexture"); - sh::Factory::getInstance()._ensureMaterial("MyGUI/NoTexture", "Default"); - mVertexProgramNoTexture = static_cast(mat->getMaterial())->getOgreTechniqueForConfiguration("Default")->getPass(0) - ->getVertexProgram()->_getBindingDelegate(); - - mat = sh::Factory::getInstance().getMaterialInstance("MyGUI/OneTexture"); - sh::Factory::getInstance()._ensureMaterial("MyGUI/OneTexture", "Default"); - mVertexProgramOneTexture = static_cast(mat->getMaterial())->getOgreTechniqueForConfiguration("Default")->getPass(0) - ->getVertexProgram()->_getBindingDelegate(); - - mat = sh::Factory::getInstance().getMaterialInstance("MyGUI/NoTexture"); - sh::Factory::getInstance()._ensureMaterial("MyGUI/NoTexture", "Default"); - mFragmentProgramNoTexture = static_cast(mat->getMaterial())->getOgreTechniqueForConfiguration("Default")->getPass(0) - ->getFragmentProgram()->_getBindingDelegate(); - - mat = sh::Factory::getInstance().getMaterialInstance("MyGUI/OneTexture"); - sh::Factory::getInstance()._ensureMaterial("MyGUI/OneTexture", "Default"); - mFragmentProgramOneTexture = static_cast(mat->getMaterial())->getOgreTechniqueForConfiguration("Default")->getPass(0) - ->getFragmentProgram()->_getBindingDelegate(); - } - - void doRender(IVertexBuffer* _buffer, ITexture* _texture, size_t _count) - { - if (getManualRender()) - { - begin(); - setManualRender(false); - } - - // ADDED - if (!mVertexProgramNoTexture) - initShaders(); - - if (_texture) - { - Ogre::Root::getSingleton().getRenderSystem()->bindGpuProgram(mVertexProgramOneTexture); - Ogre::Root::getSingleton().getRenderSystem()->bindGpuProgram(mFragmentProgramOneTexture); - } - else - { - Ogre::Root::getSingleton().getRenderSystem()->bindGpuProgram(mVertexProgramNoTexture); - Ogre::Root::getSingleton().getRenderSystem()->bindGpuProgram(mFragmentProgramNoTexture); - } - - if (_texture) - { - OgreTexture* texture = static_cast(_texture); - Ogre::TexturePtr texture_ptr = texture->getOgreTexture(); - if (!texture_ptr.isNull()) - { - mRenderSystem->_setTexture(0, true, texture_ptr); - mRenderSystem->_setTextureUnitFiltering(0, Ogre::FO_LINEAR, Ogre::FO_LINEAR, Ogre::FO_NONE); - } - } - - OgreVertexBuffer* buffer = static_cast(_buffer); - Ogre::RenderOperation* operation = buffer->getRenderOperation(); - operation->vertexData->vertexCount = _count; - - mRenderSystem->_render(*operation); - - ++ mCountBatch; - } - - void begin() - { - // set-up matrices - mRenderSystem->_setWorldMatrix(Ogre::Matrix4::IDENTITY); - mRenderSystem->_setViewMatrix(Ogre::Matrix4::IDENTITY); - -#if OGRE_VERSION >= MYGUI_DEFINE_VERSION(1, 7, 0) && OGRE_NO_VIEWPORT_ORIENTATIONMODE == 0 - Ogre::OrientationMode orient = mWindow->getViewport(mActiveViewport)->getOrientationMode(); - mRenderSystem->_setProjectionMatrix(Ogre::Matrix4::IDENTITY * Ogre::Quaternion(Ogre::Degree(orient * 90.f), Ogre::Vector3::UNIT_Z)); -#else - mRenderSystem->_setProjectionMatrix(Ogre::Matrix4::IDENTITY); -#endif - - // initialise render settings - mRenderSystem->setLightingEnabled(false); - mRenderSystem->_setDepthBufferParams(false, false); - mRenderSystem->_setDepthBias(0, 0); - mRenderSystem->_setCullingMode(Ogre::CULL_NONE); - mRenderSystem->_setFog(Ogre::FOG_NONE); - mRenderSystem->_setColourBufferWriteEnabled(true, true, true, true); - mRenderSystem->unbindGpuProgram(Ogre::GPT_FRAGMENT_PROGRAM); - mRenderSystem->unbindGpuProgram(Ogre::GPT_VERTEX_PROGRAM); - mRenderSystem->setShadingType(Ogre::SO_GOURAUD); - - // initialise texture settings - mRenderSystem->_setTextureCoordCalculation(0, Ogre::TEXCALC_NONE); - mRenderSystem->_setTextureCoordSet(0, 0); - mRenderSystem->_setTextureUnitFiltering(0, Ogre::FO_LINEAR, Ogre::FO_LINEAR, Ogre::FO_NONE); - mRenderSystem->_setTextureAddressingMode(0, mTextureAddressMode); - mRenderSystem->_setTextureMatrix(0, Ogre::Matrix4::IDENTITY); -#if OGRE_VERSION < MYGUI_DEFINE_VERSION(1, 6, 0) - mRenderSystem->_setAlphaRejectSettings(Ogre::CMPF_ALWAYS_PASS, 0); -#else - mRenderSystem->_setAlphaRejectSettings(Ogre::CMPF_ALWAYS_PASS, 0, false); -#endif - mRenderSystem->_setTextureBlendMode(0, mColorBlendMode); - mRenderSystem->_setTextureBlendMode(0, mAlphaBlendMode); - mRenderSystem->_disableTextureUnitsFrom(1); - - // enable alpha blending - mRenderSystem->_setSceneBlending(Ogre::SBF_SOURCE_ALPHA, Ogre::SBF_ONE_MINUS_SOURCE_ALPHA); - - // always use wireframe - mRenderSystem->_setPolygonMode(Ogre::PM_SOLID); - } - - void end() - { - } - - ITexture* createTexture(const std::string& _name) - { - MapTexture::const_iterator item = mTextures.find(_name); - MYGUI_PLATFORM_ASSERT(item == mTextures.end(), "Texture '" << _name << "' already exist"); - - OgreTexture* texture = new OgreTexture(_name, OgreDataManager::getInstance().getGroup()); - mTextures[_name] = texture; - return texture; - } - - void destroyTexture(ITexture* _texture) - { - if (_texture == nullptr) return; - - MapTexture::iterator item = mTextures.find(_texture->getName()); - MYGUI_PLATFORM_ASSERT(item != mTextures.end(), "Texture '" << _texture->getName() << "' not found"); - - mTextures.erase(item); - delete _texture; - } - - ITexture* getTexture(const std::string& _name) - { - MapTexture::const_iterator item = mTextures.find(_name); - if (item == mTextures.end()) - { - Ogre::TexturePtr texture = (Ogre::TexturePtr)Ogre::TextureManager::getSingleton().getByName(_name); - if (!texture.isNull()) - { - ITexture* result = createTexture(_name); - static_cast(result)->setOgreTexture(texture); - return result; - } - return nullptr; - } - return item->second; - } - - bool isFormatSupported(PixelFormat _format, TextureUsage _usage) - { - return Ogre::TextureManager::getSingleton().isFormatSupported( - Ogre::TEX_TYPE_2D, - OgreTexture::convertFormat(_format), - OgreTexture::convertUsage(_usage)); - } - - void destroyAllResources() - { - for (MapTexture::const_iterator item = mTextures.begin(); item != mTextures.end(); ++item) - { - delete item->second; - } - mTextures.clear(); - } - -#if MYGUI_DEBUG_MODE == 1 - bool checkTexture(ITexture* _texture) - { - for (MapTexture::const_iterator item = mTextures.begin(); item != mTextures.end(); ++item) - { - if (item->second == _texture) - return true; - } - return false; - } -#endif - - const IntSize& getViewSize() const - { - return mViewSize; - } - - VertexColourType getVertexFormat() - { - return mVertexFormat; - } - - const RenderTargetInfo& getInfo() - { - return mInfo; - } - - size_t getActiveViewport() - { - return mActiveViewport; - } - - Ogre::RenderWindow* getRenderWindow() - { - return mWindow; - } - - bool getManualRender() - { - return mManualRender; - } - - void setManualRender(bool _value) - { - mManualRender = _value; - } - - size_t getBatchCount() const - { - return mCountBatch; - } -}; - -/// \brief Helper class holding data that required during -/// MyGUI log creation -class LogFacility -{ - ConsoleLogListener mConsole; - CustomLogListener mFile; - LevelLogFilter mFilter; - LogSource mSource; - -public: - - LogFacility(const std::string &output, bool console) - : mFile(output) - { - mConsole.setEnabled(console); - mFilter.setLoggingLevel(LogLevel::Info); - - mSource.addLogListener(&mFile); - mSource.addLogListener(&mConsole); - mSource.setLogFilter(&mFilter); - - mSource.open(); - } - - LogSource *getSource() { return &mSource; } -}; - -} - -void MyGUIManager::setup(Ogre::RenderWindow *wnd, Ogre::SceneManager *mgr, bool logging, const std::string& logDir) -{ - assert(wnd); - assert(mgr); - - mSceneMgr = mgr; - mShaderRenderManager = NULL; - mRenderManager = NULL; - - using namespace MyGUI; - - // Enable/disable MyGUI logging to stdout. (Logging to MyGUI.log is - // still enabled.) In order to do this we have to initialize the log - // manager before the main gui system itself, otherwise the main - // object will get the chance to spit out a few messages before we - // can able to disable it. - - std::string theLogFile = std::string(MYGUI_PLATFORM_LOG_FILENAME); - if(!logDir.empty()) - theLogFile.insert(0, logDir); - - // Set up OGRE platform (bypassing OgrePlatform). We might make this more generic later. - mLogManager = new LogManager(); - if (!Ogre::Root::getSingleton().getRenderSystem()->getCapabilities()->hasCapability(Ogre::RSC_FIXED_FUNCTION)) - mShaderRenderManager = new MyGUI::ShaderBasedRenderManager(); - else - mRenderManager = new MyGUI::OgreRenderManager(); - mDataManager = new MyGUI::FixedOgreDataManager(); - - // Do not use default log since it don't support Unicode path on Windows. - // Instead, manually create log source using LogFacility and pass it. - mLogFacility = new MyGUI::LogFacility(theLogFile, logging); - LogManager::getInstance().addLogSource(mLogFacility->getSource()); - - if (mShaderRenderManager) - mShaderRenderManager->initialise(wnd, mgr); - else - mRenderManager->initialise(wnd, mgr); - mDataManager->initialise("General"); - - // Create GUI - mGui = new Gui(); - mGui->initialise(""); -} - -void MyGUIManager::windowResized() -{ -#ifndef ANDROID - mRenderManager->setActiveViewport(0); -#endif -} - -void MyGUIManager::shutdown() -{ - mGui->shutdown (); - delete mGui; - if(mRenderManager) - { - mRenderManager->shutdown(); - delete mRenderManager; - mRenderManager = NULL; - } - if(mShaderRenderManager) - { - mShaderRenderManager->shutdown(); - delete mShaderRenderManager; - mShaderRenderManager = NULL; - } - if(mDataManager) - { - mDataManager->shutdown(); - delete mDataManager; - mDataManager = NULL; - } - if (mLogManager) - { - delete mLogManager; - mLogManager = NULL; - } - delete mLogFacility; - - mGui = NULL; -} diff --git a/libs/openengine/gui/manager.hpp b/libs/openengine/gui/manager.hpp deleted file mode 100644 index 28eb6419b..000000000 --- a/libs/openengine/gui/manager.hpp +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef OENGINE_MYGUI_MANAGER_H -#define OENGINE_MYGUI_MANAGER_H - -#include - -namespace MyGUI -{ - class Gui; - class LogManager; - class OgreDataManager; - class OgreRenderManager; - class ShaderBasedRenderManager; - class LogFacility; -} - -namespace Ogre -{ - class RenderWindow; - class SceneManager; -} - -namespace OEngine { -namespace GUI -{ - class MyGUIManager - { - MyGUI::Gui *mGui; - MyGUI::LogManager* mLogManager; - MyGUI::LogFacility* mLogFacility; - MyGUI::OgreDataManager* mDataManager; - MyGUI::OgreRenderManager* mRenderManager; - MyGUI::ShaderBasedRenderManager* mShaderRenderManager; - Ogre::SceneManager* mSceneMgr; - - - public: - MyGUIManager(Ogre::RenderWindow *wnd, Ogre::SceneManager *mgr, bool logging=false, const std::string& logDir = std::string("")) - { - setup(wnd,mgr,logging, logDir); - } - ~MyGUIManager() - { - shutdown(); - } - - void windowResized(); - - void setup(Ogre::RenderWindow *wnd, Ogre::SceneManager *mgr, bool logging=false, const std::string& logDir = std::string("")); - void shutdown(); - }; -} -} -#endif From a6925683c69817aad02305356e02e881d9a03c3e Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 25 Apr 2015 06:04:39 +1000 Subject: [PATCH 1018/3725] Off by one error - can't delete the last element of a refid collection. --- apps/opencs/model/world/refiddata.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/world/refiddata.hpp b/apps/opencs/model/world/refiddata.hpp index eaa7b115d..85d16a6eb 100644 --- a/apps/opencs/model/world/refiddata.hpp +++ b/apps/opencs/model/world/refiddata.hpp @@ -130,7 +130,7 @@ namespace CSMWorld template void RefIdDataContainer::erase (int index, int count) { - if (index<0 || index+count>=getSize()) + if (index<0 || index+count>getSize()) throw std::runtime_error ("invalid RefIdDataContainer index"); mContainer.erase (mContainer.begin()+index, mContainer.begin()+index+count); From 8aaa74a9838aeb92710c601369534b3b82433e9a Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 25 Apr 2015 06:06:11 +1000 Subject: [PATCH 1019/3725] Undo for delete operation in referenceables table. Implemented by saving UniversalId::Type in DeleteCommand. --- apps/opencs/model/world/commanddispatcher.cpp | 24 ++++++++++++++++--- apps/opencs/model/world/commands.cpp | 7 +++--- apps/opencs/model/world/commands.hpp | 4 +++- apps/opencs/model/world/idtable.cpp | 4 ++-- apps/opencs/model/world/idtable.hpp | 3 ++- apps/opencs/model/world/idtree.cpp | 7 ++++++ apps/opencs/model/world/idtree.hpp | 2 ++ 7 files changed, 41 insertions(+), 10 deletions(-) diff --git a/apps/opencs/model/world/commanddispatcher.cpp b/apps/opencs/model/world/commanddispatcher.cpp index ca6faafbc..d94033d9c 100644 --- a/apps/opencs/model/world/commanddispatcher.cpp +++ b/apps/opencs/model/world/commanddispatcher.cpp @@ -8,6 +8,7 @@ #include "../doc/document.hpp" #include "idtable.hpp" +#include "idtree.hpp" #include "record.hpp" #include "commands.hpp" @@ -153,7 +154,15 @@ void CSMWorld::CommandDispatcher::executeDelete() std::string id = model.data (model.getModelIndex (*iter, columnIndex)). toString().toUtf8().constData(); - mDocument.getUndoStack().push (new CSMWorld::DeleteCommand (model, id)); + if (mId.getType() == UniversalId::Type_Referenceables) + { + IdTree& tree = dynamic_cast (*mDocument.getData().getTableModel (mId)); + std::pair localIndex = tree.searchId (id); + + mDocument.getUndoStack().push (new CSMWorld::DeleteCommand (model, id, localIndex.second)); + } + else + mDocument.getUndoStack().push (new CSMWorld::DeleteCommand (model, id)); } if (rows.size()>1) @@ -219,8 +228,17 @@ void CSMWorld::CommandDispatcher::executeExtendedDelete() Misc::StringUtils::lowerCase (record.get().mCell))) continue; - mDocument.getUndoStack().push ( - new CSMWorld::DeleteCommand (model, record.get().mId)); + if (mId.getType() == UniversalId::Type_Referenceables) + { + IdTree& tree = dynamic_cast (*mDocument.getData().getTableModel (mId)); + std::pair localIndex = tree.searchId (record.get().mId); + + mDocument.getUndoStack().push ( + new CSMWorld::DeleteCommand (model, record.get().mId, localIndex.second)); + } + else + mDocument.getUndoStack().push ( + new CSMWorld::DeleteCommand (model, record.get().mId)); } } } diff --git a/apps/opencs/model/world/commands.cpp b/apps/opencs/model/world/commands.cpp index ce82e07bf..5a3190846 100644 --- a/apps/opencs/model/world/commands.cpp +++ b/apps/opencs/model/world/commands.cpp @@ -103,8 +103,9 @@ void CSMWorld::RevertCommand::undo() mModel.setRecord (mId, *mOld); } -CSMWorld::DeleteCommand::DeleteCommand (IdTable& model, const std::string& id, QUndoCommand* parent) -: QUndoCommand (parent), mModel (model), mId (id), mOld (0) +CSMWorld::DeleteCommand::DeleteCommand (IdTable& model, + const std::string& id, CSMWorld::UniversalId::Type type, QUndoCommand* parent) +: QUndoCommand (parent), mModel (model), mId (id), mOld (0), mType(type) { setText (("Delete record " + id).c_str()); @@ -135,7 +136,7 @@ void CSMWorld::DeleteCommand::redo() void CSMWorld::DeleteCommand::undo() { - mModel.setRecord (mId, *mOld); + mModel.setRecord (mId, *mOld, mType); } diff --git a/apps/opencs/model/world/commands.hpp b/apps/opencs/model/world/commands.hpp index 2bd47ae91..89ca5d1ff 100644 --- a/apps/opencs/model/world/commands.hpp +++ b/apps/opencs/model/world/commands.hpp @@ -111,6 +111,7 @@ namespace CSMWorld IdTable& mModel; std::string mId; RecordBase *mOld; + UniversalId::Type mType; // not implemented DeleteCommand (const DeleteCommand&); @@ -118,7 +119,8 @@ namespace CSMWorld public: - DeleteCommand (IdTable& model, const std::string& id, QUndoCommand *parent = 0); + DeleteCommand (IdTable& model, const std::string& id, + UniversalId::Type type = UniversalId::Type_None, QUndoCommand *parent = 0); virtual ~DeleteCommand(); diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 28742c8f2..2f0164c2d 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -145,7 +145,7 @@ QModelIndex CSMWorld::IdTable::getModelIndex (const std::string& id, int column) return index(mIdCollection->getIndex (id), column); } -void CSMWorld::IdTable::setRecord (const std::string& id, const RecordBase& record) +void CSMWorld::IdTable::setRecord (const std::string& id, const RecordBase& record, CSMWorld::UniversalId::Type type) { int index = mIdCollection->searchId (id); @@ -155,7 +155,7 @@ void CSMWorld::IdTable::setRecord (const std::string& id, const RecordBase& reco beginInsertRows (QModelIndex(), index, index); - mIdCollection->appendRecord (record); + mIdCollection->appendRecord (record, type); endInsertRows(); } diff --git a/apps/opencs/model/world/idtable.hpp b/apps/opencs/model/world/idtable.hpp index 559a43cb7..9ecba0214 100644 --- a/apps/opencs/model/world/idtable.hpp +++ b/apps/opencs/model/world/idtable.hpp @@ -59,7 +59,8 @@ namespace CSMWorld virtual QModelIndex getModelIndex (const std::string& id, int column) const; - void setRecord (const std::string& id, const RecordBase& record); + void setRecord (const std::string& id, const RecordBase& record, + UniversalId::Type type = UniversalId::Type_None); ///< Add record or overwrite existing recrod. const RecordBase& getRecord (const std::string& id) const; diff --git a/apps/opencs/model/world/idtree.cpp b/apps/opencs/model/world/idtree.cpp index 06db09a0f..564e4ec2f 100644 --- a/apps/opencs/model/world/idtree.cpp +++ b/apps/opencs/model/world/idtree.cpp @@ -4,6 +4,7 @@ #include "collectionbase.hpp" #include "nestedcollection.hpp" +#include "refidcollection.hpp" // HACK: for searchId() only #include "columnbase.hpp" // NOTE: parent class still needs idCollection @@ -257,3 +258,9 @@ CSMWorld::NestedTableWrapperBase* CSMWorld::IdTree::nestedTable(const QModelInde return mNestedCollection->nestedTable(index.row(), index.column()); } + +// HACK: to get the UniversalId::Type associated with a particular record +std::pair CSMWorld::IdTree::searchId (const std::string& id) const +{ + return dynamic_cast(idCollection())->getDataSet().searchId(id); +} diff --git a/apps/opencs/model/world/idtree.hpp b/apps/opencs/model/world/idtree.hpp index 5337ed82b..73cc9bdfd 100644 --- a/apps/opencs/model/world/idtree.hpp +++ b/apps/opencs/model/world/idtree.hpp @@ -73,6 +73,8 @@ namespace CSMWorld virtual bool hasChildren (const QModelIndex& index) const; + std::pair searchId (const std::string& id) const; + signals: void resetStart(const QString& id); From 15164e20f7c9c7eb5a65a30903390f269251539a Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 24 Apr 2015 23:30:30 +0200 Subject: [PATCH 1020/3725] Cleanup fix --- apps/openmw/engine.cpp | 21 +++++++++++---------- apps/openmw/engine.hpp | 2 +- apps/openmw/mwgui/myguirendermanager.cpp | 2 +- apps/openmw/mwgui/windowmanagerimp.cpp | 6 ++++-- apps/openmw/mwgui/windowmanagerimp.hpp | 4 ++++ 5 files changed, 21 insertions(+), 14 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 7698c3146..7dac03c34 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -314,9 +314,9 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) settings.getBool("minimize on focus loss", "Video") ? "1" : "0"); // not handling fullscreen yet, we should figure this out when adding SDL to the mix - mViewer.setUpViewInWindow(0, 0, settings.getInt("resolution x", "Video"), settings.getInt("resolution y", "Video"), settings.getInt("screen", "Video")); + mViewer->setUpViewInWindow(0, 0, settings.getInt("resolution x", "Video"), settings.getInt("resolution y", "Video"), settings.getInt("screen", "Video")); osg::ref_ptr rootNode (new osg::Group); - mViewer.setSceneData(rootNode); + mViewer->setSceneData(rootNode); mVFS.reset(new VFS::Manager(mFSStrict)); @@ -355,7 +355,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) std::string myguiResources = (mResDir / "mygui").string(); osg::ref_ptr guiRoot = new osg::Group; rootNode->addChild(guiRoot); - MWGui::WindowManager* window = new MWGui::WindowManager(&mViewer, guiRoot, mResourceSystem->getTextureManager(), + MWGui::WindowManager* window = new MWGui::WindowManager(mViewer, guiRoot, mResourceSystem->getTextureManager(), mCfgMgr.getLogPath().string() + std::string("/"), myguiResources, mScriptConsoleMode, mTranslationDataStorage, mEncoding, mExportFonts, mFallbackMap); mEnvironment.setWindowManager (window); @@ -371,7 +371,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) } // Create the world - mEnvironment.setWorld( new MWWorld::World (mViewer, rootNode, mResourceSystem.get(), + mEnvironment.setWorld( new MWWorld::World (*mViewer, rootNode, mResourceSystem.get(), mFileCollections, mContentFiles, mEncoder, mFallbackMap, mActivationDistanceOverride, mCellName, mStartupScript)); MWBase::Environment::get().getWorld()->setupPlayer(); @@ -433,7 +433,8 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) void OMW::Engine::go() { assert (!mContentFiles.empty()); - //assert (!mOgre); + + mViewer = new osgViewer::Viewer; Settings::Manager settings; std::string settingspath; @@ -474,12 +475,12 @@ void OMW::Engine::go() } // Start the main rendering loop - mViewer.setCameraManipulator(new osgGA::TrackballManipulator); - mViewer.addEventHandler(new osgViewer::StatsHandler); + mViewer->setCameraManipulator(new osgGA::TrackballManipulator); + mViewer->addEventHandler(new osgViewer::StatsHandler); - mViewer.realize(); + mViewer->realize(); osg::Timer frameTimer; - while (!mViewer.done()) + while (!mViewer->done()) { double dt = frameTimer.time_s(); frameTimer.setStartTick(); @@ -491,7 +492,7 @@ void OMW::Engine::go() MWBase::Environment::get().getWorld()->advanceTime( dt*MWBase::Environment::get().getWorld()->getTimeScaleFactor()/3600); - mViewer.frame(/*simulationTime*/); + mViewer->frame(/*simulationTime*/); } // Save user settings diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index 8c73920bd..be405c600 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -69,7 +69,7 @@ namespace OMW Files::PathContainer mDataDirs; std::vector mArchives; boost::filesystem::path mResDir; - osgViewer::Viewer mViewer; + osg::ref_ptr mViewer; std::string mCellName; std::vector mContentFiles; bool mVerboseScripts; diff --git a/apps/openmw/mwgui/myguirendermanager.cpp b/apps/openmw/mwgui/myguirendermanager.cpp index 53a194c73..55e78cb0c 100644 --- a/apps/openmw/mwgui/myguirendermanager.cpp +++ b/apps/openmw/mwgui/myguirendermanager.cpp @@ -561,7 +561,7 @@ void RenderManager::setViewSize(int width, int height) mInfo.aspectCoef = float(mViewSize.height) / float(mViewSize.width); mInfo.pixScaleX = 1.0f / float(mViewSize.width); mInfo.pixScaleY = 1.0f / float(mViewSize.height); -std::cout << "setviewsize " << width << " " << height << std::endl; + onResizeView(mViewSize); mUpdate = true; } diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 63d74b355..86d065e39 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -173,8 +173,8 @@ namespace MWGui , mCurrentModals() , mFallbackMap(fallbackMap) { - Platform* platform = new Platform(viewer, guiRoot, textureManager); - platform->initialise(resourcePath, logpath); + mGuiPlatform = new Platform(viewer, guiRoot, textureManager); + mGuiPlatform->initialise(resourcePath, logpath); MyGUI::Gui* gui = new MyGUI::Gui; gui->initialise(""); @@ -411,6 +411,8 @@ namespace MWGui //delete mCursorManager; cleanupGarbage(); + + delete mGuiPlatform; } void WindowManager::cleanupGarbage() diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index a98fbf7b8..54b69be40 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -107,6 +107,8 @@ namespace MWGui class DebugWindow; class JailScreen; + class Platform; + class WindowManager : public MWBase::WindowManager { public: @@ -365,6 +367,8 @@ namespace MWGui virtual void cycleWeapon(bool next); private: + Platform* mGuiPlatform; + bool mConsoleOnlyScripts; std::map mTrackedWindows; From a3417a9c49d4aa4b5be70719002870052ff2768d Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 25 Apr 2015 01:20:07 +0200 Subject: [PATCH 1021/3725] CharacterController compiles --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwmechanics/actors.cpp | 4 ++- apps/openmw/mwmechanics/character.cpp | 44 +++++++++++++++------------ apps/openmw/mwrender/animation.cpp | 6 ++++ apps/openmw/mwrender/animation.hpp | 17 +++++++++++ 5 files changed, 51 insertions(+), 22 deletions(-) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 3349a1afe..acca23f8e 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -82,7 +82,7 @@ add_openmw_dir (mwmechanics drawstate spells activespells npcstats aipackage aisequence aipursue alchemy aiwander aitravel aifollow aiavoiddoor aiescort aiactivate aicombat repair enchanting pathfinding pathgrid security spellsuccess spellcasting disease pickpocket levelledlist combat steering obstacle autocalcspell difficultyscaling aicombataction actor summoning -# character actors objects + character actors objects ) add_openmw_dir (mwstate diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index c6df24154..bab022d94 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -252,7 +252,7 @@ namespace MWMechanics .search("VFX_Soul_Trap"); if (fx) MWBase::Environment::get().getWorld()->spawnEffect("meshes\\" + fx->mModel, - "", Ogre::Vector3(mCreature.getRefData().getPosition().pos)); + "", mCreature.getRefData().getPosition().asVec3()); MWBase::Environment::get().getSoundManager()->playSound3D(mCreature, "conjuration hit", 1.f, 1.f, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_NoTrack); @@ -274,6 +274,7 @@ namespace MWMechanics void Actors::updateHeadTracking(const MWWorld::Ptr& actor, const MWWorld::Ptr& targetActor, MWWorld::Ptr& headTrackTarget, float& sqrHeadTrackDistance) { + /* static const float fMaxHeadTrackDistance = MWBase::Environment::get().getWorld()->getStore().get() .find("fMaxHeadTrackDistance")->getFloat(); static const float fInteriorHeadTrackMult = MWBase::Environment::get().getWorld()->getStore().get() @@ -306,6 +307,7 @@ namespace MWMechanics sqrHeadTrackDistance = sqrDist; headTrackTarget = targetActor; } + */ } void Actors::engageCombat (const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2, bool againstPlayer) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index ffde59aee..c989e3f45 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -27,7 +27,7 @@ #include "creaturestats.hpp" #include "security.hpp" -#include +#include #include @@ -222,7 +222,7 @@ std::string CharacterController::chooseRandomGroup (const std::string& prefix, i while (mAnimation->hasAnimation(prefix + Ogre::StringConverter::toString(numAnims+1))) ++numAnims; - int roll = OEngine::Misc::Rng::rollDice(numAnims) + 1; // [1, numAnims] + int roll = Misc::Rng::rollDice(numAnims) + 1; // [1, numAnims] if (num) *num = roll; return prefix + Ogre::StringConverter::toString(roll); @@ -654,7 +654,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim { /* Accumulate along X/Y only for now, until we can figure out how we should * handle knockout and death which moves the character down. */ - mAnimation->setAccumulation(Ogre::Vector3(1.0f, 1.0f, 0.0f)); + mAnimation->setAccumulation(osg::Vec3f(1.0f, 1.0f, 0.0f)); if (cls.hasInventoryStore(mPtr)) { @@ -685,7 +685,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim else { /* Don't accumulate with non-actors. */ - mAnimation->setAccumulation(Ogre::Vector3(0.0f)); + mAnimation->setAccumulation(osg::Vec3f(0.f, 0.f, 0.f)); mIdleState = CharState_Idle; } @@ -710,12 +710,14 @@ void CharacterController::updatePtr(const MWWorld::Ptr &ptr) void CharacterController::updateIdleStormState() { bool inStormDirection = false; + /* if (MWBase::Environment::get().getWorld()->isInStorm()) { Ogre::Vector3 stormDirection = MWBase::Environment::get().getWorld()->getStormDirection(); Ogre::Vector3 characterDirection = mPtr.getRefData().getBaseNode()->getOrientation().yAxis(); inStormDirection = stormDirection.angleBetween(characterDirection) > Ogre::Degree(120); } + */ if (inStormDirection && mUpperBodyState == UpperCharState_Nothing && mAnimation->hasAnimation("idlestorm")) { float complete = 0; @@ -831,7 +833,7 @@ bool CharacterController::updateCreatureState() } if (weapType != WeapType_Spell || !mAnimation->hasAnimation("spellcast")) // Not all creatures have a dedicated spellcast animation { - int roll = OEngine::Misc::Rng::rollDice(3); // [0, 2] + int roll = Misc::Rng::rollDice(3); // [0, 2] if (roll == 0) mCurrentWeapon = "attack1"; else if (roll == 1) @@ -1030,12 +1032,12 @@ bool CharacterController::updateWeaponState() effect = store.get().find(effectentry.mEffectID); const ESM::Static* castStatic = MWBase::Environment::get().getWorld()->getStore().get().find ("VFX_Hands"); - if (mAnimation->getNode("Left Hand")) + if (mAnimation->hasNode("Left Hand")) mAnimation->addEffect("meshes\\" + castStatic->mModel, -1, false, "Left Hand", effect->mParticle); else mAnimation->addEffect("meshes\\" + castStatic->mModel, -1, false, "Bip01 L Hand", effect->mParticle); - if (mAnimation->getNode("Right Hand")) + if (mAnimation->hasNode("Right Hand")) mAnimation->addEffect("meshes\\" + castStatic->mModel, -1, false, "Right Hand", effect->mParticle); else mAnimation->addEffect("meshes\\" + castStatic->mModel, -1, false, "Bip01 R Hand", effect->mParticle); @@ -1127,7 +1129,7 @@ bool CharacterController::updateWeaponState() // most creatures don't actually have an attack wind-up animation, so use a uniform random value // (even some creatures that can use weapons don't have a wind-up animation either, e.g. Rieklings) // Note: vanilla MW uses a random value for *all* non-player actors, but we probably don't need to go that far. - attackStrength = std::min(1.f, 0.1f + OEngine::Misc::Rng::rollClosedProbability()); + attackStrength = std::min(1.f, 0.1f + Misc::Rng::rollClosedProbability()); } if(mWeaponType != WeapType_Crossbow && mWeaponType != WeapType_BowAndArrow) @@ -1690,26 +1692,26 @@ void CharacterController::update(float duration) world->queueMovement(mPtr, Ogre::Vector3(0.0f)); } - Ogre::Vector3 moved = mAnimation->runAnimation(mSkipAnim ? 0.f : duration); + osg::Vec3f moved = mAnimation->runAnimation(mSkipAnim ? 0.f : duration); if(duration > 0.0f) moved /= duration; else - moved = Ogre::Vector3(0.0f); + moved = osg::Vec3f(0.f, 0.f, 0.f); // Ensure we're moving in generally the right direction... if(mMovementSpeed > 0.f) { float l = moved.length(); - if((movement.x < 0.0f && movement.x < moved.x*2.0f) || - (movement.x > 0.0f && movement.x > moved.x*2.0f)) - moved.x = movement.x; - if((movement.y < 0.0f && movement.y < moved.y*2.0f) || - (movement.y > 0.0f && movement.y > moved.y*2.0f)) - moved.y = movement.y; - if((movement.z < 0.0f && movement.z < moved.z*2.0f) || - (movement.z > 0.0f && movement.z > moved.z*2.0f)) - moved.z = movement.z; + if((movement.x < 0.0f && movement.x < moved.x()*2.0f) || + (movement.x > 0.0f && movement.x > moved.x()*2.0f)) + moved.x() = movement.x; + if((movement.y < 0.0f && movement.y < moved.y()*2.0f) || + (movement.y > 0.0f && movement.y > moved.y()*2.0f)) + moved.y() = movement.y; + if((movement.z < 0.0f && movement.z < moved.z()*2.0f) || + (movement.z > 0.0f && movement.z > moved.z()*2.0f)) + moved.z() = movement.z; // but keep the original speed float newLength = moved.length(); if (newLength > 0) @@ -1721,7 +1723,7 @@ void CharacterController::update(float duration) // Update movement if(mMovementAnimationControlled && mPtr.getClass().isActor()) - world->queueMovement(mPtr, moved); + world->queueMovement(mPtr, Ogre::Vector3(moved.x(), moved.y(), moved.z())); mSkipAnim = false; @@ -1904,6 +1906,7 @@ void CharacterController::setHeadTrackTarget(const MWWorld::Ptr &target) void CharacterController::updateHeadTracking(float duration) { + /* Ogre::Node* head = mAnimation->getNode("Bip01 Head"); if (!head) return; @@ -1946,6 +1949,7 @@ void CharacterController::updateHeadTracking(float duration) mAnimation->setHeadPitch(xAngle); mAnimation->setHeadYaw(zAngle); + */ } } diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 27e54b228..4a1ec3f2f 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1050,6 +1050,12 @@ namespace MWRender } } + bool Animation::hasNode(const std::string &name) + { + std::string lowerName = Misc::StringUtils::lowerCase(name); + return (mNodeMap.find(lowerName) != mNodeMap.end()); + } + float Animation::AnimationTime::getValue(osg::NodeVisitor*) { // FIXME: hold a pointer instead of searching every frame diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index d5b2de81b..9aa15520f 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -338,6 +338,23 @@ public: /// This is typically called as part of runAnimation, but may be called manually if needed. void updateEffects(float duration); + /// Is there a node with the specified name? + /// @note The matching is case-insensitive. + bool hasNode(const std::string& name); + + virtual void showWeapons(bool showWeapon) {} + virtual void showCarriedLeft(bool show) {} + virtual void setWeaponGroup(const std::string& group) {} + virtual void setVampire(bool vampire) {} + virtual void setAlpha(float alpha) {} + virtual void setPitchFactor(float factor) {} + virtual void attachArrow() {} + virtual void enableHeadAnimation(bool enable) {} + // TODO: move outside of this class + /// Makes this object glow, by placing a Light in its center. + /// @param effect Controls the radius and intensity of the light. + virtual void setLightEffect(float effect) {} + private: Animation(const Animation&); void operator=(Animation&); From 372a54bbc70f3e20e1044059f3f743c0114fc149 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 25 Apr 2015 01:28:01 +0200 Subject: [PATCH 1022/3725] Dead code removal --- apps/openmw/engine.hpp | 1 - components/CMakeLists.txt | 4 --- components/nif/niffile.hpp | 1 + components/nifcache/nifcache.cpp | 40 ------------------------- components/nifcache/nifcache.hpp | 50 -------------------------------- components/nifosg/controller.hpp | 2 -- components/nifosg/nifloader.hpp | 2 -- 7 files changed, 1 insertion(+), 99 deletions(-) delete mode 100644 components/nifcache/nifcache.cpp delete mode 100644 components/nifcache/nifcache.hpp diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index be405c600..f3b3a8fbf 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -7,7 +7,6 @@ #include #include #include -#include #include diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index ece1148cb..cc913912f 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -50,10 +50,6 @@ add_component_dir (nifosg nifloader controller particle userdata ) -#add_component_dir (nifcache -# nifcache -# ) - #add_component_dir (nifbullet # bulletnifloader # ) diff --git a/components/nif/niffile.hpp b/components/nif/niffile.hpp index ae5aca5ac..6fbef31ca 100644 --- a/components/nif/niffile.hpp +++ b/components/nif/niffile.hpp @@ -94,6 +94,7 @@ public: /// Get the name of the file std::string getFilename(){ return filename; } }; +typedef boost::shared_ptr NIFFilePtr; diff --git a/components/nifcache/nifcache.cpp b/components/nifcache/nifcache.cpp deleted file mode 100644 index 342251dbc..000000000 --- a/components/nifcache/nifcache.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#include "nifcache.hpp" - -namespace Nif -{ - -Cache* Cache::sThis = 0; - -Cache& Cache::getInstance() -{ - assert (sThis); - return *sThis; -} - -Cache* Cache::getInstancePtr() -{ - return sThis; -} - -Cache::Cache() -{ - assert (!sThis); - sThis = this; -} - -NIFFilePtr Cache::load(const std::string &filename) -{ - // TODO: normalize file path to make sure we're not loading the same file twice - - LoadedMap::iterator it = mLoadedMap.find(filename); - if (it != mLoadedMap.end()) - return it->second; - else - { - NIFFilePtr file(new Nif::NIFFile(filename)); - mLoadedMap[filename] = file; - return file; - } -} - -} diff --git a/components/nifcache/nifcache.hpp b/components/nifcache/nifcache.hpp deleted file mode 100644 index 173b91865..000000000 --- a/components/nifcache/nifcache.hpp +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef OPENMW_COMPONENTS_NIFCACHE_H -#define OPENMW_COMPONENTS_NIFCACHE_H - -#include - -#include - -#include - -namespace Nif -{ - - typedef boost::shared_ptr NIFFilePtr; - - /// @brief A basic resource manager for NIF files - class Cache - { - public: - Cache(); - - /// Queue this file for background loading. A worker thread will start loading the file. - /// To get the loaded NIFFilePtr, use the load method, which will wait until the worker thread is finished - /// and then return the loaded file. - //void loadInBackground (const std::string& file); - - /// Read and parse the given file. May retrieve from cache if this file has been used previously. - /// @note If the file is currently loading in the background, this function will block until - /// the background loading finishes, then return the background loaded file. - /// @note Returns a SharedPtr to the file and the file will stay loaded as long as the user holds on to this pointer. - /// When all external SharedPtrs to a file are released, the cache may decide to unload the file. - NIFFilePtr load (const std::string& filename); - - /// Return instance of this class. - static Cache& getInstance(); - static Cache* getInstancePtr(); - - private: - static Cache* sThis; - - Cache(const Cache&); - Cache& operator =(const Cache&); - - typedef std::map LoadedMap; - - LoadedMap mLoadedMap; - }; - -} - -#endif diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index d32c9f977..4ebd4f41d 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -6,8 +6,6 @@ #include #include -#include - #include #include diff --git a/components/nifosg/nifloader.hpp b/components/nifosg/nifloader.hpp index f2f3c2534..bf1dbe6b5 100644 --- a/components/nifosg/nifloader.hpp +++ b/components/nifosg/nifloader.hpp @@ -3,8 +3,6 @@ #include -#include // NIFFilePtr - #include #include From acb800b8f980f5cdb52974f6ec43def7a6ac7480 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 25 Apr 2015 09:39:37 +1000 Subject: [PATCH 1023/3725] Resolve merge issues and fix typos. --- apps/opencs/model/world/columnbase.hpp | 2 +- apps/opencs/model/world/ref.cpp | 3 -- apps/opencs/view/world/dialoguesubview.cpp | 42 ++++++++++------------ apps/opencs/view/world/dialoguesubview.hpp | 17 ++------- apps/opencs/view/world/nestedtable.cpp | 4 +++ apps/opencs/view/world/nestedtable.hpp | 3 ++ apps/opencs/view/world/util.cpp | 8 ++--- components/esm/cellref.cpp | 6 ++-- components/esm/cellref.hpp | 13 +++---- 9 files changed, 38 insertions(+), 60 deletions(-) diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index 257b67d72..71c22a9f0 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -18,7 +18,7 @@ namespace CSMWorld { Role_Flags = Qt::UserRole, Role_Display = Qt::UserRole+1, - Role_ColumnId = Qt::UserRole+1 + Role_ColumnId = Qt::UserRole+2 }; enum Flags diff --git a/apps/opencs/model/world/ref.cpp b/apps/opencs/model/world/ref.cpp index 6612349f7..13706c950 100644 --- a/apps/opencs/model/world/ref.cpp +++ b/apps/opencs/model/world/ref.cpp @@ -8,7 +8,6 @@ CSMWorld::CellRef::CellRef() mRefNum.mIndex = 0; mRefNum.mContentFile = 0; } -<<<<<<< HEAD std::pair CSMWorld::CellRef::getCellIndex() const { @@ -17,5 +16,3 @@ std::pair CSMWorld::CellRef::getCellIndex() const return std::make_pair ( std::floor (mPos.pos[0]/cellSize), std::floor (mPos.pos[1]/cellSize)); } -======= ->>>>>>> master diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 12b4c86f6..cf3653c1b 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -176,18 +176,12 @@ void CSVWorld::DialogueDelegateDispatcherProxy::tableMimeDataDropped(const std:: ==============================DialogueDelegateDispatcher========================================== */ -<<<<<<< HEAD -CSVWorld::DialogueDelegateDispatcher::DialogueDelegateDispatcher(QObject* parent, CSMWorld::IdTable* table, CSMWorld::CommandDispatcher& commandDispatcher, CSMDoc::Document& document) : -mParent(parent), -mTable(table), -mCommandDispatcher (commandDispatcher), mDocument (document), -======= CSVWorld::DialogueDelegateDispatcher::DialogueDelegateDispatcher(QObject* parent, - CSMWorld::IdTable* table, CSMDoc::Document& document, QAbstractItemModel *model) : + CSMWorld::IdTable* table, CSMWorld::CommandDispatcher& commandDispatcher, + CSMDoc::Document& document, QAbstractItemModel *model) : mParent(parent), mTable(model ? model : table), -mDocument (document), ->>>>>>> master +mCommandDispatcher (commandDispatcher), mDocument (document), mNotEditableDelegate(table, parent) { } @@ -350,10 +344,6 @@ CSVWorld::DialogueDelegateDispatcher::~DialogueDelegateDispatcher() =============================================================EditWidget===================================================== */ -<<<<<<< HEAD -CSVWorld::EditWidget::EditWidget(QWidget *parent, int row, CSMWorld::IdTable* table, CSMWorld::CommandDispatcher& commandDispatcher, CSMDoc::Document& document, bool createAndDelete) : -mDispatcher(this, table, commandDispatcher, document), -======= CSVWorld::EditWidget::~EditWidget() { for (unsigned i = 0; i < mNestedModels.size(); ++i) @@ -363,15 +353,17 @@ CSVWorld::EditWidget::~EditWidget() delete mNestedTableDispatcher; } -CSVWorld::EditWidget::EditWidget(QWidget *parent, int row, CSMWorld::IdTable* table, CSMDoc::Document& document, bool createAndDelete) : -mDispatcher(this, table, document), +CSVWorld::EditWidget::EditWidget(QWidget *parent, + int row, CSMWorld::IdTable* table, CSMWorld::CommandDispatcher& commandDispatcher, + CSMDoc::Document& document, bool createAndDelete) : +mDispatcher(this, table, commandDispatcher, document), mNestedTableDispatcher(NULL), ->>>>>>> master QScrollArea(parent), mWidgetMapper(NULL), mNestedTableMapper(NULL), mMainWidget(NULL), mCommandDispatcher (commandDispatcher), +mDocument (document), mTable(table) { remake (row); @@ -454,7 +446,14 @@ void CSVWorld::EditWidget::remake(int row) { mNestedModels.push_back(new CSMWorld::NestedTableProxyModel (mTable->index(row, i), display, dynamic_cast(mTable))); - NestedTable* table = new NestedTable(mDocument, mNestedModels.back(), this); + int idColumn = mTable->findColumnIndex (CSMWorld::Columns::ColumnId_Id); + int typeColumn = mTable->findColumnIndex (CSMWorld::Columns::ColumnId_RecordType); + + CSMWorld::UniversalId id = CSMWorld::UniversalId( + static_cast (mTable->data (mTable->index (row, typeColumn)).toInt()), + mTable->data (mTable->index (row, idColumn)).toString().toUtf8().constData()); + + NestedTable* table = new NestedTable(mDocument, id, mNestedModels.back(), this); // FIXME: does not work well when enum delegates are used //table->resizeColumnsToContents(); table->setEditTriggers(QAbstractItemView::SelectedClicked | QAbstractItemView::CurrentChanged); @@ -511,7 +510,7 @@ void CSVWorld::EditWidget::remake(int row) mNestedTableMapper->setModel(mNestedModels.back()); // FIXME: lack MIME support? mNestedTableDispatcher = - new DialogueDelegateDispatcher (this, mTable, mDocument, mNestedModels.back()); + new DialogueDelegateDispatcher (this, mTable, mCommandDispatcher, mDocument, mNestedModels.back()); mNestedTableMapper->setItemDelegate(mNestedTableDispatcher); int columnCount = @@ -638,11 +637,8 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSM mMainLayout = new QVBoxLayout(mainWidget); -<<<<<<< HEAD - mEditWidget = new EditWidget(mainWidget, mRow, mTable, mCommandDispatcher, document, false); -======= - mEditWidget = new EditWidget(mainWidget, mTable->getModelIndex(mCurrentId, 0).row(), mTable, document, false); ->>>>>>> master + mEditWidget = new EditWidget(mainWidget, + mTable->getModelIndex(mCurrentId, 0).row(), mTable, mCommandDispatcher, document, false); connect(mEditWidget, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*)), this, SLOT(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*))); diff --git a/apps/opencs/view/world/dialoguesubview.hpp b/apps/opencs/view/world/dialoguesubview.hpp index 4d463246a..b5a44d266 100644 --- a/apps/opencs/view/world/dialoguesubview.hpp +++ b/apps/opencs/view/world/dialoguesubview.hpp @@ -109,10 +109,7 @@ namespace CSVWorld QAbstractItemModel* mTable; -<<<<<<< HEAD CSMWorld::CommandDispatcher& mCommandDispatcher; -======= ->>>>>>> master CSMDoc::Document& mDocument; NotEditableSubDelegate mNotEditableDelegate; @@ -121,15 +118,11 @@ namespace CSVWorld //once we move to the C++11 we should use unique_ptr public: -<<<<<<< HEAD - DialogueDelegateDispatcher(QObject* parent, CSMWorld::IdTable* table, - CSMWorld::CommandDispatcher& commandDispatcher, CSMDoc::Document& document); -======= DialogueDelegateDispatcher(QObject* parent, CSMWorld::IdTable* table, + CSMWorld::CommandDispatcher& commandDispatcher, CSMDoc::Document& document, QAbstractItemModel* model = 0); ->>>>>>> master ~DialogueDelegateDispatcher(); @@ -176,23 +169,17 @@ namespace CSVWorld DialogueDelegateDispatcher *mNestedTableDispatcher; QWidget* mMainWidget; CSMWorld::IdTable* mTable; -<<<<<<< HEAD CSMWorld::CommandDispatcher& mCommandDispatcher; - - public: - - EditWidget (QWidget *parent, int row, CSMWorld::IdTable* table, CSMWorld::CommandDispatcher& commandDispatcher, CSMDoc::Document& document, bool createAndDelete = false); -======= CSMDoc::Document& mDocument; std::vector mNestedModels; //Plain, raw C pointers, deleted in the dtor public: EditWidget (QWidget *parent, int row, CSMWorld::IdTable* table, + CSMWorld::CommandDispatcher& commandDispatcher, CSMDoc::Document& document, bool createAndDelete = false); virtual ~EditWidget(); ->>>>>>> master void remake(int row); diff --git a/apps/opencs/view/world/nestedtable.cpp b/apps/opencs/view/world/nestedtable.cpp index 1597c81a3..5c8762020 100644 --- a/apps/opencs/view/world/nestedtable.cpp +++ b/apps/opencs/view/world/nestedtable.cpp @@ -2,6 +2,7 @@ #include "../../model/world/nestedtableproxymodel.hpp" #include "../../model/world/universalid.hpp" #include "../../model/world/commands.hpp" +#include "../../model/world/commanddispatcher.hpp" #include "util.hpp" #include @@ -10,12 +11,14 @@ #include CSVWorld::NestedTable::NestedTable(CSMDoc::Document& document, + CSMWorld::UniversalId id, CSMWorld::NestedTableProxyModel* model, QWidget* parent) : QTableView(parent), mUndoStack(document.getUndoStack()), mModel(model) { + mDispatcher = new CSMWorld::CommandDispatcher (document, id, this); setSelectionBehavior (QAbstractItemView::SelectRows); setSelectionMode (QAbstractItemView::ExtendedSelection); @@ -31,6 +34,7 @@ CSVWorld::NestedTable::NestedTable(CSMDoc::Document& document, model->headerData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Display).toInt()); CommandDelegate *delegate = CommandDelegateFactoryCollection::get().makeDelegate(display, + mDispatcher, document, this); diff --git a/apps/opencs/view/world/nestedtable.hpp b/apps/opencs/view/world/nestedtable.hpp index f41ba4345..b8e91844c 100644 --- a/apps/opencs/view/world/nestedtable.hpp +++ b/apps/opencs/view/world/nestedtable.hpp @@ -12,6 +12,7 @@ namespace CSMWorld { class NestedTableProxyModel; class UniversalId; + class CommandDispatcher; } namespace CSMDoc @@ -29,9 +30,11 @@ namespace CSVWorld QAction *mRemoveRowAction; QUndoStack& mUndoStack; CSMWorld::NestedTableProxyModel* mModel; + CSMWorld::CommandDispatcher *mDispatcher; public: NestedTable(CSMDoc::Document& document, + CSMWorld::UniversalId id, CSMWorld::NestedTableProxyModel* model, QWidget* parent = NULL); diff --git a/apps/opencs/view/world/util.cpp b/apps/opencs/view/world/util.cpp index fbcfc5215..8b4bfeaac 100644 --- a/apps/opencs/view/world/util.cpp +++ b/apps/opencs/view/world/util.cpp @@ -124,13 +124,9 @@ void CSVWorld::CommandDelegate::setModelDataImp (QWidget *editor, QAbstractItemM QVariant new_ = hack.getData(); -<<<<<<< HEAD - if (model->data (index)!=new_) - mCommandDispatcher->executeModify (model, index, new_); -======= if ((model->data (index)!=new_) && (model->flags(index) & Qt::ItemIsEditable)) - getUndoStack().push (new CSMWorld::ModifyCommand (*model, index, new_)); ->>>>>>> master + //getUndoStack().push (new CSMWorld::ModifyCommand (*model, index, new_)); // FIXME + mCommandDispatcher->executeModify (model, index, new_); } CSVWorld::CommandDelegate::CommandDelegate (CSMWorld::CommandDispatcher *commandDispatcher, diff --git a/components/esm/cellref.cpp b/components/esm/cellref.cpp index f78cc0c85..f9f5e161a 100644 --- a/components/esm/cellref.cpp +++ b/components/esm/cellref.cpp @@ -18,7 +18,7 @@ void ESM::RefNum::save (ESMWriter &esm, bool wide, const std::string& tag) const esm.writeHNT (tag, *this, 8); else { - int refNum = (mIndex & 0xffffff) | ((mContentFile==-1 ? 0xff : mContentFile)<<24); + int refNum = (mIndex & 0xffffff) | ((hasContentFile() ? mContentFile<<24 : 0xff)); esm.writeHNT (tag, refNum, 4); } @@ -27,11 +27,11 @@ void ESM::RefNum::save (ESMWriter &esm, bool wide, const std::string& tag) const void ESM::CellRef::load (ESMReader& esm, bool wideRefNum, bool ignoreRefNum) { - loadId(esm, wideRefNum); + loadId(esm, wideRefNum, ignoreRefNum); loadData(esm); } -void ESM::CellRef::loadId(ESMReader &esm, bool wideRefNum) +void ESM::CellRef::loadId (ESMReader& esm, bool wideRefNum, bool ignoreRefNum) { // According to Hrnchamd, this does not belong to the actual ref. Instead, it is a marker indicating that // the following refs are part of a "temp refs" section. A temp ref is not being tracked by the moved references system. diff --git a/components/esm/cellref.hpp b/components/esm/cellref.hpp index f98b407c6..0fb449e16 100644 --- a/components/esm/cellref.hpp +++ b/components/esm/cellref.hpp @@ -13,21 +13,16 @@ namespace ESM struct RefNum { -<<<<<<< HEAD - int mIndex; - int mContentFile; // -1 no content file + unsigned int mIndex; + int mContentFile; void load (ESMReader& esm, bool wide = false); void save (ESMWriter &esm, bool wide = false, const std::string& tag = "FRMR") const; -======= - unsigned int mIndex; - int mContentFile; enum { RefNum_NoContentFile = -1 }; inline bool hasContentFile() const { return mContentFile != RefNum_NoContentFile; } inline void unset() { mIndex = 0; mContentFile = RefNum_NoContentFile; } ->>>>>>> master }; /* Cell reference. This represents ONE object (of many) inside the @@ -105,9 +100,9 @@ namespace ESM Position mPos; /// Calls loadId and loadData - void load (ESMReader& esm, bool wideRefNum = false); + void load (ESMReader& esm, bool wideRefNum = false, bool ignoreRefNum = false); - void loadId (ESMReader& esm, bool wideRefNum = false); + void loadId (ESMReader& esm, bool wideRefNum = false, bool ignoreRefNum = false); /// Implicitly called by load void loadData (ESMReader& esm); From 932f1f9fbd02b50770a7831d1862bdfde954fdfd Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 25 Apr 2015 15:26:32 +1000 Subject: [PATCH 1024/3725] Alternative way of finding UniversalId without bloating IdTree. --- apps/opencs/model/world/commanddispatcher.cpp | 22 +++++-------------- apps/opencs/model/world/idtree.cpp | 7 ------ apps/opencs/model/world/idtree.hpp | 2 -- 3 files changed, 6 insertions(+), 25 deletions(-) diff --git a/apps/opencs/model/world/commanddispatcher.cpp b/apps/opencs/model/world/commanddispatcher.cpp index d94033d9c..199f91e29 100644 --- a/apps/opencs/model/world/commanddispatcher.cpp +++ b/apps/opencs/model/world/commanddispatcher.cpp @@ -8,7 +8,6 @@ #include "../doc/document.hpp" #include "idtable.hpp" -#include "idtree.hpp" #include "record.hpp" #include "commands.hpp" @@ -156,10 +155,10 @@ void CSMWorld::CommandDispatcher::executeDelete() if (mId.getType() == UniversalId::Type_Referenceables) { - IdTree& tree = dynamic_cast (*mDocument.getData().getTableModel (mId)); - std::pair localIndex = tree.searchId (id); - - mDocument.getUndoStack().push (new CSMWorld::DeleteCommand (model, id, localIndex.second)); + mDocument.getUndoStack().push ( new CSMWorld::DeleteCommand (model, id, + static_cast(model.data (model.index ( + model.getModelIndex (id, columnIndex).row(), + model.findColumnIndex (CSMWorld::Columns::ColumnId_RecordType))).toInt()))); } else mDocument.getUndoStack().push (new CSMWorld::DeleteCommand (model, id)); @@ -228,17 +227,8 @@ void CSMWorld::CommandDispatcher::executeExtendedDelete() Misc::StringUtils::lowerCase (record.get().mCell))) continue; - if (mId.getType() == UniversalId::Type_Referenceables) - { - IdTree& tree = dynamic_cast (*mDocument.getData().getTableModel (mId)); - std::pair localIndex = tree.searchId (record.get().mId); - - mDocument.getUndoStack().push ( - new CSMWorld::DeleteCommand (model, record.get().mId, localIndex.second)); - } - else - mDocument.getUndoStack().push ( - new CSMWorld::DeleteCommand (model, record.get().mId)); + mDocument.getUndoStack().push ( + new CSMWorld::DeleteCommand (model, record.get().mId)); } } } diff --git a/apps/opencs/model/world/idtree.cpp b/apps/opencs/model/world/idtree.cpp index 564e4ec2f..06db09a0f 100644 --- a/apps/opencs/model/world/idtree.cpp +++ b/apps/opencs/model/world/idtree.cpp @@ -4,7 +4,6 @@ #include "collectionbase.hpp" #include "nestedcollection.hpp" -#include "refidcollection.hpp" // HACK: for searchId() only #include "columnbase.hpp" // NOTE: parent class still needs idCollection @@ -258,9 +257,3 @@ CSMWorld::NestedTableWrapperBase* CSMWorld::IdTree::nestedTable(const QModelInde return mNestedCollection->nestedTable(index.row(), index.column()); } - -// HACK: to get the UniversalId::Type associated with a particular record -std::pair CSMWorld::IdTree::searchId (const std::string& id) const -{ - return dynamic_cast(idCollection())->getDataSet().searchId(id); -} diff --git a/apps/opencs/model/world/idtree.hpp b/apps/opencs/model/world/idtree.hpp index 73cc9bdfd..5337ed82b 100644 --- a/apps/opencs/model/world/idtree.hpp +++ b/apps/opencs/model/world/idtree.hpp @@ -73,8 +73,6 @@ namespace CSMWorld virtual bool hasChildren (const QModelIndex& index) const; - std::pair searchId (const std::string& id) const; - signals: void resetStart(const QString& id); From dcce59f76cb5915216dfaffface63a8592eba85b Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 25 Apr 2015 17:20:02 +1000 Subject: [PATCH 1025/3725] Pass MovedCellRef info to RefCollection. Still has debugging code. --- apps/opencs/model/world/refcollection.cpp | 21 ++++++++++++++++-- components/esm/loadcell.cpp | 26 +++++++++++++++++++---- components/esm/loadcell.hpp | 3 ++- 3 files changed, 43 insertions(+), 7 deletions(-) diff --git a/apps/opencs/model/world/refcollection.cpp b/apps/opencs/model/world/refcollection.cpp index 39f85da70..bd4e69d6b 100644 --- a/apps/opencs/model/world/refcollection.cpp +++ b/apps/opencs/model/world/refcollection.cpp @@ -2,8 +2,10 @@ #include "refcollection.hpp" #include +#include // FIXME: debug only #include +#include #include "ref.hpp" #include "cell.hpp" @@ -20,20 +22,35 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool CellRef ref; bool deleted = false; + ESM::MovedCellRef mref; - while (ESM::Cell::getNextRef (reader, ref, deleted, true)) + // hack to initialise mindex + while (!(mref.mRefNum.mIndex = 0) && ESM::Cell::getNextRef (reader, ref, deleted, true, &mref)) { // Keep mOriginalCell empty when in modified (as an indicator that the // original cell will always be equal the current cell). ref.mOriginalCell = base ? cell2.mId : ""; + if (mref.mRefNum.mIndex != 0 && + ((int)std::floor(ref.mPos.pos[0]/8192) != mref.mTarget[0] || + (int)std::floor(ref.mPos.pos[1]/8192) != mref.mTarget[1])) + { + //std::cout <<"refcollection #" << mref.mTarget[0] << " " << mref.mTarget[1] << std::endl; + } + if (cell.get().isExterior()) { // ignoring moved references sub-record; instead calculate cell from coordinates std::pair index = ref.getCellIndex(); std::ostringstream stream; - stream << "#" << index.first << " " << index.second; + if (mref.mRefNum.mIndex) + { + stream << "#" << mref.mTarget[0] << " " << mref.mTarget[1]; + //std::cout <<"refcollection " + stream.str() << std::endl; + } + else + stream << "#" << index.first << " " << index.second; ref.mCell = stream.str(); } diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index d836ec9cf..aed56f415 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -3,6 +3,7 @@ #include #include #include +#include // FIXME: debugging only #include @@ -168,11 +169,12 @@ std::string Cell::getDescription() const } } -bool Cell::getNextRef(ESMReader &esm, CellRef &ref, bool& deleted, bool ignoreMoves) +bool Cell::getNextRef(ESMReader &esm, CellRef &ref, bool& deleted, bool ignoreMoves, MovedCellRef *mref) { // TODO: Try and document reference numbering, I don't think this has been done anywhere else. if (!esm.hasMoreSubs()) return false; + //bool print = false; // FIXME: debugging only // NOTE: We should not need this check. It is a safety check until we have checked // more plugins, and how they treat these moved references. @@ -180,9 +182,12 @@ bool Cell::getNextRef(ESMReader &esm, CellRef &ref, bool& deleted, bool ignoreMo { if (ignoreMoves) { - MovedCellRef mref; - esm.getHT (mref.mRefNum.mIndex); - esm.getHNOT (mref.mTarget, "CNDT"); + esm.getHT (mref->mRefNum.mIndex); + esm.getHNOT (mref->mTarget, "CNDT"); + //std::cout << "index " + std::to_string(mref->mRefNum.mIndex) + " target " << + //std::to_string(mref->mTarget[0]) + ", " + std::to_string(mref->mTarget[1]) << std::endl; + //print = true; // FIXME: debugging only + adjustRefNum (mref->mRefNum, esm); } else { @@ -194,6 +199,19 @@ bool Cell::getNextRef(ESMReader &esm, CellRef &ref, bool& deleted, bool ignoreMo ref.load (esm); +#if 0 + // FIXME: debugging only + if (print && + ((int)std::floor(ref.mPos.pos[0]/8192) != mref->mTarget[0] || + (int)std::floor(ref.mPos.pos[1]/8192) != mref->mTarget[1])) + { + std::cout << ref.mRefID << + ", " + std::to_string((int)std::floor(ref.mPos.pos[0]/8192)) << + ", " + std::to_string((int)std::floor(ref.mPos.pos[1]/8192)) << + ", Z: " +std::to_string(ref.mPos.pos[2]) << std::endl; + } +#endif + // Identify references belonging to a parent file and adapt the ID accordingly. adjustRefNum (ref.mRefNum, esm); diff --git a/components/esm/loadcell.hpp b/components/esm/loadcell.hpp index 554fa3967..b78d4075a 100644 --- a/components/esm/loadcell.hpp +++ b/components/esm/loadcell.hpp @@ -157,7 +157,8 @@ struct Cell reuse one memory location without blanking it between calls. */ /// \param ignoreMoves ignore MVRF record and read reference like a regular CellRef. - static bool getNextRef(ESMReader &esm, CellRef &ref, bool& deleted, bool ignoreMoves = false); + static bool getNextRef(ESMReader &esm, + CellRef &ref, bool& deleted, bool ignoreMoves = false, MovedCellRef *mref = 0); /* This fetches an MVRF record, which is used to track moved references. * Since they are comparably rare, we use a separate method for this. From 2e2d6e04feb8e5cf80b04219b0c1730fe90b26e1 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 25 Apr 2015 17:43:29 +1000 Subject: [PATCH 1026/3725] gcc friendly version. --- apps/opencs/model/world/refcollection.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/world/refcollection.cpp b/apps/opencs/model/world/refcollection.cpp index bd4e69d6b..14d4a1db5 100644 --- a/apps/opencs/model/world/refcollection.cpp +++ b/apps/opencs/model/world/refcollection.cpp @@ -31,12 +31,14 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool // original cell will always be equal the current cell). ref.mOriginalCell = base ? cell2.mId : ""; +#if 0 if (mref.mRefNum.mIndex != 0 && ((int)std::floor(ref.mPos.pos[0]/8192) != mref.mTarget[0] || (int)std::floor(ref.mPos.pos[1]/8192) != mref.mTarget[1])) { - //std::cout <<"refcollection #" << mref.mTarget[0] << " " << mref.mTarget[1] << std::endl; + std::cout <<"refcollection #" << mref.mTarget[0] << " " << mref.mTarget[1] << std::endl; } +#endif if (cell.get().isExterior()) { From e668b35b02ee40236a7291cd14f7df3b5fb27b49 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 25 Apr 2015 17:51:31 +1000 Subject: [PATCH 1027/3725] Fix typo. --- components/esm/cellref.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esm/cellref.cpp b/components/esm/cellref.cpp index f9f5e161a..ef33f495f 100644 --- a/components/esm/cellref.cpp +++ b/components/esm/cellref.cpp @@ -18,7 +18,7 @@ void ESM::RefNum::save (ESMWriter &esm, bool wide, const std::string& tag) const esm.writeHNT (tag, *this, 8); else { - int refNum = (mIndex & 0xffffff) | ((hasContentFile() ? mContentFile<<24 : 0xff)); + int refNum = (mIndex & 0xffffff) | ((hasContentFile() ? mContentFile : 0xff)<<24); esm.writeHNT (tag, refNum, 4); } From 2db097f80e3b494856055f8c2e8cf72d692f5176 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 25 Apr 2015 15:10:37 +0200 Subject: [PATCH 1028/3725] Fix nested callbacks bug --- apps/openmw/mwrender/animation.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 4a1ec3f2f..c5479e3f7 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -549,9 +549,16 @@ namespace MWRender { osg::Node* node = it->first; node->removeUpdateCallback(it->second); + + // Should be no longer needed with OSG 3.4 + it->second->setNestedCallback(NULL); } if (mResetAccumRootCallback && mAccumRoot) + { mAccumRoot->removeUpdateCallback(mResetAccumRootCallback); + // Should be no longer needed with OSG 3.4 + mResetAccumRootCallback->setNestedCallback(NULL); + } mAnimSourceControllers.clear(); mAccumCtrl = NULL; @@ -589,6 +596,7 @@ namespace MWRender { mAccumCtrl = it->second; + // make sure reset is last in the chain of callbacks if (!mResetAccumRootCallback) { mResetAccumRootCallback = new ResetAccumRootCallback; From 0ff7b2ff11313987019759e583d28a7f1481f109 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 25 Apr 2015 15:19:17 +0200 Subject: [PATCH 1029/3725] MechanicsManager, frame update --- apps/openmw/engine.cpp | 24 +------ apps/openmw/engine.hpp | 7 +- apps/openmw/main.cpp | 2 + apps/openmw/mwmechanics/actor.cpp | 8 +-- apps/openmw/mwmechanics/actors.cpp | 2 + apps/openmw/mwmechanics/character.cpp | 1 - .../mwmechanics/mechanicsmanagerimp.cpp | 70 ++++++++----------- .../mwmechanics/mechanicsmanagerimp.hpp | 8 +-- apps/openmw/mwrender/objects.cpp | 4 +- apps/openmw/mwrender/renderingmanager.cpp | 5 ++ apps/openmw/mwrender/renderingmanager.hpp | 2 + apps/openmw/mwworld/physicssystem.cpp | 14 ++-- apps/openmw/mwworld/scene.cpp | 32 ++++----- apps/openmw/mwworld/scene.hpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 31 ++++---- 15 files changed, 95 insertions(+), 117 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 7dac03c34..582172bff 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -69,23 +69,10 @@ void OMW::Engine::executeLocalScripts() localScripts.setIgnore (MWWorld::Ptr()); } -bool OMW::Engine::frameStarted (const Ogre::FrameEvent& evt) -{ - if (MWBase::Environment::get().getStateManager()->getState()!= - MWBase::StateManager::State_NoGame) - { - bool paused = MWBase::Environment::get().getWindowManager()->isGuiMode(); - MWBase::Environment::get().getWorld()->frameStarted(evt.timeSinceLastFrame, paused); - MWBase::Environment::get().getWindowManager ()->frameStarted(evt.timeSinceLastFrame); - } - return true; -} - -bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) +void OMW::Engine::frame(float frametime) { try { - float frametime = evt.timeSinceLastFrame; mEnvironment.setFrameDuration (frametime); // update input @@ -173,8 +160,6 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) { std::cerr << "Error in framelistener: " << e.what() << std::endl; } - - return true; } OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) @@ -486,12 +471,7 @@ void OMW::Engine::go() frameTimer.setStartTick(); //dt = std::min(dt, 0.2f); - // frameRenderingQueued(dt); - MWBase::Environment::get().getWorld()->update(dt, false); - - MWBase::Environment::get().getWorld()->advanceTime( - dt*MWBase::Environment::get().getWorld()->getTimeScaleFactor()/3600); - + frame(dt); mViewer->frame(/*simulationTime*/); } diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index f3b3a8fbf..b47a7bb76 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -1,8 +1,6 @@ #ifndef ENGINE_H #define ENGINE_H -#include - #include #include #include @@ -58,7 +56,7 @@ namespace Files namespace OMW { /// \brief Main engine class, that brings together all the components of OpenMW - class Engine : private Ogre::FrameListener + class Engine { std::auto_ptr mVFS; std::auto_ptr mResourceSystem; @@ -104,8 +102,7 @@ namespace OMW void executeLocalScripts(); - virtual bool frameRenderingQueued (const Ogre::FrameEvent& evt); - virtual bool frameStarted (const Ogre::FrameEvent& evt); + void frame (float dt); /// Load settings from various files, returns the path to the user settings file std::string loadSettings (Settings::Manager & settings); diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 070136dfd..792a2674e 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -12,6 +12,8 @@ #include #include +#include + #if defined(_WIN32) // For OutputDebugString #define WIN32_LEAN_AND_MEAN diff --git a/apps/openmw/mwmechanics/actor.cpp b/apps/openmw/mwmechanics/actor.cpp index 3161bb413..675bd160a 100644 --- a/apps/openmw/mwmechanics/actor.cpp +++ b/apps/openmw/mwmechanics/actor.cpp @@ -1,23 +1,23 @@ #include "actor.hpp" -//#include "character.hpp" +#include "character.hpp" namespace MWMechanics { Actor::Actor(const MWWorld::Ptr &ptr, MWRender::Animation *animation) { - //mCharacterController.reset(new CharacterController(ptr, animation)); + mCharacterController.reset(new CharacterController(ptr, animation)); } void Actor::updatePtr(const MWWorld::Ptr &newPtr) { - //mCharacterController->updatePtr(newPtr); + mCharacterController->updatePtr(newPtr); } CharacterController* Actor::getCharacterController() { - return 0;//mCharacterController.get(); + return mCharacterController.get(); } AiState& Actor::getAiState() diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index bab022d94..bb59d46c0 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1014,6 +1014,8 @@ namespace MWMechanics removeActor(ptr); MWRender::Animation *anim = MWBase::Environment::get().getWorld()->getAnimation(ptr); + if (!anim) + return; mActors.insert(std::make_pair(ptr, new Actor(ptr, anim))); if (updateImmediately) mActors[ptr]->getCharacterController()->update(0); diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index c989e3f45..98a420ba6 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -20,7 +20,6 @@ #include "character.hpp" #include -#include #include "movement.hpp" #include "npcstats.hpp" diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 0e3220cf8..7e6e29670 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -294,27 +294,22 @@ namespace MWMechanics void MechanicsManager::add(const MWWorld::Ptr& ptr) { - /* if(ptr.getClass().isActor()) mActors.addActor(ptr); else mObjects.addObject(ptr); - */ } void MechanicsManager::remove(const MWWorld::Ptr& ptr) { - /* if(ptr == mWatched) mWatched = MWWorld::Ptr(); mActors.removeActor(ptr); mObjects.removeObject(ptr); - */ } void MechanicsManager::updateCell(const MWWorld::Ptr &old, const MWWorld::Ptr &ptr) { - /* if(old == mWatched) mWatched = ptr; @@ -322,16 +317,13 @@ namespace MWMechanics mActors.updateActor(old, ptr); else mObjects.updateObject(old, ptr); - */ } void MechanicsManager::drop(const MWWorld::CellStore *cellStore) { - /* mActors.dropActors(cellStore, mWatched); mObjects.dropObjects(cellStore); - */ } @@ -472,24 +464,24 @@ namespace MWMechanics // HACK? The player has been changed, so a new Animation object may // have been made for them. Make sure they're properly updated. - //MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr(); - //mActors.removeActor(ptr); - //mActors.addActor(ptr, true); + MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr(); + mActors.removeActor(ptr); + mActors.addActor(ptr, true); } - //mActors.update(duration, paused); - //mObjects.update(duration, paused); + mActors.update(duration, paused); + mObjects.update(duration, paused); } void MechanicsManager::rest(bool sleep) { - //mActors.restoreDynamicStats (sleep); - //mActors.fastForwardAi(); + mActors.restoreDynamicStats (sleep); + mActors.fastForwardAi(); } int MechanicsManager::getHoursToRest() const { - return 0;//mActors.getHoursToRest(mWatched); + return mActors.getHoursToRest(mWatched); } void MechanicsManager::setPlayerName (const std::string& name) @@ -679,7 +671,7 @@ namespace MWMechanics int MechanicsManager::countDeaths (const std::string& id) const { - return 0;//mActors.countDeaths (id); + return mActors.countDeaths (id); } void MechanicsManager::getPersuasionDispositionChange (const MWWorld::Ptr& npc, PersuasionType type, @@ -835,39 +827,35 @@ namespace MWMechanics void MechanicsManager::forceStateUpdate(const MWWorld::Ptr &ptr) { - //if(ptr.getClass().isActor()) - //mActors.forceStateUpdate(ptr); + if(ptr.getClass().isActor()) + mActors.forceStateUpdate(ptr); } void MechanicsManager::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number) { - /* if(ptr.getClass().isActor()) mActors.playAnimationGroup(ptr, groupName, mode, number); else mObjects.playAnimationGroup(ptr, groupName, mode, number); - */ } void MechanicsManager::skipAnimation(const MWWorld::Ptr& ptr) { - /* if(ptr.getClass().isActor()) mActors.skipAnimation(ptr); else mObjects.skipAnimation(ptr); - */ } bool MechanicsManager::checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string &groupName) { - //if(ptr.getClass().isActor()) - // return mActors.checkAnimationPlaying(ptr, groupName); - //else + if(ptr.getClass().isActor()) + return mActors.checkAnimationPlaying(ptr, groupName); + else return false; } void MechanicsManager::updateMagicEffects(const MWWorld::Ptr &ptr) { - //mActors.updateMagicEffects(ptr); + mActors.updateMagicEffects(ptr); } bool MechanicsManager::toggleAI() @@ -1062,7 +1050,7 @@ namespace MWMechanics const MWWorld::ESMStore& esmStore = MWBase::Environment::get().getWorld()->getStore(); float radius = esmStore.get().find("fAlarmRadius")->getFloat(); - //mActors.getObjectsInRange(from, radius, neighbors); + mActors.getObjectsInRange(from, radius, neighbors); // victim should be considered even beyond alarm radius if (!victim.isEmpty() && from.squaredDistance(Ogre::Vector3(victim.getRefData().getPosition().pos)) > radius*radius) @@ -1151,7 +1139,7 @@ namespace MWMechanics Ogre::Vector3 from = Ogre::Vector3(player.getRefData().getPosition().pos); float radius = esmStore.get().find("fAlarmRadius")->getFloat(); - //mActors.getObjectsInRange(from, radius, neighbors); + mActors.getObjectsInRange(from, radius, neighbors); // victim should be considered even beyond alarm radius if (!victim.isEmpty() && from.squaredDistance(Ogre::Vector3(victim.getRefData().getPosition().pos)) > radius*radius) @@ -1406,7 +1394,6 @@ namespace MWMechanics // if guard starts combat with player, guards pursuing player should do the same if (ptr.getClass().isClass(ptr, "Guard")) { - /* for (Actors::PtrActorMap::const_iterator iter = mActors.begin(); iter != mActors.end(); ++iter) { if (iter->first.getClass().isClass(iter->first, "Guard")) @@ -1419,7 +1406,6 @@ namespace MWMechanics } } } - */ } } @@ -1430,27 +1416,27 @@ namespace MWMechanics void MechanicsManager::getObjectsInRange(const Ogre::Vector3 &position, float radius, std::vector &objects) { - //mActors.getObjectsInRange(position, radius, objects); - //mObjects.getObjectsInRange(position, radius, objects); + mActors.getObjectsInRange(position, radius, objects); + mObjects.getObjectsInRange(position, radius, objects); } void MechanicsManager::getActorsInRange(const Ogre::Vector3 &position, float radius, std::vector &objects) { - //mActors.getObjectsInRange(position, radius, objects); + mActors.getObjectsInRange(position, radius, objects); } std::list MechanicsManager::getActorsFollowing(const MWWorld::Ptr& actor) { - return std::list();//mActors.getActorsFollowing(actor); + return mActors.getActorsFollowing(actor); } std::list MechanicsManager::getActorsFollowingIndices(const MWWorld::Ptr& actor) { - return std::list(); //mActors.getActorsFollowingIndices(actor); + return mActors.getActorsFollowingIndices(actor); } std::list MechanicsManager::getActorsFighting(const MWWorld::Ptr& actor) { - return std::list();// mActors.getActorsFighting(actor); + return mActors.getActorsFighting(actor); } int MechanicsManager::countSavedGameRecords() const @@ -1461,7 +1447,7 @@ namespace MWMechanics void MechanicsManager::write(ESM::ESMWriter &writer, Loading::Listener &listener) const { - //mActors.write(writer, listener); + mActors.write(writer, listener); ESM::StolenItems items; items.mStolenItems = mStolenItems; @@ -1478,13 +1464,13 @@ namespace MWMechanics items.load(reader); mStolenItems = items.mStolenItems; } - //else - //mActors.readRecord(reader, type); + else + mActors.readRecord(reader, type); } void MechanicsManager::clear() { - //mActors.clear(); + mActors.clear(); mStolenItems.clear(); } @@ -1530,6 +1516,6 @@ namespace MWMechanics bool MechanicsManager::isReadyToBlock(const MWWorld::Ptr &ptr) const { - return 0;//mActors.isReadyToBlock(ptr); + return mActors.isReadyToBlock(ptr); } } diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index 30cc207f7..d08334ae8 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -7,8 +7,8 @@ #include "creaturestats.hpp" #include "npcstats.hpp" -//#include "objects.hpp" -//#include "actors.hpp" +#include "objects.hpp" +#include "actors.hpp" namespace Ogre { @@ -32,8 +32,8 @@ namespace MWMechanics bool mRaceSelected; bool mAI;///< is AI active? - //Objects mObjects; - //Actors mActors; + Objects mObjects; + Actors mActors; typedef std::pair Owner; // < Owner id, bool isFaction > typedef std::map OwnerMap; // < Owner, number of stolen items with this id from this owner > diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index be21b2bec..f77865634 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -197,9 +197,7 @@ void Objects::removeCell(const MWWorld::CellStore* store) void Objects::update(float dt) { - PtrAnimationMap::const_iterator it = mObjects.begin(); - for(;it != mObjects.end();++it) - it->second->runAnimation(dt); + } void Objects::updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 32afc73c2..d68620f8a 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -248,4 +248,9 @@ namespace MWRender notifyWorldSpaceChanged(); } + MWRender::Animation* RenderingManager::getAnimation(const MWWorld::Ptr &ptr) + { + return mObjects->getAnimation(ptr); + } + } diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index c47317608..005100701 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -78,6 +78,8 @@ namespace MWRender void update(float dt, bool paused); + MWRender::Animation* getAnimation(const MWWorld::Ptr& ptr); + private: osgViewer::Viewer& mViewer; osg::ref_ptr mRootNode; diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 623a79576..a1b37a275 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -503,15 +503,15 @@ namespace MWWorld { // Create physics. shapeLoader is deleted by the physic engine //NifBullet::ManualBulletShapeLoader* shapeLoader = new NifBullet::ManualBulletShapeLoader(); - mEngine = new OEngine::Physic::PhysicEngine(0);//shapeLoader); + //mEngine = new OEngine::Physic::PhysicEngine(0);//shapeLoader); } PhysicsSystem::~PhysicsSystem() { - if (mWaterCollisionObject.get()) - mEngine->mDynamicsWorld->removeCollisionObject(mWaterCollisionObject.get()); - delete mEngine; - delete OEngine::Physic::BulletShapeManager::getSingletonPtr(); + //if (mWaterCollisionObject.get()) + // mEngine->mDynamicsWorld->removeCollisionObject(mWaterCollisionObject.get()); + //delete mEngine; + //delete OEngine::Physic::BulletShapeManager::getSingletonPtr(); } OEngine::Physic::PhysicEngine* PhysicsSystem::getEngine() @@ -674,19 +674,23 @@ namespace MWWorld void PhysicsSystem::addObject (const Ptr& ptr, const std::string& mesh, bool placeable) { + /* Ogre::SceneNode* node = ptr.getRefData().getBaseNodeOld(); handleToMesh[node->getName()] = mesh; mEngine->createAndAdjustRigidBody( mesh, node->getName(), ptr.getCellRef().getScale(), node->getPosition(), node->getOrientation(), 0, 0, false, placeable); mEngine->createAndAdjustRigidBody( mesh, node->getName(), ptr.getCellRef().getScale(), node->getPosition(), node->getOrientation(), 0, 0, true, placeable); + */ } void PhysicsSystem::addActor (const Ptr& ptr, const std::string& mesh) { + /* Ogre::SceneNode* node = ptr.getRefData().getBaseNodeOld(); //TODO:optimize this. Searching the std::map isn't very efficient i think. mEngine->addCharacter(node->getName(), mesh, node->getPosition(), node->getScale().x, node->getOrientation()); + */ } void PhysicsSystem::removeObject (const std::string& handle) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 191a8ffef..e61e5d84e 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -31,7 +31,7 @@ namespace { - void addObject(const MWWorld::Ptr& ptr, //MWWorld::PhysicsSystem& physics, + void addObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics, MWRender::RenderingManager& rendering) { std::string model = Misc::ResourceHelpers::correctActorModelPath(ptr.getClass().getModel(ptr), rendering.getResourceSystem()->getVFS()); @@ -39,10 +39,10 @@ namespace if (id == "prisonmarker" || id == "divinemarker" || id == "templemarker" || id == "northmarker") model = ""; // marker objects that have a hardcoded function in the game logic, should be hidden from the player ptr.getClass().insertObjectRendering(ptr, model, rendering); - //ptr.getClass().insertObject (ptr, model, physics); + ptr.getClass().insertObject (ptr, model, physics); } - void updateObjectLocalRotation (const MWWorld::Ptr& ptr, /*MWWorld::PhysicsSystem& physics,*/ + void updateObjectLocalRotation (const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics, MWRender::RenderingManager& rendering) { if (ptr.getRefData().getBaseNode() != NULL) @@ -65,7 +65,7 @@ namespace } } - void updateObjectScale(const MWWorld::Ptr& ptr, /*MWWorld::PhysicsSystem& physics,*/ + void updateObjectScale(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics, MWRender::RenderingManager& rendering) { if (ptr.getRefData().getBaseNode() != NULL) @@ -82,20 +82,20 @@ namespace MWWorld::CellStore& mCell; bool mRescale; Loading::Listener& mLoadingListener; - //MWWorld::PhysicsSystem& mPhysics; + MWWorld::PhysicsSystem& mPhysics; MWRender::RenderingManager& mRendering; InsertFunctor (MWWorld::CellStore& cell, bool rescale, Loading::Listener& loadingListener, - /*MWWorld::PhysicsSystem& physics, */MWRender::RenderingManager& rendering); + MWWorld::PhysicsSystem& physics, MWRender::RenderingManager& rendering); bool operator() (const MWWorld::Ptr& ptr); }; InsertFunctor::InsertFunctor (MWWorld::CellStore& cell, bool rescale, - Loading::Listener& loadingListener, /*MWWorld::PhysicsSystem& physics,*/ + Loading::Listener& loadingListener, MWWorld::PhysicsSystem& physics, MWRender::RenderingManager& rendering) : mCell (cell), mRescale (rescale), mLoadingListener (loadingListener), - //mPhysics (physics), + mPhysics (physics), mRendering (rendering) {} @@ -113,9 +113,9 @@ namespace { try { - addObject(ptr, /*mPhysics, */mRendering); - updateObjectLocalRotation(ptr, /*mPhysics,*/ mRendering); - updateObjectScale(ptr, /*mPhysics,*/ mRendering); + addObject(ptr, mPhysics, mRendering); + updateObjectLocalRotation(ptr, mPhysics, mRendering); + updateObjectScale(ptr, mPhysics, mRendering); ptr.getClass().adjustPosition (ptr, false); } catch (const std::exception& e) @@ -137,12 +137,12 @@ namespace MWWorld void Scene::updateObjectLocalRotation (const Ptr& ptr) { - ::updateObjectLocalRotation(ptr, /* *mPhysics,*/ mRendering); + ::updateObjectLocalRotation(ptr, *mPhysics, mRendering); } void Scene::updateObjectScale(const Ptr &ptr) { - ::updateObjectScale(ptr, /* *mPhysics,*/ mRendering); + ::updateObjectScale(ptr, *mPhysics, mRendering); } void Scene::getGridCenter(int &cellX, int &cellY) @@ -447,7 +447,7 @@ namespace MWWorld //We need the ogre renderer and a scene node. Scene::Scene (MWRender::RenderingManager& rendering, PhysicsSystem *physics) - : mCurrentCell (0), mCellChanged (false), /*mPhysics(physics),*/ mRendering(rendering), mNeedMapUpdate(false) + : mCurrentCell (0), mCellChanged (false), mPhysics(physics), mRendering(rendering), mNeedMapUpdate(false) { } @@ -557,7 +557,7 @@ namespace MWWorld void Scene::insertCell (CellStore &cell, bool rescale, Loading::Listener* loadingListener) { - InsertFunctor functor (cell, rescale, *loadingListener, /* *mPhysics, */mRendering); + InsertFunctor functor (cell, rescale, *loadingListener, *mPhysics, mRendering); cell.forEach (functor); } @@ -565,7 +565,7 @@ namespace MWWorld { try { - addObject(ptr, /* *mPhysics, */mRendering); + addObject(ptr, *mPhysics, mRendering); MWBase::Environment::get().getWorld()->rotateObject(ptr, 0, 0, 0, true); MWBase::Environment::get().getWorld()->scaleObject(ptr, ptr.getCellRef().getScale()); } diff --git a/apps/openmw/mwworld/scene.hpp b/apps/openmw/mwworld/scene.hpp index ea1a56d63..26590c796 100644 --- a/apps/openmw/mwworld/scene.hpp +++ b/apps/openmw/mwworld/scene.hpp @@ -63,7 +63,7 @@ namespace MWWorld CellStore* mCurrentCell; // the cell the player is in CellStoreCollection mActiveCells; bool mCellChanged; - //PhysicsSystem *mPhysics; + PhysicsSystem *mPhysics; MWRender::RenderingManager& mRendering; bool mNeedMapUpdate; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 4b1946d1c..77028aaff 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -54,6 +54,7 @@ #include "actionteleport.hpp" //#include "projectilemanager.hpp" #include "weather.hpp" +#include "physicssystem.hpp" #include "contentloader.hpp" #include "esmloader.hpp" @@ -160,7 +161,7 @@ namespace MWWorld mStartCell (startCell), mStartupScript(startupScript), mScriptsEnabled(true) { - //mPhysics = new PhysicsSystem(renderer); + mPhysics = new PhysicsSystem(); //mPhysEngine = mPhysics->getEngine(); #if 0 mProjectileManager.reset(new ProjectileManager(renderer.getScene(), *mPhysEngine)); @@ -199,7 +200,7 @@ namespace MWWorld mGlobalVariables.fill (mStore); - mWorldScene = new Scene(*mRendering, NULL/*mPhysics*/); + mWorldScene = new Scene(*mRendering, mPhysics); } void World::startNewGame (bool bypass) @@ -480,7 +481,7 @@ namespace MWWorld delete mWeatherManager; delete mWorldScene; delete mRendering; - //delete mPhysics; + delete mPhysics; delete mPlayer; } @@ -2000,7 +2001,7 @@ namespace MWWorld && isLevitationEnabled()) return true; - const OEngine::Physic::PhysicActor *actor = mPhysEngine->getCharacter(ptr.getRefData().getHandle()); + const OEngine::Physic::PhysicActor *actor = 0;//mPhysEngine->getCharacter(ptr.getRefData().getHandle()); if(!actor || !actor->getCollisionMode()) return true; @@ -2040,7 +2041,7 @@ namespace MWWorld const float *fpos = object.getRefData().getPosition().pos; Ogre::Vector3 pos(fpos[0], fpos[1], fpos[2]); - const OEngine::Physic::PhysicActor *actor = mPhysEngine->getCharacter(object.getRefData().getHandle()); + const OEngine::Physic::PhysicActor *actor = 0;//mPhysEngine->getCharacter(object.getRefData().getHandle()); if (actor) { pos.z += heightRatio*2*actor->getHalfExtents().z; @@ -2069,8 +2070,8 @@ namespace MWWorld // TODO: There might be better places to update PhysicActor::mOnGround. bool World::isOnGround(const MWWorld::Ptr &ptr) const { - RefData &refdata = ptr.getRefData(); - OEngine::Physic::PhysicActor *physactor = mPhysEngine->getCharacter(refdata.getHandle()); + //RefData &refdata = ptr.getRefData(); + OEngine::Physic::PhysicActor *physactor = 0;//mPhysEngine->getCharacter(refdata.getHandle()); if(!physactor) return false; @@ -2142,15 +2143,17 @@ namespace MWWorld CellStore *currentCell = mWorldScene->getCurrentCell(); Ptr player = mPlayer->getPlayer(); - RefData &refdata = player.getRefData(); - Ogre::Vector3 playerPos(refdata.getPosition().pos); + //RefData &refdata = player.getRefData(); + //Ogre::Vector3 playerPos(refdata.getPosition().pos); + /* const OEngine::Physic::PhysicActor *physactor = mPhysEngine->getCharacter(refdata.getHandle()); if (!physactor) throw std::runtime_error("can't find player"); if((!physactor->getOnGround()&&physactor->getCollisionMode()) || isUnderwater(currentCell, playerPos) || isWalkingOnWater(player)) return 2; + */ if((currentCell->getCell()->mData.mFlags&ESM::Cell::NoSleep) || player.getClass().getNpcStats(player).isWerewolf()) return 1; @@ -2160,7 +2163,7 @@ namespace MWWorld MWRender::Animation* World::getAnimation(const MWWorld::Ptr &ptr) { - return 0;//return mRendering->getAnimation(ptr); + return mRendering->getAnimation(ptr); } void World::frameStarted (float dt, bool paused) @@ -2295,7 +2298,7 @@ namespace MWWorld float World::getWindSpeed() { if (isCellExterior() || isCellQuasiExterior()) - return 0;//mWeatherManager->getWindSpeed(); + return mWeatherManager->getWindSpeed(); else return 0.f; } @@ -2303,7 +2306,7 @@ namespace MWWorld bool World::isInStorm() const { if (isCellExterior() || isCellQuasiExterior()) - return 0;//mWeatherManager->isInStorm(); + return mWeatherManager->isInStorm(); else return false; } @@ -2311,7 +2314,7 @@ namespace MWWorld Ogre::Vector3 World::getStormDirection() const { if (isCellExterior() || isCellQuasiExterior()) - return Ogre::Vector3();//mWeatherManager->getStormDirection(); + return mWeatherManager->getStormDirection(); else return Ogre::Vector3(0,1,0); } @@ -2800,7 +2803,7 @@ namespace MWWorld { MWWorld::CellStore* cell = mPlayer->getPlayer().getCell(); if (cell->isExterior()) - return 0;//mWeatherManager->isDark(); + return mWeatherManager->isDark(); else { uint32_t ambient = cell->getCell()->mAmbi.mAmbient; From 7809caf9dc69ec6d3ad361c0066ca232c75cfe4c Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 25 Apr 2015 15:53:11 +0200 Subject: [PATCH 1030/3725] Dead code removal --- apps/openmw/mwbase/windowmanager.hpp | 2 -- apps/openmw/mwbase/world.hpp | 1 - apps/openmw/mwgui/myguirendermanager.cpp | 4 +--- apps/openmw/mwgui/windowmanagerimp.cpp | 6 ------ apps/openmw/mwgui/windowmanagerimp.hpp | 2 -- apps/openmw/mwworld/worldimp.cpp | 5 ----- apps/openmw/mwworld/worldimp.hpp | 1 - 7 files changed, 1 insertion(+), 20 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index fdd51ef44..d5960779c 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -303,8 +303,6 @@ namespace MWBase virtual void showSoulgemDialog (MWWorld::Ptr item) = 0; - virtual void frameStarted(float dt) = 0; - virtual void changePointer (const std::string& name) = 0; virtual void setEnemy (const MWWorld::Ptr& enemy) = 0; diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 0c1874ce6..00d4d8536 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -460,7 +460,6 @@ namespace MWBase virtual void reattachPlayerCamera() = 0; /// \todo this does not belong here - virtual void frameStarted (float dt, bool paused) = 0; virtual void screenshot (Ogre::Image& image, int w, int h) = 0; /// Find default position inside exterior cell specified by name diff --git a/apps/openmw/mwgui/myguirendermanager.cpp b/apps/openmw/mwgui/myguirendermanager.cpp index 55e78cb0c..c066ba308 100644 --- a/apps/openmw/mwgui/myguirendermanager.cpp +++ b/apps/openmw/mwgui/myguirendermanager.cpp @@ -460,15 +460,13 @@ void RenderManager::initialise() state->setTextureAttribute(0, new osg::TexEnv(osg::TexEnv::MODULATE)); state->setAttribute(new osg::PolygonMode(osg::PolygonMode::FRONT, osg::PolygonMode::FILL)); state->setAttribute(new osg::BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); - state->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); - state->setRenderBinDetails(11, "RenderBin"); state->setMode(GL_CULL_FACE, osg::StateAttribute::OFF); geode->setStateSet(state); geode->setCullingActive(false); camera->addChild(geode.get()); mGuiRoot = camera; - mSceneRoot->addChild(mGuiRoot.get()); + //mSceneRoot->addChild(mGuiRoot.get()); mViewer->addEventHandler(new ResizeHandler(this)); osg::ref_ptr vp = mViewer->getCamera()->getViewport(); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 86d065e39..ce1314c6f 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1501,12 +1501,6 @@ namespace MWGui updateVisible(); } - void WindowManager::frameStarted (float dt) - { - mInventoryWindow->doRenderUpdate (); - mCharGen->doRenderUpdate(); - } - void WindowManager::updatePlayer() { mInventoryWindow->updatePlayer(); diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 54b69be40..738690bbc 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -309,8 +309,6 @@ namespace MWGui virtual void showBook(const MWWorld::Ptr& item, bool showTakeButton); virtual void showScroll(const MWWorld::Ptr& item, bool showTakeButton); - virtual void frameStarted(float dt); - virtual void showSoulgemDialog (MWWorld::Ptr item); virtual void changePointer (const std::string& name); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 77028aaff..2c92ad93b 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2166,11 +2166,6 @@ namespace MWWorld return mRendering->getAnimation(ptr); } - void World::frameStarted (float dt, bool paused) - { - //mRendering->frameStarted(dt, paused); - } - void World::screenshot(Ogre::Image &image, int w, int h) { //mRendering->screenshot(image, w, h); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 5f79f52dc..e9655b12e 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -564,7 +564,6 @@ namespace MWWorld virtual void reattachPlayerCamera(); /// \todo this does not belong here - virtual void frameStarted (float dt, bool paused); virtual void screenshot (Ogre::Image& image, int w, int h); /// Find center of exterior cell above land surface From b4a06bd78d361983e29c190264c1ea557ad779cf Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 25 Apr 2015 19:32:07 +0200 Subject: [PATCH 1031/3725] Improve skinning performance --- components/sceneutil/riggeometry.cpp | 82 +++++++++++++++++++++------- components/sceneutil/riggeometry.hpp | 11 +++- 2 files changed, 70 insertions(+), 23 deletions(-) diff --git a/components/sceneutil/riggeometry.cpp b/components/sceneutil/riggeometry.cpp index ab9abcdda..9205ef379 100644 --- a/components/sceneutil/riggeometry.cpp +++ b/components/sceneutil/riggeometry.cpp @@ -114,19 +114,60 @@ bool RigGeometry::initFromParentSkeleton(osg::NodeVisitor* nv) return false; } + typedef std::map > Vertex2BoneMap; + Vertex2BoneMap vertex2BoneMap; for (std::map::const_iterator it = mInfluenceMap->mMap.begin(); it != mInfluenceMap->mMap.end(); ++it) { - Bone* b = mSkeleton->getBone(it->first); - if (!b) + Bone* bone = mSkeleton->getBone(it->first); + if (!bone) { std::cerr << "RigGeometry did not find bone " << it->first << std::endl; + continue; } - mResolvedInfluenceMap[b] = it->second; + const BoneInfluence& bi = it->second; + + const std::map& weights = it->second.mWeights; + for (std::map::const_iterator weightIt = weights.begin(); weightIt != weights.end(); ++weightIt) + { + std::vector& vec = vertex2BoneMap[weightIt->first]; + + BoneWeight b = std::make_pair(std::make_pair(bone, bi.mInvBindMatrix), weightIt->second); + + vec.push_back(b); + } } + + for (Vertex2BoneMap::iterator it = vertex2BoneMap.begin(); it != vertex2BoneMap.end(); it++) + { + mBone2VertexMap[it->second].push_back(it->first); + } + return true; } +void accummulateMatrix(const osg::Matrixf& invBindMatrix, const osg::Matrixf& matrix, float weight, osg::Matrixf& result) +{ + osg::Matrixf m = invBindMatrix * matrix; + float* ptr = m.ptr(); + float* ptrresult = result.ptr(); + ptrresult[0] += ptr[0] * weight; + ptrresult[1] += ptr[1] * weight; + ptrresult[2] += ptr[2] * weight; + + ptrresult[4] += ptr[4] * weight; + ptrresult[5] += ptr[5] * weight; + ptrresult[6] += ptr[6] * weight; + + ptrresult[8] += ptr[8] * weight; + ptrresult[9] += ptr[9] * weight; + ptrresult[10] += ptr[10] * weight; + + ptrresult[12] += ptr[12] * weight; + ptrresult[13] += ptr[13] * weight; + ptrresult[14] += ptr[14] * weight; +} + void RigGeometry::update(osg::NodeVisitor* nv) { if (!mSkeleton) @@ -158,29 +199,28 @@ void RigGeometry::update(osg::NodeVisitor* nv) osg::Vec3Array* positionDst = static_cast(getVertexArray()); osg::Vec3Array* normalDst = static_cast(getNormalArray()); - for (unsigned int i=0; isize(); ++i) - (*positionDst)[i] = osg::Vec3f(0,0,0); - for (unsigned int i=0; isize(); ++i) - (*normalDst)[i] = osg::Vec3f(0,0,0); - - for (ResolvedInfluenceMap::const_iterator it = mResolvedInfluenceMap.begin(); it != mResolvedInfluenceMap.end(); ++it) + for (Bone2VertexMap::const_iterator it = mBone2VertexMap.begin(); it != mBone2VertexMap.end(); ++it) { - const BoneInfluence& bi = it->second; - Bone* bone = it->first; + osg::Matrixf resultMat (0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 1); - // Here we could cache the (weighted) matrix for each combination of bone weights - - osg::Matrixf finalMatrix = bi.mInvBindMatrix * bone->mMatrixInSkeletonSpace * geomToSkel; - - for (std::map::const_iterator weightIt = bi.mWeights.begin(); weightIt != bi.mWeights.end(); ++weightIt) + for (std::vector::const_iterator weightIt = it->first.begin(); weightIt != it->first.end(); ++weightIt) { - unsigned short vertex = weightIt->first; + Bone* bone = weightIt->first.first; + const osg::Matrix& invBindMatrix = weightIt->first.second; float weight = weightIt->second; + const osg::Matrixf& boneMatrix = bone->mMatrixInSkeletonSpace; + accummulateMatrix(invBindMatrix, boneMatrix, weight, resultMat); + } + resultMat = resultMat * geomToSkel; - osg::Vec3f a = (*positionSrc)[vertex]; - - (*positionDst)[vertex] += finalMatrix.preMult(a) * weight; - (*normalDst)[vertex] += osg::Matrix::transform3x3((*normalSrc)[vertex], finalMatrix) * weight; + for (std::vector::const_iterator vertexIt = it->second.begin(); vertexIt != it->second.end(); ++vertexIt) + { + unsigned short vertex = *vertexIt; + (*positionDst)[vertex] = resultMat.preMult((*positionSrc)[vertex]); + (*normalDst)[vertex] = osg::Matrix::transform3x3((*normalSrc)[vertex], resultMat); } } diff --git a/components/sceneutil/riggeometry.hpp b/components/sceneutil/riggeometry.hpp index c77ff7c72..f8458cdfa 100644 --- a/components/sceneutil/riggeometry.hpp +++ b/components/sceneutil/riggeometry.hpp @@ -47,8 +47,15 @@ namespace SceneUtil osg::ref_ptr mInfluenceMap; - typedef std::map ResolvedInfluenceMap; - ResolvedInfluenceMap mResolvedInfluenceMap; + typedef std::pair BoneBindMatrixPair; + + typedef std::pair BoneWeight; + + typedef std::vector VertexList; + + typedef std::map, VertexList> Bone2VertexMap; + + Bone2VertexMap mBone2VertexMap; bool initFromParentSkeleton(osg::NodeVisitor* nv); }; From 74b98f7178584a04d32f9e1b1bc7cd3ab1b1b1ba Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 26 Apr 2015 11:35:46 +1000 Subject: [PATCH 1032/3725] Fixed initial loading of moved refs. --- apps/opencs/model/world/data.cpp | 13 ++++-- apps/opencs/model/world/idcollection.hpp | 9 ++++ apps/opencs/model/world/refcollection.cpp | 55 ++++++++++++++++------- 3 files changed, 57 insertions(+), 20 deletions(-) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index b25d84829..91fa556ab 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -3,6 +3,7 @@ #include #include +#include #include @@ -861,9 +862,15 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Messages& messages) case ESM::REC_CELL: { - mCells.load (*mReader, mBase); - std::string cellId = Misc::StringUtils::lowerCase (mCells.getId (mCells.getSize()-1)); - mRefs.load (*mReader, mCells.getSize()-1, mBase, mRefLoadCache[cellId], messages); + int index = mCells.load (*mReader, mBase); + if (index < 0 || index >= mCells.getSize()) + { + // log an error and continue loading the refs to the last loaded cell + std::cerr << "Logic error: cell index out of bounds" << std::endl; + index = mCells.getSize()-1; + } + std::string cellId = Misc::StringUtils::lowerCase (mCells.getId (index)); + mRefs.load (*mReader, index, mBase, mRefLoadCache[cellId], messages); break; } diff --git a/apps/opencs/model/world/idcollection.hpp b/apps/opencs/model/world/idcollection.hpp index f00ea447a..4eafc59bd 100644 --- a/apps/opencs/model/world/idcollection.hpp +++ b/apps/opencs/model/world/idcollection.hpp @@ -74,6 +74,15 @@ namespace CSMWorld { ESXRecordT record; + // Sometimes id (i.e. NAME of the cell) may be different to the id we stored + // earlier. e.g. NAME == "Vivec, Arena" but id == "#-4 11". Sometime NAME is + // missing altogether for scripts or cells. + // + // In such cases the returned index will be -1. We then try updating the + // IdAccessor's id manually (e.g. set mId of the record to "Vivec, Arena") + // and try getting the index once more after loading the record. The mId of the + // record would have changed to "#-4 11" after the load, and searchId() should find + // it (if this is a modify) int index = this->searchId (id); if (index==-1) diff --git a/apps/opencs/model/world/refcollection.cpp b/apps/opencs/model/world/refcollection.cpp index 14d4a1db5..bd4cf918c 100644 --- a/apps/opencs/model/world/refcollection.cpp +++ b/apps/opencs/model/world/refcollection.cpp @@ -2,7 +2,6 @@ #include "refcollection.hpp" #include -#include // FIXME: debug only #include #include @@ -25,36 +24,58 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool ESM::MovedCellRef mref; // hack to initialise mindex - while (!(mref.mRefNum.mIndex = 0) && ESM::Cell::getNextRef (reader, ref, deleted, true, &mref)) + while (!(mref.mRefNum.mIndex = 0) && ESM::Cell::getNextRef(reader, ref, deleted, true, &mref)) { // Keep mOriginalCell empty when in modified (as an indicator that the // original cell will always be equal the current cell). ref.mOriginalCell = base ? cell2.mId : ""; -#if 0 - if (mref.mRefNum.mIndex != 0 && - ((int)std::floor(ref.mPos.pos[0]/8192) != mref.mTarget[0] || - (int)std::floor(ref.mPos.pos[1]/8192) != mref.mTarget[1])) - { - std::cout <<"refcollection #" << mref.mTarget[0] << " " << mref.mTarget[1] << std::endl; - } -#endif - if (cell.get().isExterior()) { // ignoring moved references sub-record; instead calculate cell from coordinates std::pair index = ref.getCellIndex(); std::ostringstream stream; - if (mref.mRefNum.mIndex) + stream << "#" << index.first << " " << index.second; + + ref.mCell = stream.str(); + + // It is not always possibe to ignore moved references sub-record and calculate from + // coordinates. Some mods may place the ref in positions outside normal bounds, + // resulting in non sensical cell id's. + // + // Use the target cell from the MVRF tag but if different output an error message + if (!base && // don't try to update base records + mref.mRefNum.mIndex != 0) // MVRF tag found { + std::ostringstream stream; stream << "#" << mref.mTarget[0] << " " << mref.mTarget[1]; - //std::cout <<"refcollection " + stream.str() << std::endl; + ref.mCell = stream.str(); // overwrite + + ref.mOriginalCell = cell2.mId; + + if (deleted) + { + // FIXME: how to mark the record deleted? + CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Cell, + mCells.getId (cellIndex)); + + messages.add (id, "Moved reference "+ref.mRefID+" is in DELE state"); + + continue; + } + else + { + if (index.first != mref.mTarget[0] || index.second != mref.mTarget[1]) + { + std::cerr << "The Position of moved ref " + << ref.mRefID << " does not match the target cell" << std::endl; + std::cerr << "Position: #" << index.first << " " << index.second + <<", Target #"<< mref.mTarget[0] << " " << mref.mTarget[1] << std::endl; + } + // FIXME: need to transfer the ref to the new cell + } } - else - stream << "#" << index.first << " " << index.second; - - ref.mCell = stream.str(); } else ref.mCell = cell2.mId; From 7673be6d0fb9a2083d63d421a0e30c886270a372 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 26 Apr 2015 12:18:23 +1000 Subject: [PATCH 1033/3725] Loading of moved refs complete. --- apps/opencs/model/world/data.cpp | 6 +++--- apps/opencs/model/world/refcollection.cpp | 19 ++++++++++++------- apps/opencs/model/world/refcollection.hpp | 2 +- components/esm/loadcell.cpp | 18 ------------------ 4 files changed, 16 insertions(+), 29 deletions(-) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 91fa556ab..f4ae78ae7 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -3,7 +3,6 @@ #include #include -#include #include @@ -866,11 +865,12 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Messages& messages) if (index < 0 || index >= mCells.getSize()) { // log an error and continue loading the refs to the last loaded cell - std::cerr << "Logic error: cell index out of bounds" << std::endl; + CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_None); + messages.add (id, "Logic error: cell index out of bounds"); index = mCells.getSize()-1; } std::string cellId = Misc::StringUtils::lowerCase (mCells.getId (index)); - mRefs.load (*mReader, index, mBase, mRefLoadCache[cellId], messages); + mRefs.load (*mReader, index, mBase, mRefLoadCache, cellId, messages); break; } diff --git a/apps/opencs/model/world/refcollection.cpp b/apps/opencs/model/world/refcollection.cpp index bd4cf918c..c94ec1dc4 100644 --- a/apps/opencs/model/world/refcollection.cpp +++ b/apps/opencs/model/world/refcollection.cpp @@ -2,6 +2,7 @@ #include "refcollection.hpp" #include +#include #include #include @@ -12,8 +13,10 @@ #include "record.hpp" void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool base, - std::map& cache, CSMDoc::Messages& messages) + std::map >& cache, const std::string& origCellId, + CSMDoc::Messages& messages) { + std::string cellid = origCellId; Record cell = mCells.getRecord (cellIndex); Cell& cell2 = base ? cell.mBase : cell.mModified; @@ -73,18 +76,20 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool std::cerr << "Position: #" << index.first << " " << index.second <<", Target #"<< mref.mTarget[0] << " " << mref.mTarget[1] << std::endl; } - // FIXME: need to transfer the ref to the new cell + + // transfer the ref to the new cell + cellid = ref.mCell; } } } else ref.mCell = cell2.mId; - std::map::iterator iter = cache.find (ref.mRefNum); + std::map::iterator iter = cache[cellid].find (ref.mRefNum); if (deleted) { - if (iter==cache.end()) + if (iter==cache[cellid].end()) { CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Cell, mCells.getId (cellIndex)); @@ -101,7 +106,7 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool if (record.mState==RecordBase::State_BaseOnly) { removeRows (index, 1); - cache.erase (iter); + cache[cellid].erase (iter); } else { @@ -112,7 +117,7 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool continue; } - if (iter==cache.end()) + if (iter==cache[cellid].end()) { // new reference ref.mId = getNewId(); @@ -123,7 +128,7 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool appendRecord (record); - cache.insert (std::make_pair (ref.mRefNum, ref.mId)); + cache[cellid].insert (std::make_pair (ref.mRefNum, ref.mId)); } else { diff --git a/apps/opencs/model/world/refcollection.hpp b/apps/opencs/model/world/refcollection.hpp index 46572752e..82ec2f390 100644 --- a/apps/opencs/model/world/refcollection.hpp +++ b/apps/opencs/model/world/refcollection.hpp @@ -27,7 +27,7 @@ namespace CSMWorld {} void load (ESM::ESMReader& reader, int cellIndex, bool base, - std::map& cache, + std::map >& cache, const std::string& cellid, CSMDoc::Messages& messages); ///< Load a sequence of references. diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index aed56f415..0f8897c48 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -3,7 +3,6 @@ #include #include #include -#include // FIXME: debugging only #include @@ -174,7 +173,6 @@ bool Cell::getNextRef(ESMReader &esm, CellRef &ref, bool& deleted, bool ignoreMo // TODO: Try and document reference numbering, I don't think this has been done anywhere else. if (!esm.hasMoreSubs()) return false; - //bool print = false; // FIXME: debugging only // NOTE: We should not need this check. It is a safety check until we have checked // more plugins, and how they treat these moved references. @@ -184,9 +182,6 @@ bool Cell::getNextRef(ESMReader &esm, CellRef &ref, bool& deleted, bool ignoreMo { esm.getHT (mref->mRefNum.mIndex); esm.getHNOT (mref->mTarget, "CNDT"); - //std::cout << "index " + std::to_string(mref->mRefNum.mIndex) + " target " << - //std::to_string(mref->mTarget[0]) + ", " + std::to_string(mref->mTarget[1]) << std::endl; - //print = true; // FIXME: debugging only adjustRefNum (mref->mRefNum, esm); } else @@ -199,19 +194,6 @@ bool Cell::getNextRef(ESMReader &esm, CellRef &ref, bool& deleted, bool ignoreMo ref.load (esm); -#if 0 - // FIXME: debugging only - if (print && - ((int)std::floor(ref.mPos.pos[0]/8192) != mref->mTarget[0] || - (int)std::floor(ref.mPos.pos[1]/8192) != mref->mTarget[1])) - { - std::cout << ref.mRefID << - ", " + std::to_string((int)std::floor(ref.mPos.pos[0]/8192)) << - ", " + std::to_string((int)std::floor(ref.mPos.pos[1]/8192)) << - ", Z: " +std::to_string(ref.mPos.pos[2]) << std::endl; - } -#endif - // Identify references belonging to a parent file and adapt the ID accordingly. adjustRefNum (ref.mRefNum, esm); From e0d061c37b9fc0f37c729bc8cf54abe8a06f11d1 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 26 Apr 2015 12:32:07 +1000 Subject: [PATCH 1034/3725] Implemented a workaround for saving moved refs. --- apps/opencs/model/doc/savingstages.cpp | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/doc/savingstages.cpp b/apps/opencs/model/doc/savingstages.cpp index e5595ccf6..5a45691d5 100644 --- a/apps/opencs/model/doc/savingstages.cpp +++ b/apps/opencs/model/doc/savingstages.cpp @@ -303,13 +303,34 @@ void CSMDoc::WriteCellCollectionStage::perform (int stage, Messages& messages) if (ref.mState==CSMWorld::RecordBase::State_Modified || ref.mState==CSMWorld::RecordBase::State_ModifiedOnly) { + // To get an MVRF tag, the ref's mOriginalCell needs to be non-empty (empty + // is meant to indicate that it is the same as the current cell) and + // different to mCell (its current cell) TODO: the second check seems redundant? + // + // To have mOriginalCell be non-empty, it needs to be loaded as 'base' in + // RefCollection::load() + // + // recalculate the ref's cell location + std::ostringstream stream; + if (!interior) + { + std::pair index = ref.get().getCellIndex(); + stream << "#" << index.first << " " << index.second; + } + if (!ref.get().mOriginalCell.empty() && - ref.get().mOriginalCell!=ref.get().mCell) + ref.get().mOriginalCell!=stream.str()) { ESM::MovedCellRef moved; moved.mRefNum = ref.get().mRefNum; - std::istringstream stream (ref.get().mCell.c_str()); + // Need to fill mTarget with the ref's new position. + // + // For this to work the view tht modified this ref needed to have the + // ref's mCell updted properly. + // + // For now use the temporary solution calculated above + std::istringstream stream (stream.str().c_str()); char ignore; stream >> ignore >> moved.mTarget[0] >> moved.mTarget[1]; From b54e5714c968b29ed3d87ca13bfa376ba28bc192 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 26 Apr 2015 14:55:40 +1000 Subject: [PATCH 1035/3725] Revert rebasing the moved refs to the new cell, because the original ref may still be referred by a mod. --- apps/opencs/model/doc/savingstages.cpp | 13 ++---- apps/opencs/model/world/data.cpp | 2 +- apps/opencs/model/world/refcollection.cpp | 55 +++++++++++------------ apps/opencs/model/world/refcollection.hpp | 3 +- 4 files changed, 33 insertions(+), 40 deletions(-) diff --git a/apps/opencs/model/doc/savingstages.cpp b/apps/opencs/model/doc/savingstages.cpp index 5a45691d5..1f6da2580 100644 --- a/apps/opencs/model/doc/savingstages.cpp +++ b/apps/opencs/model/doc/savingstages.cpp @@ -303,13 +303,6 @@ void CSMDoc::WriteCellCollectionStage::perform (int stage, Messages& messages) if (ref.mState==CSMWorld::RecordBase::State_Modified || ref.mState==CSMWorld::RecordBase::State_ModifiedOnly) { - // To get an MVRF tag, the ref's mOriginalCell needs to be non-empty (empty - // is meant to indicate that it is the same as the current cell) and - // different to mCell (its current cell) TODO: the second check seems redundant? - // - // To have mOriginalCell be non-empty, it needs to be loaded as 'base' in - // RefCollection::load() - // // recalculate the ref's cell location std::ostringstream stream; if (!interior) @@ -318,8 +311,10 @@ void CSMDoc::WriteCellCollectionStage::perform (int stage, Messages& messages) stream << "#" << index.first << " " << index.second; } - if (!ref.get().mOriginalCell.empty() && - ref.get().mOriginalCell!=stream.str()) + // An empty mOriginalCell is meant to indicate that it is the same as + // the current cell. It is possible that a moved ref is moved again. + if ((ref.get().mOriginalCell.empty() ? ref.get().mCell : ref.get().mOriginalCell) + != stream.str()) { ESM::MovedCellRef moved; moved.mRefNum = ref.get().mRefNum; diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index f4ae78ae7..97b34551d 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -870,7 +870,7 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Messages& messages) index = mCells.getSize()-1; } std::string cellId = Misc::StringUtils::lowerCase (mCells.getId (index)); - mRefs.load (*mReader, index, mBase, mRefLoadCache, cellId, messages); + mRefs.load (*mReader, index, mBase, mRefLoadCache[cellId], messages); break; } diff --git a/apps/opencs/model/world/refcollection.cpp b/apps/opencs/model/world/refcollection.cpp index c94ec1dc4..8f12b6844 100644 --- a/apps/opencs/model/world/refcollection.cpp +++ b/apps/opencs/model/world/refcollection.cpp @@ -13,10 +13,8 @@ #include "record.hpp" void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool base, - std::map >& cache, const std::string& origCellId, - CSMDoc::Messages& messages) + std::map& cache, CSMDoc::Messages& messages) { - std::string cellid = origCellId; Record cell = mCells.getRecord (cellIndex); Cell& cell2 = base ? cell.mBase : cell.mModified; @@ -43,18 +41,13 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool ref.mCell = stream.str(); - // It is not always possibe to ignore moved references sub-record and calculate from - // coordinates. Some mods may place the ref in positions outside normal bounds, - // resulting in non sensical cell id's. - // - // Use the target cell from the MVRF tag but if different output an error message if (!base && // don't try to update base records mref.mRefNum.mIndex != 0) // MVRF tag found { - std::ostringstream stream; - stream << "#" << mref.mTarget[0] << " " << mref.mTarget[1]; - ref.mCell = stream.str(); // overwrite - + // there is a requirement for a placeholder where the original object was + // + // see the forum discussions here for more details: + // https://forum.openmw.org/viewtopic.php?f=6&t=577&start=30 ref.mOriginalCell = cell2.mId; if (deleted) @@ -67,29 +60,35 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool continue; } - else + + // It is not always possibe to ignore moved references sub-record and + // calculate from coordinates. Some mods may place the ref in positions + // outside normal bounds, resulting in non sensical cell id's. This often + // happens if the moved ref was deleted. + // + // Use the target cell from the MVRF tag but if different output an error + // message + if (index.first != mref.mTarget[0] || index.second != mref.mTarget[1]) { - if (index.first != mref.mTarget[0] || index.second != mref.mTarget[1]) - { - std::cerr << "The Position of moved ref " - << ref.mRefID << " does not match the target cell" << std::endl; - std::cerr << "Position: #" << index.first << " " << index.second - <<", Target #"<< mref.mTarget[0] << " " << mref.mTarget[1] << std::endl; - } - - // transfer the ref to the new cell - cellid = ref.mCell; + std::cerr << "The Position of moved ref " + << ref.mRefID << " does not match the target cell" << std::endl; + std::cerr << "Position: #" << index.first << " " << index.second + <<", Target #"<< mref.mTarget[0] << " " << mref.mTarget[1] << std::endl; + + std::ostringstream stream; + stream << "#" << mref.mTarget[0] << " " << mref.mTarget[1]; + ref.mCell = stream.str(); // overwrite } } } else ref.mCell = cell2.mId; - std::map::iterator iter = cache[cellid].find (ref.mRefNum); + std::map::iterator iter = cache.find (ref.mRefNum); if (deleted) { - if (iter==cache[cellid].end()) + if (iter==cache.end()) { CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Cell, mCells.getId (cellIndex)); @@ -106,7 +105,7 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool if (record.mState==RecordBase::State_BaseOnly) { removeRows (index, 1); - cache[cellid].erase (iter); + cache.erase (iter); } else { @@ -117,7 +116,7 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool continue; } - if (iter==cache[cellid].end()) + if (iter==cache.end()) { // new reference ref.mId = getNewId(); @@ -128,7 +127,7 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool appendRecord (record); - cache[cellid].insert (std::make_pair (ref.mRefNum, ref.mId)); + cache.insert (std::make_pair (ref.mRefNum, ref.mId)); } else { diff --git a/apps/opencs/model/world/refcollection.hpp b/apps/opencs/model/world/refcollection.hpp index 82ec2f390..d031398d3 100644 --- a/apps/opencs/model/world/refcollection.hpp +++ b/apps/opencs/model/world/refcollection.hpp @@ -27,8 +27,7 @@ namespace CSMWorld {} void load (ESM::ESMReader& reader, int cellIndex, bool base, - std::map >& cache, const std::string& cellid, - CSMDoc::Messages& messages); + std::map& cache, CSMDoc::Messages& messages); ///< Load a sequence of references. std::string getNewId(); From 889749a4933b4b641320363cad2b007cfef17658 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 26 Apr 2015 15:44:40 +1000 Subject: [PATCH 1036/3725] Allow non-empty mOriginalCell (case where a moved ref is moved again) --- apps/opencs/model/doc/savingstages.cpp | 17 ++++++++++++++--- apps/opencs/model/world/commands.cpp | 7 +------ apps/opencs/model/world/commands.hpp | 1 - 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/apps/opencs/model/doc/savingstages.cpp b/apps/opencs/model/doc/savingstages.cpp index 1f6da2580..7363f999e 100644 --- a/apps/opencs/model/doc/savingstages.cpp +++ b/apps/opencs/model/doc/savingstages.cpp @@ -238,8 +238,19 @@ void CSMDoc::CollectionReferencesStage::perform (int stage, Messages& messages) mState.getSubRecords()[Misc::StringUtils::lowerCase (cellId)]; // collect moved references at the end of the container - if (!record.get().mOriginalCell.empty() && - record.get().mOriginalCell!=record.get().mCell) + bool interior = cellId.substr (0, 1)!="#"; + std::ostringstream stream; + if (!interior) + { + // recalculate the ref's cell location + std::pair index = record.get().getCellIndex(); + stream << "#" << index.first << " " << index.second; + } + + // An empty mOriginalCell is meant to indicate that it is the same as + // the current cell. It is possible that a moved ref is moved again. + if ((record.get().mOriginalCell.empty() ? + record.get().mCell : record.get().mOriginalCell) != stream.str() && !interior) indices.push_back (i); else indices.push_front (i); @@ -314,7 +325,7 @@ void CSMDoc::WriteCellCollectionStage::perform (int stage, Messages& messages) // An empty mOriginalCell is meant to indicate that it is the same as // the current cell. It is possible that a moved ref is moved again. if ((ref.get().mOriginalCell.empty() ? ref.get().mCell : ref.get().mOriginalCell) - != stream.str()) + != stream.str() && !interior) { ESM::MovedCellRef moved; moved.mRefNum = ref.get().mRefNum; diff --git a/apps/opencs/model/world/commands.cpp b/apps/opencs/model/world/commands.cpp index afc4fcb96..4fe965148 100644 --- a/apps/opencs/model/world/commands.cpp +++ b/apps/opencs/model/world/commands.cpp @@ -8,11 +8,10 @@ #include #include +#include "idtable.hpp" #include "idtree.hpp" #include "nestedtablewrapper.hpp" -#include "idtable.hpp" - CSMWorld::ModifyCommand::ModifyCommand (QAbstractItemModel& model, const QModelIndex& index, const QVariant& new_, QUndoCommand* parent) : QUndoCommand (parent), mModel (&model), mIndex (index), mNew (new_) @@ -227,10 +226,6 @@ void CSMWorld::UpdateCellCommand::undo() } - - - - CSMWorld::DeleteNestedCommand::DeleteNestedCommand (IdTree& model, const std::string& id, int nestedRow, diff --git a/apps/opencs/model/world/commands.hpp b/apps/opencs/model/world/commands.hpp index ca7c13fea..f3d2b852a 100644 --- a/apps/opencs/model/world/commands.hpp +++ b/apps/opencs/model/world/commands.hpp @@ -20,7 +20,6 @@ class QAbstractItemModel; namespace CSMWorld { class IdTable; - class RecordBase; class IdTree; struct RecordBase; struct NestedTableWrapperBase; From 2ef8103cc77c18c46113ebb6d4decc565cdd72ea Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 26 Apr 2015 12:36:05 +0200 Subject: [PATCH 1037/3725] fixed ReportModel::RemoveRows view updates --- apps/opencs/model/tools/reportmodel.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/tools/reportmodel.cpp b/apps/opencs/model/tools/reportmodel.cpp index 5648ace54..1248e202b 100644 --- a/apps/opencs/model/tools/reportmodel.cpp +++ b/apps/opencs/model/tools/reportmodel.cpp @@ -120,7 +120,14 @@ bool CSMTools::ReportModel::removeRows (int row, int count, const QModelIndex& p if (parent.isValid()) return false; - mRows.erase (mRows.begin()+row, mRows.begin()+row+count); + if (count>0) + { + beginRemoveRows (parent, row, row+count-1); + + mRows.erase (mRows.begin()+row, mRows.begin()+row+count); + + endRemoveRows(); + } return true; } From 33a8cd245a37cec85dfc7bf1bbb8e32f1f247fa9 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 26 Apr 2015 21:02:50 +1000 Subject: [PATCH 1038/3725] Fix crash with gcc/linux. --- apps/opencs/model/doc/savingstages.cpp | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/apps/opencs/model/doc/savingstages.cpp b/apps/opencs/model/doc/savingstages.cpp index 7363f999e..d6258da6a 100644 --- a/apps/opencs/model/doc/savingstages.cpp +++ b/apps/opencs/model/doc/savingstages.cpp @@ -331,15 +331,10 @@ void CSMDoc::WriteCellCollectionStage::perform (int stage, Messages& messages) moved.mRefNum = ref.get().mRefNum; // Need to fill mTarget with the ref's new position. - // - // For this to work the view tht modified this ref needed to have the - // ref's mCell updted properly. - // - // For now use the temporary solution calculated above - std::istringstream stream (stream.str().c_str()); + std::istringstream istream (stream.str().c_str()); char ignore; - stream >> ignore >> moved.mTarget[0] >> moved.mTarget[1]; + istream >> ignore >> moved.mTarget[0] >> moved.mTarget[1]; ref.get().mRefNum.save (mState.getWriter(), false, "MVRF"); mState.getWriter().writeHNT ("CNDT", moved.mTarget, 8); From dab650a3d54f2ff903716ffe0b0b0f829e3c8aa7 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 26 Apr 2015 13:26:20 +0200 Subject: [PATCH 1039/3725] remove rows from result table after a successful replace (configurable via user settings) --- apps/opencs/model/settings/usersettings.cpp | 5 ++++- apps/opencs/view/tools/searchsubview.cpp | 9 ++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/settings/usersettings.cpp b/apps/opencs/model/settings/usersettings.cpp index 7a975c99c..6e240c998 100644 --- a/apps/opencs/model/settings/usersettings.cpp +++ b/apps/opencs/model/settings/usersettings.cpp @@ -220,7 +220,10 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() "Characters after search string"); after->setDefaultValue (10); after->setRange (0, 1000); - after->setToolTip ("Maximum number of character to display in search result after the searched text"); + after->setToolTip ("Maximum number of character to display in search result after the searched text"); + + Setting *autoDelete = createSetting (Type_CheckBox, "auto-delete", "Delete row from result table after a successful replace"); + autoDelete->setDefaultValue ("true"); } { diff --git a/apps/opencs/view/tools/searchsubview.cpp b/apps/opencs/view/tools/searchsubview.cpp index 5743ad761..9a654c802 100644 --- a/apps/opencs/view/tools/searchsubview.cpp +++ b/apps/opencs/view/tools/searchsubview.cpp @@ -7,6 +7,7 @@ #include "../../model/tools/search.hpp" #include "../../model/tools/reportmodel.hpp" #include "../../model/world/idtablebase.hpp" +#include "../../model/settings/usersettings.hpp" #include "reporttable.hpp" #include "searchbox.hpp" @@ -22,7 +23,10 @@ void CSVTools::SearchSubView::replace (bool selection) const CSMTools::ReportModel& model = dynamic_cast (*mTable->model()); - + + bool autoDelete = CSMSettings::UserSettings::instance().setting ( + "search/auto-delete", QString ("true"))=="true"; + // We are running through the indices in reverse order to avoid messing up multiple results // in a single string. for (std::vector::const_reverse_iterator iter (indices.rbegin()); iter!=indices.rend(); ++iter) @@ -38,6 +42,9 @@ void CSVTools::SearchSubView::replace (bool selection) mSearch.replace (mDocument, table, id, hint, replace); mTable->flagAsReplaced (*iter); + + if (autoDelete) + mTable->model()->removeRows (*iter, 1); } } From 6fac4c5dd981d0f11f409fb9099e04e01e826e93 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 26 Apr 2015 13:31:35 +0200 Subject: [PATCH 1040/3725] made user settings handling in search sub view more consistent --- apps/opencs/view/tools/searchsubview.cpp | 18 +++++++----------- apps/opencs/view/tools/searchsubview.hpp | 2 -- 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/apps/opencs/view/tools/searchsubview.cpp b/apps/opencs/view/tools/searchsubview.cpp index 9a654c802..2038612a2 100644 --- a/apps/opencs/view/tools/searchsubview.cpp +++ b/apps/opencs/view/tools/searchsubview.cpp @@ -49,8 +49,7 @@ void CSVTools::SearchSubView::replace (bool selection) } CSVTools::SearchSubView::SearchSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) -: CSVDoc::SubView (id), mDocument (document), mPaddingBefore (10), mPaddingAfter (10), - mLocked (false) +: CSVDoc::SubView (id), mDocument (document), mLocked (false) { QVBoxLayout *layout = new QVBoxLayout; @@ -91,14 +90,6 @@ void CSVTools::SearchSubView::setEditLock (bool locked) void CSVTools::SearchSubView::updateUserSetting (const QString &name, const QStringList &list) { mTable->updateUserSetting (name, list); - - if (!list.empty()) - { - if (name=="search/char-before") - mPaddingBefore = list.at (0).toInt(); - else if (name=="search/char-after") - mPaddingAfter = list.at (0).toInt(); - } } void CSVTools::SearchSubView::stateChanged (int state, CSMDoc::Document *document) @@ -108,8 +99,13 @@ void CSVTools::SearchSubView::stateChanged (int state, CSMDoc::Document *documen void CSVTools::SearchSubView::startSearch (const CSMTools::Search& search) { + CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); + + int paddingBefore = userSettings.setting ("search/char-before", QString ("5")).toInt(); + int paddingAfter = userSettings.setting ("search/char-after", QString ("5")).toInt(); + mSearch = search; - mSearch.setPadding (mPaddingBefore, mPaddingAfter); + mSearch.setPadding (paddingBefore, paddingAfter); mTable->clear(); mDocument.runSearch (getUniversalId(), mSearch); diff --git a/apps/opencs/view/tools/searchsubview.hpp b/apps/opencs/view/tools/searchsubview.hpp index eeefa9afb..6dedd6ef2 100644 --- a/apps/opencs/view/tools/searchsubview.hpp +++ b/apps/opencs/view/tools/searchsubview.hpp @@ -26,8 +26,6 @@ namespace CSVTools ReportTable *mTable; SearchBox mSearchBox; CSMDoc::Document& mDocument; - int mPaddingBefore; - int mPaddingAfter; CSMTools::Search mSearch; bool mLocked; From 8971a200f7ef882729170f04d3d2e486f079ce2d Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 26 Apr 2015 14:34:14 +0200 Subject: [PATCH 1041/3725] Sky fix --- apps/openmw/mwrender/sky.cpp | 1 + apps/openmw/mwworld/worldimp.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 0529b9a7b..97055ecae 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -554,6 +554,7 @@ void SkyManager::create() depth->setWriteMask(false); mRootNode->getOrCreateStateSet()->setAttributeAndModes(depth, osg::StateAttribute::ON); mRootNode->getOrCreateStateSet()->setMode(GL_BLEND, osg::StateAttribute::ON); + mRootNode->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::ON); mCreated = true; } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 2c92ad93b..4e737fc07 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2401,7 +2401,7 @@ namespace MWWorld void World::enableActorCollision(const MWWorld::Ptr& actor, bool enable) { - OEngine::Physic::PhysicActor *physicActor = mPhysEngine->getCharacter(actor.getRefData().getHandle()); + OEngine::Physic::PhysicActor *physicActor = 0;//mPhysEngine->getCharacter(actor.getRefData().getHandle()); if (physicActor) physicActor->enableCollisionBody(enable); } From 63b69db617c66c33f303195f8504f34976a9f471 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 27 Apr 2015 15:41:34 +0200 Subject: [PATCH 1042/3725] Port skeleton based bounding boxes to the new skinning system Not sure if going to keep this, there's a noticable performance impact. --- components/nifosg/nifloader.cpp | 33 +---------- components/sceneutil/riggeometry.cpp | 82 +++++++++++++++++++++++----- components/sceneutil/riggeometry.hpp | 9 +++ 3 files changed, 77 insertions(+), 47 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 38ead0925..936f266dd 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -1043,24 +1043,6 @@ namespace NifOsg return morphGeom; } - class BoundingBoxCallback : public osg::NodeCallback - { - public: - virtual void operator()( osg::Node* node, osg::NodeVisitor* nv ) - { - osg::BoundingBox bb = mDrawable->getBound(); - - static_cast(node)->setMatrix( - osg::Matrix::scale(bb.xMax()-bb.xMin(), bb.yMax()-bb.yMin(), bb.zMax()-bb.zMin()) * - osg::Matrix::translate(bb.center()) ); - - traverse(node, nv); - } - - osg::Drawable* mDrawable; - }; - - static void handleSkinnedTriShape(const Nif::NiTriShape *triShape, osg::Group *parentNode, const std::map& boundTextures, int animflags) { osg::ref_ptr geode (new osg::Geode); @@ -1091,25 +1073,12 @@ namespace NifOsg influence.mWeights.insert(indexWeight); } influence.mInvBindMatrix = toMatrix(data->bones[i].trafo); + influence.mBoundSphere = osg::BoundingSpheref(data->bones[i].boundSphereCenter, data->bones[i].boundSphereRadius); map->mMap.insert(std::make_pair(boneName, influence)); } rig->setInfluenceMap(map); - // Compute the bounding box - osg::BoundingBox boundingBox; - - osg::Matrix worldTrans = getWorldTransform(triShape); - for(size_t i = 0;i < bones.length();i++) - { - osg::BoundingSphere boneSphere (data->bones[i].boundSphereCenter, data->bones[i].boundSphereRadius); - osg::Matrix boneWorldTrans(getWorldTransform(bones[i].getPtr())); - osg::Matrix mat = boneWorldTrans * worldTrans.inverse(worldTrans); - SceneUtil::transformBoundingSphere(mat, boneSphere); - boundingBox.expandBy(boneSphere); - } - rig->setComputeBoundingBoxCallback(new StaticBoundingBoxCallback(boundingBox)); - geode->addDrawable(rig); // Add a copy, we will alternate between the two copies every other frame using the FrameSwitch diff --git a/components/sceneutil/riggeometry.cpp b/components/sceneutil/riggeometry.cpp index 9205ef379..19e5b0ae6 100644 --- a/components/sceneutil/riggeometry.cpp +++ b/components/sceneutil/riggeometry.cpp @@ -6,14 +6,34 @@ #include #include +#include #include "skeleton.hpp" - -#include +#include "util.hpp" namespace SceneUtil { +class UpdateRigBounds : public osg::Drawable::UpdateCallback +{ +public: + UpdateRigBounds() + { + } + + UpdateRigBounds(const UpdateRigBounds& copy, const osg::CopyOp& copyop) + : osg::Drawable::UpdateCallback(copy, copyop) + { + } + + void update(osg::NodeVisitor* nv, osg::Drawable* drw) + { + RigGeometry* rig = static_cast(drw); + + rig->updateBounds(nv); + } +}; + // TODO: make threadsafe for multiple cull threads class UpdateRigGeometry : public osg::Drawable::CullCallback { @@ -40,6 +60,7 @@ public: RigGeometry::RigGeometry() { setCullCallback(new UpdateRigGeometry); + setUpdateCallback(new UpdateRigBounds); setSupportsDisplayList(false); } @@ -125,6 +146,8 @@ bool RigGeometry::initFromParentSkeleton(osg::NodeVisitor* nv) continue; } + mBoneSphereMap[bone] = it->second.mBoundSphere; + const BoneInfluence& bi = it->second; const std::map& weights = it->second.mWeights; @@ -178,19 +201,7 @@ void RigGeometry::update(osg::NodeVisitor* nv) mSkeleton->updateBoneMatrices(nv); - osg::NodePath path; - bool foundSkel = false; - for (osg::NodePath::const_iterator it = nv->getNodePath().begin(); it != nv->getNodePath().end(); ++it) - { - if (!foundSkel) - { - if (*it == mSkeleton) - foundSkel = true; - } - else - path.push_back(*it); - } - osg::Matrixf geomToSkel = osg::computeWorldToLocal(path); + osg::Matrixf geomToSkel = getGeomToSkelMatrix(nv); // skinning osg::Vec3Array* positionSrc = static_cast(mSourceGeometry->getVertexArray()); @@ -228,6 +239,47 @@ void RigGeometry::update(osg::NodeVisitor* nv) normalDst->dirty(); } +void RigGeometry::updateBounds(osg::NodeVisitor *nv) +{ + if (!mSkeleton) + { + if (!initFromParentSkeleton(nv)) + return; + } + + mSkeleton->updateBoneMatrices(nv); + + osg::Matrixf geomToSkel = getGeomToSkelMatrix(nv); + osg::BoundingBox box; + for (BoneSphereMap::const_iterator it = mBoneSphereMap.begin(); it != mBoneSphereMap.end(); ++it) + { + Bone* bone = it->first; + osg::BoundingSpheref bs = it->second; + transformBoundingSphere(bone->mMatrixInSkeletonSpace * geomToSkel, bs); + box.expandBy(bs); + } + + setInitialBound(box); +} + +osg::Matrixf RigGeometry::getGeomToSkelMatrix(osg::NodeVisitor *nv) +{ + osg::NodePath path; + bool foundSkel = false; + for (osg::NodePath::const_iterator it = nv->getNodePath().begin(); it != nv->getNodePath().end(); ++it) + { + if (!foundSkel) + { + if (*it == mSkeleton) + foundSkel = true; + } + else + path.push_back(*it); + } + return osg::computeWorldToLocal(path); + +} + void RigGeometry::setInfluenceMap(osg::ref_ptr influenceMap) { mInfluenceMap = influenceMap; diff --git a/components/sceneutil/riggeometry.hpp b/components/sceneutil/riggeometry.hpp index f8458cdfa..e82f6254a 100644 --- a/components/sceneutil/riggeometry.hpp +++ b/components/sceneutil/riggeometry.hpp @@ -24,6 +24,7 @@ namespace SceneUtil struct BoneInfluence { osg::Matrixf mInvBindMatrix; + osg::BoundingSpheref mBoundSphere; // std::map mWeights; }; @@ -40,6 +41,8 @@ namespace SceneUtil // Called automatically by our CullCallback void update(osg::NodeVisitor* nv); + // Called automatically by our UpdateCallback + void updateBounds(osg::NodeVisitor* nv); private: osg::ref_ptr mSourceGeometry; @@ -57,7 +60,13 @@ namespace SceneUtil Bone2VertexMap mBone2VertexMap; + typedef std::map BoneSphereMap; + + BoneSphereMap mBoneSphereMap; + bool initFromParentSkeleton(osg::NodeVisitor* nv); + + osg::Matrixf getGeomToSkelMatrix(osg::NodeVisitor* nv); }; } From ae5de0cb2b1ad90ded17fc227a513979dd8118e9 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 27 Apr 2015 22:43:09 +0200 Subject: [PATCH 1043/3725] implemented additional check before performing replace (make sure data hasn't been changed since the search) --- apps/opencs/model/tools/search.cpp | 17 +++++++++++++++++ apps/opencs/model/tools/search.hpp | 4 ++++ apps/opencs/view/tools/searchsubview.cpp | 24 ++++++++++++++++++------ 3 files changed, 39 insertions(+), 6 deletions(-) diff --git a/apps/opencs/model/tools/search.cpp b/apps/opencs/model/tools/search.cpp index cb8850754..7eb531161 100644 --- a/apps/opencs/model/tools/search.cpp +++ b/apps/opencs/model/tools/search.cpp @@ -276,4 +276,21 @@ void CSMTools::Search::replace (CSMDoc::Document& document, CSMWorld::IdTableBas new CSMWorld::ModifyCommand (*model, index, QString::fromUtf8 (newText.c_str()))); } } + +bool CSMTools::Search::verify (CSMDoc::Document& document, CSMWorld::IdTableBase *model, + const CSMWorld::UniversalId& id, const std::string& messageHint) const +{ + CSMDoc::Messages messages; + + int row = model->getModelIndex (id.getId(), + model->findColumnIndex (CSMWorld::Columns::ColumnId_Id)).row(); + + searchRow (model, row, messages); + + for (CSMDoc::Messages::Iterator iter (messages.begin()); iter!=messages.end(); ++iter) + if (iter->mHint==messageHint) + return true; + + return false; +} diff --git a/apps/opencs/model/tools/search.hpp b/apps/opencs/model/tools/search.hpp index c9dfc4c44..69b98bbdb 100644 --- a/apps/opencs/model/tools/search.hpp +++ b/apps/opencs/model/tools/search.hpp @@ -88,6 +88,10 @@ namespace CSMTools void replace (CSMDoc::Document& document, CSMWorld::IdTableBase *model, const CSMWorld::UniversalId& id, const std::string& messageHint, const std::string& replaceText) const; + + // Check if model still matches search results. + bool verify (CSMDoc::Document& document, CSMWorld::IdTableBase *model, + const CSMWorld::UniversalId& id, const std::string& messageHint) const; }; } diff --git a/apps/opencs/view/tools/searchsubview.cpp b/apps/opencs/view/tools/searchsubview.cpp index 2038612a2..32c26ee96 100644 --- a/apps/opencs/view/tools/searchsubview.cpp +++ b/apps/opencs/view/tools/searchsubview.cpp @@ -26,6 +26,9 @@ void CSVTools::SearchSubView::replace (bool selection) bool autoDelete = CSMSettings::UserSettings::instance().setting ( "search/auto-delete", QString ("true"))=="true"; + + CSMTools::Search search (mSearch); + CSMWorld::IdTableBase *currentTable = 0; // We are running through the indices in reverse order to avoid messing up multiple results // in a single string. @@ -37,14 +40,23 @@ void CSVTools::SearchSubView::replace (bool selection) CSMWorld::IdTableBase *table = &dynamic_cast ( *mDocument.getData().getTableModel (type)); - + + if (table!=currentTable) + { + search.configure (table); + currentTable = table; + } + std::string hint = model.getHint (*iter); - - mSearch.replace (mDocument, table, id, hint, replace); - mTable->flagAsReplaced (*iter); - if (autoDelete) - mTable->model()->removeRows (*iter, 1); + if (search.verify (mDocument, table, id, hint)) + { + search.replace (mDocument, table, id, hint, replace); + mTable->flagAsReplaced (*iter); + + if (autoDelete) + mTable->model()->removeRows (*iter, 1); + } } } From 49884f54f7f00e1d4413b77eae3d6091043aa016 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Tue, 28 Apr 2015 08:07:01 +1000 Subject: [PATCH 1044/3725] Fix loading moved references. --- apps/opencs/model/world/data.cpp | 4 ++-- apps/opencs/model/world/refcollection.cpp | 8 +++++++- apps/opencs/view/world/util.cpp | 1 - 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 97b34551d..fc4532fb0 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -458,6 +458,8 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc UniversalId::Type_Texture); addModel (new ResourceTable (&mResourcesManager.get (UniversalId::Type_Videos)), UniversalId::Type_Video); + + mRefLoadCache.clear(); // clear here rather than startLoading() and continueLoading() for multiple content files } CSMWorld::Data::~Data() @@ -779,7 +781,6 @@ int CSMWorld::Data::startLoading (const boost::filesystem::path& path, bool base mReader = 0; mDialogue = 0; - mRefLoadCache.clear(); mReader = new ESM::ESMReader; mReader->setEncoder (&mEncoder); @@ -816,7 +817,6 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Messages& messages) mReader = 0; mDialogue = 0; - mRefLoadCache.clear(); return true; } diff --git a/apps/opencs/model/world/refcollection.cpp b/apps/opencs/model/world/refcollection.cpp index 8f12b6844..ff30dafae 100644 --- a/apps/opencs/model/world/refcollection.cpp +++ b/apps/opencs/model/world/refcollection.cpp @@ -84,7 +84,13 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool else ref.mCell = cell2.mId; - std::map::iterator iter = cache.find (ref.mRefNum); + // ignore content file number + std::map::iterator iter = cache.begin(); + for (; iter != cache.end(); ++iter) + { + if (ref.mRefNum.mIndex == iter->first.mIndex) + break; + } if (deleted) { diff --git a/apps/opencs/view/world/util.cpp b/apps/opencs/view/world/util.cpp index 8b4bfeaac..a11b5bdde 100644 --- a/apps/opencs/view/world/util.cpp +++ b/apps/opencs/view/world/util.cpp @@ -125,7 +125,6 @@ void CSVWorld::CommandDelegate::setModelDataImp (QWidget *editor, QAbstractItemM QVariant new_ = hack.getData(); if ((model->data (index)!=new_) && (model->flags(index) & Qt::ItemIsEditable)) - //getUndoStack().push (new CSMWorld::ModifyCommand (*model, index, new_)); // FIXME mCommandDispatcher->executeModify (model, index, new_); } From e69687b0f290a6ea519d167d467530ddc0a0de6e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 28 Apr 2015 14:06:52 +0200 Subject: [PATCH 1045/3725] silenced a warning (potentially unintialised variable) --- components/nif/nifkey.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/nif/nifkey.hpp b/components/nif/nifkey.hpp index cb8142720..b36b1d8cb 100644 --- a/components/nif/nifkey.hpp +++ b/components/nif/nifkey.hpp @@ -18,6 +18,8 @@ struct KeyT { float mTension; // Only for TBC interpolation float mBias; // Only for TBC interpolation float mContinuity; // Only for TBC interpolation + + KeyT() : mTension (0), mBias (0), mContinuity (0) {} }; typedef KeyT FloatKey; typedef KeyT Vector3Key; From 28048c0bf36e267320f6e4ca43d2998829be20d8 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Tue, 28 Apr 2015 23:07:42 +1000 Subject: [PATCH 1046/3725] Simple line numbering and fixed-width fonts for the script dialogue. Based on Qt examples. Should resolve Bugs #2505 and #2512. --- apps/opencs/view/world/scriptedit.cpp | 122 ++++++++++++++++++++++++++ apps/opencs/view/world/scriptedit.hpp | 29 +++++- 2 files changed, 150 insertions(+), 1 deletion(-) diff --git a/apps/opencs/view/world/scriptedit.cpp b/apps/opencs/view/world/scriptedit.cpp index 271b0316d..991e58ae7 100644 --- a/apps/opencs/view/world/scriptedit.cpp +++ b/apps/opencs/view/world/scriptedit.cpp @@ -5,6 +5,8 @@ #include #include #include +#include +#include #include "../../model/doc/document.hpp" @@ -72,6 +74,20 @@ CSVWorld::ScriptEdit::ScriptEdit (const CSMDoc::Document& document, ScriptHighli connect (&mUpdateTimer, SIGNAL (timeout()), this, SLOT (updateHighlighting())); mUpdateTimer.setSingleShot (true); + + // FIXME: make this configurable or provide a font selector dialogue + // FIXME: save QFontInfo somewhere before switching to a new one + QFont font("Monospace"); + font.setStyleHint(QFont::TypeWriter); + setFont(font); + + // FIXME: make this configurable + lineNumberArea = new LineNumberArea(this); + + connect(this, SIGNAL(blockCountChanged(int)), this, SLOT(updateLineNumberAreaWidth(int))); + connect(this, SIGNAL(updateRequest(QRect,int)), this, SLOT(updateLineNumberArea(QRect,int))); + + updateLineNumberAreaWidth(0); } bool CSVWorld::ScriptEdit::isChangeLocked() const @@ -157,3 +173,109 @@ void CSVWorld::ScriptEdit::updateHighlighting() mHighlighter->rehighlight(); } + +int CSVWorld::ScriptEdit::lineNumberAreaWidth() +{ + int digits = 1; + int max = qMax(1, blockCount()); + while (max >= 10) + { + max /= 10; + ++digits; + } + + int space = 3 + fontMetrics().width(QLatin1Char('9')) * digits; + + return space; +} + +void CSVWorld::ScriptEdit::updateLineNumberAreaWidth(int /* newBlockCount */) +{ + setViewportMargins(lineNumberAreaWidth(), 0, 0, 0); +} + +void CSVWorld::ScriptEdit::updateLineNumberArea(const QRect &rect, int dy) +{ + if (dy) + lineNumberArea->scroll(0, dy); + else + lineNumberArea->update(0, rect.y(), lineNumberArea->width(), rect.height()); + + if (rect.contains(viewport()->rect())) + updateLineNumberAreaWidth(0); +} + +void CSVWorld::ScriptEdit::resizeEvent(QResizeEvent *e) +{ + QPlainTextEdit::resizeEvent(e); + + QRect cr = contentsRect(); + lineNumberArea->setGeometry(QRect(cr.left(), cr.top(), lineNumberAreaWidth(), cr.height())); +} + +void CSVWorld::ScriptEdit::lineNumberAreaPaintEvent(QPaintEvent *event) +{ + QPainter painter(lineNumberArea); + + QTextBlock block = firstVisibleBlock(); + int blockNumber = block.blockNumber(); + int top = (int) blockBoundingGeometry(block).translated(contentOffset()).top(); + int bottom = top + (int) blockBoundingRect(block).height(); + + int startBlock = textCursor().blockNumber(); + int endBlock = textCursor().blockNumber(); + if(textCursor().hasSelection()) + { + QString str = textCursor().selection().toPlainText(); + int selectedLines = str.count("\n")+1; + if(textCursor().position() < textCursor().anchor()) + endBlock += selectedLines; + else + startBlock -= selectedLines; + } + painter.setBackgroundMode(Qt::OpaqueMode); + QFont font = painter.font(); + QBrush background = painter.background(); + + while (block.isValid() && top <= event->rect().bottom()) + { + if (block.isVisible() && bottom >= event->rect().top()) + { + QFont newFont = painter.font(); + QString number = QString::number(blockNumber + 1); + if(blockNumber >= startBlock && blockNumber <= endBlock) + { + painter.setBackground(Qt::cyan); + painter.setPen(Qt::darkMagenta); + newFont.setBold(true); + } + else + { + painter.setBackground(background); + painter.setPen(Qt::black); + } + painter.setFont(newFont); + painter.drawText(0, top, lineNumberArea->width(), fontMetrics().height(), + Qt::AlignRight, number); + painter.setFont(font); + } + + block = block.next(); + top = bottom; + bottom = top + (int) blockBoundingRect(block).height(); + ++blockNumber; + } +} + +CSVWorld::LineNumberArea::LineNumberArea(ScriptEdit *editor) : QWidget(editor), mScriptEdit(editor) +{} + +QSize CSVWorld::LineNumberArea::sizeHint() const +{ + return QSize(mScriptEdit->lineNumberAreaWidth(), 0); +} + +void CSVWorld::LineNumberArea::paintEvent(QPaintEvent *event) +{ + mScriptEdit->lineNumberAreaPaintEvent(event); +} diff --git a/apps/opencs/view/world/scriptedit.hpp b/apps/opencs/view/world/scriptedit.hpp index 0192bc550..90fe2917e 100644 --- a/apps/opencs/view/world/scriptedit.hpp +++ b/apps/opencs/view/world/scriptedit.hpp @@ -2,6 +2,7 @@ #define SCRIPTEDIT_H #include +#include #include #include @@ -9,7 +10,6 @@ #include "scripthighlighter.hpp" -class QWidget; class QRegExp; namespace CSMDoc @@ -19,6 +19,8 @@ namespace CSMDoc namespace CSVWorld { + class LineNumberArea; + class ScriptEdit : public QPlainTextEdit { Q_OBJECT @@ -45,6 +47,7 @@ namespace CSVWorld int mChangeLocked; ScriptHighlighter *mHighlighter; QTimer mUpdateTimer; + QWidget *lineNumberArea; public: @@ -56,6 +59,13 @@ namespace CSVWorld /// \note This mechanism is used to avoid infinite update recursions bool isChangeLocked() const; + void lineNumberAreaPaintEvent(QPaintEvent *event); + int lineNumberAreaWidth(); + + protected: + + virtual void resizeEvent(QResizeEvent *e); + private: QVector mAllowedTypes; const CSMDoc::Document& mDocument; @@ -74,6 +84,23 @@ namespace CSVWorld void idListChanged(); void updateHighlighting(); + + void updateLineNumberAreaWidth(int newBlockCount); + void updateLineNumberArea(const QRect &, int); + }; + + class LineNumberArea : public QWidget + { + ScriptEdit *mScriptEdit; + + public: + + LineNumberArea(ScriptEdit *editor); + QSize sizeHint() const; + + protected: + + void paintEvent(QPaintEvent *event); }; } #endif // SCRIPTEDIT_H From a27446c8fbc8900273852c9f8ca7da8e69fc7f10 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 28 Apr 2015 16:02:29 +0200 Subject: [PATCH 1047/3725] Remove unused headers --- apps/openmw/mwgui/myguiplatform.hpp | 5 +---- apps/openmw/mwgui/myguirendermanager.cpp | 4 ++++ apps/openmw/mwgui/myguirendermanager.hpp | 1 + 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwgui/myguiplatform.hpp b/apps/openmw/mwgui/myguiplatform.hpp index 4c3e70143..a2256e970 100644 --- a/apps/openmw/mwgui/myguiplatform.hpp +++ b/apps/openmw/mwgui/myguiplatform.hpp @@ -2,9 +2,6 @@ #define OPENMW_MWGUI_MYGUIPLATFORM_H #include "MyGUI_Prerequest.h" -#include "MyGUI_DummyRenderManager.h" -#include "MyGUI_DummyDataManager.h" -#include "MyGUI_DummyDiagnostic.h" #include "MyGUI_LogManager.h" #include "myguirendermanager.hpp" @@ -36,7 +33,7 @@ namespace MWGui mLogManager = nullptr; } - void initialise(const std::string& resourcePath, const std::string& _logName = MYGUI_PLATFORM_LOG_FILENAME) + void initialise(const std::string& resourcePath, const std::string& _logName = "MyGUI.log") { if (!_logName.empty()) MyGUI::LogManager::getInstance().createDefaultSource(_logName); diff --git a/apps/openmw/mwgui/myguirendermanager.cpp b/apps/openmw/mwgui/myguirendermanager.cpp index c066ba308..06e404d88 100644 --- a/apps/openmw/mwgui/myguirendermanager.cpp +++ b/apps/openmw/mwgui/myguirendermanager.cpp @@ -476,6 +476,10 @@ void RenderManager::initialise() mIsInitialise = true; } +void RenderManager::shutdown() +{ +} + MyGUI::IVertexBuffer* RenderManager::createVertexBuffer() { return new OSGVertexBuffer(); diff --git a/apps/openmw/mwgui/myguirendermanager.hpp b/apps/openmw/mwgui/myguirendermanager.hpp index 64a5fe07b..513edb5b7 100644 --- a/apps/openmw/mwgui/myguirendermanager.hpp +++ b/apps/openmw/mwgui/myguirendermanager.hpp @@ -53,6 +53,7 @@ public: virtual ~RenderManager(); void initialise(); + void shutdown(); static RenderManager& getInstance() { return *getInstancePtr(); } static RenderManager* getInstancePtr() From 48a6d7c1a0bc9b0867f98e5387c31326397bd751 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 28 Apr 2015 16:31:32 +0200 Subject: [PATCH 1048/3725] Remove mygui platform libraries from cmake --- CMakeLists.txt | 1 - apps/openmw/CMakeLists.txt | 2 -- cmake/FindMyGUI.cmake | 24 ++---------------------- 3 files changed, 2 insertions(+), 25 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e8a2458b1..d2a245366 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -241,7 +241,6 @@ include_directories("." ${LIBS_DIR} ${Boost_INCLUDE_DIR} ${PLATFORM_INCLUDE_DIR} ${MYGUI_INCLUDE_DIRS} - ${MYGUI_PLATFORM_INCLUDE_DIRS} ${OPENAL_INCLUDE_DIR} ${BULLET_INCLUDE_DIRS} ) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index acca23f8e..a36dd4e2a 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -139,7 +139,6 @@ target_link_libraries(openmw ${BULLET_LIBRARIES} ${MYGUI_LIBRARIES} ${SDL2_LIBRARY} - ${MYGUI_PLATFORM_LIBRARIES} ${OPENGL_gl_LIBRARY} "osg-ffmpeg-videoplayer" "oics" @@ -153,7 +152,6 @@ if (ANDROID) android log dl - MyGUI.OgrePlatform MyGUIEngineStatic Plugin_StrangeButtonStatic cpufeatures diff --git a/cmake/FindMyGUI.cmake b/cmake/FindMyGUI.cmake index b5c4e8ade..b52d94f98 100644 --- a/cmake/FindMyGUI.cmake +++ b/cmake/FindMyGUI.cmake @@ -27,7 +27,6 @@ IF (WIN32) #Windows STRING(REGEX REPLACE "[\\]" "/" MYGUISDK "${MYGUISDK}" ) find_path ( MYGUI_INCLUDE_DIRS MyGUI.h "${MYGUISDK}/MyGUIEngine/include" NO_DEFAULT_PATH ) - find_path ( MYGUI_PLATFORM_INCLUDE_DIRS MyGUI_OgrePlatform.h "${MYGUISDK}/Platforms/Ogre/OgrePlatform/include" NO_DEFAULT_PATH ) SET ( MYGUI_LIB_DIR ${MYGUISDK}/lib ${MYGUISDK}/*/lib ) @@ -35,27 +34,15 @@ IF (WIN32) #Windows set(LIB_SUFFIX "Static") endif ( MYGUI_STATIC ) - find_library ( MYGUI_LIBRARIES_REL NAMES MyGUIEngine${LIB_SUFFIX}.lib MyGUI.OgrePlatform.lib HINTS ${MYGUI_LIB_DIR} PATH_SUFFIXES "" release relwithdebinfo minsizerel ) - find_library ( MYGUI_LIBRARIES_DBG NAMES MyGUIEngine${LIB_SUFFIX}_d.lib MyGUI.OgrePlatform_d.lib HINTS ${MYGUI_LIB_DIR} PATH_SUFFIXES "" debug ) - - find_library ( MYGUI_PLATFORM_LIBRARIES_REL NAMES MyGUI.OgrePlatform.lib HINTS ${MYGUI_LIB_DIR} PATH_SUFFIXES "" release relwithdebinfo minsizerel ) - find_library ( MYGUI_PLATFORM_LIBRARIES_DBG NAMES MyGUI.OgrePlatform_d.lib HINTS ${MYGUI_LIB_DIR} PATH_SUFFIXES "" debug ) + find_library ( MYGUI_LIBRARIES_REL NAMES MyGUIEngine${LIB_SUFFIX}.lib HINTS ${MYGUI_LIB_DIR} PATH_SUFFIXES "" release relwithdebinfo minsizerel ) + find_library ( MYGUI_LIBRARIES_DBG NAMES MyGUIEngine${LIB_SUFFIX}_d.lib HINTS ${MYGUI_LIB_DIR} PATH_SUFFIXES "" debug ) make_library_set ( MYGUI_LIBRARIES ) - make_library_set ( MYGUI_PLATFORM_LIBRARIES ) MESSAGE ("${MYGUI_LIBRARIES}") - MESSAGE ("${MYGUI_PLATFORM_LIBRARIES}") #findpkg_finish ( "MYGUI" ) ENDIF (MYGUISDK) - IF (OGRESOURCE) - MESSAGE(STATUS "Using MyGUI in OGRE dependencies") - STRING(REGEX REPLACE "[\\]" "/" OGRESDK "${OGRESOURCE}" ) - SET(MYGUI_INCLUDE_DIRS ${OGRESOURCE}/OgreMain/include/MYGUI) - SET(MYGUI_LIB_DIR ${OGRESOURCE}/lib) - SET(MYGUI_LIBRARIES debug Debug/MyGUIEngine_d optimized Release/MyGUIEngine) - ENDIF (OGRESOURCE) ELSE (WIN32) #Unix CMAKE_MINIMUM_REQUIRED(VERSION 2.4.7 FATAL_ERROR) FIND_PACKAGE(PkgConfig) @@ -67,11 +54,9 @@ ELSE (WIN32) #Unix SET(MYGUI_INCLUDE_DIRS ${MYGUI_INCLUDE_DIRS}) SET(MYGUI_LIB_DIR ${MYGUI_LIBDIR}) SET(MYGUI_LIBRARIES ${MYGUI_LIBRARIES} CACHE STRING "") - SET(MYGUI_PLATFORM_LIBRARIES "MyGUI.DummyPlatform") ELSE (MYGUI_INCLUDE_DIRS) FIND_PATH(MYGUI_INCLUDE_DIRS MyGUI.h PATHS /usr/local/include /usr/include PATH_SUFFIXES MyGUI MYGUI) FIND_LIBRARY(MYGUI_LIBRARIES myguistatic PATHS /usr/lib /usr/local/lib) - SET(MYGUI_PLATFORM_LIBRARIES "MyGUI.DummyPlatform") SET(MYGUI_LIB_DIR ${MYGUI_LIBRARIES}) STRING(REGEX REPLACE "(.*)/.*" "\\1" MYGUI_LIB_DIR "${MYGUI_LIB_DIR}") STRING(REGEX REPLACE ".*/" "" MYGUI_LIBRARIES "${MYGUI_LIBRARIES}") @@ -81,7 +66,6 @@ ELSE (WIN32) #Unix FIND_PACKAGE(freetype) FIND_PATH(MYGUI_INCLUDE_DIRS MyGUI.h PATHS /usr/local/include /usr/include PATH_SUFFIXES MyGUI MYGUI) FIND_LIBRARY(MYGUI_LIBRARIES MyGUIEngineStatic PATHS /usr/lib /usr/local/lib) - SET(MYGUI_PLATFORM_LIBRARIES "MyGUI.DummyPlatform") SET(MYGUI_LIB_DIR ${MYGUI_LIBRARIES}) STRING(REGEX REPLACE "(.*)/.*" "\\1" MYGUI_LIB_DIR "${MYGUI_LIB_DIR}") STRING(REGEX REPLACE ".*/" "" MYGUI_LIBRARIES "${MYGUI_LIBRARIES}") @@ -92,11 +76,9 @@ ELSE (WIN32) #Unix SET(MYGUI_INCLUDE_DIRS ${MYGUI_INCLUDE_DIRS}) SET(MYGUI_LIB_DIR ${MYGUI_LIBDIR}) SET(MYGUI_LIBRARIES ${MYGUI_LIBRARIES} CACHE STRING "") - SET(MYGUI_PLATFORM_LIBRARIES "MyGUI.DummyPlatform") ELSE (MYGUI_INCLUDE_DIRS) FIND_PATH(MYGUI_INCLUDE_DIRS MyGUI.h PATHS /usr/local/include /usr/include PATH_SUFFIXES MyGUI MYGUI) FIND_LIBRARY(MYGUI_LIBRARIES mygui PATHS /usr/lib /usr/local/lib) - SET(MYGUI_PLATFORM_LIBRARIES "MyGUI.DummyPlatform") SET(MYGUI_LIB_DIR ${MYGUI_LIBRARIES}) STRING(REGEX REPLACE "(.*)/.*" "\\1" MYGUI_LIB_DIR "${MYGUI_LIB_DIR}") STRING(REGEX REPLACE ".*/" "" MYGUI_LIBRARIES "${MYGUI_LIBRARIES}") @@ -108,14 +90,12 @@ ENDIF (WIN32) IF (NOT WIN32) # This does not work on Windows for paths with spaces in them SEPARATE_ARGUMENTS(MYGUI_INCLUDE_DIRS) SEPARATE_ARGUMENTS(MYGUI_LIBRARIES) - SEPARATE_ARGUMENTS(MYGUI_PLATFORM_LIBRARIES) ENDIF (NOT WIN32) SET(MYGUI_LIBRARIES ${MYGUI_LIBRARIES} ${FREETYPE_LIBRARIES}) SET(MYGUI_INCLUDE_DIRS ${MYGUI_INCLUDE_DIRS} CACHE PATH "") SET(MYGUI_LIBRARIES ${MYGUI_LIBRARIES} CACHE STRING "") -SET(MYGUI_PLATFORM_LIBRARIES ${MYGUI_PLATFORM_LIBRARIES} CACHE STRING "") SET(MYGUI_LIB_DIR ${MYGUI_LIB_DIR} CACHE PATH "") IF (NOT APPLE OR NOT MYGUI_STATIC) # we need explicit freetype libs only on OS X for static build, for other cases just make it TRUE From 997347b01eb2f0ab8e0c73f7839613ce21b350a8 Mon Sep 17 00:00:00 2001 From: Rohit Nirmal Date: Sat, 25 Apr 2015 13:37:42 -0500 Subject: [PATCH 1049/3725] Silence -Wreorder warnings. --- apps/launcher/datafilespage.cpp | 4 ++-- apps/launcher/maindialog.cpp | 2 +- apps/opencs/view/settings/rangeview.cpp | 2 +- apps/opencs/view/settings/textview.cpp | 2 +- apps/openmw/engine.cpp | 14 ++++++------- apps/openmw/mwgui/hud.cpp | 12 +++++------ apps/openmw/mwgui/mainmenu.cpp | 4 ++-- apps/openmw/mwgui/spellicons.hpp | 4 ++-- apps/openmw/mwgui/spellmodel.hpp | 4 ++-- apps/openmw/mwgui/spellview.cpp | 4 ++-- apps/openmw/mwgui/tooltips.hpp | 6 +++--- apps/openmw/mwgui/tradewindow.cpp | 6 +++--- apps/openmw/mwgui/widgets.hpp | 14 ++++++------- apps/openmw/mwgui/windowmanagerimp.cpp | 6 +++--- apps/openmw/mwinput/inputmanagerimp.cpp | 24 +++++++++++----------- apps/openmw/mwmechanics/aicombataction.hpp | 2 +- apps/openmw/mwrender/animation.cpp | 2 +- apps/openmw/mwrender/characterpreview.cpp | 14 ++++++------- apps/openmw/mwrender/debugging.cpp | 6 +++--- apps/openmw/mwrender/localmap.cpp | 4 ++-- apps/openmw/mwrender/npcanimation.cpp | 10 ++++----- apps/openmw/mwrender/renderingmanager.cpp | 8 ++++---- apps/openmw/mwrender/sky.cpp | 24 +++++++++++----------- apps/openmw/mwrender/water.hpp | 6 +++--- apps/wizard/mainwizard.cpp | 4 ++-- components/esm/esmreader.cpp | 4 ++-- components/esm/esmwriter.cpp | 4 ++-- components/esm/loadcell.hpp | 4 ++-- components/esm/loadland.cpp | 2 +- components/files/fixedpath.hpp | 2 +- components/nif/nifstream.hpp | 2 +- components/nifbullet/bulletnifloader.hpp | 2 +- components/nifogre/ogrenifloader.hpp | 2 +- components/terrain/defaultworld.cpp | 12 +++++------ components/terrain/quadtreenode.cpp | 4 ++-- components/terrain/world.cpp | 12 +++++------ components/widgets/list.cpp | 4 ++-- libs/openengine/bullet/physic.cpp | 14 ++++++------- libs/openengine/gui/manager.cpp | 2 +- 39 files changed, 128 insertions(+), 130 deletions(-) diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index 7861894b0..ec2e1246e 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -24,10 +24,10 @@ const char *Launcher::DataFilesPage::mDefaultContentListName = "Default"; Launcher::DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, Config::GameSettings &gameSettings, Config::LauncherSettings &launcherSettings, QWidget *parent) - : mCfgMgr(cfg) + : QWidget(parent) + , mCfgMgr(cfg) , mGameSettings(gameSettings) , mLauncherSettings(launcherSettings) - , QWidget(parent) { ui.setupUi (this); setObjectName ("DataFilesPage"); diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index 4c142231d..00e6a9aa2 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -25,7 +25,7 @@ using namespace Process; Launcher::MainDialog::MainDialog(QWidget *parent) - : mGameSettings(mCfgMgr), QMainWindow (parent) + : QMainWindow(parent), mGameSettings (mCfgMgr) { setupUi(this); diff --git a/apps/opencs/view/settings/rangeview.cpp b/apps/opencs/view/settings/rangeview.cpp index 246f7ece2..5893c5d0d 100644 --- a/apps/opencs/view/settings/rangeview.cpp +++ b/apps/opencs/view/settings/rangeview.cpp @@ -12,7 +12,7 @@ CSVSettings::RangeView::RangeView (CSMSettings::Setting *setting, Page *parent) - : mRangeWidget (0), mRangeType (setting->type()), View (setting, parent) + : View (setting, parent), mRangeWidget (0), mRangeType (setting->type()) { mRangeWidget = 0; diff --git a/apps/opencs/view/settings/textview.cpp b/apps/opencs/view/settings/textview.cpp index 6886732db..a6ab657fe 100644 --- a/apps/opencs/view/settings/textview.cpp +++ b/apps/opencs/view/settings/textview.cpp @@ -5,7 +5,7 @@ #include "../../model/settings/setting.hpp" CSVSettings::TextView::TextView(CSMSettings::Setting *setting, Page *parent) - : mDelimiter (setting->delimiter()), View (setting, parent) + : View (setting, parent), mDelimiter (setting->delimiter()) { if (setting->isMultiLine()) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index a4bb8c538..4496490d4 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -174,24 +174,24 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) } OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) - : mOgre (0) + : mEncoding(ToUTF8::WINDOWS_1252) + , mEncoder(NULL) + , mOgre (0) , mVerboseScripts (false) , mSkipMenu (false) , mUseSound (true) , mCompileAll (false) , mCompileAllDialogue (false) , mWarningsMode (1) - , mScriptContext (0) - , mFSStrict (false) , mScriptConsoleMode (false) - , mCfgMgr(configurationManager) - , mEncoding(ToUTF8::WINDOWS_1252) - , mEncoder(NULL) , mActivationDistanceOverride(-1) , mGrab(true) - , mScriptBlacklistUse (true) , mExportFonts(false) + , mScriptContext (0) + , mFSStrict (false) + , mScriptBlacklistUse (true) , mNewGame (false) + , mCfgMgr(configurationManager) { OEngine::Misc::Rng::init(); std::srand ( static_cast(std::time(NULL)) ); diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index eb458be50..1f24b58d8 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -77,8 +77,6 @@ namespace MWGui , mMagicka(NULL) , mStamina(NULL) , mDrowning(NULL) - , mDrowningFrame(NULL) - , mDrowningFlash(NULL) , mWeapImage(NULL) , mSpellImage(NULL) , mWeapStatus(NULL) @@ -87,6 +85,9 @@ namespace MWGui , mMinimap(NULL) , mCompass(NULL) , mCrosshair(NULL) + , mCellNameBox(NULL) + , mDrowningFrame(NULL) + , mDrowningFlash(NULL) , mFpsBox(NULL) , mFpsCounter(NULL) , mTriangleCounter(NULL) @@ -94,19 +95,18 @@ namespace MWGui , mHealthManaStaminaBaseLeft(0) , mWeapBoxBaseLeft(0) , mSpellBoxBaseLeft(0) - , mEffectBoxBaseRight(0) , mMinimapBoxBaseRight(0) + , mEffectBoxBaseRight(0) , mDragAndDrop(dragAndDrop) , mCellNameTimer(0.0f) - , mCellNameBox(NULL) + , mWeaponSpellTimer(0.f) , mMapVisible(true) , mWeaponVisible(true) , mSpellVisible(true) , mWorldMouseOver(false) - , mEnemyHealthTimer(-1) , mEnemyActorId(-1) + , mEnemyHealthTimer(-1) , mIsDrowning(false) - , mWeaponSpellTimer(0.f) , mDrowningFlashTheta(0.f) { mMainWidget->setSize(MyGUI::RenderManager::getInstance().getViewSize()); diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index 6ad4da3bf..9a737af64 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -31,11 +31,11 @@ namespace MWGui MainMenu::MainMenu(int w, int h) : OEngine::GUI::Layout("openmw_mainmenu.layout") - , mButtonBox(0), mWidth (w), mHeight (h) - , mSaveGameDialog(NULL) + , mWidth (w), mHeight (h), mButtonBox(0) , mBackground(NULL) , mVideoBackground(NULL) , mVideo(NULL) + , mSaveGameDialog(NULL) { getWidget(mVersionText, "VersionText"); std::stringstream sstream; diff --git a/apps/openmw/mwgui/spellicons.hpp b/apps/openmw/mwgui/spellicons.hpp index 5099fc4d6..26761f2fc 100644 --- a/apps/openmw/mwgui/spellicons.hpp +++ b/apps/openmw/mwgui/spellicons.hpp @@ -24,10 +24,10 @@ namespace MWGui struct MagicEffectInfo { MagicEffectInfo() - : mPermanent(false) - , mMagnitude(0) + : mMagnitude(0) , mRemainingTime(0.f) , mTotalTime(0.f) + , mPermanent(false) {} std::string mSource; // display name for effect source (e.g. potion name) MWMechanics::EffectKey mKey; diff --git a/apps/openmw/mwgui/spellmodel.hpp b/apps/openmw/mwgui/spellmodel.hpp index 7859c8a7b..21fbc9a6e 100644 --- a/apps/openmw/mwgui/spellmodel.hpp +++ b/apps/openmw/mwgui/spellmodel.hpp @@ -24,9 +24,9 @@ namespace MWGui bool mActive; // (Items only) is the item equipped? Spell() - : mSelected(false) + : mType(Type_Spell) + , mSelected(false) , mActive(false) - , mType(Type_Spell) { } }; diff --git a/apps/openmw/mwgui/spellview.cpp b/apps/openmw/mwgui/spellview.cpp index a7c1d781b..6d86b4a23 100644 --- a/apps/openmw/mwgui/spellview.cpp +++ b/apps/openmw/mwgui/spellview.cpp @@ -21,9 +21,9 @@ namespace MWGui } SpellView::SpellView() - : mShowCostColumn(true) + : mScrollView(NULL) + , mShowCostColumn(true) , mHighlightSelected(true) - , mScrollView(NULL) { } diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp index 71b4a560f..c50d47ef5 100644 --- a/apps/openmw/mwgui/tooltips.hpp +++ b/apps/openmw/mwgui/tooltips.hpp @@ -20,10 +20,10 @@ namespace MWGui { public: ToolTipInfo() - : isPotion(false) - , imageSize(32) - , wordWrap(true) + : imageSize(32) , remainingEnchantCharge(-1) + , isPotion(false) + , wordWrap(true) {} std::string caption; diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 42491a5e8..aecfce98d 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -54,10 +54,10 @@ namespace MWGui TradeWindow::TradeWindow() : WindowBase("openmw_trade_window.layout") - , mCurrentBalance(0) - , mItemToSell(-1) - , mTradeModel(NULL) , mSortModel(NULL) + , mTradeModel(NULL) + , mItemToSell(-1) + , mCurrentBalance(0) , mCurrentMerchantOffer(0) { getWidget(mFilterAll, "AllButton"); diff --git a/apps/openmw/mwgui/widgets.hpp b/apps/openmw/mwgui/widgets.hpp index 09a3c11ac..6d9c0a580 100644 --- a/apps/openmw/mwgui/widgets.hpp +++ b/apps/openmw/mwgui/widgets.hpp @@ -36,17 +36,17 @@ namespace MWGui struct SpellEffectParams { SpellEffectParams() - : mMagnMin(-1) + : mNoTarget(false) + , mIsConstant(false) + , mKnown(true) + , mEffectID(-1) + , mSkill(-1) + , mAttribute(-1) + , mMagnMin(-1) , mMagnMax(-1) , mRange(-1) , mDuration(-1) - , mSkill(-1) , mArea(0) - , mAttribute(-1) - , mEffectID(-1) - , mNoTarget(false) - , mIsConstant(false) - , mKnown(true) { } diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 279c2f22e..015af0043 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -102,6 +102,7 @@ namespace MWGui const std::string& logpath, const std::string& cacheDir, bool consoleOnlyScripts, Translation::Storage& translationDataStorage, ToUTF8::FromType encoding, bool exportFonts, const std::map& fallbackMap) : mConsoleOnlyScripts(consoleOnlyScripts) + , mCurrentModals() , mGuiManager(NULL) , mRendering(ogre) , mHud(NULL) @@ -135,8 +136,8 @@ namespace MWGui , mTrainingWindow(NULL) , mMerchantRepair(NULL) , mSoulgemDialog(NULL) - , mRecharge(NULL) , mRepair(NULL) + , mRecharge(NULL) , mCompanionWindow(NULL) , mVideoBackground(NULL) , mVideoWidget(NULL) @@ -159,8 +160,8 @@ namespace MWGui , mPlayerName() , mPlayerRaceId() , mPlayerAttributes() - , mPlayerMinorSkills() , mPlayerMajorSkills() + , mPlayerMinorSkills() , mPlayerSkillValues() , mGui(NULL) , mGuiModes() @@ -173,7 +174,6 @@ namespace MWGui , mFPS(0.0f) , mTriangleCount(0) , mBatchCount(0) - , mCurrentModals() , mFallbackMap(fallbackMap) { // Set up the GUI system diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 88d891a02..2e82faa6d 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -102,32 +102,32 @@ namespace MWInput OMW::Engine& engine, const std::string& userFile, bool userFileExists, const std::string& controllerBindingsFile, bool grab) - : mOgre(ogre) + : mJoystickLastUsed(false) + , mOgre(ogre) , mPlayer(NULL) , mEngine(engine) - , mMouseLookEnabled(false) - , mMouseX(ogre.getWindow()->getWidth ()/2.f) - , mMouseY(ogre.getWindow()->getHeight ()/2.f) - , mMouseWheel(0) - , mDragDrop(false) - , mGuiCursorEnabled(true) , mUserFile(userFile) - , mUserFileExists(userFileExists) + , mDragDrop(false) + , mGrabCursor (Settings::Manager::getBool("grab cursor", "Input")) , mInvertY (Settings::Manager::getBool("invert y axis", "Input")) + , mControlsDisabled(false) , mCameraSensitivity (Settings::Manager::getFloat("camera sensitivity", "Input")) , mUISensitivity (Settings::Manager::getFloat("ui sensitivity", "Input")) , mCameraYMultiplier (Settings::Manager::getFloat("camera y multiplier", "Input")) - , mGrabCursor (Settings::Manager::getBool("grab cursor", "Input")) , mPreviewPOVDelay(0.f) , mTimeIdle(0.f) + , mMouseLookEnabled(false) + , mGuiCursorEnabled(true) + , mDetectingKeyboard(false) , mOverencumberedMessageDelay(0.f) + , mMouseX(ogre.getWindow()->getWidth ()/2.f) + , mMouseY(ogre.getWindow()->getHeight ()/2.f) + , mMouseWheel(0) + , mUserFileExists(userFileExists) , mAlwaysRunActive(Settings::Manager::getBool("always run", "Input")) , mSneakToggles(Settings::Manager::getBool("toggle sneak", "Input")) , mSneaking(false) , mAttemptJump(false) - , mControlsDisabled(false) - , mJoystickLastUsed(false) - , mDetectingKeyboard(false) , mFakeDeviceID(1) { diff --git a/apps/openmw/mwmechanics/aicombataction.hpp b/apps/openmw/mwmechanics/aicombataction.hpp index 1c7451c32..a4a398d05 100644 --- a/apps/openmw/mwmechanics/aicombataction.hpp +++ b/apps/openmw/mwmechanics/aicombataction.hpp @@ -66,7 +66,7 @@ namespace MWMechanics public: /// \a weapon may be empty for hand-to-hand combat ActionWeapon(const MWWorld::Ptr& weapon, const MWWorld::Ptr& ammo = MWWorld::Ptr()) - : mWeapon(weapon), mAmmunition(ammo) {} + : mAmmunition(ammo), mWeapon(weapon) {} /// Equips the given weapon. virtual void prepare(const MWWorld::Ptr& actor); virtual void getCombatRange (float& rangeAttack, float& rangeFollow); diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 871561bdc..6dcd92b15 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -65,6 +65,7 @@ void Animation::EffectAnimationTime::setValue(Ogre::Real) Animation::Animation(const MWWorld::Ptr &ptr, Ogre::SceneNode *node) : mPtr(ptr) + , mGlowLight(NULL) , mInsert(node) , mSkelBase(NULL) , mAccumRoot(NULL) @@ -72,7 +73,6 @@ Animation::Animation(const MWWorld::Ptr &ptr, Ogre::SceneNode *node) , mNonAccumCtrl(NULL) , mAccumulate(0.0f) , mNullAnimationTimePtr(OGRE_NEW NullAnimationTime) - , mGlowLight(NULL) { for(size_t i = 0;i < sNumGroups;i++) mAnimationTimePtr[i].bind(OGRE_NEW AnimationTime(this)); diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 8071dd5fd..7d61e3b6c 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -25,7 +25,12 @@ namespace MWRender CharacterPreview::CharacterPreview(MWWorld::Ptr character, int sizeX, int sizeY, const std::string& name, Ogre::Vector3 position, Ogre::Vector3 lookAt) - : mSceneMgr (0) + : mRecover(false) + , mRenderTarget(NULL) + , mViewport(NULL) + , mCamera(NULL) + , mSceneMgr (0) + , mNode(NULL) , mPosition(position) , mLookAt(lookAt) , mCharacter(character) @@ -33,11 +38,6 @@ namespace MWRender , mName(name) , mSizeX(sizeX) , mSizeY(sizeY) - , mRenderTarget(NULL) - , mViewport(NULL) - , mCamera(NULL) - , mNode(NULL) - , mRecover(false) { mCharacter.mCell = NULL; } @@ -161,9 +161,9 @@ namespace MWRender InventoryPreview::InventoryPreview(MWWorld::Ptr character) : CharacterPreview(character, 512, 1024, "CharacterPreview", Ogre::Vector3(0, 71, -700), Ogre::Vector3(0,71,0)) - , mSelectionBuffer(NULL) , mSizeX(0) , mSizeY(0) + , mSelectionBuffer(NULL) { } diff --git a/apps/openmw/mwrender/debugging.cpp b/apps/openmw/mwrender/debugging.cpp index 79eeff2d0..49e65490d 100644 --- a/apps/openmw/mwrender/debugging.cpp +++ b/apps/openmw/mwrender/debugging.cpp @@ -155,10 +155,10 @@ ManualObject *Debugging::createPathgridPoints(const ESM::Pathgrid *pathgrid) } Debugging::Debugging(SceneNode *root, OEngine::Physic::PhysicEngine *engine) : - mRootNode(root), mEngine(engine), - mSceneMgr(root->getCreator()), + mEngine(engine), mSceneMgr(root->getCreator()), mPathgridEnabled(false), - mInteriorPathgridNode(NULL), mPathGridRoot(NULL), + mRootNode(root), + mPathGridRoot(NULL), mInteriorPathgridNode(NULL), mGridMatsCreated(false) { ResourceGroupManager::getSingleton().createResourceGroup(DEBUGGING_GROUP); diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 0299dc493..b69222664 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -25,9 +25,9 @@ using namespace MWRender; using namespace Ogre; LocalMap::LocalMap(OEngine::Render::OgreRenderer* rend, MWRender::RenderingManager* rendering) - : mInterior(false) + : mMapResolution(Settings::Manager::getInt("local map resolution", "Map")) , mAngle(0.f) - , mMapResolution(Settings::Manager::getInt("local map resolution", "Map")) + , mInterior(false) { mRendering = rend; mRenderingManager = rendering; diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index a724644a7..6a6d52e26 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -91,7 +91,7 @@ namespace MWRender { HeadAnimationTime::HeadAnimationTime(MWWorld::Ptr reference) - : mReference(reference), mTalkStart(0), mTalkStop(0), mBlinkStart(0), mBlinkStop(0), mValue(0), mEnabled(true) + : mReference(reference), mTalkStart(0), mTalkStop(0), mBlinkStart(0), mBlinkStop(0), mEnabled(true), mValue(0) { resetBlinkTimer(); } @@ -203,17 +203,17 @@ NpcAnimation::~NpcAnimation() NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, int visibilityFlags, bool disableListener, bool disableSounds, ViewMode viewMode) : Animation(ptr, node), - mVisibilityFlags(visibilityFlags), mListenerDisabled(disableListener), mViewMode(viewMode), mShowWeapons(false), mShowCarriedLeft(true), + mNpcType(Type_Normal), + mVisibilityFlags(visibilityFlags), mFirstPersonOffset(0.f, 0.f, 0.f), mAlpha(1.f), - mNpcType(Type_Normal), mSoundsDisabled(disableSounds), - mHeadPitch(0.f), - mHeadYaw(0.f) + mHeadYaw(0.f), + mHeadPitch(0.f) { mNpc = mPtr.get()->mBase; diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 8fb1ee53c..f00ebb303 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -56,14 +56,14 @@ namespace MWRender { RenderingManager::RenderingManager(OEngine::Render::OgreRenderer& _rend, const boost::filesystem::path& resDir, const boost::filesystem::path& cacheDir, OEngine::Physic::PhysicEngine* engine, MWWorld::Fallback* fallback) - : mRendering(_rend) + : mSunEnabled(0) , mFallback(fallback) + , mTerrain(NULL) + , mRendering(_rend) + , mEffectManager(NULL) , mPlayerAnimation(NULL) , mAmbientMode(0) - , mSunEnabled(0) , mPhysicsEngine(engine) - , mTerrain(NULL) - , mEffectManager(NULL) , mRenderWorld(true) { mActors = new MWRender::Actors(mRendering, this); diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index d591cca2e..fd439050c 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -247,9 +247,13 @@ unsigned int Moon::getPhaseInt() const } SkyManager::SkyManager(Ogre::SceneNode *root, Ogre::Camera *pCamera) - : mHour(0.0f) + : mCreated(false) + , mMoonRed(false) + , mIsStorm(false) + , mHour(0.0f) , mDay(0) , mMonth(0) + , mCloudAnimationTimer(0.f) , mSun(NULL) , mSunGlare(NULL) , mMasser(NULL) @@ -260,6 +264,9 @@ SkyManager::SkyManager(Ogre::SceneNode *root, Ogre::Camera *pCamera) , mAtmosphereDay(NULL) , mAtmosphereNight(NULL) , mCloudNode(NULL) + , mParticleNode(NULL) + , mRainTimer(0) + , mStormDirection(0,-1,0) , mClouds() , mNextClouds() , mCloudBlendFactor(0.0f) @@ -268,22 +275,15 @@ SkyManager::SkyManager(Ogre::SceneNode *root, Ogre::Camera *pCamera) , mStarsOpacity(0.0f) , mLightning(NULL) , mRemainingTransitionTime(0.0f) - , mGlareFade(0.0f) , mGlare(0.0f) + , mGlareFade(0.0f) + , mRainEnabled(false) + , mRainSpeed(0) + , mRainFrequency(1) , mEnabled(true) , mSunEnabled(true) , mMasserEnabled(true) , mSecundaEnabled(true) - , mCreated(false) - , mCloudAnimationTimer(0.f) - , mMoonRed(false) - , mParticleNode(NULL) - , mRainEnabled(false) - , mRainTimer(0) - , mRainSpeed(0) - , mRainFrequency(1) - , mStormDirection(0,-1,0) - , mIsStorm(false) { mSceneMgr = root->getCreator(); mRootNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(); diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index 775950431..53d54cdc9 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -46,10 +46,10 @@ namespace MWRender { { public: Reflection(Ogre::SceneManager* sceneManager) - : mSceneMgr(sceneManager) - , mIsUnderwater(false) - , mCamera(NULL) + : mCamera(NULL) , mParentCamera(NULL) + , mSceneMgr(sceneManager) + , mIsUnderwater(false) {} virtual ~Reflection() {} diff --git a/apps/wizard/mainwizard.cpp b/apps/wizard/mainwizard.cpp index a61daa5a4..7538511fe 100644 --- a/apps/wizard/mainwizard.cpp +++ b/apps/wizard/mainwizard.cpp @@ -25,10 +25,10 @@ using namespace Process; Wizard::MainWizard::MainWizard(QWidget *parent) : - mGameSettings(mCfgMgr), QWizard(parent), + mInstallations(), mError(false), - mInstallations() + mGameSettings(mCfgMgr) { #ifndef Q_OS_MAC setWizardStyle(QWizard::ModernStyle); diff --git a/components/esm/esmreader.cpp b/components/esm/esmreader.cpp index bbe475ff7..2804f89d4 100644 --- a/components/esm/esmreader.cpp +++ b/components/esm/esmreader.cpp @@ -21,9 +21,9 @@ ESM_Context ESMReader::getContext() } ESMReader::ESMReader() - : mBuffer(50*1024) + : mIdx(0) , mRecordFlags(0) - , mIdx(0) + , mBuffer(50*1024) , mGlobalReaderList(NULL) , mEncoder(NULL) { diff --git a/components/esm/esmwriter.cpp b/components/esm/esmwriter.cpp index 14951608d..c64678e70 100644 --- a/components/esm/esmwriter.cpp +++ b/components/esm/esmwriter.cpp @@ -9,10 +9,10 @@ namespace ESM { ESMWriter::ESMWriter() - : mEncoder (0) + : mStream(NULL) + , mEncoder (0) , mRecordCount (0) , mCounting (true) - , mStream(NULL) {} unsigned int ESMWriter::getVersion() const diff --git a/components/esm/loadcell.hpp b/components/esm/loadcell.hpp index b78d4075a..1aef97d9f 100644 --- a/components/esm/loadcell.hpp +++ b/components/esm/loadcell.hpp @@ -78,9 +78,9 @@ struct Cell float mFogDensity; }; - Cell() : mWater(0), - mName(""), + Cell() : mName(""), mRegion(""), + mWater(0), mWaterInt(false), mMapColor(0), mRefNumCounter(0) diff --git a/components/esm/loadland.cpp b/components/esm/loadland.cpp index b1c01fcba..b0897ec67 100644 --- a/components/esm/loadland.cpp +++ b/components/esm/loadland.cpp @@ -67,11 +67,11 @@ Land::Land() : mFlags(0) , mX(0) , mY(0) + , mPlugin(0) , mEsm(NULL) , mDataTypes(0) , mDataLoaded(false) , mLandData(NULL) - , mPlugin(0) { } diff --git a/components/files/fixedpath.hpp b/components/files/fixedpath.hpp index 9fb36d984..5e0ea6c86 100644 --- a/components/files/fixedpath.hpp +++ b/components/files/fixedpath.hpp @@ -57,8 +57,8 @@ struct FixedPath , mGlobalConfigPath(mPath.getGlobalConfigPath()) , mLocalPath(mPath.getLocalPath()) , mGlobalDataPath(mPath.getGlobalDataPath()) - , mInstallPath(mPath.getInstallPath()) , mCachePath(mPath.getCachePath()) + , mInstallPath(mPath.getInstallPath()) { } diff --git a/components/nif/nifstream.hpp b/components/nif/nifstream.hpp index 6c5e83eeb..aee16f280 100644 --- a/components/nif/nifstream.hpp +++ b/components/nif/nifstream.hpp @@ -35,7 +35,7 @@ public: NIFFile * const file; - NIFStream (NIFFile * file, Ogre::DataStreamPtr inp): file (file), inp (inp) {} + NIFStream (NIFFile * file, Ogre::DataStreamPtr inp): inp (inp), file (file) {} void skip(size_t size) { inp->skip(size); } diff --git a/components/nifbullet/bulletnifloader.hpp b/components/nifbullet/bulletnifloader.hpp index 0d81d84b6..f4126b7a7 100644 --- a/components/nifbullet/bulletnifloader.hpp +++ b/components/nifbullet/bulletnifloader.hpp @@ -69,8 +69,8 @@ class ManualBulletShapeLoader : public OEngine::Physic::BulletShapeLoader public: ManualBulletShapeLoader(bool showMarkers=false) : mShape(NULL) - , mStaticMesh(NULL) , mCompoundShape(NULL) + , mStaticMesh(NULL) , mBoundingBox(NULL) , mShowMarkers(showMarkers) { diff --git a/components/nifogre/ogrenifloader.hpp b/components/nifogre/ogrenifloader.hpp index c13532644..b583429dd 100644 --- a/components/nifogre/ogrenifloader.hpp +++ b/components/nifogre/ogrenifloader.hpp @@ -75,7 +75,7 @@ struct ObjectScene { std::vector > mControllers; - ObjectScene(Ogre::SceneManager* sceneMgr) : mSkelBase(0), mMaxControllerLength(0), mSceneMgr(sceneMgr) + ObjectScene(Ogre::SceneManager* sceneMgr) : mSkelBase(0), mSceneMgr(sceneMgr), mMaxControllerLength(0) { } ~ObjectScene(); diff --git a/components/terrain/defaultworld.cpp b/components/terrain/defaultworld.cpp index c6f0f7136..7bc73ddda 100644 --- a/components/terrain/defaultworld.cpp +++ b/components/terrain/defaultworld.cpp @@ -78,15 +78,15 @@ namespace Terrain DefaultWorld::DefaultWorld(Ogre::SceneManager* sceneMgr, Storage* storage, int visibilityFlags, bool shaders, Alignment align, float minBatchSize, float maxBatchSize) : World(sceneMgr, storage, visibilityFlags, shaders, align) - , mMinBatchSize(minBatchSize) - , mMaxBatchSize(maxBatchSize) + , mWorkQueueChannel(0) , mVisible(true) - , mMaxX(0) + , mChunksLoading(0) , mMinX(0) - , mMaxY(0) + , mMaxX(0) , mMinY(0) - , mChunksLoading(0) - , mWorkQueueChannel(0) + , mMaxY(0) + , mMinBatchSize(minBatchSize) + , mMaxBatchSize(maxBatchSize) , mLayerLoadPending(true) { #if TERRAIN_USE_SHADER == 0 diff --git a/components/terrain/quadtreenode.cpp b/components/terrain/quadtreenode.cpp index 6a9964213..89e5e34a3 100644 --- a/components/terrain/quadtreenode.cpp +++ b/components/terrain/quadtreenode.cpp @@ -133,6 +133,7 @@ namespace QuadTreeNode::QuadTreeNode(DefaultWorld* terrain, ChildDirection dir, float size, const Ogre::Vector2 ¢er, QuadTreeNode* parent) : mMaterialGenerator(NULL) + , mLoadState(LS_Unloaded) , mIsDummy(false) , mSize(size) , mLodLevel(Log2(static_cast(mSize))) @@ -142,9 +143,8 @@ QuadTreeNode::QuadTreeNode(DefaultWorld* terrain, ChildDirection dir, float size , mCenter(center) , mSceneNode(NULL) , mParent(parent) - , mTerrain(terrain) , mChunk(NULL) - , mLoadState(LS_Unloaded) + , mTerrain(terrain) { mBounds.setNull(); for (int i=0; i<4; ++i) diff --git a/components/terrain/world.cpp b/components/terrain/world.cpp index 5cc2647c6..3baaaed44 100644 --- a/components/terrain/world.cpp +++ b/components/terrain/world.cpp @@ -30,14 +30,14 @@ namespace Terrain World::World(Ogre::SceneManager* sceneMgr, Storage* storage, int visibilityFlags, bool shaders, Alignment align) - : mStorage(storage) - , mSceneMgr(sceneMgr) - , mVisibilityFlags(visibilityFlags) - , mShaders(shaders) - , mAlign(align) - , mCache(storage->getCellVertices()) + : mShaders(shaders) , mShadows(false) , mSplitShadows(false) + , mAlign(align) + , mStorage(storage) + , mVisibilityFlags(visibilityFlags) + , mSceneMgr(sceneMgr) + , mCache(storage->getCellVertices()) { } diff --git a/components/widgets/list.cpp b/components/widgets/list.cpp index 8517a0303..5a79de3d1 100644 --- a/components/widgets/list.cpp +++ b/components/widgets/list.cpp @@ -9,8 +9,8 @@ namespace Gui { MWList::MWList() : - mClient(0) - , mScrollView(0) + mScrollView(0) + ,mClient(0) , mItemHeight(0) { } diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index 013ef1003..15be7665a 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -74,13 +74,11 @@ namespace Physic { PhysicActor::PhysicActor(const std::string &name, const std::string &mesh, PhysicEngine *engine, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, float scale) - : mName(name), mEngine(engine), mMesh(mesh) - , mBody(0), mOnGround(false), mInternalCollisionMode(true) + : mCanWaterWalk(false), mWalkingOnWater(false) + , mBody(0), mScale(scale), mForce(0.0f), mOnGround(false) + , mInternalCollisionMode(true) , mExternalCollisionMode(true) - , mForce(0.0f) - , mScale(scale) - , mWalkingOnWater(false) - , mCanWaterWalk(false) + , mMesh(mesh), mName(name), mEngine(engine) { if (!NifBullet::getBoundingBox(mMesh, mHalfExtents, mMeshTranslation, mMeshOrientation)) { @@ -239,8 +237,8 @@ namespace Physic PhysicEngine::PhysicEngine(BulletShapeLoader* shapeLoader) : - mDebugActive(0) - , mSceneMgr(NULL) + mSceneMgr(NULL) + , mDebugActive(0) { // Set up the collision configuration and dispatcher collisionConfiguration = new btDefaultCollisionConfiguration(); diff --git a/libs/openengine/gui/manager.cpp b/libs/openengine/gui/manager.cpp index 349647892..5fa284c00 100644 --- a/libs/openengine/gui/manager.cpp +++ b/libs/openengine/gui/manager.cpp @@ -99,8 +99,8 @@ public: mManualRender(false), mCountBatch(0), mVertexProgramNoTexture(NULL), - mFragmentProgramNoTexture(NULL), mVertexProgramOneTexture(NULL), + mFragmentProgramNoTexture(NULL), mFragmentProgramOneTexture(NULL) { mTextureAddressMode.u = Ogre::TextureUnitState::TAM_CLAMP; From 7f2bd01f79749d05d18e563c013153376338118e Mon Sep 17 00:00:00 2001 From: cc9cii Date: Wed, 29 Apr 2015 12:08:11 +1000 Subject: [PATCH 1050/3725] Handle plugins that has 0x00 for levelled list types, for example Ravenloft v5.02d, to use 0x01. --- apps/opencs/model/world/refidadapterimp.hpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index 41d8c65d5..e38554383 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -2,6 +2,7 @@ #define CSM_WOLRD_REFIDADAPTERIMP_H #include +#include #include @@ -1895,6 +1896,20 @@ namespace CSMWorld { return QString("All Levels"); } + else if (mType == CSMWorld::UniversalId::Type_CreatureLevelledList && + record.get().mFlags == 0x00) + { + std::cerr << "Unknown creature leveled list type: " << record.get().mFlags + << ", Using \"All Levels\""<< std::endl; + return QString("All Levels"); + } + else if (mType == CSMWorld::UniversalId::Type_ItemLevelledList && + record.get().mFlags == 0x00) + { + std::cerr << "Unknown item leveled list type: " << record.get().mFlags + << ", Using \"Each\""<< std::endl; + return QString("Each"); + } else throw std::runtime_error("unknown leveled list type"); } From 607a16eb01387aad3239d13378f9a7b294cd840a Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 29 Apr 2015 11:36:56 +0200 Subject: [PATCH 1051/3725] removed leftover ignoreRefNum argument --- components/esm/cellref.cpp | 9 ++++----- components/esm/cellref.hpp | 4 ++-- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/components/esm/cellref.cpp b/components/esm/cellref.cpp index ef33f495f..c3b889df5 100644 --- a/components/esm/cellref.cpp +++ b/components/esm/cellref.cpp @@ -25,13 +25,13 @@ void ESM::RefNum::save (ESMWriter &esm, bool wide, const std::string& tag) const } -void ESM::CellRef::load (ESMReader& esm, bool wideRefNum, bool ignoreRefNum) +void ESM::CellRef::load (ESMReader& esm, bool wideRefNum) { - loadId(esm, wideRefNum, ignoreRefNum); + loadId(esm, wideRefNum); loadData(esm); } -void ESM::CellRef::loadId (ESMReader& esm, bool wideRefNum, bool ignoreRefNum) +void ESM::CellRef::loadId (ESMReader& esm, bool wideRefNum) { // According to Hrnchamd, this does not belong to the actual ref. Instead, it is a marker indicating that // the following refs are part of a "temp refs" section. A temp ref is not being tracked by the moved references system. @@ -40,8 +40,7 @@ void ESM::CellRef::loadId (ESMReader& esm, bool wideRefNum, bool ignoreRefNum) if (esm.isNextSub ("NAM0")) esm.skipHSub(); - if (!ignoreRefNum) - mRefNum.load (esm, wideRefNum); + mRefNum.load (esm, wideRefNum); mRefID = esm.getHNString ("NAME"); } diff --git a/components/esm/cellref.hpp b/components/esm/cellref.hpp index 0fb449e16..e9959611b 100644 --- a/components/esm/cellref.hpp +++ b/components/esm/cellref.hpp @@ -100,9 +100,9 @@ namespace ESM Position mPos; /// Calls loadId and loadData - void load (ESMReader& esm, bool wideRefNum = false, bool ignoreRefNum = false); + void load (ESMReader& esm, bool wideRefNum = false); - void loadId (ESMReader& esm, bool wideRefNum = false, bool ignoreRefNum = false); + void loadId (ESMReader& esm, bool wideRefNum = false); /// Implicitly called by load void loadData (ESMReader& esm); From 8e49ccc2f4f7c6a510f7416226623ea0313e3d73 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Wed, 29 Apr 2015 20:24:17 +1000 Subject: [PATCH 1052/3725] Added user setting options. --- apps/opencs/model/settings/usersettings.cpp | 6 ++- apps/opencs/view/world/scriptedit.cpp | 50 +++++++++++++++------ apps/opencs/view/world/scriptedit.hpp | 5 ++- apps/opencs/view/world/scriptsubview.cpp | 45 +++++++++++++++++-- apps/opencs/view/world/scriptsubview.hpp | 9 ++++ 5 files changed, 96 insertions(+), 19 deletions(-) diff --git a/apps/opencs/model/settings/usersettings.cpp b/apps/opencs/model/settings/usersettings.cpp index 6e240c998..d9db95c71 100644 --- a/apps/opencs/model/settings/usersettings.cpp +++ b/apps/opencs/model/settings/usersettings.cpp @@ -143,6 +143,10 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() minWidth->setDefaultValue (325); minWidth->setRange (50, 10000); minWidth->setToolTip ("Minimum width of subviews."); + + Setting *monoFont = createSetting (Type_CheckBox, "mono-font", "Use monospace font"); + monoFont->setDefaultValue ("true"); + monoFont->setToolTip ("Whether to use monospaced fonts on script edit subview."); } declareSection ("records", "Records"); @@ -225,7 +229,7 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() Setting *autoDelete = createSetting (Type_CheckBox, "auto-delete", "Delete row from result table after a successful replace"); autoDelete->setDefaultValue ("true"); } - + { /****************************************************************** * There are three types of values: diff --git a/apps/opencs/view/world/scriptedit.cpp b/apps/opencs/view/world/scriptedit.cpp index 991e58ae7..9e0a7e95a 100644 --- a/apps/opencs/view/world/scriptedit.cpp +++ b/apps/opencs/view/world/scriptedit.cpp @@ -12,6 +12,7 @@ #include "../../model/world/universalid.hpp" #include "../../model/world/tablemimedata.hpp" +#include "../../model/settings/usersettings.hpp" CSVWorld::ScriptEdit::ChangeLock::ChangeLock (ScriptEdit& edit) : mEdit (edit) @@ -30,7 +31,9 @@ CSVWorld::ScriptEdit::ScriptEdit (const CSMDoc::Document& document, ScriptHighli : QPlainTextEdit (parent), mDocument (document), mWhiteListQoutes("^[a-z|_]{1}[a-z|0-9|_]{0,}$", Qt::CaseInsensitive), - mChangeLocked (0) + mChangeLocked (0), + mLineNumberArea(0), + mShowLineNum(false) { // setAcceptRichText (false); setLineWrapMode (QPlainTextEdit::NoWrap); @@ -75,19 +78,35 @@ CSVWorld::ScriptEdit::ScriptEdit (const CSMDoc::Document& document, ScriptHighli mUpdateTimer.setSingleShot (true); - // FIXME: make this configurable or provide a font selector dialogue - // FIXME: save QFontInfo somewhere before switching to a new one - QFont font("Monospace"); - font.setStyleHint(QFont::TypeWriter); - setFont(font); + // TODO: provide a font selector dialogue + std::string useMonoFont = + CSMSettings::UserSettings::instance().setting("window/mono-font", "true").toStdString(); + if (useMonoFont == "true") + { + QFont font("Monospace"); + font.setStyleHint(QFont::TypeWriter); + setFont(font); + } - // FIXME: make this configurable - lineNumberArea = new LineNumberArea(this); + mLineNumberArea = new LineNumberArea(this); + updateLineNumberAreaWidth(0); connect(this, SIGNAL(blockCountChanged(int)), this, SLOT(updateLineNumberAreaWidth(int))); connect(this, SIGNAL(updateRequest(QRect,int)), this, SLOT(updateLineNumberArea(QRect,int))); - updateLineNumberAreaWidth(0); + std::string showStatusBar = + CSMSettings::UserSettings::instance().settingValue("window/show-statusbar").toStdString(); + + showLineNum(showStatusBar == "true"); +} + +void CSVWorld::ScriptEdit::showLineNum(bool show) +{ + if(show!=mShowLineNum) + { + mShowLineNum = show; + updateLineNumberAreaWidth(0); + } } bool CSVWorld::ScriptEdit::isChangeLocked() const @@ -176,6 +195,9 @@ void CSVWorld::ScriptEdit::updateHighlighting() int CSVWorld::ScriptEdit::lineNumberAreaWidth() { + if(!mShowLineNum) + return 0; + int digits = 1; int max = qMax(1, blockCount()); while (max >= 10) @@ -197,9 +219,9 @@ void CSVWorld::ScriptEdit::updateLineNumberAreaWidth(int /* newBlockCount */) void CSVWorld::ScriptEdit::updateLineNumberArea(const QRect &rect, int dy) { if (dy) - lineNumberArea->scroll(0, dy); + mLineNumberArea->scroll(0, dy); else - lineNumberArea->update(0, rect.y(), lineNumberArea->width(), rect.height()); + mLineNumberArea->update(0, rect.y(), mLineNumberArea->width(), rect.height()); if (rect.contains(viewport()->rect())) updateLineNumberAreaWidth(0); @@ -210,12 +232,12 @@ void CSVWorld::ScriptEdit::resizeEvent(QResizeEvent *e) QPlainTextEdit::resizeEvent(e); QRect cr = contentsRect(); - lineNumberArea->setGeometry(QRect(cr.left(), cr.top(), lineNumberAreaWidth(), cr.height())); + mLineNumberArea->setGeometry(QRect(cr.left(), cr.top(), lineNumberAreaWidth(), cr.height())); } void CSVWorld::ScriptEdit::lineNumberAreaPaintEvent(QPaintEvent *event) { - QPainter painter(lineNumberArea); + QPainter painter(mLineNumberArea); QTextBlock block = firstVisibleBlock(); int blockNumber = block.blockNumber(); @@ -255,7 +277,7 @@ void CSVWorld::ScriptEdit::lineNumberAreaPaintEvent(QPaintEvent *event) painter.setPen(Qt::black); } painter.setFont(newFont); - painter.drawText(0, top, lineNumberArea->width(), fontMetrics().height(), + painter.drawText(0, top, mLineNumberArea->width(), fontMetrics().height(), Qt::AlignRight, number); painter.setFont(font); } diff --git a/apps/opencs/view/world/scriptedit.hpp b/apps/opencs/view/world/scriptedit.hpp index 90fe2917e..3355d40c1 100644 --- a/apps/opencs/view/world/scriptedit.hpp +++ b/apps/opencs/view/world/scriptedit.hpp @@ -5,6 +5,7 @@ #include #include #include +#include #include "../../model/world/universalid.hpp" @@ -47,7 +48,8 @@ namespace CSVWorld int mChangeLocked; ScriptHighlighter *mHighlighter; QTimer mUpdateTimer; - QWidget *lineNumberArea; + bool mShowLineNum; + LineNumberArea *mLineNumberArea; public: @@ -61,6 +63,7 @@ namespace CSVWorld void lineNumberAreaPaintEvent(QPaintEvent *event); int lineNumberAreaWidth(); + void showLineNum(bool show); protected: diff --git a/apps/opencs/view/world/scriptsubview.cpp b/apps/opencs/view/world/scriptsubview.cpp index ea9dcee8c..335cb97af 100644 --- a/apps/opencs/view/world/scriptsubview.cpp +++ b/apps/opencs/view/world/scriptsubview.cpp @@ -1,8 +1,11 @@ - #include "scriptsubview.hpp" #include +#include +#include +#include + #include "../../model/doc/document.hpp" #include "../../model/world/universalid.hpp" #include "../../model/world/data.hpp" @@ -13,9 +16,26 @@ #include "scriptedit.hpp" CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) -: SubView (id), mDocument (document), mColumn (-1) +: SubView (id), mDocument (document), mColumn (-1), mBottom(0), mStatus(0) { - setWidget (mEditor = new ScriptEdit (mDocument, ScriptHighlighter::Mode_General, this)); + QVBoxLayout *layout = new QVBoxLayout; + layout->setContentsMargins (QMargins (0, 0, 0, 0)); + + mBottom = new QWidget(this); + QStackedLayout *bottmLayout = new QStackedLayout(mBottom); + bottmLayout->setContentsMargins (0, 0, 0, 0); + QStatusBar *statusBar = new QStatusBar(mBottom); + mStatus = new QLabel(mBottom); + statusBar->addWidget (mStatus); + bottmLayout->addWidget (statusBar); + mBottom->setLayout (bottmLayout); + + layout->addWidget (mBottom, 0); + layout->insertWidget (0, mEditor = new ScriptEdit (mDocument, ScriptHighlighter::Mode_General, this), 2); + + QWidget *widget = new QWidget; + widget->setLayout (layout); + setWidget (widget); mModel = &dynamic_cast ( *document.getData().getTableModel (CSMWorld::UniversalId::Type_Scripts)); @@ -40,6 +60,25 @@ CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc: connect (mModel, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)), this, SLOT (rowsAboutToBeRemoved (const QModelIndex&, int, int))); + + updateStatusBar(); + connect(mEditor, SIGNAL(cursorPositionChanged()), this, SLOT(updateStatusBar())); +} + +void CSVWorld::ScriptSubView::setStatusBar (bool show) +{ + mEditor->showLineNum(show); + mBottom->setVisible(show); +} + +void CSVWorld::ScriptSubView::updateStatusBar () +{ + std::ostringstream stream; + + stream << "(" << mEditor->textCursor().blockNumber() + 1 << ", " + << mEditor->textCursor().columnNumber() + 1 << ")"; + + mStatus->setText (QString::fromUtf8 (stream.str().c_str())); } void CSVWorld::ScriptSubView::setEditLock (bool locked) diff --git a/apps/opencs/view/world/scriptsubview.hpp b/apps/opencs/view/world/scriptsubview.hpp index 561476577..5d85891cf 100644 --- a/apps/opencs/view/world/scriptsubview.hpp +++ b/apps/opencs/view/world/scriptsubview.hpp @@ -4,6 +4,7 @@ #include "../doc/subview.hpp" class QModelIndex; +class QLabel; namespace CSMDoc { @@ -27,6 +28,8 @@ namespace CSVWorld CSMDoc::Document& mDocument; CSMWorld::IdTable *mModel; int mColumn; + QWidget *mBottom; + QLabel *mStatus; public: @@ -36,6 +39,8 @@ namespace CSVWorld virtual void useHint (const std::string& hint); + virtual void setStatusBar (bool show); + public slots: void textChanged(); @@ -43,6 +48,10 @@ namespace CSVWorld void dataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight); void rowsAboutToBeRemoved (const QModelIndex& parent, int start, int end); + + private slots: + + void updateStatusBar(); }; } From 31db37afd460201d83767b7a4f0cd4933a7b96c1 Mon Sep 17 00:00:00 2001 From: k1ll Date: Wed, 19 Jun 2013 20:22:07 +0200 Subject: [PATCH 1053/3725] FindMygui mingw --- cmake/FindMyGUI.cmake | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/cmake/FindMyGUI.cmake b/cmake/FindMyGUI.cmake index 40fa2373f..2829a74d3 100644 --- a/cmake/FindMyGUI.cmake +++ b/cmake/FindMyGUI.cmake @@ -19,7 +19,46 @@ include(PreprocessorUtils) # ENDIF (MYGUI_LIBRARIES AND MYGUI_INCLUDE_DIRS) IF (WIN32) #Windows + MESSAGE(STATUS "Looking for MyGUI") + + IF(MINGW) + + FIND_PATH ( MYGUI_INCLUDE_DIRS MyGUI.h PATH_SUFFIXES MYGUI) + FIND_PATH ( MYGUI_PLATFORM_INCLUDE_DIRS MyGUI_OgrePlatform.h PATH_SUFFIXES MYGUI) + FIND_LIBRARY ( MYGUI_LIBRARIES_REL NAMES + libMyGUIEngine${CMAKE_SHARED_LIBRARY_SUFFIX} + libMyGUI.OgrePlatform${CMAKE_STATIC_LIBRARY_SUFFIX} + HINTS + ${MYGUI_LIB_DIR} + PATH_SUFFIXES "" release relwithdebinfo minsizerel ) + + FIND_LIBRARY ( MYGUI_LIBRARIES_DBG NAMES + libMyGUIEngine_d${CMAKE_SHARED_LIBRARY_SUFFIX} + libMyGUI.OgrePlatform_d${CMAKE_STATIC_LIBRARY_SUFFIX} + HINTS + ${MYGUI_LIB_DIR} + PATH_SUFFIXES "" debug ) + + FIND_LIBRARY ( MYGUI_PLATFORM_LIBRARIES_REL NAMES + libMyGUI.OgrePlatform${CMAKE_STATIC_LIBRARY_SUFFIX} + HINTS + ${MYGUI_LIB_DIR} + PATH_SUFFIXES "" release relwithdebinfo minsizerel ) + + FIND_LIBRARY ( MYGUI_PLATFORM_LIBRARIES_DBG NAMES + MyGUI.OgrePlatform_d${CMAKE_STATIC_LIBRARY_SUFFIX} + HINTS + ${MYGUI_LIB_DIR} + PATH_SUFFIXES "" debug ) + + make_library_set ( MYGUI_LIBRARIES ) + make_library_set ( MYGUI_PLATFORM_LIBRARIES ) + + MESSAGE ("${MYGUI_LIBRARIES}") + MESSAGE ("${MYGUI_PLATFORM_LIBRARIES}") + ENDIF(MINGW) + SET(MYGUISDK $ENV{MYGUI_HOME}) IF (MYGUISDK) findpkg_begin ( "MYGUI" ) From 00b7712a5910932f5bb8e333e6a28883f506092a Mon Sep 17 00:00:00 2001 From: k1ll Date: Sat, 22 Jun 2013 11:33:22 +0200 Subject: [PATCH 1054/3725] Fix shlwapi include case and add the lib for linking when building for windows --- components/CMakeLists.txt | 4 ++++ components/files/windowspath.cpp | 4 +--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 38fcd88e3..5bd18d119 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -170,6 +170,10 @@ if (GIT_CHECKOUT) add_dependencies (components git-version) endif (GIT_CHECKOUT) +if (WIN32) +target_link_libraries(components shlwapi) +endif() + # Fix for not visible pthreads functions for linker with glibc 2.15 if (UNIX AND NOT APPLE) target_link_libraries(components ${CMAKE_THREAD_LIBS_INIT}) diff --git a/components/files/windowspath.cpp b/components/files/windowspath.cpp index 0df782702..ece4049a8 100644 --- a/components/files/windowspath.cpp +++ b/components/files/windowspath.cpp @@ -6,9 +6,7 @@ #include #include -#include - -#pragma comment(lib, "Shlwapi.lib") +#include #include namespace bconv = boost::locale::conv; From a230050ec8d4d094a5905b0280173fc3e780a09a Mon Sep 17 00:00:00 2001 From: k1ll Date: Sat, 22 Jun 2013 11:37:17 +0200 Subject: [PATCH 1055/3725] Boost tr1 unordered map does not work with mingw --- apps/openmw/mwworld/worldimp.cpp | 2 +- components/files/configurationmanager.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 013386f8f..744057e43 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1,6 +1,6 @@ #include "worldimp.hpp" -#ifdef _WIN32 +#if defined(_WIN32) && !defined(__MINGW32__) #include #elif defined HAVE_UNORDERED_MAP #include diff --git a/components/files/configurationmanager.hpp b/components/files/configurationmanager.hpp index b0b7fea9a..24b08c523 100644 --- a/components/files/configurationmanager.hpp +++ b/components/files/configurationmanager.hpp @@ -1,7 +1,7 @@ #ifndef COMPONENTS_FILES_CONFIGURATIONMANAGER_HPP #define COMPONENTS_FILES_CONFIGURATIONMANAGER_HPP -#ifdef _WIN32 +#if defined(_WIN32) && !defined(__MINGW32__) #include #elif defined HAVE_UNORDERED_MAP #include From de247ec94b26f08b15fff61a3fed070a7e06109c Mon Sep 17 00:00:00 2001 From: k1ll Date: Sat, 22 Jun 2013 11:48:52 +0200 Subject: [PATCH 1056/3725] Fix ifdef --- extern/sdl4ogre/sdlwindowhelper.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extern/sdl4ogre/sdlwindowhelper.cpp b/extern/sdl4ogre/sdlwindowhelper.cpp index 637fae0ef..6690e3cab 100644 --- a/extern/sdl4ogre/sdlwindowhelper.cpp +++ b/extern/sdl4ogre/sdlwindowhelper.cpp @@ -30,7 +30,7 @@ SDLWindowHelper::SDLWindowHelper (SDL_Window* window, int w, int h, switch (wmInfo.subsystem) { -#ifdef WIN32 +#ifdef _WIN32 case SDL_SYSWM_WINDOWS: // Windows code winHandle = Ogre::StringConverter::toString((uintptr_t)wmInfo.info.win.window); From c61919501dfb4416797c398a957bcf5259748ed5 Mon Sep 17 00:00:00 2001 From: k1ll Date: Sat, 22 Jun 2013 11:56:18 +0200 Subject: [PATCH 1057/3725] Fix unnecessary include, ssize_t define and use pretty function instead of funcsig for mingw --- extern/ogre-ffmpeg-videoplayer/audiodecoder.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extern/ogre-ffmpeg-videoplayer/audiodecoder.hpp b/extern/ogre-ffmpeg-videoplayer/audiodecoder.hpp index b05b16d42..fe36ec39f 100644 --- a/extern/ogre-ffmpeg-videoplayer/audiodecoder.hpp +++ b/extern/ogre-ffmpeg-videoplayer/audiodecoder.hpp @@ -21,8 +21,8 @@ extern "C" #endif } -#ifdef _WIN32 -#include +#if defined(_WIN32) && !defined(__MINGW32__) +#include typedef SSIZE_T ssize_t; #endif From b194af4ab27d35a167c69c9b8f6a6f481017b237 Mon Sep 17 00:00:00 2001 From: k1ll Date: Sat, 6 Jul 2013 13:32:59 +0200 Subject: [PATCH 1058/3725] Add static qt to components --- components/CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 5bd18d119..e6158c0a2 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -170,6 +170,10 @@ if (GIT_CHECKOUT) add_dependencies (components git-version) endif (GIT_CHECKOUT) +if(MINGW) +target_link_libraries(components ${QT_LIBRARIES}) +endif() + if (WIN32) target_link_libraries(components shlwapi) endif() From 8e094d6fa5ed03434c1fd7e86a1018dc8a895137 Mon Sep 17 00:00:00 2001 From: k1ll Date: Sat, 6 Jul 2013 17:18:11 +0200 Subject: [PATCH 1059/3725] Add static bullet to components --- components/CMakeLists.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index e6158c0a2..01de1c28e 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -127,6 +127,9 @@ set (ESM_UI ${CMAKE_SOURCE_DIR}/files/ui/contentselector.ui ) find_package(Qt4 COMPONENTS QtCore QtGui) +if(MINGW) +find_package(Bullet REQUIRED COMPONENTS Collision) +endif() if(QT_QTGUI_LIBRARY AND QT_QTCORE_LIBRARY) add_component_qt_dir (contentselector @@ -171,7 +174,7 @@ if (GIT_CHECKOUT) endif (GIT_CHECKOUT) if(MINGW) -target_link_libraries(components ${QT_LIBRARIES}) +target_link_libraries(components ${QT_LIBRARIES} ${BULLET_LIBRARIES}) endif() if (WIN32) From fe03727ae5fa6e598b151122ad5f3878e52b2e3c Mon Sep 17 00:00:00 2001 From: k1ll Date: Tue, 6 Aug 2013 18:55:17 +0200 Subject: [PATCH 1060/3725] Don't force linking static boost libraries when building with mingw --- CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 07fffd577..2c83e2662 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -134,9 +134,11 @@ endif() # Platform specific if (WIN32) + if(NOT MINGW) set(Boost_USE_STATIC_LIBS ON) set(PLATFORM_INCLUDE_DIR "platform") add_definitions(-DBOOST_ALL_NO_LIB) + endif(NOT MINGW) # Suppress WinMain(), provided by SDL add_definitions(-DSDL_MAIN_HANDLED) From 96d9afec384d16de4876c3e3b74a190afee28732 Mon Sep 17 00:00:00 2001 From: k1ll Date: Fri, 23 May 2014 23:26:05 +0200 Subject: [PATCH 1061/3725] More header case fixes --- apps/openmw/main.cpp | 2 +- extern/oics/tinyxml.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 070136dfd..2d2c9af0c 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -15,7 +15,7 @@ #if defined(_WIN32) // For OutputDebugString #define WIN32_LEAN_AND_MEAN -#include +#include // makes __argc and __argv available on windows #include #endif diff --git a/extern/oics/tinyxml.cpp b/extern/oics/tinyxml.cpp index 21b2d9c9a..5d8eb475a 100644 --- a/extern/oics/tinyxml.cpp +++ b/extern/oics/tinyxml.cpp @@ -32,7 +32,7 @@ distribution. #include "tinyxml.h" #ifdef _WIN32 -#include // import MultiByteToWideChar +#include // import MultiByteToWideChar #endif From 901ee5b756ab1d156e055ccf1f5d0624d240c53b Mon Sep 17 00:00:00 2001 From: k1ll Date: Fri, 23 May 2014 23:35:28 +0200 Subject: [PATCH 1062/3725] Add flag for mingw-w64 unicode support --- apps/mwiniimporter/CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/mwiniimporter/CMakeLists.txt b/apps/mwiniimporter/CMakeLists.txt index 790d47dc4..753c86fef 100644 --- a/apps/mwiniimporter/CMakeLists.txt +++ b/apps/mwiniimporter/CMakeLists.txt @@ -18,6 +18,10 @@ target_link_libraries(openmw-iniimporter components ) +if (MINGW) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -municode") +endif() + if (BUILD_WITH_CODE_COVERAGE) add_definitions (--coverage) target_link_libraries(openmw-iniimporter gcov) From 7b4a9f1ea1d8b8a43674bc914d99960ef5581356 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Thu, 30 Apr 2015 06:32:03 +1000 Subject: [PATCH 1063/3725] Moved script editor settings to its own section. --- apps/opencs/model/settings/usersettings.cpp | 16 ++++++++++++---- apps/opencs/view/world/scriptedit.cpp | 4 ++-- apps/opencs/view/world/scriptsubview.cpp | 13 ++++++++++--- apps/opencs/view/world/scriptsubview.hpp | 2 +- 4 files changed, 25 insertions(+), 10 deletions(-) diff --git a/apps/opencs/model/settings/usersettings.cpp b/apps/opencs/model/settings/usersettings.cpp index d9db95c71..9e00b7d1a 100644 --- a/apps/opencs/model/settings/usersettings.cpp +++ b/apps/opencs/model/settings/usersettings.cpp @@ -143,10 +143,6 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() minWidth->setDefaultValue (325); minWidth->setRange (50, 10000); minWidth->setToolTip ("Minimum width of subviews."); - - Setting *monoFont = createSetting (Type_CheckBox, "mono-font", "Use monospace font"); - monoFont->setDefaultValue ("true"); - monoFont->setToolTip ("Whether to use monospaced fonts on script edit subview."); } declareSection ("records", "Records"); @@ -230,6 +226,18 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() autoDelete->setDefaultValue ("true"); } + declareSection ("script-editor", "Script Editor"); + { + Setting *lineNum = createSetting (Type_CheckBox, "show-linenum", "Show Line Numbers"); + lineNum->setDefaultValue ("true"); + lineNum->setToolTip ("Show line numbers to the left of the script editor window." + "The current row and column numbers of the text cursor are shown at the bottom."); + + Setting *monoFont = createSetting (Type_CheckBox, "mono-font", "Use monospace font"); + monoFont->setDefaultValue ("true"); + monoFont->setToolTip ("Whether to use monospaced fonts on script edit subview."); + } + { /****************************************************************** * There are three types of values: diff --git a/apps/opencs/view/world/scriptedit.cpp b/apps/opencs/view/world/scriptedit.cpp index 9e0a7e95a..0909c00f9 100644 --- a/apps/opencs/view/world/scriptedit.cpp +++ b/apps/opencs/view/world/scriptedit.cpp @@ -80,7 +80,7 @@ CSVWorld::ScriptEdit::ScriptEdit (const CSMDoc::Document& document, ScriptHighli // TODO: provide a font selector dialogue std::string useMonoFont = - CSMSettings::UserSettings::instance().setting("window/mono-font", "true").toStdString(); + CSMSettings::UserSettings::instance().setting("script-editor/mono-font", "true").toStdString(); if (useMonoFont == "true") { QFont font("Monospace"); @@ -95,7 +95,7 @@ CSVWorld::ScriptEdit::ScriptEdit (const CSMDoc::Document& document, ScriptHighli connect(this, SIGNAL(updateRequest(QRect,int)), this, SLOT(updateLineNumberArea(QRect,int))); std::string showStatusBar = - CSMSettings::UserSettings::instance().settingValue("window/show-statusbar").toStdString(); + CSMSettings::UserSettings::instance().settingValue("script-editor/show-linenum").toStdString(); showLineNum(showStatusBar == "true"); } diff --git a/apps/opencs/view/world/scriptsubview.cpp b/apps/opencs/view/world/scriptsubview.cpp index 335cb97af..c7ddcd82a 100644 --- a/apps/opencs/view/world/scriptsubview.cpp +++ b/apps/opencs/view/world/scriptsubview.cpp @@ -12,6 +12,7 @@ #include "../../model/world/columnbase.hpp" #include "../../model/world/commands.hpp" #include "../../model/world/idtable.hpp" +#include "../../model/settings/usersettings.hpp" #include "scriptedit.hpp" @@ -65,10 +66,16 @@ CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc: connect(mEditor, SIGNAL(cursorPositionChanged()), this, SLOT(updateStatusBar())); } -void CSVWorld::ScriptSubView::setStatusBar (bool show) +void CSVWorld::ScriptSubView::updateUserSetting (const QString& name, const QStringList& value) { - mEditor->showLineNum(show); - mBottom->setVisible(show); + if (name != "script-editor/show-linenum") + return; + + std::string showLinenum = + CSMSettings::UserSettings::instance().settingValue("script-editor/show-linenum").toStdString(); + + mEditor->showLineNum(showLinenum == "true"); + mBottom->setVisible(showLinenum == "true"); } void CSVWorld::ScriptSubView::updateStatusBar () diff --git a/apps/opencs/view/world/scriptsubview.hpp b/apps/opencs/view/world/scriptsubview.hpp index 5d85891cf..1c6474e54 100644 --- a/apps/opencs/view/world/scriptsubview.hpp +++ b/apps/opencs/view/world/scriptsubview.hpp @@ -39,7 +39,7 @@ namespace CSVWorld virtual void useHint (const std::string& hint); - virtual void setStatusBar (bool show); + virtual void updateUserSetting (const QString& name, const QStringList& value); public slots: From 83c6ba97c01a9a335ecde520db3f830cee0c1023 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 29 Apr 2015 23:48:08 +0200 Subject: [PATCH 1064/3725] Disable skinning updates for actors beyond the AI processing distance --- apps/openmw/mwmechanics/actors.cpp | 9 ++++++--- apps/openmw/mwmechanics/character.cpp | 5 +++++ apps/openmw/mwmechanics/character.hpp | 3 +++ apps/openmw/mwrender/animation.cpp | 8 ++++++++ apps/openmw/mwrender/animation.hpp | 4 ++++ components/sceneutil/riggeometry.cpp | 12 ++++++++++++ components/sceneutil/riggeometry.hpp | 3 +++ components/sceneutil/skeleton.cpp | 14 ++++++++++++-- components/sceneutil/skeleton.hpp | 8 ++++++++ 9 files changed, 61 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index bb59d46c0..3333511d3 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1085,12 +1085,15 @@ namespace MWMechanics // AI and magic effects update for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter) { + bool inProcessingRange = Ogre::Vector3(player.getRefData().getPosition().pos).squaredDistance(Ogre::Vector3(iter->first.getRefData().getPosition().pos)) + <= sqrProcessingDistance; + + iter->second->getCharacterController()->setActive(inProcessingRange); + if (!iter->first.getClass().getCreatureStats(iter->first).isDead()) { updateActor(iter->first, duration); - if (MWBase::Environment::get().getMechanicsManager()->isAIActive() && - Ogre::Vector3(player.getRefData().getPosition().pos).squaredDistance(Ogre::Vector3(iter->first.getRefData().getPosition().pos)) - <= sqrProcessingDistance) + if (MWBase::Environment::get().getMechanicsManager()->isAIActive() && inProcessingRange) { if (timerUpdateAITargets == 0) { diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 98a420ba6..adcfb57a4 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1898,6 +1898,11 @@ bool CharacterController::isKnockedOut() const return mHitState == CharState_KnockOut; } +void CharacterController::setActive(bool active) +{ + mAnimation->setActive(active); +} + void CharacterController::setHeadTrackTarget(const MWWorld::Ptr &target) { mHeadTrackTarget = target; diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index da74b2a33..987a0d29a 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -228,6 +228,9 @@ public: bool isReadyToBlock() const; bool isKnockedOut() const; + /// @see Animation::setActive + void setActive(bool active); + /// Make this character turn its head towards \a target. To turn off head tracking, pass an empty Ptr. void setHeadTrackTarget(const MWWorld::Ptr& target); }; diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index c5479e3f7..245095492 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -214,6 +214,14 @@ namespace MWRender mInsert->removeChild(mObjectRoot); } + void Animation::setActive(bool active) + { + if (SceneUtil::Skeleton* skel = dynamic_cast(mObjectRoot.get())) + { + skel->setActive(active); + } + } + void Animation::updatePtr(const MWWorld::Ptr &ptr) { mPtr = ptr; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 9aa15520f..c85f87403 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -242,6 +242,10 @@ public: Animation(const MWWorld::Ptr &ptr, osg::ref_ptr parentNode, Resource::ResourceSystem* resourceSystem); virtual ~Animation(); + /// Set active flag on the object skeleton, if one exists. + /// @see SceneUtil::Skeleton::setActive + void setActive(bool active); + osg::Group* getOrCreateObjectRoot(); osg::Group* getObjectRoot(); diff --git a/components/sceneutil/riggeometry.cpp b/components/sceneutil/riggeometry.cpp index 19e5b0ae6..7f30aff74 100644 --- a/components/sceneutil/riggeometry.cpp +++ b/components/sceneutil/riggeometry.cpp @@ -58,6 +58,8 @@ public: }; RigGeometry::RigGeometry() + : mFirstFrame(true) + , mBoundsFirstFrame(true) { setCullCallback(new UpdateRigGeometry); setUpdateCallback(new UpdateRigBounds); @@ -67,6 +69,8 @@ RigGeometry::RigGeometry() RigGeometry::RigGeometry(const RigGeometry ©, const osg::CopyOp ©op) : osg::Geometry(copy, copyop) , mInfluenceMap(copy.mInfluenceMap) + , mFirstFrame(copy.mFirstFrame) + , mBoundsFirstFrame(copy.mBoundsFirstFrame) { setSourceGeometry(copy.mSourceGeometry); } @@ -199,6 +203,10 @@ void RigGeometry::update(osg::NodeVisitor* nv) return; } + if (!mSkeleton->getActive() && !mFirstFrame) + return; + mFirstFrame = false; + mSkeleton->updateBoneMatrices(nv); osg::Matrixf geomToSkel = getGeomToSkelMatrix(nv); @@ -247,6 +255,10 @@ void RigGeometry::updateBounds(osg::NodeVisitor *nv) return; } + if (!mSkeleton->getActive() && !mBoundsFirstFrame) + return; + mBoundsFirstFrame = false; + mSkeleton->updateBoneMatrices(nv); osg::Matrixf geomToSkel = getGeomToSkelMatrix(nv); diff --git a/components/sceneutil/riggeometry.hpp b/components/sceneutil/riggeometry.hpp index e82f6254a..ea4245aa8 100644 --- a/components/sceneutil/riggeometry.hpp +++ b/components/sceneutil/riggeometry.hpp @@ -64,6 +64,9 @@ namespace SceneUtil BoneSphereMap mBoneSphereMap; + bool mFirstFrame; + bool mBoundsFirstFrame; + bool initFromParentSkeleton(osg::NodeVisitor* nv); osg::Matrixf getGeomToSkelMatrix(osg::NodeVisitor* nv); diff --git a/components/sceneutil/skeleton.cpp b/components/sceneutil/skeleton.cpp index c1ab36136..f105977ba 100644 --- a/components/sceneutil/skeleton.cpp +++ b/components/sceneutil/skeleton.cpp @@ -35,6 +35,7 @@ Skeleton::Skeleton() : mBoneCacheInit(false) , mNeedToUpdateBoneMatrices(true) , mLastFrameNumber(0) + , mActive(true) { } @@ -44,12 +45,11 @@ Skeleton::Skeleton(const Skeleton ©, const osg::CopyOp ©op) , mBoneCacheInit(false) , mNeedToUpdateBoneMatrices(true) , mLastFrameNumber(0) + , mActive(copy.mActive) { } - - Bone* Skeleton::getBone(const std::string &name) { if (!mBoneCacheInit) @@ -123,6 +123,16 @@ void Skeleton::updateBoneMatrices(osg::NodeVisitor* nv) } } +void Skeleton::setActive(bool active) +{ + mActive = active; +} + +bool Skeleton::getActive() const +{ + return mActive; +} + Bone::Bone() : mNode(NULL) { diff --git a/components/sceneutil/skeleton.hpp b/components/sceneutil/skeleton.hpp index d710ac61b..1987fd4e8 100644 --- a/components/sceneutil/skeleton.hpp +++ b/components/sceneutil/skeleton.hpp @@ -47,6 +47,12 @@ namespace SceneUtil /// Request an update of bone matrices. May be a no-op if already updated in this frame. void updateBoneMatrices(osg::NodeVisitor* nv); + /// Set the skinning active flag. Inactive skeletons will not have their child rigs updated. + /// You should set this flag to false if you know that bones are not currently moving. + void setActive(bool active); + + bool getActive() const; + private: // The root bone is not a "real" bone, it has no corresponding node in the scene graph. // As far as the scene graph goes we support multiple root bones. @@ -58,6 +64,8 @@ namespace SceneUtil bool mNeedToUpdateBoneMatrices; + bool mActive; + unsigned int mLastFrameNumber; }; From a98dc78cc568ee9fd984bc0f113de441a2615497 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 30 Apr 2015 15:46:16 +0200 Subject: [PATCH 1065/3725] Bounds fix --- components/sceneutil/riggeometry.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/components/sceneutil/riggeometry.cpp b/components/sceneutil/riggeometry.cpp index 7f30aff74..df5f65029 100644 --- a/components/sceneutil/riggeometry.cpp +++ b/components/sceneutil/riggeometry.cpp @@ -271,7 +271,9 @@ void RigGeometry::updateBounds(osg::NodeVisitor *nv) box.expandBy(bs); } - setInitialBound(box); + _boundingBox = box; + for (unsigned int i=0; idirtyBound(); } osg::Matrixf RigGeometry::getGeomToSkelMatrix(osg::NodeVisitor *nv) From 081f3ed263f5077be9e2853d6e5f1b2ec9e468aa Mon Sep 17 00:00:00 2001 From: cc9cii Date: Fri, 1 May 2015 06:08:04 +1000 Subject: [PATCH 1066/3725] Make font setting selection immediate. --- apps/opencs/view/world/scriptedit.cpp | 19 +++++++++++++------ apps/opencs/view/world/scriptedit.hpp | 3 +++ apps/opencs/view/world/scriptsubview.cpp | 18 ++++++++++-------- 3 files changed, 26 insertions(+), 14 deletions(-) diff --git a/apps/opencs/view/world/scriptedit.cpp b/apps/opencs/view/world/scriptedit.cpp index 0909c00f9..b4f4234f1 100644 --- a/apps/opencs/view/world/scriptedit.cpp +++ b/apps/opencs/view/world/scriptedit.cpp @@ -33,7 +33,9 @@ CSVWorld::ScriptEdit::ScriptEdit (const CSMDoc::Document& document, ScriptHighli mWhiteListQoutes("^[a-z|_]{1}[a-z|0-9|_]{0,}$", Qt::CaseInsensitive), mChangeLocked (0), mLineNumberArea(0), - mShowLineNum(false) + mShowLineNum(false), + mDefaultFont(font()), + mMonoFont(QFont("Monospace")) { // setAcceptRichText (false); setLineWrapMode (QPlainTextEdit::NoWrap); @@ -79,14 +81,11 @@ CSVWorld::ScriptEdit::ScriptEdit (const CSMDoc::Document& document, ScriptHighli mUpdateTimer.setSingleShot (true); // TODO: provide a font selector dialogue + mMonoFont.setStyleHint(QFont::TypeWriter); std::string useMonoFont = CSMSettings::UserSettings::instance().setting("script-editor/mono-font", "true").toStdString(); if (useMonoFont == "true") - { - QFont font("Monospace"); - font.setStyleHint(QFont::TypeWriter); - setFont(font); - } + setFont(mMonoFont); mLineNumberArea = new LineNumberArea(this); updateLineNumberAreaWidth(0); @@ -109,6 +108,14 @@ void CSVWorld::ScriptEdit::showLineNum(bool show) } } +void CSVWorld::ScriptEdit::setMonoFont(bool show) +{ + if(show) + setFont(mMonoFont); + else + setFont(mDefaultFont); +} + bool CSVWorld::ScriptEdit::isChangeLocked() const { return mChangeLocked!=0; diff --git a/apps/opencs/view/world/scriptedit.hpp b/apps/opencs/view/world/scriptedit.hpp index 3355d40c1..a19cee486 100644 --- a/apps/opencs/view/world/scriptedit.hpp +++ b/apps/opencs/view/world/scriptedit.hpp @@ -50,6 +50,8 @@ namespace CSVWorld QTimer mUpdateTimer; bool mShowLineNum; LineNumberArea *mLineNumberArea; + QFont mDefaultFont; + QFont mMonoFont; public: @@ -64,6 +66,7 @@ namespace CSVWorld void lineNumberAreaPaintEvent(QPaintEvent *event); int lineNumberAreaWidth(); void showLineNum(bool show); + void setMonoFont(bool show); protected: diff --git a/apps/opencs/view/world/scriptsubview.cpp b/apps/opencs/view/world/scriptsubview.cpp index c7ddcd82a..411eb3660 100644 --- a/apps/opencs/view/world/scriptsubview.cpp +++ b/apps/opencs/view/world/scriptsubview.cpp @@ -68,14 +68,16 @@ CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc: void CSVWorld::ScriptSubView::updateUserSetting (const QString& name, const QStringList& value) { - if (name != "script-editor/show-linenum") - return; - - std::string showLinenum = - CSMSettings::UserSettings::instance().settingValue("script-editor/show-linenum").toStdString(); - - mEditor->showLineNum(showLinenum == "true"); - mBottom->setVisible(showLinenum == "true"); + if (name == "script-editor/show-linenum") + { + std::string showLinenum = value.at(0).toStdString(); + mEditor->showLineNum(showLinenum == "true"); + mBottom->setVisible(showLinenum == "true"); + } + else if (name == "script-editor/mono-font") + { + mEditor->setMonoFont(value.at(0).toStdString() == "true"); + } } void CSVWorld::ScriptSubView::updateStatusBar () From 15bdb7db01b58bea6ad20048eb45838c107b71b8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 30 Apr 2015 17:17:13 +0200 Subject: [PATCH 1067/3725] transformBoundingSphere optimization --- components/sceneutil/util.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/components/sceneutil/util.cpp b/components/sceneutil/util.cpp index a41c6b74b..52f9c9e54 100644 --- a/components/sceneutil/util.cpp +++ b/components/sceneutil/util.cpp @@ -20,17 +20,18 @@ void transformBoundingSphere (const osg::Matrix& matrix, osg::BoundingSphere& bs bsphere._center = bsphere._center*matrix; xdash -= bsphere._center; - osg::BoundingSphere::value_type len_xdash = xdash.length(); + osg::BoundingSphere::value_type sqrlen_xdash = xdash.length2(); ydash -= bsphere._center; - osg::BoundingSphere::value_type len_ydash = ydash.length(); + osg::BoundingSphere::value_type sqrlen_ydash = ydash.length2(); zdash -= bsphere._center; - osg::BoundingSphere::value_type len_zdash = zdash.length(); + osg::BoundingSphere::value_type sqrlen_zdash = zdash.length2(); - bsphere._radius = len_xdash; - if (bsphere._radius Date: Thu, 30 Apr 2015 23:17:06 +0200 Subject: [PATCH 1068/3725] Uninitialized basenode fix --- apps/openmw/mwworld/refdata.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwworld/refdata.cpp b/apps/openmw/mwworld/refdata.cpp index 7e83fda5e..82bb06b8d 100644 --- a/apps/openmw/mwworld/refdata.cpp +++ b/apps/openmw/mwworld/refdata.cpp @@ -37,7 +37,7 @@ namespace MWWorld } RefData::RefData() - : mBaseNode(0), mHasLocals (false), mEnabled (true), mCount (1), mCustomData (0), mChanged(false), mDeleted(false) + : mBaseNode(0), mBase(0), mHasLocals (false), mEnabled (true), mCount (1), mCustomData (0), mChanged(false), mDeleted(false) { for (int i=0; i<3; ++i) { @@ -48,7 +48,7 @@ namespace MWWorld } RefData::RefData (const ESM::CellRef& cellRef) - : mBaseNode(0), mHasLocals (false), mEnabled (true), mCount (1), mPosition (cellRef.mPos), + : mBaseNode(0), mBase(0), mHasLocals (false), mEnabled (true), mCount (1), mPosition (cellRef.mPos), mCustomData (0), mChanged(false), // Loading from ESM/ESP files -> assume unchanged mDeleted(false) @@ -59,7 +59,7 @@ namespace MWWorld } RefData::RefData (const ESM::ObjectState& objectState) - : mBaseNode (0), mHasLocals (false), mEnabled (objectState.mEnabled != 0), + : mBaseNode (0), mBase(0), mHasLocals (false), mEnabled (objectState.mEnabled != 0), mCount (objectState.mCount), mPosition (objectState.mPosition), mCustomData (0), mChanged(true), // Loading from a savegame -> assume changed mDeleted(false) @@ -69,7 +69,7 @@ namespace MWWorld } RefData::RefData (const RefData& refData) - : mBaseNode(0), mCustomData (0) + : mBaseNode(0), mBase(0), mCustomData (0) { try { From 62847f0489d4adf099bef35dbd8c9a4f78e969b7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 30 Apr 2015 23:21:25 +0200 Subject: [PATCH 1069/3725] Use node masks to separate Scene and GUI --- apps/openmw/engine.cpp | 3 +++ apps/openmw/mwgui/myguirendermanager.cpp | 2 +- apps/openmw/mwrender/renderingmanager.cpp | 9 +++++++-- apps/openmw/mwrender/sky.cpp | 6 +++++- apps/openmw/mwrender/vismask.hpp | 7 ++++++- 5 files changed, 22 insertions(+), 5 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 582172bff..e2e09bdec 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -41,6 +41,8 @@ #include "mwworld/player.hpp" #include "mwworld/worldimp.hpp" +#include "mwrender/vismask.hpp" + #include "mwclass/classes.hpp" #include "mwdialogue/dialoguemanagerimp.hpp" @@ -339,6 +341,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) std::string myguiResources = (mResDir / "mygui").string(); osg::ref_ptr guiRoot = new osg::Group; + guiRoot->setNodeMask(MWRender::Mask_GUI); rootNode->addChild(guiRoot); MWGui::WindowManager* window = new MWGui::WindowManager(mViewer, guiRoot, mResourceSystem->getTextureManager(), mCfgMgr.getLogPath().string() + std::string("/"), myguiResources, diff --git a/apps/openmw/mwgui/myguirendermanager.cpp b/apps/openmw/mwgui/myguirendermanager.cpp index 06e404d88..f218d9ff0 100644 --- a/apps/openmw/mwgui/myguirendermanager.cpp +++ b/apps/openmw/mwgui/myguirendermanager.cpp @@ -466,7 +466,7 @@ void RenderManager::initialise() camera->addChild(geode.get()); mGuiRoot = camera; - //mSceneRoot->addChild(mGuiRoot.get()); + mSceneRoot->addChild(mGuiRoot.get()); mViewer->addEventHandler(new ResizeHandler(this)); osg::ref_ptr vp = mViewer->getCamera()->getViewport(); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index d68620f8a..8689935d0 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -23,6 +23,7 @@ #include "sky.hpp" #include "effectmanager.hpp" +#include "vismask.hpp" namespace MWRender { @@ -87,8 +88,6 @@ namespace MWRender mObjects.reset(new Objects(mResourceSystem, lightRoot)); - mSky.reset(new SkyManager(mRootNode, resourceSystem->getSceneManager())); - mEffectManager.reset(new EffectManager(mRootNode, mResourceSystem)); mViewer.setLightingMode(osgViewer::View::NO_LIGHT); @@ -105,6 +104,10 @@ namespace MWRender lightRoot->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::ON); lightRoot->getOrCreateStateSet()->setMode(GL_NORMALIZE, osg::StateAttribute::ON); + lightRoot->setNodeMask(Mask_Scene); + + mSky.reset(new SkyManager(lightRoot, resourceSystem->getSceneManager())); + source->setStateSetModes(*mRootNode->getOrCreateStateSet(), osg::StateAttribute::ON); mStateUpdater = new StateUpdater; @@ -128,6 +131,8 @@ namespace MWRender zNear = 5.f; zFar = mViewDistance; mViewer.getCamera()->setProjectionMatrixAsPerspective(fovy, aspect, zNear, zFar); + + mViewer.getCamera()->setCullMask(mViewer.getCamera()->getCullMask() & (~Mask_GUI)); } RenderingManager::~RenderingManager() diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 97055ecae..4fd5b7e63 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -554,7 +554,6 @@ void SkyManager::create() depth->setWriteMask(false); mRootNode->getOrCreateStateSet()->setAttributeAndModes(depth, osg::StateAttribute::ON); mRootNode->getOrCreateStateSet()->setMode(GL_BLEND, osg::StateAttribute::ON); - mRootNode->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::ON); mCreated = true; } @@ -562,6 +561,11 @@ void SkyManager::create() SkyManager::~SkyManager() { clearRain(); + if (mRootNode) + { + mRootNode->getParent(0)->removeChild(mRootNode); + mRootNode = NULL; + } } int SkyManager::getMasserPhase() const diff --git a/apps/openmw/mwrender/vismask.hpp b/apps/openmw/mwrender/vismask.hpp index 4a064b60f..48845c78c 100644 --- a/apps/openmw/mwrender/vismask.hpp +++ b/apps/openmw/mwrender/vismask.hpp @@ -9,7 +9,12 @@ namespace MWRender { Mask_UpdateVisitor = 0x1, // reserved for separating UpdateVisitors from CullVisitors - Mask_Effect = 0x2 + // child of Scene + Mask_Effect = 0x2, + + // top level masks + Mask_Scene = 0x10, + Mask_GUI = 0x20 }; } From db7fe1952dcf8033628b7a4bca7f9430a9590d50 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 1 May 2015 00:59:41 +0200 Subject: [PATCH 1070/3725] Move MyGUI texture to a separate file --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwgui/myguirendermanager.cpp | 182 +---------------------- apps/openmw/mwgui/myguitexture.cpp | 164 ++++++++++++++++++++ apps/openmw/mwgui/myguitexture.hpp | 64 ++++++++ 4 files changed, 231 insertions(+), 181 deletions(-) create mode 100644 apps/openmw/mwgui/myguitexture.cpp create mode 100644 apps/openmw/mwgui/myguitexture.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index a36dd4e2a..680ea9c86 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -44,7 +44,7 @@ add_openmw_dir (mwgui itemmodel containeritemmodel inventoryitemmodel sortfilteritemmodel itemview tradeitemmodel companionitemmodel pickpocketitemmodel controllers savegamedialog recharge mode videowidget backgroundimage itemwidget screenfader debugwindow spellmodel spellview - draganddrop timeadvancer jailscreen myguiplatform myguirendermanager myguidatamanager + draganddrop timeadvancer jailscreen myguiplatform myguirendermanager myguidatamanager myguitexture ) add_openmw_dir (mwdialogue diff --git a/apps/openmw/mwgui/myguirendermanager.cpp b/apps/openmw/mwgui/myguirendermanager.cpp index f218d9ff0..e5160bb5b 100644 --- a/apps/openmw/mwgui/myguirendermanager.cpp +++ b/apps/openmw/mwgui/myguirendermanager.cpp @@ -19,6 +19,8 @@ #include +#include "myguitexture.hpp" + #define MYGUI_PLATFORM_LOG_SECTION "Platform" #define MYGUI_PLATFORM_LOG(level, text) MYGUI_LOGGING(MYGUI_PLATFORM_LOG_SECTION, level, text) @@ -217,186 +219,6 @@ void OSGVertexBuffer::create() // --------------------------------------------------------------------------- -class OSGTexture : public MyGUI::ITexture { - std::string mName; - Resource::TextureManager* mTextureManager; - - osg::ref_ptr mLockedImage; - osg::ref_ptr mTexture; - MyGUI::PixelFormat mFormat; - MyGUI::TextureUsage mUsage; - size_t mNumElemBytes; - -public: - OSGTexture(const std::string &name, Resource::TextureManager* textureManager); - virtual ~OSGTexture(); - - virtual const std::string& getName() const { return mName; } - - virtual void createManual(int width, int height, MyGUI::TextureUsage usage, MyGUI::PixelFormat format); - virtual void loadFromFile(const std::string &fname); - virtual void saveToFile(const std::string &fname); - - virtual void destroy(); - - virtual void* lock(MyGUI::TextureUsage access); - virtual void unlock(); - virtual bool isLocked(); - - virtual int getWidth(); - virtual int getHeight(); - - virtual MyGUI::PixelFormat getFormat() { return mFormat; } - virtual MyGUI::TextureUsage getUsage() { return mUsage; } - virtual size_t getNumElemBytes() { return mNumElemBytes; } - - virtual MyGUI::IRenderTarget *getRenderTarget(); - -/*internal:*/ - osg::Texture2D *getTexture() const { return mTexture.get(); } -}; - -OSGTexture::OSGTexture(const std::string &name, Resource::TextureManager* textureManager) - : mName(name) - , mTextureManager(textureManager) - , mFormat(MyGUI::PixelFormat::Unknow) - , mUsage(MyGUI::TextureUsage::Default) - , mNumElemBytes(0) -{ -} - -OSGTexture::~OSGTexture() -{ -} - -void OSGTexture::createManual(int width, int height, MyGUI::TextureUsage usage, MyGUI::PixelFormat format) -{ - GLenum glfmt = GL_NONE; - size_t numelems = 0; - switch(format.getValue()) - { - case MyGUI::PixelFormat::L8: - glfmt = GL_LUMINANCE; - numelems = 1; - break; - case MyGUI::PixelFormat::L8A8: - glfmt = GL_LUMINANCE_ALPHA; - numelems = 2; - break; - case MyGUI::PixelFormat::R8G8B8: - glfmt = GL_RGB; - numelems = 3; - break; - case MyGUI::PixelFormat::R8G8B8A8: - glfmt = GL_RGBA; - numelems = 4; - break; - } - if(glfmt == GL_NONE) - throw std::runtime_error("Texture format not supported"); - - mTexture = new osg::Texture2D(); - mTexture->setTextureSize(width, height); - mTexture->setSourceFormat(glfmt); - mTexture->setSourceType(GL_UNSIGNED_BYTE); - - mTexture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR); - mTexture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); - mTexture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); - mTexture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); - - mFormat = format; - mUsage = usage; - mNumElemBytes = numelems; -} - -void OSGTexture::destroy() -{ - mTexture = nullptr; - mFormat = MyGUI::PixelFormat::Unknow; - mUsage = MyGUI::TextureUsage::Default; - mNumElemBytes = 0; -} - -void OSGTexture::loadFromFile(const std::string &fname) -{ - mTexture = mTextureManager->getTexture2D(fname, osg::Texture2D::CLAMP, osg::Texture2D::CLAMP); - - // FIXME - mFormat = MyGUI::PixelFormat::R8G8B8; - mUsage = MyGUI::TextureUsage::Static | MyGUI::TextureUsage::Write; - mNumElemBytes = 3; // FIXME -} - -void OSGTexture::saveToFile(const std::string &fname) -{ - std::cerr << "Would save image to file " << fname << std::endl; -} - - -int OSGTexture::getWidth() -{ - if(!mTexture.valid()) - return 0; - osg::Image *image = mTexture->getImage(); - if(image) return image->s(); - return mTexture->getTextureWidth(); -} - -int OSGTexture::getHeight() -{ - if(!mTexture.valid()) - return 0; - osg::Image *image = mTexture->getImage(); - if(image) return image->t(); - return mTexture->getTextureHeight(); -} - - -void *OSGTexture::lock(MyGUI::TextureUsage /*access*/) -{ - MYGUI_PLATFORM_ASSERT(mTexture.valid(), "Texture is not created"); - MYGUI_PLATFORM_ASSERT(!mLockedImage.valid(), "Texture already locked"); - - mLockedImage = mTexture->getImage(); - if(!mLockedImage.valid()) - { - mLockedImage = new osg::Image(); - mLockedImage->allocateImage( - mTexture->getTextureWidth(), mTexture->getTextureHeight(), mTexture->getTextureDepth(), - mTexture->getSourceFormat(), mTexture->getSourceType() - ); - } - return mLockedImage->data(); -} - -void OSGTexture::unlock() -{ - MYGUI_PLATFORM_ASSERT(mLockedImage.valid(), "Texture not locked"); - - // Tell the texture it can get rid of the image for static textures (since - // they aren't expected to update much at all). - mTexture->setImage(mLockedImage.get()); - mTexture->setUnRefImageDataAfterApply(mUsage.isValue(MyGUI::TextureUsage::Static) ? true : false); - mTexture->dirtyTextureObject(); - - mLockedImage = nullptr; -} - -bool OSGTexture::isLocked() -{ - return mLockedImage.valid(); -} - - -// FIXME: Render-to-texture not currently implemented. -MyGUI::IRenderTarget* OSGTexture::getRenderTarget() -{ - return nullptr; -} - -// --------------------------------------------------------------------------- - RenderManager::RenderManager(osgViewer::Viewer *viewer, osg::Group *sceneroot, Resource::TextureManager* textureManager) : mViewer(viewer) , mSceneRoot(sceneroot) diff --git a/apps/openmw/mwgui/myguitexture.cpp b/apps/openmw/mwgui/myguitexture.cpp new file mode 100644 index 000000000..d61e396f1 --- /dev/null +++ b/apps/openmw/mwgui/myguitexture.cpp @@ -0,0 +1,164 @@ +#include "myguitexture.hpp" + +#include +#include + +#include + +#include + +namespace MWGui +{ + + OSGTexture::OSGTexture(const std::string &name, Resource::TextureManager* textureManager) + : mName(name) + , mTextureManager(textureManager) + , mFormat(MyGUI::PixelFormat::Unknow) + , mUsage(MyGUI::TextureUsage::Default) + , mNumElemBytes(0) + { + } + + OSGTexture::OSGTexture(osg::Texture2D *texture) + : mTextureManager(NULL) + , mTexture(texture) + , mFormat(MyGUI::PixelFormat::Unknow) + , mUsage(MyGUI::TextureUsage::Default) + , mNumElemBytes(0) + { + } + + OSGTexture::~OSGTexture() + { + } + + void OSGTexture::createManual(int width, int height, MyGUI::TextureUsage usage, MyGUI::PixelFormat format) + { + GLenum glfmt = GL_NONE; + size_t numelems = 0; + switch(format.getValue()) + { + case MyGUI::PixelFormat::L8: + glfmt = GL_LUMINANCE; + numelems = 1; + break; + case MyGUI::PixelFormat::L8A8: + glfmt = GL_LUMINANCE_ALPHA; + numelems = 2; + break; + case MyGUI::PixelFormat::R8G8B8: + glfmt = GL_RGB; + numelems = 3; + break; + case MyGUI::PixelFormat::R8G8B8A8: + glfmt = GL_RGBA; + numelems = 4; + break; + } + if(glfmt == GL_NONE) + throw std::runtime_error("Texture format not supported"); + + mTexture = new osg::Texture2D(); + mTexture->setTextureSize(width, height); + mTexture->setSourceFormat(glfmt); + mTexture->setSourceType(GL_UNSIGNED_BYTE); + + mTexture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR); + mTexture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); + mTexture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); + mTexture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); + + mFormat = format; + mUsage = usage; + mNumElemBytes = numelems; + } + + void OSGTexture::destroy() + { + mTexture = nullptr; + mFormat = MyGUI::PixelFormat::Unknow; + mUsage = MyGUI::TextureUsage::Default; + mNumElemBytes = 0; + } + + void OSGTexture::loadFromFile(const std::string &fname) + { + if (!mTextureManager) + throw std::runtime_error("No texturemanager set"); + + mTexture = mTextureManager->getTexture2D(fname, osg::Texture2D::CLAMP, osg::Texture2D::CLAMP); + + // FIXME + mFormat = MyGUI::PixelFormat::R8G8B8; + mUsage = MyGUI::TextureUsage::Static | MyGUI::TextureUsage::Write; + mNumElemBytes = 3; // FIXME + } + + void OSGTexture::saveToFile(const std::string &fname) + { + std::cerr << "Would save image to file " << fname << std::endl; + } + + int OSGTexture::getWidth() + { + if(!mTexture.valid()) + return 0; + osg::Image *image = mTexture->getImage(); + if(image) return image->s(); + return mTexture->getTextureWidth(); + } + + int OSGTexture::getHeight() + { + if(!mTexture.valid()) + return 0; + osg::Image *image = mTexture->getImage(); + if(image) return image->t(); + return mTexture->getTextureHeight(); + } + + void *OSGTexture::lock(MyGUI::TextureUsage /*access*/) + { + if (!mTexture.valid()) + throw std::runtime_error("Texture is not created"); + if (mLockedImage.valid()) + throw std::runtime_error("Texture already locked"); + + mLockedImage = mTexture->getImage(); + if(!mLockedImage.valid()) + { + mLockedImage = new osg::Image(); + mLockedImage->allocateImage( + mTexture->getTextureWidth(), mTexture->getTextureHeight(), mTexture->getTextureDepth(), + mTexture->getSourceFormat(), mTexture->getSourceType() + ); + } + return mLockedImage->data(); + } + + void OSGTexture::unlock() + { + if (!mLockedImage.valid()) + throw std::runtime_error("Texture not locked"); + + // Tell the texture it can get rid of the image for static textures (since + // they aren't expected to update much at all). + mTexture->setImage(mLockedImage.get()); + mTexture->setUnRefImageDataAfterApply(mUsage.isValue(MyGUI::TextureUsage::Static) ? true : false); + mTexture->dirtyTextureObject(); + + mLockedImage = nullptr; + } + + bool OSGTexture::isLocked() + { + return mLockedImage.valid(); + } + + // Render-to-texture not currently implemented. + MyGUI::IRenderTarget* OSGTexture::getRenderTarget() + { + return nullptr; + } + +} diff --git a/apps/openmw/mwgui/myguitexture.hpp b/apps/openmw/mwgui/myguitexture.hpp new file mode 100644 index 000000000..5ae34a3d6 --- /dev/null +++ b/apps/openmw/mwgui/myguitexture.hpp @@ -0,0 +1,64 @@ +#ifndef OPENMW_MWGUI_MYGUITEXTURE_H +#define OPENMW_MWGUI_MYGUITEXTURE_H + +#include + +#include + +namespace osg +{ + class Image; + class Texture2D; +} + +namespace Resource +{ + class TextureManager; +} + +namespace MWGui +{ + + class OSGTexture : public MyGUI::ITexture { + std::string mName; + Resource::TextureManager* mTextureManager; + + osg::ref_ptr mLockedImage; + osg::ref_ptr mTexture; + MyGUI::PixelFormat mFormat; + MyGUI::TextureUsage mUsage; + size_t mNumElemBytes; + + public: + OSGTexture(const std::string &name, Resource::TextureManager* textureManager); + OSGTexture(osg::Texture2D* texture); + virtual ~OSGTexture(); + + virtual const std::string& getName() const { return mName; } + + virtual void createManual(int width, int height, MyGUI::TextureUsage usage, MyGUI::PixelFormat format); + virtual void loadFromFile(const std::string &fname); + virtual void saveToFile(const std::string &fname); + + virtual void destroy(); + + virtual void* lock(MyGUI::TextureUsage access); + virtual void unlock(); + virtual bool isLocked(); + + virtual int getWidth(); + virtual int getHeight(); + + virtual MyGUI::PixelFormat getFormat() { return mFormat; } + virtual MyGUI::TextureUsage getUsage() { return mUsage; } + virtual size_t getNumElemBytes() { return mNumElemBytes; } + + virtual MyGUI::IRenderTarget *getRenderTarget(); + + /*internal:*/ + osg::Texture2D *getTexture() const { return mTexture.get(); } + }; + +} + +#endif From a59940a2c734858332fba99ed8ba94366d23406d Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 1 May 2015 01:15:25 +0200 Subject: [PATCH 1071/3725] Move MyGUI platform to components --- apps/openmw/CMakeLists.txt | 6 +---- apps/openmw/engine.cpp | 2 +- apps/openmw/mwgui/windowmanagerimp.cpp | 10 ++++--- apps/openmw/mwgui/windowmanagerimp.hpp | 27 ++++++------------- apps/openmw/mwsound/soundmanagerimp.cpp | 2 ++ apps/openmw/mwworld/scene.hpp | 7 ----- apps/openmw/mwworld/worldimp.hpp | 6 ----- components/CMakeLists.txt | 8 ++++++ .../myguiplatform}/myguidatamanager.cpp | 2 +- .../myguiplatform}/myguidatamanager.hpp | 6 ++--- .../myguiplatform}/myguiplatform.cpp | 0 .../myguiplatform}/myguiplatform.hpp | 6 ++--- .../myguiplatform}/myguirendermanager.cpp | 14 +++++----- .../myguiplatform}/myguirendermanager.hpp | 6 ++--- .../myguiplatform}/myguitexture.cpp | 2 +- .../myguiplatform}/myguitexture.hpp | 6 ++--- components/widgets/imagebutton.hpp | 4 +-- components/widgets/list.hpp | 4 +-- 18 files changed, 51 insertions(+), 67 deletions(-) rename {apps/openmw/mwgui => components/myguiplatform}/myguidatamanager.cpp (98%) rename {apps/openmw/mwgui => components/myguiplatform}/myguidatamanager.hpp (89%) rename {apps/openmw/mwgui => components/myguiplatform}/myguiplatform.cpp (100%) rename {apps/openmw/mwgui => components/myguiplatform}/myguiplatform.hpp (92%) rename {apps/openmw/mwgui => components/myguiplatform}/myguirendermanager.cpp (97%) rename {apps/openmw/mwgui => components/myguiplatform}/myguirendermanager.hpp (95%) rename {apps/openmw/mwgui => components/myguiplatform}/myguitexture.cpp (99%) rename {apps/openmw/mwgui => components/myguiplatform}/myguitexture.hpp (92%) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 680ea9c86..f352547e0 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -44,7 +44,7 @@ add_openmw_dir (mwgui itemmodel containeritemmodel inventoryitemmodel sortfilteritemmodel itemview tradeitemmodel companionitemmodel pickpocketitemmodel controllers savegamedialog recharge mode videowidget backgroundimage itemwidget screenfader debugwindow spellmodel spellview - draganddrop timeadvancer jailscreen myguiplatform myguirendermanager myguidatamanager myguitexture + draganddrop timeadvancer jailscreen ) add_openmw_dir (mwdialogue @@ -107,9 +107,6 @@ endif(WIN32) find_package(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS}) -# for MyGUI platform -find_package(OpenGL REQUIRED) - if (NOT ANDROID) add_executable(openmw ${OPENMW_FILES} @@ -139,7 +136,6 @@ target_link_libraries(openmw ${BULLET_LIBRARIES} ${MYGUI_LIBRARIES} ${SDL2_LIBRARY} - ${OPENGL_gl_LIBRARY} "osg-ffmpeg-videoplayer" "oics" components diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index e2e09bdec..488c94501 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -343,7 +343,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) osg::ref_ptr guiRoot = new osg::Group; guiRoot->setNodeMask(MWRender::Mask_GUI); rootNode->addChild(guiRoot); - MWGui::WindowManager* window = new MWGui::WindowManager(mViewer, guiRoot, mResourceSystem->getTextureManager(), + MWGui::WindowManager* window = new MWGui::WindowManager(mViewer, guiRoot, mResourceSystem.get(), mCfgMgr.getLogPath().string() + std::string("/"), myguiResources, mScriptConsoleMode, mTranslationDataStorage, mEncoding, mExportFonts, mFallbackMap); mEnvironment.setWindowManager (window); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index ce1314c6f..cac4939ed 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -26,8 +26,12 @@ #include +#include + #include +#include + #include #include @@ -91,13 +95,11 @@ #include "controllers.hpp" #include "jailscreen.hpp" -#include "myguiplatform.hpp" - namespace MWGui { WindowManager::WindowManager( - osgViewer::Viewer* viewer, osg::Group* guiRoot, Resource::TextureManager* textureManager + osgViewer::Viewer* viewer, osg::Group* guiRoot, Resource::ResourceSystem* resourceSystem , const std::string& logpath, const std::string& resourcePath, bool consoleOnlyScripts, Translation::Storage& translationDataStorage, ToUTF8::FromType encoding, bool exportFonts, const std::map& fallbackMap) : mConsoleOnlyScripts(consoleOnlyScripts) @@ -173,7 +175,7 @@ namespace MWGui , mCurrentModals() , mFallbackMap(fallbackMap) { - mGuiPlatform = new Platform(viewer, guiRoot, textureManager); + mGuiPlatform = new osgMyGUI::Platform(viewer, guiRoot, resourceSystem->getTextureManager()); mGuiPlatform->initialise(resourcePath, logpath); MyGUI::Gui* gui = new MyGUI::Gui; diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 738690bbc..894c81ec9 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -38,20 +38,6 @@ namespace Translation class Storage; } -namespace OEngine -{ - namespace GUI - { - class Layout; - class MyGUIManager; - } - - namespace Render - { - class OgreRenderer; - } -} - namespace osg { class Group; @@ -63,7 +49,7 @@ namespace osgViewer namespace Resource { - class TextureManager; + class ResourceSystem; } namespace SFO @@ -71,6 +57,11 @@ namespace SFO class CursorManager; } +namespace osgMyGUI +{ + class Platform; +} + namespace MWGui { class WindowBase; @@ -107,15 +98,13 @@ namespace MWGui class DebugWindow; class JailScreen; - class Platform; - class WindowManager : public MWBase::WindowManager { public: typedef std::pair Faction; typedef std::vector FactionList; - WindowManager(osgViewer::Viewer* viewer, osg::Group* guiRoot, Resource::TextureManager* textureManager, + WindowManager(osgViewer::Viewer* viewer, osg::Group* guiRoot, Resource::ResourceSystem* resourceSystem, const std::string& logpath, const std::string& cacheDir, bool consoleOnlyScripts, Translation::Storage& translationDataStorage, ToUTF8::FromType encoding, bool exportFonts, const std::map& fallbackMap); virtual ~WindowManager(); @@ -365,7 +354,7 @@ namespace MWGui virtual void cycleWeapon(bool next); private: - Platform* mGuiPlatform; + osgMyGUI::Platform* mGuiPlatform; bool mConsoleOnlyScripts; diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index a5e18dd49..775e3da19 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -223,6 +223,8 @@ namespace MWSound { if (found->first.size() >= pattern.size() && found->first.substr(0, pattern.size()) == pattern) filelist.push_back(found->first); + else + break; ++found; } diff --git a/apps/openmw/mwworld/scene.hpp b/apps/openmw/mwworld/scene.hpp index 26590c796..f7ef9b276 100644 --- a/apps/openmw/mwworld/scene.hpp +++ b/apps/openmw/mwworld/scene.hpp @@ -33,15 +33,9 @@ namespace Loading class Listener; } -namespace Render -{ - class OgreRenderer; -} - namespace MWRender { class SkyManager; - class CellRender; class RenderingManager; } @@ -59,7 +53,6 @@ namespace MWWorld private: - //OEngine::Render::OgreRenderer& mRenderer; CellStore* mCurrentCell; // the cell the player is in CellStoreCollection mActiveCells; bool mCellChanged; diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index e9655b12e..447bb1300 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -53,15 +53,9 @@ namespace Files class Collections; } -namespace Render -{ - class OgreRenderer; -} - namespace MWRender { class SkyManager; - class CellRender; class Animation; class Camera; } diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index cc913912f..563a77268 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -20,6 +20,8 @@ else (GIT_CHECKOUT) configure_file(${VERSION_HPP_IN} ${VERSION_HPP}) endif (GIT_CHECKOUT) +find_package(OpenGL REQUIRED) + # source files add_component_dir (settings @@ -116,6 +118,10 @@ add_component_dir (ogreinit ogreinit ogreplugin ) +add_component_dir (myguiplatform + myguirendermanager myguidatamanager myguiplatform myguitexture + ) + add_component_dir (widgets box imagebutton tags list numericeditbox sharedstatebutton windowcaption widgets ) @@ -170,6 +176,8 @@ target_link_libraries(components ${OGRE_LIBRARIES} ${OENGINE_LIBRARY} ${OPENSCENEGRAPH_LIBRARIES} + # For MyGUI platform + ${OPENGL_gl_LIBRARY} ) if (GIT_CHECKOUT) diff --git a/apps/openmw/mwgui/myguidatamanager.cpp b/components/myguiplatform/myguidatamanager.cpp similarity index 98% rename from apps/openmw/mwgui/myguidatamanager.cpp rename to components/myguiplatform/myguidatamanager.cpp index 5ba54b009..69bc3878d 100644 --- a/apps/openmw/mwgui/myguidatamanager.cpp +++ b/components/myguiplatform/myguidatamanager.cpp @@ -7,7 +7,7 @@ #include -namespace MWGui +namespace osgMyGUI { void DataManager::setResourcePath(const std::string &path) diff --git a/apps/openmw/mwgui/myguidatamanager.hpp b/components/myguiplatform/myguidatamanager.hpp similarity index 89% rename from apps/openmw/mwgui/myguidatamanager.hpp rename to components/myguiplatform/myguidatamanager.hpp index eaf60f8b9..5002f0fb7 100644 --- a/apps/openmw/mwgui/myguidatamanager.hpp +++ b/components/myguiplatform/myguidatamanager.hpp @@ -1,9 +1,9 @@ -#ifndef OPENMW_MWGUI_MYGUIDATAMANAGER_H -#define OPENMW_MWGUI_MYGUIDATAMANAGER_H +#ifndef OPENMW_COMPONENTS_MYGUIPLATFORM_MYGUIDATAMANAGER_H +#define OPENMW_COMPONENTS_MYGUIPLATFORM_MYGUIDATAMANAGER_H #include -namespace MWGui +namespace osgMyGUI { diff --git a/apps/openmw/mwgui/myguiplatform.cpp b/components/myguiplatform/myguiplatform.cpp similarity index 100% rename from apps/openmw/mwgui/myguiplatform.cpp rename to components/myguiplatform/myguiplatform.cpp diff --git a/apps/openmw/mwgui/myguiplatform.hpp b/components/myguiplatform/myguiplatform.hpp similarity index 92% rename from apps/openmw/mwgui/myguiplatform.hpp rename to components/myguiplatform/myguiplatform.hpp index a2256e970..5079b23b0 100644 --- a/apps/openmw/mwgui/myguiplatform.hpp +++ b/components/myguiplatform/myguiplatform.hpp @@ -1,5 +1,5 @@ -#ifndef OPENMW_MWGUI_MYGUIPLATFORM_H -#define OPENMW_MWGUI_MYGUIPLATFORM_H +#ifndef OPENMW_COMPONENTS_MYGUIPLATFORM_MYGUIPLATFORM_H +#define OPENMW_COMPONENTS_MYGUIPLATFORM_MYGUIPLATFORM_H #include "MyGUI_Prerequest.h" #include "MyGUI_LogManager.h" @@ -7,7 +7,7 @@ #include "myguirendermanager.hpp" #include "myguidatamanager.hpp" -namespace MWGui +namespace osgMyGUI { class Platform diff --git a/apps/openmw/mwgui/myguirendermanager.cpp b/components/myguiplatform/myguirendermanager.cpp similarity index 97% rename from apps/openmw/mwgui/myguirendermanager.cpp rename to components/myguiplatform/myguirendermanager.cpp index e5160bb5b..3ebbd957a 100644 --- a/apps/openmw/mwgui/myguirendermanager.cpp +++ b/components/myguiplatform/myguirendermanager.cpp @@ -48,24 +48,24 @@ namespace // Proxy to forward a Drawable's draw call to RenderManager::drawFrame class Renderable : public osg::Drawable { - MWGui::RenderManager *mParent; + osgMyGUI::RenderManager *mParent; virtual void drawImplementation(osg::RenderInfo &renderInfo) const { mParent->drawFrame(renderInfo); } public: - Renderable(MWGui::RenderManager *parent=nullptr) : mParent(parent) { } + Renderable(osgMyGUI::RenderManager *parent=nullptr) : mParent(parent) { } Renderable(const Renderable ©, const osg::CopyOp ©op=osg::CopyOp::SHALLOW_COPY) : osg::Drawable(copy, copyop) , mParent(copy.mParent) { } - META_Object(MWGui, Renderable) + META_Object(osgMyGUI, Renderable) }; // Proxy to forward an OSG resize event to RenderManager::setViewSize class ResizeHandler : public osgGA::GUIEventHandler { - MWGui::RenderManager *mParent; + osgMyGUI::RenderManager *mParent; virtual bool handle(const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter &aa) { @@ -79,19 +79,19 @@ class ResizeHandler : public osgGA::GUIEventHandler { } public: - ResizeHandler(MWGui::RenderManager *parent=nullptr) : mParent(parent) { } + ResizeHandler(osgMyGUI::RenderManager *parent=nullptr) : mParent(parent) { } ResizeHandler(const ResizeHandler ©, const osg::CopyOp ©op=osg::CopyOp::SHALLOW_COPY) : osg::Object(copy, copyop), osgGA::GUIEventHandler(copy, copyop) , mParent(copy.mParent) { } - META_Object(MWGui, ResizeHandler) + META_Object(osgMyGUI, ResizeHandler) }; } -namespace MWGui +namespace osgMyGUI { class OSGVertexBuffer : public MyGUI::IVertexBuffer diff --git a/apps/openmw/mwgui/myguirendermanager.hpp b/components/myguiplatform/myguirendermanager.hpp similarity index 95% rename from apps/openmw/mwgui/myguirendermanager.hpp rename to components/myguiplatform/myguirendermanager.hpp index 513edb5b7..05d0f9a5a 100644 --- a/apps/openmw/mwgui/myguirendermanager.hpp +++ b/components/myguiplatform/myguirendermanager.hpp @@ -1,5 +1,5 @@ -#ifndef OPENMW_MWGUI_MYGUIRENDERMANAGER_H -#define OPENMW_MWGUI_MYGUIRENDERMANAGER_H +#ifndef OPENMW_COMPONENTS_MYGUIPLATFORM_MYGUIRENDERMANAGER_H +#define OPENMW_COMPONENTS_MYGUIPLATFORM_MYGUIRENDERMANAGER_H #include @@ -22,7 +22,7 @@ namespace osg class RenderInfo; } -namespace MWGui +namespace osgMyGUI { class RenderManager : public MyGUI::RenderManager, public MyGUI::IRenderTarget diff --git a/apps/openmw/mwgui/myguitexture.cpp b/components/myguiplatform/myguitexture.cpp similarity index 99% rename from apps/openmw/mwgui/myguitexture.cpp rename to components/myguiplatform/myguitexture.cpp index d61e396f1..7de7ebfb0 100644 --- a/apps/openmw/mwgui/myguitexture.cpp +++ b/components/myguiplatform/myguitexture.cpp @@ -7,7 +7,7 @@ #include -namespace MWGui +namespace osgMyGUI { OSGTexture::OSGTexture(const std::string &name, Resource::TextureManager* textureManager) diff --git a/apps/openmw/mwgui/myguitexture.hpp b/components/myguiplatform/myguitexture.hpp similarity index 92% rename from apps/openmw/mwgui/myguitexture.hpp rename to components/myguiplatform/myguitexture.hpp index 5ae34a3d6..de385e94d 100644 --- a/apps/openmw/mwgui/myguitexture.hpp +++ b/components/myguiplatform/myguitexture.hpp @@ -1,5 +1,5 @@ -#ifndef OPENMW_MWGUI_MYGUITEXTURE_H -#define OPENMW_MWGUI_MYGUITEXTURE_H +#ifndef OPENMW_COMPONENTS_MYGUIPLATFORM_MYGUITEXTURE_H +#define OPENMW_COMPONENTS_MYGUIPLATFORM_MYGUITEXTURE_H #include @@ -16,7 +16,7 @@ namespace Resource class TextureManager; } -namespace MWGui +namespace osgMyGUI { class OSGTexture : public MyGUI::ITexture { diff --git a/components/widgets/imagebutton.hpp b/components/widgets/imagebutton.hpp index bed6a2794..10150c6b1 100644 --- a/components/widgets/imagebutton.hpp +++ b/components/widgets/imagebutton.hpp @@ -1,5 +1,5 @@ -#ifndef MWGUI_IMAGEBUTTON_H -#define MWGUI_IMAGEBUTTON_H +#ifndef OPENMW_COMPONENTS_WIDGETS_IMAGEBUTTON_H +#define OPENMW_COMPONENTS_WIDGETS_IMAGEBUTTON_H #include diff --git a/components/widgets/list.hpp b/components/widgets/list.hpp index 72c8a733c..6ee2ef3f2 100644 --- a/components/widgets/list.hpp +++ b/components/widgets/list.hpp @@ -1,5 +1,5 @@ -#ifndef MWGUI_LIST_HPP -#define MWGUI_LIST_HPP +#ifndef OPENMW_COMPONENTS_WIDGETS_LIST_HPP +#define OPENMW_COMPONENTS_WIDGETS_LIST_HPP #include From 6afb0e43ef3b3781d852eeb1f16b8c9130a599f8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 1 May 2015 01:41:33 +0200 Subject: [PATCH 1072/3725] Port FontLoader - requires MyGUI patch from https://github.com/MyGUI/mygui/pull/69 --- apps/openmw/mwgui/windowmanagerimp.cpp | 4 +- apps/openmw/mwgui/windowmanagerimp.hpp | 7 ++ components/fontloader/fontloader.cpp | 115 +++++++++++++++++-------- components/fontloader/fontloader.hpp | 28 +++++- 4 files changed, 111 insertions(+), 43 deletions(-) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index cac4939ed..ce9735f9d 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -184,8 +184,8 @@ namespace MWGui MyGUI::LanguageManager::getInstance().eventRequestTag = MyGUI::newDelegate(this, &WindowManager::onRetrieveTag); // Load fonts - Gui::FontLoader fontLoader (encoding); - fontLoader.loadAllFonts(exportFonts); + mFontLoader.reset(new Gui::FontLoader(encoding, resourceSystem->getVFS())); + mFontLoader->loadAllFonts(exportFonts); //Register own widgets with MyGUI MyGUI::FactoryManager::getInstance().registerFactory("Widget"); diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 894c81ec9..16dab08a9 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -62,6 +62,11 @@ namespace osgMyGUI class Platform; } +namespace Gui +{ + class FontLoader; +} + namespace MWGui { class WindowBase; @@ -356,6 +361,8 @@ namespace MWGui private: osgMyGUI::Platform* mGuiPlatform; + std::auto_ptr mFontLoader; + bool mConsoleOnlyScripts; std::map mTrackedWindows; diff --git a/components/fontloader/fontloader.cpp b/components/fontloader/fontloader.cpp index 1b61aea90..e579de18f 100644 --- a/components/fontloader/fontloader.cpp +++ b/components/fontloader/fontloader.cpp @@ -2,8 +2,10 @@ #include -#include -#include +#include +#include + +#include #include #include @@ -11,9 +13,12 @@ #include #include +#include #include +#include + namespace { unsigned long utf8ToUnicode(const std::string& utf8) @@ -123,12 +128,12 @@ namespace return encoder.getUtf8(std::string(1, c)); } - void fail (Ogre::DataStreamPtr file, const std::string& fileName, const std::string& message) + void fail (Files::IStreamPtr file, const std::string& fileName, const std::string& message) { std::stringstream error; error << "Font loading error: " << message; error << "\n File: " << fileName; - error << "\n Offset: 0x" << std::hex << file->tell(); + error << "\n Offset: 0x" << std::hex << file->tellg(); throw std::runtime_error(error.str()); } @@ -137,7 +142,8 @@ namespace namespace Gui { - FontLoader::FontLoader(ToUTF8::FromType encoding) + FontLoader::FontLoader(ToUTF8::FromType encoding, const VFS::Manager* vfs) + : mVFS(vfs) { if (encoding == ToUTF8::WINDOWS_1252) mEncoding = ToUTF8::CP437; @@ -145,19 +151,38 @@ namespace Gui mEncoding = encoding; } + FontLoader::~FontLoader() + { + for (std::vector::iterator it = mTextures.begin(); it != mTextures.end(); ++it) + delete *it; + mTextures.clear(); + + for (std::vector::iterator it = mFonts.begin(); it != mFonts.end(); ++it) + MyGUI::ResourceManager::getInstance().removeByName((*it)->getResourceName()); + mFonts.clear(); + } + void FontLoader::loadAllFonts(bool exportToFile) { - /* - Ogre::StringVector groups = Ogre::ResourceGroupManager::getSingleton().getResourceGroups (); - for (Ogre::StringVector::iterator it = groups.begin(); it != groups.end(); ++it) + const std::map& index = mVFS->getIndex(); + + std::string pattern = "Fonts/"; + mVFS->normalizeFilename(pattern); + + std::map::const_iterator found = index.lower_bound(pattern); + while (found != index.end()) { - Ogre::StringVectorPtr resourcesInThisGroup = Ogre::ResourceGroupManager::getSingleton ().findResourceNames (*it, "*.fnt"); - for (Ogre::StringVector::iterator resource = resourcesInThisGroup->begin(); resource != resourcesInThisGroup->end(); ++resource) + const std::string& name = found->first; + if (name.size() >= pattern.size() && name.substr(0, pattern.size()) == pattern) { - loadFont(*resource, exportToFile); + size_t pos = name.find_last_of('.'); + if (pos != std::string::npos && name.compare(pos, name.size()-pos, ".fnt") == 0) + loadFont(name, exportToFile); } + else + break; + ++found; } - */ } @@ -183,54 +208,62 @@ namespace Gui void FontLoader::loadFont(const std::string &fileName, bool exportToFile) { - Ogre::DataStreamPtr file = Ogre::ResourceGroupManager::getSingleton().openResource(fileName); + Files::IStreamPtr file = mVFS->get(fileName); float fontSize; - if (file->read(&fontSize, sizeof(fontSize)) < sizeof(fontSize)) + file->read((char*)&fontSize, sizeof(fontSize)); + if (!file->good()) fail(file, fileName, "File too small to be a valid font"); int one; - if (file->read(&one, sizeof(int)) < sizeof(int)) + file->read((char*)&one, sizeof(one)); + if (!file->good()) fail(file, fileName, "File too small to be a valid font"); if (one != 1) fail(file, fileName, "Unexpected value"); - if (file->read(&one, sizeof(int)) < sizeof(int)) + file->read((char*)&one, sizeof(one)); + if (!file->good()) fail(file, fileName, "File too small to be a valid font"); if (one != 1) fail(file, fileName, "Unexpected value"); char name_[284]; - if (file->read(name_, sizeof(name_)) < sizeof(name_)) + file->read(name_, sizeof(name_)); + if (!file->good()) fail(file, fileName, "File too small to be a valid font"); std::string name(name_); GlyphInfo data[256]; - if (file->read(data, sizeof(data)) < sizeof(data)) + file->read((char*)data, sizeof(data)); + if (!file->good()) fail(file, fileName, "File too small to be a valid font"); - file->close(); + + file.reset(); // Create the font texture std::string bitmapFilename = "Fonts/" + std::string(name) + ".tex"; - Ogre::DataStreamPtr bitmapFile = Ogre::ResourceGroupManager::getSingleton().openResource(bitmapFilename); + + Files::IStreamPtr bitmapFile = mVFS->get(bitmapFilename); int width, height; - if (bitmapFile->read(&width, sizeof(int)) < sizeof(int)) - fail(bitmapFile, bitmapFilename, "File too small to be a valid bitmap"); + bitmapFile->read((char*)&width, sizeof(int)); + bitmapFile->read((char*)&height, sizeof(int)); - if (bitmapFile->read(&height, sizeof(int)) < sizeof(int)) + if (!bitmapFile->good()) fail(bitmapFile, bitmapFilename, "File too small to be a valid bitmap"); if (width <= 0 || height <= 0) fail(bitmapFile, bitmapFilename, "Width and height must be positive"); - std::vector textureData; + std::vector textureData; textureData.resize(width*height*4); - if (bitmapFile->read(&textureData[0], width*height*4) < (size_t)(width*height*4)) - fail(bitmapFile, bitmapFilename, "Bitmap does not contain the specified number of pixels"); - bitmapFile->close(); + bitmapFile->read(&textureData[0], width*height*4); + if (!bitmapFile->good()) + fail(bitmapFile, bitmapFilename, "File too small to be a valid bitmap"); + bitmapFile.reset(); std::string resourceName; if (name.size() >= 5 && Misc::StringUtils::ciEqual(name.substr(0, 5), "magic")) @@ -239,24 +272,31 @@ namespace Gui resourceName = "Century Gothic"; else if (name.size() >= 7 && Misc::StringUtils::ciEqual(name.substr(0, 7), "daedric")) resourceName = "Daedric"; - else - return; // no point in loading it, since there is no way of using additional fonts std::string textureName = name; - Ogre::Image image; - image.loadDynamicImage(&textureData[0], width, height, Ogre::PF_BYTE_RGBA); - Ogre::TexturePtr texture = Ogre::TextureManager::getSingleton().createManual(textureName, - Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - Ogre::TEX_TYPE_2D, - width, height, 0, Ogre::PF_BYTE_RGBA); - texture->loadImage(image); + + osg::ref_ptr image = new osg::Image; + + unsigned char* bytes = (unsigned char*)calloc(width*height*4, sizeof(unsigned char)); + memcpy(bytes, &textureData[0], textureData.size()); + image->setImage(width, height, 1, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, bytes, osg::Image::USE_MALLOC_FREE); + + osg::ref_ptr texture = new osg::Texture2D; + texture->setImage(image); if (exportToFile) - image.save(resourceName + ".png"); + { + std::cout << "Writing " << resourceName + ".png" << std::endl; + osgDB::writeImageFile(*image, resourceName + ".png"); + } // Register the font with MyGUI MyGUI::ResourceManualFont* font = static_cast( MyGUI::FactoryManager::getInstance().createObject("Resource", "ResourceManualFont")); + mFonts.push_back(font); + osgMyGUI::OSGTexture* myguiTex = new osgMyGUI::OSGTexture(texture); + mTextures.push_back(myguiTex); + font->setTexture(myguiTex); // We need to emulate loading from XML because the data members are private as of mygui 3.2.0 MyGUI::xml::Document xmlDocument; @@ -390,6 +430,7 @@ namespace Gui if (exportToFile) { + std::cout << "Writing " << resourceName + ".xml" << std::endl; xmlDocument.createDeclaration(); xmlDocument.save(resourceName + ".xml"); } diff --git a/components/fontloader/fontloader.hpp b/components/fontloader/fontloader.hpp index a41506dbb..b92815f13 100644 --- a/components/fontloader/fontloader.hpp +++ b/components/fontloader/fontloader.hpp @@ -1,26 +1,46 @@ -#ifndef MWGUI_FONTLOADER_H -#define MWGUI_FONTLOADER_H +#ifndef OPENMW_COMPONENTS_FONTLOADER_H +#define OPENMW_COMPONENTS_FONTLOADER_H #include +namespace VFS +{ + class Manager; +} + +namespace MyGUI +{ + class ITexture; + class ResourceManualFont; +} + namespace Gui { - /// @brief loads Morrowind's .fnt/.tex fonts for use with MyGUI and Ogre + /// @brief loads Morrowind's .fnt/.tex fonts for use with MyGUI and OSG + /// @note The FontLoader needs to remain in scope as long as you want to use the loaded fonts. class FontLoader { public: - FontLoader (ToUTF8::FromType encoding); + FontLoader (ToUTF8::FromType encoding, const VFS::Manager* vfs); + ~FontLoader(); /// @param exportToFile export the converted fonts (Images and XML with glyph metrics) to files? void loadAllFonts (bool exportToFile); private: ToUTF8::FromType mEncoding; + const VFS::Manager* mVFS; + + std::vector mTextures; + std::vector mFonts; /// @param exportToFile export the converted font (Image and XML with glyph metrics) to files? void loadFont (const std::string& fileName, bool exportToFile); + + FontLoader(const FontLoader&); + void operator=(const FontLoader&); }; } From 9f74be8fcb3308797a0ceed3e93db9990f890b48 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 1 May 2015 02:04:24 +0200 Subject: [PATCH 1073/3725] Add back the custom MyGUI log facility for utf8 paths on windows --- components/CMakeLists.txt | 2 +- .../myguiplatform/myguiloglistener.cpp | 6 +- components/myguiplatform/myguiloglistener.hpp | 69 +++++++++++++++++++ components/myguiplatform/myguiplatform.hpp | 22 ++++-- libs/openengine/CMakeLists.txt | 2 - libs/openengine/gui/loglistener.hpp | 37 ---------- 6 files changed, 88 insertions(+), 50 deletions(-) rename libs/openengine/gui/loglistener.cpp => components/myguiplatform/myguiloglistener.cpp (78%) create mode 100644 components/myguiplatform/myguiloglistener.hpp delete mode 100644 libs/openengine/gui/loglistener.hpp diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 563a77268..ac7eef16a 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -119,7 +119,7 @@ add_component_dir (ogreinit ) add_component_dir (myguiplatform - myguirendermanager myguidatamanager myguiplatform myguitexture + myguirendermanager myguidatamanager myguiplatform myguitexture myguiloglistener ) add_component_dir (widgets diff --git a/libs/openengine/gui/loglistener.cpp b/components/myguiplatform/myguiloglistener.cpp similarity index 78% rename from libs/openengine/gui/loglistener.cpp rename to components/myguiplatform/myguiloglistener.cpp index da36b90a2..b36e0d852 100644 --- a/libs/openengine/gui/loglistener.cpp +++ b/components/myguiplatform/myguiloglistener.cpp @@ -1,11 +1,11 @@ -#include "loglistener.hpp" +#include "myguiloglistener.hpp" #include #include #include -namespace MyGUI +namespace osgMyGUI { void CustomLogListener::open() { @@ -24,7 +24,7 @@ namespace MyGUI mStream.flush(); } - void CustomLogListener::log(const std::string& _section, LogLevel _level, const struct tm* _time, const std::string& _message, const char* _file, int _line) + void CustomLogListener::log(const std::string& _section, MyGUI::LogLevel _level, const struct tm* _time, const std::string& _message, const char* _file, int _line) { if (mStream.is_open()) { diff --git a/components/myguiplatform/myguiloglistener.hpp b/components/myguiplatform/myguiloglistener.hpp new file mode 100644 index 000000000..3da4d3c52 --- /dev/null +++ b/components/myguiplatform/myguiloglistener.hpp @@ -0,0 +1,69 @@ +#ifndef OPENENGINE_MYGUI_LOGLISTENER_H +#define OPENENGINE_MYGUI_LOGLISTENER_H + +#include +#include + +#include +#include +#include +#include + +namespace osgMyGUI +{ + + /// \brief Custom MyGUI::ILogListener interface implementation + /// being able to portably handle UTF-8 encoded path. + /// \todo try patching MyGUI to make this easier + class CustomLogListener : public MyGUI::ILogListener + { + public: + CustomLogListener(const std::string &name) + : mFileName(name) + {} + + ~CustomLogListener() {} + + virtual void open(); + virtual void close(); + virtual void flush(); + + virtual void log(const std::string& _section, MyGUI::LogLevel _level, const struct tm* _time, const std::string& _message, const char* _file, int _line); + + const std::string& getFileName() const { return mFileName; } + + private: + boost::filesystem::ofstream mStream; + std::string mFileName; + }; + + /// \brief Helper class holding data that required during + /// MyGUI log creation + class LogFacility + { + MyGUI::ConsoleLogListener mConsole; + CustomLogListener mFile; + MyGUI::LevelLogFilter mFilter; + MyGUI::LogSource mSource; + + public: + + LogFacility(const std::string &output, bool console) + : mFile(output) + { + mConsole.setEnabled(console); + mFilter.setLoggingLevel(MyGUI::LogLevel::Info); + + mSource.addLogListener(&mFile); + mSource.addLogListener(&mConsole); + mSource.setLogFilter(&mFilter); + + mSource.open(); + } + + MyGUI::LogSource *getSource() { return &mSource; } + }; + +} + +#endif diff --git a/components/myguiplatform/myguiplatform.hpp b/components/myguiplatform/myguiplatform.hpp index 5079b23b0..c0c9e0ce4 100644 --- a/components/myguiplatform/myguiplatform.hpp +++ b/components/myguiplatform/myguiplatform.hpp @@ -6,6 +6,7 @@ #include "myguirendermanager.hpp" #include "myguidatamanager.hpp" +#include "myguiloglistener.hpp" namespace osgMyGUI { @@ -13,10 +14,11 @@ namespace osgMyGUI class Platform { public: - Platform(osgViewer::Viewer* viewer, osg::Group* guiRoot, Resource::TextureManager* textureManager) : - mLogManager(nullptr), - mRenderManager(nullptr), - mDataManager(nullptr) + Platform(osgViewer::Viewer* viewer, osg::Group* guiRoot, Resource::TextureManager* textureManager) + : mRenderManager(nullptr) + , mDataManager(nullptr) + , mLogManager(nullptr) + , mLogFacility(nullptr) { mLogManager = new MyGUI::LogManager(); mRenderManager = new RenderManager(viewer, guiRoot, textureManager); @@ -31,12 +33,17 @@ namespace osgMyGUI mDataManager = nullptr; delete mLogManager; mLogManager = nullptr; + delete mLogFacility; + mLogFacility = nullptr; } void initialise(const std::string& resourcePath, const std::string& _logName = "MyGUI.log") { - if (!_logName.empty()) - MyGUI::LogManager::getInstance().createDefaultSource(_logName); + if (!_logName.empty() && !mLogFacility) + { + mLogFacility = new LogFacility(_logName, false); + mLogManager->addLogSource(mLogFacility->getSource()); + } mDataManager->setResourcePath(resourcePath); @@ -46,7 +53,7 @@ namespace osgMyGUI void shutdown() { - //mRenderManager->shutdown(); + mRenderManager->shutdown(); mDataManager->shutdown(); } @@ -64,6 +71,7 @@ namespace osgMyGUI RenderManager* mRenderManager; DataManager* mDataManager; MyGUI::LogManager* mLogManager; + LogFacility* mLogFacility; }; } diff --git a/libs/openengine/CMakeLists.txt b/libs/openengine/CMakeLists.txt index 07ac60bc6..fa3df0820 100644 --- a/libs/openengine/CMakeLists.txt +++ b/libs/openengine/CMakeLists.txt @@ -1,6 +1,4 @@ set(OENGINE_GUI - gui/loglistener.cpp - #gui/manager.cpp gui/layout.cpp ) diff --git a/libs/openengine/gui/loglistener.hpp b/libs/openengine/gui/loglistener.hpp deleted file mode 100644 index 47978ba44..000000000 --- a/libs/openengine/gui/loglistener.hpp +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef OPENENGINE_MYGUI_LOGLISTENER_H -#define OPENENGINE_MYGUI_LOGLISTENER_H - -#include -#include - -#include - -namespace MyGUI -{ - /// \brief Custom MyGUI::ILogListener interface implementation - /// being able to portably handle UTF-8 encoded path. - class CustomLogListener : public ILogListener - { - public: - CustomLogListener(const std::string &name) - : mFileName(name) - {} - - ~CustomLogListener() {} - - virtual void open(); - virtual void close(); - virtual void flush(); - - virtual void log(const std::string& _section, LogLevel _level, const struct tm* _time, const std::string& _message, const char* _file, int _line); - - const std::string& getFileName() const { return mFileName; } - - private: - boost::filesystem::ofstream mStream; - std::string mFileName; - }; - -} - -#endif From 223e3a53f58d92e69d56a6d2b29196e84fcdad1a Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 1 May 2015 02:09:57 +0200 Subject: [PATCH 1074/3725] Move OEngine::Gui::Layout to MWGui --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwbase/windowmanager.hpp | 12 +++--------- apps/openmw/mwgui/hud.hpp | 2 +- .../openengine/gui => apps/openmw/mwgui}/layout.cpp | 5 +---- .../openengine/gui => apps/openmw/mwgui}/layout.hpp | 9 ++++----- apps/openmw/mwgui/mainmenu.cpp | 4 ++-- apps/openmw/mwgui/mainmenu.hpp | 4 ++-- apps/openmw/mwgui/messagebox.hpp | 2 +- apps/openmw/mwgui/tooltips.hpp | 4 ++-- apps/openmw/mwgui/windowbase.hpp | 4 ++-- apps/openmw/mwgui/windowmanagerimp.cpp | 6 +++--- apps/openmw/mwgui/windowmanagerimp.hpp | 6 +++--- libs/openengine/CMakeLists.txt | 6 +----- 13 files changed, 26 insertions(+), 40 deletions(-) rename {libs/openengine/gui => apps/openmw/mwgui}/layout.cpp (98%) rename {libs/openengine/gui => apps/openmw/mwgui}/layout.hpp (94%) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index f352547e0..f049f0387 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -33,7 +33,7 @@ add_openmw_dir (mwrender # ) add_openmw_dir (mwgui - textinput widgets race class birth review windowmanagerimp console dialogue + layout textinput widgets race class birth review windowmanagerimp console dialogue windowbase statswindow messagebox journalwindow charactercreation mapwindow windowpinnablebase tooltips scrollwindow bookwindow formatting inventorywindow container hud countdialog tradewindow settingswindow diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index d5960779c..743577812 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -26,14 +26,6 @@ namespace MyGUI class UString; } -namespace OEngine -{ - namespace GUI - { - class Layout; - } -} - namespace ESM { struct Class; @@ -58,6 +50,8 @@ namespace MWWorld namespace MWGui { + class Layout; + class Console; class SpellWindow; class TradeWindow; @@ -241,7 +235,7 @@ namespace MWBase virtual void addVisitedLocation(const std::string& name, int x, int y) = 0; /// Hides dialog and schedules dialog to be deleted. - virtual void removeDialog(OEngine::GUI::Layout* dialog) = 0; + virtual void removeDialog(MWGui::Layout* dialog) = 0; ///Gracefully attempts to exit the topmost GUI mode /** No guarentee of actually closing the window **/ diff --git a/apps/openmw/mwgui/hud.hpp b/apps/openmw/mwgui/hud.hpp index 263c08774..e717e094e 100644 --- a/apps/openmw/mwgui/hud.hpp +++ b/apps/openmw/mwgui/hud.hpp @@ -16,7 +16,7 @@ namespace MWGui class SpellIcons; class ItemWidget; - class HUD : public OEngine::GUI::Layout, public LocalMapBase + class HUD : public Layout, public LocalMapBase { public: HUD(CustomMarkerCollection& customMarkers, int fpsLevel, DragAndDrop* dragAndDrop); diff --git a/libs/openengine/gui/layout.cpp b/apps/openmw/mwgui/layout.cpp similarity index 98% rename from libs/openengine/gui/layout.cpp rename to apps/openmw/mwgui/layout.cpp index cd94387f9..6bdb1a9f4 100644 --- a/libs/openengine/gui/layout.cpp +++ b/apps/openmw/mwgui/layout.cpp @@ -6,9 +6,7 @@ #include #include -namespace OEngine -{ -namespace GUI +namespace MWGui { void Layout::initialise(const std::string& _layout, MyGUI::Widget* _parent) { @@ -78,4 +76,3 @@ namespace GUI } } -} diff --git a/libs/openengine/gui/layout.hpp b/apps/openmw/mwgui/layout.hpp similarity index 94% rename from libs/openengine/gui/layout.hpp rename to apps/openmw/mwgui/layout.hpp index b0515ccbb..0e7cf3faa 100644 --- a/libs/openengine/gui/layout.hpp +++ b/apps/openmw/mwgui/layout.hpp @@ -1,12 +1,11 @@ -#ifndef OENGINE_MYGUI_LAYOUT_H -#define OENGINE_MYGUI_LAYOUT_H +#ifndef OPENMW_MWGUI_LAYOUT_H +#define OPENMW_MWGUI_LAYOUT_H #include #include #include -namespace OEngine { -namespace GUI +namespace MWGui { /** The Layout class is an utility class used to load MyGUI layouts from xml files, and to manipulate member widgets. @@ -60,5 +59,5 @@ namespace GUI std::string mLayoutName; MyGUI::VectorWidgetPtr mListWindowRoot; }; -}} +} #endif diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index 0a8667d80..d563eacc8 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -30,7 +30,7 @@ namespace MWGui { MainMenu::MainMenu(int w, int h) - : OEngine::GUI::Layout("openmw_mainmenu.layout") + : Layout("openmw_mainmenu.layout") , mButtonBox(0), mWidth (w), mHeight (h) , mSaveGameDialog(NULL) , mBackground(NULL) @@ -80,7 +80,7 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_MainMenu) && MWBase::Environment::get().getStateManager()->getState() == MWBase::StateManager::State_NoGame); - OEngine::GUI::Layout::setVisible (visible); + Layout::setVisible (visible); } void MainMenu::onNewGameConfirmed() diff --git a/apps/openmw/mwgui/mainmenu.hpp b/apps/openmw/mwgui/mainmenu.hpp index cd2050d0f..9089ed1d5 100644 --- a/apps/openmw/mwgui/mainmenu.hpp +++ b/apps/openmw/mwgui/mainmenu.hpp @@ -1,7 +1,7 @@ #ifndef OPENMW_GAME_MWGUI_MAINMENU_H #define OPENMW_GAME_MWGUI_MAINMENU_H -#include +#include "layout.hpp" namespace Gui { @@ -15,7 +15,7 @@ namespace MWGui class SaveGameDialog; class VideoWidget; - class MainMenu : public OEngine::GUI::Layout + class MainMenu : public Layout { int mWidth; int mHeight; diff --git a/apps/openmw/mwgui/messagebox.hpp b/apps/openmw/mwgui/messagebox.hpp index 48a92c844..59d1a0b06 100644 --- a/apps/openmw/mwgui/messagebox.hpp +++ b/apps/openmw/mwgui/messagebox.hpp @@ -51,7 +51,7 @@ namespace MWGui int mLastButtonPressed; }; - class MessageBox : public OEngine::GUI::Layout + class MessageBox : public Layout { public: MessageBox (MessageBoxManager& parMessageBoxManager, const std::string& message); diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp index 71b4a560f..0ddd313df 100644 --- a/apps/openmw/mwgui/tooltips.hpp +++ b/apps/openmw/mwgui/tooltips.hpp @@ -2,7 +2,7 @@ #ifndef MWGUI_TOOLTIPS_H #define MWGUI_TOOLTIPS_H -#include +#include "layout.hpp" #include "../mwworld/ptr.hpp" #include "widgets.hpp" @@ -45,7 +45,7 @@ namespace MWGui bool wordWrap; }; - class ToolTips : public OEngine::GUI::Layout + class ToolTips : public Layout { public: ToolTips(); diff --git a/apps/openmw/mwgui/windowbase.hpp b/apps/openmw/mwgui/windowbase.hpp index bf74c8bf0..195b6c384 100644 --- a/apps/openmw/mwgui/windowbase.hpp +++ b/apps/openmw/mwgui/windowbase.hpp @@ -1,7 +1,7 @@ #ifndef MWGUI_WINDOW_BASE_H #define MWGUI_WINDOW_BASE_H -#include +#include "layout.hpp" namespace MWBase { @@ -13,7 +13,7 @@ namespace MWGui class WindowManager; class DragAndDrop; - class WindowBase: public OEngine::GUI::Layout + class WindowBase: public Layout { public: WindowBase(const std::string& parLayout); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index ce9735f9d..cf7475d5c 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -422,7 +422,7 @@ namespace MWGui // Delete any dialogs which are no longer in use if (!mGarbageDialogs.empty()) { - for (std::vector::iterator it = mGarbageDialogs.begin(); it != mGarbageDialogs.end(); ++it) + for (std::vector::iterator it = mGarbageDialogs.begin(); it != mGarbageDialogs.end(); ++it) { delete *it; } @@ -722,7 +722,7 @@ namespace MWGui mStatsWindow->updateSkillArea(); } - void WindowManager::removeDialog(OEngine::GUI::Layout*dialog) + void WindowManager::removeDialog(Layout*dialog) { if (!dialog) return; @@ -1566,7 +1566,7 @@ namespace MWGui return mCursorVisible; } - void WindowManager::trackWindow(OEngine::GUI::Layout *layout, const std::string &name) + void WindowManager::trackWindow(Layout *layout, const std::string &name) { MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize(); MyGUI::IntPoint pos(static_cast(Settings::Manager::getFloat(name + " x", "Windows") * viewSize.width), diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 16dab08a9..ec99364c7 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -242,7 +242,7 @@ namespace MWGui virtual void addVisitedLocation(const std::string& name, int x, int y); ///Hides dialog and schedules dialog to be deleted. - virtual void removeDialog(OEngine::GUI::Layout* dialog); + virtual void removeDialog(Layout* dialog); ///Gracefully attempts to exit the topmost GUI mode virtual void exitCurrentGuiMode(); @@ -366,7 +366,7 @@ namespace MWGui bool mConsoleOnlyScripts; std::map mTrackedWindows; - void trackWindow(OEngine::GUI::Layout* layout, const std::string& name); + void trackWindow(Layout* layout, const std::string& name); void onWindowChangeCoord(MyGUI::Window* _sender); std::string mSelectedSpell; @@ -448,7 +448,7 @@ namespace MWGui SFO::CursorManager* mCursorManager; - std::vector mGarbageDialogs; + std::vector mGarbageDialogs; void cleanupGarbage(); GuiWindow mShown; // Currently shown windows in inventory mode diff --git a/libs/openengine/CMakeLists.txt b/libs/openengine/CMakeLists.txt index fa3df0820..b135d0fc6 100644 --- a/libs/openengine/CMakeLists.txt +++ b/libs/openengine/CMakeLists.txt @@ -1,7 +1,3 @@ -set(OENGINE_GUI - gui/layout.cpp -) - set(OENGINE_BULLET bullet/BtOgre.cpp bullet/BtOgreExtras.h @@ -15,7 +11,7 @@ set(OENGINE_BULLET bullet/trace.h ) -set(OENGINE_ALL ${OENGINE_GUI} ${OENGINE_BULLET}) +set(OENGINE_ALL ${OENGINE_BULLET}) set(OENGINE_LIBRARY "oengine") set(OENGINE_LIBRARY ${OENGINE_LIBRARY} PARENT_SCOPE) From b0804734e577d58c7b514b9df8893d2d187e6b7d Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 1 May 2015 03:03:44 +0200 Subject: [PATCH 1075/3725] Port VideoWidget --- apps/openmw/engine.cpp | 2 +- apps/openmw/mwgui/videowidget.cpp | 41 ++++++++++++++----- apps/openmw/mwgui/videowidget.hpp | 16 ++++++-- apps/openmw/mwgui/windowmanagerimp.cpp | 37 ++++++++--------- apps/openmw/mwgui/windowmanagerimp.hpp | 1 + extern/osg-ffmpeg-videoplayer/videoplayer.cpp | 8 ++-- 6 files changed, 65 insertions(+), 40 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 488c94501..0abb43cfd 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -468,7 +468,7 @@ void OMW::Engine::go() mViewer->realize(); osg::Timer frameTimer; - while (!mViewer->done()) + while (!mViewer->done() && !MWBase::Environment::get().getStateManager()->hasQuitRequest()) { double dt = frameTimer.time_s(); frameTimer.setStartTick(); diff --git a/apps/openmw/mwgui/videowidget.cpp b/apps/openmw/mwgui/videowidget.cpp index 28771f14f..13fabfeed 100644 --- a/apps/openmw/mwgui/videowidget.cpp +++ b/apps/openmw/mwgui/videowidget.cpp @@ -1,51 +1,70 @@ #include "videowidget.hpp" -//#include +#include #include -//#include "../mwsound/movieaudiofactory.hpp" +#include + +#include +#include + +#include "../mwsound/movieaudiofactory.hpp" namespace MWGui { VideoWidget::VideoWidget() + : mVFS(NULL) { - //mPlayer.reset(new Video::VideoPlayer()); + mPlayer.reset(new Video::VideoPlayer()); setNeedKeyFocus(true); } +void VideoWidget::setVFS(const VFS::Manager *vfs) +{ + mVFS = vfs; +} + void VideoWidget::playVideo(const std::string &video) { - //mPlayer->setAudioFactory(new MWSound::MovieAudioFactory()); - //mPlayer->playVideo(video); + mPlayer->setAudioFactory(new MWSound::MovieAudioFactory()); + + mPlayer->playVideo(mVFS->get(video)); + + osg::ref_ptr texture = mPlayer->getVideoTexture(); + if (!texture) + return; + + mTexture.reset(new osgMyGUI::OSGTexture(texture)); - //setImageTexture(mPlayer->getTextureName()); + setRenderItemTexture(mTexture.get()); + getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 0.f, 1.f, 1.f)); } int VideoWidget::getVideoWidth() { - return 0;//mPlayer->getVideoWidth(); + return mPlayer->getVideoWidth(); } int VideoWidget::getVideoHeight() { - return 0;//mPlayer->getVideoHeight(); + return mPlayer->getVideoHeight(); } bool VideoWidget::update() { - return 0;//mPlayer->update(); + return mPlayer->update(); } void VideoWidget::stop() { - //mPlayer->close(); + mPlayer->close(); } bool VideoWidget::hasAudioStream() { - return 0;//mPlayer->hasAudioStream(); + return mPlayer->hasAudioStream(); } void VideoWidget::autoResize(bool stretch) diff --git a/apps/openmw/mwgui/videowidget.hpp b/apps/openmw/mwgui/videowidget.hpp index 75aa6e98a..6b265628e 100644 --- a/apps/openmw/mwgui/videowidget.hpp +++ b/apps/openmw/mwgui/videowidget.hpp @@ -1,26 +1,34 @@ #ifndef OPENMW_MWGUI_VIDEOWIDGET_H #define OPENMW_MWGUI_VIDEOWIDGET_H -#include +#include namespace Video { class VideoPlayer; } +namespace VFS +{ + class Manager; +} + namespace MWGui { /** * Widget that plays a video. */ - class VideoWidget : public MyGUI::ImageBox + class VideoWidget : public MyGUI::Widget { public: MYGUI_RTTI_DERIVED(VideoWidget) VideoWidget(); + /// Set the VFS (virtual file system) to find the videos on. + void setVFS(const VFS::Manager* vfs); + void playVideo (const std::string& video); int getVideoWidth(); @@ -42,7 +50,9 @@ namespace MWGui void autoResize (bool stretch); private: - //std::auto_ptr mPlayer; + const VFS::Manager* mVFS; + std::auto_ptr mTexture; + std::auto_ptr mPlayer; }; } diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index cf7475d5c..7ce8d6200 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -3,9 +3,7 @@ #include #include -#include -#include -#include +#include #include #include @@ -38,6 +36,8 @@ #include "../mwbase/inputmanager.hpp" #include "../mwbase/statemanager.hpp" +#include "../mwrender/vismask.hpp" + #include "../mwworld/class.hpp" #include "../mwworld/player.hpp" #include "../mwworld/cellstore.hpp" @@ -102,7 +102,8 @@ namespace MWGui osgViewer::Viewer* viewer, osg::Group* guiRoot, Resource::ResourceSystem* resourceSystem , const std::string& logpath, const std::string& resourcePath, bool consoleOnlyScripts, Translation::Storage& translationDataStorage, ToUTF8::FromType encoding, bool exportFonts, const std::map& fallbackMap) - : mConsoleOnlyScripts(consoleOnlyScripts) + : mViewer(viewer) + , mConsoleOnlyScripts(consoleOnlyScripts) , mHud(NULL) , mMap(NULL) , mMenu(NULL) @@ -236,6 +237,7 @@ namespace MWGui mVideoWidget = mVideoBackground->createWidgetReal("ImageBox", 0,0,1,1, MyGUI::Align::Default); mVideoWidget->setNeedMouseFocus(true); mVideoWidget->setNeedKeyFocus(true); + mVideoWidget->setVFS(resourceSystem->getVFS()); // Removes default MyGUI system clipboard implementation, which supports windows only MyGUI::ClipboardManager::getInstance().eventClipboardChanged.clear(); @@ -1127,8 +1129,8 @@ namespace MWGui mGuiModes.push_back(mode); - bool gameMode = !isGuiMode(); - MWBase::Environment::get().getInputManager()->changeInputMode(!gameMode); + //bool gameMode = !isGuiMode(); + //MWBase::Environment::get().getInputManager()->changeInputMode(!gameMode); updateVisible(); } @@ -1683,7 +1685,6 @@ namespace MWGui void WindowManager::playVideo(const std::string &name, bool allowSkipping) { - return; mVideoWidget->playVideo("video\\" + name); mVideoWidget->eventKeyButtonPressed.clear(); @@ -1695,16 +1696,10 @@ namespace MWGui } // Turn off all rendering except for the GUI - /* - mRendering->getScene()->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) - mRendering->getScene()->addSpecialCaseRenderQueue(i); - } - mRendering->getScene()->setSpecialCaseRenderQueueMode(Ogre::SceneManager::SCRQM_EXCLUDE); - */ + int oldUpdateMask = mViewer->getUpdateVisitor()->getTraversalMask(); + int oldCullMask = mViewer->getCamera()->getCullMask(); + mViewer->getUpdateVisitor()->setTraversalMask(MWRender::Mask_GUI); + mViewer->getCamera()->setCullMask(MWRender::Mask_GUI); MyGUI::IntSize screenSize = MyGUI::RenderManager::getInstance().getViewSize(); sizeVideo(screenSize.width, screenSize.height); @@ -1722,9 +1717,9 @@ namespace MWGui while (mVideoWidget->update() && !MWBase::Environment::get().getStateManager()->hasQuitRequest()) { - MWBase::Environment::get().getInputManager()->update(0, true, false); + //MWBase::Environment::get().getInputManager()->update(0, true, false); - //mRendering->getWindow()->update(); + mViewer->frame(); } mVideoWidget->stop(); @@ -1733,8 +1728,8 @@ namespace MWGui setCursorVisible(cursorWasVisible); // Restore normal rendering - //mRendering->getScene()->clearSpecialCaseRenderQueues(); - //mRendering->getScene()->setSpecialCaseRenderQueueMode(Ogre::SceneManager::SCRQM_EXCLUDE); + mViewer->getUpdateVisitor()->setTraversalMask(oldUpdateMask); + mViewer->getCamera()->setCullMask(oldCullMask); mVideoBackground->setVisible(false); } diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index ec99364c7..3a6f3b024 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -360,6 +360,7 @@ namespace MWGui private: osgMyGUI::Platform* mGuiPlatform; + osgViewer::Viewer* mViewer; std::auto_ptr mFontLoader; diff --git a/extern/osg-ffmpeg-videoplayer/videoplayer.cpp b/extern/osg-ffmpeg-videoplayer/videoplayer.cpp index 8dedeaf64..1336e45a3 100644 --- a/extern/osg-ffmpeg-videoplayer/videoplayer.cpp +++ b/extern/osg-ffmpeg-videoplayer/videoplayer.cpp @@ -65,16 +65,16 @@ osg::ref_ptr VideoPlayer::getVideoTexture() int VideoPlayer::getVideoWidth() { int width=0; - if (mState && mState->mTexture.get()) - width = mState->mTexture->getTextureWidth(); + if (mState && mState->mTexture.get() && mState->mTexture->getImage()) + width = mState->mTexture->getImage()->s(); return width; } int VideoPlayer::getVideoHeight() { int height=0; - if (mState && mState->mTexture.get()) - height = mState->mTexture->getTextureHeight(); + if (mState && mState->mTexture.get() && mState->mTexture->getImage()) + height = mState->mTexture->getImage()->t(); return height; } From b04aeb6aad5ca7441d3091a85fc871049db0c8e8 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Fri, 1 May 2015 12:14:09 +1000 Subject: [PATCH 1076/3725] Fixed levelled lists flags - now bit masks represented by tick boxes in the dialogue subview. --- apps/opencs/model/world/columns.cpp | 5 +- apps/opencs/model/world/columns.hpp | 11 +- apps/opencs/model/world/commands.cpp | 7 +- apps/opencs/model/world/refidadapterimp.hpp | 126 +++++++++++--------- apps/opencs/model/world/refidcollection.cpp | 4 +- apps/opencs/view/world/dialoguesubview.cpp | 5 +- 6 files changed, 89 insertions(+), 69 deletions(-) diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 3d735ddca..3172e72e4 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -222,7 +222,6 @@ namespace CSMWorld { ColumnId_HitSound, "Hit Sound" }, { ColumnId_AreaSound, "Area Sound" }, { ColumnId_BoltSound, "Bolt Sound" }, - { ColumnId_OriginalCell, "Original Cell" }, { ColumnId_PathgridPoints, "Points" }, { ColumnId_PathgridIndex, "Index" }, @@ -267,13 +266,15 @@ namespace CSMWorld { ColumnId_LevelledList,"Levelled List" }, { ColumnId_LevelledItemId,"Item ID" }, { ColumnId_LevelledItemLevel,"Level" }, - { ColumnId_LevelledItemType, "Type" }, + { ColumnId_LevelledItemType, "Calculate all levels <= player" }, + { ColumnId_LevelledItemTypeEach, "Select a new item each instance" }, { ColumnId_LevelledItemChanceNone, "Chance None" }, { ColumnId_PowerList, "Powers" }, { ColumnId_SkillImpact, "Skills" }, { ColumnId_InfoList, "Info List" }, + { ColumnId_OriginalCell, "Original Cell" }, { ColumnId_UseValue1, "Use value 1" }, { ColumnId_UseValue2, "Use value 2" }, diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 0c525fd11..b87f6c53d 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -257,14 +257,15 @@ namespace CSMWorld ColumnId_LevelledItemId = 234, ColumnId_LevelledItemLevel = 235, ColumnId_LevelledItemType = 236, - ColumnId_LevelledItemChanceNone = 237, + ColumnId_LevelledItemTypeEach = 237, + ColumnId_LevelledItemChanceNone = 238, - ColumnId_PowerList = 238, - ColumnId_SkillImpact = 239, // impact from magic effects + ColumnId_PowerList = 239, + ColumnId_SkillImpact = 240, // impact from magic effects - ColumnId_InfoList = 240, + ColumnId_InfoList = 241, - ColumnId_OriginalCell = 241, + ColumnId_OriginalCell = 242, // Allocated to a separate value range, so we don't get a collision should we ever need // to extend the number of use values. diff --git a/apps/opencs/model/world/commands.cpp b/apps/opencs/model/world/commands.cpp index 232959727..9a0401081 100644 --- a/apps/opencs/model/world/commands.cpp +++ b/apps/opencs/model/world/commands.cpp @@ -21,9 +21,12 @@ CSMWorld::ModifyCommand::ModifyCommand (QAbstractItemModel& model, const QModelI // Replace proxy with actual model mIndex = proxy->mapToSource (index); mModel = proxy->sourceModel(); - } - setText ("Modify " + mModel->headerData (mIndex.column(), Qt::Horizontal, Qt::DisplayRole).toString()); + setText ("Modify " + dynamic_cast(mModel)->nestedHeaderData ( + mIndex.parent().column(), mIndex.column(), Qt::Horizontal, Qt::DisplayRole).toString()); + } + else + setText ("Modify " + mModel->headerData (mIndex.column(), Qt::Horizontal, Qt::DisplayRole).toString()); } void CSMWorld::ModifyCommand::redo() diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index e38554383..61e8115c0 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -1830,10 +1830,10 @@ namespace CSMWorld } + // for non-tables template class NestedListLevListRefIdAdapter : public NestedRefIdAdapterBase { - UniversalId::Type mType; // not implemented @@ -1877,45 +1877,27 @@ namespace CSMWorld const Record& record = static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); - switch (subColIndex) + if (mType == UniversalId::Type_CreatureLevelledList) { - case 0: + switch (subColIndex) { - if (mType == CSMWorld::UniversalId::Type_CreatureLevelledList && - record.get().mFlags == 0x01) - { - return QString("All Levels"); - } - else if(mType == CSMWorld::UniversalId::Type_ItemLevelledList && - record.get().mFlags == 0x01) - { - return QString("Each"); - } - else if(mType == CSMWorld::UniversalId::Type_ItemLevelledList && - record.get().mFlags == 0x02) - { - return QString("All Levels"); - } - else if (mType == CSMWorld::UniversalId::Type_CreatureLevelledList && - record.get().mFlags == 0x00) - { - std::cerr << "Unknown creature leveled list type: " << record.get().mFlags - << ", Using \"All Levels\""<< std::endl; - return QString("All Levels"); - } - else if (mType == CSMWorld::UniversalId::Type_ItemLevelledList && - record.get().mFlags == 0x00) - { - std::cerr << "Unknown item leveled list type: " << record.get().mFlags - << ", Using \"Each\""<< std::endl; - return QString("Each"); - } - else - throw std::runtime_error("unknown leveled list type"); + case 0: return QVariant(); // don't allow checkbox editor to be created + case 1: return record.get().mFlags & ESM::CreatureLevList::AllLevels; + case 2: return static_cast (record.get().mChanceNone); + default: + throw std::runtime_error("Trying to access non-existing column in levelled creatues!"); + } + } + else + { + switch (subColIndex) + { + case 0: return record.get().mFlags & ESM::ItemLevList::Each; + case 1: return record.get().mFlags & ESM::ItemLevList::AllLevels; + case 2: return static_cast (record.get().mChanceNone); + default: + throw std::runtime_error("Trying to access non-existing column in levelled items!"); } - case 1: return static_cast (record.get().mChanceNone); - default: - throw std::runtime_error("Trying to access non-existing column in the nested table!"); } } @@ -1926,34 +1908,63 @@ namespace CSMWorld static_cast&> (data.getRecord (RefIdData::LocalIndex (row, mType))); ESXRecordT leveled = record.get(); - switch(subColIndex) + if (mType == UniversalId::Type_CreatureLevelledList) { - case 0: + switch(subColIndex) { - if (mType == CSMWorld::UniversalId::Type_CreatureLevelledList && - value.toString().toStdString() == "All Levels") + case 0: return; // return without saving + case 1: { - leveled.mFlags = 0x01; - break; + if(value.toBool()) + { + leveled.mFlags |= ESM::CreatureLevList::AllLevels; + break; + } + else + { + leveled.mFlags &= ~ESM::CreatureLevList::AllLevels; + break; + } } - else if(mType == CSMWorld::UniversalId::Type_ItemLevelledList && - value.toString().toStdString() == "Each") + case 2: leveled.mChanceNone = static_cast(value.toInt()); break; + default: + throw std::runtime_error("Trying to set non-existing column in levelled creatures!"); + } + } + else + { + switch(subColIndex) + { + case 0: { - leveled.mFlags = 0x01; - break; + if(value.toBool()) + { + leveled.mFlags |= ESM::ItemLevList::Each; + break; + } + else + { + leveled.mFlags &= ~ESM::ItemLevList::Each; + break; + } } - else if(mType == CSMWorld::UniversalId::Type_ItemLevelledList && - value.toString().toStdString() == "All Levels") + case 1: { - leveled.mFlags = 0x02; - break; + if(value.toBool()) + { + leveled.mFlags |= ESM::ItemLevList::AllLevels; + break; + } + else + { + leveled.mFlags &= ~ESM::ItemLevList::AllLevels; + break; + } } - else - return; // return without saving + case 2: leveled.mChanceNone = static_cast(value.toInt()); break; + default: + throw std::runtime_error("Trying to set non-existing column in levelled items!"); } - case 1: leveled.mChanceNone = static_cast(value.toInt()); break; - default: - throw std::runtime_error("Trying to access non-existing column in the nested table!"); } record.setModified (leveled); @@ -1961,7 +1972,7 @@ namespace CSMWorld virtual int getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const { - return 2; + return 3; } virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const @@ -1970,6 +1981,7 @@ namespace CSMWorld } }; + // for tables template class NestedLevListRefIdAdapter : public NestedRefIdAdapterBase { diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 4a8f398cd..1941c505a 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -514,7 +514,9 @@ CSMWorld::RefIdCollection::RefIdCollection() new NestedListLevListRefIdAdapter (UniversalId::Type_ItemLevelledList))); mNestedAdapters.push_back (std::make_pair(&mColumns.back(), nestedListLevListMap)); mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_LevelledItemType, CSMWorld::ColumnBase::Display_String)); + new RefIdColumn (Columns::ColumnId_LevelledItemTypeEach, CSMWorld::ColumnBase::Display_Boolean)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_LevelledItemType, CSMWorld::ColumnBase::Display_Boolean)); mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_LevelledItemChanceNone, CSMWorld::ColumnBase::Display_Integer)); diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index cf3653c1b..0d0e82dbf 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -29,8 +29,8 @@ #include "../../model/world/record.hpp" #include "../../model/world/tablemimedata.hpp" #include "../../model/world/idtree.hpp" -#include "../../model/doc/document.hpp" #include "../../model/world/commands.hpp" +#include "../../model/doc/document.hpp" #include "recordstatusdelegate.hpp" #include "util.hpp" @@ -444,7 +444,8 @@ void CSVWorld::EditWidget::remake(int row) if (mTable->hasChildren(mTable->index(row, i)) && !(flags & CSMWorld::ColumnBase::Flag_Dialogue_List)) { - mNestedModels.push_back(new CSMWorld::NestedTableProxyModel (mTable->index(row, i), display, dynamic_cast(mTable))); + mNestedModels.push_back(new CSMWorld::NestedTableProxyModel ( + mTable->index(row, i), display, dynamic_cast(mTable))); int idColumn = mTable->findColumnIndex (CSMWorld::Columns::ColumnId_Id); int typeColumn = mTable->findColumnIndex (CSMWorld::Columns::ColumnId_RecordType); From bd8f0248f00c537bca974f3998eae44fafb30b56 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 1 May 2015 18:21:50 +0200 Subject: [PATCH 1077/3725] Player rendering --- .../mwmechanics/mechanicsmanagerimp.cpp | 2 ++ apps/openmw/mwrender/animation.cpp | 2 ++ apps/openmw/mwrender/objects.cpp | 12 -------- apps/openmw/mwrender/renderingmanager.cpp | 29 +++++++++++++++++++ apps/openmw/mwrender/renderingmanager.hpp | 11 ++++++- apps/openmw/mwworld/worldimp.cpp | 15 ++++++---- 6 files changed, 53 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 7e6e29670..077f67b5e 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1318,6 +1318,8 @@ namespace MWMechanics bool MechanicsManager::awarenessCheck(const MWWorld::Ptr &ptr, const MWWorld::Ptr &observer) { + return false; + if (observer.getClass().getCreatureStats(observer).isDead() || !observer.getRefData().isEnabled()) return false; diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 245095492..1f749ab4e 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -866,6 +866,8 @@ namespace MWRender NodeMapVisitor visitor; mObjectRoot->accept(visitor); mNodeMap = visitor.getNodeMap(); + + mObjectRoot->addCullCallback(new SceneUtil::LightListCallback); } osg::Group* Animation::getObjectRoot() diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index f77865634..a06b751cc 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -10,9 +10,6 @@ #include #include -// light -#include - #include #include @@ -112,9 +109,6 @@ void Objects::insertModel(const MWWorld::Ptr &ptr, const std::string &mesh, bool std::auto_ptr anim (new ObjectAnimation(ptr, mesh, mResourceSystem, allowLight)); - if (anim->getObjectRoot()) - anim->getObjectRoot()->addCullCallback(new SceneUtil::LightListCallback); - if (!allowLight) { RemoveParticlesVisitor visitor; @@ -137,9 +131,6 @@ void Objects::insertCreature(const MWWorld::Ptr &ptr, const std::string &mesh, b else anim.reset(new CreatureAnimation(ptr, mesh, mResourceSystem)); - if (anim->getObjectRoot()) - anim->getObjectRoot()->addCullCallback(new SceneUtil::LightListCallback); - mObjects.insert(std::make_pair(ptr, anim.release())); } @@ -149,9 +140,6 @@ void Objects::insertNPC(const MWWorld::Ptr &ptr) std::auto_ptr anim (new NpcAnimation(ptr, osg::ref_ptr(ptr.getRefData().getBaseNode()), mResourceSystem, 0)); - if (anim->getObjectRoot()) - anim->getObjectRoot()->addCullCallback(new SceneUtil::LightListCallback); - mObjects.insert(std::make_pair(ptr, anim.release())); } diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 8689935d0..d07c98ed7 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -23,6 +23,7 @@ #include "sky.hpp" #include "effectmanager.hpp" +#include "npcanimation.hpp" #include "vismask.hpp" namespace MWRender @@ -82,6 +83,7 @@ namespace MWRender , mResourceSystem(resourceSystem) { osg::ref_ptr lightRoot = new SceneUtil::LightManager; + mLightRoot = lightRoot; lightRoot->setStartLight(1); mRootNode->addChild(lightRoot); @@ -258,4 +260,31 @@ namespace MWRender return mObjects->getAnimation(ptr); } + MWRender::Animation* RenderingManager::getPlayerAnimation() + { + return mPlayerAnimation.get(); + } + + void RenderingManager::setupPlayer(const MWWorld::Ptr &player) + { + if (!mPlayerNode) + { + mPlayerNode = new osg::PositionAttitudeTransform; + mLightRoot->addChild(mPlayerNode); + } + + player.getRefData().setBaseNode(mPlayerNode); + + //attachCameraTo(player); + } + + void RenderingManager::renderPlayer(const MWWorld::Ptr &player) + { + mPlayerAnimation.reset(new NpcAnimation(player, player.getRefData().getBaseNode(), mResourceSystem, 0)); + + //mCamera->setAnimation(mPlayerAnimation); + //mWater->removeEmitter(ptr); + //mWater->addEmitter(ptr); + } + } diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 005100701..71c70b990 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -11,6 +11,7 @@ namespace osg { class Group; + class PositionAttitudeTransform; } namespace Resource @@ -35,6 +36,7 @@ namespace MWRender class EffectManager; class SkyManager; + class NpcAnimation; class RenderingManager : public MWRender::RenderingInterface { @@ -78,11 +80,16 @@ namespace MWRender void update(float dt, bool paused); - MWRender::Animation* getAnimation(const MWWorld::Ptr& ptr); + Animation* getAnimation(const MWWorld::Ptr& ptr); + Animation* getPlayerAnimation(); + + void setupPlayer(const MWWorld::Ptr& player); + void renderPlayer(const MWWorld::Ptr& player); private: osgViewer::Viewer& mViewer; osg::ref_ptr mRootNode; + osg::ref_ptr mLightRoot; Resource::ResourceSystem* mResourceSystem; osg::ref_ptr mSunLight; @@ -90,6 +97,8 @@ namespace MWRender std::auto_ptr mObjects; std::auto_ptr mSky; std::auto_ptr mEffectManager; + std::auto_ptr mPlayerAnimation; + osg::ref_ptr mPlayerNode; osg::ref_ptr mStateUpdater; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 4e737fc07..8cb9f4d50 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1563,7 +1563,8 @@ namespace MWWorld } const ESM::NPC *ret = mStore.insert(record); if (update) { - //mRendering->renderPlayer(mPlayer->getPlayer()); + mRendering->renderPlayer(getPlayerPtr()); + scaleObject(getPlayerPtr(), 1.f); // apply race height } return ret; } @@ -2120,18 +2121,20 @@ namespace MWWorld mPlayer->set(player); } - //Ptr ptr = mPlayer->getPlayer(); - //mRendering->setupPlayer(ptr); + Ptr ptr = mPlayer->getPlayer(); + mRendering->setupPlayer(ptr); } void World::renderPlayer() { - //mRendering->renderPlayer(mPlayer->getPlayer()); + mRendering->renderPlayer(getPlayerPtr()); + + scaleObject(getPlayerPtr(), 1.f); // apply race height // At this point the Animation object is live, and the CharacterController associated with it must be created. // It has to be done at this point: resetCamera below does animation->setViewMode -> CharacterController::forceStateUpdate // so we should make sure not to use a "stale" controller for that. - MWBase::Environment::get().getMechanicsManager()->add(mPlayer->getPlayer()); + MWBase::Environment::get().getMechanicsManager()->add(getPlayerPtr()); std::string model = getPlayerPtr().getClass().getModel(getPlayerPtr()); //model = Misc::ResourceHelpers::correctActorModelPath(model); @@ -2163,6 +2166,8 @@ namespace MWWorld MWRender::Animation* World::getAnimation(const MWWorld::Ptr &ptr) { + if (ptr == getPlayerPtr()) + return mRendering->getPlayerAnimation(); return mRendering->getAnimation(ptr); } From 82c4d01b377d0d21ac5923d93fd9126dcbef9c17 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 1 May 2015 18:37:24 +0200 Subject: [PATCH 1078/3725] Add back resource handling workarounds to the gui code --- apps/openmw/mwbase/windowmanager.hpp | 5 +++++ apps/openmw/mwgui/birth.cpp | 2 +- apps/openmw/mwgui/formatting.cpp | 6 +++++- apps/openmw/mwgui/hud.cpp | 2 +- apps/openmw/mwgui/itemwidget.cpp | 6 +++++- apps/openmw/mwgui/quickkeysmenu.cpp | 2 +- apps/openmw/mwgui/spellcreationdialog.cpp | 2 +- apps/openmw/mwgui/spellicons.cpp | 2 +- apps/openmw/mwgui/tooltips.cpp | 4 ++-- apps/openmw/mwgui/widgets.cpp | 2 +- apps/openmw/mwgui/windowmanagerimp.cpp | 20 +++++++++++++++++++- apps/openmw/mwgui/windowmanagerimp.hpp | 7 +++++++ components/misc/resourcehelpers.hpp | 5 ++++- 13 files changed, 53 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 743577812..59407fbeb 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -353,6 +353,11 @@ namespace MWBase virtual void cycleSpell(bool next) = 0; /// Cycle to next or previous weapon virtual void cycleWeapon(bool next) = 0; + + // In WindowManager for now since there isn't a VFS singleton + virtual std::string correctIconPath(const std::string& path) = 0; + virtual std::string correctBookartPath(const std::string& path, int width, int height) = 0; + virtual std::string correctTexturePath(const std::string& path) = 0; }; } diff --git a/apps/openmw/mwgui/birth.cpp b/apps/openmw/mwgui/birth.cpp index 475428f33..dd20999e0 100644 --- a/apps/openmw/mwgui/birth.cpp +++ b/apps/openmw/mwgui/birth.cpp @@ -183,7 +183,7 @@ namespace MWGui const ESM::BirthSign *birth = store.get().find(mCurrentBirthId); - //mBirthImage->setImageTexture(Misc::ResourceHelpers::correctTexturePath(birth->mTexture)); + mBirthImage->setImageTexture(MWBase::Environment::get().getWindowManager()->correctTexturePath(birth->mTexture)); std::vector abilities, powers, spells; diff --git a/apps/openmw/mwgui/formatting.cpp b/apps/openmw/mwgui/formatting.cpp index d96255c85..461d8e32e 100644 --- a/apps/openmw/mwgui/formatting.cpp +++ b/apps/openmw/mwgui/formatting.cpp @@ -6,6 +6,10 @@ #include #include +// correctBookartPath +#include "../mwbase/environment.hpp" +#include "../mwbase/windowmanager.hpp" + #include #include @@ -463,7 +467,7 @@ namespace MWGui MyGUI::IntCoord(left, pag.getCurrentTop(), width, mImageHeight), MyGUI::Align::Left | MyGUI::Align::Top, parent->getName() + MyGUI::utility::toString(parent->getChildCount())); - std::string image;// = Misc::ResourceHelpers::correctBookartPath(src, width, mImageHeight); + std::string image = MWBase::Environment::get().getWindowManager()->correctBookartPath(src, width, mImageHeight); mImageBox->setImageTexture(image); mImageBox->setProperty("NeedMouse", "false"); } diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 2323d39e7..9c8fa48a1 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -448,7 +448,7 @@ namespace MWGui std::string icon = effect->mIcon; int slashPos = icon.rfind('\\'); icon.insert(slashPos+1, "b_"); - //icon = Misc::ResourceHelpers::correctIconPath(icon); + icon = MWBase::Environment::get().getWindowManager()->correctIconPath(icon); mSpellImage->setItem(MWWorld::Ptr()); mSpellImage->setIcon(icon); diff --git a/apps/openmw/mwgui/itemwidget.cpp b/apps/openmw/mwgui/itemwidget.cpp index 1da2ab879..645a72277 100644 --- a/apps/openmw/mwgui/itemwidget.cpp +++ b/apps/openmw/mwgui/itemwidget.cpp @@ -6,6 +6,10 @@ #include +// correctIconPath +#include "../mwbase/environment.hpp" +#include "../mwbase/windowmanager.hpp" + #include "../mwworld/class.hpp" namespace @@ -77,7 +81,7 @@ namespace MWGui void ItemWidget::setIcon(const MWWorld::Ptr &ptr) { - //setIcon(Misc::ResourceHelpers::correctIconPath(ptr.getClass().getInventoryIcon(ptr))); + setIcon(MWBase::Environment::get().getWindowManager()->correctIconPath(ptr.getClass().getInventoryIcon(ptr))); } diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index 3fddbc84b..0c462c67d 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -245,7 +245,7 @@ namespace MWGui std::string path = effect->mIcon; int slashPos = path.rfind('\\'); path.insert(slashPos+1, "b_"); - //path = Misc::ResourceHelpers::correctIconPath(path); + path = MWBase::Environment::get().getWindowManager()->correctIconPath(path); button->setFrame("textures\\menu_icon_select_magic.dds", MyGUI::IntCoord(2, 2, 40, 40)); button->setIcon(path); diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index 80806941c..e0a1493c2 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -180,7 +180,7 @@ namespace MWGui void EditEffectDialog::setMagicEffect (const ESM::MagicEffect *effect) { - //mEffectImage->setImageTexture(Misc::ResourceHelpers::correctIconPath(effect->mIcon)); + mEffectImage->setImageTexture(MWBase::Environment::get().getWindowManager()->correctIconPath(effect->mIcon)); mEffectName->setCaptionWithReplacing("#{"+ESM::MagicEffect::effectIdToString (effect->mIndex)+"}"); diff --git a/apps/openmw/mwgui/spellicons.cpp b/apps/openmw/mwgui/spellicons.cpp index 8770bab38..c26316626 100644 --- a/apps/openmw/mwgui/spellicons.cpp +++ b/apps/openmw/mwgui/spellicons.cpp @@ -145,7 +145,7 @@ namespace MWGui ("ImageBox", MyGUI::IntCoord(w,2,16,16), MyGUI::Align::Default); mWidgetMap[it->first] = image; - //image->setImageTexture(Misc::ResourceHelpers::correctIconPath(effect->mIcon)); + image->setImageTexture(MWBase::Environment::get().getWindowManager()->correctIconPath(effect->mIcon)); std::string name = ESM::MagicEffect::effectIdToString (it->first); diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 8b63ab541..f91c17370 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -388,7 +388,7 @@ namespace MWGui const int imageCaptionHPadding = (caption != "" ? 8 : 0); const int imageCaptionVPadding = (caption != "" ? 4 : 0); - std::string realImage;// = Misc::ResourceHelpers::correctIconPath(image); + std::string realImage = MWBase::Environment::get().getWindowManager()->correctIconPath(image); MyGUI::EditBox* captionWidget = mDynamicToolTipBox->createWidget("NormalText", MyGUI::IntCoord(0, 0, 300, 300), MyGUI::Align::Left | MyGUI::Align::Top, "ToolTipCaption"); captionWidget->setProperty("Static", "true"); @@ -686,7 +686,7 @@ namespace MWGui widget->setUserString("ToolTipType", "Layout"); widget->setUserString("ToolTipLayout", "BirthSignToolTip"); - widget->setUserString("ImageTexture_BirthSignImage", "");//Misc::ResourceHelpers::correctTexturePath(sign->mTexture)); + widget->setUserString("ImageTexture_BirthSignImage", MWBase::Environment::get().getWindowManager()->correctTexturePath(sign->mTexture)); std::string text; text += sign->mName; diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index 888955391..996cc528d 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -474,7 +474,7 @@ namespace MWGui mTextWidget->setCaptionWithReplacing(spellLine); mRequestedWidth = mTextWidget->getTextSize().width + 24; - //mImageWidget->setImageTexture(Misc::ResourceHelpers::correctIconPath(magicEffect->mIcon)); + mImageWidget->setImageTexture(MWBase::Environment::get().getWindowManager()->correctIconPath(magicEffect->mIcon)); } MWSpellEffect::~MWSpellEffect() diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 7ce8d6200..096838f81 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -33,6 +33,8 @@ #include #include +#include + #include "../mwbase/inputmanager.hpp" #include "../mwbase/statemanager.hpp" @@ -102,7 +104,8 @@ namespace MWGui osgViewer::Viewer* viewer, osg::Group* guiRoot, Resource::ResourceSystem* resourceSystem , const std::string& logpath, const std::string& resourcePath, bool consoleOnlyScripts, Translation::Storage& translationDataStorage, ToUTF8::FromType encoding, bool exportFonts, const std::map& fallbackMap) - : mViewer(viewer) + : mResourceSystem(resourceSystem) + , mViewer(viewer) , mConsoleOnlyScripts(consoleOnlyScripts) , mHud(NULL) , mMap(NULL) @@ -1917,4 +1920,19 @@ namespace MWGui mScrollWindow->open(item, showTakeButton); } + std::string WindowManager::correctIconPath(const std::string& path) + { + return Misc::ResourceHelpers::correctIconPath(path, mResourceSystem->getVFS()); + } + + std::string WindowManager::correctBookartPath(const std::string& path, int width, int height) + { + return Misc::ResourceHelpers::correctBookartPath(path, width, height, mResourceSystem->getVFS()); + } + + std::string WindowManager::correctTexturePath(const std::string& path) + { + return Misc::ResourceHelpers::correctTexturePath(path, mResourceSystem->getVFS()); + } + } diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 3a6f3b024..765a18156 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -358,7 +358,14 @@ namespace MWGui /// Cycle to next or previous weapon virtual void cycleWeapon(bool next); + // In WindowManager for now since there isn't a VFS singleton + virtual std::string correctIconPath(const std::string& path); + virtual std::string correctBookartPath(const std::string& path, int width, int height); + virtual std::string correctTexturePath(const std::string& path); + private: + Resource::ResourceSystem* mResourceSystem; + osgMyGUI::Platform* mGuiPlatform; osgViewer::Viewer* mViewer; diff --git a/components/misc/resourcehelpers.hpp b/components/misc/resourcehelpers.hpp index 1763f7777..fa50cce22 100644 --- a/components/misc/resourcehelpers.hpp +++ b/components/misc/resourcehelpers.hpp @@ -10,6 +10,9 @@ namespace VFS namespace Misc { + // Workarounds for messy resource handling in vanilla morrowind + // The below functions are provided on a opt-in basis, instead of built into the VFS, + // so we have the opportunity to use proper resource handling for content created in OpenMW-CS. namespace ResourceHelpers { bool changeExtensionToDds(std::string &path); @@ -18,7 +21,7 @@ namespace Misc std::string correctIconPath(const std::string &resPath, const VFS::Manager* vfs); std::string correctBookartPath(const std::string &resPath, const VFS::Manager* vfs); std::string correctBookartPath(const std::string &resPath, int width, int height, const VFS::Manager* vfs); - /// Uses "xfoo.nif" instead of "foo.nif" if available + /// Use "xfoo.nif" instead of "foo.nif" if available std::string correctActorModelPath(const std::string &resPath, const VFS::Manager* vfs); } } From a592c1a1c2319574159686bc314b86aea0bb6a99 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 1 May 2015 18:42:44 +0200 Subject: [PATCH 1079/3725] Remove unused resources --- files/CMakeLists.txt | 49 -- files/materials/atmosphere.shader | 39 -- files/materials/atmosphere.shaderset | 15 - files/materials/clouds.shader | 55 --- files/materials/clouds.shaderset | 15 - files/materials/core.h | 181 -------- files/materials/moon.shader | 51 --- files/materials/moon.shaderset | 15 - files/materials/mygui.mat | 25 -- files/materials/mygui.shader | 45 -- files/materials/mygui.shaderset | 15 - files/materials/objects.mat | 147 ------ files/materials/objects.shader | 591 ------------------------- files/materials/objects.shaderset | 15 - files/materials/openmw.configuration | 20 - files/materials/quad.mat | 22 - files/materials/quad.shader | 25 -- files/materials/quad.shaderset | 15 - files/materials/ripples.particle | 26 -- files/materials/selection.mat | 9 - files/materials/selection.shader | 24 - files/materials/selection.shaderset | 15 - files/materials/shadowcaster.mat | 35 -- files/materials/shadowcaster.shader | 55 --- files/materials/shadowcaster.shaderset | 15 - files/materials/shadows.h | 51 --- files/materials/sky.mat | 140 ------ files/materials/stars.shader | 48 -- files/materials/stars.shaderset | 15 - files/materials/sun.shader | 41 -- files/materials/sun.shaderset | 15 - files/materials/terrain.shader | 507 --------------------- files/materials/terrain.shaderset | 15 - files/materials/underwater.h | 121 ----- files/materials/water.mat | 101 ----- files/materials/water.shader | 354 --------------- files/materials/water.shaderset | 15 - files/water/circle.png | Bin 753 -> 0 bytes files/water/water_nm.png | Bin 24405 -> 0 bytes 39 files changed, 2942 deletions(-) delete mode 100644 files/materials/atmosphere.shader delete mode 100644 files/materials/atmosphere.shaderset delete mode 100644 files/materials/clouds.shader delete mode 100644 files/materials/clouds.shaderset delete mode 100644 files/materials/core.h delete mode 100644 files/materials/moon.shader delete mode 100644 files/materials/moon.shaderset delete mode 100644 files/materials/mygui.mat delete mode 100644 files/materials/mygui.shader delete mode 100644 files/materials/mygui.shaderset delete mode 100644 files/materials/objects.mat delete mode 100644 files/materials/objects.shader delete mode 100644 files/materials/objects.shaderset delete mode 100644 files/materials/openmw.configuration delete mode 100644 files/materials/quad.mat delete mode 100644 files/materials/quad.shader delete mode 100644 files/materials/quad.shaderset delete mode 100644 files/materials/ripples.particle delete mode 100644 files/materials/selection.mat delete mode 100644 files/materials/selection.shader delete mode 100644 files/materials/selection.shaderset delete mode 100644 files/materials/shadowcaster.mat delete mode 100644 files/materials/shadowcaster.shader delete mode 100644 files/materials/shadowcaster.shaderset delete mode 100644 files/materials/shadows.h delete mode 100644 files/materials/sky.mat delete mode 100644 files/materials/stars.shader delete mode 100644 files/materials/stars.shaderset delete mode 100644 files/materials/sun.shader delete mode 100644 files/materials/sun.shaderset delete mode 100644 files/materials/terrain.shader delete mode 100644 files/materials/terrain.shaderset delete mode 100644 files/materials/underwater.h delete mode 100644 files/materials/water.mat delete mode 100644 files/materials/water.shader delete mode 100644 files/materials/water.shaderset delete mode 100644 files/water/circle.png delete mode 100644 files/water/water_nm.png diff --git a/files/CMakeLists.txt b/files/CMakeLists.txt index da3451d93..e69de29bb 100644 --- a/files/CMakeLists.txt +++ b/files/CMakeLists.txt @@ -1,49 +0,0 @@ -project(resources) - -set(WATER_FILES - water_nm.png - circle.png -) - -set(MATERIAL_FILES - atmosphere.shader - atmosphere.shaderset - clouds.shader - clouds.shaderset - core.h - moon.shader - moon.shaderset - objects.mat - objects.shader - objects.shaderset - openmw.configuration - quad.mat - quad.shader - quad.shaderset - shadowcaster.mat - shadowcaster.shader - shadowcaster.shaderset - shadows.h - sky.mat - stars.shader - stars.shaderset - sun.shader - sun.shaderset - terrain.shader - terrain.shaderset - underwater.h - water.mat - water.shader - water.shaderset - selection.mat - selection.shader - selection.shaderset - mygui.mat - mygui.shader - mygui.shaderset - ripples.particle -) - -copy_all_files(${CMAKE_CURRENT_SOURCE_DIR}/water "${OpenMW_BINARY_DIR}/resources/water/" "${WATER_FILES}") - -copy_all_files(${CMAKE_CURRENT_SOURCE_DIR}/materials "${OpenMW_BINARY_DIR}/resources/materials/" "${MATERIAL_FILES}") diff --git a/files/materials/atmosphere.shader b/files/materials/atmosphere.shader deleted file mode 100644 index 3eaa73b1c..000000000 --- a/files/materials/atmosphere.shader +++ /dev/null @@ -1,39 +0,0 @@ -#include "core.h" - -#ifdef SH_VERTEX_SHADER - - SH_BEGIN_PROGRAM - shUniform(float4x4, view) @shAutoConstant(view, view_matrix) - shUniform(float4x4, projection) @shAutoConstant(projection, projection_matrix) - - shOutput(float, alphaFade) - - SH_START_PROGRAM - { - float4x4 viewFixed = view; -#if !SH_GLSL && !SH_GLSLES - viewFixed[0][3] = 0.0; - viewFixed[1][3] = 0.0; - viewFixed[2][3] = 0.0; -#else - viewFixed[3][0] = 0.0; - viewFixed[3][1] = 0.0; - viewFixed[3][2] = 0.0; -#endif - shOutputPosition = shMatrixMult(projection, shMatrixMult(viewFixed, shInputPosition)); - alphaFade = shInputPosition.z < 150.0 ? 0.0 : 1.0; - } - -#else - - SH_BEGIN_PROGRAM - shInput(float, alphaFade) - shUniform(float4, atmosphereColour) @shSharedParameter(atmosphereColour) - shUniform(float4, horizonColour) @shSharedParameter(horizonColour, horizonColour) - - SH_START_PROGRAM - { - shOutputColour(0) = alphaFade * atmosphereColour + (1.0 - alphaFade) * horizonColour; - } - -#endif diff --git a/files/materials/atmosphere.shaderset b/files/materials/atmosphere.shaderset deleted file mode 100644 index 54108dbba..000000000 --- a/files/materials/atmosphere.shaderset +++ /dev/null @@ -1,15 +0,0 @@ -shader_set atmosphere_vertex -{ - source atmosphere.shader - type vertex - profiles_cg vs_2_0 arbvp1 - profiles_hlsl vs_2_0 -} - -shader_set atmosphere_fragment -{ - source atmosphere.shader - type fragment - profiles_cg ps_2_x ps_2_0 ps arbfp1 - profiles_hlsl ps_2_0 -} diff --git a/files/materials/clouds.shader b/files/materials/clouds.shader deleted file mode 100644 index 5902d2fdc..000000000 --- a/files/materials/clouds.shader +++ /dev/null @@ -1,55 +0,0 @@ -#include "core.h" - -#ifdef SH_VERTEX_SHADER - - SH_BEGIN_PROGRAM - shUniform(float4x4, worldview) @shAutoConstant(worldview, worldview_matrix) - shUniform(float4x4, proj) @shAutoConstant(proj, projection_matrix) - shVertexInput(float2, uv0) - shOutput(float2, UV) - shOutput(float, alphaFade) - - SH_START_PROGRAM - { - float4x4 worldviewFixed = worldview; - -#if !SH_GLSL && !SH_GLSLES - worldviewFixed[0][3] = 0.0; - worldviewFixed[1][3] = 0.0; - worldviewFixed[2][3] = 0.0; -#else - worldviewFixed[3][0] = 0.0; - worldviewFixed[3][1] = 0.0; - worldviewFixed[3][2] = 0.0; -#endif - - shOutputPosition = shMatrixMult(proj, shMatrixMult(worldviewFixed, shInputPosition)); - UV = uv0; - alphaFade = (shInputPosition.z <= 200.0) ? ((shInputPosition.z <= 100.0) ? 0.0 : 0.25) : 1.0; - } - -#else - - SH_BEGIN_PROGRAM - shInput(float2, UV) - shInput(float, alphaFade) - - shSampler2D(diffuseMap1) - shSampler2D(diffuseMap2) - - shUniform(float, cloudBlendFactor) @shSharedParameter(cloudBlendFactor) - shUniform(float, cloudAnimationTimer) @shSharedParameter(cloudAnimationTimer) - shUniform(float, cloudOpacity) @shSharedParameter(cloudOpacity) - shUniform(float3, cloudColour) @shSharedParameter(cloudColour) - - SH_START_PROGRAM - { - // Scroll in y direction - float2 scrolledUV = UV + float2(0,1) * cloudAnimationTimer * 0.003; - - float4 albedo = shSample(diffuseMap1, scrolledUV) * (1.0-cloudBlendFactor) + shSample(diffuseMap2, scrolledUV) * cloudBlendFactor; - - shOutputColour(0) = float4(cloudColour, 1) * albedo * float4(1,1,1, cloudOpacity * alphaFade); - } - -#endif diff --git a/files/materials/clouds.shaderset b/files/materials/clouds.shaderset deleted file mode 100644 index 5fffb5658..000000000 --- a/files/materials/clouds.shaderset +++ /dev/null @@ -1,15 +0,0 @@ -shader_set clouds_vertex -{ - source clouds.shader - type vertex - profiles_cg vs_2_0 arbvp1 - profiles_hlsl vs_2_0 -} - -shader_set clouds_fragment -{ - source clouds.shader - type fragment - profiles_cg ps_2_x ps_2_0 ps arbfp1 - profiles_hlsl ps_2_0 -} diff --git a/files/materials/core.h b/files/materials/core.h deleted file mode 100644 index e6cde4bda..000000000 --- a/files/materials/core.h +++ /dev/null @@ -1,181 +0,0 @@ -#if SH_HLSL == 1 || SH_CG == 1 - - #define shTexture2D sampler2D - #define shSample(tex, coord) tex2D(tex, coord) - #define shCubicSample(tex, coord) texCUBE(tex, coord) - #define shLerp(a, b, t) lerp(a, b, t) - #define shSaturate(a) saturate(a) - - #define shSampler2D(name) , uniform sampler2D name : register(s@shCounter(0)) @shUseSampler(name) - - #define shSamplerCube(name) , uniform samplerCUBE name : register(s@shCounter(0)) @shUseSampler(name) - - #define shMatrixMult(m, v) mul(m, v) - - #define shUniform(type, name) , uniform type name - - #define shTangentInput(type) , in type tangent : TANGENT - #define shVertexInput(type, name) , in type name : TEXCOORD@shCounter(1) - #define shInput(type, name) , in type name : TEXCOORD@shCounter(1) - #define shOutput(type, name) , out type name : TEXCOORD@shCounter(2) - - #define shNormalInput(type) , in type normal : NORMAL - - #define shColourInput(type) , in type colour : COLOR - - #define shFract(val) frac(val) - - #ifdef SH_VERTEX_SHADER - - #define shOutputPosition oPosition - #define shInputPosition iPosition - - - #define SH_BEGIN_PROGRAM \ - void main( \ - float4 iPosition : POSITION \ - , out float4 oPosition : POSITION - - #define SH_START_PROGRAM \ - ) \ - - #endif - - #ifdef SH_FRAGMENT_SHADER - - #define shOutputColour(num) oColor##num - - #define shDeclareMrtOutput(num) , out float4 oColor##num : COLOR##num - - #define SH_BEGIN_PROGRAM \ - void main( \ - out float4 oColor0 : COLOR - - #define SH_START_PROGRAM \ - ) \ - - #endif - -#endif - -#if SH_GLSL == 1 || SH_GLSLES == 1 - - #define shFract(val) fract(val) - -#if SH_GLSLES == 1 - @version 100 -#else - @version 120 -#endif - -#if SH_GLSLES == 1 -precision mediump int; -precision mediump float; -#endif - - #define float2 vec2 - #define float3 vec3 - #define float4 vec4 - #define int2 ivec2 - #define int3 ivec3 - #define int4 ivec4 - #define shTexture2D sampler2D - #define shSample(tex, coord) texture2D(tex, coord) - #define shCubicSample(tex, coord) textureCube(tex, coord) - #define shLerp(a, b, t) mix(a, b, t) - #define shSaturate(a) clamp(a, 0.0, 1.0) - - #define shUniform(type, name) uniform type name; - - #define shSampler2D(name) uniform sampler2D name; @shUseSampler(name) - - #define shSamplerCube(name) uniform samplerCube name; @shUseSampler(name) - - #define shMatrixMult(m, v) ((m) * (v)) - - #define shOutputPosition gl_Position - - #define float4x4 mat4 - #define float3x3 mat3 - - // GLSL 1.3 - #if 0 - - // automatically recognized by ogre when the input name equals this - #define shInputPosition vertex - - #define shOutputColour(num) oColor##num - - #define shTangentInput(type) in type tangent; - #define shVertexInput(type, name) in type name; - #define shInput(type, name) in type name; - #define shOutput(type, name) out type name; - - // automatically recognized by ogre when the input name equals this - #define shNormalInput(type) in type normal; - #define shColourInput(type) in type colour; - - #ifdef SH_VERTEX_SHADER - - #define SH_BEGIN_PROGRAM \ - in float4 vertex; - #define SH_START_PROGRAM \ - void main(void) - - #endif - - #ifdef SH_FRAGMENT_SHADER - - #define shDeclareMrtOutput(num) out vec4 oColor##num; - - #define SH_BEGIN_PROGRAM \ - out float4 oColor0; - #define SH_START_PROGRAM \ - void main(void) - - - #endif - - #endif - - // GLSL 1.2 - - #if 1 - - // automatically recognized by ogre when the input name equals this - #define shInputPosition vertex - - #define shOutputColour(num) gl_FragData[num] - - #define shTangentInput(type) attribute type tangent; - #define shVertexInput(type, name) attribute type name; - #define shInput(type, name) varying type name; - #define shOutput(type, name) varying type name; - - // automatically recognized by ogre when the input name equals this - #define shNormalInput(type) attribute type normal; - #define shColourInput(type) attribute type colour; - - #ifdef SH_VERTEX_SHADER - - #define SH_BEGIN_PROGRAM \ - attribute vec4 vertex; - #define SH_START_PROGRAM \ - void main(void) - - #endif - - #ifdef SH_FRAGMENT_SHADER - - #define shDeclareMrtOutput(num) - - #define SH_BEGIN_PROGRAM - - #define SH_START_PROGRAM \ - void main(void) - - - #endif - - #endif -#endif diff --git a/files/materials/moon.shader b/files/materials/moon.shader deleted file mode 100644 index 151b94180..000000000 --- a/files/materials/moon.shader +++ /dev/null @@ -1,51 +0,0 @@ -#include "core.h" - -#ifdef SH_VERTEX_SHADER - - SH_BEGIN_PROGRAM - shUniform(float4x4, world) @shAutoConstant(world, world_matrix) - shUniform(float4x4, view) @shAutoConstant(view, view_matrix) -shUniform(float4x4, projection) @shAutoConstant(projection, projection_matrix) - shVertexInput(float2, uv0) - shOutput(float2, UV) - - SH_START_PROGRAM - { - float4x4 viewFixed = view; -#if !SH_GLSL && !SH_GLSLES - viewFixed[0][3] = 0.0; - viewFixed[1][3] = 0.0; - viewFixed[2][3] = 0.0; -#else - viewFixed[3][0] = 0.0; - viewFixed[3][1] = 0.0; - viewFixed[3][2] = 0.0; -#endif - shOutputPosition = shMatrixMult(projection, shMatrixMult(viewFixed, shMatrixMult(world, shInputPosition))); - UV = uv0; - } - -#else - - SH_BEGIN_PROGRAM - shSampler2D(diffuseMap) - shSampler2D(alphaMap) - shInput(float2, UV) - shUniform(float4, materialDiffuse) @shAutoConstant(materialDiffuse, surface_diffuse_colour) - shUniform(float4, materialEmissive) @shAutoConstant(materialEmissive, surface_emissive_colour) - - shUniform(float4, atmosphereColour) @shSharedParameter(atmosphereColour) - - SH_START_PROGRAM - { - float4 phaseTex = shSample(diffuseMap, UV); - float4 fullCircleTex = shSample(alphaMap, UV); - - shOutputColour(0).a = max(phaseTex.a, fullCircleTex.a) * materialDiffuse.a; - - shOutputColour(0).xyz = fullCircleTex.xyz * atmosphereColour.xyz; - shOutputColour(0).xyz = shLerp(shOutputColour(0).xyz, phaseTex.xyz, phaseTex.a); - shOutputColour(0).xyz *= materialEmissive.xyz; - } - -#endif diff --git a/files/materials/moon.shaderset b/files/materials/moon.shaderset deleted file mode 100644 index 659481a96..000000000 --- a/files/materials/moon.shaderset +++ /dev/null @@ -1,15 +0,0 @@ -shader_set moon_vertex -{ - source moon.shader - type vertex - profiles_cg vs_2_0 arbvp1 - profiles_hlsl vs_2_0 -} - -shader_set moon_fragment -{ - source moon.shader - type fragment - profiles_cg ps_2_x ps_2_0 ps arbfp1 - profiles_hlsl ps_2_0 -} diff --git a/files/materials/mygui.mat b/files/materials/mygui.mat deleted file mode 100644 index 78cba3f89..000000000 --- a/files/materials/mygui.mat +++ /dev/null @@ -1,25 +0,0 @@ -material MyGUI/NoTexture -{ - pass - { - vertex_program mygui_vertex - fragment_program mygui_fragment - shader_properties - { - has_texture false - } - } -} - -material MyGUI/OneTexture -{ - pass - { - vertex_program mygui_vertex - fragment_program mygui_fragment - shader_properties - { - has_texture true - } - } -} diff --git a/files/materials/mygui.shader b/files/materials/mygui.shader deleted file mode 100644 index 4d12eba90..000000000 --- a/files/materials/mygui.shader +++ /dev/null @@ -1,45 +0,0 @@ -#include "core.h" - -#define TEXTURE @shPropertyBool(has_texture) - -#ifdef SH_VERTEX_SHADER - - SH_BEGIN_PROGRAM -#if TEXTURE - shVertexInput(float2, uv0) - shOutput(float2, UV) -#endif - shColourInput(float4) - shOutput(float4, colourPassthrough) - - SH_START_PROGRAM - { - shOutputPosition = float4(shInputPosition.xyz, 1.0); -#if TEXTURE - UV.xy = uv0; -#endif - colourPassthrough = colour; - } - -#else - - - SH_BEGIN_PROGRAM - -#if TEXTURE - shSampler2D(diffuseMap) - shInput(float2, UV) -#endif - - shInput(float4, colourPassthrough) - - SH_START_PROGRAM - { -#if TEXTURE - shOutputColour(0) = shSample(diffuseMap, UV.xy) * colourPassthrough; -#else - shOutputColour(0) = colourPassthrough; -#endif - } - -#endif diff --git a/files/materials/mygui.shaderset b/files/materials/mygui.shaderset deleted file mode 100644 index 980cd4caf..000000000 --- a/files/materials/mygui.shaderset +++ /dev/null @@ -1,15 +0,0 @@ -shader_set mygui_vertex -{ - source mygui.shader - type vertex - profiles_cg vs_2_0 vp40 arbvp1 - profiles_hlsl vs_3_0 vs_2_0 -} - -shader_set mygui_fragment -{ - source mygui.shader - type fragment - profiles_cg ps_3_0 ps_2_x ps_2_0 fp40 arbfp1 - profiles_hlsl ps_3_0 ps_2_0 -} diff --git a/files/materials/objects.mat b/files/materials/objects.mat deleted file mode 100644 index 7d3085b0f..000000000 --- a/files/materials/objects.mat +++ /dev/null @@ -1,147 +0,0 @@ -material openmw_objects_base -{ - diffuse 1.0 1.0 1.0 1.0 - specular 0 0 0 0 1 - ambient 1.0 1.0 1.0 - emissive 0.0 0.0 0.0 - vertmode 0 - diffuseMap black.png - normalMap - emissiveMap - specMap - darkMap - use_emissive_map false - use_detail_map false - use_diffuse_map false - use_dark_map false - emissiveMapUVSet 0 - detailMapUVSet 0 - diffuseMapUVSet 0 - darkMapUVSet 0 - use_parallax false - - scene_blend default - depth_write default - depth_check default - alpha_rejection default - transparent_sorting default - polygon_mode default - env_map false - env_map_color 1 1 1 - - alphaTestMode 0 - alphaTestValue 0 - - pass - { - vertex_program openmw_objects_vertex - fragment_program openmw_objects_fragment - - shader_properties - { - vertexcolor_mode $vertmode - normalMap $normalMap - emissiveMapUVSet $emissiveMapUVSet - detailMapUVSet $detailMapUVSet - diffuseMapUVSet $diffuseMapUVSet - darkMapUVSet $darkMapUVSet - emissiveMap $emissiveMap - detailMap $detailMap - diffuseMap $diffuseMap - specMap $specMap - darkMap $darkMap - env_map $env_map - env_map_color $env_map_color - use_parallax $use_parallax - alphaTestMode $alphaTestMode - alphaTestValue $alphaTestValue - } - - diffuse $diffuse - specular $specular - ambient $ambient - emissive $emissive - scene_blend $scene_blend - alpha_rejection $alpha_rejection - depth_write $depth_write - depth_check $depth_check - transparent_sorting $transparent_sorting - polygon_mode $polygon_mode - cull_hardware $cullmode - - texture_unit diffuseMap - { - direct_texture $diffuseMap - create_in_ffp $use_diffuse_map - tex_coord_set $diffuseMapUVSet - tex_address_mode $diffuseMapClampMode - } - - texture_unit normalMap - { - direct_texture $normalMap - // force automips here for now - num_mipmaps 4 - } - - texture_unit darkMap - { - create_in_ffp $use_dark_map - colour_op_ex modulate src_current src_texture - alpha_op_ex modulate src_current src_texture - direct_texture $darkMap - tex_coord_set $darkMapUVSet - tex_address_mode $darkMapClampMode - } - - texture_unit detailMap - { - create_in_ffp $use_detail_map - colour_op_ex modulate_x2 src_current src_texture - direct_texture $detailMap - tex_coord_set $detailMapUVSet - tex_address_mode $detailMapClampMode - } - - texture_unit emissiveMap - { - create_in_ffp $use_emissive_map - colour_op add - direct_texture $emissiveMap - tex_coord_set $emissiveMapUVSet - tex_address_mode $emissiveMapClampMode - } - - texture_unit envMap - { - create_in_ffp $env_map - env_map spherical - anim_texture2 textures\magicitem\caust.dds 32 2 - colour_op add - } - - texture_unit specMap - { - direct_texture $specMap - } - - texture_unit shadowMap0 - { - content_type shadow - tex_address_mode clamp - filtering none - } - texture_unit shadowMap1 - { - content_type shadow - tex_address_mode clamp - filtering none - } - texture_unit shadowMap2 - { - content_type shadow - tex_address_mode clamp - filtering none - } - } -} diff --git a/files/materials/objects.shader b/files/materials/objects.shader deleted file mode 100644 index 5c74b1139..000000000 --- a/files/materials/objects.shader +++ /dev/null @@ -1,591 +0,0 @@ -#include "core.h" - - -#define FOG @shGlobalSettingBool(fog) - -#define SHADOWS_PSSM @shGlobalSettingBool(shadows_pssm) -#define SHADOWS @shGlobalSettingBool(shadows) - -#if SHADOWS || SHADOWS_PSSM - #include "shadows.h" -#endif - -#if FOG || SHADOWS_PSSM -#define NEED_DEPTH -#endif - -#define SPECULAR 1 - -#define NORMAL_MAP @shPropertyHasValue(normalMap) -#define EMISSIVE_MAP @shPropertyHasValue(emissiveMap) -#define DETAIL_MAP @shPropertyHasValue(detailMap) -#define DIFFUSE_MAP @shPropertyHasValue(diffuseMap) -#define DARK_MAP @shPropertyHasValue(darkMap) -#define SPEC_MAP @shPropertyHasValue(specMap) && SPECULAR - -#define ALPHATEST_MODE @shPropertyString(alphaTestMode) - -#define PARALLAX @shPropertyBool(use_parallax) -#define PARALLAX_SCALE 0.04 -#define PARALLAX_BIAS -0.02 - -// right now we support 2 UV sets max. implementing them is tedious, and we're probably not going to need more -#define SECOND_UV_SET (@shPropertyString(emissiveMapUVSet) || @shPropertyString(detailMapUVSet) || @shPropertyString(diffuseMapUVSet) || @shPropertyString(darkMapUVSet)) - -// if normal mapping is enabled, we force pixel lighting -#define VERTEX_LIGHTING (!@shPropertyHasValue(normalMap)) - -#define UNDERWATER @shGlobalSettingBool(render_refraction) - -#define VERTEXCOLOR_MODE @shPropertyString(vertexcolor_mode) - -#define VIEWPROJ_FIX @shGlobalSettingBool(viewproj_fix) - -#define ENV_MAP @shPropertyBool(env_map) - -#define NEED_NORMAL (!VERTEX_LIGHTING || ENV_MAP) || SPECULAR - -#ifdef SH_VERTEX_SHADER - - // ------------------------------------- VERTEX --------------------------------------- - - SH_BEGIN_PROGRAM - shUniform(float4x4, wvp) @shAutoConstant(wvp, worldviewproj_matrix) - - shUniform(float4x4, textureMatrix0) @shAutoConstant(textureMatrix0, texture_matrix, 0) - -#if (VIEWPROJ_FIX) || (SHADOWS) - shUniform(float4x4, worldMatrix) @shAutoConstant(worldMatrix, world_matrix) -#endif - -#if VIEWPROJ_FIX - shUniform(float4, vpRow2Fix) @shSharedParameter(vpRow2Fix, vpRow2Fix) - shUniform(float4x4, vpMatrix) @shAutoConstant(vpMatrix, viewproj_matrix) -#endif - - shVertexInput(float2, uv0) -#if SECOND_UV_SET - shVertexInput(float2, uv1) -#endif - shOutput(float4, UV) - - shNormalInput(float4) - -#if NORMAL_MAP - shTangentInput(float4) - shOutput(float3, tangentPassthrough) -#endif - -#if NEED_NORMAL - shOutput(float3, normalPassthrough) -#endif - - // Depth in w - shOutput(float4, objSpacePositionPassthrough) - -#if VERTEXCOLOR_MODE != 0 - shColourInput(float4) -#endif - -#if VERTEXCOLOR_MODE != 0 && !VERTEX_LIGHTING - shOutput(float4, colourPassthrough) -#endif - -#if ENV_MAP || VERTEX_LIGHTING - shUniform(float4x4, worldView) @shAutoConstant(worldView, worldview_matrix) -#endif - -#if VERTEX_LIGHTING - shUniform(float4, lightPosition[@shGlobalSettingString(num_lights)]) @shAutoConstant(lightPosition, light_position_view_space_array, @shGlobalSettingString(num_lights)) - shUniform(float4, lightDiffuse[@shGlobalSettingString(num_lights)]) @shAutoConstant(lightDiffuse, light_diffuse_colour_array, @shGlobalSettingString(num_lights)) - shUniform(float4, lightAttenuation[@shGlobalSettingString(num_lights)]) @shAutoConstant(lightAttenuation, light_attenuation_array, @shGlobalSettingString(num_lights)) - shUniform(float4, lightAmbient) @shAutoConstant(lightAmbient, ambient_light_colour) -#if VERTEXCOLOR_MODE != 2 - shUniform(float4, materialAmbient) @shAutoConstant(materialAmbient, surface_ambient_colour) -#endif - shUniform(float4, materialDiffuse) @shAutoConstant(materialDiffuse, surface_diffuse_colour) -#if VERTEXCOLOR_MODE != 1 - shUniform(float4, materialEmissive) @shAutoConstant(materialEmissive, surface_emissive_colour) -#endif - -#endif - -#if SHADOWS - shOutput(float4, lightSpacePos0) - shUniform(float4x4, texViewProjMatrix0) @shAutoConstant(texViewProjMatrix0, texture_viewproj_matrix) -#endif - -#if SHADOWS_PSSM - @shForeach(3) - shOutput(float4, lightSpacePos@shIterator) - shUniform(float4x4, texViewProjMatrix@shIterator) @shAutoConstant(texViewProjMatrix@shIterator, texture_viewproj_matrix, @shIterator) - @shEndForeach -#if !VIEWPROJ_FIX - shUniform(float4x4, worldMatrix) @shAutoConstant(worldMatrix, world_matrix) -#endif -#endif - -#if VERTEX_LIGHTING - shOutput(float4, lightResult) - shOutput(float3, directionalResult) -#endif - SH_START_PROGRAM - { - shOutputPosition = shMatrixMult(wvp, shInputPosition); - - UV.xy = shMatrixMult (textureMatrix0, float4(uv0,0,1)).xy; -#if SECOND_UV_SET - UV.zw = uv1; -#endif - -#if ENV_MAP || VERTEX_LIGHTING - float3 viewNormal = normalize(shMatrixMult(worldView, float4(normal.xyz, 0)).xyz); -#endif - -#if ENV_MAP - float3 viewVec = normalize( shMatrixMult(worldView, shInputPosition).xyz); - - float3 r = reflect( viewVec, viewNormal ); - float m = 2.0 * sqrt( r.x*r.x + r.y*r.y + (r.z+1.0)*(r.z+1.0) ); - UV.z = r.x/m + 0.5; - UV.w = r.y/m + 0.5; -#endif - -#if NORMAL_MAP - tangentPassthrough = tangent.xyz; -#endif -#if NEED_NORMAL - normalPassthrough = normal.xyz; -#endif -#if VERTEXCOLOR_MODE != 0 && !VERTEX_LIGHTING - colourPassthrough = colour; -#endif - -#ifdef NEED_DEPTH - - -#if VIEWPROJ_FIX - float4x4 vpFixed = vpMatrix; -#if !SH_GLSL && !SH_GLSLES - vpFixed[2] = vpRow2Fix; -#else - vpFixed[0][2] = vpRow2Fix.x; - vpFixed[1][2] = vpRow2Fix.y; - vpFixed[2][2] = vpRow2Fix.z; - vpFixed[3][2] = vpRow2Fix.w; -#endif - - float4x4 fixedWVP = shMatrixMult(vpFixed, worldMatrix); - - objSpacePositionPassthrough.w = shMatrixMult(fixedWVP, shInputPosition).z; -#else - objSpacePositionPassthrough.w = shOutputPosition.z; -#endif - -#endif - - objSpacePositionPassthrough.xyz = shInputPosition.xyz; - -#if SHADOWS - lightSpacePos0 = shMatrixMult(texViewProjMatrix0, shMatrixMult(worldMatrix, shInputPosition)); -#endif -#if SHADOWS_PSSM - float4 wPos = shMatrixMult(worldMatrix, shInputPosition); - @shForeach(3) - lightSpacePos@shIterator = shMatrixMult(texViewProjMatrix@shIterator, wPos); - @shEndForeach -#endif - - -#if VERTEX_LIGHTING - float3 viewPos = shMatrixMult(worldView, shInputPosition).xyz; - - float3 lightDir; - float d; - lightResult = float4(0,0,0,1); - @shForeach(@shGlobalSettingString(num_lights)) - lightDir = lightPosition[@shIterator].xyz - (viewPos * lightPosition[@shIterator].w); - d = length(lightDir); - lightDir = normalize(lightDir); - - -#if VERTEXCOLOR_MODE == 2 - lightResult.xyz += colour.xyz * lightDiffuse[@shIterator].xyz - * shSaturate(1.0 / ((lightAttenuation[@shIterator].y) + (lightAttenuation[@shIterator].z * d) + (lightAttenuation[@shIterator].w * d * d))) - * max(dot(viewNormal.xyz, lightDir), 0.0); -#else - lightResult.xyz += materialDiffuse.xyz * lightDiffuse[@shIterator].xyz - * shSaturate(1.0 / ((lightAttenuation[@shIterator].y) + (lightAttenuation[@shIterator].z * d) + (lightAttenuation[@shIterator].w * d * d))) - * max(dot(viewNormal.xyz, lightDir), 0.0); -#endif - -#if @shIterator == 0 - directionalResult = lightResult.xyz; -#endif - - @shEndForeach - - -#if VERTEXCOLOR_MODE == 2 - lightResult.xyz += lightAmbient.xyz * colour.xyz + materialEmissive.xyz; - lightResult.a *= colour.a; -#endif -#if VERTEXCOLOR_MODE == 1 - lightResult.xyz += lightAmbient.xyz * materialAmbient.xyz + colour.xyz; -#endif -#if VERTEXCOLOR_MODE == 0 - lightResult.xyz += lightAmbient.xyz * materialAmbient.xyz + materialEmissive.xyz; -#endif - - lightResult.a *= materialDiffuse.a; - -#endif - } - -#else -#if NORMAL_MAP && SH_GLSLES - mat3 transpose( mat3 m); -#endif - // ----------------------------------- FRAGMENT ------------------------------------------ - -#if UNDERWATER - #include "underwater.h" -#endif - - SH_BEGIN_PROGRAM -#if DIFFUSE_MAP - shSampler2D(diffuseMap) -#endif - -#if NORMAL_MAP - shSampler2D(normalMap) -#endif - -#if DARK_MAP - shSampler2D(darkMap) -#endif - -#if DETAIL_MAP - shSampler2D(detailMap) -#endif - -#if EMISSIVE_MAP - shSampler2D(emissiveMap) -#endif - -#if ENV_MAP - shSampler2D(envMap) - shUniform(float3, env_map_color) @shUniformProperty3f(env_map_color, env_map_color) -#endif - -#if SPEC_MAP - shSampler2D(specMap) -#endif - -#if ENV_MAP || SPECULAR || PARALLAX - shUniform(float3, cameraPosObjSpace) @shAutoConstant(cameraPosObjSpace, camera_position_object_space) -#endif -#if SPECULAR - shUniform(float3, lightSpec0) @shAutoConstant(lightSpec0, light_specular_colour, 0) - shUniform(float3, lightPosObjSpace0) @shAutoConstant(lightPosObjSpace0, light_position_object_space, 0) - shUniform(float, matShininess) @shAutoConstant(matShininess, surface_shininess) - shUniform(float3, matSpec) @shAutoConstant(matSpec, surface_specular_colour) -#endif - - shInput(float4, UV) - -#if NORMAL_MAP - shInput(float3, tangentPassthrough) -#endif -#if NEED_NORMAL - shInput(float3, normalPassthrough) -#endif - - shInput(float4, objSpacePositionPassthrough) - -#if VERTEXCOLOR_MODE != 0 && !VERTEX_LIGHTING - shInput(float4, colourPassthrough) -#endif - -#if FOG - shUniform(float3, fogColour) @shAutoConstant(fogColour, fog_colour) - shUniform(float4, fogParams) @shAutoConstant(fogParams, fog_params) -#endif - -#if SHADOWS - shInput(float4, lightSpacePos0) - shSampler2D(shadowMap0) - shUniform(float2, invShadowmapSize0) @shAutoConstant(invShadowmapSize0, inverse_texture_size, 1) -#endif -#if SHADOWS_PSSM - @shForeach(3) - shInput(float4, lightSpacePos@shIterator) - shSampler2D(shadowMap@shIterator) - shUniform(float2, invShadowmapSize@shIterator) @shAutoConstant(invShadowmapSize@shIterator, inverse_texture_size, @shIterator(1)) - @shEndForeach - shUniform(float3, pssmSplitPoints) @shSharedParameter(pssmSplitPoints) -#endif - -#if SHADOWS || SHADOWS_PSSM - shUniform(float4, shadowFar_fadeStart) @shSharedParameter(shadowFar_fadeStart) -#endif - -#if (UNDERWATER) || (FOG) - shUniform(float4x4, worldMatrix) @shAutoConstant(worldMatrix, world_matrix) - shUniform(float4, cameraPos) @shAutoConstant(cameraPos, camera_position) -#endif - -#if UNDERWATER - shUniform(float, waterLevel) @shSharedParameter(waterLevel) - shUniform(float, waterEnabled) @shSharedParameter(waterEnabled) -#endif - -#if VERTEX_LIGHTING - shInput(float4, lightResult) - shInput(float3, directionalResult) -#else - shUniform(float4, lightPosition[@shGlobalSettingString(num_lights)]) @shAutoConstant(lightPosition, light_position_view_space_array, @shGlobalSettingString(num_lights)) - shUniform(float4, lightDiffuse[@shGlobalSettingString(num_lights)]) @shAutoConstant(lightDiffuse, light_diffuse_colour_array, @shGlobalSettingString(num_lights)) - shUniform(float4, lightAttenuation[@shGlobalSettingString(num_lights)]) @shAutoConstant(lightAttenuation, light_attenuation_array, @shGlobalSettingString(num_lights)) - shUniform(float4, lightAmbient) @shAutoConstant(lightAmbient, ambient_light_colour) - shUniform(float4x4, worldView) @shAutoConstant(worldView, worldview_matrix) - #if VERTEXCOLOR_MODE != 2 - shUniform(float4, materialAmbient) @shAutoConstant(materialAmbient, surface_ambient_colour) - #endif - shUniform(float4, materialDiffuse) @shAutoConstant(materialDiffuse, surface_diffuse_colour) - #if VERTEXCOLOR_MODE != 1 - shUniform(float4, materialEmissive) @shAutoConstant(materialEmissive, surface_emissive_colour) - #endif -#endif - -#if ALPHATEST_MODE != 0 - shUniform(float, alphaTestValue) @shUniformProperty1f(alphaTestValue, alphaTestValue) -#endif - - SH_START_PROGRAM - { - float4 newUV = UV; - -#ifdef NEED_DEPTH - float depthPassthrough = objSpacePositionPassthrough.w; -#endif - -#if NEED_NORMAL - float3 normal = normalPassthrough; -#endif - -#if NORMAL_MAP - float3 binormal = cross(tangentPassthrough.xyz, normal.xyz); - float3x3 tbn = float3x3(tangentPassthrough.xyz, binormal, normal.xyz); - - #if SH_GLSL || SH_GLSLES - tbn = transpose(tbn); - #endif - - float4 normalTex = shSample(normalMap, UV.xy); - - normal = normalize (shMatrixMult( transpose(tbn), normalTex.xyz * 2.0 - 1.0 )); -#endif - -#if ENV_MAP || SPECULAR || PARALLAX - float3 eyeDir = normalize(cameraPosObjSpace.xyz - objSpacePositionPassthrough.xyz); -#endif - -#if PARALLAX - float3 TSeyeDir = normalize(shMatrixMult(tbn, eyeDir)); - - newUV += (TSeyeDir.xyxy * ( normalTex.a * PARALLAX_SCALE + PARALLAX_BIAS )).xyxy; -#endif - -#if DIFFUSE_MAP - #if @shPropertyString(diffuseMapUVSet) - float4 diffuse = shSample(diffuseMap, newUV.zw); - #else - float4 diffuse = shSample(diffuseMap, newUV.xy); - #endif -#else - float4 diffuse = float4(1,1,1,1); -#endif - -#if ALPHATEST_MODE == 1 - if (diffuse.a >= alphaTestValue) - discard; -#elif ALPHATEST_MODE == 2 - if (diffuse.a != alphaTestValue) - discard; -#elif ALPHATEST_MODE == 3 - if (diffuse.a > alphaTestValue) - discard; -#elif ALPHATEST_MODE == 4 - if (diffuse.a <= alphaTestValue) - discard; -#elif ALPHATEST_MODE == 5 - if (diffuse.a == alphaTestValue) - discard; -#elif ALPHATEST_MODE == 6 - if (diffuse.a < alphaTestValue) - discard; -#elif ALPHATEST_MODE == 7 - discard; -#endif - - -#if DETAIL_MAP -#if @shPropertyString(detailMapUVSet) - diffuse *= shSample(detailMap, newUV.zw)*2; -#else - diffuse *= shSample(detailMap, newUV.xy)*2; -#endif -#endif - -#if DARK_MAP -#if @shPropertyString(darkMapUVSet) - diffuse *= shSample(darkMap, newUV.zw); -#else - diffuse *= shSample(darkMap, newUV.xy); -#endif -#endif - - shOutputColour(0) = diffuse; - -#if !VERTEX_LIGHTING - float3 viewPos = shMatrixMult(worldView, float4(objSpacePositionPassthrough.xyz,1)).xyz; - float3 viewNormal = normalize(shMatrixMult(worldView, float4(normal.xyz, 0)).xyz); - - float3 lightDir; - float d; - float4 lightResult = float4(0,0,0,1); - @shForeach(@shGlobalSettingString(num_lights)) - lightDir = lightPosition[@shIterator].xyz - (viewPos * lightPosition[@shIterator].w); - d = length(lightDir); - lightDir = normalize(lightDir); - -#if VERTEXCOLOR_MODE == 2 - lightResult.xyz += colourPassthrough.xyz * lightDiffuse[@shIterator].xyz - * shSaturate(1.0 / ((lightAttenuation[@shIterator].y) + (lightAttenuation[@shIterator].z * d) + (lightAttenuation[@shIterator].w * d * d))) - * max(dot(viewNormal.xyz, lightDir), 0.0); -#else - lightResult.xyz += materialDiffuse.xyz * lightDiffuse[@shIterator].xyz - * shSaturate(1.0 / ((lightAttenuation[@shIterator].y) + (lightAttenuation[@shIterator].z * d) + (lightAttenuation[@shIterator].w * d * d))) - * max(dot(viewNormal.xyz, lightDir), 0.0); -#endif - -#if @shIterator == 0 - float3 directionalResult = lightResult.xyz; -#endif - - @shEndForeach - - -#if VERTEXCOLOR_MODE == 2 - lightResult.xyz += lightAmbient.xyz * colourPassthrough.xyz + materialEmissive.xyz; - lightResult.a *= colourPassthrough.a; -#endif -#if VERTEXCOLOR_MODE == 1 - lightResult.xyz += lightAmbient.xyz * materialAmbient.xyz + colourPassthrough.xyz; -#endif -#if VERTEXCOLOR_MODE == 0 - lightResult.xyz += lightAmbient.xyz * materialAmbient.xyz + materialEmissive.xyz; -#endif - - lightResult.a *= materialDiffuse.a; -#endif - - // shadows only for the first (directional) light -#if SHADOWS - float shadow = depthShadowPCF (shadowMap0, lightSpacePos0, invShadowmapSize0); -#endif -#if SHADOWS_PSSM - float shadow = pssmDepthShadow (lightSpacePos0, invShadowmapSize0, shadowMap0, lightSpacePos1, invShadowmapSize1, shadowMap1, lightSpacePos2, invShadowmapSize2, shadowMap2, depthPassthrough, pssmSplitPoints); -#endif - -#if SHADOWS || SHADOWS_PSSM - float fadeRange = shadowFar_fadeStart.x - shadowFar_fadeStart.y; - float fade = 1.0-((depthPassthrough - shadowFar_fadeStart.y) / fadeRange); - shadow = (depthPassthrough > shadowFar_fadeStart.x) ? 1.0 : ((depthPassthrough > shadowFar_fadeStart.y) ? 1.0-((1.0-shadow)*fade) : shadow); -#endif - -#if !SHADOWS && !SHADOWS_PSSM - float shadow = 1.0; -#endif - - - -#if (UNDERWATER) || (FOG) - float3 worldPos = shMatrixMult(worldMatrix, float4(objSpacePositionPassthrough.xyz,1)).xyz; -#endif - -#if UNDERWATER - float3 waterEyePos = intercept(worldPos, cameraPos.xyz - worldPos, float3(0.0,0.0,1.0), waterLevel); -#endif - -#if SHADOWS || SHADOWS_PSSM - shOutputColour(0) *= (lightResult - float4(directionalResult * (1.0-shadow),0.0)); -#else - shOutputColour(0) *= lightResult; -#endif - -#if EMISSIVE_MAP - #if @shPropertyString(emissiveMapUVSet) - shOutputColour(0).xyz += shSample(emissiveMap, newUV.zw).xyz; - #else - shOutputColour(0).xyz += shSample(emissiveMap, newUV.xy).xyz; - #endif -#endif - -#if ENV_MAP - // Everything looks better with fresnel - float facing = 1.0 - max(abs(dot(-eyeDir, normal)), 0.0); - float envFactor = shSaturate(0.25 + 0.75 * pow(facing, 1.0)); - - shOutputColour(0).xyz += shSample(envMap, UV.zw).xyz * envFactor * env_map_color; -#endif - -#if SPECULAR - float3 light0Dir = normalize(lightPosObjSpace0.xyz); - - float NdotL = max(dot(normal, light0Dir), 0.0); - float3 halfVec = normalize (light0Dir + eyeDir); - - float shininess = matShininess; -#if SPEC_MAP - float4 specTex = shSample(specMap, UV.xy); - shininess *= (specTex.a); -#endif - - float3 specular = pow(max(dot(normal, halfVec), 0.0), shininess) * lightSpec0 * matSpec; -#if SPEC_MAP - specular *= specTex.xyz; -#else - specular *= diffuse.a; -#endif - - shOutputColour(0).xyz += specular * shadow; -#endif - -#if FOG - float fogValue = shSaturate((depthPassthrough - fogParams.y) * fogParams.w); - - -#if UNDERWATER - shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, UNDERWATER_COLOUR, shSaturate(length(waterEyePos-worldPos) / VISIBILITY)); -#else - shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, fogColour, fogValue); -#endif - -#endif - - // prevent negative colour output (for example with negative lights) - shOutputColour(0).xyz = max(shOutputColour(0).xyz, float3(0.0,0.0,0.0)); - } -#if NORMAL_MAP && SH_GLSLES - mat3 transpose(mat3 m){ - return mat3( - m[0][0],m[1][0],m[2][0], - m[0][1],m[1][1],m[2][1], - m[0][2],m[1][2],m[2][2] - ); - } -#endif - -#endif diff --git a/files/materials/objects.shaderset b/files/materials/objects.shaderset deleted file mode 100644 index 028c15ce8..000000000 --- a/files/materials/objects.shaderset +++ /dev/null @@ -1,15 +0,0 @@ -shader_set openmw_objects_vertex -{ - source objects.shader - type vertex - profiles_cg vs_2_0 vp40 arbvp1 - profiles_hlsl vs_3_0 vs_2_0 -} - -shader_set openmw_objects_fragment -{ - source objects.shader - type fragment - profiles_cg ps_3_0 ps_2_x ps_2_0 fp40 arbfp1 - profiles_hlsl ps_3_0 ps_2_0 -} diff --git a/files/materials/openmw.configuration b/files/materials/openmw.configuration deleted file mode 100644 index b953a9131..000000000 --- a/files/materials/openmw.configuration +++ /dev/null @@ -1,20 +0,0 @@ -configuration water_reflection -{ - shadows false - shadows_pssm false - viewproj_fix true -} - -configuration water_refraction -{ - viewproj_fix true - render_refraction true -} - -configuration local_map -{ - fog false - shadows false - shadows_pssm false - simple_water true -} diff --git a/files/materials/quad.mat b/files/materials/quad.mat deleted file mode 100644 index 77a2c0c34..000000000 --- a/files/materials/quad.mat +++ /dev/null @@ -1,22 +0,0 @@ -material quad -{ - depth_write on - - pass - { - vertex_program transform_vertex - fragment_program quad_fragment - - depth_write $depth_write - - texture_unit SceneBuffer - { - } - } -} - -material quad_noDepthWrite -{ - parent quad - depth_write off -} diff --git a/files/materials/quad.shader b/files/materials/quad.shader deleted file mode 100644 index 4620588c3..000000000 --- a/files/materials/quad.shader +++ /dev/null @@ -1,25 +0,0 @@ -#include "core.h" - -#ifdef SH_VERTEX_SHADER - - SH_BEGIN_PROGRAM - shVertexInput(float2, uv0) - shOutput(float2, UV) - shUniform(float4x4, wvp) @shAutoConstant(wvp, worldviewproj_matrix) - SH_START_PROGRAM - { - shOutputPosition = shMatrixMult(wvp, shInputPosition); - UV = uv0; - } - -#else - - SH_BEGIN_PROGRAM - shInput(float2, UV) - shSampler2D(SceneBuffer) - SH_START_PROGRAM - { - shOutputColour(0) = shSample(SceneBuffer, UV); - } - -#endif diff --git a/files/materials/quad.shaderset b/files/materials/quad.shaderset deleted file mode 100644 index 71fd82da4..000000000 --- a/files/materials/quad.shaderset +++ /dev/null @@ -1,15 +0,0 @@ -shader_set transform_vertex -{ - source quad.shader - type vertex - profiles_cg vs_2_0 vp40 arbvp1 - profiles_hlsl vs_2_0 -} - -shader_set quad_fragment -{ - source quad.shader - type fragment - profiles_cg ps_2_x ps_2_0 ps fp40 arbfp1 - profiles_hlsl ps_2_0 -} diff --git a/files/materials/ripples.particle b/files/materials/ripples.particle deleted file mode 100644 index 58045f6d7..000000000 --- a/files/materials/ripples.particle +++ /dev/null @@ -1,26 +0,0 @@ -particle_system openmw/Ripples -{ - material openmw/Ripple - particle_width 30 - particle_height 30 - // To make the particles move with the scene node when the waterlevel changes - local_space true - quota 300 - billboard_type perpendicular_common - common_up_vector 0 1 0 - common_direction 0 0 1 - - affector ColourFader - { - alpha -0.33 - } - - affector Scaler - { - rate 120 - } - - affector Rotator - { - } -} diff --git a/files/materials/selection.mat b/files/materials/selection.mat deleted file mode 100644 index 2cb92f884..000000000 --- a/files/materials/selection.mat +++ /dev/null @@ -1,9 +0,0 @@ -material SelectionColour -{ - allow_fixed_function false - pass - { - vertex_program selection_vertex - fragment_program selection_fragment - } -} diff --git a/files/materials/selection.shader b/files/materials/selection.shader deleted file mode 100644 index 095a31259..000000000 --- a/files/materials/selection.shader +++ /dev/null @@ -1,24 +0,0 @@ -#include "core.h" - -#ifdef SH_VERTEX_SHADER - - SH_BEGIN_PROGRAM - shUniform(float4x4, wvp) @shAutoConstant(wvp, worldviewproj_matrix) - - SH_START_PROGRAM - { - shOutputPosition = shMatrixMult(wvp, shInputPosition); - } - -#else - - SH_BEGIN_PROGRAM - shUniform(float4, colour) @shAutoConstant(colour, custom, 1) - - SH_START_PROGRAM - { - shOutputColour(0) = colour; - //shOutputColour(0) = float4(1,0,0,1); - } - -#endif diff --git a/files/materials/selection.shaderset b/files/materials/selection.shaderset deleted file mode 100644 index c90826282..000000000 --- a/files/materials/selection.shaderset +++ /dev/null @@ -1,15 +0,0 @@ -shader_set selection_vertex -{ - source selection.shader - type vertex - profiles_cg vs_2_0 arbvp1 - profiles_hlsl vs_2_0 -} - -shader_set selection_fragment -{ - source selection.shader - type fragment - profiles_cg ps_2_x ps_2_0 ps arbfp1 - profiles_hlsl ps_2_0 -} diff --git a/files/materials/shadowcaster.mat b/files/materials/shadowcaster.mat deleted file mode 100644 index 5c5c8e088..000000000 --- a/files/materials/shadowcaster.mat +++ /dev/null @@ -1,35 +0,0 @@ -material openmw_shadowcaster_default -{ - create_configuration Default - allow_fixed_function false - pass - { - fog_override true - - vertex_program openmw_shadowcaster_vertex - fragment_program openmw_shadowcaster_fragment - - shader_properties - { - shadow_transparency true - } - } -} - -material openmw_shadowcaster_noalpha -{ - create_configuration Default - allow_fixed_function false - pass - { - fog_override true - - vertex_program openmw_shadowcaster_vertex - fragment_program openmw_shadowcaster_fragment - - shader_properties - { - shadow_transparency false - } - } -} diff --git a/files/materials/shadowcaster.shader b/files/materials/shadowcaster.shader deleted file mode 100644 index 8f7911553..000000000 --- a/files/materials/shadowcaster.shader +++ /dev/null @@ -1,55 +0,0 @@ -#include "core.h" - -#define ALPHA @shPropertyBool(shadow_transparency) - -#ifdef SH_VERTEX_SHADER - - SH_BEGIN_PROGRAM -#if ALPHA - shVertexInput(float2, uv0) - shOutput(float2, UV) -#endif - shUniform(float4x4, wvp) @shAutoConstant(wvp, worldviewproj_matrix) - shOutput(float2, depth) - SH_START_PROGRAM - { - // this is the view space position - shOutputPosition = shMatrixMult(wvp, shInputPosition); - - // depth info for the fragment. - depth.x = shOutputPosition.z; - depth.y = shOutputPosition.w; - - // clamp z to zero. seem to do the trick. :-/ - shOutputPosition.z = max(shOutputPosition.z, 0.0); - -#if ALPHA - UV = uv0; -#endif - } - -#else - - SH_BEGIN_PROGRAM -#if ALPHA - shInput(float2, UV) - shSampler2D(texture1) -#endif - shInput(float2, depth) - SH_START_PROGRAM - { - float finalDepth = depth.x / depth.y; - - -#if ALPHA - // use alpha channel of the first texture - float alpha = shSample(texture1, UV).a; - - if (alpha < 0.5) - discard; -#endif - - shOutputColour(0) = float4(finalDepth, finalDepth, finalDepth, 1.0); - } - -#endif diff --git a/files/materials/shadowcaster.shaderset b/files/materials/shadowcaster.shaderset deleted file mode 100644 index 5f4990ed1..000000000 --- a/files/materials/shadowcaster.shaderset +++ /dev/null @@ -1,15 +0,0 @@ -shader_set openmw_shadowcaster_vertex -{ - source shadowcaster.shader - type vertex - profiles_cg vs_2_0 arbvp1 - profiles_hlsl vs_2_0 -} - -shader_set openmw_shadowcaster_fragment -{ - source shadowcaster.shader - type fragment - profiles_cg ps_2_x ps_2_0 ps arbfp1 - profiles_hlsl ps_2_0 -} diff --git a/files/materials/shadows.h b/files/materials/shadows.h deleted file mode 100644 index eba3a3ea7..000000000 --- a/files/materials/shadows.h +++ /dev/null @@ -1,51 +0,0 @@ - -#define FIXED_BIAS 0.0003 - -float depthShadowPCF (shTexture2D shadowMap, float4 shadowMapPos, float2 offset) -{ - shadowMapPos /= shadowMapPos.w; - float3 o = float3(offset.xy, -offset.x) * 0.3; - //float3 o = float3(0,0,0); - float c = (shadowMapPos.z <= FIXED_BIAS + shSample(shadowMap, shadowMapPos.xy - o.xy).r) ? 1.0 : 0.0; // top left - c += (shadowMapPos.z <= FIXED_BIAS + shSample(shadowMap, shadowMapPos.xy + o.xy).r) ? 1.0 : 0.0; // bottom right - c += (shadowMapPos.z <= FIXED_BIAS + shSample(shadowMap, shadowMapPos.xy + o.zy).r) ? 1.0 : 0.0; // bottom left - c += (shadowMapPos.z <= FIXED_BIAS + shSample(shadowMap, shadowMapPos.xy - o.zy).r) ? 1.0 : 0.0; // top right - return c / 4.0; -} - - - -float pssmDepthShadow ( - - - float4 lightSpacePos0, - float2 invShadowmapSize0, - shTexture2D shadowMap0, - - float4 lightSpacePos1, - float2 invShadowmapSize1, - shTexture2D shadowMap1, - - float4 lightSpacePos2, - float2 invShadowmapSize2, - shTexture2D shadowMap2, - - float depth, - float3 pssmSplitPoints) - -{ - float shadow; - - float pcf1 = depthShadowPCF(shadowMap0, lightSpacePos0, invShadowmapSize0); - float pcf2 = depthShadowPCF(shadowMap1, lightSpacePos1, invShadowmapSize1); - float pcf3 = depthShadowPCF(shadowMap2, lightSpacePos2, invShadowmapSize2); - - if (depth < pssmSplitPoints.x) - shadow = pcf1; - else if (depth < pssmSplitPoints.y) - shadow = pcf2; - else - shadow = pcf3; - - return shadow; -} diff --git a/files/materials/sky.mat b/files/materials/sky.mat deleted file mode 100644 index c2e8ddeb0..000000000 --- a/files/materials/sky.mat +++ /dev/null @@ -1,140 +0,0 @@ -material QueryTotalPixels -{ - allow_fixed_function false - pass - { - vertex_program sun_vertex - fragment_program sun_fragment - cull_hardware none - polygon_mode_overrideable off - depth_check off - depth_write off - colour_write off - } -} - -material QueryVisiblePixels -{ - allow_fixed_function false - pass - { - vertex_program sun_vertex - fragment_program sun_fragment - cull_hardware none - cull_software none - polygon_mode_overrideable off - depth_check on - depth_write off - colour_write off - } -} - -material openmw_moon -{ - allow_fixed_function false - pass - { - vertex_program moon_vertex - fragment_program moon_fragment - cull_hardware none - - polygon_mode_overrideable off - depth_write off - depth_check off - scene_blend alpha_blend - - texture_unit diffuseMap - { - texture_alias $texture - } - - texture_unit alphaMap - { - texture_alias $alphatexture - } - } -} - -material openmw_clouds -{ - allow_fixed_function false - pass - { - vertex_program clouds_vertex - fragment_program clouds_fragment - - polygon_mode_overrideable off - - scene_blend alpha_blend - depth_write off - - // second diffuse map is used for weather transitions - texture_unit diffuseMap1 - { - texture_alias cloud_texture_1 - } - - texture_unit diffuseMap2 - { - texture_alias cloud_texture_2 - } - } -} - -material openmw_atmosphere -{ - allow_fixed_function false - pass - { - vertex_program atmosphere_vertex - fragment_program atmosphere_fragment - - polygon_mode_overrideable off - - depth_write off - } -} - -material openmw_stars -{ - allow_fixed_function false - pass - { - vertex_program stars_vertex - fragment_program stars_fragment - - polygon_mode_overrideable off - - depth_check off - depth_write off - scene_blend alpha_blend - - texture_unit diffuseMap - { - direct_texture $texture - } - } -} - -// used for both sun and sun glare -material openmw_sun -{ - allow_fixed_function false - pass - { - vertex_program sun_vertex - fragment_program sun_fragment - cull_hardware none - - polygon_mode_overrideable off - - depth_check off - depth_write off - scene_blend alpha_blend - - texture_unit diffuseMap - { - direct_texture $texture - } - } -} diff --git a/files/materials/stars.shader b/files/materials/stars.shader deleted file mode 100644 index 830be862a..000000000 --- a/files/materials/stars.shader +++ /dev/null @@ -1,48 +0,0 @@ -#include "core.h" - -#ifdef SH_VERTEX_SHADER - - SH_BEGIN_PROGRAM - shUniform(float4x4, worldview) @shAutoConstant(worldview, worldview_matrix) - shUniform(float4x4, proj) @shAutoConstant(proj, projection_matrix) - - shVertexInput(float2, uv0) - shOutput(float2, UV) - shOutput(float, fade) - - SH_START_PROGRAM - { - float4x4 worldviewFixed = worldview; -#if !SH_GLSL && !SH_GLSLES - worldviewFixed[0][3] = 0.0; - worldviewFixed[1][3] = 0.0; - worldviewFixed[2][3] = 0.0; -#else - worldviewFixed[3][0] = 0.0; - worldviewFixed[3][1] = 0.0; - worldviewFixed[3][2] = 0.0; -#endif - - shOutputPosition = shMatrixMult(proj, shMatrixMult(worldviewFixed, shInputPosition)); - UV = uv0; - - fade = (shInputPosition.z > 50.0) ? 1.0 : 0.0; - } - -#else - - SH_BEGIN_PROGRAM - - shInput(float2, UV) - shInput(float, fade) - - shSampler2D(diffuseMap) - shUniform(float, nightFade) @shSharedParameter(nightFade) - - - SH_START_PROGRAM - { - shOutputColour(0) = shSample(diffuseMap, UV) * float4(1,1,1, nightFade * fade); - } - -#endif diff --git a/files/materials/stars.shaderset b/files/materials/stars.shaderset deleted file mode 100644 index 0f8803450..000000000 --- a/files/materials/stars.shaderset +++ /dev/null @@ -1,15 +0,0 @@ -shader_set stars_vertex -{ - source stars.shader - type vertex - profiles_cg vs_2_0 arbvp1 - profiles_hlsl vs_2_0 -} - -shader_set stars_fragment -{ - source stars.shader - type fragment - profiles_cg ps_2_x ps_2_0 ps arbfp1 - profiles_hlsl ps_2_0 -} diff --git a/files/materials/sun.shader b/files/materials/sun.shader deleted file mode 100644 index 72e49d1a7..000000000 --- a/files/materials/sun.shader +++ /dev/null @@ -1,41 +0,0 @@ -#include "core.h" - -#ifdef SH_VERTEX_SHADER - - SH_BEGIN_PROGRAM - shUniform(float4x4, world) @shAutoConstant(world, world_matrix) - shUniform(float4x4, view) @shAutoConstant(view, view_matrix) -shUniform(float4x4, projection) @shAutoConstant(projection, projection_matrix) - shVertexInput(float2, uv0) - shOutput(float2, UV) - - SH_START_PROGRAM - { - float4x4 viewFixed = view; -#if !SH_GLSL && !SH_GLSLES - viewFixed[0][3] = 0.0; - viewFixed[1][3] = 0.0; - viewFixed[2][3] = 0.0; -#else - viewFixed[3][0] = 0.0; - viewFixed[3][1] = 0.0; - viewFixed[3][2] = 0.0; -#endif - shOutputPosition = shMatrixMult(projection, shMatrixMult(viewFixed, shMatrixMult(world, shInputPosition))); - UV = uv0; - } - -#else - - SH_BEGIN_PROGRAM - shSampler2D(diffuseMap) - shInput(float2, UV) - shUniform(float4, materialDiffuse) @shAutoConstant(materialDiffuse, surface_diffuse_colour) - //shUniform(float4, materialEmissive) @shAutoConstant(materialEmissive, surface_emissive_colour) - - SH_START_PROGRAM - { - shOutputColour(0) = float4(1,1,1,materialDiffuse.a) * shSample(diffuseMap, UV); - } - -#endif diff --git a/files/materials/sun.shaderset b/files/materials/sun.shaderset deleted file mode 100644 index 1b9e92a43..000000000 --- a/files/materials/sun.shaderset +++ /dev/null @@ -1,15 +0,0 @@ -shader_set sun_vertex -{ - source sun.shader - type vertex - profiles_cg vs_2_0 arbvp1 - profiles_hlsl vs_2_0 -} - -shader_set sun_fragment -{ - source sun.shader - type fragment - profiles_cg ps_2_x ps_2_0 ps arbfp1 - profiles_hlsl ps_2_0 -} diff --git a/files/materials/terrain.shader b/files/materials/terrain.shader deleted file mode 100644 index f20fce506..000000000 --- a/files/materials/terrain.shader +++ /dev/null @@ -1,507 +0,0 @@ -/* - * Copyright (c) 2015 scrawl - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "core.h" - -#define IS_FIRST_PASS (@shPropertyString(pass_index) == 0) - -#define FOG (@shGlobalSettingBool(fog) && !@shPropertyBool(render_composite_map)) - -#define SHADOWS_PSSM @shGlobalSettingBool(shadows_pssm) -#define SHADOWS @shGlobalSettingBool(shadows) - -#if SHADOWS || SHADOWS_PSSM -#include "shadows.h" -#endif - -#define NUM_LAYERS @shPropertyString(num_layers) - -#if FOG || SHADOWS_PSSM -#define NEED_DEPTH 1 -#endif - -#define UNDERWATER @shGlobalSettingBool(render_refraction) - -#define VIEWPROJ_FIX @shGlobalSettingBool(viewproj_fix) - -#define RENDERCMP @shPropertyBool(render_composite_map) - -#define LIGHTING !RENDERCMP - -#define COMPOSITE_MAP @shPropertyBool(display_composite_map) - -#define NORMAL_MAP @shPropertyBool(normal_map_enabled) -#define PARALLAX @shPropertyBool(parallax_enabled) - -#define VERTEX_LIGHTING (!NORMAL_MAP) - -#define PARALLAX_SCALE 0.04 -#define PARALLAX_BIAS -0.02 - -// This is just for the permutation handler -#define NORMAL_MAPS @shPropertyString(normal_maps) - -#if NEED_DEPTH -@shAllocatePassthrough(1, depth) -#endif - -@shAllocatePassthrough(2, UV) - -@shAllocatePassthrough(3, worldPos) - -#if LIGHTING -@shAllocatePassthrough(3, normalPassthrough) -#if VERTEX_LIGHTING -@shAllocatePassthrough(3, lightResult) -@shAllocatePassthrough(3, directionalResult) -#else -@shAllocatePassthrough(3, colourPassthrough) -#endif - -#if SHADOWS -@shAllocatePassthrough(4, lightSpacePos0) -#endif -#if SHADOWS_PSSM -@shForeach(3) - @shAllocatePassthrough(4, lightSpacePos@shIterator) -@shEndForeach -#endif -#endif - -#ifdef SH_VERTEX_SHADER - - // ------------------------------------- VERTEX --------------------------------------- - - SH_BEGIN_PROGRAM - shUniform(float4x4, worldMatrix) @shAutoConstant(worldMatrix, world_matrix) - shUniform(float4x4, viewProjMatrix) @shAutoConstant(viewProjMatrix, viewproj_matrix) - -#if VIEWPROJ_FIX - shUniform(float4, vpRow2Fix) @shSharedParameter(vpRow2Fix, vpRow2Fix) -#endif - - shVertexInput(float2, uv0) - -#if LIGHTING - shNormalInput(float4) - shColourInput(float4) - -#if VERTEX_LIGHTING - shUniform(float4, lightPosition[@shGlobalSettingString(num_lights)]) @shAutoConstant(lightPosition, light_position_object_space_array, @shGlobalSettingString(num_lights)) - shUniform(float4, lightDiffuse[@shGlobalSettingString(num_lights)]) @shAutoConstant(lightDiffuse, light_diffuse_colour_array, @shGlobalSettingString(num_lights)) - shUniform(float4, lightAttenuation[@shGlobalSettingString(num_lights)]) @shAutoConstant(lightAttenuation, light_attenuation_array, @shGlobalSettingString(num_lights)) - shUniform(float4, lightAmbient) @shAutoConstant(lightAmbient, ambient_light_colour) -#endif - -#if SHADOWS - shUniform(float4x4, texViewProjMatrix0) @shAutoConstant(texViewProjMatrix0, texture_viewproj_matrix) -#endif - -#if SHADOWS_PSSM - @shForeach(3) - shUniform(float4x4, texViewProjMatrix@shIterator) @shAutoConstant(texViewProjMatrix@shIterator, texture_viewproj_matrix, @shIterator) - @shEndForeach -#endif - -#endif - - - @shPassthroughVertexOutputs - - SH_START_PROGRAM - { - float4 worldPos = shMatrixMult(worldMatrix, shInputPosition); - - shOutputPosition = shMatrixMult(viewProjMatrix, worldPos); - -#if NEED_DEPTH -#if VIEWPROJ_FIX - float4x4 vpFixed = viewProjMatrix; -#if !SH_GLSL && !SH_GLSLES - vpFixed[2] = vpRow2Fix; -#else - vpFixed[0][2] = vpRow2Fix.x; - vpFixed[1][2] = vpRow2Fix.y; - vpFixed[2][2] = vpRow2Fix.z; - vpFixed[3][2] = vpRow2Fix.w; -#endif - - float4x4 fixedWVP = shMatrixMult(vpFixed, worldMatrix); - - float depth = shMatrixMult(fixedWVP, shInputPosition).z; - @shPassthroughAssign(depth, depth); -#else - @shPassthroughAssign(depth, shOutputPosition.z); -#endif - -#endif - - @shPassthroughAssign(UV, uv0); - - @shPassthroughAssign(worldPos, worldPos.xyz); - -#if LIGHTING - @shPassthroughAssign(normalPassthrough, normal.xyz); -#endif -#if LIGHTING && !VERTEX_LIGHTING - @shPassthroughAssign(colourPassthrough, colour.xyz); -#endif - -#if LIGHTING - -#if SHADOWS - float4 lightSpacePos = shMatrixMult(texViewProjMatrix0, shMatrixMult(worldMatrix, shInputPosition)); - @shPassthroughAssign(lightSpacePos0, lightSpacePos); -#endif -#if SHADOWS_PSSM - float4 wPos = shMatrixMult(worldMatrix, shInputPosition); - - float4 lightSpacePos; - @shForeach(3) - lightSpacePos = shMatrixMult(texViewProjMatrix@shIterator, wPos); - @shPassthroughAssign(lightSpacePos@shIterator, lightSpacePos); - @shEndForeach -#endif - - -#if VERTEX_LIGHTING - // Lighting - float3 lightDir; - float d; - float3 lightResult = float3(0,0,0); - float3 directionalResult = float3(0,0,0); - @shForeach(@shGlobalSettingString(num_lights)) - lightDir = lightPosition[@shIterator].xyz - (shInputPosition.xyz * lightPosition[@shIterator].w); - d = length(lightDir); - lightDir = normalize(lightDir); - - - lightResult.xyz += lightDiffuse[@shIterator].xyz - * shSaturate(1.0 / ((lightAttenuation[@shIterator].y) + (lightAttenuation[@shIterator].z * d) + (lightAttenuation[@shIterator].w * d * d))) - * max(dot(normal.xyz, lightDir), 0.0); - -#if @shIterator == 0 - directionalResult = lightResult.xyz; -#endif - @shEndForeach - lightResult.xyz += lightAmbient.xyz; - lightResult.xyz *= colour.xyz; - directionalResult.xyz *= colour.xyz; - - @shPassthroughAssign(lightResult, lightResult); - @shPassthroughAssign(directionalResult, directionalResult); -#endif - -#endif - } - -#else - - // ----------------------------------- FRAGMENT ------------------------------------------ - -#if UNDERWATER - #include "underwater.h" -#endif -#if NORMAL_MAP && SH_GLSLES - mat3 transpose(mat3 m); -#endif - - SH_BEGIN_PROGRAM - - -#if COMPOSITE_MAP - shSampler2D(compositeMap) -#else - -@shForeach(@shPropertyString(num_blendmaps)) - shSampler2D(blendMap@shIterator) -@shEndForeach - -@shForeach(@shPropertyString(num_layers)) - shSampler2D(diffuseMap@shIterator) -#if @shPropertyBool(use_normal_map_@shIterator) - shSampler2D(normalMap@shIterator) -#endif -@shEndForeach - -#endif - -#if FOG - shUniform(float3, fogColour) @shAutoConstant(fogColour, fog_colour) - shUniform(float4, fogParams) @shAutoConstant(fogParams, fog_params) -#endif - - @shPassthroughFragmentInputs - -#if LIGHTING - -#if !VERTEX_LIGHTING -shUniform(float4, lightPosition[@shGlobalSettingString(num_lights)]) @shAutoConstant(lightPosition, light_position_array, @shGlobalSettingString(num_lights)) -shUniform(float4, lightDiffuse[@shGlobalSettingString(num_lights)]) @shAutoConstant(lightDiffuse, light_diffuse_colour_array, @shGlobalSettingString(num_lights)) -shUniform(float4, lightAttenuation[@shGlobalSettingString(num_lights)]) @shAutoConstant(lightAttenuation, light_attenuation_array, @shGlobalSettingString(num_lights)) -shUniform(float4, lightAmbient) @shAutoConstant(lightAmbient, ambient_light_colour) -shUniform(float4x4, worldView) @shAutoConstant(worldView, worldview_matrix) -#endif - -#if SHADOWS - shSampler2D(shadowMap0) - shUniform(float2, invShadowmapSize0) @shAutoConstant(invShadowmapSize0, inverse_texture_size, @shPropertyString(shadowtexture_offset)) -#endif -#if SHADOWS_PSSM - @shForeach(3) - shSampler2D(shadowMap@shIterator) - shUniform(float2, invShadowmapSize@shIterator) @shAutoConstant(invShadowmapSize@shIterator, inverse_texture_size, @shIterator(@shPropertyString(shadowtexture_offset))) - @shEndForeach - shUniform(float3, pssmSplitPoints) @shSharedParameter(pssmSplitPoints) -#endif - -#if SHADOWS || SHADOWS_PSSM - shUniform(float4, shadowFar_fadeStart) @shSharedParameter(shadowFar_fadeStart) -#endif -#endif - -#if (UNDERWATER) || (FOG) - shUniform(float4x4, worldMatrix) @shAutoConstant(worldMatrix, world_matrix) -#endif - -#if UNDERWATER - shUniform(float, waterLevel) @shSharedParameter(waterLevel) -#endif - - -// For specular -#if LIGHTING - shUniform(float3, lightSpec0) @shAutoConstant(lightSpec0, light_specular_colour, 0) - shUniform(float3, lightPos0) @shAutoConstant(lightPos0, light_position, 0) -#endif - -shUniform(float4, cameraPos) @shAutoConstant(cameraPos, camera_position) - - SH_START_PROGRAM - { - -#if NEED_DEPTH - float depth = @shPassthroughReceive(depth); -#endif - - float2 UV = @shPassthroughReceive(UV); - - float3 worldPos = @shPassthroughReceive(worldPos); - -#if LIGHTING - float3 normal = @shPassthroughReceive(normalPassthrough); -#endif - -#if LIGHTING && !VERTEX_LIGHTING - -#if NORMAL_MAP - // derive the tangent space basis - float3 tangent = float3(1,0, 0); - - float3 binormal = normalize(cross(tangent, normal)); - tangent = normalize(cross(normal, binormal)); // note, now we need to re-cross to derive tangent again because it wasn't orthonormal - - // derive final matrix - float3x3 tbn = float3x3(tangent, binormal, normal); - #if SH_GLSL || SH_GLSLES - tbn = transpose(tbn); - #endif -#endif - -#endif - -#if UNDERWATER - float3 waterEyePos = intercept(worldPos, cameraPos.xyz - worldPos, float3(0,0,1), waterLevel); -#endif - -#if !IS_FIRST_PASS -// Opacity the previous passes should have, i.e. 1 - (opacity of this pass) -float previousAlpha = 1.0; -#endif - - -shOutputColour(0) = float4(1,1,1,1); - -float3 TSnormal = float3(0,0,1); - -#if COMPOSITE_MAP - shOutputColour(0).xyz = shSample(compositeMap, UV).xyz; -#else - - // Layer calculations -// rescale UV to directly map edge vertices to texel centers - this is -// important to get correct blending at cell transitions -// TODO: parameterize texel size -float2 blendUV = (UV - 0.5) * (16.0 / (16.0+1.0)) + 0.5; -@shForeach(@shPropertyString(num_blendmaps)) - float4 blendValues@shIterator = shSaturate(shSample(blendMap@shIterator, blendUV)); -@shEndForeach - - - float4 albedo = float4(0,0,0,1); - - float2 layerUV = float2(UV.x, 1.0-UV.y) * 16.0; // Reverse Y, required to get proper tangents - float2 thisLayerUV; - float4 normalTex; - float4 diffuseTex; - - float3 eyeDir = normalize(cameraPos.xyz - worldPos); -#if PARALLAX - float3 TSeyeDir = normalize(shMatrixMult(tbn, eyeDir)); -#endif - -@shForeach(@shPropertyString(num_layers)) - thisLayerUV = layerUV; -#if @shPropertyBool(use_normal_map_@shIterator) - normalTex = shSample(normalMap@shIterator, thisLayerUV); -#if @shIterator == 0 && IS_FIRST_PASS - TSnormal = normalize(normalTex.xyz * 2.0 - 1.0); -#else - TSnormal = shLerp(TSnormal, normalTex.xyz * 2.0 - 1.0, blendValues@shPropertyString(blendmap_component_@shIterator)); -#endif -#endif - -#if @shPropertyBool(use_parallax_@shIterator) - thisLayerUV += TSeyeDir.xy * ( normalTex.a * PARALLAX_SCALE + PARALLAX_BIAS ); -#endif - - diffuseTex = shSample(diffuseMap@shIterator, layerUV); -#if !@shPropertyBool(use_specular_@shIterator) - diffuseTex.a = 0.0; -#endif - -#if @shIterator == 0 -albedo = diffuseTex; -#else -albedo = shLerp(albedo, diffuseTex, blendValues@shPropertyString(blendmap_component_@shIterator)); -#endif - -#if !IS_FIRST_PASS - previousAlpha *= 1.0-blendValues@shPropertyString(blendmap_component_@shIterator); -#endif - - -@shEndForeach - - shOutputColour(0).rgb *= albedo.xyz; - -#endif - -#if LIGHTING - -#if VERTEX_LIGHTING - // Lighting - float3 lightResult = @shPassthroughReceive(lightResult); - float3 directionalResult = @shPassthroughReceive(directionalResult); -#else - -#if NORMAL_MAP - normal = normalize (shMatrixMult( transpose(tbn), TSnormal )); -#endif - - float3 colour = @shPassthroughReceive(colourPassthrough); - float3 lightDir; - float d; - float3 lightResult = float3(0,0,0); - @shForeach(@shGlobalSettingString(num_lights)) - lightDir = lightPosition[@shIterator].xyz - (worldPos * lightPosition[@shIterator].w); - d = length(lightDir); - lightDir = normalize(lightDir); - - lightResult.xyz += lightDiffuse[@shIterator].xyz - * shSaturate(1.0 / ((lightAttenuation[@shIterator].y) + (lightAttenuation[@shIterator].z * d) + (lightAttenuation[@shIterator].w * d * d))) - * max(dot(normal.xyz, lightDir), 0.0); -#if @shIterator == 0 - float3 directionalResult = lightResult.xyz; -#endif - @shEndForeach - lightResult.xyz += lightAmbient.xyz; - lightResult.xyz *= colour.xyz; - directionalResult.xyz *= colour.xyz; -#endif - - // shadows only for the first (directional) light -#if SHADOWS - float4 lightSpacePos0 = @shPassthroughReceive(lightSpacePos0); - float shadow = depthShadowPCF (shadowMap0, lightSpacePos0, invShadowmapSize0); -#endif -#if SHADOWS_PSSM - @shForeach(3) - float4 lightSpacePos@shIterator = @shPassthroughReceive(lightSpacePos@shIterator); - @shEndForeach - - float shadow = pssmDepthShadow (lightSpacePos0, invShadowmapSize0, shadowMap0, lightSpacePos1, invShadowmapSize1, shadowMap1, lightSpacePos2, invShadowmapSize2, shadowMap2, depth, pssmSplitPoints); -#endif - -#if SHADOWS || SHADOWS_PSSM - float fadeRange = shadowFar_fadeStart.x - shadowFar_fadeStart.y; - float fade = 1-((depth - shadowFar_fadeStart.y) / fadeRange); - shadow = (depth > shadowFar_fadeStart.x) ? 1.0 : ((depth > shadowFar_fadeStart.y) ? 1.0-((1.0-shadow)*fade) : shadow); -#endif - -#if !SHADOWS && !SHADOWS_PSSM - float shadow = 1.0; -#endif - - shOutputColour(0).xyz *= (lightResult - directionalResult * (1.0-shadow)); -#endif - -#if LIGHTING && !COMPOSITE_MAP - // Specular - float3 light0Dir = normalize(lightPos0.xyz); - - float NdotL = max(dot(normal, light0Dir), 0.0); - float3 halfVec = normalize (light0Dir + eyeDir); - - float3 specular = pow(max(dot(normal, halfVec), 0.0), 32.0) * lightSpec0; - shOutputColour(0).xyz += specular * (albedo.a) * shadow; -#endif - -#if FOG - float fogValue = shSaturate((depth - fogParams.y) * fogParams.w); - - #if UNDERWATER - shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, UNDERWATER_COLOUR, shSaturate(length(waterEyePos-worldPos) / VISIBILITY)); - #else - shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, fogColour, fogValue); - #endif -#endif - - // prevent negative colour output (for example with negative lights) - shOutputColour(0).xyz = max(shOutputColour(0).xyz, float3(0,0,0)); - -#if IS_FIRST_PASS - shOutputColour(0).a = 1.0; -#else - shOutputColour(0).a = 1.0-previousAlpha; -#endif - } -#if NORMAL_MAP && SH_GLSLES - mat3 transpose(mat3 m){ - return mat3( - m[0][0],m[1][0],m[2][0], - m[0][1],m[1][1],m[2][1], - m[0][2],m[1][2],m[2][2] - ); - } -#endif -#endif diff --git a/files/materials/terrain.shaderset b/files/materials/terrain.shaderset deleted file mode 100644 index a72f2358f..000000000 --- a/files/materials/terrain.shaderset +++ /dev/null @@ -1,15 +0,0 @@ -shader_set terrain_vertex -{ - source terrain.shader - type vertex - profiles_cg vs_2_0 vp40 arbvp1 - profiles_hlsl vs_3_0 vs_2_0 -} - -shader_set terrain_fragment -{ - source terrain.shader - type fragment - profiles_cg ps_3_0 ps_2_x ps_2_0 fp40 arbfp1 - profiles_hlsl ps_3_0 ps_2_0 -} diff --git a/files/materials/underwater.h b/files/materials/underwater.h deleted file mode 100644 index 2f38f6546..000000000 --- a/files/materials/underwater.h +++ /dev/null @@ -1,121 +0,0 @@ -#define UNDERWATER_COLOUR float3(0.090195, 0.115685, 0.12745) - -#define VISIBILITY 1000.0 // how far you can look through water - -#define BIG_WAVES_X 0.3 // strength of big waves -#define BIG_WAVES_Y 0.3 - -#define MID_WAVES_X 0.3 // strength of middle sized waves -#define MID_WAVES_Y 0.15 - -#define SMALL_WAVES_X 0.15 // strength of small waves -#define SMALL_WAVES_Y 0.1 - -#define WAVE_CHOPPYNESS 0.15 // wave choppyness -#define WAVE_SCALE 0.01 // overall wave scale - -#define ABBERATION 0.001 // chromatic abberation amount - -#define SUN_EXT float3(0.45, 0.55, 0.68) //sunlight extinction - -float3 intercept(float3 lineP, - float3 lineN, - float3 planeN, - float planeD) -{ - - float distance = (planeD - dot(planeN, lineP)) / dot(lineN, planeN); - return lineP + lineN * distance; -} - -float3 perturb1(shTexture2D tex, float2 coords, float bend, float2 windDir, float windSpeed, float timer) -{ - float2 nCoord = float2(0,0); - bend *= WAVE_CHOPPYNESS; - nCoord = coords * (WAVE_SCALE * 0.05) + windDir * timer * (windSpeed*0.04); - float3 normal0 = 2.0 * shSample(tex, nCoord + float2(-timer*0.015,-timer*0.05)).rgb - 1.0; - nCoord = coords * (WAVE_SCALE * 0.1) + windDir * timer * (windSpeed*0.08)-normal0.xy*bend; - float3 normal1 = 2.0 * shSample(tex, nCoord + float2(+timer*0.020,+timer*0.015)).rgb - 1.0; - - nCoord = coords * (WAVE_SCALE * 0.25) + windDir * timer * (windSpeed*0.07)-normal1.xy*bend; - float3 normal2 = 2.0 * shSample(tex, nCoord + float2(-timer*0.04,-timer*0.03)).rgb - 1.0; - nCoord = coords * (WAVE_SCALE * 0.5) + windDir * timer * (windSpeed*0.09)-normal2.xy*bend; - float3 normal3 = 2.0 * shSample(tex, nCoord + float2(+timer*0.03,+timer*0.04)).rgb - 1.0; - - nCoord = coords * (WAVE_SCALE* 1.0) + windDir * timer * (windSpeed*0.4)-normal3.xy*bend; - float3 normal4 = 2.0 * shSample(tex, nCoord + float2(-timer*0.2,+timer*0.1)).rgb - 1.0; - nCoord = coords * (WAVE_SCALE * 2.0) + windDir * timer * (windSpeed*0.7)-normal4.xy*bend; - float3 normal5 = 2.0 * shSample(tex, nCoord + float2(+timer*0.1,-timer*0.06)).rgb - 1.0; - - - float3 normal = normalize(normal0 * BIG_WAVES_X + normal1 * BIG_WAVES_Y + - normal2 * MID_WAVES_X + normal3 * MID_WAVES_Y + - normal4 * SMALL_WAVES_X + normal5 * SMALL_WAVES_Y); - return normal; -} - -float3 perturb(shTexture2D tex, float2 coords, float bend, float2 windDir, float windSpeed, float timer) -{ - bend *= WAVE_CHOPPYNESS; - float3 col = float3(0,0,0); - float2 nCoord = float2(0,0); //normal coords - - nCoord = coords * (WAVE_SCALE * 0.025) + windDir * timer * (windSpeed*0.03); - col += shSample(tex,nCoord + float2(-timer*0.005,-timer*0.01)).rgb*0.20; - nCoord = coords * (WAVE_SCALE * 0.1) + windDir * timer * (windSpeed*0.05)-(col.xy/col.zz)*bend; - col += shSample(tex,nCoord + float2(+timer*0.01,+timer*0.005)).rgb*0.20; - - nCoord = coords * (WAVE_SCALE * 0.2) + windDir * timer * (windSpeed*0.1)-(col.xy/col.zz)*bend; - col += shSample(tex,nCoord + float2(-timer*0.02,-timer*0.03)).rgb*0.20; - nCoord = coords * (WAVE_SCALE * 0.5) + windDir * timer * (windSpeed*0.2)-(col.xy/col.zz)*bend; - col += shSample(tex,nCoord + float2(+timer*0.03,+timer*0.02)).rgb*0.15; - - nCoord = coords * (WAVE_SCALE* 0.8) + windDir * timer * (windSpeed*1.0)-(col.xy/col.zz)*bend; - col += shSample(tex, nCoord + float2(-timer*0.06,+timer*0.08)).rgb*0.15; - nCoord = coords * (WAVE_SCALE * 1.0) + windDir * timer * (windSpeed*1.3)-(col.xy/col.zz)*bend; - col += shSample(tex,nCoord + float2(+timer*0.08,-timer*0.06)).rgb*0.10; - - return col; -} - - -float3 getCaustics (shTexture2D causticMap, float3 worldPos, float3 waterEyePos, float3 worldNormal, float3 lightDirectionWS0, float waterLevel, float waterTimer, float3 windDir_windSpeed) -{ - float waterDepth = shSaturate((waterEyePos.z - worldPos.z) / 50.0); - - float3 causticPos = intercept(worldPos.xyz, lightDirectionWS0.xyz, float3(0,0,1), waterLevel); - - ///\ todo clean this up - float causticdepth = length(causticPos-worldPos.xyz); - causticdepth = 1.0-shSaturate(causticdepth / VISIBILITY); - causticdepth = shSaturate(causticdepth); - - // NOTE: the original shader calculated a tangent space basis here, - // but using only the world normal is cheaper and i couldn't see a visual difference - // also, if this effect gets moved to screen-space some day, it's unlikely to have tangent information - float3 causticNorm = worldNormal.xyz * perturb(causticMap, causticPos.xy, causticdepth, windDir_windSpeed.xy, windDir_windSpeed.z, waterTimer).xyz * 2.0 - 1.0; - causticNorm = float3(causticNorm.x, causticNorm.y, -causticNorm.z); - - //float fresnel = pow(clamp(dot(LV,causticnorm),0.0,1.0),2.0); - - float NdotL = max(dot(worldNormal.xyz, lightDirectionWS0.xyz),0.0); - - float causticR = 1.0-perturb(causticMap, causticPos.xy, causticdepth, windDir_windSpeed.xy, windDir_windSpeed.z, waterTimer).z; - - /// \todo sunFade - - // float3 caustics = clamp(pow(float3(causticR)*5.5,float3(5.5*causticdepth)),0.0,1.0)*NdotL*sunFade*causticdepth; - float3 caustics = clamp(pow(float3(causticR,causticR,causticR)*5.5,float3(5.5*causticdepth,5.5*causticdepth,5.5*causticdepth)),0.0,1.0)*NdotL*causticdepth; - float causticG = 1.0-perturb(causticMap,causticPos.xy+(1.0-causticdepth)*ABBERATION, causticdepth, windDir_windSpeed.xy, windDir_windSpeed.z, waterTimer).z; - float causticB = 1.0-perturb(causticMap,causticPos.xy+(1.0-causticdepth)*ABBERATION*2.0, causticdepth, windDir_windSpeed.xy, windDir_windSpeed.z, waterTimer).z; - //caustics = shSaturate(pow(float3(causticR,causticG,causticB)*5.5,float3(5.5*causticdepth)))*NdotL*sunFade*causticdepth; - caustics = shSaturate(pow(float3(causticR,causticG,causticB)*5.5,float3(5.5*causticdepth,5.5*causticdepth,5.5*causticdepth)))*NdotL*causticdepth; - - caustics *= 3.0; - - // shore transition - caustics = shLerp (float3(1,1,1), caustics, waterDepth); - - return caustics; -} - diff --git a/files/materials/water.mat b/files/materials/water.mat deleted file mode 100644 index cf03be39e..000000000 --- a/files/materials/water.mat +++ /dev/null @@ -1,101 +0,0 @@ -material Water -{ - allow_fixed_function false - - pass - { - emissive 1.0 1.0 1.0 - ambient 0 0 0 - diffuse 0 0 0 1 - specular 0 0 0 32 - - vertex_program water_vertex - fragment_program water_fragment - - cull_hardware none - - scene_blend alpha_blend - depth_write off - - texture_unit reflectionMap - { - texture_alias WaterReflection - tex_address_mode clamp - } - - texture_unit refractionMap - { - direct_texture WaterRefraction - tex_address_mode clamp - } - - texture_unit depthMap - { - texture_alias SceneDepth - tex_address_mode clamp - } - - texture_unit normalMap - { - texture water_nm.png - } - - texture_unit rippleNormalMap - { - direct_texture RippleNormal - tex_address_mode border - tex_border_colour 0.5 0.5 1.0 - } - - // for simple_water - texture_unit animatedTexture - { - create_in_ffp true - scale 0.1 0.1 - alpha_op_ex source1 src_manual src_current 0.7 - } - - texture_unit shadowMap0 - { - content_type shadow - tex_address_mode clamp - filtering none - } - texture_unit shadowMap1 - { - content_type shadow - tex_address_mode clamp - filtering none - } - texture_unit shadowMap2 - { - content_type shadow - tex_address_mode clamp - filtering none - } - } -} - -material openmw/Ripple -{ - // this will be overridden by Water_RippleFrameCount fallback setting - anim_texture2 textures\water\ripple.dds 4 0.25 - pass - { - scene_blend alpha_blend - depth_write off - cull_hardware none - diffuse vertexcolour - emissive 1 1 1 - ambient 0 0 0 - texture_unit diffuseMap - { - create_in_ffp true - anim_texture2 $anim_texture2 - - // to make sure rotating doesn't cause the texture to repeat - tex_address_mode border - tex_border_colour 0 0 0 0 - } - } -} diff --git a/files/materials/water.shader b/files/materials/water.shader deleted file mode 100644 index eff245b5e..000000000 --- a/files/materials/water.shader +++ /dev/null @@ -1,354 +0,0 @@ -#include "core.h" - - -#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) - -#if FOG - shOutput(float, depth) -#endif - SH_START_PROGRAM - { - shOutputPosition = shMatrixMult(wvp, shInputPosition); - UV = uv0; -#if FOG - depth = shOutputPosition.z; -#endif - } - -#else - - SH_BEGIN_PROGRAM - shSampler2D(animatedTexture) - shInput(float2, UV) - shInput(float, depth) - - shUniform(float3, fogColor) @shAutoConstant(fogColor, fog_colour) - shUniform(float4, fogParams) @shAutoConstant(fogParams, fog_params) - - - SH_START_PROGRAM - { - shOutputColour(0).xyz = shSample(animatedTexture, UV * float2(15.0, 15.0)).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 - -#else - - - -// Inspired by Blender GLSL Water by martinsh ( http://devlog-martinsh.blogspot.de/2012/07/waterundewater-shader-wip.html ) - -#define SHADOWS_PSSM @shGlobalSettingBool(shadows_pssm) -#define SHADOWS @shGlobalSettingBool(shadows) - -#if SHADOWS || SHADOWS_PSSM - #include "shadows.h" -#endif - -#define REFRACTION @shGlobalSettingBool(refraction) - -#ifdef SH_VERTEX_SHADER - - SH_BEGIN_PROGRAM - shUniform(float4x4, wvp) @shAutoConstant(wvp, worldviewproj_matrix) - - shOutput(float3, screenCoordsPassthrough) - shOutput(float4, position) - shOutput(float, depthPassthrough) - - -#if SHADOWS - shOutput(float4, lightSpacePos0) - shUniform(float4x4, texViewProjMatrix0) @shAutoConstant(texViewProjMatrix0, texture_viewproj_matrix) -#endif - -#if SHADOWS_PSSM - @shForeach(3) - shOutput(float4, lightSpacePos@shIterator) - shUniform(float4x4, texViewProjMatrix@shIterator) @shAutoConstant(texViewProjMatrix@shIterator, texture_viewproj_matrix, @shIterator) - @shEndForeach -#endif - -#if SHADOWS || SHADOWS_PSSM - shUniform(float4x4, worldMatrix) @shAutoConstant(worldMatrix, world_matrix) -#endif - - SH_START_PROGRAM - { - shOutputPosition = shMatrixMult(wvp, shInputPosition); - - - #if !SH_GLSL && !SH_GLSLES - float4x4 scalemat = float4x4( 0.5, 0.0, 0.0, 0.5, - 0.0, -0.5, 0.0, 0.5, - 0.0, 0.0, 0.5, 0.5, - 0.0, 0.0, 0.0, 1.0 ); - #else - mat4 scalemat = mat4(0.5, 0.0, 0.0, 0.0, - 0.0, -0.5, 0.0, 0.0, - 0.0, 0.0, 0.5, 0.0, - 0.5, 0.5, 0.5, 1.0); - #endif - - float4 texcoordProj = shMatrixMult(scalemat, shOutputPosition); - screenCoordsPassthrough = float3(texcoordProj.x, texcoordProj.y, texcoordProj.w); - - position = shInputPosition; - - depthPassthrough = shOutputPosition.z; - - -#if SHADOWS - lightSpacePos0 = shMatrixMult(texViewProjMatrix0, shMatrixMult(worldMatrix, shInputPosition)); -#endif -#if SHADOWS_PSSM - float4 wPos = shMatrixMult(worldMatrix, shInputPosition); - @shForeach(3) - lightSpacePos@shIterator = shMatrixMult(texViewProjMatrix@shIterator, wPos); - @shEndForeach -#endif - } - -#else - - // tweakables ---------------------------------------------------- - - #define VISIBILITY 1500.0 // how far you can look through water - - #define BIG_WAVES_X 0.1 // strength of big waves - #define BIG_WAVES_Y 0.1 - - #define MID_WAVES_X 0.1 // strength of middle sized waves - #define MID_WAVES_Y 0.1 - - #define SMALL_WAVES_X 0.1 // strength of small waves - #define SMALL_WAVES_Y 0.1 - - #define WAVE_CHOPPYNESS 0.05 // wave choppyness - #define WAVE_SCALE 75.0 // overall wave scale - - #define BUMP 0.5 // overall water surface bumpiness - #define REFL_BUMP 0.15 // reflection distortion amount - #define REFR_BUMP 0.06 // refraction distortion amount - - #define SCATTER_AMOUNT 0.3 // amount of sunlight scattering - #define SCATTER_COLOUR float3(0.0,1.0,0.95) // colour of sunlight scattering - - #define SUN_EXT float3(0.45, 0.55, 0.68) //sunlight extinction - - #define SPEC_HARDNESS 256.0 // specular highlights hardness - - // --------------------------------------------------------------- - - - - float fresnel_dielectric(float3 Incoming, float3 Normal, float eta) - { - /* compute fresnel reflectance without explicitly computing - the refracted direction */ - float c = abs(dot(Incoming, Normal)); - float g = eta * eta - 1.0 + c * c; - float result; - - if(g > 0.0) { - g = sqrt(g); - float A =(g - c)/(g + c); - float B =(c *(g + c)- 1.0)/(c *(g - c)+ 1.0); - result = 0.5 * A * A *(1.0 + B * B); - } - else - result = 1.0; /* TIR (no refracted component) */ - - return result; - } - - SH_BEGIN_PROGRAM - shInput(float3, screenCoordsPassthrough) - shInput(float4, position) - shInput(float, depthPassthrough) - - shUniform(float, far) @shAutoConstant(far, far_clip_distance) - - shSampler2D(reflectionMap) -#if REFRACTION - shSampler2D(refractionMap) -#endif - shSampler2D(depthMap) - shSampler2D(normalMap) - - shUniform(float4x4, wMat) @shAutoConstant(wMat, world_matrix) - shUniform(float3, windDir_windSpeed) @shSharedParameter(windDir_windSpeed) - #define WIND_SPEED windDir_windSpeed.z - #define WIND_DIR windDir_windSpeed.xy - - shUniform(float, waterTimer) @shSharedParameter(waterTimer) - shUniform(float2, waterSunFade_sunHeight) @shSharedParameter(waterSunFade_sunHeight) - - shUniform(float4, sunPosition) @shAutoConstant(sunPosition, light_position, 0) - shUniform(float4, sunSpecular) @shAutoConstant(sunSpecular, light_specular_colour, 0) - - shUniform(float, renderTargetFlipping) @shAutoConstant(renderTargetFlipping, render_target_flipping) - - - shUniform(float3, fogColor) @shAutoConstant(fogColor, fog_colour) - shUniform(float4, fogParams) @shAutoConstant(fogParams, fog_params) - - shUniform(float4, cameraPos) @shAutoConstant(cameraPos, camera_position_object_space) - - -#if SHADOWS - shInput(float4, lightSpacePos0) - shSampler2D(shadowMap0) - shUniform(float2, invShadowmapSize0) @shAutoConstant(invShadowmapSize0, inverse_texture_size, 1) -#endif -#if SHADOWS_PSSM - @shForeach(3) - shInput(float4, lightSpacePos@shIterator) - shSampler2D(shadowMap@shIterator) - shUniform(float2, invShadowmapSize@shIterator) @shAutoConstant(invShadowmapSize@shIterator, inverse_texture_size, @shIterator(1)) - @shEndForeach - shUniform(float3, pssmSplitPoints) @shSharedParameter(pssmSplitPoints) -#endif - -#if SHADOWS || SHADOWS_PSSM - shUniform(float4, shadowFar_fadeStart) @shSharedParameter(shadowFar_fadeStart) -#endif - - - SH_START_PROGRAM - { - float3 worldPos = shMatrixMult (wMat, position).xyz; - float2 UV = worldPos.xy / (8192.0*5.0) * 3.0; - UV.y *= -1.0; - -#if SHADOWS - float shadow = depthShadowPCF (shadowMap0, lightSpacePos0, invShadowmapSize0); -#endif -#if SHADOWS_PSSM - float shadow = pssmDepthShadow (lightSpacePos0, invShadowmapSize0, shadowMap0, lightSpacePos1, invShadowmapSize1, shadowMap1, lightSpacePos2, invShadowmapSize2, shadowMap2, depthPassthrough, pssmSplitPoints); -#endif - -#if SHADOWS || SHADOWS_PSSM - float fadeRange = shadowFar_fadeStart.x - shadowFar_fadeStart.y; - float fade = 1.0-((depthPassthrough - shadowFar_fadeStart.y) / fadeRange); - shadow = (depthPassthrough > shadowFar_fadeStart.x) ? 1.0 : ((depthPassthrough > shadowFar_fadeStart.y) ? 1.0-((1.0-shadow)*fade) : shadow); -#endif - -#if !SHADOWS && !SHADOWS_PSSM - float shadow = 1.0; -#endif - - - float2 screenCoords = screenCoordsPassthrough.xy / screenCoordsPassthrough.z; - screenCoords.y = (1.0-shSaturate(renderTargetFlipping))+renderTargetFlipping*screenCoords.y; - - float2 nCoord = float2(0.0,0.0); - - nCoord = UV * (WAVE_SCALE * 0.05) + WIND_DIR * waterTimer * (WIND_SPEED*0.04); - float3 normal0 = 2.0 * shSample(normalMap, nCoord + float2(-waterTimer*0.015,-waterTimer*0.005)).rgb - 1.0; - nCoord = UV * (WAVE_SCALE * 0.1) + WIND_DIR * waterTimer * (WIND_SPEED*0.08)-(normal0.xy/normal0.zz)*WAVE_CHOPPYNESS; - float3 normal1 = 2.0 * shSample(normalMap, nCoord + float2(+waterTimer*0.020,+waterTimer*0.015)).rgb - 1.0; - - nCoord = UV * (WAVE_SCALE * 0.25) + WIND_DIR * waterTimer * (WIND_SPEED*0.07)-(normal1.xy/normal1.zz)*WAVE_CHOPPYNESS; - float3 normal2 = 2.0 * shSample(normalMap, nCoord + float2(-waterTimer*0.04,-waterTimer*0.03)).rgb - 1.0; - nCoord = UV * (WAVE_SCALE * 0.5) + WIND_DIR * waterTimer * (WIND_SPEED*0.09)-(normal2.xy/normal2.z)*WAVE_CHOPPYNESS; - float3 normal3 = 2.0 * shSample(normalMap, nCoord + float2(+waterTimer*0.03,+waterTimer*0.04)).rgb - 1.0; - - nCoord = UV * (WAVE_SCALE* 1.0) + WIND_DIR * waterTimer * (WIND_SPEED*0.4)-(normal3.xy/normal3.zz)*WAVE_CHOPPYNESS; - float3 normal4 = 2.0 * shSample(normalMap, nCoord + float2(-waterTimer*0.02,+waterTimer*0.1)).rgb - 1.0; - nCoord = UV * (WAVE_SCALE * 2.0) + WIND_DIR * waterTimer * (WIND_SPEED*0.7)-(normal4.xy/normal4.zz)*WAVE_CHOPPYNESS; - float3 normal5 = 2.0 * shSample(normalMap, nCoord + float2(+waterTimer*0.1,-waterTimer*0.06)).rgb - 1.0; - - - - float3 normal = (normal0 * BIG_WAVES_X + normal1 * BIG_WAVES_Y + - normal2 * MID_WAVES_X + normal3 * MID_WAVES_Y + - normal4 * SMALL_WAVES_X + normal5 * SMALL_WAVES_Y); - - normal = normalize(float3(normal.x * BUMP, normal.y * BUMP, normal.z)); - normal = float3(normal.x, normal.y, -normal.z); - - // normal for sunlight scattering - float3 lNormal = (normal0 * BIG_WAVES_X*0.5 + normal1 * BIG_WAVES_Y*0.5 + - normal2 * MID_WAVES_X*0.2 + normal3 * MID_WAVES_Y*0.2 + - normal4 * SMALL_WAVES_X*0.1 + normal5 * SMALL_WAVES_Y*0.1).xyz; - lNormal = normalize(float3(lNormal.x * BUMP, lNormal.y * BUMP, lNormal.z)); - lNormal = float3(lNormal.x, lNormal.y, -lNormal.z); - - - float3 lVec = normalize(sunPosition.xyz); - float3 vVec = normalize(position.xyz - cameraPos.xyz); - - - float isUnderwater = (cameraPos.z > 0.0) ? 0.0 : 1.0; - - // sunlight scattering - float3 pNormal = float3(0,0,1); - float3 lR = reflect(lVec, lNormal); - float3 llR = reflect(lVec, pNormal); - - float s = shSaturate(dot(lR, vVec)*2.0-1.2); - float lightScatter = shadow * shSaturate(dot(-lVec,lNormal)*0.7+0.3) * s * SCATTER_AMOUNT * waterSunFade_sunHeight.x * shSaturate(1.0-exp(-waterSunFade_sunHeight.y)); - float3 scatterColour = shLerp(float3(SCATTER_COLOUR)*float3(1.0,0.4,0.0), SCATTER_COLOUR, shSaturate(1.0-exp(-waterSunFade_sunHeight.y*SUN_EXT))); - - // fresnel - float ior = (cameraPos.z>0.0)?(1.333/1.0):(1.0/1.333); //air to water; water to air - float fresnel = fresnel_dielectric(-vVec, normal, ior); - - fresnel = shSaturate(fresnel); - - // reflection - float3 reflection = shSample(reflectionMap, screenCoords+(normal.xy*REFL_BUMP)).rgb; - - // refraction - float3 R = reflect(vVec, normal); - -#if REFRACTION - float3 refraction = shSample(refractionMap, (screenCoords-(normal.xy*REFR_BUMP))*1.0).rgb; - - // brighten up the refraction underwater - refraction = (cameraPos.z < 0.0) ? shSaturate(refraction * 1.5) : refraction; -#endif - - // specular - float specular = pow(max(dot(R, lVec), 0.0),SPEC_HARDNESS) * shadow; - -#if REFRACTION - shOutputColour(0).xyz = shLerp( shLerp(refraction, scatterColour, lightScatter), reflection, fresnel) + specular * sunSpecular.xyz; -#else - shOutputColour(0).xyz = shLerp(reflection, float3(0.090195, 0.115685, 0.12745), (1.0-fresnel)*0.5) + specular * sunSpecular.xyz; -#endif - // fog - float fogValue = shSaturate((depthPassthrough - fogParams.y) * fogParams.w); - shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, fogColor, fogValue); - -#if REFRACTION - shOutputColour(0).w = 1.0; -#else - shOutputColour(0).w = shSaturate(fresnel*2.0 + specular); -#endif - } - -#endif - - -#endif diff --git a/files/materials/water.shaderset b/files/materials/water.shaderset deleted file mode 100644 index 5e070a45a..000000000 --- a/files/materials/water.shaderset +++ /dev/null @@ -1,15 +0,0 @@ -shader_set water_vertex -{ - source water.shader - type vertex - profiles_cg vs_2_0 vp40 arbvp1 - profiles_hlsl vs_3_0 vs_2_0 -} - -shader_set water_fragment -{ - source water.shader - type fragment - profiles_cg ps_2_x ps_2_0 ps fp40 arbfp1 - profiles_hlsl ps_3_0 ps_2_0 -} diff --git a/files/water/circle.png b/files/water/circle.png deleted file mode 100644 index 9a1cf268c0be2cdae27fe04ee7f7c0aa6de12c11..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 753 zcmVPx#32;bRa{vGf6951U69E94oEQKA00(qQO+^RY0s#yODLP_H6#xJL8FWQhbVF}# zZDnqB07G(RVRU6=Aa`kWXdp*PO;A^X4i^9b0$xc(K~#9!?VG<&8$l4pf3r}yK~51x zqM)L&3(GXPrAgYOr>3Lk4JgeU@D%ooAf>PicNCFA3Q(Fz0Zj_eDdq^q=iI@0XFq8g z%YXL!d^@wd^R1{VbwWh8fL)*q99VRLJ>Vno0NepLzy!Fqm;m2Y^|96gs%qr{w1Es5 z0s5aYvhQlwGS&)73oxjN^fEC9fHXz`BmM=rt&w;!ZtXYaT?GL8!0Zi)7h?wW-&_Eo z1q|Pjcrk`RYaK39whD+y2lxtX(=0pyJyo5S`A{fHKC|-FH1gP(CN{?E%OG&pphy0- zIIA=V0OuP-K9BQC1lX{DzVwsu8u@I4$>))+B>>QgfP5aEQe{v?TENeSX8UzZkrykKL0jHxq|slR18ie6i&%hJaRXJH0-u3>;>Esk{G0FcBq$;Re794Y znDGPnq(*%42{?2>9^-iUED6?plGC&pJy{2cNZSr3J>i3@-se-`2!A+Q%mJqk1vt&? z{+2BjJz_gp)50rugLP@Vq8qGLfHVc>U0Sc$6X17bhaaU*iUQ6N9PR-YaTl07 zGrZy^Fz@ww#UwEI<9Nk&62SWuNZVoa;f)=VAFJwPz7V={D8Lnv4n+fis@^-B24my= zq%SbQPhVj0%pc&sHD)iIIC%U|bkP;!y*-``5-%8}h7pn{vCMkPkFQUZP`xp5a z1uzk&z;OiRkC!^glT|jErITI0j0l@xp3c&hnGz`78L}VP0WKRv{?h9Flr;#YYjf%1 jWV$-*_wuxOzdrv5<*cfu_Ri)S00000NkvXXu0mjfBzZwt diff --git a/files/water/water_nm.png b/files/water/water_nm.png deleted file mode 100644 index 361431a0efc35882b56bab8ea407d245f27c879d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 24405 zcmV(~K+nI4P)zc5 z|C-I$7<43zLB=3!a^>X8VD@AJlVs9l!-FOovbTP(O;@uvd~NvJ!LFdUpF!yNjKLWA z`N9miMi4X^n@Ihc)lh8KDqg#IEnsbW7gSTbh=z_$braF_XgVQ={@l2N$e^x(k?c&K zkxU9kH|&54x{D?$ijJTIA{#pB+%yFQbU?R0L^rV;Xfol^#Xqw7TJTpCtApx>eg5rc z_atd5psOH)AczX0;r=lV(a9Q36FfWkD}(3u%kKdV8PL7RPDVkl&3rXka1o5!1WCrG zM-Ux)G8yDZ=GD}MO+o}6LAJhUWw0A^Cxaw_ilA%gud5gV*+3NZBw{nsGijP%1yD2) zTmOEr=so;Bn+{kNJfdI#r2`sOj0U=>E}EjED4^Ly6irh!9Zik%lVC)$Q-7VQ=jyLT z7R>R4y@M#A3Mxr_{eTKR_-50EzEW4GAt*t9|kM9~@a zN3b424EQMhxkVEZR4FR4gC@ux6i_6y280guU_x)YC&?zd$WC7txM+4LBH-5+rN7FC zp24nGRG6EhnY$sNq8JoKK^GZCcG07VYC4PFO;uCbG*F?N-vQefc>uljJkM*Zg2_)9 zRrF5X<&i59(pX@kV6kAMl%Z@3H2&Jp71BokJ}x}R}~Du^zg%P ziprprJ?IfS8L`PqsyDF`B|wN*5E10|e}`URR}n+6hlDwSA3^-4G|&v1=CKDq5?+p4 zT|rcm-Na5Z6y@}=lIWlldY8f~gCa;49fRg82j9Qr5;e&?xE0@ z9X^oB=%8va*u+*oX6xlmPB>SpuWp!7pF#f)`5D9r-NIgE4?be^MoDu85nJCU(@_Uq;iAd075dnKB3O4p zGsap~a5y{-m9D|w=kDwnupo0NE5eMXuj1=RuztY) zRQ(beekQ>fsz1g@GG34ybwykC4_)j|KR=i!8D~1ugbzS|`{HrFhyG?~(-->n2h?u? zpFz&nzc+otXm;oUM8e0`OI(-!ak}^Y7?7(KzVPkOzH?z_Qyb=1*kd>Bgx>6O;@bgH ztbk&uKAFRxE6EYeRzZ1%4t$=VZym zSd4(E@PpM~4~kBh3o3;fj7RH#I~pE!_y0PG+%?G6&8}vA!Co*{v0o4!tP&8gDj)|d zHvJgv$7YQ5F;5plL2u}h^lAYiK)~(QYHKfcnzi1O27CB0ZUu;%p;l) zg3oh_KmBF-A$)4UY1f?-vJ^;&rPr2$J>YHCfMP7x#l+i&9wUQYs zeB9+Ll6TWR80~Q0O@@96_R}pN(|5=Do2WYiW$Uo^tLPQv7qFB*UQS)Bi@FAp1*w!% zos3phojcgTD22VwRuUbhbbx@AnegeuvR>yM>cxW(Ks2#ocQW%t$RaYBQDg)iPL=+Z zqg8jz)*+c2t|VqtSFt1YJ`9pY7%V%D1IhNwk5nfTrN5pXTzl|=3e=3Cvx(mpm6QG` z>gf(^G(D2pS5SkyU<#vZOh0g=ca#c>9q>$e4i!8R%0Cs!s9?m@5AIe#b&*4qk-nn3 z)mi~*P-%B@rK)AJEB70GoJCyf7~&sAJVQ70)$El@Uu-G_)I>J}fi%4YdJPxz zJDWM2M~wjPQAFz2e-7vhzP1j)c6UMvb&IVOH!1eg8_EoNZ#se+#TBP|ErsDKY6Lx1 zE7UdM(sv#$3?OcDR?qkAzPtjuyCPP>4TEap2@BuaD*@-;V@pORY(S{7s#e7xeHPM zCvJI3Az5(>lIW9LZa6vzlxu=mD%!e?A-lM%)y&v*4fWAE=!Bg*Fhr}nOX$=MjH%D~ z@ee)hU;hofc;7}^;kl9>YCEBXIUJmIozGmlRn-dZ(JY!8I;?d1K&TfHu3_BPr!ky@ zUnQ_$SCTmd9Qp7@39SS@hY^b05nBgrz)yl#!V0~Mxm~7Y=}SbMA&kL-P_JJNmC4?H z-}>H7M(T^K;T9;ASIdoiv=4z_Zu{?Z6FZ4E+SN()I+uk$pwL0nQ=wN))^Me*-y`9g zeu2@jg4zfw-D;;OrvTKxzD6=Gw_}&n*Xd}S2GjLGxWM}L->`ncF5Uj171_#p-~V5( zn=*u+jy6oLz{O9EU6fW*9n7ep5ZI)dg%7zQ_cF#?5%_ib!VVvcm#YMJU4>cLDtY^&%xY*suv)J+e-Y9ge?-f zO`2c@?B!x}(y{IXFhYl}dsEw;#~FL{@JSgySZc?5DnP7OeGpsep-V+r`G%E?wO6JF zIRgPhMhi!)_vfU;--4b2{{!`J2cXg+J0MtuQUlSRLA>h#Tr*U_ujzt(s!bzcW%6i) zUp~aRJz-Cxw0i3@FI(hpSW=qsW>nifThly43<1|D<{`I~5?ppc?|G_Gr%q zTBp8(7|wG{ClKAXO4u*Gl)X?C=zibOp)m7|$;f68)iSe#kpfJF?`zCDjHky8;vWH5 zu>J@7X;8&o4<2%jhT&OBN4XeQUGt=P7E}f-wP*bdwR{ooRa%3natG$-Xy^Hs2bIx* zP1grK6n#6CI(F>4D_N2J?Jj2xZJ1z_H14b)jlr_ zACmM7I@o?2|5wjko)-+y&IMWs#$C{Zsur*j`Z9%vMLS?m-b0=&RlnW-749m8lkbMT zb<=jkYJpa(6{0I9jM7X#6@m`{7CC&d1ni^(-bW}()Fa@(g8g^HFM%u=vd>oJ#8nZk z89)r-_J7TA3+aj6KE*Z$-?&l4?LvGzBtJckt@LNA7L4x_X>X?%lDO)g>r`r1^Xk;p zzXMld%-RPGIMbjBtLfaPV{GU_`ioozpBw&)W*fyCQ81@lk~rtxv&8rRWpTHF-ANiK zi(0TXcnaK~XXvB6jNt7vidNy*E-IsZ07{VQ*g@}NwsPJAO%R#9C|;55(e(7JGvTp- zE7^`*S?$p#PA^6wQ@G5Jkvga!Dx7(i>x9jyVmKmnZ*r)r-Y$#Q!8Y!JkOo0f=@z-% z-xpoNyGVFt@XP}$xkbm5+n3Yr3M$PL@I^YznqLJgHQ+jsbugH*4vZS#X0R$g(se<` zg5?3rZXPrr8-B5AQZ>ZhH=aODg|RzJodLhmw=S~uaKlAfm!?y9y9B&8tPa+~VOyiw zU4~sXBGCisO;))Q763&HMx7A~y(GV~HCvb}W=F%QWImgHC0Q_Hz=5&FN%GLkHKHTZ zD~mm$RxqNuqPYTQZjXjF@QPIQ`3j}5?4)uN+hEZSW{E=(E>bx!*#+bFP0Dxq1r@$T zanC9CcGlgBk~NjXo&#PDHPUko9j2+9ID80B8MrBBTB6$d&Ev$~e0Fm+yiADbWoAwL zn)D)4dASZ^dB&*i7gk$El25SOAy@kTvtJtSu}=(Sus4jMLt9{C#`dHuPFX~bre^Rc z1P(>;ielwpT_q9+1$(esbBgf{x173Bjm7zC3Xv zfR0v^r%%7XVuC|5wO!4-^`ZF@ra2vyu1@=^e_w2xezQ96vt=Z0!K|WJ6TOtIDLP7n zkEz4;icmM{pFCn1l^hynQZ5cm#%NKkpc$jtk7CSZm8#&^C>VnkYL#k>1=U-ffjR{7 z12o)Gfty{1Tuael2epf;X1|(Tdg;@Ln=FloL!i&|1L`+FhMn+LnttYHZoypxv9Zd} zORT$~66%4W_Ml%zOY%KwOyeqt?6KGTpj5-Nl~T=9AwpHa%faIiAYd}n73(YiztO_g?~NNXY1wf*O`x>@E7zF{7_pa-b{&S5r7@QQ7ri%D#o?kGZqGg4F zppm89H=7>Cy5Q@-;5D7YY4}LS*u=jFGdymNdj{&c3-l+{nYp;%*&o4p1$^oJ=N1BZ zE+L1{<-dP*+(mIr4OdQTne6h!FWwkHHJSBBWU_9OUWZz#+06&VFI)Fm+6ibNr@ zgwjcDBU*)rDWyWCe50cDp_lV&!D|VLsV(TZ{a!T08RRn4)vV%X(KYnKJeVPZ$Px(! z9J;4zZ>hq`e75$(YxS|BZ$&FiBQi#~R;d@{v-qfH@6sT(MB7qVz3l$IG7ec|Gg^gKY@>PwSwcwD-=WQ?>{1%5XnuYu_wO{&=F$6PGG{S=Gtlq^zVs0) zpngDKiejA!8Akb>zef z*t+osQN-41mdNl#Z>}A%Len|l{&)lH3a>lfWJEOZ8E)GM9fb3HVV+wxOy&C=K`r&t z!z9Tt(^cr3Zu;I^!D^UJoND)mdHj#r{MzO|B;+dQ9>l8{t?D@Tez(M~mb1z%;Zhy6 zMI;cPVBeihx$A&pXY=!dzkV3>InO*pT)b=^8RW^!*_3$_dl>A=gY&0TTtX@Wm>fl3 zDtL3kctHJ`zLJO02CiX>H=8RFeHoBZ!^bR|v;H%#Bo5|9!trpg8T1L6-AAsf-Mt`V9VK7fBi|E=2_ zB_=UUc9(`mhaEL^2!b}-!llpHx-FNLEK|i7;rVwgJ(OBxPM_7KuERKc3>Bg^R1}r_ z!r5?z63vdh`{>!td^KZ>^QU~D`sI-k~U$eyBmsZ5j}!gxx?)FH@XZjGY(cn`Ds+03V@;yXNh zv34b-XPC9NV9FSbSRz17AKK73xUOdZ2;##zsT7_fLIq8F()FAF_a9Kdihd=X%T;{o z^jWS{-LCj?3h<}PW?VkCVQ82ldU?*U$e2`Zf03lvJP?6$E`@#01hHY&sd%9~edB~! z&YDb`StrkHDk&hwWA9h+XFDiYLp;6wG*=H(&dnzJYX&d3p#s>(T>y&o?5@e|+^EfF@M4RRT+$DQDQ+F}&98`Y zOYrD494uPf2NzutV6)119(_GjHXg!TTQEAr{>i=hdT@Ptr-%f%%u_S{t8yK@byKu9Ku+=X zj;`-Ow!h*VVbfF5?jaVDYk_W)^iNpsrfR6JNvuUkA%^Fc=e(mNEAA=M(H^L)()=c> znC5U^G>q%(37K^0V2WNnYy7k2q9_)1duwk~dvC4h5R`(59tM zWRnIShWc}#mz^zM{SBLLx|A!ghnj~hwPkx-=k{7|hvGkx%dHo_OB2DpCBypb3C{@n zl0Hz%=iou`Ig;O|h?8L?`nB}Zh31RwxsUAXpTO_%cr+j5t@%@#QdD@_mLAQT5qwy? z!Qdg4jp*w)GfF9OhgxcOzDYO6FFMCP5R(kcAwJW@Q_m9G<9jn}g64B54g9@}Y)w~j zN}M}3UkP(2{Ydx>;-Mb6Gfjj{@zcu;o_>FrZ1nJ3Bi+rA&?JIofd)hT{Uh9nJXp3K zU_|?c>O-e7g#cho$VQY^fUV5|+9A*?b1+_-L(EKd;wS(n>$;da$_!00s&0_}n z!_V}uW(;`lW;y&nXS04l{lkUs@Hn>nPJ>6g(+1C<4t){hEh7_z!^0Ru#x|8*FF8#Z zxWT9r(e`jP6!G$IQOh^IjJb^1Y}$W5Z^g73#Xkc6HQ?EGi%(v_>{-f@pTU|%W-wAs z>p<1}8Q%(o7r>llh__B#SrCKFX64|ODrO3eIy=%>w@$dYb#-({H}D*mq)iuAJ3UY- zrIt2XBkDb3$a>S-5192D@IM?{cf3!$@%^h635FxpbOAS(h`Jm2ieg{EzD(rgeSpd@ zeYmp<^qszr$itO7x1d}yTiTJk$Cfb=ey-=ct5D zWSLj1W9Vcd01II5N0ArwSQ1jiP_NxXG%R!1YkRuC#k0%hm|1yP5cJed`ZaLXne-5V z5g`x*>kf}9hiEZ-4quR^XwXHBlDug;L?X6Lzupq^n?Jb)*0iNsUkU#ndRxmA#_HrU zOCgOdR0LxnU@L{kZ!?9rTi1Q$$-Kof`q|~Q;(y%DubyH(=Mae0N1i1xD(sao`bc!c zYT+|s%%iFCK`5%Gira%wo)=syN;@T!TNICoTUPJ-Q>{J4n4zNeOGHuWCVx{amJ^G* zVf0|HO^?Ae3K%VJU9?p)b=Whm!TkGc1b*5JN0Q&!=YsdlCDh;@r@%d z=!HqhsL4~!F+wH|@$waTHe>1U^BY1~L*Z_xip-;Vcp*=M;!R`A20#QCBeX5sgkjXT@f0QatW>H}!sRB%HL#1Zm zr04rp?u8L+0v zZ1+^J2!3IrY>bF#hpE=`0#e6%{{)JE&I2c4>TuQB*-7nk*mSOBvE{)`raS7{rTVXo!4N7-?H z@1$6Mq2;;&u4P8^QShGex#@P*OGMQUg?=<~#Gj?aZqxgl8lA68s;&r_4-e*^K~0$X z8N@Gr*<9bu4mucHE*4n_&@fxg@|Gu4iD-AY&}m{pgrF|HG6o47)QtJ zNN~Kx8;%HNWdfl?Jy>=csk<5aYuQ;L_h`hIB!BQNxvNt7{JFc;vXd(scXTr7&Ne{5G0@_T=w#6JCZ_J@l$> zUiP(l)R1C%CgBdFQs7b=LXB7Pv0<7XCrn|Bku!p)PkkaHOmC}^O;L$?RF`qsMKm(6_q=TRG^AJ`QG>mR{eDuDR`L-a>8N)aOHC zOaq|9E|$7irbvBT*$m6i{@E}xc!p95M%APvP}tvVuy)WNFn+?mh8;P~h~6TCR)i)0%xxY$~@8p$@={5O4odeydJ$2#465g3Mh) zy(ew|D7lOMvIk*dDs?u!)G}@wYS5SL6}8R#_!e3jhEh z07*naR3q%&y?weJ2^(9Ca%YvA%^!Jrje~@?@d1B!UyF3hl)VmaB!<<^uCm!h`{uVT z;W}>JMW&+ZfrqgZWH!v`LB`S5)vbVG7t0dsws%`!YAIAsx~%IrSAAL*n4akEGJR_6 z5ClVXaL?k;0eDMfj(k9}s=eVW;O~^VRM@vCN6=$P>z^%}c-1Y#4$s;zPw_;a2wwKk zsfK)d@>#`p+sPJjAcxyV3p|B7+8_(T;pK{}fIq)+sb>UxTM)Bayu}^24x(S`CSr-Z z(0g0dTJEii>DM0zx;C*z<6hVi7VE~XwcSI!!7&e4!?r&a^hzR*;g^`l5|9=%>mqB} z)&w4-Ji1Nww?n{5+EufVJ4Mt{zpCvUb`+hZAxRC*;a?>w*2z1kyCA}ieciRdc^LSH z)NFnNUuBTW7H~ZWwQU76Lc)s}^eD~FQHaI_&OEX!G2K|3n*-P;a?~nh&!O5R;~m+e zE&mEj+3h|Sz}JAM(Y_JF?5`H}JDktwmcTQ&iaOHtv291t*u+(a#;q|pTOs32(D*K7$(bVp7Rq9H%!TnvV#FRSz5E7#OLL+I55l zaho@FBbE!Mjt`-9(}qYp!kU2iHYeWP@IoJNoujB}p2$~Et(hJ`-#=60klwP36~thi z!Kok)N57hB-`+0I6a34av|jF3e;iW=4Tl#IcJMmUtEa~DuYmvQV4F4;6-*OLDM{yN zOJSwXs)XS$6--s7$T*w*ENVy>k%wk)lre1M6D7cC4;#mgpv~3jOLfjj!BgEy*I+cJ z%}M)lP~Grhn4^Z-F4h3_BvRVCGY3DCm#1R; z8&z%ybBV9yf_> z_r;z`hjIK!YA2CH564IJrgzsA!7}v2MmDdhp7z(PEpd9&#CN~zhPH?@rv9DpeC4u* zTJ-HBY03AH*EtRUuoN_n6d( z8mWWOXY48y=1&uQi)Qb>ef(}?%&>;;t8WaiZ2@7_%Aj&+-&$jJr3E*kpeoFAJz|gq;ff#s7sTW%0O~Ee)qh-Z^r`dXQ2#)9srjW>z z^Touo`Y`7|{qPpai;|gu35tqyliG1+TY`m44vt-^=Acy_4Bw0(_=sjj5mOZLebh(~ z;Scdc6G^6!$JiS5ToJsi--|ACrya)ZS-g+wVZW)82@iuT$=h0nHUnu(#k(p*9yzs3 zg$mXlnk?2ag_a$BdyKI*{5hmJ<^W$Qys29reHqD^1+Qf6tsMS>c=c^q!8dw*hpcyx z9nRqpjzg&%DtOmW0Z1pg_2MPpA12Knhn8pro)BNts2N% zo*lQD#BnD!t0l?<*L~yOfvWVJ!MFt6EDw?7%+btDyLOq@R1!LTgbJ-)Dn@T^JI5sY z&~f5+Rwy=e37Q_fU#1|GBzx@$nLp%$9A<$*{g;&CS**sEDd=FRsBXw~u(d*QT4k`w@2CTDgW8V6S z=scb;M>+7O0((x}xtMt#-qH2PGCO$iJiR8vbLb&5C~x<#WY`Ob`w#DJE28(joCr2>$b2hJgsewXublh%oN0)eW4qOTU?!5l= z0);diS;grh7}hVAWmepu=lp(q;JMYOikv~dlK%4i!zPzW+yK`(*PTh%V$I-RSMdCV z_&unp=%zYG1FP#;+}zV_&r|9&_9pCI2DMCb$qj4ER=-^R*ErUA&iSF2E{F0<9!ujg z$mWO}CYHpwE%^lLAES=rF|$qz_(tuj@}>#iu!QN_yU%3I7s?!VLR&jjhLEm`12o0|8d$?&E_dUJ4X4~atZnD4 zH}QvfPjOpe^#GOj2FPezo#^BqmJe-JOe$}Eb?|H45>xf_ws#$M&uL7I+}h7$+koui zH@koReTFJMiKusrc<}Fhn;^&xQu705z^8iWdJKo`W<&}uenJ0&{MlSTH5kgDhHULk z{rn96{71+RpU@P}mUVFxHp4)Sh$0&Gv=6~@Ix&`FwQokUM|qK!(8?ZIL!oH9Wa{S9 zd+NsLG~dz+qM@!p)&}wRIIv#gY%m&?w_(>*(cpXQ0mU#czRvjGEtIO(Er-w(9HYI> zBFv2s7cksUGU?0$2qOQ&2yE{2`ovwMFdm3Yo8AZ9?ewcBUb4!;rUwiye$Y)O-0oIqZia@=8-C zw3{hyN0wf3GqcO5!XSvJQu`#Z@)XU}zUm`7Sk{^Ur+TJF+~ZjuA?$s@GmZUE>|5r) zFWbEKv1^w-UDzlv&jKfcA5r4mjnf}1l+C+L*#P7T}fOn=^#4*yKqDwOWxD3d&d ze>7Z=X8xD-`ur4TksF>-EQVOWAxc}AxR}Hd`tTqAEp-eZO|UtOH%dfLZEIN~;<9Az7eNnE-YO;^a#GC~-% zj21gY(rAe^PFvHVR;OLn%XeT)g6#!KmBFu(#Iw~hz1&b&+PO$>q6`^J^w@qdKEaMW znVLzYi^}lxNOu+zPMS-9ne7{S;~GZ`)ppJh$R(GO;|MldRINwY2Vg>cLOh!_u<1H<4QKu!D?Af1mnydh~OK zQ4aN~-HQxI@02&;@X8;hd(Uhl&VRv;PVFvPm(+0zx5v+tWvn1y2_fjSH)pAOwRLTq z-L=>8`aRRb(3(0AO@h=eoE=_EqZVq0vR<1=nl?Q&^2v7LbADKy2Re@Hs7V>|&8hHa zQg|s&4=Z#eG0N5}7;Xv2IXtIH$`U8w7RVayysb9Fx9mUqhxgAj&hp+7;?JJvg-YT* z9RY6q#b(@H(g!9<)X>duL{i}xbbIaJS)w^Lbv!Ts@REk%=9v_`%I3tyF(se=2-}5N zS8#RRhK7>!$z&;a@f_mZomqbkh58sEczt7YJLoJsFxnW6PA z!>ji4fEfMF_VadEJ9@w-)2<)W%QBA%Mp>CvZ(RiziIV^65iFnKakH%AMm-N@tQL;#i$(*9LPLzJo6=%D^{|=DQ~8@2Q>8*EI{3=;%Th>=EPDuY^Zbvs z?7=#_sShLqq zChV=Kms@Ldj0gD-xYy&94V{j-R1Ze2U|J9oJy--EYf$+%mp&;c`uH=~e?|m0W7oIs zCCk%5L=HIXPF};t#y^TH<-pZX;IAdY-CuPtIV`+x<^mqcdI-a>tO5V zw=*oony>~uCah=?E8Yu)?u8Ov!XeITSMlB6j^no*#mV{Kh9Q`bxNo-z?LQDp24PI||%d^fzD{~t&FyZl}hAlE?MQBrI#$9j)dAF^2Xx068 zFkzL~vC5cYmljQ4E%8VYJn_DQsXlv-Al%NjRc%4rsZ><=yumK}7VKlSYlG}qas>C3 z^7#0_5}WkvNTvPW5A+ho1&$2t_yfo8_vW{=Rlp|N@;Fw}*S(poTUoi89h*Iiuc39M ze7sMT3JZxAv1)61tIF$fgIV`WtK(f;!N>2&?CC1|PdYnd%|Gb-Mh}PRUU7!U3T^UIr!$!+N!fc9w>7~@yudP5i=-tw8I-YvfoxPXNYu= zx&EfN3-@Qkn>VgZ=4|p)0Dn9@*LQ8yxxMP-05ti{=-^-z-@}G~IeOa2OaFKY>hGnt zvBF!k-tNLSp4hioBE1LcY~nu5;F{WsmYl*fS(oMza={PA!)@(Mt$eE>y~Zw|Z`nFe zz5K)bpSL4w*-2etZe{b8@M{F?JH_iPgQ#I642^cj&YS8kLZjW?oyuKJSaPQHDdzWP zvq_`AJvQ^#D85X@Jfq7t#2NeBM(_OQDVm5h~g-_9BBm!E|MJV3#-BO9>}Q`EE8M(HLGc9h??Z|>%@uAxu#(B^dOK?aer9~9?nzeJ)Z{xmUg^?zH>~C#FOrLc9gXEawIw5a) z=+&+}M4rWx`#5|aq0*^Kj6u|qcGtH<;004`iBfL=pKNkZ(=>}Q+H%Fx8-QNMLuo4{J%ysD-HqC ztCQD}TI+$#!@_g1w}-ceUgiN#dEv~$%c88-ZFvpI>1y93ka?Q6wwW>JFz&o_a=^pG3)FdaJ#c^{hCjx+tVOZN~(vKWN3Ma3`i>>Nm|l*}|LlQa5g3J=kyn^}3MKSe}a?sw4Z7*+elLCFT;}W|Iz)rMeSU5(VH91m$qUz0X-|Scj%4`zr6=NDVqjNDM|kfz z=w@s~@2#Cethl25j1Z`z5 zaS)&Sj|dh-t8|!`=j}sdsO#IaDAxv!Pyr*$I%5#=t=Y?&!n-E!@*n;$Q&pj{_rg$lt+Y3`;` z!3Z&O>LYmiXKQk%(r)lh2cyLn+Q;pDD!a^hTN2s*nf}m<_jo1sk|SArhhKkFtR5>Y z`a22aeZUSM@bu*!b zJ>I(t_-OVYLH{Aw)4UXs!Zn5RnG8W5c2S?7BjF*<+_0O4s9JSPlvcx+*}eK?;|A38 zNVHELv)*5{7dGjVeC7`K!3eAszCDc@DLeF@x~~>JndIpX#{{wA>2gydBGS z!ehUwho>nZT-e6(A@J~I2!rUayH*m_(d}v7o74{Dr~D$kk^9~p(%&|w#@qcnJhe=3 zNB0!7hry#1CH^-t(s{igUs{TlwW*lGKm6TC?0eo-7TrWP>$6#ZXuh%^o?(o$&~4aS zz8K}|qeLG0q?wOMW)$NiB&kAqx=@kvJou2+FW57`O^j4Av@H)mmgi;?#bFZj9!~7d zd}3xof$17%W>#ut}R-)LzqqaXKEC~ub=ama;oixZ65C|JjOK^; zX|PW5t!?Lvw0oY0Kr!u>I-34nH@zP4nsP*Hw<31^J=r?{PBA;e+&8n zb4X}WB|o4r#9UtV*rhdSVGN+%l2sR#!Dy|Znf4V3)6DZ5gXeQ=ukQUmy}q`P=Wp11 zNYTd=kR6VMnlF?ImUsPdkj@m%{jAEVkY(f;+xp1Vzy|m+;MKC5E2E%i+`n2bYk4V+ zCGqs- z+D*K?wR;^pl_=zW*2?bkL(~vNTgoB?zz@01g#Xj_BPrfZlwtrk=>-uWy3Hw(u zj)Wdnpd;dlP+GpI5}yli1_ z|N7$#Sk=S@Yc!7u^=Rs$D5gsxv&gH09~1W1i5>!cUQS~@f_@C*6Y@h*puOkeMe-GO z)5wq3vQ86pYdei*ngJaYbG*D7_8?GaHOa&NKl6w=adPI_clKv9zo4bd<6Rn zn@F2;aN4Y`MUA;tDF0=Bi+a@w#_MegukdN#fkq^_$3`yl{%gFRRyB*L z=Cjvf>BfBs&NS|o@Rz*;I=E4=Xu+j9y$WG@oeGk7XC0IZv+u+_4r7{qHP1_&f<5I3 z(#Iy%EqCpMY)UtFZC!_al~71CmB$(Da!-531b!X!sU{wlTzju!p(^`0ndWz9l{b1s zPOowoM?fQ5+0`Da7s@VQfvXu8ds>exEDglfUA@WIEY~uKm1%)zdMM1 z#IwWd>}Yp3>8)c44zS;^aF zs5jE;*ktq4A36m2Tq*86E^4t116+}5s~uYJqAYlc$lQ^e*DHy-k((cr|V? z&}P|Q;@LMZ#w_ZsUGgMTUd7F>B*%Nz%b&oX=G9lf?J?5-IYU}_Q36Vs$K~mi8|pCn z)-6Ara@hQJ!QW@M4*gy&8 zt3Z@Ox1&**rz^uH!?Ee*R?NQ1!FNY^tnz&T?uFS~Jc5mE^Y=)42yN6xv*MX@{#>K& zS^T!srM%y#oAFQuDAiTm*1WZ$zJ?ZWAHl1?S2_&VYOlA|HquK_{s;InxiVb!4#TXY z&_aflj4Gx_(rxRvK6`?Pc?+rWv6f0W^d0dha{1~}_kO?fm^q?l963ug?2z^CF~qjN z684C^H;J(=qw{Cb%KNsAO@p$9mQ~=TS6f^-9xJJ-Tiw0yZbS<>tTRX%S^dk@xU(Fq ztWVs#nYOt-!vkR!LLak_`baN+*t3Yd*OTeub<@bQvYi2lOSDP#KW)b{)!JiMWGWXil^r4&^uF@=G-h6_(O{B4>@nM8y zwMU+=+-Zf&d*%H(1a8x;Al9}L`~75450s;mcP+Gq)yGlbe52oo|GaQyNjr~hcNoi& z?KYw`1|kV~5-;<~&(1@WMzfDPTYf_u)60w7$uyT&&h;RB!A^EBTf(e6f<+{e%gZv% z!ig>7Z0O}PU{>w_udB1$lHd-Eo%qhJPu^OB=M#KFQD&PdlDx+5nmxXLqTj<;os7dL~h zQK@Sv)!K$N4eN(CikG$wMlg{FSKYLXorGI^s})-&XL%xJL(8CE)mk~HQxd&+D#us( z$eqk?zB52D2Jq0}^!9cVYtIyR@O;4*aux{S>IX&4M+;^kaZ8)KKB}R~X%uFnRCRLi z@lzW5Z17VW@@beaQ${kq_-@+zjocHbp<@=4^X$r|ZzTg2v+z?t3o~o9O_Y|ydf1ld z3oreiHkp)-4{ipzkICj+@C|EK?u*kCzYA00*xXgvRx;v8v6!r(4FYI18C=qIf5h z6)Vk~8Nr3ZFED6gg=@SjF{syeO!xl3J)Sv9C%36q$agKKG}2x+>EUr;e9*=<2hU`` zwPvoQGwFjGfPC;>Wfp>C6!rN0iyi(j%v%E^4W*`Y=+z5f_cy!^PD>_H6;FX2jErAK z_c7QBMdbDv+Jmk1)2X`{4$Kb@-OLJj(V%)QdLSAAQc6J$U+nE6>Z|mFE;I|60aD-F5(8RF*1<(N$ z#+iT{0~qSTr3of`>kXgUX_e=MsW&?mDlwBGk-Yo)Mb8Ypb5M8dL*kRv<{bL#l9f%}QIl$9OBhd1Sl0kfvepHkgUse^g}Zyj=c^_MRQ(goySz_^Uo?y00P>tnU!PaQUI z_?-9{g&zt0Q%xH`sFV`NM=K+CT{*-OAXq9}g1!?*oMY%u+@SOzbFM8MvcP!3-F(Sf9WL% zI+_5TqVnDDjWgO88v9&Bz-T4Jg{&Q9x0lkl_i)<81nQhIk| z+e;e!Hf>COMdNfVFMVV-c)XgN>a&=HK0kr+Dc;~0zW}C;1M7oG{E)@2q%&-P@YE2@ zrD7hsdQ6eI*#S{@zIbadf&QG)4?wr5lbXgke83|2atm6rSfnIh>e;nWu@7wuT{=LV zKh#q*dS@I7EHQJSurQJj#P=#hCH|=?36*W+u+-du3&?=MS8KarfO;v9m((T>X-XVZhM8$f)Q;rFEwVj(wcpHuAuq9Z2JdfINm<3abV9p(-LGY} z?OEI{HY6ZWs9eBtumR9Nt{`j?0!w(ZNizZKg30i-8Y)o7@!OdxJiJ{^b zw$Nm0z>>*nS?0hMiRF{))+TFaKM+FMY~Ou*C9zclJIKPg&aLEU)>Ulv#!I__Y9*4k zuSmimIQimL(@0(~#p&iL@-jN-fR1RE0Rl^=Xky|ixsY`nTTgh=3prgs(Ad_a(z~mp z&DkP$b`baD3`ZQHnb_8X>qAkDS(_9LrFJg1LuOPWf)Bw9td?C1qf@MeG>7A4>GtN! zPk>&j4a_R6!I?!Cvk49}Pz2Ge4M%UOdLZss5SpD*T$jk*Q`@Colg7t_BP%Z3)SmE+jewS96ScEMg3hYY66&! zuH{sF>y4hj(QJC-I(sUx8OkcGGNyj4zUq2B{I-3Qv^z7mP_;dcAr@jE+1|k%si}m1 zUze}ZYVeBGX}2-Edkop`Rw+*o)M59Drr0eP*>3p+ikBoB&w?{$lj^;D( z2Ouf2&I4*#APXo}xz^I1*`rPy+>~KZ2~?b*HQUEqcV@}sMsOatQYdpVXAgz%DEtaO zY!0J`zL((W2>3(|=B3%B^0%P0tgB!j1^WPE7E)kn!@#h@lvvfk-h1T0g}|#Ekx9+| z_SyrH6E1Zxx12^1#una$9;ml?doN^2GCuV0EOm07=$U>CQ*Gcr0o?w8U5N#5NLl<#2it_QcaYmEy8+WHqJv@Ppnjkc)77aYqAwWP!E!Gv=- zG>UJCML(IkMvU$t>mE7*bLQ_1m+7NqC`sTOfd58eiQW;tz)*C3hbfwxZl-|)F^GJ} zqkwM)yQrDx%~ZJClxc<#a;X8W!wL^Gyn?^0t;MRpTx!|w3~XcLQmgI3l_UfULd&;@vVn7(DWSLAEtKw+7*0$( ze<#YI{zBm=>Y!g#qL+dY()7m9L=GqR{hOm62ESZ_Q(fm9t1WZ+?Y%Gu@UJW^CnkQil5AHHfvSO2gh~iy zhXGPW!HBkgOG4|<4Aa_`@u}_GqmB>wD8rZ9QRLa~MNW}ZnTS?$5|tAv(`oA_qYIRg z$YZs+0XQ6iOn!br@1hHo949t9??!sSB0i03~fry*w1Iwvoi4QJLFcsb`*Gwh_kTwW-4o$#D8p@VZO*C{$ zmop~uaKj1()(UiOb|Z0-JG5~)bO3G9OEn`|s8=b8D@Xh337qWXy+R3Kve`LD#TgEp zq>wlFk=JRL5iL*&uBRnUvMMRB3m-*_`?GzC$BBvIM`YBF-(ybjAiddeoPFl3v#Ngc2>a80a45y?_VPQ3$ROfqi~IH#s{M7_ixiySwC5`I6DQ!_n3HnCAR9fU#0k8Qz4 zTjR$B9yjp2^OZCX9V4d&{6`n4zq_i}hfni2>)fy&& z4wG37=QJ^;vRz59gdD6y$ssY}Bz@FHR4P}RDt_KfAqReZ(x`XLY4NDn5=!hG_NCK9 z89O-0H8ZT@8_mT>;kLrdCt|4bpM)gE1n*#h+_ygm!Bzu5+lMKxFcFMubr3^GU|DOZ{qQW7+# z!c1Nul7$U&a-jRHii(^P9m~?T!sZ|(_jN-R>-*FZ@2EKw(S}FgCH4N2H{j_MrKV9h z+7HwWK`lPGeO&s>*0N)(T7LKgAgO$~hBd~}i;@O!DAg03fK!q+`Q*}5Ap7_*87*9~ zHEpJlNoAACq^$A6Y|)Ge>Ek64hxQI`flRV`yq}`Z5qe|$SA}vBcvJoWK> ztp6GK`et}eYU$@E7jt$M?B78BhhuN39`OvG@<<6e3lkG`<~onLSDBfvgu1Tyh!qt?fQ1#i>@>-WU728a+M&s%nXu)2M0OSVHj5>J`K!9 ze4IKF(X)->71V;**&dgY`9-I#2g;_#x&&%Iirgd{B!J+m0-*;@Ub{K;;eshC8v2Ax=d_BuJ=a{LQD$Ma8oOEjM zFaQmdU8)cgHiVG%p)Wl#f(hUw^6X00nrwQGu`F>ngp|NvMzo2AE6nlmcFa2VB{2hn zAxVN>e4^JZ*b7@yR29n0CB>tIk}OzE9#_7i5!;^^g z^L2C0m;I&3_Wwr#k%ku>&%uW!yePOta%^gIPv^Xs?d`;E9IOghJUBM)4c0X3kp86!J-`9lu}oxBJsr%~|XVmYa{ z7-C7L;6%R`kKrhhZo|dFRh~}rEw!G2i9BUmGSFPwop=2|4L1RWHk6B7hL=+a62TxS zU(NoNwmt!~slBxn%H8ja24P;h4rovT3iaY0zc-sHF0j+DNE;SsFTWQxdALai=iY!q zR3>rZq;l_8PF;lwa%pG4)U`{wK8wo`51_u$I?vI8tmo>W=QPAmL;ma)gBDF*%x}7U z>pEtEox^H3wUCoa2J2;B@A5rLO6@kZ%C%^r+$3PGFuVfzH5kjb_tNs8`Qnm;h%vQ% z-9r`c(I!><=GnbvvZ&|*M0+p8x*%n+iDYq{G(0ii5Ufi1gvH706TQodBy1bDvkbio z_9{j;mn`e1902`uP2fLi_!{IHAv$>44y_yZ=MYA2C{*a@TSs4y-gv6JK+$+Q0DRKv z^yv9Wz1iI-AB_6Wadth`LYnFV6|7viVJztv6kusu76HK(e}EcIot#Wf zZ8Z}xR{%fFu<}jMpS|bT@+Ucs>kk83J2ISDJMiB9zC#Es2sj>RO-Yj|!OYS2DY0z^ z6eeAMOdUIo#9`Jud*$F1yA>~k4~9ASkO$_d`$lAKA0v$OhPzmM++Hv(B%D3~x_+^O zBkhQ7!0a#VX@!>!Dv=}z9o6DYrHA%-8#Kf6B&v=n(E#k+y{Qa@-!gdK^X&Ouq(`=s zn)FN7?T!t)s0UED6vA4IH&~U>DOxe`5&XH zfkp#6nYL(SA(g08frJ^N*_6qWrF6jNqUNAm*UXpsinqHe1$M~HO`UUi6$mzk=EeZ`i0I@N~)Z~RGUb? z-Z8b5%%3fJp{8v_cFwHibU$^ zurH;WH%zGotj4>NQ>#!H(uTS|tChEtK!KP$cPf{|3r{b+^ue7Eu$*Z|`hQ*d# z)e!ZpIM_}v#7v$nJswCqsV8Yj8)~t)yjo%p+o@tEzrbi3i1Dgy@3?7xZ9UtM{3A57 z-3j~#6=nNQz?L07g|qo`VAdr|lAS8p;kpHd6xzM@?8})!-+O6`k{B`H`enm1 zM`GbN!>fgl$32NhI%|0`=1H+a5ve;q2# zldWZCO*A?C6u@@N#=Q{-WEr{D)o7*fM&dUQsSYJvMewlP1vqooF3F`^gRe2|bgF5_ z`ryMQZm_q4g%h|c+ONsQ@wezx zJ09q&?Pe}h%zS4VcmD5=uxX^gVz4t3pKiFl6xqW4yRYP1j|sUTs6|i>l3Ve{nSwiG zcI}bKt6xOlOMs1?SAb;Y`SMxHxNK#UQ@Xe0(X7H_*EI~2j^zOTRSi?yTYY5XB0LAJ(U$e@vv^KqsETb=Ua!2irqUV7`dnm;lbU%e?qI7O8WI0|{xXf`&!sg#N z*okk%CR(Rz>ie8Elu*a3G*@>vl8$9-`cDDJsqBzq_|LKKbYkSQWdqVPc(!aFTjW~e zG?GBJ5G&zRISfsYZsQP$)W3#fjxKWQ;8BKdWyhAh?qLavDV630`(7AV;{KViUx{3a zmz1h&4y=((-9{km675@gx{66-a+vMS8c%vTfcpe!9B-bM(yUO!u&i(o(y|MK>|S*T zHK>bE?K_58{Pv<1Y^=n8dEuV{+^GbU4qfVnaQl3IHLDp6}nWvsYdp<57k>K;48DIWw!hAY4L&JFh--9Z#oyebfKCB{gsmAZa3 zCQw^0U>qK0m_EiIY9DWLxfv}{c9vlK=t$aUj60hHh42BYxrSAP(J^l@> z$z_LY$Ye`u5B;+M$5LYUI$W5|hmrDEmbg`p=QQ@UT?CaOG}sBTg0ee`nDC{115Gv` zMkmd`XQIk+4?ciP5iIx{@J|xQhRJ-Q`T8uDhhwYxcXPTidywI_kVwU?Ib=Syfly~~ zZH~)PTlC!FLm7YNg*B8eTA{q?5WSSge+I>#v5HjEbwHNg5vJP~j?Tuz_!d8mJxH*| zjVojs*fR%i?L^6(pz3CP(C8O3MWj}%s6eg@RyWx{FtXZf9`D;8A$K3%!Hn2>JrGc_ z3Ru(eWkI-tOqu-uh?q?b%q6kuqWjqwr+in4B&x;Ne|h0I3~O?#c8@}Sr_~HYZ;qR+ ziPTK!w$PD{%|oD_D{*Ob@Cxh{mY%lIa_)Kvq_U9QY_IZok)Q)yuQaZ*SEFh*s8UD= zSJw5p|L>29!2tMt%$Jp1gFM}evB%oTbL#}kV=MoxvVl_LY&*y_sF zvowsG3#?HC(^4s*2ckR&@Hv4mXM4LooUZCYEl4`8RS)e3P?ENz6TPVe^J42bx5tMc z>x!;{0;oxZz7-u;Vh_aN&c0x0Dky@uSK-5x^7qNi<8qF>8|zt?JBt}8+}g^v8!dxV gMoYrLm+F-N1M82l_OpCl^Z)<=07*qoM6N<$g1e6Q^Z)<= From d9d84bd7b2054cba16e6d1ee3c7110daa2a82d4a Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 1 May 2015 21:43:21 +0200 Subject: [PATCH 1080/3725] Remove bullet raycasting shapes, to be replaced with OSG ray casts --- apps/openmw/mwworld/physicssystem.cpp | 123 +------------- apps/openmw/mwworld/physicssystem.hpp | 14 +- apps/openmw/mwworld/worldimp.cpp | 4 +- components/CMakeLists.txt | 6 +- components/nifbullet/bulletnifloader.cpp | 123 +++++--------- components/nifbullet/bulletnifloader.hpp | 5 +- libs/openengine/bullet/BulletShapeLoader.cpp | 5 - libs/openengine/bullet/BulletShapeLoader.h | 12 +- libs/openengine/bullet/physic.cpp | 163 +++---------------- libs/openengine/bullet/physic.hpp | 22 +-- 10 files changed, 87 insertions(+), 390 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index a1b37a275..14cab6c82 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -519,58 +519,6 @@ namespace MWWorld return mEngine; } - std::pair PhysicsSystem::getFacedHandle(float queryDistance) - { - Ray ray;// = mRender.getCamera()->getCameraToViewportRay(0.5, 0.5); - - Ogre::Vector3 origin_ = ray.getOrigin(); - btVector3 origin(origin_.x, origin_.y, origin_.z); - Ogre::Vector3 dir_ = ray.getDirection().normalisedCopy(); - btVector3 dir(dir_.x, dir_.y, dir_.z); - - btVector3 dest = origin + dir * queryDistance; - std::pair result = mEngine->rayTest(origin, dest); - result.second *= queryDistance; - - return std::make_pair (result.second, result.first); - } - - std::vector < std::pair > PhysicsSystem::getFacedHandles (float queryDistance) - { - Ray ray;// = mRender.getCamera()->getCameraToViewportRay(0.5, 0.5); - - Ogre::Vector3 origin_ = ray.getOrigin(); - btVector3 origin(origin_.x, origin_.y, origin_.z); - Ogre::Vector3 dir_ = ray.getDirection().normalisedCopy(); - btVector3 dir(dir_.x, dir_.y, dir_.z); - - btVector3 dest = origin + dir * queryDistance; - std::vector < std::pair > results; - /* auto */ results = mEngine->rayTest2(origin, dest); - std::vector < std::pair >::iterator i; - for (/* auto */ i = results.begin (); i != results.end (); ++i) - i->first *= queryDistance; - return results; - } - - std::vector < std::pair > PhysicsSystem::getFacedHandles (float mouseX, float mouseY, float queryDistance) - { - Ray ray;// = mRender.getCamera()->getCameraToViewportRay(mouseX, mouseY); - Ogre::Vector3 from = ray.getOrigin(); - Ogre::Vector3 to = ray.getPoint(queryDistance); - - btVector3 _from, _to; - _from = btVector3(from.x, from.y, from.z); - _to = btVector3(to.x, to.y, to.z); - - std::vector < std::pair > results; - /* auto */ results = mEngine->rayTest2(_from,_to); - std::vector < std::pair >::iterator i; - for (/* auto */ i = results.begin (); i != results.end (); ++i) - i->first *= queryDistance; - return results; - } - std::pair PhysicsSystem::getHitContact(const std::string &name, const Ogre::Vector3 &origin, const Ogre::Quaternion &orient, @@ -600,13 +548,13 @@ namespace MWWorld } - bool PhysicsSystem::castRay(const Vector3& from, const Vector3& to, bool raycastingObjectOnly,bool ignoreHeightMap) + bool PhysicsSystem::castRay(const Vector3& from, const Vector3& to, bool ignoreHeightMap) { btVector3 _from, _to; _from = btVector3(from.x, from.y, from.z); _to = btVector3(to.x, to.y, to.z); - std::pair result = mEngine->rayTest(_from, _to, raycastingObjectOnly,ignoreHeightMap); + std::pair result = mEngine->rayTest(_from, _to,ignoreHeightMap); return !(result.first == ""); } @@ -626,30 +574,6 @@ namespace MWWorld return std::make_pair(true, ray.getPoint(len * test.second)); } - std::pair PhysicsSystem::castRay(float mouseX, float mouseY, Ogre::Vector3* normal, std::string* hit) - { - Ogre::Ray ray;// = mRender.getCamera()->getCameraToViewportRay( - //mouseX, - //mouseY); - Ogre::Vector3 from = ray.getOrigin(); - Ogre::Vector3 to = ray.getPoint(200); /// \todo make this distance (ray length) configurable - - btVector3 _from, _to; - _from = btVector3(from.x, from.y, from.z); - _to = btVector3(to.x, to.y, to.z); - - std::pair result = mEngine->rayTest(_from, _to, true, false, normal); - - if (result.first == "") - return std::make_pair(false, Ogre::Vector3()); - else - { - if (hit != NULL) - *hit = result.first; - return std::make_pair(true, ray.getPoint(200*result.second)); /// \todo make this distance (ray length) configurable - } - } - std::vector PhysicsSystem::getCollisions(const Ptr &ptr, int collisionGroup, int collisionMask) { return mEngine->getCollisions(ptr.getRefData().getBaseNodeOld()->getName(), collisionGroup, collisionMask); @@ -712,12 +636,6 @@ namespace MWWorld mEngine->mDynamicsWorld->updateSingleAabb(body); } - if(OEngine::Physic::RigidBody *body = mEngine->getRigidBody(handle, true)) - { - body->getWorldTransform().setOrigin(btVector3(position.x,position.y,position.z)); - mEngine->mDynamicsWorld->updateSingleAabb(body); - } - // Actors update their AABBs every frame (DISABLE_DEACTIVATION), so no need to do it manually if(OEngine::Physic::PhysicActor *physact = mEngine->getCharacter(handle)) physact->setPosition(position); @@ -742,14 +660,6 @@ namespace MWWorld mEngine->boxAdjustExternal(handleToMesh[handle], body, node->getScale().x, node->getPosition(), rotation); mEngine->mDynamicsWorld->updateSingleAabb(body); } - if (OEngine::Physic::RigidBody* body = mEngine->getRigidBody(handle, true)) - { - if(dynamic_cast(body->getCollisionShape()) == NULL) - body->getWorldTransform().setRotation(btQuaternion(rotation.x, rotation.y, rotation.z, rotation.w)); - else - mEngine->boxAdjustExternal(handleToMesh[handle], body, node->getScale().x, node->getPosition(), rotation); - mEngine->mDynamicsWorld->updateSingleAabb(body); - } } void PhysicsSystem::scaleObject (const Ptr& ptr) @@ -762,9 +672,7 @@ namespace MWWorld //model = Misc::ResourceHelpers::correctActorModelPath(model); // FIXME: scaling shouldn't require model bool placeable = false; - if (OEngine::Physic::RigidBody* body = mEngine->getRigidBody(handle,true)) - placeable = body->mPlaceable; - else if (OEngine::Physic::RigidBody* body = mEngine->getRigidBody(handle,false)) + if (OEngine::Physic::RigidBody* body = mEngine->getRigidBody(handle)) placeable = body->mPlaceable; removeObject(handle); addObject(ptr, model, placeable); @@ -806,30 +714,6 @@ namespace MWWorld throw std::logic_error ("can't find player"); } - bool PhysicsSystem::getObjectAABB(const MWWorld::Ptr &ptr, Ogre::Vector3 &min, Ogre::Vector3 &max) - { - // FIXME: since raycasting shapes are going away, this should use the osg ComputeBoundingBoxVisitor - std::string model = ptr.getClass().getModel(ptr); - //model = Misc::ResourceHelpers::correctActorModelPath(model); - if (model.empty()) { - return false; - } - btVector3 btMin, btMax; - float scale = ptr.getCellRef().getScale(); - mEngine->getObjectAABB(model, scale, btMin, btMax); - - min.x = btMin.x(); - min.y = btMin.y(); - min.z = btMin.z(); - - max.x = btMax.x(); - max.y = btMax.y(); - max.z = btMax.z(); - - return true; - } - - void PhysicsSystem::queueObjectMovement(const Ptr &ptr, const Ogre::Vector3 &movement) { PtrVelocityList::iterator iter = mMovementQueue.begin(); @@ -913,7 +797,6 @@ namespace MWWorld void PhysicsSystem::stepSimulation(float dt) { animateCollisionShapes(mEngine->mAnimatedShapes, mEngine->mDynamicsWorld); - animateCollisionShapes(mEngine->mAnimatedRaycastingShapes, mEngine->mDynamicsWorld); mEngine->stepSimulation(dt); } diff --git a/apps/openmw/mwworld/physicssystem.hpp b/apps/openmw/mwworld/physicssystem.hpp index bc61914bc..23bf47543 100644 --- a/apps/openmw/mwworld/physicssystem.hpp +++ b/apps/openmw/mwworld/physicssystem.hpp @@ -60,29 +60,19 @@ namespace MWWorld std::vector getCollisions(const MWWorld::Ptr &ptr, int collisionGroup, int collisionMask); ///< get handles this object collides with Ogre::Vector3 traceDown(const MWWorld::Ptr &ptr, float maxHeight); - std::pair getFacedHandle(float queryDistance); std::pair getHitContact(const std::string &name, const Ogre::Vector3 &origin, const Ogre::Quaternion &orientation, float queryDistance); - std::vector < std::pair > getFacedHandles (float queryDistance); - std::vector < std::pair > getFacedHandles (float mouseX, float mouseY, float queryDistance); - // cast ray, return true if it hit something. if raycasringObjectOnlt is set to false, it ignores NPCs and objects with no collisions. - bool castRay(const Ogre::Vector3& from, const Ogre::Vector3& to, bool raycastingObjectOnly = true,bool ignoreHeightMap = false); + // cast ray, return true if it hit something. + bool castRay(const Ogre::Vector3& from, const Ogre::Vector3& to,bool ignoreHeightMap = false); std::pair castRay(const Ogre::Vector3 &orig, const Ogre::Vector3 &dir, float len); - std::pair castRay(float mouseX, float mouseY, Ogre::Vector3* normal = NULL, std::string* hit = NULL); - ///< cast ray from the mouse, return true if it hit something and the first result - /// @param normal if non-NULL, the hit normal will be written there (if there is a hit) - /// @param hit if non-NULL, the string handle of the hit object will be written there (if there is a hit) - OEngine::Physic::PhysicEngine* getEngine(); - bool getObjectAABB(const MWWorld::Ptr &ptr, Ogre::Vector3 &min, Ogre::Vector3 &max); - /// Queues velocity movement for a Ptr. If a Ptr is already queued, its velocity will /// be overwritten. Valid until the next call to applyQueuedMovement. void queueObjectMovement(const Ptr &ptr, const Ogre::Vector3 &velocity); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 8cb9f4d50..416ef7416 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2724,13 +2724,14 @@ namespace MWWorld origin += node->_getDerivedPosition(); } #endif + /* + Ogre::Quaternion orient; orient = Ogre::Quaternion(Ogre::Radian(actor.getRefData().getPosition().rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z) * Ogre::Quaternion(Ogre::Radian(actor.getRefData().getPosition().rot[0]), Ogre::Vector3::NEGATIVE_UNIT_X); Ogre::Vector3 direction = orient.yAxis(); Ogre::Vector3 dest = origin + direction * distance; - std::vector > collisions = mPhysEngine->rayTest2(btVector3(origin.x, origin.y, origin.z), btVector3(dest.x, dest.y, dest.z)); for (std::vector >::iterator cIt = collisions.begin(); cIt != collisions.end(); ++cIt) { @@ -2741,6 +2742,7 @@ namespace MWWorld break; } } + */ } std::string selectedSpell = stats.getSpells().getSelectedSpell(); diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index ac7eef16a..9ec648381 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -52,9 +52,9 @@ add_component_dir (nifosg nifloader controller particle userdata ) -#add_component_dir (nifbullet -# bulletnifloader -# ) +add_component_dir (nifbullet + bulletnifloader + ) add_component_dir (to_utf8 to_utf8 diff --git a/components/nifbullet/bulletnifloader.cpp b/components/nifbullet/bulletnifloader.cpp index cdc06f985..1d07bea26 100644 --- a/components/nifbullet/bulletnifloader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -25,11 +25,9 @@ http://www.gnu.org/licenses/ . #include - +#include #include -#include - #include "../nif/niffile.hpp" #include "../nif/node.hpp" #include "../nif/data.hpp" @@ -43,11 +41,6 @@ http://www.gnu.org/licenses/ . // For warning messages #include -// float infinity -#include - -typedef unsigned char ubyte; - // Extract a list of keyframe-controlled nodes from a .kf file // FIXME: this is a similar copy of OgreNifLoader::loadKf void extractControlledNodes(Nif::NIFFilePtr kfFile, std::set& controlled) @@ -116,14 +109,13 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource) { mShape = static_cast(resource); mResourceName = mShape->getName(); - mShape->mCollide = false; mBoundingBox = NULL; - mShape->mBoxTranslation = Ogre::Vector3(0,0,0); - mShape->mBoxRotation = Ogre::Quaternion::IDENTITY; + mShape->mBoxTranslation = osg::Vec3f(0,0,0); + mShape->mBoxRotation = osg::Quat(); mCompoundShape = NULL; mStaticMesh = NULL; - Nif::NIFFilePtr pnif (Nif::Cache::getInstance().load(mResourceName.substr(0, mResourceName.length()-7))); + Nif::NIFFilePtr pnif;// (Nif::Cache::getInstance().load(mResourceName.substr(0, mResourceName.length()-7))); Nif::NIFFile & nif = *pnif.get (); if (nif.numRoots() < 1) { @@ -140,7 +132,7 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource) kfname.replace(kfname.size()-4, 4, ".kf"); if (Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(kfname)) { - Nif::NIFFilePtr kf (Nif::Cache::getInstance().load(kfname)); + Nif::NIFFilePtr kf;// (Nif::Cache::getInstance().load(kfname)); extractControlledNodes(kf, mControlledNodes); } @@ -188,28 +180,6 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource) else if (mStaticMesh) mShape->mCollisionShape = new TriangleMeshShape(mStaticMesh,true); } - - //second pass which create a shape for raycasting. - mResourceName = mShape->getName(); - mShape->mCollide = false; - mBoundingBox = NULL; - mStaticMesh = NULL; - mCompoundShape = NULL; - - handleNode(node,0,true,true,false); - - if (mCompoundShape) - { - mShape->mRaycastingShape = mCompoundShape; - if (mStaticMesh) - { - btTransform trans; - trans.setIdentity(); - mCompoundShape->addChildShape(trans, new TriangleMeshShape(mStaticMesh,true)); - } - } - else if (mStaticMesh) - mShape->mRaycastingShape = new TriangleMeshShape(mStaticMesh,true); } bool ManualBulletShapeLoader::hasAutoGeneratedCollision(Nif::Node const * rootNode) @@ -231,8 +201,7 @@ bool ManualBulletShapeLoader::hasAutoGeneratedCollision(Nif::Node const * rootNo } void ManualBulletShapeLoader::handleNode(const Nif::Node *node, int flags, - bool isCollisionNode, - bool raycasting, bool isAnimated) + bool isCollisionNode, bool isAnimated) { // Accumulate the flags from all the child nodes. This works for all // the flags we currently use, at least. @@ -245,10 +214,7 @@ void ManualBulletShapeLoader::handleNode(const Nif::Node *node, int flags, if (mControlledNodes.find(node->name) != mControlledNodes.end()) isAnimated = true; - if (!raycasting) - isCollisionNode = isCollisionNode || (node->recType == Nif::RC_RootCollisionNode); - else - isCollisionNode = isCollisionNode && (node->recType != Nif::RC_RootCollisionNode); + isCollisionNode = isCollisionNode || (node->recType == Nif::RC_RootCollisionNode); // Don't collide with AvoidNode shapes if(node->recType == Nif::RC_AvoidNode) @@ -274,33 +240,26 @@ void ManualBulletShapeLoader::handleNode(const Nif::Node *node, int flags, // No collision. Use an internal flag setting to mark this. flags |= 0x800; } - else if (sd->string == "MRK" && !mShowMarkers && raycasting) - { - // Marker objects should be invisible, but still have collision. - // Except in the editor, the marker objects are visible. - return; - } } } - if (isCollisionNode || (mShape->mAutogenerated && !raycasting)) + if (isCollisionNode || (mShape->mAutogenerated)) { // NOTE: a trishape with hasBounds=true, but no BBoxCollision flag should NOT go through handleNiTriShape! // It must be ignored completely. // (occurs in tr_ex_imp_wall_arch_04.nif) if(node->hasBounds) { - if (flags & Nif::NiNode::Flag_BBoxCollision && !raycasting) + if (flags & Nif::NiNode::Flag_BBoxCollision) { mShape->mBoxTranslation = node->boundPos; - mShape->mBoxRotation = node->boundRot; - mBoundingBox = new btBoxShape(getbtVector(node->boundXYZ)); + //mShape->mBoxRotation = node->boundRot; + //mBoundingBox = new btBoxShape(getbtVector(node->boundXYZ)); } } else if(node->recType == Nif::RC_NiTriShape) { - mShape->mCollide = !(flags&0x800); - handleNiTriShape(static_cast(node), flags, node->getWorldTransform(), raycasting, isAnimated); + handleNiTriShape(static_cast(node), flags, Ogre::Matrix4()/*node->getWorldTransform()*/, isAnimated); } } @@ -312,13 +271,12 @@ void ManualBulletShapeLoader::handleNode(const Nif::Node *node, int flags, for(size_t i = 0;i < list.length();i++) { if(!list[i].empty()) - handleNode(list[i].getPtr(), flags, isCollisionNode, raycasting, isAnimated); + handleNode(list[i].getPtr(), flags, isCollisionNode, isAnimated); } } } -void ManualBulletShapeLoader::handleNiTriShape(const Nif::NiTriShape *shape, int flags, const Ogre::Matrix4 &transform, - bool raycasting, bool isAnimated) +void ManualBulletShapeLoader::handleNiTriShape(const Nif::NiTriShape *shape, int flags, const Ogre::Matrix4 &transform, bool isAnimated) { assert(shape != NULL); @@ -329,12 +287,12 @@ void ManualBulletShapeLoader::handleNiTriShape(const Nif::NiTriShape *shape, int // If the object was marked "NCO" earlier, it shouldn't collide with // anything. So don't do anything. - if ((flags & 0x800) && !raycasting) + if ((flags & 0x800)) { return; } - if (!collide && !bbcollide && hidden && !raycasting) + if (!collide && !bbcollide && hidden) // This mesh apparently isn't being used for anything, so don't // bother setting it up. return; @@ -354,18 +312,18 @@ void ManualBulletShapeLoader::handleNiTriShape(const Nif::NiTriShape *shape, int childMesh->preallocateVertices(data->vertices.size()); childMesh->preallocateIndices(data->triangles.size()); - const std::vector &vertices = data->vertices; - const std::vector &triangles = data->triangles; + //const std::vector &vertices = data->vertices; + //const std::vector &triangles = data->triangles; for(size_t i = 0;i < data->triangles.size();i+=3) { - Ogre::Vector3 b1 = vertices[triangles[i+0]]; - Ogre::Vector3 b2 = vertices[triangles[i+1]]; - Ogre::Vector3 b3 = vertices[triangles[i+2]]; - childMesh->addTriangle(btVector3(b1.x,b1.y,b1.z),btVector3(b2.x,b2.y,b2.z),btVector3(b3.x,b3.y,b3.z)); + //Ogre::Vector3 b1 = vertices[triangles[i+0]]; + //Ogre::Vector3 b2 = vertices[triangles[i+1]]; + //Ogre::Vector3 b3 = vertices[triangles[i+2]]; + //childMesh->addTriangle(btVector3(b1.x,b1.y,b1.z),btVector3(b2.x,b2.y,b2.z),btVector3(b3.x,b3.y,b3.z)); } - TriangleMeshShape* childShape = new TriangleMeshShape(childMesh,true); + //TriangleMeshShape* childShape = new TriangleMeshShape(childMesh,true); float scale = shape->trafo.scale; const Nif::Node* parent = shape; @@ -374,18 +332,15 @@ void ManualBulletShapeLoader::handleNiTriShape(const Nif::NiTriShape *shape, int parent = parent->parent; scale *= parent->trafo.scale; } - Ogre::Quaternion q = transform.extractQuaternion(); - Ogre::Vector3 v = transform.getTrans(); - childShape->setLocalScaling(btVector3(scale, scale, scale)); + //Ogre::Quaternion q = transform.extractQuaternion(); + //Ogre::Vector3 v = transform.getTrans(); + //childShape->setLocalScaling(btVector3(scale, scale, scale)); - btTransform trans(btQuaternion(q.x, q.y, q.z, q.w), btVector3(v.x, v.y, v.z)); + //btTransform trans(btQuaternion(q.x, q.y, q.z, q.w), btVector3(v.x, v.y, v.z)); - if (raycasting) - mShape->mAnimatedRaycastingShapes.insert(std::make_pair(shape->recIndex, mCompoundShape->getNumChildShapes())); - else - mShape->mAnimatedShapes.insert(std::make_pair(shape->recIndex, mCompoundShape->getNumChildShapes())); + //mShape->mAnimatedShapes.insert(std::make_pair(shape->recIndex, mCompoundShape->getNumChildShapes())); - mCompoundShape->addChildShape(trans, childShape); + //mCompoundShape->addChildShape(trans, childShape); } else { @@ -394,15 +349,17 @@ void ManualBulletShapeLoader::handleNiTriShape(const Nif::NiTriShape *shape, int // Static shape, just transform all vertices into position const Nif::NiTriShapeData *data = shape->data.getPtr(); - const std::vector &vertices = data->vertices; - const std::vector &triangles = data->triangles; + //const std::vector &vertices = data->vertices; + //const std::vector &triangles = data->triangles; for(size_t i = 0;i < data->triangles.size();i+=3) { - Ogre::Vector3 b1 = transform*vertices[triangles[i+0]]; - Ogre::Vector3 b2 = transform*vertices[triangles[i+1]]; - Ogre::Vector3 b3 = transform*vertices[triangles[i+2]]; + /* + osg::Vec3f b1 = transform*vertices[triangles[i+0]]; + osg::Vec3f b2 = transform*vertices[triangles[i+1]]; + osg::Vec3f b3 = transform*vertices[triangles[i+2]]; mStaticMesh->addTriangle(btVector3(b1.x,b1.y,b1.z),btVector3(b2.x,b2.y,b2.z),btVector3(b3.x,b3.y,b3.z)); + */ } } } @@ -422,9 +379,9 @@ bool findBoundingBox (const Nif::Node* node, Ogre::Vector3& halfExtents, Ogre::V { if (!(node->flags & Nif::NiNode::Flag_Hidden)) { - translation = node->boundPos; - orientation = node->boundRot; - halfExtents = node->boundXYZ; + //translation = node->boundPos; + //orientation = node->boundRot; + //halfExtents = node->boundXYZ; return true; } } @@ -445,7 +402,7 @@ bool findBoundingBox (const Nif::Node* node, Ogre::Vector3& halfExtents, Ogre::V bool getBoundingBox(const std::string& nifFile, Ogre::Vector3& halfExtents, Ogre::Vector3& translation, Ogre::Quaternion& orientation) { - Nif::NIFFilePtr pnif (Nif::Cache::getInstance().load(nifFile)); + Nif::NIFFilePtr pnif;// (Nif::Cache::getInstance().load(nifFile)); Nif::NIFFile & nif = *pnif.get (); if (nif.numRoots() < 1) diff --git a/components/nifbullet/bulletnifloader.hpp b/components/nifbullet/bulletnifloader.hpp index 0d81d84b6..81e854a94 100644 --- a/components/nifbullet/bulletnifloader.hpp +++ b/components/nifbullet/bulletnifloader.hpp @@ -107,8 +107,7 @@ private: /** *Parse a node. */ - void handleNode(Nif::Node const *node, int flags, bool isCollisionNode, - bool raycasting, bool isAnimated=false); + void handleNode(Nif::Node const *node, int flags, bool isCollisionNode, bool isAnimated=false); /** *Helper function @@ -118,7 +117,7 @@ private: /** *convert a NiTriShape to a bullet trishape. */ - void handleNiTriShape(const Nif::NiTriShape *shape, int flags, const Ogre::Matrix4 &transform, bool raycasting, bool isAnimated); + void handleNiTriShape(const Nif::NiTriShape *shape, int flags, const Ogre::Matrix4 &transform, bool isAnimated); std::string mResourceName; diff --git a/libs/openengine/bullet/BulletShapeLoader.cpp b/libs/openengine/bullet/BulletShapeLoader.cpp index 92d56b42c..26b6caa0e 100644 --- a/libs/openengine/bullet/BulletShapeLoader.cpp +++ b/libs/openengine/bullet/BulletShapeLoader.cpp @@ -18,16 +18,13 @@ Ogre::Resource(creator, name, handle, group, isManual, loader) we have none as such. Full details can be set through scripts. */ mCollisionShape = NULL; - mRaycastingShape = NULL; mAutogenerated = true; - mCollide = true; createParamDictionary("BulletShape"); } BulletShape::~BulletShape() { deleteShape(mCollisionShape); - deleteShape(mRaycastingShape); } // farm out to BulletShapeLoader @@ -56,9 +53,7 @@ void BulletShape::deleteShape(btCollisionShape* shape) void BulletShape::unloadImpl() { deleteShape(mCollisionShape); - deleteShape(mRaycastingShape); mCollisionShape = NULL; - mRaycastingShape = NULL; } //TODO:change this? diff --git a/libs/openengine/bullet/BulletShapeLoader.h b/libs/openengine/bullet/BulletShapeLoader.h index 907ff8bfe..472efac6d 100644 --- a/libs/openengine/bullet/BulletShapeLoader.h +++ b/libs/openengine/bullet/BulletShapeLoader.h @@ -6,6 +6,9 @@ #include #include +#include +#include + namespace OEngine { namespace Physic { @@ -36,18 +39,13 @@ public: // we store the node's record index mapped to the child index of the shape in the btCompoundShape. std::map mAnimatedShapes; - std::map mAnimatedRaycastingShapes; - btCollisionShape* mCollisionShape; - btCollisionShape* mRaycastingShape; // Does this .nif have an autogenerated collision mesh? bool mAutogenerated; - Ogre::Vector3 mBoxTranslation; - Ogre::Quaternion mBoxRotation; - //this flag indicate if the shape is used for collision or if it's for raycasting only. - bool mCollide; + osg::Vec3f mBoxTranslation; + osg::Quat mBoxRotation; }; /** diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index d5103d32b..0125fd01e 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -266,7 +266,6 @@ namespace Physic { new BulletShapeManager(); } - //TODO:singleton? mShapeLoader = shapeLoader; isDebugCreated = false; @@ -310,8 +309,6 @@ namespace Physic { for (std::map::iterator it = mAnimatedShapes.begin(); it != mAnimatedShapes.end(); ++it) deleteShape(it->second.mCompound); - for (std::map::iterator it = mAnimatedRaycastingShapes.begin(); it != mAnimatedRaycastingShapes.end(); ++it) - deleteShape(it->second.mCompound); HeightFieldContainer::iterator hf_it = mHeightFieldMap.begin(); for (; hf_it != mHeightFieldMap.end(); ++hf_it) @@ -332,17 +329,6 @@ namespace Physic rb_it->second = NULL; } } - rb_it = mRaycastingObjectMap.begin(); - for (; rb_it != mRaycastingObjectMap.end(); ++rb_it) - { - if (rb_it->second != NULL) - { - mDynamicsWorld->removeRigidBody(rb_it->second); - - delete rb_it->second; - rb_it->second = NULL; - } - } PhysicActorContainer::iterator pa_it = mActorMap.begin(); for (; pa_it != mActorMap.end(); ++pa_it) @@ -362,9 +348,6 @@ namespace Physic delete dispatcher; delete broadphase; delete mShapeLoader; - - // Moved the cleanup to mwworld/physicssystem - //delete BulletShapeManager::getSingletonPtr(); } void PhysicEngine::addHeightField(float* heights, @@ -407,7 +390,7 @@ namespace Physic mHeightFieldMap [name] = hf; mDynamicsWorld->addRigidBody(body,CollisionType_HeightMap, - CollisionType_Actor|CollisionType_Raycasting|CollisionType_Projectile); + CollisionType_Actor|CollisionType_Projectile); } void PhysicEngine::removeHeightField(int x, int y) @@ -452,12 +435,12 @@ namespace Physic BulletShapeManager::getSingletonPtr()->load(outputstring,"General"); BulletShapePtr shape = BulletShapeManager::getSingleton().getByName(outputstring,"General"); - adjustRigidBody(body, position, rotation, shape->mBoxTranslation * scale, shape->mBoxRotation); + //adjustRigidBody(body, position, rotation, shape->mBoxTranslation * scale, shape->mBoxRotation); } RigidBody* PhysicEngine::createAndAdjustRigidBody(const std::string &mesh, const std::string &name, float scale, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, - Ogre::Vector3* scaledBoxTranslation, Ogre::Quaternion* boxRotation, bool raycasting, bool placeable) + Ogre::Vector3* scaledBoxTranslation, Ogre::Quaternion* boxRotation, bool placeable) { std::string sid = (boost::format("%07.3f") % scale).str(); std::string outputstring = mesh + sid; @@ -469,21 +452,17 @@ namespace Physic // TODO: add option somewhere to enable collision for placeable meshes - if (placeable && !raycasting && shape->mCollisionShape) + if (placeable && shape->mCollisionShape) return NULL; - if (!shape->mCollisionShape && !raycasting) - return NULL; - if (!shape->mRaycastingShape && raycasting) + if (!shape->mCollisionShape) return NULL; - btCollisionShape* collisionShape = raycasting ? shape->mRaycastingShape : shape->mCollisionShape; + btCollisionShape* collisionShape = shape->mCollisionShape; // If this is an animated compound shape, we must duplicate it so we can animate // multiple instances independently. - if (!raycasting && !shape->mAnimatedShapes.empty()) - collisionShape = duplicateCollisionShape(collisionShape); - if (raycasting && !shape->mAnimatedRaycastingShapes.empty()) + if (!shape->mAnimatedShapes.empty()) collisionShape = duplicateCollisionShape(collisionShape); collisionShape->setLocalScaling( btVector3(scale,scale,scale)); @@ -494,41 +473,24 @@ namespace Physic RigidBody* body = new RigidBody(CI,name); body->mPlaceable = placeable; - if (!raycasting && !shape->mAnimatedShapes.empty()) + if (!shape->mAnimatedShapes.empty()) { AnimatedShapeInstance instance; instance.mAnimatedShapes = shape->mAnimatedShapes; instance.mCompound = collisionShape; mAnimatedShapes[body] = instance; } - if (raycasting && !shape->mAnimatedRaycastingShapes.empty()) - { - AnimatedShapeInstance instance; - instance.mAnimatedShapes = shape->mAnimatedRaycastingShapes; - instance.mCompound = collisionShape; - mAnimatedRaycastingShapes[body] = instance; - } - if(scaledBoxTranslation != 0) - *scaledBoxTranslation = shape->mBoxTranslation * scale; - if(boxRotation != 0) - *boxRotation = shape->mBoxRotation; + //if(scaledBoxTranslation != 0) + // *scaledBoxTranslation = shape->mBoxTranslation * scale; + //if(boxRotation != 0) + // *boxRotation = shape->mBoxRotation; - adjustRigidBody(body, position, rotation, shape->mBoxTranslation * scale, shape->mBoxRotation); + //adjustRigidBody(body, position, rotation, shape->mBoxTranslation * scale, shape->mBoxRotation); - if (!raycasting) - { - assert (mCollisionObjectMap.find(name) == mCollisionObjectMap.end()); - mCollisionObjectMap[name] = body; - mDynamicsWorld->addRigidBody(body,CollisionType_World,CollisionType_Actor|CollisionType_HeightMap); - } - else - { - assert (mRaycastingObjectMap.find(name) == mRaycastingObjectMap.end()); - mRaycastingObjectMap[name] = body; - mDynamicsWorld->addRigidBody(body,CollisionType_Raycasting,CollisionType_Raycasting|CollisionType_Projectile); - body->setCollisionFlags(body->getCollisionFlags() | btCollisionObject::CF_DISABLE_VISUALIZE_OBJECT); - } + assert (mCollisionObjectMap.find(name) == mCollisionObjectMap.end()); + mCollisionObjectMap[name] = body; + mDynamicsWorld->addRigidBody(body,CollisionType_World,CollisionType_Actor|CollisionType_HeightMap); return body; } @@ -544,15 +506,6 @@ namespace Physic mDynamicsWorld->removeRigidBody(body); } } - it = mRaycastingObjectMap.find(name); - if (it != mRaycastingObjectMap.end() ) - { - RigidBody* body = it->second; - if(body != NULL) - { - mDynamicsWorld->removeRigidBody(body); - } - } } void PhysicEngine::deleteRigidBody(const std::string &name) @@ -572,30 +525,14 @@ namespace Physic } mCollisionObjectMap.erase(it); } - it = mRaycastingObjectMap.find(name); - if (it != mRaycastingObjectMap.end() ) - { - RigidBody* body = it->second; - - if(body != NULL) - { - if (mAnimatedRaycastingShapes.find(body) != mAnimatedRaycastingShapes.end()) - deleteShape(mAnimatedRaycastingShapes[body].mCompound); - mAnimatedRaycastingShapes.erase(body); - - delete body; - } - mRaycastingObjectMap.erase(it); - } } - RigidBody* PhysicEngine::getRigidBody(const std::string &name, bool raycasting) + RigidBody* PhysicEngine::getRigidBody(const std::string &name) { - RigidBodyContainer* map = raycasting ? &mRaycastingObjectMap : &mCollisionObjectMap; - RigidBodyContainer::iterator it = map->find(name); - if (it != map->end() ) + RigidBodyContainer::iterator it = mCollisionObjectMap.find(name); + if (it != mCollisionObjectMap.end() ) { - RigidBody* body = (*map)[name]; + RigidBody* body = mCollisionObjectMap[name]; return body; } else @@ -617,8 +554,7 @@ namespace Physic const btCollisionObjectWrapper* colObj1Wrap,int partId1,int index1) { const RigidBody* body = dynamic_cast(colObj0Wrap->m_collisionObject); - if (body && !(colObj0Wrap->m_collisionObject->getBroadphaseHandle()->m_collisionFilterGroup - & CollisionType_Raycasting)) + if (body) mResult.push_back(body->mName); return 0.f; @@ -628,8 +564,7 @@ namespace Physic const btCollisionObject* col1, int partId1, int index1) { const RigidBody* body = dynamic_cast(col0); - if (body && !(col0->getBroadphaseHandle()->m_collisionFilterGroup - & CollisionType_Raycasting)) + if (body) mResult.push_back(body->mName); return 0.f; @@ -698,8 +633,6 @@ namespace Physic std::vector PhysicEngine::getCollisions(const std::string& name, int collisionGroup, int collisionMask) { RigidBody* body = getRigidBody(name); - if (!body) // fall back to raycasting body if there is no collision body - body = getRigidBody(name, true); ContactTestResultCallback callback; callback.m_collisionFilterGroup = collisionGroup; callback.m_collisionFilterMask = collisionMask; @@ -769,17 +702,14 @@ namespace Physic } } - std::pair PhysicEngine::rayTest(const btVector3 &from, const btVector3 &to, bool raycastingObjectOnly, bool ignoreHeightMap, Ogre::Vector3* normal) + std::pair PhysicEngine::rayTest(const btVector3 &from, const btVector3 &to, bool ignoreHeightMap, Ogre::Vector3* normal) { std::string name = ""; float d = -1; btCollisionWorld::ClosestRayResultCallback resultCallback1(from, to); resultCallback1.m_collisionFilterGroup = 0xff; - if(raycastingObjectOnly) - resultCallback1.m_collisionFilterMask = CollisionType_Raycasting|CollisionType_Actor; - else - resultCallback1.m_collisionFilterMask = CollisionType_World; + resultCallback1.m_collisionFilterMask = CollisionType_World; if(!ignoreHeightMap) resultCallback1.m_collisionFilterMask = resultCallback1.m_collisionFilterMask | CollisionType_HeightMap; @@ -833,51 +763,6 @@ namespace Physic return std::make_pair(false, 1.0f); } - std::vector< std::pair > PhysicEngine::rayTest2(const btVector3& from, const btVector3& to, int filterGroup) - { - MyRayResultCallback resultCallback1; - resultCallback1.m_collisionFilterGroup = filterGroup; - resultCallback1.m_collisionFilterMask = CollisionType_Raycasting|CollisionType_Actor|CollisionType_HeightMap; - mDynamicsWorld->rayTest(from, to, resultCallback1); - std::vector< std::pair > results = resultCallback1.results; - - std::vector< std::pair > results2; - - for (std::vector< std::pair >::iterator it=results.begin(); - it != results.end(); ++it) - { - results2.push_back( std::make_pair( (*it).first, static_cast(*(*it).second).mName ) ); - } - - std::sort(results2.begin(), results2.end(), MyRayResultCallback::cmp); - - return results2; - } - - void PhysicEngine::getObjectAABB(const std::string &mesh, float scale, btVector3 &min, btVector3 &max) - { - std::string sid = (boost::format("%07.3f") % scale).str(); - std::string outputstring = mesh + sid; - - mShapeLoader->load(outputstring, "General"); - BulletShapeManager::getSingletonPtr()->load(outputstring, "General"); - BulletShapePtr shape = - BulletShapeManager::getSingleton().getByName(outputstring, "General"); - - btTransform trans; - trans.setIdentity(); - - if (shape->mRaycastingShape) - shape->mRaycastingShape->getAabb(trans, min, max); - else if (shape->mCollisionShape) - shape->mCollisionShape->getAabb(trans, min, max); - else - { - min = btVector3(0,0,0); - max = btVector3(0,0,0); - } - } - int PhysicEngine::toggleDebugRendering(Ogre::SceneManager *sceneMgr) { if(!sceneMgr) diff --git a/libs/openengine/bullet/physic.hpp b/libs/openengine/bullet/physic.hpp index 7784e8941..71f84cca7 100644 --- a/libs/openengine/bullet/physic.hpp +++ b/libs/openengine/bullet/physic.hpp @@ -46,9 +46,8 @@ namespace Physic CollisionType_World = 1<<0, // rayTest(const btVector3& from,const btVector3& to,bool raycastingObjectOnly = true, + std::pair rayTest(const btVector3& from,const btVector3& to, bool ignoreHeightMap = false, Ogre::Vector3* normal = NULL); - /** - * Return all objects hit by a ray. - */ - std::vector< std::pair > rayTest2(const btVector3 &from, const btVector3 &to, int filterGroup=0xff); - std::pair sphereCast (float radius, btVector3& from, btVector3& to); ///< @return (hit, relative distance) @@ -333,10 +325,6 @@ namespace Physic // the index refers to an element in mCollisionObjectMap std::map mAnimatedShapes; - RigidBodyContainer mRaycastingObjectMap; - - std::map mAnimatedRaycastingShapes; - typedef std::map PhysicActorContainer; PhysicActorContainer mActorMap; From cac288d5be337758005ca9b2583821e8f5f3665f Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 1 May 2015 21:49:36 +0200 Subject: [PATCH 1081/3725] Remove OgreInit --- apps/launcher/graphicspage.cpp | 121 +---------------- apps/launcher/graphicspage.hpp | 13 -- components/CMakeLists.txt | 4 - components/ogreinit/ogreinit.cpp | 210 ----------------------------- components/ogreinit/ogreinit.hpp | 78 ----------- components/ogreinit/ogreplugin.cpp | 45 ------- components/ogreinit/ogreplugin.hpp | 42 ------ files/settings-default.cfg | 7 - 8 files changed, 1 insertion(+), 519 deletions(-) delete mode 100644 components/ogreinit/ogreinit.cpp delete mode 100644 components/ogreinit/ogreinit.hpp delete mode 100644 components/ogreinit/ogreplugin.cpp delete mode 100644 components/ogreinit/ogreplugin.hpp diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index cdb51348c..cb3a3e7cb 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -12,9 +12,6 @@ #include -#include -#include - #include #include @@ -36,11 +33,7 @@ QString getAspect(int x, int y) } Launcher::GraphicsPage::GraphicsPage(Files::ConfigurationManager &cfg, GraphicsSettings &graphicsSetting, QWidget *parent) - : mOgre(NULL) - , mSelectedRenderSystem(NULL) - , mOpenGLRenderSystem(NULL) - , mDirect3DRenderSystem(NULL) - , mCfgMgr(cfg) + : mCfgMgr(cfg) , mGraphicsSettings(graphicsSetting) , QWidget(parent) { @@ -52,79 +45,12 @@ Launcher::GraphicsPage::GraphicsPage(Files::ConfigurationManager &cfg, GraphicsS customWidthSpinBox->setMaximum(res.width()); customHeightSpinBox->setMaximum(res.height()); - connect(rendererComboBox, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(rendererChanged(const QString&))); connect(fullScreenCheckBox, SIGNAL(stateChanged(int)), this, SLOT(slotFullScreenChanged(int))); connect(standardRadioButton, SIGNAL(toggled(bool)), this, SLOT(slotStandardToggled(bool))); connect(screenComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(screenChanged(int))); } -bool Launcher::GraphicsPage::setupOgre() -{ - try - { - mOgre = mOgreInit.init(mCfgMgr.getLogPath().string() + "/launcherOgre.log"); - } - catch(Ogre::Exception &ex) - { - QString ogreError = QString::fromUtf8(ex.getFullDescription().c_str()); - QMessageBox msgBox; - msgBox.setWindowTitle("Error creating Ogre::Root"); - msgBox.setIcon(QMessageBox::Critical); - msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(tr("
Failed to create the Ogre::Root object

\ - Press \"Show Details...\" for more information.
")); - msgBox.setDetailedText(ogreError); - msgBox.exec(); - - qCritical("Error creating Ogre::Root, the error reported was:\n %s", qPrintable(ogreError)); - return false; - } - - // Get the available renderers and put them in the combobox - const Ogre::RenderSystemList &renderers = mOgre->getAvailableRenderers(); - - for (Ogre::RenderSystemList::const_iterator r = renderers.begin(); r != renderers.end(); ++r) { - mSelectedRenderSystem = *r; - rendererComboBox->addItem((*r)->getName().c_str()); - } - - QString openGLName = QString("OpenGL Rendering Subsystem"); - QString direct3DName = QString("Direct3D9 Rendering Subsystem"); - - // Create separate rendersystems - mOpenGLRenderSystem = mOgre->getRenderSystemByName(openGLName.toStdString()); - mDirect3DRenderSystem = mOgre->getRenderSystemByName(direct3DName.toStdString()); - - if (!mOpenGLRenderSystem && !mDirect3DRenderSystem) { - QMessageBox msgBox; - msgBox.setWindowTitle(tr("Error creating renderer")); - msgBox.setIcon(QMessageBox::Critical); - msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(tr("
Could not select a valid render system

\ - Please make sure Ogre plugins were installed correctly.
")); - msgBox.exec(); - return false; - } - - // Now fill the GUI elements - int index = rendererComboBox->findText(mGraphicsSettings.value(QString("Video/render system"))); - if ( index != -1) { - rendererComboBox->setCurrentIndex(index); - } else { -#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32 - rendererComboBox->setCurrentIndex(rendererComboBox->findText(direct3DName)); -#else - rendererComboBox->setCurrentIndex(rendererComboBox->findText(openGLName)); -#endif - } - - antiAliasingComboBox->clear(); - antiAliasingComboBox->addItems(getAvailableOptions(QString("FSAA"), mSelectedRenderSystem)); - - return true; -} - bool Launcher::GraphicsPage::setupSDL() { int displays = SDL_GetNumVideoDisplays(); @@ -153,8 +79,6 @@ bool Launcher::GraphicsPage::loadSettings() { if (!setupSDL()) return false; - if (!mOgre && !setupOgre()) - return false; if (mGraphicsSettings.value(QString("Video/vsync")) == QLatin1String("true")) vSyncCheckBox->setCheckState(Qt::Checked); @@ -203,7 +127,6 @@ void Launcher::GraphicsPage::saveSettings() : mGraphicsSettings.setValue(QString("Video/window border"), QString("false")); mGraphicsSettings.setValue(QString("Video/antialiasing"), antiAliasingComboBox->currentText()); - mGraphicsSettings.setValue(QString("Video/render system"), rendererComboBox->currentText()); if (standardRadioButton->isChecked()) { @@ -221,39 +144,6 @@ void Launcher::GraphicsPage::saveSettings() mGraphicsSettings.setValue(QString("Video/screen"), QString::number(screenComboBox->currentIndex())); } -QStringList Launcher::GraphicsPage::getAvailableOptions(const QString &key, Ogre::RenderSystem *renderer) -{ - QStringList result; - - uint row = 0; - Ogre::ConfigOptionMap options = renderer->getConfigOptions(); - - for (Ogre::ConfigOptionMap::iterator i = options.begin (); i != options.end (); ++i, ++row) - { - Ogre::StringVector::iterator opt_it; - uint idx = 0; - - for (opt_it = i->second.possibleValues.begin(); - opt_it != i->second.possibleValues.end(); ++opt_it, ++idx) - { - if (strcmp (key.toStdString().c_str(), i->first.c_str()) == 0) { - result << ((key == "FSAA") ? QString("MSAA ") : QString("")) + QString::fromUtf8((*opt_it).c_str()).simplified(); - } - } - } - - // Sort ascending - qSort(result.begin(), result.end(), naturalSortLessThanCI); - - // Replace the zero option with Off - int index = result.indexOf("MSAA 0"); - - if (index != -1) - result.replace(index, tr("Off")); - - return result; -} - QStringList Launcher::GraphicsPage::getAvailableResolutions(int screen) { QStringList result; @@ -316,15 +206,6 @@ QRect Launcher::GraphicsPage::getMaximumResolution() return max; } -void Launcher::GraphicsPage::rendererChanged(const QString &renderer) -{ - mSelectedRenderSystem = mOgre->getRenderSystemByName(renderer.toStdString()); - - antiAliasingComboBox->clear(); - - antiAliasingComboBox->addItems(getAvailableOptions(QString("FSAA"), mSelectedRenderSystem)); -} - void Launcher::GraphicsPage::screenChanged(int screen) { if (screen >= 0) { diff --git a/apps/launcher/graphicspage.hpp b/apps/launcher/graphicspage.hpp index 213b6bccb..fb96c39d7 100644 --- a/apps/launcher/graphicspage.hpp +++ b/apps/launcher/graphicspage.hpp @@ -3,12 +3,8 @@ #include -#include - #include "ui_graphicspage.h" -namespace Ogre { class Root; class RenderSystem; } - namespace Files { struct ConfigurationManager; } namespace Launcher @@ -26,7 +22,6 @@ namespace Launcher bool loadSettings(); public slots: - void rendererChanged(const QString &renderer); void screenChanged(int screen); private slots: @@ -34,20 +29,12 @@ namespace Launcher void slotStandardToggled(bool checked); private: - OgreInit::OgreInit mOgreInit; - Ogre::Root *mOgre; - Ogre::RenderSystem *mSelectedRenderSystem; - Ogre::RenderSystem *mOpenGLRenderSystem; - Ogre::RenderSystem *mDirect3DRenderSystem; - Files::ConfigurationManager &mCfgMgr; GraphicsSettings &mGraphicsSettings; - QStringList getAvailableOptions(const QString &key, Ogre::RenderSystem *renderer); QStringList getAvailableResolutions(int screen); QRect getMaximumResolution(); - bool setupOgre(); bool setupSDL(); }; } diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 9ec648381..1f9bd337b 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -114,10 +114,6 @@ add_component_dir (loadinglistener loadinglistener ) -add_component_dir (ogreinit - ogreinit ogreplugin - ) - add_component_dir (myguiplatform myguirendermanager myguidatamanager myguiplatform myguitexture myguiloglistener ) diff --git a/components/ogreinit/ogreinit.cpp b/components/ogreinit/ogreinit.cpp deleted file mode 100644 index e8ca2e8bd..000000000 --- a/components/ogreinit/ogreinit.cpp +++ /dev/null @@ -1,210 +0,0 @@ -#include "ogreinit.hpp" - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE -#include -#endif - -#include -#include - -#include "ogreplugin.hpp" - - -namespace bfs = boost::filesystem; - -namespace -{ - /** \brief Custom Ogre::LogListener interface implementation being - able to portably handle UTF-8 encoded path. - - Effectively this is used in conjunction with default listener, - but since on every message messageLogged() set 'skip' flag to - true, there should be no troubles sharing same file. - */ - class LogListener : public Ogre::LogListener - { - bfs::ofstream file; - char buffer[16]; - - - public: - - LogListener(const std::string &path) - : file((bfs::path(path))) - { - memset(buffer, 0, sizeof(buffer)); - } - - void timestamp() - { - int local = time(0) % 86400; - int sec = local % 60; - int min = (local / 60) % 60; - int hrs = local / 3600; - sprintf(buffer, "%02d:%02d:%02d: ", hrs, min, sec); - } - - virtual void messageLogged(const std::string &msg, Ogre::LogMessageLevel lvl, bool mask, const std::string &logName, bool &skip) - { - timestamp(); - file << buffer << msg << std::endl; - skip = true; - } - }; -} - -namespace OgreInit -{ - - OgreInit::OgreInit() - : mRoot(NULL) - #ifdef ENABLE_PLUGIN_CgProgramManager - , mCgPlugin(NULL) - #endif - #ifdef ENABLE_PLUGIN_OctreeSceneManager - , mOctreePlugin(NULL) - #endif - #ifdef ENABLE_PLUGIN_ParticleFX - , mParticleFXPlugin(NULL) - #endif - #ifdef ENABLE_PLUGIN_GL - , mGLPlugin(NULL) - #endif - #ifdef ENABLE_PLUGIN_GLES2 - , mGLES2Plugin(NULL) - #endif - - #ifdef ENABLE_PLUGIN_Direct3D9 - , mD3D9Plugin(NULL) - #endif - {} - - Ogre::Root* OgreInit::init(const std::string &logPath) - { - if (mRoot) - throw std::runtime_error("OgreInit was already initialised"); - - #ifndef ANDROID - // Set up logging first - new Ogre::LogManager; - Ogre::Log *log = Ogre::LogManager::getSingleton().createLog(logPath); - - #if OGRE_PLATFORM == OGRE_PLATFORM_WIN32 - // Use custom listener only on Windows - log->addListener(new LogListener(logPath)); - #endif - - // Disable logging to cout/cerr - log->setDebugOutputEnabled(false); - #endif - mRoot = new Ogre::Root("", "", ""); - - #if defined(ENABLE_PLUGIN_GL) || (ENABLE_PLUGIN_GLES2) || defined(ENABLE_PLUGIN_Direct3D9) || defined(ENABLE_PLUGIN_CgProgramManager) || defined(ENABLE_PLUGIN_OctreeSceneManager) || defined(ENABLE_PLUGIN_ParticleFX) - loadStaticPlugins(); - #else - loadPlugins(); - #endif - - return mRoot; - } - - OgreInit::~OgreInit() - { - delete mRoot; - delete Ogre::LogManager::getSingletonPtr(); - - #ifdef ENABLE_PLUGIN_GL - delete mGLPlugin; - mGLPlugin = NULL; - #endif - #ifdef ENABLE_PLUGIN_GLES2 - delete mGLES2Plugin; - mGLES2Plugin = NULL; - #endif - #ifdef ENABLE_PLUGIN_Direct3D9 - delete mD3D9Plugin; - mD3D9Plugin = NULL; - #endif - #ifdef ENABLE_PLUGIN_CgProgramManager - delete mCgPlugin; - mCgPlugin = NULL; - #endif - #ifdef ENABLE_PLUGIN_OctreeSceneManager - delete mOctreePlugin; - mOctreePlugin = NULL; - #endif - #ifdef ENABLE_PLUGIN_ParticleFX - delete mParticleFXPlugin; - mParticleFXPlugin = NULL; - #endif - } - - void OgreInit::loadStaticPlugins() - { - #ifdef ENABLE_PLUGIN_GL - mGLPlugin = new Ogre::GLPlugin(); - mRoot->installPlugin(mGLPlugin); - #endif - #ifdef ENABLE_PLUGIN_GLES2 - mGLES2Plugin = new Ogre::GLES2Plugin(); - mRoot->installPlugin(mGLES2Plugin); - #endif - #ifdef ENABLE_PLUGIN_Direct3D9 - mD3D9Plugin = new Ogre::D3D9Plugin(); - mRoot->installPlugin(mD3D9Plugin); - #endif - #ifdef ENABLE_PLUGIN_CgProgramManager - mCgPlugin = new Ogre::CgPlugin(); - mRoot->installPlugin(mCgPlugin); - #endif - #ifdef ENABLE_PLUGIN_OctreeSceneManager - mOctreePlugin = new Ogre::OctreePlugin(); - mRoot->installPlugin(mOctreePlugin); - #endif - #ifdef ENABLE_PLUGIN_ParticleFX - mParticleFXPlugin = new Ogre::ParticleFXPlugin(); - mRoot->installPlugin(mParticleFXPlugin); - #endif - } - - void OgreInit::loadPlugins() - { - std::string pluginDir; - const char* pluginEnv = getenv("OPENMW_OGRE_PLUGIN_DIR"); - if (pluginEnv) - pluginDir = pluginEnv; - else - { - #if OGRE_PLATFORM == OGRE_PLATFORM_WIN32 - pluginDir = ".\\"; - #endif - #if OGRE_PLATFORM == OGRE_PLATFORM_APPLE - pluginDir = OGRE_PLUGIN_DIR; - // if path is not specified try to find plugins inside the app bundle - if (pluginDir.empty()) - pluginDir = Ogre::macFrameworksPath(); - #endif - #if OGRE_PLATFORM == OGRE_PLATFORM_LINUX - pluginDir = OGRE_PLUGIN_DIR; - #endif - } - Files::loadOgrePlugin(pluginDir, "RenderSystem_GL", *mRoot); - Files::loadOgrePlugin(pluginDir, "RenderSystem_GLES2", *mRoot); - Files::loadOgrePlugin(pluginDir, "RenderSystem_GL3Plus", *mRoot); - Files::loadOgrePlugin(pluginDir, "RenderSystem_Direct3D9", *mRoot); - Files::loadOgrePlugin(pluginDir, "Plugin_CgProgramManager", *mRoot); - if (!Files::loadOgrePlugin(pluginDir, "Plugin_ParticleFX", *mRoot)) - throw std::runtime_error("Required Plugin_ParticleFX for Ogre not found!"); - } -} diff --git a/components/ogreinit/ogreinit.hpp b/components/ogreinit/ogreinit.hpp deleted file mode 100644 index d1743950f..000000000 --- a/components/ogreinit/ogreinit.hpp +++ /dev/null @@ -1,78 +0,0 @@ -#ifndef OPENMW_COMPONENTS_OGREINIT_H -#define OPENMW_COMPONENTS_OGREINIT_H - -#include -#include - -// Static plugin headers -#ifdef ENABLE_PLUGIN_CgProgramManager -# include "OgreCgPlugin.h" -#endif -#ifdef ENABLE_PLUGIN_OctreeSceneManager -# include "OgreOctreePlugin.h" -#endif -#ifdef ENABLE_PLUGIN_ParticleFX -# include "OgreParticleFXPlugin.h" -#endif -#ifdef ENABLE_PLUGIN_GL -# include "OgreGLPlugin.h" -#endif -#ifdef ENABLE_PLUGIN_GLES2 -# include "OgreGLES2Plugin.h" -#endif - -#ifdef ENABLE_PLUGIN_Direct3D9 -# include "OgreD3D9Plugin.h" -#endif - -namespace Ogre -{ - class ParticleEmitterFactory; - class ParticleAffectorFactory; - class Root; -} - -namespace OgreInit -{ - /** - * @brief Starts Ogre::Root and loads required plugins and NIF particle factories - */ - class OgreInit - { - public: - OgreInit(); - - Ogre::Root* init(const std::string &logPath // Path to directory where to store log files - ); - - ~OgreInit(); - - private: - Ogre::Root* mRoot; - - void loadStaticPlugins(); - void loadPlugins(); - - #ifdef ENABLE_PLUGIN_CgProgramManager - Ogre::CgPlugin* mCgPlugin; - #endif - #ifdef ENABLE_PLUGIN_OctreeSceneManager - Ogre::OctreePlugin* mOctreePlugin; - #endif - #ifdef ENABLE_PLUGIN_ParticleFX - Ogre::ParticleFXPlugin* mParticleFXPlugin; - #endif - #ifdef ENABLE_PLUGIN_GL - Ogre::GLPlugin* mGLPlugin; - #endif - #ifdef ENABLE_PLUGIN_GLES2 - Ogre::GLES2Plugin* mGLES2Plugin; - #endif - #ifdef ENABLE_PLUGIN_Direct3D9 - Ogre::D3D9Plugin* mD3D9Plugin; - #endif - - }; -} - -#endif diff --git a/components/ogreinit/ogreplugin.cpp b/components/ogreinit/ogreplugin.cpp deleted file mode 100644 index 069b25e7b..000000000 --- a/components/ogreinit/ogreplugin.cpp +++ /dev/null @@ -1,45 +0,0 @@ -#include "ogreplugin.hpp" - -#include -#include - -namespace Files { - -bool loadOgrePlugin(const std::string &pluginDir, std::string pluginName, Ogre::Root &ogreRoot) { - std::string pluginExt; -#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32 - pluginExt = ".dll"; -#endif -#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE - pluginExt = ".framework"; -#endif -#if OGRE_PLATFORM == OGRE_PLATFORM_LINUX - pluginExt = ".so"; -#endif - - // Append plugin suffix if debugging. - std::string pluginPath; -#if defined(DEBUG) - pluginPath = pluginDir + "/" + pluginName + OGRE_PLUGIN_DEBUG_SUFFIX + pluginExt; - if (boost::filesystem::exists(pluginPath)) { - ogreRoot.loadPlugin(pluginPath); - return true; - } - else { -#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32 - return false; -#endif //OGRE_PLATFORM == OGRE_PLATFORM_WIN32 - } -#endif //defined(DEBUG) - - pluginPath = pluginDir + "/" + pluginName + pluginExt; - if (boost::filesystem::exists(pluginPath)) { - ogreRoot.loadPlugin(pluginPath); - return true; - } - else { - return false; - } -} - -} diff --git a/components/ogreinit/ogreplugin.hpp b/components/ogreinit/ogreplugin.hpp deleted file mode 100644 index 6fcf61376..000000000 --- a/components/ogreinit/ogreplugin.hpp +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef COMPONENTS_FILES_OGREPLUGIN_H -#define COMPONENTS_FILES_OGREPLUGIN_H - -#include - -#include -#include - -namespace Ogre { - class Root; -} - -#if (BOOST_VERSION <= 104500) -namespace boost { -namespace filesystem { -inline path absolute(const path& p, const path& base=current_path()) { - // call obsolete version of this function on older boost - return complete(p, base); -} -} -} -#endif /* (BOOST_VERSION <= 104300) */ - -/** - * \namespace Files - */ -namespace Files { - -/** - * \brief Loads Ogre plugin with given name. - * - * \param pluginDir absolute path to plugins - * \param pluginName plugin name, for example "RenderSystem_GL" - * \param ogreRoot Ogre::Root instance - * - * \return whether plugin was located or not - */ -bool loadOgrePlugin(const std::string &pluginDir, std::string pluginName, Ogre::Root &ogreRoot); - -} - -#endif /* COMPONENTS_FILES_OGREPLUGIN_H */ diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 32c3861c0..f1af8b654 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -12,13 +12,6 @@ screen = 0 # Minimize the window if it loses key focus? minimize on focus loss = true -# Render system -# blank means default -# Valid values: -# OpenGL Rendering Subsystem -# Direct3D9 Rendering Subsystem -render system = - # Valid values: # none # MSAA 2 From d873c2c6032c5091ce3ab8172573c87435b18b10 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 2 May 2015 13:20:42 +0200 Subject: [PATCH 1082/3725] focus main input widget when bringing up creator bar (Fixes #2514) --- apps/opencs/view/world/creator.hpp | 3 +++ apps/opencs/view/world/genericcreator.cpp | 5 +++++ apps/opencs/view/world/genericcreator.hpp | 3 +++ apps/opencs/view/world/infocreator.cpp | 5 +++++ apps/opencs/view/world/infocreator.hpp | 5 ++++- apps/opencs/view/world/referencecreator.cpp | 5 +++++ apps/opencs/view/world/referencecreator.hpp | 3 +++ apps/opencs/view/world/tablebottombox.cpp | 2 ++ 8 files changed, 30 insertions(+), 1 deletion(-) diff --git a/apps/opencs/view/world/creator.hpp b/apps/opencs/view/world/creator.hpp index 7c0422c88..506bdab2c 100644 --- a/apps/opencs/view/world/creator.hpp +++ b/apps/opencs/view/world/creator.hpp @@ -40,6 +40,9 @@ namespace CSVWorld /// Default implementation: Throw an exception if scope!=Scope_Content. virtual void setScope (unsigned int scope); + /// Focus main input widget + virtual void focus() = 0; + signals: void done(); diff --git a/apps/opencs/view/world/genericcreator.cpp b/apps/opencs/view/world/genericcreator.cpp index b4cf46040..4269679bf 100644 --- a/apps/opencs/view/world/genericcreator.cpp +++ b/apps/opencs/view/world/genericcreator.cpp @@ -225,6 +225,11 @@ void CSVWorld::GenericCreator::toggleWidgets(bool active) { } +void CSVWorld::GenericCreator::focus() +{ + mId->setFocus(); +} + void CSVWorld::GenericCreator::setScope (unsigned int scope) { mScopes = scope; diff --git a/apps/opencs/view/world/genericcreator.hpp b/apps/opencs/view/world/genericcreator.hpp index 678005082..1f854c69e 100644 --- a/apps/opencs/view/world/genericcreator.hpp +++ b/apps/opencs/view/world/genericcreator.hpp @@ -101,6 +101,9 @@ namespace CSVWorld virtual void setScope (unsigned int scope); + /// Focus main input widget + virtual void focus(); + private slots: void textChanged (const QString& text); diff --git a/apps/opencs/view/world/infocreator.cpp b/apps/opencs/view/world/infocreator.cpp index 14034ea7f..f88b9f0b9 100644 --- a/apps/opencs/view/world/infocreator.cpp +++ b/apps/opencs/view/world/infocreator.cpp @@ -91,6 +91,11 @@ std::string CSVWorld::InfoCreator::getErrors() const return errors; } +void CSVWorld::InfoCreator::focus() +{ + mTopic->setFocus(); +} + void CSVWorld::InfoCreator::topicChanged() { update(); diff --git a/apps/opencs/view/world/infocreator.hpp b/apps/opencs/view/world/infocreator.hpp index 2296a8297..edc12975c 100644 --- a/apps/opencs/view/world/infocreator.hpp +++ b/apps/opencs/view/world/infocreator.hpp @@ -35,7 +35,10 @@ namespace CSVWorld virtual std::string getErrors() const; ///< Return formatted error descriptions for the current state of the creator. if an empty /// string is returned, there is no error. - + + /// Focus main input widget + virtual void focus(); + private slots: void topicChanged(); diff --git a/apps/opencs/view/world/referencecreator.cpp b/apps/opencs/view/world/referencecreator.cpp index 1e3cc00d7..e9bb04ba7 100644 --- a/apps/opencs/view/world/referencecreator.cpp +++ b/apps/opencs/view/world/referencecreator.cpp @@ -118,6 +118,11 @@ std::string CSVWorld::ReferenceCreator::getErrors() const return errors; } +void CSVWorld::ReferenceCreator::focus() +{ + mCell->setFocus(); +} + void CSVWorld::ReferenceCreator::cellChanged() { update(); diff --git a/apps/opencs/view/world/referencecreator.hpp b/apps/opencs/view/world/referencecreator.hpp index 002a62d87..877307c29 100644 --- a/apps/opencs/view/world/referencecreator.hpp +++ b/apps/opencs/view/world/referencecreator.hpp @@ -39,6 +39,9 @@ namespace CSVWorld ///< Return formatted error descriptions for the current state of the creator. if an empty /// string is returned, there is no error. + /// Focus main input widget + virtual void focus(); + private slots: void cellChanged(); diff --git a/apps/opencs/view/world/tablebottombox.cpp b/apps/opencs/view/world/tablebottombox.cpp index 239c7410f..e9d644f61 100644 --- a/apps/opencs/view/world/tablebottombox.cpp +++ b/apps/opencs/view/world/tablebottombox.cpp @@ -157,6 +157,7 @@ void CSVWorld::TableBottomBox::createRequest() mLayout->setCurrentWidget (mCreator); setVisible (true); mCreating = true; + mCreator->focus(); } void CSVWorld::TableBottomBox::cloneRequest(const std::string& id, @@ -168,4 +169,5 @@ void CSVWorld::TableBottomBox::cloneRequest(const std::string& id, mCreator->toggleWidgets(false); setVisible (true); mCreating = true; + mCreator->focus(); } From bddd31e385d1897597fdd21d093fd4083b22c742 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 2 May 2015 16:39:03 +0200 Subject: [PATCH 1083/3725] Dead code removal --- apps/openmw/mwworld/physicssystem.cpp | 8 +-- libs/openengine/bullet/physic.cpp | 75 --------------------------- libs/openengine/bullet/physic.hpp | 9 ---- 3 files changed, 4 insertions(+), 88 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 14cab6c82..271b23d09 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -503,14 +503,14 @@ namespace MWWorld { // Create physics. shapeLoader is deleted by the physic engine //NifBullet::ManualBulletShapeLoader* shapeLoader = new NifBullet::ManualBulletShapeLoader(); - //mEngine = new OEngine::Physic::PhysicEngine(0);//shapeLoader); + mEngine = new OEngine::Physic::PhysicEngine(0);//shapeLoader); } PhysicsSystem::~PhysicsSystem() { - //if (mWaterCollisionObject.get()) - // mEngine->mDynamicsWorld->removeCollisionObject(mWaterCollisionObject.get()); - //delete mEngine; + if (mWaterCollisionObject.get()) + mEngine->mDynamicsWorld->removeCollisionObject(mWaterCollisionObject.get()); + delete mEngine; //delete OEngine::Physic::BulletShapeManager::getSingletonPtr(); } diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index 0125fd01e..b1bd978c6 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -262,10 +262,6 @@ namespace Physic mDynamicsWorld->setGravity(btVector3(0,0,-10)); - if(BulletShapeManager::getSingletonPtr() == NULL) - { - new BulletShapeManager(); - } mShapeLoader = shapeLoader; isDebugCreated = false; @@ -763,76 +759,5 @@ namespace Physic return std::make_pair(false, 1.0f); } - int PhysicEngine::toggleDebugRendering(Ogre::SceneManager *sceneMgr) - { - if(!sceneMgr) - return 0; - - std::map::iterator iter = - mDebugDrawers.find(sceneMgr); - if(iter != mDebugDrawers.end()) // found scene manager - { - if((*iter).second) - { - // set a new drawer each time (maybe with a different scene manager) - mDynamicsWorld->setDebugDrawer(mDebugDrawers[sceneMgr]); - if(!mDebugDrawers[sceneMgr]->getDebugMode()) - mDebugDrawers[sceneMgr]->setDebugMode(1 /*mDebugDrawFlags*/); - else - mDebugDrawers[sceneMgr]->setDebugMode(0); - mDynamicsWorld->debugDrawWorld(); - - return mDebugDrawers[sceneMgr]->getDebugMode(); - } - } - return 0; - } - - void PhysicEngine::stepDebug(Ogre::SceneManager *sceneMgr) - { - if(!sceneMgr) - return; - - std::map::iterator iter = - mDebugDrawers.find(sceneMgr); - if(iter != mDebugDrawers.end()) // found scene manager - { - if((*iter).second) - (*iter).second->step(); - else - return; - } - } - - void PhysicEngine::createDebugDraw(Ogre::SceneManager *sceneMgr) - { - if(mDebugDrawers.find(sceneMgr) == mDebugDrawers.end()) - { - mDebugSceneNodes[sceneMgr] = sceneMgr->getRootSceneNode()->createChildSceneNode(); - mDebugDrawers[sceneMgr] = new BtOgre::DebugDrawer(mDebugSceneNodes[sceneMgr], mDynamicsWorld); - mDebugDrawers[sceneMgr]->setDebugMode(0); - } - } - - void PhysicEngine::removeDebugDraw(Ogre::SceneManager *sceneMgr) - { - std::map::iterator iter = - mDebugDrawers.find(sceneMgr); - if(iter != mDebugDrawers.end()) - { - delete (*iter).second; - mDebugDrawers.erase(iter); - } - - std::map::iterator it = - mDebugSceneNodes.find(sceneMgr); - if(it != mDebugSceneNodes.end()) - { - std::string sceneNodeName = (*it).second->getName(); - if(sceneMgr->hasSceneNode(sceneNodeName)) - sceneMgr->destroySceneNode(sceneNodeName); - } - } - } } diff --git a/libs/openengine/bullet/physic.hpp b/libs/openengine/bullet/physic.hpp index 71f84cca7..e92e9c3c1 100644 --- a/libs/openengine/bullet/physic.hpp +++ b/libs/openengine/bullet/physic.hpp @@ -335,15 +335,6 @@ namespace Physic bool isDebugCreated; bool mDebugActive; - // for OpenCS with multiple engines per document - std::map mDebugDrawers; - std::map mDebugSceneNodes; - - int toggleDebugRendering(Ogre::SceneManager *sceneMgr); - void stepDebug(Ogre::SceneManager *sceneMgr); - void createDebugDraw(Ogre::SceneManager *sceneMgr); - void removeDebugDraw(Ogre::SceneManager *sceneMgr); - private: PhysicEngine(const PhysicEngine&); PhysicEngine& operator=(const PhysicEngine&); From 8817f44d6390bacec6118ca9fc4ca7eae7da02f2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 2 May 2015 17:48:24 +0200 Subject: [PATCH 1084/3725] Remove advanced FPS counter (obsoleted by the OSG stats viewer) --- apps/openmw/engine.cpp | 5 +--- apps/openmw/mwbase/windowmanager.hpp | 2 +- apps/openmw/mwbase/world.hpp | 2 -- apps/openmw/mwgui/hud.cpp | 31 +++---------------- apps/openmw/mwgui/hud.hpp | 8 ++--- apps/openmw/mwgui/settingswindow.cpp | 8 ++--- apps/openmw/mwgui/windowmanagerimp.cpp | 10 ++----- apps/openmw/mwgui/windowmanagerimp.hpp | 4 +-- apps/openmw/mwworld/worldimp.cpp | 5 ---- apps/openmw/mwworld/worldimp.hpp | 2 -- files/mygui/openmw_hud.layout | 41 -------------------------- files/settings-default.cfg | 3 +- 12 files changed, 15 insertions(+), 106 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 0abb43cfd..0dc19144c 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -150,10 +150,7 @@ void OMW::Engine::frame(float frametime) MWBase::StateManager::State_NoGame) { #if 0 - Ogre::RenderWindow* window = mOgre->getWindow(); - unsigned int tri, batch; - MWBase::Environment::get().getWorld()->getTriangleBatchCount(tri, batch); - MWBase::Environment::get().getWindowManager()->wmUpdateFps(window->getLastFPS(), tri, batch); + MWBase::Environment::get().getWindowManager()->wmUpdateFps(fps); #endif MWBase::Environment::get().getWindowManager()->update(); } diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 59407fbeb..d1f1ad3a3 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -152,7 +152,7 @@ namespace MWBase virtual void setConsoleSelectedObject(const MWWorld::Ptr& object) = 0; - virtual void wmUpdateFps(float fps, unsigned int triangleCount, unsigned int batchCount) = 0; + virtual void wmUpdateFps(float fps) = 0; /// Set value for the given ID. virtual void setValue (const std::string& id, const MWMechanics::AttributeValue& value) = 0; diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 00d4d8536..1f27756d1 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -130,8 +130,6 @@ namespace MWBase virtual void adjustSky() = 0; - virtual void getTriangleBatchCount(unsigned int &triangles, unsigned int &batches) = 0; - virtual const MWWorld::Fallback *getFallback () const = 0; virtual MWWorld::Player& getPlayer() = 0; diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 9c8fa48a1..5f5f2eca3 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -70,7 +70,7 @@ namespace MWGui }; - HUD::HUD(CustomMarkerCollection &customMarkers, int fpsLevel, DragAndDrop* dragAndDrop) + HUD::HUD(CustomMarkerCollection &customMarkers, bool showFps, DragAndDrop* dragAndDrop) : Layout("openmw_hud.layout") , LocalMapBase(customMarkers) , mHealth(NULL) @@ -89,8 +89,6 @@ namespace MWGui , mCrosshair(NULL) , mFpsBox(NULL) , mFpsCounter(NULL) - , mTriangleCounter(NULL) - , mBatchCounter(NULL) , mHealthManaStaminaBaseLeft(0) , mWeapBoxBaseLeft(0) , mSpellBoxBaseLeft(0) @@ -166,10 +164,7 @@ namespace MWGui getWidget(mCrosshair, "Crosshair"); - setFpsLevel(fpsLevel); - - getWidget(mTriangleCounter, "TriangleCounter"); - getWidget(mBatchCounter, "BatchCounter"); + setFpsVisible(showFps); LocalMapBase::init(mMinimap, mCompass, Settings::Manager::getInt("local map hud widget size", "Map")); @@ -189,23 +184,15 @@ namespace MWGui delete mSpellIcons; } - void HUD::setFpsLevel(int level) + void HUD::setFpsVisible(const bool visible) { mFpsCounter = 0; MyGUI::Widget* fps; - getWidget(fps, "FPSBoxAdv"); - fps->setVisible(false); getWidget(fps, "FPSBox"); fps->setVisible(false); - if (level == 2) - { - getWidget(mFpsBox, "FPSBoxAdv"); - mFpsBox->setVisible(true); - getWidget(mFpsCounter, "FPSCounterAdv"); - } - else if (level == 1) + if (visible) { getWidget(mFpsBox, "FPSBox"); mFpsBox->setVisible(true); @@ -219,16 +206,6 @@ namespace MWGui mFpsCounter->setCaption(MyGUI::utility::toString((int)fps)); } - void HUD::setTriangleCount(unsigned int count) - { - mTriangleCounter->setCaption(MyGUI::utility::toString(count)); - } - - void HUD::setBatchCount(unsigned int count) - { - mBatchCounter->setCaption(MyGUI::utility::toString(count)); - } - void HUD::setValue(const std::string& id, const MWMechanics::DynamicStat& value) { int current = std::max(0, static_cast(value.getCurrent())); diff --git a/apps/openmw/mwgui/hud.hpp b/apps/openmw/mwgui/hud.hpp index e717e094e..9eed9811a 100644 --- a/apps/openmw/mwgui/hud.hpp +++ b/apps/openmw/mwgui/hud.hpp @@ -19,12 +19,10 @@ namespace MWGui class HUD : public Layout, public LocalMapBase { public: - HUD(CustomMarkerCollection& customMarkers, int fpsLevel, DragAndDrop* dragAndDrop); + HUD(CustomMarkerCollection& customMarkers, bool fpsVisible, DragAndDrop* dragAndDrop); virtual ~HUD(); void setValue (const std::string& id, const MWMechanics::DynamicStat& value); void setFPS(float fps); - void setTriangleCount(unsigned int count); - void setBatchCount(unsigned int count); /// Set time left for the player to start drowning /// @param time time left to start drowning @@ -40,7 +38,7 @@ namespace MWGui void setEffectVisible(bool visible); void setMinimapVisible(bool visible); - void setFpsLevel(const int level); + void setFpsVisible(const bool visible); void setSelectedSpell(const std::string& spellId, int successChancePercent); void setSelectedEnchantItem(const MWWorld::Ptr& item, int chargePercent); @@ -80,8 +78,6 @@ namespace MWGui MyGUI::Widget* mFpsBox; MyGUI::TextBox* mFpsCounter; - MyGUI::TextBox* mTriangleCounter; - MyGUI::TextBox* mBatchCounter; // bottom left elements int mHealthManaStaminaBaseLeft, mWeapBoxBaseLeft, mSpellBoxBaseLeft, mSneakBoxBaseLeft; diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index d895a28ea..23cf2c62e 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -32,10 +32,8 @@ namespace { if (level == 0) return "#{sOff}"; - else if (level == 1) - return "Basic"; - else - return "Detailed"; + else //if (level == 1) + return "#{sOn}"; } std::string textureFilteringToStr(const std::string& val) @@ -413,7 +411,7 @@ namespace MWGui void SettingsWindow::onFpsToggled(MyGUI::Widget* _sender) { - int newLevel = (Settings::Manager::getInt("fps", "HUD") + 1) % 3; + int newLevel = (Settings::Manager::getInt("fps", "HUD") + 1) % 2; Settings::Manager::setInt("fps", "HUD", newLevel); mFPSButton->setCaptionWithReplacing(fpsLevelToStr(newLevel)); apply(); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 096838f81..e4e0c3167 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -174,8 +174,6 @@ namespace MWGui , mAllowed(GW_ALL) , mRestAllowed(true) , mFPS(0.0f) - , mTriangleCount(0) - , mBatchCount(0) , mCurrentModals() , mFallbackMap(fallbackMap) { @@ -440,8 +438,6 @@ namespace MWGui cleanupGarbage(); mHud->setFPS(mFPS); - mHud->setTriangleCount(mTriangleCount); - mHud->setBatchCount(mBatchCount); mHud->update(); } @@ -1078,7 +1074,7 @@ namespace MWGui void WindowManager::processChangedSettings(const Settings::CategorySettingVector& changed) { - mHud->setFpsLevel(Settings::Manager::getInt("fps", "HUD")); + mHud->setFpsVisible(static_cast(Settings::Manager::getInt("fps", "HUD"))); mToolTips->setDelay(Settings::Manager::getFloat("tooltip delay", "GUI")); for (Settings::CategorySettingVector::const_iterator it = changed.begin(); @@ -1278,11 +1274,9 @@ namespace MWGui mConsole->executeFile (path); } - void WindowManager::wmUpdateFps(float fps, unsigned int triangleCount, unsigned int batchCount) + void WindowManager::wmUpdateFps(float fps) { mFPS = fps; - mTriangleCount = triangleCount; - mBatchCount = batchCount; } MWGui::DialogueWindow* WindowManager::getDialogueWindow() { return mDialogueWindow; } diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 765a18156..7fccff2d8 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -172,7 +172,7 @@ namespace MWGui virtual void setConsoleSelectedObject(const MWWorld::Ptr& object); - virtual void wmUpdateFps(float fps, unsigned int triangleCount, unsigned int batchCount); + virtual void wmUpdateFps(float fps); ///< Set value for the given ID. virtual void setValue (const std::string& id, const MWMechanics::AttributeValue& value); @@ -474,8 +474,6 @@ namespace MWGui void updateVisible(); // Update visibility of all windows based on mode, shown and allowed settings float mFPS; - unsigned int mTriangleCount; - unsigned int mBatchCount; std::map mFallbackMap; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 416ef7416..842a24ded 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1979,11 +1979,6 @@ namespace MWWorld //mRendering->processChangedSettings(settings); } - void World::getTriangleBatchCount(unsigned int &triangles, unsigned int &batches) - { - //mRendering->getTriangleBatchCount(triangles, batches); - } - bool World::isFlying(const MWWorld::Ptr &ptr) const { const MWMechanics::CreatureStats &stats = ptr.getClass().getCreatureStats(ptr); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 447bb1300..9598d4357 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -205,8 +205,6 @@ namespace MWWorld virtual void adjustSky(); - virtual void getTriangleBatchCount(unsigned int &triangles, unsigned int &batches); - virtual const Fallback *getFallback() const; virtual Player& getPlayer(); diff --git a/files/mygui/openmw_hud.layout b/files/mygui/openmw_hud.layout index 0cbe0dd97..dd114097e 100644 --- a/files/mygui/openmw_hud.layout +++ b/files/mygui/openmw_hud.layout @@ -132,46 +132,5 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
diff --git a/files/settings-default.cfg b/files/settings-default.cfg index f1af8b654..862f9495a 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -93,8 +93,7 @@ debug = false [HUD] # FPS counter # 0: not visible -# 1: basic FPS display -# 2: advanced FPS display (batches, triangles) +# 1: FPS display fps = 0 crosshair = true From 1b78acc2c01e168dc3d556a3501dc26791ebeb50 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 2 May 2015 18:06:17 +0200 Subject: [PATCH 1085/3725] Remove manual allocation for images --- components/fontloader/fontloader.cpp | 7 ++++--- components/resource/texturemanager.cpp | 13 +++++++------ 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/components/fontloader/fontloader.cpp b/components/fontloader/fontloader.cpp index e579de18f..080c64c4c 100644 --- a/components/fontloader/fontloader.cpp +++ b/components/fontloader/fontloader.cpp @@ -277,9 +277,10 @@ namespace Gui osg::ref_ptr image = new osg::Image; - unsigned char* bytes = (unsigned char*)calloc(width*height*4, sizeof(unsigned char)); - memcpy(bytes, &textureData[0], textureData.size()); - image->setImage(width, height, 1, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, bytes, osg::Image::USE_MALLOC_FREE); + image->allocateImage(width, height, 1, GL_RGBA, GL_UNSIGNED_BYTE); + assert (image->isDataContiguous()); + + memcpy(image->data(), &textureData[0], textureData.size()); osg::ref_ptr texture = new osg::Texture2D; texture->setImage(image); diff --git a/components/resource/texturemanager.cpp b/components/resource/texturemanager.cpp index d0d32a40e..b86b70cde 100644 --- a/components/resource/texturemanager.cpp +++ b/components/resource/texturemanager.cpp @@ -13,15 +13,16 @@ namespace { osg::ref_ptr warningImage = new osg::Image; - int width=8, height=8; - unsigned char* bytes = (unsigned char*)calloc(width*height*3, sizeof(unsigned char)); + int width = 8, height = 8; + warningImage->allocateImage(width, height, 1, GL_RGB, GL_UNSIGNED_BYTE); + assert (warningImage->isDataContiguous()); + unsigned char* data = warningImage->data(); for (int i=0;isetImage(width, height, 1, GL_RGB, GL_RGB, GL_UNSIGNED_BYTE, bytes, osg::Image::USE_MALLOC_FREE); osg::ref_ptr warningTexture = new osg::Texture2D; warningTexture->setImage(warningImage); From dc9b27acfe175dfec36a1e0bd6db59e82d3b03a9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 2 May 2015 18:06:54 +0200 Subject: [PATCH 1086/3725] Create manual GUI textures --- apps/openmw/mwgui/windowmanagerimp.cpp | 56 +++++++++++++++++++ apps/openmw/mwgui/windowmanagerimp.hpp | 3 + .../myguiplatform/myguirendermanager.cpp | 3 + 3 files changed, 62 insertions(+) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index e4e0c3167..3755de07e 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -183,6 +183,8 @@ namespace MWGui MyGUI::Gui* gui = new MyGUI::Gui; gui->initialise(""); + createTextures(); + MyGUI::LanguageManager::getInstance().eventRequestTag = MyGUI::newDelegate(this, &WindowManager::onRetrieveTag); // Load fonts @@ -1084,6 +1086,8 @@ namespace MWGui mCrosshairEnabled = Settings::Manager::getBool ("crosshair", "HUD"); else if (it->first == "GUI" && it->second == "subtitles") mSubtitlesEnabled = Settings::Manager::getBool ("subtitles", "GUI"); + else if (it->first == "GUI" && it->second == "menu transparency") + setMenuTransparency(Settings::Manager::getFloat("menu transparency", "GUI")); } } @@ -1929,4 +1933,56 @@ namespace MWGui return Misc::ResourceHelpers::correctTexturePath(path, mResourceSystem->getVFS()); } + void WindowManager::createTextures() + { + { + MyGUI::ITexture* tex = MyGUI::RenderManager::getInstance().createTexture("white.png"); + tex->createManual(8, 8, MyGUI::TextureUsage::Write, MyGUI::PixelFormat::R8G8B8); + unsigned char* data = reinterpret_cast(tex->lock(MyGUI::TextureUsage::Write)); + for (int x=0; x<8; ++x) + for (int y=0; y<8; ++y) + { + *(data++) = 255; + *(data++) = 255; + *(data++) = 255; + } + tex->unlock(); + } + + { + MyGUI::ITexture* tex = MyGUI::RenderManager::getInstance().createTexture("black.png"); + tex->createManual(8, 8, MyGUI::TextureUsage::Write, MyGUI::PixelFormat::R8G8B8); + unsigned char* data = reinterpret_cast(tex->lock(MyGUI::TextureUsage::Write)); + for (int x=0; x<8; ++x) + for (int y=0; y<8; ++y) + { + *(data++) = 0; + *(data++) = 0; + *(data++) = 0; + } + tex->unlock(); + } + + { + MyGUI::ITexture* tex = MyGUI::RenderManager::getInstance().createTexture("transparent.png"); + tex->createManual(8, 8, MyGUI::TextureUsage::Write, MyGUI::PixelFormat::R8G8B8A8); + setMenuTransparency(Settings::Manager::getFloat("menu transparency", "GUI")); + } + } + + void WindowManager::setMenuTransparency(float value) + { + MyGUI::ITexture* tex = MyGUI::RenderManager::getInstance().getTexture("transparent.png"); + unsigned char* data = reinterpret_cast(tex->lock(MyGUI::TextureUsage::Write)); + for (int x=0; x<8; ++x) + for (int y=0; y<8; ++y) + { + *(data++) = 255; + *(data++) = 255; + *(data++) = 255; + *(data++) = static_cast(value*255); + } + tex->unlock(); + } + } diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 7fccff2d8..325881889 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -499,6 +499,9 @@ namespace MWGui void onClipboardChanged(const std::string& _type, const std::string& _data); void onClipboardRequested(const std::string& _type, std::string& _data); + + void createTextures(); + void setMenuTransparency(float value); }; } diff --git a/components/myguiplatform/myguirendermanager.cpp b/components/myguiplatform/myguirendermanager.cpp index 3ebbd957a..87464f22d 100644 --- a/components/myguiplatform/myguirendermanager.cpp +++ b/components/myguiplatform/myguirendermanager.cpp @@ -420,6 +420,9 @@ void RenderManager::destroyTexture(MyGUI::ITexture *texture) MyGUI::ITexture* RenderManager::getTexture(const std::string &name) { + if (name.empty()) + return NULL; + MapTexture::const_iterator item = mTextures.find(name); if(item == mTextures.end()) { From d772da37202941e139e22834e7f827db5481b457 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 2 May 2015 18:14:53 +0200 Subject: [PATCH 1087/3725] Main menu background videos --- apps/openmw/mwgui/mainmenu.cpp | 7 +++++-- apps/openmw/mwgui/mainmenu.hpp | 8 +++++++- apps/openmw/mwgui/windowmanagerimp.cpp | 2 +- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index d563eacc8..48f9ee42c 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -10,6 +10,7 @@ #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" @@ -29,8 +30,9 @@ namespace MWGui { - MainMenu::MainMenu(int w, int h) + MainMenu::MainMenu(int w, int h, const VFS::Manager* vfs) : Layout("openmw_mainmenu.layout") + , mVFS(vfs) , mButtonBox(0), mWidth (w), mHeight (h) , mSaveGameDialog(NULL) , mBackground(NULL) @@ -53,7 +55,7 @@ namespace MWGui std::string output = sstream.str(); mVersionText->setCaption(output); - mHasAnimatedMenu = 0;//(Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup("video\\menu_background.bik")); + mHasAnimatedMenu = mVFS->exists("video/menu_background.bik"); updateMenu(); } @@ -174,6 +176,7 @@ namespace MWGui mVideo = mVideoBackground->createWidget("ImageBox", 0,0,1,1, MyGUI::Align::Stretch, "Menu"); + mVideo->setVFS(mVFS); mVideo->playVideo("video\\menu_background.bik"); } diff --git a/apps/openmw/mwgui/mainmenu.hpp b/apps/openmw/mwgui/mainmenu.hpp index 9089ed1d5..d01f67fbd 100644 --- a/apps/openmw/mwgui/mainmenu.hpp +++ b/apps/openmw/mwgui/mainmenu.hpp @@ -8,6 +8,11 @@ namespace Gui class ImageButton; } +namespace VFS +{ + class Manager; +} + namespace MWGui { @@ -24,7 +29,7 @@ namespace MWGui public: - MainMenu(int w, int h); + MainMenu(int w, int h, const VFS::Manager* vfs); ~MainMenu(); void onResChange(int w, int h); @@ -34,6 +39,7 @@ namespace MWGui void update(float dt); private: + const VFS::Manager* mVFS; MyGUI::Widget* mButtonBox; MyGUI::TextBox* mVersionText; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 3755de07e..9d9ba329b 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -259,7 +259,7 @@ namespace MWGui mDragAndDrop = new DragAndDrop(); mRecharge = new Recharge(); - mMenu = new MainMenu(w,h); + mMenu = new MainMenu(w, h, mResourceSystem->getVFS()); mMap = new MapWindow(mCustomMarkers, mDragAndDrop, ""); trackWindow(mMap, "map"); mStatsWindow = new StatsWindow(mDragAndDrop); From 1a5407af989efcf3f79f53f95fee2e7470929015 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 2 May 2015 19:36:36 +0200 Subject: [PATCH 1088/3725] Reduce texture memory usage in OpenMW --- apps/openmw/engine.cpp | 2 ++ components/resource/texturemanager.cpp | 9 +++++++-- components/resource/texturemanager.hpp | 5 +++++ 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 0dc19144c..15fee0cb1 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -17,6 +17,7 @@ #include #include +#include #include @@ -307,6 +308,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) VFS::registerArchives(mVFS.get(), mFileCollections, mArchives, true); mResourceSystem.reset(new Resource::ResourceSystem(mVFS.get())); + mResourceSystem->getTextureManager()->setUnRefImageDataAfterApply(true); // Create input and UI first to set up a bootstrapping environment for // showing a loading screen and keeping the window responsive while doing so diff --git a/components/resource/texturemanager.cpp b/components/resource/texturemanager.cpp index b86b70cde..939f81d9b 100644 --- a/components/resource/texturemanager.cpp +++ b/components/resource/texturemanager.cpp @@ -37,10 +37,16 @@ namespace Resource TextureManager::TextureManager(const VFS::Manager *vfs) : mVFS(vfs) , mWarningTexture(createWarningTexture()) + , mUnRefImageDataAfterApply(false) { } + void TextureManager::setUnRefImageDataAfterApply(bool unref) + { + mUnRefImageDataAfterApply = unref; + } + /* osg::ref_ptr TextureManager::getImage(const std::string &filename) { @@ -91,8 +97,7 @@ namespace Resource texture->setWrap(osg::Texture::WRAP_S, wrapS); texture->setWrap(osg::Texture::WRAP_T, wrapT); - // Can be enabled for single-context, i.e. in openmw - //texture->setUnRefImageDataAfterApply(true); + texture->setUnRefImageDataAfterApply(mUnRefImageDataAfterApply); mTextures.insert(std::make_pair(key, texture)); return texture; diff --git a/components/resource/texturemanager.hpp b/components/resource/texturemanager.hpp index f4ade515d..d44d47d24 100644 --- a/components/resource/texturemanager.hpp +++ b/components/resource/texturemanager.hpp @@ -24,6 +24,10 @@ namespace Resource // TODO: texture filtering settings + /// Keep a copy of the texture data around in system memory? This is needed when using multiple graphics contexts, + /// otherwise should be disabled to reduce memory usage. + void setUnRefImageDataAfterApply(bool unref); + /// Create or retrieve a Texture2D using the specified image filename, and wrap parameters. osg::ref_ptr getTexture2D(const std::string& filename, osg::Texture::WrapMode wrapS, osg::Texture::WrapMode wrapT); @@ -43,6 +47,7 @@ namespace Resource osg::ref_ptr mWarningTexture; + bool mUnRefImageDataAfterApply; }; } From 9cf9c2876e9bcd9ea40d3090deb896df6988e9b4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 2 May 2015 22:45:27 +0200 Subject: [PATCH 1089/3725] Pathgrid rendering --- apps/openmw/CMakeLists.txt | 4 +- apps/openmw/mwbase/world.hpp | 12 +- apps/openmw/mwmechanics/pathfinding.hpp | 5 + apps/openmw/mwrender/creatureanimation.cpp | 3 - apps/openmw/mwrender/debugging.cpp | 249 +++++++++------------ apps/openmw/mwrender/debugging.hpp | 50 ++--- apps/openmw/mwrender/npcanimation.cpp | 1 - apps/openmw/mwrender/objects.cpp | 1 - apps/openmw/mwrender/renderconst.hpp | 76 ------- apps/openmw/mwrender/renderingmanager.cpp | 30 +++ apps/openmw/mwrender/renderingmanager.hpp | 6 + apps/openmw/mwrender/rendermode.hpp | 17 ++ apps/openmw/mwrender/sky.cpp | 1 - apps/openmw/mwrender/vismask.hpp | 1 + apps/openmw/mwscript/miscextensions.cpp | 8 +- apps/openmw/mwworld/scene.cpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 4 +- apps/openmw/mwworld/worldimp.hpp | 2 +- 18 files changed, 199 insertions(+), 273 deletions(-) delete mode 100644 apps/openmw/mwrender/renderconst.hpp create mode 100644 apps/openmw/mwrender/rendermode.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index f049f0387..ed5530126 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -21,8 +21,8 @@ source_group(game FILES ${GAME} ${GAME_HEADER}) add_openmw_dir (mwrender actors objects renderingmanager animation sky npcanimation vismask - creatureanimation effectmanager util renderinginterface -# debugging camera activatoranimation + creatureanimation effectmanager util renderinginterface debugging rendermode +# camera activatoranimation # localmap occlusionquery water shadows # characterpreview globalmap ripplesimulation refraction # terrainstorage renderconst weaponanimation diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 1f27756d1..4ccbfc784 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -9,6 +9,8 @@ #include "../mwworld/ptr.hpp" +#include "../mwrender/rendermode.hpp" + namespace Ogre { class Vector2; @@ -83,14 +85,6 @@ namespace MWBase public: - enum RenderMode - { - Render_CollisionDebug, - Render_Wireframe, - Render_Pathgrid, - Render_BoundingBoxes - }; - struct DoorMarker { std::string name; @@ -320,7 +314,7 @@ namespace MWBase /// collisions and gravity. /// \return Resulting mode - virtual bool toggleRenderMode (RenderMode mode) = 0; + virtual bool toggleRenderMode (MWRender::RenderMode mode) = 0; ///< Toggle a render mode. ///< \return Resulting mode diff --git a/apps/openmw/mwmechanics/pathfinding.hpp b/apps/openmw/mwmechanics/pathfinding.hpp index f48de6624..0f4d42775 100644 --- a/apps/openmw/mwmechanics/pathfinding.hpp +++ b/apps/openmw/mwmechanics/pathfinding.hpp @@ -88,6 +88,11 @@ namespace MWMechanics return ESM::Pathgrid::Point(static_cast(p.pos[0]), static_cast(p.pos[1]), static_cast(p.pos[2])); } + static osg::Vec3f MakeOsgVec3(const ESM::Pathgrid::Point& p) + { + return osg::Vec3f(static_cast(p.mX), static_cast(p.mY), static_cast(p.mZ)); + } + /// utility function to convert a Pathgrid::Point to a Ogre::Vector3 static Ogre::Vector3 MakeOgreVector3(const ESM::Pathgrid::Point& p) { diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index d2abf1413..25d9e9e47 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -12,12 +12,9 @@ #include "../mwworld/class.hpp" -#include "renderconst.hpp" - namespace MWRender { - CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr, const std::string& model, Resource::ResourceSystem* resourceSystem) : Animation(ptr, osg::ref_ptr(ptr.getRefData().getBaseNode()), resourceSystem) diff --git a/apps/openmw/mwrender/debugging.cpp b/apps/openmw/mwrender/debugging.cpp index 79eeff2d0..97ead9d7d 100644 --- a/apps/openmw/mwrender/debugging.cpp +++ b/apps/openmw/mwrender/debugging.cpp @@ -2,13 +2,10 @@ #include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include #include @@ -23,145 +20,118 @@ #include "../mwworld/esmstore.hpp" #include "../mwmechanics/pathfinding.hpp" -#include "renderconst.hpp" - -using namespace Ogre; +#include "vismask.hpp" namespace MWRender { -static const std::string PATHGRID_POINT_MATERIAL = "pathgridPointMaterial"; -static const std::string PATHGRID_LINE_MATERIAL = "pathgridLineMaterial"; -static const std::string DEBUGGING_GROUP = "debugging"; static const int POINT_MESH_BASE = 35; -void Debugging::createGridMaterials() -{ - if (mGridMatsCreated) return; - - if (MaterialManager::getSingleton().getByName(PATHGRID_LINE_MATERIAL, DEBUGGING_GROUP).isNull()) - { - MaterialPtr lineMatPtr = MaterialManager::getSingleton().create(PATHGRID_LINE_MATERIAL, DEBUGGING_GROUP); - lineMatPtr->setReceiveShadows(false); - lineMatPtr->getTechnique(0)->setLightingEnabled(true); - lineMatPtr->getTechnique(0)->getPass(0)->setDiffuse(1,1,0,0); - lineMatPtr->getTechnique(0)->getPass(0)->setAmbient(1,1,0); - lineMatPtr->getTechnique(0)->getPass(0)->setSelfIllumination(1,1,0); - } - - if (MaterialManager::getSingleton().getByName(PATHGRID_POINT_MATERIAL, DEBUGGING_GROUP).isNull()) - { - MaterialPtr pointMatPtr = MaterialManager::getSingleton().create(PATHGRID_POINT_MATERIAL, DEBUGGING_GROUP); - pointMatPtr->setReceiveShadows(false); - pointMatPtr->getTechnique(0)->setLightingEnabled(true); - pointMatPtr->getTechnique(0)->getPass(0)->setDiffuse(1,0,0,0); - pointMatPtr->getTechnique(0)->getPass(0)->setAmbient(1,0,0); - pointMatPtr->getTechnique(0)->getPass(0)->setSelfIllumination(1,0,0); - } - mGridMatsCreated = true; -} - -void Debugging::destroyGridMaterials() +osg::ref_ptr Debugging::createPathgridLines(const ESM::Pathgrid *pathgrid) { - if (mGridMatsCreated) - { - MaterialManager::getSingleton().remove(PATHGRID_POINT_MATERIAL); - MaterialManager::getSingleton().remove(PATHGRID_LINE_MATERIAL); - mGridMatsCreated = false; - } -} + osg::ref_ptr geom = new osg::Geometry; -ManualObject *Debugging::createPathgridLines(const ESM::Pathgrid *pathgrid) -{ - ManualObject *result = mSceneMgr->createManualObject(); + osg::ref_ptr vertices = new osg::Vec3Array; - result->begin(PATHGRID_LINE_MATERIAL, RenderOperation::OT_LINE_LIST); for(ESM::Pathgrid::EdgeList::const_iterator it = pathgrid->mEdges.begin(); it != pathgrid->mEdges.end(); ++it) { const ESM::Pathgrid::Edge &edge = *it; const ESM::Pathgrid::Point &p1 = pathgrid->mPoints[edge.mV0], &p2 = pathgrid->mPoints[edge.mV1]; - Vector3 direction = (MWMechanics::PathFinder::MakeOgreVector3(p2) - MWMechanics::PathFinder::MakeOgreVector3(p1)); - Vector3 lineDisplacement = direction.crossProduct(Vector3::UNIT_Z).normalisedCopy(); + + osg::Vec3f direction = MWMechanics::PathFinder::MakeOsgVec3(p2) - MWMechanics::PathFinder::MakeOsgVec3(p1); + osg::Vec3f lineDisplacement = (direction^osg::Vec3f(0,0,1)); + lineDisplacement.normalize(); + lineDisplacement = lineDisplacement * POINT_MESH_BASE + - Vector3(0, 0, 10); // move lines up a little, so they will be less covered by meshes/landscape - result->position(MWMechanics::PathFinder::MakeOgreVector3(p1) + lineDisplacement); - result->position(MWMechanics::PathFinder::MakeOgreVector3(p2) + lineDisplacement); + osg::Vec3f(0, 0, 10); // move lines up a little, so they will be less covered by meshes/landscape + + vertices->push_back(MWMechanics::PathFinder::MakeOsgVec3(p1) + lineDisplacement); + vertices->push_back(MWMechanics::PathFinder::MakeOsgVec3(p2) + lineDisplacement); } - result->end(); - result->setVisibilityFlags (RV_Debug); + geom->setVertexArray(vertices); + + geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINES, 0, vertices->size())); - return result; + osg::ref_ptr colors = new osg::Vec4Array; + colors->push_back(osg::Vec4(1.f, 1.f, 0.f, 1.f)); + geom->setColorArray(colors, osg::Array::BIND_OVERALL); + + return geom; } -ManualObject *Debugging::createPathgridPoints(const ESM::Pathgrid *pathgrid) +osg::ref_ptr Debugging::createPathgridPoints(const ESM::Pathgrid *pathgrid) { - ManualObject *result = mSceneMgr->createManualObject(); + osg::ref_ptr geom = new osg::Geometry; + const float height = POINT_MESH_BASE * sqrtf(2); - result->begin(PATHGRID_POINT_MATERIAL, RenderOperation::OT_TRIANGLE_STRIP); + osg::ref_ptr vertices = new osg::Vec3Array; + osg::ref_ptr indices = new osg::UShortArray; bool first = true; - uint32 startIndex = 0; + unsigned short startIndex = 0; for(ESM::Pathgrid::PointList::const_iterator it = pathgrid->mPoints.begin(); it != pathgrid->mPoints.end(); ++it, startIndex += 6) { - Vector3 pointPos(MWMechanics::PathFinder::MakeOgreVector3(*it)); + osg::Vec3f pointPos(MWMechanics::PathFinder::MakeOsgVec3(*it)); if (!first) { // degenerate triangle from previous octahedron - result->index(startIndex - 4); // 2nd point of previous octahedron - result->index(startIndex); // start point of current octahedron + indices->push_back(startIndex - 4); // 2nd point of previous octahedron + indices->push_back(startIndex); // start point of current octahedron } - Ogre::Real pointMeshBase = static_cast(POINT_MESH_BASE); - - result->position(pointPos + Vector3(0, 0, height)); // 0 - result->position(pointPos + Vector3(-pointMeshBase, -pointMeshBase, 0)); // 1 - result->position(pointPos + Vector3(pointMeshBase, -pointMeshBase, 0)); // 2 - result->position(pointPos + Vector3(pointMeshBase, pointMeshBase, 0)); // 3 - result->position(pointPos + Vector3(-pointMeshBase, pointMeshBase, 0)); // 4 - result->position(pointPos + Vector3(0, 0, -height)); // 5 - - result->index(startIndex + 0); - result->index(startIndex + 1); - result->index(startIndex + 2); - result->index(startIndex + 5); - result->index(startIndex + 3); - result->index(startIndex + 4); + float pointMeshBase = static_cast(POINT_MESH_BASE); + + vertices->push_back(pointPos + osg::Vec3f(0, 0, height)); // 0 + vertices->push_back(pointPos + osg::Vec3f(-pointMeshBase, -pointMeshBase, 0)); // 1 + vertices->push_back(pointPos + osg::Vec3f(pointMeshBase, -pointMeshBase, 0)); // 2 + vertices->push_back(pointPos + osg::Vec3f(pointMeshBase, pointMeshBase, 0)); // 3 + vertices->push_back(pointPos + osg::Vec3f(-pointMeshBase, pointMeshBase, 0)); // 4 + vertices->push_back(pointPos + osg::Vec3f(0, 0, -height)); // 5 + + indices->push_back(startIndex + 0); + indices->push_back(startIndex + 1); + indices->push_back(startIndex + 2); + indices->push_back(startIndex + 5); + indices->push_back(startIndex + 3); + indices->push_back(startIndex + 4); // degenerates - result->index(startIndex + 4); - result->index(startIndex + 5); - result->index(startIndex + 5); + indices->push_back(startIndex + 4); + indices->push_back(startIndex + 5); + indices->push_back(startIndex + 5); // end degenerates - result->index(startIndex + 1); - result->index(startIndex + 4); - result->index(startIndex + 0); - result->index(startIndex + 3); - result->index(startIndex + 2); + indices->push_back(startIndex + 1); + indices->push_back(startIndex + 4); + indices->push_back(startIndex + 0); + indices->push_back(startIndex + 3); + indices->push_back(startIndex + 2); first = false; } - result->end(); + geom->setVertexArray(vertices); - result->setVisibilityFlags (RV_Debug); + geom->addPrimitiveSet(new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLE_STRIP, indices->size(), &(*indices)[0])); - return result; + osg::ref_ptr colors = new osg::Vec4Array; + colors->push_back(osg::Vec4(1.f, 0.f, 0.f, 1.f)); + geom->setColorArray(colors, osg::Array::BIND_OVERALL); + + return geom; } -Debugging::Debugging(SceneNode *root, OEngine::Physic::PhysicEngine *engine) : - mRootNode(root), mEngine(engine), - mSceneMgr(root->getCreator()), - mPathgridEnabled(false), - mInteriorPathgridNode(NULL), mPathGridRoot(NULL), - mGridMatsCreated(false) +Debugging::Debugging(osg::ref_ptr root /*, OEngine::Physic::PhysicEngine *engine*/) + : mRootNode(root) + , mPathgridEnabled(false) + , mInteriorPathgridNode(NULL) + , mPathGridRoot(NULL) { - ResourceGroupManager::getSingleton().createResourceGroup(DEBUGGING_GROUP); } Debugging::~Debugging() @@ -170,34 +140,34 @@ Debugging::~Debugging() { togglePathgrid(); } - - ResourceGroupManager::getSingleton().destroyResourceGroup(DEBUGGING_GROUP); } bool Debugging::toggleRenderMode (int mode){ switch (mode) { - case MWBase::World::Render_CollisionDebug: + //case Render_CollisionDebug: - return mEngine->toggleDebugRendering(); + //return mEngine->toggleDebugRendering(); - case MWBase::World::Render_Pathgrid: + case Render_Pathgrid: togglePathgrid(); return mPathgridEnabled; + default: + return false; } return false; } -void Debugging::cellAdded(MWWorld::CellStore *store) +void Debugging::addCell(const MWWorld::CellStore *store) { mActiveCells.push_back(store); if (mPathgridEnabled) enableCellPathgrid(store); } -void Debugging::cellRemoved(MWWorld::CellStore *store) +void Debugging::removeCell(const MWWorld::CellStore *store) { mActiveCells.erase(std::remove(mActiveCells.begin(), mActiveCells.end(), store), mActiveCells.end()); if (mPathgridEnabled) @@ -209,10 +179,11 @@ void Debugging::togglePathgrid() mPathgridEnabled = !mPathgridEnabled; if (mPathgridEnabled) { - createGridMaterials(); - // add path grid meshes to already loaded cells - mPathGridRoot = mRootNode->createChildSceneNode(); + mPathGridRoot = new osg::Group; + mPathGridRoot->setNodeMask(Mask_Debug); + mRootNode->addChild(mPathGridRoot); + for(CellList::iterator it = mActiveCells.begin(); it != mActiveCells.end(); ++it) { enableCellPathgrid(*it); @@ -225,29 +196,44 @@ void Debugging::togglePathgrid() { disableCellPathgrid(*it); } - mPathGridRoot->removeAndDestroyAllChildren(); - mSceneMgr->destroySceneNode(mPathGridRoot); - mPathGridRoot = NULL; - destroyGridMaterials(); + + if (mPathGridRoot) + { + mRootNode->removeChild(mPathGridRoot); + mPathGridRoot = NULL; + } } } -void Debugging::enableCellPathgrid(MWWorld::CellStore *store) +void Debugging::enableCellPathgrid(const MWWorld::CellStore *store) { MWBase::World* world = MWBase::Environment::get().getWorld(); const ESM::Pathgrid *pathgrid = world->getStore().get().search(*store->getCell()); if (!pathgrid) return; - Vector3 cellPathGridPos(0, 0, 0); + osg::Vec3f cellPathGridPos(0, 0, 0); if (store->getCell()->isExterior()) { - cellPathGridPos.x = static_cast(store->getCell()->mData.mX * ESM::Land::REAL_SIZE); - cellPathGridPos.y = static_cast(store->getCell()->mData.mY * ESM::Land::REAL_SIZE); + cellPathGridPos.x() = static_cast(store->getCell()->mData.mX * ESM::Land::REAL_SIZE); + cellPathGridPos.y() = static_cast(store->getCell()->mData.mY * ESM::Land::REAL_SIZE); } - SceneNode *cellPathGrid = mPathGridRoot->createChildSceneNode(cellPathGridPos); - cellPathGrid->attachObject(createPathgridLines(pathgrid)); - cellPathGrid->attachObject(createPathgridPoints(pathgrid)); + + osg::ref_ptr cellPathGrid = new osg::PositionAttitudeTransform; + cellPathGrid->setPosition(cellPathGridPos); + + osg::ref_ptr lineGeode = new osg::Geode; + osg::ref_ptr lines = createPathgridLines(pathgrid); + lineGeode->addDrawable(lines); + + osg::ref_ptr pointGeode = new osg::Geode; + osg::ref_ptr points = createPathgridPoints(pathgrid); + pointGeode->addDrawable(points); + + cellPathGrid->addChild(lineGeode); + cellPathGrid->addChild(pointGeode); + + mPathGridRoot->addChild(cellPathGrid); if (store->getCell()->isExterior()) { @@ -260,7 +246,7 @@ void Debugging::enableCellPathgrid(MWWorld::CellStore *store) } } -void Debugging::disableCellPathgrid(MWWorld::CellStore *store) +void Debugging::disableCellPathgrid(const MWWorld::CellStore *store) { if (store->getCell()->isExterior()) { @@ -268,7 +254,7 @@ void Debugging::disableCellPathgrid(MWWorld::CellStore *store) mExteriorPathgridNodes.find(std::make_pair(store->getCell()->getGridX(), store->getCell()->getGridY())); if (it != mExteriorPathgridNodes.end()) { - destroyCellPathgridNode(it->second); + mPathGridRoot->removeChild(it->second); mExteriorPathgridNodes.erase(it); } } @@ -276,27 +262,10 @@ void Debugging::disableCellPathgrid(MWWorld::CellStore *store) { if (mInteriorPathgridNode) { - destroyCellPathgridNode(mInteriorPathgridNode); + mPathGridRoot->removeChild(mInteriorPathgridNode); mInteriorPathgridNode = NULL; } } } -void Debugging::destroyCellPathgridNode(SceneNode *node) -{ - mPathGridRoot->removeChild(node); - destroyAttachedObjects(node); - mSceneMgr->destroySceneNode(node); -} - -void Debugging::destroyAttachedObjects(SceneNode *node) -{ - SceneNode::ObjectIterator objIt = node->getAttachedObjectIterator(); - while (objIt.hasMoreElements()) - { - MovableObject *mesh = static_cast(objIt.getNext()); - mSceneMgr->destroyMovableObject(mesh); - } -} - } diff --git a/apps/openmw/mwrender/debugging.hpp b/apps/openmw/mwrender/debugging.hpp index e24331801..4ec5bc41d 100644 --- a/apps/openmw/mwrender/debugging.hpp +++ b/apps/openmw/mwrender/debugging.hpp @@ -7,6 +7,8 @@ #include #include +#include + namespace ESM { struct Pathgrid; @@ -20,16 +22,10 @@ namespace OEngine } } -namespace Ogre +namespace osg { - class Camera; - class Viewport; - class SceneManager; - class SceneNode; - class RaySceneQuery; - class Quaternion; - class Vector3; - class ManualObject; + class Group; + class Geometry; } namespace MWWorld @@ -42,47 +38,37 @@ namespace MWRender { class Debugging { - OEngine::Physic::PhysicEngine* mEngine; - Ogre::SceneManager *mSceneMgr; + //OEngine::Physic::PhysicEngine* mEngine; // Path grid stuff bool mPathgridEnabled; void togglePathgrid(); - typedef std::vector CellList; + typedef std::vector CellList; CellList mActiveCells; - Ogre::SceneNode *mRootNode; + osg::ref_ptr mRootNode; - Ogre::SceneNode *mPathGridRoot; + osg::ref_ptr mPathGridRoot; - typedef std::map, Ogre::SceneNode *> ExteriorPathgridNodes; + typedef std::map, osg::ref_ptr > ExteriorPathgridNodes; ExteriorPathgridNodes mExteriorPathgridNodes; - Ogre::SceneNode *mInteriorPathgridNode; - - void enableCellPathgrid(MWWorld::CellStore *store); - void disableCellPathgrid(MWWorld::CellStore *store); - - // utility - void destroyCellPathgridNode(Ogre::SceneNode *node); - void destroyAttachedObjects(Ogre::SceneNode *node); + osg::ref_ptr mInteriorPathgridNode; - // materials - bool mGridMatsCreated; - void createGridMaterials(); - void destroyGridMaterials(); + void enableCellPathgrid(const MWWorld::CellStore *store); + void disableCellPathgrid(const MWWorld::CellStore *store); // path grid meshes - Ogre::ManualObject *createPathgridLines(const ESM::Pathgrid *pathgrid); - Ogre::ManualObject *createPathgridPoints(const ESM::Pathgrid *pathgrid); + osg::ref_ptr createPathgridLines(const ESM::Pathgrid *pathgrid); + osg::ref_ptr createPathgridPoints(const ESM::Pathgrid *pathgrid); public: - Debugging(Ogre::SceneNode* root, OEngine::Physic::PhysicEngine *engine); + Debugging(osg::ref_ptr root /*, OEngine::Physic::PhysicEngine *engine*/); ~Debugging(); bool toggleRenderMode (int mode); - void cellAdded(MWWorld::CellStore* store); - void cellRemoved(MWWorld::CellStore* store); + void addCell(const MWWorld::CellStore* store); + void removeCell(const MWWorld::CellStore* store); }; diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 80dbf3c7f..d6aa05fcb 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -23,7 +23,6 @@ #include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/soundmanager.hpp" -#include "renderconst.hpp" #include "camera.hpp" namespace diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index a06b751cc..6f4f4ef79 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -17,7 +17,6 @@ #include "../mwworld/ptr.hpp" #include "../mwworld/class.hpp" -#include "renderconst.hpp" #include "animation.hpp" #include "npcanimation.hpp" #include "creatureanimation.hpp" diff --git a/apps/openmw/mwrender/renderconst.hpp b/apps/openmw/mwrender/renderconst.hpp deleted file mode 100644 index cfd84cb32..000000000 --- a/apps/openmw/mwrender/renderconst.hpp +++ /dev/null @@ -1,76 +0,0 @@ -#ifndef GAME_RENDER_CONST_H -#define GAME_RENDER_CONST_H - -#include - -namespace MWRender -{ - -// Render queue groups -enum RenderQueueGroups -{ - // Sky early (atmosphere, clouds, moons) - RQG_SkiesEarly = Ogre::RENDER_QUEUE_SKIES_EARLY, - - RQG_Main = Ogre::RENDER_QUEUE_MAIN, - - RQG_Alpha = Ogre::RENDER_QUEUE_MAIN+1, - - RQG_OcclusionQuery = Ogre::RENDER_QUEUE_6, - - RQG_UnderWater = Ogre::RENDER_QUEUE_4, - - RQG_Water = RQG_Alpha, - RQG_Ripples = RQG_Water+1, - - // Sky late (sun & sun flare) - RQG_SkiesLate = Ogre::RENDER_QUEUE_SKIES_LATE -}; - -// Visibility flags -enum VisibilityFlags -{ - // Terrain - RV_Terrain = (1<<0), - - // Statics (e.g. trees, houses) - RV_Statics = (1<<1), - - // Small statics - RV_StaticsSmall = (1<<2), - - // Water - RV_Water = (1<<3), - - // Actors (npcs, creatures) - RV_Actors = (1<<4), - - // Misc objects (containers, dynamic objects) - RV_Misc = (1<<5), - - // VFX, don't appear on map and don't cast shadows - RV_Effects = (1<<6), - - RV_Sky = (1<<7), - - // not visible in reflection - RV_NoReflection = (1<<8), - - RV_OcclusionQuery = (1<<9), - - RV_Debug = (1<<10), - - // overlays, we only want these on the main render target - RV_Overlay = (1<<11), - - // First person meshes do not cast shadows - RV_FirstPerson = (1<<12), - - RV_Map = RV_Terrain + RV_Statics + RV_StaticsSmall + RV_Misc + RV_Water, - - RV_Refraction = RV_Actors + RV_Misc + RV_Statics + RV_StaticsSmall + RV_Terrain + RV_Effects + RV_Sky + RV_FirstPerson -}; - -} - -#endif diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index d07c98ed7..5cb779545 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -21,10 +21,13 @@ #include +#include "../mwbase/world.hpp" + #include "sky.hpp" #include "effectmanager.hpp" #include "npcanimation.hpp" #include "vismask.hpp" +#include "debugging.hpp" namespace MWRender { @@ -88,6 +91,8 @@ namespace MWRender mRootNode->addChild(lightRoot); + mDebugging.reset(new Debugging(mRootNode)); + mObjects.reset(new Objects(mResourceSystem, lightRoot)); mEffectManager.reset(new EffectManager(mRootNode, mResourceSystem)); @@ -182,8 +187,14 @@ namespace MWRender return eye; } + void RenderingManager::addCell(const MWWorld::CellStore *store) + { + mDebugging->addCell(store); + } + void RenderingManager::removeCell(const MWWorld::CellStore *store) { + mDebugging->removeCell(store); mObjects->removeCell(store); } @@ -192,6 +203,25 @@ namespace MWRender mSky->setEnabled(enabled); } + bool RenderingManager::toggleRenderMode(RenderMode mode) + { + if (mode == Render_CollisionDebug || mode == Render_Pathgrid) + return mDebugging->toggleRenderMode(mode); + else if (mode == Render_Wireframe) + { + return false; + } + /* + else //if (mode == Render_BoundingBoxes) + { + bool show = !mRendering.getScene()->getShowBoundingBoxes(); + mRendering.getScene()->showBoundingBoxes(show); + return show; + } + */ + return false; + } + void RenderingManager::configureFog(const ESM::Cell *cell) { osg::Vec4f color = SceneUtil::colourFromRGB(cell->mAmbi.mFog); diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 71c70b990..334025096 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -7,6 +7,7 @@ #include "objects.hpp" #include "renderinginterface.hpp" +#include "rendermode.hpp" namespace osg { @@ -37,6 +38,7 @@ namespace MWRender class EffectManager; class SkyManager; class NpcAnimation; + class Debugging; class RenderingManager : public MWRender::RenderingInterface { @@ -57,6 +59,7 @@ namespace MWRender void configureFog(const ESM::Cell* cell); void configureFog(float fogDepth, const osg::Vec4f& colour); + void addCell(const MWWorld::CellStore* store); void removeCell(const MWWorld::CellStore* store); // TODO rename to setRotation/setPosition/setScale, along with the World equivalents @@ -66,6 +69,8 @@ namespace MWRender void setSkyEnabled(bool enabled); + bool toggleRenderMode(RenderMode mode); + SkyManager* getSkyManager(); osg::Vec3f getEyePos(); @@ -94,6 +99,7 @@ namespace MWRender osg::ref_ptr mSunLight; + std::auto_ptr mDebugging; std::auto_ptr mObjects; std::auto_ptr mSky; std::auto_ptr mEffectManager; diff --git a/apps/openmw/mwrender/rendermode.hpp b/apps/openmw/mwrender/rendermode.hpp new file mode 100644 index 000000000..a74d9bd52 --- /dev/null +++ b/apps/openmw/mwrender/rendermode.hpp @@ -0,0 +1,17 @@ +#ifndef OPENMW_MWRENDER_RENDERMODE_H +#define OPENMW_MWRENDER_RENDERMODE_H + +namespace MWRender +{ + + enum RenderMode + { + Render_CollisionDebug, + Render_Wireframe, + Render_Pathgrid, + Render_BoundingBoxes + }; + +} + +#endif diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 4fd5b7e63..48de57239 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -34,7 +34,6 @@ #include "../mwworld/fallback.hpp" -#include "renderconst.hpp" #include "renderingmanager.hpp" namespace diff --git a/apps/openmw/mwrender/vismask.hpp b/apps/openmw/mwrender/vismask.hpp index 48845c78c..872695556 100644 --- a/apps/openmw/mwrender/vismask.hpp +++ b/apps/openmw/mwrender/vismask.hpp @@ -11,6 +11,7 @@ namespace MWRender // child of Scene Mask_Effect = 0x2, + Mask_Debug = 0x4, // top level masks Mask_Scene = 0x10, diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 29f586a65..ce74c0c9f 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -213,7 +213,7 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { bool enabled = - MWBase::Environment::get().getWorld()->toggleRenderMode (MWBase::World::Render_CollisionDebug); + MWBase::Environment::get().getWorld()->toggleRenderMode (MWRender::Render_CollisionDebug); runtime.getContext().report (enabled ? "Collision Mesh Rendering -> On" : "Collision Mesh Rendering -> Off"); @@ -228,7 +228,7 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { bool enabled = - MWBase::Environment::get().getWorld()->toggleRenderMode (MWBase::World::Render_BoundingBoxes); + MWBase::Environment::get().getWorld()->toggleRenderMode (MWRender::Render_BoundingBoxes); runtime.getContext().report (enabled ? "Bounding Box Rendering -> On" : "Bounding Box Rendering -> Off"); @@ -242,7 +242,7 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { bool enabled = - MWBase::Environment::get().getWorld()->toggleRenderMode (MWBase::World::Render_Wireframe); + MWBase::Environment::get().getWorld()->toggleRenderMode (MWRender::Render_Wireframe); runtime.getContext().report (enabled ? "Wireframe Rendering -> On" : "Wireframe Rendering -> Off"); @@ -255,7 +255,7 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { bool enabled = - MWBase::Environment::get().getWorld()->toggleRenderMode (MWBase::World::Render_Pathgrid); + MWBase::Environment::get().getWorld()->toggleRenderMode (MWRender::Render_Pathgrid); runtime.getContext().report (enabled ? "Path Grid rendering -> On" : "Path Grid Rendering -> Off"); diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index e61e5d84e..637fde18c 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -270,8 +270,8 @@ namespace MWWorld /// \todo rescale depending on the state of a new GMST insertCell (*cell, true, loadingListener); + mRendering.addCell(cell); #if 0 - mRendering.cellAdded (cell); bool waterEnabled = cell->getCell()->hasWater(); mRendering.setWaterEnabled(waterEnabled); if (waterEnabled) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 842a24ded..fda9d53af 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1501,9 +1501,9 @@ namespace MWWorld return 0;//mPhysics->toggleCollisionMode(); } - bool World::toggleRenderMode (RenderMode mode) + bool World::toggleRenderMode (MWRender::RenderMode mode) { - return 0;//mRendering->toggleRenderMode (mode); + return mRendering->toggleRenderMode (mode); } const ESM::Potion *World::createRecord (const ESM::Potion& record) diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 9598d4357..464f2d605 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -396,7 +396,7 @@ namespace MWWorld /// collisions and gravity. ///< \return Resulting mode - virtual bool toggleRenderMode (RenderMode mode); + virtual bool toggleRenderMode (MWRender::RenderMode mode); ///< Toggle a render mode. ///< \return Resulting mode From 1943110170fb7c5242da9a4fa511f779fbc21121 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 3 May 2015 00:39:01 +0200 Subject: [PATCH 1090/3725] Add bullet debug drawer --- apps/openmw/CMakeLists.txt | 1 + apps/openmw/mwrender/bulletdebugdraw.cpp | 98 ++++++++++++++++++++++++ apps/openmw/mwrender/bulletdebugdraw.hpp | 58 ++++++++++++++ apps/openmw/mwrender/debugging.cpp | 4 - apps/openmw/mwworld/physicssystem.cpp | 26 ++++++- apps/openmw/mwworld/physicssystem.hpp | 21 ++++- apps/openmw/mwworld/scene.cpp | 26 ++----- apps/openmw/mwworld/worldimp.cpp | 17 ++-- libs/openengine/bullet/physic.cpp | 46 +---------- libs/openengine/bullet/physic.hpp | 23 ------ 10 files changed, 221 insertions(+), 99 deletions(-) create mode 100644 apps/openmw/mwrender/bulletdebugdraw.cpp create mode 100644 apps/openmw/mwrender/bulletdebugdraw.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index ed5530126..81cecc2c8 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -22,6 +22,7 @@ source_group(game FILES ${GAME} ${GAME_HEADER}) add_openmw_dir (mwrender actors objects renderingmanager animation sky npcanimation vismask creatureanimation effectmanager util renderinginterface debugging rendermode + bulletdebugdraw # camera activatoranimation # localmap occlusionquery water shadows # characterpreview globalmap ripplesimulation refraction diff --git a/apps/openmw/mwrender/bulletdebugdraw.cpp b/apps/openmw/mwrender/bulletdebugdraw.cpp new file mode 100644 index 000000000..9e683232b --- /dev/null +++ b/apps/openmw/mwrender/bulletdebugdraw.cpp @@ -0,0 +1,98 @@ +#include "bulletdebugdraw.hpp" + +#include + +#include +#include +#include + +#include "vismask.hpp" + +namespace +{ + osg::Vec3f toOsg(const btVector3& vec) + { + return osg::Vec3f(vec.x(), vec.y(), vec.z()); + } +} + +namespace MWRender +{ + +DebugDrawer::DebugDrawer(osg::ref_ptr parentNode, btDynamicsWorld *world) + : mParentNode(parentNode), + mWorld(world), + mDebugOn(true) +{ + mGeode = new osg::Geode; + mParentNode->addChild(mGeode); + mGeode->setNodeMask(Mask_Debug); + + mGeometry = new osg::Geometry; + + mVertices = new osg::Vec3Array; + + mDrawArrays = new osg::DrawArrays(osg::PrimitiveSet::LINES); + + mGeometry->setUseDisplayList(false); + mGeometry->setVertexArray(mVertices); + mGeometry->setDataVariance(osg::Object::DYNAMIC); + mGeometry->addPrimitiveSet(mDrawArrays); + + mGeode->addDrawable(mGeometry); + mParentNode->addChild(mGeode); +} + +DebugDrawer::~DebugDrawer() +{ + mParentNode->removeChild(mGeode); +} + +void DebugDrawer::step() +{ + if (mDebugOn) + { + mVertices->clear(); + mWorld->debugDrawWorld(); + mDrawArrays->setCount(mVertices->size()); + mVertices->dirty(); + } +} + +void DebugDrawer::drawLine(const btVector3 &from, const btVector3 &to, const btVector3 &color) +{ + mVertices->push_back(toOsg(from)); + mVertices->push_back(toOsg(to)); +} + +void DebugDrawer::drawContactPoint(const btVector3 &PointOnB, const btVector3 &normalOnB, btScalar distance, int lifeTime, const btVector3 &color) +{ + mVertices->push_back(toOsg(PointOnB)); + mVertices->push_back(toOsg(PointOnB) + (toOsg(normalOnB) * distance * 20)); +} + +void DebugDrawer::reportErrorWarning(const char *warningString) +{ + std::cerr << warningString << std::endl; +} + +void DebugDrawer::setDebugMode(int isOn) +{ + mDebugOn = (isOn == 0) ? false : true; + + if (!mDebugOn) + { + mVertices->clear(); + mVertices->releaseGLObjects(0); + mGeometry->releaseGLObjects(0); + } +} + +int DebugDrawer::getDebugMode() const +{ + return mDebugOn; +} + + + +} diff --git a/apps/openmw/mwrender/bulletdebugdraw.hpp b/apps/openmw/mwrender/bulletdebugdraw.hpp new file mode 100644 index 000000000..288091e7c --- /dev/null +++ b/apps/openmw/mwrender/bulletdebugdraw.hpp @@ -0,0 +1,58 @@ +#ifndef OPENMW_MWRENDER_BULLETDEBUGDRAW_H +#define OPENMW_MWRENDER_BULLETDEBUGDRAW_H + +#include "btBulletDynamicsCommon.h" + +#include +#include +#include + +namespace osg +{ + class Group; + class Geode; + class Geometry; +} + +namespace MWRender +{ + +class DebugDrawer : public btIDebugDraw +{ +protected: + osg::ref_ptr mParentNode; + btDynamicsWorld *mWorld; + osg::ref_ptr mGeode; + osg::ref_ptr mGeometry; + osg::ref_ptr mVertices; + osg::ref_ptr mDrawArrays; + + bool mDebugOn; + +public: + + DebugDrawer(osg::ref_ptr parentNode, btDynamicsWorld *world); + ~DebugDrawer(); + + void step(); + + void drawLine(const btVector3& from,const btVector3& to,const btVector3& color); + + void drawContactPoint(const btVector3& PointOnB,const btVector3& normalOnB,btScalar distance,int lifeTime,const btVector3& color); + + void reportErrorWarning(const char* warningString); + + void draw3dText(const btVector3& location,const char* textString) {} + + //0 for off, anything else for on. + void setDebugMode(int isOn); + + //0 for off, anything else for on. + int getDebugMode() const; + +}; + + +} + +#endif diff --git a/apps/openmw/mwrender/debugging.cpp b/apps/openmw/mwrender/debugging.cpp index 97ead9d7d..9cbf94d46 100644 --- a/apps/openmw/mwrender/debugging.cpp +++ b/apps/openmw/mwrender/debugging.cpp @@ -146,10 +146,6 @@ Debugging::~Debugging() bool Debugging::toggleRenderMode (int mode){ switch (mode) { - //case Render_CollisionDebug: - - //return mEngine->toggleDebugRendering(); - case Render_Pathgrid: togglePathgrid(); return mPathgridEnabled; diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 271b23d09..422268397 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -10,6 +10,8 @@ #include #include +#include + #include #include #include @@ -29,6 +31,8 @@ #include "../mwworld/esmstore.hpp" #include "../mwworld/cellstore.hpp" +#include "../mwrender/bulletdebugdraw.hpp" + //#include "../apps/openmw/mwrender/animation.hpp" #include "../apps/openmw/mwbase/world.hpp" #include "../apps/openmw/mwbase/environment.hpp" @@ -498,8 +502,8 @@ namespace MWWorld }; - PhysicsSystem::PhysicsSystem() : - mEngine(0), mTimeAccum(0.0f), mWaterEnabled(false), mWaterHeight(0) + PhysicsSystem::PhysicsSystem(osg::ref_ptr parentNode) : + mEngine(0), mTimeAccum(0.0f), mWaterEnabled(false), mWaterHeight(0), mDebugDrawEnabled(false), mParentNode(parentNode) { // Create physics. shapeLoader is deleted by the physic engine //NifBullet::ManualBulletShapeLoader* shapeLoader = new NifBullet::ManualBulletShapeLoader(); @@ -514,6 +518,21 @@ namespace MWWorld //delete OEngine::Physic::BulletShapeManager::getSingletonPtr(); } + bool PhysicsSystem::toggleDebugRendering() + { + mDebugDrawEnabled = !mDebugDrawEnabled; + + if (mDebugDrawEnabled && !mDebugDrawer.get()) + { + mDebugDrawer.reset(new MWRender::DebugDrawer(mParentNode, mEngine->mDynamicsWorld)); + mEngine->mDynamicsWorld->setDebugDrawer(mDebugDrawer.get()); + mDebugDrawer->setDebugMode(mDebugDrawEnabled); + } + else if (mDebugDrawer.get()) + mDebugDrawer->setDebugMode(mDebugDrawEnabled); + return mDebugDrawEnabled; + } + OEngine::Physic::PhysicEngine* PhysicsSystem::getEngine() { return mEngine; @@ -799,6 +818,9 @@ namespace MWWorld animateCollisionShapes(mEngine->mAnimatedShapes, mEngine->mDynamicsWorld); mEngine->stepSimulation(dt); + + if (mDebugDrawer.get()) + mDebugDrawer->step(); } bool PhysicsSystem::isActorStandingOn(const Ptr &actor, const Ptr &object) const diff --git a/apps/openmw/mwworld/physicssystem.hpp b/apps/openmw/mwworld/physicssystem.hpp index 23bf47543..1fc0e0e76 100644 --- a/apps/openmw/mwworld/physicssystem.hpp +++ b/apps/openmw/mwworld/physicssystem.hpp @@ -7,8 +7,14 @@ #include +#include + #include "ptr.hpp" +namespace osg +{ + class Group; +} namespace OEngine { @@ -18,6 +24,11 @@ namespace OEngine } } +namespace MWRender +{ + class DebugDrawer; +} + namespace MWWorld { class World; @@ -27,7 +38,7 @@ namespace MWWorld class PhysicsSystem { public: - PhysicsSystem (); + PhysicsSystem (osg::ref_ptr parentNode); ~PhysicsSystem (); void enableWater(float height); @@ -98,10 +109,14 @@ namespace MWWorld /// Get the handle of all actors colliding with \a object in this frame. void getActorsCollidingWith(const MWWorld::Ptr& object, std::vector& out) const; + bool toggleDebugRendering(); + private: void updateWater(); + bool mDebugDrawEnabled; + OEngine::Physic::PhysicEngine* mEngine; std::map handleToMesh; @@ -123,6 +138,10 @@ namespace MWWorld std::auto_ptr mWaterCollisionObject; std::auto_ptr mWaterCollisionShape; + std::auto_ptr mDebugDrawer; + + osg::ref_ptr mParentNode; + PhysicsSystem (const PhysicsSystem&); PhysicsSystem& operator= (const PhysicsSystem&); }; diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 637fde18c..1ccbc6b55 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -18,7 +18,7 @@ #include "../mwrender/renderingmanager.hpp" -//#include "physicssystem.hpp" +#include "physicssystem.hpp" #include "player.hpp" #include "localscripts.hpp" #include "esmstore.hpp" @@ -26,8 +26,6 @@ #include "cellfunctors.hpp" #include "cellstore.hpp" -#include - namespace { @@ -194,26 +192,22 @@ namespace MWWorld ListAndResetHandles functor; (*iter)->forEach(functor); + for (std::vector::const_iterator iter2 (functor.mHandles.begin()); + iter2!=functor.mHandles.end(); ++iter2) { - // silence annoying g++ warning - for (std::vector::const_iterator iter2 (functor.mHandles.begin()); - iter2!=functor.mHandles.end(); ++iter2) - { - //Ogre::SceneNode* node = *iter2; - //mPhysics->removeObject (node->getName()); - } + //Ogre::SceneNode* node = *iter2; + //mPhysics->removeObject (node->getName()); } if ((*iter)->getCell()->isExterior()) { - /*ESM::Land* land = + ESM::Land* land = MWBase::Environment::get().getWorld()->getStore().get().search( (*iter)->getCell()->getGridX(), (*iter)->getCell()->getGridY() ); if (land && land->mDataTypes&ESM::Land::DATA_VHGT) mPhysics->removeHeightField ((*iter)->getCell()->getGridX(), (*iter)->getCell()->getGridY()); - */ } mRendering.removeCell(*iter); @@ -234,10 +228,9 @@ namespace MWWorld { std::cout << "loading cell " << cell->getCell()->getDescription() << std::endl; - //float verts = ESM::Land::LAND_SIZE; - //float worldsize = ESM::Land::REAL_SIZE; + float verts = ESM::Land::LAND_SIZE; + float worldsize = ESM::Land::REAL_SIZE; -#if 0 // Load terrain physics first... if (cell->getCell()->isExterior()) { @@ -262,7 +255,6 @@ namespace MWWorld ; } } -#endif cell->respawn(); @@ -316,9 +308,7 @@ namespace MWWorld { int newX, newY; MWBase::Environment::get().getWorld()->positionToIndex(pos.x(), pos.y(), newX, newY); - osg::Timer timer; changeCellGrid(newX, newY); - std::cout << "changeCellGrid took " << timer.time_m() << std::endl; //mRendering.updateTerrain(); } } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index fda9d53af..04fd82e80 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -161,7 +161,7 @@ namespace MWWorld mStartCell (startCell), mStartupScript(startupScript), mScriptsEnabled(true) { - mPhysics = new PhysicsSystem(); + mPhysics = new PhysicsSystem(rootNode); //mPhysEngine = mPhysics->getEngine(); #if 0 mProjectileManager.reset(new ProjectileManager(renderer.getScene(), *mPhysEngine)); @@ -1409,9 +1409,8 @@ namespace MWWorld void World::doPhysics(float duration) { + mPhysics->stepSimulation(duration); #if 0 - //mPhysics->stepSimulation(duration); - processDoors(duration); mProjectileManager->update(duration); @@ -1503,7 +1502,13 @@ namespace MWWorld bool World::toggleRenderMode (MWRender::RenderMode mode) { - return mRendering->toggleRenderMode (mode); + switch (mode) + { + case MWRender::Render_CollisionDebug: + return mPhysics->toggleDebugRendering(); + default: + return mRendering->toggleRenderMode(mode); + } } const ESM::Potion *World::createRecord (const ESM::Potion& record) @@ -1601,8 +1606,8 @@ namespace MWWorld updateWeather(duration, paused); - //if (!paused) - // doPhysics (duration); + if (!paused) + doPhysics (duration); mWorldScene->update (duration, paused); diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index b1bd978c6..35c767ca9 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -240,9 +240,7 @@ namespace Physic - PhysicEngine::PhysicEngine(BulletShapeLoader* shapeLoader) : - mDebugActive(0) - , mSceneMgr(NULL) + PhysicEngine::PhysicEngine(BulletShapeLoader* shapeLoader) { // Set up the collision configuration and dispatcher collisionConfiguration = new btDefaultCollisionConfiguration(); @@ -263,42 +261,6 @@ namespace Physic mDynamicsWorld->setGravity(btVector3(0,0,-10)); mShapeLoader = shapeLoader; - - isDebugCreated = false; - mDebugDrawer = NULL; - } - - void PhysicEngine::createDebugRendering() - { - if(!isDebugCreated) - { - Ogre::SceneNode* node = mSceneMgr->getRootSceneNode()->createChildSceneNode(); - mDebugDrawer = new BtOgre::DebugDrawer(node, mDynamicsWorld); - mDynamicsWorld->setDebugDrawer(mDebugDrawer); - isDebugCreated = true; - mDynamicsWorld->debugDrawWorld(); - } - } - - void PhysicEngine::setDebugRenderingMode(bool isDebug) - { - if(!isDebugCreated) - { - createDebugRendering(); - } - mDebugDrawer->setDebugMode(isDebug); - mDebugActive = isDebug; - } - - bool PhysicEngine::toggleDebugRendering() - { - setDebugRenderingMode(!mDebugActive); - return mDebugActive; - } - - void PhysicEngine::setSceneManager(Ogre::SceneManager* sceneMgr) - { - mSceneMgr = sceneMgr; } PhysicEngine::~PhysicEngine() @@ -336,8 +298,6 @@ namespace Physic } } - delete mDebugDrawer; - delete mDynamicsWorld; delete solver; delete collisionConfiguration; @@ -652,10 +612,6 @@ namespace Physic { // This seems to be needed for character controller objects mDynamicsWorld->stepSimulation(static_cast(deltaT), 10, 1 / 60.0f); - if(isDebugCreated) - { - mDebugDrawer->step(); - } } void PhysicEngine::addCharacter(const std::string &name, const std::string &mesh, diff --git a/libs/openengine/bullet/physic.hpp b/libs/openengine/bullet/physic.hpp index e92e9c3c1..6322105e8 100644 --- a/libs/openengine/bullet/physic.hpp +++ b/libs/openengine/bullet/physic.hpp @@ -271,22 +271,6 @@ namespace Physic */ void stepSimulation(double deltaT); - /** - * Create a debug rendering. It is called by setDebgRenderingMode if it's not created yet. - * Important Note: this will crash if the Render is not yet initialise! - */ - void createDebugRendering(); - - /** - * Set the debug rendering mode. 0 to turn it off. - * Important Note: this will crash if the Render is not yet initialise! - */ - void setDebugRenderingMode(bool isDebug); - - bool toggleDebugRendering(); - - void setSceneManager(Ogre::SceneManager* sceneMgr); - /** * Return the closest object hit by a ray. If there are no objects, it will return ("",-1). * If \a normal is non-NULL, the hit normal will be written there (if there is a hit) @@ -328,13 +312,6 @@ namespace Physic typedef std::map PhysicActorContainer; PhysicActorContainer mActorMap; - Ogre::SceneManager* mSceneMgr; - - //debug rendering - BtOgre::DebugDrawer* mDebugDrawer; - bool isDebugCreated; - bool mDebugActive; - private: PhysicEngine(const PhysicEngine&); PhysicEngine& operator=(const PhysicEngine&); From 92cbc139648daf586202ff551fdd4e0ab05cb765 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 3 May 2015 00:50:56 +0200 Subject: [PATCH 1091/3725] Remove BtOgre --- apps/openmw/mwworld/physicssystem.cpp | 30 +- libs/openengine/CMakeLists.txt | 4 - libs/openengine/bullet/BtOgre.cpp | 1096 ------------------------- libs/openengine/bullet/BtOgreExtras.h | 284 ------- libs/openengine/bullet/BtOgreGP.h | 144 ---- libs/openengine/bullet/BtOgrePG.h | 81 -- libs/openengine/bullet/physic.cpp | 25 +- 7 files changed, 40 insertions(+), 1624 deletions(-) delete mode 100644 libs/openengine/bullet/BtOgre.cpp delete mode 100644 libs/openengine/bullet/BtOgreExtras.h delete mode 100644 libs/openengine/bullet/BtOgreGP.h delete mode 100644 libs/openengine/bullet/BtOgrePG.h diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 422268397..6a08e8e1f 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -14,7 +14,6 @@ #include #include -#include //#include #include @@ -93,6 +92,35 @@ void animateCollisionShapes (std::map -#include -#include - -using namespace Ogre; - -namespace BtOgre { - -/* - * ============================================================================================= - * BtOgre::VertexIndexToShape - * ============================================================================================= - */ - - void VertexIndexToShape::addStaticVertexData(const VertexData *vertex_data) - { - if (!vertex_data) - return; - - const VertexData *data = vertex_data; - - const unsigned int prev_size = mVertexCount; - mVertexCount += (unsigned int)data->vertexCount; - - Ogre::Vector3* tmp_vert = new Ogre::Vector3[mVertexCount]; - if (mVertexBuffer) - { - memcpy(tmp_vert, mVertexBuffer, sizeof(Vector3) * prev_size); - delete[] mVertexBuffer; - } - mVertexBuffer = tmp_vert; - - // Get the positional buffer element - { - const Ogre::VertexElement* posElem = data->vertexDeclaration->findElementBySemantic(Ogre::VES_POSITION); - Ogre::HardwareVertexBufferSharedPtr vbuf = data->vertexBufferBinding->getBuffer(posElem->getSource()); - const unsigned int vSize = (unsigned int)vbuf->getVertexSize(); - - unsigned char* vertex = static_cast(vbuf->lock(Ogre::HardwareBuffer::HBL_READ_ONLY)); - float* pReal; - Ogre::Vector3 * curVertices = &mVertexBuffer[prev_size]; - const unsigned int vertexCount = (unsigned int)data->vertexCount; - for(unsigned int j = 0; j < vertexCount; ++j) - { - posElem->baseVertexPointerToElement(vertex, &pReal); - vertex += vSize; - - curVertices->x = (*pReal++); - curVertices->y = (*pReal++); - curVertices->z = (*pReal++); - - *curVertices = mTransform * (*curVertices); - - curVertices++; - } - vbuf->unlock(); - } - } - - //------------------------------------------------------------------------------------------------ - void VertexIndexToShape::addAnimatedVertexData(const Ogre::VertexData *vertex_data, - const Ogre::VertexData *blend_data, - const Ogre::Mesh::IndexMap *indexMap) - { - // Get the bone index element - assert(vertex_data); - - const VertexData *data = blend_data; - const unsigned int prev_size = mVertexCount; - mVertexCount += (unsigned int)data->vertexCount; - Ogre::Vector3* tmp_vert = new Ogre::Vector3[mVertexCount]; - if (mVertexBuffer) - { - memcpy(tmp_vert, mVertexBuffer, sizeof(Vector3) * prev_size); - delete[] mVertexBuffer; - } - mVertexBuffer = tmp_vert; - - // Get the positional buffer element - { - const Ogre::VertexElement* posElem = data->vertexDeclaration->findElementBySemantic(Ogre::VES_POSITION); - assert (posElem); - Ogre::HardwareVertexBufferSharedPtr vbuf = data->vertexBufferBinding->getBuffer(posElem->getSource()); - const unsigned int vSize = (unsigned int)vbuf->getVertexSize(); - - unsigned char* vertex = static_cast(vbuf->lock(Ogre::HardwareBuffer::HBL_READ_ONLY)); - float* pReal; - Ogre::Vector3 * curVertices = &mVertexBuffer[prev_size]; - const unsigned int vertexCount = (unsigned int)data->vertexCount; - for(unsigned int j = 0; j < vertexCount; ++j) - { - posElem->baseVertexPointerToElement(vertex, &pReal); - vertex += vSize; - - curVertices->x = (*pReal++); - curVertices->y = (*pReal++); - curVertices->z = (*pReal++); - - *curVertices = mTransform * (*curVertices); - - curVertices++; - } - vbuf->unlock(); - } - - { - const Ogre::VertexElement* bneElem = vertex_data->vertexDeclaration->findElementBySemantic(Ogre::VES_BLEND_INDICES); - assert (bneElem); - - Ogre::HardwareVertexBufferSharedPtr vbuf = vertex_data->vertexBufferBinding->getBuffer(bneElem->getSource()); - const unsigned int vSize = (unsigned int)vbuf->getVertexSize(); - unsigned char* vertex = static_cast(vbuf->lock(Ogre::HardwareBuffer::HBL_READ_ONLY)); - - unsigned char* pBone; - - if (!mBoneIndex) - mBoneIndex = new BoneIndex(); - BoneIndex::iterator i; - - Ogre::Vector3 * curVertices = &mVertexBuffer[prev_size]; - - const unsigned int vertexCount = (unsigned int)vertex_data->vertexCount; - for(unsigned int j = 0; j < vertexCount; ++j) - { - bneElem->baseVertexPointerToElement(vertex, &pBone); - vertex += vSize; - - const unsigned char currBone = (indexMap) ? (*indexMap)[*pBone] : *pBone; - i = mBoneIndex->find (currBone); - Vector3Array* l = 0; - if (i == mBoneIndex->end()) - { - l = new Vector3Array; - mBoneIndex->insert(std::make_pair(currBone, l)); - } - else - { - l = i->second; - } - - l->push_back(*curVertices); - - curVertices++; - } - vbuf->unlock(); - } - } - - //------------------------------------------------------------------------------------------------ - void VertexIndexToShape::addIndexData(IndexData *data, const unsigned int offset) - { - const unsigned int prev_size = mIndexCount; - mIndexCount += (unsigned int)data->indexCount; - - unsigned int* tmp_ind = new unsigned int[mIndexCount]; - if (mIndexBuffer) - { - memcpy (tmp_ind, mIndexBuffer, sizeof(unsigned int) * prev_size); - delete[] mIndexBuffer; - } - mIndexBuffer = tmp_ind; - - const unsigned int numTris = (unsigned int) data->indexCount / 3; - HardwareIndexBufferSharedPtr ibuf = data->indexBuffer; - const bool use32bitindexes = (ibuf->getType() == HardwareIndexBuffer::IT_32BIT); - unsigned int index_offset = prev_size; - - if (use32bitindexes) - { - const unsigned int* pInt = static_cast(ibuf->lock(HardwareBuffer::HBL_READ_ONLY)); - for(unsigned int k = 0; k < numTris; ++k) - { - mIndexBuffer[index_offset ++] = offset + *pInt++; - mIndexBuffer[index_offset ++] = offset + *pInt++; - mIndexBuffer[index_offset ++] = offset + *pInt++; - } - ibuf->unlock(); - } - else - { - const unsigned short* pShort = static_cast(ibuf->lock(HardwareBuffer::HBL_READ_ONLY)); - for(unsigned int k = 0; k < numTris; ++k) - { - mIndexBuffer[index_offset ++] = offset + static_cast (*pShort++); - mIndexBuffer[index_offset ++] = offset + static_cast (*pShort++); - mIndexBuffer[index_offset ++] = offset + static_cast (*pShort++); - } - ibuf->unlock(); - } - - } - - //------------------------------------------------------------------------------------------------ - Real VertexIndexToShape::getRadius() - { - if (mBoundRadius == (-1)) - { - getSize(); - mBoundRadius = (std::max(mBounds.x,std::max(mBounds.y,mBounds.z)) * 0.5f); - } - return mBoundRadius; - } - - //------------------------------------------------------------------------------------------------ - Vector3 VertexIndexToShape::getSize() - { - const unsigned int vCount = getVertexCount(); - if (mBounds == Ogre::Vector3(-1,-1,-1) && vCount > 0) - { - - const Ogre::Vector3 * const v = getVertices(); - - Ogre::Vector3 vmin(v[0]); - Ogre::Vector3 vmax(v[0]); - - for(unsigned int j = 1; j < vCount; j++) - { - vmin.x = std::min(vmin.x, v[j].x); - vmin.y = std::min(vmin.y, v[j].y); - vmin.z = std::min(vmin.z, v[j].z); - - vmax.x = std::max(vmax.x, v[j].x); - vmax.y = std::max(vmax.y, v[j].y); - vmax.z = std::max(vmax.z, v[j].z); - } - - mBounds.x = vmax.x - vmin.x; - mBounds.y = vmax.y - vmin.y; - mBounds.z = vmax.z - vmin.z; - } - - return mBounds; - } - - //------------------------------------------------------------------------------------------------ - const Ogre::Vector3* VertexIndexToShape::getVertices() - { - return mVertexBuffer; - } - - //------------------------------------------------------------------------------------------------ - unsigned int VertexIndexToShape::getVertexCount() - { - return mVertexCount; - } - - //------------------------------------------------------------------------------------------------ - const unsigned int* VertexIndexToShape::getIndices() - { - return mIndexBuffer; - } - - //------------------------------------------------------------------------------------------------ - unsigned int VertexIndexToShape::getIndexCount() - { - return mIndexCount; - } - - //------------------------------------------------------------------------------------------------ - btSphereShape* VertexIndexToShape::createSphere() - { - const Ogre::Real rad = getRadius(); - assert((rad > 0.0) && - ("Sphere radius must be greater than zero")); - btSphereShape* shape = new btSphereShape(rad); - - shape->setLocalScaling(Convert::toBullet(mScale)); - - return shape; - } - - //------------------------------------------------------------------------------------------------ - btBoxShape* VertexIndexToShape::createBox() - { - const Ogre::Vector3 sz = getSize(); - - assert((sz.x > 0.0) && (sz.y > 0.0) && (sz.z > 0.0) && - ("Size of box must be greater than zero on all axes")); - - btBoxShape* shape = new btBoxShape(Convert::toBullet(sz * 0.5)); - - shape->setLocalScaling(Convert::toBullet(mScale)); - - return shape; - } - - //------------------------------------------------------------------------------------------------ - btCylinderShape* VertexIndexToShape::createCylinder() - { - const Ogre::Vector3 sz = getSize(); - - assert((sz.x > 0.0) && (sz.y > 0.0) && (sz.z > 0.0) && - ("Size of Cylinder must be greater than zero on all axes")); - - btCylinderShape* shape = new btCylinderShapeX(Convert::toBullet(sz * 0.5)); - - shape->setLocalScaling(Convert::toBullet(mScale)); - - return shape; - } - - //------------------------------------------------------------------------------------------------ - btConvexHullShape* VertexIndexToShape::createConvex() - { - assert(mVertexCount && (mIndexCount >= 6) && - ("Mesh must have some vertices and at least 6 indices (2 triangles)")); - - return new btConvexHullShape((btScalar*) &mVertexBuffer[0].x, mVertexCount, sizeof(Vector3)); - } - - //------------------------------------------------------------------------------------------------ - btBvhTriangleMeshShape* VertexIndexToShape::createTrimesh() - { - assert(mVertexCount && (mIndexCount >= 6) && - ("Mesh must have some vertices and at least 6 indices (2 triangles)")); - - unsigned int numFaces = mIndexCount / 3; - - btTriangleMesh *trimesh = new btTriangleMesh(); - unsigned int *indices = mIndexBuffer; - Vector3 *vertices = mVertexBuffer; - - btVector3 vertexPos[3]; - for (unsigned int n = 0; n < numFaces; ++n) - { - { - const Vector3 &vec = vertices[*indices]; - vertexPos[0][0] = vec.x; - vertexPos[0][1] = vec.y; - vertexPos[0][2] = vec.z; - } - { - const Vector3 &vec = vertices[*(indices + 1)]; - vertexPos[1][0] = vec.x; - vertexPos[1][1] = vec.y; - vertexPos[1][2] = vec.z; - } - { - const Vector3 &vec = vertices[*(indices + 2)]; - vertexPos[2][0] = vec.x; - vertexPos[2][1] = vec.y; - vertexPos[2][2] = vec.z; - } - - indices += 3; - - trimesh->addTriangle(vertexPos[0], vertexPos[1], vertexPos[2]); - } - - const bool useQuantizedAABB = true; - btBvhTriangleMeshShape *shape = new btBvhTriangleMeshShape(trimesh, useQuantizedAABB); - - shape->setLocalScaling(Convert::toBullet(mScale)); - - return shape; - } - - //------------------------------------------------------------------------------------------------ - VertexIndexToShape::~VertexIndexToShape() - { - delete[] mVertexBuffer; - delete[] mIndexBuffer; - - if (mBoneIndex) - { - for(BoneIndex::iterator i = mBoneIndex->begin(); - i != mBoneIndex->end(); - ++i) - { - delete i->second; - } - delete mBoneIndex; - } - } - - //------------------------------------------------------------------------------------------------ - VertexIndexToShape::VertexIndexToShape(const Matrix4 &transform) : - mVertexBuffer (0), - mIndexBuffer (0), - mVertexCount (0), - mIndexCount (0), - mTransform (transform), - mBoundRadius (-1), - mBounds (Vector3(-1,-1,-1)), - mBoneIndex (0), - mScale(1) - { - } - -/* - * ============================================================================================= - * BtOgre::StaticMeshToShapeConverter - * ============================================================================================= - */ - - StaticMeshToShapeConverter::StaticMeshToShapeConverter() : - VertexIndexToShape(), - mEntity (0), - mNode (0) - { - } - - //------------------------------------------------------------------------------------------------ - StaticMeshToShapeConverter::~StaticMeshToShapeConverter() - { - } - - //------------------------------------------------------------------------------------------------ - StaticMeshToShapeConverter::StaticMeshToShapeConverter(Entity *entity, const Matrix4 &transform) : - VertexIndexToShape(transform), - mEntity (0), - mNode (0) - { - addEntity(entity, transform); - } - - //------------------------------------------------------------------------------------------------ - StaticMeshToShapeConverter::StaticMeshToShapeConverter(Renderable *rend, const Matrix4 &transform) : - VertexIndexToShape(transform), - mEntity (0), - mNode (0) - { - RenderOperation op; - rend->getRenderOperation(op); - VertexIndexToShape::addStaticVertexData(op.vertexData); - if(op.useIndexes) - VertexIndexToShape::addIndexData(op.indexData); - - } - - //------------------------------------------------------------------------------------------------ - void StaticMeshToShapeConverter::addEntity(Entity *entity,const Matrix4 &transform) - { - // Each entity added need to reset size and radius - // next time getRadius and getSize are asked, they're computed. - mBounds = Ogre::Vector3(-1,-1,-1); - mBoundRadius = -1; - - mEntity = entity; - mNode = (SceneNode*)(mEntity->getParentNode()); - mTransform = transform; - mScale = mNode->getScale(); - - if (mEntity->getMesh()->sharedVertexData) - { - VertexIndexToShape::addStaticVertexData (mEntity->getMesh()->sharedVertexData); - } - - for (unsigned int i = 0;i < mEntity->getNumSubEntities();++i) - { - SubMesh *sub_mesh = mEntity->getSubEntity(i)->getSubMesh(); - - if (!sub_mesh->useSharedVertices) - { - VertexIndexToShape::addIndexData(sub_mesh->indexData, mVertexCount); - VertexIndexToShape::addStaticVertexData (sub_mesh->vertexData); - } - else - { - VertexIndexToShape::addIndexData (sub_mesh->indexData); - } - - } - } - - //------------------------------------------------------------------------------------------------ - void StaticMeshToShapeConverter::addMesh(const MeshPtr &mesh, const Matrix4 &transform) - { - // Each entity added need to reset size and radius - // next time getRadius and getSize are asked, they're computed. - mBounds = Ogre::Vector3(-1,-1,-1); - mBoundRadius = -1; - - //_entity = entity; - //_node = (SceneNode*)(_entity->getParentNode()); - mTransform = transform; - - if (mesh->hasSkeleton ()) - Ogre::LogManager::getSingleton().logMessage("MeshToShapeConverter::addMesh : Mesh " + mesh->getName () + " as skeleton but added to trimesh non animated"); - - if (mesh->sharedVertexData) - { - VertexIndexToShape::addStaticVertexData (mesh->sharedVertexData); - } - - for(unsigned int i = 0;i < mesh->getNumSubMeshes();++i) - { - SubMesh *sub_mesh = mesh->getSubMesh(i); - - if (!sub_mesh->useSharedVertices) - { - VertexIndexToShape::addIndexData(sub_mesh->indexData, mVertexCount); - VertexIndexToShape::addStaticVertexData (sub_mesh->vertexData); - } - else - { - VertexIndexToShape::addIndexData (sub_mesh->indexData); - } - - } - } - -/* - * ============================================================================================= - * BtOgre::AnimatedMeshToShapeConverter - * ============================================================================================= - */ - - AnimatedMeshToShapeConverter::AnimatedMeshToShapeConverter(Entity *entity,const Matrix4 &transform) : - VertexIndexToShape(transform), - mEntity (0), - mNode (0), - mTransformedVerticesTemp(0), - mTransformedVerticesTempSize(0) - { - addEntity(entity, transform); - } - - //------------------------------------------------------------------------------------------------ - AnimatedMeshToShapeConverter::AnimatedMeshToShapeConverter() : - VertexIndexToShape(), - mEntity (0), - mNode (0), - mTransformedVerticesTemp(0), - mTransformedVerticesTempSize(0) - { - } - - //------------------------------------------------------------------------------------------------ - AnimatedMeshToShapeConverter::~AnimatedMeshToShapeConverter() - { - delete[] mTransformedVerticesTemp; - } - - //------------------------------------------------------------------------------------------------ - void AnimatedMeshToShapeConverter::addEntity(Entity *entity,const Matrix4 &transform) - { - // Each entity added need to reset size and radius - // next time getRadius and getSize are asked, they're computed. - mBounds = Ogre::Vector3(-1,-1,-1); - mBoundRadius = -1; - - mEntity = entity; - mNode = (SceneNode*)(mEntity->getParentNode()); - mTransform = transform; - - assert (entity->getMesh()->hasSkeleton ()); - - mEntity->addSoftwareAnimationRequest(false); - mEntity->_updateAnimation(); - - if (mEntity->getMesh()->sharedVertexData) - { - VertexIndexToShape::addAnimatedVertexData (mEntity->getMesh()->sharedVertexData, - mEntity->_getSkelAnimVertexData(), - &mEntity->getMesh()->sharedBlendIndexToBoneIndexMap); - } - - for (unsigned int i = 0;i < mEntity->getNumSubEntities();++i) - { - SubMesh *sub_mesh = mEntity->getSubEntity(i)->getSubMesh(); - - if (!sub_mesh->useSharedVertices) - { - VertexIndexToShape::addIndexData(sub_mesh->indexData, mVertexCount); - - VertexIndexToShape::addAnimatedVertexData (sub_mesh->vertexData, - mEntity->getSubEntity(i)->_getSkelAnimVertexData(), - &sub_mesh->blendIndexToBoneIndexMap); - } - else - { - VertexIndexToShape::addIndexData (sub_mesh->indexData); - } - - } - - mEntity->removeSoftwareAnimationRequest(false); - } - - //------------------------------------------------------------------------------------------------ - void AnimatedMeshToShapeConverter::addMesh(const MeshPtr &mesh, const Matrix4 &transform) - { - // Each entity added need to reset size and radius - // next time getRadius and getSize are asked, they're computed. - mBounds = Ogre::Vector3(-1,-1,-1); - mBoundRadius = -1; - - //_entity = entity; - //_node = (SceneNode*)(_entity->getParentNode()); - mTransform = transform; - - assert (mesh->hasSkeleton ()); - - if (mesh->sharedVertexData) - { - VertexIndexToShape::addAnimatedVertexData (mesh->sharedVertexData, - 0, - &mesh->sharedBlendIndexToBoneIndexMap); - } - - for(unsigned int i = 0;i < mesh->getNumSubMeshes();++i) - { - SubMesh *sub_mesh = mesh->getSubMesh(i); - - if (!sub_mesh->useSharedVertices) - { - VertexIndexToShape::addIndexData(sub_mesh->indexData, mVertexCount); - - VertexIndexToShape::addAnimatedVertexData (sub_mesh->vertexData, - 0, - &sub_mesh->blendIndexToBoneIndexMap); - } - else - { - VertexIndexToShape::addIndexData (sub_mesh->indexData); - } - - } - } - - //------------------------------------------------------------------------------------------------ - bool AnimatedMeshToShapeConverter::getBoneVertices(unsigned char bone, - unsigned int &vertex_count, - Ogre::Vector3* &vertices, - const Vector3 &bonePosition) - { - BoneIndex::iterator i = mBoneIndex->find(bone); - - if (i == mBoneIndex->end()) - return false; - - if (i->second->empty()) - return false; - - vertex_count = (unsigned int) i->second->size() + 1; - if (vertex_count > mTransformedVerticesTempSize) - { - if (mTransformedVerticesTemp) - delete[] mTransformedVerticesTemp; - - mTransformedVerticesTemp = new Ogre::Vector3[vertex_count]; - - } - - vertices = mTransformedVerticesTemp; - vertices[0] = bonePosition; - //mEntity->_getParentNodeFullTransform() * - //mEntity->getSkeleton()->getBone(bone)->_getDerivedPosition(); - - //mEntity->getSkeleton()->getBone(bone)->_getDerivedOrientation() - unsigned int currBoneVertex = 1; - Vector3Array::iterator j = i->second->begin(); - while(j != i->second->end()) - { - vertices[currBoneVertex] = (*j); - ++j; - ++currBoneVertex; - } - return true; - } - - //------------------------------------------------------------------------------------------------ - btBoxShape* AnimatedMeshToShapeConverter::createAlignedBox(unsigned char bone, - const Vector3 &bonePosition, - const Quaternion &boneOrientation) - { - unsigned int vertex_count; - Vector3* vertices; - - if (!getBoneVertices(bone, vertex_count, vertices, bonePosition)) - return 0; - - Vector3 min_vec(vertices[0]); - Vector3 max_vec(vertices[0]); - - for(unsigned int j = 1; j < vertex_count ;j++) - { - min_vec.x = std::min(min_vec.x,vertices[j].x); - min_vec.y = std::min(min_vec.y,vertices[j].y); - min_vec.z = std::min(min_vec.z,vertices[j].z); - - max_vec.x = std::max(max_vec.x,vertices[j].x); - max_vec.y = std::max(max_vec.y,vertices[j].y); - max_vec.z = std::max(max_vec.z,vertices[j].z); - } - const Ogre::Vector3 maxMinusMin(max_vec - min_vec); - btBoxShape* box = new btBoxShape(Convert::toBullet(maxMinusMin)); - - /*const Ogre::Vector3 pos - (min_vec.x + (maxMinusMin.x * 0.5), - min_vec.y + (maxMinusMin.y * 0.5), - min_vec.z + (maxMinusMin.z * 0.5));*/ - - //box->setPosition(pos); - - return box; - } - - //------------------------------------------------------------------------------------------------ - bool AnimatedMeshToShapeConverter::getOrientedBox(unsigned char bone, - const Vector3 &bonePosition, - const Quaternion &boneOrientation, - Vector3 &box_afExtent, - Vector3 *box_akAxis, - Vector3 &box_kCenter) - { - unsigned int vertex_count; - Vector3* vertices; - - if (!getBoneVertices(bone, vertex_count, vertices, bonePosition)) - return false; - - box_kCenter = Vector3::ZERO; - - { - for(unsigned int c = 0 ;c < vertex_count;c++) - { - box_kCenter += vertices[c]; - } - const Ogre::Real invVertexCount = 1.0f / vertex_count; - box_kCenter *= invVertexCount; - } - Quaternion orient = boneOrientation; - orient.ToAxes(box_akAxis); - - // Let C be the box center and let U0, U1, and U2 be the box axes. Each - // input point is of the form X = C + y0*U0 + y1*U1 + y2*U2. The - // following code computes min(y0), max(y0), min(y1), max(y1), min(y2), - // and max(y2). The box center is then adjusted to be - // C' = C + 0.5*(min(y0)+max(y0))*U0 + 0.5*(min(y1)+max(y1))*U1 + - // 0.5*(min(y2)+max(y2))*U2 - - Ogre::Vector3 kDiff (vertices[1] - box_kCenter); - Ogre::Real fY0Min = kDiff.dotProduct(box_akAxis[0]), fY0Max = fY0Min; - Ogre::Real fY1Min = kDiff.dotProduct(box_akAxis[1]), fY1Max = fY1Min; - Ogre::Real fY2Min = kDiff.dotProduct(box_akAxis[2]), fY2Max = fY2Min; - - for (unsigned int i = 2; i < vertex_count; i++) - { - kDiff = vertices[i] - box_kCenter; - - const Ogre::Real fY0 = kDiff.dotProduct(box_akAxis[0]); - if ( fY0 < fY0Min ) - fY0Min = fY0; - else if ( fY0 > fY0Max ) - fY0Max = fY0; - - const Ogre::Real fY1 = kDiff.dotProduct(box_akAxis[1]); - if ( fY1 < fY1Min ) - fY1Min = fY1; - else if ( fY1 > fY1Max ) - fY1Max = fY1; - - const Ogre::Real fY2 = kDiff.dotProduct(box_akAxis[2]); - if ( fY2 < fY2Min ) - fY2Min = fY2; - else if ( fY2 > fY2Max ) - fY2Max = fY2; - } - - box_afExtent.x = ((Real)0.5)*(fY0Max - fY0Min); - box_afExtent.y = ((Real)0.5)*(fY1Max - fY1Min); - box_afExtent.z = ((Real)0.5)*(fY2Max - fY2Min); - - box_kCenter += (0.5f*(fY0Max+fY0Min))*box_akAxis[0] + - (0.5f*(fY1Max+fY1Min))*box_akAxis[1] + - (0.5f*(fY2Max+fY2Min))*box_akAxis[2]; - - box_afExtent *= 2.0; - - return true; - } - - //------------------------------------------------------------------------------------------------ - btBoxShape *AnimatedMeshToShapeConverter::createOrientedBox(unsigned char bone, - const Vector3 &bonePosition, - const Quaternion &boneOrientation) - { - Ogre::Vector3 box_akAxis[3]; - Ogre::Vector3 box_afExtent; - Ogre::Vector3 box_afCenter; - - if (!getOrientedBox(bone, bonePosition, boneOrientation, - box_afExtent, - box_akAxis, - box_afCenter)) - return 0; - - btBoxShape *geom = new btBoxShape(Convert::toBullet(box_afExtent)); - //geom->setOrientation(Quaternion(box_akAxis[0],box_akAxis[1],box_akAxis[2])); - //geom->setPosition(box_afCenter); - return geom; - } - -/* - * ============================================================================================= - * BtOgre::DynamicRenderable - * ============================================================================================= - */ - - DynamicRenderable::DynamicRenderable() - : mVertexBufferCapacity(0) - , mIndexBufferCapacity(0) - { - } - - //------------------------------------------------------------------------------------------------ - DynamicRenderable::~DynamicRenderable() - { - delete mRenderOp.vertexData; - delete mRenderOp.indexData; - } - - //------------------------------------------------------------------------------------------------ - void DynamicRenderable::initialize(RenderOperation::OperationType operationType, - bool useIndices) - { - // Initialize render operation - mRenderOp.operationType = operationType; - mRenderOp.useIndexes = useIndices; - mRenderOp.vertexData = new VertexData; - if (mRenderOp.useIndexes) - mRenderOp.indexData = new IndexData; - - // Reset buffer capacities - mVertexBufferCapacity = 0; - mIndexBufferCapacity = 0; - - // Create vertex declaration - createVertexDeclaration(); - } - - //------------------------------------------------------------------------------------------------ - void DynamicRenderable::prepareHardwareBuffers(size_t vertexCount, - size_t indexCount) - { - // Prepare vertex buffer - size_t newVertCapacity = mVertexBufferCapacity; - if ((vertexCount > mVertexBufferCapacity) || - (!mVertexBufferCapacity)) - { - // vertexCount exceeds current capacity! - // It is necessary to reallocate the buffer. - - // Check if this is the first call - if (!newVertCapacity) - newVertCapacity = 1; - - // Make capacity the next power of two - while (newVertCapacity < vertexCount) - newVertCapacity <<= 1; - } - else if (vertexCount < mVertexBufferCapacity>>1) { - // Make capacity the previous power of two - while (vertexCount < newVertCapacity>>1) - newVertCapacity >>= 1; - } - if (newVertCapacity != mVertexBufferCapacity) - { - mVertexBufferCapacity = newVertCapacity; - // Create new vertex buffer - HardwareVertexBufferSharedPtr vbuf = - HardwareBufferManager::getSingleton().createVertexBuffer( - mRenderOp.vertexData->vertexDeclaration->getVertexSize(0), - mVertexBufferCapacity, - HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY); // TODO: Custom HBU_? - - // Bind buffer - mRenderOp.vertexData->vertexBufferBinding->setBinding(0, vbuf); - } - // Update vertex count in the render operation - mRenderOp.vertexData->vertexCount = vertexCount; - - if (mRenderOp.useIndexes) - { - OgreAssert(indexCount <= std::numeric_limits::max(), "indexCount exceeds 16 bit"); - - size_t newIndexCapacity = mIndexBufferCapacity; - // Prepare index buffer - if ((indexCount > newIndexCapacity) || - (!newIndexCapacity)) - { - // indexCount exceeds current capacity! - // It is necessary to reallocate the buffer. - - // Check if this is the first call - if (!newIndexCapacity) - newIndexCapacity = 1; - - // Make capacity the next power of two - while (newIndexCapacity < indexCount) - newIndexCapacity <<= 1; - - } - else if (indexCount < newIndexCapacity>>1) - { - // Make capacity the previous power of two - while (indexCount < newIndexCapacity>>1) - newIndexCapacity >>= 1; - } - - if (newIndexCapacity != mIndexBufferCapacity) - { - mIndexBufferCapacity = newIndexCapacity; - // Create new index buffer - mRenderOp.indexData->indexBuffer = - HardwareBufferManager::getSingleton().createIndexBuffer( - HardwareIndexBuffer::IT_16BIT, - mIndexBufferCapacity, - HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY); // TODO: Custom HBU_? - } - - // Update index count in the render operation - mRenderOp.indexData->indexCount = indexCount; - } - } - - //------------------------------------------------------------------------------------------------ - Real DynamicRenderable::getBoundingRadius(void) const - { - return Math::Sqrt(std::max(mBox.getMaximum().squaredLength(), mBox.getMinimum().squaredLength())); - } - - //------------------------------------------------------------------------------------------------ - Real DynamicRenderable::getSquaredViewDepth(const Camera* cam) const - { - Vector3 vMin, vMax, vMid, vDist; - vMin = mBox.getMinimum(); - vMax = mBox.getMaximum(); - vMid = ((vMax - vMin) * 0.5) + vMin; - vDist = cam->getDerivedPosition() - vMid; - - return vDist.squaredLength(); - } - -/* - * ============================================================================================= - * BtOgre::DynamicLines - * ============================================================================================= - */ - - enum { - POSITION_BINDING, - TEXCOORD_BINDING - }; - - //------------------------------------------------------------------------------------------------ - DynamicLines::DynamicLines(OperationType opType) - { - initialize(opType,false); - setMaterial("BaseWhiteNoLighting"); - mDirty = true; - } - - //------------------------------------------------------------------------------------------------ - DynamicLines::~DynamicLines() - { - } - - //------------------------------------------------------------------------------------------------ - void DynamicLines::setOperationType(OperationType opType) - { - mRenderOp.operationType = opType; - } - - //------------------------------------------------------------------------------------------------ - RenderOperation::OperationType DynamicLines::getOperationType() const - { - return mRenderOp.operationType; - } - - //------------------------------------------------------------------------------------------------ - void DynamicLines::addPoint(const Vector3 &p) - { - mPoints.push_back(p); - mDirty = true; - } - - //------------------------------------------------------------------------------------------------ - void DynamicLines::addPoint(Real x, Real y, Real z) - { - mPoints.push_back(Vector3(x,y,z)); - mDirty = true; - } - - //------------------------------------------------------------------------------------------------ - const Vector3& DynamicLines::getPoint(unsigned short index) const - { - assert(index < mPoints.size() && "Point index is out of bounds!!"); - return mPoints[index]; - } - - //------------------------------------------------------------------------------------------------ - unsigned short DynamicLines::getNumPoints(void) const - { - return (unsigned short)mPoints.size(); - } - - //------------------------------------------------------------------------------------------------ - void DynamicLines::setPoint(unsigned short index, const Vector3 &value) - { - assert(index < mPoints.size() && "Point index is out of bounds!!"); - - mPoints[index] = value; - mDirty = true; - } - - //------------------------------------------------------------------------------------------------ - void DynamicLines::clear() - { - mPoints.clear(); - mDirty = true; - } - - //------------------------------------------------------------------------------------------------ - void DynamicLines::update() - { - if (mDirty) fillHardwareBuffers(); - } - - //------------------------------------------------------------------------------------------------ - void DynamicLines::createVertexDeclaration() - { - VertexDeclaration *decl = mRenderOp.vertexData->vertexDeclaration; - decl->addElement(POSITION_BINDING, 0, VET_FLOAT3, VES_POSITION); - } - - //------------------------------------------------------------------------------------------------ - void DynamicLines::fillHardwareBuffers() - { - int size = mPoints.size(); - - prepareHardwareBuffers(size,0); - - if (!size) { - mBox.setExtents(Vector3::ZERO,Vector3::ZERO); - mDirty=false; - return; - } - - Vector3 vaabMin = mPoints[0]; - Vector3 vaabMax = mPoints[0]; - - HardwareVertexBufferSharedPtr vbuf = - mRenderOp.vertexData->vertexBufferBinding->getBuffer(0); - - Real *prPos = static_cast(vbuf->lock(HardwareBuffer::HBL_DISCARD)); - { - for(int i = 0; i < size; i++) - { - *prPos++ = mPoints[i].x; - *prPos++ = mPoints[i].y; - *prPos++ = mPoints[i].z; - - if(mPoints[i].x < vaabMin.x) - vaabMin.x = mPoints[i].x; - if(mPoints[i].y < vaabMin.y) - vaabMin.y = mPoints[i].y; - if(mPoints[i].z < vaabMin.z) - vaabMin.z = mPoints[i].z; - - if(mPoints[i].x > vaabMax.x) - vaabMax.x = mPoints[i].x; - if(mPoints[i].y > vaabMax.y) - vaabMax.y = mPoints[i].y; - if(mPoints[i].z > vaabMax.z) - vaabMax.z = mPoints[i].z; - } - } - vbuf->unlock(); - - mBox.setExtents(vaabMin, vaabMax); - - mDirty = false; - } -} diff --git a/libs/openengine/bullet/BtOgreExtras.h b/libs/openengine/bullet/BtOgreExtras.h deleted file mode 100644 index f8c1fe41d..000000000 --- a/libs/openengine/bullet/BtOgreExtras.h +++ /dev/null @@ -1,284 +0,0 @@ -/* - * ===================================================================================== - * - * Filename: BtOgreExtras.h - * - * Description: Contains the Ogre Mesh to Bullet Shape converters. - * - * Version: 1.0 - * Created: 27/12/2008 01:45:56 PM - * - * Author: Nikhilesh (nikki) - * - * ===================================================================================== - */ - -#ifndef BtOgreShapes_H_ -#define BtOgreShapes_H_ - -#include "btBulletDynamicsCommon.h" -#include "OgreSimpleRenderable.h" -#include "OgreCamera.h" -#include "OgreHardwareBufferManager.h" -#include "OgreMaterialManager.h" -#include "OgreTechnique.h" -#include "OgrePass.h" - -#include "OgreLogManager.h" - -namespace BtOgre -{ - -typedef std::vector Vector3Array; - -//Converts from and to Bullet and Ogre stuff. Pretty self-explanatory. -class Convert -{ -public: - Convert() {}; - ~Convert() {}; - - static btQuaternion toBullet(const Ogre::Quaternion &q) - { - return btQuaternion(q.x, q.y, q.z, q.w); - } - static btVector3 toBullet(const Ogre::Vector3 &v) - { - return btVector3(v.x, v.y, v.z); - } - - static Ogre::Quaternion toOgre(const btQuaternion &q) - { - return Ogre::Quaternion(q.w(), q.x(), q.y(), q.z()); - } - static Ogre::Vector3 toOgre(const btVector3 &v) - { - return Ogre::Vector3(v.x(), v.y(), v.z()); - } -}; - -//From here on its debug-drawing stuff. ------------------------------------------------------------------ - -class DynamicRenderable : public Ogre::SimpleRenderable -{ -public: - /// Constructor - DynamicRenderable(); - /// Virtual destructor - virtual ~DynamicRenderable(); - - /** Initializes the dynamic renderable. - @remarks - This function should only be called once. It initializes the - render operation, and calls the abstract function - createVertexDeclaration(). - @param operationType The type of render operation to perform. - @param useIndices Specifies whether to use indices to determine the - vertices to use as input. */ - void initialize(Ogre::RenderOperation::OperationType operationType, - bool useIndices); - - /// Implementation of Ogre::SimpleRenderable - virtual Ogre::Real getBoundingRadius(void) const; - /// Implementation of Ogre::SimpleRenderable - virtual Ogre::Real getSquaredViewDepth(const Ogre::Camera* cam) const; - -protected: - /// Maximum capacity of the currently allocated vertex buffer. - size_t mVertexBufferCapacity; - /// Maximum capacity of the currently allocated index buffer. - size_t mIndexBufferCapacity; - - /** Creates the vertex declaration. - @remarks - Override and set mRenderOp.vertexData->vertexDeclaration here. - mRenderOp.vertexData will be created for you before this method - is called. */ - virtual void createVertexDeclaration() = 0; - - /** Prepares the hardware buffers for the requested vertex and index counts. - @remarks - This function must be called before locking the buffers in - fillHardwareBuffers(). It guarantees that the hardware buffers - are large enough to hold at least the requested number of - vertices and indices (if using indices). The buffers are - possibly reallocated to achieve this. - @par - The vertex and index count in the render operation are set to - the values of vertexCount and indexCount respectively. - @param vertexCount The number of vertices the buffer must hold. - - @param indexCount The number of indices the buffer must hold. This - parameter is ignored if not using indices. */ - void prepareHardwareBuffers(size_t vertexCount, size_t indexCount); - - /** Fills the hardware vertex and index buffers with data. - @remarks - This function must call prepareHardwareBuffers() before locking - the buffers to ensure the they are large enough for the data to - be written. Afterwards the vertex and index buffers (if using - indices) can be locked, and data can be written to them. */ - virtual void fillHardwareBuffers() = 0; -}; - -class DynamicLines : public DynamicRenderable -{ - typedef Ogre::Vector3 Vector3; - typedef Ogre::Quaternion Quaternion; - typedef Ogre::Camera Camera; - typedef Ogre::Real Real; - typedef Ogre::RenderOperation::OperationType OperationType; - -public: - /// Constructor - see setOperationType() for description of argument. - DynamicLines(OperationType opType=Ogre::RenderOperation::OT_LINE_STRIP); - virtual ~DynamicLines(); - - /// Add a point to the point list - void addPoint(const Ogre::Vector3 &p); - /// Add a point to the point list - void addPoint(Real x, Real y, Real z); - - /// Change the location of an existing point in the point list - void setPoint(unsigned short index, const Vector3 &value); - - /// Return the location of an existing point in the point list - const Vector3& getPoint(unsigned short index) const; - - /// Return the total number of points in the point list - unsigned short getNumPoints(void) const; - - /// Remove all points from the point list - void clear(); - - /// Call this to update the hardware buffer after making changes. - void update(); - - /** Set the type of operation to draw with. - * @param opType Can be one of - * - RenderOperation::OT_LINE_STRIP - * - RenderOperation::OT_LINE_LIST - * - RenderOperation::OT_POINT_LIST - * - RenderOperation::OT_TRIANGLE_LIST - * - RenderOperation::OT_TRIANGLE_STRIP - * - RenderOperation::OT_TRIANGLE_FAN - * The default is OT_LINE_STRIP. - */ - void setOperationType(OperationType opType); - OperationType getOperationType() const; - -protected: - /// Implementation DynamicRenderable, creates a simple vertex-only decl - virtual void createVertexDeclaration(); - /// Implementation DynamicRenderable, pushes point list out to hardware memory - virtual void fillHardwareBuffers(); - -private: - std::vector mPoints; - bool mDirty; -}; - -class DebugDrawer : public btIDebugDraw -{ -protected: - Ogre::SceneNode *mNode; - btDynamicsWorld *mWorld; - DynamicLines *mLineDrawer; - bool mDebugOn; - -public: - - DebugDrawer(Ogre::SceneNode *node, btDynamicsWorld *world) - : mNode(node), - mWorld(world), - mDebugOn(true) - { - mLineDrawer = new DynamicLines(Ogre::RenderOperation::OT_LINE_LIST); - mNode->attachObject(mLineDrawer); - - if (!Ogre::ResourceGroupManager::getSingleton().resourceGroupExists("BtOgre")) - Ogre::ResourceGroupManager::getSingleton().createResourceGroup("BtOgre"); - if (!Ogre::MaterialManager::getSingleton().resourceExists("BtOgre/DebugLines")) - { - Ogre::MaterialPtr mat = Ogre::MaterialManager::getSingleton().create("BtOgre/DebugLines", "BtOgre"); - mat->setReceiveShadows(false); - mat->setSelfIllumination(1,1,1); - } - - mLineDrawer->setMaterial("BtOgre/DebugLines"); - - //mLineDrawer->setVisibilityFlags (1024); - } - - ~DebugDrawer() - { - if (Ogre::MaterialManager::getSingleton().resourceExists("BtOgre/DebugLines")) - Ogre::MaterialManager::getSingleton().remove("BtOgre/DebugLines"); - if (Ogre::ResourceGroupManager::getSingleton().resourceGroupExists("BtOgre")) - Ogre::ResourceGroupManager::getSingleton().destroyResourceGroup("BtOgre"); - delete mLineDrawer; - } - - void step() - { - if (mDebugOn) - { - mWorld->debugDrawWorld(); - mLineDrawer->update(); - mNode->needUpdate(); - mLineDrawer->clear(); - } - else - { - mLineDrawer->clear(); - mLineDrawer->update(); - mNode->needUpdate(); - } - } - - void drawLine(const btVector3& from,const btVector3& to,const btVector3& color) - { - mLineDrawer->addPoint(Convert::toOgre(from)); - mLineDrawer->addPoint(Convert::toOgre(to)); - } - - void drawContactPoint(const btVector3& PointOnB,const btVector3& normalOnB,btScalar distance,int lifeTime,const btVector3& color) - { - mLineDrawer->addPoint(Convert::toOgre(PointOnB)); - mLineDrawer->addPoint(Convert::toOgre(PointOnB) + (Convert::toOgre(normalOnB) * distance * 20)); - } - - void reportErrorWarning(const char* warningString) - { - Ogre::LogManager::getSingleton().logMessage(warningString); - } - - void draw3dText(const btVector3& location,const char* textString) - { - } - - //0 for off, anything else for on. - void setDebugMode(int isOn) - { - mDebugOn = (isOn == 0) ? false : true; - - if (!mDebugOn) - mLineDrawer->clear(); - } - - //0 for off, anything else for on. - int getDebugMode() const - { - return mDebugOn; - } - -}; - -} - -#endif - - - - - diff --git a/libs/openengine/bullet/BtOgreGP.h b/libs/openengine/bullet/BtOgreGP.h deleted file mode 100644 index 7e497b535..000000000 --- a/libs/openengine/bullet/BtOgreGP.h +++ /dev/null @@ -1,144 +0,0 @@ -/* - * ===================================================================================== - * - * Filename: BtOgreGP.h - * - * Description: The part of BtOgre that handles information transfer from Ogre to - * Bullet (like mesh data for making trimeshes). - * - * Version: 1.0 - * Created: 27/12/2008 03:29:56 AM - * - * Author: Nikhilesh (nikki) - * - * ===================================================================================== - */ - -#ifndef BtOgrePG_H_ -#define BtOgrePG_H_ - -#include "btBulletDynamicsCommon.h" -#include "BtOgreExtras.h" - -#include -#include -#include - -namespace BtOgre { - -typedef std::map BoneIndex; - -class VertexIndexToShape -{ -public: - VertexIndexToShape(const Ogre::Matrix4 &transform = Ogre::Matrix4::IDENTITY); - ~VertexIndexToShape(); - - Ogre::Real getRadius(); - Ogre::Vector3 getSize(); - - - btSphereShape* createSphere(); - btBoxShape* createBox(); - btBvhTriangleMeshShape* createTrimesh(); - btCylinderShape* createCylinder(); - btConvexHullShape* createConvex(); - - const Ogre::Vector3* getVertices(); - unsigned int getVertexCount(); - const unsigned int* getIndices(); - unsigned int getIndexCount(); - -protected: - - void addStaticVertexData(const Ogre::VertexData *vertex_data); - - void addAnimatedVertexData(const Ogre::VertexData *vertex_data, - const Ogre::VertexData *blended_data, - const Ogre::Mesh::IndexMap *indexMap); - - void addIndexData(Ogre::IndexData *data, const unsigned int offset = 0); - - -protected: - Ogre::Vector3* mVertexBuffer; - unsigned int* mIndexBuffer; - unsigned int mVertexCount; - unsigned int mIndexCount; - - Ogre::Matrix4 mTransform; - - Ogre::Real mBoundRadius; - Ogre::Vector3 mBounds; - - BoneIndex *mBoneIndex; - - Ogre::Vector3 mScale; -}; - -//For static (non-animated) meshes. -class StaticMeshToShapeConverter : public VertexIndexToShape -{ -public: - - StaticMeshToShapeConverter(Ogre::Renderable *rend, const Ogre::Matrix4 &transform = Ogre::Matrix4::IDENTITY); - StaticMeshToShapeConverter(Ogre::Entity *entity, const Ogre::Matrix4 &transform = Ogre::Matrix4::IDENTITY); - StaticMeshToShapeConverter(); - - ~StaticMeshToShapeConverter(); - - void addEntity(Ogre::Entity *entity,const Ogre::Matrix4 &transform = Ogre::Matrix4::IDENTITY); - - void addMesh(const Ogre::MeshPtr &mesh, const Ogre::Matrix4 &transform = Ogre::Matrix4::IDENTITY); - - -protected: - - Ogre::Entity* mEntity; - Ogre::SceneNode* mNode; -}; - -//For animated meshes. -class AnimatedMeshToShapeConverter : public VertexIndexToShape -{ -public: - - AnimatedMeshToShapeConverter(Ogre::Entity *entity, const Ogre::Matrix4 &transform = Ogre::Matrix4::IDENTITY); - AnimatedMeshToShapeConverter(); - ~AnimatedMeshToShapeConverter(); - - void addEntity(Ogre::Entity *entity,const Ogre::Matrix4 &transform = Ogre::Matrix4::IDENTITY); - void addMesh(const Ogre::MeshPtr &mesh, const Ogre::Matrix4 &transform); - - btBoxShape* createAlignedBox(unsigned char bone, - const Ogre::Vector3 &bonePosition, - const Ogre::Quaternion &boneOrientation); - - btBoxShape* createOrientedBox(unsigned char bone, - const Ogre::Vector3 &bonePosition, - const Ogre::Quaternion &boneOrientation); - -protected: - - bool getBoneVertices(unsigned char bone, - unsigned int &vertex_count, - Ogre::Vector3* &vertices, - const Ogre::Vector3 &bonePosition); - - bool getOrientedBox(unsigned char bone, - const Ogre::Vector3 &bonePosition, - const Ogre::Quaternion &boneOrientation, - Ogre::Vector3 &extents, - Ogre::Vector3 *axis, - Ogre::Vector3 ¢er); - - Ogre::Entity* mEntity; - Ogre::SceneNode* mNode; - - Ogre::Vector3 *mTransformedVerticesTemp; - size_t mTransformedVerticesTempSize; -}; - -} - -#endif diff --git a/libs/openengine/bullet/BtOgrePG.h b/libs/openengine/bullet/BtOgrePG.h deleted file mode 100644 index 2e42fe1f9..000000000 --- a/libs/openengine/bullet/BtOgrePG.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * ===================================================================================== - * - * Filename: BtOgrePG.h - * - * Description: The part of BtOgre that handles information transfer from Bullet to - * Ogre (like updating graphics object positions). - * - * Version: 1.0 - * Created: 27/12/2008 03:40:56 AM - * - * Author: Nikhilesh (nikki) - * - * ===================================================================================== - */ - -#ifndef BtOgreGP_H_ -#define BtOgreGP_H_ - -#include "btBulletDynamicsCommon.h" -#include "OgreSceneNode.h" -#include "BtOgreExtras.h" - -namespace BtOgre { - -//A MotionState is Bullet's way of informing you about updates to an object. -//Pass this MotionState to a btRigidBody to have your SceneNode updated automaticaly. -class RigidBodyState : public btMotionState -{ - protected: - btTransform mTransform; - btTransform mCenterOfMassOffset; - - Ogre::SceneNode *mNode; - - public: - RigidBodyState(Ogre::SceneNode *node, const btTransform &transform, const btTransform &offset = btTransform::getIdentity()) - : mTransform(transform), - mCenterOfMassOffset(offset), - mNode(node) - { - } - - RigidBodyState(Ogre::SceneNode *node) - : mTransform(((node != NULL) ? BtOgre::Convert::toBullet(node->getOrientation()) : btQuaternion(0,0,0,1)), - ((node != NULL) ? BtOgre::Convert::toBullet(node->getPosition()) : btVector3(0,0,0))), - mCenterOfMassOffset(btTransform::getIdentity()), - mNode(node) - { - } - - virtual void getWorldTransform(btTransform &ret) const - { - ret = mCenterOfMassOffset.inverse() * mTransform; - } - - virtual void setWorldTransform(const btTransform &in) - { - if (mNode == NULL) - return; - - mTransform = in; - btTransform transform = in * mCenterOfMassOffset; - - btQuaternion rot = transform.getRotation(); - btVector3 pos = transform.getOrigin(); - mNode->setOrientation(rot.w(), rot.x(), rot.y(), rot.z()); - mNode->setPosition(pos.x(), pos.y(), pos.z()); - } - - void setNode(Ogre::SceneNode *node) - { - mNode = node; - } -}; - -//Softbody-Ogre connection goes here! - -} - -#endif diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index 35c767ca9..11b6b1834 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -12,10 +12,6 @@ #include #include -#include "BtOgrePG.h" -#include "BtOgreGP.h" -#include "BtOgreExtras.h" - namespace { @@ -90,7 +86,7 @@ namespace Physic mMeshOrientation = Ogre::Quaternion::IDENTITY; } */ - + /* // Use capsule shape only if base is square (nonuniform scaling apparently doesn't work on it) if (std::abs(mHalfExtents.x-mHalfExtents.y)= mHalfExtents.x) { @@ -99,6 +95,7 @@ namespace Physic } else mShape.reset(new btBoxShape(BtOgre::Convert::toBullet(mHalfExtents))); + */ mShape->setLocalScaling(btVector3(scale,scale,scale)); @@ -160,20 +157,20 @@ namespace Physic mPosition = position; - btTransform tr = mBody->getWorldTransform(); - Ogre::Quaternion meshrot = mMeshOrientation; - Ogre::Vector3 transrot = meshrot * (mMeshTranslation * mScale); - Ogre::Vector3 newPosition = transrot + position; + //btTransform tr = mBody->getWorldTransform(); + //Ogre::Quaternion meshrot = mMeshOrientation; + //Ogre::Vector3 transrot = meshrot * (mMeshTranslation * mScale); + //Ogre::Vector3 newPosition = transrot + position; - tr.setOrigin(BtOgre::Convert::toBullet(newPosition)); - mBody->setWorldTransform(tr); + //tr.setOrigin(BtOgre::Convert::toBullet(newPosition)); + //mBody->setWorldTransform(tr); } void PhysicActor::setRotation (const Ogre::Quaternion& rotation) { - btTransform tr = mBody->getWorldTransform(); - tr.setRotation(BtOgre::Convert::toBullet(mMeshOrientation * rotation)); - mBody->setWorldTransform(tr); + //btTransform tr = mBody->getWorldTransform(); + //tr.setRotation(BtOgre::Convert::toBullet(mMeshOrientation * rotation)); + //mBody->setWorldTransform(tr); } void PhysicActor::setScale(float scale) From 048d7be87c4a1555f27b08f4efa67722bfdcc56d Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 3 May 2015 16:35:10 +0200 Subject: [PATCH 1092/3725] Adjusted terminology for references/referenceables in OpenMW-CS user-interface (Fixes #2516) --- apps/opencs/model/tools/referencecheck.cpp | 2 +- apps/opencs/model/world/universalid.cpp | 8 ++++---- apps/opencs/view/doc/view.cpp | 4 ++-- apps/opencs/view/render/worldspacewidget.cpp | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/apps/opencs/model/tools/referencecheck.cpp b/apps/opencs/model/tools/referencecheck.cpp index 198c3627f..be9663e7a 100644 --- a/apps/opencs/model/tools/referencecheck.cpp +++ b/apps/opencs/model/tools/referencecheck.cpp @@ -28,7 +28,7 @@ void CSMTools::ReferenceCheckStage::perform(int stage, CSMDoc::Messages &message // Check for empty reference id if (cellRef.mRefID.empty()) { - messages.push_back(std::make_pair(id, " is an empty reference")); + messages.push_back(std::make_pair(id, " is an empty instance (not based on an object)")); } else { // Check for non existing referenced object if (mReferencables.searchId(cellRef.mRefID) == -1) { diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index fbc942f8e..e496fe79b 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -38,9 +38,9 @@ namespace { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Enchantments, "Enchantments", 0 }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_BodyParts, "Body Parts", 0 }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Referenceables, - "Referenceables", 0 }, + "Objects", 0 }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_References, - "References", 0 }, + "Instances", 0 }, { CSMWorld::UniversalId::Class_NonRecord, CSMWorld::UniversalId::Type_RegionMap, "Region Map", 0 }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Filters, "Filters", 0 }, @@ -79,7 +79,7 @@ namespace { CSMWorld::UniversalId::Class_SubRecord, CSMWorld::UniversalId::Type_JournalInfo, "JournalInfo", 0 }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Cell, "Cell", ":./cell.png" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Cell_Missing, "Cell", ":./cell.png" }, - { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Referenceable, "Referenceables", 0 }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Referenceable, "Object", 0 }, { CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Activator, "Activator", ":./activator.png" }, { CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Potion, "Potion", ":./potion.png" }, { CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Apparatus, "Apparatus", ":./apparatus.png" }, @@ -103,7 +103,7 @@ namespace { CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Repair, "Repair", ":./repair.png" }, { 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_Reference, "Instance", 0 }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Filter, "Filter", ":./filter.png" }, { CSMWorld::UniversalId::Class_Collection, CSMWorld::UniversalId::Type_Scene, "Scene", 0 }, { CSMWorld::UniversalId::Class_Collection, CSMWorld::UniversalId::Type_Preview, "Preview", 0 }, diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index e430bfa5e..5636fff94 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -131,11 +131,11 @@ void CSVDoc::View::setupWorldMenu() connect (cells, SIGNAL (triggered()), this, SLOT (addCellsSubView())); world->addAction (cells); - QAction *referenceables = new QAction (tr ("Referenceables"), this); + QAction *referenceables = new QAction (tr ("Objects"), this); connect (referenceables, SIGNAL (triggered()), this, SLOT (addReferenceablesSubView())); world->addAction (referenceables); - QAction *references = new QAction (tr ("References"), this); + QAction *references = new QAction (tr ("Instances"), this); connect (references, SIGNAL (triggered()), this, SLOT (addReferencesSubView())); world->addAction (references); diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 582ccea64..e3e5ce50e 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -258,7 +258,7 @@ unsigned int CSVRender::WorldspaceWidget::getInteractionMask() const void CSVRender::WorldspaceWidget::addVisibilitySelectorButtons ( CSVWidget::SceneToolToggle2 *tool) { - tool->addButton (Element_Reference, "References"); + tool->addButton (Element_Reference, "Instances"); tool->addButton (Element_Water, "Water"); tool->addButton (Element_Pathgrid, "Pathgrid"); } @@ -267,7 +267,7 @@ void CSVRender::WorldspaceWidget::addEditModeSelectorButtons (CSVWidget::SceneTo { /// \todo replace EditMode with suitable subclasses tool->addButton ( - new EditMode (this, QIcon (":placeholder"), Element_Reference, "Reference editing"), + new EditMode (this, QIcon (":placeholder"), Element_Reference, "Instance editing"), "object"); tool->addButton ( new EditMode (this, QIcon (":placeholder"), Element_Pathgrid, "Pathgrid editing"), From 351fd842fd497236d77d8096e6efb2a3867a76c9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 3 May 2015 16:58:05 +0200 Subject: [PATCH 1093/3725] Port loading screen --- apps/openmw/mwgui/loadingscreen.cpp | 114 +++++++++++-------------- apps/openmw/mwgui/loadingscreen.hpp | 30 ++++--- apps/openmw/mwgui/windowmanagerimp.cpp | 29 ++----- 3 files changed, 77 insertions(+), 96 deletions(-) diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index 7e88f2d97..01bd590a7 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -1,14 +1,6 @@ #include "loadingscreen.hpp" -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include #include #include @@ -18,6 +10,7 @@ #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -26,15 +19,17 @@ #include "../mwbase/windowmanager.hpp" #include "../mwbase/inputmanager.hpp" +#include "../mwrender/vismask.hpp" + #include "backgroundimage.hpp" namespace MWGui { - LoadingScreen::LoadingScreen(Ogre::SceneManager* sceneMgr, Ogre::RenderWindow* rw) - : mSceneMgr(sceneMgr) - , mWindow(rw) - , WindowBase("openmw_loading_screen.layout") + LoadingScreen::LoadingScreen(const VFS::Manager* vfs, osgViewer::Viewer* viewer) + : WindowBase("openmw_loading_screen.layout") + , mVFS(vfs) + , mViewer(viewer) , mLastRenderTime(0) , mLastWallpaperChangeTime(0) , mProgress(0) @@ -52,6 +47,32 @@ namespace MWGui MyGUI::Align::Stretch, "Menu"); setVisible(false); + + findSplashScreens(); + } + + void LoadingScreen::findSplashScreens() + { + const std::map& index = mVFS->getIndex(); + std::string pattern = "Splash/"; + mVFS->normalizeFilename(pattern); + + std::map::const_iterator found = index.lower_bound(pattern); + while (found != index.end()) + { + const std::string& name = found->first; + if (name.size() >= pattern.size() && name.substr(0, pattern.size()) == pattern) + { + size_t pos = name.find_last_of('.'); + if (pos != std::string::npos && name.compare(pos, name.size()-pos, ".tga") == 0) + mSplashScreens.push_back(found->first); + } + else + break; + ++found; + } + if (mSplashScreens.empty()) + std::cerr << "No splash screens found!" << std::endl; } void LoadingScreen::setLabel(const std::string &label) @@ -80,17 +101,13 @@ namespace MWGui if (mMainWidget->getVisible()) return; - // Temporarily turn off VSync, we want to do actual loading rather than waiting for the screen to sync. - // Threaded loading would be even better, of course - especially because some drivers force VSync to on and we can't change it. - mVSyncWasEnabled = mWindow->isVSyncEnabled(); - mWindow->setVSyncEnabled(false); - bool showWallpaper = (MWBase::Environment::get().getStateManager()->getState() == MWBase::StateManager::State_NoGame); - if (!showWallpaper) { + // TODO + /* mBackgroundImage->setImageTexture(""); int width = mWindow->getWidth(); int height = mWindow->getHeight(); @@ -111,6 +128,7 @@ namespace MWGui mWindow->copyContentsToMemory(texture->getBuffer()->lock(Ogre::Image::Box(0,0,width,height), Ogre::HardwareBuffer::HBL_DISCARD)); texture->getBuffer()->unlock(); mBackgroundImage->setBackgroundImage(texture->getName(), false, false); + */ } setVisible(true); @@ -125,9 +143,6 @@ namespace MWGui void LoadingScreen::loadingOff() { - // Re-enable vsync now. - mWindow->setVSyncEnabled(mVSyncWasEnabled); - setVisible(false); MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Loading); @@ -136,29 +151,15 @@ namespace MWGui void LoadingScreen::changeWallpaper () { - if (mResources.empty()) + if (!mSplashScreens.empty()) { - Ogre::StringVector groups = Ogre::ResourceGroupManager::getSingleton().getResourceGroups (); - for (Ogre::StringVector::iterator it = groups.begin(); it != groups.end(); ++it) - { - Ogre::StringVectorPtr resourcesInThisGroup = Ogre::ResourceGroupManager::getSingleton ().findResourceNames (*it, "Splash/*.tga"); - mResources.insert(mResources.end(), resourcesInThisGroup->begin(), resourcesInThisGroup->end()); - } - } - - if (!mResources.empty()) - { - std::string const & randomSplash = mResources.at(Misc::Rng::rollDice(mResources.size())); - - Ogre::TextureManager::getSingleton ().load (randomSplash, Ogre::ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME); + std::string const & randomSplash = mSplashScreens.at(Misc::Rng::rollDice(mSplashScreens.size())); // TODO: add option (filename pattern?) to use image aspect ratio instead of 4:3 // we can't do this by default, because the Morrowind splash screens are 1024x1024, but should be displayed as 4:3 bool stretch = Settings::Manager::getBool("stretch menu background", "GUI"); mBackgroundImage->setBackgroundImage(randomSplash, true, stretch); } - else - std::cerr << "No loading screens found!" << std::endl; } void LoadingScreen::setProgressRange (size_t range) @@ -190,7 +191,7 @@ namespace MWGui void LoadingScreen::indicateProgress() { - float time = (mTimer.getMilliseconds() % 2001) / 1000.f; + float time = (static_cast(mTimer.time_m()) % 2001) / 1000.f; if (time > 1) time = (time-2)*-1; @@ -203,43 +204,32 @@ namespace MWGui { const float loadingScreenFps = 20.f; - if (mTimer.getMilliseconds () > mLastRenderTime + (1.f/loadingScreenFps) * 1000.f) + if (mTimer.time_m() > mLastRenderTime + (1.f/loadingScreenFps) * 1000.f) { - mLastRenderTime = mTimer.getMilliseconds (); + mLastRenderTime = mTimer.time_m(); bool showWallpaper = (MWBase::Environment::get().getStateManager()->getState() == MWBase::StateManager::State_NoGame); - if (showWallpaper && mTimer.getMilliseconds () > mLastWallpaperChangeTime + 5000*1) + if (showWallpaper && mTimer.time_m() > mLastWallpaperChangeTime + 5000*1) { - mLastWallpaperChangeTime = mTimer.getMilliseconds (); + mLastWallpaperChangeTime = mTimer.time_m(); 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, true); + int oldUpdateMask = mViewer->getUpdateVisitor()->getTraversalMask(); + int oldCullMask = mViewer->getCamera()->getCullMask(); + mViewer->getUpdateVisitor()->setTraversalMask(MWRender::Mask_GUI); + mViewer->getCamera()->setCullMask(MWRender::Mask_GUI); - // 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(); + //MWBase::Environment::get().getInputManager()->update(0, true, true); - mWindow->update(false); + mViewer->frame(); // resume 3d rendering - mSceneMgr->clearSpecialCaseRenderQueues(); - mSceneMgr->setSpecialCaseRenderQueueMode(Ogre::SceneManager::SCRQM_EXCLUDE); + mViewer->getUpdateVisitor()->setTraversalMask(oldUpdateMask); + mViewer->getCamera()->setCullMask(oldCullMask); } } } diff --git a/apps/openmw/mwgui/loadingscreen.hpp b/apps/openmw/mwgui/loadingscreen.hpp index 0d3ffbbec..46bbb00cc 100644 --- a/apps/openmw/mwgui/loadingscreen.hpp +++ b/apps/openmw/mwgui/loadingscreen.hpp @@ -1,16 +1,20 @@ #ifndef MWGUI_LOADINGSCREEN_H #define MWGUI_LOADINGSCREEN_H -#include -#include +#include +#include #include "windowbase.hpp" #include -namespace Ogre +namespace osgViewer { - class SceneManager; + class Viewer; +} +namespace VFS +{ + class Manager; } namespace MWGui @@ -20,6 +24,9 @@ namespace MWGui class LoadingScreen : public WindowBase, public Loading::Listener { public: + LoadingScreen(const VFS::Manager* vfs, osgViewer::Viewer* viewer); + virtual ~LoadingScreen(); + virtual void setLabel (const std::string& label); /// Indicate that some progress has been made, without specifying how much @@ -34,21 +41,18 @@ namespace MWGui virtual void setVisible(bool visible); - LoadingScreen(Ogre::SceneManager* sceneMgr, Ogre::RenderWindow* rw); - virtual ~LoadingScreen(); - void setLoadingProgress (const std::string& stage, int depth, int current, int total); void loadingDone(); - void updateWindow(Ogre::RenderWindow* rw) { mWindow = rw; } - private: - Ogre::SceneManager* mSceneMgr; - Ogre::RenderWindow* mWindow; + void findSplashScreens(); + + const VFS::Manager* mVFS; + osg::ref_ptr mViewer; unsigned long mLastWallpaperChangeTime; unsigned long mLastRenderTime; - Ogre::Timer mTimer; + osg::Timer mTimer; size_t mProgress; @@ -58,7 +62,7 @@ namespace MWGui MyGUI::ScrollBar* mProgressBar; BackgroundImage* mBackgroundImage; - Ogre::StringVector mResources; + std::vector mSplashScreens; bool mVSyncWasEnabled; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 9d9ba329b..575d7045a 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -213,9 +213,9 @@ namespace MWGui MyGUI::FactoryManager::getInstance().registerFactory("Resource", "ResourceImageSetPointer"); MyGUI::ResourceManager::getInstance().load("core.xml"); -#if 0 - mLoadingScreen = new LoadingScreen(mRendering->getScene (), mRendering->getWindow ()); -#endif + + mLoadingScreen = new LoadingScreen(mResourceSystem->getVFS(), mViewer); + //set up the hardware cursor manager //mCursorManager = new SFO::SDLCursorManager(); @@ -1173,8 +1173,8 @@ namespace MWGui if (!mGuiModes.empty()) mGuiModes.pop_back(); - bool gameMode = !isGuiMode(); - MWBase::Environment::get().getInputManager()->changeInputMode(!gameMode); + //bool gameMode = !isGuiMode(); + //MWBase::Environment::get().getInputManager()->changeInputMode(!gameMode); updateVisible(); } @@ -1190,8 +1190,8 @@ namespace MWGui ++it; } - bool gameMode = !isGuiMode(); - MWBase::Environment::get().getInputManager()->changeInputMode(!gameMode); + //bool gameMode = !isGuiMode(); + //MWBase::Environment::get().getInputManager()->changeInputMode(!gameMode); updateVisible(); } @@ -1541,22 +1541,9 @@ namespace MWGui mHud->setEnemy(enemy); } - class DummyListener : public Loading::Listener - { - public: - virtual void setLabel (const std::string& label){} - virtual void loadingOn(){} - virtual void loadingOff(){} - virtual void indicateProgress (){} - virtual void setProgressRange (size_t range){} - virtual void setProgress (size_t value){} - virtual void increaseProgress (size_t increase = 1){} - }; - Loading::Listener* WindowManager::getLoadingScreen() { - static DummyListener listener; - return &listener; + return mLoadingScreen; } void WindowManager::startRecharge(MWWorld::Ptr soulgem) From 31ead3a9f463ac24155711fbbddc921dc0c06bb3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 3 May 2015 17:04:21 +0200 Subject: [PATCH 1094/3725] Increase loading screen FPS Now that it's rendered in a background thread, we can have a smooth loading bar at virtually no performance cost. --- apps/openmw/mwgui/loadingscreen.cpp | 10 +++++----- apps/openmw/mwgui/loadingscreen.hpp | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index 01bd590a7..3b13ed5a9 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -30,8 +30,8 @@ namespace MWGui : WindowBase("openmw_loading_screen.layout") , mVFS(vfs) , mViewer(viewer) - , mLastRenderTime(0) - , mLastWallpaperChangeTime(0) + , mLastRenderTime(0.0) + , mLastWallpaperChangeTime(0.0) , mProgress(0) , mVSyncWasEnabled(false) { @@ -202,12 +202,10 @@ namespace MWGui void LoadingScreen::draw() { - const float loadingScreenFps = 20.f; + const float loadingScreenFps = 120.f; if (mTimer.time_m() > mLastRenderTime + (1.f/loadingScreenFps) * 1000.f) { - mLastRenderTime = mTimer.time_m(); - bool showWallpaper = (MWBase::Environment::get().getStateManager()->getState() == MWBase::StateManager::State_NoGame); @@ -230,6 +228,8 @@ namespace MWGui // resume 3d rendering mViewer->getUpdateVisitor()->setTraversalMask(oldUpdateMask); mViewer->getCamera()->setCullMask(oldCullMask); + + mLastRenderTime = mTimer.time_m(); } } } diff --git a/apps/openmw/mwgui/loadingscreen.hpp b/apps/openmw/mwgui/loadingscreen.hpp index 46bbb00cc..4c9d45f66 100644 --- a/apps/openmw/mwgui/loadingscreen.hpp +++ b/apps/openmw/mwgui/loadingscreen.hpp @@ -50,8 +50,8 @@ namespace MWGui const VFS::Manager* mVFS; osg::ref_ptr mViewer; - unsigned long mLastWallpaperChangeTime; - unsigned long mLastRenderTime; + double mLastWallpaperChangeTime; + double mLastRenderTime; osg::Timer mTimer; size_t mProgress; From 140e67036c3beef4fb85e27f20e24c4f0471d195 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 3 May 2015 17:10:50 +0200 Subject: [PATCH 1095/3725] Flip non-dds textures vertically Fixes the up-side down loading screens. --- components/resource/texturemanager.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/components/resource/texturemanager.cpp b/components/resource/texturemanager.cpp index 939f81d9b..ee75296a7 100644 --- a/components/resource/texturemanager.cpp +++ b/components/resource/texturemanager.cpp @@ -92,6 +92,15 @@ namespace Resource } osg::Image* image = result.getImage(); + + // We need to flip images, because the Morrowind texture coordinates use the DirectX convention (top-left image origin), + // but OpenGL uses bottom left as the image origin. + // For some reason this doesn't concern DDS textures, which are already flipped when loaded. + if (ext != "dds") + { + image->flipVertical(); + } + osg::ref_ptr texture(new osg::Texture2D); texture->setImage(image); texture->setWrap(osg::Texture::WRAP_S, wrapS); From 283b252142085fdb0c9f780e810fc7c650e4bc9c Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 3 May 2015 17:24:35 +0200 Subject: [PATCH 1096/3725] Stub InputManager --- apps/openmw/CMakeLists.txt | 10 ++-- apps/openmw/engine.cpp | 13 ++--- apps/openmw/mwgui/loadingscreen.cpp | 2 +- apps/openmw/mwgui/windowmanagerimp.cpp | 18 +++---- apps/openmw/mwinput/inputmanagerimp.cpp | 53 +++++++++++---------- apps/openmw/mwinput/inputmanagerimp.hpp | 3 +- apps/openmw/mwrender/activatoranimation.cpp | 51 -------------------- apps/openmw/mwrender/activatoranimation.hpp | 24 ---------- apps/openmw/mwscript/interpretercontext.cpp | 2 - 9 files changed, 51 insertions(+), 125 deletions(-) delete mode 100644 apps/openmw/mwrender/activatoranimation.cpp delete mode 100644 apps/openmw/mwrender/activatoranimation.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 81cecc2c8..4a93daec7 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -23,15 +23,15 @@ add_openmw_dir (mwrender actors objects renderingmanager animation sky npcanimation vismask creatureanimation effectmanager util renderinginterface debugging rendermode bulletdebugdraw -# camera activatoranimation +# camera # localmap occlusionquery water shadows # characterpreview globalmap ripplesimulation refraction -# terrainstorage renderconst weaponanimation +# terrainstorage weaponanimation ) -#add_openmw_dir (mwinput -# inputmanagerimp -# ) +add_openmw_dir (mwinput + inputmanagerimp + ) add_openmw_dir (mwgui layout textinput widgets race class birth review windowmanagerimp console dialogue diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 15fee0cb1..5be9317eb 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -28,7 +28,7 @@ #include -//#include "mwinput/inputmanagerimp.hpp" +#include "mwinput/inputmanagerimp.hpp" #include "mwgui/windowmanagerimp.hpp" @@ -79,7 +79,7 @@ void OMW::Engine::frame(float frametime) mEnvironment.setFrameDuration (frametime); // update input - //MWBase::Environment::get().getInputManager()->update(frametime, false); + MWBase::Environment::get().getInputManager()->update(frametime, false); // When the window is minimized, pause everything. Currently this *has* to be here to work around a MyGUI bug. // If we are not currently rendering, then RenderItems will not be reused resulting in a memory leak upon changing widget textures. @@ -335,8 +335,9 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) else gameControllerdb = ""; //if it doesn't exist, pass in an empty string - //MWInput::InputManager* input = new MWInput::InputManager (*mOgre, *this, keybinderUser, keybinderUserExists, gameControllerdb, mGrab); - //mEnvironment.setInputManager (input); + // FIXME: shouldn't depend on Engine + MWInput::InputManager* input = new MWInput::InputManager (*this, keybinderUser, keybinderUserExists, gameControllerdb, mGrab); + mEnvironment.setInputManager (input); std::string myguiResources = (mResDir / "mygui").string(); osg::ref_ptr guiRoot = new osg::Group; @@ -354,7 +355,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) { std::string logo = mFallbackMap["Movies_Company_Logo"]; if (!logo.empty()) - window->playVideo(logo, 1); + window->playVideo(logo, true); } // Create the world @@ -362,7 +363,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) mFileCollections, mContentFiles, mEncoder, mFallbackMap, mActivationDistanceOverride, mCellName, mStartupScript)); MWBase::Environment::get().getWorld()->setupPlayer(); - //input->setPlayer(&mEnvironment.getWorld()->getPlayer()); + input->setPlayer(&mEnvironment.getWorld()->getPlayer()); window->initUI(); window->renderWorldMap(); diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index 3b13ed5a9..a7791d838 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -221,7 +221,7 @@ namespace MWGui mViewer->getUpdateVisitor()->setTraversalMask(MWRender::Mask_GUI); mViewer->getCamera()->setCullMask(MWRender::Mask_GUI); - //MWBase::Environment::get().getInputManager()->update(0, true, true); + MWBase::Environment::get().getInputManager()->update(0, true, true); mViewer->frame(); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 575d7045a..ebca96b19 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -334,7 +334,7 @@ namespace MWGui // Set up visibility updateVisible(); - //MWBase::Environment::get().getInputManager()->changeInputMode(false); + MWBase::Environment::get().getInputManager()->changeInputMode(false); } void WindowManager::renderWorldMap() @@ -834,7 +834,7 @@ namespace MWGui mMessageBoxManager->onFrame(0.f); MWBase::Environment::get().getInputManager()->update(0, true, false); - //mRendering->getWindow()->update(); + mViewer->frame(); } } } @@ -1132,8 +1132,8 @@ namespace MWGui mGuiModes.push_back(mode); - //bool gameMode = !isGuiMode(); - //MWBase::Environment::get().getInputManager()->changeInputMode(!gameMode); + bool gameMode = !isGuiMode(); + MWBase::Environment::get().getInputManager()->changeInputMode(!gameMode); updateVisible(); } @@ -1173,8 +1173,8 @@ namespace MWGui if (!mGuiModes.empty()) mGuiModes.pop_back(); - //bool gameMode = !isGuiMode(); - //MWBase::Environment::get().getInputManager()->changeInputMode(!gameMode); + bool gameMode = !isGuiMode(); + MWBase::Environment::get().getInputManager()->changeInputMode(!gameMode); updateVisible(); } @@ -1190,8 +1190,8 @@ namespace MWGui ++it; } - //bool gameMode = !isGuiMode(); - //MWBase::Environment::get().getInputManager()->changeInputMode(!gameMode); + bool gameMode = !isGuiMode(); + MWBase::Environment::get().getInputManager()->changeInputMode(!gameMode); updateVisible(); } @@ -1705,7 +1705,7 @@ namespace MWGui while (mVideoWidget->update() && !MWBase::Environment::get().getStateManager()->hasQuitRequest()) { - //MWBase::Environment::get().getInputManager()->update(0, true, false); + MWBase::Environment::get().getInputManager()->update(0, true, false); mViewer->frame(); } diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 88d891a02..442a5e8b2 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -14,8 +14,6 @@ #include -#include - #include "../engine.hpp" #include "../mwbase/world.hpp" @@ -98,16 +96,16 @@ namespace namespace MWInput { - InputManager::InputManager(OEngine::Render::OgreRenderer &ogre, + InputManager::InputManager( OMW::Engine& engine, const std::string& userFile, bool userFileExists, const std::string& controllerBindingsFile, bool grab) - : mOgre(ogre) + : mInputManager(NULL) , mPlayer(NULL) , mEngine(engine) , mMouseLookEnabled(false) - , mMouseX(ogre.getWindow()->getWidth ()/2.f) - , mMouseY(ogre.getWindow()->getHeight ()/2.f) + , mMouseX(0)//ogre.getWindow()->getWidth ()/2.f) + , mMouseY(0)//ogre.getWindow()->getHeight ()/2.f) , mMouseWheel(0) , mDragDrop(false) , mGuiCursorEnabled(true) @@ -131,17 +129,18 @@ namespace MWInput , mFakeDeviceID(1) { + /* Ogre::RenderWindow* window = ogre.getWindow (); - mInputManager = new SFO::InputWrapper(mOgre.getSDLWindow(), mOgre.getWindow(), grab); mInputManager->setMouseEventCallback (this); mInputManager->setKeyboardEventCallback (this); mInputManager->setWindowEventCallback(this); mInputManager->setControllerEventCallback(this); + */ std::string file = userFileExists ? userFile : ""; mInputBinder = new ICS::InputControlSystem(file, true, this, NULL, A_Last); - adjustMouseRegion (window->getWidth(), window->getHeight()); + //adjustMouseRegion (window->getWidth(), window->getHeight()); loadKeyDefaults(); loadControllerDefaults(); @@ -199,7 +198,7 @@ namespace MWInput delete mInputBinder; - delete mInputManager; + //delete mInputManager; } void InputManager::setPlayerControlsEnabled(bool enabled) @@ -366,24 +365,24 @@ namespace MWInput void InputManager::updateCursorMode() { - bool grab = !MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_MainMenu) - && MWBase::Environment::get().getWindowManager()->getMode() != MWGui::GM_Console; + //bool grab = !MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_MainMenu) + // && MWBase::Environment::get().getWindowManager()->getMode() != MWGui::GM_Console; - bool was_relative = mInputManager->getMouseRelative(); + bool was_relative = 0;//mInputManager->getMouseRelative(); 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 - mInputManager->setMouseRelative(is_relative); + //mInputManager->setMouseRelative(is_relative); //we let the mouse escape in the main menu - mInputManager->setGrabPointer(grab && (mGrabCursor || is_relative)); + //mInputManager->setGrabPointer(grab && (mGrabCursor || is_relative)); //we switched to non-relative mode, move our cursor to where the in-game //cursor is if( !is_relative && was_relative != is_relative ) { - mInputManager->warpMouse(static_cast(mMouseX), static_cast(mMouseY)); + //mInputManager->warpMouse(static_cast(mMouseX), static_cast(mMouseY)); } } @@ -391,9 +390,9 @@ namespace MWInput { mControlsDisabled = disableControls; - mInputManager->setMouseVisible(MWBase::Environment::get().getWindowManager()->getCursorVisible()); + //mInputManager->setMouseVisible(MWBase::Environment::get().getWindowManager()->getCursorVisible()); - mInputManager->capture(disableEvents); + //mInputManager->capture(disableEvents); // inject some fake mouse movement to force updating MyGUI's widget states MyGUI::InputManager::getInstance().injectMouseMove( int(mMouseX), int(mMouseY), mMouseWheel); @@ -427,7 +426,7 @@ namespace MWInput mMouseY = std::max(0.f, std::min(mMouseY, float(viewSize.height))); MyGUI::InputManager::getInstance().injectMouseMove(static_cast(mMouseX), static_cast(mMouseY), mMouseWheel); - mInputManager->warpMouse(static_cast(mMouseX), static_cast(mMouseY)); + //mInputManager->warpMouse(static_cast(mMouseX), static_cast(mMouseY)); } if (mMouseLookEnabled) { @@ -668,6 +667,7 @@ namespace MWInput // HACK: to make Morrowind's default keybinding for the console work without printing an extra "^" upon closing // This assumes that SDL_TextInput events always come *after* the key event // (which is somewhat reasonable, and hopefully true for all SDL platforms) + /* OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(arg.keysym.sym); if (mInputBinder->getKeyBinding(mInputBinder->getControl(A_Console), ICS::Control::INCREASE) == arg.keysym.scancode @@ -685,6 +685,7 @@ namespace MWInput if (!mControlsDisabled && !consumed) mInputBinder->keyPressed (arg); mJoystickLastUsed = false; + */ } void InputManager::textInput(const SDL_TextInputEvent &arg) @@ -697,11 +698,13 @@ namespace MWInput void InputManager::keyReleased(const SDL_KeyboardEvent &arg ) { + /* mJoystickLastUsed = false; OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(arg.keysym.sym); setPlayerControlsEnabled(!MyGUI::InputManager::getInstance().injectKeyRelease(MyGUI::KeyCode::Enum(kc))); mInputBinder->keyReleased (arg); + */ } void InputManager::mousePressed( const SDL_MouseButtonEvent &arg, Uint8 id ) @@ -827,9 +830,9 @@ namespace MWInput setPlayerControlsEnabled(!guiMode); //esc, to leave initial movie screen - OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(SDLK_ESCAPE); - bool guiFocus = MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::Enum(kc), 0); - setPlayerControlsEnabled(!guiFocus); + //OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(SDLK_ESCAPE); + //bool guiFocus = MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::Enum(kc), 0); + //setPlayerControlsEnabled(!guiFocus); if (!mControlsDisabled) mInputBinder->buttonPressed(deviceID, arg); @@ -853,9 +856,9 @@ namespace MWInput else mInputBinder->buttonReleased(deviceID, arg); - //to escape initial movie - OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(SDLK_ESCAPE); - setPlayerControlsEnabled(!MyGUI::InputManager::getInstance().injectKeyRelease(MyGUI::KeyCode::Enum(kc))); + ///to escape initial movie + //OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(SDLK_ESCAPE); + //setPlayerControlsEnabled(!MyGUI::InputManager::getInstance().injectKeyRelease(MyGUI::KeyCode::Enum(kc))); } void InputManager::axisMoved(int deviceID, const SDL_ControllerAxisEvent &arg ) @@ -885,7 +888,7 @@ namespace MWInput void InputManager::windowResized(int x, int y) { - mOgre.windowResized(x,y); + //mOgre.windowResized(x,y); } void InputManager::windowClosed() diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 558801023..26a1fcb21 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -66,7 +66,7 @@ namespace MWInput public ICS::DetectingBindingListener { public: - InputManager(OEngine::Render::OgreRenderer &_ogre, + InputManager( OMW::Engine& engine, const std::string& userFile, bool userFileExists, const std::string& controllerBindingsFile, bool grab); @@ -143,7 +143,6 @@ namespace MWInput private: bool mJoystickLastUsed; - OEngine::Render::OgreRenderer &mOgre; MWWorld::Player* mPlayer; OMW::Engine& mEngine; diff --git a/apps/openmw/mwrender/activatoranimation.cpp b/apps/openmw/mwrender/activatoranimation.cpp deleted file mode 100644 index 1ef68f619..000000000 --- a/apps/openmw/mwrender/activatoranimation.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include "activatoranimation.hpp" - -#include -#include - -#include - -#include "renderconst.hpp" - -namespace MWRender -{ - -ActivatorAnimation::~ActivatorAnimation() -{ -} - -ActivatorAnimation::ActivatorAnimation(const MWWorld::Ptr &ptr, const std::string& model) - : Animation(ptr, ptr.getRefData().getBaseNode()) -{ - if(!model.empty()) - { - setObjectRoot(model, false); - setRenderProperties(mObjectRoot, RV_Misc, RQG_Main, RQG_Alpha); - - addAnimSource(model); - } - else - { - // No model given. Create an object root anyway, so that lights can be added to it if needed. - mObjectRoot = NifOgre::ObjectScenePtr (new NifOgre::ObjectScene(mInsert->getCreator())); - } -} - -void ActivatorAnimation::addLight(const ESM::Light *light) -{ - addExtraLight(mInsert->getCreator(), mObjectRoot, light); -} - -void ActivatorAnimation::removeParticles() -{ - for (unsigned int i=0; imParticles.size(); ++i) - { - // Don't destroyParticleSystem, the ParticleSystemController is still holding a pointer to it. - // Don't setVisible, this could conflict with a VisController. - // The following will remove all spawned particles, then set the speed factor to zero so that no new ones will be spawned. - mObjectRoot->mParticles[i]->setSpeedFactor(0.f); - mObjectRoot->mParticles[i]->clear(); - } -} - -} diff --git a/apps/openmw/mwrender/activatoranimation.hpp b/apps/openmw/mwrender/activatoranimation.hpp deleted file mode 100644 index a234defe7..000000000 --- a/apps/openmw/mwrender/activatoranimation.hpp +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef GAME_RENDER_ACTIVATORANIMATION_H -#define GAME_RENDER_ACTIVATORANIMATION_H - -#include "animation.hpp" - -namespace MWWorld -{ - class Ptr; -} - -namespace MWRender -{ - class ActivatorAnimation : public Animation - { - public: - ActivatorAnimation(const MWWorld::Ptr& ptr, const std::string &model); - virtual ~ActivatorAnimation(); - - void addLight(const ESM::Light *light); - void removeParticles(); - }; -} - -#endif diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index fab65b152..a8c04aa4b 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -270,7 +270,6 @@ namespace MWScript std::string InterpreterContext::getActionBinding(const std::string& action) const { - /* MWBase::InputManager* input = MWBase::Environment::get().getInputManager(); std::vector actions = input->getActionKeySorting (); for (std::vector::const_iterator it = actions.begin(); it != actions.end(); ++it) @@ -287,7 +286,6 @@ namespace MWScript return input->getActionKeyBindingName (*it); } } - */ return "None"; } From 157d8bfedd4b1ed4cbb0361891fea1f25da9286a Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 3 May 2015 17:26:12 +0200 Subject: [PATCH 1097/3725] Remove unused mygui files --- CMakeLists.txt | 1 - files/CMakeLists.txt | 1 + files/mygui/CMakeLists.txt | 2 -- files/mygui/black.png | Bin 103 -> 0 bytes files/mygui/white.png | Bin 118 -> 0 bytes 5 files changed, 1 insertion(+), 3 deletions(-) delete mode 100644 files/mygui/black.png delete mode 100644 files/mygui/white.png diff --git a/CMakeLists.txt b/CMakeLists.txt index d2a245366..d1008d313 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -310,7 +310,6 @@ endif() add_subdirectory(files/) -add_subdirectory(files/mygui) # Specify build paths diff --git a/files/CMakeLists.txt b/files/CMakeLists.txt index e69de29bb..00cae86d2 100644 --- a/files/CMakeLists.txt +++ b/files/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(mygui) diff --git a/files/mygui/CMakeLists.txt b/files/mygui/CMakeLists.txt index 13d1a9e1a..602397743 100644 --- a/files/mygui/CMakeLists.txt +++ b/files/mygui/CMakeLists.txt @@ -4,8 +4,6 @@ set(SDIR ${CMAKE_CURRENT_SOURCE_DIR}) set(DDIR ${OpenMW_BINARY_DIR}/resources/mygui) set(MYGUI_FILES - black.png - white.png core.skin core.xml core_layouteditor.xml diff --git a/files/mygui/black.png b/files/mygui/black.png deleted file mode 100644 index 69db2911a7fc479a8d7c1da556c72a2c18109ed4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 103 zcmeAS@N?(olHy`uVBq!ia0vp^93afW1SGw4HSYi^#^NA%Cx&(BWL^R}oCO|{#S9GG t!XV7ZFl&wkP>{#d#W95AdUAq<9FTW{fw3kzvlhr=@O1TaS?83{1OS+*6e9ot diff --git a/files/mygui/white.png b/files/mygui/white.png deleted file mode 100644 index 9bed5f523c6ec8ffcbcd4dd203ea8ee2bc56fed0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 118 zcmeAS@N?(olHy`uVBq!ia0vp^93afW1SGw4HSYi^&H|6fVg?3oVGw3ym^DWND9B#o z>FdgVk5ib>QlDk|1u>wIsHcl#2*>s0KmY&RGn*Ya(!k8)$H@?Og_$?;bw(Xf0fVQj KpUXO@geCy^jvCGY From 37e3118d21a5f44706812fe3e3a4e70c623b6f25 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 3 May 2015 17:52:50 +0200 Subject: [PATCH 1098/3725] FontLoader cleanup fix --- apps/openmw/mwgui/windowmanagerimp.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index ebca96b19..c32f2bfe8 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -419,6 +419,8 @@ namespace MWGui cleanupGarbage(); + mFontLoader.reset(); + delete mGuiPlatform; } From 9de575ad42cd0170b514a10bf2bed4277f04f6e3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 3 May 2015 18:16:54 +0200 Subject: [PATCH 1099/3725] Use IncrementalCompileOperation to incrementally upload OpenGL objects during the loading screen For now, not much difference, but should result in a sizable speed up once MyGUI no longer needs the DYNAMIC flag (i.e. the loading screen truly renders in the background). --- apps/openmw/engine.cpp | 5 +---- apps/openmw/mwgui/loadingscreen.cpp | 9 ++++++++- apps/openmw/mwgui/loadingscreen.hpp | 1 + apps/openmw/mwrender/objects.cpp | 16 ++++++++++++++++ apps/openmw/mwrender/objects.hpp | 9 +++++++++ apps/openmw/mwrender/renderingmanager.cpp | 6 ++++++ 6 files changed, 41 insertions(+), 5 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 5be9317eb..d7ad97e6e 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -391,8 +391,6 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) mEnvironment.setJournal (new MWDialogue::Journal); mEnvironment.setDialogueManager (new MWDialogue::DialogueManager (mExtensions, mVerboseScripts, mTranslationDataStorage)); - //mOgre->getRoot()->addFrameListener (this); - // scripts if (mCompileAll) { @@ -466,13 +464,12 @@ void OMW::Engine::go() mViewer->setCameraManipulator(new osgGA::TrackballManipulator); mViewer->addEventHandler(new osgViewer::StatsHandler); - mViewer->realize(); osg::Timer frameTimer; while (!mViewer->done() && !MWBase::Environment::get().getStateManager()->hasQuitRequest()) { double dt = frameTimer.time_s(); frameTimer.setStartTick(); - //dt = std::min(dt, 0.2f); + //dt = std::min(dt, 0.2); frame(dt); mViewer->frame(/*simulationTime*/); diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index a7791d838..45bd5bf9d 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -30,8 +30,9 @@ namespace MWGui : WindowBase("openmw_loading_screen.layout") , mVFS(vfs) , mViewer(viewer) - , mLastRenderTime(0.0) , mLastWallpaperChangeTime(0.0) + , mLastRenderTime(0.0) + , mLoadingOnTime(0.0) , mProgress(0) , mVSyncWasEnabled(false) { @@ -97,6 +98,7 @@ namespace MWGui void LoadingScreen::loadingOn() { + mLoadingOnTime = mTimer.time_m(); // Early-out if already on if (mMainWidget->getVisible()) return; @@ -143,6 +145,7 @@ namespace MWGui void LoadingScreen::loadingOff() { + //std::cout << "loading took " << mTimer.time_m() - mLoadingOnTime << std::endl; setVisible(false); MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Loading); @@ -215,6 +218,8 @@ namespace MWGui changeWallpaper(); } + mViewer->getIncrementalCompileOperation()->setMaximumNumOfObjectsToCompilePerFrame(80); + // Turn off rendering except the GUI int oldUpdateMask = mViewer->getUpdateVisitor()->getTraversalMask(); int oldCullMask = mViewer->getCamera()->getCullMask(); @@ -223,6 +228,8 @@ namespace MWGui MWBase::Environment::get().getInputManager()->update(0, true, true); + //std::cout << "num to compile " << mViewer->getIncrementalCompileOperation()->getToCompile().size() << std::endl; + mViewer->frame(); // resume 3d rendering diff --git a/apps/openmw/mwgui/loadingscreen.hpp b/apps/openmw/mwgui/loadingscreen.hpp index 4c9d45f66..7c49df027 100644 --- a/apps/openmw/mwgui/loadingscreen.hpp +++ b/apps/openmw/mwgui/loadingscreen.hpp @@ -53,6 +53,7 @@ namespace MWGui double mLastWallpaperChangeTime; double mLastRenderTime; osg::Timer mTimer; + double mLoadingOnTime; size_t mProgress; diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 6f4f4ef79..69311c111 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -7,6 +7,8 @@ #include #include +#include + #include #include @@ -78,6 +80,11 @@ Objects::~Objects() mCellSceneNodes.clear(); } +void Objects::setIncrementalCompileOperation(osgUtil::IncrementalCompileOperation *ico) +{ + mIncrementalCompileOperation = ico; +} + void Objects::insertBegin(const MWWorld::Ptr& ptr) { osg::ref_ptr cellnode; @@ -108,6 +115,9 @@ void Objects::insertModel(const MWWorld::Ptr &ptr, const std::string &mesh, bool std::auto_ptr anim (new ObjectAnimation(ptr, mesh, mResourceSystem, allowLight)); + if (mIncrementalCompileOperation && anim->getObjectRoot()) + mIncrementalCompileOperation->add(anim->getObjectRoot()); + if (!allowLight) { RemoveParticlesVisitor visitor; @@ -130,6 +140,9 @@ void Objects::insertCreature(const MWWorld::Ptr &ptr, const std::string &mesh, b else anim.reset(new CreatureAnimation(ptr, mesh, mResourceSystem)); + if (mIncrementalCompileOperation && anim->getObjectRoot()) + mIncrementalCompileOperation->add(anim->getObjectRoot()); + mObjects.insert(std::make_pair(ptr, anim.release())); } @@ -139,6 +152,9 @@ void Objects::insertNPC(const MWWorld::Ptr &ptr) std::auto_ptr anim (new NpcAnimation(ptr, osg::ref_ptr(ptr.getRefData().getBaseNode()), mResourceSystem, 0)); + if (mIncrementalCompileOperation && anim->getObjectRoot()) + mIncrementalCompileOperation->add(anim->getObjectRoot()); + mObjects.insert(std::make_pair(ptr, anim.release())); } diff --git a/apps/openmw/mwrender/objects.hpp b/apps/openmw/mwrender/objects.hpp index 2acf10d10..fd6ceab54 100644 --- a/apps/openmw/mwrender/objects.hpp +++ b/apps/openmw/mwrender/objects.hpp @@ -12,6 +12,11 @@ namespace osg class Group; } +namespace osgUtil +{ + class IncrementalCompileOperation; +} + namespace Resource { class ResourceSystem; @@ -41,10 +46,14 @@ class Objects{ Resource::ResourceSystem* mResourceSystem; + osg::ref_ptr mIncrementalCompileOperation; + public: Objects(Resource::ResourceSystem* resourceSystem, osg::ref_ptr rootNode); ~Objects(); + void setIncrementalCompileOperation(osgUtil::IncrementalCompileOperation* ico); + /// @param animated Attempt to load separate keyframes from a .kf file matching the model file? /// @param allowLight If false, no lights will be created, and particles systems will be removed. void insertModel(const MWWorld::Ptr& ptr, const std::string &model, bool animated=false, bool allowLight=true); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 5cb779545..4f13df8e7 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -9,6 +9,8 @@ #include #include +#include + #include #include @@ -95,6 +97,10 @@ namespace MWRender mObjects.reset(new Objects(mResourceSystem, lightRoot)); + mViewer.setIncrementalCompileOperation(new osgUtil::IncrementalCompileOperation); + + mObjects->setIncrementalCompileOperation(mViewer.getIncrementalCompileOperation()); + mEffectManager.reset(new EffectManager(mRootNode, mResourceSystem)); mViewer.setLightingMode(osgViewer::View::NO_LIGHT); From 5a759f8b0d9577a41d8c8ae81e23eba508e73bcd Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 3 May 2015 18:35:29 +0200 Subject: [PATCH 1100/3725] GUI cleanup fix --- apps/opencs/editor.cpp | 5 ----- apps/openmw/mwgui/mainmenu.cpp | 2 -- apps/openmw/mwgui/windowmanagerimp.cpp | 11 +++++++---- components/fontloader/fontloader.cpp | 11 ++++++++++- 4 files changed, 17 insertions(+), 12 deletions(-) diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 83fcb3e37..56076dbe0 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -311,11 +311,6 @@ int CS::Editor::run() return QApplication::exec(); } - // for font used in overlays - //Ogre::Root::getSingleton().addResourceLocation ((mResources / "mygui").string(), - // "FileSystem", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, true); - - void CS::Editor::documentAdded (CSMDoc::Document *document) { mViewManager.addView (document); diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index 48f9ee42c..ef86666f4 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -1,7 +1,5 @@ #include "mainmenu.hpp" -#include - #include #include #include diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index c32f2bfe8..abc19b3f9 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -30,6 +30,8 @@ #include +#include + #include #include @@ -180,8 +182,8 @@ namespace MWGui mGuiPlatform = new osgMyGUI::Platform(viewer, guiRoot, resourceSystem->getTextureManager()); mGuiPlatform->initialise(resourcePath, logpath); - MyGUI::Gui* gui = new MyGUI::Gui; - gui->initialise(""); + mGui = new MyGUI::Gui; + mGui->initialise(""); createTextures(); @@ -307,8 +309,8 @@ namespace MWGui std::string hitFaderTexture = "textures\\bm_player_hit_01.dds"; // fall back to player_hit_01.dds if bm_player_hit_01.dds is not available // TODO: check if non-BM versions actually use player_hit_01.dds - //if(!Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(hitFaderTexture)) - // hitFaderTexture = "textures\\player_hit_01.dds"; + if(!mResourceSystem->getVFS()->exists(hitFaderTexture)) + hitFaderTexture = "textures\\player_hit_01.dds"; mHitFader = new ScreenFader(hitFaderTexture); mScreenFader = new ScreenFader("black.png"); @@ -421,6 +423,7 @@ namespace MWGui mFontLoader.reset(); + delete mGui; delete mGuiPlatform; } diff --git a/components/fontloader/fontloader.cpp b/components/fontloader/fontloader.cpp index 080c64c4c..7635c43da 100644 --- a/components/fontloader/fontloader.cpp +++ b/components/fontloader/fontloader.cpp @@ -438,7 +438,16 @@ namespace Gui font->deserialization(root, MyGUI::Version(3,2,0)); - MyGUI::ResourceManager::getInstance().removeByName(font->getResourceName()); + for (std::vector::iterator it = mFonts.begin(); it != mFonts.end();) + { + if ((*it)->getResourceName() == font->getResourceName()) + { + MyGUI::ResourceManager::getInstance().removeByName(font->getResourceName()); + it = mFonts.erase(it); + } + else + ++it; + } MyGUI::ResourceManager::getInstance().addResource(font); } From a37a83eaea0c5c543d71d49ba36ab41d8952e29e Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 3 May 2015 22:15:53 +0200 Subject: [PATCH 1101/3725] Use interleaved vertex data in MyGUI render manager, avoiding redundant copies --- .../myguiplatform/myguirendermanager.cpp | 93 ++++++------------- 1 file changed, 29 insertions(+), 64 deletions(-) diff --git a/components/myguiplatform/myguirendermanager.cpp b/components/myguiplatform/myguirendermanager.cpp index 87464f22d..e63756ecd 100644 --- a/components/myguiplatform/myguirendermanager.cpp +++ b/components/myguiplatform/myguirendermanager.cpp @@ -97,9 +97,7 @@ namespace osgMyGUI class OSGVertexBuffer : public MyGUI::IVertexBuffer { osg::ref_ptr mBuffer; - osg::ref_ptr mPositionArray; - osg::ref_ptr mColorArray; - osg::ref_ptr mTexCoordArray; + osg::ref_ptr mVertexArray; std::vector mLockedData; size_t mNeedVertexCount; @@ -150,71 +148,32 @@ MyGUI::Vertex *OSGVertexBuffer::lock() { MYGUI_PLATFORM_ASSERT(mBuffer.valid(), "Vertex buffer is not created"); - // NOTE: Unfortunately, MyGUI wants the VBO data to be interleaved as a - // MyGUI::Vertex structure. However, OSG uses non-interleaved elements, so - // we have to give back a "temporary" structure array then copy it to the - // actual VBO arrays on unlock. This is extra unfortunate since the VBO may - // be backed by VRAM, meaning we could have up to 3 copies of the data - // (which we'll need to keep for VBOs that are continually updated). - mLockedData.resize(mNeedVertexCount, MyGUI::Vertex()); - return mLockedData.data(); + mVertexArray->resize(mNeedVertexCount * sizeof(MyGUI::Vertex)); + return (MyGUI::Vertex*)&(*mVertexArray)[0]; } void OSGVertexBuffer::unlock() { - osg::Vec3 *vec = &mPositionArray->front(); - for (std::vector::const_iterator it = mLockedData.begin(); it != mLockedData.end(); ++it) - { - const MyGUI::Vertex& elem = *it; - vec->set(elem.x, elem.y, elem.z); - ++vec; - } - osg::Vec4ub *clr = &mColorArray->front(); - for (std::vector::const_iterator it = mLockedData.begin(); it != mLockedData.end(); ++it) - { - const MyGUI::Vertex& elem = *it; - union { - MyGUI::uint32 ui; - unsigned char ub4[4]; - } val = { elem.colour }; - clr->set(val.ub4[0], val.ub4[1], val.ub4[2], val.ub4[3]); - ++clr; - } - osg::Vec2 *crds = &mTexCoordArray->front(); - for (std::vector::const_iterator it = mLockedData.begin(); it != mLockedData.end(); ++it) - { - const MyGUI::Vertex& elem = *it; - crds->set(elem.u, elem.v); - ++crds; - } - + mVertexArray->dirty(); mBuffer->dirty(); } void OSGVertexBuffer::destroy() { mBuffer = nullptr; - mPositionArray = nullptr; - mColorArray = nullptr; - mTexCoordArray = nullptr; - std::vector().swap(mLockedData); + mVertexArray = nullptr; } void OSGVertexBuffer::create() { MYGUI_PLATFORM_ASSERT(!mBuffer.valid(), "Vertex buffer already exist"); - mPositionArray = new osg::Vec3Array(mNeedVertexCount); - mColorArray = new osg::Vec4ubArray(mNeedVertexCount); - mTexCoordArray = new osg::Vec2Array(mNeedVertexCount); - mColorArray->setNormalize(true); + mVertexArray = new osg::UByteArray(mNeedVertexCount*sizeof(MyGUI::Vertex)); mBuffer = new osg::VertexBufferObject; mBuffer->setDataVariance(osg::Object::DYNAMIC); - mBuffer->setUsage(GL_STREAM_DRAW); - mBuffer->setArray(0, mPositionArray.get()); - mBuffer->setArray(1, mColorArray.get()); - mBuffer->setArray(2, mTexCoordArray.get()); + mBuffer->setUsage(GL_DYNAMIC_DRAW); + mBuffer->setArray(0, mVertexArray.get()); } // --------------------------------------------------------------------------- @@ -270,19 +229,10 @@ void RenderManager::initialise() camera->setRenderOrder(osg::Camera::POST_RENDER); camera->setClearMask(GL_NONE); osg::StateSet *state = new osg::StateSet; - state->setTextureMode(0, GL_TEXTURE_GEN_S, osg::StateAttribute::OFF); - state->setTextureMode(0, GL_TEXTURE_GEN_T, osg::StateAttribute::OFF); - state->setTextureMode(0, GL_TEXTURE_GEN_R, osg::StateAttribute::OFF); state->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::ON); state->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF); - state->setMode(GL_LIGHTING, osg::StateAttribute::OFF); - state->setMode(GL_LIGHT0, osg::StateAttribute::OFF); state->setMode(GL_BLEND, osg::StateAttribute::ON); - state->setMode(GL_FOG, osg::StateAttribute::OFF); - state->setTextureAttribute(0, new osg::TexEnv(osg::TexEnv::MODULATE)); - state->setAttribute(new osg::PolygonMode(osg::PolygonMode::FRONT, osg::PolygonMode::FILL)); state->setAttribute(new osg::BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); - state->setMode(GL_CULL_FACE, osg::StateAttribute::OFF); geode->setStateSet(state); geode->setCullingActive(false); camera->addChild(geode.get()); @@ -317,6 +267,10 @@ void RenderManager::begin() { osg::State *state = mRenderInfo->getState(); state->disableAllVertexArrays(); + state->setClientActiveTextureUnit(0); + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glEnableClientState(GL_COLOR_ARRAY); } void RenderManager::doRender(MyGUI::IVertexBuffer *buffer, MyGUI::ITexture *texture, size_t count) @@ -332,9 +286,21 @@ void RenderManager::doRender(MyGUI::IVertexBuffer *buffer, MyGUI::ITexture *text state->applyTextureAttribute(0, tex); } - state->setVertexPointer(vbo->getArray(0)); - state->setColorPointer(vbo->getArray(1)); - state->setTexCoordPointer(0, vbo->getArray(2)); + osg::GLBufferObject* bufferobject = state->isVertexBufferObjectSupported() ? vbo->getOrCreateGLBufferObject(state->getContextID()) : 0; + if (bufferobject) + { + state->bindVertexBufferObject(bufferobject); + + glVertexPointer(3, GL_FLOAT, sizeof(MyGUI::Vertex), (char*)NULL); + glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(MyGUI::Vertex), (char*)NULL + 12); + glTexCoordPointer(2, GL_FLOAT, sizeof(MyGUI::Vertex), (char*)NULL + 16); + } + else + { + glVertexPointer(3, GL_FLOAT, sizeof(MyGUI::Vertex), (char*)vbo->getArray(0)->getDataPointer()); + glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(MyGUI::Vertex), (char*)vbo->getArray(0)->getDataPointer() + 12); + glTexCoordPointer(2, GL_FLOAT, sizeof(MyGUI::Vertex), (char*)vbo->getArray(0)->getDataPointer() + 16); + } glDrawArrays(GL_TRIANGLES, 0, count); } @@ -342,10 +308,9 @@ void RenderManager::doRender(MyGUI::IVertexBuffer *buffer, MyGUI::ITexture *text void RenderManager::end() { osg::State *state = mRenderInfo->getState(); - state->disableTexCoordPointer(0); - state->disableColorPointer(); - state->disableVertexPointer(); state->unbindVertexBufferObject(); + state->dirtyAllVertexArrays(); + state->disableAllVertexArrays(); } void RenderManager::drawFrame(osg::RenderInfo &renderInfo) From f0789352c630661ff3d53d024a8bc89701c67e50 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 4 May 2015 00:34:30 +0200 Subject: [PATCH 1102/3725] Silence error message --- apps/openmw/mwgui/inventorywindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index c3932d388..cbce86650 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -117,10 +117,10 @@ namespace MWGui mPreview.reset(NULL); mAvatarImage->setImageTexture(""); +#if 0 MyGUI::ITexture* tex = MyGUI::RenderManager::getInstance().getTexture("CharacterPreview"); if (tex) MyGUI::RenderManager::getInstance().destroyTexture(tex); -#if 0 mPreview.reset(new MWRender::InventoryPreview(mPtr)); mPreview->setup(); #endif From c1edc30ad718a631259ff69844232bd47fe0f294 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 4 May 2015 03:29:12 +0200 Subject: [PATCH 1103/3725] Dead code removal --- CMakeLists.txt | 171 +--------------------- apps/launcher/CMakeLists.txt | 1 - apps/opencs/CMakeLists.txt | 2 - apps/openmw/CMakeLists.txt | 3 - apps/openmw/engine.cpp | 10 -- apps/openmw/mwgui/settingswindow.cpp | 20 --- apps/openmw/mwgui/settingswindow.hpp | 2 - files/mygui/openmw_settings_window.layout | 6 - files/settings-default.cfg | 2 - 9 files changed, 1 insertion(+), 216 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d1008d313..92023da2c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -54,12 +54,9 @@ endif (ANDROID) configure_file ("${OpenMW_SOURCE_DIR}/docs/mainpage.hpp.cmake" "${OpenMW_BINARY_DIR}/docs/mainpage.hpp") option(MYGUI_STATIC "Link static build of Mygui into the binaries" FALSE) -option(OGRE_STATIC "Link static build of Ogre and Ogre Plugins into the binaries" FALSE) option(BOOST_STATIC "Link static build of Boost into the binaries" FALSE) option(SDL2_STATIC "Link static build of SDL into the binaries" FALSE) -set(CUSTOM_OGRE_PLUGIN_DIR "" CACHE PATH "Specify a custom directory for Ogre plugins (autodetected by default)") - option(OPENMW_UNITY_BUILD "Use fewer compilation units to speed up compile time" FALSE) # Apps and tools @@ -197,46 +194,9 @@ find_package(SDL2 REQUIRED) find_package(OpenAL REQUIRED) find_package(Bullet REQUIRED) -set(OGRE_PLUGIN_INCLUDE_DIRS "") -set(OGRE_STATIC_PLUGINS "") - -macro(add_static_ogre_plugin PLUGIN) - if(OGRE_${PLUGIN}_FOUND) - # strip RenderSystem_ or Plugin_ prefix from plugin name - string(REPLACE "RenderSystem_" "" PLUGIN_TEMP ${PLUGIN}) - string(REPLACE "Plugin_" "" PLUGIN_NAME ${PLUGIN_TEMP}) - add_definitions(-DENABLE_PLUGIN_${PLUGIN_NAME}) - - list(APPEND OGRE_PLUGIN_INCLUDE_DIRS ${OGRE_${PLUGIN}_INCLUDE_DIRS}) - list(APPEND OGRE_STATIC_PLUGINS ${OGRE_${PLUGIN}_LIBRARIES}) - endif(OGRE_${PLUGIN}_FOUND) -endmacro(add_static_ogre_plugin) - -if(OGRE_STATIC) - # set up OGRE_PLUGIN_INCLUDE_DIRS and OGRE_STATIC_PLUGINS - add_static_ogre_plugin(Plugin_OctreeSceneManager) - add_static_ogre_plugin(Plugin_ParticleFX) - find_package(Cg) - if(Cg_FOUND) - add_static_ogre_plugin(Plugin_CgProgramManager) - list(APPEND OGRE_STATIC_PLUGINS ${Cg_LIBRARIES}) - endif(Cg_FOUND) - -if (ANDROID) - add_static_ogre_plugin(RenderSystem_GLES2) -else () - add_static_ogre_plugin(RenderSystem_GL) -endif () - - if(WIN32) - add_static_ogre_plugin(RenderSystem_Direct3D9) - endif(WIN32) -endif(OGRE_STATIC) - include_directories("." ${LIBS_DIR} SYSTEM - ${OGRE_INCLUDE_DIR} ${OGRE_INCLUDE_DIR}/Ogre ${OGRE_INCLUDE_DIR}/OGRE ${OGRE_INCLUDE_DIRS} ${OGRE_PLUGIN_INCLUDE_DIRS} - ${OGRE_INCLUDE_DIR}/Overlay ${OGRE_Overlay_INCLUDE_DIR} + ${OGRE_INCLUDE_DIR} ${OGRE_INCLUDE_DIR}/Ogre ${OGRE_INCLUDE_DIR}/OGRE ${OGRE_INCLUDE_DIRS} ${SDL2_INCLUDE_DIR} ${Boost_INCLUDE_DIR} ${PLATFORM_INCLUDE_DIR} @@ -252,31 +212,6 @@ if(MYGUI_STATIC) endif (MYGUI_STATIC) if (APPLE) - # List used Ogre plugins - SET(USED_OGRE_PLUGINS ${OGRE_RenderSystem_GL_LIBRARY_REL} - ${OGRE_Plugin_ParticleFX_LIBRARY_REL}) - - # Actually we must use OGRE_Plugin_CgProgramManager_FOUND but it's - # not reliable and equals TRUE even if there's no Ogre Cg plugin - if (Cg_FOUND) - set(USED_OGRE_PLUGINS ${USED_OGRE_PLUGINS} - ${OGRE_Plugin_CgProgramManager_LIBRARY_REL}) - endif () - - if (${OGRE_PLUGIN_DIR_REL}}) - set(OGRE_PLUGINS_REL_FOUND TRUE) - endif () - - if (${OGRE_PLUGIN_DIR_DBG}) - set(OGRE_PLUGINS_DBG_FOUND TRUE) - endif () - - if (${OGRE_PLUGINS_REL_FOUND}) - set(OGRE_PLUGIN_DIR ${OGRE_PLUGIN_DIR_REL}) - else () - set(OGRE_PLUGIN_DIR ${OGRE_PLUGIN_DIR_DBG}) - endif () - configure_file(${OpenMW_SOURCE_DIR}/files/mac/Info.plist "${APP_BUNDLE_DIR}/Contents/Info.plist") @@ -287,28 +222,6 @@ endif (APPLE) # Set up DEBUG define set_directory_properties(PROPERTIES COMPILE_DEFINITIONS_DEBUG DEBUG=1) -# Set up Ogre plugin folder & debug suffix -if (APPLE) - # Ogre on OS X doesn't use "_d" suffix (see Ogre's CMakeLists.txt) - add_definitions(-DOGRE_PLUGIN_DEBUG_SUFFIX="") -else () - add_definitions(-DOGRE_PLUGIN_DEBUG_SUFFIX="_d") -endif() - -if (APPLE AND OPENMW_OSX_DEPLOYMENT) - # make it empty so plugin loading code can check this and try to find plugins inside app bundle - add_definitions(-DOGRE_PLUGIN_DIR="") -else() - if (CUSTOM_OGRE_PLUGIN_DIR STREQUAL "") - set(OGRE_PLUGIN_DIR ${OGRE_PLUGIN_DIR_REL}) - else() - set(OGRE_PLUGIN_DIR ${CUSTOM_OGRE_PLUGIN_DIR}) - endif() - - add_definitions(-DOGRE_PLUGIN_DIR="${OGRE_PLUGIN_DIR}") -endif() - - add_subdirectory(files/) # Specify build paths @@ -651,12 +564,6 @@ if (WIN32) 4987 # nonstandard extension used (triggered by setjmp.h) 4996 # Function was declared deprecated - # cause by ogre extensivly - 4193 # #pragma warning(pop) : no matching '#pragma warning(push)' - 4251 # class 'XXXX' needs to have dll-interface to be used by clients of class 'YYYY' - 4275 # non dll-interface struct 'XXXX' used as base for dll-interface class 'YYYY' - 4315 # undocumented, 'this' pointer for member might not be aligned (OgreMemoryStlAllocator.h) - # caused by boost 4191 # 'type cast' : unsafe conversion (1.56, thread_primitives.hpp, normally off) @@ -722,90 +629,14 @@ if (APPLE) set(OPENCS_BUNDLE_NAME "OpenMW-CS.app") set(OPENCS_APP "\${CMAKE_INSTALL_PREFIX}/${INSTALL_SUBDIR}/${OPENCS_BUNDLE_NAME}") - set(ABSOLUTE_PLUGINS "") - - foreach (PLUGIN ${USED_OGRE_PLUGINS}) - get_filename_component(PLUGIN_ABS ${PLUGIN} REALPATH) - set(ABSOLUTE_PLUGINS ${PLUGIN_ABS} ${ABSOLUTE_PLUGINS}) - endforeach () - install(CODE " set(BU_CHMOD_BUNDLE_ITEMS ON) include(BundleUtilities) " COMPONENT Runtime) - # installs used plugins in bundle at given path (bundle_path must be relative to ${CMAKE_INSTALL_PREFIX}) - # and returns list of install paths for all installed plugins - function (install_plugins_for_bundle bundle_path plugins_var) - set(RELATIVE_PLUGIN_INSTALL_BASE "${bundle_path}/Contents/Frameworks") - - set(PLUGINS "") - set(PLUGIN_INSTALL_BASE "\${CMAKE_INSTALL_PREFIX}/${RELATIVE_PLUGIN_INSTALL_BASE}") - - foreach (PLUGIN ${ABSOLUTE_PLUGINS}) - get_filename_component(PLUGIN_RELATIVE ${PLUGIN} NAME) - get_filename_component(PLUGIN_RELATIVE_WE ${PLUGIN} NAME_WE) - - set(PLUGIN_DYLIB_IN_BUNDLE "${PLUGIN_INSTALL_BASE}/${PLUGIN_RELATIVE}/${PLUGIN_RELATIVE_WE}") - set(PLUGINS ${PLUGINS} "${PLUGIN_DYLIB_IN_BUNDLE}") - - install(CODE " - copy_resolved_framework_into_bundle(\"${PLUGIN}/${PLUGIN_RELATIVE_WE}\" \"${PLUGIN_DYLIB_IN_BUNDLE}\") - " COMPONENT Runtime) - endforeach () - - set(${plugins_var} ${PLUGINS} PARENT_SCOPE) - endfunction (install_plugins_for_bundle) - - install_plugins_for_bundle("${INSTALL_SUBDIR}/${APP_BUNDLE_NAME}" PLUGINS) - install_plugins_for_bundle("${INSTALL_SUBDIR}/${OPENCS_BUNDLE_NAME}" OPENCS_PLUGINS) - #For now, search unresolved dependencies only in default system paths, so if you put unresolveable (i.e. with @executable_path in id name) lib or framework somewhere else, it would fail set(DIRS "") - # Overriding item resolving during installation, it needed if - # some library already has been "fixed up", i.e. its id name contains @executable_path, - # but library is not embedded in bundle. For example, it's Ogre.framework from Ogre SDK. - # Current implementation of GetPrerequsities/BundleUtilities doesn't handle that case. - # - # Current limitations: - # 1. Handles only frameworks, not simple libs - INSTALL(CODE " - cmake_policy(SET CMP0009 OLD) - set(CMAKE_FIND_LIBRARY_PREFIXES ${CMAKE_FIND_LIBRARY_PREFIXES}) - set(CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES}) - set(CMAKE_SYSTEM_FRAMEWORK_PATH ${CMAKE_SYSTEM_FRAMEWORK_PATH}) - - set(OPENMW_RESOLVED_ITEMS \"\") - - function(gp_resolve_item_override context item exepath dirs resolved_item_var resolved_var) - if(item MATCHES \"@executable_path\" AND NOT \${\${resolved_var}}) - if (item MATCHES \"Frameworks\") # if it is a framework - # get last segment of path - get_filename_component(fname \"\${item}\" NAME_WE) - find_library(ri NAMES \${fname} PATHS \${exepath} \${dirs} \${CMAKE_SYSTEM_FRAMEWORK_PATH}) - if (ri) - string(REGEX REPLACE \"^.*/Frameworks/.*\\\\.framework\" \"\" item_part \${item}) - set(ri \"\${ri}\${item_part}\") - set(\${resolved_item_var} \${ri} PARENT_SCOPE) - set(\${resolved_var} 1 PARENT_SCOPE) - endif() - else() - # code path for standard (non-framework) libs (ogre & qt pugins) - get_filename_component(fname \"\${item}\" NAME_WE) - string(REGEX REPLACE \"^lib\" \"\" fname \${fname}) - find_library(ri NAMES \${fname} PATHS \${exepath} \${dirs} /usr/lib /usr/local/lib) - if (ri) - set(\${resolved_item_var} \${ri} PARENT_SCOPE) - set(\${resolved_var} 1 PARENT_SCOPE) - endif () - endif() - endif() - endfunction(gp_resolve_item_override) - - fixup_bundle(\"${OPENMW_APP}\" \"${PLUGINS}\" \"${DIRS}\") - fixup_bundle(\"${OPENCS_APP}\" \"${OPENCS_PLUGINS}\" \"${DIRS}\") - " COMPONENT Runtime) include(CPack) endif (APPLE) diff --git a/apps/launcher/CMakeLists.txt b/apps/launcher/CMakeLists.txt index 0de79f8f6..76b6e46bd 100644 --- a/apps/launcher/CMakeLists.txt +++ b/apps/launcher/CMakeLists.txt @@ -90,7 +90,6 @@ add_executable(openmw-launcher target_link_libraries(openmw-launcher ${Boost_LIBRARIES} ${OGRE_LIBRARIES} - ${OGRE_STATIC_PLUGINS} ${SDL2_LIBRARY_ONLY} ${QT_LIBRARIES} components diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 8347af6ee..d7aafcf30 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -201,8 +201,6 @@ endif(APPLE) target_link_libraries(openmw-cs ${OENGINE_LIBRARY} ${OGRE_LIBRARIES} - ${OGRE_Overlay_LIBRARIES} - ${OGRE_STATIC_PLUGINS} ${OPENSCENEGRAPH_LIBRARIES} ${Boost_LIBRARIES} ${BULLET_LIBRARIES} diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 4a93daec7..d680f49d6 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -129,7 +129,6 @@ include_directories(${SOUND_INPUT_INCLUDES}) target_link_libraries(openmw ${OENGINE_LIBRARY} ${OGRE_LIBRARIES} - ${OGRE_STATIC_PLUGINS} ${OPENSCENEGRAPH_LIBRARIES} ${Boost_LIBRARIES} ${OPENAL_LIBRARY} @@ -144,13 +143,11 @@ target_link_libraries(openmw if (ANDROID) target_link_libraries(openmw - ${OGRE_STATIC_PLUGINS} EGL android log dl MyGUIEngineStatic - Plugin_StrangeButtonStatic cpufeatures BulletCollision BulletDynamics diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index ac51eace8..d91d32a28 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -277,16 +277,6 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) mEnvironment.setStateManager ( new MWState::StateManager (mCfgMgr.getUserDataPath() / "saves", mContentFiles.at (0))); - std::string renderSystem = settings.getString("render system", "Video"); - if (renderSystem == "") - { -#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32 - renderSystem = "Direct3D9 Rendering Subsystem"; -#else - renderSystem = "OpenGL Rendering Subsystem"; -#endif - } - //OEngine::Render::WindowSettings windowSettings; //windowSettings.fullscreen = settings.getBool("fullscreen", "Video"); //windowSettings.window_border = settings.getBool("window border", "Video"); diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 23cf2c62e..c23e2bb94 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -75,11 +75,6 @@ namespace return MyGUI::utility::toString(xaspect) + " : " + MyGUI::utility::toString(yaspect); } - std::string hlslGlsl () - { - return (Ogre::Root::getSingleton ().getRenderSystem ()->getName ().find("OpenGL") != std::string::npos) ? "glsl" : "hlsl"; - } - const char* checkButtonType = "CheckButton"; const char* sliderType = "Slider"; @@ -180,7 +175,6 @@ namespace MWGui getWidget(mAnisotropyLabel, "AnisotropyLabel"); getWidget(mAnisotropyBox, "AnisotropyBox"); getWidget(mShadersButton, "ShadersButton"); - getWidget(mShaderModeButton, "ShaderModeButton"); getWidget(mShadowsEnabledButton, "ShadowsEnabledButton"); getWidget(mShadowsTextureSize, "ShadowsTextureSize"); getWidget(mControlsBox, "ControlsBox"); @@ -207,7 +201,6 @@ namespace MWGui mMainWidget->castType()->eventWindowChangeCoord += MyGUI::newDelegate(this, &SettingsWindow::onWindowResize); mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onOkButtonClicked); - mShaderModeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onShaderModeToggled); mTextureFilteringButton->eventComboChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onTextureFilteringChanged); mFPSButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onFpsToggled); mResolutionList->eventListChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onResolutionSelected); @@ -248,8 +241,6 @@ namespace MWGui mShadowsTextureSize->setCaption (Settings::Manager::getString ("texture size", "Shadows")); - mShaderModeButton->setCaption (Settings::Manager::getString("shader mode", "General")); - if (!Settings::Manager::getBool("shaders", "Objects")) { mRefractionButton->setEnabled(false); @@ -398,17 +389,6 @@ namespace MWGui } } - void SettingsWindow::onShaderModeToggled(MyGUI::Widget* _sender) - { - std::string val = hlslGlsl(); - - _sender->castType()->setCaption(val); - - Settings::Manager::setString("shader mode", "General", val); - - apply(); - } - void SettingsWindow::onFpsToggled(MyGUI::Widget* _sender) { int newLevel = (Settings::Manager::getInt("fps", "HUD") + 1) % 2; diff --git a/apps/openmw/mwgui/settingswindow.hpp b/apps/openmw/mwgui/settingswindow.hpp index 1b970b8de..7cebb10d1 100644 --- a/apps/openmw/mwgui/settingswindow.hpp +++ b/apps/openmw/mwgui/settingswindow.hpp @@ -37,7 +37,6 @@ namespace MWGui MyGUI::TextBox* mAnisotropyLabel; MyGUI::Widget* mAnisotropyBox; MyGUI::Button* mShadersButton; - MyGUI::Button* mShaderModeButton; MyGUI::Button* mRefractionButton; MyGUI::Button* mShadowsEnabledButton; @@ -59,7 +58,6 @@ namespace MWGui void onResolutionAccept(); void onResolutionCancel(); - void onShaderModeToggled(MyGUI::Widget* _sender); void onShadowTextureSizeChanged(MyGUI::ComboBox* _sender, size_t pos); void onRebindAction(MyGUI::Widget* _sender); diff --git a/files/mygui/openmw_settings_window.layout b/files/mygui/openmw_settings_window.layout index 2efd5841e..cc9c3d1dc 100644 --- a/files/mygui/openmw_settings_window.layout +++ b/files/mygui/openmw_settings_window.layout @@ -271,12 +271,6 @@
- - - - - - diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 862f9495a..7f2185b62 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -59,8 +59,6 @@ anisotropy = 4 # Number of texture mipmaps to generate num mipmaps = 8 -shader mode = - screenshot format = png [Shadows] From b0c4be231622666eab9253c6e5700e5157559c9c Mon Sep 17 00:00:00 2001 From: dteviot Date: Mon, 4 May 2015 14:52:47 +1200 Subject: [PATCH 1104/3725] Multi-select + context menu. (Fixes #2480) Content selector, added multi-select + context menu to allow check/uncheck the multi-selected items. --- .../contentselector/view/contentselector.cpp | 40 +++++++++++++++++++ .../contentselector/view/contentselector.hpp | 6 +++ files/ui/contentselector.ui | 2 +- 3 files changed, 47 insertions(+), 1 deletion(-) diff --git a/components/contentselector/view/contentselector.cpp b/components/contentselector/view/contentselector.cpp index e3093d568..2fae8e74b 100644 --- a/components/contentselector/view/contentselector.cpp +++ b/components/contentselector/view/contentselector.cpp @@ -57,6 +57,17 @@ void ContentSelectorView::ContentSelector::buildAddonView() connect(ui.addonView, SIGNAL(activated(const QModelIndex&)), this, SLOT(slotAddonTableItemActivated(const QModelIndex&))); connect(mContentModel, SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&)), this, SIGNAL(signalAddonDataChanged(QModelIndex,QModelIndex))); + buildContextMenu(); +} + +void ContentSelectorView::ContentSelector::buildContextMenu() +{ + ui.addonView->setContextMenuPolicy(Qt::CustomContextMenu); + connect(ui.addonView, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(slotShowContextMenu(const QPoint&))); + + mContextMenu = new QMenu(ui.addonView); + mContextMenu->addAction(tr("&Check Selected"), this, SLOT(slotCheckMultiSelectedItems())); + mContextMenu->addAction(tr("&Uncheck Selected"), this, SLOT(slotUncheckMultiSelectedItems())); } void ContentSelectorView::ContentSelector::setProfileContent(const QStringList &fileList) @@ -196,3 +207,32 @@ void ContentSelectorView::ContentSelector::slotAddonTableItemActivated(const QMo mContentModel->setData(sourceIndex, checkState, Qt::CheckStateRole); } + +void ContentSelectorView::ContentSelector::slotShowContextMenu(const QPoint& pos) +{ + QPoint globalPos = ui.addonView->viewport()->mapToGlobal(pos); + mContextMenu->exec(globalPos); +} + +void ContentSelectorView::ContentSelector::setCheckStateForMultiSelectedItems(bool checked) +{ + Qt::CheckState checkState = checked ? Qt::Checked : Qt::Unchecked; + foreach(const QModelIndex& index, ui.addonView->selectionModel()->selectedIndexes()) + { + QModelIndex sourceIndex = mAddonProxyModel->mapToSource(index); + if (mContentModel->data(sourceIndex, Qt::CheckStateRole).toInt() != checkState) + { + mContentModel->setData(sourceIndex, checkState, Qt::CheckStateRole); + } + } +} + +void ContentSelectorView::ContentSelector::slotUncheckMultiSelectedItems() +{ + setCheckStateForMultiSelectedItems(false); +} + +void ContentSelectorView::ContentSelector::slotCheckMultiSelectedItems() +{ + setCheckStateForMultiSelectedItems(true); +} diff --git a/components/contentselector/view/contentselector.hpp b/components/contentselector/view/contentselector.hpp index 2507cf6ad..e455807c9 100644 --- a/components/contentselector/view/contentselector.hpp +++ b/components/contentselector/view/contentselector.hpp @@ -14,6 +14,7 @@ namespace ContentSelectorView { Q_OBJECT + QMenu *mContextMenu; QStringList mFilePaths; protected: @@ -51,7 +52,9 @@ namespace ContentSelectorView void buildContentModel(); void buildGameFileView(); void buildAddonView(); + void buildContextMenu(); void setGameFileSelected(int index, bool selected); + void setCheckStateForMultiSelectedItems(bool checked); signals: void signalCurrentGamefileIndexChanged (int); @@ -62,6 +65,9 @@ namespace ContentSelectorView void slotCurrentGameFileIndexChanged(int index); void slotAddonTableItemActivated(const QModelIndex& index); + void slotShowContextMenu(const QPoint& pos); + void slotCheckMultiSelectedItems(); + void slotUncheckMultiSelectedItems(); }; } diff --git a/files/ui/contentselector.ui b/files/ui/contentselector.ui index b9b5ba5a0..7832239b5 100644 --- a/files/ui/contentselector.ui +++ b/files/ui/contentselector.ui @@ -72,7 +72,7 @@ true
- QAbstractItemView::SingleSelection + QAbstractItemView::ExtendedSelection QAbstractItemView::SelectRows From 27751db99afae9368fc29fabbe0bbedb980c3ace Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 4 May 2015 16:23:33 +0200 Subject: [PATCH 1105/3725] Use btScaledBvhTriangleMeshShape, bump required bullet version to 2.83 --- components/nifbullet/bulletnifloader.cpp | 4 +-- libs/openengine/bullet/physic.cpp | 32 +++++++++++++++++------- libs/openengine/bullet/physic.hpp | 3 +++ 3 files changed, 28 insertions(+), 11 deletions(-) diff --git a/components/nifbullet/bulletnifloader.cpp b/components/nifbullet/bulletnifloader.cpp index 93c9797b2..3207af0fe 100644 --- a/components/nifbullet/bulletnifloader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -123,7 +123,7 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource) mCompoundShape = NULL; mStaticMesh = NULL; - Nif::NIFFilePtr pnif (Nif::Cache::getInstance().load(mResourceName.substr(0, mResourceName.length()-7))); + Nif::NIFFilePtr pnif (Nif::Cache::getInstance().load(mResourceName)); Nif::NIFFile & nif = *pnif.get (); if (nif.numRoots() < 1) { @@ -134,7 +134,7 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource) // Have to load controlled nodes from the .kf // FIXME: the .kf has to be loaded both for rendering and physics, ideally it should be opened once and then reused mControlledNodes.clear(); - std::string kfname = mResourceName.substr(0, mResourceName.length()-7); + std::string kfname = mResourceName; Misc::StringUtils::toLower(kfname); if(kfname.size() > 4 && kfname.compare(kfname.size()-4, 4, ".nif") == 0) kfname.replace(kfname.size()-4, 4, ".kf"); diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index 013ef1003..76dbc224c 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -457,8 +457,7 @@ namespace Physic float scale, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, Ogre::Vector3* scaledBoxTranslation, Ogre::Quaternion* boxRotation, bool raycasting, bool placeable) { - std::string sid = (boost::format("%07.3f") % scale).str(); - std::string outputstring = mesh + sid; + std::string outputstring = mesh; //get the shape from the .nif mShapeLoader->load(outputstring,"General"); @@ -477,20 +476,35 @@ namespace Physic btCollisionShape* collisionShape = raycasting ? shape->mRaycastingShape : shape->mCollisionShape; - // If this is an animated compound shape, we must duplicate it so we can animate - // multiple instances independently. - if (!raycasting && !shape->mAnimatedShapes.empty()) - collisionShape = duplicateCollisionShape(collisionShape); - if (raycasting && !shape->mAnimatedRaycastingShapes.empty()) - collisionShape = duplicateCollisionShape(collisionShape); +// TODO: check this from cmake? +#if BT_BULLET_VERSION < 283 +#error "Bullet version 2.83 or later required" +#endif - collisionShape->setLocalScaling( btVector3(scale,scale,scale)); + bool needDelete = false; + if (btBvhTriangleMeshShape* triangleShape = dynamic_cast(shape->mCollisionShape)) + { + btScaledBvhTriangleMeshShape* scaled = new btScaledBvhTriangleMeshShape(triangleShape, btVector3(scale,scale,scale)); + collisionShape = scaled; + needDelete = true; + } + else + { + // If this is an animated compound shape, we must duplicate it so we can animate + // multiple instances independently. + if (!raycasting && !shape->mAnimatedShapes.empty()) + collisionShape = duplicateCollisionShape(collisionShape); + if (raycasting && !shape->mAnimatedRaycastingShapes.empty()) + collisionShape = duplicateCollisionShape(collisionShape); + } //create the real body btRigidBody::btRigidBodyConstructionInfo CI = btRigidBody::btRigidBodyConstructionInfo (0,0, collisionShape); RigidBody* body = new RigidBody(CI,name); body->mPlaceable = placeable; + if (needDelete) + body->mCollisionShape.reset(collisionShape); if (!raycasting && !shape->mAnimatedShapes.empty()) { diff --git a/libs/openengine/bullet/physic.hpp b/libs/openengine/bullet/physic.hpp index 7784e8941..7b0906694 100644 --- a/libs/openengine/bullet/physic.hpp +++ b/libs/openengine/bullet/physic.hpp @@ -63,6 +63,9 @@ namespace Physic virtual ~RigidBody(); std::string mName; + // May be empty if the collision shape is a shared resource + std::auto_ptr mCollisionShape; + // Hack: placeable objects (that can be picked up by the player) have different collision behaviour. // This variable needs to be passed to BulletNifLoader. bool mPlaceable; From e191f0e044f5f9b5ea9de737322f015737553a6a Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 4 May 2015 17:41:30 +0200 Subject: [PATCH 1106/3725] Rename MWRender::Debugging to MWRender::Pathgrid --- apps/openmw/CMakeLists.txt | 2 +- .../mwrender/{debugging.cpp => pathgrid.cpp} | 24 +++++++++---------- .../mwrender/{debugging.hpp => pathgrid.hpp} | 17 +++---------- apps/openmw/mwrender/renderingmanager.cpp | 10 ++++---- apps/openmw/mwrender/renderingmanager.hpp | 4 ++-- apps/openmw/mwworld/worldimp.hpp | 10 ++++++-- 6 files changed, 30 insertions(+), 37 deletions(-) rename apps/openmw/mwrender/{debugging.cpp => pathgrid.cpp} (92%) rename apps/openmw/mwrender/{debugging.hpp => pathgrid.hpp} (81%) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index d680f49d6..e1de2a556 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -21,7 +21,7 @@ source_group(game FILES ${GAME} ${GAME_HEADER}) add_openmw_dir (mwrender actors objects renderingmanager animation sky npcanimation vismask - creatureanimation effectmanager util renderinginterface debugging rendermode + creatureanimation effectmanager util renderinginterface pathgrid rendermode bulletdebugdraw # camera # localmap occlusionquery water shadows diff --git a/apps/openmw/mwrender/debugging.cpp b/apps/openmw/mwrender/pathgrid.cpp similarity index 92% rename from apps/openmw/mwrender/debugging.cpp rename to apps/openmw/mwrender/pathgrid.cpp index 9cbf94d46..5e559eeed 100644 --- a/apps/openmw/mwrender/debugging.cpp +++ b/apps/openmw/mwrender/pathgrid.cpp @@ -1,4 +1,4 @@ -#include "debugging.hpp" +#include "pathgrid.hpp" #include @@ -7,8 +7,6 @@ #include #include -#include - #include #include @@ -27,7 +25,7 @@ namespace MWRender static const int POINT_MESH_BASE = 35; -osg::ref_ptr Debugging::createPathgridLines(const ESM::Pathgrid *pathgrid) +osg::ref_ptr Pathgrid::createPathgridLines(const ESM::Pathgrid *pathgrid) { osg::ref_ptr geom = new osg::Geometry; @@ -62,7 +60,7 @@ osg::ref_ptr Debugging::createPathgridLines(const ESM::Pathgrid * return geom; } -osg::ref_ptr Debugging::createPathgridPoints(const ESM::Pathgrid *pathgrid) +osg::ref_ptr Pathgrid::createPathgridPoints(const ESM::Pathgrid *pathgrid) { osg::ref_ptr geom = new osg::Geometry; @@ -126,7 +124,7 @@ osg::ref_ptr Debugging::createPathgridPoints(const ESM::Pathgrid return geom; } -Debugging::Debugging(osg::ref_ptr root /*, OEngine::Physic::PhysicEngine *engine*/) +Pathgrid::Pathgrid(osg::ref_ptr root) : mRootNode(root) , mPathgridEnabled(false) , mInteriorPathgridNode(NULL) @@ -134,7 +132,7 @@ Debugging::Debugging(osg::ref_ptr root /*, OEngine::Physic::PhysicEn { } -Debugging::~Debugging() +Pathgrid::~Pathgrid() { if (mPathgridEnabled) { @@ -143,7 +141,7 @@ Debugging::~Debugging() } -bool Debugging::toggleRenderMode (int mode){ +bool Pathgrid::toggleRenderMode (int mode){ switch (mode) { case Render_Pathgrid: @@ -156,21 +154,21 @@ bool Debugging::toggleRenderMode (int mode){ return false; } -void Debugging::addCell(const MWWorld::CellStore *store) +void Pathgrid::addCell(const MWWorld::CellStore *store) { mActiveCells.push_back(store); if (mPathgridEnabled) enableCellPathgrid(store); } -void Debugging::removeCell(const MWWorld::CellStore *store) +void Pathgrid::removeCell(const MWWorld::CellStore *store) { mActiveCells.erase(std::remove(mActiveCells.begin(), mActiveCells.end(), store), mActiveCells.end()); if (mPathgridEnabled) disableCellPathgrid(store); } -void Debugging::togglePathgrid() +void Pathgrid::togglePathgrid() { mPathgridEnabled = !mPathgridEnabled; if (mPathgridEnabled) @@ -201,7 +199,7 @@ void Debugging::togglePathgrid() } } -void Debugging::enableCellPathgrid(const MWWorld::CellStore *store) +void Pathgrid::enableCellPathgrid(const MWWorld::CellStore *store) { MWBase::World* world = MWBase::Environment::get().getWorld(); const ESM::Pathgrid *pathgrid = @@ -242,7 +240,7 @@ void Debugging::enableCellPathgrid(const MWWorld::CellStore *store) } } -void Debugging::disableCellPathgrid(const MWWorld::CellStore *store) +void Pathgrid::disableCellPathgrid(const MWWorld::CellStore *store) { if (store->getCell()->isExterior()) { diff --git a/apps/openmw/mwrender/debugging.hpp b/apps/openmw/mwrender/pathgrid.hpp similarity index 81% rename from apps/openmw/mwrender/debugging.hpp rename to apps/openmw/mwrender/pathgrid.hpp index 4ec5bc41d..39a6d71ed 100644 --- a/apps/openmw/mwrender/debugging.hpp +++ b/apps/openmw/mwrender/pathgrid.hpp @@ -14,14 +14,6 @@ namespace ESM struct Pathgrid; } -namespace OEngine -{ - namespace Physic - { - class PhysicEngine; - } -} - namespace osg { class Group; @@ -36,11 +28,8 @@ namespace MWWorld namespace MWRender { - class Debugging + class Pathgrid { - //OEngine::Physic::PhysicEngine* mEngine; - - // Path grid stuff bool mPathgridEnabled; void togglePathgrid(); @@ -63,8 +52,8 @@ namespace MWRender osg::ref_ptr createPathgridLines(const ESM::Pathgrid *pathgrid); osg::ref_ptr createPathgridPoints(const ESM::Pathgrid *pathgrid); public: - Debugging(osg::ref_ptr root /*, OEngine::Physic::PhysicEngine *engine*/); - ~Debugging(); + Pathgrid(osg::ref_ptr root); + ~Pathgrid(); bool toggleRenderMode (int mode); void addCell(const MWWorld::CellStore* store); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 4f13df8e7..4d06d901a 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -29,7 +29,7 @@ #include "effectmanager.hpp" #include "npcanimation.hpp" #include "vismask.hpp" -#include "debugging.hpp" +#include "pathgrid.hpp" namespace MWRender { @@ -93,7 +93,7 @@ namespace MWRender mRootNode->addChild(lightRoot); - mDebugging.reset(new Debugging(mRootNode)); + mPathgrid.reset(new Pathgrid(mRootNode)); mObjects.reset(new Objects(mResourceSystem, lightRoot)); @@ -195,12 +195,12 @@ namespace MWRender void RenderingManager::addCell(const MWWorld::CellStore *store) { - mDebugging->addCell(store); + mPathgrid->addCell(store); } void RenderingManager::removeCell(const MWWorld::CellStore *store) { - mDebugging->removeCell(store); + mPathgrid->removeCell(store); mObjects->removeCell(store); } @@ -212,7 +212,7 @@ namespace MWRender bool RenderingManager::toggleRenderMode(RenderMode mode) { if (mode == Render_CollisionDebug || mode == Render_Pathgrid) - return mDebugging->toggleRenderMode(mode); + return mPathgrid->toggleRenderMode(mode); else if (mode == Render_Wireframe) { return false; diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 334025096..0dc0fe571 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -38,7 +38,7 @@ namespace MWRender class EffectManager; class SkyManager; class NpcAnimation; - class Debugging; + class Pathgrid; class RenderingManager : public MWRender::RenderingInterface { @@ -99,7 +99,7 @@ namespace MWRender osg::ref_ptr mSunLight; - std::auto_ptr mDebugging; + std::auto_ptr mPathgrid; std::auto_ptr mObjects; std::auto_ptr mSky; std::auto_ptr mEffectManager; diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 464f2d605..cb58f0496 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -1,8 +1,6 @@ #ifndef GAME_MWWORLD_WORLDIMP_H #define GAME_MWWORLD_WORLDIMP_H -#include "../mwrender/debugging.hpp" - #include #include @@ -23,6 +21,14 @@ #include +namespace OEngine +{ +namespace Physic +{ + class PhysicEngine; +} +} + namespace osg { class Group; From 1c334a01ced6b05da2e5da54c09c026927be7386 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 4 May 2015 19:04:06 +0200 Subject: [PATCH 1107/3725] one more referenceable that escaped the change into object --- apps/opencs/model/world/columns.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 3172e72e4..9076aa096 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -172,7 +172,7 @@ namespace CSMWorld { ColumnId_Rank, "Rank" }, { ColumnId_Gender, "Gender" }, { ColumnId_PcRank, "PC Rank" }, - { ColumnId_ReferenceableId, "Referenceable ID" }, + { ColumnId_ReferenceableId, "Object ID" }, { ColumnId_ContainerContent, "Content" }, { ColumnId_ItemCount, "Count" }, From 9f6bc1b3a9b141030b4450a7999d6637882741ce Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 4 May 2015 19:06:02 +0200 Subject: [PATCH 1108/3725] increased version number --- CMakeLists.txt | 4 ++-- README.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 07fffd577..7c19c57eb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,8 +19,8 @@ set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/) message(STATUS "Configuring OpenMW...") set(OPENMW_VERSION_MAJOR 0) -set(OPENMW_VERSION_MINOR 35) -set(OPENMW_VERSION_RELEASE 1) +set(OPENMW_VERSION_MINOR 36) +set(OPENMW_VERSION_RELEASE 0) set(OPENMW_VERSION_COMMITHASH "") set(OPENMW_VERSION_TAGHASH "") diff --git a/README.md b/README.md index 811eb8763..f62800e1f 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ OpenMW 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.35.1 +* Version: 0.36.0 * License: GPL (see docs/license/GPL3.txt for more information) * Website: http://www.openmw.org * IRC: #openmw on irc.freenode.net From ee60df1e2717727998fb6a8de7452122df88ffd2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 4 May 2015 22:17:28 +0200 Subject: [PATCH 1109/3725] Split MyGUI rendering into Update, Cull and Draw stages --- .../myguiplatform/myguirendermanager.cpp | 222 ++++++++++++------ .../myguiplatform/myguirendermanager.hpp | 10 +- 2 files changed, 164 insertions(+), 68 deletions(-) diff --git a/components/myguiplatform/myguirendermanager.cpp b/components/myguiplatform/myguirendermanager.cpp index e63756ecd..e1ebf781c 100644 --- a/components/myguiplatform/myguirendermanager.cpp +++ b/components/myguiplatform/myguirendermanager.cpp @@ -46,23 +46,6 @@ namespace { -// Proxy to forward a Drawable's draw call to RenderManager::drawFrame -class Renderable : public osg::Drawable { - osgMyGUI::RenderManager *mParent; - - virtual void drawImplementation(osg::RenderInfo &renderInfo) const - { mParent->drawFrame(renderInfo); } - -public: - Renderable(osgMyGUI::RenderManager *parent=nullptr) : mParent(parent) { } - Renderable(const Renderable ©, const osg::CopyOp ©op=osg::CopyOp::SHALLOW_COPY) - : osg::Drawable(copy, copyop) - , mParent(copy.mParent) - { } - - META_Object(osgMyGUI, Renderable) -}; - // Proxy to forward an OSG resize event to RenderManager::setViewSize class ResizeHandler : public osgGA::GUIEventHandler { osgMyGUI::RenderManager *mParent; @@ -94,6 +77,147 @@ public: namespace osgMyGUI { +class Drawable : public osg::Drawable { + osgMyGUI::RenderManager *mParent; + + // Stage 0: update widget animations and controllers. Run during the Update traversal. + class FrameUpdate : public osg::Drawable::UpdateCallback + { + public: + FrameUpdate() + : mRenderManager(NULL) + { + } + + void setRenderManager(osgMyGUI::RenderManager* renderManager) + { + mRenderManager = renderManager; + } + + virtual void update(osg::NodeVisitor*, osg::Drawable*) + { + if (mRenderManager) + mRenderManager->update(); + } + + private: + osgMyGUI::RenderManager* mRenderManager; + }; + + // Stage 1: collect draw calls. Run during the Cull traversal. + class CollectDrawCalls : public osg::Drawable::CullCallback + { + public: + CollectDrawCalls() + : mRenderManager(NULL) + { + } + + void setRenderManager(osgMyGUI::RenderManager* renderManager) + { + mRenderManager = renderManager; + } + + virtual bool cull(osg::NodeVisitor*, osg::Drawable*, osg::State*) const + { + if (!mRenderManager) + return false; + + mRenderManager->collectDrawCalls(); + return false; + } + + private: + osgMyGUI::RenderManager* mRenderManager; + }; + + // Stage 2: execute the draw calls. Run during the Draw traversal. May run in parallel with the update traversal of the next frame. + virtual void drawImplementation(osg::RenderInfo &renderInfo) const + { + osg::State *state = renderInfo.getState(); + state->disableAllVertexArrays(); + state->setClientActiveTextureUnit(0); + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glEnableClientState(GL_COLOR_ARRAY); + + for (std::vector::const_iterator it = mBatchVector.begin(); it != mBatchVector.end(); ++it) + { + const Batch& batch = *it; + osg::VertexBufferObject *vbo = batch.mVertexBuffer; + osg::Texture2D* texture = batch.mTexture; + if(texture) + state->applyTextureAttribute(0, texture); + + osg::GLBufferObject* bufferobject = state->isVertexBufferObjectSupported() ? vbo->getOrCreateGLBufferObject(state->getContextID()) : 0; + if (bufferobject) + { + state->bindVertexBufferObject(bufferobject); + + glVertexPointer(3, GL_FLOAT, sizeof(MyGUI::Vertex), (char*)NULL); + glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(MyGUI::Vertex), (char*)NULL + 12); + glTexCoordPointer(2, GL_FLOAT, sizeof(MyGUI::Vertex), (char*)NULL + 16); + } + else + { + glVertexPointer(3, GL_FLOAT, sizeof(MyGUI::Vertex), (char*)vbo->getArray(0)->getDataPointer()); + glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(MyGUI::Vertex), (char*)vbo->getArray(0)->getDataPointer() + 12); + glTexCoordPointer(2, GL_FLOAT, sizeof(MyGUI::Vertex), (char*)vbo->getArray(0)->getDataPointer() + 16); + } + + glDrawArrays(GL_TRIANGLES, 0, batch.mVertexCount); + } + + state->unbindVertexBufferObject(); + state->dirtyAllVertexArrays(); + state->disableAllVertexArrays(); + } + +public: + Drawable(osgMyGUI::RenderManager *parent = nullptr) : mParent(parent) + { + setSupportsDisplayList(false); + + osg::ref_ptr collectDrawCalls = new CollectDrawCalls; + collectDrawCalls->setRenderManager(mParent); + setCullCallback(collectDrawCalls); + + osg::ref_ptr frameUpdate = new Drawable::FrameUpdate; + frameUpdate->setRenderManager(mParent); + setUpdateCallback(frameUpdate); + } + Drawable(const Drawable ©, const osg::CopyOp ©op=osg::CopyOp::SHALLOW_COPY) + : osg::Drawable(copy, copyop) + , mParent(copy.mParent) + { + } + + // Defines the necessary information for a draw call + struct Batch + { + // May be empty + osg::ref_ptr mTexture; + + osg::ref_ptr mVertexBuffer; + size_t mVertexCount; + }; + + void addBatch(const Batch& batch) + { + mBatchVector.push_back(batch); + } + + void clear() + { + mBatchVector.clear(); + } + + META_Object(osgMyGUI, Drawable) + +private: + std::vector mBatchVector; +}; + class OSGVertexBuffer : public MyGUI::IVertexBuffer { osg::ref_ptr mBuffer; @@ -213,13 +337,11 @@ void RenderManager::initialise() mUpdate = false; - osg::ref_ptr drawable = new Renderable(this); - drawable->setSupportsDisplayList(false); - drawable->setUseVertexBufferObjects(true); - drawable->setDataVariance(osg::Object::DYNAMIC); + mDrawable = new Drawable(this); + mDrawable->setDataVariance(osg::Object::DYNAMIC); osg::ref_ptr geode = new osg::Geode; - geode->addDrawable(drawable.get()); + geode->addDrawable(mDrawable.get()); osg::ref_ptr camera = new osg::Camera(); camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF); @@ -265,61 +387,25 @@ void RenderManager::destroyVertexBuffer(MyGUI::IVertexBuffer *buffer) void RenderManager::begin() { - osg::State *state = mRenderInfo->getState(); - state->disableAllVertexArrays(); - state->setClientActiveTextureUnit(0); - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glEnableClientState(GL_COLOR_ARRAY); } void RenderManager::doRender(MyGUI::IVertexBuffer *buffer, MyGUI::ITexture *texture, size_t count) { - osg::State *state = mRenderInfo->getState(); - osg::VertexBufferObject *vbo = static_cast(buffer)->getBuffer(); - MYGUI_PLATFORM_ASSERT(vbo, "Vertex buffer is not created"); + Drawable::Batch batch; + batch.mVertexCount = count; + batch.mVertexBuffer = static_cast(buffer)->getBuffer(); + if (texture) + batch.mTexture = static_cast(texture)->getTexture(); - if(texture) - { - osg::Texture2D *tex = static_cast(texture)->getTexture(); - MYGUI_PLATFORM_ASSERT(tex, "Texture is not created"); - state->applyTextureAttribute(0, tex); - } - - osg::GLBufferObject* bufferobject = state->isVertexBufferObjectSupported() ? vbo->getOrCreateGLBufferObject(state->getContextID()) : 0; - if (bufferobject) - { - state->bindVertexBufferObject(bufferobject); - - glVertexPointer(3, GL_FLOAT, sizeof(MyGUI::Vertex), (char*)NULL); - glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(MyGUI::Vertex), (char*)NULL + 12); - glTexCoordPointer(2, GL_FLOAT, sizeof(MyGUI::Vertex), (char*)NULL + 16); - } - else - { - glVertexPointer(3, GL_FLOAT, sizeof(MyGUI::Vertex), (char*)vbo->getArray(0)->getDataPointer()); - glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(MyGUI::Vertex), (char*)vbo->getArray(0)->getDataPointer() + 12); - glTexCoordPointer(2, GL_FLOAT, sizeof(MyGUI::Vertex), (char*)vbo->getArray(0)->getDataPointer() + 16); - } - - glDrawArrays(GL_TRIANGLES, 0, count); + mDrawable->addBatch(batch); } void RenderManager::end() { - osg::State *state = mRenderInfo->getState(); - state->unbindVertexBufferObject(); - state->dirtyAllVertexArrays(); - state->disableAllVertexArrays(); } -void RenderManager::drawFrame(osg::RenderInfo &renderInfo) +void RenderManager::update() { - MyGUI::Gui *gui = MyGUI::Gui::getInstancePtr(); - if(gui == nullptr) return; - - mRenderInfo = &renderInfo; - static MyGUI::Timer timer; static unsigned long last_time = timer.getMilliseconds(); unsigned long now_time = timer.getMilliseconds(); @@ -328,10 +414,12 @@ void RenderManager::drawFrame(osg::RenderInfo &renderInfo) onFrameEvent((float)((double)(time) / (double)1000)); last_time = now_time; +} - begin(); +void RenderManager::collectDrawCalls() +{ + mDrawable->clear(); onRenderToTarget(this, mUpdate); - end(); mUpdate = false; } diff --git a/components/myguiplatform/myguirendermanager.hpp b/components/myguiplatform/myguirendermanager.hpp index 05d0f9a5a..342050d90 100644 --- a/components/myguiplatform/myguirendermanager.hpp +++ b/components/myguiplatform/myguirendermanager.hpp @@ -25,10 +25,13 @@ namespace osg namespace osgMyGUI { +class Drawable; + class RenderManager : public MyGUI::RenderManager, public MyGUI::IRenderTarget { osg::ref_ptr mViewer; osg::ref_ptr mSceneRoot; + osg::ref_ptr mDrawable; Resource::TextureManager* mTextureManager; MyGUI::IntSize mViewSize; @@ -80,20 +83,25 @@ public: /** @see RenderManager::getTexture */ virtual MyGUI::ITexture* getTexture(const std::string &name); + // Called by the update traversal + void update(); + // Called by the cull traversal /** @see IRenderTarget::begin */ virtual void begin(); /** @see IRenderTarget::end */ virtual void end(); /** @see IRenderTarget::doRender */ virtual void doRender(MyGUI::IVertexBuffer *buffer, MyGUI::ITexture *texture, size_t count); + /** @see IRenderTarget::getInfo */ virtual const MyGUI::RenderTargetInfo& getInfo() { return mInfo; } bool checkTexture(MyGUI::ITexture* _texture); /*internal:*/ - void drawFrame(osg::RenderInfo &renderInfo); + + void collectDrawCalls(); void setViewSize(int width, int height); }; From 100d6e5fffd7700d12c79566847d74ef6f7cf2cc Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 5 May 2015 02:38:59 +0200 Subject: [PATCH 1110/3725] Render MyGUI in background thread, i.e. refactor to get rid of DYNAMIC DataVariance --- apps/openmw/mwrender/renderingmanager.cpp | 2 - .../myguiplatform/myguirendermanager.cpp | 37 +++++++++++++------ .../myguiplatform/myguirendermanager.hpp | 3 -- 3 files changed, 26 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 4d06d901a..853ba3834 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -144,8 +144,6 @@ namespace MWRender zNear = 5.f; zFar = mViewDistance; mViewer.getCamera()->setProjectionMatrixAsPerspective(fovy, aspect, zNear, zFar); - - mViewer.getCamera()->setCullMask(mViewer.getCamera()->getCullMask() & (~Mask_GUI)); } RenderingManager::~RenderingManager() diff --git a/components/myguiplatform/myguirendermanager.cpp b/components/myguiplatform/myguirendermanager.cpp index e1ebf781c..d1bf73904 100644 --- a/components/myguiplatform/myguirendermanager.cpp +++ b/components/myguiplatform/myguirendermanager.cpp @@ -7,10 +7,7 @@ #include #include -#include #include -#include -#include #include #include @@ -141,7 +138,9 @@ class Drawable : public osg::Drawable { glEnableClientState(GL_TEXTURE_COORD_ARRAY); glEnableClientState(GL_COLOR_ARRAY); - for (std::vector::const_iterator it = mBatchVector.begin(); it != mBatchVector.end(); ++it) + mReadFrom = (mReadFrom+1)%2; + const std::vector& vec = mBatchVector[mReadFrom]; + for (std::vector::const_iterator it = vec.begin(); it != vec.end(); ++it) { const Batch& batch = *it; osg::VertexBufferObject *vbo = batch.mVertexBuffer; @@ -174,7 +173,10 @@ class Drawable : public osg::Drawable { } public: - Drawable(osgMyGUI::RenderManager *parent = nullptr) : mParent(parent) + Drawable(osgMyGUI::RenderManager *parent = nullptr) + : mParent(parent) + , mWriteTo(0) + , mReadFrom(0) { setSupportsDisplayList(false); @@ -182,7 +184,7 @@ public: collectDrawCalls->setRenderManager(mParent); setCullCallback(collectDrawCalls); - osg::ref_ptr frameUpdate = new Drawable::FrameUpdate; + osg::ref_ptr frameUpdate = new FrameUpdate; frameUpdate->setRenderManager(mParent); setUpdateCallback(frameUpdate); } @@ -199,30 +201,35 @@ public: osg::ref_ptr mTexture; osg::ref_ptr mVertexBuffer; + // need to hold on to this too as the mVertexBuffer does not hold a ref to its own array + osg::ref_ptr mArray; + size_t mVertexCount; }; void addBatch(const Batch& batch) { - mBatchVector.push_back(batch); + mBatchVector[mWriteTo].push_back(batch); } void clear() { - mBatchVector.clear(); + mWriteTo = (mWriteTo+1)%2; + mBatchVector[mWriteTo].clear(); } META_Object(osgMyGUI, Drawable) private: - std::vector mBatchVector; + std::vector mBatchVector[2]; + int mWriteTo; + mutable int mReadFrom; }; class OSGVertexBuffer : public MyGUI::IVertexBuffer { osg::ref_ptr mBuffer; osg::ref_ptr mVertexArray; - std::vector mLockedData; size_t mNeedVertexCount; @@ -241,6 +248,7 @@ public: void create(); osg::VertexBufferObject *getBuffer() const { return mBuffer.get(); } + osg::UByteArray *getArray() const { return mVertexArray.get(); } }; OSGVertexBuffer::OSGVertexBuffer() @@ -270,6 +278,12 @@ size_t OSGVertexBuffer::getVertexCount() MyGUI::Vertex *OSGVertexBuffer::lock() { + // Force recreating the buffer, to make sure we are not modifying a buffer currently + // queued for rendering in the last frame's draw thread. + // a more efficient solution might be double buffering + destroy(); + create(); + MYGUI_PLATFORM_ASSERT(mBuffer.valid(), "Vertex buffer is not created"); mVertexArray->resize(mNeedVertexCount * sizeof(MyGUI::Vertex)); @@ -297,6 +311,7 @@ void OSGVertexBuffer::create() mBuffer = new osg::VertexBufferObject; mBuffer->setDataVariance(osg::Object::DYNAMIC); mBuffer->setUsage(GL_DYNAMIC_DRAW); + // NB mBuffer does not own the array mBuffer->setArray(0, mVertexArray.get()); } @@ -338,7 +353,6 @@ void RenderManager::initialise() mUpdate = false; mDrawable = new Drawable(this); - mDrawable->setDataVariance(osg::Object::DYNAMIC); osg::ref_ptr geode = new osg::Geode; geode->addDrawable(mDrawable.get()); @@ -394,6 +408,7 @@ void RenderManager::doRender(MyGUI::IVertexBuffer *buffer, MyGUI::ITexture *text Drawable::Batch batch; batch.mVertexCount = count; batch.mVertexBuffer = static_cast(buffer)->getBuffer(); + batch.mArray = static_cast(buffer)->getArray(); if (texture) batch.mTexture = static_cast(texture)->getTexture(); diff --git a/components/myguiplatform/myguirendermanager.hpp b/components/myguiplatform/myguirendermanager.hpp index 342050d90..afb07eaa6 100644 --- a/components/myguiplatform/myguirendermanager.hpp +++ b/components/myguiplatform/myguirendermanager.hpp @@ -46,9 +46,6 @@ class RenderManager : public MyGUI::RenderManager, public MyGUI::IRenderTarget osg::ref_ptr mGuiRoot; - // Only valid during drawFrame()! - osg::RenderInfo *mRenderInfo; - void destroyAllResources(); public: From e9ef9eedae94cee61d71f951fa740eb83953c178 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 5 May 2015 10:51:48 +0200 Subject: [PATCH 1111/3725] updated changelog --- CHANGELOG.md | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1766aa21d..15464b1d7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,42 @@ +0.36.0 +------ + + Bug #923: Editor: Operations-Multithreading is broken + Bug #1317: Erene Llenim in Seyda Neen does not walk around + Bug #1621: "Error Detecting Morrowind Installation" in the default directory + Bug #2216: Creating a clone of the player stops you moving. + Bug #2387: Casting bound weapon spell doesn't switch to "ready weapon" mode + Bug #2407: Default to (0, 0) when "unknown cell" is encountered. + Bug #2411: enchanted item charges don't update/refresh if spell list window is pinned open + Bug #2428: Editor: cloning / creating new container class results in invalid omwaddon file - openmw-0.35 + Bug #2429: Editor - cloning omits some values or sets different values than the original has + Bug #2430: NPC with negative fatigue don't fall (LGNPC Vivec, Foreign Quarter v2.21) + Bug #2432: Error on startup with Uvirith's Legacy enabled + Bug #2435: Editor: changed entries in the objects window are not shown as such + Bug #2437: Editor: changing an entry of a container/NPC/clothing/ingredient/globals will not be saved in the omwaddon file + Bug #2447: Editor doesn't save terrain information + Bug #2451: Editor not listing files with accented characters + Bug #2453: Chargen: sex, race and hair sliders not initialized properly + Bug #2459: Minor terrain clipping through statics due to difference in triangle alignment + Bug #2461: Invisible sound mark has collision in Sandus Ancestral Tomb + Bug #2465: tainted gold stack + Bug #2475: cumulative stacks of 100 point fortify skill speechcraft boosts do not apply correctly + Bug #2498: Editor: crash when issuing undo command after the table subview is closed + Bug #2500: Editor: object table - can't undo delete record + Feature #139: Editor: Global Search & Replace + Feature #1219: Editor: Add dialogue mode only columns + Feature #2024: Hotkey for hand to hand (i.e. unequip any weapon) + Feature #2119: "Always Sneak" key bind + Feature #2262: Editor: Handle moved instances + Feature #2425: Editor: Add start script table + Feature #2426: Editor: start script record verifier + Feature #2480: Launcher: Multiselect entries in the Data Files list + Feature #2505: Editor: optionally show a line number column in the script editor + Feature #2512: Editor: Offer use of monospace fonts in the script editor as an option + Feature #2514: Editor: focus on ID input field on clone/add + Task #2460: OS X: Use Application Support directory as user data path + Task #2516: Editor: Change References / Referenceables terminology + 0.35.1 ------ From 60fffec3452c68ef2675a7c573af0436c051a6d4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 5 May 2015 16:08:01 +0200 Subject: [PATCH 1112/3725] Collision fix --- libs/openengine/bullet/physic.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index 22312e3bc..17d4aeab5 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -480,7 +480,7 @@ namespace Physic #endif bool needDelete = false; - if (btBvhTriangleMeshShape* triangleShape = dynamic_cast(shape->mCollisionShape)) + if (btBvhTriangleMeshShape* triangleShape = dynamic_cast(collisionShape)) { btScaledBvhTriangleMeshShape* scaled = new btScaledBvhTriangleMeshShape(triangleShape, btVector3(scale,scale,scale)); collisionShape = scaled; From f760aebc926432d364292c9e916e72c4f4f46623 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 5 May 2015 17:55:38 +0200 Subject: [PATCH 1113/3725] Disable MyGUI VBOs due to crashes (will look into proper fix) --- components/myguiplatform/myguirendermanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/myguiplatform/myguirendermanager.cpp b/components/myguiplatform/myguirendermanager.cpp index d1bf73904..e9a6f8c4e 100644 --- a/components/myguiplatform/myguirendermanager.cpp +++ b/components/myguiplatform/myguirendermanager.cpp @@ -148,7 +148,7 @@ class Drawable : public osg::Drawable { if(texture) state->applyTextureAttribute(0, texture); - osg::GLBufferObject* bufferobject = state->isVertexBufferObjectSupported() ? vbo->getOrCreateGLBufferObject(state->getContextID()) : 0; + osg::GLBufferObject* bufferobject = 0;//state->isVertexBufferObjectSupported() ? vbo->getOrCreateGLBufferObject(state->getContextID()) : 0; if (bufferobject) { state->bindVertexBufferObject(bufferobject); From 604580d75dbb225005b91841dc09c66785c0692c Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 7 May 2015 21:17:15 +0200 Subject: [PATCH 1114/3725] Move toMatrix to Nif::Node --- components/nif/niftypes.hpp | 13 ++++ components/nifbullet/bulletnifloader.cpp | 93 +++++++----------------- components/nifbullet/bulletnifloader.hpp | 4 +- components/nifosg/nifloader.cpp | 22 +----- 4 files changed, 44 insertions(+), 88 deletions(-) diff --git a/components/nif/niftypes.hpp b/components/nif/niftypes.hpp index 7fefb92a2..d95180145 100644 --- a/components/nif/niftypes.hpp +++ b/components/nif/niftypes.hpp @@ -25,6 +25,7 @@ #define OPENMW_COMPONENTS_NIF_NIFTYPES_HPP #include +#include // Common types used in NIF files @@ -49,6 +50,18 @@ struct Transformation Matrix3 rotation; // this can contain scale components too, including negative and nonuniform scales float scale; + osg::Matrixf toMatrix() const + { + osg::Matrixf transform; + transform.setTrans(pos); + + for (int i=0;i<3;++i) + for (int j=0;j<3;++j) + transform(j,i) = rotation.mValues[i][j] * scale; // NB column/row major difference + + return transform; + } + static const Transformation& getIdentity() { static const Transformation identity = { diff --git a/components/nifbullet/bulletnifloader.cpp b/components/nifbullet/bulletnifloader.cpp index 1d07bea26..0ddb6291c 100644 --- a/components/nifbullet/bulletnifloader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -41,55 +41,16 @@ http://www.gnu.org/licenses/ . // For warning messages #include -// Extract a list of keyframe-controlled nodes from a .kf file -// FIXME: this is a similar copy of OgreNifLoader::loadKf -void extractControlledNodes(Nif::NIFFilePtr kfFile, std::set& controlled) +namespace { - if(kfFile->numRoots() < 1) - { - kfFile->warn("Found no root nodes in "+kfFile->getFilename()+"."); - return; - } - const Nif::Record *r = kfFile->getRoot(0); - assert(r != NULL); - - if(r->recType != Nif::RC_NiSequenceStreamHelper) - { - kfFile->warn("First root was not a NiSequenceStreamHelper, but a "+ - r->recName+"."); - return; - } - const Nif::NiSequenceStreamHelper *seq = static_cast(r); - - Nif::ExtraPtr extra = seq->extra; - if(extra.empty() || extra->recType != Nif::RC_NiTextKeyExtraData) - { - kfFile->warn("First extra data was not a NiTextKeyExtraData, but a "+ - (extra.empty() ? std::string("nil") : extra->recName)+"."); - return; - } - - extra = extra->extra; - Nif::ControllerPtr ctrl = seq->controller; - for(;!extra.empty() && !ctrl.empty();(extra=extra->extra),(ctrl=ctrl->next)) - { - if(extra->recType != Nif::RC_NiStringExtraData || ctrl->recType != Nif::RC_NiKeyframeController) - { - kfFile->warn("Unexpected extra data "+extra->recName+" with controller "+ctrl->recName); - continue; - } - - if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active)) - continue; - - const Nif::NiStringExtraData *strdata = static_cast(extra.getPtr()); - const Nif::NiKeyframeController *key = static_cast(ctrl.getPtr()); +osg::Matrixf getWorldTransform(const Nif::Node *node) +{ + if(node->parent != NULL) + return node->trafo.toMatrix() * getWorldTransform(node->parent); + return node->trafo.toMatrix(); +} - if(key->data.empty()) - continue; - controlled.insert(strdata->string); - } } namespace NifBullet @@ -133,7 +94,7 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource) if (Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(kfname)) { Nif::NIFFilePtr kf;// (Nif::Cache::getInstance().load(kfname)); - extractControlledNodes(kf, mControlledNodes); + //extractControlledNodes(kf, mControlledNodes); } Nif::Record *r = nif.getRoot(0); @@ -259,7 +220,7 @@ void ManualBulletShapeLoader::handleNode(const Nif::Node *node, int flags, } else if(node->recType == Nif::RC_NiTriShape) { - handleNiTriShape(static_cast(node), flags, Ogre::Matrix4()/*node->getWorldTransform()*/, isAnimated); + handleNiTriShape(static_cast(node), flags, getWorldTransform(node), isAnimated); } } @@ -276,7 +237,7 @@ void ManualBulletShapeLoader::handleNode(const Nif::Node *node, int flags, } } -void ManualBulletShapeLoader::handleNiTriShape(const Nif::NiTriShape *shape, int flags, const Ogre::Matrix4 &transform, bool isAnimated) +void ManualBulletShapeLoader::handleNiTriShape(const Nif::NiTriShape *shape, int flags, const osg::Matrixf &transform, bool isAnimated) { assert(shape != NULL); @@ -312,18 +273,18 @@ void ManualBulletShapeLoader::handleNiTriShape(const Nif::NiTriShape *shape, int childMesh->preallocateVertices(data->vertices.size()); childMesh->preallocateIndices(data->triangles.size()); - //const std::vector &vertices = data->vertices; - //const std::vector &triangles = data->triangles; + const std::vector &vertices = data->vertices; + const std::vector &triangles = data->triangles; for(size_t i = 0;i < data->triangles.size();i+=3) { - //Ogre::Vector3 b1 = vertices[triangles[i+0]]; - //Ogre::Vector3 b2 = vertices[triangles[i+1]]; - //Ogre::Vector3 b3 = vertices[triangles[i+2]]; - //childMesh->addTriangle(btVector3(b1.x,b1.y,b1.z),btVector3(b2.x,b2.y,b2.z),btVector3(b3.x,b3.y,b3.z)); + osg::Vec3f b1 = vertices[triangles[i+0]]; + osg::Vec3f b2 = vertices[triangles[i+1]]; + osg::Vec3f b3 = vertices[triangles[i+2]]; + childMesh->addTriangle(btVector3(b1.x(),b1.y(),b1.z()),btVector3(b2.x(),b2.y(),b2.z()),btVector3(b3.x(),b3.y(),b3.z())); } - //TriangleMeshShape* childShape = new TriangleMeshShape(childMesh,true); + TriangleMeshShape* childShape = new TriangleMeshShape(childMesh,true); float scale = shape->trafo.scale; const Nif::Node* parent = shape; @@ -332,15 +293,15 @@ void ManualBulletShapeLoader::handleNiTriShape(const Nif::NiTriShape *shape, int parent = parent->parent; scale *= parent->trafo.scale; } - //Ogre::Quaternion q = transform.extractQuaternion(); - //Ogre::Vector3 v = transform.getTrans(); - //childShape->setLocalScaling(btVector3(scale, scale, scale)); + osg::Quat q = transform.getRotate(); + osg::Vec3f v = transform.getTrans(); + childShape->setLocalScaling(btVector3(scale, scale, scale)); - //btTransform trans(btQuaternion(q.x, q.y, q.z, q.w), btVector3(v.x, v.y, v.z)); + btTransform trans(btQuaternion(q.x(), q.y(), q.z(), q.w()), btVector3(v.x(), v.y(), v.z())); - //mShape->mAnimatedShapes.insert(std::make_pair(shape->recIndex, mCompoundShape->getNumChildShapes())); + mShape->mAnimatedShapes.insert(std::make_pair(shape->recIndex, mCompoundShape->getNumChildShapes())); - //mCompoundShape->addChildShape(trans, childShape); + mCompoundShape->addChildShape(trans, childShape); } else { @@ -349,17 +310,15 @@ void ManualBulletShapeLoader::handleNiTriShape(const Nif::NiTriShape *shape, int // Static shape, just transform all vertices into position const Nif::NiTriShapeData *data = shape->data.getPtr(); - //const std::vector &vertices = data->vertices; - //const std::vector &triangles = data->triangles; + const std::vector &vertices = data->vertices; + const std::vector &triangles = data->triangles; for(size_t i = 0;i < data->triangles.size();i+=3) { - /* osg::Vec3f b1 = transform*vertices[triangles[i+0]]; osg::Vec3f b2 = transform*vertices[triangles[i+1]]; osg::Vec3f b3 = transform*vertices[triangles[i+2]]; - mStaticMesh->addTriangle(btVector3(b1.x,b1.y,b1.z),btVector3(b2.x,b2.y,b2.z),btVector3(b3.x,b3.y,b3.z)); - */ + mStaticMesh->addTriangle(btVector3(b1.x(),b1.y(),b1.z()),btVector3(b2.x(),b2.y(),b2.z()),btVector3(b3.x(),b3.y(),b3.z())); } } } diff --git a/components/nifbullet/bulletnifloader.hpp b/components/nifbullet/bulletnifloader.hpp index 3ffb6ac8f..733e9264b 100644 --- a/components/nifbullet/bulletnifloader.hpp +++ b/components/nifbullet/bulletnifloader.hpp @@ -32,6 +32,8 @@ #include #include +#include + // For warning messages #include @@ -117,7 +119,7 @@ private: /** *convert a NiTriShape to a bullet trishape. */ - void handleNiTriShape(const Nif::NiTriShape *shape, int flags, const Ogre::Matrix4 &transform, bool isAnimated); + void handleNiTriShape(const Nif::NiTriShape *shape, int flags, const osg::Matrixf& transform, bool isAnimated); std::string mResourceName; diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 936f266dd..adf7e94b4 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -49,24 +49,6 @@ namespace { - osg::Matrixf toMatrix(const Nif::Transformation& nifTrafo) - { - osg::Matrixf transform; - transform.setTrans(nifTrafo.pos); - - for (int i=0;i<3;++i) - for (int j=0;j<3;++j) - transform(j,i) = nifTrafo.rotation.mValues[i][j] * nifTrafo.scale; // NB column/row major difference - - return transform; - } - - osg::Matrixf getWorldTransform(const Nif::Node* node) - { - if(node->parent != NULL) - return toMatrix(node->trafo) * getWorldTransform(node->parent); - return toMatrix(node->trafo); - } void getAllNiNodes(const Nif::Node* node, std::vector& outIndices) { @@ -467,7 +449,7 @@ namespace NifOsg static osg::ref_ptr handleNode(const Nif::Node* nifNode, osg::Group* parentNode, Resource::TextureManager* textureManager, std::map boundTextures, int animflags, int particleflags, bool skipMeshes, TextKeyMap* textKeys, osg::Node* rootNode=NULL) { - osg::ref_ptr transformNode = new osg::MatrixTransform(toMatrix(nifNode->trafo)); + osg::ref_ptr transformNode = new osg::MatrixTransform(nifNode->trafo.toMatrix()); if (nifNode->recType == Nif::RC_NiBillboardNode) { @@ -1072,7 +1054,7 @@ namespace NifOsg std::pair indexWeight = std::make_pair(weights[j].vertex, weights[j].weight); influence.mWeights.insert(indexWeight); } - influence.mInvBindMatrix = toMatrix(data->bones[i].trafo); + influence.mInvBindMatrix = data->bones[i].trafo.toMatrix(); influence.mBoundSphere = osg::BoundingSpheref(data->bones[i].boundSphereCenter, data->bones[i].boundSphereRadius); map->mMap.insert(std::make_pair(boneName, influence)); From 77f733362c1c393f55e1c3faafed3051114ea17b Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 7 May 2015 21:57:02 +0200 Subject: [PATCH 1115/3725] Add stats graphs for Script, Mechanics and Physics timings --- apps/openmw/engine.cpp | 40 +++++++++++++++++++++-- apps/openmw/engine.hpp | 2 ++ apps/openmw/mwrender/objects.cpp | 5 --- apps/openmw/mwrender/objects.hpp | 3 -- apps/openmw/mwrender/renderingmanager.cpp | 1 - 5 files changed, 39 insertions(+), 12 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index d91d32a28..368af216f 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -76,6 +76,7 @@ void OMW::Engine::frame(float frametime) { try { + mStartTick = mViewer->getStartTick(); mEnvironment.setFrameDuration (frametime); // update input @@ -99,6 +100,7 @@ void OMW::Engine::frame(float frametime) // update game state MWBase::Environment::get().getStateManager()->update (frametime); + osg::Timer_t beforeScriptTick = osg::Timer::instance()->tick(); if (MWBase::Environment::get().getStateManager()->getState()== MWBase::StateManager::State_Running) { @@ -120,15 +122,17 @@ void OMW::Engine::frame(float frametime) MWBase::Environment::get().getWorld()->advanceTime( frametime*MWBase::Environment::get().getWorld()->getTimeScaleFactor()/3600); } - + osg::Timer_t afterScriptTick = osg::Timer::instance()->tick(); // update actors + osg::Timer_t beforeMechanicsTick = osg::Timer::instance()->tick(); if (MWBase::Environment::get().getStateManager()->getState()!= MWBase::StateManager::State_NoGame) { MWBase::Environment::get().getMechanicsManager()->update(frametime, guiActive); } + osg::Timer_t afterMechanicsTick = osg::Timer::instance()->tick(); if (MWBase::Environment::get().getStateManager()->getState()== MWBase::StateManager::State_Running) @@ -139,11 +143,13 @@ void OMW::Engine::frame(float frametime) } // update world + osg::Timer_t beforePhysicsTick = osg::Timer::instance()->tick();; if (MWBase::Environment::get().getStateManager()->getState()!= MWBase::StateManager::State_NoGame) { MWBase::Environment::get().getWorld()->update(frametime, guiActive); } + osg::Timer_t afterPhysicsTick = osg::Timer::instance()->tick(); // update GUI MWBase::Environment::get().getWindowManager()->onFrame(frametime); @@ -155,6 +161,21 @@ void OMW::Engine::frame(float frametime) #endif MWBase::Environment::get().getWindowManager()->update(); } + + int frameNumber = mViewer->getFrameStamp()->getFrameNumber(); + osg::Stats* stats = mViewer->getViewerStats(); + stats->setAttribute(frameNumber, "script_time_begin", osg::Timer::instance()->delta_s(mStartTick, beforeScriptTick)); + stats->setAttribute(frameNumber, "script_time_taken", osg::Timer::instance()->delta_s(beforeScriptTick, afterScriptTick)); + stats->setAttribute(frameNumber, "script_time_end", osg::Timer::instance()->delta_s(mStartTick, afterScriptTick)); + + stats->setAttribute(frameNumber, "mechanics_time_begin", osg::Timer::instance()->delta_s(mStartTick, beforeMechanicsTick)); + stats->setAttribute(frameNumber, "mechanics_time_taken", osg::Timer::instance()->delta_s(beforeMechanicsTick, afterMechanicsTick)); + stats->setAttribute(frameNumber, "mechanics_time_end", osg::Timer::instance()->delta_s(mStartTick, afterMechanicsTick)); + + stats->setAttribute(frameNumber, "physics_time_begin", osg::Timer::instance()->delta_s(mStartTick, beforePhysicsTick)); + stats->setAttribute(frameNumber, "physics_time_taken", osg::Timer::instance()->delta_s(beforePhysicsTick, afterPhysicsTick)); + stats->setAttribute(frameNumber, "physics_time_end", osg::Timer::instance()->delta_s(mStartTick, afterPhysicsTick)); + } catch (const std::exception& e) { @@ -194,6 +215,8 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) throw std::runtime_error("Could not initialize SDL! " + std::string(SDL_GetError())); } } + + mStartTick = osg::Timer::instance()->tick(); } OMW::Engine::~Engine() @@ -430,7 +453,7 @@ void OMW::Engine::go() { MWBase::Environment::get().getStateManager()->loadGame(mSaveGameFile); } - else if (0)// !mSkipMenu) + else if (!mSkipMenu) { // start in main menu MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_MainMenu); @@ -452,7 +475,18 @@ void OMW::Engine::go() // Start the main rendering loop mViewer->setCameraManipulator(new osgGA::TrackballManipulator); - mViewer->addEventHandler(new osgViewer::StatsHandler); + + osg::ref_ptr statshandler = new osgViewer::StatsHandler; + + statshandler->addUserStatsLine("Script", osg::Vec4f(1.f, 1.f, 1.f, 1.f), osg::Vec4f(1.f, 1.f, 1.f, 1.f), + "script_time_taken", 1000.0, true, false, "script_time_begin", "script_time_end", 10000); + statshandler->addUserStatsLine("Mechanics", osg::Vec4f(1.f, 1.f, 1.f, 1.f), osg::Vec4f(1.f, 1.f, 1.f, 1.f), + "mechanics_time_taken", 1000.0, true, false, "mechanics_time_begin", "mechanics_time_end", 10000); + statshandler->addUserStatsLine("Physics", osg::Vec4f(1.f, 1.f, 1.f, 1.f), osg::Vec4f(1.f, 1.f, 1.f, 1.f), + "physics_time_taken", 1000.0, true, false, "physics_time_begin", "physics_time_end", 10000); + + mViewer->addEventHandler(statshandler); + osg::Timer frameTimer; while (!mViewer->done() && !MWBase::Environment::get().getStateManager()->hasQuitRequest()) diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index b47a7bb76..e94b5e3ff 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -96,6 +96,8 @@ namespace OMW bool mScriptBlacklistUse; bool mNewGame; + osg::Timer_t mStartTick; + // not implemented Engine (const Engine&); Engine& operator= (const Engine&); diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 69311c111..17fbbe549 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -198,11 +198,6 @@ void Objects::removeCell(const MWWorld::CellStore* store) } } -void Objects::update(float dt) -{ - -} - void Objects::updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur) { /* diff --git a/apps/openmw/mwrender/objects.hpp b/apps/openmw/mwrender/objects.hpp index fd6ceab54..e920869b9 100644 --- a/apps/openmw/mwrender/objects.hpp +++ b/apps/openmw/mwrender/objects.hpp @@ -63,9 +63,6 @@ public: Animation* getAnimation(const MWWorld::Ptr &ptr); - void update (float dt); - ///< per-frame update - //Ogre::AxisAlignedBox getDimensions(MWWorld::CellStore*); ///< get a bounding box that encloses all objects in the specified cell diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 853ba3834..c9bf22009 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -248,7 +248,6 @@ namespace MWRender void RenderingManager::update(float dt, bool paused) { - mObjects->update(dt); mEffectManager->update(dt); mSky->update(dt); } From 00f4f7871730e43a9ee0cc0c12fff8fe3e5b1071 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 7 May 2015 23:08:52 +0200 Subject: [PATCH 1116/3725] Give a name to video streams for logging purposes --- apps/openmw/mwgui/videowidget.cpp | 2 +- extern/osg-ffmpeg-videoplayer/videoplayer.cpp | 4 ++-- extern/osg-ffmpeg-videoplayer/videoplayer.hpp | 3 ++- extern/osg-ffmpeg-videoplayer/videostate.cpp | 8 +++----- extern/osg-ffmpeg-videoplayer/videostate.hpp | 2 +- 5 files changed, 9 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwgui/videowidget.cpp b/apps/openmw/mwgui/videowidget.cpp index 13fabfeed..2c9b1c97e 100644 --- a/apps/openmw/mwgui/videowidget.cpp +++ b/apps/openmw/mwgui/videowidget.cpp @@ -30,7 +30,7 @@ void VideoWidget::playVideo(const std::string &video) { mPlayer->setAudioFactory(new MWSound::MovieAudioFactory()); - mPlayer->playVideo(mVFS->get(video)); + mPlayer->playVideo(mVFS->get(video), video); osg::ref_ptr texture = mPlayer->getVideoTexture(); if (!texture) diff --git a/extern/osg-ffmpeg-videoplayer/videoplayer.cpp b/extern/osg-ffmpeg-videoplayer/videoplayer.cpp index 1336e45a3..9bd4a2df3 100644 --- a/extern/osg-ffmpeg-videoplayer/videoplayer.cpp +++ b/extern/osg-ffmpeg-videoplayer/videoplayer.cpp @@ -25,7 +25,7 @@ void VideoPlayer::setAudioFactory(MovieAudioFactory *factory) mAudioFactory.reset(factory); } -void VideoPlayer::playVideo(boost::shared_ptr inputstream) +void VideoPlayer::playVideo(boost::shared_ptr inputstream, const std::string& name) { if(mState) close(); @@ -33,7 +33,7 @@ void VideoPlayer::playVideo(boost::shared_ptr inputstream) try { mState = new VideoState; mState->setAudioFactory(mAudioFactory.get()); - mState->init(inputstream); + mState->init(inputstream, name); // wait until we have the first picture while (mState->video_st && !mState->mTexture.get()) diff --git a/extern/osg-ffmpeg-videoplayer/videoplayer.hpp b/extern/osg-ffmpeg-videoplayer/videoplayer.hpp index 261246f39..b886257e7 100644 --- a/extern/osg-ffmpeg-videoplayer/videoplayer.hpp +++ b/extern/osg-ffmpeg-videoplayer/videoplayer.hpp @@ -41,7 +41,8 @@ namespace Video /// Play the given video. If a video is already playing, the old video is closed first. /// @note The video will be unpaused by default. Use the pause() and play() methods to control pausing. - void playVideo (boost::shared_ptr inputstream); + /// @param name A name for the video stream - only used for logging purposes. + void playVideo (boost::shared_ptr inputstream, const std::string& name); /// Get the current playback time position in the video, in seconds double getCurrentTime(); diff --git a/extern/osg-ffmpeg-videoplayer/videostate.cpp b/extern/osg-ffmpeg-videoplayer/videostate.cpp index 72fc82f86..4dd618858 100644 --- a/extern/osg-ffmpeg-videoplayer/videostate.cpp +++ b/extern/osg-ffmpeg-videoplayer/videostate.cpp @@ -602,7 +602,7 @@ int VideoState::stream_open(int stream_index, AVFormatContext *pFormatCtx) return 0; } -void VideoState::init(boost::shared_ptr inputstream) +void VideoState::init(boost::shared_ptr inputstream, const std::string &name) { int video_index = -1; int audio_index = -1; @@ -622,8 +622,6 @@ void VideoState::init(boost::shared_ptr inputstream) if(this->format_ctx) this->format_ctx->pb = ioCtx; - std::string videoName; - // Open video file /// /// format_ctx->pb->buffer must be freed by hand, @@ -631,7 +629,7 @@ void VideoState::init(boost::shared_ptr inputstream) /// /// https://trac.ffmpeg.org/ticket/1357 /// - if(!this->format_ctx || avformat_open_input(&this->format_ctx, videoName.c_str(), NULL, NULL)) + if(!this->format_ctx || avformat_open_input(&this->format_ctx, name.c_str(), NULL, NULL)) { if (this->format_ctx != NULL) { @@ -655,7 +653,7 @@ void VideoState::init(boost::shared_ptr inputstream) throw std::runtime_error("Failed to retrieve stream information"); // Dump information about file onto standard error - av_dump_format(this->format_ctx, 0, videoName.c_str(), 0); + av_dump_format(this->format_ctx, 0, name.c_str(), 0); for(i = 0;i < this->format_ctx->nb_streams;i++) { diff --git a/extern/osg-ffmpeg-videoplayer/videostate.hpp b/extern/osg-ffmpeg-videoplayer/videostate.hpp index 40925e014..4a4f2fc6b 100644 --- a/extern/osg-ffmpeg-videoplayer/videostate.hpp +++ b/extern/osg-ffmpeg-videoplayer/videostate.hpp @@ -84,7 +84,7 @@ struct VideoState { void setAudioFactory(MovieAudioFactory* factory); - void init(boost::shared_ptr inputstream); + void init(boost::shared_ptr inputstream, const std::string& name); void deinit(); void setPaused(bool isPaused); From 483dc9de45d63184879cfe6a781bfb4a2d115e11 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 7 May 2015 23:17:30 +0200 Subject: [PATCH 1117/3725] Stop viewer threading before changing MyGUI textures --- apps/openmw/mwgui/windowmanagerimp.cpp | 4 ++++ components/myguiplatform/myguitexture.hpp | 2 ++ 2 files changed, 6 insertions(+) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 6421df824..40180d700 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1092,7 +1092,11 @@ namespace MWGui else if (it->first == "GUI" && it->second == "subtitles") mSubtitlesEnabled = Settings::Manager::getBool ("subtitles", "GUI"); else if (it->first == "GUI" && it->second == "menu transparency") + { + mViewer->stopThreading(); setMenuTransparency(Settings::Manager::getFloat("menu transparency", "GUI")); + mViewer->startThreading(); + } } } diff --git a/components/myguiplatform/myguitexture.hpp b/components/myguiplatform/myguitexture.hpp index de385e94d..109858bc8 100644 --- a/components/myguiplatform/myguitexture.hpp +++ b/components/myguiplatform/myguitexture.hpp @@ -42,6 +42,8 @@ namespace osgMyGUI virtual void destroy(); + /// @warning If you intend to change a texture during the frame update, you must either declare the texture with DataVariance::DYNAMIC + /// or temporarily stop the viewer threading, to prevent race conditions with the draw thread. virtual void* lock(MyGUI::TextureUsage access); virtual void unlock(); virtual bool isLocked(); From cf0fc4300408b2b5c5d91574c3ada05a2dffe402 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 8 May 2015 15:10:17 +0200 Subject: [PATCH 1118/3725] GUI shutdown fix --- apps/openmw/mwgui/windowmanagerimp.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 40180d700..9c7a9de20 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -423,7 +423,10 @@ namespace MWGui mFontLoader.reset(); + mGui->shutdown(); delete mGui; + + mGuiPlatform->shutdown(); delete mGuiPlatform; } From 5db0639983f759103ae157b9e4351fef49ed3802 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 8 May 2015 16:20:40 +0200 Subject: [PATCH 1119/3725] IncrementalCompileOperation tweak --- apps/openmw/mwgui/loadingscreen.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index 45bd5bf9d..d56c77bdd 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -103,6 +103,13 @@ namespace MWGui if (mMainWidget->getVisible()) return; + if (mViewer->getIncrementalCompileOperation()) + { + mViewer->getIncrementalCompileOperation()->setMaximumNumOfObjectsToCompilePerFrame(200); + // keep this in sync with loadingScreenFps + mViewer->getIncrementalCompileOperation()->setTargetFrameRate(1.0/120.0); + } + bool showWallpaper = (MWBase::Environment::get().getStateManager()->getState() == MWBase::StateManager::State_NoGame); @@ -218,8 +225,6 @@ namespace MWGui changeWallpaper(); } - mViewer->getIncrementalCompileOperation()->setMaximumNumOfObjectsToCompilePerFrame(80); - // Turn off rendering except the GUI int oldUpdateMask = mViewer->getUpdateVisitor()->getTraversalMask(); int oldCullMask = mViewer->getCamera()->getCullMask(); @@ -228,8 +233,6 @@ namespace MWGui MWBase::Environment::get().getInputManager()->update(0, true, true); - //std::cout << "num to compile " << mViewer->getIncrementalCompileOperation()->getToCompile().size() << std::endl; - mViewer->frame(); // resume 3d rendering From c8eb77c55740331bf6249e7bf05cbe1f9e006248 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 8 May 2015 16:22:42 +0200 Subject: [PATCH 1120/3725] Move StatsHandler construction to allow profiling of loading screen --- apps/openmw/engine.cpp | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 368af216f..59c3667a4 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -435,6 +435,17 @@ void OMW::Engine::go() mViewer = new osgViewer::Viewer; + osg::ref_ptr statshandler = new osgViewer::StatsHandler; + + statshandler->addUserStatsLine("Script", osg::Vec4f(1.f, 1.f, 1.f, 1.f), osg::Vec4f(1.f, 1.f, 1.f, 1.f), + "script_time_taken", 1000.0, true, false, "script_time_begin", "script_time_end", 10000); + statshandler->addUserStatsLine("Mechanics", osg::Vec4f(1.f, 1.f, 1.f, 1.f), osg::Vec4f(1.f, 1.f, 1.f, 1.f), + "mechanics_time_taken", 1000.0, true, false, "mechanics_time_begin", "mechanics_time_end", 10000); + statshandler->addUserStatsLine("Physics", osg::Vec4f(1.f, 1.f, 1.f, 1.f), osg::Vec4f(1.f, 1.f, 1.f, 1.f), + "physics_time_taken", 1000.0, true, false, "physics_time_begin", "physics_time_end", 10000); + + mViewer->addEventHandler(statshandler); + Settings::Manager settings; std::string settingspath; @@ -476,18 +487,6 @@ void OMW::Engine::go() // Start the main rendering loop mViewer->setCameraManipulator(new osgGA::TrackballManipulator); - osg::ref_ptr statshandler = new osgViewer::StatsHandler; - - statshandler->addUserStatsLine("Script", osg::Vec4f(1.f, 1.f, 1.f, 1.f), osg::Vec4f(1.f, 1.f, 1.f, 1.f), - "script_time_taken", 1000.0, true, false, "script_time_begin", "script_time_end", 10000); - statshandler->addUserStatsLine("Mechanics", osg::Vec4f(1.f, 1.f, 1.f, 1.f), osg::Vec4f(1.f, 1.f, 1.f, 1.f), - "mechanics_time_taken", 1000.0, true, false, "mechanics_time_begin", "mechanics_time_end", 10000); - statshandler->addUserStatsLine("Physics", osg::Vec4f(1.f, 1.f, 1.f, 1.f), osg::Vec4f(1.f, 1.f, 1.f, 1.f), - "physics_time_taken", 1000.0, true, false, "physics_time_begin", "physics_time_end", 10000); - - mViewer->addEventHandler(statshandler); - - osg::Timer frameTimer; while (!mViewer->done() && !MWBase::Environment::get().getStateManager()->hasQuitRequest()) { From 7a2a7633d5d0f2c8b42a66d1bb5ccfb461d3e7b2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 8 May 2015 17:11:40 +0200 Subject: [PATCH 1121/3725] Fix videoplayer destruction issue that valgrind complained about --- extern/osg-ffmpeg-videoplayer/videostate.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/extern/osg-ffmpeg-videoplayer/videostate.cpp b/extern/osg-ffmpeg-videoplayer/videostate.cpp index 4dd618858..dea08de92 100644 --- a/extern/osg-ffmpeg-videoplayer/videostate.cpp +++ b/extern/osg-ffmpeg-videoplayer/videostate.cpp @@ -721,7 +721,12 @@ void VideoState::deinit() avformat_close_input(&this->format_ctx); } - mTexture = NULL; + if (mTexture) + { + // reset Image separately, it's pointing to *this and there might still be outside references to mTexture + mTexture->setImage(NULL); + mTexture = NULL; + } } double VideoState::get_external_clock() From af7cbb2e3ba0828322f9c654987d30165f6b9004 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 8 May 2015 17:52:35 +0200 Subject: [PATCH 1122/3725] Leak fix --- components/resource/resourcesystem.cpp | 5 +++++ components/resource/resourcesystem.hpp | 4 ++++ components/resource/scenemanager.cpp | 5 +++++ components/resource/scenemanager.hpp | 4 ++++ components/resource/texturemanager.cpp | 5 +++++ components/resource/texturemanager.hpp | 4 ++++ 6 files changed, 27 insertions(+) diff --git a/components/resource/resourcesystem.cpp b/components/resource/resourcesystem.cpp index acde8f5d2..bd6824079 100644 --- a/components/resource/resourcesystem.cpp +++ b/components/resource/resourcesystem.cpp @@ -13,6 +13,11 @@ namespace Resource mSceneManager.reset(new SceneManager(vfs, mTextureManager.get())); } + ResourceSystem::~ResourceSystem() + { + // this has to be defined in the .cpp file as we can't delete incomplete types + } + SceneManager* ResourceSystem::getSceneManager() { return mSceneManager.get(); diff --git a/components/resource/resourcesystem.hpp b/components/resource/resourcesystem.hpp index 3bb454785..7c00a11ee 100644 --- a/components/resource/resourcesystem.hpp +++ b/components/resource/resourcesystem.hpp @@ -21,6 +21,7 @@ namespace Resource { public: ResourceSystem(const VFS::Manager* vfs); + ~ResourceSystem(); SceneManager* getSceneManager(); TextureManager* getTextureManager(); @@ -32,6 +33,9 @@ namespace Resource std::auto_ptr mTextureManager; const VFS::Manager* mVFS; + + ResourceSystem(const ResourceSystem&); + void operator = (const ResourceSystem&); }; } diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index 393f322d7..8a0d526fa 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -70,6 +70,11 @@ namespace Resource { } + SceneManager::~SceneManager() + { + // this has to be defined in the .cpp file as we can't delete incomplete types + } + osg::ref_ptr SceneManager::getTemplate(const std::string &name) { std::string normalized = name; diff --git a/components/resource/scenemanager.hpp b/components/resource/scenemanager.hpp index 6a52dfb21..9f3c5387e 100644 --- a/components/resource/scenemanager.hpp +++ b/components/resource/scenemanager.hpp @@ -32,6 +32,7 @@ namespace Resource { public: SceneManager(const VFS::Manager* vfs, Resource::TextureManager* textureManager); + ~SceneManager(); /// Get a read-only copy of this scene "template" osg::ref_ptr getTemplate(const std::string& name); @@ -69,6 +70,9 @@ namespace Resource typedef std::map > KeyframeIndex; KeyframeIndex mKeyframeIndex; + + SceneManager(const SceneManager&); + void operator = (const SceneManager&); }; } diff --git a/components/resource/texturemanager.cpp b/components/resource/texturemanager.cpp index ee75296a7..b9b9fad5f 100644 --- a/components/resource/texturemanager.cpp +++ b/components/resource/texturemanager.cpp @@ -42,6 +42,11 @@ namespace Resource } + TextureManager::~TextureManager() + { + + } + void TextureManager::setUnRefImageDataAfterApply(bool unref) { mUnRefImageDataAfterApply = unref; diff --git a/components/resource/texturemanager.hpp b/components/resource/texturemanager.hpp index d44d47d24..851a55166 100644 --- a/components/resource/texturemanager.hpp +++ b/components/resource/texturemanager.hpp @@ -21,6 +21,7 @@ namespace Resource { public: TextureManager(const VFS::Manager* vfs); + ~TextureManager(); // TODO: texture filtering settings @@ -48,6 +49,9 @@ namespace Resource osg::ref_ptr mWarningTexture; bool mUnRefImageDataAfterApply; + + TextureManager(const TextureManager&); + void operator = (const TextureManager&); }; } From 52a4456cf70669d7bf127730ee6432695d913354 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 9 May 2015 00:02:38 +0200 Subject: [PATCH 1123/3725] LoadingScreen update --- apps/openmw/mwgui/loadingscreen.cpp | 24 ++++++++++++++---------- apps/openmw/mwgui/loadingscreen.hpp | 2 ++ 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index d56c77bdd..cdb2d6bdf 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -30,6 +30,7 @@ namespace MWGui : WindowBase("openmw_loading_screen.layout") , mVFS(vfs) , mViewer(viewer) + , mTargetFrameRate(120.0) , mLastWallpaperChangeTime(0.0) , mLastRenderTime(0.0) , mLoadingOnTime(0.0) @@ -52,6 +53,10 @@ namespace MWGui findSplashScreens(); } + LoadingScreen::~LoadingScreen() + { + } + void LoadingScreen::findSplashScreens() { const std::map& index = mVFS->getIndex(); @@ -86,10 +91,6 @@ namespace MWGui mLoadingBox->setPosition(mMainWidget->getWidth()/2 - mLoadingBox->getWidth()/2, mLoadingBox->getTop()); } - LoadingScreen::~LoadingScreen() - { - } - void LoadingScreen::setVisible(bool visible) { WindowBase::setVisible(visible); @@ -105,9 +106,8 @@ namespace MWGui if (mViewer->getIncrementalCompileOperation()) { - mViewer->getIncrementalCompileOperation()->setMaximumNumOfObjectsToCompilePerFrame(200); - // keep this in sync with loadingScreenFps - mViewer->getIncrementalCompileOperation()->setTargetFrameRate(1.0/120.0); + mViewer->getIncrementalCompileOperation()->setMaximumNumOfObjectsToCompilePerFrame(100); + mViewer->getIncrementalCompileOperation()->setTargetFrameRate(mTargetFrameRate); } bool showWallpaper = (MWBase::Environment::get().getStateManager()->getState() @@ -212,9 +212,7 @@ namespace MWGui void LoadingScreen::draw() { - const float loadingScreenFps = 120.f; - - if (mTimer.time_m() > mLastRenderTime + (1.f/loadingScreenFps) * 1000.f) + if (mTimer.time_m() > mLastRenderTime + (1.0/mTargetFrameRate) * 1000.0) { bool showWallpaper = (MWBase::Environment::get().getStateManager()->getState() == MWBase::StateManager::State_NoGame); @@ -233,7 +231,12 @@ namespace MWGui MWBase::Environment::get().getInputManager()->update(0, true, true); + //osg::Timer timer; mViewer->frame(); + //std::cout << "frame took " << timer.time_m() << std::endl; + + //if (mViewer->getIncrementalCompileOperation()) + //std::cout << "num to compile " << mViewer->getIncrementalCompileOperation()->getToCompile().size() << std::endl; // resume 3d rendering mViewer->getUpdateVisitor()->setTraversalMask(oldUpdateMask); @@ -242,4 +245,5 @@ namespace MWGui mLastRenderTime = mTimer.time_m(); } } + } diff --git a/apps/openmw/mwgui/loadingscreen.hpp b/apps/openmw/mwgui/loadingscreen.hpp index 7c49df027..a1e6e4d21 100644 --- a/apps/openmw/mwgui/loadingscreen.hpp +++ b/apps/openmw/mwgui/loadingscreen.hpp @@ -50,6 +50,8 @@ namespace MWGui const VFS::Manager* mVFS; osg::ref_ptr mViewer; + double mTargetFrameRate; + double mLastWallpaperChangeTime; double mLastRenderTime; osg::Timer mTimer; From d432a3ed08c84d1d7993df2b1bfffbd9f6e26e87 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 9 May 2015 00:13:22 +0200 Subject: [PATCH 1124/3725] Fix MyGUI rendering not taking DataVariance of textures into account --- components/myguiplatform/myguirendermanager.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/components/myguiplatform/myguirendermanager.cpp b/components/myguiplatform/myguirendermanager.cpp index e9a6f8c4e..442b6be78 100644 --- a/components/myguiplatform/myguirendermanager.cpp +++ b/components/myguiplatform/myguirendermanager.cpp @@ -401,6 +401,9 @@ void RenderManager::destroyVertexBuffer(MyGUI::IVertexBuffer *buffer) void RenderManager::begin() { + mDrawable->clear(); + // variance will be recomputed based on textures being rendered in this frame + mDrawable->setDataVariance(osg::Object::STATIC); } void RenderManager::doRender(MyGUI::IVertexBuffer *buffer, MyGUI::ITexture *texture, size_t count) @@ -410,7 +413,11 @@ void RenderManager::doRender(MyGUI::IVertexBuffer *buffer, MyGUI::ITexture *text batch.mVertexBuffer = static_cast(buffer)->getBuffer(); batch.mArray = static_cast(buffer)->getArray(); if (texture) + { batch.mTexture = static_cast(texture)->getTexture(); + if (batch.mTexture->getDataVariance() == osg::Object::DYNAMIC) + mDrawable->setDataVariance(osg::Object::DYNAMIC); // only for this frame, reset in begin() + } mDrawable->addBatch(batch); } @@ -433,8 +440,9 @@ void RenderManager::update() void RenderManager::collectDrawCalls() { - mDrawable->clear(); + begin(); onRenderToTarget(this, mUpdate); + end(); mUpdate = false; } From 0da1e0e905ce0554897b45e0199bba9699c7bfaf Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 9 May 2015 00:17:08 +0200 Subject: [PATCH 1125/3725] Add comment --- components/myguiplatform/myguirendermanager.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/components/myguiplatform/myguirendermanager.cpp b/components/myguiplatform/myguirendermanager.cpp index 442b6be78..3a36a3b10 100644 --- a/components/myguiplatform/myguirendermanager.cpp +++ b/components/myguiplatform/myguirendermanager.cpp @@ -148,6 +148,7 @@ class Drawable : public osg::Drawable { if(texture) state->applyTextureAttribute(0, texture); + // VBOs disabled due to crash in OSG: http://forum.openscenegraph.org/viewtopic.php?t=14909 osg::GLBufferObject* bufferobject = 0;//state->isVertexBufferObjectSupported() ? vbo->getOrCreateGLBufferObject(state->getContextID()) : 0; if (bufferobject) { From 48ffeab191714b62ec679400c883803e3a7961df Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 9 May 2015 01:06:55 +0200 Subject: [PATCH 1126/3725] Remove old BulletShapeManager --- apps/openmw/mwworld/physicssystem.cpp | 5 +- .../myguiplatform/myguirendermanager.cpp | 4 + components/nifbullet/bulletnifloader.cpp | 9 -- components/nifbullet/bulletnifloader.hpp | 9 +- libs/openengine/bullet/BulletShapeLoader.cpp | 88 ------------------- libs/openengine/bullet/BulletShapeLoader.h | 78 ---------------- libs/openengine/bullet/physic.cpp | 33 +++---- libs/openengine/bullet/physic.hpp | 31 ++----- 8 files changed, 25 insertions(+), 232 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 6a08e8e1f..a43ca9178 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -533,9 +533,7 @@ namespace MWWorld PhysicsSystem::PhysicsSystem(osg::ref_ptr parentNode) : mEngine(0), mTimeAccum(0.0f), mWaterEnabled(false), mWaterHeight(0), mDebugDrawEnabled(false), mParentNode(parentNode) { - // Create physics. shapeLoader is deleted by the physic engine - //NifBullet::ManualBulletShapeLoader* shapeLoader = new NifBullet::ManualBulletShapeLoader(); - mEngine = new OEngine::Physic::PhysicEngine(0);//shapeLoader); + mEngine = new OEngine::Physic::PhysicEngine; } PhysicsSystem::~PhysicsSystem() @@ -543,7 +541,6 @@ namespace MWWorld if (mWaterCollisionObject.get()) mEngine->mDynamicsWorld->removeCollisionObject(mWaterCollisionObject.get()); delete mEngine; - //delete OEngine::Physic::BulletShapeManager::getSingletonPtr(); } bool PhysicsSystem::toggleDebugRendering() diff --git a/components/myguiplatform/myguirendermanager.cpp b/components/myguiplatform/myguirendermanager.cpp index 3a36a3b10..3caa61548 100644 --- a/components/myguiplatform/myguirendermanager.cpp +++ b/components/myguiplatform/myguirendermanager.cpp @@ -168,6 +168,10 @@ class Drawable : public osg::Drawable { glDrawArrays(GL_TRIANGLES, 0, batch.mVertexCount); } + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + glDisableClientState(GL_COLOR_ARRAY); + state->unbindVertexBufferObject(); state->dirtyAllVertexArrays(); state->disableAllVertexArrays(); diff --git a/components/nifbullet/bulletnifloader.cpp b/components/nifbullet/bulletnifloader.cpp index 0ddb6291c..b80bbb83f 100644 --- a/components/nifbullet/bulletnifloader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -323,15 +323,6 @@ void ManualBulletShapeLoader::handleNiTriShape(const Nif::NiTriShape *shape, int } } -void ManualBulletShapeLoader::load(const std::string &name,const std::string &group) -{ - // Check if the resource already exists - Ogre::ResourcePtr ptr = OEngine::Physic::BulletShapeManager::getSingleton().getByName(name, group); - if (!ptr.isNull()) - return; - OEngine::Physic::BulletShapeManager::getSingleton().create(name,group,true,this); -} - bool findBoundingBox (const Nif::Node* node, Ogre::Vector3& halfExtents, Ogre::Vector3& translation, Ogre::Quaternion& orientation) { if(node->hasBounds) diff --git a/components/nifbullet/bulletnifloader.hpp b/components/nifbullet/bulletnifloader.hpp index 733e9264b..b3e30cbd9 100644 --- a/components/nifbullet/bulletnifloader.hpp +++ b/components/nifbullet/bulletnifloader.hpp @@ -66,7 +66,7 @@ struct TriangleMeshShape : public btBvhTriangleMeshShape /** *Load bulletShape from NIF files. */ -class ManualBulletShapeLoader : public OEngine::Physic::BulletShapeLoader +class ManualBulletShapeLoader { public: ManualBulletShapeLoader(bool showMarkers=false) @@ -96,13 +96,6 @@ public: */ void loadResource(Ogre::Resource *resource); - /** - *This function load a new bulletShape from a NIF file into the BulletShapeManager. - *When the file is loaded, you can then use BulletShapeManager::getByName() to retrive the bulletShape. - *Warning: this function will just crash if the resourceGroup doesn't exist! - */ - void load(const std::string &name,const std::string &group); - private: btVector3 getbtVector(Ogre::Vector3 const &v); diff --git a/libs/openengine/bullet/BulletShapeLoader.cpp b/libs/openengine/bullet/BulletShapeLoader.cpp index 26b6caa0e..d164b9b23 100644 --- a/libs/openengine/bullet/BulletShapeLoader.cpp +++ b/libs/openengine/bullet/BulletShapeLoader.cpp @@ -62,93 +62,5 @@ size_t BulletShape::calculateSize() const return 1; } - - -//============================================================================================================= -BulletShapeManager *BulletShapeManager::sThis = 0; - -BulletShapeManager *BulletShapeManager::getSingletonPtr() -{ - return sThis; -} - -BulletShapeManager &BulletShapeManager::getSingleton() -{ - assert(sThis); - return(*sThis); -} - -BulletShapeManager::BulletShapeManager() -{ - assert(!sThis); - sThis = this; - - mResourceType = "BulletShape"; - - // low, because it will likely reference other resources - mLoadOrder = 30.0f; - - // this is how we register the ResourceManager with OGRE - Ogre::ResourceGroupManager::getSingleton()._registerResourceManager(mResourceType, this); -} - -BulletShapeManager::~BulletShapeManager() -{ - // and this is how we unregister it - Ogre::ResourceGroupManager::getSingleton()._unregisterResourceManager(mResourceType); - - sThis = 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(); -} - -Ogre::ResourcePtr BulletShapeManager::load(const Ogre::String &name, const Ogre::String &group, - bool isManual, Ogre::ManualResourceLoader *loader, const Ogre::NameValuePairList *loadParams, - bool backgroundThread) -{ - return this->load(name, group); -} - -BulletShapePtr BulletShapeManager::load(const Ogre::String &name, const Ogre::String &group) -{ - BulletShapePtr textf = getByName(name); - - if (textf.isNull()) - textf = create(name, group); - - textf->load(); - return textf; -} - -Ogre::Resource *BulletShapeManager::createImpl(const Ogre::String &name, Ogre::ResourceHandle handle, - const Ogre::String &group, bool isManual, Ogre::ManualResourceLoader *loader, - const Ogre::NameValuePairList *createParams) -{ - BulletShape* res = new BulletShape(this, name, handle, group, isManual, loader); - //if(isManual) - //{ - //loader->loadResource(res); - //} - return res; -} - - -//==================================================================== -void BulletShapeLoader::loadResource(Ogre::Resource *resource) -{} - -void BulletShapeLoader::load(const std::string &name,const std::string &group) -{} - } } diff --git a/libs/openengine/bullet/BulletShapeLoader.h b/libs/openengine/bullet/BulletShapeLoader.h index 472efac6d..a856e8153 100644 --- a/libs/openengine/bullet/BulletShapeLoader.h +++ b/libs/openengine/bullet/BulletShapeLoader.h @@ -53,84 +53,6 @@ public: */ typedef Ogre::SharedPtr BulletShapePtr; - -/** -*Hold any BulletShape that was created by the ManualBulletShapeLoader. -* -*To get a bulletShape, you must load it first. -*First, create a manualBulletShapeLoader. Then call ManualBulletShapeManager->load(). This create an "empty" resource. -*Then use BulletShapeManager->load(). This will fill the resource with the required info. -*To get the resource,use BulletShapeManager::getByName. -*When you use the resource no more, just use BulletShapeManager->unload(). It won't completly delete the resource, but it will -*"empty" it.This allow a better management of memory: when you are leaving a cell, just unload every useless shape. -* -*Alternatively, you can call BulletShape->load() in order to actually load the resource. -*When you are finished with it, just call BulletShape->unload(). -* -*IMO: prefere the first methode, i am not completly sure about the 2nd. -* -*Important Note: i have no idea of what happen if you try to load two time the same resource without unloading. -*It won't crash, but it might lead to memory leaks(I don't know how Ogre handle this). So don't do it! -*/ -class BulletShapeManager : public Ogre::ResourceManager -{ -protected: - - // must implement this from ResourceManager's interface - Ogre::Resource *createImpl(const Ogre::String &name, Ogre::ResourceHandle handle, - const Ogre::String &group, bool isManual, Ogre::ManualResourceLoader *loader, - const Ogre::NameValuePairList *createParams); - - static BulletShapeManager *sThis; - -private: - /** \brief Explicit private copy constructor. This is a forbidden operation.*/ - BulletShapeManager(const BulletShapeManager &); - - /** \brief Private operator= . This is a forbidden operation. */ - BulletShapeManager& operator=(const BulletShapeManager &); - - // Not intended to be used, declared here to keep the compiler from complaining - // about hidden virtual methods. - virtual Ogre::ResourcePtr load(const Ogre::String &name, const Ogre::String &group, - bool isManual, Ogre::ManualResourceLoader *loader, const Ogre::NameValuePairList *loadParams, - bool backgroundThread); - -public: - - BulletShapeManager(); - virtual ~BulletShapeManager(); - - - /// 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); - - virtual BulletShapePtr load(const Ogre::String &name, const Ogre::String &group); - - static BulletShapeManager &getSingleton(); - static BulletShapeManager *getSingletonPtr(); -}; - -class BulletShapeLoader : public Ogre::ManualResourceLoader -{ -public: - - BulletShapeLoader(){}; - virtual ~BulletShapeLoader() {} - - virtual void loadResource(Ogre::Resource *resource); - - virtual void load(const std::string &name,const std::string &group); -}; - } } diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index 889986339..391d266df 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -235,27 +235,25 @@ namespace Physic - PhysicEngine::PhysicEngine(BulletShapeLoader* shapeLoader) + PhysicEngine::PhysicEngine() { // Set up the collision configuration and dispatcher - collisionConfiguration = new btDefaultCollisionConfiguration(); - dispatcher = new btCollisionDispatcher(collisionConfiguration); + mCollisionConfiguration = new btDefaultCollisionConfiguration(); + mDispatcher = new btCollisionDispatcher(mCollisionConfiguration); // The actual physics solver - solver = new btSequentialImpulseConstraintSolver; + mSolver = new btSequentialImpulseConstraintSolver; - broadphase = new btDbvtBroadphase(); + mBroadphase = new btDbvtBroadphase(); // The world. - mDynamicsWorld = new btDiscreteDynamicsWorld(dispatcher,broadphase,solver,collisionConfiguration); + mDynamicsWorld = new btDiscreteDynamicsWorld(mDispatcher,mBroadphase,mSolver,mCollisionConfiguration); // Don't update AABBs of all objects every frame. Most objects in MW are static, so we don't need this. // Should a "static" object ever be moved, we have to update its AABB manually using DynamicsWorld::updateSingleAabb. mDynamicsWorld->setForceUpdateAllAabbs(false); mDynamicsWorld->setGravity(btVector3(0,0,-10)); - - mShapeLoader = shapeLoader; } PhysicEngine::~PhysicEngine() @@ -294,11 +292,10 @@ namespace Physic } delete mDynamicsWorld; - delete solver; - delete collisionConfiguration; - delete dispatcher; - delete broadphase; - delete mShapeLoader; + delete mSolver; + delete mCollisionConfiguration; + delete mDispatcher; + delete mBroadphase; } void PhysicEngine::addHeightField(float* heights, @@ -382,9 +379,8 @@ namespace Physic std::string outputstring = mesh + sid; //get the shape from the .nif - mShapeLoader->load(outputstring,"General"); - BulletShapeManager::getSingletonPtr()->load(outputstring,"General"); - BulletShapePtr shape = BulletShapeManager::getSingleton().getByName(outputstring,"General"); + //mShapeLoader->load(outputstring,"General"); + //BulletShapePtr shape = BulletShapeManager::getSingleton().getByName(outputstring,"General"); //adjustRigidBody(body, position, rotation, shape->mBoxTranslation * scale, shape->mBoxRotation); } @@ -397,9 +393,8 @@ namespace Physic std::string outputstring = mesh + sid; //get the shape from the .nif - mShapeLoader->load(outputstring,"General"); - BulletShapeManager::getSingletonPtr()->load(outputstring,"General"); - BulletShapePtr shape = BulletShapeManager::getSingleton().getByName(outputstring,"General"); + //mShapeLoader->load(outputstring,"General"); + BulletShapePtr shape;// = BulletShapeManager::getSingleton().getByName(outputstring,"General"); // TODO: add option somewhere to enable collision for placeable meshes diff --git a/libs/openengine/bullet/physic.hpp b/libs/openengine/bullet/physic.hpp index 6322105e8..691ccbfd6 100644 --- a/libs/openengine/bullet/physic.hpp +++ b/libs/openengine/bullet/physic.hpp @@ -197,7 +197,7 @@ namespace Physic /** * Note that the shapeLoader IS destroyed by the phyic Engine!! */ - PhysicEngine(BulletShapeLoader* shapeLoader); + PhysicEngine(); /** * It DOES destroy the shape loader! @@ -290,15 +290,12 @@ namespace Physic btCollisionObject *object); //Bullet Stuff - btBroadphaseInterface* broadphase; - btDefaultCollisionConfiguration* collisionConfiguration; - btSequentialImpulseConstraintSolver* solver; - btCollisionDispatcher* dispatcher; + btBroadphaseInterface* mBroadphase; + btDefaultCollisionConfiguration* mCollisionConfiguration; + btSequentialImpulseConstraintSolver* mSolver; + btCollisionDispatcher* mDispatcher; btDiscreteDynamicsWorld* mDynamicsWorld; - //the NIF file loader. - BulletShapeLoader* mShapeLoader; - typedef std::map HeightFieldContainer; HeightFieldContainer mHeightFieldMap; @@ -318,24 +315,6 @@ namespace Physic }; - struct MyRayResultCallback : public btCollisionWorld::RayResultCallback - { - virtual btScalar addSingleResult( btCollisionWorld::LocalRayResult& rayResult, bool bNormalInWorldSpace) - { - results.push_back( std::make_pair(rayResult.m_hitFraction, rayResult.m_collisionObject) ); - return rayResult.m_hitFraction; - } - - static bool cmp( const std::pair& i, const std::pair& j ) - { - if( i.first > j.first ) return false; - if( j.first > i.first ) return true; - return false; - } - - std::vector < std::pair > results; - }; - }} #endif From 0c461f4424a0912af405530878d559ebd376c3b8 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 9 May 2015 21:21:16 +1000 Subject: [PATCH 1127/3725] Add TopicInfos special conditions table. --- apps/opencs/model/world/columnbase.cpp | 3 + apps/opencs/model/world/columnbase.hpp | 3 + apps/opencs/model/world/columns.cpp | 21 + apps/opencs/model/world/columns.hpp | 7 +- apps/opencs/model/world/data.cpp | 13 + .../model/world/nestedcoladapterimp.cpp | 413 ++++++++++++++++++ .../model/world/nestedcoladapterimp.hpp | 25 ++ apps/opencs/view/doc/viewmanager.cpp | 4 +- 8 files changed, 487 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/world/columnbase.cpp b/apps/opencs/model/world/columnbase.cpp index 659954f48..cf125aa63 100644 --- a/apps/opencs/model/world/columnbase.cpp +++ b/apps/opencs/model/world/columnbase.cpp @@ -81,6 +81,9 @@ bool CSMWorld::ColumnBase::isId (Display display) Display_PartRefType, Display_AiPackageType, Display_YesNo, + Display_InfoCondFunc, + Display_InfoCondVar, + Display_InfoCondComp, Display_None }; diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index 71c22a9f0..2d2513774 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -116,6 +116,9 @@ namespace CSMWorld Display_PartRefType, Display_AiPackageType, Display_YesNo, + Display_InfoCondFunc, + Display_InfoCondVar, + Display_InfoCondComp, //top level columns that nest other columns Display_NestedHeader diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 9076aa096..89ee6258b 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -274,6 +274,11 @@ namespace CSMWorld { ColumnId_SkillImpact, "Skills" }, { ColumnId_InfoList, "Info List" }, + { ColumnId_InfoCondition, "Info Conditions" }, + { ColumnId_InfoCondFunc, "Function" }, + { ColumnId_InfoCondVar, "Func/Variable" }, + { ColumnId_InfoCondComp, "Comp" }, + { ColumnId_InfoCondValue, "Value" }, { ColumnId_OriginalCell, "Original Cell" }, { ColumnId_UseValue1, "Use value 1" }, @@ -502,6 +507,18 @@ namespace "No", "Yes", 0 }; + static const char *sInfoCondFunc[] = + { + " ", "Function", "Global", "Local", "Journal", + "Item", "Dead", "Not ID", "Not Faction", "Not Class", + "Not Race", "Not Cell", "Not Local", 0 + }; + + static const char *sInfoCondComp[] = + { + "!=", "<", "<=", "=", ">", ">=", 0 + }; + const char **getEnumNames (CSMWorld::Columns::ColumnId column) { switch (column) @@ -530,6 +547,10 @@ namespace case CSMWorld::Columns::ColumnId_PartRefType: return sPartRefType; case CSMWorld::Columns::ColumnId_AiPackageType: return sAiPackageType; case CSMWorld::Columns::ColumnId_AiWanderRepeat: return sAiWanderRepeat; + case CSMWorld::Columns::ColumnId_InfoCondFunc: return sInfoCondFunc; + // FIXME: don't have dynamic value enum delegate, use Display_String for now + //case CSMWorld::Columns::ColumnId_InfoCond: return sInfoCond; + case CSMWorld::Columns::ColumnId_InfoCondComp: return sInfoCondComp; default: return 0; } diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index b87f6c53d..f971f3fd8 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -264,8 +264,13 @@ namespace CSMWorld ColumnId_SkillImpact = 240, // impact from magic effects ColumnId_InfoList = 241, + ColumnId_InfoCondition = 242, + ColumnId_InfoCondFunc = 243, + ColumnId_InfoCondVar = 244, + ColumnId_InfoCondComp = 245, + ColumnId_InfoCondValue = 246, - ColumnId_OriginalCell = 242, + ColumnId_OriginalCell = 247, // Allocated to a separate value range, so we don't get a collision should we ever need // to extend the number of use values. diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index fc4532fb0..e2fab0a25 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -242,6 +242,19 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mTopicInfos.addAdapter (std::make_pair(&mTopicInfos.getColumn(index), new InfoListAdapter ())); mTopicInfos.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_ScriptText, ColumnBase::Display_ScriptLines)); + // Special conditions + mTopicInfos.addColumn (new NestedParentColumn (Columns::ColumnId_InfoCondition)); + index = mTopicInfos.getColumns()-1; + mTopicInfos.addAdapter (std::make_pair(&mTopicInfos.getColumn(index), new InfoConditionAdapter ())); + mTopicInfos.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_InfoCondFunc, ColumnBase::Display_InfoCondFunc)); + // FIXME: don't have dynamic value enum delegate, use Display_String for now + mTopicInfos.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_InfoCondVar, ColumnBase::Display_String)); + mTopicInfos.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_InfoCondComp, ColumnBase::Display_InfoCondComp)); + mTopicInfos.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_Value, ColumnBase::Display_Var)); mJournalInfos.addColumn (new StringIdColumn (true)); mJournalInfos.addColumn (new RecordStateColumn); diff --git a/apps/opencs/model/world/nestedcoladapterimp.cpp b/apps/opencs/model/world/nestedcoladapterimp.cpp index d29155a47..9cd1a0a3b 100644 --- a/apps/opencs/model/world/nestedcoladapterimp.cpp +++ b/apps/opencs/model/world/nestedcoladapterimp.cpp @@ -528,4 +528,417 @@ namespace CSMWorld { return 1; // fixed at size 1 } + + // ESM::DialInfo::SelectStruct.mSelectRule + // 012345... + // ^^^ ^^ + // ||| || + // ||| |+------------- condition variable string + // ||| +-------------- comparison type, ['0'..'5']; e.g. !=, <, >=, etc + // ||+---------------- function index (encoded, where function == '1') + // |+----------------- function, ['1'..'C']; e.g. Global, Local, Not ID, etc + // +------------------ unknown + // + InfoConditionAdapter::InfoConditionAdapter () {} + + void InfoConditionAdapter::addRow(Record& record, int position) const + { + Info info = record.get(); + + std::vector& conditions = info.mSelects; + + // blank row + ESM::DialInfo::SelectStruct condStruct; + condStruct.mSelectRule = "00000"; + condStruct.mValue = ESM::Variant(); + + conditions.insert(conditions.begin()+position, condStruct); + + record.setModified (info); + } + + void InfoConditionAdapter::removeRow(Record& record, int rowToRemove) const + { + Info info = record.get(); + + std::vector& conditions = info.mSelects; + + if (rowToRemove < 0 || rowToRemove >= static_cast (conditions.size())) + throw std::runtime_error ("index out of range"); + + conditions.erase(conditions.begin()+rowToRemove); + + record.setModified (info); + } + + void InfoConditionAdapter::setTable(Record& record, + const NestedTableWrapperBase& nestedTable) const + { + Info info = record.get(); + + info.mSelects = + static_cast >&>(nestedTable).mNestedTable; + + record.setModified (info); + } + + NestedTableWrapperBase* InfoConditionAdapter::table(const Record& record) const + { + // deleted by dtor of NestedTableStoring + return new NestedTableWrapper >(record.get().mSelects); + } + + // See the mappings in MWDialogue::SelectWrapper::getArgument + // from ESM::Attribute, ESM::Skill and MWMechanics::CreatureStats (for AI) + static const std::map sEncToInfoFunc = + { + { "00", "Rank Low" }, + { "01", "Rank High" }, + { "02", "Rank Requirement" }, + { "03", "Reputation" }, + { "04", "Health Percent" }, + { "05", "PC Reputation" }, + { "06", "PC Level" }, + { "07", "PC Health Percent" }, + { "08", "PC Magicka" }, // dynamic stat + { "09", "PC Fatigue" }, // dynamic stat + { "10", "PC Strength" }, // attrib + { "11", "PC Block" }, + { "12", "PC Armoror" }, + { "13", "PC Medium Armor" }, + { "14", "PC Heavy Armor" }, + { "15", "PC Blunt Weapon" }, + { "16", "PC Long Blade" }, + { "17", "PC Axe" }, + { "18", "PC Spear" }, + { "19", "PC Athletics" }, + { "20", "PC Enchant" }, + { "21", "PC Destruction" }, + { "22", "PC Alteration" }, + { "23", "PC Illusion" }, + { "24", "PC Conjuration" }, + { "25", "PC Mysticism" }, + { "26", "PC Restoration" }, + { "27", "PC Alchemy" }, + { "28", "PC Unarmored" }, + { "29", "PC Security" }, + { "30", "PC Sneak" }, + { "31", "PC Acrobatics" }, + { "32", "PC Light Armor" }, + { "33", "PC Short Blade" }, + { "34", "PC Marksman" }, + { "35", "PC Merchantile" }, + { "36", "PC Speechcraft" }, + { "37", "PC Hand To Hand" }, + { "38", "PC Sex" }, + { "39", "PC Expelled" }, + { "40", "PC Common Disease" }, + { "41", "PC Blight Disease" }, + { "42", "PC Clothing Modifier" }, + { "43", "PC Crime Level" }, + { "44", "Same Sex" }, + { "45", "Same Race" }, + { "46", "Same Faction" }, + { "47", "Faction Rank Difference" }, + { "48", "Detected" }, + { "49", "Alarmed" }, + { "50", "Choice" }, + { "51", "PC Intelligence" }, // attrib + { "52", "PC Willpower" }, // attrib + { "53", "PC Agility" }, // attrib + { "54", "PC Speed" }, // attrib + { "55", "PC Endurance" }, // attrib + { "56", "PC Personality" }, // attrib + { "57", "PC Luck" }, // attrib + { "58", "PC Corpus" }, + { "59", "Weather" }, + { "60", "PC Vampire" }, + { "61", "Level" }, + { "62", "Attacked" }, + { "63", "Talked To PC" }, + { "64", "PC Health" }, // dynamic stat + { "65", "Creature Target" }, + { "66", "Friend Hit" }, + { "67", "Fight" }, // AI + { "68", "Hello" }, // AI + { "69", "Alarm" }, // AI + { "70", "Flee" }, // AI + { "71", "Should Attack" }, + { "72", "Werewolf" }, + { "73", "PC Werewolf Kills" } + }; + + QVariant InfoConditionAdapter::getData(const Record& record, + int subRowIndex, int subColIndex) const + { + Info info = record.get(); + + std::vector& conditions = info.mSelects; + + if (subRowIndex < 0 || subRowIndex >= static_cast (conditions.size())) + throw std::runtime_error ("index out of range"); + + switch (subColIndex) + { + case 0: + { + char condType = conditions[subRowIndex].mSelectRule[1]; + switch (condType) + { + case '1': return 1; // Function + case '2': return 2; // Global + case '3': return 3; // Local + case '4': return 4; // Journal + case '5': return 5; // Item + case '6': return 6; // Dead + case '7': return 7; // Not ID + case '8': return 8; // Not Factio + case '9': return 9; // Not Class + case 'A': return 10; // Not Race + case 'B': return 11; // Not Cell + case 'C': return 12; // Not Local + default: return QVariant(); // TODO: log an error? + } + } + case 1: + { + if (conditions[subRowIndex].mSelectRule[1] == '1') + { + // throws an exception if the encoding is not found + return sEncToInfoFunc.at(conditions[subRowIndex].mSelectRule.substr(2, 2)).c_str(); + } + else + return QString(conditions[subRowIndex].mSelectRule.substr(5).c_str()); + } + case 2: + { + char compType = conditions[subRowIndex].mSelectRule[4]; + switch (compType) + { + case '0': return 3; // = + case '1': return 0; // != + case '2': return 4; // > + case '3': return 5; // >= + case '4': return 1; // < + case '5': return 2; // <= + default: return QVariant(); // TODO: log an error? + } + } + case 3: + { + switch (conditions[subRowIndex].mValue.getType()) + { + case ESM::VT_String: + { + return QString::fromUtf8 (conditions[subRowIndex].mValue.getString().c_str()); + } + case ESM::VT_Int: + case ESM::VT_Short: + case ESM::VT_Long: + { + return conditions[subRowIndex].mValue.getInteger(); + } + case ESM::VT_Float: + { + return conditions[subRowIndex].mValue.getFloat(); + } + default: return QVariant(); + } + } + default: throw std::runtime_error("Info condition subcolumn index out of range"); + } + } + + static const std::map sInfoFuncToEnc = + { + { "Alarm", "69" }, // AI + { "Alarmed", "49" }, + { "Attacked", "62" }, + { "Choice", "50" }, + { "Creature Target", "65" }, + { "Detected", "48" }, + { "Faction Rank Difference", "47" }, + { "Fight", "67" }, // AI + { "Flee", "70" }, // AI + { "Friend Hit", "66" }, + { "Health Percent", "04" }, + { "Hello", "68" }, // AI + { "Level", "61" }, + { "PC Acrobatics", "31" }, + { "PC Agility", "53" }, // attrib + { "PC Alchemy", "27" }, + { "PC Alteration", "22" }, + { "PC Armoror", "12" }, + { "PC Athletics", "19" }, + { "PC Axe", "17" }, + { "PC Blight Disease", "41" }, + { "PC Block", "11" }, + { "PC Blunt Weapon", "15" }, + { "PC Clothing Modifier", "42" }, + { "PC Common Disease", "40" }, + { "PC Conjuration", "24" }, + { "PC Corpus", "58" }, + { "PC Crime Level", "43" }, + { "PC Destruction", "21" }, + { "PC Enchant", "20" }, + { "PC Endurance", "55" }, // attrib + { "PC Expelled", "39" }, + { "PC Fatigue", "09" }, // dynamic stat + { "PC Hand To Hand", "37" }, + { "PC Health", "64" }, // dynamic stat + { "PC Health Percent", "07" }, + { "PC Heavy Armor", "14" }, + { "PC Illusion", "23" }, + { "PC Intelligence", "51" }, // attrib + { "PC Level", "06" }, + { "PC Light Armor", "32" }, + { "PC Long Blade", "16" }, + { "PC Luck", "57" }, // attrib + { "PC Magicka", "08" }, // dynamic stat + { "PC Marksman", "34" }, + { "PC Medium Armor", "13" }, + { "PC Merchantile", "35" }, + { "PC Mysticism", "25" }, + { "PC Personality", "56" }, // attrib + { "PC Reputation", "05" }, + { "PC Restoration", "26" }, + { "PC Security", "29" }, + { "PC Sex", "38" }, + { "PC Short Blade", "33" }, + { "PC Sneak", "30" }, + { "PC Spear", "18" }, + { "PC Speechcraft", "36" }, + { "PC Speed", "54" }, // attrib + { "PC Strength", "10" }, // attrib + { "PC Unarmored", "28" }, + { "PC Vampire", "60" }, + { "PC Werewolf Kills", "73" }, + { "PC Willpower", "52" }, // attrib + { "Rank Requirement", "02" }, + { "Rank High", "01" }, + { "Rank Low", "00" }, + { "Reputation", "03" }, + { "Same Faction", "46" }, + { "Same Race", "45" }, + { "Same Sex", "44" }, + { "Should Attack", "71" }, + { "Talked To PC", "63" }, + { "Weather", "59" }, + { "Werewolf", "72" } + }; + + void InfoConditionAdapter::setData(Record& record, + const QVariant& value, int subRowIndex, int subColIndex) const + { + Info info = record.get(); + + std::vector& conditions = info.mSelects; + + if (subRowIndex < 0 || subRowIndex >= static_cast (conditions.size())) + throw std::runtime_error ("index out of range"); + + switch (subColIndex) + { + case 0: + { + // See sInfoCondFunc in columns.cpp for the enum values + switch (value.toInt()) + { + // FIXME: when these change the values of the other columns need to change + // correspondingly (and automatically) + case 1: conditions[subRowIndex].mSelectRule[1] = '1'; break; // Function + case 2: conditions[subRowIndex].mSelectRule[1] = '2'; break; // Global + case 3: conditions[subRowIndex].mSelectRule[1] = '3'; break; // Local + case 4: conditions[subRowIndex].mSelectRule[1] = '4'; break; // Journal + case 5: conditions[subRowIndex].mSelectRule[1] = '5'; break; // Item + case 6: conditions[subRowIndex].mSelectRule[1] = '6'; break; // Dead + case 7: conditions[subRowIndex].mSelectRule[1] = '7'; break; // Not ID + case 8: conditions[subRowIndex].mSelectRule[1] = '8'; break; // Not Faction + case 9: conditions[subRowIndex].mSelectRule[1] = '9'; break; // Not Class + case 10: conditions[subRowIndex].mSelectRule[1] = 'A'; break; // Not Race + case 11: conditions[subRowIndex].mSelectRule[1] = 'B'; break; // Not Cell + case 12: conditions[subRowIndex].mSelectRule[1] = 'C'; break; // Not Local + default: return; // return without saving + } + break; + } + case 1: + { + if (conditions[subRowIndex].mSelectRule[1] == '1') + { + // throws an exception if the function is not found + const std::map::const_iterator it = sInfoFuncToEnc.find( + value.toString().toUtf8().constData()); + if (it != sInfoFuncToEnc.end()) + { + std::string rule = conditions[subRowIndex].mSelectRule.substr(0, 2); + rule.append(it->second); + rule.append(std::string(1, conditions[subRowIndex].mSelectRule[4])); + conditions[subRowIndex].mSelectRule = rule.append(value.toString().toUtf8().constData()); + } + else + return; // return without saving; TODO: maybe log an error here + } + else + { + // FIXME: validate the string values before saving, based on the current function + std::string rule = conditions[subRowIndex].mSelectRule.substr(0, 5); + conditions[subRowIndex].mSelectRule = rule.append(value.toString().toUtf8().constData()); + } + break; + } + case 2: + { + // See sInfoCondComp in columns.cpp for the enum values + switch (value.toInt()) + { + case 0: conditions[subRowIndex].mSelectRule[4] = '1'; break; // != + case 1: conditions[subRowIndex].mSelectRule[4] = '4'; break; // < + case 2: conditions[subRowIndex].mSelectRule[4] = '5'; break; // <= + case 3: conditions[subRowIndex].mSelectRule[4] = '0'; break; // = + case 4: conditions[subRowIndex].mSelectRule[4] = '2'; break; // > + case 5: conditions[subRowIndex].mSelectRule[4] = '3'; break; // >= + default: return; // return without saving + } + break; + } + case 3: + { + switch (conditions[subRowIndex].mValue.getType()) + { + case ESM::VT_String: + { + conditions[subRowIndex].mValue.setString (value.toString().toUtf8().constData()); + break; + } + case ESM::VT_Int: + case ESM::VT_Short: + case ESM::VT_Long: + { + conditions[subRowIndex].mValue.setInteger (value.toInt()); + break; + } + case ESM::VT_Float: + { + conditions[subRowIndex].mValue.setFloat (value.toFloat()); + break; + } + default: break; + } + } + default: throw std::runtime_error("Info condition subcolumn index out of range"); + } + + record.setModified (info); + } + + int InfoConditionAdapter::getColumnsCount(const Record& record) const + { + return 4; + } + + int InfoConditionAdapter::getRowsCount(const Record& record) const + { + return static_cast(record.get().mSelects.size()); + } } diff --git a/apps/opencs/model/world/nestedcoladapterimp.hpp b/apps/opencs/model/world/nestedcoladapterimp.hpp index 96dcd943d..ea2037eb8 100644 --- a/apps/opencs/model/world/nestedcoladapterimp.hpp +++ b/apps/opencs/model/world/nestedcoladapterimp.hpp @@ -412,6 +412,31 @@ namespace CSMWorld virtual int getRowsCount(const Record& record) const; }; + + class InfoConditionAdapter : public NestedColumnAdapter + { + public: + InfoConditionAdapter (); + + virtual void addRow(Record& record, int position) const; + + virtual void removeRow(Record& record, int rowToRemove) const; + + virtual void setTable(Record& record, + const NestedTableWrapperBase& nestedTable) const; + + virtual NestedTableWrapperBase* table(const Record& record) const; + + virtual QVariant getData(const Record& record, + int subRowIndex, int subColIndex) const; + + virtual void setData(Record& record, + const QVariant& value, int subRowIndex, int subColIndex) const; + + virtual int getColumnsCount(const Record& record) const; + + virtual int getRowsCount(const Record& record) const; + }; } #endif // CSM_WOLRD_NESTEDCOLADAPTERIMP_H diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 5908c67a1..6362f9659 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -90,7 +90,9 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) { CSMWorld::ColumnBase::Display_EffectId, CSMWorld::Columns::ColumnId_EffectId, false }, { CSMWorld::ColumnBase::Display_PartRefType, CSMWorld::Columns::ColumnId_PartRefType, false }, { CSMWorld::ColumnBase::Display_AiPackageType, CSMWorld::Columns::ColumnId_AiPackageType, false }, - { CSMWorld::ColumnBase::Display_YesNo, CSMWorld::Columns::ColumnId_AiWanderRepeat, false } + { CSMWorld::ColumnBase::Display_YesNo, CSMWorld::Columns::ColumnId_AiWanderRepeat, false }, + { CSMWorld::ColumnBase::Display_InfoCondFunc, CSMWorld::Columns::ColumnId_InfoCondFunc, false }, + { CSMWorld::ColumnBase::Display_InfoCondComp, CSMWorld::Columns::ColumnId_InfoCondComp, false } }; for (std::size_t i=0; i Date: Sun, 10 May 2015 05:55:50 +1000 Subject: [PATCH 1128/3725] For compiling with osx - try using a different syntax for initializing the static maps. --- .../model/world/nestedcoladapterimp.cpp | 296 +++++++++--------- 1 file changed, 148 insertions(+), 148 deletions(-) diff --git a/apps/opencs/model/world/nestedcoladapterimp.cpp b/apps/opencs/model/world/nestedcoladapterimp.cpp index 9cd1a0a3b..debb7ca2f 100644 --- a/apps/opencs/model/world/nestedcoladapterimp.cpp +++ b/apps/opencs/model/world/nestedcoladapterimp.cpp @@ -592,80 +592,80 @@ namespace CSMWorld // from ESM::Attribute, ESM::Skill and MWMechanics::CreatureStats (for AI) static const std::map sEncToInfoFunc = { - { "00", "Rank Low" }, - { "01", "Rank High" }, - { "02", "Rank Requirement" }, - { "03", "Reputation" }, - { "04", "Health Percent" }, - { "05", "PC Reputation" }, - { "06", "PC Level" }, - { "07", "PC Health Percent" }, - { "08", "PC Magicka" }, // dynamic stat - { "09", "PC Fatigue" }, // dynamic stat - { "10", "PC Strength" }, // attrib - { "11", "PC Block" }, - { "12", "PC Armoror" }, - { "13", "PC Medium Armor" }, - { "14", "PC Heavy Armor" }, - { "15", "PC Blunt Weapon" }, - { "16", "PC Long Blade" }, - { "17", "PC Axe" }, - { "18", "PC Spear" }, - { "19", "PC Athletics" }, - { "20", "PC Enchant" }, - { "21", "PC Destruction" }, - { "22", "PC Alteration" }, - { "23", "PC Illusion" }, - { "24", "PC Conjuration" }, - { "25", "PC Mysticism" }, - { "26", "PC Restoration" }, - { "27", "PC Alchemy" }, - { "28", "PC Unarmored" }, - { "29", "PC Security" }, - { "30", "PC Sneak" }, - { "31", "PC Acrobatics" }, - { "32", "PC Light Armor" }, - { "33", "PC Short Blade" }, - { "34", "PC Marksman" }, - { "35", "PC Merchantile" }, - { "36", "PC Speechcraft" }, - { "37", "PC Hand To Hand" }, - { "38", "PC Sex" }, - { "39", "PC Expelled" }, - { "40", "PC Common Disease" }, - { "41", "PC Blight Disease" }, - { "42", "PC Clothing Modifier" }, - { "43", "PC Crime Level" }, - { "44", "Same Sex" }, - { "45", "Same Race" }, - { "46", "Same Faction" }, - { "47", "Faction Rank Difference" }, - { "48", "Detected" }, - { "49", "Alarmed" }, - { "50", "Choice" }, - { "51", "PC Intelligence" }, // attrib - { "52", "PC Willpower" }, // attrib - { "53", "PC Agility" }, // attrib - { "54", "PC Speed" }, // attrib - { "55", "PC Endurance" }, // attrib - { "56", "PC Personality" }, // attrib - { "57", "PC Luck" }, // attrib - { "58", "PC Corpus" }, - { "59", "Weather" }, - { "60", "PC Vampire" }, - { "61", "Level" }, - { "62", "Attacked" }, - { "63", "Talked To PC" }, - { "64", "PC Health" }, // dynamic stat - { "65", "Creature Target" }, - { "66", "Friend Hit" }, - { "67", "Fight" }, // AI - { "68", "Hello" }, // AI - { "69", "Alarm" }, // AI - { "70", "Flee" }, // AI - { "71", "Should Attack" }, - { "72", "Werewolf" }, - { "73", "PC Werewolf Kills" } + std::make_pair( "00", "Rank Low" ), + std::make_pair( "01", "Rank High" ), + std::make_pair( "02", "Rank Requirement" ), + std::make_pair( "03", "Reputation" ), + std::make_pair( "04", "Health Percent" ), + std::make_pair( "05", "PC Reputation" ), + std::make_pair( "06", "PC Level" ), + std::make_pair( "07", "PC Health Percent" ), + std::make_pair( "08", "PC Magicka" ), // dynamic stat + std::make_pair( "09", "PC Fatigue" ), // dynamic stat + std::make_pair( "10", "PC Strength" ), // attrib + std::make_pair( "11", "PC Block" ), + std::make_pair( "12", "PC Armoror" ), + std::make_pair( "13", "PC Medium Armor" ), + std::make_pair( "14", "PC Heavy Armor" ), + std::make_pair( "15", "PC Blunt Weapon" ), + std::make_pair( "16", "PC Long Blade" ), + std::make_pair( "17", "PC Axe" ), + std::make_pair( "18", "PC Spear" ), + std::make_pair( "19", "PC Athletics" ), + std::make_pair( "20", "PC Enchant" ), + std::make_pair( "21", "PC Destruction" ), + std::make_pair( "22", "PC Alteration" ), + std::make_pair( "23", "PC Illusion" ), + std::make_pair( "24", "PC Conjuration" ), + std::make_pair( "25", "PC Mysticism" ), + std::make_pair( "26", "PC Restoration" ), + std::make_pair( "27", "PC Alchemy" ), + std::make_pair( "28", "PC Unarmored" ), + std::make_pair( "29", "PC Security" ), + std::make_pair( "30", "PC Sneak" ), + std::make_pair( "31", "PC Acrobatics" ), + std::make_pair( "32", "PC Light Armor" ), + std::make_pair( "33", "PC Short Blade" ), + std::make_pair( "34", "PC Marksman" ), + std::make_pair( "35", "PC Merchantile" ), + std::make_pair( "36", "PC Speechcraft" ), + std::make_pair( "37", "PC Hand To Hand" ), + std::make_pair( "38", "PC Sex" ), + std::make_pair( "39", "PC Expelled" ), + std::make_pair( "40", "PC Common Disease" ), + std::make_pair( "41", "PC Blight Disease" ), + std::make_pair( "42", "PC Clothing Modifier" ), + std::make_pair( "43", "PC Crime Level" ), + std::make_pair( "44", "Same Sex" ), + std::make_pair( "45", "Same Race" ), + std::make_pair( "46", "Same Faction" ), + std::make_pair( "47", "Faction Rank Difference" ), + std::make_pair( "48", "Detected" ), + std::make_pair( "49", "Alarmed" ), + std::make_pair( "50", "Choice" ), + std::make_pair( "51", "PC Intelligence" ), // attrib + std::make_pair( "52", "PC Willpower" ), // attrib + std::make_pair( "53", "PC Agility" ), // attrib + std::make_pair( "54", "PC Speed" ), // attrib + std::make_pair( "55", "PC Endurance" ), // attrib + std::make_pair( "56", "PC Personality" ), // attrib + std::make_pair( "57", "PC Luck" ), // attrib + std::make_pair( "58", "PC Corpus" ), + std::make_pair( "59", "Weather" ), + std::make_pair( "60", "PC Vampire" ), + std::make_pair( "61", "Level" ), + std::make_pair( "62", "Attacked" ), + std::make_pair( "63", "Talked To PC" ), + std::make_pair( "64", "PC Health" ), // dynamic stat + std::make_pair( "65", "Creature Target" ), + std::make_pair( "66", "Friend Hit" ), + std::make_pair( "67", "Fight" ), // AI + std::make_pair( "68", "Hello" ), // AI + std::make_pair( "69", "Alarm" ), // AI + std::make_pair( "70", "Flee" ), // AI + std::make_pair( "71", "Should Attack" ), + std::make_pair( "72", "Werewolf" ), + std::make_pair( "73", "PC Werewolf Kills" ) }; QVariant InfoConditionAdapter::getData(const Record& record, @@ -751,80 +751,80 @@ namespace CSMWorld static const std::map sInfoFuncToEnc = { - { "Alarm", "69" }, // AI - { "Alarmed", "49" }, - { "Attacked", "62" }, - { "Choice", "50" }, - { "Creature Target", "65" }, - { "Detected", "48" }, - { "Faction Rank Difference", "47" }, - { "Fight", "67" }, // AI - { "Flee", "70" }, // AI - { "Friend Hit", "66" }, - { "Health Percent", "04" }, - { "Hello", "68" }, // AI - { "Level", "61" }, - { "PC Acrobatics", "31" }, - { "PC Agility", "53" }, // attrib - { "PC Alchemy", "27" }, - { "PC Alteration", "22" }, - { "PC Armoror", "12" }, - { "PC Athletics", "19" }, - { "PC Axe", "17" }, - { "PC Blight Disease", "41" }, - { "PC Block", "11" }, - { "PC Blunt Weapon", "15" }, - { "PC Clothing Modifier", "42" }, - { "PC Common Disease", "40" }, - { "PC Conjuration", "24" }, - { "PC Corpus", "58" }, - { "PC Crime Level", "43" }, - { "PC Destruction", "21" }, - { "PC Enchant", "20" }, - { "PC Endurance", "55" }, // attrib - { "PC Expelled", "39" }, - { "PC Fatigue", "09" }, // dynamic stat - { "PC Hand To Hand", "37" }, - { "PC Health", "64" }, // dynamic stat - { "PC Health Percent", "07" }, - { "PC Heavy Armor", "14" }, - { "PC Illusion", "23" }, - { "PC Intelligence", "51" }, // attrib - { "PC Level", "06" }, - { "PC Light Armor", "32" }, - { "PC Long Blade", "16" }, - { "PC Luck", "57" }, // attrib - { "PC Magicka", "08" }, // dynamic stat - { "PC Marksman", "34" }, - { "PC Medium Armor", "13" }, - { "PC Merchantile", "35" }, - { "PC Mysticism", "25" }, - { "PC Personality", "56" }, // attrib - { "PC Reputation", "05" }, - { "PC Restoration", "26" }, - { "PC Security", "29" }, - { "PC Sex", "38" }, - { "PC Short Blade", "33" }, - { "PC Sneak", "30" }, - { "PC Spear", "18" }, - { "PC Speechcraft", "36" }, - { "PC Speed", "54" }, // attrib - { "PC Strength", "10" }, // attrib - { "PC Unarmored", "28" }, - { "PC Vampire", "60" }, - { "PC Werewolf Kills", "73" }, - { "PC Willpower", "52" }, // attrib - { "Rank Requirement", "02" }, - { "Rank High", "01" }, - { "Rank Low", "00" }, - { "Reputation", "03" }, - { "Same Faction", "46" }, - { "Same Race", "45" }, - { "Same Sex", "44" }, - { "Should Attack", "71" }, - { "Talked To PC", "63" }, - { "Weather", "59" }, - { "Werewolf", "72" } + std::make_pair( "Alarm", "69" ), // AI + std::make_pair( "Alarmed", "49" ), + std::make_pair( "Attacked", "62" ), + std::make_pair( "Choice", "50" ), + std::make_pair( "Creature Target", "65" ), + std::make_pair( "Detected", "48" ), + std::make_pair( "Faction Rank Difference", "47" ), + std::make_pair( "Fight", "67" ), // AI + std::make_pair( "Flee", "70" ), // AI + std::make_pair( "Friend Hit", "66" ), + std::make_pair( "Health Percent", "04" ), + std::make_pair( "Hello", "68" ), // AI + std::make_pair( "Level", "61" ), + std::make_pair( "PC Acrobatics", "31" ), + std::make_pair( "PC Agility", "53" ), // attrib + std::make_pair( "PC Alchemy", "27" ), + std::make_pair( "PC Alteration", "22" ), + std::make_pair( "PC Armoror", "12" ), + std::make_pair( "PC Athletics", "19" ), + std::make_pair( "PC Axe", "17" ), + std::make_pair( "PC Blight Disease", "41" ), + std::make_pair( "PC Block", "11" ), + std::make_pair( "PC Blunt Weapon", "15" ), + std::make_pair( "PC Clothing Modifier", "42" ), + std::make_pair( "PC Common Disease", "40" ), + std::make_pair( "PC Conjuration", "24" ), + std::make_pair( "PC Corpus", "58" ), + std::make_pair( "PC Crime Level", "43" ), + std::make_pair( "PC Destruction", "21" ), + std::make_pair( "PC Enchant", "20" ), + std::make_pair( "PC Endurance", "55" ), // attrib + std::make_pair( "PC Expelled", "39" ), + std::make_pair( "PC Fatigue", "09" ), // dynamic stat + std::make_pair( "PC Hand To Hand", "37" ), + std::make_pair( "PC Health", "64" ), // dynamic stat + std::make_pair( "PC Health Percent", "07" ), + std::make_pair( "PC Heavy Armor", "14" ), + std::make_pair( "PC Illusion", "23" ), + std::make_pair( "PC Intelligence", "51" ), // attrib + std::make_pair( "PC Level", "06" ), + std::make_pair( "PC Light Armor", "32" ), + std::make_pair( "PC Long Blade", "16" ), + std::make_pair( "PC Luck", "57" ), // attrib + std::make_pair( "PC Magicka", "08" ), // dynamic stat + std::make_pair( "PC Marksman", "34" ), + std::make_pair( "PC Medium Armor", "13" ), + std::make_pair( "PC Merchantile", "35" ), + std::make_pair( "PC Mysticism", "25" ), + std::make_pair( "PC Personality", "56" ), // attrib + std::make_pair( "PC Reputation", "05" ), + std::make_pair( "PC Restoration", "26" ), + std::make_pair( "PC Security", "29" ), + std::make_pair( "PC Sex", "38" ), + std::make_pair( "PC Short Blade", "33" ), + std::make_pair( "PC Sneak", "30" ), + std::make_pair( "PC Spear", "18" ), + std::make_pair( "PC Speechcraft", "36" ), + std::make_pair( "PC Speed", "54" ), // attrib + std::make_pair( "PC Strength", "10" ), // attrib + std::make_pair( "PC Unarmored", "28" ), + std::make_pair( "PC Vampire", "60" ), + std::make_pair( "PC Werewolf Kills", "73" ), + std::make_pair( "PC Willpower", "52" ), // attrib + std::make_pair( "Rank Requirement", "02" ), + std::make_pair( "Rank High", "01" ), + std::make_pair( "Rank Low", "00" ), + std::make_pair( "Reputation", "03" ), + std::make_pair( "Same Faction", "46" ), + std::make_pair( "Same Race", "45" ), + std::make_pair( "Same Sex", "44" ), + std::make_pair( "Should Attack", "71" ), + std::make_pair( "Talked To PC", "63" ), + std::make_pair( "Weather", "59" ), + std::make_pair( "Werewolf", "72" ) }; void InfoConditionAdapter::setData(Record& record, From d6ecc64168bf164d7157abe4b8deaf3336fd3d8f Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 10 May 2015 06:17:57 +1000 Subject: [PATCH 1129/3725] Aggregate types can't be static - osx compiler appears to be more strict. --- .../model/world/nestedcoladapterimp.cpp | 304 +++++++++--------- 1 file changed, 152 insertions(+), 152 deletions(-) diff --git a/apps/opencs/model/world/nestedcoladapterimp.cpp b/apps/opencs/model/world/nestedcoladapterimp.cpp index debb7ca2f..f1088829e 100644 --- a/apps/opencs/model/world/nestedcoladapterimp.cpp +++ b/apps/opencs/model/world/nestedcoladapterimp.cpp @@ -590,82 +590,82 @@ namespace CSMWorld // See the mappings in MWDialogue::SelectWrapper::getArgument // from ESM::Attribute, ESM::Skill and MWMechanics::CreatureStats (for AI) - static const std::map sEncToInfoFunc = - { - std::make_pair( "00", "Rank Low" ), - std::make_pair( "01", "Rank High" ), - std::make_pair( "02", "Rank Requirement" ), - std::make_pair( "03", "Reputation" ), - std::make_pair( "04", "Health Percent" ), - std::make_pair( "05", "PC Reputation" ), - std::make_pair( "06", "PC Level" ), - std::make_pair( "07", "PC Health Percent" ), - std::make_pair( "08", "PC Magicka" ), // dynamic stat - std::make_pair( "09", "PC Fatigue" ), // dynamic stat - std::make_pair( "10", "PC Strength" ), // attrib - std::make_pair( "11", "PC Block" ), - std::make_pair( "12", "PC Armoror" ), - std::make_pair( "13", "PC Medium Armor" ), - std::make_pair( "14", "PC Heavy Armor" ), - std::make_pair( "15", "PC Blunt Weapon" ), - std::make_pair( "16", "PC Long Blade" ), - std::make_pair( "17", "PC Axe" ), - std::make_pair( "18", "PC Spear" ), - std::make_pair( "19", "PC Athletics" ), - std::make_pair( "20", "PC Enchant" ), - std::make_pair( "21", "PC Destruction" ), - std::make_pair( "22", "PC Alteration" ), - std::make_pair( "23", "PC Illusion" ), - std::make_pair( "24", "PC Conjuration" ), - std::make_pair( "25", "PC Mysticism" ), - std::make_pair( "26", "PC Restoration" ), - std::make_pair( "27", "PC Alchemy" ), - std::make_pair( "28", "PC Unarmored" ), - std::make_pair( "29", "PC Security" ), - std::make_pair( "30", "PC Sneak" ), - std::make_pair( "31", "PC Acrobatics" ), - std::make_pair( "32", "PC Light Armor" ), - std::make_pair( "33", "PC Short Blade" ), - std::make_pair( "34", "PC Marksman" ), - std::make_pair( "35", "PC Merchantile" ), - std::make_pair( "36", "PC Speechcraft" ), - std::make_pair( "37", "PC Hand To Hand" ), - std::make_pair( "38", "PC Sex" ), - std::make_pair( "39", "PC Expelled" ), - std::make_pair( "40", "PC Common Disease" ), - std::make_pair( "41", "PC Blight Disease" ), - std::make_pair( "42", "PC Clothing Modifier" ), - std::make_pair( "43", "PC Crime Level" ), - std::make_pair( "44", "Same Sex" ), - std::make_pair( "45", "Same Race" ), - std::make_pair( "46", "Same Faction" ), - std::make_pair( "47", "Faction Rank Difference" ), - std::make_pair( "48", "Detected" ), - std::make_pair( "49", "Alarmed" ), - std::make_pair( "50", "Choice" ), - std::make_pair( "51", "PC Intelligence" ), // attrib - std::make_pair( "52", "PC Willpower" ), // attrib - std::make_pair( "53", "PC Agility" ), // attrib - std::make_pair( "54", "PC Speed" ), // attrib - std::make_pair( "55", "PC Endurance" ), // attrib - std::make_pair( "56", "PC Personality" ), // attrib - std::make_pair( "57", "PC Luck" ), // attrib - std::make_pair( "58", "PC Corpus" ), - std::make_pair( "59", "Weather" ), - std::make_pair( "60", "PC Vampire" ), - std::make_pair( "61", "Level" ), - std::make_pair( "62", "Attacked" ), - std::make_pair( "63", "Talked To PC" ), - std::make_pair( "64", "PC Health" ), // dynamic stat - std::make_pair( "65", "Creature Target" ), - std::make_pair( "66", "Friend Hit" ), - std::make_pair( "67", "Fight" ), // AI - std::make_pair( "68", "Hello" ), // AI - std::make_pair( "69", "Alarm" ), // AI - std::make_pair( "70", "Flee" ), // AI - std::make_pair( "71", "Should Attack" ), - std::make_pair( "72", "Werewolf" ), - std::make_pair( "73", "PC Werewolf Kills" ) + const std::map sEncToInfoFunc = + { + { "00", "Rank Low" }, + { "01", "Rank High" }, + { "02", "Rank Requirement" }, + { "03", "Reputation" }, + { "04", "Health Percent" }, + { "05", "PC Reputation" }, + { "06", "PC Level" }, + { "07", "PC Health Percent" }, + { "08", "PC Magicka" }, // dynamic stat + { "09", "PC Fatigue" }, // dynamic stat + { "10", "PC Strength" }, // attrib + { "11", "PC Block" }, + { "12", "PC Armoror" }, + { "13", "PC Medium Armor" }, + { "14", "PC Heavy Armor" }, + { "15", "PC Blunt Weapon" }, + { "16", "PC Long Blade" }, + { "17", "PC Axe" }, + { "18", "PC Spear" }, + { "19", "PC Athletics" }, + { "20", "PC Enchant" }, + { "21", "PC Destruction" }, + { "22", "PC Alteration" }, + { "23", "PC Illusion" }, + { "24", "PC Conjuration" }, + { "25", "PC Mysticism" }, + { "26", "PC Restoration" }, + { "27", "PC Alchemy" }, + { "28", "PC Unarmored" }, + { "29", "PC Security" }, + { "30", "PC Sneak" }, + { "31", "PC Acrobatics" }, + { "32", "PC Light Armor" }, + { "33", "PC Short Blade" }, + { "34", "PC Marksman" }, + { "35", "PC Merchantile" }, + { "36", "PC Speechcraft" }, + { "37", "PC Hand To Hand" }, + { "38", "PC Sex" }, + { "39", "PC Expelled" }, + { "40", "PC Common Disease" }, + { "41", "PC Blight Disease" }, + { "42", "PC Clothing Modifier" }, + { "43", "PC Crime Level" }, + { "44", "Same Sex" }, + { "45", "Same Race" }, + { "46", "Same Faction" }, + { "47", "Faction Rank Difference" }, + { "48", "Detected" }, + { "49", "Alarmed" }, + { "50", "Choice" }, + { "51", "PC Intelligence" }, // attrib + { "52", "PC Willpower" }, // attrib + { "53", "PC Agility" }, // attrib + { "54", "PC Speed" }, // attrib + { "55", "PC Endurance" }, // attrib + { "56", "PC Personality" }, // attrib + { "57", "PC Luck" }, // attrib + { "58", "PC Corpus" }, + { "59", "Weather" }, + { "60", "PC Vampire" }, + { "61", "Level" }, + { "62", "Attacked" }, + { "63", "Talked To PC" }, + { "64", "PC Health" }, // dynamic stat + { "65", "Creature Target" }, + { "66", "Friend Hit" }, + { "67", "Fight" }, // AI + { "68", "Hello" }, // AI + { "69", "Alarm" }, // AI + { "70", "Flee" }, // AI + { "71", "Should Attack" }, + { "72", "Werewolf" }, + { "73", "PC Werewolf Kills" } }; QVariant InfoConditionAdapter::getData(const Record& record, @@ -749,82 +749,82 @@ namespace CSMWorld } } - static const std::map sInfoFuncToEnc = - { - std::make_pair( "Alarm", "69" ), // AI - std::make_pair( "Alarmed", "49" ), - std::make_pair( "Attacked", "62" ), - std::make_pair( "Choice", "50" ), - std::make_pair( "Creature Target", "65" ), - std::make_pair( "Detected", "48" ), - std::make_pair( "Faction Rank Difference", "47" ), - std::make_pair( "Fight", "67" ), // AI - std::make_pair( "Flee", "70" ), // AI - std::make_pair( "Friend Hit", "66" ), - std::make_pair( "Health Percent", "04" ), - std::make_pair( "Hello", "68" ), // AI - std::make_pair( "Level", "61" ), - std::make_pair( "PC Acrobatics", "31" ), - std::make_pair( "PC Agility", "53" ), // attrib - std::make_pair( "PC Alchemy", "27" ), - std::make_pair( "PC Alteration", "22" ), - std::make_pair( "PC Armoror", "12" ), - std::make_pair( "PC Athletics", "19" ), - std::make_pair( "PC Axe", "17" ), - std::make_pair( "PC Blight Disease", "41" ), - std::make_pair( "PC Block", "11" ), - std::make_pair( "PC Blunt Weapon", "15" ), - std::make_pair( "PC Clothing Modifier", "42" ), - std::make_pair( "PC Common Disease", "40" ), - std::make_pair( "PC Conjuration", "24" ), - std::make_pair( "PC Corpus", "58" ), - std::make_pair( "PC Crime Level", "43" ), - std::make_pair( "PC Destruction", "21" ), - std::make_pair( "PC Enchant", "20" ), - std::make_pair( "PC Endurance", "55" ), // attrib - std::make_pair( "PC Expelled", "39" ), - std::make_pair( "PC Fatigue", "09" ), // dynamic stat - std::make_pair( "PC Hand To Hand", "37" ), - std::make_pair( "PC Health", "64" ), // dynamic stat - std::make_pair( "PC Health Percent", "07" ), - std::make_pair( "PC Heavy Armor", "14" ), - std::make_pair( "PC Illusion", "23" ), - std::make_pair( "PC Intelligence", "51" ), // attrib - std::make_pair( "PC Level", "06" ), - std::make_pair( "PC Light Armor", "32" ), - std::make_pair( "PC Long Blade", "16" ), - std::make_pair( "PC Luck", "57" ), // attrib - std::make_pair( "PC Magicka", "08" ), // dynamic stat - std::make_pair( "PC Marksman", "34" ), - std::make_pair( "PC Medium Armor", "13" ), - std::make_pair( "PC Merchantile", "35" ), - std::make_pair( "PC Mysticism", "25" ), - std::make_pair( "PC Personality", "56" ), // attrib - std::make_pair( "PC Reputation", "05" ), - std::make_pair( "PC Restoration", "26" ), - std::make_pair( "PC Security", "29" ), - std::make_pair( "PC Sex", "38" ), - std::make_pair( "PC Short Blade", "33" ), - std::make_pair( "PC Sneak", "30" ), - std::make_pair( "PC Spear", "18" ), - std::make_pair( "PC Speechcraft", "36" ), - std::make_pair( "PC Speed", "54" ), // attrib - std::make_pair( "PC Strength", "10" ), // attrib - std::make_pair( "PC Unarmored", "28" ), - std::make_pair( "PC Vampire", "60" ), - std::make_pair( "PC Werewolf Kills", "73" ), - std::make_pair( "PC Willpower", "52" ), // attrib - std::make_pair( "Rank Requirement", "02" ), - std::make_pair( "Rank High", "01" ), - std::make_pair( "Rank Low", "00" ), - std::make_pair( "Reputation", "03" ), - std::make_pair( "Same Faction", "46" ), - std::make_pair( "Same Race", "45" ), - std::make_pair( "Same Sex", "44" ), - std::make_pair( "Should Attack", "71" ), - std::make_pair( "Talked To PC", "63" ), - std::make_pair( "Weather", "59" ), - std::make_pair( "Werewolf", "72" ) + const std::map sInfoFuncToEnc = + { + { "Alarm", "69" }, // AI + { "Alarmed", "49" }, + { "Attacked", "62" }, + { "Choice", "50" }, + { "Creature Target", "65" }, + { "Detected", "48" }, + { "Faction Rank Difference", "47" }, + { "Fight", "67" }, // AI + { "Flee", "70" }, // AI + { "Friend Hit", "66" }, + { "Health Percent", "04" }, + { "Hello", "68" }, // AI + { "Level", "61" }, + { "PC Acrobatics", "31" }, + { "PC Agility", "53" }, // attrib + { "PC Alchemy", "27" }, + { "PC Alteration", "22" }, + { "PC Armoror", "12" }, + { "PC Athletics", "19" }, + { "PC Axe", "17" }, + { "PC Blight Disease", "41" }, + { "PC Block", "11" }, + { "PC Blunt Weapon", "15" }, + { "PC Clothing Modifier", "42" }, + { "PC Common Disease", "40" }, + { "PC Conjuration", "24" }, + { "PC Corpus", "58" }, + { "PC Crime Level", "43" }, + { "PC Destruction", "21" }, + { "PC Enchant", "20" }, + { "PC Endurance", "55" }, // attrib + { "PC Expelled", "39" }, + { "PC Fatigue", "09" }, // dynamic stat + { "PC Hand To Hand", "37" }, + { "PC Health", "64" }, // dynamic stat + { "PC Health Percent", "07" }, + { "PC Heavy Armor", "14" }, + { "PC Illusion", "23" }, + { "PC Intelligence", "51" }, // attrib + { "PC Level", "06" }, + { "PC Light Armor", "32" }, + { "PC Long Blade", "16" }, + { "PC Luck", "57" }, // attrib + { "PC Magicka", "08" }, // dynamic stat + { "PC Marksman", "34" }, + { "PC Medium Armor", "13" }, + { "PC Merchantile", "35" }, + { "PC Mysticism", "25" }, + { "PC Personality", "56" }, // attrib + { "PC Reputation", "05" }, + { "PC Restoration", "26" }, + { "PC Security", "29" }, + { "PC Sex", "38" }, + { "PC Short Blade", "33" }, + { "PC Sneak", "30" }, + { "PC Spear", "18" }, + { "PC Speechcraft", "36" }, + { "PC Speed", "54" }, // attrib + { "PC Strength", "10" }, // attrib + { "PC Unarmored", "28" }, + { "PC Vampire", "60" }, + { "PC Werewolf Kills", "73" }, + { "PC Willpower", "52" }, // attrib + { "Rank Requirement", "02" }, + { "Rank High", "01" }, + { "Rank Low", "00" }, + { "Reputation", "03" }, + { "Same Faction", "46" }, + { "Same Race", "45" }, + { "Same Sex", "44" }, + { "Should Attack", "71" }, + { "Talked To PC", "63" }, + { "Weather", "59" }, + { "Werewolf", "72" } }; void InfoConditionAdapter::setData(Record& record, From 5fb269336f3d7e78588141a0d21bba15b55db76e Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 10 May 2015 07:02:08 +1000 Subject: [PATCH 1130/3725] Don't use initializer list --- .../model/world/nestedcoladapterimp.cpp | 316 +++++++++--------- 1 file changed, 161 insertions(+), 155 deletions(-) diff --git a/apps/opencs/model/world/nestedcoladapterimp.cpp b/apps/opencs/model/world/nestedcoladapterimp.cpp index f1088829e..8ee4af2f8 100644 --- a/apps/opencs/model/world/nestedcoladapterimp.cpp +++ b/apps/opencs/model/world/nestedcoladapterimp.cpp @@ -590,83 +590,86 @@ namespace CSMWorld // See the mappings in MWDialogue::SelectWrapper::getArgument // from ESM::Attribute, ESM::Skill and MWMechanics::CreatureStats (for AI) - const std::map sEncToInfoFunc = - { - { "00", "Rank Low" }, - { "01", "Rank High" }, - { "02", "Rank Requirement" }, - { "03", "Reputation" }, - { "04", "Health Percent" }, - { "05", "PC Reputation" }, - { "06", "PC Level" }, - { "07", "PC Health Percent" }, - { "08", "PC Magicka" }, // dynamic stat - { "09", "PC Fatigue" }, // dynamic stat - { "10", "PC Strength" }, // attrib - { "11", "PC Block" }, - { "12", "PC Armoror" }, - { "13", "PC Medium Armor" }, - { "14", "PC Heavy Armor" }, - { "15", "PC Blunt Weapon" }, - { "16", "PC Long Blade" }, - { "17", "PC Axe" }, - { "18", "PC Spear" }, - { "19", "PC Athletics" }, - { "20", "PC Enchant" }, - { "21", "PC Destruction" }, - { "22", "PC Alteration" }, - { "23", "PC Illusion" }, - { "24", "PC Conjuration" }, - { "25", "PC Mysticism" }, - { "26", "PC Restoration" }, - { "27", "PC Alchemy" }, - { "28", "PC Unarmored" }, - { "29", "PC Security" }, - { "30", "PC Sneak" }, - { "31", "PC Acrobatics" }, - { "32", "PC Light Armor" }, - { "33", "PC Short Blade" }, - { "34", "PC Marksman" }, - { "35", "PC Merchantile" }, - { "36", "PC Speechcraft" }, - { "37", "PC Hand To Hand" }, - { "38", "PC Sex" }, - { "39", "PC Expelled" }, - { "40", "PC Common Disease" }, - { "41", "PC Blight Disease" }, - { "42", "PC Clothing Modifier" }, - { "43", "PC Crime Level" }, - { "44", "Same Sex" }, - { "45", "Same Race" }, - { "46", "Same Faction" }, - { "47", "Faction Rank Difference" }, - { "48", "Detected" }, - { "49", "Alarmed" }, - { "50", "Choice" }, - { "51", "PC Intelligence" }, // attrib - { "52", "PC Willpower" }, // attrib - { "53", "PC Agility" }, // attrib - { "54", "PC Speed" }, // attrib - { "55", "PC Endurance" }, // attrib - { "56", "PC Personality" }, // attrib - { "57", "PC Luck" }, // attrib - { "58", "PC Corpus" }, - { "59", "Weather" }, - { "60", "PC Vampire" }, - { "61", "Level" }, - { "62", "Attacked" }, - { "63", "Talked To PC" }, - { "64", "PC Health" }, // dynamic stat - { "65", "Creature Target" }, - { "66", "Friend Hit" }, - { "67", "Fight" }, // AI - { "68", "Hello" }, // AI - { "69", "Alarm" }, // AI - { "70", "Flee" }, // AI - { "71", "Should Attack" }, - { "72", "Werewolf" }, - { "73", "PC Werewolf Kills" } - }; + static std::map populateEncToInfoFunc() + { + std::map funcMap; + funcMap["00"] = "Rank Low"; + funcMap["01"] = "Rank High"; + funcMap["02"] = "Rank Requirement"; + funcMap["03"] = "Reputation"; + funcMap["04"] = "Health Percent"; + funcMap["05"] = "PC Reputation"; + funcMap["06"] = "PC Level"; + funcMap["07"] = "PC Health Percent"; + funcMap["08"] = "PC Magicka"; + funcMap["09"] = "PC Fatigue"; + funcMap["10"] = "PC Strength"; + funcMap["11"] = "PC Block"; + funcMap["12"] = "PC Armoror"; + funcMap["13"] = "PC Medium Armor"; + funcMap["14"] = "PC Heavy Armor"; + funcMap["15"] = "PC Blunt Weapon"; + funcMap["16"] = "PC Long Blade"; + funcMap["17"] = "PC Axe"; + funcMap["18"] = "PC Spear"; + funcMap["19"] = "PC Athletics"; + funcMap["20"] = "PC Enchant"; + funcMap["21"] = "PC Destruction"; + funcMap["22"] = "PC Alteration"; + funcMap["23"] = "PC Illusion"; + funcMap["24"] = "PC Conjuration"; + funcMap["25"] = "PC Mysticism"; + funcMap["26"] = "PC Restoration"; + funcMap["27"] = "PC Alchemy"; + funcMap["28"] = "PC Unarmored"; + funcMap["29"] = "PC Security"; + funcMap["30"] = "PC Sneak"; + funcMap["31"] = "PC Acrobatics"; + funcMap["32"] = "PC Light Armor"; + funcMap["33"] = "PC Short Blade"; + funcMap["34"] = "PC Marksman"; + funcMap["35"] = "PC Merchantile"; + funcMap["36"] = "PC Speechcraft"; + funcMap["37"] = "PC Hand To Hand"; + funcMap["38"] = "PC Sex"; + funcMap["39"] = "PC Expelled"; + funcMap["40"] = "PC Common Disease"; + funcMap["41"] = "PC Blight Disease"; + funcMap["42"] = "PC Clothing Modifier"; + funcMap["43"] = "PC Crime Level"; + funcMap["44"] = "Same Sex"; + funcMap["45"] = "Same Race"; + funcMap["46"] = "Same Faction"; + funcMap["47"] = "Faction Rank Difference"; + funcMap["48"] = "Detected"; + funcMap["49"] = "Alarmed"; + funcMap["50"] = "Choice"; + funcMap["51"] = "PC Intelligence"; + funcMap["52"] = "PC Willpower"; + funcMap["53"] = "PC Agility"; + funcMap["54"] = "PC Speed"; + funcMap["55"] = "PC Endurance"; + funcMap["56"] = "PC Personality"; + funcMap["57"] = "PC Luck"; + funcMap["58"] = "PC Corpus"; + funcMap["59"] = "Weather"; + funcMap["60"] = "PC Vampire"; + funcMap["61"] = "Level"; + funcMap["62"] = "Attacked"; + funcMap["63"] = "Talked To PC"; + funcMap["64"] = "PC Health"; + funcMap["65"] = "Creature Target"; + funcMap["66"] = "Friend Hit"; + funcMap["67"] = "Fight"; + funcMap["68"] = "Hello"; + funcMap["69"] = "Alarm"; + funcMap["70"] = "Flee"; + funcMap["71"] = "Should Attack"; + funcMap["72"] = "Werewolf"; + funcMap["73"] = "PC Werewolf Kills"; + return funcMap; + } + static const std::map sEncToInfoFunc = populateEncToInfoFunc(); QVariant InfoConditionAdapter::getData(const Record& record, int subRowIndex, int subColIndex) const @@ -749,83 +752,86 @@ namespace CSMWorld } } - const std::map sInfoFuncToEnc = - { - { "Alarm", "69" }, // AI - { "Alarmed", "49" }, - { "Attacked", "62" }, - { "Choice", "50" }, - { "Creature Target", "65" }, - { "Detected", "48" }, - { "Faction Rank Difference", "47" }, - { "Fight", "67" }, // AI - { "Flee", "70" }, // AI - { "Friend Hit", "66" }, - { "Health Percent", "04" }, - { "Hello", "68" }, // AI - { "Level", "61" }, - { "PC Acrobatics", "31" }, - { "PC Agility", "53" }, // attrib - { "PC Alchemy", "27" }, - { "PC Alteration", "22" }, - { "PC Armoror", "12" }, - { "PC Athletics", "19" }, - { "PC Axe", "17" }, - { "PC Blight Disease", "41" }, - { "PC Block", "11" }, - { "PC Blunt Weapon", "15" }, - { "PC Clothing Modifier", "42" }, - { "PC Common Disease", "40" }, - { "PC Conjuration", "24" }, - { "PC Corpus", "58" }, - { "PC Crime Level", "43" }, - { "PC Destruction", "21" }, - { "PC Enchant", "20" }, - { "PC Endurance", "55" }, // attrib - { "PC Expelled", "39" }, - { "PC Fatigue", "09" }, // dynamic stat - { "PC Hand To Hand", "37" }, - { "PC Health", "64" }, // dynamic stat - { "PC Health Percent", "07" }, - { "PC Heavy Armor", "14" }, - { "PC Illusion", "23" }, - { "PC Intelligence", "51" }, // attrib - { "PC Level", "06" }, - { "PC Light Armor", "32" }, - { "PC Long Blade", "16" }, - { "PC Luck", "57" }, // attrib - { "PC Magicka", "08" }, // dynamic stat - { "PC Marksman", "34" }, - { "PC Medium Armor", "13" }, - { "PC Merchantile", "35" }, - { "PC Mysticism", "25" }, - { "PC Personality", "56" }, // attrib - { "PC Reputation", "05" }, - { "PC Restoration", "26" }, - { "PC Security", "29" }, - { "PC Sex", "38" }, - { "PC Short Blade", "33" }, - { "PC Sneak", "30" }, - { "PC Spear", "18" }, - { "PC Speechcraft", "36" }, - { "PC Speed", "54" }, // attrib - { "PC Strength", "10" }, // attrib - { "PC Unarmored", "28" }, - { "PC Vampire", "60" }, - { "PC Werewolf Kills", "73" }, - { "PC Willpower", "52" }, // attrib - { "Rank Requirement", "02" }, - { "Rank High", "01" }, - { "Rank Low", "00" }, - { "Reputation", "03" }, - { "Same Faction", "46" }, - { "Same Race", "45" }, - { "Same Sex", "44" }, - { "Should Attack", "71" }, - { "Talked To PC", "63" }, - { "Weather", "59" }, - { "Werewolf", "72" } - }; + static std::map populateInfoFuncToEnc() + { + std::map encMap; + encMap["Alarm"] = "69"; // AI + encMap["Alarmed"] = "49"; + encMap["Attacked"] = "62"; + encMap["Choice"] = "50"; + encMap["Creature Target"] = "65"; + encMap["Detected"] = "48"; + encMap["Faction Rank Difference"] ="47"; + encMap["Fight"] = "67"; // AI + encMap["Flee"] = "70"; // AI + encMap["Friend Hit"] = "66"; + encMap["Health Percent"] = "04"; + encMap["Hello"] = "68"; // AI + encMap["Level"] = "61"; + encMap["PC Acrobatics"] = "31"; + encMap["PC Agility"] = "53"; // attrib + encMap["PC Alchemy"] = "27"; + encMap["PC Alteration"] = "22"; + encMap["PC Armoror"] = "12"; + encMap["PC Athletics"] = "19"; + encMap["PC Axe"] = "17"; + encMap["PC Blight Disease"] = "41"; + encMap["PC Block"] = "11"; + encMap["PC Blunt Weapon"] = "15"; + encMap["PC Clothing Modifier"] = "42"; + encMap["PC Common Disease"] = "40"; + encMap["PC Conjuration"] = "24"; + encMap["PC Corpus"] = "58"; + encMap["PC Crime Level"] = "43"; + encMap["PC Destruction"] = "21"; + encMap["PC Enchant"] = "20"; + encMap["PC Endurance"] = "55"; // attrib + encMap["PC Expelled"] = "39"; + encMap["PC Fatigue"] = "09"; // dynamic stat + encMap["PC Hand To Hand"] = "37"; + encMap["PC Health"] = "64"; // dynamic stat + encMap["PC Health Percent"] = "07"; + encMap["PC Heavy Armor"] = "14"; + encMap["PC Illusion"] = "23"; + encMap["PC Intelligence"] = "51"; // attrib + encMap["PC Level"] = "06"; + encMap["PC Light Armor"] = "32"; + encMap["PC Long Blade"] = "16"; + encMap["PC Luck"] = "57"; // attrib + encMap["PC Magicka"] = "08"; // dynamic stat + encMap["PC Marksman"] = "34"; + encMap["PC Medium Armor"] = "13"; + encMap["PC Merchantile"] = "35"; + encMap["PC Mysticism"] = "25"; + encMap["PC Personality"] = "56"; // attrib + encMap["PC Reputation"] = "05"; + encMap["PC Restoration"] = "26"; + encMap["PC Security"] = "29"; + encMap["PC Sex"] = "38"; + encMap["PC Short Blade"] = "33"; + encMap["PC Sneak"] = "30"; + encMap["PC Spear"] = "18"; + encMap["PC Speechcraft"] = "36"; + encMap["PC Speed"] = "54"; // attrib + encMap["PC Strength"] = "10"; // attrib + encMap["PC Unarmored"] = "28"; + encMap["PC Vampire"] = "60"; + encMap["PC Werewolf Kills"] = "73"; + encMap["PC Willpower"] = "52"; // attrib + encMap["Rank Requirement"] = "02"; + encMap["Rank High"] = "01"; + encMap["Rank Low"] = "00"; + encMap["Reputation"] = "03"; + encMap["Same Faction"] = "46"; + encMap["Same Race"] = "45"; + encMap["Same Sex"] = "44"; + encMap["Should Attack"] = "71"; + encMap["Talked To PC"] = "63"; + encMap["Weather"] = "59"; + encMap["Werewolf"] = "72"; + return encMap; + } + static const std::map sInfoFuncToEnc = populateInfoFuncToEnc(); void InfoConditionAdapter::setData(Record& record, const QVariant& value, int subRowIndex, int subColIndex) const @@ -867,7 +873,7 @@ namespace CSMWorld if (conditions[subRowIndex].mSelectRule[1] == '1') { // throws an exception if the function is not found - const std::map::const_iterator it = sInfoFuncToEnc.find( + const std::map::const_iterator it = sInfoFuncToEnc.find( value.toString().toUtf8().constData()); if (it != sInfoFuncToEnc.end()) { From 587efcfe9db6f2fa6194971368b256cd006c1b49 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 10 May 2015 07:49:18 +1000 Subject: [PATCH 1131/3725] Use better initial value type. Fix exception while saving values. --- apps/opencs/model/world/nestedcoladapterimp.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/opencs/model/world/nestedcoladapterimp.cpp b/apps/opencs/model/world/nestedcoladapterimp.cpp index 8ee4af2f8..8c62fb59b 100644 --- a/apps/opencs/model/world/nestedcoladapterimp.cpp +++ b/apps/opencs/model/world/nestedcoladapterimp.cpp @@ -551,6 +551,7 @@ namespace CSMWorld ESM::DialInfo::SelectStruct condStruct; condStruct.mSelectRule = "00000"; condStruct.mValue = ESM::Variant(); + condStruct.mValue.setType(ESM::VT_Int); // default to ints conditions.insert(conditions.begin()+position, condStruct); @@ -688,6 +689,7 @@ namespace CSMWorld char condType = conditions[subRowIndex].mSelectRule[1]; switch (condType) { + case '0': return 0; // blank space case '1': return 1; // Function case '2': return 2; // Global case '3': return 3; // Local @@ -931,6 +933,7 @@ namespace CSMWorld } default: break; } + break; } default: throw std::runtime_error("Info condition subcolumn index out of range"); } From c843cfc8e26e692ff4ee805d313d70d36c5e0fc1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 10 May 2015 00:28:51 +0200 Subject: [PATCH 1132/3725] Physics stub in preparation for rewrite --- CMakeLists.txt | 4 - apps/openmw/engine.cpp | 2 - apps/openmw/mwworld/physicssystem.cpp | 200 ++--- apps/openmw/mwworld/physicssystem.hpp | 12 - apps/openmw/mwworld/worldimp.cpp | 45 +- components/CMakeLists.txt | 6 +- components/myguiplatform/myguiloglistener.hpp | 4 +- components/nifbullet/bulletnifloader.hpp | 12 +- libs/openengine/.gitignore | 3 - libs/openengine/CMakeLists.txt | 17 - libs/openengine/README | 12 - libs/openengine/bullet/BulletShapeLoader.cpp | 66 -- libs/openengine/bullet/BulletShapeLoader.h | 59 -- libs/openengine/bullet/physic.cpp | 709 ------------------ libs/openengine/bullet/physic.hpp | 320 -------- libs/openengine/bullet/trace.cpp | 133 ---- libs/openengine/bullet/trace.h | 33 - 17 files changed, 80 insertions(+), 1557 deletions(-) delete mode 100644 libs/openengine/.gitignore delete mode 100644 libs/openengine/CMakeLists.txt delete mode 100644 libs/openengine/README delete mode 100644 libs/openengine/bullet/BulletShapeLoader.cpp delete mode 100644 libs/openengine/bullet/BulletShapeLoader.h delete mode 100644 libs/openengine/bullet/physic.cpp delete mode 100644 libs/openengine/bullet/physic.hpp delete mode 100644 libs/openengine/bullet/trace.cpp delete mode 100644 libs/openengine/bullet/trace.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 92023da2c..2fa9cb821 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -455,10 +455,6 @@ if(WIN32) include(CPack) endif(WIN32) -# Libs -include_directories(libs) -add_subdirectory(libs/openengine) - # Extern add_subdirectory (extern/osg-ffmpeg-videoplayer) add_subdirectory (extern/oics) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 59c3667a4..4c6d1585b 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -24,8 +24,6 @@ #include #include -#include - #include #include "mwinput/inputmanagerimp.hpp" diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index a43ca9178..7c1a44e48 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -2,20 +2,8 @@ #include -#include -#include -#include -#include -#include -#include -#include - #include -#include -#include -//#include - #include #include @@ -33,20 +21,18 @@ #include "../mwrender/bulletdebugdraw.hpp" //#include "../apps/openmw/mwrender/animation.hpp" -#include "../apps/openmw/mwbase/world.hpp" -#include "../apps/openmw/mwbase/environment.hpp" +#include "../mwbase/world.hpp" +#include "../mwbase/environment.hpp" #include "ptr.hpp" #include "class.hpp" -using namespace Ogre; - namespace { +/* void animateCollisionShapes (std::map& map, btDynamicsWorld* dynamicsWorld) { - /* for (std::map::iterator it = map.begin(); it != map.end(); ++it) { @@ -87,41 +73,11 @@ void animateCollisionShapes (std::mapupdateSingleAabb(it->first); } - */ } + */ } -namespace BtOgre -{ -//Converts from and to Bullet and Ogre stuff. Pretty self-explanatory. -class Convert -{ -public: - Convert() {}; - ~Convert() {}; - - static btQuaternion toBullet(const Ogre::Quaternion &q) - { - return btQuaternion(q.x, q.y, q.z, q.w); - } - static btVector3 toBullet(const Ogre::Vector3 &v) - { - return btVector3(v.x, v.y, v.z); - } - - static Ogre::Quaternion toOgre(const btQuaternion &q) - { - return Ogre::Quaternion(q.w(), q.x(), q.y(), q.z()); - } - static Ogre::Vector3 toOgre(const btVector3 &v) - { - return Ogre::Vector3(v.x(), v.y(), v.z()); - } -}; -} - - namespace MWWorld { @@ -188,6 +144,8 @@ namespace MWWorld * +--+ +-------- * ============================================== */ + return false; +#if 0 OEngine::Physic::ActorTracer tracer, stepper; stepper.doTrace(colobj, position, position+Ogre::Vector3(0.0f,0.0f,sStepSizeUp), engine); @@ -243,6 +201,7 @@ namespace MWWorld // moved between 0 and just under sStepSize distance but slope was too great, // or moved full sStepSize distance (FIXME: is this a bug?) +#endif return false; } @@ -266,6 +225,8 @@ namespace MWWorld const ESM::Position &refpos = ptr.getRefData().getPosition(); Ogre::Vector3 position(refpos.pos); + return position; +#if 0 OEngine::Physic::PhysicActor *physicActor = engine->getCharacter(ptr.getRefData().getHandle()); if (!physicActor) return position; @@ -302,6 +263,7 @@ namespace MWWorld return tracer.mEndPos; } +#endif } static Ogre::Vector3 move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time, @@ -311,7 +273,8 @@ namespace MWWorld { const ESM::Position &refpos = ptr.getRefData().getPosition(); Ogre::Vector3 position(refpos.pos); - + return position; +#if 0 // Early-out for totally static creatures // (Not sure if gravity should still apply?) if (!ptr.getClass().isMobile(ptr)) @@ -526,21 +489,20 @@ namespace MWWorld newPosition.z -= halfExtents.z; // remove what was added at the beginning return newPosition; +#endif } }; PhysicsSystem::PhysicsSystem(osg::ref_ptr parentNode) : - mEngine(0), mTimeAccum(0.0f), mWaterEnabled(false), mWaterHeight(0), mDebugDrawEnabled(false), mParentNode(parentNode) + mTimeAccum(0.0f), mWaterEnabled(false), mWaterHeight(0), mDebugDrawEnabled(false), mParentNode(parentNode) { - mEngine = new OEngine::Physic::PhysicEngine; } PhysicsSystem::~PhysicsSystem() { - if (mWaterCollisionObject.get()) - mEngine->mDynamicsWorld->removeCollisionObject(mWaterCollisionObject.get()); - delete mEngine; + //if (mWaterCollisionObject.get()) + // mEngine->mDynamicsWorld->removeCollisionObject(mWaterCollisionObject.get()); } bool PhysicsSystem::toggleDebugRendering() @@ -549,25 +511,22 @@ namespace MWWorld if (mDebugDrawEnabled && !mDebugDrawer.get()) { - mDebugDrawer.reset(new MWRender::DebugDrawer(mParentNode, mEngine->mDynamicsWorld)); - mEngine->mDynamicsWorld->setDebugDrawer(mDebugDrawer.get()); - mDebugDrawer->setDebugMode(mDebugDrawEnabled); + //mDebugDrawer.reset(new MWRender::DebugDrawer(mParentNode, mEngine->mDynamicsWorld)); + //mEngine->mDynamicsWorld->setDebugDrawer(mDebugDrawer.get()); + //mDebugDrawer->setDebugMode(mDebugDrawEnabled); } else if (mDebugDrawer.get()) mDebugDrawer->setDebugMode(mDebugDrawEnabled); return mDebugDrawEnabled; } - OEngine::Physic::PhysicEngine* PhysicsSystem::getEngine() - { - return mEngine; - } - std::pair PhysicsSystem::getHitContact(const std::string &name, const Ogre::Vector3 &origin, const Ogre::Quaternion &orient, float queryDistance) { + return std::make_pair(std::string(), Ogre::Vector3()); + /* const MWWorld::Store &store = MWBase::Environment::get().getWorld()->getStore().get(); btConeShape shape(Ogre::Degree(store.find("fCombatAngleXY")->getFloat()/2.0f).valueRadians(), @@ -589,22 +548,28 @@ namespace MWWorld if(!result.first) return std::make_pair(std::string(), Ogre::Vector3(&result.second[0])); return std::make_pair(result.first->mName, Ogre::Vector3(&result.second[0])); + */ } - bool PhysicsSystem::castRay(const Vector3& from, const Vector3& to, bool ignoreHeightMap) + bool PhysicsSystem::castRay(const Ogre::Vector3& from, const Ogre::Vector3& to, bool ignoreHeightMap) { + return false; + /* btVector3 _from, _to; _from = btVector3(from.x, from.y, from.z); _to = btVector3(to.x, to.y, to.z); std::pair result = mEngine->rayTest(_from, _to,ignoreHeightMap); return !(result.first == ""); + */ } std::pair PhysicsSystem::castRay(const Ogre::Vector3 &orig, const Ogre::Vector3 &dir, float len) { + return std::make_pair(false, Ogre::Vector3()); + /* Ogre::Ray ray = Ogre::Ray(orig, dir); Ogre::Vector3 to = ray.getPoint(len); @@ -616,125 +581,42 @@ namespace MWWorld return std::make_pair(false, Ogre::Vector3()); } return std::make_pair(true, ray.getPoint(len * test.second)); + */ } std::vector PhysicsSystem::getCollisions(const Ptr &ptr, int collisionGroup, int collisionMask) { - return mEngine->getCollisions(ptr.getRefData().getBaseNodeOld()->getName(), collisionGroup, collisionMask); + return std::vector();//mEngine->getCollisions(ptr.getRefData().getBaseNodeOld()->getName(), collisionGroup, collisionMask); } Ogre::Vector3 PhysicsSystem::traceDown(const MWWorld::Ptr &ptr, float maxHeight) { - return MovementSolver::traceDown(ptr, mEngine, maxHeight); + return Ogre::Vector3();//MovementSolver::traceDown(ptr, mEngine, maxHeight); } void PhysicsSystem::addHeightField (float* heights, int x, int y, float yoffset, float triSize, float sqrtVerts) { - mEngine->addHeightField(heights, x, y, yoffset, triSize, sqrtVerts); } void PhysicsSystem::removeHeightField (int x, int y) { - mEngine->removeHeightField(x, y); } void PhysicsSystem::addObject (const Ptr& ptr, const std::string& mesh, bool placeable) { - /* - Ogre::SceneNode* node = ptr.getRefData().getBaseNodeOld(); - handleToMesh[node->getName()] = mesh; - mEngine->createAndAdjustRigidBody( - mesh, node->getName(), ptr.getCellRef().getScale(), node->getPosition(), node->getOrientation(), 0, 0, false, placeable); - mEngine->createAndAdjustRigidBody( - mesh, node->getName(), ptr.getCellRef().getScale(), node->getPosition(), node->getOrientation(), 0, 0, true, placeable); - */ - } - - void PhysicsSystem::addActor (const Ptr& ptr, const std::string& mesh) - { - /* - Ogre::SceneNode* node = ptr.getRefData().getBaseNodeOld(); - //TODO:optimize this. Searching the std::map isn't very efficient i think. - mEngine->addCharacter(node->getName(), mesh, node->getPosition(), node->getScale().x, node->getOrientation()); - */ - } - - void PhysicsSystem::removeObject (const std::string& handle) - { - mEngine->removeCharacter(handle); - mEngine->removeRigidBody(handle); - mEngine->deleteRigidBody(handle); - } - - void PhysicsSystem::moveObject (const Ptr& ptr) - { - Ogre::SceneNode *node = ptr.getRefData().getBaseNodeOld(); - const std::string &handle = node->getName(); - const Ogre::Vector3 &position = node->getPosition(); - - if(OEngine::Physic::RigidBody *body = mEngine->getRigidBody(handle)) - { - body->getWorldTransform().setOrigin(btVector3(position.x,position.y,position.z)); - mEngine->mDynamicsWorld->updateSingleAabb(body); - } - - // Actors update their AABBs every frame (DISABLE_DEACTIVATION), so no need to do it manually - if(OEngine::Physic::PhysicActor *physact = mEngine->getCharacter(handle)) - physact->setPosition(position); - } - - void PhysicsSystem::rotateObject (const Ptr& ptr) - { - Ogre::SceneNode* node = ptr.getRefData().getBaseNodeOld(); - const std::string &handle = node->getName(); - const Ogre::Quaternion &rotation = node->getOrientation(); - // TODO: map to MWWorld::Ptr for faster access - if (OEngine::Physic::PhysicActor* act = mEngine->getCharacter(handle)) - { - act->setRotation(rotation); - } - if (OEngine::Physic::RigidBody* body = mEngine->getRigidBody(handle)) - { - if(dynamic_cast(body->getCollisionShape()) == NULL) - body->getWorldTransform().setRotation(btQuaternion(rotation.x, rotation.y, rotation.z, rotation.w)); - else - mEngine->boxAdjustExternal(handleToMesh[handle], body, node->getScale().x, node->getPosition(), rotation); - mEngine->mDynamicsWorld->updateSingleAabb(body); - } } - void PhysicsSystem::scaleObject (const Ptr& ptr) + void PhysicsSystem::addActor (const Ptr& ptr, const std::string& mesh) { - Ogre::SceneNode* node = ptr.getRefData().getBaseNodeOld(); - const std::string &handle = node->getName(); - if(handleToMesh.find(handle) != handleToMesh.end()) - { - std::string model = ptr.getClass().getModel(ptr); - //model = Misc::ResourceHelpers::correctActorModelPath(model); // FIXME: scaling shouldn't require model - - bool placeable = false; - if (OEngine::Physic::RigidBody* body = mEngine->getRigidBody(handle)) - placeable = body->mPlaceable; - removeObject(handle); - addObject(ptr, model, placeable); - } - if (OEngine::Physic::PhysicActor* act = mEngine->getCharacter(handle)) - { - float scale = ptr.getCellRef().getScale(); - osg::Vec3f scaleVec (scale,scale,scale); - if (!ptr.getClass().isNpc()) - // NOTE: Ignoring Npc::adjustScale (race height) on purpose. This is a bug in MW and must be replicated for compatibility reasons - ptr.getClass().adjustScale(ptr, scaleVec); - act->setScale(scaleVec.x()); - } } bool PhysicsSystem::toggleCollisionMode() { + /* for(std::map::iterator it = mEngine->mActorMap.begin(); it != mEngine->mActorMap.end();++it) { if (it->first=="player") @@ -756,6 +638,8 @@ namespace MWWorld } throw std::logic_error ("can't find player"); + */ + return false; } void PhysicsSystem::queueObjectMovement(const Ptr &ptr, const Ogre::Vector3 &movement) @@ -791,6 +675,8 @@ namespace MWWorld mCollisions.clear(); mStandingCollisions.clear(); + /* + const MWBase::World *world = MWBase::Environment::get().getWorld(); PtrVelocityList::iterator iter = mMovementQueue.begin(); for(;iter != mMovementQueue.end();++iter) @@ -831,6 +717,8 @@ namespace MWWorld mMovementResults.push_back(std::make_pair(iter->first, newpos)); } + */ + mTimeAccum = 0.0f; } mMovementQueue.clear(); @@ -840,9 +728,9 @@ namespace MWWorld void PhysicsSystem::stepSimulation(float dt) { - animateCollisionShapes(mEngine->mAnimatedShapes, mEngine->mDynamicsWorld); + //animateCollisionShapes(mEngine->mAnimatedShapes, mEngine->mDynamicsWorld); - mEngine->stepSimulation(dt); + //mEngine->stepSimulation(dt); if (mDebugDrawer.get()) mDebugDrawer->step(); @@ -932,7 +820,7 @@ namespace MWWorld { if (mWaterCollisionObject.get()) { - mEngine->mDynamicsWorld->removeCollisionObject(mWaterCollisionObject.get()); + //mEngine->mDynamicsWorld->removeCollisionObject(mWaterCollisionObject.get()); } if (!mWaterEnabled) @@ -941,7 +829,7 @@ namespace MWWorld mWaterCollisionObject.reset(new btCollisionObject()); mWaterCollisionShape.reset(new btStaticPlaneShape(btVector3(0,0,1), mWaterHeight)); mWaterCollisionObject->setCollisionShape(mWaterCollisionShape.get()); - mEngine->mDynamicsWorld->addCollisionObject(mWaterCollisionObject.get(), OEngine::Physic::CollisionType_Water, - OEngine::Physic::CollisionType_Actor); + //mEngine->mDynamicsWorld->addCollisionObject(mWaterCollisionObject.get(), OEngine::Physic::CollisionType_Water, + // OEngine::Physic::CollisionType_Actor); } } diff --git a/apps/openmw/mwworld/physicssystem.hpp b/apps/openmw/mwworld/physicssystem.hpp index 1fc0e0e76..018ea0a28 100644 --- a/apps/openmw/mwworld/physicssystem.hpp +++ b/apps/openmw/mwworld/physicssystem.hpp @@ -55,15 +55,6 @@ namespace MWWorld void removeHeightField (int x, int y); - // have to keep this as handle for now as unloadcell only knows scenenode names - void removeObject (const std::string& handle); - - void moveObject (const MWWorld::Ptr& ptr); - - void rotateObject (const MWWorld::Ptr& ptr); - - void scaleObject (const MWWorld::Ptr& ptr); - bool toggleCollisionMode(); void stepSimulation(float dt); @@ -82,8 +73,6 @@ namespace MWWorld std::pair castRay(const Ogre::Vector3 &orig, const Ogre::Vector3 &dir, float len); - OEngine::Physic::PhysicEngine* getEngine(); - /// Queues velocity movement for a Ptr. If a Ptr is already queued, its velocity will /// be overwritten. Valid until the next call to applyQueuedMovement. void queueObjectMovement(const Ptr &ptr, const Ogre::Vector3 &velocity); @@ -117,7 +106,6 @@ namespace MWWorld bool mDebugDrawEnabled; - OEngine::Physic::PhysicEngine* mEngine; std::map handleToMesh; // Tracks all movement collisions happening during a single frame. diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 04fd82e80..7047978ff 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -13,9 +13,6 @@ #include -#include -#include - #include #include @@ -59,8 +56,6 @@ #include "contentloader.hpp" #include "esmloader.hpp" -using namespace Ogre; - namespace { @@ -1402,7 +1397,7 @@ namespace MWWorld cellY = static_cast(std::floor(y / cellSize)); } - void World::queueMovement(const Ptr &ptr, const Vector3 &velocity) + void World::queueMovement(const Ptr &ptr, const Ogre::Vector3 &velocity) { //mPhysics->queueObjectMovement(ptr, velocity); } @@ -1630,7 +1625,9 @@ namespace MWWorld void World::updateSoundListener() { + /* Ogre::Vector3 playerPos = mPlayer->getPlayer().getRefData().getBaseNodeOld()->getPosition(); + const OEngine::Physic::PhysicActor *actor = mPhysEngine->getCharacter(getPlayerPtr().getRefData().getHandle()); if(actor) playerPos.z += 1.85f * actor->getHalfExtents().z; Ogre::Quaternion playerOrient = Ogre::Quaternion(Ogre::Radian(getPlayerPtr().getRefData().getPosition().rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z) * @@ -1638,6 +1635,7 @@ namespace MWWorld Ogre::Quaternion(Ogre::Radian(getPlayerPtr().getRefData().getPosition().rot[1]), Ogre::Vector3::NEGATIVE_UNIT_Y); MWBase::Environment::get().getSoundManager()->setListenerPosDir(playerPos, playerOrient.yAxis(), playerOrient.zAxis()); + */ } void World::updateWindowManager () @@ -1654,7 +1652,7 @@ namespace MWWorld Ogre::AxisAlignedBox bounds = node->_getWorldAABB(); if (bounds.isFinite()) { - Vector4 screenCoords;// = mRendering->boundingBoxToScreen(bounds); + Ogre::Vector4 screenCoords;// = mRendering->boundingBoxToScreen(bounds); MWBase::Environment::get().getWindowManager()->setFocusObjectScreenCoords( screenCoords[0], screenCoords[1], screenCoords[2], screenCoords[3]); } @@ -1746,11 +1744,11 @@ namespace MWWorld MWWorld::CellRefList& statics = cell->get(); MWWorld::LiveCellRef* ref = statics.find("northmarker"); if (!ref) - return Vector2(0, 1); + return Ogre::Vector2(0, 1); Ogre::Quaternion orient (Ogre::Radian(-ref->mData.getPosition().rot[2]), Ogre::Vector3::UNIT_Z); - Vector3 dir = orient * Ogre::Vector3(0,1,0); - Vector2 d = Vector2(dir.x, dir.y); + Ogre::Vector3 dir = orient * Ogre::Vector3(0,1,0); + Ogre::Vector2 d = Ogre::Vector2(dir.x, dir.y); return d; } @@ -2002,9 +2000,9 @@ namespace MWWorld && isLevitationEnabled()) return true; - const OEngine::Physic::PhysicActor *actor = 0;//mPhysEngine->getCharacter(ptr.getRefData().getHandle()); - if(!actor || !actor->getCollisionMode()) - return true; + //const OEngine::Physic::PhysicActor *actor = 0;//mPhysEngine->getCharacter(ptr.getRefData().getHandle()); + //if(!actor || !actor->getCollisionMode()) + // return true; return false; } @@ -2042,10 +2040,10 @@ namespace MWWorld const float *fpos = object.getRefData().getPosition().pos; Ogre::Vector3 pos(fpos[0], fpos[1], fpos[2]); - const OEngine::Physic::PhysicActor *actor = 0;//mPhysEngine->getCharacter(object.getRefData().getHandle()); - if (actor) + //const OEngine::Physic::PhysicActor *actor = 0;//mPhysEngine->getCharacter(object.getRefData().getHandle()); + //if (actor) { - pos.z += heightRatio*2*actor->getHalfExtents().z; + // pos.z += heightRatio*2*actor->getHalfExtents().z; } return isUnderwater(object.getCell(), pos); @@ -2071,6 +2069,8 @@ namespace MWWorld // TODO: There might be better places to update PhysicActor::mOnGround. bool World::isOnGround(const MWWorld::Ptr &ptr) const { + return true; + /* //RefData &refdata = ptr.getRefData(); OEngine::Physic::PhysicActor *physactor = 0;//mPhysEngine->getCharacter(refdata.getHandle()); @@ -2096,6 +2096,7 @@ namespace MWWorld else return false; } + */ } bool World::vanityRotateCamera(float * rot) @@ -2371,6 +2372,7 @@ namespace MWWorld if (!targetActor.getRefData().getBaseNodeOld() || !targetActor.getRefData().getBaseNodeOld()) return false; // not in active cell + /* OEngine::Physic::PhysicActor* actor1 = mPhysEngine->getCharacter(actor.getRefData().getHandle()); OEngine::Physic::PhysicActor* actor2 = mPhysEngine->getCharacter(targetActor.getRefData().getHandle()); @@ -2387,12 +2389,15 @@ namespace MWWorld std::pair result = mPhysEngine->rayTest(from, to,false); if(result.first == "") return true; + */ return false; } float World::getDistToNearestRayHit(const Ogre::Vector3& from, const Ogre::Vector3& dir, float maxDist) { + return 0; + /* btVector3 btFrom(from.x, from.y, from.z); btVector3 btTo = btVector3(dir.x, dir.y, dir.z); btTo.normalize(); @@ -2402,13 +2407,16 @@ namespace MWWorld if(result.second == -1) return maxDist; else return result.second*(btTo-btFrom).length(); + */ } void World::enableActorCollision(const MWWorld::Ptr& actor, bool enable) { + /* OEngine::Physic::PhysicActor *physicActor = 0;//mPhysEngine->getCharacter(actor.getRefData().getHandle()); if (physicActor) physicActor->enableCollisionBody(enable); + */ } bool World::findInteriorPosition(const std::string &name, ESM::Position &pos) @@ -3235,7 +3243,7 @@ namespace MWWorld mRendering->spawnEffect(model, textureOverride, worldPos); } - void World::explodeSpell(const Vector3 &origin, const ESM::EffectList &effects, const Ptr &caster, ESM::RangeType rangeType, + void World::explodeSpell(const Ogre::Vector3 &origin, const ESM::EffectList &effects, const Ptr &caster, ESM::RangeType rangeType, const std::string& id, const std::string& sourceName) { std::map > toApply; @@ -3350,9 +3358,12 @@ namespace MWWorld bool World::isWalkingOnWater(const Ptr &actor) { + return false; + /* OEngine::Physic::PhysicActor* physicActor = mPhysEngine->getCharacter(actor.getRefData().getHandle()); if (physicActor && physicActor->isWalkingOnWater()) return true; return false; + */ } } diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 1f9bd337b..931d84e26 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -52,9 +52,9 @@ add_component_dir (nifosg nifloader controller particle userdata ) -add_component_dir (nifbullet - bulletnifloader - ) +#add_component_dir (nifbullet +# bulletnifloader +# ) add_component_dir (to_utf8 to_utf8 diff --git a/components/myguiplatform/myguiloglistener.hpp b/components/myguiplatform/myguiloglistener.hpp index 3da4d3c52..70dfc4ecf 100644 --- a/components/myguiplatform/myguiloglistener.hpp +++ b/components/myguiplatform/myguiloglistener.hpp @@ -1,5 +1,5 @@ -#ifndef OPENENGINE_MYGUI_LOGLISTENER_H -#define OPENENGINE_MYGUI_LOGLISTENER_H +#ifndef OPENMW_COMPONENTS_MYGUIPLATFORM_LOGLISTENER_H +#define OPENMW_COMPONENTS_MYGUIPLATFORM_LOGLISTENER_H #include #include diff --git a/components/nifbullet/bulletnifloader.hpp b/components/nifbullet/bulletnifloader.hpp index b3e30cbd9..2a2e914e3 100644 --- a/components/nifbullet/bulletnifloader.hpp +++ b/components/nifbullet/bulletnifloader.hpp @@ -26,11 +26,11 @@ #include #include +#include #include #include #include #include -#include #include @@ -70,8 +70,7 @@ class ManualBulletShapeLoader { public: ManualBulletShapeLoader(bool showMarkers=false) - : mShape(NULL) - , mCompoundShape(NULL) + : mCompoundShape(NULL) , mStaticMesh(NULL) , mBoundingBox(NULL) , mShowMarkers(showMarkers) @@ -91,11 +90,6 @@ public: abort(); } - /** - *This function should not be called manualy. Use load instead. (this is called by the BulletShapeManager when you use load). - */ - void loadResource(Ogre::Resource *resource); - private: btVector3 getbtVector(Ogre::Vector3 const &v); @@ -116,7 +110,7 @@ private: std::string mResourceName; - OEngine::Physic::BulletShape* mShape;//current shape + //OEngine::Physic::BulletShape* mShape;//current shape btCompoundShape* mCompoundShape; diff --git a/libs/openengine/.gitignore b/libs/openengine/.gitignore deleted file mode 100644 index 23a5e931b..000000000 --- a/libs/openengine/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -*~ -*.o -*_test diff --git a/libs/openengine/CMakeLists.txt b/libs/openengine/CMakeLists.txt deleted file mode 100644 index 52c12a84a..000000000 --- a/libs/openengine/CMakeLists.txt +++ /dev/null @@ -1,17 +0,0 @@ -set(OENGINE_BULLET - bullet/physic.cpp - bullet/physic.hpp - bullet/BulletShapeLoader.cpp - bullet/BulletShapeLoader.h - bullet/trace.cpp - bullet/trace.h -) - -set(OENGINE_ALL ${OENGINE_BULLET}) - -set(OENGINE_LIBRARY "oengine") -set(OENGINE_LIBRARY ${OENGINE_LIBRARY} PARENT_SCOPE) - -source_group(oengine FILES ${OENGINE_ALL}) - -add_library(${OENGINE_LIBRARY} STATIC ${OENGINE_ALL}) diff --git a/libs/openengine/README b/libs/openengine/README deleted file mode 100644 index 621fe8d60..000000000 --- a/libs/openengine/README +++ /dev/null @@ -1,12 +0,0 @@ -OpenEngine README -================= - -OpenEngine is a bunch of stand-alone game engine modules collected from the OpenMW project (see http://github.com/korslund/openmw or http://openmw.com ) and from certain other projects. - -It is currently a very early work in progress, and development will follow OpenMW closely for a while forward. - -OpenEngine will depend heavily on Mangle ( http://github.com/korslund/mangle/ ) and will thus aim to be backend agnostic. When finished it should work with a variety for free and commercial middleware libraries as backends for graphics, sound, physics, input and so on. - -All questions can be directed to Nicolay Korslund at korslund@gmail.com - -- Nicolay diff --git a/libs/openengine/bullet/BulletShapeLoader.cpp b/libs/openengine/bullet/BulletShapeLoader.cpp deleted file mode 100644 index d164b9b23..000000000 --- a/libs/openengine/bullet/BulletShapeLoader.cpp +++ /dev/null @@ -1,66 +0,0 @@ -#include "BulletShapeLoader.h" - -namespace OEngine { -namespace Physic -{ - -BulletShape::BulletShape(Ogre::ResourceManager* creator, const Ogre::String &name, - Ogre::ResourceHandle handle, const Ogre::String &group, bool isManual, - Ogre::ManualResourceLoader *loader) : -Ogre::Resource(creator, name, handle, group, isManual, loader) -{ - /* If you were storing a pointer to an object, then you would set that pointer to NULL here. - */ - - /* For consistency with StringInterface, but we don't add any parameters here - That's because the Resource implementation of StringInterface is to - list all the options that need to be set before loading, of which - we have none as such. Full details can be set through scripts. - */ - mCollisionShape = NULL; - mAutogenerated = true; - createParamDictionary("BulletShape"); -} - -BulletShape::~BulletShape() -{ - deleteShape(mCollisionShape); -} - -// farm out to BulletShapeLoader -void BulletShape::loadImpl() -{ - mLoader->loadResource(this); -} - -void BulletShape::deleteShape(btCollisionShape* shape) -{ - if(shape!=NULL) - { - if(shape->isCompound()) - { - btCompoundShape* ms = static_cast(shape); - int a = ms->getNumChildShapes(); - for(int i=0; i getChildShape(i)); - } - } - delete shape; - } -} - -void BulletShape::unloadImpl() -{ - deleteShape(mCollisionShape); - mCollisionShape = NULL; -} - -//TODO:change this? -size_t BulletShape::calculateSize() const -{ - return 1; -} - -} -} diff --git a/libs/openengine/bullet/BulletShapeLoader.h b/libs/openengine/bullet/BulletShapeLoader.h deleted file mode 100644 index a856e8153..000000000 --- a/libs/openengine/bullet/BulletShapeLoader.h +++ /dev/null @@ -1,59 +0,0 @@ -#ifndef OPENMW_BULLET_SHAPE_LOADER_H_ -#define OPENMW_BULLET_SHAPE_LOADER_H_ - -#include -#include -#include -#include - -#include -#include - -namespace OEngine { -namespace Physic -{ - -/** -*Define a new resource which describe a Shape usable by bullet.See BulletShapeManager for how to get/use them. -*/ -class BulletShape : public Ogre::Resource -{ -protected: - void loadImpl(); - void unloadImpl(); - size_t calculateSize() const; - - void deleteShape(btCollisionShape* shape); - -public: - - BulletShape(Ogre::ResourceManager *creator, const Ogre::String &name, - Ogre::ResourceHandle handle, const Ogre::String &group, bool isManual = false, - Ogre::ManualResourceLoader *loader = 0); - - virtual ~BulletShape(); - - // Stores animated collision shapes. If any collision nodes in the NIF are animated, then mCollisionShape - // will be a btCompoundShape (which consists of one or more child shapes). - // In this map, for each animated collision shape, - // we store the node's record index mapped to the child index of the shape in the btCompoundShape. - std::map mAnimatedShapes; - - btCollisionShape* mCollisionShape; - - // Does this .nif have an autogenerated collision mesh? - bool mAutogenerated; - - osg::Vec3f mBoxTranslation; - osg::Quat mBoxRotation; -}; - -/** -* -*/ - -typedef Ogre::SharedPtr BulletShapePtr; -} -} - -#endif diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp deleted file mode 100644 index 391d266df..000000000 --- a/libs/openengine/bullet/physic.cpp +++ /dev/null @@ -1,709 +0,0 @@ -#include "physic.hpp" - -#include -#include -#include - -#include -#include - -#include - -#include -#include - -namespace -{ - -// Create a copy of the given collision shape (responsibility of user to delete the returned shape). -btCollisionShape *duplicateCollisionShape(btCollisionShape *shape) -{ - if(shape->isCompound()) - { - btCompoundShape *comp = static_cast(shape); - btCompoundShape *newShape = new btCompoundShape; - - int numShapes = comp->getNumChildShapes(); - for(int i = 0;i < numShapes;i++) - { - btCollisionShape *child = duplicateCollisionShape(comp->getChildShape(i)); - btTransform trans = comp->getChildTransform(i); - newShape->addChildShape(trans, child); - } - - return newShape; - } - - if(btBvhTriangleMeshShape *trishape = dynamic_cast(shape)) - { - btTriangleMesh* oldMesh = static_cast(trishape->getMeshInterface()); - btTriangleMesh* newMesh = new btTriangleMesh(*oldMesh); - NifBullet::TriangleMeshShape *newShape = new NifBullet::TriangleMeshShape(newMesh, true); - - return newShape; - } - - throw std::logic_error(std::string("Unhandled Bullet shape duplication: ")+shape->getName()); -} - -void deleteShape(btCollisionShape* shape) -{ - if(shape!=NULL) - { - if(shape->isCompound()) - { - btCompoundShape* ms = static_cast(shape); - int a = ms->getNumChildShapes(); - for(int i=0; i getChildShape(i)); - } - } - delete shape; - } -} - -} - -namespace OEngine { -namespace Physic -{ - - PhysicActor::PhysicActor(const std::string &name, const std::string &mesh, PhysicEngine *engine, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, float scale) - : mCanWaterWalk(false), mWalkingOnWater(false) - , mBody(0), mScale(scale), mForce(0.0f), mOnGround(false) - , mInternalCollisionMode(true) - , mExternalCollisionMode(true) - , mMesh(mesh), mName(name), mEngine(engine) - { - /* - if (!NifBullet::getBoundingBox(mMesh, mHalfExtents, mMeshTranslation, mMeshOrientation)) - { - mHalfExtents = Ogre::Vector3(0.f); - mMeshTranslation = Ogre::Vector3(0.f); - mMeshOrientation = Ogre::Quaternion::IDENTITY; - } - */ - /* - // Use capsule shape only if base is square (nonuniform scaling apparently doesn't work on it) - if (std::abs(mHalfExtents.x-mHalfExtents.y)= mHalfExtents.x) - { - // Could also be btCapsuleShapeZ, but the movement solver seems to have issues with it (jumping on slopes doesn't work) - mShape.reset(new btCylinderShapeZ(BtOgre::Convert::toBullet(mHalfExtents))); - } - else - mShape.reset(new btBoxShape(BtOgre::Convert::toBullet(mHalfExtents))); - */ - - mShape->setLocalScaling(btVector3(scale,scale,scale)); - - btRigidBody::btRigidBodyConstructionInfo CI = btRigidBody::btRigidBodyConstructionInfo - (0,0, mShape.get()); - mBody = new RigidBody(CI, name); - mBody->mPlaceable = false; - mBody->setCollisionFlags(btCollisionObject::CF_KINEMATIC_OBJECT); - mBody->setActivationState(DISABLE_DEACTIVATION); - - setPosition(position); - setRotation(rotation); - - updateCollisionMask(); - } - - PhysicActor::~PhysicActor() - { - if(mBody) - { - mEngine->mDynamicsWorld->removeRigidBody(mBody); - delete mBody; - } - } - - void PhysicActor::enableCollisionMode(bool collision) - { - mInternalCollisionMode = collision; - } - - void PhysicActor::enableCollisionBody(bool collision) - { - if (mExternalCollisionMode != collision) - { - mExternalCollisionMode = collision; - updateCollisionMask(); - } - } - - void PhysicActor::updateCollisionMask() - { - mEngine->mDynamicsWorld->removeRigidBody(mBody); - int collisionMask = CollisionType_World | CollisionType_HeightMap; - if (mExternalCollisionMode) - collisionMask |= CollisionType_Actor | CollisionType_Projectile; - if (mCanWaterWalk) - collisionMask |= CollisionType_Water; - mEngine->mDynamicsWorld->addRigidBody(mBody, CollisionType_Actor, collisionMask); - } - - const Ogre::Vector3& PhysicActor::getPosition() const - { - return mPosition; - } - - void PhysicActor::setPosition(const Ogre::Vector3 &position) - { - assert(mBody); - - mPosition = position; - - //btTransform tr = mBody->getWorldTransform(); - //Ogre::Quaternion meshrot = mMeshOrientation; - //Ogre::Vector3 transrot = meshrot * (mMeshTranslation * mScale); - //Ogre::Vector3 newPosition = transrot + position; - - //tr.setOrigin(BtOgre::Convert::toBullet(newPosition)); - //mBody->setWorldTransform(tr); - } - - void PhysicActor::setRotation (const Ogre::Quaternion& rotation) - { - //btTransform tr = mBody->getWorldTransform(); - //tr.setRotation(BtOgre::Convert::toBullet(mMeshOrientation * rotation)); - //mBody->setWorldTransform(tr); - } - - void PhysicActor::setScale(float scale) - { - mScale = scale; - mShape->setLocalScaling(btVector3(scale,scale,scale)); - setPosition(mPosition); - } - - Ogre::Vector3 PhysicActor::getHalfExtents() const - { - return mHalfExtents * mScale; - } - - void PhysicActor::setInertialForce(const Ogre::Vector3 &force) - { - mForce = force; - } - - void PhysicActor::setOnGround(bool grounded) - { - mOnGround = grounded; - } - - bool PhysicActor::isWalkingOnWater() const - { - return mWalkingOnWater; - } - - void PhysicActor::setWalkingOnWater(bool walkingOnWater) - { - mWalkingOnWater = walkingOnWater; - } - - void PhysicActor::setCanWaterWalk(bool waterWalk) - { - if (waterWalk != mCanWaterWalk) - { - mCanWaterWalk = waterWalk; - updateCollisionMask(); - } - } - - //////////////////////////////////////////////////////////////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - - RigidBody::RigidBody(btRigidBody::btRigidBodyConstructionInfo& CI,std::string name) - : btRigidBody(CI) - , mName(name) - , mPlaceable(false) - { - } - - RigidBody::~RigidBody() - { - delete getMotionState(); - } - - - - /////////////////////////////////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////////////////////////////////// - - - - PhysicEngine::PhysicEngine() - { - // Set up the collision configuration and dispatcher - mCollisionConfiguration = new btDefaultCollisionConfiguration(); - mDispatcher = new btCollisionDispatcher(mCollisionConfiguration); - - // The actual physics solver - mSolver = new btSequentialImpulseConstraintSolver; - - mBroadphase = new btDbvtBroadphase(); - - // The world. - mDynamicsWorld = new btDiscreteDynamicsWorld(mDispatcher,mBroadphase,mSolver,mCollisionConfiguration); - - // Don't update AABBs of all objects every frame. Most objects in MW are static, so we don't need this. - // Should a "static" object ever be moved, we have to update its AABB manually using DynamicsWorld::updateSingleAabb. - mDynamicsWorld->setForceUpdateAllAabbs(false); - - mDynamicsWorld->setGravity(btVector3(0,0,-10)); - } - - PhysicEngine::~PhysicEngine() - { - for (std::map::iterator it = mAnimatedShapes.begin(); it != mAnimatedShapes.end(); ++it) - deleteShape(it->second.mCompound); - - HeightFieldContainer::iterator hf_it = mHeightFieldMap.begin(); - for (; hf_it != mHeightFieldMap.end(); ++hf_it) - { - mDynamicsWorld->removeRigidBody(hf_it->second.mBody); - delete hf_it->second.mShape; - delete hf_it->second.mBody; - } - - RigidBodyContainer::iterator rb_it = mCollisionObjectMap.begin(); - for (; rb_it != mCollisionObjectMap.end(); ++rb_it) - { - if (rb_it->second != NULL) - { - mDynamicsWorld->removeRigidBody(rb_it->second); - - delete rb_it->second; - rb_it->second = NULL; - } - } - - PhysicActorContainer::iterator pa_it = mActorMap.begin(); - for (; pa_it != mActorMap.end(); ++pa_it) - { - if (pa_it->second != NULL) - { - delete pa_it->second; - pa_it->second = NULL; - } - } - - delete mDynamicsWorld; - delete mSolver; - delete mCollisionConfiguration; - delete mDispatcher; - delete mBroadphase; - } - - void PhysicEngine::addHeightField(float* heights, - int x, int y, float yoffset, - float triSize, float sqrtVerts) - { - const std::string name = "HeightField_" - + boost::lexical_cast(x) + "_" - + boost::lexical_cast(y); - - // find the minimum and maximum heights (needed for bullet) - float minh = heights[0]; - float maxh = heights[0]; - for (int i=0; imaxh) maxh = h; - if (h(sqrtVerts), static_cast(sqrtVerts), heights, 1, - minh, maxh, 2, - PHY_FLOAT,true); - - hfShape->setUseDiamondSubdivision(true); - - btVector3 scl(triSize, triSize, 1); - hfShape->setLocalScaling(scl); - - btRigidBody::btRigidBodyConstructionInfo CI = btRigidBody::btRigidBodyConstructionInfo(0,0,hfShape); - RigidBody* body = new RigidBody(CI,name); - body->getWorldTransform().setOrigin(btVector3( (x+0.5f)*triSize*(sqrtVerts-1), (y+0.5f)*triSize*(sqrtVerts-1), (maxh+minh)/2.f)); - - HeightField hf; - hf.mBody = body; - hf.mShape = hfShape; - - mHeightFieldMap [name] = hf; - - mDynamicsWorld->addRigidBody(body,CollisionType_HeightMap, - CollisionType_Actor|CollisionType_Projectile); - } - - void PhysicEngine::removeHeightField(int x, int y) - { - const std::string name = "HeightField_" - + boost::lexical_cast(x) + "_" - + boost::lexical_cast(y); - - HeightFieldContainer::iterator it = mHeightFieldMap.find(name); - if (it == mHeightFieldMap.end()) - return; - - const HeightField& hf = it->second; - - mDynamicsWorld->removeRigidBody(hf.mBody); - delete hf.mShape; - delete hf.mBody; - - mHeightFieldMap.erase(it); - } - - void PhysicEngine::adjustRigidBody(RigidBody* body, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, - const Ogre::Vector3 &scaledBoxTranslation, const Ogre::Quaternion &boxRotation) - { - btTransform tr; - Ogre::Quaternion boxrot = rotation * boxRotation; - Ogre::Vector3 transrot = boxrot * scaledBoxTranslation; - Ogre::Vector3 newPosition = transrot + position; - - tr.setOrigin(btVector3(newPosition.x, newPosition.y, newPosition.z)); - tr.setRotation(btQuaternion(boxrot.x,boxrot.y,boxrot.z,boxrot.w)); - body->setWorldTransform(tr); - } - void PhysicEngine::boxAdjustExternal(const std::string &mesh, RigidBody* body, - float scale, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation) - { - std::string sid = (boost::format("%07.3f") % scale).str(); - std::string outputstring = mesh + sid; - - //get the shape from the .nif - //mShapeLoader->load(outputstring,"General"); - //BulletShapePtr shape = BulletShapeManager::getSingleton().getByName(outputstring,"General"); - - //adjustRigidBody(body, position, rotation, shape->mBoxTranslation * scale, shape->mBoxRotation); - } - - RigidBody* PhysicEngine::createAndAdjustRigidBody(const std::string &mesh, const std::string &name, - float scale, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, - Ogre::Vector3* scaledBoxTranslation, Ogre::Quaternion* boxRotation, bool placeable) - { - std::string sid = (boost::format("%07.3f") % scale).str(); - std::string outputstring = mesh + sid; - - //get the shape from the .nif - //mShapeLoader->load(outputstring,"General"); - BulletShapePtr shape;// = BulletShapeManager::getSingleton().getByName(outputstring,"General"); - - // TODO: add option somewhere to enable collision for placeable meshes - - if (placeable && shape->mCollisionShape) - return NULL; - - if (!shape->mCollisionShape) - return NULL; - - btCollisionShape* collisionShape = shape->mCollisionShape; - - // If this is an animated compound shape, we must duplicate it so we can animate - // multiple instances independently. - if (!shape->mAnimatedShapes.empty()) - collisionShape = duplicateCollisionShape(collisionShape); - - collisionShape->setLocalScaling( btVector3(scale,scale,scale)); - - //create the real body - btRigidBody::btRigidBodyConstructionInfo CI = btRigidBody::btRigidBodyConstructionInfo - (0,0, collisionShape); - RigidBody* body = new RigidBody(CI,name); - body->mPlaceable = placeable; - - if (!shape->mAnimatedShapes.empty()) - { - AnimatedShapeInstance instance; - instance.mAnimatedShapes = shape->mAnimatedShapes; - instance.mCompound = collisionShape; - mAnimatedShapes[body] = instance; - } - - //if(scaledBoxTranslation != 0) - // *scaledBoxTranslation = shape->mBoxTranslation * scale; - //if(boxRotation != 0) - // *boxRotation = shape->mBoxRotation; - - //adjustRigidBody(body, position, rotation, shape->mBoxTranslation * scale, shape->mBoxRotation); - - assert (mCollisionObjectMap.find(name) == mCollisionObjectMap.end()); - mCollisionObjectMap[name] = body; - mDynamicsWorld->addRigidBody(body,CollisionType_World,CollisionType_Actor|CollisionType_HeightMap); - - return body; - } - - void PhysicEngine::removeRigidBody(const std::string &name) - { - RigidBodyContainer::iterator it = mCollisionObjectMap.find(name); - if (it != mCollisionObjectMap.end() ) - { - RigidBody* body = it->second; - if(body != NULL) - { - mDynamicsWorld->removeRigidBody(body); - } - } - } - - void PhysicEngine::deleteRigidBody(const std::string &name) - { - RigidBodyContainer::iterator it = mCollisionObjectMap.find(name); - if (it != mCollisionObjectMap.end() ) - { - RigidBody* body = it->second; - - if(body != NULL) - { - if (mAnimatedShapes.find(body) != mAnimatedShapes.end()) - deleteShape(mAnimatedShapes[body].mCompound); - mAnimatedShapes.erase(body); - - delete body; - } - mCollisionObjectMap.erase(it); - } - } - - RigidBody* PhysicEngine::getRigidBody(const std::string &name) - { - RigidBodyContainer::iterator it = mCollisionObjectMap.find(name); - if (it != mCollisionObjectMap.end() ) - { - RigidBody* body = mCollisionObjectMap[name]; - return body; - } - else - { - return NULL; - } - } - - class ContactTestResultCallback : public btCollisionWorld::ContactResultCallback - { - public: - std::vector mResult; - - // added in bullet 2.81 - // this is just a quick hack, as there does not seem to be a BULLET_VERSION macro? -#if defined(BT_COLLISION_OBJECT_WRAPPER_H) - virtual btScalar addSingleResult(btManifoldPoint& cp, - const btCollisionObjectWrapper* colObj0Wrap,int partId0,int index0, - const btCollisionObjectWrapper* colObj1Wrap,int partId1,int index1) - { - const RigidBody* body = dynamic_cast(colObj0Wrap->m_collisionObject); - if (body) - mResult.push_back(body->mName); - - return 0.f; - } -#else - virtual btScalar addSingleResult(btManifoldPoint& cp, const btCollisionObject* col0, int partId0, int index0, - const btCollisionObject* col1, int partId1, int index1) - { - const RigidBody* body = dynamic_cast(col0); - if (body) - mResult.push_back(body->mName); - - return 0.f; - } -#endif - }; - - class DeepestNotMeContactTestResultCallback : public btCollisionWorld::ContactResultCallback - { - const std::string &mFilter; - // Store the real origin, since the shape's origin is its center - btVector3 mOrigin; - - public: - const RigidBody *mObject; - btVector3 mContactPoint; - btScalar mLeastDistSqr; - - DeepestNotMeContactTestResultCallback(const std::string &filter, const btVector3 &origin) - : mFilter(filter), mOrigin(origin), mObject(0), mContactPoint(0,0,0), - mLeastDistSqr(std::numeric_limits::max()) - { } - -#if defined(BT_COLLISION_OBJECT_WRAPPER_H) - virtual btScalar addSingleResult(btManifoldPoint& cp, - const btCollisionObjectWrapper* col0Wrap,int partId0,int index0, - const btCollisionObjectWrapper* col1Wrap,int partId1,int index1) - { - const RigidBody* body = dynamic_cast(col1Wrap->m_collisionObject); - if(body && body->mName != mFilter) - { - btScalar distsqr = mOrigin.distance2(cp.getPositionWorldOnA()); - if(!mObject || distsqr < mLeastDistSqr) - { - mObject = body; - mLeastDistSqr = distsqr; - mContactPoint = cp.getPositionWorldOnA(); - } - } - - return 0.f; - } -#else - virtual btScalar addSingleResult(btManifoldPoint& cp, - const btCollisionObject* col0, int partId0, int index0, - const btCollisionObject* col1, int partId1, int index1) - { - const RigidBody* body = dynamic_cast(col1); - if(body && body->mName != mFilter) - { - btScalar distsqr = mOrigin.distance2(cp.getPositionWorldOnA()); - if(!mObject || distsqr < mLeastDistSqr) - { - mObject = body; - mLeastDistSqr = distsqr; - mContactPoint = cp.getPositionWorldOnA(); - } - } - - return 0.f; - } -#endif - }; - - - std::vector PhysicEngine::getCollisions(const std::string& name, int collisionGroup, int collisionMask) - { - RigidBody* body = getRigidBody(name); - ContactTestResultCallback callback; - callback.m_collisionFilterGroup = collisionGroup; - callback.m_collisionFilterMask = collisionMask; - mDynamicsWorld->contactTest(body, callback); - return callback.mResult; - } - - - std::pair PhysicEngine::getFilteredContact(const std::string &filter, - const btVector3 &origin, - btCollisionObject *object) - { - DeepestNotMeContactTestResultCallback callback(filter, origin); - callback.m_collisionFilterGroup = CollisionType_Actor; - callback.m_collisionFilterMask = CollisionType_World | CollisionType_HeightMap | CollisionType_Actor; - mDynamicsWorld->contactTest(object, callback); - return std::make_pair(callback.mObject, callback.mContactPoint); - } - - void PhysicEngine::stepSimulation(double deltaT) - { - // This seems to be needed for character controller objects - mDynamicsWorld->stepSimulation(static_cast(deltaT), 10, 1 / 60.0f); - } - - void PhysicEngine::addCharacter(const std::string &name, const std::string &mesh, - const Ogre::Vector3 &position, float scale, const Ogre::Quaternion &rotation) - { - // Remove character with given name, so we don't make memory - // leak when character would be added twice - removeCharacter(name); - - PhysicActor* newActor = new PhysicActor(name, mesh, this, position, rotation, scale); - - mActorMap[name] = newActor; - } - - void PhysicEngine::removeCharacter(const std::string &name) - { - PhysicActorContainer::iterator it = mActorMap.find(name); - if (it != mActorMap.end() ) - { - PhysicActor* act = it->second; - if(act != NULL) - { - delete act; - } - mActorMap.erase(it); - } - } - - PhysicActor* PhysicEngine::getCharacter(const std::string &name) - { - PhysicActorContainer::iterator it = mActorMap.find(name); - if (it != mActorMap.end() ) - { - PhysicActor* act = mActorMap[name]; - return act; - } - else - { - return 0; - } - } - - std::pair PhysicEngine::rayTest(const btVector3 &from, const btVector3 &to, bool ignoreHeightMap, Ogre::Vector3* normal) - { - std::string name = ""; - float d = -1; - - btCollisionWorld::ClosestRayResultCallback resultCallback1(from, to); - resultCallback1.m_collisionFilterGroup = 0xff; - resultCallback1.m_collisionFilterMask = CollisionType_World; - - if(!ignoreHeightMap) - resultCallback1.m_collisionFilterMask = resultCallback1.m_collisionFilterMask | CollisionType_HeightMap; - mDynamicsWorld->rayTest(from, to, resultCallback1); - if (resultCallback1.hasHit()) - { - name = static_cast(*resultCallback1.m_collisionObject).mName; - d = resultCallback1.m_closestHitFraction; - if (normal) - *normal = Ogre::Vector3(resultCallback1.m_hitNormalWorld.x(), - resultCallback1.m_hitNormalWorld.y(), - resultCallback1.m_hitNormalWorld.z()); - } - - return std::pair(name,d); - } - - // callback that ignores player in results - struct OurClosestConvexResultCallback : public btCollisionWorld::ClosestConvexResultCallback - { - public: - OurClosestConvexResultCallback(const btVector3& convexFromWorld,const btVector3& convexToWorld) - : btCollisionWorld::ClosestConvexResultCallback(convexFromWorld, convexToWorld) {} - - virtual btScalar addSingleResult(btCollisionWorld::LocalConvexResult& convexResult,bool normalInWorldSpace) - { - if (const RigidBody* body = dynamic_cast(convexResult.m_hitCollisionObject)) - if (body->mName == "player") - return 0; - return btCollisionWorld::ClosestConvexResultCallback::addSingleResult(convexResult, normalInWorldSpace); - } - }; - - std::pair PhysicEngine::sphereCast (float radius, btVector3& from, btVector3& to) - { - OurClosestConvexResultCallback callback(from, to); - callback.m_collisionFilterGroup = 0xff; - callback.m_collisionFilterMask = OEngine::Physic::CollisionType_World|OEngine::Physic::CollisionType_HeightMap; - - btSphereShape shape(radius); - const btQuaternion btrot(0.0f, 0.0f, 0.0f); - - btTransform from_ (btrot, from); - btTransform to_ (btrot, to); - - mDynamicsWorld->convexSweepTest(&shape, from_, to_, callback); - - if (callback.hasHit()) - return std::make_pair(true, callback.m_closestHitFraction); - else - return std::make_pair(false, 1.0f); - } - -} -} diff --git a/libs/openengine/bullet/physic.hpp b/libs/openengine/bullet/physic.hpp deleted file mode 100644 index 691ccbfd6..000000000 --- a/libs/openengine/bullet/physic.hpp +++ /dev/null @@ -1,320 +0,0 @@ -#ifndef OENGINE_BULLET_PHYSIC_H -#define OENGINE_BULLET_PHYSIC_H - -#include -#include "BulletCollision/CollisionDispatch/btGhostObject.h" -#include -#include -#include -#include "BulletShapeLoader.h" -#include "BulletCollision/CollisionShapes/btScaledBvhTriangleMeshShape.h" -#include - -class btRigidBody; -class btBroadphaseInterface; -class btDefaultCollisionConfiguration; -class btSequentialImpulseConstraintSolver; -class btCollisionDispatcher; -class btDiscreteDynamicsWorld; -class btHeightfieldTerrainShape; - -namespace BtOgre -{ - class DebugDrawer; -} - -namespace Ogre -{ - class SceneManager; -} - -namespace MWWorld -{ - class World; -} - - -namespace OEngine { -namespace Physic -{ - struct PhysicEvent; - class PhysicEngine; - class RigidBody; - - enum CollisionType { - CollisionType_Nothing = 0, // mShape; - - OEngine::Physic::RigidBody* mBody; - - Ogre::Quaternion mMeshOrientation; - Ogre::Vector3 mMeshTranslation; - Ogre::Vector3 mHalfExtents; - - float mScale; - Ogre::Vector3 mPosition; - - Ogre::Vector3 mForce; - bool mOnGround; - bool mInternalCollisionMode; - bool mExternalCollisionMode; - - std::string mMesh; - std::string mName; - PhysicEngine *mEngine; - - PhysicActor(const PhysicActor&); - PhysicActor& operator=(const PhysicActor&); - }; - - - struct HeightField - { - btHeightfieldTerrainShape* mShape; - RigidBody* mBody; - }; - - struct AnimatedShapeInstance - { - btCollisionShape* mCompound; - - // Maps node record index to child index in the compound shape - std::map mAnimatedShapes; - }; - - /** - * The PhysicEngine class contain everything which is needed for Physic. - * It's needed that Ogre Resources are set up before the PhysicEngine is created. - * Note:deleting it WILL NOT delete the RigidBody! - * TODO:unload unused resources? - */ - class PhysicEngine - { - public: - /** - * Note that the shapeLoader IS destroyed by the phyic Engine!! - */ - PhysicEngine(); - - /** - * It DOES destroy the shape loader! - */ - ~PhysicEngine(); - - /** - * Creates a RigidBody. It does not add it to the simulation. - * After created, the body is set to the correct rotation, position, and scale - */ - RigidBody* createAndAdjustRigidBody(const std::string &mesh, const std::string &name, - float scale, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, - Ogre::Vector3* scaledBoxTranslation = 0, Ogre::Quaternion* boxRotation = 0, bool placeable=false); - - /** - * Adjusts a rigid body to the right position and rotation - */ - - void adjustRigidBody(RigidBody* body, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, - const Ogre::Vector3 &scaledBoxTranslation = Ogre::Vector3::ZERO, - const Ogre::Quaternion &boxRotation = Ogre::Quaternion::IDENTITY); - /** - Mainly used to (but not limited to) adjust rigid bodies based on box shapes to the right position and rotation. - */ - void boxAdjustExternal(const std::string &mesh, RigidBody* body, float scale, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation); - /** - * Add a HeightField to the simulation - */ - void addHeightField(float* heights, - int x, int y, float yoffset, - float triSize, float sqrtVerts); - - /** - * Remove a HeightField from the simulation - */ - void removeHeightField(int x, int y); - - /** - * Remove a RigidBody from the simulation. It does not delete it, and does not remove it from the RigidBodyMap. - */ - void removeRigidBody(const std::string &name); - - /** - * Delete a RigidBody, and remove it from RigidBodyMap. - */ - void deleteRigidBody(const std::string &name); - - /** - * Return a pointer to a given rigid body. - */ - RigidBody* getRigidBody(const std::string &name); - - /** - * Create and add a character to the scene, and add it to the ActorMap. - */ - void addCharacter(const std::string &name, const std::string &mesh, - const Ogre::Vector3 &position, float scale, const Ogre::Quaternion &rotation); - - /** - * Remove a character from the scene. - */ - void removeCharacter(const std::string &name); - - /** - * Return a pointer to a character - */ - PhysicActor* getCharacter(const std::string &name); - - /** - * This step the simulation of a given time. - */ - void stepSimulation(double deltaT); - - /** - * Return the closest object hit by a ray. If there are no objects, it will return ("",-1). - * If \a normal is non-NULL, the hit normal will be written there (if there is a hit) - */ - std::pair rayTest(const btVector3& from,const btVector3& to, - bool ignoreHeightMap = false, Ogre::Vector3* normal = NULL); - - std::pair sphereCast (float radius, btVector3& from, btVector3& to); - ///< @return (hit, relative distance) - - std::vector getCollisions(const std::string& name, int collisionGroup, int collisionMask); - - // Get the nearest object that's inside the given object, filtering out objects of the - // provided name - std::pair getFilteredContact(const std::string &filter, - const btVector3 &origin, - btCollisionObject *object); - - //Bullet Stuff - btBroadphaseInterface* mBroadphase; - btDefaultCollisionConfiguration* mCollisionConfiguration; - btSequentialImpulseConstraintSolver* mSolver; - btCollisionDispatcher* mDispatcher; - btDiscreteDynamicsWorld* mDynamicsWorld; - - typedef std::map HeightFieldContainer; - HeightFieldContainer mHeightFieldMap; - - typedef std::map RigidBodyContainer; - RigidBodyContainer mCollisionObjectMap; - - // Compound shapes that must be animated each frame based on bone positions - // the index refers to an element in mCollisionObjectMap - std::map mAnimatedShapes; - - typedef std::map PhysicActorContainer; - PhysicActorContainer mActorMap; - - private: - PhysicEngine(const PhysicEngine&); - PhysicEngine& operator=(const PhysicEngine&); - }; - - -}} - -#endif diff --git a/libs/openengine/bullet/trace.cpp b/libs/openengine/bullet/trace.cpp deleted file mode 100644 index c0f653dae..000000000 --- a/libs/openengine/bullet/trace.cpp +++ /dev/null @@ -1,133 +0,0 @@ - -#include "trace.h" - -#include - -#include -#include - -#include "physic.hpp" - - -namespace OEngine -{ -namespace Physic -{ - -class ClosestNotMeConvexResultCallback : public btCollisionWorld::ClosestConvexResultCallback -{ -public: - ClosestNotMeConvexResultCallback(btCollisionObject *me, const btVector3 &up, btScalar minSlopeDot) - : btCollisionWorld::ClosestConvexResultCallback(btVector3(0.0, 0.0, 0.0), btVector3(0.0, 0.0, 0.0)), - mMe(me), mUp(up), mMinSlopeDot(minSlopeDot) - { - } - - virtual btScalar addSingleResult(btCollisionWorld::LocalConvexResult& convexResult,bool normalInWorldSpace) - { - if(convexResult.m_hitCollisionObject == mMe) - return btScalar( 1 ); - - btVector3 hitNormalWorld; - if(normalInWorldSpace) - hitNormalWorld = convexResult.m_hitNormalLocal; - else - { - ///need to transform normal into worldspace - hitNormalWorld = convexResult.m_hitCollisionObject->getWorldTransform().getBasis()*convexResult.m_hitNormalLocal; - } - - // NOTE : m_hitNormalLocal is not always vertical on the ground with a capsule or a box... - - btScalar dotUp = mUp.dot(hitNormalWorld); - if(dotUp < mMinSlopeDot) - return btScalar(1); - - return ClosestConvexResultCallback::addSingleResult(convexResult, normalInWorldSpace); - } - -protected: - btCollisionObject *mMe; - const btVector3 mUp; - const btScalar mMinSlopeDot; -}; - - -void ActorTracer::doTrace(btCollisionObject *actor, const Ogre::Vector3 &start, const Ogre::Vector3 &end, const PhysicEngine *enginePass) -{ - const btVector3 btstart(start.x, start.y, start.z); - const btVector3 btend(end.x, end.y, end.z); - - const btTransform &trans = actor->getWorldTransform(); - btTransform from(trans); - btTransform to(trans); - from.setOrigin(btstart); - to.setOrigin(btend); - - ClosestNotMeConvexResultCallback newTraceCallback(actor, btstart-btend, btScalar(0.0)); - // Inherit the actor's collision group and mask - newTraceCallback.m_collisionFilterGroup = actor->getBroadphaseHandle()->m_collisionFilterGroup; - newTraceCallback.m_collisionFilterMask = actor->getBroadphaseHandle()->m_collisionFilterMask; - - btCollisionShape *shape = actor->getCollisionShape(); - assert(shape->isConvex()); - enginePass->mDynamicsWorld->convexSweepTest(static_cast(shape), - from, to, newTraceCallback); - - // Copy the hit data over to our trace results struct: - if(newTraceCallback.hasHit()) - { - const btVector3& tracehitnormal = newTraceCallback.m_hitNormalWorld; - mFraction = newTraceCallback.m_closestHitFraction; - mPlaneNormal = Ogre::Vector3(tracehitnormal.x(), tracehitnormal.y(), tracehitnormal.z()); - mEndPos = (end-start)*mFraction + start; - mHitObject = newTraceCallback.m_hitCollisionObject; - } - else - { - mEndPos = end; - mPlaneNormal = Ogre::Vector3(0.0f, 0.0f, 1.0f); - mFraction = 1.0f; - mHitObject = NULL; - } -} - -void ActorTracer::findGround(const OEngine::Physic::PhysicActor* actor, const Ogre::Vector3 &start, const Ogre::Vector3 &end, const PhysicEngine *enginePass) -{ - const btVector3 btstart(start.x, start.y, start.z+1.0f); - const btVector3 btend(end.x, end.y, end.z+1.0f); - - const btTransform &trans = actor->getCollisionBody()->getWorldTransform(); - btTransform from(trans.getBasis(), btstart); - btTransform to(trans.getBasis(), btend); - - ClosestNotMeConvexResultCallback newTraceCallback(actor->getCollisionBody(), btstart-btend, btScalar(0.0)); - // Inherit the actor's collision group and mask - newTraceCallback.m_collisionFilterGroup = actor->getCollisionBody()->getBroadphaseHandle()->m_collisionFilterGroup; - newTraceCallback.m_collisionFilterMask = actor->getCollisionBody()->getBroadphaseHandle()->m_collisionFilterMask; - newTraceCallback.m_collisionFilterMask &= ~CollisionType_Actor; - - btVector3 halfExtents(actor->getHalfExtents().x, actor->getHalfExtents().y, actor->getHalfExtents().z); - - halfExtents[2] = 1.0f; - btCylinderShapeZ base(halfExtents); - - enginePass->mDynamicsWorld->convexSweepTest(&base, from, to, newTraceCallback); - if(newTraceCallback.hasHit()) - { - const btVector3& tracehitnormal = newTraceCallback.m_hitNormalWorld; - mFraction = newTraceCallback.m_closestHitFraction; - mPlaneNormal = Ogre::Vector3(tracehitnormal.x(), tracehitnormal.y(), tracehitnormal.z()); - mEndPos = (end-start)*mFraction + start; - mEndPos[2] += 1.0f; - } - else - { - mEndPos = end; - mPlaneNormal = Ogre::Vector3(0.0f, 0.0f, 1.0f); - mFraction = 1.0f; - } -} - -} -} diff --git a/libs/openengine/bullet/trace.h b/libs/openengine/bullet/trace.h deleted file mode 100644 index f499f4a27..000000000 --- a/libs/openengine/bullet/trace.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef OENGINE_BULLET_TRACE_H -#define OENGINE_BULLET_TRACE_H - -#include - - -class btCollisionObject; - - -namespace OEngine -{ -namespace Physic -{ - class PhysicEngine; - class PhysicActor; - - struct ActorTracer - { - Ogre::Vector3 mEndPos; - Ogre::Vector3 mPlaneNormal; - const btCollisionObject* mHitObject; - - float mFraction; - - void doTrace(btCollisionObject *actor, const Ogre::Vector3 &start, const Ogre::Vector3 &end, - const PhysicEngine *enginePass); - void findGround(const OEngine::Physic::PhysicActor* actor, const Ogre::Vector3 &start, const Ogre::Vector3 &end, - const PhysicEngine *enginePass); - }; -} -} - -#endif From fe15f31f3e415c2a427bc43bce8bedf4558e6f97 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 10 May 2015 00:36:04 +0200 Subject: [PATCH 1133/3725] Remove strings.h wrapper --- CMakeLists.txt | 2 +- apps/bsatool/bsatool.cpp | 1 + components/bsa/bsa_file.hpp | 5 ++--- components/vfs/registerarchives.cpp | 3 +++ libs/platform/strings.h | 18 ------------------ 5 files changed, 7 insertions(+), 22 deletions(-) delete mode 100644 libs/platform/strings.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 2fa9cb821..fae7ff683 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -194,7 +194,7 @@ find_package(SDL2 REQUIRED) find_package(OpenAL REQUIRED) find_package(Bullet REQUIRED) -include_directories("." ${LIBS_DIR} +include_directories("." SYSTEM ${OGRE_INCLUDE_DIR} ${OGRE_INCLUDE_DIR}/Ogre ${OGRE_INCLUDE_DIR}/OGRE ${OGRE_INCLUDE_DIRS} ${SDL2_INCLUDE_DIR} diff --git a/apps/bsatool/bsatool.cpp b/apps/bsatool/bsatool.cpp index 2ea736db7..7f305052b 100644 --- a/apps/bsatool/bsatool.cpp +++ b/apps/bsatool/bsatool.cpp @@ -1,4 +1,5 @@ #include +#include #include #include diff --git a/components/bsa/bsa_file.hpp b/components/bsa/bsa_file.hpp index 8a7576f92..8ed63f35d 100644 --- a/components/bsa/bsa_file.hpp +++ b/components/bsa/bsa_file.hpp @@ -25,12 +25,11 @@ #define BSA_BSA_FILE_H #include -#include #include #include #include -#include +#include #include @@ -74,7 +73,7 @@ private: struct iltstr { bool operator()(const char *s1, const char *s2) const - { return strcasecmp(s1,s2) < 0; } + { return Misc::StringUtils::ciLess(s1, s2); } }; /** A map used for fast file name lookup. The value is the index into diff --git a/components/vfs/registerarchives.cpp b/components/vfs/registerarchives.cpp index 69d4498bb..aeda3191d 100644 --- a/components/vfs/registerarchives.cpp +++ b/components/vfs/registerarchives.cpp @@ -1,5 +1,8 @@ #include "registerarchives.hpp" +#include +#include + #include #include #include diff --git a/libs/platform/strings.h b/libs/platform/strings.h deleted file mode 100644 index c0fbb1a1b..000000000 --- a/libs/platform/strings.h +++ /dev/null @@ -1,18 +0,0 @@ -// Wrapper for MSVC/GCC -#ifndef _STRINGS_WRAPPER_H -#define _STRINGS_WRAPPER_H - - -// For GCC, just use strings.h (this applies to mingw too) -#if defined(__GNUC__) -# include -#elif defined(MSVC) || defined(_MSC_VER) -# pragma warning(disable: 4996) -# define strcasecmp stricmp -# define snprintf _snprintf -#else -# warning "Unable to determine your compiler, you should probably take a look here." -# include // Just take a guess -#endif - -#endif /* _STRINGS_WRAPPER_H */ From c31b416ba127044f7de60ec81b4064d42398ea20 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 10 May 2015 01:09:00 +0200 Subject: [PATCH 1134/3725] Move physicssystem to a new mwphysics module --- apps/opencs/CMakeLists.txt | 1 - apps/opencs/view/render/object.hpp | 5 ---- apps/openmw/CMakeLists.txt | 5 +++- apps/openmw/mwclass/activator.cpp | 5 ++-- apps/openmw/mwclass/activator.hpp | 2 +- apps/openmw/mwclass/apparatus.cpp | 4 +-- apps/openmw/mwclass/apparatus.hpp | 2 +- apps/openmw/mwclass/armor.cpp | 4 +-- apps/openmw/mwclass/armor.hpp | 2 +- apps/openmw/mwclass/book.cpp | 4 +-- apps/openmw/mwclass/book.hpp | 2 +- apps/openmw/mwclass/clothing.cpp | 4 +-- apps/openmw/mwclass/clothing.hpp | 2 +- apps/openmw/mwclass/container.cpp | 4 +-- apps/openmw/mwclass/container.hpp | 2 +- apps/openmw/mwclass/creature.cpp | 4 +-- apps/openmw/mwclass/creature.hpp | 2 +- apps/openmw/mwclass/door.cpp | 4 +-- apps/openmw/mwclass/door.hpp | 2 +- apps/openmw/mwclass/ingredient.cpp | 4 +-- apps/openmw/mwclass/ingredient.hpp | 2 +- apps/openmw/mwclass/light.cpp | 4 +-- apps/openmw/mwclass/light.hpp | 2 +- apps/openmw/mwclass/lockpick.cpp | 4 +-- apps/openmw/mwclass/lockpick.hpp | 2 +- apps/openmw/mwclass/misc.cpp | 4 +-- apps/openmw/mwclass/misc.hpp | 2 +- apps/openmw/mwclass/npc.cpp | 4 +-- apps/openmw/mwclass/npc.hpp | 2 +- apps/openmw/mwclass/potion.cpp | 4 +-- apps/openmw/mwclass/potion.hpp | 2 +- apps/openmw/mwclass/probe.cpp | 4 +-- apps/openmw/mwclass/probe.hpp | 2 +- apps/openmw/mwclass/repair.cpp | 4 +-- apps/openmw/mwclass/repair.hpp | 2 +- apps/openmw/mwclass/static.cpp | 4 +-- apps/openmw/mwclass/static.hpp | 2 +- apps/openmw/mwclass/weapon.cpp | 4 +-- apps/openmw/mwclass/weapon.hpp | 2 +- apps/openmw/mwinput/inputmanagerimp.hpp | 8 ------ .../{mwworld => mwphysics}/physicssystem.cpp | 28 +++++++++---------- .../{mwworld => mwphysics}/physicssystem.hpp | 18 +++--------- apps/openmw/mwworld/class.cpp | 2 +- apps/openmw/mwworld/class.hpp | 8 ++++-- apps/openmw/mwworld/scene.cpp | 17 +++++------ apps/openmw/mwworld/scene.hpp | 10 +++++-- apps/openmw/mwworld/worldimp.cpp | 4 +-- apps/openmw/mwworld/worldimp.hpp | 12 +------- components/CMakeLists.txt | 1 - 49 files changed, 102 insertions(+), 126 deletions(-) rename apps/openmw/{mwworld => mwphysics}/physicssystem.cpp (97%) rename apps/openmw/{mwworld => mwphysics}/physicssystem.hpp (93%) diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index d7aafcf30..5a74fa48f 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -199,7 +199,6 @@ if(APPLE) endif(APPLE) target_link_libraries(openmw-cs - ${OENGINE_LIBRARY} ${OGRE_LIBRARIES} ${OPENSCENEGRAPH_LIBRARIES} ${Boost_LIBRARIES} diff --git a/apps/opencs/view/render/object.hpp b/apps/opencs/view/render/object.hpp index d18a199ff..9f411ffc6 100644 --- a/apps/opencs/view/render/object.hpp +++ b/apps/opencs/view/render/object.hpp @@ -27,11 +27,6 @@ namespace CSMWorld struct CellRef; } -namespace CSVWorld -{ - class PhysicsSystem; -} - namespace CSVRender { class Object diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index e1de2a556..bcfc24053 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -73,6 +73,10 @@ add_openmw_dir (mwworld # projectilemanager ) +add_openmw_dir (mwphysics + physicssystem + ) + add_openmw_dir (mwclass classes activator creature npc weapon armor potion apparatus book clothing container door ingredient creaturelevlist itemlevlist light lockpick misc probe repair static @@ -127,7 +131,6 @@ endif () include_directories(${SOUND_INPUT_INCLUDES}) target_link_libraries(openmw - ${OENGINE_LIBRARY} ${OGRE_LIBRARIES} ${OPENSCENEGRAPH_LIBRARIES} ${Boost_LIBRARIES} diff --git a/apps/openmw/mwclass/activator.cpp b/apps/openmw/mwclass/activator.cpp index 2621f5e52..4cf33ceb8 100644 --- a/apps/openmw/mwclass/activator.cpp +++ b/apps/openmw/mwclass/activator.cpp @@ -11,11 +11,12 @@ #include "../mwworld/cellstore.hpp" #include "../mwworld/esmstore.hpp" #include "../mwworld/ptr.hpp" -#include "../mwworld/physicssystem.hpp" #include "../mwworld/action.hpp" #include "../mwworld/failedaction.hpp" #include "../mwworld/nullaction.hpp" +#include "../mwphysics/physicssystem.hpp" + #include "../mwrender/objects.hpp" #include "../mwrender/renderinginterface.hpp" @@ -38,7 +39,7 @@ namespace MWClass } } - void Activator::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const + void Activator::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const { if(!model.empty()) physics.addObject(ptr, model); diff --git a/apps/openmw/mwclass/activator.hpp b/apps/openmw/mwclass/activator.hpp index e79318a55..646bb79bb 100644 --- a/apps/openmw/mwclass/activator.hpp +++ b/apps/openmw/mwclass/activator.hpp @@ -19,7 +19,7 @@ namespace MWClass virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const; + virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); diff --git a/apps/openmw/mwclass/apparatus.cpp b/apps/openmw/mwclass/apparatus.cpp index 2abd071bd..55209764a 100644 --- a/apps/openmw/mwclass/apparatus.cpp +++ b/apps/openmw/mwclass/apparatus.cpp @@ -11,7 +11,7 @@ #include "../mwworld/actiontake.hpp" #include "../mwworld/actionalchemy.hpp" #include "../mwworld/cellstore.hpp" -#include "../mwworld/physicssystem.hpp" +#include "../mwphysics/physicssystem.hpp" #include "../mwworld/nullaction.hpp" #include "../mwrender/objects.hpp" @@ -33,7 +33,7 @@ namespace MWClass } } - void Apparatus::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const + void Apparatus::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const { if(!model.empty()) physics.addObject(ptr, model, true); diff --git a/apps/openmw/mwclass/apparatus.hpp b/apps/openmw/mwclass/apparatus.hpp index 2ab0a47e3..94e998e48 100644 --- a/apps/openmw/mwclass/apparatus.hpp +++ b/apps/openmw/mwclass/apparatus.hpp @@ -21,7 +21,7 @@ namespace MWClass virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const; + virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index 686f5af61..ec3658b3d 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -15,7 +15,7 @@ #include "../mwworld/inventorystore.hpp" #include "../mwworld/cellstore.hpp" #include "../mwworld/esmstore.hpp" -#include "../mwworld/physicssystem.hpp" +#include "../mwphysics/physicssystem.hpp" #include "../mwworld/nullaction.hpp" #include "../mwworld/containerstore.hpp" @@ -38,7 +38,7 @@ namespace MWClass } } - void Armor::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const + void Armor::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const { if(!model.empty()) physics.addObject(ptr, model, true); diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index 21d711a0d..ec3290878 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -20,7 +20,7 @@ namespace MWClass virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const; + virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index a9c96e7c7..e71dd6769 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -12,7 +12,7 @@ #include "../mwworld/failedaction.hpp" #include "../mwworld/cellstore.hpp" #include "../mwworld/esmstore.hpp" -#include "../mwworld/physicssystem.hpp" +#include "../mwphysics/physicssystem.hpp" #include "../mwrender/objects.hpp" #include "../mwrender/renderinginterface.hpp" @@ -35,7 +35,7 @@ namespace MWClass } } - void Book::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const + void Book::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const { if(!model.empty()) physics.addObject(ptr, model, true); diff --git a/apps/openmw/mwclass/book.hpp b/apps/openmw/mwclass/book.hpp index 05ff88bb2..8dcae731a 100644 --- a/apps/openmw/mwclass/book.hpp +++ b/apps/openmw/mwclass/book.hpp @@ -18,7 +18,7 @@ namespace MWClass virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const; + virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index b387a3e9f..39025227c 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -13,7 +13,7 @@ #include "../mwworld/inventorystore.hpp" #include "../mwworld/cellstore.hpp" #include "../mwworld/esmstore.hpp" -#include "../mwworld/physicssystem.hpp" +#include "../mwphysics/physicssystem.hpp" #include "../mwworld/nullaction.hpp" #include "../mwgui/tooltips.hpp" @@ -35,7 +35,7 @@ namespace MWClass } } - void Clothing::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const + void Clothing::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const { if(!model.empty()) physics.addObject(ptr, model, true); diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index 570054348..adb349158 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -18,7 +18,7 @@ namespace MWClass virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const; + virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index ac23744e8..862ae6c5d 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -18,7 +18,7 @@ #include "../mwworld/esmstore.hpp" #include "../mwworld/actionopen.hpp" #include "../mwworld/actiontrap.hpp" -#include "../mwworld/physicssystem.hpp" +#include "../mwphysics/physicssystem.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwgui/tooltips.hpp" @@ -97,7 +97,7 @@ namespace MWClass } } - void Container::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const + void Container::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const { if(!model.empty()) physics.addObject(ptr, model); diff --git a/apps/openmw/mwclass/container.hpp b/apps/openmw/mwclass/container.hpp index 52873374e..3268d45d1 100644 --- a/apps/openmw/mwclass/container.hpp +++ b/apps/openmw/mwclass/container.hpp @@ -21,7 +21,7 @@ namespace MWClass virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const; + virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index a85c648f4..7d4fcf5d6 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -25,7 +25,7 @@ #include "../mwworld/failedaction.hpp" #include "../mwworld/customdata.hpp" #include "../mwworld/containerstore.hpp" -#include "../mwworld/physicssystem.hpp" +#include "../mwphysics/physicssystem.hpp" #include "../mwworld/cellstore.hpp" #include "../mwrender/renderinginterface.hpp" @@ -169,7 +169,7 @@ namespace MWClass objects.insertCreature(ptr, model, (ref->mBase->mFlags & ESM::Creature::Weapon) != 0); } - void Creature::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const + void Creature::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const { if(!model.empty()) { diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index 5585835fd..7a50968bf 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -47,7 +47,7 @@ namespace MWClass virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const; + virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; virtual void adjustPosition(const MWWorld::Ptr& ptr, bool force) const; ///< Adjust position to stand on ground. Must be called post model load diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index f46ede730..36f7b021c 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -17,7 +17,7 @@ #include "../mwworld/actiondoor.hpp" #include "../mwworld/cellstore.hpp" #include "../mwworld/esmstore.hpp" -#include "../mwworld/physicssystem.hpp" +#include "../mwphysics/physicssystem.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwworld/actiontrap.hpp" #include "../mwworld/customdata.hpp" @@ -56,7 +56,7 @@ namespace MWClass } } - void Door::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const + void Door::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const { if(!model.empty()) physics.addObject(ptr, model); diff --git a/apps/openmw/mwclass/door.hpp b/apps/openmw/mwclass/door.hpp index c5f258d3e..9cfb46509 100644 --- a/apps/openmw/mwclass/door.hpp +++ b/apps/openmw/mwclass/door.hpp @@ -22,7 +22,7 @@ namespace MWClass virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const; + virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); diff --git a/apps/openmw/mwclass/ingredient.cpp b/apps/openmw/mwclass/ingredient.cpp index de43e818e..9b35b8530 100644 --- a/apps/openmw/mwclass/ingredient.cpp +++ b/apps/openmw/mwclass/ingredient.cpp @@ -11,7 +11,7 @@ #include "../mwworld/actiontake.hpp" #include "../mwworld/cellstore.hpp" #include "../mwworld/esmstore.hpp" -#include "../mwworld/physicssystem.hpp" +#include "../mwphysics/physicssystem.hpp" #include "../mwworld/actioneat.hpp" #include "../mwworld/nullaction.hpp" @@ -39,7 +39,7 @@ namespace MWClass } } - void Ingredient::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const + void Ingredient::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const { if(!model.empty()) physics.addObject(ptr, model, true); diff --git a/apps/openmw/mwclass/ingredient.hpp b/apps/openmw/mwclass/ingredient.hpp index a4681f462..69dd70743 100644 --- a/apps/openmw/mwclass/ingredient.hpp +++ b/apps/openmw/mwclass/ingredient.hpp @@ -18,7 +18,7 @@ namespace MWClass virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const; + virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 2cf31d996..7ea5ae1be 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -17,7 +17,7 @@ #include "../mwworld/failedaction.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwworld/cellstore.hpp" -#include "../mwworld/physicssystem.hpp" +#include "../mwphysics/physicssystem.hpp" #include "../mwworld/customdata.hpp" #include "../mwgui/tooltips.hpp" @@ -41,7 +41,7 @@ namespace MWClass renderingInterface.getObjects().insertModel(ptr, model, true, !(ref->mBase->mData.mFlags & ESM::Light::OffDefault)); } - void Light::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const + void Light::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const { MWWorld::LiveCellRef *ref = ptr.get(); diff --git a/apps/openmw/mwclass/light.hpp b/apps/openmw/mwclass/light.hpp index 8658375b7..6161f1899 100644 --- a/apps/openmw/mwclass/light.hpp +++ b/apps/openmw/mwclass/light.hpp @@ -18,7 +18,7 @@ namespace MWClass virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const; + virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index 478c50301..e1e774755 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -12,7 +12,7 @@ #include "../mwworld/actionequip.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwworld/cellstore.hpp" -#include "../mwworld/physicssystem.hpp" +#include "../mwphysics/physicssystem.hpp" #include "../mwworld/nullaction.hpp" #include "../mwgui/tooltips.hpp" @@ -34,7 +34,7 @@ namespace MWClass } } - void Lockpick::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const + void Lockpick::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const { if(!model.empty()) physics.addObject(ptr, model, true); diff --git a/apps/openmw/mwclass/lockpick.hpp b/apps/openmw/mwclass/lockpick.hpp index 293a40be1..3f2c004f8 100644 --- a/apps/openmw/mwclass/lockpick.hpp +++ b/apps/openmw/mwclass/lockpick.hpp @@ -18,7 +18,7 @@ namespace MWClass virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const; + virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index f5daafeec..df28daee9 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -13,7 +13,7 @@ #include "../mwworld/actiontake.hpp" #include "../mwworld/cellstore.hpp" #include "../mwworld/esmstore.hpp" -#include "../mwworld/physicssystem.hpp" +#include "../mwphysics/physicssystem.hpp" #include "../mwworld/manualref.hpp" #include "../mwworld/nullaction.hpp" #include "../mwworld/actionsoulgem.hpp" @@ -51,7 +51,7 @@ namespace MWClass } } - void Miscellaneous::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const + void Miscellaneous::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const { if(!model.empty()) physics.addObject(ptr, model, true); diff --git a/apps/openmw/mwclass/misc.hpp b/apps/openmw/mwclass/misc.hpp index 23160d41c..66699f9df 100644 --- a/apps/openmw/mwclass/misc.hpp +++ b/apps/openmw/mwclass/misc.hpp @@ -18,7 +18,7 @@ namespace MWClass virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const; + virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 8be551dd2..6f969146b 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -32,7 +32,7 @@ #include "../mwworld/failedaction.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwworld/customdata.hpp" -#include "../mwworld/physicssystem.hpp" +#include "../mwphysics/physicssystem.hpp" #include "../mwworld/cellstore.hpp" #include "../mwrender/objects.hpp" @@ -412,7 +412,7 @@ namespace MWClass renderingInterface.getObjects().insertNPC(ptr); } - void Npc::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const + void Npc::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const { physics.addActor(ptr, model); MWBase::Environment::get().getMechanicsManager()->add(ptr); diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index b74546395..e0ebbec2b 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -51,7 +51,7 @@ namespace MWClass virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const; + virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; virtual void adjustPosition(const MWWorld::Ptr& ptr, bool force) const; ///< Adjust position to stand on ground. Must be called post model load diff --git a/apps/openmw/mwclass/potion.cpp b/apps/openmw/mwclass/potion.cpp index ee299ab4f..98bb703cb 100644 --- a/apps/openmw/mwclass/potion.cpp +++ b/apps/openmw/mwclass/potion.cpp @@ -13,7 +13,7 @@ #include "../mwworld/cellstore.hpp" #include "../mwworld/esmstore.hpp" #include "../mwworld/containerstore.hpp" -#include "../mwworld/physicssystem.hpp" +#include "../mwphysics/physicssystem.hpp" #include "../mwworld/nullaction.hpp" #include "../mwgui/tooltips.hpp" @@ -37,7 +37,7 @@ namespace MWClass } } - void Potion::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const + void Potion::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const { if(!model.empty()) physics.addObject(ptr, model, true); diff --git a/apps/openmw/mwclass/potion.hpp b/apps/openmw/mwclass/potion.hpp index 32e390115..091d29195 100644 --- a/apps/openmw/mwclass/potion.hpp +++ b/apps/openmw/mwclass/potion.hpp @@ -18,7 +18,7 @@ namespace MWClass virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const; + virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index da22e9be6..fb96bff5a 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -12,7 +12,7 @@ #include "../mwworld/actionequip.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwworld/cellstore.hpp" -#include "../mwworld/physicssystem.hpp" +#include "../mwphysics/physicssystem.hpp" #include "../mwworld/nullaction.hpp" #include "../mwgui/tooltips.hpp" @@ -34,7 +34,7 @@ namespace MWClass } } - void Probe::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const + void Probe::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const { if(!model.empty()) physics.addObject(ptr, model, true); diff --git a/apps/openmw/mwclass/probe.hpp b/apps/openmw/mwclass/probe.hpp index bb90ac153..e39e43c27 100644 --- a/apps/openmw/mwclass/probe.hpp +++ b/apps/openmw/mwclass/probe.hpp @@ -18,7 +18,7 @@ namespace MWClass virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const; + virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); diff --git a/apps/openmw/mwclass/repair.cpp b/apps/openmw/mwclass/repair.cpp index c02146f12..9ddc36ff9 100644 --- a/apps/openmw/mwclass/repair.cpp +++ b/apps/openmw/mwclass/repair.cpp @@ -10,7 +10,7 @@ #include "../mwworld/ptr.hpp" #include "../mwworld/actiontake.hpp" #include "../mwworld/cellstore.hpp" -#include "../mwworld/physicssystem.hpp" +#include "../mwphysics/physicssystem.hpp" #include "../mwworld/nullaction.hpp" #include "../mwworld/actionrepair.hpp" @@ -33,7 +33,7 @@ namespace MWClass } } - void Repair::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const + void Repair::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const { if(!model.empty()) physics.addObject(ptr, model, true); diff --git a/apps/openmw/mwclass/repair.hpp b/apps/openmw/mwclass/repair.hpp index 2589a4af3..295b9d4f1 100644 --- a/apps/openmw/mwclass/repair.hpp +++ b/apps/openmw/mwclass/repair.hpp @@ -18,7 +18,7 @@ namespace MWClass virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const; + virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); diff --git a/apps/openmw/mwclass/static.cpp b/apps/openmw/mwclass/static.cpp index 834ce129e..6438046de 100644 --- a/apps/openmw/mwclass/static.cpp +++ b/apps/openmw/mwclass/static.cpp @@ -4,7 +4,7 @@ #include #include "../mwworld/ptr.hpp" -#include "../mwworld/physicssystem.hpp" +#include "../mwphysics/physicssystem.hpp" #include "../mwworld/cellstore.hpp" #include "../mwrender/objects.hpp" @@ -24,7 +24,7 @@ namespace MWClass } } - void Static::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const + void Static::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const { if(!model.empty()) physics.addObject(ptr, model); diff --git a/apps/openmw/mwclass/static.hpp b/apps/openmw/mwclass/static.hpp index a94dff394..3d78f949b 100644 --- a/apps/openmw/mwclass/static.hpp +++ b/apps/openmw/mwclass/static.hpp @@ -18,7 +18,7 @@ namespace MWClass virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const; + virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index a484ad668..bbe81f370 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -13,7 +13,7 @@ #include "../mwworld/inventorystore.hpp" #include "../mwworld/cellstore.hpp" #include "../mwworld/esmstore.hpp" -#include "../mwworld/physicssystem.hpp" +#include "../mwphysics/physicssystem.hpp" #include "../mwworld/nullaction.hpp" #include "../mwgui/tooltips.hpp" @@ -37,7 +37,7 @@ namespace MWClass } } - void Weapon::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const + void Weapon::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const { if(!model.empty()) physics.addObject(ptr, model, true); diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index 47f1c5251..47c1157a0 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -18,7 +18,7 @@ namespace MWClass virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const; + virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 26a1fcb21..cd80ed460 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -9,14 +9,6 @@ #include "../mwbase/inputmanager.hpp" #include -namespace OEngine -{ - namespace Render - { - class OgreRenderer; - } -} - namespace MWWorld { class Player; diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp similarity index 97% rename from apps/openmw/mwworld/physicssystem.cpp rename to apps/openmw/mwphysics/physicssystem.cpp index 7c1a44e48..f57a8fbff 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -24,8 +24,7 @@ #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" -#include "ptr.hpp" -#include "class.hpp" +#include "../mwworld/class.hpp" namespace { @@ -78,7 +77,7 @@ void animateCollisionShapes (std::map& collisionTracker , std::map& standingCollisionTracker) { @@ -584,7 +582,7 @@ namespace MWWorld */ } - std::vector PhysicsSystem::getCollisions(const Ptr &ptr, int collisionGroup, int collisionMask) + std::vector PhysicsSystem::getCollisions(const MWWorld::Ptr &ptr, int collisionGroup, int collisionMask) { return std::vector();//mEngine->getCollisions(ptr.getRefData().getBaseNodeOld()->getName(), collisionGroup, collisionMask); } @@ -604,12 +602,12 @@ namespace MWWorld { } - void PhysicsSystem::addObject (const Ptr& ptr, const std::string& mesh, bool placeable) + void PhysicsSystem::addObject (const MWWorld::Ptr& ptr, const std::string& mesh, bool placeable) { } - void PhysicsSystem::addActor (const Ptr& ptr, const std::string& mesh) + void PhysicsSystem::addActor (const MWWorld::Ptr& ptr, const std::string& mesh) { } @@ -642,7 +640,7 @@ namespace MWWorld return false; } - void PhysicsSystem::queueObjectMovement(const Ptr &ptr, const Ogre::Vector3 &movement) + void PhysicsSystem::queueObjectMovement(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement) { PtrVelocityList::iterator iter = mMovementQueue.begin(); for(;iter != mMovementQueue.end();++iter) @@ -736,7 +734,7 @@ namespace MWWorld mDebugDrawer->step(); } - bool PhysicsSystem::isActorStandingOn(const Ptr &actor, const Ptr &object) const + bool PhysicsSystem::isActorStandingOn(const MWWorld::Ptr &actor, const MWWorld::Ptr &object) const { const std::string& actorHandle = actor.getRefData().getHandle(); const std::string& objectHandle = object.getRefData().getHandle(); @@ -750,7 +748,7 @@ namespace MWWorld return false; } - void PhysicsSystem::getActorsStandingOn(const Ptr &object, std::vector &out) const + void PhysicsSystem::getActorsStandingOn(const MWWorld::Ptr &object, std::vector &out) const { const std::string& objectHandle = object.getRefData().getHandle(); @@ -762,7 +760,7 @@ namespace MWWorld } } - bool PhysicsSystem::isActorCollidingWith(const Ptr &actor, const Ptr &object) const + bool PhysicsSystem::isActorCollidingWith(const MWWorld::Ptr &actor, const MWWorld::Ptr &object) const { const std::string& actorHandle = actor.getRefData().getHandle(); const std::string& objectHandle = object.getRefData().getHandle(); @@ -776,7 +774,7 @@ namespace MWWorld return false; } - void PhysicsSystem::getActorsCollidingWith(const Ptr &object, std::vector &out) const + void PhysicsSystem::getActorsCollidingWith(const MWWorld::Ptr &object, std::vector &out) const { const std::string& objectHandle = object.getRefData().getHandle(); diff --git a/apps/openmw/mwworld/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp similarity index 93% rename from apps/openmw/mwworld/physicssystem.hpp rename to apps/openmw/mwphysics/physicssystem.hpp index 018ea0a28..e04ac1b51 100644 --- a/apps/openmw/mwworld/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -9,31 +9,21 @@ #include -#include "ptr.hpp" +#include "../mwworld/ptr.hpp" namespace osg { class Group; } -namespace OEngine -{ - namespace Physic - { - class PhysicEngine; - } -} - namespace MWRender { class DebugDrawer; } -namespace MWWorld +namespace MWPhysics { - class World; - - typedef std::vector > PtrVelocityList; + typedef std::vector > PtrVelocityList; class PhysicsSystem { @@ -75,7 +65,7 @@ namespace MWWorld /// Queues velocity movement for a Ptr. If a Ptr is already queued, its velocity will /// be overwritten. Valid until the next call to applyQueuedMovement. - void queueObjectMovement(const Ptr &ptr, const Ogre::Vector3 &velocity); + void queueObjectMovement(const MWWorld::Ptr &ptr, const Ogre::Vector3 &velocity); /// Apply all queued movements, then clear the list. const PtrVelocityList& applyQueuedMovement(float dt); diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 79444e110..0ab18699d 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -43,7 +43,7 @@ namespace MWWorld } - void Class::insertObject(const Ptr& ptr, const std::string& mesh, MWWorld::PhysicsSystem& physics) const + void Class::insertObject(const Ptr& ptr, const std::string& mesh, MWPhysics::PhysicsSystem& physics) const { } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 3f65af05c..15058294f 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -24,6 +24,11 @@ namespace MWRender class RenderingInterface; } +namespace MWPhysics +{ + class PhysicsSystem; +} + namespace MWMechanics { class CreatureStats; @@ -45,7 +50,6 @@ namespace MWWorld { class ContainerStore; class InventoryStore; - class PhysicsSystem; class CellStore; class Action; @@ -84,7 +88,7 @@ namespace MWWorld /// Leaving it here for now in case we want to optimize later. virtual void insertObjectRendering (const Ptr& ptr, const std::string& mesh, MWRender::RenderingInterface& renderingInterface) const; - virtual void insertObject(const Ptr& ptr, const std::string& mesh, MWWorld::PhysicsSystem& physics) const; + virtual void insertObject(const Ptr& ptr, const std::string& mesh, MWPhysics::PhysicsSystem& physics) const; ///< Add reference into a cell for rendering (default implementation: don't render anything). virtual std::string getName (const Ptr& ptr) const = 0; diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 1ccbc6b55..0e17dad74 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -18,7 +18,8 @@ #include "../mwrender/renderingmanager.hpp" -#include "physicssystem.hpp" +#include "../mwphysics/physicssystem.hpp" + #include "player.hpp" #include "localscripts.hpp" #include "esmstore.hpp" @@ -29,7 +30,7 @@ namespace { - void addObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics, + void addObject(const MWWorld::Ptr& ptr, MWPhysics::PhysicsSystem& physics, MWRender::RenderingManager& rendering) { std::string model = Misc::ResourceHelpers::correctActorModelPath(ptr.getClass().getModel(ptr), rendering.getResourceSystem()->getVFS()); @@ -40,7 +41,7 @@ namespace ptr.getClass().insertObject (ptr, model, physics); } - void updateObjectLocalRotation (const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics, + void updateObjectLocalRotation (const MWWorld::Ptr& ptr, MWPhysics::PhysicsSystem& physics, MWRender::RenderingManager& rendering) { if (ptr.getRefData().getBaseNode() != NULL) @@ -63,7 +64,7 @@ namespace } } - void updateObjectScale(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics, + void updateObjectScale(const MWWorld::Ptr& ptr, MWPhysics::PhysicsSystem& physics, MWRender::RenderingManager& rendering) { if (ptr.getRefData().getBaseNode() != NULL) @@ -80,17 +81,17 @@ namespace MWWorld::CellStore& mCell; bool mRescale; Loading::Listener& mLoadingListener; - MWWorld::PhysicsSystem& mPhysics; + MWPhysics::PhysicsSystem& mPhysics; MWRender::RenderingManager& mRendering; InsertFunctor (MWWorld::CellStore& cell, bool rescale, Loading::Listener& loadingListener, - MWWorld::PhysicsSystem& physics, MWRender::RenderingManager& rendering); + MWPhysics::PhysicsSystem& physics, MWRender::RenderingManager& rendering); bool operator() (const MWWorld::Ptr& ptr); }; InsertFunctor::InsertFunctor (MWWorld::CellStore& cell, bool rescale, - Loading::Listener& loadingListener, MWWorld::PhysicsSystem& physics, + Loading::Listener& loadingListener, MWPhysics::PhysicsSystem& physics, MWRender::RenderingManager& rendering) : mCell (cell), mRescale (rescale), mLoadingListener (loadingListener), mPhysics (physics), @@ -436,7 +437,7 @@ namespace MWWorld } //We need the ogre renderer and a scene node. - Scene::Scene (MWRender::RenderingManager& rendering, PhysicsSystem *physics) + Scene::Scene (MWRender::RenderingManager& rendering, MWPhysics::PhysicsSystem *physics) : mCurrentCell (0), mCellChanged (false), mPhysics(physics), mRendering(rendering), mNeedMapUpdate(false) { } diff --git a/apps/openmw/mwworld/scene.hpp b/apps/openmw/mwworld/scene.hpp index f7ef9b276..24ffdf07b 100644 --- a/apps/openmw/mwworld/scene.hpp +++ b/apps/openmw/mwworld/scene.hpp @@ -39,9 +39,13 @@ namespace MWRender class RenderingManager; } -namespace MWWorld +namespace MWPhysics { class PhysicsSystem; +} + +namespace MWWorld +{ class Player; class CellStore; @@ -56,7 +60,7 @@ namespace MWWorld CellStore* mCurrentCell; // the cell the player is in CellStoreCollection mActiveCells; bool mCellChanged; - PhysicsSystem *mPhysics; + MWPhysics::PhysicsSystem *mPhysics; MWRender::RenderingManager& mRendering; bool mNeedMapUpdate; @@ -70,7 +74,7 @@ namespace MWWorld public: - Scene (MWRender::RenderingManager& rendering, PhysicsSystem *physics); + Scene (MWRender::RenderingManager& rendering, MWPhysics::PhysicsSystem *physics); ~Scene(); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 7047978ff..72423f476 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -51,7 +51,7 @@ #include "actionteleport.hpp" //#include "projectilemanager.hpp" #include "weather.hpp" -#include "physicssystem.hpp" +#include "../mwphysics/physicssystem.hpp" #include "contentloader.hpp" #include "esmloader.hpp" @@ -156,7 +156,7 @@ namespace MWWorld mStartCell (startCell), mStartupScript(startupScript), mScriptsEnabled(true) { - mPhysics = new PhysicsSystem(rootNode); + mPhysics = new MWPhysics::PhysicsSystem(rootNode); //mPhysEngine = mPhysics->getEngine(); #if 0 mProjectileManager.reset(new ProjectileManager(renderer.getScene(), *mPhysEngine)); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index cb58f0496..efb9b88c6 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -21,14 +21,6 @@ #include -namespace OEngine -{ -namespace Physic -{ - class PhysicEngine; -} -} - namespace osg { class Group; @@ -89,15 +81,13 @@ namespace MWWorld MWWorld::ESMStore mStore; LocalScripts mLocalScripts; MWWorld::Globals mGlobalVariables; - MWWorld::PhysicsSystem *mPhysics; + MWPhysics::PhysicsSystem *mPhysics; bool mSky; Cells mCells; std::string mCurrentWorldSpace; - OEngine::Physic::PhysicEngine* mPhysEngine; - boost::shared_ptr mProjectileManager; bool mGodMode; diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 931d84e26..417164f2d 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -170,7 +170,6 @@ add_library(components STATIC ${COMPONENT_FILES} ${MOC_SRCS} ${ESM_UI_HDR}) target_link_libraries(components ${Boost_LIBRARIES} ${OGRE_LIBRARIES} - ${OENGINE_LIBRARY} ${OPENSCENEGRAPH_LIBRARIES} # For MyGUI platform ${OPENGL_gl_LIBRARY} From 54c1f19c183350c2b55965ff0f197db52c7559ae Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 10 May 2015 02:08:25 +0200 Subject: [PATCH 1135/3725] Readded height fields --- apps/openmw/mwphysics/physicssystem.cpp | 132 ++++++++++++++++++++---- apps/openmw/mwphysics/physicssystem.hpp | 26 ++++- apps/openmw/mwworld/scene.cpp | 10 +- 3 files changed, 137 insertions(+), 31 deletions(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index f57a8fbff..8ae4fc853 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -4,6 +4,8 @@ #include +#include + #include #include @@ -187,7 +189,7 @@ namespace MWPhysics if(stepper.mFraction < 1.0f && getSlope(stepper.mPlaneNormal) <= sMaxSlope) { // don't allow stepping up other actors - if (stepper.mHitObject->getBroadphaseHandle()->m_collisionFilterGroup == OEngine::Physic::CollisionType_Actor) + if (stepper.mHitObject->getBroadphaseHandle()->m_collisionFilterGroup == CollisionType_Actor) return false; // only step down onto semi-horizontal surfaces. don't step down onto the side of a house or a wall. // TODO: stepper.mPlaneNormal does not appear to be reliable - needs more testing @@ -246,7 +248,7 @@ namespace MWPhysics btCollisionWorld::ClosestRayResultCallback resultCallback1(from, to); resultCallback1.m_collisionFilterGroup = 0xff; - resultCallback1.m_collisionFilterMask = OEngine::Physic::CollisionType_World|OEngine::Physic::CollisionType_HeightMap; + resultCallback1.m_collisionFilterMask = CollisionType_World|CollisionType_HeightMap; engine->mDynamicsWorld->rayTest(from, to, resultCallback1); if (resultCallback1.hasHit() && @@ -437,14 +439,14 @@ namespace MWPhysics Ogre::Vector3(0,0,sStepSizeDown+2.f) : Ogre::Vector3(0,0,2.f)); tracer.doTrace(colobj, from, to, engine); if(tracer.mFraction < 1.0f && getSlope(tracer.mPlaneNormal) <= sMaxSlope - && tracer.mHitObject->getBroadphaseHandle()->m_collisionFilterGroup != OEngine::Physic::CollisionType_Actor) + && tracer.mHitObject->getBroadphaseHandle()->m_collisionFilterGroup != CollisionType_Actor) { const btCollisionObject* standingOn = tracer.mHitObject; if (const OEngine::Physic::RigidBody* body = dynamic_cast(standingOn)) { standingCollisionTracker[ptr.getRefData().getHandle()] = body->mName; } - if (standingOn->getBroadphaseHandle()->m_collisionFilterGroup == OEngine::Physic::CollisionType_Water) + if (standingOn->getBroadphaseHandle()->m_collisionFilterGroup == CollisionType_Water) physicActor->setWalkingOnWater(true); if (!isFlying) @@ -457,7 +459,7 @@ namespace MWPhysics // standing on actors is not allowed (see above). // in addition to that, apply a sliding effect away from the center of the actor, // so that we do not stay suspended in air indefinitely. - if (tracer.mFraction < 1.0f && tracer.mHitObject->getBroadphaseHandle()->m_collisionFilterGroup == OEngine::Physic::CollisionType_Actor) + if (tracer.mFraction < 1.0f && tracer.mHitObject->getBroadphaseHandle()->m_collisionFilterGroup == CollisionType_Actor) { if (Ogre::Vector3(velocity.x, velocity.y, 0).squaredLength() < 100.f*100.f) { @@ -492,15 +494,94 @@ namespace MWPhysics }; - PhysicsSystem::PhysicsSystem(osg::ref_ptr parentNode) : - mTimeAccum(0.0f), mWaterEnabled(false), mWaterHeight(0), mDebugDrawEnabled(false), mParentNode(parentNode) + // --------------------------------------------------------------- + + class HeightField + { + public: + HeightField(float* heights, int x, int y, float triSize, float sqrtVerts) + { + // find the minimum and maximum heights (needed for bullet) + float minh = heights[0]; + float maxh = heights[0]; + for(int i = 1;i < sqrtVerts*sqrtVerts;++i) + { + float h = heights[i]; + if(h > maxh) maxh = h; + if(h < minh) minh = h; + } + + mShape = new btHeightfieldTerrainShape( + sqrtVerts, sqrtVerts, heights, 1, + minh, maxh, 2, + PHY_FLOAT, true + ); + mShape->setUseDiamondSubdivision(true); + mShape->setLocalScaling(btVector3(triSize, triSize, 1)); + + btTransform transform(btQuaternion::getIdentity(), + btVector3((x+0.5f) * triSize * (sqrtVerts-1), + (y+0.5f) * triSize * (sqrtVerts-1), + (maxh+minh)*0.5f)); + + mCollisionObject = new btCollisionObject; + mCollisionObject->setCollisionShape(mShape); + mCollisionObject->setWorldTransform(transform); + } + ~HeightField() + { + delete mCollisionObject; + delete mShape; + } + btCollisionObject* getCollisionObject() + { + return mCollisionObject; + } + + private: + btHeightfieldTerrainShape* mShape; + btCollisionObject* mCollisionObject; + }; + + // --------------------------------------------------------------- + + + PhysicsSystem::PhysicsSystem(osg::ref_ptr parentNode) + : mTimeAccum(0.0f) + , mWaterEnabled(false) + , mWaterHeight(0) + , mDebugDrawEnabled(false) + , mParentNode(parentNode) { + mCollisionConfiguration = new btDefaultCollisionConfiguration(); + mDispatcher = new btCollisionDispatcher(mCollisionConfiguration); + mSolver = new btSequentialImpulseConstraintSolver; + mBroadphase = new btDbvtBroadphase(); + mDynamicsWorld = new btDiscreteDynamicsWorld(mDispatcher,mBroadphase,mSolver,mCollisionConfiguration); + + // Don't update AABBs of all objects every frame. Most objects in MW are static, so we don't need this. + // Should a "static" object ever be moved, we have to update its AABB manually using DynamicsWorld::updateSingleAabb. + mDynamicsWorld->setForceUpdateAllAabbs(false); + + mDynamicsWorld->setGravity(btVector3(0,0,-10)); } PhysicsSystem::~PhysicsSystem() { - //if (mWaterCollisionObject.get()) - // mEngine->mDynamicsWorld->removeCollisionObject(mWaterCollisionObject.get()); + if (mWaterCollisionObject.get()) + mDynamicsWorld->removeCollisionObject(mWaterCollisionObject.get()); + + for (HeightFieldMap::iterator it = mHeightFields.begin(); it != mHeightFields.end(); ++it) + { + mDynamicsWorld->removeCollisionObject(it->second->getCollisionObject()); + delete it->second; + } + + delete mDynamicsWorld; + delete mSolver; + delete mCollisionConfiguration; + delete mDispatcher; + delete mBroadphase; } bool PhysicsSystem::toggleDebugRendering() @@ -509,9 +590,9 @@ namespace MWPhysics if (mDebugDrawEnabled && !mDebugDrawer.get()) { - //mDebugDrawer.reset(new MWRender::DebugDrawer(mParentNode, mEngine->mDynamicsWorld)); - //mEngine->mDynamicsWorld->setDebugDrawer(mDebugDrawer.get()); - //mDebugDrawer->setDebugMode(mDebugDrawEnabled); + mDebugDrawer.reset(new MWRender::DebugDrawer(mParentNode, mDynamicsWorld)); + mDynamicsWorld->setDebugDrawer(mDebugDrawer.get()); + mDebugDrawer->setDebugMode(mDebugDrawEnabled); } else if (mDebugDrawer.get()) mDebugDrawer->setDebugMode(mDebugDrawEnabled); @@ -592,14 +673,24 @@ namespace MWPhysics return Ogre::Vector3();//MovementSolver::traceDown(ptr, mEngine, maxHeight); } - void PhysicsSystem::addHeightField (float* heights, - int x, int y, float yoffset, - float triSize, float sqrtVerts) + void PhysicsSystem::addHeightField (float* heights, int x, int y, float triSize, float sqrtVerts) { + HeightField *heightfield = new HeightField(heights, x, y, triSize, sqrtVerts); + mHeightFields[std::make_pair(x,y)] = heightfield; + + mDynamicsWorld->addCollisionObject(heightfield->getCollisionObject(), CollisionType_HeightMap, + CollisionType_Actor|CollisionType_Projectile); } void PhysicsSystem::removeHeightField (int x, int y) { + HeightFieldMap::iterator heightfield = mHeightFields.find(std::make_pair(x,y)); + if(heightfield != mHeightFields.end()) + { + mDynamicsWorld->removeCollisionObject(heightfield->second->getCollisionObject()); + delete heightfield->second; + mHeightFields.erase(heightfield); + } } void PhysicsSystem::addObject (const MWWorld::Ptr& ptr, const std::string& mesh, bool placeable) @@ -726,9 +817,10 @@ namespace MWPhysics void PhysicsSystem::stepSimulation(float dt) { - //animateCollisionShapes(mEngine->mAnimatedShapes, mEngine->mDynamicsWorld); + //animateCollisionShapes(mEngine->mAnimatedShapes, mDynamicsWorld); - //mEngine->stepSimulation(dt); + // We have nothing to simulate, but character controllers aren't working without this call. Might be related to updating AABBs. + mDynamicsWorld->stepSimulation(static_cast(dt), 1, 1 / 60.0f); if (mDebugDrawer.get()) mDebugDrawer->step(); @@ -818,7 +910,7 @@ namespace MWPhysics { if (mWaterCollisionObject.get()) { - //mEngine->mDynamicsWorld->removeCollisionObject(mWaterCollisionObject.get()); + mDynamicsWorld->removeCollisionObject(mWaterCollisionObject.get()); } if (!mWaterEnabled) @@ -827,7 +919,7 @@ namespace MWPhysics mWaterCollisionObject.reset(new btCollisionObject()); mWaterCollisionShape.reset(new btStaticPlaneShape(btVector3(0,0,1), mWaterHeight)); mWaterCollisionObject->setCollisionShape(mWaterCollisionShape.get()); - //mEngine->mDynamicsWorld->addCollisionObject(mWaterCollisionObject.get(), OEngine::Physic::CollisionType_Water, - // OEngine::Physic::CollisionType_Actor); + mDynamicsWorld->addCollisionObject(mWaterCollisionObject.get(), CollisionType_Water, + CollisionType_Actor); } } diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index e04ac1b51..4dbecdb7c 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -21,10 +21,23 @@ namespace MWRender class DebugDrawer; } +class btSequentialImpulseConstraintSolver; +class btDiscreteDynamicsWorld; + namespace MWPhysics { typedef std::vector > PtrVelocityList; + enum CollisionType { + CollisionType_World = 1<<0, + CollisionType_Actor = 1<<1, + CollisionType_HeightMap = 1<<2, + CollisionType_Projectile = 1<<4, + CollisionType_Water = 1<<5 + }; + + class HeightField; + class PhysicsSystem { public: @@ -39,9 +52,7 @@ namespace MWPhysics void addActor (const MWWorld::Ptr& ptr, const std::string& mesh); - void addHeightField (float* heights, - int x, int y, float yoffset, - float triSize, float sqrtVerts); + void addHeightField (float* heights, int x, int y, float triSize, float sqrtVerts); void removeHeightField (int x, int y); @@ -94,6 +105,15 @@ namespace MWPhysics void updateWater(); + btBroadphaseInterface* mBroadphase; + btDefaultCollisionConfiguration* mCollisionConfiguration; + btSequentialImpulseConstraintSolver* mSolver; + btCollisionDispatcher* mDispatcher; + btDiscreteDynamicsWorld* mDynamicsWorld; + + typedef std::map, HeightField*> HeightFieldMap; + HeightFieldMap mHeightFields; + bool mDebugDrawEnabled; std::map handleToMesh; diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 0e17dad74..6a994f0cd 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -246,14 +246,8 @@ namespace MWWorld const int flags = ESM::Land::DATA_VCLR|ESM::Land::DATA_VHGT|ESM::Land::DATA_VNML|ESM::Land::DATA_VTEX; if (!land->isDataLoaded(flags)) land->loadData(flags); - mPhysics->addHeightField ( - land->mLandData->mHeights, - cell->getCell()->getGridX(), - cell->getCell()->getGridY(), - 0, - worldsize / (verts-1), - verts) - ; + mPhysics->addHeightField (land->mLandData->mHeights, cell->getCell()->getGridX(), cell->getCell()->getGridY(), + worldsize / (verts-1), verts); } } From ab21c0551c6f5c3ccb63f6f2670a5f39c2c4294a Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 10 May 2015 13:34:45 +1000 Subject: [PATCH 1136/3725] Provide a default encoding when changing to "Function". --- apps/opencs/model/world/nestedcoladapterimp.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/world/nestedcoladapterimp.cpp b/apps/opencs/model/world/nestedcoladapterimp.cpp index 8c62fb59b..4c720ba24 100644 --- a/apps/opencs/model/world/nestedcoladapterimp.cpp +++ b/apps/opencs/model/world/nestedcoladapterimp.cpp @@ -854,7 +854,14 @@ namespace CSMWorld { // FIXME: when these change the values of the other columns need to change // correspondingly (and automatically) - case 1: conditions[subRowIndex].mSelectRule[1] = '1'; break; // Function + case 1: + { + conditions[subRowIndex].mSelectRule[1] = '1'; // Function + // default to "Rank Low" + conditions[subRowIndex].mSelectRule[2] = '0'; + conditions[subRowIndex].mSelectRule[3] = '0'; + break; + } case 2: conditions[subRowIndex].mSelectRule[1] = '2'; break; // Global case 3: conditions[subRowIndex].mSelectRule[1] = '3'; break; // Local case 4: conditions[subRowIndex].mSelectRule[1] = '4'; break; // Journal @@ -874,7 +881,6 @@ namespace CSMWorld { if (conditions[subRowIndex].mSelectRule[1] == '1') { - // throws an exception if the function is not found const std::map::const_iterator it = sInfoFuncToEnc.find( value.toString().toUtf8().constData()); if (it != sInfoFuncToEnc.end()) From 8e35ad54bd280a7a540624b1ce6c6267c79ee007 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 10 May 2015 11:17:52 +0200 Subject: [PATCH 1137/3725] temporarily remove the test for bullet version --- libs/openengine/bullet/physic.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index 22312e3bc..c0da03651 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -475,9 +475,9 @@ namespace Physic btCollisionShape* collisionShape = raycasting ? shape->mRaycastingShape : shape->mCollisionShape; // TODO: check this from cmake? -#if BT_BULLET_VERSION < 283 -#error "Bullet version 2.83 or later required" -#endif +//#if BT_BULLET_VERSION < 283 +//#error "Bullet version 2.83 or later required" +//#endif bool needDelete = false; if (btBvhTriangleMeshShape* triangleShape = dynamic_cast(shape->mCollisionShape)) From 2b84598e852694650d2fbe8886e7fea31131c793 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 10 May 2015 20:52:29 +1000 Subject: [PATCH 1138/3725] Remove duplicated but reversed map. --- .../model/world/nestedcoladapterimp.cpp | 102 +++--------------- 1 file changed, 13 insertions(+), 89 deletions(-) diff --git a/apps/opencs/model/world/nestedcoladapterimp.cpp b/apps/opencs/model/world/nestedcoladapterimp.cpp index 4c720ba24..a0d764576 100644 --- a/apps/opencs/model/world/nestedcoladapterimp.cpp +++ b/apps/opencs/model/world/nestedcoladapterimp.cpp @@ -754,87 +754,6 @@ namespace CSMWorld } } - static std::map populateInfoFuncToEnc() - { - std::map encMap; - encMap["Alarm"] = "69"; // AI - encMap["Alarmed"] = "49"; - encMap["Attacked"] = "62"; - encMap["Choice"] = "50"; - encMap["Creature Target"] = "65"; - encMap["Detected"] = "48"; - encMap["Faction Rank Difference"] ="47"; - encMap["Fight"] = "67"; // AI - encMap["Flee"] = "70"; // AI - encMap["Friend Hit"] = "66"; - encMap["Health Percent"] = "04"; - encMap["Hello"] = "68"; // AI - encMap["Level"] = "61"; - encMap["PC Acrobatics"] = "31"; - encMap["PC Agility"] = "53"; // attrib - encMap["PC Alchemy"] = "27"; - encMap["PC Alteration"] = "22"; - encMap["PC Armoror"] = "12"; - encMap["PC Athletics"] = "19"; - encMap["PC Axe"] = "17"; - encMap["PC Blight Disease"] = "41"; - encMap["PC Block"] = "11"; - encMap["PC Blunt Weapon"] = "15"; - encMap["PC Clothing Modifier"] = "42"; - encMap["PC Common Disease"] = "40"; - encMap["PC Conjuration"] = "24"; - encMap["PC Corpus"] = "58"; - encMap["PC Crime Level"] = "43"; - encMap["PC Destruction"] = "21"; - encMap["PC Enchant"] = "20"; - encMap["PC Endurance"] = "55"; // attrib - encMap["PC Expelled"] = "39"; - encMap["PC Fatigue"] = "09"; // dynamic stat - encMap["PC Hand To Hand"] = "37"; - encMap["PC Health"] = "64"; // dynamic stat - encMap["PC Health Percent"] = "07"; - encMap["PC Heavy Armor"] = "14"; - encMap["PC Illusion"] = "23"; - encMap["PC Intelligence"] = "51"; // attrib - encMap["PC Level"] = "06"; - encMap["PC Light Armor"] = "32"; - encMap["PC Long Blade"] = "16"; - encMap["PC Luck"] = "57"; // attrib - encMap["PC Magicka"] = "08"; // dynamic stat - encMap["PC Marksman"] = "34"; - encMap["PC Medium Armor"] = "13"; - encMap["PC Merchantile"] = "35"; - encMap["PC Mysticism"] = "25"; - encMap["PC Personality"] = "56"; // attrib - encMap["PC Reputation"] = "05"; - encMap["PC Restoration"] = "26"; - encMap["PC Security"] = "29"; - encMap["PC Sex"] = "38"; - encMap["PC Short Blade"] = "33"; - encMap["PC Sneak"] = "30"; - encMap["PC Spear"] = "18"; - encMap["PC Speechcraft"] = "36"; - encMap["PC Speed"] = "54"; // attrib - encMap["PC Strength"] = "10"; // attrib - encMap["PC Unarmored"] = "28"; - encMap["PC Vampire"] = "60"; - encMap["PC Werewolf Kills"] = "73"; - encMap["PC Willpower"] = "52"; // attrib - encMap["Rank Requirement"] = "02"; - encMap["Rank High"] = "01"; - encMap["Rank Low"] = "00"; - encMap["Reputation"] = "03"; - encMap["Same Faction"] = "46"; - encMap["Same Race"] = "45"; - encMap["Same Sex"] = "44"; - encMap["Should Attack"] = "71"; - encMap["Talked To PC"] = "63"; - encMap["Weather"] = "59"; - encMap["Werewolf"] = "72"; - return encMap; - } - static const std::map sInfoFuncToEnc = populateInfoFuncToEnc(); - void InfoConditionAdapter::setData(Record& record, const QVariant& value, int subRowIndex, int subColIndex) const { @@ -881,16 +800,21 @@ namespace CSMWorld { if (conditions[subRowIndex].mSelectRule[1] == '1') { - const std::map::const_iterator it = sInfoFuncToEnc.find( - value.toString().toUtf8().constData()); - if (it != sInfoFuncToEnc.end()) + std::map::const_iterator it = sEncToInfoFunc.begin(); + for (;it != sEncToInfoFunc.end(); ++it) { - std::string rule = conditions[subRowIndex].mSelectRule.substr(0, 2); - rule.append(it->second); - rule.append(std::string(1, conditions[subRowIndex].mSelectRule[4])); - conditions[subRowIndex].mSelectRule = rule.append(value.toString().toUtf8().constData()); + if (it->second == value.toString().toUtf8().constData()) + { + std::string rule = conditions[subRowIndex].mSelectRule.substr(0, 2); + rule.append(it->first); + // leave old values for undo (NOTE: may not be vanilla's behaviour) + rule.append(conditions[subRowIndex].mSelectRule.substr(4)); + conditions[subRowIndex].mSelectRule = rule; + break; + } } - else + + if (it == sEncToInfoFunc.end()) return; // return without saving; TODO: maybe log an error here } else From e4ffb985a153b1b4cc3a1c6c44ce4ba27d7b7170 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 10 May 2015 13:32:01 +0200 Subject: [PATCH 1139/3725] Revert "Collision fix" This reverts commit 60fffec3452c68ef2675a7c573af0436c051a6d4. --- libs/openengine/bullet/physic.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index cf7dea1db..c0da03651 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -480,7 +480,7 @@ namespace Physic //#endif bool needDelete = false; - if (btBvhTriangleMeshShape* triangleShape = dynamic_cast(collisionShape)) + if (btBvhTriangleMeshShape* triangleShape = dynamic_cast(shape->mCollisionShape)) { btScaledBvhTriangleMeshShape* scaled = new btScaledBvhTriangleMeshShape(triangleShape, btVector3(scale,scale,scale)); collisionShape = scaled; From 107bf818e726827ee57856462c04a4403ed13f17 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 10 May 2015 13:35:21 +0200 Subject: [PATCH 1140/3725] Revert "Use btScaledBvhTriangleMeshShape, bump required bullet version to 2.83" This reverts commit 27751db99afae9368fc29fabbe0bbedb980c3ace. Conflicts: libs/openengine/bullet/physic.cpp --- components/nifbullet/bulletnifloader.cpp | 4 +-- libs/openengine/bullet/physic.cpp | 32 +++++++----------------- libs/openengine/bullet/physic.hpp | 3 --- 3 files changed, 11 insertions(+), 28 deletions(-) diff --git a/components/nifbullet/bulletnifloader.cpp b/components/nifbullet/bulletnifloader.cpp index 3207af0fe..93c9797b2 100644 --- a/components/nifbullet/bulletnifloader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -123,7 +123,7 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource) mCompoundShape = NULL; mStaticMesh = NULL; - Nif::NIFFilePtr pnif (Nif::Cache::getInstance().load(mResourceName)); + Nif::NIFFilePtr pnif (Nif::Cache::getInstance().load(mResourceName.substr(0, mResourceName.length()-7))); Nif::NIFFile & nif = *pnif.get (); if (nif.numRoots() < 1) { @@ -134,7 +134,7 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource) // Have to load controlled nodes from the .kf // FIXME: the .kf has to be loaded both for rendering and physics, ideally it should be opened once and then reused mControlledNodes.clear(); - std::string kfname = mResourceName; + std::string kfname = mResourceName.substr(0, mResourceName.length()-7); Misc::StringUtils::toLower(kfname); if(kfname.size() > 4 && kfname.compare(kfname.size()-4, 4, ".nif") == 0) kfname.replace(kfname.size()-4, 4, ".kf"); diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index c0da03651..15be7665a 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -455,7 +455,8 @@ namespace Physic float scale, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, Ogre::Vector3* scaledBoxTranslation, Ogre::Quaternion* boxRotation, bool raycasting, bool placeable) { - std::string outputstring = mesh; + std::string sid = (boost::format("%07.3f") % scale).str(); + std::string outputstring = mesh + sid; //get the shape from the .nif mShapeLoader->load(outputstring,"General"); @@ -474,35 +475,20 @@ namespace Physic btCollisionShape* collisionShape = raycasting ? shape->mRaycastingShape : shape->mCollisionShape; -// TODO: check this from cmake? -//#if BT_BULLET_VERSION < 283 -//#error "Bullet version 2.83 or later required" -//#endif + // If this is an animated compound shape, we must duplicate it so we can animate + // multiple instances independently. + if (!raycasting && !shape->mAnimatedShapes.empty()) + collisionShape = duplicateCollisionShape(collisionShape); + if (raycasting && !shape->mAnimatedRaycastingShapes.empty()) + collisionShape = duplicateCollisionShape(collisionShape); - bool needDelete = false; - if (btBvhTriangleMeshShape* triangleShape = dynamic_cast(shape->mCollisionShape)) - { - btScaledBvhTriangleMeshShape* scaled = new btScaledBvhTriangleMeshShape(triangleShape, btVector3(scale,scale,scale)); - collisionShape = scaled; - needDelete = true; - } - else - { - // If this is an animated compound shape, we must duplicate it so we can animate - // multiple instances independently. - if (!raycasting && !shape->mAnimatedShapes.empty()) - collisionShape = duplicateCollisionShape(collisionShape); - if (raycasting && !shape->mAnimatedRaycastingShapes.empty()) - collisionShape = duplicateCollisionShape(collisionShape); - } + collisionShape->setLocalScaling( btVector3(scale,scale,scale)); //create the real body btRigidBody::btRigidBodyConstructionInfo CI = btRigidBody::btRigidBodyConstructionInfo (0,0, collisionShape); RigidBody* body = new RigidBody(CI,name); body->mPlaceable = placeable; - if (needDelete) - body->mCollisionShape.reset(collisionShape); if (!raycasting && !shape->mAnimatedShapes.empty()) { diff --git a/libs/openengine/bullet/physic.hpp b/libs/openengine/bullet/physic.hpp index 7b0906694..7784e8941 100644 --- a/libs/openengine/bullet/physic.hpp +++ b/libs/openengine/bullet/physic.hpp @@ -63,9 +63,6 @@ namespace Physic virtual ~RigidBody(); std::string mName; - // May be empty if the collision shape is a shared resource - std::auto_ptr mCollisionShape; - // Hack: placeable objects (that can be picked up by the player) have different collision behaviour. // This variable needs to be passed to BulletNifLoader. bool mPlaceable; From ca53457a1c572851491fe8d6e1238ee5bd608ae5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 6 May 2015 01:46:34 +0200 Subject: [PATCH 1141/3725] Correct the map icons used for detect spells (Fixes #2519) --- apps/openmw/mwgui/mapwindow.cpp | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 02e8ffdfe..269b43a71 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -468,21 +468,17 @@ namespace MWGui return; std::string markerTexture; - MyGUI::Colour markerColour; if (type == MWBase::World::Detect_Creature) { - markerTexture = "textures\\menu_map_dcreature.dds"; - markerColour = MyGUI::Colour(1,0,0,1); + markerTexture = "textures\\detect_animal_icon.dds"; } if (type == MWBase::World::Detect_Key) { - markerTexture = "textures\\menu_map_dkey.dds"; - markerColour = MyGUI::Colour(0,1,0,1); + markerTexture = "textures\\detect_key_icon.dds"; } if (type == MWBase::World::Detect_Enchantment) { - markerTexture = "textures\\menu_map_dmagic.dds"; - markerColour = MyGUI::Colour(0,0,1,1); + markerTexture = "textures\\detect_enchantment_icon.dds"; } int counter = 0; @@ -499,7 +495,7 @@ namespace MWGui widgetCoord, MyGUI::Align::Default); markerWidget->setDepth(Local_MarkerAboveFogLayer); markerWidget->setImageTexture(markerTexture); - markerWidget->setColour(markerColour); + markerWidget->setImageCoord(MyGUI::IntCoord(0,0,8,8)); markerWidget->setNeedMouseFocus(false); mMagicMarkerWidgets.push_back(markerWidget); } From 033719ccd70db35d3d67d4d707bb2de3c4c184b4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 6 May 2015 02:11:35 +0200 Subject: [PATCH 1142/3725] Correct the icon used for custom map markers --- apps/openmw/mwgui/mapwindow.cpp | 12 ++++++------ files/mygui/openmw_resources.xml | 9 +++++++++ 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 269b43a71..9adfeffe8 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -300,17 +300,17 @@ namespace MWGui MarkerUserData markerPos; MyGUI::IntPoint widgetPos = getMarkerPosition(marker.mWorldX, marker.mWorldY, markerPos); - MyGUI::IntCoord widgetCoord(widgetPos.left - 4, - widgetPos.top - 4, - 8, 8); - MarkerWidget* markerWidget = mLocalMap->createWidget("MarkerButton", + MyGUI::IntCoord widgetCoord(widgetPos.left - 8, + widgetPos.top - 8, + 16, 16); + MarkerWidget* markerWidget = mLocalMap->createWidget("CustomMarkerButton", widgetCoord, MyGUI::Align::Default); markerWidget->setDepth(Local_MarkerAboveFogLayer); markerWidget->setUserString("ToolTipType", "Layout"); markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine"); markerWidget->setUserString("Caption_TextOneLine", MyGUI::TextIterator::toTagsString(marker.mNote)); - markerWidget->setNormalColour(MyGUI::Colour(1.0f, 0.3f, 0.3f)); - markerWidget->setHoverColour(MyGUI::Colour(1.0f, 0.5f, 0.5f)); + markerWidget->setNormalColour(MyGUI::Colour(0.6f, 0.6f, 0.6f)); + markerWidget->setHoverColour(MyGUI::Colour(1.0f, 1.0f, 1.0f)); markerWidget->setUserData(marker); markerWidget->setNeedMouseFocus(true); customMarkerCreated(markerWidget); diff --git a/files/mygui/openmw_resources.xml b/files/mygui/openmw_resources.xml index 423281a62..305cb0c0d 100644 --- a/files/mygui/openmw_resources.xml +++ b/files/mygui/openmw_resources.xml @@ -31,6 +31,15 @@ + + + + + + + + + From b312f50b1f609355011fc89763df6aeeec0ab8cf Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 6 May 2015 02:12:55 +0200 Subject: [PATCH 1143/3725] Fix regression with detect spells detecting deleted objects (Fixes #2518) --- apps/openmw/mwworld/worldimp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 013386f8f..0f8110624 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2956,7 +2956,7 @@ namespace MWWorld Ogre::Vector3(mDetector.getRefData().getPosition().pos)) >= mSquaredDist) return true; - if (!ptr.getRefData().isEnabled()) + if (!ptr.getRefData().isEnabled() || ptr.getRefData().isDeleted()) return true; // Consider references inside containers as well (except if we are looking for a Creature, they cannot be in containers) From eef8f717973d69f1242db16db4517156d37f1d77 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 7 May 2015 16:46:59 +0200 Subject: [PATCH 1144/3725] Add a comment --- apps/openmw/mwworld/cellstore.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index d7036d6b1..672b6046b 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -120,6 +120,7 @@ namespace MWWorld /// Call functor (ref) for each reference. functor must return a bool. Returning /// false will abort the iteration. + /// \attention This function also lists deleted (count 0) objects! /// \return Iteration completed? /// /// \note Creatures and NPCs are handled last. From 3b8b217888469c839c53ca4945deaeb88ac4d6bf Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 8 May 2015 02:22:39 +0200 Subject: [PATCH 1145/3725] Fix no punishment for stealing when taking an item with the inventory opened --- apps/openmw/mwgui/inventorywindow.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 80b246e84..9aa8a8ea1 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -594,6 +594,8 @@ namespace MWGui MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); MWBase::Environment::get().getWorld()->breakInvisibility(player); + MWBase::Environment::get().getMechanicsManager()->itemTaken(player, object, MWWorld::Ptr(), count); + // add to player inventory // can't use ActionTake here because we need an MWWorld::Ptr to the newly inserted object MWWorld::Ptr newObject = *player.getClass().getContainerStore (player).add (object, object.getRefData().getCount(), player); @@ -612,8 +614,6 @@ namespace MWGui throw std::runtime_error("Added item not found"); mDragAndDrop->startDrag(i, mSortModel, mTradeModel, mItemView, count); - MWBase::Environment::get().getMechanicsManager()->itemTaken(player, newObject, MWWorld::Ptr(), count); - MWBase::Environment::get().getWindowManager()->updateSpellWindow(); } From ac88326909d80223815a84743578a0c2adcbb583 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 8 May 2015 23:57:23 +0200 Subject: [PATCH 1146/3725] Exit out of choice when no responses are found (Fixes #2525) --- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index b928738dd..0b9fd65d2 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -485,6 +485,12 @@ namespace MWDialogue executeScript (info->mResultScript); } + else + { + mChoice = -1; + mIsInChoice = false; + MWBase::Environment::get().getWindowManager()->getDialogueWindow()->clearChoices(); + } } } From 9d86e5b02803550d7406a6cff53d6e12534d3a16 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 10 May 2015 13:04:50 +0200 Subject: [PATCH 1147/3725] GetSpellEffects returns true for active abilities (Fixes #2530) --- apps/openmw/mwmechanics/spells.cpp | 14 ++++++++++++++ apps/openmw/mwmechanics/spells.hpp | 3 +++ apps/openmw/mwscript/miscextensions.cpp | 3 ++- 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/spells.cpp b/apps/openmw/mwmechanics/spells.cpp index 04225b43e..b1829964b 100644 --- a/apps/openmw/mwmechanics/spells.cpp +++ b/apps/openmw/mwmechanics/spells.cpp @@ -143,6 +143,20 @@ namespace MWMechanics return mSelectedSpell; } + bool Spells::isSpellActive(const std::string &id) const + { + TContainer::const_iterator found = mSpells.find(id); + if (found != mSpells.end()) + { + const ESM::Spell *spell = + MWBase::Environment::get().getWorld()->getStore().get().find (id); + + return (spell->mData.mType==ESM::Spell::ST_Ability || spell->mData.mType==ESM::Spell::ST_Blight || + spell->mData.mType==ESM::Spell::ST_Disease || spell->mData.mType==ESM::Spell::ST_Curse); + } + return false; + } + bool Spells::hasCommonDisease() const { for (TIterator iter = mSpells.begin(); iter!=mSpells.end(); ++iter) diff --git a/apps/openmw/mwmechanics/spells.hpp b/apps/openmw/mwmechanics/spells.hpp index 064b2c1e5..6b4149939 100644 --- a/apps/openmw/mwmechanics/spells.hpp +++ b/apps/openmw/mwmechanics/spells.hpp @@ -98,6 +98,9 @@ namespace MWMechanics const std::string getSelectedSpell() const; ///< May return an empty string. + bool isSpellActive(const std::string& id) const; + ///< Are we under the effects of the given spell ID? + bool hasCommonDisease() const; bool hasBlightDisease() const; diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 29f586a65..38106340a 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -595,7 +595,8 @@ namespace MWScript std::string id = runtime.getStringLiteral(runtime[0].mInteger); runtime.pop(); - runtime.push(ptr.getClass().getCreatureStats(ptr).getActiveSpells().isSpellActive(id)); + const MWMechanics::CreatureStats& stats = ptr.getClass().getCreatureStats(ptr); + runtime.push(stats.getActiveSpells().isSpellActive(id) || stats.getSpells().isSpellActive(id)); } }; From c819180aa1299422f42f94b82cc58d48f6c76a6c Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 10 May 2015 13:09:22 +0200 Subject: [PATCH 1148/3725] Minor cleanup --- apps/openmw/mwgui/spellbuyingwindow.cpp | 8 +------- apps/openmw/mwscript/statsextensions.cpp | 10 ++-------- 2 files changed, 3 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwgui/spellbuyingwindow.cpp b/apps/openmw/mwgui/spellbuyingwindow.cpp index 57b02940e..76a1d51e5 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.cpp +++ b/apps/openmw/mwgui/spellbuyingwindow.cpp @@ -127,13 +127,7 @@ namespace MWGui bool SpellBuyingWindow::playerHasSpell(const std::string &id) { MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); - MWMechanics::Spells& playerSpells = player.getClass().getCreatureStats (player).getSpells(); - for (MWMechanics::Spells::TIterator it = playerSpells.begin(); it != playerSpells.end(); ++it) - { - if (Misc::StringUtils::ciEqual(id, it->first)) - return true; - } - return false; + return player.getClass().getCreatureStats(player).getSpells().hasSpell(id); } void SpellBuyingWindow::onSpellButtonClick(MyGUI::Widget* _sender) diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index d825b085e..80f46e457 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -515,14 +515,8 @@ namespace MWScript Interpreter::Type_Integer value = 0; - for (MWMechanics::Spells::TIterator iter ( - ptr.getClass().getCreatureStats (ptr).getSpells().begin()); - iter!=ptr.getClass().getCreatureStats (ptr).getSpells().end(); ++iter) - if (iter->first==id) - { - value = 1; - break; - } + if (ptr.getClass().getCreatureStats(ptr).getSpells().hasSpell(id)) + value = 1; runtime.push (value); } From 97c35da441f1de47aeb523cb3f1594b6195caf91 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 10 May 2015 15:34:07 +0200 Subject: [PATCH 1149/3725] Change exterior water level to z=-1 (Fixes #1405) --- apps/openmw/mwworld/scene.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 8d689240b..f5a9b8960 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -256,12 +256,13 @@ namespace MWWorld insertCell (*cell, true, loadingListener); mRendering.cellAdded (cell); - bool waterEnabled = cell->getCell()->hasWater(); + bool waterEnabled = cell->getCell()->hasWater() || cell->isExterior(); mRendering.setWaterEnabled(waterEnabled); + float waterLevel = cell->isExterior() ? -1.f : cell->getWaterLevel(); if (waterEnabled) { - mPhysics->enableWater(cell->getWaterLevel()); - mRendering.setWaterHeight(cell->getWaterLevel()); + mPhysics->enableWater(waterLevel); + mRendering.setWaterHeight(waterLevel); } else mPhysics->disableWater(); From 58a2ad663cee7de5e9f419af80485c97ca890c63 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 11 May 2015 16:24:52 +0200 Subject: [PATCH 1150/3725] Fix regression of sleep interruption chance --- apps/openmw/mwgui/waitdialog.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index f74b06891..94905dd9e 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -155,8 +155,9 @@ namespace MWGui if (!region->mSleepList.empty()) { // figure out if player will be woken while sleeping + int x = OEngine::Misc::Rng::rollDice(hoursToWait); float fSleepRandMod = world->getStore().get().find("fSleepRandMod")->getFloat(); - if (OEngine::Misc::Rng::rollProbability() > fSleepRandMod) + if (x > fSleepRandMod * hoursToWait) { float fSleepRestMod = world->getStore().get().find("fSleepRestMod")->getFloat(); mInterruptAt = hoursToWait - int(fSleepRestMod * hoursToWait); From 5abeab21edb1854955bb0865b3cf6d22b2d48a38 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 11 May 2015 16:55:09 +0200 Subject: [PATCH 1151/3725] Various integer/floating point roll adjustments based on wiki --- apps/openmw/mwclass/creature.cpp | 2 +- apps/openmw/mwclass/npc.cpp | 2 +- apps/openmw/mwgui/pickpocketitemmodel.cpp | 2 +- apps/openmw/mwmechanics/combat.cpp | 2 +- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 8404b9523..192bdf2ce 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -251,7 +251,7 @@ namespace MWClass float hitchance = MWMechanics::getHitChance(ptr, victim, ref->mBase->mData.mCombat); - if(OEngine::Misc::Rng::rollProbability() >= hitchance/100.0f) + if(OEngine::Misc::Rng::roll0to99() >= hitchance) { victim.getClass().onHit(victim, 0.0f, false, MWWorld::Ptr(), ptr, false); MWMechanics::reduceWeaponCondition(0.f, false, weapon, ptr); diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 1d58dc87e..3ca57aca8 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -515,7 +515,7 @@ namespace MWClass float hitchance = MWMechanics::getHitChance(ptr, victim, ptr.getClass().getSkill(ptr, weapskill)); - if (OEngine::Misc::Rng::rollProbability() >= hitchance / 100.0f) + if (OEngine::Misc::Rng::roll0to99() >= hitchance) { othercls.onHit(victim, 0.0f, false, weapon, ptr, false); MWMechanics::reduceWeaponCondition(0.f, false, weapon, ptr); diff --git a/apps/openmw/mwgui/pickpocketitemmodel.cpp b/apps/openmw/mwgui/pickpocketitemmodel.cpp index bc7c5528e..b8ac20f99 100644 --- a/apps/openmw/mwgui/pickpocketitemmodel.cpp +++ b/apps/openmw/mwgui/pickpocketitemmodel.cpp @@ -20,7 +20,7 @@ namespace MWGui { for (size_t i = 0; igetItemCount(); ++i) { - if (chance <= OEngine::Misc::Rng::roll0to99()) + if (OEngine::Misc::Rng::roll0to99() > chance) mHiddenItems.push_back(mSourceModel->getItem(i)); } } diff --git a/apps/openmw/mwmechanics/combat.cpp b/apps/openmw/mwmechanics/combat.cpp index c5fc34507..045f0108c 100644 --- a/apps/openmw/mwmechanics/combat.cpp +++ b/apps/openmw/mwmechanics/combat.cpp @@ -187,7 +187,7 @@ namespace MWMechanics int skillValue = attacker.getClass().getSkill(attacker, weapon.getClass().getEquipmentSkill(weapon)); - if (OEngine::Misc::Rng::rollProbability() >= getHitChance(attacker, victim, skillValue) / 100.0f) + if (OEngine::Misc::Rng::roll0to99() >= getHitChance(attacker, victim, skillValue)) { victim.getClass().onHit(victim, 0.0f, false, projectile, attacker, false); MWMechanics::reduceWeaponCondition(0.f, false, weapon, attacker); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index da8d49db0..c829154e2 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -737,7 +737,7 @@ namespace MWMechanics float x = 0; float y = 0; - float roll = OEngine::Misc::Rng::rollClosedProbability() * 100; + int roll = OEngine::Misc::Rng::roll0to99(); if (type == PT_Admire) { From 47758c11cd1096c7060c2dbe0310eb2c6e53e4f6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 12 May 2015 03:02:15 +0200 Subject: [PATCH 1152/3725] Readded collision objects and movement physics --- apps/opencs/CMakeLists.txt | 3 +- apps/openmw/CMakeLists.txt | 6 +- apps/openmw/mwbase/world.hpp | 4 +- apps/openmw/mwclass/apparatus.cpp | 3 +- apps/openmw/mwclass/armor.cpp | 3 +- apps/openmw/mwclass/book.cpp | 3 +- apps/openmw/mwclass/clothing.cpp | 3 +- apps/openmw/mwclass/ingredient.cpp | 3 +- apps/openmw/mwclass/light.cpp | 5 +- apps/openmw/mwclass/lockpick.cpp | 3 +- apps/openmw/mwclass/misc.cpp | 3 +- apps/openmw/mwclass/potion.cpp | 3 +- apps/openmw/mwclass/probe.cpp | 3 +- apps/openmw/mwclass/repair.cpp | 3 +- apps/openmw/mwclass/weapon.cpp | 3 +- apps/openmw/mwmechanics/character.cpp | 73 ++-- apps/openmw/mwmechanics/movement.hpp | 7 + apps/openmw/mwphysics/actor.cpp | 152 +++++++ apps/openmw/mwphysics/actor.hpp | 125 ++++++ apps/openmw/mwphysics/collisiontype.hpp | 17 + apps/openmw/mwphysics/convert.hpp | 35 ++ apps/openmw/mwphysics/physicssystem.cpp | 420 +++++++++++++------- apps/openmw/mwphysics/physicssystem.hpp | 56 ++- apps/openmw/mwphysics/trace.cpp | 128 ++++++ apps/openmw/mwphysics/trace.h | 27 ++ apps/openmw/mwscript/aiextensions.cpp | 2 +- apps/openmw/mwscript/miscextensions.cpp | 4 +- apps/openmw/mwworld/cellfunctors.hpp | 18 +- apps/openmw/mwworld/scene.cpp | 24 +- apps/openmw/mwworld/weather.cpp | 8 +- apps/openmw/mwworld/weather.hpp | 4 +- apps/openmw/mwworld/worldimp.cpp | 46 +-- apps/openmw/mwworld/worldimp.hpp | 4 +- components/CMakeLists.txt | 7 +- components/nifbullet/bulletnifloader.cpp | 294 ++++++++------ components/nifbullet/bulletnifloader.hpp | 113 +++--- components/nifbullet/bulletshapemanager.cpp | 47 +++ components/nifbullet/bulletshapemanager.hpp | 37 ++ 38 files changed, 1232 insertions(+), 467 deletions(-) create mode 100644 apps/openmw/mwphysics/actor.cpp create mode 100644 apps/openmw/mwphysics/actor.hpp create mode 100644 apps/openmw/mwphysics/collisiontype.hpp create mode 100644 apps/openmw/mwphysics/convert.hpp create mode 100644 apps/openmw/mwphysics/trace.cpp create mode 100644 apps/openmw/mwphysics/trace.h create mode 100644 components/nifbullet/bulletshapemanager.cpp create mode 100644 components/nifbullet/bulletshapemanager.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 5a74fa48f..1b71cf0ed 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -151,7 +151,7 @@ if(WIN32) set(QT_USE_QTMAIN TRUE) endif(WIN32) -set(BOOST_COMPONENTS system filesystem program_options thread wave) +set(BOOST_COMPONENTS system filesystem program_options thread) if(WIN32) set(BOOST_COMPONENTS ${BOOST_COMPONENTS} locale) endif(WIN32) @@ -202,7 +202,6 @@ target_link_libraries(openmw-cs ${OGRE_LIBRARIES} ${OPENSCENEGRAPH_LIBRARIES} ${Boost_LIBRARIES} - ${BULLET_LIBRARIES} ${QT_LIBRARIES} components ) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index bcfc24053..95875de10 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -74,7 +74,7 @@ add_openmw_dir (mwworld ) add_openmw_dir (mwphysics - physicssystem + physicssystem trace collisiontype actor convert ) add_openmw_dir (mwclass @@ -101,9 +101,9 @@ add_openmw_dir (mwbase # Main executable if (ANDROID) - set(BOOST_COMPONENTS system filesystem program_options thread wave atomic) + set(BOOST_COMPONENTS system filesystem program_options thread atomic) else () - set(BOOST_COMPONENTS system filesystem program_options thread wave) + set(BOOST_COMPONENTS system filesystem program_options thread) endif () if(WIN32) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 4ccbfc784..7cc0a6e5e 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -302,7 +302,7 @@ namespace MWBase virtual void positionToIndex (float x, float y, int &cellX, int &cellY) const = 0; ///< Convert position to cell numbers - virtual void queueMovement(const MWWorld::Ptr &ptr, const Ogre::Vector3 &velocity) = 0; + virtual void queueMovement(const MWWorld::Ptr &ptr, const osg::Vec3f &velocity) = 0; ///< Queues movement for \a ptr (in local space), to be applied in the next call to /// doPhysics. @@ -555,7 +555,7 @@ namespace MWBase virtual bool isInStorm() const = 0; /// @see MWWorld::WeatherManager::getStormDirection - virtual Ogre::Vector3 getStormDirection() const = 0; + virtual osg::Vec3f getStormDirection() const = 0; /// Resets all actors in the current active cells to their original location within that cell. virtual void resetActors() = 0; diff --git a/apps/openmw/mwclass/apparatus.cpp b/apps/openmw/mwclass/apparatus.cpp index 55209764a..6f11a36c7 100644 --- a/apps/openmw/mwclass/apparatus.cpp +++ b/apps/openmw/mwclass/apparatus.cpp @@ -35,8 +35,7 @@ namespace MWClass void Apparatus::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const { - if(!model.empty()) - physics.addObject(ptr, model, true); + // TODO: add option somewhere to enable collision for placeable objects } std::string Apparatus::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index ec3658b3d..04c98e437 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -40,8 +40,7 @@ namespace MWClass void Armor::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const { - if(!model.empty()) - physics.addObject(ptr, model, true); + // TODO: add option somewhere to enable collision for placeable objects } std::string Armor::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index e71dd6769..2c20435b2 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -37,8 +37,7 @@ namespace MWClass void Book::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const { - if(!model.empty()) - physics.addObject(ptr, model, true); + // TODO: add option somewhere to enable collision for placeable objects } std::string Book::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index 39025227c..8964b65e0 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -37,8 +37,7 @@ namespace MWClass void Clothing::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const { - if(!model.empty()) - physics.addObject(ptr, model, true); + // TODO: add option somewhere to enable collision for placeable objects } std::string Clothing::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/ingredient.cpp b/apps/openmw/mwclass/ingredient.cpp index 9b35b8530..fb409cb55 100644 --- a/apps/openmw/mwclass/ingredient.cpp +++ b/apps/openmw/mwclass/ingredient.cpp @@ -41,8 +41,7 @@ namespace MWClass void Ingredient::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const { - if(!model.empty()) - physics.addObject(ptr, model, true); + // TODO: add option somewhere to enable collision for placeable objects } std::string Ingredient::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 7ea5ae1be..4d0c0cba9 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -47,8 +47,9 @@ namespace MWClass ptr.get(); assert (ref->mBase != NULL); - if(!model.empty()) - physics.addObject(ptr, model, (ref->mBase->mData.mFlags & ESM::Light::Carry) != 0); + // TODO: add option somewhere to enable collision for placeable objects + if ((ref->mBase->mData.mFlags & ESM::Light::Carry) == 0) + physics.addObject(ptr, model); if (!ref->mBase->mSound.empty() && !(ref->mBase->mData.mFlags & ESM::Light::OffDefault)) MWBase::Environment::get().getSoundManager()->playSound3D(ptr, ref->mBase->mSound, 1.0, 1.0, diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index e1e774755..8f22c3fa1 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -36,8 +36,7 @@ namespace MWClass void Lockpick::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const { - if(!model.empty()) - physics.addObject(ptr, model, true); + // TODO: add option somewhere to enable collision for placeable objects } std::string Lockpick::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index df28daee9..b7c39b50a 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -53,8 +53,7 @@ namespace MWClass void Miscellaneous::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const { - if(!model.empty()) - physics.addObject(ptr, model, true); + // TODO: add option somewhere to enable collision for placeable objects } std::string Miscellaneous::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/potion.cpp b/apps/openmw/mwclass/potion.cpp index 98bb703cb..647f83f67 100644 --- a/apps/openmw/mwclass/potion.cpp +++ b/apps/openmw/mwclass/potion.cpp @@ -39,8 +39,7 @@ namespace MWClass void Potion::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const { - if(!model.empty()) - physics.addObject(ptr, model, true); + // TODO: add option somewhere to enable collision for placeable objects } std::string Potion::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index fb96bff5a..cb43ccce6 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -36,8 +36,7 @@ namespace MWClass void Probe::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const { - if(!model.empty()) - physics.addObject(ptr, model, true); + // TODO: add option somewhere to enable collision for placeable objects } std::string Probe::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/repair.cpp b/apps/openmw/mwclass/repair.cpp index 9ddc36ff9..0bc64a99e 100644 --- a/apps/openmw/mwclass/repair.cpp +++ b/apps/openmw/mwclass/repair.cpp @@ -35,8 +35,7 @@ namespace MWClass void Repair::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const { - if(!model.empty()) - physics.addObject(ptr, model, true); + // TODO: add option somewhere to enable collision for placeable objects } std::string Repair::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index bbe81f370..8c3d7fb10 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -39,8 +39,7 @@ namespace MWClass void Weapon::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const { - if(!model.empty()) - physics.addObject(ptr, model, true); + // TODO: add option somewhere to enable collision for placeable objects } std::string Weapon::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index adcfb57a4..5769138fa 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1346,7 +1346,7 @@ void CharacterController::update(float duration) { MWBase::World *world = MWBase::Environment::get().getWorld(); const MWWorld::Class &cls = mPtr.getClass(); - Ogre::Vector3 movement(0.0f); + osg::Vec3f movement(0.f, 0.f, 0.f); updateMagicEffects(); @@ -1403,23 +1403,23 @@ void CharacterController::update(float duration) } } - Ogre::Vector3 vec(cls.getMovementSettings(mPtr).mPosition); - vec.normalise(); + osg::Vec3f vec(cls.getMovementSettings(mPtr).asVec3()); + vec.normalize(); if(mHitState != CharState_None && mJumpState == JumpState_None) - vec = Ogre::Vector3(0.0f); + vec = osg::Vec3f(0.f, 0.f, 0.f); Ogre::Vector3 rot = cls.getRotationVector(mPtr); mMovementSpeed = cls.getSpeed(mPtr); - vec.x *= mMovementSpeed; - vec.y *= mMovementSpeed; + vec.x() *= mMovementSpeed; + vec.y() *= mMovementSpeed; CharacterState movestate = CharState_None; CharacterState idlestate = CharState_SpecialIdle; bool forcestateupdate = false; - mHasMovedInXY = std::abs(vec[0])+std::abs(vec[1]) > 0.0f; + mHasMovedInXY = std::abs(vec.x())+std::abs(vec.y()) > 0.0f; isrunning = isrunning && mHasMovedInXY; @@ -1482,7 +1482,7 @@ void CharacterController::update(float duration) cls.getCreatureStats(mPtr).setFatigue(fatigue); if(sneak || inwater || flying) - vec.z = 0.0f; + vec.z() = 0.0f; if (inwater || flying) cls.getCreatureStats(mPtr).land(); @@ -1505,22 +1505,23 @@ void CharacterController::update(float duration) static const float fJumpMoveMult = gmst.find("fJumpMoveMult")->getFloat(); float factor = fJumpMoveBase + fJumpMoveMult * mPtr.getClass().getSkill(mPtr, ESM::Skill::Acrobatics)/100.f; factor = std::min(1.f, factor); - vec.x *= factor; - vec.y *= factor; - vec.z = 0.0f; + vec.x() *= factor; + vec.y() *= factor; + vec.z() = 0.0f; } - else if(vec.z > 0.0f && mJumpState == JumpState_None) + else if(vec.z() > 0.0f && mJumpState == JumpState_None) { // Started a jump. float z = cls.getJump(mPtr); if (z > 0) { - if(vec.x == 0 && vec.y == 0) - vec = Ogre::Vector3(0.0f, 0.0f, z); + if(vec.x() == 0 && vec.y() == 0) + vec = osg::Vec3f(0.0f, 0.0f, z); else { - Ogre::Vector3 lat = Ogre::Vector3(vec.x, vec.y, 0.0f).normalisedCopy(); - vec = Ogre::Vector3(lat.x, lat.y, 1.0f) * z * 0.707f; + osg::Vec3f lat (vec.x(), vec.y(), 0.0f); + lat.normalize(); + vec = osg::Vec3f(lat.x(), lat.y(), 1.0f) * z * 0.707f; } // advance acrobatics @@ -1544,7 +1545,7 @@ void CharacterController::update(float duration) { forcestateupdate = true; mJumpState = JumpState_Landing; - vec.z = 0.0f; + vec.z() = 0.0f; float height = cls.getCreatureStats(mPtr).land(); float healthLost = getFallDamage(mPtr, height); @@ -1575,28 +1576,28 @@ void CharacterController::update(float duration) else { mJumpState = JumpState_None; - vec.z = 0.0f; + vec.z() = 0.0f; inJump = false; - if(std::abs(vec.x/2.0f) > std::abs(vec.y)) + if(std::abs(vec.x()/2.0f) > std::abs(vec.y())) { - if(vec.x > 0.0f) + if(vec.x() > 0.0f) movestate = (inwater ? (isrunning ? CharState_SwimRunRight : CharState_SwimWalkRight) : (sneak ? CharState_SneakRight : (isrunning ? CharState_RunRight : CharState_WalkRight))); - else if(vec.x < 0.0f) + else if(vec.x() < 0.0f) movestate = (inwater ? (isrunning ? CharState_SwimRunLeft : CharState_SwimWalkLeft) : (sneak ? CharState_SneakLeft : (isrunning ? CharState_RunLeft : CharState_WalkLeft))); } - else if(vec.y != 0.0f) + else if(vec.y() != 0.0f) { - if(vec.y > 0.0f) + if(vec.y() > 0.0f) movestate = (inwater ? (isrunning ? CharState_SwimRunForward : CharState_SwimWalkForward) : (sneak ? CharState_SneakForward : (isrunning ? CharState_RunForward : CharState_WalkForward))); - else if(vec.y < 0.0f) + else if(vec.y() < 0.0f) movestate = (inwater ? (isrunning ? CharState_SwimRunBack : CharState_SwimWalkBack) : (sneak ? CharState_SneakBack : (isrunning ? CharState_RunBack : CharState_WalkBack))); @@ -1676,7 +1677,7 @@ void CharacterController::update(float duration) } else // We must always queue movement, even if there is none, to apply gravity. - world->queueMovement(mPtr, Ogre::Vector3(0.0f)); + world->queueMovement(mPtr, osg::Vec3f(0.f, 0.f, 0.f)); movement = vec; cls.getMovementSettings(mPtr).mPosition[0] = cls.getMovementSettings(mPtr).mPosition[1] = 0; @@ -1688,7 +1689,7 @@ void CharacterController::update(float duration) } else if(cls.getCreatureStats(mPtr).isDead()) { - world->queueMovement(mPtr, Ogre::Vector3(0.0f)); + world->queueMovement(mPtr, osg::Vec3f(0.f, 0.f, 0.f)); } osg::Vec3f moved = mAnimation->runAnimation(mSkipAnim ? 0.f : duration); @@ -1702,15 +1703,15 @@ void CharacterController::update(float duration) { float l = moved.length(); - if((movement.x < 0.0f && movement.x < moved.x()*2.0f) || - (movement.x > 0.0f && movement.x > moved.x()*2.0f)) - moved.x() = movement.x; - if((movement.y < 0.0f && movement.y < moved.y()*2.0f) || - (movement.y > 0.0f && movement.y > moved.y()*2.0f)) - moved.y() = movement.y; - if((movement.z < 0.0f && movement.z < moved.z()*2.0f) || - (movement.z > 0.0f && movement.z > moved.z()*2.0f)) - moved.z() = movement.z; + if((movement.x() < 0.0f && movement.x() < moved.x()*2.0f) || + (movement.x() > 0.0f && movement.x() > moved.x()*2.0f)) + moved.x() = movement.x(); + if((movement.y() < 0.0f && movement.y() < moved.y()*2.0f) || + (movement.y() > 0.0f && movement.y() > moved.y()*2.0f)) + moved.y() = movement.y(); + if((movement.z() < 0.0f && movement.z() < moved.z()*2.0f) || + (movement.z() > 0.0f && movement.z() > moved.z()*2.0f)) + moved.z() = movement.z(); // but keep the original speed float newLength = moved.length(); if (newLength > 0) @@ -1722,7 +1723,7 @@ void CharacterController::update(float duration) // Update movement if(mMovementAnimationControlled && mPtr.getClass().isActor()) - world->queueMovement(mPtr, Ogre::Vector3(moved.x(), moved.y(), moved.z())); + world->queueMovement(mPtr, moved); mSkipAnim = false; diff --git a/apps/openmw/mwmechanics/movement.hpp b/apps/openmw/mwmechanics/movement.hpp index 6c9a4b758..c12b61538 100644 --- a/apps/openmw/mwmechanics/movement.hpp +++ b/apps/openmw/mwmechanics/movement.hpp @@ -1,6 +1,8 @@ #ifndef GAME_MWMECHANICS_MOVEMENT_H #define GAME_MWMECHANICS_MOVEMENT_H +#include + namespace MWMechanics { /// Desired movement for an actor @@ -14,6 +16,11 @@ namespace MWMechanics mPosition[0] = mPosition[1] = mPosition[2] = 0.0f; mRotation[0] = mRotation[1] = mRotation[2] = 0.0f; } + + osg::Vec3f asVec3() + { + return osg::Vec3f(mPosition[0], mPosition[1], mPosition[2]); + } }; } diff --git a/apps/openmw/mwphysics/actor.cpp b/apps/openmw/mwphysics/actor.cpp new file mode 100644 index 000000000..edad7e196 --- /dev/null +++ b/apps/openmw/mwphysics/actor.cpp @@ -0,0 +1,152 @@ +#include "actor.hpp" +#include + +#include + +#include + +#include "../mwworld/class.hpp" + +#include + +#include "convert.hpp" +#include "collisiontype.hpp" + +namespace MWPhysics +{ + + +Actor::Actor(const MWWorld::Ptr& ptr, osg::ref_ptr shape, btDynamicsWorld* world) + : mCanWaterWalk(false), mWalkingOnWater(false) + , mCollisionObject(0), mForce(0.f, 0.f, 0.f), mOnGround(false) + , mInternalCollisionMode(true) + , mExternalCollisionMode(true) + , mDynamicsWorld(world) +{ + mPtr = ptr; + + mHalfExtents = shape->mCollisionBoxHalfExtents; + mMeshTranslation = shape->mCollisionBoxTranslate; + + // Use capsule shape only if base is square (nonuniform scaling apparently doesn't work on it) + if (std::abs(mHalfExtents.x()-mHalfExtents.y())= mHalfExtents.x()) + { + // Could also be btCapsuleShapeZ, but the movement solver seems to have issues with it (jumping on slopes doesn't work) + mShape.reset(new btCylinderShapeZ(toBullet(mHalfExtents))); + } + else + mShape.reset(new btBoxShape(toBullet(mHalfExtents))); + + mCollisionObject.reset(new btCollisionObject); + mCollisionObject->setCollisionFlags(btCollisionObject::CF_KINEMATIC_OBJECT); + mCollisionObject->setActivationState(DISABLE_DEACTIVATION); + mCollisionObject->setCollisionShape(mShape.get()); + mCollisionObject->setUserPointer(static_cast(this)); + + updateRotation(); + updateScale(); + // already called by updateScale() + //updatePosition(); + + updateCollisionMask(); +} + +Actor::~Actor() +{ + if (mCollisionObject.get()) + mDynamicsWorld->removeCollisionObject(mCollisionObject.get()); +} + +void Actor::enableCollisionMode(bool collision) +{ + mInternalCollisionMode = collision; +} + +void Actor::enableCollisionBody(bool collision) +{ + if (mExternalCollisionMode != collision) + { + mExternalCollisionMode = collision; + updateCollisionMask(); + } +} + +void Actor::updateCollisionMask() +{ + mDynamicsWorld->removeCollisionObject(mCollisionObject.get()); + int collisionMask = CollisionType_World | CollisionType_HeightMap; + if (mExternalCollisionMode) + collisionMask |= CollisionType_Actor | CollisionType_Projectile; + if (mCanWaterWalk) + collisionMask |= CollisionType_Water; + mDynamicsWorld->addCollisionObject(mCollisionObject.get(), CollisionType_Actor, collisionMask); +} + +void Actor::updatePosition() +{ + osg::Vec3f position = mPtr.getRefData().getPosition().asVec3(); + + btTransform tr = mCollisionObject->getWorldTransform(); + osg::Vec3f scaledTranslation = osg::componentMultiply(mMeshTranslation, mScale); + osg::Vec3f newPosition = scaledTranslation + position; + + tr.setOrigin(toBullet(newPosition)); + mCollisionObject->setWorldTransform(tr); +} + +void Actor::updateRotation () +{ + btTransform tr = mCollisionObject->getWorldTransform(); + tr.setRotation(toBullet(mPtr.getRefData().getBaseNode()->getAttitude())); + mCollisionObject->setWorldTransform(tr); +} + +void Actor::updateScale() +{ + float scale = mPtr.getCellRef().getScale(); + osg::Vec3f scaleVec(scale,scale,scale); + + if (!mPtr.getClass().isNpc()) + mPtr.getClass().adjustScale(mPtr, scaleVec); + + mScale = scaleVec; + mShape->setLocalScaling(toBullet(mScale)); + + updatePosition(); +} + +osg::Vec3f Actor::getHalfExtents() const +{ + return osg::componentMultiply(mHalfExtents, mScale); +} + +void Actor::setInertialForce(const osg::Vec3f &force) +{ + mForce = force; +} + +void Actor::setOnGround(bool grounded) +{ + mOnGround = grounded; +} + +bool Actor::isWalkingOnWater() const +{ + return mWalkingOnWater; +} + +void Actor::setWalkingOnWater(bool walkingOnWater) +{ + mWalkingOnWater = walkingOnWater; +} + +void Actor::setCanWaterWalk(bool waterWalk) +{ + if (waterWalk != mCanWaterWalk) + { + mCanWaterWalk = waterWalk; + updateCollisionMask(); + } +} + +} diff --git a/apps/openmw/mwphysics/actor.hpp b/apps/openmw/mwphysics/actor.hpp new file mode 100644 index 000000000..ec1d81fd9 --- /dev/null +++ b/apps/openmw/mwphysics/actor.hpp @@ -0,0 +1,125 @@ +#ifndef OPENMW_MWPHYSICS_ACTOR_H +#define OPENMW_MWPHYSICS_ACTOR_H + +#include + +#include "../mwworld/ptr.hpp" + +#include +#include + +class btDynamicsWorld; +class btCollisionShape; +class btCollisionObject; + +namespace NifBullet +{ + class BulletShapeInstance; +} + +namespace MWPhysics +{ + + class PtrHolder + { + public: + virtual ~PtrHolder() {} + + protected: + MWWorld::Ptr mPtr; + }; + + class Actor : public PtrHolder + { + public: + Actor(const MWWorld::Ptr& ptr, osg::ref_ptr shape, btDynamicsWorld* world); + ~Actor(); + + /** + * Sets the collisionMode for this actor. If disabled, the actor can fly and clip geometry. + */ + void enableCollisionMode(bool collision); + + bool getCollisionMode() const + { + return mInternalCollisionMode; + } + + /** + * Enables or disables the *external* collision body. If disabled, other actors will not collide with this actor. + */ + void enableCollisionBody(bool collision); + + void updateScale(); + void updateRotation(); + void updatePosition(); + + /** + * Returns the (scaled) half extents + */ + osg::Vec3f getHalfExtents() const; + + /** + * Sets the current amount of inertial force (incl. gravity) affecting this physic actor + */ + void setInertialForce(const osg::Vec3f &force); + + /** + * Gets the current amount of inertial force (incl. gravity) affecting this physic actor + */ + const osg::Vec3f &getInertialForce() const + { + return mForce; + } + + void setOnGround(bool grounded); + + bool getOnGround() const + { + return mInternalCollisionMode && mOnGround; + } + + btCollisionObject* getCollisionObject() const + { + return mCollisionObject.get(); + } + + /// Sets whether this actor should be able to collide with the water surface + void setCanWaterWalk(bool waterWalk); + + /// Sets whether this actor has been walking on the water surface in the last frame + void setWalkingOnWater(bool walkingOnWater); + bool isWalkingOnWater() const; + + private: + /// Removes then re-adds the collision object to the dynamics world + void updateCollisionMask(); + + bool mCanWaterWalk; + bool mWalkingOnWater; + + std::auto_ptr mShape; + + std::auto_ptr mCollisionObject; + + osg::Vec3f mMeshTranslation; + osg::Vec3f mHalfExtents; + + osg::Vec3f mScale; + osg::Vec3f mPosition; + + osg::Vec3f mForce; + bool mOnGround; + bool mInternalCollisionMode; + bool mExternalCollisionMode; + + btDynamicsWorld* mDynamicsWorld; + + Actor(const Actor&); + Actor& operator=(const Actor&); + }; + +} + + +#endif diff --git a/apps/openmw/mwphysics/collisiontype.hpp b/apps/openmw/mwphysics/collisiontype.hpp new file mode 100644 index 000000000..0f083ab35 --- /dev/null +++ b/apps/openmw/mwphysics/collisiontype.hpp @@ -0,0 +1,17 @@ +#ifndef OPENMW_MWPHYSICS_COLLISIONTYPE_H +#define OPENMW_MWPHYSICS_COLLISIONTYPE_H + +namespace MWPhysics +{ + +enum CollisionType { + CollisionType_World = 1<<0, + CollisionType_Actor = 1<<1, + CollisionType_HeightMap = 1<<2, + CollisionType_Projectile = 1<<4, + CollisionType_Water = 1<<5 +}; + +} + +#endif diff --git a/apps/openmw/mwphysics/convert.hpp b/apps/openmw/mwphysics/convert.hpp new file mode 100644 index 000000000..c5075a2c3 --- /dev/null +++ b/apps/openmw/mwphysics/convert.hpp @@ -0,0 +1,35 @@ +#ifndef OPENMW_MWPHYSICS_CONVERT_H +#define OPENMW_MWPHYSICS_CONVERT_H + +#include +#include + +#include +#include + +namespace MWPhysics +{ + + inline btVector3 toBullet(const osg::Vec3f& vec) + { + return btVector3(vec.x(), vec.y(), vec.z()); + } + + inline btQuaternion toBullet(const osg::Quat& quat) + { + return btQuaternion(quat.x(), quat.y(), quat.z(), quat.w()); + } + + inline osg::Vec3f toOsg(const btVector3& vec) + { + return osg::Vec3f(vec.x(), vec.y(), vec.z()); + } + + inline osg::Quat toOsg(const btQuaternion& quat) + { + return osg::Quat(quat.x(), quat.y(), quat.z(), quat.w()); + } + +} + +#endif diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 8ae4fc853..6d429f3e5 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -3,15 +3,17 @@ #include #include +#include #include +#include #include #include #include -#include "../mwbase/world.hpp" // FIXME +#include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" #include "../mwmechanics/creaturestats.hpp" @@ -28,6 +30,11 @@ #include "../mwworld/class.hpp" +#include "collisiontype.hpp" +#include "actor.hpp" +#include "convert.hpp" +#include "trace.h" + namespace { @@ -89,16 +96,17 @@ namespace MWPhysics // Arbitrary number. To prevent infinite loops. They shouldn't happen but it's good to be prepared. static const int sMaxIterations = 8; + // FIXME: move to a separate file class MovementSolver { private: - static float getSlope(const Ogre::Vector3 &normal) + static float getSlope(const osg::Vec3f &normal) { - return normal.angleBetween(Ogre::Vector3(0.0f,0.0f,1.0f)).valueDegrees(); + return osg::RadiansToDegrees(std::acos(normal * osg::Vec3f(0.f, 0.f, 1.f))); } - static bool stepMove(btCollisionObject *colobj, Ogre::Vector3 &position, - const Ogre::Vector3 &toMove, float &remainingTime /*, OEngine::Physic::PhysicEngine *engine*/) + static bool stepMove(btCollisionObject *colobj, osg::Vec3f &position, + const osg::Vec3f &toMove, float &remainingTime, btDynamicsWorld* dynamicsWorld) { /* * Slide up an incline or set of stairs. Should be called only after a @@ -144,11 +152,9 @@ namespace MWPhysics * +--+ +-------- * ============================================== */ - return false; -#if 0 - OEngine::Physic::ActorTracer tracer, stepper; + ActorTracer tracer, stepper; - stepper.doTrace(colobj, position, position+Ogre::Vector3(0.0f,0.0f,sStepSizeUp), engine); + stepper.doTrace(colobj, position, position+osg::Vec3f(0.0f,0.0f,sStepSizeUp), dynamicsWorld); if(stepper.mFraction < std::numeric_limits::epsilon()) return false; // didn't even move the smallest representable amount // (TODO: shouldn't this be larger? Why bother with such a small amount?) @@ -166,7 +172,7 @@ namespace MWPhysics * +--+ * ============================================== */ - tracer.doTrace(colobj, stepper.mEndPos, stepper.mEndPos + toMove, engine); + tracer.doTrace(colobj, stepper.mEndPos, stepper.mEndPos + toMove, dynamicsWorld); if(tracer.mFraction < std::numeric_limits::epsilon()) return false; // didn't even move the smallest representable amount @@ -185,7 +191,7 @@ namespace MWPhysics * +--+ +--+ * ============================================== */ - stepper.doTrace(colobj, tracer.mEndPos, tracer.mEndPos-Ogre::Vector3(0.0f,0.0f,sStepSizeDown), engine); + stepper.doTrace(colobj, tracer.mEndPos, tracer.mEndPos-osg::Vec3f(0.0f,0.0f,sStepSizeDown), dynamicsWorld); if(stepper.mFraction < 1.0f && getSlope(stepper.mPlaneNormal) <= sMaxSlope) { // don't allow stepping up other actors @@ -201,41 +207,39 @@ namespace MWPhysics // moved between 0 and just under sStepSize distance but slope was too great, // or moved full sStepSize distance (FIXME: is this a bug?) -#endif return false; } ///Project a vector u on another vector v - static inline Ogre::Vector3 project(const Ogre::Vector3 u, const Ogre::Vector3 &v) + static inline osg::Vec3f project(const osg::Vec3f& u, const osg::Vec3f &v) { - return v * u.dotProduct(v); + return v * (u * v); + // ^ dot product } ///Helper for computing the character sliding - static inline Ogre::Vector3 slide(Ogre::Vector3 direction, const Ogre::Vector3 &planeNormal) + static inline osg::Vec3f slide(const osg::Vec3f& direction, const osg::Vec3f &planeNormal) { return direction - project(direction, planeNormal); } + static inline osg::Vec3f reflect(const osg::Vec3& velocity, const osg::Vec3f& normal) + { + return (normal * (normal * velocity)) * 2 - velocity; + } + public: - static Ogre::Vector3 traceDown(const MWWorld::Ptr &ptr, /*OEngine::Physic::PhysicEngine *engine,*/ float maxHeight) + static osg::Vec3f traceDown(const MWWorld::Ptr &ptr, Actor* actor, btDynamicsWorld* dynamicsWorld, float maxHeight) { - const ESM::Position &refpos = ptr.getRefData().getPosition(); - Ogre::Vector3 position(refpos.pos); - - return position; -#if 0 - OEngine::Physic::PhysicActor *physicActor = engine->getCharacter(ptr.getRefData().getHandle()); - if (!physicActor) - return position; + osg::Vec3f position(ptr.getRefData().getPosition().asVec3()); - OEngine::Physic::ActorTracer tracer; - tracer.findGround(physicActor, position, position-Ogre::Vector3(0,0,maxHeight), engine); + ActorTracer tracer; + tracer.findGround(actor, position, position-osg::Vec3f(0,0,maxHeight), dynamicsWorld); if(tracer.mFraction >= 1.0f) { - physicActor->setOnGround(false); + actor->setOnGround(false); return position; } else @@ -243,79 +247,73 @@ namespace MWPhysics // Check if we actually found a valid spawn point (use an infinitely thin ray this time). // Required for some broken door destinations in Morrowind.esm, where the spawn point // intersects with other geometry if the actor's base is taken into account - btVector3 from = BtOgre::Convert::toBullet(position); + btVector3 from = toBullet(position); btVector3 to = from - btVector3(0,0,maxHeight); btCollisionWorld::ClosestRayResultCallback resultCallback1(from, to); resultCallback1.m_collisionFilterGroup = 0xff; resultCallback1.m_collisionFilterMask = CollisionType_World|CollisionType_HeightMap; - engine->mDynamicsWorld->rayTest(from, to, resultCallback1); + dynamicsWorld->rayTest(from, to, resultCallback1); if (resultCallback1.hasHit() && - (BtOgre::Convert::toOgre(resultCallback1.m_hitPointWorld).distance(tracer.mEndPos) > 30 + ( (toOsg(resultCallback1.m_hitPointWorld) - tracer.mEndPos).length() > 30 || getSlope(tracer.mPlaneNormal) > sMaxSlope)) { - physicActor->setOnGround(getSlope(BtOgre::Convert::toOgre(resultCallback1.m_hitNormalWorld)) <= sMaxSlope); - return BtOgre::Convert::toOgre(resultCallback1.m_hitPointWorld) + Ogre::Vector3(0,0,1.f); + actor->setOnGround(getSlope(toOsg(resultCallback1.m_hitNormalWorld)) <= sMaxSlope); + return toOsg(resultCallback1.m_hitPointWorld) + osg::Vec3f(0.f, 0.f, 1.f); } - physicActor->setOnGround(getSlope(tracer.mPlaneNormal) <= sMaxSlope); + actor->setOnGround(getSlope(tracer.mPlaneNormal) <= sMaxSlope); return tracer.mEndPos; } -#endif } - static Ogre::Vector3 move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time, - bool isFlying, float waterlevel, float slowFall /*, OEngine::Physic::PhysicEngine *engine*/ + static osg::Vec3f move(const MWWorld::Ptr &ptr, Actor* physicActor, const osg::Vec3f &movement, float time, + bool isFlying, float waterlevel, float slowFall, btDynamicsWorld* dynamicsWorld , std::map& collisionTracker , std::map& standingCollisionTracker) { - const ESM::Position &refpos = ptr.getRefData().getPosition(); - Ogre::Vector3 position(refpos.pos); - return position; -#if 0 + const ESM::Position& refpos = ptr.getRefData().getPosition(); + osg::Vec3f position(refpos.asVec3()); + // Early-out for totally static creatures // (Not sure if gravity should still apply?) if (!ptr.getClass().isMobile(ptr)) return position; - OEngine::Physic::PhysicActor *physicActor = engine->getCharacter(ptr.getRefData().getHandle()); - if (!physicActor) - return position; - // Reset per-frame data physicActor->setWalkingOnWater(false); // Anything to collide with? if(!physicActor->getCollisionMode()) { - return position + (Ogre::Quaternion(Ogre::Radian(refpos.rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z) * - Ogre::Quaternion(Ogre::Radian(refpos.rot[0]), Ogre::Vector3::NEGATIVE_UNIT_X)) - * movement * time; + return position + (osg::Quat(refpos.rot[0], osg::Vec3f(-1, 0, 0)) * + osg::Quat(refpos.rot[2], osg::Vec3f(0, 0, -1)) + ) * movement * time; } - btCollisionObject *colobj = physicActor->getCollisionBody(); - Ogre::Vector3 halfExtents = physicActor->getHalfExtents(); - position.z += halfExtents.z; + btCollisionObject *colobj = physicActor->getCollisionObject(); + osg::Vec3f halfExtents = physicActor->getHalfExtents(); + position.z() += halfExtents.z(); static const float fSwimHeightScale = MWBase::Environment::get().getWorld()->getStore().get() .find("fSwimHeightScale")->getFloat(); - float swimlevel = waterlevel + halfExtents.z - (halfExtents.z * 2 * fSwimHeightScale); + float swimlevel = waterlevel + halfExtents.z() - (halfExtents.z() * 2 * fSwimHeightScale); - OEngine::Physic::ActorTracer tracer; - Ogre::Vector3 inertia = physicActor->getInertialForce(); - Ogre::Vector3 velocity; + ActorTracer tracer; + osg::Vec3f inertia = physicActor->getInertialForce(); + osg::Vec3f velocity; - if(position.z < swimlevel || isFlying) + if(position.z() < swimlevel || isFlying) { - velocity = (Ogre::Quaternion(Ogre::Radian(refpos.rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z)* - Ogre::Quaternion(Ogre::Radian(refpos.rot[0]), Ogre::Vector3::NEGATIVE_UNIT_X)) * movement; + velocity = (osg::Quat(refpos.rot[0], osg::Vec3f(-1, 0, 0)) * + osg::Quat(refpos.rot[2], osg::Vec3f(0, 0, -1))) * movement; } else { - velocity = Ogre::Quaternion(Ogre::Radian(refpos.rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z) * movement; + velocity = (osg::Quat(refpos.rot[2], osg::Vec3f(0, 0, -1))) * movement; - if (velocity.z > 0.f) + if (velocity.z() > 0.f) inertia = velocity; if(!physicActor->getOnGround()) { @@ -327,16 +325,16 @@ namespace MWPhysics // Now that we have the effective movement vector, apply wind forces to it if (MWBase::Environment::get().getWorld()->isInStorm()) { - Ogre::Vector3 stormDirection = MWBase::Environment::get().getWorld()->getStormDirection(); - Ogre::Degree angle = stormDirection.angleBetween(velocity); + osg::Vec3f stormDirection = MWBase::Environment::get().getWorld()->getStormDirection(); + float angleDegrees = osg::RadiansToDegrees(std::acos(stormDirection * velocity)); static const float fStromWalkMult = MWBase::Environment::get().getWorld()->getStore().get() .find("fStromWalkMult")->getFloat(); - velocity *= 1.f-(fStromWalkMult * (angle.valueDegrees()/180.f)); + velocity *= 1.f-(fStromWalkMult * (angleDegrees/180.f)); } - Ogre::Vector3 origVelocity = velocity; + osg::Vec3f origVelocity = velocity; - Ogre::Vector3 newPosition = position; + osg::Vec3f newPosition = position; /* * A loop to find newPosition using tracer, if successful different from the starting position. * nextpos is the local variable used to find potential newPosition, using velocity and remainingTime @@ -345,27 +343,27 @@ namespace MWPhysics float remainingTime = time; for(int iterations = 0; iterations < sMaxIterations && remainingTime > 0.01f; ++iterations) { - Ogre::Vector3 nextpos = newPosition + velocity * remainingTime; + osg::Vec3f nextpos = newPosition + velocity * remainingTime; // If not able to fly, don't allow to swim up into the air - if(newPosition.z < swimlevel && + if(newPosition.z() < swimlevel && !isFlying && // can't fly - nextpos.z > swimlevel && // but about to go above water - newPosition.z <= swimlevel) + nextpos.z() > swimlevel && // but about to go above water + newPosition.z() <= swimlevel) { - const Ogre::Vector3 down(0,0,-1); - Ogre::Real movelen = velocity.normalise(); - Ogre::Vector3 reflectdir = velocity.reflect(down); - reflectdir.normalise(); + const osg::Vec3f down(0,0,-1); + float movelen = velocity.normalize(); + osg::Vec3f reflectdir = reflect(velocity, down); + reflectdir.normalize(); velocity = slide(reflectdir, down)*movelen; // NOTE: remainingTime is unchanged before the loop continues continue; // velocity updated, calculate nextpos again } - if(newPosition.squaredDistance(nextpos) > 0.0001) + if((newPosition - nextpos).length2() > 0.0001) { // trace to where character would go if there were no obstructions - tracer.doTrace(colobj, newPosition, nextpos, engine); + tracer.doTrace(colobj, newPosition, nextpos, dynamicsWorld); // check for obstructions if(tracer.mFraction >= 1.0f) @@ -375,11 +373,13 @@ namespace MWPhysics } else { + /* const btCollisionObject* standingOn = tracer.mHitObject; if (const OEngine::Physic::RigidBody* body = dynamic_cast(standingOn)) { collisionTracker[ptr.getRefData().getHandle()] = body->mName; } + */ } } else @@ -395,62 +395,68 @@ namespace MWPhysics } - Ogre::Vector3 oldPosition = newPosition; + osg::Vec3f oldPosition = newPosition; // We hit something. Try to step up onto it. (NOTE: stepMove does not allow stepping over) // NOTE: stepMove modifies newPosition if successful - bool result = stepMove(colobj, newPosition, velocity*remainingTime, remainingTime, engine); + bool result = stepMove(colobj, newPosition, velocity*remainingTime, remainingTime, dynamicsWorld); if (!result) // to make sure the maximum stepping distance isn't framerate-dependent or movement-speed dependent - result = stepMove(colobj, newPosition, velocity.normalisedCopy()*10.f, remainingTime, engine); + { + osg::Vec3f normalizedVelocity = velocity; + normalizedVelocity.normalize(); + result = stepMove(colobj, newPosition, normalizedVelocity*10.f, remainingTime, dynamicsWorld); + } if(result) { // don't let pure water creatures move out of water after stepMove if (ptr.getClass().isPureWaterCreature(ptr) - && newPosition.z + halfExtents.z > waterlevel) + && newPosition.z() + halfExtents.z() > waterlevel) newPosition = oldPosition; } else { // Can't move this way, try to find another spot along the plane - Ogre::Vector3 direction = velocity; - Ogre::Real movelen = direction.normalise(); - Ogre::Vector3 reflectdir = velocity.reflect(tracer.mPlaneNormal); - reflectdir.normalise(); + osg::Vec3f direction = velocity; + float movelen = direction.normalize(); + osg::Vec3f reflectdir = reflect(velocity, tracer.mPlaneNormal); + reflectdir.normalize(); - Ogre::Vector3 newVelocity = slide(reflectdir, tracer.mPlaneNormal)*movelen; - if ((newVelocity-velocity).squaredLength() < 0.01) - break; - if (velocity.dotProduct(origVelocity) <= 0.f) + osg::Vec3f newVelocity = slide(reflectdir, tracer.mPlaneNormal)*movelen; + if ((newVelocity-velocity).length2() < 0.01) break; + if ((velocity * origVelocity) <= 0.f) + break; // ^ dot product velocity = newVelocity; // Do not allow sliding upward if there is gravity. Stepping will have taken // care of that. - if(!(newPosition.z < swimlevel || isFlying)) - velocity.z = std::min(velocity.z, 0.0f); + if(!(newPosition.z() < swimlevel || isFlying)) + velocity.z() = std::min(velocity.z(), 0.0f); } } bool isOnGround = false; - if (!(inertia.z > 0.f) && !(newPosition.z < swimlevel)) + if (!(inertia.z() > 0.f) && !(newPosition.z() < swimlevel)) { - Ogre::Vector3 from = newPosition; - Ogre::Vector3 to = newPosition - (physicActor->getOnGround() ? - Ogre::Vector3(0,0,sStepSizeDown+2.f) : Ogre::Vector3(0,0,2.f)); - tracer.doTrace(colobj, from, to, engine); + osg::Vec3f from = newPosition; + osg::Vec3f to = newPosition - (physicActor->getOnGround() ? + osg::Vec3f(0,0,sStepSizeDown+2.f) : osg::Vec3f(0,0,2.f)); + tracer.doTrace(colobj, from, to, dynamicsWorld); if(tracer.mFraction < 1.0f && getSlope(tracer.mPlaneNormal) <= sMaxSlope && tracer.mHitObject->getBroadphaseHandle()->m_collisionFilterGroup != CollisionType_Actor) { + /* const btCollisionObject* standingOn = tracer.mHitObject; + if (const OEngine::Physic::RigidBody* body = dynamic_cast(standingOn)) { standingCollisionTracker[ptr.getRefData().getHandle()] = body->mName; } if (standingOn->getBroadphaseHandle()->m_collisionFilterGroup == CollisionType_Water) physicActor->setWalkingOnWater(true); - + */ if (!isFlying) - newPosition.z = tracer.mEndPos.z + 1.0f; + newPosition.z() = tracer.mEndPos.z() + 1.0f; isOnGround = true; } @@ -461,13 +467,13 @@ namespace MWPhysics // so that we do not stay suspended in air indefinitely. if (tracer.mFraction < 1.0f && tracer.mHitObject->getBroadphaseHandle()->m_collisionFilterGroup == CollisionType_Actor) { - if (Ogre::Vector3(velocity.x, velocity.y, 0).squaredLength() < 100.f*100.f) + if (osg::Vec3f(velocity.x(), velocity.y(), 0).length2() < 100.f*100.f) { btVector3 aabbMin, aabbMax; tracer.mHitObject->getCollisionShape()->getAabb(tracer.mHitObject->getWorldTransform(), aabbMin, aabbMax); btVector3 center = (aabbMin + aabbMax) / 2.f; - inertia = Ogre::Vector3(position.x - center.x(), position.y - center.y(), 0); - inertia.normalise(); + inertia = osg::Vec3f(position.x() - center.x(), position.y() - center.y(), 0); + inertia.normalize(); inertia *= 100; } } @@ -476,20 +482,19 @@ namespace MWPhysics } } - if(isOnGround || newPosition.z < swimlevel || isFlying) - physicActor->setInertialForce(Ogre::Vector3(0.0f)); + if(isOnGround || newPosition.z() < swimlevel || isFlying) + physicActor->setInertialForce(osg::Vec3f(0.f, 0.f, 0.f)); else { - inertia.z += time * -627.2f; - if (inertia.z < 0) - inertia.z *= slowFall; + inertia.z() += time * -627.2f; + if (inertia.z() < 0) + inertia.z() *= slowFall; physicActor->setInertialForce(inertia); } physicActor->setOnGround(isOnGround); - newPosition.z -= halfExtents.z; // remove what was added at the beginning + newPosition.z() -= halfExtents.z(); // remove what was added at the beginning return newPosition; -#endif } }; @@ -543,11 +548,62 @@ namespace MWPhysics btCollisionObject* mCollisionObject; }; - // --------------------------------------------------------------- + // -------------------------------------------------------------- + + class Object : public PtrHolder + { + public: + Object(const MWWorld::Ptr& ptr, osg::ref_ptr shapeInstance) + : mShapeInstance(shapeInstance) + { + mPtr = ptr; + mCollisionObject.reset(new btCollisionObject); + mCollisionObject->setCollisionShape(shapeInstance->getCollisionShape()); + + mCollisionObject->setUserPointer(static_cast(this)); + + setScale(ptr.getCellRef().getScale()); + setRotation(toBullet(ptr.getRefData().getBaseNode()->getAttitude())); + const float* pos = ptr.getRefData().getPosition().pos; + setOrigin(btVector3(pos[0], pos[1], pos[2])); + } + + void updatePtr(const MWWorld::Ptr& updated) + { + mPtr = updated; + } - PhysicsSystem::PhysicsSystem(osg::ref_ptr parentNode) - : mTimeAccum(0.0f) + void setScale(float scale) + { + mShapeInstance->getCollisionShape()->setLocalScaling(btVector3(scale,scale,scale)); + } + + void setRotation(const btQuaternion& quat) + { + mCollisionObject->getWorldTransform().setRotation(quat); + } + + void setOrigin(const btVector3& vec) + { + mCollisionObject->getWorldTransform().setOrigin(vec); + } + + btCollisionObject* getCollisionObject() + { + return mCollisionObject.get(); + } + + private: + std::auto_ptr mCollisionObject; + osg::ref_ptr mShapeInstance; + }; + + // --------------------------------------------------------------- + + PhysicsSystem::PhysicsSystem(const VFS::Manager* vfs, osg::ref_ptr parentNode) + : mShapeManager(new NifBullet::BulletShapeManager(vfs)) + , mTimeAccum(0.0f) , mWaterEnabled(false) , mWaterHeight(0) , mDebugDrawEnabled(false) @@ -577,6 +633,17 @@ namespace MWPhysics delete it->second; } + for (ObjectMap::iterator it = mObjects.begin(); it != mObjects.end(); ++it) + { + mDynamicsWorld->removeCollisionObject(it->second->getCollisionObject()); + delete it->second; + } + + for (ActorMap::iterator it = mActors.begin(); it != mActors.end(); ++it) + { + delete it->second; + } + delete mDynamicsWorld; delete mSolver; delete mCollisionConfiguration; @@ -668,9 +735,13 @@ namespace MWPhysics return std::vector();//mEngine->getCollisions(ptr.getRefData().getBaseNodeOld()->getName(), collisionGroup, collisionMask); } - Ogre::Vector3 PhysicsSystem::traceDown(const MWWorld::Ptr &ptr, float maxHeight) + osg::Vec3f PhysicsSystem::traceDown(const MWWorld::Ptr &ptr, float maxHeight) { - return Ogre::Vector3();//MovementSolver::traceDown(ptr, mEngine, maxHeight); + ActorMap::iterator found = mActors.find(ptr); + if (found == mActors.end()) + return ptr.getRefData().getPosition().asVec3(); + else + return MovementSolver::traceDown(ptr, found->second, mDynamicsWorld, maxHeight); } void PhysicsSystem::addHeightField (float* heights, int x, int y, float triSize, float sqrtVerts) @@ -693,45 +764,115 @@ namespace MWPhysics } } - void PhysicsSystem::addObject (const MWWorld::Ptr& ptr, const std::string& mesh, bool placeable) + void PhysicsSystem::addObject (const MWWorld::Ptr& ptr, const std::string& mesh) + { + osg::ref_ptr shapeInstance = mShapeManager->createInstance(mesh); + if (!shapeInstance->getCollisionShape()) + return; + + Object *obj = new Object(ptr, shapeInstance); + mObjects.insert(std::make_pair(ptr, obj)); + + mDynamicsWorld->addCollisionObject(obj->getCollisionObject(), CollisionType_World, + CollisionType_Actor|CollisionType_HeightMap|CollisionType_Projectile); + } + + void PhysicsSystem::remove(const MWWorld::Ptr &ptr) + { + ObjectMap::iterator found = mObjects.find(ptr); + if (found != mObjects.end()) + { + mDynamicsWorld->removeCollisionObject(found->second->getCollisionObject()); + delete found->second; + mObjects.erase(found); + } + + ActorMap::iterator foundActor = mActors.find(ptr); + if (foundActor != mActors.end()) + { + delete foundActor->second; + mActors.erase(foundActor); + } + } + + void PhysicsSystem::updateScale(const MWWorld::Ptr &ptr) { + ObjectMap::iterator found = mObjects.find(ptr); + float scale = ptr.getCellRef().getScale(); + if (found != mObjects.end()) + { + found->second->setScale(scale); + mDynamicsWorld->updateSingleAabb(found->second->getCollisionObject()); + return; + } + ActorMap::iterator foundActor = mActors.find(ptr); + if (foundActor != mActors.end()) + { + foundActor->second->updateScale(); + // no aabb update needed (DISABLE_DEACTIVATION) + return; + } + } + + void PhysicsSystem::updateRotation(const MWWorld::Ptr &ptr) + { + ObjectMap::iterator found = mObjects.find(ptr); + if (found != mObjects.end()) + { + found->second->setRotation(toBullet(ptr.getRefData().getBaseNode()->getAttitude())); + mDynamicsWorld->updateSingleAabb(found->second->getCollisionObject()); + return; + } + ActorMap::iterator foundActor = mActors.find(ptr); + if (foundActor != mActors.end()) + { + foundActor->second->updateRotation(); + // no aabb update needed (DISABLE_DEACTIVATION) + return; + } + } + void PhysicsSystem::updatePosition(const MWWorld::Ptr &ptr) + { + ObjectMap::iterator found = mObjects.find(ptr); + if (found != mObjects.end()) + { + found->second->setOrigin(toBullet(ptr.getRefData().getPosition().asVec3())); + mDynamicsWorld->updateSingleAabb(found->second->getCollisionObject()); + return; + } + ActorMap::iterator foundActor = mActors.find(ptr); + if (foundActor != mActors.end()) + { + foundActor->second->updatePosition(); + // no aabb update needed (DISABLE_DEACTIVATION) + return; + } } void PhysicsSystem::addActor (const MWWorld::Ptr& ptr, const std::string& mesh) { + osg::ref_ptr shapeInstance = mShapeManager->createInstance(mesh); + Actor* actor = new Actor(ptr, shapeInstance, mDynamicsWorld); + mActors.insert(std::make_pair(ptr, actor)); } bool PhysicsSystem::toggleCollisionMode() { - /* - for(std::map::iterator it = mEngine->mActorMap.begin(); it != mEngine->mActorMap.end();++it) + ActorMap::iterator found = mActors.find(MWBase::Environment::get().getWorld()->getPlayerPtr()); + if (found != mActors.end()) { - if (it->first=="player") - { - OEngine::Physic::PhysicActor* act = it->second; - - bool cmode = act->getCollisionMode(); - if(cmode) - { - act->enableCollisionMode(false); - return false; - } - else - { - act->enableCollisionMode(true); - return true; - } - } + bool cmode = found->second->getCollisionMode(); + cmode = !cmode; + found->second->enableCollisionMode(cmode); + return cmode; } - throw std::logic_error ("can't find player"); - */ return false; } - void PhysicsSystem::queueObjectMovement(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement) + void PhysicsSystem::queueObjectMovement(const MWWorld::Ptr &ptr, const osg::Vec3f &movement) { PtrVelocityList::iterator iter = mMovementQueue.begin(); for(;iter != mMovementQueue.end();++iter) @@ -764,8 +905,6 @@ namespace MWPhysics mCollisions.clear(); mStandingCollisions.clear(); - /* - const MWBase::World *world = MWBase::Environment::get().getWorld(); PtrVelocityList::iterator iter = mMovementQueue.begin(); for(;iter != mMovementQueue.end();++iter) @@ -786,19 +925,20 @@ namespace MWPhysics Ogre::Vector3(iter->first.getRefData().getPosition().pos))) waterCollision = true; - OEngine::Physic::PhysicActor *physicActor = mEngine->getCharacter(iter->first.getRefData().getHandle()); - if (!physicActor) // actor was already removed from the scene + ActorMap::iterator foundActor = mActors.find(iter->first); + if (foundActor == mActors.end()) // actor was already removed from the scene continue; + Actor* physicActor = foundActor->second; physicActor->setCanWaterWalk(waterCollision); // Slow fall reduces fall speed by a factor of (effect magnitude / 200) float slowFall = 1.f - std::max(0.f, std::min(1.f, effects.get(ESM::MagicEffect::SlowFall).getMagnitude() * 0.005f)); - Ogre::Vector3 newpos = MovementSolver::move(iter->first, iter->second, mTimeAccum, + osg::Vec3f newpos = MovementSolver::move(iter->first, physicActor, iter->second, mTimeAccum, world->isFlying(iter->first), - waterlevel, slowFall, mEngine, mCollisions, mStandingCollisions); + waterlevel, slowFall, mDynamicsWorld, mCollisions, mStandingCollisions); - float heightDiff = newpos.z - oldHeight; + float heightDiff = newpos.z() - oldHeight; if (heightDiff < 0) iter->first.getClass().getCreatureStats(iter->first).addToFallHeight(-heightDiff); @@ -806,8 +946,6 @@ namespace MWPhysics mMovementResults.push_back(std::make_pair(iter->first, newpos)); } - */ - mTimeAccum = 0.0f; } mMovementQueue.clear(); diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index 4dbecdb7c..e6bfd7cd2 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -1,5 +1,5 @@ -#ifndef GAME_MWWORLD_PHYSICSSYSTEM_H -#define GAME_MWWORLD_PHYSICSSYSTEM_H +#ifndef OPENMW_MWPHYSICS_PHYSICSSYSTEM_H +#define OPENMW_MWPHYSICS_PHYSICSSYSTEM_H #include @@ -21,34 +21,48 @@ namespace MWRender class DebugDrawer; } +namespace NifBullet +{ + class BulletShapeManager; +} + +namespace VFS +{ + class Manager; +} + class btSequentialImpulseConstraintSolver; class btDiscreteDynamicsWorld; namespace MWPhysics { - typedef std::vector > PtrVelocityList; - - enum CollisionType { - CollisionType_World = 1<<0, - CollisionType_Actor = 1<<1, - CollisionType_HeightMap = 1<<2, - CollisionType_Projectile = 1<<4, - CollisionType_Water = 1<<5 - }; + typedef std::vector > PtrVelocityList; class HeightField; + class Object; + class Actor; class PhysicsSystem { public: - PhysicsSystem (osg::ref_ptr parentNode); + PhysicsSystem (const VFS::Manager* vfs, osg::ref_ptr parentNode); ~PhysicsSystem (); void enableWater(float height); void setWaterHeight(float height); void disableWater(); - void addObject (const MWWorld::Ptr& ptr, const std::string& mesh, bool placeable=false); + void addObject (const MWWorld::Ptr& ptr, const std::string& mesh); + + // Object or Actor + void remove (const MWWorld::Ptr& ptr); + + void updateScale (const MWWorld::Ptr& ptr); + void updateRotation (const MWWorld::Ptr& ptr); + void updatePosition (const MWWorld::Ptr& ptr); + + // TODO + //void updatePtr (const MWWorld::Ptr& old, const MWWorld::Ptr& updated); void addActor (const MWWorld::Ptr& ptr, const std::string& mesh); @@ -61,7 +75,7 @@ namespace MWPhysics void stepSimulation(float dt); std::vector getCollisions(const MWWorld::Ptr &ptr, int collisionGroup, int collisionMask); ///< get handles this object collides with - Ogre::Vector3 traceDown(const MWWorld::Ptr &ptr, float maxHeight); + osg::Vec3f traceDown(const MWWorld::Ptr &ptr, float maxHeight); std::pair getHitContact(const std::string &name, const Ogre::Vector3 &origin, @@ -76,7 +90,7 @@ namespace MWPhysics /// Queues velocity movement for a Ptr. If a Ptr is already queued, its velocity will /// be overwritten. Valid until the next call to applyQueuedMovement. - void queueObjectMovement(const MWWorld::Ptr &ptr, const Ogre::Vector3 &velocity); + void queueObjectMovement(const MWWorld::Ptr &ptr, const osg::Vec3f &velocity); /// Apply all queued movements, then clear the list. const PtrVelocityList& applyQueuedMovement(float dt); @@ -111,6 +125,14 @@ namespace MWPhysics btCollisionDispatcher* mDispatcher; btDiscreteDynamicsWorld* mDynamicsWorld; + std::auto_ptr mShapeManager; + + typedef std::map ObjectMap; + ObjectMap mObjects; + + typedef std::map ActorMap; + ActorMap mActors; + typedef std::map, HeightField*> HeightFieldMap; HeightFieldMap mHeightFields; @@ -121,9 +143,9 @@ namespace MWPhysics // Tracks all movement collisions happening during a single frame. // This will detect e.g. running against a vertical wall. It will not detect climbing up stairs, // stepping up small objects, etc. - std::map mCollisions; + std::map mCollisions; // FIXME: reimplement - std::map mStandingCollisions; + std::map mStandingCollisions; // FIXME: reimplement PtrVelocityList mMovementQueue; PtrVelocityList mMovementResults; diff --git a/apps/openmw/mwphysics/trace.cpp b/apps/openmw/mwphysics/trace.cpp new file mode 100644 index 000000000..ddb984821 --- /dev/null +++ b/apps/openmw/mwphysics/trace.cpp @@ -0,0 +1,128 @@ +#include "trace.h" + +#include + +#include +#include + +#include "collisiontype.hpp" +#include "actor.hpp" +#include "convert.hpp" + +namespace MWPhysics +{ + +class ClosestNotMeConvexResultCallback : public btCollisionWorld::ClosestConvexResultCallback +{ +public: + ClosestNotMeConvexResultCallback(btCollisionObject *me, const btVector3 &up, btScalar minSlopeDot) + : btCollisionWorld::ClosestConvexResultCallback(btVector3(0.0, 0.0, 0.0), btVector3(0.0, 0.0, 0.0)), + mMe(me), mUp(up), mMinSlopeDot(minSlopeDot) + { + } + + virtual btScalar addSingleResult(btCollisionWorld::LocalConvexResult& convexResult,bool normalInWorldSpace) + { + if(convexResult.m_hitCollisionObject == mMe) + return btScalar( 1 ); + + btVector3 hitNormalWorld; + if(normalInWorldSpace) + hitNormalWorld = convexResult.m_hitNormalLocal; + else + { + ///need to transform normal into worldspace + hitNormalWorld = convexResult.m_hitCollisionObject->getWorldTransform().getBasis()*convexResult.m_hitNormalLocal; + } + + btScalar dotUp = mUp.dot(hitNormalWorld); + if(dotUp < mMinSlopeDot) + return btScalar(1); + + return ClosestConvexResultCallback::addSingleResult(convexResult, normalInWorldSpace); + } + +protected: + btCollisionObject *mMe; + const btVector3 mUp; + const btScalar mMinSlopeDot; +}; + + +void ActorTracer::doTrace(btCollisionObject *actor, const osg::Vec3f& start, const osg::Vec3f& end, btDynamicsWorld* world) +{ + const btVector3 btstart = toBullet(start); + const btVector3 btend = toBullet(end); + + const btTransform &trans = actor->getWorldTransform(); + btTransform from(trans); + btTransform to(trans); + from.setOrigin(btstart); + to.setOrigin(btend); + + ClosestNotMeConvexResultCallback newTraceCallback(actor, btstart-btend, btScalar(0.0)); + // Inherit the actor's collision group and mask + newTraceCallback.m_collisionFilterGroup = actor->getBroadphaseHandle()->m_collisionFilterGroup; + newTraceCallback.m_collisionFilterMask = actor->getBroadphaseHandle()->m_collisionFilterMask; + + btCollisionShape *shape = actor->getCollisionShape(); + assert(shape->isConvex()); + world->convexSweepTest(static_cast(shape), + from, to, newTraceCallback); + + // Copy the hit data over to our trace results struct: + if(newTraceCallback.hasHit()) + { + const btVector3& tracehitnormal = newTraceCallback.m_hitNormalWorld; + mFraction = newTraceCallback.m_closestHitFraction; + mPlaneNormal = osg::Vec3f(tracehitnormal.x(), tracehitnormal.y(), tracehitnormal.z()); + mEndPos = (end-start)*mFraction + start; + mHitObject = newTraceCallback.m_hitCollisionObject; + } + else + { + mEndPos = end; + mPlaneNormal = osg::Vec3f(0.0f, 0.0f, 1.0f); + mFraction = 1.0f; + mHitObject = NULL; + } +} + +void ActorTracer::findGround(const Actor* actor, const osg::Vec3f& start, const osg::Vec3f& end, btDynamicsWorld* world) +{ + const btVector3 btstart(start.x(), start.y(), start.z()+1.0f); + const btVector3 btend(end.x(), end.y(), end.z()+1.0f); + + const btTransform &trans = actor->getCollisionObject()->getWorldTransform(); + btTransform from(trans.getBasis(), btstart); + btTransform to(trans.getBasis(), btend); + + ClosestNotMeConvexResultCallback newTraceCallback(actor->getCollisionObject(), btstart-btend, btScalar(0.0)); + // Inherit the actor's collision group and mask + newTraceCallback.m_collisionFilterGroup = actor->getCollisionObject()->getBroadphaseHandle()->m_collisionFilterGroup; + newTraceCallback.m_collisionFilterMask = actor->getCollisionObject()->getBroadphaseHandle()->m_collisionFilterMask; + newTraceCallback.m_collisionFilterMask &= ~CollisionType_Actor; + + btVector3 halfExtents = toBullet(actor->getHalfExtents()); + + halfExtents[2] = 1.0f; + btCylinderShapeZ base(halfExtents); + + world->convexSweepTest(&base, from, to, newTraceCallback); + if(newTraceCallback.hasHit()) + { + const btVector3& tracehitnormal = newTraceCallback.m_hitNormalWorld; + mFraction = newTraceCallback.m_closestHitFraction; + mPlaneNormal = osg::Vec3f(tracehitnormal.x(), tracehitnormal.y(), tracehitnormal.z()); + mEndPos = (end-start)*mFraction + start; + mEndPos[2] += 1.0f; + } + else + { + mEndPos = end; + mPlaneNormal = osg::Vec3f(0.0f, 0.0f, 1.0f); + mFraction = 1.0f; + } +} + +} diff --git a/apps/openmw/mwphysics/trace.h b/apps/openmw/mwphysics/trace.h new file mode 100644 index 000000000..02f9ebdd1 --- /dev/null +++ b/apps/openmw/mwphysics/trace.h @@ -0,0 +1,27 @@ +#ifndef OENGINE_BULLET_TRACE_H +#define OENGINE_BULLET_TRACE_H + +#include + +class btCollisionObject; +class btDynamicsWorld; + + +namespace MWPhysics +{ + class Actor; + + struct ActorTracer + { + osg::Vec3f mEndPos; + osg::Vec3f mPlaneNormal; + const btCollisionObject* mHitObject; + + float mFraction; + + void doTrace(btCollisionObject *actor, const osg::Vec3f& start, const osg::Vec3f& end, btDynamicsWorld* world); + void findGround(const Actor* actor, const osg::Vec3f& start, const osg::Vec3f& end, btDynamicsWorld* world); + }; +} + +#endif diff --git a/apps/openmw/mwscript/aiextensions.cpp b/apps/openmw/mwscript/aiextensions.cpp index f0cb8a967..4a7952c44 100644 --- a/apps/openmw/mwscript/aiextensions.cpp +++ b/apps/openmw/mwscript/aiextensions.cpp @@ -425,7 +425,7 @@ namespace MWScript MWWorld::Ptr targetPtr; if (creatureStats.getAiSequence().getCombatTarget (targetPtr)) { - if (targetPtr.getRefData().getHandle() == testedTargetId) + if (targetPtr.getCellRef().getRefId() == testedTargetId) targetsAreEqual = true; } runtime.push(int(targetsAreEqual)); diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index ce74c0c9f..9fe23ff14 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -811,10 +811,10 @@ namespace MWScript const std::string script = ptr.getClass().getScript(ptr); if(script.empty()) - str<< ptr.getCellRef().getRefId()<<" ("<getLocals(script); diff --git a/apps/openmw/mwworld/cellfunctors.hpp b/apps/openmw/mwworld/cellfunctors.hpp index cf6f7bf56..c7fdc793c 100644 --- a/apps/openmw/mwworld/cellfunctors.hpp +++ b/apps/openmw/mwworld/cellfunctors.hpp @@ -6,25 +6,21 @@ #include "ptr.hpp" -namespace ESM -{ - class CellRef; -} namespace MWWorld { - /// List all (Ogre-)handles, then reset RefData::mBaseNode to 0. - struct ListAndResetHandles + struct ListAndResetObjects { - std::vector mHandles; + std::vector mObjects; bool operator() (MWWorld::Ptr ptr) { - Ogre::SceneNode* handle = ptr.getRefData().getBaseNodeOld(); - if (handle) - mHandles.push_back (handle); + if (ptr.getRefData().getBaseNode()) + { + ptr.getRefData().setBaseNode(NULL); + mObjects.push_back (ptr); + } - ptr.getRefData().setBaseNodeOld(0); return true; } }; diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 6a994f0cd..81e240698 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -60,7 +60,7 @@ namespace rot = rot * osg::Quat(y, osg::Vec3(0,-1,0)) * osg::Quat(x, osg::Vec3(-1,0,0)); rendering.rotateObject(ptr, rot * worldRotQuat); - //physics.rotateObject(ptr); + physics.updateRotation(ptr); } } @@ -190,14 +190,13 @@ namespace MWWorld void Scene::unloadCell (CellStoreCollection::iterator iter) { std::cout << "Unloading cell\n"; - ListAndResetHandles functor; + ListAndResetObjects functor; - (*iter)->forEach(functor); - for (std::vector::const_iterator iter2 (functor.mHandles.begin()); - iter2!=functor.mHandles.end(); ++iter2) + (*iter)->forEach(functor); + for (std::vector::const_iterator iter2 (functor.mObjects.begin()); + iter2!=functor.mObjects.end(); ++iter2) { - //Ogre::SceneNode* node = *iter2; - //mPhysics->removeObject (node->getName()); + mPhysics->remove(*iter2); } if ((*iter)->getCell()->isExterior()) @@ -258,17 +257,16 @@ namespace MWWorld insertCell (*cell, true, loadingListener); mRendering.addCell(cell); -#if 0 bool waterEnabled = cell->getCell()->hasWater(); - mRendering.setWaterEnabled(waterEnabled); + //mRendering.setWaterEnabled(waterEnabled); if (waterEnabled) { mPhysics->enableWater(cell->getWaterLevel()); - mRendering.setWaterHeight(cell->getWaterLevel()); + //mRendering.setWaterHeight(cell->getWaterLevel()); } else mPhysics->disableWater(); -#endif + if (!cell->isExterior() && !(cell->getCell()->mData.mFlags & ESM::Cell::QuasiEx)) mRendering.configureAmbient(cell->getCell()); } @@ -564,8 +562,8 @@ namespace MWWorld { MWBase::Environment::get().getMechanicsManager()->remove (ptr); MWBase::Environment::get().getSoundManager()->stopSound3D (ptr); - //mPhysics->removeObject (ptr.getRefData().getHandle()); - //mRendering.removeObject (ptr); + mPhysics->remove(ptr); + //Rendering.removeObject (ptr); } bool Scene::isCellActive(const CellStore &cell) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index b9d16993f..b37a38353 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -415,11 +415,11 @@ void WeatherManager::update(float duration, bool paused) if (mIsStorm) { MWWorld::Ptr player = world->getPlayerPtr(); - Ogre::Vector3 playerPos (player.getRefData().getPosition().pos); - Ogre::Vector3 redMountainPos (19950, 72032, 27831); + osg::Vec3f playerPos (player.getRefData().getPosition().asVec3()); + osg::Vec3f redMountainPos (19950, 72032, 27831); mStormDirection = (playerPos - redMountainPos); - mStormDirection.z = 0; + mStormDirection.z() = 0; //mRendering->getSkyManager()->setStormDirection(mStormDirection); } @@ -844,7 +844,7 @@ bool WeatherManager::isInStorm() const return mIsStorm; } -Ogre::Vector3 WeatherManager::getStormDirection() const +osg::Vec3f WeatherManager::getStormDirection() const { return mStormDirection; } diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index 002f4355c..77d961057 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -184,7 +184,7 @@ namespace MWWorld /// Are we in an ash or blight storm? bool isInStorm() const; - Ogre::Vector3 getStormDirection() const; + osg::Vec3f getStormDirection() const; void advanceTime(double hours); @@ -205,7 +205,7 @@ namespace MWWorld float mHour; float mWindSpeed; bool mIsStorm; - Ogre::Vector3 mStormDirection; + osg::Vec3f mStormDirection; MWBase::SoundPtr mAmbientSound; std::string mPlayingSoundID; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 72423f476..add8d0373 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -7,8 +7,6 @@ #else #include #endif -#include "../mwbase/scriptmanager.hpp" -#include "../mwscript/globalscripts.hpp" #include #include @@ -19,6 +17,7 @@ #include #include #include +#include #include @@ -26,6 +25,7 @@ #include "../mwbase/soundmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwbase/scriptmanager.hpp" #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/movement.hpp" @@ -39,9 +39,12 @@ #include "../mwrender/renderingmanager.hpp" #include "../mwscript/interpretercontext.hpp" +#include "../mwscript/globalscripts.hpp" #include "../mwclass/door.hpp" +#include "../mwphysics/physicssystem.hpp" + #include "player.hpp" #include "manualref.hpp" #include "cellstore.hpp" @@ -51,7 +54,6 @@ #include "actionteleport.hpp" //#include "projectilemanager.hpp" #include "weather.hpp" -#include "../mwphysics/physicssystem.hpp" #include "contentloader.hpp" #include "esmloader.hpp" @@ -156,7 +158,7 @@ namespace MWWorld mStartCell (startCell), mStartupScript(startupScript), mScriptsEnabled(true) { - mPhysics = new MWPhysics::PhysicsSystem(rootNode); + mPhysics = new MWPhysics::PhysicsSystem(resourceSystem->getVFS(), rootNode); //mPhysEngine = mPhysics->getEngine(); #if 0 mProjectileManager.reset(new ProjectileManager(renderer.getScene(), *mPhysEngine)); @@ -1216,7 +1218,7 @@ namespace MWWorld if (haveToMove && ptr.getRefData().getBaseNode()) { mRendering->moveObject(ptr, osg::Vec3f(vec.x, vec.y, vec.z)); - //mPhysics->moveObject (ptr); + mPhysics->updatePosition(ptr); } if (isPlayer) { @@ -1343,9 +1345,9 @@ namespace MWWorld if (force || !isFlying(ptr)) { - //Ogre::Vector3 traced = mPhysics->traceDown(ptr, 500); - //if (traced.z < pos.pos[2]) - // pos.pos[2] = traced.z; + osg::Vec3f traced = mPhysics->traceDown(ptr, 500); + if (traced.z() < pos.pos[2]) + pos.pos[2] = traced.z(); } moveObject(ptr, ptr.getCell(), pos.pos[0], pos.pos[1], pos.pos[2]); @@ -1358,8 +1360,8 @@ namespace MWWorld pos.pos[2] += dist; actor.getRefData().setPosition(pos); - Ogre::Vector3 traced;// = mPhysics->traceDown(actor, dist*1.1f); - moveObject(actor, actor.getCell(), traced.x, traced.y, traced.z); + osg::Vec3f traced = mPhysics->traceDown(actor, dist*1.1f); + moveObject(actor, actor.getCell(), traced.x(), traced.y(), traced.z()); } void World::rotateObject (const Ptr& ptr,float x,float y,float z, bool adjust) @@ -1397,34 +1399,32 @@ namespace MWWorld cellY = static_cast(std::floor(y / cellSize)); } - void World::queueMovement(const Ptr &ptr, const Ogre::Vector3 &velocity) + void World::queueMovement(const Ptr &ptr, const osg::Vec3f &velocity) { - //mPhysics->queueObjectMovement(ptr, velocity); + mPhysics->queueObjectMovement(ptr, velocity); } void World::doPhysics(float duration) { mPhysics->stepSimulation(duration); -#if 0 processDoors(duration); - mProjectileManager->update(duration); + //mProjectileManager->update(duration); - const PtrVelocityList &results = mPhysics->applyQueuedMovement(duration); - PtrVelocityList::const_iterator player(results.end()); - for(PtrVelocityList::const_iterator iter(results.begin());iter != results.end();++iter) + const MWPhysics::PtrVelocityList &results = mPhysics->applyQueuedMovement(duration); + MWPhysics::PtrVelocityList::const_iterator player(results.end()); + for(MWPhysics::PtrVelocityList::const_iterator iter(results.begin());iter != results.end();++iter) { if(iter->first == getPlayerPtr()) { - /* Handle player last, in case a cell transition occurs */ + // Handle player last, in case a cell transition occurs player = iter; continue; } - moveObjectImp(iter->first, iter->second.x, iter->second.y, iter->second.z); + moveObjectImp(iter->first, iter->second.x(), iter->second.y(), iter->second.z()); } if(player != results.end()) - moveObjectImp(player->first, player->second.x, player->second.y, player->second.z); -#endif + moveObjectImp(player->first, player->second.x(), player->second.y(), player->second.z()); } bool World::castRay (float x1, float y1, float z1, float x2, float y2, float z2) @@ -2312,12 +2312,12 @@ namespace MWWorld return false; } - Ogre::Vector3 World::getStormDirection() const + osg::Vec3f World::getStormDirection() const { if (isCellExterior() || isCellQuasiExterior()) return mWeatherManager->getStormDirection(); else - return Ogre::Vector3(0,1,0); + return osg::Vec3f(0,1,0); } void World::getContainersOwnedBy (const MWWorld::Ptr& npc, std::vector& out) diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index efb9b88c6..a7830da3a 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -380,7 +380,7 @@ namespace MWWorld virtual void positionToIndex (float x, float y, int &cellX, int &cellY) const; ///< Convert position to cell numbers - virtual void queueMovement(const Ptr &ptr, const Ogre::Vector3 &velocity); + virtual void queueMovement(const Ptr &ptr, const osg::Vec3f &velocity); ///< Queues movement for \a ptr (in local space), to be applied in the next call to /// doPhysics. @@ -650,7 +650,7 @@ namespace MWWorld virtual bool isInStorm() const; /// @see MWWorld::WeatherManager::getStormDirection - virtual Ogre::Vector3 getStormDirection() const; + virtual osg::Vec3f getStormDirection() const; /// Resets all actors in the current active cells to their original location within that cell. virtual void resetActors(); diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 417164f2d..ef32e10dc 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -52,9 +52,9 @@ add_component_dir (nifosg nifloader controller particle userdata ) -#add_component_dir (nifbullet -# bulletnifloader -# ) +add_component_dir (nifbullet + bulletnifloader bulletshapemanager + ) add_component_dir (to_utf8 to_utf8 @@ -171,6 +171,7 @@ target_link_libraries(components ${Boost_LIBRARIES} ${OGRE_LIBRARIES} ${OPENSCENEGRAPH_LIBRARIES} + ${BULLET_LIBRARIES} # For MyGUI platform ${OPENGL_gl_LIBRARY} ) diff --git a/components/nifbullet/bulletnifloader.cpp b/components/nifbullet/bulletnifloader.cpp index b80bbb83f..62f2d94d8 100644 --- a/components/nifbullet/bulletnifloader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -1,31 +1,11 @@ - /* -OpenMW - The completely unofficial reimplementation of Morrowind -Copyright (C) 2008-2010 Nicolay Korslund -Email: < korslund@gmail.com > -WWW: http://openmw.sourceforge.net/ - -This file (ogre_nif_loader.cpp) is part of the OpenMW package. - -OpenMW is distributed as free software: you can redistribute it -and/or modify it under the terms of the GNU General Public License -version 3, as published by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -General Public License for more details. - -You should have received a copy of the GNU General Public License -version 3 along with this program. If not, see -http://www.gnu.org/licenses/ . - -*/ - #include "bulletnifloader.hpp" #include +#include +#include +#include +#include -#include #include #include "../nif/niffile.hpp" @@ -34,12 +14,7 @@ http://www.gnu.org/licenses/ . #include "../nif/property.hpp" #include "../nif/controller.hpp" #include "../nif/extra.hpp" -#include -#include -#include -// For warning messages -#include namespace { @@ -51,53 +26,40 @@ osg::Matrixf getWorldTransform(const Nif::Node *node) return node->trafo.toMatrix(); } +btVector3 getbtVector(const osg::Vec3f &v) +{ + return btVector3(v.x(), v.y(), v.z()); +} + } namespace NifBullet { -ManualBulletShapeLoader::~ManualBulletShapeLoader() +BulletNifLoader::BulletNifLoader() + : mCompoundShape(NULL) + , mStaticMesh(NULL) { } - -btVector3 ManualBulletShapeLoader::getbtVector(Ogre::Vector3 const &v) +BulletNifLoader::~BulletNifLoader() { - return btVector3(v[0], v[1], v[2]); } -void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource) +osg::ref_ptr BulletNifLoader::load(const Nif::NIFFilePtr nif) { - mShape = static_cast(resource); - mResourceName = mShape->getName(); - mBoundingBox = NULL; - mShape->mBoxTranslation = osg::Vec3f(0,0,0); - mShape->mBoxRotation = osg::Quat(); + mShape = new BulletShape; + mCompoundShape = NULL; mStaticMesh = NULL; - Nif::NIFFilePtr pnif;// (Nif::Cache::getInstance().load(mResourceName.substr(0, mResourceName.length()-7))); - Nif::NIFFile & nif = *pnif.get (); - if (nif.numRoots() < 1) + if (nif->numRoots() < 1) { warn("Found no root nodes in NIF."); - return; - } - - // Have to load controlled nodes from the .kf - // FIXME: the .kf has to be loaded both for rendering and physics, ideally it should be opened once and then reused - mControlledNodes.clear(); - std::string kfname = mResourceName.substr(0, mResourceName.length()-7); - Misc::StringUtils::toLower(kfname); - if(kfname.size() > 4 && kfname.compare(kfname.size()-4, 4, ".nif") == 0) - kfname.replace(kfname.size()-4, 4, ".kf"); - if (Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(kfname)) - { - Nif::NIFFilePtr kf;// (Nif::Cache::getInstance().load(kfname)); - //extractControlledNodes(kf, mControlledNodes); + return mShape; } - Nif::Record *r = nif.getRoot(0); + Nif::Record *r = nif->getRoot(0); assert(r != NULL); Nif::Node *node = dynamic_cast(r); @@ -105,29 +67,40 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource) { warn("First root in file was not a node, but a " + r->recName + ". Skipping file."); - return; + return mShape; } - mShape->mAutogenerated = hasAutoGeneratedCollision(node); + if (findBoundingBox(node)) + { + std::auto_ptr compound (new btCompoundShape); - //do a first pass - handleNode(node,0,false,false); + btBoxShape* boxShape = new btBoxShape(getbtVector(mShape->mCollisionBoxHalfExtents)); + btTransform transform = btTransform::getIdentity(); + transform.setOrigin(getbtVector(mShape->mCollisionBoxTranslate)); + compound->addChildShape(transform, boxShape); - if(mBoundingBox != NULL) - { - mShape->mCollisionShape = mBoundingBox; - delete mStaticMesh; - if (mCompoundShape) - { - int n = mCompoundShape->getNumChildShapes(); - for(int i=0; i getChildShape(i)); - delete mCompoundShape; - mShape->mAnimatedShapes.clear(); - } + mShape->mCollisionShape = compound.release(); + return mShape; } else { + /* + // Have to load controlled nodes from the .kf + mControlledNodes.clear(); + std::string kfname = mResourceName.substr(0, mResourceName.length()-7); + Misc::StringUtils::toLower(kfname); + if(kfname.size() > 4 && kfname.compare(kfname.size()-4, 4, ".nif") == 0) + kfname.replace(kfname.size()-4, 4, ".kf"); + if (Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(kfname)) + { + Nif::NIFFilePtr kf;// (Nif::Cache::getInstance().load(kfname)); + //extractControlledNodes(kf, mControlledNodes); + } + */ + + bool autogenerated = hasAutoGeneratedCollision(node); + handleNode(node, 0, autogenerated, false, autogenerated); + if (mCompoundShape) { mShape->mCollisionShape = mCompoundShape; @@ -140,10 +113,46 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource) } else if (mStaticMesh) mShape->mCollisionShape = new TriangleMeshShape(mStaticMesh,true); + + return mShape; } } -bool ManualBulletShapeLoader::hasAutoGeneratedCollision(Nif::Node const * rootNode) +// Find a boundingBox in the node hierarchy. +// Return: use bounding box for collision? +bool BulletNifLoader::findBoundingBox(const Nif::Node* node, int flags) +{ + flags |= node->flags; + + if (node->hasBounds) + { + mShape->mCollisionBoxHalfExtents = node->boundXYZ; + mShape->mCollisionBoxTranslate = node->boundPos; + + if (flags & Nif::NiNode::Flag_BBoxCollision) + { + return true; + } + } + + const Nif::NiNode *ninode = dynamic_cast(node); + if(ninode) + { + const Nif::NodeList &list = ninode->children; + for(size_t i = 0;i < list.length();i++) + { + if(!list[i].empty()) + { + bool found = findBoundingBox (list[i].getPtr()); + if (found) + return true; + } + } + } + return false; +} + +bool BulletNifLoader::hasAutoGeneratedCollision(const Nif::Node* rootNode) { const Nif::NiNode *ninode = dynamic_cast(rootNode); if(ninode) @@ -161,8 +170,8 @@ bool ManualBulletShapeLoader::hasAutoGeneratedCollision(Nif::Node const * rootNo return true; } -void ManualBulletShapeLoader::handleNode(const Nif::Node *node, int flags, - bool isCollisionNode, bool isAnimated) +void BulletNifLoader::handleNode(const Nif::Node *node, int flags, + bool isCollisionNode, bool isAnimated, bool autogenerated) { // Accumulate the flags from all the child nodes. This works for all // the flags we currently use, at least. @@ -201,24 +210,21 @@ void ManualBulletShapeLoader::handleNode(const Nif::Node *node, int flags, // No collision. Use an internal flag setting to mark this. flags |= 0x800; } + else if (sd->string == "MRK" && autogenerated) + { + // Marker can still have collision if the model explicitely specifies it via a RootCollisionNode. + return; + } + } } - if (isCollisionNode || (mShape->mAutogenerated)) + if (isCollisionNode) { // NOTE: a trishape with hasBounds=true, but no BBoxCollision flag should NOT go through handleNiTriShape! // It must be ignored completely. // (occurs in tr_ex_imp_wall_arch_04.nif) - if(node->hasBounds) - { - if (flags & Nif::NiNode::Flag_BBoxCollision) - { - mShape->mBoxTranslation = node->boundPos; - //mShape->mBoxRotation = node->boundRot; - //mBoundingBox = new btBoxShape(getbtVector(node->boundXYZ)); - } - } - else if(node->recType == Nif::RC_NiTriShape) + if(!node->hasBounds && node->recType == Nif::RC_NiTriShape) { handleNiTriShape(static_cast(node), flags, getWorldTransform(node), isAnimated); } @@ -237,7 +243,7 @@ void ManualBulletShapeLoader::handleNode(const Nif::Node *node, int flags, } } -void ManualBulletShapeLoader::handleNiTriShape(const Nif::NiTriShape *shape, int flags, const osg::Matrixf &transform, bool isAnimated) +void BulletNifLoader::handleNiTriShape(const Nif::NiTriShape *shape, int flags, const osg::Matrixf &transform, bool isAnimated) { assert(shape != NULL); @@ -261,6 +267,7 @@ void ManualBulletShapeLoader::handleNiTriShape(const Nif::NiTriShape *shape, int if (!shape->skin.empty()) isAnimated = false; + /* if (isAnimated) { if (!mCompoundShape) @@ -281,7 +288,7 @@ void ManualBulletShapeLoader::handleNiTriShape(const Nif::NiTriShape *shape, int osg::Vec3f b1 = vertices[triangles[i+0]]; osg::Vec3f b2 = vertices[triangles[i+1]]; osg::Vec3f b3 = vertices[triangles[i+2]]; - childMesh->addTriangle(btVector3(b1.x(),b1.y(),b1.z()),btVector3(b2.x(),b2.y(),b2.z()),btVector3(b3.x(),b3.y(),b3.z())); + childMesh->addTriangle(getbtVector(b1), getbtVector(b2), getbtVector(b3)); } TriangleMeshShape* childShape = new TriangleMeshShape(childMesh,true); @@ -304,9 +311,10 @@ void ManualBulletShapeLoader::handleNiTriShape(const Nif::NiTriShape *shape, int mCompoundShape->addChildShape(trans, childShape); } else + */ { if (!mStaticMesh) - mStaticMesh = new btTriangleMesh(); + mStaticMesh = new btTriangleMesh(false); // Static shape, just transform all vertices into position const Nif::NiTriShapeData *data = shape->data.getPtr(); @@ -315,61 +323,99 @@ void ManualBulletShapeLoader::handleNiTriShape(const Nif::NiTriShape *shape, int for(size_t i = 0;i < data->triangles.size();i+=3) { - osg::Vec3f b1 = transform*vertices[triangles[i+0]]; - osg::Vec3f b2 = transform*vertices[triangles[i+1]]; - osg::Vec3f b3 = transform*vertices[triangles[i+2]]; - mStaticMesh->addTriangle(btVector3(b1.x(),b1.y(),b1.z()),btVector3(b2.x(),b2.y(),b2.z()),btVector3(b3.x(),b3.y(),b3.z())); + osg::Vec3f b1 = vertices[triangles[i+0]]*transform; + osg::Vec3f b2 = vertices[triangles[i+1]]*transform; + osg::Vec3f b3 = vertices[triangles[i+2]]*transform; + mStaticMesh->addTriangle(getbtVector(b1), getbtVector(b2), getbtVector(b3)); } } } -bool findBoundingBox (const Nif::Node* node, Ogre::Vector3& halfExtents, Ogre::Vector3& translation, Ogre::Quaternion& orientation) +BulletShape::BulletShape() + : mCollisionShape(NULL) { - if(node->hasBounds) + +} + +BulletShape::~BulletShape() +{ + deleteShape(mCollisionShape); +} + +void BulletShape::deleteShape(btCollisionShape* shape) +{ + if(shape!=NULL) { - if (!(node->flags & Nif::NiNode::Flag_Hidden)) + if(shape->isCompound()) { - //translation = node->boundPos; - //orientation = node->boundRot; - //halfExtents = node->boundXYZ; - return true; + btCompoundShape* ms = static_cast(shape); + int a = ms->getNumChildShapes(); + for(int i=0; i getChildShape(i)); } + delete shape; } +} - const Nif::NiNode *ninode = dynamic_cast(node); - if(ninode) +btCollisionShape* BulletShape::duplicateCollisionShape(btCollisionShape *shape) const +{ + if(shape->isCompound()) { - const Nif::NodeList &list = ninode->children; - for(size_t i = 0;i < list.length();i++) + btCompoundShape *comp = static_cast(shape); + btCompoundShape *newShape = new btCompoundShape; + + int numShapes = comp->getNumChildShapes(); + for(int i = 0;i < numShapes;++i) { - if(!list[i].empty()) - if (findBoundingBox(list[i].getPtr(), halfExtents, translation, orientation)) - return true; + btCollisionShape *child = duplicateCollisionShape(comp->getChildShape(i)); + btTransform trans = comp->getChildTransform(i); + newShape->addChildShape(trans, child); } - } - return false; -} -bool getBoundingBox(const std::string& nifFile, Ogre::Vector3& halfExtents, Ogre::Vector3& translation, Ogre::Quaternion& orientation) -{ - Nif::NIFFilePtr pnif;// (Nif::Cache::getInstance().load(nifFile)); - Nif::NIFFile & nif = *pnif.get (); + return newShape; + } - if (nif.numRoots() < 1) + if(btBvhTriangleMeshShape* trishape = dynamic_cast(shape)) { - return false; +#if BT_BULLET_VERSION >= 283 + btScaledBvhTriangleMeshShape* newShape = new btScaledBvhTriangleMeshShape(trishape, btVector3(1.f, 1.f, 1.f)); +#else + // work around btScaledBvhTriangleMeshShape bug ( https://code.google.com/p/bullet/issues/detail?id=371 ) in older bullet versions + btTriangleMesh* oldMesh = static_cast(trishape->getMeshInterface()); + btTriangleMesh* newMesh = new btTriangleMesh(*oldMesh); + NifBullet::TriangleMeshShape* newShape = new NifBullet::TriangleMeshShape(newMesh, true); +#endif + return newShape; } - Nif::Record *r = nif.getRoot(0); - assert(r != NULL); - - Nif::Node *node = dynamic_cast(r); - if (node == NULL) + if (btBoxShape* boxshape = dynamic_cast(shape)) { - return false; + return new btBoxShape(*boxshape); } - return findBoundingBox(node, halfExtents, translation, orientation); + throw std::logic_error(std::string("Unhandled Bullet shape duplication: ")+shape->getName()); +} + +btCollisionShape *BulletShape::getCollisionShape() +{ + return mCollisionShape; +} + +osg::ref_ptr BulletShape::makeInstance() +{ + osg::ref_ptr instance (new BulletShapeInstance(this)); + return instance; +} + +BulletShapeInstance::BulletShapeInstance(osg::ref_ptr source) + : BulletShape() + , mSource(source) +{ + mCollisionBoxHalfExtents = source->mCollisionBoxHalfExtents; + mCollisionBoxTranslate = source->mCollisionBoxTranslate; + + if (source->mCollisionShape) + mCollisionShape = duplicateCollisionShape(source->mCollisionShape); } } // namespace NifBullet diff --git a/components/nifbullet/bulletnifloader.hpp b/components/nifbullet/bulletnifloader.hpp index 2a2e914e3..d80ab77bd 100644 --- a/components/nifbullet/bulletnifloader.hpp +++ b/components/nifbullet/bulletnifloader.hpp @@ -1,41 +1,22 @@ -/* - OpenMW - The completely unofficial reimplementation of Morrowind - Copyright (C) 2008-2010 Nicolay Korslund - Email: < korslund@gmail.com > - WWW: http://openmw.sourceforge.net/ - - This file (ogre_nif_loader.h) is part of the OpenMW package. - - OpenMW is distributed as free software: you can redistribute it - and/or modify it under the terms of the GNU General Public License - version 3, as published by the Free Software Foundation. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - version 3 along with this program. If not, see - http://www.gnu.org/licenses/ . - - */ - #ifndef OPENMW_COMPONENTS_NIFBULLET_BULLETNIFLOADER_HPP #define OPENMW_COMPONENTS_NIFBULLET_BULLETNIFLOADER_HPP #include #include #include +#include +#include #include #include #include #include #include +#include +#include +#include -// For warning messages -#include +#include namespace Nif { @@ -47,6 +28,48 @@ namespace Nif namespace NifBullet { +class BulletShapeInstance; +class BulletShape : public osg::Referenced +{ +public: + BulletShape(); + virtual ~BulletShape(); + + btCollisionShape* mCollisionShape; + + // Used for actors. Note, ideally actors would use a separate loader - as it is + // we have to keep a redundant copy of the actor model around in mCollisionShape, which isn't used. + // For now, use one file <-> one resource for simplicity. + osg::Vec3f mCollisionBoxHalfExtents; + osg::Vec3f mCollisionBoxTranslate; + + // Stores animated collision shapes. If any collision nodes in the NIF are animated, then mCollisionShape + // will be a btCompoundShape (which consists of one or more child shapes). + // In this map, for each animated collision shape, + // we store the node's record index mapped to the child index of the shape in the btCompoundShape. + std::map mAnimatedShapes; + + osg::ref_ptr makeInstance(); + + btCollisionShape* duplicateCollisionShape(btCollisionShape* shape) const; + + btCollisionShape* getCollisionShape(); + +private: + void deleteShape(btCollisionShape* shape); +}; + +// An instance of a BulletShape that may have its own unique scaling set on the mCollisionShape. +// Vertex data is shallow-copied where possible. A ref_ptr to the original shape needs to be held to keep vertex pointers intact. +class BulletShapeInstance : public BulletShape +{ +public: + BulletShapeInstance(osg::ref_ptr source); + +private: + osg::ref_ptr mSource; +}; + // Subclass btBhvTriangleMeshShape to auto-delete the meshInterface struct TriangleMeshShape : public btBvhTriangleMeshShape { @@ -66,18 +89,12 @@ struct TriangleMeshShape : public btBvhTriangleMeshShape /** *Load bulletShape from NIF files. */ -class ManualBulletShapeLoader +class BulletNifLoader { public: - ManualBulletShapeLoader(bool showMarkers=false) - : mCompoundShape(NULL) - , mStaticMesh(NULL) - , mBoundingBox(NULL) - , mShowMarkers(showMarkers) - { - } + BulletNifLoader(); - virtual ~ManualBulletShapeLoader(); + virtual ~BulletNifLoader(); void warn(const std::string &msg) { @@ -90,44 +107,26 @@ public: abort(); } + osg::ref_ptr load(const Nif::NIFFilePtr file); + private: - btVector3 getbtVector(Ogre::Vector3 const &v); + bool findBoundingBox(const Nif::Node* node, int flags = 0); - /** - *Parse a node. - */ - void handleNode(Nif::Node const *node, int flags, bool isCollisionNode, bool isAnimated=false); + void handleNode(Nif::Node const *node, int flags, bool isCollisionNode, bool isAnimated=false, bool autogenerated=false); - /** - *Helper function - */ bool hasAutoGeneratedCollision(const Nif::Node *rootNode); - /** - *convert a NiTriShape to a bullet trishape. - */ void handleNiTriShape(const Nif::NiTriShape *shape, int flags, const osg::Matrixf& transform, bool isAnimated); - std::string mResourceName; - - //OEngine::Physic::BulletShape* mShape;//current shape - btCompoundShape* mCompoundShape; btTriangleMesh* mStaticMesh; - btBoxShape *mBoundingBox; - std::set mControlledNodes; - bool mShowMarkers; + osg::ref_ptr mShape; }; - -bool getBoundingBox(const std::string& nifFile, Ogre::Vector3& halfExtents, Ogre::Vector3& translation, Ogre::Quaternion& orientation); - -bool findBoundingBox(const Nif::Node* node, Ogre::Vector3& halfExtents, Ogre::Vector3& translation, Ogre::Quaternion& orientation); - } #endif diff --git a/components/nifbullet/bulletshapemanager.cpp b/components/nifbullet/bulletshapemanager.cpp new file mode 100644 index 000000000..6acfdd408 --- /dev/null +++ b/components/nifbullet/bulletshapemanager.cpp @@ -0,0 +1,47 @@ +#include "bulletshapemanager.hpp" + +#include + +#include + +namespace NifBullet +{ + +BulletShapeManager::BulletShapeManager(const VFS::Manager* vfs) + : mVFS(vfs) +{ + +} + +BulletShapeManager::~BulletShapeManager() +{ + +} + +osg::ref_ptr BulletShapeManager::createInstance(const std::string &name) +{ + std::string normalized = name; + mVFS->normalizeFilename(normalized); + + osg::ref_ptr shape; + Index::iterator it = mIndex.find(normalized); + if (it == mIndex.end()) + { + Files::IStreamPtr file = mVFS->get(normalized); + + // TODO: add support for non-NIF formats + + BulletNifLoader loader; + // might be worth sharing NIFFiles with SceneManager in some way + shape = loader.load(Nif::NIFFilePtr(new Nif::NIFFile(file, normalized))); + + mIndex[normalized] = shape; + } + else + shape = it->second; + + osg::ref_ptr instance = shape->makeInstance(); + return instance; +} + +} diff --git a/components/nifbullet/bulletshapemanager.hpp b/components/nifbullet/bulletshapemanager.hpp new file mode 100644 index 000000000..d9ba3ffbb --- /dev/null +++ b/components/nifbullet/bulletshapemanager.hpp @@ -0,0 +1,37 @@ +#ifndef OPENMW_COMPONENTS_BULLETSHAPEMANAGER_H +#define OPENMW_COMPONENTS_BULLETSHAPEMANAGER_H + +#include +#include + +#include + +namespace VFS +{ + class Manager; +} + +namespace NifBullet +{ + + class BulletShape; + class BulletShapeInstance; + + class BulletShapeManager + { + public: + BulletShapeManager(const VFS::Manager* vfs); + ~BulletShapeManager(); + + osg::ref_ptr createInstance(const std::string& name); + + private: + const VFS::Manager* mVFS; + + typedef std::map > Index; + Index mIndex; + }; + +} + +#endif From 19988d5e45d4a00b2d773743024f08cfce80585d Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 12 May 2015 04:04:54 +0200 Subject: [PATCH 1153/3725] Remove RefData::getHandle --- apps/openmw/mwbase/world.hpp | 6 --- apps/openmw/mwphysics/physicssystem.cpp | 8 +++ apps/openmw/mwworld/cellreflist.hpp | 10 ---- apps/openmw/mwworld/cellstore.cpp | 71 ------------------------- apps/openmw/mwworld/cellstore.hpp | 3 -- apps/openmw/mwworld/refdata.cpp | 11 ---- apps/openmw/mwworld/refdata.hpp | 3 -- apps/openmw/mwworld/scene.cpp | 12 +---- apps/openmw/mwworld/scene.hpp | 2 - apps/openmw/mwworld/worldimp.cpp | 57 ++++++++------------ apps/openmw/mwworld/worldimp.hpp | 8 --- 11 files changed, 32 insertions(+), 159 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 7cc0a6e5e..008d64aaf 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -189,12 +189,6 @@ namespace MWBase ///< Return a pointer to a liveCellRef with the given name. /// \param activeOnly do non search inactive cells. - virtual MWWorld::Ptr getPtrViaHandle (const std::string& handle) = 0; - ///< Return a pointer to a liveCellRef with the given Ogre handle. - - virtual MWWorld::Ptr searchPtrViaHandle (const std::string& handle) = 0; - ///< Return a pointer to a liveCellRef with the given Ogre handle or Ptr() if not found - virtual MWWorld::Ptr searchPtrViaActorId (int actorId) = 0; ///< Search is limited to the active cells. diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 6d429f3e5..9b56a46b8 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -966,6 +966,7 @@ namespace MWPhysics bool PhysicsSystem::isActorStandingOn(const MWWorld::Ptr &actor, const MWWorld::Ptr &object) const { + /* const std::string& actorHandle = actor.getRefData().getHandle(); const std::string& objectHandle = object.getRefData().getHandle(); @@ -975,11 +976,13 @@ namespace MWPhysics if (it->first == actorHandle && it->second == objectHandle) return true; } + */ return false; } void PhysicsSystem::getActorsStandingOn(const MWWorld::Ptr &object, std::vector &out) const { + /* const std::string& objectHandle = object.getRefData().getHandle(); for (std::map::const_iterator it = mStandingCollisions.begin(); @@ -988,10 +991,12 @@ namespace MWPhysics if (it->second == objectHandle) out.push_back(it->first); } + */ } bool PhysicsSystem::isActorCollidingWith(const MWWorld::Ptr &actor, const MWWorld::Ptr &object) const { + /* const std::string& actorHandle = actor.getRefData().getHandle(); const std::string& objectHandle = object.getRefData().getHandle(); @@ -1001,11 +1006,13 @@ namespace MWPhysics if (it->first == actorHandle && it->second == objectHandle) return true; } + */ return false; } void PhysicsSystem::getActorsCollidingWith(const MWWorld::Ptr &object, std::vector &out) const { + /* const std::string& objectHandle = object.getRefData().getHandle(); for (std::map::const_iterator it = mCollisions.begin(); @@ -1014,6 +1021,7 @@ namespace MWPhysics if (it->second == objectHandle) out.push_back(it->first); } + */ } void PhysicsSystem::disableWater() diff --git a/apps/openmw/mwworld/cellreflist.hpp b/apps/openmw/mwworld/cellreflist.hpp index 2c5e01aaa..49197d167 100644 --- a/apps/openmw/mwworld/cellreflist.hpp +++ b/apps/openmw/mwworld/cellreflist.hpp @@ -40,16 +40,6 @@ namespace MWWorld mList.push_back(item); return mList.back(); } - - LiveCellRef *searchViaHandle (const std::string& handle) - { - for (typename List::iterator iter (mList.begin()); iter!=mList.end(); ++iter) - if (iter->mData.getBaseNode() && - iter->mData.getHandle()==handle) - return &*iter; - - return 0; - } }; } diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 7da7c187d..4e6c6f116 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -282,77 +282,6 @@ namespace MWWorld return Ptr(); } - Ptr CellStore::searchViaHandle (const std::string& handle) - { - bool oldState = mHasState; - - mHasState = true; - - if (LiveCellRef *ref = mActivators.searchViaHandle (handle)) - return Ptr (ref, this); - - if (LiveCellRef *ref = mPotions.searchViaHandle (handle)) - return Ptr (ref, this); - - if (LiveCellRef *ref = mAppas.searchViaHandle (handle)) - return Ptr (ref, this); - - if (LiveCellRef *ref = mArmors.searchViaHandle (handle)) - return Ptr (ref, this); - - if (LiveCellRef *ref = mBooks.searchViaHandle (handle)) - return Ptr (ref, this); - - if (LiveCellRef *ref = mClothes.searchViaHandle (handle)) - return Ptr (ref, this); - - if (LiveCellRef *ref = mContainers.searchViaHandle (handle)) - return Ptr (ref, this); - - if (LiveCellRef *ref = mCreatures.searchViaHandle (handle)) - return Ptr (ref, this); - - if (LiveCellRef *ref = mDoors.searchViaHandle (handle)) - return Ptr (ref, this); - - if (LiveCellRef *ref = mIngreds.searchViaHandle (handle)) - return Ptr (ref, this); - - if (LiveCellRef *ref = mCreatureLists.searchViaHandle (handle)) - return Ptr (ref, this); - - if (LiveCellRef *ref = mItemLists.searchViaHandle (handle)) - return Ptr (ref, this); - - if (LiveCellRef *ref = mLights.searchViaHandle (handle)) - return Ptr (ref, this); - - if (LiveCellRef *ref = mLockpicks.searchViaHandle (handle)) - return Ptr (ref, this); - - if (LiveCellRef *ref = mMiscItems.searchViaHandle (handle)) - return Ptr (ref, this); - - if (LiveCellRef *ref = mNpcs.searchViaHandle (handle)) - return Ptr (ref, this); - - if (LiveCellRef *ref = mProbes.searchViaHandle (handle)) - return Ptr (ref, this); - - if (LiveCellRef *ref = mRepairs.searchViaHandle (handle)) - return Ptr (ref, this); - - if (LiveCellRef *ref = mStatics.searchViaHandle (handle)) - return Ptr (ref, this); - - if (LiveCellRef *ref = mWeapons.searchViaHandle (handle)) - return Ptr (ref, this); - - mHasState = oldState; - - return Ptr(); - } - Ptr CellStore::searchViaActorId (int id) { if (Ptr ptr = ::searchViaActorId (mNpcs, id, this)) diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index d7036d6b1..d3c6d0735 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -94,9 +94,6 @@ namespace MWWorld ///< Will return an empty Ptr if cell is not loaded. Does not check references in /// containers. - Ptr searchViaHandle (const std::string& handle); - ///< Will return an empty Ptr if cell is not loaded. - Ptr searchViaActorId (int id); ///< Will return an empty Ptr if cell is not loaded. diff --git a/apps/openmw/mwworld/refdata.cpp b/apps/openmw/mwworld/refdata.cpp index 82bb06b8d..a95a66f7e 100644 --- a/apps/openmw/mwworld/refdata.cpp +++ b/apps/openmw/mwworld/refdata.cpp @@ -123,17 +123,6 @@ namespace MWWorld {} } - const std::string &RefData::getHandle() - { - if(!mBaseNode) - { - static const std::string empty; - return empty; - } - - return mBaseNode->getName(); - } - Ogre::SceneNode* RefData::getBaseNodeOld() { return mBaseNode; diff --git a/apps/openmw/mwworld/refdata.hpp b/apps/openmw/mwworld/refdata.hpp index 955913d9c..5951cb101 100644 --- a/apps/openmw/mwworld/refdata.hpp +++ b/apps/openmw/mwworld/refdata.hpp @@ -81,9 +81,6 @@ namespace MWWorld RefData& operator= (const RefData& refData); - /// Return OGRE handle (may be empty). - const std::string &getHandle(); - /// Return OGRE base node (can be a null pointer). /// obsolete Ogre::SceneNode* getBaseNodeOld(); diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 81e240698..20f1f7ebc 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -563,7 +563,7 @@ namespace MWWorld MWBase::Environment::get().getMechanicsManager()->remove (ptr); MWBase::Environment::get().getSoundManager()->stopSound3D (ptr); mPhysics->remove(ptr); - //Rendering.removeObject (ptr); + //mRendering.removeObject (ptr); } bool Scene::isCellActive(const CellStore &cell) @@ -578,16 +578,6 @@ namespace MWWorld return false; } - Ptr Scene::searchPtrViaHandle (const std::string& handle) - { - for (CellStoreCollection::const_iterator iter (mActiveCells.begin()); - iter!=mActiveCells.end(); ++iter) - if (Ptr ptr = (*iter)->searchViaHandle (handle)) - return ptr; - - return Ptr(); - } - Ptr Scene::searchPtrViaActorId (int actorId) { for (CellStoreCollection::const_iterator iter (mActiveCells.begin()); diff --git a/apps/openmw/mwworld/scene.hpp b/apps/openmw/mwworld/scene.hpp index 24ffdf07b..af0b82fc3 100644 --- a/apps/openmw/mwworld/scene.hpp +++ b/apps/openmw/mwworld/scene.hpp @@ -117,8 +117,6 @@ namespace MWWorld bool isCellActive(const CellStore &cell); - Ptr searchPtrViaHandle (const std::string& handle); - Ptr searchPtrViaActorId (int actorId); }; } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index add8d0373..094098a91 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -676,22 +676,6 @@ namespace MWWorld throw std::runtime_error ("unknown ID: " + name); } - Ptr World::getPtrViaHandle (const std::string& handle) - { - Ptr res = searchPtrViaHandle (handle); - if (res.isEmpty ()) - throw std::runtime_error ("unknown Ogre handle: " + handle); - return res; - } - - Ptr World::searchPtrViaHandle (const std::string& handle) - { - if (mPlayer->getPlayer().getRefData().getHandle()==handle) - return mPlayer->getPlayer(); - - return mWorldScene->searchPtrViaHandle (handle); - } - Ptr World::searchPtrViaActorId (int actorId) { // The player is not registered in any CellStore so must be checked manually @@ -1060,10 +1044,10 @@ namespace MWWorld getFacedHandle(facedHandle, activationDistance); } - if (facedHandle.empty()) + //if (facedHandle.empty()) return MWWorld::Ptr(); - return getPtrViaHandle(facedHandle); + //return getPtrViaHandle(facedHandle); } std::pair World::getHitContact(const MWWorld::Ptr &ptr, float distance) @@ -1083,7 +1067,6 @@ namespace MWWorld if(node != NULL) pos += node->_getDerivedPosition(); } - */ std::pair result;// = mPhysics->getHitContact(ptr.getRefData().getHandle(), // pos, rot, distance); @@ -1091,6 +1074,8 @@ namespace MWWorld return std::make_pair(MWWorld::Ptr(), Ogre::Vector3(0.0f)); return std::make_pair(searchPtrViaHandle(result.first), result.second); + */ + return std::make_pair(MWWorld::Ptr(), Ogre::Vector3(0.0f)); } void World::deleteObject (const Ptr& ptr) @@ -1875,10 +1860,11 @@ namespace MWWorld if (normal.angleBetween(Ogre::Vector3(0.f,0.f,1.f)).valueDegrees() >= 30) return false; + /* MWWorld::Ptr hitObject = searchPtrViaHandle(handle); if (!hitObject.isEmpty() && hitObject.getClass().isActor()) return false; - + */ return true; } else @@ -2239,8 +2225,9 @@ namespace MWWorld if (MWBase::Environment::get().getWindowManager()->isGuiMode()) return; + /* std::vector actors; - //mPhysics->getActorsStandingOn(object, actors); + mPhysics->getActorsStandingOn(object, actors); for (std::vector::iterator it = actors.begin(); it != actors.end(); ++it) { MWWorld::Ptr actor = searchPtrViaHandle(*it); // Collision events are from the last frame, actor might no longer exist @@ -2263,6 +2250,7 @@ namespace MWWorld MWBase::Environment::get().getSoundManager()->playSound3D(actor, "Health Damage", 1.0f, 1.0f); } } + */ } void World::hurtCollidingActors(const Ptr &object, float healthPerSecond) @@ -2270,8 +2258,9 @@ namespace MWWorld if (MWBase::Environment::get().getWindowManager()->isGuiMode()) return; + /* std::vector actors; - //mPhysics->getActorsCollidingWith(object, actors); + mPhysics->getActorsCollidingWith(object, actors); for (std::vector::iterator it = actors.begin(); it != actors.end(); ++it) { MWWorld::Ptr actor = searchPtrViaHandle(*it); // Collision events are from the last frame, actor might no longer exist @@ -2294,6 +2283,7 @@ namespace MWWorld MWBase::Environment::get().getSoundManager()->playSound3D(actor, "Health Damage", 1.0f, 1.0f); } } + */ } float World::getWindSpeed() @@ -2338,15 +2328,14 @@ namespace MWWorld } } - struct ListHandlesFunctor + struct ListObjectsFunctor { - std::vector mHandles; + std::vector mObjects; bool operator() (Ptr ptr) { - Ogre::SceneNode* handle = ptr.getRefData().getBaseNodeOld(); - if (handle) - mHandles.push_back(handle->getName()); + if (ptr.getRefData().getBaseNode()) + mObjects.push_back(ptr); return true; } }; @@ -2356,12 +2345,12 @@ namespace MWWorld const Scene::CellStoreCollection& collection = mWorldScene->getActiveCells(); for (Scene::CellStoreCollection::const_iterator cellIt = collection.begin(); cellIt != collection.end(); ++cellIt) { - ListHandlesFunctor functor; - (*cellIt)->forEach(functor); + ListObjectsFunctor functor; + (*cellIt)->forEach(functor); - for (std::vector::iterator it = functor.mHandles.begin(); it != functor.mHandles.end(); ++it) - if (Misc::StringUtils::ciEqual(searchPtrViaHandle(*it).getCellRef().getOwner(), npc.getCellRef().getRefId())) - out.push_back(searchPtrViaHandle(*it)); + for (std::vector::iterator it = functor.mObjects.begin(); it != functor.mObjects.end(); ++it) + if (Misc::StringUtils::ciEqual(it->getCellRef().getOwner(), npc.getCellRef().getRefId())) + out.push_back(*it); } } @@ -2714,8 +2703,8 @@ namespace MWWorld // For the player, use camera to aim std::string facedHandle; getFacedHandle(facedHandle, distance); - if (!facedHandle.empty()) - target = getPtrViaHandle(facedHandle); + //if (!facedHandle.empty()) + // target = getPtrViaHandle(facedHandle); } else { diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index a7830da3a..97515b7d0 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -98,8 +98,6 @@ namespace MWWorld World (const World&); World& operator= (const World&); - Ptr getPtrViaHandle (const std::string& handle, CellStore& cellStore); - int mActivationDistanceOverride; std::string mStartupScript; @@ -266,12 +264,6 @@ namespace MWWorld ///< Return a pointer to a liveCellRef with the given name. /// \param activeOnly do non search inactive cells. - virtual Ptr getPtrViaHandle (const std::string& handle); - ///< Return a pointer to a liveCellRef with the given Ogre handle. - - virtual Ptr searchPtrViaHandle (const std::string& handle); - ///< Return a pointer to a liveCellRef with the given Ogre handle or Ptr() if not found - virtual Ptr searchPtrViaActorId (int actorId); ///< Search is limited to the active cells. From 65f0195c71e97c67167128c6a900ad1c83fd2028 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 12 May 2015 16:24:53 +0200 Subject: [PATCH 1154/3725] Readded animated collision shape support --- apps/openmw/mwphysics/actor.hpp | 5 + apps/openmw/mwphysics/physicssystem.cpp | 130 +++++++++++--------- apps/openmw/mwphysics/physicssystem.hpp | 9 +- apps/openmw/mwworld/worldimp.cpp | 3 +- components/nifbullet/bulletnifloader.cpp | 27 ++-- components/nifbullet/bulletnifloader.hpp | 4 +- components/nifbullet/bulletshapemanager.cpp | 18 ++- components/nifbullet/bulletshapemanager.hpp | 9 +- components/sceneutil/clone.cpp | 3 +- 9 files changed, 118 insertions(+), 90 deletions(-) diff --git a/apps/openmw/mwphysics/actor.hpp b/apps/openmw/mwphysics/actor.hpp index ec1d81fd9..1f5838543 100644 --- a/apps/openmw/mwphysics/actor.hpp +++ b/apps/openmw/mwphysics/actor.hpp @@ -25,6 +25,11 @@ namespace MWPhysics public: virtual ~PtrHolder() {} + void updatePtr(const MWWorld::Ptr& updated) + { + mPtr = updated; + } + protected: MWWorld::Ptr mPtr; }; diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 9b56a46b8..81fc1e225 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -9,10 +9,12 @@ #include #include -#include +#include #include +#include // FindRecIndexVisitor + #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" @@ -24,7 +26,6 @@ #include "../mwrender/bulletdebugdraw.hpp" -//#include "../apps/openmw/mwrender/animation.hpp" #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" @@ -35,57 +36,6 @@ #include "convert.hpp" #include "trace.h" -namespace -{ - -/* -void animateCollisionShapes (std::map& map, btDynamicsWorld* dynamicsWorld) -{ - for (std::map::iterator it = map.begin(); - it != map.end(); ++it) - { - MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->searchPtrViaHandle(it->first->mName); - if (ptr.isEmpty()) // Shouldn't happen - throw std::runtime_error("can't find Ptr"); - - MWRender::Animation* animation = MWBase::Environment::get().getWorld()->getAnimation(ptr); - if (!animation) - continue; - - OEngine::Physic::AnimatedShapeInstance& instance = it->second; - - std::map& shapes = instance.mAnimatedShapes; - for (std::map::iterator shapeIt = shapes.begin(); - shapeIt != shapes.end(); ++shapeIt) - { - - const std::string& mesh = animation->getObjectRootName(); - int boneHandle = NifOgre::NIFSkeletonLoader::lookupOgreBoneHandle(mesh, shapeIt->first); - Ogre::Node* bone = animation->getNode(boneHandle); - - if (bone == NULL) - continue; - - btCompoundShape* compound = static_cast(instance.mCompound); - - btTransform trans; - trans.setOrigin(BtOgre::Convert::toBullet(bone->_getDerivedPosition()) * compound->getLocalScaling()); - trans.setRotation(BtOgre::Convert::toBullet(bone->_getDerivedOrientation())); - - compound->getChildShape(shapeIt->second)->setLocalScaling( - compound->getLocalScaling() * - BtOgre::Convert::toBullet(bone->_getDerivedScale())); - compound->updateChildTransform(shapeIt->second, trans); - } - - // needed because we used btDynamicsWorld::setForceUpdateAllAabbs(false) - dynamicsWorld->updateSingleAabb(it->first); - } -} - */ - -} - namespace MWPhysics { @@ -569,11 +519,6 @@ namespace MWPhysics setOrigin(btVector3(pos[0], pos[1], pos[2])); } - void updatePtr(const MWWorld::Ptr& updated) - { - mPtr = updated; - } - void setScale(float scale) { mShapeInstance->getCollisionShape()->setLocalScaling(btVector3(scale,scale,scale)); @@ -594,6 +539,47 @@ namespace MWPhysics return mCollisionObject.get(); } + void animateCollisionShapes(btDynamicsWorld* dynamicsWorld) + { + if (mShapeInstance->mAnimatedShapes.empty()) + return; + + assert (mShapeInstance->getCollisionShape()->isCompound()); + + btCompoundShape* compound = dynamic_cast(mShapeInstance->getCollisionShape()); + + for (std::map::const_iterator it = mShapeInstance->mAnimatedShapes.begin(); it != mShapeInstance->mAnimatedShapes.end(); ++it) + { + int recIndex = it->first; + int shapeIndex = it->second; + + NifOsg::FindRecIndexVisitor visitor(recIndex); + mPtr.getRefData().getBaseNode()->accept(visitor); + if (!visitor.mFound) + { + std::cerr << "animateCollisionShapes: Can't find node " << recIndex << std::endl; + return; + } + + osg::NodePath path = visitor.mFoundPath; + path.erase(path.begin()); + osg::Matrixf matrix = osg::computeLocalToWorld(path); + osg::Vec3f scale = matrix.getScale(); + matrix.orthoNormalize(matrix); + + btTransform transform; + transform.setOrigin(toBullet(matrix.getTrans()) * compound->getLocalScaling()); + for (int i=0; i<3; ++i) + for (int j=0; j<3; ++j) + transform.getBasis()[i][j] = matrix(j,i); // NB column/row major difference + + compound->getChildShape(shapeIndex)->setLocalScaling(compound->getLocalScaling() * toBullet(scale)); + compound->updateChildTransform(shapeIndex, transform); + } + + dynamicsWorld->updateSingleAabb(mCollisionObject.get()); + } + private: std::auto_ptr mCollisionObject; osg::ref_ptr mShapeInstance; @@ -601,8 +587,8 @@ namespace MWPhysics // --------------------------------------------------------------- - PhysicsSystem::PhysicsSystem(const VFS::Manager* vfs, osg::ref_ptr parentNode) - : mShapeManager(new NifBullet::BulletShapeManager(vfs)) + PhysicsSystem::PhysicsSystem(Resource::ResourceSystem* resourceSystem, osg::ref_ptr parentNode) + : mShapeManager(new NifBullet::BulletShapeManager(resourceSystem->getVFS(), resourceSystem->getSceneManager())) , mTimeAccum(0.0f) , mWaterEnabled(false) , mWaterHeight(0) @@ -795,6 +781,27 @@ namespace MWPhysics } } + void PhysicsSystem::updatePtr(const MWWorld::Ptr &old, const MWWorld::Ptr &updated) + { + ObjectMap::iterator found = mObjects.find(old); + if (found != mObjects.end()) + { + Object* obj = found->second; + obj->updatePtr(updated); + mObjects.erase(found); + mObjects.insert(std::make_pair(updated, obj)); + } + + ActorMap::iterator foundActor = mActors.find(old); + if (foundActor != mActors.end()) + { + Actor* actor = foundActor->second; + actor->updatePtr(updated); + mActors.erase(foundActor); + mActors.insert(std::make_pair(updated, actor)); + } + } + void PhysicsSystem::updateScale(const MWWorld::Ptr &ptr) { ObjectMap::iterator found = mObjects.find(ptr); @@ -955,7 +962,8 @@ namespace MWPhysics void PhysicsSystem::stepSimulation(float dt) { - //animateCollisionShapes(mEngine->mAnimatedShapes, mDynamicsWorld); + for (ObjectMap::iterator it = mObjects.begin(); it != mObjects.end(); ++it) + it->second->animateCollisionShapes(mDynamicsWorld); // We have nothing to simulate, but character controllers aren't working without this call. Might be related to updating AABBs. mDynamicsWorld->stepSimulation(static_cast(dt), 1, 1 / 60.0f); diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index e6bfd7cd2..54cf48ad1 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -26,9 +26,9 @@ namespace NifBullet class BulletShapeManager; } -namespace VFS +namespace Resource { - class Manager; + class ResourceSystem; } class btSequentialImpulseConstraintSolver; @@ -45,7 +45,7 @@ namespace MWPhysics class PhysicsSystem { public: - PhysicsSystem (const VFS::Manager* vfs, osg::ref_ptr parentNode); + PhysicsSystem (Resource::ResourceSystem* resourceSystem, osg::ref_ptr parentNode); ~PhysicsSystem (); void enableWater(float height); @@ -61,8 +61,7 @@ namespace MWPhysics void updateRotation (const MWWorld::Ptr& ptr); void updatePosition (const MWWorld::Ptr& ptr); - // TODO - //void updatePtr (const MWWorld::Ptr& old, const MWWorld::Ptr& updated); + void updatePtr (const MWWorld::Ptr& old, const MWWorld::Ptr& updated); void addActor (const MWWorld::Ptr& ptr, const std::string& mesh); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 094098a91..c1e31453f 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -17,7 +17,6 @@ #include #include #include -#include #include @@ -158,7 +157,7 @@ namespace MWWorld mStartCell (startCell), mStartupScript(startupScript), mScriptsEnabled(true) { - mPhysics = new MWPhysics::PhysicsSystem(resourceSystem->getVFS(), rootNode); + mPhysics = new MWPhysics::PhysicsSystem(resourceSystem, rootNode); //mPhysEngine = mPhysics->getEngine(); #if 0 mProjectileManager.reset(new ProjectileManager(renderer.getScene(), *mPhysEngine)); diff --git a/components/nifbullet/bulletnifloader.cpp b/components/nifbullet/bulletnifloader.cpp index 62f2d94d8..89daf898a 100644 --- a/components/nifbullet/bulletnifloader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -46,6 +46,11 @@ BulletNifLoader::~BulletNifLoader() { } +void BulletNifLoader::setAnimatedNodes(const std::set &animatedNodes) +{ + mAnimatedNodes = animatedNodes; +} + osg::ref_ptr BulletNifLoader::load(const Nif::NIFFilePtr nif) { mShape = new BulletShape; @@ -84,20 +89,6 @@ osg::ref_ptr BulletNifLoader::load(const Nif::NIFFilePtr nif) } else { - /* - // Have to load controlled nodes from the .kf - mControlledNodes.clear(); - std::string kfname = mResourceName.substr(0, mResourceName.length()-7); - Misc::StringUtils::toLower(kfname); - if(kfname.size() > 4 && kfname.compare(kfname.size()-4, 4, ".nif") == 0) - kfname.replace(kfname.size()-4, 4, ".kf"); - if (Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(kfname)) - { - Nif::NIFFilePtr kf;// (Nif::Cache::getInstance().load(kfname)); - //extractControlledNodes(kf, mControlledNodes); - } - */ - bool autogenerated = hasAutoGeneratedCollision(node); handleNode(node, 0, autogenerated, false, autogenerated); @@ -181,7 +172,7 @@ void BulletNifLoader::handleNode(const Nif::Node *node, int flags, && (node->controller->flags & Nif::NiNode::ControllerFlag_Active)) isAnimated = true; - if (mControlledNodes.find(node->name) != mControlledNodes.end()) + if (mAnimatedNodes.find(node->name) != mAnimatedNodes.end()) isAnimated = true; isCollisionNode = isCollisionNode || (node->recType == Nif::RC_RootCollisionNode); @@ -238,7 +229,7 @@ void BulletNifLoader::handleNode(const Nif::Node *node, int flags, for(size_t i = 0;i < list.length();i++) { if(!list[i].empty()) - handleNode(list[i].getPtr(), flags, isCollisionNode, isAnimated); + handleNode(list[i].getPtr(), flags, isCollisionNode, isAnimated, autogenerated); } } } @@ -267,7 +258,6 @@ void BulletNifLoader::handleNiTriShape(const Nif::NiTriShape *shape, int flags, if (!shape->skin.empty()) isAnimated = false; - /* if (isAnimated) { if (!mCompoundShape) @@ -311,7 +301,6 @@ void BulletNifLoader::handleNiTriShape(const Nif::NiTriShape *shape, int flags, mCompoundShape->addChildShape(trans, childShape); } else - */ { if (!mStaticMesh) mStaticMesh = new btTriangleMesh(false); @@ -414,6 +403,8 @@ BulletShapeInstance::BulletShapeInstance(osg::ref_ptr source) mCollisionBoxHalfExtents = source->mCollisionBoxHalfExtents; mCollisionBoxTranslate = source->mCollisionBoxTranslate; + mAnimatedShapes = source->mAnimatedShapes; + if (source->mCollisionShape) mCollisionShape = duplicateCollisionShape(source->mCollisionShape); } diff --git a/components/nifbullet/bulletnifloader.hpp b/components/nifbullet/bulletnifloader.hpp index d80ab77bd..ae4279f40 100644 --- a/components/nifbullet/bulletnifloader.hpp +++ b/components/nifbullet/bulletnifloader.hpp @@ -107,6 +107,8 @@ public: abort(); } + void setAnimatedNodes(const std::set& animatedNodes); + osg::ref_ptr load(const Nif::NIFFilePtr file); private: @@ -122,7 +124,7 @@ private: btTriangleMesh* mStaticMesh; - std::set mControlledNodes; + std::set mAnimatedNodes; osg::ref_ptr mShape; }; diff --git a/components/nifbullet/bulletshapemanager.cpp b/components/nifbullet/bulletshapemanager.cpp index 6acfdd408..34c64570e 100644 --- a/components/nifbullet/bulletshapemanager.cpp +++ b/components/nifbullet/bulletshapemanager.cpp @@ -4,11 +4,14 @@ #include +#include + namespace NifBullet { -BulletShapeManager::BulletShapeManager(const VFS::Manager* vfs) +BulletShapeManager::BulletShapeManager(const VFS::Manager* vfs, Resource::SceneManager* sceneManager) : mVFS(vfs) + , mSceneManager(sceneManager) { } @@ -31,7 +34,20 @@ osg::ref_ptr BulletShapeManager::createInstance(const std:: // TODO: add support for non-NIF formats + std::string kfname = normalized; + if(kfname.size() > 4 && kfname.compare(kfname.size()-4, 4, ".nif") == 0) + kfname.replace(kfname.size()-4, 4, ".kf"); + std::set animatedNodes; + if (mVFS->exists(kfname)) + { + osg::ref_ptr keyframes = mSceneManager->getKeyframes(normalized); + for (NifOsg::KeyframeHolder::KeyframeControllerMap::const_iterator it = keyframes->mKeyframeControllers.begin(); + it != keyframes->mKeyframeControllers.end(); ++it) + animatedNodes.insert(it->first); + } + BulletNifLoader loader; + loader.setAnimatedNodes(animatedNodes); // might be worth sharing NIFFiles with SceneManager in some way shape = loader.load(Nif::NIFFilePtr(new Nif::NIFFile(file, normalized))); diff --git a/components/nifbullet/bulletshapemanager.hpp b/components/nifbullet/bulletshapemanager.hpp index d9ba3ffbb..9db674d6d 100644 --- a/components/nifbullet/bulletshapemanager.hpp +++ b/components/nifbullet/bulletshapemanager.hpp @@ -11,6 +11,11 @@ namespace VFS class Manager; } +namespace Resource +{ + class SceneManager; +} + namespace NifBullet { @@ -20,13 +25,15 @@ namespace NifBullet class BulletShapeManager { public: - BulletShapeManager(const VFS::Manager* vfs); + BulletShapeManager(const VFS::Manager* vfs, Resource::SceneManager* sceneManager); ~BulletShapeManager(); osg::ref_ptr createInstance(const std::string& name); private: const VFS::Manager* mVFS; + // need to load keyframes to know what nodes are going to be animated + Resource::SceneManager* mSceneManager; typedef std::map > Index; Index mIndex; diff --git a/components/sceneutil/clone.cpp b/components/sceneutil/clone.cpp index eb7e63587..862a070d8 100644 --- a/components/sceneutil/clone.cpp +++ b/components/sceneutil/clone.cpp @@ -18,7 +18,8 @@ namespace SceneUtil { setCopyFlags(osg::CopyOp::DEEP_COPY_NODES // Controller might need different inputs per scene instance - | osg::CopyOp::DEEP_COPY_CALLBACKS); + | osg::CopyOp::DEEP_COPY_CALLBACKS + | osg::CopyOp::DEEP_COPY_USERDATA); } osg::StateSet* CopyOp::operator ()(const osg::StateSet* stateset) const From 2bc95df265b4e75de057a0769b919bb5f15dd678 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 12 May 2015 16:49:21 +0200 Subject: [PATCH 1155/3725] Actor collision object placement fix --- apps/openmw/mwphysics/actor.cpp | 7 +++++-- apps/openmw/mwphysics/actor.hpp | 2 ++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwphysics/actor.cpp b/apps/openmw/mwphysics/actor.cpp index edad7e196..1a712461e 100644 --- a/apps/openmw/mwphysics/actor.cpp +++ b/apps/openmw/mwphysics/actor.cpp @@ -87,7 +87,7 @@ void Actor::updatePosition() osg::Vec3f position = mPtr.getRefData().getPosition().asVec3(); btTransform tr = mCollisionObject->getWorldTransform(); - osg::Vec3f scaledTranslation = osg::componentMultiply(mMeshTranslation, mScale); + osg::Vec3f scaledTranslation = mRotation * osg::componentMultiply(mMeshTranslation, mScale); osg::Vec3f newPosition = scaledTranslation + position; tr.setOrigin(toBullet(newPosition)); @@ -97,8 +97,11 @@ void Actor::updatePosition() void Actor::updateRotation () { btTransform tr = mCollisionObject->getWorldTransform(); - tr.setRotation(toBullet(mPtr.getRefData().getBaseNode()->getAttitude())); + mRotation = mPtr.getRefData().getBaseNode()->getAttitude(); + tr.setRotation(toBullet(mRotation)); mCollisionObject->setWorldTransform(tr); + + updatePosition(); } void Actor::updateScale() diff --git a/apps/openmw/mwphysics/actor.hpp b/apps/openmw/mwphysics/actor.hpp index 1f5838543..513985c94 100644 --- a/apps/openmw/mwphysics/actor.hpp +++ b/apps/openmw/mwphysics/actor.hpp @@ -6,6 +6,7 @@ #include "../mwworld/ptr.hpp" #include +#include #include class btDynamicsWorld; @@ -109,6 +110,7 @@ namespace MWPhysics osg::Vec3f mMeshTranslation; osg::Vec3f mHalfExtents; + osg::Quat mRotation; osg::Vec3f mScale; osg::Vec3f mPosition; From 82316105de11384d509a54e185b1999d2547899f Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 12 May 2015 16:49:53 +0200 Subject: [PATCH 1156/3725] BulletShapeManager kf loading fix --- components/nifbullet/bulletshapemanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/nifbullet/bulletshapemanager.cpp b/components/nifbullet/bulletshapemanager.cpp index 34c64570e..e53a351cf 100644 --- a/components/nifbullet/bulletshapemanager.cpp +++ b/components/nifbullet/bulletshapemanager.cpp @@ -40,7 +40,7 @@ osg::ref_ptr BulletShapeManager::createInstance(const std:: std::set animatedNodes; if (mVFS->exists(kfname)) { - osg::ref_ptr keyframes = mSceneManager->getKeyframes(normalized); + osg::ref_ptr keyframes = mSceneManager->getKeyframes(kfname); for (NifOsg::KeyframeHolder::KeyframeControllerMap::const_iterator it = keyframes->mKeyframeControllers.begin(); it != keyframes->mKeyframeControllers.end(); ++it) animatedNodes.insert(it->first); From e8ec4387d6081c37fdbc8a4da4ca6eb0944b4b58 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 12 May 2015 16:50:11 +0200 Subject: [PATCH 1157/3725] Creature collision fix --- apps/openmw/mwclass/creature.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 7d4fcf5d6..89302dcc0 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -173,7 +173,7 @@ namespace MWClass { if(!model.empty()) { - //physics.addActor(ptr, model); + physics.addActor(ptr, model); if (getCreatureStats(ptr).isDead()) MWBase::Environment::get().getWorld()->enableActorCollision(ptr, false); } From 4036978718241b62cb532f13a9c987d5e467bac2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 12 May 2015 16:50:31 +0200 Subject: [PATCH 1158/3725] Empty model exception fix --- apps/openmw/mwclass/light.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 4d0c0cba9..1e882b568 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -48,7 +48,7 @@ namespace MWClass assert (ref->mBase != NULL); // TODO: add option somewhere to enable collision for placeable objects - if ((ref->mBase->mData.mFlags & ESM::Light::Carry) == 0) + if (!model.empty() && (ref->mBase->mData.mFlags & ESM::Light::Carry) == 0) physics.addObject(ptr, model); if (!ref->mBase->mSound.empty() && !(ref->mBase->mData.mFlags & ESM::Light::OffDefault)) From 56ff280230ddc1fc49ced71c9f0ea2982c49eb2d Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 12 May 2015 16:50:43 +0200 Subject: [PATCH 1159/3725] Mention the RefId in "error during rendering: " errors --- apps/openmw/mwworld/scene.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 20f1f7ebc..d087a40d8 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -119,7 +119,7 @@ namespace } catch (const std::exception& e) { - std::string error ("error during rendering: "); + std::string error ("error during rendering '" + ptr.getCellRef().getRefId() + "': "); std::cerr << error + e.what() << std::endl; } } From ccab8cc9a1a46040d9f82d2d6acbd2553c809c5a Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 12 May 2015 17:40:42 +0200 Subject: [PATCH 1160/3725] Register Player in the PhysicsSystem --- apps/launcher/CMakeLists.txt | 1 - apps/launcher/maindialog.cpp | 2 +- apps/openmw/mwmechanics/aicombat.cpp | 10 ++++------ apps/openmw/mwrender/animation.cpp | 14 ++++++++++++++ apps/openmw/mwrender/animation.hpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 12 +++++++----- apps/openmw/mwworld/worldimp.hpp | 2 ++ 7 files changed, 29 insertions(+), 14 deletions(-) diff --git a/apps/launcher/CMakeLists.txt b/apps/launcher/CMakeLists.txt index 76b6e46bd..bc1975ac9 100644 --- a/apps/launcher/CMakeLists.txt +++ b/apps/launcher/CMakeLists.txt @@ -89,7 +89,6 @@ add_executable(openmw-launcher target_link_libraries(openmw-launcher ${Boost_LIBRARIES} - ${OGRE_LIBRARIES} ${SDL2_LIBRARY_ONLY} ${QT_LIBRARIES} components diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index 00e6a9aa2..edbe48077 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -199,7 +199,7 @@ bool Launcher::MainDialog::setup() // Now create the pages as they need the settings createPages(); - // Call this so we can exit on Ogre/SDL errors before mainwindow is shown + // Call this so we can exit on SDL errors before mainwindow is shown if (!mGraphicsPage->loadSettings()) return false; diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 84cf6f519..ac5d1691c 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -16,13 +16,13 @@ #include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/dialoguemanager.hpp" -//#include "../mwrender/animation.hpp" +#include "../mwrender/animation.hpp" #include "creaturestats.hpp" #include "steering.hpp" #include "movement.hpp" -//#include "character.hpp" // fixme: for getActiveWeapon +#include "character.hpp" // fixme: for getActiveWeapon #include "aicombataction.hpp" #include "combat.hpp" @@ -188,7 +188,6 @@ namespace MWMechanics */ bool AiCombat::execute (const MWWorld::Ptr& actor, AiState& state, float duration) { -#if 0 // get or create temporary storage AiCombatStorage& storage = state.get(); @@ -257,9 +256,11 @@ namespace MWMechanics if(readyToAttack) { + if (!minMaxAttackDurationInitialised) { // TODO: this must be updated when a different weapon is equipped + // FIXME: attack durations would be easier to control if we interact more closely with the CharacterController getMinMaxAttackDuration(actor, minMaxAttackDuration); minMaxAttackDurationInitialised = true; } @@ -674,7 +675,6 @@ namespace MWMechanics // FIXME: can fool actors to stay behind doors, etc. // Related to Bug#1102 and to some degree #1155 as well } -#endif return false; } @@ -812,7 +812,6 @@ ESM::Weapon::AttackType chooseBestAttack(const ESM::Weapon* weapon, MWMechanics: return attackType; } -#if 0 void getMinMaxAttackDuration(const MWWorld::Ptr& actor, float (*fMinMaxDurations)[2]) { if (!actor.getClass().hasInventoryStore(actor)) // creatures @@ -876,7 +875,6 @@ void getMinMaxAttackDuration(const MWWorld::Ptr& actor, float (*fMinMaxDurations fMinMaxDurations[i][1] = fMinMaxDurations[i][0] + (start1 - start2) / weapSpeed; } } -#endif Ogre::Vector3 AimDirToMovingTarget(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, const Ogre::Vector3& vLastTargetPos, float duration, int weapType, float strength) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 1f749ab4e..888846789 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -34,6 +34,8 @@ #include "../mwworld/esmstore.hpp" #include "../mwworld/class.hpp" +#include "../mwmechanics/character.hpp" // FIXME: for MWMechanics::Priority + #include "vismask.hpp" #include "util.hpp" @@ -1068,6 +1070,18 @@ namespace MWRender } } + bool Animation::upperBodyReady() const + { + for (AnimStateMap::const_iterator stateiter = mStates.begin(); stateiter != mStates.end(); ++stateiter) + { + if((stateiter->second.mPriority > MWMechanics::Priority_Movement + && stateiter->second.mPriority < MWMechanics::Priority_Torch) + || stateiter->second.mPriority == MWMechanics::Priority_Death) + return false; + } + return true; + } + bool Animation::hasNode(const std::string &name) { std::string lowerName = Misc::StringUtils::lowerCase(name); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index c85f87403..81f044707 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -309,7 +309,7 @@ public: bool isPlaying(const std::string &groupname) const; /// Returns true if no important animations are currently playing on the upper body. - //bool upperBodyReady() const; + bool upperBodyReady() const; /** Gets info about the given animation group. * \param groupname Animation group to check. diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index c1e31453f..6ea38a8fb 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include @@ -148,7 +149,7 @@ namespace MWWorld const std::vector& contentFiles, ToUTF8::Utf8Encoder* encoder, const std::map& fallbackMap, int activationDistanceOverride, const std::string& startCell, const std::string& startupScript) - : mPlayer (0), mLocalScripts (mStore), + : mResourceSystem(resourceSystem), mPlayer (0), mLocalScripts (mStore), mSky (true), mCells (mStore, mEsm), mActivationDistanceOverride (activationDistanceOverride), mFallback(fallbackMap), mTeleportEnabled(true), mLevitationEnabled(true), @@ -1170,7 +1171,7 @@ namespace MWWorld MWWorld::Ptr newPtr = ptr.getClass() .copyToCell(ptr, *newCell); - newPtr.getRefData().setBaseNodeOld(0); + newPtr.getRefData().setBaseNode(0); } else if (!currCellActive && !newCellActive) ptr.getClass().copyToCell(ptr, *newCell); @@ -1180,8 +1181,9 @@ namespace MWWorld ptr.getClass().copyToCell(ptr, *newCell, pos); //mRendering->updateObjectCell(ptr, copy); - ptr.getRefData().setBaseNodeOld(NULL); + ptr.getRefData().setBaseNode(NULL); MWBase::Environment::get().getSoundManager()->updatePtr (ptr, copy); + mPhysics->updatePtr(ptr, copy); MWBase::MechanicsManager *mechMgr = MWBase::Environment::get().getMechanicsManager(); mechMgr->updateCell(ptr, copy); @@ -2123,8 +2125,8 @@ namespace MWWorld MWBase::Environment::get().getMechanicsManager()->add(getPlayerPtr()); std::string model = getPlayerPtr().getClass().getModel(getPlayerPtr()); - //model = Misc::ResourceHelpers::correctActorModelPath(model); - //mPhysics->addActor(mPlayer->getPlayer(), model); + model = Misc::ResourceHelpers::correctActorModelPath(model, mResourceSystem->getVFS()); + mPhysics->addActor(getPlayerPtr(), model); } int World::canRest () diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 97515b7d0..279d35329 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -70,6 +70,8 @@ namespace MWWorld class World : public MWBase::World { + Resource::ResourceSystem* mResourceSystem; + MWWorld::Fallback mFallback; MWRender::RenderingManager* mRendering; From 7a3bc69df7d33a0b0629d7637b182efe0d6fb4f1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 12 May 2015 19:02:56 +0200 Subject: [PATCH 1161/3725] Readded sound listener --- apps/openmw/mwbase/soundmanager.hpp | 9 +-- apps/openmw/mwphysics/physicssystem.cpp | 8 ++ apps/openmw/mwphysics/physicssystem.hpp | 8 +- .../mwscript/transformationextensions.cpp | 37 +++++----- apps/openmw/mwsound/loudness.cpp | 4 +- apps/openmw/mwsound/openal_output.cpp | 22 +++--- apps/openmw/mwsound/openal_output.hpp | 4 +- apps/openmw/mwsound/sound.hpp | 6 +- apps/openmw/mwsound/sound_output.hpp | 8 +- apps/openmw/mwsound/soundmanagerimp.cpp | 16 ++-- apps/openmw/mwsound/soundmanagerimp.hpp | 10 +-- apps/openmw/mwworld/containerstore.cpp | 2 +- apps/openmw/mwworld/projectilemanager.hpp | 8 +- apps/openmw/mwworld/worldimp.cpp | 74 +++++++++---------- 14 files changed, 109 insertions(+), 107 deletions(-) diff --git a/apps/openmw/mwbase/soundmanager.hpp b/apps/openmw/mwbase/soundmanager.hpp index e71558de0..4fccec40b 100644 --- a/apps/openmw/mwbase/soundmanager.hpp +++ b/apps/openmw/mwbase/soundmanager.hpp @@ -7,11 +7,6 @@ #include "../mwworld/ptr.hpp" -namespace Ogre -{ - class Vector3; -} - namespace MWWorld { class CellStore; @@ -125,7 +120,7 @@ namespace MWBase ///< Play a 3D sound attached to an MWWorld::Ptr. Will be updated automatically with the Ptr's position, unless Play_NoTrack is specified. ///< @param offset Value from [0,1] meaning from which fraction the sound the playback starts. - virtual MWBase::SoundPtr playManualSound3D(const Ogre::Vector3& initialPos, const std::string& soundId, + virtual MWBase::SoundPtr playManualSound3D(const osg::Vec3f& initialPos, const std::string& soundId, float volume, float pitch, PlayType type, PlayMode mode, float offset=0) = 0; ///< Play a 3D sound at \a initialPos. If the sound should be moving, it must be updated manually using Sound::setPosition. @@ -162,7 +157,7 @@ namespace MWBase virtual void update(float duration) = 0; - virtual void setListenerPosDir(const Ogre::Vector3 &pos, const Ogre::Vector3 &dir, const Ogre::Vector3 &up) = 0; + virtual void setListenerPosDir(const osg::Vec3f &pos, const osg::Vec3f &dir, const osg::Vec3f &up) = 0; virtual void updatePtr (const MWWorld::Ptr& old, const MWWorld::Ptr& updated) = 0; diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 81fc1e225..04b53a8e3 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -802,6 +802,14 @@ namespace MWPhysics } } + Actor *PhysicsSystem::getActor(const MWWorld::Ptr &ptr) + { + ActorMap::iterator found = mActors.find(ptr); + if (found != mActors.end()) + return found->second; + return NULL; + } + void PhysicsSystem::updateScale(const MWWorld::Ptr &ptr) { ObjectMap::iterator found = mObjects.find(ptr); diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index 54cf48ad1..91e166bef 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -53,6 +53,11 @@ namespace MWPhysics void disableWater(); void addObject (const MWWorld::Ptr& ptr, const std::string& mesh); + void addActor (const MWWorld::Ptr& ptr, const std::string& mesh); + + void updatePtr (const MWWorld::Ptr& old, const MWWorld::Ptr& updated); + + Actor* getActor(const MWWorld::Ptr& ptr); // Object or Actor void remove (const MWWorld::Ptr& ptr); @@ -61,9 +66,6 @@ namespace MWPhysics void updateRotation (const MWWorld::Ptr& ptr); void updatePosition (const MWWorld::Ptr& ptr); - void updatePtr (const MWWorld::Ptr& old, const MWWorld::Ptr& updated); - - void addActor (const MWWorld::Ptr& ptr, const std::string& mesh); void addHeightField (float* heights, int x, int y, float triSize, float sqrtVerts); diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index e71a4a34b..d43eae021 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -1,4 +1,4 @@ -#include +#include #include @@ -519,17 +519,17 @@ namespace MWScript for (int i=0; igetOrientation() * posChange; - Ogre::Vector3 worldPos(ptr.getRefData().getPosition().pos); + osg::Vec3f diff = ptr.getRefData().getBaseNode()->getAttitude() * posChange; + osg::Vec3f worldPos(ptr.getRefData().getPosition().asVec3()); worldPos += diff; - MWBase::Environment::get().getWorld()->moveObject(ptr, worldPos.x, worldPos.y, worldPos.z); + MWBase::Environment::get().getWorld()->moveObject(ptr, worldPos.x(), worldPos.y(), worldPos.z()); } }; diff --git a/apps/openmw/mwsound/loudness.cpp b/apps/openmw/mwsound/loudness.cpp index 007791984..9446a1dae 100644 --- a/apps/openmw/mwsound/loudness.cpp +++ b/apps/openmw/mwsound/loudness.cpp @@ -1,5 +1,7 @@ #include "loudness.hpp" +#include + #include "soundmanagerimp.hpp" namespace MWSound @@ -28,7 +30,7 @@ namespace MWSound value = ((char)(data[sample*advance]^0x80))/128.f; else if (type == SampleType_Int16) { - value = *reinterpret_cast(&data[sample*advance]); + value = *reinterpret_cast(&data[sample*advance]); value /= float(std::numeric_limits::max()); } else if (type == SampleType_Float32) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 266b97f87..6862bb889 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -271,7 +271,7 @@ private: OpenAL_SoundStream::OpenAL_SoundStream(OpenAL_Output &output, ALuint src, DecoderPtr decoder, float basevol, float pitch, int flags) - : Sound(Ogre::Vector3(0.0f), 1.0f, basevol, pitch, 1.0f, 1000.0f, flags) + : Sound(osg::Vec3f(0.f, 0.f, 0.f), 1.0f, basevol, pitch, 1.0f, 1000.0f, flags) , mOutput(output), mSource(src), mSamplesQueued(0), mDecoder(decoder), mIsFinished(true), mIsInitialBatchEnqueued(false) { throwALerror(); @@ -505,7 +505,7 @@ private: OpenAL_Sound& operator=(const OpenAL_Sound &rhs); public: - OpenAL_Sound(OpenAL_Output &output, ALuint src, ALuint buf, const Ogre::Vector3& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags); + OpenAL_Sound(OpenAL_Output &output, ALuint src, ALuint buf, const osg::Vec3f& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags); virtual ~OpenAL_Sound(); virtual void stop(); @@ -524,14 +524,14 @@ class OpenAL_Sound3D : public OpenAL_Sound OpenAL_Sound3D& operator=(const OpenAL_Sound &rhs); public: - OpenAL_Sound3D(OpenAL_Output &output, ALuint src, ALuint buf, const Ogre::Vector3& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags) + OpenAL_Sound3D(OpenAL_Output &output, ALuint src, ALuint buf, const osg::Vec3f& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags) : OpenAL_Sound(output, src, buf, pos, vol, basevol, pitch, mindist, maxdist, flags) { } virtual void update(); }; -OpenAL_Sound::OpenAL_Sound(OpenAL_Output &output, ALuint src, ALuint buf, const Ogre::Vector3& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags) +OpenAL_Sound::OpenAL_Sound(OpenAL_Output &output, ALuint src, ALuint buf, const osg::Vec3f& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags) : Sound(pos, vol, basevol, pitch, mindist, maxdist, flags) , mOutput(output), mSource(src), mBuffer(buf) { @@ -628,7 +628,7 @@ void OpenAL_Sound3D::update() { ALfloat gain = mVolume*mBaseVolume; ALfloat pitch = mPitch; - if(mPos.squaredDistance(mOutput.mPos) > mMaxDistance*mMaxDistance) + if((mPos - mOutput.mPos).length2() > mMaxDistance*mMaxDistance) gain = 0.0f; else if(!(mFlags&MWBase::SoundManager::Play_NoEnv) && mOutput.mLastEnvironment == Env_Underwater) { @@ -867,7 +867,7 @@ MWBase::SoundPtr OpenAL_Output::playSound(const std::string &fname, float vol, f try { buf = getBuffer(fname).mALBuffer; - sound.reset(new OpenAL_Sound(*this, src, buf, Ogre::Vector3(0.0f), vol, basevol, pitch, 1.0f, 1000.0f, flags)); + sound.reset(new OpenAL_Sound(*this, src, buf, osg::Vec3f(0.f, 0.f, 0.f), vol, basevol, pitch, 1.0f, 1000.0f, flags)); } catch(std::exception&) { @@ -892,7 +892,7 @@ MWBase::SoundPtr OpenAL_Output::playSound(const std::string &fname, float vol, f return sound; } -MWBase::SoundPtr OpenAL_Output::playSound3D(const std::string &fname, const Ogre::Vector3 &pos, float vol, float basevol, float pitch, +MWBase::SoundPtr OpenAL_Output::playSound3D(const std::string &fname, const osg::Vec3f &pos, float vol, float basevol, float pitch, float min, float max, int flags, float offset, bool extractLoudness) { boost::shared_ptr sound; @@ -967,7 +967,7 @@ MWBase::SoundPtr OpenAL_Output::streamSound(DecoderPtr decoder, float volume, fl } -void OpenAL_Output::updateListener(const Ogre::Vector3 &pos, const Ogre::Vector3 &atdir, const Ogre::Vector3 &updir, Environment env) +void OpenAL_Output::updateListener(const osg::Vec3f &pos, const osg::Vec3f &atdir, const osg::Vec3f &updir, Environment env) { mPos = pos; mLastEnvironment = env; @@ -975,10 +975,10 @@ void OpenAL_Output::updateListener(const Ogre::Vector3 &pos, const Ogre::Vector3 if(mContext) { ALfloat orient[6] = { - atdir.x, atdir.y, atdir.z, - updir.x, updir.y, updir.z + atdir.x(), atdir.y(), atdir.z(), + updir.x(), updir.y(), updir.z() }; - alListener3f(AL_POSITION, mPos.x, mPos.y, mPos.z); + alListener3f(AL_POSITION, mPos.x(), mPos.y(), mPos.z()); alListenerfv(AL_ORIENTATION, orient); throwALerror(); } diff --git a/apps/openmw/mwsound/openal_output.hpp b/apps/openmw/mwsound/openal_output.hpp index 1a95d6150..755a0e5b6 100644 --- a/apps/openmw/mwsound/openal_output.hpp +++ b/apps/openmw/mwsound/openal_output.hpp @@ -54,11 +54,11 @@ namespace MWSound /// @param offset Value from [0,1] meaning from which fraction the sound the playback starts. virtual MWBase::SoundPtr playSound(const std::string &fname, float vol, float basevol, float pitch, int flags, float offset); /// @param offset Value from [0,1] meaning from which fraction the sound the playback starts. - virtual MWBase::SoundPtr playSound3D(const std::string &fname, const Ogre::Vector3 &pos, + virtual MWBase::SoundPtr playSound3D(const std::string &fname, const osg::Vec3f &pos, float vol, float basevol, float pitch, float min, float max, int flags, float offset, bool extractLoudness=false); virtual MWBase::SoundPtr streamSound(DecoderPtr decoder, float volume, float pitch, int flags); - virtual void updateListener(const Ogre::Vector3 &pos, const Ogre::Vector3 &atdir, const Ogre::Vector3 &updir, Environment env); + virtual void updateListener(const osg::Vec3f &pos, const osg::Vec3f &atdir, const osg::Vec3f &updir, Environment env); virtual void pauseSounds(int types); virtual void resumeSounds(int types); diff --git a/apps/openmw/mwsound/sound.hpp b/apps/openmw/mwsound/sound.hpp index 1b5c00196..bdc8cf459 100644 --- a/apps/openmw/mwsound/sound.hpp +++ b/apps/openmw/mwsound/sound.hpp @@ -15,7 +15,7 @@ namespace MWSound Sound(const Sound &rhs); protected: - Ogre::Vector3 mPos; + osg::Vec3f mPos; float mVolume; /* NOTE: Real volume = mVolume*mBaseVolume */ float mBaseVolume; float mPitch; @@ -31,7 +31,7 @@ namespace MWSound virtual void stop() = 0; virtual bool isPlaying() = 0; virtual double getTimeOffset() = 0; - void setPosition(const Ogre::Vector3 &pos) { mPos = pos; } + void setPosition(const osg::Vec3f &pos) { mPos = pos; } void setVolume(float volume) { mVolume = volume; } void setFadeout(float duration) { mFadeOutTime=duration; } void setLoudnessVector(const std::vector& loudnessVector, float loudnessFPS); @@ -44,7 +44,7 @@ namespace MWSound { return (MWBase::SoundManager::PlayType)(mFlags&MWBase::SoundManager::Play_TypeMask); } - Sound(const Ogre::Vector3& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags) + Sound(const osg::Vec3f& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags) : mPos(pos) , mVolume(vol) , mBaseVolume(basevol) diff --git a/apps/openmw/mwsound/sound_output.hpp b/apps/openmw/mwsound/sound_output.hpp index 4f5c210bb..a0c6fb17b 100644 --- a/apps/openmw/mwsound/sound_output.hpp +++ b/apps/openmw/mwsound/sound_output.hpp @@ -4,8 +4,6 @@ #include #include -#include - #include "soundmanagerimp.hpp" #include "../mwworld/ptr.hpp" @@ -27,11 +25,11 @@ namespace MWSound /// @param offset Value from [0,1] meaning from which fraction the sound the playback starts. virtual MWBase::SoundPtr playSound(const std::string &fname, float vol, float basevol, float pitch, int flags, float offset) = 0; /// @param offset Value from [0,1] meaning from which fraction the sound the playback starts. - virtual MWBase::SoundPtr playSound3D(const std::string &fname, const Ogre::Vector3 &pos, + virtual MWBase::SoundPtr playSound3D(const std::string &fname, const osg::Vec3f &pos, float vol, float basevol, float pitch, float min, float max, int flags, float offset, bool extractLoudness=false) = 0; virtual MWBase::SoundPtr streamSound(DecoderPtr decoder, float volume, float pitch, int flags) = 0; - virtual void updateListener(const Ogre::Vector3 &pos, const Ogre::Vector3 &atdir, const Ogre::Vector3 &updir, Environment env) = 0; + virtual void updateListener(const osg::Vec3f &pos, const osg::Vec3f &atdir, const osg::Vec3f &updir, Environment env) = 0; virtual void pauseSounds(int types) = 0; virtual void resumeSounds(int types) = 0; @@ -41,7 +39,7 @@ namespace MWSound protected: bool mInitialized; - Ogre::Vector3 mPos; + osg::Vec3f mPos; Sound_Output(SoundManager &mgr) : mManager(mgr) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 775e3da19..a5ae9f0e2 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -268,7 +268,7 @@ namespace MWSound float basevol = volumeFromType(Play_TypeVoice); std::string filePath = "Sound/"+filename; const ESM::Position &pos = ptr.getRefData().getPosition(); - const Ogre::Vector3 objpos(pos.pos); + const osg::Vec3f objpos(pos.asVec3()); MWBase::World* world = MWBase::Environment::get().getWorld(); static const float fAudioMinDistanceMult = world->getStore().get().find("fAudioMinDistanceMult")->getFloat(); @@ -396,9 +396,9 @@ namespace MWSound float min, max; std::string file = lookup(soundId, volume, min, max); const ESM::Position &pos = ptr.getRefData().getPosition(); - const Ogre::Vector3 objpos(pos.pos); + const osg::Vec3f objpos(pos.asVec3()); - if ((mode & Play_RemoveAtDistance) && mListenerPos.squaredDistance(objpos) > 2000*2000) + if ((mode & Play_RemoveAtDistance) && (mListenerPos-objpos).length2() > 2000*2000) { return MWBase::SoundPtr(); } @@ -416,7 +416,7 @@ namespace MWSound return sound; } - MWBase::SoundPtr SoundManager::playManualSound3D(const Ogre::Vector3& initialPos, const std::string& soundId, + MWBase::SoundPtr SoundManager::playManualSound3D(const osg::Vec3f& initialPos, const std::string& soundId, float volume, float pitch, PlayType type, PlayMode mode, float offset) { MWBase::SoundPtr sound; @@ -666,11 +666,11 @@ namespace MWSound if(!ptr.isEmpty()) { const ESM::Position &pos = ptr.getRefData().getPosition(); - const Ogre::Vector3 objpos(pos.pos); + const osg::Vec3f objpos(pos.asVec3()); snditer->first->setPosition(objpos); if ((snditer->first->mFlags & Play_RemoveAtDistance) - && mListenerPos.squaredDistance(Ogre::Vector3(ptr.getRefData().getPosition().pos)) > 2000*2000) + && (mListenerPos - ptr.getRefData().getPosition().asVec3()).length2() > 2000*2000) { mActiveSounds.erase(snditer++); continue; @@ -728,7 +728,7 @@ namespace MWSound } } - void SoundManager::setListenerPosDir(const Ogre::Vector3 &pos, const Ogre::Vector3 &dir, const Ogre::Vector3 &up) + void SoundManager::setListenerPosDir(const osg::Vec3f &pos, const osg::Vec3f &dir, const osg::Vec3f &up) { mListenerPos = pos; mListenerDir = dir; @@ -738,7 +738,7 @@ namespace MWSound MWBase::Environment::get().getWorld()->getPlayerPtr(); const MWWorld::CellStore *cell = player.getCell(); - mListenerUnderwater = ((cell->getCell()->mData.mFlags&ESM::Cell::HasWater) && mListenerPos.z < cell->getWaterLevel()); + mListenerUnderwater = ((cell->getCell()->mData.mFlags&ESM::Cell::HasWater) && mListenerPos.z() < cell->getWaterLevel()); } void SoundManager::updatePtr(const MWWorld::Ptr &old, const MWWorld::Ptr &updated) diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index 8089a7e6f..27af1e65b 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -55,9 +55,9 @@ namespace MWSound MWBase::SoundPtr mUnderwaterSound; bool mListenerUnderwater; - Ogre::Vector3 mListenerPos; - Ogre::Vector3 mListenerDir; - Ogre::Vector3 mListenerUp; + osg::Vec3f mListenerPos; + osg::Vec3f mListenerDir; + osg::Vec3f mListenerUp; int mPausedSoundTypes; @@ -132,7 +132,7 @@ namespace MWSound ///< Play a 3D sound attached to an MWWorld::Ptr. Will be updated automatically with the Ptr's position, unless Play_NoTrack is specified. ///< @param offset Value from [0,1] meaning from which fraction the sound the playback starts. - virtual MWBase::SoundPtr playManualSound3D(const Ogre::Vector3& initialPos, const std::string& soundId, + virtual MWBase::SoundPtr playManualSound3D(const osg::Vec3f& initialPos, const std::string& soundId, float volume, float pitch, PlayType type, PlayMode mode, float offset=0); ///< Play a 3D sound at \a initialPos. If the sound should be moving, it must be updated manually using Sound::setPosition. @@ -171,7 +171,7 @@ namespace MWSound virtual void update(float duration); - virtual void setListenerPosDir(const Ogre::Vector3 &pos, const Ogre::Vector3 &dir, const Ogre::Vector3 &up); + virtual void setListenerPosDir(const osg::Vec3f &pos, const osg::Vec3f &dir, const osg::Vec3f &up); virtual void updatePtr (const MWWorld::Ptr& old, const MWWorld::Ptr& updated); diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 371543f2e..d4aadc6c7 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -242,7 +242,7 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& itemPtr MWWorld::Ptr item = *it; // we may have copied an item from the world, so reset a few things first - item.getRefData().setBaseNodeOld(NULL); // Especially important, otherwise scripts on the item could think that it's actually in a cell + item.getRefData().setBaseNode(NULL); // Especially important, otherwise scripts on the item could think that it's actually in a cell ESM::Position pos; pos.rot[0] = 0; pos.rot[1] = 0; diff --git a/apps/openmw/mwworld/projectilemanager.hpp b/apps/openmw/mwworld/projectilemanager.hpp index 93f54c008..f46f544d2 100644 --- a/apps/openmw/mwworld/projectilemanager.hpp +++ b/apps/openmw/mwworld/projectilemanager.hpp @@ -6,18 +6,14 @@ #include #include -#include #include "../mwbase/soundmanager.hpp" #include "ptr.hpp" -namespace OEngine +namespace MWPhysics { -namespace Physic -{ - class PhysicEngine; -} + class PhysicsSystem; } namespace Loading diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 6ea38a8fb..6c7fd6ff3 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -44,6 +44,7 @@ #include "../mwclass/door.hpp" #include "../mwphysics/physicssystem.hpp" +#include "../mwphysics/actor.hpp" #include "player.hpp" #include "manualref.hpp" @@ -1314,7 +1315,7 @@ namespace MWWorld { ESM::Position pos (ptr.getRefData().getPosition()); - if(!ptr.getRefData().getBaseNodeOld()) + if(!ptr.getRefData().getBaseNode()) { // will be adjusted when Ptr's cell becomes active return; @@ -1596,9 +1597,9 @@ namespace MWWorld performUpdateSceneQueries (); updateWindowManager (); - + */ updateSoundListener(); - + /* if (!paused && mPlayer->getPlayer().getCell()->isExterior()) { ESM::Position pos = mPlayer->getPlayer().getRefData().getPosition(); @@ -1611,17 +1612,21 @@ namespace MWWorld void World::updateSoundListener() { - /* - Ogre::Vector3 playerPos = mPlayer->getPlayer().getRefData().getBaseNodeOld()->getPosition(); - - const OEngine::Physic::PhysicActor *actor = mPhysEngine->getCharacter(getPlayerPtr().getRefData().getHandle()); - if(actor) playerPos.z += 1.85f * actor->getHalfExtents().z; - Ogre::Quaternion playerOrient = Ogre::Quaternion(Ogre::Radian(getPlayerPtr().getRefData().getPosition().rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z) * - Ogre::Quaternion(Ogre::Radian(getPlayerPtr().getRefData().getPosition().rot[0]), Ogre::Vector3::NEGATIVE_UNIT_X) * - Ogre::Quaternion(Ogre::Radian(getPlayerPtr().getRefData().getPosition().rot[1]), Ogre::Vector3::NEGATIVE_UNIT_Y); - MWBase::Environment::get().getSoundManager()->setListenerPosDir(playerPos, playerOrient.yAxis(), - playerOrient.zAxis()); - */ + const ESM::Position& refpos = getPlayerPtr().getRefData().getPosition(); + osg::Vec3f playerPos = refpos.asVec3(); + + const MWPhysics::Actor* actor = mPhysics->getActor(getPlayerPtr()); + if (actor) + playerPos.z() += 1.85f * actor->getHalfExtents().z(); + + osg::Quat playerOrient = osg::Quat(refpos.rot[1], osg::Vec3f(0,-1,0)) * + osg::Quat(refpos.rot[0], osg::Vec3f(-1,0,0)) * + osg::Quat(refpos.rot[2], osg::Vec3f(0,0,-1)); + + osg::Vec3f forward = playerOrient * osg::Vec3f(0,1,0); + osg::Vec3f up = playerOrient * osg::Vec3f(0,0,1); + + MWBase::Environment::get().getSoundManager()->setListenerPosDir(playerPos, forward, up); } void World::updateWindowManager () @@ -1987,9 +1992,9 @@ namespace MWWorld && isLevitationEnabled()) return true; - //const OEngine::Physic::PhysicActor *actor = 0;//mPhysEngine->getCharacter(ptr.getRefData().getHandle()); - //if(!actor || !actor->getCollisionMode()) - // return true; + const MWPhysics::Actor* actor = mPhysics->getActor(ptr); + if(!actor || !actor->getCollisionMode()) + return true; return false; } @@ -2027,10 +2032,10 @@ namespace MWWorld const float *fpos = object.getRefData().getPosition().pos; Ogre::Vector3 pos(fpos[0], fpos[1], fpos[2]); - //const OEngine::Physic::PhysicActor *actor = 0;//mPhysEngine->getCharacter(object.getRefData().getHandle()); - //if (actor) + const MWPhysics::Actor* actor = mPhysics->getActor(object); + if (actor) { - // pos.z += heightRatio*2*actor->getHalfExtents().z; + pos.z += heightRatio*2*actor->getHalfExtents().z(); } return isUnderwater(object.getCell(), pos); @@ -2134,17 +2139,16 @@ namespace MWWorld CellStore *currentCell = mWorldScene->getCurrentCell(); Ptr player = mPlayer->getPlayer(); - //RefData &refdata = player.getRefData(); - //Ogre::Vector3 playerPos(refdata.getPosition().pos); + RefData &refdata = player.getRefData(); + Ogre::Vector3 playerPos(refdata.getPosition().pos); - /* - const OEngine::Physic::PhysicActor *physactor = mPhysEngine->getCharacter(refdata.getHandle()); - if (!physactor) + const MWPhysics::Actor* actor = mPhysics->getActor(player); + if (!actor) throw std::runtime_error("can't find player"); - if((!physactor->getOnGround()&&physactor->getCollisionMode()) || isUnderwater(currentCell, playerPos) || isWalkingOnWater(player)) + if((!actor->getOnGround()&&actor->getCollisionMode()) || isUnderwater(currentCell, playerPos) || isWalkingOnWater(player)) return 2; - */ + if((currentCell->getCell()->mData.mFlags&ESM::Cell::NoSleep) || player.getClass().getNpcStats(player).isWerewolf()) return 1; @@ -2359,9 +2363,10 @@ namespace MWWorld { if (!targetActor.getRefData().isEnabled() || !actor.getRefData().isEnabled()) return false; // cannot get LOS unless both NPC's are enabled - if (!targetActor.getRefData().getBaseNodeOld() || !targetActor.getRefData().getBaseNodeOld()) + if (!targetActor.getRefData().getBaseNode() || !targetActor.getRefData().getBaseNode()) return false; // not in active cell + // TODO: move to PhysicsSystem /* OEngine::Physic::PhysicActor* actor1 = mPhysEngine->getCharacter(actor.getRefData().getHandle()); OEngine::Physic::PhysicActor* actor2 = mPhysEngine->getCharacter(targetActor.getRefData().getHandle()); @@ -2402,11 +2407,9 @@ namespace MWWorld void World::enableActorCollision(const MWWorld::Ptr& actor, bool enable) { - /* - OEngine::Physic::PhysicActor *physicActor = 0;//mPhysEngine->getCharacter(actor.getRefData().getHandle()); + MWPhysics::Actor *physicActor = mPhysics->getActor(actor); if (physicActor) physicActor->enableCollisionBody(enable); - */ } bool World::findInteriorPosition(const std::string &name, ESM::Position &pos) @@ -3261,9 +3264,9 @@ namespace MWWorld { MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); if(!effect->mAreaSound.empty()) - sndMgr->playManualSound3D(origin, effect->mAreaSound, 1.0f, 1.0f, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_NoTrack); + sndMgr->playManualSound3D(osg::Vec3f(origin.x, origin.y, origin.z), effect->mAreaSound, 1.0f, 1.0f, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_NoTrack); else - sndMgr->playManualSound3D(origin, schools[effect->mData.mSchool]+" area", 1.0f, 1.0f, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_NoTrack); + sndMgr->playManualSound3D(osg::Vec3f(origin.x, origin.y, origin.z), schools[effect->mData.mSchool]+" area", 1.0f, 1.0f, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_NoTrack); } // Get the actors in range of the effect std::vector objects; @@ -3348,12 +3351,9 @@ namespace MWWorld bool World::isWalkingOnWater(const Ptr &actor) { - return false; - /* - OEngine::Physic::PhysicActor* physicActor = mPhysEngine->getCharacter(actor.getRefData().getHandle()); + MWPhysics::Actor* physicActor = mPhysics->getActor(actor); if (physicActor && physicActor->isWalkingOnWater()) return true; return false; - */ } } From 538e550b2b2b9f0d71a7adca8d4e89912b3a1d70 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Wed, 13 May 2015 10:30:44 +1000 Subject: [PATCH 1162/3725] Fix for Bug #2543. Spells magic effect id typo. --- apps/opencs/model/world/nestedcoladapterimp.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/world/nestedcoladapterimp.hpp b/apps/opencs/model/world/nestedcoladapterimp.hpp index ea2037eb8..776a908ba 100644 --- a/apps/opencs/model/world/nestedcoladapterimp.hpp +++ b/apps/opencs/model/world/nestedcoladapterimp.hpp @@ -311,7 +311,7 @@ namespace CSMWorld case 0: { if (effect.mEffectID >=0 && effect.mEffectID < ESM::MagicEffect::Length) - return effect.mRange; + return effect.mEffectID; else throw std::runtime_error("Magic effects ID unexpected value"); } From 375b736e74d83696720a85dfb78ad41f873e9cbe Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 13 May 2015 02:52:04 +0200 Subject: [PATCH 1163/3725] Use SDL to create the window No input nor event loop handling yet, so the window will "stop responding" after a few seconds. Thanks to KittyCat for the GraphicsWindowSDL2 code. --- apps/openmw/engine.cpp | 103 +++++++-- apps/openmw/engine.hpp | 5 + apps/openmw/mwclass/creature.cpp | 10 - apps/openmw/mwclass/creature.hpp | 4 - apps/openmw/mwclass/npc.cpp | 10 - apps/openmw/mwclass/npc.hpp | 4 - apps/openmw/mwworld/class.cpp | 5 - apps/openmw/mwworld/class.hpp | 4 - components/CMakeLists.txt | 5 + components/sdlutil/sdlgraphicswindow.cpp | 272 +++++++++++++++++++++++ components/sdlutil/sdlgraphicswindow.hpp | 108 +++++++++ 11 files changed, 477 insertions(+), 53 deletions(-) create mode 100644 components/sdlutil/sdlgraphicswindow.cpp create mode 100644 components/sdlutil/sdlgraphicswindow.hpp diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 4c6d1585b..a77b3e293 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -6,16 +6,15 @@ #include #include -#include - #include -// TODO: move to component #include #include #include +#include + #include #include @@ -182,7 +181,8 @@ void OMW::Engine::frame(float frametime) } OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) - : mEncoding(ToUTF8::WINDOWS_1252) + : mWindow(NULL) + , mEncoding(ToUTF8::WINDOWS_1252) , mEncoder(NULL) , mVerboseScripts (false) , mSkipMenu (false) @@ -219,6 +219,13 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) OMW::Engine::~Engine() { + mResourceSystem.reset(); + + mViewer = NULL; + + SDL_DestroyWindow(mWindow); + mWindow = NULL; + mEnvironment.cleanup(); delete mScriptContext; SDL_Quit(); @@ -293,24 +300,88 @@ std::string OMW::Engine::loadSettings (Settings::Manager & settings) return settingspath; } -void OMW::Engine::prepareEngine (Settings::Manager & settings) +void OMW::Engine::createWindow(Settings::Manager& settings) { - mEnvironment.setStateManager ( - new MWState::StateManager (mCfgMgr.getUserDataPath() / "saves", mContentFiles.at (0))); + int screen = settings.getInt("screen", "Video"); + int width = settings.getInt("resolution x", "Video"); + int height = settings.getInt("resolution y", "Video"); + bool fullscreen = settings.getBool("fullscreen", "Video"); + bool windowBorder = settings.getBool("window border", "Video"); + bool vsync = settings.getBool("vsync", "Video"); + int antialiasing = settings.getInt("antialiasing", "Video"); + + int pos_x = SDL_WINDOWPOS_CENTERED_DISPLAY(screen), + pos_y = SDL_WINDOWPOS_CENTERED_DISPLAY(screen); + + if(fullscreen) + { + pos_x = SDL_WINDOWPOS_UNDEFINED_DISPLAY(screen); + pos_y = SDL_WINDOWPOS_UNDEFINED_DISPLAY(screen); + } - //OEngine::Render::WindowSettings windowSettings; - //windowSettings.fullscreen = settings.getBool("fullscreen", "Video"); - //windowSettings.window_border = settings.getBool("window border", "Video"); - //windowSettings.vsync = settings.getBool("vsync", "Video"); - //windowSettings.icon = "openmw.png"; - //std::string aa = settings.getString("antialiasing", "Video"); - //windowSettings.fsaa = (aa.substr(0, 4) == "MSAA") ? aa.substr(5, aa.size()-5) : "0"; + Uint32 flags = SDL_WINDOW_OPENGL|SDL_WINDOW_SHOWN|SDL_WINDOW_RESIZABLE; + if(fullscreen) + flags |= SDL_WINDOW_FULLSCREEN; + + if (!windowBorder) + flags |= SDL_WINDOW_BORDERLESS; SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, settings.getBool("minimize on focus loss", "Video") ? "1" : "0"); - // not handling fullscreen yet, we should figure this out when adding SDL to the mix - mViewer->setUpViewInWindow(0, 0, settings.getInt("resolution x", "Video"), settings.getInt("resolution y", "Video"), settings.getInt("screen", "Video")); + if (antialiasing > 0) + { + if (SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1) != 0) + std::cerr << "SDL error: " << SDL_GetError() << std::endl; + if (SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, antialiasing) != 0) + std::cerr << "SDL error: " << SDL_GetError() << std::endl; + } + + mWindow = SDL_CreateWindow("OpenMW", pos_x, pos_y, width, height, flags); + if (mWindow == NULL) + { + std::cerr << "Failed to create SDL window: " << SDL_GetError() << std::endl; + return; + } + + // TODO: set window icon + + SDLUtil::setupWindowingSystemInterface(); + + osg::ref_ptr traits = new osg::GraphicsContext::Traits; + SDL_GetWindowPosition(mWindow, &traits->x, &traits->y); + SDL_GetWindowSize(mWindow, &traits->width, &traits->height); + traits->windowName = SDL_GetWindowTitle(mWindow); + traits->windowDecoration = !(SDL_GetWindowFlags(mWindow)&SDL_WINDOW_BORDERLESS); + traits->screenNum = SDL_GetWindowDisplayIndex(mWindow); + // FIXME: Some way to get these settings back from the SDL window? + traits->red = 8; + traits->green = 8; + traits->blue = 8; + traits->alpha = 8; + traits->depth = 24; + traits->stencil = 8; + traits->vsync = vsync; + traits->doubleBuffer = true; + traits->inheritedWindowData = new SDLUtil::GraphicsWindowSDL2::WindowData(mWindow); + + osg::ref_ptr gc = osg::GraphicsContext::createGraphicsContext(traits.get()); + if(!gc.valid()) throw std::runtime_error("Failed to create GraphicsContext"); + + osg::ref_ptr camera = mViewer->getCamera(); + camera->setGraphicsContext(gc.get()); + camera->setViewport(0, 0, width, height); + + mViewer->realize(); +} + +void OMW::Engine::prepareEngine (Settings::Manager & settings) +{ + mEnvironment.setStateManager ( + new MWState::StateManager (mCfgMgr.getUserDataPath() / "saves", mContentFiles.at (0))); + + createWindow(settings); + osg::ref_ptr rootNode (new osg::Group); mViewer->setSceneData(rootNode); diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index e94b5e3ff..420121a8e 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -53,11 +53,14 @@ namespace Files struct ConfigurationManager; } +struct SDL_Window; + namespace OMW { /// \brief Main engine class, that brings together all the components of OpenMW class Engine { + SDL_Window* mWindow; std::auto_ptr mVFS; std::auto_ptr mResourceSystem; MWBase::Environment mEnvironment; @@ -112,6 +115,8 @@ namespace OMW /// Prepare engine for game play void prepareEngine (Settings::Manager & settings); + void createWindow(Settings::Manager& settings); + public: Engine(Files::ConfigurationManager& configurationManager); virtual ~Engine(); diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 89302dcc0..1e41aea24 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -580,16 +580,6 @@ namespace MWClass return dynamic_cast (*ptr.getRefData().getCustomData()).mMovement; } - Ogre::Vector3 Creature::getMovementVector (const MWWorld::Ptr& ptr) const - { - MWMechanics::Movement &movement = getMovementSettings(ptr); - Ogre::Vector3 vec(movement.mPosition); - movement.mPosition[0] = 0.0f; - movement.mPosition[1] = 0.0f; - movement.mPosition[2] = 0.0f; - return vec; - } - Ogre::Vector3 Creature::getRotationVector (const MWWorld::Ptr& ptr) const { MWMechanics::Movement &movement = getMovementSettings(ptr); diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index 7a50968bf..f5a2402f3 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -113,10 +113,6 @@ namespace MWClass virtual MWMechanics::Movement& getMovementSettings (const MWWorld::Ptr& ptr) const; ///< Return desired movement. - virtual Ogre::Vector3 getMovementVector (const MWWorld::Ptr& ptr) const; - ///< Return desired movement vector (determined based on movement settings, - /// stance and stats). - virtual Ogre::Vector3 getRotationVector (const MWWorld::Ptr& ptr) const; ///< Return desired rotations, as euler angles. diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 6f969146b..463209df8 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -961,16 +961,6 @@ namespace MWClass return dynamic_cast (*ptr.getRefData().getCustomData()).mMovement; } - Ogre::Vector3 Npc::getMovementVector (const MWWorld::Ptr& ptr) const - { - MWMechanics::Movement &movement = getMovementSettings(ptr); - Ogre::Vector3 vec(movement.mPosition); - movement.mPosition[0] = 0.0f; - movement.mPosition[1] = 0.0f; - movement.mPosition[2] = 0.0f; - return vec; - } - Ogre::Vector3 Npc::getRotationVector (const MWWorld::Ptr& ptr) const { MWMechanics::Movement &movement = getMovementSettings(ptr); diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index e0ebbec2b..f72a9bb2c 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -105,10 +105,6 @@ namespace MWClass virtual MWMechanics::Movement& getMovementSettings (const MWWorld::Ptr& ptr) const; ///< Return desired movement. - virtual Ogre::Vector3 getMovementVector (const MWWorld::Ptr& ptr) const; - ///< Return desired movement vector (determined based on movement settings, - /// stance and stats). - virtual Ogre::Vector3 getRotationVector (const MWWorld::Ptr& ptr) const; ///< Return desired rotations, as euler angles. diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 0ab18699d..5999979de 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -186,11 +186,6 @@ namespace MWWorld throw std::runtime_error ("movement settings not supported by class"); } - Ogre::Vector3 Class::getMovementVector (const Ptr& ptr) const - { - return Ogre::Vector3 (0, 0, 0); - } - Ogre::Vector3 Class::getRotationVector (const Ptr& ptr) const { return Ogre::Vector3 (0, 0, 0); diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 15058294f..02afd8960 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -192,10 +192,6 @@ namespace MWWorld virtual MWMechanics::Movement& getMovementSettings (const Ptr& ptr) const; ///< Return desired movement. - virtual Ogre::Vector3 getMovementVector (const Ptr& ptr) const; - ///< Return desired movement vector (determined based on movement settings, - /// stance and stats). - virtual Ogre::Vector3 getRotationVector (const Ptr& ptr) const; ///< Return desired rotations, as euler angles. diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index ef32e10dc..d62ff3f00 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -126,6 +126,10 @@ add_component_dir (fontloader fontloader ) +add_component_dir (sdlutil + sdlgraphicswindow + ) + add_component_dir (version version ) @@ -172,6 +176,7 @@ target_link_libraries(components ${OGRE_LIBRARIES} ${OPENSCENEGRAPH_LIBRARIES} ${BULLET_LIBRARIES} + ${SDL2_LIBRARY} # For MyGUI platform ${OPENGL_gl_LIBRARY} ) diff --git a/components/sdlutil/sdlgraphicswindow.cpp b/components/sdlutil/sdlgraphicswindow.cpp new file mode 100644 index 000000000..5a9db5923 --- /dev/null +++ b/components/sdlutil/sdlgraphicswindow.cpp @@ -0,0 +1,272 @@ +#include "sdlgraphicswindow.hpp" + +#include + +#include + +namespace SDLUtil +{ + +GraphicsWindowSDL2::~GraphicsWindowSDL2() +{ + close(true); +} + + +bool GraphicsWindowSDL2::setWindowDecorationImplementation(bool flag) +{ + if(!mWindow) return false; + + SDL_SetWindowBordered(mWindow, flag ? SDL_TRUE : SDL_FALSE); + return true; +} + +bool GraphicsWindowSDL2::setWindowRectangleImplementation(int x, int y, int width, int height) +{ + if(!mWindow) return false; + + SDL_SetWindowPosition(mWindow, x, y); + SDL_SetWindowSize(mWindow, width, height); + return true; +} + +void GraphicsWindowSDL2::setWindowName(const std::string &name) +{ + if(!mWindow) return; + + SDL_SetWindowTitle(mWindow, name.c_str()); + _traits->windowName = name; +} + +void GraphicsWindowSDL2::setCursor(MouseCursor mouseCursor) +{ + _traits->useCursor = false; +} + + +void GraphicsWindowSDL2::init() +{ + if(mValid) return; + + if(!_traits.valid()) + return; + + // getEventQueue()->setCurrentEventState(osgGA::GUIEventAdapter::getAccumulatedEventState().get()); + + WindowData *inheritedWindowData = dynamic_cast(_traits->inheritedWindowData.get()); + mWindow = inheritedWindowData ? inheritedWindowData->mWindow : NULL; + + mOwnsWindow = (mWindow == 0); + if(mOwnsWindow) + { + OSG_NOTICE<<"Error: No SDL window provided."<vsync); + + SDL_GL_MakeCurrent(oldWin, oldCtx); + + mValid = true; + + getEventQueue()->syncWindowRectangleWithGraphcisContext(); +} + + +bool GraphicsWindowSDL2::realizeImplementation() +{ + if(mRealized) + { + OSG_NOTICE<< "GraphicsWindowSDL2::realizeImplementation() Already realized" <syncWindowRectangleWithGraphcisContext(); + + mRealized = true; + + return true; +} + +bool GraphicsWindowSDL2::makeCurrentImplementation() +{ + if(!mRealized) + { + OSG_NOTICE<<"Warning: GraphicsWindow not realized, cannot do makeCurrent."<setNumFramesToRetainObjects(0); + osg::Referenced::getDeleteHandler()->flushAll(); + } + + //OSG_NOTICE<< "~SDL2WindowingSystemInterface()" <pbuffer) + return NULL; + + osg::ref_ptr window = new GraphicsWindowSDL2(traits); + if(window->valid()) return window.release(); + return NULL; + } +}; + +void setupWindowingSystemInterface() +{ + osg::GraphicsContext::setWindowingSystemInterface(new SDL2WindowingSystemInterface); +} + +} // namespace TK diff --git a/components/sdlutil/sdlgraphicswindow.hpp b/components/sdlutil/sdlgraphicswindow.hpp new file mode 100644 index 000000000..27b9e8e28 --- /dev/null +++ b/components/sdlutil/sdlgraphicswindow.hpp @@ -0,0 +1,108 @@ +#ifndef OSGGRAPHICSWINDOW_H +#define OSGGRAPHICSWINDOW_H + +#include + +#include + +namespace SDLUtil +{ + +class GraphicsWindowSDL2 : public osgViewer::GraphicsWindow +{ + SDL_Window* mWindow; + SDL_GLContext mContext; + + bool mValid; + bool mRealized; + bool mOwnsWindow; + + void init(); + + virtual ~GraphicsWindowSDL2(); + +public: + GraphicsWindowSDL2(osg::GraphicsContext::Traits *traits) + : mWindow(0) + , mContext(0) + , mValid(false) + , mRealized(false) + , mOwnsWindow(false) + { + _traits = traits; + + init(); + if(valid()) + { + setState(new osg::State); + getState()->setGraphicsContext(this); + + if(_traits.valid() && _traits->sharedContext.valid()) + { + getState()->setContextID(_traits->sharedContext->getState()->getContextID()); + incrementContextIDUsageCount(getState()->getContextID()); + } + else + { + getState()->setContextID(osg::GraphicsContext::createNewContextID()); + } + } + } + + virtual bool isSameKindAs(const Object* object) const { return dynamic_cast(object)!=0; } + virtual const char* libraryName() const { return "osgViewer"; } + virtual const char* className() const { return "GraphicsWindowSDL2"; } + + virtual bool valid() const { return mValid; } + + /** Realise the GraphicsContext.*/ + virtual bool realizeImplementation(); + + /** Return true if the graphics context has been realised and is ready to use.*/ + virtual bool isRealizedImplementation() const { return mRealized; } + + /** Close the graphics context.*/ + virtual void closeImplementation(); + + /** Make this graphics context current.*/ + virtual bool makeCurrentImplementation(); + + /** Release the graphics context.*/ + virtual bool releaseContextImplementation(); + + /** Swap the front and back buffers.*/ + virtual void swapBuffersImplementation(); + + /** Set sync-to-vblank. */ + virtual void setSyncToVBlank(bool on); + + /** Set Window decoration.*/ + virtual bool setWindowDecorationImplementation(bool flag); + + /** Raise specified window */ + virtual void raiseWindow(); + + /** Set the window's position and size.*/ + virtual bool setWindowRectangleImplementation(int x, int y, int width, int height); + + /** Set the name of the window */ + virtual void setWindowName(const std::string &name); + + /** Set mouse cursor to a specific shape.*/ + virtual void setCursor(MouseCursor cursor); + + /** WindowData is used to pass in the SDL2 window handle attached the GraphicsContext::Traits structure. */ + struct WindowData : public osg::Referenced + { + WindowData(SDL_Window *window) : mWindow(window) + { } + + SDL_Window *mWindow; + }; +}; + +void setupWindowingSystemInterface(); + +} // namespace TK + +#endif /* OSGGRAPHICSWINDOW_H */ From 36e0cfbc9dd20ca40b53ccd1eeeadce0fa2c45ce Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 13 May 2015 03:36:20 +0200 Subject: [PATCH 1164/3725] Cleanup --- apps/openmw/engine.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index a77b3e293..9270b07e8 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -201,7 +201,6 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) , mCfgMgr(configurationManager) { Misc::Rng::init(); - std::srand ( static_cast(std::time(NULL)) ); MWClass::registerClasses(); Uint32 flags = SDL_INIT_VIDEO|SDL_INIT_NOPARACHUTE|SDL_INIT_GAMECONTROLLER|SDL_INIT_JOYSTICK; @@ -219,6 +218,11 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) OMW::Engine::~Engine() { + mEnvironment.cleanup(); + + delete mScriptContext; + mScriptContext = NULL; + mResourceSystem.reset(); mViewer = NULL; @@ -226,8 +230,6 @@ OMW::Engine::~Engine() SDL_DestroyWindow(mWindow); mWindow = NULL; - mEnvironment.cleanup(); - delete mScriptContext; SDL_Quit(); } From 7f12fc47706076545505c9c0f80c7b6ed3cad531 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Wed, 13 May 2015 13:39:04 +1000 Subject: [PATCH 1165/3725] Fix for Bug #2544. Add a default mNpdtType to ESM::Npc::blank(). --- components/esm/loadnpc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esm/loadnpc.cpp b/components/esm/loadnpc.cpp index 751c7f252..44d298785 100644 --- a/components/esm/loadnpc.cpp +++ b/components/esm/loadnpc.cpp @@ -143,7 +143,7 @@ namespace ESM void NPC::blank() { - mNpdtType = 0; + mNpdtType = NPC_DEFAULT; mNpdt52.mLevel = 0; mNpdt52.mStrength = mNpdt52.mIntelligence = mNpdt52.mWillpower = mNpdt52.mAgility = mNpdt52.mSpeed = mNpdt52.mEndurance = mNpdt52.mPersonality = mNpdt52.mLuck = 0; From 0498e6e5f0fe36cc4a211733c15f97e4e4995660 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 13 May 2015 15:03:21 +0200 Subject: [PATCH 1166/3725] Readded window icon --- apps/openmw/engine.cpp | 26 +++++++++++++++++++++- apps/openmw/engine.hpp | 1 + components/CMakeLists.txt | 2 +- components/sdlutil/imagetosurface.cpp | 28 ++++++++++++++++++++++++ components/sdlutil/imagetosurface.hpp | 20 +++++++++++++++++ components/sdlutil/sdlgraphicswindow.cpp | 2 +- components/sdlutil/sdlgraphicswindow.hpp | 4 ++-- 7 files changed, 78 insertions(+), 5 deletions(-) create mode 100644 components/sdlutil/imagetosurface.cpp create mode 100644 components/sdlutil/imagetosurface.hpp diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 9270b07e8..7f98f6ad7 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -3,8 +3,11 @@ #include #include +#include + #include #include +#include #include @@ -14,6 +17,7 @@ #include #include +#include #include #include @@ -346,7 +350,7 @@ void OMW::Engine::createWindow(Settings::Manager& settings) return; } - // TODO: set window icon + setWindowIcon(); SDLUtil::setupWindowingSystemInterface(); @@ -377,6 +381,26 @@ void OMW::Engine::createWindow(Settings::Manager& settings) mViewer->realize(); } +void OMW::Engine::setWindowIcon() +{ + boost::filesystem::ifstream windowIconStream; + std::string windowIcon = (mResDir / "mygui" / "openmw.png").string(); + windowIconStream.open(windowIcon); + if (windowIconStream.fail()) + std::cerr << "Failed to open " << windowIcon << std::endl; + osgDB::ReaderWriter* reader = osgDB::Registry::instance()->getReaderWriterForExtension("png"); + osgDB::ReaderWriter::ReadResult result = reader->readImage(windowIconStream); + if (!result.success()) + std::cerr << "Failed to read " << windowIcon << ": " << result.message() << std::endl; + else + { + osg::ref_ptr image = result.getImage(); + SDL_Surface* surface = SDLUtil::imageToSurface(image); + SDL_SetWindowIcon(mWindow, surface); + SDL_FreeSurface(surface); + } +} + void OMW::Engine::prepareEngine (Settings::Manager & settings) { mEnvironment.setStateManager ( diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index 420121a8e..bb70c288d 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -116,6 +116,7 @@ namespace OMW void prepareEngine (Settings::Manager & settings); void createWindow(Settings::Manager& settings); + void setWindowIcon(); public: Engine(Files::ConfigurationManager& configurationManager); diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index d62ff3f00..e18871a64 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -127,7 +127,7 @@ add_component_dir (fontloader ) add_component_dir (sdlutil - sdlgraphicswindow + sdlgraphicswindow imagetosurface ) add_component_dir (version diff --git a/components/sdlutil/imagetosurface.cpp b/components/sdlutil/imagetosurface.cpp new file mode 100644 index 000000000..36e503c74 --- /dev/null +++ b/components/sdlutil/imagetosurface.cpp @@ -0,0 +1,28 @@ +#include "imagetosurface.hpp" + +#include +#include + +namespace SDLUtil +{ + +SDL_Surface* imageToSurface(osg::Image *image) +{ + int width = image->s(); + int height = image->t(); + SDL_Surface* surface = SDL_CreateRGBSurface(0, width, height, 32, 0xFF000000,0x00FF0000,0x0000FF00,0x000000FF); + + for(int x = 0; x < width; ++x) + for(int y = 0; y < height; ++y) + { + osg::Vec4f clr = image->getColor(x, (height-1)-y); + int bpp = surface->format->BytesPerPixel; + Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp; + *(Uint32*)(p) = SDL_MapRGBA(surface->format, static_cast(clr.r() * 255), + static_cast(clr.g() * 255), static_cast(clr.b() * 255), static_cast(clr.a() * 255)); + } + + return surface; +} + +} diff --git a/components/sdlutil/imagetosurface.hpp b/components/sdlutil/imagetosurface.hpp new file mode 100644 index 000000000..2c5df5cbd --- /dev/null +++ b/components/sdlutil/imagetosurface.hpp @@ -0,0 +1,20 @@ +#ifndef OPENMW_COMPONENTS_SDLUTIL_IMAGETOSURFACE_H +#define OPENMW_COMPONENTS_SDLUTIL_IMAGETOSURFACE_H + +struct SDL_Surface; + +namespace osg +{ + class Image; +} + +namespace SDLUtil +{ + + /// Convert an osg::Image to an SDL_Surface. + /// @note The returned surface must be freed using SDL_FreeSurface. + SDL_Surface* imageToSurface(osg::Image* image); + +} + +#endif diff --git a/components/sdlutil/sdlgraphicswindow.cpp b/components/sdlutil/sdlgraphicswindow.cpp index 5a9db5923..1424337ab 100644 --- a/components/sdlutil/sdlgraphicswindow.cpp +++ b/components/sdlutil/sdlgraphicswindow.cpp @@ -269,4 +269,4 @@ void setupWindowingSystemInterface() osg::GraphicsContext::setWindowingSystemInterface(new SDL2WindowingSystemInterface); } -} // namespace TK +} diff --git a/components/sdlutil/sdlgraphicswindow.hpp b/components/sdlutil/sdlgraphicswindow.hpp index 27b9e8e28..cfe40d98e 100644 --- a/components/sdlutil/sdlgraphicswindow.hpp +++ b/components/sdlutil/sdlgraphicswindow.hpp @@ -91,7 +91,7 @@ public: /** Set mouse cursor to a specific shape.*/ virtual void setCursor(MouseCursor cursor); - /** WindowData is used to pass in the SDL2 window handle attached the GraphicsContext::Traits structure. */ + /** WindowData is used to pass in the SDL2 window handle attached to the GraphicsContext::Traits structure. */ struct WindowData : public osg::Referenced { WindowData(SDL_Window *window) : mWindow(window) @@ -103,6 +103,6 @@ public: void setupWindowingSystemInterface(); -} // namespace TK +} #endif /* OSGGRAPHICSWINDOW_H */ From 298b3ed2efbf52ba2887aa8acacf4677b3cf0532 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 13 May 2015 15:08:47 +0200 Subject: [PATCH 1167/3725] Create the GraphicsWindowSDL2 directly --- apps/openmw/engine.cpp | 8 +- components/sdlutil/sdlgraphicswindow.cpp | 106 ----------------------- components/sdlutil/sdlgraphicswindow.hpp | 2 - 3 files changed, 3 insertions(+), 113 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 7f98f6ad7..98e1c5a28 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -352,8 +352,6 @@ void OMW::Engine::createWindow(Settings::Manager& settings) setWindowIcon(); - SDLUtil::setupWindowingSystemInterface(); - osg::ref_ptr traits = new osg::GraphicsContext::Traits; SDL_GetWindowPosition(mWindow, &traits->x, &traits->y); SDL_GetWindowSize(mWindow, &traits->width, &traits->height); @@ -371,11 +369,11 @@ void OMW::Engine::createWindow(Settings::Manager& settings) traits->doubleBuffer = true; traits->inheritedWindowData = new SDLUtil::GraphicsWindowSDL2::WindowData(mWindow); - osg::ref_ptr gc = osg::GraphicsContext::createGraphicsContext(traits.get()); - if(!gc.valid()) throw std::runtime_error("Failed to create GraphicsContext"); + osg::ref_ptr graphicsWindow = new SDLUtil::GraphicsWindowSDL2(traits); + if(!graphicsWindow->valid()) throw std::runtime_error("Failed to create GraphicsContext"); osg::ref_ptr camera = mViewer->getCamera(); - camera->setGraphicsContext(gc.get()); + camera->setGraphicsContext(graphicsWindow); camera->setViewport(0, 0, width, height); mViewer->realize(); diff --git a/components/sdlutil/sdlgraphicswindow.cpp b/components/sdlutil/sdlgraphicswindow.cpp index 1424337ab..6c7bac12e 100644 --- a/components/sdlutil/sdlgraphicswindow.cpp +++ b/components/sdlutil/sdlgraphicswindow.cpp @@ -163,110 +163,4 @@ void GraphicsWindowSDL2::raiseWindow() SDL_RaiseWindow(mWindow); } - -class SDL2WindowingSystemInterface : public osg::GraphicsContext::WindowingSystemInterface -{ -public: - SDL2WindowingSystemInterface() - { - OSG_INFO<< "SDL2WindowingSystemInterface()" <setNumFramesToRetainObjects(0); - osg::Referenced::getDeleteHandler()->flushAll(); - } - - //OSG_NOTICE<< "~SDL2WindowingSystemInterface()" <pbuffer) - return NULL; - - osg::ref_ptr window = new GraphicsWindowSDL2(traits); - if(window->valid()) return window.release(); - return NULL; - } -}; - -void setupWindowingSystemInterface() -{ - osg::GraphicsContext::setWindowingSystemInterface(new SDL2WindowingSystemInterface); -} - } diff --git a/components/sdlutil/sdlgraphicswindow.hpp b/components/sdlutil/sdlgraphicswindow.hpp index cfe40d98e..45cf47002 100644 --- a/components/sdlutil/sdlgraphicswindow.hpp +++ b/components/sdlutil/sdlgraphicswindow.hpp @@ -101,8 +101,6 @@ public: }; }; -void setupWindowingSystemInterface(); - } #endif /* OSGGRAPHICSWINDOW_H */ From 39fb46601a71342366b2dee79fe01849c432160e Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 13 May 2015 16:50:47 +0200 Subject: [PATCH 1168/3725] Readded input & event handling --- apps/openmw/engine.cpp | 2 +- apps/openmw/mwinput/inputmanagerimp.cpp | 72 +++++----- apps/openmw/mwinput/inputmanagerimp.hpp | 37 +++-- components/CMakeLists.txt | 2 +- .../sdlutil/OISCompat.hpp | 0 .../events.h => components/sdlutil/events.hpp | 3 +- components/sdlutil/sdlgraphicswindow.cpp | 27 ++++ components/sdlutil/sdlgraphicswindow.hpp | 33 +---- .../sdlutil}/sdlinputwrapper.cpp | 43 +++--- .../sdlutil}/sdlinputwrapper.hpp | 42 +++--- extern/oics/ICSInputControlSystem.h | 27 ++-- extern/oics/ICSInputControlSystem_mouse.cpp | 6 +- extern/sdl4ogre/imagerotate.cpp | 99 ------------- extern/sdl4ogre/imagerotate.hpp | 25 ---- extern/sdl4ogre/osx_utils.h | 12 -- extern/sdl4ogre/osx_utils.mm | 15 -- extern/sdl4ogre/sdlwindowhelper.cpp | 130 ------------------ extern/sdl4ogre/sdlwindowhelper.hpp | 31 ----- 18 files changed, 150 insertions(+), 456 deletions(-) rename extern/sdl4ogre/OISCompat.h => components/sdlutil/OISCompat.hpp (100%) rename extern/sdl4ogre/events.h => components/sdlutil/events.hpp (99%) rename {extern/sdl4ogre => components/sdlutil}/sdlinputwrapper.cpp (94%) rename {extern/sdl4ogre => components/sdlutil}/sdlinputwrapper.hpp (70%) delete mode 100644 extern/sdl4ogre/imagerotate.cpp delete mode 100644 extern/sdl4ogre/imagerotate.hpp delete mode 100644 extern/sdl4ogre/osx_utils.h delete mode 100644 extern/sdl4ogre/osx_utils.mm delete mode 100644 extern/sdl4ogre/sdlwindowhelper.cpp delete mode 100644 extern/sdl4ogre/sdlwindowhelper.hpp diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 98e1c5a28..08d77e7af 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -442,7 +442,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) gameControllerdb = ""; //if it doesn't exist, pass in an empty string // FIXME: shouldn't depend on Engine - MWInput::InputManager* input = new MWInput::InputManager (*this, keybinderUser, keybinderUserExists, gameControllerdb, mGrab); + MWInput::InputManager* input = new MWInput::InputManager (mWindow, mViewer, *this, keybinderUser, keybinderUserExists, gameControllerdb, mGrab); mEnvironment.setInputManager (input); std::string myguiResources = (mResDir / "mygui").string(); diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 62d3bdd03..0fc25db4c 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -1,8 +1,7 @@ #include "inputmanagerimp.hpp" -#include -#include #include +#include #include @@ -14,6 +13,8 @@ #include +#include + #include "../engine.hpp" #include "../mwbase/world.hpp" @@ -31,8 +32,6 @@ #include "../mwdialogue/dialoguemanagerimp.hpp" -#include - using namespace ICS; namespace @@ -97,6 +96,8 @@ namespace namespace MWInput { InputManager::InputManager( + SDL_Window* window, + osg::ref_ptr viewer, OMW::Engine& engine, const std::string& userFile, bool userFileExists, const std::string& controllerBindingsFile, bool grab) @@ -118,8 +119,8 @@ namespace MWInput , mGuiCursorEnabled(true) , mDetectingKeyboard(false) , mOverencumberedMessageDelay(0.f) - , mMouseX(0)//ogre.getWindow()->getWidth ()/2.f) - , mMouseY(0)//ogre.getWindow()->getHeight ()/2.f) + , mMouseX(0) + , mMouseY(0) , mMouseWheel(0) , mUserFileExists(userFileExists) , mAlwaysRunActive(Settings::Manager::getBool("always run", "Input")) @@ -128,19 +129,20 @@ namespace MWInput , mAttemptJump(false) , mFakeDeviceID(1) { + int w,h; + SDL_GetWindowSize(window, &w, &h); + + mMouseX = w / 2.f; + mMouseY = h / 2.f; - /* - Ogre::RenderWindow* window = ogre.getWindow (); - mInputManager = new SFO::InputWrapper(mOgre.getSDLWindow(), mOgre.getWindow(), grab); + mInputManager = new SDLUtil::InputWrapper(window, viewer, grab); mInputManager->setMouseEventCallback (this); mInputManager->setKeyboardEventCallback (this); mInputManager->setWindowEventCallback(this); mInputManager->setControllerEventCallback(this); - */ std::string file = userFileExists ? userFile : ""; mInputBinder = new ICS::InputControlSystem(file, true, this, NULL, A_Last); - //adjustMouseRegion (window->getWidth(), window->getHeight()); loadKeyDefaults(); loadControllerDefaults(); @@ -198,7 +200,7 @@ namespace MWInput delete mInputBinder; - //delete mInputManager; + delete mInputManager; } void InputManager::setPlayerControlsEnabled(bool enabled) @@ -365,24 +367,24 @@ namespace MWInput void InputManager::updateCursorMode() { - //bool grab = !MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_MainMenu) - // && MWBase::Environment::get().getWindowManager()->getMode() != MWGui::GM_Console; + bool grab = !MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_MainMenu) + && MWBase::Environment::get().getWindowManager()->getMode() != MWGui::GM_Console; - bool was_relative = 0;//mInputManager->getMouseRelative(); + bool was_relative = mInputManager->getMouseRelative(); 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 - //mInputManager->setMouseRelative(is_relative); + mInputManager->setMouseRelative(is_relative); //we let the mouse escape in the main menu - //mInputManager->setGrabPointer(grab && (mGrabCursor || is_relative)); + mInputManager->setGrabPointer(grab && (mGrabCursor || is_relative)); //we switched to non-relative mode, move our cursor to where the in-game //cursor is if( !is_relative && was_relative != is_relative ) { - //mInputManager->warpMouse(static_cast(mMouseX), static_cast(mMouseY)); + mInputManager->warpMouse(static_cast(mMouseX), static_cast(mMouseY)); } } @@ -390,9 +392,9 @@ namespace MWInput { mControlsDisabled = disableControls; - //mInputManager->setMouseVisible(MWBase::Environment::get().getWindowManager()->getCursorVisible()); + mInputManager->setMouseVisible(MWBase::Environment::get().getWindowManager()->getCursorVisible()); - //mInputManager->capture(disableEvents); + mInputManager->capture(disableEvents); // inject some fake mouse movement to force updating MyGUI's widget states MyGUI::InputManager::getInstance().injectMouseMove( int(mMouseX), int(mMouseY), mMouseWheel); @@ -426,7 +428,7 @@ namespace MWInput mMouseY = std::max(0.f, std::min(mMouseY, float(viewSize.height))); MyGUI::InputManager::getInstance().injectMouseMove(static_cast(mMouseX), static_cast(mMouseY), mMouseWheel); - //mInputManager->warpMouse(static_cast(mMouseX), static_cast(mMouseY)); + mInputManager->warpMouse(static_cast(mMouseX), static_cast(mMouseY)); } if (mMouseLookEnabled) { @@ -657,17 +659,11 @@ namespace MWInput mControlSwitch[sw] = value; } - void InputManager::adjustMouseRegion(int width, int height) - { - mInputBinder->adjustMouseRegion(width, height); - } - void InputManager::keyPressed( const SDL_KeyboardEvent &arg ) { // HACK: to make Morrowind's default keybinding for the console work without printing an extra "^" upon closing // This assumes that SDL_TextInput events always come *after* the key event // (which is somewhat reasonable, and hopefully true for all SDL platforms) - /* OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(arg.keysym.sym); if (mInputBinder->getKeyBinding(mInputBinder->getControl(A_Console), ICS::Control::INCREASE) == arg.keysym.scancode @@ -685,7 +681,6 @@ namespace MWInput if (!mControlsDisabled && !consumed) mInputBinder->keyPressed (arg); mJoystickLastUsed = false; - */ } void InputManager::textInput(const SDL_TextInputEvent &arg) @@ -698,13 +693,11 @@ namespace MWInput void InputManager::keyReleased(const SDL_KeyboardEvent &arg ) { - /* mJoystickLastUsed = false; OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(arg.keysym.sym); setPlayerControlsEnabled(!MyGUI::InputManager::getInstance().injectKeyRelease(MyGUI::KeyCode::Enum(kc))); mInputBinder->keyReleased (arg); - */ } void InputManager::mousePressed( const SDL_MouseButtonEvent &arg, Uint8 id ) @@ -751,7 +744,7 @@ namespace MWInput } } - void InputManager::mouseMoved(const SFO::MouseMotionEvent &arg ) + void InputManager::mouseMoved(const SDLUtil::MouseMotionEvent &arg ) { mInputBinder->mouseMoved (arg); @@ -830,9 +823,9 @@ namespace MWInput setPlayerControlsEnabled(!guiMode); //esc, to leave initial movie screen - //OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(SDLK_ESCAPE); - //bool guiFocus = MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::Enum(kc), 0); - //setPlayerControlsEnabled(!guiFocus); + OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(SDLK_ESCAPE); + bool guiFocus = MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::Enum(kc), 0); + setPlayerControlsEnabled(!guiFocus); if (!mControlsDisabled) mInputBinder->buttonPressed(deviceID, arg); @@ -857,8 +850,8 @@ namespace MWInput mInputBinder->buttonReleased(deviceID, arg); ///to escape initial movie - //OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(SDLK_ESCAPE); - //setPlayerControlsEnabled(!MyGUI::InputManager::getInstance().injectKeyRelease(MyGUI::KeyCode::Enum(kc))); + OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(SDLK_ESCAPE); + setPlayerControlsEnabled(!MyGUI::InputManager::getInstance().injectKeyRelease(MyGUI::KeyCode::Enum(kc))); } void InputManager::axisMoved(int deviceID, const SDL_ControllerAxisEvent &arg ) @@ -883,12 +876,15 @@ namespace MWInput void InputManager::windowVisibilityChange(bool visible) { - //TODO: Pause game? + //TODO: Pause game? } void InputManager::windowResized(int x, int y) { - //mOgre.windowResized(x,y); + Settings::Manager::setInt("resolution x", "Video", x); + Settings::Manager::setInt("resolution y", "Video", y); + + MWBase::Environment::get().getWindowManager()->windowResized(x, y); } void InputManager::windowClosed() diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index cd80ed460..27c08ed32 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -3,11 +3,17 @@ #include "../mwgui/mode.hpp" +#include + +#include +#include + #include #include +#include #include "../mwbase/inputmanager.hpp" -#include + namespace MWWorld { @@ -39,8 +45,17 @@ namespace Files struct ConfigurationManager; } -#include -#include +namespace SDLUtil +{ + class InputWrapper; +} + +namespace osgViewer +{ + class Viewer; +} + +struct SDL_Window; namespace MWInput { @@ -50,15 +65,17 @@ namespace MWInput */ class InputManager : public MWBase::InputManager, - public SFO::KeyListener, - public SFO::MouseListener, - public SFO::WindowListener, - public SFO::ControllerListener, + public SDLUtil::KeyListener, + public SDLUtil::MouseListener, + public SDLUtil::WindowListener, + public SDLUtil::ControllerListener, public ICS::ChannelListener, public ICS::DetectingBindingListener { public: InputManager( + SDL_Window* window, + osg::ref_ptr viewer, OMW::Engine& engine, const std::string& userFile, bool userFileExists, const std::string& controllerBindingsFile, bool grab); @@ -100,7 +117,7 @@ namespace MWInput virtual void mousePressed( const SDL_MouseButtonEvent &arg, Uint8 id ); virtual void mouseReleased( const SDL_MouseButtonEvent &arg, Uint8 id ); - virtual void mouseMoved( const SFO::MouseMotionEvent &arg ); + virtual void mouseMoved( const SDLUtil::MouseMotionEvent &arg ); virtual void buttonPressed(int deviceID, const SDL_ControllerButtonEvent &arg); virtual void buttonReleased(int deviceID, const SDL_ControllerButtonEvent &arg); @@ -140,8 +157,7 @@ namespace MWInput ICS::InputControlSystem* mInputBinder; - - SFO::InputWrapper* mInputManager; + SDLUtil::InputWrapper* mInputManager; std::string mUserFile; @@ -178,7 +194,6 @@ namespace MWInput std::map mControlSwitch; private: - void adjustMouseRegion(int width, int height); MyGUI::MouseButton sdlButtonToMyGUI(Uint8 button); virtual std::string sdlControllerAxisToString(int axis); diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index e18871a64..6590c7e99 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -127,7 +127,7 @@ add_component_dir (fontloader ) add_component_dir (sdlutil - sdlgraphicswindow imagetosurface + sdlgraphicswindow imagetosurface sdlinputwrapper OISCompat events ) add_component_dir (version diff --git a/extern/sdl4ogre/OISCompat.h b/components/sdlutil/OISCompat.hpp similarity index 100% rename from extern/sdl4ogre/OISCompat.h rename to components/sdlutil/OISCompat.hpp diff --git a/extern/sdl4ogre/events.h b/components/sdlutil/events.hpp similarity index 99% rename from extern/sdl4ogre/events.h rename to components/sdlutil/events.hpp index 986dd7d8b..7c79470ff 100644 --- a/extern/sdl4ogre/events.h +++ b/components/sdlutil/events.hpp @@ -8,7 +8,8 @@ // Events // //////////// -namespace SFO { +namespace SDLUtil +{ /** Extended mouse event struct where we treat the wheel like an axis, like everyone expects */ struct MouseMotionEvent : SDL_MouseMotionEvent { diff --git a/components/sdlutil/sdlgraphicswindow.cpp b/components/sdlutil/sdlgraphicswindow.cpp index 6c7bac12e..c69fcca64 100644 --- a/components/sdlutil/sdlgraphicswindow.cpp +++ b/components/sdlutil/sdlgraphicswindow.cpp @@ -12,6 +12,33 @@ GraphicsWindowSDL2::~GraphicsWindowSDL2() close(true); } +GraphicsWindowSDL2::GraphicsWindowSDL2(osg::GraphicsContext::Traits *traits) + : mWindow(0) + , mContext(0) + , mValid(false) + , mRealized(false) + , mOwnsWindow(false) +{ + _traits = traits; + + init(); + if(valid()) + { + setState(new osg::State); + getState()->setGraphicsContext(this); + + if(_traits.valid() && _traits->sharedContext.valid()) + { + getState()->setContextID(_traits->sharedContext->getState()->getContextID()); + incrementContextIDUsageCount(getState()->getContextID()); + } + else + { + getState()->setContextID(osg::GraphicsContext::createNewContextID()); + } + } +} + bool GraphicsWindowSDL2::setWindowDecorationImplementation(bool flag) { diff --git a/components/sdlutil/sdlgraphicswindow.hpp b/components/sdlutil/sdlgraphicswindow.hpp index 45cf47002..b2b7cfaf0 100644 --- a/components/sdlutil/sdlgraphicswindow.hpp +++ b/components/sdlutil/sdlgraphicswindow.hpp @@ -1,7 +1,7 @@ -#ifndef OSGGRAPHICSWINDOW_H -#define OSGGRAPHICSWINDOW_H +#ifndef OPENMW_COMPONENTS_SDLUTIL_SDLGRAPHICSWINDOW_H +#define OPENMW_COMPONENTS_SDLUTIL_SDLGRAPHICSWINDOW_H -#include +#include #include @@ -22,32 +22,7 @@ class GraphicsWindowSDL2 : public osgViewer::GraphicsWindow virtual ~GraphicsWindowSDL2(); public: - GraphicsWindowSDL2(osg::GraphicsContext::Traits *traits) - : mWindow(0) - , mContext(0) - , mValid(false) - , mRealized(false) - , mOwnsWindow(false) - { - _traits = traits; - - init(); - if(valid()) - { - setState(new osg::State); - getState()->setGraphicsContext(this); - - if(_traits.valid() && _traits->sharedContext.valid()) - { - getState()->setContextID(_traits->sharedContext->getState()->getContextID()); - incrementContextIDUsageCount(getState()->getContextID()); - } - else - { - getState()->setContextID(osg::GraphicsContext::createNewContextID()); - } - } - } + GraphicsWindowSDL2(osg::GraphicsContext::Traits *traits); virtual bool isSameKindAs(const Object* object) const { return dynamic_cast(object)!=0; } virtual const char* libraryName() const { return "osgViewer"; } diff --git a/extern/sdl4ogre/sdlinputwrapper.cpp b/components/sdlutil/sdlinputwrapper.cpp similarity index 94% rename from extern/sdl4ogre/sdlinputwrapper.cpp rename to components/sdlutil/sdlinputwrapper.cpp index aaf669ff4..44492cf6c 100644 --- a/extern/sdl4ogre/sdlinputwrapper.cpp +++ b/components/sdlutil/sdlinputwrapper.cpp @@ -1,17 +1,16 @@ #include "sdlinputwrapper.hpp" -#include -#include -#include +#include +#include +#include -namespace SFO +namespace SDLUtil { - /// \brief General purpose wrapper for OGRE applications around SDL's event - /// queue, mostly used for handling input-related events. - InputWrapper::InputWrapper(SDL_Window* window, Ogre::RenderWindow* ogreWindow, bool grab) : + +InputWrapper::InputWrapper(SDL_Window* window, osg::ref_ptr viewer, bool grab) : mSDLWindow(window), - mOgreWindow(ogreWindow), + mViewer(viewer), mWarpCompensate(false), mMouseRelative(false), mGrabPointer(false), @@ -147,28 +146,26 @@ namespace SFO mMouseInWindow = false; updateMouseSettings(); break; + case SDL_WINDOWEVENT_MOVED: + // I'm not sure what OSG is using the window position for, but I don't think it's needed, + // so we ignore window moved events (improves window movement performance) + break; case SDL_WINDOWEVENT_SIZE_CHANGED: int w,h; SDL_GetWindowSize(mSDLWindow, &w, &h); - // TODO: Fix Ogre to handle this more consistently (fixed in 1.9) -#if OGRE_PLATFORM == OGRE_PLATFORM_LINUX - mOgreWindow->resize(w, h); -#else - mOgreWindow->windowMovedOrResized(); -#endif + int x,y; + SDL_GetWindowPosition(mSDLWindow, &x,&y); + mViewer->getCamera()->getGraphicsContext()->resized(x,y,w,h); + + mViewer->getEventQueue()->windowResize(x,y,w,h); + if (mWindowListener) mWindowListener->windowResized(w, h); + break; case SDL_WINDOWEVENT_RESIZED: - // TODO: Fix Ogre to handle this more consistently (fixed in 1.9) -#if OGRE_PLATFORM == OGRE_PLATFORM_LINUX - mOgreWindow->resize(evt.window.data1, evt.window.data2); -#else - mOgreWindow->windowMovedOrResized(); -#endif - if (mWindowListener) - mWindowListener->windowResized(evt.window.data1, evt.window.data2); + // This should also fire SIZE_CHANGED, so no need to handle break; case SDL_WINDOWEVENT_FOCUS_GAINED: @@ -187,12 +184,10 @@ namespace SFO case SDL_WINDOWEVENT_CLOSE: break; case SDL_WINDOWEVENT_SHOWN: - mOgreWindow->setVisible(true); if (mWindowListener) mWindowListener->windowVisibilityChange(true); break; case SDL_WINDOWEVENT_HIDDEN: - mOgreWindow->setVisible(false); if (mWindowListener) mWindowListener->windowVisibilityChange(false); break; diff --git a/extern/sdl4ogre/sdlinputwrapper.hpp b/components/sdlutil/sdlinputwrapper.hpp similarity index 70% rename from extern/sdl4ogre/sdlinputwrapper.hpp rename to components/sdlutil/sdlinputwrapper.hpp index a7023207c..bdb5842ae 100644 --- a/extern/sdl4ogre/sdlinputwrapper.hpp +++ b/components/sdlutil/sdlinputwrapper.hpp @@ -1,24 +1,27 @@ -#ifndef SDL4OGRE_SDLINPUTWRAPPER_H -#define SDL4OGRE_SDLINPUTWRAPPER_H +#ifndef OPENMW_COMPONENTS_SDLUTIL_SDLINPUTWRAPPER_H +#define OPENMW_COMPONENTS_SDLUTIL_SDLINPUTWRAPPER_H -#define NOMINMAX +#include -#include - -#include -#include +#include -#include "OISCompat.h" -#include "events.h" +#include +#include "OISCompat.hpp" +#include "events.hpp" +namespace osgViewer +{ + class Viewer; +} -namespace SFO +namespace SDLUtil { + /// \brief A wrapper around SDL's event queue, mostly used for handling input-related events. class InputWrapper { public: - InputWrapper(SDL_Window *window, Ogre::RenderWindow* ogreWindow, bool grab); + InputWrapper(SDL_Window *window, osg::ref_ptr viewer, bool grab); ~InputWrapper(); void setMouseEventCallback(MouseListener* listen) { mMouseListener = listen; } @@ -42,7 +45,6 @@ namespace SFO void updateMouseSettings(); private: - void handleWindowEvent(const SDL_Event& evt); bool _handleWarpMotion(const SDL_MouseMotionEvent& evt); @@ -51,12 +53,15 @@ namespace SFO void _setupOISKeys(); - SFO::MouseListener* mMouseListener; - SFO::KeyListener* mKeyboardListener; - SFO::WindowListener* mWindowListener; - SFO::ControllerListener* mConListener; + SDL_Window* mSDLWindow; + osg::ref_ptr mViewer; + + MouseListener* mMouseListener; + KeyListener* mKeyboardListener; + WindowListener* mWindowListener; + ControllerListener* mConListener; - typedef boost::unordered_map KeyMap; + typedef std::map KeyMap; KeyMap mKeyMap; Uint16 mWarpX; @@ -79,9 +84,6 @@ namespace SFO bool mWindowHasFocus; bool mMouseInWindow; - - SDL_Window* mSDLWindow; - Ogre::RenderWindow* mOgreWindow; }; } diff --git a/extern/oics/ICSInputControlSystem.h b/extern/oics/ICSInputControlSystem.h index 51b701b48..a82a11d75 100644 --- a/extern/oics/ICSInputControlSystem.h +++ b/extern/oics/ICSInputControlSystem.h @@ -32,8 +32,6 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "ICSControl.h" #include "ICSChannel.h" -#include "../sdl4ogre/events.h" - #include "boost/lexical_cast.hpp" #define ICS_LOG(text) if(mLog) mLog->logMessage( ("ICS: " + std::string(text)).c_str() ); @@ -51,11 +49,8 @@ namespace ICS virtual void logMessage(const char* text) = 0; }; - class DllExport InputControlSystem : - public SFO::MouseListener, - public SFO::KeyListener, - public SFO::ControllerListener - { + class DllExport InputControlSystem + { public: @@ -64,7 +59,7 @@ namespace ICS typedef NamedAxis MouseAxis; // MouseAxis is deprecated. It will be removed in future versions - typedef std::map JoystickInstanceMap; + typedef std::map JoystickInstanceMap; typedef std::list JoystickIDList; typedef struct @@ -101,13 +96,13 @@ namespace ICS inline void activate(){ this->mActive = true; }; inline void deactivate(){ this->mActive = false; }; - void controllerAdded (int deviceID, const SDL_ControllerDeviceEvent &args); + void controllerAdded (int deviceID, const SDL_ControllerDeviceEvent &args); void controllerRemoved(const SDL_ControllerDeviceEvent &args); - JoystickIDList& getJoystickIdList(){ return mJoystickIDList; }; + JoystickIDList& getJoystickIdList(){ return mJoystickIDList; }; JoystickInstanceMap& getJoystickInstanceMap(){ return mJoystickInstanceMap; }; // MouseListener - void mouseMoved(const SFO::MouseMotionEvent &evt); + void mouseMoved(const SDL_MouseMotionEvent &evt); void mousePressed(const SDL_MouseButtonEvent &evt, Uint8); void mouseReleased(const SDL_MouseButtonEvent &evt, Uint8); @@ -185,9 +180,9 @@ namespace ICS typedef std::map ControlsKeyBinderMapType; // typedef std::map ControlsAxisBinderMapType; // - typedef std::map ControlsButtonBinderMapType; // - - typedef std::map JoystickAxisBinderMapType; // > + typedef std::map ControlsButtonBinderMapType; // + + typedef std::map JoystickAxisBinderMapType; // > typedef std::map JoystickButtonBinderMapType; // > ControlsAxisBinderMapType mControlsMouseAxisBinderMap; // @@ -210,7 +205,7 @@ namespace ICS bool mXmouseAxisBinded; bool mYmouseAxisBinded; - JoystickIDList mJoystickIDList; + JoystickIDList mJoystickIDList; JoystickInstanceMap mJoystickInstanceMap; int mMouseAxisBindingInitialValues[3]; @@ -237,7 +232,7 @@ namespace ICS , int axis, Control::ControlChangingDirection direction); virtual void joystickButtonBindingDetected(InputControlSystem* ICS, int deviceID, Control* control - , unsigned int button, Control::ControlChangingDirection direction); + , unsigned int button, Control::ControlChangingDirection direction); }; diff --git a/extern/oics/ICSInputControlSystem_mouse.cpp b/extern/oics/ICSInputControlSystem_mouse.cpp index 9742d389c..5decaf1eb 100644 --- a/extern/oics/ICSInputControlSystem_mouse.cpp +++ b/extern/oics/ICSInputControlSystem_mouse.cpp @@ -224,11 +224,11 @@ namespace ICS } // mouse Listeners - void InputControlSystem::mouseMoved(const SFO::MouseMotionEvent& evt) + void InputControlSystem::mouseMoved(const SDL_MouseMotionEvent& evt) { if(mActive) { - if(!mDetectingBindingControl) + if(!mDetectingBindingControl) { if(mXmouseAxisBinded && evt.xrel) { @@ -289,7 +289,7 @@ namespace ICS mMouseAxisBindingInitialValues[0] += evt.xrel; mMouseAxisBindingInitialValues[1] += evt.yrel; - mMouseAxisBindingInitialValues[2] += evt.zrel; + // mMouseAxisBindingInitialValues[2] += evt.zrel; if( abs(mMouseAxisBindingInitialValues[0]) > ICS_MOUSE_BINDING_MARGIN ) { diff --git a/extern/sdl4ogre/imagerotate.cpp b/extern/sdl4ogre/imagerotate.cpp deleted file mode 100644 index b825943fc..000000000 --- a/extern/sdl4ogre/imagerotate.cpp +++ /dev/null @@ -1,99 +0,0 @@ -#include "imagerotate.hpp" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace Ogre; - -namespace SFO -{ - -void ImageRotate::rotate(const std::string& sourceImage, const std::string& destImage, const float angle) -{ - Root* root = Ogre::Root::getSingletonPtr(); - - std::string destImageRot = std::string(destImage) + std::string("_rot"); - - SceneManager* sceneMgr = root->createSceneManager(ST_GENERIC); - Camera* camera = sceneMgr->createCamera("ImageRotateCamera"); - - MaterialPtr material = MaterialManager::getSingleton().create("ImageRotateMaterial", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); - material->getTechnique(0)->getPass(0)->setLightingEnabled(false); - material->getTechnique(0)->getPass(0)->setDepthCheckEnabled(false); - TextureUnitState* tus = material->getTechnique(0)->getPass(0)->createTextureUnitState(sourceImage); - Degree deg(angle); - tus->setTextureRotate(Radian(deg.valueRadians())); - tus->setTextureAddressingMode(TextureUnitState::TAM_BORDER); - tus->setTextureBorderColour(ColourValue(0, 0, 0, 0)); - - Rectangle2D* rect = new Rectangle2D(true); - rect->setCorners(-1.0, 1.0, 1.0, -1.0); - rect->setMaterial("ImageRotateMaterial"); - // Render the background before everything else - rect->setRenderQueueGroup(RENDER_QUEUE_BACKGROUND); - - // Use infinite AAB to always stay visible - AxisAlignedBox aabInf; - aabInf.setInfinite(); - rect->setBoundingBox(aabInf); - - // Attach background to the scene - SceneNode* node = sceneMgr->getRootSceneNode()->createChildSceneNode(); - node->attachObject(rect); - - // retrieve image width and height - TexturePtr sourceTexture = TextureManager::getSingleton().getByName(sourceImage); - unsigned int width = sourceTexture->getWidth(); - unsigned int height = sourceTexture->getHeight(); - - TexturePtr destTextureRot = TextureManager::getSingleton().createManual( - destImageRot, - ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - TEX_TYPE_2D, - width, height, - 0, - PF_A8B8G8R8, - TU_RENDERTARGET); - - RenderTarget* rtt = destTextureRot->getBuffer()->getRenderTarget(); - rtt->setAutoUpdated(false); - Viewport* vp = rtt->addViewport(camera); - vp->setOverlaysEnabled(false); - vp->setShadowsEnabled(false); - vp->setBackgroundColour(ColourValue(0,0,0,0)); - - rtt->update(); - - //copy the rotated image to a static texture - TexturePtr destTexture = TextureManager::getSingleton().createManual( - destImage, - ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - TEX_TYPE_2D, - width, height, - 0, - PF_A8B8G8R8, - Ogre::TU_STATIC); - - destTexture->getBuffer()->blit(destTextureRot->getBuffer()); - - // remove all the junk we've created - TextureManager::getSingleton().remove(destImageRot); - MaterialManager::getSingleton().remove("ImageRotateMaterial"); - root->destroySceneManager(sceneMgr); - delete rect; -} - -} diff --git a/extern/sdl4ogre/imagerotate.hpp b/extern/sdl4ogre/imagerotate.hpp deleted file mode 100644 index 7135a571a..000000000 --- a/extern/sdl4ogre/imagerotate.hpp +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef OENGINE_OGRE_IMAGEROTATE_HPP -#define OENGINE_OGRE_IMAGEROTATE_HPP - -#include - - -namespace SFO -{ - - /// Rotate an image by certain degrees and save as file, uses the GPU - /// Make sure Ogre Root is initialised before calling - class ImageRotate - { - public: - /** - * @param source image (file name - has to exist in an resource group) - * @param name of the destination texture to save to (in memory) - * @param angle in degrees to turn - */ - static void rotate(const std::string& sourceImage, const std::string& destImage, const float angle); - }; - -} - -#endif diff --git a/extern/sdl4ogre/osx_utils.h b/extern/sdl4ogre/osx_utils.h deleted file mode 100644 index 48149827a..000000000 --- a/extern/sdl4ogre/osx_utils.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef SDL4OGRE_OSX_UTILS_H -#define SDL4OGRE_OSX_UTILS_H - -#include - -namespace SFO { - -extern unsigned long WindowContentViewHandle(SDL_SysWMinfo &info); - -} - -#endif // SDL4OGRE_OSX_UTILS_H diff --git a/extern/sdl4ogre/osx_utils.mm b/extern/sdl4ogre/osx_utils.mm deleted file mode 100644 index 4069959cb..000000000 --- a/extern/sdl4ogre/osx_utils.mm +++ /dev/null @@ -1,15 +0,0 @@ -#include "osx_utils.h" -#import - - -namespace SFO { - -unsigned long WindowContentViewHandle(SDL_SysWMinfo &info) -{ - NSWindow *window = info.info.cocoa.window; - NSView *view = [window contentView]; - - return (unsigned long)view; -} - -} diff --git a/extern/sdl4ogre/sdlwindowhelper.cpp b/extern/sdl4ogre/sdlwindowhelper.cpp deleted file mode 100644 index 637fae0ef..000000000 --- a/extern/sdl4ogre/sdlwindowhelper.cpp +++ /dev/null @@ -1,130 +0,0 @@ -#include "sdlwindowhelper.hpp" - -#include -#include -#include - -#include -#include -#include - -#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE -#include "osx_utils.h" -#endif - -namespace SFO -{ - -SDLWindowHelper::SDLWindowHelper (SDL_Window* window, int w, int h, - const std::string& title, bool fullscreen, Ogre::NameValuePairList params) - : mSDLWindow(window) -{ - //get the native whnd - struct SDL_SysWMinfo wmInfo; - SDL_VERSION(&wmInfo.version); - - if (SDL_GetWindowWMInfo(mSDLWindow, &wmInfo) == SDL_FALSE) - throw std::runtime_error("Couldn't get WM Info!"); - - Ogre::String winHandle; - - switch (wmInfo.subsystem) - { -#ifdef WIN32 - case SDL_SYSWM_WINDOWS: - // Windows code - winHandle = Ogre::StringConverter::toString((uintptr_t)wmInfo.info.win.window); - break; -#elif __MACOSX__ - case SDL_SYSWM_COCOA: - //required to make OGRE play nice with our window - params.insert(std::make_pair("macAPI", "cocoa")); - params.insert(std::make_pair("macAPICocoaUseNSView", "true")); - winHandle = Ogre::StringConverter::toString(WindowContentViewHandle(wmInfo)); - break; -#elif ANDROID - case SDL_SYSWM_ANDROID: - winHandle = Ogre::StringConverter::toString((unsigned long)wmInfo.info.android.window); - break; - #else - case SDL_SYSWM_X11: - winHandle = Ogre::StringConverter::toString((unsigned long)wmInfo.info.x11.window); - break; -#endif - default: - throw std::runtime_error("Unexpected WM!"); - break; - } - - /// \todo externalWindowHandle is deprecated according to the source code. Figure out a way to get parentWindowHandle - /// to work properly. On Linux/X11 it causes an occasional GLXBadDrawable error. - -#ifdef ANDROID - SDL_GLContext context= SDL_GL_CreateContext(window); - params.insert(std::make_pair("currentGLContext","True")); -#endif - params.insert(std::make_pair("externalWindowHandle", winHandle)); - - mWindow = Ogre::Root::getSingleton().createRenderWindow(title, w, h, fullscreen, ¶ms); -} - -void SDLWindowHelper::setWindowIcon(const std::string &name) -{ - Ogre::TexturePtr texture = Ogre::TextureManager::getSingleton().load(name, Ogre::ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME); - if (texture.isNull()) - { - std::stringstream error; - error << "Window icon not found: " << name; - throw std::runtime_error(error.str()); - } - Ogre::Image image; - texture->convertToImage(image); - - SDL_Surface* surface = SDL_CreateRGBSurface(0,texture->getWidth(),texture->getHeight(),32,0xFF000000,0x00FF0000,0x0000FF00,0x000000FF); - - //copy the Ogre texture to an SDL surface - for(size_t x = 0; x < texture->getWidth(); ++x) - { - for(size_t y = 0; y < texture->getHeight(); ++y) - { - Ogre::ColourValue clr = image.getColourAt(x, y, 0); - - //set the pixel on the SDL surface to the same value as the Ogre texture's - int bpp = surface->format->BytesPerPixel; - /* Here p is the address to the pixel we want to set */ - Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp; - Uint32 pixel = SDL_MapRGBA(surface->format, static_cast(clr.r * 255), - static_cast(clr.g * 255), static_cast(clr.b * 255), static_cast(clr.a * 255)); - switch(bpp) { - case 1: - *p = pixel; - break; - - case 2: - *(Uint16 *)p = pixel; - break; - - case 3: - if(SDL_BYTEORDER == SDL_BIG_ENDIAN) { - p[0] = (pixel >> 16) & 0xff; - p[1] = (pixel >> 8) & 0xff; - p[2] = pixel & 0xff; - } else { - p[0] = pixel & 0xff; - p[1] = (pixel >> 8) & 0xff; - p[2] = (pixel >> 16) & 0xff; - } - break; - - case 4: - *(Uint32 *)p = pixel; - break; - } - } - } - - SDL_SetWindowIcon(mSDLWindow, surface); - SDL_FreeSurface(surface); -} - -} diff --git a/extern/sdl4ogre/sdlwindowhelper.hpp b/extern/sdl4ogre/sdlwindowhelper.hpp deleted file mode 100644 index 834716b22..000000000 --- a/extern/sdl4ogre/sdlwindowhelper.hpp +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef SDL4OGRE_SDLWINDOWHELPER_H -#define SDL4OGRE_SDLWINDOWHELPER_H - -#include - -namespace Ogre -{ - class RenderWindow; -} -struct SDL_Window; - -namespace SFO -{ - - /// @brief Creates an Ogre window from an SDL window and allows setting an Ogre texture as window icon - class SDLWindowHelper - { - public: - SDLWindowHelper (SDL_Window* window, int w, int h, const std::string& title, bool fullscreen, Ogre::NameValuePairList params); - void setWindowIcon(const std::string& name); - Ogre::RenderWindow* getWindow() { return mWindow; } - - private: - Ogre::RenderWindow* mWindow; - SDL_Window* mSDLWindow; - }; - -} - - -#endif From 4825744a0386a1104736e0d4a6ab70b99677bd98 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 13 May 2015 17:25:54 +0200 Subject: [PATCH 1169/3725] Fix inconsistent health bar skin --- files/mygui/openmw_progress.skin.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/mygui/openmw_progress.skin.xml b/files/mygui/openmw_progress.skin.xml index 761574c15..71bbfe9f0 100644 --- a/files/mygui/openmw_progress.skin.xml +++ b/files/mygui/openmw_progress.skin.xml @@ -2,7 +2,7 @@ - + From 9ea416b852447669317aa547b3584cef32a58ec2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 13 May 2015 18:56:14 +0200 Subject: [PATCH 1170/3725] Readded HW cursor manager (no image rotation yet) --- CMakeLists.txt | 1 - apps/openmw/engine.cpp | 2 +- apps/openmw/mwgui/windowmanagerimp.cpp | 20 +-- apps/openmw/mwgui/windowmanagerimp.hpp | 6 +- components/CMakeLists.txt | 2 +- components/sdlutil/imagetosurface.cpp | 4 +- components/sdlutil/imagetosurface.hpp | 2 +- components/sdlutil/sdlcursormanager.cpp | 182 +++++++++++++++++++++++ components/sdlutil/sdlcursormanager.hpp | 51 +++++++ components/sdlutil/sdlgraphicswindow.cpp | 9 +- components/sdlutil/sdlinputwrapper.cpp | 10 ++ extern/sdl4ogre/CMakeLists.txt | 27 ---- extern/sdl4ogre/cursormanager.hpp | 30 ---- extern/sdl4ogre/sdlcursormanager.cpp | 161 -------------------- extern/sdl4ogre/sdlcursormanager.hpp | 39 ----- 15 files changed, 270 insertions(+), 276 deletions(-) create mode 100644 components/sdlutil/sdlcursormanager.cpp create mode 100644 components/sdlutil/sdlcursormanager.hpp delete mode 100644 extern/sdl4ogre/CMakeLists.txt delete mode 100644 extern/sdl4ogre/cursormanager.hpp delete mode 100644 extern/sdl4ogre/sdlcursormanager.cpp delete mode 100644 extern/sdl4ogre/sdlcursormanager.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index fae7ff683..d0515a1fb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -458,7 +458,6 @@ endif(WIN32) # Extern add_subdirectory (extern/osg-ffmpeg-videoplayer) add_subdirectory (extern/oics) -#add_subdirectory (extern/sdl4ogre) # Components add_subdirectory (components) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 08d77e7af..403cb79f2 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -393,7 +393,7 @@ void OMW::Engine::setWindowIcon() else { osg::ref_ptr image = result.getImage(); - SDL_Surface* surface = SDLUtil::imageToSurface(image); + SDL_Surface* surface = SDLUtil::imageToSurface(image, true); SDL_SetWindowIcon(mWindow, surface); SDL_FreeSurface(surface); } diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 9c7a9de20..5e573c1e4 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -20,11 +20,12 @@ #include #include -#include +#include #include #include +#include #include @@ -35,6 +36,8 @@ #include #include +#include + #include #include "../mwbase/inputmanager.hpp" @@ -219,7 +222,7 @@ namespace MWGui mLoadingScreen = new LoadingScreen(mResourceSystem->getVFS(), mViewer); //set up the hardware cursor manager - //mCursorManager = new SFO::SDLCursorManager(); + mCursorManager = new SDLUtil::SDLCursorManager(); MyGUI::PointerManager::getInstance().eventChangeMousePointer += MyGUI::newDelegate(this, &WindowManager::onCursorChange); @@ -227,7 +230,7 @@ namespace MWGui onCursorChange(MyGUI::PointerManager::getInstance().getDefaultPointer()); - //mCursorManager->setEnabled(true); + mCursorManager->setEnabled(true); // hide mygui's pointer MyGUI::PointerManager::getInstance().setVisible(false); @@ -417,7 +420,7 @@ namespace MWGui delete mDebugWindow; delete mJailScreen; - //delete mCursorManager; + delete mCursorManager; cleanupGarbage(); @@ -1152,7 +1155,6 @@ namespace MWGui void WindowManager::onCursorChange(const std::string &name) { - /* if(!mCursorManager->cursorChanged(name)) return; //the cursor manager doesn't want any more info about this cursor //See if we can get the information we need out of the cursor resource @@ -1163,10 +1165,11 @@ namespace MWGui std::string tex_name = imgSet->getIndexInfo(0,0).texture; - Ogre::TexturePtr tex = Ogre::TextureManager::getSingleton().getByName(tex_name); + osg::ref_ptr tex = mResourceSystem->getTextureManager()->getTexture2D(tex_name, osg::Texture::CLAMP, osg::Texture::CLAMP); + tex->setUnRefImageDataAfterApply(false); // FIXME? //everything looks good, send it to the cursor manager - if(!tex.isNull()) + if(tex.valid()) { Uint8 size_x = imgSetPtr->getSize().width; Uint8 size_y = imgSetPtr->getSize().height; @@ -1174,10 +1177,9 @@ namespace MWGui Uint8 hotspot_y = imgSetPtr->getHotSpot().top; int rotation = imgSetPtr->getRotation(); - mCursorManager->receiveCursorInfo(name, rotation, tex, size_x, size_y, hotspot_x, hotspot_y); + mCursorManager->receiveCursorInfo(name, rotation, tex->getImage(), size_x, size_y, hotspot_x, hotspot_y); } } - */ } void WindowManager::popGuiMode() diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 325881889..d07f2fb98 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -52,9 +52,9 @@ namespace Resource class ResourceSystem; } -namespace SFO +namespace SDLUtil { - class CursorManager; + class SDLCursorManager; } namespace osgMyGUI @@ -454,7 +454,7 @@ namespace MWGui MyGUI::Gui *mGui; // Gui std::vector mGuiModes; - SFO::CursorManager* mCursorManager; + SDLUtil::SDLCursorManager* mCursorManager; std::vector mGarbageDialogs; void cleanupGarbage(); diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 6590c7e99..0c76f666b 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -127,7 +127,7 @@ add_component_dir (fontloader ) add_component_dir (sdlutil - sdlgraphicswindow imagetosurface sdlinputwrapper OISCompat events + sdlgraphicswindow imagetosurface sdlinputwrapper OISCompat events sdlcursormanager ) add_component_dir (version diff --git a/components/sdlutil/imagetosurface.cpp b/components/sdlutil/imagetosurface.cpp index 36e503c74..6313c0a8f 100644 --- a/components/sdlutil/imagetosurface.cpp +++ b/components/sdlutil/imagetosurface.cpp @@ -6,7 +6,7 @@ namespace SDLUtil { -SDL_Surface* imageToSurface(osg::Image *image) +SDL_Surface* imageToSurface(osg::Image *image, bool flip) { int width = image->s(); int height = image->t(); @@ -15,7 +15,7 @@ SDL_Surface* imageToSurface(osg::Image *image) for(int x = 0; x < width; ++x) for(int y = 0; y < height; ++y) { - osg::Vec4f clr = image->getColor(x, (height-1)-y); + osg::Vec4f clr = image->getColor(x, flip ? ((height-1)-y) : y); int bpp = surface->format->BytesPerPixel; Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp; *(Uint32*)(p) = SDL_MapRGBA(surface->format, static_cast(clr.r() * 255), diff --git a/components/sdlutil/imagetosurface.hpp b/components/sdlutil/imagetosurface.hpp index 2c5df5cbd..ad0457433 100644 --- a/components/sdlutil/imagetosurface.hpp +++ b/components/sdlutil/imagetosurface.hpp @@ -13,7 +13,7 @@ namespace SDLUtil /// Convert an osg::Image to an SDL_Surface. /// @note The returned surface must be freed using SDL_FreeSurface. - SDL_Surface* imageToSurface(osg::Image* image); + SDL_Surface* imageToSurface(osg::Image* image, bool flip=false); } diff --git a/components/sdlutil/sdlcursormanager.cpp b/components/sdlutil/sdlcursormanager.cpp new file mode 100644 index 000000000..b8ae92c57 --- /dev/null +++ b/components/sdlutil/sdlcursormanager.cpp @@ -0,0 +1,182 @@ +#include "sdlcursormanager.hpp" + +#include + +#include +#include + +#include +#include +#include + +#include "imagetosurface.hpp" + +namespace +{ + + class MyGraphicsContext { + public: + MyGraphicsContext(int w, int h) + { + osg::ref_ptr traits = new osg::GraphicsContext::Traits; + traits->x = 0; + traits->y = 0; + traits->width = 1;//w; + traits->height = 1;//h; + traits->windowDecoration = false; + traits->doubleBuffer = false; + traits->sharedContext = 0; + traits->pbuffer = true; + + _gc = osg::GraphicsContext::createGraphicsContext(traits.get()); + + if (!_gc) + { + osg::notify(osg::NOTICE)<<"Failed to create pbuffer, failing back to normal graphics window."<pbuffer = false; + _gc = osg::GraphicsContext::createGraphicsContext(traits.get()); + } + + if (_gc.valid()) + { + _gc->realize(); + _gc->makeCurrent(); + } + } + + osg::ref_ptr getContext() + { + return _gc; + } + + bool valid() const { return _gc.valid() && _gc->isRealized(); } + + private: + osg::ref_ptr _gc; + }; + + osg::ref_ptr decompress (osg::ref_ptr source) + { + int width = source->s(); + int height = source->t(); + + MyGraphicsContext context(width, height); + + osg::ref_ptr state = context.getContext()->getState(); + + osg::ref_ptr texture = new osg::Texture2D; + texture->setImage(source); + + state->applyTextureAttribute(0, texture); + + osg::ref_ptr resultImage = new osg::Image; + resultImage->allocateImage(width, height, 1, GL_RGBA, GL_UNSIGNED_BYTE); + + assert(resultImage->isDataContiguous()); + + // FIXME: implement for GL ES (PBO & glMapBufferRange?) + glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, resultImage->data()); + + source->releaseGLObjects(); + texture->releaseGLObjects(); + + return resultImage; + } + +} + +namespace SDLUtil +{ + + SDLCursorManager::SDLCursorManager() : + mEnabled(false), + mInitialized(false) + { + } + + SDLCursorManager::~SDLCursorManager() + { + CursorMap::const_iterator curs_iter = mCursorMap.begin(); + + while(curs_iter != mCursorMap.end()) + { + SDL_FreeCursor(curs_iter->second); + ++curs_iter; + } + + mCursorMap.clear(); + } + + void SDLCursorManager::setEnabled(bool enabled) + { + if(mInitialized && enabled == mEnabled) + return; + + mInitialized = true; + mEnabled = enabled; + + //turn on hardware cursors + if(enabled) + { + _setGUICursor(mCurrentCursor); + } + //turn off hardware cursors + else + { + SDL_ShowCursor(SDL_FALSE); + } + } + + bool SDLCursorManager::cursorChanged(const std::string& name) + { + mCurrentCursor = name; + + CursorMap::const_iterator curs_iter = mCursorMap.find(name); + + //we have this cursor + if(curs_iter != mCursorMap.end()) + { + _setGUICursor(name); + + return false; + } + else + { + //they should get back to us with more info + return true; + } + } + + void SDLCursorManager::_setGUICursor(const std::string &name) + { + SDL_SetCursor(mCursorMap.find(name)->second); + } + + void SDLCursorManager::receiveCursorInfo(const std::string& name, int rotDegrees, osg::Image* image, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y) + { + _createCursorFromResource(name, rotDegrees, image, size_x, size_y, hotspot_x, hotspot_y); + } + + void SDLCursorManager::_createCursorFromResource(const std::string& name, int rotDegrees, osg::Image* image, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y) + { + if (mCursorMap.find(name) != mCursorMap.end()) + return; + + osg::ref_ptr decompressed = decompress(image); + + // TODO: rotate + + SDL_Surface* surf = SDLUtil::imageToSurface(decompressed, false); + + //set the cursor and store it for later + SDL_Cursor* curs = SDL_CreateColorCursor(surf, hotspot_x, hotspot_y); + mCursorMap.insert(CursorMap::value_type(std::string(name), curs)); + + //clean up + SDL_FreeSurface(surf); + + _setGUICursor(name); + } + +} diff --git a/components/sdlutil/sdlcursormanager.hpp b/components/sdlutil/sdlcursormanager.hpp new file mode 100644 index 000000000..646f548e3 --- /dev/null +++ b/components/sdlutil/sdlcursormanager.hpp @@ -0,0 +1,51 @@ +#ifndef OPENMW_COMPONENTS_SDLUTIL_SDLCURSORMANAGER_H +#define OPENMW_COMPONENTS_SDLUTIL_SDLCURSORMANAGER_H + +#include +#include + +#include + +struct SDL_Cursor; +struct SDL_Surface; + +namespace osg +{ + class Image; +} + +namespace SDLUtil +{ + class SDLCursorManager + { + public: + SDLCursorManager(); + virtual ~SDLCursorManager(); + + /// \brief sets whether to actively manage cursors or not + virtual void setEnabled(bool enabled); + + /// \brief Tell the manager that the cursor has changed, giving the + /// name of the cursor we changed to ("arrow", "ibeam", etc) + /// \return Whether the manager is interested in more information about the cursor + virtual bool cursorChanged(const std::string &name); + + /// \brief Follow up a cursorChanged() call with enough info to create an cursor. + virtual void receiveCursorInfo(const std::string &name, int rotDegrees, osg::Image* image, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y); + + private: + void _createCursorFromResource(const std::string &name, int rotDegrees, osg::Image* image, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y); + void _putPixel(SDL_Surface *surface, int x, int y, Uint32 pixel); + + void _setGUICursor(const std::string& name); + + typedef std::map CursorMap; + CursorMap mCursorMap; + + std::string mCurrentCursor; + bool mEnabled; + bool mInitialized; + }; +} + +#endif diff --git a/components/sdlutil/sdlgraphicswindow.cpp b/components/sdlutil/sdlgraphicswindow.cpp index c69fcca64..f16c0bca4 100644 --- a/components/sdlutil/sdlgraphicswindow.cpp +++ b/components/sdlutil/sdlgraphicswindow.cpp @@ -102,7 +102,7 @@ void GraphicsWindowSDL2::init() return; } - setSyncToVBlank(_traits->vsync); + SDL_GL_SetSwapInterval(_traits->vsync ? 1 : 0); SDL_GL_MakeCurrent(oldWin, oldCtx); @@ -182,7 +182,14 @@ void GraphicsWindowSDL2::swapBuffersImplementation() void GraphicsWindowSDL2::setSyncToVBlank(bool on) { + SDL_Window *oldWin = SDL_GL_GetCurrentWindow(); + SDL_GLContext oldCtx = SDL_GL_GetCurrentContext(); + + SDL_GL_MakeCurrent(mWindow, mContext); + SDL_GL_SetSwapInterval(on ? 1 : 0); + + SDL_GL_MakeCurrent(oldWin, oldCtx); } void GraphicsWindowSDL2::raiseWindow() diff --git a/components/sdlutil/sdlinputwrapper.cpp b/components/sdlutil/sdlinputwrapper.cpp index 44492cf6c..eb3370cf7 100644 --- a/components/sdlutil/sdlinputwrapper.cpp +++ b/components/sdlutil/sdlinputwrapper.cpp @@ -82,10 +82,20 @@ InputWrapper::InputWrapper(SDL_Window* window, osg::ref_ptr v case SDL_KEYDOWN: if (!evt.key.repeat) mKeyboardListener->keyPressed(evt.key); + + // temporary for the stats viewer + if (evt.key.keysym.sym == SDLK_s) + mViewer->getEventQueue()->keyPress('s'); + break; case SDL_KEYUP: if (!evt.key.repeat) mKeyboardListener->keyReleased(evt.key); + + // temporary for the stats viewer + if (evt.key.keysym.sym == SDLK_s) + mViewer->getEventQueue()->keyRelease('s'); + break; case SDL_TEXTINPUT: mKeyboardListener->textInput(evt.text); diff --git a/extern/sdl4ogre/CMakeLists.txt b/extern/sdl4ogre/CMakeLists.txt deleted file mode 100644 index b8c56bd00..000000000 --- a/extern/sdl4ogre/CMakeLists.txt +++ /dev/null @@ -1,27 +0,0 @@ -set(SDL4OGRE_LIBRARY "sdl4ogre") - -# Sources - -set(SDL4OGRE_SOURCE_FILES - sdlinputwrapper.cpp - sdlcursormanager.cpp - sdlwindowhelper.cpp - imagerotate.cpp -) - -if (APPLE) - set(SDL4OGRE_SOURCE_FILES ${SDL4OGRE_SOURCE_FILES} osx_utils.mm) -endif () - -set(SDL4OGRE_HEADER_FILES - OISCompat.h - cursormanager.hpp - events.h -) - -add_library(${SDL4OGRE_LIBRARY} STATIC ${SDL4OGRE_SOURCE_FILES} ${SDL4OGRE_HEADER_FILES}) - -link_directories(${CMAKE_CURRENT_BINARY_DIR}) - - -target_link_libraries(${SDL4OGRE_LIBRARY} ${SDL2_LIBRARY}) diff --git a/extern/sdl4ogre/cursormanager.hpp b/extern/sdl4ogre/cursormanager.hpp deleted file mode 100644 index 3036b236b..000000000 --- a/extern/sdl4ogre/cursormanager.hpp +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef SDL4OGRE_CURSOR_MANAGER_H -#define SDL4OGRE_CURSOR_MANAGER_H - -#include -#include - -#include -#include - -namespace SFO -{ -class CursorManager -{ -public: - virtual ~CursorManager(){} - - /// \brief Tell the manager that the cursor has changed, giving the - /// name of the cursor we changed to ("arrow", "ibeam", etc) - /// \return Whether the manager is interested in more information about the cursor - virtual bool cursorChanged(const std::string &name) = 0; - - /// \brief Follow up a cursorChanged() call with enough info to create an cursor. - virtual void receiveCursorInfo(const std::string &name, int rotDegrees, Ogre::TexturePtr tex, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y) = 0; - - /// \brief sets whether to actively manage cursors or not - virtual void setEnabled(bool enabled) = 0; -}; -} - -#endif diff --git a/extern/sdl4ogre/sdlcursormanager.cpp b/extern/sdl4ogre/sdlcursormanager.cpp deleted file mode 100644 index 61d9c32dd..000000000 --- a/extern/sdl4ogre/sdlcursormanager.cpp +++ /dev/null @@ -1,161 +0,0 @@ -#include "sdlcursormanager.hpp" - -#include -#include -#include - -#include -#include - -#include "imagerotate.hpp" - -namespace SFO -{ - - SDLCursorManager::SDLCursorManager() : - mEnabled(false), - mInitialized(false) - { - } - - SDLCursorManager::~SDLCursorManager() - { - CursorMap::const_iterator curs_iter = mCursorMap.begin(); - - while(curs_iter != mCursorMap.end()) - { - SDL_FreeCursor(curs_iter->second); - ++curs_iter; - } - - mCursorMap.clear(); - } - - void SDLCursorManager::setEnabled(bool enabled) - { - if(mInitialized && enabled == mEnabled) - return; - - mInitialized = true; - mEnabled = enabled; - - //turn on hardware cursors - if(enabled) - { - _setGUICursor(mCurrentCursor); - } - //turn off hardware cursors - else - { - SDL_ShowCursor(SDL_FALSE); - } - } - - bool SDLCursorManager::cursorChanged(const std::string &name) - { - mCurrentCursor = name; - - CursorMap::const_iterator curs_iter = mCursorMap.find(name); - - //we have this cursor - if(curs_iter != mCursorMap.end()) - { - _setGUICursor(name); - - return false; - } - else - { - //they should get back to us with more info - return true; - } - } - - void SDLCursorManager::_setGUICursor(const std::string &name) - { - SDL_SetCursor(mCursorMap.find(name)->second); - } - - void SDLCursorManager::receiveCursorInfo(const std::string& name, int rotDegrees, Ogre::TexturePtr tex, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y) - { - _createCursorFromResource(name, rotDegrees, tex, size_x, size_y, hotspot_x, hotspot_y); - } - - /// \brief creates an SDL cursor from an Ogre texture - void SDLCursorManager::_createCursorFromResource(const std::string& name, int rotDegrees, Ogre::TexturePtr tex, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y) - { - if (mCursorMap.find(name) != mCursorMap.end()) - return; - - std::string tempName = tex->getName() + "_rotated"; - - // we use a render target to uncompress the DDS texture - // just blitting doesn't seem to work on D3D9 - ImageRotate::rotate(tex->getName(), tempName, static_cast(-rotDegrees)); - - Ogre::TexturePtr resultTexture = Ogre::TextureManager::getSingleton().getByName(tempName); - - // now blit to memory - Ogre::Image destImage; - resultTexture->convertToImage(destImage); - - SDL_Surface* surf = SDL_CreateRGBSurface(0,size_x,size_y,32,0xFF000000,0x00FF0000,0x0000FF00,0x000000FF); - - - //copy the Ogre texture to an SDL surface - for(size_t x = 0; x < size_x; ++x) - { - for(size_t y = 0; y < size_y; ++y) - { - Ogre::ColourValue clr = destImage.getColourAt(x, y, 0); - - //set the pixel on the SDL surface to the same value as the Ogre texture's - _putPixel(surf, x, y, SDL_MapRGBA(surf->format, static_cast(clr.r * 255), - static_cast(clr.g * 255), static_cast(clr.b * 255), static_cast(clr.a * 255))); - } - } - - //set the cursor and store it for later - SDL_Cursor* curs = SDL_CreateColorCursor(surf, hotspot_x, hotspot_y); - mCursorMap.insert(CursorMap::value_type(std::string(name), curs)); - - //clean up - SDL_FreeSurface(surf); - Ogre::TextureManager::getSingleton().remove(tempName); - - _setGUICursor(name); - } - - void SDLCursorManager::_putPixel(SDL_Surface *surface, int x, int y, Uint32 pixel) - { - int bpp = surface->format->BytesPerPixel; - /* Here p is the address to the pixel we want to set */ - Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp; - - switch(bpp) { - case 1: - *p = pixel; - break; - - case 2: - *(Uint16 *)p = pixel; - break; - - case 3: - if(SDL_BYTEORDER == SDL_BIG_ENDIAN) { - p[0] = (pixel >> 16) & 0xff; - p[1] = (pixel >> 8) & 0xff; - p[2] = pixel & 0xff; - } else { - p[0] = pixel & 0xff; - p[1] = (pixel >> 8) & 0xff; - p[2] = (pixel >> 16) & 0xff; - } - break; - - case 4: - *(Uint32 *)p = pixel; - break; - } - } -} diff --git a/extern/sdl4ogre/sdlcursormanager.hpp b/extern/sdl4ogre/sdlcursormanager.hpp deleted file mode 100644 index 58324fc01..000000000 --- a/extern/sdl4ogre/sdlcursormanager.hpp +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef SDL4OGRE_CURSORMANAGER_H -#define SDL4OGRE_CURSORMANAGER_H - -#include "cursormanager.hpp" -#include - -struct SDL_Cursor; -struct SDL_Surface; - -namespace SFO -{ - class SDLCursorManager : - public CursorManager - { - public: - SDLCursorManager(); - virtual ~SDLCursorManager(); - - virtual void setEnabled(bool enabled); - - virtual bool cursorChanged(const std::string &name); - virtual void receiveCursorInfo(const std::string &name, int rotDegrees, Ogre::TexturePtr tex, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y); - - private: - void _createCursorFromResource(const std::string &name, int rotDegrees, Ogre::TexturePtr tex, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y); - void _putPixel(SDL_Surface *surface, int x, int y, Uint32 pixel); - - void _setGUICursor(const std::string& name); - - typedef std::map CursorMap; - CursorMap mCursorMap; - - std::string mCurrentCursor; - bool mEnabled; - bool mInitialized; - }; -} - -#endif From 5cf50227b4e0a1318606df0c5e56c7f41a5dd9fd Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 13 May 2015 19:53:50 +0200 Subject: [PATCH 1171/3725] updated changelog --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 15464b1d7..3219edd9a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ Bug #923: Editor: Operations-Multithreading is broken Bug #1317: Erene Llenim in Seyda Neen does not walk around + Bug #1405: Water rendering glitch near Seyda Neen lighthouse Bug #1621: "Error Detecting Morrowind Installation" in the default directory Bug #2216: Creating a clone of the player stops you moving. Bug #2387: Casting bound weapon spell doesn't switch to "ready weapon" mode @@ -23,6 +24,10 @@ Bug #2475: cumulative stacks of 100 point fortify skill speechcraft boosts do not apply correctly Bug #2498: Editor: crash when issuing undo command after the table subview is closed Bug #2500: Editor: object table - can't undo delete record + Bug #2518: OpenMW detect spell returns false positives + Bug #2521: NPCs don't react to stealing when inventory menu is open. + Bug #2525: Can't click on red dialogue choice [rise of house telvanni][60fffec] + Bug #2530: GetSpellEffects not working as in vanilla Feature #139: Editor: Global Search & Replace Feature #1219: Editor: Add dialogue mode only columns Feature #2024: Hotkey for hand to hand (i.e. unequip any weapon) @@ -34,6 +39,7 @@ Feature #2505: Editor: optionally show a line number column in the script editor Feature #2512: Editor: Offer use of monospace fonts in the script editor as an option Feature #2514: Editor: focus on ID input field on clone/add + Feature #2519: it is not possible to change icons that appear on the map after casting the Detect spells Task #2460: OS X: Use Application Support directory as user data path Task #2516: Editor: Change References / Referenceables terminology From c775cbbbaa4cd8dc650f11b3e2b1e324324612fd Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 14 May 2015 00:40:51 +0200 Subject: [PATCH 1172/3725] Silence an annoying message --- components/sdlutil/sdlgraphicswindow.hpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/components/sdlutil/sdlgraphicswindow.hpp b/components/sdlutil/sdlgraphicswindow.hpp index b2b7cfaf0..4b48b4073 100644 --- a/components/sdlutil/sdlgraphicswindow.hpp +++ b/components/sdlutil/sdlgraphicswindow.hpp @@ -66,6 +66,12 @@ public: /** Set mouse cursor to a specific shape.*/ virtual void setCursor(MouseCursor cursor); + /** Get focus.*/ + virtual void grabFocus() {} + + /** Get focus on if the pointer is in this window.*/ + virtual void grabFocusIfPointerInWindow() {} + /** WindowData is used to pass in the SDL2 window handle attached to the GraphicsContext::Traits structure. */ struct WindowData : public osg::Referenced { From 5dd1b2ae860c9ba6eb83b72c232945b03dddd3df Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 14 May 2015 01:04:34 +0200 Subject: [PATCH 1173/3725] Readded HW cursor rotation --- components/sdlutil/sdlcursormanager.cpp | 54 ++++++++++++++++++++----- 1 file changed, 45 insertions(+), 9 deletions(-) diff --git a/components/sdlutil/sdlcursormanager.cpp b/components/sdlutil/sdlcursormanager.cpp index b8ae92c57..9a7c2aa76 100644 --- a/components/sdlutil/sdlcursormanager.cpp +++ b/components/sdlutil/sdlcursormanager.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include "imagetosurface.hpp" @@ -21,8 +22,12 @@ namespace osg::ref_ptr traits = new osg::GraphicsContext::Traits; traits->x = 0; traits->y = 0; - traits->width = 1;//w; - traits->height = 1;//h; + traits->width = w; + traits->height = h; + traits->red = 8; + traits->green = 8; + traits->blue = 8; + traits->alpha = 8; traits->windowDecoration = false; traits->doubleBuffer = false; traits->sharedContext = 0; @@ -56,7 +61,7 @@ namespace osg::ref_ptr _gc; }; - osg::ref_ptr decompress (osg::ref_ptr source) + osg::ref_ptr decompress (osg::ref_ptr source, float rotDegrees) { int width = source->s(); int height = source->t(); @@ -67,17 +72,50 @@ namespace osg::ref_ptr texture = new osg::Texture2D; texture->setImage(source); + texture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_BORDER); + texture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_BORDER); + texture->setBorderColor(osg::Vec4f(0.f, 0.f, 0.f, 0.f)); + osg::ref_ptr texmat = new osg::TexMat; + osg::Matrix texRot (osg::Matrix::identity()); + float theta ( osg::DegreesToRadians(-rotDegrees) ); + float cosTheta = std::cos(theta); + float sinTheta = std::sin(theta); + + texRot(0,0) = cosTheta; + texRot(1,0) = -sinTheta; + texRot(0,1) = sinTheta; + texRot(1,1) = cosTheta; + // Offset center of rotation to center of texture + texRot(3,0) = 0.5f + ( (-0.5f * cosTheta) - (-0.5f * sinTheta) ); + texRot(3,1) = 0.5f + ( (-0.5f * sinTheta) + (-0.5f * cosTheta) ); + + texmat->setMatrix(texRot); + + state->applyTextureAttribute(0, texmat); + + osg::ref_ptr identity (new osg::RefMatrix(osg::Matrix::identity())); + state->applyModelViewMatrix(identity); + state->applyProjectionMatrix(identity); + + state->applyMode(GL_TEXTURE_2D, true); state->applyTextureAttribute(0, texture); osg::ref_ptr resultImage = new osg::Image; resultImage->allocateImage(width, height, 1, GL_RGBA, GL_UNSIGNED_BYTE); - assert(resultImage->isDataContiguous()); + osg::RenderInfo renderInfo; + renderInfo.setState(state); + + glViewport(0, 0, width, height); - // FIXME: implement for GL ES (PBO & glMapBufferRange?) - glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, resultImage->data()); + osg::ref_ptr geom = osg::createTexturedQuadGeometry(osg::Vec3(-1,-1,0), osg::Vec3(2,0,0), osg::Vec3(0,2,0)); + geom->drawImplementation(renderInfo); + // TODO: implement for GL ES + glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, resultImage->data()); + + geom->releaseGLObjects(); source->releaseGLObjects(); texture->releaseGLObjects(); @@ -163,9 +201,7 @@ namespace SDLUtil if (mCursorMap.find(name) != mCursorMap.end()) return; - osg::ref_ptr decompressed = decompress(image); - - // TODO: rotate + osg::ref_ptr decompressed = decompress(image, static_cast(rotDegrees)); SDL_Surface* surf = SDLUtil::imageToSurface(decompressed, false); From fd3d49c1717b105070071e46bb80bab6898ac74e Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 14 May 2015 01:18:24 +0200 Subject: [PATCH 1174/3725] Fix typo in settings layout --- files/mygui/openmw_settings_window.layout | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/mygui/openmw_settings_window.layout b/files/mygui/openmw_settings_window.layout index cc9c3d1dc..768652e1a 100644 --- a/files/mygui/openmw_settings_window.layout +++ b/files/mygui/openmw_settings_window.layout @@ -175,7 +175,7 @@ - + From a18663c8b3b9d3a59721e745d85a30413982a755 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 14 May 2015 01:26:10 +0200 Subject: [PATCH 1175/3725] Improve MyGUI texture updates --- apps/openmw/mwgui/windowmanagerimp.cpp | 4 ---- components/myguiplatform/myguitexture.cpp | 16 +++++++++++++--- components/myguiplatform/myguitexture.hpp | 2 -- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 5e573c1e4..3bedb5d5e 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1098,11 +1098,7 @@ namespace MWGui else if (it->first == "GUI" && it->second == "subtitles") mSubtitlesEnabled = Settings::Manager::getBool ("subtitles", "GUI"); else if (it->first == "GUI" && it->second == "menu transparency") - { - mViewer->stopThreading(); setMenuTransparency(Settings::Manager::getFloat("menu transparency", "GUI")); - mViewer->startThreading(); - } } } diff --git a/components/myguiplatform/myguitexture.cpp b/components/myguiplatform/myguitexture.cpp index 7de7ebfb0..68408dd3a 100644 --- a/components/myguiplatform/myguitexture.cpp +++ b/components/myguiplatform/myguitexture.cpp @@ -141,11 +141,21 @@ namespace osgMyGUI if (!mLockedImage.valid()) throw std::runtime_error("Texture not locked"); + // mTexture might be in use by the draw thread, so create a new texture instead and use that. + osg::ref_ptr newTexture = new osg::Texture2D; + newTexture->setTextureSize(getWidth(), getHeight()); + newTexture->setSourceFormat(mTexture->getSourceFormat()); + newTexture->setSourceType(mTexture->getSourceType()); + newTexture->setFilter(osg::Texture::MIN_FILTER, mTexture->getFilter(osg::Texture::MIN_FILTER)); + newTexture->setFilter(osg::Texture::MAG_FILTER, mTexture->getFilter(osg::Texture::MAG_FILTER)); + newTexture->setWrap(osg::Texture::WRAP_S, mTexture->getWrap(osg::Texture::WRAP_S)); + newTexture->setWrap(osg::Texture::WRAP_T, mTexture->getWrap(osg::Texture::WRAP_T)); + newTexture->setImage(mLockedImage.get()); // Tell the texture it can get rid of the image for static textures (since // they aren't expected to update much at all). - mTexture->setImage(mLockedImage.get()); - mTexture->setUnRefImageDataAfterApply(mUsage.isValue(MyGUI::TextureUsage::Static) ? true : false); - mTexture->dirtyTextureObject(); + newTexture->setUnRefImageDataAfterApply(mUsage.isValue(MyGUI::TextureUsage::Static) ? true : false); + + mTexture = newTexture; mLockedImage = nullptr; } diff --git a/components/myguiplatform/myguitexture.hpp b/components/myguiplatform/myguitexture.hpp index 109858bc8..de385e94d 100644 --- a/components/myguiplatform/myguitexture.hpp +++ b/components/myguiplatform/myguitexture.hpp @@ -42,8 +42,6 @@ namespace osgMyGUI virtual void destroy(); - /// @warning If you intend to change a texture during the frame update, you must either declare the texture with DataVariance::DYNAMIC - /// or temporarily stop the viewer threading, to prevent race conditions with the draw thread. virtual void* lock(MyGUI::TextureUsage access); virtual void unlock(); virtual bool isLocked(); From 4dd96f33188fac381d9f8a28a834680b92c789f1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 14 May 2015 01:32:46 +0200 Subject: [PATCH 1176/3725] Fix missing tiling in skin --- files/mygui/openmw_windows.skin.xml | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/files/mygui/openmw_windows.skin.xml b/files/mygui/openmw_windows.skin.xml index 2854401c8..ca95a552b 100644 --- a/files/mygui/openmw_windows.skin.xml +++ b/files/mygui/openmw_windows.skin.xml @@ -151,14 +151,22 @@ - - + + + + + + - - + + + + + + From e3b1707bbd26f2ad33fbc263c11a6fc4b2810ba8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 14 May 2015 02:24:15 +0200 Subject: [PATCH 1177/3725] Pause simulationTime when the GUI is up --- apps/openmw/engine.cpp | 10 +++++++--- apps/openmw/engine.hpp | 4 +++- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 403cb79f2..f9bb297a9 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -73,7 +73,7 @@ void OMW::Engine::executeLocalScripts() localScripts.setIgnore (MWWorld::Ptr()); } -void OMW::Engine::frame(float frametime) +double OMW::Engine::frame(float frametime) { try { @@ -94,6 +94,8 @@ void OMW::Engine::frame(float frametime) // GUI active? Most game processing will be paused, but scripts still run. bool guiActive = MWBase::Environment::get().getWindowManager()->isGuiMode(); + if (!guiActive) + mSimulationTime += frametime; // Main menu opened? Then scripts are also paused. bool paused = MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_MainMenu); @@ -182,6 +184,7 @@ void OMW::Engine::frame(float frametime) { std::cerr << "Error in framelistener: " << e.what() << std::endl; } + return mSimulationTime; } OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) @@ -203,6 +206,7 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) , mScriptBlacklistUse (true) , mNewGame (false) , mCfgMgr(configurationManager) + , mSimulationTime(0.0) { Misc::Rng::init(); MWClass::registerClasses(); @@ -587,8 +591,8 @@ void OMW::Engine::go() frameTimer.setStartTick(); //dt = std::min(dt, 0.2); - frame(dt); - mViewer->frame(/*simulationTime*/); + double simulationTime = frame(dt); + mViewer->frame(simulationTime); } // Save user settings diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index bb70c288d..8b792c5a8 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -100,6 +100,7 @@ namespace OMW bool mNewGame; osg::Timer_t mStartTick; + double mSimulationTime; // not implemented Engine (const Engine&); @@ -107,7 +108,8 @@ namespace OMW void executeLocalScripts(); - void frame (float dt); + /// @return The new simulationTime + double frame (float dt); /// Load settings from various files, returns the path to the user settings file std::string loadSettings (Settings::Manager & settings); From c9d519f36c62611a768936018fe185a011a4d6a0 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 14 May 2015 14:48:29 +0200 Subject: [PATCH 1178/3725] focus search input field when opening search subview (Fixes #2534) --- apps/opencs/view/tools/searchbox.cpp | 7 +++++++ apps/opencs/view/tools/searchbox.hpp | 2 ++ apps/opencs/view/tools/searchsubview.cpp | 8 +++++++- apps/opencs/view/tools/searchsubview.hpp | 4 ++++ 4 files changed, 20 insertions(+), 1 deletion(-) diff --git a/apps/opencs/view/tools/searchbox.cpp b/apps/opencs/view/tools/searchbox.cpp index ca5520787..1307c1aab 100644 --- a/apps/opencs/view/tools/searchbox.cpp +++ b/apps/opencs/view/tools/searchbox.cpp @@ -153,6 +153,11 @@ void CSVTools::SearchBox::setEditLock (bool locked) mReplace.setEnabled (!locked); } +void CSVTools::SearchBox::focus() +{ + mInput.currentWidget()->setFocus(); +} + void CSVTools::SearchBox::modeSelected (int index) { switch (index) @@ -172,6 +177,8 @@ void CSVTools::SearchBox::modeSelected (int index) break; } + mInput.currentWidget()->setFocus(); + updateSearchButton(); } diff --git a/apps/opencs/view/tools/searchbox.hpp b/apps/opencs/view/tools/searchbox.hpp index 433c09693..fe56966d1 100644 --- a/apps/opencs/view/tools/searchbox.hpp +++ b/apps/opencs/view/tools/searchbox.hpp @@ -49,6 +49,8 @@ namespace CSVTools void setEditLock (bool locked); + void focus(); + private slots: void modeSelected (int index); diff --git a/apps/opencs/view/tools/searchsubview.cpp b/apps/opencs/view/tools/searchsubview.cpp index 32c26ee96..dc670af40 100644 --- a/apps/opencs/view/tools/searchsubview.cpp +++ b/apps/opencs/view/tools/searchsubview.cpp @@ -60,6 +60,12 @@ void CSVTools::SearchSubView::replace (bool selection) } } +void CSVTools::SearchSubView::showEvent (QShowEvent *event) +{ + CSVDoc::SubView::showEvent (event); + mSearchBox.focus(); +} + CSVTools::SearchSubView::SearchSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) : CSVDoc::SubView (id), mDocument (document), mLocked (false) { @@ -83,7 +89,7 @@ CSVTools::SearchSubView::SearchSubView (const CSMWorld::UniversalId& id, CSMDoc: SIGNAL (focusId (const CSMWorld::UniversalId&, const std::string&))); connect (mTable, SIGNAL (replaceRequest()), this, SLOT (replaceRequest())); - + connect (&document, SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (stateChanged (int, CSMDoc::Document *))); diff --git a/apps/opencs/view/tools/searchsubview.hpp b/apps/opencs/view/tools/searchsubview.hpp index 6dedd6ef2..2e96b98b5 100644 --- a/apps/opencs/view/tools/searchsubview.hpp +++ b/apps/opencs/view/tools/searchsubview.hpp @@ -32,6 +32,10 @@ namespace CSVTools private: void replace (bool selection); + + protected: + + void showEvent (QShowEvent *event); public: From b6cb73e6e8d5c513a72bd36a43c4f163e8269e2a Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 14 May 2015 15:07:58 +0200 Subject: [PATCH 1179/3725] Fix deep copying of controllers This fixes the cell loading crash. --- components/sceneutil/clone.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/components/sceneutil/clone.cpp b/components/sceneutil/clone.cpp index 862a070d8..237417974 100644 --- a/components/sceneutil/clone.cpp +++ b/components/sceneutil/clone.cpp @@ -27,7 +27,7 @@ namespace SceneUtil if (!stateset) return NULL; if (stateset->getDataVariance() == osg::StateSet::DYNAMIC) - return osg::clone(stateset, osg::CopyOp::DEEP_COPY_STATESETS); + return osg::clone(stateset, *this); return const_cast(stateset); } @@ -37,7 +37,7 @@ namespace SceneUtil return operator()(processor); if (const osgParticle::ParticleSystemUpdater* updater = dynamic_cast(node)) { - osgParticle::ParticleSystemUpdater* cloned = osg::clone(updater, osg::CopyOp::DEEP_COPY_NODES); + osgParticle::ParticleSystemUpdater* cloned = osg::clone(updater, *this); mMap2[cloned] = updater->getParticleSystem(0); return cloned; } @@ -50,21 +50,26 @@ namespace SceneUtil return operator()(partsys); if (dynamic_cast(drawable) || dynamic_cast(drawable)) - return osg::clone(drawable, osg::CopyOp::DEEP_COPY_DRAWABLES); + { + osg::Drawable* cloned = osg::clone(drawable, *this); + if (cloned->getUpdateCallback()) + cloned->setUpdateCallback(osg::clone(cloned->getUpdateCallback(), *this)); + return cloned; + } return osg::CopyOp::operator()(drawable); } osgParticle::ParticleProcessor* CopyOp::operator() (const osgParticle::ParticleProcessor* processor) const { - osgParticle::ParticleProcessor* cloned = osg::clone(processor, osg::CopyOp::DEEP_COPY_NODES); + osgParticle::ParticleProcessor* cloned = osg::clone(processor, *this); mMap[cloned] = processor->getParticleSystem(); return cloned; } osgParticle::ParticleSystem* CopyOp::operator ()(const osgParticle::ParticleSystem* partsys) const { - osgParticle::ParticleSystem* cloned = osg::clone(partsys, osg::CopyOp::DEEP_COPY_DRAWABLES); + osgParticle::ParticleSystem* cloned = osg::clone(partsys, *this); for (std::map::const_iterator it = mMap.begin(); it != mMap.end(); ++it) { From 4ad0b83aa5ecfaf904da8a480b54fa898159cca8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 14 May 2015 16:33:41 +0200 Subject: [PATCH 1180/3725] Eliminate string lookups in AnimationTime --- apps/openmw/mwrender/animation.cpp | 73 ++++++++++++++---------------- apps/openmw/mwrender/animation.hpp | 26 +++++++---- 2 files changed, 53 insertions(+), 46 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 888846789..c0cddb4d0 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -326,7 +326,7 @@ namespace MWRender mStates.clear(); for(size_t i = 0;i < sNumGroups;i++) - mAnimationTimePtr[i]->setAnimName(std::string()); + mAnimationTimePtr[i]->setTimePtr(boost::shared_ptr()); mAccumCtrl = NULL; @@ -433,32 +433,32 @@ namespace MWRender state.mSource = *iter; state.mSpeedMult = speedmult; state.mLoopCount = loops; - state.mPlaying = (state.mTime < state.mStopTime); + state.mPlaying = (state.getTime() < state.mStopTime); state.mPriority = priority; state.mGroups = groups; state.mAutoDisable = autodisable; mStates[groupname] = state; - NifOsg::TextKeyMap::const_iterator textkey(textkeys.lower_bound(state.mTime)); + NifOsg::TextKeyMap::const_iterator textkey(textkeys.lower_bound(state.getTime())); if (state.mPlaying) { - while(textkey != textkeys.end() && textkey->first <= state.mTime) + while(textkey != textkeys.end() && textkey->first <= state.getTime()) { handleTextKey(state, groupname, textkey, textkeys); ++textkey; } } - if(state.mTime >= state.mLoopStopTime && state.mLoopCount > 0) + if(state.getTime() >= state.mLoopStopTime && state.mLoopCount > 0) { state.mLoopCount--; - state.mTime = state.mLoopStartTime; + state.setTime(state.mLoopStartTime); state.mPlaying = true; - if(state.mTime >= state.mLoopStopTime) + if(state.getTime() >= state.mLoopStopTime) break; - NifOsg::TextKeyMap::const_iterator textkey(textkeys.lower_bound(state.mTime)); - while(textkey != textkeys.end() && textkey->first <= state.mTime) + NifOsg::TextKeyMap::const_iterator textkey(textkeys.lower_bound(state.getTime())); + while(textkey != textkeys.end() && textkey->first <= state.getTime()) { handleTextKey(state, groupname, textkey, textkeys); ++textkey; @@ -527,11 +527,11 @@ namespace MWRender } state.mStopTime = stopkey->first; - state.mTime = state.mStartTime + ((state.mStopTime - state.mStartTime) * startpoint); + state.setTime(state.mStartTime + ((state.mStopTime - state.mStartTime) * startpoint)); // mLoopStartTime and mLoopStopTime normally get assigned when encountering these keys while playing the animation // (see handleTextKey). But if startpoint is already past these keys, we need to assign them now. - if(state.mTime > state.mStartTime) + if(state.getTime() > state.mStartTime) { const std::string loopstarttag = groupname+": loop start"; const std::string loopstoptag = groupname+": loop stop"; @@ -539,7 +539,7 @@ namespace MWRender NifOsg::TextKeyMap::const_reverse_iterator key(groupend); for (; key != startkey && key != keys.rend(); ++key) { - if (key->first > state.mTime) + if (key->first > state.getTime()) continue; if (key->second == loopstarttag) @@ -587,8 +587,7 @@ namespace MWRender active = state; } - mAnimationTimePtr[grp]->setAnimName((active == mStates.end()) ? - std::string() : active->first); + mAnimationTimePtr[grp]->setTimePtr(active == mStates.end() ? boost::shared_ptr() : active->second.mTime); // add external controllers for the AnimSource active in this group if (active != mStates.end()) @@ -671,7 +670,7 @@ namespace MWRender if(complete) { if(iter->second.mStopTime > iter->second.mStartTime) - *complete = (iter->second.mTime - iter->second.mStartTime) / + *complete = (iter->second.getTime() - iter->second.mStartTime) / (iter->second.mStopTime - iter->second.mStartTime); else *complete = (iter->second.mPlaying ? 0.0f : 1.0f); @@ -686,7 +685,7 @@ namespace MWRender if(iter == mStates.end()) return -1.f; - return iter->second.mTime; + return iter->second.getTime(); } void Animation::disable(const std::string &groupname) @@ -767,54 +766,54 @@ namespace MWRender { AnimState &state = stateiter->second; const NifOsg::TextKeyMap &textkeys = state.mSource->getTextKeys(); - NifOsg::TextKeyMap::const_iterator textkey(textkeys.upper_bound(state.mTime)); + NifOsg::TextKeyMap::const_iterator textkey(textkeys.upper_bound(state.getTime())); float timepassed = duration * state.mSpeedMult; while(state.mPlaying) { float targetTime; - if(state.mTime >= state.mLoopStopTime && state.mLoopCount > 0) + if(state.getTime() >= state.mLoopStopTime && state.mLoopCount > 0) goto handle_loop; - targetTime = state.mTime + timepassed; + targetTime = state.getTime() + timepassed; if(textkey == textkeys.end() || textkey->first > targetTime) { - if(mAccumCtrl && stateiter->first == mAnimationTimePtr[0]->getAnimName()) - updatePosition(state.mTime, targetTime, movement); - state.mTime = std::min(targetTime, state.mStopTime); + if(mAccumCtrl && state.mTime == mAnimationTimePtr[0]->getTimePtr()) + updatePosition(state.getTime(), targetTime, movement); + state.setTime(std::min(targetTime, state.mStopTime)); } else { - if(mAccumCtrl && stateiter->first == mAnimationTimePtr[0]->getAnimName()) - updatePosition(state.mTime, textkey->first, movement); - state.mTime = textkey->first; + if(mAccumCtrl && state.mTime == mAnimationTimePtr[0]->getTimePtr()) + updatePosition(state.getTime(), textkey->first, movement); + state.setTime(textkey->first); } - state.mPlaying = (state.mTime < state.mStopTime); - timepassed = targetTime - state.mTime; + state.mPlaying = (state.getTime() < state.mStopTime); + timepassed = targetTime - state.getTime(); - while(textkey != textkeys.end() && textkey->first <= state.mTime) + while(textkey != textkeys.end() && textkey->first <= state.getTime()) { handleTextKey(state, stateiter->first, textkey, textkeys); ++textkey; } - if(state.mTime >= state.mLoopStopTime && state.mLoopCount > 0) + if(state.getTime() >= state.mLoopStopTime && state.mLoopCount > 0) { handle_loop: state.mLoopCount--; - state.mTime = state.mLoopStartTime; + state.setTime(state.mLoopStartTime); state.mPlaying = true; - textkey = textkeys.lower_bound(state.mTime); - while(textkey != textkeys.end() && textkey->first <= state.mTime) + textkey = textkeys.lower_bound(state.getTime()); + while(textkey != textkeys.end() && textkey->first <= state.getTime()) { handleTextKey(state, stateiter->first, textkey, textkeys); ++textkey; } - if(state.mTime >= state.mLoopStopTime) + if(state.getTime() >= state.mLoopStopTime) break; } @@ -1090,11 +1089,9 @@ namespace MWRender float Animation::AnimationTime::getValue(osg::NodeVisitor*) { - // FIXME: hold a pointer instead of searching every frame - AnimStateMap::const_iterator iter = mAnimation->mStates.find(mAnimationName); - if(iter != mAnimation->mStates.end()) - return iter->second.mTime; - return 0.0f; + if (mTimePtr) + return *mTimePtr; + return 0.f; } float EffectAnimationTime::getValue(osg::NodeVisitor*) diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 81f044707..3426094c8 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -62,17 +62,17 @@ protected: { private: Animation *mAnimation; - std::string mAnimationName; + boost::shared_ptr mTimePtr; public: AnimationTime(Animation *anim) : mAnimation(anim) { } - void setAnimName(const std::string &name) - { mAnimationName = name; } - const std::string &getAnimName() const - { return mAnimationName; } + void setTimePtr(boost::shared_ptr time) + { mTimePtr = time; } + boost::shared_ptr getTimePtr() const + { return mTimePtr; } virtual float getValue(osg::NodeVisitor* nv); }; @@ -104,7 +104,8 @@ protected: float mLoopStopTime; float mStopTime; - float mTime; + typedef boost::shared_ptr TimePtr; + TimePtr mTime; float mSpeedMult; bool mPlaying; @@ -115,9 +116,18 @@ protected: bool mAutoDisable; AnimState() : mStartTime(0.0f), mLoopStartTime(0.0f), mLoopStopTime(0.0f), mStopTime(0.0f), - mTime(0.0f), mSpeedMult(1.0f), mPlaying(false), mLoopCount(0), + mTime(new float), mSpeedMult(1.0f), mPlaying(false), mLoopCount(0), mPriority(0), mGroups(0), mAutoDisable(true) - { } + { + } + float getTime() const + { + return *mTime; + } + void setTime(float time) + { + *mTime = time; + } }; typedef std::map AnimStateMap; AnimStateMap mStates; From bc237ee1fe95a841d84d317f4bd078f55ad6714c Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 14 May 2015 17:14:49 +0200 Subject: [PATCH 1181/3725] Actor placement fix --- apps/openmw/mwworld/worldimp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 6c7fd6ff3..1ee9586ae 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1321,7 +1321,7 @@ namespace MWWorld return; } - float terrainHeight = 0;//mRendering->getTerrainHeightAt(Ogre::Vector3(pos.pos)); + float terrainHeight = -FLT_MAX;//mRendering->getTerrainHeightAt(Ogre::Vector3(pos.pos)); if (pos.pos[2] < terrainHeight) pos.pos[2] = terrainHeight; From b7258c8d234751e3aac2f048e3c90e1a681a575c Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 14 May 2015 17:34:55 +0200 Subject: [PATCH 1182/3725] Readded Objects::updatePtr --- apps/openmw/mwrender/animation.hpp | 2 +- apps/openmw/mwrender/npcanimation.cpp | 11 +++++++++++ apps/openmw/mwrender/npcanimation.hpp | 4 ++++ apps/openmw/mwrender/objects.cpp | 21 ++++++++++++--------- apps/openmw/mwrender/objects.hpp | 2 +- apps/openmw/mwrender/renderingmanager.cpp | 5 +++++ apps/openmw/mwrender/renderingmanager.hpp | 2 ++ apps/openmw/mwworld/worldimp.cpp | 2 +- 8 files changed, 37 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 3426094c8..a12375a9b 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -274,7 +274,7 @@ public: void removeEffect (int effectId); void getLoopingEffects (std::vector& out); - void updatePtr(const MWWorld::Ptr &ptr); + virtual void updatePtr(const MWWorld::Ptr &ptr); bool hasAnimation(const std::string &anim); diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 26f05e35f..2bb1b66fd 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -76,6 +76,11 @@ HeadAnimationTime::HeadAnimationTime(MWWorld::Ptr reference) resetBlinkTimer(); } +void HeadAnimationTime::updatePtr(const MWWorld::Ptr &updated) +{ + mReference = updated; +} + void HeadAnimationTime::setEnabled(bool enabled) { mEnabled = enabled; @@ -901,6 +906,12 @@ void NpcAnimation::setVampire(bool vampire) } } +void NpcAnimation::updatePtr(const MWWorld::Ptr &updated) +{ + Animation::updatePtr(updated); + mHeadAnimationTime->updatePtr(updated); +} + /* void NpcAnimation::setHeadPitch(Ogre::Radian pitch) { diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 0c91dfe6e..a58f0fdf3 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -34,6 +34,8 @@ private: public: HeadAnimationTime(MWWorld::Ptr reference); + void updatePtr(const MWWorld::Ptr& updated); + void update(float dt); void setEnabled(bool enabled); @@ -176,6 +178,8 @@ public: virtual void setAlpha(float alpha); virtual void setVampire(bool vampire); + + virtual void updatePtr(const MWWorld::Ptr& updated); }; } diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 17fbbe549..5face96a6 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -198,30 +198,33 @@ void Objects::removeCell(const MWWorld::CellStore* store) } } -void Objects::updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur) +void Objects::updatePtr(const MWWorld::Ptr &old, const MWWorld::Ptr &cur) { - /* - Ogre::SceneNode *node; MWWorld::CellStore *newCell = cur.getCell(); + osg::Group* cellnode; if(mCellSceneNodes.find(newCell) == mCellSceneNodes.end()) { - node = mRootNode->createChildSceneNode(); - mCellSceneNodes[newCell] = node; + cellnode = new osg::Group; + mRootNode->addChild(cellnode); + mCellSceneNodes[newCell] = cellnode; } else { - node = mCellSceneNodes[newCell]; + cellnode = mCellSceneNodes[newCell]; } - node->addChild(cur.getRefData().getBaseNode()); + osg::Node* objectNode = cur.getRefData().getBaseNode(); + + if (objectNode->getNumParents()) + objectNode->getParent(0)->removeChild(objectNode); + cellnode->addChild(objectNode); PtrAnimationMap::iterator iter = mObjects.find(old); if(iter != mObjects.end()) { - ObjectAnimation *anim = iter->second; + Animation *anim = iter->second; mObjects.erase(iter); anim->updatePtr(cur); mObjects[cur] = anim; } - */ } Animation* Objects::getAnimation(const MWWorld::Ptr &ptr) diff --git a/apps/openmw/mwrender/objects.hpp b/apps/openmw/mwrender/objects.hpp index e920869b9..3e1af6087 100644 --- a/apps/openmw/mwrender/objects.hpp +++ b/apps/openmw/mwrender/objects.hpp @@ -72,7 +72,7 @@ public: void removeCell(const MWWorld::CellStore* store); /// Updates containing cell for object rendering data - void updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur); + void updatePtr(const MWWorld::Ptr &old, const MWWorld::Ptr &cur); private: void operator = (const Objects&); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index c9bf22009..49e6ba06f 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -271,6 +271,11 @@ namespace MWRender ptr.getRefData().getBaseNode()->setScale(scale); } + void RenderingManager::updatePtr(const MWWorld::Ptr &old, const MWWorld::Ptr &updated) + { + mObjects->updatePtr(old, updated); + } + void RenderingManager::spawnEffect(const std::string &model, const std::string &texture, const osg::Vec3f &worldPosition, float scale) { mEffectManager->addEffect(model, texture, worldPosition, scale); diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 0dc0fe571..7d902b854 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -62,6 +62,8 @@ namespace MWRender void addCell(const MWWorld::CellStore* store); void removeCell(const MWWorld::CellStore* store); + void updatePtr(const MWWorld::Ptr& old, const MWWorld::Ptr& updated); + // TODO rename to setRotation/setPosition/setScale, along with the World equivalents void rotateObject(const MWWorld::Ptr& ptr, const osg::Quat& rot); void moveObject(const MWWorld::Ptr& ptr, const osg::Vec3f& pos); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 1ee9586ae..32eb92d2a 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1181,7 +1181,7 @@ namespace MWWorld MWWorld::Ptr copy = ptr.getClass().copyToCell(ptr, *newCell, pos); - //mRendering->updateObjectCell(ptr, copy); + mRendering->updatePtr(ptr, copy); ptr.getRefData().setBaseNode(NULL); MWBase::Environment::get().getSoundManager()->updatePtr (ptr, copy); mPhysics->updatePtr(ptr, copy); From 3e86dd7df0f757a8f59a91ef4a3bb3af6a49b51d Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 14 May 2015 18:46:04 +0200 Subject: [PATCH 1183/3725] Apply runtime changes to field of view & view distance --- apps/openmw/mwrender/renderingmanager.cpp | 42 ++++++++++++++++++----- apps/openmw/mwrender/renderingmanager.hpp | 7 ++++ apps/openmw/mwworld/worldimp.cpp | 2 +- files/settings-default.cfg | 3 ++ 4 files changed, 44 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 49e6ba06f..7822ccb30 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -128,8 +128,10 @@ namespace MWRender osg::Camera::CullingMode cullingMode = osg::Camera::DEFAULT_CULLING|osg::Camera::FAR_PLANE_CULLING; - // for consistent benchmarks against the ogre branch. remove later - cullingMode &= ~(osg::CullStack::SMALL_FEATURE_CULLING); + if (!Settings::Manager::getBool("small feature culling", "Viewing distance")) + cullingMode &= ~(osg::CullStack::SMALL_FEATURE_CULLING); + else + cullingMode |= osg::CullStack::SMALL_FEATURE_CULLING; viewer.getCamera()->setCullingMode( cullingMode ); @@ -137,13 +139,8 @@ namespace MWRender mViewer.getCamera()->setCullingMode(cullingMode); mViewDistance = Settings::Manager::getFloat("viewing distance", "Viewing distance"); - - double fovy, aspect, zNear, zFar; - mViewer.getCamera()->getProjectionMatrixAsPerspective(fovy, aspect, zNear, zFar); - fovy = 55.f; - zNear = 5.f; - zFar = mViewDistance; - mViewer.getCamera()->setProjectionMatrixAsPerspective(fovy, aspect, zNear, zFar); + mFieldOfView = Settings::Manager::getFloat("field of view", "General"); + updateProjectionMatrix(); } RenderingManager::~RenderingManager() @@ -325,4 +322,31 @@ namespace MWRender //mWater->addEmitter(ptr); } + void RenderingManager::updateProjectionMatrix() + { + double fovy, aspect, zNear, zFar; + mViewer.getCamera()->getProjectionMatrixAsPerspective(fovy, aspect, zNear, zFar); + fovy = mFieldOfView; + zNear = 5.f; + zFar = mViewDistance; + mViewer.getCamera()->setProjectionMatrixAsPerspective(fovy, aspect, zNear, zFar); + } + + void RenderingManager::processChangedSettings(const Settings::CategorySettingVector &changed) + { + for (Settings::CategorySettingVector::const_iterator it = changed.begin(); it != changed.end(); ++it) + { + if (it->first == "General" && it->second == "field of view") + { + mFieldOfView = Settings::Manager::getFloat("field of view", "General"); + updateProjectionMatrix(); + } + else if (it->first == "Viewing distance" && it->second == "viewing distance") + { + mViewDistance = Settings::Manager::getFloat("viewing distance", "Viewing distance"); + updateProjectionMatrix(); + } + } + } + } diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 7d902b854..b13dffb8c 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -4,6 +4,8 @@ #include #include +#include + #include "objects.hpp" #include "renderinginterface.hpp" @@ -93,7 +95,11 @@ namespace MWRender void setupPlayer(const MWWorld::Ptr& player); void renderPlayer(const MWWorld::Ptr& player); + void processChangedSettings(const Settings::CategorySettingVector& settings); + private: + void updateProjectionMatrix(); + osgViewer::Viewer& mViewer; osg::ref_ptr mRootNode; osg::ref_ptr mLightRoot; @@ -111,6 +117,7 @@ namespace MWRender osg::ref_ptr mStateUpdater; float mViewDistance; + float mFieldOfView; void operator = (const RenderingManager&); RenderingManager(const RenderingManager&); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 32eb92d2a..bbd98be56 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1971,7 +1971,7 @@ namespace MWWorld void World::processChangedSettings(const Settings::CategorySettingVector& settings) { - //mRendering->processChangedSettings(settings); + mRendering->processChangedSettings(settings); } bool World::isFlying(const MWWorld::Ptr &ptr) const diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 7f2185b62..eeea0e6e1 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -132,6 +132,9 @@ fog start factor = 0.5 # Distance at which fog ends (proportional to viewing distance) fog end factor = 1.0 +# Culling of objects smaller than a pixel +small feature culling = true + [Terrain] distant land = false From 5442bf23a6e8fe16f2feefbf18877d13561590ae Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 14 May 2015 20:31:16 +0200 Subject: [PATCH 1184/3725] Apply video mode & gamma setting changes --- apps/openmw/mwinput/inputmanagerimp.cpp | 35 ++++++++- apps/openmw/mwinput/inputmanagerimp.hpp | 5 ++ components/CMakeLists.txt | 2 +- components/sdlutil/sdlvideowrapper.cpp | 94 +++++++++++++++++++++++ components/sdlutil/sdlvideowrapper.hpp | 44 +++++++++++ files/mygui/openmw_settings_window.layout | 2 +- files/settings-default.cfg | 5 +- 7 files changed, 182 insertions(+), 5 deletions(-) create mode 100644 components/sdlutil/sdlvideowrapper.cpp create mode 100644 components/sdlutil/sdlvideowrapper.hpp diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 0fc25db4c..6abd3c0c9 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -14,6 +14,7 @@ #include #include +#include #include "../engine.hpp" @@ -101,10 +102,13 @@ namespace MWInput OMW::Engine& engine, const std::string& userFile, bool userFileExists, const std::string& controllerBindingsFile, bool grab) - : mJoystickLastUsed(false) + : mWindow(window) + , mViewer(viewer) + , mJoystickLastUsed(false) , mPlayer(NULL) , mEngine(engine) , mInputManager(NULL) + , mVideoWrapper(NULL) , mUserFile(userFile) , mDragDrop(false) , mGrabCursor (Settings::Manager::getBool("grab cursor", "Input")) @@ -141,6 +145,10 @@ namespace MWInput mInputManager->setWindowEventCallback(this); mInputManager->setControllerEventCallback(this); + mVideoWrapper = new SDLUtil::VideoWrapper(window, viewer); + mVideoWrapper->setGammaContrast(Settings::Manager::getFloat("gamma", "Video"), + Settings::Manager::getFloat("contrast", "Video")); + std::string file = userFileExists ? userFile : ""; mInputBinder = new ICS::InputControlSystem(file, true, this, NULL, A_Last); @@ -201,6 +209,8 @@ namespace MWInput delete mInputBinder; delete mInputManager; + + delete mVideoWrapper; } void InputManager::setPlayerControlsEnabled(bool enabled) @@ -614,6 +624,8 @@ namespace MWInput void InputManager::processChangedSettings(const Settings::CategorySettingVector& changed) { + bool changeRes = false; + for (Settings::CategorySettingVector::const_iterator it = changed.begin(); it != changed.end(); ++it) { @@ -629,6 +641,27 @@ namespace MWInput if (it->first == "Input" && it->second == "grab cursor") mGrabCursor = Settings::Manager::getBool("grab cursor", "Input"); + if (it->first == "Video" && ( + it->second == "resolution x" + || it->second == "resolution y" + || it->second == "fullscreen" + || it->second == "window border")) + changeRes = true; + + if (it->first == "Video" && it->second == "vsync") + mVideoWrapper->setSyncToVBlank(Settings::Manager::getBool("vsync", "Video")); + + if (it->first == "Video" && (it->second == "gamma" || it->second == "contrast")) + mVideoWrapper->setGammaContrast(Settings::Manager::getFloat("gamma", "Video"), + Settings::Manager::getFloat("contrast", "Video")); + } + + if (changeRes) + { + mVideoWrapper->setVideoMode(Settings::Manager::getInt("resolution x", "Video"), + Settings::Manager::getInt("resolution y", "Video"), + Settings::Manager::getBool("fullscreen", "Video"), + Settings::Manager::getBool("window border", "Video")); } } diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 27c08ed32..6b636058f 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -48,6 +48,7 @@ namespace Files namespace SDLUtil { class InputWrapper; + class VideoWrapper; } namespace osgViewer @@ -151,6 +152,9 @@ namespace MWInput void clearAllControllerBindings (ICS::Control* control); private: + SDL_Window* mWindow; + osg::ref_ptr mViewer; + bool mJoystickLastUsed; MWWorld::Player* mPlayer; OMW::Engine& mEngine; @@ -158,6 +162,7 @@ namespace MWInput ICS::InputControlSystem* mInputBinder; SDLUtil::InputWrapper* mInputManager; + SDLUtil::VideoWrapper* mVideoWrapper; std::string mUserFile; diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 0c76f666b..b800da701 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -127,7 +127,7 @@ add_component_dir (fontloader ) add_component_dir (sdlutil - sdlgraphicswindow imagetosurface sdlinputwrapper OISCompat events sdlcursormanager + sdlgraphicswindow imagetosurface sdlinputwrapper sdlvideowrapper OISCompat events sdlcursormanager ) add_component_dir (version diff --git a/components/sdlutil/sdlvideowrapper.cpp b/components/sdlutil/sdlvideowrapper.cpp new file mode 100644 index 000000000..dd89d1072 --- /dev/null +++ b/components/sdlutil/sdlvideowrapper.cpp @@ -0,0 +1,94 @@ +#include "sdlvideowrapper.hpp" + +#include + +#include + +#include + +namespace SDLUtil +{ + + VideoWrapper::VideoWrapper(SDL_Window *window, osg::ref_ptr viewer) + : mWindow(window) + , mViewer(viewer) + , mGamma(1.f) + , mContrast(1.f) + , mHasSetGammaContrast(false) + { + SDL_GetWindowGammaRamp(mWindow, mOldSystemGammaRamp, &mOldSystemGammaRamp[256], &mOldSystemGammaRamp[512]); + } + + VideoWrapper::~VideoWrapper() + { + SDL_SetWindowFullscreen(mWindow, 0); + + // If user hasn't touched the defaults no need to restore + if (mHasSetGammaContrast) + SDL_SetWindowGammaRamp(mWindow, mOldSystemGammaRamp, &mOldSystemGammaRamp[256], &mOldSystemGammaRamp[512]); + } + + void VideoWrapper::setSyncToVBlank(bool sync) + { + osgViewer::Viewer::Windows windows; + mViewer->getWindows(windows); + mViewer->stopThreading(); + for (osgViewer::Viewer::Windows::iterator it = windows.begin(); it != windows.end(); ++it) + { + osgViewer::GraphicsWindow* win = *it; + win->setSyncToVBlank(sync); + } + mViewer->startThreading(); + } + + void VideoWrapper::setGammaContrast(float gamma, float contrast) + { + if (gamma == mGamma && contrast == mContrast) + return; + + mGamma = gamma; + mContrast = contrast; + + mHasSetGammaContrast = true; + + Uint16 red[256], green[256], blue[256]; + for (int i = 0; i < 256; i++) + { + float k = i/256.0f; + k = (k - 0.5f) * contrast + 0.5f; + k = pow(k, 1.f/gamma); + k *= 256; + float value = k*256; + if (value > 65535) value = 65535; + else if (value < 0) value = 0; + + red[i] = green[i] = blue[i] = static_cast(value); + } + if (SDL_SetWindowGammaRamp(mWindow, red, green, blue) < 0) + std::cout << "Couldn't set gamma: " << SDL_GetError() << std::endl; + } + + void VideoWrapper::setVideoMode(int width, int height, bool fullscreen, bool windowBorder) + { + SDL_SetWindowFullscreen(mWindow, 0); + + if (SDL_GetWindowFlags(mWindow) & SDL_WINDOW_MAXIMIZED) + SDL_RestoreWindow(mWindow); + + if (fullscreen) + { + SDL_DisplayMode mode; + SDL_GetWindowDisplayMode(mWindow, &mode); + mode.w = width; + mode.h = height; + SDL_SetWindowDisplayMode(mWindow, &mode); + SDL_SetWindowFullscreen(mWindow, fullscreen); + } + else + { + SDL_SetWindowSize(mWindow, width, height); + SDL_SetWindowBordered(mWindow, windowBorder ? SDL_TRUE : SDL_FALSE); + } + } + +} diff --git a/components/sdlutil/sdlvideowrapper.hpp b/components/sdlutil/sdlvideowrapper.hpp new file mode 100644 index 000000000..77f0b8039 --- /dev/null +++ b/components/sdlutil/sdlvideowrapper.hpp @@ -0,0 +1,44 @@ +#ifndef OPENMW_COMPONENTS_SDLUTIL_SDLVIDEOWRAPPER_H +#define OPENMW_COMPONENTS_SDLUTIL_SDLVIDEOWRAPPER_H + +#include + +#include + +struct SDL_Window; + +namespace osgViewer +{ + class Viewer; +} + +namespace SDLUtil +{ + + class VideoWrapper + { + public: + VideoWrapper(SDL_Window* window, osg::ref_ptr viewer); + ~VideoWrapper(); + + void setSyncToVBlank(bool sync); + + void setGammaContrast(float gamma, float contrast); + + void setVideoMode(int width, int height, bool fullscreen, bool windowBorder); + + private: + SDL_Window* mWindow; + osg::ref_ptr mViewer; + + float mGamma; + float mContrast; + bool mHasSetGammaContrast; + + // Store system gamma ramp on window creation. Restore system gamma ramp on exit + Uint16 mOldSystemGammaRamp[256*3]; + }; + +} + +#endif diff --git a/files/mygui/openmw_settings_window.layout b/files/mygui/openmw_settings_window.layout index 768652e1a..397a9df04 100644 --- a/files/mygui/openmw_settings_window.layout +++ b/files/mygui/openmw_settings_window.layout @@ -299,7 +299,7 @@ - + diff --git a/files/settings-default.cfg b/files/settings-default.cfg index eeea0e6e1..d28240f2c 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -26,6 +26,9 @@ vsync = false # PBuffer, FBO, Copy opengl rtt mode = FBO +gamma = 1.00 +contrast = 1.00 + [GUI] # 1 is fully opaque menu transparency = 0.84 @@ -43,8 +46,6 @@ stretch menu background = false [General] # Camera field of view field of view = 55 -gamma = 1.00 -contrast = 1.00 # Texture filtering mode. valid values: # none From 24bb2e152cdd54b08b06b4c0b5b8b80f8f5f0ebc Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 14 May 2015 21:42:04 +0200 Subject: [PATCH 1185/3725] Apply texture filter setting changes --- apps/openmw/engine.cpp | 8 ++++- apps/openmw/mwgui/settingswindow.cpp | 8 ++--- apps/openmw/mwrender/renderingmanager.cpp | 40 ++++++++++++++++------- apps/openmw/mwrender/renderingmanager.hpp | 5 +-- apps/openmw/mwworld/worldimp.cpp | 2 +- apps/openmw/mwworld/worldimp.hpp | 2 +- components/resource/texturemanager.cpp | 21 ++++++++++++ components/resource/texturemanager.hpp | 7 +++- files/mygui/openmw_settings_window.layout | 1 - files/settings-default.cfg | 5 +-- 10 files changed, 72 insertions(+), 27 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index f9bb297a9..9fb233140 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -419,6 +419,12 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) mResourceSystem.reset(new Resource::ResourceSystem(mVFS.get())); mResourceSystem->getTextureManager()->setUnRefImageDataAfterApply(true); + osg::Texture::FilterMode min = osg::Texture::LINEAR_MIPMAP_NEAREST; + osg::Texture::FilterMode mag = osg::Texture::LINEAR; + if (Settings::Manager::getString("texture filtering", "General") == "trilinear") + min = osg::Texture::LINEAR_MIPMAP_LINEAR; + int maxAnisotropy = Settings::Manager::getInt("anisotropy", "General"); + mResourceSystem->getTextureManager()->setFilterSettings(min, mag, maxAnisotropy); // Create input and UI first to set up a bootstrapping environment for // showing a loading screen and keeping the window responsive while doing so @@ -469,7 +475,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) } // Create the world - mEnvironment.setWorld( new MWWorld::World (*mViewer, rootNode, mResourceSystem.get(), + mEnvironment.setWorld( new MWWorld::World (mViewer, rootNode, mResourceSystem.get(), mFileCollections, mContentFiles, mEncoder, mFallbackMap, mActivationDistanceOverride, mCellName, mStartupScript)); MWBase::Environment::get().getWorld()->setupPlayer(); diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index c23e2bb94..8ba46339a 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -38,12 +38,10 @@ namespace std::string textureFilteringToStr(const std::string& val) { - if (val == "anisotropic") - return "Anisotropic"; - else if (val == "bilinear") - return "Bilinear"; - else + if (val == "trilinear") return "Trilinear"; + else + return "Bilinear"; } void parseResolution (int &x, int &y, const std::string& str) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 7822ccb30..7e742e729 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -14,6 +14,7 @@ #include #include +#include #include @@ -82,7 +83,7 @@ namespace MWRender float mFogEnd; }; - RenderingManager::RenderingManager(osgViewer::Viewer &viewer, osg::ref_ptr rootNode, Resource::ResourceSystem* resourceSystem) + RenderingManager::RenderingManager(osgViewer::Viewer* viewer, osg::ref_ptr rootNode, Resource::ResourceSystem* resourceSystem) : mViewer(viewer) , mRootNode(rootNode) , mResourceSystem(resourceSystem) @@ -97,13 +98,13 @@ namespace MWRender mObjects.reset(new Objects(mResourceSystem, lightRoot)); - mViewer.setIncrementalCompileOperation(new osgUtil::IncrementalCompileOperation); + mViewer->setIncrementalCompileOperation(new osgUtil::IncrementalCompileOperation); - mObjects->setIncrementalCompileOperation(mViewer.getIncrementalCompileOperation()); + mObjects->setIncrementalCompileOperation(mViewer->getIncrementalCompileOperation()); mEffectManager.reset(new EffectManager(mRootNode, mResourceSystem)); - mViewer.setLightingMode(osgViewer::View::NO_LIGHT); + mViewer->setLightingMode(osgViewer::View::NO_LIGHT); osg::ref_ptr source = new osg::LightSource; mSunLight = new osg::Light; @@ -133,10 +134,10 @@ namespace MWRender else cullingMode |= osg::CullStack::SMALL_FEATURE_CULLING; - viewer.getCamera()->setCullingMode( cullingMode ); + mViewer->getCamera()->setCullingMode( cullingMode ); - mViewer.getCamera()->setComputeNearFarMode(osg::Camera::DO_NOT_COMPUTE_NEAR_FAR); - mViewer.getCamera()->setCullingMode(cullingMode); + mViewer->getCamera()->setComputeNearFarMode(osg::Camera::DO_NOT_COMPUTE_NEAR_FAR); + mViewer->getCamera()->setCullingMode(cullingMode); mViewDistance = Settings::Manager::getFloat("viewing distance", "Viewing distance"); mFieldOfView = Settings::Manager::getFloat("field of view", "General"); @@ -184,7 +185,7 @@ namespace MWRender osg::Vec3f RenderingManager::getEyePos() { - osg::Vec3d eye = mViewer.getCameraManipulator()->getMatrix().getTrans(); + osg::Vec3d eye = mViewer->getCameraManipulator()->getMatrix().getTrans(); return eye; } @@ -232,7 +233,7 @@ namespace MWRender void RenderingManager::configureFog(float /* fogDepth */, const osg::Vec4f &colour) { - mViewer.getCamera()->setClearColor(colour); + mViewer->getCamera()->setClearColor(colour); mStateUpdater->setFogColor(colour); mStateUpdater->setFogEnd(mViewDistance); @@ -325,11 +326,26 @@ namespace MWRender void RenderingManager::updateProjectionMatrix() { double fovy, aspect, zNear, zFar; - mViewer.getCamera()->getProjectionMatrixAsPerspective(fovy, aspect, zNear, zFar); + mViewer->getCamera()->getProjectionMatrixAsPerspective(fovy, aspect, zNear, zFar); fovy = mFieldOfView; zNear = 5.f; zFar = mViewDistance; - mViewer.getCamera()->setProjectionMatrixAsPerspective(fovy, aspect, zNear, zFar); + mViewer->getCamera()->setProjectionMatrixAsPerspective(fovy, aspect, zNear, zFar); + } + + void RenderingManager::updateTextureFiltering() + { + osg::Texture::FilterMode min = osg::Texture::LINEAR_MIPMAP_NEAREST; + osg::Texture::FilterMode mag = osg::Texture::LINEAR; + + if (Settings::Manager::getString("texture filtering", "General") == "trilinear") + min = osg::Texture::LINEAR_MIPMAP_LINEAR; + + int maxAnisotropy = Settings::Manager::getInt("anisotropy", "General"); + + mViewer->stopThreading(); + mResourceSystem->getTextureManager()->setFilterSettings(min, mag, maxAnisotropy); + mViewer->startThreading(); } void RenderingManager::processChangedSettings(const Settings::CategorySettingVector &changed) @@ -346,6 +362,8 @@ namespace MWRender mViewDistance = Settings::Manager::getFloat("viewing distance", "Viewing distance"); updateProjectionMatrix(); } + else if (it->first == "General" && (it->second == "texture filtering" || it->second == "anisotropy")) + updateTextureFiltering(); } } diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index b13dffb8c..32e081995 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -45,7 +45,7 @@ namespace MWRender class RenderingManager : public MWRender::RenderingInterface { public: - RenderingManager(osgViewer::Viewer& viewer, osg::ref_ptr rootNode, Resource::ResourceSystem* resourceSystem); + RenderingManager(osgViewer::Viewer* viewer, osg::ref_ptr rootNode, Resource::ResourceSystem* resourceSystem); ~RenderingManager(); MWRender::Objects& getObjects(); @@ -99,8 +99,9 @@ namespace MWRender private: void updateProjectionMatrix(); + void updateTextureFiltering(); - osgViewer::Viewer& mViewer; + osg::ref_ptr mViewer; osg::ref_ptr mRootNode; osg::ref_ptr mLightRoot; Resource::ResourceSystem* mResourceSystem; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index bbd98be56..91484a6ba 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -143,7 +143,7 @@ namespace MWWorld } World::World ( - osgViewer::Viewer& viewer, + osgViewer::Viewer* viewer, osg::ref_ptr rootNode, Resource::ResourceSystem* resourceSystem, const Files::Collections& fileCollections, diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 279d35329..21ad2d7ef 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -162,7 +162,7 @@ namespace MWWorld public: World ( - osgViewer::Viewer& viewer, + osgViewer::Viewer* viewer, osg::ref_ptr rootNode, Resource::ResourceSystem* resourceSystem, const Files::Collections& fileCollections, diff --git a/components/resource/texturemanager.cpp b/components/resource/texturemanager.cpp index b9b9fad5f..5f2ca19ef 100644 --- a/components/resource/texturemanager.cpp +++ b/components/resource/texturemanager.cpp @@ -36,6 +36,9 @@ namespace Resource TextureManager::TextureManager(const VFS::Manager *vfs) : mVFS(vfs) + , mMinFilter(osg::Texture::LINEAR_MIPMAP_LINEAR) + , mMagFilter(osg::Texture::LINEAR) + , mMaxAnisotropy(1) , mWarningTexture(createWarningTexture()) , mUnRefImageDataAfterApply(false) { @@ -52,6 +55,21 @@ namespace Resource mUnRefImageDataAfterApply = unref; } + void TextureManager::setFilterSettings(osg::Texture::FilterMode minFilter, osg::Texture::FilterMode magFilter, int maxAnisotropy) + { + mMinFilter = minFilter; + mMagFilter = magFilter; + mMaxAnisotropy = std::max(1, maxAnisotropy); + + for (std::map >::iterator it = mTextures.begin(); it != mTextures.end(); ++it) + { + osg::ref_ptr tex = it->second; + tex->setFilter(osg::Texture::MIN_FILTER, mMinFilter); + tex->setFilter(osg::Texture::MAG_FILTER, mMagFilter); + tex->setMaxAnisotropy(static_cast(mMaxAnisotropy)); + } + } + /* osg::ref_ptr TextureManager::getImage(const std::string &filename) { @@ -110,6 +128,9 @@ namespace Resource texture->setImage(image); texture->setWrap(osg::Texture::WRAP_S, wrapS); texture->setWrap(osg::Texture::WRAP_T, wrapT); + texture->setFilter(osg::Texture::MIN_FILTER, mMinFilter); + texture->setFilter(osg::Texture::MAG_FILTER, mMagFilter); + texture->setMaxAnisotropy(mMaxAnisotropy); texture->setUnRefImageDataAfterApply(mUnRefImageDataAfterApply); diff --git a/components/resource/texturemanager.hpp b/components/resource/texturemanager.hpp index 851a55166..5ff233348 100644 --- a/components/resource/texturemanager.hpp +++ b/components/resource/texturemanager.hpp @@ -23,7 +23,8 @@ namespace Resource TextureManager(const VFS::Manager* vfs); ~TextureManager(); - // TODO: texture filtering settings + /// @warning It is unsafe to call this function when a draw thread is using the textures. Call stopThreading() first! + void setFilterSettings(osg::Texture::FilterMode minFilter, osg::Texture::FilterMode maxFilter, int maxAnisotropy); /// Keep a copy of the texture data around in system memory? This is needed when using multiple graphics contexts, /// otherwise should be disabled to reduce memory usage. @@ -40,6 +41,10 @@ namespace Resource private: const VFS::Manager* mVFS; + osg::Texture::FilterMode mMinFilter; + osg::Texture::FilterMode mMagFilter; + int mMaxAnisotropy; + typedef std::pair, std::string> MapKey; std::map > mImages; diff --git a/files/mygui/openmw_settings_window.layout b/files/mygui/openmw_settings_window.layout index 397a9df04..66514c886 100644 --- a/files/mygui/openmw_settings_window.layout +++ b/files/mygui/openmw_settings_window.layout @@ -322,7 +322,6 @@ - diff --git a/files/settings-default.cfg b/files/settings-default.cfg index d28240f2c..4ad2a323f 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -48,13 +48,10 @@ stretch menu background = false field of view = 55 # Texture filtering mode. valid values: -# none -# anisotropic # bilinear # trilinear -texture filtering = anisotropic +texture filtering = -# Has no effect when texture filtering is not anisotropic anisotropy = 4 # Number of texture mipmaps to generate From a73362f036ce4ae541acdcf54c3d296a366937ff Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 14 May 2015 21:45:18 +0200 Subject: [PATCH 1186/3725] Settings file cleanup --- files/settings-default.cfg | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 4ad2a323f..cbb3ff6b0 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -12,20 +12,11 @@ screen = 0 # Minimize the window if it loses key focus? minimize on focus loss = true -# Valid values: -# none -# MSAA 2 -# MSAA 4 -# MSAA 8 -# MSAA 16 -antialiasing = none +# Valid values: 0 for no antialiasing, or any power of two +antialiasing = 0 vsync = false -# opengl render to texture mode, valid options: -# PBuffer, FBO, Copy -opengl rtt mode = FBO - gamma = 1.00 contrast = 1.00 @@ -54,9 +45,6 @@ texture filtering = anisotropy = 4 -# Number of texture mipmaps to generate -num mipmaps = 8 - screenshot format = png [Shadows] From 842ff4d874da28bfa77a51093552c6fb761ffb06 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 15 May 2015 00:23:31 +0200 Subject: [PATCH 1187/3725] Catch exception for not found videos --- apps/openmw/mwgui/videowidget.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/videowidget.cpp b/apps/openmw/mwgui/videowidget.cpp index 2c9b1c97e..d28ea0b66 100644 --- a/apps/openmw/mwgui/videowidget.cpp +++ b/apps/openmw/mwgui/videowidget.cpp @@ -30,7 +30,18 @@ void VideoWidget::playVideo(const std::string &video) { mPlayer->setAudioFactory(new MWSound::MovieAudioFactory()); - mPlayer->playVideo(mVFS->get(video), video); + Files::IStreamPtr videoStream; + try + { + videoStream = mVFS->get(video); + } + catch (std::exception& e) + { + std::cerr << "Failed to open video: " << e.what() << std::endl; + return; + } + + mPlayer->playVideo(videoStream, video); osg::ref_ptr texture = mPlayer->getVideoTexture(); if (!texture) From 49df07ea7f34c0aa952f53311bcc5e0c71198f1d Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 15 May 2015 00:41:21 +0200 Subject: [PATCH 1188/3725] Implement UI scaling factor --- apps/openmw/mwgui/windowbase.cpp | 7 +-- apps/openmw/mwgui/windowmanagerimp.cpp | 10 +++- apps/openmw/mwinput/inputmanagerimp.cpp | 56 +++++++++---------- apps/openmw/mwinput/inputmanagerimp.hpp | 8 ++- components/myguiplatform/myguiplatform.hpp | 4 +- .../myguiplatform/myguirendermanager.cpp | 40 ++----------- .../myguiplatform/myguirendermanager.hpp | 6 +- components/myguiplatform/myguitexture.cpp | 2 +- files/settings-default.cfg | 2 + 9 files changed, 61 insertions(+), 74 deletions(-) diff --git a/apps/openmw/mwgui/windowbase.cpp b/apps/openmw/mwgui/windowbase.cpp index 8fdcf6b20..c3be3539e 100644 --- a/apps/openmw/mwgui/windowbase.cpp +++ b/apps/openmw/mwgui/windowbase.cpp @@ -1,6 +1,7 @@ #include "windowbase.hpp" #include +#include #include @@ -48,11 +49,7 @@ void WindowBase::center() { // Centre dialog - // MyGUI::IntSize gameWindowSize = MyGUI::RenderManager::getInstance().getViewSize(); - // Note by scrawl: The following works more reliably in the case when the window was _just_ - // resized and MyGUI RenderManager doesn't know about the new size yet - MyGUI::IntSize gameWindowSize = MyGUI::IntSize(Settings::Manager::getInt("resolution x", "Video"), - Settings::Manager::getInt("resolution y", "Video")); + MyGUI::IntSize gameWindowSize = MyGUI::RenderManager::getInstance().getViewSize(); MyGUI::IntCoord coord = mMainWidget->getCoord(); coord.left = (gameWindowSize.width - coord.width)/2; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 3bedb5d5e..aef37809b 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -182,7 +182,8 @@ namespace MWGui , mFPS(0.0f) , mFallbackMap(fallbackMap) { - mGuiPlatform = new osgMyGUI::Platform(viewer, guiRoot, resourceSystem->getTextureManager()); + float uiScale = Settings::Manager::getFloat("scaling factor", "GUI"); + mGuiPlatform = new osgMyGUI::Platform(viewer, guiRoot, resourceSystem->getTextureManager(), uiScale); mGuiPlatform->initialise(resourcePath, logpath); mGui = new MyGUI::Gui; @@ -1104,6 +1105,13 @@ namespace MWGui void WindowManager::windowResized(int x, int y) { + mGuiPlatform->getRenderManagerPtr()->setViewSize(x, y); + + // scaled size + const MyGUI::IntSize& viewSize = MyGUI::RenderManager::getInstance().getViewSize(); + x = viewSize.width; + y = viewSize.height; + sizeVideo(x, y); if (!mHud) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 6abd3c0c9..7a3dd5e18 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -123,8 +123,8 @@ namespace MWInput , mGuiCursorEnabled(true) , mDetectingKeyboard(false) , mOverencumberedMessageDelay(0.f) - , mMouseX(0) - , mMouseY(0) + , mGuiCursorX(0) + , mGuiCursorY(0) , mMouseWheel(0) , mUserFileExists(userFileExists) , mAlwaysRunActive(Settings::Manager::getBool("always run", "Input")) @@ -132,13 +132,8 @@ namespace MWInput , mSneaking(false) , mAttemptJump(false) , mFakeDeviceID(1) + , mInvUiScalingFactor(1.f) { - int w,h; - SDL_GetWindowSize(window, &w, &h); - - mMouseX = w / 2.f; - mMouseY = h / 2.f; - mInputManager = new SDLUtil::InputWrapper(window, viewer, grab); mInputManager->setMouseEventCallback (this); mInputManager->setKeyboardEventCallback (this); @@ -193,6 +188,16 @@ namespace MWInput //ICS_LOG(std::string("Unusable controller plugged in: ")+SDL_JoystickNameForIndex(i)); } } + + float uiScale = Settings::Manager::getFloat("scaling factor", "GUI"); + if (uiScale != 0.f) + mInvUiScalingFactor = 1.f / uiScale; + + int w,h; + SDL_GetWindowSize(window, &w, &h); + + mGuiCursorX = mInvUiScalingFactor * w / 2.f; + mGuiCursorY = mInvUiScalingFactor * h / 2.f; } void InputManager::clear() @@ -394,7 +399,7 @@ namespace MWInput //cursor is if( !is_relative && was_relative != is_relative ) { - mInputManager->warpMouse(static_cast(mMouseX), static_cast(mMouseY)); + mInputManager->warpMouse(static_cast(mGuiCursorX/mInvUiScalingFactor), static_cast(mGuiCursorY/mInvUiScalingFactor)); } } @@ -406,7 +411,7 @@ namespace MWInput mInputManager->capture(disableEvents); // inject some fake mouse movement to force updating MyGUI's widget states - MyGUI::InputManager::getInstance().injectMouseMove( int(mMouseX), int(mMouseY), mMouseWheel); + MyGUI::InputManager::getInstance().injectMouseMove( int(mGuiCursorX), int(mGuiCursorY), mMouseWheel); if (mControlsDisabled) { @@ -430,15 +435,15 @@ namespace MWInput // We keep track of our own mouse position, so that moving the mouse while in // game mode does not move the position of the GUI cursor - mMouseX += xAxis * dt * 1500.0f; - mMouseY += yAxis * dt * 1500.0f; + mGuiCursorX += xAxis * dt * 1500.0f * mInvUiScalingFactor; + mGuiCursorY += yAxis * dt * 1500.0f * mInvUiScalingFactor; mMouseWheel -= static_cast(zAxis * dt * 1500.0f); - mMouseX = std::max(0.f, std::min(mMouseX, float(viewSize.width))); - mMouseY = std::max(0.f, std::min(mMouseY, float(viewSize.height))); + mGuiCursorX = std::max(0.f, std::min(mGuiCursorX, float(viewSize.width))); + mGuiCursorY = std::max(0.f, std::min(mGuiCursorY, float(viewSize.height))); - MyGUI::InputManager::getInstance().injectMouseMove(static_cast(mMouseX), static_cast(mMouseY), mMouseWheel); - mInputManager->warpMouse(static_cast(mMouseX), static_cast(mMouseY)); + MyGUI::InputManager::getInstance().injectMouseMove(static_cast(mGuiCursorX), static_cast(mGuiCursorY), mMouseWheel); + mInputManager->warpMouse(static_cast(mGuiCursorX/mInvUiScalingFactor), static_cast(mGuiCursorY/mInvUiScalingFactor)); } if (mMouseLookEnabled) { @@ -741,7 +746,7 @@ namespace MWInput if (id == SDL_BUTTON_LEFT || id == SDL_BUTTON_RIGHT) // MyGUI only uses these mouse events { guiMode = MWBase::Environment::get().getWindowManager()->isGuiMode(); - guiMode = MyGUI::InputManager::getInstance().injectMousePress(static_cast(mMouseX), static_cast(mMouseY), sdlButtonToMyGUI(id)) && guiMode; + guiMode = MyGUI::InputManager::getInstance().injectMousePress(static_cast(mGuiCursorX), static_cast(mGuiCursorY), sdlButtonToMyGUI(id)) && guiMode; if (MyGUI::InputManager::getInstance ().getMouseFocusWidget () != 0) { MyGUI::Button* b = MyGUI::InputManager::getInstance ().getMouseFocusWidget ()->castType(false); @@ -768,7 +773,7 @@ namespace MWInput mInputBinder->mouseReleased (arg, id); } else { bool guiMode = MWBase::Environment::get().getWindowManager()->isGuiMode(); - guiMode = MyGUI::InputManager::getInstance().injectMouseRelease(static_cast(mMouseX), static_cast(mMouseY), sdlButtonToMyGUI(id)) && guiMode; + guiMode = MyGUI::InputManager::getInstance().injectMouseRelease(static_cast(mGuiCursorX), static_cast(mGuiCursorY), sdlButtonToMyGUI(id)) && guiMode; if(mInputBinder->detectingBindingState()) return; // don't allow same mouseup to bind as initiated bind @@ -786,19 +791,14 @@ namespace MWInput if (mGuiCursorEnabled) { - const MyGUI::IntSize& viewSize = MyGUI::RenderManager::getInstance().getViewSize(); - // We keep track of our own mouse position, so that moving the mouse while in // game mode does not move the position of the GUI cursor - mMouseX = static_cast(arg.x); - mMouseY = static_cast(arg.y); - - mMouseX = std::max(0.f, std::min(mMouseX, float(viewSize.width))); - mMouseY = std::max(0.f, std::min(mMouseY, float(viewSize.height))); + mGuiCursorX = static_cast(arg.x) * mInvUiScalingFactor; + mGuiCursorY = static_cast(arg.y) * mInvUiScalingFactor; mMouseWheel = int(arg.z); - MyGUI::InputManager::getInstance().injectMouseMove( int(mMouseX), int(mMouseY), mMouseWheel); + MyGUI::InputManager::getInstance().injectMouseMove( int(mGuiCursorX), int(mGuiCursorY), mMouseWheel); } if (mMouseLookEnabled && !mControlsDisabled) @@ -840,7 +840,7 @@ namespace MWInput guiMode = MWBase::Environment::get().getWindowManager()->isGuiMode(); if(!mInputBinder->detectingBindingState()) { - guiMode = MyGUI::InputManager::getInstance().injectMousePress(static_cast(mMouseX), static_cast(mMouseY), + guiMode = MyGUI::InputManager::getInstance().injectMousePress(static_cast(mGuiCursorX), static_cast(mGuiCursorY), sdlButtonToMyGUI((arg.button == SDL_CONTROLLER_BUTTON_B) ? SDL_BUTTON_RIGHT : SDL_BUTTON_LEFT)) && guiMode; if (MyGUI::InputManager::getInstance ().getMouseFocusWidget () != 0) { @@ -872,7 +872,7 @@ namespace MWInput else if(arg.button == SDL_CONTROLLER_BUTTON_A || arg.button == SDL_CONTROLLER_BUTTON_B) { bool guiMode = MWBase::Environment::get().getWindowManager()->isGuiMode(); - guiMode = MyGUI::InputManager::getInstance().injectMouseRelease(static_cast(mMouseX), static_cast(mMouseY), sdlButtonToMyGUI((arg.button == SDL_CONTROLLER_BUTTON_B) ? SDL_BUTTON_RIGHT : SDL_BUTTON_LEFT)) && guiMode; + guiMode = MyGUI::InputManager::getInstance().injectMouseRelease(static_cast(mGuiCursorX), static_cast(mGuiCursorY), sdlButtonToMyGUI((arg.button == SDL_CONTROLLER_BUTTON_B) ? SDL_BUTTON_RIGHT : SDL_BUTTON_LEFT)) && guiMode; if(mInputBinder->detectingBindingState()) return; // don't allow same mouseup to bind as initiated bind diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 6b636058f..aec640736 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -187,8 +187,8 @@ namespace MWInput float mOverencumberedMessageDelay; - float mMouseX; - float mMouseY; + float mGuiCursorX; + float mGuiCursorY; int mMouseWheel; bool mUserFileExists; bool mAlwaysRunActive; @@ -198,7 +198,11 @@ namespace MWInput std::map mControlSwitch; + float mInvUiScalingFactor; + private: + void convertMousePosForMyGUI(int& x, int& y); + MyGUI::MouseButton sdlButtonToMyGUI(Uint8 button); virtual std::string sdlControllerAxisToString(int axis); diff --git a/components/myguiplatform/myguiplatform.hpp b/components/myguiplatform/myguiplatform.hpp index c0c9e0ce4..513267c99 100644 --- a/components/myguiplatform/myguiplatform.hpp +++ b/components/myguiplatform/myguiplatform.hpp @@ -14,14 +14,14 @@ namespace osgMyGUI class Platform { public: - Platform(osgViewer::Viewer* viewer, osg::Group* guiRoot, Resource::TextureManager* textureManager) + Platform(osgViewer::Viewer* viewer, osg::Group* guiRoot, Resource::TextureManager* textureManager, float uiScalingFactor) : mRenderManager(nullptr) , mDataManager(nullptr) , mLogManager(nullptr) , mLogFacility(nullptr) { mLogManager = new MyGUI::LogManager(); - mRenderManager = new RenderManager(viewer, guiRoot, textureManager); + mRenderManager = new RenderManager(viewer, guiRoot, textureManager, uiScalingFactor); mDataManager = new DataManager(); } diff --git a/components/myguiplatform/myguirendermanager.cpp b/components/myguiplatform/myguirendermanager.cpp index 3caa61548..e2f2f9820 100644 --- a/components/myguiplatform/myguirendermanager.cpp +++ b/components/myguiplatform/myguirendermanager.cpp @@ -40,37 +40,6 @@ } \ } while(0) -namespace -{ - -// Proxy to forward an OSG resize event to RenderManager::setViewSize -class ResizeHandler : public osgGA::GUIEventHandler { - osgMyGUI::RenderManager *mParent; - - virtual bool handle(const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter &aa) - { - if(ea.getEventType() == osgGA::GUIEventAdapter::RESIZE) - { - int width = ea.getWindowWidth(); - int height = ea.getWindowHeight(); - mParent->setViewSize(width, height); - } - return false; - } - -public: - ResizeHandler(osgMyGUI::RenderManager *parent=nullptr) : mParent(parent) { } - ResizeHandler(const ResizeHandler ©, const osg::CopyOp ©op=osg::CopyOp::SHALLOW_COPY) - : osg::Object(copy, copyop), osgGA::GUIEventHandler(copy, copyop) - , mParent(copy.mParent) - { } - - META_Object(osgMyGUI, ResizeHandler) -}; - -} - - namespace osgMyGUI { @@ -322,13 +291,16 @@ void OSGVertexBuffer::create() // --------------------------------------------------------------------------- -RenderManager::RenderManager(osgViewer::Viewer *viewer, osg::Group *sceneroot, Resource::TextureManager* textureManager) +RenderManager::RenderManager(osgViewer::Viewer *viewer, osg::Group *sceneroot, Resource::TextureManager* textureManager, float scalingFactor) : mViewer(viewer) , mSceneRoot(sceneroot) , mTextureManager(textureManager) , mUpdate(false) , mIsInitialise(false) + , mInvScalingFactor(1.f) { + if (scalingFactor != 0.f) + mInvScalingFactor = 1.f / scalingFactor; } RenderManager::~RenderManager() @@ -380,7 +352,6 @@ void RenderManager::initialise() mGuiRoot = camera; mSceneRoot->addChild(mGuiRoot.get()); - mViewer->addEventHandler(new ResizeHandler(this)); osg::ref_ptr vp = mViewer->getCamera()->getViewport(); setViewSize(vp->width(), vp->height()); @@ -458,7 +429,8 @@ void RenderManager::setViewSize(int width, int height) if(height < 1) height = 1; mGuiRoot->setViewport(0, 0, width, height); - mViewSize.set(width, height); + + mViewSize.set(width * mInvScalingFactor, height * mInvScalingFactor); mInfo.maximumDepth = 1; mInfo.hOffset = 0; diff --git a/components/myguiplatform/myguirendermanager.hpp b/components/myguiplatform/myguirendermanager.hpp index afb07eaa6..d9fdc1834 100644 --- a/components/myguiplatform/myguirendermanager.hpp +++ b/components/myguiplatform/myguirendermanager.hpp @@ -46,15 +46,19 @@ class RenderManager : public MyGUI::RenderManager, public MyGUI::IRenderTarget osg::ref_ptr mGuiRoot; + float mInvScalingFactor; + void destroyAllResources(); public: - RenderManager(osgViewer::Viewer *viewer, osg::Group *sceneroot, Resource::TextureManager* textureManager); + RenderManager(osgViewer::Viewer *viewer, osg::Group *sceneroot, Resource::TextureManager* textureManager, float scalingFactor); virtual ~RenderManager(); void initialise(); void shutdown(); + void setScalingFactor(float factor); + static RenderManager& getInstance() { return *getInstancePtr(); } static RenderManager* getInstancePtr() { return static_cast(MyGUI::RenderManager::getInstancePtr()); } diff --git a/components/myguiplatform/myguitexture.cpp b/components/myguiplatform/myguitexture.cpp index 68408dd3a..2a32dd9f3 100644 --- a/components/myguiplatform/myguitexture.cpp +++ b/components/myguiplatform/myguitexture.cpp @@ -86,7 +86,7 @@ namespace osgMyGUI if (!mTextureManager) throw std::runtime_error("No texturemanager set"); - mTexture = mTextureManager->getTexture2D(fname, osg::Texture2D::CLAMP, osg::Texture2D::CLAMP); + mTexture = mTextureManager->getTexture2D(fname, osg::Texture2D::REPEAT, osg::Texture2D::REPEAT); // FIXME mFormat = MyGUI::PixelFormat::R8G8B8; diff --git a/files/settings-default.cfg b/files/settings-default.cfg index cbb3ff6b0..fc8571bf8 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -21,6 +21,8 @@ gamma = 1.00 contrast = 1.00 [GUI] +scaling factor = 1.0 + # 1 is fully opaque menu transparency = 0.84 From f92d801fafa64ea3cabd78886a3d6dae2760b5af Mon Sep 17 00:00:00 2001 From: cc9cii Date: Fri, 15 May 2015 12:32:29 +1000 Subject: [PATCH 1189/3725] Jump to the added/cloned record (or undeleted record in case of undo). Should resolve Feature #2541. Controlled by radio buttons on user preferences settings. --- apps/opencs/model/settings/usersettings.cpp | 8 +++ apps/opencs/view/world/table.cpp | 54 +++++++++++++++++++-- apps/opencs/view/world/table.hpp | 4 ++ 3 files changed, 63 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/settings/usersettings.cpp b/apps/opencs/model/settings/usersettings.cpp index 9e00b7d1a..41ce593b7 100644 --- a/apps/opencs/model/settings/usersettings.cpp +++ b/apps/opencs/model/settings/usersettings.cpp @@ -206,6 +206,14 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() shiftCtrlDoubleClick->setDeclaredValues (values); shiftCtrlDoubleClick->setDefaultValue (editRecordAndClose); shiftCtrlDoubleClick->setToolTip ("Action on shift control double click in table:

" + toolTip); + + QString defaultValue = "Jump and Select"; + QStringList jumpValues = QStringList() << defaultValue << "Jump Only" << "No Jump"; + + Setting *jumpToAdded = createSetting (Type_RadioButton, "jump-to-added", + "Jump to the added or cloned record."); + jumpToAdded->setDefaultValue (defaultValue); + jumpToAdded->setDeclaredValues (jumpValues); } declareSection ("search", "Search & Replace"); diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index 5a650f98a..44150bbc6 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -21,6 +21,7 @@ #include "../../model/world/tablemimedata.hpp" #include "../../model/world/tablemimedata.hpp" #include "../../model/world/commanddispatcher.hpp" +#include "../../model/settings/usersettings.hpp" #include "recordstatusdelegate.hpp" #include "util.hpp" @@ -255,6 +256,24 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id, : mCreateAction (0), mCloneAction(0), mRecordStatusDisplay (0), DragRecordTable(document) { + CSMSettings::UserSettings &settings = CSMSettings::UserSettings::instance(); + QString jumpSetting = settings.settingValue ("table-input/jump-to-added"); + if (jumpSetting.isEmpty() || jumpSetting == "Jump and Select") // default + { + mJumpToAddedRecord = true; + mUnselectAfterJump = false; + } + else if(jumpSetting == "Jump Only") + { + mJumpToAddedRecord = true; + mUnselectAfterJump = true; + } + else + { + mJumpToAddedRecord = false; + mUnselectAfterJump = false; + } + mModel = &dynamic_cast (*mDocument.getData().getTableModel (id)); mProxyModel = new CSMWorld::IdTableProxyModel (this); @@ -346,7 +365,7 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id, addAction (mExtendedRevertAction); connect (mProxyModel, SIGNAL (rowsInserted (const QModelIndex&, int, int)), - this, SLOT (tableSizeUpdate())); + this, SLOT (rowsInsertedEvent(const QModelIndex&, int, int))); /// \note This signal could instead be connected to a slot that filters out changes not affecting /// the records status column (for permanence reasons) @@ -517,9 +536,27 @@ void CSVWorld::Table::previewRecord() } } -void CSVWorld::Table::updateUserSetting - (const QString &name, const QStringList &list) +void CSVWorld::Table::updateUserSetting (const QString &name, const QStringList &list) { + if (name=="table-input/jump-to-added") + { + if(list.isEmpty() || list.at(0) == "Jump and Select") // default + { + mJumpToAddedRecord = true; + mUnselectAfterJump = false; + } + else if(list.at(0) == "Jump Only") + { + mJumpToAddedRecord = true; + mUnselectAfterJump = true; + } + else // No Jump + { + mJumpToAddedRecord = false; + mUnselectAfterJump = false; + } + } + if (name=="records/type-format" || name=="records/status-format") { int columns = mModel->columnCount(); @@ -700,3 +737,14 @@ std::vector< CSMWorld::UniversalId > CSVWorld::Table::getDraggedRecords() const return idToDrag; } +void CSVWorld::Table::rowsInsertedEvent(const QModelIndex& parent, int start, int end) +{ + tableSizeUpdate(); + if(mJumpToAddedRecord) + { + selectRow(end); + + if(mUnselectAfterJump) + clearSelection(); + } +} diff --git a/apps/opencs/view/world/table.hpp b/apps/opencs/view/world/table.hpp index 75161b8b6..becb21f65 100644 --- a/apps/opencs/view/world/table.hpp +++ b/apps/opencs/view/world/table.hpp @@ -67,6 +67,8 @@ namespace CSVWorld CSMWorld::CommandDispatcher *mDispatcher; CSMWorld::UniversalId mEditCellId; std::map mDoubleClickActions; + bool mJumpToAddedRecord; + bool mUnselectAfterJump; private: @@ -139,6 +141,8 @@ namespace CSVWorld void recordFilterChanged (boost::shared_ptr filter); void updateUserSetting (const QString &name, const QStringList &list); + + void rowsInsertedEvent(const QModelIndex& parent, int start, int end); }; } From 28617c8beb8cf3353033b2d946d6f2bd93c3a561 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Fri, 15 May 2015 12:33:31 +1000 Subject: [PATCH 1190/3725] Update table size status for removed rows. --- apps/opencs/view/world/table.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index 44150bbc6..86daf8af7 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -364,6 +364,9 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id, connect (mExtendedRevertAction, SIGNAL (triggered()), mDispatcher, SLOT (executeExtendedRevert())); addAction (mExtendedRevertAction); + connect (mProxyModel, SIGNAL (rowsRemoved (const QModelIndex&, int, int)), + this, SLOT (tableSizeUpdate())); + connect (mProxyModel, SIGNAL (rowsInserted (const QModelIndex&, int, int)), this, SLOT (rowsInsertedEvent(const QModelIndex&, int, int))); From 27000fb36b8a2ffdfb4d57087b5751cb1e7526b0 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 15 May 2015 14:09:35 +0200 Subject: [PATCH 1191/3725] don't reject single precision float values in value filters (Fixes #2533) --- apps/opencs/model/filter/valuenode.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/filter/valuenode.cpp b/apps/opencs/model/filter/valuenode.cpp index 72cf5896b..6fdae3e1b 100644 --- a/apps/opencs/model/filter/valuenode.cpp +++ b/apps/opencs/model/filter/valuenode.cpp @@ -27,7 +27,7 @@ bool CSMFilter::ValueNode::test (const CSMWorld::IdTableBase& table, int row, QVariant data = table.data (index); if (data.type()!=QVariant::Double && data.type()!=QVariant::Bool && data.type()!=QVariant::Int && - data.type()!=QVariant::UInt) + data.type()!=QVariant::UInt && data.type()!=static_cast (QMetaType::Float)) return false; double value = data.toDouble(); From b7fa64553009effbc4b6c0cab3838560396ed6bd Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 15 May 2015 19:34:18 +0200 Subject: [PATCH 1192/3725] Don't destroy a NULL window --- apps/openmw/engine.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 9fb233140..be873d09b 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -235,8 +235,11 @@ OMW::Engine::~Engine() mViewer = NULL; - SDL_DestroyWindow(mWindow); - mWindow = NULL; + if (mWindow) + { + SDL_DestroyWindow(mWindow); + mWindow = NULL; + } SDL_Quit(); } From 737c2114dcfb86110d8cddd6cef3a9f91a37ddd0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 15 May 2015 19:43:48 +0200 Subject: [PATCH 1193/3725] Change viewer stats keybinding to F9 --- apps/openmw/engine.cpp | 1 + components/sdlutil/sdlinputwrapper.cpp | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index be873d09b..ca21e3612 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -542,6 +542,7 @@ void OMW::Engine::go() mViewer = new osgViewer::Viewer; osg::ref_ptr statshandler = new osgViewer::StatsHandler; + statshandler->setKeyEventTogglesOnScreenStats(osgGA::GUIEventAdapter::KEY_F9); statshandler->addUserStatsLine("Script", osg::Vec4f(1.f, 1.f, 1.f, 1.f), osg::Vec4f(1.f, 1.f, 1.f, 1.f), "script_time_taken", 1000.0, true, false, "script_time_begin", "script_time_end", 10000); diff --git a/components/sdlutil/sdlinputwrapper.cpp b/components/sdlutil/sdlinputwrapper.cpp index eb3370cf7..1f47d5304 100644 --- a/components/sdlutil/sdlinputwrapper.cpp +++ b/components/sdlutil/sdlinputwrapper.cpp @@ -84,8 +84,8 @@ InputWrapper::InputWrapper(SDL_Window* window, osg::ref_ptr v mKeyboardListener->keyPressed(evt.key); // temporary for the stats viewer - if (evt.key.keysym.sym == SDLK_s) - mViewer->getEventQueue()->keyPress('s'); + if (evt.key.keysym.sym == SDLK_F9) + mViewer->getEventQueue()->keyPress(osgGA::GUIEventAdapter::KEY_F9); break; case SDL_KEYUP: @@ -93,8 +93,8 @@ InputWrapper::InputWrapper(SDL_Window* window, osg::ref_ptr v mKeyboardListener->keyReleased(evt.key); // temporary for the stats viewer - if (evt.key.keysym.sym == SDLK_s) - mViewer->getEventQueue()->keyRelease('s'); + if (evt.key.keysym.sym == SDLK_F9) + mViewer->getEventQueue()->keyRelease(osgGA::GUIEventAdapter::KEY_F9); break; case SDL_TEXTINPUT: From bec9abd319c866796f2c6ad9c1a4f4715466757e Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 15 May 2015 23:21:29 +0200 Subject: [PATCH 1194/3725] Remove name extension for internal MyGUI textures Since they're no longer loaded from disk, the extension makes no sense. --- apps/openmw/mwgui/backgroundimage.cpp | 2 +- apps/openmw/mwgui/mainmenu.cpp | 2 +- apps/openmw/mwgui/mapwindow.cpp | 4 ++-- apps/openmw/mwgui/windowmanagerimp.cpp | 14 +++++++------- files/mygui/openmw_screen_fader.layout | 2 +- files/mygui/openmw_windows.skin.xml | 4 ++-- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwgui/backgroundimage.cpp b/apps/openmw/mwgui/backgroundimage.cpp index ee966c189..98828a041 100644 --- a/apps/openmw/mwgui/backgroundimage.cpp +++ b/apps/openmw/mwgui/backgroundimage.cpp @@ -14,7 +14,7 @@ void BackgroundImage::setBackgroundImage (const std::string& image, bool fixedRa } if (!stretch) { - setImageTexture("black.png"); + setImageTexture("black"); if (fixedRatio) mAspect = 4.0/3.0; diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index f594cd43c..dbc513049 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -170,7 +170,7 @@ namespace MWGui // Use black background to correct aspect ratio mVideoBackground = MyGUI::Gui::getInstance().createWidgetReal("ImageBox", 0,0,1,1, MyGUI::Align::Default, "Menu"); - mVideoBackground->setImageTexture("black.png"); + mVideoBackground->setImageTexture("black"); mVideo = mVideoBackground->createWidget("ImageBox", 0,0,1,1, MyGUI::Align::Stretch, "Menu"); diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index d65e242de..4b3711071 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -222,7 +222,7 @@ namespace MWGui MyGUI::ImageBox* fog = mFogWidgets[my + 3*mx]; fog->setImageTexture(mFogOfWar ? ((MyGUI::RenderManager::getInstance().getTexture(image+"_fog") != 0) ? image+"_fog" - : "black.png" ) + : "black" ) : ""); } } @@ -354,7 +354,7 @@ namespace MWGui if (MyGUI::RenderManager::getInstance().getTexture(image) != 0) box->setImageTexture(image); else - box->setImageTexture("black.png"); + box->setImageTexture("black"); } } #endif diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index aef37809b..0a9e86750 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -238,7 +238,7 @@ namespace MWGui mVideoBackground = MyGUI::Gui::getInstance().createWidgetReal("ImageBox", 0,0,1,1, MyGUI::Align::Default, "Overlay"); - mVideoBackground->setImageTexture("black.png"); + mVideoBackground->setImageTexture("black"); mVideoBackground->setVisible(false); mVideoBackground->setNeedMouseFocus(true); mVideoBackground->setNeedKeyFocus(true); @@ -309,14 +309,14 @@ namespace MWGui mJailScreen = new JailScreen(); mWerewolfFader = new ScreenFader("textures\\werewolfoverlay.dds"); - mBlindnessFader = new ScreenFader("black.png"); + mBlindnessFader = new ScreenFader("black"); std::string hitFaderTexture = "textures\\bm_player_hit_01.dds"; // fall back to player_hit_01.dds if bm_player_hit_01.dds is not available // TODO: check if non-BM versions actually use player_hit_01.dds if(!mResourceSystem->getVFS()->exists(hitFaderTexture)) hitFaderTexture = "textures\\player_hit_01.dds"; mHitFader = new ScreenFader(hitFaderTexture); - mScreenFader = new ScreenFader("black.png"); + mScreenFader = new ScreenFader("black"); mDebugWindow = new DebugWindow(); @@ -1941,7 +1941,7 @@ namespace MWGui void WindowManager::createTextures() { { - MyGUI::ITexture* tex = MyGUI::RenderManager::getInstance().createTexture("white.png"); + MyGUI::ITexture* tex = MyGUI::RenderManager::getInstance().createTexture("white"); tex->createManual(8, 8, MyGUI::TextureUsage::Write, MyGUI::PixelFormat::R8G8B8); unsigned char* data = reinterpret_cast(tex->lock(MyGUI::TextureUsage::Write)); for (int x=0; x<8; ++x) @@ -1955,7 +1955,7 @@ namespace MWGui } { - MyGUI::ITexture* tex = MyGUI::RenderManager::getInstance().createTexture("black.png"); + MyGUI::ITexture* tex = MyGUI::RenderManager::getInstance().createTexture("black"); tex->createManual(8, 8, MyGUI::TextureUsage::Write, MyGUI::PixelFormat::R8G8B8); unsigned char* data = reinterpret_cast(tex->lock(MyGUI::TextureUsage::Write)); for (int x=0; x<8; ++x) @@ -1969,7 +1969,7 @@ namespace MWGui } { - MyGUI::ITexture* tex = MyGUI::RenderManager::getInstance().createTexture("transparent.png"); + MyGUI::ITexture* tex = MyGUI::RenderManager::getInstance().createTexture("transparent"); tex->createManual(8, 8, MyGUI::TextureUsage::Write, MyGUI::PixelFormat::R8G8B8A8); setMenuTransparency(Settings::Manager::getFloat("menu transparency", "GUI")); } @@ -1977,7 +1977,7 @@ namespace MWGui void WindowManager::setMenuTransparency(float value) { - MyGUI::ITexture* tex = MyGUI::RenderManager::getInstance().getTexture("transparent.png"); + MyGUI::ITexture* tex = MyGUI::RenderManager::getInstance().getTexture("transparent"); unsigned char* data = reinterpret_cast(tex->lock(MyGUI::TextureUsage::Write)); for (int x=0; x<8; ++x) for (int y=0; y<8; ++y) diff --git a/files/mygui/openmw_screen_fader.layout b/files/mygui/openmw_screen_fader.layout index fffd2e66e..13234792f 100644 --- a/files/mygui/openmw_screen_fader.layout +++ b/files/mygui/openmw_screen_fader.layout @@ -2,6 +2,6 @@ - + diff --git a/files/mygui/openmw_windows.skin.xml b/files/mygui/openmw_windows.skin.xml index ca95a552b..e74038391 100644 --- a/files/mygui/openmw_windows.skin.xml +++ b/files/mygui/openmw_windows.skin.xml @@ -2,7 +2,7 @@ - + @@ -122,7 +122,7 @@ - + From 60a835c16d0ae58e1fed8fe933dad752c4e03a5d Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 16 May 2015 10:18:11 +0200 Subject: [PATCH 1195/3725] stop script editor from eating undo/redo shortcuts (Fixes #2506) --- apps/opencs/view/world/scriptedit.cpp | 13 +++++++++++++ apps/opencs/view/world/scriptedit.hpp | 4 ++++ 2 files changed, 17 insertions(+) diff --git a/apps/opencs/view/world/scriptedit.cpp b/apps/opencs/view/world/scriptedit.cpp index b4f4234f1..2e05fa110 100644 --- a/apps/opencs/view/world/scriptedit.cpp +++ b/apps/opencs/view/world/scriptedit.cpp @@ -25,6 +25,19 @@ CSVWorld::ScriptEdit::ChangeLock::~ChangeLock() --mEdit.mChangeLocked; } +bool CSVWorld::ScriptEdit::event (QEvent *event) +{ + // ignore undo and redo shortcuts + if (event->type()==QEvent::ShortcutOverride) + { + QKeyEvent *keyEvent = static_cast (event); + + if (keyEvent->matches (QKeySequence::Undo) || keyEvent->matches (QKeySequence::Redo)) + return true; + } + + return QPlainTextEdit::event (event); +} CSVWorld::ScriptEdit::ScriptEdit (const CSMDoc::Document& document, ScriptHighlighter::Mode mode, QWidget* parent) diff --git a/apps/opencs/view/world/scriptedit.hpp b/apps/opencs/view/world/scriptedit.hpp index a19cee486..fb577e60e 100644 --- a/apps/opencs/view/world/scriptedit.hpp +++ b/apps/opencs/view/world/scriptedit.hpp @@ -53,6 +53,10 @@ namespace CSVWorld QFont mDefaultFont; QFont mMonoFont; + protected: + + bool event (QEvent *event); + public: ScriptEdit (const CSMDoc::Document& document, ScriptHighlighter::Mode mode, From 7d321e0fb7faba64cbb5f11dea2ea8dbf70bdb27 Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Sat, 16 May 2015 13:18:04 +0300 Subject: [PATCH 1196/3725] Fix #2557 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Don’t show main dialog right away if wizard is selected. --- apps/launcher/main.cpp | 6 ++++-- apps/launcher/maindialog.cpp | 10 +++++----- apps/launcher/maindialog.hpp | 8 +++++++- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/apps/launcher/main.cpp b/apps/launcher/main.cpp index 11ea56869..ba0686110 100644 --- a/apps/launcher/main.cpp +++ b/apps/launcher/main.cpp @@ -59,14 +59,16 @@ int main(int argc, char *argv[]) Launcher::MainDialog mainWin; - if (!mainWin.showFirstRunDialog()) + Launcher::FirstRunDialogResult result = mainWin.showFirstRunDialog(); + if (result == Launcher::FirstRunDialogResultFailure) return 0; // if (!mainWin.setup()) { // return 0; // } - mainWin.show(); + if (result == Launcher::FirstRunDialogResultContinue) + mainWin.show(); int returnValue = app.exec(); SDL_Quit(); diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index 00e6a9aa2..fd36993bf 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -148,10 +148,10 @@ void Launcher::MainDialog::createPages() } -bool Launcher::MainDialog::showFirstRunDialog() +Launcher::FirstRunDialogResult Launcher::MainDialog::showFirstRunDialog() { if (!setupLauncherSettings()) - return false; + return FirstRunDialogResultFailure; if (mLauncherSettings.value(QString("General/firstrun"), QString("true")) == QLatin1String("true")) { @@ -176,14 +176,14 @@ bool Launcher::MainDialog::showFirstRunDialog() if (msgBox.clickedButton() == wizardButton) { if (!mWizardInvoker->startProcess(QLatin1String("openmw-wizard"), false)) { - return false; + return FirstRunDialogResultFailure; } else { - return true; + return FirstRunDialogResultWizard; } } } - return setup(); + return setup() ? FirstRunDialogResultContinue : FirstRunDialogResultFailure; } bool Launcher::MainDialog::setup() diff --git a/apps/launcher/maindialog.hpp b/apps/launcher/maindialog.hpp index 0708f7002..4c21dbaf4 100644 --- a/apps/launcher/maindialog.hpp +++ b/apps/launcher/maindialog.hpp @@ -31,6 +31,12 @@ namespace Launcher class UnshieldThread; class SettingsPage; + typedef enum { + FirstRunDialogResultFailure, + FirstRunDialogResultContinue, + FirstRunDialogResultWizard + } FirstRunDialogResult; + #ifndef WIN32 bool expansions(Launcher::UnshieldThread& cd); #endif @@ -44,7 +50,7 @@ namespace Launcher ~MainDialog(); bool setup(); - bool showFirstRunDialog(); + FirstRunDialogResult showFirstRunDialog(); bool reloadSettings(); bool writeSettings(); From 1b41f6c4c54bbb8f46393bb8f57fcdf00ef820f5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 16 May 2015 12:29:26 +0200 Subject: [PATCH 1197/3725] Sleep interruption fix --- apps/openmw/mwgui/waitdialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index 94905dd9e..28e3be591 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -157,7 +157,7 @@ namespace MWGui // figure out if player will be woken while sleeping int x = OEngine::Misc::Rng::rollDice(hoursToWait); float fSleepRandMod = world->getStore().get().find("fSleepRandMod")->getFloat(); - if (x > fSleepRandMod * hoursToWait) + if (x < fSleepRandMod * hoursToWait) { float fSleepRestMod = world->getStore().get().find("fSleepRestMod")->getFloat(); mInterruptAt = hoursToWait - int(fSleepRestMod * hoursToWait); From 75ace9f8b51bb619c825f3fb8de2a1953dbe0b58 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 16 May 2015 14:48:20 +0200 Subject: [PATCH 1198/3725] Global map base layer --- apps/openmw/CMakeLists.txt | 4 +- apps/openmw/mwgui/mapwindow.cpp | 40 +++++++++----------- apps/openmw/mwgui/mapwindow.hpp | 3 +- apps/openmw/mwrender/globalmap.cpp | 60 +++++++++++++----------------- apps/openmw/mwrender/globalmap.hpp | 22 ++++++----- 5 files changed, 60 insertions(+), 69 deletions(-) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 95875de10..7d66b2aba 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -22,10 +22,10 @@ source_group(game FILES ${GAME} ${GAME_HEADER}) add_openmw_dir (mwrender actors objects renderingmanager animation sky npcanimation vismask creatureanimation effectmanager util renderinginterface pathgrid rendermode - bulletdebugdraw + bulletdebugdraw globalmap # camera # localmap occlusionquery water shadows -# characterpreview globalmap ripplesimulation refraction +# characterpreview ripplesimulation refraction # terrainstorage weaponanimation ) diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 4b3711071..a44c0214c 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -1,8 +1,9 @@ #include "mapwindow.hpp" -#include #include +#include + #include #include #include @@ -14,6 +15,7 @@ #include #include +#include #include "../mwbase/windowmanager.hpp" #include "../mwbase/world.hpp" @@ -559,6 +561,7 @@ namespace MWGui : WindowPinnableBase("openmw_map_window.layout") , NoDrop(drag, mMainWidget) , LocalMapBase(customMarkers) + , mGlobalMapTexture(NULL) , mGlobal(false) , mGlobalMap(0) //, mGlobalMapRender(0) @@ -708,19 +711,23 @@ namespace MWGui void MapWindow::renderGlobalMap(Loading::Listener* loadingListener) { -#if 0 - mGlobalMapRender = new MWRender::GlobalMap(""); + mGlobalMapRender = new MWRender::GlobalMap(); mGlobalMapRender->render(loadingListener); mGlobalMap->setCanvasSize (mGlobalMapRender->getWidth(), mGlobalMapRender->getHeight()); mGlobalMapImage->setSize(mGlobalMapRender->getWidth(), mGlobalMapRender->getHeight()); - mGlobalMapImage->setImageTexture("GlobalMap.png"); - mGlobalMapOverlay->setImageTexture("GlobalMapOverlay"); -#endif + + mGlobalMapTexture = new osgMyGUI::OSGTexture(mGlobalMapRender->getBaseTexture()); + mGlobalMapImage->setRenderItemTexture(mGlobalMapTexture); + mGlobalMapImage->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 0.f, 1.f, 1.f)); + + //mGlobalMapOverlay->setImageTexture("GlobalMapOverlay"); } MapWindow::~MapWindow() { - //delete mGlobalMapRender; + delete mGlobalMapTexture; + + delete mGlobalMapRender; } void MapWindow::setCellName(const std::string& cellName) @@ -730,7 +737,6 @@ namespace MWGui void MapWindow::addVisitedLocation(const std::string& name, int x, int y) { -#if 0 CellId cell; cell.first = x; cell.second = y; @@ -757,7 +763,6 @@ namespace MWGui markerWidget->eventMouseDrag += MyGUI::newDelegate(this, &MapWindow::onMouseDrag); markerWidget->eventMouseButtonPressed += MyGUI::newDelegate(this, &MapWindow::onDragStart); } -#endif } void MapWindow::cellExplored(int x, int y) @@ -769,12 +774,11 @@ namespace MWGui { LocalMapBase::onFrame(dt); -#if 0 for (std::vector::iterator it = mQueuedToExplore.begin(); it != mQueuedToExplore.end(); ++it) { mGlobalMapRender->exploreCell(it->first, it->second); } -#endif + mQueuedToExplore.clear(); NoDrop::onFrame(dt); @@ -831,14 +835,12 @@ namespace MWGui void MapWindow::globalMapUpdatePlayer () { -#if 0 // For interiors, position is set by WindowManager via setGlobalMapPlayerPosition if (MWBase::Environment::get().getWorld ()->isCellExterior ()) { - Ogre::Vector3 pos = MWBase::Environment::get().getWorld ()->getPlayerPtr().getRefData ().getBaseNode ()->_getDerivedPosition (); - setGlobalMapPlayerPosition(pos.x, pos.y); + osg::Vec3f pos = MWBase::Environment::get().getWorld ()->getPlayerPtr().getRefData().getPosition().asVec3(); + setGlobalMapPlayerPosition(pos.x(), pos.y()); } -#endif } void MapWindow::notifyPlayerUpdate () @@ -848,7 +850,6 @@ namespace MWGui void MapWindow::setGlobalMapPlayerPosition(float worldX, float worldY) { -#if 0 float x, y; mGlobalMapRender->worldPosToImageSpace (worldX, worldY, x, y); x *= mGlobalMapRender->getWidth(); @@ -860,7 +861,6 @@ namespace MWGui MyGUI::IntSize viewsize = mGlobalMap->getSize(); MyGUI::IntPoint viewoffs(static_cast(viewsize.width * 0.5f - x), static_cast(viewsize.height *0.5 - y)); mGlobalMap->setViewOffset(viewoffs); -#endif } void MapWindow::setGlobalMapPlayerDir(const float x, const float y) @@ -876,7 +876,7 @@ namespace MWGui { mMarkers.clear(); - //mGlobalMapRender->clear(); + mGlobalMapRender->clear(); mChanged = true; while (mEventBoxGlobal->getChildCount()) @@ -885,7 +885,6 @@ namespace MWGui void MapWindow::write(ESM::ESMWriter &writer, Loading::Listener& progress) { -#if 0 ESM::GlobalMap map; mGlobalMapRender->write(map); @@ -894,12 +893,10 @@ namespace MWGui writer.startRecord(ESM::REC_GMAP); map.save(writer); writer.endRecord(ESM::REC_GMAP); -#endif } void MapWindow::readRecord(ESM::ESMReader &reader, uint32_t type) { -#if 0 if (type == ESM::REC_GMAP) { ESM::GlobalMap map; @@ -914,7 +911,6 @@ namespace MWGui addVisitedLocation(cell->mName, it->first, it->second); } } -#endif } void MapWindow::setAlpha(float alpha) diff --git a/apps/openmw/mwgui/mapwindow.hpp b/apps/openmw/mwgui/mapwindow.hpp index 68d2e28de..1e1e2c97e 100644 --- a/apps/openmw/mwgui/mapwindow.hpp +++ b/apps/openmw/mwgui/mapwindow.hpp @@ -195,6 +195,7 @@ namespace MWGui void globalMapUpdatePlayer(); MyGUI::ScrollView* mGlobalMap; + MyGUI::ITexture* mGlobalMapTexture; MyGUI::ImageBox* mGlobalMapImage; MyGUI::ImageBox* mGlobalMapOverlay; MyGUI::ImageBox* mPlayerArrowLocal; @@ -216,7 +217,7 @@ namespace MWGui MyGUI::Button* mEventBoxGlobal; MyGUI::Button* mEventBoxLocal; - //MWRender::GlobalMap* mGlobalMapRender; + MWRender::GlobalMap* mGlobalMapRender; EditNoteDialog mEditNoteDialog; ESM::CustomMarker mEditingMarker; diff --git a/apps/openmw/mwrender/globalmap.cpp b/apps/openmw/mwrender/globalmap.cpp index 95d4429d6..897225a72 100644 --- a/apps/openmw/mwrender/globalmap.cpp +++ b/apps/openmw/mwrender/globalmap.cpp @@ -1,14 +1,9 @@ #include "globalmap.hpp" -#include -#include +#include -#include -#include -#include -#include -#include -#include +#include +#include #include #include @@ -23,9 +18,8 @@ namespace MWRender { - GlobalMap::GlobalMap(const std::string &cacheDir) - : mCacheDir(cacheDir) - , mMinX(0), mMaxX(0) + GlobalMap::GlobalMap() + : mMinX(0), mMaxX(0) , mMinY(0), mMaxY(0) , mWidth(0) , mHeight(0) @@ -35,13 +29,10 @@ namespace MWRender GlobalMap::~GlobalMap() { - Ogre::TextureManager::getSingleton().remove(mOverlayTexture->getName()); } void GlobalMap::render (Loading::Listener* loadingListener) { - Ogre::TexturePtr tex; - const MWWorld::ESMStore &esmStore = MWBase::Environment::get().getWorld()->getStore(); @@ -67,7 +58,9 @@ namespace MWRender loadingListener->setProgressRange((mMaxX-mMinX+1) * (mMaxY-mMinY+1)); loadingListener->setProgress(0); - std::vector data (mWidth * mHeight * 3); + osg::ref_ptr image = new osg::Image; + image->allocateImage(mWidth, mHeight, 1, GL_RGB, GL_UNSIGNED_BYTE); + unsigned char* data = image->data(); for (int x = mMinX; x <= mMaxX; ++x) { @@ -139,16 +132,8 @@ namespace MWRender } } - Ogre::DataStreamPtr stream(new Ogre::MemoryDataStream(&data[0], data.size())); - - tex = Ogre::TextureManager::getSingleton ().createManual ("GlobalMap.png", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - Ogre::TEX_TYPE_2D, mWidth, mHeight, 0, Ogre::PF_B8G8R8, Ogre::TU_STATIC); - tex->loadRawData(stream, mWidth, mHeight, Ogre::PF_B8G8R8); - - tex->load(); - - mOverlayTexture = Ogre::TextureManager::getSingleton().createManual("GlobalMapOverlay", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - Ogre::TEX_TYPE_2D, mWidth, mHeight, 0, Ogre::PF_A8B8G8R8, Ogre::TU_DYNAMIC, this); + mBaseTexture = new osg::Texture2D; + mBaseTexture->setImage(image); clear(); @@ -172,13 +157,14 @@ namespace MWRender void GlobalMap::exploreCell(int cellX, int cellY) { - float originX = static_cast((cellX - mMinX) * mCellSize); + //float originX = static_cast((cellX - mMinX) * mCellSize); // NB y + 1, because we want the top left corner, not bottom left where the origin of the cell is - float originY = static_cast(mHeight - (cellY + 1 - mMinY) * mCellSize); + //float originY = static_cast(mHeight - (cellY + 1 - mMinY) * mCellSize); if (cellX > mMaxX || cellX < mMinX || cellY > mMaxY || cellY < mMinY) return; + /* Ogre::TexturePtr localMapTexture = Ogre::TextureManager::getSingleton().getByName("Cell_" + boost::lexical_cast(cellX) + "_" + boost::lexical_cast(cellY)); @@ -208,24 +194,19 @@ namespace MWRender mOverlayImage.setColourAt(backup.getColourAt(x, y, 0), static_cast(originX + x), static_cast(originY + y), 0); } } + */ } void GlobalMap::clear() { + /* Ogre::uchar* buffer = OGRE_ALLOC_T(Ogre::uchar, mWidth * mHeight * 4, Ogre::MEMCATEGORY_GENERAL); memset(buffer, 0, mWidth * mHeight * 4); mOverlayImage.loadDynamicImage(&buffer[0], mWidth, mHeight, 1, Ogre::PF_A8B8G8R8, true); // pass ownership of buffer to image mOverlayTexture->load(); - } - - void GlobalMap::loadResource(Ogre::Resource *resource) - { - Ogre::Texture* tex = static_cast(resource); - Ogre::ConstImagePtrList list; - list.push_back(&mOverlayImage); - tex->_loadImages(list); + */ } void GlobalMap::write(ESM::GlobalMap& map) @@ -235,9 +216,11 @@ namespace MWRender map.mBounds.mMinY = mMinY; map.mBounds.mMaxY = mMaxY; + /* Ogre::DataStreamPtr encoded = mOverlayImage.encode("png"); map.mImageData.resize(encoded->size()); encoded->read(&map.mImageData[0], encoded->size()); + */ } void GlobalMap::read(ESM::GlobalMap& map) @@ -253,6 +236,7 @@ namespace MWRender || bounds.mMinY > bounds.mMaxY) throw std::runtime_error("invalid map bounds"); + /* Ogre::Image image; Ogre::DataStreamPtr stream(new Ogre::MemoryDataStream(&map.mImageData[0], map.mImageData.size())); image.load(stream, "png"); @@ -309,5 +293,11 @@ namespace MWRender mOverlayTexture->convertToImage(mOverlayImage); Ogre::TextureManager::getSingleton().remove("@temp"); + */ + } + + osg::ref_ptr GlobalMap::getBaseTexture() + { + return mBaseTexture; } } diff --git a/apps/openmw/mwrender/globalmap.hpp b/apps/openmw/mwrender/globalmap.hpp index a162ab68f..d7e20a3a7 100644 --- a/apps/openmw/mwrender/globalmap.hpp +++ b/apps/openmw/mwrender/globalmap.hpp @@ -2,8 +2,14 @@ #define GAME_RENDER_GLOBALMAP_H #include +#include -#include +#include + +namespace osg +{ + class Texture2D; +} namespace Loading { @@ -18,10 +24,10 @@ namespace ESM namespace MWRender { - class GlobalMap : public Ogre::ManualResourceLoader + class GlobalMap { public: - GlobalMap(const std::string& cacheDir); + GlobalMap(); ~GlobalMap(); void render(Loading::Listener* loadingListener); @@ -37,23 +43,21 @@ namespace MWRender void exploreCell (int cellX, int cellY); - virtual void loadResource(Ogre::Resource* resource); - /// Clears the overlay void clear(); void write (ESM::GlobalMap& map); void read (ESM::GlobalMap& map); - private: - std::string mCacheDir; + osg::ref_ptr getBaseTexture(); + //osg::ref_ptr getOverlayTexture(); + private: int mCellSize; std::vector< std::pair > mExploredCells; - Ogre::TexturePtr mOverlayTexture; - Ogre::Image mOverlayImage; // Backup in system memory + osg::ref_ptr mBaseTexture; int mWidth; int mHeight; From 34f106749a3b302f00f9c0172e1a5911dca4c6df Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 17 May 2015 10:38:15 +0200 Subject: [PATCH 1199/3725] removed a redundant typedef --- apps/launcher/maindialog.hpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/launcher/maindialog.hpp b/apps/launcher/maindialog.hpp index 4c21dbaf4..c90309990 100644 --- a/apps/launcher/maindialog.hpp +++ b/apps/launcher/maindialog.hpp @@ -31,11 +31,12 @@ namespace Launcher class UnshieldThread; class SettingsPage; - typedef enum { + enum FirstRunDialogResult + { FirstRunDialogResultFailure, FirstRunDialogResultContinue, FirstRunDialogResultWizard - } FirstRunDialogResult; + }; #ifndef WIN32 bool expansions(Launcher::UnshieldThread& cd); From b9856162b33ff4f0d1a1d46d68b64373496b29ba Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 17 May 2015 10:38:54 +0200 Subject: [PATCH 1200/3725] updated changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3219edd9a..466c2ef25 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ Bug #2521: NPCs don't react to stealing when inventory menu is open. Bug #2525: Can't click on red dialogue choice [rise of house telvanni][60fffec] Bug #2530: GetSpellEffects not working as in vanilla + Bug #2557: Crash on first launch after choosing "Run installation wizard" Feature #139: Editor: Global Search & Replace Feature #1219: Editor: Add dialogue mode only columns Feature #2024: Hotkey for hand to hand (i.e. unequip any weapon) From e9ca02216201fdb64e1dcd59a6a385d8a4c067d5 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 17 May 2015 20:45:13 +1000 Subject: [PATCH 1201/3725] Add an optional horizontal scrollbar to the main view window. Should resolve Feature #2549. - TableSubviews and DialogueSubviews now provide size hints - Option to stop the growth of the window at the screen boundary for multi-monitor setup with different resolution. - Three options: Grow Only: No change to current, except the use of size hints Scrollbar Only: Simple addition of a scrollbar, the view window does not grow Grow then Scroll: Window grows as per current behaviour. The scrollbar appears once it cannot grow any further. --- apps/opencs/model/settings/usersettings.cpp | 14 ++ apps/opencs/view/doc/subview.cpp | 16 +++ apps/opencs/view/doc/subview.hpp | 13 ++ apps/opencs/view/doc/view.cpp | 145 +++++++++++++++++++- apps/opencs/view/doc/view.hpp | 5 + apps/opencs/view/world/dialoguesubview.cpp | 12 +- apps/opencs/view/world/tablesubview.cpp | 12 +- 7 files changed, 213 insertions(+), 4 deletions(-) diff --git a/apps/opencs/model/settings/usersettings.cpp b/apps/opencs/model/settings/usersettings.cpp index 41ce593b7..bd31b6e38 100644 --- a/apps/opencs/model/settings/usersettings.cpp +++ b/apps/opencs/model/settings/usersettings.cpp @@ -143,6 +143,20 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() minWidth->setDefaultValue (325); minWidth->setRange (50, 10000); minWidth->setToolTip ("Minimum width of subviews."); + + QString defaultScroll = "Scrollbar Only"; + QStringList scrollValues = QStringList() << defaultScroll << "Grow Only" << "Grow then Scroll"; + + Setting *mainwinScroll = createSetting (Type_RadioButton, "mainwindow-scrollbar", + "Add a horizontal scrollbar to the main view window."); + mainwinScroll->setDefaultValue (defaultScroll); + mainwinScroll->setDeclaredValues (scrollValues); + + Setting *grow = createSetting (Type_CheckBox, "grow-limit", "Grow Limit Screen"); + grow->setDefaultValue ("false"); + grow->setToolTip ("When \"Grow then Scroll\" option is selected, the window size grows to" + " the width of the virtual desktop. \nIf this option is selected the the window growth" + "is limited to the current screen."); } declareSection ("records", "Records"); diff --git a/apps/opencs/view/doc/subview.cpp b/apps/opencs/view/doc/subview.cpp index df1e7ee49..09128d919 100644 --- a/apps/opencs/view/doc/subview.cpp +++ b/apps/opencs/view/doc/subview.cpp @@ -43,3 +43,19 @@ void CSVDoc::SubView::closeRequest() { emit closeRequest (this); } + +CSVDoc::SizeHintWidget::SizeHintWidget(QWidget *parent) : QWidget(parent) +{} + +CSVDoc::SizeHintWidget::~SizeHintWidget() +{} + +QSize CSVDoc::SizeHintWidget::sizeHint() const +{ + return mSize; +} + +void CSVDoc::SizeHintWidget::setSizeHint(const QSize &size) +{ + mSize = size; +} diff --git a/apps/opencs/view/doc/subview.hpp b/apps/opencs/view/doc/subview.hpp index a8aa3cda1..f327107c2 100644 --- a/apps/opencs/view/doc/subview.hpp +++ b/apps/opencs/view/doc/subview.hpp @@ -8,6 +8,7 @@ #include "subviewfactory.hpp" #include +#include class QUndoStack; @@ -70,6 +71,18 @@ namespace CSVDoc void closeRequest(); }; + + class SizeHintWidget : public QWidget + { + QSize mSize; + + public: + SizeHintWidget(QWidget *parent = 0); + ~SizeHintWidget(); + + virtual QSize sizeHint() const; + void setSizeHint(const QSize &size); + }; } #endif diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 5636fff94..16b96ed4d 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -9,6 +9,10 @@ #include #include #include +#include +#include +#include +#include #include "../../model/doc/document.hpp" #include "../../model/settings/usersettings.hpp" @@ -16,6 +20,7 @@ #include "../../model/world/idtable.hpp" #include "../world/subviews.hpp" +#include "../world/tablesubview.hpp" #include "../tools/subviews.hpp" @@ -334,8 +339,15 @@ void CSVDoc::View::updateTitle() void CSVDoc::View::updateSubViewIndicies(SubView *view) { if(view && mSubViews.contains(view)) + { mSubViews.removeOne(view); + // adjust (reduce) the scroll area (even floating), except when it is "Scrollbar Only" + CSMSettings::UserSettings &settings = CSMSettings::UserSettings::instance(); + if(settings.settingValue ("window/mainwindow-scrollbar") == "Grow then Scroll") + updateScrollbar(); + } + CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); bool hideTitle = userSettings.setting ("window/hide-subview", QString ("false"))=="true" && @@ -381,7 +393,7 @@ void CSVDoc::View::updateActions() CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews) : mViewManager (viewManager), mDocument (document), mViewIndex (totalViews-1), - mViewTotal (totalViews) + mViewTotal (totalViews), mScroll(0), mScrollbarOnly(false) { int width = CSMSettings::UserSettings::instance().settingValue ("window/default-width").toInt(); @@ -400,7 +412,18 @@ CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int to mSubViewWindow.setDockOptions (QMainWindow::AllowNestedDocks); - setCentralWidget (&mSubViewWindow); + CSMSettings::UserSettings &settings = CSMSettings::UserSettings::instance(); + if(settings.settingValue ("window/mainwindow-scrollbar") == "Grow Only") + { + setCentralWidget (&mSubViewWindow); + } + else + { + mScroll = new QScrollArea(this); + mScroll->setWidgetResizable(true); + mScroll->setWidget(&mSubViewWindow); + setCentralWidget(mScroll); + } mOperations = new Operations; addDockWidget (Qt::BottomDockWidgetArea, mOperations); @@ -527,6 +550,59 @@ void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id, const std::strin view->setStatusBar (mShowStatusBar->isChecked()); + // Work out how to deal with additional subviews + // + // Policy for "Grow then Scroll": + // + // - Increase the horizontal width of the mainwindow until it becomes greater than or equal + // to the screen (monitor) width. + // - Move the mainwindow position sideways if necessary to fit within the screen. + // - Any more additions increases the size of the mSubViewWindow (horizontal scrollbar + // should become visible) + // - Move the scroll bar to the newly added subview + // + CSMSettings::UserSettings &settings = CSMSettings::UserSettings::instance(); + QString mainwinScroll = settings.settingValue ("window/mainwindow-scrollbar"); + if (mainwinScroll.isEmpty() || mainwinScroll == "Scrollbar Only") + mScrollbarOnly = true; + else if(mainwinScroll == "Grow Only") + mScrollbarOnly = false; + else + mScrollbarOnly = false; + + QDesktopWidget *dw = QApplication::desktop(); + QRect rect; + if(settings.settingValue ("window/grow-limit") == "true") + rect = dw->screenGeometry(this); + else + rect = dw->screenGeometry(dw->screen(dw->screenNumber(this))); + + if (!mScrollbarOnly && mScroll && mSubViews.size() > 1) + { + int newWidth = width()+minWidth; + int frameWidth = frameGeometry().width() - width(); + if (newWidth+frameWidth <= rect.width()) + { + resize(newWidth, height()); + // WARNING: below code assumes that new subviews are added to the right + if (x() > rect.width()-(newWidth+frameWidth)) + move(rect.width()-(newWidth+frameWidth), y()); // shift left to stay within the screen + } + else + { + // full width + resize(rect.width()-frameWidth, height()); + mSubViewWindow.setMinimumWidth(mSubViewWindow.width()+minWidth); + move(0, y()); + } + + // Make the new subview visible, setFocus() or raise() don't seem to work + // On Ubuntu the scrollbar does not go right to the end, even if using + // mScroll->horizontalScrollBar()->setValue(mScroll->horizontalScrollBar()->maximum()); + if (mSubViewWindow.width() > rect.width()) + mScroll->horizontalScrollBar()->setValue(mSubViewWindow.width()); + } + mSubViewWindow.addDockWidget (Qt::TopDockWidgetArea, view); updateSubViewIndicies(); @@ -774,6 +850,48 @@ void CSVDoc::View::updateUserSetting (const QString &name, const QStringList &li { subView->updateUserSetting (name, list); } + + if (name=="window/mainwindow-scrollbar") + { + if(list.at(0) != "Grow Only") + { + if (mScroll) + { + if (list.at(0).isEmpty() || list.at(0) == "Scrollbar Only") + { + mScrollbarOnly = true; + mSubViewWindow.setMinimumWidth(0); + } + else + { + if(!mScrollbarOnly) + return; + + mScrollbarOnly = false; + updateScrollbar(); + } + } + else + { + mScroll = new QScrollArea(this); + mScroll->setWidgetResizable(true); + mScroll->setWidget(&mSubViewWindow); + setCentralWidget(mScroll); + } + } + else + { + if (mScroll) + { + mScroll->takeWidget(); + setCentralWidget (&mSubViewWindow); + mScroll->deleteLater(); + mScroll = 0; + } + else + return; + } + } } void CSVDoc::View::toggleShowStatusBar (bool show) @@ -815,3 +933,26 @@ void CSVDoc::View::closeRequest (SubView *subView) else if (mViewManager.closeRequest (this)) mViewManager.removeDocAndView (mDocument); } + +void CSVDoc::View::updateScrollbar() +{ + QRect rect; + QWidget *topLevel = QApplication::topLevelAt(pos()); + if (topLevel) + rect = topLevel->rect(); + else + rect = this->rect(); + + int newWidth = 0; + for (int i = 0; i < mSubViews.size(); ++i) + { + newWidth += mSubViews[i]->width(); + } + + int frameWidth = frameGeometry().width() - width(); + + if ((newWidth+frameWidth) >= rect.width()) + mSubViewWindow.setMinimumWidth(newWidth); + else + mSubViewWindow.setMinimumWidth(0); +} diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index 32d7159c2..1d44cb7f5 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -10,6 +10,7 @@ class QAction; class QDockWidget; +class QScrollArea; namespace CSMDoc { @@ -47,6 +48,8 @@ namespace CSVDoc SubViewFactoryManager mSubViewFactory; QMainWindow mSubViewWindow; GlobalDebugProfileMenu *mGlobalDebugProfileMenu; + QScrollArea *mScroll; + bool mScrollbarOnly; // not implemented @@ -87,6 +90,8 @@ namespace CSVDoc /// User preference function void resizeViewHeight (int height); + void updateScrollbar(); + public: View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews); diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 0d0e82dbf..ccab576fa 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -20,6 +20,8 @@ #include #include #include +#include +#include #include "../../model/world/nestedtableproxymodel.hpp" #include "../../model/world/columnbase.hpp" @@ -581,7 +583,15 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSM changeCurrentId(id.getId()); - QWidget *mainWidget = new QWidget(this); + //QWidget *mainWidget = new QWidget(this); + CSVDoc::SizeHintWidget *mainWidget = new CSVDoc::SizeHintWidget; + + const QRect rect = QApplication::desktop()->screenGeometry(this); + int frameHeight = 40; // set a reasonable default + QWidget *topLevel = QApplication::topLevelAt(pos()); + if (topLevel) + frameHeight = topLevel->frameGeometry().height() - topLevel->height(); + mainWidget->setSizeHint(QSize(400, rect.height()-frameHeight)); // FIXME: 400 QHBoxLayout *buttonsLayout = new QHBoxLayout; QToolButton* prevButton = new QToolButton(mainWidget); diff --git a/apps/opencs/view/world/tablesubview.cpp b/apps/opencs/view/world/tablesubview.cpp index 729b6b8d7..dde04fb3f 100644 --- a/apps/opencs/view/world/tablesubview.cpp +++ b/apps/opencs/view/world/tablesubview.cpp @@ -3,6 +3,9 @@ #include #include +#include +#include +#include #include "../../model/doc/document.hpp" #include "../../model/world/tablemimedata.hpp" @@ -30,11 +33,18 @@ CSVWorld::TableSubView::TableSubView (const CSMWorld::UniversalId& id, CSMDoc::D layout->insertWidget (0, mFilterBox); - QWidget *widget = new QWidget; + CSVDoc::SizeHintWidget *widget = new CSVDoc::SizeHintWidget; widget->setLayout (layout); setWidget (widget); + // prefer height of the screen and full width of the table + const QRect rect = QApplication::desktop()->screenGeometry(this); + int frameHeight = 40; // set a reasonable default + QWidget *topLevel = QApplication::topLevelAt(pos()); + if (topLevel) + frameHeight = topLevel->frameGeometry().height() - topLevel->height(); + widget->setSizeHint(QSize(mTable->horizontalHeader()->length(), rect.height()-frameHeight)); connect (mTable, SIGNAL (editRequest (const CSMWorld::UniversalId&, const std::string&)), this, SLOT (editRequest (const CSMWorld::UniversalId&, const std::string&))); From 93c3bb37167a2887f2c5d07c2265a1bf63fb650b Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 17 May 2015 14:27:17 +0200 Subject: [PATCH 1202/3725] fixed subview-closing related crash (Fixes #2564) --- apps/opencs/view/doc/view.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 5636fff94..e10f85c64 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -811,7 +811,10 @@ void CSVDoc::View::closeRequest (SubView *subView) if (mSubViews.size()>1 || mViewTotal<=1 || userSettings.setting ("window/hide-subview", QString ("false"))!="true") + { subView->deleteLater(); + mSubViews.removeOne (subView); + } else if (mViewManager.closeRequest (this)) mViewManager.removeDocAndView (mDocument); } From 7b207a795468c7f9603655722f33a54a2476de52 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 17 May 2015 14:31:53 +0200 Subject: [PATCH 1203/3725] added shortcut for closing subviews (Fixes #2558) --- apps/opencs/view/doc/subview.cpp | 18 ++++++++++++++++++ apps/opencs/view/doc/subview.hpp | 2 ++ 2 files changed, 20 insertions(+) diff --git a/apps/opencs/view/doc/subview.cpp b/apps/opencs/view/doc/subview.cpp index df1e7ee49..f4f0c6afe 100644 --- a/apps/opencs/view/doc/subview.cpp +++ b/apps/opencs/view/doc/subview.cpp @@ -2,6 +2,24 @@ #include "view.hpp" +#include +#include +#include + +bool CSVDoc::SubView::event (QEvent *event) +{ + if (event->type()==QEvent::ShortcutOverride) + { + QKeyEvent *keyEvent = static_cast (event); + + if (keyEvent->key()==Qt::Key_W && keyEvent->modifiers()==(Qt::ShiftModifier | Qt::ControlModifier)) + emit closeRequest(); + return true; + } + + return QDockWidget::event (event); +} + CSVDoc::SubView::SubView (const CSMWorld::UniversalId& id) : mUniversalId (id) { diff --git a/apps/opencs/view/doc/subview.hpp b/apps/opencs/view/doc/subview.hpp index a8aa3cda1..b323f9ed9 100644 --- a/apps/opencs/view/doc/subview.hpp +++ b/apps/opencs/view/doc/subview.hpp @@ -34,6 +34,8 @@ namespace CSVDoc void setUniversalId(const CSMWorld::UniversalId& id); + bool event (QEvent *event); + public: SubView (const CSMWorld::UniversalId& id); From 8bcfac1ea3779ad3ac18b2dfedecb291f5c98418 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 17 May 2015 16:25:13 +0200 Subject: [PATCH 1204/3725] Fix adjustPosition not always working correctly (Fixes #2563) moveObject was returning an incorrect Ptr for cell movements. --- apps/openmw/mwbase/world.hpp | 4 +- .../mwscript/transformationextensions.cpp | 7 ++-- apps/openmw/mwworld/worldimp.cpp | 37 +++++++++---------- apps/openmw/mwworld/worldimp.hpp | 4 +- 4 files changed, 25 insertions(+), 27 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 9e6c6d9bf..c110e94d6 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -286,8 +286,8 @@ namespace MWBase virtual MWWorld::Ptr moveObject (const MWWorld::Ptr& ptr, float x, float y, float z) = 0; ///< @return an updated Ptr in case the Ptr's cell changes - virtual void - moveObject(const MWWorld::Ptr &ptr, MWWorld::CellStore* newCell, float x, float y, float z) = 0; + virtual MWWorld::Ptr moveObject(const MWWorld::Ptr &ptr, MWWorld::CellStore* newCell, float x, float y, float z) = 0; + ///< @return an updated Ptr virtual void scaleObject (const MWWorld::Ptr& ptr, float scale) = 0; diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index f87983ce8..414ef7fb7 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -370,18 +370,17 @@ namespace MWScript // another morrowind oddity: player will be moved to the exterior cell at this location, // non-player actors will move within the cell they are in. - MWWorld::Ptr updated; if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) { MWWorld::CellStore* cell = MWBase::Environment::get().getWorld()->getExterior(cx,cy); MWBase::Environment::get().getWorld()->moveObject(ptr,cell,x,y,z); - updated = MWWorld::Ptr(ptr.getBase(), cell); + ptr = MWWorld::Ptr(ptr.getBase(), cell); } else { - updated = MWBase::Environment::get().getWorld()->moveObject(ptr, x, y, z); + ptr = MWBase::Environment::get().getWorld()->moveObject(ptr, x, y, z); } - dynamic_cast(runtime.getContext()).updatePtr(updated); + dynamic_cast(runtime.getContext()).updatePtr(ptr); float ax = Ogre::Radian(ptr.getRefData().getPosition().rot[0]).valueDegrees(); float ay = Ogre::Radian(ptr.getRefData().getPosition().rot[1]).valueDegrees(); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 0f8110624..bb0402c4e 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1108,7 +1108,7 @@ namespace MWWorld } } - void World::moveObject(const Ptr &ptr, CellStore* newCell, float x, float y, float z) + MWWorld::Ptr World::moveObject(const Ptr &ptr, CellStore* newCell, float x, float y, float z) { ESM::Position pos = ptr.getRefData().getPosition(); @@ -1123,6 +1123,7 @@ namespace MWWorld CellStore *currCell = ptr.isInCell() ? ptr.getCell() : NULL; // currCell == NULL should only happen for player, during initial startup bool isPlayer = ptr == mPlayer->getPlayer(); bool haveToMove = isPlayer || (currCell && mWorldScene->isCellActive(*currCell)); + MWWorld::Ptr newPtr = ptr; if (currCell != newCell) { @@ -1140,6 +1141,7 @@ namespace MWWorld mWorldScene->changeToExteriorCell(pos, false); } addContainerScripts (getPlayerPtr(), newCell); + newPtr = getPlayerPtr(); } else { @@ -1147,7 +1149,7 @@ namespace MWWorld bool newCellActive = mWorldScene->isCellActive(*newCell); if (!currCellActive && newCellActive) { - MWWorld::Ptr newPtr = ptr.getClass().copyToCell(ptr, *newCell, pos); + newPtr = ptr.getClass().copyToCell(ptr, *newCell, pos); mWorldScene->addObjectToScene(newPtr); std::string script = newPtr.getClass().getScript(newPtr); @@ -1163,23 +1165,21 @@ namespace MWWorld removeContainerScripts (ptr); haveToMove = false; - MWWorld::Ptr newPtr = ptr.getClass() - .copyToCell(ptr, *newCell); + newPtr = ptr.getClass().copyToCell(ptr, *newCell); newPtr.getRefData().setBaseNode(0); } else if (!currCellActive && !newCellActive) - ptr.getClass().copyToCell(ptr, *newCell); + newPtr = ptr.getClass().copyToCell(ptr, *newCell); else // both cells active { - MWWorld::Ptr copy = - ptr.getClass().copyToCell(ptr, *newCell, pos); + newPtr = ptr.getClass().copyToCell(ptr, *newCell, pos); - mRendering->updateObjectCell(ptr, copy); + mRendering->updateObjectCell(ptr, newPtr); ptr.getRefData().setBaseNode(NULL); - MWBase::Environment::get().getSoundManager()->updatePtr (ptr, copy); + MWBase::Environment::get().getSoundManager()->updatePtr (ptr, newPtr); MWBase::MechanicsManager *mechMgr = MWBase::Environment::get().getMechanicsManager(); - mechMgr->updateCell(ptr, copy); + mechMgr->updateCell(ptr, newPtr); std::string script = ptr.getClass().getScript(ptr); @@ -1187,22 +1187,23 @@ namespace MWWorld { mLocalScripts.remove(ptr); removeContainerScripts (ptr); - mLocalScripts.add(script, copy); - addContainerScripts (copy, newCell); + mLocalScripts.add(script, newPtr); + addContainerScripts (newPtr, newCell); } } ptr.getRefData().setCount(0); } } - if (haveToMove && ptr.getRefData().getBaseNode()) + if (haveToMove && newPtr.getRefData().getBaseNode()) { - mRendering->moveObject(ptr, vec); - mPhysics->moveObject (ptr); + mRendering->moveObject(newPtr, vec); + mPhysics->moveObject (newPtr); } if (isPlayer) { mWorldScene->playerMoved (vec); } + return newPtr; } MWWorld::Ptr World::moveObjectImp(const Ptr& ptr, float x, float y, float z) @@ -1216,11 +1217,7 @@ namespace MWWorld cell = getExterior(cellX, cellY); } - moveObject(ptr, cell, x, y, z); - - MWWorld::Ptr updated = ptr; - updated.mCell = cell; - return updated; + return moveObject(ptr, cell, x, y, z); } MWWorld::Ptr World::moveObject (const Ptr& ptr, float x, float y, float z) diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 63d6506de..bf25c20bb 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -348,7 +348,9 @@ namespace MWWorld virtual MWWorld::Ptr moveObject (const Ptr& ptr, float x, float y, float z); ///< @return an updated Ptr in case the Ptr's cell changes - virtual void moveObject (const Ptr& ptr, CellStore* newCell, float x, float y, float z); + + virtual MWWorld::Ptr moveObject (const Ptr& ptr, CellStore* newCell, float x, float y, float z); + ///< @return an updated Ptr virtual void scaleObject (const Ptr& ptr, float scale); From 99eb78fc19d86508e641f08ae74845fec4dee9a0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 17 May 2015 22:16:14 +0200 Subject: [PATCH 1205/3725] Fix $DISPLAY not being accounted for in cursor decompression context --- components/sdlutil/sdlcursormanager.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/components/sdlutil/sdlcursormanager.cpp b/components/sdlutil/sdlcursormanager.cpp index 9a7c2aa76..70f389136 100644 --- a/components/sdlutil/sdlcursormanager.cpp +++ b/components/sdlutil/sdlcursormanager.cpp @@ -33,6 +33,12 @@ namespace traits->sharedContext = 0; traits->pbuffer = true; + osg::GraphicsContext::ScreenIdentifier si; + si.readDISPLAY(); + traits->displayNum = si.displayNum; + traits->screenNum = si.screenNum; + traits->hostName = si.hostName; + _gc = osg::GraphicsContext::createGraphicsContext(traits.get()); if (!_gc) From cfcfb173205bb1148b7b40f20b3eb75eb6791295 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 18 May 2015 07:12:02 +1000 Subject: [PATCH 1206/3725] Updates to optional horizontal scrollbar. - move SizeHintWidget out to separate files - remove redundant logic in view.cpp - remove sizehint from dialogue subview - add tooltip hints in user preferences --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/settings/usersettings.cpp | 4 ++++ apps/opencs/view/doc/sizehint.cpp | 17 ++++++++++++++++ apps/opencs/view/doc/sizehint.hpp | 22 +++++++++++++++++++++ apps/opencs/view/doc/subview.cpp | 16 --------------- apps/opencs/view/doc/subview.hpp | 13 ------------ apps/opencs/view/doc/view.cpp | 7 +------ apps/opencs/view/world/dialoguesubview.cpp | 12 +---------- apps/opencs/view/world/tablesubview.cpp | 1 + 9 files changed, 47 insertions(+), 47 deletions(-) create mode 100644 apps/opencs/view/doc/sizehint.cpp create mode 100644 apps/opencs/view/doc/sizehint.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 9fb80324e..438f3c694 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -46,7 +46,7 @@ opencs_units_noqt (model/tools opencs_units (view/doc viewmanager view operations operation subview startup filedialog newgame - filewidget adjusterwidget loader globaldebugprofilemenu runlogsubview + filewidget adjusterwidget loader globaldebugprofilemenu runlogsubview sizehint ) diff --git a/apps/opencs/model/settings/usersettings.cpp b/apps/opencs/model/settings/usersettings.cpp index bd31b6e38..ea002c5ed 100644 --- a/apps/opencs/model/settings/usersettings.cpp +++ b/apps/opencs/model/settings/usersettings.cpp @@ -151,6 +151,10 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() "Add a horizontal scrollbar to the main view window."); mainwinScroll->setDefaultValue (defaultScroll); mainwinScroll->setDeclaredValues (scrollValues); + mainwinScroll->setToolTip ("Scrollbar Only: Simple addition of scrollbars, the view window does not grow" + " automatically.\n" + "Grow Only: Original Editor behaviour. The view window grows as subviews are added. No scrollbars.\n" + "Grow then Scroll: The view window grows. The scrollbar appears once it cannot grow any further."); Setting *grow = createSetting (Type_CheckBox, "grow-limit", "Grow Limit Screen"); grow->setDefaultValue ("false"); diff --git a/apps/opencs/view/doc/sizehint.cpp b/apps/opencs/view/doc/sizehint.cpp new file mode 100644 index 000000000..038bd9e4d --- /dev/null +++ b/apps/opencs/view/doc/sizehint.cpp @@ -0,0 +1,17 @@ +#include "sizehint.hpp" + +CSVDoc::SizeHintWidget::SizeHintWidget(QWidget *parent) : QWidget(parent) +{} + +CSVDoc::SizeHintWidget::~SizeHintWidget() +{} + +QSize CSVDoc::SizeHintWidget::sizeHint() const +{ + return mSize; +} + +void CSVDoc::SizeHintWidget::setSizeHint(const QSize &size) +{ + mSize = size; +} diff --git a/apps/opencs/view/doc/sizehint.hpp b/apps/opencs/view/doc/sizehint.hpp new file mode 100644 index 000000000..cf5a02580 --- /dev/null +++ b/apps/opencs/view/doc/sizehint.hpp @@ -0,0 +1,22 @@ +#ifndef CSV_DOC_SIZEHINT_H +#define CSV_DOC_SIZEHINT_H + +#include +#include + +namespace CSVDoc +{ + class SizeHintWidget : public QWidget + { + QSize mSize; + + public: + SizeHintWidget(QWidget *parent = 0); + ~SizeHintWidget(); + + virtual QSize sizeHint() const; + void setSizeHint(const QSize &size); + }; +} + +#endif // CSV_DOC_SIZEHINT_H diff --git a/apps/opencs/view/doc/subview.cpp b/apps/opencs/view/doc/subview.cpp index 09128d919..df1e7ee49 100644 --- a/apps/opencs/view/doc/subview.cpp +++ b/apps/opencs/view/doc/subview.cpp @@ -43,19 +43,3 @@ void CSVDoc::SubView::closeRequest() { emit closeRequest (this); } - -CSVDoc::SizeHintWidget::SizeHintWidget(QWidget *parent) : QWidget(parent) -{} - -CSVDoc::SizeHintWidget::~SizeHintWidget() -{} - -QSize CSVDoc::SizeHintWidget::sizeHint() const -{ - return mSize; -} - -void CSVDoc::SizeHintWidget::setSizeHint(const QSize &size) -{ - mSize = size; -} diff --git a/apps/opencs/view/doc/subview.hpp b/apps/opencs/view/doc/subview.hpp index f327107c2..a8aa3cda1 100644 --- a/apps/opencs/view/doc/subview.hpp +++ b/apps/opencs/view/doc/subview.hpp @@ -8,7 +8,6 @@ #include "subviewfactory.hpp" #include -#include class QUndoStack; @@ -71,18 +70,6 @@ namespace CSVDoc void closeRequest(); }; - - class SizeHintWidget : public QWidget - { - QSize mSize; - - public: - SizeHintWidget(QWidget *parent = 0); - ~SizeHintWidget(); - - virtual QSize sizeHint() const; - void setSizeHint(const QSize &size); - }; } #endif diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 16b96ed4d..47810a115 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -563,12 +563,7 @@ void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id, const std::strin // CSMSettings::UserSettings &settings = CSMSettings::UserSettings::instance(); QString mainwinScroll = settings.settingValue ("window/mainwindow-scrollbar"); - if (mainwinScroll.isEmpty() || mainwinScroll == "Scrollbar Only") - mScrollbarOnly = true; - else if(mainwinScroll == "Grow Only") - mScrollbarOnly = false; - else - mScrollbarOnly = false; + mScrollbarOnly = mainwinScroll.isEmpty() || mainwinScroll == "Scrollbar Only"; QDesktopWidget *dw = QApplication::desktop(); QRect rect; diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index ccab576fa..0d0e82dbf 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -20,8 +20,6 @@ #include #include #include -#include -#include #include "../../model/world/nestedtableproxymodel.hpp" #include "../../model/world/columnbase.hpp" @@ -583,15 +581,7 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSM changeCurrentId(id.getId()); - //QWidget *mainWidget = new QWidget(this); - CSVDoc::SizeHintWidget *mainWidget = new CSVDoc::SizeHintWidget; - - const QRect rect = QApplication::desktop()->screenGeometry(this); - int frameHeight = 40; // set a reasonable default - QWidget *topLevel = QApplication::topLevelAt(pos()); - if (topLevel) - frameHeight = topLevel->frameGeometry().height() - topLevel->height(); - mainWidget->setSizeHint(QSize(400, rect.height()-frameHeight)); // FIXME: 400 + QWidget *mainWidget = new QWidget(this); QHBoxLayout *buttonsLayout = new QHBoxLayout; QToolButton* prevButton = new QToolButton(mainWidget); diff --git a/apps/opencs/view/world/tablesubview.cpp b/apps/opencs/view/world/tablesubview.cpp index dde04fb3f..af0b64447 100644 --- a/apps/opencs/view/world/tablesubview.cpp +++ b/apps/opencs/view/world/tablesubview.cpp @@ -10,6 +10,7 @@ #include "../../model/doc/document.hpp" #include "../../model/world/tablemimedata.hpp" +#include "../doc/sizehint.hpp" #include "../filter/filterbox.hpp" #include "table.hpp" #include "tablebottombox.hpp" From 7494340b66500c08aa6f6f7fe41c957d293cdcab Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 18 May 2015 22:08:36 +1000 Subject: [PATCH 1207/3725] Add the remaining NPC data for editing with dialogue subview. Should resolve Bug #2547. --- apps/opencs/model/world/columns.cpp | 15 + apps/opencs/model/world/columns.hpp | 15 + apps/opencs/model/world/refidadapterimp.cpp | 350 +++++++++++++++++++- apps/opencs/model/world/refidadapterimp.hpp | 95 ++++++ apps/opencs/model/world/refidcollection.cpp | 56 ++++ apps/opencs/view/world/dialoguesubview.cpp | 6 +- 6 files changed, 535 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 89ee6258b..2bfe79464 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -281,6 +281,21 @@ namespace CSMWorld { ColumnId_InfoCondValue, "Value" }, { ColumnId_OriginalCell, "Original Cell" }, + { ColumnId_NpcAttributes, "Attributes" }, + { ColumnId_NpcSkills, "Skills" }, + { ColumnId_UChar, "Value [0..255]" }, + { ColumnId_NpcMisc, "Misc" }, + { ColumnId_NpcLevel, "Level" }, + { ColumnId_NpcFactionID, "Faction ID" }, + { ColumnId_NpcHealth, "Health" }, + { ColumnId_NpcMana, "Mana" }, + { ColumnId_NpcFatigue, "Fatigue" }, + { ColumnId_NpcDisposition, "Disposition" }, + { ColumnId_NpcReputation, "Reputation" }, + { ColumnId_NpcRank, "Rank" }, + { ColumnId_NpcGold, "Gold" }, + { ColumnId_NpcPersistence, "Persistent" }, + { ColumnId_UseValue1, "Use value 1" }, { ColumnId_UseValue2, "Use value 2" }, { ColumnId_UseValue3, "Use value 3" }, diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index f971f3fd8..b2234ad49 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -272,6 +272,21 @@ namespace CSMWorld ColumnId_OriginalCell = 247, + ColumnId_NpcAttributes = 248, + ColumnId_NpcSkills = 249, + ColumnId_UChar = 250, + ColumnId_NpcMisc = 251, + ColumnId_NpcLevel = 252, + ColumnId_NpcFactionID = 253, + ColumnId_NpcHealth = 254, + ColumnId_NpcMana = 255, + ColumnId_NpcFatigue = 256, + ColumnId_NpcDisposition = 257, + ColumnId_NpcReputation = 258, + ColumnId_NpcRank = 259, + ColumnId_NpcGold = 260, + ColumnId_NpcPersistence = 261, + // Allocated to a separate value range, so we don't get a collision should we ever need // to extend the number of use values. ColumnId_UseValue1 = 0x10000, diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index 98c1b6f0f..a5f0b2244 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -468,7 +468,10 @@ CSMWorld::NpcColumns::NpcColumns (const ActorColumns& actorColumns) mClass(NULL), mFaction(NULL), mHair(NULL), - mHead(NULL) + mHead(NULL), + mAttributes(NULL), + mSkills(NULL), + mMisc(NULL) {} CSMWorld::NpcRefIdAdapter::NpcRefIdAdapter (const NpcColumns& columns) @@ -496,6 +499,17 @@ QVariant CSMWorld::NpcRefIdAdapter::getData (const RefIdColumn *column, const Re if (column==mColumns.mHead) return QString::fromUtf8 (record.get().mHead.c_str()); + if (column==mColumns.mAttributes || column==mColumns.mSkills) + { + if ((record.get().mFlags & ESM::NPC::Autocalc) != 0) + return QVariant(); + else + return true; + } + + if (column==mColumns.mMisc) + return true; + std::map::const_iterator iter = mColumns.mFlags.find (column); @@ -538,6 +552,340 @@ void CSMWorld::NpcRefIdAdapter::setData (const RefIdColumn *column, RefIdData& d } } +CSMWorld::NpcAttributesRefIdAdapter::NpcAttributesRefIdAdapter () +{} + +void CSMWorld::NpcAttributesRefIdAdapter::addNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int position) const +{ + // Do nothing, this table cannot be changed by the user +} + +void CSMWorld::NpcAttributesRefIdAdapter::removeNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int rowToRemove) const +{ + // Do nothing, this table cannot be changed by the user +} + +void CSMWorld::NpcAttributesRefIdAdapter::setNestedTable (const RefIdColumn* column, + RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const +{ + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Npc))); + ESM::NPC npc = record.get(); + + // store the whole struct + npc.mNpdt52 = + static_cast > &>(nestedTable).mNestedTable.at(0); + + record.setModified (npc); +} + +CSMWorld::NestedTableWrapperBase* CSMWorld::NpcAttributesRefIdAdapter::nestedTable (const RefIdColumn* column, + const RefIdData& data, int index) const +{ + const Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Npc))); + + // return the whole struct + std::vector wrap; + wrap.push_back(record.get().mNpdt52); + // deleted by dtor of NestedTableStoring + return new NestedTableWrapper >(wrap); +} + +QVariant CSMWorld::NpcAttributesRefIdAdapter::getNestedData (const RefIdColumn *column, + const RefIdData& data, int index, int subRowIndex, int subColIndex) const +{ + const Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Npc))); + + const ESM::NPC::NPDTstruct52& npcStruct = record.get().mNpdt52; + + if (subColIndex == 0) + switch (subRowIndex) + { + case 0: return QString("Strength"); + case 1: return QString("Intelligence"); + case 2: return QString("Willpower"); + case 3: return QString("Agility"); + case 4: return QString("Speed"); + case 5: return QString("Endurance"); + case 6: return QString("Personality"); + case 7: return QString("Luck"); + default: return QVariant(); // throw an exception here? + } + else if (subColIndex == 1) + switch (subRowIndex) + { + case 0: return static_cast(npcStruct.mStrength); + case 1: return static_cast(npcStruct.mIntelligence); + case 2: return static_cast(npcStruct.mWillpower); + case 3: return static_cast(npcStruct.mAgility); + case 4: return static_cast(npcStruct.mSpeed); + case 5: return static_cast(npcStruct.mEndurance); + case 6: return static_cast(npcStruct.mPersonality); + case 7: return static_cast(npcStruct.mLuck); + default: return QVariant(); // throw an exception here? + } + else + return QVariant(); // throw an exception here? +} + +void CSMWorld::NpcAttributesRefIdAdapter::setNestedData (const RefIdColumn *column, + RefIdData& data, int row, const QVariant& value, int subRowIndex, int subColIndex) const +{ + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (row, UniversalId::Type_Npc))); + ESM::NPC npc = record.get(); + ESM::NPC::NPDTstruct52& npcStruct = npc.mNpdt52; + + if (subColIndex == 1) + switch(subRowIndex) + { + case 0: npcStruct.mStrength = static_cast(value.toInt()); break; + case 1: npcStruct.mIntelligence = static_cast(value.toInt()); break; + case 2: npcStruct.mWillpower = static_cast(value.toInt()); break; + case 3: npcStruct.mAgility = static_cast(value.toInt()); break; + case 4: npcStruct.mSpeed = static_cast(value.toInt()); break; + case 5: npcStruct.mEndurance = static_cast(value.toInt()); break; + case 6: npcStruct.mPersonality = static_cast(value.toInt()); break; + case 7: npcStruct.mLuck = static_cast(value.toInt()); break; + default: return; // throw an exception here? + } + else + return; // throw an exception here? + + record.setModified (npc); +} + +int CSMWorld::NpcAttributesRefIdAdapter::getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const +{ + return 2; +} + +int CSMWorld::NpcAttributesRefIdAdapter::getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const +{ + // There are 8 attributes + return 8; +} + +CSMWorld::NpcSkillsRefIdAdapter::NpcSkillsRefIdAdapter () +{} + +void CSMWorld::NpcSkillsRefIdAdapter::addNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int position) const +{ + // Do nothing, this table cannot be changed by the user +} + +void CSMWorld::NpcSkillsRefIdAdapter::removeNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int rowToRemove) const +{ + // Do nothing, this table cannot be changed by the user +} + +void CSMWorld::NpcSkillsRefIdAdapter::setNestedTable (const RefIdColumn* column, + RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const +{ + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Npc))); + ESM::NPC npc = record.get(); + + // store the whole struct + npc.mNpdt52 = + static_cast > &>(nestedTable).mNestedTable.at(0); + + record.setModified (npc); +} + +CSMWorld::NestedTableWrapperBase* CSMWorld::NpcSkillsRefIdAdapter::nestedTable (const RefIdColumn* column, + const RefIdData& data, int index) const +{ + const Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Npc))); + + // return the whole struct + std::vector wrap; + wrap.push_back(record.get().mNpdt52); + // deleted by dtor of NestedTableStoring + return new NestedTableWrapper >(wrap); +} + +QVariant CSMWorld::NpcSkillsRefIdAdapter::getNestedData (const RefIdColumn *column, + const RefIdData& data, int index, int subRowIndex, int subColIndex) const +{ + const Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Npc))); + + const ESM::NPC::NPDTstruct52& npcStruct = record.get().mNpdt52; + + if (subRowIndex < 0 || subRowIndex >= ESM::Skill::Length) + std::cout << "getNestedDatat index" << std::endl; + //throw std::runtime_error ("index out of range"); + + if (subColIndex == 0) + return QString(ESM::Skill::sSkillNames[subRowIndex].c_str()); + else if (subColIndex == 1) + return static_cast(npcStruct.mSkills[subRowIndex]); + else + return QVariant(); // throw an exception here? +} + +void CSMWorld::NpcSkillsRefIdAdapter::setNestedData (const RefIdColumn *column, + RefIdData& data, int row, const QVariant& value, int subRowIndex, int subColIndex) const +{ + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (row, UniversalId::Type_Npc))); + ESM::NPC npc = record.get(); + ESM::NPC::NPDTstruct52& npcStruct = npc.mNpdt52; + + if (subRowIndex < 0 || subRowIndex >= ESM::Skill::Length) + std::cout << "setNestedDatat index" << std::endl; + //throw std::runtime_error ("index out of range"); + + if (subColIndex == 1) + npcStruct.mSkills[subRowIndex] = static_cast(value.toInt()); + else + return; // throw an exception here? + + record.setModified (npc); +} + +int CSMWorld::NpcSkillsRefIdAdapter::getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const +{ + return 2; +} + +int CSMWorld::NpcSkillsRefIdAdapter::getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const +{ + // There are 27 skills + return ESM::Skill::Length; +} + +CSMWorld::NpcMiscRefIdAdapter::NpcMiscRefIdAdapter () +{} + +CSMWorld::NpcMiscRefIdAdapter::~NpcMiscRefIdAdapter() +{} + +void CSMWorld::NpcMiscRefIdAdapter::addNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int position) const +{ + throw std::logic_error ("cannot add a row to a fixed table"); +} + +void CSMWorld::NpcMiscRefIdAdapter::removeNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int rowToRemove) const +{ + throw std::logic_error ("cannot remove a row to a fixed table"); +} + +void CSMWorld::NpcMiscRefIdAdapter::setNestedTable (const RefIdColumn* column, + RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const +{ + throw std::logic_error ("table operation not supported"); +} + +CSMWorld::NestedTableWrapperBase* CSMWorld::NpcMiscRefIdAdapter::nestedTable (const RefIdColumn* column, + const RefIdData& data, int index) const +{ + throw std::logic_error ("table operation not supported"); +} + +QVariant CSMWorld::NpcMiscRefIdAdapter::getNestedData (const RefIdColumn *column, + const RefIdData& data, int index, int subRowIndex, int subColIndex) const +{ + const Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Npc))); + + bool autoCalc = (record.get().mFlags & ESM::NPC::Autocalc) != 0; + + if (autoCalc) + switch (subColIndex) + { + case 0: return static_cast(record.get().mNpdt12.mLevel); + case 1: return QVariant(); + case 2: return QVariant(); + case 3: return QVariant(); + case 4: return QVariant(); + case 5: return static_cast(record.get().mNpdt12.mDisposition); + case 6: return static_cast(record.get().mNpdt12.mReputation); + case 7: return static_cast(record.get().mNpdt12.mRank); + case 8: return record.get().mNpdt12.mGold; + case 9: return record.get().mPersistent == true; + default: return QVariant(); // throw an exception here? + } + else + switch (subColIndex) + { + case 0: return static_cast(record.get().mNpdt52.mLevel); + case 1: return static_cast(record.get().mNpdt52.mFactionID); + case 2: return static_cast(record.get().mNpdt52.mHealth); + case 3: return static_cast(record.get().mNpdt52.mMana); + case 4: return static_cast(record.get().mNpdt52.mFatigue); + case 5: return static_cast(record.get().mNpdt52.mDisposition); + case 6: return static_cast(record.get().mNpdt52.mReputation); + case 7: return static_cast(record.get().mNpdt52.mRank); + case 8: return record.get().mNpdt52.mGold; + case 9: return record.get().mPersistent == true; + default: return QVariant(); // throw an exception here? + } +} + +void CSMWorld::NpcMiscRefIdAdapter::setNestedData (const RefIdColumn *column, + RefIdData& data, int row, const QVariant& value, int subRowIndex, int subColIndex) const +{ + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (row, UniversalId::Type_Npc))); + ESM::NPC npc = record.get(); + + bool autoCalc = (record.get().mFlags & ESM::NPC::Autocalc) != 0; + + if (autoCalc) + switch(subColIndex) + { + case 0: npc.mNpdt12.mLevel = static_cast(value.toInt()); break; + case 1: return; + case 2: return; + case 3: return; + case 4: return; + case 5: npc.mNpdt12.mDisposition = static_cast(value.toInt()); break; + case 6: npc.mNpdt12.mReputation = static_cast(value.toInt()); break; + case 7: npc.mNpdt12.mRank = static_cast(value.toInt()); break; + case 8: npc.mNpdt12.mGold = value.toInt(); break; + case 9: npc.mPersistent = value.toBool(); break; + default: return; // throw an exception here? + } + else + switch(subColIndex) + { + case 0: npc.mNpdt52.mLevel = static_cast(value.toInt()); break; + case 1: npc.mNpdt52.mFactionID = static_cast(value.toInt()); break; + case 2: npc.mNpdt52.mHealth = static_cast(value.toInt()); break; + case 3: npc.mNpdt52.mMana = static_cast(value.toInt()); break; + case 4: npc.mNpdt52.mFatigue = static_cast(value.toInt()); break; + case 5: npc.mNpdt52.mDisposition = static_cast(value.toInt()); break; + case 6: npc.mNpdt52.mReputation = static_cast(value.toInt()); break; + case 7: npc.mNpdt52.mRank = static_cast(value.toInt()); break; + case 8: npc.mNpdt52.mGold = value.toInt(); break; + case 9: npc.mPersistent = value.toBool(); break; + default: return; // throw an exception here? + } + + record.setModified (npc); +} + +int CSMWorld::NpcMiscRefIdAdapter::getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const +{ + return 10; // Level, FactionID, Health, Mana, Fatigue, Disposition, Reputation, Rank, Gold, Persist +} + +int CSMWorld::NpcMiscRefIdAdapter::getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const +{ + return 1; // fixed at size 1 +} + CSMWorld::WeaponColumns::WeaponColumns (const EnchantableColumns& columns) : EnchantableColumns (columns) {} diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index 61e8115c0..143b46c44 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -792,6 +792,9 @@ namespace CSMWorld const RefIdColumn *mFaction; const RefIdColumn *mHair; const RefIdColumn *mHead; + const RefIdColumn *mAttributes; // depends on npc type + const RefIdColumn *mSkills; // depends on npc type + const RefIdColumn *mMisc; // may depend on npc type, e.g. FactionID NpcColumns (const ActorColumns& actorColumns); }; @@ -842,8 +845,100 @@ namespace CSMWorld ///< If the data type does not match an exception is thrown. }; + class NestedRefIdAdapterBase; + class NpcAttributesRefIdAdapter : public NestedRefIdAdapterBase + { + public: + + NpcAttributesRefIdAdapter (); + + virtual void addNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int position) const; + + virtual void removeNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int rowToRemove) const; + + virtual void setNestedTable (const RefIdColumn* column, + RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const; + + virtual NestedTableWrapperBase* nestedTable (const RefIdColumn* column, + const RefIdData& data, int index) const; + + virtual QVariant getNestedData (const RefIdColumn *column, + const RefIdData& data, int index, int subRowIndex, int subColIndex) const; + + virtual void setNestedData (const RefIdColumn *column, + RefIdData& data, int row, const QVariant& value, int subRowIndex, int subColIndex) const; + + virtual int getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const; + + virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const; + }; + + class NpcSkillsRefIdAdapter : public NestedRefIdAdapterBase + { + public: + + NpcSkillsRefIdAdapter (); + + virtual void addNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int position) const; + + virtual void removeNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int rowToRemove) const; + + virtual void setNestedTable (const RefIdColumn* column, + RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const; + + virtual NestedTableWrapperBase* nestedTable (const RefIdColumn* column, + const RefIdData& data, int index) const; + + virtual QVariant getNestedData (const RefIdColumn *column, + const RefIdData& data, int index, int subRowIndex, int subColIndex) const; + + virtual void setNestedData (const RefIdColumn *column, + RefIdData& data, int row, const QVariant& value, int subRowIndex, int subColIndex) const; + + virtual int getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const; + + virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const; + }; + + class NpcMiscRefIdAdapter : public NestedRefIdAdapterBase + { + NpcMiscRefIdAdapter (const NpcMiscRefIdAdapter&); + NpcMiscRefIdAdapter& operator= (const NpcMiscRefIdAdapter&); + + public: + + NpcMiscRefIdAdapter (); + virtual ~NpcMiscRefIdAdapter(); + + virtual void addNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int position) const; + + virtual void removeNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int rowToRemove) const; + + virtual void setNestedTable (const RefIdColumn* column, + RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const; + + virtual NestedTableWrapperBase* nestedTable (const RefIdColumn* column, + const RefIdData& data, int index) const; + + virtual QVariant getNestedData (const RefIdColumn *column, + const RefIdData& data, int index, int subRowIndex, int subColIndex) const; + + virtual void setNestedData (const RefIdColumn *column, + RefIdData& data, int row, const QVariant& value, int subRowIndex, int subColIndex) const; + + virtual int getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const; + + virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const; + }; + template class EffectsListAdapter; diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 1941c505a..9d9e9826a 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -427,6 +427,62 @@ CSMWorld::RefIdCollection::RefIdCollection() npcColumns.mFlags.insert (std::make_pair (metalBlood, ESM::NPC::Metal)); + // Need a way to add a table of stats and values (rather than adding a long list of + // entries in the dialogue subview) E.g. attributes+stats(health, mana, fatigue), skills + // These needs to be driven from the autocalculated setting. + + // Nested table + mColumns.push_back(RefIdColumn (Columns::ColumnId_NpcAttributes, + ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue)); + npcColumns.mAttributes = &mColumns.back(); + std::map attrMap; + attrMap.insert(std::make_pair(UniversalId::Type_Npc, new NpcAttributesRefIdAdapter())); + mNestedAdapters.push_back (std::make_pair(&mColumns.back(), attrMap)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_NpcAttributes, CSMWorld::ColumnBase::Display_String, false, false)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_UChar, CSMWorld::ColumnBase::Display_Integer)); + + // Nested table + mColumns.push_back(RefIdColumn (Columns::ColumnId_NpcSkills, + ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue)); + npcColumns.mSkills = &mColumns.back(); + std::map skillsMap; + skillsMap.insert(std::make_pair(UniversalId::Type_Npc, new NpcSkillsRefIdAdapter())); + mNestedAdapters.push_back (std::make_pair(&mColumns.back(), skillsMap)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_NpcSkills, CSMWorld::ColumnBase::Display_String, false, false)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_UChar, CSMWorld::ColumnBase::Display_Integer)); + + // Nested list + mColumns.push_back(RefIdColumn (Columns::ColumnId_NpcMisc, + ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue | ColumnBase::Flag_Dialogue_List)); + npcColumns.mMisc = &mColumns.back(); + std::map miscMap; + miscMap.insert(std::make_pair(UniversalId::Type_Npc, new NpcMiscRefIdAdapter())); + mNestedAdapters.push_back (std::make_pair(&mColumns.back(), miscMap)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_NpcLevel, CSMWorld::ColumnBase::Display_Integer)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_NpcFactionID, CSMWorld::ColumnBase::Display_Integer)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_NpcHealth, CSMWorld::ColumnBase::Display_Integer)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_NpcMana, CSMWorld::ColumnBase::Display_Integer)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_NpcFatigue, CSMWorld::ColumnBase::Display_Integer)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_NpcDisposition, CSMWorld::ColumnBase::Display_Integer)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_NpcReputation, CSMWorld::ColumnBase::Display_Integer)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_NpcRank, CSMWorld::ColumnBase::Display_Integer)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_NpcGold, CSMWorld::ColumnBase::Display_Integer)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_NpcPersistence, CSMWorld::ColumnBase::Display_Boolean)); + WeaponColumns weaponColumns (enchantableColumns); mColumns.push_back (RefIdColumn (Columns::ColumnId_WeaponType, ColumnBase::Display_WeaponType)); diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 0d0e82dbf..4b4afc666 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include "../../model/world/nestedtableproxymodel.hpp" #include "../../model/world/columnbase.hpp" @@ -511,7 +512,7 @@ void CSVWorld::EditWidget::remake(int row) mNestedTableMapper->setModel(mNestedModels.back()); // FIXME: lack MIME support? mNestedTableDispatcher = - new DialogueDelegateDispatcher (this, mTable, mCommandDispatcher, mDocument, mNestedModels.back()); + new DialogueDelegateDispatcher (0/*this*/, mTable, mCommandDispatcher, mDocument, mNestedModels.back()); mNestedTableMapper->setItemDelegate(mNestedTableDispatcher); int columnCount = @@ -763,6 +764,9 @@ void CSVWorld::DialogueSubView::dataChanged (const QModelIndex & index) CSMWorld::RecordBase::State state = static_cast(mTable->data (mTable->index (currentIndex.row(), 1)).toInt()); mEditWidget->setDisabled (state==CSMWorld::RecordBase::State_Deleted || mLocked); + int y = mEditWidget->verticalScrollBar()->value(); + mEditWidget->remake (index.row()); + mEditWidget->verticalScrollBar()->setValue(y); } } From 314c1161ae1bc018316adb0512867b77c6331e81 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 18 May 2015 21:05:17 +0200 Subject: [PATCH 1208/3725] Minor addition to reading display --- components/sdlutil/sdlcursormanager.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/components/sdlutil/sdlcursormanager.cpp b/components/sdlutil/sdlcursormanager.cpp index 70f389136..2befc7bd0 100644 --- a/components/sdlutil/sdlcursormanager.cpp +++ b/components/sdlutil/sdlcursormanager.cpp @@ -35,6 +35,7 @@ namespace osg::GraphicsContext::ScreenIdentifier si; si.readDISPLAY(); + if (si.displayNum<0) si.displayNum = 0; traits->displayNum = si.displayNum; traits->screenNum = si.screenNum; traits->hostName = si.hostName; From 8b768f4377b4bb37c3cca3f8e0735607de0d1165 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 18 May 2015 21:06:42 +0200 Subject: [PATCH 1209/3725] Minor fix for behaviour with non-existing LightManager --- components/sceneutil/lightmanager.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/components/sceneutil/lightmanager.cpp b/components/sceneutil/lightmanager.cpp index 1aaf7ab40..ce7a343da 100644 --- a/components/sceneutil/lightmanager.cpp +++ b/components/sceneutil/lightmanager.cpp @@ -244,7 +244,10 @@ namespace SceneUtil } } if (!mLightManager) + { + traverse(node, nv); return; + } } mLightManager->prepareForCamera(cv->getCurrentCamera()); From 0ecfd9119f1c7ec5c2326c7d15a1b1a1813fa354 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Tue, 19 May 2015 06:56:38 +1000 Subject: [PATCH 1210/3725] Add the remaining Race data for editing with dialogue subview. Should resolve Bug #2546. --- apps/opencs/model/world/columnbase.cpp | 1 + apps/opencs/model/world/columnbase.hpp | 1 + apps/opencs/model/world/columns.cpp | 8 + apps/opencs/model/world/columns.hpp | 7 + apps/opencs/model/world/data.cpp | 18 +++ .../model/world/nestedcoladapterimp.cpp | 153 ++++++++++++++++++ .../model/world/nestedcoladapterimp.hpp | 51 ++++++ apps/opencs/view/doc/viewmanager.cpp | 3 +- 8 files changed, 241 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/world/columnbase.cpp b/apps/opencs/model/world/columnbase.cpp index cf125aa63..087a1df7b 100644 --- a/apps/opencs/model/world/columnbase.cpp +++ b/apps/opencs/model/world/columnbase.cpp @@ -84,6 +84,7 @@ bool CSMWorld::ColumnBase::isId (Display display) Display_InfoCondFunc, Display_InfoCondVar, Display_InfoCondComp, + Display_RaceSkill, Display_None }; diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index 2d2513774..d6dd4b291 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -119,6 +119,7 @@ namespace CSMWorld Display_InfoCondFunc, Display_InfoCondVar, Display_InfoCondComp, + Display_RaceSkill, //top level columns that nest other columns Display_NestedHeader diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 2bfe79464..daf537c0c 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -296,6 +296,13 @@ namespace CSMWorld { ColumnId_NpcGold, "Gold" }, { ColumnId_NpcPersistence, "Persistent" }, + { ColumnId_RaceAttributes, "Attributes" }, + { ColumnId_RaceMaleValue, "Male" }, + { ColumnId_RaceFemaleValue, "Female" }, + { ColumnId_RaceSkillBonus, "Skill Bonus" }, + { ColumnId_RaceSkill, "Skills" }, + { ColumnId_RaceBonus, "Bonus" }, + { ColumnId_UseValue1, "Use value 1" }, { ColumnId_UseValue2, "Use value 2" }, { ColumnId_UseValue3, "Use value 3" }, @@ -566,6 +573,7 @@ namespace // FIXME: don't have dynamic value enum delegate, use Display_String for now //case CSMWorld::Columns::ColumnId_InfoCond: return sInfoCond; case CSMWorld::Columns::ColumnId_InfoCondComp: return sInfoCondComp; + case CSMWorld::Columns::ColumnId_RaceSkill: return sSkills; default: return 0; } diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index b2234ad49..85276a695 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -287,6 +287,13 @@ namespace CSMWorld ColumnId_NpcGold = 260, ColumnId_NpcPersistence = 261, + ColumnId_RaceAttributes = 262, + ColumnId_RaceMaleValue = 263, + ColumnId_RaceFemaleValue = 264, + ColumnId_RaceSkillBonus = 265, + ColumnId_RaceSkill = 266, + ColumnId_RaceBonus = 267, + // Allocated to a separate value range, so we don't get a collision should we ever need // to extend the number of use values. ColumnId_UseValue1 = 0x10000, diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index e2fab0a25..fa7e48a0e 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -136,6 +136,24 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mRaces.addAdapter (std::make_pair(&mRaces.getColumn(index), new SpellListAdapter ())); mRaces.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_SpellId, ColumnBase::Display_String)); + // Race attributes + mRaces.addColumn (new NestedParentColumn (Columns::ColumnId_RaceAttributes)); + index = mRaces.getColumns()-1; + mRaces.addAdapter (std::make_pair(&mRaces.getColumn(index), new RaceAttributeAdapter())); + mRaces.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_RaceAttributes, ColumnBase::Display_String, false)); + mRaces.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_RaceMaleValue, ColumnBase::Display_Integer)); + mRaces.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_RaceFemaleValue, ColumnBase::Display_Integer)); + // Race skill bonus + mRaces.addColumn (new NestedParentColumn (Columns::ColumnId_RaceSkillBonus)); + index = mRaces.getColumns()-1; + mRaces.addAdapter (std::make_pair(&mRaces.getColumn(index), new RaceSkillsBonusAdapter())); + mRaces.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_RaceSkill, ColumnBase::Display_RaceSkill)); + mRaces.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_RaceBonus, ColumnBase::Display_Integer)); mSounds.addColumn (new StringIdColumn); mSounds.addColumn (new RecordStateColumn); diff --git a/apps/opencs/model/world/nestedcoladapterimp.cpp b/apps/opencs/model/world/nestedcoladapterimp.cpp index a0d764576..7efe14dee 100644 --- a/apps/opencs/model/world/nestedcoladapterimp.cpp +++ b/apps/opencs/model/world/nestedcoladapterimp.cpp @@ -880,4 +880,157 @@ namespace CSMWorld { return static_cast(record.get().mSelects.size()); } + + RaceAttributeAdapter::RaceAttributeAdapter () {} + + void RaceAttributeAdapter::addRow(Record& record, int position) const + { + // Do nothing, this table cannot be changed by the user + } + + void RaceAttributeAdapter::removeRow(Record& record, int rowToRemove) const + { + // Do nothing, this table cannot be changed by the user + } + + void RaceAttributeAdapter::setTable(Record& record, + const NestedTableWrapperBase& nestedTable) const + { + ESM::Race race = record.get(); + + race.mData = + static_cast >&>(nestedTable).mNestedTable.at(0); + + record.setModified (race); + } + + NestedTableWrapperBase* RaceAttributeAdapter::table(const Record& record) const + { + std::vector wrap; + wrap.push_back(record.get().mData); + // deleted by dtor of NestedTableStoring + return new NestedTableWrapper >(wrap); + } + + QVariant RaceAttributeAdapter::getData(const Record& record, + int subRowIndex, int subColIndex) const + { + ESM::Race race = record.get(); + + if (subRowIndex < 0 || subRowIndex >= ESM::Attribute::Length) + throw std::runtime_error ("index out of range"); + + switch (subColIndex) + { + case 0: return QString(ESM::Attribute::sAttributeNames[subRowIndex].c_str()); + case 1: return race.mData.mAttributeValues[subRowIndex].mMale; + case 2: return race.mData.mAttributeValues[subRowIndex].mFemale; + default: throw std::runtime_error("Race Attribute subcolumn index out of range"); + } + } + + void RaceAttributeAdapter::setData(Record& record, + const QVariant& value, int subRowIndex, int subColIndex) const + { + ESM::Race race = record.get(); + + if (subRowIndex < 0 || subRowIndex >= ESM::Attribute::Length) + throw std::runtime_error ("index out of range"); + + switch (subColIndex) + { + case 0: return; // throw an exception here? + case 1: race.mData.mAttributeValues[subRowIndex].mMale = value.toInt(); break; + case 2: race.mData.mAttributeValues[subRowIndex].mFemale = value.toInt(); break; + default: throw std::runtime_error("Race Attribute subcolumn index out of range"); + } + + record.setModified (race); + } + + int RaceAttributeAdapter::getColumnsCount(const Record& record) const + { + return 3; // attrib, male, female + } + + int RaceAttributeAdapter::getRowsCount(const Record& record) const + { + return ESM::Attribute::Length; // there are 8 attributes + } + + RaceSkillsBonusAdapter::RaceSkillsBonusAdapter () {} + + void RaceSkillsBonusAdapter::addRow(Record& record, int position) const + { + // Do nothing, this table cannot be changed by the user + } + + void RaceSkillsBonusAdapter::removeRow(Record& record, int rowToRemove) const + { + // Do nothing, this table cannot be changed by the user + } + + void RaceSkillsBonusAdapter::setTable(Record& record, + const NestedTableWrapperBase& nestedTable) const + { + ESM::Race race = record.get(); + + race.mData = + static_cast >&>(nestedTable).mNestedTable.at(0); + + record.setModified (race); + } + + NestedTableWrapperBase* RaceSkillsBonusAdapter::table(const Record& record) const + { + std::vector wrap; + wrap.push_back(record.get().mData); + // deleted by dtor of NestedTableStoring + return new NestedTableWrapper >(wrap); + } + + QVariant RaceSkillsBonusAdapter::getData(const Record& record, + int subRowIndex, int subColIndex) const + { + ESM::Race race = record.get(); + + if (subRowIndex < 0 || subRowIndex >= static_cast(sizeof(race.mData.mBonus)/sizeof(race.mData.mBonus[0]))) + throw std::runtime_error ("index out of range"); + + switch (subColIndex) + { + case 0: return race.mData.mBonus[subRowIndex].mSkill; // can be -1 + case 1: return race.mData.mBonus[subRowIndex].mBonus; + default: throw std::runtime_error("Race skill bonus subcolumn index out of range"); + } + } + + void RaceSkillsBonusAdapter::setData(Record& record, + const QVariant& value, int subRowIndex, int subColIndex) const + { + ESM::Race race = record.get(); + + if (subRowIndex < 0 || subRowIndex >= static_cast(sizeof(race.mData.mBonus)/sizeof(race.mData.mBonus[0]))) + throw std::runtime_error ("index out of range"); + + switch (subColIndex) + { + case 0: race.mData.mBonus[subRowIndex].mSkill = value.toInt(); break; // can be -1 + case 1: race.mData.mBonus[subRowIndex].mBonus = value.toInt(); break; + default: throw std::runtime_error("Race skill bonus subcolumn index out of range"); + } + + record.setModified (race); + } + + int RaceSkillsBonusAdapter::getColumnsCount(const Record& record) const + { + return 2; // skill, bonus + } + + int RaceSkillsBonusAdapter::getRowsCount(const Record& record) const + { + // there are 7 skill bonuses + return static_cast(sizeof(record.get().mData.mBonus)/sizeof(record.get().mData.mBonus[0])); + } } diff --git a/apps/opencs/model/world/nestedcoladapterimp.hpp b/apps/opencs/model/world/nestedcoladapterimp.hpp index 776a908ba..4b1e2cd09 100644 --- a/apps/opencs/model/world/nestedcoladapterimp.hpp +++ b/apps/opencs/model/world/nestedcoladapterimp.hpp @@ -8,6 +8,7 @@ #include // for converting magic effect id to string & back #include // for converting skill names #include // for converting attributes +#include #include "nestedcolumnadapter.hpp" #include "nestedtablewrapper.hpp" @@ -437,6 +438,56 @@ namespace CSMWorld virtual int getRowsCount(const Record& record) const; }; + + class RaceAttributeAdapter : public NestedColumnAdapter + { + public: + RaceAttributeAdapter (); + + virtual void addRow(Record& record, int position) const; + + virtual void removeRow(Record& record, int rowToRemove) const; + + virtual void setTable(Record& record, + const NestedTableWrapperBase& nestedTable) const; + + virtual NestedTableWrapperBase* table(const Record& record) const; + + virtual QVariant getData(const Record& record, + int subRowIndex, int subColIndex) const; + + virtual void setData(Record& record, + const QVariant& value, int subRowIndex, int subColIndex) const; + + virtual int getColumnsCount(const Record& record) const; + + virtual int getRowsCount(const Record& record) const; + }; + + class RaceSkillsBonusAdapter : public NestedColumnAdapter + { + public: + RaceSkillsBonusAdapter (); + + virtual void addRow(Record& record, int position) const; + + virtual void removeRow(Record& record, int rowToRemove) const; + + virtual void setTable(Record& record, + const NestedTableWrapperBase& nestedTable) const; + + virtual NestedTableWrapperBase* table(const Record& record) const; + + virtual QVariant getData(const Record& record, + int subRowIndex, int subColIndex) const; + + virtual void setData(Record& record, + const QVariant& value, int subRowIndex, int subColIndex) const; + + virtual int getColumnsCount(const Record& record) const; + + virtual int getRowsCount(const Record& record) const; + }; } #endif // CSM_WOLRD_NESTEDCOLADAPTERIMP_H diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 6362f9659..97b7aac19 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -92,7 +92,8 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) { CSMWorld::ColumnBase::Display_AiPackageType, CSMWorld::Columns::ColumnId_AiPackageType, false }, { CSMWorld::ColumnBase::Display_YesNo, CSMWorld::Columns::ColumnId_AiWanderRepeat, false }, { CSMWorld::ColumnBase::Display_InfoCondFunc, CSMWorld::Columns::ColumnId_InfoCondFunc, false }, - { CSMWorld::ColumnBase::Display_InfoCondComp, CSMWorld::Columns::ColumnId_InfoCondComp, false } + { CSMWorld::ColumnBase::Display_InfoCondComp, CSMWorld::Columns::ColumnId_InfoCondComp, false }, + { CSMWorld::ColumnBase::Display_RaceSkill, CSMWorld::Columns::ColumnId_RaceSkill, true }, }; for (std::size_t i=0; i Date: Tue, 19 May 2015 19:19:52 +1000 Subject: [PATCH 1211/3725] Fix occasional crash with DialogueSubView, e.g. when deleting a row of a subtable. --- apps/opencs/view/world/dialoguesubview.cpp | 53 ++++++++++++---------- apps/opencs/view/world/dialoguesubview.hpp | 2 +- 2 files changed, 29 insertions(+), 26 deletions(-) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 4b4afc666..fee302e2c 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -348,16 +348,19 @@ CSVWorld::DialogueDelegateDispatcher::~DialogueDelegateDispatcher() CSVWorld::EditWidget::~EditWidget() { for (unsigned i = 0; i < mNestedModels.size(); ++i) - { delete mNestedModels[i]; - } - delete mNestedTableDispatcher; + + if (mDispatcher) + delete mDispatcher; + + if (mNestedTableDispatcher) + delete mNestedTableDispatcher; } CSVWorld::EditWidget::EditWidget(QWidget *parent, int row, CSMWorld::IdTable* table, CSMWorld::CommandDispatcher& commandDispatcher, CSMDoc::Document& document, bool createAndDelete) : -mDispatcher(this, table, commandDispatcher, document), +mDispatcher(0), mNestedTableDispatcher(NULL), QScrollArea(parent), mWidgetMapper(NULL), @@ -369,41 +372,41 @@ mTable(table) { remake (row); - connect(&mDispatcher, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*)), + connect(mDispatcher, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*)), this, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*))); } void CSVWorld::EditWidget::remake(int row) { for (unsigned i = 0; i < mNestedModels.size(); ++i) - { delete mNestedModels[i]; - } + mNestedModels.clear(); - delete mNestedTableDispatcher; - if (mMainWidget) - { - delete mMainWidget; - mMainWidget = 0; - } - mMainWidget = new QWidget (this); + if (mDispatcher) + delete mDispatcher; + mDispatcher = new DialogueDelegateDispatcher(0/*this*/, mTable, mCommandDispatcher, mDocument); + + if (mNestedTableDispatcher) + delete mNestedTableDispatcher; //not sure if widget mapper can handle deleting the widgets that were mapped if (mWidgetMapper) - { delete mWidgetMapper; - mWidgetMapper = 0; - } + + mWidgetMapper = new QDataWidgetMapper (this); + mWidgetMapper->setModel(mTable); + mWidgetMapper->setItemDelegate(mDispatcher); + if (mNestedTableMapper) - { delete mNestedTableMapper; - mNestedTableMapper = 0; - } - mWidgetMapper = new QDataWidgetMapper (this); - mWidgetMapper->setModel(mTable); - mWidgetMapper->setItemDelegate(&mDispatcher); + if (mMainWidget) + { + QWidget *del = this->takeWidget(); + del->deleteLater(); + } + mMainWidget = new QWidget (this); QFrame* line = new QFrame(mMainWidget); line->setObjectName(QString::fromUtf8("line")); @@ -476,8 +479,8 @@ void CSVWorld::EditWidget::remake(int row) } else if (!(flags & CSMWorld::ColumnBase::Flag_Dialogue_List)) { - mDispatcher.makeDelegate (display); - QWidget* editor = mDispatcher.makeEditor (display, (mTable->index (row, i))); + mDispatcher->makeDelegate (display); + QWidget* editor = mDispatcher->makeEditor (display, (mTable->index (row, i))); if (editor) { diff --git a/apps/opencs/view/world/dialoguesubview.hpp b/apps/opencs/view/world/dialoguesubview.hpp index b5a44d266..8783d935f 100644 --- a/apps/opencs/view/world/dialoguesubview.hpp +++ b/apps/opencs/view/world/dialoguesubview.hpp @@ -165,7 +165,7 @@ namespace CSVWorld Q_OBJECT QDataWidgetMapper *mWidgetMapper; QDataWidgetMapper *mNestedTableMapper; - DialogueDelegateDispatcher mDispatcher; + DialogueDelegateDispatcher *mDispatcher; DialogueDelegateDispatcher *mNestedTableDispatcher; QWidget* mMainWidget; CSMWorld::IdTable* mTable; From b27a879352b155205a9809f567007e97bf7dd1a6 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Tue, 19 May 2015 22:01:40 +1000 Subject: [PATCH 1212/3725] Add the remaining Cell data for editing with dialogue subview. Should resolve Bug #2551. - NOTE: the interior water flag and water level logic needs reviewing - does not automatically disable region names for interiors without mQuasiEx flag - Colour values can't be entered as RGB - Region names are not drop down menus --- apps/opencs/model/world/columns.cpp | 11 +- apps/opencs/model/world/columns.hpp | 11 +- apps/opencs/model/world/data.cpp | 25 ++- apps/opencs/model/world/data.hpp | 2 +- .../model/world/nestedcoladapterimp.cpp | 161 +++++++++++++++++- .../model/world/nestedcoladapterimp.hpp | 26 +++ 6 files changed, 230 insertions(+), 6 deletions(-) diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index daf537c0c..ee7a00ca0 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -62,7 +62,7 @@ namespace CSMWorld { ColumnId_StarterSpell, "Starter Spell" }, { ColumnId_AlwaysSucceeds, "Always Succeeds" }, { ColumnId_SleepForbidden, "Sleep Forbidden" }, - { ColumnId_InteriorWater, "Interior Water" }, + { ColumnId_Water, "Has Water" }, { ColumnId_InteriorSky, "Interior Sky" }, { ColumnId_Model, "Model" }, { ColumnId_Script, "Script" }, @@ -303,6 +303,15 @@ namespace CSMWorld { ColumnId_RaceSkill, "Skills" }, { ColumnId_RaceBonus, "Bonus" }, + { ColumnId_Interior, "Interior" }, + { ColumnId_Ambient, "Ambient" }, + { ColumnId_Sunlight, "Sunlight" }, + { ColumnId_Fog, "Fog" }, + { ColumnId_FogDensity, "Fog Density" }, + { ColumnId_WaterLevel, "Water Level" }, + { ColumnId_InteriorWater, "Interior Water" }, + { ColumnId_MapColor, "Map Color" }, + { ColumnId_UseValue1, "Use value 1" }, { ColumnId_UseValue2, "Use value 2" }, { ColumnId_UseValue3, "Use value 3" }, diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 85276a695..3a345b3ec 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -57,7 +57,7 @@ namespace CSMWorld ColumnId_StarterSpell = 42, ColumnId_AlwaysSucceeds = 43, ColumnId_SleepForbidden = 44, - ColumnId_InteriorWater = 45, + ColumnId_Water = 45, ColumnId_InteriorSky = 46, ColumnId_Model = 47, ColumnId_Script = 48, @@ -294,6 +294,15 @@ namespace CSMWorld ColumnId_RaceSkill = 266, ColumnId_RaceBonus = 267, + ColumnId_Interior = 268, + ColumnId_Ambient = 269, + ColumnId_Sunlight = 270, + ColumnId_Fog = 271, + ColumnId_FogDensity = 272, + ColumnId_WaterLevel = 273, + ColumnId_InteriorWater = 274, + ColumnId_MapColor = 275, + // Allocated to a separate value range, so we don't get a collision should we ever need // to extend the number of use values. ColumnId_UseValue1 = 0x10000, diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index fa7e48a0e..00349d476 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -287,10 +287,31 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mCells.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Cell)); mCells.addColumn (new NameColumn); mCells.addColumn (new FlagColumn (Columns::ColumnId_SleepForbidden, ESM::Cell::NoSleep)); - mCells.addColumn (new FlagColumn (Columns::ColumnId_InteriorWater, ESM::Cell::HasWater)); + mCells.addColumn (new FlagColumn (Columns::ColumnId_Water, ESM::Cell::HasWater)); mCells.addColumn (new FlagColumn (Columns::ColumnId_InteriorSky, ESM::Cell::QuasiEx)); mCells.addColumn (new RegionColumn); mCells.addColumn (new RefNumCounterColumn); + // Misc Cell data + mCells.addColumn (new NestedParentColumn (Columns::ColumnId_Cell, + ColumnBase::Flag_Dialogue | ColumnBase::Flag_Dialogue_List)); + index = mCells.getColumns()-1; + mCells.addAdapter (std::make_pair(&mCells.getColumn(index), new CellListAdapter ())); + mCells.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_Interior, ColumnBase::Display_Boolean)); + mCells.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_Ambient, ColumnBase::Display_Integer)); + mCells.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_Sunlight, ColumnBase::Display_Integer)); + mCells.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_Fog, ColumnBase::Display_Integer)); + mCells.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_FogDensity, ColumnBase::Display_Float)); + mCells.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_InteriorWater, ColumnBase::Display_Boolean)); + mCells.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_WaterLevel, ColumnBase::Display_Float)); + mCells.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_MapColor, ColumnBase::Display_Integer)); mEnchantments.addColumn (new StringIdColumn); mEnchantments.addColumn (new RecordStateColumn); @@ -465,7 +486,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc addModel (new IdTree (&mTopicInfos, &mTopicInfos, IdTable::Feature_ReorderWithinTopic), UniversalId::Type_TopicInfo); addModel (new IdTable (&mJournalInfos, IdTable::Feature_ReorderWithinTopic), UniversalId::Type_JournalInfo); - addModel (new IdTable (&mCells, IdTable::Feature_ViewId), UniversalId::Type_Cell); + addModel (new IdTree (&mCells, &mCells, IdTable::Feature_ViewId), UniversalId::Type_Cell); addModel (new IdTree (&mEnchantments, &mEnchantments), UniversalId::Type_Enchantment); addModel (new IdTable (&mBodyParts), UniversalId::Type_BodyPart); addModel (new IdTable (&mSoundGens), UniversalId::Type_SoundGen); diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 8689b98c0..060e47bd9 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -88,7 +88,7 @@ namespace CSMWorld IdCollection mStartScripts; NestedInfoCollection mTopicInfos; InfoCollection mJournalInfos; - IdCollection mCells; + NestedIdCollection mCells; IdCollection mLandTextures; IdCollection mLand; RefIdCollection mReferenceables; diff --git a/apps/opencs/model/world/nestedcoladapterimp.cpp b/apps/opencs/model/world/nestedcoladapterimp.cpp index 7efe14dee..a63ebe672 100644 --- a/apps/opencs/model/world/nestedcoladapterimp.cpp +++ b/apps/opencs/model/world/nestedcoladapterimp.cpp @@ -481,7 +481,7 @@ namespace CSMWorld void InfoListAdapter::removeRow(Record& record, int rowToRemove) const { - throw std::logic_error ("cannot add a row to a fixed table"); + throw std::logic_error ("cannot remove a row to a fixed table"); } void InfoListAdapter::setTable(Record& record, @@ -1033,4 +1033,163 @@ namespace CSMWorld // there are 7 skill bonuses return static_cast(sizeof(record.get().mData.mBonus)/sizeof(record.get().mData.mBonus[0])); } + + CellListAdapter::CellListAdapter () {} + + void CellListAdapter::addRow(Record& record, int position) const + { + throw std::logic_error ("cannot add a row to a fixed table"); + } + + void CellListAdapter::removeRow(Record& record, int rowToRemove) const + { + throw std::logic_error ("cannot remove a row to a fixed table"); + } + + void CellListAdapter::setTable(Record& record, + const NestedTableWrapperBase& nestedTable) const + { + throw std::logic_error ("table operation not supported"); + } + + NestedTableWrapperBase* CellListAdapter::table(const Record& record) const + { + throw std::logic_error ("table operation not supported"); + } + + QVariant CellListAdapter::getData(const Record& record, + int subRowIndex, int subColIndex) const + { + CSMWorld::Cell cell = record.get(); + + bool isInterior = (cell.mData.mFlags & ESM::Cell::Interior) != 0; + bool behaveLikeExterior = (cell.mData.mFlags & ESM::Cell::QuasiEx) != 0; + + switch (subColIndex) + { + case 0: return isInterior; + case 1: return (isInterior && !behaveLikeExterior) ? cell.mAmbi.mAmbient : QVariant(); + case 2: return (isInterior && !behaveLikeExterior) ? cell.mAmbi.mSunlight : QVariant(); + case 3: return (isInterior && !behaveLikeExterior) ? cell.mAmbi.mFog : QVariant(); + case 4: return (isInterior && !behaveLikeExterior) ? cell.mAmbi.mFogDensity : QVariant(); + case 5: return (isInterior && !behaveLikeExterior) ? cell.mWaterInt==true : QVariant(); + case 6: + { + if (isInterior && !behaveLikeExterior && cell.mWaterInt) + return cell.mWater; + else + return QVariant(); + } + case 7: return isInterior ? QVariant() : cell.mMapColor; // TODO: how to select? + //case 8: return isInterior ? behaveLikeExterior : QVariant(); + default: throw std::runtime_error("Cell subcolumn index out of range"); + } + } + + void CellListAdapter::setData(Record& record, + const QVariant& value, int subRowIndex, int subColIndex) const + { + CSMWorld::Cell cell = record.get(); + + bool isInterior = (cell.mData.mFlags & ESM::Cell::Interior) != 0; + bool behaveLikeExterior = (cell.mData.mFlags & ESM::Cell::QuasiEx) != 0; + + switch (subColIndex) + { + case 0: + { + if (value.toBool()) + cell.mData.mFlags |= ESM::Cell::Interior; + else + cell.mData.mFlags &= ~ESM::Cell::Interior; + break; + } + case 1: + { + if (isInterior && !behaveLikeExterior) + cell.mAmbi.mAmbient = static_cast(value.toInt()); + else + return; // return without saving + break; + } + case 2: + { + if (isInterior && !behaveLikeExterior) + cell.mAmbi.mSunlight = static_cast(value.toInt()); + else + return; // return without saving + break; + } + case 3: + { + if (isInterior && !behaveLikeExterior) + cell.mAmbi.mFog = static_cast(value.toInt()); + else + return; // return without saving + break; + } + case 4: + { + if (isInterior && !behaveLikeExterior) + cell.mAmbi.mFogDensity = value.toFloat(); + else + return; // return without saving + break; + } + case 5: + { + if (isInterior && !behaveLikeExterior) + cell.mWaterInt = value.toBool(); + else + return; // return without saving + break; + } + case 6: + { + if (isInterior && !behaveLikeExterior && cell.mWaterInt) + cell.mWater = value.toFloat(); + else + return; // return without saving + break; + } + case 7: + { + if (!isInterior) + cell.mMapColor = value.toInt(); + else + return; // return without saving + break; + } +#if 0 + // redundant since this flag is shown in the main table as "Interior Sky" + // keep here for documenting the logic based on vanilla + case 8: + { + if (isInterior) + { + if (value.toBool()) + cell.mData.mFlags |= ESM::Cell::QuasiEx; + else + cell.mData.mFlags &= ~ESM::Cell::QuasiEx; + } + else + return; // return without saving + break; + } +#endif + default: throw std::runtime_error("Cell subcolumn index out of range"); + } + + record.setModified (cell); + } + + int CellListAdapter::getColumnsCount(const Record& record) const + { + return 8; + } + + int CellListAdapter::getRowsCount(const Record& record) const + { + return 1; // fixed at size 1 + } } diff --git a/apps/opencs/model/world/nestedcoladapterimp.hpp b/apps/opencs/model/world/nestedcoladapterimp.hpp index 4b1e2cd09..81c52588b 100644 --- a/apps/opencs/model/world/nestedcoladapterimp.hpp +++ b/apps/opencs/model/world/nestedcoladapterimp.hpp @@ -12,6 +12,7 @@ #include "nestedcolumnadapter.hpp" #include "nestedtablewrapper.hpp" +#include "cell.hpp" namespace ESM { @@ -488,6 +489,31 @@ namespace CSMWorld virtual int getRowsCount(const Record& record) const; }; + + class CellListAdapter : public NestedColumnAdapter + { + public: + CellListAdapter (); + + virtual void addRow(Record& record, int position) const; + + virtual void removeRow(Record& record, int rowToRemove) const; + + virtual void setTable(Record& record, + const NestedTableWrapperBase& nestedTable) const; + + virtual NestedTableWrapperBase* table(const Record& record) const; + + virtual QVariant getData(const Record& record, + int subRowIndex, int subColIndex) const; + + virtual void setData(Record& record, + const QVariant& value, int subRowIndex, int subColIndex) const; + + virtual int getColumnsCount(const Record& record) const; + + virtual int getRowsCount(const Record& record) const; + }; } #endif // CSM_WOLRD_NESTEDCOLADAPTERIMP_H From 196be7283d07cb371d699fdb1f9d4b19c6841774 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Tue, 19 May 2015 21:39:17 +0300 Subject: [PATCH 1213/3725] Reset an activated reference after activation's exectution (Fix #1738) --- apps/openmw/mwscript/interpretercontext.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index a8c04aa4b..df675aebb 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -505,7 +505,10 @@ namespace MWScript boost::shared_ptr action = (ptr.getClass().activate(ptr, actor)); action->execute (actor); if (mActivated == ptr) + { mActivationHandled = true; + mActivated = MWWorld::Ptr(); + } } float InterpreterContext::getSecondsPassed() const From 820f4a2688b0910aaa53859d05159e25f69e0212 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 20 May 2015 02:07:18 +0200 Subject: [PATCH 1214/3725] Fix light direction --- apps/opencs/view/render/lightingbright.cpp | 2 +- apps/opencs/view/render/lightingday.cpp | 2 +- apps/opencs/view/render/lightingnight.cpp | 2 +- apps/openmw/mwrender/renderingmanager.cpp | 5 +++-- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/apps/opencs/view/render/lightingbright.cpp b/apps/opencs/view/render/lightingbright.cpp index 035e57c56..00c4fb815 100644 --- a/apps/opencs/view/render/lightingbright.cpp +++ b/apps/opencs/view/render/lightingbright.cpp @@ -13,7 +13,7 @@ void CSVRender::LightingBright::activate (osg::Group* rootNode) osg::ref_ptr light (new osg::Light); light->setAmbient(osg::Vec4f(0.f, 0.f, 0.f, 1.f)); - light->setDirection(osg::Vec3f(0.f, 0.f, -1.f)); + light->setPosition(osg::Vec4f(0.f, 0.f, 1.f, 0.f)); light->setDiffuse(osg::Vec4f(1.f, 1.f, 1.f, 1.f)); light->setSpecular(osg::Vec4f(0.f, 0.f, 0.f, 0.f)); light->setConstantAttenuation(1.f); diff --git a/apps/opencs/view/render/lightingday.cpp b/apps/opencs/view/render/lightingday.cpp index 376f3e432..a841edc63 100644 --- a/apps/opencs/view/render/lightingday.cpp +++ b/apps/opencs/view/render/lightingday.cpp @@ -11,7 +11,7 @@ void CSVRender::LightingDay::activate (osg::Group* rootNode) mLightSource = new osg::LightSource; osg::ref_ptr light (new osg::Light); - light->setDirection(osg::Vec3f(0.f, 0.f, -1.f)); + light->setPosition(osg::Vec4f(0.f, 0.f, 1.f, 0.f)); light->setAmbient(osg::Vec4f(0.f, 0.f, 0.f, 1.f)); light->setDiffuse(osg::Vec4f(1.f, 1.f, 1.f, 1.f)); light->setSpecular(osg::Vec4f(0.f, 0.f, 0.f, 0.f)); diff --git a/apps/opencs/view/render/lightingnight.cpp b/apps/opencs/view/render/lightingnight.cpp index 18a12d63d..6f87d020b 100644 --- a/apps/opencs/view/render/lightingnight.cpp +++ b/apps/opencs/view/render/lightingnight.cpp @@ -11,7 +11,7 @@ void CSVRender::LightingNight::activate (osg::Group* rootNode) mLightSource = new osg::LightSource; osg::ref_ptr light (new osg::Light); - light->setDirection(osg::Vec3f(0.f, 0.f, -1.f)); + light->setPosition(osg::Vec4f(0.f, 0.f, 1.f, 0.f)); light->setAmbient(osg::Vec4f(0.f, 0.f, 0.f, 1.f)); light->setDiffuse(osg::Vec4f(0.2f, 0.2f, 0.2f, 1.f)); light->setSpecular(osg::Vec4f(0.f, 0.f, 0.f, 0.f)); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 7e742e729..c0eb00ea4 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -178,9 +178,10 @@ namespace MWRender void RenderingManager::setSunDirection(const osg::Vec3f &direction) { - mSunLight->setDirection(direction*-1); + osg::Vec3 position = direction * -1; + mSunLight->setPosition(osg::Vec4(position.x(), position.y(), position.z(), 0)); - mSky->setSunDirection(direction*-1); + mSky->setSunDirection(position); } osg::Vec3f RenderingManager::getEyePos() From 72c1f37527cab2e5924f4c1759f4219b7d10385e Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 20 May 2015 02:18:20 +0200 Subject: [PATCH 1215/3725] Port CharacterPreview --- apps/openmw/CMakeLists.txt | 4 +- apps/openmw/mwgui/charactercreation.cpp | 14 +- apps/openmw/mwgui/charactercreation.hpp | 16 +- apps/openmw/mwgui/inventorywindow.cpp | 103 +++--- apps/openmw/mwgui/inventorywindow.hpp | 23 +- apps/openmw/mwgui/race.cpp | 64 ++-- apps/openmw/mwgui/race.hpp | 24 +- apps/openmw/mwgui/windowmanagerimp.cpp | 6 +- apps/openmw/mwrender/animation.cpp | 11 +- apps/openmw/mwrender/animation.hpp | 6 +- apps/openmw/mwrender/characterpreview.cpp | 367 +++++++++++----------- apps/openmw/mwrender/characterpreview.hpp | 93 +++--- 12 files changed, 377 insertions(+), 354 deletions(-) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 7d66b2aba..9fa5e38a2 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -22,10 +22,10 @@ source_group(game FILES ${GAME} ${GAME_HEADER}) add_openmw_dir (mwrender actors objects renderingmanager animation sky npcanimation vismask creatureanimation effectmanager util renderinginterface pathgrid rendermode - bulletdebugdraw globalmap + bulletdebugdraw globalmap characterpreview # camera # localmap occlusionquery water shadows -# characterpreview ripplesimulation refraction +# ripplesimulation refraction # terrainstorage weaponanimation ) diff --git a/apps/openmw/mwgui/charactercreation.cpp b/apps/openmw/mwgui/charactercreation.cpp index fb00d6a98..73b950a6a 100644 --- a/apps/openmw/mwgui/charactercreation.cpp +++ b/apps/openmw/mwgui/charactercreation.cpp @@ -60,8 +60,10 @@ namespace namespace MWGui { - CharacterCreation::CharacterCreation() - : mNameDialog(0) + CharacterCreation::CharacterCreation(osgViewer::Viewer* viewer, Resource::ResourceSystem* resourceSystem) + : mViewer(viewer) + , mResourceSystem(resourceSystem) + , mNameDialog(0) , mRaceDialog(0) , mClassChoiceDialog(0) , mGenerateClassQuestionDialog(0) @@ -146,7 +148,7 @@ namespace MWGui case GM_Race: MWBase::Environment::get().getWindowManager()->removeDialog(mRaceDialog); mRaceDialog = 0; - mRaceDialog = new RaceDialog(); + mRaceDialog = new RaceDialog(mViewer, mResourceSystem); mRaceDialog->setNextButtonShow(mCreationStage >= CSE_RaceChosen); mRaceDialog->setRaceId(mPlayerRaceId); mRaceDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onRaceDialogDone); @@ -261,12 +263,6 @@ namespace MWGui } } - void CharacterCreation::doRenderUpdate() - { - if (mRaceDialog) - mRaceDialog->doRenderUpdate(); - } - void CharacterCreation::onReviewDialogDone(WindowBase* parWindow) { MWBase::Environment::get().getWindowManager()->removeDialog(mReviewDialog); diff --git a/apps/openmw/mwgui/charactercreation.hpp b/apps/openmw/mwgui/charactercreation.hpp index a4515569d..f6e7c6c92 100644 --- a/apps/openmw/mwgui/charactercreation.hpp +++ b/apps/openmw/mwgui/charactercreation.hpp @@ -8,6 +8,16 @@ #include "../mwmechanics/stat.hpp" +namespace osgViewer +{ + class Viewer; +} + +namespace Resource +{ + class ResourceSystem; +} + namespace MWGui { class WindowBase; @@ -29,7 +39,7 @@ namespace MWGui public: typedef std::vector SkillList; - CharacterCreation(); + CharacterCreation(osgViewer::Viewer* viewer, Resource::ResourceSystem* resourceSystem); ~CharacterCreation(); //Show a dialog @@ -39,9 +49,11 @@ namespace MWGui void setValue (const std::string& id, const MWMechanics::DynamicStat& value); void setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::SkillValue& value); void configureSkills (const SkillList& major, const SkillList& minor); - void doRenderUpdate(); private: + osgViewer::Viewer* mViewer; + Resource::ResourceSystem* mResourceSystem; + //Dialogs TextInputDialog* mNameDialog; RaceDialog* mRaceDialog; diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index cbce86650..a225b4e11 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -8,6 +8,10 @@ #include #include +#include + +#include + #include #include "../mwbase/world.hpp" @@ -48,22 +52,23 @@ namespace namespace MWGui { - InventoryWindow::InventoryWindow(DragAndDrop* dragAndDrop) + InventoryWindow::InventoryWindow(DragAndDrop* dragAndDrop, osgViewer::Viewer* viewer, Resource::ResourceSystem* resourceSystem) : WindowPinnableBase("openmw_inventory_window.layout") , mTrading(false) , mLastXSize(0) , mLastYSize(0) - #if 0 - , mPreview(new MWRender::InventoryPreview(MWBase::Environment::get().getWorld ()->getPlayerPtr())) - #endif - , mPreviewDirty(true) - , mPreviewResize(true) + , mViewer(viewer) + , mResourceSystem(resourceSystem) + , mPreview(new MWRender::InventoryPreview(viewer, resourceSystem, MWBase::Environment::get().getWorld()->getPlayerPtr())) , mDragAndDrop(dragAndDrop) , mSortModel(NULL) , mTradeModel(NULL) , mSelectedItem(-1) , mGuiMode(GM_Inventory) { + mPreviewTexture.reset(new osgMyGUI::OSGTexture(mPreview->getTexture())); + mPreview->rebuild(); + mMainWidget->castType()->eventWindowChangeCoord += MyGUI::newDelegate(this, &InventoryWindow::onWindowResize); getWidget(mAvatar, "Avatar"); @@ -79,6 +84,8 @@ namespace MWGui getWidget(mArmorRating, "ArmorRating"); mAvatarImage->eventMouseButtonClick += MyGUI::newDelegate(this, &InventoryWindow::onAvatarClicked); + mAvatarImage->setRenderItemTexture(mPreviewTexture.get()); + mAvatarImage->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 1.f, 1.f, 0.f)); getWidget(mItemView, "ItemView"); mItemView->eventItemClicked += MyGUI::newDelegate(this, &InventoryWindow::onItemSelected); @@ -115,17 +122,13 @@ namespace MWGui mSortModel = new SortFilterItemModel(mTradeModel); mItemView->setModel(mSortModel); - mPreview.reset(NULL); - mAvatarImage->setImageTexture(""); -#if 0 - MyGUI::ITexture* tex = MyGUI::RenderManager::getInstance().getTexture("CharacterPreview"); - if (tex) - MyGUI::RenderManager::getInstance().destroyTexture(tex); - mPreview.reset(new MWRender::InventoryPreview(mPtr)); - mPreview->setup(); -#endif - mPreviewDirty = true; - mPreviewResize = true; + mPreview->updatePtr(mPtr); + mPreview->rebuild(); + mPreview->update(); + + dirtyPreview(); + + updatePreviewSize(); } void InventoryWindow::setGuiMode(GuiMode mode) @@ -158,7 +161,7 @@ namespace MWGui static_cast(Settings::Manager::getFloat(setting + " h", "Windows") * viewSize.height)); if (size.width != mMainWidget->getWidth() || size.height != mMainWidget->getHeight()) - mPreviewResize = true; + updatePreviewSize(); mMainWidget->setPosition(pos); mMainWidget->setSize(size); @@ -319,7 +322,8 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->updateSpellWindow(); mItemView->update(); - mPreviewDirty = true; + + dirtyPreview(); } void InventoryWindow::open() @@ -366,10 +370,31 @@ namespace MWGui { mLastXSize = mMainWidget->getSize().width; mLastYSize = mMainWidget->getSize().height; - mPreviewResize = true; + + updatePreviewSize(); + updateArmorRating(); } } + void InventoryWindow::updateArmorRating() + { + mArmorRating->setCaptionWithReplacing ("#{sArmor}: " + + MyGUI::utility::toString(static_cast(mPtr.getClass().getArmorRating(mPtr)))); + if (mArmorRating->getTextSize().width > mArmorRating->getSize().width) + mArmorRating->setCaptionWithReplacing (MyGUI::utility::toString(static_cast(mPtr.getClass().getArmorRating(mPtr)))); + } + + void InventoryWindow::updatePreviewSize() + { + MyGUI::IntSize size = mAvatarImage->getSize(); + int width = std::min(mPreview->getTextureWidth(), size.width); + int height = std::min(mPreview->getTextureHeight(), size.height); + mPreview->setViewport(width, height); + + mAvatarImage->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, height/float(mPreview->getTextureHeight()), + width/float(mPreview->getTextureWidth()), 0.f)); + } + void InventoryWindow::onFilterChanged(MyGUI::Widget* _sender) { if (_sender == mFilterAll) @@ -483,8 +508,6 @@ namespace MWGui MWWorld::Ptr InventoryWindow::getAvatarSelectedItem(int x, int y) { - return MWWorld::Ptr(); -#if 0 int slot = mPreview->getSlotSelected (x, y); if (slot == -1) @@ -503,7 +526,6 @@ namespace MWGui } return MWWorld::Ptr(); -#endif } void InventoryWindow::updateEncumbranceBar() @@ -529,36 +551,11 @@ namespace MWGui mTrading = trading; } - void InventoryWindow::doRenderUpdate () + void InventoryWindow::dirtyPreview() { -#if 0 - mPreview->onFrame(); - - if (mPreviewResize || mPreviewDirty) - { - mArmorRating->setCaptionWithReplacing ("#{sArmor}: " - + MyGUI::utility::toString(static_cast(mPtr.getClass().getArmorRating(mPtr)))); - if (mArmorRating->getTextSize().width > mArmorRating->getSize().width) - mArmorRating->setCaptionWithReplacing (MyGUI::utility::toString(static_cast(mPtr.getClass().getArmorRating(mPtr)))); - } - if (mPreviewResize) - { - mPreviewResize = false; - MyGUI::IntSize size = mAvatarImage->getSize(); - mPreview->resize(size.width, size.height); - - mAvatarImage->setImageTexture("CharacterPreview"); - mAvatarImage->setImageCoord(MyGUI::IntCoord(0, 0, std::min(512, size.width), std::min(1024, size.height))); - mAvatarImage->setImageTile(MyGUI::IntSize(std::min(512, size.width), std::min(1024, size.height))); - } - if (mPreviewDirty) - { - mPreviewDirty = false; - mPreview->update (); + mPreview->update(); - mAvatarImage->setImageTexture("CharacterPreview"); - } -#endif + updateArmorRating(); } void InventoryWindow::notifyContentChanged() @@ -569,7 +566,7 @@ namespace MWGui MWBase::Environment::get().getMechanicsManager()->updateMagicEffects( MWBase::Environment::get().getWorld()->getPlayerPtr()); - mPreviewDirty = true; + dirtyPreview(); } void InventoryWindow::pickUpObject (MWWorld::Ptr object) @@ -675,8 +672,6 @@ namespace MWGui void InventoryWindow::rebuildAvatar() { -#if 0 mPreview->rebuild(); -#endif } } diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index ee71d9b04..fc579ae62 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -6,6 +6,16 @@ #include "../mwworld/ptr.hpp" +namespace osgViewer +{ + class Viewer; +} + +namespace Resource +{ + class ResourceSystem; +} + namespace MWRender { class InventoryPreview; @@ -27,12 +37,10 @@ namespace MWGui class InventoryWindow : public WindowPinnableBase { public: - InventoryWindow(DragAndDrop* dragAndDrop); + InventoryWindow(DragAndDrop* dragAndDrop, osgViewer::Viewer* viewer, Resource::ResourceSystem* resourceSystem); virtual void open(); - void doRenderUpdate(); - /// start trading, disables item drag&drop void setTrading(bool trading); @@ -62,8 +70,6 @@ namespace MWGui private: DragAndDrop* mDragAndDrop; - bool mPreviewDirty; - bool mPreviewResize; int mSelectedItem; MWWorld::Ptr mPtr; @@ -93,6 +99,10 @@ namespace MWGui int mLastXSize; int mLastYSize; + Resource::ResourceSystem* mResourceSystem; + osgViewer::Viewer* mViewer; + + std::auto_ptr mPreviewTexture; std::auto_ptr mPreview; bool mTrading; @@ -113,6 +123,9 @@ namespace MWGui void updateEncumbranceBar(); void notifyContentChanged(); + void dirtyPreview(); + void updatePreviewSize(); + void updateArmorRating(); void adjustPanes(); diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index af4332c7c..a65379fca 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -5,8 +5,12 @@ #include #include +#include + #include +#include + #include "../mwworld/esmstore.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -37,8 +41,10 @@ namespace namespace MWGui { - RaceDialog::RaceDialog() + RaceDialog::RaceDialog(osgViewer::Viewer* viewer, Resource::ResourceSystem* resourceSystem) : WindowModal("openmw_chargen_race.layout") + , mViewer(viewer) + , mResourceSystem(resourceSystem) , mGenderIndex(0) , mFaceIndex(0) , mHairIndex(0) @@ -125,19 +131,20 @@ namespace MWGui updateSkills(); updateSpellPowers(); - //mPreview.reset(NULL); + mPreviewImage->setRenderItemTexture(NULL); - mPreviewImage->setImageTexture(""); + mPreview.reset(NULL); + mPreviewTexture.reset(NULL); - const std::string textureName = "CharacterHeadPreview"; - MyGUI::RenderManager::getInstance().destroyTexture(MyGUI::RenderManager::getInstance().getTexture(textureName)); + mPreview.reset(new MWRender::RaceSelectionPreview(mViewer, mResourceSystem)); + mPreview->rebuild(); + mPreview->setAngle (mCurrentAngle); - //mPreview.reset(new MWRender::RaceSelectionPreview()); - //mPreview->setup(); - //mPreview->update (mCurrentAngle); + mPreviewTexture.reset(new osgMyGUI::OSGTexture(mPreview->getTexture())); + mPreviewImage->setRenderItemTexture(mPreviewTexture.get()); + mPreviewImage->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 1.f, 1.f, 0.f)); - //const ESM::NPC& proto = mPreview->getPrototype(); - ESM::NPC proto; + const ESM::NPC& proto = mPreview->getPrototype(); setRaceId(proto.mRace); recountParts(); @@ -153,8 +160,6 @@ namespace MWGui mHairIndex = i; } - mPreviewImage->setImageTexture (textureName); - mPreviewDirty = true; size_t initialPos = mHeadRotate->getScrollRange()/2+mHeadRotate->getScrollRange()/10; @@ -182,10 +187,10 @@ namespace MWGui void RaceDialog::close() { - mPreviewImage->setImageTexture(""); - const std::string textureName = "CharacterHeadPreview"; - MyGUI::RenderManager::getInstance().destroyTexture(MyGUI::RenderManager::getInstance().getTexture(textureName)); - //mPreview.reset(NULL); + mPreviewImage->setRenderItemTexture(NULL); + + mPreviewTexture.reset(NULL); + mPreview.reset(NULL); } // widget controls @@ -205,8 +210,8 @@ namespace MWGui void RaceDialog::onHeadRotate(MyGUI::ScrollBar* scroll, size_t _position) { float angle = (float(_position) / (scroll->getScrollRange()-1) - 0.5f) * 3.14f * 2; - //mPreview->update (angle); - mPreviewDirty = true; + mPreview->setAngle (angle); + mCurrentAngle = angle; } @@ -317,7 +322,7 @@ namespace MWGui void RaceDialog::updatePreview() { - ESM::NPC record;// = mPreview->getPrototype(); + ESM::NPC record = mPreview->getPrototype(); record.mRace = mCurrentRaceId; record.setIsMale(mGenderIndex == 0); @@ -326,27 +331,12 @@ namespace MWGui try { - //mPreview->setPrototype(record); + mPreview->setPrototype(record); } catch (std::exception& e) { std::cerr << "Error creating preview: " << e.what() << std::endl; } - - mPreviewDirty = true; - } - - void RaceDialog::doRenderUpdate() - { - //if (!mPreview.get()) - return; - - //mPreview->onFrame(); - if (mPreviewDirty) - { - //mPreview->render(); - mPreviewDirty = false; - } } void RaceDialog::updateRaces() @@ -451,8 +441,6 @@ namespace MWGui const ESM::NPC& RaceDialog::getResult() const { - static ESM::NPC result; - return result; - //return mPreview->getPrototype(); + return mPreview->getPrototype(); } } diff --git a/apps/openmw/mwgui/race.hpp b/apps/openmw/mwgui/race.hpp index f188af2b3..b3de9bef0 100644 --- a/apps/openmw/mwgui/race.hpp +++ b/apps/openmw/mwgui/race.hpp @@ -19,12 +19,22 @@ namespace ESM struct NPC; } +namespace osgViewer +{ + class Viewer; +} + +namespace Resource +{ + class ResourceSystem; +} + namespace MWGui { class RaceDialog : public WindowModal { public: - RaceDialog(); + RaceDialog(osgViewer::Viewer* viewer, Resource::ResourceSystem* resourceSystem); enum Gender { @@ -35,13 +45,9 @@ namespace MWGui const ESM::NPC &getResult() const; const std::string &getRaceId() const { return mCurrentRaceId; } Gender getGender() const { return mGenderIndex == 0 ? GM_Male : GM_Female; } - // getFace() - // getHair() void setRaceId(const std::string &raceId); void setGender(Gender gender) { mGenderIndex = gender == GM_Male ? 0 : 1; } - // setFace() - // setHair() void setNextButtonShow(bool shown); virtual void open(); @@ -60,8 +66,6 @@ namespace MWGui */ EventHandle_WindowBase eventDone; - void doRenderUpdate(); - protected: void onHeadRotate(MyGUI::ScrollBar* _sender, size_t _position); @@ -89,6 +93,9 @@ namespace MWGui void getBodyParts (int part, std::vector& out); + osgViewer::Viewer* mViewer; + Resource::ResourceSystem* mResourceSystem; + std::vector mAvailableHeads; std::vector mAvailableHairs; @@ -108,7 +115,8 @@ namespace MWGui float mCurrentAngle; - //std::auto_ptr mPreview; + std::auto_ptr mPreview; + std::auto_ptr mPreviewTexture; bool mPreviewDirty; }; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 0a9e86750..5649908fc 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -275,7 +275,7 @@ namespace MWGui mJournal = JournalWindow::create(JournalViewModel::create ()); mMessageBoxManager = new MessageBoxManager( MWBase::Environment::get().getWorld()->getStore().get().find("fMessageTimePerChar")->getFloat()); - mInventoryWindow = new InventoryWindow(mDragAndDrop); + mInventoryWindow = new InventoryWindow(mDragAndDrop, mViewer, mResourceSystem); mTradeWindow = new TradeWindow(); trackWindow(mTradeWindow, "barter"); mSpellBuyingWindow = new SpellBuyingWindow(); @@ -324,7 +324,7 @@ namespace MWGui mHud->setVisible(mHudEnabled); - mCharGen = new CharacterCreation(); + mCharGen = new CharacterCreation(mViewer, mResourceSystem); // Setup player stats for (int i = 0; i < ESM::Attribute::Length; ++i) @@ -358,7 +358,7 @@ namespace MWGui { disallowAll(); delete mCharGen; - mCharGen = new CharacterCreation(); + mCharGen = new CharacterCreation(mViewer, mResourceSystem); mGuiModes.clear(); MWBase::Environment::get().getInputManager()->changeInputMode(false); mHud->unsetSelectedWeapon(); diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index c0cddb4d0..3a0f543d9 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1081,12 +1081,21 @@ namespace MWRender return true; } - bool Animation::hasNode(const std::string &name) + bool Animation::hasNode(const std::string &name) const { std::string lowerName = Misc::StringUtils::lowerCase(name); return (mNodeMap.find(lowerName) != mNodeMap.end()); } + const osg::Node* Animation::getNode(const std::string &name) const + { + std::string lowerName = Misc::StringUtils::lowerCase(name); + NodeMap::const_iterator found = mNodeMap.find(lowerName); + if (found == mNodeMap.end()) + throw std::runtime_error("Can't find node " + name); + return found->second; + } + float Animation::AnimationTime::getValue(osg::NodeVisitor*) { if (mTimePtr) diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index a12375a9b..0c490b525 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -354,7 +354,11 @@ public: /// Is there a node with the specified name? /// @note The matching is case-insensitive. - bool hasNode(const std::string& name); + bool hasNode(const std::string& name) const; + + /// Return a node with the specified name, throws an exception if the node is not found. + /// @note The matching is case-insensitive. + const osg::Node* getNode(const std::string& name) const; virtual void showWeapons(bool showWeapon) {} virtual void showCarriedLeft(bool show) {} diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 7d61e3b6c..1a7b4ea39 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -1,189 +1,186 @@ #include "characterpreview.hpp" -#include -#include -#include -#include -#include -#include -#include -#include - -#include +#include +#include +#include +#include +#include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwworld/class.hpp" #include "../mwworld/inventorystore.hpp" -#include "renderconst.hpp" #include "npcanimation.hpp" namespace MWRender { - CharacterPreview::CharacterPreview(MWWorld::Ptr character, int sizeX, int sizeY, const std::string& name, - Ogre::Vector3 position, Ogre::Vector3 lookAt) - : mRecover(false) - , mRenderTarget(NULL) - , mViewport(NULL) - , mCamera(NULL) - , mSceneMgr (0) - , mNode(NULL) + class DrawOnceCallback : public osg::NodeCallback + { + public: + DrawOnceCallback () + : mRendered(false) + { + } + + virtual void operator () (osg::Node* node, osg::NodeVisitor* nv) + { + if (!mRendered) + { + mRendered = true; + } + else + { + node->setNodeMask(0); + } + + traverse(node, nv); + } + + void redrawNextFrame() + { + mRendered = false; + } + + private: + bool mRendered; + }; + + CharacterPreview::CharacterPreview(osgViewer::Viewer* viewer, Resource::ResourceSystem* resourceSystem, + MWWorld::Ptr character, int sizeX, int sizeY, const osg::Vec3f& position, const osg::Vec3f& lookAt) + : mViewer(viewer) + , mResourceSystem(resourceSystem) , mPosition(position) , mLookAt(lookAt) , mCharacter(character) , mAnimation(NULL) - , mName(name) , mSizeX(sizeX) , mSizeY(sizeY) { + mTexture = new osg::Texture2D; + mTexture->setTextureSize(sizeX, sizeY); + mTexture->setInternalFormat(GL_RGBA); + mTexture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR); + mTexture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); + + mCamera = new osg::Camera; + // hints that the camera is not relative to the master camera + mCamera->setReferenceFrame(osg::Camera::ABSOLUTE_RF); + mCamera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT, osg::Camera::PIXEL_BUFFER_RTT); + mCamera->setClearColor(osg::Vec4(0.f, 0.f, 0.f, 0.f)); + mCamera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + const float fovYDegrees = 12.3f; + mCamera->setProjectionMatrixAsPerspective(fovYDegrees, sizeX/static_cast(sizeY), 0.1f, 10000.f); // zNear and zFar are autocomputed + mCamera->setViewport(0, 0, sizeX, sizeY); + mCamera->setRenderOrder(osg::Camera::PRE_RENDER); + mCamera->attach(osg::Camera::COLOR_BUFFER, mTexture); + mCamera->setGraphicsContext(mViewer->getCamera()->getGraphicsContext()); + + osg::ref_ptr lightManager = new SceneUtil::LightManager; + lightManager->setStartLight(1); + osg::ref_ptr stateset = new osg::StateSet; + stateset->setMode(GL_LIGHTING, osg::StateAttribute::ON); + stateset->setMode(GL_NORMALIZE, osg::StateAttribute::ON); + stateset->setMode(GL_CULL_FACE, osg::StateAttribute::ON); + + osg::ref_ptr lightmodel = new osg::LightModel; + lightmodel->setAmbientIntensity(osg::Vec4(0.25, 0.25, 0.25, 1.0)); + stateset->setAttributeAndModes(lightmodel, osg::StateAttribute::ON); + + /// \todo Read the fallback values from INIImporter (Inventory:Directional*) ? + osg::ref_ptr light = new osg::Light; + light->setPosition(osg::Vec4(-0.3,0.3,0.7, 0.0)); + light->setDiffuse(osg::Vec4(1,1,1,1)); + light->setAmbient(osg::Vec4(0,0,0,1)); + light->setSpecular(osg::Vec4(0,0,0,0)); + light->setLightNum(0); + light->setConstantAttenuation(1.f); + light->setLinearAttenuation(0.f); + light->setQuadraticAttenuation(0.f); + + osg::ref_ptr lightSource = new osg::LightSource; + lightSource->setLight(light); + + lightSource->setStateSetModes(*stateset, osg::StateAttribute::ON); + + lightManager->setStateSet(stateset); + lightManager->addChild(lightSource); + + mCamera->addChild(lightManager); + + mNode = new osg::PositionAttitudeTransform; + lightManager->addChild(mNode); + + mDrawOnceCallback = new DrawOnceCallback; + mCamera->addUpdateCallback(mDrawOnceCallback); + + mViewer->getSceneData()->asGroup()->addChild(mCamera); + mCharacter.mCell = NULL; } - void CharacterPreview::onSetup() + CharacterPreview::~CharacterPreview () { - + mViewer->getSceneData()->asGroup()->removeChild(mCamera); } - void CharacterPreview::onFrame() + int CharacterPreview::getTextureWidth() const { - if (mRecover) - { - setupRenderTarget(); - mRenderTarget->update(); - mRecover = false; - } + return mSizeX; } - void CharacterPreview::setup () + int CharacterPreview::getTextureHeight() const { - mSceneMgr = Ogre::Root::getSingleton().createSceneManager(Ogre::ST_GENERIC); - - // This is a dummy light to turn off shadows without having to use a separate set of shaders - Ogre::Light* l = mSceneMgr->createLight(); - l->setType (Ogre::Light::LT_DIRECTIONAL); - l->setDiffuseColour (Ogre::ColourValue(0,0,0)); - - /// \todo Read the fallback values from INIImporter (Inventory:Directional*) - l = mSceneMgr->createLight(); - l->setType (Ogre::Light::LT_DIRECTIONAL); - l->setDirection (Ogre::Vector3(0.3f, -0.7f, 0.3f)); - l->setDiffuseColour (Ogre::ColourValue(1,1,1)); - - mSceneMgr->setAmbientLight (Ogre::ColourValue(0.25, 0.25, 0.25)); - - mCamera = mSceneMgr->createCamera (mName); - mCamera->setFOVy(Ogre::Degree(12.3f)); - mCamera->setAspectRatio (float(mSizeX) / float(mSizeY)); - - Ogre::SceneNode* renderRoot = mSceneMgr->getRootSceneNode()->createChildSceneNode("renderRoot"); - - // leftover of old coordinate system. TODO: remove this and adjust positions/orientations to match - renderRoot->pitch(Ogre::Degree(-90)); - - mNode = renderRoot->createChildSceneNode(); - - mAnimation = new NpcAnimation(mCharacter, mNode, - 0, true, true, (renderHeadOnly() ? NpcAnimation::VM_HeadOnly : NpcAnimation::VM_Normal)); - - Ogre::Vector3 scale = mNode->getScale(); - mCamera->setPosition(mPosition * scale); - mCamera->lookAt(mLookAt * scale); - - mCamera->setNearClipDistance (1); - mCamera->setFarClipDistance (1000); - - mTexture = Ogre::TextureManager::getSingleton().createManual(mName, - Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::TEX_TYPE_2D, mSizeX, mSizeY, 0, Ogre::PF_A8R8G8B8, Ogre::TU_RENDERTARGET, this); - - setupRenderTarget(); + return mSizeY; + } - onSetup (); + void CharacterPreview::onSetup() + { } - CharacterPreview::~CharacterPreview () + osg::ref_ptr CharacterPreview::getTexture() { - if (mSceneMgr) - { - mSceneMgr->destroyAllCameras(); - delete mAnimation; - Ogre::Root::getSingleton().destroySceneManager(mSceneMgr); - Ogre::TextureManager::getSingleton().remove(mName); - } + return mTexture; } void CharacterPreview::rebuild() { delete mAnimation; mAnimation = NULL; - mAnimation = new NpcAnimation(mCharacter, mNode, - 0, true, true, (renderHeadOnly() ? NpcAnimation::VM_HeadOnly : NpcAnimation::VM_Normal)); - - float scale=1.f; - mCharacter.getClass().adjustScale(mCharacter, scale); - mNode->setScale(Ogre::Vector3(scale)); - mCamera->setPosition(mPosition * mNode->getScale()); - mCamera->lookAt(mLookAt * mNode->getScale()); + mAnimation = new NpcAnimation(mCharacter, mNode, mResourceSystem, 0, true, true, + (renderHeadOnly() ? NpcAnimation::VM_HeadOnly : NpcAnimation::VM_Normal)); onSetup(); - } - - void CharacterPreview::loadResource(Ogre::Resource *resource) - { - Ogre::Texture* tex = dynamic_cast(resource); - if (!tex) - return; - - tex->createInternalResources(); - mRenderTarget = NULL; - mViewport = NULL; - mRecover = true; + redraw(); } - void CharacterPreview::setupRenderTarget() + void CharacterPreview::redraw() { - mRenderTarget = mTexture->getBuffer()->getRenderTarget(); - mRenderTarget->removeAllViewports (); - mViewport = mRenderTarget->addViewport(mCamera); - mViewport->setOverlaysEnabled(false); - mViewport->setBackgroundColour(Ogre::ColourValue(0, 0, 0, 0)); - mViewport->setShadowsEnabled(false); - mRenderTarget->setActive(true); - mRenderTarget->setAutoUpdated (false); + mCamera->setNodeMask(~0); + mDrawOnceCallback->redrawNextFrame(); } // -------------------------------------------------------------------------------------------------- - InventoryPreview::InventoryPreview(MWWorld::Ptr character) - : CharacterPreview(character, 512, 1024, "CharacterPreview", Ogre::Vector3(0, 71, -700), Ogre::Vector3(0,71,0)) - , mSizeX(0) - , mSizeY(0) - , mSelectionBuffer(NULL) + InventoryPreview::InventoryPreview(osgViewer::Viewer* viewer, Resource::ResourceSystem* resourceSystem, MWWorld::Ptr character) + : CharacterPreview(viewer, resourceSystem, character, 512, 1024, osg::Vec3f(0, 700, 71), osg::Vec3f(0,0,71)) { } - InventoryPreview::~InventoryPreview() + void InventoryPreview::setViewport(int sizeX, int sizeY) { - delete mSelectionBuffer; - } - - void InventoryPreview::resize(int sizeX, int sizeY) - { - mSizeX = sizeX; - mSizeY = sizeY; + sizeX = std::max(sizeX, 0); + sizeY = std::max(sizeY, 0); - mViewport->setDimensions (0, 0, std::min(1.f, float(mSizeX) / float(512)), std::min(1.f, float(mSizeY) / float(1024))); - mTexture->load(); + mCamera->setViewport(0, 0, std::min(mSizeX, sizeX), std::min(mSizeY, sizeY)); - if (!mRenderTarget) - setupRenderTarget(); - - mRenderTarget->update(); + redraw(); } void InventoryPreview::update() @@ -191,6 +188,7 @@ namespace MWRender if (!mAnimation) return; + mAnimation->showWeapons(true); mAnimation->updateParts(); MWWorld::InventoryStore &inv = mCharacter.getClass().getInventoryStore(mCharacter); @@ -250,70 +248,51 @@ namespace MWRender mAnimation->runAnimation(0.0f); - mNode->setOrientation (Ogre::Quaternion::IDENTITY); - - mViewport->setDimensions (0, 0, std::min(1.f, float(mSizeX) / float(512)), std::min(1.f, float(mSizeY) / float(1024))); - mTexture->load(); - - if (!mRenderTarget) - setupRenderTarget(); - - mRenderTarget->update(); - - mSelectionBuffer->update(); + redraw(); } - void InventoryPreview::setupRenderTarget() + int InventoryPreview::getSlotSelected (int posX, int posY) { - CharacterPreview::setupRenderTarget(); - mViewport->setDimensions (0, 0, std::min(1.f, float(mSizeX) / float(512)), std::min(1.f, float(mSizeY) / float(1024))); + // TODO: implement + return 0; } - int InventoryPreview::getSlotSelected (int posX, int posY) + void InventoryPreview::updatePtr(const MWWorld::Ptr &ptr) { - return mSelectionBuffer->getSelected (posX, posY); + mCharacter = MWWorld::Ptr(ptr.getBase(), NULL); } - void InventoryPreview::onSetup () + void InventoryPreview::onSetup() { - delete mSelectionBuffer; - mSelectionBuffer = new OEngine::Render::SelectionBuffer(mCamera, 512, 1024, 0); + osg::Vec3f scale (1.f, 1.f, 1.f); + mCharacter.getClass().adjustScale(mCharacter, scale); - mAnimation->showWeapons(true); + mNode->setScale(scale); - mCurrentAnimGroup = "inventoryhandtohand"; - mAnimation->play(mCurrentAnimGroup, 1, Animation::Group_All, false, 1.0f, "start", "stop", 0.0f, 0); + mCamera->setViewMatrixAsLookAt(mPosition * scale.z(), mLookAt * scale.z(), osg::Vec3f(0,0,1)); } // -------------------------------------------------------------------------------------------------- - RaceSelectionPreview::RaceSelectionPreview() - : CharacterPreview(MWBase::Environment::get().getWorld()->getPlayerPtr(), - 512, 512, "CharacterHeadPreview", Ogre::Vector3(0, 8, -125), Ogre::Vector3(0,127,0)) + RaceSelectionPreview::RaceSelectionPreview(osgViewer::Viewer* viewer, Resource::ResourceSystem* resourceSystem) + : CharacterPreview(viewer, resourceSystem, MWBase::Environment::get().getWorld()->getPlayerPtr(), + 512, 512, osg::Vec3f(0, 125, 8), osg::Vec3f(0,0,8)) , mBase (*mCharacter.get()->mBase) , mRef(&mBase) - , mPitch(Ogre::Degree(6)) + , mPitchRadians(osg::DegreesToRadians(6.f)) { mCharacter = MWWorld::Ptr(&mRef, NULL); } - void RaceSelectionPreview::update(float angle) + RaceSelectionPreview::~RaceSelectionPreview() { - mAnimation->runAnimation(0.0f); - - mNode->setOrientation(Ogre::Quaternion(Ogre::Radian(angle), Ogre::Vector3::UNIT_Z) - * Ogre::Quaternion(mPitch, Ogre::Vector3::UNIT_X)); - - updateCamera(); } - void RaceSelectionPreview::render() + void RaceSelectionPreview::setAngle(float angleRadians) { - mTexture->load(); - - if (!mRenderTarget) - setupRenderTarget(); - mRenderTarget->update(); + mNode->setAttitude(osg::Quat(mPitchRadians, osg::Vec3(1,0,0)) + * osg::Quat(angleRadians, osg::Vec3(0,0,1))); + redraw(); } void RaceSelectionPreview::setPrototype(const ESM::NPC &proto) @@ -321,27 +300,53 @@ namespace MWRender mBase = proto; mBase.mId = "player"; rebuild(); - mAnimation->runAnimation(0.0f); - updateCamera(); } - void RaceSelectionPreview::onSetup () + class UpdateCameraCallback : public osg::NodeCallback { - mAnimation->play("idle", 1, Animation::Group_All, false, 1.0f, "start", "stop", 0.0f, 0); + public: + UpdateCameraCallback(osg::ref_ptr nodeToFollow, const osg::Vec3& posOffset, const osg::Vec3& lookAtOffset) + : mNodeToFollow(nodeToFollow) + , mPosOffset(posOffset) + , mLookAtOffset(lookAtOffset) + { + } - updateCamera(); - } + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) + { + osg::Camera* cam = static_cast(node); - void RaceSelectionPreview::updateCamera() + // Update keyframe controllers in the scene graph first... + traverse(node, nv); + + // Now update camera utilizing the updated head position + osg::MatrixList mats = mNodeToFollow->getWorldMatrices(); + if (!mats.size()) + return; + osg::Matrix worldMat = mats[0]; + osg::Vec3 headOffset = worldMat.getTrans(); + + cam->setViewMatrixAsLookAt(headOffset + mPosOffset, headOffset + mLookAtOffset, osg::Vec3(0,0,1)); + } + + private: + osg::ref_ptr mNodeToFollow; + osg::Vec3 mPosOffset; + osg::Vec3 mLookAtOffset; + }; + + void RaceSelectionPreview::onSetup () { - Ogre::Vector3 scale = mNode->getScale(); - Ogre::Node* headNode = mAnimation->getNode("Bip01 Head"); - if (!headNode) - return; - Ogre::Vector3 headOffset = headNode->_getDerivedPosition(); - headOffset = mNode->convertLocalToWorldPosition(headOffset); + mAnimation->play("idle", 1, Animation::Group_All, false, 1.0f, "start", "stop", 0.0f, 0); + mAnimation->runAnimation(0.f); - mCamera->setPosition(headOffset + mPosition * scale); - mCamera->lookAt(headOffset + mPosition*Ogre::Vector3(0,1,0) * scale); + // attach camera to follow the head node + if (mUpdateCameraCallback) + mCamera->removeUpdateCallback(mUpdateCameraCallback); + + const osg::Node* head = mAnimation->getNode("Bip01 Head"); + mUpdateCameraCallback = new UpdateCameraCallback(head, mPosition, mLookAt); + mCamera->addUpdateCallback(mUpdateCameraCallback); } + } diff --git a/apps/openmw/mwrender/characterpreview.hpp b/apps/openmw/mwrender/characterpreview.hpp index 80dbe18b4..b7722d1f3 100644 --- a/apps/openmw/mwrender/characterpreview.hpp +++ b/apps/openmw/mwrender/characterpreview.hpp @@ -1,45 +1,48 @@ #ifndef MWRENDER_CHARACTERPREVIEW_H #define MWRENDER_CHARACTERPREVIEW_H -#include -#include #include +#include + #include +#include + #include "../mwworld/ptr.hpp" -namespace OEngine +namespace osg { -namespace Render -{ -class SelectionBuffer; + class Texture2D; + class Camera; } + +namespace osgViewer +{ + class Viewer; } namespace MWRender { class NpcAnimation; + class DrawOnceCallback; - class CharacterPreview : public Ogre::ManualResourceLoader + class CharacterPreview { public: - CharacterPreview(MWWorld::Ptr character, int sizeX, int sizeY, const std::string& name, - Ogre::Vector3 position, Ogre::Vector3 lookAt); + CharacterPreview(osgViewer::Viewer* viewer, Resource::ResourceSystem* resourceSystem, MWWorld::Ptr character, int sizeX, int sizeY, + const osg::Vec3f& position, const osg::Vec3f& lookAt); virtual ~CharacterPreview(); - virtual void setup (); - virtual void onSetup(); - - virtual void rebuild(); + int getTextureWidth() const; + int getTextureHeight() const; - void onFrame(); + void redraw(); - void loadResource(Ogre::Resource *resource); + void rebuild(); - private: - bool mRecover; // Texture content was lost and needs to be re-rendered + osg::ref_ptr getTexture(); private: CharacterPreview(const CharacterPreview&); @@ -47,28 +50,23 @@ namespace MWRender protected: virtual bool renderHeadOnly() { return false; } + virtual void onSetup(); - virtual void setupRenderTarget(); - - Ogre::TexturePtr mTexture; - Ogre::RenderTarget* mRenderTarget; - Ogre::Viewport* mViewport; - - Ogre::Camera* mCamera; - - Ogre::SceneManager* mSceneMgr; - Ogre::SceneNode* mNode; + osg::ref_ptr mViewer; + Resource::ResourceSystem* mResourceSystem; + osg::ref_ptr mTexture; + osg::ref_ptr mCamera; + osg::ref_ptr mDrawOnceCallback; - Ogre::Vector3 mPosition; - Ogre::Vector3 mLookAt; + osg::Vec3f mPosition; + osg::Vec3f mLookAt; MWWorld::Ptr mCharacter; MWRender::NpcAnimation* mAnimation; + osg::ref_ptr mNode; std::string mCurrentAnimGroup; - std::string mName; - int mSizeX; int mSizeY; }; @@ -77,25 +75,21 @@ namespace MWRender { public: - InventoryPreview(MWWorld::Ptr character); - virtual ~InventoryPreview(); - virtual void onSetup(); + InventoryPreview(osgViewer::Viewer* viewer, Resource::ResourceSystem* resourceSystem, MWWorld::Ptr character); + + void updatePtr(const MWWorld::Ptr& ptr); void update(); // Render preview again, e.g. after changed equipment - void resize(int sizeX, int sizeY); + void setViewport(int sizeX, int sizeY); int getSlotSelected(int posX, int posY); protected: - virtual void setupRenderTarget(); - - private: - int mSizeX; - int mSizeY; - - OEngine::Render::SelectionBuffer* mSelectionBuffer; + virtual void onSetup(); }; + class UpdateCameraCallback; + class RaceSelectionPreview : public CharacterPreview { ESM::NPC mBase; @@ -104,16 +98,13 @@ namespace MWRender protected: virtual bool renderHeadOnly() { return true; } - - void updateCamera(); + virtual void onSetup(); public: - RaceSelectionPreview(); + RaceSelectionPreview(osgViewer::Viewer* viewer, Resource::ResourceSystem* resourceSystem); + virtual ~RaceSelectionPreview(); - virtual void onSetup(); - void render(); - - void update(float angle); + void setAngle(float angleRadians); const ESM::NPC &getPrototype() const { return mBase; @@ -123,7 +114,9 @@ namespace MWRender private: - Ogre::Radian mPitch; + osg::ref_ptr mUpdateCameraCallback; + + float mPitchRadians; }; } From 8d033f055814ed7c27851fcdfbd343fc41d255a7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 20 May 2015 03:12:42 +0200 Subject: [PATCH 1216/3725] Fix UpdateRigBounds not being copied properly --- components/sceneutil/riggeometry.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/components/sceneutil/riggeometry.cpp b/components/sceneutil/riggeometry.cpp index df5f65029..065ee60d9 100644 --- a/components/sceneutil/riggeometry.cpp +++ b/components/sceneutil/riggeometry.cpp @@ -26,6 +26,8 @@ public: { } + META_Object(SceneUtil, UpdateRigBounds) + void update(osg::NodeVisitor* nv, osg::Drawable* drw) { RigGeometry* rig = static_cast(drw); @@ -47,7 +49,7 @@ public: { } - META_Object(NifOsg, UpdateRigGeometry) + META_Object(SceneUtil, UpdateRigGeometry) virtual bool cull(osg::NodeVisitor* nv, osg::Drawable* drw, osg::State*) const { From c4452afd89956185c9542842c2f91949df43b67c Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 20 May 2015 03:35:52 +0200 Subject: [PATCH 1217/3725] Inventory item picking --- apps/openmw/mwgui/inventorywindow.cpp | 6 +++--- apps/openmw/mwgui/tooltips.cpp | 4 +--- apps/openmw/mwrender/characterpreview.cpp | 19 +++++++++++++++++-- apps/openmw/mwrender/npcanimation.cpp | 15 +++++++++++++++ apps/openmw/mwrender/npcanimation.hpp | 3 +++ apps/openmw/mwrender/renderingmanager.cpp | 2 ++ 6 files changed, 41 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index a225b4e11..943d09f1a 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -487,10 +487,8 @@ namespace MWGui { MyGUI::IntPoint mousePos = MyGUI::InputManager::getInstance ().getLastPressedPosition (MyGUI::MouseButton::Left); MyGUI::IntPoint relPos = mousePos - mAvatarImage->getAbsolutePosition (); - int realX = int(float(relPos.left) / float(mAvatarImage->getSize().width) * 512.f ); - int realY = int(float(relPos.top) / float(mAvatarImage->getSize().height) * 1024.f ); - MWWorld::Ptr itemSelected = getAvatarSelectedItem (realX, realY); + MWWorld::Ptr itemSelected = getAvatarSelectedItem (relPos.left, relPos.top); if (itemSelected.isEmpty ()) return; @@ -508,6 +506,8 @@ namespace MWGui MWWorld::Ptr InventoryWindow::getAvatarSelectedItem(int x, int y) { + // convert to OpenGL lower-left origin + y = (mAvatarImage->getHeight()-1) - y; int slot = mPreview->getSlotSelected (x, y); if (slot == -1) diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 14eed0e10..f423142e0 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -200,9 +200,7 @@ namespace MWGui { MyGUI::IntCoord avatarPos = focus->getAbsoluteCoord(); MyGUI::IntPoint relMousePos = MyGUI::InputManager::getInstance ().getMousePosition () - MyGUI::IntPoint(avatarPos.left, avatarPos.top); - int realX = int(float(relMousePos.left) / float(avatarPos.width) * 512.f ); - int realY = int(float(relMousePos.top) / float(avatarPos.height) * 1024.f ); - MWWorld::Ptr item = MWBase::Environment::get().getWindowManager()->getInventoryWindow ()->getAvatarSelectedItem (realX, realY); + MWWorld::Ptr item = MWBase::Environment::get().getWindowManager()->getInventoryWindow ()->getAvatarSelectedItem (relMousePos.left, relMousePos.top); mFocusObject = item; if (!mFocusObject.isEmpty ()) diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 1a7b4ea39..cc6b4a9bb 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -5,6 +5,8 @@ #include #include #include +#include +#include #include @@ -253,8 +255,21 @@ namespace MWRender int InventoryPreview::getSlotSelected (int posX, int posY) { - // TODO: implement - return 0; + osg::ref_ptr intersector (new osgUtil::LineSegmentIntersector(osgUtil::Intersector::WINDOW, posX, posY)); + intersector->setIntersectionLimit(osgUtil::LineSegmentIntersector::LIMIT_ONE); + osgUtil::IntersectionVisitor visitor(intersector); + + osg::Node::NodeMask nodeMask = mCamera->getNodeMask(); + mCamera->setNodeMask(~0); + mCamera->accept(visitor); + mCamera->setNodeMask(nodeMask); + + if (intersector->containsIntersections()) + { + osgUtil::LineSegmentIntersector::Intersection intersection = intersector->getFirstIntersection(); + return mAnimation->getSlot(intersection.nodePath); + } + return -1; } void InventoryPreview::updatePtr(const MWWorld::Ptr &ptr) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 2bb1b66fd..932da30b9 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -235,6 +235,21 @@ void NpcAnimation::rebuild() MWBase::Environment::get().getMechanicsManager()->forceStateUpdate(mPtr); } +int NpcAnimation::getSlot(const osg::NodePath &path) const +{ + for (int i=0; igetNode().get()) != path.end()) + { + return mPartslots[i]; + } + } + return -1; +} + void NpcAnimation::updateNpcBase() { clearAnimSources(); diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index a58f0fdf3..7ebc42784 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -174,6 +174,9 @@ public: /// Rebuilds the NPC, updating their root model, animation sources, and equipment. void rebuild(); + /// Get the inventory slot that the given node path leads into, or -1 if not found. + int getSlot(const osg::NodePath& path) const; + /// Make the NPC only partially visible virtual void setAlpha(float alpha); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index c0eb00ea4..5ece10dc1 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -139,6 +139,8 @@ namespace MWRender mViewer->getCamera()->setComputeNearFarMode(osg::Camera::DO_NOT_COMPUTE_NEAR_FAR); mViewer->getCamera()->setCullingMode(cullingMode); + mViewer->getCamera()->setCullMask(~(Mask_UpdateVisitor)); + mViewDistance = Settings::Manager::getFloat("viewing distance", "Viewing distance"); mFieldOfView = Settings::Manager::getFloat("field of view", "General"); updateProjectionMatrix(); From 7882c3d7f05565409672870089b7c16af16e8619 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 20 May 2015 03:38:40 +0200 Subject: [PATCH 1218/3725] Fix incorrect rotation for meshes with BoneOffset --- components/sceneutil/attach.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/sceneutil/attach.cpp b/components/sceneutil/attach.cpp index 49e2acbd2..2432b5eb2 100644 --- a/components/sceneutil/attach.cpp +++ b/components/sceneutil/attach.cpp @@ -82,7 +82,7 @@ namespace SceneUtil trans = new osg::PositionAttitudeTransform; trans->setPosition(boneOffset->getMatrix().getTrans()); // The BoneOffset rotation seems to be incorrect - trans->setAttitude(osg::Quat(-90, osg::Vec3f(1,0,0))); + trans->setAttitude(osg::Quat(osg::DegreesToRadians(-90.f), osg::Vec3f(1,0,0))); } if (attachNode.find("Left") != std::string::npos) From cfe57199d7f8f1c1240664a7d8da47a6bc777e5c Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 20 May 2015 03:54:04 +0200 Subject: [PATCH 1219/3725] Minor cleanup --- apps/openmw/mwrender/npcanimation.cpp | 6 ++---- apps/openmw/mwrender/npcanimation.hpp | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 932da30b9..b23a72e55 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -586,15 +586,13 @@ void NpcAnimation::addFirstPersonOffset(const Ogre::Vector3 &offset) mFirstPersonOffset += offset; }*/ -Animation::PartHolderPtr NpcAnimation::insertBoundedPart(const std::string& model, int group, const std::string& bonename, const std::string& bonefilter, bool enchantedGlow, osg::Vec4f* glowColor) +Animation::PartHolderPtr NpcAnimation::insertBoundedPart(const std::string& model, const std::string& bonename, const std::string& bonefilter, bool enchantedGlow, osg::Vec4f* glowColor) { osg::ref_ptr instance = mResourceSystem->getSceneManager()->createInstance(model); osg::ref_ptr attached = SceneUtil::attach(instance, mObjectRoot, bonefilter, bonename); if (enchantedGlow) addGlow(attached, *glowColor); - // TODO: set group userdata for inventory picking - return PartHolderPtr(new PartHolder(attached)); } @@ -679,7 +677,7 @@ bool NpcAnimation::addOrReplaceIndividualPart(ESM::PartReferenceType type, int g const std::string& bonename = sPartList.at(type); // PRT_Hair seems to be the only type that breaks consistency and uses a filter that's different from the attachment bone const std::string bonefilter = (type == ESM::PRT_Hair) ? "hair" : bonename; - mObjectParts[type] = insertBoundedPart(mesh, group, bonename, bonefilter, enchantedGlow, glowColor); + mObjectParts[type] = insertBoundedPart(mesh, bonename, bonefilter, enchantedGlow, glowColor); } catch (std::exception& e) { diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 7ebc42784..eda59f50c 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -105,7 +105,7 @@ private: void updateNpcBase(); - PartHolderPtr insertBoundedPart(const std::string &model, int group, const std::string &bonename, + PartHolderPtr insertBoundedPart(const std::string &model, const std::string &bonename, const std::string &bonefilter, bool enchantedGlow, osg::Vec4f* glowColor=NULL); void removeIndividualPart(ESM::PartReferenceType type); From ca7829032eac7e43e0edb58cf4d27137433f0aee Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 20 May 2015 11:45:16 +0200 Subject: [PATCH 1220/3725] updated credits file --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index 0cd961c61..4fef9233a 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -98,6 +98,7 @@ Programmers Sebastian Wick (swick) Sergey Shambir sir_herrbatka + smbas Stefan Galowicz (bogglez) Stanislav Bobrov (Jiub) Sylvain Thesnieres (Garvek) From 1d0b8587a1682dd1116b0a254f4b0ea4416fefd9 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Wed, 20 May 2015 21:14:17 +1000 Subject: [PATCH 1221/3725] Use HasWater bit flag rather than mWaterInt bool. --- apps/opencs/model/world/columns.cpp | 3 +-- apps/opencs/model/world/columns.hpp | 5 ++-- apps/opencs/model/world/data.cpp | 4 +-- .../model/world/nestedcoladapterimp.cpp | 27 +++++++------------ 4 files changed, 14 insertions(+), 25 deletions(-) diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index ee7a00ca0..c937997a9 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -62,7 +62,7 @@ namespace CSMWorld { ColumnId_StarterSpell, "Starter Spell" }, { ColumnId_AlwaysSucceeds, "Always Succeeds" }, { ColumnId_SleepForbidden, "Sleep Forbidden" }, - { ColumnId_Water, "Has Water" }, + { ColumnId_InteriorWater, "Interior Water" }, { ColumnId_InteriorSky, "Interior Sky" }, { ColumnId_Model, "Model" }, { ColumnId_Script, "Script" }, @@ -309,7 +309,6 @@ namespace CSMWorld { ColumnId_Fog, "Fog" }, { ColumnId_FogDensity, "Fog Density" }, { ColumnId_WaterLevel, "Water Level" }, - { ColumnId_InteriorWater, "Interior Water" }, { ColumnId_MapColor, "Map Color" }, { ColumnId_UseValue1, "Use value 1" }, diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 3a345b3ec..191bbdea8 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -57,7 +57,7 @@ namespace CSMWorld ColumnId_StarterSpell = 42, ColumnId_AlwaysSucceeds = 43, ColumnId_SleepForbidden = 44, - ColumnId_Water = 45, + ColumnId_InteriorWater = 45, ColumnId_InteriorSky = 46, ColumnId_Model = 47, ColumnId_Script = 48, @@ -300,8 +300,7 @@ namespace CSMWorld ColumnId_Fog = 271, ColumnId_FogDensity = 272, ColumnId_WaterLevel = 273, - ColumnId_InteriorWater = 274, - ColumnId_MapColor = 275, + ColumnId_MapColor = 274, // Allocated to a separate value range, so we don't get a collision should we ever need // to extend the number of use values. diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 00349d476..920c7db71 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -287,7 +287,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mCells.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Cell)); mCells.addColumn (new NameColumn); mCells.addColumn (new FlagColumn (Columns::ColumnId_SleepForbidden, ESM::Cell::NoSleep)); - mCells.addColumn (new FlagColumn (Columns::ColumnId_Water, ESM::Cell::HasWater)); + mCells.addColumn (new FlagColumn (Columns::ColumnId_InteriorWater, ESM::Cell::HasWater)); mCells.addColumn (new FlagColumn (Columns::ColumnId_InteriorSky, ESM::Cell::QuasiEx)); mCells.addColumn (new RegionColumn); mCells.addColumn (new RefNumCounterColumn); @@ -306,8 +306,6 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc new NestedChildColumn (Columns::ColumnId_Fog, ColumnBase::Display_Integer)); mCells.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_FogDensity, ColumnBase::Display_Float)); - mCells.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_InteriorWater, ColumnBase::Display_Boolean)); mCells.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_WaterLevel, ColumnBase::Display_Float)); mCells.getNestableColumn(index)->addColumn( diff --git a/apps/opencs/model/world/nestedcoladapterimp.cpp b/apps/opencs/model/world/nestedcoladapterimp.cpp index a63ebe672..8c897f71c 100644 --- a/apps/opencs/model/world/nestedcoladapterimp.cpp +++ b/apps/opencs/model/world/nestedcoladapterimp.cpp @@ -1064,6 +1064,7 @@ namespace CSMWorld bool isInterior = (cell.mData.mFlags & ESM::Cell::Interior) != 0; bool behaveLikeExterior = (cell.mData.mFlags & ESM::Cell::QuasiEx) != 0; + bool interiorWater = (cell.mData.mFlags & ESM::Cell::HasWater) != 0; switch (subColIndex) { @@ -1072,16 +1073,15 @@ namespace CSMWorld case 2: return (isInterior && !behaveLikeExterior) ? cell.mAmbi.mSunlight : QVariant(); case 3: return (isInterior && !behaveLikeExterior) ? cell.mAmbi.mFog : QVariant(); case 4: return (isInterior && !behaveLikeExterior) ? cell.mAmbi.mFogDensity : QVariant(); - case 5: return (isInterior && !behaveLikeExterior) ? cell.mWaterInt==true : QVariant(); - case 6: + case 5: { - if (isInterior && !behaveLikeExterior && cell.mWaterInt) + if (isInterior && !behaveLikeExterior && interiorWater) return cell.mWater; else return QVariant(); } - case 7: return isInterior ? QVariant() : cell.mMapColor; // TODO: how to select? - //case 8: return isInterior ? behaveLikeExterior : QVariant(); + case 6: return isInterior ? QVariant() : cell.mMapColor; // TODO: how to select? + //case 7: return isInterior ? behaveLikeExterior : QVariant(); default: throw std::runtime_error("Cell subcolumn index out of range"); } } @@ -1093,6 +1093,7 @@ namespace CSMWorld bool isInterior = (cell.mData.mFlags & ESM::Cell::Interior) != 0; bool behaveLikeExterior = (cell.mData.mFlags & ESM::Cell::QuasiEx) != 0; + bool interiorWater = (cell.mData.mFlags & ESM::Cell::HasWater) != 0; switch (subColIndex) { @@ -1138,21 +1139,13 @@ namespace CSMWorld } case 5: { - if (isInterior && !behaveLikeExterior) - cell.mWaterInt = value.toBool(); - else - return; // return without saving - break; - } - case 6: - { - if (isInterior && !behaveLikeExterior && cell.mWaterInt) + if (isInterior && !behaveLikeExterior && interiorWater) cell.mWater = value.toFloat(); else return; // return without saving break; } - case 7: + case 6: { if (!isInterior) cell.mMapColor = value.toInt(); @@ -1163,7 +1156,7 @@ namespace CSMWorld #if 0 // redundant since this flag is shown in the main table as "Interior Sky" // keep here for documenting the logic based on vanilla - case 8: + case 7: { if (isInterior) { @@ -1185,7 +1178,7 @@ namespace CSMWorld int CellListAdapter::getColumnsCount(const Record& record) const { - return 8; + return 7; } int CellListAdapter::getRowsCount(const Record& record) const From 2fc964ca7372b7f67055706c661f79202ddbe539 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Thu, 21 May 2015 13:11:07 +1000 Subject: [PATCH 1222/3725] Grey out disabled entries rather than hiding them. --- .../model/world/nestedcoladapterimp.cpp | 20 ++++++++++------ apps/opencs/model/world/refidadapterimp.cpp | 10 ++++---- apps/opencs/model/world/refidadapterimp.hpp | 2 +- apps/opencs/view/world/dialoguesubview.cpp | 23 ++++++++++++++++++- 4 files changed, 41 insertions(+), 14 deletions(-) diff --git a/apps/opencs/model/world/nestedcoladapterimp.cpp b/apps/opencs/model/world/nestedcoladapterimp.cpp index 8c897f71c..b7d09777d 100644 --- a/apps/opencs/model/world/nestedcoladapterimp.cpp +++ b/apps/opencs/model/world/nestedcoladapterimp.cpp @@ -1069,19 +1069,25 @@ namespace CSMWorld switch (subColIndex) { case 0: return isInterior; - case 1: return (isInterior && !behaveLikeExterior) ? cell.mAmbi.mAmbient : QVariant(); - case 2: return (isInterior && !behaveLikeExterior) ? cell.mAmbi.mSunlight : QVariant(); - case 3: return (isInterior && !behaveLikeExterior) ? cell.mAmbi.mFog : QVariant(); - case 4: return (isInterior && !behaveLikeExterior) ? cell.mAmbi.mFogDensity : QVariant(); + case 1: return (isInterior && !behaveLikeExterior) ? + cell.mAmbi.mAmbient : QVariant(QVariant::UserType); + case 2: return (isInterior && !behaveLikeExterior) ? + cell.mAmbi.mSunlight : QVariant(QVariant::UserType); + case 3: return (isInterior && !behaveLikeExterior) ? + cell.mAmbi.mFog : QVariant(QVariant::UserType); + case 4: return (isInterior && !behaveLikeExterior) ? + cell.mAmbi.mFogDensity : QVariant(QVariant::UserType); case 5: { if (isInterior && !behaveLikeExterior && interiorWater) return cell.mWater; else - return QVariant(); + return QVariant(QVariant::UserType); } - case 6: return isInterior ? QVariant() : cell.mMapColor; // TODO: how to select? - //case 7: return isInterior ? behaveLikeExterior : QVariant(); + case 6: return isInterior ? + QVariant(QVariant::UserType) : cell.mMapColor; // TODO: how to select? + //case 7: return isInterior ? + //behaveLikeExterior : QVariant(QVariant::UserType); default: throw std::runtime_error("Cell subcolumn index out of range"); } } diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index a5f0b2244..ee045afd0 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -502,7 +502,7 @@ QVariant CSMWorld::NpcRefIdAdapter::getData (const RefIdColumn *column, const Re if (column==mColumns.mAttributes || column==mColumns.mSkills) { if ((record.get().mFlags & ESM::NPC::Autocalc) != 0) - return QVariant(); + return QVariant(QVariant::UserType); else return true; } @@ -805,10 +805,10 @@ QVariant CSMWorld::NpcMiscRefIdAdapter::getNestedData (const RefIdColumn *column switch (subColIndex) { case 0: return static_cast(record.get().mNpdt12.mLevel); - case 1: return QVariant(); - case 2: return QVariant(); - case 3: return QVariant(); - case 4: return QVariant(); + case 1: return QVariant(QVariant::UserType); + case 2: return QVariant(QVariant::UserType); + case 3: return QVariant(QVariant::UserType); + case 4: return QVariant(QVariant::UserType); case 5: return static_cast(record.get().mNpdt12.mDisposition); case 6: return static_cast(record.get().mNpdt12.mReputation); case 7: return static_cast(record.get().mNpdt12.mRank); diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index 143b46c44..3411429d0 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -1976,7 +1976,7 @@ namespace CSMWorld { switch (subColIndex) { - case 0: return QVariant(); // don't allow checkbox editor to be created + case 0: return QVariant(QVariant::UserType); // disable the checkbox editor case 1: return record.get().mFlags & ESM::CreatureLevList::AllLevels; case 2: return static_cast (record.get().mChanceNone); default: diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index fee302e2c..0a5eb5202 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -461,7 +461,14 @@ void CSVWorld::EditWidget::remake(int row) NestedTable* table = new NestedTable(mDocument, id, mNestedModels.back(), this); // FIXME: does not work well when enum delegates are used //table->resizeColumnsToContents(); - table->setEditTriggers(QAbstractItemView::SelectedClicked | QAbstractItemView::CurrentChanged); + + if(mTable->index(row, i).data().type() == QVariant::UserType) + { + table->setEditTriggers(QAbstractItemView::NoEditTriggers); + table->setEnabled(false); + } + else + table->setEditTriggers(QAbstractItemView::SelectedClicked | QAbstractItemView::CurrentChanged); int rows = mTable->rowCount(mTable->index(row, i)); int rowHeight = (rows == 0) ? table->horizontalHeader()->height() : table->rowHeight(0); @@ -473,6 +480,8 @@ void CSVWorld::EditWidget::remake(int row) new QLabel (mTable->headerData (i, Qt::Horizontal, Qt::DisplayRole).toString(), mMainWidget); label->setSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed); + if(mTable->index(row, i).data().type() == QVariant::UserType) + label->setEnabled(false); tablesLayout->addWidget(label); tablesLayout->addWidget(table); @@ -503,6 +512,12 @@ void CSVWorld::EditWidget::remake(int row) unlockedLayout->addWidget (editor, unlocked, 1); ++unlocked; } + + if(mTable->index(row, i).data().type() == QVariant::UserType) + { + editor->setEnabled(false); + label->setEnabled(false); + } } } else @@ -550,6 +565,12 @@ void CSVWorld::EditWidget::remake(int row) unlockedLayout->addWidget (label, unlocked, 0); unlockedLayout->addWidget (editor, unlocked, 1); ++unlocked; + + if(mNestedModels.back()->index(0, col).data().type() == QVariant::UserType) + { + editor->setEnabled(false); + label->setEnabled(false); + } } } mNestedTableMapper->setCurrentModelIndex(mNestedModels.back()->index(0, 0)); From 8f8fdedcde09552f79114357d78ed3bda2f2eba7 Mon Sep 17 00:00:00 2001 From: Nicola Bodill Date: Thu, 21 May 2015 14:20:35 +1000 Subject: [PATCH 1223/3725] Some more edits Responding to sirherrbatka's feedback. --- manual/opencs/files_and_directories.tex | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/manual/opencs/files_and_directories.tex b/manual/opencs/files_and_directories.tex index 1b07fe267..55d3011b4 100644 --- a/manual/opencs/files_and_directories.tex +++ b/manual/opencs/files_and_directories.tex @@ -1,8 +1,8 @@ \section{Files and Directories} \subsection{Introduction} -This section of the manual describes the directories and file types used by OpenCS. A file is a resource for storing data, identified by its -filename extension (e.g. .exe, .jpg, .txt), whereas a directory is a folder or file system structure in which these files are stored. You -are most likely already familiar with these concepts. +This section of the manual describes the directories and file types used by OpenCS. A file is a resource for storing data (e.g. .exe, .jpg, .txt), +whereas a directory is a folder or file system structure which points to these files (or other directories). You are most likely already familiar +with these concepts. \subsection{Used terms} %TODO @@ -15,7 +15,7 @@ files and several other folders. The location of the user directory is hard code %TODO list paths. In addition to the user directory, both \OMW{} and \OCS{} need a place to store the game’s actual data files: for example, the textures, models, sounds and records of in-game objects. We support multiple paths to these files (termed \textbf{data paths}), -as specified in the configuration. Usually, one data path points to the directory where \MW{} is installed, however, you are +as specified in the configuration. Usually, one data path points to the directory where \MW{} is installed; however, you are free to specify as many data paths as you would like. In addition, one particular data path, as described below, is used to store newly created content files. @@ -23,7 +23,7 @@ newly created content files. \BS{} \MW{} engine uses two file types: ESM (master) and ESP (plugin). The distinction between the two is often confusing. You would expect that the ESM (master) file is used to specify a single master which is modified by the ESP files (plugins), and indeed: this is the basic idea. However, the original expansions are also ESM files, even though they can be described as very large plugins. -There were technical reasons behind this decision -- somewhat valid in the case of the original engine, but a more logical file system is +There were technical reasons behind this decision -- somewhat valid in the case of the original engine -- but a more logical file system is much preferable. \OMW{} achieves this through the creation of our own types of content file. We support both ESM and ESP files, but, in order to make use of \OMW{}'s new features, one should consider using new file types designed @@ -42,9 +42,9 @@ Furthermore, our content files’ extensions are .omwaddon for addon files and . \subparagraph{\MW{} content files} Using our content files is the recommended solution for projects that employ the \OMW{} engine. However, some players will wish to use the original \MW{} engine, despite its large flaws and lacking features\footnote{If this is wrong, we are a very successful project. Yay!}. -In addition, since 2002 thousands of ESP/ESM files have been created, some with truly outstanding content. Because of this, \OCS{} is -committed to supporting ESP/ESM files. If you do decide to use ESP/ESM files rather than our own content files, you are most likely aiming -for original engine compatibility. This subject is covered in the very last section of the manual. +In addition, since 2002, thousands of ESP/ESM files have been created, some with truly outstanding content. Because of this, \OCS{} +will support ESP/ESM files, although this will impose limitations on the user. If you do decide to use ESP/ESM files rather than our own content +files, you are most likely aiming for original engine compatibility. This subject is covered in the very last section of the manual. %not finished TODO add the said section. Most likely when more features are present. The actual creation of new files is described in the next chapter. Here we are going to focus only on the essential information needed From 9767910f0615e8c5f68502798f1aae0a55bc420b Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 21 May 2015 17:51:20 +0200 Subject: [PATCH 1224/3725] updated credits file --- AUTHORS.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/AUTHORS.md b/AUTHORS.md index 4fef9233a..fb83a1a91 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -110,6 +110,12 @@ Programmers Vincent Heuken vocollapse +Manual +------ + + Bodillium + sir_herrbatka + Packagers --------- From 6031db78825df365327d1e4af012576625c115b3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 21 May 2015 21:04:48 +0200 Subject: [PATCH 1225/3725] Character sliding fix --- apps/openmw/mwphysics/physicssystem.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 04b53a8e3..db34e0411 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -176,7 +176,8 @@ namespace MWPhysics static inline osg::Vec3f reflect(const osg::Vec3& velocity, const osg::Vec3f& normal) { - return (normal * (normal * velocity)) * 2 - velocity; + return velocity - (normal * (normal * velocity)) * 2; + // ^ dot product } From aecd9a275e34d5e539e90713ca0e4158220f526d Mon Sep 17 00:00:00 2001 From: cc9cii Date: Fri, 22 May 2015 06:09:55 +1000 Subject: [PATCH 1226/3725] Remove debugging comments. --- apps/opencs/model/world/refidadapterimp.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index ee045afd0..0bb565e51 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -721,8 +721,7 @@ QVariant CSMWorld::NpcSkillsRefIdAdapter::getNestedData (const RefIdColumn *colu const ESM::NPC::NPDTstruct52& npcStruct = record.get().mNpdt52; if (subRowIndex < 0 || subRowIndex >= ESM::Skill::Length) - std::cout << "getNestedDatat index" << std::endl; - //throw std::runtime_error ("index out of range"); + throw std::runtime_error ("index out of range"); if (subColIndex == 0) return QString(ESM::Skill::sSkillNames[subRowIndex].c_str()); @@ -741,8 +740,7 @@ void CSMWorld::NpcSkillsRefIdAdapter::setNestedData (const RefIdColumn *column, ESM::NPC::NPDTstruct52& npcStruct = npc.mNpdt52; if (subRowIndex < 0 || subRowIndex >= ESM::Skill::Length) - std::cout << "setNestedDatat index" << std::endl; - //throw std::runtime_error ("index out of range"); + throw std::runtime_error ("index out of range"); if (subColIndex == 1) npcStruct.mSkills[subRowIndex] = static_cast(value.toInt()); From 0fb97bd2e7ace6656ab975999ee35d3b67d137d9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 21 May 2015 23:24:22 +0200 Subject: [PATCH 1227/3725] Readded baseonly parameter to Animation::setObjectRoot Fixes the first person view. --- apps/openmw/mwrender/animation.cpp | 44 +++++++++++++++++++++- apps/openmw/mwrender/animation.hpp | 4 +- apps/openmw/mwrender/creatureanimation.cpp | 4 +- apps/openmw/mwrender/npcanimation.cpp | 2 +- 4 files changed, 48 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 3a0f543d9..df6d6e9f2 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include @@ -167,6 +168,38 @@ namespace return 0.0f; } + + + // Removes all drawables from a graph. + class RemoveDrawableVisitor : public osg::NodeVisitor + { + public: + RemoveDrawableVisitor() + : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) + { + } + + virtual void apply(osg::Geode &node) + { + // Not safe to remove in apply(), since the visitor is still iterating the child list + mToRemove.push_back(&node); + traverse(node); + } + + void remove() + { + for (std::vector::iterator it = mToRemove.begin(); it != mToRemove.end(); ++it) + { + osg::Node* node = *it; + if (node->getNumParents()) + node->getParent(0)->removeChild(node); + } + } + + private: + std::vector mToRemove; + }; + } namespace MWRender @@ -836,7 +869,7 @@ namespace MWRender return movement; } - void Animation::setObjectRoot(const std::string &model, bool forceskeleton) + void Animation::setObjectRoot(const std::string &model, bool forceskeleton, bool baseonly) { if (mObjectRoot) { @@ -864,6 +897,13 @@ namespace MWRender mObjectRoot = newObjectRoot; } + if (baseonly) + { + RemoveDrawableVisitor removeDrawableVisitor; + mObjectRoot->accept(removeDrawableVisitor); + removeDrawableVisitor.remove(); + } + NodeMapVisitor visitor; mObjectRoot->accept(visitor); mNodeMap = visitor.getNodeMap(); @@ -1130,7 +1170,7 @@ namespace MWRender { if (!model.empty()) { - setObjectRoot(model, false); + setObjectRoot(model, false, false); if (!ptr.getClass().getEnchantment(ptr).empty()) addGlow(mObjectRoot, getEnchantmentColor(ptr)); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 0c490b525..119814135 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -230,8 +230,10 @@ protected: * Note that you must make sure all animation sources are cleared before reseting the object * root. All nodes previously retrieved with getNode will also become invalidated. * @param forceskeleton Wrap the object root in a Skeleton, even if it contains no skinned parts. Use this if you intend to add skinned parts manually. + * @param baseonly If true, then any meshes or particle systems in the model are ignored + * (useful for NPCs, where only the skeleton is needed for the root, and the actual NPC parts are then assembled from separate files). */ - void setObjectRoot(const std::string &model, bool forceskeleton); + void setObjectRoot(const std::string &model, bool forceskeleton, bool baseonly); /* Adds the keyframe controllers in the specified model as a new animation source. Note that * the filename portion of the provided model name will be prepended with 'x', and the .nif diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index 25d9e9e47..e15dee532 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -23,7 +23,7 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr, if(!model.empty()) { - setObjectRoot(model, false /* , baseonly = false */); + setObjectRoot(model, false, false); //setRenderProperties(mObjectRoot, RV_Actors, RQG_Main, RQG_Alpha); if((ref->mBase->mFlags&ESM::Creature::Bipedal)) @@ -42,7 +42,7 @@ CreatureWeaponAnimation::CreatureWeaponAnimation(const MWWorld::Ptr &ptr, const if(!model.empty()) { - setObjectRoot(model, true /* , baseonly = false*/); + setObjectRoot(model, true, false); //setRenderProperties(mObjectRoot, RV_Actors, RQG_Main, RQG_Alpha); if((ref->mBase->mFlags&ESM::Creature::Bipedal)) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index b23a72e55..5fafa6d59 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -299,7 +299,7 @@ void NpcAnimation::updateNpcBase() : "meshes\\wolf\\skin.1st.nif"); smodel = Misc::ResourceHelpers::correctActorModelPath(smodel, mResourceSystem->getVFS()); - setObjectRoot(smodel, true /*, baseonly = true*/); + setObjectRoot(smodel, true, true); if(mViewMode != VM_FirstPerson) { From d27b92e9f1b093798cbe2404ed0b998c8f3b750f Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Fri, 22 May 2015 00:57:47 +0300 Subject: [PATCH 1228/3725] Avoid gaps between local indexes in RefIdData after removal of records (Fix #2545) --- apps/opencs/model/world/refiddata.cpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/world/refiddata.cpp b/apps/opencs/model/world/refiddata.cpp index f67ab2152..7f5c25f36 100644 --- a/apps/opencs/model/world/refiddata.cpp +++ b/apps/opencs/model/world/refiddata.cpp @@ -176,7 +176,6 @@ void CSMWorld::RefIdData::erase (const LocalIndex& index, int count) { std::map::iterator iter = mRecordContainers.find (index.second); - if (iter==mRecordContainers.end()) throw std::logic_error ("invalid local index type"); @@ -189,6 +188,20 @@ void CSMWorld::RefIdData::erase (const LocalIndex& index, int count) mIndex.erase (result); } + // Adjust the local indexes to avoid gaps between them after removal of records + int recordIndex = index.first + count; + int recordCount = iter->second->getSize(); + while (recordIndex < recordCount) + { + std::map::iterator recordIndexFound = + mIndex.find(Misc::StringUtils::lowerCase(iter->second->getId(recordIndex))); + if (recordIndexFound != mIndex.end()) + { + recordIndexFound->second.first -= count; + } + ++recordIndex; + } + iter->second->erase (index.first, count); } From 9b8e2e9db3bb205175215b02ce0d9c740ae2b8a3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 21 May 2015 23:54:39 +0200 Subject: [PATCH 1229/3725] Port MWRender::Camera --- apps/openmw/CMakeLists.txt | 3 +- apps/openmw/engine.cpp | 3 - apps/openmw/mwrender/animation.cpp | 5 + apps/openmw/mwrender/animation.hpp | 2 + apps/openmw/mwrender/camera.cpp | 222 +++++++++++----------- apps/openmw/mwrender/camera.hpp | 39 ++-- apps/openmw/mwrender/renderingmanager.cpp | 111 ++++++++++- apps/openmw/mwrender/renderingmanager.hpp | 20 +- apps/openmw/mwworld/scene.cpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 61 +++++- apps/openmw/mwworld/worldimp.hpp | 28 +-- 11 files changed, 326 insertions(+), 170 deletions(-) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 9fa5e38a2..941222b0c 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -22,8 +22,7 @@ source_group(game FILES ${GAME} ${GAME_HEADER}) add_openmw_dir (mwrender actors objects renderingmanager animation sky npcanimation vismask creatureanimation effectmanager util renderinginterface pathgrid rendermode - bulletdebugdraw globalmap characterpreview -# camera + bulletdebugdraw globalmap characterpreview camera # localmap occlusionquery water shadows # ripplesimulation refraction # terrainstorage weaponanimation diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index ca21e3612..5ce1607b5 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -5,7 +5,6 @@ #include -#include #include #include @@ -592,8 +591,6 @@ void OMW::Engine::go() } // Start the main rendering loop - mViewer->setCameraManipulator(new osgGA::TrackballManipulator); - osg::Timer frameTimer; while (!mViewer->done() && !MWBase::Environment::get().getStateManager()->hasQuitRequest()) { diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index df6d6e9f2..416f66cec 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -249,6 +249,11 @@ namespace MWRender mInsert->removeChild(mObjectRoot); } + MWWorld::Ptr Animation::getPtr() + { + return mPtr; + } + void Animation::setActive(bool active) { if (SceneUtil::Skeleton* skel = dynamic_cast(mObjectRoot.get())) diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 119814135..82b54bdea 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -254,6 +254,8 @@ public: Animation(const MWWorld::Ptr &ptr, osg::ref_ptr parentNode, Resource::ResourceSystem* resourceSystem); virtual ~Animation(); + MWWorld::Ptr getPtr(); + /// Set active flag on the object skeleton, if one exists. /// @see SceneUtil::Skeleton::setActive void setActive(bool active); diff --git a/apps/openmw/mwrender/camera.cpp b/apps/openmw/mwrender/camera.cpp index c7a27dfe8..a92f90158 100644 --- a/apps/openmw/mwrender/camera.cpp +++ b/apps/openmw/mwrender/camera.cpp @@ -1,9 +1,6 @@ #include "camera.hpp" -#include -#include -#include -#include +#include #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" @@ -13,12 +10,38 @@ #include "npcanimation.hpp" +namespace +{ + +class UpdateCameraCallback : public osg::NodeCallback +{ +public: + UpdateCameraCallback(MWRender::Camera* cam) + : mCamera(cam) + { + } + + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) + { + osg::Camera* cam = static_cast(node); + + // traverse first to update animations, in case the camera is attached to an animated node + traverse(node, nv); + + mCamera->updateCamera(cam); + } + +private: + MWRender::Camera* mCamera; +}; + +} + namespace MWRender { - Camera::Camera (Ogre::Camera *camera) + + Camera::Camera (osg::Camera* camera) : mCamera(camera), - mCameraNode(NULL), - mCameraPosNode(NULL), mAnimation(NULL), mFirstPersonView(true), mPreviewMode(false), @@ -27,10 +50,11 @@ namespace MWRender mFurthest(800.f), mIsNearest(false), mHeight(124.f), - mCameraDistance(192.f), + mMaxCameraDistance(192.f), mDistanceAdjusted(false), mVanityToggleQueued(false), - mViewModeToggleQueued(false) + mViewModeToggleQueued(false), + mCameraDistance(0.f) { mVanity.enabled = false; mVanity.allowed = true; @@ -41,82 +65,70 @@ namespace MWRender mMainCam.pitch = 0.f; mMainCam.yaw = 0.f; mMainCam.offset = 400.f; + + mUpdateCallback = new UpdateCameraCallback(this); + mCamera->addUpdateCallback(mUpdateCallback); } Camera::~Camera() { + mCamera->removeUpdateCallback(mUpdateCallback); } - void Camera::reset() + MWWorld::Ptr Camera::getTrackingPtr() const { - togglePreviewMode(false); - toggleVanityMode(false); - if (!mFirstPersonView) - toggleViewMode(); + return mTrackingPtr; } - void Camera::rotateCamera(const Ogre::Vector3 &rot, bool adjust) + void Camera::updateCamera(osg::Camera *cam) { - if (adjust) { - setYaw(getYaw() + rot.z); - setPitch(getPitch() + rot.x); - } else { - setYaw(rot.z); - setPitch(rot.x); - } + if (mTrackingPtr.isEmpty()) + return; + const osg::Node* trackNode = mTrackingNode; + if (!trackNode) + return; + osg::MatrixList mats = trackNode->getWorldMatrices(); + if (!mats.size()) + return; + const osg::Matrix& worldMat = mats[0]; - Ogre::Quaternion xr(Ogre::Radian(getPitch() + Ogre::Math::HALF_PI), Ogre::Vector3::UNIT_X); - Ogre::Quaternion orient = xr; - if (mVanity.enabled || mPreviewMode) { - Ogre::Quaternion zr(Ogre::Radian(getYaw()), Ogre::Vector3::UNIT_Z); - orient = zr * xr; - } + osg::Vec3 position = worldMat.getTrans(); + if (!isFirstPerson()) + position.z() += mHeight; - if (isFirstPerson()) - mCamera->getParentNode()->setOrientation(orient); - else - mCameraNode->setOrientation(orient); + osg::Quat orient = osg::Quat(getPitch(), osg::Vec3(1,0,0)) * osg::Quat(getYaw(), osg::Vec3(0,0,1)); + + osg::Vec3 offset = orient * osg::Vec3(0, -mCameraDistance, 0); + position += offset; + + osg::Vec3 forward = orient * osg::Vec3(0,1,0); + osg::Vec3 up = orient * osg::Vec3(0,0,1); + + cam->setViewMatrixAsLookAt(position, position + forward, up); } - const std::string &Camera::getHandle() const + void Camera::reset() { - return mTrackingPtr.getRefData().getHandle(); + togglePreviewMode(false); + toggleVanityMode(false); + if (!mFirstPersonView) + toggleViewMode(); } - Ogre::SceneNode* Camera::attachTo(const MWWorld::Ptr &ptr) + void Camera::rotateCamera(float pitch, float yaw, bool adjust) { - mTrackingPtr = ptr; - Ogre::SceneNode *node = mTrackingPtr.getRefData().getBaseNode()->createChildSceneNode(Ogre::Vector3(0.0f, 0.0f, mHeight)); - node->setInheritScale(false); - Ogre::SceneNode *posNode = node->createChildSceneNode(); - posNode->setInheritScale(false); - if(mCameraNode) + if (adjust) { - node->setOrientation(mCameraNode->getOrientation()); - posNode->setPosition(mCameraPosNode->getPosition()); - mCameraNode->getCreator()->destroySceneNode(mCameraNode); - mCameraNode->getCreator()->destroySceneNode(mCameraPosNode); + pitch += getPitch(); + yaw += getYaw(); } - mCameraNode = node; - mCameraPosNode = posNode; - - if (!isFirstPerson()) - { - mCamera->detachFromParent(); - mCameraPosNode->attachObject(mCamera); - } - - return mCameraPosNode; + setYaw(yaw); + setPitch(pitch); } - void Camera::setPosition(const Ogre::Vector3& position) + void Camera::attachTo(const MWWorld::Ptr &ptr) { - mCameraPosNode->setPosition(position); - } - - void Camera::setPosition(float x, float y, float z) - { - setPosition(Ogre::Vector3(x,y,z)); + mTrackingPtr = ptr; } void Camera::update(float duration, bool paused) @@ -147,9 +159,7 @@ namespace MWRender if(mVanity.enabled) { - Ogre::Vector3 rot(0.f, 0.f, 0.f); - rot.z = Ogre::Degree(3.f * duration).valueRadians(); - rotateCamera(rot, true); + rotateCamera(0.f, osg::DegreesToRadians(3.f * duration), true); } } @@ -169,9 +179,9 @@ namespace MWRender processViewChange(); if (mFirstPersonView) { - setPosition(0.f, 0.f, 0.f); + mCameraDistance = 0.f; } else { - setPosition(0.f, 0.f, mCameraDistance); + mCameraDistance = mMaxCameraDistance; } } @@ -202,18 +212,15 @@ namespace MWRender processViewChange(); float offset = mPreviewCam.offset; - Ogre::Vector3 rot(0.f, 0.f, 0.f); + if (mVanity.enabled) { - rot.x = Ogre::Degree(-30.f).valueRadians(); - mMainCam.offset = mCameraPosNode->getPosition().z; + setPitch(osg::DegreesToRadians(-30.f)); + mMainCam.offset = mCameraDistance; } else { - rot.x = getPitch(); offset = mMainCam.offset; } - rot.z = getYaw(); - setPosition(0.f, 0.f, offset); - rotateCamera(rot, false); + mCameraDistance = offset; return true; } @@ -229,7 +236,7 @@ namespace MWRender mPreviewMode = enable; processViewChange(); - float offset = mCameraPosNode->getPosition().z; + float offset = mCameraDistance; if (mPreviewMode) { mMainCam.offset = offset; offset = mPreviewCam.offset; @@ -238,13 +245,12 @@ namespace MWRender offset = mMainCam.offset; } - setPosition(0.f, 0.f, offset); + mCameraDistance = offset; } void Camera::setSneakOffset(float offset) { - if(mAnimation) - mAnimation->addFirstPersonOffset(Ogre::Vector3(0.f, 0.f, -offset)); + // TODO: implement } float Camera::getYaw() @@ -256,10 +262,10 @@ namespace MWRender void Camera::setYaw(float angle) { - if (angle > Ogre::Math::PI) { - angle -= Ogre::Math::TWO_PI; - } else if (angle < -Ogre::Math::PI) { - angle += Ogre::Math::TWO_PI; + if (angle > osg::PI) { + angle -= osg::PI*2; + } else if (angle < -osg::PI) { + angle += osg::PI*2; } if (mVanity.enabled || mPreviewMode) { mPreviewCam.yaw = angle; @@ -279,7 +285,7 @@ namespace MWRender void Camera::setPitch(float angle) { const float epsilon = 0.000001f; - float limit = Ogre::Math::HALF_PI - epsilon; + float limit = osg::PI_2 - epsilon; if(mPreviewMode) limit /= 2; @@ -297,7 +303,7 @@ namespace MWRender float Camera::getCameraDistance() const { - return mCameraPosNode->getPosition().z; + return mCameraDistance; } void Camera::setCameraDistance(float dist, bool adjust, bool override) @@ -307,25 +313,24 @@ namespace MWRender mIsNearest = false; - Ogre::Vector3 v(0.f, 0.f, dist); - if (adjust) { - v += mCameraPosNode->getPosition(); - } - if (v.z >= mFurthest) { - v.z = mFurthest; - } else if (!override && v.z < 10.f) { - v.z = 10.f; - } else if (override && v.z <= mNearest) { - v.z = mNearest; + if (adjust) + dist += mCameraDistance; + + if (dist >= mFurthest) { + dist = mFurthest; + } else if (!override && dist < 10.f) { + dist = -10.f; + } else if (override && dist <= mNearest) { + dist = -mNearest; mIsNearest = true; } - setPosition(v); + mCameraDistance = dist; if (override) { if (mVanity.enabled || mPreviewMode) { - mPreviewCam.offset = v.z; + mPreviewCam.offset = mCameraDistance; } else if (!mFirstPersonView) { - mCameraDistance = v.z; + mMaxCameraDistance = mCameraDistance; } } else { mDistanceAdjusted = true; @@ -336,9 +341,9 @@ namespace MWRender { if (mDistanceAdjusted) { if (mVanity.enabled || mPreviewMode) { - setPosition(0, 0, mPreviewCam.offset); + mCameraDistance = mPreviewCam.offset; } else if (!mFirstPersonView) { - setPosition(0, 0, mCameraDistance); + mCameraDistance = mMaxCameraDistance; } } mDistanceAdjusted = false; @@ -351,7 +356,6 @@ namespace MWRender if(mAnimation && mAnimation != anim) { mAnimation->setViewMode(NpcAnimation::VM_Normal); - mAnimation->detachObjectFromBone(mCamera); } mAnimation = anim; @@ -360,29 +364,25 @@ namespace MWRender void Camera::processViewChange() { - mAnimation->detachObjectFromBone(mCamera); - mCamera->detachFromParent(); - if(isFirstPerson()) { mAnimation->setViewMode(NpcAnimation::VM_FirstPerson); - Ogre::TagPoint *tag = mAnimation->attachObjectToBone("Head", mCamera); - tag->setInheritOrientation(false); + mTrackingNode = mAnimation->getNode("Head"); } else { mAnimation->setViewMode(NpcAnimation::VM_Normal); - mCameraPosNode->attachObject(mCamera); + mTrackingNode = mTrackingPtr.getRefData().getBaseNode(); } - rotateCamera(Ogre::Vector3(getPitch(), 0.f, getYaw()), false); + rotateCamera(getPitch(), getYaw(), false); } - void Camera::getPosition(Ogre::Vector3 &focal, Ogre::Vector3 &camera) + void Camera::getPosition(osg::Vec3 &focal, osg::Vec3 &camera) { - mCamera->getParentSceneNode()->needUpdate(true); + //mCamera->getParentSceneNode()->needUpdate(true); - camera = mCamera->getRealPosition(); - focal = mCameraNode->_getDerivedPosition(); + //camera = mCamera->getRealPosition(); + //focal = mCameraNode->_getDerivedPosition(); } void Camera::togglePlayerLooking(bool enable) diff --git a/apps/openmw/mwrender/camera.hpp b/apps/openmw/mwrender/camera.hpp index 691a80862..68f0870d7 100644 --- a/apps/openmw/mwrender/camera.hpp +++ b/apps/openmw/mwrender/camera.hpp @@ -3,13 +3,16 @@ #include +#include +#include + #include "../mwworld/ptr.hpp" -namespace Ogre +namespace osg { - class Vector3; class Camera; - class SceneNode; + class NodeCallback; + class Node; } namespace MWRender @@ -24,10 +27,9 @@ namespace MWRender }; MWWorld::Ptr mTrackingPtr; + osg::ref_ptr mTrackingNode; - Ogre::Camera *mCamera; - Ogre::SceneNode *mCameraNode; - Ogre::SceneNode *mCameraPosNode; + osg::ref_ptr mCamera; NpcAnimation *mAnimation; @@ -42,7 +44,7 @@ namespace MWRender bool enabled, allowed; } mVanity; - float mHeight, mCameraDistance; + float mHeight, mMaxCameraDistance; CamData mMainCam, mPreviewCam; bool mDistanceAdjusted; @@ -50,19 +52,25 @@ namespace MWRender bool mVanityToggleQueued; bool mViewModeToggleQueued; - void setPosition(const Ogre::Vector3& position); - void setPosition(float x, float y, float z); + float mCameraDistance; + + osg::ref_ptr mUpdateCallback; public: - Camera(Ogre::Camera *camera); + Camera(osg::Camera* camera); ~Camera(); + MWWorld::Ptr getTrackingPtr() const; + + /// Update the view matrix of \a cam + void updateCamera(osg::Camera* cam); + /// Reset to defaults void reset(); /// Set where the camera is looking at. Uses Morrowind (euler) angles /// \param rot Rotation angles in radians - void rotateCamera(const Ogre::Vector3 &rot, bool adjust); + void rotateCamera(float pitch, float yaw, bool adjust); float getYaw(); void setYaw(float angle); @@ -70,10 +78,8 @@ namespace MWRender float getPitch(); void setPitch(float angle); - const std::string &getHandle() const; - /// Attach camera to object - Ogre::SceneNode* attachTo(const MWWorld::Ptr &); + void attachTo(const MWWorld::Ptr &); /// @param Force view mode switch, even if currently not allowed by the animation. void toggleViewMode(bool force=false); @@ -85,9 +91,6 @@ namespace MWRender void togglePreviewMode(bool enable); /// \brief Lowers the camera for sneak. - /// As animation is tied to the camera, this needs - /// to be set each frame after the animation is - /// applied. void setSneakOffset(float offset); bool isFirstPerson() const @@ -111,7 +114,7 @@ namespace MWRender void setAnimation(NpcAnimation *anim); /// Stores focal and camera world positions in passed arguments - void getPosition(Ogre::Vector3 &focal, Ogre::Vector3 &camera); + void getPosition(osg::Vec3 &focal, osg::Vec3 &camera); void togglePlayerLooking(bool enable); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 5ece10dc1..bbff16a10 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -31,6 +31,7 @@ #include "npcanimation.hpp" #include "vismask.hpp" #include "pathgrid.hpp" +#include "camera.hpp" namespace MWRender { @@ -104,6 +105,8 @@ namespace MWRender mEffectManager.reset(new EffectManager(mRootNode, mResourceSystem)); + mCamera.reset(new Camera(mViewer->getCamera())); + mViewer->setLightingMode(osgViewer::View::NO_LIGHT); osg::ref_ptr source = new osg::LightSource; @@ -253,11 +256,21 @@ namespace MWRender mSky->update(dt); } + void RenderingManager::updatePlayerPtr(const MWWorld::Ptr &ptr) + { + if(mPlayerAnimation.get()) + mPlayerAnimation->updatePtr(ptr); + + mCamera->attachTo(ptr); + } + void RenderingManager::rotateObject(const MWWorld::Ptr &ptr, const osg::Quat& rot) { - //if(ptr.getRefData().getHandle() == mCamera->getHandle() && - // !mCamera->isVanityOrPreviewModeEnabled()) - // mCamera->rotateCamera(-rot, false); + if(ptr == mCamera->getTrackingPtr() && + !mCamera->isVanityOrPreviewModeEnabled()) + { + mCamera->rotateCamera(-ptr.getRefData().getPosition().rot[0], -ptr.getRefData().getPosition().rot[2], false); + } ptr.getRefData().getBaseNode()->setAttitude(rot); } @@ -321,11 +334,30 @@ namespace MWRender { mPlayerAnimation.reset(new NpcAnimation(player, player.getRefData().getBaseNode(), mResourceSystem, 0)); - //mCamera->setAnimation(mPlayerAnimation); + mCamera->setAnimation(mPlayerAnimation.get()); + mCamera->attachTo(player); //mWater->removeEmitter(ptr); //mWater->addEmitter(ptr); } + void RenderingManager::rebuildPtr(const MWWorld::Ptr &ptr) + { + NpcAnimation *anim = NULL; + if(ptr == mPlayerAnimation->getPtr()) + anim = mPlayerAnimation.get(); + else + anim = dynamic_cast(mObjects->getAnimation(ptr)); + if(anim) + { + anim->rebuild(); + if(mCamera->getTrackingPtr() == ptr) + { + mCamera->attachTo(ptr); + mCamera->setAnimation(anim); + } + } + } + void RenderingManager::updateProjectionMatrix() { double fovy, aspect, zNear, zFar; @@ -370,4 +402,75 @@ namespace MWRender } } + bool RenderingManager::vanityRotateCamera(const float *rot) + { + if(!mCamera->isVanityOrPreviewModeEnabled()) + return false; + + mCamera->rotateCamera(rot[0], rot[2], true); + return true; + } + + void RenderingManager::setCameraDistance(float dist, bool adjust, bool override) + { + if(!mCamera->isVanityOrPreviewModeEnabled() && !mCamera->isFirstPerson()) + { + if(mCamera->isNearest() && dist > 0.f) + mCamera->toggleViewMode(); + else + mCamera->setCameraDistance(-dist / 120.f * 10, adjust, override); + } + else if(mCamera->isFirstPerson() && dist < 0.f) + { + mCamera->toggleViewMode(); + mCamera->setCameraDistance(0.f, false, override); + } + } + + void RenderingManager::resetCamera() + { + mCamera->reset(); + } + + float RenderingManager::getCameraDistance() const + { + return mCamera->getCameraDistance(); + } + + Camera* RenderingManager::getCamera() + { + return mCamera.get(); + } + + void RenderingManager::togglePOV() + { + mCamera->toggleViewMode(); + } + + void RenderingManager::togglePreviewMode(bool enable) + { + mCamera->togglePreviewMode(enable); + } + + bool RenderingManager::toggleVanityMode(bool enable) + { + return mCamera->toggleVanityMode(enable); + } + + void RenderingManager::allowVanityMode(bool allow) + { + mCamera->allowVanityMode(allow); + } + + void RenderingManager::togglePlayerLooking(bool enable) + { + mCamera->togglePlayerLooking(enable); + } + + void RenderingManager::changeVanityModeScale(float factor) + { + if(mCamera->isVanityOrPreviewModeEnabled()) + mCamera->setCameraDistance(-factor/120.f*10, true, true); + } + } diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 32e081995..bb04d04e1 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -41,6 +41,7 @@ namespace MWRender class SkyManager; class NpcAnimation; class Pathgrid; + class Camera; class RenderingManager : public MWRender::RenderingInterface { @@ -66,7 +67,6 @@ namespace MWRender void updatePtr(const MWWorld::Ptr& old, const MWWorld::Ptr& updated); - // TODO rename to setRotation/setPosition/setScale, along with the World equivalents void rotateObject(const MWWorld::Ptr& ptr, const osg::Quat& rot); void moveObject(const MWWorld::Ptr& ptr, const osg::Vec3f& pos); void scaleObject(const MWWorld::Ptr& ptr, const osg::Vec3f& scale); @@ -92,11 +92,28 @@ namespace MWRender Animation* getAnimation(const MWWorld::Ptr& ptr); Animation* getPlayerAnimation(); + void updatePlayerPtr(const MWWorld::Ptr &ptr); + void setupPlayer(const MWWorld::Ptr& player); void renderPlayer(const MWWorld::Ptr& player); + void rebuildPtr(const MWWorld::Ptr& ptr); + void processChangedSettings(const Settings::CategorySettingVector& settings); + // camera stuff + bool vanityRotateCamera(const float *rot); + void setCameraDistance(float dist, bool adjust, bool override); + void resetCamera(); + float getCameraDistance() const; + Camera* getCamera(); + void togglePOV(); + void togglePreviewMode(bool enable); + bool toggleVanityMode(bool enable); + void allowVanityMode(bool allow); + void togglePlayerLooking(bool enable); + void changeVanityModeScale(float factor); + private: void updateProjectionMatrix(); void updateTextureFiltering(); @@ -114,6 +131,7 @@ namespace MWRender std::auto_ptr mEffectManager; std::auto_ptr mPlayerAnimation; osg::ref_ptr mPlayerNode; + std::auto_ptr mCamera; osg::ref_ptr mStateUpdater; diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index d087a40d8..fd63146f2 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -406,7 +406,7 @@ namespace MWWorld world->getPlayer().setCell(cell); MWWorld::Ptr player = world->getPlayerPtr(); - //mRendering.updatePlayerPtr(player); + mRendering.updatePlayerPtr(player); if (adjustPlayerPos) { world->moveObject(player, pos.pos[0], pos.pos[1], pos.pos[2]); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 91484a6ba..110ed61be 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -37,6 +37,7 @@ //#include "../mwrender/animation.hpp" #include "../mwrender/renderingmanager.hpp" +#include "../mwrender/camera.hpp" #include "../mwscript/interpretercontext.hpp" #include "../mwscript/globalscripts.hpp" @@ -211,7 +212,7 @@ namespace MWWorld setupPlayer(); renderPlayer(); - //mRendering->resetCamera(); + mRendering->resetCamera(); MWBase::Environment::get().getWindowManager()->updatePlayer(); @@ -531,7 +532,6 @@ namespace MWWorld void World::useDeathCamera() { -#if 0 if(mRendering->getCamera()->isVanityOrPreviewModeEnabled() ) { mRendering->getCamera()->togglePreviewMode(false); @@ -539,7 +539,6 @@ namespace MWWorld } if(mRendering->getCamera()->isFirstPerson()) mRendering->getCamera()->toggleViewMode(true); -#endif } MWWorld::Player& World::getPlayer() @@ -1479,7 +1478,7 @@ namespace MWWorld bool World::toggleCollisionMode() { - return 0;//mPhysics->toggleCollisionMode(); + return mPhysics->toggleCollisionMode(); } bool World::toggleRenderMode (MWRender::RenderMode mode) @@ -1607,7 +1606,16 @@ namespace MWWorld } */ - //mWorldScene->playerMoved(mRendering->getEyePos()); + // Sink the camera while sneaking + bool sneaking = getPlayerPtr().getClass().getCreatureStats(getPlayerPtr()).getStance(MWMechanics::CreatureStats::Stance_Sneak); + bool inair = !isOnGround(getPlayerPtr()); + bool swimming = isSwimming(getPlayerPtr()); + + static const float i1stPersonSneakDelta = getStore().get().find("i1stPersonSneakDelta")->getFloat(); + if(!paused && sneaking && !(swimming || inair)) + mRendering->getCamera()->setSneakOffset(i1stPersonSneakDelta); + else + mRendering->getCamera()->setSneakOffset(0.f); } void World::updateSoundListener() @@ -2091,14 +2099,49 @@ namespace MWWorld */ } + void World::togglePOV() + { + mRendering->togglePOV(); + } + + bool World::isFirstPerson() const + { + return mRendering->getCamera()->isFirstPerson(); + } + + void World::togglePreviewMode(bool enable) + { + mRendering->togglePreviewMode(enable); + } + + bool World::toggleVanityMode(bool enable) + { + return mRendering->toggleVanityMode(enable); + } + + void World::allowVanityMode(bool allow) + { + mRendering->allowVanityMode(allow); + } + + void World::togglePlayerLooking(bool enable) + { + mRendering->togglePlayerLooking(enable); + } + + void World::changeVanityModeScale(float factor) + { + mRendering->changeVanityModeScale(factor); + } + bool World::vanityRotateCamera(float * rot) { - return 0;//mRendering->vanityRotateCamera(rot); + return mRendering->vanityRotateCamera(rot); } void World::setCameraDistance(float dist, bool adjust, bool override_) { - //mRendering->setCameraDistance(dist, adjust, override_); + mRendering->setCameraDistance(dist, adjust, override_); } void World::setupPlayer() @@ -2509,7 +2552,7 @@ namespace MWWorld void World::reattachPlayerCamera() { - //mRendering->rebuildPtr(getPlayerPtr()); + mRendering->rebuildPtr(getPlayerPtr()); } void World::setWerewolf(const MWWorld::Ptr& actor, bool werewolf) @@ -2542,7 +2585,7 @@ namespace MWWorld // NpcAnimation::updateParts will already rebuild the animation when it detects change of Npc type. // the following is just for reattaching the camera properly. - //mRendering->rebuildPtr(actor); + mRendering->rebuildPtr(actor); if(actor == getPlayerPtr()) { diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 21ad2d7ef..67d4f863a 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -467,33 +467,19 @@ namespace MWWorld virtual bool isWading(const MWWorld::Ptr &object) const; virtual bool isOnGround(const MWWorld::Ptr &ptr) const; - virtual void togglePOV() { - //mRendering->togglePOV(); - } + virtual void togglePOV(); - virtual bool isFirstPerson() const { - return 0;//mRendering->getCamera()->isFirstPerson(); - } + virtual bool isFirstPerson() const; - virtual void togglePreviewMode(bool enable) { - //mRendering->togglePreviewMode(enable); - } + virtual void togglePreviewMode(bool enable); - virtual bool toggleVanityMode(bool enable) { - return 0;//mRendering->toggleVanityMode(enable); - } + virtual bool toggleVanityMode(bool enable); - virtual void allowVanityMode(bool allow) { - //mRendering->allowVanityMode(allow); - } + virtual void allowVanityMode(bool allow); - virtual void togglePlayerLooking(bool enable) { - //mRendering->togglePlayerLooking(enable); - } + virtual void togglePlayerLooking(bool enable); - virtual void changeVanityModeScale(float factor) { - //mRendering->changeVanityModeScale(factor); - } + virtual void changeVanityModeScale(float factor); virtual bool vanityRotateCamera(float * rot); virtual void setCameraDistance(float dist, bool adjust = false, bool override = true); From 2235d2978b2609db5c94f7e2ef0bfe7b81d77c4a Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 22 May 2015 00:55:43 +0200 Subject: [PATCH 1230/3725] Restore animation text key handling --- apps/openmw/mwmechanics/character.cpp | 141 ++++++++++++++++++++++ apps/openmw/mwmechanics/character.hpp | 7 +- apps/openmw/mwrender/animation.cpp | 9 +- apps/openmw/mwrender/animation.hpp | 11 ++ apps/openmw/mwrender/objects.cpp | 2 +- apps/openmw/mwrender/objects.hpp | 2 +- apps/openmw/mwrender/renderingmanager.cpp | 5 + apps/openmw/mwrender/renderingmanager.hpp | 2 + apps/openmw/mwworld/scene.cpp | 6 +- 9 files changed, 178 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 5769138fa..a89a06091 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -648,6 +648,8 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim if(!mAnimation) return; + mAnimation->setTextKeyListener(this); + const MWWorld::Class &cls = mPtr.getClass(); if(cls.isActor()) { @@ -698,8 +700,147 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim CharacterController::~CharacterController() { + if (mAnimation) + mAnimation->setTextKeyListener(NULL); +} + +void split(const std::string &s, char delim, std::vector &elems) { + std::stringstream ss(s); + std::string item; + while (std::getline(ss, item, delim)) { + elems.push_back(item); + } } +void CharacterController::handleTextKey(const std::string &groupname, const std::multimap::const_iterator &key, const std::multimap &map) +{ + const std::string &evt = key->second; + + if(evt.compare(0, 7, "sound: ") == 0) + { + MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); + sndMgr->playSound3D(mPtr, evt.substr(7), 1.0f, 1.0f); + return; + } + if(evt.compare(0, 10, "soundgen: ") == 0) + { + std::string soundgen = evt.substr(10); + + // The event can optionally contain volume and pitch modifiers + float volume=1.f, pitch=1.f; + if (soundgen.find(" ") != std::string::npos) + { + std::vector tokens; + split(soundgen, ' ', tokens); + soundgen = tokens[0]; + if (tokens.size() >= 2) + volume = Ogre::StringConverter::parseReal(tokens[1]); + if (tokens.size() >= 3) + pitch = Ogre::StringConverter::parseReal(tokens[2]); + } + + std::string sound = mPtr.getClass().getSoundIdFromSndGen(mPtr, soundgen); + if(!sound.empty()) + { + MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); + MWBase::SoundManager::PlayType type = MWBase::SoundManager::Play_TypeSfx; + if(evt.compare(10, evt.size()-10, "left") == 0 || evt.compare(10, evt.size()-10, "right") == 0 || evt.compare(10, evt.size()-10, "land") == 0) + type = MWBase::SoundManager::Play_TypeFoot; + sndMgr->playSound3D(mPtr, sound, volume, pitch, type); + } + return; + } + + if(evt.compare(0, groupname.size(), groupname) != 0 || + evt.compare(groupname.size(), 2, ": ") != 0) + { + // Not ours, skip it + return; + } + size_t off = groupname.size()+2; + size_t len = evt.size() - off; + + if(evt.compare(off, len, "equip attach") == 0) + mAnimation->showWeapons(true); + else if(evt.compare(off, len, "unequip detach") == 0) + mAnimation->showWeapons(false); + else if(evt.compare(off, len, "chop hit") == 0) + mPtr.getClass().hit(mPtr, ESM::Weapon::AT_Chop); + else if(evt.compare(off, len, "slash hit") == 0) + mPtr.getClass().hit(mPtr, ESM::Weapon::AT_Slash); + else if(evt.compare(off, len, "thrust hit") == 0) + mPtr.getClass().hit(mPtr, ESM::Weapon::AT_Thrust); + else if(evt.compare(off, len, "hit") == 0) + { + if (groupname == "attack1") + mPtr.getClass().hit(mPtr, ESM::Weapon::AT_Chop); + else if (groupname == "attack2") + mPtr.getClass().hit(mPtr, ESM::Weapon::AT_Slash); + else if (groupname == "attack3") + mPtr.getClass().hit(mPtr, ESM::Weapon::AT_Thrust); + else + mPtr.getClass().hit(mPtr); + } + else if (!groupname.empty() && groupname.compare(0, groupname.size()-1, "attack") == 0 + && evt.compare(off, len, "start") == 0) + { + std::multimap::const_iterator hitKey = key; + + // Not all animations have a hit key defined. If there is none, the hit happens with the start key. + bool hasHitKey = false; + while (hitKey != map.end()) + { + if (hitKey->second == groupname + ": hit") + { + hasHitKey = true; + break; + } + if (hitKey->second == groupname + ": stop") + break; + ++hitKey; + } + if (!hasHitKey) + { + if (groupname == "attack1") + mPtr.getClass().hit(mPtr, ESM::Weapon::AT_Chop); + else if (groupname == "attack2") + mPtr.getClass().hit(mPtr, ESM::Weapon::AT_Slash); + else if (groupname == "attack3") + mPtr.getClass().hit(mPtr, ESM::Weapon::AT_Thrust); + } + } + else if (evt.compare(off, len, "shoot attach") == 0) + mAnimation->attachArrow(); + else if (evt.compare(off, len, "shoot release") == 0) + {;}//mAnimation->releaseArrow(); + else if (evt.compare(off, len, "shoot follow attach") == 0) + mAnimation->attachArrow(); + + else if (groupname == "spellcast" && evt.substr(evt.size()-7, 7) == "release") + { + // Make sure this key is actually for the RangeType we are casting. The flame atronach has + // the same animation for all range types, so there are 3 "release" keys on the same time, one for each range type. + // FIXME: compare with mCurrentWeapon instead + const std::string& spellid = mPtr.getClass().getCreatureStats(mPtr).getSpells().getSelectedSpell(); + const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get().find(spellid); + const ESM::ENAMstruct &effectentry = spell->mEffects.mList.at(0); + int range = 0; + if (evt.compare(off, len, "self release") == 0) + range = 0; + else if (evt.compare(off, len, "touch release") == 0) + range = 1; + else if (evt.compare(off, len, "target release") == 0) + range = 2; + if (effectentry.mRange == range) + { + MWBase::Environment::get().getWorld()->castSpell(mPtr); + } + std::cout << "current attack: " << mCurrentWeapon << std::endl; + } + + else if (groupname == "shield" && evt.compare(off, len, "block hit") == 0) + mPtr.getClass().block(mPtr); +} void CharacterController::updatePtr(const MWWorld::Ptr &ptr) { diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 987a0d29a..2b2131061 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -7,6 +7,8 @@ #include "../mwworld/ptr.hpp" +#include "../mwrender/animation.hpp" + namespace MWWorld { class ContainerStoreIterator; @@ -134,7 +136,7 @@ enum JumpingState { JumpState_Landing }; -class CharacterController +class CharacterController : public MWRender::Animation::TextKeyListener { MWWorld::Ptr mPtr; MWRender::Animation *mAnimation; @@ -205,6 +207,9 @@ public: CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim); virtual ~CharacterController(); + virtual void handleTextKey(const std::string &groupname, const std::multimap::const_iterator &key, + const std::multimap& map); + // Be careful when to call this, see comment in Actors void updateContinuousVfx(); diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 416f66cec..e8d6bbcc9 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -238,6 +238,7 @@ namespace MWRender , mInsert(parentNode) , mResourceSystem(resourceSystem) , mAccumulate(1.f, 1.f, 0.f) + , mTextKeyListener(NULL) { for(size_t i = 0;i < sNumGroups;i++) mAnimationTimePtr[i].reset(new AnimationTime(this)); @@ -426,7 +427,8 @@ namespace MWRender else if(evt.compare(off, len, "loop stop") == 0) state.mLoopStopTime = key->first; - // TODO: forward to listener? + if (mTextKeyListener) + mTextKeyListener->handleTextKey(groupname, key, map); } void Animation::play(const std::string &groupname, int priority, int groups, bool autodisable, float speedmult, @@ -590,6 +592,11 @@ namespace MWRender return true; } + void Animation::setTextKeyListener(Animation::TextKeyListener *listener) + { + mTextKeyListener = listener; + } + void Animation::resetActiveGroups() { // remove all previous external controllers from the scene graph diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 82b54bdea..20fbbed5c 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -54,6 +54,15 @@ public: Group_All = Group_LowerBody | Group_UpperBody }; + class TextKeyListener + { + public: + virtual void handleTextKey(const std::string &groupname, const std::multimap::const_iterator &key, + const std::multimap& map) = 0; + }; + + void setTextKeyListener(TextKeyListener* listener); + protected: /* This is the number of *discrete* groups. */ static const size_t sNumGroups = 4; @@ -203,6 +212,8 @@ protected: std::vector mEffects; + TextKeyListener* mTextKeyListener; + /* Sets the appropriate animations on the bone groups based on priority. */ void resetActiveGroups(); diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 5face96a6..6c5709b5d 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -158,7 +158,7 @@ void Objects::insertNPC(const MWWorld::Ptr &ptr) mObjects.insert(std::make_pair(ptr, anim.release())); } -bool Objects::deleteObject (const MWWorld::Ptr& ptr) +bool Objects::removeObject (const MWWorld::Ptr& ptr) { if(!ptr.getRefData().getBaseNode()) return true; diff --git a/apps/openmw/mwrender/objects.hpp b/apps/openmw/mwrender/objects.hpp index 3e1af6087..298dc97bb 100644 --- a/apps/openmw/mwrender/objects.hpp +++ b/apps/openmw/mwrender/objects.hpp @@ -66,7 +66,7 @@ public: //Ogre::AxisAlignedBox getDimensions(MWWorld::CellStore*); ///< get a bounding box that encloses all objects in the specified cell - bool deleteObject (const MWWorld::Ptr& ptr); + bool removeObject (const MWWorld::Ptr& ptr); ///< \return found? void removeCell(const MWWorld::CellStore* store); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index bbff16a10..9b796a359 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -285,6 +285,11 @@ namespace MWRender ptr.getRefData().getBaseNode()->setScale(scale); } + void RenderingManager::removeObject(const MWWorld::Ptr &ptr) + { + mObjects->removeObject(ptr); + } + void RenderingManager::updatePtr(const MWWorld::Ptr &old, const MWWorld::Ptr &updated) { mObjects->updatePtr(old, updated); diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index bb04d04e1..8a81aacd7 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -71,6 +71,8 @@ namespace MWRender void moveObject(const MWWorld::Ptr& ptr, const osg::Vec3f& pos); void scaleObject(const MWWorld::Ptr& ptr, const osg::Vec3f& scale); + void removeObject(const MWWorld::Ptr& ptr); + void setSkyEnabled(bool enabled); bool toggleRenderMode(RenderMode mode); diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index fd63146f2..d210ff162 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -210,12 +210,12 @@ namespace MWWorld mPhysics->removeHeightField ((*iter)->getCell()->getGridX(), (*iter)->getCell()->getGridY()); } + MWBase::Environment::get().getMechanicsManager()->drop (*iter); + mRendering.removeCell(*iter); MWBase::Environment::get().getWorld()->getLocalScripts().clearCell (*iter); - MWBase::Environment::get().getMechanicsManager()->drop (*iter); - MWBase::Environment::get().getSoundManager()->stopSound (*iter); mActiveCells.erase(*iter); } @@ -563,7 +563,7 @@ namespace MWWorld MWBase::Environment::get().getMechanicsManager()->remove (ptr); MWBase::Environment::get().getSoundManager()->stopSound3D (ptr); mPhysics->remove(ptr); - //mRendering.removeObject (ptr); + mRendering.removeObject (ptr); } bool Scene::isCellActive(const CellStore &cell) From 5ea61af6ac19e210b9afc1bfadd043343663f760 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 22 May 2015 01:43:04 +0200 Subject: [PATCH 1231/3725] Fix for applying view distance --- apps/openmw/mwrender/renderingmanager.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 9b796a359..def16ae30 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -400,6 +400,7 @@ namespace MWRender else if (it->first == "Viewing distance" && it->second == "viewing distance") { mViewDistance = Settings::Manager::getFloat("viewing distance", "Viewing distance"); + mStateUpdater->setFogEnd(mViewDistance); updateProjectionMatrix(); } else if (it->first == "General" && (it->second == "texture filtering" || it->second == "anisotropy")) From d6da5c8007b8798e02002d3ea920f16d1394f515 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 22 May 2015 01:43:16 +0200 Subject: [PATCH 1232/3725] Fix for crosshair not showing --- apps/openmw/mwrender/renderingmanager.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index def16ae30..4a28ba9de 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -254,6 +254,7 @@ namespace MWRender { mEffectManager->update(dt); mSky->update(dt); + mCamera->update(dt, paused); } void RenderingManager::updatePlayerPtr(const MWWorld::Ptr &ptr) From cac7c1e5351e46d65ec9e80077f1ddc4b0c34fab Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 22 May 2015 01:43:45 +0200 Subject: [PATCH 1233/3725] Restore various physics features --- apps/openmw/mwphysics/physicssystem.cpp | 30 +++++------ apps/openmw/mwphysics/physicssystem.hpp | 4 +- apps/openmw/mwworld/worldimp.cpp | 69 ++++++++++++------------- 3 files changed, 49 insertions(+), 54 deletions(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index db34e0411..840bb3bd6 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -396,16 +396,16 @@ namespace MWPhysics if(tracer.mFraction < 1.0f && getSlope(tracer.mPlaneNormal) <= sMaxSlope && tracer.mHitObject->getBroadphaseHandle()->m_collisionFilterGroup != CollisionType_Actor) { - /* const btCollisionObject* standingOn = tracer.mHitObject; - + /* if (const OEngine::Physic::RigidBody* body = dynamic_cast(standingOn)) { standingCollisionTracker[ptr.getRefData().getHandle()] = body->mName; } + */ + if (standingOn->getBroadphaseHandle()->m_collisionFilterGroup == CollisionType_Water) physicActor->setWalkingOnWater(true); - */ if (!isFlying) newPosition.z() = tracer.mEndPos.z() + 1.0f; @@ -698,23 +698,21 @@ namespace MWPhysics */ } - std::pair - PhysicsSystem::castRay(const Ogre::Vector3 &orig, const Ogre::Vector3 &dir, float len) + std::pair PhysicsSystem::castRay(const osg::Vec3f &from, const osg::Vec3f &to) { - return std::make_pair(false, Ogre::Vector3()); - /* - Ogre::Ray ray = Ogre::Ray(orig, dir); - Ogre::Vector3 to = ray.getPoint(len); + btVector3 btFrom = toBullet(from); + btVector3 btTo = toBullet(to); - btVector3 btFrom = btVector3(orig.x, orig.y, orig.z); - btVector3 btTo = btVector3(to.x, to.y, to.z); + btCollisionWorld::ClosestRayResultCallback resultCallback(btFrom, btTo); + resultCallback.m_collisionFilterGroup = 0xff; + resultCallback.m_collisionFilterMask = CollisionType_World | CollisionType_HeightMap; - std::pair test = mEngine->rayTest(btFrom, btTo); - if (test.second == -1) { - return std::make_pair(false, Ogre::Vector3()); + mDynamicsWorld->rayTest(btFrom, btTo, resultCallback); + if (resultCallback.hasHit()) + { + return std::make_pair(true, toOsg(resultCallback.m_hitPointWorld)); } - return std::make_pair(true, ray.getPoint(len * test.second)); - */ + return std::make_pair(false, osg::Vec3f()); } std::vector PhysicsSystem::getCollisions(const MWWorld::Ptr &ptr, int collisionGroup, int collisionMask) diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index 91e166bef..5f89b1b43 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -86,8 +86,8 @@ namespace MWPhysics // cast ray, return true if it hit something. bool castRay(const Ogre::Vector3& from, const Ogre::Vector3& to,bool ignoreHeightMap = false); - std::pair - castRay(const Ogre::Vector3 &orig, const Ogre::Vector3 &dir, float len); + /// @return + std::pair castRay(const osg::Vec3f &from, const osg::Vec3f &to); /// Queues velocity movement for a Ptr. If a Ptr is already queued, its velocity will /// be overwritten. Valid until the next call to applyQueuedMovement. diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 110ed61be..c81a3f71b 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -10,6 +10,8 @@ #include #include +#include +#include #include @@ -1888,29 +1890,6 @@ namespace MWWorld Ptr World::copyObjectToCell(const Ptr &object, CellStore* cell, ESM::Position pos, bool adjustPos) { -#if 0 - if (!object.getClass().isActor() && adjustPos) - { - // Adjust position so the location we wanted ends up in the middle of the object bounding box - Ogre::Vector3 min, max; - if (mPhysics->getObjectAABB(object, min, max)) { - Ogre::Quaternion xr(Ogre::Radian(-pos.rot[0]), Ogre::Vector3::UNIT_X); - Ogre::Quaternion yr(Ogre::Radian(-pos.rot[1]), Ogre::Vector3::UNIT_Y); - Ogre::Quaternion zr(Ogre::Radian(-pos.rot[2]), Ogre::Vector3::UNIT_Z); - - Ogre::Vector3 adjust ( - (min.x + max.x) / 2, - (min.y + max.y) / 2, - min.z - ); - adjust = (xr*yr*zr) * adjust; - pos.pos[0] -= adjust.x; - pos.pos[1] -= adjust.y; - pos.pos[2] -= adjust.z; - } - } -#endif - if (cell->isExterior()) { int cellX, cellY; @@ -1941,6 +1920,28 @@ namespace MWWorld addContainerScripts(dropped, cell); } + if (!object.getClass().isActor() && adjustPos && dropped.getRefData().getBaseNode()) + { + // Adjust position so the location we wanted ends up in the middle of the object bounding box + osg::ComputeBoundsVisitor computeBounds; + dropped.getRefData().getBaseNode()->accept(computeBounds); + osg::BoundingBox bounds = computeBounds.getBoundingBox(); + if (bounds.valid()) + { + bounds.set(bounds._min - pos.asVec3(), bounds._max - pos.asVec3()); + + osg::Vec3f adjust ( + (bounds.xMin() + bounds.xMax()) / 2, + (bounds.yMin() + bounds.yMax()) / 2, + bounds.zMin() + ); + pos.pos[0] -= adjust.x(); + pos.pos[1] -= adjust.y(); + pos.pos[2] -= adjust.z(); + moveObject(dropped, pos.pos[0], pos.pos[1], pos.pos[2]); + } + } + return dropped; } @@ -1954,17 +1955,15 @@ namespace MWWorld pos.rot[0] = 0; pos.rot[1] = 0; - Ogre::Vector3 orig = - Ogre::Vector3(pos.pos); - orig.z += 20; - //Ogre::Vector3 dir = Ogre::Vector3(0, 0, -1); + osg::Vec3f orig = pos.asVec3(); + orig.z() += 20; + osg::Vec3f dir (0, 0, -1); - //float len = 100.0; + float len = 100.0; - std::pair hit;// = - //mPhysics->castRay(orig, dir, len); + std::pair hit = mPhysics->castRay(orig, dir*len); if (hit.first) - pos.pos[2] = hit.second.z; + pos.pos[2] = hit.second.z(); // copy the object and set its count int origCount = object.getRefData().getCount(); @@ -2069,14 +2068,12 @@ namespace MWWorld // TODO: There might be better places to update PhysicActor::mOnGround. bool World::isOnGround(const MWWorld::Ptr &ptr) const { - return true; - /* - //RefData &refdata = ptr.getRefData(); - OEngine::Physic::PhysicActor *physactor = 0;//mPhysEngine->getCharacter(refdata.getHandle()); + MWPhysics::Actor* physactor = mPhysics->getActor(ptr); if(!physactor) return false; - + return physactor->getOnGround(); + /* if(physactor->getOnGround()) return true; else From 627fee07bc2f91d7b062665f9e24984206e24240 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 22 May 2015 01:54:06 +0200 Subject: [PATCH 1234/3725] Minor cleanup --- apps/openmw/mwrender/characterpreview.hpp | 2 -- apps/openmw/mwrender/creatureanimation.cpp | 16 +++------------- apps/openmw/mwrender/objects.hpp | 3 --- apps/openmw/mwrender/sky.cpp | 2 +- apps/openmw/mwrender/sky.hpp | 8 ++++---- apps/openmw/mwworld/weather.cpp | 2 +- 6 files changed, 9 insertions(+), 24 deletions(-) diff --git a/apps/openmw/mwrender/characterpreview.hpp b/apps/openmw/mwrender/characterpreview.hpp index b7722d1f3..0f85cc3bf 100644 --- a/apps/openmw/mwrender/characterpreview.hpp +++ b/apps/openmw/mwrender/characterpreview.hpp @@ -1,8 +1,6 @@ #ifndef MWRENDER_CHARACTERPREVIEW_H #define MWRENDER_CHARACTERPREVIEW_H -#include - #include #include diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index e15dee532..810fc8b19 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -145,16 +145,6 @@ void CreatureWeaponAnimation::updatePart(PartHolderPtr& scene, int slot) */ } -/* -void CreatureWeaponAnimation::configureAddedObject(NifOgre::ObjectScenePtr object, MWWorld::Ptr ptr, int slot) -{ - //Ogre::Vector3 glowColor = getEnchantmentColor(ptr); - - //setRenderProperties(object, RV_Actors, RQG_Main, RQG_Alpha, 0, - // !ptr.getClass().getEnchantment(ptr).empty(), &glowColor); -} -*/ - void CreatureWeaponAnimation::attachArrow() { //WeaponAnimation::attachArrow(mPtr); @@ -167,14 +157,14 @@ void CreatureWeaponAnimation::releaseArrow() osg::Vec3f CreatureWeaponAnimation::runAnimation(float duration) { - /* - Ogre::Vector3 ret = Animation::runAnimation(duration); + osg::Vec3f ret = Animation::runAnimation(duration); + /* if (mSkelBase) pitchSkeleton(mPtr.getRefData().getPosition().rot[0], mSkelBase->getSkeleton()); */ - return osg::Vec3f(); + return ret; } } diff --git a/apps/openmw/mwrender/objects.hpp b/apps/openmw/mwrender/objects.hpp index 298dc97bb..716192959 100644 --- a/apps/openmw/mwrender/objects.hpp +++ b/apps/openmw/mwrender/objects.hpp @@ -63,9 +63,6 @@ public: Animation* getAnimation(const MWWorld::Ptr &ptr); - //Ogre::AxisAlignedBox getDimensions(MWWorld::CellStore*); - ///< get a bounding box that encloses all objects in the specified cell - bool removeObject (const MWWorld::Ptr& ptr); ///< \return found? diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 2f3a87c5b..6b432ae5e 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -799,7 +799,7 @@ void SkyManager::sunDisable() mSun->setVisible(false); } -void SkyManager::setStormDirection(const Ogre::Vector3 &direction) +void SkyManager::setStormDirection(const osg::Vec3f &direction) { mStormDirection = direction; } diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index ebf3ee87f..652de28b4 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -59,7 +59,7 @@ namespace MWRender void setRainSpeed(float speed); - void setStormDirection(const Ogre::Vector3& direction); + void setStormDirection(const osg::Vec3f& direction); void setSunDirection(const osg::Vec3f& direction); @@ -123,11 +123,11 @@ namespace MWRender float mRainTimer; - Ogre::Vector3 mStormDirection; + osg::Vec3f mStormDirection; // remember some settings so we don't have to apply them again if they didnt change - Ogre::String mClouds; - Ogre::String mNextClouds; + std::string mClouds; + std::string mNextClouds; float mCloudBlendFactor; float mCloudOpacity; float mCloudSpeed; diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index b37a38353..655e0a073 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -420,7 +420,7 @@ void WeatherManager::update(float duration, bool paused) mStormDirection = (playerPos - redMountainPos); mStormDirection.z() = 0; - //mRendering->getSkyManager()->setStormDirection(mStormDirection); + mRendering->getSkyManager()->setStormDirection(mStormDirection); } mRendering->configureFog(mResult.mFogDepth, mResult.mFogColor); From 85345e663a19c5dc3920822730b994ca6c077bc1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 22 May 2015 04:36:17 +0200 Subject: [PATCH 1235/3725] Restore getHitContact --- apps/openmw/mwbase/world.hpp | 2 +- apps/openmw/mwclass/creature.cpp | 4 +- apps/openmw/mwclass/npc.cpp | 4 +- apps/openmw/mwphysics/actor.hpp | 5 ++ apps/openmw/mwphysics/physicssystem.cpp | 79 +++++++++++++++++------ apps/openmw/mwphysics/physicssystem.hpp | 8 ++- apps/openmw/mwrender/renderingmanager.cpp | 3 + apps/openmw/mwworld/worldimp.cpp | 36 +++++------ apps/openmw/mwworld/worldimp.hpp | 2 +- 9 files changed, 98 insertions(+), 45 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 008d64aaf..88dbf89f8 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -262,7 +262,7 @@ namespace MWBase /// Returns a pointer to the object the provided object would hit (if within the /// specified distance), and the point where the hit occurs. This will attempt to /// use the "Head" node, or alternatively the "Bip01 Head" node as a basis. - virtual std::pair getHitContact(const MWWorld::Ptr &ptr, float distance) = 0; + virtual std::pair getHitContact(const MWWorld::Ptr &ptr, float distance) = 0; virtual void adjustPosition (const MWWorld::Ptr& ptr, bool force) = 0; ///< Adjust position after load to be on ground. Must be called after model load. diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 1e41aea24..b6eb930c9 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -238,7 +238,7 @@ namespace MWClass const float fCombatDistance = gmst.find("fCombatDistance")->getFloat(); dist = fCombatDistance * weapon.get()->mBase->mData.mReach; } - std::pair result = MWBase::Environment::get().getWorld()->getHitContact(ptr, dist); + std::pair result = MWBase::Environment::get().getWorld()->getHitContact(ptr, dist); if (result.first.isEmpty()) return; // Didn't hit anything @@ -247,7 +247,7 @@ namespace MWClass if (!victim.getClass().isActor()) return; // Can't hit non-actors - Ogre::Vector3 hitPosition = result.second; + Ogre::Vector3 hitPosition (result.second.x(), result.second.y(), result.second.z()); float hitchance = MWMechanics::getHitChance(ptr, victim, ref->mBase->mData.mCombat); diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 463209df8..829862ad1 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -491,9 +491,9 @@ namespace MWClass store.find("fHandToHandReach")->getFloat()); // TODO: Use second to work out the hit angle - std::pair result = world->getHitContact(ptr, dist); + std::pair result = world->getHitContact(ptr, dist); MWWorld::Ptr victim = result.first; - Ogre::Vector3 hitPosition = result.second; + Ogre::Vector3 hitPosition (result.second.x(), result.second.y(), result.second.z()); if(victim.isEmpty()) // Didn't hit anything return; diff --git a/apps/openmw/mwphysics/actor.hpp b/apps/openmw/mwphysics/actor.hpp index 513985c94..60de42151 100644 --- a/apps/openmw/mwphysics/actor.hpp +++ b/apps/openmw/mwphysics/actor.hpp @@ -31,6 +31,11 @@ namespace MWPhysics mPtr = updated; } + MWWorld::Ptr getPtr() const + { + return mPtr; + } + protected: MWWorld::Ptr mPtr; }; diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 840bb3bd6..afc81da8b 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -653,35 +653,78 @@ namespace MWPhysics return mDebugDrawEnabled; } - std::pair PhysicsSystem::getHitContact(const std::string &name, - const Ogre::Vector3 &origin, - const Ogre::Quaternion &orient, + class DeepestNotMeContactTestResultCallback : public btCollisionWorld::ContactResultCallback + { + const btCollisionObject* mMe; + + // Store the real origin, since the shape's origin is its center + btVector3 mOrigin; + + public: + const btCollisionObject *mObject; + btVector3 mContactPoint; + btScalar mLeastDistSqr; + + DeepestNotMeContactTestResultCallback(const btCollisionObject* me, const btVector3 &origin) + : mMe(me), mOrigin(origin), mObject(NULL), mContactPoint(0,0,0), + mLeastDistSqr(std::numeric_limits::max()) + { } + + virtual btScalar addSingleResult(btManifoldPoint& cp, + const btCollisionObjectWrapper* col0Wrap,int partId0,int index0, + const btCollisionObjectWrapper* col1Wrap,int partId1,int index1) + { + if (col1Wrap->m_collisionObject != mMe) + { + btScalar distsqr = mOrigin.distance2(cp.getPositionWorldOnA()); + if(!mObject || distsqr < mLeastDistSqr) + { + mObject = col1Wrap->m_collisionObject; + mLeastDistSqr = distsqr; + mContactPoint = cp.getPositionWorldOnA(); + } + } + + return 0.f; + } + }; + + std::pair PhysicsSystem::getHitContact(const MWWorld::Ptr& actor, + const osg::Vec3f &origin, + const osg::Quat &orient, float queryDistance) { - return std::make_pair(std::string(), Ogre::Vector3()); - /* const MWWorld::Store &store = MWBase::Environment::get().getWorld()->getStore().get(); - btConeShape shape(Ogre::Degree(store.find("fCombatAngleXY")->getFloat()/2.0f).valueRadians(), - queryDistance); - shape.setLocalScaling(btVector3(1, 1, Ogre::Degree(store.find("fCombatAngleZ")->getFloat()/2.0f).valueRadians() / + btConeShape shape (osg::DegreesToRadians(store.find("fCombatAngleXY")->getFloat()/2.0f), queryDistance); + shape.setLocalScaling(btVector3(1, 1, osg::DegreesToRadians(store.find("fCombatAngleZ")->getFloat()/2.0f) / shape.getRadius())); // The shape origin is its center, so we have to move it forward by half the length. The // real origin will be provided to getFilteredContact to find the closest. - Ogre::Vector3 center = origin + (orient * Ogre::Vector3(0.0f, queryDistance*0.5f, 0.0f)); + osg::Vec3f center = origin + (orient * osg::Vec3f(0.0f, queryDistance*0.5f, 0.0f)); btCollisionObject object; object.setCollisionShape(&shape); - object.setWorldTransform(btTransform(btQuaternion(orient.x, orient.y, orient.z, orient.w), - btVector3(center.x, center.y, center.z))); - - std::pair result = mEngine->getFilteredContact( - name, btVector3(origin.x, origin.y, origin.z), &object); - if(!result.first) - return std::make_pair(std::string(), Ogre::Vector3(&result.second[0])); - return std::make_pair(result.first->mName, Ogre::Vector3(&result.second[0])); - */ + object.setWorldTransform(btTransform(toBullet(orient), toBullet(center))); + + const btCollisionObject* me = NULL; + Actor* physactor = getActor(actor); + if (physactor) + me = physactor->getCollisionObject(); + + DeepestNotMeContactTestResultCallback resultCallback(me, toBullet(origin)); + resultCallback.m_collisionFilterGroup = CollisionType_Actor; + resultCallback.m_collisionFilterMask = CollisionType_World | CollisionType_HeightMap | CollisionType_Actor; + mDynamicsWorld->contactTest(&object, resultCallback); + + if (resultCallback.mObject) + { + const PtrHolder* holder = static_cast(resultCallback.mObject->getUserPointer()); + if (holder) + return std::make_pair(holder->getPtr(), toOsg(resultCallback.mContactPoint)); + } + return std::make_pair(MWWorld::Ptr(), osg::Vec3f()); } diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index 5f89b1b43..aca24105e 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -11,6 +11,8 @@ #include "../mwworld/ptr.hpp" +#include + namespace osg { class Group; @@ -78,9 +80,9 @@ namespace MWPhysics std::vector getCollisions(const MWWorld::Ptr &ptr, int collisionGroup, int collisionMask); ///< get handles this object collides with osg::Vec3f traceDown(const MWWorld::Ptr &ptr, float maxHeight); - std::pair getHitContact(const std::string &name, - const Ogre::Vector3 &origin, - const Ogre::Quaternion &orientation, + std::pair getHitContact(const MWWorld::Ptr& actor, + const osg::Vec3f &origin, + const osg::Quat &orientation, float queryDistance); // cast ray, return true if it hit something. diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 4a28ba9de..af4e46f62 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -315,6 +315,9 @@ namespace MWRender MWRender::Animation* RenderingManager::getAnimation(const MWWorld::Ptr &ptr) { + if (mPlayerAnimation.get() && ptr == mPlayerAnimation->getPtr()) + return mPlayerAnimation.get(); + return mObjects->getAnimation(ptr); } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index c81a3f71b..35b6fc103 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -37,7 +37,7 @@ #include "../mwmechanics/combat.hpp" #include "../mwmechanics/aiavoiddoor.hpp" //Used to tell actors to avoid doors -//#include "../mwrender/animation.hpp" +#include "../mwrender/animation.hpp" #include "../mwrender/renderingmanager.hpp" #include "../mwrender/camera.hpp" @@ -1052,32 +1052,32 @@ namespace MWWorld //return getPtrViaHandle(facedHandle); } - std::pair World::getHitContact(const MWWorld::Ptr &ptr, float distance) + std::pair World::getHitContact(const MWWorld::Ptr &ptr, float distance) { - /* const ESM::Position &posdata = ptr.getRefData().getPosition(); - Ogre::Vector3 pos(posdata.pos); - Ogre::Quaternion rot = Ogre::Quaternion(Ogre::Radian(posdata.rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z) * - Ogre::Quaternion(Ogre::Radian(posdata.rot[0]), Ogre::Vector3::NEGATIVE_UNIT_X); - MWRender::Animation *anim = mRendering->getAnimation(ptr); - if(anim != NULL) + osg::Quat rot = osg::Quat(posdata.rot[0], osg::Vec3f(-1,0,0)) * osg::Quat(posdata.rot[2], osg::Vec3f(0,0,-1)); + osg::Vec3f pos (posdata.asVec3()); + + MWRender::Animation* anim = mRendering->getAnimation(ptr); + if (anim != NULL) { - Ogre::Node *node = anim->getNode("Head"); + const osg::Node* node = anim->getNode("Head"); if (node == NULL) node = anim->getNode("Bip01 Head"); - if(node != NULL) - pos += node->_getDerivedPosition(); + if (node != NULL) + { + osg::MatrixList mats = node->getWorldMatrices(); + if (mats.size()) + pos = mats[0].getTrans(); + } } - std::pair result;// = mPhysics->getHitContact(ptr.getRefData().getHandle(), - // pos, rot, distance); - if(result.first.empty()) - return std::make_pair(MWWorld::Ptr(), Ogre::Vector3(0.0f)); + std::pair result = mPhysics->getHitContact(ptr, pos, rot, distance); + if(result.first.isEmpty()) + return std::make_pair(MWWorld::Ptr(), osg::Vec3f()); - return std::make_pair(searchPtrViaHandle(result.first), result.second); - */ - return std::make_pair(MWWorld::Ptr(), Ogre::Vector3(0.0f)); + return std::make_pair(result.first, result.second); } void World::deleteObject (const Ptr& ptr) diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 67d4f863a..8b4772309 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -344,7 +344,7 @@ namespace MWWorld /// Returns a pointer to the object the provided object would hit (if within the /// specified distance), and the point where the hit occurs. This will attempt to /// use the "Head" node as a basis. - virtual std::pair getHitContact(const MWWorld::Ptr &ptr, float distance); + virtual std::pair getHitContact(const MWWorld::Ptr &ptr, float distance); virtual void deleteObject (const Ptr& ptr); virtual void undeleteObject (const Ptr& ptr); From 396fba7fa9891dad8c11dd4877278467cd9e19b8 Mon Sep 17 00:00:00 2001 From: Rohit Nirmal Date: Thu, 30 Apr 2015 19:24:27 -0500 Subject: [PATCH 1236/3725] Silence -Wreorder warnings, and remove -Wno-reorder. --- CMakeLists.txt | 2 +- apps/launcher/graphicspage.cpp | 4 +-- apps/launcher/settingspage.cpp | 4 +-- apps/opencs/editor.cpp | 4 +-- apps/opencs/model/doc/document.cpp | 3 +- apps/opencs/model/filter/valuenode.cpp | 2 +- apps/opencs/model/settings/connector.cpp | 2 +- .../opencs/model/tools/referenceablecheck.cpp | 2 +- apps/opencs/model/tools/tools.cpp | 4 +-- apps/opencs/model/world/columnbase.cpp | 2 +- apps/opencs/model/world/commanddispatcher.cpp | 2 +- apps/opencs/model/world/commands.cpp | 16 ++++----- apps/opencs/model/world/refidadapterimp.cpp | 2 +- apps/opencs/view/doc/filedialog.cpp | 2 +- apps/opencs/view/render/cell.cpp | 2 +- apps/opencs/view/render/mousestate.cpp | 10 +++--- apps/opencs/view/render/textoverlay.cpp | 4 +-- apps/opencs/view/render/worldspacewidget.cpp | 2 +- apps/opencs/view/settings/booleanview.cpp | 2 +- apps/opencs/view/settings/dialog.cpp | 2 +- apps/opencs/view/settings/frame.cpp | 4 +-- apps/opencs/view/settings/listview.cpp | 2 +- apps/opencs/view/settings/page.cpp | 2 +- apps/opencs/view/settings/spinbox.cpp | 2 +- apps/opencs/view/settings/view.cpp | 6 ++-- apps/opencs/view/world/dialoguesubview.cpp | 10 +++--- apps/opencs/view/world/dragrecordtable.cpp | 2 +- apps/opencs/view/world/genericcreator.cpp | 4 +-- apps/opencs/view/world/scenesubview.cpp | 2 +- apps/opencs/view/world/scriptedit.cpp | 9 ++--- apps/opencs/view/world/table.cpp | 4 +-- apps/openmw/mwbase/environment.cpp | 4 +-- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 13 ++++--- apps/openmw/mwgui/alchemywindow.cpp | 4 +-- apps/openmw/mwgui/bookpage.cpp | 16 ++++----- apps/openmw/mwgui/bookwindow.cpp | 2 +- apps/openmw/mwgui/companionwindow.cpp | 6 ++-- apps/openmw/mwgui/container.cpp | 6 ++-- apps/openmw/mwgui/dialogue.cpp | 4 +-- apps/openmw/mwgui/draganddrop.cpp | 6 ++-- apps/openmw/mwgui/inventorywindow.cpp | 12 +++---- apps/openmw/mwgui/itemmodel.cpp | 12 +++---- apps/openmw/mwgui/jailscreen.cpp | 4 +-- apps/openmw/mwgui/journalbooks.cpp | 6 ++-- apps/openmw/mwgui/journalviewmodel.cpp | 2 +- apps/openmw/mwgui/loadingscreen.cpp | 6 ++-- apps/openmw/mwgui/mapwindow.cpp | 22 ++++++------ apps/openmw/mwgui/messagebox.cpp | 6 ++-- apps/openmw/mwgui/sortfilteritemmodel.cpp | 2 +- apps/openmw/mwgui/spellbuyingwindow.cpp | 2 +- apps/openmw/mwgui/spellcreationdialog.cpp | 6 ++-- apps/openmw/mwgui/tooltips.cpp | 6 ++-- apps/openmw/mwgui/waitdialog.cpp | 2 +- apps/openmw/mwgui/windowbase.cpp | 2 +- apps/openmw/mwmechanics/aiavoiddoor.cpp | 2 +- apps/openmw/mwmechanics/aicombat.cpp | 6 ++-- apps/openmw/mwmechanics/aiescort.cpp | 7 ++-- apps/openmw/mwmechanics/aifollow.cpp | 12 +++---- apps/openmw/mwmechanics/aiwander.cpp | 2 +- apps/openmw/mwmechanics/character.cpp | 2 +- apps/openmw/mwmechanics/creaturestats.cpp | 16 ++++----- apps/openmw/mwmechanics/npcstats.cpp | 6 ++-- apps/openmw/mwmechanics/obstacle.cpp | 2 +- apps/openmw/mwmechanics/pathgrid.cpp | 4 +-- apps/openmw/mwrender/globalmap.cpp | 5 +-- apps/openmw/mwrender/water.cpp | 6 ++-- apps/openmw/mwsound/soundmanagerimp.cpp | 6 ++-- apps/openmw/mwworld/action.cpp | 2 +- apps/openmw/mwworld/esmloader.cpp | 2 +- apps/openmw/mwworld/inventorystore.cpp | 8 ++--- apps/openmw/mwworld/physicssystem.cpp | 2 +- apps/openmw/mwworld/player.cpp | 2 +- apps/openmw/mwworld/refdata.cpp | 18 +++++----- apps/openmw/mwworld/weather.cpp | 9 +++-- apps/openmw/mwworld/worldimp.cpp | 14 ++++---- components/compiler/lineparser.cpp | 4 +-- components/interpreter/runtime.cpp | 2 +- .../ogre-ffmpeg-videoplayer/audiodecoder.cpp | 14 ++++---- extern/ogre-ffmpeg-videoplayer/videostate.cpp | 8 +++-- extern/oics/ICSControl.cpp | 4 +-- extern/oics/ICSInputControlSystem.cpp | 36 +++++++++---------- extern/sdl4ogre/sdlinputwrapper.cpp | 34 +++++++++--------- extern/shiny/Main/Factory.cpp | 12 +++---- extern/shiny/Main/MaterialInstance.cpp | 6 ++-- extern/shiny/Main/Platform.cpp | 4 +-- extern/shiny/Main/ShaderSet.cpp | 2 +- 86 files changed, 266 insertions(+), 264 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7c19c57eb..1fefc673e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -351,7 +351,7 @@ endif() # CXX Compiler settings if (CMAKE_CXX_COMPILER_ID STREQUAL GNU OR CMAKE_CXX_COMPILER_ID STREQUAL Clang) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wno-unused-parameter -Wno-reorder -std=c++98 -pedantic -Wno-long-long") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wno-unused-parameter -std=c++98 -pedantic -Wno-long-long") if (CMAKE_CXX_COMPILER_ID STREQUAL Clang AND NOT APPLE) execute_process(COMMAND ${CMAKE_C_COMPILER} --version OUTPUT_VARIABLE CLANG_VERSION) diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index cdb51348c..5176d7fa0 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -36,13 +36,13 @@ QString getAspect(int x, int y) } Launcher::GraphicsPage::GraphicsPage(Files::ConfigurationManager &cfg, GraphicsSettings &graphicsSetting, QWidget *parent) - : mOgre(NULL) + : QWidget(parent) + , mOgre(NULL) , mSelectedRenderSystem(NULL) , mOpenGLRenderSystem(NULL) , mDirect3DRenderSystem(NULL) , mCfgMgr(cfg) , mGraphicsSettings(graphicsSetting) - , QWidget(parent) { setObjectName ("GraphicsPage"); setupUi(this); diff --git a/apps/launcher/settingspage.cpp b/apps/launcher/settingspage.cpp index 34b4b41a9..843b51391 100644 --- a/apps/launcher/settingspage.cpp +++ b/apps/launcher/settingspage.cpp @@ -18,10 +18,10 @@ using namespace Process; Launcher::SettingsPage::SettingsPage(Files::ConfigurationManager &cfg, Config::GameSettings &gameSettings, Config::LauncherSettings &launcherSettings, MainDialog *parent) - : mCfgMgr(cfg) + : QWidget(parent) + , mCfgMgr(cfg) , mGameSettings(gameSettings) , mLauncherSettings(launcherSettings) - , QWidget(parent) , mMain(parent) { setupUi(this); diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 1d31c8396..53a9e9e83 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -23,8 +23,8 @@ CS::Editor::Editor (OgreInit::OgreInit& ogreInit) : mUserSettings (mCfgMgr), mOverlaySystem (0), mDocumentManager (mCfgMgr), - mViewManager (mDocumentManager), - mIpcServerName ("org.openmw.OpenCS"), mServer(NULL), mClientSocket(NULL), mPid(""), mLock() + mViewManager (mDocumentManager), mPid(""), + mLock(), mIpcServerName ("org.openmw.OpenCS"), mServer(NULL), mClientSocket(NULL) { std::pair > config = readConfig(); diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 31d0aaccd..a73201ec0 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -2251,11 +2251,12 @@ CSMDoc::Document::Document (const Files::ConfigurationManager& configuration, ToUTF8::FromType encoding, const CSMWorld::ResourcesManager& resourcesManager, const std::vector& blacklistedScripts) : mSavePath (savePath), mContentFiles (files), mNew (new_), mData (encoding, resourcesManager), - mTools (*this), mResDir(resDir), + mTools (*this), mProjectPath ((configuration.getUserDataPath() / "projects") / (savePath.filename().string() + ".project")), mSavingOperation (*this, mProjectPath, encoding), mSaving (&mSavingOperation), + mResDir(resDir), mRunner (mProjectPath), mPhysics(boost::shared_ptr()) { if (mContentFiles.empty()) diff --git a/apps/opencs/model/filter/valuenode.cpp b/apps/opencs/model/filter/valuenode.cpp index 6fdae3e1b..6fdb5cb02 100644 --- a/apps/opencs/model/filter/valuenode.cpp +++ b/apps/opencs/model/filter/valuenode.cpp @@ -9,7 +9,7 @@ CSMFilter::ValueNode::ValueNode (int columnId, Type lowerType, Type upperType, double lower, double upper) -: mColumnId (columnId), mLowerType (lowerType), mUpperType (upperType), mLower (lower), mUpper (upper){} +: mColumnId (columnId), mLower (lower), mUpper (upper), mLowerType (lowerType), mUpperType (upperType){} bool CSMFilter::ValueNode::test (const CSMWorld::IdTableBase& table, int row, const std::map& columns) const diff --git a/apps/opencs/model/settings/connector.cpp b/apps/opencs/model/settings/connector.cpp index 5e1d64544..3cf21123c 100644 --- a/apps/opencs/model/settings/connector.cpp +++ b/apps/opencs/model/settings/connector.cpp @@ -4,7 +4,7 @@ CSMSettings::Connector::Connector(CSVSettings::View *master, QObject *parent) - : mMasterView (master), QObject(parent) + : QObject(parent), mMasterView (master) {} void CSMSettings::Connector::addSlaveView (CSVSettings::View *view, diff --git a/apps/opencs/model/tools/referenceablecheck.cpp b/apps/opencs/model/tools/referenceablecheck.cpp index 5190aacd5..c0991a330 100644 --- a/apps/opencs/model/tools/referenceablecheck.cpp +++ b/apps/opencs/model/tools/referenceablecheck.cpp @@ -11,8 +11,8 @@ CSMTools::ReferenceableCheckStage::ReferenceableCheckStage( const CSMWorld::IdCollection& faction) : mReferencables(referenceable), - mClasses(classes), mRaces(races), + mClasses(classes), mFactions(faction), mPlayerPresent(false) { diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index 970a8ac4f..99e462b1d 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -103,8 +103,8 @@ CSMDoc::OperationHolder *CSMTools::Tools::getVerifier() } CSMTools::Tools::Tools (CSMDoc::Document& document) -: mDocument (document), mData (document.getData()), mVerifierOperation (0), mNextReportNumber (0), - mSearchOperation (0) +: mDocument (document), mData (document.getData()), mVerifierOperation (0), + mSearchOperation (0), mNextReportNumber (0) { // index 0: load error log mReports.insert (std::make_pair (mNextReportNumber++, new ReportModel)); diff --git a/apps/opencs/model/world/columnbase.cpp b/apps/opencs/model/world/columnbase.cpp index cf125aa63..53987b23c 100644 --- a/apps/opencs/model/world/columnbase.cpp +++ b/apps/opencs/model/world/columnbase.cpp @@ -3,7 +3,7 @@ #include "columns.hpp" CSMWorld::ColumnBase::ColumnBase (int columnId, Display displayType, int flags) - : mColumnId (columnId), mDisplayType (displayType), mFlags (flags) + : mColumnId (columnId), mFlags (flags), mDisplayType (displayType) {} CSMWorld::ColumnBase::~ColumnBase() {} diff --git a/apps/opencs/model/world/commanddispatcher.cpp b/apps/opencs/model/world/commanddispatcher.cpp index 2d3262487..b9d5bd7fe 100644 --- a/apps/opencs/model/world/commanddispatcher.cpp +++ b/apps/opencs/model/world/commanddispatcher.cpp @@ -83,7 +83,7 @@ std::vector CSMWorld::CommandDispatcher::getRevertableRecords() con CSMWorld::CommandDispatcher::CommandDispatcher (CSMDoc::Document& document, const CSMWorld::UniversalId& id, QObject *parent) -: QObject (parent), mDocument (document), mId (id), mLocked (false) +: QObject (parent), mLocked (false), mDocument (document), mId (id) {} void CSMWorld::CommandDispatcher::setEditLock (bool locked) diff --git a/apps/opencs/model/world/commands.cpp b/apps/opencs/model/world/commands.cpp index 9a0401081..fbb4de756 100644 --- a/apps/opencs/model/world/commands.cpp +++ b/apps/opencs/model/world/commands.cpp @@ -235,12 +235,12 @@ CSMWorld::DeleteNestedCommand::DeleteNestedCommand (IdTree& model, int nestedRow, int parentColumn, QUndoCommand* parent) : - mId(id), + QUndoCommand(parent), + NestedTableStoring(model, id, parentColumn), mModel(model), + mId(id), mParentColumn(parentColumn), - QUndoCommand(parent), - mNestedRow(nestedRow), - NestedTableStoring(model, id, parentColumn) + mNestedRow(nestedRow) { std::string title = model.headerData(parentColumn, Qt::Horizontal, Qt::DisplayRole).toString().toUtf8().constData(); @@ -263,12 +263,12 @@ void CSMWorld::DeleteNestedCommand::undo() } CSMWorld::AddNestedCommand::AddNestedCommand(IdTree& model, const std::string& id, int nestedRow, int parentColumn, QUndoCommand* parent) - : mModel(model), + : QUndoCommand(parent), + NestedTableStoring(model, id, parentColumn), + mModel(model), mId(id), mNewRow(nestedRow), - mParentColumn(parentColumn), - QUndoCommand(parent), - NestedTableStoring(model, id, parentColumn) + mParentColumn(parentColumn) { std::string title = model.headerData(parentColumn, Qt::Horizontal, Qt::DisplayRole).toString().toUtf8().constData(); diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index 98c1b6f0f..c784e14ce 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -13,7 +13,7 @@ CSMWorld::PotionColumns::PotionColumns (const InventoryColumns& columns) CSMWorld::PotionRefIdAdapter::PotionRefIdAdapter (const PotionColumns& columns, const RefIdColumn *autoCalc) : InventoryRefIdAdapter (UniversalId::Type_Potion, columns), - mAutoCalc (autoCalc), mColumns(columns) + mColumns(columns), mAutoCalc (autoCalc) {} QVariant CSMWorld::PotionRefIdAdapter::getData (const RefIdColumn *column, const RefIdData& data, diff --git a/apps/opencs/view/doc/filedialog.cpp b/apps/opencs/view/doc/filedialog.cpp index 1b3196112..eeec81109 100644 --- a/apps/opencs/view/doc/filedialog.cpp +++ b/apps/opencs/view/doc/filedialog.cpp @@ -18,7 +18,7 @@ #include "adjusterwidget.hpp" CSVDoc::FileDialog::FileDialog(QWidget *parent) : - QDialog(parent), mSelector (0), mFileWidget (0), mAdjusterWidget (0), mDialogBuilt(false), mAction(ContentAction_Undefined) + QDialog(parent), mSelector (0), mAction(ContentAction_Undefined), mFileWidget (0), mAdjusterWidget (0), mDialogBuilt(false) { ui.setupUi (this); resize(400, 400); diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index a030ea11f..99658e1c8 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -55,7 +55,7 @@ bool CSVRender::Cell::addObjects (int start, int end) CSVRender::Cell::Cell (CSMWorld::Data& data, Ogre::SceneManager *sceneManager, const std::string& id, boost::shared_ptr physics, const Ogre::Vector3& origin) -: mData (data), mId (Misc::StringUtils::lowerCase (id)), mSceneMgr(sceneManager), mPhysics(physics), mX(0), mY(0) +: mData (data), mId (Misc::StringUtils::lowerCase (id)), mPhysics(physics), mSceneMgr(sceneManager), mX(0), mY(0) { mCellNode = sceneManager->getRootSceneNode()->createChildSceneNode(); mCellNode->setPosition (origin); diff --git a/apps/opencs/view/render/mousestate.cpp b/apps/opencs/view/render/mousestate.cpp index a94f4f8ab..206820194 100644 --- a/apps/opencs/view/render/mousestate.cpp +++ b/apps/opencs/view/render/mousestate.cpp @@ -56,11 +56,11 @@ namespace CSVRender // MouseState::MouseState(WorldspaceWidget *parent) - : mParent(parent), mPhysics(parent->mDocument.getPhysics()), mSceneManager(parent->getSceneManager()) - , mCurrentObj(""), mMouseState(Mouse_Default), mOldPos(0,0), mMouseEventTimer(0), mPlane(0) - , mGrabbedSceneNode(""), mOrigObjPos(Ogre::Vector3()), mOrigMousePos(Ogre::Vector3()) - , mCurrentMousePos(Ogre::Vector3()), mOffset(0.0f) - , mColIndexPosX(0), mColIndexPosY(0), mColIndexPosZ(0), mIdTableModel(0) + : mMouseState(Mouse_Default), mParent(parent), mPhysics(parent->mDocument.getPhysics()) + , mSceneManager(parent->getSceneManager()), mOldPos(0,0), mCurrentObj(""), mGrabbedSceneNode("") + , mMouseEventTimer(0), mPlane(0), mOrigObjPos(Ogre::Vector3()), mOrigMousePos(Ogre::Vector3()) + , mCurrentMousePos(Ogre::Vector3()), mOffset(0.0f), mIdTableModel(0), mColIndexPosX(0) + , mColIndexPosY(0), mColIndexPosZ(0) { const CSMWorld::RefCollection& references = mParent->mDocument.getData().getReferences(); diff --git a/apps/opencs/view/render/textoverlay.cpp b/apps/opencs/view/render/textoverlay.cpp index 656ea959c..c41d5f318 100644 --- a/apps/opencs/view/render/textoverlay.cpp +++ b/apps/opencs/view/render/textoverlay.cpp @@ -27,8 +27,8 @@ namespace CSVRender // http://www.ogre3d.org/tikiwiki/Creating+dynamic+textures // http://www.ogre3d.org/tikiwiki/ManualObject TextOverlay::TextOverlay(const Ogre::MovableObject* obj, const Ogre::Camera* camera, const Ogre::String& id) - : mOverlay(0), mCaption(""), mDesc(""), mEnabled(true), mCamera(camera), mObj(obj), mId(id) - , mOnScreen(false) , mInstance(0), mFontHeight(16) // FIXME: make font height configurable + : mOverlay(0), mCaption(""), mDesc(""), mObj(obj), mCamera(camera), mFontHeight(16), mId(id) + , mEnabled(true), mOnScreen(false), mInstance(0) // FIXME: make font height configurable { if(id == "" || !camera || !obj) throw std::runtime_error("TextOverlay could not be created."); diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index e3e5ce50e..e88814818 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -22,7 +22,7 @@ #include "editmode.hpp" CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidget* parent) -: SceneWidget (parent), mDocument(document), mSceneElements(0), mRun(0), mPhysics(boost::shared_ptr()), mMouse(0), +: SceneWidget (parent), mSceneElements(0), mRun(0), mDocument(document), mPhysics(boost::shared_ptr()), mMouse(0), mInteractionMask (0) { setAcceptDrops(true); diff --git a/apps/opencs/view/settings/booleanview.cpp b/apps/opencs/view/settings/booleanview.cpp index 29f9775af..8c759cabb 100644 --- a/apps/opencs/view/settings/booleanview.cpp +++ b/apps/opencs/view/settings/booleanview.cpp @@ -12,7 +12,7 @@ CSVSettings::BooleanView::BooleanView (CSMSettings::Setting *setting, Page *parent) - : mType(setting->type()), View (setting, parent) + : View (setting, parent), mType(setting->type()) { foreach (const QString &value, setting->declaredValues()) { diff --git a/apps/opencs/view/settings/dialog.cpp b/apps/opencs/view/settings/dialog.cpp index 0b1231266..e8832e2bc 100644 --- a/apps/opencs/view/settings/dialog.cpp +++ b/apps/opencs/view/settings/dialog.cpp @@ -23,7 +23,7 @@ #include CSVSettings::Dialog::Dialog(QMainWindow *parent) - : mStackedWidget (0), mDebugMode (false), SettingWindow (parent) + : SettingWindow (parent), mStackedWidget (0), mDebugMode (false) { setWindowTitle(QString::fromUtf8 ("User Settings")); diff --git a/apps/opencs/view/settings/frame.cpp b/apps/opencs/view/settings/frame.cpp index 32e094274..454d3fefa 100644 --- a/apps/opencs/view/settings/frame.cpp +++ b/apps/opencs/view/settings/frame.cpp @@ -7,8 +7,8 @@ const QString CSVSettings::Frame::sInvisibleBoxStyle = CSVSettings::Frame::Frame (bool isVisible, const QString &title, QWidget *parent) - : mIsHorizontal (true), mLayout (new SettingLayout()), - QGroupBox (title, parent) + : QGroupBox (title, parent), mIsHorizontal (true), + mLayout (new SettingLayout()) { setFlat (true); mVisibleBoxStyle = styleSheet(); diff --git a/apps/opencs/view/settings/listview.cpp b/apps/opencs/view/settings/listview.cpp index 36cdbb0ae..0876b3982 100644 --- a/apps/opencs/view/settings/listview.cpp +++ b/apps/opencs/view/settings/listview.cpp @@ -7,7 +7,7 @@ CSVSettings::ListView::ListView(CSMSettings::Setting *setting, Page *parent) - : mComboBox (0), mAbstractItemView (0), View(setting, parent) + : View(setting, parent), mAbstractItemView (0), mComboBox (0) { QWidget *widget = buildWidget(setting->isMultiLine(), setting->widgetWidth()); diff --git a/apps/opencs/view/settings/page.cpp b/apps/opencs/view/settings/page.cpp index e846840b8..c009cdd7a 100644 --- a/apps/opencs/view/settings/page.cpp +++ b/apps/opencs/view/settings/page.cpp @@ -19,7 +19,7 @@ QMap CSVSettings::Page::Page (const QString &pageName, QList settingList, SettingWindow *parent, const QString& label) -: mParent(parent), mIsEditorPage (false), Frame(false, "", parent), mLabel (label) +: Frame(false, "", parent), mParent(parent), mIsEditorPage (false), mLabel (label) { setObjectName (pageName); diff --git a/apps/opencs/view/settings/spinbox.cpp b/apps/opencs/view/settings/spinbox.cpp index c70fc36d1..043107bb7 100644 --- a/apps/opencs/view/settings/spinbox.cpp +++ b/apps/opencs/view/settings/spinbox.cpp @@ -3,7 +3,7 @@ #include CSVSettings::SpinBox::SpinBox(QWidget *parent) - : mValueList(QStringList()), QSpinBox(parent) + : QSpinBox(parent), mValueList(QStringList()) { setRange (0, 0); } diff --git a/apps/opencs/view/settings/view.cpp b/apps/opencs/view/settings/view.cpp index 39c7f89b2..21cf55fdd 100644 --- a/apps/opencs/view/settings/view.cpp +++ b/apps/opencs/view/settings/view.cpp @@ -12,12 +12,12 @@ CSVSettings::View::View(CSMSettings::Setting *setting, Page *parent) - : mDataModel(0), mParentPage (parent), + : Frame(true, setting->getLabel(), parent), + mParentPage (parent), mDataModel(0), mHasFixedValues (!setting->declaredValues().isEmpty()), mIsMultiValue (setting->isMultiValue()), mViewKey (setting->page() + '/' + setting->name()), - mSerializable (setting->serializable()), - Frame(true, setting->getLabel(), parent) + mSerializable (setting->serializable()) { if (!setting->getToolTip().isEmpty()) setToolTip (setting->getToolTip()); diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 0d0e82dbf..647accd4c 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -356,15 +356,15 @@ CSVWorld::EditWidget::~EditWidget() CSVWorld::EditWidget::EditWidget(QWidget *parent, int row, CSMWorld::IdTable* table, CSMWorld::CommandDispatcher& commandDispatcher, CSMDoc::Document& document, bool createAndDelete) : -mDispatcher(this, table, commandDispatcher, document), -mNestedTableDispatcher(NULL), QScrollArea(parent), mWidgetMapper(NULL), mNestedTableMapper(NULL), +mDispatcher(this, table, commandDispatcher, document), +mNestedTableDispatcher(NULL), mMainWidget(NULL), +mTable(table), mCommandDispatcher (commandDispatcher), -mDocument (document), -mTable(table) +mDocument (document) { remake (row); @@ -571,8 +571,8 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSM SubView (id), mEditWidget(0), mMainLayout(NULL), - mUndoStack(document.getUndoStack()), mTable(dynamic_cast(document.getData().getTableModel(id))), + mUndoStack(document.getUndoStack()), mLocked(false), mDocument(document), mCommandDispatcher (document, CSMWorld::UniversalId::getParentType (id.getType())) diff --git a/apps/opencs/view/world/dragrecordtable.cpp b/apps/opencs/view/world/dragrecordtable.cpp index f45c45809..7032fee6d 100644 --- a/apps/opencs/view/world/dragrecordtable.cpp +++ b/apps/opencs/view/world/dragrecordtable.cpp @@ -17,8 +17,8 @@ void CSVWorld::DragRecordTable::startDragFromTable (const CSVWorld::DragRecordTa } CSVWorld::DragRecordTable::DragRecordTable (CSMDoc::Document& document, QWidget* parent) : -mDocument(document), QTableView(parent), +mDocument(document), mEditLock(false) {} diff --git a/apps/opencs/view/world/genericcreator.cpp b/apps/opencs/view/world/genericcreator.cpp index 4269679bf..a123e127f 100644 --- a/apps/opencs/view/world/genericcreator.cpp +++ b/apps/opencs/view/world/genericcreator.cpp @@ -129,9 +129,9 @@ void CSVWorld::GenericCreator::addScope (const QString& name, CSMWorld::Scope sc CSVWorld::GenericCreator::GenericCreator (CSMWorld::Data& data, QUndoStack& undoStack, const CSMWorld::UniversalId& id, bool relaxedIdRules) -: mData (data), mUndoStack (undoStack), mListId (id), mLocked (false), mCloneMode (false), +: mData (data), mUndoStack (undoStack), mListId (id), mLocked (false), mClonedType (CSMWorld::UniversalId::Type_None), mScopes (CSMWorld::Scope_Content), mScope (0), - mScopeLabel (0) + mScopeLabel (0), mCloneMode (false) { mLayout = new QHBoxLayout; mLayout->setContentsMargins (0, 0, 0, 0); diff --git a/apps/opencs/view/world/scenesubview.cpp b/apps/opencs/view/world/scenesubview.cpp index 3fdf2f6e5..aa2161259 100644 --- a/apps/opencs/view/world/scenesubview.cpp +++ b/apps/opencs/view/world/scenesubview.cpp @@ -27,7 +27,7 @@ #include "creator.hpp" CSVWorld::SceneSubView::SceneSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) -: SubView (id), mLayout(new QHBoxLayout), mDocument(document), mScene(NULL), mToolbar(NULL) +: SubView (id), mScene(NULL), mLayout(new QHBoxLayout), mDocument(document), mToolbar(NULL) { QVBoxLayout *layout = new QVBoxLayout; diff --git a/apps/opencs/view/world/scriptedit.cpp b/apps/opencs/view/world/scriptedit.cpp index 2e05fa110..2f0d82ae1 100644 --- a/apps/opencs/view/world/scriptedit.cpp +++ b/apps/opencs/view/world/scriptedit.cpp @@ -42,13 +42,14 @@ bool CSVWorld::ScriptEdit::event (QEvent *event) CSVWorld::ScriptEdit::ScriptEdit (const CSMDoc::Document& document, ScriptHighlighter::Mode mode, QWidget* parent) : QPlainTextEdit (parent), - mDocument (document), - mWhiteListQoutes("^[a-z|_]{1}[a-z|0-9|_]{0,}$", Qt::CaseInsensitive), mChangeLocked (0), - mLineNumberArea(0), mShowLineNum(false), + mLineNumberArea(0), mDefaultFont(font()), - mMonoFont(QFont("Monospace")) + mMonoFont(QFont("Monospace")), + mDocument (document), + mWhiteListQoutes("^[a-z|_]{1}[a-z|0-9|_]{0,}$", Qt::CaseInsensitive) + { // setAcceptRichText (false); setLineWrapMode (QPlainTextEdit::NoWrap); diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index 86daf8af7..b8972edbe 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -253,8 +253,8 @@ void CSVWorld::Table::mouseDoubleClickEvent (QMouseEvent *event) CSVWorld::Table::Table (const CSMWorld::UniversalId& id, bool createAndDelete, bool sorting, CSMDoc::Document& document) -: mCreateAction (0), mCloneAction(0), mRecordStatusDisplay (0), - DragRecordTable(document) +: DragRecordTable(document), mCreateAction (0), + mCloneAction(0),mRecordStatusDisplay (0) { CSMSettings::UserSettings &settings = CSMSettings::UserSettings::instance(); QString jumpSetting = settings.settingValue ("table-input/jump-to-added"); diff --git a/apps/openmw/mwbase/environment.cpp b/apps/openmw/mwbase/environment.cpp index 3bc15746e..a90eec5bf 100644 --- a/apps/openmw/mwbase/environment.cpp +++ b/apps/openmw/mwbase/environment.cpp @@ -17,8 +17,8 @@ MWBase::Environment *MWBase::Environment::sThis = 0; MWBase::Environment::Environment() : mWorld (0), mSoundManager (0), mScriptManager (0), mWindowManager (0), - mMechanicsManager (0), mDialogueManager (0), mJournal (0), mInputManager (0), mFrameDuration (0), - mStateManager (0) + mMechanicsManager (0), mDialogueManager (0), mJournal (0), mInputManager (0), mStateManager (0), + mFrameDuration (0) { assert (!sThis); sThis = this; diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 0b9fd65d2..1785575fc 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -48,12 +48,15 @@ namespace MWDialogue { DialogueManager::DialogueManager (const Compiler::Extensions& extensions, bool scriptVerbose, Translation::Storage& translationDataStorage) : - mCompilerContext (MWScript::CompilerContext::Type_Dialogue), - mErrorStream(std::cout.rdbuf()),mErrorHandler(mErrorStream) - , mTemporaryDispositionChange(0.f) - , mPermanentDispositionChange(0.f), mScriptVerbose (scriptVerbose) - , mTranslationDataStorage(translationDataStorage) + mTranslationDataStorage(translationDataStorage) + , mCompilerContext (MWScript::CompilerContext::Type_Dialogue) + , mErrorStream(std::cout.rdbuf()) + , mErrorHandler(mErrorStream) , mTalkedTo(false) + , mTemporaryDispositionChange(0.f) + , mPermanentDispositionChange(0.f) + , mScriptVerbose (scriptVerbose) + { mChoice = -1; mIsInChoice = false; diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index b28e4de09..a54744370 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -26,10 +26,10 @@ namespace MWGui { AlchemyWindow::AlchemyWindow() : WindowBase("openmw_alchemy_window.layout") - , mApparatus (4) - , mIngredients (4) , mSortModel(NULL) , mAlchemy(new MWMechanics::Alchemy()) + , mApparatus (4) + , mIngredients (4) { getWidget(mCreateButton, "CreateButton"); getWidget(mCancelButton, "CancelButton"); diff --git a/apps/openmw/mwgui/bookpage.cpp b/apps/openmw/mwgui/bookpage.cpp index 962e594ae..cfb49ebff 100644 --- a/apps/openmw/mwgui/bookpage.cpp +++ b/apps/openmw/mwgui/bookpage.cpp @@ -228,8 +228,8 @@ struct TypesetBookImpl::Typesetter : BookTypesetter Typesetter (size_t width, size_t height) : mPageWidth (width), mPageHeight(height), mSection (NULL), mLine (NULL), mRun (NULL), - mCurrentAlignment (AlignLeft), - mCurrentContent (NULL) + mCurrentContent (NULL), + mCurrentAlignment (AlignLeft) { mBook = boost::make_shared (); } @@ -697,10 +697,10 @@ namespace GlyphStream (MyGUI::IFont* font, float left, float top, float Z, MyGUI::Vertex* vertices, RenderXform const & renderXform) : - mZ(Z), mOrigin (left, top), - mFont (font), mVertices (vertices), - mRenderXform (renderXform), - mC(0) + mZ(Z), + mC(0), mFont (font), mOrigin (left, top), + mVertices (vertices), + mRenderXform (renderXform) { mVertexColourType = MyGUI::RenderManager::getInstance().getVertexFormat(); } @@ -801,10 +801,10 @@ protected: TextFormat (MyGUI::IFont* id, PageDisplay * display) : mFont (id), + mCountVertex (0), mTexture (NULL), mRenderItem (NULL), - mDisplay (display), - mCountVertex (0) + mDisplay (display) { } diff --git a/apps/openmw/mwgui/bookwindow.cpp b/apps/openmw/mwgui/bookwindow.cpp index 55a9b6191..6863994b8 100644 --- a/apps/openmw/mwgui/bookwindow.cpp +++ b/apps/openmw/mwgui/bookwindow.cpp @@ -18,9 +18,9 @@ namespace MWGui BookWindow::BookWindow () : WindowBase("openmw_book.layout") + , mCurrentPage(0) , mTakeButtonShow(true) , mTakeButtonAllowed(true) - , mCurrentPage(0) { getWidget(mCloseButton, "CloseButton"); mCloseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BookWindow::onCloseButtonClicked); diff --git a/apps/openmw/mwgui/companionwindow.cpp b/apps/openmw/mwgui/companionwindow.cpp index fe47437ca..4433f9ef8 100644 --- a/apps/openmw/mwgui/companionwindow.cpp +++ b/apps/openmw/mwgui/companionwindow.cpp @@ -37,11 +37,11 @@ namespace MWGui CompanionWindow::CompanionWindow(DragAndDrop *dragAndDrop, MessageBoxManager* manager) : WindowBase("openmw_companion_window.layout") + , mSortModel(NULL) + , mModel(NULL) + , mSelectedItem(-1) , mDragAndDrop(dragAndDrop) , mMessageBoxManager(manager) - , mSelectedItem(-1) - , mModel(NULL) - , mSortModel(NULL) { getWidget(mCloseButton, "CloseButton"); getWidget(mProfitLabel, "ProfitLabel"); diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 579730f42..1317e1e25 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -33,10 +33,10 @@ namespace MWGui ContainerWindow::ContainerWindow(DragAndDrop* dragAndDrop) : WindowBase("openmw_container_window.layout") , mDragAndDrop(dragAndDrop) - , mSelectedItem(-1) - , mModel(NULL) - , mSortModel(NULL) , mPickpocketDetected(false) + , mSortModel(NULL) + , mModel(NULL) + , mSelectedItem(-1) { getWidget(mDisposeCorpseButton, "DisposeCorpseButton"); getWidget(mTakeButton, "TakeButton"); diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 1b07522f3..692cea952 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -248,10 +248,10 @@ namespace MWGui DialogueWindow::DialogueWindow() : WindowBase("openmw_dialogue_window.layout") - , mPersuasionDialog() - , mEnabled(false) , mServices(0) + , mEnabled(false) , mGoodbye(false) + , mPersuasionDialog() { // Centre dialog center(); diff --git a/apps/openmw/mwgui/draganddrop.cpp b/apps/openmw/mwgui/draganddrop.cpp index fcb381b95..55aeb969c 100644 --- a/apps/openmw/mwgui/draganddrop.cpp +++ b/apps/openmw/mwgui/draganddrop.cpp @@ -20,12 +20,12 @@ namespace MWGui DragAndDrop::DragAndDrop() - : mDraggedWidget(NULL) - , mDraggedCount(0) + : mIsOnDragAndDrop(false) + , mDraggedWidget(NULL) , mSourceModel(NULL) , mSourceView(NULL) , mSourceSortModel(NULL) - , mIsOnDragAndDrop(false) + , mDraggedCount(0) { } diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 9aa8a8ea1..af24f3f79 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -50,17 +50,17 @@ namespace MWGui InventoryWindow::InventoryWindow(DragAndDrop* dragAndDrop) : WindowPinnableBase("openmw_inventory_window.layout") - , mTrading(false) - , mLastXSize(0) - , mLastYSize(0) - , mPreview(new MWRender::InventoryPreview(MWBase::Environment::get().getWorld ()->getPlayerPtr())) + , mDragAndDrop(dragAndDrop) , mPreviewDirty(true) , mPreviewResize(true) - , mDragAndDrop(dragAndDrop) + , mSelectedItem(-1) , mSortModel(NULL) , mTradeModel(NULL) - , mSelectedItem(-1) , mGuiMode(GM_Inventory) + , mLastXSize(0) + , mLastYSize(0) + , mPreview(new MWRender::InventoryPreview(MWBase::Environment::get().getWorld ()->getPlayerPtr())) + , mTrading(false) { mMainWidget->castType()->eventWindowChangeCoord += MyGUI::newDelegate(this, &InventoryWindow::onWindowResize); diff --git a/apps/openmw/mwgui/itemmodel.cpp b/apps/openmw/mwgui/itemmodel.cpp index 8224fd55b..9fce6e84d 100644 --- a/apps/openmw/mwgui/itemmodel.cpp +++ b/apps/openmw/mwgui/itemmodel.cpp @@ -14,10 +14,10 @@ namespace MWGui { ItemStack::ItemStack(const MWWorld::Ptr &base, ItemModel *creator, size_t count) - : mCreator(creator) - , mCount(count) + : mType(Type_Normal) , mFlags(0) - , mType(Type_Normal) + , mCreator(creator) + , mCount(count) , mBase(base) { if (base.getClass().getEnchantment(base) != "") @@ -59,10 +59,10 @@ namespace MWGui } ItemStack::ItemStack() - : mCreator(NULL) - , mCount(0) + : mType(Type_Normal) , mFlags(0) - , mType(Type_Normal) + , mCreator(NULL) + , mCount(0) { } diff --git a/apps/openmw/mwgui/jailscreen.cpp b/apps/openmw/mwgui/jailscreen.cpp index 5c0a6ec5f..936da2d8e 100644 --- a/apps/openmw/mwgui/jailscreen.cpp +++ b/apps/openmw/mwgui/jailscreen.cpp @@ -19,9 +19,9 @@ namespace MWGui { JailScreen::JailScreen() : WindowBase("openmw_jail_screen.layout"), - mTimeAdvancer(0.01f), mDays(1), - mFadeTimeRemaining(0) + mFadeTimeRemaining(0), + mTimeAdvancer(0.01f) { getWidget(mProgressBar, "ProgressBar"); diff --git a/apps/openmw/mwgui/journalbooks.cpp b/apps/openmw/mwgui/journalbooks.cpp index 34a852562..f84fb517b 100644 --- a/apps/openmw/mwgui/journalbooks.cpp +++ b/apps/openmw/mwgui/journalbooks.cpp @@ -68,8 +68,8 @@ namespace AddJournalEntry (MWGui::BookTypesetter::Ptr typesetter, MWGui::BookTypesetter::Style* body_style, MWGui::BookTypesetter::Style* header_style, bool add_header) : AddEntry (typesetter, body_style), - mHeaderStyle (header_style), - mAddHeader (add_header) + mAddHeader (add_header), + mHeaderStyle (header_style) { } @@ -94,7 +94,7 @@ namespace AddTopicEntry (MWGui::BookTypesetter::Ptr typesetter, MWGui::BookTypesetter::Style* body_style, MWGui::BookTypesetter::Style* header_style, intptr_t contentId) : - AddEntry (typesetter, body_style), mHeaderStyle (header_style), mContentId (contentId) + AddEntry (typesetter, body_style), mContentId (contentId), mHeaderStyle (header_style) { } diff --git a/apps/openmw/mwgui/journalviewmodel.cpp b/apps/openmw/mwgui/journalviewmodel.cpp index 9a47070c2..d05257e46 100644 --- a/apps/openmw/mwgui/journalviewmodel.cpp +++ b/apps/openmw/mwgui/journalviewmodel.cpp @@ -92,7 +92,7 @@ struct JournalViewModelImpl : JournalViewModel JournalViewModelImpl const * mModel; BaseEntry (JournalViewModelImpl const * model, iterator_t itr) : - mModel (model), itr (itr), loaded (false) + itr (itr), mModel (model), loaded (false) {} virtual ~BaseEntry () {} diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index 3204c6548..db7b32018 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -32,11 +32,11 @@ namespace MWGui { LoadingScreen::LoadingScreen(Ogre::SceneManager* sceneMgr, Ogre::RenderWindow* rw) - : mSceneMgr(sceneMgr) + : WindowBase("openmw_loading_screen.layout") + , mSceneMgr(sceneMgr) , mWindow(rw) - , WindowBase("openmw_loading_screen.layout") - , mLastRenderTime(0) , mLastWallpaperChangeTime(0) + , mLastRenderTime(0) , mProgress(0) , mVSyncWasEnabled(false) { diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 9adfeffe8..c59432796 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -144,16 +144,16 @@ namespace MWGui : mCurX(0) , mCurY(0) , mInterior(false) - , mFogOfWar(true) , mLocalMap(NULL) + , mCompass(NULL) , mPrefix() , mChanged(true) + , mFogOfWar(true) + , mMapWidgetSize(0) + , mCustomMarkers(markers) + , mMarkerUpdateTimer(0.0f) , mLastDirectionX(0.0f) , mLastDirectionY(0.0f) - , mCompass(NULL) - , mMarkerUpdateTimer(0.0f) - , mCustomMarkers(markers) - , mMapWidgetSize(0) { mCustomMarkers.eventMarkersChanged += MyGUI::newDelegate(this, &LocalMapBase::updateCustomMarkers); } @@ -550,16 +550,16 @@ namespace MWGui MapWindow::MapWindow(CustomMarkerCollection &customMarkers, DragAndDrop* drag, const std::string& cacheDir) : WindowPinnableBase("openmw_map_window.layout") - , NoDrop(drag, mMainWidget) , LocalMapBase(customMarkers) - , mGlobal(false) + , NoDrop(drag, mMainWidget) , mGlobalMap(0) - , mGlobalMapRender(0) - , mEditNoteDialog() - , mEventBoxGlobal(NULL) - , mEventBoxLocal(NULL) , mGlobalMapImage(NULL) , mGlobalMapOverlay(NULL) + , mGlobal(false) + , mEventBoxGlobal(NULL) + , mEventBoxLocal(NULL) + , mGlobalMapRender(0) + , mEditNoteDialog() { static bool registered = false; if (!registered) diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index b7c67e68b..6e81ed626 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -161,10 +161,10 @@ namespace MWGui MessageBox::MessageBox(MessageBoxManager& parMessageBoxManager, const std::string& message) : Layout("openmw_messagebox.layout") - , mMessageBoxManager(parMessageBoxManager) - , mMessage(message) , mCurrentTime(0) , mMaxTime(0) + , mMessageBoxManager(parMessageBoxManager) + , mMessage(message) { // defines mBottomPadding = 48; @@ -195,8 +195,8 @@ namespace MWGui InteractiveMessageBox::InteractiveMessageBox(MessageBoxManager& parMessageBoxManager, const std::string& message, const std::vector& buttons) : WindowModal("openmw_interactive_messagebox.layout") , mMessageBoxManager(parMessageBoxManager) + , mTextButtonPadding(0) , mButtonPressed(-1) - , mTextButtonPadding(0) { WindowModal::open(); diff --git a/apps/openmw/mwgui/sortfilteritemmodel.cpp b/apps/openmw/mwgui/sortfilteritemmodel.cpp index 6c164df88..183ab07ff 100644 --- a/apps/openmw/mwgui/sortfilteritemmodel.cpp +++ b/apps/openmw/mwgui/sortfilteritemmodel.cpp @@ -70,9 +70,9 @@ namespace MWGui SortFilterItemModel::SortFilterItemModel(ItemModel *sourceModel) : mCategory(Category_All) + , mFilter(0) , mShowEquipped(true) , mSortByType(true) - , mFilter(0) { mSourceModel = sourceModel; } diff --git a/apps/openmw/mwgui/spellbuyingwindow.cpp b/apps/openmw/mwgui/spellbuyingwindow.cpp index 76a1d51e5..ae7b7588a 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.cpp +++ b/apps/openmw/mwgui/spellbuyingwindow.cpp @@ -23,8 +23,8 @@ namespace MWGui SpellBuyingWindow::SpellBuyingWindow() : WindowBase("openmw_spell_buying_window.layout") - , mCurrentY(0) , mLastPos(0) + , mCurrentY(0) { setCoord(0, 0, 450, 300); diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index c744d3ed6..1c670838f 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -483,15 +483,15 @@ namespace MWGui EffectEditorBase::EffectEditorBase(Type type) - : mAddEffectDialog() - , mAvailableEffectsList(NULL) + : mAvailableEffectsList(NULL) , mUsedEffectsView(NULL) + , mAddEffectDialog() , mSelectAttributeDialog(NULL) , mSelectSkillDialog(NULL) , mSelectedEffect(0) , mSelectedKnownEffectId(0) - , mType(type) , mConstantEffect(false) + , mType(type) { mAddEffectDialog.eventEffectAdded += MyGUI::newDelegate(this, &EffectEditorBase::onEffectAdded); mAddEffectDialog.eventEffectModified += MyGUI::newDelegate(this, &EffectEditorBase::onEffectModified); diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 4e83c25db..34896c0bd 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -30,15 +30,15 @@ namespace MWGui ToolTips::ToolTips() : Layout("openmw_tooltips.layout") - , mFullHelp(false) - , mEnabled(true) , mFocusToolTipX(0.0) , mFocusToolTipY(0.0) + , mHorizontalScrollIndex(0) , mDelay(0.0) , mRemainingDelay(0.0) , mLastMouseX(0) , mLastMouseY(0) - , mHorizontalScrollIndex(0) + , mEnabled(true) + , mFullHelp(false) { getWidget(mDynamicToolTipBox, "DynamicToolTipBox"); diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index 28e3be591..ed261e7eb 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -50,13 +50,13 @@ namespace MWGui WaitDialog::WaitDialog() : WindowBase("openmw_wait_dialog.layout") - , mProgressBar() , mTimeAdvancer(0.05f) , mSleeping(false) , mHours(1) , mManualHours(1) , mFadeTimeRemaining(0) , mInterruptAt(-1) + , mProgressBar() { getWidget(mDateTimeText, "DateTimeText"); getWidget(mRestText, "RestText"); diff --git a/apps/openmw/mwgui/windowbase.cpp b/apps/openmw/mwgui/windowbase.cpp index 8fdcf6b20..899f8a5e8 100644 --- a/apps/openmw/mwgui/windowbase.cpp +++ b/apps/openmw/mwgui/windowbase.cpp @@ -78,7 +78,7 @@ void WindowModal::close() } NoDrop::NoDrop(DragAndDrop *drag, MyGUI::Widget *widget) - : mDrag(drag), mWidget(widget), mTransparent(false) + : mWidget(widget), mDrag(drag), mTransparent(false) { if (!mWidget) throw std::runtime_error("NoDrop needs a non-NULL widget!"); diff --git a/apps/openmw/mwmechanics/aiavoiddoor.cpp b/apps/openmw/mwmechanics/aiavoiddoor.cpp index a73d955c5..fccace55c 100644 --- a/apps/openmw/mwmechanics/aiavoiddoor.cpp +++ b/apps/openmw/mwmechanics/aiavoiddoor.cpp @@ -13,7 +13,7 @@ #include "steering.hpp" MWMechanics::AiAvoidDoor::AiAvoidDoor(const MWWorld::Ptr& doorPtr) -: AiPackage(), mDoorPtr(doorPtr), mDuration(1), mAdjAngle(0) +: AiPackage(), mDuration(1), mDoorPtr(doorPtr), mAdjAngle(0) { } diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 2f68087e5..649f259d9 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -111,17 +111,17 @@ namespace MWMechanics mTimerAttack(0), mTimerReact(0), mTimerCombatMove(0), + mReadyToAttack(false), mAttack(false), mFollowTarget(false), mCombatMove(false), - mReadyToAttack(false), - mForceNoShortcut(false), + mLastTargetPos(0,0,0), mCell(NULL), mCurrentAction(), mActionCooldown(0), mStrength(), mMinMaxAttackDurationInitialised(false), - mLastTargetPos(0,0,0), + mForceNoShortcut(false), mLastActorPos(0,0,0), mMovement(){} }; diff --git a/apps/openmw/mwmechanics/aiescort.cpp b/apps/openmw/mwmechanics/aiescort.cpp index 91bf7c9b0..f9ebefe13 100644 --- a/apps/openmw/mwmechanics/aiescort.cpp +++ b/apps/openmw/mwmechanics/aiescort.cpp @@ -49,12 +49,11 @@ namespace MWMechanics } AiEscort::AiEscort(const ESM::AiSequence::AiEscort *escort) - : mActorId(escort->mTargetId), mX(escort->mData.mX), mY(escort->mData.mY), mZ(escort->mData.mZ) + : mActorId(escort->mTargetId), mCellId(escort->mCellId), mX(escort->mData.mX), mY(escort->mData.mY), mZ(escort->mData.mZ) + , mMaxDist(450) + , mRemainingDuration(escort->mRemainingDuration) , mCellX(std::numeric_limits::max()) , mCellY(std::numeric_limits::max()) - , mCellId(escort->mCellId) - , mRemainingDuration(escort->mRemainingDuration) - , mMaxDist(450) { } diff --git a/apps/openmw/mwmechanics/aifollow.cpp b/apps/openmw/mwmechanics/aifollow.cpp index 161f4bb90..ddfc14581 100644 --- a/apps/openmw/mwmechanics/aifollow.cpp +++ b/apps/openmw/mwmechanics/aifollow.cpp @@ -32,27 +32,27 @@ int AiFollow::mFollowIndexCounter = 0; AiFollow::AiFollow(const std::string &actorId,float duration, float x, float y, float z) : mAlwaysFollow(false), mCommanded(false), mRemainingDuration(duration), mX(x), mY(y), mZ(z) -, mActorRefId(actorId), mCellId(""), mActorId(-1), mFollowIndex(mFollowIndexCounter++), mActive(false) +, mActorRefId(actorId), mActorId(-1), mCellId(""), mActive(false), mFollowIndex(mFollowIndexCounter++) { } AiFollow::AiFollow(const std::string &actorId,const std::string &cellId,float duration, float x, float y, float z) : mAlwaysFollow(false), mCommanded(false), mRemainingDuration(duration), mX(x), mY(y), mZ(z) -, mActorRefId(actorId), mCellId(cellId), mActorId(-1), mFollowIndex(mFollowIndexCounter++), mActive(false) +, mActorRefId(actorId), mActorId(-1), mCellId(cellId), mActive(false), mFollowIndex(mFollowIndexCounter++) { } AiFollow::AiFollow(const std::string &actorId, bool commanded) : mAlwaysFollow(true), mCommanded(commanded), mRemainingDuration(0), mX(0), mY(0), mZ(0) -, mActorRefId(actorId), mCellId(""), mActorId(-1), mFollowIndex(mFollowIndexCounter++), mActive(false) +, mActorRefId(actorId), mActorId(-1), mCellId(""), mActive(false), mFollowIndex(mFollowIndexCounter++) { } AiFollow::AiFollow(const ESM::AiSequence::AiFollow *follow) - : mAlwaysFollow(follow->mAlwaysFollow), mRemainingDuration(follow->mRemainingDuration) + : mAlwaysFollow(follow->mAlwaysFollow), mCommanded(follow->mCommanded), mRemainingDuration(follow->mRemainingDuration) , mX(follow->mData.mX), mY(follow->mData.mY), mZ(follow->mData.mZ) - , mActorRefId(follow->mTargetId), mActorId(-1), mCellId(follow->mCellId) - , mCommanded(follow->mCommanded), mFollowIndex(mFollowIndexCounter++), mActive(follow->mActive) + , mActorRefId(follow->mTargetId), mActorId(-1) + , mCellId(follow->mCellId), mActive(follow->mActive), mFollowIndex(mFollowIndexCounter++) { } diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 560e756ce..076636974 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -786,10 +786,10 @@ namespace MWMechanics AiWander::AiWander (const ESM::AiSequence::AiWander* wander) : mDistance(wander->mData.mDistance) , mDuration(wander->mData.mDuration) - , mStartTime(MWWorld::TimeStamp(wander->mStartTime)) , mTimeOfDay(wander->mData.mTimeOfDay) , mRepeat(wander->mData.mShouldRepeat != 0) , mStoredInitialActorPosition(wander->mStoredInitialActorPosition) + , mStartTime(MWWorld::TimeStamp(wander->mStartTime)) { if (mStoredInitialActorPosition) mInitialActorPosition = wander->mInitialActorPosition; diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index ffde59aee..399b51151 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -642,8 +642,8 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim , mJumpState(JumpState_None) , mWeaponType(WeapType_None) , mSkipAnim(false) - , mSecondsOfRunning(0) , mSecondsOfSwimming(0) + , mSecondsOfRunning(0) , mTurnAnimationThreshold(0) { if(!mAnimation) diff --git a/apps/openmw/mwmechanics/creaturestats.cpp b/apps/openmw/mwmechanics/creaturestats.cpp index 4c338e23f..308e72027 100644 --- a/apps/openmw/mwmechanics/creaturestats.cpp +++ b/apps/openmw/mwmechanics/creaturestats.cpp @@ -15,16 +15,12 @@ namespace MWMechanics int CreatureStats::sActorId = 0; CreatureStats::CreatureStats() - : mLevel (0), mDead (false), mDied (false), mMurdered(false), mFriendlyHits (0), - mTalkedTo (false), mAlarmed (false), - mAttacked (false), - mAttackingOrSpell(false), - mIsWerewolf(false), - mFallHeight(0), mRecalcMagicka(false), mKnockdown(false), mKnockdownOneFrame(false), - mKnockdownOverOneFrame(false), mHitRecovery(false), mBlock(false), - mMovementFlags(0), mDrawState (DrawState_Nothing), mAttackStrength(0.f), - mLastRestock(0,0), mGoldPool(0), mActorId(-1), - mDeathAnimation(0) + : mDrawState (DrawState_Nothing), mDead (false), mDied (false), mMurdered(false), mFriendlyHits (0), + mTalkedTo (false), mAlarmed (false), mAttacked (false), mAttackingOrSpell(false), + mKnockdown(false), mKnockdownOneFrame(false), mKnockdownOverOneFrame(false), + mHitRecovery(false), mBlock(false), mMovementFlags(0), mAttackStrength(0.f), + mFallHeight(0), mRecalcMagicka(false), mLastRestock(0,0), mGoldPool(0), mActorId(-1), + mDeathAnimation(0), mIsWerewolf(false), mLevel (0) { for (int i=0; i<4; ++i) mAiSettings[i] = 0; diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index 7f468f6d4..94819e626 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -25,12 +25,12 @@ #include "../mwbase/soundmanager.hpp" MWMechanics::NpcStats::NpcStats() - : mBounty (0) -, mLevelProgress(0) -, mDisposition(0) + : mDisposition (0) , mReputation(0) , mCrimeId(-1) +, mBounty(0) , mWerewolfKills (0) +, mLevelProgress(0) , mTimeToStartDrowning(20.0) { mSkillIncreases.resize (ESM::Attribute::Length, 0); diff --git a/apps/openmw/mwmechanics/obstacle.cpp b/apps/openmw/mwmechanics/obstacle.cpp index 6bf81e861..7cfa6fcd5 100644 --- a/apps/openmw/mwmechanics/obstacle.cpp +++ b/apps/openmw/mwmechanics/obstacle.cpp @@ -63,10 +63,10 @@ namespace MWMechanics ObstacleCheck::ObstacleCheck(): mPrevX(0) // to see if the moved since last time , mPrevY(0) - , mDistSameSpot(-1) // avoid calculating it each time , mWalkState(State_Norm) , mStuckDuration(0) , mEvadeDuration(0) + , mDistSameSpot(-1) // avoid calculating it each time { } diff --git a/apps/openmw/mwmechanics/pathgrid.cpp b/apps/openmw/mwmechanics/pathgrid.cpp index c1e094bb1..4e9bc8904 100644 --- a/apps/openmw/mwmechanics/pathgrid.cpp +++ b/apps/openmw/mwmechanics/pathgrid.cpp @@ -51,12 +51,12 @@ namespace MWMechanics { PathgridGraph::PathgridGraph() : mCell(NULL) - , mIsGraphConstructed(false) , mPathgrid(NULL) + , mIsExterior(0) , mGraph(0) + , mIsGraphConstructed(false) , mSCCId(0) , mSCCIndex(0) - , mIsExterior(0) { } diff --git a/apps/openmw/mwrender/globalmap.cpp b/apps/openmw/mwrender/globalmap.cpp index 95d4429d6..90cf27049 100644 --- a/apps/openmw/mwrender/globalmap.cpp +++ b/apps/openmw/mwrender/globalmap.cpp @@ -25,10 +25,11 @@ namespace MWRender GlobalMap::GlobalMap(const std::string &cacheDir) : mCacheDir(cacheDir) - , mMinX(0), mMaxX(0) - , mMinY(0), mMaxY(0) , mWidth(0) , mHeight(0) + , mMinX(0), mMaxX(0) + , mMinY(0), mMaxY(0) + { mCellSize = Settings::Manager::getInt("global map cell size", "Map"); } diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index a16b156ae..f2175ced5 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -186,10 +186,10 @@ void PlaneReflection::setVisibilityMask (int flags) Water::Water (Ogre::Camera *camera, RenderingManager* rend, const MWWorld::Fallback* fallback) : mCamera (camera), mSceneMgr (camera->getSceneManager()), - mIsUnderwater(false), mVisibilityFlags(0), - mActive(1), mToggled(1), + mIsUnderwater(false), mActive(1), + mToggled(1), mWaterTimer(0.f), mRendering(rend), - mWaterTimer(0.f), + mVisibilityFlags(0), mReflection(NULL), mRefraction(NULL), mSimulation(NULL), diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 06c40dd8e..c7fb9ea50 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -33,13 +33,13 @@ namespace MWSound , mMasterVolume(1.0f) , mSFXVolume(1.0f) , mMusicVolume(1.0f) - , mFootstepsVolume(1.0f) , mVoiceVolume(1.0f) - , mPausedSoundTypes(0) + , mFootstepsVolume(1.0f) + , mListenerUnderwater(false) , mListenerPos(0,0,0) , mListenerDir(1,0,0) , mListenerUp(0,0,1) - , mListenerUnderwater(false) + , mPausedSoundTypes(0) { if(!useSound) return; diff --git a/apps/openmw/mwworld/action.cpp b/apps/openmw/mwworld/action.cpp index 1c360fd4d..5e1fb41a6 100644 --- a/apps/openmw/mwworld/action.cpp +++ b/apps/openmw/mwworld/action.cpp @@ -11,7 +11,7 @@ const MWWorld::Ptr& MWWorld::Action::getTarget() const return mTarget; } -MWWorld::Action::Action (bool keepSound, const Ptr& target) : mKeepSound (keepSound), mTarget (target), mSoundOffset(0) +MWWorld::Action::Action (bool keepSound, const Ptr& target) : mKeepSound (keepSound), mSoundOffset(0), mTarget (target) {} MWWorld::Action::~Action() {} diff --git a/apps/openmw/mwworld/esmloader.cpp b/apps/openmw/mwworld/esmloader.cpp index 13a786d00..b12d646e7 100644 --- a/apps/openmw/mwworld/esmloader.cpp +++ b/apps/openmw/mwworld/esmloader.cpp @@ -9,8 +9,8 @@ namespace MWWorld EsmLoader::EsmLoader(MWWorld::ESMStore& store, std::vector& readers, ToUTF8::Utf8Encoder* encoder, Loading::Listener& listener) : ContentLoader(listener) - , mStore(store) , mEsm(readers) + , mStore(store) , mEncoder(encoder) { } diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 2de3abc75..a2e445d58 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -96,10 +96,10 @@ void MWWorld::InventoryStore::readEquipmentState(const MWWorld::ContainerStoreIt } MWWorld::InventoryStore::InventoryStore() - : mSelectedEnchantItem(end()) + : mListener(NULL) , mUpdatesEnabled (true) , mFirstAutoEquip(true) - , mListener(NULL) + , mSelectedEnchantItem(end()) , mRechargingItemsUpToDate(false) { initSlots (mSlots); @@ -107,12 +107,12 @@ MWWorld::InventoryStore::InventoryStore() MWWorld::InventoryStore::InventoryStore (const InventoryStore& store) : ContainerStore (store) - , mSelectedEnchantItem(end()) , mMagicEffects(store.mMagicEffects) - , mFirstAutoEquip(store.mFirstAutoEquip) , mListener(store.mListener) , mUpdatesEnabled(store.mUpdatesEnabled) + , mFirstAutoEquip(store.mFirstAutoEquip) , mPermanentMagicEffectMagnitudes(store.mPermanentMagicEffectMagnitudes) + , mSelectedEnchantItem(end()) , mRechargingItemsUpToDate(false) { copySlots (store); diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index d31ae520b..bec4c6db3 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -499,7 +499,7 @@ namespace MWWorld PhysicsSystem::PhysicsSystem(OEngine::Render::OgreRenderer &_rend) : - mRender(_rend), mEngine(0), mTimeAccum(0.0f), mWaterEnabled(false), mWaterHeight(0) + mRender(_rend), mEngine(0), mTimeAccum(0.0f), mWaterHeight(0), mWaterEnabled(false) { // Create physics. shapeLoader is deleted by the physic engine NifBullet::ManualBulletShapeLoader* shapeLoader = new NifBullet::ManualBulletShapeLoader(); diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index 58718074e..0b81532e1 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -32,10 +32,10 @@ namespace MWWorld Player::Player (const ESM::NPC *player, const MWBase::World& world) : mCellStore(0), mLastKnownExteriorPosition(0,0,0), + mMarkedCell(NULL), mAutoMove(false), mForwardBackward(0), mTeleported(false), - mMarkedCell(NULL), mCurrentCrimeId(-1), mPaidCrimeId(-1) { diff --git a/apps/openmw/mwworld/refdata.cpp b/apps/openmw/mwworld/refdata.cpp index 14a315a81..ae985f857 100644 --- a/apps/openmw/mwworld/refdata.cpp +++ b/apps/openmw/mwworld/refdata.cpp @@ -37,7 +37,7 @@ namespace MWWorld } RefData::RefData() - : mBaseNode(0), mHasLocals (false), mEnabled (true), mCount (1), mCustomData (0), mChanged(false), mDeleted(false) + : mBaseNode(0), mDeleted(false), mHasLocals (false), mEnabled (true), mCount (1), mCustomData (0), mChanged(false) { for (int i=0; i<3; ++i) { @@ -48,10 +48,10 @@ namespace MWWorld } RefData::RefData (const ESM::CellRef& cellRef) - : mBaseNode(0), mHasLocals (false), mEnabled (true), mCount (1), mPosition (cellRef.mPos), + : mBaseNode(0), mDeleted(false), mHasLocals (false), mEnabled (true), + mCount (1), mPosition (cellRef.mPos), mCustomData (0), - mChanged(false), // Loading from ESM/ESP files -> assume unchanged - mDeleted(false) + mChanged(false) // Loading from ESM/ESP files -> assume unchanged { mLocalRotation.rot[0]=0; mLocalRotation.rot[1]=0; @@ -59,10 +59,12 @@ namespace MWWorld } RefData::RefData (const ESM::ObjectState& objectState) - : mBaseNode (0), mHasLocals (false), mEnabled (objectState.mEnabled != 0), - mCount (objectState.mCount), mPosition (objectState.mPosition), mCustomData (0), - mChanged(true), // Loading from a savegame -> assume changed - mDeleted(false) + : mBaseNode (0), mDeleted(false), mHasLocals (false), + mEnabled (objectState.mEnabled != 0), + mCount (objectState.mCount), + mPosition (objectState.mPosition), + mCustomData (0), + mChanged(true) // Loading from a savegame -> assume changed { for (int i=0; i<3; ++i) mLocalRotation.rot[i] = objectState.mLocalRotation[i]; diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index a9ca8e72b..41ed7c20d 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -114,11 +114,10 @@ float WeatherManager::calculateAngleFade (const std::string& moonName, float ang } WeatherManager::WeatherManager(MWRender::RenderingManager* rendering,MWWorld::Fallback* fallback) : - mHour(14), mCurrentWeather("clear"), mNextWeather(""), mFirstUpdate(true), - mWeatherUpdateTime(0), mThunderFlash(0), mThunderChance(0), - mThunderChanceNeeded(50), mThunderSoundDelay(0), mRemainingTransitionTime(0), - mTimePassed(0), mFallback(fallback), mWindSpeed(0.f), mRendering(rendering), mIsStorm(false), - mStormDirection(0,1,0) + mHour(14), mWindSpeed(0.f), mIsStorm(false), mStormDirection(0,1,0), mFallback(fallback), + mRendering(rendering), mCurrentWeather("clear"), mNextWeather(""), mFirstUpdate(true), + mRemainingTransitionTime(0), mThunderFlash(0), mThunderChance(0), mThunderChanceNeeded(50), + mTimePassed(0), mWeatherUpdateTime(0), mThunderSoundDelay(0) { //Globals mThunderSoundID0 = mFallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_0"); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index bb0402c4e..b1bac2f4b 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -147,14 +147,12 @@ namespace MWWorld const boost::filesystem::path& resDir, const boost::filesystem::path& cacheDir, ToUTF8::Utf8Encoder* encoder, const std::map& fallbackMap, int activationDistanceOverride, const std::string& startCell, const std::string& startupScript) - : mPlayer (0), mLocalScripts (mStore), + : mFallback(fallbackMap), mPlayer (0), mLocalScripts (mStore), mSky (true), mCells (mStore, mEsm), - mActivationDistanceOverride (activationDistanceOverride), - mFallback(fallbackMap), mTeleportEnabled(true), mLevitationEnabled(true), - mGodMode(false), mContentFiles (contentFiles), - mGoToJail(false), mDaysInPrison(0), - mStartCell (startCell), mStartupScript(startupScript), - mScriptsEnabled(true) + mGodMode(false), mScriptsEnabled(true), mContentFiles (contentFiles), + mActivationDistanceOverride (activationDistanceOverride), mStartupScript(startupScript), + mStartCell (startCell), mTeleportEnabled(true), + mLevitationEnabled(true), mGoToJail(false), mDaysInPrison(0) { mPhysics = new PhysicsSystem(renderer); mPhysEngine = mPhysics->getEngine(); @@ -2939,7 +2937,7 @@ namespace MWWorld struct AddDetectedReference { AddDetectedReference(std::vector& out, Ptr detector, World::DetectionType type, float squaredDist) - : mOut(out), mDetector(detector), mType(type), mSquaredDist(squaredDist) + : mOut(out), mDetector(detector), mSquaredDist(squaredDist), mType(type) { } diff --git a/components/compiler/lineparser.cpp b/components/compiler/lineparser.cpp index 88b5f5ddb..a71672916 100644 --- a/components/compiler/lineparser.cpp +++ b/components/compiler/lineparser.cpp @@ -56,8 +56,8 @@ namespace Compiler LineParser::LineParser (ErrorHandler& errorHandler, const Context& context, Locals& locals, Literals& literals, std::vector& code, bool allowExpression) : Parser (errorHandler, context), mLocals (locals), mLiterals (literals), mCode (code), - mState (BeginState), mExprParser (errorHandler, context, locals, literals), - mAllowExpression (allowExpression), mButtons(0), mType(0), mReferenceMember(false) + mState (BeginState), mReferenceMember(false), mButtons(0), mType(0), + mExprParser (errorHandler, context, locals, literals), mAllowExpression (allowExpression) {} bool LineParser::parseInt (int value, const TokenLoc& loc, Scanner& scanner) diff --git a/components/interpreter/runtime.cpp b/components/interpreter/runtime.cpp index c71aef95c..dc3da07a8 100644 --- a/components/interpreter/runtime.cpp +++ b/components/interpreter/runtime.cpp @@ -7,7 +7,7 @@ namespace Interpreter { - Runtime::Runtime() : mContext (0), mCode (0), mPC (0), mCodeSize(0) {} + Runtime::Runtime() : mContext (0), mCode (0), mCodeSize(0), mPC (0) {} int Runtime::getPC() const { diff --git a/extern/ogre-ffmpeg-videoplayer/audiodecoder.cpp b/extern/ogre-ffmpeg-videoplayer/audiodecoder.cpp index 1a56802da..77e6b4b6c 100644 --- a/extern/ogre-ffmpeg-videoplayer/audiodecoder.cpp +++ b/extern/ogre-ffmpeg-videoplayer/audiodecoder.cpp @@ -60,21 +60,21 @@ struct AudioResampler MovieAudioDecoder::MovieAudioDecoder(VideoState* videoState) : mVideoState(videoState) , mAVStream(*videoState->audio_st) - , mFrame(av_frame_alloc()) + , mOutputSampleFormat(AV_SAMPLE_FMT_NONE) + , mOutputChannelLayout(0) + , mOutputSampleRate(0) , mFramePos(0) , mFrameSize(0) , mAudioClock(0.0) + , mDataBuf(NULL) + , mFrameData(NULL) + , mDataBufLen(0) + , mFrame(av_frame_alloc()) , mAudioDiffAccum(0.0) , mAudioDiffAvgCoef(exp(log(0.01 / AUDIO_DIFF_AVG_NB))) /* Correct audio only if larger error than this */ , mAudioDiffThreshold(2.0 * 0.050/* 50 ms */) , mAudioDiffAvgCount(0) - , mOutputSampleFormat(AV_SAMPLE_FMT_NONE) - , mOutputSampleRate(0) - , mOutputChannelLayout(0) - , mDataBuf(NULL) - , mFrameData(NULL) - , mDataBufLen(0) { mAudioResampler.reset(new AudioResampler()); } diff --git a/extern/ogre-ffmpeg-videoplayer/videostate.cpp b/extern/ogre-ffmpeg-videoplayer/videostate.cpp index 66c7c2ad5..877906f6d 100644 --- a/extern/ogre-ffmpeg-videoplayer/videostate.cpp +++ b/extern/ogre-ffmpeg-videoplayer/videostate.cpp @@ -59,16 +59,18 @@ namespace Video { VideoState::VideoState() - : format_ctx(NULL), av_sync_type(AV_SYNC_DEFAULT) + : mAudioFactory(NULL) + , format_ctx(NULL) + , av_sync_type(AV_SYNC_DEFAULT) , audio_st(NULL) , video_st(NULL), frame_last_pts(0.0) , video_clock(0.0), sws_context(NULL), rgbaFrame(NULL), pictq_size(0) , pictq_rindex(0), pictq_windex(0) - , mQuit(false), mPaused(false) - , mAudioFactory(NULL) , mSeekRequested(false) , mSeekPos(0) , mVideoEnded(false) + , mPaused(false) + , mQuit(false) { mFlushPktData = flush_pkt.data; diff --git a/extern/oics/ICSControl.cpp b/extern/oics/ICSControl.cpp index 974d69f08..1e9679d1f 100644 --- a/extern/oics/ICSControl.cpp +++ b/extern/oics/ICSControl.cpp @@ -32,9 +32,9 @@ namespace ICS { Control::Control(const std::string& name, bool autoChangeDirectionOnLimitsAfterStop, bool autoReverseToInitialValue , float initialValue, float stepSize, float stepsPerSeconds, bool axisBindable) - : mName(name) - , mValue(initialValue) + : mValue(initialValue) , mInitialValue(initialValue) + , mName(name) , mStepSize(stepSize) , mStepsPerSeconds(stepsPerSeconds) , mAutoReverseToInitialValue(autoReverseToInitialValue) diff --git a/extern/oics/ICSInputControlSystem.cpp b/extern/oics/ICSInputControlSystem.cpp index 2599c5761..a8aedfd2e 100644 --- a/extern/oics/ICSInputControlSystem.cpp +++ b/extern/oics/ICSInputControlSystem.cpp @@ -32,13 +32,13 @@ namespace ICS , DetectingBindingListener* detectingBindingListener , InputControlSystemLog* log, size_t channelCount) : mFileName(file) + , mLog(log) , mDetectingBindingListener(detectingBindingListener) , mDetectingBindingControl(NULL) - , mLog(log) - , mXmouseAxisBinded(false), mYmouseAxisBinded(false) - , mClientHeight(1) - , mClientWidth(1) , mDetectingBindingDirection(Control::STOP) + , mXmouseAxisBinded(false), mYmouseAxisBinded(false) + , mClientWidth(1) + , mClientHeight(1) { ICS_LOG(" - Creating InputControlSystem - "); @@ -539,10 +539,10 @@ namespace ICS } binder.SetAttribute( "direction", "DECREASE" ); control.InsertEndChild(binder); - } - JoystickIDList::const_iterator it = mJoystickIDList.begin(); - while(it!=mJoystickIDList.end()) - { + } + JoystickIDList::const_iterator it = mJoystickIDList.begin(); + while(it!=mJoystickIDList.end()) + { int deviceID = *it; if(getJoystickAxisBinding(*o, deviceID, Control/*::ControlChangingDirection*/::INCREASE) != /*NamedAxis::*/UNASSIGNED) @@ -552,8 +552,8 @@ namespace ICS binder.SetAttribute( "axis", ToString( getJoystickAxisBinding(*o, deviceID, Control/*::ControlChangingDirection*/::INCREASE)).c_str() ); - binder.SetAttribute( "direction", "INCREASE" ); - + binder.SetAttribute( "direction", "INCREASE" ); + binder.SetAttribute( "deviceId", deviceID ); //completely useless, but required for backwards compatability control.InsertEndChild(binder); @@ -567,8 +567,8 @@ namespace ICS binder.SetAttribute( "axis", ToString( getJoystickAxisBinding(*o, deviceID, Control/*::ControlChangingDirection*/::DECREASE)).c_str() ); - binder.SetAttribute( "direction", "DECREASE" ); - + binder.SetAttribute( "direction", "DECREASE" ); + binder.SetAttribute( "deviceId", deviceID ); //completely useless, but required for backwards compatability control.InsertEndChild(binder); @@ -582,8 +582,8 @@ namespace ICS binder.SetAttribute( "button", ToString( getJoystickButtonBinding(*o, deviceID, Control/*::ControlChangingDirection*/::INCREASE)).c_str() ); - binder.SetAttribute( "direction", "INCREASE" ); - + binder.SetAttribute( "direction", "INCREASE" ); + binder.SetAttribute( "deviceId", deviceID ); //completely useless, but required for backwards compatability control.InsertEndChild(binder); @@ -597,13 +597,13 @@ namespace ICS binder.SetAttribute( "button", ToString( getJoystickButtonBinding(*o, deviceID, Control/*::ControlChangingDirection*/::DECREASE)).c_str() ); - binder.SetAttribute( "direction", "DECREASE" ); - + binder.SetAttribute( "direction", "DECREASE" ); + binder.SetAttribute( "deviceId", deviceID ); //completely useless, but required for backwards compatability control.InsertEndChild(binder); - } - it++; + } + it++; } diff --git a/extern/sdl4ogre/sdlinputwrapper.cpp b/extern/sdl4ogre/sdlinputwrapper.cpp index aaf669ff4..7e3536ab4 100644 --- a/extern/sdl4ogre/sdlinputwrapper.cpp +++ b/extern/sdl4ogre/sdlinputwrapper.cpp @@ -10,28 +10,28 @@ namespace SFO /// \brief General purpose wrapper for OGRE applications around SDL's event /// queue, mostly used for handling input-related events. InputWrapper::InputWrapper(SDL_Window* window, Ogre::RenderWindow* ogreWindow, bool grab) : - mSDLWindow(window), - mOgreWindow(ogreWindow), + mMouseListener(NULL), + mKeyboardListener(NULL), + mWindowListener(NULL), + mConListener(NULL), + mWarpX(0), + mWarpY(0), mWarpCompensate(false), - mMouseRelative(false), - mGrabPointer(false), mWrapPointer(false), + mAllowGrab(grab), + mWantMouseVisible(false), + mWantGrab(false), + mWantRelative(false), + mGrabPointer(false), + mMouseRelative(false), + mFirstMouseMove(true), mMouseZ(0), - mMouseY(0), mMouseX(0), - mMouseInWindow(true), - mConListener(NULL), - mKeyboardListener(NULL), - mMouseListener(NULL), - mWindowListener(NULL), + mMouseY(0), mWindowHasFocus(true), - mWantGrab(false), - mWantRelative(false), - mWantMouseVisible(false), - mAllowGrab(grab), - mWarpX(0), - mWarpY(0), - mFirstMouseMove(true) + mMouseInWindow(true), + mSDLWindow(window), + mOgreWindow(ogreWindow) { _setupOISKeys(); } diff --git a/extern/shiny/Main/Factory.cpp b/extern/shiny/Main/Factory.cpp index d7c4234cb..d0b86cbf9 100644 --- a/extern/shiny/Main/Factory.cpp +++ b/extern/shiny/Main/Factory.cpp @@ -29,17 +29,17 @@ namespace sh } Factory::Factory (Platform* platform) - : mPlatform(platform) - , mShadersEnabled(true) + : mShadersEnabled(true) , mShaderDebugOutputEnabled(false) - , mCurrentLanguage(Language_None) - , mListener(NULL) - , mCurrentConfiguration(NULL) - , mCurrentLodConfiguration(NULL) , mReadMicrocodeCache(false) , mWriteMicrocodeCache(false) , mReadSourceCache(false) , mWriteSourceCache(false) + , mCurrentConfiguration(NULL) + , mCurrentLodConfiguration(NULL) + , mCurrentLanguage(Language_None) + , mListener(NULL) + , mPlatform(platform) { assert (!sThis); sThis = this; diff --git a/extern/shiny/Main/MaterialInstance.cpp b/extern/shiny/Main/MaterialInstance.cpp index c69d13401..5d1a8e7f9 100644 --- a/extern/shiny/Main/MaterialInstance.cpp +++ b/extern/shiny/Main/MaterialInstance.cpp @@ -9,11 +9,11 @@ namespace sh { MaterialInstance::MaterialInstance (const std::string& name, Factory* f) - : mName(name) + : mFailedToCreate(false) + , mListener(NULL) + , mName(name) , mShadersEnabled(true) , mFactory(f) - , mListener(NULL) - , mFailedToCreate(false) { } diff --git a/extern/shiny/Main/Platform.cpp b/extern/shiny/Main/Platform.cpp index 3eb7f4ad3..f09956e0f 100644 --- a/extern/shiny/Main/Platform.cpp +++ b/extern/shiny/Main/Platform.cpp @@ -7,9 +7,9 @@ namespace sh { Platform::Platform (const std::string& basePath) - : mBasePath(basePath) - , mCacheFolder("./") + : mCacheFolder("./") , mFactory(NULL) + , mBasePath(basePath) { } diff --git a/extern/shiny/Main/ShaderSet.cpp b/extern/shiny/Main/ShaderSet.cpp index 8fb530d39..4e19948ad 100644 --- a/extern/shiny/Main/ShaderSet.cpp +++ b/extern/shiny/Main/ShaderSet.cpp @@ -15,9 +15,9 @@ namespace sh ShaderSet::ShaderSet (const std::string& type, const std::string& cgProfile, const std::string& hlslProfile, const std::string& sourceFile, const std::string& basePath, const std::string& name, PropertySetGet* globalSettingsPtr) : mBasePath(basePath) - , mName(name) , mCgProfile(cgProfile) , mHlslProfile(hlslProfile) + , mName(name) { if (type == "vertex") mType = GPT_Vertex; From d1b6289cad544ddf71b59c22e0edbc92404f81b1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 22 May 2015 19:56:39 +0200 Subject: [PATCH 1237/3725] Don't teleport followers when using teleportation spells --- apps/openmw/mwclass/door.cpp | 2 +- apps/openmw/mwgui/travelwindow.cpp | 2 +- apps/openmw/mwmechanics/spellcasting.cpp | 2 +- apps/openmw/mwworld/actionteleport.cpp | 25 +++++++++++++----------- apps/openmw/mwworld/actionteleport.hpp | 4 +++- apps/openmw/mwworld/worldimp.cpp | 2 +- 6 files changed, 21 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 2d39881b1..48fc3b64c 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -147,7 +147,7 @@ namespace MWClass if (ptr.getCellRef().getTeleport()) { - boost::shared_ptr action(new MWWorld::ActionTeleport (ptr.getCellRef().getDestCell(), ptr.getCellRef().getDoorDest())); + boost::shared_ptr action(new MWWorld::ActionTeleport (ptr.getCellRef().getDestCell(), ptr.getCellRef().getDoorDest(), true)); action->setSound(openSound); diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index 4da1ab33a..ba6fc2a78 100644 --- a/apps/openmw/mwgui/travelwindow.cpp +++ b/apps/openmw/mwgui/travelwindow.cpp @@ -183,7 +183,7 @@ namespace MWGui MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); // Teleports any followers, too. - MWWorld::ActionTeleport action(interior ? cellname : "", pos); + MWWorld::ActionTeleport action(interior ? cellname : "", pos, true); action.execute(player); MWBase::Environment::get().getWindowManager()->fadeScreenOut(0); diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 8a43cc932..1f3a88827 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -679,7 +679,7 @@ namespace MWMechanics if (markedCell) { MWWorld::ActionTeleport action(markedCell->isExterior() ? "" : markedCell->getCell()->mName, - markedPosition); + markedPosition, false); action.execute(target); } } diff --git a/apps/openmw/mwworld/actionteleport.cpp b/apps/openmw/mwworld/actionteleport.cpp index 8bbb08008..fccd176a8 100644 --- a/apps/openmw/mwworld/actionteleport.cpp +++ b/apps/openmw/mwworld/actionteleport.cpp @@ -25,23 +25,26 @@ namespace namespace MWWorld { ActionTeleport::ActionTeleport (const std::string& cellName, - const ESM::Position& position) - : Action (true), mCellName (cellName), mPosition (position) + const ESM::Position& position, bool teleportFollowers) + : Action (true), mCellName (cellName), mPosition (position), mTeleportFollowers(teleportFollowers) { } void ActionTeleport::executeImp (const Ptr& actor) { - //find any NPC that is following the actor and teleport him too - std::set followers; - getFollowers(actor, followers); - for(std::set::iterator it = followers.begin();it != followers.end();++it) + if (mTeleportFollowers) { - MWWorld::Ptr follower = *it; - if (Ogre::Vector3(follower.getRefData().getPosition().pos).squaredDistance( - Ogre::Vector3( actor.getRefData().getPosition().pos)) - <= 800*800) - teleport(*it); + //find any NPC that is following the actor and teleport him too + std::set followers; + getFollowers(actor, followers); + for(std::set::iterator it = followers.begin();it != followers.end();++it) + { + MWWorld::Ptr follower = *it; + if (Ogre::Vector3(follower.getRefData().getPosition().pos).squaredDistance( + Ogre::Vector3( actor.getRefData().getPosition().pos)) + <= 800*800) + teleport(*it); + } } teleport(actor); diff --git a/apps/openmw/mwworld/actionteleport.hpp b/apps/openmw/mwworld/actionteleport.hpp index 9ca664de8..6191ee9f6 100644 --- a/apps/openmw/mwworld/actionteleport.hpp +++ b/apps/openmw/mwworld/actionteleport.hpp @@ -13,6 +13,7 @@ namespace MWWorld { std::string mCellName; ESM::Position mPosition; + bool mTeleportFollowers; /// Teleports this actor and also teleports anyone following that actor. virtual void executeImp (const Ptr& actor); @@ -22,8 +23,9 @@ namespace MWWorld public: - ActionTeleport (const std::string& cellName, const ESM::Position& position); + ActionTeleport (const std::string& cellName, const ESM::Position& position, bool teleportFollowers); ///< If cellName is empty, an exterior cell is assumed. + /// @param teleportFollowers Whether to teleport any following actors of the target actor as well. }; } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index bb0402c4e..96fad106e 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2921,7 +2921,7 @@ namespace MWWorld if ( !closestMarker.mCell->isExterior() ) cellName = closestMarker.mCell->getCell()->mName; - MWWorld::ActionTeleport action(cellName, closestMarker.getRefData().getPosition()); + MWWorld::ActionTeleport action(cellName, closestMarker.getRefData().getPosition(), false); action.execute(ptr); } From 0fb59178b614530a2a1ce5bb0ce81140217e882f Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 22 May 2015 20:15:50 +0200 Subject: [PATCH 1238/3725] Settings file cleanup --- files/settings-default.cfg | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/files/settings-default.cfg b/files/settings-default.cfg index fc8571bf8..64ef4e302 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -87,13 +87,6 @@ crosshair = true [Objects] shaders = true -# Max. number of lights that affect objects. Setting to 1 will only reflect sunlight -# Note: has no effect when shaders are turned off -num lights = 8 - -# Use static geometry for static objects. Improves rendering speed. -use static geometry = true - [Map] # Adjusts the scale of the global map global map cell size = 18 @@ -114,12 +107,6 @@ exterior grid size = 3 # exact factor would depend on FOV viewing distance = 4600 -# Distance at which fog starts (proportional to viewing distance) -fog start factor = 0.5 - -# Distance at which fog ends (proportional to viewing distance) -fog end factor = 1.0 - # Culling of objects smaller than a pixel small feature culling = true From a5183aefbe41a99dd1481249bb180f3314966c81 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Fri, 22 May 2015 23:53:25 +0300 Subject: [PATCH 1239/3725] Add record state tracking to the ModifyCommand (Fix #2555) --- apps/opencs/model/world/commands.cpp | 15 ++++++++++++++- apps/opencs/model/world/commands.hpp | 4 ++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/world/commands.cpp b/apps/opencs/model/world/commands.cpp index 9a0401081..11cb91176 100644 --- a/apps/opencs/model/world/commands.cpp +++ b/apps/opencs/model/world/commands.cpp @@ -14,7 +14,7 @@ CSMWorld::ModifyCommand::ModifyCommand (QAbstractItemModel& model, const QModelIndex& index, const QVariant& new_, QUndoCommand* parent) -: QUndoCommand (parent), mModel (&model), mIndex (index), mNew (new_) +: QUndoCommand (parent), mModel (&model), mIndex (index), mNew (new_), mHasRecordState(false) { if (QAbstractProxyModel *proxy = dynamic_cast (&model)) { @@ -27,6 +27,15 @@ CSMWorld::ModifyCommand::ModifyCommand (QAbstractItemModel& model, const QModelI } else setText ("Modify " + mModel->headerData (mIndex.column(), Qt::Horizontal, Qt::DisplayRole).toString()); + + // Remember record state before the modification + if (CSMWorld::IdTable *table = dynamic_cast(mModel)) + { + mHasRecordState = true; + int stateColumnIndex = table->findColumnIndex(Columns::ColumnId_Modification); + mRecordStateIndex = table->index(mIndex.row(), stateColumnIndex); + mOldRecordState = static_cast(table->data(mRecordStateIndex).toInt()); + } } void CSMWorld::ModifyCommand::redo() @@ -38,6 +47,10 @@ void CSMWorld::ModifyCommand::redo() void CSMWorld::ModifyCommand::undo() { mModel->setData (mIndex, mOld); + if (mHasRecordState) + { + mModel->setData(mRecordStateIndex, mOldRecordState); + } } diff --git a/apps/opencs/model/world/commands.hpp b/apps/opencs/model/world/commands.hpp index f13376145..cdd398153 100644 --- a/apps/opencs/model/world/commands.hpp +++ b/apps/opencs/model/world/commands.hpp @@ -31,6 +31,10 @@ namespace CSMWorld QVariant mNew; QVariant mOld; + bool mHasRecordState; + QModelIndex mRecordStateIndex; + CSMWorld::RecordBase::State mOldRecordState; + public: ModifyCommand (QAbstractItemModel& model, const QModelIndex& index, const QVariant& new_, From 8092f37ce5e9ef6dd7009c703fd1c01f395f6b44 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 23 May 2015 05:40:24 +0200 Subject: [PATCH 1240/3725] New game crash fix --- apps/openmw/mwrender/camera.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/apps/openmw/mwrender/camera.cpp b/apps/openmw/mwrender/camera.cpp index a92f90158..3982e5ad4 100644 --- a/apps/openmw/mwrender/camera.cpp +++ b/apps/openmw/mwrender/camera.cpp @@ -351,12 +351,6 @@ namespace MWRender void Camera::setAnimation(NpcAnimation *anim) { - // If we're switching to a new NpcAnimation, ensure the old one is - // using a normal view mode - if(mAnimation && mAnimation != anim) - { - mAnimation->setViewMode(NpcAnimation::VM_Normal); - } mAnimation = anim; processViewChange(); From cd81ec92db13d8ca440b75b3a8b1fe21a8378b42 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 23 May 2015 05:41:53 +0200 Subject: [PATCH 1241/3725] Minor cleanup --- apps/openmw/mwworld/refdata.cpp | 4 ---- apps/openmw/mwworld/refdata.hpp | 4 ---- 2 files changed, 8 deletions(-) diff --git a/apps/openmw/mwworld/refdata.cpp b/apps/openmw/mwworld/refdata.cpp index a95a66f7e..c14ad6930 100644 --- a/apps/openmw/mwworld/refdata.cpp +++ b/apps/openmw/mwworld/refdata.cpp @@ -128,10 +128,6 @@ namespace MWWorld return mBaseNode; } - void RefData::setBaseNodeOld(Ogre::SceneNode* base) - { - } - void RefData::setBaseNode(osg::PositionAttitudeTransform *base) { mBase = base; diff --git a/apps/openmw/mwworld/refdata.hpp b/apps/openmw/mwworld/refdata.hpp index 5951cb101..b5b1f1560 100644 --- a/apps/openmw/mwworld/refdata.hpp +++ b/apps/openmw/mwworld/refdata.hpp @@ -88,10 +88,6 @@ namespace MWWorld /// Return base node (can be a null pointer). osg::PositionAttitudeTransform* getBaseNode(); - /// Set OGRE base node (can be a null pointer). - /// obsolete - void setBaseNodeOld (Ogre::SceneNode* base); - /// Set base node (can be a null pointer). void setBaseNode (osg::PositionAttitudeTransform* base); From 04e827ecf6446910dc8127ab10fe689ad8d3c684 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 23 May 2015 05:42:21 +0200 Subject: [PATCH 1242/3725] Don't try to play an empty video --- apps/openmw/mwworld/worldimp.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 35b6fc103..30be5a00c 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -260,7 +260,11 @@ namespace MWWorld } if (!bypass) - MWBase::Environment::get().getWindowManager()->playVideo(mFallback.getFallbackString("Movies_New_Game"), true); + { + std::string video = mFallback.getFallbackString("Movies_New_Game"); + if (!video.empty()) + MWBase::Environment::get().getWindowManager()->playVideo(video, true); + } // enable collision //if (!mPhysics->toggleCollisionMode()) From 0b042b75cc9b098f66d555d534c04a7f41fc0fd4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 23 May 2015 05:42:37 +0200 Subject: [PATCH 1243/3725] Restore actor visibility mask --- apps/openmw/mwrender/objects.cpp | 3 +++ apps/openmw/mwrender/vismask.hpp | 1 + 2 files changed, 4 insertions(+) diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 6c5709b5d..237e90b74 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -22,6 +22,7 @@ #include "animation.hpp" #include "npcanimation.hpp" #include "creatureanimation.hpp" +#include "vismask.hpp" namespace { @@ -131,6 +132,7 @@ void Objects::insertModel(const MWWorld::Ptr &ptr, const std::string &mesh, bool void Objects::insertCreature(const MWWorld::Ptr &ptr, const std::string &mesh, bool weaponsShields) { insertBegin(ptr); + ptr.getRefData().getBaseNode()->setNodeMask(Mask_Actor); // CreatureAnimation std::auto_ptr anim; @@ -149,6 +151,7 @@ void Objects::insertCreature(const MWWorld::Ptr &ptr, const std::string &mesh, b void Objects::insertNPC(const MWWorld::Ptr &ptr) { insertBegin(ptr); + ptr.getRefData().getBaseNode()->setNodeMask(Mask_Actor); std::auto_ptr anim (new NpcAnimation(ptr, osg::ref_ptr(ptr.getRefData().getBaseNode()), mResourceSystem, 0)); diff --git a/apps/openmw/mwrender/vismask.hpp b/apps/openmw/mwrender/vismask.hpp index 872695556..512f9f4ad 100644 --- a/apps/openmw/mwrender/vismask.hpp +++ b/apps/openmw/mwrender/vismask.hpp @@ -12,6 +12,7 @@ namespace MWRender // child of Scene Mask_Effect = 0x2, Mask_Debug = 0x4, + Mask_Actor = 0x8, // top level masks Mask_Scene = 0x10, From 0de6839890a397e883258bdf533f76040709dcac Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 23 May 2015 06:07:11 +0200 Subject: [PATCH 1244/3725] Minor cleanup --- apps/openmw/mwworld/worldimp.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 30be5a00c..70751e445 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -267,8 +267,8 @@ namespace MWWorld } // enable collision - //if (!mPhysics->toggleCollisionMode()) - // mPhysics->toggleCollisionMode(); + if (!mPhysics->toggleCollisionMode()) + mPhysics->toggleCollisionMode(); // we don't want old weather to persist on a new game delete mWeatherManager; @@ -972,7 +972,7 @@ namespace MWWorld void World::changeToInteriorCell (const std::string& cellName, const ESM::Position& position) { - //mPhysics->clearQueuedMovement(); + mPhysics->clearQueuedMovement(); if (mCurrentWorldSpace != cellName) { @@ -992,7 +992,7 @@ namespace MWWorld void World::changeToExteriorCell (const ESM::Position& position) { - //mPhysics->clearQueuedMovement(); + mPhysics->clearQueuedMovement(); if (mCurrentWorldSpace != "sys::default") // FIXME { From f2809ab63b92c9ec7d17c301dafaf2760ec9ded4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 23 May 2015 06:53:26 +0200 Subject: [PATCH 1245/3725] Delete nifosgtest again --- CMakeLists.txt | 2 - apps/nifosgtest/CMakeLists.txt | 7 -- apps/nifosgtest/test.cpp | 166 --------------------------------- 3 files changed, 175 deletions(-) delete mode 100644 apps/nifosgtest/CMakeLists.txt delete mode 100644 apps/nifosgtest/test.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index d0515a1fb..4b6ede3dd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -473,8 +473,6 @@ if (BUILD_NIFTEST) endif(BUILD_NIFTEST) # Apps and tools -add_subdirectory( apps/nifosgtest ) - if (BUILD_OPENMW) add_subdirectory( apps/openmw ) endif() diff --git a/apps/nifosgtest/CMakeLists.txt b/apps/nifosgtest/CMakeLists.txt deleted file mode 100644 index 265577d98..000000000 --- a/apps/nifosgtest/CMakeLists.txt +++ /dev/null @@ -1,7 +0,0 @@ -set (FILES - test.cpp -) - -add_executable (test ${FILES}) - -target_link_libraries (test ${OPENSCENEGRAPH_LIBRARIES} "components") diff --git a/apps/nifosgtest/test.cpp b/apps/nifosgtest/test.cpp deleted file mode 100644 index 6d0586775..000000000 --- a/apps/nifosgtest/test.cpp +++ /dev/null @@ -1,166 +0,0 @@ -#include -#include - -#include -#include - -#include - -#include -#include -#include - -#include - -#include - -#include - -#include -#include - -#include - -#include - -// EventHandler to toggle wireframe when 'w' key is pressed -class WireframeKeyHandler : public osgGA::GUIEventHandler -{ -public: - WireframeKeyHandler(osg::Node* node) - : mWireframe(false) - , mNode(node) - { - - } - - virtual bool handle(const osgGA::GUIEventAdapter& adapter,osgGA::GUIActionAdapter& action) - { - switch (adapter.getEventType()) - { - case osgGA::GUIEventAdapter::KEYDOWN: - if (adapter.getKey() == osgGA::GUIEventAdapter::KEY_W) - { - mWireframe = !mWireframe; - osg::PolygonMode* mode = new osg::PolygonMode; - mode->setMode(osg::PolygonMode::FRONT_AND_BACK, - mWireframe ? osg::PolygonMode::LINE : osg::PolygonMode::FILL); - - // Create a new stateset instead of changing the old one, this alleviates the need to set - // the StateSet to DYNAMIC DataVariance, which would have a performance impact. - - osg::StateSet* stateset = new osg::StateSet; - stateset->setAttributeAndModes(mode, osg::StateAttribute::ON); - stateset->setMode(GL_CULL_FACE, mWireframe ? osg::StateAttribute::OFF - : osg::StateAttribute::ON); - - mNode->setStateSet(stateset); - - return true; - } - default: - break; - } - return false; - } - -private: - bool mWireframe; - osg::Node* mNode; -}; - -int main(int argc, char** argv) -{ - if (argc < 2) - { - std::cout << "Usage: " << argv[0] << " " << std::endl; - return 1; - } - - Files::ConfigurationManager cfgMgr; - boost::program_options::options_description desc(""); - desc.add_options() - ("data", boost::program_options::value()->default_value(Files::PathContainer(), "data")->multitoken()->composing()) - ("fs-strict", boost::program_options::value()->implicit_value(true)->default_value(false)) - ("fallback-archive", boost::program_options::value >()-> - default_value(std::vector(), "fallback-archive")->multitoken()); - - boost::program_options::variables_map variables; - cfgMgr.readConfiguration(variables, desc); - - std::vector archives = variables["fallback-archive"].as >(); - bool fsStrict = variables["fs-strict"].as(); - Files::PathContainer dataDirs; - if (!variables["data"].empty()) { - dataDirs = Files::PathContainer(variables["data"].as()); - } - - cfgMgr.processPaths(dataDirs); - - VFS::Manager resourceMgr (fsStrict); - Files::Collections collections (dataDirs, !fsStrict); - - for (std::vector::const_iterator it = archives.begin(); it != archives.end(); ++it) - { - std::string filepath = collections.getPath(*it).string(); - resourceMgr.addArchive(new VFS::BsaArchive(filepath)); - } - for (Files::PathContainer::const_iterator it = dataDirs.begin(); it != dataDirs.end(); ++it) - { - resourceMgr.addArchive(new VFS::FileSystemArchive(it->string())); - } - - resourceMgr.buildIndex(); - - Nif::NIFFilePtr nif(new Nif::NIFFile(resourceMgr.get(argv[1]), std::string(argv[1]))); - - // For NiStencilProperty - osg::DisplaySettings::instance()->setMinimumNumStencilBits(8); - - osgViewer::Viewer viewer; - - osg::ref_ptr root(new osg::Group()); - root->getOrCreateStateSet()->setMode(GL_CULL_FACE, osg::StateAttribute::ON); - // To prevent lighting issues with scaled meshes - root->getOrCreateStateSet()->setMode(GL_NORMALIZE, osg::StateAttribute::ON); - - - //osgDB::writeNodeFile(*newNode, "out.osg"); - osg::Group* newNode = new osg::Group; - NifOsg::Loader loader; - Resource::TextureManager texMgr(&resourceMgr); - newNode->addChild(loader.load(nif, &texMgr)); - - SceneUtil::AssignControllerSourcesVisitor visitor(boost::shared_ptr(new SceneUtil::FrameTimeSource)); - newNode->accept(visitor); - - osg::PositionAttitudeTransform* trans = new osg::PositionAttitudeTransform; - root->addChild(trans); - - for (int x=0; x<1;++x) - { - //root->addChild(newNode); - trans->addChild(newNode); - } - - viewer.setSceneData(root); - - viewer.setUpViewInWindow(0, 0, 800, 600); - viewer.realize(); - viewer.setCameraManipulator(new osgGA::TrackballManipulator()); - viewer.addEventHandler(new WireframeKeyHandler(root)); - - // Mask to separate cull visitors from update visitors - viewer.getCamera()->setCullMask(~(0x1)); - - viewer.addEventHandler(new osgViewer::StatsHandler); - - while (!viewer.done()) - { - //trans->setAttitude(osg::Quat(viewer.getFrameStamp()->getSimulationTime()*5, osg::Vec3f(0,0,1))); - - viewer.frame(); - } - - return 0; -} From 10ca6cf3796b3035d97b50d6ac092bc36ee21600 Mon Sep 17 00:00:00 2001 From: Cramal Date: Sat, 23 May 2015 14:39:16 +0900 Subject: [PATCH 1246/3725] debug latex code --- manual/opencs/tables.tex | 2 -- 1 file changed, 2 deletions(-) diff --git a/manual/opencs/tables.tex b/manual/opencs/tables.tex index b47d5f3d4..503489872 100644 --- a/manual/opencs/tables.tex +++ b/manual/opencs/tables.tex @@ -92,5 +92,3 @@ when you hover your reticle over the object. This is a library of all the items, triggers, containers, NPCs, etc. in the game. There are several kinds of Record Types. Depending on which type a record is, it will need specific information to function. For example, an NPC needs a value attached to its aggression level. A chest, of course, does not. All Record Types contain at least a model. How else would the player see them? Usually they also have a Name, which is what you see when you hover your reticle over the object. Please refer to the Record Types section for an overview of what each type of Referenceable does and what you can tell OpenCS about these objects. - -\end{description} From 45f6e3b39ef99b4be5ec33e9027e0e010cb79a48 Mon Sep 17 00:00:00 2001 From: Cramal Date: Sat, 23 May 2015 14:40:04 +0900 Subject: [PATCH 1247/3725] debug latex code --- manual/opencs/recordtypes.tex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/manual/opencs/recordtypes.tex b/manual/opencs/recordtypes.tex index afe5a67e3..4dbfbe286 100644 --- a/manual/opencs/recordtypes.tex +++ b/manual/opencs/recordtypes.tex @@ -9,8 +9,8 @@ Let's go through all Record Types and discuss what you can tell OpenCS about the \item[Activator:] When the player enters the same cell as this object, a script is started. Often it also has a \textbf{Script} attached to it, though it not mandatory. These scripts are small bits of code written in a special scripting language that OpenCS can read and interpret. \item[Potion:] This is a potion that is not self-made. It has an \textbf{Icon} for your inventory, Aside from the self-explanatory \textbf{Weight} and \textbf{Coin Value}, it has an attribute called \textbf{Auto Calc} set to ``False''. This means that the effects of this potion are preconfigured. This does not happen when the player makes their own potion. \item[Apparatus:] This is a tool to make potions. Again there's an icon for your inventory as well as a weight and a coin value. It also has a \textbf{Quality} value attached to it: higher the number, the better the effect on your potions will be. The \textbf{Apparatus Type} describes if the item is a Calcinator, Retort, Alembir or Mortar & Pestal. Each has a different effect on the potion the player makes. For more information on this subject, please refer to the \href{http://www.uesp.net/wiki/Morrowind:Alchemy#Tools}{UESP page on Alchemy Tools}. - \item[Armor:] This type of item adds \textbf{Enchantment Points} to the mix. Every piece of clothing or armor has a ''pool'' of potential magicka that gets unlocked when you enchant it. Strong enchantments consume more magicka from this pool: the stronger the enchantment, the more Enchantment Points each cast will take up. For more information on this subject, please refer to the \href{Enchant page on UESP}{http://www.uesp.net/wiki/Morrowind:Enchant}. \textbf{Health} means the amount of hit points this piece of armor has. If it sustains enough damage, the armor will be destroyed. Finally, \textbf{Armor Value} tells the game how much points to add to the player character's Armor Rating. - \item[Book:] This includes scrolls and notes. For the game to make the distinction between books and scrolls, an extra property, \textbf{Scroll}, has been added. Under the \textbf{Skill} column a scroll or book can have an in-game skill listed. Reading this item will raise the player's level in that specific skill. For more information on this, please refer to the \href{Skill Books page on UESP}{http://www.uesp.net/wiki/Morrowind:Skill_Books}. + \item[Armor:] This type of item adds \textbf{Enchantment Points} to the mix. Every piece of clothing or armor has a ''pool'' of potential magicka that gets unlocked when you enchant it. Strong enchantments consume more magicka from this pool: the stronger the enchantment, the more Enchantment Points each cast will take up. For more information on this subject, please refer to the \href{http://www.uesp.net/wiki/Morrowind:Enchant}{Enchant page on UESP}. \textbf{Health} means the amount of hit points this piece of armor has. If it sustains enough damage, the armor will be destroyed. Finally, \textbf{Armor Value} tells the game how much points to add to the player character's Armor Rating. + \item[Book:] This includes scrolls and notes. For the game to make the distinction between books and scrolls, an extra property, \textbf{Scroll}, has been added. Under the \textbf{Skill} column a scroll or book can have an in-game skill listed. Reading this item will raise the player's level in that specific skill. For more information on this, please refer to the \href{http://www.uesp.net/wiki/Morrowind:Skill_Books}{Skill Books page on UESP}. \item[Clothing:] These items work just like Armors, but confer no protective properties. Rather than ``Armor Type'', these items have a ``Clothing Type''. \item[Container:] This is all the stuff that stores items, from chests to sacks to plants. Its \textbf{Capacity} shows how much stuff you can put in the container. You can compare it to the maximum allowed load a player character can carry (who will get over-encumbered and unable to move if he crosses this threshold). A container, however, will just refuse to take the item in question when it gets ''over-encumbered''. \textbf{Organic Container}s are containers such as plants. Containers that \textbf{Respawn} are not safe to store stuff in. After a certain amount of time they will reset to their default contents, meaning that everything in it is gone forever. \item[Creature:] These can be monsters, animals and the like. From 63c3d8df2e38dac647e6f50a4a1e5c0e14a2e4da Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 23 May 2015 09:46:48 +0200 Subject: [PATCH 1248/3725] updated credits file --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index fb83a1a91..ce76c104e 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -114,6 +114,7 @@ Manual ------ Bodillium + Cramal sir_herrbatka Packagers From da24e298ee152807ae2bc6cff30c4b13ae5b395e Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 23 May 2015 22:44:00 +0200 Subject: [PATCH 1249/3725] Fix -Wreorder warnings --- apps/opencs/view/render/object.cpp | 2 +- apps/openmw/engine.cpp | 2 +- apps/openmw/mwgui/inventorywindow.cpp | 4 ++-- apps/openmw/mwinput/inputmanagerimp.cpp | 2 +- apps/openmw/mwphysics/physicssystem.cpp | 4 ++-- apps/openmw/mwrender/animation.cpp | 4 ++-- apps/openmw/mwrender/npcanimation.cpp | 5 ++--- apps/openmw/mwrender/objects.cpp | 4 ++-- apps/openmw/mwrender/pathgrid.cpp | 6 +++--- apps/openmw/mwrender/sky.cpp | 4 ++-- components/nif/niffile.cpp | 2 +- components/nifosg/controller.cpp | 2 +- components/nifosg/particle.cpp | 2 +- components/nifosg/particle.hpp | 2 +- components/sceneutil/lightcontroller.cpp | 2 +- components/sceneutil/skeleton.cpp | 4 ++-- 16 files changed, 25 insertions(+), 26 deletions(-) diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index ec184a563..6ddea913a 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -115,7 +115,7 @@ const CSMWorld::CellRef& CSVRender::Object::getReference() const CSVRender::Object::Object (CSMWorld::Data& data, osg::Group* parentNode, const std::string& id, bool referenceable, bool forceBaseToZero) -: mResourceSystem(data.getResourceSystem()), mData (data), mBaseNode(0), mParentNode(parentNode), mForceBaseToZero (forceBaseToZero) +: mData (data), mBaseNode(0), mParentNode(parentNode), mResourceSystem(data.getResourceSystem()), mForceBaseToZero (forceBaseToZero) { mBaseNode = new osg::PositionAttitudeTransform; parentNode->addChild(mBaseNode); diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 5ce1607b5..08dba334f 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -204,8 +204,8 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) , mFSStrict (false) , mScriptBlacklistUse (true) , mNewGame (false) - , mCfgMgr(configurationManager) , mSimulationTime(0.0) + , mCfgMgr(configurationManager) { Misc::Rng::init(); MWClass::registerClasses(); diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index e9c973fc3..b96e79ca9 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -54,8 +54,6 @@ namespace MWGui InventoryWindow::InventoryWindow(DragAndDrop* dragAndDrop, osgViewer::Viewer* viewer, Resource::ResourceSystem* resourceSystem) : WindowPinnableBase("openmw_inventory_window.layout") - , mViewer(viewer) - , mResourceSystem(resourceSystem) , mDragAndDrop(dragAndDrop) , mSelectedItem(-1) , mSortModel(NULL) @@ -63,6 +61,8 @@ namespace MWGui , mGuiMode(GM_Inventory) , mLastXSize(0) , mLastYSize(0) + , mResourceSystem(resourceSystem) + , mViewer(viewer) , mPreview(new MWRender::InventoryPreview(viewer, resourceSystem, MWBase::Environment::get().getWorld()->getPlayerPtr())) , mTrading(false) { diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 7a3dd5e18..1b5abc099 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -131,8 +131,8 @@ namespace MWInput , mSneakToggles(Settings::Manager::getBool("toggle sneak", "Input")) , mSneaking(false) , mAttemptJump(false) - , mFakeDeviceID(1) , mInvUiScalingFactor(1.f) + , mFakeDeviceID(1) { mInputManager = new SDLUtil::InputWrapper(window, viewer, grab); mInputManager->setMouseEventCallback (this); diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index afc81da8b..b32ac2f52 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -590,10 +590,10 @@ namespace MWPhysics PhysicsSystem::PhysicsSystem(Resource::ResourceSystem* resourceSystem, osg::ref_ptr parentNode) : mShapeManager(new NifBullet::BulletShapeManager(resourceSystem->getVFS(), resourceSystem->getSceneManager())) + , mDebugDrawEnabled(false) , mTimeAccum(0.0f) - , mWaterEnabled(false) , mWaterHeight(0) - , mDebugDrawEnabled(false) + , mWaterEnabled(false) , mParentNode(parentNode) { mCollisionConfiguration = new btDefaultCollisionConfiguration(); diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index e8d6bbcc9..1c436d440 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -234,8 +234,8 @@ namespace MWRender }; Animation::Animation(const MWWorld::Ptr &ptr, osg::ref_ptr parentNode, Resource::ResourceSystem* resourceSystem) - : mPtr(ptr) - , mInsert(parentNode) + : mInsert(parentNode) + , mPtr(ptr) , mResourceSystem(resourceSystem) , mAccumulate(1.f, 1.f, 0.f) , mTextKeyListener(NULL) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 5fafa6d59..aeff1f60a 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -186,17 +186,16 @@ NpcAnimation::~NpcAnimation() mPtr.getClass().getInventoryStore(mPtr).setListener(NULL, mPtr); } - NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, osg::ref_ptr parentNode, Resource::ResourceSystem* resourceSystem, int visibilityFlags, bool disableListener, bool disableSounds, ViewMode viewMode) : Animation(ptr, parentNode, resourceSystem), - mVisibilityFlags(visibilityFlags), mListenerDisabled(disableListener), mViewMode(viewMode), mShowWeapons(false), mShowCarriedLeft(true), //mFirstPersonOffset(0.f, 0.f, 0.f), - mAlpha(1.f), mNpcType(Type_Normal), + mVisibilityFlags(visibilityFlags), + mAlpha(1.f), mSoundsDisabled(disableSounds) //mHeadPitch(0.f), //mHeadYaw(0.f) diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 237e90b74..3d981a9c7 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -65,8 +65,8 @@ namespace MWRender { Objects::Objects(Resource::ResourceSystem* resourceSystem, osg::ref_ptr rootNode) - : mResourceSystem(resourceSystem) - , mRootNode(rootNode) + : mRootNode(rootNode) + , mResourceSystem(resourceSystem) { } diff --git a/apps/openmw/mwrender/pathgrid.cpp b/apps/openmw/mwrender/pathgrid.cpp index 5e559eeed..9fffd76d1 100644 --- a/apps/openmw/mwrender/pathgrid.cpp +++ b/apps/openmw/mwrender/pathgrid.cpp @@ -125,10 +125,10 @@ osg::ref_ptr Pathgrid::createPathgridPoints(const ESM::Pathgrid * } Pathgrid::Pathgrid(osg::ref_ptr root) - : mRootNode(root) - , mPathgridEnabled(false) - , mInteriorPathgridNode(NULL) + : mPathgridEnabled(false) + , mRootNode(root) , mPathGridRoot(NULL) + , mInteriorPathgridNode(NULL) { } diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 6b432ae5e..43c88427e 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -326,8 +326,8 @@ public: Moon(osg::Group* parentNode, Resource::SceneManager* sceneManager, float scaleFactor, Type type) : CelestialBody(parentNode, sceneManager, scaleFactor, 2) - , mPhase(Phase_Unspecified) , mType(type) + , mPhase(Phase_Unspecified) { mUpdater = new MoonUpdater; mGeode->addUpdateCallback(mUpdater); @@ -487,6 +487,7 @@ SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneMana , mMonth(0) , mCloudAnimationTimer(0.f) , mRainTimer(0.f) + , mStormDirection(0,-1,0) , mClouds() , mNextClouds() , mCloudBlendFactor(0.0f) @@ -503,7 +504,6 @@ SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneMana , mSunEnabled(true) , mMasserEnabled(true) , mSecundaEnabled(true) - , mStormDirection(0,-1,0) { osg::ref_ptr skyroot (new CameraRelativeTransform); parentNode->addChild(skyroot); diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index a73985cfb..0a6f8f505 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -11,8 +11,8 @@ namespace Nif NIFFile::NIFFile(Files::IStreamPtr stream, const std::string &name) : ver(0) , filename(name) - , mStream(stream) , mUseSkinning(false) + , mStream(stream) { parse(); } diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index 27665b6c6..d676bc3f8 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -349,7 +349,7 @@ AlphaController::AlphaController() } AlphaController::AlphaController(const AlphaController ©, const osg::CopyOp ©op) - : StateSetUpdater(copy, copyop), ValueInterpolator(), Controller(copy) + : StateSetUpdater(copy, copyop), Controller(copy), ValueInterpolator() , mData(copy.mData) { } diff --git a/components/nifosg/particle.cpp b/components/nifosg/particle.cpp index 3cfd91f1f..b733987d0 100644 --- a/components/nifosg/particle.cpp +++ b/components/nifosg/particle.cpp @@ -155,9 +155,9 @@ void ParticleColorAffector::operate(osgParticle::Particle* particle, double /* d GravityAffector::GravityAffector(const Nif::NiGravity *gravity) : mForce(gravity->mForce) , mType(static_cast(gravity->mType)) - , mDecay(gravity->mDecay) , mPosition(gravity->mPosition) , mDirection(gravity->mDirection) + , mDecay(gravity->mDecay) { } diff --git a/components/nifosg/particle.hpp b/components/nifosg/particle.hpp index 416477cdd..5e463aae3 100644 --- a/components/nifosg/particle.hpp +++ b/components/nifosg/particle.hpp @@ -61,7 +61,7 @@ namespace NifOsg { } InverseWorldMatrix(const InverseWorldMatrix& copy, const osg::CopyOp& op = osg::CopyOp::SHALLOW_COPY) - : osg::NodeCallback(), osg::Object() + : osg::Object(), osg::NodeCallback() { } diff --git a/components/sceneutil/lightcontroller.cpp b/components/sceneutil/lightcontroller.cpp index 484cea447..d31e3d107 100644 --- a/components/sceneutil/lightcontroller.cpp +++ b/components/sceneutil/lightcontroller.cpp @@ -47,9 +47,9 @@ namespace SceneUtil LightController::LightController() : mType(LT_Normal) , mPhase((Misc::Rng::rollClosedProbability() * 2.f - 1.f) * 500.f) - , mLastTime(0.0) , mDeltaCount(0.f) , mDirection(1.f) + , mLastTime(0.0) { } diff --git a/components/sceneutil/skeleton.cpp b/components/sceneutil/skeleton.cpp index f105977ba..96941126b 100644 --- a/components/sceneutil/skeleton.cpp +++ b/components/sceneutil/skeleton.cpp @@ -34,8 +34,8 @@ private: Skeleton::Skeleton() : mBoneCacheInit(false) , mNeedToUpdateBoneMatrices(true) - , mLastFrameNumber(0) , mActive(true) + , mLastFrameNumber(0) { } @@ -44,8 +44,8 @@ Skeleton::Skeleton(const Skeleton ©, const osg::CopyOp ©op) : osg::Group(copy, copyop) , mBoneCacheInit(false) , mNeedToUpdateBoneMatrices(true) - , mLastFrameNumber(0) , mActive(copy.mActive) + , mLastFrameNumber(0) { } From 152d690a7aea9b0f890aaa0fe9185e96609a1a37 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 23 May 2015 23:10:53 +0200 Subject: [PATCH 1250/3725] Minor cleanup --- apps/openmw/CMakeLists.txt | 4 +- apps/openmw/mwclass/npc.cpp | 6 +-- apps/openmw/mwrender/localmap.cpp | 60 ++++++++++++++----------- apps/openmw/mwrender/localmap.hpp | 9 +--- apps/openmw/mwsound/loudness.cpp | 3 +- apps/openmw/mwsound/soundmanagerimp.hpp | 2 - 6 files changed, 42 insertions(+), 42 deletions(-) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 941222b0c..d45e76f25 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -22,8 +22,8 @@ source_group(game FILES ${GAME} ${GAME_HEADER}) add_openmw_dir (mwrender actors objects renderingmanager animation sky npcanimation vismask creatureanimation effectmanager util renderinginterface pathgrid rendermode - bulletdebugdraw globalmap characterpreview camera -# localmap occlusionquery water shadows + bulletdebugdraw globalmap characterpreview camera localmap +# occlusionquery water shadows # ripplesimulation refraction # terrainstorage weaponanimation ) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index b55ececc2..791c2f57e 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -1148,9 +1148,9 @@ namespace MWClass if (ptr.getClass().getNpcStats(ptr).isWerewolf() && ptr.getClass().getCreatureStats(ptr).getStance(MWMechanics::CreatureStats::Stance_Run)) { - //MWMechanics::WeaponType weaponType = MWMechanics::WeapType_None; - //MWMechanics::getActiveWeapon(ptr.getClass().getCreatureStats(ptr), ptr.getClass().getInventoryStore(ptr), &weaponType); - //if (weaponType == MWMechanics::WeapType_None) + MWMechanics::WeaponType weaponType = MWMechanics::WeapType_None; + MWMechanics::getActiveWeapon(ptr.getClass().getCreatureStats(ptr), ptr.getClass().getInventoryStore(ptr), &weaponType); + if (weaponType == MWMechanics::WeapType_None) return ""; } diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index b69222664..f675fe1d8 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -10,6 +10,7 @@ #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -18,30 +19,20 @@ #include "../mwworld/esmstore.hpp" #include "../mwworld/cellstore.hpp" -#include "renderconst.hpp" -#include "renderingmanager.hpp" using namespace MWRender; using namespace Ogre; -LocalMap::LocalMap(OEngine::Render::OgreRenderer* rend, MWRender::RenderingManager* rendering) +LocalMap::LocalMap() : mMapResolution(Settings::Manager::getInt("local map resolution", "Map")) , mAngle(0.f) , mInterior(false) { - mRendering = rend; - mRenderingManager = rendering; - - mCameraPosNode = mRendering->getScene()->getRootSceneNode()->createChildSceneNode(); - mCameraRotNode = mCameraPosNode->createChildSceneNode(); - mCameraNode = mCameraRotNode->createChildSceneNode(); - - mCellCamera = mRendering->getScene()->createCamera("CellCamera"); + // mCellCamera = mRendering->getScene()->createCamera("CellCamera"); mCellCamera->setProjectionType(PT_ORTHOGRAPHIC); mCameraNode->attachObject(mCellCamera); - mLight = mRendering->getScene()->createLight(); mLight->setType (Ogre::Light::LT_DIRECTIONAL); mLight->setDirection (Ogre::Vector3(0.3f, 0.3f, -0.7f)); mLight->setVisible (false); @@ -62,7 +53,6 @@ LocalMap::LocalMap(OEngine::Render::OgreRenderer* rend, MWRender::RenderingManag vp->setOverlaysEnabled(false); vp->setShadowsEnabled(false); vp->setBackgroundColour(ColourValue(0, 0, 0)); - vp->setVisibilityMask(RV_Map); vp->setMaterialScheme("local_map"); } @@ -83,12 +73,11 @@ std::string LocalMap::coordStr(const int x, const int y) void LocalMap::clear() { - // Not actually removing the Textures here. That doesnt appear to work properly. It seems MyGUI still keeps some pointers. - mBuffers.clear(); } void LocalMap::saveFogOfWar(MWWorld::CellStore* cell) { + /* if (!mInterior) { std::string textureName = "Cell_"+coordStr(cell->getCell()->getGridX(), cell->getCell()->getGridY())+"_fog"; @@ -156,6 +145,7 @@ void LocalMap::saveFogOfWar(MWWorld::CellStore* cell) cell->setFog(fog.release()); } + */ } void LocalMap::requestMap(MWWorld::CellStore* cell, float zMin, float zMax) @@ -177,6 +167,7 @@ void LocalMap::requestMap(MWWorld::CellStore* cell, float zMin, float zMax) // (and objects in a different cell can "bleed" into another cell's map if they cross the border) render((x+0.5f)*sSize, (y+0.5f)*sSize, zMin, zMax, static_cast(sSize), static_cast(sSize), name, true); + /* if (mBuffers.find(name) == mBuffers.end()) { if (cell->getFog()) @@ -184,6 +175,7 @@ void LocalMap::requestMap(MWWorld::CellStore* cell, float zMin, float zMax) else createFogOfWar(name); } + */ } void LocalMap::requestMap(MWWorld::CellStore* cell, @@ -241,6 +233,7 @@ void LocalMap::requestMap(MWWorld::CellStore* cell, // If they changed by too much (for bounds, < padding is considered acceptable) then parts of the interior might not // be covered by the map anymore. // The following code detects this, and discards the CellStore's fog state if it needs to. + /* if (cell->getFog()) { ESM::FogState* fog = cell->getFog(); @@ -265,6 +258,7 @@ void LocalMap::requestMap(MWWorld::CellStore* cell, mAngle = fog->mNorthMarkerAngle; } } + */ Vector2 center(mBounds.getCenter().x, mBounds.getCenter().y); @@ -296,6 +290,7 @@ void LocalMap::requestMap(MWWorld::CellStore* cell, render(newcenter.x - center.x, newcenter.y - center.y, zMin, zMax, static_cast(sSize), static_cast(sSize), texturePrefix); + /* if (!cell->getFog()) createFogOfWar(texturePrefix); else @@ -309,6 +304,7 @@ void LocalMap::requestMap(MWWorld::CellStore* cell, ESM::FogTexture& esm = fog->mFogTextures[i]; loadFogOfWar(texturePrefix, esm); } + */ ++i; } } @@ -316,6 +312,7 @@ void LocalMap::requestMap(MWWorld::CellStore* cell, void LocalMap::createFogOfWar(const std::string& texturePrefix) { + /* const std::string texName = texturePrefix + "_fog"; TexturePtr tex = createFogOfWarTexture(texName); @@ -331,12 +328,14 @@ void LocalMap::createFogOfWar(const std::string& texturePrefix) tex->getBuffer()->unlock(); mBuffers[texturePrefix] = buffer; + */ } Ogre::TexturePtr LocalMap::createFogOfWarTexture(const std::string &texName) { - TexturePtr tex = TextureManager::getSingleton().getByName(texName); - if (tex.isNull()) + TexturePtr tex;// = TextureManager::getSingleton().getByName(texName); + /* + * if (tex.isNull()) { tex = TextureManager::getSingleton().createManual( texName, @@ -349,12 +348,14 @@ Ogre::TexturePtr LocalMap::createFogOfWarTexture(const std::string &texName) this // ManualResourceLoader required if the texture contents are lost (due to lost devices nonsense that can occur with D3D) ); } + */ return tex; } void LocalMap::loadFogOfWar (const std::string& texturePrefix, ESM::FogTexture& esm) { + /* std::vector& data = esm.mImageData; Ogre::DataStreamPtr stream(new Ogre::MemoryDataStream(&data[0], data.size())); Ogre::Image image; @@ -376,6 +377,7 @@ void LocalMap::loadFogOfWar (const std::string& texturePrefix, ESM::FogTexture& memcpy(&buffer[0], image.getData(), image.getSize()); mBuffers[texturePrefix] = buffer; + */ } void LocalMap::render(const float x, const float y, @@ -390,15 +392,12 @@ void LocalMap::render(const float x, const float y, // disable fog (only necessary for fixed function, the shader based // materials already do this through local_map material configuration) - float oldFogStart = mRendering->getScene()->getFogStart(); - float oldFogEnd = mRendering->getScene()->getFogEnd(); - Ogre::ColourValue oldFogColour = mRendering->getScene()->getFogColour(); - mRendering->getScene()->setFog(FOG_NONE); + //mRendering->getScene()->setFog(FOG_NONE); // set up lighting - Ogre::ColourValue oldAmbient = mRendering->getScene()->getAmbientLight(); - mRendering->getScene()->setAmbientLight(Ogre::ColourValue(0.3f, 0.3f, 0.3f)); - mRenderingManager->disableLights(true); + //Ogre::ColourValue oldAmbient = mRendering->getScene()->getAmbientLight(); + //mRendering->getScene()->setAmbientLight(Ogre::ColourValue(0.3f, 0.3f, 0.3f)); + //mRenderingManager->disableLights(true); mLight->setVisible(true); TexturePtr tex; @@ -425,12 +424,12 @@ void LocalMap::render(const float x, const float y, tex->getBuffer()->blit(mRenderTexture->getBuffer()); } - mRenderingManager->enableLights(true); + //mRenderingManager->enableLights(true); mLight->setVisible(false); // re-enable fog - mRendering->getScene()->setFog(FOG_LINEAR, oldFogColour, 0, oldFogStart, oldFogEnd); - mRendering->getScene()->setAmbientLight(oldAmbient); + //mRendering->getScene()->setFog(FOG_LINEAR, oldFogColour, 0, oldFogStart, oldFogEnd); + //mRendering->getScene()->setAmbientLight(oldAmbient); } void LocalMap::worldToInteriorMapPosition (Ogre::Vector2 pos, float& nX, float& nY, int& x, int& y) @@ -460,6 +459,8 @@ Ogre::Vector2 LocalMap::interiorMapToWorldPosition (float nX, float nY, int x, i bool LocalMap::isPositionExplored (float nX, float nY, int x, int y, bool interior) { + return false; + /* std::string texName = (interior ? mInteriorName + "_" : "Cell_") + coordStr(x, y); if (mBuffers.find(texName) == mBuffers.end()) @@ -474,10 +475,12 @@ bool LocalMap::isPositionExplored (float nX, float nY, int x, int y, bool interi Ogre::uint32 clr = mBuffers[texName][texV * sFogOfWarResolution + texU]; uint8 alpha = (clr >> 24); return alpha < 200; + */ } void LocalMap::loadResource(Ogre::Resource* resource) { + /* std::string resourceName = resource->getName(); size_t pos = resourceName.find("_fog"); if (pos != std::string::npos) @@ -498,10 +501,12 @@ void LocalMap::loadResource(Ogre::Resource* resource) tex->createInternalResources(); memcpy(tex->getBuffer()->lock(HardwareBuffer::HBL_DISCARD), &buffer[0], sFogOfWarResolution*sFogOfWarResolution*4); tex->getBuffer()->unlock(); + */ } void LocalMap::updatePlayer (const Ogre::Vector3& position, const Ogre::Quaternion& orientation) { + /* if (sFogOfWarSkip != 0) { static int count=0; @@ -607,4 +612,5 @@ void LocalMap::updatePlayer (const Ogre::Vector3& position, const Ogre::Quaterni } } } + */ } diff --git a/apps/openmw/mwrender/localmap.hpp b/apps/openmw/mwrender/localmap.hpp index 014c67f16..d0d7d73d2 100644 --- a/apps/openmw/mwrender/localmap.hpp +++ b/apps/openmw/mwrender/localmap.hpp @@ -1,8 +1,6 @@ #ifndef GAME_RENDER_LOCALMAP_H #define GAME_RENDER_LOCALMAP_H -#include - #include #include #include @@ -24,10 +22,10 @@ namespace MWRender /// /// \brief Local map rendering /// - class LocalMap : public Ogre::ManualResourceLoader + class LocalMap { public: - LocalMap(OEngine::Render::OgreRenderer*, MWRender::RenderingManager* rendering); + LocalMap(); ~LocalMap(); virtual void loadResource(Ogre::Resource* resource); @@ -84,9 +82,6 @@ namespace MWRender bool isPositionExplored (float nX, float nY, int x, int y, bool interior); private: - OEngine::Render::OgreRenderer* mRendering; - MWRender::RenderingManager* mRenderingManager; - int mMapResolution; // the dynamic texture is a bottleneck, so don't set this too high diff --git a/apps/openmw/mwsound/loudness.cpp b/apps/openmw/mwsound/loudness.cpp index 9446a1dae..1e6872a76 100644 --- a/apps/openmw/mwsound/loudness.cpp +++ b/apps/openmw/mwsound/loudness.cpp @@ -1,6 +1,7 @@ #include "loudness.hpp" #include +#include #include "soundmanagerimp.hpp" @@ -31,7 +32,7 @@ namespace MWSound else if (type == SampleType_Int16) { value = *reinterpret_cast(&data[sample*advance]); - value /= float(std::numeric_limits::max()); + value /= float(std::numeric_limits::max()); } else if (type == SampleType_Float32) { diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index 27af1e65b..f79bfce15 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -7,8 +7,6 @@ #include -#include - #include #include "../mwbase/soundmanager.hpp" From 9a0db5d55ae1976d80d677ebfd9ee481e30a41e9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 24 May 2015 01:32:00 +0200 Subject: [PATCH 1251/3725] Restore cell changes --- apps/openmw/mwworld/worldimp.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 4f7a5b87f..442f493c1 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1128,7 +1128,7 @@ namespace MWWorld ptr.getRefData().setPosition(pos); - Ogre::Vector3 vec(x, y, z); + osg::Vec3f vec(x, y, z); CellStore *currCell = ptr.isInCell() ? ptr.getCell() : NULL; // currCell == NULL should only happen for player, during initial startup bool isPlayer = ptr == mPlayer->getPlayer(); @@ -1207,12 +1207,12 @@ namespace MWWorld } if (haveToMove && newPtr.getRefData().getBaseNode()) { - mRendering->moveObject(newPtr, osg::Vec3f(vec.x, vec.y, vec.z)); + mRendering->moveObject(newPtr, vec); mPhysics->updatePosition(newPtr); } if (isPlayer) { - //mWorldScene->playerMoved (vec); + mWorldScene->playerMoved(vec); } return newPtr; } From c748ea73632d86a18be87f0bb58956433c9b5b63 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 24 May 2015 01:40:49 +0200 Subject: [PATCH 1252/3725] Fix view distance slider --- files/mygui/openmw_settings_window.layout | 2 +- files/settings-default.cfg | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/files/mygui/openmw_settings_window.layout b/files/mygui/openmw_settings_window.layout index 66514c886..3fb4adf42 100644 --- a/files/mygui/openmw_settings_window.layout +++ b/files/mygui/openmw_settings_window.layout @@ -345,7 +345,7 @@ - + diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 64ef4e302..6653966cf 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -102,10 +102,10 @@ exterior grid size = 3 [Viewing distance] # Viewing distance at normal weather conditions # The maximum distance with no pop-in will be: (see RenderingManager::configureFog) -# viewing distance / minimum weather fog depth (.69) * view frustum factor <= cell size (8192) - loading threshold (1024) +# viewing distance * view frustum factor <= cell size (8192) - loading threshold (1024) # view frustum factor takes into account that the view frustum end is a plane, so at the edges of the screen you can see further than you should be able to. # exact factor would depend on FOV -viewing distance = 4600 +viewing distance = 6666 # Culling of objects smaller than a pixel small feature culling = true From c2131e7c31cb331ce8c9bfe48d26fcb2d4a2bbda Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 24 May 2015 02:34:20 +0200 Subject: [PATCH 1253/3725] Make near clip distance configurable --- apps/openmw/mwrender/renderingmanager.cpp | 11 ++++++----- apps/openmw/mwrender/renderingmanager.hpp | 1 + files/mygui/openmw_settings_window.layout | 2 +- files/settings-default.cfg | 5 +++-- 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index af4e46f62..b8620d60b 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -132,7 +132,7 @@ namespace MWRender osg::Camera::CullingMode cullingMode = osg::Camera::DEFAULT_CULLING|osg::Camera::FAR_PLANE_CULLING; - if (!Settings::Manager::getBool("small feature culling", "Viewing distance")) + if (!Settings::Manager::getBool("small feature culling", "Camera")) cullingMode &= ~(osg::CullStack::SMALL_FEATURE_CULLING); else cullingMode |= osg::CullStack::SMALL_FEATURE_CULLING; @@ -144,7 +144,8 @@ namespace MWRender mViewer->getCamera()->setCullMask(~(Mask_UpdateVisitor)); - mViewDistance = Settings::Manager::getFloat("viewing distance", "Viewing distance"); + mNearClip = Settings::Manager::getFloat("near clip", "Camera"); + mViewDistance = Settings::Manager::getFloat("viewing distance", "Camera"); mFieldOfView = Settings::Manager::getFloat("field of view", "General"); updateProjectionMatrix(); } @@ -372,7 +373,7 @@ namespace MWRender double fovy, aspect, zNear, zFar; mViewer->getCamera()->getProjectionMatrixAsPerspective(fovy, aspect, zNear, zFar); fovy = mFieldOfView; - zNear = 5.f; + zNear = mNearClip; zFar = mViewDistance; mViewer->getCamera()->setProjectionMatrixAsPerspective(fovy, aspect, zNear, zFar); } @@ -401,9 +402,9 @@ namespace MWRender mFieldOfView = Settings::Manager::getFloat("field of view", "General"); updateProjectionMatrix(); } - else if (it->first == "Viewing distance" && it->second == "viewing distance") + else if (it->first == "Camera" && it->second == "viewing distance") { - mViewDistance = Settings::Manager::getFloat("viewing distance", "Viewing distance"); + mViewDistance = Settings::Manager::getFloat("viewing distance", "Camera"); mStateUpdater->setFogEnd(mViewDistance); updateProjectionMatrix(); } diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 8a81aacd7..2978c9983 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -137,6 +137,7 @@ namespace MWRender osg::ref_ptr mStateUpdater; + float mNearClip; float mViewDistance; float mFieldOfView; diff --git a/files/mygui/openmw_settings_window.layout b/files/mygui/openmw_settings_window.layout index 3fb4adf42..19e3bcf88 100644 --- a/files/mygui/openmw_settings_window.layout +++ b/files/mygui/openmw_settings_window.layout @@ -341,7 +341,7 @@ - + diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 6653966cf..0581d7356 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -99,8 +99,9 @@ local map hud widget size = 256 [Cells] exterior grid size = 3 -[Viewing distance] -# Viewing distance at normal weather conditions +[Camera] +near clip = 5 + # The maximum distance with no pop-in will be: (see RenderingManager::configureFog) # viewing distance * view frustum factor <= cell size (8192) - loading threshold (1024) # view frustum factor takes into account that the view frustum end is a plane, so at the edges of the screen you can see further than you should be able to. From 8b322fcd062d7786cdcc0d97979987e40fca881f Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 24 May 2015 03:36:34 +0200 Subject: [PATCH 1254/3725] Implement getFacedObject using osgUtil::IntersectionVisitor --- apps/openmw/mwrender/objects.cpp | 11 +++ apps/openmw/mwrender/objects.hpp | 25 ++++++- apps/openmw/mwrender/renderingmanager.cpp | 82 +++++++++++++++++++++++ apps/openmw/mwrender/renderingmanager.hpp | 7 ++ apps/openmw/mwrender/vismask.hpp | 11 +-- apps/openmw/mwworld/worldimp.cpp | 65 ++++-------------- apps/openmw/mwworld/worldimp.hpp | 3 +- 7 files changed, 144 insertions(+), 60 deletions(-) diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 3d981a9c7..cb53105a7 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include @@ -103,6 +104,8 @@ void Objects::insertBegin(const MWWorld::Ptr& ptr) osg::ref_ptr insert (new osg::PositionAttitudeTransform); cellnode->addChild(insert); + insert->getOrCreateUserDataContainer()->addUserObject(new PtrHolder(ptr)); + const float *f = ptr.getRefData().getPosition().pos; insert->setPosition(osg::Vec3(f[0], f[1], f[2])); @@ -216,6 +219,14 @@ void Objects::updatePtr(const MWWorld::Ptr &old, const MWWorld::Ptr &cur) osg::Node* objectNode = cur.getRefData().getBaseNode(); + osg::UserDataContainer* userDataContainer = objectNode->getUserDataContainer(); + if (userDataContainer) + for (unsigned int i=0; igetNumUserObjects(); ++i) + { + if (dynamic_cast(userDataContainer->getUserObject(i))) + userDataContainer->setUserObject(i, new PtrHolder(cur)); + } + if (objectNode->getNumParents()) objectNode->getParent(0)->removeChild(objectNode); cellnode->addChild(objectNode); diff --git a/apps/openmw/mwrender/objects.hpp b/apps/openmw/mwrender/objects.hpp index 716192959..b3799d0ef 100644 --- a/apps/openmw/mwrender/objects.hpp +++ b/apps/openmw/mwrender/objects.hpp @@ -6,6 +6,9 @@ #include #include +#include + +#include "../mwworld/ptr.hpp" namespace osg { @@ -24,7 +27,6 @@ namespace Resource namespace MWWorld { - class Ptr; class CellStore; } @@ -32,6 +34,27 @@ namespace MWRender{ class Animation; +class PtrHolder : public osg::Object +{ +public: + PtrHolder(MWWorld::Ptr ptr) + : mPtr(ptr) + { + } + + PtrHolder() + { + } + + PtrHolder(const PtrHolder& copy, const osg::CopyOp& copyop) + : mPtr(copy.mPtr) + { + } + + META_Object(MWRender, PtrHolder) + + MWWorld::Ptr mPtr; +}; class Objects{ typedef std::map PtrAnimationMap; diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index b8620d60b..c49a44493 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -8,7 +8,10 @@ #include #include #include +#include +#include +#include #include #include @@ -292,6 +295,84 @@ namespace MWRender mObjects->removeObject(ptr); } + osg::Vec4f RenderingManager::getScreenBounds(const MWWorld::Ptr& ptr) + { + if (!ptr.getRefData().getBaseNode()) + return osg::Vec4f(); + + osg::ComputeBoundsVisitor computeBoundsVisitor; + ptr.getRefData().getBaseNode()->accept(computeBoundsVisitor); + + osg::Matrix viewProj = mViewer->getCamera()->getViewMatrix() * mViewer->getCamera()->getProjectionMatrix(); + float min_x = 1.0f, max_x = 0.0f, min_y = 1.0f, max_y = 0.0f; + for (int i=0; i<8; ++i) + { + osg::Vec3f corner = computeBoundsVisitor.getBoundingBox().corner(i); + corner = corner * viewProj; + + float x = (corner.x() + 1.f) * 0.5f; + float y = (corner.y() - 1.f) * (-0.5f); + + if (x < min_x) + min_x = x; + + if (x > max_x) + max_x = x; + + if (y < min_y) + min_y = y; + + if (y > max_y) + max_y = y; + } + + return osg::Vec4f(min_x, min_y, max_x, max_y); + } + + MWWorld::Ptr RenderingManager::getFacedObject(const float nX, const float nY, float maxDistance, bool ignorePlayer) + { + osg::ref_ptr intersector (new osgUtil::LineSegmentIntersector(osgUtil::LineSegmentIntersector::PROJECTION, + nX * 2.f - 1.f, nY * (-2.f) + 1.f)); + + osg::Vec3d dist (0.f, 0.f, -maxDistance); + + dist = dist * mViewer->getCamera()->getProjectionMatrix(); + + osg::Vec3d end = intersector->getEnd(); + end.z() = dist.z(); + intersector->setEnd(end); + intersector->setIntersectionLimit(osgUtil::LineSegmentIntersector::LIMIT_NEAREST); + + osgUtil::IntersectionVisitor intersectionVisitor(intersector); + if (ignorePlayer) + intersectionVisitor.setTraversalMask(intersectionVisitor.getTraversalMask() & (~Mask_Player)); + + mViewer->getCamera()->accept(intersectionVisitor); + + if (intersector->containsIntersections()) + { + osgUtil::LineSegmentIntersector::Intersection intersection = intersector->getFirstIntersection(); + + PtrHolder* ptrHolder = NULL; + for (osg::NodePath::const_iterator it = intersection.nodePath.begin(); it != intersection.nodePath.end(); ++it) + { + osg::UserDataContainer* userDataContainer = (*it)->getUserDataContainer(); + if (!userDataContainer) + continue; + for (unsigned int i=0; igetNumUserObjects(); ++i) + { + if (PtrHolder* p = dynamic_cast(userDataContainer->getUserObject(i))) + ptrHolder = p; + } + } + + if (ptrHolder) + return ptrHolder->mPtr; + } + + return MWWorld::Ptr(); + } + void RenderingManager::updatePtr(const MWWorld::Ptr &old, const MWWorld::Ptr &updated) { mObjects->updatePtr(old, updated); @@ -332,6 +413,7 @@ namespace MWRender if (!mPlayerNode) { mPlayerNode = new osg::PositionAttitudeTransform; + mPlayerNode->setNodeMask(Mask_Player); mLightRoot->addChild(mPlayerNode); } diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 2978c9983..011ceee09 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -73,6 +73,13 @@ namespace MWRender void removeObject(const MWWorld::Ptr& ptr); + /// Return the object under the mouse cursor / crosshair position, given by nX and nY normalized screen coordinates, + /// where (0,0) is the top left corner. + MWWorld::Ptr getFacedObject(const float nX, const float nY, float maxDistance, bool ignorePlayer); + + /// Get the bounding box of the given object in screen coordinates as (minX, minY, maxX, maxY), with (0,0) being the top left corner. + osg::Vec4f getScreenBounds(const MWWorld::Ptr& ptr); + void setSkyEnabled(bool enabled); bool toggleRenderMode(RenderMode mode); diff --git a/apps/openmw/mwrender/vismask.hpp b/apps/openmw/mwrender/vismask.hpp index 512f9f4ad..7382438d1 100644 --- a/apps/openmw/mwrender/vismask.hpp +++ b/apps/openmw/mwrender/vismask.hpp @@ -10,13 +10,14 @@ namespace MWRender Mask_UpdateVisitor = 0x1, // reserved for separating UpdateVisitors from CullVisitors // child of Scene - Mask_Effect = 0x2, - Mask_Debug = 0x4, - Mask_Actor = 0x8, + Mask_Effect = (1<<1), + Mask_Debug = (1<<2), + Mask_Actor = (1<<3), + Mask_Player = (1<<4), // top level masks - Mask_Scene = 0x10, - Mask_GUI = 0x20 + Mask_Scene = (1<<5), + Mask_GUI = (1<<6) }; } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 442f493c1..5689b12cc 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1031,11 +1031,11 @@ namespace MWWorld MWWorld::Ptr World::getFacedObject() { - std::string facedHandle; + MWWorld::Ptr facedObject; if (MWBase::Environment::get().getWindowManager()->isGuiMode() && MWBase::Environment::get().getWindowManager()->isConsoleMode()) - getFacedHandle(facedHandle, getMaxActivationDistance() * 50, false); + facedObject = getFacedObject(getMaxActivationDistance() * 50, false); else { float telekinesisRangeBonus = @@ -1045,13 +1045,10 @@ namespace MWWorld float activationDistance = getMaxActivationDistance() + telekinesisRangeBonus; - getFacedHandle(facedHandle, activationDistance); + facedObject = getFacedObject(activationDistance); } - //if (facedHandle.empty()) - return MWWorld::Ptr(); - - //return getPtrViaHandle(facedHandle); + return facedObject; } std::pair World::getHitContact(const MWWorld::Ptr &ptr, float distance) @@ -1593,11 +1590,8 @@ namespace MWWorld mWorldScene->update (duration, paused); - /* - performUpdateSceneQueries (); - updateWindowManager (); - */ + updateSoundListener(); /* if (!paused && mPlayer->getPlayer().getCell()->isExterior()) @@ -1648,57 +1642,27 @@ namespace MWWorld // retrieve object dimensions so we know where to place the floating label if (!object.isEmpty ()) { - Ogre::SceneNode* node = object.getRefData().getBaseNodeOld(); - Ogre::AxisAlignedBox bounds = node->_getWorldAABB(); - if (bounds.isFinite()) - { - Ogre::Vector4 screenCoords;// = mRendering->boundingBoxToScreen(bounds); - MWBase::Environment::get().getWindowManager()->setFocusObjectScreenCoords( - screenCoords[0], screenCoords[1], screenCoords[2], screenCoords[3]); - } - } - } + osg::Vec4f screenBounds = mRendering->getScreenBounds(object); - void World::performUpdateSceneQueries () - { -#if 0 - if (!mRendering->occlusionQuerySupported()) - { - // cast a ray from player to sun to detect if the sun is visible - // this is temporary until we find a better place to put this code - // currently its here because we need to access the physics system - const float* p = mPlayer->getPlayer().getRefData().getPosition().pos; - Vector3 sun = mRendering->getSkyManager()->getRealSunPos(); - mRendering->getSkyManager()->setGlare(!mPhysics->castRay(Ogre::Vector3(p[0], p[1], p[2]), sun)); + MWBase::Environment::get().getWindowManager()->setFocusObjectScreenCoords( + screenBounds.x(), screenBounds.y(), screenBounds.z(), screenBounds.w()); } -#endif } - void World::getFacedHandle(std::string& facedHandle, float maxDistance, bool ignorePlayer) + MWWorld::Ptr World::getFacedObject(float maxDistance, bool ignorePlayer) { - //maxDistance += mRendering->getCameraDistance(); + maxDistance += mRendering->getCameraDistance(); - std::vector < std::pair < float, std::string > > results; if (MWBase::Environment::get().getWindowManager()->isGuiMode()) { float x, y; MWBase::Environment::get().getWindowManager()->getMousePosition(x, y); - //results = mPhysics->getFacedHandles(x, y, maxDistance); + return mRendering->getFacedObject(x, y, maxDistance, ignorePlayer); } else { - //results = mPhysics->getFacedHandles(maxDistance); + return mRendering->getFacedObject(0.5f, 0.5f, maxDistance, ignorePlayer); } - - if (ignorePlayer && - !results.empty() && results.front().second == "player") - results.erase(results.begin()); - - if (results.empty() - || results.front().second.find("HeightField") != std::string::npos) // Blocked by terrain - facedHandle = ""; - else - facedHandle = results.front().second; } bool World::isCellExterior() const @@ -2744,10 +2708,7 @@ namespace MWWorld if (actor == getPlayerPtr()) { // For the player, use camera to aim - std::string facedHandle; - getFacedHandle(facedHandle, distance); - //if (!facedHandle.empty()) - // target = getPtrViaHandle(facedHandle); + target = getFacedObject(distance); } else { diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index af1e68af1..e217f4bc4 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -121,8 +121,7 @@ namespace MWWorld void updateSoundListener(); void updateWindowManager (); - void performUpdateSceneQueries (); - void getFacedHandle(std::string& facedHandle, float maxDistance, bool ignorePlayer=true); + MWWorld::Ptr getFacedObject(float maxDistance, bool ignorePlayer=true); void removeContainerScripts(const Ptr& reference); void addContainerScripts(const Ptr& reference, CellStore* cell); From d84990be85a0041c66effb8d622853adb408d286 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 24 May 2015 03:59:22 +0200 Subject: [PATCH 1255/3725] Restore getCollisions --- apps/openmw/mwphysics/physicssystem.cpp | 32 +++++++++++++++++++++++-- apps/openmw/mwphysics/physicssystem.hpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 14 +++++------ 3 files changed, 37 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index b32ac2f52..065be083d 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -758,9 +758,37 @@ namespace MWPhysics return std::make_pair(false, osg::Vec3f()); } - std::vector PhysicsSystem::getCollisions(const MWWorld::Ptr &ptr, int collisionGroup, int collisionMask) + class ContactTestResultCallback : public btCollisionWorld::ContactResultCallback { - return std::vector();//mEngine->getCollisions(ptr.getRefData().getBaseNodeOld()->getName(), collisionGroup, collisionMask); + public: + std::vector mResult; + + virtual btScalar addSingleResult(btManifoldPoint& cp, + const btCollisionObjectWrapper* colObj0Wrap,int partId0,int index0, + const btCollisionObjectWrapper* colObj1Wrap,int partId1,int index1) + { + const PtrHolder* holder = static_cast(colObj0Wrap->m_collisionObject->getUserPointer()); + if (holder) + mResult.push_back(holder->getPtr()); + return 0.f; + } + }; + + std::vector PhysicsSystem::getCollisions(const MWWorld::Ptr &ptr, int collisionGroup, int collisionMask) + { + btCollisionObject* me = NULL; + + ObjectMap::iterator found = mObjects.find(ptr); + if (found != mObjects.end()) + me = found->second->getCollisionObject(); + else + return std::vector(); + + ContactTestResultCallback resultCallback; + resultCallback.m_collisionFilterGroup = collisionGroup; + resultCallback.m_collisionFilterMask = collisionMask; + mDynamicsWorld->contactTest(me, resultCallback); + return resultCallback.mResult; } osg::Vec3f PhysicsSystem::traceDown(const MWWorld::Ptr &ptr, float maxHeight) diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index aca24105e..2ebe16e3b 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -77,7 +77,7 @@ namespace MWPhysics void stepSimulation(float dt); - std::vector getCollisions(const MWWorld::Ptr &ptr, int collisionGroup, int collisionMask); ///< get handles this object collides with + std::vector getCollisions(const MWWorld::Ptr &ptr, int collisionGroup, int collisionMask); ///< get handles this object collides with osg::Vec3f traceDown(const MWWorld::Ptr &ptr, float maxHeight); std::pair getHitContact(const MWWorld::Ptr& actor, diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 5689b12cc..57b8b67a4 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -48,6 +48,7 @@ #include "../mwphysics/physicssystem.hpp" #include "../mwphysics/actor.hpp" +#include "../mwphysics/collisiontype.hpp" #include "player.hpp" #include "manualref.hpp" @@ -1420,7 +1421,6 @@ namespace MWWorld void World::processDoors(float duration) { -#if 0 std::map::iterator it = mDoorStates.begin(); while (it != mDoorStates.end()) { @@ -1433,19 +1433,18 @@ namespace MWWorld } else { - float oldRot = Ogre::Radian(it->first.getRefData().getLocalRotation().rot[2]).valueDegrees(); - float diff = duration * 90; + float oldRot = osg::RadiansToDegrees(it->first.getRefData().getLocalRotation().rot[2]); + float diff = duration * 90.f; float targetRot = std::min(std::max(0.f, oldRot + diff * (it->second == 1 ? 1 : -1)), 90.f); localRotateObject(it->first, 0, 0, targetRot); bool reached = (targetRot == 90.f && it->second) || targetRot == 0.f; /// \todo should use convexSweepTest here - std::vector collisions = mPhysics->getCollisions(it->first, OEngine::Physic::CollisionType_Actor - , OEngine::Physic::CollisionType_Actor); - for (std::vector::iterator cit = collisions.begin(); cit != collisions.end(); ++cit) + std::vector collisions = mPhysics->getCollisions(it->first, MWPhysics::CollisionType_Actor, MWPhysics::CollisionType_Actor); + for (std::vector::iterator cit = collisions.begin(); cit != collisions.end(); ++cit) { - MWWorld::Ptr ptr = getPtrViaHandle(*cit); + MWWorld::Ptr ptr = *cit; if (ptr.getClass().isActor()) { // Collided with actor, ask actor to try to avoid door @@ -1471,7 +1470,6 @@ namespace MWWorld ++it; } } -#endif } bool World::toggleCollisionMode() From 95465a1489e63bd7c25046f417c898dfdf848dc2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 24 May 2015 04:00:35 +0200 Subject: [PATCH 1256/3725] Player raycast fix --- apps/openmw/mwrender/renderingmanager.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index c49a44493..e60b35524 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -27,8 +27,6 @@ #include -#include "../mwbase/world.hpp" - #include "sky.hpp" #include "effectmanager.hpp" #include "npcanimation.hpp" @@ -417,9 +415,10 @@ namespace MWRender mLightRoot->addChild(mPlayerNode); } - player.getRefData().setBaseNode(mPlayerNode); + mPlayerNode->setUserDataContainer(new osg::DefaultUserDataContainer); + mPlayerNode->getUserDataContainer()->addUserObject(new PtrHolder(player)); - //attachCameraTo(player); + player.getRefData().setBaseNode(mPlayerNode); } void RenderingManager::renderPlayer(const MWWorld::Ptr &player) From 1fd9fba7a3b68df838436bd2e5703ce9686bfdc1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 24 May 2015 04:28:34 +0200 Subject: [PATCH 1257/3725] Fix debug drawer crash --- apps/openmw/mwrender/bulletdebugdraw.cpp | 46 ++++++++++++++++-------- apps/openmw/mwrender/bulletdebugdraw.hpp | 3 ++ 2 files changed, 35 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwrender/bulletdebugdraw.cpp b/apps/openmw/mwrender/bulletdebugdraw.cpp index 9e683232b..36fc24226 100644 --- a/apps/openmw/mwrender/bulletdebugdraw.cpp +++ b/apps/openmw/mwrender/bulletdebugdraw.cpp @@ -28,19 +28,39 @@ DebugDrawer::DebugDrawer(osg::ref_ptr parentNode, btDynamicsWorld *w mParentNode->addChild(mGeode); mGeode->setNodeMask(Mask_Debug); - mGeometry = new osg::Geometry; + createGeometry(); - mVertices = new osg::Vec3Array; + mParentNode->addChild(mGeode); +} + +void DebugDrawer::createGeometry() +{ + if (!mGeometry) + { + mGeometry = new osg::Geometry; - mDrawArrays = new osg::DrawArrays(osg::PrimitiveSet::LINES); + mVertices = new osg::Vec3Array; - mGeometry->setUseDisplayList(false); - mGeometry->setVertexArray(mVertices); - mGeometry->setDataVariance(osg::Object::DYNAMIC); - mGeometry->addPrimitiveSet(mDrawArrays); + mDrawArrays = new osg::DrawArrays(osg::PrimitiveSet::LINES); - mGeode->addDrawable(mGeometry); - mParentNode->addChild(mGeode); + mGeometry->setUseDisplayList(false); + mGeometry->setVertexArray(mVertices); + mGeometry->setDataVariance(osg::Object::DYNAMIC); + mGeometry->addPrimitiveSet(mDrawArrays); + + mGeode->addDrawable(mGeometry); + } +} + +void DebugDrawer::destroyGeometry() +{ + if (mGeometry) + { + mGeode->removeDrawable(mGeometry); + mGeometry = NULL; + mVertices = NULL; + mDrawArrays = NULL; + } } DebugDrawer::~DebugDrawer() @@ -81,11 +101,9 @@ void DebugDrawer::setDebugMode(int isOn) mDebugOn = (isOn == 0) ? false : true; if (!mDebugOn) - { - mVertices->clear(); - mVertices->releaseGLObjects(0); - mGeometry->releaseGLObjects(0); - } + destroyGeometry(); + else + createGeometry(); } int DebugDrawer::getDebugMode() const diff --git a/apps/openmw/mwrender/bulletdebugdraw.hpp b/apps/openmw/mwrender/bulletdebugdraw.hpp index 288091e7c..d2a4163cf 100644 --- a/apps/openmw/mwrender/bulletdebugdraw.hpp +++ b/apps/openmw/mwrender/bulletdebugdraw.hpp @@ -29,6 +29,9 @@ protected: bool mDebugOn; + void createGeometry(); + void destroyGeometry(); + public: DebugDrawer(osg::ref_ptr parentNode, btDynamicsWorld *world); From 76dd3e40345653aac40647783d45e98e0ce5fb07 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 24 May 2015 04:40:09 +0200 Subject: [PATCH 1258/3725] Fix lip animation regression --- apps/openmw/mwsound/loudness.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwsound/loudness.cpp b/apps/openmw/mwsound/loudness.cpp index 1e6872a76..12fe8ae4d 100644 --- a/apps/openmw/mwsound/loudness.cpp +++ b/apps/openmw/mwsound/loudness.cpp @@ -31,8 +31,8 @@ namespace MWSound value = ((char)(data[sample*advance]^0x80))/128.f; else if (type == SampleType_Int16) { - value = *reinterpret_cast(&data[sample*advance]); - value /= float(std::numeric_limits::max()); + value = *reinterpret_cast(&data[sample*advance]); + value /= float(std::numeric_limits::max()); } else if (type == SampleType_Float32) { From 21af1913e1d1e30dc3fc91e503ff862dba0fae1d Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 24 May 2015 19:18:54 +1000 Subject: [PATCH 1259/3725] Ensure ColumnId names are unique. --- apps/opencs/model/world/columns.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index c937997a9..9491c3246 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -176,7 +176,7 @@ namespace CSMWorld { ColumnId_ContainerContent, "Content" }, { ColumnId_ItemCount, "Count" }, - { ColumnId_InventoryItemId, "ID"}, + { ColumnId_InventoryItemId, "Item ID"}, { ColumnId_CombatState, "Combat" }, { ColumnId_MagicState, "Magic" }, @@ -188,10 +188,10 @@ namespace CSMWorld { ColumnId_ActorInventory, "Inventory" }, { ColumnId_SpellList, "Spells" }, - { ColumnId_SpellId, "ID"}, + { ColumnId_SpellId, "Spell ID"}, { ColumnId_NpcDestinations, "Destinations" }, - { ColumnId_DestinationCell, "Cell"}, + { ColumnId_DestinationCell, "Dest Cell"}, { ColumnId_PosX, "Dest X"}, { ColumnId_PosY, "Dest Y"}, { ColumnId_PosZ, "Dest Z"}, @@ -224,17 +224,17 @@ namespace CSMWorld { ColumnId_BoltSound, "Bolt Sound" }, { ColumnId_PathgridPoints, "Points" }, - { ColumnId_PathgridIndex, "Index" }, + { ColumnId_PathgridIndex, "pIndex" }, { ColumnId_PathgridPosX, "X" }, { ColumnId_PathgridPosY, "Y" }, { ColumnId_PathgridPosZ, "Z" }, { ColumnId_PathgridEdges, "Edges" }, - { ColumnId_PathgridEdgeIndex, "Index" }, + { ColumnId_PathgridEdgeIndex, "eIndex" }, { ColumnId_PathgridEdge0, "Point 0" }, { ColumnId_PathgridEdge1, "Point 1" }, { ColumnId_RegionSounds, "Sounds" }, - { ColumnId_SoundName, "Name" }, + { ColumnId_SoundName, "Sound Name" }, { ColumnId_SoundChance, "Chance" }, { ColumnId_FactionReactions, "Reactions" }, @@ -250,7 +250,7 @@ namespace CSMWorld { ColumnId_AiPackageList, "Ai Packages" }, { ColumnId_AiPackageType, "Package" }, { ColumnId_AiWanderDist, "Wander Dist" }, - { ColumnId_AiDuration, "Duration" }, + { ColumnId_AiDuration, "Ai Duration" }, { ColumnId_AiWanderToD, "Wander ToD" }, { ColumnId_AiWanderIdle, "Wander Idle" }, { ColumnId_AiWanderRepeat, "Wander Repeat" }, @@ -260,11 +260,11 @@ namespace CSMWorld { ColumnId_PartRefList, "Part Reference" }, { ColumnId_PartRefType, "Type" }, - { ColumnId_PartRefMale, "Male" }, - { ColumnId_PartRefFemale, "Female" }, + { ColumnId_PartRefMale, "Male Part" }, + { ColumnId_PartRefFemale, "Female Part" }, { ColumnId_LevelledList,"Levelled List" }, - { ColumnId_LevelledItemId,"Item ID" }, + { ColumnId_LevelledItemId,"Levelled Item" }, { ColumnId_LevelledItemLevel,"Level" }, { ColumnId_LevelledItemType, "Calculate all levels <= player" }, { ColumnId_LevelledItemTypeEach, "Select a new item each instance" }, @@ -278,7 +278,7 @@ namespace CSMWorld { ColumnId_InfoCondFunc, "Function" }, { ColumnId_InfoCondVar, "Func/Variable" }, { ColumnId_InfoCondComp, "Comp" }, - { ColumnId_InfoCondValue, "Value" }, + { ColumnId_InfoCondValue, "Values" }, { ColumnId_OriginalCell, "Original Cell" }, { ColumnId_NpcAttributes, "Attributes" }, From 22420c3a83e5294bbf9d2ef73383d7fc151ca87f Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 24 May 2015 23:19:06 +1000 Subject: [PATCH 1260/3725] Close DialogueSubView if the corresponding record is deleted. Should resolve Bug #2575. - ToDo: Doesn't seem to shrink the widget width properly (when horizontal scrollbar is active) --- apps/opencs/view/world/dialoguesubview.cpp | 19 +++++++++++++++++++ apps/opencs/view/world/dialoguesubview.hpp | 2 ++ 2 files changed, 21 insertions(+) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 647accd4c..0860cf2b2 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -578,6 +578,7 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSM mCommandDispatcher (document, CSMWorld::UniversalId::getParentType (id.getType())) { connect(mTable, SIGNAL(dataChanged (const QModelIndex&, const QModelIndex&)), this, SLOT(dataChanged(const QModelIndex&))); + connect(mTable, SIGNAL(rowsAboutToBeRemoved(const QModelIndex&, int, int)), this, SLOT(rowsAboutToBeRemoved(const QModelIndex&, int, int))); changeCurrentId(id.getId()); @@ -740,6 +741,9 @@ void CSVWorld::DialogueSubView::nextId () void CSVWorld::DialogueSubView::setEditLock (bool locked) { + if (!mEditWidget) // hack to indicate that mCurrentId is no longer valid + return; + mLocked = locked; QModelIndex currentIndex(mTable->getModelIndex(mCurrentId, 0)); @@ -766,6 +770,21 @@ void CSVWorld::DialogueSubView::dataChanged (const QModelIndex & index) } } +void CSVWorld::DialogueSubView::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) +{ + QModelIndex currentIndex(mTable->getModelIndex(mCurrentId, 0)); + + if (currentIndex.isValid() && currentIndex.row() >= start && currentIndex.row() <= end) + { + if(mEditWidget) + { + delete mEditWidget; + mEditWidget = 0; + } + emit closeRequest(this); + } +} + void CSVWorld::DialogueSubView::tableMimeDataDropped (QWidget* editor, const QModelIndex& index, const CSMWorld::UniversalId& id, diff --git a/apps/opencs/view/world/dialoguesubview.hpp b/apps/opencs/view/world/dialoguesubview.hpp index b5a44d266..6d12d62c1 100644 --- a/apps/opencs/view/world/dialoguesubview.hpp +++ b/apps/opencs/view/world/dialoguesubview.hpp @@ -235,6 +235,8 @@ namespace CSVWorld const CSMDoc::Document* document); void requestFocus (const std::string& id); + + void rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end); }; } From e6d2821b78affea63b588988f1b338dcc4667315 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 25 May 2015 09:15:07 +1000 Subject: [PATCH 1261/3725] Refresh table filters when the model is updated. Should resolve Bug #2579. --- apps/opencs/model/world/idtableproxymodel.cpp | 6 ++++++ apps/opencs/model/world/idtableproxymodel.hpp | 2 ++ apps/opencs/view/world/table.cpp | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/apps/opencs/model/world/idtableproxymodel.cpp b/apps/opencs/model/world/idtableproxymodel.cpp index 93c1749c6..84869716e 100644 --- a/apps/opencs/model/world/idtableproxymodel.cpp +++ b/apps/opencs/model/world/idtableproxymodel.cpp @@ -53,3 +53,9 @@ bool CSMWorld::IdTableProxyModel::lessThan(const QModelIndex &left, const QModel { return QSortFilterProxyModel::lessThan(left, right); } + +void CSMWorld::IdTableProxyModel::refreshFilter() +{ + updateColumnMap(); + invalidateFilter(); +} diff --git a/apps/opencs/model/world/idtableproxymodel.hpp b/apps/opencs/model/world/idtableproxymodel.hpp index 23e3193fb..8683c2b9e 100644 --- a/apps/opencs/model/world/idtableproxymodel.hpp +++ b/apps/opencs/model/world/idtableproxymodel.hpp @@ -34,6 +34,8 @@ namespace CSMWorld void setFilter (const boost::shared_ptr& filter); + void refreshFilter(); + protected: bool lessThan(const QModelIndex &left, const QModelIndex &right) const; diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index b8972edbe..bb3dfa4d3 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -649,6 +649,10 @@ void CSVWorld::Table::tableSizeUpdate() } emit tableSizeChanged (size, deleted, modified); + + // not really related to tableSizeUpdate() but placed here for convenience rather than + // creating a bunch of extra connections & slot + mProxyModel->refreshFilter(); } void CSVWorld::Table::selectionSizeUpdate() From 3c82e6d03401795d1e147a8e2f5d32e812eb9c4a Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 25 May 2015 16:36:42 +1000 Subject: [PATCH 1262/3725] Retrieve the correct index for the type of record being un-deleted. --- apps/opencs/model/world/idtable.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index a0dd0b47b..36b3f5c97 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -160,7 +160,7 @@ void CSMWorld::IdTable::setRecord (const std::string& id, const RecordBase& reco if (index==-1) { - int index = mIdCollection->getAppendIndex (id); + int index = mIdCollection->getAppendIndex (id, type); beginInsertRows (QModelIndex(), index, index); From 18f047f50e1f720bafd486a1185f113f2dc35d60 Mon Sep 17 00:00:00 2001 From: Cramal Date: Mon, 25 May 2015 18:40:13 +0900 Subject: [PATCH 1263/3725] Moving to Object/Instance terminology + minor spelling corrections --- manual/opencs/creating_file.tex | 2 +- manual/opencs/main.tex | 2 ++ manual/opencs/recordmodification.tex | 16 ++++++++-------- manual/opencs/recordtypes.tex | 8 ++++---- manual/opencs/tables.tex | 18 +++++++++--------- 5 files changed, 24 insertions(+), 22 deletions(-) diff --git a/manual/opencs/creating_file.tex b/manual/opencs/creating_file.tex index 317e453b7..8cab33fb9 100644 --- a/manual/opencs/creating_file.tex +++ b/manual/opencs/creating_file.tex @@ -17,7 +17,7 @@ It is simple. When you click either \textbf{Create new Addon} you will be asked The last thing to do is to name your your addon and click create. \paragraph{Selecting File for Editing} -Clicking \textbf{Edit A Content File} will show somewhat similar window. Here you should select your Game file with drop down menu. If you want to edit this game file, simply click \textbf{OK} button. If you want to alter addon depending on that file, mark it with checkbox and than click \textbf{Ok} button. +Clicking \textbf{Edit A Content File} will show somewhat similar window. Here you should select your Game file with drop down menu. If you want to edit this game file, simply click \textbf{OK} button. If you want to alter addon depending on that file, mark it with check-box and than click \textbf{Ok} button. \subsection{Advanced} If you are paying attention, you noticed any extra icon with wrench. This one will open small settings window. Those are general OpenCS settings. We will cover this is separate section.\\ diff --git a/manual/opencs/main.tex b/manual/opencs/main.tex index f3a46c1b7..fd85baee4 100644 --- a/manual/opencs/main.tex +++ b/manual/opencs/main.tex @@ -25,7 +25,9 @@ \title{OpenCS User Manual} \maketitle +\newpage \tableofcontents{} +\newpage \input{files_and_directories} \input{creating_file} \input{windows} diff --git a/manual/opencs/recordmodification.tex b/manual/opencs/recordmodification.tex index b1cf866d6..570bd4a95 100644 --- a/manual/opencs/recordmodification.tex +++ b/manual/opencs/recordmodification.tex @@ -1,17 +1,17 @@ \section{Records Modification} \subsection{Introduction} -So far you learned how to browse trough records stored inside the content files, but not how to modify them using the \OCS{} editor. Although browsing is certainly a usefull ability on it's own, You probabbly counted on doing actual editing with this editor. There are few ways user can alter records stored in the content files, each suited for certain class of a problem. In this section We will describe how to do change records using tables interface and edit panel. +So far you learned how to browse trough records stored inside the content files, but not how to modify them using the \OCS{} editor. Although browsing is certainly a useful ability on it's own, You probably counted on doing actual editing with this editor. There are few ways user can alter records stored in the content files, each suited for certain class of a problem. In this section We will describe how to do change records using tables interface and edit panel. \subsubsection{Glossary} \begin{description} - \item[Edit Panel] Interface element used inside the \OCS{} to present records data for editing. Unlike table it showes only one record at the time. However it also presents fields that are not visible inside the table. It is also safe to say that Edit Panel presents data in way that is easier to read thanks to it's horizontal layout. + \item[Edit Panel] Interface element used inside the \OCS{} to present records data for editing. Unlike table it shows only one record at the time. However it also presents fields that are not visible inside the table. It is also safe to say that Edit Panel presents data in way that is easier to read thanks to it's horizontal layout. \end{description} \subsection{Edit Panel Interface} -Edit Panel is designed to aid you with record modification tasks. As It has been said, it uses vertical layout and presents some additional fields when compared with the table -- and some fields, even if they are actually displayed in the table, clearly ill-suited for modification isnide of them (this applies to fields that holds long text strings -- like descriptions). It also displays visual difference beetween non-editable field and editable.\\ +Edit Panel is designed to aid you with record modification tasks. As It has been said, it uses vertical layout and presents some additional fields when compared with the table -- and some fields, even if they are actually displayed in the table, clearly ill-suited for modification inside of them (this applies to fields that holds long text strings -- like descriptions). It also displays visual difference between non-editable field and editable.\\ To open edit panel, please open context menu on any record and choose edit action. This will open edit panel in the same window as your table and will present you the record fields. First data fields are actually not user editable and presented in the form of the text labels at the top of the edit panel. Lower data fields are presented in the form of actually user-editable widgets. Those includes spinboxes, text edits and text fields\footnote{Those are actually a valid terms used to describe classes of the user interface elements. If you don't understand those, don't worry -- those are very standard {GUI} elements present in almost every application since the rise of the desktop metaphor.}. Once you will finish editing one of those fields, data will be updated. There is no apply button of any sort -- simply use one of those widgets and be merry.\\ -In addition to that you probabbly noticed some icons in the bar located at the very bottom of the edit panel. Those can be used to perform the following actions: +In addition to that you probably noticed some icons in the bar located at the very bottom of the edit panel. Those can be used to perform the following actions: \begin{description} \item[Preview] This will launch simple preview panel -- which will be described later. @@ -20,7 +20,7 @@ In addition to that you probabbly noticed some icons in the bar located at the v \end{description} \subsection{Verification tool} -As you could notice there is nothing that can stop you from breaking the game by violating record fields logic, and yet -- it is something that you are always trying to avoid. To adress this problem \OCS{} utilizes so called verification tool (or verifer as many prefer to call it) that basicly goes trough all records and checks if it contains any illogical fields. This includes for instance torch duration equal 0\footnote{Interestingly negative values are perfectly fine: they indicate that light source has no duration limit at all. There are records like this in the original game.} or characters without name, race or any other record with a mandatory field missing.\\ -This tool is even more usefull than it seems. If you somehow delete race that is used by some of the characters, all those characters will be suddenly broken. As a rule of thumb it is a good idea to use verifer before saving your content file.\\ -To launch this usefull tool %don't remember, todo... -Resoults are presented as a yet another table with short (and hopefully descriptive enough) description of the identified problem. It is worth noticing that some records located in the \MW{} esm files are listed by the verification tool -- it is not fault of our tool: those records are just broken. For instance, you actually may find the 0 duration torch. However, those records are usually not placed in game world itself -- and that's good since \MW{} game engine will crash if player equip light source like this!\footnote{We would like to thanks \BS{} for such a usefull testing material. It makes us feel special.} +As you could notice there is nothing that can stop you from breaking the game by violating record fields logic, and yet -- it is something that you are always trying to avoid. To address this problem \OCS{} utilizes so called verification tool (or verifer as many prefer to call it) that basically goes trough all records and checks if it contains any illogical fields. This includes for instance torch duration equal 0\footnote{Interestingly negative values are perfectly fine: they indicate that light source has no duration limit at all. There are records like this in the original game.} or characters without name, race or any other record with a mandatory field missing.\\ +This tool is even more useful than it seems. If you somehow delete race that is used by some of the characters, all those characters will be suddenly broken. As a rule of thumb it is a good idea to use verifer before saving your content file.\\ +To launch this useful tool %don't remember, todo... +Results are presented as a yet another table with short (and hopefully descriptive enough) description of the identified problem. It is worth noticing that some records located in the \MW{} esm files are listed by the verification tool -- it is not fault of our tool: those records are just broken. For instance, you actually may find the 0 duration torch. However, those records are usually not placed in game world itself -- and that's good since \MW{} game engine will crash if player equip light source like this!\footnote{We would like to thanks \BS{} for such a useful testing material. It makes us feel special.} diff --git a/manual/opencs/recordtypes.tex b/manual/opencs/recordtypes.tex index 4dbfbe286..6db338e7e 100644 --- a/manual/opencs/recordtypes.tex +++ b/manual/opencs/recordtypes.tex @@ -1,15 +1,15 @@ \section{Record Types} \subsection{Introduction} -A gameworld contains many objects, such as chests, weapons and monsters. All these objects are merely instances of templates that we call Referenceables. The OpenCS Referenceables table contains information about each of these template objects, eg. its value and weight in the case of items and an aggression level in the case of NPCs. +A gameworld contains many items, such as chests, weapons and monsters. All these items are merely instances of templates that we call \textbf{Objects}. The OpenCS \textbf{Objects} table contains information about each of these template objects, eg. its value and weight in the case of items and an aggression level in the case of NPCs. Let's go through all Record Types and discuss what you can tell OpenCS about them. \begin{description} \item[Activator:] When the player enters the same cell as this object, a script is started. Often it also has a \textbf{Script} attached to it, though it not mandatory. These scripts are small bits of code written in a special scripting language that OpenCS can read and interpret. - \item[Potion:] This is a potion that is not self-made. It has an \textbf{Icon} for your inventory, Aside from the self-explanatory \textbf{Weight} and \textbf{Coin Value}, it has an attribute called \textbf{Auto Calc} set to ``False''. This means that the effects of this potion are preconfigured. This does not happen when the player makes their own potion. - \item[Apparatus:] This is a tool to make potions. Again there's an icon for your inventory as well as a weight and a coin value. It also has a \textbf{Quality} value attached to it: higher the number, the better the effect on your potions will be. The \textbf{Apparatus Type} describes if the item is a Calcinator, Retort, Alembir or Mortar & Pestal. Each has a different effect on the potion the player makes. For more information on this subject, please refer to the \href{http://www.uesp.net/wiki/Morrowind:Alchemy#Tools}{UESP page on Alchemy Tools}. - \item[Armor:] This type of item adds \textbf{Enchantment Points} to the mix. Every piece of clothing or armor has a ''pool'' of potential magicka that gets unlocked when you enchant it. Strong enchantments consume more magicka from this pool: the stronger the enchantment, the more Enchantment Points each cast will take up. For more information on this subject, please refer to the \href{http://www.uesp.net/wiki/Morrowind:Enchant}{Enchant page on UESP}. \textbf{Health} means the amount of hit points this piece of armor has. If it sustains enough damage, the armor will be destroyed. Finally, \textbf{Armor Value} tells the game how much points to add to the player character's Armor Rating. + \item[Potion:] This is a potion that is not self-made. It has an \textbf{Icon} for your inventory, Aside from the self-explanatory \textbf{Weight} and \textbf{Coin Value}, it has an attribute called \textbf{Auto Calc} set to ``False''. This means that the effects of this potion are pre-configured. This does not happen when the player makes their own potion. + \item[Apparatus:] This is a tool to make potions. Again there's an icon for your inventory as well as a weight and a coin value. It also has a \textbf{Quality} value attached to it: higher the number, the better the effect on your potions will be. The \textbf{Apparatus Type} describes if the item is a Calcinator, Retort, Alembic or Mortar & Pestle. Each has a different effect on the potion the player makes. For more information on this subject, please refer to the \href{http://www.uesp.net/wiki/Morrowind:Alchemy#Tools}{UESP page on Alchemy Tools}. + \item[Armor:] This type of item adds \textbf{Enchantment Points} to the mix. Every piece of clothing or armor has a ''pool'' of potential Magicka that gets unlocked when you enchant it. Strong enchantments consume more Magicka from this pool: the stronger the enchantment, the more Enchantment Points each cast will take up. For more information on this subject, please refer to the \href{http://www.uesp.net/wiki/Morrowind:Enchant}{Enchant page on UESP}. \textbf{Health} means the amount of hit points this piece of armor has. If it sustains enough damage, the armor will be destroyed. Finally, \textbf{Armor Value} tells the game how much points to add to the player character's Armor Rating. \item[Book:] This includes scrolls and notes. For the game to make the distinction between books and scrolls, an extra property, \textbf{Scroll}, has been added. Under the \textbf{Skill} column a scroll or book can have an in-game skill listed. Reading this item will raise the player's level in that specific skill. For more information on this, please refer to the \href{http://www.uesp.net/wiki/Morrowind:Skill_Books}{Skill Books page on UESP}. \item[Clothing:] These items work just like Armors, but confer no protective properties. Rather than ``Armor Type'', these items have a ``Clothing Type''. \item[Container:] This is all the stuff that stores items, from chests to sacks to plants. Its \textbf{Capacity} shows how much stuff you can put in the container. You can compare it to the maximum allowed load a player character can carry (who will get over-encumbered and unable to move if he crosses this threshold). A container, however, will just refuse to take the item in question when it gets ''over-encumbered''. \textbf{Organic Container}s are containers such as plants. Containers that \textbf{Respawn} are not safe to store stuff in. After a certain amount of time they will reset to their default contents, meaning that everything in it is gone forever. diff --git a/manual/opencs/tables.tex b/manual/opencs/tables.tex index 503489872..51aac50fd 100644 --- a/manual/opencs/tables.tex +++ b/manual/opencs/tables.tex @@ -14,7 +14,7 @@ Let's browse through the various screens and see what all these tables show. \begin{description} \item[Record:] An entry in \OCS{} representing an item, location, sound, NPC or anything else. - \item[Reference, Referenceable:] When an item is placed in the world, it isn't an isolated and unique object. For example, the game world might contain a lot of exquisite belts on different NPCs and in many crates, but they all refer to one specific record in the game's library: the Exquisite Belt record. In this case, all those belts in crates and on NPCs are references. The central Exquisite Belt record is called a referenceable. This allows modders to make changes to all items of the same type. For example, if you want all exquisite belts to have 4000 enchantment points rather than 400, you will only need to change the referenceable Exquisite Belt rather than all exquisite belts references individually. + \item[Instance, Object:] When an item is placed in the world, it isn't an isolated and unique object. For example, the game world might contain a lot of exquisite belts on different NPCs and in many crates, but they all refer to one specific record in the game's library: the Exquisite Belt record. In this case, all those belts in crates and on NPCs are \textbf{instances}. The central Exquisite Belt record is called a \textbf{object}. This allows modders to make changes to all items of the same type. For example, if you want all exquisite belts to have 4000 enchantment points rather than 400, you will only need to change the \textbf{object}} Exquisite Belt rather than all exquisite belts \textbf{instances}} individually. \end{description} \subsubsection{Recurring Terms} @@ -29,7 +29,7 @@ optionally the Bloodmoon and Tribunal expansions. \item[Modified] means that the record is part of the base game, but has been changed in some way. \item[Deleted] means that this record used to be part of the base game, but has been removed as an entry. This does not mean, however, that the occurrences in the game itself have been removed! For example, if you remove the CharGen\_Bed entry from morrowind.esm, it does not mean the bedroll in the basement -of the Census and Excise Office in Seyda Neen is gone. You're going to have to delete that reference yourself or make sure that that object is replaced +of the Census and Excise Office in Seyda Neen is gone. You're going to have to delete that instance yourself or make sure that that object is replaced by something that still exists otherwise you will get crashes in the worst case scenario. \end{description} @@ -37,12 +37,12 @@ by something that still exists otherwise you will get crashes in the worst case The contents of the game world can be changed by choosing one of the options in the appropriate menu at the top of the screen. \subsubsection{Regions} -This describes the general areas of Vvardenfell. Each of these areas has different rules about things such as encounters and weather. +This describes the general areas of the gameworld. Each of these areas has different rules about things such as encounters and weather. \begin{description} \item[Name:] This is how the game will show your location in-game. - \item[Map Colour:] This is a six-digit hexidecimal representation of the colour used to identify the region on the map available in - World > Region Map. If you do not have an application with a colour picker, you can use your favourite search engine to find a colour picker online. + \item[Map Colour:] This is a six-digit hexadecimal representation of the color used to identify the region on the map available in + World > Region Map. If you do not have an application with a color picker, you can use your favorite search engine to find a color picker on-line. \item[Sleep Encounter:] These are the rules for what kind of enemies you might encounter when you sleep outside in the wild. \end{description} @@ -52,7 +52,7 @@ why would the computer need to keep track the exact locations of NPCs walking th be quite useless and bring your system to its knees! So the world has been divided up into squares we call "cells". Once your character enters a cell, the game will load everything that is going on in that cell so you can interact with it. -In the original \MW{} this could be seen when you were travelling and you would see a small loading bar at the bottom of the screen; +In the original \MW{} this could be seen when you were traveling and you would see a small loading bar at the bottom of the screen; you had just entered a new cell and the game would have to load all the items and NPCs. The Cells screen in \OCS{} provides you with a list of cells in the game, both the interior cells (houses, dungeons, mines, etc.) and the exterior cells (the outside world). @@ -71,7 +71,7 @@ in the game, both the interior cells (houses, dungeons, mines, etc.) and the ext \item[Interior Sky:] Should this interior cell have a sky? This is a rather unique case. The \TB{} expansion took place in a city on the mainland. Normally this would require the city to be composed of exterior cells so it has a sky, weather and the like. But if the player is - in an exterior cell and looks at his in-game map, he sees Vvardenfell with an overview of all exterior cells. The player would have to see + in an exterior cell and looks at his in-game map, he sees the map of the gameworld with an overview of all exterior cells. The player would have to see the city's very own map, as if he was walking around in an interior cell. So the developers decided to create a workaround and take a bit of both: The whole city would technically work exactly like an interior cell, @@ -83,7 +83,7 @@ in the game, both the interior cells (houses, dungeons, mines, etc.) and the ext \end{description} -\subsubsection{Referenceables} +\subsubsection{Objects} This is a library of all the items, triggers, containers, NPCs, etc. in the game. There are several kinds of Record Types. Depending on which type a record is, it will need specific information to function. For example, an NPC needs a value attached to its aggression level. A chest, of course, does not. All Record Types contain at least a~model. How else would the player see them? Usually they also have a Name, which is what you see @@ -91,4 +91,4 @@ when you hover your reticle over the object. This is a library of all the items, triggers, containers, NPCs, etc. in the game. There are several kinds of Record Types. Depending on which type a record is, it will need specific information to function. For example, an NPC needs a value attached to its aggression level. A chest, of course, does not. All Record Types contain at least a model. How else would the player see them? Usually they also have a Name, which is what you see when you hover your reticle over the object. -Please refer to the Record Types section for an overview of what each type of Referenceable does and what you can tell OpenCS about these objects. +Please refer to the Record Types section for an overview of what each type of object does and what you can tell OpenCS about these objects. From ad77c662aaffab0db65712187ae80dba556611ce Mon Sep 17 00:00:00 2001 From: Cramal Date: Mon, 25 May 2015 18:44:21 +0900 Subject: [PATCH 1264/3725] correct latex error --- manual/opencs/tables.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manual/opencs/tables.tex b/manual/opencs/tables.tex index 51aac50fd..984157f88 100644 --- a/manual/opencs/tables.tex +++ b/manual/opencs/tables.tex @@ -14,7 +14,7 @@ Let's browse through the various screens and see what all these tables show. \begin{description} \item[Record:] An entry in \OCS{} representing an item, location, sound, NPC or anything else. - \item[Instance, Object:] When an item is placed in the world, it isn't an isolated and unique object. For example, the game world might contain a lot of exquisite belts on different NPCs and in many crates, but they all refer to one specific record in the game's library: the Exquisite Belt record. In this case, all those belts in crates and on NPCs are \textbf{instances}. The central Exquisite Belt record is called a \textbf{object}. This allows modders to make changes to all items of the same type. For example, if you want all exquisite belts to have 4000 enchantment points rather than 400, you will only need to change the \textbf{object}} Exquisite Belt rather than all exquisite belts \textbf{instances}} individually. + \item[Instance, Object:] When an item is placed in the world, it isn't an isolated and unique object. For example, the game world might contain a lot of exquisite belts on different NPCs and in many crates, but they all refer to one specific record in the game's library: the Exquisite Belt record. In this case, all those belts in crates and on NPCs are \textbf{instances}. The central Exquisite Belt record is called a \textbf{object}. This allows modders to make changes to all items of the same type. For example, if you want all exquisite belts to have 4000 enchantment points rather than 400, you will only need to change the \textbf{object} Exquisite Belt rather than all exquisite belts \textbf{instances} individually. \end{description} \subsubsection{Recurring Terms} From 08484a46c7e8ed17202eb28d1cbf4f43799e5320 Mon Sep 17 00:00:00 2001 From: Cramal Date: Mon, 25 May 2015 18:45:42 +0900 Subject: [PATCH 1265/3725] remove latex error --- manual/opencs/recordtypes.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manual/opencs/recordtypes.tex b/manual/opencs/recordtypes.tex index 6db338e7e..661f5ac7d 100644 --- a/manual/opencs/recordtypes.tex +++ b/manual/opencs/recordtypes.tex @@ -8,7 +8,7 @@ Let's go through all Record Types and discuss what you can tell OpenCS about the \begin{description} \item[Activator:] When the player enters the same cell as this object, a script is started. Often it also has a \textbf{Script} attached to it, though it not mandatory. These scripts are small bits of code written in a special scripting language that OpenCS can read and interpret. \item[Potion:] This is a potion that is not self-made. It has an \textbf{Icon} for your inventory, Aside from the self-explanatory \textbf{Weight} and \textbf{Coin Value}, it has an attribute called \textbf{Auto Calc} set to ``False''. This means that the effects of this potion are pre-configured. This does not happen when the player makes their own potion. - \item[Apparatus:] This is a tool to make potions. Again there's an icon for your inventory as well as a weight and a coin value. It also has a \textbf{Quality} value attached to it: higher the number, the better the effect on your potions will be. The \textbf{Apparatus Type} describes if the item is a Calcinator, Retort, Alembic or Mortar & Pestle. Each has a different effect on the potion the player makes. For more information on this subject, please refer to the \href{http://www.uesp.net/wiki/Morrowind:Alchemy#Tools}{UESP page on Alchemy Tools}. + \item[Apparatus:] This is a tool to make potions. Again there's an icon for your inventory as well as a weight and a coin value. It also has a \textbf{Quality} value attached to it: higher the number, the better the effect on your potions will be. The \textbf{Apparatus Type} describes if the item is a Calcinator, Retort, Alembic or Mortar \& Pestle. Each has a different effect on the potion the player makes. For more information on this subject, please refer to the \href{http://www.uesp.net/wiki/Morrowind:Alchemy#Tools}{UESP page on Alchemy Tools}. \item[Armor:] This type of item adds \textbf{Enchantment Points} to the mix. Every piece of clothing or armor has a ''pool'' of potential Magicka that gets unlocked when you enchant it. Strong enchantments consume more Magicka from this pool: the stronger the enchantment, the more Enchantment Points each cast will take up. For more information on this subject, please refer to the \href{http://www.uesp.net/wiki/Morrowind:Enchant}{Enchant page on UESP}. \textbf{Health} means the amount of hit points this piece of armor has. If it sustains enough damage, the armor will be destroyed. Finally, \textbf{Armor Value} tells the game how much points to add to the player character's Armor Rating. \item[Book:] This includes scrolls and notes. For the game to make the distinction between books and scrolls, an extra property, \textbf{Scroll}, has been added. Under the \textbf{Skill} column a scroll or book can have an in-game skill listed. Reading this item will raise the player's level in that specific skill. For more information on this, please refer to the \href{http://www.uesp.net/wiki/Morrowind:Skill_Books}{Skill Books page on UESP}. \item[Clothing:] These items work just like Armors, but confer no protective properties. Rather than ``Armor Type'', these items have a ``Clothing Type''. From 95f740ec40b76db5892ef9c93ef35480fb6a00a7 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 25 May 2015 22:28:41 +1000 Subject: [PATCH 1266/3725] Give CSVWorld::EditWidget::mMainWidget a chance to clean up its children. Should resolve Bug #2578. --- apps/opencs/view/world/dialoguesubview.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 2cf30dcbe..7a25a7fc1 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -378,6 +378,13 @@ mDocument (document) void CSVWorld::EditWidget::remake(int row) { + if (mMainWidget) + { + QWidget *del = this->takeWidget(); + del->deleteLater(); + } + mMainWidget = new QWidget (this); + for (unsigned i = 0; i < mNestedModels.size(); ++i) delete mNestedModels[i]; @@ -401,12 +408,6 @@ void CSVWorld::EditWidget::remake(int row) if (mNestedTableMapper) delete mNestedTableMapper; - if (mMainWidget) - { - QWidget *del = this->takeWidget(); - del->deleteLater(); - } - mMainWidget = new QWidget (this); QFrame* line = new QFrame(mMainWidget); line->setObjectName(QString::fromUtf8("line")); From ec808843c3614e4615a6c7afb6f0acc5a28a94c7 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Tue, 26 May 2015 13:35:10 +1000 Subject: [PATCH 1267/3725] Do not rebuild the dialogue subview unless required. Should resolve Bug #2581. The loss of focus was caused by each text change (i.e. character entry) to a QPlainTextEdit resulting in dataChanged() signal which in turn rebuilt the dialogue subview. Changes in this commit include: - Do not send signal to update entire row if only a single item has changed. - Do not rebuild the dialogue subview unless the data item that triggers a conditional display is changed. - Add column flags to indicate whether the data in this column should rebuild the dialogue subview. - Return the correct flags for nested columns - Disable, rather than grey out, checkbox that does not apply to creature levelled list --- apps/opencs/model/world/columnbase.cpp | 4 ++-- apps/opencs/model/world/columnbase.hpp | 8 ++++--- apps/opencs/model/world/columnimp.hpp | 4 ++-- apps/opencs/model/world/data.cpp | 21 +++++++++++------ apps/opencs/model/world/idtable.cpp | 3 +-- apps/opencs/model/world/idtree.cpp | 6 ++--- apps/opencs/model/world/refidadapterimp.hpp | 2 +- apps/opencs/model/world/refidcollection.cpp | 3 ++- apps/opencs/view/world/dialoguesubview.cpp | 26 +++++++++++++++++---- 9 files changed, 52 insertions(+), 25 deletions(-) diff --git a/apps/opencs/model/world/columnbase.cpp b/apps/opencs/model/world/columnbase.cpp index 0e0ff11d4..3d13538c0 100644 --- a/apps/opencs/model/world/columnbase.cpp +++ b/apps/opencs/model/world/columnbase.cpp @@ -138,8 +138,8 @@ bool CSMWorld::NestableColumn::hasChildren() const } CSMWorld::NestedChildColumn::NestedChildColumn (int id, - CSMWorld::ColumnBase::Display display, bool isEditable) - : NestableColumn (id, display, CSMWorld::ColumnBase::Flag_Dialogue) , mIsEditable(isEditable) + CSMWorld::ColumnBase::Display display, int flags, bool isEditable) + : NestableColumn (id, display, flags) , mIsEditable(isEditable) {} bool CSMWorld::NestedChildColumn::isEditable () const diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index d6dd4b291..70b2a35b7 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -25,7 +25,8 @@ namespace CSMWorld { Flag_Table = 1, // column should be displayed in table view Flag_Dialogue = 2, // column should be displayed in dialogue view - Flag_Dialogue_List = 4 // column should be diaplyed in dialogue view + Flag_Dialogue_List = 4, // column should be diaplyed in dialogue view + Flag_Dialogue_Refresh = 8 // refresh dialogue view if this column is modified }; enum Display @@ -183,7 +184,7 @@ namespace CSMWorld template struct NestedParentColumn : public Column { - NestedParentColumn (int id, int flags = ColumnBase::Flag_Dialogue) : Column (id, + NestedParentColumn (int id, int flags = Flag_Dialogue) : Column (id, ColumnBase::Display_NestedHeader, flags) {} @@ -200,7 +201,8 @@ namespace CSMWorld struct NestedChildColumn : public NestableColumn { - NestedChildColumn (int id, Display display, bool isEditable = true); + NestedChildColumn (int id, + Display display, int flags = Flag_Dialogue, bool isEditable = true); virtual bool isEditable() const; diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index cbe0d74c4..64a1cf3d7 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -467,8 +467,8 @@ namespace CSMWorld int mMask; bool mInverted; - FlagColumn (int columnId, int mask, bool inverted = false) - : Column (columnId, ColumnBase::Display_Boolean), mMask (mask), + FlagColumn (int columnId, int mask, int flags = Flag_Table | Flag_Dialogue, bool inverted = false) + : Column (columnId, ColumnBase::Display_Boolean, flags), mMask (mask), mInverted (inverted) {} diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 920c7db71..c27c068f1 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -141,7 +141,8 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc index = mRaces.getColumns()-1; mRaces.addAdapter (std::make_pair(&mRaces.getColumn(index), new RaceAttributeAdapter())); mRaces.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_RaceAttributes, ColumnBase::Display_String, false)); + new NestedChildColumn (Columns::ColumnId_RaceAttributes, ColumnBase::Display_String, + ColumnBase::Flag_Dialogue, false)); mRaces.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_RaceMaleValue, ColumnBase::Display_Integer)); mRaces.getNestableColumn(index)->addColumn( @@ -287,8 +288,10 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mCells.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Cell)); mCells.addColumn (new NameColumn); mCells.addColumn (new FlagColumn (Columns::ColumnId_SleepForbidden, ESM::Cell::NoSleep)); - mCells.addColumn (new FlagColumn (Columns::ColumnId_InteriorWater, ESM::Cell::HasWater)); - mCells.addColumn (new FlagColumn (Columns::ColumnId_InteriorSky, ESM::Cell::QuasiEx)); + mCells.addColumn (new FlagColumn (Columns::ColumnId_InteriorWater, ESM::Cell::HasWater, + ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue | ColumnBase::Flag_Dialogue_Refresh)); + mCells.addColumn (new FlagColumn (Columns::ColumnId_InteriorSky, ESM::Cell::QuasiEx, + ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue | ColumnBase::Flag_Dialogue_Refresh)); mCells.addColumn (new RegionColumn); mCells.addColumn (new RefNumCounterColumn); // Misc Cell data @@ -297,7 +300,8 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc index = mCells.getColumns()-1; mCells.addAdapter (std::make_pair(&mCells.getColumn(index), new CellListAdapter ())); mCells.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_Interior, ColumnBase::Display_Boolean)); + new NestedChildColumn (Columns::ColumnId_Interior, ColumnBase::Display_Boolean, + ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue | ColumnBase::Flag_Dialogue_Refresh)); mCells.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_Ambient, ColumnBase::Display_Integer)); mCells.getNestableColumn(index)->addColumn( @@ -346,7 +350,8 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mBodyParts.addColumn (new BodyPartTypeColumn); mBodyParts.addColumn (new VampireColumn); mBodyParts.addColumn (new FlagColumn (Columns::ColumnId_Female, ESM::BodyPart::BPF_Female)); - mBodyParts.addColumn (new FlagColumn (Columns::ColumnId_Playable, ESM::BodyPart::BPF_NotPlayable, true)); + mBodyParts.addColumn (new FlagColumn (Columns::ColumnId_Playable, + ESM::BodyPart::BPF_NotPlayable, ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue, true)); mBodyParts.addColumn (new MeshTypeColumn); mBodyParts.addColumn (new ModelColumn); mBodyParts.addColumn (new RaceColumn); @@ -393,7 +398,8 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc // new objects deleted in dtor of NestableColumn // WARNING: The order of the columns below are assumed in PathgridPointListAdapter mPathgrids.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_PathgridIndex, ColumnBase::Display_Integer, false)); + new NestedChildColumn (Columns::ColumnId_PathgridIndex, ColumnBase::Display_Integer, + ColumnBase::Flag_Dialogue, false)); mPathgrids.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_PathgridPosX, ColumnBase::Display_Integer)); mPathgrids.getNestableColumn(index)->addColumn( @@ -405,7 +411,8 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc index = mPathgrids.getColumns()-1; mPathgrids.addAdapter (std::make_pair(&mPathgrids.getColumn(index), new PathgridEdgeListAdapter ())); mPathgrids.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_PathgridEdgeIndex, ColumnBase::Display_Integer, false)); + new NestedChildColumn (Columns::ColumnId_PathgridEdgeIndex, ColumnBase::Display_Integer, + ColumnBase::Flag_Dialogue, false)); mPathgrids.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_PathgridEdge0, ColumnBase::Display_Integer)); mPathgrids.getNestableColumn(index)->addColumn( diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 36b3f5c97..04aa271cc 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -74,8 +74,7 @@ bool CSMWorld::IdTable::setData (const QModelIndex &index, const QVariant &value { mIdCollection->setData (index.row(), index.column(), value); - emit dataChanged (CSMWorld::IdTable::index (index.row(), 0), - CSMWorld::IdTable::index (index.row(), mIdCollection->getColumns()-1)); + emit dataChanged (index, index); return true; } diff --git a/apps/opencs/model/world/idtree.cpp b/apps/opencs/model/world/idtree.cpp index 06db09a0f..7351c03a7 100644 --- a/apps/opencs/model/world/idtree.cpp +++ b/apps/opencs/model/world/idtree.cpp @@ -74,7 +74,7 @@ QVariant CSMWorld::IdTree::nestedHeaderData(int section, int subSection, Qt::Ori return tr(parentColumn->nestedColumn(subSection).getTitle().c_str()); if (role==ColumnBase::Role_Flags) - return idCollection()->getColumn (section).mFlags; + return parentColumn->nestedColumn(subSection).mFlags; if (role==ColumnBase::Role_Display) return parentColumn->nestedColumn(subSection).mDisplayType; @@ -92,8 +92,8 @@ bool CSMWorld::IdTree::setData (const QModelIndex &index, const QVariant &value, mNestedCollection->setNestedData(parentAddress.first, parentAddress.second, value, index.row(), index.column()); - emit dataChanged (CSMWorld::IdTree::index (parentAddress.first, 0), - CSMWorld::IdTree::index (parentAddress.first, idCollection()->getColumns()-1)); + emit dataChanged (index, index); + return true; } else diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index 3411429d0..869996da5 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -1976,7 +1976,7 @@ namespace CSMWorld { switch (subColIndex) { - case 0: return QVariant(QVariant::UserType); // disable the checkbox editor + case 0: return QVariant(); // disable the checkbox editor case 1: return record.get().mFlags & ESM::CreatureLevList::AllLevels; case 2: return static_cast (record.get().mChanceNone); default: diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 9d9e9826a..cda19c87b 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -245,7 +245,8 @@ CSMWorld::RefIdCollection::RefIdCollection() actorsColumns.mServices.insert (std::make_pair (&mColumns.back(), sServiceTable[i].mFlag)); } - mColumns.push_back (RefIdColumn (Columns::ColumnId_AutoCalc, ColumnBase::Display_Boolean)); + mColumns.push_back (RefIdColumn (Columns::ColumnId_AutoCalc, ColumnBase::Display_Boolean, + ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue | ColumnBase::Flag_Dialogue_Refresh)); const RefIdColumn *autoCalc = &mColumns.back(); mColumns.push_back (RefIdColumn (Columns::ColumnId_ApparatusType, diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 2cf30dcbe..03fa532c5 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -787,14 +787,32 @@ void CSVWorld::DialogueSubView::dataChanged (const QModelIndex & index) { QModelIndex currentIndex(mTable->getModelIndex(mCurrentId, 0)); - if (currentIndex.isValid() && index.row() == currentIndex.row()) + if (currentIndex.isValid() && + (index.parent().isValid() ? index.parent().row() : index.row()) == currentIndex.row()) { CSMWorld::RecordBase::State state = static_cast(mTable->data (mTable->index (currentIndex.row(), 1)).toInt()); mEditWidget->setDisabled (state==CSMWorld::RecordBase::State_Deleted || mLocked); - int y = mEditWidget->verticalScrollBar()->value(); - mEditWidget->remake (index.row()); - mEditWidget->verticalScrollBar()->setValue(y); + + // Check if the changed data should force refresh (rebuild) the dialogue subview + int flags = 0; + if (index.parent().isValid()) // TODO: check that index is topLeft + { + flags = static_cast(mTable)->nestedHeaderData (index.parent().column(), + index.column(), Qt::Horizontal, CSMWorld::ColumnBase::Role_Flags).toInt(); + } + else + { + flags = mTable->headerData (index.column(), + Qt::Horizontal, CSMWorld::ColumnBase::Role_Flags).toInt(); + } + + if (flags & CSMWorld::ColumnBase::Flag_Dialogue_Refresh) + { + int y = mEditWidget->verticalScrollBar()->value(); + mEditWidget->remake (index.parent().isValid() ? index.parent().row() : index.row()); + mEditWidget->verticalScrollBar()->setValue(y); + } } } From 2f29c2c077491f378e3abad231010e1643c64319 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Tue, 26 May 2015 13:58:58 +1000 Subject: [PATCH 1268/3725] Qualify the scope of Flag_Dialogue. --- apps/opencs/model/world/columnbase.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index 70b2a35b7..bf8378e37 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -184,7 +184,7 @@ namespace CSMWorld template struct NestedParentColumn : public Column { - NestedParentColumn (int id, int flags = Flag_Dialogue) : Column (id, + NestedParentColumn (int id, int flags = ColumnBase::Flag_Dialogue) : Column (id, ColumnBase::Display_NestedHeader, flags) {} @@ -202,7 +202,7 @@ namespace CSMWorld struct NestedChildColumn : public NestableColumn { NestedChildColumn (int id, - Display display, int flags = Flag_Dialogue, bool isEditable = true); + Display display, int flags = ColumnBase::Flag_Dialogue, bool isEditable = true); virtual bool isEditable() const; From aafcaf32c5ba50bb1b92c44dda31e1d0f4ba1d5b Mon Sep 17 00:00:00 2001 From: cc9cii Date: Tue, 26 May 2015 16:12:54 +1000 Subject: [PATCH 1269/3725] Qualify the scope of Flag_Dialogue. (another one) --- apps/opencs/model/world/columnimp.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index 64a1cf3d7..6b496e0ca 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -467,7 +467,8 @@ namespace CSMWorld int mMask; bool mInverted; - FlagColumn (int columnId, int mask, int flags = Flag_Table | Flag_Dialogue, bool inverted = false) + FlagColumn (int columnId, int mask, + int flags = ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue, bool inverted = false) : Column (columnId, ColumnBase::Display_Boolean, flags), mMask (mask), mInverted (inverted) {} From f06ddd47c40f100a9610af3baf8b572d6308bbed Mon Sep 17 00:00:00 2001 From: cc9cii Date: Tue, 26 May 2015 17:38:22 +1000 Subject: [PATCH 1270/3725] Return the correct range for a given topic. Should resolve Bug #2569. --- apps/opencs/model/world/infocollection.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/apps/opencs/model/world/infocollection.cpp b/apps/opencs/model/world/infocollection.cpp index f2d81823c..a508d28f3 100644 --- a/apps/opencs/model/world/infocollection.cpp +++ b/apps/opencs/model/world/infocollection.cpp @@ -173,6 +173,17 @@ CSMWorld::InfoCollection::Range CSMWorld::InfoCollection::getTopicRange (const s RecordConstIterator begin = getRecords().begin()+iter->second; + while (begin != getRecords().begin()) + { + if (!Misc::StringUtils::ciEqual(begin->get().mTopicId, topic2)) + { + // we've gone one too far, go back + ++begin; + break; + } + --begin; + } + // Find end RecordConstIterator end = begin; From 3dcb167066831c47a6a5a1063faefe8ac3da473b Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 26 May 2015 16:40:44 +0200 Subject: [PATCH 1271/3725] Map rendering --- apps/openmw/engine.cpp | 2 +- apps/openmw/mwbase/windowmanager.hpp | 9 +- apps/openmw/mwbase/world.hpp | 11 +- apps/openmw/mwgui/hud.cpp | 4 +- apps/openmw/mwgui/hud.hpp | 2 +- apps/openmw/mwgui/loadingscreen.cpp | 1 - apps/openmw/mwgui/loadingscreen.hpp | 2 - apps/openmw/mwgui/mapwindow.cpp | 61 ++- apps/openmw/mwgui/mapwindow.hpp | 19 +- apps/openmw/mwgui/tooltips.cpp | 2 +- apps/openmw/mwgui/windowmanagerimp.cpp | 68 ++- apps/openmw/mwgui/windowmanagerimp.hpp | 13 +- apps/openmw/mwphysics/actor.cpp | 1 - apps/openmw/mwrender/animation.cpp | 1 - apps/openmw/mwrender/characterpreview.cpp | 3 + apps/openmw/mwrender/localmap.cpp | 524 +++++++++++----------- apps/openmw/mwrender/localmap.hpp | 119 ++--- apps/openmw/mwrender/objects.cpp | 7 +- apps/openmw/mwrender/renderingmanager.cpp | 17 +- apps/openmw/mwrender/sky.cpp | 9 +- apps/openmw/mwrender/vismask.hpp | 10 +- apps/openmw/mwworld/scene.cpp | 10 +- apps/openmw/mwworld/worldimp.cpp | 58 ++- apps/openmw/mwworld/worldimp.hpp | 12 +- components/myguiplatform/myguitexture.cpp | 2 +- components/nifosg/controller.cpp | 1 - components/nifosg/nifloader.cpp | 2 - components/nifosg/particle.cpp | 2 - components/sceneutil/lightmanager.cpp | 7 + components/sceneutil/lightmanager.hpp | 3 + components/sceneutil/riggeometry.cpp | 1 - 31 files changed, 530 insertions(+), 453 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 08dba334f..9bfd86709 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -596,7 +596,7 @@ void OMW::Engine::go() { double dt = frameTimer.time_s(); frameTimer.setStartTick(); - //dt = std::min(dt, 0.2); + dt = std::min(dt, 0.2); double simulationTime = frame(dt); mViewer->frame(simulationTime); diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index d1f1ad3a3..37112477e 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -178,12 +178,6 @@ namespace MWBase virtual void changeCell(MWWorld::CellStore* cell) = 0; ///< change the active cell - virtual void setPlayerPos(int cellX, int cellY, const float x, const float y) = 0; - ///< set player position in map space - - virtual void setPlayerDir(const float x, const float y) = 0; - ///< set player view direction in map space - virtual void setFocusObject(const MWWorld::Ptr& focus) = 0; virtual void setFocusObjectScreenCoords(float min_x, float min_y, float max_x, float max_y) = 0; @@ -358,6 +352,9 @@ namespace MWBase virtual std::string correctIconPath(const std::string& path) = 0; virtual std::string correctBookartPath(const std::string& path, int width, int height) = 0; virtual std::string correctTexturePath(const std::string& path) = 0; + + virtual void requestMap(std::set cells) = 0; + virtual void removeCell(MWWorld::CellStore* cell) = 0; }; } diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 6d1bc34bc..c0e2ade0f 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -142,21 +142,12 @@ namespace MWBase virtual bool isCellQuasiExterior() const = 0; - virtual Ogre::Vector2 getNorthVector (MWWorld::CellStore* cell) = 0; + virtual osg::Vec2f getNorthVector (MWWorld::CellStore* cell) = 0; ///< get north vector for given interior cell virtual void getDoorMarkers (MWWorld::CellStore* cell, std::vector& out) = 0; ///< get a list of teleport door markers for a given cell, to be displayed on the local map - virtual void worldToInteriorMapPosition (Ogre::Vector2 position, float& nX, float& nY, int &x, int& y) = 0; - ///< see MWRender::LocalMap::worldToInteriorMapPosition - - virtual Ogre::Vector2 interiorMapToWorldPosition (float nX, float nY, int x, int y) = 0; - ///< see MWRender::LocalMap::interiorMapToWorldPosition - - virtual bool isPositionExplored (float nX, float nY, int x, int y, bool interior) = 0; - ///< see MWRender::LocalMap::isPositionExplored - virtual void setGlobalInt (const std::string& name, int value) = 0; ///< Set value independently from real type. diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index a1e027f89..43df37b6d 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -70,9 +70,9 @@ namespace MWGui }; - HUD::HUD(CustomMarkerCollection &customMarkers, bool showFps, DragAndDrop* dragAndDrop) + HUD::HUD(CustomMarkerCollection &customMarkers, bool showFps, DragAndDrop* dragAndDrop, MWRender::LocalMap* localMapRender) : Layout("openmw_hud.layout") - , LocalMapBase(customMarkers) + , LocalMapBase(customMarkers, localMapRender) , mHealth(NULL) , mMagicka(NULL) , mStamina(NULL) diff --git a/apps/openmw/mwgui/hud.hpp b/apps/openmw/mwgui/hud.hpp index 9eed9811a..72fc06f6a 100644 --- a/apps/openmw/mwgui/hud.hpp +++ b/apps/openmw/mwgui/hud.hpp @@ -19,7 +19,7 @@ namespace MWGui class HUD : public Layout, public LocalMapBase { public: - HUD(CustomMarkerCollection& customMarkers, bool fpsVisible, DragAndDrop* dragAndDrop); + HUD(CustomMarkerCollection& customMarkers, bool fpsVisible, DragAndDrop* dragAndDrop, MWRender::LocalMap* localMapRender); virtual ~HUD(); void setValue (const std::string& id, const MWMechanics::DynamicStat& value); void setFPS(float fps); diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index cdb2d6bdf..1f084402b 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -35,7 +35,6 @@ namespace MWGui , mLastRenderTime(0.0) , mLoadingOnTime(0.0) , mProgress(0) - , mVSyncWasEnabled(false) { mMainWidget->setSize(MyGUI::RenderManager::getInstance().getViewSize()); diff --git a/apps/openmw/mwgui/loadingscreen.hpp b/apps/openmw/mwgui/loadingscreen.hpp index a1e6e4d21..baacc7133 100644 --- a/apps/openmw/mwgui/loadingscreen.hpp +++ b/apps/openmw/mwgui/loadingscreen.hpp @@ -67,8 +67,6 @@ namespace MWGui std::vector mSplashScreens; - bool mVSyncWasEnabled; - void changeWallpaper(); void draw(); diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 28fd13335..95de175a3 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -26,6 +26,7 @@ #include "../mwworld/esmstore.hpp" #include "../mwrender/globalmap.hpp" +#include "../mwrender/localmap.hpp" #include "widgets.hpp" #include "confirmationdialog.hpp" @@ -142,8 +143,9 @@ namespace MWGui // ------------------------------------------------------ - LocalMapBase::LocalMapBase(CustomMarkerCollection &markers) - : mCurX(0) + LocalMapBase::LocalMapBase(CustomMarkerCollection &markers, MWRender::LocalMap* localMapRender) + : mLocalMapRender(localMapRender) + , mCurX(0) , mCurY(0) , mInterior(false) , mLocalMap(NULL) @@ -260,8 +262,8 @@ namespace MWGui else { int cellX, cellY; - Ogre::Vector2 worldPos (worldX, worldY); - MWBase::Environment::get().getWorld ()->worldToInteriorMapPosition (worldPos, nX, nY, cellX, cellY); + osg::Vec2f worldPos (worldX, worldY); + mLocalMapRender->worldToInteriorMapPosition(worldPos, nX, nY, cellX, cellY); markerPos.cellX = cellX; markerPos.cellY = cellY; @@ -301,7 +303,7 @@ namespace MWGui continue; } - MarkerUserData markerPos; + MarkerUserData markerPos (mLocalMapRender); MyGUI::IntPoint widgetPos = getMarkerPosition(marker.mWorldX, marker.mWorldY, markerPos); MyGUI::IntCoord widgetCoord(widgetPos.left - 8, @@ -342,24 +344,30 @@ namespace MWGui mDoorMarkerWidgets.clear(); // Update the map textures -#if 0 + std::vector > textures; for (int mx=0; mx<3; ++mx) { for (int my=0; my<3; ++my) { - // map - std::string image = mPrefix+"_"+ MyGUI::utility::toString(x + (mx-1)) + "_" - + MyGUI::utility::toString(y + (-1*(my-1))); + int mapX = x + (mx-1); + int mapY = y + (-1*(my-1)); MyGUI::ImageBox* box = mMapWidgets[my + 3*mx]; - if (MyGUI::RenderManager::getInstance().getTexture(image) != 0) - box->setImageTexture(image); + osg::ref_ptr texture = mLocalMapRender->getMapTexture(mInterior, mapX, mapY); + if (texture) + { + boost::shared_ptr guiTex (new osgMyGUI::OSGTexture(texture)); + textures.push_back(guiTex); + box->setRenderItemTexture(guiTex.get()); + box->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 1.f, 1.f, 0.f)); + } else - box->setImageTexture("black"); + box->setRenderItemTexture(NULL); } } -#endif + mMapTextures.swap(textures); + MWBase::World* world = MWBase::Environment::get().getWorld(); // Retrieve the door markers we want to show @@ -394,7 +402,7 @@ namespace MWGui destNotes.push_back(it->mNote); } - MarkerUserData data; + MarkerUserData data (mLocalMapRender); data.notes = destNotes; data.caption = marker.name; MyGUI::IntPoint widgetPos = getMarkerPosition(marker.x, marker.y, data); @@ -490,7 +498,7 @@ namespace MWGui for (std::vector::iterator it = markers.begin(); it != markers.end(); ++it) { const ESM::Position& worldPos = it->getRefData().getPosition(); - MarkerUserData markerPos; + MarkerUserData markerPos (mLocalMapRender); MyGUI::IntPoint widgetPos = getMarkerPosition(worldPos.pos[0], worldPos.pos[1], markerPos); MyGUI::IntCoord widgetCoord(widgetPos.left - 4, widgetPos.top - 4, @@ -535,7 +543,7 @@ namespace MWGui if (markedCell && markedCell->isExterior() == !mInterior && (!mInterior || Misc::StringUtils::ciEqual(markedCell->getCell()->mName, mPrefix))) { - MarkerUserData markerPos; + MarkerUserData markerPos (mLocalMapRender); MyGUI::IntPoint widgetPos = getMarkerPosition(markedPosition.pos[0], markedPosition.pos[1], markerPos); MyGUI::IntCoord widgetCoord(widgetPos.left - 4, widgetPos.top - 4, @@ -553,9 +561,9 @@ namespace MWGui // ------------------------------------------------------------------------------------------ - MapWindow::MapWindow(CustomMarkerCollection &customMarkers, DragAndDrop* drag, const std::string& cacheDir) + MapWindow::MapWindow(CustomMarkerCollection &customMarkers, DragAndDrop* drag, MWRender::LocalMap* localMapRender) : WindowPinnableBase("openmw_map_window.layout") - , LocalMapBase(customMarkers) + , LocalMapBase(customMarkers, localMapRender) , NoDrop(drag, mMainWidget) , mGlobalMap(0) , mGlobalMapTexture(NULL) @@ -662,19 +670,19 @@ namespace MWGui x += mCurX; y += mCurY; - Ogre::Vector2 worldPos; + osg::Vec2f worldPos; if (mInterior) { - worldPos = MWBase::Environment::get().getWorld()->interiorMapToWorldPosition(nX, nY, x, y); + worldPos = mLocalMapRender->interiorMapToWorldPosition(nX, nY, x, y); } else { - worldPos.x = (x + nX) * cellSize; - worldPos.y = (y + (1.0f-nY)) * cellSize; + worldPos.x() = (x + nX) * cellSize; + worldPos.y() = (y + (1.0f-nY)) * cellSize; } - mEditingMarker.mWorldX = worldPos.x; - mEditingMarker.mWorldY = worldPos.y; + mEditingMarker.mWorldX = worldPos.x(); + mEditingMarker.mWorldY = worldPos.y(); mEditingMarker.mCell.mPaged = !mInterior; if (mInterior) @@ -993,4 +1001,9 @@ namespace MWGui eventDeleteClicked(); } + bool LocalMapBase::MarkerUserData::isPositionExplored() const + { + return mLocalMapRender->isPositionExplored(nX, nY, cellX, cellY, interior); + } + } diff --git a/apps/openmw/mwgui/mapwindow.hpp b/apps/openmw/mwgui/mapwindow.hpp index 1e1e2c97e..92cd880f4 100644 --- a/apps/openmw/mwgui/mapwindow.hpp +++ b/apps/openmw/mwgui/mapwindow.hpp @@ -3,6 +3,8 @@ #include +#include + #include "windowpinnablebase.hpp" #include @@ -12,6 +14,7 @@ namespace MWRender { class GlobalMap; + class LocalMap; } namespace ESM @@ -52,7 +55,7 @@ namespace MWGui class LocalMapBase { public: - LocalMapBase(CustomMarkerCollection& markers); + LocalMapBase(CustomMarkerCollection& markers, MWRender::LocalMap* localMapRender); virtual ~LocalMapBase(); void init(MyGUI::ScrollView* widget, MyGUI::ImageBox* compass, int mapWidgetSize); @@ -67,6 +70,14 @@ namespace MWGui struct MarkerUserData { + MarkerUserData(MWRender::LocalMap* map) + : mLocalMapRender(map) + { + } + + bool isPositionExplored() const; + + MWRender::LocalMap* mLocalMapRender; bool interior; int cellX; int cellY; @@ -77,6 +88,8 @@ namespace MWGui }; protected: + MWRender::LocalMap* mLocalMapRender; + int mCurX, mCurY; bool mInterior; MyGUI::ScrollView* mLocalMap; @@ -93,6 +106,8 @@ namespace MWGui std::vector mMapWidgets; std::vector mFogWidgets; + std::vector > mMapTextures; + // Keep track of created marker widgets, just to easily remove them later. std::vector mDoorMarkerWidgets; std::vector mMagicMarkerWidgets; @@ -153,7 +168,7 @@ namespace MWGui class MapWindow : public MWGui::WindowPinnableBase, public LocalMapBase, public NoDrop { public: - MapWindow(CustomMarkerCollection& customMarkers, DragAndDrop* drag, const std::string& cacheDir); + MapWindow(CustomMarkerCollection& customMarkers, DragAndDrop* drag, MWRender::LocalMap* localMapRender); virtual ~MapWindow(); void setCellName(const std::string& cellName); diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 43acbeaab..5dd201068 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -169,7 +169,7 @@ namespace MWGui { LocalMapBase::MarkerUserData data = *focus->getUserData(); - if (!MWBase::Environment::get().getWorld ()->isPositionExplored (data.nX, data.nY, data.cellX, data.cellY, data.interior)) + if (!data.isPositionExplored()) return; ToolTipInfo info; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 5649908fc..e4ecdad53 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -53,6 +53,8 @@ #include "../mwmechanics/stat.hpp" #include "../mwmechanics/npcstats.hpp" +#include "../mwrender/localmap.hpp" + #include "../mwsound/soundmanagerimp.hpp" #include "console.hpp" @@ -115,6 +117,7 @@ namespace MWGui , mCurrentModals() , mHud(NULL) , mMap(NULL) + , mLocalMapRender(NULL) , mMenu(NULL) , mToolTips(NULL) , mStatsWindow(NULL) @@ -266,7 +269,8 @@ namespace MWGui mRecharge = new Recharge(); mMenu = new MainMenu(w, h, mResourceSystem->getVFS()); - mMap = new MapWindow(mCustomMarkers, mDragAndDrop, ""); + mLocalMapRender = new MWRender::LocalMap(mViewer); + mMap = new MapWindow(mCustomMarkers, mDragAndDrop, mLocalMapRender); trackWindow(mMap, "map"); mStatsWindow = new StatsWindow(mDragAndDrop); trackWindow(mStatsWindow, "stats"); @@ -284,7 +288,7 @@ namespace MWGui trackWindow(mDialogueWindow, "dialogue"); mContainerWindow = new ContainerWindow(mDragAndDrop); trackWindow(mContainerWindow, "container"); - mHud = new HUD(mCustomMarkers, Settings::Manager::getInt("fps", "HUD"), mDragAndDrop); + mHud = new HUD(mCustomMarkers, Settings::Manager::getInt("fps", "HUD"), mDragAndDrop, mLocalMapRender); mToolTips = new ToolTips(); mScrollWindow = new ScrollWindow(); mBookWindow = new BookWindow(); @@ -383,6 +387,7 @@ namespace MWGui delete mMessageBoxManager; delete mHud; delete mMap; + delete mLocalMapRender; delete mMenu; delete mStatsWindow; delete mJournal; @@ -886,6 +891,31 @@ namespace MWGui return default_; } + void WindowManager::updateMap() + { + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + + osg::Vec3f playerPosition = player.getRefData().getPosition().asVec3(); + osg::Quat playerOrientation (-player.getRefData().getPosition().rot[2], osg::Vec3(0,0,1)); + + osg::Vec3f playerdirection; + int x,y; + float u,v; + mLocalMapRender->updatePlayer(playerPosition, playerOrientation, u, v, x, y, playerdirection); + + if (!player.getCell()->isExterior()) + { + mMap->setActiveCell(x, y, true); + mHud->setActiveCell(x, y, true); + } + // else: need to know the current grid center, call setActiveCell from MWWorld::Scene + + mMap->setPlayerDir(playerdirection.x(), playerdirection.y()); + mMap->setPlayerPos(x, y, u, v); + mHud->setPlayerDir(playerdirection.x(), playerdirection.y()); + mHud->setPlayerPos(x, y, u, v); + } + void WindowManager::onFrame (float frameDuration) { mMessageBoxManager->onFrame(frameDuration); @@ -894,6 +924,9 @@ namespace MWGui mMenu->update(frameDuration); + if (mLocalMapRender) + mLocalMapRender->cleanupCameras(); + if (MWBase::Environment::get().getStateManager()->getState()== MWBase::StateManager::State_NoGame) return; @@ -908,6 +941,8 @@ namespace MWGui mInventoryWindow->onFrame(); + updateMap(); + mStatsWindow->onFrame(frameDuration); mMap->onFrame(frameDuration); mSpellWindow->onFrame(frameDuration); @@ -968,29 +1003,10 @@ namespace MWGui void WindowManager::setActiveMap(int x, int y, bool interior) { - if (!interior) - { - mMap->setCellPrefix("Cell"); - mHud->setCellPrefix("Cell"); - } - mMap->setActiveCell(x,y, interior); mHud->setActiveCell(x,y, interior); } - void WindowManager::setPlayerPos(int cellX, int cellY, const float x, const float y) - { - mMap->setPlayerPos(cellX, cellY, x, y); - mHud->setPlayerPos(cellX, cellY, x, y); - } - - void WindowManager::setPlayerDir(const float x, const float y) - { - mMap->setPlayerDir(x,y); - mMap->setGlobalMapPlayerDir(x, y); - mHud->setPlayerDir(x,y); - } - void WindowManager::setDrowningBarVisibility(bool visible) { mHud->setDrowningBarVisible(visible); @@ -1990,4 +2006,14 @@ namespace MWGui tex->unlock(); } + void WindowManager::requestMap(std::set cells) + { + mLocalMapRender->requestMap(cells); + } + + void WindowManager::removeCell(MWWorld::CellStore *cell) + { + mLocalMapRender->removeCell(cell); + } + } diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index d07f2fb98..c0184d4b6 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -67,6 +67,11 @@ namespace Gui class FontLoader; } +namespace MWRender +{ + class LocalMap; +} + namespace MWGui { class WindowBase; @@ -191,8 +196,6 @@ namespace MWGui virtual void updateSkillArea(); ///< update display of skills, factions, birth sign, reputation and bounty virtual void changeCell(MWWorld::CellStore* cell); ///< change the active cell - virtual void setPlayerPos(int cellX, int cellY, const float x, const float y); ///< set player position in map space - virtual void setPlayerDir(const float x, const float y); ///< set player view direction in map space virtual void setFocusObject(const MWWorld::Ptr& focus); virtual void setFocusObjectScreenCoords(float min_x, float min_y, float max_x, float max_y); @@ -363,6 +366,9 @@ namespace MWGui virtual std::string correctBookartPath(const std::string& path, int width, int height); virtual std::string correctTexturePath(const std::string& path); + void requestMap(std::set cells); + void removeCell(MWWorld::CellStore* cell); + private: Resource::ResourceSystem* mResourceSystem; @@ -386,6 +392,7 @@ namespace MWGui HUD *mHud; MapWindow *mMap; + MWRender::LocalMap* mLocalMapRender; MainMenu *mMenu; ToolTips *mToolTips; StatsWindow *mStatsWindow; @@ -473,6 +480,8 @@ namespace MWGui void updateVisible(); // Update visibility of all windows based on mode, shown and allowed settings + void updateMap(); + float mFPS; std::map mFallbackMap; diff --git a/apps/openmw/mwphysics/actor.cpp b/apps/openmw/mwphysics/actor.cpp index 1a712461e..7084af862 100644 --- a/apps/openmw/mwphysics/actor.cpp +++ b/apps/openmw/mwphysics/actor.cpp @@ -1,5 +1,4 @@ #include "actor.hpp" -#include #include diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 1c436d440..1f78f0dd8 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -8,7 +8,6 @@ #include #include #include -#include #include #include diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index cc6b4a9bb..62c732051 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -16,6 +16,7 @@ #include "../mwworld/inventorystore.hpp" #include "npcanimation.hpp" +#include "vismask.hpp" namespace MWRender { @@ -81,6 +82,8 @@ namespace MWRender mCamera->attach(osg::Camera::COLOR_BUFFER, mTexture); mCamera->setGraphicsContext(mViewer->getCamera()->getGraphicsContext()); + mCamera->setNodeMask(Mask_RenderToTexture); + osg::ref_ptr lightManager = new SceneUtil::LightManager; lightManager->setStartLight(1); osg::ref_ptr stateset = new osg::StateSet; diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index f675fe1d8..8ab16283e 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -1,74 +1,82 @@ #include "localmap.hpp" -#include -#include -#include -#include -#include -#include -#include -#include +#include + +#include +#include +#include + +#include #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" -#include "../mwbase/windowmanager.hpp" -#include "../mwworld/esmstore.hpp" #include "../mwworld/cellstore.hpp" +#include "vismask.hpp" + +namespace +{ + + class CameraUpdateCallback : public osg::NodeCallback + { + public: + CameraUpdateCallback(osg::Camera* cam, MWRender::LocalMap* parent) + : mCamera(cam), mParent(parent) + { + } + + virtual void operator()(osg::Node*, osg::NodeVisitor*) + { + mParent->markForRemoval(mCamera); + + // Note, we intentionally do not traverse children here. The map camera's scene data is the same as the master camera's, + // so it has been updated already. + //traverse(node, nv); + } + + private: + osg::ref_ptr mCamera; + MWRender::LocalMap* mParent; + }; + +} -using namespace MWRender; -using namespace Ogre; +namespace MWRender +{ -LocalMap::LocalMap() - : mMapResolution(Settings::Manager::getInt("local map resolution", "Map")) +LocalMap::LocalMap(osgViewer::Viewer* viewer) + : mViewer(viewer) + , mMapResolution(Settings::Manager::getInt("local map resolution", "Map")) + , mMapWorldSize(8192.f) , mAngle(0.f) , mInterior(false) { - // mCellCamera = mRendering->getScene()->createCamera("CellCamera"); - mCellCamera->setProjectionType(PT_ORTHOGRAPHIC); - - mCameraNode->attachObject(mCellCamera); - - mLight->setType (Ogre::Light::LT_DIRECTIONAL); - mLight->setDirection (Ogre::Vector3(0.3f, 0.3f, -0.7f)); - mLight->setVisible (false); - mLight->setDiffuseColour (ColourValue(0.7f,0.7f,0.7f)); - - mRenderTexture = TextureManager::getSingleton().createManual( - "localmap/rtt", - ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - TEX_TYPE_2D, - mMapResolution, mMapResolution, - 0, - PF_R8G8B8, - TU_RENDERTARGET); - - mRenderTarget = mRenderTexture->getBuffer()->getRenderTarget(); - mRenderTarget->setAutoUpdated(false); - Viewport* vp = mRenderTarget->addViewport(mCellCamera); - vp->setOverlaysEnabled(false); - vp->setShadowsEnabled(false); - vp->setBackgroundColour(ColourValue(0, 0, 0)); - vp->setMaterialScheme("local_map"); -} + mRoot = mViewer->getSceneData()->asGroup(); -LocalMap::~LocalMap() -{ + SceneUtil::FindByNameVisitor find("Scene Root"); + mRoot->accept(find); + mSceneRoot = find.mFoundNode; + if (!mSceneRoot) + throw std::runtime_error("no scene root found"); } -const Ogre::Vector2 LocalMap::rotatePoint(const Ogre::Vector2& p, const Ogre::Vector2& c, const float angle) +LocalMap::~LocalMap() { - return Vector2( Math::Cos(angle) * (p.x - c.x) - Math::Sin(angle) * (p.y - c.y) + c.x, - Math::Sin(angle) * (p.x - c.x) + Math::Cos(angle) * (p.y - c.y) + c.y); + for (CameraVector::iterator it = mActiveCameras.begin(); it != mActiveCameras.end(); ++it) + mRoot->removeChild(*it); + for (CameraVector::iterator it = mCamerasPendingRemoval.begin(); it != mCamerasPendingRemoval.end(); ++it) + mRoot->removeChild(*it); } -std::string LocalMap::coordStr(const int x, const int y) +const osg::Vec2f LocalMap::rotatePoint(const osg::Vec2f& p, const osg::Vec2f& c, const float angle) { - return StringConverter::toString(x) + "_" + StringConverter::toString(y); + return osg::Vec2f( std::cos(angle) * (p.x() - c.x()) - std::sin(angle) * (p.y() - c.y()) + c.x(), + std::sin(angle) * (p.x() - c.x()) + std::cos(angle) * (p.y() - c.y()) + c.y()); } void LocalMap::clear() @@ -103,8 +111,8 @@ void LocalMap::saveFogOfWar(MWWorld::CellStore* cell) Vector2 min(mBounds.getMinimum().x, mBounds.getMinimum().y); Vector2 max(mBounds.getMaximum().x, mBounds.getMaximum().y); Vector2 length = max-min; - const int segsX = static_cast(std::ceil(length.x / sSize)); - const int segsY = static_cast(std::ceil(length.y / sSize)); + const int segsX = static_cast(std::ceil(length.x / mMapWorldSize)); + const int segsY = static_cast(std::ceil(length.y / mMapWorldSize)); mInteriorName = cell->getCell()->mName; @@ -148,24 +156,145 @@ void LocalMap::saveFogOfWar(MWWorld::CellStore* cell) */ } -void LocalMap::requestMap(MWWorld::CellStore* cell, float zMin, float zMax) +osg::ref_ptr LocalMap::createOrthographicCamera(float x, float y, float width, float height, const osg::Vec3d& upVector, float zmin, float zmax) { - mInterior = false; + osg::ref_ptr camera (new osg::Camera); + + camera->setProjectionMatrixAsOrtho(-width/2, width/2, -height/2, height/2, 5, (zmax-zmin) + 10); + camera->setComputeNearFarMode(osg::Camera::DO_NOT_COMPUTE_NEAR_FAR); + camera->setViewMatrixAsLookAt(osg::Vec3d(x, y, zmax + 5), osg::Vec3d(x, y, zmin), upVector); + camera->setReferenceFrame(osg::Camera::ABSOLUTE_RF); + camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT, osg::Camera::PIXEL_BUFFER_RTT); + camera->setClearColor(osg::Vec4(0.f, 0.f, 0.f, 1.f)); + camera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + camera->setRenderOrder(osg::Camera::PRE_RENDER); + + camera->setCullMask(MWRender::Mask_Scene); + camera->setNodeMask(Mask_RenderToTexture); + + osg::ref_ptr stateset = new osg::StateSet; + stateset->setMode(GL_LIGHTING, osg::StateAttribute::ON); + stateset->setMode(GL_NORMALIZE, osg::StateAttribute::ON); + stateset->setMode(GL_CULL_FACE, osg::StateAttribute::ON); + stateset->setMode(GL_FOG, osg::StateAttribute::OFF|osg::StateAttribute::OVERRIDE); + + osg::ref_ptr lightmodel = new osg::LightModel; + lightmodel->setAmbientIntensity(osg::Vec4(0.3f, 0.3f, 0.3f, 1.f)); + stateset->setAttributeAndModes(lightmodel, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + + osg::ref_ptr light = new osg::Light; + light->setPosition(osg::Vec4(-0.3f, -0.3f, 0.7f, 0.f)); + light->setDiffuse(osg::Vec4(0.7f, 0.7f, 0.7f, 1.f)); + light->setAmbient(osg::Vec4(0,0,0,1)); + light->setSpecular(osg::Vec4(0,0,0,0)); + light->setLightNum(0); + light->setConstantAttenuation(1.f); + light->setLinearAttenuation(0.f); + light->setQuadraticAttenuation(0.f); + + osg::ref_ptr lightSource = new osg::LightSource; + lightSource->setLight(light); + + lightSource->setStateSetModes(*stateset, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + + camera->addChild(lightSource); + camera->setStateSet(stateset); + camera->setGraphicsContext(mViewer->getCamera()->getGraphicsContext()); + camera->setViewport(0, 0, mMapResolution, mMapResolution); + camera->setUpdateCallback(new CameraUpdateCallback(camera, this)); + + return camera; +} - mCameraRotNode->setOrientation(Quaternion::IDENTITY); - mCellCamera->setOrientation(Quaternion(Ogre::Math::Cos(Ogre::Degree(0)/2.f), 0, 0, -Ogre::Math::Sin(Ogre::Degree(0)/2.f))); +void LocalMap::setupRenderToTexture(osg::ref_ptr camera, int x, int y) +{ + osg::ref_ptr texture (new osg::Texture2D); + texture->setTextureSize(mMapResolution, mMapResolution); + texture->setInternalFormat(GL_RGB); + texture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR); + texture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); + texture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); + texture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); + + camera->attach(osg::Camera::COLOR_BUFFER, texture); + + camera->addChild(mSceneRoot); + mRoot->addChild(camera); + mActiveCameras.push_back(camera); + mTextures[std::make_pair(x, y)] = texture; +} + +void LocalMap::requestMap(std::set cells) +{ + for (std::set::iterator it = cells.begin(); it != cells.end(); ++it) + { + MWWorld::CellStore* cell = *it; + if (cell->isExterior()) + requestExteriorMap(cell); + else + requestInteriorMap(cell); + } +} + +void LocalMap::removeCell(MWWorld::CellStore *cell) +{ + if (cell->isExterior()) + mTextures.erase(std::make_pair(cell->getCell()->getGridX(), cell->getCell()->getGridY())); + else + mTextures.clear(); +} + +osg::ref_ptr LocalMap::getMapTexture(bool interior, int x, int y) +{ + TextureMap::iterator found = mTextures.find(std::make_pair(x, y)); + if (found == mTextures.end()) + return osg::ref_ptr(); + else + return found->second; +} + +void LocalMap::markForRemoval(osg::Camera *cam) +{ + CameraVector::iterator found = std::find(mActiveCameras.begin(), mActiveCameras.end(), cam); + if (found == mActiveCameras.end()) + { + std::cerr << "trying to remove an inactive camera" << std::endl; + return; + } + mActiveCameras.erase(found); + mCamerasPendingRemoval.push_back(cam); +} + +void LocalMap::cleanupCameras() +{ + if (mCamerasPendingRemoval.empty()) + return; + + for (CameraVector::iterator it = mCamerasPendingRemoval.begin(); it != mCamerasPendingRemoval.end(); ++it) + { + (*it)->removeChildren(0, (*it)->getNumChildren()); + (*it)->setGraphicsContext(NULL); + mRoot->removeChild(*it); + } + + + mCamerasPendingRemoval.clear(); +} + +void LocalMap::requestExteriorMap(MWWorld::CellStore* cell) +{ + mInterior = false; int x = cell->getCell()->getGridX(); int y = cell->getCell()->getGridY(); - std::string name = "Cell_"+coordStr(x, y); + osg::BoundingSphere bound = mViewer->getSceneData()->getBound(); + float zmin = bound.center().z() - bound.radius(); + float zmax = bound.center().z() + bound.radius(); - mCameraPosNode->setPosition(Vector3(0,0,0)); - - // Note: using force=true for exterior cell maps. - // They must be updated even if they were visited before, because the set of surrounding active cells might be different - // (and objects in a different cell can "bleed" into another cell's map if they cross the border) - render((x+0.5f)*sSize, (y+0.5f)*sSize, zMin, zMax, static_cast(sSize), static_cast(sSize), name, true); + osg::ref_ptr camera = createOrthographicCamera(x*mMapWorldSize + mMapWorldSize/2.f, y*mMapWorldSize + mMapWorldSize/2.f, mMapWorldSize, mMapWorldSize, + osg::Vec3d(0,1,0), zmin, zmax); + setupRenderToTexture(camera, cell->getCell()->getGridX(), cell->getCell()->getGridY()); /* if (mBuffers.find(name) == mBuffers.end()) @@ -178,12 +307,17 @@ void LocalMap::requestMap(MWWorld::CellStore* cell, float zMin, float zMax) */ } -void LocalMap::requestMap(MWWorld::CellStore* cell, - AxisAlignedBox bounds) +void LocalMap::requestInteriorMap(MWWorld::CellStore* cell) { + osg::ComputeBoundsVisitor computeBoundsVisitor; + computeBoundsVisitor.setTraversalMask(Mask_Scene); + mSceneRoot->accept(computeBoundsVisitor); + + osg::BoundingBox bounds = computeBoundsVisitor.getBoundingBox(); + // If we're in an empty cell, bail out // The operations in this function are only valid for finite bounds - if (bounds.isNull ()) + if (!bounds.valid() || bounds.radius2() == 0.0) return; mInterior = true; @@ -191,41 +325,31 @@ void LocalMap::requestMap(MWWorld::CellStore* cell, mBounds = bounds; // Get the cell's NorthMarker rotation. This is used to rotate the entire map. - const Vector2& north = MWBase::Environment::get().getWorld()->getNorthVector(cell); - Radian angle = Ogre::Math::ATan2 (north.x, north.y); - mAngle = angle.valueRadians(); + osg::Vec2f north = MWBase::Environment::get().getWorld()->getNorthVector(cell); + + mAngle = std::atan2(north.x(), north.y()); // Rotate the cell and merge the rotated corners to the bounding box - Vector2 _center(bounds.getCenter().x, bounds.getCenter().y); - Vector3 _c1 = bounds.getCorner(AxisAlignedBox::FAR_LEFT_BOTTOM); - Vector3 _c2 = bounds.getCorner(AxisAlignedBox::FAR_RIGHT_BOTTOM); - Vector3 _c3 = bounds.getCorner(AxisAlignedBox::FAR_LEFT_TOP); - Vector3 _c4 = bounds.getCorner(AxisAlignedBox::FAR_RIGHT_TOP); - - Vector2 c1(_c1.x, _c1.y); - Vector2 c2(_c2.x, _c2.y); - Vector2 c3(_c3.x, _c3.y); - Vector2 c4(_c4.x, _c4.y); - c1 = rotatePoint(c1, _center, mAngle); - c2 = rotatePoint(c2, _center, mAngle); - c3 = rotatePoint(c3, _center, mAngle); - c4 = rotatePoint(c4, _center, mAngle); - mBounds.merge(Vector3(c1.x, c1.y, 0)); - mBounds.merge(Vector3(c2.x, c2.y, 0)); - mBounds.merge(Vector3(c3.x, c3.y, 0)); - mBounds.merge(Vector3(c4.x, c4.y, 0)); + osg::Vec2f _center(bounds.center().x(), bounds.center().y()); + for (int i=0; i<8; ++i) + { + osg::Vec3f corner = mBounds.corner(i); + osg::Vec2f corner2d (corner.x(), corner.y()); + corner2d = rotatePoint(corner2d, _center, mAngle); + mBounds.expandBy(osg::Vec3f(corner2d.x(), corner2d.y(), 0)); + } // Do NOT change padding! This will break older savegames. // If the padding really needs to be changed, then it must be saved in the ESM::FogState and // assume the old (500) value as default for older savegames. - const Ogre::Real padding = 500.0f; + const float padding = 500.0f; // Apply a little padding - mBounds.setMinimum (mBounds.getMinimum() - Vector3(padding,padding,0)); - mBounds.setMaximum (mBounds.getMaximum() + Vector3(padding,padding,0)); + mBounds.set(mBounds._min - osg::Vec3f(padding,padding,0.f), + mBounds._max + osg::Vec3f(padding,padding,0.f)); - float zMin = mBounds.getMinimum().z; - float zMax = mBounds.getMaximum().z; + float zMin = mBounds.zMin(); + float zMax = mBounds.zMax(); // If there is fog state in the CellStore (e.g. when it came from a savegame) we need to do some checks // to see if this state is still valid. @@ -244,8 +368,8 @@ void LocalMap::requestMap(MWWorld::CellStore* cell, Ogre::Vector3 minDiff = newMin - mBounds.getMinimum(); Ogre::Vector3 maxDiff = newMax - mBounds.getMaximum(); - if (std::abs(minDiff.x) > 500 || std::abs(minDiff.y) > 500 - || std::abs(maxDiff.x) > 500 || std::abs(maxDiff.y) > 500 + if (std::abs(minDiff.x) > padding || std::abs(minDiff.y) > padding + || std::abs(maxDiff.x) > padding || std::abs(maxDiff.y) > padding || std::abs(mAngle - fog->mNorthMarkerAngle) > Ogre::Degree(5).valueRadians()) { // Nuke it @@ -260,35 +384,35 @@ void LocalMap::requestMap(MWWorld::CellStore* cell, } */ - Vector2 center(mBounds.getCenter().x, mBounds.getCenter().y); - - Vector2 min(mBounds.getMinimum().x, mBounds.getMinimum().y); - Vector2 max(mBounds.getMaximum().x, mBounds.getMaximum().y); + osg::Vec2f min(mBounds.xMin(), mBounds.yMin()); + osg::Vec2f max(mBounds.xMax(), mBounds.yMax()); - Vector2 length = max-min; + osg::Vec2f length = max-min; - mCellCamera->setOrientation(Quaternion::IDENTITY); - mCameraRotNode->setOrientation(Quaternion(Math::Cos(mAngle/2.f), 0, 0, -Math::Sin(mAngle/2.f))); - - mCameraPosNode->setPosition(Vector3(center.x, center.y, 0)); + osg::Vec2f center(bounds.center().x(), bounds.center().y()); // divide into segments - const int segsX = static_cast(std::ceil(length.x / sSize)); - const int segsY = static_cast(std::ceil(length.y / sSize)); - - mInteriorName = cell->getCell()->mName; + const int segsX = static_cast(std::ceil(length.x() / mMapWorldSize)); + const int segsY = static_cast(std::ceil(length.y() / mMapWorldSize)); - int i=0; for (int x=0; x(sSize*x), static_cast(sSize*y)); - Vector2 newcenter = start + sSize/2; + osg::Vec2f start = min + osg::Vec2f(mMapWorldSize*x, mMapWorldSize*y); + osg::Vec2f newcenter = start + osg::Vec2f(mMapWorldSize/2.f, mMapWorldSize/2.f); + + osg::Quat cameraOrient (mAngle, osg::Vec3d(0,0,-1)); + osg::Vec2f a = newcenter - center; + osg::Vec3f rotatedCenter = cameraOrient * (osg::Vec3f(a.x(), a.y(), 0)); + + osg::Vec2f pos = osg::Vec2f(rotatedCenter.x(), rotatedCenter.y()) + center; - std::string texturePrefix = cell->getCell()->mName + "_" + coordStr(x,y); + osg::ref_ptr camera = createOrthographicCamera(pos.x(), pos.y(), + mMapWorldSize, mMapWorldSize, + osg::Vec3f(north.x(), north.y(), 0.f), zMin, zMax); - render(newcenter.x - center.x, newcenter.y - center.y, zMin, zMax, static_cast(sSize), static_cast(sSize), texturePrefix); + setupRenderToTexture(camera, x, y); /* if (!cell->getFog()) @@ -305,14 +429,13 @@ void LocalMap::requestMap(MWWorld::CellStore* cell, loadFogOfWar(texturePrefix, esm); } */ - ++i; } } } +/* void LocalMap::createFogOfWar(const std::string& texturePrefix) { - /* const std::string texName = texturePrefix + "_fog"; TexturePtr tex = createFogOfWarTexture(texName); @@ -328,34 +451,12 @@ void LocalMap::createFogOfWar(const std::string& texturePrefix) tex->getBuffer()->unlock(); mBuffers[texturePrefix] = buffer; - */ -} - -Ogre::TexturePtr LocalMap::createFogOfWarTexture(const std::string &texName) -{ - TexturePtr tex;// = TextureManager::getSingleton().getByName(texName); - /* - * if (tex.isNull()) - { - tex = TextureManager::getSingleton().createManual( - texName, - ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - TEX_TYPE_2D, - sFogOfWarResolution, sFogOfWarResolution, - 0, - PF_A8R8G8B8, - TU_DYNAMIC_WRITE_ONLY, - this // ManualResourceLoader required if the texture contents are lost (due to lost devices nonsense that can occur with D3D) - ); - } - */ - - return tex; } +*/ +/* void LocalMap::loadFogOfWar (const std::string& texturePrefix, ESM::FogTexture& esm) { - /* std::vector& data = esm.mImageData; Ogre::DataStreamPtr stream(new Ogre::MemoryDataStream(&data[0], data.size())); Ogre::Image image; @@ -377,89 +478,35 @@ void LocalMap::loadFogOfWar (const std::string& texturePrefix, ESM::FogTexture& memcpy(&buffer[0], image.getData(), image.getSize()); mBuffers[texturePrefix] = buffer; - */ -} - -void LocalMap::render(const float x, const float y, - const float zlow, const float zhigh, - const float xw, const float yw, const std::string& texture, bool force) -{ - mCellCamera->setFarClipDistance( (zhigh-zlow) + 2000 ); - mCellCamera->setNearClipDistance(50); - - mCellCamera->setOrthoWindow(xw, yw); - mCameraNode->setPosition(Vector3(x, y, zhigh+1000)); - - // disable fog (only necessary for fixed function, the shader based - // materials already do this through local_map material configuration) - //mRendering->getScene()->setFog(FOG_NONE); - - // set up lighting - //Ogre::ColourValue oldAmbient = mRendering->getScene()->getAmbientLight(); - //mRendering->getScene()->setAmbientLight(Ogre::ColourValue(0.3f, 0.3f, 0.3f)); - //mRenderingManager->disableLights(true); - mLight->setVisible(true); - - TexturePtr tex; - // try loading from memory - tex = TextureManager::getSingleton().getByName(texture); - if (tex.isNull()) - { - // render - mRenderTarget->update(); - - // create a new texture and blit to it - Ogre::TexturePtr tex = TextureManager::getSingleton().createManual( - texture, - ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - TEX_TYPE_2D, - mMapResolution, mMapResolution, - 0, - PF_R8G8B8); - tex->getBuffer()->blit(mRenderTexture->getBuffer()); - } - else if (force) - { - mRenderTarget->update(); - tex->getBuffer()->blit(mRenderTexture->getBuffer()); - } - - //mRenderingManager->enableLights(true); - mLight->setVisible(false); - - // re-enable fog - //mRendering->getScene()->setFog(FOG_LINEAR, oldFogColour, 0, oldFogStart, oldFogEnd); - //mRendering->getScene()->setAmbientLight(oldAmbient); } +*/ -void LocalMap::worldToInteriorMapPosition (Ogre::Vector2 pos, float& nX, float& nY, int& x, int& y) +void LocalMap::worldToInteriorMapPosition (osg::Vec2f pos, float& nX, float& nY, int& x, int& y) { - pos = rotatePoint(pos, Vector2(mBounds.getCenter().x, mBounds.getCenter().y), mAngle); + pos = rotatePoint(pos, osg::Vec2f(mBounds.center().x(), mBounds.center().y()), mAngle); - Vector2 min(mBounds.getMinimum().x, mBounds.getMinimum().y); + osg::Vec2f min(mBounds.xMin(), mBounds.yMin()); - x = static_cast(std::ceil((pos.x - min.x) / sSize) - 1); - y = static_cast(std::ceil((pos.y - min.y) / sSize) - 1); + x = static_cast(std::ceil((pos.x() - min.x()) / mMapWorldSize) - 1); + y = static_cast(std::ceil((pos.y() - min.y()) / mMapWorldSize) - 1); - nX = (pos.x - min.x - sSize*x)/sSize; - nY = 1.0f-(pos.y - min.y - sSize*y)/sSize; + nX = (pos.x() - min.x() - mMapWorldSize*x)/mMapWorldSize; + nY = 1.0f-(pos.y() - min.y() - mMapWorldSize*y)/mMapWorldSize; } -Ogre::Vector2 LocalMap::interiorMapToWorldPosition (float nX, float nY, int x, int y) +osg::Vec2f LocalMap::interiorMapToWorldPosition (float nX, float nY, int x, int y) { - Vector2 min(mBounds.getMinimum().x, mBounds.getMinimum().y); - Ogre::Vector2 pos; + osg::Vec2f min(mBounds.xMin(), mBounds.yMin()); + osg::Vec2f pos (mMapWorldSize * (nX + x) + min.x(), + mMapWorldSize * (1.0f-nY + y) + min.y()); - pos.x = sSize * (nX + x) + min.x; - pos.y = sSize * (1.0f-nY + y) + min.y; - - pos = rotatePoint(pos, Vector2(mBounds.getCenter().x, mBounds.getCenter().y), -mAngle); + pos = rotatePoint(pos, osg::Vec2f(mBounds.center().x(), mBounds.center().y()), -mAngle); return pos; } bool LocalMap::isPositionExplored (float nX, float nY, int x, int y, bool interior) { - return false; + return true; /* std::string texName = (interior ? mInteriorName + "_" : "Cell_") + coordStr(x, y); @@ -478,33 +525,8 @@ bool LocalMap::isPositionExplored (float nX, float nY, int x, int y, bool interi */ } -void LocalMap::loadResource(Ogre::Resource* resource) -{ - /* - std::string resourceName = resource->getName(); - size_t pos = resourceName.find("_fog"); - if (pos != std::string::npos) - resourceName = resourceName.substr(0, pos); - if (mBuffers.find(resourceName) == mBuffers.end()) - { - // create a buffer to use for dynamic operations - std::vector buffer; - - // initialize to (0, 0, 0, 1) - buffer.resize(sFogOfWarResolution*sFogOfWarResolution, 0xFF000000); - mBuffers[resourceName] = buffer; - } - - std::vector& buffer = mBuffers[resourceName]; - - Ogre::Texture* tex = static_cast(resource); - tex->createInternalResources(); - memcpy(tex->getBuffer()->lock(HardwareBuffer::HBL_DISCARD), &buffer[0], sFogOfWarResolution*sFogOfWarResolution*4); - tex->getBuffer()->unlock(); - */ -} - -void LocalMap::updatePlayer (const Ogre::Vector3& position, const Ogre::Quaternion& orientation) +void LocalMap::updatePlayer (const osg::Vec3f& position, const osg::Quat& orientation, + float& u, float& v, int& x, int& y, osg::Vec3f& direction) { /* if (sFogOfWarSkip != 0) @@ -513,42 +535,32 @@ void LocalMap::updatePlayer (const Ogre::Vector3& position, const Ogre::Quaterni if (++count % sFogOfWarSkip != 0) return; } + */ // retrieve the x,y grid coordinates the player is in - int x,y; - float u,v; - - Vector2 pos(position.x, position.y); + osg::Vec2f pos(position.x(), position.y()); if (mInterior) - worldToInteriorMapPosition(pos, u,v, x,y); - - Vector3 playerdirection = mCameraRotNode->convertWorldToLocalOrientation(orientation).yAxis(); - - if (!mInterior) { - x = static_cast(std::ceil(pos.x / sSize) - 1); - y = static_cast(std::ceil(pos.y / sSize) - 1); - } - else - MWBase::Environment::get().getWindowManager()->setActiveMap(x,y,mInterior); + worldToInteriorMapPosition(pos, u,v, x,y); - // convert from world coordinates to texture UV coordinates - std::string texBaseName; - if (!mInterior) - { - u = std::abs((pos.x - (sSize*x))/sSize); - v = 1.0f-std::abs((pos.y - (sSize*y))/sSize); - texBaseName = "Cell_"; + osg::Quat cameraOrient (mAngle, osg::Vec3(0,0,-1)); + direction = orientation * cameraOrient.inverse() * osg::Vec3f(0,1,0); } else { - texBaseName = mInteriorName + "_"; + direction = orientation * osg::Vec3f(0,1,0); + + x = static_cast(std::ceil(pos.x() / mMapWorldSize) - 1); + y = static_cast(std::ceil(pos.y() / mMapWorldSize) - 1); + + // convert from world coordinates to texture UV coordinates + u = std::abs((pos.x() - (mMapWorldSize*x))/mMapWorldSize); + v = 1.0f-std::abs((pos.y() - (mMapWorldSize*y))/mMapWorldSize); } - MWBase::Environment::get().getWindowManager()->setPlayerPos(x, y, u, v); - MWBase::Environment::get().getWindowManager()->setPlayerDir(playerdirection.x, playerdirection.y); + /* // explore radius (squared) const float exploreRadius = (mInterior ? 0.1f : 0.3f) * (sFogOfWarResolution-1); // explore radius from 0 to sFogOfWarResolution-1 const float sqrExploreRadius = Math::Sqr(exploreRadius); @@ -614,3 +626,5 @@ void LocalMap::updatePlayer (const Ogre::Vector3& position, const Ogre::Quaterni } */ } + +} diff --git a/apps/openmw/mwrender/localmap.hpp b/apps/openmw/mwrender/localmap.hpp index d0d7d73d2..8160c325c 100644 --- a/apps/openmw/mwrender/localmap.hpp +++ b/apps/openmw/mwrender/localmap.hpp @@ -1,9 +1,13 @@ #ifndef GAME_RENDER_LOCALMAP_H #define GAME_RENDER_LOCALMAP_H -#include -#include -#include +#include +#include +#include + +#include +#include +#include namespace MWWorld { @@ -15,52 +19,57 @@ namespace ESM struct FogTexture; } -namespace MWRender +namespace osgViewer { - class RenderingManager; + class Viewer; +} +namespace osg +{ + class Texture2D; + class Camera; + class Group; + class Node; +} + +namespace MWRender +{ /// /// \brief Local map rendering /// class LocalMap { public: - LocalMap(); + LocalMap(osgViewer::Viewer* viewer); ~LocalMap(); - virtual void loadResource(Ogre::Resource* resource); - /** * Clear all savegame-specific data (i.e. fog of war textures) */ void clear(); - /** - * Request the local map for an exterior cell. - * @remarks It will either be loaded from a disk cache, - * or rendered if it is not already cached. - * @param cell exterior cell - * @param zMin min height of objects or terrain in cell - * @param zMax max height of objects or terrain in cell - */ - void requestMap (MWWorld::CellStore* cell, float zMin, float zMax); + void requestMap (std::set cells); + + void removeCell (MWWorld::CellStore* cell); + + osg::ref_ptr getMapTexture (bool interior, int x, int y); + + void markForRemoval(osg::Camera* cam); /** - * Request the local map for an interior cell. - * @remarks It will either be loaded from a disk cache, - * or rendered if it is not already cached. - * @param cell interior cell - * @param bounds bounding box of the cell + * Removes cameras that have already been rendered. Should be called every frame to ensure that + * we do not render the same map more than once. Note, this cleanup is difficult to implement in an + * automated fashion, since we can't alter the scene graph structure from within an update callback. */ - void requestMap (MWWorld::CellStore* cell, - Ogre::AxisAlignedBox bounds); + void cleanupCameras(); /** - * Set the position & direction of the player. + * Set the position & direction of the player, and returns the position in map space through the reference parameters. * @remarks This is used to draw a "fog of war" effect * to hide areas on the map the player has not discovered yet. */ - void updatePlayer (const Ogre::Vector3& position, const Ogre::Quaternion& orientation); + void updatePlayer (const osg::Vec3f& position, const osg::Quat& orientation, + float& u, float& v, int& x, int& y, osg::Vec3f& direction); /** * Save the fog of war for this cell to its CellStore. @@ -72,9 +81,9 @@ namespace MWRender * Get the interior map texture index and normalized position * on this texture, given a world position */ - void worldToInteriorMapPosition (Ogre::Vector2 pos, float& nX, float& nY, int& x, int& y); + void worldToInteriorMapPosition (osg::Vec2f pos, float& nX, float& nY, int& x, int& y); - Ogre::Vector2 interiorMapToWorldPosition (float nX, float nY, int x, int y); + osg::Vec2f interiorMapToWorldPosition (float nX, float nY, int x, int y); /** * Check if a given position is explored by the player (i.e. not obscured by fog of war) @@ -82,6 +91,20 @@ namespace MWRender bool isPositionExplored (float nX, float nY, int x, int y, bool interior); private: + osg::ref_ptr mViewer; + + osg::ref_ptr mRoot; + osg::ref_ptr mSceneRoot; + + typedef std::vector< osg::ref_ptr > CameraVector; + + CameraVector mActiveCameras; + + CameraVector mCamerasPendingRemoval; + + typedef std::map, osg::ref_ptr > TextureMap; + TextureMap mTextures; + int mMapResolution; // the dynamic texture is a bottleneck, so don't set this too high @@ -91,46 +114,34 @@ namespace MWRender static const int sFogOfWarSkip = 2; // size of a map segment (for exteriors, 1 cell) - static const int sSize = 8192; - - Ogre::Camera* mCellCamera; - Ogre::SceneNode* mCameraNode; - Ogre::SceneNode* mCameraPosNode; - Ogre::SceneNode* mCameraRotNode; - - // directional light from a fixed angle - Ogre::Light* mLight; + float mMapWorldSize; float mAngle; - const Ogre::Vector2 rotatePoint(const Ogre::Vector2& p, const Ogre::Vector2& c, const float angle); + const osg::Vec2f rotatePoint(const osg::Vec2f& p, const osg::Vec2f& c, const float angle); - /// @param force Always render, even if we already have a cached map - void render(const float x, const float y, - const float zlow, const float zhigh, - const float xw, const float yw, - const std::string& texture, bool force=false); + void requestExteriorMap(MWWorld::CellStore* cell); + void requestInteriorMap(MWWorld::CellStore* cell); + + osg::ref_ptr createOrthographicCamera(float left, float top, float width, float height, const osg::Vec3d& upVector, float zmin, float zmax); + void setupRenderToTexture(osg::ref_ptr camera, int x, int y); // Creates a fog of war texture and initializes it to full black - void createFogOfWar(const std::string& texturePrefix); + //void createFogOfWar(const std::string& texturePrefix); // Loads a fog of war texture from its ESM struct - void loadFogOfWar(const std::string& texturePrefix, ESM::FogTexture& esm); // FogTexture not const because MemoryDataStream doesn't accept it - - Ogre::TexturePtr createFogOfWarTexture(const std::string& name); - - std::string coordStr(const int x, const int y); + //void loadFogOfWar(const std::string& texturePrefix, ESM::FogTexture& esm); // FogTexture not const because MemoryDataStream doesn't accept it // A buffer for the "fog of war" textures of the current cell. // Both interior and exterior maps are possibly divided into multiple textures. - std::map > mBuffers; + //std::map > mBuffers; // The render texture we will use to create the map images - Ogre::TexturePtr mRenderTexture; - Ogre::RenderTarget* mRenderTarget; + //Ogre::TexturePtr mRenderTexture; + //Ogre::RenderTarget* mRenderTarget; bool mInterior; - Ogre::AxisAlignedBox mBounds; - std::string mInteriorName; + osg::BoundingBox mBounds; + //std::string mInteriorName; }; } diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index cb53105a7..816002753 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -2,7 +2,6 @@ #include -#include #include #include #include @@ -206,6 +205,10 @@ void Objects::removeCell(const MWWorld::CellStore* store) void Objects::updatePtr(const MWWorld::Ptr &old, const MWWorld::Ptr &cur) { + osg::Node* objectNode = cur.getRefData().getBaseNode(); + if (!objectNode) + return; + MWWorld::CellStore *newCell = cur.getCell(); osg::Group* cellnode; @@ -217,8 +220,6 @@ void Objects::updatePtr(const MWWorld::Ptr &old, const MWWorld::Ptr &cur) cellnode = mCellSceneNodes[newCell]; } - osg::Node* objectNode = cur.getRefData().getBaseNode(); - osg::UserDataContainer* userDataContainer = objectNode->getUserDataContainer(); if (userDataContainer) for (unsigned int i=0; igetNumUserObjects(); ++i) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index e60b35524..b1c26812c 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -2,7 +2,6 @@ #include -#include #include #include #include @@ -111,6 +110,7 @@ namespace MWRender mViewer->setLightingMode(osgViewer::View::NO_LIGHT); osg::ref_ptr source = new osg::LightSource; + source->setNodeMask(SceneUtil::Mask_Lit); mSunLight = new osg::Light; source->setLight(mSunLight); mSunLight->setDiffuse(osg::Vec4f(0,0,0,1)); @@ -123,6 +123,7 @@ namespace MWRender lightRoot->getOrCreateStateSet()->setMode(GL_NORMALIZE, osg::StateAttribute::ON); lightRoot->setNodeMask(Mask_Scene); + lightRoot->setName("Scene Root"); mSky.reset(new SkyManager(lightRoot, resourceSystem->getSceneManager())); @@ -342,8 +343,12 @@ namespace MWRender intersector->setIntersectionLimit(osgUtil::LineSegmentIntersector::LIMIT_NEAREST); osgUtil::IntersectionVisitor intersectionVisitor(intersector); + int mask = intersectionVisitor.getTraversalMask(); + mask &= ~(Mask_RenderToTexture|Mask_Sky|Mask_Debug|Mask_Effect); if (ignorePlayer) - intersectionVisitor.setTraversalMask(intersectionVisitor.getTraversalMask() & (~Mask_Player)); + mask &= ~(Mask_Player); + + intersectionVisitor.setTraversalMask(mask); mViewer->getCamera()->accept(intersectionVisitor); @@ -451,12 +456,8 @@ namespace MWRender void RenderingManager::updateProjectionMatrix() { - double fovy, aspect, zNear, zFar; - mViewer->getCamera()->getProjectionMatrixAsPerspective(fovy, aspect, zNear, zFar); - fovy = mFieldOfView; - zNear = mNearClip; - zFar = mViewDistance; - mViewer->getCamera()->setProjectionMatrixAsPerspective(fovy, aspect, zNear, zFar); + double aspect = mViewer->getCamera()->getViewport()->aspectRatio(); + mViewer->getCamera()->setProjectionMatrixAsPerspective(mFieldOfView, aspect, mNearClip, mViewDistance); } void RenderingManager::updateTextureFiltering() diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 43c88427e..990f3a5d9 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -8,10 +8,6 @@ #include #include -#include - -#include - #include #include @@ -34,7 +30,7 @@ #include "../mwworld/fallback.hpp" -#include "renderingmanager.hpp" +#include "vismask.hpp" namespace { @@ -506,6 +502,7 @@ SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneMana , mSecundaEnabled(true) { osg::ref_ptr skyroot (new CameraRelativeTransform); + skyroot->setNodeMask(Mask_Sky); parentNode->addChild(skyroot); mRootNode = skyroot; @@ -652,7 +649,7 @@ void SkyManager::setEnabled(bool enabled) if (!enabled) clearRain(); - mRootNode->setNodeMask(enabled ? ~((unsigned int)(0)) : 0); + mRootNode->setNodeMask(enabled ? Mask_Sky : 0); mEnabled = enabled; } diff --git a/apps/openmw/mwrender/vismask.hpp b/apps/openmw/mwrender/vismask.hpp index 7382438d1..c9ac35c67 100644 --- a/apps/openmw/mwrender/vismask.hpp +++ b/apps/openmw/mwrender/vismask.hpp @@ -14,10 +14,16 @@ namespace MWRender Mask_Debug = (1<<2), Mask_Actor = (1<<3), Mask_Player = (1<<4), + Mask_Sky = (1<<5), // top level masks - Mask_Scene = (1<<5), - Mask_GUI = (1<<6) + Mask_Scene = (1<<6), + Mask_GUI = (1<<7), + + // Set on cameras within the main scene graph + Mask_RenderToTexture = (1<<8) + + // reserved: (1<<16) for SceneUtil::Mask_Lit }; } diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 397ebbe75..939fbe873 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -172,8 +172,13 @@ namespace MWWorld { // Note: exterior cell maps must be updated, even if they were visited before, because the set of surrounding cells might be different // (and objects in a different cell can "bleed" into another cells map if they cross the border) - //for (CellStoreCollection::iterator active = mActiveCells.begin(); active!=mActiveCells.end(); ++active) - //mRendering.requestMap(*active); + std::set cellsToUpdate; + for (CellStoreCollection::iterator active = mActiveCells.begin(); active!=mActiveCells.end(); ++active) + { + cellsToUpdate.insert(*active); + } + MWBase::Environment::get().getWindowManager()->requestMap(cellsToUpdate); + mNeedMapUpdate = false; if (mCurrentCell->isExterior()) @@ -213,6 +218,7 @@ namespace MWWorld MWBase::Environment::get().getMechanicsManager()->drop (*iter); mRendering.removeCell(*iter); + MWBase::Environment::get().getWindowManager()->removeCell(*iter); MWBase::Environment::get().getWorld()->getLocalScripts().clearCell (*iter); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 57b8b67a4..e20904d71 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -162,14 +162,11 @@ namespace MWWorld mLevitationEnabled(true), mGoToJail(false), mDaysInPrison(0) { mPhysics = new MWPhysics::PhysicsSystem(resourceSystem, rootNode); - //mPhysEngine = mPhysics->getEngine(); #if 0 mProjectileManager.reset(new ProjectileManager(renderer.getScene(), *mPhysEngine)); #endif mRendering = new MWRender::RenderingManager(viewer, rootNode, resourceSystem); - //mPhysEngine->setSceneManager(renderer.getScene()); - mWeatherManager = new MWWorld::WeatherManager(mRendering,&mFallback); mEsm.resize(contentFiles.size()); @@ -1591,24 +1588,38 @@ namespace MWWorld updateWindowManager (); updateSoundListener(); - /* - if (!paused && mPlayer->getPlayer().getCell()->isExterior()) + + updatePlayer(paused); + } + + void World::updatePlayer(bool paused) + { + MWWorld::Ptr player = getPlayerPtr(); + + // TODO: move to MWWorld::Player + + if (player.getCell()->isExterior()) { - ESM::Position pos = mPlayer->getPlayer().getRefData().getPosition(); + ESM::Position pos = player.getRefData().getPosition(); mPlayer->setLastKnownExteriorPosition(Ogre::Vector3(pos.pos)); } - */ + + if (player.getClass().getNpcStats(player).isWerewolf()) + MWBase::Environment::get().getWindowManager()->setWerewolfOverlay(mRendering->getCamera()->isFirstPerson()); // Sink the camera while sneaking - bool sneaking = getPlayerPtr().getClass().getCreatureStats(getPlayerPtr()).getStance(MWMechanics::CreatureStats::Stance_Sneak); - bool inair = !isOnGround(getPlayerPtr()); - bool swimming = isSwimming(getPlayerPtr()); + bool sneaking = player.getClass().getCreatureStats(getPlayerPtr()).getStance(MWMechanics::CreatureStats::Stance_Sneak); + bool inair = !isOnGround(player); + bool swimming = isSwimming(player); static const float i1stPersonSneakDelta = getStore().get().find("i1stPersonSneakDelta")->getFloat(); if(!paused && sneaking && !(swimming || inair)) mRendering->getCamera()->setSneakOffset(i1stPersonSneakDelta); else mRendering->getCamera()->setSneakOffset(0.f); + + int blind = static_cast(player.getClass().getCreatureStats(player).getMagicEffects().get(ESM::MagicEffect::Blind).getMagnitude()); + MWBase::Environment::get().getWindowManager()->setBlindness(std::max(0, std::min(100, blind))); } void World::updateSoundListener() @@ -1701,16 +1712,16 @@ namespace MWWorld mWeatherManager->modRegion(regionid, chances); } - Ogre::Vector2 World::getNorthVector (CellStore* cell) + osg::Vec2f World::getNorthVector (CellStore* cell) { MWWorld::CellRefList& statics = cell->get(); MWWorld::LiveCellRef* ref = statics.find("northmarker"); if (!ref) - return Ogre::Vector2(0, 1); + return osg::Vec2f(0, 1); - Ogre::Quaternion orient (Ogre::Radian(-ref->mData.getPosition().rot[2]), Ogre::Vector3::UNIT_Z); - Ogre::Vector3 dir = orient * Ogre::Vector3(0,1,0); - Ogre::Vector2 d = Ogre::Vector2(dir.x, dir.y); + osg::Quat orient (-ref->mData.getPosition().rot[2], osg::Vec3f(0,0,1)); + osg::Vec3f dir = orient * osg::Vec3f(0,1,0); + osg::Vec2f d (dir.x(), dir.y()); return d; } @@ -1756,24 +1767,9 @@ namespace MWWorld } } - void World::worldToInteriorMapPosition (Ogre::Vector2 position, float& nX, float& nY, int &x, int& y) - { - //mRendering->worldToInteriorMapPosition(position, nX, nY, x, y); - } - - Ogre::Vector2 World::interiorMapToWorldPosition(float nX, float nY, int x, int y) - { - return Ogre::Vector2();//mRendering->interiorMapToWorldPosition(nX, nY, x, y); - } - - bool World::isPositionExplored (float nX, float nY, int x, int y, bool interior) - { - return 0;//mRendering->isPositionExplored(nX, nY, x, y, interior); - } - void World::setWaterHeight(const float height) { - //mPhysics->setWaterHeight(height); + mPhysics->setWaterHeight(height); //mRendering->setWaterHeight(height); } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index e217f4bc4..dedfebdf2 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -121,6 +121,7 @@ namespace MWWorld void updateSoundListener(); void updateWindowManager (); + void updatePlayer(bool paused); MWWorld::Ptr getFacedObject(float maxDistance, bool ignorePlayer=true); void removeContainerScripts(const Ptr& reference); @@ -218,21 +219,12 @@ namespace MWWorld virtual bool isCellQuasiExterior() const; - virtual Ogre::Vector2 getNorthVector (CellStore* cell); + virtual osg::Vec2f getNorthVector (CellStore* cell); ///< get north vector for given interior cell virtual void getDoorMarkers (MWWorld::CellStore* cell, std::vector& out); ///< get a list of teleport door markers for a given cell, to be displayed on the local map - virtual void worldToInteriorMapPosition (Ogre::Vector2 position, float& nX, float& nY, int &x, int& y); - ///< see MWRender::LocalMap::worldToInteriorMapPosition - - virtual Ogre::Vector2 interiorMapToWorldPosition (float nX, float nY, int x, int y); - ///< see MWRender::LocalMap::interiorMapToWorldPosition - - virtual bool isPositionExplored (float nX, float nY, int x, int y, bool interior); - ///< see MWRender::LocalMap::isPositionExplored - virtual void setGlobalInt (const std::string& name, int value); ///< Set value independently from real type. diff --git a/components/myguiplatform/myguitexture.cpp b/components/myguiplatform/myguitexture.cpp index 2a32dd9f3..0a846b227 100644 --- a/components/myguiplatform/myguitexture.cpp +++ b/components/myguiplatform/myguitexture.cpp @@ -86,7 +86,7 @@ namespace osgMyGUI if (!mTextureManager) throw std::runtime_error("No texturemanager set"); - mTexture = mTextureManager->getTexture2D(fname, osg::Texture2D::REPEAT, osg::Texture2D::REPEAT); + mTexture = mTextureManager->getTexture2D(fname, osg::Texture2D::CLAMP_TO_EDGE, osg::Texture2D::CLAMP_TO_EDGE); // FIXME mFormat = MyGUI::PixelFormat::R8G8B8; diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index d676bc3f8..06d5d8792 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -4,7 +4,6 @@ #include #include #include -#include #include #include diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index adf7e94b4..5fdf964c4 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -9,8 +9,6 @@ #include #include -#include - // resource #include #include diff --git a/components/nifosg/particle.cpp b/components/nifosg/particle.cpp index b733987d0..ac304bdf3 100644 --- a/components/nifosg/particle.cpp +++ b/components/nifosg/particle.cpp @@ -6,8 +6,6 @@ #include -#include - #include "userdata.hpp" namespace NifOsg diff --git a/components/sceneutil/lightmanager.cpp b/components/sceneutil/lightmanager.cpp index ce7a343da..e53a55bf3 100644 --- a/components/sceneutil/lightmanager.cpp +++ b/components/sceneutil/lightmanager.cpp @@ -226,6 +226,7 @@ namespace SceneUtil LightSource::LightSource() : mRadius(0.f) { + setNodeMask(Mask_Lit); setUpdateCallback(new CollectLightCallback); } @@ -233,6 +234,12 @@ namespace SceneUtil { osgUtil::CullVisitor* cv = static_cast(nv); + if (!(cv->getCurrentCamera()->getCullMask()&Mask_Lit)) + { + traverse(node, nv); + return; + } + if (!mLightManager) { for (unsigned int i=0;igetNodePath().size(); ++i) diff --git a/components/sceneutil/lightmanager.hpp b/components/sceneutil/lightmanager.hpp index 1cd73589a..dd0c2d3e6 100644 --- a/components/sceneutil/lightmanager.hpp +++ b/components/sceneutil/lightmanager.hpp @@ -9,6 +9,9 @@ namespace SceneUtil { + // This mask should be included in the Cull and Update visitor's traversal mask if lighting is desired. + const int Mask_Lit = (1<<16); + /// LightSource managed by a LightManager. class LightSource : public osg::Node { diff --git a/components/sceneutil/riggeometry.cpp b/components/sceneutil/riggeometry.cpp index 065ee60d9..dd6b9a499 100644 --- a/components/sceneutil/riggeometry.cpp +++ b/components/sceneutil/riggeometry.cpp @@ -6,7 +6,6 @@ #include #include -#include #include "skeleton.hpp" #include "util.hpp" From c4951d1e73fface33580f70474dd315404c8a404 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 26 May 2015 18:10:31 +0200 Subject: [PATCH 1272/3725] Map rotation fix --- apps/openmw/mwrender/localmap.cpp | 16 ++++++++++------ apps/openmw/mwrender/localmap.hpp | 2 +- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 8ab16283e..0da14f702 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -73,10 +73,10 @@ LocalMap::~LocalMap() mRoot->removeChild(*it); } -const osg::Vec2f LocalMap::rotatePoint(const osg::Vec2f& p, const osg::Vec2f& c, const float angle) +const osg::Vec2f LocalMap::rotatePoint(const osg::Vec2f& point, const osg::Vec2f& center, const float angle) { - return osg::Vec2f( std::cos(angle) * (p.x() - c.x()) - std::sin(angle) * (p.y() - c.y()) + c.x(), - std::sin(angle) * (p.x() - c.x()) + std::cos(angle) * (p.y() - c.y()) + c.y()); + return osg::Vec2f( std::cos(angle) * (point.x() - center.x()) - std::sin(angle) * (point.y() - center.y()) + center.x(), + std::sin(angle) * (point.x() - center.x()) + std::cos(angle) * (point.y() - center.y()) + center.y()); } void LocalMap::clear() @@ -330,12 +330,16 @@ void LocalMap::requestInteriorMap(MWWorld::CellStore* cell) mAngle = std::atan2(north.x(), north.y()); // Rotate the cell and merge the rotated corners to the bounding box - osg::Vec2f _center(bounds.center().x(), bounds.center().y()); + osg::Vec2f origCenter(bounds.center().x(), bounds.center().y()); + osg::Vec3f origCorners[8]; + for (int i=0; i<8; ++i) + origCorners[i] = mBounds.corner(i); + for (int i=0; i<8; ++i) { - osg::Vec3f corner = mBounds.corner(i); + osg::Vec3f corner = origCorners[i]; osg::Vec2f corner2d (corner.x(), corner.y()); - corner2d = rotatePoint(corner2d, _center, mAngle); + corner2d = rotatePoint(corner2d, origCenter, mAngle); mBounds.expandBy(osg::Vec3f(corner2d.x(), corner2d.y(), 0)); } diff --git a/apps/openmw/mwrender/localmap.hpp b/apps/openmw/mwrender/localmap.hpp index 8160c325c..ba92cde24 100644 --- a/apps/openmw/mwrender/localmap.hpp +++ b/apps/openmw/mwrender/localmap.hpp @@ -117,7 +117,7 @@ namespace MWRender float mMapWorldSize; float mAngle; - const osg::Vec2f rotatePoint(const osg::Vec2f& p, const osg::Vec2f& c, const float angle); + const osg::Vec2f rotatePoint(const osg::Vec2f& point, const osg::Vec2f& center, const float angle); void requestExteriorMap(MWWorld::CellStore* cell); void requestInteriorMap(MWWorld::CellStore* cell); From 099f93f00df5d3fd76ff707da5993e7154a881f3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 26 May 2015 18:22:21 +0200 Subject: [PATCH 1273/3725] Sky fixes --- apps/openmw/mwrender/renderingmanager.cpp | 5 ++++- apps/openmw/mwrender/sky.cpp | 3 +++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index b1c26812c..6a1ed89a2 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -50,6 +50,7 @@ namespace MWRender stateset->setAttribute(lightModel, osg::StateAttribute::ON); osg::Fog* fog = new osg::Fog; fog->setStart(1); + fog->setMode(osg::Fog::LINEAR); stateset->setAttributeAndModes(fog, osg::StateAttribute::ON); } @@ -60,7 +61,6 @@ namespace MWRender osg::Fog* fog = static_cast(stateset->getAttribute(osg::StateAttribute::FOG)); fog->setColor(mFogColor); fog->setEnd(mFogEnd); - fog->setMode(osg::Fog::LINEAR); } void setAmbientColor(const osg::Vec4f& col) @@ -115,6 +115,7 @@ namespace MWRender source->setLight(mSunLight); mSunLight->setDiffuse(osg::Vec4f(0,0,0,1)); mSunLight->setAmbient(osg::Vec4f(0,0,0,1)); + mSunLight->setSpecular(osg::Vec4f(0,0,0,0)); mSunLight->setConstantAttenuation(1.f); lightRoot->addChild(source); @@ -181,12 +182,14 @@ namespace MWRender void RenderingManager::setSunColour(const osg::Vec4f &colour) { + // need to wrap this in a StateUpdater? mSunLight->setDiffuse(colour); } void RenderingManager::setSunDirection(const osg::Vec3f &direction) { osg::Vec3 position = direction * -1; + // need to wrap this in a StateUpdater? mSunLight->setPosition(osg::Vec4(position.x(), position.y(), position.z(), 0)); mSky->setSunDirection(position); diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 990f3a5d9..d66761195 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -41,6 +41,7 @@ namespace mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 1.f)); mat->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 1.f)); mat->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(1.f, 1.f, 1.f, 1.f)); + mat->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 0.f)); mat->setColorMode(osg::Material::DIFFUSE); return mat; } @@ -51,6 +52,7 @@ namespace mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 1.f)); mat->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 1.f)); mat->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(1.f, 1.f, 1.f, 1.f)); + mat->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 0.f)); mat->setColorMode(osg::Material::OFF); return mat; } @@ -550,6 +552,7 @@ void SkyManager::create() depth->setWriteMask(false); mRootNode->getOrCreateStateSet()->setAttributeAndModes(depth, osg::StateAttribute::ON); mRootNode->getOrCreateStateSet()->setMode(GL_BLEND, osg::StateAttribute::ON); + mRootNode->getOrCreateStateSet()->setMode(GL_FOG, osg::StateAttribute::OFF); mCreated = true; } From 5de24552a8aa275931e8bca71d78bc5bcf2f3a77 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 26 May 2015 19:12:29 +0200 Subject: [PATCH 1274/3725] Leak fix --- components/sceneutil/riggeometry.cpp | 4 +++- components/sceneutil/riggeometry.hpp | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/components/sceneutil/riggeometry.cpp b/components/sceneutil/riggeometry.cpp index dd6b9a499..2a67c6ce6 100644 --- a/components/sceneutil/riggeometry.cpp +++ b/components/sceneutil/riggeometry.cpp @@ -59,7 +59,8 @@ public: }; RigGeometry::RigGeometry() - : mFirstFrame(true) + : mSkeleton(NULL) + , mFirstFrame(true) , mBoundsFirstFrame(true) { setCullCallback(new UpdateRigGeometry); @@ -69,6 +70,7 @@ RigGeometry::RigGeometry() RigGeometry::RigGeometry(const RigGeometry ©, const osg::CopyOp ©op) : osg::Geometry(copy, copyop) + , mSkeleton(NULL) , mInfluenceMap(copy.mInfluenceMap) , mFirstFrame(copy.mFirstFrame) , mBoundsFirstFrame(copy.mBoundsFirstFrame) diff --git a/components/sceneutil/riggeometry.hpp b/components/sceneutil/riggeometry.hpp index ea4245aa8..bd7c586c4 100644 --- a/components/sceneutil/riggeometry.hpp +++ b/components/sceneutil/riggeometry.hpp @@ -46,7 +46,7 @@ namespace SceneUtil private: osg::ref_ptr mSourceGeometry; - osg::ref_ptr mSkeleton; + Skeleton* mSkeleton; osg::ref_ptr mInfluenceMap; From 723beb1cac998a92320b83f9ff14aa0d80d86ff4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 26 May 2015 20:20:18 +0200 Subject: [PATCH 1275/3725] Move IncrementalCompileOperation to SceneManager --- apps/openmw/mwgui/loadingscreen.cpp | 3 ++- apps/openmw/mwrender/objects.cpp | 16 ---------------- apps/openmw/mwrender/objects.hpp | 4 ---- apps/openmw/mwrender/renderingmanager.cpp | 3 ++- components/resource/scenemanager.cpp | 12 +++++++++++- components/resource/scenemanager.hpp | 10 ++++++++++ 6 files changed, 25 insertions(+), 23 deletions(-) diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index 1f084402b..f6a9f5ccd 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -181,7 +181,8 @@ namespace MWGui void LoadingScreen::setProgress (size_t value) { - if (value - mProgress < mProgressBar->getScrollRange()/100.f) + // skip expensive update if there isn't enough visible progress + if (value - mProgress < mProgressBar->getScrollRange()/200.f) return; mProgress = value; mProgressBar->setScrollPosition(0); diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 816002753..47a54fdbf 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -7,8 +7,6 @@ #include #include -#include - #include #include @@ -81,11 +79,6 @@ Objects::~Objects() mCellSceneNodes.clear(); } -void Objects::setIncrementalCompileOperation(osgUtil::IncrementalCompileOperation *ico) -{ - mIncrementalCompileOperation = ico; -} - void Objects::insertBegin(const MWWorld::Ptr& ptr) { osg::ref_ptr cellnode; @@ -118,9 +111,6 @@ void Objects::insertModel(const MWWorld::Ptr &ptr, const std::string &mesh, bool std::auto_ptr anim (new ObjectAnimation(ptr, mesh, mResourceSystem, allowLight)); - if (mIncrementalCompileOperation && anim->getObjectRoot()) - mIncrementalCompileOperation->add(anim->getObjectRoot()); - if (!allowLight) { RemoveParticlesVisitor visitor; @@ -144,9 +134,6 @@ void Objects::insertCreature(const MWWorld::Ptr &ptr, const std::string &mesh, b else anim.reset(new CreatureAnimation(ptr, mesh, mResourceSystem)); - if (mIncrementalCompileOperation && anim->getObjectRoot()) - mIncrementalCompileOperation->add(anim->getObjectRoot()); - mObjects.insert(std::make_pair(ptr, anim.release())); } @@ -157,9 +144,6 @@ void Objects::insertNPC(const MWWorld::Ptr &ptr) std::auto_ptr anim (new NpcAnimation(ptr, osg::ref_ptr(ptr.getRefData().getBaseNode()), mResourceSystem, 0)); - if (mIncrementalCompileOperation && anim->getObjectRoot()) - mIncrementalCompileOperation->add(anim->getObjectRoot()); - mObjects.insert(std::make_pair(ptr, anim.release())); } diff --git a/apps/openmw/mwrender/objects.hpp b/apps/openmw/mwrender/objects.hpp index b3799d0ef..5c7ea32f4 100644 --- a/apps/openmw/mwrender/objects.hpp +++ b/apps/openmw/mwrender/objects.hpp @@ -69,14 +69,10 @@ class Objects{ Resource::ResourceSystem* mResourceSystem; - osg::ref_ptr mIncrementalCompileOperation; - public: Objects(Resource::ResourceSystem* resourceSystem, osg::ref_ptr rootNode); ~Objects(); - void setIncrementalCompileOperation(osgUtil::IncrementalCompileOperation* ico); - /// @param animated Attempt to load separate keyframes from a .kf file matching the model file? /// @param allowLight If false, no lights will be created, and particles systems will be removed. void insertModel(const MWWorld::Ptr& ptr, const std::string &model, bool animated=false, bool allowLight=true); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 6a1ed89a2..e1f1e13d1 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -17,6 +17,7 @@ #include #include +#include #include @@ -101,7 +102,7 @@ namespace MWRender mViewer->setIncrementalCompileOperation(new osgUtil::IncrementalCompileOperation); - mObjects->setIncrementalCompileOperation(mViewer->getIncrementalCompileOperation()); + mResourceSystem->getSceneManager()->setIncrementalCompileOperation(mViewer->getIncrementalCompileOperation()); mEffectManager.reset(new EffectManager(mRootNode, mResourceSystem)); diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index 8a0d526fa..5c3d9f151 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -6,6 +6,8 @@ #include +#include + #include #include @@ -88,7 +90,10 @@ namespace Resource // TODO: add support for non-NIF formats NifOsg::Loader loader; - osg::ref_ptr loaded = loader.load(Nif::NIFFilePtr(new Nif::NIFFile(file, normalized)), mTextureManager); + osg::ref_ptr loaded = loader.load(Nif::NIFFilePtr(new Nif::NIFFile(file, normalized)), mTextureManager); + + if (mIncrementalCompileOperation) + mIncrementalCompileOperation->add(loaded); mIndex[normalized] = loaded; return loaded; @@ -147,6 +152,11 @@ namespace Resource } } + void SceneManager::setIncrementalCompileOperation(osgUtil::IncrementalCompileOperation *ico) + { + mIncrementalCompileOperation = ico; + } + const VFS::Manager* SceneManager::getVFS() const { return mVFS; diff --git a/components/resource/scenemanager.hpp b/components/resource/scenemanager.hpp index 9f3c5387e..625c1cd5e 100644 --- a/components/resource/scenemanager.hpp +++ b/components/resource/scenemanager.hpp @@ -24,6 +24,11 @@ namespace NifOsg class KeyframeHolder; } +namespace osgUtil +{ + class IncrementalCompileOperation; +} + namespace Resource { @@ -56,6 +61,9 @@ namespace Resource /// in cases where multiple contexts are used over the lifetime of the application. void releaseGLObjects(osg::State* state); + /// Set up an IncrementalCompileOperation for background compiling of loaded scenes. + void setIncrementalCompileOperation(osgUtil::IncrementalCompileOperation* ico); + const VFS::Manager* getVFS() const; Resource::TextureManager* getTextureManager(); @@ -64,6 +72,8 @@ namespace Resource const VFS::Manager* mVFS; Resource::TextureManager* mTextureManager; + osg::ref_ptr mIncrementalCompileOperation; + // observer_ptr? typedef std::map > Index; Index mIndex; From 2f976495403ddc5ed39038632021ef536697df11 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 27 May 2015 00:30:39 +0200 Subject: [PATCH 1276/3725] Fix for cleanup issue when exiting after a failed savegame load (Fixes #2580) --- apps/openmw/mwrender/npcanimation.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 6a6d52e26..f4943ba55 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -196,7 +196,11 @@ const NpcAnimation::PartBoneMap NpcAnimation::sPartList = createPartListMap(); NpcAnimation::~NpcAnimation() { - if (!mListenerDisabled) + if (!mListenerDisabled + // No need to getInventoryStore() to reset, if none exists + // This is to avoid triggering the listener via ensureCustomData()->autoEquip()->fireEquipmentChanged() + // all from within this destructor. ouch! + && mPtr.getRefData().getCustomData()) mPtr.getClass().getInventoryStore(mPtr).setListener(NULL, mPtr); } From 5fd107a95c7a763d3fe7a84d433b8bc7de1dac69 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Wed, 27 May 2015 10:19:26 +1000 Subject: [PATCH 1277/3725] Fix crash with array out of bounds when refNum index is incorrect. --- components/esm/loadcell.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index 0f8897c48..94f4b0b6e 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -18,9 +18,11 @@ namespace ///< Translate 8bit/24bit code (stored in refNum.mIndex) into a proper refNum void adjustRefNum (ESM::RefNum& refNum, ESM::ESMReader& reader) { - int local = (refNum.mIndex & 0xff000000) >> 24; + unsigned int local = (refNum.mIndex & 0xff000000) >> 24; - if (local) + // If we have an index value that does not make sense, assume that it was an addition + // by the present plugin (but a faulty one) + if (local && local <= reader.getGameFiles().size()) { // If the most significant 8 bits are used, then this reference already exists. // In this case, do not spawn a new reference, but overwrite the old one. From b7044ac119b6bbbdd7b74749c5201a462fec0d59 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Wed, 27 May 2015 10:27:57 +1000 Subject: [PATCH 1278/3725] Fix crash loading some addon files. Should resolve Bug #2583. - This may be a bug within QSortFilterProxyModel - It isn't 100% clear what aspects of these addon files cause the issue, but something about them causes Qt to lose track of its internal row numbers. --- apps/opencs/model/world/idtableproxymodel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/world/idtableproxymodel.cpp b/apps/opencs/model/world/idtableproxymodel.cpp index 84869716e..987d27462 100644 --- a/apps/opencs/model/world/idtableproxymodel.cpp +++ b/apps/opencs/model/world/idtableproxymodel.cpp @@ -46,7 +46,7 @@ void CSMWorld::IdTableProxyModel::setFilter (const boost::shared_ptr Date: Wed, 27 May 2015 15:55:00 +1000 Subject: [PATCH 1279/3725] Object verifier check to see if the script used by that object actually exists. Should resolve Bug #2582. --- .../opencs/model/tools/referenceablecheck.cpp | 83 ++++++++++++++++--- .../opencs/model/tools/referenceablecheck.hpp | 20 +++-- apps/opencs/model/tools/tools.cpp | 14 ++-- 3 files changed, 93 insertions(+), 24 deletions(-) diff --git a/apps/opencs/model/tools/referenceablecheck.cpp b/apps/opencs/model/tools/referenceablecheck.cpp index c0991a330..548fcd36f 100644 --- a/apps/opencs/model/tools/referenceablecheck.cpp +++ b/apps/opencs/model/tools/referenceablecheck.cpp @@ -8,12 +8,14 @@ CSMTools::ReferenceableCheckStage::ReferenceableCheckStage( const CSMWorld::RefIdData& referenceable, const CSMWorld::IdCollection& races, const CSMWorld::IdCollection& classes, - const CSMWorld::IdCollection& faction) + const CSMWorld::IdCollection& faction, + const CSMWorld::IdCollection& scripts) : mReferencables(referenceable), mRaces(races), mClasses(classes), mFactions(faction), + mScripts(scripts), mPlayerPresent(false) { } @@ -245,6 +247,9 @@ void CSMTools::ReferenceableCheckStage::bookCheck( CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Book, book.mId); inventoryItemCheck(book, messages, id.toString(), true); + + // Check that mentioned scripts exist + scriptCheck(book, messages, id.toString()); } void CSMTools::ReferenceableCheckStage::activatorCheck( @@ -265,6 +270,9 @@ void CSMTools::ReferenceableCheckStage::activatorCheck( //Checking for model, IIRC all activators should have a model if (activator.mModel.empty()) messages.push_back (std::make_pair (id, activator.mId + " has no model")); + + // Check that mentioned scripts exist + scriptCheck(activator, messages, id.toString()); } void CSMTools::ReferenceableCheckStage::potionCheck( @@ -284,6 +292,9 @@ void CSMTools::ReferenceableCheckStage::potionCheck( inventoryItemCheck(potion, messages, id.toString()); //IIRC potion can have empty effects list just fine. + + // Check that mentioned scripts exist + scriptCheck(potion, messages, id.toString()); } @@ -305,6 +316,9 @@ void CSMTools::ReferenceableCheckStage::apparatusCheck( inventoryItemCheck(apparatus, messages, id.toString()); toolCheck(apparatus, messages, id.toString()); + + // Check that mentioned scripts exist + scriptCheck(apparatus, messages, id.toString()); } void CSMTools::ReferenceableCheckStage::armorCheck( @@ -331,6 +345,9 @@ void CSMTools::ReferenceableCheckStage::armorCheck( //checking for health. Only positive numbers are allowed, or 0 is illegal if (armor.mData.mHealth <= 0) messages.push_back (std::make_pair (id, armor.mId + " has non positive health")); + + // Check that mentioned scripts exist + scriptCheck(armor, messages, id.toString()); } void CSMTools::ReferenceableCheckStage::clothingCheck( @@ -348,6 +365,9 @@ void CSMTools::ReferenceableCheckStage::clothingCheck( const ESM::Clothing& clothing = (dynamic_cast& >(baseRecord)).get(); CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Clothing, clothing.mId); inventoryItemCheck(clothing, messages, id.toString(), true); + + // Check that mentioned scripts exist + scriptCheck(clothing, messages, id.toString()); } void CSMTools::ReferenceableCheckStage::containerCheck( @@ -377,6 +397,9 @@ void CSMTools::ReferenceableCheckStage::containerCheck( //checking for name if (container.mName.empty()) messages.push_back (std::make_pair (id, container.mId + " has an empty name")); + + // Check that mentioned scripts exist + scriptCheck(container, messages, id.toString()); } void CSMTools::ReferenceableCheckStage::creatureCheck ( @@ -444,6 +467,9 @@ void CSMTools::ReferenceableCheckStage::creatureCheck ( //TODO, find meaning of other values if (creature.mData.mGold < 0) //It seems that this is for gold in merchant creatures messages.push_back (std::make_pair (id, creature.mId + " has negative gold ")); + + // Check that mentioned scripts exist + scriptCheck(creature, messages, id.toString()); } void CSMTools::ReferenceableCheckStage::doorCheck( @@ -455,15 +481,18 @@ void CSMTools::ReferenceableCheckStage::doorCheck( if (baseRecord.isDeleted()) return; - const ESM::Door& Door = (dynamic_cast&>(baseRecord)).get(); - CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Door, Door.mId); + const ESM::Door& door = (dynamic_cast&>(baseRecord)).get(); + CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Door, door.mId); //usual, name or model - if (Door.mName.empty()) - messages.push_back (std::make_pair (id, Door.mId + " has an empty name")); + if (door.mName.empty()) + messages.push_back (std::make_pair (id, door.mId + " has an empty name")); + + if (door.mModel.empty()) + messages.push_back (std::make_pair (id, door.mId + " has no model")); - if (Door.mModel.empty()) - messages.push_back (std::make_pair (id, Door.mId + " has no model")); + // Check that mentioned scripts exist + scriptCheck(door, messages, id.toString()); } void CSMTools::ReferenceableCheckStage::ingredientCheck( @@ -478,10 +507,13 @@ void CSMTools::ReferenceableCheckStage::ingredientCheck( return; } - const ESM::Ingredient& Ingredient = (dynamic_cast& >(baseRecord)).get(); - CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Ingredient, Ingredient.mId); + const ESM::Ingredient& ingredient = (dynamic_cast& >(baseRecord)).get(); + CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Ingredient, ingredient.mId); - inventoryItemCheck(Ingredient, messages, id.toString()); + inventoryItemCheck(ingredient, messages, id.toString()); + + // Check that mentioned scripts exist + scriptCheck(ingredient, messages, id.toString()); } void CSMTools::ReferenceableCheckStage::creaturesLevListCheck( @@ -542,6 +574,9 @@ void CSMTools::ReferenceableCheckStage::lightCheck( if (light.mData.mTime == 0) messages.push_back (std::make_pair (id, light.mId + " has zero duration")); } + + // Check that mentioned scripts exist + scriptCheck(light, messages, id.toString()); } void CSMTools::ReferenceableCheckStage::lockpickCheck( @@ -562,6 +597,9 @@ void CSMTools::ReferenceableCheckStage::lockpickCheck( inventoryItemCheck(lockpick, messages, id.toString()); toolCheck(lockpick, messages, id.toString(), true); + + // Check that mentioned scripts exist + scriptCheck(lockpick, messages, id.toString()); } void CSMTools::ReferenceableCheckStage::miscCheck( @@ -580,6 +618,9 @@ void CSMTools::ReferenceableCheckStage::miscCheck( CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Miscellaneous, miscellaneous.mId); inventoryItemCheck(miscellaneous, messages, id.toString()); + + // Check that mentioned scripts exist + scriptCheck(miscellaneous, messages, id.toString()); } void CSMTools::ReferenceableCheckStage::npcCheck ( @@ -697,6 +738,9 @@ void CSMTools::ReferenceableCheckStage::npcCheck ( messages.push_back (std::make_pair (id, npc.mId + " has no hair")); //TODO: reputation, Disposition, rank, everything else + + // Check that mentioned scripts exist + scriptCheck(npc, messages, id.toString()); } void CSMTools::ReferenceableCheckStage::weaponCheck( @@ -773,6 +817,9 @@ void CSMTools::ReferenceableCheckStage::weaponCheck( messages.push_back (std::make_pair (id, weapon.mId + " has negative reach")); } } + + // Check that mentioned scripts exist + scriptCheck(weapon, messages, id.toString()); } void CSMTools::ReferenceableCheckStage::probeCheck( @@ -792,6 +839,9 @@ void CSMTools::ReferenceableCheckStage::probeCheck( inventoryItemCheck(probe, messages, id.toString()); toolCheck(probe, messages, id.toString(), true); + + // Check that mentioned scripts exist + scriptCheck(probe, messages, id.toString()); } void CSMTools::ReferenceableCheckStage::repairCheck ( @@ -808,6 +858,9 @@ void CSMTools::ReferenceableCheckStage::repairCheck ( inventoryItemCheck (repair, messages, id.toString()); toolCheck (repair, messages, id.toString(), true); + + // Check that mentioned scripts exist + scriptCheck(repair, messages, id.toString()); } void CSMTools::ReferenceableCheckStage::staticCheck ( @@ -919,3 +972,13 @@ template void CSMTools::ReferenceableCheckStage::listCheck ( someList.mId + " contains item with non-positive level")); } } + +template void CSMTools::ReferenceableCheckStage::scriptCheck ( + const Tool& someTool, CSMDoc::Messages& messages, const std::string& someID) +{ + if (!someTool.mScript.empty()) + { + if (mScripts.searchId(someTool.mScript) == -1) + messages.push_back (std::make_pair (someID, someTool.mId + " refers to an unknown script \""+someTool.mScript+"\"")); + } +} diff --git a/apps/opencs/model/tools/referenceablecheck.hpp b/apps/opencs/model/tools/referenceablecheck.hpp index ac7ed7082..a34f3a789 100644 --- a/apps/opencs/model/tools/referenceablecheck.hpp +++ b/apps/opencs/model/tools/referenceablecheck.hpp @@ -15,7 +15,8 @@ namespace CSMTools ReferenceableCheckStage (const CSMWorld::RefIdData& referenceable, const CSMWorld::IdCollection& races, const CSMWorld::IdCollection& classes, - const CSMWorld::IdCollection& factions); + const CSMWorld::IdCollection& factions, + const CSMWorld::IdCollection& scripts); virtual void perform(int stage, CSMDoc::Messages& messages); virtual int setup(); @@ -46,26 +47,30 @@ namespace CSMTools //FINAL CHECK void finalCheck (CSMDoc::Messages& messages); - //TEMPLATE CHECKS - template void inventoryItemCheck(const ITEM& someItem, + //TEMPLATE CHECKS + template void inventoryItemCheck(const ITEM& someItem, CSMDoc::Messages& messages, const std::string& someID, bool enchantable); //for all enchantable items. - template void inventoryItemCheck(const ITEM& someItem, + template void inventoryItemCheck(const ITEM& someItem, CSMDoc::Messages& messages, const std::string& someID); //for non-enchantable items. - template void toolCheck(const TOOL& someTool, + template void toolCheck(const TOOL& someTool, CSMDoc::Messages& messages, const std::string& someID, bool canbebroken); //for tools with uses. - template void toolCheck(const TOOL& someTool, + template void toolCheck(const TOOL& someTool, CSMDoc::Messages& messages, const std::string& someID); //for tools without uses. - template void listCheck(const LIST& someList, + template void listCheck(const LIST& someList, + CSMDoc::Messages& messages, + const std::string& someID); + + template void scriptCheck(const TOOL& someTool, CSMDoc::Messages& messages, const std::string& someID); @@ -73,6 +78,7 @@ namespace CSMTools const CSMWorld::IdCollection& mRaces; const CSMWorld::IdCollection& mClasses; const CSMWorld::IdCollection& mFactions; + const CSMWorld::IdCollection& mScripts; bool mPlayerPresent; }; } diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index 99e462b1d..979f72486 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -81,7 +81,7 @@ CSMDoc::OperationHolder *CSMTools::Tools::getVerifier() mVerifierOperation->appendStage (new SpellCheckStage (mData.getSpells())); - mVerifierOperation->appendStage (new ReferenceableCheckStage (mData.getReferenceables().getDataSet(), mData.getRaces(), mData.getClasses(), mData.getFactions())); + mVerifierOperation->appendStage (new ReferenceableCheckStage (mData.getReferenceables().getDataSet(), mData.getRaces(), mData.getClasses(), mData.getFactions(), mData.getScripts())); mVerifierOperation->appendStage (new ReferenceCheckStage(mData.getReferences(), mData.getReferenceables(), mData.getCells(), mData.getFactions())); @@ -114,7 +114,7 @@ CSMTools::Tools::Tools (CSMDoc::Document& document) connect (&mSearch, SIGNAL (done (int, bool)), this, SIGNAL (done (int, bool))); connect (&mSearch, SIGNAL (reportMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int)), - this, SLOT (verifierMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int))); + this, SLOT (verifierMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int))); } CSMTools::Tools::~Tools() @@ -130,7 +130,7 @@ CSMTools::Tools::~Tools() mSearch.abortAndWait(); delete mSearchOperation; } - + for (std::map::iterator iter (mReports.begin()); iter!=mReports.end(); ++iter) delete iter->second; } @@ -149,7 +149,7 @@ CSMWorld::UniversalId CSMTools::Tools::newSearch() { mReports.insert (std::make_pair (mNextReportNumber++, new ReportModel (true))); - return CSMWorld::UniversalId (CSMWorld::UniversalId::Type_Search, mNextReportNumber-1); + return CSMWorld::UniversalId (CSMWorld::UniversalId::Type_Search, mNextReportNumber-1); } void CSMTools::Tools::runSearch (const CSMWorld::UniversalId& searchId, const Search& search) @@ -159,11 +159,11 @@ void CSMTools::Tools::runSearch (const CSMWorld::UniversalId& searchId, const Se if (!mSearchOperation) { mSearchOperation = new SearchOperation (mDocument); - mSearch.setOperation (mSearchOperation); + mSearch.setOperation (mSearchOperation); } mSearchOperation->configure (search); - + mSearch.start(); } @@ -198,7 +198,7 @@ CSMTools::ReportModel *CSMTools::Tools::getReport (const CSMWorld::UniversalId& id.getType()!=CSMWorld::UniversalId::Type_LoadErrorLog && id.getType()!=CSMWorld::UniversalId::Type_Search) throw std::logic_error ("invalid request for report model: " + id.toString()); - + return mReports.at (id.getIndex()); } From 3a31468af07548a17d2a0cd45020bb9aa552c349 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Wed, 27 May 2015 22:12:11 +1000 Subject: [PATCH 1280/3725] Pathgrid record verifier. Feature #2000. --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/tools/pathgridcheck.cpp | 158 ++++++++++++++++++++++ apps/opencs/model/tools/pathgridcheck.hpp | 31 +++++ apps/opencs/model/tools/tools.cpp | 3 + 4 files changed, 193 insertions(+), 1 deletion(-) create mode 100644 apps/opencs/model/tools/pathgridcheck.cpp create mode 100644 apps/opencs/model/tools/pathgridcheck.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 438f3c694..78b2deb7a 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -40,7 +40,7 @@ opencs_units (model/tools opencs_units_noqt (model/tools mandatoryid skillcheck classcheck factioncheck racecheck soundcheck regioncheck birthsigncheck spellcheck referencecheck referenceablecheck scriptcheck bodypartcheck - startscriptcheck search searchoperation searchstage + startscriptcheck search searchoperation searchstage pathgridcheck ) diff --git a/apps/opencs/model/tools/pathgridcheck.cpp b/apps/opencs/model/tools/pathgridcheck.cpp new file mode 100644 index 000000000..71f596f4f --- /dev/null +++ b/apps/opencs/model/tools/pathgridcheck.cpp @@ -0,0 +1,158 @@ +#include "pathgridcheck.hpp" + +#include +#include + +#include "../world/universalid.hpp" +#include "../world/idcollection.hpp" +#include "../world/subcellcollection.hpp" +#include "../world/pathgrid.hpp" + + +CSMTools::PathgridCheckStage::PathgridCheckStage (const CSMWorld::SubCellCollection& pathgrids) +: mPathgrids (pathgrids) +{} + +int CSMTools::PathgridCheckStage::setup() +{ + return mPathgrids.getSize(); +} + +void CSMTools::PathgridCheckStage::perform (int stage, CSMDoc::Messages& messages) +{ + const CSMWorld::Record& record = mPathgrids.getRecord (stage); + + if (record.isDeleted()) + return; + + const CSMWorld::Pathgrid& pathgrid = record.get(); + + CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Pathgrid, pathgrid.mId); + + // check the number of pathgrid points + if (pathgrid.mData.mS2 > static_cast(pathgrid.mPoints.size())) + messages.push_back (std::make_pair (id, pathgrid.mId + " has less points than expected")); + else if (pathgrid.mData.mS2 > static_cast(pathgrid.mPoints.size())) + messages.push_back (std::make_pair (id, pathgrid.mId + " has more points than expected")); + + struct Point + { + unsigned char mConnectionNum; + std::vector mOtherIndex; + Point() : mConnectionNum(0), mOtherIndex(0) {} + }; + std::vector pointList(pathgrid.mPoints.size()); + std::vector duplList; + + for (unsigned int i = 0; i < pathgrid.mEdges.size(); ++i) + { + if (pathgrid.mEdges[i].mV0 < static_cast(pathgrid.mPoints.size()) && pathgrid.mEdges[i].mV0 >= 0) + { + pointList[pathgrid.mEdges[i].mV0].mConnectionNum++; + // first check for duplicate edges + unsigned int j = 0; + for (; j < pointList[pathgrid.mEdges[i].mV0].mOtherIndex.size(); ++j) + { + if (pointList[pathgrid.mEdges[i].mV0].mOtherIndex[j] == pathgrid.mEdges[i].mV1) + { + std::ostringstream ss; + ss << "has a duplicate edge between points" << pathgrid.mEdges[i].mV0 + << " and " << pathgrid.mEdges[i].mV1; + messages.push_back (std::make_pair (id, pathgrid.mId + ss.str())); + break; + } + } + + // only add if not a duplicate + if (j == pointList[pathgrid.mEdges[i].mV0].mOtherIndex.size()) + pointList[pathgrid.mEdges[i].mV0].mOtherIndex.push_back(pathgrid.mEdges[i].mV1); + } + else + { + std::ostringstream ss; + ss << " has an edge connecting a non-existent point " << pathgrid.mEdges[i].mV0; + messages.push_back (std::make_pair (id, pathgrid.mId + ss.str())); + } + } + + for (unsigned int i = 0; i < pathgrid.mPoints.size(); ++i) + { + // check the connection number for each point matches the edge connections + if (pathgrid.mPoints[i].mConnectionNum > pointList[i].mConnectionNum) + { + std::ostringstream ss; + ss << " has has less edges than expected for point " << i; + messages.push_back (std::make_pair (id, pathgrid.mId + ss.str())); + } + else if (pathgrid.mPoints[i].mConnectionNum < pointList[i].mConnectionNum) + { + std::ostringstream ss; + ss << " has has more edges than expected for point " << i; + messages.push_back (std::make_pair (id, pathgrid.mId + ss.str())); + } + + // check that edges are bidirectional + bool foundReverse = false; + for (unsigned int j = 0; j < pointList[i].mOtherIndex.size(); ++j) + { + for (unsigned int k = 0; k < pointList[pointList[i].mOtherIndex[j]].mOtherIndex.size(); ++k) + { + if (pointList[pointList[i].mOtherIndex[j]].mOtherIndex[k] == static_cast(i)) + { + foundReverse = true; + break; + } + } + + if (!foundReverse) + { + std::ostringstream ss; + ss << " has a missing edge between points " << i << " and " << pointList[i].mOtherIndex[j]; + messages.push_back (std::make_pair (id, pathgrid.mId + ss.str())); + } + } + + // check duplicate points + // FIXME: how to do this efficiently? + for (unsigned int j = 0; j < pathgrid.mPoints.size(); ++j) + { + if (j == i) + continue; + + if (pathgrid.mPoints[i].mX == pathgrid.mPoints[j].mX && + pathgrid.mPoints[i].mY == pathgrid.mPoints[j].mY && + pathgrid.mPoints[i].mZ == pathgrid.mPoints[j].mZ) + { + std::vector::const_iterator it = find(duplList.begin(), duplList.end(), i); + if (it == duplList.end()) + { + std::ostringstream ss; + ss << " has a duplicated point (" << i + << ") x=" << pathgrid.mPoints[i].mX + << ", y=" << pathgrid.mPoints[i].mY + << ", z=" << pathgrid.mPoints[i].mZ; + messages.push_back (std::make_pair (id, pathgrid.mId + ss.str())); + + duplList.push_back(i); + break; + } + } + } + } + + // check pathgrid points that are not connected to anything + for (unsigned int i = 0; i < pointList.size(); ++i) + { + if (pointList[i].mConnectionNum == 0) + { + std::ostringstream ss; + ss << " has an orphaned point (" << i + << ") x=" << pathgrid.mPoints[i].mX + << ", y=" << pathgrid.mPoints[i].mY + << ", z=" << pathgrid.mPoints[i].mZ; + messages.push_back (std::make_pair (id, pathgrid.mId + ss.str())); + } + } + + // TODO: check whether there are disconnected graphs +} diff --git a/apps/opencs/model/tools/pathgridcheck.hpp b/apps/opencs/model/tools/pathgridcheck.hpp new file mode 100644 index 000000000..c90dbc8ed --- /dev/null +++ b/apps/opencs/model/tools/pathgridcheck.hpp @@ -0,0 +1,31 @@ +#ifndef CSM_TOOLS_PATHGRIDCHECK_H +#define CSM_TOOLS_PATHGRIDCHECK_H + +#include "../world/collection.hpp" + +#include "../doc/stage.hpp" + +namespace CSMWorld +{ + struct Pathgrid; + template + class SubCellCollection; +} + +namespace CSMTools +{ + class PathgridCheckStage : public CSMDoc::Stage + { + const CSMWorld::SubCellCollection >& mPathgrids; + + public: + + PathgridCheckStage (const CSMWorld::SubCellCollection >& pathgrids); + + virtual int setup(); + + virtual void perform (int stage, CSMDoc::Messages& messages); + }; +} + +#endif // CSM_TOOLS_PATHGRIDCHECK_H diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index 99e462b1d..fd1569697 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -26,6 +26,7 @@ #include "referencecheck.hpp" #include "startscriptcheck.hpp" #include "searchoperation.hpp" +#include "pathgridcheck.hpp" CSMDoc::OperationHolder *CSMTools::Tools::get (int type) { @@ -96,6 +97,8 @@ CSMDoc::OperationHolder *CSMTools::Tools::getVerifier() CSMWorld::UniversalId( CSMWorld::UniversalId::Type_Meshes )), mData.getRaces() )); + mVerifierOperation->appendStage (new PathgridCheckStage (mData.getPathgrids())); + mVerifier.setOperation (mVerifierOperation); } From 674a124bc6efe5afeba544a5ebb9eb3fd8e855ef Mon Sep 17 00:00:00 2001 From: cc9cii Date: Wed, 27 May 2015 22:27:32 +1000 Subject: [PATCH 1281/3725] Don't use local type as a template parameter. --- apps/opencs/model/tools/pathgridcheck.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/apps/opencs/model/tools/pathgridcheck.cpp b/apps/opencs/model/tools/pathgridcheck.cpp index 71f596f4f..8f22cc8cd 100644 --- a/apps/opencs/model/tools/pathgridcheck.cpp +++ b/apps/opencs/model/tools/pathgridcheck.cpp @@ -8,6 +8,15 @@ #include "../world/subcellcollection.hpp" #include "../world/pathgrid.hpp" +namespace +{ + struct Point + { + unsigned char mConnectionNum; + std::vector mOtherIndex; + Point() : mConnectionNum(0), mOtherIndex(0) {} + }; +} CSMTools::PathgridCheckStage::PathgridCheckStage (const CSMWorld::SubCellCollection& pathgrids) : mPathgrids (pathgrids) @@ -35,12 +44,6 @@ void CSMTools::PathgridCheckStage::perform (int stage, CSMDoc::Messages& message else if (pathgrid.mData.mS2 > static_cast(pathgrid.mPoints.size())) messages.push_back (std::make_pair (id, pathgrid.mId + " has more points than expected")); - struct Point - { - unsigned char mConnectionNum; - std::vector mOtherIndex; - Point() : mConnectionNum(0), mOtherIndex(0) {} - }; std::vector pointList(pathgrid.mPoints.size()); std::vector duplList; From b6878c2e0c02bc6c3c5f8d14b96e991f2cb1f6bd Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 27 May 2015 19:45:26 +0200 Subject: [PATCH 1282/3725] improved error handling in LocalScripts::add --- apps/openmw/mwworld/localscripts.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/localscripts.cpp b/apps/openmw/mwworld/localscripts.cpp index 5be66ccea..e30246f7c 100644 --- a/apps/openmw/mwworld/localscripts.cpp +++ b/apps/openmw/mwworld/localscripts.cpp @@ -93,7 +93,7 @@ std::pair MWWorld::LocalScripts::getNext() void MWWorld::LocalScripts::add (const std::string& scriptName, const Ptr& ptr) { - if (const ESM::Script *script = mStore.get().find (scriptName)) + if (const ESM::Script *script = mStore.get().search (scriptName)) { try { @@ -108,6 +108,10 @@ void MWWorld::LocalScripts::add (const std::string& scriptName, const Ptr& ptr) << " because an exception has been thrown: " << exception.what() << std::endl; } } + else + std::cerr + << "failed to add local script " << scriptName + << " because the script does not exist." << std::endl; } void MWWorld::LocalScripts::addCell (CellStore *cell) From fe439e53fffc53e951cfafa690e22e7c536e114d Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 27 May 2015 22:32:11 +0200 Subject: [PATCH 1283/3725] Bullet include cleanup --- apps/openmw/mwphysics/actor.cpp | 8 +++++--- apps/openmw/mwphysics/physicssystem.cpp | 11 +++++++++++ apps/openmw/mwphysics/physicssystem.hpp | 7 +++++-- apps/openmw/mwphysics/trace.cpp | 5 +++-- apps/openmw/mwrender/bulletdebugdraw.cpp | 2 ++ apps/openmw/mwrender/bulletdebugdraw.hpp | 6 ++++-- components/nifbullet/bulletnifloader.cpp | 20 ++++++++++++++++++++ components/nifbullet/bulletnifloader.hpp | 24 ++++-------------------- 8 files changed, 54 insertions(+), 29 deletions(-) diff --git a/apps/openmw/mwphysics/actor.cpp b/apps/openmw/mwphysics/actor.cpp index 7084af862..c47ecd17c 100644 --- a/apps/openmw/mwphysics/actor.cpp +++ b/apps/openmw/mwphysics/actor.cpp @@ -2,12 +2,14 @@ #include -#include - -#include "../mwworld/class.hpp" +#include +#include +#include #include +#include "../mwworld/class.hpp" + #include "convert.hpp" #include "collisiontype.hpp" diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 065be083d..b706912ed 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -6,6 +6,15 @@ #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include @@ -600,6 +609,8 @@ namespace MWPhysics mDispatcher = new btCollisionDispatcher(mCollisionConfiguration); mSolver = new btSequentialImpulseConstraintSolver; mBroadphase = new btDbvtBroadphase(); + + // Note we don't use any Dynamics at the moment - a btCollisionWorld might be sufficient? mDynamicsWorld = new btDiscreteDynamicsWorld(mDispatcher,mBroadphase,mSolver,mCollisionConfiguration); // Don't update AABBs of all objects every frame. Most objects in MW are static, so we don't need this. diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index 2ebe16e3b..75666acd7 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -5,8 +5,6 @@ #include -#include - #include #include "../mwworld/ptr.hpp" @@ -35,6 +33,11 @@ namespace Resource class btSequentialImpulseConstraintSolver; class btDiscreteDynamicsWorld; +class btBroadphaseInterface; +class btDefaultCollisionConfiguration; +class btCollisionDispatcher; +class btCollisionObject; +class btCollisionShape; namespace MWPhysics { diff --git a/apps/openmw/mwphysics/trace.cpp b/apps/openmw/mwphysics/trace.cpp index ddb984821..79d4de1a0 100644 --- a/apps/openmw/mwphysics/trace.cpp +++ b/apps/openmw/mwphysics/trace.cpp @@ -2,8 +2,9 @@ #include -#include -#include +#include +#include +#include #include "collisiontype.hpp" #include "actor.hpp" diff --git a/apps/openmw/mwrender/bulletdebugdraw.cpp b/apps/openmw/mwrender/bulletdebugdraw.cpp index 36fc24226..8ac8e3121 100644 --- a/apps/openmw/mwrender/bulletdebugdraw.cpp +++ b/apps/openmw/mwrender/bulletdebugdraw.cpp @@ -2,6 +2,8 @@ #include +#include + #include #include #include diff --git a/apps/openmw/mwrender/bulletdebugdraw.hpp b/apps/openmw/mwrender/bulletdebugdraw.hpp index d2a4163cf..66af2f565 100644 --- a/apps/openmw/mwrender/bulletdebugdraw.hpp +++ b/apps/openmw/mwrender/bulletdebugdraw.hpp @@ -1,12 +1,14 @@ #ifndef OPENMW_MWRENDER_BULLETDEBUGDRAW_H #define OPENMW_MWRENDER_BULLETDEBUGDRAW_H -#include "btBulletDynamicsCommon.h" - #include #include #include +#include + +class btDynamicsWorld; + namespace osg { class Group; diff --git a/components/nifbullet/bulletnifloader.cpp b/components/nifbullet/bulletnifloader.cpp index 89daf898a..33c8c449d 100644 --- a/components/nifbullet/bulletnifloader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -6,6 +6,11 @@ #include #include +#include +#include +#include +#include + #include #include "../nif/niffile.hpp" @@ -36,6 +41,21 @@ btVector3 getbtVector(const osg::Vec3f &v) namespace NifBullet { +// Subclass btBhvTriangleMeshShape to auto-delete the meshInterface +struct TriangleMeshShape : public btBvhTriangleMeshShape +{ + TriangleMeshShape(btStridingMeshInterface* meshInterface, bool useQuantizedAabbCompression) + : btBvhTriangleMeshShape(meshInterface, useQuantizedAabbCompression) + { + } + + virtual ~TriangleMeshShape() + { + delete getTriangleInfoMap(); + delete m_meshInterface; + } +}; + BulletNifLoader::BulletNifLoader() : mCompoundShape(NULL) , mStaticMesh(NULL) diff --git a/components/nifbullet/bulletnifloader.hpp b/components/nifbullet/bulletnifloader.hpp index ae4279f40..0865b134a 100644 --- a/components/nifbullet/bulletnifloader.hpp +++ b/components/nifbullet/bulletnifloader.hpp @@ -6,10 +6,6 @@ #include #include #include -#include -#include -#include -#include #include #include @@ -18,6 +14,10 @@ #include +class btTriangleMesh; +class btCompoundShape; +class btCollisionShape; + namespace Nif { class Node; @@ -70,22 +70,6 @@ private: osg::ref_ptr mSource; }; -// Subclass btBhvTriangleMeshShape to auto-delete the meshInterface -struct TriangleMeshShape : public btBvhTriangleMeshShape -{ - TriangleMeshShape(btStridingMeshInterface* meshInterface, bool useQuantizedAabbCompression) - : btBvhTriangleMeshShape(meshInterface, useQuantizedAabbCompression) - { - } - - virtual ~TriangleMeshShape() - { - delete getTriangleInfoMap(); - delete m_meshInterface; - } -}; - - /** *Load bulletShape from NIF files. */ From 1f00174c026901ac33f00a794d38fd9bb5da3f13 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 27 May 2015 23:09:38 +0200 Subject: [PATCH 1284/3725] Use a btCollisionWorld instead of btDiscreteDynamicsWorld Slightly improves performance, since we no longer need to stepSimulation(). We don't use any Dynamics (yet). --- apps/openmw/CMakeLists.txt | 1 - apps/openmw/mwphysics/actor.cpp | 12 +-- apps/openmw/mwphysics/actor.hpp | 6 +- apps/openmw/mwphysics/physicssystem.cpp | 95 +++++++++++------------- apps/openmw/mwphysics/physicssystem.hpp | 6 +- apps/openmw/mwphysics/trace.cpp | 6 +- apps/openmw/mwphysics/trace.h | 6 +- apps/openmw/mwrender/bulletdebugdraw.cpp | 4 +- apps/openmw/mwrender/bulletdebugdraw.hpp | 6 +- cmake/FindBullet.cmake | 6 +- 10 files changed, 70 insertions(+), 78 deletions(-) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index d45e76f25..b4ecdd956 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -152,7 +152,6 @@ if (ANDROID) MyGUIEngineStatic cpufeatures BulletCollision - BulletDynamics LinearMath ) endif (ANDROID) diff --git a/apps/openmw/mwphysics/actor.cpp b/apps/openmw/mwphysics/actor.cpp index c47ecd17c..94d93e7d7 100644 --- a/apps/openmw/mwphysics/actor.cpp +++ b/apps/openmw/mwphysics/actor.cpp @@ -4,7 +4,7 @@ #include #include -#include +#include #include @@ -17,12 +17,12 @@ namespace MWPhysics { -Actor::Actor(const MWWorld::Ptr& ptr, osg::ref_ptr shape, btDynamicsWorld* world) +Actor::Actor(const MWWorld::Ptr& ptr, osg::ref_ptr shape, btCollisionWorld* world) : mCanWaterWalk(false), mWalkingOnWater(false) , mCollisionObject(0), mForce(0.f, 0.f, 0.f), mOnGround(false) , mInternalCollisionMode(true) , mExternalCollisionMode(true) - , mDynamicsWorld(world) + , mCollisionWorld(world) { mPtr = ptr; @@ -55,7 +55,7 @@ Actor::Actor(const MWWorld::Ptr& ptr, osg::ref_ptrremoveCollisionObject(mCollisionObject.get()); + mCollisionWorld->removeCollisionObject(mCollisionObject.get()); } void Actor::enableCollisionMode(bool collision) @@ -74,13 +74,13 @@ void Actor::enableCollisionBody(bool collision) void Actor::updateCollisionMask() { - mDynamicsWorld->removeCollisionObject(mCollisionObject.get()); + mCollisionWorld->removeCollisionObject(mCollisionObject.get()); int collisionMask = CollisionType_World | CollisionType_HeightMap; if (mExternalCollisionMode) collisionMask |= CollisionType_Actor | CollisionType_Projectile; if (mCanWaterWalk) collisionMask |= CollisionType_Water; - mDynamicsWorld->addCollisionObject(mCollisionObject.get(), CollisionType_Actor, collisionMask); + mCollisionWorld->addCollisionObject(mCollisionObject.get(), CollisionType_Actor, collisionMask); } void Actor::updatePosition() diff --git a/apps/openmw/mwphysics/actor.hpp b/apps/openmw/mwphysics/actor.hpp index 60de42151..7a12f549d 100644 --- a/apps/openmw/mwphysics/actor.hpp +++ b/apps/openmw/mwphysics/actor.hpp @@ -9,7 +9,7 @@ #include #include -class btDynamicsWorld; +class btCollisionWorld; class btCollisionShape; class btCollisionObject; @@ -43,7 +43,7 @@ namespace MWPhysics class Actor : public PtrHolder { public: - Actor(const MWWorld::Ptr& ptr, osg::ref_ptr shape, btDynamicsWorld* world); + Actor(const MWWorld::Ptr& ptr, osg::ref_ptr shape, btCollisionWorld* world); ~Actor(); /** @@ -125,7 +125,7 @@ namespace MWPhysics bool mInternalCollisionMode; bool mExternalCollisionMode; - btDynamicsWorld* mDynamicsWorld; + btCollisionWorld* mCollisionWorld; Actor(const Actor&); Actor& operator=(const Actor&); diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index b706912ed..2bd88e634 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -12,9 +12,9 @@ #include #include #include +#include #include -#include -#include +#include #include #include @@ -65,7 +65,7 @@ namespace MWPhysics } static bool stepMove(btCollisionObject *colobj, osg::Vec3f &position, - const osg::Vec3f &toMove, float &remainingTime, btDynamicsWorld* dynamicsWorld) + const osg::Vec3f &toMove, float &remainingTime, btCollisionWorld* collisionWorld) { /* * Slide up an incline or set of stairs. Should be called only after a @@ -113,7 +113,7 @@ namespace MWPhysics */ ActorTracer tracer, stepper; - stepper.doTrace(colobj, position, position+osg::Vec3f(0.0f,0.0f,sStepSizeUp), dynamicsWorld); + stepper.doTrace(colobj, position, position+osg::Vec3f(0.0f,0.0f,sStepSizeUp), collisionWorld); if(stepper.mFraction < std::numeric_limits::epsilon()) return false; // didn't even move the smallest representable amount // (TODO: shouldn't this be larger? Why bother with such a small amount?) @@ -131,7 +131,7 @@ namespace MWPhysics * +--+ * ============================================== */ - tracer.doTrace(colobj, stepper.mEndPos, stepper.mEndPos + toMove, dynamicsWorld); + tracer.doTrace(colobj, stepper.mEndPos, stepper.mEndPos + toMove, collisionWorld); if(tracer.mFraction < std::numeric_limits::epsilon()) return false; // didn't even move the smallest representable amount @@ -150,7 +150,7 @@ namespace MWPhysics * +--+ +--+ * ============================================== */ - stepper.doTrace(colobj, tracer.mEndPos, tracer.mEndPos-osg::Vec3f(0.0f,0.0f,sStepSizeDown), dynamicsWorld); + stepper.doTrace(colobj, tracer.mEndPos, tracer.mEndPos-osg::Vec3f(0.0f,0.0f,sStepSizeDown), collisionWorld); if(stepper.mFraction < 1.0f && getSlope(stepper.mPlaneNormal) <= sMaxSlope) { // don't allow stepping up other actors @@ -191,12 +191,12 @@ namespace MWPhysics public: - static osg::Vec3f traceDown(const MWWorld::Ptr &ptr, Actor* actor, btDynamicsWorld* dynamicsWorld, float maxHeight) + static osg::Vec3f traceDown(const MWWorld::Ptr &ptr, Actor* actor, btCollisionWorld* collisionWorld, float maxHeight) { osg::Vec3f position(ptr.getRefData().getPosition().asVec3()); ActorTracer tracer; - tracer.findGround(actor, position, position-osg::Vec3f(0,0,maxHeight), dynamicsWorld); + tracer.findGround(actor, position, position-osg::Vec3f(0,0,maxHeight), collisionWorld); if(tracer.mFraction >= 1.0f) { actor->setOnGround(false); @@ -214,7 +214,7 @@ namespace MWPhysics resultCallback1.m_collisionFilterGroup = 0xff; resultCallback1.m_collisionFilterMask = CollisionType_World|CollisionType_HeightMap; - dynamicsWorld->rayTest(from, to, resultCallback1); + collisionWorld->rayTest(from, to, resultCallback1); if (resultCallback1.hasHit() && ( (toOsg(resultCallback1.m_hitPointWorld) - tracer.mEndPos).length() > 30 || getSlope(tracer.mPlaneNormal) > sMaxSlope)) @@ -230,7 +230,7 @@ namespace MWPhysics } static osg::Vec3f move(const MWWorld::Ptr &ptr, Actor* physicActor, const osg::Vec3f &movement, float time, - bool isFlying, float waterlevel, float slowFall, btDynamicsWorld* dynamicsWorld + bool isFlying, float waterlevel, float slowFall, btCollisionWorld* collisionWorld , std::map& collisionTracker , std::map& standingCollisionTracker) { @@ -323,7 +323,7 @@ namespace MWPhysics if((newPosition - nextpos).length2() > 0.0001) { // trace to where character would go if there were no obstructions - tracer.doTrace(colobj, newPosition, nextpos, dynamicsWorld); + tracer.doTrace(colobj, newPosition, nextpos, collisionWorld); // check for obstructions if(tracer.mFraction >= 1.0f) @@ -358,12 +358,12 @@ namespace MWPhysics osg::Vec3f oldPosition = newPosition; // We hit something. Try to step up onto it. (NOTE: stepMove does not allow stepping over) // NOTE: stepMove modifies newPosition if successful - bool result = stepMove(colobj, newPosition, velocity*remainingTime, remainingTime, dynamicsWorld); + bool result = stepMove(colobj, newPosition, velocity*remainingTime, remainingTime, collisionWorld); if (!result) // to make sure the maximum stepping distance isn't framerate-dependent or movement-speed dependent { osg::Vec3f normalizedVelocity = velocity; normalizedVelocity.normalize(); - result = stepMove(colobj, newPosition, normalizedVelocity*10.f, remainingTime, dynamicsWorld); + result = stepMove(colobj, newPosition, normalizedVelocity*10.f, remainingTime, collisionWorld); } if(result) { @@ -401,7 +401,7 @@ namespace MWPhysics osg::Vec3f from = newPosition; osg::Vec3f to = newPosition - (physicActor->getOnGround() ? osg::Vec3f(0,0,sStepSizeDown+2.f) : osg::Vec3f(0,0,2.f)); - tracer.doTrace(colobj, from, to, dynamicsWorld); + tracer.doTrace(colobj, from, to, collisionWorld); if(tracer.mFraction < 1.0f && getSlope(tracer.mPlaneNormal) <= sMaxSlope && tracer.mHitObject->getBroadphaseHandle()->m_collisionFilterGroup != CollisionType_Actor) { @@ -549,7 +549,7 @@ namespace MWPhysics return mCollisionObject.get(); } - void animateCollisionShapes(btDynamicsWorld* dynamicsWorld) + void animateCollisionShapes(btCollisionWorld* collisionWorld) { if (mShapeInstance->mAnimatedShapes.empty()) return; @@ -587,7 +587,7 @@ namespace MWPhysics compound->updateChildTransform(shapeIndex, transform); } - dynamicsWorld->updateSingleAabb(mCollisionObject.get()); + collisionWorld->updateSingleAabb(mCollisionObject.get()); } private: @@ -607,33 +607,29 @@ namespace MWPhysics { mCollisionConfiguration = new btDefaultCollisionConfiguration(); mDispatcher = new btCollisionDispatcher(mCollisionConfiguration); - mSolver = new btSequentialImpulseConstraintSolver; mBroadphase = new btDbvtBroadphase(); - // Note we don't use any Dynamics at the moment - a btCollisionWorld might be sufficient? - mDynamicsWorld = new btDiscreteDynamicsWorld(mDispatcher,mBroadphase,mSolver,mCollisionConfiguration); + mCollisionWorld = new btCollisionWorld(mDispatcher, mBroadphase, mCollisionConfiguration); // Don't update AABBs of all objects every frame. Most objects in MW are static, so we don't need this. // Should a "static" object ever be moved, we have to update its AABB manually using DynamicsWorld::updateSingleAabb. - mDynamicsWorld->setForceUpdateAllAabbs(false); - - mDynamicsWorld->setGravity(btVector3(0,0,-10)); + mCollisionWorld->setForceUpdateAllAabbs(false); } PhysicsSystem::~PhysicsSystem() { if (mWaterCollisionObject.get()) - mDynamicsWorld->removeCollisionObject(mWaterCollisionObject.get()); + mCollisionWorld->removeCollisionObject(mWaterCollisionObject.get()); for (HeightFieldMap::iterator it = mHeightFields.begin(); it != mHeightFields.end(); ++it) { - mDynamicsWorld->removeCollisionObject(it->second->getCollisionObject()); + mCollisionWorld->removeCollisionObject(it->second->getCollisionObject()); delete it->second; } for (ObjectMap::iterator it = mObjects.begin(); it != mObjects.end(); ++it) { - mDynamicsWorld->removeCollisionObject(it->second->getCollisionObject()); + mCollisionWorld->removeCollisionObject(it->second->getCollisionObject()); delete it->second; } @@ -642,8 +638,7 @@ namespace MWPhysics delete it->second; } - delete mDynamicsWorld; - delete mSolver; + delete mCollisionWorld; delete mCollisionConfiguration; delete mDispatcher; delete mBroadphase; @@ -655,8 +650,8 @@ namespace MWPhysics if (mDebugDrawEnabled && !mDebugDrawer.get()) { - mDebugDrawer.reset(new MWRender::DebugDrawer(mParentNode, mDynamicsWorld)); - mDynamicsWorld->setDebugDrawer(mDebugDrawer.get()); + mDebugDrawer.reset(new MWRender::DebugDrawer(mParentNode, mCollisionWorld)); + mCollisionWorld->setDebugDrawer(mDebugDrawer.get()); mDebugDrawer->setDebugMode(mDebugDrawEnabled); } else if (mDebugDrawer.get()) @@ -727,7 +722,7 @@ namespace MWPhysics DeepestNotMeContactTestResultCallback resultCallback(me, toBullet(origin)); resultCallback.m_collisionFilterGroup = CollisionType_Actor; resultCallback.m_collisionFilterMask = CollisionType_World | CollisionType_HeightMap | CollisionType_Actor; - mDynamicsWorld->contactTest(&object, resultCallback); + mCollisionWorld->contactTest(&object, resultCallback); if (resultCallback.mObject) { @@ -761,7 +756,7 @@ namespace MWPhysics resultCallback.m_collisionFilterGroup = 0xff; resultCallback.m_collisionFilterMask = CollisionType_World | CollisionType_HeightMap; - mDynamicsWorld->rayTest(btFrom, btTo, resultCallback); + mCollisionWorld->rayTest(btFrom, btTo, resultCallback); if (resultCallback.hasHit()) { return std::make_pair(true, toOsg(resultCallback.m_hitPointWorld)); @@ -798,7 +793,7 @@ namespace MWPhysics ContactTestResultCallback resultCallback; resultCallback.m_collisionFilterGroup = collisionGroup; resultCallback.m_collisionFilterMask = collisionMask; - mDynamicsWorld->contactTest(me, resultCallback); + mCollisionWorld->contactTest(me, resultCallback); return resultCallback.mResult; } @@ -808,7 +803,7 @@ namespace MWPhysics if (found == mActors.end()) return ptr.getRefData().getPosition().asVec3(); else - return MovementSolver::traceDown(ptr, found->second, mDynamicsWorld, maxHeight); + return MovementSolver::traceDown(ptr, found->second, mCollisionWorld, maxHeight); } void PhysicsSystem::addHeightField (float* heights, int x, int y, float triSize, float sqrtVerts) @@ -816,7 +811,7 @@ namespace MWPhysics HeightField *heightfield = new HeightField(heights, x, y, triSize, sqrtVerts); mHeightFields[std::make_pair(x,y)] = heightfield; - mDynamicsWorld->addCollisionObject(heightfield->getCollisionObject(), CollisionType_HeightMap, + mCollisionWorld->addCollisionObject(heightfield->getCollisionObject(), CollisionType_HeightMap, CollisionType_Actor|CollisionType_Projectile); } @@ -825,7 +820,7 @@ namespace MWPhysics HeightFieldMap::iterator heightfield = mHeightFields.find(std::make_pair(x,y)); if(heightfield != mHeightFields.end()) { - mDynamicsWorld->removeCollisionObject(heightfield->second->getCollisionObject()); + mCollisionWorld->removeCollisionObject(heightfield->second->getCollisionObject()); delete heightfield->second; mHeightFields.erase(heightfield); } @@ -840,7 +835,7 @@ namespace MWPhysics Object *obj = new Object(ptr, shapeInstance); mObjects.insert(std::make_pair(ptr, obj)); - mDynamicsWorld->addCollisionObject(obj->getCollisionObject(), CollisionType_World, + mCollisionWorld->addCollisionObject(obj->getCollisionObject(), CollisionType_World, CollisionType_Actor|CollisionType_HeightMap|CollisionType_Projectile); } @@ -849,7 +844,7 @@ namespace MWPhysics ObjectMap::iterator found = mObjects.find(ptr); if (found != mObjects.end()) { - mDynamicsWorld->removeCollisionObject(found->second->getCollisionObject()); + mCollisionWorld->removeCollisionObject(found->second->getCollisionObject()); delete found->second; mObjects.erase(found); } @@ -898,14 +893,14 @@ namespace MWPhysics if (found != mObjects.end()) { found->second->setScale(scale); - mDynamicsWorld->updateSingleAabb(found->second->getCollisionObject()); + mCollisionWorld->updateSingleAabb(found->second->getCollisionObject()); return; } ActorMap::iterator foundActor = mActors.find(ptr); if (foundActor != mActors.end()) { foundActor->second->updateScale(); - // no aabb update needed (DISABLE_DEACTIVATION) + mCollisionWorld->updateSingleAabb(foundActor->second->getCollisionObject()); return; } } @@ -916,14 +911,14 @@ namespace MWPhysics if (found != mObjects.end()) { found->second->setRotation(toBullet(ptr.getRefData().getBaseNode()->getAttitude())); - mDynamicsWorld->updateSingleAabb(found->second->getCollisionObject()); + mCollisionWorld->updateSingleAabb(found->second->getCollisionObject()); return; } ActorMap::iterator foundActor = mActors.find(ptr); if (foundActor != mActors.end()) { foundActor->second->updateRotation(); - // no aabb update needed (DISABLE_DEACTIVATION) + mCollisionWorld->updateSingleAabb(foundActor->second->getCollisionObject()); return; } } @@ -934,14 +929,14 @@ namespace MWPhysics if (found != mObjects.end()) { found->second->setOrigin(toBullet(ptr.getRefData().getPosition().asVec3())); - mDynamicsWorld->updateSingleAabb(found->second->getCollisionObject()); + mCollisionWorld->updateSingleAabb(found->second->getCollisionObject()); return; } ActorMap::iterator foundActor = mActors.find(ptr); if (foundActor != mActors.end()) { foundActor->second->updatePosition(); - // no aabb update needed (DISABLE_DEACTIVATION) + mCollisionWorld->updateSingleAabb(foundActor->second->getCollisionObject()); return; } } @@ -950,7 +945,7 @@ namespace MWPhysics { osg::ref_ptr shapeInstance = mShapeManager->createInstance(mesh); - Actor* actor = new Actor(ptr, shapeInstance, mDynamicsWorld); + Actor* actor = new Actor(ptr, shapeInstance, mCollisionWorld); mActors.insert(std::make_pair(ptr, actor)); } @@ -1032,7 +1027,7 @@ namespace MWPhysics osg::Vec3f newpos = MovementSolver::move(iter->first, physicActor, iter->second, mTimeAccum, world->isFlying(iter->first), - waterlevel, slowFall, mDynamicsWorld, mCollisions, mStandingCollisions); + waterlevel, slowFall, mCollisionWorld, mCollisions, mStandingCollisions); float heightDiff = newpos.z() - oldHeight; @@ -1052,10 +1047,10 @@ namespace MWPhysics void PhysicsSystem::stepSimulation(float dt) { for (ObjectMap::iterator it = mObjects.begin(); it != mObjects.end(); ++it) - it->second->animateCollisionShapes(mDynamicsWorld); + it->second->animateCollisionShapes(mCollisionWorld); - // We have nothing to simulate, but character controllers aren't working without this call. Might be related to updating AABBs. - mDynamicsWorld->stepSimulation(static_cast(dt), 1, 1 / 60.0f); + CProfileManager::Reset(); + CProfileManager::Increment_Frame_Counter(); if (mDebugDrawer.get()) mDebugDrawer->step(); @@ -1153,7 +1148,7 @@ namespace MWPhysics { if (mWaterCollisionObject.get()) { - mDynamicsWorld->removeCollisionObject(mWaterCollisionObject.get()); + mCollisionWorld->removeCollisionObject(mWaterCollisionObject.get()); } if (!mWaterEnabled) @@ -1162,7 +1157,7 @@ namespace MWPhysics mWaterCollisionObject.reset(new btCollisionObject()); mWaterCollisionShape.reset(new btStaticPlaneShape(btVector3(0,0,1), mWaterHeight)); mWaterCollisionObject->setCollisionShape(mWaterCollisionShape.get()); - mDynamicsWorld->addCollisionObject(mWaterCollisionObject.get(), CollisionType_Water, + mCollisionWorld->addCollisionObject(mWaterCollisionObject.get(), CollisionType_Water, CollisionType_Actor); } } diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index 75666acd7..841085f47 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -31,8 +31,7 @@ namespace Resource class ResourceSystem; } -class btSequentialImpulseConstraintSolver; -class btDiscreteDynamicsWorld; +class btCollisionWorld; class btBroadphaseInterface; class btDefaultCollisionConfiguration; class btCollisionDispatcher; @@ -127,9 +126,8 @@ namespace MWPhysics btBroadphaseInterface* mBroadphase; btDefaultCollisionConfiguration* mCollisionConfiguration; - btSequentialImpulseConstraintSolver* mSolver; btCollisionDispatcher* mDispatcher; - btDiscreteDynamicsWorld* mDynamicsWorld; + btCollisionWorld* mCollisionWorld; std::auto_ptr mShapeManager; diff --git a/apps/openmw/mwphysics/trace.cpp b/apps/openmw/mwphysics/trace.cpp index 79d4de1a0..94434b856 100644 --- a/apps/openmw/mwphysics/trace.cpp +++ b/apps/openmw/mwphysics/trace.cpp @@ -2,7 +2,7 @@ #include -#include +#include #include #include @@ -50,7 +50,7 @@ protected: }; -void ActorTracer::doTrace(btCollisionObject *actor, const osg::Vec3f& start, const osg::Vec3f& end, btDynamicsWorld* world) +void ActorTracer::doTrace(btCollisionObject *actor, const osg::Vec3f& start, const osg::Vec3f& end, btCollisionWorld* world) { const btVector3 btstart = toBullet(start); const btVector3 btend = toBullet(end); @@ -89,7 +89,7 @@ void ActorTracer::doTrace(btCollisionObject *actor, const osg::Vec3f& start, con } } -void ActorTracer::findGround(const Actor* actor, const osg::Vec3f& start, const osg::Vec3f& end, btDynamicsWorld* world) +void ActorTracer::findGround(const Actor* actor, const osg::Vec3f& start, const osg::Vec3f& end, btCollisionWorld* world) { const btVector3 btstart(start.x(), start.y(), start.z()+1.0f); const btVector3 btend(end.x(), end.y(), end.z()+1.0f); diff --git a/apps/openmw/mwphysics/trace.h b/apps/openmw/mwphysics/trace.h index 02f9ebdd1..ef1a24d44 100644 --- a/apps/openmw/mwphysics/trace.h +++ b/apps/openmw/mwphysics/trace.h @@ -4,7 +4,7 @@ #include class btCollisionObject; -class btDynamicsWorld; +class btCollisionWorld; namespace MWPhysics @@ -19,8 +19,8 @@ namespace MWPhysics float mFraction; - void doTrace(btCollisionObject *actor, const osg::Vec3f& start, const osg::Vec3f& end, btDynamicsWorld* world); - void findGround(const Actor* actor, const osg::Vec3f& start, const osg::Vec3f& end, btDynamicsWorld* world); + void doTrace(btCollisionObject *actor, const osg::Vec3f& start, const osg::Vec3f& end, btCollisionWorld* world); + void findGround(const Actor* actor, const osg::Vec3f& start, const osg::Vec3f& end, btCollisionWorld* world); }; } diff --git a/apps/openmw/mwrender/bulletdebugdraw.cpp b/apps/openmw/mwrender/bulletdebugdraw.cpp index 8ac8e3121..c6d7935c5 100644 --- a/apps/openmw/mwrender/bulletdebugdraw.cpp +++ b/apps/openmw/mwrender/bulletdebugdraw.cpp @@ -2,7 +2,7 @@ #include -#include +#include #include #include @@ -21,7 +21,7 @@ namespace namespace MWRender { -DebugDrawer::DebugDrawer(osg::ref_ptr parentNode, btDynamicsWorld *world) +DebugDrawer::DebugDrawer(osg::ref_ptr parentNode, btCollisionWorld *world) : mParentNode(parentNode), mWorld(world), mDebugOn(true) diff --git a/apps/openmw/mwrender/bulletdebugdraw.hpp b/apps/openmw/mwrender/bulletdebugdraw.hpp index 66af2f565..1bccc20bd 100644 --- a/apps/openmw/mwrender/bulletdebugdraw.hpp +++ b/apps/openmw/mwrender/bulletdebugdraw.hpp @@ -7,7 +7,7 @@ #include -class btDynamicsWorld; +class btCollisionWorld; namespace osg { @@ -23,7 +23,7 @@ class DebugDrawer : public btIDebugDraw { protected: osg::ref_ptr mParentNode; - btDynamicsWorld *mWorld; + btCollisionWorld *mWorld; osg::ref_ptr mGeode; osg::ref_ptr mGeometry; osg::ref_ptr mVertices; @@ -36,7 +36,7 @@ protected: public: - DebugDrawer(osg::ref_ptr parentNode, btDynamicsWorld *world); + DebugDrawer(osg::ref_ptr parentNode, btCollisionWorld *world); ~DebugDrawer(); void step(); diff --git a/cmake/FindBullet.cmake b/cmake/FindBullet.cmake index b75f3105a..5204c00ce 100644 --- a/cmake/FindBullet.cmake +++ b/cmake/FindBullet.cmake @@ -54,8 +54,8 @@ find_path(BULLET_INCLUDE_DIR NAMES btBulletCollisionCommon.h # Find the libraries -_FIND_BULLET_LIBRARY(BULLET_DYNAMICS_LIBRARY BulletDynamics) -_FIND_BULLET_LIBRARY(BULLET_DYNAMICS_LIBRARY_DEBUG BulletDynamics_Debug BulletDynamics_d) +#_FIND_BULLET_LIBRARY(BULLET_DYNAMICS_LIBRARY BulletDynamics) +#_FIND_BULLET_LIBRARY(BULLET_DYNAMICS_LIBRARY_DEBUG BulletDynamics_Debug BulletDynamics_d) _FIND_BULLET_LIBRARY(BULLET_COLLISION_LIBRARY BulletCollision) _FIND_BULLET_LIBRARY(BULLET_COLLISION_LIBRARY_DEBUG BulletCollision_Debug BulletCollision_d) _FIND_BULLET_LIBRARY(BULLET_MATH_LIBRARY BulletMath LinearMath) @@ -71,7 +71,7 @@ FIND_PACKAGE_HANDLE_STANDARD_ARGS(Bullet DEFAULT_MSG set(BULLET_INCLUDE_DIRS ${BULLET_INCLUDE_DIR}) if(BULLET_FOUND) - _BULLET_APPEND_LIBRARIES(BULLET_LIBRARIES BULLET_DYNAMICS_LIBRARY) + #_BULLET_APPEND_LIBRARIES(BULLET_LIBRARIES BULLET_DYNAMICS_LIBRARY) _BULLET_APPEND_LIBRARIES(BULLET_LIBRARIES BULLET_COLLISION_LIBRARY) _BULLET_APPEND_LIBRARIES(BULLET_LIBRARIES BULLET_MATH_LIBRARY) endif() From 00c165d3a5e1ef5b79c95d54e6edb8421e1ae7c9 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Thu, 28 May 2015 08:44:17 +1000 Subject: [PATCH 1285/3725] Add user preference option to check unused or redundant pathgrid points. Also resolve namespace clash issue in osx. --- apps/opencs/model/settings/usersettings.cpp | 7 ++++++ apps/opencs/model/tools/pathgridcheck.cpp | 24 ++++++++++++--------- apps/opencs/model/tools/pathgridcheck.hpp | 14 ++++++++++-- 3 files changed, 33 insertions(+), 12 deletions(-) diff --git a/apps/opencs/model/settings/usersettings.cpp b/apps/opencs/model/settings/usersettings.cpp index ea002c5ed..ea75fd6d9 100644 --- a/apps/opencs/model/settings/usersettings.cpp +++ b/apps/opencs/model/settings/usersettings.cpp @@ -264,6 +264,13 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() monoFont->setToolTip ("Whether to use monospaced fonts on script edit subview."); } + declareSection ("verifier", "Verifier"); + { + Setting *extraPathgrid = createSetting (Type_CheckBox, "pathgrid-extra-check", "Pathgrid: Extra Check"); + extraPathgrid->setDefaultValue ("false"); + extraPathgrid->setToolTip ("Additional checks for orphaned or duplicated pathgrid points"); + } + { /****************************************************************** * There are three types of values: diff --git a/apps/opencs/model/tools/pathgridcheck.cpp b/apps/opencs/model/tools/pathgridcheck.cpp index 8f22cc8cd..c436cfe04 100644 --- a/apps/opencs/model/tools/pathgridcheck.cpp +++ b/apps/opencs/model/tools/pathgridcheck.cpp @@ -8,15 +8,7 @@ #include "../world/subcellcollection.hpp" #include "../world/pathgrid.hpp" -namespace -{ - struct Point - { - unsigned char mConnectionNum; - std::vector mOtherIndex; - Point() : mConnectionNum(0), mOtherIndex(0) {} - }; -} +#include "../settings/usersettings.hpp" CSMTools::PathgridCheckStage::PathgridCheckStage (const CSMWorld::SubCellCollection& pathgrids) : mPathgrids (pathgrids) @@ -29,6 +21,12 @@ int CSMTools::PathgridCheckStage::setup() void CSMTools::PathgridCheckStage::perform (int stage, CSMDoc::Messages& messages) { + // NOTE: This is horribly inefficient but in order to use signals the entire Stage class + // hierarchy needs to be braught under Qt which seems like an overkill for a small + // performance gain during verify operations + CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); + bool extraCheck = userSettings.setting ("verifier/pathgrid-extra-check", QString ("false"))=="true"; + const CSMWorld::Record& record = mPathgrids.getRecord (stage); if (record.isDeleted()) @@ -44,7 +42,7 @@ void CSMTools::PathgridCheckStage::perform (int stage, CSMDoc::Messages& message else if (pathgrid.mData.mS2 > static_cast(pathgrid.mPoints.size())) messages.push_back (std::make_pair (id, pathgrid.mId + " has more points than expected")); - std::vector pointList(pathgrid.mPoints.size()); + std::vector pointList(pathgrid.mPoints.size()); std::vector duplList; for (unsigned int i = 0; i < pathgrid.mEdges.size(); ++i) @@ -115,6 +113,9 @@ void CSMTools::PathgridCheckStage::perform (int stage, CSMDoc::Messages& message } } + if (!extraCheck) + continue; + // check duplicate points // FIXME: how to do this efficiently? for (unsigned int j = 0; j < pathgrid.mPoints.size(); ++j) @@ -143,6 +144,9 @@ void CSMTools::PathgridCheckStage::perform (int stage, CSMDoc::Messages& message } } + if (!extraCheck) + return; + // check pathgrid points that are not connected to anything for (unsigned int i = 0; i < pointList.size(); ++i) { diff --git a/apps/opencs/model/tools/pathgridcheck.hpp b/apps/opencs/model/tools/pathgridcheck.hpp index c90dbc8ed..603235552 100644 --- a/apps/opencs/model/tools/pathgridcheck.hpp +++ b/apps/opencs/model/tools/pathgridcheck.hpp @@ -14,13 +14,23 @@ namespace CSMWorld namespace CSMTools { + + struct Point + { + unsigned char mConnectionNum; + std::vector mOtherIndex; + Point() : mConnectionNum(0), mOtherIndex(0) {} + }; + class PathgridCheckStage : public CSMDoc::Stage { - const CSMWorld::SubCellCollection >& mPathgrids; + const CSMWorld::SubCellCollection >& mPathgrids; public: - PathgridCheckStage (const CSMWorld::SubCellCollection >& pathgrids); + PathgridCheckStage (const CSMWorld::SubCellCollection >& pathgrids); virtual int setup(); From 025a1a7866b8333651bff57b301813c3e7ebf609 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 28 May 2015 02:34:38 +0200 Subject: [PATCH 1286/3725] Restore savegame screenshot display --- apps/openmw/mwgui/savegamedialog.cpp | 62 +++++++++++++++++----------- apps/openmw/mwgui/savegamedialog.hpp | 1 + components/CMakeLists.txt | 2 +- components/files/memorystream.hpp | 31 ++++++++++++++ 4 files changed, 70 insertions(+), 26 deletions(-) create mode 100644 components/files/memorystream.hpp diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index 980afdfae..ab8d93a87 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -1,18 +1,21 @@ #include "savegamedialog.hpp" -#include "widgets.hpp" - -#include -#include #include #include #include #include +#include +#include + +#include + #include #include +#include + #include "../mwbase/statemanager.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -22,6 +25,7 @@ #include "../mwstate/character.hpp" #include "confirmationdialog.hpp" +#include "widgets.hpp" namespace MWGui { @@ -358,30 +362,38 @@ namespace MWGui << " " << hour << " " << (pm ? "#{sSaveMenuHelp05}" : "#{sSaveMenuHelp04}"); mInfoText->setCaptionWithReplacing(text.str()); -#if 0 + + // Decode screenshot - std::vector data = mCurrentSlot->mProfile.mScreenshot; // MemoryDataStream doesn't work with const data :( - Ogre::DataStreamPtr stream(new Ogre::MemoryDataStream(&data[0], data.size())); - Ogre::Image image; - image.load(stream, "jpg"); - - const std::string textureName = "@savegame_screenshot"; - Ogre::TexturePtr texture; - texture = Ogre::TextureManager::getSingleton().getByName(textureName); - mScreenshot->setImageTexture(""); - if (texture.isNull()) + const std::vector& data = mCurrentSlot->mProfile.mScreenshot; + Files::IMemStream instream (&data[0], data.size()); + + osgDB::ReaderWriter* readerwriter = osgDB::Registry::instance()->getReaderWriterForExtension("jpg"); + if (!readerwriter) + { + std::cerr << "Can't open savegame screenshot, no jpg readerwriter found" << std::endl; + return; + } + + osgDB::ReaderWriter::ReadResult result = readerwriter->readImage(instream); + if (!result.success()) { - texture = Ogre::TextureManager::getSingleton().createManual(textureName, - Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - Ogre::TEX_TYPE_2D, - image.getWidth(), image.getHeight(), 0, Ogre::PF_BYTE_RGBA, Ogre::TU_DYNAMIC_WRITE_ONLY); + std::cerr << "Failed to read savegame screenshot: " << result.message() << std::endl; + return; } - texture->unload(); - texture->setWidth(image.getWidth()); - texture->setHeight(image.getHeight()); - texture->loadImage(image); - mScreenshot->setImageTexture(textureName); -#endif + osg::ref_ptr texture (new osg::Texture2D); + texture->setImage(result.getImage()); + texture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); + texture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); + texture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR); + texture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); + texture->setResizeNonPowerOfTwoHint(false); + texture->setUnRefImageDataAfterApply(true); + + mScreenshotTexture.reset(new osgMyGUI::OSGTexture(texture)); + + mScreenshot->setRenderItemTexture(mScreenshotTexture.get()); + mScreenshot->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 1.f, 1.f, 0.f)); } } diff --git a/apps/openmw/mwgui/savegamedialog.hpp b/apps/openmw/mwgui/savegamedialog.hpp index 2192adbde..6a9e59cc6 100644 --- a/apps/openmw/mwgui/savegamedialog.hpp +++ b/apps/openmw/mwgui/savegamedialog.hpp @@ -48,6 +48,7 @@ namespace MWGui void fillSaveList(); + std::auto_ptr mScreenshotTexture; MyGUI::ImageBox* mScreenshot; bool mSaving; diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index b800da701..6a5b7f59a 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -85,7 +85,7 @@ IF(NOT WIN32 AND NOT APPLE) ENDIF() add_component_dir (files linuxpath androidpath windowspath macospath fixedpath multidircollection collections configurationmanager - lowlevelfile constrainedfilestream + lowlevelfile constrainedfilestream memorystream ) add_component_dir (compiler diff --git a/components/files/memorystream.hpp b/components/files/memorystream.hpp new file mode 100644 index 000000000..9a3510044 --- /dev/null +++ b/components/files/memorystream.hpp @@ -0,0 +1,31 @@ +#ifndef OPENMW_COMPONENTS_FILES_MEMORYSTREAM_H +#define OPENMW_COMPONENTS_FILES_MEMORYSTREAM_H + +#include + +namespace Files +{ + + struct MemBuf : std::streambuf + { + MemBuf(char const* buffer, size_t size) + { + // a streambuf isn't specific to istreams, so we need a non-const pointer :/ + char* nonconstBuffer = (const_cast(buffer)); + this->setg(nonconstBuffer, nonconstBuffer, nonconstBuffer + size); + } + }; + + /// @brief A variant of std::istream that reads from a constant in-memory buffer. + struct IMemStream: virtual MemBuf, std::istream + { + IMemStream(char const* buffer, size_t size) + : MemBuf(buffer, size) + , std::istream(static_cast(this)) + { + } + }; + +} + +#endif From 6555ee8d80bf647e5982318a475ced750bf8e58f Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 28 May 2015 02:37:35 +0200 Subject: [PATCH 1287/3725] Minor include cleanup --- apps/openmw/mwgui/quickkeysmenu.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index 0c462c67d..cd6e2405c 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -19,8 +20,6 @@ #include "../mwmechanics/creaturestats.hpp" #include "../mwgui/inventorywindow.hpp" -#include "../mwgui/bookwindow.hpp" -#include "../mwgui/scrollwindow.hpp" #include "windowmanagerimp.hpp" #include "itemselection.hpp" From 8b3054aa8be0e62a4daff170922a97644c055eca Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 28 May 2015 02:45:38 +0200 Subject: [PATCH 1288/3725] Fix for player collision cleanup issue --- apps/openmw/mwworld/worldimp.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index e20904d71..38353fa68 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2107,6 +2107,7 @@ namespace MWWorld { // Remove the old CharacterController MWBase::Environment::get().getMechanicsManager()->remove(getPlayerPtr()); + mPhysics->remove(getPlayerPtr()); mPlayer->set(player); } @@ -2128,6 +2129,7 @@ namespace MWWorld std::string model = getPlayerPtr().getClass().getModel(getPlayerPtr()); model = Misc::ResourceHelpers::correctActorModelPath(model, mResourceSystem->getVFS()); + mPhysics->remove(getPlayerPtr()); mPhysics->addActor(getPlayerPtr(), model); } From 5628a2b823dfdc2bc812fff22b7d3b52e62e9451 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 28 May 2015 03:47:53 +0200 Subject: [PATCH 1289/3725] Camera zoom fix --- apps/openmw/mwrender/camera.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/camera.cpp b/apps/openmw/mwrender/camera.cpp index 3982e5ad4..a945a171e 100644 --- a/apps/openmw/mwrender/camera.cpp +++ b/apps/openmw/mwrender/camera.cpp @@ -319,9 +319,9 @@ namespace MWRender if (dist >= mFurthest) { dist = mFurthest; } else if (!override && dist < 10.f) { - dist = -10.f; + dist = 10.f; } else if (override && dist <= mNearest) { - dist = -mNearest; + dist = mNearest; mIsNearest = true; } mCameraDistance = dist; From c811ac6afe0bf4497812a8471be38990f5a0fcd7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 28 May 2015 03:50:44 +0200 Subject: [PATCH 1290/3725] Port fog of war Not optimized yet, need to work on fog texture's DataVariance. --- apps/openmw/mwbase/windowmanager.hpp | 1 + apps/openmw/mwgui/mapwindow.cpp | 36 ++- apps/openmw/mwgui/mapwindow.hpp | 4 +- apps/openmw/mwgui/windowmanagerimp.cpp | 5 + apps/openmw/mwgui/windowmanagerimp.hpp | 1 + apps/openmw/mwrender/localmap.cpp | 363 +++++++++++++----------- apps/openmw/mwrender/localmap.hpp | 56 ++-- apps/openmw/mwstate/statemanagerimp.cpp | 2 + apps/openmw/mwworld/worldimp.cpp | 4 +- 9 files changed, 267 insertions(+), 205 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 37112477e..f8bf157c2 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -355,6 +355,7 @@ namespace MWBase virtual void requestMap(std::set cells) = 0; virtual void removeCell(MWWorld::CellStore* cell) = 0; + virtual void writeFog(MWWorld::CellStore* cell) = 0; }; } diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 95de175a3..8d2aaf04a 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -216,21 +216,37 @@ namespace MWGui void LocalMapBase::applyFogOfWar() { -#if 0 + TextureVector fogTextures; for (int mx=0; mx<3; ++mx) { for (int my=0; my<3; ++my) { - std::string image = mPrefix+"_"+ MyGUI::utility::toString(mCurX + (mx-1)) + "_" - + MyGUI::utility::toString(mCurY + (-1*(my-1))); + int x = mCurX + (mx-1); + int y = mCurY + (-1*(my-1)); MyGUI::ImageBox* fog = mFogWidgets[my + 3*mx]; - fog->setImageTexture(mFogOfWar ? - ((MyGUI::RenderManager::getInstance().getTexture(image+"_fog") != 0) ? image+"_fog" - : "black" ) - : ""); + + if (!mFogOfWar) + { + fog->setImageTexture(""); + continue; + } + + osg::ref_ptr tex = mLocalMapRender->getFogOfWarTexture(x, y); + if (tex) + { + boost::shared_ptr myguitex (new osgMyGUI::OSGTexture(tex)); + fog->setRenderItemTexture(myguitex.get()); + fog->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 0.f, 1.f, 1.f)); + fogTextures.push_back(myguitex); + } + else + fog->setImageTexture("black"); } } -#endif + // Move the textures we just set into mFogTextures, and move the previous textures into fogTextures, for deletion when this function ends. + // Note, above we need to ensure that all widgets are getting a new texture set, lest we delete textures that are still in use. + mFogTextures.swap(fogTextures); + redraw(); } @@ -344,7 +360,7 @@ namespace MWGui mDoorMarkerWidgets.clear(); // Update the map textures - std::vector > textures; + TextureVector textures; for (int mx=0; mx<3; ++mx) { for (int my=0; my<3; ++my) @@ -354,7 +370,7 @@ namespace MWGui MyGUI::ImageBox* box = mMapWidgets[my + 3*mx]; - osg::ref_ptr texture = mLocalMapRender->getMapTexture(mInterior, mapX, mapY); + osg::ref_ptr texture = mLocalMapRender->getMapTexture(mapX, mapY); if (texture) { boost::shared_ptr guiTex (new osgMyGUI::OSGTexture(texture)); diff --git a/apps/openmw/mwgui/mapwindow.hpp b/apps/openmw/mwgui/mapwindow.hpp index 92cd880f4..b44b545d2 100644 --- a/apps/openmw/mwgui/mapwindow.hpp +++ b/apps/openmw/mwgui/mapwindow.hpp @@ -106,7 +106,9 @@ namespace MWGui std::vector mMapWidgets; std::vector mFogWidgets; - std::vector > mMapTextures; + typedef std::vector > TextureVector; + TextureVector mMapTextures; + TextureVector mFogTextures; // Keep track of created marker widgets, just to easily remove them later. std::vector mDoorMarkerWidgets; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index e4ecdad53..88b0bd321 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -2016,4 +2016,9 @@ namespace MWGui mLocalMapRender->removeCell(cell); } + void WindowManager::writeFog(MWWorld::CellStore *cell) + { + mLocalMapRender->saveFogOfWar(cell); + } + } diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index c0184d4b6..c275a9f62 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -368,6 +368,7 @@ namespace MWGui void requestMap(std::set cells); void removeCell(MWWorld::CellStore* cell); + void writeFog(MWWorld::CellStore* cell); private: Resource::ResourceSystem* mResourceSystem; diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 0da14f702..0e7256345 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -1,16 +1,20 @@ #include "localmap.hpp" #include +#include #include #include #include +#include + #include #include #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -44,6 +48,11 @@ namespace MWRender::LocalMap* mParent; }; + float square(float val) + { + return val*val; + } + } namespace MWRender @@ -81,47 +90,37 @@ const osg::Vec2f LocalMap::rotatePoint(const osg::Vec2f& point, const osg::Vec2f void LocalMap::clear() { + mSegments.clear(); } void LocalMap::saveFogOfWar(MWWorld::CellStore* cell) { - /* if (!mInterior) { - std::string textureName = "Cell_"+coordStr(cell->getCell()->getGridX(), cell->getCell()->getGridY())+"_fog"; + const MapSegment& segment = mSegments[std::make_pair(cell->getCell()->getGridX(), cell->getCell()->getGridY())]; + std::auto_ptr fog (new ESM::FogState()); fog->mFogTextures.push_back(ESM::FogTexture()); - TexturePtr tex = TextureManager::getSingleton().getByName(textureName); - if (tex.isNull()) - return; - - Ogre::Image image; - tex->load(); - tex->convertToImage(image); - - Ogre::DataStreamPtr encoded = image.encode("tga"); - fog->mFogTextures.back().mImageData.resize(encoded->size()); - encoded->read(&fog->mFogTextures.back().mImageData[0], encoded->size()); + segment.saveFogOfWar(fog->mFogTextures.back()); cell->setFog(fog.release()); } else { - Vector2 min(mBounds.getMinimum().x, mBounds.getMinimum().y); - Vector2 max(mBounds.getMaximum().x, mBounds.getMaximum().y); - Vector2 length = max-min; - const int segsX = static_cast(std::ceil(length.x / mMapWorldSize)); - const int segsY = static_cast(std::ceil(length.y / mMapWorldSize)); - - mInteriorName = cell->getCell()->mName; + // FIXME: segmenting code duplicated from requestMap + osg::Vec2f min(mBounds.xMin(), mBounds.yMin()); + osg::Vec2f max(mBounds.xMax(), mBounds.yMax()); + osg::Vec2f length = max-min; + const int segsX = static_cast(std::ceil(length.x() / mMapWorldSize)); + const int segsY = static_cast(std::ceil(length.y() / mMapWorldSize)); std::auto_ptr fog (new ESM::FogState()); - fog->mBounds.mMinX = mBounds.getMinimum().x; - fog->mBounds.mMaxX = mBounds.getMaximum().x; - fog->mBounds.mMinY = mBounds.getMinimum().y; - fog->mBounds.mMaxY = mBounds.getMaximum().y; + fog->mBounds.mMinX = mBounds.xMin(); + fog->mBounds.mMaxX = mBounds.xMax(); + fog->mBounds.mMinY = mBounds.yMin(); + fog->mBounds.mMaxY = mBounds.yMax(); fog->mNorthMarkerAngle = mAngle; fog->mFogTextures.reserve(segsX*segsY); @@ -130,21 +129,11 @@ void LocalMap::saveFogOfWar(MWWorld::CellStore* cell) { for (int y=0; ygetCell()->mName + "_" + coordStr(x,y) + "_fog"; - - TexturePtr tex = TextureManager::getSingleton().getByName(textureName); - if (tex.isNull()) - return; - - Ogre::Image image; - tex->load(); - tex->convertToImage(image); + const MapSegment& segment = mSegments[std::make_pair(x,y)]; fog->mFogTextures.push_back(ESM::FogTexture()); - Ogre::DataStreamPtr encoded = image.encode("tga"); - fog->mFogTextures.back().mImageData.resize(encoded->size()); - encoded->read(&fog->mFogTextures.back().mImageData[0], encoded->size()); + segment.saveFogOfWar(fog->mFogTextures.back()); fog->mFogTextures.back().mX = x; fog->mFogTextures.back().mY = y; @@ -153,7 +142,6 @@ void LocalMap::saveFogOfWar(MWWorld::CellStore* cell) cell->setFog(fog.release()); } - */ } osg::ref_ptr LocalMap::createOrthographicCamera(float x, float y, float width, float height, const osg::Vec3d& upVector, float zmin, float zmax) @@ -221,7 +209,9 @@ void LocalMap::setupRenderToTexture(osg::ref_ptr camera, int x, int camera->addChild(mSceneRoot); mRoot->addChild(camera); mActiveCameras.push_back(camera); - mTextures[std::make_pair(x, y)] = texture; + + MapSegment& segment = mSegments[std::make_pair(x, y)]; + segment.mMapTexture = texture; } void LocalMap::requestMap(std::set cells) @@ -238,19 +228,30 @@ void LocalMap::requestMap(std::set cells) void LocalMap::removeCell(MWWorld::CellStore *cell) { + saveFogOfWar(cell); + if (cell->isExterior()) - mTextures.erase(std::make_pair(cell->getCell()->getGridX(), cell->getCell()->getGridY())); + mSegments.erase(std::make_pair(cell->getCell()->getGridX(), cell->getCell()->getGridY())); + else + mSegments.clear(); +} + +osg::ref_ptr LocalMap::getMapTexture(int x, int y) +{ + SegmentMap::iterator found = mSegments.find(std::make_pair(x, y)); + if (found == mSegments.end()) + return osg::ref_ptr(); else - mTextures.clear(); + return found->second.mMapTexture; } -osg::ref_ptr LocalMap::getMapTexture(bool interior, int x, int y) +osg::ref_ptr LocalMap::getFogOfWarTexture(int x, int y) { - TextureMap::iterator found = mTextures.find(std::make_pair(x, y)); - if (found == mTextures.end()) + SegmentMap::iterator found = mSegments.find(std::make_pair(x, y)); + if (found == mSegments.end()) return osg::ref_ptr(); else - return found->second; + return found->second.mFogOfWarTexture; } void LocalMap::markForRemoval(osg::Camera *cam) @@ -277,7 +278,6 @@ void LocalMap::cleanupCameras() mRoot->removeChild(*it); } - mCamerasPendingRemoval.clear(); } @@ -296,15 +296,11 @@ void LocalMap::requestExteriorMap(MWWorld::CellStore* cell) osg::Vec3d(0,1,0), zmin, zmax); setupRenderToTexture(camera, cell->getCell()->getGridX(), cell->getCell()->getGridY()); - /* - if (mBuffers.find(name) == mBuffers.end()) - { - if (cell->getFog()) - loadFogOfWar(name, cell->getFog()->mFogTextures.back()); - else - createFogOfWar(name); - } - */ + MapSegment& segment = mSegments[std::make_pair(cell->getCell()->getGridX(), cell->getCell()->getGridY())]; + if (cell->getFog()) + segment.loadFogOfWar(cell->getFog()->mFogTextures.back()); + else + segment.initFogOfWar(); } void LocalMap::requestInteriorMap(MWWorld::CellStore* cell) @@ -361,20 +357,19 @@ void LocalMap::requestInteriorMap(MWWorld::CellStore* cell) // If they changed by too much (for bounds, < padding is considered acceptable) then parts of the interior might not // be covered by the map anymore. // The following code detects this, and discards the CellStore's fog state if it needs to. - /* if (cell->getFog()) { ESM::FogState* fog = cell->getFog(); - Ogre::Vector3 newMin (fog->mBounds.mMinX, fog->mBounds.mMinY, zMin); - Ogre::Vector3 newMax (fog->mBounds.mMaxX, fog->mBounds.mMaxY, zMax); + osg::Vec3f newMin (fog->mBounds.mMinX, fog->mBounds.mMinY, zMin); + osg::Vec3f newMax (fog->mBounds.mMaxX, fog->mBounds.mMaxY, zMax); - Ogre::Vector3 minDiff = newMin - mBounds.getMinimum(); - Ogre::Vector3 maxDiff = newMax - mBounds.getMaximum(); + osg::Vec3f minDiff = newMin - mBounds._min; + osg::Vec3f maxDiff = newMax - mBounds._max; - if (std::abs(minDiff.x) > padding || std::abs(minDiff.y) > padding - || std::abs(maxDiff.x) > padding || std::abs(maxDiff.y) > padding - || std::abs(mAngle - fog->mNorthMarkerAngle) > Ogre::Degree(5).valueRadians()) + if (std::abs(minDiff.x()) > padding || std::abs(minDiff.y()) > padding + || std::abs(maxDiff.x()) > padding || std::abs(maxDiff.y()) > padding + || std::abs(mAngle - fog->mNorthMarkerAngle) > osg::DegreesToRadians(5.f)) { // Nuke it cell->setFog(NULL); @@ -382,11 +377,10 @@ void LocalMap::requestInteriorMap(MWWorld::CellStore* cell) else { // Looks sane, use it - mBounds = Ogre::AxisAlignedBox(newMin, newMax); + mBounds = osg::BoundingBox(newMin, newMax); mAngle = fog->mNorthMarkerAngle; } } - */ osg::Vec2f min(mBounds.xMin(), mBounds.yMin()); osg::Vec2f max(mBounds.xMax(), mBounds.yMax()); @@ -399,6 +393,7 @@ void LocalMap::requestInteriorMap(MWWorld::CellStore* cell) const int segsX = static_cast(std::ceil(length.x() / mMapWorldSize)); const int segsY = static_cast(std::ceil(length.y() / mMapWorldSize)); + int i = 0; for (int x=0; xgetFog()) - createFogOfWar(texturePrefix); + segment.initFogOfWar(); else { ESM::FogState* fog = cell->getFog(); // We are using the same bounds and angle as we were using when the textures were originally made. Segments should come out the same. if (i >= int(fog->mFogTextures.size())) - throw std::runtime_error("fog texture count mismatch"); + { + std::cout << "Warning: fog texture count mismatch" << std::endl; + break; + } - ESM::FogTexture& esm = fog->mFogTextures[i]; - loadFogOfWar(texturePrefix, esm); + segment.loadFogOfWar(fog->mFogTextures[i]); } - */ + ++i; } } } -/* -void LocalMap::createFogOfWar(const std::string& texturePrefix) -{ - const std::string texName = texturePrefix + "_fog"; - TexturePtr tex = createFogOfWarTexture(texName); - - // create a buffer to use for dynamic operations - std::vector buffer; - - // initialize to (0, 0, 0, 1) - buffer.resize(sFogOfWarResolution*sFogOfWarResolution, 0xFF000000); - - // upload to the texture - tex->load(); - memcpy(tex->getBuffer()->lock(HardwareBuffer::HBL_DISCARD), &buffer[0], sFogOfWarResolution*sFogOfWarResolution*4); - tex->getBuffer()->unlock(); - - mBuffers[texturePrefix] = buffer; -} -*/ - -/* -void LocalMap::loadFogOfWar (const std::string& texturePrefix, ESM::FogTexture& esm) -{ - std::vector& data = esm.mImageData; - Ogre::DataStreamPtr stream(new Ogre::MemoryDataStream(&data[0], data.size())); - Ogre::Image image; - image.load(stream, "tga"); - - if (int(image.getWidth()) != sFogOfWarResolution || int(image.getHeight()) != sFogOfWarResolution) - throw std::runtime_error("fog texture size mismatch"); - - std::string texName = texturePrefix + "_fog"; - - Ogre::TexturePtr tex = createFogOfWarTexture(texName); - - tex->unload(); - tex->loadImage(image); - - // create a buffer to use for dynamic operations - std::vector buffer; - buffer.resize(sFogOfWarResolution*sFogOfWarResolution); - memcpy(&buffer[0], image.getData(), image.getSize()); - - mBuffers[texturePrefix] = buffer; -} -*/ - void LocalMap::worldToInteriorMapPosition (osg::Vec2f pos, float& nX, float& nY, int& x, int& y) { pos = rotatePoint(pos, osg::Vec2f(mBounds.center().x(), mBounds.center().y()), mAngle); @@ -510,11 +459,8 @@ osg::Vec2f LocalMap::interiorMapToWorldPosition (float nX, float nY, int x, int bool LocalMap::isPositionExplored (float nX, float nY, int x, int y, bool interior) { - return true; - /* - std::string texName = (interior ? mInteriorName + "_" : "Cell_") + coordStr(x, y); - - if (mBuffers.find(texName) == mBuffers.end()) + const MapSegment& segment = mSegments[std::make_pair(x, y)]; + if (!segment.mFogOfWarImage) return false; nX = std::max(0.f, std::min(1.f, nX)); @@ -523,24 +469,14 @@ bool LocalMap::isPositionExplored (float nX, float nY, int x, int y, bool interi int texU = static_cast((sFogOfWarResolution - 1) * nX); int texV = static_cast((sFogOfWarResolution - 1) * nY); - Ogre::uint32 clr = mBuffers[texName][texV * sFogOfWarResolution + texU]; - uint8 alpha = (clr >> 24); + uint32_t clr = ((const uint32_t*)segment.mFogOfWarImage->data())[texV * sFogOfWarResolution + texU]; + uint8_t alpha = (clr >> 24); return alpha < 200; - */ } void LocalMap::updatePlayer (const osg::Vec3f& position, const osg::Quat& orientation, float& u, float& v, int& x, int& y, osg::Vec3f& direction) { - /* - if (sFogOfWarSkip != 0) - { - static int count=0; - if (++count % sFogOfWarSkip != 0) - return; - } - */ - // retrieve the x,y grid coordinates the player is in osg::Vec2f pos(position.x(), position.y()); @@ -563,11 +499,9 @@ void LocalMap::updatePlayer (const osg::Vec3f& position, const osg::Quat& orient v = 1.0f-std::abs((pos.y() - (mMapWorldSize*y))/mMapWorldSize); } - - /* // explore radius (squared) const float exploreRadius = (mInterior ? 0.1f : 0.3f) * (sFogOfWarResolution-1); // explore radius from 0 to sFogOfWarResolution-1 - const float sqrExploreRadius = Math::Sqr(exploreRadius); + const float sqrExploreRadius = square(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) @@ -575,7 +509,6 @@ void LocalMap::updatePlayer (const osg::Vec3f& position, const osg::Quat& orient { for (int my = -1; my<2; ++my) { - // is this texture affected at all? bool affected = false; if (mx == 0 && my == 0) // the player is always in the center of the 3x3 grid @@ -590,45 +523,137 @@ void LocalMap::updatePlayer (const osg::Vec3f& position, const osg::Quat& orient if (!affected) continue; - std::string texName = texBaseName + coordStr(x+mx,y+my*-1); + int texX = x + mx; + int texY = y + my*-1; - TexturePtr tex = TextureManager::getSingleton().getByName(texName+"_fog"); - if (!tex.isNull()) - { - std::map >::iterator anIter; + MapSegment& segment = mSegments[std::make_pair(texX, texY)]; - // get its buffer - anIter = mBuffers.find(texName); - if (anIter == mBuffers.end()) return; + if (!segment.mFogOfWarImage || !segment.mMapTexture) + continue; - std::vector& aBuffer = (*anIter).second; - int i=0; - for (int texV = 0; texVdata(); + for (int texV = 0; texV> 24); - alpha = std::min( alpha, (uint8) (std::max(0.f, std::min(1.f, (sqrDist/sqrExploreRadius)))*255) ); - aBuffer[i] = (uint32) (alpha << 24); - - ++i; - } - } + float sqrDist = square((texU + mx*(sFogOfWarResolution-1)) - u*(sFogOfWarResolution-1)) + + square((texV + my*(sFogOfWarResolution-1)) - v*(sFogOfWarResolution-1)); - tex->load(); + uint32_t clr = *(uint32_t*)data; + uint8_t alpha = (clr >> 24); - // copy to the texture - // NOTE: Could be optimized later. We actually only need to update the region that changed. - // Not a big deal at the moment, the FoW is only 32x32 anyway. - memcpy(tex->getBuffer()->lock(HardwareBuffer::HBL_DISCARD), &aBuffer[0], sFogOfWarResolution*sFogOfWarResolution*4); - tex->getBuffer()->unlock(); + alpha = std::min( alpha, (uint8_t) (std::max(0.f, std::min(1.f, (sqrDist/sqrExploreRadius)))*255) ); + *(uint32_t*)data = (uint32_t) (alpha << 24); + + data += 4; + } } + + segment.mHasFogState = true; + segment.mFogOfWarImage->dirty(); } } - */ +} + +LocalMap::MapSegment::MapSegment() + : mHasFogState(false) +{ +} + +LocalMap::MapSegment::~MapSegment() +{ + +} + +void LocalMap::MapSegment::createFogOfWarTexture() +{ + if (mFogOfWarTexture) + return; + mFogOfWarTexture = new osg::Texture2D; + mFogOfWarTexture->setDataVariance(osg::Object::DYNAMIC); + mFogOfWarTexture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR); + mFogOfWarTexture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); + mFogOfWarTexture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); + mFogOfWarTexture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); + mFogOfWarTexture->setUnRefImageDataAfterApply(false); +} + +void LocalMap::MapSegment::initFogOfWar() +{ + mFogOfWarImage = new osg::Image; + mFogOfWarImage->allocateImage(sFogOfWarResolution, sFogOfWarResolution, 1, GL_RGBA, GL_UNSIGNED_BYTE); + assert(mFogOfWarImage->isDataContiguous()); + std::vector data; + data.resize(sFogOfWarResolution*sFogOfWarResolution, 0xff000000); + + memcpy(mFogOfWarImage->data(), &data[0], data.size()*4); + + createFogOfWarTexture(); + mFogOfWarTexture->setImage(mFogOfWarImage); +} + +void LocalMap::MapSegment::loadFogOfWar(const ESM::FogTexture &esm) +{ + const std::vector& data = esm.mImageData; + if (!data.size()) + { + initFogOfWar(); + return; + } + + // TODO: deprecate tga and use raw data instead + + osgDB::ReaderWriter* readerwriter = osgDB::Registry::instance()->getReaderWriterForExtension("tga"); + if (!readerwriter) + { + std::cerr << "Unable to load fog, can't find a tga ReaderWriter" << std::endl; + return; + } + + Files::IMemStream in(&data[0], data.size()); + + osgDB::ReaderWriter::ReadResult result = readerwriter->readImage(in); + if (!result.success()) + { + std::cerr << "Failed to read fog: " << result.message() << std::endl; + return; + } + + mFogOfWarImage = result.getImage(); + mFogOfWarImage->flipVertical(); + mFogOfWarImage->dirty(); + + createFogOfWarTexture(); + mFogOfWarTexture->setImage(mFogOfWarImage); + mHasFogState = true; +} + +void LocalMap::MapSegment::saveFogOfWar(ESM::FogTexture &fog) const +{ + if (!mFogOfWarImage || !mHasFogState) + return; + + std::ostringstream ostream; + + osgDB::ReaderWriter* readerwriter = osgDB::Registry::instance()->getReaderWriterForExtension("tga"); + if (!readerwriter) + { + std::cerr << "Unable to write fog, can't find a tga ReaderWriter" << std::endl; + return; + } + + // extra flips are unfortunate, but required for compatibility with older versions + mFogOfWarImage->flipVertical(); + osgDB::ReaderWriter::WriteResult result = readerwriter->writeImage(*mFogOfWarImage, ostream); + if (!result.success()) + { + std::cerr << "Unable to write fog: " << result.message() << std::endl; + return; + } + mFogOfWarImage->flipVertical(); + + std::string data = ostream.str(); + fog.mImageData = std::vector(data.begin(), data.end()); } } diff --git a/apps/openmw/mwrender/localmap.hpp b/apps/openmw/mwrender/localmap.hpp index ba92cde24..c319b7ce7 100644 --- a/apps/openmw/mwrender/localmap.hpp +++ b/apps/openmw/mwrender/localmap.hpp @@ -27,6 +27,7 @@ namespace osgViewer namespace osg { class Texture2D; + class Image; class Camera; class Group; class Node; @@ -48,12 +49,23 @@ namespace MWRender */ void clear(); + /** + * Request a map render for the given cells. Render textures will be immediately created and can be retrieved with the getMapTexture function. + */ void requestMap (std::set cells); + /** + * Remove map and fog textures for the given cell. + */ void removeCell (MWWorld::CellStore* cell); - osg::ref_ptr getMapTexture (bool interior, int x, int y); + osg::ref_ptr getMapTexture (int x, int y); + osg::ref_ptr getFogOfWarTexture (int x, int y); + + /** + * Indicates a camera has been queued for rendering and can be cleaned up in the next frame. For internal use only. + */ void markForRemoval(osg::Camera* cam); /** @@ -78,8 +90,7 @@ namespace MWRender void saveFogOfWar(MWWorld::CellStore* cell); /** - * Get the interior map texture index and normalized position - * on this texture, given a world position + * Get the interior map texture index and normalized position on this texture, given a world position */ void worldToInteriorMapPosition (osg::Vec2f pos, float& nX, float& nY, int& x, int& y); @@ -102,17 +113,31 @@ namespace MWRender CameraVector mCamerasPendingRemoval; - typedef std::map, osg::ref_ptr > TextureMap; - TextureMap mTextures; + struct MapSegment + { + MapSegment(); + ~MapSegment(); + + void initFogOfWar(); + void loadFogOfWar(const ESM::FogTexture& fog); + void saveFogOfWar(ESM::FogTexture& fog) const; + void createFogOfWarTexture(); + + osg::ref_ptr mMapTexture; + osg::ref_ptr mFogOfWarTexture; + osg::ref_ptr mFogOfWarImage; + + bool mHasFogState; + }; + + typedef std::map, MapSegment> SegmentMap; + SegmentMap mSegments; int mMapResolution; // the dynamic texture is a bottleneck, so don't set this too high static const int sFogOfWarResolution = 32; - // frames to skip before rendering fog of war - static const int sFogOfWarSkip = 2; - // size of a map segment (for exteriors, 1 cell) float mMapWorldSize; @@ -125,23 +150,8 @@ namespace MWRender osg::ref_ptr createOrthographicCamera(float left, float top, float width, float height, const osg::Vec3d& upVector, float zmin, float zmax); void setupRenderToTexture(osg::ref_ptr camera, int x, int y); - // Creates a fog of war texture and initializes it to full black - //void createFogOfWar(const std::string& texturePrefix); - - // Loads a fog of war texture from its ESM struct - //void loadFogOfWar(const std::string& texturePrefix, ESM::FogTexture& esm); // FogTexture not const because MemoryDataStream doesn't accept it - - // A buffer for the "fog of war" textures of the current cell. - // Both interior and exterior maps are possibly divided into multiple textures. - //std::map > mBuffers; - - // The render texture we will use to create the map images - //Ogre::TexturePtr mRenderTexture; - //Ogre::RenderTarget* mRenderTarget; - bool mInterior; osg::BoundingBox mBounds; - //std::string mInteriorName; }; } diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 0883bc63b..d403590dd 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -179,12 +179,14 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot profile.mTimePlayed = mTimePlayed; profile.mDescription = description; + /* int screenshotW = 259*2, screenshotH = 133*2; // *2 to get some nice antialiasing Ogre::Image screenshot; world.screenshot(screenshot, screenshotW, screenshotH); Ogre::DataStreamPtr encoded = screenshot.encode("jpg"); profile.mScreenshot.resize(encoded->size()); encoded->read(&profile.mScreenshot[0], encoded->size()); + */ if (!slot) slot = getCurrentCharacter()->createSlot (profile); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 38353fa68..427a41d64 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -337,8 +337,8 @@ namespace MWWorld for (Scene::CellStoreCollection::const_iterator iter (mWorldScene->getActiveCells().begin()); iter!=mWorldScene->getActiveCells().end(); ++iter) { - //CellStore* cellstore = *iter; - //mRendering->writeFog(cellstore); + CellStore* cellstore = *iter; + MWBase::Environment::get().getWindowManager()->writeFog(cellstore); } MWMechanics::CreatureStats::writeActorIdCounter(writer); From f4ee805e3be333177a3c5f518f0b172c9f9b6634 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 28 May 2015 15:44:58 +0200 Subject: [PATCH 1291/3725] Object animation fix --- apps/openmw/mwmechanics/aiavoiddoor.cpp | 3 ++- apps/openmw/mwmechanics/character.cpp | 2 +- apps/openmw/mwrender/animation.cpp | 4 +++- apps/openmw/mwrender/animation.hpp | 2 +- apps/openmw/mwrender/creatureanimation.cpp | 2 -- apps/openmw/mwrender/objects.cpp | 2 +- apps/openmw/mwworld/player.cpp | 1 - 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwmechanics/aiavoiddoor.cpp b/apps/openmw/mwmechanics/aiavoiddoor.cpp index fccace55c..9ec5bc19a 100644 --- a/apps/openmw/mwmechanics/aiavoiddoor.cpp +++ b/apps/openmw/mwmechanics/aiavoiddoor.cpp @@ -2,11 +2,12 @@ #include #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" +#include "../mwbase/mechanicsmanager.hpp" #include "../mwworld/class.hpp" #include "../mwworld/cellstore.hpp" #include "creaturestats.hpp" #include "movement.hpp" -#include "mechanicsmanagerimp.hpp" + #include diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 9f3a23dd0..7588a3287 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1875,7 +1875,7 @@ void CharacterController::update(float duration) void CharacterController::playGroup(const std::string &groupname, int mode, int count) { if(!mAnimation || !mAnimation->hasAnimation(groupname)) - std::cerr<< "Animation "<(ptr.getRefData().getBaseNode()), resourceSystem) { if (!model.empty()) { setObjectRoot(model, false, false); + if (animated) + addAnimSource(model); if (!ptr.getClass().getEnchantment(ptr).empty()) addGlow(mObjectRoot, getEnchantmentColor(ptr)); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 20fbbed5c..d298fdff0 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -395,7 +395,7 @@ private: class ObjectAnimation : public Animation { public: - ObjectAnimation(const MWWorld::Ptr& ptr, const std::string &model, Resource::ResourceSystem* resourceSystem, bool allowLight); + ObjectAnimation(const MWWorld::Ptr& ptr, const std::string &model, Resource::ResourceSystem* resourceSystem, bool animated, bool allowLight); }; } diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index 810fc8b19..b653f4d30 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -24,7 +24,6 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr, if(!model.empty()) { setObjectRoot(model, false, false); - //setRenderProperties(mObjectRoot, RV_Actors, RQG_Main, RQG_Alpha); if((ref->mBase->mFlags&ESM::Creature::Bipedal)) addAnimSource("meshes\\xbase_anim.nif"); @@ -43,7 +42,6 @@ CreatureWeaponAnimation::CreatureWeaponAnimation(const MWWorld::Ptr &ptr, const if(!model.empty()) { setObjectRoot(model, true, false); - //setRenderProperties(mObjectRoot, RV_Actors, RQG_Main, RQG_Alpha); if((ref->mBase->mFlags&ESM::Creature::Bipedal)) addAnimSource("meshes\\xbase_anim.nif"); diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 47a54fdbf..2eb72dfd2 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -109,7 +109,7 @@ void Objects::insertModel(const MWWorld::Ptr &ptr, const std::string &mesh, bool { insertBegin(ptr); - std::auto_ptr anim (new ObjectAnimation(ptr, mesh, mResourceSystem, allowLight)); + std::auto_ptr anim (new ObjectAnimation(ptr, mesh, mResourceSystem, animated, allowLight)); if (!allowLight) { diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index 0b81532e1..09f6de072 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -20,7 +20,6 @@ #include "../mwmechanics/movement.hpp" #include "../mwmechanics/npcstats.hpp" #include "../mwmechanics/actors.hpp" -#include "../mwmechanics/mechanicsmanagerimp.hpp" #include "class.hpp" #include "ptr.hpp" From 5f7a82e0dad7a1809c59ca31b599c024f9b093ca Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 28 May 2015 16:20:29 +0200 Subject: [PATCH 1292/3725] Fog of war fix --- apps/openmw/mwrender/localmap.cpp | 41 +++++++++++++++++++------------ 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 0e7256345..495ea2d1d 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -297,10 +297,13 @@ void LocalMap::requestExteriorMap(MWWorld::CellStore* cell) setupRenderToTexture(camera, cell->getCell()->getGridX(), cell->getCell()->getGridY()); MapSegment& segment = mSegments[std::make_pair(cell->getCell()->getGridX(), cell->getCell()->getGridY())]; - if (cell->getFog()) - segment.loadFogOfWar(cell->getFog()->mFogTextures.back()); - else - segment.initFogOfWar(); + if (!segment.mFogOfWarImage) + { + if (cell->getFog()) + segment.loadFogOfWar(cell->getFog()->mFogTextures.back()); + else + segment.initFogOfWar(); + } } void LocalMap::requestInteriorMap(MWWorld::CellStore* cell) @@ -414,20 +417,23 @@ void LocalMap::requestInteriorMap(MWWorld::CellStore* cell) setupRenderToTexture(camera, x, y); MapSegment& segment = mSegments[std::make_pair(x,y)]; - if (!cell->getFog()) - segment.initFogOfWar(); - else + if (!segment.mFogOfWarImage) { - ESM::FogState* fog = cell->getFog(); - - // We are using the same bounds and angle as we were using when the textures were originally made. Segments should come out the same. - if (i >= int(fog->mFogTextures.size())) + if (!cell->getFog()) + segment.initFogOfWar(); + else { - std::cout << "Warning: fog texture count mismatch" << std::endl; - break; - } + ESM::FogState* fog = cell->getFog(); - segment.loadFogOfWar(fog->mFogTextures[i]); + // We are using the same bounds and angle as we were using when the textures were originally made. Segments should come out the same. + if (i >= int(fog->mFogTextures.size())) + { + std::cout << "Warning: fog texture count mismatch" << std::endl; + break; + } + + segment.loadFogOfWar(fog->mFogTextures[i]); + } } ++i; } @@ -570,7 +576,8 @@ void LocalMap::MapSegment::createFogOfWarTexture() if (mFogOfWarTexture) return; mFogOfWarTexture = new osg::Texture2D; - mFogOfWarTexture->setDataVariance(osg::Object::DYNAMIC); + // TODO: synchronize access? for now, the worst that could happen is the draw thread jumping a frame ahead. + //mFogOfWarTexture->setDataVariance(osg::Object::DYNAMIC); mFogOfWarTexture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR); mFogOfWarTexture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); mFogOfWarTexture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); @@ -581,6 +588,8 @@ void LocalMap::MapSegment::createFogOfWarTexture() void LocalMap::MapSegment::initFogOfWar() { mFogOfWarImage = new osg::Image; + // Assign a PixelBufferObject for asynchronous transfer of data to the GPU + mFogOfWarImage->setPixelBufferObject(new osg::PixelBufferObject); mFogOfWarImage->allocateImage(sFogOfWarResolution, sFogOfWarResolution, 1, GL_RGBA, GL_UNSIGNED_BYTE); assert(mFogOfWarImage->isDataContiguous()); std::vector data; From 9ee63dc3f406cb14846b09c9c2b22c9c3e2083f2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 28 May 2015 16:28:48 +0200 Subject: [PATCH 1293/3725] Change stats viewer key to f3 --- apps/openmw/engine.cpp | 2 +- components/sdlutil/sdlinputwrapper.cpp | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 9bfd86709..fed1f134b 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -541,7 +541,7 @@ void OMW::Engine::go() mViewer = new osgViewer::Viewer; osg::ref_ptr statshandler = new osgViewer::StatsHandler; - statshandler->setKeyEventTogglesOnScreenStats(osgGA::GUIEventAdapter::KEY_F9); + statshandler->setKeyEventTogglesOnScreenStats(osgGA::GUIEventAdapter::KEY_F3); statshandler->addUserStatsLine("Script", osg::Vec4f(1.f, 1.f, 1.f, 1.f), osg::Vec4f(1.f, 1.f, 1.f, 1.f), "script_time_taken", 1000.0, true, false, "script_time_begin", "script_time_end", 10000); diff --git a/components/sdlutil/sdlinputwrapper.cpp b/components/sdlutil/sdlinputwrapper.cpp index c321c342c..a9209bf58 100644 --- a/components/sdlutil/sdlinputwrapper.cpp +++ b/components/sdlutil/sdlinputwrapper.cpp @@ -84,8 +84,8 @@ InputWrapper::InputWrapper(SDL_Window* window, osg::ref_ptr v mKeyboardListener->keyPressed(evt.key); // temporary for the stats viewer - if (evt.key.keysym.sym == SDLK_F9) - mViewer->getEventQueue()->keyPress(osgGA::GUIEventAdapter::KEY_F9); + if (evt.key.keysym.sym == SDLK_F3) + mViewer->getEventQueue()->keyPress(osgGA::GUIEventAdapter::KEY_F3); break; case SDL_KEYUP: @@ -93,8 +93,8 @@ InputWrapper::InputWrapper(SDL_Window* window, osg::ref_ptr v mKeyboardListener->keyReleased(evt.key); // temporary for the stats viewer - if (evt.key.keysym.sym == SDLK_F9) - mViewer->getEventQueue()->keyRelease(osgGA::GUIEventAdapter::KEY_F9); + if (evt.key.keysym.sym == SDLK_F3) + mViewer->getEventQueue()->keyRelease(osgGA::GUIEventAdapter::KEY_F3); break; case SDL_TEXTINPUT: From 1cdb440b77f262685e8fb1789652eda77abe7424 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 28 May 2015 17:23:06 +0200 Subject: [PATCH 1294/3725] glReadPixels *is* available on OpenGL ES --- components/sdlutil/sdlcursormanager.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/components/sdlutil/sdlcursormanager.cpp b/components/sdlutil/sdlcursormanager.cpp index 2befc7bd0..1c5008f7a 100644 --- a/components/sdlutil/sdlcursormanager.cpp +++ b/components/sdlutil/sdlcursormanager.cpp @@ -119,7 +119,6 @@ namespace osg::ref_ptr geom = osg::createTexturedQuadGeometry(osg::Vec3(-1,-1,0), osg::Vec3(2,0,0), osg::Vec3(0,2,0)); geom->drawImplementation(renderInfo); - // TODO: implement for GL ES glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, resultImage->data()); geom->releaseGLObjects(); From 72d0a69132864c5d84fcf9b3a021acdfe452d412 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 28 May 2015 18:44:34 +0200 Subject: [PATCH 1295/3725] Fix global map markers not being cleared on a new game --- apps/openmw/mwgui/mapwindow.cpp | 6 ++++-- apps/openmw/mwgui/mapwindow.hpp | 2 ++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 8d2aaf04a..3a56d3dfd 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -782,6 +782,7 @@ namespace MWGui markerWidget->setDepth(Global_MarkerLayer); markerWidget->eventMouseDrag += MyGUI::newDelegate(this, &MapWindow::onMouseDrag); markerWidget->eventMouseButtonPressed += MyGUI::newDelegate(this, &MapWindow::onDragStart); + mGlobalMapMarkers.push_back(markerWidget); } } @@ -899,8 +900,9 @@ namespace MWGui mGlobalMapRender->clear(); mChanged = true; - while (mEventBoxGlobal->getChildCount()) - MyGUI::Gui::getInstance().destroyWidget(mEventBoxGlobal->getChildAt(0)); + for (std::vector::iterator it = mGlobalMapMarkers.begin(); it != mGlobalMapMarkers.end(); ++it) + MyGUI::Gui::getInstance().destroyWidget(*it); + mGlobalMapMarkers.clear(); } void MapWindow::write(ESM::ESMWriter &writer, Loading::Listener& progress) diff --git a/apps/openmw/mwgui/mapwindow.hpp b/apps/openmw/mwgui/mapwindow.hpp index b44b545d2..40ccbda5f 100644 --- a/apps/openmw/mwgui/mapwindow.hpp +++ b/apps/openmw/mwgui/mapwindow.hpp @@ -236,6 +236,8 @@ namespace MWGui MWRender::GlobalMap* mGlobalMapRender; + std::vector mGlobalMapMarkers; + EditNoteDialog mEditNoteDialog; ESM::CustomMarker mEditingMarker; From 7a1408cfed960ded9d10baedb5b8ba126a73fb9d Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 28 May 2015 18:49:24 +0200 Subject: [PATCH 1296/3725] Restore display of global map overlay, no exploration yet --- apps/openmw/mwgui/mapwindow.cpp | 11 +-- apps/openmw/mwgui/mapwindow.hpp | 3 +- apps/openmw/mwrender/globalmap.cpp | 146 ++++++++++++++++++++--------- apps/openmw/mwrender/globalmap.hpp | 6 +- 4 files changed, 115 insertions(+), 51 deletions(-) diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 3a56d3dfd..46e2f29e0 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -582,7 +582,6 @@ namespace MWGui , LocalMapBase(customMarkers, localMapRender) , NoDrop(drag, mMainWidget) , mGlobalMap(0) - , mGlobalMapTexture(NULL) , mGlobalMapImage(NULL) , mGlobalMapOverlay(NULL) , mGlobal(false) @@ -736,17 +735,17 @@ namespace MWGui mGlobalMap->setCanvasSize (mGlobalMapRender->getWidth(), mGlobalMapRender->getHeight()); mGlobalMapImage->setSize(mGlobalMapRender->getWidth(), mGlobalMapRender->getHeight()); - mGlobalMapTexture = new osgMyGUI::OSGTexture(mGlobalMapRender->getBaseTexture()); - mGlobalMapImage->setRenderItemTexture(mGlobalMapTexture); + mGlobalMapTexture.reset(new osgMyGUI::OSGTexture(mGlobalMapRender->getBaseTexture())); + mGlobalMapImage->setRenderItemTexture(mGlobalMapTexture.get()); mGlobalMapImage->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 0.f, 1.f, 1.f)); - //mGlobalMapOverlay->setImageTexture("GlobalMapOverlay"); + mGlobalMapOverlayTexture.reset(new osgMyGUI::OSGTexture(mGlobalMapRender->getOverlayTexture())); + mGlobalMapOverlay->setRenderItemTexture(mGlobalMapOverlayTexture.get()); + mGlobalMapOverlay->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 1.f, 1.f, 0.f)); } MapWindow::~MapWindow() { - delete mGlobalMapTexture; - delete mGlobalMapRender; } diff --git a/apps/openmw/mwgui/mapwindow.hpp b/apps/openmw/mwgui/mapwindow.hpp index 40ccbda5f..bea3d33b9 100644 --- a/apps/openmw/mwgui/mapwindow.hpp +++ b/apps/openmw/mwgui/mapwindow.hpp @@ -212,7 +212,8 @@ namespace MWGui void globalMapUpdatePlayer(); MyGUI::ScrollView* mGlobalMap; - MyGUI::ITexture* mGlobalMapTexture; + std::auto_ptr mGlobalMapTexture; + std::auto_ptr mGlobalMapOverlayTexture; MyGUI::ImageBox* mGlobalMapImage; MyGUI::ImageBox* mGlobalMapOverlay; MyGUI::ImageBox* mPlayerArrowLocal; diff --git a/apps/openmw/mwrender/globalmap.cpp b/apps/openmw/mwrender/globalmap.cpp index da1be0028..8ca21cbfb 100644 --- a/apps/openmw/mwrender/globalmap.cpp +++ b/apps/openmw/mwrender/globalmap.cpp @@ -5,8 +5,11 @@ #include #include +#include + #include #include +#include #include @@ -134,7 +137,12 @@ namespace MWRender } mBaseTexture = new osg::Texture2D; + mBaseTexture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); + mBaseTexture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); + mBaseTexture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR); + mBaseTexture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); mBaseTexture->setImage(image); + mBaseTexture->setResizeNonPowerOfTwoHint(false); clear(); @@ -200,14 +208,25 @@ namespace MWRender void GlobalMap::clear() { - /* - Ogre::uchar* buffer = OGRE_ALLOC_T(Ogre::uchar, mWidth * mHeight * 4, Ogre::MEMCATEGORY_GENERAL); - memset(buffer, 0, mWidth * mHeight * 4); - - mOverlayImage.loadDynamicImage(&buffer[0], mWidth, mHeight, 1, Ogre::PF_A8B8G8R8, true); // pass ownership of buffer to image + if (!mOverlayImage) + { + mOverlayImage = new osg::Image; + mOverlayImage->allocateImage(mWidth, mHeight, 1, GL_RGBA, GL_UNSIGNED_BYTE); + assert(mOverlayImage->isDataContiguous()); + } + memset(mOverlayImage->data(), 0, mOverlayImage->getTotalSizeInBytes()); + mOverlayImage->dirty(); - mOverlayTexture->load(); - */ + if (!mOverlayTexture) + { + mOverlayTexture = new osg::Texture2D; + mOverlayTexture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); + mOverlayTexture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); + mOverlayTexture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR); + mOverlayTexture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); + mOverlayTexture->setImage(mOverlayImage); + mOverlayTexture->setResizeNonPowerOfTwoHint(false); + } } void GlobalMap::write(ESM::GlobalMap& map) @@ -217,13 +236,35 @@ namespace MWRender map.mBounds.mMinY = mMinY; map.mBounds.mMaxY = mMaxY; - /* - Ogre::DataStreamPtr encoded = mOverlayImage.encode("png"); - map.mImageData.resize(encoded->size()); - encoded->read(&map.mImageData[0], encoded->size()); - */ + std::ostringstream ostream; + osgDB::ReaderWriter* readerwriter = osgDB::Registry::instance()->getReaderWriterForExtension("png"); + if (!readerwriter) + { + std::cerr << "Can't write map overlay: no png readerwriter found" << std::endl; + return; + } + + osgDB::ReaderWriter::WriteResult result = readerwriter->writeImage(*mOverlayImage, ostream); + if (!result.success()) + { + std::cerr << "Can't write map overlay: " << result.message() << std::endl; + return; + } + + std::string data = ostream.str(); + map.mImageData = std::vector(data.begin(), data.end()); } + struct Box + { + int mLeft, mRight, mTop, mBottom; + + Box(int left, int right, int top, int bottom) + : mLeft(left), mRight(right), mTop(top), mBottom(bottom) + { + } + }; + void GlobalMap::read(ESM::GlobalMap& map) { const ESM::GlobalMap::Bounds& bounds = map.mBounds; @@ -237,17 +278,35 @@ namespace MWRender || bounds.mMinY > bounds.mMaxY) throw std::runtime_error("invalid map bounds"); - /* - Ogre::Image image; - Ogre::DataStreamPtr stream(new Ogre::MemoryDataStream(&map.mImageData[0], map.mImageData.size())); - image.load(stream, "png"); + if (!map.mImageData.size()) + return; + + Files::IMemStream istream(&map.mImageData[0], map.mImageData.size()); + + osgDB::ReaderWriter* readerwriter = osgDB::Registry::instance()->getReaderWriterForExtension("png"); + if (!readerwriter) + { + std::cerr << "Can't read map overlay: no png readerwriter found" << std::endl; + return; + } + + osgDB::ReaderWriter::ReadResult result = readerwriter->readImage(istream); + if (!result.success()) + { + std::cerr << "Can't read map overlay: " << result.message() << std::endl; + return; + } + + osg::ref_ptr image = result.getImage(); + int imageWidth = image->s(); + int imageHeight = image->t(); int xLength = (bounds.mMaxX-bounds.mMinX+1); int yLength = (bounds.mMaxY-bounds.mMinY+1); // Size of one cell in image space - int cellImageSizeSrc = image.getWidth() / xLength; - if (int(image.getHeight() / yLength) != cellImageSizeSrc) + int cellImageSizeSrc = imageWidth / xLength; + if (int(imageHeight / yLength) != cellImageSizeSrc) throw std::runtime_error("cell size must be quadratic"); // If cell bounds of the currently loaded content and the loaded savegame do not match, @@ -266,39 +325,40 @@ namespace MWRender int topDiff = (bounds.mMaxY - mMaxY); int rightDiff = (bounds.mMaxX - mMaxX); int bottomDiff = (mMinY - bounds.mMinY); - Ogre::Image::Box srcBox ( std::max(0, leftDiff * cellImageSizeSrc), + + Box srcBox ( std::max(0, leftDiff * cellImageSizeSrc), std::max(0, topDiff * cellImageSizeSrc), - std::min(image.getWidth(), image.getWidth() - rightDiff * cellImageSizeSrc), - std::min(image.getHeight(), image.getHeight() - bottomDiff * cellImageSizeSrc)); + std::min(imageWidth, imageWidth - rightDiff * cellImageSizeSrc), + std::min(imageHeight, imageHeight - bottomDiff * cellImageSizeSrc)); - Ogre::Image::Box destBox ( std::max(0, -leftDiff * cellImageSizeDst), + Box destBox ( std::max(0, -leftDiff * cellImageSizeDst), std::max(0, -topDiff * cellImageSizeDst), - std::min(mOverlayTexture->getWidth(), mOverlayTexture->getWidth() + rightDiff * cellImageSizeDst), - std::min(mOverlayTexture->getHeight(), mOverlayTexture->getHeight() + bottomDiff * cellImageSizeDst)); - - // Looks like there is no interface for blitting from memory with src/dst boxes. - // So we create a temporary texture for blitting. - Ogre::TexturePtr tex = Ogre::TextureManager::getSingleton().createManual("@temp", - Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::TEX_TYPE_2D, image.getWidth(), - image.getHeight(), 0, Ogre::PF_A8B8G8R8); - tex->loadImage(image); - - mOverlayTexture->load(); - mOverlayTexture->getBuffer()->blit(tex->getBuffer(), srcBox, destBox); - - if (srcBox.left == destBox.left && srcBox.right == destBox.right - && srcBox.top == destBox.top && srcBox.bottom == destBox.bottom - && int(image.getWidth()) == mWidth && int(image.getHeight()) == mHeight) - mOverlayImage = image; - else - mOverlayTexture->convertToImage(mOverlayImage); + std::min(mWidth, mWidth + rightDiff * cellImageSizeDst), + std::min(mHeight, mHeight + bottomDiff * cellImageSizeDst)); - Ogre::TextureManager::getSingleton().remove("@temp"); - */ + if (srcBox.mLeft == destBox.mLeft && srcBox.mRight == destBox.mRight + && srcBox.mTop == destBox.mTop && srcBox.mBottom == destBox.mBottom + && imageWidth == mWidth && imageHeight == mHeight) + { + mOverlayImage->copySubImage(0, 0, 0, image); + } + else + { + // TODO: + // Dimensions don't match. This could mean a changed map region, or a changed map resolution. + // In the latter case, we'll want to use filtering. + // Create a RTT Camera and draw the image onto mOverlayImage in the next frame? + } + mOverlayImage->dirty(); } osg::ref_ptr GlobalMap::getBaseTexture() { return mBaseTexture; } + + osg::ref_ptr GlobalMap::getOverlayTexture() + { + return mOverlayTexture; + } } diff --git a/apps/openmw/mwrender/globalmap.hpp b/apps/openmw/mwrender/globalmap.hpp index d7e20a3a7..9ca7ed5b4 100644 --- a/apps/openmw/mwrender/globalmap.hpp +++ b/apps/openmw/mwrender/globalmap.hpp @@ -9,6 +9,7 @@ namespace osg { class Texture2D; + class Image; } namespace Loading @@ -50,7 +51,7 @@ namespace MWRender void read (ESM::GlobalMap& map); osg::ref_ptr getBaseTexture(); - //osg::ref_ptr getOverlayTexture(); + osg::ref_ptr getOverlayTexture(); private: int mCellSize; @@ -58,6 +59,9 @@ namespace MWRender std::vector< std::pair > mExploredCells; osg::ref_ptr mBaseTexture; + osg::ref_ptr mOverlayTexture; + + osg::ref_ptr mOverlayImage; int mWidth; int mHeight; From 6821cb4133e0456a42ac279a3fd69b312a6b6c5e Mon Sep 17 00:00:00 2001 From: cc9cii Date: Fri, 29 May 2015 05:40:20 +1000 Subject: [PATCH 1297/3725] Use the tree model rather than a nested proxy for the dialogue only listing (i.e. non table) items. Should resolve Bug #2586. - QDataWidgetMapper requires the rootindex to be set, which was not possible with the nested proxy model. --- apps/opencs/view/world/dialoguesubview.cpp | 39 +++++++++++++--------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 5e2fa29a5..66e8fcb7a 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -211,8 +211,17 @@ void CSVWorld::DialogueDelegateDispatcher::editorDataCommited(QWidget* editor, void CSVWorld::DialogueDelegateDispatcher::setEditorData (QWidget* editor, const QModelIndex& index) const { - CSMWorld::ColumnBase::Display display = static_cast - (mTable->headerData (index.column(), Qt::Horizontal, CSMWorld::ColumnBase::Role_Display).toInt()); + CSMWorld::ColumnBase::Display display = CSMWorld::ColumnBase::Display_None; + if (index.parent().isValid()) + { + display = static_cast + (static_cast(mTable)->nestedHeaderData (index.parent().column(), index.column(), Qt::Horizontal, CSMWorld::ColumnBase::Role_Display).toInt()); + } + else + { + display = static_cast + (mTable->headerData (index.column(), Qt::Horizontal, CSMWorld::ColumnBase::Role_Display).toInt()); + } QLabel* label = qobject_cast(editor); if(label) @@ -523,22 +532,20 @@ void CSVWorld::EditWidget::remake(int row) } else { - mNestedModels.push_back(new CSMWorld::NestedTableProxyModel ( - static_cast(mTable)->index(row, i), - display, static_cast(mTable))); + CSMWorld::IdTree *tree = static_cast(mTable); mNestedTableMapper = new QDataWidgetMapper (this); - mNestedTableMapper->setModel(mNestedModels.back()); + mNestedTableMapper->setModel(tree); // FIXME: lack MIME support? mNestedTableDispatcher = - new DialogueDelegateDispatcher (0/*this*/, mTable, mCommandDispatcher, mDocument, mNestedModels.back()); + new DialogueDelegateDispatcher (0/*this*/, mTable, mCommandDispatcher, mDocument, tree); + mNestedTableMapper->setRootIndex (tree->index(row, i)); mNestedTableMapper->setItemDelegate(mNestedTableDispatcher); - int columnCount = - mTable->columnCount(mTable->getModelIndex (mNestedModels.back()->getParentId(), i)); + int columnCount = tree->columnCount(tree->index(row, i)); for (int col = 0; col < columnCount; ++col) { - int displayRole = mNestedModels.back()->headerData (col, + int displayRole = tree->nestedHeaderData (i, col, Qt::Horizontal, CSMWorld::ColumnBase::Role_Display).toInt(); CSMWorld::ColumnBase::Display display = @@ -548,16 +555,16 @@ void CSVWorld::EditWidget::remake(int row) // FIXME: assumed all columns are editable QWidget* editor = - mNestedTableDispatcher->makeEditor (display, mNestedModels.back()->index (0, col)); + mNestedTableDispatcher->makeEditor (display, tree->index (0, col, tree->index(row, i))); if (editor) { mNestedTableMapper->addMapping (editor, col); - std::string disString = mNestedModels.back()->headerData (col, + std::string disString = tree->nestedHeaderData (i, col, Qt::Horizontal, Qt::DisplayRole).toString().toStdString(); - // Need ot use Qt::DisplayRole in order to get the correct string + // Need to use Qt::DisplayRole in order to get the correct string // from CSMWorld::Columns - QLabel* label = new QLabel (mNestedModels.back()->headerData (col, + QLabel* label = new QLabel (tree->nestedHeaderData (i, col, Qt::Horizontal, Qt::DisplayRole).toString(), mMainWidget); label->setSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed); @@ -567,14 +574,14 @@ void CSVWorld::EditWidget::remake(int row) unlockedLayout->addWidget (editor, unlocked, 1); ++unlocked; - if(mNestedModels.back()->index(0, col).data().type() == QVariant::UserType) + if(tree->index(0, col, tree->index(row, i)).data().type() == QVariant::UserType) { editor->setEnabled(false); label->setEnabled(false); } } } - mNestedTableMapper->setCurrentModelIndex(mNestedModels.back()->index(0, 0)); + mNestedTableMapper->setCurrentModelIndex(tree->index(0, 0, tree->index(row, i))); } } } From 9ad69d908529edfecdd830fd970af6ffb3451a88 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Fri, 29 May 2015 05:44:35 +1000 Subject: [PATCH 1298/3725] Allow wheel events in dialogue spin box types only when they have focus. Should resolve Feature #2585. --- apps/opencs/CMakeLists.txt | 1 + apps/opencs/view/world/dialoguespinbox.cpp | 53 ++++++++++++++++++++++ apps/opencs/view/world/dialoguespinbox.hpp | 40 ++++++++++++++++ apps/opencs/view/world/util.cpp | 8 ++-- 4 files changed, 97 insertions(+), 5 deletions(-) create mode 100644 apps/opencs/view/world/dialoguespinbox.cpp create mode 100644 apps/opencs/view/world/dialoguespinbox.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 78b2deb7a..7723b15f5 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -63,6 +63,7 @@ opencs_units (view/world table tablesubview scriptsubview util regionmapsubview tablebottombox creator genericcreator cellcreator referenceablecreator referencecreator scenesubview infocreator scriptedit dialoguesubview previewsubview regionmap dragrecordtable nestedtable + dialoguespinbox ) opencs_units_noqt (view/world diff --git a/apps/opencs/view/world/dialoguespinbox.cpp b/apps/opencs/view/world/dialoguespinbox.cpp new file mode 100644 index 000000000..1228ca0da --- /dev/null +++ b/apps/opencs/view/world/dialoguespinbox.cpp @@ -0,0 +1,53 @@ +#include "dialoguespinbox.hpp" + +#include + +CSVWorld::DialogueSpinBox::DialogueSpinBox(QWidget *parent) : QSpinBox(parent) +{ + setFocusPolicy(Qt::StrongFocus); +} + +void CSVWorld::DialogueSpinBox::focusInEvent(QFocusEvent *event) +{ + setFocusPolicy(Qt::WheelFocus); + QSpinBox::focusInEvent(event); +} + +void CSVWorld::DialogueSpinBox::focusOutEvent(QFocusEvent *event) +{ + setFocusPolicy(Qt::StrongFocus); + QSpinBox::focusOutEvent(event); +} + +void CSVWorld::DialogueSpinBox::wheelEvent(QWheelEvent *event) +{ + if (!hasFocus()) + event->ignore(); + else + QSpinBox::wheelEvent(event); +} + +CSVWorld::DialogueDoubleSpinBox::DialogueDoubleSpinBox(QWidget *parent) : QDoubleSpinBox(parent) +{ + setFocusPolicy(Qt::StrongFocus); +} + +void CSVWorld::DialogueDoubleSpinBox::focusInEvent(QFocusEvent *event) +{ + setFocusPolicy(Qt::WheelFocus); + QDoubleSpinBox::focusInEvent(event); +} + +void CSVWorld::DialogueDoubleSpinBox::focusOutEvent(QFocusEvent *event) +{ + setFocusPolicy(Qt::StrongFocus); + QDoubleSpinBox::focusOutEvent(event); +} + +void CSVWorld::DialogueDoubleSpinBox::wheelEvent(QWheelEvent *event) +{ + if (!hasFocus()) + event->ignore(); + else + QDoubleSpinBox::wheelEvent(event); +} diff --git a/apps/opencs/view/world/dialoguespinbox.hpp b/apps/opencs/view/world/dialoguespinbox.hpp new file mode 100644 index 000000000..a68e0c314 --- /dev/null +++ b/apps/opencs/view/world/dialoguespinbox.hpp @@ -0,0 +1,40 @@ +#ifndef CSV_WORLD_DIALOGUESPINBOX_H +#define CSV_WORLD_DIALOGUESPINBOX_H + +#include +#include + +namespace CSVWorld +{ + class DialogueSpinBox : public QSpinBox + { + Q_OBJECT + + public: + + DialogueSpinBox (QWidget *parent = 0); + + protected: + + virtual void focusInEvent(QFocusEvent *event); + virtual void focusOutEvent(QFocusEvent *event); + virtual void wheelEvent(QWheelEvent *event); + }; + + class DialogueDoubleSpinBox : public QDoubleSpinBox + { + Q_OBJECT + + public: + + DialogueDoubleSpinBox (QWidget *parent = 0); + + protected: + + virtual void focusInEvent(QFocusEvent *event); + virtual void focusOutEvent(QFocusEvent *event); + virtual void wheelEvent(QWheelEvent *event); + }; +} + +#endif // CSV_WORLD_DIALOGUESPINBOX_H diff --git a/apps/opencs/view/world/util.cpp b/apps/opencs/view/world/util.cpp index a11b5bdde..5452214ef 100644 --- a/apps/opencs/view/world/util.cpp +++ b/apps/opencs/view/world/util.cpp @@ -9,8 +9,6 @@ #include #include #include -#include -#include #include #include #include @@ -19,7 +17,7 @@ #include "../../model/world/commands.hpp" #include "../../model/world/tablemimedata.hpp" #include "../../model/world/commanddispatcher.hpp" - +#include "dialoguespinbox.hpp" #include "scriptedit.hpp" CSVWorld::NastyTableModelHack::NastyTableModelHack (QAbstractItemModel& model) @@ -174,7 +172,7 @@ QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleO case CSMWorld::ColumnBase::Display_Integer: { - QSpinBox *sb = new QSpinBox(parent); + DialogueSpinBox *sb = new DialogueSpinBox(parent); sb->setRange(INT_MIN, INT_MAX); return sb; } @@ -185,7 +183,7 @@ QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleO case CSMWorld::ColumnBase::Display_Float: { - QDoubleSpinBox *dsb = new QDoubleSpinBox(parent); + DialogueDoubleSpinBox *dsb = new DialogueDoubleSpinBox(parent); dsb->setRange(-FLT_MAX, FLT_MAX); dsb->setSingleStep(0.01f); dsb->setDecimals(3); From 734e52d1c82e2f2a250c3a11fbaecd53592ee27f Mon Sep 17 00:00:00 2001 From: cc9cii Date: Fri, 29 May 2015 06:40:40 +1000 Subject: [PATCH 1299/3725] Move the user preference check to the preparation step before the running of the operation. --- apps/opencs/model/tools/pathgridcheck.cpp | 13 +++++-------- apps/opencs/model/tools/pathgridcheck.hpp | 15 ++++++++------- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/apps/opencs/model/tools/pathgridcheck.cpp b/apps/opencs/model/tools/pathgridcheck.cpp index c436cfe04..58fdbeb2d 100644 --- a/apps/opencs/model/tools/pathgridcheck.cpp +++ b/apps/opencs/model/tools/pathgridcheck.cpp @@ -16,17 +16,14 @@ CSMTools::PathgridCheckStage::PathgridCheckStage (const CSMWorld::SubCellCollect int CSMTools::PathgridCheckStage::setup() { + CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); + mExtraCheck = userSettings.setting ("verifier/pathgrid-extra-check", QString ("false"))=="true"; + return mPathgrids.getSize(); } void CSMTools::PathgridCheckStage::perform (int stage, CSMDoc::Messages& messages) { - // NOTE: This is horribly inefficient but in order to use signals the entire Stage class - // hierarchy needs to be braught under Qt which seems like an overkill for a small - // performance gain during verify operations - CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); - bool extraCheck = userSettings.setting ("verifier/pathgrid-extra-check", QString ("false"))=="true"; - const CSMWorld::Record& record = mPathgrids.getRecord (stage); if (record.isDeleted()) @@ -113,7 +110,7 @@ void CSMTools::PathgridCheckStage::perform (int stage, CSMDoc::Messages& message } } - if (!extraCheck) + if (!mExtraCheck) continue; // check duplicate points @@ -144,7 +141,7 @@ void CSMTools::PathgridCheckStage::perform (int stage, CSMDoc::Messages& message } } - if (!extraCheck) + if (!mExtraCheck) return; // check pathgrid points that are not connected to anything diff --git a/apps/opencs/model/tools/pathgridcheck.hpp b/apps/opencs/model/tools/pathgridcheck.hpp index 603235552..86ace6af2 100644 --- a/apps/opencs/model/tools/pathgridcheck.hpp +++ b/apps/opencs/model/tools/pathgridcheck.hpp @@ -24,17 +24,18 @@ namespace CSMTools class PathgridCheckStage : public CSMDoc::Stage { - const CSMWorld::SubCellCollection >& mPathgrids; + bool mExtraCheck; + const CSMWorld::SubCellCollection >& mPathgrids; - public: + public: - PathgridCheckStage (const CSMWorld::SubCellCollection >& pathgrids); + PathgridCheckStage (const CSMWorld::SubCellCollection >& pathgrids); - virtual int setup(); + virtual int setup(); - virtual void perform (int stage, CSMDoc::Messages& messages); + virtual void perform (int stage, CSMDoc::Messages& messages); }; } From 6d3528af7099e300e819f6311a0b299130d7e834 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 29 May 2015 01:49:52 +0200 Subject: [PATCH 1300/3725] Port global map exploration --- apps/openmw/mwgui/mapwindow.cpp | 9 +- apps/openmw/mwrender/globalmap.cpp | 239 +++++++++++++++++++++++------ apps/openmw/mwrender/globalmap.hpp | 53 ++++++- apps/openmw/mwrender/localmap.cpp | 5 + apps/openmw/mwrender/localmap.hpp | 2 + 5 files changed, 255 insertions(+), 53 deletions(-) diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 46e2f29e0..d748bef6c 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -587,7 +587,7 @@ namespace MWGui , mGlobal(false) , mEventBoxGlobal(NULL) , mEventBoxLocal(NULL) - , mGlobalMapRender(0) + , mGlobalMapRender(new MWRender::GlobalMap(localMapRender->getRoot())) , mEditNoteDialog() { static bool registered = false; @@ -730,7 +730,6 @@ namespace MWGui void MapWindow::renderGlobalMap(Loading::Listener* loadingListener) { - mGlobalMapRender = new MWRender::GlobalMap(); mGlobalMapRender->render(loadingListener); mGlobalMap->setCanvasSize (mGlobalMapRender->getWidth(), mGlobalMapRender->getHeight()); mGlobalMapImage->setSize(mGlobalMapRender->getWidth(), mGlobalMapRender->getHeight()); @@ -794,9 +793,11 @@ namespace MWGui { LocalMapBase::onFrame(dt); + mGlobalMapRender->cleanupCameras(); + for (std::vector::iterator it = mQueuedToExplore.begin(); it != mQueuedToExplore.end(); ++it) { - mGlobalMapRender->exploreCell(it->first, it->second); + mGlobalMapRender->exploreCell(it->first, it->second, mLocalMapRender->getMapTexture(it->first, it->second)); } mQueuedToExplore.clear(); @@ -866,6 +867,8 @@ namespace MWGui void MapWindow::notifyPlayerUpdate () { globalMapUpdatePlayer (); + + setGlobalMapPlayerDir(mLastDirectionX, mLastDirectionY); } void MapWindow::setGlobalMapPlayerPosition(float worldX, float worldY) diff --git a/apps/openmw/mwrender/globalmap.cpp b/apps/openmw/mwrender/globalmap.cpp index 8ca21cbfb..1e30eb0fc 100644 --- a/apps/openmw/mwrender/globalmap.cpp +++ b/apps/openmw/mwrender/globalmap.cpp @@ -4,6 +4,10 @@ #include #include +#include +#include +#include +#include #include @@ -18,11 +22,66 @@ #include "../mwworld/esmstore.hpp" +#include "vismask.hpp" + +namespace +{ + + // Create a screen-aligned quad with given texture coordinates. + // Assumes a top-left origin of the sampled image. + osg::ref_ptr createTexturedQuad(float leftTexCoord, float topTexCoord, float rightTexCoord, float bottomTexCoord) + { + osg::ref_ptr geom = new osg::Geometry; + + osg::ref_ptr verts = new osg::Vec3Array; + verts->push_back(osg::Vec3f(-1, -1, 0)); + verts->push_back(osg::Vec3f(-1, 1, 0)); + verts->push_back(osg::Vec3f(1, 1, 0)); + verts->push_back(osg::Vec3f(1, -1, 0)); + + geom->setVertexArray(verts); + + osg::ref_ptr texcoords = new osg::Vec2Array; + texcoords->push_back(osg::Vec2f(leftTexCoord, 1.f-bottomTexCoord)); + texcoords->push_back(osg::Vec2f(leftTexCoord, 1.f-topTexCoord)); + texcoords->push_back(osg::Vec2f(rightTexCoord, 1.f-topTexCoord)); + texcoords->push_back(osg::Vec2f(rightTexCoord, 1.f-bottomTexCoord)); + + geom->setTexCoordArray(0, texcoords, osg::Array::BIND_PER_VERTEX); + + geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,4)); + + return geom; + } + + + class CameraUpdateCallback : public osg::NodeCallback + { + public: + CameraUpdateCallback(osg::Camera* cam, MWRender::GlobalMap* parent) + : mCamera(cam), mParent(parent) + { + } + + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) + { + mParent->markForRemoval(mCamera); + traverse(node, nv); + } + + private: + osg::ref_ptr mCamera; + MWRender::GlobalMap* mParent; + }; + +} + namespace MWRender { - GlobalMap::GlobalMap() - : mWidth(0) + GlobalMap::GlobalMap(osg::Group* root) + : mRoot(root) + , mWidth(0) , mHeight(0) , mMinX(0), mMaxX(0) , mMinY(0), mMaxY(0) @@ -164,46 +223,78 @@ namespace MWRender imageY = 1.f-float(y - mMinY + 1) / (mMaxY - mMinY + 1); } - void GlobalMap::exploreCell(int cellX, int cellY) + void GlobalMap::requestOverlayTextureUpdate(int x, int y, int width, int height, osg::ref_ptr texture, bool clear, bool cpuCopy, + float srcLeft, float srcTop, float srcRight, float srcBottom) { - //float originX = static_cast((cellX - mMinX) * mCellSize); - // NB y + 1, because we want the top left corner, not bottom left where the origin of the cell is - //float originY = static_cast(mHeight - (cellY + 1 - mMinY) * mCellSize); + osg::ref_ptr camera (new osg::Camera); + camera->setNodeMask(Mask_RenderToTexture); + camera->setReferenceFrame(osg::Camera::ABSOLUTE_RF); + camera->setViewMatrix(osg::Matrix::identity()); + camera->setProjectionMatrix(osg::Matrix::identity()); + camera->setProjectionResizePolicy(osg::Camera::FIXED); + camera->setRenderOrder(osg::Camera::PRE_RENDER); + camera->setViewport(x, y, width, height); + + if (clear) + { + camera->setClearMask(GL_COLOR_BUFFER_BIT); + camera->setClearColor(osg::Vec4(0,0,0,0)); + } + else + camera->setClearMask(GL_NONE); - if (cellX > mMaxX || cellX < mMinX || cellY > mMaxY || cellY < mMinY) - return; + camera->setUpdateCallback(new CameraUpdateCallback(camera, this)); - /* - Ogre::TexturePtr localMapTexture = Ogre::TextureManager::getSingleton().getByName("Cell_" - + boost::lexical_cast(cellX) + "_" + boost::lexical_cast(cellY)); + camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT, osg::Camera::PIXEL_BUFFER_RTT); + camera->attach(osg::Camera::COLOR_BUFFER, mOverlayTexture); - if (!localMapTexture.isNull()) + if (cpuCopy) { - int mapWidth = localMapTexture->getWidth(); - int mapHeight = localMapTexture->getHeight(); - mOverlayTexture->load(); - mOverlayTexture->getBuffer()->blit(localMapTexture->getBuffer(), Ogre::Image::Box(0,0,mapWidth,mapHeight), - Ogre::Image::Box(static_cast(originX), static_cast(originY), - static_cast(originX + mCellSize), static_cast(originY + mCellSize))); - - Ogre::Image backup; - std::vector data; - data.resize(mCellSize*mCellSize*4, 0); - backup.loadDynamicImage(&data[0], mCellSize, mCellSize, Ogre::PF_A8B8G8R8); - - localMapTexture->getBuffer()->blitToMemory(Ogre::Image::Box(0,0,mapWidth,mapHeight), backup.getPixelBox()); - - for (int x=0; x(originX + x), static_cast(originY + y), 0); - } + // Attach an image to copy the render back to the CPU when finished + osg::ref_ptr image (new osg::Image); + image->setPixelFormat(mOverlayImage->getPixelFormat()); + image->setDataType(mOverlayImage->getDataType()); + camera->attach(osg::Camera::COLOR_BUFFER, image); + + // FIXME: why does the image get slightly darker by the read back? + ImageDest imageDest; + imageDest.mImage = image; + imageDest.mX = x; + imageDest.mY = y; + mPendingImageDest.push_back(imageDest); + } + + // Create a quad rendering the updated texture + if (texture) + { + osg::ref_ptr geom = createTexturedQuad(srcLeft, srcTop, srcRight, srcBottom); + osg::ref_ptr depth = new osg::Depth; + depth->setFunction(osg::Depth::ALWAYS); + geom->getOrCreateStateSet()->setAttributeAndModes(depth, osg::StateAttribute::ON); + geom->getOrCreateStateSet()->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON); + geom->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF); + osg::ref_ptr geode = new osg::Geode; + geode->addDrawable(geom); + camera->addChild(geode); } - */ + + mRoot->addChild(camera); + + mActiveCameras.push_back(camera); + } + + void GlobalMap::exploreCell(int cellX, int cellY, osg::ref_ptr localMapTexture) + { + if (!localMapTexture) + return; + + int originX = (cellX - mMinX) * mCellSize; + int originY = (cellY - mMinY) * mCellSize; + + if (cellX > mMaxX || cellX < mMinX || cellY > mMaxY || cellY < mMinY) + return; + + requestOverlayTextureUpdate(originX, originY, mCellSize, mCellSize, localMapTexture, false, true); } void GlobalMap::clear() @@ -215,7 +306,6 @@ namespace MWRender assert(mOverlayImage->isDataContiguous()); } memset(mOverlayImage->data(), 0, mOverlayImage->getTotalSizeInBytes()); - mOverlayImage->dirty(); if (!mOverlayTexture) { @@ -224,9 +314,16 @@ namespace MWRender mOverlayTexture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); mOverlayTexture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR); mOverlayTexture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); - mOverlayTexture->setImage(mOverlayImage); mOverlayTexture->setResizeNonPowerOfTwoHint(false); + mOverlayTexture->setInternalFormat(GL_RGBA); + mOverlayTexture->setTextureSize(mWidth, mHeight); } + + mPendingImageDest.clear(); + + // just push a Camera to clear the FBO, instead of setImage()/dirty() + // easier, since we don't need to worry about synchronizing access :) + requestOverlayTextureUpdate(0, 0, mWidth, mHeight, osg::ref_ptr(), true, false); } void GlobalMap::write(ESM::GlobalMap& map) @@ -257,11 +354,15 @@ namespace MWRender struct Box { - int mLeft, mRight, mTop, mBottom; + int mLeft, mTop, mRight, mBottom; - Box(int left, int right, int top, int bottom) - : mLeft(left), mRight(right), mTop(top), mBottom(bottom) + Box(int left, int top, int right, int bottom) + : mLeft(left), mTop(top), mRight(right), mBottom(bottom) + { + } + bool operator == (const Box& other) { + return mLeft == other.mLeft && mTop == other.mTop && mRight == other.mRight && mBottom == other.mBottom; } }; @@ -336,20 +437,29 @@ namespace MWRender std::min(mWidth, mWidth + rightDiff * cellImageSizeDst), std::min(mHeight, mHeight + bottomDiff * cellImageSizeDst)); - if (srcBox.mLeft == destBox.mLeft && srcBox.mRight == destBox.mRight - && srcBox.mTop == destBox.mTop && srcBox.mBottom == destBox.mBottom - && imageWidth == mWidth && imageHeight == mHeight) + osg::ref_ptr texture (new osg::Texture2D); + texture->setImage(image); + texture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); + texture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); + texture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR); + texture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); + texture->setResizeNonPowerOfTwoHint(false); + + if (srcBox == destBox && imageWidth == mWidth && imageHeight == mHeight) { mOverlayImage->copySubImage(0, 0, 0, image); + + requestOverlayTextureUpdate(0, 0, mWidth, mHeight, texture, true, false); } else { - // TODO: // Dimensions don't match. This could mean a changed map region, or a changed map resolution. - // In the latter case, we'll want to use filtering. - // Create a RTT Camera and draw the image onto mOverlayImage in the next frame? + // In the latter case, we'll want filtering. + // Create a RTT Camera and draw the image onto mOverlayImage in the next frame. + requestOverlayTextureUpdate(destBox.mLeft, destBox.mTop, destBox.mRight-destBox.mLeft, destBox.mBottom-destBox.mTop, texture, true, true, + srcBox.mLeft/float(imageWidth), srcBox.mTop/float(imageHeight), + srcBox.mRight/float(imageWidth), srcBox.mBottom/float(imageHeight)); } - mOverlayImage->dirty(); } osg::ref_ptr GlobalMap::getBaseTexture() @@ -361,4 +471,37 @@ namespace MWRender { return mOverlayTexture; } + + void GlobalMap::markForRemoval(osg::Camera *camera) + { + CameraVector::iterator found = std::find(mActiveCameras.begin(), mActiveCameras.end(), camera); + if (found == mActiveCameras.end()) + { + std::cerr << "GlobalMap trying to remove an inactive camera" << std::endl; + return; + } + mActiveCameras.erase(found); + mCamerasPendingRemoval.push_back(camera); + } + + void GlobalMap::cleanupCameras() + { + for (CameraVector::iterator it = mCamerasPendingRemoval.begin(); it != mCamerasPendingRemoval.end(); ++it) + mRoot->removeChild(*it); + mCamerasPendingRemoval.clear(); + + for (ImageDestVector::iterator it = mPendingImageDest.begin(); it != mPendingImageDest.end();) + { + ImageDest& imageDest = *it; + if (--imageDest.mFramesUntilDone > 0) + { + ++it; + continue; + } + + mOverlayImage->copySubImage(imageDest.mX, imageDest.mY, 0, imageDest.mImage); + + it = mPendingImageDest.erase(it); + } + } } diff --git a/apps/openmw/mwrender/globalmap.hpp b/apps/openmw/mwrender/globalmap.hpp index 9ca7ed5b4..7adb8218a 100644 --- a/apps/openmw/mwrender/globalmap.hpp +++ b/apps/openmw/mwrender/globalmap.hpp @@ -10,6 +10,8 @@ namespace osg { class Texture2D; class Image; + class Group; + class Camera; } namespace Loading @@ -28,7 +30,7 @@ namespace MWRender class GlobalMap { public: - GlobalMap(); + GlobalMap(osg::Group* root); ~GlobalMap(); void render(Loading::Listener* loadingListener); @@ -42,11 +44,23 @@ namespace MWRender void cellTopLeftCornerToImageSpace(int x, int y, float& imageX, float& imageY); - void exploreCell (int cellX, int cellY); + void exploreCell (int cellX, int cellY, osg::ref_ptr localMapTexture); /// Clears the overlay void clear(); + /** + * Removes cameras that have already been rendered. Should be called every frame to ensure that + * we do not render the same map more than once. Note, this cleanup is difficult to implement in an + * automated fashion, since we can't alter the scene graph structure from within an update callback. + */ + void cleanupCameras(); + + /** + * Mark a camera for cleanup in the next update. For internal use only. + */ + void markForRemoval(osg::Camera* camera); + void write (ESM::GlobalMap& map); void read (ESM::GlobalMap& map); @@ -54,13 +68,48 @@ namespace MWRender osg::ref_ptr getOverlayTexture(); private: + /** + * Request rendering a 2d quad onto mOverlayTexture. + * x, y, width and height are the destination coordinates. + * @param cpuCopy copy the resulting render onto mOverlayImage as well? + */ + void requestOverlayTextureUpdate(int x, int y, int width, int height, osg::ref_ptr texture, bool clear, bool cpuCopy, + float srcLeft = 0.f, float srcTop = 0.f, float srcRight = 1.f, float srcBottom = 1.f); + int mCellSize; + osg::ref_ptr mRoot; + + typedef std::vector > CameraVector; + CameraVector mActiveCameras; + + CameraVector mCamerasPendingRemoval; + + struct ImageDest + { + ImageDest() + : mFramesUntilDone(3) // wait an extra frame to ensure the draw thread has completed its frame. + { + } + + osg::ref_ptr mImage; + int mX, mY; + int mFramesUntilDone; + }; + + typedef std::vector ImageDestVector; + + ImageDestVector mPendingImageDest; + std::vector< std::pair > mExploredCells; osg::ref_ptr mBaseTexture; + + // GPU copy of overlay + // Note, uploads are pushed through a Camera, instead of through mOverlayImage osg::ref_ptr mOverlayTexture; + // CPU copy of overlay osg::ref_ptr mOverlayImage; int mWidth; diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 495ea2d1d..edc88ac55 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -480,6 +480,11 @@ bool LocalMap::isPositionExplored (float nX, float nY, int x, int y, bool interi return alpha < 200; } +osg::Group* LocalMap::getRoot() +{ + return mRoot; +} + void LocalMap::updatePlayer (const osg::Vec3f& position, const osg::Quat& orientation, float& u, float& v, int& x, int& y, osg::Vec3f& direction) { diff --git a/apps/openmw/mwrender/localmap.hpp b/apps/openmw/mwrender/localmap.hpp index c319b7ce7..72ee0354e 100644 --- a/apps/openmw/mwrender/localmap.hpp +++ b/apps/openmw/mwrender/localmap.hpp @@ -101,6 +101,8 @@ namespace MWRender */ bool isPositionExplored (float nX, float nY, int x, int y, bool interior); + osg::Group* getRoot(); + private: osg::ref_ptr mViewer; From 7e715decd30948beffbc60d5089337465a123c07 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 29 May 2015 02:26:58 +0200 Subject: [PATCH 1301/3725] Color fix --- apps/openmw/mwrender/globalmap.cpp | 4 ++++ apps/openmw/mwrender/sky.cpp | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/apps/openmw/mwrender/globalmap.cpp b/apps/openmw/mwrender/globalmap.cpp index 1e30eb0fc..bcf9e74bf 100644 --- a/apps/openmw/mwrender/globalmap.cpp +++ b/apps/openmw/mwrender/globalmap.cpp @@ -47,6 +47,10 @@ namespace texcoords->push_back(osg::Vec2f(rightTexCoord, 1.f-topTexCoord)); texcoords->push_back(osg::Vec2f(rightTexCoord, 1.f-bottomTexCoord)); + osg::ref_ptr colors = new osg::Vec4Array; + colors->push_back(osg::Vec4(1.f, 1.f, 1.f, 1.f)); + geom->setColorArray(colors, osg::Array::BIND_OVERALL); + geom->setTexCoordArray(0, texcoords, osg::Array::BIND_PER_VERTEX); geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,4)); diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index d66761195..5b01edb16 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -75,6 +75,10 @@ namespace texcoords->push_back(osg::Vec2f(1, 1)); texcoords->push_back(osg::Vec2f(1, 0)); + osg::ref_ptr colors = new osg::Vec4Array; + colors->push_back(osg::Vec4(1.f, 1.f, 1.f, 1.f)); + geom->setColorArray(colors, osg::Array::BIND_OVERALL); + for (int i=0; isetTexCoordArray(i, texcoords, osg::Array::BIND_PER_VERTEX); From ce421b230b1938398a9559fdcc89c28c01a4a615 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Fri, 29 May 2015 14:07:41 +1000 Subject: [PATCH 1302/3725] Move scrollbar to newly opened subview. Should resolve Bug #2576. --- apps/opencs/view/doc/view.cpp | 21 +++++++++++++++------ apps/opencs/view/doc/view.hpp | 2 ++ 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 5e3df2739..c100e84e6 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -519,6 +519,10 @@ void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id, const std::strin } } + if (mScroll) + QObject::connect(mScroll->horizontalScrollBar(), + SIGNAL(rangeChanged(int,int)), this, SLOT(moveScrollBarToEnd(int,int))); + // User setting for limiting the number of sub views per top level view. // Automatically open a new top level view if this number is exceeded // @@ -590,12 +594,6 @@ void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id, const std::strin mSubViewWindow.setMinimumWidth(mSubViewWindow.width()+minWidth); move(0, y()); } - - // Make the new subview visible, setFocus() or raise() don't seem to work - // On Ubuntu the scrollbar does not go right to the end, even if using - // mScroll->horizontalScrollBar()->setValue(mScroll->horizontalScrollBar()->maximum()); - if (mSubViewWindow.width() > rect.width()) - mScroll->horizontalScrollBar()->setValue(mSubViewWindow.width()); } mSubViewWindow.addDockWidget (Qt::TopDockWidgetArea, view); @@ -618,6 +616,17 @@ void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id, const std::strin view->useHint (hint); } +void CSVDoc::View::moveScrollBarToEnd(int min, int max) +{ + if (mScroll) + { + mScroll->horizontalScrollBar()->setValue(max); + + QObject::disconnect(mScroll->horizontalScrollBar(), + SIGNAL(rangeChanged(int,int)), this, SLOT(moveScrollBarToEnd(int,int))); + } +} + void CSVDoc::View::newView() { mViewManager.addView (mDocument); diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index 1d44cb7f5..814dabc6b 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -233,6 +233,8 @@ namespace CSVDoc void stop(); void closeRequest (SubView *subView); + + void moveScrollBarToEnd(int min, int max); }; } From 393cee406fce7f0781c55451b53efd06427d2ab7 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Fri, 29 May 2015 19:28:25 +1000 Subject: [PATCH 1303/3725] Use signals for user preference setting updates. --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/tools/pathgridcheck.cpp | 15 +++++++++---- apps/opencs/model/tools/pathgridcheck.hpp | 7 +++++- apps/opencs/model/tools/signalhandler.cpp | 23 ++++++++++++++++++++ apps/opencs/model/tools/signalhandler.hpp | 26 +++++++++++++++++++++++ apps/opencs/model/tools/tools.cpp | 9 ++++++-- apps/opencs/model/tools/tools.hpp | 2 +- 7 files changed, 75 insertions(+), 9 deletions(-) create mode 100644 apps/opencs/model/tools/signalhandler.cpp create mode 100644 apps/opencs/model/tools/signalhandler.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 78b2deb7a..9ed0d6a8b 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -34,7 +34,7 @@ opencs_hdrs_noqt (model/world opencs_units (model/tools - tools reportmodel + tools reportmodel signalhandler ) opencs_units_noqt (model/tools diff --git a/apps/opencs/model/tools/pathgridcheck.cpp b/apps/opencs/model/tools/pathgridcheck.cpp index 58fdbeb2d..2b11b7066 100644 --- a/apps/opencs/model/tools/pathgridcheck.cpp +++ b/apps/opencs/model/tools/pathgridcheck.cpp @@ -10,14 +10,21 @@ #include "../settings/usersettings.hpp" -CSMTools::PathgridCheckStage::PathgridCheckStage (const CSMWorld::SubCellCollection& pathgrids) -: mPathgrids (pathgrids) +#include "signalhandler.hpp" + +CSMTools::PathgridCheckStage::PathgridCheckStage (const CSMWorld::SubCellCollection& pathgrids, + CSMTools::SignalHandler *signalHandler) +: mPathgrids (pathgrids), mSigHandler(signalHandler) {} +CSMTools::PathgridCheckStage::~PathgridCheckStage () +{ + delete mSigHandler; +} + int CSMTools::PathgridCheckStage::setup() { - CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); - mExtraCheck = userSettings.setting ("verifier/pathgrid-extra-check", QString ("false"))=="true"; + mExtraCheck = mSigHandler->extraCheck(); return mPathgrids.getSize(); } diff --git a/apps/opencs/model/tools/pathgridcheck.hpp b/apps/opencs/model/tools/pathgridcheck.hpp index 86ace6af2..8b5dc08a7 100644 --- a/apps/opencs/model/tools/pathgridcheck.hpp +++ b/apps/opencs/model/tools/pathgridcheck.hpp @@ -14,6 +14,7 @@ namespace CSMWorld namespace CSMTools { + class SignalHandler; struct Point { @@ -25,13 +26,17 @@ namespace CSMTools class PathgridCheckStage : public CSMDoc::Stage { bool mExtraCheck; + CSMTools::SignalHandler *mSigHandler; + const CSMWorld::SubCellCollection >& mPathgrids; public: PathgridCheckStage (const CSMWorld::SubCellCollection >& pathgrids); + CSMWorld::IdAccessor >& pathgrids, CSMTools::SignalHandler *signallHandler); + + ~PathgridCheckStage (); virtual int setup(); diff --git a/apps/opencs/model/tools/signalhandler.cpp b/apps/opencs/model/tools/signalhandler.cpp new file mode 100644 index 000000000..cfb52ed63 --- /dev/null +++ b/apps/opencs/model/tools/signalhandler.cpp @@ -0,0 +1,23 @@ +#include "signalhandler.hpp" + +#include "../settings/usersettings.hpp" + +CSMTools::SignalHandler::SignalHandler(bool extraCheck) + : mExtraCheck(extraCheck) +{ + connect (&CSMSettings::UserSettings::instance(), + SIGNAL (userSettingUpdated(const QString &, const QStringList &)), + this, + SLOT (updateUserSetting (const QString &, const QStringList &))); +} + +void CSMTools::SignalHandler::updateUserSetting (const QString &name, const QStringList &list) +{ + if (name=="verifier/pathgrid-extra-check") + mExtraCheck = list.at(0) == "true"; +} + +bool CSMTools::SignalHandler::extraCheck () +{ + return mExtraCheck; +} diff --git a/apps/opencs/model/tools/signalhandler.hpp b/apps/opencs/model/tools/signalhandler.hpp new file mode 100644 index 000000000..c3d075fdf --- /dev/null +++ b/apps/opencs/model/tools/signalhandler.hpp @@ -0,0 +1,26 @@ +#ifndef CSM_TOOLS_SIGNALHANDLER_H +#define CSM_TOOLS_SIGNALHANDLER_H + +#include + +namespace CSMTools +{ + class SignalHandler : public QObject + { + Q_OBJECT + + bool mExtraCheck; + + public: + + SignalHandler (bool extraCheck); + + bool extraCheck (); + + public slots: + + void updateUserSetting (const QString &name, const QStringList &list); + }; +} + +#endif diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index 8d93a9433..45c7fbae3 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -10,6 +10,8 @@ #include "../world/data.hpp" #include "../world/universalid.hpp" +#include "../settings/usersettings.hpp" + #include "reportmodel.hpp" #include "mandatoryid.hpp" #include "skillcheck.hpp" @@ -27,6 +29,7 @@ #include "startscriptcheck.hpp" #include "searchoperation.hpp" #include "pathgridcheck.hpp" +#include "signalhandler.hpp" CSMDoc::OperationHolder *CSMTools::Tools::get (int type) { @@ -56,6 +59,8 @@ CSMDoc::OperationHolder *CSMTools::Tools::getVerifier() SIGNAL (reportMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int)), this, SLOT (verifierMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int))); + CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); + std::vector mandatoryIds; // I want C++11, damn it! mandatoryIds.push_back ("Day"); mandatoryIds.push_back ("DaysPassed"); @@ -97,7 +102,8 @@ CSMDoc::OperationHolder *CSMTools::Tools::getVerifier() CSMWorld::UniversalId( CSMWorld::UniversalId::Type_Meshes )), mData.getRaces() )); - mVerifierOperation->appendStage (new PathgridCheckStage (mData.getPathgrids())); + mVerifierOperation->appendStage (new PathgridCheckStage (mData.getPathgrids(), + new SignalHandler(userSettings.setting ("verifier/pathgrid-extra-check", QString ("false"))=="true"))); mVerifier.setOperation (mVerifierOperation); } @@ -213,4 +219,3 @@ void CSMTools::Tools::verifierMessage (const CSMWorld::UniversalId& id, const st if (iter!=mActiveReports.end()) mReports[iter->second]->add (id, message, hint); } - diff --git a/apps/opencs/model/tools/tools.hpp b/apps/opencs/model/tools/tools.hpp index 0f9e57044..dc19cf456 100644 --- a/apps/opencs/model/tools/tools.hpp +++ b/apps/opencs/model/tools/tools.hpp @@ -64,7 +64,7 @@ namespace CSMTools CSMWorld::UniversalId newSearch(); void runSearch (const CSMWorld::UniversalId& searchId, const Search& search); - + void abortOperation (int type); ///< \attention The operation is not aborted immediately. From 9cbda0ffada698d45e404c02775bc78d09351636 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Fri, 29 May 2015 22:20:43 +1000 Subject: [PATCH 1304/3725] Allow users to select syntax highlighting colours. Should resolve Feature #2507. --- apps/opencs/model/settings/usersettings.cpp | 36 +++++ apps/opencs/view/world/scriptedit.cpp | 22 ++-- apps/opencs/view/world/scriptedit.hpp | 7 +- apps/opencs/view/world/scripthighlighter.cpp | 132 +++++++++++++++++-- apps/opencs/view/world/scripthighlighter.hpp | 2 + 5 files changed, 182 insertions(+), 17 deletions(-) diff --git a/apps/opencs/model/settings/usersettings.cpp b/apps/opencs/model/settings/usersettings.cpp index ea002c5ed..5b6e7ab8b 100644 --- a/apps/opencs/model/settings/usersettings.cpp +++ b/apps/opencs/model/settings/usersettings.cpp @@ -262,6 +262,42 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() Setting *monoFont = createSetting (Type_CheckBox, "mono-font", "Use monospace font"); monoFont->setDefaultValue ("true"); monoFont->setToolTip ("Whether to use monospaced fonts on script edit subview."); + + QString tooltip = + "\n#RGB (each of R, G, and B is a single hex digit)" + "\n#RRGGBB" + "\n#RRRGGGBBB" + "\n#RRRRGGGGBBBB" + "\nA name from the list of colors defined in the list of SVG color keyword names." + "\nX11 color names may also work."; + + Setting *formatInt = createSetting (Type_LineEdit, "colour-int", "Highlight Colour: Int"); + formatInt->setDefaultValues (QStringList() << "Dark magenta"); + formatInt->setToolTip ("(Default: Green) Use one of the following formats:" + tooltip); + + Setting *formatFloat = createSetting (Type_LineEdit, "colour-float", "Highlight Colour: Float"); + formatFloat->setDefaultValues (QStringList() << "Magenta"); + formatFloat->setToolTip ("(Default: Magenta) Use one of the following formats:" + tooltip); + + Setting *formatName = createSetting (Type_LineEdit, "colour-name", "Highlight Colour: Name"); + formatName->setDefaultValues (QStringList() << "Gray"); + formatName->setToolTip ("(Default: Gray) Use one of the following formats:" + tooltip); + + Setting *formatKeyword = createSetting (Type_LineEdit, "colour-keyword", "Highlight Colour: Keyword"); + formatKeyword->setDefaultValues (QStringList() << "Red"); + formatKeyword->setToolTip ("(Default: Red) Use one of the following formats:" + tooltip); + + Setting *formatSpecial = createSetting (Type_LineEdit, "colour-special", "Highlight Colour: Special"); + formatSpecial->setDefaultValues (QStringList() << "Dark yellow"); + formatSpecial->setToolTip ("(Default: Dark yellow) Use one of the following formats:" + tooltip); + + Setting *formatComment = createSetting (Type_LineEdit, "colour-comment", "Highlight Colour: Comment"); + formatComment->setDefaultValues (QStringList() << "Green"); + formatComment->setToolTip ("(Default: Green) Use one of the following formats:" + tooltip); + + Setting *formatId = createSetting (Type_LineEdit, "colour-id", "Highlight Colour: Id"); + formatId->setDefaultValues (QStringList() << "Blue"); + formatId->setToolTip ("(Default: Blue) Use one of the following formats:" + tooltip); } { diff --git a/apps/opencs/view/world/scriptedit.cpp b/apps/opencs/view/world/scriptedit.cpp index 2f0d82ae1..ad2cddbf8 100644 --- a/apps/opencs/view/world/scriptedit.cpp +++ b/apps/opencs/view/world/scriptedit.cpp @@ -31,11 +31,11 @@ bool CSVWorld::ScriptEdit::event (QEvent *event) if (event->type()==QEvent::ShortcutOverride) { QKeyEvent *keyEvent = static_cast (event); - + if (keyEvent->matches (QKeySequence::Undo) || keyEvent->matches (QKeySequence::Redo)) return true; } - + return QPlainTextEdit::event (event); } @@ -92,13 +92,16 @@ CSVWorld::ScriptEdit::ScriptEdit (const CSMDoc::Document& document, ScriptHighli connect (&mUpdateTimer, SIGNAL (timeout()), this, SLOT (updateHighlighting())); + CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); + connect (&userSettings, SIGNAL (userSettingUpdated(const QString &, const QStringList &)), + this, SLOT (updateUserSetting (const QString &, const QStringList &))); + mUpdateTimer.setSingleShot (true); // TODO: provide a font selector dialogue mMonoFont.setStyleHint(QFont::TypeWriter); - std::string useMonoFont = - CSMSettings::UserSettings::instance().setting("script-editor/mono-font", "true").toStdString(); - if (useMonoFont == "true") + + if (userSettings.setting("script-editor/mono-font", "true") == "true") setFont(mMonoFont); mLineNumberArea = new LineNumberArea(this); @@ -107,10 +110,13 @@ CSVWorld::ScriptEdit::ScriptEdit (const CSMDoc::Document& document, ScriptHighli connect(this, SIGNAL(blockCountChanged(int)), this, SLOT(updateLineNumberAreaWidth(int))); connect(this, SIGNAL(updateRequest(QRect,int)), this, SLOT(updateLineNumberArea(QRect,int))); - std::string showStatusBar = - CSMSettings::UserSettings::instance().settingValue("script-editor/show-linenum").toStdString(); + showLineNum(userSettings.settingValue("script-editor/show-linenum") == "true"); +} - showLineNum(showStatusBar == "true"); +void CSVWorld::ScriptEdit::updateUserSetting (const QString &name, const QStringList &list) +{ + if (mHighlighter->updateUserSetting (name, list)) + updateHighlighting(); } void CSVWorld::ScriptEdit::showLineNum(bool show) diff --git a/apps/opencs/view/world/scriptedit.hpp b/apps/opencs/view/world/scriptedit.hpp index fb577e60e..d17abf24e 100644 --- a/apps/opencs/view/world/scriptedit.hpp +++ b/apps/opencs/view/world/scriptedit.hpp @@ -56,7 +56,7 @@ namespace CSVWorld protected: bool event (QEvent *event); - + public: ScriptEdit (const CSMDoc::Document& document, ScriptHighlighter::Mode mode, @@ -96,7 +96,12 @@ namespace CSVWorld void updateHighlighting(); void updateLineNumberAreaWidth(int newBlockCount); + void updateLineNumberArea(const QRect &, int); + + public slots: + + void updateUserSetting (const QString &name, const QStringList &list); }; class LineNumberArea : public QWidget diff --git a/apps/opencs/view/world/scripthighlighter.cpp b/apps/opencs/view/world/scripthighlighter.cpp index 6dda8d4fa..4923a44d8 100644 --- a/apps/opencs/view/world/scripthighlighter.cpp +++ b/apps/opencs/view/world/scripthighlighter.cpp @@ -6,6 +6,8 @@ #include #include +#include "../../model/settings/usersettings.hpp" + bool CSVWorld::ScriptHighlighter::parseInt (int value, const Compiler::TokenLoc& loc, Compiler::Scanner& scanner) { @@ -78,46 +80,77 @@ CSVWorld::ScriptHighlighter::ScriptHighlighter (const CSMWorld::Data& data, Mode : QSyntaxHighlighter (parent), Compiler::Parser (mErrorHandler, mContext), mContext (data), mMode (mode) { - /// \todo replace this with user settings + CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); + + QColor color = QColor(); + { + color.setNamedColor(userSettings.setting("script-editor/colour-int", "Dark magenta")); + if (!color.isValid()) + color = QColor(Qt::darkMagenta); + QTextCharFormat format; - format.setForeground (Qt::darkMagenta); + format.setForeground (color); mScheme.insert (std::make_pair (Type_Int, format)); } { + color.setNamedColor(userSettings.setting ("script-editor/colour-float", "Magenta")); + if (!color.isValid()) + color = QColor(Qt::magenta); + QTextCharFormat format; - format.setForeground (Qt::magenta); + format.setForeground (color); mScheme.insert (std::make_pair (Type_Float, format)); } { + color.setNamedColor(userSettings.setting ("script-editor/colour-name", "Gray")); + if (!color.isValid()) + color = QColor(Qt::gray); + QTextCharFormat format; - format.setForeground (Qt::gray); + format.setForeground (color); mScheme.insert (std::make_pair (Type_Name, format)); } { + color.setNamedColor(userSettings.setting ("script-editor/colour-keyword", "Red")); + if (!color.isValid()) + color = QColor(Qt::red); + QTextCharFormat format; - format.setForeground (Qt::red); + format.setForeground (color); mScheme.insert (std::make_pair (Type_Keyword, format)); } { + color.setNamedColor(userSettings.setting ("script-editor/colour-special", "Dark yellow")); + if (!color.isValid()) + color = QColor(Qt::darkYellow); + QTextCharFormat format; - format.setForeground (Qt::darkYellow); + format.setForeground (color); mScheme.insert (std::make_pair (Type_Special, format)); } { + color.setNamedColor(userSettings.setting ("script-editor/colour-comment", "Green")); + if (!color.isValid()) + color = QColor(Qt::green); + QTextCharFormat format; - format.setForeground (Qt::green); + format.setForeground (color); mScheme.insert (std::make_pair (Type_Comment, format)); } { + color.setNamedColor(userSettings.setting ("script-editor/colour-id", "Blue")); + if (!color.isValid()) + color = QColor(Qt::blue); + QTextCharFormat format; - format.setForeground (Qt::blue); + format.setForeground (color); mScheme.insert (std::make_pair (Type_Id, format)); } @@ -143,3 +176,86 @@ void CSVWorld::ScriptHighlighter::invalidateIds() { mContext.invalidateIds(); } + +bool CSVWorld::ScriptHighlighter::updateUserSetting (const QString &name, const QStringList &list) +{ + if (list.empty()) + return false; + + QColor color = QColor(); + + if (name == "script-editor/colour-int") + { + color.setNamedColor(list.at(0)); + if (!color.isValid()) + return false; + + QTextCharFormat format; + format.setForeground (color); + mScheme[Type_Int] = format; + } + else if (name == "script-editor/colour-float") + { + color.setNamedColor(list.at(0)); + if (!color.isValid()) + return false; + + QTextCharFormat format; + format.setForeground (color); + mScheme[Type_Float] = format; + } + else if (name == "script-editor/colour-name") + { + color.setNamedColor(list.at(0)); + if (!color.isValid()) + return false; + + QTextCharFormat format; + format.setForeground (color); + mScheme[Type_Name] = format; + } + else if (name == "script-editor/colour-keyword") + { + color.setNamedColor(list.at(0)); + if (!color.isValid()) + return false; + + QTextCharFormat format; + format.setForeground (color); + mScheme[Type_Keyword] = format; + } + else if (name == "script-editor/colour-special") + { + color.setNamedColor(list.at(0)); + if (!color.isValid()) + return false; + + QTextCharFormat format; + format.setForeground (color); + mScheme[Type_Special] = format; + } + else if (name == "script-editor/colour-comment") + { + color.setNamedColor(list.at(0)); + if (!color.isValid()) + return false; + + QTextCharFormat format; + format.setForeground (color); + mScheme[Type_Comment] = format; + } + else if (name == "script-editor/colour-id") + { + color.setNamedColor(list.at(0)); + if (!color.isValid()) + return false; + + QTextCharFormat format; + format.setForeground (color); + mScheme[Type_Id] = format; + } + else + return false; + + return true; +} diff --git a/apps/opencs/view/world/scripthighlighter.hpp b/apps/opencs/view/world/scripthighlighter.hpp index 953f2f953..6f1f58e82 100644 --- a/apps/opencs/view/world/scripthighlighter.hpp +++ b/apps/opencs/view/world/scripthighlighter.hpp @@ -87,6 +87,8 @@ namespace CSVWorld virtual void highlightBlock (const QString& text); void invalidateIds(); + + bool updateUserSetting (const QString &name, const QStringList &list); }; } From b75d993da4635d2ee4f11b70738c75e15506cfec Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 29 May 2015 14:25:47 +0200 Subject: [PATCH 1305/3725] Fix for BULLET_DYNAMICS_LIBRARY cmake leftover --- cmake/FindBullet.cmake | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cmake/FindBullet.cmake b/cmake/FindBullet.cmake index 5204c00ce..6d5c517af 100644 --- a/cmake/FindBullet.cmake +++ b/cmake/FindBullet.cmake @@ -66,7 +66,8 @@ _FIND_BULLET_LIBRARY(BULLET_MATH_LIBRARY_DEBUG BulletMath_Debug BulletMath_ # all listed variables are TRUE include(FindPackageHandleStandardArgs) FIND_PACKAGE_HANDLE_STANDARD_ARGS(Bullet DEFAULT_MSG - BULLET_DYNAMICS_LIBRARY BULLET_COLLISION_LIBRARY BULLET_MATH_LIBRARY + #BULLET_DYNAMICS_LIBRARY + BULLET_COLLISION_LIBRARY BULLET_MATH_LIBRARY BULLET_INCLUDE_DIR) set(BULLET_INCLUDE_DIRS ${BULLET_INCLUDE_DIR}) From 261ed1f4e5119f0d30d855393149143d32df8c45 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 29 May 2015 20:31:26 +0200 Subject: [PATCH 1306/3725] Revert "Enable culling for particle emitters & programs" This reverts commit 8b206e0aeda6feee2470a61aa363a79dbe3ba25f. --- components/nifosg/nifloader.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 5fdf964c4..219f6e194 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -682,7 +682,6 @@ namespace NifOsg attachTo->addChild(program); program->setParticleSystem(partsys); program->setReferenceFrame(rf); - program->setCullingActive(true); for (; !affectors.empty(); affectors = affectors->extra) { if (affectors->recType == Nif::RC_NiParticleGrowFade) @@ -829,7 +828,6 @@ namespace NifOsg osg::ref_ptr emitter = handleParticleEmitter(partctrl); emitter->setParticleSystem(partsys); emitter->setReferenceFrame(osgParticle::ParticleProcessor::RELATIVE_RF); - emitter->setCullingActive(true); // Note: we assume that the Emitter node is placed *before* the Particle node in the scene graph. // This seems to be true for all NIF files in the game that I've checked, suggesting that NIFs work similar to OSG with regards to update order. @@ -870,7 +868,6 @@ namespace NifOsg // particle system updater (after the emitters and affectors in the scene graph) // I think for correct culling needs to be *before* the ParticleSystem, though osg examples do it the other way osg::ref_ptr updater = new osgParticle::ParticleSystemUpdater; - updater->setCullingActive(true); updater->addParticleSystem(partsys); parentNode->addChild(updater); From af2f26d04d124395903265c6a1dfb2a14fd4b89f Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 29 May 2015 20:45:27 +0200 Subject: [PATCH 1307/3725] Particle fixes --- apps/openmw/mwmechanics/character.cpp | 8 ++------ apps/openmw/mwrender/animation.cpp | 8 ++++---- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 7588a3287..9feb831c9 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1172,14 +1172,10 @@ bool CharacterController::updateWeaponState() effect = store.get().find(effectentry.mEffectID); const ESM::Static* castStatic = MWBase::Environment::get().getWorld()->getStore().get().find ("VFX_Hands"); - if (mAnimation->hasNode("Left Hand")) - mAnimation->addEffect("meshes\\" + castStatic->mModel, -1, false, "Left Hand", effect->mParticle); - else + if (mAnimation->hasNode("Bip01 L Hand")) mAnimation->addEffect("meshes\\" + castStatic->mModel, -1, false, "Bip01 L Hand", effect->mParticle); - if (mAnimation->hasNode("Right Hand")) - mAnimation->addEffect("meshes\\" + castStatic->mModel, -1, false, "Right Hand", effect->mParticle); - else + if (mAnimation->hasNode("Bip01 R Hand")) mAnimation->addEffect("meshes\\" + castStatic->mModel, -1, false, "Bip01 R Hand", effect->mParticle); switch(effectentry.mRange) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 91f4f766e..327f59df8 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1042,11 +1042,11 @@ namespace MWRender parentNode = mObjectRoot->asGroup(); else { - SceneUtil::FindByNameVisitor visitor(bonename); - mObjectRoot->accept(visitor); - if (!visitor.mFoundNode) + NodeMap::iterator found = mNodeMap.find(Misc::StringUtils::lowerCase(bonename)); + if (found == mNodeMap.end()) throw std::runtime_error("Can't find bone " + bonename); - parentNode = visitor.mFoundNode; + + parentNode = found->second; } osg::ref_ptr node = mResourceSystem->getSceneManager()->createInstance(model, parentNode); params.mObjects = PartHolderPtr(new PartHolder(node)); From 668d365ef9a5d2a3366c4cbc7a10510dd0b2b199 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 29 May 2015 21:47:43 +0200 Subject: [PATCH 1308/3725] MorphGeometry copy fix --- components/sceneutil/clone.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/components/sceneutil/clone.cpp b/components/sceneutil/clone.cpp index 237417974..0131adc89 100644 --- a/components/sceneutil/clone.cpp +++ b/components/sceneutil/clone.cpp @@ -51,7 +51,9 @@ namespace SceneUtil if (dynamic_cast(drawable) || dynamic_cast(drawable)) { - osg::Drawable* cloned = osg::clone(drawable, *this); + osg::CopyOp copyop = *this; + copyop.setCopyFlags(copyop.getCopyFlags()|osg::CopyOp::DEEP_COPY_ARRAYS); + osg::Drawable* cloned = osg::clone(drawable, copyop); if (cloned->getUpdateCallback()) cloned->setUpdateCallback(osg::clone(cloned->getUpdateCallback(), *this)); return cloned; From 5c7ecb9c1d93cf2290fcca025aa5c06a1637d563 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 29 May 2015 23:38:31 +0200 Subject: [PATCH 1309/3725] string::compare exception fix --- apps/openmw/mwrender/animation.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 327f59df8..fed96f213 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -421,10 +421,14 @@ namespace MWRender size_t off = groupname.size()+2; size_t len = evt.size() - off; - if(evt.compare(off, len, "loop start") == 0) - state.mLoopStartTime = key->first; - else if(evt.compare(off, len, "loop stop") == 0) - state.mLoopStopTime = key->first; + if(evt.compare(0, groupname.size(), groupname) == 0 && + evt.compare(groupname.size(), 2, ": ") == 0) + { + if(evt.compare(off, len, "loop start") == 0) + state.mLoopStartTime = key->first; + else if(evt.compare(off, len, "loop stop") == 0) + state.mLoopStopTime = key->first; + } if (mTextKeyListener) mTextKeyListener->handleTextKey(groupname, key, map); From a56d0e9cc3d7e82de78ffeab7b775c6a2d6efa82 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 29 May 2015 23:39:52 +0200 Subject: [PATCH 1310/3725] ControllerVisitor fix --- components/sceneutil/controller.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/sceneutil/controller.cpp b/components/sceneutil/controller.cpp index 6beb1bc80..4b51485f2 100644 --- a/components/sceneutil/controller.cpp +++ b/components/sceneutil/controller.cpp @@ -90,6 +90,8 @@ namespace SceneUtil if (Controller* ctrl = dynamic_cast(callback)) visit(geode, *ctrl); } + + apply(static_cast(geode)); } AssignControllerSourcesVisitor::AssignControllerSourcesVisitor() From 0aaac59cc3cfdd834ed36d3585ffc96b38237f67 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 30 May 2015 08:37:58 +1000 Subject: [PATCH 1311/3725] Return to startup dialog when the open/create action is cancelled. Should resolve Bug #2588. --- apps/opencs/editor.cpp | 30 +++++++++++++++++++++++ apps/opencs/editor.hpp | 2 ++ apps/opencs/model/doc/documentmanager.cpp | 5 ++++ apps/opencs/model/doc/documentmanager.hpp | 2 ++ apps/opencs/view/doc/newgame.cpp | 6 +++++ apps/opencs/view/doc/newgame.hpp | 4 +++ 6 files changed, 49 insertions(+) diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 53a9e9e83..84849cbbb 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -67,9 +67,11 @@ CS::Editor::Editor (OgreInit::OgreInit& ogreInit) connect (&mFileDialog, SIGNAL(signalCreateNewFile (const boost::filesystem::path&)), this, SLOT(createNewFile (const boost::filesystem::path&))); + connect (&mFileDialog, SIGNAL (rejected()), this, SLOT (cancelFileDialog ())); connect (&mNewGame, SIGNAL (createRequest (const boost::filesystem::path&)), this, SLOT (createNewGame (const boost::filesystem::path&))); + connect (&mNewGame, SIGNAL (cancelCreateGame()), this, SLOT (cancelCreateGame ())); } CS::Editor::~Editor () @@ -176,12 +178,40 @@ void CS::Editor::createGame() mNewGame.activateWindow(); } +void CS::Editor::cancelCreateGame() +{ + if (!mDocumentManager.isEmpty()) + return; + + mNewGame.hide(); + + if (mStartup.isHidden()) + mStartup.show(); + + mStartup.raise(); + mStartup.activateWindow(); +} + void CS::Editor::createAddon() { mStartup.hide(); mFileDialog.showDialog (CSVDoc::ContentAction_New); } +void CS::Editor::cancelFileDialog() +{ + if (!mDocumentManager.isEmpty()) + return; + + mFileDialog.hide(); + + if (mStartup.isHidden()) + mStartup.show(); + + mStartup.raise(); + mStartup.activateWindow(); +} + void CS::Editor::loadDocument() { mStartup.hide(); diff --git a/apps/opencs/editor.hpp b/apps/opencs/editor.hpp index 273f0825b..eb85743a3 100644 --- a/apps/opencs/editor.hpp +++ b/apps/opencs/editor.hpp @@ -87,6 +87,8 @@ namespace CS void createGame(); void createAddon(); + void cancelCreateGame(); + void cancelFileDialog(); void loadDocument(); void openFiles (const boost::filesystem::path &path); diff --git a/apps/opencs/model/doc/documentmanager.cpp b/apps/opencs/model/doc/documentmanager.cpp index 2d444f245..29d7a8d3a 100644 --- a/apps/opencs/model/doc/documentmanager.cpp +++ b/apps/opencs/model/doc/documentmanager.cpp @@ -49,6 +49,11 @@ CSMDoc::DocumentManager::~DocumentManager() delete *iter; } +bool CSMDoc::DocumentManager::isEmpty() +{ + return mDocuments.empty(); +} + void CSMDoc::DocumentManager::addDocument (const std::vector& files, const boost::filesystem::path& savePath, bool new_) { diff --git a/apps/opencs/model/doc/documentmanager.hpp b/apps/opencs/model/doc/documentmanager.hpp index 0ae73e70c..f3fcbf8ec 100644 --- a/apps/opencs/model/doc/documentmanager.hpp +++ b/apps/opencs/model/doc/documentmanager.hpp @@ -59,6 +59,8 @@ namespace CSMDoc /// Ask OGRE for a list of available resources. void listResources(); + bool isEmpty(); + private: boost::filesystem::path mResDir; diff --git a/apps/opencs/view/doc/newgame.cpp b/apps/opencs/view/doc/newgame.cpp index 98681c499..32b483728 100644 --- a/apps/opencs/view/doc/newgame.cpp +++ b/apps/opencs/view/doc/newgame.cpp @@ -66,3 +66,9 @@ void CSVDoc::NewGameDialogue::create() { emit createRequest (mAdjusterWidget->getPath()); } + +void CSVDoc::NewGameDialogue::reject() +{ + emit cancelCreateGame (); + QDialog::reject(); +} diff --git a/apps/opencs/view/doc/newgame.hpp b/apps/opencs/view/doc/newgame.hpp index 9ad7ea169..70e9d684b 100644 --- a/apps/opencs/view/doc/newgame.hpp +++ b/apps/opencs/view/doc/newgame.hpp @@ -36,11 +36,15 @@ namespace CSVDoc void createRequest (const boost::filesystem::path& file); + void cancelCreateGame (); + private slots: void stateChanged (bool valid); void create(); + + void reject(); }; } From 6231cd8557079eb8951456b0baadb2e153685070 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 30 May 2015 00:59:34 +0200 Subject: [PATCH 1312/3725] RigGeometry clone fix --- components/sceneutil/clone.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/components/sceneutil/clone.cpp b/components/sceneutil/clone.cpp index 0131adc89..36c5c02a1 100644 --- a/components/sceneutil/clone.cpp +++ b/components/sceneutil/clone.cpp @@ -48,8 +48,7 @@ namespace SceneUtil { if (const osgParticle::ParticleSystem* partsys = dynamic_cast(drawable)) return operator()(partsys); - if (dynamic_cast(drawable) - || dynamic_cast(drawable)) + if (dynamic_cast(drawable)) { osg::CopyOp copyop = *this; copyop.setCopyFlags(copyop.getCopyFlags()|osg::CopyOp::DEEP_COPY_ARRAYS); @@ -58,6 +57,11 @@ namespace SceneUtil cloned->setUpdateCallback(osg::clone(cloned->getUpdateCallback(), *this)); return cloned; } + if (dynamic_cast(drawable)) + { + return osg::clone(drawable, *this); + } + return osg::CopyOp::operator()(drawable); } From fd50be0fb8787c04901c1d504d86ebe67efc5c82 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 30 May 2015 01:00:24 +0200 Subject: [PATCH 1313/3725] Restore various gameplay --- apps/openmw/mwmechanics/aiwander.cpp | 11 ++---- apps/openmw/mwmechanics/character.cpp | 24 +++---------- apps/openmw/mwmechanics/combat.cpp | 23 +++++++------ .../mwmechanics/mechanicsmanagerimp.cpp | 34 +++++++++---------- apps/openmw/mwmechanics/spellcasting.cpp | 17 +++++----- apps/openmw/mwmechanics/summoning.cpp | 6 ++-- apps/openmw/mwworld/refdata.cpp | 17 ++++------ apps/openmw/mwworld/refdata.hpp | 12 +------ apps/openmw/mwworld/worldimp.cpp | 2 +- components/sceneutil/controller.hpp | 1 + 10 files changed, 57 insertions(+), 90 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index b4476de11..6593bbf89 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -473,14 +473,9 @@ namespace MWMechanics { Ogre::Vector3 dir = playerPos - actorPos; - Ogre::Radian faceAngle = Ogre::Math::ATan2(dir.x,dir.y); - Ogre::Radian actorAngle = actor.getRefData().getBaseNodeOld()->getOrientation().getRoll(); - // an attempt at reducing the turning animation glitch - if( Ogre::Math::Abs( faceAngle - actorAngle ) >= Ogre::Degree(5) ) // TODO: is there a better way? - { - targetAngle = faceAngle; - rotate = true; - } + float faceAngleRadians = std::atan2(dir.x, dir.y); + targetAngle = faceAngleRadians; + rotate = true; } if (greetingTimer >= GREETING_SHOULD_END) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 9feb831c9..a8a6f74aa 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -816,26 +816,12 @@ void CharacterController::handleTextKey(const std::string &groupname, const std: else if (evt.compare(off, len, "shoot follow attach") == 0) mAnimation->attachArrow(); - else if (groupname == "spellcast" && evt.substr(evt.size()-7, 7) == "release") + else if (groupname == "spellcast" && evt.substr(evt.size()-7, 7) == "release" + // Make sure this key is actually for the RangeType we are casting. The flame atronach has + // the same animation for all range types, so there are 3 "release" keys on the same time, one for each range type. + && evt.compare(off, len, mAttackType + " release") == 0) { - // Make sure this key is actually for the RangeType we are casting. The flame atronach has - // the same animation for all range types, so there are 3 "release" keys on the same time, one for each range type. - // FIXME: compare with mCurrentWeapon instead - const std::string& spellid = mPtr.getClass().getCreatureStats(mPtr).getSpells().getSelectedSpell(); - const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get().find(spellid); - const ESM::ENAMstruct &effectentry = spell->mEffects.mList.at(0); - int range = 0; - if (evt.compare(off, len, "self release") == 0) - range = 0; - else if (evt.compare(off, len, "touch release") == 0) - range = 1; - else if (evt.compare(off, len, "target release") == 0) - range = 2; - if (effectentry.mRange == range) - { - MWBase::Environment::get().getWorld()->castSpell(mPtr); - } - std::cout << "current attack: " << mCurrentWeapon << std::endl; + MWBase::Environment::get().getWorld()->castSpell(mPtr); } else if (groupname == "shield" && evt.compare(off, len, "block hit") == 0) diff --git a/apps/openmw/mwmechanics/combat.cpp b/apps/openmw/mwmechanics/combat.cpp index 97dea7341..ee48d124f 100644 --- a/apps/openmw/mwmechanics/combat.cpp +++ b/apps/openmw/mwmechanics/combat.cpp @@ -1,6 +1,6 @@ #include "combat.hpp" -#include +#include #include @@ -23,12 +23,9 @@ namespace { -Ogre::Radian signedAngle(Ogre::Vector3 v1, Ogre::Vector3 v2, Ogre::Vector3 normal) +float signedAngleRadians (const osg::Vec3f& v1, const osg::Vec3f& v2, const osg::Vec3f& normal) { - return Ogre::Math::ATan2( - normal.dotProduct( v1.crossProduct(v2) ), - v1.dotProduct(v2) - ); + return std::atan2((normal * (v1 ^ v2)), (v1 * v2)); } bool applyEnchantment (const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim, const MWWorld::Ptr& object, const Ogre::Vector3& hitPosition) @@ -74,13 +71,19 @@ namespace MWMechanics if (shield == inv.end() || shield->getTypeName() != typeid(ESM::Armor).name()) return false; - Ogre::Degree angle = signedAngle (Ogre::Vector3(attacker.getRefData().getPosition().pos) - Ogre::Vector3(blocker.getRefData().getPosition().pos), - blocker.getRefData().getBaseNodeOld()->getOrientation().yAxis(), Ogre::Vector3(0,0,1)); + if (!blocker.getRefData().getBaseNode()) + return false; // shouldn't happen + + float angleDegrees = osg::RadiansToDegrees( + signedAngleRadians ( + (attacker.getRefData().getPosition().asVec3() - blocker.getRefData().getPosition().asVec3()), + blocker.getRefData().getBaseNode()->getAttitude() * osg::Vec3f(0,1,0), + osg::Vec3f(0,0,1))); const MWWorld::Store& gmst = MWBase::Environment::get().getWorld()->getStore().get(); - if (angle.valueDegrees() < gmst.find("fCombatBlockLeftAngle")->getFloat()) + if (angleDegrees < gmst.find("fCombatBlockLeftAngle")->getFloat()) return false; - if (angle.valueDegrees() > gmst.find("fCombatBlockRightAngle")->getFloat()) + if (angleDegrees > gmst.find("fCombatBlockRightAngle")->getFloat()) return false; MWMechanics::CreatureStats& attackerStats = attacker.getClass().getCreatureStats(attacker); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 72a68e96b..0ae9395c5 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1,6 +1,8 @@ - #include "mechanicsmanagerimp.hpp" -#include "npcstats.hpp" + +#include + +#include #include @@ -20,12 +22,9 @@ #include "../mwmechanics/aicombat.hpp" #include "../mwmechanics/aipursue.hpp" -#include - #include "spellcasting.hpp" #include "autocalcspell.hpp" - -#include +#include "npcstats.hpp" namespace { @@ -1332,8 +1331,6 @@ namespace MWMechanics bool MechanicsManager::awarenessCheck(const MWWorld::Ptr &ptr, const MWWorld::Ptr &observer) { - return false; - if (observer.getClass().getCreatureStats(observer).isDead() || !observer.getRefData().isEnabled()) return false; @@ -1369,9 +1366,9 @@ namespace MWMechanics static float fSneakDistBase = store.find("fSneakDistanceBase")->getFloat(); static float fSneakDistMult = store.find("fSneakDistanceMultiplier")->getFloat(); - Ogre::Vector3 pos1 (ptr.getRefData().getPosition().pos); - Ogre::Vector3 pos2 (observer.getRefData().getPosition().pos); - float distTerm = fSneakDistBase + fSneakDistMult * pos1.distance(pos2); + osg::Vec3f pos1 (ptr.getRefData().getPosition().asVec3()); + osg::Vec3f pos2 (observer.getRefData().getPosition().asVec3()); + float distTerm = fSneakDistBase + fSneakDistMult * (pos1 - pos2).length(); float chameleon = stats.getMagicEffects().get(ESM::MagicEffect::Chameleon).getMagnitude(); float x = sneakTerm * distTerm * stats.getFatigueTerm() + chameleon + invisibility; @@ -1388,12 +1385,15 @@ namespace MWMechanics static float fSneakNoViewMult = store.find("fSneakNoViewMult")->getFloat(); static float fSneakViewMult = store.find("fSneakViewMult")->getFloat(); float y = 0; - Ogre::Vector3 vec = pos1 - pos2; - Ogre::Radian angle = observer.getRefData().getBaseNodeOld()->getOrientation().yAxis().angleBetween(vec); - if (angle < Ogre::Degree(90)) - y = obsTerm * observerStats.getFatigueTerm() * fSneakNoViewMult; - else - y = obsTerm * observerStats.getFatigueTerm() * fSneakViewMult; + osg::Vec3f vec = pos1 - pos2; + if (observer.getRefData().getBaseNode()) + { + float angleRadians = std::acos((observer.getRefData().getBaseNode()->getAttitude() * osg::Vec3f(0,1,0)) * vec); + if (angleRadians < osg::DegreesToRadians(90.f)) + y = obsTerm * observerStats.getFatigueTerm() * fSneakNoViewMult; + else + y = obsTerm * observerStats.getFatigueTerm() * fSneakViewMult; + } float target = x - y; diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index ff3d2fceb..8965d3b0d 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -19,7 +19,7 @@ #include "../mwworld/cellstore.hpp" #include "../mwworld/esmstore.hpp" -//#include "../mwrender/animation.hpp" +#include "../mwrender/animation.hpp" #include "magiceffects.hpp" #include "npcstats.hpp" @@ -418,9 +418,9 @@ namespace MWMechanics absorbed = (Misc::Rng::roll0to99() < absorb); if (absorbed) { - //const ESM::Static* absorbStatic = MWBase::Environment::get().getWorld()->getStore().get().find ("VFX_Absorb"); - //MWBase::Environment::get().getWorld()->getAnimation(target)->addEffect( - // "meshes\\" + absorbStatic->mModel, ESM::MagicEffect::SpellAbsorption, false, ""); + const ESM::Static* absorbStatic = MWBase::Environment::get().getWorld()->getStore().get().find ("VFX_Absorb"); + MWBase::Environment::get().getWorld()->getAnimation(target)->addEffect( + "meshes\\" + absorbStatic->mModel, ESM::MagicEffect::SpellAbsorption, false, ""); // Magicka is increased by cost of spell DynamicStat magicka = target.getClass().getCreatureStats(target).getMagicka(); magicka.setCurrent(magicka.getCurrent() + spell->mData.mCost); @@ -466,9 +466,9 @@ namespace MWMechanics bool isReflected = (Misc::Rng::roll0to99() < reflect); if (isReflected) { - //const ESM::Static* reflectStatic = MWBase::Environment::get().getWorld()->getStore().get().find ("VFX_Reflect"); - //MWBase::Environment::get().getWorld()->getAnimation(target)->addEffect( - // "meshes\\" + reflectStatic->mModel, ESM::MagicEffect::Reflect, false, ""); + const ESM::Static* reflectStatic = MWBase::Environment::get().getWorld()->getStore().get().find ("VFX_Reflect"); + MWBase::Environment::get().getWorld()->getAnimation(target)->addEffect( + "meshes\\" + reflectStatic->mModel, ESM::MagicEffect::Reflect, false, ""); reflectedEffects.mList.push_back(*effectIt); magnitudeMult = 0; } @@ -565,7 +565,7 @@ namespace MWMechanics } // Add VFX - /*const ESM::Static* castStatic; + const ESM::Static* castStatic; if (!magicEffect->mHit.empty()) castStatic = MWBase::Environment::get().getWorld()->getStore().get().find (magicEffect->mHit); else @@ -577,7 +577,6 @@ namespace MWMechanics MWRender::Animation* anim = MWBase::Environment::get().getWorld()->getAnimation(target); if (anim) anim->addEffect("meshes\\" + castStatic->mModel, magicEffect->mIndex, loop, ""); - */ } } } diff --git a/apps/openmw/mwmechanics/summoning.cpp b/apps/openmw/mwmechanics/summoning.cpp index 221c67267..4140fd3c0 100644 --- a/apps/openmw/mwmechanics/summoning.cpp +++ b/apps/openmw/mwmechanics/summoning.cpp @@ -12,7 +12,7 @@ #include "../mwworld/manualref.hpp" #include "../mwworld/inventorystore.hpp" -//#include "../mwrender/animation.hpp" +#include "../mwrender/animation.hpp" #include "creaturestats.hpp" #include "aifollow.hpp" @@ -143,9 +143,8 @@ namespace MWMechanics summonedCreatureStats.getAiSequence().stack(package, ref.getPtr()); int creatureActorId = summonedCreatureStats.getActorId(); - /*MWWorld::Ptr placed = */MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),store,ipos); + MWWorld::Ptr placed = MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),store,ipos); - /* MWRender::Animation* anim = MWBase::Environment::get().getWorld()->getAnimation(placed); if (anim) { @@ -154,7 +153,6 @@ namespace MWMechanics if (fx) anim->addEffect("meshes\\" + fx->mModel, -1, false); } - */ creatureMap.insert(std::make_pair(*it, creatureActorId)); } diff --git a/apps/openmw/mwworld/refdata.cpp b/apps/openmw/mwworld/refdata.cpp index b8ebf99d0..54860fc31 100644 --- a/apps/openmw/mwworld/refdata.cpp +++ b/apps/openmw/mwworld/refdata.cpp @@ -37,7 +37,7 @@ namespace MWWorld } RefData::RefData() - : mBaseNode(0), mBase(0), mDeleted(false), mHasLocals (false), mEnabled (true), mCount (1), mCustomData (0), mChanged(false) + : mBaseNode(0), mDeleted(false), mHasLocals (false), mEnabled (true), mCount (1), mCustomData (0), mChanged(false) { for (int i=0; i<3; ++i) { @@ -48,7 +48,7 @@ namespace MWWorld } RefData::RefData (const ESM::CellRef& cellRef) - : mBaseNode(0), mBase(0), mDeleted(false), mHasLocals (false), mEnabled (true), + : mBaseNode(0), mDeleted(false), mHasLocals (false), mEnabled (true), mCount (1), mPosition (cellRef.mPos), mCustomData (0), mChanged(false) // Loading from ESM/ESP files -> assume unchanged @@ -59,7 +59,7 @@ namespace MWWorld } RefData::RefData (const ESM::ObjectState& objectState) - : mBaseNode (0), mBase(0), mDeleted(false), mHasLocals (false), + : mBaseNode(0), mDeleted(false), mHasLocals (false), mEnabled (objectState.mEnabled != 0), mCount (objectState.mCount), mPosition (objectState.mPosition), @@ -71,7 +71,7 @@ namespace MWWorld } RefData::RefData (const RefData& refData) - : mBaseNode(0), mBase(0), mCustomData (0) + : mBaseNode(0), mCustomData (0) { try { @@ -125,19 +125,14 @@ namespace MWWorld {} } - Ogre::SceneNode* RefData::getBaseNodeOld() - { - return mBaseNode; - } - void RefData::setBaseNode(osg::PositionAttitudeTransform *base) { - mBase = base; + mBaseNode = base; } osg::PositionAttitudeTransform* RefData::getBaseNode() { - return mBase; + return mBaseNode; } int RefData::getCount() const diff --git a/apps/openmw/mwworld/refdata.hpp b/apps/openmw/mwworld/refdata.hpp index b5b1f1560..61055aa73 100644 --- a/apps/openmw/mwworld/refdata.hpp +++ b/apps/openmw/mwworld/refdata.hpp @@ -7,11 +7,6 @@ #include -namespace Ogre -{ - class SceneNode; -} - namespace osg { class PositionAttitudeTransform; @@ -34,8 +29,7 @@ namespace MWWorld class RefData { - Ogre::SceneNode* mBaseNode; - osg::PositionAttitudeTransform* mBase; + osg::PositionAttitudeTransform* mBaseNode; MWScript::Locals mLocals; // if we find the overhead of heaving a locals // object in the refdata of refs without a script, @@ -81,10 +75,6 @@ namespace MWWorld RefData& operator= (const RefData& refData); - /// Return OGRE base node (can be a null pointer). - /// obsolete - Ogre::SceneNode* getBaseNodeOld(); - /// Return base node (can be a null pointer). osg::PositionAttitudeTransform* getBaseNode(); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 427a41d64..08617d0d6 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2385,7 +2385,7 @@ namespace MWWorld if(result.first == "") return true; */ - return false; + return true; } float World::getDistToNearestRayHit(const Ogre::Vector3& from, const Ogre::Vector3& dir, float maxDist) diff --git a/components/sceneutil/controller.hpp b/components/sceneutil/controller.hpp index 84fe6e896..0ef1356e7 100644 --- a/components/sceneutil/controller.hpp +++ b/components/sceneutil/controller.hpp @@ -36,6 +36,7 @@ namespace SceneUtil { public: Controller(); + virtual ~Controller() {} bool hasInput() const; From b2fe21dd3b2bb1ce99ac9d21742eed7484614342 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 30 May 2015 01:11:00 +0200 Subject: [PATCH 1314/3725] Minor cleanup --- apps/openmw/mwworld/scene.cpp | 1 - apps/openmw/mwworld/worldimp.hpp | 1 - 2 files changed, 2 deletions(-) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 939fbe873..db1f9714a 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -435,7 +435,6 @@ namespace MWWorld MWBase::Environment::get().getWorld()->adjustSky(); } - //We need the ogre renderer and a scene node. Scene::Scene (MWRender::RenderingManager& rendering, MWPhysics::PhysicsSystem *physics) : mCurrentCell (0), mCellChanged (false), mPhysics(physics), mRendering(rendering), mNeedMapUpdate(false) { diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index dedfebdf2..b642a1ba7 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -8,7 +8,6 @@ #include "ptr.hpp" #include "scene.hpp" #include "esmstore.hpp" -//#include "physicssystem.hpp" #include "cells.hpp" #include "localscripts.hpp" #include "timestamp.hpp" From cc3bfe2bb216412fe7e5e672bb2e2ca6b0c6af0d Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 30 May 2015 01:32:00 +0200 Subject: [PATCH 1315/3725] Restore collision tracker --- apps/openmw/mwphysics/physicssystem.cpp | 83 +++++++++++-------------- apps/openmw/mwphysics/physicssystem.hpp | 13 ++-- apps/openmw/mwworld/worldimp.cpp | 38 +++++------ 3 files changed, 58 insertions(+), 76 deletions(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 2bd88e634..8e63fecfb 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -231,8 +231,8 @@ namespace MWPhysics static osg::Vec3f move(const MWWorld::Ptr &ptr, Actor* physicActor, const osg::Vec3f &movement, float time, bool isFlying, float waterlevel, float slowFall, btCollisionWorld* collisionWorld - , std::map& collisionTracker - , std::map& standingCollisionTracker) + , std::map& collisionTracker + , std::map& standingCollisionTracker) { const ESM::Position& refpos = ptr.getRefData().getPosition(); osg::Vec3f position(refpos.asVec3()); @@ -333,13 +333,10 @@ namespace MWPhysics } else { - /* const btCollisionObject* standingOn = tracer.mHitObject; - if (const OEngine::Physic::RigidBody* body = dynamic_cast(standingOn)) - { - collisionTracker[ptr.getRefData().getHandle()] = body->mName; - } - */ + const PtrHolder* ptrHolder = static_cast(standingOn->getUserPointer()); + if (ptrHolder) + collisionTracker[ptr] = ptrHolder->getPtr(); } } else @@ -406,12 +403,9 @@ namespace MWPhysics && tracer.mHitObject->getBroadphaseHandle()->m_collisionFilterGroup != CollisionType_Actor) { const btCollisionObject* standingOn = tracer.mHitObject; - /* - if (const OEngine::Physic::RigidBody* body = dynamic_cast(standingOn)) - { - standingCollisionTracker[ptr.getRefData().getHandle()] = body->mName; - } - */ + const PtrHolder* ptrHolder = static_cast(standingOn->getUserPointer()); + if (ptrHolder) + standingCollisionTracker[ptr] = ptrHolder->getPtr(); if (standingOn->getBroadphaseHandle()->m_collisionFilterGroup == CollisionType_Water) physicActor->setWalkingOnWater(true); @@ -857,6 +851,22 @@ namespace MWPhysics } } + void PhysicsSystem::updateCollisionMapPtr(CollisionMap& map, const MWWorld::Ptr &old, const MWWorld::Ptr &updated) + { + CollisionMap::iterator found = map.find(old); + if (found != map.end()) + { + map[updated] = found->second; + map.erase(found); + } + + for (CollisionMap::iterator it = map.begin(); it != map.end(); ++it) + { + if (it->second == old) + it->second = updated; + } + } + void PhysicsSystem::updatePtr(const MWWorld::Ptr &old, const MWWorld::Ptr &updated) { ObjectMap::iterator found = mObjects.find(old); @@ -876,6 +886,9 @@ namespace MWPhysics mActors.erase(foundActor); mActors.insert(std::make_pair(updated, actor)); } + + updateCollisionMapPtr(mCollisions, old, updated); + updateCollisionMapPtr(mStandingCollisions, old, updated); } Actor *PhysicsSystem::getActor(const MWWorld::Ptr &ptr) @@ -1058,62 +1071,40 @@ namespace MWPhysics bool PhysicsSystem::isActorStandingOn(const MWWorld::Ptr &actor, const MWWorld::Ptr &object) const { - /* - const std::string& actorHandle = actor.getRefData().getHandle(); - const std::string& objectHandle = object.getRefData().getHandle(); - - for (std::map::const_iterator it = mStandingCollisions.begin(); - it != mStandingCollisions.end(); ++it) + for (CollisionMap::const_iterator it = mStandingCollisions.begin(); it != mStandingCollisions.end(); ++it) { - if (it->first == actorHandle && it->second == objectHandle) + if (it->first == actor && it->second == object) return true; } - */ return false; } - void PhysicsSystem::getActorsStandingOn(const MWWorld::Ptr &object, std::vector &out) const + void PhysicsSystem::getActorsStandingOn(const MWWorld::Ptr &object, std::vector &out) const { - /* - const std::string& objectHandle = object.getRefData().getHandle(); - - for (std::map::const_iterator it = mStandingCollisions.begin(); - it != mStandingCollisions.end(); ++it) + for (CollisionMap::const_iterator it = mStandingCollisions.begin(); it != mStandingCollisions.end(); ++it) { - if (it->second == objectHandle) + if (it->second == object) out.push_back(it->first); } - */ } bool PhysicsSystem::isActorCollidingWith(const MWWorld::Ptr &actor, const MWWorld::Ptr &object) const { - /* - const std::string& actorHandle = actor.getRefData().getHandle(); - const std::string& objectHandle = object.getRefData().getHandle(); - - for (std::map::const_iterator it = mCollisions.begin(); - it != mCollisions.end(); ++it) + for (CollisionMap::const_iterator it = mCollisions.begin(); it != mCollisions.end(); ++it) { - if (it->first == actorHandle && it->second == objectHandle) + if (it->first == actor && it->second == object) return true; } - */ return false; } - void PhysicsSystem::getActorsCollidingWith(const MWWorld::Ptr &object, std::vector &out) const + void PhysicsSystem::getActorsCollidingWith(const MWWorld::Ptr &object, std::vector &out) const { - /* - const std::string& objectHandle = object.getRefData().getHandle(); - - for (std::map::const_iterator it = mCollisions.begin(); - it != mCollisions.end(); ++it) + for (CollisionMap::const_iterator it = mCollisions.begin(); it != mCollisions.end(); ++it) { - if (it->second == objectHandle) + if (it->second == object) out.push_back(it->first); } - */ } void PhysicsSystem::disableWater() diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index 841085f47..2240a5119 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -109,14 +109,14 @@ namespace MWPhysics bool isActorStandingOn(const MWWorld::Ptr& actor, const MWWorld::Ptr& object) const; /// Get the handle of all actors standing on \a object in this frame. - void getActorsStandingOn(const MWWorld::Ptr& object, std::vector& out) const; + void getActorsStandingOn(const MWWorld::Ptr& object, std::vector& out) const; /// Return true if \a actor has collided with \a object in this frame. /// This will detect running into objects, but will not detect climbing stairs, stepping up a small object, etc. bool isActorCollidingWith(const MWWorld::Ptr& actor, const MWWorld::Ptr& object) const; /// Get the handle of all actors colliding with \a object in this frame. - void getActorsCollidingWith(const MWWorld::Ptr& object, std::vector& out) const; + void getActorsCollidingWith(const MWWorld::Ptr& object, std::vector& out) const; bool toggleDebugRendering(); @@ -142,14 +142,15 @@ namespace MWPhysics bool mDebugDrawEnabled; - std::map handleToMesh; - // Tracks all movement collisions happening during a single frame. // This will detect e.g. running against a vertical wall. It will not detect climbing up stairs, // stepping up small objects, etc. - std::map mCollisions; // FIXME: reimplement + typedef std::map CollisionMap; + CollisionMap mCollisions; + CollisionMap mStandingCollisions; - std::map mStandingCollisions; // FIXME: reimplement + // replaces all occurences of 'old' in the map by 'updated', no matter if its a key or value + void updateCollisionMapPtr(CollisionMap& map, const MWWorld::Ptr &old, const MWWorld::Ptr &updated); PtrVelocityList mMovementQueue; PtrVelocityList mMovementResults; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 08617d0d6..39b26c5d2 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2200,27 +2200,27 @@ namespace MWWorld bool World::getPlayerStandingOn (const MWWorld::Ptr& object) { - //MWWorld::Ptr player = getPlayerPtr(); - return 0;//mPhysics->isActorStandingOn(player, object); + MWWorld::Ptr player = getPlayerPtr(); + return mPhysics->isActorStandingOn(player, object); } bool World::getActorStandingOn (const MWWorld::Ptr& object) { - std::vector actors; - //mPhysics->getActorsStandingOn(object, actors); + std::vector actors; + mPhysics->getActorsStandingOn(object, actors); return !actors.empty(); } bool World::getPlayerCollidingWith (const MWWorld::Ptr& object) { - //MWWorld::Ptr player = getPlayerPtr(); - return 0;//mPhysics->isActorCollidingWith(player, object); + MWWorld::Ptr player = getPlayerPtr(); + return mPhysics->isActorCollidingWith(player, object); } bool World::getActorCollidingWith (const MWWorld::Ptr& object) { - std::vector actors; - //mPhysics->getActorsCollidingWith(object, actors); + std::vector actors; + mPhysics->getActorsCollidingWith(object, actors); return !actors.empty(); } @@ -2229,15 +2229,11 @@ namespace MWWorld if (MWBase::Environment::get().getWindowManager()->isGuiMode()) return; - /* - std::vector actors; + std::vector actors; mPhysics->getActorsStandingOn(object, actors); - for (std::vector::iterator it = actors.begin(); it != actors.end(); ++it) + for (std::vector::iterator it = actors.begin(); it != actors.end(); ++it) { - MWWorld::Ptr actor = searchPtrViaHandle(*it); // Collision events are from the last frame, actor might no longer exist - if (actor.isEmpty()) - continue; - + MWWorld::Ptr actor = *it; MWMechanics::CreatureStats& stats = actor.getClass().getCreatureStats(actor); if (stats.isDead()) continue; @@ -2254,7 +2250,6 @@ namespace MWWorld MWBase::Environment::get().getSoundManager()->playSound3D(actor, "Health Damage", 1.0f, 1.0f); } } - */ } void World::hurtCollidingActors(const Ptr &object, float healthPerSecond) @@ -2262,15 +2257,11 @@ namespace MWWorld if (MWBase::Environment::get().getWindowManager()->isGuiMode()) return; - /* - std::vector actors; + std::vector actors; mPhysics->getActorsCollidingWith(object, actors); - for (std::vector::iterator it = actors.begin(); it != actors.end(); ++it) + for (std::vector::iterator it = actors.begin(); it != actors.end(); ++it) { - MWWorld::Ptr actor = searchPtrViaHandle(*it); // Collision events are from the last frame, actor might no longer exist - if (actor.isEmpty()) - continue; - + MWWorld::Ptr actor = *it; MWMechanics::CreatureStats& stats = actor.getClass().getCreatureStats(actor); if (stats.isDead()) continue; @@ -2287,7 +2278,6 @@ namespace MWWorld MWBase::Environment::get().getSoundManager()->playSound3D(actor, "Health Damage", 1.0f, 1.0f); } } - */ } float World::getWindSpeed() From 988a9cad58b41abee8453424ea5071643f7799d4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 30 May 2015 01:41:38 +0200 Subject: [PATCH 1316/3725] getHitContact Head exception fix --- apps/openmw/mwmechanics/character.cpp | 4 ++-- apps/openmw/mwrender/animation.cpp | 11 +++-------- apps/openmw/mwrender/animation.hpp | 6 +----- apps/openmw/mwrender/characterpreview.cpp | 9 +++++++-- 4 files changed, 13 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index a8a6f74aa..379025c9e 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1158,10 +1158,10 @@ bool CharacterController::updateWeaponState() effect = store.get().find(effectentry.mEffectID); const ESM::Static* castStatic = MWBase::Environment::get().getWorld()->getStore().get().find ("VFX_Hands"); - if (mAnimation->hasNode("Bip01 L Hand")) + if (mAnimation->getNode("Bip01 L Hand")) mAnimation->addEffect("meshes\\" + castStatic->mModel, -1, false, "Bip01 L Hand", effect->mParticle); - if (mAnimation->hasNode("Bip01 R Hand")) + if (mAnimation->getNode("Bip01 R Hand")) mAnimation->addEffect("meshes\\" + castStatic->mModel, -1, false, "Bip01 R Hand", effect->mParticle); switch(effectentry.mRange) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index fed96f213..403f270d8 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1136,19 +1136,14 @@ namespace MWRender return true; } - bool Animation::hasNode(const std::string &name) const - { - std::string lowerName = Misc::StringUtils::lowerCase(name); - return (mNodeMap.find(lowerName) != mNodeMap.end()); - } - const osg::Node* Animation::getNode(const std::string &name) const { std::string lowerName = Misc::StringUtils::lowerCase(name); NodeMap::const_iterator found = mNodeMap.find(lowerName); if (found == mNodeMap.end()) - throw std::runtime_error("Can't find node " + name); - return found->second; + return NULL; + else + return found->second; } float Animation::AnimationTime::getValue(osg::NodeVisitor*) diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index d298fdff0..d1a1b01c6 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -367,11 +367,7 @@ public: /// This is typically called as part of runAnimation, but may be called manually if needed. void updateEffects(float duration); - /// Is there a node with the specified name? - /// @note The matching is case-insensitive. - bool hasNode(const std::string& name) const; - - /// Return a node with the specified name, throws an exception if the node is not found. + /// Return a node with the specified name, or NULL if not existing. /// @note The matching is case-insensitive. const osg::Node* getNode(const std::string& name) const; diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 62c732051..cdf99f0fc 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -363,8 +363,13 @@ namespace MWRender mCamera->removeUpdateCallback(mUpdateCameraCallback); const osg::Node* head = mAnimation->getNode("Bip01 Head"); - mUpdateCameraCallback = new UpdateCameraCallback(head, mPosition, mLookAt); - mCamera->addUpdateCallback(mUpdateCameraCallback); + if (head) + { + mUpdateCameraCallback = new UpdateCameraCallback(head, mPosition, mLookAt); + mCamera->addUpdateCallback(mUpdateCameraCallback); + } + else + std::cerr << "Error: Bip01 Head node not found" << std::endl; } } From 0f8f19958a4abfd9ccaba6ff4f58e7bbc4e6c302 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 30 May 2015 04:26:00 +0200 Subject: [PATCH 1317/3725] NifLoader: Fix empty StateSets being created in some cases --- components/nifosg/nifloader.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 219f6e194..1f089f0c4 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -1075,8 +1075,6 @@ namespace NifOsg static void handleProperty(const Nif::Property *property, osg::Node *node, SceneUtil::CompositeStateSetUpdater* composite, Resource::TextureManager* textureManager, std::map& boundTextures, int animflags) { - osg::StateSet* stateset = node->getOrCreateStateSet(); - switch (property->recType) { case Nif::RC_NiStencilProperty: @@ -1095,6 +1093,7 @@ namespace NifOsg break; } + osg::StateSet* stateset = node->getOrCreateStateSet(); stateset->setAttribute(frontFace, osg::StateAttribute::ON); stateset->setMode(GL_CULL_FACE, stencilprop->data.drawMode == 3 ? osg::StateAttribute::OFF : osg::StateAttribute::ON); @@ -1117,7 +1116,7 @@ namespace NifOsg osg::PolygonMode* mode = new osg::PolygonMode; mode->setMode(osg::PolygonMode::FRONT_AND_BACK, wireprop->flags == 0 ? osg::PolygonMode::FILL : osg::PolygonMode::LINE); - stateset->setAttributeAndModes(mode, osg::StateAttribute::ON); + node->getOrCreateStateSet()->setAttributeAndModes(mode, osg::StateAttribute::ON); break; } case Nif::RC_NiZBufferProperty: @@ -1126,7 +1125,7 @@ namespace NifOsg // VER_MW doesn't support a DepthFunction according to NifSkope osg::Depth* depth = new osg::Depth; depth->setWriteMask((zprop->flags>>1)&1); - stateset->setAttributeAndModes(depth, osg::StateAttribute::ON); + node->getOrCreateStateSet()->setAttributeAndModes(depth, osg::StateAttribute::ON); break; } // OSG groups the material properties that NIFs have separate, so we have to parse them all again when one changed @@ -1141,6 +1140,7 @@ namespace NifOsg { const Nif::NiAlphaProperty* alphaprop = static_cast(property); osg::BlendFunc* blendfunc = new osg::BlendFunc; + osg::StateSet* stateset = node->getOrCreateStateSet(); if (alphaprop->flags&1) { blendfunc->setFunction(getBlendMode((alphaprop->flags>>1)&0xf), @@ -1174,6 +1174,7 @@ namespace NifOsg case Nif::RC_NiTexturingProperty: { const Nif::NiTexturingProperty* texprop = static_cast(property); + osg::StateSet* stateset = node->getOrCreateStateSet(); for (int i=0; itextures[i].inUse) From 76196d815dcd4172b16a751352a52b056b5ab58b Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 30 May 2015 18:58:33 +1000 Subject: [PATCH 1318/3725] Update user preference setting value via an event message queue. --- apps/opencs/model/tools/signalhandler.cpp | 14 ++++++++++++-- apps/opencs/model/tools/signalhandler.hpp | 4 ++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/tools/signalhandler.cpp b/apps/opencs/model/tools/signalhandler.cpp index cfb52ed63..64e5ead55 100644 --- a/apps/opencs/model/tools/signalhandler.cpp +++ b/apps/opencs/model/tools/signalhandler.cpp @@ -1,5 +1,7 @@ #include "signalhandler.hpp" +#include + #include "../settings/usersettings.hpp" CSMTools::SignalHandler::SignalHandler(bool extraCheck) @@ -11,12 +13,20 @@ CSMTools::SignalHandler::SignalHandler(bool extraCheck) SLOT (updateUserSetting (const QString &, const QStringList &))); } +// called from the main thread void CSMTools::SignalHandler::updateUserSetting (const QString &name, const QStringList &list) { - if (name=="verifier/pathgrid-extra-check") - mExtraCheck = list.at(0) == "true"; + if (name=="verifier/pathgrid-extra-check" && !list.empty()) + QMetaObject::invokeMethod(this, "updateExtraCheck", Qt::AutoConnection, Q_ARG(bool, list.at(0) == "true")); +} + +// should be in the operations thread via an event message queue +void CSMTools::SignalHandler::updateExtraCheck (bool extraCheck) +{ + mExtraCheck = extraCheck; } +// called from the operations thread bool CSMTools::SignalHandler::extraCheck () { return mExtraCheck; diff --git a/apps/opencs/model/tools/signalhandler.hpp b/apps/opencs/model/tools/signalhandler.hpp index c3d075fdf..bc063ebd6 100644 --- a/apps/opencs/model/tools/signalhandler.hpp +++ b/apps/opencs/model/tools/signalhandler.hpp @@ -20,6 +20,10 @@ namespace CSMTools public slots: void updateUserSetting (const QString &name, const QStringList &list); + + private slots: + + void updateExtraCheck (bool extraCheck); }; } From 01eba7b721be21a71f54431721b0da039d7c1074 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 30 May 2015 19:17:42 +1000 Subject: [PATCH 1319/3725] Extra check for thread affinity. --- apps/opencs/model/tools/signalhandler.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/apps/opencs/model/tools/signalhandler.cpp b/apps/opencs/model/tools/signalhandler.cpp index 64e5ead55..2e94e1f87 100644 --- a/apps/opencs/model/tools/signalhandler.cpp +++ b/apps/opencs/model/tools/signalhandler.cpp @@ -1,6 +1,7 @@ #include "signalhandler.hpp" #include +#include #include "../settings/usersettings.hpp" @@ -23,6 +24,13 @@ void CSMTools::SignalHandler::updateUserSetting (const QString &name, const QStr // should be in the operations thread via an event message queue void CSMTools::SignalHandler::updateExtraCheck (bool extraCheck) { + if (thread()!=QThread::currentThread()) + { + QMetaObject::invokeMethod(this,"updateExtraCheck", Qt::QueuedConnection, Q_ARG(bool, extraCheck)); + return; + } + + // extra safety mExtraCheck = extraCheck; } From 88d5aed62d65e2798bf6f21f8e2b053f9af77fd8 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 30 May 2015 12:05:35 +0200 Subject: [PATCH 1320/3725] removed code that interfered with the default window size on Linux (Fixes #2568) --- apps/opencs/view/doc/view.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 5e3df2739..fca9b2715 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -404,11 +404,7 @@ CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int to width = std::max(width, 300); height = std::max(height, 300); - // trick to get the window decorations and their sizes - show(); - hide(); - resize (width - (frameGeometry().width() - geometry().width()), - height - (frameGeometry().height() - geometry().height())); + resize (width, height); mSubViewWindow.setDockOptions (QMainWindow::AllowNestedDocks); From c4aa3d3ee319a884e77f05313f3a4441cd6f98dc Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 30 May 2015 21:12:47 +1000 Subject: [PATCH 1321/3725] Revert user preference setting checks until a thread safe method is worked out. The OSX namespace issue is retained. --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/settings/usersettings.cpp | 7 ---- apps/opencs/model/tools/pathgridcheck.cpp | 22 +---------- apps/opencs/model/tools/pathgridcheck.hpp | 9 +---- apps/opencs/model/tools/signalhandler.cpp | 41 --------------------- apps/opencs/model/tools/signalhandler.hpp | 30 --------------- apps/opencs/model/tools/tools.cpp | 9 +---- apps/opencs/model/tools/tools.hpp | 2 +- 8 files changed, 7 insertions(+), 115 deletions(-) delete mode 100644 apps/opencs/model/tools/signalhandler.cpp delete mode 100644 apps/opencs/model/tools/signalhandler.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 9ed0d6a8b..78b2deb7a 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -34,7 +34,7 @@ opencs_hdrs_noqt (model/world opencs_units (model/tools - tools reportmodel signalhandler + tools reportmodel ) opencs_units_noqt (model/tools diff --git a/apps/opencs/model/settings/usersettings.cpp b/apps/opencs/model/settings/usersettings.cpp index ea75fd6d9..ea002c5ed 100644 --- a/apps/opencs/model/settings/usersettings.cpp +++ b/apps/opencs/model/settings/usersettings.cpp @@ -264,13 +264,6 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() monoFont->setToolTip ("Whether to use monospaced fonts on script edit subview."); } - declareSection ("verifier", "Verifier"); - { - Setting *extraPathgrid = createSetting (Type_CheckBox, "pathgrid-extra-check", "Pathgrid: Extra Check"); - extraPathgrid->setDefaultValue ("false"); - extraPathgrid->setToolTip ("Additional checks for orphaned or duplicated pathgrid points"); - } - { /****************************************************************** * There are three types of values: diff --git a/apps/opencs/model/tools/pathgridcheck.cpp b/apps/opencs/model/tools/pathgridcheck.cpp index 2b11b7066..76edeb573 100644 --- a/apps/opencs/model/tools/pathgridcheck.cpp +++ b/apps/opencs/model/tools/pathgridcheck.cpp @@ -8,24 +8,12 @@ #include "../world/subcellcollection.hpp" #include "../world/pathgrid.hpp" -#include "../settings/usersettings.hpp" - -#include "signalhandler.hpp" - -CSMTools::PathgridCheckStage::PathgridCheckStage (const CSMWorld::SubCellCollection& pathgrids, - CSMTools::SignalHandler *signalHandler) -: mPathgrids (pathgrids), mSigHandler(signalHandler) +CSMTools::PathgridCheckStage::PathgridCheckStage (const CSMWorld::SubCellCollection& pathgrids) +: mPathgrids (pathgrids) {} -CSMTools::PathgridCheckStage::~PathgridCheckStage () -{ - delete mSigHandler; -} - int CSMTools::PathgridCheckStage::setup() { - mExtraCheck = mSigHandler->extraCheck(); - return mPathgrids.getSize(); } @@ -117,9 +105,6 @@ void CSMTools::PathgridCheckStage::perform (int stage, CSMDoc::Messages& message } } - if (!mExtraCheck) - continue; - // check duplicate points // FIXME: how to do this efficiently? for (unsigned int j = 0; j < pathgrid.mPoints.size(); ++j) @@ -148,9 +133,6 @@ void CSMTools::PathgridCheckStage::perform (int stage, CSMDoc::Messages& message } } - if (!mExtraCheck) - return; - // check pathgrid points that are not connected to anything for (unsigned int i = 0; i < pointList.size(); ++i) { diff --git a/apps/opencs/model/tools/pathgridcheck.hpp b/apps/opencs/model/tools/pathgridcheck.hpp index 8b5dc08a7..f45b5bc93 100644 --- a/apps/opencs/model/tools/pathgridcheck.hpp +++ b/apps/opencs/model/tools/pathgridcheck.hpp @@ -14,8 +14,6 @@ namespace CSMWorld namespace CSMTools { - class SignalHandler; - struct Point { unsigned char mConnectionNum; @@ -25,18 +23,13 @@ namespace CSMTools class PathgridCheckStage : public CSMDoc::Stage { - bool mExtraCheck; - CSMTools::SignalHandler *mSigHandler; - const CSMWorld::SubCellCollection >& mPathgrids; public: PathgridCheckStage (const CSMWorld::SubCellCollection >& pathgrids, CSMTools::SignalHandler *signallHandler); - - ~PathgridCheckStage (); + CSMWorld::IdAccessor >& pathgrids); virtual int setup(); diff --git a/apps/opencs/model/tools/signalhandler.cpp b/apps/opencs/model/tools/signalhandler.cpp deleted file mode 100644 index 2e94e1f87..000000000 --- a/apps/opencs/model/tools/signalhandler.cpp +++ /dev/null @@ -1,41 +0,0 @@ -#include "signalhandler.hpp" - -#include -#include - -#include "../settings/usersettings.hpp" - -CSMTools::SignalHandler::SignalHandler(bool extraCheck) - : mExtraCheck(extraCheck) -{ - connect (&CSMSettings::UserSettings::instance(), - SIGNAL (userSettingUpdated(const QString &, const QStringList &)), - this, - SLOT (updateUserSetting (const QString &, const QStringList &))); -} - -// called from the main thread -void CSMTools::SignalHandler::updateUserSetting (const QString &name, const QStringList &list) -{ - if (name=="verifier/pathgrid-extra-check" && !list.empty()) - QMetaObject::invokeMethod(this, "updateExtraCheck", Qt::AutoConnection, Q_ARG(bool, list.at(0) == "true")); -} - -// should be in the operations thread via an event message queue -void CSMTools::SignalHandler::updateExtraCheck (bool extraCheck) -{ - if (thread()!=QThread::currentThread()) - { - QMetaObject::invokeMethod(this,"updateExtraCheck", Qt::QueuedConnection, Q_ARG(bool, extraCheck)); - return; - } - - // extra safety - mExtraCheck = extraCheck; -} - -// called from the operations thread -bool CSMTools::SignalHandler::extraCheck () -{ - return mExtraCheck; -} diff --git a/apps/opencs/model/tools/signalhandler.hpp b/apps/opencs/model/tools/signalhandler.hpp deleted file mode 100644 index bc063ebd6..000000000 --- a/apps/opencs/model/tools/signalhandler.hpp +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef CSM_TOOLS_SIGNALHANDLER_H -#define CSM_TOOLS_SIGNALHANDLER_H - -#include - -namespace CSMTools -{ - class SignalHandler : public QObject - { - Q_OBJECT - - bool mExtraCheck; - - public: - - SignalHandler (bool extraCheck); - - bool extraCheck (); - - public slots: - - void updateUserSetting (const QString &name, const QStringList &list); - - private slots: - - void updateExtraCheck (bool extraCheck); - }; -} - -#endif diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index 45c7fbae3..8d93a9433 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -10,8 +10,6 @@ #include "../world/data.hpp" #include "../world/universalid.hpp" -#include "../settings/usersettings.hpp" - #include "reportmodel.hpp" #include "mandatoryid.hpp" #include "skillcheck.hpp" @@ -29,7 +27,6 @@ #include "startscriptcheck.hpp" #include "searchoperation.hpp" #include "pathgridcheck.hpp" -#include "signalhandler.hpp" CSMDoc::OperationHolder *CSMTools::Tools::get (int type) { @@ -59,8 +56,6 @@ CSMDoc::OperationHolder *CSMTools::Tools::getVerifier() SIGNAL (reportMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int)), this, SLOT (verifierMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int))); - CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); - std::vector mandatoryIds; // I want C++11, damn it! mandatoryIds.push_back ("Day"); mandatoryIds.push_back ("DaysPassed"); @@ -102,8 +97,7 @@ CSMDoc::OperationHolder *CSMTools::Tools::getVerifier() CSMWorld::UniversalId( CSMWorld::UniversalId::Type_Meshes )), mData.getRaces() )); - mVerifierOperation->appendStage (new PathgridCheckStage (mData.getPathgrids(), - new SignalHandler(userSettings.setting ("verifier/pathgrid-extra-check", QString ("false"))=="true"))); + mVerifierOperation->appendStage (new PathgridCheckStage (mData.getPathgrids())); mVerifier.setOperation (mVerifierOperation); } @@ -219,3 +213,4 @@ void CSMTools::Tools::verifierMessage (const CSMWorld::UniversalId& id, const st if (iter!=mActiveReports.end()) mReports[iter->second]->add (id, message, hint); } + diff --git a/apps/opencs/model/tools/tools.hpp b/apps/opencs/model/tools/tools.hpp index dc19cf456..0f9e57044 100644 --- a/apps/opencs/model/tools/tools.hpp +++ b/apps/opencs/model/tools/tools.hpp @@ -64,7 +64,7 @@ namespace CSMTools CSMWorld::UniversalId newSearch(); void runSearch (const CSMWorld::UniversalId& searchId, const Search& search); - + void abortOperation (int type); ///< \attention The operation is not aborted immediately. From 87a1f9f9aa2e05db33df52b3a35efe94e9935988 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sat, 30 May 2015 15:31:44 +0300 Subject: [PATCH 1322/3725] Add ID completion manager --- apps/opencs/CMakeLists.txt | 1 + .../model/world/idcompletionmanager.cpp | 121 ++++++++++++++++++ .../model/world/idcompletionmanager.hpp | 38 ++++++ 3 files changed, 160 insertions(+) create mode 100644 apps/opencs/model/world/idcompletionmanager.cpp create mode 100644 apps/opencs/model/world/idcompletionmanager.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 7723b15f5..99ba54ac1 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -26,6 +26,7 @@ opencs_units_noqt (model/world universalid record commands columnbase scriptcontext cell refidcollection refidadapter refiddata refidadapterimp ref collectionbase refcollection columns infocollection tablemimedata cellcoordinates cellselection resources resourcesmanager scope pathgrid landtexture land nestedtablewrapper nestedcollection nestedcoladapterimp nestedinfocollection + idcompletionmanager ) opencs_hdrs_noqt (model/world diff --git a/apps/opencs/model/world/idcompletionmanager.cpp b/apps/opencs/model/world/idcompletionmanager.cpp new file mode 100644 index 000000000..ca614dcd9 --- /dev/null +++ b/apps/opencs/model/world/idcompletionmanager.cpp @@ -0,0 +1,121 @@ +#include "idcompletionmanager.hpp" + +#include + +#include + +#include "data.hpp" +#include "idtablebase.hpp" + +namespace +{ + std::map generateModelTypes() + { + std::map types; + + types[CSMWorld::Columns::ColumnId_Actor] = CSMWorld::UniversalId::Type_Referenceable; + types[CSMWorld::Columns::ColumnId_AreaObject] = CSMWorld::UniversalId::Type_Referenceable; + types[CSMWorld::Columns::ColumnId_AreaSound] = CSMWorld::UniversalId::Type_Sound; + types[CSMWorld::Columns::ColumnId_BoltObject] = CSMWorld::UniversalId::Type_Referenceable; + types[CSMWorld::Columns::ColumnId_BoltSound] = CSMWorld::UniversalId::Type_Sound; + types[CSMWorld::Columns::ColumnId_CastingObject] = CSMWorld::UniversalId::Type_Referenceable; + types[CSMWorld::Columns::ColumnId_CastingSound] = CSMWorld::UniversalId::Type_Sound; + types[CSMWorld::Columns::ColumnId_Cell] = CSMWorld::UniversalId::Type_Cell; + types[CSMWorld::Columns::ColumnId_Class] = CSMWorld::UniversalId::Type_Class; + types[CSMWorld::Columns::ColumnId_Creature] = CSMWorld::UniversalId::Type_Referenceable; + types[CSMWorld::Columns::ColumnId_DestinationCell] = CSMWorld::UniversalId::Type_Cell; + types[CSMWorld::Columns::ColumnId_Enchantment] = CSMWorld::UniversalId::Type_Enchantment; + types[CSMWorld::Columns::ColumnId_Faction] = CSMWorld::UniversalId::Type_Faction; + types[CSMWorld::Columns::Columnid_Hair] = CSMWorld::UniversalId::Type_Mesh; + types[CSMWorld::Columns::ColumnId_Head] = CSMWorld::UniversalId::Type_Mesh; + types[CSMWorld::Columns::ColumnId_HitObject] = CSMWorld::UniversalId::Type_Referenceable; + types[CSMWorld::Columns::ColumnId_HitSound] = CSMWorld::UniversalId::Type_Sound; + types[CSMWorld::Columns::ColumnId_Icon] = CSMWorld::UniversalId::Type_Icon; + types[CSMWorld::Columns::ColumnId_InventoryItemId] = CSMWorld::UniversalId::Type_Referenceable; + types[CSMWorld::Columns::ColumnId_MajorSkill1] = CSMWorld::UniversalId::Type_Skill; + types[CSMWorld::Columns::ColumnId_MajorSkill2] = CSMWorld::UniversalId::Type_Skill; + types[CSMWorld::Columns::ColumnId_MajorSkill3] = CSMWorld::UniversalId::Type_Skill; + types[CSMWorld::Columns::ColumnId_MajorSkill4] = CSMWorld::UniversalId::Type_Skill; + types[CSMWorld::Columns::ColumnId_MajorSkill5] = CSMWorld::UniversalId::Type_Skill; + types[CSMWorld::Columns::ColumnId_MinorSkill1] = CSMWorld::UniversalId::Type_Skill; + types[CSMWorld::Columns::ColumnId_MinorSkill2] = CSMWorld::UniversalId::Type_Skill; + types[CSMWorld::Columns::ColumnId_MinorSkill3] = CSMWorld::UniversalId::Type_Skill; + types[CSMWorld::Columns::ColumnId_MinorSkill4] = CSMWorld::UniversalId::Type_Skill; + types[CSMWorld::Columns::ColumnId_MinorSkill5] = CSMWorld::UniversalId::Type_Skill; + types[CSMWorld::Columns::ColumnId_Model] = CSMWorld::UniversalId::Type_Mesh; + types[CSMWorld::Columns::ColumnId_Owner] = CSMWorld::UniversalId::Type_Referenceable; + types[CSMWorld::Columns::ColumnId_OwnerGlobal] = CSMWorld::UniversalId::Type_Global; + types[CSMWorld::Columns::ColumnId_Particle] = CSMWorld::UniversalId::Type_Texture; + types[CSMWorld::Columns::ColumnId_PcFaction] = CSMWorld::UniversalId::Type_Faction; + types[CSMWorld::Columns::ColumnId_Race] = CSMWorld::UniversalId::Type_Race; + types[CSMWorld::Columns::ColumnId_ReferenceableId] = CSMWorld::UniversalId::Type_Referenceable; + types[CSMWorld::Columns::ColumnId_Region] = CSMWorld::UniversalId::Type_Region; + types[CSMWorld::Columns::ColumnId_Skill1] = CSMWorld::UniversalId::Type_Skill; + types[CSMWorld::Columns::ColumnId_Skill2] = CSMWorld::UniversalId::Type_Skill; + types[CSMWorld::Columns::ColumnId_Skill3] = CSMWorld::UniversalId::Type_Skill; + types[CSMWorld::Columns::ColumnId_Skill4] = CSMWorld::UniversalId::Type_Skill; + types[CSMWorld::Columns::ColumnId_Skill5] = CSMWorld::UniversalId::Type_Skill; + types[CSMWorld::Columns::ColumnId_Skill6] = CSMWorld::UniversalId::Type_Skill; + types[CSMWorld::Columns::ColumnId_Skill7] = CSMWorld::UniversalId::Type_Skill; + types[CSMWorld::Columns::ColumnId_SleepEncounter] = CSMWorld::UniversalId::Type_Referenceable; + types[CSMWorld::Columns::ColumnId_Soul] = CSMWorld::UniversalId::Type_Referenceable; + types[CSMWorld::Columns::ColumnId_Sound] = CSMWorld::UniversalId::Type_Sound; + types[CSMWorld::Columns::ColumnId_SoundFile] = CSMWorld::UniversalId::Type_SoundRes; + types[CSMWorld::Columns::ColumnId_SoundName] = CSMWorld::UniversalId::Type_Sound; + types[CSMWorld::Columns::ColumnId_SpellId] = CSMWorld::UniversalId::Type_Spell; + types[CSMWorld::Columns::ColumnId_Script] = CSMWorld::UniversalId::Type_Script; + types[CSMWorld::Columns::ColumnId_TeleportCell] = CSMWorld::UniversalId::Type_Cell; + types[CSMWorld::Columns::ColumnId_Texture] = CSMWorld::UniversalId::Type_Texture; + types[CSMWorld::Columns::ColumnId_Trap] = CSMWorld::UniversalId::Type_Spell; + + return types; + } +} + +const std::map + CSMWorld::IdCompletionManager::sCompleterModelTypes = generateModelTypes(); + +CSMWorld::IdCompletionManager::IdCompletionManager(CSMWorld::Data &data) +{ + generateCompleters(data); +} + +bool CSMWorld::IdCompletionManager::isCompleterExistFor(CSMWorld::Columns::ColumnId id) const +{ + return mCompleters.find(id) != mCompleters.end(); +} + +boost::shared_ptr CSMWorld::IdCompletionManager::getCompleter(CSMWorld::Columns::ColumnId id) +{ + if (!isCompleterExistFor(id)) + { + throw std::logic_error("This column doesn't have an ID completer"); + } + return mCompleters[id]; +} + +void CSMWorld::IdCompletionManager::generateCompleters(CSMWorld::Data &data) +{ + typedef std::map::const_iterator ModelTypeConstIterator; + + ModelTypeConstIterator current = sCompleterModelTypes.begin(); + ModelTypeConstIterator end = sCompleterModelTypes.end(); + for (; current != end; ++current) + { + QAbstractItemModel *model = data.getTableModel(current->second); + CSMWorld::IdTableBase *table = dynamic_cast(model); + if (table != NULL) + { + int idColumn = table->searchColumnIndex(CSMWorld::Columns::ColumnId_Id); + if (idColumn != -1) + { + boost::shared_ptr completer = boost::make_shared(table); + completer->setCompletionColumn(idColumn); + // The completion role must be Qt::DisplayRole to get the ID values from the model + completer->setCompletionRole(Qt::DisplayRole); + completer->setCaseSensitivity(Qt::CaseInsensitive); + mCompleters[current->first] = completer; + } + } + } +} \ No newline at end of file diff --git a/apps/opencs/model/world/idcompletionmanager.hpp b/apps/opencs/model/world/idcompletionmanager.hpp new file mode 100644 index 000000000..725cfa331 --- /dev/null +++ b/apps/opencs/model/world/idcompletionmanager.hpp @@ -0,0 +1,38 @@ +#ifndef CSM_WORLD_IDCOMPLETIONMANAGER_HPP +#define CSM_WORLD_IDCOMPLETIONMANAGER_HPP + +#include + +#include + +#include "columns.hpp" +#include "universalid.hpp" + +class QCompleter; + +namespace CSMWorld +{ + class Data; + + /// \brief Creates and stores all ID completers + class IdCompletionManager + { + static const std::map sCompleterModelTypes; + + std::map > mCompleters; + + // Don't allow copying + IdCompletionManager(const IdCompletionManager &); + IdCompletionManager &operator = (const IdCompletionManager &); + + void generateCompleters(CSMWorld::Data &data); + + public: + IdCompletionManager(CSMWorld::Data &data); + + bool isCompleterExistFor(CSMWorld::Columns::ColumnId id) const; + boost::shared_ptr getCompleter(CSMWorld::Columns::ColumnId id); + }; +} + +#endif \ No newline at end of file From 19cc6b83e5c795f8b1a8b8fb9989ab84d262b1ed Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sat, 30 May 2015 15:40:23 +0300 Subject: [PATCH 1323/3725] Integrate the Id completion manager into the Document class --- apps/opencs/model/doc/document.cpp | 8 +++++++- apps/opencs/model/doc/document.hpp | 4 ++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index a73201ec0..1e3d1c59b 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -2257,7 +2257,8 @@ CSMDoc::Document::Document (const Files::ConfigurationManager& configuration, mSavingOperation (*this, mProjectPath, encoding), mSaving (&mSavingOperation), mResDir(resDir), - mRunner (mProjectPath), mPhysics(boost::shared_ptr()) + mRunner (mProjectPath), mPhysics(boost::shared_ptr()), + mIdCompletionManager(mData) { if (mContentFiles.empty()) throw std::runtime_error ("Empty content file sequence"); @@ -2488,3 +2489,8 @@ boost::shared_ptr CSMDoc::Document::getPhysics () return mPhysics; } + +CSMWorld::IdCompletionManager &CSMDoc::Document::getIdCompletionManager() +{ + return mIdCompletionManager; +} \ No newline at end of file diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp index 6b1a1fc1e..14daeeb75 100644 --- a/apps/opencs/model/doc/document.hpp +++ b/apps/opencs/model/doc/document.hpp @@ -13,6 +13,7 @@ #include #include "../world/data.hpp" +#include "../world/idcompletionmanager.hpp" #include "../tools/tools.hpp" @@ -66,6 +67,7 @@ namespace CSMDoc Blacklist mBlacklist; Runner mRunner; boost::shared_ptr mPhysics; + CSMWorld::IdCompletionManager mIdCompletionManager; // It is important that the undo stack is declared last, because on desctruction it fires a signal, that is connected to a slot, that is // using other member variables. Unfortunately this connection is cut only in the QObject destructor, which is way too late. @@ -144,6 +146,8 @@ namespace CSMDoc boost::shared_ptr getPhysics(); + CSMWorld::IdCompletionManager &getIdCompletionManager(); + signals: void stateChanged (int state, CSMDoc::Document *document); From 33e36ee9227d88e334c8dbc9f0fd8017216d54ee Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sat, 30 May 2015 15:51:33 +0300 Subject: [PATCH 1324/3725] Add the ID completion delegate --- apps/opencs/CMakeLists.txt | 2 +- .../view/world/idcompletiondelegate.cpp | 41 +++++++++++++++++++ .../view/world/idcompletiondelegate.hpp | 36 ++++++++++++++++ 3 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 apps/opencs/view/world/idcompletiondelegate.cpp create mode 100644 apps/opencs/view/world/idcompletiondelegate.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 99ba54ac1..efbe77ccb 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -69,7 +69,7 @@ opencs_units (view/world opencs_units_noqt (view/world subviews enumdelegate vartypedelegate recordstatusdelegate idtypedelegate datadisplaydelegate - scripthighlighter idvalidator dialoguecreator physicssystem + scripthighlighter idvalidator dialoguecreator physicssystem idcompletiondelegate ) opencs_units (view/widget diff --git a/apps/opencs/view/world/idcompletiondelegate.cpp b/apps/opencs/view/world/idcompletiondelegate.cpp new file mode 100644 index 000000000..0f309054b --- /dev/null +++ b/apps/opencs/view/world/idcompletiondelegate.cpp @@ -0,0 +1,41 @@ +#include "idcompletiondelegate.hpp" + +#include "../../model/world/idcompletionmanager.hpp" + +CSVWorld::IdCompletionDelegate::IdCompletionDelegate(CSMWorld::CommandDispatcher *dispatcher, + CSMDoc::Document& document, + QObject *parent) + : CommandDelegate(dispatcher, document, parent) +{} + +QWidget *CSVWorld::IdCompletionDelegate::createEditor(QWidget *parent, + const QStyleOptionViewItem &option, + const QModelIndex &index) const +{ + return createEditor(parent, option, index, CSMWorld::ColumnBase::Display_None); +} + +QWidget *CSVWorld::IdCompletionDelegate::createEditor(QWidget *parent, + const QStyleOptionViewItem &option, + const QModelIndex &index, + CSMWorld::ColumnBase::Display display) const +{ + int columnIdData = index.data(CSMWorld::ColumnBase::Role_ColumnId).toInt(); + CSMWorld::Columns::ColumnId columnId = static_cast(columnIdData); + CSMWorld::IdCompletionManager &completionManager = getDocument().getIdCompletionManager(); + + QWidget *editor = CSVWorld::CommandDelegate::createEditor(parent, option, index, display); + QLineEdit *lineEditor = qobject_cast(editor); + if (lineEditor != NULL && completionManager.isCompleterExistFor(columnId)) + { + lineEditor->setCompleter(completionManager.getCompleter(columnId).get()); + } + return editor; +} + +CSVWorld::CommandDelegate *CSVWorld::IdCompletionDelegateFactory::makeDelegate(CSMWorld::CommandDispatcher *dispatcher, + CSMDoc::Document& document, + QObject *parent) const +{ + return new IdCompletionDelegate(dispatcher, document, parent); +} \ No newline at end of file diff --git a/apps/opencs/view/world/idcompletiondelegate.hpp b/apps/opencs/view/world/idcompletiondelegate.hpp new file mode 100644 index 000000000..11ecc1cb9 --- /dev/null +++ b/apps/opencs/view/world/idcompletiondelegate.hpp @@ -0,0 +1,36 @@ +#ifndef CSV_WORLD_IDCOMPLETIONMANAGER_HPP +#define CSV_WORLD_IDCOMPLETIONMANAGER_HPP + +#include "util.hpp" + +namespace CSVWorld +{ + /// \brief Enables the Id completion for a column + class IdCompletionDelegate : public CommandDelegate + { + public: + IdCompletionDelegate(CSMWorld::CommandDispatcher *dispatcher, + CSMDoc::Document& document, + QObject *parent); + + virtual QWidget *createEditor (QWidget *parent, + const QStyleOptionViewItem &option, + const QModelIndex &index) const; + + virtual QWidget *createEditor (QWidget *parent, + const QStyleOptionViewItem &option, + const QModelIndex &index, + CSMWorld::ColumnBase::Display display) const; + }; + + class IdCompletionDelegateFactory : public CommandDelegateFactory + { + public: + virtual CommandDelegate *makeDelegate(CSMWorld::CommandDispatcher *dispatcher, + CSMDoc::Document& document, + QObject *parent) const; + ///< The ownership of the returned CommandDelegate is transferred to the caller. + }; +} + +#endif \ No newline at end of file From 7f2dd21c6642147a0cf7f27df29ab6559cab8938 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 30 May 2015 17:20:49 +0200 Subject: [PATCH 1325/3725] Fix for StartScript regression (Fixes #2590) --- apps/openmw/mwworld/store.hpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index d6aeeb51e..ba8be733a 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -366,6 +366,19 @@ namespace MWWorld inserted.first->second = scpt; } + template <> + inline void Store::load(ESM::ESMReader &esm, const std::string &id) + { + ESM::StartScript s; + s.load(esm); + s.mId = Misc::StringUtils::toLower(s.mId); + std::pair inserted = mStatic.insert(std::make_pair(s.mId, s)); + if (inserted.second) + mShared.push_back(&inserted.first->second); + else + inserted.first->second = s; + } + template <> class Store : public StoreBase { From 5e8718d8b2ba976f7e1c4a339a464f7786b047c1 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sat, 30 May 2015 18:37:13 +0300 Subject: [PATCH 1326/3725] Add the ID completion delegate factory to the delegate factory collection --- apps/opencs/view/doc/viewmanager.cpp | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 97b7aac19..3e7c2cb97 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -16,6 +16,7 @@ #include "../world/vartypedelegate.hpp" #include "../world/recordstatusdelegate.hpp" #include "../world/idtypedelegate.hpp" +#include "../world/idcompletiondelegate.hpp" #include "../../model/settings/usersettings.hpp" @@ -60,6 +61,33 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) mDelegateFactories->add (CSMWorld::ColumnBase::Display_RefRecordType, new CSVWorld::IdTypeDelegateFactory()); + // Columns with QLineEdit editor + static const CSMWorld::ColumnBase::Display sIdCompletionColumns[] = + { + CSMWorld::ColumnBase::Display_Class, + CSMWorld::ColumnBase::Display_Faction, + CSMWorld::ColumnBase::Display_String, + CSMWorld::ColumnBase::Display_GlobalVariable, + CSMWorld::ColumnBase::Display_Icon, + CSMWorld::ColumnBase::Display_Mesh, + CSMWorld::ColumnBase::Display_Miscellaneous, + CSMWorld::ColumnBase::Display_Music, + CSMWorld::ColumnBase::Display_None, + CSMWorld::ColumnBase::Display_Race, + CSMWorld::ColumnBase::Display_Region, + CSMWorld::ColumnBase::Display_Script, + CSMWorld::ColumnBase::Display_Skill, + CSMWorld::ColumnBase::Display_Sound, + CSMWorld::ColumnBase::Display_SoundRes, + CSMWorld::ColumnBase::Display_Texture, + CSMWorld::ColumnBase::Display_Video + }; + + for (std::size_t i = 0; i < sizeof(sIdCompletionColumns) / sizeof(CSMWorld::ColumnBase::Display); ++i) + { + mDelegateFactories->add(sIdCompletionColumns[i], new CSVWorld::IdCompletionDelegateFactory()); + } + struct Mapping { CSMWorld::ColumnBase::Display mDisplay; From 602f33bd91dfcc87da6d8a0cef37d40d2f482594 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sat, 30 May 2015 21:30:25 +0300 Subject: [PATCH 1327/3725] Add ColumnId role to the IdTree data methods --- apps/opencs/model/world/idtree.cpp | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/apps/opencs/model/world/idtree.cpp b/apps/opencs/model/world/idtree.cpp index 7351c03a7..a9ec2c4cd 100644 --- a/apps/opencs/model/world/idtree.cpp +++ b/apps/opencs/model/world/idtree.cpp @@ -35,28 +35,26 @@ QVariant CSMWorld::IdTree::data (const QModelIndex & index, int role) const if (!index.isValid()) return QVariant(); - if ((role!=Qt::DisplayRole && role!=Qt::EditRole) || index.row() < 0 || index.column() < 0) - return QVariant(); - if (index.internalId() != 0) { std::pair parentAddress(unfoldIndexAddress(index.internalId())); + const NestableColumn *parentColumn = mNestedCollection->getNestableColumn(parentAddress.second); - if (role == Qt::EditRole && - !mNestedCollection->getNestableColumn(parentAddress.second)->nestedColumn(index.column()).isEditable()) - { + if (role == ColumnBase::Role_ColumnId) + return parentColumn->nestedColumn(index.column()).mColumnId; + + if (role == Qt::EditRole && !parentColumn->nestedColumn(index.column()).isEditable()) + return QVariant(); + + if (role != Qt::DisplayRole && role != Qt::EditRole) return QVariant(); - } return mNestedCollection->getNestedData(parentAddress.first, parentAddress.second, index.row(), index.column()); } else { - if (role==Qt::EditRole && !idCollection()->getColumn (index.column()).isEditable()) - return QVariant(); - - return idCollection()->getData (index.row(), index.column()); + return IdTable::data(index, role); } } @@ -79,6 +77,9 @@ QVariant CSMWorld::IdTree::nestedHeaderData(int section, int subSection, Qt::Ori if (role==ColumnBase::Role_Display) return parentColumn->nestedColumn(subSection).mDisplayType; + if (role==ColumnBase::Role_ColumnId) + return parentColumn->nestedColumn(subSection).mColumnId; + return QVariant(); } From 62ce2cc123fb0a50ec3471664f235823b89979fb Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 30 May 2015 20:44:19 +0200 Subject: [PATCH 1328/3725] Minor cleanup --- CMakeLists.txt | 6 ------ 1 file changed, 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 87c3fabd4..3c3cd9f6b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -133,16 +133,10 @@ endif() # Platform specific if (WIN32) set(Boost_USE_STATIC_LIBS ON) - set(PLATFORM_INCLUDE_DIR "platform") add_definitions(-DBOOST_ALL_NO_LIB) # Suppress WinMain(), provided by SDL add_definitions(-DSDL_MAIN_HANDLED) -else (WIN32) - set(PLATFORM_INCLUDE_DIR "") -endif (WIN32) -if (MSVC10) - set(PLATFORM_INCLUDE_DIR "") endif() # Dependencies From e943d17b2905fb3b509662cda4800f6e5129191d Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sat, 30 May 2015 22:01:21 +0300 Subject: [PATCH 1329/3725] Check for invalid index in IdTable::flags(). This prevents QCompleter from crashes --- apps/opencs/model/world/idtable.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 04aa271cc..bde6412ec 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -84,6 +84,9 @@ bool CSMWorld::IdTable::setData (const QModelIndex &index, const QVariant &value Qt::ItemFlags CSMWorld::IdTable::flags (const QModelIndex & index) const { + if (!index.isValid()) + return 0; + Qt::ItemFlags flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled; if (mIdCollection->getColumn (index.column()).isUserEditable()) From 994c6833bcd91f72d00d1784a227dfcc14f0cfbc Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sat, 30 May 2015 23:54:16 +0300 Subject: [PATCH 1330/3725] Add missing columns for the ID completion --- apps/opencs/model/world/idcompletionmanager.cpp | 11 +++++++++-- apps/opencs/view/doc/viewmanager.cpp | 11 +++++++++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/apps/opencs/model/world/idcompletionmanager.cpp b/apps/opencs/model/world/idcompletionmanager.cpp index ca614dcd9..c9e135c83 100644 --- a/apps/opencs/model/world/idcompletionmanager.cpp +++ b/apps/opencs/model/world/idcompletionmanager.cpp @@ -22,16 +22,19 @@ namespace types[CSMWorld::Columns::ColumnId_CastingSound] = CSMWorld::UniversalId::Type_Sound; types[CSMWorld::Columns::ColumnId_Cell] = CSMWorld::UniversalId::Type_Cell; types[CSMWorld::Columns::ColumnId_Class] = CSMWorld::UniversalId::Type_Class; + types[CSMWorld::Columns::ColumnId_CloseSound] = CSMWorld::UniversalId::Type_Sound; types[CSMWorld::Columns::ColumnId_Creature] = CSMWorld::UniversalId::Type_Referenceable; types[CSMWorld::Columns::ColumnId_DestinationCell] = CSMWorld::UniversalId::Type_Cell; types[CSMWorld::Columns::ColumnId_Enchantment] = CSMWorld::UniversalId::Type_Enchantment; types[CSMWorld::Columns::ColumnId_Faction] = CSMWorld::UniversalId::Type_Faction; - types[CSMWorld::Columns::Columnid_Hair] = CSMWorld::UniversalId::Type_Mesh; - types[CSMWorld::Columns::ColumnId_Head] = CSMWorld::UniversalId::Type_Mesh; + types[CSMWorld::Columns::Columnid_Hair] = CSMWorld::UniversalId::Type_BodyPart; + types[CSMWorld::Columns::ColumnId_Head] = CSMWorld::UniversalId::Type_BodyPart; types[CSMWorld::Columns::ColumnId_HitObject] = CSMWorld::UniversalId::Type_Referenceable; types[CSMWorld::Columns::ColumnId_HitSound] = CSMWorld::UniversalId::Type_Sound; types[CSMWorld::Columns::ColumnId_Icon] = CSMWorld::UniversalId::Type_Icon; types[CSMWorld::Columns::ColumnId_InventoryItemId] = CSMWorld::UniversalId::Type_Referenceable; + types[CSMWorld::Columns::ColumnId_Key] = CSMWorld::UniversalId::Type_Referenceable; + types[CSMWorld::Columns::ColumnId_LevelledItemId] = CSMWorld::UniversalId::Type_Referenceable; types[CSMWorld::Columns::ColumnId_MajorSkill1] = CSMWorld::UniversalId::Type_Skill; types[CSMWorld::Columns::ColumnId_MajorSkill2] = CSMWorld::UniversalId::Type_Skill; types[CSMWorld::Columns::ColumnId_MajorSkill3] = CSMWorld::UniversalId::Type_Skill; @@ -43,9 +46,13 @@ namespace types[CSMWorld::Columns::ColumnId_MinorSkill4] = CSMWorld::UniversalId::Type_Skill; types[CSMWorld::Columns::ColumnId_MinorSkill5] = CSMWorld::UniversalId::Type_Skill; types[CSMWorld::Columns::ColumnId_Model] = CSMWorld::UniversalId::Type_Mesh; + types[CSMWorld::Columns::ColumnId_OpenSound] = CSMWorld::UniversalId::Type_Sound; + types[CSMWorld::Columns::ColumnId_OriginalCreature] = CSMWorld::UniversalId::Type_Referenceable; types[CSMWorld::Columns::ColumnId_Owner] = CSMWorld::UniversalId::Type_Referenceable; types[CSMWorld::Columns::ColumnId_OwnerGlobal] = CSMWorld::UniversalId::Type_Global; types[CSMWorld::Columns::ColumnId_Particle] = CSMWorld::UniversalId::Type_Texture; + types[CSMWorld::Columns::ColumnId_PartRefMale] = CSMWorld::UniversalId::Type_BodyPart; + types[CSMWorld::Columns::ColumnId_PartRefFemale] = CSMWorld::UniversalId::Type_BodyPart; types[CSMWorld::Columns::ColumnId_PcFaction] = CSMWorld::UniversalId::Type_Faction; types[CSMWorld::Columns::ColumnId_Race] = CSMWorld::UniversalId::Type_Race; types[CSMWorld::Columns::ColumnId_ReferenceableId] = CSMWorld::UniversalId::Type_Referenceable; diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 3e7c2cb97..f48513703 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -64,7 +64,9 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) // Columns with QLineEdit editor static const CSMWorld::ColumnBase::Display sIdCompletionColumns[] = { + CSMWorld::ColumnBase::Display_Cell, CSMWorld::ColumnBase::Display_Class, + CSMWorld::ColumnBase::Display_Creature, CSMWorld::ColumnBase::Display_Faction, CSMWorld::ColumnBase::Display_String, CSMWorld::ColumnBase::Display_GlobalVariable, @@ -72,15 +74,20 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) CSMWorld::ColumnBase::Display_Mesh, CSMWorld::ColumnBase::Display_Miscellaneous, CSMWorld::ColumnBase::Display_Music, - CSMWorld::ColumnBase::Display_None, + CSMWorld::ColumnBase::Display_None, // Inplace editing (Table SubView) creates QLineEdit using Display_None + CSMWorld::ColumnBase::Display_Npc, CSMWorld::ColumnBase::Display_Race, + CSMWorld::ColumnBase::Display_Referenceable, CSMWorld::ColumnBase::Display_Region, CSMWorld::ColumnBase::Display_Script, CSMWorld::ColumnBase::Display_Skill, CSMWorld::ColumnBase::Display_Sound, CSMWorld::ColumnBase::Display_SoundRes, + CSMWorld::ColumnBase::Display_Static, + CSMWorld::ColumnBase::Display_String, CSMWorld::ColumnBase::Display_Texture, - CSMWorld::ColumnBase::Display_Video + CSMWorld::ColumnBase::Display_Video, + CSMWorld::ColumnBase::Display_Weapon }; for (std::size_t i = 0; i < sizeof(sIdCompletionColumns) / sizeof(CSMWorld::ColumnBase::Display); ++i) From a066b2430331e156f340e50f32dd56785d945df3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 31 May 2015 01:07:43 +0200 Subject: [PATCH 1331/3725] Restore WeaponAnimation --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwbase/world.hpp | 3 +- apps/openmw/mwmechanics/character.cpp | 2 +- apps/openmw/mwrender/animation.hpp | 51 ++++++++-------- apps/openmw/mwrender/camera.cpp | 2 +- apps/openmw/mwrender/creatureanimation.cpp | 58 +++++++++++------- apps/openmw/mwrender/creatureanimation.hpp | 16 ++--- apps/openmw/mwrender/npcanimation.cpp | 49 +++++++++++---- apps/openmw/mwrender/npcanimation.hpp | 6 +- apps/openmw/mwrender/weaponanimation.cpp | 69 ++++++++++------------ apps/openmw/mwrender/weaponanimation.hpp | 26 ++++---- apps/openmw/mwworld/worldimp.cpp | 2 +- apps/openmw/mwworld/worldimp.hpp | 2 +- components/esm/defs.hpp | 2 + 14 files changed, 170 insertions(+), 120 deletions(-) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index b4ecdd956..2193f4ca0 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -21,7 +21,7 @@ source_group(game FILES ${GAME} ${GAME_HEADER}) add_openmw_dir (mwrender actors objects renderingmanager animation sky npcanimation vismask - creatureanimation effectmanager util renderinginterface pathgrid rendermode + creatureanimation effectmanager util renderinginterface pathgrid rendermode weaponanimation bulletdebugdraw globalmap characterpreview camera localmap # occlusionquery water shadows # ripplesimulation refraction diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index c0e2ade0f..4d01f9529 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -22,6 +22,7 @@ namespace Ogre namespace osg { class Vec3f; + class Quat; } namespace Loading @@ -486,7 +487,7 @@ namespace MWBase float speed, bool stack, const ESM::EffectList& effects, const MWWorld::Ptr& caster, const std::string& sourceName, const Ogre::Vector3& fallbackDirection) = 0; virtual void launchProjectile (MWWorld::Ptr actor, MWWorld::Ptr projectile, - const Ogre::Vector3& worldPos, const Ogre::Quaternion& orient, MWWorld::Ptr bow, float speed) = 0; + const osg::Vec3f& worldPos, const osg::Quat& orient, MWWorld::Ptr bow, float speed) = 0; virtual const std::vector& getContentFiles() const = 0; diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 379025c9e..5765d8b04 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -812,7 +812,7 @@ void CharacterController::handleTextKey(const std::string &groupname, const std: else if (evt.compare(off, len, "shoot attach") == 0) mAnimation->attachArrow(); else if (evt.compare(off, len, "shoot release") == 0) - {;}//mAnimation->releaseArrow(); + mAnimation->releaseArrow(); else if (evt.compare(off, len, "shoot follow attach") == 0) mAnimation->attachArrow(); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index d1a1b01c6..86dd21df4 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -39,6 +39,31 @@ public: EffectAnimationTime() : mTime(0) { } }; +/// @brief Detaches the node from its parent when the object goes out of scope. +class PartHolder +{ +public: + PartHolder(osg::ref_ptr node) + : mNode(node) + { + } + + ~PartHolder() + { + if (mNode->getNumParents()) + mNode->getParent(0)->removeChild(mNode); + } + + osg::ref_ptr getNode() + { + return mNode; + } + +private: + osg::ref_ptr mNode; +}; +typedef boost::shared_ptr PartHolderPtr; + class Animation { public: @@ -174,31 +199,6 @@ protected: osg::Vec3f mAccumulate; - /// @brief Detaches the node from its parent when the object goes out of scope. - class PartHolder - { - public: - PartHolder(osg::ref_ptr node) - : mNode(node) - { - } - - ~PartHolder() - { - if (mNode->getNumParents()) - mNode->getParent(0)->removeChild(mNode); - } - - osg::ref_ptr getNode() - { - return mNode; - } - - private: - osg::ref_ptr mNode; - }; - typedef boost::shared_ptr PartHolderPtr; - struct EffectParams { std::string mModelName; // Just here so we don't add the same effect twice @@ -378,6 +378,7 @@ public: virtual void setAlpha(float alpha) {} virtual void setPitchFactor(float factor) {} virtual void attachArrow() {} + virtual void releaseArrow() {} virtual void enableHeadAnimation(bool enable) {} // TODO: move outside of this class /// Makes this object glow, by placing a Light in its center. diff --git a/apps/openmw/mwrender/camera.cpp b/apps/openmw/mwrender/camera.cpp index a945a171e..392f8978a 100644 --- a/apps/openmw/mwrender/camera.cpp +++ b/apps/openmw/mwrender/camera.cpp @@ -361,7 +361,7 @@ namespace MWRender if(isFirstPerson()) { mAnimation->setViewMode(NpcAnimation::VM_FirstPerson); - mTrackingNode = mAnimation->getNode("Head"); + mTrackingNode = mAnimation->getNode("Camera"); } else { diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index b653f4d30..b98b26179 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include "../mwbase/world.hpp" @@ -52,7 +53,7 @@ CreatureWeaponAnimation::CreatureWeaponAnimation(const MWWorld::Ptr &ptr, const updateParts(); } - //mWeaponAnimationTime = Ogre::SharedPtr(new WeaponAnimationTime(this)); + mWeaponAnimationTime = boost::shared_ptr(new WeaponAnimationTime(this)); } void CreatureWeaponAnimation::showWeapons(bool showWeapon) @@ -122,35 +123,52 @@ void CreatureWeaponAnimation::updatePart(PartHolderPtr& scene, int slot) MWWorld::ContainerStoreIterator ammo = inv.getSlot(MWWorld::InventoryStore::Slot_Ammunition); if (ammo != inv.end() && ammo->get()->mBase->mData.mType == ESM::Weapon::Bolt) attachArrow(); - //else - // mAmmunition.setNull(); + else + mAmmunition.reset(); } - //else - //mAmmunition.setNull(); + else + mAmmunition.reset(); - /* - std::vector >::iterator ctrl(scene->mControllers.begin()); - for(;ctrl != scene->mControllers.end();++ctrl) - { - if(ctrl->getSource().isNull()) - { - if (slot == MWWorld::InventoryStore::Slot_CarriedRight) - ctrl->setSource(mWeaponAnimationTime); - else - ctrl->setSource(Ogre::SharedPtr(new NullAnimationTime())); - } - } - */ + boost::shared_ptr source; + + if (slot == MWWorld::InventoryStore::Slot_CarriedRight) + source = mWeaponAnimationTime; + else + source.reset(new NullAnimationTime); + + SceneUtil::AssignControllerSourcesVisitor assignVisitor(source); + node->accept(assignVisitor); } void CreatureWeaponAnimation::attachArrow() { - //WeaponAnimation::attachArrow(mPtr); + WeaponAnimation::attachArrow(mPtr); } void CreatureWeaponAnimation::releaseArrow() { - //WeaponAnimation::releaseArrow(mPtr); + WeaponAnimation::releaseArrow(mPtr); +} + +osg::Group *CreatureWeaponAnimation::getArrowBone() +{ + if (!mWeapon) + return NULL; + + SceneUtil::FindByNameVisitor findVisitor ("ArrowBone"); + mWeapon->getNode()->accept(findVisitor); + + return findVisitor.mFoundNode; +} + +osg::Node *CreatureWeaponAnimation::getWeaponNode() +{ + return mWeapon ? mWeapon->getNode().get() : NULL; +} + +Resource::ResourceSystem *CreatureWeaponAnimation::getResourceSystem() +{ + return mResourceSystem; } osg::Vec3f CreatureWeaponAnimation::runAnimation(float duration) diff --git a/apps/openmw/mwrender/creatureanimation.hpp b/apps/openmw/mwrender/creatureanimation.hpp index ccb553d99..61d077df3 100644 --- a/apps/openmw/mwrender/creatureanimation.hpp +++ b/apps/openmw/mwrender/creatureanimation.hpp @@ -22,7 +22,7 @@ namespace MWRender // For creatures with weapons and shields // Animation is already virtual anyway, so might as well make a separate class. // Most creatures don't need weapons/shields, so this will save some memory. - class CreatureWeaponAnimation : public Animation/*, public WeaponAnimation*/, public MWWorld::InventoryStoreListener + class CreatureWeaponAnimation : public Animation, public WeaponAnimation, public MWWorld::InventoryStoreListener { public: CreatureWeaponAnimation(const MWWorld::Ptr &ptr, const std::string& model, Resource::ResourceSystem* resourceSystem); @@ -39,6 +39,12 @@ namespace MWRender virtual void attachArrow(); virtual void releaseArrow(); + // WeaponAnimation + virtual osg::Group* getArrowBone(); + virtual osg::Node* getWeaponNode(); + virtual Resource::ResourceSystem* getResourceSystem(); + virtual void showWeapon(bool show) { showWeapons(show); } + virtual void setWeaponGroup(const std::string& group) { mWeaponAnimationTime->setGroup(group); } virtual osg::Vec3f runAnimation(float duration); @@ -46,12 +52,6 @@ namespace MWRender /// to indicate the facing orientation of the character. //virtual void setPitchFactor(float factor) { mPitchFactor = factor; } - //virtual void setWeaponGroup(const std::string& group) { mWeaponAnimationTime->setGroup(group); } - - // WeaponAnimation - //virtual NifOgre::ObjectScenePtr getWeapon() { return mWeapon; } - //virtual void showWeapon(bool show) { showWeapons(show); } - //virtual void configureAddedObject(NifOgre::ObjectScenePtr object, MWWorld::Ptr ptr, int slot); private: PartHolderPtr mWeapon; @@ -59,7 +59,7 @@ namespace MWRender bool mShowWeapons; bool mShowCarriedLeft; - //Ogre::SharedPtr mWeaponAnimationTime; + boost::shared_ptr mWeaponAnimationTime; }; } diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index aeff1f60a..e9e3b7aef 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -2,6 +2,9 @@ #include + +#include // XXX + #include #include @@ -9,6 +12,7 @@ #include #include #include +#include #include // TextKeyMapHolder @@ -203,7 +207,7 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, osg::ref_ptr par mNpc = mPtr.get()->mBase; mHeadAnimationTime = boost::shared_ptr(new HeadAnimationTime(mPtr)); - //mWeaponAnimationTime = Ogre::SharedPtr(new WeaponAnimationTime(this)); + mWeaponAnimationTime = boost::shared_ptr(new WeaponAnimationTime(this)); for(size_t i = 0;i < ESM::PRT_Count;i++) { @@ -333,7 +337,7 @@ void NpcAnimation::updateNpcBase() removeIndividualPart((ESM::PartReferenceType)i); updateParts(); - //mWeaponAnimationTime->updateStartTime(); + mWeaponAnimationTime->updateStartTime(); } void NpcAnimation::updateParts() @@ -585,7 +589,7 @@ void NpcAnimation::addFirstPersonOffset(const Ogre::Vector3 &offset) mFirstPersonOffset += offset; }*/ -Animation::PartHolderPtr NpcAnimation::insertBoundedPart(const std::string& model, const std::string& bonename, const std::string& bonefilter, bool enchantedGlow, osg::Vec4f* glowColor) +PartHolderPtr NpcAnimation::insertBoundedPart(const std::string& model, const std::string& bonename, const std::string& bonefilter, bool enchantedGlow, osg::Vec4f* glowColor) { osg::ref_ptr instance = mResourceSystem->getSceneManager()->createInstance(model); osg::ref_ptr attached = SceneUtil::attach(instance, mObjectRoot, bonefilter, bonename); @@ -729,8 +733,8 @@ bool NpcAnimation::addOrReplaceIndividualPart(ESM::PartReferenceType type, int g } } } - //else if (type == ESM::PRT_Weapon) - // src = mWeaponAnimationTime; + else if (type == ESM::PRT_Weapon) + src = mWeaponAnimationTime; else src.reset(new NullAnimationTime); @@ -809,11 +813,11 @@ void NpcAnimation::showWeapons(bool showWeapon) MWWorld::ContainerStoreIterator ammo = inv.getSlot(MWWorld::InventoryStore::Slot_Ammunition); if (ammo != inv.end() && ammo->get()->mBase->mData.mType == ESM::Weapon::Bolt) attachArrow(); - //else - //mAmmunition.setNull(); + else + mAmmunition.reset(); } - //else - //mAmmunition.setNull(); + else + mAmmunition.reset(); } } else @@ -853,6 +857,31 @@ void NpcAnimation::releaseArrow() WeaponAnimation::releaseArrow(mPtr); } +osg::Group* NpcAnimation::getArrowBone() +{ + PartHolderPtr part = mObjectParts[ESM::PRT_Weapon]; + if (!part) + return NULL; + + SceneUtil::FindByNameVisitor findVisitor ("ArrowBone"); + part->getNode()->accept(findVisitor); + + return findVisitor.mFoundNode; +} + +osg::Node* NpcAnimation::getWeaponNode() +{ + PartHolderPtr part = mObjectParts[ESM::PRT_Weapon]; + if (!part) + return NULL; + return part->getNode(); +} + +Resource::ResourceSystem* NpcAnimation::getResourceSystem() +{ + return mResourceSystem; +} + void NpcAnimation::permanentEffectAdded(const ESM::MagicEffect *magicEffect, bool isNew, bool playSound) { // During first auto equip, we don't play any sounds. @@ -897,7 +926,7 @@ void NpcAnimation::enableHeadAnimation(bool enable) void NpcAnimation::setWeaponGroup(const std::string &group) { - //mWeaponAnimationTime-> + mWeaponAnimationTime->setGroup(group); } void NpcAnimation::equipmentChanged() diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index eda59f50c..0f90bb2d7 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -95,7 +95,7 @@ private: //Ogre::Vector3 mFirstPersonOffset; boost::shared_ptr mHeadAnimationTime; - //Ogre::SharedPtr mWeaponAnimationTime; + boost::shared_ptr mWeaponAnimationTime; float mAlpha; bool mSoundsDisabled; @@ -157,6 +157,10 @@ public: virtual void attachArrow(); virtual void releaseArrow(); + virtual osg::Group* getArrowBone(); + virtual osg::Node* getWeaponNode(); + virtual Resource::ResourceSystem* getResourceSystem(); + // WeaponAnimation //virtual NifOgre::ObjectScenePtr getWeapon() { return mObjectParts[ESM::PRT_Weapon]; } virtual void showWeapon(bool show) { showWeapons(show); } diff --git a/apps/openmw/mwrender/weaponanimation.cpp b/apps/openmw/mwrender/weaponanimation.cpp index d16afe3ce..23a74fb95 100644 --- a/apps/openmw/mwrender/weaponanimation.cpp +++ b/apps/openmw/mwrender/weaponanimation.cpp @@ -1,9 +1,7 @@ #include "weaponanimation.hpp" -#include -#include -#include -#include +#include +#include #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" @@ -21,10 +19,11 @@ namespace MWRender { -float WeaponAnimationTime::getValue() const +float WeaponAnimationTime::getValue(osg::NodeVisitor*) { if (mWeaponGroup.empty()) return 0; + float current = mAnimation->getCurrentTime(mWeaponGroup); if (current == -1) return 0; @@ -42,6 +41,11 @@ void WeaponAnimationTime::updateStartTime() setGroup(mWeaponGroup); } +WeaponAnimation::WeaponAnimation() + : mPitchFactor(0) +{ +} + void WeaponAnimation::attachArrow(MWWorld::Ptr actor) { MWWorld::InventoryStore& inv = actor.getClass().getInventoryStore(actor); @@ -63,8 +67,8 @@ void WeaponAnimation::attachArrow(MWWorld::Ptr actor) } else if (weaponType == ESM::Weapon::MarksmanBow || weaponType == ESM::Weapon::MarksmanCrossbow) { - NifOgre::ObjectScenePtr weapon = getWeapon(); - if (!weapon.get()) + osg::Group* parent = getArrowBone(); + if (!parent) return; MWWorld::ContainerStoreIterator ammo = inv.getSlot(MWWorld::InventoryStore::Slot_Ammunition); @@ -72,12 +76,9 @@ void WeaponAnimation::attachArrow(MWWorld::Ptr actor) return; std::string model = ammo->getClass().getModel(*ammo); - if (!weapon->mSkelBase) - throw std::runtime_error("Need a skeleton to attach the arrow to"); + osg::ref_ptr arrow = getResourceSystem()->getSceneManager()->createInstance(model, parent); - const std::string bonename = "ArrowBone"; - mAmmunition = NifOgre::Loader::createObjects(weapon->mSkelBase, bonename, bonename, weapon->mSkelBase->getParentSceneNode(), model); - configureAddedObject(mAmmunition, *ammo, MWWorld::InventoryStore::Slot_Ammunition); + mAmmunition = PartHolderPtr(new PartHolder(arrow)); } } @@ -91,8 +92,8 @@ void WeaponAnimation::releaseArrow(MWWorld::Ptr actor) return; // The orientation of the launched projectile. Always the same as the actor orientation, even if the ArrowBone's orientation dictates otherwise. - Ogre::Quaternion orient = Ogre::Quaternion(Ogre::Radian(actor.getRefData().getPosition().rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z) * - Ogre::Quaternion(Ogre::Radian(actor.getRefData().getPosition().rot[0]), Ogre::Vector3::NEGATIVE_UNIT_X); + osg::Quat orient = osg::Quat(actor.getRefData().getPosition().rot[0], osg::Vec3f(-1,0,0)) + * osg::Quat(actor.getRefData().getPosition().rot[2], osg::Vec3f(0,0,-1)); const MWWorld::Store &gmst = MWBase::Environment::get().getWorld()->getStore().get(); @@ -102,18 +103,13 @@ void WeaponAnimation::releaseArrow(MWWorld::Ptr actor) if (weapon->get()->mBase->mData.mType == ESM::Weapon::MarksmanThrown) { // Thrown weapons get detached now - NifOgre::ObjectScenePtr objects = getWeapon(); - - Ogre::Vector3 launchPos(0,0,0); - if (objects->mSkelBase) - { - launchPos = objects->mSkelBase->getParentNode()->_getDerivedPosition(); - } - else if (objects->mEntities.size()) - { - objects->mEntities[0]->getParentNode()->needUpdate(true); - launchPos = objects->mEntities[0]->getParentNode()->_getDerivedPosition(); - } + osg::Node* weaponNode = getWeaponNode(); + if (!weaponNode) + return; + osg::MatrixList mats = weaponNode->getWorldMatrices(); + if (mats.empty()) + return; + osg::Vec3f launchPos = mats[0].getTrans(); float fThrownWeaponMinSpeed = gmst.find("fThrownWeaponMinSpeed")->getFloat(); float fThrownWeaponMaxSpeed = gmst.find("fThrownWeaponMaxSpeed")->getFloat(); @@ -133,19 +129,14 @@ void WeaponAnimation::releaseArrow(MWWorld::Ptr actor) if (ammo == inv.end()) return; - if (!mAmmunition.get()) + if (!mAmmunition) return; - Ogre::Vector3 launchPos(0,0,0); - if (mAmmunition->mSkelBase) - { - launchPos = mAmmunition->mSkelBase->getParentNode()->_getDerivedPosition(); - } - else if (mAmmunition->mEntities.size()) - { - mAmmunition->mEntities[0]->getParentNode()->needUpdate(true); - launchPos = mAmmunition->mEntities[0]->getParentNode()->_getDerivedPosition(); - } + osg::ref_ptr ammoNode = mAmmunition->getNode(); + osg::MatrixList mats = ammoNode->getWorldMatrices(); + if (mats.empty()) + return; + osg::Vec3f launchPos = mats[0].getTrans(); float fProjectileMinSpeed = gmst.find("fProjectileMinSpeed")->getFloat(); float fProjectileMaxSpeed = gmst.find("fProjectileMaxSpeed")->getFloat(); @@ -154,10 +145,11 @@ void WeaponAnimation::releaseArrow(MWWorld::Ptr actor) MWBase::Environment::get().getWorld()->launchProjectile(actor, *ammo, launchPos, orient, *weapon, speed); inv.remove(*ammo, 1, actor); - mAmmunition.setNull(); + mAmmunition.reset(); } } +/* void WeaponAnimation::pitchSkeleton(float xrot, Ogre::SkeletonInstance* skel) { if (mPitchFactor == 0) @@ -179,5 +171,6 @@ void WeaponAnimation::pitchSkeleton(float xrot, Ogre::SkeletonInstance* skel) node = skel->getBone("Bip01 Spine1"); node->pitch(Ogre::Radian(-pitch/2), Ogre::Node::TS_WORLD); } +*/ } diff --git a/apps/openmw/mwrender/weaponanimation.hpp b/apps/openmw/mwrender/weaponanimation.hpp index 400962856..f46638ac8 100644 --- a/apps/openmw/mwrender/weaponanimation.hpp +++ b/apps/openmw/mwrender/weaponanimation.hpp @@ -1,15 +1,15 @@ #ifndef OPENMW_MWRENDER_WEAPONANIMATION_H #define OPENMW_MWRENDER_WEAPONANIMATION_H +#include + #include "../mwworld/ptr.hpp" +#include "animation.hpp" namespace MWRender { - class Animation; - - /* - class WeaponAnimationTime : public Ogre::ControllerValue + class WeaponAnimationTime : public SceneUtil::ControllerSource { private: Animation* mAnimation; @@ -20,27 +20,29 @@ namespace MWRender void setGroup(const std::string& group); void updateStartTime(); - virtual Ogre::Real getValue() const; - virtual void setValue(Ogre::Real value) - { } + virtual float getValue(osg::NodeVisitor* nv); }; - */ /// Handles attach & release of projectiles for ranged weapons class WeaponAnimation { public: - WeaponAnimation() : mPitchFactor(0) {} + WeaponAnimation(); virtual ~WeaponAnimation() {} /// @note If no weapon (or an invalid weapon) is equipped, this function is a no-op. - void attachArrow(MWWorld::Ptr actor) {} + void attachArrow(MWWorld::Ptr actor); /// @note If no weapon (or an invalid weapon) is equipped, this function is a no-op. - void releaseArrow(MWWorld::Ptr actor) {} + void releaseArrow(MWWorld::Ptr actor); protected: - //NifOgre::ObjectScenePtr mAmmunition; + PartHolderPtr mAmmunition; + + virtual osg::Group* getArrowBone() = 0; + virtual osg::Node* getWeaponNode() = 0; + virtual Resource::ResourceSystem* getResourceSystem() = 0; + //virtual NifOgre::ObjectScenePtr getWeapon() = 0; virtual void showWeapon(bool show) = 0; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 39b26c5d2..768177b16 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2757,7 +2757,7 @@ namespace MWWorld } void World::launchProjectile (MWWorld::Ptr actor, MWWorld::Ptr projectile, - const Ogre::Vector3& worldPos, const Ogre::Quaternion& orient, MWWorld::Ptr bow, float speed) + const osg::Vec3f& worldPos, const osg::Quat& orient, MWWorld::Ptr bow, float speed) { #if 0 mProjectileManager->launchProjectile(actor, projectile, worldPos, orient, bow, speed); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index b642a1ba7..b1718f030 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -574,7 +574,7 @@ namespace MWWorld float speed, bool stack, const ESM::EffectList& effects, const MWWorld::Ptr& caster, const std::string& sourceName, const Ogre::Vector3& fallbackDirection); virtual void launchProjectile (MWWorld::Ptr actor, MWWorld::Ptr projectile, - const Ogre::Vector3& worldPos, const Ogre::Quaternion& orient, MWWorld::Ptr bow, float speed); + const osg::Vec3f& worldPos, const osg::Quat& orient, MWWorld::Ptr bow, float speed); virtual const std::vector& getContentFiles() const; diff --git a/components/esm/defs.hpp b/components/esm/defs.hpp index 8ce76a8ea..9f1a935ae 100644 --- a/components/esm/defs.hpp +++ b/components/esm/defs.hpp @@ -38,6 +38,8 @@ enum RangeType struct Position { float pos[3]; + + // In radians float rot[3]; osg::Vec3f asVec3() const From 60f55997fd0942e663b041376814f5788e0e5afa Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 31 May 2015 02:26:31 +0200 Subject: [PATCH 1332/3725] Rotate first person meshes, sneak camera offset in first person --- apps/openmw/mwrender/animation.cpp | 17 ++- apps/openmw/mwrender/animation.hpp | 12 ++- apps/openmw/mwrender/camera.cpp | 2 +- apps/openmw/mwrender/npcanimation.cpp | 146 ++++++++++++++++++++++---- apps/openmw/mwrender/npcanimation.hpp | 12 ++- 5 files changed, 153 insertions(+), 36 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 403f270d8..b23981f81 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -603,7 +603,7 @@ namespace MWRender void Animation::resetActiveGroups() { // remove all previous external controllers from the scene graph - for (AnimSourceControllerMap::iterator it = mAnimSourceControllers.begin(); it != mAnimSourceControllers.end(); ++it) + for (ControllerMap::iterator it = mActiveControllers.begin(); it != mActiveControllers.end(); ++it) { osg::Node* node = it->first; node->removeUpdateCallback(it->second); @@ -611,13 +611,8 @@ namespace MWRender // Should be no longer needed with OSG 3.4 it->second->setNestedCallback(NULL); } - if (mResetAccumRootCallback && mAccumRoot) - { - mAccumRoot->removeUpdateCallback(mResetAccumRootCallback); - // Should be no longer needed with OSG 3.4 - mResetAccumRootCallback->setNestedCallback(NULL); - } - mAnimSourceControllers.clear(); + + mActiveControllers.clear(); mAccumCtrl = NULL; @@ -647,7 +642,7 @@ namespace MWRender osg::ref_ptr node = mNodeMap.at(it->first); // this should not throw, we already checked for the node existing in addAnimSource node->addUpdateCallback(it->second); - mAnimSourceControllers[node] = it->second; + mActiveControllers.insert(std::make_pair(node, it->second)); if (grp == 0 && node == mAccumRoot) { @@ -660,10 +655,12 @@ namespace MWRender mResetAccumRootCallback->setAccumulate(mAccumulate); } mAccumRoot->addUpdateCallback(mResetAccumRootCallback); + mActiveControllers.insert(std::make_pair(mAccumRoot, mResetAccumRootCallback)); } } } } + addControllers(); } void Animation::changeGroups(const std::string &groupname, int groups) @@ -893,7 +890,7 @@ namespace MWRender mObjectRoot = NULL; mNodeMap.clear(); - mAnimSourceControllers.clear(); + mActiveControllers.clear(); mAccumRoot = NULL; mAccumCtrl = NULL; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 86dd21df4..e30f2b082 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -182,10 +182,10 @@ protected: // Used to reset the position of the accumulation root every frame - the movement should be applied to the physics system osg::ref_ptr mResetAccumRootCallback; - // Keep track of keyframe controllers from external files that we added to our scene graph. + // Keep track of controllers that we added to our scene graph. // We may need to rebuild these controllers when the active animation groups / sources change. - typedef std::map, osg::ref_ptr > AnimSourceControllerMap; - AnimSourceControllerMap mAnimSourceControllers; + typedef std::multimap, osg::ref_ptr > ControllerMap; + ControllerMap mActiveControllers; boost::shared_ptr mAnimationTimePtr[sNumGroups]; @@ -256,6 +256,12 @@ protected: void clearAnimSources(); + /** + * Provided to allow derived classes adding their own controllers. Note, the controllers must be added to mActiveControllers + * so they get cleaned up properly on the next controller rebuild. A controller rebuild may be necessary to ensure correct ordering. + */ + virtual void addControllers() {} + osg::Vec4f getEnchantmentColor(MWWorld::Ptr item); void addGlow(osg::ref_ptr node, osg::Vec4f glowColor); diff --git a/apps/openmw/mwrender/camera.cpp b/apps/openmw/mwrender/camera.cpp index 392f8978a..bb4724555 100644 --- a/apps/openmw/mwrender/camera.cpp +++ b/apps/openmw/mwrender/camera.cpp @@ -250,7 +250,7 @@ namespace MWRender void Camera::setSneakOffset(float offset) { - // TODO: implement + mAnimation->setFirstPersonOffset(osg::Vec3f(0,0,-offset)); } float Camera::getYaw() diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index e9e3b7aef..598e2fba9 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -1,9 +1,7 @@ #include "npcanimation.hpp" #include - - -#include // XXX +#include #include @@ -74,6 +72,100 @@ std::string getVampireHead(const std::string& race, bool female) namespace MWRender { +/// @note Assumes that the node being rotated has its "original" orientation set every frame by a different controller. +/// The pitch is then applied on top of that orientation. +/// @note Must be set on a MatrixTransform. +class RotateController : public osg::NodeCallback +{ +public: + RotateController(osg::Node* relativeTo, osg::Vec3f axis) + : mRotate(0.f) + , mAxis(axis) + , mRelativeTo(relativeTo) + { + + } + + void setRotate(float rotate) + { + mRotate = rotate; + } + + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) + { + if (mRotate == 0.f) + return; + osg::MatrixTransform* transform = static_cast(node); + osg::Matrix matrix = transform->getMatrix(); + osg::Quat worldOrient = getWorldOrientation(node); + + osg::Quat rotate (mRotate, mAxis); + osg::Quat orient = worldOrient * rotate * worldOrient.inverse() * matrix.getRotate(); + matrix.setRotate(orient); + + transform->setMatrix(matrix); + + traverse(node,nv); + } + + osg::Quat getWorldOrientation(osg::Node* node) + { + // this could be optimized later, we just need the world orientation, not the full matrix + osg::MatrixList worldMats = node->getWorldMatrices(mRelativeTo); + osg::Quat worldOrient; + if (worldMats.size()) + { + osg::Matrixf worldMat = worldMats[0]; + worldOrient = worldMat.getRotate(); + } + return worldOrient; + } + +protected: + float mRotate; + osg::Vec3f mAxis; + osg::ref_ptr mRelativeTo; +}; + +/// Subclass RotateController to add a Z-offset for sneaking in first person mode. +/// @note We use inheritance instead of adding another controller, so that we do not have to compute the worldOrient twice. +/// @note Must be set on a MatrixTransform. +class NeckController : public RotateController +{ +public: + NeckController(osg::Node* relativeTo) + : RotateController(relativeTo, osg::Vec3f(-1,0,0)) + { + } + + void setOffset(osg::Vec3f offset) + { + mOffset = offset; + } + + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) + { + osg::MatrixTransform* transform = static_cast(node); + osg::Matrix matrix = transform->getMatrix(); + + osg::Quat worldOrient = getWorldOrientation(node); + osg::Quat rotate (mRotate, mAxis); + osg::Quat orient = worldOrient * rotate * worldOrient.inverse() * matrix.getRotate(); + + matrix.setRotate(orient); + matrix.setTrans(matrix.getTrans() + worldOrient.inverse() * mOffset); + + transform->setMatrix(matrix); + + traverse(node,nv); + } + +private: + osg::Vec3f mOffset; +}; + +// -------------------------------------------------------------------------------------------------------------- + HeadAnimationTime::HeadAnimationTime(MWWorld::Ptr reference) : mReference(reference), mTalkStart(0), mTalkStop(0), mBlinkStart(0), mBlinkStop(0), mEnabled(true), mValue(0) { @@ -150,6 +242,8 @@ void HeadAnimationTime::setBlinkStop(float value) mBlinkStop = value; } +// ---------------------------------------------------- + static NpcAnimation::PartBoneMap createPartListMap() { NpcAnimation::PartBoneMap result; @@ -196,7 +290,6 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, osg::ref_ptr par mViewMode(viewMode), mShowWeapons(false), mShowCarriedLeft(true), - //mFirstPersonOffset(0.f, 0.f, 0.f), mNpcType(Type_Normal), mVisibilityFlags(visibilityFlags), mAlpha(1.f), @@ -583,11 +676,6 @@ void NpcAnimation::updateParts() if (wasArrowAttached) attachArrow(); } -/* -void NpcAnimation::addFirstPersonOffset(const Ogre::Vector3 &offset) -{ - mFirstPersonOffset += offset; -}*/ PartHolderPtr NpcAnimation::insertBoundedPart(const std::string& model, const std::string& bonename, const std::string& bonefilter, bool enchantedGlow, osg::Vec4f* glowColor) { @@ -605,21 +693,17 @@ osg::Vec3f NpcAnimation::runAnimation(float timepassed) mHeadAnimationTime->update(timepassed); + if (mFirstPersonNeckController) + { + mFirstPersonNeckController->setRotate(mPtr.getRefData().getPosition().rot[0]); + mFirstPersonNeckController->setOffset(mFirstPersonOffset); + } + /* if (mSkelBase) { Ogre::SkeletonInstance *baseinst = mSkelBase->getSkeleton(); - if(mViewMode == VM_FirstPerson) - { - float pitch = mPtr.getRefData().getPosition().rot[0]; - Ogre::Node *node = baseinst->getBone("Bip01 Neck"); - node->pitch(Ogre::Radian(-pitch), Ogre::Node::TS_WORLD); - - // This has to be done before this function ends; - // updateSkeletonInstance, below, touches the hands. - node->translate(mFirstPersonOffset, Ogre::Node::TS_WORLD); - } - else + if(mViewMode != VM_FirstPerson) { // In third person mode we may still need pitch for ranged weapon targeting pitchSkeleton(mPtr.getRefData().getPosition().rot[0], baseinst); @@ -629,7 +713,6 @@ osg::Vec3f NpcAnimation::runAnimation(float timepassed) node->rotate(Ogre::Quaternion(mHeadYaw, Ogre::Vector3::UNIT_Z) * Ogre::Quaternion(mHeadPitch, Ogre::Vector3::UNIT_X), Ogre::Node::TS_WORLD); } } - mFirstPersonOffset = 0.f; // reset the X, Y, Z offset for the next frame. */ return ret; @@ -792,6 +875,22 @@ void NpcAnimation::addPartGroup(int group, int priority, const std::vector(found->second.get())) + { + osg::Node* node = found->second; + mFirstPersonNeckController = new NeckController(mObjectRoot.get()); + node->addUpdateCallback(mFirstPersonNeckController); + mActiveControllers.insert(std::make_pair(node, mFirstPersonNeckController)); + } + } +} + void NpcAnimation::showWeapons(bool showWeapon) { mShowWeapons = showWeapon; @@ -947,6 +1046,11 @@ void NpcAnimation::setVampire(bool vampire) } } +void NpcAnimation::setFirstPersonOffset(const osg::Vec3f &offset) +{ + mFirstPersonOffset = offset; +} + void NpcAnimation::updatePtr(const MWWorld::Ptr &updated) { Animation::updatePtr(updated); diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 0f90bb2d7..28ae43144 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -48,6 +48,8 @@ public: virtual float getValue(osg::NodeVisitor* nv); }; +class NeckController; + class NpcAnimation : public Animation, public WeaponAnimation, public MWWorld::InventoryStoreListener { public: @@ -92,7 +94,7 @@ private: int mPartslots[ESM::PRT_Count]; //Each part slot is taken by clothing, armor, or is empty int mPartPriorities[ESM::PRT_Count]; - //Ogre::Vector3 mFirstPersonOffset; + osg::Vec3f mFirstPersonOffset; boost::shared_ptr mHeadAnimationTime; boost::shared_ptr mWeaponAnimationTime; @@ -119,6 +121,11 @@ private: //void applyAlpha(float alpha, Ogre::Entity* ent, NifOgre::ObjectScenePtr scene); + osg::ref_ptr mFirstPersonNeckController; + +protected: + virtual void addControllers(); + public: /** * @param ptr @@ -186,6 +193,9 @@ public: virtual void setVampire(bool vampire); + /// Set a translation offset (in object root space) to apply to meshes when in first person mode. + void setFirstPersonOffset(const osg::Vec3f& offset); + virtual void updatePtr(const MWWorld::Ptr& updated); }; From cc9b7638913ee0a5494a27af2ff7669f3ed451aa Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 30 May 2015 17:20:49 +0200 Subject: [PATCH 1333/3725] Fix for StartScript regression (Fixes #2590) --- apps/openmw/mwworld/store.hpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index d6aeeb51e..ba8be733a 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -366,6 +366,19 @@ namespace MWWorld inserted.first->second = scpt; } + template <> + inline void Store::load(ESM::ESMReader &esm, const std::string &id) + { + ESM::StartScript s; + s.load(esm); + s.mId = Misc::StringUtils::toLower(s.mId); + std::pair inserted = mStatic.insert(std::make_pair(s.mId, s)); + if (inserted.second) + mShared.push_back(&inserted.first->second); + else + inserted.first->second = s; + } + template <> class Store : public StoreBase { From d05d7f51d9bc581581ce2d88ebec9ab3ca085e4e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 31 May 2015 14:20:13 +0200 Subject: [PATCH 1334/3725] increased version number --- CMakeLists.txt | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7c19c57eb..95035e85e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,7 +20,7 @@ message(STATUS "Configuring OpenMW...") set(OPENMW_VERSION_MAJOR 0) set(OPENMW_VERSION_MINOR 36) -set(OPENMW_VERSION_RELEASE 0) +set(OPENMW_VERSION_RELEASE 1) set(OPENMW_VERSION_COMMITHASH "") set(OPENMW_VERSION_TAGHASH "") diff --git a/README.md b/README.md index f62800e1f..833d9b282 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ OpenMW 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.36.0 +* Version: 0.36.1 * License: GPL (see docs/license/GPL3.txt for more information) * Website: http://www.openmw.org * IRC: #openmw on irc.freenode.net From e8e3407062caad86c3e0c9dc3af0ae7ad7921434 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 31 May 2015 14:21:21 +0200 Subject: [PATCH 1335/3725] updated changelog --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 466c2ef25..b2e7dc25c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +0.36.1 +------ + + Bug #2590: Start scripts not added correctly + 0.36.0 ------ From 9e405b69fa74e429c23b4039365957dbdf1bc82d Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sun, 31 May 2015 16:43:28 +0300 Subject: [PATCH 1336/3725] Create the custom completer popup to avoid the problem with the wrong height of the default popup --- apps/opencs/CMakeLists.txt | 2 +- .../model/world/idcompletionmanager.cpp | 7 +++++ apps/opencs/view/widget/completerpopup.cpp | 28 +++++++++++++++++++ apps/opencs/view/widget/completerpopup.hpp | 17 +++++++++++ 4 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 apps/opencs/view/widget/completerpopup.cpp create mode 100644 apps/opencs/view/widget/completerpopup.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index efbe77ccb..37d13223a 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -74,7 +74,7 @@ opencs_units_noqt (view/world opencs_units (view/widget scenetoolbar scenetool scenetoolmode pushbutton scenetooltoggle scenetoolrun modebutton - scenetooltoggle2 + scenetooltoggle2 completerpopup ) opencs_units (view/render diff --git a/apps/opencs/model/world/idcompletionmanager.cpp b/apps/opencs/model/world/idcompletionmanager.cpp index c9e135c83..c483a9fb5 100644 --- a/apps/opencs/model/world/idcompletionmanager.cpp +++ b/apps/opencs/model/world/idcompletionmanager.cpp @@ -4,6 +4,8 @@ #include +#include "../../view/widget/completerpopup.hpp" + #include "data.hpp" #include "idtablebase.hpp" @@ -121,6 +123,11 @@ void CSMWorld::IdCompletionManager::generateCompleters(CSMWorld::Data &data) // The completion role must be Qt::DisplayRole to get the ID values from the model completer->setCompletionRole(Qt::DisplayRole); completer->setCaseSensitivity(Qt::CaseInsensitive); + + QAbstractItemView *popup = new CSVWidget::CompleterPopup(); + completer->setPopup(popup); // The completer takes ownership of the popup + completer->setMaxVisibleItems(10); + mCompleters[current->first] = completer; } } diff --git a/apps/opencs/view/widget/completerpopup.cpp b/apps/opencs/view/widget/completerpopup.cpp new file mode 100644 index 000000000..ad50b76e6 --- /dev/null +++ b/apps/opencs/view/widget/completerpopup.cpp @@ -0,0 +1,28 @@ +#include "completerpopup.hpp" + +CSVWidget::CompleterPopup::CompleterPopup(QWidget *parent) + : QListView(parent) +{ + setEditTriggers(QAbstractItemView::NoEditTriggers); + setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + setSelectionBehavior(QAbstractItemView::SelectRows); + setSelectionMode(QAbstractItemView::SingleSelection); +} + +int CSVWidget::CompleterPopup::sizeHintForRow(int row) const +{ + if (model() == NULL) + { + return -1; + } + if (row < 0 || row >= model()->rowCount()) + { + return -1; + } + + ensurePolished(); + QModelIndex index = model()->index(row, modelColumn()); + QStyleOptionViewItem option = viewOptions(); + QAbstractItemDelegate *delegate = itemDelegate(index); + return delegate->sizeHint(option, index).height(); +} \ No newline at end of file diff --git a/apps/opencs/view/widget/completerpopup.hpp b/apps/opencs/view/widget/completerpopup.hpp new file mode 100644 index 000000000..92731ab50 --- /dev/null +++ b/apps/opencs/view/widget/completerpopup.hpp @@ -0,0 +1,17 @@ +#ifndef CSV_WIDGET_COMPLETERPOPUP_HPP +#define CSV_WIDGET_COMPLETERPOPUP_HPP + +#include + +namespace CSVWidget +{ + class CompleterPopup : public QListView + { + public: + CompleterPopup(QWidget *parent = 0); + + virtual int sizeHintForRow(int row) const; + }; +} + +#endif \ No newline at end of file From e636101725c8fe214bf18bfdab455ed81cfd3d67 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sun, 31 May 2015 18:18:49 +0300 Subject: [PATCH 1337/3725] Add missing new lines at the ends of files --- apps/opencs/model/doc/document.cpp | 2 +- apps/opencs/model/world/idcompletionmanager.cpp | 2 +- apps/opencs/model/world/idcompletionmanager.hpp | 2 +- apps/opencs/view/widget/completerpopup.cpp | 2 +- apps/opencs/view/widget/completerpopup.hpp | 2 +- apps/opencs/view/world/idcompletiondelegate.cpp | 2 +- apps/opencs/view/world/idcompletiondelegate.hpp | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 1e3d1c59b..18a4f4878 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -2493,4 +2493,4 @@ boost::shared_ptr CSMDoc::Document::getPhysics () CSMWorld::IdCompletionManager &CSMDoc::Document::getIdCompletionManager() { return mIdCompletionManager; -} \ No newline at end of file +} diff --git a/apps/opencs/model/world/idcompletionmanager.cpp b/apps/opencs/model/world/idcompletionmanager.cpp index c483a9fb5..ff5ec6b4b 100644 --- a/apps/opencs/model/world/idcompletionmanager.cpp +++ b/apps/opencs/model/world/idcompletionmanager.cpp @@ -132,4 +132,4 @@ void CSMWorld::IdCompletionManager::generateCompleters(CSMWorld::Data &data) } } } -} \ No newline at end of file +} diff --git a/apps/opencs/model/world/idcompletionmanager.hpp b/apps/opencs/model/world/idcompletionmanager.hpp index 725cfa331..fff9868ea 100644 --- a/apps/opencs/model/world/idcompletionmanager.hpp +++ b/apps/opencs/model/world/idcompletionmanager.hpp @@ -35,4 +35,4 @@ namespace CSMWorld }; } -#endif \ No newline at end of file +#endif diff --git a/apps/opencs/view/widget/completerpopup.cpp b/apps/opencs/view/widget/completerpopup.cpp index ad50b76e6..5777325c8 100644 --- a/apps/opencs/view/widget/completerpopup.cpp +++ b/apps/opencs/view/widget/completerpopup.cpp @@ -25,4 +25,4 @@ int CSVWidget::CompleterPopup::sizeHintForRow(int row) const QStyleOptionViewItem option = viewOptions(); QAbstractItemDelegate *delegate = itemDelegate(index); return delegate->sizeHint(option, index).height(); -} \ No newline at end of file +} diff --git a/apps/opencs/view/widget/completerpopup.hpp b/apps/opencs/view/widget/completerpopup.hpp index 92731ab50..6857064b8 100644 --- a/apps/opencs/view/widget/completerpopup.hpp +++ b/apps/opencs/view/widget/completerpopup.hpp @@ -14,4 +14,4 @@ namespace CSVWidget }; } -#endif \ No newline at end of file +#endif diff --git a/apps/opencs/view/world/idcompletiondelegate.cpp b/apps/opencs/view/world/idcompletiondelegate.cpp index 0f309054b..33e1282d4 100644 --- a/apps/opencs/view/world/idcompletiondelegate.cpp +++ b/apps/opencs/view/world/idcompletiondelegate.cpp @@ -38,4 +38,4 @@ CSVWorld::CommandDelegate *CSVWorld::IdCompletionDelegateFactory::makeDelegate(C QObject *parent) const { return new IdCompletionDelegate(dispatcher, document, parent); -} \ No newline at end of file +} diff --git a/apps/opencs/view/world/idcompletiondelegate.hpp b/apps/opencs/view/world/idcompletiondelegate.hpp index 11ecc1cb9..979c10c34 100644 --- a/apps/opencs/view/world/idcompletiondelegate.hpp +++ b/apps/opencs/view/world/idcompletiondelegate.hpp @@ -33,4 +33,4 @@ namespace CSVWorld }; } -#endif \ No newline at end of file +#endif From dbe61115b2086fdee2649972d171db5a93c30793 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sun, 31 May 2015 18:22:43 +0300 Subject: [PATCH 1338/3725] Fix the mistyping header guard in the idcompletiondelegate.hpp --- apps/opencs/view/world/idcompletiondelegate.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/world/idcompletiondelegate.hpp b/apps/opencs/view/world/idcompletiondelegate.hpp index 979c10c34..d2ac6874f 100644 --- a/apps/opencs/view/world/idcompletiondelegate.hpp +++ b/apps/opencs/view/world/idcompletiondelegate.hpp @@ -1,5 +1,5 @@ -#ifndef CSV_WORLD_IDCOMPLETIONMANAGER_HPP -#define CSV_WORLD_IDCOMPLETIONMANAGER_HPP +#ifndef CSV_WORLD_IDCOMPLETIONDELEGATE_HPP +#define CSV_WORLD_IDCOMPLETIONDELEGATE_HPP #include "util.hpp" From 71bafcb52bbf590f2a853ec43059ec3e787e2ea7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 31 May 2015 18:04:14 +0200 Subject: [PATCH 1339/3725] Restore head tracking --- apps/openmw/mwmechanics/actors.cpp | 30 ++++----- apps/openmw/mwmechanics/character.cpp | 79 +++++++++++++---------- apps/openmw/mwphysics/physicssystem.cpp | 3 +- apps/openmw/mwrender/animation.hpp | 5 ++ apps/openmw/mwrender/npcanimation.cpp | 83 ++++++++++++++++++------- apps/openmw/mwrender/npcanimation.hpp | 14 +++-- 6 files changed, 135 insertions(+), 79 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 3333511d3..84e97487a 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1,15 +1,12 @@ - #include "actors.hpp" #include -#include -#include +#include #include #include "../mwworld/esmstore.hpp" - #include "../mwworld/class.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwworld/manualref.hpp" @@ -20,6 +17,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwbase/soundmanager.hpp" +#include "../mwbase/mechanicsmanager.hpp" #include "../mwrender/animation.hpp" @@ -27,14 +25,9 @@ #include "creaturestats.hpp" #include "movement.hpp" #include "character.hpp" - -#include "../mwbase/environment.hpp" -#include "../mwbase/mechanicsmanager.hpp" - #include "aicombat.hpp" #include "aifollow.hpp" #include "aipursue.hpp" - #include "actor.hpp" #include "summoning.hpp" #include "combat.hpp" @@ -274,7 +267,6 @@ namespace MWMechanics void Actors::updateHeadTracking(const MWWorld::Ptr& actor, const MWWorld::Ptr& targetActor, MWWorld::Ptr& headTrackTarget, float& sqrHeadTrackDistance) { - /* static const float fMaxHeadTrackDistance = MWBase::Environment::get().getWorld()->getStore().get() .find("fMaxHeadTrackDistance")->getFloat(); static const float fInteriorHeadTrackMult = MWBase::Environment::get().getWorld()->getStore().get() @@ -286,7 +278,7 @@ namespace MWMechanics const ESM::Position& actor1Pos = actor.getRefData().getPosition(); const ESM::Position& actor2Pos = targetActor.getRefData().getPosition(); - float sqrDist = Ogre::Vector3(actor1Pos.pos).squaredDistance(Ogre::Vector3(actor2Pos.pos)); + float sqrDist = (actor1Pos.asVec3() - actor2Pos.asVec3()).length2(); if (sqrDist > maxDistance*maxDistance) return; @@ -294,12 +286,17 @@ namespace MWMechanics if (targetActor.getClass().getCreatureStats(targetActor).isDead()) return; + if (!actor.getRefData().getBaseNode()) + return; + // stop tracking when target is behind the actor - Ogre::Vector3 actorDirection (actor.getRefData().getBaseNode()->getOrientation().yAxis()); - Ogre::Vector3 targetDirection (Ogre::Vector3(actor2Pos.pos) - Ogre::Vector3(actor1Pos.pos)); - actorDirection.z = 0; - targetDirection.z = 0; - if (actorDirection.angleBetween(targetDirection) < Ogre::Degree(90) + osg::Vec3f actorDirection = actor.getRefData().getBaseNode()->getAttitude() * osg::Vec3f(0,1,0); + osg::Vec3f targetDirection (actor2Pos.asVec3() - actor1Pos.asVec3()); + actorDirection.z() = 0; + targetDirection.z() = 0; + actorDirection.normalize(); + targetDirection.normalize(); + if (std::acos(actorDirection * targetDirection) < osg::DegreesToRadians(90.f) && sqrDist <= sqrHeadTrackDistance && MWBase::Environment::get().getWorld()->getLOS(actor, targetActor) // check LOS and awareness last as it's the most expensive function && MWBase::Environment::get().getMechanicsManager()->awarenessCheck(targetActor, actor)) @@ -307,7 +304,6 @@ namespace MWMechanics sqrHeadTrackDistance = sqrDist; headTrackTarget = targetActor; } - */ } void Actors::engageCombat (const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2, bool againstPlayer) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 5765d8b04..354ca998c 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -21,6 +21,8 @@ #include +#include + #include "movement.hpp" #include "npcstats.hpp" #include "creaturestats.hpp" @@ -46,12 +48,12 @@ namespace { // Wraps a value to (-PI, PI] -void wrap(Ogre::Radian& rad) +void wrap(float& rad) { - if (rad.valueRadians()>0) - rad = Ogre::Radian(std::fmod(rad.valueRadians()+Ogre::Math::PI, 2.0f*Ogre::Math::PI)-Ogre::Math::PI); + if (rad>0) + rad = std::fmod(rad+osg::PI, 2.0f*osg::PI)-osg::PI; else - rad = Ogre::Radian(std::fmod(rad.valueRadians()-Ogre::Math::PI, 2.0f*Ogre::Math::PI)+Ogre::Math::PI); + rad = std::fmod(rad-osg::PI, 2.0f*osg::PI)+osg::PI; } std::string getBestAttack (const ESM::Weapon* weapon) @@ -2034,50 +2036,61 @@ void CharacterController::setHeadTrackTarget(const MWWorld::Ptr &target) void CharacterController::updateHeadTracking(float duration) { - /* - Ogre::Node* head = mAnimation->getNode("Bip01 Head"); + const osg::Node* head = mAnimation->getNode("Bip01 Head"); if (!head) return; - Ogre::Radian zAngle (0.f); - Ogre::Radian xAngle (0.f); + + float zAngleRadians = 0.f; + float xAngleRadians = 0.f; + if (!mHeadTrackTarget.isEmpty()) { - Ogre::Vector3 headPos = mPtr.getRefData().getBaseNode()->convertLocalToWorldPosition(head->_getDerivedPosition()); - Ogre::Vector3 targetPos (mHeadTrackTarget.getRefData().getPosition().pos); + osg::MatrixList mats = head->getWorldMatrices(); + if (mats.empty()) + return; + osg::Matrixf mat = mats[0]; + osg::Vec3f headPos = mat.getTrans(); + + osg::Vec3f targetPos (mHeadTrackTarget.getRefData().getPosition().asVec3()); if (MWRender::Animation* anim = MWBase::Environment::get().getWorld()->getAnimation(mHeadTrackTarget)) { - Ogre::Node* targetHead = anim->getNode("Head"); - if (!targetHead) - targetHead = anim->getNode("Bip01 Head"); - if (targetHead) - targetPos = mHeadTrackTarget.getRefData().getBaseNode()->convertLocalToWorldPosition( - targetHead->_getDerivedPosition()); + const osg::Node* node = anim->getNode("Head"); + if (node == NULL) + node = anim->getNode("Bip01 Head"); + if (node != NULL) + { + osg::MatrixList mats = node->getWorldMatrices(); + if (mats.size()) + targetPos = mats[0].getTrans(); + } } - Ogre::Vector3 direction = targetPos - headPos; - direction.normalise(); + osg::Vec3f direction = targetPos - headPos; + direction.normalize(); + + if (!mPtr.getRefData().getBaseNode()) + return; + const osg::Vec3f actorDirection = mPtr.getRefData().getBaseNode()->getAttitude() * osg::Vec3f(0,1,0); - const Ogre::Vector3 actorDirection = mPtr.getRefData().getBaseNode()->getOrientation().yAxis(); + zAngleRadians = std::atan2(direction.x(), direction.y()) - std::atan2(actorDirection.x(), actorDirection.y()); + xAngleRadians = -std::asin(direction.z()); - zAngle = Ogre::Math::ATan2(direction.x,direction.y) - - Ogre::Math::ATan2(actorDirection.x, actorDirection.y); - xAngle = -Ogre::Math::ASin(direction.z); - wrap(zAngle); - wrap(xAngle); - xAngle = Ogre::Degree(std::min(xAngle.valueDegrees(), 40.f)); - xAngle = Ogre::Degree(std::max(xAngle.valueDegrees(), -40.f)); - zAngle = Ogre::Degree(std::min(zAngle.valueDegrees(), 30.f)); - zAngle = Ogre::Degree(std::max(zAngle.valueDegrees(), -30.f)); + wrap(zAngleRadians); + wrap(xAngleRadians); + xAngleRadians = std::min(xAngleRadians, osg::DegreesToRadians(40.f)); + xAngleRadians = std::max(xAngleRadians, osg::DegreesToRadians(-40.f)); + zAngleRadians = std::min(zAngleRadians, osg::DegreesToRadians(30.f)); + zAngleRadians = std::max(zAngleRadians, osg::DegreesToRadians(-30.f)); } + float factor = duration*5; factor = std::min(factor, 1.f); - xAngle = (1.f-factor) * mAnimation->getHeadPitch() + factor * (-xAngle); - zAngle = (1.f-factor) * mAnimation->getHeadYaw() + factor * (-zAngle); + xAngleRadians = (1.f-factor) * mAnimation->getHeadPitch() + factor * (-xAngleRadians); + zAngleRadians = (1.f-factor) * mAnimation->getHeadYaw() + factor * (-zAngleRadians); - mAnimation->setHeadPitch(xAngle); - mAnimation->setHeadYaw(zAngle); - */ + mAnimation->setHeadPitch(xAngleRadians); + mAnimation->setHeadYaw(zAngleRadians); } } diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 8e63fecfb..d36aded24 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -59,8 +59,9 @@ namespace MWPhysics class MovementSolver { private: - static float getSlope(const osg::Vec3f &normal) + static float getSlope(osg::Vec3f normal) { + normal.normalize(); return osg::RadiansToDegrees(std::acos(normal * osg::Vec3f(0.f, 0.f, 1.f))); } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index e30f2b082..bd864c936 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -391,6 +391,11 @@ public: /// @param effect Controls the radius and intensity of the light. virtual void setLightEffect(float effect) {} + virtual void setHeadPitch(float pitchRadians) {} + virtual void setHeadYaw(float yawRadians) {} + virtual float getHeadPitch() const {return 0.f;} + virtual float getHeadYaw() const {return 0.f;} + private: Animation(const Animation&); void operator=(Animation&); diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 598e2fba9..92e61801e 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -73,34 +73,37 @@ namespace MWRender { /// @note Assumes that the node being rotated has its "original" orientation set every frame by a different controller. -/// The pitch is then applied on top of that orientation. +/// The rotation is then applied on top of that orientation. /// @note Must be set on a MatrixTransform. class RotateController : public osg::NodeCallback { public: - RotateController(osg::Node* relativeTo, osg::Vec3f axis) - : mRotate(0.f) - , mAxis(axis) + RotateController(osg::Node* relativeTo) + : mEnabled(true) , mRelativeTo(relativeTo) { } - void setRotate(float rotate) + void setEnabled(bool enabled) + { + mEnabled = enabled; + } + + void setRotate(const osg::Quat& rotate) { mRotate = rotate; } virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) { - if (mRotate == 0.f) + if (!mEnabled) return; osg::MatrixTransform* transform = static_cast(node); osg::Matrix matrix = transform->getMatrix(); osg::Quat worldOrient = getWorldOrientation(node); - osg::Quat rotate (mRotate, mAxis); - osg::Quat orient = worldOrient * rotate * worldOrient.inverse() * matrix.getRotate(); + osg::Quat orient = worldOrient * mRotate * worldOrient.inverse() * matrix.getRotate(); matrix.setRotate(orient); transform->setMatrix(matrix); @@ -113,7 +116,7 @@ public: // this could be optimized later, we just need the world orientation, not the full matrix osg::MatrixList worldMats = node->getWorldMatrices(mRelativeTo); osg::Quat worldOrient; - if (worldMats.size()) + if (!worldMats.empty()) { osg::Matrixf worldMat = worldMats[0]; worldOrient = worldMat.getRotate(); @@ -122,8 +125,8 @@ public: } protected: - float mRotate; - osg::Vec3f mAxis; + bool mEnabled; + osg::Quat mRotate; osg::ref_ptr mRelativeTo; }; @@ -134,7 +137,7 @@ class NeckController : public RotateController { public: NeckController(osg::Node* relativeTo) - : RotateController(relativeTo, osg::Vec3f(-1,0,0)) + : RotateController(relativeTo) { } @@ -149,8 +152,7 @@ public: osg::Matrix matrix = transform->getMatrix(); osg::Quat worldOrient = getWorldOrientation(node); - osg::Quat rotate (mRotate, mAxis); - osg::Quat orient = worldOrient * rotate * worldOrient.inverse() * matrix.getRotate(); + osg::Quat orient = worldOrient * mRotate * worldOrient.inverse() * matrix.getRotate(); matrix.setRotate(orient); matrix.setTrans(matrix.getTrans() + worldOrient.inverse() * mOffset); @@ -293,9 +295,9 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, osg::ref_ptr par mNpcType(Type_Normal), mVisibilityFlags(visibilityFlags), mAlpha(1.f), - mSoundsDisabled(disableSounds) - //mHeadPitch(0.f), - //mHeadYaw(0.f) + mSoundsDisabled(disableSounds), + mHeadYawRadians(0.f), + mHeadPitchRadians(0.f) { mNpc = mPtr.get()->mBase; @@ -695,10 +697,19 @@ osg::Vec3f NpcAnimation::runAnimation(float timepassed) if (mFirstPersonNeckController) { - mFirstPersonNeckController->setRotate(mPtr.getRefData().getPosition().rot[0]); + mFirstPersonNeckController->setRotate(osg::Quat(mPtr.getRefData().getPosition().rot[0], osg::Vec3f(-1,0,0))); mFirstPersonNeckController->setOffset(mFirstPersonOffset); } + if (mHeadController) + { + const float epsilon = 0.001f; + bool enable = (std::abs(mHeadPitchRadians) > epsilon || std::abs(mHeadYawRadians) > epsilon); + mHeadController->setEnabled(enable); + if (enable) + mHeadController->setRotate(osg::Quat(mHeadPitchRadians, osg::Vec3f(1,0,0)) * osg::Quat(mHeadYawRadians, osg::Vec3f(0,0,1))); + } + /* if (mSkelBase) { @@ -707,10 +718,6 @@ osg::Vec3f NpcAnimation::runAnimation(float timepassed) { // In third person mode we may still need pitch for ranged weapon targeting pitchSkeleton(mPtr.getRefData().getPosition().rot[0], baseinst); - - Ogre::Node* node = baseinst->getBone("Bip01 Head"); - if (node) - node->rotate(Ogre::Quaternion(mHeadYaw, Ogre::Vector3::UNIT_Z) * Ogre::Quaternion(mHeadPitch, Ogre::Vector3::UNIT_X), Ogre::Node::TS_WORLD); } } */ @@ -718,6 +725,26 @@ osg::Vec3f NpcAnimation::runAnimation(float timepassed) return ret; } +void NpcAnimation::setHeadPitch(float pitchRadians) +{ + mHeadPitchRadians = pitchRadians; +} + +void NpcAnimation::setHeadYaw(float yawRadians) +{ + mHeadYawRadians = yawRadians; +} + +float NpcAnimation::getHeadPitch() const +{ + return mHeadPitchRadians; +} + +float NpcAnimation::getHeadYaw() const +{ + return mHeadYawRadians; +} + void NpcAnimation::removeIndividualPart(ESM::PartReferenceType type) { mPartPriorities[type] = 0; @@ -878,6 +905,7 @@ void NpcAnimation::addPartGroup(int group, int priority, const std::vector(found->second.get())) + { + osg::Node* node = found->second; + mHeadController = new RotateController(mObjectRoot.get()); + node->addUpdateCallback(mHeadController); + mActiveControllers.insert(std::make_pair(node, mHeadController)); + } + } } void NpcAnimation::showWeapons(bool showWeapon) diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 28ae43144..db0b4ea0c 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -49,6 +49,7 @@ public: }; class NeckController; +class RotateController; class NpcAnimation : public Animation, public WeaponAnimation, public MWWorld::InventoryStoreListener { @@ -102,8 +103,8 @@ private: float mAlpha; bool mSoundsDisabled; - //Ogre::Radian mHeadYaw; - //Ogre::Radian mHeadPitch; + float mHeadYawRadians; + float mHeadPitchRadians; void updateNpcBase(); @@ -122,6 +123,7 @@ private: //void applyAlpha(float alpha, Ogre::Entity* ent, NifOgre::ObjectScenePtr scene); osg::ref_ptr mFirstPersonNeckController; + osg::ref_ptr mHeadController; protected: virtual void addControllers(); @@ -153,10 +155,10 @@ public: /// to indicate the facing orientation of the character. virtual void setPitchFactor(float factor) { mPitchFactor = factor; } - //virtual void setHeadPitch(Ogre::Radian pitch); - //virtual void setHeadYaw(Ogre::Radian yaw); - //virtual Ogre::Radian getHeadPitch() const; - //virtual Ogre::Radian getHeadYaw() const; + virtual void setHeadPitch(float pitchRadians); + virtual void setHeadYaw(float yawRadians); + virtual float getHeadPitch() const; + virtual float getHeadYaw() const; virtual void showWeapons(bool showWeapon); virtual void showCarriedLeft(bool show); From ed4863ad7db53c6835cca1e3ecd5778933024334 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 31 May 2015 18:53:16 +0200 Subject: [PATCH 1340/3725] Restore ranged weapon aiming --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwrender/creatureanimation.cpp | 10 +-- apps/openmw/mwrender/creatureanimation.hpp | 4 +- apps/openmw/mwrender/npcanimation.cpp | 75 ++-------------------- apps/openmw/mwrender/rotatecontroller.cpp | 57 ++++++++++++++++ apps/openmw/mwrender/rotatecontroller.hpp | 36 +++++++++++ apps/openmw/mwrender/weaponanimation.cpp | 65 +++++++++++++------ apps/openmw/mwrender/weaponanimation.hpp | 15 ++++- 8 files changed, 170 insertions(+), 94 deletions(-) create mode 100644 apps/openmw/mwrender/rotatecontroller.cpp create mode 100644 apps/openmw/mwrender/rotatecontroller.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 2193f4ca0..3cf43749d 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -20,7 +20,7 @@ set(GAME_HEADER source_group(game FILES ${GAME} ${GAME_HEADER}) add_openmw_dir (mwrender - actors objects renderingmanager animation sky npcanimation vismask + actors objects renderingmanager animation rotatecontroller sky npcanimation vismask creatureanimation effectmanager util renderinginterface pathgrid rendermode weaponanimation bulletdebugdraw globalmap characterpreview camera localmap # occlusionquery water shadows diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index b98b26179..0dd647c9c 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -171,14 +171,16 @@ Resource::ResourceSystem *CreatureWeaponAnimation::getResourceSystem() return mResourceSystem; } +void CreatureWeaponAnimation::addControllers() +{ + WeaponAnimation::addControllers(mNodeMap, mActiveControllers, mObjectRoot.get()); +} + osg::Vec3f CreatureWeaponAnimation::runAnimation(float duration) { osg::Vec3f ret = Animation::runAnimation(duration); - /* - if (mSkelBase) - pitchSkeleton(mPtr.getRefData().getPosition().rot[0], mSkelBase->getSkeleton()); - */ + WeaponAnimation::configureControllers(mPtr.getRefData().getPosition().rot[0]); return ret; } diff --git a/apps/openmw/mwrender/creatureanimation.hpp b/apps/openmw/mwrender/creatureanimation.hpp index 61d077df3..8a4ebb930 100644 --- a/apps/openmw/mwrender/creatureanimation.hpp +++ b/apps/openmw/mwrender/creatureanimation.hpp @@ -46,11 +46,13 @@ namespace MWRender virtual void showWeapon(bool show) { showWeapons(show); } virtual void setWeaponGroup(const std::string& group) { mWeaponAnimationTime->setGroup(group); } + virtual void addControllers(); + virtual osg::Vec3f runAnimation(float duration); /// A relative factor (0-1) that decides if and how much the skeleton should be pitched /// to indicate the facing orientation of the character. - //virtual void setPitchFactor(float factor) { mPitchFactor = factor; } + virtual void setPitchFactor(float factor) { mPitchFactor = factor; } private: diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 92e61801e..7283a621a 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -26,6 +26,7 @@ #include "../mwbase/soundmanager.hpp" #include "camera.hpp" +#include "rotatecontroller.hpp" namespace { @@ -72,64 +73,6 @@ std::string getVampireHead(const std::string& race, bool female) namespace MWRender { -/// @note Assumes that the node being rotated has its "original" orientation set every frame by a different controller. -/// The rotation is then applied on top of that orientation. -/// @note Must be set on a MatrixTransform. -class RotateController : public osg::NodeCallback -{ -public: - RotateController(osg::Node* relativeTo) - : mEnabled(true) - , mRelativeTo(relativeTo) - { - - } - - void setEnabled(bool enabled) - { - mEnabled = enabled; - } - - void setRotate(const osg::Quat& rotate) - { - mRotate = rotate; - } - - virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) - { - if (!mEnabled) - return; - osg::MatrixTransform* transform = static_cast(node); - osg::Matrix matrix = transform->getMatrix(); - osg::Quat worldOrient = getWorldOrientation(node); - - osg::Quat orient = worldOrient * mRotate * worldOrient.inverse() * matrix.getRotate(); - matrix.setRotate(orient); - - transform->setMatrix(matrix); - - traverse(node,nv); - } - - osg::Quat getWorldOrientation(osg::Node* node) - { - // this could be optimized later, we just need the world orientation, not the full matrix - osg::MatrixList worldMats = node->getWorldMatrices(mRelativeTo); - osg::Quat worldOrient; - if (!worldMats.empty()) - { - osg::Matrixf worldMat = worldMats[0]; - worldOrient = worldMat.getRotate(); - } - return worldOrient; - } - -protected: - bool mEnabled; - osg::Quat mRotate; - osg::ref_ptr mRelativeTo; -}; - /// Subclass RotateController to add a Z-offset for sneaking in first person mode. /// @note We use inheritance instead of adding another controller, so that we do not have to compute the worldOrient twice. /// @note Must be set on a MatrixTransform. @@ -710,17 +653,7 @@ osg::Vec3f NpcAnimation::runAnimation(float timepassed) mHeadController->setRotate(osg::Quat(mHeadPitchRadians, osg::Vec3f(1,0,0)) * osg::Quat(mHeadYawRadians, osg::Vec3f(0,0,1))); } - /* - if (mSkelBase) - { - Ogre::SkeletonInstance *baseinst = mSkelBase->getSkeleton(); - if(mViewMode != VM_FirstPerson) - { - // In third person mode we may still need pitch for ranged weapon targeting - pitchSkeleton(mPtr.getRefData().getPosition().rot[0], baseinst); - } - } - */ + WeaponAnimation::configureControllers(mPtr.getRefData().getPosition().rot[0]); return ret; } @@ -906,6 +839,8 @@ void NpcAnimation::addControllers() { mFirstPersonNeckController = NULL; mHeadController = NULL; + WeaponAnimation::deleteControllers(); + if (mViewMode == VM_FirstPerson) { NodeMap::iterator found = mNodeMap.find("bip01 neck"); @@ -927,6 +862,8 @@ void NpcAnimation::addControllers() node->addUpdateCallback(mHeadController); mActiveControllers.insert(std::make_pair(node, mHeadController)); } + + WeaponAnimation::addControllers(mNodeMap, mActiveControllers, mObjectRoot.get()); } } diff --git a/apps/openmw/mwrender/rotatecontroller.cpp b/apps/openmw/mwrender/rotatecontroller.cpp new file mode 100644 index 000000000..11f5b943d --- /dev/null +++ b/apps/openmw/mwrender/rotatecontroller.cpp @@ -0,0 +1,57 @@ +#include "rotatecontroller.hpp" + +#include + +namespace MWRender +{ + +RotateController::RotateController(osg::Node *relativeTo) + : mEnabled(true) + , mRelativeTo(relativeTo) +{ + +} + +void RotateController::setEnabled(bool enabled) +{ + mEnabled = enabled; +} + +void RotateController::setRotate(const osg::Quat &rotate) +{ + mRotate = rotate; +} + +void RotateController::operator()(osg::Node *node, osg::NodeVisitor *nv) +{ + if (!mEnabled) + { + traverse(node, nv); + return; + } + osg::MatrixTransform* transform = static_cast(node); + osg::Matrix matrix = transform->getMatrix(); + osg::Quat worldOrient = getWorldOrientation(node); + + osg::Quat orient = worldOrient * mRotate * worldOrient.inverse() * matrix.getRotate(); + matrix.setRotate(orient); + + transform->setMatrix(matrix); + + traverse(node,nv); +} + +osg::Quat RotateController::getWorldOrientation(osg::Node *node) +{ + // this could be optimized later, we just need the world orientation, not the full matrix + osg::MatrixList worldMats = node->getWorldMatrices(mRelativeTo); + osg::Quat worldOrient; + if (!worldMats.empty()) + { + osg::Matrixf worldMat = worldMats[0]; + worldOrient = worldMat.getRotate(); + } + return worldOrient; +} + +} diff --git a/apps/openmw/mwrender/rotatecontroller.hpp b/apps/openmw/mwrender/rotatecontroller.hpp new file mode 100644 index 000000000..8c3758cb0 --- /dev/null +++ b/apps/openmw/mwrender/rotatecontroller.hpp @@ -0,0 +1,36 @@ +#ifndef OPENMW_MWRENDER_ROTATECONTROLLER_H +#define OPENMW_MWRENDER_ROTATECONTROLLER_H + +#include +#include + +namespace MWRender +{ + +/// Applies a rotation in \a relativeTo's space. +/// @note Assumes that the node being rotated has its "original" orientation set every frame by a different controller. +/// The rotation is then applied on top of that orientation. +/// @note Must be set on a MatrixTransform. +class RotateController : public osg::NodeCallback +{ +public: + RotateController(osg::Node* relativeTo); + + void setEnabled(bool enabled); + + void setRotate(const osg::Quat& rotate); + + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv); + +protected: + osg::Quat getWorldOrientation(osg::Node* node); + + bool mEnabled; + osg::Quat mRotate; + osg::ref_ptr mRelativeTo; +}; + + +} + +#endif diff --git a/apps/openmw/mwrender/weaponanimation.cpp b/apps/openmw/mwrender/weaponanimation.cpp index 23a74fb95..301779c1e 100644 --- a/apps/openmw/mwrender/weaponanimation.cpp +++ b/apps/openmw/mwrender/weaponanimation.cpp @@ -1,5 +1,7 @@ #include "weaponanimation.hpp" +#include + #include #include @@ -15,6 +17,7 @@ #include "../mwmechanics/combat.hpp" #include "animation.hpp" +#include "rotatecontroller.hpp" namespace MWRender { @@ -46,6 +49,11 @@ WeaponAnimation::WeaponAnimation() { } +WeaponAnimation::~WeaponAnimation() +{ + +} + void WeaponAnimation::attachArrow(MWWorld::Ptr actor) { MWWorld::InventoryStore& inv = actor.getClass().getInventoryStore(actor); @@ -149,28 +157,49 @@ void WeaponAnimation::releaseArrow(MWWorld::Ptr actor) } } -/* -void WeaponAnimation::pitchSkeleton(float xrot, Ogre::SkeletonInstance* skel) +void WeaponAnimation::addControllers(const std::map >& nodes, + std::multimap, osg::ref_ptr > &map, osg::Node* objectRoot) { - if (mPitchFactor == 0) - return; + for (int i=0; i<2; ++i) + { + mSpineControllers[i] = NULL; - float pitch = xrot * mPitchFactor; - Ogre::Node *node; + std::map >::const_iterator found = nodes.find(i == 0 ? "bip01 spine1" : "bip01 spine2"); + if (found != nodes.end()) + { + osg::Node* node = found->second; + mSpineControllers[i] = new RotateController(objectRoot); + node->addUpdateCallback(mSpineControllers[i]); + map.insert(std::make_pair(node, mSpineControllers[i])); + } + } +} - // In spherearcher.nif, we have spine, not Spine. Not sure if all bone names should be case insensitive? - if (skel->hasBone("Bip01 spine2")) - node = skel->getBone("Bip01 spine2"); - else - node = skel->getBone("Bip01 Spine2"); - node->pitch(Ogre::Radian(-pitch/2), Ogre::Node::TS_WORLD); +void WeaponAnimation::deleteControllers() +{ + for (int i=0; i<2; ++i) + mSpineControllers[i] = NULL; +} - if (skel->hasBone("Bip01 spine1")) // in spherearcher.nif - node = skel->getBone("Bip01 spine1"); - else - node = skel->getBone("Bip01 Spine1"); - node->pitch(Ogre::Radian(-pitch/2), Ogre::Node::TS_WORLD); +void WeaponAnimation::configureControllers(float characterPitchRadians) +{ + if (!mSpineControllers[0]) + return; + + if (mPitchFactor == 0.f || characterPitchRadians == 0.f) + { + for (int i=0; i<2; ++i) + mSpineControllers[i]->setEnabled(false); + return; + } + + float pitch = characterPitchRadians * mPitchFactor; + osg::Quat rotate (pitch/2, osg::Vec3f(-1,0,0)); + for (int i=0; i<2; ++i) + { + mSpineControllers[i]->setRotate(rotate); + mSpineControllers[i]->setEnabled(true); + } } -*/ } diff --git a/apps/openmw/mwrender/weaponanimation.hpp b/apps/openmw/mwrender/weaponanimation.hpp index f46638ac8..9336afd4c 100644 --- a/apps/openmw/mwrender/weaponanimation.hpp +++ b/apps/openmw/mwrender/weaponanimation.hpp @@ -9,6 +9,8 @@ namespace MWRender { + class RotateController; + class WeaponAnimationTime : public SceneUtil::ControllerSource { private: @@ -28,7 +30,7 @@ namespace MWRender { public: WeaponAnimation(); - virtual ~WeaponAnimation() {} + virtual ~WeaponAnimation(); /// @note If no weapon (or an invalid weapon) is equipped, this function is a no-op. void attachArrow(MWWorld::Ptr actor); @@ -36,9 +38,20 @@ namespace MWRender /// @note If no weapon (or an invalid weapon) is equipped, this function is a no-op. void releaseArrow(MWWorld::Ptr actor); + /// Add WeaponAnimation-related controllers to \a nodes and store the added controllers in \a map. + void addControllers(const std::map >& nodes, + std::multimap, osg::ref_ptr >& map, osg::Node* objectRoot); + + void deleteControllers(); + + /// Configure controllers, should be called every animation frame. + void configureControllers(float characterPitchRadians); + protected: PartHolderPtr mAmmunition; + osg::ref_ptr mSpineControllers[2]; + virtual osg::Group* getArrowBone() = 0; virtual osg::Node* getWeaponNode() = 0; virtual Resource::ResourceSystem* getResourceSystem() = 0; From 5b846ebc71ef34905809f3c78ad4591e7921da74 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 31 May 2015 23:09:37 +0200 Subject: [PATCH 1341/3725] Camera precision fix --- apps/openmw/mwrender/camera.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/camera.cpp b/apps/openmw/mwrender/camera.cpp index bb4724555..69998ed26 100644 --- a/apps/openmw/mwrender/camera.cpp +++ b/apps/openmw/mwrender/camera.cpp @@ -92,17 +92,17 @@ namespace MWRender return; const osg::Matrix& worldMat = mats[0]; - osg::Vec3 position = worldMat.getTrans(); + osg::Vec3d position = worldMat.getTrans(); if (!isFirstPerson()) position.z() += mHeight; - osg::Quat orient = osg::Quat(getPitch(), osg::Vec3(1,0,0)) * osg::Quat(getYaw(), osg::Vec3(0,0,1)); + osg::Quat orient = osg::Quat(getPitch(), osg::Vec3d(1,0,0)) * osg::Quat(getYaw(), osg::Vec3d(0,0,1)); - osg::Vec3 offset = orient * osg::Vec3(0, -mCameraDistance, 0); + osg::Vec3d offset = orient * osg::Vec3d(0, -mCameraDistance, 0); position += offset; - osg::Vec3 forward = orient * osg::Vec3(0,1,0); - osg::Vec3 up = orient * osg::Vec3(0,0,1); + osg::Vec3d forward = orient * osg::Vec3d(0,1,0); + osg::Vec3d up = orient * osg::Vec3d(0,0,1); cam->setViewMatrixAsLookAt(position, position + forward, up); } From 5dc6cdeb99907385c7ca9cf513aa46f251595e8b Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Mon, 1 Jun 2015 01:14:11 +0300 Subject: [PATCH 1342/3725] Scroll to the top of the topic list when dialog is started --- apps/openmw/mwgui/dialogue.cpp | 2 ++ components/widgets/list.cpp | 4 ++++ components/widgets/list.hpp | 2 ++ 3 files changed, 8 insertions(+) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 692cea952..48b9be17d 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -364,6 +364,7 @@ namespace MWGui bool sameActor = (mPtr == actor); mPtr = actor; mTopicsList->setEnabled(true); + mTopicsList->scrollToFirstItem(); setTitle(npcName); clearChoices(); @@ -455,6 +456,7 @@ namespace MWGui mKeywordSearch.seed(Misc::StringUtils::lowerCase(*it), intptr_t(t)); } mTopicsList->adjustSize(); + mTopicsList->scrollToFirstItem(); updateHistory(); } diff --git a/components/widgets/list.cpp b/components/widgets/list.cpp index 5a79de3d1..e1d80f022 100644 --- a/components/widgets/list.cpp +++ b/components/widgets/list.cpp @@ -157,4 +157,8 @@ namespace Gui return mScrollView->findWidget (getName() + "_item_" + name)->castType(); } + void MWList::scrollToFirstItem() + { + mScrollView->setViewOffset(MyGUI::IntPoint(0, 0)); + } } diff --git a/components/widgets/list.hpp b/components/widgets/list.hpp index 72c8a733c..1c24af6a4 100644 --- a/components/widgets/list.hpp +++ b/components/widgets/list.hpp @@ -46,6 +46,8 @@ namespace Gui MyGUI::Button* getItemWidget(const std::string& name); ///< get widget for an item name, useful to set up tooltip + void scrollToFirstItem(); + virtual void setPropertyOverride(const std::string& _key, const std::string& _value); protected: From 84fd682e4e1d0ec923bd1276fa192ac7a5952dc5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 1 Jun 2015 00:40:05 +0200 Subject: [PATCH 1343/3725] Fix for unnecessary exceptions when opening sounds This would throw often during normal play, even though the throws are caught and ignored, can be annoying when the debugger is set to 'catch throw'. --- apps/openmw/mwsound/openal_output.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 6862bb889..a984fffa9 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -5,6 +5,8 @@ #include +#include + #include #include "openal_output.hpp" @@ -782,17 +784,15 @@ const CachedSound& OpenAL_Output::getBuffer(const std::string &fname) int srate; DecoderPtr decoder = mManager.getDecoder(); - try - { - decoder->open(fname); - } - catch(std::exception&) + // Workaround: Bethesda at some point converted some of the files to mp3, but the references were kept as .wav. + std::string file = fname; + if (!decoder->mResourceMgr->exists(file)) { - std::string::size_type pos = fname.rfind('.'); - if(pos == std::string::npos) - throw; - decoder->open(fname.substr(0, pos)+".mp3"); + std::string::size_type pos = file.rfind('.'); + if(pos != std::string::npos) + file = file.substr(0, pos)+".mp3"; } + decoder->open(file); decoder->getInfo(&srate, &chans, &type); format = getALFormat(chans, type); From e30685357055f0fddfae10fc242477882cc847f2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 1 Jun 2015 00:50:48 +0200 Subject: [PATCH 1344/3725] Fix chargen crash --- apps/openmw/mwworld/worldimp.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 768177b16..926e453b8 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1542,8 +1542,7 @@ namespace MWWorld } const ESM::NPC *ret = mStore.insert(record); if (update) { - mRendering->renderPlayer(getPlayerPtr()); - scaleObject(getPlayerPtr(), 1.f); // apply race height + renderPlayer(); } return ret; } @@ -2118,13 +2117,12 @@ namespace MWWorld void World::renderPlayer() { + MWBase::Environment::get().getMechanicsManager()->remove(getPlayerPtr()); + mRendering->renderPlayer(getPlayerPtr()); scaleObject(getPlayerPtr(), 1.f); // apply race height - // At this point the Animation object is live, and the CharacterController associated with it must be created. - // It has to be done at this point: resetCamera below does animation->setViewMode -> CharacterController::forceStateUpdate - // so we should make sure not to use a "stale" controller for that. MWBase::Environment::get().getMechanicsManager()->add(getPlayerPtr()); std::string model = getPlayerPtr().getClass().getModel(getPlayerPtr()); From 8e0a9882890f264803337873bc8f40d9ffe77cd0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 1 Jun 2015 01:32:02 +0200 Subject: [PATCH 1345/3725] Icon fix --- apps/openmw/mwgui/birth.cpp | 1 - apps/openmw/mwgui/formatting.cpp | 1 - apps/openmw/mwgui/hud.cpp | 1 - apps/openmw/mwgui/itemwidget.cpp | 2 -- apps/openmw/mwgui/quickkeysmenu.cpp | 1 - apps/openmw/mwgui/spellcreationdialog.cpp | 1 - apps/openmw/mwgui/spellicons.cpp | 1 - apps/openmw/mwgui/tooltips.cpp | 3 +-- apps/openmw/mwgui/widgets.cpp | 2 -- 9 files changed, 1 insertion(+), 12 deletions(-) diff --git a/apps/openmw/mwgui/birth.cpp b/apps/openmw/mwgui/birth.cpp index dd20999e0..1122a4069 100644 --- a/apps/openmw/mwgui/birth.cpp +++ b/apps/openmw/mwgui/birth.cpp @@ -5,7 +5,6 @@ #include #include -#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" diff --git a/apps/openmw/mwgui/formatting.cpp b/apps/openmw/mwgui/formatting.cpp index 461d8e32e..6adef5eeb 100644 --- a/apps/openmw/mwgui/formatting.cpp +++ b/apps/openmw/mwgui/formatting.cpp @@ -14,7 +14,6 @@ #include #include -#include #include #include "../mwscript/interpretercontext.hpp" diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 43df37b6d..0fab66a25 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -9,7 +9,6 @@ #include #include -#include #include #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwgui/itemwidget.cpp b/apps/openmw/mwgui/itemwidget.cpp index 645a72277..75436e797 100644 --- a/apps/openmw/mwgui/itemwidget.cpp +++ b/apps/openmw/mwgui/itemwidget.cpp @@ -4,8 +4,6 @@ #include #include -#include - // correctIconPath #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index cd6e2405c..b673e5bd0 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -6,7 +6,6 @@ #include #include -#include #include "../mwworld/inventorystore.hpp" #include "../mwworld/class.hpp" diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index 86c502580..08b205ec7 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -3,7 +3,6 @@ #include #include -#include #include #include diff --git a/apps/openmw/mwgui/spellicons.cpp b/apps/openmw/mwgui/spellicons.cpp index c26316626..db0453623 100644 --- a/apps/openmw/mwgui/spellicons.cpp +++ b/apps/openmw/mwgui/spellicons.cpp @@ -6,7 +6,6 @@ #include #include -#include #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 5dd201068..526cbaabe 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -7,7 +7,6 @@ #include #include -#include #include #include "../mwbase/world.hpp" @@ -782,7 +781,7 @@ namespace MWGui std::string icon = effect->mIcon; int slashPos = icon.rfind('\\'); icon.insert(slashPos+1, "b_"); - //icon = Misc::ResourceHelpers::correctIconPath(icon); + icon = MWBase::Environment::get().getWindowManager()->correctIconPath(icon); widget->setUserString("ToolTipType", "Layout"); widget->setUserString("ToolTipLayout", "MagicEffectToolTip"); diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index 996cc528d..1fa5d9cbf 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -7,8 +7,6 @@ #include #include -#include - #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" From ccd95419e579b0e707a67274b3efdfa93f95e661 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 1 Jun 2015 01:57:15 +0200 Subject: [PATCH 1346/3725] Restore various raycasting --- apps/openmw/mwmechanics/character.cpp | 8 +- apps/openmw/mwphysics/physicssystem.cpp | 73 ++++++++--- apps/openmw/mwphysics/physicssystem.hpp | 19 ++- apps/openmw/mwrender/animation.cpp | 2 - apps/openmw/mwrender/effectmanager.cpp | 2 - apps/openmw/mwrender/renderingmanager.cpp | 15 +++ apps/openmw/mwrender/renderingmanager.hpp | 3 + apps/openmw/mwworld/weather.cpp | 1 + apps/openmw/mwworld/worldimp.cpp | 147 ++++++++++------------ 9 files changed, 158 insertions(+), 112 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 354ca998c..3843df132 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -838,14 +838,12 @@ void CharacterController::updatePtr(const MWWorld::Ptr &ptr) void CharacterController::updateIdleStormState() { bool inStormDirection = false; - /* if (MWBase::Environment::get().getWorld()->isInStorm()) { - Ogre::Vector3 stormDirection = MWBase::Environment::get().getWorld()->getStormDirection(); - Ogre::Vector3 characterDirection = mPtr.getRefData().getBaseNode()->getOrientation().yAxis(); - inStormDirection = stormDirection.angleBetween(characterDirection) > Ogre::Degree(120); + osg::Vec3f stormDirection = MWBase::Environment::get().getWorld()->getStormDirection(); + osg::Vec3f characterDirection = mPtr.getRefData().getBaseNode()->getAttitude() * osg::Vec3f(0,1,0); + inStormDirection = std::acos(stormDirection * characterDirection) > osg::DegreesToRadians(120.f); } - */ if (inStormDirection && mUpperBodyState == UpperCharState_Nothing && mAnimation->hasAnimation("idlestorm")) { float complete = 0; diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index d36aded24..c942fecb1 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -728,35 +728,74 @@ namespace MWPhysics return std::make_pair(MWWorld::Ptr(), osg::Vec3f()); } - - bool PhysicsSystem::castRay(const Ogre::Vector3& from, const Ogre::Vector3& to, bool ignoreHeightMap) + class ClosestNotMeRayResultCallback : public btCollisionWorld::ClosestRayResultCallback { - return false; - /* - btVector3 _from, _to; - _from = btVector3(from.x, from.y, from.z); - _to = btVector3(to.x, to.y, to.z); - - std::pair result = mEngine->rayTest(_from, _to,ignoreHeightMap); - return !(result.first == ""); - */ - } + public: + ClosestNotMeRayResultCallback(const btCollisionObject* me, const btVector3& from, const btVector3& to) + : btCollisionWorld::ClosestRayResultCallback(from, to) + , mMe(me) + { + } - std::pair PhysicsSystem::castRay(const osg::Vec3f &from, const osg::Vec3f &to) + virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult,bool normalInWorldSpace) + { + if (rayResult.m_collisionObject == mMe) + return 1.f; + return btCollisionWorld::ClosestRayResultCallback::addSingleResult(rayResult, normalInWorldSpace); + } + private: + const btCollisionObject* mMe; + }; + + PhysicsSystem::RayResult PhysicsSystem::castRay(const osg::Vec3f &from, const osg::Vec3f &to, MWWorld::Ptr ignore, int mask) { btVector3 btFrom = toBullet(from); btVector3 btTo = toBullet(to); - btCollisionWorld::ClosestRayResultCallback resultCallback(btFrom, btTo); + const btCollisionObject* me = NULL; + if (!ignore.isEmpty()) + { + Actor* actor = getActor(ignore); + if (actor) + me = actor->getCollisionObject(); + } + + ClosestNotMeRayResultCallback resultCallback(me, btFrom, btTo); resultCallback.m_collisionFilterGroup = 0xff; - resultCallback.m_collisionFilterMask = CollisionType_World | CollisionType_HeightMap; + resultCallback.m_collisionFilterMask = mask; mCollisionWorld->rayTest(btFrom, btTo, resultCallback); + + RayResult result; + result.mHit = resultCallback.hasHit(); if (resultCallback.hasHit()) { - return std::make_pair(true, toOsg(resultCallback.m_hitPointWorld)); + result.mHitPos = toOsg(resultCallback.m_hitPointWorld); + result.mHitNormal = toOsg(resultCallback.m_hitNormalWorld); + if (PtrHolder* ptrHolder = static_cast(resultCallback.m_collisionObject->getUserPointer())) + result.mHitObject = ptrHolder->getPtr(); } - return std::make_pair(false, osg::Vec3f()); + return result; + } + + bool PhysicsSystem::getLineOfSight(const MWWorld::Ptr &actor1, const MWWorld::Ptr &actor2) + { + Actor* physactor1 = getActor(actor1); + Actor* physactor2 = getActor(actor2); + + if (!physactor1 || !physactor2) + return false; + + osg::Vec3f halfExt1 = physactor1->getHalfExtents(); + osg::Vec3f pos1 (actor1.getRefData().getPosition().asVec3()); + pos1.z() += halfExt1.z()*2*0.9f; // eye level + osg::Vec3f halfExt2 = physactor2->getHalfExtents(); + osg::Vec3f pos2 (actor2.getRefData().getPosition().asVec3()); + pos2.z() += halfExt2.z()*2*0.9f; + + RayResult result = castRay(pos1, pos2, MWWorld::Ptr(), CollisionType_World|CollisionType_HeightMap); + + return !result.mHit; } class ContactTestResultCallback : public btCollisionWorld::ContactResultCallback diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index 2240a5119..7920347ad 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -11,6 +11,8 @@ #include +#include "collisiontype.hpp" + namespace osg { class Group; @@ -87,11 +89,20 @@ namespace MWPhysics const osg::Quat &orientation, float queryDistance); - // cast ray, return true if it hit something. - bool castRay(const Ogre::Vector3& from, const Ogre::Vector3& to,bool ignoreHeightMap = false); + struct RayResult + { + bool mHit; + osg::Vec3f mHitPos; + osg::Vec3f mHitNormal; + MWWorld::Ptr mHitObject; + }; + + /// @param me Optional, a Ptr to ignore in the list of results + RayResult castRay(const osg::Vec3f &from, const osg::Vec3f &to, MWWorld::Ptr ignore = MWWorld::Ptr(), int mask = + CollisionType_World|CollisionType_HeightMap|CollisionType_Actor); - /// @return - std::pair castRay(const osg::Vec3f &from, const osg::Vec3f &to); + /// Return true if actor1 can see actor2. + bool getLineOfSight(const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2); /// Queues velocity movement for a Ptr. If a Ptr is already queued, its velocity will /// be overwritten. Valid until the next call to applyQueuedMovement. diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index b23981f81..2279375c2 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -20,8 +20,6 @@ #include -#include - #include #include #include diff --git a/apps/openmw/mwrender/effectmanager.cpp b/apps/openmw/mwrender/effectmanager.cpp index 642909cda..42a63fc68 100644 --- a/apps/openmw/mwrender/effectmanager.cpp +++ b/apps/openmw/mwrender/effectmanager.cpp @@ -2,8 +2,6 @@ #include -#include - #include #include diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index e1f1e13d1..a067422d4 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -298,6 +298,21 @@ namespace MWRender mObjects->removeObject(ptr); } + void RenderingManager::getCameraToViewportRay(float nX, float nY, osg::Vec3f &origin, osg::Vec3f &dest) + { + osg::Matrix viewProj = mViewer->getCamera()->getViewMatrix() * mViewer->getCamera()->getProjectionMatrix(); + osg::Matrix invViewProj = viewProj.inverse(viewProj); + + nX = nX * 2 - 1; + nY = nY * -2 + 1; + + osg::Vec3f start (nX, nY, -1.f); + osg::Vec3f end (nX, nY, 1.f); + + origin = invViewProj.preMult(start); + dest = invViewProj.preMult(end); + } + osg::Vec4f RenderingManager::getScreenBounds(const MWWorld::Ptr& ptr) { if (!ptr.getRefData().getBaseNode()) diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 011ceee09..e2524b360 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -80,6 +80,9 @@ namespace MWRender /// Get the bounding box of the given object in screen coordinates as (minX, minY, maxX, maxY), with (0,0) being the top left corner. osg::Vec4f getScreenBounds(const MWWorld::Ptr& ptr); + /// Get a camera to viewport ray for normalized screen coordinates nX and nY, with the top left corner being at (0,0) + void getCameraToViewportRay(float nX, float nY, osg::Vec3f& origin, osg::Vec3f& dest); + void setSkyEnabled(bool enabled); bool toggleRenderMode(RenderMode mode); diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index c9e69b0b4..81497aa6c 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -419,6 +419,7 @@ void WeatherManager::update(float duration, bool paused) mStormDirection = (playerPos - redMountainPos); mStormDirection.z() = 0; + mStormDirection.normalize(); mRendering->getSkyManager()->setStormDirection(mStormDirection); } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 926e453b8..f4f960d97 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -7,7 +7,6 @@ #else #include #endif -#include #include #include @@ -21,8 +20,6 @@ #include #include -#include - #include "../mwbase/environment.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" @@ -1411,9 +1408,10 @@ namespace MWWorld bool World::castRay (float x1, float y1, float z1, float x2, float y2, float z2) { - Ogre::Vector3 a(x1,y1,z1); - Ogre::Vector3 b(x2,y2,z2); - return 0;//mPhysics->castRay(a,b,false,true); + osg::Vec3f a(x1,y1,z1); + osg::Vec3f b(x2,y2,z2); + MWPhysics::PhysicsSystem::RayResult result = mPhysics->castRay(a, b, MWWorld::Ptr(), MWPhysics::CollisionType_World); + return result.mHit; } void World::processDoors(float duration) @@ -1793,17 +1791,26 @@ namespace MWWorld MWWorld::Ptr World::placeObject (const MWWorld::Ptr& object, float cursorX, float cursorY, int amount) { - std::pair result;// = mPhysics->castRay(cursorX, cursorY); + osg::Vec3f origin, dest; + mRendering->getCameraToViewportRay(cursorX, cursorY, origin, dest); + + const float maxDist = 200.f; + osg::Vec3f dir = (dest - origin); + dir.normalize(); + dest = origin + dir * maxDist; - if (!result.first) - return MWWorld::Ptr(); + MWPhysics::PhysicsSystem::RayResult result = mPhysics->castRay(origin, dest, MWWorld::Ptr(), + MWPhysics::CollisionType_World|MWPhysics::CollisionType_HeightMap); CellStore* cell = getPlayerPtr().getCell(); ESM::Position pos = getPlayerPtr().getRefData().getPosition(); - pos.pos[0] = result.second[0]; - pos.pos[1] = result.second[1]; - pos.pos[2] = result.second[2]; + if (result.mHit) + { + pos.pos[0] = result.mHitPos.x(); + pos.pos[1] = result.mHitPos.y(); + pos.pos[2] = result.mHitPos.z(); + } // We want only the Z part of the player's rotation pos.rot[0] = 0; pos.rot[1] = 0; @@ -1822,21 +1829,23 @@ namespace MWWorld bool World::canPlaceObject(float cursorX, float cursorY) { - Ogre::Vector3 normal(0,0,0); - std::string handle; - std::pair result;// = mPhysics->castRay(cursorX, cursorY, &normal, &handle); + osg::Vec3f origin, dest; + mRendering->getCameraToViewportRay(cursorX, cursorY, origin, dest); - if (result.first) + const float maxDist = 200.f; + osg::Vec3f dir = (dest - origin); + dir.normalize(); + dest = origin + dir * maxDist; + + MWPhysics::PhysicsSystem::RayResult result = mPhysics->castRay(origin, dest, MWWorld::Ptr(), + MWPhysics::CollisionType_World|MWPhysics::CollisionType_HeightMap); + + if (result.mHit) { // check if the wanted position is on a flat surface, and not e.g. against a vertical wall - if (normal.angleBetween(Ogre::Vector3(0.f,0.f,1.f)).valueDegrees() >= 30) + if (std::acos(result.mHitNormal * osg::Vec3f(0,0,1)) >= osg::DegreesToRadians(30.f)) return false; - /* - MWWorld::Ptr hitObject = searchPtrViaHandle(handle); - if (!hitObject.isEmpty() && hitObject.getClass().isActor()) - return false; - */ return true; } else @@ -1917,9 +1926,10 @@ namespace MWWorld float len = 100.0; - std::pair hit = mPhysics->castRay(orig, dir*len); - if (hit.first) - pos.pos[2] = hit.second.z(); + MWPhysics::PhysicsSystem::RayResult result = mPhysics->castRay(orig, orig+dir*len, MWWorld::Ptr(), + MWPhysics::CollisionType_World|MWPhysics::CollisionType_HeightMap); + if (result.mHit) + pos.pos[2] = result.mHitPos.z(); // copy the object and set its count int origCount = object.getRefData().getCount(); @@ -2346,50 +2356,30 @@ namespace MWWorld } } - bool World::getLOS(const MWWorld::Ptr& actor,const MWWorld::Ptr& targetActor) + bool World::getLOS(const MWWorld::Ptr& actor, const MWWorld::Ptr& targetActor) { if (!targetActor.getRefData().isEnabled() || !actor.getRefData().isEnabled()) return false; // cannot get LOS unless both NPC's are enabled if (!targetActor.getRefData().getBaseNode() || !targetActor.getRefData().getBaseNode()) return false; // not in active cell - // TODO: move to PhysicsSystem - /* - OEngine::Physic::PhysicActor* actor1 = mPhysEngine->getCharacter(actor.getRefData().getHandle()); - OEngine::Physic::PhysicActor* actor2 = mPhysEngine->getCharacter(targetActor.getRefData().getHandle()); - - if (!actor1 || !actor2) - return false; - - Ogre::Vector3 halfExt1 = actor1->getHalfExtents(); - const float* pos1 = actor.getRefData().getPosition().pos; - Ogre::Vector3 halfExt2 = actor2->getHalfExtents(); - const float* pos2 = targetActor.getRefData().getPosition().pos; - - btVector3 from(pos1[0],pos1[1],pos1[2]+halfExt1.z*2*0.9f); // eye level - btVector3 to(pos2[0],pos2[1],pos2[2]+halfExt2.z*2*0.9f); - - std::pair result = mPhysEngine->rayTest(from, to,false); - if(result.first == "") return true; - */ - - return true; + return mPhysics->getLineOfSight(actor, targetActor); } float World::getDistToNearestRayHit(const Ogre::Vector3& from, const Ogre::Vector3& dir, float maxDist) { - return 0; - /* - btVector3 btFrom(from.x, from.y, from.z); - btVector3 btTo = btVector3(dir.x, dir.y, dir.z); - btTo.normalize(); - btTo = btFrom + btTo * maxDist; + osg::Vec3f from_ (from.x, from.y, from.z); + osg::Vec3f to_ (dir.x, dir.y, dir.z); + to_.normalize(); + to_ = from_ + (to_ * maxDist); - std::pair result = mPhysEngine->rayTest(btFrom, btTo, false); + MWPhysics::PhysicsSystem::RayResult result = mPhysics->castRay(from_, to_, MWWorld::Ptr(), + MWPhysics::CollisionType_World|MWPhysics::CollisionType_HeightMap); - if(result.second == -1) return maxDist; - else return result.second*(btTo-btFrom).length(); - */ + if (!result.mHit) + return maxDist; + else + return (result.mHitPos - from_).length(); } void World::enableActorCollision(const MWWorld::Ptr& actor, bool enable) @@ -2697,37 +2687,30 @@ namespace MWWorld else { // For NPCs use facing direction from Head node - Ogre::Vector3 origin(actor.getRefData().getPosition().pos); -#if 0 - MWRender::Animation *anim = mRendering->getAnimation(actor); - if(anim != NULL) + osg::Vec3f origin(actor.getRefData().getPosition().asVec3()); + + MWRender::Animation* anim = mRendering->getAnimation(actor); + if (anim != NULL) { - Ogre::Node *node = anim->getNode("Head"); + const osg::Node* node = anim->getNode("Head"); if (node == NULL) node = anim->getNode("Bip01 Head"); - if(node != NULL) - origin += node->_getDerivedPosition(); - } -#endif - /* - - Ogre::Quaternion orient; - orient = Ogre::Quaternion(Ogre::Radian(actor.getRefData().getPosition().rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z) * - Ogre::Quaternion(Ogre::Radian(actor.getRefData().getPosition().rot[0]), Ogre::Vector3::NEGATIVE_UNIT_X); - Ogre::Vector3 direction = orient.yAxis(); - Ogre::Vector3 dest = origin + direction * distance; - - std::vector > collisions = mPhysEngine->rayTest2(btVector3(origin.x, origin.y, origin.z), btVector3(dest.x, dest.y, dest.z)); - for (std::vector >::iterator cIt = collisions.begin(); cIt != collisions.end(); ++cIt) - { - MWWorld::Ptr collided = getPtrViaHandle(cIt->second); - if (collided != actor) + if (node != NULL) { - target = collided; - break; + osg::MatrixList mats = node->getWorldMatrices(); + if (mats.size()) + origin = mats[0].getTrans(); } } - */ + + osg::Quat orient = osg::Quat(actor.getRefData().getPosition().rot[0], osg::Vec3f(-1,0,0)) + * osg::Quat(actor.getRefData().getPosition().rot[2], osg::Vec3f(0,0,-1)); + + osg::Vec3f direction = orient * osg::Vec3f(0,1,0); + osg::Vec3f dest = origin + direction * distance; + + MWPhysics::PhysicsSystem::RayResult result = mPhysics->castRay(origin, dest, actor); + target = result.mHitObject; } std::string selectedSpell = stats.getSpells().getSelectedSpell(); From f88079fddd1b77e5e1b09fe9e41e9f55d3250cb3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 1 Jun 2015 02:40:42 +0200 Subject: [PATCH 1347/3725] Restore the isOnGround hack --- apps/openmw/mwphysics/physicssystem.cpp | 37 +++++++++++++++++++++++++ apps/openmw/mwphysics/physicssystem.hpp | 2 ++ apps/openmw/mwworld/worldimp.cpp | 37 +------------------------ 3 files changed, 40 insertions(+), 36 deletions(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index c942fecb1..7c083ca08 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -798,6 +798,43 @@ namespace MWPhysics return !result.mHit; } + // physactor->getOnGround() is not a reliable indicator of whether the actor + // is on the ground (defaults to false, which means code blocks such as + // CharacterController::update() may falsely detect "falling"). + // + // Also, collisions can move z position slightly off zero, giving a false + // indication. In order to reduce false detection of jumping, small distance + // below the actor is detected and ignored. A value of 1.5 is used here, but + // something larger may be more suitable. This change should resolve Bug#1271. + // + // TODO: There might be better places to update PhysicActor::mOnGround. + bool PhysicsSystem::isOnGround(const MWWorld::Ptr &actor) + { + Actor* physactor = getActor(actor); + if(!physactor) + return false; + if(physactor->getOnGround()) + return true; + else + { + osg::Vec3f pos(actor.getRefData().getPosition().asVec3()); + + ActorTracer tracer; + // a small distance above collision object is considered "on ground" + tracer.findGround(physactor, + pos, + pos - osg::Vec3f(0, 0, 1.5f), // trace a small amount down + mCollisionWorld); + if(tracer.mFraction < 1.0f) // collision, must be close to something below + { + physactor->setOnGround(true); + return true; + } + else + return false; + } + } + class ContactTestResultCallback : public btCollisionWorld::ContactResultCallback { public: diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index 7920347ad..2defd7a50 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -104,6 +104,8 @@ namespace MWPhysics /// Return true if actor1 can see actor2. bool getLineOfSight(const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2); + bool isOnGround (const MWWorld::Ptr& actor); + /// Queues velocity movement for a Ptr. If a Ptr is already queued, its velocity will /// be overwritten. Valid until the next call to applyQueuedMovement. void queueObjectMovement(const MWWorld::Ptr &ptr, const osg::Vec3f &velocity); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index f4f960d97..aa21ca7fb 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2022,44 +2022,9 @@ namespace MWWorld return pos.z < cell->getWaterLevel(); } - // physactor->getOnGround() is not a reliable indicator of whether the actor - // is on the ground (defaults to false, which means code blocks such as - // CharacterController::update() may falsely detect "falling"). - // - // Also, collisions can move z position slightly off zero, giving a false - // indication. In order to reduce false detection of jumping, small distance - // below the actor is detected and ignored. A value of 1.5 is used here, but - // something larger may be more suitable. This change should resolve Bug#1271. - // - // TODO: There might be better places to update PhysicActor::mOnGround. bool World::isOnGround(const MWWorld::Ptr &ptr) const { - MWPhysics::Actor* physactor = mPhysics->getActor(ptr); - - if(!physactor) - return false; - return physactor->getOnGround(); - /* - if(physactor->getOnGround()) - return true; - else - { - Ogre::Vector3 pos(ptr.getRefData().getPosition().pos); - OEngine::Physic::ActorTracer tracer; - // a small distance above collision object is considered "on ground" - tracer.findGround(physactor, - pos, - pos - Ogre::Vector3(0, 0, 1.5f), // trace a small amount down - mPhysEngine); - if(tracer.mFraction < 1.0f) // collision, must be close to something below - { - physactor->setOnGround(true); - return true; - } - else - return false; - } - */ + return mPhysics->isOnGround(ptr); } void World::togglePOV() From b0b55e2037d52b392c1031c81cbb8d3ecd602ae6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 1 Jun 2015 02:46:09 +0200 Subject: [PATCH 1348/3725] Delete niftest as it's currently broken --- CMakeLists.txt | 9 --- components/nif/tests/.gitignore | 1 - components/nif/tests/CMakeLists.txt | 19 ------ components/nif/tests/niftest.cpp | 96 ----------------------------- components/nif/tests/test.sh | 15 ----- 5 files changed, 140 deletions(-) delete mode 100644 components/nif/tests/.gitignore delete mode 100644 components/nif/tests/CMakeLists.txt delete mode 100644 components/nif/tests/niftest.cpp delete mode 100755 components/nif/tests/test.sh diff --git a/CMakeLists.txt b/CMakeLists.txt index 3c3cd9f6b..43d40c2ef 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -70,7 +70,6 @@ option(BUILD_OPENCS "build OpenMW Construction Set" ON) option(BUILD_WIZARD "build Installation Wizard" ON) option(BUILD_WITH_CODE_COVERAGE "Enable code coverage with gconv" OFF) option(BUILD_UNITTESTS "Enable Unittests with Google C++ Unittest" OFF) -option(BUILD_NIFTEST "build nif file tester" OFF) option(BUILD_MYGUI_PLUGIN "build MyGUI plugin for OpenMW resources, to use with MyGUI tools" ON) # OS X deployment @@ -319,9 +318,6 @@ IF(NOT WIN32 AND NOT APPLE) IF(BUILD_OPENCS) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/openmw-cs" DESTINATION "${BINDIR}" ) ENDIF(BUILD_OPENCS) - IF(BUILD_NIFTEST) - INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/niftest" DESTINATION "${BINDIR}" ) - ENDIF(BUILD_NIFTEST) IF(BUILD_WIZARD) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/openmw-wizard" DESTINATION "${BINDIR}" ) ENDIF(BUILD_WIZARD) @@ -461,11 +457,6 @@ add_subdirectory (components) # add_subdirectory(plugins/mygui_resource_plugin) #endif() -#Testing -if (BUILD_NIFTEST) - add_subdirectory(components/nif/tests/) -endif(BUILD_NIFTEST) - # Apps and tools if (BUILD_OPENMW) add_subdirectory( apps/openmw ) diff --git a/components/nif/tests/.gitignore b/components/nif/tests/.gitignore deleted file mode 100644 index 397b4a762..000000000 --- a/components/nif/tests/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.log diff --git a/components/nif/tests/CMakeLists.txt b/components/nif/tests/CMakeLists.txt deleted file mode 100644 index a45298180..000000000 --- a/components/nif/tests/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ -set(NIFTEST - niftest.cpp -) -source_group(components\\nif\\tests FILES ${NIFTEST}) - -# Main executable -add_executable(niftest - ${NIFTEST} -) - -target_link_libraries(niftest - ${Boost_LIBRARIES} - components -) - -if (BUILD_WITH_CODE_COVERAGE) - add_definitions (--coverage) - target_link_libraries(niftest gcov) -endif() diff --git a/components/nif/tests/niftest.cpp b/components/nif/tests/niftest.cpp deleted file mode 100644 index a06c002df..000000000 --- a/components/nif/tests/niftest.cpp +++ /dev/null @@ -1,96 +0,0 @@ -///Program to test .nif files both on the FileSystem and in BSA archives. - -#include "../niffile.hpp" -#include "../../bsa/bsa_file.hpp" -#include "../../bsa/bsa_archive.hpp" -#include -#include -#include -#include -#include - -///See if the file has the named extension -bool hasExtension(std::string filename, std::string extensionToFind) -{ - std::string extension = filename.substr(filename.find_last_of(".")+1); - - //Convert strings to lower case for comparison - std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower); - std::transform(extensionToFind.begin(), extensionToFind.end(), extensionToFind.begin(), ::tolower); - - if(extension == extensionToFind) - return true; - else - return false; -} - -///See if the file has the "nif" extension. -bool isNIF(std::string filename) -{ - return hasExtension(filename,"nif"); -} -///See if the file has the "bsa" extension. -bool isBSA(std::string filename) -{ - return hasExtension(filename,"bsa"); -} - -///Check all the nif files in the given BSA archive -void readBSA(std::string filename) -{ - Bsa::BSAFile bsa; - bsa.open(filename.c_str()); - - const Bsa::BSAFile::FileList &files = bsa.getList(); - Bsa::addBSA(filename,"Bsa Files"); - - for(unsigned int i=0; i nifs.txt -find "$DATAFILESDIR" -iname *nif >> nifs.txt - -sed -e 's/.*/\"&\"/' nifs.txt > quoted_nifs.txt - -xargs --arg-file=quoted_nifs.txt ../../../niftest - -rm nifs.txt -rm quoted_nifs.txt From 28694248477abad8c82a0e12b32354d20ff2313f Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 1 Jun 2015 04:41:03 +0200 Subject: [PATCH 1349/3725] Fix first person camera for beast races --- apps/openmw/mwrender/camera.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwrender/camera.cpp b/apps/openmw/mwrender/camera.cpp index 69998ed26..e28b6befa 100644 --- a/apps/openmw/mwrender/camera.cpp +++ b/apps/openmw/mwrender/camera.cpp @@ -362,6 +362,8 @@ namespace MWRender { mAnimation->setViewMode(NpcAnimation::VM_FirstPerson); mTrackingNode = mAnimation->getNode("Camera"); + if (!mTrackingNode) + mTrackingNode = mAnimation->getNode("Head"); } else { From bed31996c910d405c09dee815cfdadf762149440 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 1 Jun 2015 15:34:46 +0200 Subject: [PATCH 1350/3725] Camera raycast --- apps/openmw/mwphysics/physicssystem.cpp | 25 +++++++++++++++++++++ apps/openmw/mwphysics/physicssystem.hpp | 2 ++ apps/openmw/mwrender/camera.cpp | 27 +++++++++++++++-------- apps/openmw/mwrender/camera.hpp | 5 ++++- apps/openmw/mwrender/renderingmanager.cpp | 5 +++++ apps/openmw/mwrender/renderingmanager.hpp | 2 ++ apps/openmw/mwworld/worldimp.cpp | 13 +++++++++++ 7 files changed, 69 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 7c083ca08..c0e7a80b9 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -778,6 +779,30 @@ namespace MWPhysics return result; } + PhysicsSystem::RayResult PhysicsSystem::castSphere(const osg::Vec3f &from, const osg::Vec3f &to, float radius) + { + btCollisionWorld::ClosestConvexResultCallback callback(toBullet(from), toBullet(to)); + callback.m_collisionFilterGroup = 0xff; + callback.m_collisionFilterMask = CollisionType_World|CollisionType_HeightMap; + + btSphereShape shape(radius); + const btQuaternion btrot = btQuaternion::getIdentity(); + + btTransform from_ (btrot, toBullet(from)); + btTransform to_ (btrot, toBullet(to)); + + mCollisionWorld->convexSweepTest(&shape, from_, to_, callback); + + RayResult result; + result.mHit = callback.hasHit(); + if (result.mHit) + { + result.mHitPos = toOsg(callback.m_hitPointWorld); + result.mHitNormal = toOsg(callback.m_hitNormalWorld); + } + return result; + } + bool PhysicsSystem::getLineOfSight(const MWWorld::Ptr &actor1, const MWWorld::Ptr &actor2) { Actor* physactor1 = getActor(actor1); diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index 2defd7a50..d4f7e25b1 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -101,6 +101,8 @@ namespace MWPhysics RayResult castRay(const osg::Vec3f &from, const osg::Vec3f &to, MWWorld::Ptr ignore = MWWorld::Ptr(), int mask = CollisionType_World|CollisionType_HeightMap|CollisionType_Actor); + RayResult castSphere(const osg::Vec3f& from, const osg::Vec3f& to, float radius); + /// Return true if actor1 can see actor2. bool getLineOfSight(const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2); diff --git a/apps/openmw/mwrender/camera.cpp b/apps/openmw/mwrender/camera.cpp index e28b6befa..9080d3164 100644 --- a/apps/openmw/mwrender/camera.cpp +++ b/apps/openmw/mwrender/camera.cpp @@ -80,21 +80,28 @@ namespace MWRender return mTrackingPtr; } - void Camera::updateCamera(osg::Camera *cam) + osg::Vec3d Camera::getFocalPoint() { - if (mTrackingPtr.isEmpty()) - return; const osg::Node* trackNode = mTrackingNode; if (!trackNode) - return; + return osg::Vec3d(); osg::MatrixList mats = trackNode->getWorldMatrices(); if (!mats.size()) - return; + return osg::Vec3d(); const osg::Matrix& worldMat = mats[0]; osg::Vec3d position = worldMat.getTrans(); if (!isFirstPerson()) position.z() += mHeight; + return position; + } + + void Camera::updateCamera(osg::Camera *cam) + { + if (mTrackingPtr.isEmpty()) + return; + + osg::Vec3d position = getFocalPoint(); osg::Quat orient = osg::Quat(getPitch(), osg::Vec3d(1,0,0)) * osg::Quat(getYaw(), osg::Vec3d(0,0,1)); @@ -373,12 +380,14 @@ namespace MWRender rotateCamera(getPitch(), getYaw(), false); } - void Camera::getPosition(osg::Vec3 &focal, osg::Vec3 &camera) + void Camera::getPosition(osg::Vec3f &focal, osg::Vec3f &camera) { - //mCamera->getParentSceneNode()->needUpdate(true); + focal = getFocalPoint(); - //camera = mCamera->getRealPosition(); - //focal = mCameraNode->_getDerivedPosition(); + osg::Quat orient = osg::Quat(getPitch(), osg::Vec3d(1,0,0)) * osg::Quat(getYaw(), osg::Vec3d(0,0,1)); + + osg::Vec3d offset = orient * osg::Vec3d(0, -mCameraDistance, 0); + camera = focal + offset; } void Camera::togglePlayerLooking(bool enable) diff --git a/apps/openmw/mwrender/camera.hpp b/apps/openmw/mwrender/camera.hpp index 68f0870d7..a655e1c1f 100644 --- a/apps/openmw/mwrender/camera.hpp +++ b/apps/openmw/mwrender/camera.hpp @@ -5,6 +5,7 @@ #include #include +#include #include "../mwworld/ptr.hpp" @@ -113,8 +114,10 @@ namespace MWRender void setAnimation(NpcAnimation *anim); + osg::Vec3d getFocalPoint(); + /// Stores focal and camera world positions in passed arguments - void getPosition(osg::Vec3 &focal, osg::Vec3 &camera); + void getPosition(osg::Vec3f &focal, osg::Vec3f &camera); void togglePlayerLooking(bool enable); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index a067422d4..021835839 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -514,6 +514,11 @@ namespace MWRender } } + float RenderingManager::getNearClipDistance() const + { + return mNearClip; + } + bool RenderingManager::vanityRotateCamera(const float *rot) { if(!mCamera->isVanityOrPreviewModeEnabled()) diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index e2524b360..57a2df60e 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -113,6 +113,8 @@ namespace MWRender void processChangedSettings(const Settings::CategorySettingVector& settings); + float getNearClipDistance() const; + // camera stuff bool vanityRotateCamera(const float *rot); void setCameraDistance(float dist, bool adjust, bool override); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index aa21ca7fb..2f47c19e6 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1617,6 +1617,19 @@ namespace MWWorld int blind = static_cast(player.getClass().getCreatureStats(player).getMagicEffects().get(ESM::MagicEffect::Blind).getMagnitude()); MWBase::Environment::get().getWindowManager()->setBlindness(std::max(0, std::min(100, blind))); + + + mRendering->getCamera()->setCameraDistance(); + if(!mRendering->getCamera()->isFirstPerson()) + { + osg::Vec3f focal, camera; + mRendering->getCamera()->getPosition(focal, camera); + float radius = mRendering->getNearClipDistance()*2.5f; + MWPhysics::PhysicsSystem::RayResult result = mPhysics->castSphere(focal, camera, radius); + if (result.mHit) + mRendering->getCamera()->setCameraDistance((result.mHitPos - focal).length() - radius, false, false); + } + } void World::updateSoundListener() From 987918ca15faf0961c056e162044beb9baa04dba Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 1 Jun 2015 16:18:57 +0200 Subject: [PATCH 1351/3725] NpcAnimation::setAlpha --- apps/openmw/mwrender/npcanimation.cpp | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 7283a621a..0bbec707f 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -2,6 +2,8 @@ #include #include +#include +#include #include @@ -991,7 +993,29 @@ void NpcAnimation::setAlpha(float alpha) return; mAlpha = alpha; - // TODO + if (alpha != 1.f) + { + osg::StateSet* stateset (new osg::StateSet); + + osg::BlendFunc* blendfunc (new osg::BlendFunc); + stateset->setAttributeAndModes(blendfunc, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + + // FIXME: overriding diffuse/ambient/emissive colors + osg::Material* material (new osg::Material); + material->setColorMode(osg::Material::DIFFUSE); + material->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(1,1,1,alpha)); + material->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(1,1,1,1)); + stateset->setAttributeAndModes(material, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + + stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); + stateset->setRenderBinMode(osg::StateSet::OVERRIDE_RENDERBIN_DETAILS); + stateset->setNestRenderBins(false); + mObjectRoot->setStateSet(stateset); + } + else + { + mObjectRoot->setStateSet(NULL); + } } void NpcAnimation::enableHeadAnimation(bool enable) From 7f9f9a32d27c9f96a53dff0ae03b529661177712 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 1 Jun 2015 16:25:15 +0200 Subject: [PATCH 1352/3725] InitWorldSpaceParticles fix --- apps/openmw/mwrender/creatureanimation.cpp | 9 +++++---- apps/openmw/mwrender/effectmanager.cpp | 1 + apps/openmw/mwrender/npcanimation.cpp | 1 + components/resource/scenemanager.cpp | 14 +++++++++++--- components/resource/scenemanager.hpp | 3 +++ 5 files changed, 21 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index 0dd647c9c..9d1fccdb2 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -107,12 +107,13 @@ void CreatureWeaponAnimation::updatePart(PartHolderPtr& scene, int slot) bonename = "Shield Bone"; osg::ref_ptr node = mResourceSystem->getSceneManager()->createInstance(item.getClass().getModel(item)); - SceneUtil::attach(node, mObjectRoot, bonename, bonename); + osg::ref_ptr attached = SceneUtil::attach(node, mObjectRoot, bonename, bonename); + mResourceSystem->getSceneManager()->notifyAttached(attached); - scene.reset(new PartHolder(node)); + scene.reset(new PartHolder(attached)); if (!item.getClass().getEnchantment(item).empty()) - addGlow(node, getEnchantmentColor(item)); + addGlow(attached, getEnchantmentColor(item)); // Crossbows start out with a bolt attached // FIXME: code duplicated from NpcAnimation @@ -137,7 +138,7 @@ void CreatureWeaponAnimation::updatePart(PartHolderPtr& scene, int slot) source.reset(new NullAnimationTime); SceneUtil::AssignControllerSourcesVisitor assignVisitor(source); - node->accept(assignVisitor); + attached->accept(assignVisitor); } void CreatureWeaponAnimation::attachArrow() diff --git a/apps/openmw/mwrender/effectmanager.cpp b/apps/openmw/mwrender/effectmanager.cpp index 42a63fc68..c4e457a1f 100644 --- a/apps/openmw/mwrender/effectmanager.cpp +++ b/apps/openmw/mwrender/effectmanager.cpp @@ -49,6 +49,7 @@ void EffectManager::addEffect(const std::string &model, const std::string& textu overrideTexture(textureOverride, mResourceSystem, node); mParentNode->addChild(trans); + mResourceSystem->getSceneManager()->notifyAttached(node); mEffects[trans] = effect; } diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 0bbec707f..da44d7f20 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -628,6 +628,7 @@ PartHolderPtr NpcAnimation::insertBoundedPart(const std::string& model, const st { osg::ref_ptr instance = mResourceSystem->getSceneManager()->createInstance(model); osg::ref_ptr attached = SceneUtil::attach(instance, mObjectRoot, bonefilter, bonename); + mResourceSystem->getSceneManager()->notifyAttached(attached); if (enchantedGlow) addGlow(attached, *glowColor); diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index 5c3d9f151..8de08bd9d 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -52,7 +52,10 @@ namespace void transformInitialParticles(osgParticle::ParticleSystem* partsys, osg::Node* node) { - osg::Matrix worldMat = node->getWorldMatrices()[0]; + osg::MatrixList mats = node->getWorldMatrices(); + if (mats.empty()) + return; + osg::Matrix worldMat = mats[0]; worldMat.orthoNormalize(worldMat); // scale is already applied on the particle node for (int i=0; inumParticles(); ++i) { @@ -140,8 +143,7 @@ namespace Resource void SceneManager::attachTo(osg::Node *instance, osg::Group *parentNode) const { parentNode->addChild(instance); - InitWorldSpaceParticlesVisitor visitor; - instance->accept(visitor); + notifyAttached(instance); } void SceneManager::releaseGLObjects(osg::State *state) @@ -157,6 +159,12 @@ namespace Resource mIncrementalCompileOperation = ico; } + void SceneManager::notifyAttached(osg::Node *node) const + { + InitWorldSpaceParticlesVisitor visitor; + node->accept(visitor); + } + const VFS::Manager* SceneManager::getVFS() const { return mVFS; diff --git a/components/resource/scenemanager.hpp b/components/resource/scenemanager.hpp index 625c1cd5e..f4ca0dea2 100644 --- a/components/resource/scenemanager.hpp +++ b/components/resource/scenemanager.hpp @@ -64,6 +64,9 @@ namespace Resource /// Set up an IncrementalCompileOperation for background compiling of loaded scenes. void setIncrementalCompileOperation(osgUtil::IncrementalCompileOperation* ico); + /// @note If you used SceneManager::attachTo, this was called automatically. + void notifyAttached(osg::Node* node) const; + const VFS::Manager* getVFS() const; Resource::TextureManager* getTextureManager(); From c85764b65451fe2409b75158f3396f204db2fbc8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 1 Jun 2015 17:02:44 +0200 Subject: [PATCH 1353/3725] Wireframe mode --- apps/openmw/mwrender/renderingmanager.cpp | 29 ++++++++++++++++++++++- components/sceneutil/statesetupdater.cpp | 6 +++++ components/sceneutil/statesetupdater.hpp | 4 ++++ 3 files changed, 38 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 021835839..31ff9b02b 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -42,6 +43,7 @@ namespace MWRender public: StateUpdater() : mFogEnd(0.f) + , mWireframe(false) { } @@ -53,6 +55,14 @@ namespace MWRender fog->setStart(1); fog->setMode(osg::Fog::LINEAR); stateset->setAttributeAndModes(fog, osg::StateAttribute::ON); + if (mWireframe) + { + osg::PolygonMode* polygonmode = new osg::PolygonMode; + polygonmode->setMode(osg::PolygonMode::FRONT_AND_BACK, osg::PolygonMode::LINE); + stateset->setAttributeAndModes(polygonmode, osg::StateAttribute::ON); + } + else + stateset->removeAttribute(osg::StateAttribute::POLYGONMODE); } virtual void apply(osg::StateSet* stateset, osg::NodeVisitor*) @@ -79,10 +89,25 @@ namespace MWRender mFogEnd = end; } + void setWireframe(bool wireframe) + { + if (mWireframe != wireframe) + { + mWireframe = wireframe; + reset(); + } + } + + bool getWireframe() const + { + return mWireframe; + } + private: osg::Vec4f mAmbientColor; osg::Vec4f mFogColor; float mFogEnd; + bool mWireframe; }; RenderingManager::RenderingManager(osgViewer::Viewer* viewer, osg::ref_ptr rootNode, Resource::ResourceSystem* resourceSystem) @@ -224,7 +249,9 @@ namespace MWRender return mPathgrid->toggleRenderMode(mode); else if (mode == Render_Wireframe) { - return false; + bool wireframe = !mStateUpdater->getWireframe(); + mStateUpdater->setWireframe(wireframe); + return wireframe; } /* else //if (mode == Render_BoundingBoxes) diff --git a/components/sceneutil/statesetupdater.cpp b/components/sceneutil/statesetupdater.cpp index 8ed229aa6..66e40f3e1 100644 --- a/components/sceneutil/statesetupdater.cpp +++ b/components/sceneutil/statesetupdater.cpp @@ -28,6 +28,12 @@ namespace SceneUtil traverse(node, nv); } + void StateSetUpdater::reset() + { + mStateSets[0] = NULL; + mStateSets[1] = NULL; + } + StateSetUpdater::StateSetUpdater() { } diff --git a/components/sceneutil/statesetupdater.hpp b/components/sceneutil/statesetupdater.hpp index 56f832a08..a4fcd7866 100644 --- a/components/sceneutil/statesetupdater.hpp +++ b/components/sceneutil/statesetupdater.hpp @@ -35,6 +35,10 @@ namespace SceneUtil /// @par May be used e.g. to allocate StateAttributes. virtual void setDefaults(osg::StateSet* stateset) {} + protected: + /// Reset mStateSets, forcing a setDefaults() on the next frame. Can be used to change the defaults if needed. + void reset(); + private: osg::ref_ptr mStateSets[2]; }; From de8e5f0db1ccde4510681b10cacc747c1a90ed63 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 1 Jun 2015 21:41:13 +0200 Subject: [PATCH 1354/3725] Restore projectiles --- apps/openmw/CMakeLists.txt | 7 +- apps/openmw/mwbase/mechanicsmanager.hpp | 8 +- apps/openmw/mwbase/world.hpp | 6 +- apps/openmw/mwclass/creature.cpp | 8 +- apps/openmw/mwclass/npc.cpp | 8 +- apps/openmw/mwgui/windowmanagerimp.cpp | 3 + apps/openmw/mwmechanics/actors.cpp | 8 +- apps/openmw/mwmechanics/actors.hpp | 2 +- apps/openmw/mwmechanics/aiavoiddoor.cpp | 2 +- apps/openmw/mwmechanics/combat.cpp | 6 +- apps/openmw/mwmechanics/combat.hpp | 2 +- .../mwmechanics/mechanicsmanagerimp.cpp | 12 +- .../mwmechanics/mechanicsmanagerimp.hpp | 4 +- apps/openmw/mwmechanics/objects.cpp | 4 +- apps/openmw/mwmechanics/objects.hpp | 2 +- apps/openmw/mwmechanics/spellcasting.cpp | 8 +- apps/openmw/mwmechanics/spellcasting.hpp | 2 +- apps/openmw/mwphysics/physicssystem.cpp | 15 +- apps/openmw/mwphysics/physicssystem.hpp | 4 +- apps/openmw/mwscript/miscextensions.cpp | 4 +- apps/openmw/mwworld/actiontrap.cpp | 6 +- apps/openmw/mwworld/projectilemanager.cpp | 195 ++++++++---------- apps/openmw/mwworld/projectilemanager.hpp | 45 ++-- apps/openmw/mwworld/worldimp.cpp | 60 ++---- apps/openmw/mwworld/worldimp.hpp | 6 +- components/esm/projectilestate.hpp | 4 +- components/esm/util.hpp | 26 +++ 27 files changed, 231 insertions(+), 226 deletions(-) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 3cf43749d..c46a83183 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -23,9 +23,7 @@ add_openmw_dir (mwrender actors objects renderingmanager animation rotatecontroller sky npcanimation vismask creatureanimation effectmanager util renderinginterface pathgrid rendermode weaponanimation bulletdebugdraw globalmap characterpreview camera localmap -# occlusionquery water shadows -# ripplesimulation refraction -# terrainstorage weaponanimation +# occlusionquery water shadows ripplesimulation refraction terrainstorage ) add_openmw_dir (mwinput @@ -68,8 +66,7 @@ add_openmw_dir (mwworld cells localscripts customdata inventorystore ptr actionopen actionread actionequip timestamp actionalchemy cellstore actionapply actioneat esmstore store recordcmp fallback actionrepair actionsoulgem livecellref actiondoor - contentloader esmloader actiontrap cellreflist cellref physicssystem weather -# projectilemanager + contentloader esmloader actiontrap cellreflist cellref physicssystem weather projectilemanager ) add_openmw_dir (mwphysics diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index f7fc515f5..1d3619d3d 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -6,9 +6,9 @@ #include #include -namespace Ogre +namespace osg { - class Vector3; + class Vec3f; } namespace ESM @@ -174,8 +174,8 @@ namespace MWBase virtual bool toggleAI() = 0; virtual bool isAIActive() = 0; - virtual void getObjectsInRange (const Ogre::Vector3& position, float radius, std::vector& objects) = 0; - virtual void getActorsInRange(const Ogre::Vector3 &position, float radius, std::vector &objects) = 0; + virtual void getObjectsInRange (const osg::Vec3f& position, float radius, std::vector& objects) = 0; + virtual void getActorsInRange(const osg::Vec3f &position, float radius, std::vector &objects) = 0; ///return the list of actors which are following the given actor /**ie AiFollow is active and the target is the actor**/ diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 4d01f9529..f258eb300 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -378,7 +378,7 @@ namespace MWBase virtual bool isWading(const MWWorld::Ptr &object) const = 0; ///Is the head of the creature underwater? virtual bool isSubmerged(const MWWorld::Ptr &object) const = 0; - virtual bool isUnderwater(const MWWorld::CellStore* cell, const Ogre::Vector3 &pos) const = 0; + virtual bool isUnderwater(const MWWorld::CellStore* cell, const osg::Vec3f &pos) const = 0; virtual bool isOnGround(const MWWorld::Ptr &ptr) const = 0; virtual void togglePOV() = 0; @@ -485,7 +485,7 @@ namespace MWBase virtual void launchMagicBolt (const std::string& model, const std::string& sound, const std::string& spellId, float speed, bool stack, const ESM::EffectList& effects, - const MWWorld::Ptr& caster, const std::string& sourceName, const Ogre::Vector3& fallbackDirection) = 0; + const MWWorld::Ptr& caster, const std::string& sourceName, const osg::Vec3f& fallbackDirection) = 0; virtual void launchProjectile (MWWorld::Ptr actor, MWWorld::Ptr projectile, const osg::Vec3f& worldPos, const osg::Quat& orient, MWWorld::Ptr bow, float speed) = 0; @@ -532,7 +532,7 @@ namespace MWBase virtual void spawnEffect (const std::string& model, const std::string& textureOverride, const osg::Vec3f& worldPos) = 0; - virtual void explodeSpell (const Ogre::Vector3& origin, const ESM::EffectList& effects, + virtual void explodeSpell (const osg::Vec3f& origin, const ESM::EffectList& effects, const MWWorld::Ptr& caster, ESM::RangeType rangeType, const std::string& id, const std::string& sourceName) = 0; virtual void activate (const MWWorld::Ptr& object, const MWWorld::Ptr& actor) = 0; diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 64850d127..ea67884d3 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -247,7 +247,7 @@ namespace MWClass if (!victim.getClass().isActor()) return; // Can't hit non-actors - Ogre::Vector3 hitPosition (result.second.x(), result.second.y(), result.second.z()); + osg::Vec3f hitPosition (result.second); float hitchance = MWMechanics::getHitChance(ptr, victim, ref->mBase->mData.mCombat); @@ -319,7 +319,7 @@ namespace MWClass damage = 0; if (damage > 0) - MWBase::Environment::get().getWorld()->spawnBloodEffect(victim, osg::Vec3f(hitPosition.x, hitPosition.y, hitPosition.z)); + MWBase::Environment::get().getWorld()->spawnBloodEffect(victim, hitPosition); MWMechanics::diseaseContact(victim, ptr); @@ -726,7 +726,7 @@ namespace MWClass if(name == "left") { MWBase::World *world = MWBase::Environment::get().getWorld(); - Ogre::Vector3 pos(ptr.getRefData().getPosition().pos); + osg::Vec3f pos(ptr.getRefData().getPosition().asVec3()); if(world->isUnderwater(ptr.getCell(), pos) || world->isWalkingOnWater(ptr)) return 2; if(world->isOnGround(ptr)) @@ -736,7 +736,7 @@ namespace MWClass if(name == "right") { MWBase::World *world = MWBase::Environment::get().getWorld(); - Ogre::Vector3 pos(ptr.getRefData().getPosition().pos); + osg::Vec3f pos(ptr.getRefData().getPosition().asVec3()); if(world->isUnderwater(ptr.getCell(), pos) || world->isWalkingOnWater(ptr)) return 3; if(world->isOnGround(ptr)) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 791c2f57e..4307fe9be 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -493,7 +493,7 @@ namespace MWClass // TODO: Use second to work out the hit angle std::pair result = world->getHitContact(ptr, dist); MWWorld::Ptr victim = result.first; - Ogre::Vector3 hitPosition (result.second.x(), result.second.y(), result.second.z()); + osg::Vec3f hitPosition (result.second); if(victim.isEmpty()) // Didn't hit anything return; @@ -583,7 +583,7 @@ namespace MWClass damage = 0; if (healthdmg && damage > 0) - MWBase::Environment::get().getWorld()->spawnBloodEffect(victim, osg::Vec3f(hitPosition.x, hitPosition.y, hitPosition.z)); + MWBase::Environment::get().getWorld()->spawnBloodEffect(victim, hitPosition); MWMechanics::diseaseContact(victim, ptr); @@ -1138,7 +1138,7 @@ namespace MWClass if(name == "left" || name == "right") { MWBase::World *world = MWBase::Environment::get().getWorld(); - Ogre::Vector3 pos(ptr.getRefData().getPosition().pos); + osg::Vec3f pos(ptr.getRefData().getPosition().asVec3()); if(world->isSwimming(ptr)) return (name == "left") ? "Swim Left" : "Swim Right"; if(world->isUnderwater(ptr.getCell(), pos) || world->isWalkingOnWater(ptr)) @@ -1175,7 +1175,7 @@ namespace MWClass if(name == "land") { MWBase::World *world = MWBase::Environment::get().getWorld(); - Ogre::Vector3 pos(ptr.getRefData().getPosition().pos); + osg::Vec3f pos(ptr.getRefData().getPosition().asVec3()); if(world->isUnderwater(ptr.getCell(), pos) || world->isWalkingOnWater(ptr)) return "DefaultLandWater"; if(world->isOnGround(ptr)) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 88b0bd321..1182de151 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1623,6 +1623,9 @@ namespace MWGui void WindowManager::clear() { + if (mLocalMapRender) + mLocalMapRender->clear(); + mMap->clear(); mQuickKeysMenu->clear(); mMessageBoxManager->clear(); diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 84e97487a..81dbca58a 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -809,7 +809,7 @@ namespace MWMechanics NpcStats &stats = ptr.getClass().getNpcStats(ptr); MWBase::World *world = MWBase::Environment::get().getWorld(); - bool knockedOutUnderwater = (ctrl->isKnockedOut() && world->isUnderwater(ptr.getCell(), Ogre::Vector3(ptr.getRefData().getPosition().pos))); + bool knockedOutUnderwater = (ctrl->isKnockedOut() && world->isUnderwater(ptr.getCell(), osg::Vec3f(ptr.getRefData().getPosition().asVec3()))); if((world->isSubmerged(ptr) || knockedOutUnderwater) && stats.getMagicEffects().get(ESM::MagicEffect::WaterBreathing).getMagnitude() == 0) { @@ -1385,11 +1385,11 @@ namespace MWMechanics return false; } - void Actors::getObjectsInRange(const Ogre::Vector3& position, float radius, std::vector& out) + void Actors::getObjectsInRange(const osg::Vec3f& position, float radius, std::vector& out) { for (PtrActorMap::iterator iter = mActors.begin(); iter != mActors.end(); ++iter) { - if (Ogre::Vector3(iter->first.getRefData().getPosition().pos).squaredDistance(position) <= radius*radius) + if ((iter->first.getRefData().getPosition().asVec3() - position).length2() <= radius*radius) out.push_back(iter->first); } } @@ -1457,7 +1457,7 @@ namespace MWMechanics std::list Actors::getActorsFighting(const MWWorld::Ptr& actor) { std::list list; std::vector neighbors; - Ogre::Vector3 position = Ogre::Vector3(actor.getRefData().getPosition().pos); + osg::Vec3f position (actor.getRefData().getPosition().asVec3()); getObjectsInRange(position, MWBase::Environment::get().getWorld()->getStore().get().find("fAlarmRadius")->getFloat(), neighbors); //only care about those within the alarm disance diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index 70f1b47d9..f9e58ab4f 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -114,7 +114,7 @@ namespace MWMechanics void skipAnimation(const MWWorld::Ptr& ptr); bool checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string& groupName); - void getObjectsInRange(const Ogre::Vector3& position, float radius, std::vector& out); + void getObjectsInRange(const osg::Vec3f& position, float radius, std::vector& out); ///Returns the list of actors which are following the given actor /**ie AiFollow is active and the target is the actor **/ diff --git a/apps/openmw/mwmechanics/aiavoiddoor.cpp b/apps/openmw/mwmechanics/aiavoiddoor.cpp index 9ec5bc19a..83f9dffb4 100644 --- a/apps/openmw/mwmechanics/aiavoiddoor.cpp +++ b/apps/openmw/mwmechanics/aiavoiddoor.cpp @@ -64,7 +64,7 @@ bool MWMechanics::AiAvoidDoor::execute (const MWWorld::Ptr& actor, AiState& stat // Make all nearby actors also avoid the door std::vector actors; - MWBase::Environment::get().getMechanicsManager()->getActorsInRange(Ogre::Vector3(pos.pos[0],pos.pos[1],pos.pos[2]),100,actors); + MWBase::Environment::get().getMechanicsManager()->getActorsInRange(pos.asVec3(),100,actors); for(std::vector::iterator it = actors.begin(); it != actors.end(); ++it) { if(*it != MWBase::Environment::get().getWorld()->getPlayerPtr()) { //Not the player MWMechanics::AiSequence& seq = it->getClass().getCreatureStats(*it).getAiSequence(); diff --git a/apps/openmw/mwmechanics/combat.cpp b/apps/openmw/mwmechanics/combat.cpp index ee48d124f..b013dbb1b 100644 --- a/apps/openmw/mwmechanics/combat.cpp +++ b/apps/openmw/mwmechanics/combat.cpp @@ -28,7 +28,7 @@ float signedAngleRadians (const osg::Vec3f& v1, const osg::Vec3f& v2, const osg: return std::atan2((normal * (v1 ^ v2)), (v1 * v2)); } -bool applyEnchantment (const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim, const MWWorld::Ptr& object, const Ogre::Vector3& hitPosition) +bool applyEnchantment (const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim, const MWWorld::Ptr& object, const osg::Vec3f& hitPosition) { std::string enchantmentName = !object.isEmpty() ? object.getClass().getEnchantment(object) : ""; if (!enchantmentName.empty()) @@ -166,7 +166,7 @@ namespace MWMechanics } void projectileHit(const MWWorld::Ptr &attacker, const MWWorld::Ptr &victim, MWWorld::Ptr weapon, const MWWorld::Ptr &projectile, - const Ogre::Vector3& hitPosition) + const osg::Vec3f& hitPosition) { MWBase::World *world = MWBase::Environment::get().getWorld(); const MWWorld::Store &gmst = world->getStore().get(); @@ -221,7 +221,7 @@ namespace MWMechanics appliedEnchantment = applyEnchantment(attacker, victim, projectile, hitPosition); if (damage > 0) - MWBase::Environment::get().getWorld()->spawnBloodEffect(victim, osg::Vec3f(hitPosition.x, hitPosition.y, hitPosition.z)); + MWBase::Environment::get().getWorld()->spawnBloodEffect(victim, hitPosition); // Non-enchanted arrows shot at enemies have a chance to turn up in their inventory if (victim != MWBase::Environment::get().getWorld()->getPlayerPtr() diff --git a/apps/openmw/mwmechanics/combat.hpp b/apps/openmw/mwmechanics/combat.hpp index a2fd8b006..0a31a1a7e 100644 --- a/apps/openmw/mwmechanics/combat.hpp +++ b/apps/openmw/mwmechanics/combat.hpp @@ -15,7 +15,7 @@ void resistNormalWeapon (const MWWorld::Ptr& actor, const MWWorld::Ptr& attacker /// @note for a thrown weapon, \a weapon == \a projectile, for bows/crossbows, \a projectile is the arrow/bolt /// @note \a victim may be empty (e.g. for a hit on terrain), a non-actor (environment objects) or an actor void projectileHit (const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim, MWWorld::Ptr weapon, const MWWorld::Ptr& projectile, - const Ogre::Vector3& hitPosition); + const osg::Vec3f& hitPosition); /// Get the chance (in percent) for \a attacker to successfully hit \a victim with a given weapon skill value float getHitChance (const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim, int skillValue); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 0ae9395c5..8fbb31fb7 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1059,14 +1059,14 @@ namespace MWMechanics // Find all the actors within the alarm radius std::vector neighbors; - Ogre::Vector3 from = Ogre::Vector3(player.getRefData().getPosition().pos); + osg::Vec3f from (player.getRefData().getPosition().asVec3()); const MWWorld::ESMStore& esmStore = MWBase::Environment::get().getWorld()->getStore(); float radius = esmStore.get().find("fAlarmRadius")->getFloat(); mActors.getObjectsInRange(from, radius, neighbors); // victim should be considered even beyond alarm radius - if (!victim.isEmpty() && from.squaredDistance(Ogre::Vector3(victim.getRefData().getPosition().pos)) > radius*radius) + if (!victim.isEmpty() && (from - victim.getRefData().getPosition().asVec3()).length2() > radius*radius) neighbors.push_back(victim); // Did anyone see it? @@ -1149,13 +1149,13 @@ namespace MWMechanics const MWWorld::ESMStore& esmStore = MWBase::Environment::get().getWorld()->getStore(); - Ogre::Vector3 from = Ogre::Vector3(player.getRefData().getPosition().pos); + osg::Vec3f from (player.getRefData().getPosition().asVec3()); float radius = esmStore.get().find("fAlarmRadius")->getFloat(); mActors.getObjectsInRange(from, radius, neighbors); // victim should be considered even beyond alarm radius - if (!victim.isEmpty() && from.squaredDistance(Ogre::Vector3(victim.getRefData().getPosition().pos)) > radius*radius) + if (!victim.isEmpty() && (from - victim.getRefData().getPosition().asVec3()).length2() > radius*radius) neighbors.push_back(victim); int id = MWBase::Environment::get().getWorld()->getPlayer().getNewCrimeId(); @@ -1430,13 +1430,13 @@ namespace MWMechanics MWBase::Environment::get().getDialogueManager()->say(ptr, "attack"); } - void MechanicsManager::getObjectsInRange(const Ogre::Vector3 &position, float radius, std::vector &objects) + void MechanicsManager::getObjectsInRange(const osg::Vec3f &position, float radius, std::vector &objects) { mActors.getObjectsInRange(position, radius, objects); mObjects.getObjectsInRange(position, radius, objects); } - void MechanicsManager::getActorsInRange(const Ogre::Vector3 &position, float radius, std::vector &objects) + void MechanicsManager::getActorsInRange(const osg::Vec3f &position, float radius, std::vector &objects) { mActors.getObjectsInRange(position, radius, objects); } diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index d08334ae8..f695ec57a 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -145,8 +145,8 @@ namespace MWMechanics /// paused we may want to do it manually (after equipping permanent enchantment) virtual void updateMagicEffects (const MWWorld::Ptr& ptr); - virtual void getObjectsInRange (const Ogre::Vector3& position, float radius, std::vector& objects); - virtual void getActorsInRange(const Ogre::Vector3 &position, float radius, std::vector &objects); + virtual void getObjectsInRange (const osg::Vec3f& position, float radius, std::vector& objects); + virtual void getActorsInRange(const osg::Vec3f &position, float radius, std::vector &objects); virtual std::list getActorsFollowing(const MWWorld::Ptr& actor); virtual std::list getActorsFollowingIndices(const MWWorld::Ptr& actor); diff --git a/apps/openmw/mwmechanics/objects.cpp b/apps/openmw/mwmechanics/objects.cpp index ba35af777..d6f5da88d 100644 --- a/apps/openmw/mwmechanics/objects.cpp +++ b/apps/openmw/mwmechanics/objects.cpp @@ -92,11 +92,11 @@ void Objects::skipAnimation(const MWWorld::Ptr& ptr) iter->second->skipAnim(); } -void Objects::getObjectsInRange(const Ogre::Vector3& position, float radius, std::vector& out) +void Objects::getObjectsInRange(const osg::Vec3f& position, float radius, std::vector& out) { for (PtrControllerMap::iterator iter = mObjects.begin(); iter != mObjects.end(); ++iter) { - if (Ogre::Vector3(iter->first.getRefData().getPosition().pos).squaredDistance(position) <= radius*radius) + if ((position - iter->first.getRefData().getPosition().asVec3()).length2() <= radius*radius) out.push_back(iter->first); } } diff --git a/apps/openmw/mwmechanics/objects.hpp b/apps/openmw/mwmechanics/objects.hpp index 373a2a105..6e22c0582 100644 --- a/apps/openmw/mwmechanics/objects.hpp +++ b/apps/openmw/mwmechanics/objects.hpp @@ -41,7 +41,7 @@ namespace MWMechanics void playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number); void skipAnimation(const MWWorld::Ptr& ptr); - void getObjectsInRange (const Ogre::Vector3& position, float radius, std::vector& out); + void getObjectsInRange (const osg::Vec3f& position, float radius, std::vector& out); }; } diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 8965d3b0d..cdca6eeaa 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -779,7 +779,7 @@ namespace MWMechanics MWBase::Environment::get().getWorld()->launchMagicBolt(projectileModel, sound, mId, speed, false, enchantment->mEffects, mCaster, mSourceName, // Not needed, enchantments can only be cast by actors - Ogre::Vector3(1,0,0)); + osg::Vec3f(1,0,0)); return true; } @@ -861,13 +861,13 @@ namespace MWMechanics getProjectileInfo(spell->mEffects, projectileModel, sound, speed); if (!projectileModel.empty()) { - Ogre::Vector3 fallbackDirection (0,1,0); + osg::Vec3f fallbackDirection (0,1,0); // Fall back to a "caster to target" direction if we have no other means of determining it // (e.g. when cast by a non-actor) if (!mTarget.isEmpty()) fallbackDirection = - Ogre::Vector3(mTarget.getRefData().getPosition().pos)- - Ogre::Vector3(mCaster.getRefData().getPosition().pos); + osg::Vec3f(mTarget.getRefData().getPosition().asVec3())- + osg::Vec3f(mCaster.getRefData().getPosition().asVec3()); MWBase::Environment::get().getWorld()->launchMagicBolt(projectileModel, sound, mId, speed, false, spell->mEffects, mCaster, mSourceName, fallbackDirection); diff --git a/apps/openmw/mwmechanics/spellcasting.hpp b/apps/openmw/mwmechanics/spellcasting.hpp index f50584edf..4241c9e3e 100644 --- a/apps/openmw/mwmechanics/spellcasting.hpp +++ b/apps/openmw/mwmechanics/spellcasting.hpp @@ -71,7 +71,7 @@ namespace MWMechanics bool mStack; std::string mId; // ID of spell, potion, item etc std::string mSourceName; // Display name for spell, potion, etc - Ogre::Vector3 mHitPosition; // Used for spawning area orb + osg::Vec3f mHitPosition; // Used for spawning area orb bool mAlwaysSucceed; // Always succeed spells casted by NPCs/creatures regardless of their chance (default: false) public: diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index c0e7a80b9..f97c5fd13 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -748,7 +748,7 @@ namespace MWPhysics const btCollisionObject* mMe; }; - PhysicsSystem::RayResult PhysicsSystem::castRay(const osg::Vec3f &from, const osg::Vec3f &to, MWWorld::Ptr ignore, int mask) + PhysicsSystem::RayResult PhysicsSystem::castRay(const osg::Vec3f &from, const osg::Vec3f &to, MWWorld::Ptr ignore, int mask, int group) { btVector3 btFrom = toBullet(from); btVector3 btTo = toBullet(to); @@ -762,7 +762,7 @@ namespace MWPhysics } ClosestNotMeRayResultCallback resultCallback(me, btFrom, btTo); - resultCallback.m_collisionFilterGroup = 0xff; + resultCallback.m_collisionFilterGroup = group; resultCallback.m_collisionFilterMask = mask; mCollisionWorld->rayTest(btFrom, btTo, resultCallback); @@ -860,6 +860,15 @@ namespace MWPhysics } } + osg::Vec3f PhysicsSystem::getHalfExtents(const MWWorld::Ptr &actor) + { + Actor* physactor = getActor(actor); + if (physactor) + return physactor->getHalfExtents(); + else + return osg::Vec3f(); + } + class ContactTestResultCallback : public btCollisionWorld::ContactResultCallback { public: @@ -1128,7 +1137,7 @@ namespace MWPhysics if (effects.get(ESM::MagicEffect::WaterWalking).getMagnitude() && cell->getCell()->hasWater() && !world->isUnderwater(iter->first.getCell(), - Ogre::Vector3(iter->first.getRefData().getPosition().pos))) + osg::Vec3f(iter->first.getRefData().getPosition().asVec3()))) waterCollision = true; ActorMap::iterator foundActor = mActors.find(iter->first); diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index d4f7e25b1..7e3c27951 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -99,7 +99,7 @@ namespace MWPhysics /// @param me Optional, a Ptr to ignore in the list of results RayResult castRay(const osg::Vec3f &from, const osg::Vec3f &to, MWWorld::Ptr ignore = MWWorld::Ptr(), int mask = - CollisionType_World|CollisionType_HeightMap|CollisionType_Actor); + CollisionType_World|CollisionType_HeightMap|CollisionType_Actor, int group=0xff); RayResult castSphere(const osg::Vec3f& from, const osg::Vec3f& to, float radius); @@ -108,6 +108,8 @@ namespace MWPhysics bool isOnGround (const MWWorld::Ptr& actor); + osg::Vec3f getHalfExtents(const MWWorld::Ptr& actor); + /// Queues velocity movement for a Ptr. If a Ptr is already queued, its velocity will /// be overwritten. Valid until the next call to applyQueuedMovement. void queueObjectMovement(const MWWorld::Ptr &ptr, const osg::Vec3f &velocity); diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index efdb49cf7..8580eb8f8 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -937,7 +937,7 @@ namespace MWScript MWWorld::Ptr target = MWBase::Environment::get().getWorld()->getPtr (targetId, false); MWMechanics::CastSpell cast(ptr, target); - cast.mHitPosition = Ogre::Vector3(target.getRefData().getPosition().pos); + cast.mHitPosition = target.getRefData().getPosition().asVec3(); cast.mAlwaysSucceed = true; cast.cast(spell); } @@ -955,7 +955,7 @@ namespace MWScript runtime.pop(); MWMechanics::CastSpell cast(ptr, ptr); - cast.mHitPosition = Ogre::Vector3(ptr.getRefData().getPosition().pos); + cast.mHitPosition = ptr.getRefData().getPosition().asVec3(); cast.mAlwaysSucceed = true; cast.cast(spell); } diff --git a/apps/openmw/mwworld/actiontrap.cpp b/apps/openmw/mwworld/actiontrap.cpp index d153b7e61..68d7c69e9 100644 --- a/apps/openmw/mwworld/actiontrap.cpp +++ b/apps/openmw/mwworld/actiontrap.cpp @@ -9,8 +9,8 @@ namespace MWWorld void ActionTrap::executeImp(const Ptr &actor) { - Ogre::Vector3 actorPosition(actor.getRefData().getPosition().pos); - Ogre::Vector3 trapPosition(mTrapSource.getRefData().getPosition().pos); + osg::Vec3f actorPosition(actor.getRefData().getPosition().asVec3()); + osg::Vec3f trapPosition(mTrapSource.getRefData().getPosition().asVec3()); float activationDistance = MWBase::Environment::get().getWorld()->getMaxActivationDistance(); // GUI calcs if object in activation distance include object and player geometry @@ -20,7 +20,7 @@ namespace MWWorld // to open door/container. // Note, can't just detonate the trap at the trapped object's location and use the blast // radius, because for most trap spells this is 1 foot, much less than the activation distance. - if (trapPosition.distance(actorPosition) < (activationDistance * fudgeFactor)) + if ((trapPosition - actorPosition).length() < (activationDistance * fudgeFactor)) { // assume actor touched trap MWMechanics::CastSpell cast(mTrapSource, actor); diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index acbe819f1..84d86fba7 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -1,11 +1,11 @@ #include "projectilemanager.hpp" -#include -#include - -#include +#include #include +#include +#include +#include #include "../mwworld/manualref.hpp" #include "../mwworld/class.hpp" @@ -22,72 +22,70 @@ #include "../mwrender/effectmanager.hpp" #include "../mwrender/animation.hpp" -#include "../mwrender/renderconst.hpp" +#include "../mwrender/vismask.hpp" #include "../mwsound/sound.hpp" +#include "../mwphysics/physicssystem.hpp" + + namespace MWWorld { - ProjectileManager::ProjectileManager(Ogre::SceneManager* sceneMgr, OEngine::Physic::PhysicEngine &engine) - : mPhysEngine(engine) - , mSceneMgr(sceneMgr) + ProjectileManager::ProjectileManager(osg::Group* parent, Resource::ResourceSystem* resourceSystem, MWPhysics::PhysicsSystem* physics) + : mParent(parent) + , mResourceSystem(resourceSystem) + , mPhysics(physics) { } void ProjectileManager::createModel(State &state, const std::string &model) { - state.mObject = NifOgre::Loader::createObjects(state.mNode, model); - for(size_t i = 0;i < state.mObject->mControllers.size();i++) - { - if(state.mObject->mControllers[i].getSource().isNull()) - state.mObject->mControllers[i].setSource(Ogre::SharedPtr (new MWRender::EffectAnimationTime())); - } + state.mNode = new osg::PositionAttitudeTransform; + state.mNode->setNodeMask(MWRender::Mask_Effect); + mParent->addChild(state.mNode); - MWRender::Animation::setRenderProperties(state.mObject, MWRender::RV_Effects, - MWRender::RQG_Main, MWRender::RQG_Alpha, 0.f, false, NULL); + mResourceSystem->getSceneManager()->createInstance(model, state.mNode); + + state.mEffectAnimationTime.reset(new MWRender::EffectAnimationTime); + + SceneUtil::AssignControllerSourcesVisitor assignVisitor (state.mEffectAnimationTime); + state.mNode->accept(assignVisitor); } - void ProjectileManager::update(NifOgre::ObjectScenePtr object, float duration) + void ProjectileManager::update(State& state, float duration) { - for(size_t i = 0; i < object->mControllers.size() ;i++) - { - MWRender::EffectAnimationTime* value = dynamic_cast(object->mControllers[i].getSource().get()); - if (value) - value->addTime(duration); - - object->mControllers[i].update(); - } + state.mEffectAnimationTime->addTime(duration); } void ProjectileManager::launchMagicBolt(const std::string &model, const std::string &sound, const std::string &spellId, float speed, bool stack, const ESM::EffectList &effects, const Ptr &caster, const std::string &sourceName, - const Ogre::Vector3& fallbackDirection) + const osg::Vec3f& fallbackDirection) { float height = 0; - if (OEngine::Physic::PhysicActor* actor = mPhysEngine.getCharacter(caster.getRefData().getHandle())) - height = actor->getHalfExtents().z * 2 * 0.75f; // Spawn at 0.75 * ActorHeight - Ogre::Vector3 pos(caster.getRefData().getPosition().pos); - pos.z += height; + height += mPhysics->getHalfExtents(caster).z() * 2.f * 0.75f; // Spawn at 0.75 * ActorHeight + + osg::Vec3f pos(caster.getRefData().getPosition().asVec3()); + pos.z() += height; if (MWBase::Environment::get().getWorld()->isUnderwater(caster.getCell(), pos)) // Underwater casting not possible return; - Ogre::Quaternion orient; + osg::Quat orient; if (caster.getClass().isActor()) - orient = Ogre::Quaternion(Ogre::Radian(caster.getRefData().getPosition().rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z) * - Ogre::Quaternion(Ogre::Radian(caster.getRefData().getPosition().rot[0]), Ogre::Vector3::NEGATIVE_UNIT_X); + orient = osg::Quat(caster.getRefData().getPosition().rot[0], osg::Vec3f(-1,0,0)) + * osg::Quat(caster.getRefData().getPosition().rot[2], osg::Vec3f(0,0,-1)); else - orient = Ogre::Vector3::UNIT_Y.getRotationTo(fallbackDirection); + orient.makeRotate(osg::Vec3f(0,1,0), osg::Vec3f(fallbackDirection)); MagicBoltState state; state.mSourceName = sourceName; state.mId = model; state.mSpellId = spellId; - state.mCasterHandle = caster.getRefData().getHandle(); + state.mCasterHandle = caster; if (caster.getClass().isActor()) state.mActorId = caster.getClass().getCreatureStats(caster).getActorId(); else @@ -107,8 +105,9 @@ namespace MWWorld MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), model); MWWorld::Ptr ptr = ref.getPtr(); - state.mNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(pos, orient); createModel(state, ptr.getClass().getModel(ptr)); + state.mNode->setPosition(pos); + state.mNode->setAttitude(orient); MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); state.mSound = sndMgr->playManualSound3D(pos, sound, 1.0f, 1.0f, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_Loop); @@ -116,20 +115,21 @@ namespace MWWorld mMagicBolts.push_back(state); } - void ProjectileManager::launchProjectile(Ptr actor, Ptr projectile, const Ogre::Vector3 &pos, - const Ogre::Quaternion &orient, Ptr bow, float speed) + void ProjectileManager::launchProjectile(Ptr actor, Ptr projectile, const osg::Vec3f &pos, const osg::Quat &orient, Ptr bow, float speed) { ProjectileState state; state.mActorId = actor.getClass().getCreatureStats(actor).getActorId(); state.mBowId = bow.getCellRef().getRefId(); - state.mVelocity = orient.yAxis() * speed; + state.mVelocity = orient * osg::Vec3f(0,1,0) * speed; state.mId = projectile.getCellRef().getRefId(); + state.mCasterHandle = actor; MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), projectile.getCellRef().getRefId()); MWWorld::Ptr ptr = ref.getPtr(); - state.mNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(pos, orient); createModel(state, ptr.getClass().getModel(ptr)); + state.mNode->setPosition(pos); + state.mNode->setAttitude(orient); mProjectiles.push_back(state); } @@ -144,60 +144,46 @@ namespace MWWorld { for (std::vector::iterator it = mMagicBolts.begin(); it != mMagicBolts.end();) { - Ogre::Quaternion orient = it->mNode->getOrientation(); + osg::Quat orient = it->mNode->getAttitude(); static float fTargetSpellMaxSpeed = MWBase::Environment::get().getWorld()->getStore().get() .find("fTargetSpellMaxSpeed")->getFloat(); float speed = fTargetSpellMaxSpeed * it->mSpeed; - Ogre::Vector3 direction = orient.yAxis(); - direction.normalise(); - Ogre::Vector3 pos(it->mNode->getPosition()); - Ogre::Vector3 newPos = pos + direction * duration * speed; + osg::Vec3f direction = orient * osg::Vec3f(0,1,0); + direction.normalize(); + osg::Vec3f pos(it->mNode->getPosition()); + osg::Vec3f newPos = pos + direction * duration * speed; if (it->mSound.get()) it->mSound->setPosition(newPos); it->mNode->setPosition(newPos); - update(it->mObject, duration); + update(*it, duration); + + MWWorld::Ptr caster = it->getCaster(); // Check for impact // TODO: use a proper btRigidBody / btGhostObject? - btVector3 from(pos.x, pos.y, pos.z); - btVector3 to(newPos.x, newPos.y, newPos.z); - - std::vector > collisions = mPhysEngine.rayTest2(from, to, OEngine::Physic::CollisionType_Projectile); - bool hit=false; + MWPhysics::PhysicsSystem::RayResult result = mPhysics->castRay(pos, newPos, caster, 0xff, MWPhysics::CollisionType_Projectile); - for (std::vector >::iterator cIt = collisions.begin(); cIt != collisions.end() && !hit; ++cIt) + bool hit = false; + if (result.mHit) { - MWWorld::Ptr obstacle = MWBase::Environment::get().getWorld()->searchPtrViaHandle(cIt->second); - - MWWorld::Ptr caster = MWBase::Environment::get().getWorld()->searchPtrViaHandle(it->mCasterHandle); - if (caster.isEmpty()) - caster = MWBase::Environment::get().getWorld()->searchPtrViaActorId(it->mActorId); - - if (!obstacle.isEmpty() && obstacle == caster) - continue; - - if (caster.isEmpty()) - caster = obstacle; - - if (obstacle.isEmpty()) + hit = true; + if (result.mHitObject.isEmpty()) { - // Terrain + // terrain } else { - MWMechanics::CastSpell cast(caster, obstacle); + MWMechanics::CastSpell cast(caster, result.mHitObject); cast.mHitPosition = pos; cast.mId = it->mSpellId; cast.mSourceName = it->mSourceName; cast.mStack = it->mStack; - cast.inflict(obstacle, caster, it->mEffects, ESM::RT_Target, false, true); + cast.inflict(result.mHitObject, caster, it->mEffects, ESM::RT_Target, false, true); } - - hit = true; } // Explodes when hitting water @@ -206,12 +192,11 @@ namespace MWWorld if (hit) { - MWWorld::Ptr caster = MWBase::Environment::get().getWorld()->searchPtrViaActorId(it->mActorId); MWBase::Environment::get().getWorld()->explodeSpell(pos, it->mEffects, caster, ESM::RT_Target, it->mSpellId, it->mSourceName); MWBase::Environment::get().getSoundManager()->stopSound(it->mSound); - mSceneMgr->destroySceneNode(it->mNode); + mParent->removeChild(it->mNode); it = mMagicBolts.erase(it); continue; @@ -227,34 +212,26 @@ namespace MWWorld { // gravity constant - must be way lower than the gravity affecting actors, since we're not // simulating aerodynamics at all - it->mVelocity -= Ogre::Vector3(0, 0, 627.2f * 0.1f) * duration; + it->mVelocity -= osg::Vec3f(0, 0, 627.2f * 0.1f) * duration; - Ogre::Vector3 pos(it->mNode->getPosition()); - Ogre::Vector3 newPos = pos + it->mVelocity * duration; + osg::Vec3f pos(it->mNode->getPosition()); + osg::Vec3f newPos = pos + it->mVelocity * duration; - Ogre::Quaternion orient = Ogre::Vector3::UNIT_Y.getRotationTo(it->mVelocity); - it->mNode->setOrientation(orient); + osg::Quat orient; + orient.makeRotate(osg::Vec3f(0,1,0), it->mVelocity); + it->mNode->setAttitude(orient); it->mNode->setPosition(newPos); - update(it->mObject, duration); + update(*it, duration); + + MWWorld::Ptr caster = it->getCaster(); // Check for impact // TODO: use a proper btRigidBody / btGhostObject? - btVector3 from(pos.x, pos.y, pos.z); - btVector3 to(newPos.x, newPos.y, newPos.z); - std::vector > collisions = mPhysEngine.rayTest2(from, to, OEngine::Physic::CollisionType_Projectile); - bool hit=false; + MWPhysics::PhysicsSystem::RayResult result = mPhysics->castRay(pos, newPos, caster, 0xff, MWPhysics::CollisionType_Projectile); - for (std::vector >::iterator cIt = collisions.begin(); cIt != collisions.end() && !hit; ++cIt) + if (result.mHit) { - MWWorld::Ptr obstacle = MWBase::Environment::get().getWorld()->searchPtrViaHandle(cIt->second); - - MWWorld::Ptr caster = MWBase::Environment::get().getWorld()->searchPtrViaActorId(it->mActorId); - - // Arrow intersects with player immediately after shooting :/ - if (obstacle == caster) - continue; - MWWorld::ManualRef projectileRef(MWBase::Environment::get().getWorld()->getStore(), it->mId); // Try to get a Ptr to the bow that was used. It might no longer exist. @@ -268,15 +245,11 @@ namespace MWWorld } if (caster.isEmpty()) - caster = obstacle; + caster = result.mHitObject; - MWMechanics::projectileHit(caster, obstacle, bow, projectileRef.getPtr(), pos + (newPos - pos) * cIt->first); + MWMechanics::projectileHit(caster, result.mHitObject, bow, projectileRef.getPtr(), result.mHitPos); - hit = true; - } - if (hit) - { - mSceneMgr->destroySceneNode(it->mNode); + mParent->removeChild(it->mNode); it = mProjectiles.erase(it); continue; @@ -290,13 +263,13 @@ namespace MWWorld { for (std::vector::iterator it = mProjectiles.begin(); it != mProjectiles.end(); ++it) { - mSceneMgr->destroySceneNode(it->mNode); + mParent->removeChild(it->mNode); } mProjectiles.clear(); for (std::vector::iterator it = mMagicBolts.begin(); it != mMagicBolts.end(); ++it) { + mParent->removeChild(it->mNode); MWBase::Environment::get().getSoundManager()->stopSound(it->mSound); - mSceneMgr->destroySceneNode(it->mNode); } mMagicBolts.clear(); } @@ -309,8 +282,8 @@ namespace MWWorld ESM::ProjectileState state; state.mId = it->mId; - state.mPosition = it->mNode->getPosition(); - state.mOrientation = it->mNode->getOrientation(); + state.mPosition = ESM::Vector3(osg::Vec3f(it->mNode->getPosition())); + state.mOrientation = ESM::Quaternion(osg::Quat(it->mNode->getAttitude())); state.mActorId = it->mActorId; state.mBowId = it->mBowId; @@ -327,8 +300,8 @@ namespace MWWorld ESM::MagicBoltState state; state.mId = it->mId; - state.mPosition = it->mNode->getPosition(); - state.mOrientation = it->mNode->getOrientation(); + state.mPosition = ESM::Vector3(osg::Vec3f(it->mNode->getPosition())); + state.mOrientation = ESM::Quaternion(osg::Quat(it->mNode->getAttitude())); state.mActorId = it->mActorId; state.mSpellId = it->mSpellId; @@ -369,8 +342,9 @@ namespace MWWorld return true; } - state.mNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(esm.mPosition, esm.mOrientation); createModel(state, model); + state.mNode->setPosition(osg::Vec3f(esm.mPosition)); + state.mNode->setAttitude(osg::Quat(esm.mOrientation)); mProjectiles.push_back(state); return true; @@ -401,8 +375,9 @@ namespace MWWorld return true; } - state.mNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(esm.mPosition, esm.mOrientation); createModel(state, model); + state.mNode->setPosition(osg::Vec3f(esm.mPosition)); + state.mNode->setAttitude(osg::Quat(esm.mOrientation)); MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); state.mSound = sndMgr->playManualSound3D(esm.mPosition, esm.mSound, 1.0f, 1.0f, @@ -421,4 +396,12 @@ namespace MWWorld return mMagicBolts.size() + mProjectiles.size(); } + MWWorld::Ptr ProjectileManager::State::getCaster() + { + if (!mCasterHandle.isEmpty()) + return mCasterHandle; + + return MWBase::Environment::get().getWorld()->searchPtrViaActorId(mActorId); + } + } diff --git a/apps/openmw/mwworld/projectilemanager.hpp b/apps/openmw/mwworld/projectilemanager.hpp index f46f544d2..f42bc040f 100644 --- a/apps/openmw/mwworld/projectilemanager.hpp +++ b/apps/openmw/mwworld/projectilemanager.hpp @@ -3,7 +3,7 @@ #include -#include +#include #include @@ -21,9 +21,20 @@ namespace Loading class Listener; } -namespace Ogre +namespace osg { - class SceneManager; + class Group; + class Quat; +} + +namespace Resource +{ + class ResourceSystem; +} + +namespace MWRender +{ + class EffectAnimationTime; } namespace MWWorld @@ -32,16 +43,16 @@ namespace MWWorld class ProjectileManager { public: - ProjectileManager (Ogre::SceneManager* sceneMgr, - OEngine::Physic::PhysicEngine& engine); + ProjectileManager (osg::Group* parent, Resource::ResourceSystem* resourceSystem, + MWPhysics::PhysicsSystem* physics); /// If caster is an actor, the actor's facing orientation is used. Otherwise fallbackDirection is used. void launchMagicBolt (const std::string& model, const std::string &sound, const std::string &spellId, float speed, bool stack, const ESM::EffectList& effects, - const MWWorld::Ptr& caster, const std::string& sourceName, const Ogre::Vector3& fallbackDirection); + const MWWorld::Ptr& caster, const std::string& sourceName, const osg::Vec3f& fallbackDirection); void launchProjectile (MWWorld::Ptr actor, MWWorld::Ptr projectile, - const Ogre::Vector3& pos, const Ogre::Quaternion& orient, MWWorld::Ptr bow, float speed); + const osg::Vec3f& pos, const osg::Quat& orient, MWWorld::Ptr bow, float speed); void update(float dt); @@ -53,22 +64,22 @@ namespace MWWorld int countSavedGameRecords() const; private: - OEngine::Physic::PhysicEngine& mPhysEngine; - Ogre::SceneManager* mSceneMgr; + osg::ref_ptr mParent; + Resource::ResourceSystem* mResourceSystem; + MWPhysics::PhysicsSystem* mPhysics; struct State { - NifOgre::ObjectScenePtr mObject; - Ogre::SceneNode* mNode; + osg::ref_ptr mNode; + boost::shared_ptr mEffectAnimationTime; int mActorId; - // actorId doesn't work for non-actors, so we also keep track of the Ogre-handle. - // For non-actors, the caster ptr is mainly needed to prevent the projectile - // from colliding with its caster. // TODO: this will break when the game is saved and reloaded, since there is currently // no way to write identifiers for non-actors to a savegame. - std::string mCasterHandle; + MWWorld::Ptr mCasterHandle; + + MWWorld::Ptr getCaster(); // MW-id of this projectile std::string mId; @@ -96,7 +107,7 @@ namespace MWWorld // RefID of the bow or crossbow the actor was using when this projectile was fired (may be empty) std::string mBowId; - Ogre::Vector3 mVelocity; + osg::Vec3f mVelocity; }; std::vector mMagicBolts; @@ -106,7 +117,7 @@ namespace MWWorld void moveMagicBolts(float dt); void createModel (State& state, const std::string& model); - void update (NifOgre::ObjectScenePtr object, float duration); + void update (State& state, float duration); }; } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 2f47c19e6..126267fd4 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -54,7 +54,7 @@ #include "containerstore.hpp" #include "inventorystore.hpp" #include "actionteleport.hpp" -//#include "projectilemanager.hpp" +#include "projectilemanager.hpp" #include "weather.hpp" #include "contentloader.hpp" @@ -159,9 +159,7 @@ namespace MWWorld mLevitationEnabled(true), mGoToJail(false), mDaysInPrison(0) { mPhysics = new MWPhysics::PhysicsSystem(resourceSystem, rootNode); -#if 0 - mProjectileManager.reset(new ProjectileManager(renderer.getScene(), *mPhysEngine)); -#endif + mProjectileManager.reset(new ProjectileManager(rootNode, resourceSystem, mPhysics)); mRendering = new MWRender::RenderingManager(viewer, rootNode, resourceSystem); mWeatherManager = new MWWorld::WeatherManager(mRendering,&mFallback); @@ -276,9 +274,7 @@ namespace MWWorld { mWeatherManager->clear(); mRendering->clear(); -#if 0 mProjectileManager->clear(); -#endif mLocalScripts.clear(); mWorldScene->changeToVoid(); @@ -313,9 +309,7 @@ namespace MWWorld mCells.countSavedGameRecords() +mStore.countSavedGameRecords() +mGlobalVariables.countSavedGameRecords() - #if 0 +mProjectileManager->countSavedGameRecords() - #endif +1 // player record +1 // weather record +1 // actorId counter @@ -346,9 +340,8 @@ namespace MWWorld mGlobalVariables.write (writer, progress); mPlayer->write (writer, progress); mWeatherManager->write (writer, progress); -#if 0 mProjectileManager->write (writer, progress); -#endif + writer.startRecord(ESM::REC_ENAB); writer.writeHNT("TELE", mTeleportEnabled); writer.writeHNT("LEVT", mLevitationEnabled); @@ -377,9 +370,7 @@ namespace MWWorld !mPlayer->readRecord (reader, type) && !mWeatherManager->readRecord (reader, type) && !mCells.readRecord (reader, type, contentFileMap) - #if 0 && !mProjectileManager->readRecord (reader, type) - #endif ) { throw std::runtime_error ("unknown record in saved game"); @@ -472,10 +463,8 @@ namespace MWWorld World::~World() { -#if 0 // Must be cleared before mRendering is destroyed mProjectileManager->clear(); -#endif delete mWeatherManager; delete mWorldScene; delete mRendering; @@ -970,9 +959,7 @@ namespace MWWorld if (mCurrentWorldSpace != cellName) { // changed worldspace -#if 0 mProjectileManager->clear(); -#endif mRendering->notifyWorldSpaceChanged(); mCurrentWorldSpace = cellName; @@ -990,9 +977,7 @@ namespace MWWorld if (mCurrentWorldSpace != "sys::default") // FIXME { // changed worldspace -#if 0 mProjectileManager->clear(); -#endif mRendering->notifyWorldSpaceChanged(); } removeContainerScripts(getPlayerPtr()); @@ -1388,7 +1373,7 @@ namespace MWWorld mPhysics->stepSimulation(duration); processDoors(duration); - //mProjectileManager->update(duration); + mProjectileManager->update(duration); const MWPhysics::PtrVelocityList &results = mPhysics->applyQueuedMovement(duration); MWPhysics::PtrVelocityList::const_iterator player(results.end()); @@ -1637,9 +1622,7 @@ namespace MWWorld const ESM::Position& refpos = getPlayerPtr().getRefData().getPosition(); osg::Vec3f playerPos = refpos.asVec3(); - const MWPhysics::Actor* actor = mPhysics->getActor(getPlayerPtr()); - if (actor) - playerPos.z() += 1.85f * actor->getHalfExtents().z(); + playerPos.z() += 1.85f * mPhysics->getHalfExtents(getPlayerPtr()).z(); osg::Quat playerOrient = osg::Quat(refpos.rot[1], osg::Vec3f(0,-1,0)) * osg::Quat(refpos.rot[0], osg::Vec3f(-1,0,0)) * @@ -2015,24 +1998,19 @@ namespace MWWorld bool World::isUnderwater(const MWWorld::Ptr &object, const float heightRatio) const { - const float *fpos = object.getRefData().getPosition().pos; - Ogre::Vector3 pos(fpos[0], fpos[1], fpos[2]); + osg::Vec3f pos (object.getRefData().getPosition().asVec3()); - const MWPhysics::Actor* actor = mPhysics->getActor(object); - if (actor) - { - pos.z += heightRatio*2*actor->getHalfExtents().z(); - } + pos.z() += heightRatio*2*mPhysics->getHalfExtents(object).z(); return isUnderwater(object.getCell(), pos); } - bool World::isUnderwater(const MWWorld::CellStore* cell, const Ogre::Vector3 &pos) const + bool World::isUnderwater(const MWWorld::CellStore* cell, const osg::Vec3f &pos) const { if (!(cell->getCell()->mData.mFlags & ESM::Cell::HasWater)) { return false; } - return pos.z < cell->getWaterLevel(); + return pos.z() < cell->getWaterLevel(); } bool World::isOnGround(const MWWorld::Ptr &ptr) const @@ -2125,7 +2103,7 @@ namespace MWWorld Ptr player = mPlayer->getPlayer(); RefData &refdata = player.getRefData(); - Ogre::Vector3 playerPos(refdata.getPosition().pos); + osg::Vec3f playerPos(refdata.getPosition().asVec3()); const MWPhysics::Actor* actor = mPhysics->getActor(player); if (!actor) @@ -2519,7 +2497,7 @@ namespace MWWorld // Witnesses of the player's transformation will make them a globally known werewolf std::vector closeActors; - MWBase::Environment::get().getMechanicsManager()->getActorsInRange(Ogre::Vector3(actor.getRefData().getPosition().pos), + MWBase::Environment::get().getMechanicsManager()->getActorsInRange(actor.getRefData().getPosition().asVec3(), getStore().get().search("fAlarmRadius")->getFloat(), closeActors); @@ -2695,7 +2673,7 @@ namespace MWWorld MWMechanics::CastSpell cast(actor, target); if (!target.isEmpty()) - cast.mHitPosition = Ogre::Vector3(target.getRefData().getPosition().pos); + cast.mHitPosition = target.getRefData().getPosition().asVec3(); if (!selectedSpell.empty()) { @@ -2718,18 +2696,14 @@ namespace MWWorld void World::launchProjectile (MWWorld::Ptr actor, MWWorld::Ptr projectile, const osg::Vec3f& worldPos, const osg::Quat& orient, MWWorld::Ptr bow, float speed) { -#if 0 mProjectileManager->launchProjectile(actor, projectile, worldPos, orient, bow, speed); -#endif } void World::launchMagicBolt (const std::string& model, const std::string &sound, const std::string &spellId, float speed, bool stack, const ESM::EffectList& effects, - const MWWorld::Ptr& caster, const std::string& sourceName, const Ogre::Vector3& fallbackDirection) + const MWWorld::Ptr& caster, const std::string& sourceName, const osg::Vec3f& fallbackDirection) { -#if 0 mProjectileManager->launchMagicBolt(model, sound, spellId, speed, stack, effects, caster, sourceName, fallbackDirection); -#endif } const std::vector& World::getContentFiles() const @@ -3181,7 +3155,7 @@ namespace MWWorld mRendering->spawnEffect(model, textureOverride, worldPos); } - void World::explodeSpell(const Ogre::Vector3 &origin, const ESM::EffectList &effects, const Ptr &caster, ESM::RangeType rangeType, + void World::explodeSpell(const osg::Vec3f &origin, const ESM::EffectList &effects, const Ptr &caster, ESM::RangeType rangeType, const std::string& id, const std::string& sourceName) { std::map > toApply; @@ -3200,7 +3174,7 @@ namespace MWWorld else areaStatic = getStore().get().find ("VFX_DefaultArea"); - mRendering->spawnEffect("meshes\\" + areaStatic->mModel, "", osg::Vec3f(origin.x, origin.y, origin.z), static_cast(effectIt->mArea)); + mRendering->spawnEffect("meshes\\" + areaStatic->mModel, "", origin, static_cast(effectIt->mArea)); // Play explosion sound (make sure to use NoTrack, since we will delete the projectile now) static const std::string schools[] = { @@ -3209,9 +3183,9 @@ namespace MWWorld { MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); if(!effect->mAreaSound.empty()) - sndMgr->playManualSound3D(osg::Vec3f(origin.x, origin.y, origin.z), effect->mAreaSound, 1.0f, 1.0f, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_NoTrack); + sndMgr->playManualSound3D(origin, effect->mAreaSound, 1.0f, 1.0f, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_NoTrack); else - sndMgr->playManualSound3D(osg::Vec3f(origin.x, origin.y, origin.z), schools[effect->mData.mSchool]+" area", 1.0f, 1.0f, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_NoTrack); + sndMgr->playManualSound3D(origin, schools[effect->mData.mSchool]+" area", 1.0f, 1.0f, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_NoTrack); } // Get the actors in range of the effect std::vector objects; diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index b1718f030..4c4df2c99 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -455,7 +455,7 @@ namespace MWWorld ///Is the head of the creature underwater? virtual bool isSubmerged(const MWWorld::Ptr &object) const; virtual bool isSwimming(const MWWorld::Ptr &object) const; - virtual bool isUnderwater(const MWWorld::CellStore* cell, const Ogre::Vector3 &pos) const; + virtual bool isUnderwater(const MWWorld::CellStore* cell, const osg::Vec3f &pos) const; virtual bool isWading(const MWWorld::Ptr &object) const; virtual bool isOnGround(const MWWorld::Ptr &ptr) const; @@ -572,7 +572,7 @@ namespace MWWorld virtual void launchMagicBolt (const std::string& model, const std::string& sound, const std::string& spellId, float speed, bool stack, const ESM::EffectList& effects, - const MWWorld::Ptr& caster, const std::string& sourceName, const Ogre::Vector3& fallbackDirection); + const MWWorld::Ptr& caster, const std::string& sourceName, const osg::Vec3f& fallbackDirection); virtual void launchProjectile (MWWorld::Ptr actor, MWWorld::Ptr projectile, const osg::Vec3f& worldPos, const osg::Quat& orient, MWWorld::Ptr bow, float speed); @@ -613,7 +613,7 @@ namespace MWWorld virtual void spawnEffect (const std::string& model, const std::string& textureOverride, const osg::Vec3f& worldPos); - virtual void explodeSpell (const Ogre::Vector3& origin, const ESM::EffectList& effects, + virtual void explodeSpell (const osg::Vec3f& origin, const ESM::EffectList& effects, const MWWorld::Ptr& caster, ESM::RangeType rangeType, const std::string& id, const std::string& sourceName); virtual void activate (const MWWorld::Ptr& object, const MWWorld::Ptr& actor); diff --git a/components/esm/projectilestate.hpp b/components/esm/projectilestate.hpp index 51cd5d8c4..38429e459 100644 --- a/components/esm/projectilestate.hpp +++ b/components/esm/projectilestate.hpp @@ -3,8 +3,8 @@ #include -#include -#include +#include +#include #include "effectlist.hpp" diff --git a/components/esm/util.hpp b/components/esm/util.hpp index bb7f3cf7c..07a7655c7 100644 --- a/components/esm/util.hpp +++ b/components/esm/util.hpp @@ -4,6 +4,9 @@ #include #include +#include +#include + namespace ESM { @@ -21,11 +24,23 @@ struct Quaternion mValues[2] = q.y; mValues[3] = q.z; } + Quaternion(const osg::Quat& q) + { + mValues[0] = q.w(); + mValues[1] = q.x(); + mValues[2] = q.y(); + mValues[3] = q.z(); + } operator Ogre::Quaternion () const { return Ogre::Quaternion(mValues[0], mValues[1], mValues[2], mValues[3]); } + + operator osg::Quat () const + { + return osg::Quat(mValues[1], mValues[2], mValues[3], mValues[0]); + } }; struct Vector3 @@ -39,11 +54,22 @@ struct Vector3 mValues[1] = v.y; mValues[2] = v.z; } + Vector3(const osg::Vec3f& v) + { + mValues[0] = v.x(); + mValues[1] = v.y(); + mValues[2] = v.z(); + } operator Ogre::Vector3 () const { return Ogre::Vector3(&mValues[0]); } + + operator osg::Vec3f () const + { + return osg::Vec3f(mValues[0], mValues[1], mValues[2]); + } }; } From 5350ce59efec0beee86f0637e5f6412631e31b79 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Mon, 1 Jun 2015 22:42:41 +0300 Subject: [PATCH 1355/3725] MWList doesn't scroll to the very bottom when it's shown for first time --- components/widgets/list.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/widgets/list.cpp b/components/widgets/list.cpp index e1d80f022..535a3cad3 100644 --- a/components/widgets/list.cpp +++ b/components/widgets/list.cpp @@ -48,7 +48,7 @@ namespace Gui const int _scrollBarWidth = 20; // fetch this from skin? const int scrollBarWidth = scrollbarShown ? _scrollBarWidth : 0; const int spacing = 3; - size_t viewPosition = -mScrollView->getViewOffset().top; + int viewPosition = mScrollView->getViewOffset().top; while (mScrollView->getChildCount()) { @@ -99,10 +99,10 @@ namespace Gui if (!scrollbarShown && mItemHeight > mClient->getSize().height) redraw(true); - size_t viewRange = mScrollView->getCanvasSize().height; + int viewRange = mScrollView->getCanvasSize().height; if(viewPosition > viewRange) viewPosition = viewRange; - mScrollView->setViewOffset(MyGUI::IntPoint(0, viewPosition * -1)); + mScrollView->setViewOffset(MyGUI::IntPoint(0, viewPosition)); } void MWList::setPropertyOverride(const std::string &_key, const std::string &_value) From 959fe3eb8773be66219575ae161e625f03536f69 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Mon, 1 Jun 2015 23:49:40 +0300 Subject: [PATCH 1356/3725] Reset the scrollbar position in the topic list when DialogueWindow is closed --- apps/openmw/mwgui/dialogue.cpp | 5 +++-- components/widgets/list.cpp | 2 +- components/widgets/list.hpp | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 48b9be17d..0cb0475c9 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -291,7 +291,10 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_MainMenu); } else + { MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); + mTopicsList->scrollToTop(); + } } void DialogueWindow::onWindowResize(MyGUI::Window* _sender) @@ -364,7 +367,6 @@ namespace MWGui bool sameActor = (mPtr == actor); mPtr = actor; mTopicsList->setEnabled(true); - mTopicsList->scrollToFirstItem(); setTitle(npcName); clearChoices(); @@ -456,7 +458,6 @@ namespace MWGui mKeywordSearch.seed(Misc::StringUtils::lowerCase(*it), intptr_t(t)); } mTopicsList->adjustSize(); - mTopicsList->scrollToFirstItem(); updateHistory(); } diff --git a/components/widgets/list.cpp b/components/widgets/list.cpp index 535a3cad3..db4092b3f 100644 --- a/components/widgets/list.cpp +++ b/components/widgets/list.cpp @@ -157,7 +157,7 @@ namespace Gui return mScrollView->findWidget (getName() + "_item_" + name)->castType(); } - void MWList::scrollToFirstItem() + void MWList::scrollToTop() { mScrollView->setViewOffset(MyGUI::IntPoint(0, 0)); } diff --git a/components/widgets/list.hpp b/components/widgets/list.hpp index 1c24af6a4..3efe1ff75 100644 --- a/components/widgets/list.hpp +++ b/components/widgets/list.hpp @@ -46,7 +46,7 @@ namespace Gui MyGUI::Button* getItemWidget(const std::string& name); ///< get widget for an item name, useful to set up tooltip - void scrollToFirstItem(); + void scrollToTop(); virtual void setPropertyOverride(const std::string& _key, const std::string& _value); From 2c4025ec72dfd021a9252536c2385672b74e39a5 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Tue, 2 Jun 2015 00:26:31 +0300 Subject: [PATCH 1357/3725] Rename the method isCompleterExistFor() to hasCompleterFor() --- apps/opencs/model/world/idcompletionmanager.cpp | 4 ++-- apps/opencs/model/world/idcompletionmanager.hpp | 2 +- apps/opencs/view/world/idcompletiondelegate.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/opencs/model/world/idcompletionmanager.cpp b/apps/opencs/model/world/idcompletionmanager.cpp index ff5ec6b4b..6736e9477 100644 --- a/apps/opencs/model/world/idcompletionmanager.cpp +++ b/apps/opencs/model/world/idcompletionmanager.cpp @@ -89,14 +89,14 @@ CSMWorld::IdCompletionManager::IdCompletionManager(CSMWorld::Data &data) generateCompleters(data); } -bool CSMWorld::IdCompletionManager::isCompleterExistFor(CSMWorld::Columns::ColumnId id) const +bool CSMWorld::IdCompletionManager::hasCompleterFor(CSMWorld::Columns::ColumnId id) const { return mCompleters.find(id) != mCompleters.end(); } boost::shared_ptr CSMWorld::IdCompletionManager::getCompleter(CSMWorld::Columns::ColumnId id) { - if (!isCompleterExistFor(id)) + if (!hasCompleterFor(id)) { throw std::logic_error("This column doesn't have an ID completer"); } diff --git a/apps/opencs/model/world/idcompletionmanager.hpp b/apps/opencs/model/world/idcompletionmanager.hpp index fff9868ea..ee75ddf24 100644 --- a/apps/opencs/model/world/idcompletionmanager.hpp +++ b/apps/opencs/model/world/idcompletionmanager.hpp @@ -30,7 +30,7 @@ namespace CSMWorld public: IdCompletionManager(CSMWorld::Data &data); - bool isCompleterExistFor(CSMWorld::Columns::ColumnId id) const; + bool hasCompleterFor(CSMWorld::Columns::ColumnId id) const; boost::shared_ptr getCompleter(CSMWorld::Columns::ColumnId id); }; } diff --git a/apps/opencs/view/world/idcompletiondelegate.cpp b/apps/opencs/view/world/idcompletiondelegate.cpp index 33e1282d4..2a1e97f4b 100644 --- a/apps/opencs/view/world/idcompletiondelegate.cpp +++ b/apps/opencs/view/world/idcompletiondelegate.cpp @@ -26,7 +26,7 @@ QWidget *CSVWorld::IdCompletionDelegate::createEditor(QWidget *parent, QWidget *editor = CSVWorld::CommandDelegate::createEditor(parent, option, index, display); QLineEdit *lineEditor = qobject_cast(editor); - if (lineEditor != NULL && completionManager.isCompleterExistFor(columnId)) + if (lineEditor != NULL && completionManager.hasCompleterFor(columnId)) { lineEditor->setCompleter(completionManager.getCompleter(columnId).get()); } From 6cb221f8d09cce21ccdba5cae6e3fac0f0e49b1b Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Tue, 2 Jun 2015 11:55:09 +0300 Subject: [PATCH 1358/3725] Some minor changes to MWList --- components/widgets/list.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/widgets/list.cpp b/components/widgets/list.cpp index db4092b3f..df7e7d61d 100644 --- a/components/widgets/list.cpp +++ b/components/widgets/list.cpp @@ -48,7 +48,7 @@ namespace Gui const int _scrollBarWidth = 20; // fetch this from skin? const int scrollBarWidth = scrollbarShown ? _scrollBarWidth : 0; const int spacing = 3; - int viewPosition = mScrollView->getViewOffset().top; + int viewPosition = -mScrollView->getViewOffset().top; while (mScrollView->getChildCount()) { @@ -102,7 +102,7 @@ namespace Gui int viewRange = mScrollView->getCanvasSize().height; if(viewPosition > viewRange) viewPosition = viewRange; - mScrollView->setViewOffset(MyGUI::IntPoint(0, viewPosition)); + mScrollView->setViewOffset(MyGUI::IntPoint(0, -viewPosition)); } void MWList::setPropertyOverride(const std::string &_key, const std::string &_value) From ee2763f2d4286bd63e15a72aa96424763146a5f4 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 2 Jun 2015 14:43:38 +0200 Subject: [PATCH 1359/3725] Allow 5th parameter for PlaceAtMe (numeric value, ignored) (Fixes #2591) --- components/compiler/extensions0.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/compiler/extensions0.cpp b/components/compiler/extensions0.cpp index c56ee2ffb..a16e653c3 100644 --- a/components/compiler/extensions0.cpp +++ b/components/compiler/extensions0.cpp @@ -531,7 +531,7 @@ namespace Compiler extensions.registerInstruction("placeitemcell","ccffff",opcodePlaceItemCell); extensions.registerInstruction("placeitem","cffff",opcodePlaceItem); extensions.registerInstruction("placeatpc","clfl",opcodePlaceAtPc); - extensions.registerInstruction("placeatme","clfl",opcodePlaceAtMe,opcodePlaceAtMeExplicit); + extensions.registerInstruction("placeatme","clflX",opcodePlaceAtMe,opcodePlaceAtMeExplicit); extensions.registerInstruction("modscale","f",opcodeModScale,opcodeModScaleExplicit); extensions.registerInstruction("rotate","cf",opcodeRotate,opcodeRotateExplicit); extensions.registerInstruction("rotateworld","cf",opcodeRotateWorld,opcodeRotateWorldExplicit); From 01944c33f5a28eb2c64188f9e9259c0cf3b9b780 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 2 Jun 2015 16:35:35 +0200 Subject: [PATCH 1360/3725] Basic water rendering --- apps/openmw/CMakeLists.txt | 4 +- apps/openmw/mwrender/localmap.cpp | 2 +- apps/openmw/mwrender/refraction.cpp | 110 ----- apps/openmw/mwrender/refraction.hpp | 45 -- apps/openmw/mwrender/renderingmanager.cpp | 63 ++- apps/openmw/mwrender/renderingmanager.hpp | 8 + apps/openmw/mwrender/rendermode.hpp | 4 +- apps/openmw/mwrender/vismask.hpp | 7 +- apps/openmw/mwrender/water.cpp | 549 +++++----------------- apps/openmw/mwrender/water.hpp | 171 +------ apps/openmw/mwworld/scene.cpp | 4 +- apps/openmw/mwworld/worldimp.cpp | 6 +- components/nifosg/controller.cpp | 7 + components/nifosg/controller.hpp | 1 + components/sceneutil/controller.cpp | 5 +- 15 files changed, 234 insertions(+), 752 deletions(-) delete mode 100644 apps/openmw/mwrender/refraction.cpp delete mode 100644 apps/openmw/mwrender/refraction.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index c46a83183..015d0db9a 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -22,8 +22,8 @@ source_group(game FILES ${GAME} ${GAME_HEADER}) add_openmw_dir (mwrender actors objects renderingmanager animation rotatecontroller sky npcanimation vismask creatureanimation effectmanager util renderinginterface pathgrid rendermode weaponanimation - bulletdebugdraw globalmap characterpreview camera localmap -# occlusionquery water shadows ripplesimulation refraction terrainstorage + bulletdebugdraw globalmap characterpreview camera localmap water +# occlusionquery shadows ripplesimulation refraction terrainstorage ) add_openmw_dir (mwinput diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index edc88ac55..3003e4736 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -157,7 +157,7 @@ osg::ref_ptr LocalMap::createOrthographicCamera(float x, float y, f camera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); camera->setRenderOrder(osg::Camera::PRE_RENDER); - camera->setCullMask(MWRender::Mask_Scene); + camera->setCullMask(MWRender::Mask_Scene|MWRender::Mask_Water); camera->setNodeMask(Mask_RenderToTexture); osg::ref_ptr stateset = new osg::StateSet; diff --git a/apps/openmw/mwrender/refraction.cpp b/apps/openmw/mwrender/refraction.cpp deleted file mode 100644 index 739ed24d9..000000000 --- a/apps/openmw/mwrender/refraction.cpp +++ /dev/null @@ -1,110 +0,0 @@ -#include "refraction.hpp" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "renderconst.hpp" - -namespace MWRender -{ - - Refraction::Refraction(Ogre::Camera *parentCamera) - : mParentCamera(parentCamera) - , mRenderActive(false) - , mIsUnderwater(false) - { - mCamera = mParentCamera->getSceneManager()->createCamera("RefractionCamera"); - - mParentCamera->getSceneManager()->addRenderQueueListener(this); - - Ogre::TexturePtr texture = Ogre::TextureManager::getSingleton().createManual("WaterRefraction", - Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::TEX_TYPE_2D, 512, 512, 0, Ogre::PF_R8G8B8, Ogre::TU_RENDERTARGET); - - mRenderTarget = texture->getBuffer()->getRenderTarget(); - Ogre::Viewport* vp = mRenderTarget->addViewport(mCamera); - vp->setOverlaysEnabled(false); - vp->setShadowsEnabled(false); - vp->setVisibilityMask(RV_Refraction); - vp->setMaterialScheme("water_refraction"); - vp->setBackgroundColour (Ogre::ColourValue(0.090195f, 0.115685f, 0.12745f)); - mRenderTarget->setAutoUpdated(true); - mRenderTarget->addListener(this); - } - - Refraction::~Refraction() - { - mRenderTarget->removeListener(this); - Ogre::TextureManager::getSingleton().remove("WaterRefraction"); - mParentCamera->getSceneManager()->destroyCamera(mCamera); - mParentCamera->getSceneManager()->removeRenderQueueListener(this); - } - - void Refraction::preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt) - { - if (mParentCamera->isAttached()) - mParentCamera->getParentSceneNode ()->needUpdate (); - mCamera->setOrientation(mParentCamera->getDerivedOrientation()); - mCamera->setPosition(mParentCamera->getDerivedPosition()); - mCamera->setNearClipDistance(mParentCamera->getNearClipDistance()); - mCamera->setFarClipDistance(mParentCamera->getFarClipDistance()); - mCamera->setAspectRatio(mParentCamera->getAspectRatio()); - mCamera->setFOVy(mParentCamera->getFOVy()); - - // for depth calculation, we want the original viewproj matrix _without_ the custom near clip plane. - // since all we are interested in is depth, we only need the third row of the matrix. - Ogre::Matrix4 projMatrix = mCamera->getProjectionMatrixWithRSDepth () * mCamera->getViewMatrix (); - sh::Vector4* row3 = new sh::Vector4(projMatrix[2][0], projMatrix[2][1], projMatrix[2][2], projMatrix[2][3]); - sh::Factory::getInstance ().setSharedParameter ("vpRow2Fix", sh::makeProperty (row3)); - - // enable clip plane here to take advantage of CPU culling for overwater or underwater objects - mCamera->enableCustomNearClipPlane(mIsUnderwater ? mNearClipPlaneUnderwater : mNearClipPlane); - - mRenderActive = true; - } - - void Refraction::postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt) - { - mCamera->disableCustomNearClipPlane (); - mRenderActive = false; - } - - void Refraction::setHeight(float height) - { - mNearClipPlane = Ogre::Plane( -Ogre::Vector3(0,0,1), -(height + 5)); - mNearClipPlaneUnderwater = Ogre::Plane( Ogre::Vector3(0,0,1), height - 5); - } - - void Refraction::renderQueueStarted (Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &skipThisInvocation) - { - // We don't want the sky to get clipped by custom near clip plane (the water plane) - if (queueGroupId < 20 && mRenderActive) - { - mCamera->disableCustomNearClipPlane(); - Ogre::Root::getSingleton().getRenderSystem()->_setProjectionMatrix(mCamera->getProjectionMatrixRS()); - } - } - - void Refraction::renderQueueEnded (Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &repeatThisInvocation) - { - if (queueGroupId < 20 && mRenderActive) - { - mCamera->enableCustomNearClipPlane(mIsUnderwater ? mNearClipPlaneUnderwater : mNearClipPlane); - Ogre::Root::getSingleton().getRenderSystem()->_setProjectionMatrix(mCamera->getProjectionMatrixRS()); - } - } - - void Refraction::setActive(bool active) - { - mRenderTarget->setActive(active); - } - -} diff --git a/apps/openmw/mwrender/refraction.hpp b/apps/openmw/mwrender/refraction.hpp deleted file mode 100644 index b9ab8deac..000000000 --- a/apps/openmw/mwrender/refraction.hpp +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef MWRENDER_REFRACTION_H -#define MWRENDER_REFRACTION_H - -#include -#include -#include - -namespace Ogre -{ - class Camera; - class RenderTarget; -} - -namespace MWRender -{ - - class Refraction : public Ogre::RenderTargetListener, public Ogre::RenderQueueListener - { - - public: - Refraction(Ogre::Camera* parentCamera); - ~Refraction(); - - void setHeight (float height); - void preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt); - void postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt); - void setUnderwater(bool underwater) {mIsUnderwater = underwater;} - void setActive (bool active); - - void renderQueueStarted (Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &skipThisInvocation); - void renderQueueEnded (Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &repeatThisInvocation); - - private: - Ogre::Camera* mParentCamera; - Ogre::Camera* mCamera; - Ogre::RenderTarget* mRenderTarget; - Ogre::Plane mNearClipPlane; - Ogre::Plane mNearClipPlaneUnderwater; - bool mRenderActive; - bool mIsUnderwater; - }; - -} - -#endif diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 31ff9b02b..a708bbe88 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -34,6 +34,7 @@ #include "vismask.hpp" #include "pathgrid.hpp" #include "camera.hpp" +#include "water.hpp" namespace MWRender { @@ -129,7 +130,9 @@ namespace MWRender mResourceSystem->getSceneManager()->setIncrementalCompileOperation(mViewer->getIncrementalCompileOperation()); - mEffectManager.reset(new EffectManager(mRootNode, mResourceSystem)); + mEffectManager.reset(new EffectManager(lightRoot, mResourceSystem)); + + mWater.reset(new Water(lightRoot, mResourceSystem)); mCamera.reset(new Camera(mViewer->getCamera())); @@ -177,6 +180,7 @@ namespace MWRender mViewDistance = Settings::Manager::getFloat("viewing distance", "Camera"); mFieldOfView = Settings::Manager::getFloat("field of view", "General"); updateProjectionMatrix(); + mStateUpdater->setFogEnd(mViewDistance); } RenderingManager::~RenderingManager() @@ -230,6 +234,8 @@ namespace MWRender void RenderingManager::addCell(const MWWorld::CellStore *store) { mPathgrid->addCell(store); + + mWater->changeCell(store); } void RenderingManager::removeCell(const MWWorld::CellStore *store) @@ -253,6 +259,22 @@ namespace MWRender mStateUpdater->setWireframe(wireframe); return wireframe; } + else if (mode == Render_Water) + { + return mWater->toggle(); + } + else if (mode == Render_Scene) + { + int mask = mViewer->getCamera()->getCullMask(); + bool enabled = mask&Mask_Scene; + enabled = !enabled; + if (enabled) + mask |= Mask_Scene; + else + mask &= ~Mask_Scene; + mViewer->getCamera()->setCullMask(mask); + return enabled; + } /* else //if (mode == Render_BoundingBoxes) { @@ -271,12 +293,9 @@ namespace MWRender configureFog (cell->mAmbi.mFogDensity, color); } - void RenderingManager::configureFog(float /* fogDepth */, const osg::Vec4f &colour) + void RenderingManager::configureFog(float /* fogDepth */, const osg::Vec4f &color) { - mViewer->getCamera()->setClearColor(colour); - - mStateUpdater->setFogColor(colour); - mStateUpdater->setFogEnd(mViewDistance); + mFogColor = color; } SkyManager* RenderingManager::getSkyManager() @@ -289,6 +308,19 @@ namespace MWRender mEffectManager->update(dt); mSky->update(dt); mCamera->update(dt, paused); + + osg::Vec3f focal, cameraPos; + mCamera->getPosition(focal, cameraPos); + if (mWater->isUnderwater(cameraPos)) + { + setFogColor(osg::Vec4f(0.090195f, 0.115685f, 0.12745f, 1.f)); + mStateUpdater->setFogEnd(1000); + } + else + { + setFogColor(mFogColor); + mStateUpdater->setFogEnd(mViewDistance); + } } void RenderingManager::updatePlayerPtr(const MWWorld::Ptr &ptr) @@ -325,6 +357,16 @@ namespace MWRender mObjects->removeObject(ptr); } + void RenderingManager::setWaterEnabled(bool enabled) + { + mWater->setEnabled(enabled); + } + + void RenderingManager::setWaterHeight(float height) + { + mWater->setHeight(height); + } + void RenderingManager::getCameraToViewportRay(float nX, float nY, osg::Vec3f &origin, osg::Vec3f &dest) { osg::Matrix viewProj = mViewer->getCamera()->getViewMatrix() * mViewer->getCamera()->getProjectionMatrix(); @@ -390,7 +432,7 @@ namespace MWRender osgUtil::IntersectionVisitor intersectionVisitor(intersector); int mask = intersectionVisitor.getTraversalMask(); - mask &= ~(Mask_RenderToTexture|Mask_Sky|Mask_Debug|Mask_Effect); + mask &= ~(Mask_RenderToTexture|Mask_Sky|Mask_Debug|Mask_Effect|Mask_Water); if (ignorePlayer) mask &= ~(Mask_Player); @@ -521,6 +563,13 @@ namespace MWRender mViewer->startThreading(); } + void RenderingManager::setFogColor(const osg::Vec4f &color) + { + mViewer->getCamera()->setClearColor(color); + + mStateUpdater->setFogColor(color); + } + void RenderingManager::processChangedSettings(const Settings::CategorySettingVector &changed) { for (Settings::CategorySettingVector::const_iterator it = changed.begin(); it != changed.end(); ++it) diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 57a2df60e..d90a75c86 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -42,6 +42,7 @@ namespace MWRender class NpcAnimation; class Pathgrid; class Camera; + class Water; class RenderingManager : public MWRender::RenderingInterface { @@ -73,6 +74,9 @@ namespace MWRender void removeObject(const MWWorld::Ptr& ptr); + void setWaterEnabled(bool enabled); + void setWaterHeight(float level); + /// Return the object under the mouse cursor / crosshair position, given by nX and nY normalized screen coordinates, /// where (0,0) is the top left corner. MWWorld::Ptr getFacedObject(const float nX, const float nY, float maxDistance, bool ignorePlayer); @@ -131,6 +135,7 @@ namespace MWRender private: void updateProjectionMatrix(); void updateTextureFiltering(); + void setFogColor(const osg::Vec4f& color); osg::ref_ptr mViewer; osg::ref_ptr mRootNode; @@ -141,6 +146,7 @@ namespace MWRender std::auto_ptr mPathgrid; std::auto_ptr mObjects; + std::auto_ptr mWater; std::auto_ptr mSky; std::auto_ptr mEffectManager; std::auto_ptr mPlayerAnimation; @@ -149,6 +155,8 @@ namespace MWRender osg::ref_ptr mStateUpdater; + osg::Vec4f mFogColor; + float mNearClip; float mViewDistance; float mFieldOfView; diff --git a/apps/openmw/mwrender/rendermode.hpp b/apps/openmw/mwrender/rendermode.hpp index a74d9bd52..ba767bc55 100644 --- a/apps/openmw/mwrender/rendermode.hpp +++ b/apps/openmw/mwrender/rendermode.hpp @@ -9,7 +9,9 @@ namespace MWRender Render_CollisionDebug, Render_Wireframe, Render_Pathgrid, - Render_BoundingBoxes + Render_BoundingBoxes, + Render_Water, + Render_Scene }; } diff --git a/apps/openmw/mwrender/vismask.hpp b/apps/openmw/mwrender/vismask.hpp index c9ac35c67..3a0336f82 100644 --- a/apps/openmw/mwrender/vismask.hpp +++ b/apps/openmw/mwrender/vismask.hpp @@ -15,13 +15,14 @@ namespace MWRender Mask_Actor = (1<<3), Mask_Player = (1<<4), Mask_Sky = (1<<5), + Mask_Water = (1<<6), // top level masks - Mask_Scene = (1<<6), - Mask_GUI = (1<<7), + Mask_Scene = (1<<7), + Mask_GUI = (1<<8), // Set on cameras within the main scene graph - Mask_RenderToTexture = (1<<8) + Mask_RenderToTexture = (1<<9) // reserved: (1<<16) for SceneUtil::Mask_Lit }; diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index f2175ced5..2dd843e4e 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -1,491 +1,184 @@ #include "water.hpp" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "sky.hpp" -#include "renderingmanager.hpp" -#include "ripplesimulation.hpp" -#include "refraction.hpp" - -#include -#include - -using namespace Ogre; +#include -namespace MWRender -{ - -CubeReflection::CubeReflection(Ogre::SceneManager* sceneManager) - : Reflection(sceneManager) -{ - Ogre::TexturePtr texture = Ogre::TextureManager::getSingleton ().createManual("CubeReflection", - ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, TEX_TYPE_CUBE_MAP, - 512,512, 0, PF_R8G8B8, TU_RENDERTARGET); - - mCamera = mSceneMgr->createCamera ("CubeCamera"); - mCamera->setNearClipDistance (5); - mCamera->setFarClipDistance (1000); - - for (int face = 0; face < 6; ++face) - { - mRenderTargets[face] = texture->getBuffer (face)->getRenderTarget(); - mRenderTargets[face]->removeAllViewports (); - Viewport* vp = mRenderTargets[face]->addViewport (mCamera); - vp->setOverlaysEnabled(false); - vp->setShadowsEnabled(false); - vp->setMaterialScheme ("water_reflection"); - mRenderTargets[face]->setAutoUpdated(false); - - /* - Vector3 lookAt(0,0,0), up(0,0,0), right(0,0,0); - switch(face) - { - case 0: lookAt.x =-1; up.y = 1; right.z = 1; break; // +X - case 1: lookAt.x = 1; up.y = 1; right.z =-1; break; // -X - case 2: lookAt.y =-1; up.z = 1; right.x = 1; break; // +Y - case 3: lookAt.y = 1; up.z =-1; right.x = 1; break; // -Y - case 4: lookAt.z = 1; up.y = 1; right.x =-1; break; // +Z - case 5: lookAt.z =-1; up.y = 1; right.x =-1; break; // -Z - } - Quaternion orient(right, up, lookAt); - mCamera->setOrientation(orient); - */ - } -} +#include +#include +#include +#include +#include +#include -CubeReflection::~CubeReflection () -{ - Ogre::TextureManager::getSingleton ().remove("CubeReflection"); - mSceneMgr->destroyCamera (mCamera); -} +#include +#include -void CubeReflection::update () -{ - if (mParentCamera->isAttached()) - mParentCamera->getParentSceneNode ()->needUpdate (); - mCamera->setPosition(mParentCamera->getDerivedPosition()); -} +#include +#include -// -------------------------------------------------------------------------------------------------------------------------------- +#include "vismask.hpp" -PlaneReflection::PlaneReflection(Ogre::SceneManager* sceneManager, SkyManager* sky) - : Reflection(sceneManager) - , mSky(sky) - , mRenderActive(false) +namespace { - mCamera = mSceneMgr->createCamera ("PlaneReflectionCamera"); - mSceneMgr->addRenderQueueListener(this); - - mTexture = TextureManager::getSingleton().createManual("WaterReflection", - ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, TEX_TYPE_2D, 512, 512, 0, PF_R8G8B8, TU_RENDERTARGET); - - mRenderTarget = mTexture->getBuffer()->getRenderTarget(); - Viewport* vp = mRenderTarget->addViewport(mCamera); - vp->setOverlaysEnabled(false); - vp->setBackgroundColour(ColourValue(0.8f, 0.9f, 1.0f)); - vp->setShadowsEnabled(false); - vp->setMaterialScheme("water_reflection"); - mRenderTarget->addListener(this); - mRenderTarget->setActive(true); - mRenderTarget->setAutoUpdated(true); - - sh::Factory::getInstance ().setTextureAlias ("WaterReflection", mTexture->getName()); -} -PlaneReflection::~PlaneReflection () -{ - mRenderTarget->removeListener (this); - mSceneMgr->destroyCamera (mCamera); - mSceneMgr->removeRenderQueueListener(this); - TextureManager::getSingleton ().remove("WaterReflection"); -} - -void PlaneReflection::renderQueueStarted (Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &skipThisInvocation) -{ - // We don't want the sky to get clipped by custom near clip plane (the water plane) - if (queueGroupId < 20 && mRenderActive) + osg::ref_ptr createWaterGeometry(float size, int segments, float textureRepeats) { - mCamera->disableCustomNearClipPlane(); - Root::getSingleton().getRenderSystem()->_setProjectionMatrix(mCamera->getProjectionMatrixRS()); - } -} - -void PlaneReflection::renderQueueEnded (Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &repeatThisInvocation) -{ - if (queueGroupId < 20 && mRenderActive) - { - mCamera->enableCustomNearClipPlane(mIsUnderwater ? mErrorPlaneUnderwater : mErrorPlane); - Root::getSingleton().getRenderSystem()->_setProjectionMatrix(mCamera->getProjectionMatrixRS()); - } -} - -void PlaneReflection::preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt) -{ - if (mParentCamera->isAttached()) - mParentCamera->getParentSceneNode ()->needUpdate (); - mCamera->setOrientation(mParentCamera->getDerivedOrientation()); - mCamera->setPosition(mParentCamera->getDerivedPosition()); - mCamera->setNearClipDistance(mParentCamera->getNearClipDistance()); - mCamera->setFarClipDistance(mParentCamera->getFarClipDistance()); - mCamera->setAspectRatio(mParentCamera->getAspectRatio()); - mCamera->setFOVy(mParentCamera->getFOVy()); - mRenderActive = true; - - mCamera->enableReflection(mWaterPlane); - - // for depth calculation, we want the original viewproj matrix _without_ the custom near clip plane. - // since all we are interested in is depth, we only need the third row of the matrix. - Ogre::Matrix4 projMatrix = mCamera->getProjectionMatrixWithRSDepth () * mCamera->getViewMatrix (); - sh::Vector4* row3 = new sh::Vector4(projMatrix[2][0], projMatrix[2][1], projMatrix[2][2], projMatrix[2][3]); - sh::Factory::getInstance ().setSharedParameter ("vpRow2Fix", sh::makeProperty (row3)); - - // enable clip plane here to take advantage of CPU culling for overwater or underwater objects - mCamera->enableCustomNearClipPlane(mIsUnderwater ? mErrorPlaneUnderwater : mErrorPlane); -} - -void PlaneReflection::postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt) -{ - mCamera->disableReflection(); - mCamera->disableCustomNearClipPlane(); - mRenderActive = false; -} - -void PlaneReflection::setHeight (float height) -{ - mWaterPlane = Plane(Ogre::Vector3(0,0,1), height); - mErrorPlane = Plane(Ogre::Vector3(0,0,1), height - 5); - mErrorPlaneUnderwater = Plane(Ogre::Vector3(0,0,-1), -height - 5); -} - -void PlaneReflection::setActive (bool active) -{ - mRenderTarget->setActive(active); -} - -void PlaneReflection::setViewportBackground(Ogre::ColourValue colour) -{ - mRenderTarget->getViewport (0)->setBackgroundColour (colour); -} - -void PlaneReflection::setVisibilityMask (int flags) -{ - mRenderTarget->getViewport (0)->setVisibilityMask (flags); -} - -// -------------------------------------------------------------------------------------------------------------------------------- - -Water::Water (Ogre::Camera *camera, RenderingManager* rend, const MWWorld::Fallback* fallback) : - mCamera (camera), mSceneMgr (camera->getSceneManager()), - mIsUnderwater(false), mActive(1), - mToggled(1), mWaterTimer(0.f), - mRendering(rend), - mVisibilityFlags(0), - mReflection(NULL), - mRefraction(NULL), - mSimulation(NULL), - mPlayer(0,0) -{ - mSimulation = new RippleSimulation(mSceneMgr, fallback); - - mSky = rend->getSkyManager(); - - mMaterial = MaterialManager::getSingleton().getByName("Water"); - - mTop = 0; - - mIsUnderwater = false; - - mWaterPlane = Plane(Vector3::UNIT_Z, 0); - - int waterScale = 30; - - MeshManager::getSingleton().createPlane("water", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, mWaterPlane, - static_cast(CELL_SIZE*5*waterScale), static_cast(CELL_SIZE*5*waterScale), - 40, 40, true, 1, static_cast(3 * waterScale), static_cast(3 * waterScale), Vector3::UNIT_Y); - - mWater = mSceneMgr->createEntity("water"); - mWater->setVisibilityFlags(RV_Water); - mWater->setCastShadows(false); - mWater->setRenderQueueGroup(RQG_Alpha); - - mWaterNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(); - - mWaterNode->attachObject(mWater); - - applyRTT(); - applyVisibilityMask(); - - mWater->setMaterial(mMaterial); + osg::ref_ptr verts (new osg::Vec3Array); + osg::ref_ptr texcoords (new osg::Vec2Array); + + // some drivers don't like huge triangles, so we do some subdivisons + // a paged solution would be even better + const float step = size/segments; + const float texCoordStep = textureRepeats / segments; + for (int x=0; xpush_back(osg::Vec3f(x1, y2, 0.f)); + verts->push_back(osg::Vec3f(x1, y1, 0.f)); + verts->push_back(osg::Vec3f(x2, y1, 0.f)); + verts->push_back(osg::Vec3f(x2, y2, 0.f)); + + float u1 = x*texCoordStep; + float v1 = y*texCoordStep; + float u2 = u1 + texCoordStep; + float v2 = v1 + texCoordStep; + + texcoords->push_back(osg::Vec2f(u1, v2)); + texcoords->push_back(osg::Vec2f(u1, v1)); + texcoords->push_back(osg::Vec2f(u2, v1)); + texcoords->push_back(osg::Vec2f(u2, v2)); + } + } - setHeight(mTop); + osg::ref_ptr waterGeom (new osg::Geometry); + waterGeom->setVertexArray(verts); + waterGeom->setTexCoordArray(0, texcoords); - sh::MaterialInstance* m = sh::Factory::getInstance ().getMaterialInstance ("Water"); - m->setListener (this); + waterGeom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,verts->size())); + return waterGeom; + } - // ---------------------------------------------------------------------------------------------- - // ---------------------------------- reflection debug overlay ---------------------------------- - // ---------------------------------------------------------------------------------------------- -/* - if (Settings::Manager::getBool("shader", "Water")) + void createWaterStateSet(Resource::ResourceSystem* resourceSystem, osg::ref_ptr node) { - OverlayManager& mgr = OverlayManager::getSingleton(); - Overlay* overlay; - // destroy if already exists - if ((overlay = mgr.getByName("ReflectionDebugOverlay"))) - mgr.destroy(overlay); + osg::ref_ptr stateset (new osg::StateSet); - overlay = mgr.create("ReflectionDebugOverlay"); + osg::ref_ptr material (new osg::Material); + material->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(1.f, 1.f, 1.f, 1.f)); + material->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 0.7f)); + material->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 1.f)); + material->setColorMode(osg::Material::OFF); + stateset->setAttributeAndModes(material, osg::StateAttribute::ON); - if (MaterialManager::getSingleton().resourceExists("Ogre/ReflectionDebugTexture")) - MaterialManager::getSingleton().remove("Ogre/ReflectionDebugTexture"); - MaterialPtr debugMat = MaterialManager::getSingleton().create( - "Ogre/ReflectionDebugTexture", - ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); + stateset->setMode(GL_BLEND, osg::StateAttribute::ON); + stateset->setMode(GL_CULL_FACE, osg::StateAttribute::OFF); - debugMat->getTechnique(0)->getPass(0)->setLightingEnabled(false); - debugMat->getTechnique(0)->getPass(0)->createTextureUnitState(mReflectionTexture->getName()); + osg::ref_ptr depth (new osg::Depth); + depth->setWriteMask(false); + stateset->setAttributeAndModes(depth, osg::StateAttribute::ON); - OverlayContainer* debugPanel; + stateset->setRenderBinDetails(9, "RenderBin"); - // destroy container if exists - try + std::vector > textures; + for (int i=0; i<32; ++i) { - if ((debugPanel = - static_cast( - mgr.getOverlayElement("Ogre/ReflectionDebugTexPanel" - )))) - mgr.destroyOverlayElement(debugPanel); + std::ostringstream texname; + texname << "textures/water/water" << std::setw(2) << std::setfill('0') << i << ".dds"; + textures.push_back(resourceSystem->getTextureManager()->getTexture2D(texname.str(), osg::Texture::REPEAT, osg::Texture::REPEAT)); } - catch (Ogre::Exception&) {} - - debugPanel = (OverlayContainer*) - (OverlayManager::getSingleton().createOverlayElement("Panel", "Ogre/ReflectionDebugTexPanel")); - debugPanel->_setPosition(0, 0.55); - debugPanel->_setDimensions(0.3, 0.3); - debugPanel->setMaterialName(debugMat->getName()); - debugPanel->show(); - overlay->add2D(debugPanel); - overlay->show(); - } -*/ -} -void Water::setActive(bool active) -{ - mActive = active; - updateVisible(); + osg::ref_ptr controller (new NifOsg::FlipController(0, 2/32.f, textures)); + controller->setSource(boost::shared_ptr(new SceneUtil::FrameTimeSource)); + node->addUpdateCallback(controller); + node->setStateSet(stateset); + stateset->setTextureAttributeAndModes(0, textures[0], osg::StateAttribute::ON); + } - sh::Factory::getInstance ().setSharedParameter ("waterEnabled", sh::makeProperty (new sh::FloatValue(active ? 1.0f : 0.0f))); } -Water::~Water() +namespace MWRender { - MeshManager::getSingleton().remove("water"); - - mWaterNode->detachObject(mWater); - mSceneMgr->destroyEntity(mWater); - mSceneMgr->destroySceneNode(mWaterNode); - delete mReflection; - delete mRefraction; - delete mSimulation; -} +// -------------------------------------------------------------------------------------------------------------------------------- -void Water::changeCell(const ESM::Cell* cell) +Water::Water(osg::Group *parent, Resource::ResourceSystem *resourceSystem) + : mParent(parent) + , mResourceSystem(resourceSystem) + , mEnabled(true) + , mToggled(true) + , mTop(0) { - if(cell->isExterior()) - mWaterNode->setPosition(getSceneNodeCoordinates(cell->mData.mX, cell->mData.mY)); -} + osg::ref_ptr waterGeom = createWaterGeometry(CELL_SIZE*150, 40, 900); -void Water::setHeight(const float height) -{ - mTop = height; + osg::ref_ptr geode (new osg::Geode); + geode->addDrawable(waterGeom); + geode->setNodeMask(Mask_Water); - mSimulation->setWaterHeight(height); + createWaterStateSet(mResourceSystem, geode); - mWaterPlane = Plane(Vector3::UNIT_Z, -height); + mWaterNode = new osg::PositionAttitudeTransform; + mWaterNode->addChild(geode); - if (mReflection) - mReflection->setHeight(height); - if (mRefraction) - mRefraction->setHeight(height); + mParent->addChild(mWaterNode); - mWaterNode->setPosition(0, 0, height); - sh::Factory::getInstance ().setSharedParameter ("waterLevel", sh::makeProperty(new sh::FloatValue(height))); + setHeight(mTop); } -bool Water::toggle() +Water::~Water() { - mToggled = !mToggled; - updateVisible(); - return mToggled; + mParent->removeChild(mWaterNode); } -void -Water::updateUnderwater(bool underwater) +void Water::setEnabled(bool enabled) { - if (!mActive) { - return; - } - mIsUnderwater = - underwater && - mWater->isVisible() && - mCamera->getPolygonMode() == Ogre::PM_SOLID; - - if (mReflection) - mReflection->setUnderwater (mIsUnderwater); - if (mRefraction) - mRefraction->setUnderwater (mIsUnderwater); - + mEnabled = enabled; updateVisible(); } -Vector3 Water::getSceneNodeCoordinates(int gridX, int gridY) +void Water::changeCell(const MWWorld::CellStore* store) { - return Vector3(static_cast(gridX * CELL_SIZE + (CELL_SIZE / 2)), static_cast(gridY * CELL_SIZE + (CELL_SIZE / 2)), mTop); + if (store->getCell()->isExterior()) + mWaterNode->setPosition(getSceneNodeCoordinates(store->getCell()->mData.mX, store->getCell()->mData.mY)); + else + mWaterNode->setPosition(osg::Vec3f(0,0,mTop)); } -void Water::setViewportBackground(const ColourValue& bg) +void Water::setHeight(const float height) { - if (mReflection) - mReflection->setViewportBackground(bg); -} + mTop = height; -void Water::updateVisible() -{ - mWater->setVisible(mToggled && mActive); - if (mReflection) - mReflection->setActive(mToggled && mActive); - if (mRefraction) - mRefraction->setActive(mToggled && mActive); + osg::Vec3f pos = mWaterNode->getPosition(); + pos.z() = height; + mWaterNode->setPosition(pos); } -void Water::update(float dt, Ogre::Vector3 player) +void Water::updateVisible() { - mWaterTimer += dt; - sh::Factory::getInstance ().setSharedParameter ("waterTimer", sh::makeProperty(new sh::FloatValue(mWaterTimer))); - - mRendering->getSkyManager ()->setGlareEnabled (!mIsUnderwater); - - mPlayer = Ogre::Vector2(player.x, player.y); + mWaterNode->setNodeMask(mEnabled && mToggled ? ~0 : 0); } -void Water::frameStarted(float dt) -{ - if (!mActive) - return; - - mSimulation->update(dt, mPlayer); - - if (mReflection) - { - mReflection->update(); - } -} - -void Water::applyRTT() +bool Water::toggle() { - delete mReflection; - mReflection = NULL; - delete mRefraction; - mRefraction = NULL; - - // Create rendertarget for reflection - //int rttsize = Settings::Manager::getInt("rtt size", "Water"); - - if (Settings::Manager::getBool("shader", "Water")) - { - mReflection = new PlaneReflection(mSceneMgr, mSky); - mReflection->setParentCamera (mCamera); - mReflection->setHeight(mTop); - - if (Settings::Manager::getBool("refraction", "Water")) - { - mRefraction = new Refraction(mCamera); - mRefraction->setHeight(mTop); - } - } - + mToggled = !mToggled; updateVisible(); + return mToggled; } -void Water::applyVisibilityMask() -{ - mVisibilityFlags = RV_Terrain * Settings::Manager::getBool("reflect terrain", "Water") - + (RV_Statics + RV_StaticsSmall + RV_Misc) * Settings::Manager::getBool("reflect statics", "Water") - + RV_Actors * Settings::Manager::getBool("reflect actors", "Water") - + RV_Effects - + RV_Sky; - - if (mReflection) - mReflection->setVisibilityMask(mVisibilityFlags); -} - -void Water::processChangedSettings(const Settings::CategorySettingVector& settings) -{ - bool applyRT = false; - bool applyVisMask = false; - for (Settings::CategorySettingVector::const_iterator it=settings.begin(); - it != settings.end(); ++it) - { - if ( it->first == "Water" && ( - it->second == "shader" - || it->second == "refraction" - || it->second == "rtt size")) - applyRT = true; - - if ( it->first == "Water" && ( - it->second == "reflect actors" - || it->second == "reflect terrain" - || it->second == "reflect statics")) - applyVisMask = true; - } - - if(applyRT) - { - applyRTT(); - applyVisibilityMask(); - mWater->setMaterial(mMaterial); - } - if (applyVisMask) - applyVisibilityMask(); -} - -void Water::requestedConfiguration (sh::MaterialInstance* m, const std::string& configuration) +bool Water::isUnderwater(const osg::Vec3f &pos) const { + return pos.z() < mTop && mToggled && mEnabled; } -void Water::createdConfiguration (sh::MaterialInstance* m, const std::string& configuration) +osg::Vec3f Water::getSceneNodeCoordinates(int gridX, int gridY) { - if (configuration == "local_map" || !Settings::Manager::getBool("shader", "Water")) - { - // for simple water, set animated texture names - // these have to be set in code - std::string textureNames[32]; - for (int i=0; i<32; ++i) - { - textureNames[i] = "textures\\water\\water" + StringConverter::toString(i, 2, '0') + ".dds"; - } - - Ogre::Technique* t = static_cast(m->getMaterial())->getOgreTechniqueForConfiguration(configuration); - if (t->getPass(0)->getNumTextureUnitStates () == 0) - return; - t->getPass(0)->getTextureUnitState(0)->setAnimatedTextureName(textureNames, 32, 2); - t->getPass(0)->setDepthWriteEnabled (false); - t->getPass(0)->setSceneBlending (Ogre::SBT_TRANSPARENT_ALPHA); - } + return osg::Vec3f(static_cast(gridX * CELL_SIZE + (CELL_SIZE / 2)), static_cast(gridY * CELL_SIZE + (CELL_SIZE / 2)), mTop); } +/* void Water::addEmitter (const MWWorld::Ptr& ptr, float scale, float force) { mSimulation->addEmitter (ptr, scale, force); @@ -500,10 +193,6 @@ void Water::updateEmitterPtr (const MWWorld::Ptr& old, const MWWorld::Ptr& ptr) { mSimulation->updateEmitterPtr(old, ptr); } +*/ -void Water::clearRipples() -{ - mSimulation->clear(); } - -} // namespace diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index 53d54cdc9..45b4b38a6 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -1,183 +1,60 @@ -#ifndef GAME_MWRENDER_WATER_H -#define GAME_MWRENDER_WATER_H +#ifndef OPENMW_MWRENDER_WATER_H +#define OPENMW_MWRENDER_WATER_H -#include -#include -#include -#include -#include -#include -#include +#include -#include -#include +#include "../mwworld/cellstore.hpp" -#include - - -#include "renderconst.hpp" - -#include "../mwworld/ptr.hpp" - -namespace Ogre +namespace osg { - class Camera; - class SceneManager; - class SceneNode; - class Entity; - class Vector3; - class Rectangle2D; - struct RenderTargetEvent; + class Group; + class PositionAttitudeTransform; } -namespace MWWorld +namespace Resource { - class Fallback; + class ResourceSystem; } -namespace MWRender { - - class SkyManager; - class RenderingManager; - class RippleSimulation; - class Refraction; - - class Reflection - { - public: - Reflection(Ogre::SceneManager* sceneManager) - : mCamera(NULL) - , mParentCamera(NULL) - , mSceneMgr(sceneManager) - , mIsUnderwater(false) - {} - virtual ~Reflection() {} - - virtual void setHeight (float height) {} - virtual void setParentCamera (Ogre::Camera* parent) { mParentCamera = parent; } - void setUnderwater(bool underwater) { mIsUnderwater = underwater; } - virtual void setActive (bool active) {} - virtual void setViewportBackground(Ogre::ColourValue colour) {} - virtual void update() {} - virtual void setVisibilityMask (int flags) {} - - protected: - Ogre::Camera* mCamera; - Ogre::Camera* mParentCamera; - Ogre::TexturePtr mTexture; - Ogre::SceneManager* mSceneMgr; - bool mIsUnderwater; - }; - - class CubeReflection : public Reflection - { - public: - CubeReflection(Ogre::SceneManager* sceneManager); - virtual ~CubeReflection(); - - virtual void update(); - protected: - Ogre::RenderTarget* mRenderTargets[6]; - }; - - class PlaneReflection : public Reflection, public Ogre::RenderQueueListener, public Ogre::RenderTargetListener - { - public: - PlaneReflection(Ogre::SceneManager* sceneManager, SkyManager* sky); - virtual ~PlaneReflection(); - - virtual void setHeight (float height); - virtual void setActive (bool active); - virtual void setVisibilityMask (int flags); - - void preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt); - void postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt); - - void renderQueueStarted (Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &skipThisInvocation); - void renderQueueEnded (Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &repeatThisInvocation); - - virtual void setViewportBackground(Ogre::ColourValue colour); - - protected: - Ogre::RenderTarget* mRenderTarget; - SkyManager* mSky; - Ogre::Plane mWaterPlane; - Ogre::Plane mErrorPlane; - Ogre::Plane mErrorPlaneUnderwater; - bool mRenderActive; - }; +namespace MWRender +{ /// Water rendering - class Water : public sh::MaterialInstanceListener + class Water { static const int CELL_SIZE = 8192; - Ogre::Camera *mCamera; - Ogre::SceneManager *mSceneMgr; - - Ogre::Plane mWaterPlane; - Ogre::SceneNode *mWaterNode; - Ogre::Entity *mWater; + osg::ref_ptr mParent; + osg::ref_ptr mWaterNode; + Resource::ResourceSystem* mResourceSystem; - bool mIsUnderwater; - bool mActive; + bool mEnabled; bool mToggled; float mTop; - float mWaterTimer; - - - Ogre::Vector3 getSceneNodeCoordinates(int gridX, int gridY); - - protected: - void applyRTT(); - void applyVisibilityMask(); - + osg::Vec3f getSceneNodeCoordinates(int gridX, int gridY); void updateVisible(); - RenderingManager* mRendering; - SkyManager* mSky; - - Ogre::MaterialPtr mMaterial; - - bool mUnderwaterEffect; - int mVisibilityFlags; - - Reflection* mReflection; - Refraction* mRefraction; - RippleSimulation* mSimulation; - - Ogre::Vector2 mPlayer; - public: - Water (Ogre::Camera *camera, RenderingManager* rend, const MWWorld::Fallback* fallback); + Water(osg::Group* parent, Resource::ResourceSystem* resourceSystem); ~Water(); - void clearRipples(); - - void setActive(bool active); + void setEnabled(bool enabled); bool toggle(); - void update(float dt, Ogre::Vector3 player); - void frameStarted(float dt); + bool isUnderwater(const osg::Vec3f& pos) const; + + /* /// adds an emitter, position will be tracked automatically using its scene node void addEmitter (const MWWorld::Ptr& ptr, float scale = 1.f, float force = 1.f); void removeEmitter (const MWWorld::Ptr& ptr); void updateEmitterPtr (const MWWorld::Ptr& old, const MWWorld::Ptr& ptr); + */ - void setViewportBackground(const Ogre::ColourValue& bg); - - void processChangedSettings(const Settings::CategorySettingVector& settings); - - /// Updates underwater state accordingly - void updateUnderwater(bool underwater); - void changeCell(const ESM::Cell* cell); + void changeCell(const MWWorld::CellStore* store); void setHeight(const float height); - virtual void requestedConfiguration (sh::MaterialInstance* m, const std::string& configuration); - virtual void createdConfiguration (sh::MaterialInstance* m, const std::string& configuration); - }; } diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index db1f9714a..1a9ae3494 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -265,11 +265,11 @@ namespace MWWorld mRendering.addCell(cell); bool waterEnabled = cell->getCell()->hasWater() || cell->isExterior(); float waterLevel = cell->isExterior() ? -1.f : cell->getWaterLevel(); - //mRendering.setWaterEnabled(waterEnabled); + mRendering.setWaterEnabled(waterEnabled); if (waterEnabled) { mPhysics->enableWater(waterLevel); - //mRendering.setWaterHeight(waterLevel); + mRendering.setWaterHeight(waterLevel); } else mPhysics->disableWater(); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 126267fd4..799f82015 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1763,17 +1763,17 @@ namespace MWWorld void World::setWaterHeight(const float height) { mPhysics->setWaterHeight(height); - //mRendering->setWaterHeight(height); + mRendering->setWaterHeight(height); } bool World::toggleWater() { - return 0;//mRendering->toggleWater(); + return mRendering->toggleRenderMode(MWRender::Render_Water); } bool World::toggleWorld() { - return 0;//mRendering->toggleWorld(); + return mRendering->toggleRenderMode(MWRender::Render_Scene); } void World::PCDropped (const Ptr& item) diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index 06d5d8792..a314910c5 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -399,6 +399,13 @@ FlipController::FlipController(const Nif::NiFlipController *ctrl, std::vector > textures) + : mTexSlot(texSlot) + , mDelta(delta) + , mTextures(textures) +{ +} + FlipController::FlipController() { } diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index 4ebd4f41d..4877c83db 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -218,6 +218,7 @@ namespace NifOsg public: FlipController(const Nif::NiFlipController* ctrl, std::vector > textures); + FlipController(int texSlot, float delta, std::vector > textures); FlipController(); FlipController(const FlipController& copy, const osg::CopyOp& copyop); diff --git a/components/sceneutil/controller.cpp b/components/sceneutil/controller.cpp index 4b51485f2..b8b452dc3 100644 --- a/components/sceneutil/controller.cpp +++ b/components/sceneutil/controller.cpp @@ -20,7 +20,10 @@ namespace SceneUtil float Controller::getInputValue(osg::NodeVisitor* nv) { - return mFunction->calculate(mSource->getValue(nv)); + if (mFunction) + return mFunction->calculate(mSource->getValue(nv)); + else + return mSource->getValue(nv); } void Controller::setSource(boost::shared_ptr source) From 5a7f2a4f1f2fb03d9f72fc0134b00648ec02ffde Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 2 Jun 2015 17:02:56 +0200 Subject: [PATCH 1361/3725] Restore light attenuation settings --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwrender/animation.cpp | 28 +++++++++++++++++++++------ components/sceneutil/lightmanager.cpp | 24 +++++++++++++++++++++++ components/sceneutil/lightmanager.hpp | 3 +++ 4 files changed, 50 insertions(+), 7 deletions(-) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 015d0db9a..bb71cb6c9 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -23,7 +23,7 @@ add_openmw_dir (mwrender actors objects renderingmanager animation rotatecontroller sky npcanimation vismask creatureanimation effectmanager util renderinginterface pathgrid rendermode weaponanimation bulletdebugdraw globalmap characterpreview camera localmap water -# occlusionquery shadows ripplesimulation refraction terrainstorage +# occlusionquery shadows ripplesimulation terrainstorage ) add_openmw_dir (mwinput diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 2279375c2..9fe9dd451 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -31,6 +31,8 @@ #include "../mwbase/world.hpp" #include "../mwworld/esmstore.hpp" #include "../mwworld/class.hpp" +#include "../mwworld/fallback.hpp" +#include "../mwworld/cellstore.hpp" #include "../mwmechanics/character.hpp" // FIXME: for MWMechanics::Priority @@ -1000,14 +1002,28 @@ namespace MWRender osg::Light* light = new osg::Light; lightSource->setLight(light); - float realRadius = esmLight->mData.mRadius; + const MWWorld::Fallback* fallback = MWBase::Environment::get().getWorld()->getFallback(); - lightSource->setRadius(realRadius); - light->setLinearAttenuation(10.f/(esmLight->mData.mRadius*2.f)); - //light->setLinearAttenuation(0.05); - light->setConstantAttenuation(0.f); + float radius = esmLight->mData.mRadius; + lightSource->setRadius(radius); - light->setDiffuse(SceneUtil::colourFromRGB(esmLight->mData.mColor)); + static bool outQuadInLin = fallback->getFallbackBool("LightAttenuation_OutQuadInLin"); + static bool useQuadratic = fallback->getFallbackBool("LightAttenuation_UseQuadratic"); + static float quadraticValue = fallback->getFallbackFloat("LightAttenuation_QuadraticValue"); + static float quadraticRadiusMult = fallback->getFallbackFloat("LightAttenuation_QuadraticRadiusMult"); + static bool useLinear = fallback->getFallbackBool("LightAttenuation_UseLinear"); + static float linearRadiusMult = fallback->getFallbackFloat("LightAttenuation_LinearRadiusMult"); + static float linearValue = fallback->getFallbackFloat("LightAttenuation_LinearValue"); + + bool exterior = mPtr.isInCell() && mPtr.getCell()->getCell()->isExterior(); + + SceneUtil::configureLight(light, radius, exterior, outQuadInLin, useQuadratic, quadraticValue, + quadraticRadiusMult, useLinear, linearRadiusMult, linearValue); + + osg::Vec4f diffuse = SceneUtil::colourFromRGB(esmLight->mData.mColor); + if (esmLight->mData.mFlags & ESM::Light::Negative) + diffuse *= -1; + light->setDiffuse(diffuse); light->setAmbient(osg::Vec4f(0,0,0,1)); light->setSpecular(osg::Vec4f(0,0,0,0)); diff --git a/components/sceneutil/lightmanager.cpp b/components/sceneutil/lightmanager.cpp index e53a55bf3..6040f9536 100644 --- a/components/sceneutil/lightmanager.cpp +++ b/components/sceneutil/lightmanager.cpp @@ -325,4 +325,28 @@ namespace SceneUtil traverse(node, nv); } + void configureLight(osg::Light *light, float radius, bool isExterior, bool outQuadInLin, bool useQuadratic, + float quadraticValue, float quadraticRadiusMult, bool useLinear, float linearRadiusMult, float linearValue) + { + bool quadratic = useQuadratic && (!outQuadInLin || isExterior); + + float quadraticAttenuation = 0; + float linearAttenuation = 0; + if (quadratic) + { + float r = radius * quadraticRadiusMult; + quadraticAttenuation = quadraticValue / std::pow(r, 2); + } + if (useLinear) + { + float r = radius * linearRadiusMult; + linearAttenuation = linearValue / r; + } + + light->setLinearAttenuation(linearAttenuation); + light->setQuadraticAttenuation(quadraticAttenuation); + light->setConstantAttenuation(0.f); + + } + } diff --git a/components/sceneutil/lightmanager.hpp b/components/sceneutil/lightmanager.hpp index dd0c2d3e6..d5aecdbb6 100644 --- a/components/sceneutil/lightmanager.hpp +++ b/components/sceneutil/lightmanager.hpp @@ -124,6 +124,9 @@ namespace SceneUtil LightManager* mLightManager; }; + /// @brief Configures a light's attenuation according to vanilla Morrowind attenuation settings. + void configureLight(osg::Light* light, float radius, bool isExterior, bool outQuadInLin, bool useQuadratic, float quadraticValue, + float quadraticRadiusMult, bool useLinear, float linearRadiusMult, float linearValue); } From 8c50f8ed26a0b2fdf42d5be8ea95dd44e110e015 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 2 Jun 2015 17:06:55 +0200 Subject: [PATCH 1362/3725] Fix for lights with no mesh --- apps/openmw/mwrender/animation.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 9fe9dd451..34a397f9a 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1022,7 +1022,10 @@ namespace MWRender osg::Vec4f diffuse = SceneUtil::colourFromRGB(esmLight->mData.mColor); if (esmLight->mData.mFlags & ESM::Light::Negative) + { diffuse *= -1; + diffuse.a() = 1; + } light->setDiffuse(diffuse); light->setAmbient(osg::Vec4f(0,0,0,1)); light->setSpecular(osg::Vec4f(0,0,0,0)); @@ -1197,10 +1200,9 @@ namespace MWRender if (!ptr.getClass().getEnchantment(ptr).empty()) addGlow(mObjectRoot, getEnchantmentColor(ptr)); - - if (ptr.getTypeName() == typeid(ESM::Light).name() && allowLight) - addExtraLight(getOrCreateObjectRoot(), ptr.get()->mBase); } + if (ptr.getTypeName() == typeid(ESM::Light).name() && allowLight) + addExtraLight(getOrCreateObjectRoot(), ptr.get()->mBase); } } From 58ebf57154daa1c98c638e4778f5929090125753 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 2 Jun 2015 17:13:30 +0200 Subject: [PATCH 1363/3725] Apply a comment that got lost in the endless depths of my git stash --- apps/openmw/mwmechanics/aicombat.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index a909adb8b..36ff927d8 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -239,7 +239,6 @@ namespace MWMechanics if(smoothTurn(actor, Ogre::Degree(movement.mRotation[0]), 0)) movement.mRotation[0] = 0; } - //TODO: Some skills affect period of strikes.For berserk-like style period ~ 0.25f float attacksPeriod = 1.0f; ESM::Weapon::AttackType attackType; @@ -260,7 +259,7 @@ namespace MWMechanics if (!minMaxAttackDurationInitialised) { // TODO: this must be updated when a different weapon is equipped - // FIXME: attack durations would be easier to control if we interact more closely with the CharacterController + // TODO: it would be much easier to ask the CharacterController about the current % completion of the weapon wind-up animation getMinMaxAttackDuration(actor, minMaxAttackDuration); minMaxAttackDurationInitialised = true; } @@ -319,6 +318,10 @@ namespace MWMechanics float rangeAttack = 0; float rangeFollow = 0; boost::shared_ptr& currentAction = storage.mCurrentAction; + // TODO: upperBodyReady() works fine for checking if we can start an attack, + // but doesn't work properly for checking if the attack is finished (as things like hit recovery or knockdown also play on the upper body) + // Only a minor problem, but can mess with the actionCooldown timer. + // To fix this the AI needs to be brought closer to the CharacterController, so we can simply check if a weapon animation is playing. if (anim->upperBodyReady()) { currentAction = prepareNextAction(actor, target); @@ -654,9 +657,6 @@ namespace MWMechanics } } - // NOTE: This section gets updated every tReaction, which is currently hard - // coded at 250ms or 1/4 second - // // TODO: Add a parameter to vary DURATION_SAME_SPOT? if((distToTarget > rangeAttack || followTarget) && mObstacleCheck.check(actor, tReaction)) // check if evasive action needed From 4d5c446a44ef80c76ea2dccf96c48daea9ece15d Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 2 Jun 2015 19:36:57 +0200 Subject: [PATCH 1364/3725] Minor cleanup --- extern/osg-ffmpeg-videoplayer/videostate.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extern/osg-ffmpeg-videoplayer/videostate.cpp b/extern/osg-ffmpeg-videoplayer/videostate.cpp index d8006b581..1b02e13be 100644 --- a/extern/osg-ffmpeg-videoplayer/videostate.cpp +++ b/extern/osg-ffmpeg-videoplayer/videostate.cpp @@ -308,7 +308,7 @@ int VideoState::queue_picture(AVFrame *pFrame, double pts) // windex is set to 0 initially vp = &this->pictq[this->pictq_windex]; - // Convert the image into RGBA format for Ogre + // Convert the image into RGBA format // TODO: we could do this in a pixel shader instead, if the source format // matches a commonly used format (ie YUV420P) if(this->sws_context == NULL) From f84c36b500b09300d49382cdcf4de90449aa32db Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Wed, 3 Jun 2015 00:00:39 +0300 Subject: [PATCH 1365/3725] CommandDelegate: extract a display type from a model if it isn't specified --- apps/opencs/model/world/idtable.cpp | 3 +++ apps/opencs/model/world/idtree.cpp | 3 +++ apps/opencs/view/world/util.cpp | 8 +++++++- apps/opencs/view/world/util.hpp | 2 ++ 4 files changed, 15 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index bde6412ec..8ca19f7e9 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -33,6 +33,9 @@ QVariant CSMWorld::IdTable::data (const QModelIndex & index, int role) const if (index.row() < 0 || index.column() < 0) return QVariant(); + if (role==ColumnBase::Role_Display) + return QVariant(mIdCollection->getColumn(index.column()).mDisplayType); + if (role==ColumnBase::Role_ColumnId) return QVariant (getColumnId (index.column())); diff --git a/apps/opencs/model/world/idtree.cpp b/apps/opencs/model/world/idtree.cpp index a9ec2c4cd..a3dbae465 100644 --- a/apps/opencs/model/world/idtree.cpp +++ b/apps/opencs/model/world/idtree.cpp @@ -40,6 +40,9 @@ QVariant CSMWorld::IdTree::data (const QModelIndex & index, int role) const std::pair parentAddress(unfoldIndexAddress(index.internalId())); const NestableColumn *parentColumn = mNestedCollection->getNestableColumn(parentAddress.second); + if (role == ColumnBase::Role_Display) + return parentColumn->nestedColumn(index.column()).mColumnId; + if (role == ColumnBase::Role_ColumnId) return parentColumn->nestedColumn(index.column()).mColumnId; diff --git a/apps/opencs/view/world/util.cpp b/apps/opencs/view/world/util.cpp index 5452214ef..3be875ffd 100644 --- a/apps/opencs/view/world/util.cpp +++ b/apps/opencs/view/world/util.cpp @@ -111,6 +111,12 @@ CSMDoc::Document& CSVWorld::CommandDelegate::getDocument() const return mDocument; } +CSMWorld::ColumnBase::Display CSVWorld::CommandDelegate::getDisplayTypeFromIndex(const QModelIndex &index) const +{ + int rawDisplay = index.data(CSMWorld::ColumnBase::Role_Display).toInt(); + return static_cast(rawDisplay); +} + void CSVWorld::CommandDelegate::setModelDataImp (QWidget *editor, QAbstractItemModel *model, const QModelIndex& index) const { @@ -146,7 +152,7 @@ void CSVWorld::CommandDelegate::setModelData (QWidget *editor, QAbstractItemMode QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleOptionViewItem& option, const QModelIndex& index) const { - return createEditor (parent, option, index, CSMWorld::ColumnBase::Display_None); + return createEditor (parent, option, index, getDisplayTypeFromIndex(index)); } QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleOptionViewItem& option, diff --git a/apps/opencs/view/world/util.hpp b/apps/opencs/view/world/util.hpp index a12e6ae36..8355e971c 100644 --- a/apps/opencs/view/world/util.hpp +++ b/apps/opencs/view/world/util.hpp @@ -124,6 +124,8 @@ namespace CSVWorld CSMDoc::Document& getDocument() const; + CSMWorld::ColumnBase::Display getDisplayTypeFromIndex(const QModelIndex &index) const; + virtual void setModelDataImp (QWidget *editor, QAbstractItemModel *model, const QModelIndex& index) const; From 4e759370def736689dfc3acc4f64a4aa5d77ad6b Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Wed, 3 Jun 2015 00:02:53 +0300 Subject: [PATCH 1366/3725] Change Display_String to the proper display type where appropriate --- apps/opencs/model/world/columnbase.cpp | 2 ++ apps/opencs/model/world/columnbase.hpp | 2 ++ apps/opencs/model/world/columnimp.hpp | 21 ++++++++++++-------- apps/opencs/model/world/data.cpp | 8 ++++---- apps/opencs/model/world/refidcollection.cpp | 22 ++++++++++----------- 5 files changed, 32 insertions(+), 23 deletions(-) diff --git a/apps/opencs/model/world/columnbase.cpp b/apps/opencs/model/world/columnbase.cpp index 3d13538c0..938503875 100644 --- a/apps/opencs/model/world/columnbase.cpp +++ b/apps/opencs/model/world/columnbase.cpp @@ -65,6 +65,8 @@ bool CSMWorld::ColumnBase::isId (Display display) Display_JournalInfo, Display_Scene, Display_GlobalVariable, + Display_BodyPart, + Display_Enchantment, Display_Script, Display_Mesh, diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index bf8378e37..789823d5c 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -74,6 +74,8 @@ namespace CSMWorld Display_JournalInfo, Display_Scene, Display_GlobalVariable, + Display_BodyPart, + Display_Enchantment, //CONCRETE TYPES ENDS HERE Display_Integer, diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index 6b496e0ca..8758d924b 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -709,7 +709,7 @@ namespace CSMWorld struct SleepListColumn : public Column { SleepListColumn() - : Column (Columns::ColumnId_SleepEncounter, ColumnBase::Display_String) + : Column (Columns::ColumnId_SleepEncounter, ColumnBase::Display_CreatureLevelledList) {} virtual QVariant get (const Record& record) const @@ -735,7 +735,7 @@ namespace CSMWorld template struct TextureColumn : public Column { - TextureColumn() : Column (Columns::ColumnId_Texture, ColumnBase::Display_String) {} + TextureColumn() : Column (Columns::ColumnId_Texture, ColumnBase::Display_Texture) {} virtual QVariant get (const Record& record) const { @@ -1269,7 +1269,7 @@ namespace CSMWorld template struct TrapColumn : public Column { - TrapColumn() : Column (Columns::ColumnId_Trap, ColumnBase::Display_String) {} + TrapColumn() : Column (Columns::ColumnId_Trap, ColumnBase::Display_Spell) {} virtual QVariant get (const Record& record) const { @@ -1294,7 +1294,7 @@ namespace CSMWorld template struct FilterColumn : public Column { - FilterColumn() : Column (Columns::ColumnId_Filter, ColumnBase::Display_String) {} + FilterColumn() : Column (Columns::ColumnId_Filter, ColumnBase::Display_Filter) {} virtual QVariant get (const Record& record) const { @@ -1497,7 +1497,10 @@ namespace CSMWorld template struct TopicColumn : public Column { - TopicColumn (bool journal) : Column (journal ? Columns::ColumnId_Journal : Columns::ColumnId_Topic, ColumnBase::Display_String) {} + TopicColumn (bool journal) + : Column (journal ? Columns::ColumnId_Journal : Columns::ColumnId_Topic, + journal ? ColumnBase::Display_Journal : ColumnBase::Display_Topic) + {} virtual QVariant get (const Record& record) const { @@ -1527,7 +1530,7 @@ namespace CSMWorld template struct ActorColumn : public Column { - ActorColumn() : Column (Columns::ColumnId_Actor, ColumnBase::Display_String) {} + ActorColumn() : Column (Columns::ColumnId_Actor, ColumnBase::Display_Npc) {} virtual QVariant get (const Record& record) const { @@ -1830,7 +1833,7 @@ namespace CSMWorld template struct ModelColumn : public Column { - ModelColumn() : Column (Columns::ColumnId_Model, ColumnBase::Display_String) {} + ModelColumn() : Column (Columns::ColumnId_Model, ColumnBase::Display_Mesh) {} virtual QVariant get (const Record& record) const { @@ -2158,7 +2161,9 @@ namespace CSMWorld struct EffectTextureColumn : public Column { EffectTextureColumn (Columns::ColumnId columnId) - : Column (columnId, ColumnBase::Display_Texture) + : Column (columnId, + columnId == Columns::ColumnId_Particle ? ColumnBase::Display_Texture + : ColumnBase::Display_Icon) { assert (this->mColumnId==Columns::ColumnId_Icon || this->mColumnId==Columns::ColumnId_Particle); diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index c27c068f1..529c8f88f 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -115,7 +115,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc index = mFactions.getColumns()-1; mFactions.addAdapter (std::make_pair(&mFactions.getColumn(index), new FactionReactionsAdapter ())); mFactions.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_Faction, ColumnBase::Display_String)); + new NestedChildColumn (Columns::ColumnId_Faction, ColumnBase::Display_Faction)); mFactions.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_FactionReaction, ColumnBase::Display_Integer)); @@ -135,7 +135,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc index = mRaces.getColumns()-1; mRaces.addAdapter (std::make_pair(&mRaces.getColumn(index), new SpellListAdapter ())); mRaces.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_SpellId, ColumnBase::Display_String)); + new NestedChildColumn (Columns::ColumnId_SpellId, ColumnBase::Display_Spell)); // Race attributes mRaces.addColumn (new NestedParentColumn (Columns::ColumnId_RaceAttributes)); index = mRaces.getColumns()-1; @@ -180,7 +180,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc index = mRegions.getColumns()-1; mRegions.addAdapter (std::make_pair(&mRegions.getColumn(index), new RegionSoundListAdapter ())); mRegions.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_SoundName, ColumnBase::Display_String)); + new NestedChildColumn (Columns::ColumnId_SoundName, ColumnBase::Display_Sound)); mRegions.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_SoundChance, ColumnBase::Display_Integer)); @@ -196,7 +196,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mBirthsigns.addAdapter (std::make_pair(&mBirthsigns.getColumn(index), new SpellListAdapter ())); mBirthsigns.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_SpellId, ColumnBase::Display_String)); + new NestedChildColumn (Columns::ColumnId_SpellId, ColumnBase::Display_Spell)); mSpells.addColumn (new StringIdColumn); mSpells.addColumn (new RecordStateColumn); diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index cda19c87b..5495926b4 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -99,7 +99,7 @@ CSMWorld::RefIdCollection::RefIdCollection() EnchantableColumns enchantableColumns (inventoryColumns); - mColumns.push_back (RefIdColumn (Columns::ColumnId_Enchantment, ColumnBase::Display_String)); + mColumns.push_back (RefIdColumn (Columns::ColumnId_Enchantment, ColumnBase::Display_Enchantment)); enchantableColumns.mEnchantment = &mColumns.back(); mColumns.push_back (RefIdColumn (Columns::ColumnId_EnchantmentPoints, ColumnBase::Display_Integer)); enchantableColumns.mEnchantmentPoints = &mColumns.back(); @@ -135,7 +135,7 @@ CSMWorld::RefIdCollection::RefIdCollection() new NestedInventoryRefIdAdapter (UniversalId::Type_Creature))); mNestedAdapters.push_back (std::make_pair(&mColumns.back(), inventoryMap)); mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_InventoryItemId, CSMWorld::ColumnBase::Display_String)); + new RefIdColumn (Columns::ColumnId_InventoryItemId, CSMWorld::ColumnBase::Display_Referenceable)); mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_ItemCount, CSMWorld::ColumnBase::Display_Integer)); @@ -150,7 +150,7 @@ CSMWorld::RefIdCollection::RefIdCollection() new NestedSpellRefIdAdapter (UniversalId::Type_Creature))); mNestedAdapters.push_back (std::make_pair(&mColumns.back(), spellsMap)); mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_SpellId, CSMWorld::ColumnBase::Display_String)); + new RefIdColumn (Columns::ColumnId_SpellId, CSMWorld::ColumnBase::Display_Spell)); // Nested table mColumns.push_back(RefIdColumn (Columns::ColumnId_NpcDestinations, @@ -163,7 +163,7 @@ CSMWorld::RefIdCollection::RefIdCollection() new NestedTravelRefIdAdapter (UniversalId::Type_Creature))); mNestedAdapters.push_back (std::make_pair(&mColumns.back(), destMap)); mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_DestinationCell, CSMWorld::ColumnBase::Display_String)); + new RefIdColumn (Columns::ColumnId_DestinationCell, CSMWorld::ColumnBase::Display_Cell)); mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_PosX, CSMWorld::ColumnBase::Display_Float)); mColumns.back().addColumn( @@ -289,7 +289,7 @@ CSMWorld::RefIdCollection::RefIdCollection() new NestedInventoryRefIdAdapter (UniversalId::Type_Container))); mNestedAdapters.push_back (std::make_pair(&mColumns.back(), contMap)); mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_InventoryItemId, CSMWorld::ColumnBase::Display_String)); + new RefIdColumn (Columns::ColumnId_InventoryItemId, CSMWorld::ColumnBase::Display_Referenceable)); mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_ItemCount, CSMWorld::ColumnBase::Display_Integer)); @@ -301,7 +301,7 @@ CSMWorld::RefIdCollection::RefIdCollection() creatureColumns.mSoul = &mColumns.back(); mColumns.push_back (RefIdColumn (Columns::ColumnId_Scale, ColumnBase::Display_Float)); creatureColumns.mScale = &mColumns.back(); - mColumns.push_back (RefIdColumn (Columns::ColumnId_OriginalCreature, ColumnBase::Display_String)); + mColumns.push_back (RefIdColumn (Columns::ColumnId_OriginalCreature, ColumnBase::Display_Creature)); creatureColumns.mOriginal = &mColumns.back(); mColumns.push_back ( RefIdColumn (Columns::ColumnId_CombatState, ColumnBase::Display_Integer)); @@ -409,10 +409,10 @@ CSMWorld::RefIdCollection::RefIdCollection() mColumns.push_back (RefIdColumn (Columns::ColumnId_Faction, ColumnBase::Display_Faction)); npcColumns.mFaction = &mColumns.back(); - mColumns.push_back (RefIdColumn (Columns::Columnid_Hair, ColumnBase::Display_String)); + mColumns.push_back (RefIdColumn (Columns::Columnid_Hair, ColumnBase::Display_BodyPart)); npcColumns.mHair = &mColumns.back(); - mColumns.push_back (RefIdColumn (Columns::ColumnId_Head, ColumnBase::Display_String)); + mColumns.push_back (RefIdColumn (Columns::ColumnId_Head, ColumnBase::Display_BodyPart)); npcColumns.mHead = &mColumns.back(); mColumns.push_back (RefIdColumn (Columns::ColumnId_Female, ColumnBase::Display_Boolean)); @@ -539,9 +539,9 @@ CSMWorld::RefIdCollection::RefIdCollection() mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_PartRefType, CSMWorld::ColumnBase::Display_PartRefType)); mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_PartRefMale, CSMWorld::ColumnBase::Display_String)); + new RefIdColumn (Columns::ColumnId_PartRefMale, CSMWorld::ColumnBase::Display_BodyPart)); mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_PartRefFemale, CSMWorld::ColumnBase::Display_String)); + new RefIdColumn (Columns::ColumnId_PartRefFemale, CSMWorld::ColumnBase::Display_BodyPart)); LevListColumns levListColumns (baseColumns); @@ -556,7 +556,7 @@ CSMWorld::RefIdCollection::RefIdCollection() new NestedLevListRefIdAdapter (UniversalId::Type_ItemLevelledList))); mNestedAdapters.push_back (std::make_pair(&mColumns.back(), levListMap)); mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_LevelledItemId, CSMWorld::ColumnBase::Display_String)); + new RefIdColumn (Columns::ColumnId_LevelledItemId, CSMWorld::ColumnBase::Display_Referenceable)); mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_LevelledItemLevel, CSMWorld::ColumnBase::Display_Integer)); From 956234cde999034c5e0a7af27d43818d4252b660 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Tue, 2 Jun 2015 23:11:09 +0200 Subject: [PATCH 1367/3725] Add preliminary appveyor data --- CI/before_script.msvc.sh | 331 +++++++++++++++++++++++++++++++++++++++ CI/build.msvc.sh | 22 +++ appveyor.yml | 20 +++ 3 files changed, 373 insertions(+) create mode 100644 CI/before_script.msvc.sh create mode 100644 CI/build.msvc.sh create mode 100644 appveyor.yml diff --git a/CI/before_script.msvc.sh b/CI/before_script.msvc.sh new file mode 100644 index 000000000..9f94d5f31 --- /dev/null +++ b/CI/before_script.msvc.sh @@ -0,0 +1,331 @@ +#!/bin/bash + +while [ $# -gt 0 ]; do + ARG=$1 + shift + + case $ARG in + -v ) + VERBOSE=true ;; + + x86|i686|win32 ) + platform=i686 ;; + + x64_64|x64|win64 ) + platform=x86_64 ;; + + * ) + echo "Unknown arg $ARG." ;; + esac +done + +if [ -z $VERBOSE ]; then + STRIP="> /dev/null 2>&1" +fi + +cd $(dirname $0)/.. +which appveyor > /dev/null +if [ $? -eq 0 ]; then + VERSION="$(cat README.md | grep Version: | awk '{ print $3; }')-$(git rev-parse --short HEAD)" + appveyor UpdateBuild -Version "$VERSION" +fi + +download() { + if ! [ -f $2 ]; then + printf " Downloading $2... " + + if [ -z $VERBOSE ]; then + curl --silent --retry 10 -kLy 5 -o $2 $1 + RET=$? + else + curl --retry 10 -kLy 5 -o $2 $1 + RET=$? + fi + + if [ $RET -ne 0 ]; then + echo "Failed!" + else + echo "Done" + fi + + return $RET + else + echo " $2 exists, skipping." + fi + + return 0 +} + +real_pwd() { + pwd | sed "s,/\(.\),\1:," +} + +msbuild() { + /c/Program\ Files\ \(x86\)/MSBuild/12.0/Bin/MSBuild.exe $@ +} + +CMAKE_OPTS="" +add_cmake_opts() { + CMAKE_OPTS="$CMAKE_OPTS $@" +} + +if [ -z "$ARCH" ]; then + if [ -z "$platform" ]; then + ARCH=`uname -m` + else + ARCH="$platform" + fi +fi + +if [ $ARCH == x86_64 ]; then + ARCHNAME=x86-64 + ARCHSUFFIX=64 + BITS=64 + + BASE_OPTS="-G\"Visual Studio 12 2013 Win64\"" + add_cmake_opts "-G\"Visual Studio 12 2013 Win64\"" +else + ARCHNAME=x86 + ARCHSUFFIX=86 + BITS=32 + + BASE_OPTS="-G\"Visual Studio 12 2013\" -Tv120_xp" + add_cmake_opts "-G\"Visual Studio 12 2013\"" -Tv120_xp +fi + +mkdir -p deps +cd deps + +DEPS="`pwd`" + +echo "Downloading dependency packages." +echo + +# Boost +echo "Boost 1.58.0..." +download http://sourceforge.net/projects/boost/files/boost-binaries/1.58.0/boost_1_58_0-msvc-12.0-$BITS.exe boost-1.58.0-win$BITS.exe +echo + +# Bullet +echo "Bullet 2.83.4..." +download https://gist.github.com/ace13/dc6aad628d48338d590e/raw/Bullet-2.83.4-win$BITS.7z Bullet-2.83.4-win$BITS.zip +echo + +# FFmpeg +echo "FFmpeg 2.5.2..." +download http://ffmpeg.zeranoe.com/builds/win$BITS/shared/ffmpeg-2.5.2-win$BITS-shared.7z ffmpeg$BITS-2.5.2.7z +download http://ffmpeg.zeranoe.com/builds/win$BITS/dev/ffmpeg-2.5.2-win$BITS-dev.7z ffmpeg$BITS-2.5.2-dev.7z +echo + +# MyGUI +echo "MyGUI 3.2.2..." +download https://gist.github.com/ace13/dc6aad628d48338d590e/raw/MyGUI-3.2.2-win$BITS.7z MyGUI-3.2.2-win$BITS.7z +echo + +# Ogre +echo "Ogre 1.9..." +download https://gist.github.com/ace13/dc6aad628d48338d590e/raw/Ogre-1.9-win$BITS.7z Ogre-1.9-win$BITS.7z +echo + +# OpenAL +echo "OpenAL-Soft 1.16.0..." +download http://kcat.strangesoft.net/openal-soft-1.16.0-bin.zip OpenAL-Soft-1.16.0.zip +echo + +# Qt +echo "Qt 4.8.6..." +download http://sourceforge.net/projects/qt64ng/files/qt/$ARCHNAME/4.8.6/msvc2013/qt-4.8.6-x$ARCHSUFFIX-msvc2013.7z qt$BITS-4.8.6.7z +echo + +# SDL2 +echo "SDL 2.0.3 binaries..." +download https://www.libsdl.org/release/SDL2-devel-2.0.3-VC.zip SDL2-2.0.3.zip +echo + +cd .. + +# Set up dependencies +rm -rf build_$BITS +mkdir -p build_$BITS/deps +cd deps + +echo +echo "Extracting dependencies..." +echo + +# Boost +printf "Boost 1.58.0... " +cd ../build_$BITS/deps + +BOOST_SDK="`real_pwd`/Boost" + +$DEPS/boost_1_58_0-msvc-12.0-$BITS.exe //dir="$BOOST_SDK" //verysilent + +add_cmake_opts -DBOOST_ROOT="$BOOST_SDK" \ + -DBOOST_LIBRARYDIR="$BOOST_SDK/lib$BITS-msvc-12.0" + +cd $DEPS + +echo Done. +echo + +# Bullet +printf "Bullet 2.83.4... " +cd ../build_$BITS/deps + +eval 7z x -y $DEPS/Bullet-2.83.4-win$BITS.7z $STRIP +mv Bullet-2.83.4-win$BITS Bullet + +BULLET_SDK="`real_pwd`/Bullet" +add_cmake_opts -DBULLET_INCLUDE_DIR="$BULLET_SDK/include" \ + -DBULLET_COLLISION_LIBRARY="$BULLET_SDK/lib/BulletCollision.lib" \ + -DBULLET_COLLISION_LIBRARY_DEBUG="$BULLET_SDK/lib/BulletCollision_Debug.lib" \ + -DBULLET_DYNAMICS_LIBRARY="$BULLET_SDK/lib/BulletDynamics.lib" \ + -DBULLET_DYNAMICS_LIBRARY_DEBUG="$BULLET_SDK/lib/BulletDynamics_Debug.lib" \ + -DBULLET_MATH_LIBRARY="$BULLET_SDK/lib/LinearMath.lib" \ + -DBULLET_MATH_LIBRARY_DEBUG="$BULLET_SDK/lib/LinearMath_Debug.lib" + +cd $DEPS + +echo Done. +echo + +# FFmpeg +printf "FFmpeg 2.5.2... " +cd ../build_$BITS/deps + +eval 7z x -y $DEPS/ffmpeg$BITS-2.5.2.7z $STRIP +eval 7z x -y $DEPS/ffmpeg$BITS-2.5.2-dev.7z $STRIP + +mv ffmpeg-2.5.2-win$BITS-shared FFmpeg +cp -r ffmpeg-2.5.2-win$BITS-dev/* FFmpeg/ +rm -rf ffmpeg-2.5.2-win$BITS-dev + +FFMPEG_SDK="`real_pwd`/FFmpeg" +add_cmake_opts -DAVCODEC_INCLUDE_DIRS="$FFMPEG_SDK/include" \ + -DAVCODEC_LIBRARIES="$FFMPEG_SDK/lib/avcodec.lib" \ + -DAVDEVICE_INCLUDE_DIRS="$FFMPEG_SDK/include" \ + -DAVDEVICE_LIBRARIES="$FFMPEG_SDK/lib/avdevice.lib" \ + -DAVFORMAT_INCLUDE_DIRS="$FFMPEG_SDK/include" \ + -DAVFORMAT_LIBRARIES="$FFMPEG_SDK/lib/avformat.lib" \ + -DAVUTIL_INCLUDE_DIRS="$FFMPEG_SDK/include" \ + -DAVUTIL_LIBRARIES="$FFMPEG_SDK/lib/avutil.lib" \ + -DPOSTPROC_INCLUDE_DIRS="$FFMPEG_SDK/include" \ + -DPOSTPROC_LIBRARIES="$FFMPEG_SDK/lib/postproc.lib" \ + -DSWRESAMPLE_INCLUDE_DIRS="$FFMPEG_SDK/include" \ + -DSWRESAMPLE_LIBRARIES="$FFMPEG_SDK/lib/swresample.lib" \ + -DSWSCALE_INCLUDE_DIRS="$FFMPEG_SDK/include" \ + -DSWSCALE_LIBRARIES="$FFMPEG_SDK/lib/swscale.lib" + +if [ $BITS -eq 32 ]; then + add_cmake_opts "-DCMAKE_EXE_LINKER_FLAGS=\"/machine:X86 /safeseh:no\"" +fi + +cd $DEPS + +echo Done. +echo + +# Ogre +printf "Ogre 1.9... " +cd ../build_$BITS/deps + +eval 7z x -y $DEPS/Ogre-1.9-win$BITS.7z $STRIP +mv Ogre-1.9-win$BITS Ogre + +OGRE_SDK="`real_pwd`/Ogre" + +add_cmake_opts -DOGRE_SDK="$OGRE_SDK" + +cd $DEPS + +echo Done. +echo + +# MyGUI +printf "MyGUI 3.2.2... " +cd ../build_$BITS/deps + +eval 7z x -y $DEPS/MyGUI-3.2.2-win$BITS.7z $STRIP +mv MyGUI-3.2.2-win$BITS MyGUI + +MYGUI_SDK="`real_pwd`/MyGUI" + +add_cmake_opts -DMYGUISDK="$MYGUI_SDK" \ + -DMYGUI_PLATFORM_INCLUDE_DIRS="$MYGUI_SDK/include/MYGUI" \ + -DMYGUI_INCLUDE_DIRS="$MYGUI_SDK/include" \ + -DMYGUI_PREQUEST_FILE="$MYGUI_SDK/include/MYGUI/MyGUI_Prerequest.hpp" + +cd $DEPS + +echo Done. +echo + +# OpenAL +printf "OpenAL-Soft 1.16.0... " +eval 7z x -y OpenAL-Soft-1.16.0.zip $STRIP + +OPENAL_SDK="`real_pwd`/openal-soft-1.16.0-bin" + +add_cmake_opts -DOPENAL_INCLUDE_DIR="$OPENAL_SDK/include" \ + -DOPENAL_LIBRARY="$OPENAL_SDK/libs/Win$BITS/OpenAL32.lib" + +echo Done. +echo + +# Qt +printf "Qt 4.8.6 binaries... " +cd ../build_$BITS/deps + +eval 7z x -y $DEPS/qt$BITS-4.8.6.7z $STRIP +mv qt-4.8.6-* Qt + +QT_SDK="`real_pwd`/Qt" + +cd $QT_SDK +eval qtbinpatcher.exe $STRIP + +add_cmake_opts -DQT_QMAKE_EXECUTABLE="$QT_SDK/bin/qmake.exe" + +cd $DEPS + +echo Done. +echo + +# SDL2 +printf "SDL 2.0.3 binaries... " +eval 7z x -y SDL2-2.0.3.zip $STRIP + +SDL_SDK="`real_pwd`/SDL2-2.0.3" +add_cmake_opts -DSDL2_INCLUDE_DIR="$SDL_SDK/include" \ + -DSDL2MAIN_LIBRARY="$SDL_SDK/lib/x$ARCHSUFFIX/SDL2main.lib" \ + -DSDL2_LIBRARY_PATH="$SDL_SDK/lib/x$ARCHSUFFIX/SDL2.lib" \ + -DSDL2_LIBRARY_ONLY="$SDL_SDK/lib/x$ARCHSUFFIX/SDL2.lib" + +cd $DEPS + +echo Done. +echo + +cd ../build_$BITS + +echo "Building OpenMW." + +add_cmake_opts -DBUILD_BSATOOL=no \ + -DBUILD_ESMTOOL=no \ + -DBUILD_MYGUI_PLUGIN=no + +if [ -z $VERBOSE ]; then + printf " Configuring... " +else + echo " cmake .. $CMAKE_OPTS" +fi + +eval cmake .. $CMAKE_OPTS $STRIP +RET=$? + +if [ -z $VERBOSE ]; then echo Done.; fi + +echo + +exit $RET \ No newline at end of file diff --git a/CI/build.msvc.sh b/CI/build.msvc.sh new file mode 100644 index 000000000..101aa8827 --- /dev/null +++ b/CI/build.msvc.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +while [ $# -gt 0 ]; do + ARG=$1 + shift + + case $ARG in + x86|i686|win32 ) + BITS=32 ;; + + x64_64|x64|win64 ) + BITS=64 ;; + + * ) + echo "Unknown arg $ARG." + exit 1 ;; + esac +done + +cd $(dirname $0)/../build_$BITS + +msbuild OpenMW.sln //t:Build //p:Configuration=Release //m:8 //logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 000000000..3bb773d28 --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,20 @@ +version: "{build}" + +platform: + - Win32 + - x64 + +matrix: + fast_finish: true + +init: + - cmd: cmake --version + - cmd: msbuild /version + +clone_folder: C:\projects\openmw + +build: + - cmd: sh C:\projects\openmw\CI\build.msvc.sh %platform% + +before_build: + - cmd: sh C:\projects\openmw\CI\before_script.msvc.sh %platform% From db521cddadc51875dcc43ab1108506fc04668ac4 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Tue, 2 Jun 2015 23:23:03 +0200 Subject: [PATCH 1368/3725] Needs to be spaces and not tabs --- appveyor.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 3bb773d28..399be0c38 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,20 +1,20 @@ version: "{build}" platform: - - Win32 - - x64 + - Win32 + - x64 matrix: - fast_finish: true + fast_finish: true init: - - cmd: cmake --version - - cmd: msbuild /version + - cmd: cmake --version + - cmd: msbuild /version clone_folder: C:\projects\openmw build: - - cmd: sh C:\projects\openmw\CI\build.msvc.sh %platform% + - cmd: sh C:\projects\openmw\CI\build.msvc.sh %platform% before_build: - - cmd: sh C:\projects\openmw\CI\before_script.msvc.sh %platform% + - cmd: sh C:\projects\openmw\CI\before_script.msvc.sh %platform% From cd4042109a5046707dfa1f07d93e41f9a34d569b Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Tue, 2 Jun 2015 23:29:47 +0200 Subject: [PATCH 1369/3725] Fix the script issues --- CI/build.msvc.sh | 25 ++++++++++--------------- appveyor.yml | 8 ++++++-- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/CI/build.msvc.sh b/CI/build.msvc.sh index 101aa8827..b19325689 100644 --- a/CI/build.msvc.sh +++ b/CI/build.msvc.sh @@ -1,22 +1,17 @@ #!/bin/bash -while [ $# -gt 0 ]; do - ARG=$1 - shift +case $1 in + x86|i686|win32 ) + BITS=32 ;; - case $ARG in - x86|i686|win32 ) - BITS=32 ;; + x64_64|x64|win64 ) + BITS=64 ;; - x64_64|x64|win64 ) - BITS=64 ;; - - * ) - echo "Unknown arg $ARG." - exit 1 ;; - esac -done + * ) + echo "Unknown platform $ARG." + exit 1 ;; +esac cd $(dirname $0)/../build_$BITS -msbuild OpenMW.sln //t:Build //p:Configuration=Release //m:8 //logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" +msbuild OpenMW.sln //t:Build //p:Configuration=$2 //m:8 //logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" diff --git a/appveyor.yml b/appveyor.yml index 399be0c38..896c0b464 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -4,6 +4,10 @@ platform: - Win32 - x64 +configuration: + - Debug + - Release + matrix: fast_finish: true @@ -13,8 +17,8 @@ init: clone_folder: C:\projects\openmw -build: - - cmd: sh C:\projects\openmw\CI\build.msvc.sh %platform% +build_script: + - cmd: sh C:\projects\openmw\CI\build.msvc.sh %platform% %configuration% before_build: - cmd: sh C:\projects\openmw\CI\before_script.msvc.sh %platform% From d7494128a2edd645fa2b4e7bd9a30964a2b3decf Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Tue, 2 Jun 2015 23:50:52 +0200 Subject: [PATCH 1370/3725] More script fixes --- CI/before_script.msvc.sh | 67 ++++++++++++++++++++++++---------------- CI/build.msvc.sh | 10 +++--- appveyor.yml | 20 ++++++++++-- 3 files changed, 64 insertions(+), 33 deletions(-) diff --git a/CI/before_script.msvc.sh b/CI/before_script.msvc.sh index 9f94d5f31..8c44a5b9e 100644 --- a/CI/before_script.msvc.sh +++ b/CI/before_script.msvc.sh @@ -8,14 +8,9 @@ while [ $# -gt 0 ]; do -v ) VERBOSE=true ;; - x86|i686|win32 ) - platform=i686 ;; - - x64_64|x64|win64 ) - platform=x86_64 ;; - * ) - echo "Unknown arg $ARG." ;; + echo "Unknown arg $ARG." + exit 1 ;; esac done @@ -23,9 +18,14 @@ if [ -z $VERBOSE ]; then STRIP="> /dev/null 2>&1" fi -cd $(dirname $0)/.. -which appveyor > /dev/null -if [ $? -eq 0 ]; then +if [ -z $APPVEYOR ]; then + echo "Running prebuild outside of Appveyor." + + cd $(dirname $0)/.. +else + echo "Running prebuild in Appveyor." + + cd $APPVEYOR_BUILD_FOLDER VERSION="$(cat README.md | grep Version: | awk '{ print $3; }')-$(git rev-parse --short HEAD)" appveyor UpdateBuild -Version "$VERSION" fi @@ -70,28 +70,43 @@ add_cmake_opts() { } if [ -z "$ARCH" ]; then - if [ -z "$platform" ]; then + if [ -z "$PLATFORM" ]; then ARCH=`uname -m` else - ARCH="$platform" + ARCH="$PLATFORM" fi fi -if [ $ARCH == x86_64 ]; then - ARCHNAME=x86-64 - ARCHSUFFIX=64 - BITS=64 +case $PLATFORM in + x64|x86_64|x86-64|win64|Win64 ) + ARCHNAME=x86-64 + ARCHSUFFIX=64 + BITS=64 - BASE_OPTS="-G\"Visual Studio 12 2013 Win64\"" - add_cmake_opts "-G\"Visual Studio 12 2013 Win64\"" -else - ARCHNAME=x86 - ARCHSUFFIX=86 - BITS=32 + BASE_OPTS="-G\"Visual Studio 12 2013 Win64\"" + add_cmake_opts "-G\"Visual Studio 12 2013 Win64\"" + ;; - BASE_OPTS="-G\"Visual Studio 12 2013\" -Tv120_xp" - add_cmake_opts "-G\"Visual Studio 12 2013\"" -Tv120_xp -fi + x32|x86|i686|i386|win32|Win32 ) + ARCHNAME=x86 + ARCHSUFFIX=86 + BITS=32 + + BASE_OPTS="-G\"Visual Studio 12 2013\" -Tv120_xp" + add_cmake_opts "-G\"Visual Studio 12 2013\"" -Tv120_xp + ;; + + * ) + echo "Unknown platform $PLATFORM." + exit 1 + ;; +esac + +echo +echo "==========================" +echo "Starting prebuild on win$BITS" +echo "==========================" +echo mkdir -p deps cd deps @@ -108,7 +123,7 @@ echo # Bullet echo "Bullet 2.83.4..." -download https://gist.github.com/ace13/dc6aad628d48338d590e/raw/Bullet-2.83.4-win$BITS.7z Bullet-2.83.4-win$BITS.zip +download https://gist.github.com/ace13/dc6aad628d48338d590e/raw/Bullet-2.83.4-win$BITS.7z Bullet-2.83.4-win$BITS.7z echo # FFmpeg diff --git a/CI/build.msvc.sh b/CI/build.msvc.sh index b19325689..34ce3d062 100644 --- a/CI/build.msvc.sh +++ b/CI/build.msvc.sh @@ -1,17 +1,17 @@ #!/bin/bash -case $1 in - x86|i686|win32 ) +case $PLATFORM in + x32|x86|i686|i386|win32|Win32 ) BITS=32 ;; - x64_64|x64|win64 ) + x64|x86_64|x86-64|win64|Win64 ) BITS=64 ;; * ) - echo "Unknown platform $ARG." + echo "Unknown platform $PLATFORM." exit 1 ;; esac cd $(dirname $0)/../build_$BITS -msbuild OpenMW.sln //t:Build //p:Configuration=$2 //m:8 //logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" +msbuild OpenMW.sln //t:Build //p:Configuration=$CONFIGURATION //m:8 //logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" diff --git a/appveyor.yml b/appveyor.yml index 896c0b464..f466b2b82 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -11,14 +11,30 @@ configuration: matrix: fast_finish: true +cache: + - C:\projects\openmw\deps\Bullet-2.83.4-win32.7z -> CI/before_script.msvc.sh + - C:\projects\openmw\deps\Bullet-2.83.4-win64.7z -> CI/before_script.msvc.sh + - C:\projects\openmw\deps\MyGUI-3.2.2-win32.7z -> CI/before_script.msvc.sh + - C:\projects\openmw\deps\MyGUI-3.2.2-win64.7z -> CI/before_script.msvc.sh + - C:\projects\openmw\deps\Ogre-1.9-win32.7z -> CI/before_script.msvc.sh + - C:\projects\openmw\deps\Ogre-1.9-win64.7z -> CI/before_script.msvc.sh + - C:\projects\openmw\deps\ffmpeg32-2.5.2.7z -> CI/before_script.msvc.sh + - C:\projects\openmw\deps\ffmpeg64-2.5.2-dev.7z -> CI/before_script.msvc.sh + - C:\projects\openmw\deps\ffmpeg64-2.5.2.7z -> CI/before_script.msvc.sh + - C:\projects\openmw\deps\ffmpeg64-2.5.2-dev.7z -> CI/before_script.msvc.sh + - C:\projects\openmw\deps\OpenAL-Soft-1.16.0.zip -> CI/before_script.msvc.sh + - C:\projects\openmw\deps\SDL2-2.0.3.zip -> CI/before_script.msvc.sh + init: + - cmd: bash --version - cmd: cmake --version - cmd: msbuild /version + - cmd: echo. clone_folder: C:\projects\openmw build_script: - - cmd: sh C:\projects\openmw\CI\build.msvc.sh %platform% %configuration% + - cmd: sh C:\projects\openmw\CI\build.msvc.sh before_build: - - cmd: sh C:\projects\openmw\CI\before_script.msvc.sh %platform% + - cmd: sh C:\projects\openmw\CI\before_script.msvc.sh From 6993fbaece237f6e0a9d49419e0fd6c31241126a Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Tue, 2 Jun 2015 23:52:34 +0200 Subject: [PATCH 1371/3725] And yet more issues slip past --- CI/before_script.msvc.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CI/before_script.msvc.sh b/CI/before_script.msvc.sh index 8c44a5b9e..ca4479dea 100644 --- a/CI/before_script.msvc.sh +++ b/CI/before_script.msvc.sh @@ -174,7 +174,7 @@ cd ../build_$BITS/deps BOOST_SDK="`real_pwd`/Boost" -$DEPS/boost_1_58_0-msvc-12.0-$BITS.exe //dir="$BOOST_SDK" //verysilent +$DEPS/boost-1.58.0-win$BITS.exe //dir="$BOOST_SDK" //verysilent add_cmake_opts -DBOOST_ROOT="$BOOST_SDK" \ -DBOOST_LIBRARYDIR="$BOOST_SDK/lib$BITS-msvc-12.0" From 0a1454d5ecbba634cb2256dee0611e31a988786a Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Wed, 3 Jun 2015 00:51:22 +0200 Subject: [PATCH 1372/3725] Final fixes, moving to Appveyor unstable for boost --- CI/before_script.msvc.sh | 72 +++++++++++++++++++++++++++++++--------- appveyor.yml | 6 ++-- 2 files changed, 60 insertions(+), 18 deletions(-) diff --git a/CI/before_script.msvc.sh b/CI/before_script.msvc.sh index ca4479dea..3bd9c490f 100644 --- a/CI/before_script.msvc.sh +++ b/CI/before_script.msvc.sh @@ -21,7 +21,8 @@ fi if [ -z $APPVEYOR ]; then echo "Running prebuild outside of Appveyor." - cd $(dirname $0)/.. + DIR=$(echo "$0" | sed "s,\\\\,/,g" | sed "s,\(.\):,/\\1,") + cd $(dirname "$DIR") else echo "Running prebuild in Appveyor." @@ -30,6 +31,33 @@ else appveyor UpdateBuild -Version "$VERSION" fi +run_cmd() { + CMD="$1" + shift + + if [ -z $VERBOSE ]; then + eval $CMD $@ > output.log 2>&1 + RET=$? + + if [ $RET -ne 0 ]; then + if [ -z $APPVEYOR ]; then + echo "Command $CMD failed, output can be found in `real_pwd`/output.log" + exit $RET + else + appveyor PushArtifact output.log -DeploymentName $CMD-output.log + appveyor AddMessage "Command $CMD failed ($RET), output has been pushed as an artifact." -Category Error + fi + else + rm output.log + fi + + return $RET + else + eval $CMD $@ + return $? + fi +} + download() { if ! [ -f $2 ]; then printf " Downloading $2... " @@ -117,9 +145,11 @@ echo "Downloading dependency packages." echo # Boost -echo "Boost 1.58.0..." -download http://sourceforge.net/projects/boost/files/boost-binaries/1.58.0/boost_1_58_0-msvc-12.0-$BITS.exe boost-1.58.0-win$BITS.exe -echo +if [ -z $APPVEYOR ]; then + echo "Boost 1.58.0..." + download http://sourceforge.net/projects/boost/files/boost-binaries/1.58.0/boost_1_58_0-msvc-12.0-$BITS.exe boost-1.58.0-win$BITS.exe + echo +fi # Bullet echo "Bullet 2.83.4..." @@ -169,20 +199,27 @@ echo "Extracting dependencies..." echo # Boost -printf "Boost 1.58.0... " -cd ../build_$BITS/deps +if [ -z $APPVEYOR ]; then + printf "Boost 1.58.0... " + cd ../build_$BITS/deps -BOOST_SDK="`real_pwd`/Boost" + BOOST_SDK="`real_pwd`/Boost" -$DEPS/boost-1.58.0-win$BITS.exe //dir="$BOOST_SDK" //verysilent + $DEPS/boost-1.58.0-win$BITS.exe //dir="$BOOST_SDK" //verysilent -add_cmake_opts -DBOOST_ROOT="$BOOST_SDK" \ - -DBOOST_LIBRARYDIR="$BOOST_SDK/lib$BITS-msvc-12.0" + add_cmake_opts -DBOOST_ROOT="$BOOST_SDK" \ + -DBOOST_LIBRARYDIR="$BOOST_SDK/lib$BITS-msvc-12.0" -cd $DEPS + cd $DEPS -echo Done. -echo + echo Done. + echo +else + # Appveyor unstable has all the boost we need already + BOOST_SDK="c:/Libraries/boost" + add_cmake_opts -DBOOST_ROOT="$BOOST_SDK" \ + -DBOOST_LIBRARYDIR="$BOOST_SDK/lib$BITS-msvc-12.0" +fi # Bullet printf "Bullet 2.83.4... " @@ -269,7 +306,7 @@ MYGUI_SDK="`real_pwd`/MyGUI" add_cmake_opts -DMYGUISDK="$MYGUI_SDK" \ -DMYGUI_PLATFORM_INCLUDE_DIRS="$MYGUI_SDK/include/MYGUI" \ -DMYGUI_INCLUDE_DIRS="$MYGUI_SDK/include" \ - -DMYGUI_PREQUEST_FILE="$MYGUI_SDK/include/MYGUI/MyGUI_Prerequest.hpp" + -DMYGUI_PREQUEST_FILE="$MYGUI_SDK/include/MYGUI/MyGUI_Prerequest.h" cd $DEPS @@ -336,10 +373,13 @@ else echo " cmake .. $CMAKE_OPTS" fi -eval cmake .. $CMAKE_OPTS $STRIP +run_cmd cmake .. $CMAKE_OPTS RET=$? -if [ -z $VERBOSE ]; then echo Done.; fi +if [ -z $VERBOSE ]; then + if [ $RET -eq 0 ]; then echo Done.; fi + else echo Failed!; fi +fi echo diff --git a/appveyor.yml b/appveyor.yml index f466b2b82..890b9684b 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -11,6 +11,8 @@ configuration: matrix: fast_finish: true +os: unstable + cache: - C:\projects\openmw\deps\Bullet-2.83.4-win32.7z -> CI/before_script.msvc.sh - C:\projects\openmw\deps\Bullet-2.83.4-win64.7z -> CI/before_script.msvc.sh @@ -34,7 +36,7 @@ init: clone_folder: C:\projects\openmw build_script: - - cmd: sh C:\projects\openmw\CI\build.msvc.sh + - cmd: bash --login C:\projects\openmw\CI\build.msvc.sh before_build: - - cmd: sh C:\projects\openmw\CI\before_script.msvc.sh + - cmd: bash --login C:\projects\openmw\CI\before_script.msvc.sh From 10f938ff8763960afb873c283c57afd829690ede Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Jun 2015 01:18:03 +0200 Subject: [PATCH 1373/3725] Add comment --- components/myguiplatform/myguirendermanager.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/myguiplatform/myguirendermanager.cpp b/components/myguiplatform/myguirendermanager.cpp index e2f2f9820..bf1d66fe8 100644 --- a/components/myguiplatform/myguirendermanager.cpp +++ b/components/myguiplatform/myguirendermanager.cpp @@ -195,7 +195,9 @@ public: META_Object(osgMyGUI, Drawable) private: + // double buffering approach, to avoid the need for synchronization with the draw thread std::vector mBatchVector[2]; + int mWriteTo; mutable int mReadFrom; }; From ba9b21bc296f25d5dd1d951badd44544fd195ee7 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Wed, 3 Jun 2015 01:18:10 +0200 Subject: [PATCH 1374/3725] Moving dependencies to a better place --- CI/before_script.msvc.sh | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/CI/before_script.msvc.sh b/CI/before_script.msvc.sh index 3bd9c490f..56d56762f 100644 --- a/CI/before_script.msvc.sh +++ b/CI/before_script.msvc.sh @@ -44,8 +44,10 @@ run_cmd() { echo "Command $CMD failed, output can be found in `real_pwd`/output.log" exit $RET else - appveyor PushArtifact output.log -DeploymentName $CMD-output.log - appveyor AddMessage "Command $CMD failed ($RET), output has been pushed as an artifact." -Category Error + 7z a output.7z output.log > /dev/null 2>&1 + + appveyor PushArtifact output.7z -DeploymentName $CMD-output.7z + appveyor AddMessage "Command $CMD failed (code $RET), output has been pushed as an artifact." -Category Error fi else rm output.log @@ -153,7 +155,7 @@ fi # Bullet echo "Bullet 2.83.4..." -download https://gist.github.com/ace13/dc6aad628d48338d590e/raw/Bullet-2.83.4-win$BITS.7z Bullet-2.83.4-win$BITS.7z +download http://www.lysator.liu.se/~ace/OpenMW/deps/Bullet-2.83.4-win$BITS.7z Bullet-2.83.4-win$BITS.7z echo # FFmpeg @@ -164,12 +166,12 @@ echo # MyGUI echo "MyGUI 3.2.2..." -download https://gist.github.com/ace13/dc6aad628d48338d590e/raw/MyGUI-3.2.2-win$BITS.7z MyGUI-3.2.2-win$BITS.7z +download http://www.lysator.liu.se/~ace/OpenMW/deps/MyGUI-3.2.2-win$BITS.7z MyGUI-3.2.2-win$BITS.7z echo # Ogre echo "Ogre 1.9..." -download https://gist.github.com/ace13/dc6aad628d48338d590e/raw/Ogre-1.9-win$BITS.7z Ogre-1.9-win$BITS.7z +download http://www.lysator.liu.se/~ace/OpenMW/deps/Ogre-1.9-win$BITS.7z Ogre-1.9-win$BITS.7z echo # OpenAL @@ -196,7 +198,6 @@ cd deps echo echo "Extracting dependencies..." -echo # Boost if [ -z $APPVEYOR ]; then @@ -213,7 +214,6 @@ if [ -z $APPVEYOR ]; then cd $DEPS echo Done. - echo else # Appveyor unstable has all the boost we need already BOOST_SDK="c:/Libraries/boost" @@ -240,7 +240,6 @@ add_cmake_opts -DBULLET_INCLUDE_DIR="$BULLET_SDK/include" \ cd $DEPS echo Done. -echo # FFmpeg printf "FFmpeg 2.5.2... " @@ -276,7 +275,6 @@ fi cd $DEPS echo Done. -echo # Ogre printf "Ogre 1.9... " @@ -292,7 +290,6 @@ add_cmake_opts -DOGRE_SDK="$OGRE_SDK" cd $DEPS echo Done. -echo # MyGUI printf "MyGUI 3.2.2... " @@ -311,7 +308,6 @@ add_cmake_opts -DMYGUISDK="$MYGUI_SDK" \ cd $DEPS echo Done. -echo # OpenAL printf "OpenAL-Soft 1.16.0... " @@ -323,10 +319,9 @@ add_cmake_opts -DOPENAL_INCLUDE_DIR="$OPENAL_SDK/include" \ -DOPENAL_LIBRARY="$OPENAL_SDK/libs/Win$BITS/OpenAL32.lib" echo Done. -echo # Qt -printf "Qt 4.8.6 binaries... " +printf "Qt 4.8.6... " cd ../build_$BITS/deps eval 7z x -y $DEPS/qt$BITS-4.8.6.7z $STRIP @@ -342,10 +337,9 @@ add_cmake_opts -DQT_QMAKE_EXECUTABLE="$QT_SDK/bin/qmake.exe" cd $DEPS echo Done. -echo # SDL2 -printf "SDL 2.0.3 binaries... " +printf "SDL 2.0.3... " eval 7z x -y SDL2-2.0.3.zip $STRIP SDL_SDK="`real_pwd`/SDL2-2.0.3" @@ -361,7 +355,7 @@ echo cd ../build_$BITS -echo "Building OpenMW." +echo "Building OpenMW..." add_cmake_opts -DBUILD_BSATOOL=no \ -DBUILD_ESMTOOL=no \ @@ -377,8 +371,8 @@ run_cmd cmake .. $CMAKE_OPTS RET=$? if [ -z $VERBOSE ]; then - if [ $RET -eq 0 ]; then echo Done.; fi - else echo Failed!; fi + if [ $RET -eq 0 ]; then echo Done. + else echo Failed.; fi fi echo From cdd062300946e7ce38152a28f2ae55c5ba754428 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Jun 2015 01:18:36 +0200 Subject: [PATCH 1375/3725] Terrain rendering --- CMakeLists.txt | 2 +- apps/opencs/model/world/data.cpp | 5 + apps/opencs/model/world/data.hpp | 2 + apps/opencs/view/render/cell.cpp | 20 +- apps/opencs/view/render/cell.hpp | 2 - apps/opencs/view/render/terrainstorage.cpp | 3 +- apps/openmw/CMakeLists.txt | 4 +- apps/openmw/mwrender/localmap.cpp | 4 +- apps/openmw/mwrender/renderingmanager.cpp | 20 +- apps/openmw/mwrender/renderingmanager.hpp | 8 + apps/openmw/mwrender/terrainstorage.cpp | 3 +- apps/openmw/mwrender/terrainstorage.hpp | 2 +- apps/openmw/mwrender/vismask.hpp | 7 +- apps/openmw/mwrender/water.cpp | 7 +- apps/openmw/mwrender/water.hpp | 8 +- apps/openmw/mwworld/worldimp.cpp | 4 +- components/CMakeLists.txt | 4 +- components/esm/loadland.hpp | 2 +- components/esmterrain/storage.cpp | 227 ++++---- components/esmterrain/storage.hpp | 48 +- components/terrain/buffercache.cpp | 129 ++--- components/terrain/buffercache.hpp | 14 +- components/terrain/chunk.cpp | 169 ------ components/terrain/chunk.hpp | 75 --- components/terrain/defaultworld.cpp | 336 ----------- components/terrain/defaultworld.hpp | 177 ------ components/terrain/defs.hpp | 42 +- components/terrain/material.cpp | 375 ++----------- components/terrain/material.hpp | 68 +-- components/terrain/quadtreenode.cpp | 611 --------------------- components/terrain/quadtreenode.hpp | 189 ------- components/terrain/storage.cpp | 2 + components/terrain/storage.hpp | 41 +- components/terrain/terraingrid.cpp | 221 ++++---- components/terrain/terraingrid.hpp | 49 +- components/terrain/world.cpp | 56 +- components/terrain/world.hpp | 82 +-- 37 files changed, 529 insertions(+), 2489 deletions(-) delete mode 100644 components/terrain/chunk.cpp delete mode 100644 components/terrain/chunk.hpp delete mode 100644 components/terrain/defaultworld.cpp delete mode 100644 components/terrain/defaultworld.hpp delete mode 100644 components/terrain/quadtreenode.cpp delete mode 100644 components/terrain/quadtreenode.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 43d40c2ef..d13437214 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -174,7 +174,7 @@ if (${OGRE_VERSION} VERSION_LESS "1.9") message(FATAL_ERROR "OpenMW requires Ogre 1.9 or later, please install the latest stable version from http://ogre3d.org") endif() -find_package(OpenSceneGraph 3.2.0 REQUIRED osgDB osgViewer osgGA osgAnimation osgParticle osgQt osgUtil) +find_package(OpenSceneGraph 3.2.0 REQUIRED osgDB osgViewer osgGA osgAnimation osgParticle osgQt osgUtil osgFX) include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS}) find_package(MyGUI REQUIRED) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 064e96150..9772a68fa 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -488,6 +488,11 @@ Resource::ResourceSystem* CSMWorld::Data::getResourceSystem() return &mResourceSystem; } +const Resource::ResourceSystem* CSMWorld::Data::getResourceSystem() const +{ + return &mResourceSystem; +} + const CSMWorld::IdCollection& CSMWorld::Data::getGlobals() const { return mGlobals; diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 93cd46d86..a41946687 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -140,6 +140,8 @@ namespace CSMWorld Resource::ResourceSystem* getResourceSystem(); + const Resource::ResourceSystem* getResourceSystem() const; + const IdCollection& getGlobals() const; IdCollection& getGlobals(); diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index 343d0d2e6..063413248 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -64,7 +64,6 @@ CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::st addObjects (0, rows-1); - /* const CSMWorld::IdCollection& land = mData.getLand(); int landIndex = land.searchId(mId); if (landIndex != -1) @@ -72,27 +71,18 @@ CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::st const ESM::Land* esmLand = land.getRecord(mId).get().mLand.get(); if(esmLand && esmLand->mDataTypes&ESM::Land::DATA_VHGT) { - mTerrain.reset(new Terrain::TerrainGrid(sceneManager, new TerrainStorage(mData), Element_Terrain, true, - Terrain::Align_XY)); + mTerrain.reset(new Terrain::TerrainGrid(mCellNode, data.getResourceSystem(), NULL, new TerrainStorage(mData), Element_Terrain<<1)); mTerrain->loadCell(esmLand->mX, esmLand->mY); - //float verts = ESM::Land::LAND_SIZE; - //float worldsize = ESM::Land::REAL_SIZE; mX = esmLand->mX; mY = esmLand->mY; - //mPhysics->addHeightField(sceneManager, - // esmLand->mLandData->mHeights, mX, mY, 0, worldsize / (verts-1), verts); } } - */ } CSVRender::Cell::~Cell() { - //if (mTerrain.get()) - // mPhysics->removeHeightField(mSceneMgr, mX, mY); - for (std::map::iterator iter (mObjects.begin()); iter!=mObjects.end(); ++iter) delete iter->second; @@ -221,11 +211,3 @@ bool CSVRender::Cell::referenceAdded (const QModelIndex& parent, int start, int return addObjects (start, end); } - -float CSVRender::Cell::getTerrainHeightAt(const Ogre::Vector3 &pos) const -{ - if(mTerrain.get() != NULL) - return mTerrain->getHeightAt(pos); - else - return -std::numeric_limits::max(); -} diff --git a/apps/opencs/view/render/cell.hpp b/apps/opencs/view/render/cell.hpp index 259ab1779..f4272b887 100644 --- a/apps/opencs/view/render/cell.hpp +++ b/apps/opencs/view/render/cell.hpp @@ -75,8 +75,6 @@ namespace CSVRender /// \return Did this call result in a modification of the visual representation of /// this cell? bool referenceAdded (const QModelIndex& parent, int start, int end); - - float getTerrainHeightAt(const Ogre::Vector3 &pos) const; }; } diff --git a/apps/opencs/view/render/terrainstorage.cpp b/apps/opencs/view/render/terrainstorage.cpp index a14eea5dd..fe302cef1 100644 --- a/apps/opencs/view/render/terrainstorage.cpp +++ b/apps/opencs/view/render/terrainstorage.cpp @@ -4,7 +4,8 @@ namespace CSVRender { TerrainStorage::TerrainStorage(const CSMWorld::Data &data) - : mData(data) + : ESMTerrain::Storage(data.getResourceSystem()->getVFS()) + , mData(data) { } diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index bb71cb6c9..ef0c4e135 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -22,8 +22,8 @@ source_group(game FILES ${GAME} ${GAME_HEADER}) add_openmw_dir (mwrender actors objects renderingmanager animation rotatecontroller sky npcanimation vismask creatureanimation effectmanager util renderinginterface pathgrid rendermode weaponanimation - bulletdebugdraw globalmap characterpreview camera localmap water -# occlusionquery shadows ripplesimulation terrainstorage + bulletdebugdraw globalmap characterpreview camera localmap water terrainstorage +# occlusionquery shadows ripplesimulation ) add_openmw_dir (mwinput diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 3003e4736..16957a585 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -157,7 +157,7 @@ osg::ref_ptr LocalMap::createOrthographicCamera(float x, float y, f camera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); camera->setRenderOrder(osg::Camera::PRE_RENDER); - camera->setCullMask(MWRender::Mask_Scene|MWRender::Mask_Water); + camera->setCullMask(Mask_Scene|Mask_Water|Mask_Terrain); camera->setNodeMask(Mask_RenderToTexture); osg::ref_ptr stateset = new osg::StateSet; @@ -309,7 +309,7 @@ void LocalMap::requestExteriorMap(MWWorld::CellStore* cell) void LocalMap::requestInteriorMap(MWWorld::CellStore* cell) { osg::ComputeBoundsVisitor computeBoundsVisitor; - computeBoundsVisitor.setTraversalMask(Mask_Scene); + computeBoundsVisitor.setTraversalMask(Mask_Scene|Mask_Terrain); mSceneRoot->accept(computeBoundsVisitor); osg::BoundingBox bounds = computeBoundsVisitor.getBoundingBox(); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index a708bbe88..6205c3ad8 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -26,6 +26,8 @@ #include #include +#include + #include #include "sky.hpp" @@ -35,6 +37,7 @@ #include "pathgrid.hpp" #include "camera.hpp" #include "water.hpp" +#include "terrainstorage.hpp" namespace MWRender { @@ -132,7 +135,10 @@ namespace MWRender mEffectManager.reset(new EffectManager(lightRoot, mResourceSystem)); - mWater.reset(new Water(lightRoot, mResourceSystem)); + mWater.reset(new Water(lightRoot, mResourceSystem, mViewer->getIncrementalCompileOperation())); + + mTerrain.reset(new Terrain::TerrainGrid(lightRoot, mResourceSystem, mViewer->getIncrementalCompileOperation(), + new TerrainStorage(mResourceSystem->getVFS(), false), Mask_Terrain)); mCamera.reset(new Camera(mViewer->getCamera())); @@ -236,12 +242,18 @@ namespace MWRender mPathgrid->addCell(store); mWater->changeCell(store); + + if (store->getCell()->isExterior()) + mTerrain->loadCell(store->getCell()->getGridX(), store->getCell()->getGridY()); } void RenderingManager::removeCell(const MWWorld::CellStore *store) { mPathgrid->removeCell(store); mObjects->removeCell(store); + + if (store->getCell()->isExterior()) + mTerrain->unloadCell(store->getCell()->getGridX(), store->getCell()->getGridY()); } void RenderingManager::setSkyEnabled(bool enabled) @@ -482,7 +494,6 @@ namespace MWRender void RenderingManager::clear() { - //mLocalMap->clear(); notifyWorldSpaceChanged(); } @@ -595,6 +606,11 @@ namespace MWRender return mNearClip; } + float RenderingManager::getTerrainHeightAt(const osg::Vec3f &pos) + { + return mTerrain->getHeightAt(pos); + } + bool RenderingManager::vanityRotateCamera(const float *rot) { if(!mCamera->isVanityOrPreviewModeEnabled()) diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index d90a75c86..c22d3c7bf 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -32,6 +32,11 @@ namespace ESM struct Cell; } +namespace Terrain +{ + class World; +} + namespace MWRender { @@ -119,6 +124,8 @@ namespace MWRender float getNearClipDistance() const; + float getTerrainHeightAt(const osg::Vec3f& pos); + // camera stuff bool vanityRotateCamera(const float *rot); void setCameraDistance(float dist, bool adjust, bool override); @@ -147,6 +154,7 @@ namespace MWRender std::auto_ptr mPathgrid; std::auto_ptr mObjects; std::auto_ptr mWater; + std::auto_ptr mTerrain; std::auto_ptr mSky; std::auto_ptr mEffectManager; std::auto_ptr mPlayerAnimation; diff --git a/apps/openmw/mwrender/terrainstorage.cpp b/apps/openmw/mwrender/terrainstorage.cpp index 8ad2ea321..269e7f99f 100644 --- a/apps/openmw/mwrender/terrainstorage.cpp +++ b/apps/openmw/mwrender/terrainstorage.cpp @@ -9,7 +9,8 @@ namespace MWRender { - TerrainStorage::TerrainStorage(bool preload) + TerrainStorage::TerrainStorage(const VFS::Manager* vfs, bool preload) + : ESMTerrain::Storage(vfs) { if (preload) { diff --git a/apps/openmw/mwrender/terrainstorage.hpp b/apps/openmw/mwrender/terrainstorage.hpp index e6f4a04ad..93531a552 100644 --- a/apps/openmw/mwrender/terrainstorage.hpp +++ b/apps/openmw/mwrender/terrainstorage.hpp @@ -16,7 +16,7 @@ namespace MWRender ///@param preload Preload all Land records at startup? If using the multithreaded terrain component, this /// should be set to "true" in order to avoid race conditions. - TerrainStorage(bool preload); + TerrainStorage(const VFS::Manager* vfs, bool preload); /// Get bounds of the whole terrain in cell units virtual void getBounds(float& minX, float& maxX, float& minY, float& maxY); diff --git a/apps/openmw/mwrender/vismask.hpp b/apps/openmw/mwrender/vismask.hpp index 3a0336f82..b794ac24a 100644 --- a/apps/openmw/mwrender/vismask.hpp +++ b/apps/openmw/mwrender/vismask.hpp @@ -16,13 +16,14 @@ namespace MWRender Mask_Player = (1<<4), Mask_Sky = (1<<5), Mask_Water = (1<<6), + Mask_Terrain = (1<<7), // top level masks - Mask_Scene = (1<<7), - Mask_GUI = (1<<8), + Mask_Scene = (1<<8), + Mask_GUI = (1<<9), // Set on cameras within the main scene graph - Mask_RenderToTexture = (1<<9) + Mask_RenderToTexture = (1<<10) // reserved: (1<<16) for SceneUtil::Mask_Lit }; diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 2dd843e4e..c2149358b 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -9,6 +9,8 @@ #include #include +#include + #include #include @@ -105,7 +107,7 @@ namespace MWRender // -------------------------------------------------------------------------------------------------------------------------------- -Water::Water(osg::Group *parent, Resource::ResourceSystem *resourceSystem) +Water::Water(osg::Group *parent, Resource::ResourceSystem *resourceSystem, osgUtil::IncrementalCompileOperation *ico) : mParent(parent) , mResourceSystem(resourceSystem) , mEnabled(true) @@ -118,6 +120,9 @@ Water::Water(osg::Group *parent, Resource::ResourceSystem *resourceSystem) geode->addDrawable(waterGeom); geode->setNodeMask(Mask_Water); + if (ico) + ico->add(geode); + createWaterStateSet(mResourceSystem, geode); mWaterNode = new osg::PositionAttitudeTransform; diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index 45b4b38a6..d389392ba 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -11,6 +11,11 @@ namespace osg class PositionAttitudeTransform; } +namespace osgUtil +{ + class IncrementalCompileOperation; +} + namespace Resource { class ResourceSystem; @@ -27,6 +32,7 @@ namespace MWRender osg::ref_ptr mParent; osg::ref_ptr mWaterNode; Resource::ResourceSystem* mResourceSystem; + osg::ref_ptr mIncrementalCompileOperation; bool mEnabled; bool mToggled; @@ -36,7 +42,7 @@ namespace MWRender void updateVisible(); public: - Water(osg::Group* parent, Resource::ResourceSystem* resourceSystem); + Water(osg::Group* parent, Resource::ResourceSystem* resourceSystem, osgUtil::IncrementalCompileOperation* ico); ~Water(); void setEnabled(bool enabled); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 799f82015..e676977de 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1298,7 +1298,9 @@ namespace MWWorld return; } - float terrainHeight = -FLT_MAX;//mRendering->getTerrainHeightAt(Ogre::Vector3(pos.pos)); + float terrainHeight = -std::numeric_limits::max(); + if (isCellExterior()) + terrainHeight = mRendering->getTerrainHeightAt(pos.asVec3()); if (pos.pos[2] < terrainHeight) pos.pos[2] = terrainHeight; diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 6a5b7f59a..51cb55aee 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -104,10 +104,8 @@ add_component_dir (translation translation ) -#add_definitions(-DTERRAIN_USE_SHADER=1) -add_definitions(-DTERRAIN_USE_SHADER=0) add_component_dir (terrain - quadtreenode chunk world defaultworld terraingrid storage material buffercache defs + storage world buffercache defs terraingrid material ) add_component_dir (loadinglistener diff --git a/components/esm/loadland.hpp b/components/esm/loadland.hpp index e510616af..edaeadb03 100644 --- a/components/esm/loadland.hpp +++ b/components/esm/loadland.hpp @@ -80,7 +80,7 @@ struct Land VNML mNormals[LAND_NUM_VERTS * 3]; uint16_t mTextures[LAND_NUM_TEXTURES]; - char mColours[3 * LAND_NUM_VERTS]; + unsigned char mColours[3 * LAND_NUM_VERTS]; int mDataTypes; // low-LOD heightmap (used for rendering the global map) diff --git a/components/esmterrain/storage.cpp b/components/esmterrain/storage.cpp index 5a69fd27a..0795a3ffc 100644 --- a/components/esmterrain/storage.cpp +++ b/components/esmterrain/storage.cpp @@ -1,34 +1,38 @@ #include "storage.hpp" -#include -#include -#include -#include -#include -#include -#include +#include + +#include +#include + +#include #include -#include #include +#include namespace ESMTerrain { - bool Storage::getMinMaxHeights(float size, const Ogre::Vector2 ¢er, float &min, float &max) + Storage::Storage(const VFS::Manager *vfs) + : mVFS(vfs) + { + } + + bool Storage::getMinMaxHeights(float size, const osg::Vec2f ¢er, float &min, float &max) { assert (size <= 1 && "Storage::getMinMaxHeights, chunk size should be <= 1 cell"); /// \todo investigate if min/max heights should be stored at load time in ESM::Land instead - Ogre::Vector2 origin = center - Ogre::Vector2(size/2.f, size/2.f); + osg::Vec2f origin = center - osg::Vec2f(size/2.f, size/2.f); - assert(origin.x == (int) origin.x); - assert(origin.y == (int) origin.y); + assert(origin.x == (int) origin.x()); + assert(origin.y == (int) origin.y()); - int cellX = static_cast(origin.x); - int cellY = static_cast(origin.y); + int cellX = static_cast(origin.x()); + int cellY = static_cast(origin.y()); const ESM::Land* land = getLand(cellX, cellY); if (!land || !(land->mDataTypes&ESM::Land::DATA_VHGT)) @@ -50,7 +54,7 @@ namespace ESMTerrain return true; } - void Storage::fixNormal (Ogre::Vector3& normal, int cellX, int cellY, int col, int row) + void Storage::fixNormal (osg::Vec3f& normal, int cellX, int cellY, int col, int row) { while (col >= ESM::Land::LAND_SIZE-1) { @@ -75,27 +79,27 @@ namespace ESMTerrain ESM::Land* land = getLand(cellX, cellY); if (land && land->mDataTypes&ESM::Land::DATA_VNML) { - normal.x = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3]; - normal.y = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3+1]; - normal.z = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3+2]; - normal.normalise(); + normal.x() = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3]; + normal.y() = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3+1]; + normal.z() = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3+2]; + normal.normalize(); } else - normal = Ogre::Vector3(0,0,1); + normal = osg::Vec3f(0,0,1); } - void Storage::averageNormal(Ogre::Vector3 &normal, int cellX, int cellY, int col, int row) + void Storage::averageNormal(osg::Vec3f &normal, int cellX, int cellY, int col, int row) { - Ogre::Vector3 n1,n2,n3,n4; + osg::Vec3f n1,n2,n3,n4; fixNormal(n1, cellX, cellY, col+1, row); fixNormal(n2, cellX, cellY, col-1, row); fixNormal(n3, cellX, cellY, col, row+1); fixNormal(n4, cellX, cellY, col, row-1); normal = (n1+n2+n3+n4); - normal.normalise(); + normal.normalize(); } - void Storage::fixColour (Ogre::ColourValue& color, int cellX, int cellY, int col, int row) + void Storage::fixColour (osg::Vec4f& color, int cellX, int cellY, int col, int row) { if (col == ESM::Land::LAND_SIZE-1) { @@ -110,42 +114,42 @@ namespace ESMTerrain ESM::Land* land = getLand(cellX, cellY); if (land && land->mDataTypes&ESM::Land::DATA_VCLR) { - color.r = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3] / 255.f; - color.g = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3+1] / 255.f; - color.b = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3+2] / 255.f; + color.r() = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3] / 255.f; + color.g() = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3+1] / 255.f; + color.b() = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3+2] / 255.f; } else { - color.r = 1; - color.g = 1; - color.b = 1; + color.r() = 1; + color.g() = 1; + color.b() = 1; } } - void Storage::fillVertexBuffers (int lodLevel, float size, const Ogre::Vector2& center, Terrain::Alignment align, - std::vector& positions, - std::vector& normals, - std::vector& colours) + void Storage::fillVertexBuffers (int lodLevel, float size, const osg::Vec2f& center, + osg::ref_ptr positions, + osg::ref_ptr normals, + osg::ref_ptr colours) { // LOD level n means every 2^n-th vertex is kept size_t increment = 1 << lodLevel; - Ogre::Vector2 origin = center - Ogre::Vector2(size/2.f, size/2.f); - assert(origin.x == (int) origin.x); - assert(origin.y == (int) origin.y); + osg::Vec2f origin = center - osg::Vec2f(size/2.f, size/2.f); + assert(origin.x() == (int) origin.x()); + assert(origin.y() == (int) origin.y()); - int startX = static_cast(origin.x); - int startY = static_cast(origin.y); + int startX = static_cast(origin.x()); + int startY = static_cast(origin.y()); size_t numVerts = static_cast(size*(ESM::Land::LAND_SIZE - 1) / increment + 1); - colours.resize(numVerts*numVerts*4); - positions.resize(numVerts*numVerts*3); - normals.resize(numVerts*numVerts*3); + positions->resize(numVerts*numVerts); + normals->resize(numVerts*numVerts); + colours->resize(numVerts*numVerts); - Ogre::Vector3 normal; - Ogre::ColourValue color; + osg::Vec3f normal; + osg::Vec4f color; float vertY = 0; float vertX = 0; @@ -175,22 +179,24 @@ namespace ESMTerrain vertX = vertX_; for (int row=rowStart; row(vertX*numVerts * 3 + vertY * 3)] = ((vertX / float(numVerts - 1) - 0.5f) * size * 8192); - positions[static_cast(vertX*numVerts * 3 + vertY * 3 + 1)] = ((vertY / float(numVerts - 1) - 0.5f) * size * 8192); + float height = -2048; if (land) - positions[static_cast(vertX*numVerts * 3 + vertY * 3 + 2)] = land->mLandData->mHeights[col*ESM::Land::LAND_SIZE + row]; - else - positions[static_cast(vertX*numVerts * 3 + vertY * 3 + 2)] = -2048; + height = land->mLandData->mHeights[col*ESM::Land::LAND_SIZE + row]; + + (*positions)[static_cast(vertX*numVerts + vertY)] + = osg::Vec3f((vertX / float(numVerts - 1) - 0.5f) * size * 8192, + (vertY / float(numVerts - 1) - 0.5f) * size * 8192, + height); if (land && land->mDataTypes&ESM::Land::DATA_VNML) { - normal.x = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3]; - normal.y = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3+1]; - normal.z = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3+2]; - normal.normalise(); + normal.x() = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3]; + normal.y() = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3+1]; + normal.z() = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3+2]; + normal.normalize(); } else - normal = Ogre::Vector3(0,0,1); + normal = osg::Vec3f(0,0,1); // Normals apparently don't connect seamlessly between cells if (col == ESM::Land::LAND_SIZE-1 || row == ESM::Land::LAND_SIZE-1) @@ -200,33 +206,30 @@ namespace ESMTerrain if ((row == 0 || row == ESM::Land::LAND_SIZE-1) && (col == 0 || col == ESM::Land::LAND_SIZE-1)) averageNormal(normal, cellX, cellY, col, row); - assert(normal.z > 0); + assert(normal.z() > 0); - normals[static_cast(vertX*numVerts * 3 + vertY * 3)] = normal.x; - normals[static_cast(vertX*numVerts * 3 + vertY * 3 + 1)] = normal.y; - normals[static_cast(vertX*numVerts * 3 + vertY * 3 + 2)] = normal.z; + (*normals)[static_cast(vertX*numVerts + vertY)] = normal; if (land && land->mDataTypes&ESM::Land::DATA_VCLR) { - color.r = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3] / 255.f; - color.g = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3+1] / 255.f; - color.b = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3+2] / 255.f; + color.r() = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3] / 255.f; + color.g() = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3+1] / 255.f; + color.b() = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3+2] / 255.f; } else { - color.r = 1; - color.g = 1; - color.b = 1; + color.r() = 1; + color.g() = 1; + color.b() = 1; } // Unlike normals, colors mostly connect seamlessly between cells, but not always... if (col == ESM::Land::LAND_SIZE-1 || row == ESM::Land::LAND_SIZE-1) fixColour(color, cellX, cellY, col, row); - color.a = 1; - Ogre::uint32 rsColor; - Ogre::Root::getSingleton().getRenderSystem()->convertColourValue(color, &rsColor); - memcpy(&colours[static_cast(vertX*numVerts * 4 + vertY * 4)], &rsColor, sizeof(Ogre::uint32)); + color.a() = 1; + + (*colours)[static_cast(vertX*numVerts + vertY)] = color; ++vertX; } @@ -281,39 +284,22 @@ namespace ESMTerrain // NB: All vtex ids are +1 compared to the ltex ids const ESM::LandTexture* ltex = getLandTexture(id.first-1, id.second); - //TODO this is needed due to MWs messed up texture handling - assert(0 && "no vfs here yet"); - std::string texture = ltex->mTexture; //Misc::ResourceHelpers::correctTexturePath(ltex->mTexture); + // this is needed due to MWs messed up texture handling + std::string texture = Misc::ResourceHelpers::correctTexturePath(ltex->mTexture, mVFS); return texture; } - void Storage::getBlendmaps (const std::vector& nodes, std::vector& out, bool pack) - { - for (std::vector::const_iterator it = nodes.begin(); it != nodes.end(); ++it) - { - out.push_back(Terrain::LayerCollection()); - out.back().mTarget = *it; - getBlendmapsImpl(static_cast((*it)->getSize()), (*it)->getCenter(), pack, out.back().mBlendmaps, out.back().mLayers); - } - } - - void Storage::getBlendmaps(float chunkSize, const Ogre::Vector2 &chunkCenter, - bool pack, std::vector &blendmaps, std::vector &layerList) - { - getBlendmapsImpl(chunkSize, chunkCenter, pack, blendmaps, layerList); - } - - void Storage::getBlendmapsImpl(float chunkSize, const Ogre::Vector2 &chunkCenter, - bool pack, std::vector &blendmaps, std::vector &layerList) + void Storage::getBlendmaps(float chunkSize, const osg::Vec2f &chunkCenter, + bool pack, ImageVector &blendmaps, std::vector &layerList) { // TODO - blending isn't completely right yet; the blending radius appears to be // different at a cell transition (2 vertices, not 4), so we may need to create a larger blendmap // and interpolate the rest of the cell by hand? :/ - Ogre::Vector2 origin = chunkCenter - Ogre::Vector2(chunkSize/2.f, chunkSize/2.f); - int cellX = static_cast(origin.x); - int cellY = static_cast(origin.y); + osg::Vec2f origin = chunkCenter - osg::Vec2f(chunkSize/2.f, chunkSize/2.f); + int cellX = static_cast(origin.x()); + int cellY = static_cast(origin.y()); // Save the used texture indices so we know the total number of textures // and number of required blend maps @@ -353,11 +339,11 @@ namespace ESMTerrain for (int i=0; i image (new osg::Image); + image->allocateImage(blendmapSize, blendmapSize, 1, format, GL_UNSIGNED_BYTE); + unsigned char* pData = image->data(); for (int y=0; y(std::floor(worldPos.x / 8192.f)); - int cellY = static_cast(std::floor(worldPos.y / 8192.f)); + int cellX = static_cast(std::floor(worldPos.x() / 8192.f)); + int cellY = static_cast(std::floor(worldPos.y() / 8192.f)); ESM::Land* land = getLand(cellX, cellY); if (!land || !(land->mDataTypes&ESM::Land::DATA_VHGT)) @@ -390,8 +377,8 @@ namespace ESMTerrain // Mostly lifted from Ogre::Terrain::getHeightAtTerrainPosition // Normalized position in the cell - float nX = (worldPos.x - (cellX * 8192))/8192.f; - float nY = (worldPos.y - (cellY * 8192))/8192.f; + float nX = (worldPos.x() - (cellX * 8192))/8192.f; + float nY = (worldPos.y() - (cellY * 8192))/8192.f; // get left / bottom points (rounded down) float factor = ESM::Land::LAND_SIZE - 1.0f; @@ -423,22 +410,23 @@ namespace ESMTerrain */ // Build all 4 positions in normalized cell space, using point-sampled height - Ogre::Vector3 v0 (startXTS, startYTS, getVertexHeight(land, startX, startY) / 8192.f); - Ogre::Vector3 v1 (endXTS, startYTS, getVertexHeight(land, endX, startY) / 8192.f); - Ogre::Vector3 v2 (endXTS, endYTS, getVertexHeight(land, endX, endY) / 8192.f); - Ogre::Vector3 v3 (startXTS, endYTS, getVertexHeight(land, startX, endY) / 8192.f); + osg::Vec3f v0 (startXTS, startYTS, getVertexHeight(land, startX, startY) / 8192.f); + osg::Vec3f v1 (endXTS, startYTS, getVertexHeight(land, endX, startY) / 8192.f); + osg::Vec3f v2 (endXTS, endYTS, getVertexHeight(land, endX, endY) / 8192.f); + osg::Vec3f v3 (startXTS, endYTS, getVertexHeight(land, startX, endY) / 8192.f); // define this plane in terrain space - Ogre::Plane plane; - // (At the moment, all rows have the same triangle alignment) + osg::Plane plane; + // FIXME: deal with differing triangle alignment if (true) { // odd row bool secondTri = ((1.0 - yParam) > xParam); if (secondTri) - plane.redefine(v0, v1, v3); + plane = osg::Plane(v0, v1, v3); else - plane.redefine(v1, v2, v3); + plane = osg::Plane(v1, v2, v3); } + /* else { // even row @@ -448,11 +436,12 @@ namespace ESMTerrain else plane.redefine(v0, v1, v2); } + */ // Solve plane equation for z - return (-plane.normal.x * nX - -plane.normal.y * nY - - plane.d) / plane.normal.z * 8192; + return (-plane.getNormal().x() * nX + -plane.getNormal().y() * nY + - plane[3]) / plane.getNormal().z() * 8192; } @@ -477,7 +466,7 @@ namespace ESMTerrain std::string texture_ = texture; boost::replace_last(texture_, ".", "_nh."); - if (Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(texture_)) + if (mVFS->exists(texture_)) { info.mNormalMap = texture_; info.mParallax = true; @@ -486,24 +475,18 @@ namespace ESMTerrain { texture_ = texture; boost::replace_last(texture_, ".", "_n."); - if (Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(texture_)) + if (mVFS->exists(texture_)) info.mNormalMap = texture_; } texture_ = texture; boost::replace_last(texture_, ".", "_diffusespec."); - if (Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(texture_)) + if (mVFS->exists(texture_)) { info.mDiffuseMap = texture_; info.mSpecular = true; } - // This wasn't cached, so the textures are probably not loaded either. - // Background load them so they are hopefully already loaded once we need them! - Ogre::ResourceBackgroundQueue::getSingleton().load("Texture", info.mDiffuseMap, "General"); - if (!info.mNormalMap.empty()) - Ogre::ResourceBackgroundQueue::getSingleton().load("Texture", info.mNormalMap, "General"); - mLayerInfoMap[texture] = info; return info; diff --git a/components/esmterrain/storage.hpp b/components/esmterrain/storage.hpp index e184cbc4c..8f4a3aa92 100644 --- a/components/esmterrain/storage.hpp +++ b/components/esmterrain/storage.hpp @@ -6,6 +6,11 @@ #include #include +namespace VFS +{ + class Manager; +} + namespace ESMTerrain { @@ -20,6 +25,7 @@ namespace ESMTerrain virtual const ESM::LandTexture* getLandTexture(int index, short plugin) = 0; public: + Storage(const VFS::Manager* vfs); // Not implemented in this class, because we need different Store implementations for game and editor /// Get bounds of the whole terrain in cell units @@ -33,11 +39,10 @@ namespace ESMTerrain /// @param min min height will be stored here /// @param max max height will be stored here /// @return true if there was data available for this terrain chunk - virtual bool getMinMaxHeights (float size, const Ogre::Vector2& center, float& min, float& max); + virtual bool getMinMaxHeights (float size, const osg::Vec2f& center, float& min, float& max); /// Fill vertex buffers for a terrain chunk. /// @note May be called from background threads. Make sure to only call thread-safe functions from here! - /// @note returned colors need to be in render-system specific format! Use RenderSystem::convertColourValue. /// @note Vertices should be written in row-major order (a row is defined as parallel to the x-axis). /// The specified positions should be in local space, i.e. relative to the center of the terrain chunk. /// @param lodLevel LOD level, 0 = most detailed @@ -46,10 +51,10 @@ namespace ESMTerrain /// @param positions buffer to write vertices /// @param normals buffer to write vertex normals /// @param colours buffer to write vertex colours - virtual void fillVertexBuffers (int lodLevel, float size, const Ogre::Vector2& center, Terrain::Alignment align, - std::vector& positions, - std::vector& normals, - std::vector& colours); + virtual void fillVertexBuffers (int lodLevel, float size, const osg::Vec2f& center, + osg::ref_ptr positions, + osg::ref_ptr normals, + osg::ref_ptr colours); /// Create textures holding layer blend values for a terrain chunk. /// @note The terrain chunk shouldn't be larger than one cell since otherwise we might @@ -62,23 +67,11 @@ namespace ESMTerrain /// can utilize packing, FFP can't. /// @param blendmaps created blendmaps will be written here /// @param layerList names of the layer textures used will be written here - virtual void getBlendmaps (float chunkSize, const Ogre::Vector2& chunkCenter, bool pack, - std::vector& blendmaps, + virtual void getBlendmaps (float chunkSize, const osg::Vec2f& chunkCenter, bool pack, + ImageVector& blendmaps, std::vector& layerList); - /// Retrieve pixel data for textures holding layer blend values for terrain chunks and layer texture information. - /// This variant is provided to eliminate the overhead of virtual function calls when retrieving a large number of blendmaps at once. - /// @note The terrain chunks shouldn't be larger than one cell since otherwise we might - /// have to do a ridiculous amount of different layers. For larger chunks, composite maps should be used. - /// @note May be called from background threads. - /// @param nodes A collection of nodes for which to retrieve the aforementioned data - /// @param out Output vector - /// @param pack Whether to pack blend values for up to 4 layers into one texture (one in each channel) - - /// otherwise, each texture contains blend values for one layer only. Shader-based rendering - /// can utilize packing, FFP can't. - virtual void getBlendmaps (const std::vector& nodes, std::vector& out, bool pack); - - virtual float getHeightAt (const Ogre::Vector3& worldPos); + virtual float getHeightAt (const osg::Vec3f& worldPos); virtual Terrain::LayerInfo getDefaultLayer(); @@ -89,9 +82,11 @@ namespace ESMTerrain virtual int getCellVertices(); private: - void fixNormal (Ogre::Vector3& normal, int cellX, int cellY, int col, int row); - void fixColour (Ogre::ColourValue& colour, int cellX, int cellY, int col, int row); - void averageNormal (Ogre::Vector3& normal, int cellX, int cellY, int col, int row); + const VFS::Manager* mVFS; + + void fixNormal (osg::Vec3f& normal, int cellX, int cellY, int col, int row); + void fixColour (osg::Vec4f& colour, int cellX, int cellY, int col, int row); + void averageNormal (osg::Vec3f& normal, int cellX, int cellY, int col, int row); float getVertexHeight (const ESM::Land* land, int x, int y); @@ -107,11 +102,6 @@ namespace ESMTerrain std::map mLayerInfoMap; Terrain::LayerInfo getLayerInfo(const std::string& texture); - - // Non-virtual - void getBlendmapsImpl (float chunkSize, const Ogre::Vector2& chunkCenter, bool pack, - std::vector& blendmaps, - std::vector& layerList); }; } diff --git a/components/terrain/buffercache.cpp b/components/terrain/buffercache.cpp index 1b000fabb..7dc93f1d6 100644 --- a/components/terrain/buffercache.cpp +++ b/components/terrain/buffercache.cpp @@ -21,15 +21,17 @@ */ #include "buffercache.hpp" -#include +#include + +#include #include "defs.hpp" namespace { -template -Ogre::HardwareIndexBufferSharedPtr createIndexBuffer(unsigned int flags, unsigned int verts, Ogre::HardwareIndexBuffer::IndexType type) +template +osg::ref_ptr createIndexBuffer(unsigned int flags, unsigned int verts) { // LOD level n means every 2^n-th vertex is kept size_t lodLevel = (flags >> (4*4)); @@ -42,8 +44,9 @@ Ogre::HardwareIndexBufferSharedPtr createIndexBuffer(unsigned int flags, unsigne size_t increment = 1 << lodLevel; assert(increment < verts); - std::vector indices; - indices.reserve((verts-1)*(verts-1)*2*3 / increment); + + osg::ref_ptr indices (new IndexArrayType(osg::PrimitiveSet::TRIANGLES)); + indices->reserve((verts-1)*(verts-1)*2*3 / increment); size_t rowStart = 0, colStart = 0, rowEnd = verts-1, colEnd = verts-1; // If any edge needs stitching we'll skip all edges at this point, @@ -62,23 +65,23 @@ Ogre::HardwareIndexBufferSharedPtr createIndexBuffer(unsigned int flags, unsigne // diamond pattern if ((row + col%2) % 2 == 1) { - indices.push_back(verts*(col+increment)+row); - indices.push_back(verts*(col+increment)+row+increment); - indices.push_back(verts*col+row+increment); + indices->push_back(verts*(col+increment)+row); + indices->push_back(verts*(col+increment)+row+increment); + indices->push_back(verts*col+row+increment); - indices.push_back(verts*col+row); - indices.push_back(verts*(col+increment)+row); - indices.push_back(verts*(col)+row+increment); + indices->push_back(verts*col+row); + indices->push_back(verts*(col+increment)+row); + indices->push_back(verts*(col)+row+increment); } else { - indices.push_back(verts*col+row); - indices.push_back(verts*(col+increment)+row+increment); - indices.push_back(verts*col+row+increment); + indices->push_back(verts*col+row); + indices->push_back(verts*(col+increment)+row+increment); + indices->push_back(verts*col+row+increment); - indices.push_back(verts*col+row); - indices.push_back(verts*(col+increment)+row); - indices.push_back(verts*(col+increment)+row+increment); + indices->push_back(verts*col+row); + indices->push_back(verts*(col+increment)+row); + indices->push_back(verts*(col+increment)+row+increment); } } } @@ -94,22 +97,22 @@ Ogre::HardwareIndexBufferSharedPtr createIndexBuffer(unsigned int flags, unsigne size_t outerStep = 1 << (lodDeltas[Terrain::South] + lodLevel); for (size_t col = 0; col < verts-1; col += outerStep) { - indices.push_back(verts*col+row); - indices.push_back(verts*(col+outerStep)+row); + indices->push_back(verts*col+row); + indices->push_back(verts*(col+outerStep)+row); // Make sure not to touch the right edge if (col+outerStep == verts-1) - indices.push_back(verts*(col+outerStep-innerStep)+row+innerStep); + indices->push_back(verts*(col+outerStep-innerStep)+row+innerStep); else - indices.push_back(verts*(col+outerStep)+row+innerStep); + indices->push_back(verts*(col+outerStep)+row+innerStep); for (size_t i = 0; i < outerStep; i += innerStep) { // Make sure not to touch the left or right edges if (col+i == 0 || col+i == verts-1-innerStep) continue; - indices.push_back(verts*(col)+row); - indices.push_back(verts*(col+i+innerStep)+row+innerStep); - indices.push_back(verts*(col+i)+row+innerStep); + indices->push_back(verts*(col)+row); + indices->push_back(verts*(col+i+innerStep)+row+innerStep); + indices->push_back(verts*(col+i)+row+innerStep); } } @@ -118,22 +121,22 @@ Ogre::HardwareIndexBufferSharedPtr createIndexBuffer(unsigned int flags, unsigne outerStep = size_t(1) << (lodDeltas[Terrain::North] + lodLevel); for (size_t col = 0; col < verts-1; col += outerStep) { - indices.push_back(verts*(col+outerStep)+row); - indices.push_back(verts*col+row); + indices->push_back(verts*(col+outerStep)+row); + indices->push_back(verts*col+row); // Make sure not to touch the left edge if (col == 0) - indices.push_back(verts*(col+innerStep)+row-innerStep); + indices->push_back(verts*(col+innerStep)+row-innerStep); else - indices.push_back(verts*col+row-innerStep); + indices->push_back(verts*col+row-innerStep); for (size_t i = 0; i < outerStep; i += innerStep) { // Make sure not to touch the left or right edges if (col+i == 0 || col+i == verts-1-innerStep) continue; - indices.push_back(verts*(col+i)+row-innerStep); - indices.push_back(verts*(col+i+innerStep)+row-innerStep); - indices.push_back(verts*(col+outerStep)+row); + indices->push_back(verts*(col+i)+row-innerStep); + indices->push_back(verts*(col+i+innerStep)+row-innerStep); + indices->push_back(verts*(col+outerStep)+row); } } @@ -142,22 +145,22 @@ Ogre::HardwareIndexBufferSharedPtr createIndexBuffer(unsigned int flags, unsigne outerStep = size_t(1) << (lodDeltas[Terrain::West] + lodLevel); for (size_t row = 0; row < verts-1; row += outerStep) { - indices.push_back(verts*col+row+outerStep); - indices.push_back(verts*col+row); + indices->push_back(verts*col+row+outerStep); + indices->push_back(verts*col+row); // Make sure not to touch the top edge if (row+outerStep == verts-1) - indices.push_back(verts*(col+innerStep)+row+outerStep-innerStep); + indices->push_back(verts*(col+innerStep)+row+outerStep-innerStep); else - indices.push_back(verts*(col+innerStep)+row+outerStep); + indices->push_back(verts*(col+innerStep)+row+outerStep); for (size_t i = 0; i < outerStep; i += innerStep) { // Make sure not to touch the top or bottom edges if (row+i == 0 || row+i == verts-1-innerStep) continue; - indices.push_back(verts*col+row); - indices.push_back(verts*(col+innerStep)+row+i); - indices.push_back(verts*(col+innerStep)+row+i+innerStep); + indices->push_back(verts*col+row); + indices->push_back(verts*(col+innerStep)+row+i); + indices->push_back(verts*(col+innerStep)+row+i+innerStep); } } @@ -166,31 +169,27 @@ Ogre::HardwareIndexBufferSharedPtr createIndexBuffer(unsigned int flags, unsigne outerStep = size_t(1) << (lodDeltas[Terrain::East] + lodLevel); for (size_t row = 0; row < verts-1; row += outerStep) { - indices.push_back(verts*col+row); - indices.push_back(verts*col+row+outerStep); + indices->push_back(verts*col+row); + indices->push_back(verts*col+row+outerStep); // Make sure not to touch the bottom edge if (row == 0) - indices.push_back(verts*(col-innerStep)+row+innerStep); + indices->push_back(verts*(col-innerStep)+row+innerStep); else - indices.push_back(verts*(col-innerStep)+row); + indices->push_back(verts*(col-innerStep)+row); for (size_t i = 0; i < outerStep; i += innerStep) { // Make sure not to touch the top or bottom edges if (row+i == 0 || row+i == verts-1-innerStep) continue; - indices.push_back(verts*col+row+outerStep); - indices.push_back(verts*(col-innerStep)+row+i+innerStep); - indices.push_back(verts*(col-innerStep)+row+i); + indices->push_back(verts*col+row+outerStep); + indices->push_back(verts*(col-innerStep)+row+i+innerStep); + indices->push_back(verts*(col-innerStep)+row+i); } } } - Ogre::HardwareBufferManager* mgr = Ogre::HardwareBufferManager::getSingletonPtr(); - Ogre::HardwareIndexBufferSharedPtr buffer = mgr->createIndexBuffer(type, - indices.size(), Ogre::HardwareBuffer::HBU_STATIC); - buffer->writeData(0, buffer->getSizeInBytes(), &indices[0], true); - return buffer; + return indices; } } @@ -198,7 +197,7 @@ Ogre::HardwareIndexBufferSharedPtr createIndexBuffer(unsigned int flags, unsigne namespace Terrain { - Ogre::HardwareVertexBufferSharedPtr BufferCache::getUVBuffer() + osg::ref_ptr BufferCache::getUVBuffer() { if (mUvBufferMap.find(mNumVerts) != mUvBufferMap.end()) { @@ -207,30 +206,23 @@ namespace Terrain int vertexCount = mNumVerts * mNumVerts; - std::vector uvs; - uvs.reserve(vertexCount*2); + osg::ref_ptr uvs (new osg::Vec2Array); + uvs->reserve(vertexCount); for (unsigned int col = 0; col < mNumVerts; ++col) { for (unsigned int row = 0; row < mNumVerts; ++row) { - uvs.push_back(col / static_cast(mNumVerts-1)); // U - uvs.push_back(row / static_cast(mNumVerts-1)); // V + uvs->push_back(osg::Vec2f(col / static_cast(mNumVerts-1), + row / static_cast(mNumVerts-1))); } } - Ogre::HardwareBufferManager* mgr = Ogre::HardwareBufferManager::getSingletonPtr(); - Ogre::HardwareVertexBufferSharedPtr buffer = mgr->createVertexBuffer( - Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT2), - vertexCount, Ogre::HardwareBuffer::HBU_STATIC); - - buffer->writeData(0, buffer->getSizeInBytes(), &uvs[0], true); - - mUvBufferMap[mNumVerts] = buffer; - return buffer; + mUvBufferMap[mNumVerts] = uvs; + return uvs; } - Ogre::HardwareIndexBufferSharedPtr BufferCache::getIndexBuffer(unsigned int flags) + osg::ref_ptr BufferCache::getIndexBuffer(unsigned int flags) { unsigned int verts = mNumVerts; @@ -239,11 +231,12 @@ namespace Terrain return mIndexBufferMap[flags]; } - Ogre::HardwareIndexBufferSharedPtr buffer; + osg::ref_ptr buffer; + if (verts*verts > (0xffffu)) - buffer = createIndexBuffer(flags, verts, Ogre::HardwareIndexBuffer::IT_32BIT); + buffer = createIndexBuffer(flags, verts); else - buffer = createIndexBuffer(flags, verts, Ogre::HardwareIndexBuffer::IT_16BIT); + buffer = createIndexBuffer(flags, verts); mIndexBufferMap[flags] = buffer; return buffer; diff --git a/components/terrain/buffercache.hpp b/components/terrain/buffercache.hpp index 887f0822e..575e9bca2 100644 --- a/components/terrain/buffercache.hpp +++ b/components/terrain/buffercache.hpp @@ -22,8 +22,8 @@ #ifndef COMPONENTS_TERRAIN_BUFFERCACHE_H #define COMPONENTS_TERRAIN_BUFFERCACHE_H -#include -#include +#include +#include #include @@ -38,16 +38,18 @@ namespace Terrain /// @param flags first 4*4 bits are LOD deltas on each edge, respectively (4 bits each) /// next 4 bits are LOD level of the index buffer (LOD 0 = don't omit any vertices) - Ogre::HardwareIndexBufferSharedPtr getIndexBuffer (unsigned int flags); + osg::ref_ptr getIndexBuffer (unsigned int flags); - Ogre::HardwareVertexBufferSharedPtr getUVBuffer (); + osg::ref_ptr getUVBuffer(); + + // TODO: add releaseGLObjects() for our vertex/element buffer objects private: // Index buffers are shared across terrain batches where possible. There is one index buffer for each // combination of LOD deltas and index buffer LOD we may need. - std::map mIndexBufferMap; + std::map > mIndexBufferMap; - std::map mUvBufferMap; + std::map > mUvBufferMap; unsigned int mNumVerts; }; diff --git a/components/terrain/chunk.cpp b/components/terrain/chunk.cpp deleted file mode 100644 index e3bae1173..000000000 --- a/components/terrain/chunk.cpp +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Copyright (c) 2015 scrawl - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "chunk.hpp" - -#include -#include -#include -#include -#include - -namespace Terrain -{ - - Chunk::Chunk(Ogre::HardwareVertexBufferSharedPtr uvBuffer, const Ogre::AxisAlignedBox& bounds, - const std::vector& positions, const std::vector& normals, const std::vector& colours) - : mBounds(bounds) - , mOwnMaterial(false) - { - mVertexData = OGRE_NEW Ogre::VertexData; - mVertexData->vertexStart = 0; - mVertexData->vertexCount = positions.size()/3; - - // Set up the vertex declaration, which specifies the info for each vertex (normals, colors, UVs, etc) - Ogre::VertexDeclaration* vertexDecl = mVertexData->vertexDeclaration; - - Ogre::HardwareBufferManager* mgr = Ogre::HardwareBufferManager::getSingletonPtr(); - size_t nextBuffer = 0; - - // Positions - vertexDecl->addElement(nextBuffer++, 0, Ogre::VET_FLOAT3, Ogre::VES_POSITION); - Ogre::HardwareVertexBufferSharedPtr vertexBuffer = mgr->createVertexBuffer(Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3), - mVertexData->vertexCount, Ogre::HardwareBuffer::HBU_STATIC); - - // Normals - vertexDecl->addElement(nextBuffer++, 0, Ogre::VET_FLOAT3, Ogre::VES_NORMAL); - Ogre::HardwareVertexBufferSharedPtr normalBuffer = mgr->createVertexBuffer(Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3), - mVertexData->vertexCount, Ogre::HardwareBuffer::HBU_STATIC); - - - // UV texture coordinates - vertexDecl->addElement(nextBuffer++, 0, Ogre::VET_FLOAT2, - Ogre::VES_TEXTURE_COORDINATES, 0); - - // Colours - vertexDecl->addElement(nextBuffer++, 0, Ogre::VET_COLOUR, Ogre::VES_DIFFUSE); - Ogre::HardwareVertexBufferSharedPtr colourBuffer = mgr->createVertexBuffer(Ogre::VertexElement::getTypeSize(Ogre::VET_COLOUR), - mVertexData->vertexCount, Ogre::HardwareBuffer::HBU_STATIC); - - vertexBuffer->writeData(0, vertexBuffer->getSizeInBytes(), &positions[0], true); - normalBuffer->writeData(0, normalBuffer->getSizeInBytes(), &normals[0], true); - colourBuffer->writeData(0, colourBuffer->getSizeInBytes(), &colours[0], true); - - mVertexData->vertexBufferBinding->setBinding(0, vertexBuffer); - mVertexData->vertexBufferBinding->setBinding(1, normalBuffer); - mVertexData->vertexBufferBinding->setBinding(2, uvBuffer); - mVertexData->vertexBufferBinding->setBinding(3, colourBuffer); - - // Assign a default material in case terrain material fails to be created - mMaterial = Ogre::MaterialManager::getSingleton().getByName("BaseWhite"); - - mIndexData = OGRE_NEW Ogre::IndexData(); - mIndexData->indexStart = 0; - } - - void Chunk::setIndexBuffer(Ogre::HardwareIndexBufferSharedPtr buffer) - { - mIndexData->indexBuffer = buffer; - mIndexData->indexCount = buffer->getNumIndexes(); - } - - Chunk::~Chunk() - { - if (!mMaterial.isNull() && mOwnMaterial) - { -#if TERRAIN_USE_SHADER - sh::Factory::getInstance().destroyMaterialInstance(mMaterial->getName()); -#endif - Ogre::MaterialManager::getSingleton().remove(mMaterial->getName()); - } - OGRE_DELETE mVertexData; - OGRE_DELETE mIndexData; - } - - void Chunk::setMaterial(const Ogre::MaterialPtr &material, bool own) - { - // Clean up the previous material, if we own it - if (!mMaterial.isNull() && mOwnMaterial) - { -#if TERRAIN_USE_SHADER - sh::Factory::getInstance().destroyMaterialInstance(mMaterial->getName()); -#endif - Ogre::MaterialManager::getSingleton().remove(mMaterial->getName()); - } - - mMaterial = material; - mOwnMaterial = own; - } - - const Ogre::AxisAlignedBox& Chunk::getBoundingBox(void) const - { - return mBounds; - } - - Ogre::Real Chunk::getBoundingRadius(void) const - { - return mBounds.getHalfSize().length(); - } - - void Chunk::_updateRenderQueue(Ogre::RenderQueue* queue) - { - queue->addRenderable(this, mRenderQueueID); - } - - void Chunk::visitRenderables(Ogre::Renderable::Visitor* visitor, - bool debugRenderables) - { - visitor->visit(this, 0, false); - } - - const Ogre::MaterialPtr& Chunk::getMaterial(void) const - { - return mMaterial; - } - - void Chunk::getRenderOperation(Ogre::RenderOperation& op) - { - assert (!mIndexData->indexBuffer.isNull() && "Trying to render, but no index buffer set!"); - assert(!mMaterial.isNull() && "Trying to render, but no material set!"); - op.useIndexes = true; - op.operationType = Ogre::RenderOperation::OT_TRIANGLE_LIST; - op.vertexData = mVertexData; - op.indexData = mIndexData; - } - - void Chunk::getWorldTransforms(Ogre::Matrix4* xform) const - { - *xform = getParentSceneNode()->_getFullTransform(); - } - - Ogre::Real Chunk::getSquaredViewDepth(const Ogre::Camera* cam) const - { - return getParentSceneNode()->getSquaredViewDepth(cam); - } - - const Ogre::LightList& Chunk::getLights(void) const - { - return queryLights(); - } - -} diff --git a/components/terrain/chunk.hpp b/components/terrain/chunk.hpp deleted file mode 100644 index 22b4f26ef..000000000 --- a/components/terrain/chunk.hpp +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2015 scrawl - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#ifndef COMPONENTS_TERRAIN_TERRAINBATCH_H -#define COMPONENTS_TERRAIN_TERRAINBATCH_H - -#include -#include - -namespace Terrain -{ - - /** - * @brief A movable object representing a chunk of terrain. - */ - class Chunk : public Ogre::Renderable, public Ogre::MovableObject - { - public: - Chunk (Ogre::HardwareVertexBufferSharedPtr uvBuffer, const Ogre::AxisAlignedBox& bounds, - const std::vector& positions, - const std::vector& normals, - const std::vector& colours); - - virtual ~Chunk(); - - /// @param own Should we take ownership of the material? - void setMaterial (const Ogre::MaterialPtr& material, bool own=true); - - void setIndexBuffer(Ogre::HardwareIndexBufferSharedPtr buffer); - - // Inherited from MovableObject - virtual const Ogre::String& getMovableType(void) const { static Ogre::String t = "MW_TERRAIN"; return t; } - virtual const Ogre::AxisAlignedBox& getBoundingBox(void) const; - virtual Ogre::Real getBoundingRadius(void) const; - virtual void _updateRenderQueue(Ogre::RenderQueue* queue); - virtual void visitRenderables(Renderable::Visitor* visitor, - bool debugRenderables = false); - - // Inherited from Renderable - virtual const Ogre::MaterialPtr& getMaterial(void) const; - virtual void getRenderOperation(Ogre::RenderOperation& op); - virtual void getWorldTransforms(Ogre::Matrix4* xform) const; - virtual Ogre::Real getSquaredViewDepth(const Ogre::Camera* cam) const; - virtual const Ogre::LightList& getLights(void) const; - - private: - Ogre::AxisAlignedBox mBounds; - Ogre::MaterialPtr mMaterial; - bool mOwnMaterial; // Should we remove mMaterial on destruction? - - Ogre::VertexData* mVertexData; - Ogre::IndexData* mIndexData; - }; - -} - -#endif diff --git a/components/terrain/defaultworld.cpp b/components/terrain/defaultworld.cpp deleted file mode 100644 index 7bc73ddda..000000000 --- a/components/terrain/defaultworld.cpp +++ /dev/null @@ -1,336 +0,0 @@ -/* - * Copyright (c) 2015 scrawl - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "defaultworld.hpp" - -#include -#include -#include -#include -#include -#include -#include - -#include "storage.hpp" -#include "quadtreenode.hpp" - -namespace -{ - - bool isPowerOfTwo(int x) - { - return ( (x > 0) && ((x & (x - 1)) == 0) ); - } - - int nextPowerOfTwo (int v) - { - if (isPowerOfTwo(v)) return v; - int depth=0; - while(v) - { - v >>= 1; - depth++; - } - return 1 << depth; - } - - Terrain::QuadTreeNode* findNode (const Ogre::Vector2& center, Terrain::QuadTreeNode* node) - { - if (center == node->getCenter()) - return node; - - if (center.x > node->getCenter().x && center.y > node->getCenter().y) - return findNode(center, node->getChild(Terrain::NE)); - else if (center.x > node->getCenter().x && center.y < node->getCenter().y) - return findNode(center, node->getChild(Terrain::SE)); - else if (center.x < node->getCenter().x && center.y > node->getCenter().y) - return findNode(center, node->getChild(Terrain::NW)); - else //if (center.x < node->getCenter().x && center.y < node->getCenter().y) - return findNode(center, node->getChild(Terrain::SW)); - } - -} - -namespace Terrain -{ - - const Ogre::uint REQ_ID_CHUNK = 1; - const Ogre::uint REQ_ID_LAYERS = 2; - - DefaultWorld::DefaultWorld(Ogre::SceneManager* sceneMgr, - Storage* storage, int visibilityFlags, bool shaders, Alignment align, float minBatchSize, float maxBatchSize) - : World(sceneMgr, storage, visibilityFlags, shaders, align) - , mWorkQueueChannel(0) - , mVisible(true) - , mChunksLoading(0) - , mMinX(0) - , mMaxX(0) - , mMinY(0) - , mMaxY(0) - , mMinBatchSize(minBatchSize) - , mMaxBatchSize(maxBatchSize) - , mLayerLoadPending(true) - { -#if TERRAIN_USE_SHADER == 0 - if (mShaders) - std::cerr << "Compiled Terrain without shader support, disabling..." << std::endl; - mShaders = false; -#endif - - mCompositeMapSceneMgr = Ogre::Root::getSingleton().createSceneManager(Ogre::ST_GENERIC); - - /// \todo make composite map size configurable - Ogre::Camera* compositeMapCam = mCompositeMapSceneMgr->createCamera("a"); - mCompositeMapRenderTexture = Ogre::TextureManager::getSingleton().createManual( - "terrain/comp/rt", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - Ogre::TEX_TYPE_2D, 128, 128, 0, Ogre::PF_A8B8G8R8, Ogre::TU_RENDERTARGET); - mCompositeMapRenderTarget = mCompositeMapRenderTexture->getBuffer()->getRenderTarget(); - mCompositeMapRenderTarget->setAutoUpdated(false); - mCompositeMapRenderTarget->addViewport(compositeMapCam); - - storage->getBounds(mMinX, mMaxX, mMinY, mMaxY); - - int origSizeX = static_cast(mMaxX - mMinX); - int origSizeY = static_cast(mMaxY - mMinY); - - // Dividing a quad tree only works well for powers of two, so round up to the nearest one - int size = nextPowerOfTwo(std::max(origSizeX, origSizeY)); - - // Adjust the center according to the new size - float centerX = (mMinX+mMaxX)/2.f + (size-origSizeX)/2.f; - float centerY = (mMinY+mMaxY)/2.f + (size-origSizeY)/2.f; - - mRootSceneNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(); - - // While building the quadtree, remember leaf nodes since we need to load their layers - LayersRequestData data; - data.mPack = getShadersEnabled(); - - mRootNode = new QuadTreeNode(this, Root, static_cast(size), Ogre::Vector2(centerX, centerY), NULL); - buildQuadTree(mRootNode, data.mNodes); - //loadingListener->indicateProgress(); - mRootNode->initAabb(); - //loadingListener->indicateProgress(); - mRootNode->initNeighbours(); - //loadingListener->indicateProgress(); - - Ogre::WorkQueue* wq = Ogre::Root::getSingleton().getWorkQueue(); - mWorkQueueChannel = wq->getChannel("LargeTerrain"); - wq->addRequestHandler(mWorkQueueChannel, this); - wq->addResponseHandler(mWorkQueueChannel, this); - - // Start loading layers in the background (for leaf nodes) - wq->addRequest(mWorkQueueChannel, REQ_ID_LAYERS, Ogre::Any(data)); - } - - DefaultWorld::~DefaultWorld() - { - Ogre::WorkQueue* wq = Ogre::Root::getSingleton().getWorkQueue(); - wq->removeRequestHandler(mWorkQueueChannel, this); - wq->removeResponseHandler(mWorkQueueChannel, this); - - delete mRootNode; - } - - void DefaultWorld::buildQuadTree(QuadTreeNode *node, std::vector& leafs) - { - float halfSize = node->getSize()/2.f; - - if (node->getSize() <= mMinBatchSize) - { - // We arrived at a leaf - float minZ,maxZ; - Ogre::Vector2 center = node->getCenter(); - float cellWorldSize = getStorage()->getCellWorldSize(); - if (mStorage->getMinMaxHeights(static_cast(node->getSize()), center, minZ, maxZ)) - { - Ogre::AxisAlignedBox bounds(Ogre::Vector3(-halfSize*cellWorldSize, -halfSize*cellWorldSize, minZ), - Ogre::Vector3(halfSize*cellWorldSize, halfSize*cellWorldSize, maxZ)); - convertBounds(bounds); - node->setBoundingBox(bounds); - leafs.push_back(node); - } - else - node->markAsDummy(); // no data available for this node, skip it - return; - } - - if (node->getCenter().x - halfSize > mMaxX - || node->getCenter().x + halfSize < mMinX - || node->getCenter().y - halfSize > mMaxY - || node->getCenter().y + halfSize < mMinY ) - // Out of bounds of the actual terrain - this will happen because - // we rounded the size up to the next power of two - { - node->markAsDummy(); - return; - } - - // Not a leaf, create its children - node->createChild(SW, halfSize, node->getCenter() - halfSize/2.f); - node->createChild(SE, halfSize, node->getCenter() + Ogre::Vector2(halfSize/2.f, -halfSize/2.f)); - node->createChild(NW, halfSize, node->getCenter() + Ogre::Vector2(-halfSize/2.f, halfSize/2.f)); - node->createChild(NE, halfSize, node->getCenter() + halfSize/2.f); - buildQuadTree(node->getChild(SW), leafs); - buildQuadTree(node->getChild(SE), leafs); - buildQuadTree(node->getChild(NW), leafs); - buildQuadTree(node->getChild(NE), leafs); - - // if all children are dummy, we are also dummy - for (int i=0; i<4; ++i) - { - if (!node->getChild((ChildDirection)i)->isDummy()) - return; - } - node->markAsDummy(); - } - - void DefaultWorld::update(const Ogre::Vector3& cameraPos) - { - if (!mVisible) - return; - mRootNode->update(cameraPos); - mRootNode->updateIndexBuffers(); - } - - Ogre::AxisAlignedBox DefaultWorld::getWorldBoundingBox (const Ogre::Vector2& center) - { - if (center.x > mMaxX - || center.x < mMinX - || center.y > mMaxY - || center.y < mMinY) - return Ogre::AxisAlignedBox::BOX_NULL; - QuadTreeNode* node = findNode(center, mRootNode); - return node->getWorldBoundingBox(); - } - - void DefaultWorld::renderCompositeMap(Ogre::TexturePtr target) - { - mCompositeMapRenderTarget->update(); - target->getBuffer()->blit(mCompositeMapRenderTexture->getBuffer()); - } - - void DefaultWorld::clearCompositeMapSceneManager() - { - mCompositeMapSceneMgr->destroyAllManualObjects(); - mCompositeMapSceneMgr->clearScene(); - } - - void DefaultWorld::applyMaterials(bool shadows, bool splitShadows) - { - mShadows = shadows; - mSplitShadows = splitShadows; - mRootNode->applyMaterials(); - } - - void DefaultWorld::setVisible(bool visible) - { - if (visible && !mVisible) - mSceneMgr->getRootSceneNode()->addChild(mRootSceneNode); - else if (!visible && mVisible) - mSceneMgr->getRootSceneNode()->removeChild(mRootSceneNode); - - mVisible = visible; - } - - bool DefaultWorld::getVisible() - { - return mVisible; - } - - void DefaultWorld::syncLoad() - { - while (mChunksLoading || mLayerLoadPending) - { - OGRE_THREAD_SLEEP(0); - Ogre::Root::getSingleton().getWorkQueue()->processResponses(); - } - } - - Ogre::WorkQueue::Response* DefaultWorld::handleRequest(const Ogre::WorkQueue::Request *req, const Ogre::WorkQueue *srcQ) - { - if (req->getType() == REQ_ID_CHUNK) - { - const LoadRequestData data = Ogre::any_cast(req->getData()); - - QuadTreeNode* node = data.mNode; - - LoadResponseData* responseData = new LoadResponseData(); - - getStorage()->fillVertexBuffers(node->getNativeLodLevel(), static_cast(node->getSize()), node->getCenter(), getAlign(), - responseData->mPositions, responseData->mNormals, responseData->mColours); - - return OGRE_NEW Ogre::WorkQueue::Response(req, true, Ogre::Any(responseData)); - } - else // REQ_ID_LAYERS - { - const LayersRequestData data = Ogre::any_cast(req->getData()); - - LayersResponseData* responseData = new LayersResponseData(); - - getStorage()->getBlendmaps(data.mNodes, responseData->mLayerCollections, data.mPack); - - return OGRE_NEW Ogre::WorkQueue::Response(req, true, Ogre::Any(responseData)); - } - } - - void DefaultWorld::handleResponse(const Ogre::WorkQueue::Response *res, const Ogre::WorkQueue *srcQ) - { - assert(res->succeeded() && "Response failure not handled"); - - if (res->getRequest()->getType() == REQ_ID_CHUNK) - { - LoadResponseData* data = Ogre::any_cast(res->getData()); - - const LoadRequestData requestData = Ogre::any_cast(res->getRequest()->getData()); - - requestData.mNode->load(*data); - - delete data; - - --mChunksLoading; - } - else // REQ_ID_LAYERS - { - LayersResponseData* data = Ogre::any_cast(res->getData()); - - for (std::vector::iterator it = data->mLayerCollections.begin(); it != data->mLayerCollections.end(); ++it) - { - it->mTarget->loadLayers(*it); - } - - delete data; - - mRootNode->loadMaterials(); - - mLayerLoadPending = false; - } - } - - void DefaultWorld::queueLoad(QuadTreeNode *node) - { - LoadRequestData data; - data.mNode = node; - - Ogre::Root::getSingleton().getWorkQueue()->addRequest(mWorkQueueChannel, REQ_ID_CHUNK, Ogre::Any(data)); - ++mChunksLoading; - } -} diff --git a/components/terrain/defaultworld.hpp b/components/terrain/defaultworld.hpp deleted file mode 100644 index 4caef8462..000000000 --- a/components/terrain/defaultworld.hpp +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Copyright (c) 2015 scrawl - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#ifndef COMPONENTS_TERRAIN_H -#define COMPONENTS_TERRAIN_H - -#include -#include -#include - -#include "world.hpp" - -namespace Ogre -{ - class Camera; -} - -namespace Terrain -{ - - class QuadTreeNode; - class Storage; - - /** - * @brief A quadtree-based terrain implementation suitable for large data sets. \n - * Near cells are rendered with alpha splatting, distant cells are merged - * together in batches and have their layers pre-rendered onto a composite map. \n - * Cracks at LOD transitions are avoided using stitching. - * @note Multiple cameras are not supported yet - */ - class DefaultWorld : public World, public Ogre::WorkQueue::RequestHandler, public Ogre::WorkQueue::ResponseHandler - { - public: - /// @note takes ownership of \a storage - /// @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 - /// @param shaders Whether to use splatting shader, or multi-pass fixed function splatting. Shader is usually - /// faster so this is just here for compatibility. - /// @param align The align of the terrain, see Alignment enum - /// @param minBatchSize Minimum size of a terrain batch along one side (in cell units). Used for building the quad tree. - /// @param maxBatchSize Maximum size of a terrain batch along one side (in cell units). Used when traversing the quad tree. - DefaultWorld(Ogre::SceneManager* sceneMgr, - Storage* storage, int visibilityFlags, bool shaders, Alignment align, float minBatchSize, float maxBatchSize); - ~DefaultWorld(); - - /// Update chunk LODs according to this camera position - /// @note Calling this method might lead to composite textures being rendered, so it is best - /// not to call it when render commands are still queued, since that would cause a flush. - virtual void update (const Ogre::Vector3& cameraPos); - - /// Get the world bounding box of a chunk of terrain centered at \a center - virtual Ogre::AxisAlignedBox getWorldBoundingBox (const Ogre::Vector2& center); - - Ogre::SceneNode* getRootSceneNode() { return mRootSceneNode; } - - /// Show or hide the whole terrain - /// @note this setting will be invalidated once you call Terrain::update, so do not call it while the terrain should be hidden - virtual void setVisible(bool visible); - virtual bool getVisible(); - - /// Recreate materials used by terrain chunks. This should be called whenever settings of - /// the material factory are changed. (Relying on the factory to update those materials is not - /// enough, since turning a feature on/off can change the number of texture units available for layer/blend - /// textures, and to properly respond to this we may need to change the structure of the material, such as - /// adding or removing passes. This can only be achieved by a full rebuild.) - virtual void applyMaterials(bool shadows, bool splitShadows); - - int getMaxBatchSize() { return static_cast(mMaxBatchSize); } - - /// Wait until all background loading is complete. - void syncLoad(); - - private: - // Called from a background worker thread - virtual Ogre::WorkQueue::Response* handleRequest(const Ogre::WorkQueue::Request* req, const Ogre::WorkQueue* srcQ); - // Called from the main thread - virtual void handleResponse(const Ogre::WorkQueue::Response* res, const Ogre::WorkQueue* srcQ); - Ogre::uint16 mWorkQueueChannel; - - bool mVisible; - - QuadTreeNode* mRootNode; - Ogre::SceneNode* mRootSceneNode; - - /// The number of chunks currently loading in a background thread. If 0, we have finished loading! - int mChunksLoading; - - Ogre::SceneManager* mCompositeMapSceneMgr; - - /// Bounds in cell units - float mMinX, mMaxX, mMinY, mMaxY; - - /// Minimum size of a terrain batch along one side (in cell units) - float mMinBatchSize; - /// Maximum size of a terrain batch along one side (in cell units) - float mMaxBatchSize; - - void buildQuadTree(QuadTreeNode* node, std::vector& leafs); - - // Are layers for leaf nodes loaded? This is done once at startup (but in a background thread) - bool mLayerLoadPending; - - public: - // ----INTERNAL---- - Ogre::SceneManager* getCompositeMapSceneManager() { return mCompositeMapSceneMgr; } - - bool areLayersLoaded() { return !mLayerLoadPending; } - - // Delete all quads - void clearCompositeMapSceneManager(); - void renderCompositeMap (Ogre::TexturePtr target); - - // Adds a WorkQueue request to load a chunk for this node in the background. - void queueLoad (QuadTreeNode* node); - - private: - Ogre::RenderTarget* mCompositeMapRenderTarget; - Ogre::TexturePtr mCompositeMapRenderTexture; - }; - - struct LoadRequestData - { - QuadTreeNode* mNode; - - friend std::ostream& operator<<(std::ostream& o, const LoadRequestData& r) - { return o; } - }; - - struct LoadResponseData - { - std::vector mPositions; - std::vector mNormals; - std::vector mColours; - - friend std::ostream& operator<<(std::ostream& o, const LoadResponseData& r) - { return o; } - }; - - struct LayersRequestData - { - std::vector mNodes; - bool mPack; - - friend std::ostream& operator<<(std::ostream& o, const LayersRequestData& r) - { return o; } - }; - - struct LayersResponseData - { - std::vector mLayerCollections; - - friend std::ostream& operator<<(std::ostream& o, const LayersResponseData& r) - { return o; } - }; - -} - -#endif diff --git a/components/terrain/defs.hpp b/components/terrain/defs.hpp index 6d173d136..7b40ad479 100644 --- a/components/terrain/defs.hpp +++ b/components/terrain/defs.hpp @@ -22,41 +22,10 @@ #ifndef COMPONENTS_TERRAIN_DEFS_HPP #define COMPONENTS_TERRAIN_DEFS_HPP +#include + namespace Terrain { - class QuadTreeNode; - - /// The alignment of the terrain - enum Alignment - { - /// Terrain is in the X/Z plane - Align_XZ = 0, - /// Terrain is in the X/Y plane - Align_XY = 1, - /// Terrain is in the Y/Z plane. - /// UNTESTED - use at own risk. - /// Besides, X as up axis? What is wrong with you? ;) - Align_YZ = 2 - }; - - inline void convertPosition(Alignment align, float &x, float &y, float &z) - { - switch (align) - { - case Align_XY: - return; - case Align_XZ: - std::swap(y, z); - // This is since -Z should be going *into* the screen - // If not doing this, we'd get wrong vertex winding - z *= -1; - return; - case Align_YZ: - std::swap(x, y); - std::swap(y, z); - return; - } - } enum Direction { @@ -74,13 +43,6 @@ namespace Terrain bool mSpecular; // Specular info in diffuse map alpha channel? }; - struct LayerCollection - { - QuadTreeNode* mTarget; - // Since we can't create a texture from a different thread, this only holds the raw texel data - std::vector mBlendmaps; - std::vector mLayers; - }; } #endif diff --git a/components/terrain/material.cpp b/components/terrain/material.cpp index 4d2318aa6..17acd940b 100644 --- a/components/terrain/material.cpp +++ b/components/terrain/material.cpp @@ -21,353 +21,86 @@ */ #include "material.hpp" -#include -#include -#include +#include -#include +#include +#include +#include +#include +#include -#if TERRAIN_USE_SHADER -#include -#endif - -namespace -{ - -int getBlendmapIndexForLayer (int layerIndex) -{ - return static_cast(std::floor((layerIndex - 1) / 4.f)); -} - -std::string getBlendmapComponentForLayer (int layerIndex) -{ - int n = (layerIndex-1)%4; - if (n == 0) - return "x"; - if (n == 1) - return "y"; - if (n == 2) - return "z"; - else - return "w"; -} - -} +#include namespace Terrain { - MaterialGenerator::MaterialGenerator() - : mShaders(true) - , mShadows(false) - , mSplitShadows(false) - , mNormalMapping(true) - , mParallaxMapping(true) - { - - } - - Ogre::MaterialPtr MaterialGenerator::generate() - { - assert(!mLayerList.empty() && "Can't create material with no layers"); - - return create(false, false); - } - - Ogre::MaterialPtr MaterialGenerator::generateForCompositeMapRTT() - { - assert(!mLayerList.empty() && "Can't create material with no layers"); - - return create(true, false); - } - - Ogre::MaterialPtr MaterialGenerator::generateForCompositeMap() + FixedFunctionTechnique::FixedFunctionTechnique(const std::vector >& layers, + const std::vector >& blendmaps) { - return create(false, true); - } - - Ogre::MaterialPtr MaterialGenerator::create(bool renderCompositeMap, bool displayCompositeMap) - { - assert(!renderCompositeMap || !displayCompositeMap); - - static int count = 0; - std::stringstream name; - name << "terrain/mat" << count++; - - if (!mShaders) + bool firstLayer = true; + int i=0; + for (std::vector >::const_iterator it = layers.begin(); it != layers.end(); ++it) { - Ogre::MaterialPtr mat = Ogre::MaterialManager::getSingleton().create(name.str(), - Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); - Ogre::Technique* technique = mat->getTechnique(0); - technique->removeAllPasses(); + osg::ref_ptr stateset (new osg::StateSet); - if (displayCompositeMap) + if (!firstLayer) { - Ogre::Pass* pass = technique->createPass(); - pass->setVertexColourTracking(Ogre::TVC_AMBIENT|Ogre::TVC_DIFFUSE); - pass->createTextureUnitState(mCompositeMap)->setTextureAddressingMode(Ogre::TextureUnitState::TAM_CLAMP); + stateset->setMode(GL_BLEND, osg::StateAttribute::ON); + osg::ref_ptr depth (new osg::Depth); + depth->setFunction(osg::Depth::EQUAL); + stateset->setAttributeAndModes(depth, osg::StateAttribute::ON); } - else - { - assert(mLayerList.size() == mBlendmapList.size()+1); - std::vector::iterator blend = mBlendmapList.begin(); - for (std::vector::iterator layer = mLayerList.begin(); layer != mLayerList.end(); ++layer) - { - Ogre::Pass* pass = technique->createPass(); - pass->setLightingEnabled(false); - pass->setVertexColourTracking(Ogre::TVC_NONE); - // TODO: How to handle fog? - pass->setFog(true, Ogre::FOG_NONE); - - bool first = (layer == mLayerList.begin()); - - Ogre::TextureUnitState* tus; - if (!first) - { - pass->setSceneBlending(Ogre::SBT_TRANSPARENT_ALPHA); - pass->setDepthFunction(Ogre::CMPF_EQUAL); - - tus = pass->createTextureUnitState((*blend)->getName()); - tus->setAlphaOperation(Ogre::LBX_BLEND_TEXTURE_ALPHA, - Ogre::LBS_TEXTURE, - Ogre::LBS_TEXTURE); - tus->setColourOperationEx(Ogre::LBX_BLEND_DIFFUSE_ALPHA, - Ogre::LBS_TEXTURE, - Ogre::LBS_TEXTURE); - tus->setIsAlpha(true); - tus->setTextureAddressingMode(Ogre::TextureUnitState::TAM_CLAMP); - - float scale = (16/(16.f+1.f)); - tus->setTextureScale(1.f/scale,1.f/scale); - } - - // Add the actual layer texture on top of the alpha map. - tus = pass->createTextureUnitState(layer->mDiffuseMap); - if (!first) - tus->setColourOperationEx(Ogre::LBX_BLEND_DIFFUSE_ALPHA, - Ogre::LBS_TEXTURE, - Ogre::LBS_CURRENT); - - tus->setTextureScale(1/16.f,1/16.f); - - if (!first) - ++blend; - } - - if (!renderCompositeMap) - { - Ogre::Pass* lightingPass = technique->createPass(); - lightingPass->setSceneBlending(Ogre::SBT_MODULATE); - lightingPass->setVertexColourTracking(Ogre::TVC_AMBIENT|Ogre::TVC_DIFFUSE); - lightingPass->setFog(true, Ogre::FOG_NONE); - } - } - - return mat; - } -#if TERRAIN_USE_SHADER - else - { - sh::MaterialInstance* material = sh::Factory::getInstance().createMaterialInstance (name.str()); - material->setProperty ("allow_fixed_function", sh::makeProperty(new sh::BooleanValue(false))); - - if (displayCompositeMap) + int texunit = 0; + if(!firstLayer) { - sh::MaterialInstancePass* p = material->createPass (); + osg::ref_ptr blendmap = blendmaps.at(i++); - p->setProperty ("vertex_program", sh::makeProperty(new sh::StringValue("terrain_vertex"))); - p->setProperty ("fragment_program", sh::makeProperty(new sh::StringValue("terrain_fragment"))); - p->mShaderProperties.setProperty ("is_first_pass", sh::makeProperty(new sh::BooleanValue(true))); - p->mShaderProperties.setProperty ("render_composite_map", sh::makeProperty(new sh::BooleanValue(false))); - p->mShaderProperties.setProperty ("display_composite_map", sh::makeProperty(new sh::BooleanValue(true))); - p->mShaderProperties.setProperty ("num_layers", sh::makeProperty (new sh::StringValue("0"))); - p->mShaderProperties.setProperty ("num_blendmaps", sh::makeProperty (new sh::StringValue("0"))); - p->mShaderProperties.setProperty ("normal_map_enabled", sh::makeProperty (new sh::BooleanValue(false))); - p->mShaderProperties.setProperty ("parallax_enabled", sh::makeProperty (new sh::BooleanValue(false))); - p->mShaderProperties.setProperty ("normal_maps", - sh::makeProperty (new sh::IntValue(0))); + stateset->setTextureAttributeAndModes(texunit, blendmap.get()); - sh::MaterialInstanceTextureUnit* tex = p->createTextureUnit ("compositeMap"); - tex->setProperty ("direct_texture", sh::makeProperty (new sh::StringValue(mCompositeMap))); - tex->setProperty ("tex_address_mode", sh::makeProperty (new sh::StringValue("clamp"))); + // This is to map corner vertices directly to the center of a blendmap texel. + osg::Matrixf texMat; + float scale = (16/(16.f+1.f)); + texMat.preMultTranslate(osg::Vec3f(0.5f, 0.5f, 0.f)); + texMat.preMultScale(osg::Vec3f(scale, scale, 1.f)); + texMat.preMultTranslate(osg::Vec3f(-0.5f, -0.5f, 0.f)); - // shadow. TODO: repeated, put in function - if (mShadows) - { - for (int i = 0; i < (mSplitShadows ? 3 : 1); ++i) - { - sh::MaterialInstanceTextureUnit* shadowTex = p->createTextureUnit ("shadowMap" + Ogre::StringConverter::toString(i)); - shadowTex->setProperty ("content_type", sh::makeProperty (new sh::StringValue("shadow"))); - } - } - p->mShaderProperties.setProperty ("shadowtexture_offset", sh::makeProperty (new sh::StringValue( - Ogre::StringConverter::toString(1)))); + stateset->setTextureAttributeAndModes(texunit, new osg::TexMat(texMat)); - p->mShaderProperties.setProperty ("pass_index", sh::makeProperty(new sh::IntValue(0))); + ++texunit; } - else - { - - bool shadows = mShadows && !renderCompositeMap; - - int layerOffset = 0; - while (layerOffset < (int)mLayerList.size()) - { - int blendmapOffset = (layerOffset == 0) ? 1 : 0; // the first layer of the first pass is the base layer and does not need a blend map - - // Check how many layers we can fit in this pass - int numLayersInThisPass = 0; - int numBlendTextures = 0; - std::vector blendTextures; - int remainingTextureUnits = OGRE_MAX_TEXTURE_LAYERS; - if (shadows) - remainingTextureUnits -= (mSplitShadows ? 3 : 1); - while (remainingTextureUnits && layerOffset + numLayersInThisPass < (int)mLayerList.size()) - { - int layerIndex = numLayersInThisPass + layerOffset; - int neededTextureUnits=0; - int neededBlendTextures=0; + // Add the actual layer texture multiplied by the alpha map. + osg::ref_ptr tex = *it; + stateset->setTextureAttributeAndModes(texunit, tex.get()); - if (layerIndex != 0) - { - std::string blendTextureName = mBlendmapList[getBlendmapIndexForLayer(layerIndex)]->getName(); - if (std::find(blendTextures.begin(), blendTextures.end(), blendTextureName) == blendTextures.end()) - { - blendTextures.push_back(blendTextureName); - ++neededBlendTextures; - ++neededTextureUnits; // blend texture - } - } - ++neededTextureUnits; // layer texture + osg::ref_ptr texMat (new osg::TexMat); + float scale = 16.f; + texMat->setMatrix(osg::Matrix::scale(osg::Vec3f(scale,scale,1.f))); + stateset->setTextureAttributeAndModes(texunit, texMat, osg::StateAttribute::ON); - // Check if this layer has a normal map - if (mNormalMapping && !mLayerList[layerIndex].mNormalMap.empty() && !renderCompositeMap) - ++neededTextureUnits; // normal map - if (neededTextureUnits <= remainingTextureUnits) - { - // We can fit another! - remainingTextureUnits -= neededTextureUnits; - numBlendTextures += neededBlendTextures; - ++numLayersInThisPass; - } - else - break; // We're full - } + firstLayer = false; + addPass(stateset); + } + } - sh::MaterialInstancePass* p = material->createPass (); - p->setProperty ("vertex_program", sh::makeProperty(new sh::StringValue("terrain_vertex"))); - p->setProperty ("fragment_program", sh::makeProperty(new sh::StringValue("terrain_fragment"))); - if (layerOffset != 0) - { - p->setProperty ("scene_blend", sh::makeProperty(new sh::StringValue("alpha_blend"))); - // Only write if depth is equal to the depth value written by the previous pass. - p->setProperty ("depth_func", sh::makeProperty(new sh::StringValue("equal"))); - } - - p->mShaderProperties.setProperty ("render_composite_map", sh::makeProperty(new sh::BooleanValue(renderCompositeMap))); - p->mShaderProperties.setProperty ("display_composite_map", sh::makeProperty(new sh::BooleanValue(displayCompositeMap))); - - p->mShaderProperties.setProperty ("num_layers", sh::makeProperty (new sh::StringValue(Ogre::StringConverter::toString(numLayersInThisPass)))); - p->mShaderProperties.setProperty ("num_blendmaps", sh::makeProperty (new sh::StringValue(Ogre::StringConverter::toString(numBlendTextures)))); - p->mShaderProperties.setProperty ("normal_map_enabled", - sh::makeProperty (new sh::BooleanValue(false))); - - // blend maps - // the index of the first blend map used in this pass - int blendmapStart; - if (mLayerList.size() == 1) // special case. if there's only one layer, we don't need blend maps at all - blendmapStart = 0; - else - blendmapStart = getBlendmapIndexForLayer(layerOffset+blendmapOffset); - for (int i = 0; i < numBlendTextures; ++i) - { - sh::MaterialInstanceTextureUnit* blendTex = p->createTextureUnit ("blendMap" + Ogre::StringConverter::toString(i)); - blendTex->setProperty ("direct_texture", sh::makeProperty (new sh::StringValue(mBlendmapList[blendmapStart+i]->getName()))); - blendTex->setProperty ("tex_address_mode", sh::makeProperty (new sh::StringValue("clamp"))); - } - - // layer maps - bool anyNormalMaps = false; - bool anyParallax = false; - size_t normalMaps = 0; - for (int i = 0; i < numLayersInThisPass; ++i) - { - const LayerInfo& layer = mLayerList[layerOffset+i]; - // diffuse map - sh::MaterialInstanceTextureUnit* diffuseTex = p->createTextureUnit ("diffuseMap" + Ogre::StringConverter::toString(i)); - diffuseTex->setProperty ("direct_texture", sh::makeProperty (new sh::StringValue(layer.mDiffuseMap))); - - // normal map (optional) - bool useNormalMap = mNormalMapping && !mLayerList[layerOffset+i].mNormalMap.empty() && !renderCompositeMap; - bool useParallax = useNormalMap && mParallaxMapping && layer.mParallax; - bool useSpecular = layer.mSpecular; - if (useNormalMap) - { - anyNormalMaps = true; - anyParallax = anyParallax || useParallax; - sh::MaterialInstanceTextureUnit* normalTex = p->createTextureUnit ("normalMap" + Ogre::StringConverter::toString(i)); - normalTex->setProperty ("direct_texture", sh::makeProperty (new sh::StringValue(layer.mNormalMap))); - } - p->mShaderProperties.setProperty ("use_normal_map_" + Ogre::StringConverter::toString(i), - sh::makeProperty (new sh::BooleanValue(useNormalMap))); - p->mShaderProperties.setProperty ("use_parallax_" + Ogre::StringConverter::toString(i), - sh::makeProperty (new sh::BooleanValue(useParallax))); - p->mShaderProperties.setProperty ("use_specular_" + Ogre::StringConverter::toString(i), - sh::makeProperty (new sh::BooleanValue(useSpecular))); - boost::hash_combine(normalMaps, useNormalMap); - boost::hash_combine(normalMaps, useNormalMap && layer.mParallax); - boost::hash_combine(normalMaps, useSpecular); - - if (i+layerOffset > 0) - { - int blendTextureIndex = getBlendmapIndexForLayer(layerOffset+i); - std::string blendTextureComponent = getBlendmapComponentForLayer(layerOffset+i); - p->mShaderProperties.setProperty ("blendmap_component_" + Ogre::StringConverter::toString(i), - sh::makeProperty (new sh::StringValue(Ogre::StringConverter::toString(blendTextureIndex-blendmapStart) + "." + blendTextureComponent))); - } - else - { - // just to make it shut up about blendmap_component_0 not existing in the first pass. - // it might be retrieved, but will never survive the preprocessing step. - p->mShaderProperties.setProperty ("blendmap_component_" + Ogre::StringConverter::toString(i), - sh::makeProperty (new sh::StringValue(""))); - } - } - p->mShaderProperties.setProperty ("normal_map_enabled", - sh::makeProperty (new sh::BooleanValue(anyNormalMaps))); - p->mShaderProperties.setProperty ("parallax_enabled", - sh::makeProperty (new sh::BooleanValue(anyParallax))); - // Since the permutation handler can't handle dynamic property names, - // combine normal map settings for all layers into one value - p->mShaderProperties.setProperty ("normal_maps", - sh::makeProperty (new sh::IntValue(normalMaps))); - - // shadow - if (shadows) - { - for (int i = 0; i < (mSplitShadows ? 3 : 1); ++i) - { - sh::MaterialInstanceTextureUnit* shadowTex = p->createTextureUnit ("shadowMap" + Ogre::StringConverter::toString(i)); - shadowTex->setProperty ("content_type", sh::makeProperty (new sh::StringValue("shadow"))); - } - } - p->mShaderProperties.setProperty ("shadowtexture_offset", sh::makeProperty (new sh::StringValue( - Ogre::StringConverter::toString(numBlendTextures + numLayersInThisPass)))); + Effect::Effect(const std::vector > &layers, const std::vector > &blendmaps) + : mLayers(layers) + , mBlendmaps(blendmaps) + { + osg::ref_ptr material (new osg::Material); + material->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE); + getOrCreateStateSet()->setAttributeAndModes(material, osg::StateAttribute::ON); - // Make sure the pass index is fed to the permutation handler, because blendmap components may be different - p->mShaderProperties.setProperty ("pass_index", sh::makeProperty(new sh::IntValue(layerOffset))); + selectTechnique(0); + } - assert ((int)p->mTexUnits.size() == OGRE_MAX_TEXTURE_LAYERS - remainingTextureUnits); + bool Effect::define_techniques() + { + addTechnique(new FixedFunctionTechnique(mLayers, mBlendmaps)); - layerOffset += numLayersInThisPass; - } - } - } -#endif - return Ogre::MaterialManager::getSingleton().getByName(name.str()); + return true; } } diff --git a/components/terrain/material.hpp b/components/terrain/material.hpp index b79df9f48..47c5142c9 100644 --- a/components/terrain/material.hpp +++ b/components/terrain/material.hpp @@ -22,51 +22,55 @@ #ifndef COMPONENTS_TERRAIN_MATERIAL_H #define COMPONENTS_TERRAIN_MATERIAL_H -#include +#include +#include -#include "storage.hpp" +#include "defs.hpp" + +namespace osg +{ + class Texture2D; +} namespace Terrain { - class MaterialGenerator + class FixedFunctionTechnique : public osgFX::Technique { public: - MaterialGenerator (); - - void setLayerList (const std::vector& layerList) { mLayerList = layerList; } - bool hasLayers() { return mLayerList.size() > 0; } - void setBlendmapList (const std::vector& blendmapList) { mBlendmapList = blendmapList; } - const std::vector& getBlendmapList() { return mBlendmapList; } - void setCompositeMap (const std::string& name) { mCompositeMap = name; } + FixedFunctionTechnique( + const std::vector >& layers, + const std::vector >& blendmaps); - void enableShaders(bool shaders) { mShaders = shaders; } - void enableShadows(bool shadows) { mShadows = shadows; } - void enableNormalMapping(bool normalMapping) { mNormalMapping = normalMapping; } - void enableParallaxMapping(bool parallaxMapping) { mParallaxMapping = parallaxMapping; } - void enableSplitShadows(bool splitShadows) { mSplitShadows = splitShadows; } + protected: + virtual void define_passes() {} + }; - /// Creates a material suitable for displaying a chunk of terrain using alpha-blending. - Ogre::MaterialPtr generate (); + class Effect : public osgFX::Effect + { + public: + Effect( + const std::vector >& layers, + const std::vector >& blendmaps); - /// Creates a material suitable for displaying a chunk of terrain using a ready-made composite map. - Ogre::MaterialPtr generateForCompositeMap (); + virtual bool define_techniques(); - /// Creates a material suitable for rendering composite maps, i.e. for "baking" several layer textures - /// into one. The main difference compared to a normal material is that no shading is applied at this point. - Ogre::MaterialPtr generateForCompositeMapRTT (); + virtual const char *effectName() const + { + return NULL; + } + virtual const char *effectDescription() const + { + return NULL; + } + virtual const char *effectAuthor() const + { + return NULL; + } private: - Ogre::MaterialPtr create (bool renderCompositeMap, bool displayCompositeMap); - - std::vector mLayerList; - std::vector mBlendmapList; - std::string mCompositeMap; - bool mShaders; - bool mShadows; - bool mSplitShadows; - bool mNormalMapping; - bool mParallaxMapping; + std::vector > mLayers; + std::vector > mBlendmaps; }; } diff --git a/components/terrain/quadtreenode.cpp b/components/terrain/quadtreenode.cpp deleted file mode 100644 index 89e5e34a3..000000000 --- a/components/terrain/quadtreenode.cpp +++ /dev/null @@ -1,611 +0,0 @@ -/* - * Copyright (c) 2015 scrawl - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "quadtreenode.hpp" - -#include -#include -#include -#include -#include - -#include "defaultworld.hpp" -#include "chunk.hpp" -#include "storage.hpp" -#include "buffercache.hpp" -#include "material.hpp" - -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) - { - assert(dir != Root); - - const int lookupTable[4][4] = - { - // NW NE SW SE - { SW, SE, NW, NE }, // N - { NE, NW, SE, SW }, // E - { SW, SE, NW, NE }, // S - { NE, NW, SE, SW } // W - }; - return (ChildDirection)lookupTable[dir2][dir]; - } - - bool adjacent(ChildDirection dir, Direction dir2) - { - assert(dir != Root); - const bool lookupTable[4][4] = - { - // NW NE SW SE - { true, true, false, false }, // N - { false, true, false, true }, // E - { false, false, true, true }, // S - { true, false, true, false } // W - }; - return lookupTable[dir2][dir]; - } - - // Algorithm described by Hanan Samet - 'Neighbour Finding in Quadtrees' - // http://www.cs.umd.edu/~hjs/pubs/SametPRIP81.pdf - QuadTreeNode* searchNeighbourRecursive (QuadTreeNode* currentNode, Direction dir) - { - if (!currentNode->getParent()) - return NULL; // Arrived at root node, the root node does not have neighbours - - QuadTreeNode* nextNode; - if (adjacent(currentNode->getDirection(), dir)) - nextNode = searchNeighbourRecursive(currentNode->getParent(), dir); - else - nextNode = currentNode->getParent(); - - if (nextNode && nextNode->hasChildren()) - return nextNode->getChild(reflect(currentNode->getDirection(), dir)); - else - return NULL; - } - - // Create a 2D quad - void makeQuad(Ogre::SceneManager* sceneMgr, float left, float top, float right, float bottom, Ogre::MaterialPtr material) - { - Ogre::ManualObject* manual = sceneMgr->createManualObject(); - - // Use identity view/projection matrices to get a 2d quad - manual->setUseIdentityProjection(true); - manual->setUseIdentityView(true); - - manual->begin(material->getName()); - - float normLeft = left*2-1; - float normTop = top*2-1; - float normRight = right*2-1; - float normBottom = bottom*2-1; - - manual->position(normLeft, normTop, 0.0); - manual->textureCoord(0, 1); - manual->position(normRight, normTop, 0.0); - manual->textureCoord(1, 1); - manual->position(normRight, normBottom, 0.0); - manual->textureCoord(1, 0); - manual->position(normLeft, normBottom, 0.0); - manual->textureCoord(0, 0); - - manual->quad(0,1,2,3); - - manual->end(); - - Ogre::AxisAlignedBox aabInf; - aabInf.setInfinite(); - manual->setBoundingBox(aabInf); - - sceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(manual); - } -} - -QuadTreeNode::QuadTreeNode(DefaultWorld* terrain, ChildDirection dir, float size, const Ogre::Vector2 ¢er, QuadTreeNode* parent) - : mMaterialGenerator(NULL) - , mLoadState(LS_Unloaded) - , mIsDummy(false) - , mSize(size) - , mLodLevel(Log2(static_cast(mSize))) - , mBounds(Ogre::AxisAlignedBox::BOX_NULL) - , mWorldBounds(Ogre::AxisAlignedBox::BOX_NULL) - , mDirection(dir) - , mCenter(center) - , mSceneNode(NULL) - , mParent(parent) - , mChunk(NULL) - , mTerrain(terrain) -{ - mBounds.setNull(); - for (int i=0; i<4; ++i) - mChildren[i] = NULL; - for (int i=0; i<4; ++i) - mNeighbours[i] = NULL; - - if (mDirection == Root) - mSceneNode = mTerrain->getRootSceneNode(); - else - mSceneNode = mTerrain->getSceneManager()->createSceneNode(); - Ogre::Vector2 pos (0,0); - if (mParent) - pos = mParent->getCenter(); - pos = mCenter - pos; - float cellWorldSize = mTerrain->getStorage()->getCellWorldSize(); - - Ogre::Vector3 sceneNodePos (pos.x*cellWorldSize, pos.y*cellWorldSize, 0); - mTerrain->convertPosition(sceneNodePos); - - mSceneNode->setPosition(sceneNodePos); - - mMaterialGenerator = new MaterialGenerator(); - mMaterialGenerator->enableShaders(mTerrain->getShadersEnabled()); -} - -void QuadTreeNode::createChild(ChildDirection id, float size, const Ogre::Vector2 ¢er) -{ - mChildren[id] = new QuadTreeNode(mTerrain, id, size, center, this); -} - -QuadTreeNode::~QuadTreeNode() -{ - for (int i=0; i<4; ++i) - delete mChildren[i]; - delete mChunk; - delete mMaterialGenerator; -} - -QuadTreeNode* QuadTreeNode::getNeighbour(Direction dir) -{ - return mNeighbours[static_cast(dir)]; -} - -void QuadTreeNode::initNeighbours() -{ - for (int i=0; i<4; ++i) - mNeighbours[i] = searchNeighbourRecursive(this, (Direction)i); - - if (hasChildren()) - for (int i=0; i<4; ++i) - mChildren[i]->initNeighbours(); -} - -void QuadTreeNode::initAabb() -{ - float cellWorldSize = mTerrain->getStorage()->getCellWorldSize(); - if (hasChildren()) - { - for (int i=0; i<4; ++i) - { - mChildren[i]->initAabb(); - mBounds.merge(mChildren[i]->getBoundingBox()); - } - float minH, maxH; - switch (mTerrain->getAlign()) - { - case Terrain::Align_XY: - minH = mBounds.getMinimum().z; - maxH = mBounds.getMaximum().z; - break; - case Terrain::Align_XZ: - minH = mBounds.getMinimum().y; - maxH = mBounds.getMaximum().y; - break; - case Terrain::Align_YZ: - minH = mBounds.getMinimum().x; - maxH = mBounds.getMaximum().x; - break; - } - Ogre::Vector3 min(-mSize/2*cellWorldSize, -mSize/2*cellWorldSize, minH); - Ogre::Vector3 max(Ogre::Vector3(mSize/2*cellWorldSize, mSize/2*cellWorldSize, maxH)); - mBounds = Ogre::AxisAlignedBox (min, max); - mTerrain->convertBounds(mBounds); - } - Ogre::Vector3 offset(mCenter.x*cellWorldSize, mCenter.y*cellWorldSize, 0); - mTerrain->convertPosition(offset); - mWorldBounds = Ogre::AxisAlignedBox(mBounds.getMinimum() + offset, - mBounds.getMaximum() + offset); -} - -void QuadTreeNode::setBoundingBox(const Ogre::AxisAlignedBox &box) -{ - mBounds = box; -} - -const Ogre::AxisAlignedBox& QuadTreeNode::getBoundingBox() -{ - return mBounds; -} - -const Ogre::AxisAlignedBox& QuadTreeNode::getWorldBoundingBox() -{ - return mWorldBounds; -} - -bool QuadTreeNode::update(const Ogre::Vector3 &cameraPos) -{ - if (isDummy()) - return true; - - if (mBounds.isNull()) - return true; - - float dist = mWorldBounds.distance(cameraPos); - - // Make sure our scene node is attached - if (!mSceneNode->isInSceneGraph()) - { - mParent->getSceneNode()->addChild(mSceneNode); - } - - // Simple LOD selection - /// \todo use error metrics? - size_t wantedLod = 0; - float cellWorldSize = mTerrain->getStorage()->getCellWorldSize(); - - if (dist > cellWorldSize*64) - wantedLod = 6; - else if (dist > cellWorldSize*32) - wantedLod = 5; - else if (dist > cellWorldSize*12) - wantedLod = 4; - else if (dist > cellWorldSize*5) - wantedLod = 3; - else if (dist > cellWorldSize*2) - wantedLod = 2; - else if (dist > cellWorldSize * 1.42) // < sqrt2 so the 3x3 grid around player is always highest lod - wantedLod = 1; - - bool wantToDisplay = mSize <= mTerrain->getMaxBatchSize() && mLodLevel <= wantedLod; - - if (wantToDisplay) - { - // Wanted LOD is small enough to render this node in one chunk - if (mLoadState == LS_Unloaded) - { - mLoadState = LS_Loading; - mTerrain->queueLoad(this); - return false; - } - - if (mLoadState == LS_Loaded) - { - // Additional (index buffer) LOD is currently disabled. - // This is due to a problem with the LOD selection when a node splits. - // After splitting, the distance is measured from the children's bounding boxes, which are possibly - // further away than the original node's bounding box, possibly causing a child to switch to a *lower* LOD - // than the original node. - // In short, we'd sometimes get a switch to a lesser detail when actually moving closer. - // This wouldn't be so bad, but unfortunately it also breaks LOD edge connections if a neighbour - // node hasn't split yet, and has a higher LOD than our node's child: - // ----- ----- ------------ - // | LOD | LOD | | - // | 1 | 1 | | - // |-----|-----| LOD 0 | - // | LOD | LOD | | - // | 0 | 0 | | - // ----- ----- ------------ - // To prevent this, nodes of the same size need to always select the same LOD, which is basically what we're - // doing here. - // But this "solution" does increase triangle overhead, so eventually we need to find a more clever way. - //mChunk->setAdditionalLod(wantedLod - mLodLevel); - - if (!mChunk->getVisible() && hasChildren()) - { - for (int i=0; i<4; ++i) - mChildren[i]->unload(true); - } - mChunk->setVisible(true); - - return true; - } - return false; // LS_Loading - } - - // We do not want to display this node - delegate to children if they are already loaded - if (!wantToDisplay && hasChildren()) - { - if (mChunk) - { - // Are children already loaded? - bool childrenLoaded = true; - for (int i=0; i<4; ++i) - if (!mChildren[i]->update(cameraPos)) - childrenLoaded = false; - - if (!childrenLoaded) - { - mChunk->setVisible(true); - // Make sure child scene nodes are detached until all children are loaded - mSceneNode->removeAllChildren(); - } - else - { - // Delegation went well, we can unload now - unload(); - - for (int i=0; i<4; ++i) - { - if (!mChildren[i]->getSceneNode()->isInSceneGraph()) - mSceneNode->addChild(mChildren[i]->getSceneNode()); - } - } - return true; - } - else - { - bool success = true; - for (int i=0; i<4; ++i) - success = mChildren[i]->update(cameraPos) & success; - return success; - } - } - return false; -} - -void QuadTreeNode::load(const LoadResponseData &data) -{ - assert (!mChunk); - - mChunk = new Chunk(mTerrain->getBufferCache().getUVBuffer(), mBounds, data.mPositions, data.mNormals, data.mColours); - mChunk->setVisibilityFlags(mTerrain->getVisibilityFlags()); - mChunk->setCastShadows(true); - mSceneNode->attachObject(mChunk); - - mMaterialGenerator->enableShadows(mTerrain->getShadowsEnabled()); - mMaterialGenerator->enableSplitShadows(mTerrain->getSplitShadowsEnabled()); - - if (mTerrain->areLayersLoaded()) - { - if (mSize == 1) - { - mChunk->setMaterial(mMaterialGenerator->generate()); - } - else - { - ensureCompositeMap(); - mMaterialGenerator->setCompositeMap(mCompositeMap->getName()); - mChunk->setMaterial(mMaterialGenerator->generateForCompositeMap()); - } - } - // else: will be loaded in loadMaterials() after background thread has finished loading layers - mChunk->setVisible(false); - - mLoadState = LS_Loaded; -} - -void QuadTreeNode::unload(bool recursive) -{ - if (mChunk) - { - mSceneNode->detachObject(mChunk); - - delete mChunk; - mChunk = NULL; - - if (!mCompositeMap.isNull()) - { - Ogre::TextureManager::getSingleton().remove(mCompositeMap->getName()); - mCompositeMap.setNull(); - } - - // Do *not* set this when we are still loading! - mLoadState = LS_Unloaded; - } - - if (recursive && hasChildren()) - { - for (int i=0; i<4; ++i) - mChildren[i]->unload(true); - } -} - -void QuadTreeNode::updateIndexBuffers() -{ - if (hasChunk()) - { - // Fetch a suitable index buffer (which may be shared) - size_t ourLod = getActualLodLevel(); - - unsigned int flags = 0; - - for (int i=0; i<4; ++i) - { - QuadTreeNode* neighbour = getNeighbour((Direction)i); - - // If the neighbour isn't currently rendering itself, - // go up until we find one. NOTE: We don't need to go down, - // because in that case neighbour's detail would be higher than - // our detail and the neighbour would handle stitching by itself. - while (neighbour && !neighbour->hasChunk()) - neighbour = neighbour->getParent(); - size_t lod = 0; - if (neighbour) - lod = neighbour->getActualLodLevel(); - if (lod <= ourLod) // We only need to worry about neighbours less detailed than we are - - lod = 0; // neighbours with more detail will do the stitching themselves - // Use 4 bits for each LOD delta - if (lod > 0) - { - assert (lod - ourLod < (1 << 4)); - flags |= static_cast(lod - ourLod) << (4*i); - } - } - flags |= 0 /*((int)mAdditionalLod)*/ << (4*4); - - mChunk->setIndexBuffer(mTerrain->getBufferCache().getIndexBuffer(flags)); - } - else if (hasChildren()) - { - for (int i=0; i<4; ++i) - mChildren[i]->updateIndexBuffers(); - } -} - -bool QuadTreeNode::hasChunk() -{ - return mSceneNode->isInSceneGraph() && mChunk && mChunk->getVisible(); -} - -size_t QuadTreeNode::getActualLodLevel() -{ - assert(hasChunk() && "Can't get actual LOD level if this node has no render chunk"); - return mLodLevel /* + mChunk->getAdditionalLod() */; -} - -void QuadTreeNode::loadLayers(const LayerCollection& collection) -{ - assert (!mMaterialGenerator->hasLayers()); - - std::vector blendTextures; - for (std::vector::const_iterator it = collection.mBlendmaps.begin(); it != collection.mBlendmaps.end(); ++it) - { - // TODO: clean up blend textures on destruction - static int count=0; - Ogre::TexturePtr map = Ogre::TextureManager::getSingleton().createManual("terrain/blend/" - + Ogre::StringConverter::toString(count++), Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - Ogre::TEX_TYPE_2D, it->getWidth(), it->getHeight(), 0, it->format); - - Ogre::DataStreamPtr stream(new Ogre::MemoryDataStream(it->data, it->getWidth()*it->getHeight()*Ogre::PixelUtil::getNumElemBytes(it->format), true)); - map->loadRawData(stream, it->getWidth(), it->getHeight(), it->format); - blendTextures.push_back(map); - } - - mMaterialGenerator->setLayerList(collection.mLayers); - mMaterialGenerator->setBlendmapList(blendTextures); -} - -void QuadTreeNode::loadMaterials() -{ - if (isDummy()) - return; - - // Load children first since we depend on them when creating a composite map - if (hasChildren()) - { - for (int i=0; i<4; ++i) - mChildren[i]->loadMaterials(); - } - - if (mChunk) - { - if (mSize == 1) - { - mChunk->setMaterial(mMaterialGenerator->generate()); - } - else - { - ensureCompositeMap(); - mMaterialGenerator->setCompositeMap(mCompositeMap->getName()); - mChunk->setMaterial(mMaterialGenerator->generateForCompositeMap()); - } - } -} - -void QuadTreeNode::prepareForCompositeMap(Ogre::TRect area) -{ - Ogre::SceneManager* sceneMgr = mTerrain->getCompositeMapSceneManager(); - - if (mIsDummy) - { - // TODO - store this default material somewhere instead of creating one for each empty cell - MaterialGenerator matGen; - matGen.enableShaders(mTerrain->getShadersEnabled()); - std::vector layer; - layer.push_back(mTerrain->getStorage()->getDefaultLayer()); - matGen.setLayerList(layer); - makeQuad(sceneMgr, area.left, area.top, area.right, area.bottom, matGen.generateForCompositeMapRTT()); - return; - } - if (mSize > 1) - { - assert(hasChildren()); - - // 0,0 -------- 1,0 - // | | | - // |-----|------| - // | | | - // 0,1 -------- 1,1 - - float halfW = area.width()/2.f; - float halfH = area.height()/2.f; - mChildren[NW]->prepareForCompositeMap(Ogre::TRect(area.left, area.top, area.right-halfW, area.bottom-halfH)); - mChildren[NE]->prepareForCompositeMap(Ogre::TRect(area.left+halfW, area.top, area.right, area.bottom-halfH)); - mChildren[SW]->prepareForCompositeMap(Ogre::TRect(area.left, area.top+halfH, area.right-halfW, area.bottom)); - mChildren[SE]->prepareForCompositeMap(Ogre::TRect(area.left+halfW, area.top+halfH, area.right, area.bottom)); - } - else - { - // TODO: when to destroy? - Ogre::MaterialPtr material = mMaterialGenerator->generateForCompositeMapRTT(); - makeQuad(sceneMgr, area.left, area.top, area.right, area.bottom, material); - } -} - -void QuadTreeNode::ensureCompositeMap() -{ - if (!mCompositeMap.isNull()) - return; - - static int i=0; - std::stringstream name; - name << "terrain/comp" << i++; - - const int size = 128; - mCompositeMap = Ogre::TextureManager::getSingleton().createManual( - name.str(), Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - Ogre::TEX_TYPE_2D, size, size, Ogre::MIP_DEFAULT, Ogre::PF_A8B8G8R8); - - // Create quads for each cell - prepareForCompositeMap(Ogre::TRect(0,0,1,1)); - - mTerrain->renderCompositeMap(mCompositeMap); - - mTerrain->clearCompositeMapSceneManager(); - -} - -void QuadTreeNode::applyMaterials() -{ - if (mChunk) - { - mMaterialGenerator->enableShadows(mTerrain->getShadowsEnabled()); - mMaterialGenerator->enableSplitShadows(mTerrain->getSplitShadowsEnabled()); - if (mSize <= 1) - mChunk->setMaterial(mMaterialGenerator->generate()); - else - mChunk->setMaterial(mMaterialGenerator->generateForCompositeMap()); - } - if (hasChildren()) - for (int i=0; i<4; ++i) - mChildren[i]->applyMaterials(); -} diff --git a/components/terrain/quadtreenode.hpp b/components/terrain/quadtreenode.hpp deleted file mode 100644 index e44b64600..000000000 --- a/components/terrain/quadtreenode.hpp +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Copyright (c) 2015 scrawl - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#ifndef COMPONENTS_TERRAIN_QUADTREENODE_H -#define COMPONENTS_TERRAIN_QUADTREENODE_H - -#include -#include -#include - -#include "defs.hpp" - -namespace Ogre -{ - class Rectangle2D; -} - -namespace Terrain -{ - class DefaultWorld; - class Chunk; - class MaterialGenerator; - struct LoadResponseData; - - enum ChildDirection - { - NW = 0, - NE = 1, - SW = 2, - SE = 3, - Root - }; - - enum LoadState - { - LS_Unloaded, - LS_Loading, - LS_Loaded - }; - - /** - * @brief A node in the quad tree for our terrain. Depending on LOD, - * a node can either choose to render itself in one batch (merging its children), - * or delegate the render process to its children, rendering each child in at least one batch. - */ - class QuadTreeNode - { - public: - /// @param terrain - /// @param dir relative to parent, or Root if we are the root node - /// @param size size (in *cell* units!) - /// @param center center (in *cell* units!) - /// @param parent parent node - QuadTreeNode (DefaultWorld* terrain, ChildDirection dir, float size, const Ogre::Vector2& center, QuadTreeNode* parent); - ~QuadTreeNode(); - - /// Rebuild all materials - void applyMaterials(); - - /// Initialize neighbours - do this after the quadtree is built - void initNeighbours(); - /// Initialize bounding boxes of non-leafs by merging children bounding boxes. - /// Do this after the quadtree is built - note that leaf bounding boxes - /// need to be set first via setBoundingBox! - void initAabb(); - - /// @note takes ownership of \a child - void createChild (ChildDirection id, float size, const Ogre::Vector2& center); - - /// Mark this node as a dummy node. This can happen if the terrain size isn't a power of two. - /// For the QuadTree to work, we need to round the size up to a power of two, which means we'll - /// end up with empty nodes that don't actually render anything. - void markAsDummy() { mIsDummy = true; } - bool isDummy() { return mIsDummy; } - - QuadTreeNode* getParent() { return mParent; } - - Ogre::SceneNode* getSceneNode() { return mSceneNode; } - - int getSize() { return static_cast(mSize); } - Ogre::Vector2 getCenter() { return mCenter; } - - bool hasChildren() { return mChildren[0] != 0; } - QuadTreeNode* getChild(ChildDirection dir) { return mChildren[dir]; } - - /// Get neighbour node in this direction - QuadTreeNode* getNeighbour (Direction dir); - - /// Returns our direction relative to the parent node, or Root if we are the root node. - ChildDirection getDirection() { return mDirection; } - - /// Set bounding box in local coordinates. Should be done at load time for leaf nodes. - /// Other nodes can merge AABB of child nodes. - void setBoundingBox (const Ogre::AxisAlignedBox& box); - - /// Get bounding box in local coordinates - const Ogre::AxisAlignedBox& getBoundingBox(); - - const Ogre::AxisAlignedBox& getWorldBoundingBox(); - - DefaultWorld* getTerrain() { return mTerrain; } - - /// Adjust LODs for the given camera position, possibly splitting up chunks or merging them. - /// @return Did we (or all of our children) choose to render? - bool update (const Ogre::Vector3& cameraPos); - - /// Adjust index buffers of chunks to stitch together chunks of different LOD, so that cracks are avoided. - /// Call after QuadTreeNode::update! - void updateIndexBuffers(); - - /// Destroy chunks rendered by this node *and* its children (if param is true) - void destroyChunks(bool children); - - /// Get the effective LOD level if this node was rendered in one chunk - /// with Storage::getCellVertices^2 vertices - size_t getNativeLodLevel() { return mLodLevel; } - - /// Get the effective current LOD level used by the chunk rendering this node - size_t getActualLodLevel(); - - /// Is this node currently configured to render itself? - bool hasChunk(); - - /// Add a textured quad to a specific 2d area in the composite map scenemanager. - /// Only nodes with size <= 1 can be rendered with alpha blending, so larger nodes will simply - /// call this method on their children. - /// @note Do not call this before World::areLayersLoaded() == true - /// @param area area in image space to put the quad - void prepareForCompositeMap(Ogre::TRect area); - - /// Create a chunk for this node from the given data. - void load (const LoadResponseData& data); - void unload(bool recursive=false); - void loadLayers (const LayerCollection& collection); - /// This is recursive! Call it once on the root node after all leafs have loaded layers. - void loadMaterials(); - - LoadState getLoadState() { return mLoadState; } - - private: - // Stored here for convenience in case we need layer list again - MaterialGenerator* mMaterialGenerator; - - LoadState mLoadState; - - bool mIsDummy; - float mSize; - size_t mLodLevel; // LOD if we were to render this node in one chunk - Ogre::AxisAlignedBox mBounds; - Ogre::AxisAlignedBox mWorldBounds; - ChildDirection mDirection; - Ogre::Vector2 mCenter; - - Ogre::SceneNode* mSceneNode; - - QuadTreeNode* mParent; - QuadTreeNode* mChildren[4]; - QuadTreeNode* mNeighbours[4]; - - Chunk* mChunk; - - DefaultWorld* mTerrain; - - Ogre::TexturePtr mCompositeMap; - - void ensureCompositeMap(); - }; - -} - -#endif diff --git a/components/terrain/storage.cpp b/components/terrain/storage.cpp index 14009127d..857713a82 100644 --- a/components/terrain/storage.cpp +++ b/components/terrain/storage.cpp @@ -19,3 +19,5 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ + +#include "storage.hpp" diff --git a/components/terrain/storage.hpp b/components/terrain/storage.hpp index 7846e91c6..a302c8f8c 100644 --- a/components/terrain/storage.hpp +++ b/components/terrain/storage.hpp @@ -22,10 +22,20 @@ #ifndef COMPONENTS_TERRAIN_STORAGE_H #define COMPONENTS_TERRAIN_STORAGE_H -#include +#include + +#include +#include +#include +#include #include "defs.hpp" +namespace osg +{ + class Image; +} + namespace Terrain { /// We keep storage of terrain data abstract here since we need different implementations for game and editor @@ -46,7 +56,7 @@ namespace Terrain /// @param min min height will be stored here /// @param max max height will be stored here /// @return true if there was data available for this terrain chunk - virtual bool getMinMaxHeights (float size, const Ogre::Vector2& center, float& min, float& max) = 0; + virtual bool getMinMaxHeights (float size, const osg::Vec2f& center, float& min, float& max) = 0; /// Fill vertex buffers for a terrain chunk. /// @note May be called from background threads. Make sure to only call thread-safe functions from here! @@ -59,11 +69,12 @@ namespace Terrain /// @param positions buffer to write vertices /// @param normals buffer to write vertex normals /// @param colours buffer to write vertex colours - virtual void fillVertexBuffers (int lodLevel, float size, const Ogre::Vector2& center, Terrain::Alignment align, - std::vector& positions, - std::vector& normals, - std::vector& colours) = 0; + virtual void fillVertexBuffers (int lodLevel, float size, const osg::Vec2f& center, + osg::ref_ptr positions, + osg::ref_ptr normals, + osg::ref_ptr colours) = 0; + typedef std::vector > ImageVector; /// Create textures holding layer blend values for a terrain chunk. /// @note The terrain chunk shouldn't be larger than one cell since otherwise we might /// have to do a ridiculous amount of different layers. For larger chunks, composite maps should be used. @@ -75,23 +86,11 @@ namespace Terrain /// can utilize packing, FFP can't. /// @param blendmaps created blendmaps will be written here /// @param layerList names of the layer textures used will be written here - virtual void getBlendmaps (float chunkSize, const Ogre::Vector2& chunkCenter, bool pack, - std::vector& blendmaps, + virtual void getBlendmaps (float chunkSize, const osg::Vec2f& chunkCenter, bool pack, + ImageVector& blendmaps, std::vector& layerList) = 0; - /// Retrieve pixel data for textures holding layer blend values for terrain chunks and layer texture information. - /// This variant is provided to eliminate the overhead of virtual function calls when retrieving a large number of blendmaps at once. - /// @note The terrain chunks shouldn't be larger than one cell since otherwise we might - /// have to do a ridiculous amount of different layers. For larger chunks, composite maps should be used. - /// @note May be called from background threads. Make sure to only call thread-safe functions from here! - /// @param nodes A collection of nodes for which to retrieve the aforementioned data - /// @param out Output vector - /// @param pack Whether to pack blend values for up to 4 layers into one texture (one in each channel) - - /// otherwise, each texture contains blend values for one layer only. Shader-based rendering - /// can utilize packing, FFP can't. - virtual void getBlendmaps (const std::vector& nodes, std::vector& out, bool pack) = 0; - - virtual float getHeightAt (const Ogre::Vector3& worldPos) = 0; + virtual float getHeightAt (const osg::Vec3f& worldPos) = 0; virtual LayerInfo getDefaultLayer() = 0; diff --git a/components/terrain/terraingrid.cpp b/components/terrain/terraingrid.cpp index bb99ca23e..e99126a2a 100644 --- a/components/terrain/terraingrid.cpp +++ b/components/terrain/terraingrid.cpp @@ -19,22 +19,54 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ + #include "terraingrid.hpp" -#include -#include -#include +#include + +#include +#include + +#include + +#include +#include +#include + +#include + +#include -#include "chunk.hpp" +#include "material.hpp" +#include "storage.hpp" + +namespace +{ + class StaticBoundingBoxCallback : public osg::Drawable::ComputeBoundingBoxCallback + { + public: + StaticBoundingBoxCallback(const osg::BoundingBox& bounds) + : mBoundingBox(bounds) + { + } + + virtual osg::BoundingBox computeBound(const osg::Drawable&) const + { + return mBoundingBox; + } + + private: + osg::BoundingBox mBoundingBox; + }; +} namespace Terrain { -TerrainGrid::TerrainGrid(Ogre::SceneManager *sceneMgr, Terrain::Storage *storage, int visibilityFlags, bool shaders, Terrain::Alignment align) - : Terrain::World(sceneMgr, storage, visibilityFlags, shaders, align) - , mVisible(true) +TerrainGrid::TerrainGrid(osg::Group* parent, Resource::ResourceSystem* resourceSystem, osgUtil::IncrementalCompileOperation* ico, + Storage* storage, int nodeMask) + : Terrain::World(parent, resourceSystem, ico, storage, nodeMask) { - mRootNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(); } TerrainGrid::~TerrainGrid() @@ -43,143 +75,118 @@ TerrainGrid::~TerrainGrid() { unloadCell(mGrid.begin()->first.first, mGrid.begin()->first.second); } - - mSceneMgr->destroySceneNode(mRootNode); } -void TerrainGrid::update(const Ogre::Vector3 &cameraPos) +class GridElement { -} +public: + osg::ref_ptr mNode; +}; void TerrainGrid::loadCell(int x, int y) { if (mGrid.find(std::make_pair(x, y)) != mGrid.end()) return; // already loaded - Ogre::Vector2 center(x+0.5f, y+0.5f); + osg::Vec2f center(x+0.5f, y+0.5f); float minH, maxH; if (!mStorage->getMinMaxHeights(1, center, minH, maxH)) return; // no terrain defined - Ogre::Vector3 min (-0.5f*mStorage->getCellWorldSize(), - -0.5f*mStorage->getCellWorldSize(), - minH); - Ogre::Vector3 max (0.5f*mStorage->getCellWorldSize(), - 0.5f*mStorage->getCellWorldSize(), - maxH); - - Ogre::AxisAlignedBox bounds(min, max); + std::auto_ptr element (new GridElement); - GridElement element; + osg::Vec2f worldCenter = center*mStorage->getCellWorldSize(); + element->mNode = new osg::PositionAttitudeTransform; + element->mNode->setPosition(osg::Vec3f(worldCenter.x(), worldCenter.y(), 0.f)); + mTerrainRoot->addChild(element->mNode); - Ogre::Vector2 worldCenter = center*mStorage->getCellWorldSize(); - element.mSceneNode = mRootNode->createChildSceneNode(Ogre::Vector3(worldCenter.x, worldCenter.y, 0)); + osg::ref_ptr positions (new osg::Vec3Array); + osg::ref_ptr normals (new osg::Vec3Array); + osg::ref_ptr colors (new osg::Vec4Array); - std::vector positions; - std::vector normals; - std::vector colours; - mStorage->fillVertexBuffers(0, 1, center, mAlign, positions, normals, colours); + mStorage->fillVertexBuffers(0, 1, center, positions, normals, colors); - element.mChunk = new Terrain::Chunk(mCache.getUVBuffer(), bounds, positions, normals, colours); - element.mChunk->setIndexBuffer(mCache.getIndexBuffer(0)); - element.mChunk->setVisibilityFlags(mVisibilityFlags); - element.mChunk->setCastShadows(true); + osg::ref_ptr geometry (new osg::Geometry); + geometry->setVertexArray(positions); + geometry->setNormalArray(normals, osg::Array::BIND_PER_VERTEX); + geometry->setColorArray(colors, osg::Array::BIND_PER_VERTEX); + geometry->setUseDisplayList(false); + geometry->setUseVertexBufferObjects(true); - std::vector blendmaps; - std::vector layerList; - mStorage->getBlendmaps(1, center, mShaders, blendmaps, layerList); + geometry->addPrimitiveSet(mCache.getIndexBuffer(0)); - element.mMaterialGenerator.setLayerList(layerList); - - // upload blendmaps to GPU - std::vector blendTextures; - for (std::vector::const_iterator it = blendmaps.begin(); it != blendmaps.end(); ++it) - { - static int count=0; - Ogre::TexturePtr map = Ogre::TextureManager::getSingleton().createManual("terrain/blend/" - + Ogre::StringConverter::toString(count++), Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - Ogre::TEX_TYPE_2D, it->getWidth(), it->getHeight(), 0, it->format); - - Ogre::DataStreamPtr stream(new Ogre::MemoryDataStream(it->data, it->getWidth()*it->getHeight()*Ogre::PixelUtil::getNumElemBytes(it->format), true)); - map->loadRawData(stream, it->getWidth(), it->getHeight(), it->format); - blendTextures.push_back(map); - } + // we already know the bounding box, so no need to let OSG compute it. + osg::Vec3f min(-0.5f*mStorage->getCellWorldSize(), + -0.5f*mStorage->getCellWorldSize(), + minH); + osg::Vec3f max (0.5f*mStorage->getCellWorldSize(), + 0.5f*mStorage->getCellWorldSize(), + maxH); + osg::BoundingBox bounds(min, max); + geometry->setComputeBoundingBoxCallback(new StaticBoundingBoxCallback(bounds)); - element.mMaterialGenerator.setBlendmapList(blendTextures); + osg::ref_ptr geode (new osg::Geode); + geode->addDrawable(geometry); - element.mSceneNode->attachObject(element.mChunk); - updateMaterial(element); + std::vector layerList; + std::vector > blendmaps; + mStorage->getBlendmaps(1.f, center, false, blendmaps, layerList); - mGrid[std::make_pair(x,y)] = element; -} + // For compiling textures, I don't think the osgFX::Effect does it correctly + osg::ref_ptr textureCompileDummy (new osg::Node); -void TerrainGrid::updateMaterial(GridElement &element) -{ - element.mMaterialGenerator.enableShadows(getShadowsEnabled()); - element.mMaterialGenerator.enableSplitShadows(getSplitShadowsEnabled()); - element.mChunk->setMaterial(element.mMaterialGenerator.generate()); -} + std::vector > layerTextures; + for (std::vector::const_iterator it = layerList.begin(); it != layerList.end(); ++it) + { + layerTextures.push_back(mResourceSystem->getTextureManager()->getTexture2D(it->mDiffuseMap, osg::Texture::REPEAT, osg::Texture::REPEAT)); + textureCompileDummy->getOrCreateStateSet()->setTextureAttributeAndModes(0, layerTextures.back()); + } -void TerrainGrid::unloadCell(int x, int y) -{ - Grid::iterator it = mGrid.find(std::make_pair(x,y)); - if (it == mGrid.end()) - return; + std::vector > blendmapTextures; + for (std::vector >::const_iterator it = blendmaps.begin(); it != blendmaps.end(); ++it) + { + osg::ref_ptr texture (new osg::Texture2D); + texture->setImage(*it); + texture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); + texture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); + texture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR); + texture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); + texture->setResizeNonPowerOfTwoHint(false); + blendmapTextures.push_back(texture); + + textureCompileDummy->getOrCreateStateSet()->setTextureAttributeAndModes(0, layerTextures.back()); + } - GridElement& element = it->second; - delete element.mChunk; - element.mChunk = NULL; + for (unsigned int i=0; isetTexCoordArray(i, mCache.getUVBuffer()); - const std::vector& blendmaps = element.mMaterialGenerator.getBlendmapList(); - for (std::vector::const_iterator it = blendmaps.begin(); it != blendmaps.end(); ++it) - Ogre::TextureManager::getSingleton().remove((*it)->getName()); + osg::ref_ptr effect (new Terrain::Effect(layerTextures, blendmapTextures)); - mSceneMgr->destroySceneNode(element.mSceneNode); - element.mSceneNode = NULL; + effect->addCullCallback(new SceneUtil::LightListCallback); - mGrid.erase(it); -} + effect->addChild(geode); + element->mNode->addChild(effect); -void TerrainGrid::applyMaterials(bool shadows, bool splitShadows) -{ - mShadows = shadows; - mSplitShadows = splitShadows; - for (Grid::iterator it = mGrid.begin(); it != mGrid.end(); ++it) + if (mIncrementalCompileOperation) { - updateMaterial(it->second); + mIncrementalCompileOperation->add(geode); + mIncrementalCompileOperation->add(textureCompileDummy); } -} -bool TerrainGrid::getVisible() -{ - return mVisible; -} - -void TerrainGrid::setVisible(bool visible) -{ - mVisible = visible; - mRootNode->setVisible(visible); + mGrid[std::make_pair(x,y)] = element.release(); } -Ogre::AxisAlignedBox TerrainGrid::getWorldBoundingBox (const Ogre::Vector2& center) +void TerrainGrid::unloadCell(int x, int y) { - int cellX = static_cast(std::floor(center.x)); - int cellY = static_cast(std::floor(center.y)); - - Grid::iterator it = mGrid.find(std::make_pair(cellX, cellY)); + Grid::iterator it = mGrid.find(std::make_pair(x,y)); if (it == mGrid.end()) - return Ogre::AxisAlignedBox::BOX_NULL; - - Terrain::Chunk* chunk = it->second.mChunk; - Ogre::SceneNode* node = it->second.mSceneNode; - Ogre::AxisAlignedBox box = chunk->getBoundingBox(); - box = Ogre::AxisAlignedBox(box.getMinimum() + node->getPosition(), box.getMaximum() + node->getPosition()); - return box; -} + return; -void TerrainGrid::syncLoad() -{ + GridElement* element = it->second; + mTerrainRoot->removeChild(element->mNode); + delete element; + mGrid.erase(it); } } diff --git a/components/terrain/terraingrid.hpp b/components/terrain/terraingrid.hpp index 97ef6d14d..3a6d71793 100644 --- a/components/terrain/terraingrid.hpp +++ b/components/terrain/terraingrid.hpp @@ -27,64 +27,23 @@ namespace Terrain { - class Chunk; - struct GridElement - { - Ogre::SceneNode* mSceneNode; - - Terrain::MaterialGenerator mMaterialGenerator; - - Terrain::Chunk* mChunk; - }; + class GridElement; /// @brief Simple terrain implementation that loads cells in a grid, with no LOD class TerrainGrid : public Terrain::World { public: - /// @note takes ownership of \a storage - /// @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 - /// @param shaders Whether to use splatting shader, or multi-pass fixed function splatting. Shader is usually - /// faster so this is just here for compatibility. - /// @param align The align of the terrain, see Alignment enum - TerrainGrid(Ogre::SceneManager* sceneMgr, - Terrain::Storage* storage, int visibilityFlags, bool shaders, Terrain::Alignment align); + TerrainGrid(osg::Group* parent, Resource::ResourceSystem* resourceSystem, osgUtil::IncrementalCompileOperation* ico, + Storage* storage, int nodeMask); ~TerrainGrid(); - /// Update chunk LODs according to this camera position - virtual void update (const Ogre::Vector3& cameraPos); - virtual void loadCell(int x, int y); virtual void unloadCell(int x, int y); - /// Get the world bounding box of a chunk of terrain centered at \a center - virtual Ogre::AxisAlignedBox getWorldBoundingBox (const Ogre::Vector2& center); - - /// Show or hide the whole terrain - /// @note this setting may be invalidated once you call Terrain::update, so do not call it while the terrain should be hidden - virtual void setVisible(bool visible); - virtual bool getVisible(); - - /// Recreate materials used by terrain chunks. This should be called whenever settings of - /// the material factory are changed. (Relying on the factory to update those materials is not - /// enough, since turning a feature on/off can change the number of texture units available for layer/blend - /// textures, and to properly respond to this we may need to change the structure of the material, such as - /// adding or removing passes. This can only be achieved by a full rebuild.) - virtual void applyMaterials(bool shadows, bool splitShadows); - - /// Wait until all background loading is complete. - virtual void syncLoad(); - private: - void updateMaterial (GridElement& element); - - typedef std::map, GridElement> Grid; + typedef std::map, GridElement*> Grid; Grid mGrid; - - Ogre::SceneNode* mRootNode; - bool mVisible; }; } diff --git a/components/terrain/world.cpp b/components/terrain/world.cpp index 3baaaed44..1cfcc80ac 100644 --- a/components/terrain/world.cpp +++ b/components/terrain/world.cpp @@ -21,63 +21,39 @@ */ #include "world.hpp" -#include +#include +#include #include "storage.hpp" namespace Terrain { -World::World(Ogre::SceneManager* sceneMgr, - Storage* storage, int visibilityFlags, bool shaders, Alignment align) - : mShaders(shaders) - , mShadows(false) - , mSplitShadows(false) - , mAlign(align) - , mStorage(storage) - , mVisibilityFlags(visibilityFlags) - , mSceneMgr(sceneMgr) +World::World(osg::Group* parent, Resource::ResourceSystem* resourceSystem, osgUtil::IncrementalCompileOperation* ico, + Storage* storage, int nodeMask) + : mStorage(storage) , mCache(storage->getCellVertices()) + , mParent(parent) + , mResourceSystem(resourceSystem) + , mIncrementalCompileOperation(ico) { + mTerrainRoot = new osg::Group; + mTerrainRoot->setNodeMask(nodeMask); + mTerrainRoot->getOrCreateStateSet()->setRenderingHint(osg::StateSet::OPAQUE_BIN); + + mParent->addChild(mTerrainRoot); } World::~World() { + mParent->removeChild(mTerrainRoot); + delete mStorage; } -float World::getHeightAt(const Ogre::Vector3 &worldPos) +float World::getHeightAt(const osg::Vec3f &worldPos) { return mStorage->getHeightAt(worldPos); } -void World::convertPosition(float &x, float &y, float &z) -{ - Terrain::convertPosition(mAlign, x, y, z); -} - -void World::convertPosition(Ogre::Vector3 &pos) -{ - convertPosition(pos.x, pos.y, pos.z); -} - -void World::convertBounds(Ogre::AxisAlignedBox& bounds) -{ - switch (mAlign) - { - case Align_XY: - return; - case Align_XZ: - convertPosition(bounds.getMinimum()); - convertPosition(bounds.getMaximum()); - // Because we changed sign of Z - std::swap(bounds.getMinimum().z, bounds.getMaximum().z); - return; - case Align_YZ: - convertPosition(bounds.getMinimum()); - convertPosition(bounds.getMaximum()); - return; - } -} - } diff --git a/components/terrain/world.hpp b/components/terrain/world.hpp index 3e63b4c93..70ec30410 100644 --- a/components/terrain/world.hpp +++ b/components/terrain/world.hpp @@ -22,14 +22,24 @@ #ifndef COMPONENTS_TERRAIN_WORLD_H #define COMPONENTS_TERRAIN_WORLD_H -#include +#include #include "defs.hpp" #include "buffercache.hpp" -namespace Ogre +namespace osg { - class SceneManager; + class Group; +} + +namespace osgUtil +{ + class IncrementalCompileOperation; +} + +namespace Resource +{ + class ResourceSystem; } namespace Terrain @@ -44,79 +54,31 @@ namespace Terrain { public: /// @note takes ownership of \a storage - /// @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 - /// @param shaders Whether to use splatting shader, or multi-pass fixed function splatting. Shader is usually - /// faster so this is just here for compatibility. - /// @param align The align of the terrain, see Alignment enum - World(Ogre::SceneManager* sceneMgr, - Storage* storage, int visiblityFlags, bool shaders, Alignment align); + /// @param nodeMask mask for the terrain root + World(osg::Group* parent, Resource::ResourceSystem* resourceSystem, osgUtil::IncrementalCompileOperation* ico, + Storage* storage, int nodeMask); virtual ~World(); - bool getShadersEnabled() { return mShaders; } - bool getShadowsEnabled() { return mShadows; } - bool getSplitShadowsEnabled() { return mSplitShadows; } - - float getHeightAt (const Ogre::Vector3& worldPos); - - /// Update chunk LODs according to this camera position - /// @note Calling this method might lead to composite textures being rendered, so it is best - /// not to call it when render commands are still queued, since that would cause a flush. - virtual void update (const Ogre::Vector3& cameraPos) = 0; + float getHeightAt (const osg::Vec3f& worldPos); // This is only a hint and may be ignored by the implementation. virtual void loadCell(int x, int y) {} virtual void unloadCell(int x, int y) {} - /// Get the world bounding box of a chunk of terrain centered at \a center - virtual Ogre::AxisAlignedBox getWorldBoundingBox (const Ogre::Vector2& center) = 0; - - Ogre::SceneManager* getSceneManager() { return mSceneMgr; } - Storage* getStorage() { return mStorage; } - /// Show or hide the whole terrain - /// @note this setting may be invalidated once you call Terrain::update, so do not call it while the terrain should be hidden - virtual void setVisible(bool visible) = 0; - virtual bool getVisible() = 0; - - /// Recreate materials used by terrain chunks. This should be called whenever settings of - /// the material factory are changed. (Relying on the factory to update those materials is not - /// enough, since turning a feature on/off can change the number of texture units available for layer/blend - /// textures, and to properly respond to this we may need to change the structure of the material, such as - /// adding or removing passes. This can only be achieved by a full rebuild.) - virtual void applyMaterials(bool shadows, bool splitShadows) = 0; - - int getVisibilityFlags() { return mVisibilityFlags; } - - Alignment getAlign() { return mAlign; } - - /// Wait until all background loading is complete. - virtual void syncLoad() {} - protected: - bool mShaders; - bool mShadows; - bool mSplitShadows; - Alignment mAlign; - Storage* mStorage; - int mVisibilityFlags; - - Ogre::SceneManager* mSceneMgr; - BufferCache mCache; - public: - // ----INTERNAL---- - BufferCache& getBufferCache() { return mCache; } + osg::ref_ptr mParent; + osg::ref_ptr mTerrainRoot; + + Resource::ResourceSystem* mResourceSystem; - // Convert the given position from Z-up align, i.e. Align_XY to the wanted align set in mAlign - void convertPosition (float& x, float& y, float& z); - void convertPosition (Ogre::Vector3& pos); - void convertBounds (Ogre::AxisAlignedBox& bounds); + osg::ref_ptr mIncrementalCompileOperation; }; } From 20b7c7b46cf3ada8aa888c51f250cf991bb6a090 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Wed, 3 Jun 2015 01:41:45 +0200 Subject: [PATCH 1376/3725] Hopefully the last fixes, build should run --- CI/before_script.msvc.sh | 16 ++++++++-------- CI/build.msvc.sh | 21 ++++++++++++++++++++- appveyor.yml | 2 ++ 3 files changed, 30 insertions(+), 9 deletions(-) diff --git a/CI/before_script.msvc.sh b/CI/before_script.msvc.sh index 56d56762f..cd4190ea9 100644 --- a/CI/before_script.msvc.sh +++ b/CI/before_script.msvc.sh @@ -22,7 +22,7 @@ if [ -z $APPVEYOR ]; then echo "Running prebuild outside of Appveyor." DIR=$(echo "$0" | sed "s,\\\\,/,g" | sed "s,\(.\):,/\\1,") - cd $(dirname "$DIR") + cd $(dirname "$DIR")/.. else echo "Running prebuild in Appveyor." @@ -99,12 +99,12 @@ add_cmake_opts() { CMAKE_OPTS="$CMAKE_OPTS $@" } -if [ -z "$ARCH" ]; then - if [ -z "$PLATFORM" ]; then - ARCH=`uname -m` - else - ARCH="$PLATFORM" - fi +if [ -z $PLATFORM ]; then + PLATFORM=`uname -m` +fi + +if [ -z $CONFIGURATION ]; then + CONFIGURATION="Debug" fi case $PLATFORM in @@ -206,7 +206,7 @@ if [ -z $APPVEYOR ]; then BOOST_SDK="`real_pwd`/Boost" - $DEPS/boost-1.58.0-win$BITS.exe //dir="$BOOST_SDK" //verysilent + $DEPS/boost-1.58.0-win$BITS.exe //dir="$(echo $BOOST_SDK | sed s,/,\\\\,g)" //verysilent add_cmake_opts -DBOOST_ROOT="$BOOST_SDK" \ -DBOOST_LIBRARYDIR="$BOOST_SDK/lib$BITS-msvc-12.0" diff --git a/CI/build.msvc.sh b/CI/build.msvc.sh index 34ce3d062..57f4f6c1d 100644 --- a/CI/build.msvc.sh +++ b/CI/build.msvc.sh @@ -1,5 +1,13 @@ #!/bin/bash +if [ -z $PLATFORM ]; then + PLATFORM=`uname -m` +fi + +if [ -z $CONFIGURATION ]; then + CONFIGURATION="Debug" +fi + case $PLATFORM in x32|x86|i686|i386|win32|Win32 ) BITS=32 ;; @@ -12,6 +20,17 @@ case $PLATFORM in exit 1 ;; esac -cd $(dirname $0)/../build_$BITS +if [ -z $APPVEYOR ]; then + echo "Running $BITS-bit $CONFIGURATION build outside of Appveyor." + + DIR=$(echo "$0" | sed "s,\\\\,/,g" | sed "s,\(.\):,/\\1,") + cd $(dirname "$DIR")/.. +else + echo "Running $BITS-bit $CONFIGURATION build in Appveyor." + + cd $APPVEYOR_BUILD_FOLDER +fi + +cd build_$BITS msbuild OpenMW.sln //t:Build //p:Configuration=$CONFIGURATION //m:8 //logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" diff --git a/appveyor.yml b/appveyor.yml index 890b9684b..3f8b27e22 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -13,6 +13,8 @@ matrix: os: unstable +shallow_clone: true + cache: - C:\projects\openmw\deps\Bullet-2.83.4-win32.7z -> CI/before_script.msvc.sh - C:\projects\openmw\deps\Bullet-2.83.4-win64.7z -> CI/before_script.msvc.sh From 108c2719a85ca915bfe90a67a854fe18cad83fad Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Wed, 3 Jun 2015 02:04:31 +0200 Subject: [PATCH 1377/3725] And yet I forgot about msbuild, should work now --- CI/before_script.msvc.sh | 6 +----- CI/build.msvc.sh | 7 +++++++ 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/CI/before_script.msvc.sh b/CI/before_script.msvc.sh index cd4190ea9..cefc06fe9 100644 --- a/CI/before_script.msvc.sh +++ b/CI/before_script.msvc.sh @@ -46,7 +46,7 @@ run_cmd() { else 7z a output.7z output.log > /dev/null 2>&1 - appveyor PushArtifact output.7z -DeploymentName $CMD-output.7z + appveyor PushArtifact output.7z -FileName $CMD-output.7z appveyor AddMessage "Command $CMD failed (code $RET), output has been pushed as an artifact." -Category Error fi else @@ -90,10 +90,6 @@ real_pwd() { pwd | sed "s,/\(.\),\1:," } -msbuild() { - /c/Program\ Files\ \(x86\)/MSBuild/12.0/Bin/MSBuild.exe $@ -} - CMAKE_OPTS="" add_cmake_opts() { CMAKE_OPTS="$CMAKE_OPTS $@" diff --git a/CI/build.msvc.sh b/CI/build.msvc.sh index 57f4f6c1d..b17e7b94c 100644 --- a/CI/build.msvc.sh +++ b/CI/build.msvc.sh @@ -33,4 +33,11 @@ fi cd build_$BITS +which msbuild > /dev/null +if [ $? -ne 0 ]; then + msbuild() { + /c/Program\ Files\ \(x86\)/MSBuild/12.0/Bin/MSBuild.exe "$@" + } +fi + msbuild OpenMW.sln //t:Build //p:Configuration=$CONFIGURATION //m:8 //logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" From 5666e0254653543398b8441acc00eb68bf1733ea Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Jun 2015 02:21:41 +0200 Subject: [PATCH 1378/3725] Fix for dark terrain in some cases --- components/terrain/material.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/components/terrain/material.cpp b/components/terrain/material.cpp index 17acd940b..ddfa10f12 100644 --- a/components/terrain/material.cpp +++ b/components/terrain/material.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include @@ -67,6 +68,12 @@ namespace Terrain stateset->setTextureAttributeAndModes(texunit, new osg::TexMat(texMat)); + osg::ref_ptr texEnvCombine (new osg::TexEnvCombine); + texEnvCombine->setCombine_RGB(osg::TexEnvCombine::REPLACE); + texEnvCombine->setSource0_RGB(osg::TexEnvCombine::PREVIOUS); + + stateset->setTextureAttributeAndModes(texunit, texEnvCombine, osg::StateAttribute::ON); + ++texunit; } From b978153edbe735000227eb99ee7414086ffcc3fc Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Jun 2015 02:24:09 +0200 Subject: [PATCH 1379/3725] Enable VBO sharing for terrain geometry --- components/terrain/buffercache.cpp | 6 ++++++ components/terrain/terraingrid.cpp | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/components/terrain/buffercache.cpp b/components/terrain/buffercache.cpp index 7dc93f1d6..dfb3eff88 100644 --- a/components/terrain/buffercache.cpp +++ b/components/terrain/buffercache.cpp @@ -218,6 +218,9 @@ namespace Terrain } } + // Assign a VBO here to enable state sharing between different Geometries. + uvs->setVertexBufferObject(new osg::VertexBufferObject); + mUvBufferMap[mNumVerts] = uvs; return uvs; } @@ -238,6 +241,9 @@ namespace Terrain else buffer = createIndexBuffer(flags, verts); + // Assign a EBO here to enable state sharing between different Geometries. + buffer->setElementBufferObject(new osg::ElementBufferObject); + mIndexBufferMap[flags] = buffer; return buffer; } diff --git a/components/terrain/terraingrid.cpp b/components/terrain/terraingrid.cpp index e99126a2a..7ae4d8511 100644 --- a/components/terrain/terraingrid.cpp +++ b/components/terrain/terraingrid.cpp @@ -104,6 +104,11 @@ void TerrainGrid::loadCell(int x, int y) osg::ref_ptr normals (new osg::Vec3Array); osg::ref_ptr colors (new osg::Vec4Array); + osg::ref_ptr vbo (new osg::VertexBufferObject); + positions->setVertexBufferObject(vbo); + normals->setVertexBufferObject(vbo); + colors->setVertexBufferObject(vbo); + mStorage->fillVertexBuffers(0, 1, center, positions, normals, colors); osg::ref_ptr geometry (new osg::Geometry); From 3425e9b1d14806cae73d7bc6256c65af55b0206b Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Wed, 3 Jun 2015 02:34:45 +0200 Subject: [PATCH 1380/3725] And done. Switched to a slight less shallow clone too, for better versioning --- CI/before_script.msvc.sh | 2 +- appveyor.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CI/before_script.msvc.sh b/CI/before_script.msvc.sh index cefc06fe9..36f8213d4 100644 --- a/CI/before_script.msvc.sh +++ b/CI/before_script.msvc.sh @@ -225,7 +225,7 @@ eval 7z x -y $DEPS/Bullet-2.83.4-win$BITS.7z $STRIP mv Bullet-2.83.4-win$BITS Bullet BULLET_SDK="`real_pwd`/Bullet" -add_cmake_opts -DBULLET_INCLUDE_DIR="$BULLET_SDK/include" \ +add_cmake_opts -DBULLET_INCLUDE_DIR="$BULLET_SDK/include/bullet" \ -DBULLET_COLLISION_LIBRARY="$BULLET_SDK/lib/BulletCollision.lib" \ -DBULLET_COLLISION_LIBRARY_DEBUG="$BULLET_SDK/lib/BulletCollision_Debug.lib" \ -DBULLET_DYNAMICS_LIBRARY="$BULLET_SDK/lib/BulletDynamics.lib" \ diff --git a/appveyor.yml b/appveyor.yml index 3f8b27e22..e46dd3dd8 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -13,7 +13,7 @@ matrix: os: unstable -shallow_clone: true +clone_depth: 5 cache: - C:\projects\openmw\deps\Bullet-2.83.4-win32.7z -> CI/before_script.msvc.sh From 2883ecc19af0721183001810e6c58fc406e7f208 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Jun 2015 02:41:04 +0200 Subject: [PATCH 1381/3725] Fix the hilarious bug of NPCs falling to their deaths in interiors --- apps/openmw/mwworld/worldimp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index e676977de..93a34f233 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1299,7 +1299,7 @@ namespace MWWorld } float terrainHeight = -std::numeric_limits::max(); - if (isCellExterior()) + if (ptr.getCell()->isExterior()) terrainHeight = mRendering->getTerrainHeightAt(pos.asVec3()); if (pos.pos[2] < terrainHeight) From cd47dff1963d7ae0035e5a04fdf137256b0382ea Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Jun 2015 03:02:43 +0200 Subject: [PATCH 1382/3725] Minor cleanup --- apps/opencs/view/render/scenewidget.cpp | 1 - components/terrain/material.cpp | 2 -- 2 files changed, 3 deletions(-) diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index 593775970..a9c9a8c6b 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -11,7 +11,6 @@ #include #include #include -#include #include diff --git a/components/terrain/material.cpp b/components/terrain/material.cpp index ddfa10f12..2af8ddcda 100644 --- a/components/terrain/material.cpp +++ b/components/terrain/material.cpp @@ -30,8 +30,6 @@ #include #include -#include - namespace Terrain { From cee1db532f653f5f373bbafcfddd1a2464809d4e Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Jun 2015 03:04:39 +0200 Subject: [PATCH 1383/3725] Improve area orb positioning for "on touch" spells --- apps/openmw/mwworld/worldimp.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 93a34f233..6376772c3 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2636,11 +2636,14 @@ namespace MWWorld // Get the target to use for "on touch" effects MWWorld::Ptr target; float distance = 192.f; // ?? + osg::Vec3f hitPosition = actor.getRefData().getPosition().asVec3(); if (actor == getPlayerPtr()) { // For the player, use camera to aim target = getFacedObject(distance); + if (!target.isEmpty()) + hitPosition = target.getRefData().getPosition().asVec3(); } else { @@ -2669,13 +2672,13 @@ namespace MWWorld MWPhysics::PhysicsSystem::RayResult result = mPhysics->castRay(origin, dest, actor); target = result.mHitObject; + hitPosition = result.mHitPos; } std::string selectedSpell = stats.getSpells().getSelectedSpell(); MWMechanics::CastSpell cast(actor, target); - if (!target.isEmpty()) - cast.mHitPosition = target.getRefData().getPosition().asVec3(); + cast.mHitPosition = hitPosition; if (!selectedSpell.empty()) { From 292fa0b5e319081a48e2065f92fb3c769bc881bf Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Jun 2015 03:13:51 +0200 Subject: [PATCH 1384/3725] Unify raycasting techniques for "on touch" magic We don't want pixel-precise raycasting here. Gets annoying when trying to hit a skeleton. --- apps/openmw/mwworld/worldimp.cpp | 50 +++++++++++++------------------- 1 file changed, 20 insertions(+), 30 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 6376772c3..2f9a13f78 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2638,42 +2638,32 @@ namespace MWWorld float distance = 192.f; // ?? osg::Vec3f hitPosition = actor.getRefData().getPosition().asVec3(); - if (actor == getPlayerPtr()) - { - // For the player, use camera to aim - target = getFacedObject(distance); - if (!target.isEmpty()) - hitPosition = target.getRefData().getPosition().asVec3(); - } - else - { - // For NPCs use facing direction from Head node - osg::Vec3f origin(actor.getRefData().getPosition().asVec3()); + // For NPCs use facing direction from Head node + osg::Vec3f origin(actor.getRefData().getPosition().asVec3()); - MWRender::Animation* anim = mRendering->getAnimation(actor); - if (anim != NULL) + MWRender::Animation* anim = mRendering->getAnimation(actor); + if (anim != NULL) + { + const osg::Node* node = anim->getNode("Head"); + if (node == NULL) + node = anim->getNode("Bip01 Head"); + if (node != NULL) { - const osg::Node* node = anim->getNode("Head"); - if (node == NULL) - node = anim->getNode("Bip01 Head"); - if (node != NULL) - { - osg::MatrixList mats = node->getWorldMatrices(); - if (mats.size()) - origin = mats[0].getTrans(); - } + osg::MatrixList mats = node->getWorldMatrices(); + if (mats.size()) + origin = mats[0].getTrans(); } + } - osg::Quat orient = osg::Quat(actor.getRefData().getPosition().rot[0], osg::Vec3f(-1,0,0)) - * osg::Quat(actor.getRefData().getPosition().rot[2], osg::Vec3f(0,0,-1)); + osg::Quat orient = osg::Quat(actor.getRefData().getPosition().rot[0], osg::Vec3f(-1,0,0)) + * osg::Quat(actor.getRefData().getPosition().rot[2], osg::Vec3f(0,0,-1)); - osg::Vec3f direction = orient * osg::Vec3f(0,1,0); - osg::Vec3f dest = origin + direction * distance; + osg::Vec3f direction = orient * osg::Vec3f(0,1,0); + osg::Vec3f dest = origin + direction * distance; - MWPhysics::PhysicsSystem::RayResult result = mPhysics->castRay(origin, dest, actor); - target = result.mHitObject; - hitPosition = result.mHitPos; - } + MWPhysics::PhysicsSystem::RayResult result = mPhysics->castRay(origin, dest, actor); + target = result.mHitObject; + hitPosition = result.mHitPos; std::string selectedSpell = stats.getSpells().getSelectedSpell(); From 41cce5240fc4e225288b924daddaec9a62a3868e Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Jun 2015 03:29:21 +0200 Subject: [PATCH 1385/3725] Delete remaining files that won't be of any use --- apps/openmw/CMakeLists.txt | 1 - apps/openmw/mwrender/occlusionquery.cpp | 208 ---------------------- apps/openmw/mwrender/occlusionquery.hpp | 77 -------- apps/openmw/mwrender/ripplesimulation.cpp | 169 ------------------ apps/openmw/mwrender/ripplesimulation.hpp | 64 ------- apps/openmw/mwrender/shadows.cpp | 187 ------------------- apps/openmw/mwrender/shadows.hpp | 37 ---- 7 files changed, 743 deletions(-) delete mode 100644 apps/openmw/mwrender/occlusionquery.cpp delete mode 100644 apps/openmw/mwrender/occlusionquery.hpp delete mode 100644 apps/openmw/mwrender/ripplesimulation.cpp delete mode 100644 apps/openmw/mwrender/ripplesimulation.hpp delete mode 100644 apps/openmw/mwrender/shadows.cpp delete mode 100644 apps/openmw/mwrender/shadows.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index ef0c4e135..b23828254 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -23,7 +23,6 @@ add_openmw_dir (mwrender actors objects renderingmanager animation rotatecontroller sky npcanimation vismask creatureanimation effectmanager util renderinginterface pathgrid rendermode weaponanimation bulletdebugdraw globalmap characterpreview camera localmap water terrainstorage -# occlusionquery shadows ripplesimulation ) add_openmw_dir (mwinput diff --git a/apps/openmw/mwrender/occlusionquery.cpp b/apps/openmw/mwrender/occlusionquery.cpp deleted file mode 100644 index 2693d68b2..000000000 --- a/apps/openmw/mwrender/occlusionquery.cpp +++ /dev/null @@ -1,208 +0,0 @@ -#include "occlusionquery.hpp" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "renderconst.hpp" - -using namespace MWRender; -using namespace Ogre; - -OcclusionQuery::OcclusionQuery(OEngine::Render::OgreRenderer* renderer, SceneNode* sunNode) : - mSunTotalAreaQuery(0), mSunVisibleAreaQuery(0), mActiveQuery(0), - mBBQueryVisible(0), mBBQueryTotal(0), mSunNode(sunNode), mBBNodeReal(0), - mSunVisibility(0), - mWasVisible(false), - mActive(false), - mFirstFrame(true), - mDoQuery(0), - mRendering(renderer) -{ - try { - RenderSystem* renderSystem = Root::getSingleton().getRenderSystem(); - - mSunTotalAreaQuery = renderSystem->createHardwareOcclusionQuery(); - mSunVisibleAreaQuery = renderSystem->createHardwareOcclusionQuery(); - - mSupported = (mSunTotalAreaQuery != 0) && (mSunVisibleAreaQuery != 0); - } - catch (Ogre::Exception&) - { - mSupported = false; - } - - if (!mSupported) - { - std::cout << "Hardware occlusion queries not supported." << std::endl; - return; - } - - mBBNodeReal = mRendering->getScene()->getRootSceneNode()->createChildSceneNode(); - - static Ogre::Mesh* plane = MeshManager::getSingleton().createPlane("occlusionbillboard", - ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::Plane(Ogre::Vector3(0,0,1), 0), 1, 1, 1, 1, true, 1, 1, 1, Vector3::UNIT_Y).get(); - plane->_setBounds(Ogre::AxisAlignedBox::BOX_INFINITE); - - mBBQueryTotal = mRendering->getScene()->createEntity("occlusionbillboard"); - mBBQueryTotal->setCastShadows(false); - mBBQueryTotal->setVisibilityFlags(RV_OcclusionQuery); - mBBQueryTotal->setRenderQueueGroup(RQG_OcclusionQuery+1); - mBBQueryTotal->setMaterialName("QueryTotalPixels"); - mBBNodeReal->attachObject(mBBQueryTotal); - - mBBQueryVisible = mRendering->getScene()->createEntity("occlusionbillboard"); - mBBQueryVisible->setCastShadows(false); - mBBQueryVisible->setVisibilityFlags(RV_OcclusionQuery); - mBBQueryVisible->setRenderQueueGroup(RQG_OcclusionQuery+1); - mBBQueryVisible->setMaterialName("QueryVisiblePixels"); - mBBNodeReal->attachObject(mBBQueryVisible); - - mRendering->getScene()->addRenderObjectListener(this); - mRendering->getScene()->addRenderQueueListener(this); - mDoQuery = true; -} - -OcclusionQuery::~OcclusionQuery() -{ - mRendering->getScene()->removeRenderObjectListener (this); - mRendering->getScene()->removeRenderQueueListener(this); - - RenderSystem* renderSystem = Root::getSingleton().getRenderSystem(); - if (mSunTotalAreaQuery) - renderSystem->destroyHardwareOcclusionQuery(mSunTotalAreaQuery); - if (mSunVisibleAreaQuery) - renderSystem->destroyHardwareOcclusionQuery(mSunVisibleAreaQuery); -} - -bool OcclusionQuery::supported() -{ - return mSupported; -} - -void OcclusionQuery::notifyRenderSingleObject(Renderable* rend, const Pass* pass, const AutoParamDataSource* source, - const LightList* pLightList, bool suppressRenderStateChanges) -{ - if (!mActive) return; - - // The following code activates and deactivates the occlusion queries - // so that the queries only include the rendering of the intended meshes - - // Close the last occlusion query - // Each occlusion query should only last a single rendering - if (mActiveQuery != NULL) - { - mActiveQuery->endOcclusionQuery(); - mActiveQuery = NULL; - } - - // Open a new occlusion query - if (mDoQuery == true) - { - if (rend == mBBQueryTotal->getSubEntity(0)) - { - mActiveQuery = mSunTotalAreaQuery; - mWasVisible = true; - } - else if (rend == mBBQueryVisible->getSubEntity(0)) - { - mActiveQuery = mSunVisibleAreaQuery; - } - } - - if (mActiveQuery != NULL) - mActiveQuery->beginOcclusionQuery(); -} - -void OcclusionQuery::renderQueueEnded(uint8 queueGroupId, const String& invocation, bool& repeatThisInvocation) -{ - if (!mActive) return; - - if (mActiveQuery != NULL) - { - mActiveQuery->endOcclusionQuery(); - mActiveQuery = NULL; - } - /** - * for every beginOcclusionQuery(), we want a respective pullOcclusionQuery() and vice versa - * this also means that results can be wrong at other places if we pull, but beginOcclusionQuery() was never called - * this can happen for example if the object that is tested is outside of the view frustum - * to prevent this, check if the queries have been performed after everything has been rendered and if not, start them manually - */ - if (queueGroupId == RQG_SkiesLate) - { - if (mWasVisible == false && mDoQuery) - { - mSunTotalAreaQuery->beginOcclusionQuery(); - mSunTotalAreaQuery->endOcclusionQuery(); - mSunVisibleAreaQuery->beginOcclusionQuery(); - mSunVisibleAreaQuery->endOcclusionQuery(); - } - } -} - -void OcclusionQuery::update(float duration) -{ - if (mFirstFrame) - { - // GLHardwareOcclusionQuery::isStillOutstanding doesn't seem to like getting called when nothing has been rendered yet - mFirstFrame = false; - return; - } - if (!mSupported) return; - - mWasVisible = false; - - // Adjust the position of the sun billboards according to camera viewing distance - // we need to do this to make sure that _everything_ can occlude the sun - float dist = mRendering->getCamera()->getFarClipDistance(); - if (dist==0) dist = 10000000; - dist -= 1000; // bias - dist /= 1000.f; - if (mSunNode) - { - mBBNodeReal->setPosition(mSunNode->getPosition() * dist); - mBBNodeReal->setOrientation(Ogre::Vector3::UNIT_Z.getRotationTo(-mBBNodeReal->getPosition().normalisedCopy())); - mBBNodeReal->setScale(150.f*dist, 150.f*dist, 150.f*dist); - } - - // Stop occlusion queries until we get their information - // (may not happen on the same frame they are requested in) - mDoQuery = false; - - if (!mSunTotalAreaQuery->isStillOutstanding() - && !mSunVisibleAreaQuery->isStillOutstanding()) - { - unsigned int totalPixels; - unsigned int visiblePixels; - - mSunTotalAreaQuery->pullOcclusionQuery(&totalPixels); - mSunVisibleAreaQuery->pullOcclusionQuery(&visiblePixels); - - if (totalPixels == 0) - { - // probably outside of the view frustum - mSunVisibility = 0; - } - else - { - mSunVisibility = float(visiblePixels) / float(totalPixels); - if (mSunVisibility > 1) mSunVisibility = 1; - } - - mDoQuery = true; - } -} - -void OcclusionQuery::setSunNode(Ogre::SceneNode* node) -{ - mSunNode = node; -} diff --git a/apps/openmw/mwrender/occlusionquery.hpp b/apps/openmw/mwrender/occlusionquery.hpp deleted file mode 100644 index 6974f37b9..000000000 --- a/apps/openmw/mwrender/occlusionquery.hpp +++ /dev/null @@ -1,77 +0,0 @@ -#ifndef GAME_OCCLUSION_QUERY_H -#define GAME_OCCLUSION_QUERY_H - -#include -#include - -namespace Ogre -{ - class HardwareOcclusionQuery; - class Entity; - class SceneNode; -} - -#include - -namespace MWRender -{ - /// - /// \brief Implements hardware occlusion queries on the GPU - /// - class OcclusionQuery : public Ogre::RenderObjectListener, public Ogre::RenderQueueListener - { - public: - OcclusionQuery(OEngine::Render::OgreRenderer*, Ogre::SceneNode* sunNode); - ~OcclusionQuery(); - - /** - * @return true if occlusion queries are supported on the user's hardware - */ - bool supported(); - - /** - * make sure to disable occlusion queries before updating unrelated render targets - * @param active - */ - void setActive (bool active) { mActive = active; } - - /** - * per-frame update - */ - void update(float duration); - - float getSunVisibility() const {return mSunVisibility;}; - - void setSunNode(Ogre::SceneNode* node); - - private: - Ogre::HardwareOcclusionQuery* mSunTotalAreaQuery; - Ogre::HardwareOcclusionQuery* mSunVisibleAreaQuery; - Ogre::HardwareOcclusionQuery* mActiveQuery; - - Ogre::Entity* mBBQueryVisible; - Ogre::Entity* mBBQueryTotal; - - Ogre::SceneNode* mSunNode; - Ogre::SceneNode* mBBNodeReal; - float mSunVisibility; - - bool mWasVisible; - - bool mActive; - bool mFirstFrame; - - bool mSupported; - bool mDoQuery; - - OEngine::Render::OgreRenderer* mRendering; - - protected: - virtual void notifyRenderSingleObject(Ogre::Renderable* rend, const Ogre::Pass* pass, const Ogre::AutoParamDataSource* source, - const Ogre::LightList* pLightList, bool suppressRenderStateChanges); - - virtual void renderQueueEnded(Ogre::uint8 queueGroupId, const Ogre::String& invocation, bool& repeatThisInvocation); - }; -} - -#endif diff --git a/apps/openmw/mwrender/ripplesimulation.cpp b/apps/openmw/mwrender/ripplesimulation.cpp deleted file mode 100644 index f75061af4..000000000 --- a/apps/openmw/mwrender/ripplesimulation.cpp +++ /dev/null @@ -1,169 +0,0 @@ -#include "ripplesimulation.hpp" - -#include - -#include -#include -#include -#include - -#include - -#include "../mwbase/environment.hpp" -#include "../mwbase/world.hpp" - -#include "../mwworld/fallback.hpp" - -#include "renderconst.hpp" - -namespace MWRender -{ - -RippleSimulation::RippleSimulation(Ogre::SceneManager* mainSceneManager, const MWWorld::Fallback* fallback) - : mSceneMgr(mainSceneManager) - , mParticleSystem(NULL) - , mSceneNode(NULL) -{ - mRippleLifeTime = fallback->getFallbackFloat("Water_RippleLifetime"); - mRippleRotSpeed = fallback->getFallbackFloat("Water_RippleRotSpeed"); - - // Unknown: - // fallback=Water_RippleScale,0.15, 6.5 - // fallback=Water_RippleAlphas,0.7, 0.1, 0.01 - - // Instantiate from ripples.particle file - mParticleSystem = mSceneMgr->createParticleSystem("openmw/Ripples", "openmw/Ripples"); - - mParticleSystem->setRenderQueueGroup(RQG_Ripples); - mParticleSystem->setVisibilityFlags(RV_Effects); - - int rippleFrameCount = fallback->getFallbackInt("Water_RippleFrameCount"); - std::string tex = fallback->getFallbackString("Water_RippleTexture"); - - sh::MaterialInstance* mat = sh::Factory::getInstance().getMaterialInstance("openmw/Ripple"); - mat->setProperty("anim_texture2", sh::makeProperty(new sh::StringValue(std::string("textures\\water\\") + tex + ".dds " - + Ogre::StringConverter::toString(rippleFrameCount) - + " " - + Ogre::StringConverter::toString(0.3)))); - - // seems to be required to allocate mFreeParticles. TODO: patch Ogre to handle this better - mParticleSystem->_update(0.f); - - mSceneNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(); - mSceneNode->attachObject(mParticleSystem); -} - -RippleSimulation::~RippleSimulation() -{ - if (mParticleSystem) - mSceneMgr->destroyParticleSystem(mParticleSystem); - mParticleSystem = NULL; - - if (mSceneNode) - mSceneMgr->destroySceneNode(mSceneNode); - mSceneNode = NULL; -} - -void RippleSimulation::update(float dt, Ogre::Vector2 position) -{ - bool newParticle = false; - for (std::vector::iterator it=mEmitters.begin(); it !=mEmitters.end(); ++it) - { - if (it->mPtr == MWBase::Environment::get().getWorld ()->getPlayerPtr()) - { - // fetch a new ptr (to handle cell change etc) - // for non-player actors this is done in updateObjectCell - it->mPtr = MWBase::Environment::get().getWorld ()->getPlayerPtr(); - } - Ogre::Vector3 currentPos (it->mPtr.getRefData().getPosition().pos); - currentPos.z = 0; - if ( (currentPos - it->mLastEmitPosition).length() > 10 - // Only emit when close to the water surface, not above it and not too deep in the water - && MWBase::Environment::get().getWorld ()->isUnderwater (it->mPtr.getCell(), - Ogre::Vector3(it->mPtr.getRefData().getPosition().pos)) - && !MWBase::Environment::get().getWorld()->isSubmerged(it->mPtr)) - { - it->mLastEmitPosition = currentPos; - - newParticle = true; - Ogre::Particle* created = mParticleSystem->createParticle(); - if (!created) - break; // TODO: cleanup the oldest particle to make room -#if OGRE_VERSION >= (1 << 16 | 10 << 8 | 0) - Ogre::Vector3& position = created->mPosition; - Ogre::Vector3& direction = created->mDirection; - Ogre::ColourValue& colour = created->mColour; - float& totalTimeToLive = created->mTotalTimeToLive; - float& timeToLive = created->mTimeToLive; - Ogre::Radian& rotSpeed = created->mRotationSpeed; - Ogre::Radian& rotation = created->mRotation; -#else - Ogre::Vector3& position = created->position; - Ogre::Vector3& direction = created->direction; - Ogre::ColourValue& colour = created->colour; - float& totalTimeToLive = created->totalTimeToLive; - float& timeToLive = created->timeToLive; - Ogre::Radian& rotSpeed = created->rotationSpeed; - Ogre::Radian& rotation = created->rotation; -#endif - timeToLive = totalTimeToLive = mRippleLifeTime; - colour = Ogre::ColourValue(0.f, 0.f, 0.f, 0.7f); // Water_RippleAlphas.x? - direction = Ogre::Vector3(0,0,0); - position = currentPos; - position.z = 0; // Z is set by the Scene Node - rotSpeed = mRippleRotSpeed; - rotation = Ogre::Radian(Ogre::Math::RangeRandom(-Ogre::Math::PI, Ogre::Math::PI)); - created->setDimensions(mParticleSystem->getDefaultWidth(), mParticleSystem->getDefaultHeight()); - } - } - - if (newParticle) // now apparently needs another update, otherwise it won't render in the first frame after a particle is created. TODO: patch Ogre to handle this better - mParticleSystem->_update(0.f); -} - -void RippleSimulation::addEmitter(const MWWorld::Ptr& ptr, float scale, float force) -{ - Emitter newEmitter; - newEmitter.mPtr = ptr; - newEmitter.mScale = scale; - newEmitter.mForce = force; - newEmitter.mLastEmitPosition = Ogre::Vector3(0,0,0); - mEmitters.push_back (newEmitter); -} - -void RippleSimulation::removeEmitter (const MWWorld::Ptr& ptr) -{ - for (std::vector::iterator it = mEmitters.begin(); it != mEmitters.end(); ++it) - { - if (it->mPtr == ptr) - { - mEmitters.erase(it); - return; - } - } -} - -void RippleSimulation::updateEmitterPtr (const MWWorld::Ptr& old, const MWWorld::Ptr& ptr) -{ - for (std::vector::iterator it = mEmitters.begin(); it != mEmitters.end(); ++it) - { - if (it->mPtr == old) - { - it->mPtr = ptr; - return; - } - } -} - -void RippleSimulation::setWaterHeight(float height) -{ - mSceneNode->setPosition(0,0,height); -} - -void RippleSimulation::clear() -{ - mParticleSystem->clear(); -} - - -} diff --git a/apps/openmw/mwrender/ripplesimulation.hpp b/apps/openmw/mwrender/ripplesimulation.hpp deleted file mode 100644 index 4551476a4..000000000 --- a/apps/openmw/mwrender/ripplesimulation.hpp +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef RIPPLE_SIMULATION_H -#define RIPPLE_SIMULATION_H - -#include - -#include "../mwworld/ptr.hpp" - -namespace Ogre -{ - class SceneManager; - class ParticleSystem; -} - -namespace MWWorld -{ - class Fallback; -} - -namespace MWRender -{ - -struct Emitter -{ - MWWorld::Ptr mPtr; - Ogre::Vector3 mLastEmitPosition; - float mScale; - float mForce; -}; - -class RippleSimulation -{ -public: - RippleSimulation(Ogre::SceneManager* mainSceneManager, const MWWorld::Fallback* fallback); - ~RippleSimulation(); - - /// @param dt Time since the last frame - /// @param position Position of the player - void update(float dt, Ogre::Vector2 position); - - /// adds an emitter, position will be tracked automatically - void addEmitter (const MWWorld::Ptr& ptr, float scale = 1.f, float force = 1.f); - void removeEmitter (const MWWorld::Ptr& ptr); - void updateEmitterPtr (const MWWorld::Ptr& old, const MWWorld::Ptr& ptr); - - /// Change the height of the water surface, thus moving all ripples with it - void setWaterHeight(float height); - - /// Remove all active ripples - void clear(); - -private: - Ogre::SceneManager* mSceneMgr; - Ogre::ParticleSystem* mParticleSystem; - Ogre::SceneNode* mSceneNode; - - std::vector mEmitters; - - float mRippleLifeTime; - float mRippleRotSpeed; -}; - -} - -#endif diff --git a/apps/openmw/mwrender/shadows.cpp b/apps/openmw/mwrender/shadows.cpp deleted file mode 100644 index f2e60b11b..000000000 --- a/apps/openmw/mwrender/shadows.cpp +++ /dev/null @@ -1,187 +0,0 @@ -#include "shadows.hpp" - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "renderconst.hpp" - -using namespace Ogre; -using namespace MWRender; - -Shadows::Shadows(OEngine::Render::OgreRenderer* rend) : - mRendering(rend), mSceneMgr(rend->getScene()), mPSSMSetup(NULL), - mShadowFar(1000), mFadeStart(0.9f) -{ - recreate(); -} - -void Shadows::recreate() -{ - bool enabled = Settings::Manager::getBool("enabled", "Shadows"); - - bool split = Settings::Manager::getBool("split", "Shadows"); - - sh::Factory::getInstance ().setGlobalSetting ("shadows", enabled && !split ? "true" : "false"); - sh::Factory::getInstance ().setGlobalSetting ("shadows_pssm", enabled && split ? "true" : "false"); - - if (!enabled) - { - mSceneMgr->setShadowTechnique(SHADOWTYPE_NONE); - return; - } - - int texsize = Settings::Manager::getInt("texture size", "Shadows"); - mSceneMgr->setShadowTextureSize(texsize); - - mSceneMgr->setShadowTechnique(SHADOWTYPE_TEXTURE_MODULATIVE_INTEGRATED); - - // no point light shadows, i'm afraid. might revisit this with Deferred Shading - mSceneMgr->setShadowTextureCountPerLightType(Light::LT_POINT, 0); - - mSceneMgr->setShadowTextureCountPerLightType(Light::LT_DIRECTIONAL, split ? 3 : 1); - mSceneMgr->setShadowTextureCount(split ? 3 : 1); - - mSceneMgr->setShadowTextureSelfShadow(true); - mSceneMgr->setShadowCasterRenderBackFaces(true); - mSceneMgr->setShadowTextureCasterMaterial("openmw_shadowcaster_default"); - mSceneMgr->setShadowTexturePixelFormat(PF_FLOAT32_R); - mSceneMgr->setShadowDirectionalLightExtrusionDistance(1000000); - - mShadowFar = Settings::Manager::getFloat(split ? "split shadow distance" : "shadow distance", "Shadows"); - mSceneMgr->setShadowFarDistance(mShadowFar); - - mFadeStart = Settings::Manager::getFloat("fade start", "Shadows"); - - ShadowCameraSetupPtr shadowCameraSetup; - if (split) - { - mPSSMSetup = new PSSMShadowCameraSetup(); - - // Make sure to keep this in sync with the camera's near clip distance! - mPSSMSetup->setSplitPadding(mRendering->getCamera()->getNearClipDistance()); - - mPSSMSetup->calculateSplitPoints(3, mRendering->getCamera()->getNearClipDistance(), mShadowFar); - - const Real adjustFactors[3] = {64, 64, 64}; - for (int i=0; i < 3; ++i) - { - mPSSMSetup->setOptimalAdjustFactor(i, adjustFactors[i]); - /*if (i==0) - mSceneMgr->setShadowTextureConfig(i, texsize, texsize, Ogre::PF_FLOAT32_R); - else if (i ==1) - mSceneMgr->setShadowTextureConfig(i, texsize/2, texsize/2, Ogre::PF_FLOAT32_R); - else if (i ==2) - mSceneMgr->setShadowTextureConfig(i, texsize/4, texsize/4, Ogre::PF_FLOAT32_R);*/ - } - - // Populate from split point 1, not 0, since split 0 isn't useful (usually 0) - const PSSMShadowCameraSetup::SplitPointList& splitPointList = getPSSMSetup()->getSplitPoints(); - sh::Vector3* splitPoints = new sh::Vector3(splitPointList[1], splitPointList[2], splitPointList[3]); - - sh::Factory::getInstance ().setSharedParameter ("pssmSplitPoints", sh::makeProperty(splitPoints)); - - shadowCameraSetup = ShadowCameraSetupPtr(mPSSMSetup); - } - else - { - LiSPSMShadowCameraSetup* lispsmSetup = new LiSPSMShadowCameraSetup(); - lispsmSetup->setOptimalAdjustFactor(64); - //lispsmSetup->setCameraLightDirectionThreshold(Degree(0)); - //lispsmSetup->setUseAggressiveFocusRegion(false); - shadowCameraSetup = ShadowCameraSetupPtr(lispsmSetup); - } - mSceneMgr->setShadowCameraSetup(shadowCameraSetup); - - sh::Vector4* shadowFar_fadeStart = new sh::Vector4(mShadowFar, mFadeStart * mShadowFar, 0, 0); - sh::Factory::getInstance ().setSharedParameter ("shadowFar_fadeStart", sh::makeProperty(shadowFar_fadeStart)); - - // Set visibility mask for the shadow render textures - int visibilityMask = RV_Actors * Settings::Manager::getBool("actor shadows", "Shadows") - + (RV_Statics + RV_StaticsSmall) * Settings::Manager::getBool("statics shadows", "Shadows") - + RV_Misc * Settings::Manager::getBool("misc shadows", "Shadows") - + RV_Terrain * (Settings::Manager::getBool("terrain shadows", "Shadows")); - for (int i = 0; i < (split ? 3 : 1); ++i) - { - TexturePtr shadowTexture = mSceneMgr->getShadowTexture(i); - Viewport* vp = shadowTexture->getBuffer()->getRenderTarget()->getViewport(0); - vp->setVisibilityMask(visibilityMask); - } - - // -------------------------------------------------------------------------------------------------------------------- - // --------------------------- Debug overlays to display the content of shadow maps ----------------------------------- - // -------------------------------------------------------------------------------------------------------------------- - /* - if (Settings::Manager::getBool("debug", "Shadows")) - { - OverlayManager& mgr = OverlayManager::getSingleton(); - Overlay* overlay; - - // destroy if already exists - if ((overlay = mgr.getByName("DebugOverlay"))) - mgr.destroy(overlay); - - overlay = mgr.create("DebugOverlay"); - for (size_t i = 0; i < (split ? 3 : 1); ++i) { - TexturePtr tex = mRendering->getScene()->getShadowTexture(i); - - // Set up a debug panel to display the shadow - - if (MaterialManager::getSingleton().resourceExists("Ogre/DebugTexture" + StringConverter::toString(i))) - MaterialManager::getSingleton().remove("Ogre/DebugTexture" + StringConverter::toString(i)); - MaterialPtr debugMat = MaterialManager::getSingleton().create( - "Ogre/DebugTexture" + StringConverter::toString(i), - ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); - - debugMat->getTechnique(0)->getPass(0)->setLightingEnabled(false); - TextureUnitState *t = debugMat->getTechnique(0)->getPass(0)->createTextureUnitState(tex->getName()); - t->setTextureAddressingMode(TextureUnitState::TAM_CLAMP); - - OverlayContainer* debugPanel; - - // destroy container if exists - try - { - if ((debugPanel = - static_cast( - mgr.getOverlayElement("Ogre/DebugTexPanel" + StringConverter::toString(i) - )))) - mgr.destroyOverlayElement(debugPanel); - } - catch (Ogre::Exception&) {} - - debugPanel = (OverlayContainer*) - (OverlayManager::getSingleton().createOverlayElement("Panel", "Ogre/DebugTexPanel" + StringConverter::toString(i))); - debugPanel->_setPosition(0.8, i*0.25); - debugPanel->_setDimensions(0.2, 0.24); - debugPanel->setMaterialName(debugMat->getName()); - debugPanel->show(); - overlay->add2D(debugPanel); - overlay->show(); - } - } - else - { - OverlayManager& mgr = OverlayManager::getSingleton(); - Overlay* overlay; - - if ((overlay = mgr.getByName("DebugOverlay"))) - mgr.destroy(overlay); - } - */ -} - -PSSMShadowCameraSetup* Shadows::getPSSMSetup() -{ - return mPSSMSetup; -} diff --git a/apps/openmw/mwrender/shadows.hpp b/apps/openmw/mwrender/shadows.hpp deleted file mode 100644 index fe125f54c..000000000 --- a/apps/openmw/mwrender/shadows.hpp +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef GAME_SHADOWS_H -#define GAME_SHADOWS_H - -// forward declares -namespace Ogre -{ - class SceneManager; - class PSSMShadowCameraSetup; -} -namespace OEngine{ - namespace Render{ - class OgreRenderer; - } -} - -namespace MWRender -{ - class Shadows - { - public: - Shadows(OEngine::Render::OgreRenderer* rend); - - void recreate(); - - Ogre::PSSMShadowCameraSetup* getPSSMSetup(); - - protected: - OEngine::Render::OgreRenderer* mRendering; - Ogre::SceneManager* mSceneMgr; - - Ogre::PSSMShadowCameraSetup* mPSSMSetup; - float mShadowFar; - float mFadeStart; - }; -} - -#endif From e49cf2888de2c8a0ef5e3189afbeda0d674d04c9 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Wed, 3 Jun 2015 10:15:28 +0200 Subject: [PATCH 1386/3725] Let's disable everything except OpenMW itself Just to check if it's at all possible to use AppVeyor --- CI/before_script.msvc.sh | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/CI/before_script.msvc.sh b/CI/before_script.msvc.sh index 36f8213d4..66f74520c 100644 --- a/CI/before_script.msvc.sh +++ b/CI/before_script.msvc.sh @@ -355,7 +355,12 @@ echo "Building OpenMW..." add_cmake_opts -DBUILD_BSATOOL=no \ -DBUILD_ESMTOOL=no \ - -DBUILD_MYGUI_PLUGIN=no + -DBUILD_MYGUI_PLUGIN=no \ + -DBUILD_OPENCS=no \ + -DBUILD_WIZARD=no \ + -DBUILD_ESSIMPORTER=no \ + -DBUILD_LAUNCHER=no \ + -DBUILD_MWINIIMPORTER=no if [ -z $VERBOSE ]; then printf " Configuring... " @@ -373,4 +378,4 @@ fi echo -exit $RET \ No newline at end of file +exit $RET From b25cc6bc556ff688fcf5becd4d71c3551f5681af Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Wed, 3 Jun 2015 12:01:13 +0300 Subject: [PATCH 1387/3725] IdCompletionManager uses Display type instread of ColumnId for creating completers --- .../model/world/idcompletionmanager.cpp | 117 +++++++----------- .../model/world/idcompletionmanager.hpp | 17 +-- apps/opencs/view/doc/viewmanager.cpp | 38 ++---- .../view/world/idcompletiondelegate.cpp | 16 ++- 4 files changed, 70 insertions(+), 118 deletions(-) diff --git a/apps/opencs/model/world/idcompletionmanager.cpp b/apps/opencs/model/world/idcompletionmanager.cpp index 6736e9477..b59987cba 100644 --- a/apps/opencs/model/world/idcompletionmanager.cpp +++ b/apps/opencs/model/world/idcompletionmanager.cpp @@ -11,102 +11,77 @@ namespace { - std::map generateModelTypes() + std::map generateModelTypes() { - std::map types; + std::map types; - types[CSMWorld::Columns::ColumnId_Actor] = CSMWorld::UniversalId::Type_Referenceable; - types[CSMWorld::Columns::ColumnId_AreaObject] = CSMWorld::UniversalId::Type_Referenceable; - types[CSMWorld::Columns::ColumnId_AreaSound] = CSMWorld::UniversalId::Type_Sound; - types[CSMWorld::Columns::ColumnId_BoltObject] = CSMWorld::UniversalId::Type_Referenceable; - types[CSMWorld::Columns::ColumnId_BoltSound] = CSMWorld::UniversalId::Type_Sound; - types[CSMWorld::Columns::ColumnId_CastingObject] = CSMWorld::UniversalId::Type_Referenceable; - types[CSMWorld::Columns::ColumnId_CastingSound] = CSMWorld::UniversalId::Type_Sound; - types[CSMWorld::Columns::ColumnId_Cell] = CSMWorld::UniversalId::Type_Cell; - types[CSMWorld::Columns::ColumnId_Class] = CSMWorld::UniversalId::Type_Class; - types[CSMWorld::Columns::ColumnId_CloseSound] = CSMWorld::UniversalId::Type_Sound; - types[CSMWorld::Columns::ColumnId_Creature] = CSMWorld::UniversalId::Type_Referenceable; - types[CSMWorld::Columns::ColumnId_DestinationCell] = CSMWorld::UniversalId::Type_Cell; - types[CSMWorld::Columns::ColumnId_Enchantment] = CSMWorld::UniversalId::Type_Enchantment; - types[CSMWorld::Columns::ColumnId_Faction] = CSMWorld::UniversalId::Type_Faction; - types[CSMWorld::Columns::Columnid_Hair] = CSMWorld::UniversalId::Type_BodyPart; - types[CSMWorld::Columns::ColumnId_Head] = CSMWorld::UniversalId::Type_BodyPart; - types[CSMWorld::Columns::ColumnId_HitObject] = CSMWorld::UniversalId::Type_Referenceable; - types[CSMWorld::Columns::ColumnId_HitSound] = CSMWorld::UniversalId::Type_Sound; - types[CSMWorld::Columns::ColumnId_Icon] = CSMWorld::UniversalId::Type_Icon; - types[CSMWorld::Columns::ColumnId_InventoryItemId] = CSMWorld::UniversalId::Type_Referenceable; - types[CSMWorld::Columns::ColumnId_Key] = CSMWorld::UniversalId::Type_Referenceable; - types[CSMWorld::Columns::ColumnId_LevelledItemId] = CSMWorld::UniversalId::Type_Referenceable; - types[CSMWorld::Columns::ColumnId_MajorSkill1] = CSMWorld::UniversalId::Type_Skill; - types[CSMWorld::Columns::ColumnId_MajorSkill2] = CSMWorld::UniversalId::Type_Skill; - types[CSMWorld::Columns::ColumnId_MajorSkill3] = CSMWorld::UniversalId::Type_Skill; - types[CSMWorld::Columns::ColumnId_MajorSkill4] = CSMWorld::UniversalId::Type_Skill; - types[CSMWorld::Columns::ColumnId_MajorSkill5] = CSMWorld::UniversalId::Type_Skill; - types[CSMWorld::Columns::ColumnId_MinorSkill1] = CSMWorld::UniversalId::Type_Skill; - types[CSMWorld::Columns::ColumnId_MinorSkill2] = CSMWorld::UniversalId::Type_Skill; - types[CSMWorld::Columns::ColumnId_MinorSkill3] = CSMWorld::UniversalId::Type_Skill; - types[CSMWorld::Columns::ColumnId_MinorSkill4] = CSMWorld::UniversalId::Type_Skill; - types[CSMWorld::Columns::ColumnId_MinorSkill5] = CSMWorld::UniversalId::Type_Skill; - types[CSMWorld::Columns::ColumnId_Model] = CSMWorld::UniversalId::Type_Mesh; - types[CSMWorld::Columns::ColumnId_OpenSound] = CSMWorld::UniversalId::Type_Sound; - types[CSMWorld::Columns::ColumnId_OriginalCreature] = CSMWorld::UniversalId::Type_Referenceable; - types[CSMWorld::Columns::ColumnId_Owner] = CSMWorld::UniversalId::Type_Referenceable; - types[CSMWorld::Columns::ColumnId_OwnerGlobal] = CSMWorld::UniversalId::Type_Global; - types[CSMWorld::Columns::ColumnId_Particle] = CSMWorld::UniversalId::Type_Texture; - types[CSMWorld::Columns::ColumnId_PartRefMale] = CSMWorld::UniversalId::Type_BodyPart; - types[CSMWorld::Columns::ColumnId_PartRefFemale] = CSMWorld::UniversalId::Type_BodyPart; - types[CSMWorld::Columns::ColumnId_PcFaction] = CSMWorld::UniversalId::Type_Faction; - types[CSMWorld::Columns::ColumnId_Race] = CSMWorld::UniversalId::Type_Race; - types[CSMWorld::Columns::ColumnId_ReferenceableId] = CSMWorld::UniversalId::Type_Referenceable; - types[CSMWorld::Columns::ColumnId_Region] = CSMWorld::UniversalId::Type_Region; - types[CSMWorld::Columns::ColumnId_Skill1] = CSMWorld::UniversalId::Type_Skill; - types[CSMWorld::Columns::ColumnId_Skill2] = CSMWorld::UniversalId::Type_Skill; - types[CSMWorld::Columns::ColumnId_Skill3] = CSMWorld::UniversalId::Type_Skill; - types[CSMWorld::Columns::ColumnId_Skill4] = CSMWorld::UniversalId::Type_Skill; - types[CSMWorld::Columns::ColumnId_Skill5] = CSMWorld::UniversalId::Type_Skill; - types[CSMWorld::Columns::ColumnId_Skill6] = CSMWorld::UniversalId::Type_Skill; - types[CSMWorld::Columns::ColumnId_Skill7] = CSMWorld::UniversalId::Type_Skill; - types[CSMWorld::Columns::ColumnId_SleepEncounter] = CSMWorld::UniversalId::Type_Referenceable; - types[CSMWorld::Columns::ColumnId_Soul] = CSMWorld::UniversalId::Type_Referenceable; - types[CSMWorld::Columns::ColumnId_Sound] = CSMWorld::UniversalId::Type_Sound; - types[CSMWorld::Columns::ColumnId_SoundFile] = CSMWorld::UniversalId::Type_SoundRes; - types[CSMWorld::Columns::ColumnId_SoundName] = CSMWorld::UniversalId::Type_Sound; - types[CSMWorld::Columns::ColumnId_SpellId] = CSMWorld::UniversalId::Type_Spell; - types[CSMWorld::Columns::ColumnId_Script] = CSMWorld::UniversalId::Type_Script; - types[CSMWorld::Columns::ColumnId_TeleportCell] = CSMWorld::UniversalId::Type_Cell; - types[CSMWorld::Columns::ColumnId_Texture] = CSMWorld::UniversalId::Type_Texture; - types[CSMWorld::Columns::ColumnId_Trap] = CSMWorld::UniversalId::Type_Spell; + types[CSMWorld::ColumnBase::Display_BodyPart ] = CSMWorld::UniversalId::Type_BodyPart; + types[CSMWorld::ColumnBase::Display_Cell ] = CSMWorld::UniversalId::Type_Cell; + types[CSMWorld::ColumnBase::Display_Class ] = CSMWorld::UniversalId::Type_Class; + types[CSMWorld::ColumnBase::Display_CreatureLevelledList] = CSMWorld::UniversalId::Type_Referenceable; + types[CSMWorld::ColumnBase::Display_Creature ] = CSMWorld::UniversalId::Type_Referenceable; + types[CSMWorld::ColumnBase::Display_Enchantment ] = CSMWorld::UniversalId::Type_Enchantment; + types[CSMWorld::ColumnBase::Display_Faction ] = CSMWorld::UniversalId::Type_Faction; + types[CSMWorld::ColumnBase::Display_GlobalVariable ] = CSMWorld::UniversalId::Type_Global; + types[CSMWorld::ColumnBase::Display_Icon ] = CSMWorld::UniversalId::Type_Icon; + types[CSMWorld::ColumnBase::Display_Mesh ] = CSMWorld::UniversalId::Type_Mesh; + types[CSMWorld::ColumnBase::Display_Miscellaneous ] = CSMWorld::UniversalId::Type_Referenceable; + types[CSMWorld::ColumnBase::Display_Npc ] = CSMWorld::UniversalId::Type_Referenceable; + types[CSMWorld::ColumnBase::Display_Race ] = CSMWorld::UniversalId::Type_Race; + types[CSMWorld::ColumnBase::Display_Region ] = CSMWorld::UniversalId::Type_Region; + types[CSMWorld::ColumnBase::Display_Referenceable ] = CSMWorld::UniversalId::Type_Referenceable; + types[CSMWorld::ColumnBase::Display_Script ] = CSMWorld::UniversalId::Type_Script; + types[CSMWorld::ColumnBase::Display_Skill ] = CSMWorld::UniversalId::Type_Skill; + types[CSMWorld::ColumnBase::Display_Sound ] = CSMWorld::UniversalId::Type_Sound; + types[CSMWorld::ColumnBase::Display_SoundRes ] = CSMWorld::UniversalId::Type_SoundRes; + types[CSMWorld::ColumnBase::Display_Spell ] = CSMWorld::UniversalId::Type_Spell; + types[CSMWorld::ColumnBase::Display_Static ] = CSMWorld::UniversalId::Type_Referenceable; + types[CSMWorld::ColumnBase::Display_Texture ] = CSMWorld::UniversalId::Type_Texture; + types[CSMWorld::ColumnBase::Display_Weapon ] = CSMWorld::UniversalId::Type_Referenceable; return types; } + + typedef std::map::const_iterator ModelTypeConstIterator; } -const std::map +const std::map CSMWorld::IdCompletionManager::sCompleterModelTypes = generateModelTypes(); +std::vector CSMWorld::IdCompletionManager::getDisplayTypes() +{ + std::vector types; + ModelTypeConstIterator current = sCompleterModelTypes.begin(); + ModelTypeConstIterator end = sCompleterModelTypes.end(); + for (; current != end; ++current) + { + types.push_back(current->first); + } + return types; +} + CSMWorld::IdCompletionManager::IdCompletionManager(CSMWorld::Data &data) { generateCompleters(data); } -bool CSMWorld::IdCompletionManager::hasCompleterFor(CSMWorld::Columns::ColumnId id) const +bool CSMWorld::IdCompletionManager::hasCompleterFor(CSMWorld::ColumnBase::Display display) const { - return mCompleters.find(id) != mCompleters.end(); + return mCompleters.find(display) != mCompleters.end(); } -boost::shared_ptr CSMWorld::IdCompletionManager::getCompleter(CSMWorld::Columns::ColumnId id) +boost::shared_ptr CSMWorld::IdCompletionManager::getCompleter(CSMWorld::ColumnBase::Display display) { - if (!hasCompleterFor(id)) + if (!hasCompleterFor(display)) { throw std::logic_error("This column doesn't have an ID completer"); } - return mCompleters[id]; + return mCompleters[display]; } void CSMWorld::IdCompletionManager::generateCompleters(CSMWorld::Data &data) { - typedef std::map::const_iterator ModelTypeConstIterator; - ModelTypeConstIterator current = sCompleterModelTypes.begin(); ModelTypeConstIterator end = sCompleterModelTypes.end(); for (; current != end; ++current) diff --git a/apps/opencs/model/world/idcompletionmanager.hpp b/apps/opencs/model/world/idcompletionmanager.hpp index ee75ddf24..7944e6777 100644 --- a/apps/opencs/model/world/idcompletionmanager.hpp +++ b/apps/opencs/model/world/idcompletionmanager.hpp @@ -1,11 +1,12 @@ #ifndef CSM_WORLD_IDCOMPLETIONMANAGER_HPP #define CSM_WORLD_IDCOMPLETIONMANAGER_HPP +#include #include #include -#include "columns.hpp" +#include "columnbase.hpp" #include "universalid.hpp" class QCompleter; @@ -17,21 +18,23 @@ namespace CSMWorld /// \brief Creates and stores all ID completers class IdCompletionManager { - static const std::map sCompleterModelTypes; + static const std::map sCompleterModelTypes; - std::map > mCompleters; + std::map > mCompleters; // Don't allow copying IdCompletionManager(const IdCompletionManager &); IdCompletionManager &operator = (const IdCompletionManager &); - void generateCompleters(CSMWorld::Data &data); + void generateCompleters(Data &data); public: - IdCompletionManager(CSMWorld::Data &data); + static std::vector getDisplayTypes(); - bool hasCompleterFor(CSMWorld::Columns::ColumnId id) const; - boost::shared_ptr getCompleter(CSMWorld::Columns::ColumnId id); + IdCompletionManager(Data &data); + + bool hasCompleterFor(ColumnBase::Display display) const; + boost::shared_ptr getCompleter(ColumnBase::Display display); }; } diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index f48513703..b2f681df1 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -1,6 +1,7 @@ #include "viewmanager.hpp" +#include #include #include @@ -10,6 +11,7 @@ #include "../../model/doc/document.hpp" #include "../../model/world/columns.hpp" #include "../../model/world/universalid.hpp" +#include "../../model/world/idcompletionmanager.hpp" #include "../world/util.hpp" #include "../world/enumdelegate.hpp" @@ -61,38 +63,12 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) mDelegateFactories->add (CSMWorld::ColumnBase::Display_RefRecordType, new CSVWorld::IdTypeDelegateFactory()); - // Columns with QLineEdit editor - static const CSMWorld::ColumnBase::Display sIdCompletionColumns[] = + std::vector idCompletionColumns = CSMWorld::IdCompletionManager::getDisplayTypes(); + for (std::vector::const_iterator current = idCompletionColumns.begin(); + current != idCompletionColumns.end(); + ++current) { - CSMWorld::ColumnBase::Display_Cell, - CSMWorld::ColumnBase::Display_Class, - CSMWorld::ColumnBase::Display_Creature, - CSMWorld::ColumnBase::Display_Faction, - CSMWorld::ColumnBase::Display_String, - CSMWorld::ColumnBase::Display_GlobalVariable, - CSMWorld::ColumnBase::Display_Icon, - CSMWorld::ColumnBase::Display_Mesh, - CSMWorld::ColumnBase::Display_Miscellaneous, - CSMWorld::ColumnBase::Display_Music, - CSMWorld::ColumnBase::Display_None, // Inplace editing (Table SubView) creates QLineEdit using Display_None - CSMWorld::ColumnBase::Display_Npc, - CSMWorld::ColumnBase::Display_Race, - CSMWorld::ColumnBase::Display_Referenceable, - CSMWorld::ColumnBase::Display_Region, - CSMWorld::ColumnBase::Display_Script, - CSMWorld::ColumnBase::Display_Skill, - CSMWorld::ColumnBase::Display_Sound, - CSMWorld::ColumnBase::Display_SoundRes, - CSMWorld::ColumnBase::Display_Static, - CSMWorld::ColumnBase::Display_String, - CSMWorld::ColumnBase::Display_Texture, - CSMWorld::ColumnBase::Display_Video, - CSMWorld::ColumnBase::Display_Weapon - }; - - for (std::size_t i = 0; i < sizeof(sIdCompletionColumns) / sizeof(CSMWorld::ColumnBase::Display); ++i) - { - mDelegateFactories->add(sIdCompletionColumns[i], new CSVWorld::IdCompletionDelegateFactory()); + mDelegateFactories->add(*current, new CSVWorld::IdCompletionDelegateFactory()); } struct Mapping diff --git a/apps/opencs/view/world/idcompletiondelegate.cpp b/apps/opencs/view/world/idcompletiondelegate.cpp index 2a1e97f4b..056026471 100644 --- a/apps/opencs/view/world/idcompletiondelegate.cpp +++ b/apps/opencs/view/world/idcompletiondelegate.cpp @@ -12,7 +12,7 @@ QWidget *CSVWorld::IdCompletionDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const { - return createEditor(parent, option, index, CSMWorld::ColumnBase::Display_None); + return createEditor(parent, option, index, getDisplayTypeFromIndex(index)); } QWidget *CSVWorld::IdCompletionDelegate::createEditor(QWidget *parent, @@ -20,16 +20,14 @@ QWidget *CSVWorld::IdCompletionDelegate::createEditor(QWidget *parent, const QModelIndex &index, CSMWorld::ColumnBase::Display display) const { - int columnIdData = index.data(CSMWorld::ColumnBase::Role_ColumnId).toInt(); - CSMWorld::Columns::ColumnId columnId = static_cast(columnIdData); - CSMWorld::IdCompletionManager &completionManager = getDocument().getIdCompletionManager(); - - QWidget *editor = CSVWorld::CommandDelegate::createEditor(parent, option, index, display); - QLineEdit *lineEditor = qobject_cast(editor); - if (lineEditor != NULL && completionManager.hasCompleterFor(columnId)) + if (!index.data(Qt::EditRole).isValid() && !index.data(Qt::DisplayRole).isValid()) { - lineEditor->setCompleter(completionManager.getCompleter(columnId).get()); + return NULL; } + + CSMWorld::IdCompletionManager &completionManager = getDocument().getIdCompletionManager(); + DropLineEdit *editor = new DropLineEdit(parent); + editor->setCompleter(completionManager.getCompleter(display).get()); return editor; } From bd46ddcf47c3a50943a14ea2772dac9e8ef247f8 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Wed, 3 Jun 2015 15:51:34 +0300 Subject: [PATCH 1388/3725] Correct the return type in IdTree::data() for Display_Role --- apps/opencs/model/world/idtree.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/world/idtree.cpp b/apps/opencs/model/world/idtree.cpp index a3dbae465..1e81d6ac2 100644 --- a/apps/opencs/model/world/idtree.cpp +++ b/apps/opencs/model/world/idtree.cpp @@ -41,7 +41,7 @@ QVariant CSMWorld::IdTree::data (const QModelIndex & index, int role) const const NestableColumn *parentColumn = mNestedCollection->getNestableColumn(parentAddress.second); if (role == ColumnBase::Role_Display) - return parentColumn->nestedColumn(index.column()).mColumnId; + return parentColumn->nestedColumn(index.column()).mDisplayType; if (role == ColumnBase::Role_ColumnId) return parentColumn->nestedColumn(index.column()).mColumnId; From 24551c7bab5cc818f258af5e366ff8da03b56481 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Jun 2015 14:56:57 +0200 Subject: [PATCH 1389/3725] Fix for savegame incompatibility with master branch --- apps/openmw/mwrender/localmap.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 16957a585..77138a124 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -99,12 +99,15 @@ void LocalMap::saveFogOfWar(MWWorld::CellStore* cell) { const MapSegment& segment = mSegments[std::make_pair(cell->getCell()->getGridX(), cell->getCell()->getGridY())]; - std::auto_ptr fog (new ESM::FogState()); - fog->mFogTextures.push_back(ESM::FogTexture()); + if (segment.mFogOfWarImage && segment.mHasFogState) + { + std::auto_ptr fog (new ESM::FogState()); + fog->mFogTextures.push_back(ESM::FogTexture()); - segment.saveFogOfWar(fog->mFogTextures.back()); + segment.saveFogOfWar(fog->mFogTextures.back()); - cell->setFog(fog.release()); + cell->setFog(fog.release()); + } } else { @@ -133,6 +136,8 @@ void LocalMap::saveFogOfWar(MWWorld::CellStore* cell) fog->mFogTextures.push_back(ESM::FogTexture()); + // saving even if !segment.mHasFogState so we don't mess up the segmenting + // plus, older openmw versions can't deal with empty images segment.saveFogOfWar(fog->mFogTextures.back()); fog->mFogTextures.back().mX = x; @@ -644,7 +649,7 @@ void LocalMap::MapSegment::loadFogOfWar(const ESM::FogTexture &esm) void LocalMap::MapSegment::saveFogOfWar(ESM::FogTexture &fog) const { - if (!mFogOfWarImage || !mHasFogState) + if (!mFogOfWarImage) return; std::ostringstream ostream; From 2a85a22dba62c875cb579a414be90729e092626a Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Jun 2015 16:40:16 +0200 Subject: [PATCH 1390/3725] Write savegame screenshot --- apps/openmw/mwbase/world.hpp | 3 +- apps/openmw/mwrender/renderingmanager.cpp | 59 +++++++++++++++++++++++ apps/openmw/mwrender/renderingmanager.hpp | 3 ++ apps/openmw/mwstate/statemanagerimp.cpp | 41 ++++++++++++---- apps/openmw/mwstate/statemanagerimp.hpp | 2 + apps/openmw/mwworld/worldimp.cpp | 4 +- apps/openmw/mwworld/worldimp.hpp | 2 +- 7 files changed, 101 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index f258eb300..bb48afc9d 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -23,6 +23,7 @@ namespace osg { class Vec3f; class Quat; + class Image; } namespace Loading @@ -438,7 +439,7 @@ namespace MWBase virtual void reattachPlayerCamera() = 0; /// \todo this does not belong here - virtual void screenshot (Ogre::Image& image, int w, int h) = 0; + virtual void screenshot (osg::Image* image, int w, int h) = 0; /// Find default position inside exterior cell specified by name /// \return false if exterior with given name not exists, true otherwise diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 6205c3ad8..7af21a5a6 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -379,6 +379,65 @@ namespace MWRender mWater->setHeight(height); } + class NotifyDrawCompletedCallback : public osg::Camera::DrawCallback + { + public: + virtual void operator () (osg::RenderInfo& renderInfo) const + { + mCondition.signal(); + } + + mutable OpenThreads::Condition mCondition; + }; + + void RenderingManager::screenshot(osg::Image *image, int w, int h) + { + int oldCullMask = mViewer->getCamera()->getCullMask(); + mViewer->getCamera()->setCullMask(oldCullMask & (~Mask_GUI)); + + osg::ref_ptr rttCamera (new osg::Camera); + rttCamera->setNodeMask(Mask_RenderToTexture); + rttCamera->attach(osg::Camera::COLOR_BUFFER, image); + rttCamera->setRenderOrder(osg::Camera::PRE_RENDER); + rttCamera->setReferenceFrame(osg::Camera::ABSOLUTE_RF); + rttCamera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT, osg::Camera::PIXEL_BUFFER_RTT); + rttCamera->setClearColor(mViewer->getCamera()->getClearColor()); + rttCamera->setClearMask(mViewer->getCamera()->getClearMask()); + rttCamera->setProjectionMatrixAsPerspective(mFieldOfView, w/float(h), mNearClip, mViewDistance); + rttCamera->setViewMatrix(mViewer->getCamera()->getViewMatrix()); + rttCamera->setViewport(0, 0, w, h); + rttCamera->setGraphicsContext(mViewer->getCamera()->getGraphicsContext()); + + osg::ref_ptr texture (new osg::Texture2D); + texture->setInternalFormat(GL_RGB); + texture->setTextureSize(w, h); + texture->setResizeNonPowerOfTwoHint(false); + rttCamera->attach(osg::Camera::COLOR_BUFFER, texture); + + image->setDataType(GL_UNSIGNED_BYTE); + image->setPixelFormat(texture->getInternalFormat()); + + rttCamera->addChild(mLightRoot); + + mRootNode->addChild(rttCamera); + + mViewer->frame(); + + // The draw needs to complete before we can copy back our image. + osg::ref_ptr callback (new NotifyDrawCompletedCallback); + rttCamera->setFinalDrawCallback(callback); + OpenThreads::Mutex m; + m.lock(); + callback->mCondition.wait(&m); + m.unlock(); + + rttCamera->removeChildren(0, rttCamera->getNumChildren()); + rttCamera->setGraphicsContext(NULL); + mRootNode->removeChild(rttCamera); + + mViewer->getCamera()->setCullMask(oldCullMask); + } + void RenderingManager::getCameraToViewportRay(float nX, float nY, osg::Vec3f &origin, osg::Vec3f &dest) { osg::Matrix viewProj = mViewer->getCamera()->getViewMatrix() * mViewer->getCamera()->getProjectionMatrix(); diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index c22d3c7bf..4452ae9f8 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -82,6 +82,9 @@ namespace MWRender void setWaterEnabled(bool enabled); void setWaterHeight(float level); + /// Take a screenshot of w*h onto the given image, not including the GUI. + void screenshot(osg::Image* image, int w, int h); + /// Return the object under the mouse cursor / crosshair position, given by nX and nY normalized screen coordinates, /// where (0,0) is the top left corner. MWWorld::Ptr getFacedObject(const float nX, const float nY, float maxDistance, bool ignorePlayer); diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index d403590dd..ce4d8f958 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -10,7 +10,9 @@ #include -#include +#include + +#include #include #include @@ -179,14 +181,7 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot profile.mTimePlayed = mTimePlayed; profile.mDescription = description; - /* - int screenshotW = 259*2, screenshotH = 133*2; // *2 to get some nice antialiasing - Ogre::Image screenshot; - world.screenshot(screenshot, screenshotW, screenshotH); - Ogre::DataStreamPtr encoded = screenshot.encode("jpg"); - profile.mScreenshot.resize(encoded->size()); - encoded->read(&profile.mScreenshot[0], encoded->size()); - */ + writeScreenshot(profile.mScreenshot); if (!slot) slot = getCurrentCharacter()->createSlot (profile); @@ -572,3 +567,31 @@ bool MWState::StateManager::verifyProfile(const ESM::SavedGame& profile) const } return true; } + +void MWState::StateManager::writeScreenshot(std::vector &imageData) const +{ + int screenshotW = 259*2, screenshotH = 133*2; // *2 to get some nice antialiasing + + osg::ref_ptr screenshot (new osg::Image); + + MWBase::Environment::get().getWorld()->screenshot(screenshot.get(), screenshotW, screenshotH); + + osgDB::ReaderWriter* readerwriter = osgDB::Registry::instance()->getReaderWriterForExtension("jpg"); + if (!readerwriter) + { + std::cerr << "Unable to write screenshot, can't find a jpg ReaderWriter" << std::endl; + return; + } + + std::ostringstream ostream; + osgDB::ReaderWriter::WriteResult result = readerwriter->writeImage(*screenshot, ostream); + if (!result.success()) + { + std::cerr << "Unable to write screenshot: " << result.message() << std::endl; + return; + } + + std::string data = ostream.str(); + imageData = std::vector(data.begin(), data.end()); + +} diff --git a/apps/openmw/mwstate/statemanagerimp.hpp b/apps/openmw/mwstate/statemanagerimp.hpp index 37f38f8df..59dc919d1 100644 --- a/apps/openmw/mwstate/statemanagerimp.hpp +++ b/apps/openmw/mwstate/statemanagerimp.hpp @@ -25,6 +25,8 @@ namespace MWState bool verifyProfile (const ESM::SavedGame& profile) const; + void writeScreenshot (std::vector& imageData) const; + std::map buildContentFileIndexMap (const ESM::ESMReader& reader) const; public: diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 7528e9286..7bc46c078 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2128,9 +2128,9 @@ namespace MWWorld return mRendering->getAnimation(ptr); } - void World::screenshot(Ogre::Image &image, int w, int h) + void World::screenshot(osg::Image* image, int w, int h) { - //mRendering->screenshot(image, w, h); + mRendering->screenshot(image, w, h); } void World::activateDoor(const MWWorld::Ptr& door) diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 4c4df2c99..20d6bf9a1 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -524,7 +524,7 @@ namespace MWWorld virtual void reattachPlayerCamera(); /// \todo this does not belong here - virtual void screenshot (Ogre::Image& image, int w, int h); + virtual void screenshot (osg::Image* image, int w, int h); /// Find center of exterior cell above land surface /// \return false if exterior with given name not exists, true otherwise From e642f20a65972f7e6bb9900816f42e54a41390e3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Jun 2015 17:25:18 +0200 Subject: [PATCH 1391/3725] Restore screenshot key functionality --- apps/openmw/engine.cpp | 73 +++++++++++++++++++------- apps/openmw/engine.hpp | 6 +++ components/sdlutil/sdlinputwrapper.cpp | 2 + 3 files changed, 63 insertions(+), 18 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index fed1f134b..a37d84621 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -7,6 +7,7 @@ #include #include +#include #include @@ -532,6 +533,54 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) } } +class WriteScreenshotToFileOperation : public osgViewer::ScreenCaptureHandler::CaptureOperation +{ +public: + WriteScreenshotToFileOperation(const std::string& screenshotPath, const std::string& screenshotFormat) + : mScreenshotPath(screenshotPath) + , mScreenshotFormat(screenshotFormat) + { + } + + virtual void operator()(const osg::Image& image, const unsigned int context_id) + { + // Count screenshots. + int shotCount = 0; + + // Find the first unused filename with a do-while + std::ostringstream stream; + do + { + // Reset the stream + stream.str(""); + stream.clear(); + + stream << mScreenshotPath << "/screenshot" << std::setw(3) << std::setfill('0') << shotCount++ << "." << mScreenshotFormat; + + } while (boost::filesystem::exists(stream.str())); + + boost::filesystem::ofstream outStream; + outStream.open(boost::filesystem::path(stream.str()), std::ios::binary); + + osgDB::ReaderWriter* readerwriter = osgDB::Registry::instance()->getReaderWriterForExtension(mScreenshotFormat); + if (!readerwriter) + { + std::cerr << "Can't write screenshot, no '" << mScreenshotFormat << "' readerwriter found" << std::endl; + return; + } + + osgDB::ReaderWriter::WriteResult result = readerwriter->writeImage(image, outStream); + if (!result.success()) + { + std::cerr << "Can't write screenshot: " << result.message() << std::endl; + } + } + +private: + std::string mScreenshotPath; + std::string mScreenshotFormat; +}; + // Initialise and enter main loop. void OMW::Engine::go() @@ -557,6 +606,10 @@ void OMW::Engine::go() settingspath = loadSettings (settings); + mScreenCaptureHandler = new osgViewer::ScreenCaptureHandler(new WriteScreenshotToFileOperation(mCfgMgr.getUserDataPath().string(), + Settings::Manager::getString("screenshot format", "General"))); + mViewer->addEventHandler(mScreenCaptureHandler); + // Create encoder ToUTF8::Utf8Encoder encoder (mEncoding); mEncoder = &encoder; @@ -639,24 +692,8 @@ void OMW::Engine::activate() void OMW::Engine::screenshot() { - // Count screenshots. - int shotCount = 0; - - const std::string& screenshotPath = mCfgMgr.getUserDataPath().string(); - std::string format = Settings::Manager::getString("screenshot format", "General"); - // Find the first unused filename with a do-while - std::ostringstream stream; - do - { - // Reset the stream - stream.str(""); - stream.clear(); - - stream << screenshotPath << "screenshot" << std::setw(3) << std::setfill('0') << shotCount++ << "." << format; - - } while (boost::filesystem::exists(stream.str())); - - //mOgre->screenshot(stream.str(), format); + mScreenCaptureHandler->setFramesToCapture(1); + mScreenCaptureHandler->captureNextFrame(*mViewer); } void OMW::Engine::setCompileAll (bool all) diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index 8b792c5a8..8ac6098b8 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -53,6 +53,11 @@ namespace Files struct ConfigurationManager; } +namespace osgViewer +{ + class ScreenCaptureHandler; +} + struct SDL_Window; namespace OMW @@ -70,6 +75,7 @@ namespace OMW std::vector mArchives; boost::filesystem::path mResDir; osg::ref_ptr mViewer; + osg::ref_ptr mScreenCaptureHandler; std::string mCellName; std::vector mContentFiles; bool mVerboseScripts; diff --git a/components/sdlutil/sdlinputwrapper.cpp b/components/sdlutil/sdlinputwrapper.cpp index a9209bf58..f607b7046 100644 --- a/components/sdlutil/sdlinputwrapper.cpp +++ b/components/sdlutil/sdlinputwrapper.cpp @@ -41,6 +41,8 @@ InputWrapper::InputWrapper(SDL_Window* window, osg::ref_ptr v void InputWrapper::capture(bool windowEventsOnly) { + mViewer->getEventQueue()->frame(0.f); + SDL_PumpEvents(); SDL_Event evt; From bd0233ce68a14d9d191149f382145c36e785adf2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Jun 2015 18:00:34 +0200 Subject: [PATCH 1392/3725] Error handling improvement --- components/resource/texturemanager.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/components/resource/texturemanager.cpp b/components/resource/texturemanager.cpp index 5f2ca19ef..50cfd9d57 100644 --- a/components/resource/texturemanager.cpp +++ b/components/resource/texturemanager.cpp @@ -107,6 +107,12 @@ namespace Resource if (extPos != std::string::npos && extPos+1 < normalized.size()) ext = normalized.substr(extPos+1); osgDB::ReaderWriter* reader = osgDB::Registry::instance()->getReaderWriterForExtension(ext); + if (!reader) + { + std::cerr << "Error loading " << filename << ": no readerwriter for '" << ext << "' found" << std::endl; + return mWarningTexture; + } + osgDB::ReaderWriter::ReadResult result = reader->readImage(*stream, opts); if (!result.success()) { From dd23981eabb35fb7e119be042d80d82f161f87c4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Jun 2015 18:00:45 +0200 Subject: [PATCH 1393/3725] Font workaround for older MyGUI versions, works with 3.2.2 now --- components/fontloader/fontloader.cpp | 30 ++++++++++++------- .../myguiplatform/myguirendermanager.cpp | 8 +++-- 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/components/fontloader/fontloader.cpp b/components/fontloader/fontloader.cpp index 7635c43da..131336683 100644 --- a/components/fontloader/fontloader.cpp +++ b/components/fontloader/fontloader.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include @@ -275,18 +276,13 @@ namespace Gui std::string textureName = name; - osg::ref_ptr image = new osg::Image; - - image->allocateImage(width, height, 1, GL_RGBA, GL_UNSIGNED_BYTE); - assert (image->isDataContiguous()); - - memcpy(image->data(), &textureData[0], textureData.size()); - - osg::ref_ptr texture = new osg::Texture2D; - texture->setImage(image); - if (exportToFile) { + osg::ref_ptr image = new osg::Image; + image->allocateImage(width, height, 1, GL_RGBA, GL_UNSIGNED_BYTE); + assert (image->isDataContiguous()); + memcpy(image->data(), &textureData[0], textureData.size()); + std::cout << "Writing " << resourceName + ".png" << std::endl; osgDB::writeImageFile(*image, resourceName + ".png"); } @@ -295,9 +291,23 @@ namespace Gui MyGUI::ResourceManualFont* font = static_cast( MyGUI::FactoryManager::getInstance().createObject("Resource", "ResourceManualFont")); mFonts.push_back(font); + + MyGUI::ITexture* tex = MyGUI::RenderManager::getInstance().createTexture(bitmapFilename); + tex->createManual(width, height, MyGUI::TextureUsage::Write, MyGUI::PixelFormat::R8G8B8A8); + unsigned char* texData = reinterpret_cast(tex->lock(MyGUI::TextureUsage::Write)); + memcpy(texData, &textureData[0], textureData.size()); + tex->unlock(); + + font->setSource(bitmapFilename); + + // Using ResourceManualFont::setTexture, enable for MyGUI 3.2.3 + /* + osg::ref_ptr texture = new osg::Texture2D; + texture->setImage(image); osgMyGUI::OSGTexture* myguiTex = new osgMyGUI::OSGTexture(texture); mTextures.push_back(myguiTex); font->setTexture(myguiTex); + */ // We need to emulate loading from XML because the data members are private as of mygui 3.2.0 MyGUI::xml::Document xmlDocument; diff --git a/components/myguiplatform/myguirendermanager.cpp b/components/myguiplatform/myguirendermanager.cpp index bf1d66fe8..e00b0221d 100644 --- a/components/myguiplatform/myguirendermanager.cpp +++ b/components/myguiplatform/myguirendermanager.cpp @@ -453,8 +453,12 @@ bool RenderManager::isFormatSupported(MyGUI::PixelFormat /*format*/, MyGUI::Text MyGUI::ITexture* RenderManager::createTexture(const std::string &name) { - MapTexture::const_iterator item = mTextures.find(name); - MYGUI_PLATFORM_ASSERT(item == mTextures.end(), "Texture '"<second; + mTextures.erase(item); + } OSGTexture* texture = new OSGTexture(name, mTextureManager); mTextures.insert(std::make_pair(name, texture)); From 1ba3fa4169b55641d57c4fc17d4704a8e64d71ce Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Jun 2015 18:11:34 +0200 Subject: [PATCH 1394/3725] Remove leftovers of the old OpenCS navigation --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/view/render/lightingday.hpp | 5 - apps/opencs/view/render/lightingnight.hpp | 5 - apps/opencs/view/render/navigation.cpp | 24 ----- apps/opencs/view/render/navigation.hpp | 47 --------- apps/opencs/view/render/navigation1st.cpp | 86 ---------------- apps/opencs/view/render/navigation1st.hpp | 35 ------- apps/opencs/view/render/navigationfree.cpp | 66 ------------ apps/opencs/view/render/navigationfree.hpp | 35 ------- apps/opencs/view/render/navigationorbit.cpp | 100 ------------------- apps/opencs/view/render/navigationorbit.hpp | 42 -------- apps/opencs/view/render/previewwidget.hpp | 2 - apps/opencs/view/render/scenewidget.cpp | 1 - apps/opencs/view/render/scenewidget.hpp | 1 - apps/opencs/view/render/worldspacewidget.hpp | 6 -- 15 files changed, 1 insertion(+), 456 deletions(-) delete mode 100644 apps/opencs/view/render/navigation.cpp delete mode 100644 apps/opencs/view/render/navigation.hpp delete mode 100644 apps/opencs/view/render/navigation1st.cpp delete mode 100644 apps/opencs/view/render/navigation1st.hpp delete mode 100644 apps/opencs/view/render/navigationfree.cpp delete mode 100644 apps/opencs/view/render/navigationfree.hpp delete mode 100644 apps/opencs/view/render/navigationorbit.cpp delete mode 100644 apps/opencs/view/render/navigationorbit.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 6fec6f194..7c539fb14 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -82,7 +82,7 @@ opencs_units (view/render ) opencs_units_noqt (view/render - navigation navigation1st navigationfree navigationorbit lighting lightingday lightingnight + lighting lightingday lightingnight lightingbright object cell terrainstorage ) diff --git a/apps/opencs/view/render/lightingday.hpp b/apps/opencs/view/render/lightingday.hpp index 407933ec6..2dc3c02b6 100644 --- a/apps/opencs/view/render/lightingday.hpp +++ b/apps/opencs/view/render/lightingday.hpp @@ -3,11 +3,6 @@ #include "lighting.hpp" -namespace Ogre -{ - class Light; -} - namespace CSVRender { class LightingDay : public Lighting diff --git a/apps/opencs/view/render/lightingnight.hpp b/apps/opencs/view/render/lightingnight.hpp index 8743cc438..dae2a8fa3 100644 --- a/apps/opencs/view/render/lightingnight.hpp +++ b/apps/opencs/view/render/lightingnight.hpp @@ -3,11 +3,6 @@ #include "lighting.hpp" -namespace Ogre -{ - class Light; -} - namespace CSVRender { class LightingNight : public Lighting diff --git a/apps/opencs/view/render/navigation.cpp b/apps/opencs/view/render/navigation.cpp deleted file mode 100644 index 705759104..000000000 --- a/apps/opencs/view/render/navigation.cpp +++ /dev/null @@ -1,24 +0,0 @@ - -#include "navigation.hpp" - -float CSVRender::Navigation::getFactor (bool mouse) const -{ - float factor = mFastModeFactor; - - if (mouse) - factor /= 2; /// \todo make this configurable - - return factor; -} - -CSVRender::Navigation::Navigation() - : mFastModeFactor(1) -{ -} - -CSVRender::Navigation::~Navigation() {} - -void CSVRender::Navigation::setFastModeFactor (float factor) -{ - mFastModeFactor = factor; -} diff --git a/apps/opencs/view/render/navigation.hpp b/apps/opencs/view/render/navigation.hpp deleted file mode 100644 index ead8f3e13..000000000 --- a/apps/opencs/view/render/navigation.hpp +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef OPENCS_VIEW_NAVIGATION_H -#define OPENCS_VIEW_NAVIGATION_H - -class QPoint; - -namespace Ogre -{ - class Camera; -} - -namespace CSVRender -{ - class Navigation - { - float mFastModeFactor; - - protected: - - float getFactor (bool mouse) const; - - public: - - Navigation(); - virtual ~Navigation(); - - void setFastModeFactor (float factor); - ///< Set currently applying fast mode factor. - - virtual bool activate (Ogre::Camera *camera) = 0; - ///< \return Update required? - - virtual bool wheelMoved (int delta) = 0; - ///< \return Update required? - - virtual bool mouseMoved (const QPoint& delta, int mode) = 0; - ///< \param mode: 0: default mouse key, 1: default mouse key and modifier key 1 - /// \return Update required? - - virtual bool handleMovementKeys (int vertical, int horizontal) = 0; - ///< \return Update required? - - virtual bool handleRollKeys (int delta) = 0; - ///< \return Update required? - }; -} - -#endif diff --git a/apps/opencs/view/render/navigation1st.cpp b/apps/opencs/view/render/navigation1st.cpp deleted file mode 100644 index 5d9a03468..000000000 --- a/apps/opencs/view/render/navigation1st.cpp +++ /dev/null @@ -1,86 +0,0 @@ - -#include "navigation1st.hpp" - -#include - -#include - -CSVRender::Navigation1st::Navigation1st() : mCamera (0) {} - -bool CSVRender::Navigation1st::activate (Ogre::Camera *camera) -{ - mCamera = camera; - mCamera->setFixedYawAxis (true, Ogre::Vector3::UNIT_Z); - - Ogre::Radian pitch = mCamera->getOrientation().getPitch(); - - Ogre::Radian limit (Ogre::Math::PI/2-0.5); - - if (pitch>limit) - mCamera->pitch (-(pitch-limit)); - else if (pitch<-limit) - mCamera->pitch (pitch-limit); - - return true; -} - -bool CSVRender::Navigation1st::wheelMoved (int delta) -{ - mCamera->move (getFactor (true) * mCamera->getDirection() * delta); - return true; -} - -bool CSVRender::Navigation1st::mouseMoved (const QPoint& delta, int mode) -{ - if (mode==0) - { - // turn camera - if (delta.x()) - mCamera->yaw (Ogre::Degree (getFactor (true) * delta.x())); - - if (delta.y()) - { - Ogre::Radian oldPitch = mCamera->getOrientation().getPitch(); - float deltaPitch = getFactor (true) * delta.y(); - Ogre::Radian newPitch = oldPitch + Ogre::Degree (deltaPitch); - - if ((deltaPitch>0 && newPitchOgre::Radian(0.5))) - { - mCamera->pitch (Ogre::Degree (deltaPitch)); - } - } - - return true; - } - else if (mode==1) - { - // pan camera - if (delta.x()) - mCamera->move (getFactor (true) * mCamera->getDerivedRight() * delta.x()); - - if (delta.y()) - mCamera->move (getFactor (true) * -mCamera->getDerivedUp() * delta.y()); - - return true; - } - - return false; -} - -bool CSVRender::Navigation1st::handleMovementKeys (int vertical, int horizontal) -{ - if (vertical) - mCamera->move (getFactor (false) * mCamera->getDirection() * vertical); - - if (horizontal) - mCamera->move (getFactor (true) * mCamera->getDerivedRight() * horizontal); - - return true; -} - -bool CSVRender::Navigation1st::handleRollKeys (int delta) -{ - // we don't roll this way in 1st person mode - return false; -} diff --git a/apps/opencs/view/render/navigation1st.hpp b/apps/opencs/view/render/navigation1st.hpp deleted file mode 100644 index d1e09d236..000000000 --- a/apps/opencs/view/render/navigation1st.hpp +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef OPENCS_VIEW_NAVIGATION1ST_H -#define OPENCS_VIEW_NAVIGATION1ST_H - -#include "navigation.hpp" - -namespace CSVRender -{ - /// \brief First person-like camera controls - class Navigation1st : public Navigation - { - Ogre::Camera *mCamera; - - public: - - Navigation1st(); - - virtual bool activate (Ogre::Camera *camera); - ///< \return Update required? - - virtual bool wheelMoved (int delta); - ///< \return Update required? - - virtual bool mouseMoved (const QPoint& delta, int mode); - ///< \param mode: 0: default mouse key, 1: default mouse key and modifier key 1 - /// \return Update required? - - virtual bool handleMovementKeys (int vertical, int horizontal); - ///< \return Update required? - - virtual bool handleRollKeys (int delta); - ///< \return Update required? - }; -} - -#endif diff --git a/apps/opencs/view/render/navigationfree.cpp b/apps/opencs/view/render/navigationfree.cpp deleted file mode 100644 index 950e137a7..000000000 --- a/apps/opencs/view/render/navigationfree.cpp +++ /dev/null @@ -1,66 +0,0 @@ - -#include "navigationfree.hpp" - -#include - -#include - -CSVRender::NavigationFree::NavigationFree() : mCamera (0) {} - -bool CSVRender::NavigationFree::activate (Ogre::Camera *camera) -{ - mCamera = camera; - mCamera->setFixedYawAxis (false); - return false; -} - -bool CSVRender::NavigationFree::wheelMoved (int delta) -{ - mCamera->move (getFactor (true) * mCamera->getDirection() * delta); - return true; -} - -bool CSVRender::NavigationFree::mouseMoved (const QPoint& delta, int mode) -{ - if (mode==0) - { - // turn camera - if (delta.x()) - mCamera->yaw (Ogre::Degree (getFactor (true) * delta.x())); - - if (delta.y()) - mCamera->pitch (Ogre::Degree (getFactor (true) * delta.y())); - - return true; - } - else if (mode==1) - { - // pan camera - if (delta.x()) - mCamera->move (getFactor (true) * mCamera->getDerivedRight() * delta.x()); - - if (delta.y()) - mCamera->move (getFactor (true) * -mCamera->getDerivedUp() * delta.y()); - - return true; - } - - return false; -} - -bool CSVRender::NavigationFree::handleMovementKeys (int vertical, int horizontal) -{ - if (vertical) - mCamera->move (getFactor (false) * mCamera->getDerivedUp() * vertical); - - if (horizontal) - mCamera->move (getFactor (true) * mCamera->getDerivedRight() * horizontal); - - return true; -} - -bool CSVRender::NavigationFree::handleRollKeys (int delta) -{ - mCamera->roll (Ogre::Degree (getFactor (false) * delta)); - return true; -} diff --git a/apps/opencs/view/render/navigationfree.hpp b/apps/opencs/view/render/navigationfree.hpp deleted file mode 100644 index e30722f75..000000000 --- a/apps/opencs/view/render/navigationfree.hpp +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef OPENCS_VIEW_NAVIGATIONFREE_H -#define OPENCS_VIEW_NAVIGATIONFREE_H - -#include "navigation.hpp" - -namespace CSVRender -{ - /// \brief Free camera controls - class NavigationFree : public Navigation - { - Ogre::Camera *mCamera; - - public: - - NavigationFree(); - - virtual bool activate (Ogre::Camera *camera); - ///< \return Update required? - - virtual bool wheelMoved (int delta); - ///< \return Update required? - - virtual bool mouseMoved (const QPoint& delta, int mode); - ///< \param mode: 0: default mouse key, 1: default mouse key and modifier key 1 - /// \return Update required? - - virtual bool handleMovementKeys (int vertical, int horizontal); - ///< \return Update required? - - virtual bool handleRollKeys (int delta); - ///< \return Update required? - }; -} - -#endif diff --git a/apps/opencs/view/render/navigationorbit.cpp b/apps/opencs/view/render/navigationorbit.cpp deleted file mode 100644 index c5f3eda96..000000000 --- a/apps/opencs/view/render/navigationorbit.cpp +++ /dev/null @@ -1,100 +0,0 @@ - -#include "navigationorbit.hpp" - -#include - -#include - -void CSVRender::NavigationOrbit::rotateCamera (const Ogre::Vector3& diff) -{ - Ogre::Vector3 pos = mCamera->getPosition(); - - float distance = (pos-mCentre).length(); - - Ogre::Vector3 direction = (pos+diff)-mCentre; - direction.normalise(); - - mCamera->setPosition (mCentre + direction*distance); - mCamera->lookAt (mCentre); -} - -CSVRender::NavigationOrbit::NavigationOrbit() : mCamera (0), mCentre (0, 0, 0), mDistance (100) -{} - -bool CSVRender::NavigationOrbit::activate (Ogre::Camera *camera) -{ - mCamera = camera; - mCamera->setFixedYawAxis (false); - - if ((mCamera->getPosition()-mCentre).length()getPosition(); - direction.normalise(); - - if (direction.length()==0) - direction = Ogre::Vector3 (1, 0, 0); - - mCamera->setPosition (mCentre - direction * mDistance); - } - - mCamera->lookAt (mCentre); - - return true; -} - -bool CSVRender::NavigationOrbit::wheelMoved (int delta) -{ - Ogre::Vector3 diff = getFactor (true) * mCamera->getDirection() * delta; - - Ogre::Vector3 pos = mCamera->getPosition(); - - if (delta>0 && diff.length()>=(pos-mCentre).length()-mDistance) - { - pos = mCentre-(mCamera->getDirection() * mDistance); - } - else - { - pos += diff; - } - - mCamera->setPosition (pos); - - return true; -} - -bool CSVRender::NavigationOrbit::mouseMoved (const QPoint& delta, int mode) -{ - Ogre::Vector3 diff = - getFactor (true) * -mCamera->getDerivedRight() * delta.x() - + getFactor (true) * mCamera->getDerivedUp() * delta.y(); - - if (mode==0) - { - rotateCamera (diff); - return true; - } - else if (mode==1) - { - mCamera->move (diff); - mCentre += diff; - return true; - } - - return false; -} - -bool CSVRender::NavigationOrbit::handleMovementKeys (int vertical, int horizontal) -{ - rotateCamera ( - - getFactor (false) * -mCamera->getDerivedRight() * horizontal - + getFactor (false) * mCamera->getDerivedUp() * vertical); - - return true; -} - -bool CSVRender::NavigationOrbit::handleRollKeys (int delta) -{ - mCamera->roll (Ogre::Degree (getFactor (false) * delta)); - return true; -} diff --git a/apps/opencs/view/render/navigationorbit.hpp b/apps/opencs/view/render/navigationorbit.hpp deleted file mode 100644 index 7796eb9e7..000000000 --- a/apps/opencs/view/render/navigationorbit.hpp +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef OPENCS_VIEW_NAVIGATIONORBIT_H -#define OPENCS_VIEW_NAVIGATIONORBIT_H - -#include "navigation.hpp" - -#include - -namespace CSVRender -{ - /// \brief Orbiting camera controls - class NavigationOrbit : public Navigation - { - Ogre::Camera *mCamera; - Ogre::Vector3 mCentre; - int mDistance; - - void rotateCamera (const Ogre::Vector3& diff); - ///< Rotate camera around centre. - - public: - - NavigationOrbit(); - - virtual bool activate (Ogre::Camera *camera); - ///< \return Update required? - - virtual bool wheelMoved (int delta); - ///< \return Update required? - - virtual bool mouseMoved (const QPoint& delta, int mode); - ///< \param mode: 0: default mouse key, 1: default mouse key and modifier key 1 - /// \return Update required? - - virtual bool handleMovementKeys (int vertical, int horizontal); - ///< \return Update required? - - virtual bool handleRollKeys (int delta); - ///< \return Update required? - }; -} - -#endif diff --git a/apps/opencs/view/render/previewwidget.hpp b/apps/opencs/view/render/previewwidget.hpp index 58a7d8552..73f7dc810 100644 --- a/apps/opencs/view/render/previewwidget.hpp +++ b/apps/opencs/view/render/previewwidget.hpp @@ -3,7 +3,6 @@ #include "scenewidget.hpp" -#include "navigationorbit.hpp" #include "object.hpp" class QModelIndex; @@ -25,7 +24,6 @@ namespace CSVRender Q_OBJECT CSMWorld::Data& mData; - CSVRender::NavigationOrbit mOrbit; CSVRender::Object mObject; public: diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index a9c9a8c6b..6136abb40 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -17,7 +17,6 @@ #include "../widget/scenetoolmode.hpp" #include "../../model/settings/usersettings.hpp" -#include "navigation.hpp" #include "lighting.hpp" namespace CSVRender diff --git a/apps/opencs/view/render/scenewidget.hpp b/apps/opencs/view/render/scenewidget.hpp index acfc0bbd4..58c376418 100644 --- a/apps/opencs/view/render/scenewidget.hpp +++ b/apps/opencs/view/render/scenewidget.hpp @@ -29,7 +29,6 @@ namespace CSVWidget namespace CSVRender { - class Navigation; class Lighting; class RenderWidget : public QWidget diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp index e935daae2..fe4555820 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -5,9 +5,6 @@ #include "scenewidget.hpp" -#include "navigation1st.hpp" -#include "navigationfree.hpp" -#include "navigationorbit.hpp" #include #include @@ -30,9 +27,6 @@ namespace CSVRender { Q_OBJECT - CSVRender::Navigation1st m1st; - CSVRender::NavigationFree mFree; - CSVRender::NavigationOrbit mOrbit; CSVWidget::SceneToolToggle2 *mSceneElements; CSVWidget::SceneToolRun *mRun; CSMDoc::Document& mDocument; From 4f0387bdb5fa6ed40fa4b0231750984c7e134651 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Jun 2015 18:34:47 +0200 Subject: [PATCH 1395/3725] Fix for recent merge --- cmake/FindMyGUI.cmake | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/cmake/FindMyGUI.cmake b/cmake/FindMyGUI.cmake index e883a29c1..eccfb54ed 100644 --- a/cmake/FindMyGUI.cmake +++ b/cmake/FindMyGUI.cmake @@ -25,38 +25,21 @@ IF (WIN32) #Windows IF(MINGW) FIND_PATH ( MYGUI_INCLUDE_DIRS MyGUI.h PATH_SUFFIXES MYGUI) - FIND_PATH ( MYGUI_PLATFORM_INCLUDE_DIRS MyGUI_OgrePlatform.h PATH_SUFFIXES MYGUI) FIND_LIBRARY ( MYGUI_LIBRARIES_REL NAMES libMyGUIEngine${CMAKE_SHARED_LIBRARY_SUFFIX} - libMyGUI.OgrePlatform${CMAKE_STATIC_LIBRARY_SUFFIX} HINTS ${MYGUI_LIB_DIR} PATH_SUFFIXES "" release relwithdebinfo minsizerel ) FIND_LIBRARY ( MYGUI_LIBRARIES_DBG NAMES libMyGUIEngine_d${CMAKE_SHARED_LIBRARY_SUFFIX} - libMyGUI.OgrePlatform_d${CMAKE_STATIC_LIBRARY_SUFFIX} - HINTS - ${MYGUI_LIB_DIR} - PATH_SUFFIXES "" debug ) - - FIND_LIBRARY ( MYGUI_PLATFORM_LIBRARIES_REL NAMES - libMyGUI.OgrePlatform${CMAKE_STATIC_LIBRARY_SUFFIX} - HINTS - ${MYGUI_LIB_DIR} - PATH_SUFFIXES "" release relwithdebinfo minsizerel ) - - FIND_LIBRARY ( MYGUI_PLATFORM_LIBRARIES_DBG NAMES - MyGUI.OgrePlatform_d${CMAKE_STATIC_LIBRARY_SUFFIX} HINTS ${MYGUI_LIB_DIR} PATH_SUFFIXES "" debug ) make_library_set ( MYGUI_LIBRARIES ) - make_library_set ( MYGUI_PLATFORM_LIBRARIES ) MESSAGE ("${MYGUI_LIBRARIES}") - MESSAGE ("${MYGUI_PLATFORM_LIBRARIES}") ENDIF(MINGW) SET(MYGUISDK $ENV{MYGUI_HOME}) From 0cc9b1bb40c17d9bf4517905436cecf21b1e7139 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Jun 2015 18:49:52 +0200 Subject: [PATCH 1396/3725] Remove dependency on OgrePlatform.h --- apps/openmw/main.cpp | 27 +++++++++++++-------------- components/files/lowlevelfile.hpp | 6 ++---- 2 files changed, 15 insertions(+), 18 deletions(-) diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 901d9ad42..dc58daed9 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -12,8 +12,6 @@ #include #include -#include - #if defined(_WIN32) // For OutputDebugString #define WIN32_LEAN_AND_MEAN @@ -23,17 +21,18 @@ #endif -#if OGRE_PLATFORM == OGRE_PLATFORM_LINUX || OGRE_PLATFORM == OGRE_PLATFORM_APPLE +#if (defined(__APPLE__) || defined(__linux) || defined(__unix) || defined(__posix)) + #define USE_CRASH_CATCHER 1 +#else + #define USE_CRASH_CATCHER 0 +#endif + +#if USE_CRASH_CATCHER #include extern int cc_install_handlers(int argc, char **argv, int num_signals, int *sigs, const char *logfile, int (*user_info)(char*, char*)); extern int is_debugger_attached(void); #endif -// for Ogre::macBundlePath -#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE -#include -#endif - #include /** * Workaround for problems with whitespaces in paths in older versions of Boost library @@ -364,7 +363,7 @@ int main(int argc, char**argv) #endif -#if OGRE_PLATFORM == OGRE_PLATFORM_LINUX || OGRE_PLATFORM == OGRE_PLATFORM_APPLE +#if USE_CRASH_CATCHER // Unix crash catcher if ((argc == 2 && strcmp(argv[1], "--cc-handle-crash") == 0) || !is_debugger_attached()) { @@ -376,10 +375,10 @@ int main(int argc, char**argv) std::cout << "Running in a debugger, not installing crash catcher" << std::endl; #endif -#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE - // set current dir to bundle path - boost::filesystem::path bundlePath = boost::filesystem::path(Ogre::macBundlePath()).parent_path(); - boost::filesystem::current_path(bundlePath); +#ifdef __APPLE__ + // FIXME: set current dir to bundle path + //boost::filesystem::path bundlePath = boost::filesystem::path(Ogre::macBundlePath()).parent_path(); + //boost::filesystem::current_path(bundlePath); #endif engine.reset(new OMW::Engine(cfgMgr)); @@ -391,7 +390,7 @@ int main(int argc, char**argv) } catch (std::exception &e) { -#if OGRE_PLATFORM == OGRE_PLATFORM_LINUX || OGRE_PLATFORM == OGRE_PLATFORM_APPLE +#if (defined(__APPLE__) || defined(__linux) || defined(__unix) || defined(__posix)) if (!isatty(fileno(stdin))) #endif SDL_ShowSimpleMessageBox(0, "OpenMW: Fatal error", e.what(), NULL); diff --git a/components/files/lowlevelfile.hpp b/components/files/lowlevelfile.hpp index d94238ad6..b2634d8c7 100644 --- a/components/files/lowlevelfile.hpp +++ b/components/files/lowlevelfile.hpp @@ -1,17 +1,15 @@ #ifndef COMPONENTS_FILES_LOWLEVELFILE_HPP #define COMPONENTS_FILES_LOWLEVELFILE_HPP -#include - #include #define FILE_API_STDIO 0 #define FILE_API_POSIX 1 #define FILE_API_WIN32 2 -#if OGRE_PLATFORM == OGRE_PLATFORM_LINUX +#if defined(__linux) || defined(__unix) || defined(__posix) #define FILE_API FILE_API_POSIX -#elif OGRE_PLATFORM == OGRE_PLATFORM_WIN32 +#elif defined(_WIN32) #define FILE_API FILE_API_WIN32 #else #define FILE_API FILE_API_STDIO From 7bacb9418de53838d5d453094921a04a190b9a37 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Jun 2015 19:41:19 +0200 Subject: [PATCH 1397/3725] Various math code ported to osg --- apps/openmw/mwbase/world.hpp | 12 +--- apps/openmw/mwclass/creature.cpp | 4 +- apps/openmw/mwclass/creature.hpp | 2 +- apps/openmw/mwclass/npc.cpp | 4 +- apps/openmw/mwclass/npc.hpp | 2 +- apps/openmw/mwgui/hud.cpp | 2 +- apps/openmw/mwgui/travelwindow.cpp | 3 +- apps/openmw/mwgui/windowmanagerimp.cpp | 4 +- apps/openmw/mwmechanics/actors.cpp | 8 +-- apps/openmw/mwmechanics/aiavoiddoor.cpp | 2 +- apps/openmw/mwmechanics/aicombat.cpp | 91 ++++++++++++++----------- apps/openmw/mwmechanics/aifollow.cpp | 4 +- apps/openmw/mwmechanics/aipackage.cpp | 4 +- apps/openmw/mwmechanics/aisequence.cpp | 6 +- apps/openmw/mwmechanics/aitravel.cpp | 10 +-- apps/openmw/mwmechanics/aiwander.cpp | 58 ++++++++-------- apps/openmw/mwmechanics/aiwander.hpp | 6 +- apps/openmw/mwmechanics/character.cpp | 16 ++--- apps/openmw/mwmechanics/pathfinding.cpp | 14 ++-- apps/openmw/mwmechanics/pathfinding.hpp | 7 ++ apps/openmw/mwmechanics/steering.cpp | 28 ++++---- apps/openmw/mwmechanics/steering.hpp | 12 ++-- apps/openmw/mwworld/class.cpp | 4 +- apps/openmw/mwworld/class.hpp | 2 +- apps/openmw/mwworld/player.cpp | 12 ++-- apps/openmw/mwworld/player.hpp | 7 +- apps/openmw/mwworld/worldimp.cpp | 27 ++++---- apps/openmw/mwworld/worldimp.hpp | 6 +- 28 files changed, 180 insertions(+), 177 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index bb48afc9d..95553de76 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -11,14 +11,6 @@ #include "../mwrender/rendermode.hpp" -namespace Ogre -{ - class Vector2; - class Vector3; - class Quaternion; - class Image; -} - namespace osg { class Vec3f; @@ -423,7 +415,7 @@ namespace MWBase virtual bool getLOS(const MWWorld::Ptr& actor,const MWWorld::Ptr& targetActor) = 0; ///< get Line of Sight (morrowind stupid implementation) - virtual float getDistToNearestRayHit(const Ogre::Vector3& from, const Ogre::Vector3& dir, float maxDist) = 0; + virtual float getDistToNearestRayHit(const osg::Vec3f& from, const osg::Vec3f& dir, float maxDist) = 0; virtual void enableActorCollision(const MWWorld::Ptr& actor, bool enable) = 0; @@ -497,7 +489,7 @@ namespace MWBase // Are we in an exterior or pseudo-exterior cell and it's night? virtual bool isDark() const = 0; - virtual bool findInteriorPositionInWorldSpace(MWWorld::CellStore* cell, Ogre::Vector3& result) = 0; + virtual bool findInteriorPositionInWorldSpace(MWWorld::CellStore* cell, osg::Vec3f& result) = 0; /// Teleports \a ptr to the closest reference of \a id (e.g. DivineMarker, PrisonMarker, TempleMarker) /// @note id must be lower case diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index ea67884d3..c88691515 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -580,10 +580,10 @@ namespace MWClass return dynamic_cast (*ptr.getRefData().getCustomData()).mMovement; } - Ogre::Vector3 Creature::getRotationVector (const MWWorld::Ptr& ptr) const + osg::Vec3f Creature::getRotationVector (const MWWorld::Ptr& ptr) const { MWMechanics::Movement &movement = getMovementSettings(ptr); - Ogre::Vector3 vec(movement.mRotation); + osg::Vec3f vec(movement.mRotation[0], movement.mRotation[1], movement.mRotation[2]); movement.mRotation[0] = 0.0f; movement.mRotation[1] = 0.0f; movement.mRotation[2] = 0.0f; diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index f5a2402f3..93ef3959c 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -113,7 +113,7 @@ namespace MWClass virtual MWMechanics::Movement& getMovementSettings (const MWWorld::Ptr& ptr) const; ///< Return desired movement. - virtual Ogre::Vector3 getRotationVector (const MWWorld::Ptr& ptr) const; + virtual osg::Vec3f getRotationVector (const MWWorld::Ptr& ptr) const; ///< Return desired rotations, as euler angles. float getSpeed (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 4307fe9be..c9de1f6ff 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -961,10 +961,10 @@ namespace MWClass return dynamic_cast (*ptr.getRefData().getCustomData()).mMovement; } - Ogre::Vector3 Npc::getRotationVector (const MWWorld::Ptr& ptr) const + osg::Vec3f Npc::getRotationVector (const MWWorld::Ptr& ptr) const { MWMechanics::Movement &movement = getMovementSettings(ptr); - Ogre::Vector3 vec(movement.mRotation); + osg::Vec3f vec(movement.mRotation[0], movement.mRotation[1], movement.mRotation[2]); movement.mRotation[0] = 0.0f; movement.mRotation[1] = 0.0f; movement.mRotation[2] = 0.0f; diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index f72a9bb2c..b786286f7 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -105,7 +105,7 @@ namespace MWClass virtual MWMechanics::Movement& getMovementSettings (const MWWorld::Ptr& ptr) const; ///< Return desired movement. - virtual Ogre::Vector3 getRotationVector (const MWWorld::Ptr& ptr) const; + virtual osg::Vec3f getRotationVector (const MWWorld::Ptr& ptr) const; ///< Return desired rotations, as euler angles. virtual float getCapacity (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 0fab66a25..44f944c3b 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -394,7 +394,7 @@ namespace MWGui } if (mIsDrowning) - mDrowningFlashTheta += dt * Ogre::Math::TWO_PI; + mDrowningFlashTheta += dt * osg::PI*2; } void HUD::setSelectedSpell(const std::string& spellId, int successChancePercent) diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index ba6fc2a78..7985e7eda 100644 --- a/apps/openmw/mwgui/travelwindow.cpp +++ b/apps/openmw/mwgui/travelwindow.cpp @@ -169,8 +169,7 @@ namespace MWGui if (!interior) { ESM::Position playerPos = player.getRefData().getPosition(); - float d = Ogre::Vector3(pos.pos[0], pos.pos[1], 0).distance( - Ogre::Vector3(playerPos.pos[0], playerPos.pos[1], 0)); + float d = (osg::Vec3f(pos.pos[0], pos.pos[1], 0) - osg::Vec3f(playerPos.pos[0], playerPos.pos[1], 0)).length(); int hours = static_cast(d /MWBase::Environment::get().getWorld()->getStore().get().find("fTravelTimeMult")->getFloat()); for(int i = 0;i < hours;i++) { diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 1182de151..1ae5cabed 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -992,12 +992,12 @@ namespace MWGui mMap->setCellPrefix (cell->getCell()->mName ); mHud->setCellPrefix (cell->getCell()->mName ); - Ogre::Vector3 worldPos; + osg::Vec3f worldPos; if (!MWBase::Environment::get().getWorld()->findInteriorPositionInWorldSpace(cell, worldPos)) worldPos = MWBase::Environment::get().getWorld()->getPlayer().getLastKnownExteriorPosition(); else MWBase::Environment::get().getWorld()->getPlayer().setLastKnownExteriorPosition(worldPos); - mMap->setGlobalMapPlayerPosition(worldPos.x, worldPos.y); + mMap->setGlobalMapPlayerPosition(worldPos.x(), worldPos.y()); } } diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 81dbca58a..03ab3d020 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -316,7 +316,7 @@ namespace MWMechanics const ESM::Position& actor1Pos = actor1.getRefData().getPosition(); const ESM::Position& actor2Pos = actor2.getRefData().getPosition(); - float sqrDist = Ogre::Vector3(actor1Pos.pos).squaredDistance(Ogre::Vector3(actor2Pos.pos)); + float sqrDist = (actor1Pos.asVec3() - actor2Pos.asVec3()).length2(); if (sqrDist > 7168*7168) return; @@ -1081,7 +1081,7 @@ namespace MWMechanics // AI and magic effects update for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter) { - bool inProcessingRange = Ogre::Vector3(player.getRefData().getPosition().pos).squaredDistance(Ogre::Vector3(iter->first.getRefData().getPosition().pos)) + bool inProcessingRange = (player.getRefData().getPosition().asVec3() - iter->first.getRefData().getPosition().asVec3()).length2() <= sqrProcessingDistance; iter->second->getCharacterController()->setActive(inProcessingRange); @@ -1151,7 +1151,7 @@ namespace MWMechanics for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter) { if (iter->first != player && - Ogre::Vector3(player.getRefData().getPosition().pos).squaredDistance(Ogre::Vector3(iter->first.getRefData().getPosition().pos)) + (player.getRefData().getPosition().asVec3() - iter->first.getRefData().getPosition().asVec3()).length2() > sqrProcessingDistance) continue; @@ -1236,7 +1236,7 @@ namespace MWMechanics continue; // is the player in range and can they be detected - if (Ogre::Vector3(iter->first.getRefData().getPosition().pos).squaredDistance(Ogre::Vector3(player.getRefData().getPosition().pos)) <= radius*radius + if ((iter->first.getRefData().getPosition().asVec3() - player.getRefData().getPosition().asVec3()).length2() <= radius*radius && MWBase::Environment::get().getWorld()->getLOS(player, iter->first)) { if (MWBase::Environment::get().getMechanicsManager()->awarenessCheck(player, iter->first)) diff --git a/apps/openmw/mwmechanics/aiavoiddoor.cpp b/apps/openmw/mwmechanics/aiavoiddoor.cpp index 83f9dffb4..9d32aa97b 100644 --- a/apps/openmw/mwmechanics/aiavoiddoor.cpp +++ b/apps/openmw/mwmechanics/aiavoiddoor.cpp @@ -56,7 +56,7 @@ bool MWMechanics::AiAvoidDoor::execute (const MWWorld::Ptr& actor, AiState& stat actor.getClass().getCreatureStats(actor).setMovementFlag(CreatureStats::Flag_Run, true); // Turn away from the door and move when turn completed - if (zTurn(actor, Ogre::Radian(std::atan2(x,y) + mAdjAngle), Ogre::Degree(5))) + if (zTurn(actor, std::atan2(x,y) + mAdjAngle, osg::DegreesToRadians(5.f))) actor.getClass().getMovementSettings(actor).mPosition[1] = 1; else actor.getClass().getMovementSettings(actor).mPosition[1] = 0; diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 36ff927d8..495aaf82b 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -35,18 +35,18 @@ namespace void getMinMaxAttackDuration(const MWWorld::Ptr& actor, float (*fMinMaxDurations)[2]); - Ogre::Vector3 AimDirToMovingTarget(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, const Ogre::Vector3& vLastTargetPos, + osg::Vec3f AimDirToMovingTarget(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, const osg::Vec3f& vLastTargetPos, float duration, int weapType, float strength); - float getZAngleToDir(const Ogre::Vector3& dir) + float getZAngleToDir(const osg::Vec3f& dir) { - return Ogre::Math::ATan2(dir.x,dir.y).valueDegrees(); + return osg::RadiansToDegrees(std::atan2(dir.x(), dir.y())); } - float getXAngleToDir(const Ogre::Vector3& dir, float dirLen = 0.0f) + float getXAngleToDir(const osg::Vec3f& dir, float dirLen = 0.0f) { float len = (dirLen > 0.0f)? dirLen : dir.length(); - return -Ogre::Math::ASin(dir.z / len).valueDegrees(); + return osg::RadiansToDegrees(-std::asin(dir.z() / len)); } @@ -58,20 +58,20 @@ namespace // cast up-down ray with some offset from actor position to check for pits/obstacles on the way to target; // magnitude of pits/obstacles is defined by PATHFIND_Z_REACH - bool checkWayIsClear(const Ogre::Vector3& from, const Ogre::Vector3& to, float offsetXY) + bool checkWayIsClear(const osg::Vec3f& from, const osg::Vec3f& to, float offsetXY) { - if((to - from).length() >= PATHFIND_CAUTION_DIST || std::abs(from.z - to.z) <= PATHFIND_Z_REACH) + if((to - from).length() >= PATHFIND_CAUTION_DIST || std::abs(from.z() - to.z()) <= PATHFIND_Z_REACH) { - Ogre::Vector3 dir = to - from; - dir.z = 0; - dir.normalise(); + osg::Vec3f dir = to - from; + dir.z() = 0; + dir.normalize(); float verticalOffset = 200; // instead of '200' here we want the height of the actor - Ogre::Vector3 _from = from + dir*offsetXY + Ogre::Vector3::UNIT_Z * verticalOffset; + osg::Vec3f _from = from + dir*offsetXY + osg::Vec3f(0,0,1) * verticalOffset; // cast up-down ray and find height in world space of hit - float h = _from.z - MWBase::Environment::get().getWorld()->getDistToNearestRayHit(_from, -Ogre::Vector3::UNIT_Z, verticalOffset + PATHFIND_Z_REACH + 1); + float h = _from.z() - MWBase::Environment::get().getWorld()->getDistToNearestRayHit(_from, osg::Vec3f(0,0,-1), verticalOffset + PATHFIND_Z_REACH + 1); - if(std::abs(from.z - h) <= PATHFIND_Z_REACH) + if(std::abs(from.z() - h) <= PATHFIND_Z_REACH) return true; } @@ -95,7 +95,7 @@ namespace MWMechanics bool mAttack; bool mFollowTarget; bool mCombatMove; - Ogre::Vector3 mLastTargetPos; + osg::Vec3f mLastTargetPos; const MWWorld::CellStore* mCell; boost::shared_ptr mCurrentAction; float mActionCooldown; @@ -104,7 +104,7 @@ namespace MWMechanics bool mMinMaxAttackDurationInitialised; bool mForceNoShortcut; ESM::Position mShortcutFailPos; - Ogre::Vector3 mLastActorPos; + osg::Vec3f mLastActorPos; MWMechanics::Movement mMovement; AiCombatStorage(): @@ -231,12 +231,12 @@ namespace MWMechanics if(movement.mRotation[2] != 0) { - if(zTurn(actor, Ogre::Degree(movement.mRotation[2]))) movement.mRotation[2] = 0; + if(zTurn(actor, osg::DegreesToRadians(movement.mRotation[2]))) movement.mRotation[2] = 0; } if(movement.mRotation[0] != 0) { - if(smoothTurn(actor, Ogre::Degree(movement.mRotation[0]), 0)) movement.mRotation[0] = 0; + if(smoothTurn(actor, osg::DegreesToRadians(movement.mRotation[0]), 0)) movement.mRotation[0] = 0; } float attacksPeriod = 1.0f; @@ -450,12 +450,12 @@ namespace MWMechanics */ ESM::Position pos = actor.getRefData().getPosition(); - Ogre::Vector3 vActorPos(pos.pos); - Ogre::Vector3 vTargetPos(target.getRefData().getPosition().pos); - Ogre::Vector3 vDirToTarget = vTargetPos - vActorPos; + osg::Vec3f vActorPos(pos.asVec3()); + osg::Vec3f vTargetPos(target.getRefData().getPosition().asVec3()); + osg::Vec3f vDirToTarget = vTargetPos - vActorPos; float distToTarget = vDirToTarget.length(); - Ogre::Vector3& lastActorPos = storage.mLastActorPos; + osg::Vec3f& lastActorPos = storage.mLastActorPos; bool& followTarget = storage.mFollowTarget; bool isStuck = false; @@ -496,8 +496,8 @@ namespace MWMechanics // note: in getZAngleToDir if we preserve dir.z then horizontal angle can be inaccurate if (distantCombat) { - Ogre::Vector3& lastTargetPos = storage.mLastTargetPos; - Ogre::Vector3 vAimDir = AimDirToMovingTarget(actor, target, lastTargetPos, tReaction, weaptype, strength); + osg::Vec3f& lastTargetPos = storage.mLastTargetPos; + osg::Vec3f vAimDir = AimDirToMovingTarget(actor, target, lastTargetPos, tReaction, weaptype, strength); lastTargetPos = vTargetPos; movement.mRotation[0] = getXAngleToDir(vAimDir); movement.mRotation[2] = getZAngleToDir(vAimDir); @@ -553,12 +553,12 @@ namespace MWMechanics ESM::Position& shortcutFailPos = storage.mShortcutFailPos; if(inLOS && (!isStuck || readyToAttack) - && (!forceNoShortcut || (Ogre::Vector3(shortcutFailPos.pos) - vActorPos).length() >= PATHFIND_SHORTCUT_RETRY_DIST)) + && (!forceNoShortcut || (shortcutFailPos.asVec3() - vActorPos).length() >= PATHFIND_SHORTCUT_RETRY_DIST)) { if(speed == 0.0f) speed = actorClass.getSpeed(actor); // maximum dist before pit/obstacle for actor to avoid them depending on his speed - float maxAvoidDist = tReaction * speed + speed / MAX_VEL_ANGULAR.valueRadians() * 2; // *2 - for reliability - preferShortcut = checkWayIsClear(vActorPos, vTargetPos, Ogre::Vector3(vDirToTarget.x, vDirToTarget.y, 0).length() > maxAvoidDist*1.5? maxAvoidDist : maxAvoidDist/2); + float maxAvoidDist = tReaction * speed + speed / MAX_VEL_ANGULAR_RADIANS * 2; // *2 - for reliability + preferShortcut = checkWayIsClear(vActorPos, vTargetPos, osg::Vec3f(vDirToTarget.x(), vDirToTarget.y(), 0).length() > maxAvoidDist*1.5? maxAvoidDist : maxAvoidDist/2); } // don't use pathgrid when actor can move in 3 dimensions @@ -594,7 +594,7 @@ namespace MWMechanics // get point just before target std::list::const_iterator pntIter = --mPathFinder.getPath().end(); --pntIter; - Ogre::Vector3 vBeforeTarget(PathFinder::MakeOgreVector3(*pntIter)); + osg::Vec3f vBeforeTarget(PathFinder::MakeOsgVec3(*pntIter)); // if current actor pos is closer to target then last point of path (excluding target itself) then go straight on target if(distToTarget <= (vTargetPos - vBeforeTarget).length()) @@ -668,7 +668,7 @@ namespace MWMechanics actor.getClass().getMovementSettings(actor).mPosition[1] = 0.1f; // change the angle a bit, too if(mPathFinder.isPathConstructed()) - zTurn(actor, Ogre::Degree(mPathFinder.getZAngleToNext(pos.pos[0] + 1, pos.pos[1]))); + zTurn(actor, osg::DegreesToRadians(mPathFinder.getZAngleToNext(pos.pos[0] + 1, pos.pos[1]))); if(followTarget) followTarget = false; @@ -680,14 +680,14 @@ namespace MWMechanics void AiCombat::buildNewPath(const MWWorld::Ptr& actor, const MWWorld::Ptr& target) { - Ogre::Vector3 newPathTarget = Ogre::Vector3(target.getRefData().getPosition().pos); + osg::Vec3f newPathTarget = target.getRefData().getPosition().asVec3(); float dist; if(!mPathFinder.getPath().empty()) { ESM::Pathgrid::Point lastPt = mPathFinder.getPath().back(); - Ogre::Vector3 currPathTarget(PathFinder::MakeOgreVector3(lastPt)); + osg::Vec3f currPathTarget(PathFinder::MakeOsgVec3(lastPt)); dist = (newPathTarget - currPathTarget).length(); } else dist = 1e+38F; // necessarily construct a new path @@ -876,7 +876,7 @@ void getMinMaxAttackDuration(const MWWorld::Ptr& actor, float (*fMinMaxDurations } } -Ogre::Vector3 AimDirToMovingTarget(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, const Ogre::Vector3& vLastTargetPos, +osg::Vec3f AimDirToMovingTarget(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, const osg::Vec3f& vLastTargetPos, float duration, int weapType, float strength) { float projSpeed; @@ -905,28 +905,37 @@ Ogre::Vector3 AimDirToMovingTarget(const MWWorld::Ptr& actor, const MWWorld::Ptr // idea: perpendicular to dir to target speed components of target move vector and projectile vector should be the same - Ogre::Vector3 vActorPos = Ogre::Vector3(actor.getRefData().getPosition().pos); - Ogre::Vector3 vTargetPos = Ogre::Vector3(target.getRefData().getPosition().pos); - Ogre::Vector3 vDirToTarget = vTargetPos - vActorPos; + osg::Vec3f vActorPos = actor.getRefData().getPosition().asVec3(); + osg::Vec3f vTargetPos = target.getRefData().getPosition().asVec3(); + osg::Vec3f vDirToTarget = vTargetPos - vActorPos; float distToTarget = vDirToTarget.length(); - Ogre::Vector3 vTargetMoveDir = vTargetPos - vLastTargetPos; + osg::Vec3f vTargetMoveDir = vTargetPos - vLastTargetPos; vTargetMoveDir /= duration; // |vTargetMoveDir| is target real speed in units/sec now - Ogre::Vector3 vPerpToDir = vDirToTarget.crossProduct(Ogre::Vector3::UNIT_Z); + osg::Vec3f vPerpToDir = vDirToTarget ^ osg::Vec3f(0,0,1); // cross product - float velPerp = vTargetMoveDir.dotProduct(vPerpToDir.normalisedCopy()); - float velDir = vTargetMoveDir.dotProduct(vDirToTarget.normalisedCopy()); + vPerpToDir.normalize(); + osg::Vec3f vDirToTargetNormalized = vDirToTarget; + vDirToTargetNormalized.normalize(); + + // dot product + float velPerp = vTargetMoveDir * vPerpToDir; + float velDir = vTargetMoveDir * vDirToTargetNormalized; // time to collision between target and projectile float t_collision; float projVelDirSquared = projSpeed * projSpeed - velPerp * velPerp; - float projDistDiff = vDirToTarget.dotProduct(vTargetMoveDir.normalisedCopy()); - projDistDiff = sqrt(distToTarget * distToTarget - projDistDiff * projDistDiff); + + osg::Vec3f vTargetMoveDirNormalized = vTargetMoveDir; + vTargetMoveDirNormalized.normalize(); + + float projDistDiff = vDirToTarget * vTargetMoveDirNormalized; // dot product + projDistDiff = std::sqrt(distToTarget * distToTarget - projDistDiff * projDistDiff); if (projVelDirSquared > 0) - t_collision = projDistDiff / (sqrt(projVelDirSquared) - velDir); + t_collision = projDistDiff / (std::sqrt(projVelDirSquared) - velDir); else t_collision = 0; // speed of projectile is not enough to reach moving target return vTargetPos + vTargetMoveDir * t_collision - vActorPos; diff --git a/apps/openmw/mwmechanics/aifollow.cpp b/apps/openmw/mwmechanics/aifollow.cpp index ddfc14581..24a50cbd6 100644 --- a/apps/openmw/mwmechanics/aifollow.cpp +++ b/apps/openmw/mwmechanics/aifollow.cpp @@ -76,7 +76,7 @@ bool AiFollow::execute (const MWWorld::Ptr& actor, AiState& state, float duratio if (storage.mTimer < 0) { - if (Ogre::Vector3(actor.getRefData().getPosition().pos).squaredDistance(Ogre::Vector3(target.getRefData().getPosition().pos)) + if ((actor.getRefData().getPosition().asVec3() - target.getRefData().getPosition().asVec3()).length2() < 500*500 && MWBase::Environment::get().getWorld()->getLOS(actor, target)) mActive = true; @@ -137,7 +137,7 @@ bool AiFollow::execute (const MWWorld::Ptr& actor, AiState& state, float duratio // turn towards target anyway float directionX = target.getRefData().getPosition().pos[0] - actor.getRefData().getPosition().pos[0]; float directionY = target.getRefData().getPosition().pos[1] - actor.getRefData().getPosition().pos[1]; - zTurn(actor, Ogre::Math::ATan2(directionX,directionY), Ogre::Degree(5)); + zTurn(actor, std::atan2(directionX,directionY), osg::DegreesToRadians(5.f)); } else { diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index 52a975320..8db62dea8 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -106,7 +106,7 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, ESM::Pathgrid::Po actor.getClass().getMovementSettings(actor).mPosition[0] = 1; actor.getClass().getMovementSettings(actor).mPosition[1] = 1; // change the angle a bit, too - zTurn(actor, Ogre::Degree(mPathFinder.getZAngleToNext(pos.pos[0] + 1, pos.pos[1]))); + zTurn(actor, osg::DegreesToRadians(mPathFinder.getZAngleToNext(pos.pos[0] + 1, pos.pos[1]))); } } else { //Not stuck, so reset things @@ -119,7 +119,7 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, ESM::Pathgrid::Po actor.getClass().getMovementSettings(actor).mPosition[1] = 1; //Just run forward the rest of the time } - zTurn(actor, Ogre::Degree(mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]))); + zTurn(actor, osg::DegreesToRadians(mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]))); return false; } diff --git a/apps/openmw/mwmechanics/aisequence.cpp b/apps/openmw/mwmechanics/aisequence.cpp index bb078f883..0606e5146 100644 --- a/apps/openmw/mwmechanics/aisequence.cpp +++ b/apps/openmw/mwmechanics/aisequence.cpp @@ -165,7 +165,7 @@ void AiSequence::execute (const MWWorld::Ptr& actor, AiState& state,float durati std::list::iterator itActualCombat; float nearestDist = std::numeric_limits::max(); - Ogre::Vector3 vActorPos = Ogre::Vector3(actor.getRefData().getPosition().pos); + osg::Vec3f vActorPos = actor.getRefData().getPosition().asVec3(); for(std::list::iterator it = mPackages.begin(); it != mPackages.end();) { @@ -183,7 +183,7 @@ void AiSequence::execute (const MWWorld::Ptr& actor, AiState& state,float durati { const ESM::Position &targetPos = target.getRefData().getPosition(); - float distTo = (Ogre::Vector3(targetPos.pos) - vActorPos).length(); + float distTo = (targetPos.asVec3() - vActorPos).length(); if (distTo < nearestDist) { nearestDist = distTo; @@ -258,7 +258,7 @@ void AiSequence::stack (const AiPackage& package, const MWWorld::Ptr& actor) return; // already in combat with this actor } else if ((*iter)->getTypeId() == AiPackage::TypeIdWander) - static_cast(*iter)->setReturnPosition(Ogre::Vector3(actor.getRefData().getPosition().pos)); + static_cast(*iter)->setReturnPosition(actor.getRefData().getPosition().asVec3()); } } diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index 2824e2c6c..f9fddf575 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -17,12 +17,12 @@ namespace { -bool isWithinMaxRange(const Ogre::Vector3& pos1, const Ogre::Vector3& pos2) +bool isWithinMaxRange(const osg::Vec3f& pos1, const osg::Vec3f& pos2) { // Maximum travel distance for vanilla compatibility. // Was likely meant to prevent NPCs walking into non-loaded exterior cells, but for some reason is used in interior cells as well. // We can make this configurable at some point, but the default *must* be the below value. Anything else will break shoddily-written content (*cough* MW *cough*) in bizarre ways. - return (pos1.squaredDistance(pos2) <= 7168*7168); + return (pos1 - pos2).length2() <= 7168*7168; } } @@ -84,7 +84,7 @@ namespace MWMechanics } } - if (!isWithinMaxRange(Ogre::Vector3(mX, mY, mZ), Ogre::Vector3(pos.pos))) + if (!isWithinMaxRange(osg::Vec3f(mX, mY, mZ), pos.asVec3())) return false; bool cellChange = cell->mData.mX != mCellX || cell->mData.mY != mCellY; @@ -106,7 +106,7 @@ namespace MWMechanics return true; } - zTurn(actor, Ogre::Degree(mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]))); + zTurn(actor, osg::DegreesToRadians(mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]))); movement.mPosition[1] = 1; return false; @@ -119,7 +119,7 @@ namespace MWMechanics void AiTravel::fastForward(const MWWorld::Ptr& actor, AiState& state) { - if (!isWithinMaxRange(Ogre::Vector3(mX, mY, mZ), Ogre::Vector3(actor.getRefData().getPosition().pos))) + if (!isWithinMaxRange(osg::Vec3f(mX, mY, mZ), actor.getRefData().getPosition().asVec3())) return; // does not do any validation on the travel target (whether it's in air, inside collision geometry, etc), // that is the user's responsibility diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 6593bbf89..71508ac51 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -48,7 +48,7 @@ namespace MWMechanics { // the z rotation angle (degrees) we want to reach // used every frame when mRotate is true - Ogre::Radian mTargetAngle; + float mTargetAngleRadians; bool mRotate; float mReaction; // update some actions infrequently @@ -69,7 +69,7 @@ namespace MWMechanics PathFinder mPathFinder; AiWanderStorage(): - mTargetAngle(0), + mTargetAngleRadians(0), mRotate(false), mReaction(0), mSaidGreeting(AiWander::Greet_None), @@ -101,7 +101,7 @@ namespace MWMechanics mTrimCurrentNode = false; mHasReturnPosition = false; - mReturnPosition = Ogre::Vector3(0,0,0); + mReturnPosition = osg::Vec3f(0,0,0); if(mDistance < 0) mDistance = 0; @@ -231,7 +231,7 @@ namespace MWMechanics if(walking) // have not yet reached the destination { // turn towards the next point in mPath - zTurn(actor, Ogre::Degree(storage.mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]))); + zTurn(actor, osg::DegreesToRadians(storage.mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]))); actor.getClass().getMovementSettings(actor).mPosition[1] = 1; // Returns true if evasive action needs to be taken @@ -255,7 +255,7 @@ namespace MWMechanics actor.getClass().getMovementSettings(actor).mPosition[0] = 1; actor.getClass().getMovementSettings(actor).mPosition[1] = 0.1f; // change the angle a bit, too - zTurn(actor, Ogre::Degree(storage.mPathFinder.getZAngleToNext(pos.pos[0] + 1, pos.pos[1]))); + zTurn(actor, osg::DegreesToRadians(storage.mPathFinder.getZAngleToNext(pos.pos[0] + 1, pos.pos[1]))); } mStuckCount++; // TODO: maybe no longer needed } @@ -275,14 +275,14 @@ namespace MWMechanics } - Ogre::Radian& targetAngle = storage.mTargetAngle; + float& targetAngleRadians = storage.mTargetAngleRadians; bool& rotate = storage.mRotate; if (rotate) { // Reduce the turning animation glitch by using a *HUGE* value of // epsilon... TODO: a proper fix might be in either the physics or the // animation subsystem - if (zTurn(actor, targetAngle, Ogre::Degree(5))) + if (zTurn(actor, targetAngleRadians, osg::DegreesToRadians(5.f))) rotate = false; } @@ -340,7 +340,7 @@ namespace MWMechanics // Only say Idle voices when player is in LOS // A bit counterintuitive, likely vanilla did this to reduce the appearance of // voices going through walls? - if (roll < x && Ogre::Vector3(player.getRefData().getPosition().pos).squaredDistance(Ogre::Vector3(pos.pos)) + if (roll < x && (player.getRefData().getPosition().asVec3() - pos.asVec3()).length2() < 3000*3000 // maybe should be fAudioVoiceDefaultMaxDistance*fAudioMaxDistanceMult instead && MWBase::Environment::get().getWorld()->getLOS(player, actor)) MWBase::Environment::get().getDialogueManager()->say(actor, "idle"); @@ -400,7 +400,7 @@ namespace MWMechanics // For stationary NPCs, move back to the starting location if another AiPackage moved us elsewhere if (cellChange) mHasReturnPosition = false; - if (mDistance == 0 && mHasReturnPosition && Ogre::Vector3(pos.pos).squaredDistance(mReturnPosition) > 20*20) + if (mDistance == 0 && mHasReturnPosition && (pos.asVec3() - mReturnPosition).length2() > 20*20) { chooseAction = false; idleNow = false; @@ -435,9 +435,9 @@ namespace MWMechanics helloDistance *= iGreetDistanceMultiplier; MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); - Ogre::Vector3 playerPos(player.getRefData().getPosition().pos); - Ogre::Vector3 actorPos(actor.getRefData().getPosition().pos); - float playerDistSqr = playerPos.squaredDistance(actorPos); + osg::Vec3f playerPos(player.getRefData().getPosition().asVec3()); + osg::Vec3f actorPos(actor.getRefData().getPosition().asVec3()); + float playerDistSqr = (playerPos - actorPos).length2(); int& greetingTimer = storage.mGreetingTimer; if (greetingState == Greet_None) @@ -471,10 +471,10 @@ namespace MWMechanics if(!rotate) { - Ogre::Vector3 dir = playerPos - actorPos; + osg::Vec3f dir = playerPos - actorPos; - float faceAngleRadians = std::atan2(dir.x, dir.y); - targetAngle = faceAngleRadians; + float faceAngleRadians = std::atan2(dir.x(), dir.y()); + targetAngleRadians = faceAngleRadians; rotate = true; } @@ -501,10 +501,8 @@ namespace MWMechanics assert(mAllowedNodes.size()); unsigned int randNode = Misc::Rng::rollDice(mAllowedNodes.size()); // NOTE: initially constructed with local (i.e. cell) co-ordinates - Ogre::Vector3 destNodePos(PathFinder::MakeOgreVector3(mAllowedNodes[randNode])); - // convert dest to use world co-ordinates - ESM::Pathgrid::Point dest(PathFinder::MakePathgridPoint(destNodePos)); + ESM::Pathgrid::Point dest(mAllowedNodes[randNode]); if (currentCell->getCell()->isExterior()) { dest.mX += currentCell->getCell()->mData.mX * ESM::Land::REAL_SIZE; @@ -607,7 +605,7 @@ namespace MWMechanics } } - void AiWander::setReturnPosition(const Ogre::Vector3& position) + void AiWander::setReturnPosition(const osg::Vec3f& position) { if (!mHasReturnPosition) { @@ -652,8 +650,8 @@ namespace MWMechanics ESM::Pathgrid::Point dest = mAllowedNodes[index]; // apply a slight offset to prevent overcrowding - dest.mX += static_cast(Ogre::Math::RangeRandom(-64, 64)); - dest.mY += static_cast(Ogre::Math::RangeRandom(-64, 64)); + dest.mX += static_cast(Misc::Rng::rollProbability() * 128 - 64); + dest.mY += static_cast(Misc::Rng::rollProbability() * 128 - 64); if (actor.getCell()->isExterior()) { @@ -670,7 +668,7 @@ namespace MWMechanics { if (!mStoredInitialActorPosition) { - mInitialActorPosition = Ogre::Vector3(actor.getRefData().getPosition().pos); + mInitialActorPosition = actor.getRefData().getPosition().asVec3(); mStoredInitialActorPosition = true; } @@ -700,7 +698,7 @@ namespace MWMechanics } // convert npcPos to local (i.e. cell) co-ordinates - Ogre::Vector3 npcPos(mInitialActorPosition); + osg::Vec3f npcPos(mInitialActorPosition); npcPos[0] = npcPos[0] - cellXOffset; npcPos[1] = npcPos[1] - cellYOffset; @@ -708,19 +706,19 @@ namespace MWMechanics // NOTE: mPoints and mAllowedNodes are in local co-ordinates for(unsigned int counter = 0; counter < pathgrid->mPoints.size(); counter++) { - Ogre::Vector3 nodePos(PathFinder::MakeOgreVector3(pathgrid->mPoints[counter])); - if(npcPos.squaredDistance(nodePos) <= mDistance * mDistance) + osg::Vec3f nodePos(PathFinder::MakeOsgVec3(pathgrid->mPoints[counter])); + if((npcPos - nodePos).length2() <= mDistance * mDistance) mAllowedNodes.push_back(pathgrid->mPoints[counter]); } if(!mAllowedNodes.empty()) { - Ogre::Vector3 firstNodePos(PathFinder::MakeOgreVector3(mAllowedNodes[0])); - float closestNode = npcPos.squaredDistance(firstNodePos); + osg::Vec3f firstNodePos(PathFinder::MakeOsgVec3(mAllowedNodes[0])); + float closestNode = (npcPos - firstNodePos).length2(); unsigned int index = 0; for(unsigned int counterThree = 1; counterThree < mAllowedNodes.size(); counterThree++) { - Ogre::Vector3 nodePos(PathFinder::MakeOgreVector3(mAllowedNodes[counterThree])); - float tempDist = npcPos.squaredDistance(nodePos); + osg::Vec3f nodePos(PathFinder::MakeOsgVec3(mAllowedNodes[counterThree])); + float tempDist = (npcPos - nodePos).length2(); if(tempDist < closestNode) index = counterThree; } @@ -737,7 +735,7 @@ namespace MWMechanics std::vector nodeDistances; for (unsigned int counter = 0; counter < pathgrid->mPoints.size(); counter++) { - float distance = npcPos.squaredDistance(PathFinder::MakeOgreVector3(pathgrid->mPoints[counter])); + float distance = (npcPos - PathFinder::MakeOsgVec3(pathgrid->mPoints[counter])).length2(); nodeDistances.push_back(std::make_pair(distance, &pathgrid->mPoints.at(counter))); } std::sort(nodeDistances.begin(), nodeDistances.end(), sortByDistance); diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 7f8fc5088..b4eb3d21c 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -54,7 +54,7 @@ namespace MWMechanics /// Set the position to return to for a stationary (non-wandering) actor /** In case another AI package moved the actor elsewhere **/ - void setReturnPosition (const Ogre::Vector3& position); + void setReturnPosition (const osg::Vec3f& position); virtual void writeState(ESM::AiSequence::AiSequence &sequence) const; @@ -83,9 +83,9 @@ namespace MWMechanics bool mHasReturnPosition; // NOTE: Could be removed if mReturnPosition was initialized to actor position, // if we had the actor in the AiWander constructor... - Ogre::Vector3 mReturnPosition; + osg::Vec3f mReturnPosition; - Ogre::Vector3 mInitialActorPosition; + osg::Vec3f mInitialActorPosition; bool mStoredInitialActorPosition; diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 3843df132..f17f2331f 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1531,7 +1531,7 @@ void CharacterController::update(float duration) if(mHitState != CharState_None && mJumpState == JumpState_None) vec = osg::Vec3f(0.f, 0.f, 0.f); - Ogre::Vector3 rot = cls.getRotationVector(mPtr); + osg::Vec3f rot = cls.getRotationVector(mPtr); mMovementSpeed = cls.getSpeed(mPtr); @@ -1728,11 +1728,11 @@ void CharacterController::update(float duration) // Don't play turning animations during attack. It would break positioning of the arrow bone when releasing a shot. // Actually, in vanilla the turning animation is not even played when merely having equipped the weapon, // but I don't think we need to go as far as that. - else if(rot.z != 0.0f && !inwater && !sneak && mUpperBodyState < UpperCharState_StartToMinAttack) + else if(rot.z() != 0.0f && !inwater && !sneak && mUpperBodyState < UpperCharState_StartToMinAttack) { - if(rot.z > 0.0f) + if(rot.z() > 0.0f) movestate = CharState_TurnRight; - else if(rot.z < 0.0f) + else if(rot.z() < 0.0f) movestate = CharState_TurnLeft; } } @@ -1782,18 +1782,18 @@ void CharacterController::update(float duration) if (mMovementState == CharState_TurnLeft || mMovementState == CharState_TurnRight) { if (duration > 0) - mAnimation->adjustSpeedMult(mCurrentMovement, std::min(1.5f, std::abs(rot.z) / duration / Ogre::Math::PI)); + mAnimation->adjustSpeedMult(mCurrentMovement, std::min(1.5f, std::abs(rot.z()) / duration / Ogre::Math::PI)); } if (!mSkipAnim) { - rot *= Ogre::Math::RadiansToDegrees(1.0f); + rot *= osg::RadiansToDegrees(1.0f); if(mHitState != CharState_KnockDown && mHitState != CharState_KnockOut) { - world->rotateObject(mPtr, rot.x, rot.y, rot.z, true); + world->rotateObject(mPtr, rot.x(), rot.y(), rot.z(), true); } else //avoid z-rotating for knockdown - world->rotateObject(mPtr, rot.x, rot.y, 0.0f, true); + world->rotateObject(mPtr, rot.x(), rot.y(), 0.0f, true); if (!mMovementAnimationControlled) world->queueMovement(mPtr, vec); diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index 5795f818a..d338cf01a 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -15,9 +15,9 @@ namespace // Caller needs to be careful for very short distances (i.e. less than 1) // or when accumuating the results i.e. (a + b)^2 != a^2 + b^2 // - float distanceSquared(ESM::Pathgrid::Point point, Ogre::Vector3 pos) + float distanceSquared(ESM::Pathgrid::Point point, const osg::Vec3f& pos) { - return MWMechanics::PathFinder::MakeOgreVector3(point).squaredDistance(pos); + return (MWMechanics::PathFinder::MakeOsgVec3(point) - pos).length2(); } // Return the closest pathgrid point index from the specified position co @@ -26,7 +26,7 @@ namespace // // NOTE: pos is expected to be in local co-ordinates, as is grid->mPoints // - int getClosestPoint(const ESM::Pathgrid* grid, Ogre::Vector3 pos) + int getClosestPoint(const ESM::Pathgrid* grid, const osg::Vec3f& pos) { if(!grid || grid->mPoints.empty()) return -1; @@ -52,7 +52,7 @@ namespace // Chooses a reachable end pathgrid point. start is assumed reachable. std::pair getClosestReachablePoint(const ESM::Pathgrid* grid, const MWWorld::CellStore *cell, - Ogre::Vector3 pos, int start) + const osg::Vec3f pos, int start) { if(!grid || grid->mPoints.empty()) return std::pair (-1, false); @@ -216,12 +216,12 @@ namespace MWMechanics // point right behind the wall that is closer than any pathgrid // point outside the wall int startNode = getClosestPoint(mPathgrid, - Ogre::Vector3(startPoint.mX - xCell, startPoint.mY - yCell, static_cast(startPoint.mZ))); + osg::Vec3f(startPoint.mX - xCell, startPoint.mY - yCell, static_cast(startPoint.mZ))); // Some cells don't have any pathgrids at all if(startNode != -1) { std::pair endNode = getClosestReachablePoint(mPathgrid, cell, - Ogre::Vector3(endPoint.mX - xCell, endPoint.mY - yCell, static_cast(endPoint.mZ)), + osg::Vec3f(endPoint.mX - xCell, endPoint.mY - yCell, static_cast(endPoint.mZ)), startNode); // this shouldn't really happen, but just in case @@ -279,7 +279,7 @@ namespace MWMechanics float directionX = nextPoint.mX - x; float directionY = nextPoint.mY - y; - return Ogre::Math::ATan2(directionX,directionY).valueDegrees(); + return osg::RadiansToDegrees(std::atan2(directionX, directionY)); } bool PathFinder::checkPathCompleted(float x, float y, float tolerance) diff --git a/apps/openmw/mwmechanics/pathfinding.hpp b/apps/openmw/mwmechanics/pathfinding.hpp index 0f4d42775..8386de70f 100644 --- a/apps/openmw/mwmechanics/pathfinding.hpp +++ b/apps/openmw/mwmechanics/pathfinding.hpp @@ -44,6 +44,7 @@ namespace MWMechanics bool checkPathCompleted(float x, float y, float tolerance=32.f); ///< \Returns true if we are within \a tolerance units of the last path point. + /// In degrees float getZAngleToNext(float x, float y) const; bool isPathConstructed() const @@ -82,6 +83,12 @@ namespace MWMechanics return ESM::Pathgrid::Point(static_cast(v[0]), static_cast(v[1]), static_cast(v[2])); } + /// utility function to convert a osg::Vec3f to a Pathgrid::Point + static ESM::Pathgrid::Point MakePathgridPoint(const osg::Vec3f& v) + { + return ESM::Pathgrid::Point(static_cast(v[0]), static_cast(v[1]), static_cast(v[2])); + } + /// utility function to convert an ESM::Position to a Pathgrid::Point static ESM::Pathgrid::Point MakePathgridPoint(const ESM::Position& p) { diff --git a/apps/openmw/mwmechanics/steering.cpp b/apps/openmw/mwmechanics/steering.cpp index 9f887f5ca..219a23655 100644 --- a/apps/openmw/mwmechanics/steering.cpp +++ b/apps/openmw/mwmechanics/steering.cpp @@ -10,37 +10,37 @@ namespace MWMechanics { -bool smoothTurn(const MWWorld::Ptr& actor, Ogre::Radian targetAngle, int axis, Ogre::Degree epsilon) +bool smoothTurn(const MWWorld::Ptr& actor, float targetAngleRadians, int axis, float epsilonRadians) { - Ogre::Radian currentAngle (actor.getRefData().getPosition().rot[axis]); - Ogre::Radian diff (targetAngle - currentAngle); - if (diff >= Ogre::Degree(180)) + float currentAngle (actor.getRefData().getPosition().rot[axis]); + float diff (targetAngleRadians - currentAngle); + if (diff >= osg::DegreesToRadians(180.f)) { // Turning the other way would be a better idea - diff = diff-Ogre::Degree(360); + diff = diff-osg::DegreesToRadians(360.f); } - else if (diff <= Ogre::Degree(-180)) + else if (diff <= osg::DegreesToRadians(-180.f)) { - diff = Ogre::Degree(360)-diff; + diff = osg::DegreesToRadians(360.f)-diff; } - Ogre::Radian absDiff = Ogre::Math::Abs(diff); + float absDiff = std::abs(diff); // The turning animation actually moves you slightly, so the angle will be wrong again. // Use epsilon to prevent jerkiness. - if (absDiff < epsilon) + if (absDiff < epsilonRadians) return true; - Ogre::Radian limit = MAX_VEL_ANGULAR * MWBase::Environment::get().getFrameDuration(); + float limit = MAX_VEL_ANGULAR_RADIANS * MWBase::Environment::get().getFrameDuration(); if (absDiff > limit) - diff = Ogre::Math::Sign(diff) * limit; + diff = osg::sign(diff) * limit; - actor.getClass().getMovementSettings(actor).mRotation[axis] = diff.valueRadians(); + actor.getClass().getMovementSettings(actor).mRotation[axis] = diff; return false; } -bool zTurn(const MWWorld::Ptr& actor, Ogre::Radian targetAngle, Ogre::Degree epsilon) +bool zTurn(const MWWorld::Ptr& actor, float targetAngleRadians, float epsilonRadians) { - return smoothTurn(actor, targetAngle, 2, epsilon); + return smoothTurn(actor, targetAngleRadians, 2, epsilonRadians); } } diff --git a/apps/openmw/mwmechanics/steering.hpp b/apps/openmw/mwmechanics/steering.hpp index 91df49f0d..4b29dc1d9 100644 --- a/apps/openmw/mwmechanics/steering.hpp +++ b/apps/openmw/mwmechanics/steering.hpp @@ -1,6 +1,6 @@ #ifndef OPENMW_MECHANICS_STEERING_H -#include +#include namespace MWWorld { @@ -11,15 +11,15 @@ namespace MWMechanics { // Max rotating speed, radian/sec -const Ogre::Radian MAX_VEL_ANGULAR(10); +const float MAX_VEL_ANGULAR_RADIANS(10); /// configure rotation settings for an actor to reach this target angle (eventually) /// @return have we reached the target angle? -bool zTurn(const MWWorld::Ptr& actor, Ogre::Radian targetAngle, - Ogre::Degree epsilon = Ogre::Degree(0.5)); +bool zTurn(const MWWorld::Ptr& actor, float targetAngleRadians, + float epsilonRadians = osg::DegreesToRadians(0.5)); -bool smoothTurn(const MWWorld::Ptr& actor, Ogre::Radian targetAngle, int axis, - Ogre::Degree epsilon = Ogre::Degree(0.5)); +bool smoothTurn(const MWWorld::Ptr& actor, float targetAngleRadians, int axis, + float epsilonRadians = osg::DegreesToRadians(0.5)); } diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 5999979de..b757b1c91 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -186,9 +186,9 @@ namespace MWWorld throw std::runtime_error ("movement settings not supported by class"); } - Ogre::Vector3 Class::getRotationVector (const Ptr& ptr) const + osg::Vec3f Class::getRotationVector (const Ptr& ptr) const { - return Ogre::Vector3 (0, 0, 0); + return osg::Vec3f (0, 0, 0); } std::pair, bool> Class::getEquipmentSlots (const Ptr& ptr) const diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 02afd8960..935718348 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -192,7 +192,7 @@ namespace MWWorld virtual MWMechanics::Movement& getMovementSettings (const Ptr& ptr) const; ///< Return desired movement. - virtual Ogre::Vector3 getRotationVector (const Ptr& ptr) const; + virtual osg::Vec3f getRotationVector (const Ptr& ptr) const; ///< Return desired rotations, as euler angles. virtual std::pair, bool> getEquipmentSlots (const Ptr& ptr) const; diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index 09f6de072..a612ff80b 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -206,9 +206,9 @@ namespace MWWorld player.mBirthsign = mSign; - player.mLastKnownExteriorPosition[0] = mLastKnownExteriorPosition.x; - player.mLastKnownExteriorPosition[1] = mLastKnownExteriorPosition.y; - player.mLastKnownExteriorPosition[2] = mLastKnownExteriorPosition.z; + player.mLastKnownExteriorPosition[0] = mLastKnownExteriorPosition.x(); + player.mLastKnownExteriorPosition[1] = mLastKnownExteriorPosition.y(); + player.mLastKnownExteriorPosition[2] = mLastKnownExteriorPosition.z(); if (mMarkedCell) { @@ -279,9 +279,9 @@ namespace MWWorld mSign = player.mBirthsign; - mLastKnownExteriorPosition.x = player.mLastKnownExteriorPosition[0]; - mLastKnownExteriorPosition.y = player.mLastKnownExteriorPosition[1]; - mLastKnownExteriorPosition.z = player.mLastKnownExteriorPosition[2]; + mLastKnownExteriorPosition.x() = player.mLastKnownExteriorPosition[0]; + mLastKnownExteriorPosition.y() = player.mLastKnownExteriorPosition[1]; + mLastKnownExteriorPosition.z() = player.mLastKnownExteriorPosition[2]; if (player.mHasMark && !player.mMarkedCell.mPaged) { diff --git a/apps/openmw/mwworld/player.hpp b/apps/openmw/mwworld/player.hpp index 25d8981cd..8d29163e6 100644 --- a/apps/openmw/mwworld/player.hpp +++ b/apps/openmw/mwworld/player.hpp @@ -37,7 +37,7 @@ namespace MWWorld MWWorld::CellStore *mCellStore; std::string mSign; - Ogre::Vector3 mLastKnownExteriorPosition; + osg::Vec3f mLastKnownExteriorPosition; ESM::Position mMarkedPosition; // If no position was marked, this is NULL @@ -61,9 +61,8 @@ namespace MWWorld /// Interiors can not always be mapped to a world position. However /// world position is still required for divine / almsivi magic effects /// and the player arrow on the global map. - /// TODO: This should be stored in the savegame, too. - void setLastKnownExteriorPosition (const Ogre::Vector3& position) { mLastKnownExteriorPosition = position; } - Ogre::Vector3 getLastKnownExteriorPosition() const { return mLastKnownExteriorPosition; } + void setLastKnownExteriorPosition (const osg::Vec3f& position) { mLastKnownExteriorPosition = position; } + osg::Vec3f getLastKnownExteriorPosition() const { return mLastKnownExteriorPosition; } void set (const ESM::NPC *player); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 7bc46c078..a5f15da8e 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1585,7 +1585,7 @@ namespace MWWorld if (player.getCell()->isExterior()) { ESM::Position pos = player.getRefData().getPosition(); - mPlayer->setLastKnownExteriorPosition(Ogre::Vector3(pos.pos)); + mPlayer->setLastKnownExteriorPosition(pos.asVec3()); } if (player.getClass().getNpcStats(player).isWerewolf()) @@ -2324,20 +2324,19 @@ namespace MWWorld return mPhysics->getLineOfSight(actor, targetActor); } - float World::getDistToNearestRayHit(const Ogre::Vector3& from, const Ogre::Vector3& dir, float maxDist) + float World::getDistToNearestRayHit(const osg::Vec3f& from, const osg::Vec3f& dir, float maxDist) { - osg::Vec3f from_ (from.x, from.y, from.z); - osg::Vec3f to_ (dir.x, dir.y, dir.z); - to_.normalize(); - to_ = from_ + (to_ * maxDist); + osg::Vec3f to (dir); + to.normalize(); + to = from + (to * maxDist); - MWPhysics::PhysicsSystem::RayResult result = mPhysics->castRay(from_, to_, MWWorld::Ptr(), + MWPhysics::PhysicsSystem::RayResult result = mPhysics->castRay(from, to, MWWorld::Ptr(), MWPhysics::CollisionType_World|MWPhysics::CollisionType_HeightMap); if (!result.mHit) return maxDist; else - return (result.mHitPos - from_).length(); + return (result.mHitPos - from).length(); } void World::enableActorCollision(const MWWorld::Ptr& actor, bool enable) @@ -2731,7 +2730,7 @@ namespace MWWorld } } - bool World::findInteriorPositionInWorldSpace(MWWorld::CellStore* cell, Ogre::Vector3& result) + bool World::findInteriorPositionInWorldSpace(MWWorld::CellStore* cell, osg::Vec3f& result) { if (cell->isExterior()) return false; @@ -2762,7 +2761,7 @@ namespace MWWorld if (ref.mRef.getDestCell().empty()) { ESM::Position pos = ref.mRef.getDoorDest(); - result = Ogre::Vector3(pos.pos); + result = pos.asVec3(); return true; } else @@ -2822,7 +2821,7 @@ namespace MWWorld if (ref.mRef.getDestCell().empty()) { - Ogre::Vector3 worldPos = Ogre::Vector3(ref.mRef.getDoorDest().pos); + osg::Vec3f worldPos = ref.mRef.getDoorDest().asVec3(); return getClosestMarkerFromExteriorPosition(worldPos, id); } else @@ -2838,7 +2837,7 @@ namespace MWWorld return MWWorld::Ptr(); } - MWWorld::Ptr World::getClosestMarkerFromExteriorPosition( const Ogre::Vector3 worldPos, const std::string &id ) { + MWWorld::Ptr World::getClosestMarkerFromExteriorPosition( const osg::Vec3f& worldPos, const std::string &id ) { MWWorld::Ptr closestMarker; float closestDistance = FLT_MAX; @@ -2847,8 +2846,8 @@ namespace MWWorld for (std::vector::iterator it2 = markers.begin(); it2 != markers.end(); ++it2) { ESM::Position pos = it2->getRefData().getPosition(); - Ogre::Vector3 markerPos = Ogre::Vector3(pos.pos); - float distance = worldPos.squaredDistance(markerPos); + osg::Vec3f markerPos = pos.asVec3(); + float distance = (worldPos - markerPos).length2(); if (distance < closestDistance) { closestDistance = distance; diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 20d6bf9a1..c70a102c3 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -156,7 +156,7 @@ namespace MWWorld float feetToGameUnits(float feet); MWWorld::Ptr getClosestMarker( const MWWorld::Ptr &ptr, const std::string &id ); - MWWorld::Ptr getClosestMarkerFromExteriorPosition( const Ogre::Vector3 worldPos, const std::string &id ); + MWWorld::Ptr getClosestMarkerFromExteriorPosition( const osg::Vec3f& worldPos, const std::string &id ); public: @@ -508,7 +508,7 @@ namespace MWWorld virtual bool getLOS(const MWWorld::Ptr& actor,const MWWorld::Ptr& targetActor); ///< get Line of Sight (morrowind stupid implementation) - virtual float getDistToNearestRayHit(const Ogre::Vector3& from, const Ogre::Vector3& dir, float maxDist); + virtual float getDistToNearestRayHit(const osg::Vec3f& from, const osg::Vec3f& dir, float maxDist); virtual void enableActorCollision(const MWWorld::Ptr& actor, bool enable); @@ -583,7 +583,7 @@ namespace MWWorld // Are we in an exterior or pseudo-exterior cell and it's night? virtual bool isDark() const; - virtual bool findInteriorPositionInWorldSpace(MWWorld::CellStore* cell, Ogre::Vector3& result); + virtual bool findInteriorPositionInWorldSpace(MWWorld::CellStore* cell, osg::Vec3f& result); /// Teleports \a ptr to the closest reference of \a id (e.g. DivineMarker, PrisonMarker, TempleMarker) /// @note id must be lower case From cc6d5a3ba0ee906db10d4482a7ae7b8e94a80a08 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Jun 2015 19:44:21 +0200 Subject: [PATCH 1398/3725] Fix player setup bug --- apps/openmw/mwworld/worldimp.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index a5f15da8e..1ac92cf16 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2092,6 +2092,7 @@ namespace MWWorld scaleObject(getPlayerPtr(), 1.f); // apply race height MWBase::Environment::get().getMechanicsManager()->add(getPlayerPtr()); + MWBase::Environment::get().getMechanicsManager()->watchActor(getPlayerPtr()); std::string model = getPlayerPtr().getClass().getModel(getPlayerPtr()); model = Misc::ResourceHelpers::correctActorModelPath(model, mResourceSystem->getVFS()); From 2eec0caca0abae3a94cc3a83a9ac9943a5c4e306 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Jun 2015 19:59:54 +0200 Subject: [PATCH 1399/3725] Remove dependency on Ogre::StringConverter --- apps/openmw/mwmechanics/character.cpp | 25 +++++++++--- components/settings/settings.cpp | 57 +++++++++++++++++++++++---- 2 files changed, 70 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index f17f2331f..c5282bdf8 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -56,6 +56,13 @@ void wrap(float& rad) rad = std::fmod(rad-osg::PI, 2.0f*osg::PI)+osg::PI; } +std::string toString(int num) +{ + std::ostringstream stream; + stream << num; + return stream.str(); +} + std::string getBestAttack (const ESM::Weapon* weapon) { int slash = (weapon->mData.mSlash[0] + weapon->mData.mSlash[1])/2; @@ -220,13 +227,13 @@ public: std::string CharacterController::chooseRandomGroup (const std::string& prefix, int* num) { int numAnims=0; - while (mAnimation->hasAnimation(prefix + Ogre::StringConverter::toString(numAnims+1))) + while (mAnimation->hasAnimation(prefix + toString(numAnims+1))) ++numAnims; int roll = Misc::Rng::rollDice(numAnims) + 1; // [1, numAnims] if (num) *num = roll; - return prefix + Ogre::StringConverter::toString(roll); + return prefix + toString(roll); } void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterState movement, bool force) @@ -569,7 +576,7 @@ void CharacterController::playDeath(float startpoint, CharacterState death) mCurrentDeath = "deathknockout"; break; default: - mCurrentDeath = "death" + Ogre::StringConverter::toString(death - CharState_Death1 + 1); + mCurrentDeath = "death" + toString(death - CharState_Death1 + 1); } mDeathState = death; @@ -736,9 +743,17 @@ void CharacterController::handleTextKey(const std::string &groupname, const std: split(soundgen, ' ', tokens); soundgen = tokens[0]; if (tokens.size() >= 2) - volume = Ogre::StringConverter::parseReal(tokens[1]); + { + std::stringstream stream; + stream << tokens[1]; + stream >> volume; + } if (tokens.size() >= 3) - pitch = Ogre::StringConverter::parseReal(tokens[2]); + { + std::stringstream stream; + stream << tokens[2]; + stream >> pitch; + } } std::string sound = mPtr.getClass().getSoundIdFromSndGen(mPtr, soundgen); diff --git a/components/settings/settings.cpp b/components/settings/settings.cpp index a9a78d035..90fd300ec 100644 --- a/components/settings/settings.cpp +++ b/components/settings/settings.cpp @@ -1,13 +1,56 @@ #include "settings.hpp" #include +#include -#include +#include #include #include #include +namespace +{ + + bool parseBool(const std::string& string) + { + return (Misc::StringUtils::ciEqual(string, "true")); + } + + float parseFloat(const std::string& string) + { + std::stringstream stream; + stream << string; + float ret = 0.f; + stream >> ret; + return ret; + } + + int parseInt(const std::string& string) + { + std::stringstream stream; + stream << string; + int ret = 0; + stream >> ret; + return ret; + } + + template + std::string toString(T val) + { + std::ostringstream stream; + stream << val; + return stream.str(); + } + + template <> + std::string toString(bool val) + { + return val ? "true" : "false"; + } + +} + namespace Settings { @@ -143,17 +186,17 @@ std::string Manager::getString(const std::string &setting, const std::string &ca float Manager::getFloat (const std::string& setting, const std::string& category) { - return Ogre::StringConverter::parseReal( getString(setting, category) ); + return parseFloat( getString(setting, category) ); } int Manager::getInt (const std::string& setting, const std::string& category) { - return Ogre::StringConverter::parseInt( getString(setting, category) ); + return parseInt( getString(setting, category) ); } bool Manager::getBool (const std::string& setting, const std::string& category) { - return Ogre::StringConverter::parseBool( getString(setting, category) ); + return parseBool( getString(setting, category) ); } void Manager::setString(const std::string &setting, const std::string &category, const std::string &value) @@ -174,17 +217,17 @@ void Manager::setString(const std::string &setting, const std::string &category, void Manager::setInt (const std::string& setting, const std::string& category, const int value) { - setString(setting, category, Ogre::StringConverter::toString(value)); + setString(setting, category, toString(value)); } void Manager::setFloat (const std::string &setting, const std::string &category, const float value) { - setString(setting, category, Ogre::StringConverter::toString(value)); + setString(setting, category, toString(value)); } void Manager::setBool(const std::string &setting, const std::string &category, const bool value) { - setString(setting, category, Ogre::StringConverter::toString(value)); + setString(setting, category, toString(value)); } const CategorySettingVector Manager::apply() From 364b785e8f37a3c8c197c7ba0986b03d9b926178 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Jun 2015 21:36:46 +0200 Subject: [PATCH 1400/3725] ESSImporter image conversions port to osg::Image --- apps/essimporter/converter.cpp | 69 +++++++++++++++++++++++----------- apps/essimporter/converter.hpp | 5 ++- apps/essimporter/importer.cpp | 56 +++++++++++++++++++++------ 3 files changed, 95 insertions(+), 35 deletions(-) diff --git a/apps/essimporter/converter.cpp b/apps/essimporter/converter.cpp index 91d290f33..ec396761c 100644 --- a/apps/essimporter/converter.cpp +++ b/apps/essimporter/converter.cpp @@ -5,6 +5,8 @@ #include #include +#include + #include #include @@ -15,12 +17,14 @@ namespace { - void convertImage(char* data, int size, int width, int height, Ogre::PixelFormat pf, const std::string& out) + void convertImage(char* data, int size, int width, int height, GLenum pf, const std::string& out) { - Ogre::Image screenshot; - Ogre::DataStreamPtr stream (new Ogre::MemoryDataStream(data, size)); - screenshot.loadRawData(stream, width, height, 1, pf); - screenshot.save(out); + osg::ref_ptr image (new osg::Image); + image->allocateImage(width, height, 1, pf, GL_UNSIGNED_BYTE); + memcpy(image->data(), data, size); + image->flipVertical(); + + osgDB::writeImageFile(*image, out); } @@ -71,17 +75,20 @@ namespace ESSImport data.resize(esm.getSubSize()); esm.getExact(&data[0], data.size()); - Ogre::DataStreamPtr stream (new Ogre::MemoryDataStream(&data[0], data.size())); - mGlobalMapImage.loadRawData(stream, maph.size, maph.size, 1, Ogre::PF_BYTE_RGB); + mGlobalMapImage = new osg::Image; + mGlobalMapImage->allocateImage(maph.size, maph.size, 1, GL_RGB, GL_UNSIGNED_BYTE); + memcpy(mGlobalMapImage->data(), &data[0], data.size()); + // to match openmw size - mGlobalMapImage.resize(maph.size*2, maph.size*2, Ogre::Image::FILTER_BILINEAR); + // FIXME: filtering? + mGlobalMapImage->scaleImage(maph.size*2, maph.size*2, 1, GL_UNSIGNED_BYTE); } void ConvertFMAP::write(ESM::ESMWriter &esm) { - int numcells = mGlobalMapImage.getWidth() / 18; // NB truncating, doesn't divide perfectly + int numcells = mGlobalMapImage->s() / 18; // NB truncating, doesn't divide perfectly // with the 512x512 map the game has by default - int cellSize = mGlobalMapImage.getWidth()/numcells; + int cellSize = mGlobalMapImage->s()/numcells; // Note the upper left corner of the (0,0) cell should be at (width/2, height/2) @@ -90,12 +97,14 @@ namespace ESSImport mContext->mGlobalMapState.mBounds.mMinY = -(numcells-1)/2; mContext->mGlobalMapState.mBounds.mMaxY = numcells/2; - Ogre::Image image2; - std::vector data; + osg::ref_ptr image2 (new osg::Image); int width = cellSize*numcells; int height = cellSize*numcells; + std::vector data; data.resize(width*height*4, 0); - image2.loadDynamicImage(&data[0], width, height, Ogre::PF_BYTE_RGBA); + + image2->allocateImage(width, height, 1, GL_RGBA, GL_UNSIGNED_BYTE); + memcpy(image2->data(), &data[0], data.size()); for (std::set >::const_iterator it = mContext->mExploredCells.begin(); it != mContext->mExploredCells.end(); ++it) { @@ -108,8 +117,8 @@ namespace ESSImport continue; } - int imageLeftSrc = mGlobalMapImage.getWidth()/2; - int imageTopSrc = mGlobalMapImage.getHeight()/2; + int imageLeftSrc = mGlobalMapImage->s()/2; + int imageTopSrc = mGlobalMapImage->t()/2; imageLeftSrc += it->first * cellSize; imageTopSrc -= it->second * cellSize; int imageLeftDst = width/2; @@ -118,13 +127,31 @@ namespace ESSImport imageTopDst -= it->second * cellSize; for (int x=0; xdata(imageLeftSrc+x, imageTopSrc+y, 0); + *(unsigned int*)image2->data(imageLeftDst+x, imageTopDst+y, 0) = col; + } + } + + std::stringstream ostream; + osgDB::ReaderWriter* readerwriter = osgDB::Registry::instance()->getReaderWriterForExtension("png"); + if (!readerwriter) + { + std::cerr << "can't write global map image, no png readerwriter found" << std::endl; + return; + } + + image2->flipVertical(); + + osgDB::ReaderWriter::WriteResult result = readerwriter->writeImage(*image2, ostream); + if (!result.success()) + { + std::cerr << "can't write global map image: " << result.message() << std::endl; + return; } - Ogre::DataStreamPtr encoded = image2.encode("png"); - mContext->mGlobalMapState.mImageData.resize(encoded->size()); - encoded->read(&mContext->mGlobalMapState.mImageData[0], encoded->size()); + std::string outData = ostream.str(); + mContext->mGlobalMapState.mImageData = std::vector(outData.begin(), outData.end()); esm.startRecord(ESM::REC_GMAP); mContext->mGlobalMapState.save(esm); @@ -194,7 +221,7 @@ namespace ESSImport std::ostringstream filename; filename << "fog_" << cell.mData.mX << "_" << cell.mData.mY << ".tga"; - convertImage((char*)&newcell.mFogOfWar[0], newcell.mFogOfWar.size()*4, 16, 16, Ogre::PF_BYTE_RGBA, filename.str()); + convertImage((char*)&newcell.mFogOfWar[0], newcell.mFogOfWar.size()*4, 16, 16, GL_RGBA, filename.str()); } } diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index 5711e6754..f00b25438 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -1,7 +1,8 @@ #ifndef OPENMW_ESSIMPORT_CONVERTER_H #define OPENMW_ESSIMPORT_CONVERTER_H -#include +#include +#include #include #include @@ -311,7 +312,7 @@ public: virtual void write(ESM::ESMWriter &esm); private: - Ogre::Image mGlobalMapImage; + osg::ref_ptr mGlobalMapImage; }; class ConvertCell : public Converter diff --git a/apps/essimporter/importer.cpp b/apps/essimporter/importer.cpp index d5ed43b8a..3959a8f5c 100644 --- a/apps/essimporter/importer.cpp +++ b/apps/essimporter/importer.cpp @@ -1,7 +1,8 @@ #include "importer.hpp" #include -#include +#include +#include #include #include @@ -32,13 +33,48 @@ namespace void writeScreenshot(const ESM::Header& fileHeader, ESM::SavedGame& out) { - Ogre::Image screenshot; - std::vector screenshotData = fileHeader.mSCRS; // MemoryDataStream doesn't work with const data :( - Ogre::DataStreamPtr screenshotStream (new Ogre::MemoryDataStream(&screenshotData[0], screenshotData.size())); - screenshot.loadRawData(screenshotStream, 128, 128, 1, Ogre::PF_BYTE_BGRA); - Ogre::DataStreamPtr encoded = screenshot.encode("jpg"); - out.mScreenshot.resize(encoded->size()); - encoded->read(&out.mScreenshot[0], encoded->size()); + if (fileHeader.mSCRS.size() != 128*128*4) + { + std::cerr << "unexpected screenshot size " << std::endl; + return; + } + + osg::ref_ptr image (new osg::Image); + image->allocateImage(128, 128, 1, GL_RGB, GL_UNSIGNED_BYTE); + + // need to convert pixel format from BGRA to RGB as the jpg readerwriter doesn't support it otherwise + std::vector::const_iterator it = fileHeader.mSCRS.begin(); + for (int y=0; y<128; ++y) + { + for (int x=0; x<128; ++x) + { + *(image->data(x,y)+2) = *it++; + *(image->data(x,y)+1) = *it++; + *image->data(x,y) = *it++; + it++; // skip alpha + } + } + + image->flipVertical(); + + std::stringstream ostream; + + osgDB::ReaderWriter* readerwriter = osgDB::Registry::instance()->getReaderWriterForExtension("jpg"); + if (!readerwriter) + { + std::cerr << "can't write screenshot: no jpg readerwriter found" << std::endl; + return; + } + + osgDB::ReaderWriter::WriteResult result = readerwriter->writeImage(*image, ostream); + if (!result.success()) + { + std::cerr << "can't write screenshot: " << result.message() << " code " << result.status() << std::endl; + return; + } + + std::string data = ostream.str(); + out.mScreenshot = std::vector(data.begin(), data.end()); } } @@ -203,10 +239,6 @@ namespace ESSImport void Importer::run() { - // construct Ogre::Root to gain access to image codecs - Ogre::LogManager logman; - Ogre::Root root; - ToUTF8::Utf8Encoder encoder(ToUTF8::calculateEncoding(mEncoding)); ESM::ESMReader esm; esm.open(mEssFile); From b70383d12762cd6b4cc8fb7d4254f10db7c8fdce Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Jun 2015 21:37:21 +0200 Subject: [PATCH 1401/3725] Remove last remains of Ogre math --- apps/openmw/mwmechanics/character.cpp | 2 +- .../mwmechanics/mechanicsmanagerimp.cpp | 6 +-- apps/openmw/mwmechanics/obstacle.cpp | 4 +- apps/openmw/mwmechanics/pathfinding.hpp | 16 +----- apps/openmw/mwmechanics/summoning.cpp | 13 ++--- apps/openmw/mwrender/npcanimation.cpp | 22 -------- apps/openmw/mwrender/npcanimation.hpp | 9 ---- apps/openmw/mwrender/weaponanimation.hpp | 5 -- apps/openmw/mwscript/miscextensions.cpp | 4 +- .../mwscript/transformationextensions.cpp | 38 +++++++------- apps/openmw/mwworld/actionteleport.cpp | 3 +- apps/openmw/mwworld/scene.cpp | 12 ++--- apps/openmw/mwworld/worldimp.cpp | 52 +++++++++---------- apps/openmw/mwworld/worldimp.hpp | 2 +- components/esm/util.hpp | 25 +-------- 15 files changed, 72 insertions(+), 141 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index c5282bdf8..b0db1dfa0 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1797,7 +1797,7 @@ void CharacterController::update(float duration) if (mMovementState == CharState_TurnLeft || mMovementState == CharState_TurnRight) { if (duration > 0) - mAnimation->adjustSpeedMult(mCurrentMovement, std::min(1.5f, std::abs(rot.z()) / duration / Ogre::Math::PI)); + mAnimation->adjustSpeedMult(mCurrentMovement, std::min(1.5f, std::abs(rot.z()) / duration / static_cast(osg::PI))); } if (!mSkipAnim) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 8fbb31fb7..b89b8c94a 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -31,10 +31,10 @@ namespace float getFightDistanceBias(const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2) { - Ogre::Vector3 pos1 (actor1.getRefData().getPosition().pos); - Ogre::Vector3 pos2 (actor2.getRefData().getPosition().pos); + osg::Vec3f pos1 (actor1.getRefData().getPosition().asVec3()); + osg::Vec3f pos2 (actor2.getRefData().getPosition().asVec3()); - float d = pos1.distance(pos2); + float d = (pos1 - pos2).length(); static const int iFightDistanceBase = MWBase::Environment::get().getWorld()->getStore().get().find( "iFightDistanceBase")->getInt(); diff --git a/apps/openmw/mwmechanics/obstacle.cpp b/apps/openmw/mwmechanics/obstacle.cpp index 7cfa6fcd5..ae2cbcafe 100644 --- a/apps/openmw/mwmechanics/obstacle.cpp +++ b/apps/openmw/mwmechanics/obstacle.cpp @@ -37,7 +37,7 @@ namespace MWMechanics MWWorld::CellRefList& doors = cell->get(); MWWorld::CellRefList::List& refList = doors.mList; MWWorld::CellRefList::List::iterator it = refList.begin(); - Ogre::Vector3 pos(actor.getRefData().getPosition().pos); + osg::Vec3f pos(actor.getRefData().getPosition().asVec3()); /// TODO: How to check whether the actor is facing a door? Below code is for /// the player, perhaps it can be adapted. @@ -50,7 +50,7 @@ namespace MWMechanics for (; it != refList.end(); ++it) { MWWorld::LiveCellRef& ref = *it; - if(pos.squaredDistance(Ogre::Vector3(ref.mData.getPosition().pos)) < minSqr) + if((pos - ref.mData.getPosition().asVec3()).length2() < minSqr) if((closed && ref.mData.getLocalRotation().rot[2] == 0) || (!closed && ref.mData.getLocalRotation().rot[2] >= 1)) { diff --git a/apps/openmw/mwmechanics/pathfinding.hpp b/apps/openmw/mwmechanics/pathfinding.hpp index 8386de70f..ce0b54192 100644 --- a/apps/openmw/mwmechanics/pathfinding.hpp +++ b/apps/openmw/mwmechanics/pathfinding.hpp @@ -22,9 +22,9 @@ namespace MWMechanics public: PathFinder(); - static float sgn(Ogre::Radian a) + static float sgn(float val) { - if(a.valueRadians() > 0) + if(val > 0) return 1.0; return -1.0; } @@ -77,12 +77,6 @@ namespace MWMechanics mPath.push_back(point); } - /// utility function to convert a Ogre::Vector3 to a Pathgrid::Point - static ESM::Pathgrid::Point MakePathgridPoint(const Ogre::Vector3& v) - { - return ESM::Pathgrid::Point(static_cast(v[0]), static_cast(v[1]), static_cast(v[2])); - } - /// utility function to convert a osg::Vec3f to a Pathgrid::Point static ESM::Pathgrid::Point MakePathgridPoint(const osg::Vec3f& v) { @@ -100,12 +94,6 @@ namespace MWMechanics return osg::Vec3f(static_cast(p.mX), static_cast(p.mY), static_cast(p.mZ)); } - /// utility function to convert a Pathgrid::Point to a Ogre::Vector3 - static Ogre::Vector3 MakeOgreVector3(const ESM::Pathgrid::Point& p) - { - return Ogre::Vector3(static_cast(p.mX), static_cast(p.mY), static_cast(p.mZ)); - } - private: bool mIsPathConstructed; diff --git a/apps/openmw/mwmechanics/summoning.cpp b/apps/openmw/mwmechanics/summoning.cpp index 4140fd3c0..768afc35a 100644 --- a/apps/openmw/mwmechanics/summoning.cpp +++ b/apps/openmw/mwmechanics/summoning.cpp @@ -115,13 +115,14 @@ namespace MWMechanics if (!found) { ESM::Position ipos = mActor.getRefData().getPosition(); - Ogre::Vector3 pos(ipos.pos); - Ogre::Quaternion rot(Ogre::Radian(-ipos.rot[2]), Ogre::Vector3::UNIT_Z); + osg::Vec3f pos(ipos.asVec3()); + + osg::Quat rot (-ipos.rot[2], osg::Vec3f(0,0,1)); const float distance = 50; - pos = pos + distance*rot.yAxis(); - ipos.pos[0] = pos.x; - ipos.pos[1] = pos.y; - ipos.pos[2] = pos.z; + pos = pos + (rot * osg::Vec3f(0,1,0)) * distance; + ipos.pos[0] = pos.x(); + ipos.pos[1] = pos.y(); + ipos.pos[2] = pos.z(); ipos.rot[0] = 0; ipos.rot[1] = 0; ipos.rot[2] = 0; diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 1f05d93b6..71c48a489 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -1062,26 +1062,4 @@ void NpcAnimation::updatePtr(const MWWorld::Ptr &updated) mHeadAnimationTime->updatePtr(updated); } -/* -void NpcAnimation::setHeadPitch(Ogre::Radian pitch) -{ - mHeadPitch = pitch; -} - -void NpcAnimation::setHeadYaw(Ogre::Radian yaw) -{ - mHeadYaw = yaw; -} - -Ogre::Radian NpcAnimation::getHeadPitch() const -{ - return mHeadPitch; -} - -Ogre::Radian NpcAnimation::getHeadYaw() const -{ - return mHeadYaw; -} -*/ - } diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index db0b4ea0c..23b663565 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -120,8 +120,6 @@ private: void addPartGroup(int group, int priority, const std::vector &parts, bool enchantedGlow=false, osg::Vec4f* glowColor=NULL); - //void applyAlpha(float alpha, Ogre::Entity* ent, NifOgre::ObjectScenePtr scene); - osg::ref_ptr mFirstPersonNeckController; osg::ref_ptr mHeadController; @@ -171,19 +169,12 @@ public: virtual Resource::ResourceSystem* getResourceSystem(); // WeaponAnimation - //virtual NifOgre::ObjectScenePtr getWeapon() { return mObjectParts[ESM::PRT_Weapon]; } virtual void showWeapon(bool show) { showWeapons(show); } - //virtual void configureAddedObject(NifOgre::ObjectScenePtr object, MWWorld::Ptr ptr, int slot); void setViewMode(ViewMode viewMode); void updateParts(); - /// \brief Applies a translation to the arms and hands. - /// This may be called multiple times before the animation - /// is updated to add additional offsets. - //void addFirstPersonOffset(const Ogre::Vector3 &offset); - /// Rebuilds the NPC, updating their root model, animation sources, and equipment. void rebuild(); diff --git a/apps/openmw/mwrender/weaponanimation.hpp b/apps/openmw/mwrender/weaponanimation.hpp index 9336afd4c..226d59c53 100644 --- a/apps/openmw/mwrender/weaponanimation.hpp +++ b/apps/openmw/mwrender/weaponanimation.hpp @@ -56,16 +56,11 @@ namespace MWRender virtual osg::Node* getWeaponNode() = 0; virtual Resource::ResourceSystem* getResourceSystem() = 0; - - //virtual NifOgre::ObjectScenePtr getWeapon() = 0; virtual void showWeapon(bool show) = 0; - //virtual void configureAddedObject(NifOgre::ObjectScenePtr object, MWWorld::Ptr ptr, int slot) = 0; /// A relative factor (0-1) that decides if and how much the skeleton should be pitched /// to indicate the facing orientation of the character, for ranged weapon aiming. float mPitchFactor; - - //void pitchSkeleton(float xrot, Ogre::SkeletonInstance* skel); }; } diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 8580eb8f8..e706140fb 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -1045,8 +1045,8 @@ namespace MWScript msg << "Cell: " << MWBase::Environment::get().getWorld()->getCellName(cell) << std::endl; if (cell->getCell()->isExterior()) msg << "Grid: " << cell->getCell()->getGridX() << " " << cell->getCell()->getGridY() << std::endl; - Ogre::Vector3 pos (ptr.getRefData().getPosition().pos); - msg << "Coordinates: " << pos << std::endl; + osg::Vec3f pos (ptr.getRefData().getPosition().asVec3()); + msg << "Coordinates: " << pos.x() << " " << pos.y() << " " << pos.z() << std::endl; msg << "Model: " << ptr.getClass().getModel(ptr) << std::endl; if (!ptr.getClass().getScript(ptr).empty()) msg << "Script: " << ptr.getClass().getScript(ptr) << std::endl; diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 6ede67932..093506113 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -84,9 +84,9 @@ namespace MWScript Interpreter::Type_Float angle = runtime[0].mFloat; runtime.pop(); - float ax = Ogre::Radian(ptr.getRefData().getPosition().rot[0]).valueDegrees(); - float ay = Ogre::Radian(ptr.getRefData().getPosition().rot[1]).valueDegrees(); - float az = Ogre::Radian(ptr.getRefData().getPosition().rot[2]).valueDegrees(); + float ax = osg::RadiansToDegrees(ptr.getRefData().getPosition().rot[0]); + float ay = osg::RadiansToDegrees(ptr.getRefData().getPosition().rot[1]); + float az = osg::RadiansToDegrees(ptr.getRefData().getPosition().rot[2]); MWWorld::LocalRotation localRot = ptr.getRefData().getLocalRotation(); @@ -127,15 +127,15 @@ namespace MWScript if (axis == "x") { - runtime.push(Ogre::Radian(ptr.getCellRef().getPosition().rot[0]).valueDegrees()); + runtime.push(osg::RadiansToDegrees(ptr.getCellRef().getPosition().rot[0])); } else if (axis == "y") { - runtime.push(Ogre::Radian(ptr.getCellRef().getPosition().rot[1]).valueDegrees()); + runtime.push(osg::RadiansToDegrees(ptr.getCellRef().getPosition().rot[1])); } else if (axis == "z") { - runtime.push(Ogre::Radian(ptr.getCellRef().getPosition().rot[2]).valueDegrees()); + runtime.push(osg::RadiansToDegrees(ptr.getCellRef().getPosition().rot[2])); } else throw std::runtime_error ("invalid rotation axis: " + axis); @@ -156,15 +156,15 @@ namespace MWScript if (axis=="x") { - runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[0]).valueDegrees()); + runtime.push(osg::RadiansToDegrees(ptr.getRefData().getPosition().rot[0])); } else if (axis=="y") { - runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[1]).valueDegrees()); + runtime.push(osg::RadiansToDegrees(ptr.getRefData().getPosition().rot[1])); } else if (axis=="z") { - runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[2]).valueDegrees()); + runtime.push(osg::RadiansToDegrees(ptr.getRefData().getPosition().rot[2])); } else throw std::runtime_error ("invalid rotation axis: " + axis); @@ -326,8 +326,8 @@ namespace MWScript ptr = MWWorld::Ptr(ptr.getBase(), store); dynamic_cast(runtime.getContext()).updatePtr(ptr); - float ax = Ogre::Radian(ptr.getRefData().getPosition().rot[0]).valueDegrees(); - float ay = Ogre::Radian(ptr.getRefData().getPosition().rot[1]).valueDegrees(); + float ax = osg::RadiansToDegrees(ptr.getRefData().getPosition().rot[0]); + float ay = osg::RadiansToDegrees(ptr.getRefData().getPosition().rot[1]); // Note that you must specify ZRot in minutes (1 degree = 60 minutes; north = 0, east = 5400, south = 10800, west = 16200) // except for when you position the player, then degrees must be used. // See "Morrowind Scripting for Dummies (9th Edition)" pages 50 and 54 for reference. @@ -382,8 +382,8 @@ namespace MWScript } dynamic_cast(runtime.getContext()).updatePtr(ptr); - float ax = Ogre::Radian(ptr.getRefData().getPosition().rot[0]).valueDegrees(); - float ay = Ogre::Radian(ptr.getRefData().getPosition().rot[1]).valueDegrees(); + float ax = osg::RadiansToDegrees(ptr.getRefData().getPosition().rot[0]); + float ay = osg::RadiansToDegrees(ptr.getRefData().getPosition().rot[1]); // Note that you must specify ZRot in minutes (1 degree = 60 minutes; north = 0, east = 5400, south = 10800, west = 16200) // except for when you position the player, then degrees must be used. // See "Morrowind Scripting for Dummies (9th Edition)" pages 50 and 54 for reference. @@ -567,9 +567,9 @@ namespace MWScript Interpreter::Type_Float rotation = (runtime[0].mFloat*MWBase::Environment::get().getFrameDuration()); runtime.pop(); - float ax = Ogre::Radian(ptr.getRefData().getLocalRotation().rot[0]).valueDegrees(); - float ay = Ogre::Radian(ptr.getRefData().getLocalRotation().rot[1]).valueDegrees(); - float az = Ogre::Radian(ptr.getRefData().getLocalRotation().rot[2]).valueDegrees(); + float ax = osg::RadiansToDegrees(ptr.getRefData().getLocalRotation().rot[0]); + float ay = osg::RadiansToDegrees(ptr.getRefData().getLocalRotation().rot[1]); + float az = osg::RadiansToDegrees(ptr.getRefData().getLocalRotation().rot[2]); if (axis == "x") { @@ -604,9 +604,9 @@ namespace MWScript const float *objRot = ptr.getRefData().getPosition().rot; - float ax = Ogre::Radian(objRot[0]).valueDegrees(); - float ay = Ogre::Radian(objRot[1]).valueDegrees(); - float az = Ogre::Radian(objRot[2]).valueDegrees(); + float ax = osg::RadiansToDegrees(objRot[0]); + float ay = osg::RadiansToDegrees(objRot[1]); + float az = osg::RadiansToDegrees(objRot[2]); if (axis == "x") { diff --git a/apps/openmw/mwworld/actionteleport.cpp b/apps/openmw/mwworld/actionteleport.cpp index fccd176a8..cd6698c98 100644 --- a/apps/openmw/mwworld/actionteleport.cpp +++ b/apps/openmw/mwworld/actionteleport.cpp @@ -40,8 +40,7 @@ namespace MWWorld for(std::set::iterator it = followers.begin();it != followers.end();++it) { MWWorld::Ptr follower = *it; - if (Ogre::Vector3(follower.getRefData().getPosition().pos).squaredDistance( - Ogre::Vector3( actor.getRefData().getPosition().pos)) + if ((follower.getRefData().getPosition().asVec3() - actor.getRefData().getPosition().asVec3()).length2() <= 800*800) teleport(*it); } diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 1a9ae3494..78d093104 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -418,9 +418,9 @@ namespace MWWorld if (adjustPlayerPos) { world->moveObject(player, pos.pos[0], pos.pos[1], pos.pos[2]); - float x = Ogre::Radian(pos.rot[0]).valueDegrees(); - float y = Ogre::Radian(pos.rot[1]).valueDegrees(); - float z = Ogre::Radian(pos.rot[2]).valueDegrees(); + float x = osg::RadiansToDegrees(pos.rot[0]); + float y = osg::RadiansToDegrees(pos.rot[1]); + float z = osg::RadiansToDegrees(pos.rot[2]); world->rotateObject(player, x, y, z); player.getClass().adjustPosition(player, true); @@ -475,9 +475,9 @@ namespace MWWorld MWBase::World *world = MWBase::Environment::get().getWorld(); world->moveObject(world->getPlayerPtr(), position.pos[0], position.pos[1], position.pos[2]); - float x = Ogre::Radian(position.rot[0]).valueDegrees(); - float y = Ogre::Radian(position.rot[1]).valueDegrees(); - float z = Ogre::Radian(position.rot[2]).valueDegrees(); + float x = osg::RadiansToDegrees(position.rot[0]); + float y = osg::RadiansToDegrees(position.rot[1]); + float z = osg::RadiansToDegrees(position.rot[2]); world->rotateObject(world->getPlayerPtr(), x, y, z); world->getPlayerPtr().getClass().adjustPosition(world->getPlayerPtr(), true); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 1ac92cf16..9a42d4587 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -66,10 +66,11 @@ namespace // Wraps a value to (-PI, PI] void wrap(float& rad) { + const float pi = static_cast(osg::PI); if (rad>0) - rad = std::fmod(rad+Ogre::Math::PI, 2.0f*Ogre::Math::PI)-Ogre::Math::PI; + rad = std::fmod(rad+pi, 2.0f*pi)-pi; else - rad = std::fmod(rad-Ogre::Math::PI, 2.0f*Ogre::Math::PI)+Ogre::Math::PI; + rad = std::fmod(rad-pi, 2.0f*pi)+pi; } } @@ -1220,24 +1221,24 @@ namespace MWWorld mWorldScene->updateObjectScale(ptr); } - void World::rotateObjectImp (const Ptr& ptr, Ogre::Vector3 rot, bool adjust) + void World::rotateObjectImp (const Ptr& ptr, const osg::Vec3f& rot, bool adjust) { - const float two_pi = Ogre::Math::TWO_PI; - const float pi = Ogre::Math::PI; + const float pi = static_cast(osg::PI); + const float two_pi = pi*2.f; ESM::Position pos = ptr.getRefData().getPosition(); float *objRot = pos.rot; if(adjust) { - objRot[0] += rot.x; - objRot[1] += rot.y; - objRot[2] += rot.z; + objRot[0] += rot.x(); + objRot[1] += rot.y(); + objRot[2] += rot.z(); } else { - objRot[0] = rot.x; - objRot[1] = rot.y; - objRot[2] = rot.z; + objRot[0] = rot.x(); + objRot[1] = rot.y(); + objRot[2] = rot.z(); } if(ptr.getClass().isActor()) @@ -1246,7 +1247,7 @@ namespace MWWorld * currently it's done so for rotating the camera, which needs * clamping. */ - const float half_pi = Ogre::Math::HALF_PI; + const float half_pi = pi/2.f; if(objRot[0] < -half_pi) objRot[0] = -half_pi; else if(objRot[0] > half_pi) objRot[0] = half_pi; @@ -1272,9 +1273,9 @@ namespace MWWorld void World::localRotateObject (const Ptr& ptr, float x, float y, float z) { LocalRotation rot = ptr.getRefData().getLocalRotation(); - rot.rot[0]=Ogre::Degree(x).valueRadians(); - rot.rot[1]=Ogre::Degree(y).valueRadians(); - rot.rot[2]=Ogre::Degree(z).valueRadians(); + rot.rot[0]=osg::DegreesToRadians(x); + rot.rot[1]=osg::DegreesToRadians(y); + rot.rot[2]=osg::DegreesToRadians(z); wrap(rot.rot[0]); wrap(rot.rot[1]); @@ -1332,9 +1333,9 @@ namespace MWWorld void World::rotateObject (const Ptr& ptr,float x,float y,float z, bool adjust) { - rotateObjectImp(ptr, Ogre::Vector3(Ogre::Degree(x).valueRadians(), - Ogre::Degree(y).valueRadians(), - Ogre::Degree(z).valueRadians()), + rotateObjectImp(ptr, osg::Vec3f(osg::DegreesToRadians(x), + osg::DegreesToRadians(y), + osg::DegreesToRadians(z)), adjust); } @@ -2904,8 +2905,7 @@ namespace MWWorld World::DetectionType mType; bool operator() (MWWorld::Ptr ptr) { - if (Ogre::Vector3(ptr.getRefData().getPosition().pos).squaredDistance( - Ogre::Vector3(mDetector.getRefData().getPosition().pos)) >= mSquaredDist) + if ((ptr.getRefData().getPosition().asVec3() - mDetector.getRefData().getPosition().asVec3()).length2() >= mSquaredDist) return true; if (!ptr.getRefData().isEnabled() || ptr.getRefData().isDeleted()) @@ -3096,13 +3096,13 @@ namespace MWWorld return; ESM::Position ipos = mPlayer->getPlayer().getRefData().getPosition(); - Ogre::Vector3 pos(ipos.pos); - Ogre::Quaternion rot(Ogre::Radian(-ipos.rot[2]), Ogre::Vector3::UNIT_Z); + osg::Vec3f pos(ipos.asVec3()); + osg::Quat rot(-ipos.rot[2], osg::Vec3f(0,0,1)); const float distance = 50; - pos = pos + distance*rot.yAxis(); - ipos.pos[0] = pos.x; - ipos.pos[1] = pos.y; - ipos.pos[2] = pos.z; + pos = pos + (rot * osg::Vec3f(0,1,0)) * distance; + ipos.pos[0] = pos.x(); + ipos.pos[1] = pos.y(); + ipos.pos[2] = pos.z(); ipos.rot[0] = 0; ipos.rot[1] = 0; ipos.rot[2] = 0; diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index c70a102c3..bbc04ffdc 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -111,7 +111,7 @@ namespace MWWorld void updateWeather(float duration, bool paused = false); int getDaysPerMonth (int month) const; - void rotateObjectImp (const Ptr& ptr, Ogre::Vector3 rot, bool adjust); + void rotateObjectImp (const Ptr& ptr, const osg::Vec3f& rot, bool adjust); Ptr moveObjectImp (const Ptr& ptr, float x, float y, float z); ///< @return an updated Ptr in case the Ptr's cell changes diff --git a/components/esm/util.hpp b/components/esm/util.hpp index 07a7655c7..3ab2ef049 100644 --- a/components/esm/util.hpp +++ b/components/esm/util.hpp @@ -17,13 +17,7 @@ struct Quaternion float mValues[4]; Quaternion() {} - Quaternion (Ogre::Quaternion q) - { - mValues[0] = q.w; - mValues[1] = q.x; - mValues[2] = q.y; - mValues[3] = q.z; - } + Quaternion(const osg::Quat& q) { mValues[0] = q.w(); @@ -32,11 +26,6 @@ struct Quaternion mValues[3] = q.z(); } - operator Ogre::Quaternion () const - { - return Ogre::Quaternion(mValues[0], mValues[1], mValues[2], mValues[3]); - } - operator osg::Quat () const { return osg::Quat(mValues[1], mValues[2], mValues[3], mValues[0]); @@ -48,12 +37,7 @@ struct Vector3 float mValues[3]; Vector3() {} - Vector3 (Ogre::Vector3 v) - { - mValues[0] = v.x; - mValues[1] = v.y; - mValues[2] = v.z; - } + Vector3(const osg::Vec3f& v) { mValues[0] = v.x(); @@ -61,11 +45,6 @@ struct Vector3 mValues[2] = v.z(); } - operator Ogre::Vector3 () const - { - return Ogre::Vector3(&mValues[0]); - } - operator osg::Vec3f () const { return osg::Vec3f(mValues[0], mValues[1], mValues[2]); From 4bb3cbf0fb29a60e223407e9875f9e8d9b2f7c61 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Jun 2015 23:04:35 +0200 Subject: [PATCH 1402/3725] Remove last remains of Ogre --- CMakeLists.txt | 8 +- apps/essimporter/converter.cpp | 3 - apps/essimporter/converter.hpp | 2 + apps/essimporter/importer.cpp | 3 + apps/opencs/CMakeLists.txt | 1 - apps/openmw/CMakeLists.txt | 1 - apps/openmw/mwgui/hud.cpp | 2 - apps/openmw/mwgui/mapwindow.cpp | 2 - apps/openmw/mwgui/settingswindow.cpp | 2 - apps/openmw/mwgui/travelwindow.cpp | 2 - apps/openmw/mwmechanics/actors.hpp | 5 - apps/openmw/mwmechanics/aiavoiddoor.cpp | 2 - apps/openmw/mwmechanics/aicombat.cpp | 2 - apps/openmw/mwmechanics/aicombat.hpp | 2 - apps/openmw/mwmechanics/aifollow.cpp | 3 - apps/openmw/mwmechanics/aipackage.cpp | 2 - apps/openmw/mwmechanics/aitravel.cpp | 2 - apps/openmw/mwmechanics/aiwander.cpp | 3 - apps/openmw/mwmechanics/aiwander.hpp | 2 - apps/openmw/mwmechanics/character.cpp | 2 - apps/openmw/mwmechanics/character.hpp | 2 +- apps/openmw/mwmechanics/combat.hpp | 1 - .../mwmechanics/mechanicsmanagerimp.hpp | 5 - apps/openmw/mwmechanics/objects.cpp | 2 - apps/openmw/mwmechanics/obstacle.cpp | 2 - apps/openmw/mwmechanics/pathfinding.cpp | 3 - apps/openmw/mwmechanics/pathfinding.hpp | 3 - apps/openmw/mwmechanics/spellcasting.hpp | 2 - apps/openmw/mwmechanics/summoning.cpp | 2 - apps/openmw/mwphysics/physicssystem.hpp | 6 +- apps/openmw/mwscript/cellextensions.cpp | 3 +- apps/openmw/mwscript/statsextensions.cpp | 2 +- .../mwscript/transformationextensions.cpp | 2 + apps/openmw/mwsound/sound.hpp | 2 - apps/openmw/mwworld/class.cpp | 2 - apps/openmw/mwworld/class.hpp | 5 - apps/openmw/mwworld/player.hpp | 2 - apps/openmw/mwworld/refdata.cpp | 2 - apps/openmw/mwworld/scene.cpp | 2 +- apps/openmw/mwworld/scene.hpp | 5 - apps/openmw/mwworld/weather.hpp | 3 +- apps/openmw/mwworld/worldimp.hpp | 5 - cmake/FindMyGUI.cmake | 2 +- cmake/FindOGRE.cmake | 568 ------------------ components/CMakeLists.txt | 1 - components/esm/util.hpp | 3 - 46 files changed, 17 insertions(+), 671 deletions(-) delete mode 100644 cmake/FindOGRE.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 487d07aa5..8dbad2924 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -171,11 +171,6 @@ IF(BOOST_STATIC) set(Boost_USE_STATIC_LIBS ON) endif() -find_package(OGRE REQUIRED) -if (${OGRE_VERSION} VERSION_LESS "1.9") - message(FATAL_ERROR "OpenMW requires Ogre 1.9 or later, please install the latest stable version from http://ogre3d.org") -endif() - find_package(OpenSceneGraph 3.2.0 REQUIRED osgDB osgViewer osgGA osgAnimation osgParticle osgQt osgUtil osgFX) include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS}) @@ -191,7 +186,6 @@ find_package(Bullet REQUIRED) include_directories("." SYSTEM - ${OGRE_INCLUDE_DIR} ${OGRE_INCLUDE_DIR}/Ogre ${OGRE_INCLUDE_DIR}/OGRE ${OGRE_INCLUDE_DIRS} ${SDL2_INCLUDE_DIR} ${Boost_INCLUDE_DIR} ${PLATFORM_INCLUDE_DIR} @@ -200,7 +194,7 @@ include_directories("." ${BULLET_INCLUDE_DIRS} ) -link_directories(${SDL2_LIBRARY_DIRS} ${Boost_LIBRARY_DIRS} ${OGRE_LIB_DIR} ${MYGUI_LIB_DIR}) +link_directories(${SDL2_LIBRARY_DIRS} ${Boost_LIBRARY_DIRS} ${MYGUI_LIB_DIR}) if(MYGUI_STATIC) add_definitions(-DMYGUI_STATIC) diff --git a/apps/essimporter/converter.cpp b/apps/essimporter/converter.cpp index ec396761c..2ef10ee34 100644 --- a/apps/essimporter/converter.cpp +++ b/apps/essimporter/converter.cpp @@ -2,9 +2,6 @@ #include -#include -#include - #include #include diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index f00b25438..fb8fb8c9f 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -1,6 +1,8 @@ #ifndef OPENMW_ESSIMPORT_CONVERTER_H #define OPENMW_ESSIMPORT_CONVERTER_H +#include + #include #include diff --git a/apps/essimporter/importer.cpp b/apps/essimporter/importer.cpp index 3959a8f5c..65f318297 100644 --- a/apps/essimporter/importer.cpp +++ b/apps/essimporter/importer.cpp @@ -1,4 +1,7 @@ #include "importer.hpp" + +#include + #include #include diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 7c539fb14..4ade2df44 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -200,7 +200,6 @@ if(APPLE) endif(APPLE) target_link_libraries(openmw-cs - ${OGRE_LIBRARIES} ${OPENSCENEGRAPH_LIBRARIES} ${Boost_LIBRARIES} ${QT_LIBRARIES} diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index b23828254..8e17f2f31 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -126,7 +126,6 @@ endif () include_directories(${SOUND_INPUT_INCLUDES}) target_link_libraries(openmw - ${OGRE_LIBRARIES} ${OPENSCENEGRAPH_LIBRARIES} ${Boost_LIBRARIES} ${OPENAL_LIBRARY} diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 44f944c3b..56a4b0807 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -1,7 +1,5 @@ #include "hud.hpp" -#include - #include #include #include diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index d748bef6c..34a9db1e1 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -1,7 +1,5 @@ #include "mapwindow.hpp" -#include - #include #include diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 8ba46339a..a50c30507 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -1,7 +1,5 @@ #include "settingswindow.hpp" -#include - #include #include #include diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index 7985e7eda..6ea6301ad 100644 --- a/apps/openmw/mwgui/travelwindow.cpp +++ b/apps/openmw/mwgui/travelwindow.cpp @@ -4,8 +4,6 @@ #include #include -#include - #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index f9e58ab4f..4baaea28d 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -10,11 +10,6 @@ #include "movement.hpp" #include "../mwbase/world.hpp" -namespace Ogre -{ - class Vector3; -} - namespace MWWorld { class Ptr; diff --git a/apps/openmw/mwmechanics/aiavoiddoor.cpp b/apps/openmw/mwmechanics/aiavoiddoor.cpp index 9d32aa97b..29bf19942 100644 --- a/apps/openmw/mwmechanics/aiavoiddoor.cpp +++ b/apps/openmw/mwmechanics/aiavoiddoor.cpp @@ -9,8 +9,6 @@ #include "movement.hpp" -#include - #include "steering.hpp" MWMechanics::AiAvoidDoor::AiAvoidDoor(const MWWorld::Ptr& doorPtr) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 495aaf82b..f31e0ff77 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -1,7 +1,5 @@ #include "aicombat.hpp" -#include - #include #include diff --git a/apps/openmw/mwmechanics/aicombat.hpp b/apps/openmw/mwmechanics/aicombat.hpp index 307df3872..e5454dc05 100644 --- a/apps/openmw/mwmechanics/aicombat.hpp +++ b/apps/openmw/mwmechanics/aicombat.hpp @@ -8,8 +8,6 @@ #include "movement.hpp" #include "obstacle.hpp" -#include - #include "../mwworld/cellstore.hpp" // for Doors #include "../mwbase/world.hpp" diff --git a/apps/openmw/mwmechanics/aifollow.cpp b/apps/openmw/mwmechanics/aifollow.cpp index 24a50cbd6..524a7f904 100644 --- a/apps/openmw/mwmechanics/aifollow.cpp +++ b/apps/openmw/mwmechanics/aifollow.cpp @@ -12,9 +12,6 @@ #include "creaturestats.hpp" #include "movement.hpp" -#include -#include - #include "steering.hpp" namespace MWMechanics diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index 8db62dea8..b5d62ee31 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -10,8 +10,6 @@ #include "movement.hpp" #include "../mwworld/action.hpp" -#include - #include "steering.hpp" MWMechanics::AiPackage::~AiPackage() {} diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index f9fddf575..6da5614d2 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -1,7 +1,5 @@ #include "aitravel.hpp" -#include - #include #include "../mwbase/world.hpp" diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 71508ac51..51b169eba 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -1,8 +1,5 @@ #include "aiwander.hpp" -#include -#include - #include #include diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index b4eb3d21c..4b83179d5 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -5,8 +5,6 @@ #include -#include - #include "pathfinding.hpp" #include "obstacle.hpp" diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index b0db1dfa0..d4ba561ed 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -19,8 +19,6 @@ #include "character.hpp" -#include - #include #include "movement.hpp" diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 2b2131061..797c2e623 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -1,7 +1,7 @@ #ifndef GAME_MWMECHANICS_CHARACTER_HPP #define GAME_MWMECHANICS_CHARACTER_HPP -#include +#include #include diff --git a/apps/openmw/mwmechanics/combat.hpp b/apps/openmw/mwmechanics/combat.hpp index 0a31a1a7e..9412f62e7 100644 --- a/apps/openmw/mwmechanics/combat.hpp +++ b/apps/openmw/mwmechanics/combat.hpp @@ -2,7 +2,6 @@ #define OPENMW_MECHANICS_COMBAT_H #include "../mwworld/ptr.hpp" -#include namespace MWMechanics { diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index f695ec57a..5cc2ce254 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -10,11 +10,6 @@ #include "objects.hpp" #include "actors.hpp" -namespace Ogre -{ - class Vector3; -} - namespace MWWorld { class CellStore; diff --git a/apps/openmw/mwmechanics/objects.cpp b/apps/openmw/mwmechanics/objects.cpp index d6f5da88d..4949d9b12 100644 --- a/apps/openmw/mwmechanics/objects.cpp +++ b/apps/openmw/mwmechanics/objects.cpp @@ -1,7 +1,5 @@ #include "objects.hpp" -#include - #include "movement.hpp" #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwmechanics/obstacle.cpp b/apps/openmw/mwmechanics/obstacle.cpp index ae2cbcafe..3d2ab7d3d 100644 --- a/apps/openmw/mwmechanics/obstacle.cpp +++ b/apps/openmw/mwmechanics/obstacle.cpp @@ -1,7 +1,5 @@ #include "obstacle.hpp" -#include - #include "../mwbase/world.hpp" #include "../mwworld/class.hpp" #include "../mwworld/cellstore.hpp" diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index d338cf01a..584bf84a0 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -1,8 +1,5 @@ #include "pathfinding.hpp" -#include "OgreMath.h" -#include "OgreVector3.h" - #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwmechanics/pathfinding.hpp b/apps/openmw/mwmechanics/pathfinding.hpp index ce0b54192..4867c4c21 100644 --- a/apps/openmw/mwmechanics/pathfinding.hpp +++ b/apps/openmw/mwmechanics/pathfinding.hpp @@ -5,9 +5,6 @@ #include #include -#include -#include - namespace MWWorld { class CellStore; diff --git a/apps/openmw/mwmechanics/spellcasting.hpp b/apps/openmw/mwmechanics/spellcasting.hpp index 4241c9e3e..2540b87db 100644 --- a/apps/openmw/mwmechanics/spellcasting.hpp +++ b/apps/openmw/mwmechanics/spellcasting.hpp @@ -3,8 +3,6 @@ #include "../mwworld/ptr.hpp" -#include - #include namespace ESM diff --git a/apps/openmw/mwmechanics/summoning.cpp b/apps/openmw/mwmechanics/summoning.cpp index 768afc35a..541026ee1 100644 --- a/apps/openmw/mwmechanics/summoning.cpp +++ b/apps/openmw/mwmechanics/summoning.cpp @@ -1,7 +1,5 @@ #include "summoning.hpp" -#include - #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index 7e3c27951..8cb31ed25 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -2,15 +2,13 @@ #define OPENMW_MWPHYSICS_PHYSICSSYSTEM_H #include +#include -#include - +#include #include #include "../mwworld/ptr.hpp" -#include - #include "collisiontype.hpp" namespace osg diff --git a/apps/openmw/mwscript/cellextensions.cpp b/apps/openmw/mwscript/cellextensions.cpp index 43d213c5a..8af2e5ef3 100644 --- a/apps/openmw/mwscript/cellextensions.cpp +++ b/apps/openmw/mwscript/cellextensions.cpp @@ -1,6 +1,7 @@ - #include "cellextensions.hpp" +#include + #include "../mwworld/esmstore.hpp" #include diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index 80f46e457..61a31e115 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -1,6 +1,6 @@ - #include "statsextensions.hpp" +#include #include #include diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 093506113..0f9faa11a 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -1,3 +1,5 @@ +#include + #include #include diff --git a/apps/openmw/mwsound/sound.hpp b/apps/openmw/mwsound/sound.hpp index bdc8cf459..96f59cea0 100644 --- a/apps/openmw/mwsound/sound.hpp +++ b/apps/openmw/mwsound/sound.hpp @@ -1,8 +1,6 @@ #ifndef GAME_SOUND_SOUND_H #define GAME_SOUND_SOUND_H -#include - #include "soundmanagerimp.hpp" namespace MWSound diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index b757b1c91..f6170da7f 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -3,8 +3,6 @@ #include -#include - #include #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 935718348..87325144a 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -14,11 +14,6 @@ namespace ESM struct ObjectState; } -namespace Ogre -{ - class Vector3; -} - namespace MWRender { class RenderingInterface; diff --git a/apps/openmw/mwworld/player.hpp b/apps/openmw/mwworld/player.hpp index 8d29163e6..2327b4dd5 100644 --- a/apps/openmw/mwworld/player.hpp +++ b/apps/openmw/mwworld/player.hpp @@ -6,8 +6,6 @@ #include "../mwmechanics/drawstate.hpp" -#include - namespace ESM { struct NPC; diff --git a/apps/openmw/mwworld/refdata.cpp b/apps/openmw/mwworld/refdata.cpp index 54860fc31..c4f63137a 100644 --- a/apps/openmw/mwworld/refdata.cpp +++ b/apps/openmw/mwworld/refdata.cpp @@ -1,8 +1,6 @@ #include "refdata.hpp" -#include - #include #include "customdata.hpp" diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 78d093104..62bc1f47e 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -1,6 +1,6 @@ #include "scene.hpp" -#include +#include #include #include diff --git a/apps/openmw/mwworld/scene.hpp b/apps/openmw/mwworld/scene.hpp index af0b82fc3..ca6ed83b9 100644 --- a/apps/openmw/mwworld/scene.hpp +++ b/apps/openmw/mwworld/scene.hpp @@ -13,11 +13,6 @@ namespace osg class Vec3f; } -namespace Ogre -{ - class Vector3; -} - namespace ESM { struct Position; diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index 77d961057..d7dfee99b 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -3,9 +3,8 @@ #include #include +#include -#include -#include #include #include "../mwbase/soundmanager.hpp" diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index bbc04ffdc..6b09fbb65 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -35,11 +35,6 @@ namespace Resource class ResourceSystem; } -namespace Ogre -{ - class Vector3; -} - namespace ESM { struct Position; diff --git a/cmake/FindMyGUI.cmake b/cmake/FindMyGUI.cmake index eccfb54ed..320765b53 100644 --- a/cmake/FindMyGUI.cmake +++ b/cmake/FindMyGUI.cmake @@ -84,7 +84,7 @@ ELSE (WIN32) #Unix STRING(REGEX REPLACE ".*/" "" MYGUI_LIBRARIES "${MYGUI_LIBRARIES}") ENDIF (MYGUI_INCLUDE_DIRS) ELSE (NOT APPLE) - SET(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} ${MYGUI_DEPENDENCIES_DIR} ${OGRE_DEPENDENCIES_DIR}) + SET(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} ${MYGUI_DEPENDENCIES_DIR}) FIND_PACKAGE(freetype) FIND_PATH(MYGUI_INCLUDE_DIRS MyGUI.h PATHS /usr/local/include /usr/include PATH_SUFFIXES MyGUI MYGUI) FIND_LIBRARY(MYGUI_LIBRARIES MyGUIEngineStatic PATHS /usr/lib /usr/local/lib) diff --git a/cmake/FindOGRE.cmake b/cmake/FindOGRE.cmake deleted file mode 100644 index f2acf9d33..000000000 --- a/cmake/FindOGRE.cmake +++ /dev/null @@ -1,568 +0,0 @@ -#------------------------------------------------------------------- -# This file is part of the CMake build system for OGRE -# (Object-oriented Graphics Rendering Engine) -# For the latest info, see http://www.ogre3d.org/ -# -# The contents of this file are placed in the public domain. Feel -# free to make use of it in any way you like. -#------------------------------------------------------------------- - -# - Try to find OGRE -# If you have multiple versions of Ogre installed, use the CMake or -# the environment variable OGRE_HOME to point to the path where the -# desired Ogre version can be found. -# By default this script will look for a dynamic Ogre build. If you -# need to link against static Ogre libraries, set the CMake variable -# OGRE_STATIC to TRUE. -# -# Once done, this will define -# -# OGRE_FOUND - system has OGRE -# OGRE_INCLUDE_DIRS - the OGRE include directories -# OGRE_LIBRARIES - link these to use the OGRE core -# OGRE_BINARY_REL - location of the main Ogre binary (win32 non-static only, release) -# OGRE_BINARY_DBG - location of the main Ogre binaries (win32 non-static only, debug) -# -# Additionally this script searches for the following optional -# parts of the Ogre package: -# Plugin_BSPSceneManager, Plugin_CgProgramManager, -# Plugin_OctreeSceneManager, Plugin_OctreeZone, -# Plugin_ParticleFX, Plugin_PCZSceneManager, -# RenderSystem_GL, RenderSystem_Direct3D9, RenderSystem_Direct3D10, -# Paging, Terrain -# -# For each of these components, the following variables are defined: -# -# OGRE_${COMPONENT}_FOUND - ${COMPONENT} is available -# OGRE_${COMPONENT}_INCLUDE_DIRS - additional include directories for ${COMPONENT} -# OGRE_${COMPONENT}_LIBRARIES - link these to use ${COMPONENT} -# OGRE_${COMPONENT}_BINARY_REL - location of the component binary (win32 non-static only, release) -# OGRE_${COMPONENT}_BINARY_DBG - location of the component binary (win32 non-static only, debug) -# -# Finally, the following variables are defined: -# -# OGRE_PLUGIN_DIR_REL - The directory where the release versions of -# the OGRE plugins are located -# OGRE_PLUGIN_DIR_DBG - The directory where the debug versions of -# the OGRE plugins are located -# OGRE_MEDIA_DIR - The directory where the OGRE sample media is -# located, if available - -include(FindPkgMacros) -include(PreprocessorUtils) -findpkg_begin(OGRE) - - -# Get path, convert backslashes as ${ENV_${var}} -getenv_path(OGRE_HOME) -getenv_path(OGRE_SDK) -getenv_path(OGRE_SOURCE) -getenv_path(OGRE_BUILD) -getenv_path(OGRE_DEPENDENCIES_DIR) -getenv_path(PROGRAMFILES) - -# Determine whether to search for a dynamic or static build -if (OGRE_STATIC) - set(OGRE_LIB_SUFFIX "Static") -else () - set(OGRE_LIB_SUFFIX "") -endif () - - -set(OGRE_LIBRARY_NAMES "OgreMain${OGRE_LIB_SUFFIX}") -get_debug_names(OGRE_LIBRARY_NAMES) - -# construct search paths from environmental hints and -# OS specific guesses -if (WIN32) - set(OGRE_PREFIX_GUESSES - ${ENV_PROGRAMFILES}/OGRE - C:/OgreSDK - ) -elseif (UNIX) - set(OGRE_PREFIX_GUESSES - /opt/ogre - /opt/OGRE - /usr/lib${LIB_SUFFIX}/ogre - /usr/lib${LIB_SUFFIX}/OGRE - /usr/local/lib${LIB_SUFFIX}/ogre - /usr/local/lib${LIB_SUFFIX}/OGRE - $ENV{HOME}/ogre - $ENV{HOME}/OGRE - ) -endif () -set(OGRE_PREFIX_PATH - ${OGRE_HOME} ${OGRE_SDK} ${ENV_OGRE_HOME} ${ENV_OGRE_SDK} - ${OGRE_PREFIX_GUESSES} -) -create_search_paths(OGRE) -# If both OGRE_BUILD and OGRE_SOURCE are set, prepare to find Ogre in a build dir -set(OGRE_PREFIX_SOURCE ${OGRE_SOURCE} ${ENV_OGRE_SOURCE}) -set(OGRE_PREFIX_BUILD ${OGRE_BUILD} ${ENV_OGRE_BUILD}) -set(OGRE_PREFIX_DEPENDENCIES_DIR ${OGRE_DEPENDENCIES_DIR} ${ENV_OGRE_DEPENDENCIES_DIR}) -if (OGRE_PREFIX_SOURCE AND OGRE_PREFIX_BUILD) - foreach(dir ${OGRE_PREFIX_SOURCE}) - set(OGRE_INC_SEARCH_PATH ${dir}/OgreMain/include ${dir}/Dependencies/include ${dir}/iPhoneDependencies/include ${OGRE_INC_SEARCH_PATH}) - set(OGRE_LIB_SEARCH_PATH ${dir}/lib ${dir}/Dependencies/lib ${dir}/iPhoneDependencies/lib ${OGRE_LIB_SEARCH_PATH}) - set(OGRE_BIN_SEARCH_PATH ${dir}/Samples/Common/bin ${OGRE_BIN_SEARCH_PATH}) - endforeach(dir) - foreach(dir ${OGRE_PREFIX_BUILD}) - set(OGRE_INC_SEARCH_PATH ${dir}/include ${OGRE_INC_SEARCH_PATH}) - set(OGRE_LIB_SEARCH_PATH ${dir}/lib ${OGRE_LIB_SEARCH_PATH}) - set(OGRE_BIN_SEARCH_PATH ${dir}/bin ${OGRE_BIN_SEARCH_PATH}) - set(OGRE_BIN_SEARCH_PATH ${dir}/Samples/Common/bin ${OGRE_BIN_SEARCH_PATH}) - endforeach(dir) - - if (OGRE_PREFIX_DEPENDENCIES_DIR) - set(OGRE_INC_SEARCH_PATH ${OGRE_PREFIX_DEPENDENCIES_DIR}/include ${OGRE_INC_SEARCH_PATH}) - set(OGRE_LIB_SEARCH_PATH ${OGRE_PREFIX_DEPENDENCIES_DIR}/lib ${OGRE_LIB_SEARCH_PATH}) - set(OGRE_BIN_SEARCH_PATH ${OGRE_PREFIX_DEPENDENCIES_DIR}/bin ${OGRE_BIN_SEARCH_PATH}) - endif() -else() - set(OGRE_PREFIX_SOURCE "NOTFOUND") - set(OGRE_PREFIX_BUILD "NOTFOUND") -endif () - -# redo search if any of the environmental hints changed -set(OGRE_COMPONENTS Paging Terrain Overlay - Plugin_BSPSceneManager Plugin_CgProgramManager Plugin_OctreeSceneManager - Plugin_OctreeZone Plugin_PCZSceneManager Plugin_ParticleFX - RenderSystem_Direct3D10 RenderSystem_Direct3D9 RenderSystem_GL RenderSystem_GLES2) -set(OGRE_RESET_VARS - OGRE_CONFIG_INCLUDE_DIR OGRE_INCLUDE_DIR - OGRE_LIBRARY_FWK OGRE_LIBRARY_REL OGRE_LIBRARY_DBG - OGRE_PLUGIN_DIR_DBG OGRE_PLUGIN_DIR_REL OGRE_MEDIA_DIR) -foreach (comp ${OGRE_COMPONENTS}) - set(OGRE_RESET_VARS ${OGRE_RESET_VARS} - OGRE_${comp}_INCLUDE_DIR OGRE_${comp}_LIBRARY_FWK - OGRE_${comp}_LIBRARY_DBG OGRE_${comp}_LIBRARY_REL - ) -endforeach (comp) -set(OGRE_PREFIX_WATCH ${OGRE_PREFIX_PATH} ${OGRE_PREFIX_SOURCE} ${OGRE_PREFIX_BUILD}) -clear_if_changed(OGRE_PREFIX_WATCH ${OGRE_RESET_VARS}) - -# try to locate Ogre via pkg-config -use_pkgconfig(OGRE_PKGC "OGRE${OGRE_LIB_SUFFIX}") - -if(NOT OGRE_BUILD_PLATFORM_IPHONE AND APPLE) - # try to find framework on OSX - findpkg_framework(OGRE) -else() - set(OGRE_LIBRARY_FWK "") -endif() - -# locate Ogre include files -find_path(OGRE_CONFIG_INCLUDE_DIR NAMES OgreBuildSettings.h HINTS ${OGRE_INC_SEARCH_PATH} ${OGRE_FRAMEWORK_INCLUDES} ${OGRE_PKGC_INCLUDE_DIRS} PATH_SUFFIXES "OGRE") -find_path(OGRE_INCLUDE_DIR NAMES OgreRoot.h HINTS ${OGRE_CONFIG_INCLUDE_DIR} ${OGRE_INC_SEARCH_PATH} ${OGRE_FRAMEWORK_INCLUDES} ${OGRE_PKGC_INCLUDE_DIRS} PATH_SUFFIXES "OGRE") -set(OGRE_INCOMPATIBLE FALSE) - -if (OGRE_INCLUDE_DIR) - if (NOT OGRE_CONFIG_INCLUDE_DIR) - set(OGRE_CONFIG_INCLUDE_DIR ${OGRE_INCLUDE_DIR}) - endif () - # determine Ogre version - file(READ ${OGRE_INCLUDE_DIR}/OgrePrerequisites.h OGRE_TEMP_VERSION_CONTENT) - get_preprocessor_entry(OGRE_TEMP_VERSION_CONTENT OGRE_VERSION_MAJOR OGRE_VERSION_MAJOR) - get_preprocessor_entry(OGRE_TEMP_VERSION_CONTENT OGRE_VERSION_MINOR OGRE_VERSION_MINOR) - get_preprocessor_entry(OGRE_TEMP_VERSION_CONTENT OGRE_VERSION_PATCH OGRE_VERSION_PATCH) - get_preprocessor_entry(OGRE_TEMP_VERSION_CONTENT OGRE_VERSION_NAME OGRE_VERSION_NAME) - set(OGRE_VERSION "${OGRE_VERSION_MAJOR}.${OGRE_VERSION_MINOR}.${OGRE_VERSION_PATCH}") - pkg_message(OGRE "Found Ogre ${OGRE_VERSION_NAME} (${OGRE_VERSION})") - - # determine configuration settings - set(OGRE_CONFIG_HEADERS - ${OGRE_CONFIG_INCLUDE_DIR}/OgreBuildSettings.h - ${OGRE_CONFIG_INCLUDE_DIR}/OgreConfig.h - ) - foreach(CFG_FILE ${OGRE_CONFIG_HEADERS}) - if (EXISTS ${CFG_FILE}) - set(OGRE_CONFIG_HEADER ${CFG_FILE}) - break() - endif() - endforeach() - if (OGRE_CONFIG_HEADER) - file(READ ${OGRE_CONFIG_HEADER} OGRE_TEMP_CONFIG_CONTENT) - has_preprocessor_entry(OGRE_TEMP_CONFIG_CONTENT OGRE_STATIC_LIB OGRE_CONFIG_STATIC) - get_preprocessor_entry(OGRE_TEMP_CONFIG_CONTENT OGRE_THREAD_SUPPORT OGRE_CONFIG_THREADS) - get_preprocessor_entry(OGRE_TEMP_CONFIG_CONTENT OGRE_THREAD_PROVIDER OGRE_CONFIG_THREAD_PROVIDER) - get_preprocessor_entry(OGRE_TEMP_CONFIG_CONTENT OGRE_NO_FREEIMAGE OGRE_CONFIG_FREEIMAGE) - if (OGRE_CONFIG_STATIC AND OGRE_STATIC) - elseif (OGRE_CONFIG_STATIC OR OGRE_STATIC) - pkg_message(OGRE "Build type (static, dynamic) does not match the requested one.") - set(OGRE_INCOMPATIBLE TRUE) - endif () - else () - pkg_message(OGRE "Could not determine Ogre build configuration.") - set(OGRE_INCOMPATIBLE TRUE) - endif () -else () - set(OGRE_INCOMPATIBLE FALSE) -endif () - -find_library(OGRE_LIBRARY_REL NAMES ${OGRE_LIBRARY_NAMES} HINTS ${OGRE_LIB_SEARCH_PATH} ${OGRE_PKGC_LIBRARY_DIRS} ${OGRE_FRAMEWORK_SEARCH_PATH} PATH_SUFFIXES "" "release" "relwithdebinfo" "minsizerel") -find_library(OGRE_LIBRARY_DBG NAMES ${OGRE_LIBRARY_NAMES_DBG} HINTS ${OGRE_LIB_SEARCH_PATH} ${OGRE_PKGC_LIBRARY_DIRS} ${OGRE_FRAMEWORK_SEARCH_PATH} PATH_SUFFIXES "" "debug") -make_library_set(OGRE_LIBRARY) - -if(APPLE) - set(OGRE_LIBRARY_DBG ${OGRE_LIB_SEARCH_PATH}) -endif() -if (OGRE_INCOMPATIBLE) - set(OGRE_LIBRARY "NOTFOUND") -endif () - -set(OGRE_INCLUDE_DIR ${OGRE_CONFIG_INCLUDE_DIR} ${OGRE_INCLUDE_DIR}) -list(REMOVE_DUPLICATES OGRE_INCLUDE_DIR) -findpkg_finish(OGRE) -add_parent_dir(OGRE_INCLUDE_DIRS OGRE_INCLUDE_DIR) -if (OGRE_SOURCE) - # If working from source rather than SDK, add samples include - set(OGRE_INCLUDE_DIRS ${OGRE_INCLUDE_DIRS} "${OGRE_SOURCE}/Samples/Common/include") -endif() - -mark_as_advanced(OGRE_CONFIG_INCLUDE_DIR OGRE_MEDIA_DIR OGRE_PLUGIN_DIR_REL OGRE_PLUGIN_DIR_DBG) - -if (NOT OGRE_FOUND) - return() -endif () - - -# look for required Ogre dependencies in case of static build and/or threading -if (OGRE_STATIC) - set(OGRE_DEPS_FOUND TRUE) - find_package(Cg QUIET) - find_package(DirectX QUIET) - find_package(FreeImage QUIET) - find_package(Freetype QUIET) - find_package(OpenGL QUIET) - find_package(OpenGLES2 QUIET) - find_package(ZLIB QUIET) - find_package(ZZip QUIET) - if (UNIX AND (NOT APPLE AND NOT ANDROID)) - find_package(X11 QUIET) - find_library(XAW_LIBRARY NAMES Xaw Xaw7 PATHS ${DEP_LIB_SEARCH_DIR} ${X11_LIB_SEARCH_PATH}) - if (NOT XAW_LIBRARY OR NOT X11_Xt_FOUND) - set(X11_FOUND FALSE) - endif () - endif () - if (APPLE AND NOT OGRE_BUILD_PLATFORM_IPHONE) - find_package(Cocoa QUIET) - find_package(Carbon QUIET) - if (NOT Cocoa_FOUND OR NOT Carbon_FOUND) - set(OGRE_DEPS_FOUND FALSE) - endif () - endif () - if (APPLE AND OGRE_BUILD_PLATFORM_IPHONE) - find_package(iPhoneSDK QUIET) - if (NOT iPhoneSDK_FOUND) - set(OGRE_DEPS_FOUND FALSE) - endif () - endif () - -if (ANDROID) - set(OGRE_LIBRARIES ${OGRE_LIBRARIES} ${OGRE_LIBRARY_FWK} ${ZZip_LIBRARIES} ${ZLIB_LIBRARIES} - ${FreeImage_LIBRARIES} ${FREETYPE_LIBRARIES} - ${Cocoa_LIBRARIES} ${Carbon_LIBRARIES}) -else () - set(OGRE_LIBRARIES ${OGRE_LIBRARIES} ${OGRE_LIBRARY_FWK} ${ZZip_LIBRARIES} ${ZLIB_LIBRARIES} - ${FreeImage_LIBRARIES} ${FREETYPE_LIBRARIES} - ${X11_LIBRARIES} ${X11_Xt_LIBRARIES} ${XAW_LIBRARY} ${X11_Xrandr_LIB} - ${Cocoa_LIBRARIES} ${Carbon_LIBRARIES}) -endif() - - if (NOT ZLIB_FOUND OR NOT ZZip_FOUND) - set(OGRE_DEPS_FOUND FALSE) - endif () - if (NOT FreeImage_FOUND AND NOT OGRE_CONFIG_FREEIMAGE) - set(OGRE_DEPS_FOUND FALSE) - endif () - if (NOT FREETYPE_FOUND) - set(OGRE_DEPS_FOUND FALSE) - endif () - if (UNIX AND NOT APPLE AND NOT ANDROID) - if (NOT X11_FOUND) - set(OGRE_DEPS_FOUND FALSE) - endif () - endif () - - if (OGRE_CONFIG_THREADS) - if (OGRE_CONFIG_THREAD_PROVIDER EQUAL 1) - find_package(Boost COMPONENTS thread QUIET) - if (NOT Boost_THREAD_FOUND) - set(OGRE_DEPS_FOUND FALSE) - else () - set(OGRE_LIBRARIES ${OGRE_LIBRARIES} ${Boost_LIBRARIES}) - set(OGRE_INCLUDE_DIRS ${OGRE_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS}) - endif () - elseif (OGRE_CONFIG_THREAD_PROVIDER EQUAL 2) - find_package(POCO QUIET) - if (NOT POCO_FOUND) - set(OGRE_DEPS_FOUND FALSE) - else () - set(OGRE_LIBRARIES ${OGRE_LIBRARIES} ${POCO_LIBRARIES}) - set(OGRE_INCLUDE_DIRS ${OGRE_INCLUDE_DIRS} ${POCO_INCLUDE_DIRS}) - endif () - elseif (OGRE_CONFIG_THREAD_PROVIDER EQUAL 3) - find_package(TBB QUIET) - if (NOT TBB_FOUND) - set(OGRE_DEPS_FOUND FALSE) - else () - set(OGRE_LIBRARIES ${OGRE_LIBRARIES} ${TBB_LIBRARIES}) - set(OGRE_INCLUDE_DIRS ${OGRE_INCLUDE_DIRS} ${TBB_INCLUDE_DIRS}) - endif () - endif () - endif () - - if (NOT OGRE_DEPS_FOUND) - pkg_message(OGRE "Could not find all required dependencies for the Ogre package.") - set(OGRE_FOUND FALSE) - endif () -endif () - -if (NOT OGRE_FOUND) - return() -endif () - - -get_filename_component(OGRE_LIBRARY_DIR_REL "${OGRE_LIBRARY_REL}" PATH) -get_filename_component(OGRE_LIBRARY_DIR_DBG "${OGRE_LIBRARY_DBG}" PATH) -set(OGRE_LIBRARY_DIRS ${OGRE_LIBRARY_DIR_REL} ${OGRE_LIBRARY_DIR_DBG}) - -# find binaries -if (NOT OGRE_STATIC) - if (WIN32) - find_file(OGRE_BINARY_REL NAMES "OgreMain.dll" HINTS ${OGRE_BIN_SEARCH_PATH} - PATH_SUFFIXES "" release relwithdebinfo minsizerel) - find_file(OGRE_BINARY_DBG NAMES "OgreMain_d.dll" HINTS ${OGRE_BIN_SEARCH_PATH} - PATH_SUFFIXES "" debug ) - endif() - mark_as_advanced(OGRE_BINARY_REL OGRE_BINARY_DBG) -endif() - - -######################################################### -# Find Ogre components -######################################################### - -set(OGRE_COMPONENT_SEARCH_PATH_REL - ${OGRE_LIBRARY_DIR_REL}/.. - ${OGRE_LIBRARY_DIR_REL}/../.. - ${OGRE_BIN_SEARCH_PATH} -) -set(OGRE_COMPONENT_SEARCH_PATH_DBG - ${OGRE_LIBRARY_DIR_DBG}/.. - ${OGRE_LIBRARY_DIR_DBG}/../.. - ${OGRE_BIN_SEARCH_PATH} -) - -macro(ogre_find_component COMPONENT HEADER) - findpkg_begin(OGRE_${COMPONENT}) - find_path(OGRE_${COMPONENT}_INCLUDE_DIR NAMES ${HEADER} HINTS ${OGRE_INCLUDE_DIRS} ${OGRE_INCLUDE_DIR}/OGRE/${COMPONENT} ${OGRE_PREFIX_SOURCE} PATH_SUFFIXES ${COMPONENT} OGRE/${COMPONENT} Components/${COMPONENT}/include) - set(OGRE_${COMPONENT}_LIBRARY_NAMES "Ogre${COMPONENT}${OGRE_LIB_SUFFIX}") - get_debug_names(OGRE_${COMPONENT}_LIBRARY_NAMES) - find_library(OGRE_${COMPONENT}_LIBRARY_REL NAMES ${OGRE_${COMPONENT}_LIBRARY_NAMES} HINTS ${OGRE_LIBRARY_DIR_REL} PATH_SUFFIXES "" "release" "relwithdebinfo" "minsizerel") - find_library(OGRE_${COMPONENT}_LIBRARY_DBG NAMES ${OGRE_${COMPONENT}_LIBRARY_NAMES_DBG} HINTS ${OGRE_LIBRARY_DIR_DBG} PATH_SUFFIXES "" "debug") - make_library_set(OGRE_${COMPONENT}_LIBRARY) - findpkg_finish(OGRE_${COMPONENT}) - if (OGRE_${COMPONENT}_FOUND) - if (APPLE) - include_directories("${OGRE_INCLUDE_DIR}/OGRE/${COMPONENT}") - endif() - # find binaries - if (NOT OGRE_STATIC) - if (WIN32) - find_file(OGRE_${COMPONENT}_BINARY_REL NAMES "Ogre${COMPONENT}.dll" HINTS ${OGRE_COMPONENT_SEARCH_PATH_REL} PATH_SUFFIXES "" bin bin/release bin/relwithdebinfo bin/minsizerel release) - find_file(OGRE_${COMPONENT}_BINARY_DBG NAMES "Ogre${COMPONENT}_d.dll" HINTS ${OGRE_COMPONENT_SEARCH_PATH_DBG} PATH_SUFFIXES "" bin bin/debug debug) - endif() - mark_as_advanced(OGRE_${COMPONENT}_BINARY_REL OGRE_${COMPONENT}_BINARY_DBG) - endif() - endif() -endmacro() - -# look for Paging component -ogre_find_component(Paging OgrePaging.h) -# look for Overlay component -ogre_find_component(Overlay OgreOverlaySystem.h) -# look for Terrain component -ogre_find_component(Terrain OgreTerrain.h) -# look for Property component -ogre_find_component(Property OgreProperty.h) -# look for RTShaderSystem component -ogre_find_component(RTShaderSystem OgreRTShaderSystem.h) - - -######################################################### -# Find Ogre plugins -######################################################### - -macro(ogre_find_plugin PLUGIN HEADER) - # On Unix, the plugins might have no prefix - if (CMAKE_FIND_LIBRARY_PREFIXES) - set(TMP_CMAKE_LIB_PREFIX ${CMAKE_FIND_LIBRARY_PREFIXES}) - set(CMAKE_FIND_LIBRARY_PREFIXES ${CMAKE_FIND_LIBRARY_PREFIXES} "") - endif() - - # strip RenderSystem_ or Plugin_ prefix from plugin name - string(REPLACE "RenderSystem_" "" PLUGIN_TEMP ${PLUGIN}) - string(REPLACE "Plugin_" "" PLUGIN_NAME ${PLUGIN_TEMP}) - - # header files for plugins are not usually needed, but find them anyway if they are present - set(OGRE_PLUGIN_PATH_SUFFIXES - PlugIns PlugIns/${PLUGIN_NAME} Plugins Plugins/${PLUGIN_NAME} ${PLUGIN} - RenderSystems RenderSystems/${PLUGIN_NAME} ${ARGN}) - find_path(OGRE_${PLUGIN}_INCLUDE_DIR NAMES ${HEADER} - HINTS ${OGRE_INCLUDE_DIRS} ${OGRE_PREFIX_SOURCE} - PATH_SUFFIXES ${OGRE_PLUGIN_PATH_SUFFIXES}) - # find link libraries for plugins - set(OGRE_${PLUGIN}_LIBRARY_NAMES "${PLUGIN}${OGRE_LIB_SUFFIX}") - get_debug_names(OGRE_${PLUGIN}_LIBRARY_NAMES) - set(OGRE_${PLUGIN}_LIBRARY_FWK ${OGRE_LIBRARY_FWK}) - # Search for release plugins in OGRE dir with version suffix - find_library(OGRE_${PLUGIN}_LIBRARY_REL NAMES ${OGRE_${PLUGIN}_LIBRARY_NAMES} - HINTS ${OGRE_LIBRARY_DIRS} PATH_SUFFIXES "" OGRE-${OGRE_VERSION} opt release release/opt relwithdebinfo relwithdebinfo/opt minsizerel minsizerel/opt) - if(NOT EXISTS "${OGRE_${PLUGIN}_LIBRARY_REL}") - # Search for release plugins in OGRE dir without version suffix - find_library(OGRE_${PLUGIN}_LIBRARY_REL NAMES ${OGRE_${PLUGIN}_LIBRARY_NAMES} - HINTS ${OGRE_LIBRARY_DIRS} PATH_SUFFIXES "" OGRE opt release release/opt relwithdebinfo relwithdebinfo/opt minsizerel minsizerel/opt) - endif() - # Search for debug plugins in OGRE dir with version suffix - find_library(OGRE_${PLUGIN}_LIBRARY_DBG NAMES ${OGRE_${PLUGIN}_LIBRARY_NAMES_DBG} - HINTS ${OGRE_LIBRARY_DIRS} PATH_SUFFIXES "" OGRE-${OGRE_VERSION} opt debug debug/opt) - if(NOT EXISTS "${OGRE_${PLUGIN}_LIBRARY_DBG}") - # Search for debug plugins in OGRE dir without version suffix - find_library(OGRE_${PLUGIN}_LIBRARY_DBG NAMES ${OGRE_${PLUGIN}_LIBRARY_NAMES_DBG} - HINTS ${OGRE_LIBRARY_DIRS} PATH_SUFFIXES "" OGRE opt debug debug/opt) - endif() - make_library_set(OGRE_${PLUGIN}_LIBRARY) - - if (OGRE_${PLUGIN}_LIBRARY OR OGRE_${PLUGIN}_INCLUDE_DIR) - set(OGRE_${PLUGIN}_FOUND TRUE) - if (OGRE_${PLUGIN}_INCLUDE_DIR) - set(OGRE_${PLUGIN}_INCLUDE_DIRS ${OGRE_${PLUGIN}_INCLUDE_DIR}) - endif() - set(OGRE_${PLUGIN}_LIBRARIES ${OGRE_${PLUGIN}_LIBRARY}) - endif () - - mark_as_advanced(OGRE_${PLUGIN}_INCLUDE_DIR OGRE_${PLUGIN}_LIBRARY_REL OGRE_${PLUGIN}_LIBRARY_DBG OGRE_${PLUGIN}_LIBRARY_FWK) - - # look for plugin dirs - if (OGRE_${PLUGIN}_FOUND) - if (NOT OGRE_PLUGIN_DIR_REL OR NOT OGRE_PLUGIN_DIR_DBG) - if (WIN32) - set(OGRE_PLUGIN_SEARCH_PATH_REL - ${OGRE_LIBRARY_DIR_REL}/.. - ${OGRE_LIBRARY_DIR_REL}/../.. - ${OGRE_BIN_SEARCH_PATH} - ) - set(OGRE_PLUGIN_SEARCH_PATH_DBG - ${OGRE_LIBRARY_DIR_DBG}/.. - ${OGRE_LIBRARY_DIR_DBG}/../.. - ${OGRE_BIN_SEARCH_PATH} - ) - find_path(OGRE_PLUGIN_DIR_REL NAMES "${PLUGIN}.dll" HINTS ${OGRE_PLUGIN_SEARCH_PATH_REL} - PATH_SUFFIXES "" bin bin/release bin/relwithdebinfo bin/minsizerel release) - find_path(OGRE_PLUGIN_DIR_DBG NAMES "${PLUGIN}_d.dll" HINTS ${OGRE_PLUGIN_SEARCH_PATH_DBG} - PATH_SUFFIXES "" bin bin/debug debug) - elseif (UNIX) - get_filename_component(OGRE_PLUGIN_DIR_TMP ${OGRE_${PLUGIN}_LIBRARY_REL} PATH) - # For some reason this fails - #set(OGRE_PLUGIN_DIR_REL ${OGRE_PLUGIN_DIR_TMP} CACHE STRING "Ogre plugin dir (release)") - set(OGRE_PLUGIN_DIR_REL ${OGRE_PLUGIN_DIR_TMP}) - get_filename_component(OGRE_PLUGIN_DIR_TMP ${OGRE_${PLUGIN}_LIBRARY_DBG} PATH) - # Same here - #set(OGRE_PLUGIN_DIR_DBG ${OGRE_PLUGIN_DIR_TMP} CACHE STRING "Ogre plugin dir (debug)") - set(OGRE_PLUGIN_DIR_DBG ${OGRE_PLUGIN_DIR_TMP}) - endif () - endif () - - # find binaries - if (NOT OGRE_STATIC) - if (WIN32) - find_file(OGRE_${PLUGIN}_REL NAMES "${PLUGIN}.dll" HINTS ${OGRE_PLUGIN_DIR_REL}) - find_file(OGRE_${PLUGIN}_DBG NAMES "${PLUGIN}_d.dll" HINTS ${OGRE_PLUGIN_DIR_DBG}) - endif() - mark_as_advanced(OGRE_${PLUGIN}_REL OGRE_${PLUGIN}_DBG) - endif() - - endif () - - if (TMP_CMAKE_LIB_PREFIX) - set(CMAKE_FIND_LIBRARY_PREFIXES ${TMP_CMAKE_LIB_PREFIX}) - endif () -endmacro(ogre_find_plugin) - -ogre_find_plugin(Plugin_PCZSceneManager OgrePCZSceneManager.h PCZ PlugIns/PCZSceneManager/include) -ogre_find_plugin(Plugin_OctreeZone OgreOctreeZone.h PCZ PlugIns/OctreeZone/include) -ogre_find_plugin(Plugin_BSPSceneManager OgreBspSceneManager.h PlugIns/BSPSceneManager/include) -ogre_find_plugin(Plugin_CgProgramManager OgreCgProgram.h PlugIns/CgProgramManager/include) -ogre_find_plugin(Plugin_OctreeSceneManager OgreOctreeSceneManager.h PlugIns/OctreeSceneManager/include) -ogre_find_plugin(Plugin_ParticleFX OgreParticleFXPrerequisites.h PlugIns/ParticleFX/include) -ogre_find_plugin(RenderSystem_GL OgreGLRenderSystem.h RenderSystems/GL/include) -ogre_find_plugin(RenderSystem_GLES2 OgreGLES2RenderSystem.h RenderSystems/GLES2/include) -ogre_find_plugin(RenderSystem_Direct3D9 OgreD3D9RenderSystem.h RenderSystems/Direct3D9/include) -ogre_find_plugin(RenderSystem_Direct3D10 OgreD3D10RenderSystem.h RenderSystems/Direct3D10/include) -ogre_find_plugin(RenderSystem_Direct3D11 OgreD3D11RenderSystem.h RenderSystems/Direct3D11/include) - -if (OGRE_STATIC) - # check if dependencies for plugins are met - if (NOT DirectX9_FOUND) - set(OGRE_RenderSystem_Direct3D9_FOUND FALSE) - else () - set(OGRE_INCLUDE_DIRS ${OGRE_INCLUDE_DIRS} ${DirectX9_INCLUDE_DIR}) - endif () - if (NOT DirectX_D3D10_FOUND) - set(OGRE_RenderSystem_Direct3D10_FOUND FALSE) - endif () - if (NOT DirectX_D3D11_FOUND) - set(OGRE_RenderSystem_Direct3D11_FOUND FALSE) - else () - set(OGRE_INCLUDE_DIRS ${OGRE_INCLUDE_DIRS} ${DirectX_D3D11_INCLUDE_DIR}) - endif () - if (NOT OPENGL_FOUND) - set(OGRE_RenderSystem_GL_FOUND FALSE) - endif () - if (NOT OPENGLES_FOUND AND NOT OPENGLES2_FOUND) - set(OGRE_RenderSystem_GLES_FOUND FALSE) - endif () - if (NOT Cg_FOUND) - set(OGRE_Plugin_CgProgramManager_FOUND FALSE) - endif () - - set(OGRE_RenderSystem_Direct3D9_LIBRARIES ${OGRE_RenderSystem_Direct3D9_LIBRARIES} - ${DirectX9_LIBRARIES} - ) - set(OGRE_RenderSystem_Direct3D10_LIBRARIES ${OGRE_RenderSystem_Direct3D10_LIBRARIES} - ${DirectX_D3D10_LIBRARIES} - ) - set(OGRE_RenderSystem_Direct3D11_LIBRARIES ${OGRE_RenderSystem_Direct3D11_LIBRARIES} - ${DirectX_D3D11_LIBRARIES} - ) - set(OGRE_RenderSystem_GL_LIBRARIES ${OGRE_RenderSystem_GL_LIBRARIES} - ${OPENGL_LIBRARIES} - ) - set(OGRE_RenderSystem_GLES2_LIBRARIES ${OGRE_RenderSystem_GLES2_LIBRARIES} - ${OPENGLES2_LIBRARIES} - ) - set(OGRE_Plugin_CgProgramManager_LIBRARIES ${OGRE_Plugin_CgProgramManager_LIBRARIES} - ${Cg_LIBRARIES} - ) -endif () - -# look for the media directory -set(OGRE_MEDIA_SEARCH_PATH - ${OGRE_SOURCE} - ${OGRE_LIBRARY_DIR_REL}/.. - ${OGRE_LIBRARY_DIR_DBG}/.. - ${OGRE_LIBRARY_DIR_REL}/../.. - ${OGRE_LIBRARY_DIR_DBG}/../.. - ${OGRE_PREFIX_SOURCE} -) -set(OGRE_MEDIA_SEARCH_SUFFIX - Samples/Media - Media - media - share/OGRE/media -) - -clear_if_changed(OGRE_PREFIX_WATCH OGRE_MEDIA_DIR) -find_path(OGRE_MEDIA_DIR NAMES packs/cubemapsJS.zip HINTS ${OGRE_MEDIA_SEARCH_PATH} - PATHS ${OGRE_PREFIX_PATH} PATH_SUFFIXES ${OGRE_MEDIA_SEARCH_SUFFIX}) diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 7b0094b3f..5a4ec605b 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -174,7 +174,6 @@ add_library(components STATIC ${COMPONENT_FILES} ${MOC_SRCS} ${ESM_UI_HDR}) target_link_libraries(components ${Boost_LIBRARIES} - ${OGRE_LIBRARIES} ${OPENSCENEGRAPH_LIBRARIES} ${BULLET_LIBRARIES} ${SDL2_LIBRARY} diff --git a/components/esm/util.hpp b/components/esm/util.hpp index 3ab2ef049..a80df2456 100644 --- a/components/esm/util.hpp +++ b/components/esm/util.hpp @@ -1,9 +1,6 @@ #ifndef OPENMW_ESM_UTIL_H #define OPENMW_ESM_UTIL_H -#include -#include - #include #include From 7991ea25c07b1f19163950e686bff41039be9edb Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Jun 2015 23:32:49 +0200 Subject: [PATCH 1403/3725] Potentially missing includes --- extern/osg-ffmpeg-videoplayer/videoplayer.cpp | 2 ++ extern/osg-ffmpeg-videoplayer/videostate.hpp | 2 ++ 2 files changed, 4 insertions(+) diff --git a/extern/osg-ffmpeg-videoplayer/videoplayer.cpp b/extern/osg-ffmpeg-videoplayer/videoplayer.cpp index 9bd4a2df3..9ec815130 100644 --- a/extern/osg-ffmpeg-videoplayer/videoplayer.cpp +++ b/extern/osg-ffmpeg-videoplayer/videoplayer.cpp @@ -1,5 +1,7 @@ #include "videoplayer.hpp" +#include + #include #include "audiofactory.hpp" diff --git a/extern/osg-ffmpeg-videoplayer/videostate.hpp b/extern/osg-ffmpeg-videoplayer/videostate.hpp index 4a4f2fc6b..72a2aab18 100644 --- a/extern/osg-ffmpeg-videoplayer/videostate.hpp +++ b/extern/osg-ffmpeg-videoplayer/videostate.hpp @@ -1,6 +1,8 @@ #ifndef VIDEOPLAYER_VIDEOSTATE_H #define VIDEOPLAYER_VIDEOSTATE_H +#include + #include #include From 60ad5680049d4670a89148b0fb3b06a6a2cc5de0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Jun 2015 23:46:04 +0200 Subject: [PATCH 1404/3725] Another missing include --- extern/osg-ffmpeg-videoplayer/videostate.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/extern/osg-ffmpeg-videoplayer/videostate.cpp b/extern/osg-ffmpeg-videoplayer/videostate.cpp index 1b02e13be..8a9cce1b7 100644 --- a/extern/osg-ffmpeg-videoplayer/videostate.cpp +++ b/extern/osg-ffmpeg-videoplayer/videostate.cpp @@ -1,5 +1,7 @@ #include "videostate.hpp" +#include + #ifndef __STDC_CONSTANT_MACROS #define __STDC_CONSTANT_MACROS #endif From 7fe86a7fe090b3b1418868d0fb073f44f0c76af3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 4 Jun 2015 00:08:28 +0200 Subject: [PATCH 1405/3725] Adjust travis config -ogre, -boost_wave, +osg --- CI/before_install.linux.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CI/before_install.linux.sh b/CI/before_install.linux.sh index 27cb71463..5823825ae 100755 --- a/CI/before_install.linux.sh +++ b/CI/before_install.linux.sh @@ -12,9 +12,9 @@ echo "yes" | sudo add-apt-repository "deb http://archive.ubuntu.com/ubuntu `lsb_ echo "yes" | sudo apt-add-repository ppa:openmw/openmw sudo apt-get update -qq sudo apt-get install -qq libgtest-dev google-mock -sudo apt-get install -qq libboost-filesystem-dev libboost-program-options-dev libboost-system-dev libboost-thread-dev libboost-wave-dev +sudo apt-get install -qq libboost-filesystem-dev libboost-program-options-dev libboost-system-dev libboost-thread-dev sudo apt-get install -qq libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libavresample-dev -sudo apt-get install -qq libbullet-dev libogre-1.9-dev libmygui-dev libsdl2-dev libunshield-dev libtinyxml-dev libopenal-dev libqt4-dev +sudo apt-get install -qq libbullet-dev libopenscenegraph-dev libmygui-dev libsdl2-dev libunshield-dev libtinyxml-dev libopenal-dev libqt4-dev if [ "${ANALYZE}" ]; then sudo apt-get install -qq clang-3.6; fi sudo mkdir /usr/src/gtest/build cd /usr/src/gtest/build From 58917bcca61e8346450045443719fff518b66ecb Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 4 Jun 2015 00:28:09 +0200 Subject: [PATCH 1406/3725] Minor cleanup --- CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8dbad2924..9f47b5fae 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -188,7 +188,6 @@ include_directories("." SYSTEM ${SDL2_INCLUDE_DIR} ${Boost_INCLUDE_DIR} - ${PLATFORM_INCLUDE_DIR} ${MYGUI_INCLUDE_DIRS} ${OPENAL_INCLUDE_DIR} ${BULLET_INCLUDE_DIRS} From 7ac4b2bb66e8915e335c5e3ef21fb100e8c1bdb9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 4 Jun 2015 01:16:52 +0200 Subject: [PATCH 1407/3725] Fix for travis build issue --- extern/osg-ffmpeg-videoplayer/videoplayer.hpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/extern/osg-ffmpeg-videoplayer/videoplayer.hpp b/extern/osg-ffmpeg-videoplayer/videoplayer.hpp index b886257e7..79f9edb1c 100644 --- a/extern/osg-ffmpeg-videoplayer/videoplayer.hpp +++ b/extern/osg-ffmpeg-videoplayer/videoplayer.hpp @@ -1,6 +1,14 @@ #ifndef VIDEOPLAYER_H #define VIDEOPLAYER_H +// FIXME: This can't be right? The ffmpeg headers refuse to build without UINT64_C, +// which only gets defined in stdint.h in either C99 mode or with this macro +// defined... +#ifndef __STDC_CONSTANT_MACROS +#define __STDC_CONSTANT_MACROS +#endif +#include + #include #include From 91eea1258c67c314fbe24bb158eee3306d3bee5f Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 4 Jun 2015 01:30:16 +0200 Subject: [PATCH 1408/3725] doc.hpp fix --- apps/openmw/doc.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/doc.hpp b/apps/openmw/doc.hpp index 978f0f5fb..ffeef94e1 100644 --- a/apps/openmw/doc.hpp +++ b/apps/openmw/doc.hpp @@ -25,7 +25,7 @@ /// \namespace MWRender /// \ingroup openmw -/// \brief Rendering via Ogre +/// \brief Rendering /// \namespace MWWorld /// \ingroup openmw From a2e211675d622a139142613b2671d2c32a35e75c Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 4 Jun 2015 02:35:52 +0200 Subject: [PATCH 1409/3725] Update openmw_layers.xml to newer version --- files/mygui/openmw_layers.xml | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/files/mygui/openmw_layers.xml b/files/mygui/openmw_layers.xml index 50f83aaa2..cf577aec5 100644 --- a/files/mygui/openmw_layers.xml +++ b/files/mygui/openmw_layers.xml @@ -1,17 +1,17 @@ - - - - - - - - - - - - - - + + + + + + + + + + + + + + From b6aed649824c355f81440d7fd0e3a2eea7c9a311 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 4 Jun 2015 15:41:49 +0200 Subject: [PATCH 1410/3725] Asking travis for a test run now that OSG 3.2 is in our PPA --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 1fc85dca3..7b5155137 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,6 +5,7 @@ language: cpp branches: only: - master + - osg - coverity_scan - /openmw-.*$/ env: From 71509d249732688cec57266ec2574ba373ace208 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 4 Jun 2015 15:59:24 +0200 Subject: [PATCH 1411/3725] Remove cmake script Ogre leftovers --- cmake/COPYING-CMAKE-SCRIPTS | 2 +- cmake/FindCg.cmake | 53 ----------------- cmake/FindDirectX.cmake | 72 ----------------------- cmake/FindDirectX11.cmake | 114 ------------------------------------ cmake/FindFreeImage.cmake | 47 --------------- cmake/FindZZip.cmake | 48 --------------- 6 files changed, 1 insertion(+), 335 deletions(-) delete mode 100644 cmake/FindCg.cmake delete mode 100644 cmake/FindDirectX.cmake delete mode 100644 cmake/FindDirectX11.cmake delete mode 100644 cmake/FindFreeImage.cmake delete mode 100644 cmake/FindZZip.cmake diff --git a/cmake/COPYING-CMAKE-SCRIPTS b/cmake/COPYING-CMAKE-SCRIPTS index 8ee3ea36b..d33c6f33b 100644 --- a/cmake/COPYING-CMAKE-SCRIPTS +++ b/cmake/COPYING-CMAKE-SCRIPTS @@ -1,7 +1,7 @@ The following files are derived from the Thermite project (http://www.thermite3d.org) and are covered under the license below. -FindMYGUI.cmake, FindOGRE.cmake, FindOIS.cmake, FindBullet.cmake +FindMYGUI.cmake, FindBullet.cmake Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions diff --git a/cmake/FindCg.cmake b/cmake/FindCg.cmake deleted file mode 100644 index 4bd348c46..000000000 --- a/cmake/FindCg.cmake +++ /dev/null @@ -1,53 +0,0 @@ -#------------------------------------------------------------------- -# This file is part of the CMake build system for OGRE -# (Object-oriented Graphics Rendering Engine) -# For the latest info, see http://www.ogre3d.org/ -# -# The contents of this file are placed in the public domain. Feel -# free to make use of it in any way you like. -#------------------------------------------------------------------- - -# - Try to find Cg -# Once done, this will define -# -# Cg_FOUND - system has Cg -# Cg_INCLUDE_DIRS - the Cg include directories -# Cg_LIBRARIES - link these to use Cg - -include(FindPkgMacros) -findpkg_begin(Cg) - -# Get path, convert backslashes as ${ENV_${var}} -getenv_path(Cg_HOME) -getenv_path(OGRE_SOURCE) -getenv_path(OGRE_HOME) - -# construct search paths -set(Cg_PREFIX_PATH ${Cg_HOME} ${ENV_Cg_HOME} - ${OGRE_SOURCE}/Dependencies - ${ENV_OGRE_SOURCE}/Dependencies - ${OGRE_HOME} ${ENV_OGRE_HOME} - /opt/nvidia-cg-toolkit) -create_search_paths(Cg) -# redo search if prefix path changed -clear_if_changed(Cg_PREFIX_PATH - Cg_LIBRARY_FWK - Cg_LIBRARY_REL - Cg_LIBRARY_DBG - Cg_INCLUDE_DIR -) - -set(Cg_LIBRARY_NAMES Cg) -get_debug_names(Cg_LIBRARY_NAMES) - -use_pkgconfig(Cg_PKGC Cg) - -findpkg_framework(Cg) - -find_path(Cg_INCLUDE_DIR NAMES cg.h HINTS ${Cg_FRAMEWORK_INCLUDES} ${Cg_INC_SEARCH_PATH} ${Cg_PKGC_INCLUDE_DIRS} PATH_SUFFIXES Cg) -find_library(Cg_LIBRARY_REL NAMES ${Cg_LIBRARY_NAMES} HINTS ${Cg_LIB_SEARCH_PATH} ${Cg_PKGC_LIBRARY_DIRS} PATH_SUFFIXES "" release relwithdebinfo minsizerel) -find_library(Cg_LIBRARY_DBG NAMES ${Cg_LIBRARY_NAMES_DBG} HINTS ${Cg_LIB_SEARCH_PATH} ${Cg_PKGC_LIBRARY_DIRS} PATH_SUFFIXES "" debug) -make_library_set(Cg_LIBRARY) - -findpkg_finish(Cg) -add_parent_dir(Cg_INCLUDE_DIRS Cg_INCLUDE_DIR) diff --git a/cmake/FindDirectX.cmake b/cmake/FindDirectX.cmake deleted file mode 100644 index 4641b55a3..000000000 --- a/cmake/FindDirectX.cmake +++ /dev/null @@ -1,72 +0,0 @@ -#------------------------------------------------------------------- -# This file is part of the CMake build system for OGRE -# (Object-oriented Graphics Rendering Engine) -# For the latest info, see http://www.ogre3d.org/ -# -# The contents of this file are placed in the public domain. Feel -# free to make use of it in any way you like. -#------------------------------------------------------------------- - -# ----------------------------------------------------------------------------- -# Find DirectX9 SDK -# Define: -# DirectX9_FOUND -# DirectX9_INCLUDE_DIR -# DirectX9_LIBRARY -# DirectX9_ROOT_DIR - -if(WIN32) # The only platform it makes sense to check for DirectX9 SDK - include(FindPkgMacros) - findpkg_begin(DirectX9) - - # Get path, convert backslashes as ${ENV_DXSDK_DIR} - getenv_path(DXSDK_DIR) - getenv_path(DirectX_HOME) - getenv_path(DirectX_ROOT) - getenv_path(DirectX_BASE) - - # construct search paths - set(DirectX9_PREFIX_PATH - "${DXSDK_DIR}" "${ENV_DXSDK_DIR}" - "${DIRECTX_HOME}" "${ENV_DIRECTX_HOME}" - "${DIRECTX_ROOT}" "${ENV_DIRECTX_ROOT}" - "${DIRECTX_BASE}" "${ENV_DIRECTX_BASE}" - "C:/apps_x86/Microsoft DirectX SDK*" - "C:/Program Files (x86)/Microsoft DirectX SDK*" - "C:/apps/Microsoft DirectX SDK*" - "C:/Program Files/Microsoft DirectX SDK*" - "$ENV{ProgramFiles}/Microsoft DirectX SDK*" - ) - - create_search_paths(DirectX9) - # redo search if prefix path changed - clear_if_changed(DirectX9_PREFIX_PATH - DirectX9_LIBRARY - DirectX9_INCLUDE_DIR - ) - - find_path(DirectX9_INCLUDE_DIR NAMES d3d9.h D3DCommon.h HINTS ${DirectX9_INC_SEARCH_PATH}) - # dlls are in DirectX9_ROOT_DIR/Developer Runtime/x64|x86 - # lib files are in DirectX9_ROOT_DIR/Lib/x64|x86 - if(CMAKE_CL_64) - set(DirectX9_LIBPATH_SUFFIX "x64") - else(CMAKE_CL_64) - set(DirectX9_LIBPATH_SUFFIX "x86") - endif(CMAKE_CL_64) - find_library(DirectX9_LIBRARY NAMES d3d9 HINTS ${DirectX9_LIB_SEARCH_PATH} PATH_SUFFIXES ${DirectX9_LIBPATH_SUFFIX}) - find_library(DirectX9_D3DX9_LIBRARY NAMES d3dx9 HINTS ${DirectX9_LIB_SEARCH_PATH} PATH_SUFFIXES ${DirectX9_LIBPATH_SUFFIX}) - find_library(DirectX9_DXERR_LIBRARY NAMES DxErr HINTS ${DirectX9_LIB_SEARCH_PATH} PATH_SUFFIXES ${DirectX9_LIBPATH_SUFFIX}) - find_library(DirectX9_DXGUID_LIBRARY NAMES dxguid HINTS ${DirectX9_LIB_SEARCH_PATH} PATH_SUFFIXES ${DirectX9_LIBPATH_SUFFIX}) - - findpkg_finish(DirectX9) - set(DirectX9_LIBRARIES ${DirectX9_LIBRARIES} - ${DirectX9_D3DX9_LIBRARY} - ${DirectX9_DXERR_LIBRARY} - ${DirectX9_DXGUID_LIBRARY} - ) - - mark_as_advanced(DirectX9_D3DX9_LIBRARY DirectX9_DXERR_LIBRARY DirectX9_DXGUID_LIBRARY - DirectX9_DXGI_LIBRARY DirectX9_D3DCOMPILER_LIBRARY) - - -endif(WIN32) diff --git a/cmake/FindDirectX11.cmake b/cmake/FindDirectX11.cmake deleted file mode 100644 index 22d5b5441..000000000 --- a/cmake/FindDirectX11.cmake +++ /dev/null @@ -1,114 +0,0 @@ -#------------------------------------------------------------------- -# This file is part of the CMake build system for OGRE -# (Object-oriented Graphics Rendering Engine) -# For the latest info, see http://www.ogre3d.org/ -# -# The contents of this file are placed in the public domain. Feel -# free to make use of it in any way you like. -#------------------------------------------------------------------- - -# ----------------------------------------------------------------------------- -# Find DirectX11 SDK -# Define: -# DirectX11_FOUND -# DirectX11_INCLUDE_DIR -# DirectX11_LIBRARY -# DirectX11_ROOT_DIR - -if(WIN32) # The only platform it makes sense to check for DirectX11 SDK - include(FindPkgMacros) - findpkg_begin(DirectX11) - - # Get path, convert backslashes as ${ENV_DXSDK_DIR} - getenv_path(DXSDK_DIR) - getenv_path(DIRECTX_HOME) - getenv_path(DIRECTX_ROOT) - getenv_path(DIRECTX_BASE) - - # construct search paths - set(DirectX11_PREFIX_PATH - "${DXSDK_DIR}" "${ENV_DXSDK_DIR}" - "${DIRECTX_HOME}" "${ENV_DIRECTX_HOME}" - "${DIRECTX_ROOT}" "${ENV_DIRECTX_ROOT}" - "${DIRECTX_BASE}" "${ENV_DIRECTX_BASE}" - "C:/apps_x86/Microsoft DirectX SDK*" - "C:/Program Files (x86)/Microsoft DirectX SDK*" - "C:/apps/Microsoft DirectX SDK*" - "C:/Program Files/Microsoft DirectX SDK*" - "$ENV{ProgramFiles}/Microsoft DirectX SDK*" - ) - - if(OGRE_BUILD_PLATFORM_WINRT) - # Windows 8 SDK has custom layout - set(DirectX11_INC_SEARCH_PATH - "C:/Program Files (x86)/Windows Kits/8.0/Include/shared" - "C:/Program Files (x86)/Windows Kits/8.0/Include/um" - ) - set(DirectX11_LIB_SEARCH_PATH - "C:/Program Files (x86)/Windows Kits/8.0/Lib/win8/um" - ) - endif() - - create_search_paths(DirectX11) - # redo search if prefix path changed - clear_if_changed(DirectX11_PREFIX_PATH - DirectX11_LIBRARY - DirectX11_INCLUDE_DIR - ) - - # dlls are in DirectX11_ROOT_DIR/Developer Runtime/x64|x86 - # lib files are in DirectX11_ROOT_DIR/Lib/x64|x86 - if(CMAKE_CL_64) - set(DirectX11_LIBPATH_SUFFIX "x64") - else(CMAKE_CL_64) - set(DirectX11_LIBPATH_SUFFIX "x86") - endif(CMAKE_CL_64) - - # look for D3D11 components - find_path(DirectX11_INCLUDE_DIR NAMES D3D11Shader.h HINTS ${DirectX11_INC_SEARCH_PATH}) - find_library(DirectX11_DXERR_LIBRARY NAMES DxErr HINTS ${DirectX11_LIB_SEARCH_PATH} PATH_SUFFIXES ${DirectX11_LIBPATH_SUFFIX}) - find_library(DirectX11_DXGUID_LIBRARY NAMES dxguid HINTS ${DirectX11_LIB_SEARCH_PATH} PATH_SUFFIXES ${DirectX11_LIBPATH_SUFFIX}) - find_library(DirectX11_DXGI_LIBRARY NAMES dxgi HINTS ${DirectX11_LIB_SEARCH_PATH} PATH_SUFFIXES ${DirectX11_LIBPATH_SUFFIX}) - find_library(DirectX11_D3DCOMPILER_LIBRARY NAMES d3dcompiler HINTS ${DirectX11_LIB_SEARCH_PATH} PATH_SUFFIXES ${DirectX11_LIBPATH_SUFFIX}) - - find_library(DirectX11_LIBRARY NAMES d3d11 HINTS ${DirectX11_LIB_SEARCH_PATH} PATH_SUFFIXES ${DirectX11_LIBPATH_SUFFIX}) - find_library(DirectX11_D3DX11_LIBRARY NAMES d3dx11 HINTS ${DirectX11_LIB_SEARCH_PATH} PATH_SUFFIXES ${DirectX11_LIBPATH_SUFFIX}) - if (DirectX11_INCLUDE_DIR AND DirectX11_LIBRARY) - set(DirectX11_D3D11_FOUND TRUE) - set(DirectX11_INCLUDE_DIR ${DirectX11_INCLUDE_DIR}) - set(DirectX11_D3D11_LIBRARIES ${DirectX11_D3D11_LIBRARIES} - ${DirectX11_LIBRARY} - ${DirectX11_DXGI_LIBRARY} - ${DirectX11_DXGUID_LIBRARY} - ${DirectX11_D3DCOMPILER_LIBRARY} - ) - endif () - if (DirectX11_D3DX11_LIBRARY) - set(DirectX11_D3D11_LIBRARIES ${DirectX11_D3D11_LIBRARIES} ${DirectX11_D3DX11_LIBRARY}) - endif () - if (DirectX11_DXERR_LIBRARY) - set(DirectX11_D3D11_LIBRARIES ${DirectX11_D3D11_LIBRARIES} ${DirectX11_DXERR_LIBRARY}) - endif () - - findpkg_finish(DirectX11) - - set(DirectX11_LIBRARIES - ${DirectX11_D3D11_LIBRARIES} - ) - - if (OGRE_BUILD_PLATFORM_WINDOWS_PHONE) - set(DirectX11_FOUND TRUE) - set(DirectX11_INCLUDE_DIR "C:/Program Files (x86)/Microsoft Visual Studio 11.0/VC/WPSDK/WP80/include" CACHE STRING "" FORCE) - set(DirectX11_LIBRARY "C:/Program Files (x86)/Microsoft Visual Studio 11.0/VC/WPSDK/WP80/lib" CACHE STRING "" FORCE) - set(DirectX11_LIBRARIES ${DirectX11_LIBRARY}) - set(CMAKE_CXX_FLAGS "/EHsc" CACHE STRING "" FORCE) - endif () - - mark_as_advanced(DirectX11_INCLUDE_DIR - DirectX11_D3D11_LIBRARIES - DirectX11_D3DX11_LIBRARY - DirectX11_DXERR_LIBRARY - DirectX11_DXGUID_LIBRARY - DirectX11_DXGI_LIBRARY - DirectX11_D3DCOMPILER_LIBRARY) -endif(WIN32) \ No newline at end of file diff --git a/cmake/FindFreeImage.cmake b/cmake/FindFreeImage.cmake deleted file mode 100644 index 3b21a17d6..000000000 --- a/cmake/FindFreeImage.cmake +++ /dev/null @@ -1,47 +0,0 @@ -#------------------------------------------------------------------- -# This file is part of the CMake build system for OGRE -# (Object-oriented Graphics Rendering Engine) -# For the latest info, see http://www.ogre3d.org/ -# -# The contents of this file are placed in the public domain. Feel -# free to make use of it in any way you like. -#------------------------------------------------------------------- - -# - Try to find FreeImage -# Once done, this will define -# -# FreeImage_FOUND - system has FreeImage -# FreeImage_INCLUDE_DIRS - the FreeImage include directories -# FreeImage_LIBRARIES - link these to use FreeImage - -include(FindPkgMacros) -findpkg_begin(FreeImage) - -# Get path, convert backslashes as ${ENV_${var}} -getenv_path(FREEIMAGE_HOME) - -# construct search paths -set(FreeImage_PREFIX_PATH ${FREEIMAGE_HOME} ${ENV_FREEIMAGE_HOME}) -create_search_paths(FreeImage) -# redo search if prefix path changed -clear_if_changed(FreeImage_PREFIX_PATH - FreeImage_LIBRARY_FWK - FreeImage_LIBRARY_REL - FreeImage_LIBRARY_DBG - FreeImage_INCLUDE_DIR -) - -set(FreeImage_LIBRARY_NAMES freeimage) -get_debug_names(FreeImage_LIBRARY_NAMES) - -use_pkgconfig(FreeImage_PKGC freeimage) - -findpkg_framework(FreeImage) - -find_path(FreeImage_INCLUDE_DIR NAMES FreeImage.h HINTS ${FreeImage_INC_SEARCH_PATH} ${FreeImage_PKGC_INCLUDE_DIRS}) -find_library(FreeImage_LIBRARY_REL NAMES ${FreeImage_LIBRARY_NAMES} HINTS ${FreeImage_LIB_SEARCH_PATH} ${FreeImage_PKGC_LIBRARY_DIRS} PATH_SUFFIXES "" release relwithdebinfo minsizerel) -find_library(FreeImage_LIBRARY_DBG NAMES ${FreeImage_LIBRARY_NAMES_DBG} HINTS ${FreeImage_LIB_SEARCH_PATH} ${FreeImage_PKGC_LIBRARY_DIRS} PATH_SUFFIXES "" debug) -make_library_set(FreeImage_LIBRARY) - -findpkg_finish(FreeImage) - diff --git a/cmake/FindZZip.cmake b/cmake/FindZZip.cmake deleted file mode 100644 index 68fe043f3..000000000 --- a/cmake/FindZZip.cmake +++ /dev/null @@ -1,48 +0,0 @@ -#------------------------------------------------------------------- -# This file is part of the CMake build system for OGRE -# (Object-oriented Graphics Rendering Engine) -# For the latest info, see http://www.ogre3d.org/ -# -# The contents of this file are placed in the public domain. Feel -# free to make use of it in any way you like. -#------------------------------------------------------------------- - -# - Try to find zziplib -# Once done, this will define -# -# ZZip_FOUND - system has ZZip -# ZZip_INCLUDE_DIRS - the ZZip include directories -# ZZip_LIBRARIES - link these to use ZZip - -include(FindPkgMacros) -findpkg_begin(ZZip) - -# Get path, convert backslashes as ${ENV_${var}} -getenv_path(ZZIP_HOME) - - -# construct search paths -set(ZZip_PREFIX_PATH ${ZZIP_HOME} ${ENV_ZZIP_HOME}) -create_search_paths(ZZip) -# redo search if prefix path changed -clear_if_changed(ZZip_PREFIX_PATH - ZZip_LIBRARY_FWK - ZZip_LIBRARY_REL - ZZip_LIBRARY_DBG - ZZip_INCLUDE_DIR -) - -set(ZZip_LIBRARY_NAMES zzip zziplib) -get_debug_names(ZZip_LIBRARY_NAMES) - -use_pkgconfig(ZZip_PKGC zziplib) - -findpkg_framework(ZZip) - -find_path(ZZip_INCLUDE_DIR NAMES zzip/zzip.h HINTS ${ZZip_INC_SEARCH_PATH} ${ZZip_PKGC_INCLUDE_DIRS}) -find_library(ZZip_LIBRARY_REL NAMES ${ZZip_LIBRARY_NAMES} HINTS ${ZZip_LIB_SEARCH_PATH} ${ZZip_PKGC_LIBRARY_DIRS} PATH_SUFFIXES "" release relwithdebinfo minsizerel) -find_library(ZZip_LIBRARY_DBG NAMES ${ZZip_LIBRARY_NAMES_DBG} HINTS ${ZZip_LIB_SEARCH_PATH} ${ZZip_PKGC_LIBRARY_DIRS} PATH_SUFFIXES "" debug) -make_library_set(ZZip_LIBRARY) - -findpkg_finish(ZZip) - From e04611948789a99e7da6f44740049218fe1686a6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 4 Jun 2015 16:15:26 +0200 Subject: [PATCH 1412/3725] Fix for unnecessary terrain texture coordinate arrays --- components/terrain/terraingrid.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/components/terrain/terraingrid.cpp b/components/terrain/terraingrid.cpp index 7ae4d8511..322c15196 100644 --- a/components/terrain/terraingrid.cpp +++ b/components/terrain/terraingrid.cpp @@ -162,7 +162,8 @@ void TerrainGrid::loadCell(int x, int y) textureCompileDummy->getOrCreateStateSet()->setTextureAttributeAndModes(0, layerTextures.back()); } - for (unsigned int i=0; isetTexCoordArray(i, mCache.getUVBuffer()); osg::ref_ptr effect (new Terrain::Effect(layerTextures, blendmapTextures)); From ce0d93caed5d2c49e30e3b57fc037e210e5fe91d Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 4 Jun 2015 16:32:21 +0200 Subject: [PATCH 1413/3725] Fix for "GlobalMap trying to erase an inactive camera" spam in main menu --- apps/openmw/mwrender/globalmap.cpp | 18 ++++++++++++++++-- apps/openmw/mwrender/localmap.cpp | 14 ++++++++++++-- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwrender/globalmap.cpp b/apps/openmw/mwrender/globalmap.cpp index bcf9e74bf..9109be799 100644 --- a/apps/openmw/mwrender/globalmap.cpp +++ b/apps/openmw/mwrender/globalmap.cpp @@ -63,17 +63,31 @@ namespace { public: CameraUpdateCallback(osg::Camera* cam, MWRender::GlobalMap* parent) - : mCamera(cam), mParent(parent) + : mRendered(false) + , mCamera(cam) + , mParent(parent) { } virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) { - mParent->markForRemoval(mCamera); + if (mRendered) + { + mCamera->setNodeMask(0); + return; + } + traverse(node, nv); + + if (!mRendered) + { + mRendered = true; + mParent->markForRemoval(mCamera); + } } private: + bool mRendered; osg::ref_ptr mCamera; MWRender::GlobalMap* mParent; }; diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 77138a124..6ce54a4ba 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -30,13 +30,22 @@ namespace { public: CameraUpdateCallback(osg::Camera* cam, MWRender::LocalMap* parent) - : mCamera(cam), mParent(parent) + : mRendered(false) + , mCamera(cam) + , mParent(parent) { } virtual void operator()(osg::Node*, osg::NodeVisitor*) { - mParent->markForRemoval(mCamera); + if (mRendered) + mCamera->setNodeMask(0); + + if (!mRendered) + { + mRendered = true; + mParent->markForRemoval(mCamera); + } // Note, we intentionally do not traverse children here. The map camera's scene data is the same as the master camera's, // so it has been updated already. @@ -44,6 +53,7 @@ namespace } private: + bool mRendered; osg::ref_ptr mCamera; MWRender::LocalMap* mParent; }; From 30053140a108dd31204efeddbc8401f12a26c238 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 4 Jun 2015 16:55:14 +0200 Subject: [PATCH 1414/3725] Add cmake-data workaround to travis script --- .travis.yml | 12 ++++++------ CI/before_install.linux.sh | 1 + 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7b5155137..d2b2ad079 100644 --- a/.travis.yml +++ b/.travis.yml @@ -49,9 +49,9 @@ notifications: email: on_success: change on_failure: always - irc: - channels: - - "chat.freenode.net#openmw" - on_success: change - on_failure: always - use_notice: true + #irc: + # channels: + # - "chat.freenode.net#openmw" + # on_success: change + # on_failure: always + # use_notice: true diff --git a/CI/before_install.linux.sh b/CI/before_install.linux.sh index 5823825ae..2408a5822 100755 --- a/CI/before_install.linux.sh +++ b/CI/before_install.linux.sh @@ -15,6 +15,7 @@ sudo apt-get install -qq libgtest-dev google-mock sudo apt-get install -qq libboost-filesystem-dev libboost-program-options-dev libboost-system-dev libboost-thread-dev sudo apt-get install -qq libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libavresample-dev sudo apt-get install -qq libbullet-dev libopenscenegraph-dev libmygui-dev libsdl2-dev libunshield-dev libtinyxml-dev libopenal-dev libqt4-dev +sudo apt-get install -qq cmake-data #workaround for broken osgqt cmake script in ubuntu 12.04 if [ "${ANALYZE}" ]; then sudo apt-get install -qq clang-3.6; fi sudo mkdir /usr/src/gtest/build cd /usr/src/gtest/build From 231b217664993843c7ae8df82d6abb394b6addc7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 4 Jun 2015 17:13:42 +0200 Subject: [PATCH 1415/3725] Build fix for MyGUI 3.2.1 --- components/fontloader/fontloader.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/components/fontloader/fontloader.cpp b/components/fontloader/fontloader.cpp index 131336683..b66fbbb20 100644 --- a/components/fontloader/fontloader.cpp +++ b/components/fontloader/fontloader.cpp @@ -274,8 +274,6 @@ namespace Gui else if (name.size() >= 7 && Misc::StringUtils::ciEqual(name.substr(0, 7), "daedric")) resourceName = "Daedric"; - std::string textureName = name; - if (exportToFile) { osg::ref_ptr image = new osg::Image; @@ -298,8 +296,6 @@ namespace Gui memcpy(texData, &textureData[0], textureData.size()); tex->unlock(); - font->setSource(bitmapFilename); - // Using ResourceManualFont::setTexture, enable for MyGUI 3.2.3 /* osg::ref_ptr texture = new osg::Texture2D; @@ -319,7 +315,7 @@ namespace Gui defaultHeight->addAttribute("value", fontSize); MyGUI::xml::ElementPtr source = root->createChild("Property"); source->addAttribute("key", "Source"); - source->addAttribute("value", std::string(textureName)); + source->addAttribute("value", std::string(bitmapFilename)); MyGUI::xml::ElementPtr codes = root->createChild("Codes"); for(int i = 0; i < 256; i++) From 869f8a329aac928db30ba14f677cb2a2b86d9943 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 4 Jun 2015 20:08:44 +0200 Subject: [PATCH 1416/3725] Cloud scrolling fix --- apps/openmw/mwrender/sky.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 5b01edb16..c742d1c90 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -119,7 +119,10 @@ private: class CloudUpdater : public SceneUtil::StateSetUpdater { public: - void setAnimationTimer(float timer); + void setAnimationTimer(float timer) + { + mAnimationTimer = timer; + } void setTexture(osg::ref_ptr texture) { @@ -143,9 +146,8 @@ protected: virtual void apply(osg::StateSet *stateset, osg::NodeVisitor *nv) { - mAnimationTimer = nv->getFrameStamp()->getSimulationTime()*0.05; osg::TexMat* texMat = static_cast(stateset->getTextureAttribute(0, osg::StateAttribute::TEXMAT)); - texMat->setMatrix(osg::Matrix::translate(osg::Vec3f(mAnimationTimer, mAnimationTimer, 0.f))); + texMat->setMatrix(osg::Matrix::translate(osg::Vec3f(0, mAnimationTimer, 0.f))); stateset->setTextureAttributeAndModes(0, mTexture, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); @@ -604,7 +606,8 @@ void SkyManager::update(float duration) updateRain(duration); // UV Scroll the clouds - mCloudAnimationTimer += duration * mCloudSpeed; + mCloudAnimationTimer += duration * mCloudSpeed * 0.003; + mCloudUpdater->setAnimationTimer(mCloudAnimationTimer); /// \todo improve this mMasser->setPhase( static_cast( (int) ((mDay % 32)/4.f)) ); From 93656aa6cfa5dd73e4025ffe56083c21e9ce1da8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 4 Jun 2015 20:10:07 +0200 Subject: [PATCH 1417/3725] Add a header missing from CMakeLists --- apps/openmw/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 8e17f2f31..19889ad13 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -82,7 +82,7 @@ add_openmw_dir (mwmechanics drawstate spells activespells npcstats aipackage aisequence aipursue alchemy aiwander aitravel aifollow aiavoiddoor aiescort aiactivate aicombat repair enchanting pathfinding pathgrid security spellsuccess spellcasting disease pickpocket levelledlist combat steering obstacle autocalcspell difficultyscaling aicombataction actor summoning - character actors objects + character actors objects aistate ) add_openmw_dir (mwstate From 78ac37b52a1cb54cb24091f16c6bfd533ae736e7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 4 Jun 2015 20:11:40 +0200 Subject: [PATCH 1418/3725] Remove BOOST_STATIC_ASSERT to fix clang warnings --- apps/openmw/mwmechanics/aistate.hpp | 27 ++++----------------------- 1 file changed, 4 insertions(+), 23 deletions(-) diff --git a/apps/openmw/mwmechanics/aistate.hpp b/apps/openmw/mwmechanics/aistate.hpp index 581f45d07..19f0ecf99 100644 --- a/apps/openmw/mwmechanics/aistate.hpp +++ b/apps/openmw/mwmechanics/aistate.hpp @@ -4,15 +4,11 @@ #include #include -// c++11 replacement -#include -#include - namespace MWMechanics { /** \brief stores one object of any class derived from Base. - * Requesting a certain dereived class via get() either returns + * Requesting a certain derived class via get() either returns * the stored object if it has the correct type or otherwise replaces * it with an object of the requested type. */ @@ -22,17 +18,6 @@ namespace MWMechanics private: Base* mStorage; - // assert that Derived is derived from Base. - template< class Derived > - void assert_derived() - { - // c++11: - // static_assert( std::is_base_of , "DerivedClassStorage may only store derived classes" ); - - // boost: - BOOST_STATIC_ASSERT((boost::is_base_of::value));//,"DerivedClassStorage may only store derived classes"); - } - //if needed you have to provide a clone member function DerivedClassStorage( const DerivedClassStorage& other ); DerivedClassStorage& operator=( const DerivedClassStorage& ); @@ -42,8 +27,6 @@ namespace MWMechanics template< class Derived > Derived& get() { - assert_derived(); - Derived* result = dynamic_cast(mStorage); if(!result) @@ -60,7 +43,6 @@ namespace MWMechanics template< class Derived > void store( const Derived& payload ) { - assert_derived(); if(mStorage) delete mStorage; mStorage = new Derived(payload); @@ -70,7 +52,6 @@ namespace MWMechanics template< class Derived > void moveIn( Derived* p ) { - assert_derived(); if(mStorage) delete mStorage; mStorage = p; @@ -87,12 +68,12 @@ namespace MWMechanics } - DerivedClassStorage():mStorage(NULL){}; + DerivedClassStorage():mStorage(NULL){} ~DerivedClassStorage() { if(mStorage) delete mStorage; - }; + } @@ -108,7 +89,7 @@ namespace MWMechanics * */ struct AiTemporaryBase { - virtual ~AiTemporaryBase(){}; + virtual ~AiTemporaryBase(){} }; /// \brief Container for AI package status. From 141e9d36a45719e35078d3ed29d6cb8253c48686 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 4 Jun 2015 20:12:39 +0200 Subject: [PATCH 1419/3725] Get rid of unused DialogueManager::mScriptVerbose --- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 2 -- apps/openmw/mwdialogue/dialoguemanagerimp.hpp | 1 - 2 files changed, 3 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 1785575fc..139862a5a 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -55,8 +55,6 @@ namespace MWDialogue , mTalkedTo(false) , mTemporaryDispositionChange(0.f) , mPermanentDispositionChange(0.f) - , mScriptVerbose (scriptVerbose) - { mChoice = -1; mIsInChoice = false; diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp index aec503e87..086b5ef2f 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp @@ -45,7 +45,6 @@ namespace MWDialogue float mTemporaryDispositionChange; float mPermanentDispositionChange; - bool mScriptVerbose; void parseText (const std::string& text); From e23775e33842f60a4d15b89af6ac8025a54a796f Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 4 Jun 2015 20:31:28 +0200 Subject: [PATCH 1420/3725] Fix -Woverloaded-virtual clang warnings --- apps/openmw/mwgui/bookwindow.cpp | 2 +- apps/openmw/mwgui/bookwindow.hpp | 2 +- apps/openmw/mwgui/companionwindow.cpp | 4 ++-- apps/openmw/mwgui/companionwindow.hpp | 2 +- apps/openmw/mwgui/confirmationdialog.cpp | 2 +- apps/openmw/mwgui/confirmationdialog.hpp | 2 +- apps/openmw/mwgui/container.cpp | 4 ++-- apps/openmw/mwgui/container.hpp | 2 +- apps/openmw/mwgui/countdialog.cpp | 2 +- apps/openmw/mwgui/countdialog.hpp | 2 +- apps/openmw/mwgui/inventorywindow.cpp | 2 +- apps/openmw/mwgui/itemview.cpp | 6 +++--- apps/openmw/mwgui/itemview.hpp | 2 +- apps/openmw/mwgui/mainmenu.cpp | 4 ++-- apps/openmw/mwgui/mapwindow.cpp | 2 +- apps/openmw/mwgui/savegamedialog.cpp | 4 ++-- apps/openmw/mwgui/scrollwindow.cpp | 2 +- apps/openmw/mwgui/scrollwindow.hpp | 2 +- apps/openmw/mwgui/settingswindow.cpp | 4 ++-- apps/openmw/mwgui/spellview.cpp | 4 ++-- apps/openmw/mwgui/spellview.hpp | 2 +- apps/openmw/mwgui/spellwindow.cpp | 2 +- apps/openmw/mwgui/tradewindow.cpp | 2 +- apps/openmw/mwgui/windowmanagerimp.cpp | 8 ++++---- components/widgets/list.cpp | 4 ++-- components/widgets/list.hpp | 2 +- 26 files changed, 38 insertions(+), 38 deletions(-) diff --git a/apps/openmw/mwgui/bookwindow.cpp b/apps/openmw/mwgui/bookwindow.cpp index 6863994b8..44a988523 100644 --- a/apps/openmw/mwgui/bookwindow.cpp +++ b/apps/openmw/mwgui/bookwindow.cpp @@ -73,7 +73,7 @@ namespace MWGui mPages.clear(); } - void BookWindow::open (MWWorld::Ptr book, bool showTakeButton) + void BookWindow::openBook (MWWorld::Ptr book, bool showTakeButton) { mBook = book; diff --git a/apps/openmw/mwgui/bookwindow.hpp b/apps/openmw/mwgui/bookwindow.hpp index 8ad4f6830..881b9997c 100644 --- a/apps/openmw/mwgui/bookwindow.hpp +++ b/apps/openmw/mwgui/bookwindow.hpp @@ -16,7 +16,7 @@ namespace MWGui virtual void exit(); - void open(MWWorld::Ptr book, bool showTakeButton); + void openBook(MWWorld::Ptr book, bool showTakeButton); void setInventoryAllowed(bool allowed); protected: diff --git a/apps/openmw/mwgui/companionwindow.cpp b/apps/openmw/mwgui/companionwindow.cpp index 4433f9ef8..4b3bab5d0 100644 --- a/apps/openmw/mwgui/companionwindow.cpp +++ b/apps/openmw/mwgui/companionwindow.cpp @@ -84,7 +84,7 @@ void CompanionWindow::onItemSelected(int index) if (count > 1 && !shift) { CountDialog* dialog = MWBase::Environment::get().getWindowManager()->getCountDialog(); - dialog->open(object.getClass().getName(object), "#{sTake}", count); + dialog->openCountDialog(object.getClass().getName(object), "#{sTake}", count); dialog->eventOkClicked.clear(); dialog->eventOkClicked += MyGUI::newDelegate(this, &CompanionWindow::dragItem); } @@ -106,7 +106,7 @@ void CompanionWindow::onBackgroundSelected() } } -void CompanionWindow::open(const MWWorld::Ptr& npc) +void CompanionWindow::openCompanion(const MWWorld::Ptr& npc) { mPtr = npc; updateEncumbranceBar(); diff --git a/apps/openmw/mwgui/companionwindow.hpp b/apps/openmw/mwgui/companionwindow.hpp index dc460e2fc..d37f0c4e4 100644 --- a/apps/openmw/mwgui/companionwindow.hpp +++ b/apps/openmw/mwgui/companionwindow.hpp @@ -22,7 +22,7 @@ namespace MWGui virtual void resetReference(); - void open(const MWWorld::Ptr& npc); + void openCompanion(const MWWorld::Ptr& npc); void onFrame (); private: diff --git a/apps/openmw/mwgui/confirmationdialog.cpp b/apps/openmw/mwgui/confirmationdialog.cpp index 83650b195..e4312914f 100644 --- a/apps/openmw/mwgui/confirmationdialog.cpp +++ b/apps/openmw/mwgui/confirmationdialog.cpp @@ -16,7 +16,7 @@ namespace MWGui mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ConfirmationDialog::onOkButtonClicked); } - void ConfirmationDialog::open(const std::string& message, const std::string& confirmMessage, const std::string& cancelMessage) + void ConfirmationDialog::askForConfirmation(const std::string& message, const std::string& confirmMessage, const std::string& cancelMessage) { setVisible(true); diff --git a/apps/openmw/mwgui/confirmationdialog.hpp b/apps/openmw/mwgui/confirmationdialog.hpp index 7ff16b10a..14caa7748 100644 --- a/apps/openmw/mwgui/confirmationdialog.hpp +++ b/apps/openmw/mwgui/confirmationdialog.hpp @@ -9,7 +9,7 @@ namespace MWGui { public: ConfirmationDialog(); - void open(const std::string& message, const std::string& confirmMessage="#{sOk}", const std::string& cancelMessage="#{sCancel}"); + void askForConfirmation(const std::string& message, const std::string& confirmMessage="#{sOk}", const std::string& cancelMessage="#{sCancel}"); virtual void exit(); typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void; diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 1317e1e25..ecf4ddcf0 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -83,7 +83,7 @@ namespace MWGui if (count > 1 && !shift) { CountDialog* dialog = MWBase::Environment::get().getWindowManager()->getCountDialog(); - dialog->open(object.getClass().getName(object), "#{sTake}", count); + dialog->openCountDialog(object.getClass().getName(object), "#{sTake}", count); dialog->eventOkClicked.clear(); dialog->eventOkClicked += MyGUI::newDelegate(this, &ContainerWindow::dragItem); } @@ -131,7 +131,7 @@ namespace MWGui dropItem(); } - void ContainerWindow::open(const MWWorld::Ptr& container, bool loot) + void ContainerWindow::openContainer(const MWWorld::Ptr& container, bool loot) { mPickpocketDetected = false; mPtr = container; diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index 87ae993a5..520bce9d9 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -33,7 +33,7 @@ namespace MWGui public: ContainerWindow(DragAndDrop* dragAndDrop); - void open(const MWWorld::Ptr& container, bool loot=false); + void openContainer(const MWWorld::Ptr& container, bool loot=false); virtual void close(); virtual void resetReference(); diff --git a/apps/openmw/mwgui/countdialog.cpp b/apps/openmw/mwgui/countdialog.cpp index c6f2180c9..03cf1cab6 100644 --- a/apps/openmw/mwgui/countdialog.cpp +++ b/apps/openmw/mwgui/countdialog.cpp @@ -29,7 +29,7 @@ namespace MWGui mItemEdit->eventEditSelectAccept += MyGUI::newDelegate(this, &CountDialog::onEnterKeyPressed); } - void CountDialog::open(const std::string& item, const std::string& message, const int maxCount) + void CountDialog::openCountDialog(const std::string& item, const std::string& message, const int maxCount) { setVisible(true); diff --git a/apps/openmw/mwgui/countdialog.hpp b/apps/openmw/mwgui/countdialog.hpp index a54e99cf4..7014b5fad 100644 --- a/apps/openmw/mwgui/countdialog.hpp +++ b/apps/openmw/mwgui/countdialog.hpp @@ -14,7 +14,7 @@ namespace MWGui { public: CountDialog(); - void open(const std::string& item, const std::string& message, const int maxCount); + void openCountDialog(const std::string& item, const std::string& message, const int maxCount); void cancel(); virtual void exit(); diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index b96e79ca9..e3d87de60 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -237,7 +237,7 @@ namespace MWGui { CountDialog* dialog = MWBase::Environment::get().getWindowManager()->getCountDialog(); std::string message = mTrading ? "#{sQuanityMenuMessage01}" : "#{sTake}"; - dialog->open(object.getClass().getName(object), message, count); + dialog->openCountDialog(object.getClass().getName(object), message, count); dialog->eventOkClicked.clear(); if (mTrading) dialog->eventOkClicked += MyGUI::newDelegate(this, &InventoryWindow::sellItem); diff --git a/apps/openmw/mwgui/itemview.cpp b/apps/openmw/mwgui/itemview.cpp index aade232d2..7391bb8fb 100644 --- a/apps/openmw/mwgui/itemview.cpp +++ b/apps/openmw/mwgui/itemview.cpp @@ -103,7 +103,7 @@ void ItemView::update() MyGUI::Align::Stretch); dragArea->setNeedMouseFocus(true); dragArea->eventMouseButtonClick += MyGUI::newDelegate(this, &ItemView::onSelectedBackground); - dragArea->eventMouseWheel += MyGUI::newDelegate(this, &ItemView::onMouseWheel); + dragArea->eventMouseWheel += MyGUI::newDelegate(this, &ItemView::onMouseWheelMoved); for (ItemModel::ModelIndex i=0; i(mModel->getItemCount()); ++i) { @@ -122,7 +122,7 @@ void ItemView::update() itemWidget->setCount(item.mCount); itemWidget->eventMouseButtonClick += MyGUI::newDelegate(this, &ItemView::onSelectedItem); - itemWidget->eventMouseWheel += MyGUI::newDelegate(this, &ItemView::onMouseWheel); + itemWidget->eventMouseWheel += MyGUI::newDelegate(this, &ItemView::onMouseWheelMoved); } layoutWidgets(); @@ -139,7 +139,7 @@ void ItemView::onSelectedBackground(MyGUI::Widget *sender) eventBackgroundClicked(); } -void ItemView::onMouseWheel(MyGUI::Widget *_sender, int _rel) +void ItemView::onMouseWheelMoved(MyGUI::Widget *_sender, int _rel) { if (mScrollView->getViewOffset().left + _rel*0.3f > 0) mScrollView->setViewOffset(MyGUI::IntPoint(0, 0)); diff --git a/apps/openmw/mwgui/itemview.hpp b/apps/openmw/mwgui/itemview.hpp index 9aeba6752..6c2dea339 100644 --- a/apps/openmw/mwgui/itemview.hpp +++ b/apps/openmw/mwgui/itemview.hpp @@ -40,7 +40,7 @@ namespace MWGui void onSelectedItem (MyGUI::Widget* sender); void onSelectedBackground (MyGUI::Widget* sender); - void onMouseWheel(MyGUI::Widget* _sender, int _rel); + void onMouseWheelMoved(MyGUI::Widget* _sender, int _rel); ItemModel* mModel; MyGUI::ScrollView* mScrollView; diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index dbc513049..e24894e89 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -112,7 +112,7 @@ namespace MWGui else { ConfirmationDialog* dialog = MWBase::Environment::get().getWindowManager()->getConfirmationDialog(); - dialog->open("#{sMessage2}"); + dialog->askForConfirmation("#{sMessage2}"); dialog->eventOkClicked.clear(); dialog->eventOkClicked += MyGUI::newDelegate(this, &MainMenu::onExitConfirmed); dialog->eventCancelClicked.clear(); @@ -125,7 +125,7 @@ namespace MWGui else { ConfirmationDialog* dialog = MWBase::Environment::get().getWindowManager()->getConfirmationDialog(); - dialog->open("#{sNotifyMessage54}"); + dialog->askForConfirmation("#{sNotifyMessage54}"); dialog->eventOkClicked.clear(); dialog->eventOkClicked += MyGUI::newDelegate(this, &MainMenu::onNewGameConfirmed); dialog->eventCancelClicked.clear(); diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 34a9db1e1..3e855c4d0 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -650,7 +650,7 @@ namespace MWGui void MapWindow::onNoteEditDelete() { ConfirmationDialog* confirmation = MWBase::Environment::get().getWindowManager()->getConfirmationDialog(); - confirmation->open("#{sDeleteNote}", "#{sYes}", "#{sNo}"); + confirmation->askForConfirmation("#{sDeleteNote}", "#{sYes}", "#{sNo}"); confirmation->eventCancelClicked.clear(); confirmation->eventOkClicked.clear(); confirmation->eventOkClicked += MyGUI::newDelegate(this, &MapWindow::onNoteEditDeleteConfirm); diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index ab8d93a87..d490d49cd 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -73,7 +73,7 @@ namespace MWGui void SaveGameDialog::confirmDeleteSave() { ConfirmationDialog* dialog = MWBase::Environment::get().getWindowManager()->getConfirmationDialog(); - dialog->open("#{sMessage3}"); + dialog->askForConfirmation("#{sMessage3}"); dialog->eventOkClicked.clear(); dialog->eventOkClicked += MyGUI::newDelegate(this, &SaveGameDialog::onDeleteSlotConfirmed); dialog->eventCancelClicked.clear(); @@ -232,7 +232,7 @@ namespace MWGui if (mCurrentSlot != NULL && !reallySure) { ConfirmationDialog* dialog = MWBase::Environment::get().getWindowManager()->getConfirmationDialog(); - dialog->open("#{sMessage4}"); + dialog->askForConfirmation("#{sMessage4}"); dialog->eventOkClicked.clear(); dialog->eventOkClicked += MyGUI::newDelegate(this, &SaveGameDialog::onConfirmationGiven); dialog->eventCancelClicked.clear(); diff --git a/apps/openmw/mwgui/scrollwindow.cpp b/apps/openmw/mwgui/scrollwindow.cpp index 85d1c8c4e..01ce7767e 100644 --- a/apps/openmw/mwgui/scrollwindow.cpp +++ b/apps/openmw/mwgui/scrollwindow.cpp @@ -48,7 +48,7 @@ namespace MWGui center(); } - void ScrollWindow::open (MWWorld::Ptr scroll, bool showTakeButton) + void ScrollWindow::openScroll (MWWorld::Ptr scroll, bool showTakeButton) { // no 3d sounds because the object could be in a container. MWBase::Environment::get().getSoundManager()->playSound ("scroll", 1.0, 1.0); diff --git a/apps/openmw/mwgui/scrollwindow.hpp b/apps/openmw/mwgui/scrollwindow.hpp index 3c9e718b6..961f1b675 100644 --- a/apps/openmw/mwgui/scrollwindow.hpp +++ b/apps/openmw/mwgui/scrollwindow.hpp @@ -17,7 +17,7 @@ namespace MWGui public: ScrollWindow (); - void open (MWWorld::Ptr scroll, bool showTakeButton); + void openScroll (MWWorld::Ptr scroll, bool showTakeButton); virtual void exit(); void setInventoryAllowed(bool allowed); diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index a50c30507..af081391c 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -271,7 +271,7 @@ namespace MWGui return; ConfirmationDialog* dialog = MWBase::Environment::get().getWindowManager()->getConfirmationDialog(); - dialog->open("#{sNotifyMessage67}"); + dialog->askForConfirmation("#{sNotifyMessage67}"); dialog->eventOkClicked.clear(); dialog->eventOkClicked += MyGUI::newDelegate(this, &SettingsWindow::onResolutionAccept); dialog->eventCancelClicked.clear(); @@ -540,7 +540,7 @@ namespace MWGui void SettingsWindow::onResetDefaultBindings(MyGUI::Widget* _sender) { ConfirmationDialog* dialog = MWBase::Environment::get().getWindowManager()->getConfirmationDialog(); - dialog->open("#{sNotifyMessage66}"); + dialog->askForConfirmation("#{sNotifyMessage66}"); dialog->eventOkClicked.clear(); dialog->eventOkClicked += MyGUI::newDelegate(this, &SettingsWindow::onResetDefaultBindingsAccept); dialog->eventCancelClicked.clear(); diff --git a/apps/openmw/mwgui/spellview.cpp b/apps/openmw/mwgui/spellview.cpp index 6d86b4a23..cb7bfc4a6 100644 --- a/apps/openmw/mwgui/spellview.cpp +++ b/apps/openmw/mwgui/spellview.cpp @@ -289,7 +289,7 @@ namespace MWGui widget->setUserString(sSpellModelIndex, MyGUI::utility::toString(index)); - widget->eventMouseWheel += MyGUI::newDelegate(this, &SpellView::onMouseWheel); + widget->eventMouseWheel += MyGUI::newDelegate(this, &SpellView::onMouseWheelMoved); widget->eventMouseButtonClick += MyGUI::newDelegate(this, &SpellView::onSpellSelected); } @@ -303,7 +303,7 @@ namespace MWGui eventSpellClicked(getSpellModelIndex(_sender)); } - void SpellView::onMouseWheel(MyGUI::Widget* _sender, int _rel) + void SpellView::onMouseWheelMoved(MyGUI::Widget* _sender, int _rel) { if (mScrollView->getViewOffset().top + _rel*0.3f > 0) mScrollView->setViewOffset(MyGUI::IntPoint(0, 0)); diff --git a/apps/openmw/mwgui/spellview.hpp b/apps/openmw/mwgui/spellview.hpp index 7af1bda7a..d40277282 100644 --- a/apps/openmw/mwgui/spellview.hpp +++ b/apps/openmw/mwgui/spellview.hpp @@ -84,7 +84,7 @@ namespace MWGui void adjustSpellWidget(const Spell& spell, SpellModel::ModelIndex index, MyGUI::Widget* widget); void onSpellSelected(MyGUI::Widget* _sender); - void onMouseWheel(MyGUI::Widget* _sender, int _rel); + void onMouseWheelMoved(MyGUI::Widget* _sender, int _rel); SpellModel::ModelIndex getSpellModelIndex(MyGUI::Widget* _sender); diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index ca5ec20bd..d2ea67ea9 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -134,7 +134,7 @@ namespace MWGui ConfirmationDialog* dialog = MWBase::Environment::get().getWindowManager()->getConfirmationDialog(); std::string question = MWBase::Environment::get().getWindowManager()->getGameSettingString("sQuestionDeleteSpell", "Delete %s?"); question = boost::str(boost::format(question) % spell->mName); - dialog->open(question); + dialog->askForConfirmation(question); dialog->eventOkClicked.clear(); dialog->eventOkClicked += MyGUI::newDelegate(this, &SpellWindow::onDeleteSpellAccept); dialog->eventCancelClicked.clear(); diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index e6a2555b6..581533060 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -194,7 +194,7 @@ namespace MWGui { CountDialog* dialog = MWBase::Environment::get().getWindowManager()->getCountDialog(); std::string message = "#{sQuanityMenuMessage02}"; - dialog->open(object.getClass().getName(object), message, count); + dialog->openCountDialog(object.getClass().getName(object), message, count); dialog->eventOkClicked.clear(); dialog->eventOkClicked += MyGUI::newDelegate(this, &TradeWindow::sellItem); mItemToSell = mSortModel->mapToSource(index); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 1ae5cabed..298d4812e 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1524,7 +1524,7 @@ namespace MWGui void WindowManager::showCompanionWindow(MWWorld::Ptr actor) { pushGuiMode(MWGui::GM_Companion); - mCompanionWindow->open(actor); + mCompanionWindow->openCompanion(actor); } void WindowManager::changePointer(const std::string &name) @@ -1927,19 +1927,19 @@ namespace MWGui void WindowManager::openContainer(const MWWorld::Ptr &container, bool loot) { pushGuiMode(GM_Container); - mContainerWindow->open(container, loot); + mContainerWindow->openContainer(container, loot); } void WindowManager::showBook(const MWWorld::Ptr &item, bool showTakeButton) { pushGuiMode(GM_Book); - mBookWindow->open(item, showTakeButton); + mBookWindow->openBook(item, showTakeButton); } void WindowManager::showScroll(const MWWorld::Ptr &item, bool showTakeButton) { pushGuiMode(GM_Scroll); - mScrollWindow->open(item, showTakeButton); + mScrollWindow->openScroll(item, showTakeButton); } std::string WindowManager::correctIconPath(const std::string& path) diff --git a/components/widgets/list.cpp b/components/widgets/list.cpp index df7e7d61d..c5a459f22 100644 --- a/components/widgets/list.cpp +++ b/components/widgets/list.cpp @@ -70,7 +70,7 @@ namespace Gui button->setCaption((*it)); button->getSubWidgetText()->setWordWrap(true); button->getSubWidgetText()->setTextAlign(MyGUI::Align::Left); - button->eventMouseWheel += MyGUI::newDelegate(this, &MWList::onMouseWheel); + button->eventMouseWheel += MyGUI::newDelegate(this, &MWList::onMouseWheelMoved); button->eventMouseButtonClick += MyGUI::newDelegate(this, &MWList::onItemSelected); int height = button->getTextSize().height; @@ -135,7 +135,7 @@ namespace Gui mItems.clear(); } - void MWList::onMouseWheel(MyGUI::Widget* _sender, int _rel) + void MWList::onMouseWheelMoved(MyGUI::Widget* _sender, int _rel) { //NB view offset is negative if (mScrollView->getViewOffset().top + _rel*0.3f > 0) diff --git a/components/widgets/list.hpp b/components/widgets/list.hpp index aed69da79..cc7b75c2f 100644 --- a/components/widgets/list.hpp +++ b/components/widgets/list.hpp @@ -55,7 +55,7 @@ namespace Gui void redraw(bool scrollbarShown = false); - void onMouseWheel(MyGUI::Widget* _sender, int _rel); + void onMouseWheelMoved(MyGUI::Widget* _sender, int _rel); void onItemSelected(MyGUI::Widget* _sender); private: From 30ab15e6054179efd09dad1c06b46eed26addb43 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 4 Jun 2015 20:33:20 +0200 Subject: [PATCH 1421/3725] Fix -Wunused-private-field clang warnings --- apps/openmw/mwgui/inventorywindow.cpp | 2 -- apps/openmw/mwgui/inventorywindow.hpp | 3 --- apps/openmw/mwgui/messagebox.cpp | 1 - apps/openmw/mwgui/messagebox.hpp | 1 - apps/openmw/mwrender/animation.cpp | 2 +- apps/openmw/mwrender/animation.hpp | 4 ---- apps/openmw/mwrender/npcanimation.cpp | 1 - apps/openmw/mwrender/npcanimation.hpp | 2 -- 8 files changed, 1 insertion(+), 15 deletions(-) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index e3d87de60..3ecfc64b2 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -61,8 +61,6 @@ namespace MWGui , mGuiMode(GM_Inventory) , mLastXSize(0) , mLastYSize(0) - , mResourceSystem(resourceSystem) - , mViewer(viewer) , mPreview(new MWRender::InventoryPreview(viewer, resourceSystem, MWBase::Environment::get().getWorld()->getPlayerPtr())) , mTrading(false) { diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index fc579ae62..a8a1b15a1 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -99,9 +99,6 @@ namespace MWGui int mLastXSize; int mLastYSize; - Resource::ResourceSystem* mResourceSystem; - osgViewer::Viewer* mViewer; - std::auto_ptr mPreviewTexture; std::auto_ptr mPreview; diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index 6e81ed626..c647ecaf5 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -195,7 +195,6 @@ namespace MWGui InteractiveMessageBox::InteractiveMessageBox(MessageBoxManager& parMessageBoxManager, const std::string& message, const std::vector& buttons) : WindowModal("openmw_interactive_messagebox.layout") , mMessageBoxManager(parMessageBoxManager) - , mTextButtonPadding(0) , mButtonPressed(-1) { WindowModal::open(); diff --git a/apps/openmw/mwgui/messagebox.hpp b/apps/openmw/mwgui/messagebox.hpp index 59d1a0b06..b4121fed3 100644 --- a/apps/openmw/mwgui/messagebox.hpp +++ b/apps/openmw/mwgui/messagebox.hpp @@ -88,7 +88,6 @@ namespace MWGui MyGUI::Widget* mButtonsWidget; std::vector mButtons; - int mTextButtonPadding; int mButtonPressed; }; diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 34a397f9a..80877e08b 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -240,7 +240,7 @@ namespace MWRender , mTextKeyListener(NULL) { for(size_t i = 0;i < sNumGroups;i++) - mAnimationTimePtr[i].reset(new AnimationTime(this)); + mAnimationTimePtr[i].reset(new AnimationTime); } Animation::~Animation() diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index bd864c936..419ae6bc0 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -95,13 +95,9 @@ protected: class AnimationTime : public SceneUtil::ControllerSource { private: - Animation *mAnimation; boost::shared_ptr mTimePtr; public: - AnimationTime(Animation *anim) - : mAnimation(anim) - { } void setTimePtr(boost::shared_ptr time) { mTimePtr = time; } diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 71c48a489..6831daa4b 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -242,7 +242,6 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, osg::ref_ptr par mShowWeapons(false), mShowCarriedLeft(true), mNpcType(Type_Normal), - mVisibilityFlags(visibilityFlags), mAlpha(1.f), mSoundsDisabled(disableSounds), mHeadYawRadians(0.f), diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 23b663565..3eb4c4754 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -90,8 +90,6 @@ private: }; NpcType mNpcType; - int mVisibilityFlags; - int mPartslots[ESM::PRT_Count]; //Each part slot is taken by clothing, armor, or is empty int mPartPriorities[ESM::PRT_Count]; From 958b34771a7f08c89b7fa04e84e3d02803844519 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 4 Jun 2015 20:34:49 +0200 Subject: [PATCH 1422/3725] Fix clang warnings about 'typename' outside of a template --- apps/opencs/model/world/nestedcoladapterimp.cpp | 4 ++-- apps/opencs/model/world/refidadapterimp.cpp | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/opencs/model/world/nestedcoladapterimp.cpp b/apps/opencs/model/world/nestedcoladapterimp.cpp index b7d09777d..dc5cd2299 100644 --- a/apps/opencs/model/world/nestedcoladapterimp.cpp +++ b/apps/opencs/model/world/nestedcoladapterimp.cpp @@ -906,7 +906,7 @@ namespace CSMWorld NestedTableWrapperBase* RaceAttributeAdapter::table(const Record& record) const { - std::vector wrap; + std::vector wrap; wrap.push_back(record.get().mData); // deleted by dtor of NestedTableStoring return new NestedTableWrapper >(wrap); @@ -983,7 +983,7 @@ namespace CSMWorld NestedTableWrapperBase* RaceSkillsBonusAdapter::table(const Record& record) const { - std::vector wrap; + std::vector wrap; wrap.push_back(record.get().mData); // deleted by dtor of NestedTableStoring return new NestedTableWrapper >(wrap); diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index d31a9ceaa..2daca16f7 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -576,7 +576,7 @@ void CSMWorld::NpcAttributesRefIdAdapter::setNestedTable (const RefIdColumn* col // store the whole struct npc.mNpdt52 = - static_cast > &>(nestedTable).mNestedTable.at(0); + static_cast > &>(nestedTable).mNestedTable.at(0); record.setModified (npc); } @@ -588,10 +588,10 @@ CSMWorld::NestedTableWrapperBase* CSMWorld::NpcAttributesRefIdAdapter::nestedTab static_cast&> (data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Npc))); // return the whole struct - std::vector wrap; + std::vector wrap; wrap.push_back(record.get().mNpdt52); // deleted by dtor of NestedTableStoring - return new NestedTableWrapper >(wrap); + return new NestedTableWrapper >(wrap); } QVariant CSMWorld::NpcAttributesRefIdAdapter::getNestedData (const RefIdColumn *column, @@ -694,7 +694,7 @@ void CSMWorld::NpcSkillsRefIdAdapter::setNestedTable (const RefIdColumn* column, // store the whole struct npc.mNpdt52 = - static_cast > &>(nestedTable).mNestedTable.at(0); + static_cast > &>(nestedTable).mNestedTable.at(0); record.setModified (npc); } @@ -706,10 +706,10 @@ CSMWorld::NestedTableWrapperBase* CSMWorld::NpcSkillsRefIdAdapter::nestedTable ( static_cast&> (data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Npc))); // return the whole struct - std::vector wrap; + std::vector wrap; wrap.push_back(record.get().mNpdt52); // deleted by dtor of NestedTableStoring - return new NestedTableWrapper >(wrap); + return new NestedTableWrapper >(wrap); } QVariant CSMWorld::NpcSkillsRefIdAdapter::getNestedData (const RefIdColumn *column, From e6ecb39d94d93ec3b1945f3fdc7a94a866d9da3c Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 4 Jun 2015 20:36:07 +0200 Subject: [PATCH 1423/3725] Potential include fix --- extern/osg-ffmpeg-videoplayer/videostate.cpp | 5 ----- extern/osg-ffmpeg-videoplayer/videostate.hpp | 3 +++ 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/extern/osg-ffmpeg-videoplayer/videostate.cpp b/extern/osg-ffmpeg-videoplayer/videostate.cpp index 8a9cce1b7..f143088e8 100644 --- a/extern/osg-ffmpeg-videoplayer/videostate.cpp +++ b/extern/osg-ffmpeg-videoplayer/videostate.cpp @@ -2,11 +2,6 @@ #include -#ifndef __STDC_CONSTANT_MACROS -#define __STDC_CONSTANT_MACROS -#endif -#include - #include extern "C" diff --git a/extern/osg-ffmpeg-videoplayer/videostate.hpp b/extern/osg-ffmpeg-videoplayer/videostate.hpp index 72a2aab18..247e04ec4 100644 --- a/extern/osg-ffmpeg-videoplayer/videostate.hpp +++ b/extern/osg-ffmpeg-videoplayer/videostate.hpp @@ -1,6 +1,9 @@ #ifndef VIDEOPLAYER_VIDEOSTATE_H #define VIDEOPLAYER_VIDEOSTATE_H +#ifndef __STDC_CONSTANT_MACROS +#define __STDC_CONSTANT_MACROS +#endif #include #include From a0b0ae9bd1f65ddd548313decebe196f9a0d8957 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 4 Jun 2015 21:51:24 +0200 Subject: [PATCH 1424/3725] Remove an unused variable --- apps/openmw/mwmechanics/aicombat.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index f31e0ff77..9d92423e9 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -79,9 +79,6 @@ namespace namespace MWMechanics { - static const float DOOR_CHECK_INTERVAL = 1.5f; // same as AiWander - // NOTE: MIN_DIST_TO_DOOR_SQUARED is defined in obstacle.hpp - /// \brief This class holds the variables AiCombat needs which are deleted if the package becomes inactive. struct AiCombatStorage : AiTemporaryBase From c40987338d93c6121997630f539ba7e9138540a3 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Thu, 4 Jun 2015 23:09:40 +0300 Subject: [PATCH 1425/3725] Scrollbars don't save their positions between openings --- apps/openmw/mwgui/alchemywindow.cpp | 1 + apps/openmw/mwgui/companionwindow.cpp | 1 + apps/openmw/mwgui/container.cpp | 1 + apps/openmw/mwgui/itemselection.cpp | 1 + apps/openmw/mwgui/itemview.cpp | 5 +++++ apps/openmw/mwgui/itemview.hpp | 2 ++ apps/openmw/mwgui/merchantrepair.cpp | 2 ++ apps/openmw/mwgui/quickkeysmenu.cpp | 1 + apps/openmw/mwgui/recharge.cpp | 2 ++ apps/openmw/mwgui/repair.cpp | 2 ++ apps/openmw/mwgui/settingswindow.cpp | 17 +++++++++++++++++ apps/openmw/mwgui/settingswindow.hpp | 5 +++++ apps/openmw/mwgui/spellcreationdialog.cpp | 1 + apps/openmw/mwgui/spellview.cpp | 4 ++++ apps/openmw/mwgui/spellview.hpp | 2 ++ apps/openmw/mwgui/tradewindow.cpp | 1 + 16 files changed, 48 insertions(+) diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index a54744370..768ad82e4 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -130,6 +130,7 @@ namespace MWGui mSortModel = new SortFilterItemModel(model); mSortModel->setFilter(SortFilterItemModel::Filter_OnlyIngredients); mItemView->setModel (mSortModel); + mItemView->resetScrollBars(); mNameEdit->setCaption(""); diff --git a/apps/openmw/mwgui/companionwindow.cpp b/apps/openmw/mwgui/companionwindow.cpp index 4433f9ef8..69b6aa9f9 100644 --- a/apps/openmw/mwgui/companionwindow.cpp +++ b/apps/openmw/mwgui/companionwindow.cpp @@ -114,6 +114,7 @@ void CompanionWindow::open(const MWWorld::Ptr& npc) mModel = new CompanionItemModel(npc); mSortModel = new SortFilterItemModel(mModel); mItemView->setModel(mSortModel); + mItemView->resetScrollBars(); setTitle(npc.getClass().getName(npc)); } diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 1317e1e25..76e9cbb5b 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -151,6 +151,7 @@ namespace MWGui mSortModel = new SortFilterItemModel(mModel); mItemView->setModel (mSortModel); + mItemView->resetScrollBars(); MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mCloseButton); diff --git a/apps/openmw/mwgui/itemselection.cpp b/apps/openmw/mwgui/itemselection.cpp index 916f13360..095f392b7 100644 --- a/apps/openmw/mwgui/itemselection.cpp +++ b/apps/openmw/mwgui/itemselection.cpp @@ -39,6 +39,7 @@ namespace MWGui mModel = new InventoryItemModel(container); mSortModel = new SortFilterItemModel(mModel); mItemView->setModel(mSortModel); + mItemView->resetScrollBars(); } void ItemSelectionDialog::setCategory(int category) diff --git a/apps/openmw/mwgui/itemview.cpp b/apps/openmw/mwgui/itemview.cpp index aade232d2..c5320a2be 100644 --- a/apps/openmw/mwgui/itemview.cpp +++ b/apps/openmw/mwgui/itemview.cpp @@ -128,6 +128,11 @@ void ItemView::update() layoutWidgets(); } +void ItemView::resetScrollBars() +{ + mScrollView->setViewOffset(MyGUI::IntPoint(0, 0)); +} + void ItemView::onSelectedItem(MyGUI::Widget *sender) { ItemModel::ModelIndex index = (*sender->getUserData >()).first; diff --git a/apps/openmw/mwgui/itemview.hpp b/apps/openmw/mwgui/itemview.hpp index 9aeba6752..f87a48aa6 100644 --- a/apps/openmw/mwgui/itemview.hpp +++ b/apps/openmw/mwgui/itemview.hpp @@ -30,6 +30,8 @@ namespace MWGui void update(); + void resetScrollBars(); + private: virtual void initialiseOverride(); diff --git a/apps/openmw/mwgui/merchantrepair.cpp b/apps/openmw/mwgui/merchantrepair.cpp index 4407bf927..862b719d4 100644 --- a/apps/openmw/mwgui/merchantrepair.cpp +++ b/apps/openmw/mwgui/merchantrepair.cpp @@ -114,6 +114,8 @@ void MerchantRepair::onMouseWheel(MyGUI::Widget* _sender, int _rel) void MerchantRepair::open() { center(); + // Reset scrollbars + mList->setViewOffset(MyGUI::IntPoint(0, 0)); } void MerchantRepair::exit() diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index 834c156f9..685c7d45c 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -548,6 +548,7 @@ namespace MWGui WindowModal::open(); mMagicList->setModel(new SpellModel(MWBase::Environment::get().getWorld()->getPlayerPtr())); + mMagicList->resetScrollbars(); } void MagicSelectionDialog::onModelIndexSelected(SpellModel::ModelIndex index) diff --git a/apps/openmw/mwgui/recharge.cpp b/apps/openmw/mwgui/recharge.cpp index a0e5991b4..b7280565b 100644 --- a/apps/openmw/mwgui/recharge.cpp +++ b/apps/openmw/mwgui/recharge.cpp @@ -44,6 +44,8 @@ Recharge::Recharge() void Recharge::open() { center(); + // Reset scrollbars + mView->setViewOffset(MyGUI::IntPoint(0, 0)); } void Recharge::exit() diff --git a/apps/openmw/mwgui/repair.cpp b/apps/openmw/mwgui/repair.cpp index 9f26923d4..534226aeb 100644 --- a/apps/openmw/mwgui/repair.cpp +++ b/apps/openmw/mwgui/repair.cpp @@ -36,6 +36,8 @@ Repair::Repair() void Repair::open() { center(); + // Reset scrollbars + mRepairView->setViewOffset(MyGUI::IntPoint(0, 0)); } void Repair::exit() diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index d895a28ea..6991bb294 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -170,6 +171,7 @@ namespace MWGui setTitle("#{sOptions}"); + getWidget(mSettingsTab, "SettingsTab"); getWidget(mOkButton, "OkButton"); getWidget(mResolutionList, "ResolutionList"); getWidget(mFullscreenButton, "FullscreenButton"); @@ -208,6 +210,7 @@ namespace MWGui mMainWidget->castType()->eventWindowChangeCoord += MyGUI::newDelegate(this, &SettingsWindow::onWindowResize); + mSettingsTab->eventTabChangeSelect += MyGUI::newDelegate(this, &SettingsWindow::onTabChanged); mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onOkButtonClicked); mShaderModeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onShaderModeToggled); mTextureFilteringButton->eventComboChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onTextureFilteringChanged); @@ -275,6 +278,11 @@ namespace MWGui mControllerSwitch->setStateSelected(false); } + void SettingsWindow::onTabChanged(MyGUI::TabControl* /*_sender*/, size_t /*index*/) + { + resetScrollbars(); + } + void SettingsWindow::onOkButtonClicked(MyGUI::Widget* _sender) { exit(); @@ -480,6 +488,7 @@ namespace MWGui mKeyboardSwitch->setStateSelected(true); mControllerSwitch->setStateSelected(false); updateControlsBox(); + resetScrollbars(); } void SettingsWindow::onControllerSwitchClicked(MyGUI::Widget* _sender) @@ -490,6 +499,7 @@ namespace MWGui mKeyboardSwitch->setStateSelected(false); mControllerSwitch->setStateSelected(true); updateControlsBox(); + resetScrollbars(); } void SettingsWindow::updateControlsBox() @@ -584,6 +594,7 @@ namespace MWGui void SettingsWindow::open() { updateControlsBox (); + resetScrollbars(); } void SettingsWindow::exit() @@ -595,4 +606,10 @@ namespace MWGui { updateControlsBox(); } + + void SettingsWindow::resetScrollbars() + { + mResolutionList->setScrollPosition(0); + mControlsBox->setViewOffset(MyGUI::IntPoint(0, 0)); + } } diff --git a/apps/openmw/mwgui/settingswindow.hpp b/apps/openmw/mwgui/settingswindow.hpp index 1b970b8de..8910960b2 100644 --- a/apps/openmw/mwgui/settingswindow.hpp +++ b/apps/openmw/mwgui/settingswindow.hpp @@ -22,6 +22,7 @@ namespace MWGui void updateControlsBox(); protected: + MyGUI::TabControl* mSettingsTab; MyGUI::Button* mOkButton; // graphics @@ -50,6 +51,7 @@ namespace MWGui MyGUI::Button* mControllerSwitch; bool mKeyboardMode; //if true, setting up the keyboard. Otherwise, it's controller + void onTabChanged(MyGUI::TabControl* _sender, size_t index); void onOkButtonClicked(MyGUI::Widget* _sender); void onFpsToggled(MyGUI::Widget* _sender); void onTextureFilteringChanged(MyGUI::ComboBox* _sender, size_t pos); @@ -74,6 +76,9 @@ namespace MWGui void apply(); void configureWidgets(MyGUI::Widget* widget); + + private: + void resetScrollbars(); }; } diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index 1c670838f..a492ea7aa 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -551,6 +551,7 @@ namespace MWGui ++i; } mAvailableEffectsList->adjustSize (); + mAvailableEffectsList->scrollToTop(); for (std::vector::const_iterator it = knownEffects.begin(); it != knownEffects.end(); ++it) { diff --git a/apps/openmw/mwgui/spellview.cpp b/apps/openmw/mwgui/spellview.cpp index 6d86b4a23..af6ff00a5 100644 --- a/apps/openmw/mwgui/spellview.cpp +++ b/apps/openmw/mwgui/spellview.cpp @@ -311,4 +311,8 @@ namespace MWGui mScrollView->setViewOffset(MyGUI::IntPoint(0, static_cast(mScrollView->getViewOffset().top + _rel*0.3f))); } + void SpellView::resetScrollbars() + { + mScrollView->setViewOffset(MyGUI::IntPoint(0, 0)); + } } diff --git a/apps/openmw/mwgui/spellview.hpp b/apps/openmw/mwgui/spellview.hpp index 7af1bda7a..0f0b8a7d2 100644 --- a/apps/openmw/mwgui/spellview.hpp +++ b/apps/openmw/mwgui/spellview.hpp @@ -51,6 +51,8 @@ namespace MWGui virtual void setSize(const MyGUI::IntSize& _value); virtual void setCoord(const MyGUI::IntCoord& _value); + void resetScrollbars(); + private: MyGUI::ScrollView* mScrollView; diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index aecfce98d..bdcf28bf2 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -136,6 +136,7 @@ namespace MWGui mTradeModel = new TradeItemModel(new ContainerItemModel(itemSources, worldItems), mPtr); mSortModel = new SortFilterItemModel(mTradeModel); mItemView->setModel (mSortModel); + mItemView->resetScrollBars(); updateLabels(); From d8d43f94b94d023c441ac84ad2e0d77924bef9da Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 5 Jun 2015 02:06:13 +0200 Subject: [PATCH 1426/3725] Fix a typo --- components/nifosg/nifloader.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/nifosg/nifloader.hpp b/components/nifosg/nifloader.hpp index bf1dbe6b5..54f067e98 100644 --- a/components/nifosg/nifloader.hpp +++ b/components/nifosg/nifloader.hpp @@ -59,7 +59,7 @@ namespace NifOsg static void loadKf(Nif::NIFFilePtr kf, KeyframeHolder& target); /// Set whether or not nodes marked as "MRK" should be shown. - /// These should be hidden ingame, but visible in the editior. + /// These should be hidden ingame, but visible in the editor. /// Default: false. static void setShowMarkers(bool show); From ddfed35d1ce26ea6b553cf57221b4cab2dc53ba3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 5 Jun 2015 02:26:16 +0200 Subject: [PATCH 1427/3725] Object placement raycasts should use the rendering meshes --- apps/openmw/mwrender/renderingmanager.cpp | 96 ++++++++++++++--------- apps/openmw/mwrender/renderingmanager.hpp | 15 +++- apps/openmw/mwworld/worldimp.cpp | 36 +++------ 3 files changed, 79 insertions(+), 68 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 7af21a5a6..d1811ed67 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -438,21 +438,6 @@ namespace MWRender mViewer->getCamera()->setCullMask(oldCullMask); } - void RenderingManager::getCameraToViewportRay(float nX, float nY, osg::Vec3f &origin, osg::Vec3f &dest) - { - osg::Matrix viewProj = mViewer->getCamera()->getViewMatrix() * mViewer->getCamera()->getProjectionMatrix(); - osg::Matrix invViewProj = viewProj.inverse(viewProj); - - nX = nX * 2 - 1; - nY = nY * -2 + 1; - - osg::Vec3f start (nX, nY, -1.f); - osg::Vec3f end (nX, nY, 1.f); - - origin = invViewProj.preMult(start); - dest = invViewProj.preMult(end); - } - osg::Vec4f RenderingManager::getScreenBounds(const MWWorld::Ptr& ptr) { if (!ptr.getRefData().getBaseNode()) @@ -487,7 +472,61 @@ namespace MWRender return osg::Vec4f(min_x, min_y, max_x, max_y); } - MWWorld::Ptr RenderingManager::getFacedObject(const float nX, const float nY, float maxDistance, bool ignorePlayer) + RenderingManager::RayResult getIntersectionResult (osgUtil::LineSegmentIntersector* intersector) + { + RenderingManager::RayResult result; + result.mHit = false; + if (intersector->containsIntersections()) + { + result.mHit = true; + osgUtil::LineSegmentIntersector::Intersection intersection = intersector->getFirstIntersection(); + + result.mHitPointWorld = intersection.getWorldIntersectPoint(); + result.mHitNormalWorld = intersection.getWorldIntersectNormal(); + + PtrHolder* ptrHolder = NULL; + for (osg::NodePath::const_iterator it = intersection.nodePath.begin(); it != intersection.nodePath.end(); ++it) + { + osg::UserDataContainer* userDataContainer = (*it)->getUserDataContainer(); + if (!userDataContainer) + continue; + for (unsigned int i=0; igetNumUserObjects(); ++i) + { + if (PtrHolder* p = dynamic_cast(userDataContainer->getUserObject(i))) + ptrHolder = p; + } + } + + if (ptrHolder) + result.mHitObject = ptrHolder->mPtr; + } + + return result; + + } + + RenderingManager::RayResult RenderingManager::castRay(const osg::Vec3f& origin, const osg::Vec3f& dest, bool ignorePlayer, bool ignoreActors) + { + osg::ref_ptr intersector (new osgUtil::LineSegmentIntersector(osgUtil::LineSegmentIntersector::MODEL, + origin, dest)); + intersector->setIntersectionLimit(osgUtil::LineSegmentIntersector::LIMIT_NEAREST); + + osgUtil::IntersectionVisitor intersectionVisitor(intersector); + int mask = intersectionVisitor.getTraversalMask(); + mask &= ~(Mask_RenderToTexture|Mask_Sky|Mask_Debug|Mask_Effect|Mask_Water); + if (ignorePlayer) + mask &= ~(Mask_Player); + if (ignoreActors) + mask &= ~(Mask_Actor|Mask_Player); + + intersectionVisitor.setTraversalMask(mask); + + mRootNode->accept(intersectionVisitor); + + return getIntersectionResult(intersector); + } + + RenderingManager::RayResult RenderingManager::castCameraToViewportRay(const float nX, const float nY, float maxDistance, bool ignorePlayer, bool ignoreActors) { osg::ref_ptr intersector (new osgUtil::LineSegmentIntersector(osgUtil::LineSegmentIntersector::PROJECTION, nX * 2.f - 1.f, nY * (-2.f) + 1.f)); @@ -506,33 +545,14 @@ namespace MWRender mask &= ~(Mask_RenderToTexture|Mask_Sky|Mask_Debug|Mask_Effect|Mask_Water); if (ignorePlayer) mask &= ~(Mask_Player); + if (ignoreActors) + mask &= ~(Mask_Actor|Mask_Player); intersectionVisitor.setTraversalMask(mask); mViewer->getCamera()->accept(intersectionVisitor); - if (intersector->containsIntersections()) - { - osgUtil::LineSegmentIntersector::Intersection intersection = intersector->getFirstIntersection(); - - PtrHolder* ptrHolder = NULL; - for (osg::NodePath::const_iterator it = intersection.nodePath.begin(); it != intersection.nodePath.end(); ++it) - { - osg::UserDataContainer* userDataContainer = (*it)->getUserDataContainer(); - if (!userDataContainer) - continue; - for (unsigned int i=0; igetNumUserObjects(); ++i) - { - if (PtrHolder* p = dynamic_cast(userDataContainer->getUserObject(i))) - ptrHolder = p; - } - } - - if (ptrHolder) - return ptrHolder->mPtr; - } - - return MWWorld::Ptr(); + return getIntersectionResult(intersector); } void RenderingManager::updatePtr(const MWWorld::Ptr &old, const MWWorld::Ptr &updated) diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 4452ae9f8..8ed590df4 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -85,16 +85,23 @@ namespace MWRender /// Take a screenshot of w*h onto the given image, not including the GUI. void screenshot(osg::Image* image, int w, int h); + struct RayResult + { + bool mHit; + osg::Vec3f mHitNormalWorld; + osg::Vec3f mHitPointWorld; + MWWorld::Ptr mHitObject; + }; + + RayResult castRay(const osg::Vec3f& origin, const osg::Vec3f& dest, bool ignorePlayer, bool ignoreActors=false); + /// Return the object under the mouse cursor / crosshair position, given by nX and nY normalized screen coordinates, /// where (0,0) is the top left corner. - MWWorld::Ptr getFacedObject(const float nX, const float nY, float maxDistance, bool ignorePlayer); + RayResult castCameraToViewportRay(const float nX, const float nY, float maxDistance, bool ignorePlayer, bool ignoreActors=false); /// Get the bounding box of the given object in screen coordinates as (minX, minY, maxX, maxY), with (0,0) being the top left corner. osg::Vec4f getScreenBounds(const MWWorld::Ptr& ptr); - /// Get a camera to viewport ray for normalized screen coordinates nX and nY, with the top left corner being at (0,0) - void getCameraToViewportRay(float nX, float nY, osg::Vec3f& origin, osg::Vec3f& dest); - void setSkyEnabled(bool enabled); bool toggleRenderMode(RenderMode mode); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 9a42d4587..9179f94f6 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1662,11 +1662,11 @@ namespace MWWorld { float x, y; MWBase::Environment::get().getWindowManager()->getMousePosition(x, y); - return mRendering->getFacedObject(x, y, maxDistance, ignorePlayer); + return mRendering->castCameraToViewportRay(x, y, maxDistance, ignorePlayer).mHitObject; } else { - return mRendering->getFacedObject(0.5f, 0.5f, maxDistance, ignorePlayer); + return mRendering->castCameraToViewportRay(0.5f, 0.5f, maxDistance, ignorePlayer).mHitObject; } } @@ -1790,25 +1790,18 @@ namespace MWWorld MWWorld::Ptr World::placeObject (const MWWorld::Ptr& object, float cursorX, float cursorY, int amount) { - osg::Vec3f origin, dest; - mRendering->getCameraToViewportRay(cursorX, cursorY, origin, dest); - const float maxDist = 200.f; - osg::Vec3f dir = (dest - origin); - dir.normalize(); - dest = origin + dir * maxDist; - MWPhysics::PhysicsSystem::RayResult result = mPhysics->castRay(origin, dest, MWWorld::Ptr(), - MWPhysics::CollisionType_World|MWPhysics::CollisionType_HeightMap); + MWRender::RenderingManager::RayResult result = mRendering->castCameraToViewportRay(cursorX, cursorY, maxDist, true, true); CellStore* cell = getPlayerPtr().getCell(); ESM::Position pos = getPlayerPtr().getRefData().getPosition(); if (result.mHit) { - pos.pos[0] = result.mHitPos.x(); - pos.pos[1] = result.mHitPos.y(); - pos.pos[2] = result.mHitPos.z(); + pos.pos[0] = result.mHitPointWorld.x(); + pos.pos[1] = result.mHitPointWorld.y(); + pos.pos[2] = result.mHitPointWorld.z(); } // We want only the Z part of the player's rotation pos.rot[0] = 0; @@ -1828,21 +1821,13 @@ namespace MWWorld bool World::canPlaceObject(float cursorX, float cursorY) { - osg::Vec3f origin, dest; - mRendering->getCameraToViewportRay(cursorX, cursorY, origin, dest); - const float maxDist = 200.f; - osg::Vec3f dir = (dest - origin); - dir.normalize(); - dest = origin + dir * maxDist; - - MWPhysics::PhysicsSystem::RayResult result = mPhysics->castRay(origin, dest, MWWorld::Ptr(), - MWPhysics::CollisionType_World|MWPhysics::CollisionType_HeightMap); + MWRender::RenderingManager::RayResult result = mRendering->castCameraToViewportRay(cursorX, cursorY, maxDist, true, true); if (result.mHit) { // check if the wanted position is on a flat surface, and not e.g. against a vertical wall - if (std::acos(result.mHitNormal * osg::Vec3f(0,0,1)) >= osg::DegreesToRadians(30.f)) + if (std::acos(result.mHitNormalWorld * osg::Vec3f(0,0,1)) >= osg::DegreesToRadians(30.f)) return false; return true; @@ -1925,10 +1910,9 @@ namespace MWWorld float len = 100.0; - MWPhysics::PhysicsSystem::RayResult result = mPhysics->castRay(orig, orig+dir*len, MWWorld::Ptr(), - MWPhysics::CollisionType_World|MWPhysics::CollisionType_HeightMap); + MWRender::RenderingManager::RayResult result = mRendering->castRay(orig, orig+dir*len, true, true); if (result.mHit) - pos.pos[2] = result.mHitPos.z(); + pos.pos[2] = result.mHitPointWorld.z(); // copy the object and set its count int origCount = object.getRefData().getCount(); From 89fc473fae453a9d4eeb76d5eb1a9509931b0763 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 5 Jun 2015 02:35:13 +0200 Subject: [PATCH 1428/3725] Remove Render System combo box from the launcher UI --- files/ui/graphicspage.ui | 23 ++--------------------- 1 file changed, 2 insertions(+), 21 deletions(-) diff --git a/files/ui/graphicspage.ui b/files/ui/graphicspage.ui index f9ea63efe..2d84d9f26 100644 --- a/files/ui/graphicspage.ui +++ b/files/ui/graphicspage.ui @@ -6,30 +6,11 @@ 0 0 - 332 - 297 + 437 + 343 - - - - Render System - - - - - - Rendering Subsystem: - - - - - - - - - From 76328677eff4e5a3e66e21110be0183834327e86 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 5 Jun 2015 02:48:51 +0200 Subject: [PATCH 1429/3725] Add some values to launcher's antialiasing combobox --- files/ui/graphicspage.ui | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/files/ui/graphicspage.ui b/files/ui/graphicspage.ui index 2d84d9f26..0afda6ac7 100644 --- a/files/ui/graphicspage.ui +++ b/files/ui/graphicspage.ui @@ -63,7 +63,33 @@ - + + + + 0 + + + + + 2 + + + + + 4 + + + + + 8 + + + + + 16 + + + From 403ce30a352e468de4a8d685ea3ce0f3ab4a4663 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 5 Jun 2015 02:53:10 +0200 Subject: [PATCH 1430/3725] Graceful handling for failing to create SDL window --- apps/openmw/engine.cpp | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index a37d84621..f23e414ab 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -350,11 +350,28 @@ void OMW::Engine::createWindow(Settings::Manager& settings) std::cerr << "SDL error: " << SDL_GetError() << std::endl; } - mWindow = SDL_CreateWindow("OpenMW", pos_x, pos_y, width, height, flags); - if (mWindow == NULL) + while (!mWindow) { - std::cerr << "Failed to create SDL window: " << SDL_GetError() << std::endl; - return; + mWindow = SDL_CreateWindow("OpenMW", pos_x, pos_y, width, height, flags); + if (!mWindow) + { + // Try with a lower AA + if (antialiasing > 0) + { + std::cout << "Note: " << antialiasing << "x antialiasing not supported, trying " << antialiasing/2 << std::endl; + antialiasing /= 2; + Settings::Manager::setInt("antialiasing", "Video", antialiasing); + if (SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, antialiasing) != 0) + std::cerr << "SDL error: " << SDL_GetError() << std::endl; + continue; + } + else + { + std::stringstream error; + error << "Failed to create SDL window: " << SDL_GetError() << std::endl; + throw std::runtime_error(error.str()); + } + } } setWindowIcon(); From 700000cbca818fd170fb1f28abe8e37b5cfc9737 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 5 Jun 2015 02:57:31 +0200 Subject: [PATCH 1431/3725] Error handling fix --- apps/openmw/engine.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index f23e414ab..eda33637b 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -411,6 +411,11 @@ void OMW::Engine::setWindowIcon() if (windowIconStream.fail()) std::cerr << "Failed to open " << windowIcon << std::endl; osgDB::ReaderWriter* reader = osgDB::Registry::instance()->getReaderWriterForExtension("png"); + if (!reader) + { + std::cerr << "Failed to read window icon, no png readerwriter found" << std::endl; + return; + } osgDB::ReaderWriter::ReadResult result = reader->readImage(windowIconStream); if (!result.success()) std::cerr << "Failed to read " << windowIcon << ": " << result.message() << std::endl; From 1fd48e6f819da2c2f15bdf5cb27dca5a85e39365 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 5 Jun 2015 03:35:59 +0200 Subject: [PATCH 1432/3725] Fix not being able to move during ashstorm --- apps/openmw/mwphysics/physicssystem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index f97c5fd13..c7df22aef 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -288,7 +288,7 @@ namespace MWPhysics if (MWBase::Environment::get().getWorld()->isInStorm()) { osg::Vec3f stormDirection = MWBase::Environment::get().getWorld()->getStormDirection(); - float angleDegrees = osg::RadiansToDegrees(std::acos(stormDirection * velocity)); + float angleDegrees = osg::RadiansToDegrees(std::acos(stormDirection * velocity / (stormDirection.length() * velocity.length()))); static const float fStromWalkMult = MWBase::Environment::get().getWorld()->getStore().get() .find("fStromWalkMult")->getFloat(); velocity *= 1.f-(fStromWalkMult * (angleDegrees/180.f)); From 4c09ecef72f90515d17b51881f377f88efd5d1f4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 5 Jun 2015 03:41:10 +0200 Subject: [PATCH 1433/3725] Normalize fixes --- apps/openmw/mwmechanics/character.cpp | 3 ++- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 4 +++- apps/openmw/mwworld/worldimp.cpp | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index d4ba561ed..ea6b39481 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -855,7 +855,8 @@ void CharacterController::updateIdleStormState() { osg::Vec3f stormDirection = MWBase::Environment::get().getWorld()->getStormDirection(); osg::Vec3f characterDirection = mPtr.getRefData().getBaseNode()->getAttitude() * osg::Vec3f(0,1,0); - inStormDirection = std::acos(stormDirection * characterDirection) > osg::DegreesToRadians(120.f); + inStormDirection = std::acos(stormDirection * characterDirection / (stormDirection.length() * characterDirection.length())) + > osg::DegreesToRadians(120.f); } if (inStormDirection && mUpperBodyState == UpperCharState_Nothing && mAnimation->hasAnimation("idlestorm")) { diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index b89b8c94a..7bc6a34ae 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1388,7 +1388,9 @@ namespace MWMechanics osg::Vec3f vec = pos1 - pos2; if (observer.getRefData().getBaseNode()) { - float angleRadians = std::acos((observer.getRefData().getBaseNode()->getAttitude() * osg::Vec3f(0,1,0)) * vec); + osg::Vec3f observerDir = (observer.getRefData().getBaseNode()->getAttitude() * osg::Vec3f(0,1,0)); + + float angleRadians = std::acos(observerDir * vec / (observerDir.length() * vec.length())); if (angleRadians < osg::DegreesToRadians(90.f)) y = obsTerm * observerStats.getFatigueTerm() * fSneakNoViewMult; else diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 9179f94f6..a2e66a96f 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1827,7 +1827,7 @@ namespace MWWorld if (result.mHit) { // check if the wanted position is on a flat surface, and not e.g. against a vertical wall - if (std::acos(result.mHitNormalWorld * osg::Vec3f(0,0,1)) >= osg::DegreesToRadians(30.f)) + if (std::acos((result.mHitNormalWorld/result.mHitNormalWorld.length()) * osg::Vec3f(0,0,1)) >= osg::DegreesToRadians(30.f)) return false; return true; From 5c37079f0c06d1837da2b3d6e3f3763d709550dc Mon Sep 17 00:00:00 2001 From: cc9cii Date: Fri, 5 Jun 2015 12:19:21 +1000 Subject: [PATCH 1434/3725] Include only the columns that are visible for sorting. Should resolve Bug #2611. --- apps/opencs/model/world/idtableproxymodel.cpp | 12 ++++++++++++ apps/opencs/model/world/idtableproxymodel.hpp | 6 ++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/world/idtableproxymodel.cpp b/apps/opencs/model/world/idtableproxymodel.cpp index 987d27462..3697b055f 100644 --- a/apps/opencs/model/world/idtableproxymodel.cpp +++ b/apps/opencs/model/world/idtableproxymodel.cpp @@ -21,6 +21,18 @@ void CSMWorld::IdTableProxyModel::updateColumnMap() } } +bool CSMWorld::IdTableProxyModel::filterAcceptsColumn (int sourceColumn, const QModelIndex& sourceParent) + const +{ + int flags = + sourceModel()->headerData (sourceColumn, Qt::Horizontal, CSMWorld::ColumnBase::Role_Flags).toInt(); + + if (flags & CSMWorld::ColumnBase::Flag_Table) + return true; + else + return false; +} + bool CSMWorld::IdTableProxyModel::filterAcceptsRow (int sourceRow, const QModelIndex& sourceParent) const { diff --git a/apps/opencs/model/world/idtableproxymodel.hpp b/apps/opencs/model/world/idtableproxymodel.hpp index 8683c2b9e..89480f288 100644 --- a/apps/opencs/model/world/idtableproxymodel.hpp +++ b/apps/opencs/model/world/idtableproxymodel.hpp @@ -24,8 +24,6 @@ namespace CSMWorld void updateColumnMap(); - bool filterAcceptsRow (int sourceRow, const QModelIndex& sourceParent) const; - public: IdTableProxyModel (QObject *parent = 0); @@ -39,6 +37,10 @@ namespace CSMWorld protected: bool lessThan(const QModelIndex &left, const QModelIndex &right) const; + + virtual bool filterAcceptsRow (int sourceRow, const QModelIndex& sourceParent) const; + + virtual bool filterAcceptsColumn (int sourceColumn, const QModelIndex& sourceParent) const; }; } From 0afc03b6b74e4df7b348260ae13bcd9d292db06e Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 5 Jun 2015 16:56:38 +0200 Subject: [PATCH 1435/3725] Build fix --- components/esmterrain/storage.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/esmterrain/storage.cpp b/components/esmterrain/storage.cpp index 0795a3ffc..1811f58e6 100644 --- a/components/esmterrain/storage.cpp +++ b/components/esmterrain/storage.cpp @@ -28,8 +28,8 @@ namespace ESMTerrain osg::Vec2f origin = center - osg::Vec2f(size/2.f, size/2.f); - assert(origin.x == (int) origin.x()); - assert(origin.y == (int) origin.y()); + assert(origin.x() == (int) origin.x()); + assert(origin.y() == (int) origin.y()); int cellX = static_cast(origin.x()); int cellY = static_cast(origin.y()); From 58e2d3711f0c6fad58218d7fc6f1914324763068 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Fri, 5 Jun 2015 22:00:02 +0300 Subject: [PATCH 1436/3725] Reset Console editbox before command execution --- apps/openmw/mwgui/console.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/console.cpp b/apps/openmw/mwgui/console.cpp index 4eb9a271c..62eeca012 100644 --- a/apps/openmw/mwgui/console.cpp +++ b/apps/openmw/mwgui/console.cpp @@ -294,10 +294,9 @@ namespace MWGui mCommandHistory.push_back(cm); mCurrent = mCommandHistory.end(); mEditString.clear(); + mCommandLine->setCaption(""); execute (cm); - - mCommandLine->setCaption(""); } std::string Console::complete( std::string input, std::vector &matches ) From d2293867ba0914993866275e173880c9f079c08a Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Fri, 5 Jun 2015 22:44:06 +0300 Subject: [PATCH 1437/3725] Add the explanation to Console::acceptCommand() --- apps/openmw/mwgui/console.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/openmw/mwgui/console.cpp b/apps/openmw/mwgui/console.cpp index 62eeca012..a1f564ffa 100644 --- a/apps/openmw/mwgui/console.cpp +++ b/apps/openmw/mwgui/console.cpp @@ -294,6 +294,10 @@ namespace MWGui mCommandHistory.push_back(cm); mCurrent = mCommandHistory.end(); mEditString.clear(); + + // Reset the command line before the command execution. + // It prevents re-triggering the acceptCommand() event during + // the actual command execution. mCommandLine->setCaption(""); execute (cm); From 49512a2b57fe2f0eb420ee37b1210c596556161a Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Fri, 5 Jun 2015 22:57:35 +0300 Subject: [PATCH 1438/3725] Correct the explanation for the Console::acceptCommand() --- apps/openmw/mwgui/console.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/console.cpp b/apps/openmw/mwgui/console.cpp index a1f564ffa..083dd32b0 100644 --- a/apps/openmw/mwgui/console.cpp +++ b/apps/openmw/mwgui/console.cpp @@ -296,8 +296,8 @@ namespace MWGui mEditString.clear(); // Reset the command line before the command execution. - // It prevents re-triggering the acceptCommand() event during - // the actual command execution. + // It prevents the re-triggering of the acceptCommand() event for the same command + // during the actual command execution mCommandLine->setCaption(""); execute (cm); From 15fe5d88e2b3c7d172a28bd453b3e0d5f89295aa Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 6 Jun 2015 20:35:55 +1000 Subject: [PATCH 1439/3725] Allow comments (lines starting with # character) and blank lines in openmw.cfg. Should resolve Feature #2535. - controlled via a checkbox in launcher settings --- apps/launcher/maindialog.cpp | 21 ++++- apps/launcher/settingspage.cpp | 8 ++ components/config/gamesettings.cpp | 128 +++++++++++++++++++++++++++++ components/config/gamesettings.hpp | 2 + files/ui/settingspage.ui | 10 +++ 5 files changed, 166 insertions(+), 3 deletions(-) diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index fd36993bf..27d37dbf0 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -490,7 +490,16 @@ bool Launcher::MainDialog::writeSettings() // Game settings QFile file(userPath + QString("openmw.cfg")); - if (!file.open(QIODevice::ReadWrite | QIODevice::Text | QIODevice::Truncate)) { + QIODevice::OpenMode mode(0); + bool keepComments = mLauncherSettings.value(QString("Settings/keep-comments"), QString("true")) + == QLatin1String("true"); + + if (keepComments) + mode = QIODevice::ReadWrite | QIODevice::Text; + else + mode = QIODevice::ReadWrite | QIODevice::Text | QIODevice::Truncate; + + if (!file.open(mode)) { // File cannot be opened or created QMessageBox msgBox; msgBox.setWindowTitle(tr("Error writing OpenMW configuration file")); @@ -504,9 +513,15 @@ bool Launcher::MainDialog::writeSettings() } QTextStream stream(&file); - stream.setCodec(QTextCodec::codecForName("UTF-8")); - mGameSettings.writeFile(stream); + if (keepComments) + mGameSettings.writeFileWithComments(file); + else + { + stream.setCodec(QTextCodec::codecForName("UTF-8")); + mGameSettings.writeFile(stream); + } + file.close(); // Graphics settings diff --git a/apps/launcher/settingspage.cpp b/apps/launcher/settingspage.cpp index 843b51391..bc8ffe618 100644 --- a/apps/launcher/settingspage.cpp +++ b/apps/launcher/settingspage.cpp @@ -260,6 +260,10 @@ void Launcher::SettingsPage::saveSettings() } else { mGameSettings.setValue(QLatin1String("encoding"), QLatin1String("win1252")); } + + QString keepComments(saveCommentsCheckBox->isChecked() ? "true" : "false"); + + mLauncherSettings.setValue(QLatin1String("Settings/keep-comments"), keepComments); } bool Launcher::SettingsPage::loadSettings() @@ -271,5 +275,9 @@ bool Launcher::SettingsPage::loadSettings() if (index != -1) languageComboBox->setCurrentIndex(index); + QString keepComments(mLauncherSettings.value(QLatin1String("Settings/keep-comments"))); + + saveCommentsCheckBox->setChecked(keepComments == "true"); + return true; } diff --git a/components/config/gamesettings.cpp b/components/config/gamesettings.cpp index 0481235c7..51c7883ad 100644 --- a/components/config/gamesettings.cpp +++ b/components/config/gamesettings.cpp @@ -1,6 +1,7 @@ #include "gamesettings.hpp" #include "launchersettings.hpp" +#include #include #include #include @@ -173,6 +174,133 @@ bool Config::GameSettings::writeFile(QTextStream &stream) return true; } +// Policy: +// +// - Always ignore a line beginning with '#' or empty lines +// +// - If a line in file exists with matching key and first part of value (before ',', +// '\n', etc) also matches, then replace the line with that of mUserSettings. +// - else remove line (maybe replace the line with '#' in front instead?) +// +// - If there is no corresponding line in file, add at the end +// +bool Config::GameSettings::writeFileWithComments(QFile &file) +{ + QTextStream stream(&file); + stream.setCodec(QTextCodec::codecForName("UTF-8")); + + // slurp + std::vector fileCopy; + QString line = stream.readLine(); + while (!line.isNull()) + { + fileCopy.push_back(line); + line = stream.readLine(); + } + stream.seek(0); + + // empty file, no comments to keep + if (fileCopy.empty()) + return writeFile(stream); + + // Temp copy of settings to save, but with the keys appended with the first part of the value + // + // ATTENTION! + // + // A hack to avoid looping through each line, makes use of the fact that fallbacks values + // are comma separated. + QMap userSettingsCopy; + QRegExp settingRegex("^([^=]+)\\s*=\\s*([^,]+)(.*)$"); + QString settingLine; + QMap::const_iterator settingsIter = mUserSettings.begin(); + for (; settingsIter != mUserSettings.end(); ++settingsIter) + { + settingLine = settingsIter.key()+"="+settingsIter.value(); + if (settingRegex.indexIn(settingLine) != -1) + { + userSettingsCopy[settingRegex.cap(1)+"="+settingRegex.cap(2)] = + (settingRegex.captureCount() < 3) ? "" : settingRegex.cap(3); + } + } + + QString keyVal; + for (std::vector::iterator iter = fileCopy.begin(); iter != fileCopy.end(); ++iter) + { + // skip empty or comment lines + if ((*iter).isEmpty() || (*iter).startsWith("#")) + continue; + + // look for a key in the line + if (settingRegex.indexIn(*iter) == -1 || settingRegex.captureCount() < 2) + { + // no key or first part of value found in line, replace with a null string which + // will be remved later + *iter = QString(); + continue; + } + + // look for a matching key in user settings + keyVal = settingRegex.cap(1)+"="+settingRegex.cap(2); + QMap::iterator it = userSettingsCopy.find(keyVal); + if (it == userSettingsCopy.end()) + { + // no such key+valStart, replace with a null string which will be remved later + *iter = QString(); + } + else + { + *iter = QString(it.key()+it.value()); + userSettingsCopy.erase(it); + } + } + + // write the new config file + QString key; + QString value; + for (std::vector::iterator iter = fileCopy.begin(); iter != fileCopy.end(); ++iter) + { + if ((*iter).isNull()) + continue; + + if ((*iter).isEmpty() || (*iter).startsWith("#")) + stream << *iter << "\n"; + + if (settingRegex.indexIn(*iter) == -1 || settingRegex.captureCount() < 2) + continue; + + // Quote paths with spaces + key = settingRegex.cap(1); + value = settingRegex.cap(2)+settingRegex.cap(3); + if (key == QLatin1String("data") + || key == QLatin1String("data-local") + || key == QLatin1String("resources")) + { + if (value.contains(QChar(' '))) + { + value.remove(QChar('\"')); // Remove quotes + + stream << key << "=\"" << value << "\"\n"; + continue; + } + } + stream << key << "=" << value << "\n"; + } + + if (!userSettingsCopy.empty()) + { + stream << "# new entries" << "\n"; + QMap::const_iterator it = userSettingsCopy.begin(); + for (; it != userSettingsCopy.end(); ++it) + { + stream << it.key() << it.value() << "\n"; + } + } + + file.resize(file.pos()); + + return true; +} + bool Config::GameSettings::hasMaster() { bool result = false; diff --git a/components/config/gamesettings.hpp b/components/config/gamesettings.hpp index cc5033f35..35614113f 100644 --- a/components/config/gamesettings.hpp +++ b/components/config/gamesettings.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -66,6 +67,7 @@ namespace Config bool readUserFile(QTextStream &stream); bool writeFile(QTextStream &stream); + bool writeFileWithComments(QFile &file); void setContentList(const QStringList& fileNames); QStringList getContentList() const; diff --git a/files/ui/settingspage.ui b/files/ui/settingspage.ui index 7f5e4a7de..f38ba764c 100644 --- a/files/ui/settingspage.ui +++ b/files/ui/settingspage.ui @@ -40,6 +40,16 @@ + + + + Keep comments in openmw.cfg + + + false + + + From d63b01dde3ebe251d9dafd157ca1104bcf413db9 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sat, 6 Jun 2015 15:41:25 +0300 Subject: [PATCH 1440/3725] Checkboxes in the table view use a combobox editor --- apps/opencs/view/world/util.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/apps/opencs/view/world/util.cpp b/apps/opencs/view/world/util.cpp index 3be875ffd..e1d165a24 100644 --- a/apps/opencs/view/world/util.cpp +++ b/apps/opencs/view/world/util.cpp @@ -152,7 +152,17 @@ void CSVWorld::CommandDelegate::setModelData (QWidget *editor, QAbstractItemMode QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleOptionViewItem& option, const QModelIndex& index) const { - return createEditor (parent, option, index, getDisplayTypeFromIndex(index)); + CSMWorld::ColumnBase::Display display = getDisplayTypeFromIndex(index); + + // This createEditor() method is called implicitly from tables. + // For boolean values in tables use the default editor (combobox). + // Checkboxes is looking ugly in the table view. + // TODO: Find a better solution? + if (display == CSMWorld::ColumnBase::Display_Boolean) + { + return QStyledItemDelegate::createEditor(parent, option, index); + } + return createEditor (parent, option, index, display); } QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleOptionViewItem& option, From 4902c6679210dee8b5158d05d99b072c2f06a494 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 7 Jun 2015 07:21:15 +1000 Subject: [PATCH 1441/3725] Allow space characters in front of comments. --- components/config/gamesettings.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/components/config/gamesettings.cpp b/components/config/gamesettings.cpp index 51c7883ad..1215f0850 100644 --- a/components/config/gamesettings.cpp +++ b/components/config/gamesettings.cpp @@ -180,7 +180,7 @@ bool Config::GameSettings::writeFile(QTextStream &stream) // // - If a line in file exists with matching key and first part of value (before ',', // '\n', etc) also matches, then replace the line with that of mUserSettings. -// - else remove line (maybe replace the line with '#' in front instead?) +// - else remove line (TODO: maybe replace the line with '#' in front instead?) // // - If there is no corresponding line in file, add at the end // @@ -224,10 +224,10 @@ bool Config::GameSettings::writeFileWithComments(QFile &file) } QString keyVal; - for (std::vector::iterator iter = fileCopy.begin(); iter != fileCopy.end(); ++iter) + for (std::vector::iterator iter = fileCopy.begin(); iter != fileCopy.end(); ++iter) { // skip empty or comment lines - if ((*iter).isEmpty() || (*iter).startsWith("#")) + if ((*iter).isEmpty() || (*iter).contains(QRegExp("^\\s*#"))) continue; // look for a key in the line @@ -257,12 +257,14 @@ bool Config::GameSettings::writeFileWithComments(QFile &file) // write the new config file QString key; QString value; - for (std::vector::iterator iter = fileCopy.begin(); iter != fileCopy.end(); ++iter) + for (std::vector::iterator iter = fileCopy.begin(); iter != fileCopy.end(); ++iter) { if ((*iter).isNull()) continue; - if ((*iter).isEmpty() || (*iter).startsWith("#")) + // Below is based on readFile() code, if that changes corresponding change may be + // required (for example duplicates may be inserted if the rules don't match) + if ((*iter).isEmpty() || (*iter).contains(QRegExp("^\\s*#"))) stream << *iter << "\n"; if (settingRegex.indexIn(*iter) == -1 || settingRegex.captureCount() < 2) From a439f49c4db32a340826ae9b77c940ca59e79e5f Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 7 Jun 2015 07:38:52 +1000 Subject: [PATCH 1442/3725] Fix loop where there was a potential for double entry. --- components/config/gamesettings.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/components/config/gamesettings.cpp b/components/config/gamesettings.cpp index 1215f0850..2b3a8ba4b 100644 --- a/components/config/gamesettings.cpp +++ b/components/config/gamesettings.cpp @@ -265,7 +265,10 @@ bool Config::GameSettings::writeFileWithComments(QFile &file) // Below is based on readFile() code, if that changes corresponding change may be // required (for example duplicates may be inserted if the rules don't match) if ((*iter).isEmpty() || (*iter).contains(QRegExp("^\\s*#"))) + { stream << *iter << "\n"; + continue; + } if (settingRegex.indexIn(*iter) == -1 || settingRegex.captureCount() < 2) continue; From 68e322f969344f571a99a44b3ba99bf630363f46 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 7 Jun 2015 01:47:19 +0200 Subject: [PATCH 1443/3725] Restore data directory verbose output that got lost --- components/vfs/registerarchives.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/components/vfs/registerarchives.cpp b/components/vfs/registerarchives.cpp index aeda3191d..b361e3f42 100644 --- a/components/vfs/registerarchives.cpp +++ b/components/vfs/registerarchives.cpp @@ -35,6 +35,7 @@ namespace VFS if (useLooseFiles) for (Files::PathContainer::const_iterator iter = dataDirs.begin(); iter != dataDirs.end(); ++iter) { + std::cout << "Adding data directory " << iter->string() << std::endl; // Last data dir has the highest priority vfs->addArchive(new FileSystemArchive(iter->string())); } From 0a411cbd7cd55cacb5c8c2c1efcbf5dddf8f862e Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 7 Jun 2015 04:41:55 +0200 Subject: [PATCH 1444/3725] Enable particle lighting --- apps/openmw/mwrender/animation.cpp | 3 +++ components/nifosg/nifloader.cpp | 13 +++++++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 80877e08b..6af8a49a4 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1067,6 +1067,9 @@ namespace MWRender parentNode = found->second; } osg::ref_ptr node = mResourceSystem->getSceneManager()->createInstance(model, parentNode); + + node->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF); + params.mObjects = PartHolderPtr(new PartHolder(node)); SceneUtil::FindMaxControllerLengthVisitor findMaxLengthVisitor; diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 1f089f0c4..530aa3dec 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -6,9 +6,6 @@ #include #include -#include -#include - // resource #include #include @@ -862,7 +859,15 @@ namespace NifOsg collectMaterialProperties(nifNode, materialProps); applyMaterialProperties(geode, materialProps, true, animflags); - partsys->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF); + // Particles don't have normals, so can't be diffuse lit. + osg::Material* mat = static_cast(geode->getStateSet()->getAttribute(osg::StateAttribute::MATERIAL)); + if (mat) + { + osg::Vec4f diffuse = mat->getDiffuse(osg::Material::FRONT_AND_BACK); + mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0,0,0,diffuse.a())); + mat->setColorMode(osg::Material::AMBIENT); + } + partsys->getOrCreateStateSet()->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); // particle system updater (after the emitters and affectors in the scene graph) From d3b7cf44d391ba9624f28070e68784352e6f514d Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 7 Jun 2015 13:29:45 +1000 Subject: [PATCH 1445/3725] Remove user preference setting option. --- apps/launcher/maindialog.cpp | 22 +++------------------- apps/launcher/settingspage.cpp | 8 -------- files/ui/settingspage.ui | 10 ---------- 3 files changed, 3 insertions(+), 37 deletions(-) diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index 27d37dbf0..2f7a9db33 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -490,16 +490,7 @@ bool Launcher::MainDialog::writeSettings() // Game settings QFile file(userPath + QString("openmw.cfg")); - QIODevice::OpenMode mode(0); - bool keepComments = mLauncherSettings.value(QString("Settings/keep-comments"), QString("true")) - == QLatin1String("true"); - - if (keepComments) - mode = QIODevice::ReadWrite | QIODevice::Text; - else - mode = QIODevice::ReadWrite | QIODevice::Text | QIODevice::Truncate; - - if (!file.open(mode)) { + if (!file.open(QIODevice::ReadWrite | QIODevice::Text)) { // File cannot be opened or created QMessageBox msgBox; msgBox.setWindowTitle(tr("Error writing OpenMW configuration file")); @@ -512,16 +503,8 @@ bool Launcher::MainDialog::writeSettings() return false; } - QTextStream stream(&file); - - if (keepComments) - mGameSettings.writeFileWithComments(file); - else - { - stream.setCodec(QTextCodec::codecForName("UTF-8")); - mGameSettings.writeFile(stream); - } + mGameSettings.writeFileWithComments(file); file.close(); // Graphics settings @@ -540,6 +523,7 @@ bool Launcher::MainDialog::writeSettings() return false; } + QTextStream stream(&file); stream.setDevice(&file); stream.setCodec(QTextCodec::codecForName("UTF-8")); diff --git a/apps/launcher/settingspage.cpp b/apps/launcher/settingspage.cpp index bc8ffe618..843b51391 100644 --- a/apps/launcher/settingspage.cpp +++ b/apps/launcher/settingspage.cpp @@ -260,10 +260,6 @@ void Launcher::SettingsPage::saveSettings() } else { mGameSettings.setValue(QLatin1String("encoding"), QLatin1String("win1252")); } - - QString keepComments(saveCommentsCheckBox->isChecked() ? "true" : "false"); - - mLauncherSettings.setValue(QLatin1String("Settings/keep-comments"), keepComments); } bool Launcher::SettingsPage::loadSettings() @@ -275,9 +271,5 @@ bool Launcher::SettingsPage::loadSettings() if (index != -1) languageComboBox->setCurrentIndex(index); - QString keepComments(mLauncherSettings.value(QLatin1String("Settings/keep-comments"))); - - saveCommentsCheckBox->setChecked(keepComments == "true"); - return true; } diff --git a/files/ui/settingspage.ui b/files/ui/settingspage.ui index f38ba764c..7f5e4a7de 100644 --- a/files/ui/settingspage.ui +++ b/files/ui/settingspage.ui @@ -40,16 +40,6 @@ - - - - Keep comments in openmw.cfg - - - false - - - From b33fe8fb6242e6b0030340429ac122de883237b9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 7 Jun 2015 16:50:34 +0200 Subject: [PATCH 1446/3725] Fix the inventory listener bug --- apps/openmw/mwrender/npcanimation.cpp | 2 +- apps/openmw/mwworld/inventorystore.cpp | 5 +++++ apps/openmw/mwworld/inventorystore.hpp | 2 ++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 6831daa4b..7de3e1d5a 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -231,7 +231,7 @@ NpcAnimation::~NpcAnimation() // No need to getInventoryStore() to reset, if none exists // This is to avoid triggering the listener via ensureCustomData()->autoEquip()->fireEquipmentChanged() // all from within this destructor. ouch! - && mPtr.getRefData().getCustomData()) + && mPtr.getRefData().getCustomData() && mPtr.getClass().getInventoryStore(mPtr).getListener() == this) mPtr.getClass().getInventoryStore(mPtr).setListener(NULL, mPtr); } diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 62d58f729..3fe86a511 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -573,6 +573,11 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::unequipItem(const MWWor throw std::runtime_error ("attempt to unequip an item that is not currently equipped"); } +MWWorld::InventoryStoreListener* MWWorld::InventoryStore::getListener() +{ + return mListener; +} + void MWWorld::InventoryStore::setListener(InventoryStoreListener *listener, const Ptr& actor) { mListener = listener; diff --git a/apps/openmw/mwworld/inventorystore.hpp b/apps/openmw/mwworld/inventorystore.hpp index 6b906207e..a60d1f464 100644 --- a/apps/openmw/mwworld/inventorystore.hpp +++ b/apps/openmw/mwworld/inventorystore.hpp @@ -192,6 +192,8 @@ namespace MWWorld void setListener (InventoryStoreListener* listener, const Ptr& actor); ///< Set a listener for various events, see \a InventoryStoreListener + InventoryStoreListener* getListener(); + void visitEffectSources (MWMechanics::EffectSourceVisitor& visitor); void rechargeItems (float duration); From 16e080e2529453fa6a42a5460639ca4a190f8bfb Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 7 Jun 2015 17:00:00 +0200 Subject: [PATCH 1447/3725] Fix the physics debug drawer lagging a frame behind --- apps/openmw/mwphysics/physicssystem.cpp | 3 +++ apps/openmw/mwphysics/physicssystem.hpp | 1 + apps/openmw/mwworld/worldimp.cpp | 2 ++ 3 files changed, 6 insertions(+) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index c7df22aef..b7d02e159 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -1175,7 +1175,10 @@ namespace MWPhysics CProfileManager::Reset(); CProfileManager::Increment_Frame_Counter(); + } + void PhysicsSystem::debugDraw() + { if (mDebugDrawer.get()) mDebugDrawer->step(); } diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index 8cb31ed25..c3b22c385 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -78,6 +78,7 @@ namespace MWPhysics bool toggleCollisionMode(); void stepSimulation(float dt); + void debugDraw(); std::vector getCollisions(const MWWorld::Ptr &ptr, int collisionGroup, int collisionMask); ///< get handles this object collides with osg::Vec3f traceDown(const MWWorld::Ptr &ptr, float maxHeight); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index a2e66a96f..7b4c33fd8 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1392,6 +1392,8 @@ namespace MWWorld } if(player != results.end()) moveObjectImp(player->first, player->second.x(), player->second.y(), player->second.z()); + + mPhysics->debugDraw(); } bool World::castRay (float x1, float y1, float z1, float x2, float y2, float z2) From 508c57d6e21f6b538579c2efa1858c701c920217 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 7 Jun 2015 17:09:37 +0200 Subject: [PATCH 1448/3725] addEffect crash fix for objects with no model --- apps/openmw/mwrender/animation.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 6af8a49a4..d92e57f19 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1048,6 +1048,9 @@ namespace MWRender void Animation::addEffect (const std::string& model, int effectId, bool loop, const std::string& bonename, std::string texture) { + if (!mObjectRoot.get()) + return; + // Early out if we already have this effect for (std::vector::iterator it = mEffects.begin(); it != mEffects.end(); ++it) if (it->mLoop && loop && it->mEffectId == effectId && it->mBoneName == bonename) From ab626ca7b90fd8574fdff511e652825bfb21ca0c Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 7 Jun 2015 18:57:26 +0200 Subject: [PATCH 1449/3725] Improve MyGUI widget creation performance --- .../myguiplatform/myguirendermanager.cpp | 37 ++++++++++++++----- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/components/myguiplatform/myguirendermanager.cpp b/components/myguiplatform/myguirendermanager.cpp index e00b0221d..ece667eb2 100644 --- a/components/myguiplatform/myguirendermanager.cpp +++ b/components/myguiplatform/myguirendermanager.cpp @@ -209,10 +209,17 @@ class OSGVertexBuffer : public MyGUI::IVertexBuffer size_t mNeedVertexCount; + bool mQueuedForDrawing; + + void destroy(); + void create(); + public: OSGVertexBuffer(); virtual ~OSGVertexBuffer(); + void markAsQueuedForDrawing(); + virtual void setVertexCount(size_t count); virtual size_t getVertexCount(); @@ -220,8 +227,6 @@ public: virtual void unlock(); /*internal:*/ - void destroy(); - void create(); osg::VertexBufferObject *getBuffer() const { return mBuffer.get(); } osg::UByteArray *getArray() const { return mVertexArray.get(); } @@ -229,6 +234,7 @@ public: OSGVertexBuffer::OSGVertexBuffer() : mNeedVertexCount(0) + , mQueuedForDrawing(false) { } @@ -237,14 +243,17 @@ OSGVertexBuffer::~OSGVertexBuffer() destroy(); } +void OSGVertexBuffer::markAsQueuedForDrawing() +{ + mQueuedForDrawing = true; +} + void OSGVertexBuffer::setVertexCount(size_t count) { if(count == mNeedVertexCount) return; mNeedVertexCount = count; - destroy(); - create(); } size_t OSGVertexBuffer::getVertexCount() @@ -254,15 +263,22 @@ size_t OSGVertexBuffer::getVertexCount() MyGUI::Vertex *OSGVertexBuffer::lock() { - // Force recreating the buffer, to make sure we are not modifying a buffer currently - // queued for rendering in the last frame's draw thread. - // a more efficient solution might be double buffering - destroy(); - create(); + if (mQueuedForDrawing || !mVertexArray) + { + // Force recreating the buffer, to make sure we are not modifying a buffer currently + // queued for rendering in the last frame's draw thread. + // a more efficient solution might be double buffering + destroy(); + create(); + mQueuedForDrawing = false; + } + else + { + mVertexArray->resize(mNeedVertexCount * sizeof(MyGUI::Vertex)); + } MYGUI_PLATFORM_ASSERT(mBuffer.valid(), "Vertex buffer is not created"); - mVertexArray->resize(mNeedVertexCount * sizeof(MyGUI::Vertex)); return (MyGUI::Vertex*)&(*mVertexArray)[0]; } @@ -389,6 +405,7 @@ void RenderManager::doRender(MyGUI::IVertexBuffer *buffer, MyGUI::ITexture *text Drawable::Batch batch; batch.mVertexCount = count; batch.mVertexBuffer = static_cast(buffer)->getBuffer(); + static_cast(buffer)->markAsQueuedForDrawing(); batch.mArray = static_cast(buffer)->getArray(); if (texture) { From bf02c7f6e4949e09adc19a7a8e043d4fa9f6e568 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 7 Jun 2015 19:28:12 +0200 Subject: [PATCH 1450/3725] Sun visibility fix --- apps/openmw/mwrender/sky.cpp | 7 ------- apps/openmw/mwrender/sky.hpp | 2 -- 2 files changed, 9 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index c742d1c90..0cd1f64d2 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -506,8 +506,6 @@ SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneMana , mRainFrequency(1) , mEnabled(true) , mSunEnabled(true) - , mMasserEnabled(true) - , mSecundaEnabled(true) { osg::ref_ptr skyroot (new CameraRelativeTransform); skyroot->setNodeMask(Mask_Sky); @@ -642,11 +640,6 @@ void SkyManager::update(float duration) */ } - //mSunGlare->setVisible(mSunEnabled); - mSun->setVisible(mSunEnabled); - mMasser->setVisible(mMasserEnabled); - mSecunda->setVisible(mSecundaEnabled); - // rotate the stars by 360 degrees every 4 days //mAtmosphereNight->roll(Degree(MWBase::Environment::get().getWorld()->getTimeScaleFactor()*duration*360 / (3600*96.f))); } diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index 652de28b4..d7cd88de5 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -150,8 +150,6 @@ namespace MWRender bool mEnabled; bool mSunEnabled; - bool mMasserEnabled; - bool mSecundaEnabled; }; } From f3cbe7b9dac6cae14bf2f8593006e1fb8f838bf0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 7 Jun 2015 19:33:48 +0200 Subject: [PATCH 1451/3725] Hide FPS widget since it currently doesn't work, use F3 instead --- apps/openmw/mwgui/hud.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 56a4b0807..76a7248ee 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -192,7 +192,7 @@ namespace MWGui if (visible) { getWidget(mFpsBox, "FPSBox"); - mFpsBox->setVisible(true); + //mFpsBox->setVisible(true); getWidget(mFpsCounter, "FPSCounter"); } } From 0330d3d61e911ea1b27ba72b14d4aaf41717dc02 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 7 Jun 2015 21:21:57 +0200 Subject: [PATCH 1452/3725] Restore the "transparent" loading screen --- apps/openmw/mwgui/loadingscreen.cpp | 69 ++++++++++++++++++++--------- apps/openmw/mwgui/loadingscreen.hpp | 11 +++++ 2 files changed, 59 insertions(+), 21 deletions(-) diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index f6a9f5ccd..774faa003 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -2,6 +2,8 @@ #include +#include + #include #include #include @@ -9,6 +11,8 @@ #include +#include + #include #include @@ -96,6 +100,28 @@ namespace MWGui mBackgroundImage->setVisible(visible); } + class CopyFramebufferToTextureCallback : public osg::Camera::DrawCallback + { + public: + CopyFramebufferToTextureCallback(osg::Texture2D* texture, int w, int h) + : mTexture(texture), mWidth(w), mHeight(h) + { + } + + virtual void operator () (osg::RenderInfo& renderInfo) const + { + mTexture->copyTexImage2D(*renderInfo.getState(), 0, 0, mWidth, mHeight); + + // Callback removes itself when done + if (renderInfo.getCurrentCamera()) + renderInfo.getCurrentCamera()->setInitialDrawCallback(NULL); + } + + private: + osg::ref_ptr mTexture; + int mWidth, mHeight; + }; + void LoadingScreen::loadingOn() { mLoadingOnTime = mTimer.time_m(); @@ -114,29 +140,30 @@ namespace MWGui if (!showWallpaper) { - // TODO - /* - mBackgroundImage->setImageTexture(""); - int width = mWindow->getWidth(); - int height = mWindow->getHeight(); - const std::string textureName = "@loading_background"; - Ogre::TexturePtr texture; - texture = Ogre::TextureManager::getSingleton().getByName(textureName); - if (texture.isNull()) + // Copy the current framebuffer onto a texture and display that texture as the background image + // Note, we could also set the camera to disable clearing and have the background image transparent, + // but then we get shaking effects on buffer swaps. + + if (!mTexture) { - texture = Ogre::TextureManager::getSingleton().createManual(textureName, - Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - Ogre::TEX_TYPE_2D, - width, height, 0, mWindow->suggestPixelFormat(), Ogre::TU_DYNAMIC_WRITE_ONLY); + mTexture = new osg::Texture2D; + mTexture->setInternalFormat(GL_RGB); + mTexture->setResizeNonPowerOfTwoHint(false); } - texture->unload(); - texture->setWidth(width); - texture->setHeight(height); - texture->createInternalResources(); - mWindow->copyContentsToMemory(texture->getBuffer()->lock(Ogre::Image::Box(0,0,width,height), Ogre::HardwareBuffer::HBL_DISCARD)); - texture->getBuffer()->unlock(); - mBackgroundImage->setBackgroundImage(texture->getName(), false, false); - */ + + int width = mViewer->getCamera()->getViewport()->width(); + int height = mViewer->getCamera()->getViewport()->height(); + mViewer->getCamera()->setInitialDrawCallback(new CopyFramebufferToTextureCallback(mTexture, width, height)); + + if (!mGuiTexture.get()) + { + mGuiTexture.reset(new osgMyGUI::OSGTexture(mTexture)); + } + + mBackgroundImage->setBackgroundImage(""); + + mBackgroundImage->setRenderItemTexture(mGuiTexture.get()); + mBackgroundImage->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 1.f, 1.f, 0.f)); } setVisible(true); diff --git a/apps/openmw/mwgui/loadingscreen.hpp b/apps/openmw/mwgui/loadingscreen.hpp index baacc7133..194535eee 100644 --- a/apps/openmw/mwgui/loadingscreen.hpp +++ b/apps/openmw/mwgui/loadingscreen.hpp @@ -12,6 +12,12 @@ namespace osgViewer { class Viewer; } + +namespace osg +{ + class Texture2D; +} + namespace VFS { class Manager; @@ -67,6 +73,11 @@ namespace MWGui std::vector mSplashScreens; + // TODO: add releaseGLObjects() for mTexture + + osg::ref_ptr mTexture; + std::auto_ptr mGuiTexture; + void changeWallpaper(); void draw(); From 9c9b83f8e20d8b2bbdaa2ed004d21ad4b6438501 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 7 Jun 2015 23:51:54 +0200 Subject: [PATCH 1453/3725] Changes to compile with osg-svn 3.3.8 --- components/sceneutil/controller.cpp | 12 ++++++++++++ components/sceneutil/statesetupdater.cpp | 1 + components/sdlutil/sdlgraphicswindow.cpp | 9 +++++++++ 3 files changed, 22 insertions(+) diff --git a/components/sceneutil/controller.cpp b/components/sceneutil/controller.cpp index b8b452dc3..a2c1cdcd3 100644 --- a/components/sceneutil/controller.cpp +++ b/components/sceneutil/controller.cpp @@ -4,6 +4,8 @@ #include #include +#include +#include namespace SceneUtil { @@ -63,7 +65,11 @@ namespace SceneUtil void ControllerVisitor::apply(osg::Node &node) { +#if OSG_MIN_VERSION_REQUIRED(3,3,3) + osg::Callback* callback = node.getUpdateCallback(); +#else osg::NodeCallback* callback = node.getUpdateCallback(); +#endif while (callback) { if (Controller* ctrl = dynamic_cast(callback)) @@ -89,7 +95,13 @@ namespace SceneUtil for (unsigned int i=0; igetUpdateCallback(); +#else osg::Drawable::UpdateCallback* callback = drw->getUpdateCallback(); +#endif + if (Controller* ctrl = dynamic_cast(callback)) visit(geode, *ctrl); } diff --git a/components/sceneutil/statesetupdater.cpp b/components/sceneutil/statesetupdater.cpp index 66e40f3e1..36aa683db 100644 --- a/components/sceneutil/statesetupdater.cpp +++ b/components/sceneutil/statesetupdater.cpp @@ -1,6 +1,7 @@ #include "statesetupdater.hpp" #include +#include namespace SceneUtil { diff --git a/components/sdlutil/sdlgraphicswindow.cpp b/components/sdlutil/sdlgraphicswindow.cpp index f16c0bca4..84aafa100 100644 --- a/components/sdlutil/sdlgraphicswindow.cpp +++ b/components/sdlutil/sdlgraphicswindow.cpp @@ -3,6 +3,7 @@ #include #include +#include namespace SDLUtil { @@ -108,7 +109,11 @@ void GraphicsWindowSDL2::init() mValid = true; +#if OSG_MIN_VERSION_REQUIRED(3,3,4) + getEventQueue()->syncWindowRectangleWithGraphicsContext(); +#else getEventQueue()->syncWindowRectangleWithGraphcisContext(); +#endif } @@ -125,7 +130,11 @@ bool GraphicsWindowSDL2::realizeImplementation() SDL_ShowWindow(mWindow); +#if OSG_MIN_VERSION_REQUIRED(3,3,4) + getEventQueue()->syncWindowRectangleWithGraphicsContext(); +#else getEventQueue()->syncWindowRectangleWithGraphcisContext(); +#endif mRealized = true; From 893ad11be109ab1a4e249c1d091092ff5cdfb9fe Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 8 Jun 2015 08:04:18 +1000 Subject: [PATCH 1454/3725] Fix missing columns in tables. Should resolve Bug #2624. - Using Flag_Table in filterAcceptsColumn() does not work. - Workaround by not allowing nested columns in sorting and filtering. --- apps/opencs/model/world/idtableproxymodel.cpp | 18 +++++++----------- apps/opencs/model/world/idtableproxymodel.hpp | 2 -- 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/apps/opencs/model/world/idtableproxymodel.cpp b/apps/opencs/model/world/idtableproxymodel.cpp index 3697b055f..d8932d205 100644 --- a/apps/opencs/model/world/idtableproxymodel.cpp +++ b/apps/opencs/model/world/idtableproxymodel.cpp @@ -21,21 +21,17 @@ void CSMWorld::IdTableProxyModel::updateColumnMap() } } -bool CSMWorld::IdTableProxyModel::filterAcceptsColumn (int sourceColumn, const QModelIndex& sourceParent) +bool CSMWorld::IdTableProxyModel::filterAcceptsRow (int sourceRow, const QModelIndex& sourceParent) const { - int flags = - sourceModel()->headerData (sourceColumn, Qt::Horizontal, CSMWorld::ColumnBase::Role_Flags).toInt(); - - if (flags & CSMWorld::ColumnBase::Flag_Table) - return true; - else + // It is not possible to use filterAcceptsColumn() and check for + // sourceModel()->headerData (sourceColumn, Qt::Horizontal, CSMWorld::ColumnBase::Role_Flags) + // because the sourceColumn parameter excludes the hidden columns, i.e. wrong columns can + // be rejected. Workaround by disallowing tree branches (nested columns), which are not meant + // to be visible, from the filter. + if (sourceParent.isValid()) return false; -} -bool CSMWorld::IdTableProxyModel::filterAcceptsRow (int sourceRow, const QModelIndex& sourceParent) - const -{ if (!mFilter) return true; diff --git a/apps/opencs/model/world/idtableproxymodel.hpp b/apps/opencs/model/world/idtableproxymodel.hpp index 89480f288..d2a240529 100644 --- a/apps/opencs/model/world/idtableproxymodel.hpp +++ b/apps/opencs/model/world/idtableproxymodel.hpp @@ -39,8 +39,6 @@ namespace CSMWorld bool lessThan(const QModelIndex &left, const QModelIndex &right) const; virtual bool filterAcceptsRow (int sourceRow, const QModelIndex& sourceParent) const; - - virtual bool filterAcceptsColumn (int sourceColumn, const QModelIndex& sourceParent) const; }; } From 5edf457ab7534567b8ef37ac87f044cbb9eb03ef Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 8 Jun 2015 01:13:23 +0200 Subject: [PATCH 1455/3725] Build fix --- components/nifosg/nifloader.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 530aa3dec..44784fd7e 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -1237,12 +1237,12 @@ namespace NifOsg texEnv->setCombine_Alpha(GL_MODULATE); texEnv->setOperand0_Alpha(GL_SRC_ALPHA); texEnv->setOperand1_Alpha(GL_SRC_ALPHA); - texEnv->setSource0_Alpha(GL_PREVIOUS); + texEnv->setSource0_Alpha(GL_PREVIOUS_ARB); texEnv->setSource1_Alpha(GL_TEXTURE); texEnv->setCombine_RGB(GL_MODULATE); texEnv->setOperand0_RGB(GL_SRC_COLOR); texEnv->setOperand1_RGB(GL_SRC_COLOR); - texEnv->setSource0_RGB(GL_PREVIOUS); + texEnv->setSource0_RGB(GL_PREVIOUS_ARB); texEnv->setSource1_RGB(GL_TEXTURE); stateset->setTextureAttributeAndModes(i, texEnv, osg::StateAttribute::ON); } From 10457c1b28190cb55d7af29c51ee0943f8bebf4e Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 8 Jun 2015 01:14:26 +0200 Subject: [PATCH 1456/3725] Include fix --- components/vfs/manager.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/components/vfs/manager.cpp b/components/vfs/manager.cpp index 829e08978..6be6dca9e 100644 --- a/components/vfs/manager.cpp +++ b/components/vfs/manager.cpp @@ -1,6 +1,7 @@ #include "manager.hpp" #include +#include #include "archive.hpp" From d9a00288f850dc2ba585d9db12ba45e9bad1ca34 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 8 Jun 2015 01:58:12 +0200 Subject: [PATCH 1457/3725] Make install fix --- CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9f47b5fae..77b054ff5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -316,9 +316,9 @@ IF(NOT WIN32 AND NOT APPLE) IF(BUILD_WIZARD) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/openmw-wizard" DESTINATION "${BINDIR}" ) ENDIF(BUILD_WIZARD) - if(BUILD_MYGUI_PLUGIN) - INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Plugin_MyGUI_OpenMW_Resources.so" DESTINATION "${LIBDIR}" ) - ENDIF(BUILD_MYGUI_PLUGIN) + #if(BUILD_MYGUI_PLUGIN) + # INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Plugin_MyGUI_OpenMW_Resources.so" DESTINATION "${LIBDIR}" ) + #ENDIF(BUILD_MYGUI_PLUGIN) # Install licenses INSTALL(FILES "docs/license/DejaVu Font License.txt" DESTINATION "${LICDIR}" ) From 347c9b57b8af392aa906f7840298a2b86f676bd8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 8 Jun 2015 01:59:42 +0200 Subject: [PATCH 1458/3725] Copy constructor signature fix --- components/nifosg/particle.cpp | 2 +- components/nifosg/particle.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/components/nifosg/particle.cpp b/components/nifosg/particle.cpp index ac304bdf3..92a849a0d 100644 --- a/components/nifosg/particle.cpp +++ b/components/nifosg/particle.cpp @@ -69,7 +69,7 @@ ParticleShooter::ParticleShooter() { } -ParticleShooter::ParticleShooter(const osgParticle::Shooter ©, const osg::CopyOp ©op) +ParticleShooter::ParticleShooter(const ParticleShooter ©, const osg::CopyOp ©op) : osgParticle::Shooter(copy, copyop) { *this = copy; diff --git a/components/nifosg/particle.hpp b/components/nifosg/particle.hpp index 5e463aae3..c7d5d585d 100644 --- a/components/nifosg/particle.hpp +++ b/components/nifosg/particle.hpp @@ -76,7 +76,7 @@ namespace NifOsg ParticleShooter(float minSpeed, float maxSpeed, float horizontalDir, float horizontalAngle, float verticalDir, float verticalAngle, float lifetime, float lifetimeRandom); ParticleShooter(); - ParticleShooter(const Shooter& copy, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY); + ParticleShooter(const ParticleShooter& copy, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY); META_Object(NifOsg, ParticleShooter) From 4f2cd1711944b12d6a90d9a54332d91d0ec96c40 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Mon, 8 Jun 2015 02:14:20 +0200 Subject: [PATCH 1459/3725] Let's get some OSG builds going --- CI/before_script.msvc.sh | 250 +++++++++++++++++++++++---------------- CMakeLists.txt | 3 + 2 files changed, 153 insertions(+), 100 deletions(-) diff --git a/CI/before_script.msvc.sh b/CI/before_script.msvc.sh index 36f8213d4..a12c17038 100644 --- a/CI/before_script.msvc.sh +++ b/CI/before_script.msvc.sh @@ -8,6 +8,15 @@ while [ $# -gt 0 ]; do -v ) VERBOSE=true ;; + -d ) + SKIP_DOWNLOAD=true ;; + + -e ) + SKIP_EXTRACT=true ;; + + -k ) + KEEP=true ;; + * ) echo "Unknown arg $ARG." exit 1 ;; @@ -61,29 +70,46 @@ run_cmd() { } download() { - if ! [ -f $2 ]; then - printf " Downloading $2... " + if [ $# -lt 3 ]; then + echo "Invalid parameters to download." + return 1 + fi - if [ -z $VERBOSE ]; then - curl --silent --retry 10 -kLy 5 -o $2 $1 - RET=$? - else - curl --retry 10 -kLy 5 -o $2 $1 - RET=$? - fi + NAME=$1 + shift - if [ $RET -ne 0 ]; then - echo "Failed!" + echo "$NAME..." + + while [ $# -gt 1 ]; do + URL=$1 + FILE=$2 + shift + shift + + if ! [ -f $FILE ]; then + printf " Downloading $FILE... " + + if [ -z $VERBOSE ]; then + curl --silent --retry 10 -kLy 5 -o $FILE $URL + RET=$? + else + curl --retry 10 -kLy 5 -o $FILE $URL + RET=$? + fi + + if [ $RET -ne 0 ]; then + echo "Failed!" + else + echo "Done." + fi else - echo "Done" + echo " $FILE exists, skipping." fi + done - return $RET - else - echo " $2 exists, skipping." + if [ $# -ne 0 ]; then + echo "Missing parameter." fi - - return 0 } real_pwd() { @@ -134,63 +160,71 @@ echo "Starting prebuild on win$BITS" echo "==========================" echo +# cd OpenMW/AppVeyor-test mkdir -p deps cd deps DEPS="`pwd`" -echo "Downloading dependency packages." -echo - -# Boost -if [ -z $APPVEYOR ]; then - echo "Boost 1.58.0..." - download http://sourceforge.net/projects/boost/files/boost-binaries/1.58.0/boost_1_58_0-msvc-12.0-$BITS.exe boost-1.58.0-win$BITS.exe +if [ -z $SKIP_DOWNLOAD ]; then + echo "Downloading dependency packages." echo -fi - -# Bullet -echo "Bullet 2.83.4..." -download http://www.lysator.liu.se/~ace/OpenMW/deps/Bullet-2.83.4-win$BITS.7z Bullet-2.83.4-win$BITS.7z -echo - -# FFmpeg -echo "FFmpeg 2.5.2..." -download http://ffmpeg.zeranoe.com/builds/win$BITS/shared/ffmpeg-2.5.2-win$BITS-shared.7z ffmpeg$BITS-2.5.2.7z -download http://ffmpeg.zeranoe.com/builds/win$BITS/dev/ffmpeg-2.5.2-win$BITS-dev.7z ffmpeg$BITS-2.5.2-dev.7z -echo - -# MyGUI -echo "MyGUI 3.2.2..." -download http://www.lysator.liu.se/~ace/OpenMW/deps/MyGUI-3.2.2-win$BITS.7z MyGUI-3.2.2-win$BITS.7z -echo - -# Ogre -echo "Ogre 1.9..." -download http://www.lysator.liu.se/~ace/OpenMW/deps/Ogre-1.9-win$BITS.7z Ogre-1.9-win$BITS.7z -echo - -# OpenAL -echo "OpenAL-Soft 1.16.0..." -download http://kcat.strangesoft.net/openal-soft-1.16.0-bin.zip OpenAL-Soft-1.16.0.zip -echo -# Qt -echo "Qt 4.8.6..." -download http://sourceforge.net/projects/qt64ng/files/qt/$ARCHNAME/4.8.6/msvc2013/qt-4.8.6-x$ARCHSUFFIX-msvc2013.7z qt$BITS-4.8.6.7z -echo + # Boost + if [ -z $APPVEYOR ]; then + download "Boost 1.58.0" \ + http://sourceforge.net/projects/boost/files/boost-binaries/1.58.0/boost_1_58_0-msvc-12.0-$BITS.exe \ + boost-1.58.0-win$BITS.exe + fi -# SDL2 -echo "SDL 2.0.3 binaries..." -download https://www.libsdl.org/release/SDL2-devel-2.0.3-VC.zip SDL2-2.0.3.zip -echo + # Bullet + download "Bullet 2.83.4" \ + http://www.lysator.liu.se/~ace/OpenMW/deps/Bullet-2.83.4-win$BITS.7z \ + Bullet-2.83.4-win$BITS.7z + + # FFmpeg + download "FFmpeg 2.5.2" \ + http://ffmpeg.zeranoe.com/builds/win$BITS/shared/ffmpeg-2.5.2-win$BITS-shared.7z \ + ffmpeg$BITS-2.5.2.7z \ + http://ffmpeg.zeranoe.com/builds/win$BITS/dev/ffmpeg-2.5.2-win$BITS-dev.7z \ + ffmpeg$BITS-2.5.2-dev.7z + + # MyGUI + download "MyGUI 3.2.2" \ + http://www.lysator.liu.se/~ace/OpenMW/deps/MyGUI-3.2.2-win$BITS.7z \ + MyGUI-3.2.2-win$BITS.7z + + # OpenAL + download "OpenAL-Soft 1.16.0" \ + http://kcat.strangesoft.net/openal-soft-1.16.0-bin.zip \ + OpenAL-Soft-1.16.0.zip + + # OSG + download "OpenSceneGraph 3.3.8" \ + http://www.lysator.liu.se/~ace/OpenMW/deps/OSG-3.3.8-win$BITS.7z \ + OSG-3.3.8-win$BITS.7z + + # Qt + download "Qt 4.8.6" \ + http://sourceforge.net/projects/qt64ng/files/qt/$ARCHNAME/4.8.6/msvc2013/qt-4.8.6-x$ARCHSUFFIX-msvc2013.7z \ + qt$BITS-4.8.6.7z + + # SDL2 + download "SDL 2.0.3" \ + https://www.libsdl.org/release/SDL2-devel-2.0.3-VC.zip \ + SDL2-2.0.3.zip +fi -cd .. +cd .. #/.. # Set up dependencies -rm -rf build_$BITS -mkdir -p build_$BITS/deps -cd deps +if [ -z $KEEP ]; then + rm -rf OSG_$BITS + mkdir -p OSG_$BITS/deps +fi +cd OSG_$BITS/deps + +DEPS_INSTALL=`pwd` echo echo "Extracting dependencies..." @@ -198,11 +232,13 @@ echo "Extracting dependencies..." # Boost if [ -z $APPVEYOR ]; then printf "Boost 1.58.0... " - cd ../build_$BITS/deps + cd $DEPS_INSTALL BOOST_SDK="`real_pwd`/Boost" - $DEPS/boost-1.58.0-win$BITS.exe //dir="$(echo $BOOST_SDK | sed s,/,\\\\,g)" //verysilent + if [ -z $SKIP_EXTRACT ]; then + $DEPS/boost-1.58.0-win$BITS.exe //dir="$(echo $BOOST_SDK | sed s,/,\\\\,g)" //verysilent + fi add_cmake_opts -DBOOST_ROOT="$BOOST_SDK" \ -DBOOST_LIBRARYDIR="$BOOST_SDK/lib$BITS-msvc-12.0" @@ -219,10 +255,12 @@ fi # Bullet printf "Bullet 2.83.4... " -cd ../build_$BITS/deps +cd $DEPS_INSTALL -eval 7z x -y $DEPS/Bullet-2.83.4-win$BITS.7z $STRIP -mv Bullet-2.83.4-win$BITS Bullet +if [ -z $SKIP_EXTRACT ]; then + eval 7z x -y $DEPS/Bullet-2.83.4-win$BITS.7z $STRIP + mv Bullet-2.83.4-win$BITS Bullet +fi BULLET_SDK="`real_pwd`/Bullet" add_cmake_opts -DBULLET_INCLUDE_DIR="$BULLET_SDK/include/bullet" \ @@ -239,14 +277,16 @@ echo Done. # FFmpeg printf "FFmpeg 2.5.2... " -cd ../build_$BITS/deps +cd $DEPS_INSTALL -eval 7z x -y $DEPS/ffmpeg$BITS-2.5.2.7z $STRIP -eval 7z x -y $DEPS/ffmpeg$BITS-2.5.2-dev.7z $STRIP +if [ -z $SKIP_EXTRACT ]; then + eval 7z x -y $DEPS/ffmpeg$BITS-2.5.2.7z $STRIP + eval 7z x -y $DEPS/ffmpeg$BITS-2.5.2-dev.7z $STRIP -mv ffmpeg-2.5.2-win$BITS-shared FFmpeg -cp -r ffmpeg-2.5.2-win$BITS-dev/* FFmpeg/ -rm -rf ffmpeg-2.5.2-win$BITS-dev + mv ffmpeg-2.5.2-win$BITS-shared FFmpeg + cp -r ffmpeg-2.5.2-win$BITS-dev/* FFmpeg/ + rm -rf ffmpeg-2.5.2-win$BITS-dev +fi FFMPEG_SDK="`real_pwd`/FFmpeg" add_cmake_opts -DAVCODEC_INCLUDE_DIRS="$FFMPEG_SDK/include" \ @@ -272,33 +312,19 @@ cd $DEPS echo Done. -# Ogre -printf "Ogre 1.9... " -cd ../build_$BITS/deps - -eval 7z x -y $DEPS/Ogre-1.9-win$BITS.7z $STRIP -mv Ogre-1.9-win$BITS Ogre - -OGRE_SDK="`real_pwd`/Ogre" - -add_cmake_opts -DOGRE_SDK="$OGRE_SDK" - -cd $DEPS - -echo Done. - # MyGUI printf "MyGUI 3.2.2... " -cd ../build_$BITS/deps +cd $DEPS_INSTALL -eval 7z x -y $DEPS/MyGUI-3.2.2-win$BITS.7z $STRIP -mv MyGUI-3.2.2-win$BITS MyGUI +if [ -z $SKIP_EXTRACT ]; then + eval 7z x -y $DEPS/MyGUI-3.2.2-win$BITS.7z $STRIP + mv MyGUI-3.2.2-win$BITS MyGUI +fi MYGUI_SDK="`real_pwd`/MyGUI" add_cmake_opts -DMYGUISDK="$MYGUI_SDK" \ - -DMYGUI_PLATFORM_INCLUDE_DIRS="$MYGUI_SDK/include/MYGUI" \ - -DMYGUI_INCLUDE_DIRS="$MYGUI_SDK/include" \ + -DMYGUI_INCLUDE_DIRS="$MYGUI_SDK/include/MYGUI" \ -DMYGUI_PREQUEST_FILE="$MYGUI_SDK/include/MYGUI/MyGUI_Prerequest.h" cd $DEPS @@ -307,7 +333,9 @@ echo Done. # OpenAL printf "OpenAL-Soft 1.16.0... " -eval 7z x -y OpenAL-Soft-1.16.0.zip $STRIP +if [ -z $SKIP_EXTRACT ]; then + eval 7z x -y OpenAL-Soft-1.16.0.zip $STRIP +fi OPENAL_SDK="`real_pwd`/openal-soft-1.16.0-bin" @@ -316,12 +344,31 @@ add_cmake_opts -DOPENAL_INCLUDE_DIR="$OPENAL_SDK/include" \ echo Done. +# OSG +printf "OSG 3.3.8... " +cd $DEPS_INSTALL + +if [ -z $SKIP_EXTRACT ]; then + eval 7z x -y $DEPS/OSG-3.3.8-win$BITS.7z $STRIP + mv OSG-3.3.8-win$BITS OSG +fi + +OSG_SDK="`real_pwd`/OSG" + +add_cmake_opts -DOSG_DIR="$OSG_SDK" + +cd $DEPS + +echo Done. + # Qt printf "Qt 4.8.6... " -cd ../build_$BITS/deps +cd $DEPS_INSTALL -eval 7z x -y $DEPS/qt$BITS-4.8.6.7z $STRIP -mv qt-4.8.6-* Qt +if [ -z $SKIP_EXTRACT ]; then + eval 7z x -y $DEPS/qt$BITS-4.8.6.7z $STRIP + mv qt-4.8.6-* Qt +fi QT_SDK="`real_pwd`/Qt" @@ -336,7 +383,10 @@ echo Done. # SDL2 printf "SDL 2.0.3... " -eval 7z x -y SDL2-2.0.3.zip $STRIP + +if [ -z $SKIP_EXTRACT ]; then + eval 7z x -y SDL2-2.0.3.zip $STRIP +fi SDL_SDK="`real_pwd`/SDL2-2.0.3" add_cmake_opts -DSDL2_INCLUDE_DIR="$SDL_SDK/include" \ @@ -349,7 +399,7 @@ cd $DEPS echo Done. echo -cd ../build_$BITS +cd $DEPS_INSTALL/.. echo "Building OpenMW..." diff --git a/CMakeLists.txt b/CMakeLists.txt index 77b054ff5..f98838452 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -138,6 +138,9 @@ if (WIN32) # Suppress WinMain(), provided by SDL add_definitions(-DSDL_MAIN_HANDLED) + + # Get rid of useless crud from windows.h + add_definitions(-DNOMINMAX -DWIN32_LEAN_AND_MEAN) endif() # Dependencies From fc8e5dde3befb5ff4e73548ff686be5e6963a634 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 8 Jun 2015 03:26:36 +0200 Subject: [PATCH 1460/3725] Fix crash when OSG_STEREO is enabled --- components/myguiplatform/myguirendermanager.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/components/myguiplatform/myguirendermanager.cpp b/components/myguiplatform/myguirendermanager.cpp index ece667eb2..773c58a59 100644 --- a/components/myguiplatform/myguirendermanager.cpp +++ b/components/myguiplatform/myguirendermanager.cpp @@ -107,7 +107,7 @@ class Drawable : public osg::Drawable { glEnableClientState(GL_TEXTURE_COORD_ARRAY); glEnableClientState(GL_COLOR_ARRAY); - mReadFrom = (mReadFrom+1)%2; + mReadFrom = (mReadFrom+1)%sNumBuffers; const std::vector& vec = mBatchVector[mReadFrom]; for (std::vector::const_iterator it = vec.begin(); it != vec.end(); ++it) { @@ -188,15 +188,18 @@ public: void clear() { - mWriteTo = (mWriteTo+1)%2; + mWriteTo = (mWriteTo+1)%sNumBuffers; mBatchVector[mWriteTo].clear(); } META_Object(osgMyGUI, Drawable) private: + // 2 would be enough in most cases, use 4 to get stereo working + static const int sNumBuffers = 4; + // double buffering approach, to avoid the need for synchronization with the draw thread - std::vector mBatchVector[2]; + std::vector mBatchVector[sNumBuffers]; int mWriteTo; mutable int mReadFrom; From cd42448cd6bb50d030070c976bc57b3b4e4548c4 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Mon, 8 Jun 2015 15:41:39 +0200 Subject: [PATCH 1461/3725] Windows build fixes and CMakeLists cleanup Adds some flags necessary to build and link with OSG. This also moves LTO and MP switches to user-accessible options, and actually applies the generated CXXFLAGS to the project. Since the generation happens after the subdirectories are added. --- CMakeLists.txt | 86 +++++++++++++++++++++++++++++++----------- apps/opencs/editor.cpp | 3 ++ 2 files changed, 67 insertions(+), 22 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 77b054ff5..523145c71 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -75,6 +75,11 @@ option(BUILD_MYGUI_PLUGIN "build MyGUI plugin for OpenMW resources, to use with # OS X deployment option(OPENMW_OSX_DEPLOYMENT OFF) +if (MSVC) + option(OPENMW_MP_BUILD "Build OpenMW with /MP flag" OFF) + option(OPENMW_LTO_BUILD "Build OpenMW with Link-Time Optimization (Needs ~2GB of RAM)" OFF) +endif() + # Location of morrowind data files if (APPLE) set(MORROWIND_DATA_FILES "./data" CACHE PATH "location of Morrowind data files") @@ -138,6 +143,9 @@ if (WIN32) # Suppress WinMain(), provided by SDL add_definitions(-DSDL_MAIN_HANDLED) + + # Get rid of useless crud from windows.h + add_definitions(-DNOMINMAX -DWIN32_LEAN_AND_MEAN) endif() # Dependencies @@ -268,10 +276,14 @@ if (CMAKE_CXX_COMPILER_ID STREQUAL GNU OR CMAKE_CXX_COMPILER_ID STREQUAL Clang) endif(CMAKE_CXX_COMPILER_ID STREQUAL GNU AND "${GCC_VERSION}" VERSION_GREATER 4.6 OR "${GCC_VERSION}" VERSION_EQUAL 4.6) elseif (MSVC) # Enable link-time code generation globally for all linking - set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /GL") - set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /LTCG") - set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /LTCG") - set(CMAKE_STATIC_LINKER_FLAGS_RELEASE "${CMAKE_STATIC_LINKER_FLAGS_RELEASE} /LTCG") + if (OPENMW_LTO_BUILD) + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /GL") + set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /LTCG") + set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /LTCG") + set(CMAKE_STATIC_LINKER_FLAGS_RELEASE "${CMAKE_STATIC_LINKER_FLAGS_RELEASE} /LTCG") + endif() + + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /FORCE:MULTIPLE") endif (CMAKE_CXX_COMPILER_ID STREQUAL GNU OR CMAKE_CXX_COMPILER_ID STREQUAL Clang) IF(NOT WIN32 AND NOT APPLE) @@ -380,6 +392,8 @@ if(WIN32) ENDIF(BUILD_MYGUI_PLUGIN) INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION ".") + FILE(GLOB plugin_dir "${OpenMW_BINARY_DIR}/Release/osgPlugins-*") + INSTALL(DIRECTORY ${plugin_dir} DESTINATION ".") SET(CPACK_GENERATOR "NSIS") SET(CPACK_PACKAGE_NAME "OpenMW") @@ -492,9 +506,9 @@ endif() if (WIN32) if (MSVC) - if (MULTITHREADED_BUILD) + if (OPENMW_MP_BUILD) set( MT_BUILD "/MP") - endif (MULTITHREADED_BUILD) + endif() foreach( OUTPUTCONFIG ${CMAKE_CONFIGURATION_TYPES} ) string( TOUPPER ${OUTPUTCONFIG} OUTPUTCONFIG ) @@ -502,20 +516,22 @@ if (WIN32) set( CMAKE_LIBRARY_OUTPUT_DIRECTORY_${OUTPUTCONFIG} "$(ProjectDir)$(Configuration)" ) endforeach( OUTPUTCONFIG ) - if (USE_DEBUG_CONSOLE) + if (USE_DEBUG_CONSOLE AND BUILD_OPENMW) set_target_properties(openmw PROPERTIES LINK_FLAGS_DEBUG "/SUBSYSTEM:CONSOLE") set_target_properties(openmw PROPERTIES LINK_FLAGS_RELWITHDEBINFO "/SUBSYSTEM:CONSOLE") set_target_properties(openmw PROPERTIES COMPILE_DEFINITIONS_DEBUG "_CONSOLE") - else() + elseif (BUILD_OPENMW) # Turn off debug console, debug output will be written to visual studio output instead set_target_properties(openmw PROPERTIES LINK_FLAGS_DEBUG "/SUBSYSTEM:WINDOWS") set_target_properties(openmw PROPERTIES LINK_FLAGS_RELWITHDEBINFO "/SUBSYSTEM:WINDOWS") endif() - # Release builds use the debug console - set_target_properties(openmw PROPERTIES LINK_FLAGS_RELEASE "/SUBSYSTEM:CONSOLE") - set_target_properties(openmw PROPERTIES COMPILE_DEFINITIONS_RELEASE "_CONSOLE") - set_target_properties(openmw PROPERTIES LINK_FLAGS_MINSIZEREL "/SUBSYSTEM:CONSOLE") + if (BUILD_OPENMW) + # Release builds use the debug console + set_target_properties(openmw PROPERTIES LINK_FLAGS_RELEASE "/SUBSYSTEM:CONSOLE") + set_target_properties(openmw PROPERTIES COMPILE_DEFINITIONS_RELEASE "_CONSOLE") + set_target_properties(openmw PROPERTIES LINK_FLAGS_MINSIZEREL "/SUBSYSTEM:CONSOLE") + endif() # Play a bit with the warning levels @@ -524,8 +540,8 @@ if (WIN32) set(WARNINGS_DISABLE # Warnings that aren't enabled normally and don't need to be enabled # They're unneeded and sometimes completely retarded warnings that /Wall enables - # Not going to bother commenting them as they tend to warn on every standard library files - 4061 4263 4264 4266 4350 4371 4514 4548 4571 4610 4619 4623 4625 4626 4628 4640 4668 4710 4711 4820 4826 4917 4946 + # Not going to bother commenting them as they tend to warn on every standard library file + 4061 4263 4264 4266 4350 4371 4435 4514 4548 4571 4610 4619 4623 4625 4626 4628 4640 4668 4710 4711 4820 4826 4917 4946 # Warnings that are thrown on standard libraries and not OpenMW 4347 # Non-template function with same name and parameter count as template function @@ -547,6 +563,7 @@ if (WIN32) 4127 # Conditional expression is constant 4242 # Storing value in a variable of a smaller type, possible loss of data 4244 # Storing value of one type in variable of another (size_t in int, for example) + 4245 # Signed/unsigned mismatch 4267 # Conversion from 'size_t' to 'int', possible loss of data 4305 # Truncating value (double to float, for example) 4309 # Variable overflow, trying to store 128 in a signed char for example @@ -562,17 +579,42 @@ if (WIN32) set(WARNINGS "${WARNINGS} /wd${d}") endforeach(d) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WARNINGS} ${MT_BUILD}") - + set_target_properties(components PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") # oics uses tinyxml, which has an initialized but unused variable - set(OICS_WARNINGS "${WARNINGS} /wd4189") - set_target_properties(oics PROPERTIES COMPILE_FLAGS "${OICS_WARNINGS} ${MT_BUILD}") + set_target_properties(oics PROPERTIES COMPILE_FLAGS "${WARNINGS} /wd4189 ${MT_BUILD}") + set_target_properties(osg-ffmpeg-videoplayer PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") + + if (BUILD_BSATOOL) + set_target_properties(bsatool PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") + endif() + + if (BUILD_ESMTOOL) + set_target_properties(esmtool PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") + endif() + + if (BUILD_ESSIMPORTER) + set_target_properties(openmw-essimporter PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") + endif() + + if (BUILD_LAUNCHER) + set_target_properties(openmw-launcher PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") + endif() + + if (BUILD_MWINIIMPORTER) + set_target_properties(openmw-iniimporter PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") + endif() if (BUILD_OPENCS) - # QT triggers an informational warning that the object layout may differ when compiled with /vd2 - set(OPENCS_WARNINGS "${WARNINGS} ${MT_BUILD} /wd4435") - set_target_properties(openmw-cs PROPERTIES COMPILE_FLAGS ${OPENCS_WARNINGS}) - endif (BUILD_OPENCS) + set_target_properties(openmw-cs PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") + endif() + + if (BUILD_OPENMW) + set_target_properties(openmw PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") + endif() + + if (BUILD_WIZARD) + set_target_properties(openmw-wizard PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") + endif() endif(MSVC) # TODO: At some point release builds should not use the console but rather write to a log file diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index d6aecd7fb..f9c527da5 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -14,6 +14,9 @@ #include "model/doc/document.hpp" #include "model/world/data.hpp" +#ifdef _WIN32 +#include +#endif CS::Editor::Editor () : mUserSettings (mCfgMgr), mDocumentManager (mCfgMgr), From c71bbd02bfccb1507d984e36127eaf54acd3205e Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Mon, 8 Jun 2015 02:26:23 +0200 Subject: [PATCH 1462/3725] Finish up the OSG build scripts and configuration Sadly it seems like Appveyor can't build OpenMW without timing out yet. More build-time improvements are in order --- CI/before_script.msvc.sh | 186 ++++++++++++++++++++++++++++++++++----- CI/build.msvc.sh | 18 +++- CMakeLists.txt | 3 - appveyor.yml | 31 +++---- 4 files changed, 197 insertions(+), 41 deletions(-) diff --git a/CI/before_script.msvc.sh b/CI/before_script.msvc.sh index a12c17038..367a402a0 100644 --- a/CI/before_script.msvc.sh +++ b/CI/before_script.msvc.sh @@ -121,6 +121,11 @@ add_cmake_opts() { CMAKE_OPTS="$CMAKE_OPTS $@" } +RUNTIME_DLLS="" +add_runtime_dlls() { + RUNTIME_DLLS="$RUNTIME_DLLS $@" +} + if [ -z $PLATFORM ]; then PLATFORM=`uname -m` fi @@ -154,6 +159,20 @@ case $PLATFORM in ;; esac +case $CONFIGURATION in + debug|Debug|DEBUG ) + CONFIGURATION=Debug + ;; + + release|Release|RELEASE ) + CONFIGURATION=Release + ;; + + relwithdebinfo|RelWithDebInfo|RELWITHDEBINFO ) + CONFIGURATION=RelWithDebInfo + ;; +esac + echo echo "==========================" echo "Starting prebuild on win$BITS" @@ -178,9 +197,9 @@ if [ -z $SKIP_DOWNLOAD ]; then fi # Bullet - download "Bullet 2.83.4" \ - http://www.lysator.liu.se/~ace/OpenMW/deps/Bullet-2.83.4-win$BITS.7z \ - Bullet-2.83.4-win$BITS.7z + download "Bullet 2.83.5" \ + http://www.lysator.liu.se/~ace/OpenMW/deps/Bullet-2.83.5-win$BITS.7z \ + Bullet-2.83.5-win$BITS.7z # FFmpeg download "FFmpeg 2.5.2" \ @@ -219,10 +238,16 @@ cd .. #/.. # Set up dependencies if [ -z $KEEP ]; then - rm -rf OSG_$BITS - mkdir -p OSG_$BITS/deps + echo + printf "Preparing build directory... " + + rm -rf Build_$BITS + mkdir -p Build_$BITS/deps + + echo Done. fi -cd OSG_$BITS/deps +mkdir -p Build_$BITS/deps +cd Build_$BITS/deps DEPS_INSTALL=`pwd` @@ -236,7 +261,10 @@ if [ -z $APPVEYOR ]; then BOOST_SDK="`real_pwd`/Boost" - if [ -z $SKIP_EXTRACT ]; then + if [ -d Boost ] && grep "BOOST_VERSION 105800" Boost/boost/version.hpp > /dev/null; then + printf "Exists. " + elif [ -z $SKIP_EXTRACT ]; then + rm -rf Boost $DEPS/boost-1.58.0-win$BITS.exe //dir="$(echo $BOOST_SDK | sed s,/,\\\\,g)" //verysilent fi @@ -254,12 +282,15 @@ else fi # Bullet -printf "Bullet 2.83.4... " +printf "Bullet 2.83.5... " cd $DEPS_INSTALL -if [ -z $SKIP_EXTRACT ]; then - eval 7z x -y $DEPS/Bullet-2.83.4-win$BITS.7z $STRIP - mv Bullet-2.83.4-win$BITS Bullet +if [ -d Bullet ]; then + printf "Exists. (No version checking) " +elif [ -z $SKIP_EXTRACT ]; then + rm -rf Bullet + eval 7z x -y $DEPS/Bullet-2.83.5-win$BITS.7z $STRIP + mv Bullet-2.83.5-win$BITS Bullet fi BULLET_SDK="`real_pwd`/Bullet" @@ -279,7 +310,11 @@ echo Done. printf "FFmpeg 2.5.2... " cd $DEPS_INSTALL -if [ -z $SKIP_EXTRACT ]; then +if [ -d FFmpeg ] && grep "FFmpeg version: 2.5.2" FFmpeg/README.txt > /dev/null; then + printf "Exists. " +elif [ -z $SKIP_EXTRACT ]; then + rm -rf FFmpeg + eval 7z x -y $DEPS/ffmpeg$BITS-2.5.2.7z $STRIP eval 7z x -y $DEPS/ffmpeg$BITS-2.5.2-dev.7z $STRIP @@ -304,6 +339,8 @@ add_cmake_opts -DAVCODEC_INCLUDE_DIRS="$FFMPEG_SDK/include" \ -DSWSCALE_INCLUDE_DIRS="$FFMPEG_SDK/include" \ -DSWSCALE_LIBRARIES="$FFMPEG_SDK/lib/swscale.lib" +add_runtime_dlls `pwd`/FFmpeg/bin/{avcodec-56,avformat-56,avutil-54,swresample-1,swscale-3}.dll + if [ $BITS -eq 32 ]; then add_cmake_opts "-DCMAKE_EXE_LINKER_FLAGS=\"/machine:X86 /safeseh:no\"" fi @@ -316,7 +353,14 @@ echo Done. printf "MyGUI 3.2.2... " cd $DEPS_INSTALL -if [ -z $SKIP_EXTRACT ]; then +if [ -d MyGUI ] && \ + grep "MYGUI_VERSION_MAJOR 3" MyGUI/include/MYGUI/MyGUI_Prerequest.h > /dev/null && \ + grep "MYGUI_VERSION_MINOR 2" MyGUI/include/MYGUI/MyGUI_Prerequest.h > /dev/null && \ + grep "MYGUI_VERSION_PATCH 2" MyGUI/include/MYGUI/MyGUI_Prerequest.h > /dev/null +then + printf "Exists. " +elif [ -z $SKIP_EXTRACT ]; then + rm -rf MyGUI eval 7z x -y $DEPS/MyGUI-3.2.2-win$BITS.7z $STRIP mv MyGUI-3.2.2-win$BITS MyGUI fi @@ -327,28 +371,47 @@ add_cmake_opts -DMYGUISDK="$MYGUI_SDK" \ -DMYGUI_INCLUDE_DIRS="$MYGUI_SDK/include/MYGUI" \ -DMYGUI_PREQUEST_FILE="$MYGUI_SDK/include/MYGUI/MyGUI_Prerequest.h" +if [ $CONFIGURATION == "Debug" ]; then + SUFFIX="_d" +else + SUFFIX="" +fi +add_runtime_dlls `pwd`/MyGUI/bin/$CONFIGURATION/MyGUIEngine$SUFFIX.dll + cd $DEPS echo Done. # OpenAL printf "OpenAL-Soft 1.16.0... " -if [ -z $SKIP_EXTRACT ]; then +if [ -d openal-soft-1.16.0-bin ]; then + printf "Exists. " +elif [ -z $SKIP_EXTRACT ]; then + rm -rf openal-soft-1.16.0-bin eval 7z x -y OpenAL-Soft-1.16.0.zip $STRIP fi OPENAL_SDK="`real_pwd`/openal-soft-1.16.0-bin" -add_cmake_opts -DOPENAL_INCLUDE_DIR="$OPENAL_SDK/include" \ +add_cmake_opts -DOPENAL_INCLUDE_DIR="$OPENAL_SDK/include/AL" \ -DOPENAL_LIBRARY="$OPENAL_SDK/libs/Win$BITS/OpenAL32.lib" + + echo Done. # OSG printf "OSG 3.3.8... " cd $DEPS_INSTALL -if [ -z $SKIP_EXTRACT ]; then +if [ -d OSG ] && \ + grep "OPENSCENEGRAPH_MAJOR_VERSION 3" OSG/include/osg/Version > /dev/null && \ + grep "OPENSCENEGRAPH_MINOR_VERSION 3" OSG/include/osg/Version > /dev/null && \ + grep "OPENSCENEGRAPH_PATCH_VERSION 8" OSG/include/osg/Version > /dev/null +then + printf "Exists. " +elif [ -z $SKIP_EXTRACT ]; then + rm -rf OSG eval 7z x -y $DEPS/OSG-3.3.8-win$BITS.7z $STRIP mv OSG-3.3.8-win$BITS OSG fi @@ -357,6 +420,21 @@ OSG_SDK="`real_pwd`/OSG" add_cmake_opts -DOSG_DIR="$OSG_SDK" +if [ $CONFIGURATION == "Debug" ]; then + SUFFIX="d" +else + SUFFIX="" +fi +add_runtime_dlls `pwd`/OSG/bin/{OpenThreads,zlib}$SUFFIX.dll \ + `pwd`/OSG/bin/osg{,Animation,DB,FX,GA,Particle,Qt,Text,Util,Viewer}$SUFFIX.dll + +OSG_PLUGINS="" +add_osg_dlls() { + OSG_PLUGINS="$OSG_PLUGINS $@" +} + +add_osg_dlls `pwd`/OSG/bin/osgPlugins-3.3.8/osgdb_{bmp,dds,gif,jpeg,png,tga}$SUFFIX.dll + cd $DEPS echo Done. @@ -365,7 +443,10 @@ echo Done. printf "Qt 4.8.6... " cd $DEPS_INSTALL -if [ -z $SKIP_EXTRACT ]; then +if [ -d Qt ] && head -n2 Qt/BUILDINFO.txt | grep "4.8.6" > /dev/null; then + printf "Exists. " +elif [ -z $SKIP_EXTRACT ]; then + rm -rf Qt eval 7z x -y $DEPS/qt$BITS-4.8.6.7z $STRIP mv qt-4.8.6-* Qt fi @@ -377,6 +458,13 @@ eval qtbinpatcher.exe $STRIP add_cmake_opts -DQT_QMAKE_EXECUTABLE="$QT_SDK/bin/qmake.exe" +if [ $CONFIGURATION == "Debug" ]; then + SUFFIX="d4" +else + SUFFIX="4" +fi +add_runtime_dlls `pwd`/bin/Qt{Core,Gui,Network,OpenGL}$SUFFIX.dll + cd $DEPS echo Done. @@ -384,7 +472,10 @@ echo Done. # SDL2 printf "SDL 2.0.3... " -if [ -z $SKIP_EXTRACT ]; then +if [ -d SDL2-2.0.3 ]; then + printf "Exists. " +elif [ -z $SKIP_EXTRACT ]; then + rm -rf SDL2-2.0.3 eval 7z x -y SDL2-2.0.3.zip $STRIP fi @@ -394,6 +485,8 @@ add_cmake_opts -DSDL2_INCLUDE_DIR="$SDL_SDK/include" \ -DSDL2_LIBRARY_PATH="$SDL_SDK/lib/x$ARCHSUFFIX/SDL2.lib" \ -DSDL2_LIBRARY_ONLY="$SDL_SDK/lib/x$ARCHSUFFIX/SDL2.lib" +add_runtime_dlls `pwd`/SDL2-2.0.3/lib/x$ARCHSUFFIX/SDL2.dll + cd $DEPS echo Done. @@ -401,11 +494,50 @@ echo cd $DEPS_INSTALL/.. -echo "Building OpenMW..." +echo "Setting up OpenMW build..." add_cmake_opts -DBUILD_BSATOOL=no \ -DBUILD_ESMTOOL=no \ - -DBUILD_MYGUI_PLUGIN=no + -DBUILD_MYGUI_PLUGIN=no \ + -DOPENMW_MP_BUILD=yes + +if [ -z $APPVEYOR ]; then + echo " (Outside of AppVeyor, doing full build.)" +else + case $STEP in + components ) + echo " Subproject: Components." + add_cmake_opts -DBUILD_ESSIMPORTER=no \ + -DBUILD_LAUNCHER=no \ + -DBUILD_MWINIIMPORTER=no \ + -DBUILD_OPENCS=no \ + -DBUILD_OPENMW=no \ + -DBUILD_WIZARD=no + rm -rf components + ;; + openmw ) + echo " Subproject: OpenMW." + add_cmake_opts -DBUILD_ESSIMPORTER=no \ + -DBUILD_LAUNCHER=no \ + -DBUILD_MWINIIMPORTER=no \ + -DBUILD_OPENCS=no \ + -DBUILD_WIZARD=no + ;; + opencs ) + echo " Subproject: OpenCS." + add_cmake_opts -DBUILD_ESSIMPORTER=no \ + -DBUILD_LAUNCHER=no \ + -DBUILD_MWINIIMPORTER=no \ + -DBUILD_OPENMW=no \ + -DBUILD_WIZARD=no + ;; + misc ) + echo " Subproject: Misc." + add_cmake_opts -DBUILD_OPENCS=no \ + -DBUILD_OPENMW=no + ;; + esac +fi if [ -z $VERBOSE ]; then printf " Configuring... " @@ -423,4 +555,18 @@ fi echo +echo "Copying Runtime DLLs..." +mkdir -p $CONFIGURATION +for DLL in $RUNTIME_DLLS; do + echo " `basename $DLL`." + cp "$DLL" $CONFIGURATION/ +done +echo "OSG Plugin DLLs..." +mkdir -p $CONFIGURATION/osgPlugins-3.3.8 +for DLL in $OSG_PLUGINS; do + echo " `basename $DLL`." + cp "$DLL" $CONFIGURATION/osgPlugins-3.3.8 +done +echo + exit $RET \ No newline at end of file diff --git a/CI/build.msvc.sh b/CI/build.msvc.sh index b17e7b94c..d426ef90d 100644 --- a/CI/build.msvc.sh +++ b/CI/build.msvc.sh @@ -10,10 +10,14 @@ fi case $PLATFORM in x32|x86|i686|i386|win32|Win32 ) - BITS=32 ;; + BITS=32 + PLATFORM=Win32 + ;; x64|x86_64|x86-64|win64|Win64 ) - BITS=64 ;; + BITS=64 + PLATFORM=x64 + ;; * ) echo "Unknown platform $PLATFORM." @@ -40,4 +44,12 @@ if [ $? -ne 0 ]; then } fi -msbuild OpenMW.sln //t:Build //p:Configuration=$CONFIGURATION //m:8 //logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" +if [ -z $APPVEYOR ]; then + msbuild OpenMW.sln //t:Build //m:8 +else + msbuild OpenMW.sln //t:Build //m:8 //logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" +fi + +if [ ! -z $PACKAGE ]; then + msbuild PACKAGE.vcxproj //t:Build //m:8 +fi \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index f98838452..77b054ff5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -138,9 +138,6 @@ if (WIN32) # Suppress WinMain(), provided by SDL add_definitions(-DSDL_MAIN_HANDLED) - - # Get rid of useless crud from windows.h - add_definitions(-DNOMINMAX -DWIN32_LEAN_AND_MEAN) endif() # Dependencies diff --git a/appveyor.yml b/appveyor.yml index e46dd3dd8..a229a2212 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -6,28 +6,27 @@ platform: configuration: - Debug - - Release + +environment: + matrix: + - STEP: openmw + - STEP: opencs + - STEP: misc matrix: fast_finish: true os: unstable -clone_depth: 5 +clone_depth: 1 cache: - - C:\projects\openmw\deps\Bullet-2.83.4-win32.7z -> CI/before_script.msvc.sh - - C:\projects\openmw\deps\Bullet-2.83.4-win64.7z -> CI/before_script.msvc.sh - - C:\projects\openmw\deps\MyGUI-3.2.2-win32.7z -> CI/before_script.msvc.sh - - C:\projects\openmw\deps\MyGUI-3.2.2-win64.7z -> CI/before_script.msvc.sh - - C:\projects\openmw\deps\Ogre-1.9-win32.7z -> CI/before_script.msvc.sh - - C:\projects\openmw\deps\Ogre-1.9-win64.7z -> CI/before_script.msvc.sh - - C:\projects\openmw\deps\ffmpeg32-2.5.2.7z -> CI/before_script.msvc.sh - - C:\projects\openmw\deps\ffmpeg64-2.5.2-dev.7z -> CI/before_script.msvc.sh - - C:\projects\openmw\deps\ffmpeg64-2.5.2.7z -> CI/before_script.msvc.sh - - C:\projects\openmw\deps\ffmpeg64-2.5.2-dev.7z -> CI/before_script.msvc.sh - - C:\projects\openmw\deps\OpenAL-Soft-1.16.0.zip -> CI/before_script.msvc.sh - - C:\projects\openmw\deps\SDL2-2.0.3.zip -> CI/before_script.msvc.sh + - C:\projects\openmw\deps\Bullet-2.83.5-win32.7z + - C:\projects\openmw\deps\Bullet-2.83.5-win64.7z + - C:\projects\openmw\deps\MyGUI-3.2.2-win32.7z + - C:\projects\openmw\deps\MyGUI-3.2.2-win64.7z + - C:\projects\openmw\deps\OSG-3.3.8-win32.7z + - C:\projects\openmw\deps\OSG-3.3.8-win64.7z init: - cmd: bash --version @@ -41,4 +40,6 @@ build_script: - cmd: bash --login C:\projects\openmw\CI\build.msvc.sh before_build: - - cmd: bash --login C:\projects\openmw\CI\before_script.msvc.sh + - cmd: bash --login C:\projects\openmw\CI\before_script.msvc.sh -k + +test: off From d7fb49725569e6fed93672f86036e6037cd112b8 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Mon, 8 Jun 2015 21:33:23 +0300 Subject: [PATCH 1463/3725] Color values are displayed as colored rectangles in tables --- apps/opencs/CMakeLists.txt | 1 + apps/opencs/view/doc/viewmanager.cpp | 4 ++ .../opencs/view/world/colorpickerdelegate.cpp | 50 +++++++++++++++++++ .../opencs/view/world/colorpickerdelegate.hpp | 45 +++++++++++++++++ 4 files changed, 100 insertions(+) create mode 100644 apps/opencs/view/world/colorpickerdelegate.cpp create mode 100644 apps/opencs/view/world/colorpickerdelegate.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 37d13223a..4a5a64f60 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -70,6 +70,7 @@ opencs_units (view/world opencs_units_noqt (view/world subviews enumdelegate vartypedelegate recordstatusdelegate idtypedelegate datadisplaydelegate scripthighlighter idvalidator dialoguecreator physicssystem idcompletiondelegate + colorpickerdelegate ) opencs_units (view/widget diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index b2f681df1..e5bb7fe81 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -19,6 +19,7 @@ #include "../world/recordstatusdelegate.hpp" #include "../world/idtypedelegate.hpp" #include "../world/idcompletiondelegate.hpp" +#include "../world/colorpickerdelegate.hpp" #include "../../model/settings/usersettings.hpp" @@ -63,6 +64,9 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) mDelegateFactories->add (CSMWorld::ColumnBase::Display_RefRecordType, new CSVWorld::IdTypeDelegateFactory()); + mDelegateFactories->add (CSMWorld::ColumnBase::Display_Colour, + new CSVWorld::ColorPickerDelegateFactory()); + std::vector idCompletionColumns = CSMWorld::IdCompletionManager::getDisplayTypes(); for (std::vector::const_iterator current = idCompletionColumns.begin(); current != idCompletionColumns.end(); diff --git a/apps/opencs/view/world/colorpickerdelegate.cpp b/apps/opencs/view/world/colorpickerdelegate.cpp new file mode 100644 index 000000000..aa9f2e937 --- /dev/null +++ b/apps/opencs/view/world/colorpickerdelegate.cpp @@ -0,0 +1,50 @@ +#include "colorpickerdelegate.hpp" + +#include +#include + +CSVWorld::ColorPickerDelegate::ColorPickerDelegate(CSMWorld::CommandDispatcher *dispatcher, + CSMDoc::Document& document, + QObject *parent) + : CommandDelegate(dispatcher, document, parent) +{} + +QWidget *CSVWorld::ColorPickerDelegate::createEditor(QWidget *parent, + const QStyleOptionViewItem &option, + const QModelIndex &index) const +{ + return createEditor(parent, option, index, getDisplayTypeFromIndex(index)); +} + +QWidget *CSVWorld::ColorPickerDelegate::createEditor(QWidget *parent, + const QStyleOptionViewItem &option, + const QModelIndex &index, + CSMWorld::ColumnBase::Display display) const +{ + if (display != CSMWorld::ColumnBase::Display_Colour) + { + throw std::logic_error("Wrong column for ColorPickerDelegate"); + } + + return CommandDelegate::createEditor(parent, option, index, display); +} + +void CSVWorld::ColorPickerDelegate::paint(QPainter *painter, + const QStyleOptionViewItem &option, + const QModelIndex &index) const +{ + QColor color = index.data().value(); + QRect rect(option.rect.x() + option.rect.width() / 4, + option.rect.y() + option.rect.height() / 4, + option.rect.width() / 2, + option.rect.height() / 2); + + painter->fillRect(rect, color); +} + +CSVWorld::CommandDelegate *CSVWorld::ColorPickerDelegateFactory::makeDelegate(CSMWorld::CommandDispatcher *dispatcher, + CSMDoc::Document &document, + QObject *parent) const +{ + return new ColorPickerDelegate(dispatcher, document, parent); +} \ No newline at end of file diff --git a/apps/opencs/view/world/colorpickerdelegate.hpp b/apps/opencs/view/world/colorpickerdelegate.hpp new file mode 100644 index 000000000..e93e0e87d --- /dev/null +++ b/apps/opencs/view/world/colorpickerdelegate.hpp @@ -0,0 +1,45 @@ +#ifndef CSV_WORLD_COLORPICKERDELEGATE_HPP +#define CSV_WORLD_COLORPICKERDELEGATE_HPP + +#include "util.hpp" + +namespace CSVWorld +{ + class ColorPickerDelegate : public CommandDelegate + { + public: + ColorPickerDelegate(CSMWorld::CommandDispatcher *dispatcher, + CSMDoc::Document& document, + QObject *parent); + + virtual QWidget *createEditor(QWidget *parent, + const QStyleOptionViewItem &option, + const QModelIndex &index) const; + + virtual QWidget *createEditor(QWidget *parent, + const QStyleOptionViewItem &option, + const QModelIndex &index, + CSMWorld::ColumnBase::Display display) const; + + virtual void paint(QPainter *painter, + const QStyleOptionViewItem &option, + const QModelIndex &index) const;/* + + virtual void setEditorData(QWidget *editor, const QModelIndex &index) const; + + virtual void setModelData(QWidget *editor, + QAbstractItemModel &model, + const QModelIndex &index) const;*/ + }; + + class ColorPickerDelegateFactory : public CommandDelegateFactory + { + public: + virtual CommandDelegate *makeDelegate(CSMWorld::CommandDispatcher *dispatcher, + CSMDoc::Document &document, + QObject *parent) const; + ///< The ownership of the returned CommandDelegate is transferred to the caller. + }; +} + +#endif From f511cb08ff73917669672359703c529eb801fcbc Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 8 Jun 2015 20:37:01 +0200 Subject: [PATCH 1464/3725] Compatibility with bullet versions < 2.81 --- apps/openmw/mwphysics/physicssystem.cpp | 28 +++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index b7d02e159..6be42affb 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -672,16 +672,24 @@ namespace MWPhysics mLeastDistSqr(std::numeric_limits::max()) { } +#if BT_BULLET_VERSION >= 281 virtual btScalar addSingleResult(btManifoldPoint& cp, const btCollisionObjectWrapper* col0Wrap,int partId0,int index0, const btCollisionObjectWrapper* col1Wrap,int partId1,int index1) { - if (col1Wrap->m_collisionObject != mMe) + const btCollisionObject* collisionObject = col1Wrap->m_collisionObject; +#else + virtual btScalar addSingleResult(btManifoldPoint& cp, const btCollisionObject* col0, int partId0, int index0, + const btCollisionObject* col1, int partId1, int index1) + { + const btCollisionObject* collisionObject = col1; +#endif + if (collisionObject != mMe) { btScalar distsqr = mOrigin.distance2(cp.getPositionWorldOnA()); if(!mObject || distsqr < mLeastDistSqr) { - mObject = col1Wrap->m_collisionObject; + mObject = collisionObject; mLeastDistSqr = distsqr; mContactPoint = cp.getPositionWorldOnA(); } @@ -874,11 +882,19 @@ namespace MWPhysics public: std::vector mResult; - virtual btScalar addSingleResult(btManifoldPoint& cp, - const btCollisionObjectWrapper* colObj0Wrap,int partId0,int index0, - const btCollisionObjectWrapper* colObj1Wrap,int partId1,int index1) +#if BT_BULLET_VERSION >= 281 + virtual btScalar addSingleResult(btManifoldPoint& cp, + const btCollisionObjectWrapper* col0Wrap,int partId0,int index0, + const btCollisionObjectWrapper* col1Wrap,int partId1,int index1) + { + const btCollisionObject* collisionObject = col1Wrap->m_collisionObject; +#else + virtual btScalar addSingleResult(btManifoldPoint& cp, const btCollisionObject* col0, int partId0, int index0, + const btCollisionObject* col1, int partId1, int index1) { - const PtrHolder* holder = static_cast(colObj0Wrap->m_collisionObject->getUserPointer()); + const btCollisionObject* collisionObject = col1; +#endif + const PtrHolder* holder = static_cast(collisionObject->getUserPointer()); if (holder) mResult.push_back(holder->getPtr()); return 0.f; From 93ee11c5e78b045848957908006044576bff8302 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 8 Jun 2015 21:21:09 +0200 Subject: [PATCH 1465/3725] Fix particlesystem nested RenderBin issue (Bug #2631) --- components/nifosg/nifloader.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 44784fd7e..fcba9893d 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -868,8 +868,6 @@ namespace NifOsg mat->setColorMode(osg::Material::AMBIENT); } - partsys->getOrCreateStateSet()->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); - // particle system updater (after the emitters and affectors in the scene graph) // I think for correct culling needs to be *before* the ParticleSystem, though osg examples do it the other way osg::ref_ptr updater = new osgParticle::ParticleSystemUpdater; From 5921e7062544ae19c1d78fd8a1e5a98ddbdb0de2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 9 Jun 2015 02:29:56 +0200 Subject: [PATCH 1466/3725] Build a kdtree for terrain geometry Improves intersection testing performance, shaving off ~2ms of frame time in exteriors. Also increases terrain loading time by ~1ms per cell, so will have to look into background loading soon. --- components/terrain/terraingrid.cpp | 5 +++++ components/terrain/terraingrid.hpp | 7 +++++++ 2 files changed, 12 insertions(+) diff --git a/components/terrain/terraingrid.cpp b/components/terrain/terraingrid.cpp index 322c15196..c8f8caef8 100644 --- a/components/terrain/terraingrid.cpp +++ b/components/terrain/terraingrid.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include @@ -66,6 +67,7 @@ namespace Terrain TerrainGrid::TerrainGrid(osg::Group* parent, Resource::ResourceSystem* resourceSystem, osgUtil::IncrementalCompileOperation* ico, Storage* storage, int nodeMask) : Terrain::World(parent, resourceSystem, ico, storage, nodeMask) + , mKdTreeBuilder(new osg::KdTreeBuilder) { } @@ -133,6 +135,9 @@ void TerrainGrid::loadCell(int x, int y) osg::ref_ptr geode (new osg::Geode); geode->addDrawable(geometry); + // build a kdtree to speed up intersection tests with the terrain + geode->accept(*mKdTreeBuilder); + std::vector layerList; std::vector > blendmaps; mStorage->getBlendmaps(1.f, center, false, blendmaps, layerList); diff --git a/components/terrain/terraingrid.hpp b/components/terrain/terraingrid.hpp index 3a6d71793..a697297b5 100644 --- a/components/terrain/terraingrid.hpp +++ b/components/terrain/terraingrid.hpp @@ -25,6 +25,11 @@ #include "world.hpp" #include "material.hpp" +namespace osg +{ + class KdTreeBuilder; +} + namespace Terrain { @@ -44,6 +49,8 @@ namespace Terrain private: typedef std::map, GridElement*> Grid; Grid mGrid; + + osg::ref_ptr mKdTreeBuilder; }; } From db16cdad027e4b53bbf62a6e40dedc1277d4e560 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 9 Jun 2015 03:16:41 +0200 Subject: [PATCH 1467/3725] Add a comment --- components/terrain/terraingrid.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/components/terrain/terraingrid.cpp b/components/terrain/terraingrid.cpp index c8f8caef8..570461bba 100644 --- a/components/terrain/terraingrid.cpp +++ b/components/terrain/terraingrid.cpp @@ -136,6 +136,7 @@ void TerrainGrid::loadCell(int x, int y) geode->addDrawable(geometry); // build a kdtree to speed up intersection tests with the terrain + // Note, the build could be optimized using a custom kdtree builder, since we know that the terrain can be represented by a quadtree geode->accept(*mKdTreeBuilder); std::vector layerList; From ef88b28c26c8031ba29a4f81a44eb6a4391f362c Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Tue, 9 Jun 2015 15:20:50 +0300 Subject: [PATCH 1468/3725] Create a custom item editor for color columns --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/view/widget/coloreditbutton.cpp | 42 +++++++++++++++++++ apps/opencs/view/widget/coloreditbutton.hpp | 30 +++++++++++++ .../opencs/view/world/colorpickerdelegate.cpp | 26 ++++++++---- .../opencs/view/world/colorpickerdelegate.hpp | 17 ++++---- 5 files changed, 100 insertions(+), 17 deletions(-) create mode 100644 apps/opencs/view/widget/coloreditbutton.cpp create mode 100644 apps/opencs/view/widget/coloreditbutton.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 4a5a64f60..f8f3ea036 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -75,7 +75,7 @@ opencs_units_noqt (view/world opencs_units (view/widget scenetoolbar scenetool scenetoolmode pushbutton scenetooltoggle scenetoolrun modebutton - scenetooltoggle2 completerpopup + scenetooltoggle2 completerpopup coloreditbutton ) opencs_units (view/render diff --git a/apps/opencs/view/widget/coloreditbutton.cpp b/apps/opencs/view/widget/coloreditbutton.cpp new file mode 100644 index 000000000..4960d1ef1 --- /dev/null +++ b/apps/opencs/view/widget/coloreditbutton.cpp @@ -0,0 +1,42 @@ +#include "coloreditbutton.hpp" + +#include +#include +#include + +CSVWidget::ColorEditButton::ColorEditButton(const QColor &color, + const QSize &coloredRectSize, + QWidget *parent) + : QPushButton(parent), + mColor(color), + mColoredRectSize(coloredRectSize) + +{} + +void CSVWidget::ColorEditButton::paintEvent(QPaintEvent *event) +{ + QPushButton::paintEvent(event); + + QRect buttonRect = rect(); + QRect coloredRect(buttonRect.x() + (buttonRect.width() - mColoredRectSize.width()) / 2, + buttonRect.y() + (buttonRect.height() - mColoredRectSize.height()) / 2, + mColoredRectSize.width(), + mColoredRectSize.height()); + QPainter painter(this); + painter.fillRect(coloredRect, mColor); +} + +QColor CSVWidget::ColorEditButton::color() const +{ + return mColor; +} + +void CSVWidget::ColorEditButton::setColor(const QColor &color) +{ + mColor = color; +} + +void CSVWidget::ColorEditButton::setColoredRectSize(const QSize &size) +{ + mColoredRectSize = size; +} \ No newline at end of file diff --git a/apps/opencs/view/widget/coloreditbutton.hpp b/apps/opencs/view/widget/coloreditbutton.hpp new file mode 100644 index 000000000..e1a8cce9d --- /dev/null +++ b/apps/opencs/view/widget/coloreditbutton.hpp @@ -0,0 +1,30 @@ +#ifndef CSV_WIDGET_COLOREDITBUTTON_HPP +#define CSV_WIDGET_COLOREDITBUTTON_HPP + +#include + +class QColor; +class QSize; + +namespace CSVWidget +{ + class ColorEditButton : public QPushButton + { + QColor mColor; + QSize mColoredRectSize; + + public: + ColorEditButton(const QColor &color, + const QSize &coloredRectSize, + QWidget *parent = 0); + + QColor color() const; + void setColor(const QColor &color); + void setColoredRectSize(const QSize &size); + + protected: + void paintEvent(QPaintEvent *event); + }; +} + +#endif diff --git a/apps/opencs/view/world/colorpickerdelegate.cpp b/apps/opencs/view/world/colorpickerdelegate.cpp index aa9f2e937..c74a1828f 100644 --- a/apps/opencs/view/world/colorpickerdelegate.cpp +++ b/apps/opencs/view/world/colorpickerdelegate.cpp @@ -3,6 +3,8 @@ #include #include +#include "../widget/coloreditbutton.hpp" + CSVWorld::ColorPickerDelegate::ColorPickerDelegate(CSMWorld::CommandDispatcher *dispatcher, CSMDoc::Document& document, QObject *parent) @@ -26,20 +28,24 @@ QWidget *CSVWorld::ColorPickerDelegate::createEditor(QWidget *parent, throw std::logic_error("Wrong column for ColorPickerDelegate"); } - return CommandDelegate::createEditor(parent, option, index, display); + return new CSVWidget::ColorEditButton(index.data().value(), + getColoredRect(option).size(), + parent); } void CSVWorld::ColorPickerDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { - QColor color = index.data().value(); - QRect rect(option.rect.x() + option.rect.width() / 4, - option.rect.y() + option.rect.height() / 4, - option.rect.width() / 2, - option.rect.height() / 2); - - painter->fillRect(rect, color); + painter->fillRect(getColoredRect(option), index.data().value()); +} + +QRect CSVWorld::ColorPickerDelegate::getColoredRect(const QStyleOptionViewItem &option) const +{ + return QRect(option.rect.x() + option.rect.width() / 4, + option.rect.y() + option.rect.height() / 4, + option.rect.width() / 2, + option.rect.height() / 2); } CSVWorld::CommandDelegate *CSVWorld::ColorPickerDelegateFactory::makeDelegate(CSMWorld::CommandDispatcher *dispatcher, @@ -47,4 +53,6 @@ CSVWorld::CommandDelegate *CSVWorld::ColorPickerDelegateFactory::makeDelegate(CS QObject *parent) const { return new ColorPickerDelegate(dispatcher, document, parent); -} \ No newline at end of file +} + + diff --git a/apps/opencs/view/world/colorpickerdelegate.hpp b/apps/opencs/view/world/colorpickerdelegate.hpp index e93e0e87d..147c2f424 100644 --- a/apps/opencs/view/world/colorpickerdelegate.hpp +++ b/apps/opencs/view/world/colorpickerdelegate.hpp @@ -3,10 +3,19 @@ #include "util.hpp" +class QRect; + +namespace CSVWidget +{ + class ColorEditButton; +} + namespace CSVWorld { class ColorPickerDelegate : public CommandDelegate { + QRect getColoredRect(const QStyleOptionViewItem &option) const; + public: ColorPickerDelegate(CSMWorld::CommandDispatcher *dispatcher, CSMDoc::Document& document, @@ -23,13 +32,7 @@ namespace CSVWorld virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, - const QModelIndex &index) const;/* - - virtual void setEditorData(QWidget *editor, const QModelIndex &index) const; - - virtual void setModelData(QWidget *editor, - QAbstractItemModel &model, - const QModelIndex &index) const;*/ + const QModelIndex &index) const; }; class ColorPickerDelegateFactory : public CommandDelegateFactory From c621d0400c58e4e7cff5ec8bfc7fe5f5073d80aa Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 9 Jun 2015 18:22:18 +0200 Subject: [PATCH 1469/3725] Fix error handling for out-of-range NIF roots (found in Bosmora, TR) --- components/nif/niffile.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index 0a6f8f505..1db9c8ccf 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -193,9 +193,9 @@ void NIFFile::parse() for(size_t i = 0;i < rootNum;i++) { int idx = nif.getInt(); - if (idx >= 0) + if (idx >= 0 && idx < int(records.size())) { - roots[i] = records.at(idx); + roots[i] = records[idx]; } else { From 8e8da724f5dd7bddc5dccee3c081664335cb60c1 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Wed, 10 Jun 2015 08:23:38 +1000 Subject: [PATCH 1470/3725] Remove unnecessary comment entry in the config file. --- components/config/gamesettings.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/config/gamesettings.cpp b/components/config/gamesettings.cpp index 2b3a8ba4b..9af6c9714 100644 --- a/components/config/gamesettings.cpp +++ b/components/config/gamesettings.cpp @@ -291,9 +291,9 @@ bool Config::GameSettings::writeFileWithComments(QFile &file) stream << key << "=" << value << "\n"; } + // new entries if (!userSettingsCopy.empty()) { - stream << "# new entries" << "\n"; QMap::const_iterator it = userSettingsCopy.begin(); for (; it != userSettingsCopy.end(); ++it) { From 15453e3d905fb149cd7502a9dc16ed39d190f1af Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 10 Jun 2015 16:59:35 +0200 Subject: [PATCH 1471/3725] Use MyGUI::UString for unicode conversion --- apps/openmw/mwinput/inputmanagerimp.cpp | 65 ++----------------------- 1 file changed, 3 insertions(+), 62 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 1b5abc099..7ef26f703 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -35,65 +35,6 @@ using namespace ICS; -namespace -{ - std::vector utf8ToUnicode(const std::string& utf8) - { - std::vector unicode; - size_t i = 0; - while (i < utf8.size()) - { - unsigned long uni; - size_t todo; - unsigned char ch = utf8[i++]; - if (ch <= 0x7F) - { - uni = ch; - todo = 0; - } - else if (ch <= 0xBF) - { - throw std::logic_error("not a UTF-8 string"); - } - else if (ch <= 0xDF) - { - uni = ch&0x1F; - todo = 1; - } - else if (ch <= 0xEF) - { - uni = ch&0x0F; - todo = 2; - } - else if (ch <= 0xF7) - { - uni = ch&0x07; - todo = 3; - } - else - { - throw std::logic_error("not a UTF-8 string"); - } - for (size_t j = 0; j < todo; ++j) - { - if (i == utf8.size()) - throw std::logic_error("not a UTF-8 string"); - unsigned char ch = utf8[i++]; - if (ch < 0x80 || ch > 0xBF) - throw std::logic_error("not a UTF-8 string"); - uni <<= 6; - uni += ch & 0x3F; - } - if (uni >= 0xD800 && uni <= 0xDFFF) - throw std::logic_error("not a UTF-8 string"); - if (uni > 0x10FFFF) - throw std::logic_error("not a UTF-8 string"); - unicode.push_back(uni); - } - return unicode; - } -} - namespace MWInput { InputManager::InputManager( @@ -723,9 +664,9 @@ namespace MWInput void InputManager::textInput(const SDL_TextInputEvent &arg) { - const char* text = &arg.text[0]; - std::vector unicode = utf8ToUnicode(std::string(text)); - for (std::vector::iterator it = unicode.begin(); it != unicode.end(); ++it) + MyGUI::UString ustring(&arg.text[0]); + MyGUI::UString::utf32string utf32string = ustring.asUTF32(); + for (MyGUI::UString::utf32string::const_iterator it = utf32string.begin(); it != utf32string.end(); ++it) MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::None, *it); } From cc71e894e1ec30782ebe9e6ef398f5b270f9ceb9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 10 Jun 2015 18:15:31 +0200 Subject: [PATCH 1472/3725] Add WorkQueue class --- components/CMakeLists.txt | 2 +- components/sceneutil/workqueue.cpp | 119 +++++++++++++++++++++++++++++ components/sceneutil/workqueue.hpp | 91 ++++++++++++++++++++++ 3 files changed, 211 insertions(+), 1 deletion(-) create mode 100644 components/sceneutil/workqueue.cpp create mode 100644 components/sceneutil/workqueue.hpp diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 5a4ec605b..8ce770657 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -41,7 +41,7 @@ add_component_dir (resource ) add_component_dir (sceneutil - clone attach lightmanager visitor util statesetupdater controller skeleton riggeometry lightcontroller + clone attach lightmanager visitor util statesetupdater controller skeleton riggeometry lightcontroller workqueue ) add_component_dir (nif diff --git a/components/sceneutil/workqueue.cpp b/components/sceneutil/workqueue.cpp new file mode 100644 index 000000000..a709eae85 --- /dev/null +++ b/components/sceneutil/workqueue.cpp @@ -0,0 +1,119 @@ +#include "workqueue.hpp" + +namespace SceneUtil +{ + +void WorkTicket::waitTillDone() +{ + if (mDone > 0) + return; + + OpenThreads::ScopedLock lock(mMutex); + while (mDone == 0) + { + mCondition.wait(&mMutex); + } +} + +void WorkTicket::signalDone() +{ + OpenThreads::ScopedLock lock(mMutex); + mDone.exchange(1); + mCondition.broadcast(); +} + +WorkItem::WorkItem() + : mTicket(new WorkTicket) +{ +} + +WorkItem::~WorkItem() +{ +} + +void WorkItem::doWork() +{ + mTicket->signalDone(); +} + +osg::ref_ptr WorkItem::getTicket() +{ + return mTicket; +} + +WorkQueue::WorkQueue(int workerThreads) + : mIsReleased(false) +{ + for (int i=0; istartThread(); + } +} + +WorkQueue::~WorkQueue() +{ + { + OpenThreads::ScopedLock lock(mMutex); + while (mQueue.size()) + { + WorkItem* item = mQueue.front(); + delete item; + mQueue.pop(); + } + mIsReleased = true; + mCondition.broadcast(); + } + + for (unsigned int i=0; ijoin(); + delete mThreads[i]; + } +} + +WorkTicket* WorkQueue::addWorkItem(WorkItem *item) +{ + WorkTicket* ticket = item->getTicket().get(); + OpenThreads::ScopedLock lock(mMutex); + mQueue.push(item); + mCondition.signal(); + return ticket; +} + +WorkItem *WorkQueue::removeWorkItem() +{ + OpenThreads::ScopedLock lock(mMutex); + while (!mQueue.size() && !mIsReleased) + { + mCondition.wait(&mMutex); + } + if (mQueue.size()) + { + WorkItem* item = mQueue.front(); + mQueue.pop(); + return item; + } + else + return NULL; +} + +WorkThread::WorkThread(WorkQueue *workQueue) + : mWorkQueue(workQueue) +{ +} + +void WorkThread::run() +{ + while (true) + { + WorkItem* item = mWorkQueue->removeWorkItem(); + if (!item) + return; + item->doWork(); + delete item; + } +} + +} diff --git a/components/sceneutil/workqueue.hpp b/components/sceneutil/workqueue.hpp new file mode 100644 index 000000000..720fbaa68 --- /dev/null +++ b/components/sceneutil/workqueue.hpp @@ -0,0 +1,91 @@ +#ifndef OPENMW_COMPONENTS_SCENEUTIL_WORKQUEUE_H +#define OPENMW_COMPONENTS_SCENEUTIL_WORKQUEUE_H + +#include +#include +#include +#include + +#include +#include + +#include + +namespace SceneUtil +{ + + class WorkTicket : public osg::Referenced + { + public: + void waitTillDone(); + + void signalDone(); + + private: + OpenThreads::Atomic mDone; + OpenThreads::Mutex mMutex; + OpenThreads::Condition mCondition; + }; + + class WorkItem + { + public: + WorkItem(); + virtual ~WorkItem(); + + /// Override in a derived WorkItem to perform actual work. + /// By default, just signals the ticket that the work is done. + virtual void doWork(); + + osg::ref_ptr getTicket(); + + protected: + osg::ref_ptr mTicket; + }; + + class WorkQueue; + + class WorkThread : public OpenThreads::Thread + { + public: + WorkThread(WorkQueue* workQueue); + + virtual void run(); + + private: + WorkQueue* mWorkQueue; + }; + + /// @brief A work queue that users can push work items onto, to be completed by one or more background threads. + class WorkQueue + { + public: + WorkQueue(int numWorkerThreads=1); + ~WorkQueue(); + + /// Add a new work item to the back of the queue. + /// @par The returned WorkTicket may be used by the caller to wait until the work is complete. + WorkTicket* addWorkItem(WorkItem* item); + + /// Get the next work item from the front of the queue. If the queue is empty, waits until a new item is added. + /// If the workqueue is in the process of being destroyed, may return NULL. + /// @note The caller must free the returned WorkItem + WorkItem* removeWorkItem(); + + void runThread(); + + private: + bool mIsReleased; + std::queue mQueue; + + OpenThreads::Mutex mMutex; + OpenThreads::Condition mCondition; + + std::vector mThreads; + }; + + + +} + +#endif From d52d0d96400c9babc8a52fffa2edf4f101d05d34 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 10 Jun 2015 18:16:02 +0200 Subject: [PATCH 1473/3725] Use the WorkQueue to update skinning --- components/sceneutil/riggeometry.cpp | 124 ++++++++++++++++++++++++--- components/sceneutil/riggeometry.hpp | 19 ++++ 2 files changed, 133 insertions(+), 10 deletions(-) diff --git a/components/sceneutil/riggeometry.cpp b/components/sceneutil/riggeometry.cpp index 2a67c6ce6..50e47e289 100644 --- a/components/sceneutil/riggeometry.cpp +++ b/components/sceneutil/riggeometry.cpp @@ -5,6 +5,8 @@ #include +#include + #include #include "skeleton.hpp" @@ -63,6 +65,8 @@ RigGeometry::RigGeometry() , mFirstFrame(true) , mBoundsFirstFrame(true) { + initWorkQueue(); + setCullCallback(new UpdateRigGeometry); setUpdateCallback(new UpdateRigBounds); setSupportsDisplayList(false); @@ -75,9 +79,21 @@ RigGeometry::RigGeometry(const RigGeometry ©, const osg::CopyOp ©op) , mFirstFrame(copy.mFirstFrame) , mBoundsFirstFrame(copy.mBoundsFirstFrame) { + initWorkQueue(); + setSourceGeometry(copy.mSourceGeometry); } +void RigGeometry::initWorkQueue() +{ + static int numCpu = OpenThreads::GetNumberOfProcessors(); + if (numCpu > 1) + { + static WorkQueue sWorkQueue(1); + mWorkQueue = &sWorkQueue; + } +} + void RigGeometry::setSourceGeometry(osg::ref_ptr sourceGeometry) { mSourceGeometry = sourceGeometry; @@ -198,22 +214,31 @@ void accummulateMatrix(const osg::Matrixf& invBindMatrix, const osg::Matrixf& ma ptrresult[14] += ptr[14] * weight; } -void RigGeometry::update(osg::NodeVisitor* nv) +class UpdateSkinningWorkItem : public WorkItem { - if (!mSkeleton) +public: + UpdateSkinningWorkItem(RigGeometry* rig, const osg::Matrixf& geomToSkelMatrix, RigGeometry::BoneMatrixMap boneMatrices) + : mRig(rig) + , mGeomToSkelMatrix(geomToSkelMatrix) + , mBoneMatrices(boneMatrices) { - if (!initFromParentSkeleton(nv)) - return; } - if (!mSkeleton->getActive() && !mFirstFrame) - return; - mFirstFrame = false; + virtual void doWork() + { + mRig->updateSkinning(mGeomToSkelMatrix, mBoneMatrices); - mSkeleton->updateBoneMatrices(nv); + mTicket->signalDone(); + } - osg::Matrixf geomToSkel = getGeomToSkelMatrix(nv); +private: + RigGeometry* mRig; + osg::Matrixf mGeomToSkelMatrix; + RigGeometry::BoneMatrixMap mBoneMatrices; +}; +void RigGeometry::updateSkinning(const osg::Matrixf& geomToSkel, RigGeometry::BoneMatrixMap boneMatrices) +{ // skinning osg::Vec3Array* positionSrc = static_cast(mSourceGeometry->getVertexArray()); osg::Vec3Array* normalSrc = static_cast(mSourceGeometry->getNormalArray()); @@ -233,7 +258,7 @@ void RigGeometry::update(osg::NodeVisitor* nv) Bone* bone = weightIt->first.first; const osg::Matrix& invBindMatrix = weightIt->first.second; float weight = weightIt->second; - const osg::Matrixf& boneMatrix = bone->mMatrixInSkeletonSpace; + const osg::Matrixf& boneMatrix = boneMatrices.at(bone); accummulateMatrix(invBindMatrix, boneMatrix, weight, resultMat); } resultMat = resultMat * geomToSkel; @@ -250,6 +275,45 @@ void RigGeometry::update(osg::NodeVisitor* nv) normalDst->dirty(); } +void RigGeometry::update(osg::NodeVisitor* nv) +{ + if (!mSkeleton) + { + if (!initFromParentSkeleton(nv)) + return; + } + + if (!mSkeleton->getActive() && !mFirstFrame) + return; + mFirstFrame = false; + + mSkeleton->updateBoneMatrices(nv); + + BoneMatrixMap boneMatrices; + for (BoneSphereMap::const_iterator it = mBoneSphereMap.begin(); it != mBoneSphereMap.end(); ++it) + boneMatrices[it->first] = it->first->mMatrixInSkeletonSpace; + + if (mWorkQueue) + { + // shouldn't happen, unless the CullCallback was a false positive, i.e. the Drawable's parent wasn't culled, but the Drawable *is* culled + if (mWorkTicket) + mWorkTicket->waitTillDone(); + + osg::Matrixf geomToSkel = getGeomToSkelMatrix(nv); + + // actual skinning update moved to a background thread + WorkItem* item = new UpdateSkinningWorkItem(this, geomToSkel, boneMatrices); + // keep the work ticket so we can synchronize in drawImplementation() + mWorkTicket = item->getTicket(); + + mWorkQueue->addWorkItem(item); + } + else + { + updateSkinning(getGeomToSkelMatrix(nv), boneMatrices); + } +} + void RigGeometry::updateBounds(osg::NodeVisitor *nv) { if (!mSkeleton) @@ -279,6 +343,46 @@ void RigGeometry::updateBounds(osg::NodeVisitor *nv) getParent(i)->dirtyBound(); } +void RigGeometry::drawImplementation(osg::RenderInfo &renderInfo) const +{ + if (mWorkTicket) + { + mWorkTicket->waitTillDone(); + mWorkTicket = NULL; + } + osg::Geometry::drawImplementation(renderInfo); +} + +void RigGeometry::compileGLObjects(osg::RenderInfo &renderInfo) const +{ + if (mWorkTicket) + { + mWorkTicket->waitTillDone(); + mWorkTicket = NULL; + } + osg::Geometry::compileGLObjects(renderInfo); +} + +void RigGeometry::accept(osg::PrimitiveFunctor &pf) const +{ + if (mWorkTicket) + { + mWorkTicket->waitTillDone(); + mWorkTicket = NULL; + } + osg::Geometry::accept(pf); +} + +void RigGeometry::accept(osg::PrimitiveIndexFunctor &pf) const +{ + if (mWorkTicket) + { + mWorkTicket->waitTillDone(); + mWorkTicket = NULL; + } + osg::Geometry::accept(pf); +} + osg::Matrixf RigGeometry::getGeomToSkelMatrix(osg::NodeVisitor *nv) { osg::NodePath path; diff --git a/components/sceneutil/riggeometry.hpp b/components/sceneutil/riggeometry.hpp index bd7c586c4..4dd8e8013 100644 --- a/components/sceneutil/riggeometry.hpp +++ b/components/sceneutil/riggeometry.hpp @@ -7,12 +7,16 @@ namespace SceneUtil { + class WorkQueue; + class WorkTicket; + class Skeleton; class Bone; /// @brief Mesh skinning implementation. /// @note A RigGeometry may be attached directly to a Skeleton, or somewhere below a Skeleton. /// Note though that the RigGeometry ignores any transforms below the Skeleton, so the attachment point is not that important. + /// @note You must use a double buffering scheme for queuing the drawing of RigGeometries, see FrameSwitch, or set their DataVariance to DYNAMIC class RigGeometry : public osg::Geometry { public: @@ -41,10 +45,23 @@ namespace SceneUtil // Called automatically by our CullCallback void update(osg::NodeVisitor* nv); + // Called by the worker thread + typedef std::map BoneMatrixMap; + void updateSkinning(const osg::Matrixf& geomToSkelMatrix, BoneMatrixMap boneMatrices); + // Called automatically by our UpdateCallback void updateBounds(osg::NodeVisitor* nv); + // Overriding a bunch of Drawable methods to synchronize access to our vertex array + virtual void drawImplementation(osg::RenderInfo& renderInfo) const; + virtual void compileGLObjects(osg::RenderInfo& renderInfo) const; + virtual void accept(osg::PrimitiveFunctor& pf) const; + virtual void accept(osg::PrimitiveIndexFunctor& pf) const; + private: + mutable osg::ref_ptr mWorkTicket; + WorkQueue* mWorkQueue; + osg::ref_ptr mSourceGeometry; Skeleton* mSkeleton; @@ -70,6 +87,8 @@ namespace SceneUtil bool initFromParentSkeleton(osg::NodeVisitor* nv); osg::Matrixf getGeomToSkelMatrix(osg::NodeVisitor* nv); + + void initWorkQueue(); }; } From 35b2d91fb3bd8f8cc6190c041ab5f8a3ede897ba Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 10 Jun 2015 18:46:51 +0200 Subject: [PATCH 1474/3725] Throw error when failing to create graphics context --- components/sdlutil/sdlcursormanager.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/components/sdlutil/sdlcursormanager.cpp b/components/sdlutil/sdlcursormanager.cpp index 1c5008f7a..a8a48f4f8 100644 --- a/components/sdlutil/sdlcursormanager.cpp +++ b/components/sdlutil/sdlcursormanager.cpp @@ -1,6 +1,7 @@ #include "sdlcursormanager.hpp" #include +#include #include #include @@ -48,6 +49,8 @@ namespace traits->pbuffer = false; _gc = osg::GraphicsContext::createGraphicsContext(traits.get()); + if (!_gc) + throw std::runtime_error("Failed to create graphics context for image decompression"); } if (_gc.valid()) From 9c86d4f8bc19fa180b77fca0b21a66c64e3cbced Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 10 Jun 2015 19:02:33 +0200 Subject: [PATCH 1475/3725] Race condition fix --- components/sceneutil/workqueue.cpp | 5 +++-- components/sceneutil/workqueue.hpp | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/components/sceneutil/workqueue.cpp b/components/sceneutil/workqueue.cpp index a709eae85..9f23fba2d 100644 --- a/components/sceneutil/workqueue.cpp +++ b/components/sceneutil/workqueue.cpp @@ -25,6 +25,7 @@ void WorkTicket::signalDone() WorkItem::WorkItem() : mTicket(new WorkTicket) { + mTicket->setThreadSafeRefUnref(true); } WorkItem::~WorkItem() @@ -73,9 +74,9 @@ WorkQueue::~WorkQueue() } } -WorkTicket* WorkQueue::addWorkItem(WorkItem *item) +osg::ref_ptr WorkQueue::addWorkItem(WorkItem *item) { - WorkTicket* ticket = item->getTicket().get(); + osg::ref_ptr ticket = item->getTicket(); OpenThreads::ScopedLock lock(mMutex); mQueue.push(item); mCondition.signal(); diff --git a/components/sceneutil/workqueue.hpp b/components/sceneutil/workqueue.hpp index 720fbaa68..492bbd090 100644 --- a/components/sceneutil/workqueue.hpp +++ b/components/sceneutil/workqueue.hpp @@ -65,7 +65,7 @@ namespace SceneUtil /// Add a new work item to the back of the queue. /// @par The returned WorkTicket may be used by the caller to wait until the work is complete. - WorkTicket* addWorkItem(WorkItem* item); + osg::ref_ptr addWorkItem(WorkItem* item); /// Get the next work item from the front of the queue. If the queue is empty, waits until a new item is added. /// If the workqueue is in the process of being destroyed, may return NULL. From a1e74a35a279ef0d66dc8bdb9945d592f8c6a6b8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 10 Jun 2015 19:08:56 +0200 Subject: [PATCH 1476/3725] Revert "Use the WorkQueue to update skinning" This reverts commit d52d0d96400c9babc8a52fffa2edf4f101d05d34. Moving to branch --- components/sceneutil/riggeometry.cpp | 124 +++------------------------ components/sceneutil/riggeometry.hpp | 19 ---- 2 files changed, 10 insertions(+), 133 deletions(-) diff --git a/components/sceneutil/riggeometry.cpp b/components/sceneutil/riggeometry.cpp index 50e47e289..2a67c6ce6 100644 --- a/components/sceneutil/riggeometry.cpp +++ b/components/sceneutil/riggeometry.cpp @@ -5,8 +5,6 @@ #include -#include - #include #include "skeleton.hpp" @@ -65,8 +63,6 @@ RigGeometry::RigGeometry() , mFirstFrame(true) , mBoundsFirstFrame(true) { - initWorkQueue(); - setCullCallback(new UpdateRigGeometry); setUpdateCallback(new UpdateRigBounds); setSupportsDisplayList(false); @@ -79,21 +75,9 @@ RigGeometry::RigGeometry(const RigGeometry ©, const osg::CopyOp ©op) , mFirstFrame(copy.mFirstFrame) , mBoundsFirstFrame(copy.mBoundsFirstFrame) { - initWorkQueue(); - setSourceGeometry(copy.mSourceGeometry); } -void RigGeometry::initWorkQueue() -{ - static int numCpu = OpenThreads::GetNumberOfProcessors(); - if (numCpu > 1) - { - static WorkQueue sWorkQueue(1); - mWorkQueue = &sWorkQueue; - } -} - void RigGeometry::setSourceGeometry(osg::ref_ptr sourceGeometry) { mSourceGeometry = sourceGeometry; @@ -214,31 +198,22 @@ void accummulateMatrix(const osg::Matrixf& invBindMatrix, const osg::Matrixf& ma ptrresult[14] += ptr[14] * weight; } -class UpdateSkinningWorkItem : public WorkItem +void RigGeometry::update(osg::NodeVisitor* nv) { -public: - UpdateSkinningWorkItem(RigGeometry* rig, const osg::Matrixf& geomToSkelMatrix, RigGeometry::BoneMatrixMap boneMatrices) - : mRig(rig) - , mGeomToSkelMatrix(geomToSkelMatrix) - , mBoneMatrices(boneMatrices) + if (!mSkeleton) { + if (!initFromParentSkeleton(nv)) + return; } - virtual void doWork() - { - mRig->updateSkinning(mGeomToSkelMatrix, mBoneMatrices); + if (!mSkeleton->getActive() && !mFirstFrame) + return; + mFirstFrame = false; - mTicket->signalDone(); - } + mSkeleton->updateBoneMatrices(nv); -private: - RigGeometry* mRig; - osg::Matrixf mGeomToSkelMatrix; - RigGeometry::BoneMatrixMap mBoneMatrices; -}; + osg::Matrixf geomToSkel = getGeomToSkelMatrix(nv); -void RigGeometry::updateSkinning(const osg::Matrixf& geomToSkel, RigGeometry::BoneMatrixMap boneMatrices) -{ // skinning osg::Vec3Array* positionSrc = static_cast(mSourceGeometry->getVertexArray()); osg::Vec3Array* normalSrc = static_cast(mSourceGeometry->getNormalArray()); @@ -258,7 +233,7 @@ void RigGeometry::updateSkinning(const osg::Matrixf& geomToSkel, RigGeometry::Bo Bone* bone = weightIt->first.first; const osg::Matrix& invBindMatrix = weightIt->first.second; float weight = weightIt->second; - const osg::Matrixf& boneMatrix = boneMatrices.at(bone); + const osg::Matrixf& boneMatrix = bone->mMatrixInSkeletonSpace; accummulateMatrix(invBindMatrix, boneMatrix, weight, resultMat); } resultMat = resultMat * geomToSkel; @@ -275,45 +250,6 @@ void RigGeometry::updateSkinning(const osg::Matrixf& geomToSkel, RigGeometry::Bo normalDst->dirty(); } -void RigGeometry::update(osg::NodeVisitor* nv) -{ - if (!mSkeleton) - { - if (!initFromParentSkeleton(nv)) - return; - } - - if (!mSkeleton->getActive() && !mFirstFrame) - return; - mFirstFrame = false; - - mSkeleton->updateBoneMatrices(nv); - - BoneMatrixMap boneMatrices; - for (BoneSphereMap::const_iterator it = mBoneSphereMap.begin(); it != mBoneSphereMap.end(); ++it) - boneMatrices[it->first] = it->first->mMatrixInSkeletonSpace; - - if (mWorkQueue) - { - // shouldn't happen, unless the CullCallback was a false positive, i.e. the Drawable's parent wasn't culled, but the Drawable *is* culled - if (mWorkTicket) - mWorkTicket->waitTillDone(); - - osg::Matrixf geomToSkel = getGeomToSkelMatrix(nv); - - // actual skinning update moved to a background thread - WorkItem* item = new UpdateSkinningWorkItem(this, geomToSkel, boneMatrices); - // keep the work ticket so we can synchronize in drawImplementation() - mWorkTicket = item->getTicket(); - - mWorkQueue->addWorkItem(item); - } - else - { - updateSkinning(getGeomToSkelMatrix(nv), boneMatrices); - } -} - void RigGeometry::updateBounds(osg::NodeVisitor *nv) { if (!mSkeleton) @@ -343,46 +279,6 @@ void RigGeometry::updateBounds(osg::NodeVisitor *nv) getParent(i)->dirtyBound(); } -void RigGeometry::drawImplementation(osg::RenderInfo &renderInfo) const -{ - if (mWorkTicket) - { - mWorkTicket->waitTillDone(); - mWorkTicket = NULL; - } - osg::Geometry::drawImplementation(renderInfo); -} - -void RigGeometry::compileGLObjects(osg::RenderInfo &renderInfo) const -{ - if (mWorkTicket) - { - mWorkTicket->waitTillDone(); - mWorkTicket = NULL; - } - osg::Geometry::compileGLObjects(renderInfo); -} - -void RigGeometry::accept(osg::PrimitiveFunctor &pf) const -{ - if (mWorkTicket) - { - mWorkTicket->waitTillDone(); - mWorkTicket = NULL; - } - osg::Geometry::accept(pf); -} - -void RigGeometry::accept(osg::PrimitiveIndexFunctor &pf) const -{ - if (mWorkTicket) - { - mWorkTicket->waitTillDone(); - mWorkTicket = NULL; - } - osg::Geometry::accept(pf); -} - osg::Matrixf RigGeometry::getGeomToSkelMatrix(osg::NodeVisitor *nv) { osg::NodePath path; diff --git a/components/sceneutil/riggeometry.hpp b/components/sceneutil/riggeometry.hpp index 4dd8e8013..bd7c586c4 100644 --- a/components/sceneutil/riggeometry.hpp +++ b/components/sceneutil/riggeometry.hpp @@ -7,16 +7,12 @@ namespace SceneUtil { - class WorkQueue; - class WorkTicket; - class Skeleton; class Bone; /// @brief Mesh skinning implementation. /// @note A RigGeometry may be attached directly to a Skeleton, or somewhere below a Skeleton. /// Note though that the RigGeometry ignores any transforms below the Skeleton, so the attachment point is not that important. - /// @note You must use a double buffering scheme for queuing the drawing of RigGeometries, see FrameSwitch, or set their DataVariance to DYNAMIC class RigGeometry : public osg::Geometry { public: @@ -45,23 +41,10 @@ namespace SceneUtil // Called automatically by our CullCallback void update(osg::NodeVisitor* nv); - // Called by the worker thread - typedef std::map BoneMatrixMap; - void updateSkinning(const osg::Matrixf& geomToSkelMatrix, BoneMatrixMap boneMatrices); - // Called automatically by our UpdateCallback void updateBounds(osg::NodeVisitor* nv); - // Overriding a bunch of Drawable methods to synchronize access to our vertex array - virtual void drawImplementation(osg::RenderInfo& renderInfo) const; - virtual void compileGLObjects(osg::RenderInfo& renderInfo) const; - virtual void accept(osg::PrimitiveFunctor& pf) const; - virtual void accept(osg::PrimitiveIndexFunctor& pf) const; - private: - mutable osg::ref_ptr mWorkTicket; - WorkQueue* mWorkQueue; - osg::ref_ptr mSourceGeometry; Skeleton* mSkeleton; @@ -87,8 +70,6 @@ namespace SceneUtil bool initFromParentSkeleton(osg::NodeVisitor* nv); osg::Matrixf getGeomToSkelMatrix(osg::NodeVisitor* nv); - - void initWorkQueue(); }; } From b5099324d19e79359a05bff7dacddc17f12f6dc4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 10 Jun 2015 20:35:59 +0200 Subject: [PATCH 1477/3725] Enable ParticleSystem's FreezeOnCull, big speed-up in Vivec --- components/nifosg/nifloader.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index fcba9893d..2c409ac96 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -822,6 +822,8 @@ namespace NifOsg partsys->getDefaultParticleTemplate().setColorRange(osgParticle::rangev4(osg::Vec4f(1.f,1.f,1.f,1.f), osg::Vec4f(1.f,1.f,1.f,1.f))); partsys->getDefaultParticleTemplate().setAlphaRange(osgParticle::rangef(1.f, 1.f)); + partsys->setFreezeOnCull(true); + osg::ref_ptr emitter = handleParticleEmitter(partctrl); emitter->setParticleSystem(partsys); emitter->setReferenceFrame(osgParticle::ParticleProcessor::RELATIVE_RF); From 8d6620b0745991a46d73077de171e9a4b51b021e Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 11 Jun 2015 02:37:49 +0200 Subject: [PATCH 1478/3725] Assign an initial bounding box to particle systems --- components/nifosg/nifloader.cpp | 4 ++++ components/resource/scenemanager.cpp | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 2c409ac96..b95eeebfc 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -749,6 +749,10 @@ namespace NifOsg created->setSizeRange(osgParticle::rangef(size, size)); } + + osg::BoundingBox box; + box.expandBy(osg::BoundingSphere(osg::Vec3(0,0,0), particledata->radius)); + partsys->setInitialBound(box); } static osg::ref_ptr handleParticleEmitter(const Nif::NiParticleSystemController* partctrl) diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index 8de08bd9d..bb4c57e4c 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -14,6 +14,7 @@ #include #include +#include namespace { @@ -61,6 +62,13 @@ namespace { partsys->getParticle(i)->transformPositionVelocity(worldMat); } + + // transform initial bounds to worldspace + osg::BoundingSphere sphere(partsys->getInitialBound()); + SceneUtil::transformBoundingSphere(worldMat, sphere); + osg::BoundingBox box; + box.expandBy(sphere); + partsys->setInitialBound(box); } }; From 6d7e6cd30c3e6a8b20a59f657e90ac91506eccab Mon Sep 17 00:00:00 2001 From: dteviot Date: Thu, 11 Jun 2015 18:28:31 +1200 Subject: [PATCH 1479/3725] AiTravel logic merged into AiPackage. --- apps/openmw/mwmechanics/aipackage.cpp | 9 ++++- apps/openmw/mwmechanics/aipackage.hpp | 4 ++ apps/openmw/mwmechanics/aitravel.cpp | 55 ++++++--------------------- apps/openmw/mwmechanics/aitravel.hpp | 3 ++ 4 files changed, 25 insertions(+), 46 deletions(-) diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index 52a975320..802a7723e 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -30,9 +30,9 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, ESM::Pathgrid::Po ESM::Position pos = actor.getRefData().getPosition(); //position of the actor /// Stops the actor when it gets too close to a unloaded cell + const ESM::Cell *cell = actor.getCell()->getCell(); { MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); - const ESM::Cell *cell = actor.getCell()->getCell(); Movement &movement = actor.getClass().getMovementSettings(actor); //Ensure pursuer doesn't leave loaded cells @@ -67,7 +67,7 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, ESM::Pathgrid::Po //*********************** if(mTimer > 0.25) { - if(distance(mPrevDest, dest) > 10) { //Only rebuild path if it's moved + if (doesPathNeedRecalc(dest, cell)) { //Only rebuild path if it's moved mPathFinder.buildPath(start, dest, actor.getCell(), true); //Rebuild path, in case the target has moved mPrevDest = dest; } @@ -123,3 +123,8 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, ESM::Pathgrid::Po return false; } + +bool MWMechanics::AiPackage::doesPathNeedRecalc(ESM::Pathgrid::Point dest, const ESM::Cell *cell) +{ + return distance(mPrevDest, dest) > 10; +} \ No newline at end of file diff --git a/apps/openmw/mwmechanics/aipackage.hpp b/apps/openmw/mwmechanics/aipackage.hpp index 179ae440b..0370072a4 100644 --- a/apps/openmw/mwmechanics/aipackage.hpp +++ b/apps/openmw/mwmechanics/aipackage.hpp @@ -4,6 +4,8 @@ #include "pathfinding.hpp" #include +#include "../mwworld/cellstore.hpp" + #include "obstacle.hpp" #include "aistate.hpp" @@ -71,6 +73,8 @@ namespace MWMechanics /** \return If the actor has arrived at his destination **/ bool pathTo(const MWWorld::Ptr& actor, ESM::Pathgrid::Point dest, float duration); + virtual bool doesPathNeedRecalc(ESM::Pathgrid::Point dest, const ESM::Cell *cell); + // TODO: all this does not belong here, move into temporary storage PathFinder mPathFinder; ObstacleCheck mObstacleCheck; diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index 2824e2c6c..4f4d4c79f 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -51,64 +51,31 @@ namespace MWMechanics bool AiTravel::execute (const MWWorld::Ptr& actor, AiState& state, float duration) { - MWBase::World *world = MWBase::Environment::get().getWorld(); ESM::Position pos = actor.getRefData().getPosition(); - Movement &movement = actor.getClass().getMovementSettings(actor); - const ESM::Cell *cell = actor.getCell()->getCell(); actor.getClass().getCreatureStats(actor).setMovementFlag(CreatureStats::Flag_Run, false); - actor.getClass().getCreatureStats(actor).setDrawState(DrawState_Nothing); - MWWorld::Ptr player = world->getPlayerPtr(); - if(cell->mData.mX != player.getCell()->getCell()->mData.mX) - { - int sideX = PathFinder::sgn(cell->mData.mX - player.getCell()->getCell()->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)) - { - movement.mPosition[1] = 0; - return false; - } - } - if(cell->mData.mY != player.getCell()->getCell()->mData.mY) - { - int sideY = PathFinder::sgn(cell->mData.mY - player.getCell()->getCell()->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)) - { - movement.mPosition[1] = 0; - return false; - } - } - if (!isWithinMaxRange(Ogre::Vector3(mX, mY, mZ), Ogre::Vector3(pos.pos))) return false; - bool cellChange = cell->mData.mX != mCellX || cell->mData.mY != mCellY; - if(!mPathFinder.isPathConstructed() || cellChange) + if (pathTo(actor, ESM::Pathgrid::Point(static_cast(mX), static_cast(mY), static_cast(mZ)), duration)) { - mCellX = cell->mData.mX; - mCellY = cell->mData.mY; - - ESM::Pathgrid::Point dest(static_cast(mX), static_cast(mY), static_cast(mZ)); - - ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(pos)); - - mPathFinder.buildPath(start, dest, actor.getCell(), true); + actor.getClass().getMovementSettings(actor).mPosition[1] = 0; + return true; } + return false; + } - if(mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1])) + bool AiTravel::doesPathNeedRecalc(ESM::Pathgrid::Point dest, const ESM::Cell *cell) + { + bool cellChange = cell->mData.mX != mCellX || cell->mData.mY != mCellY; + if (!mPathFinder.isPathConstructed() || cellChange) { - movement.mPosition[1] = 0; + mCellX = cell->mData.mX; + mCellY = cell->mData.mY; return true; } - - zTurn(actor, Ogre::Degree(mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]))); - movement.mPosition[1] = 1; - return false; } diff --git a/apps/openmw/mwmechanics/aitravel.hpp b/apps/openmw/mwmechanics/aitravel.hpp index c2732e3aa..a5a4577e6 100644 --- a/apps/openmw/mwmechanics/aitravel.hpp +++ b/apps/openmw/mwmechanics/aitravel.hpp @@ -34,6 +34,9 @@ namespace MWMechanics virtual int getTypeId() const; + protected: + virtual bool doesPathNeedRecalc(ESM::Pathgrid::Point dest, const ESM::Cell *cell); + private: float mX; float mY; From cb8ca2f03a751373b81e15f75b05b691bb2dee58 Mon Sep 17 00:00:00 2001 From: dteviot Date: Thu, 11 Jun 2015 18:31:35 +1200 Subject: [PATCH 1480/3725] Moved logic for building a Sync'ed path from AiCombat to PathFinding. Is now used by AiFollow, which should fix "running in circles" bug caused when recalc a path and closest way point is the one NPC has just passed. --- apps/openmw/mwmechanics/aicombat.cpp | 50 ++++++++++--------------- apps/openmw/mwmechanics/aicombat.hpp | 3 ++ apps/openmw/mwmechanics/aipackage.cpp | 2 +- apps/openmw/mwmechanics/pathfinding.cpp | 38 ++++++++++++------- apps/openmw/mwmechanics/pathfinding.hpp | 12 +++--- 5 files changed, 54 insertions(+), 51 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 649f259d9..8f43c6280 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -677,44 +677,32 @@ namespace MWMechanics return false; } - void AiCombat::buildNewPath(const MWWorld::Ptr& actor, const MWWorld::Ptr& target) + bool AiCombat::doesPathNeedRecalc(ESM::Pathgrid::Point dest, const ESM::Cell *cell) { - Ogre::Vector3 newPathTarget = Ogre::Vector3(target.getRefData().getPosition().pos); - - float dist; - - if(!mPathFinder.getPath().empty()) + if (!mPathFinder.getPath().empty()) + { + Ogre::Vector3 currPathTarget(PathFinder::MakeOgreVector3(mPathFinder.getPath().back())); + Ogre::Vector3 newPathTarget = PathFinder::MakeOgreVector3(dest); + float dist = (newPathTarget - currPathTarget).length(); + float targetPosThreshold = (cell->isExterior()) ? 300.0f : 100.0f; + return dist > targetPosThreshold; + } + else { - ESM::Pathgrid::Point lastPt = mPathFinder.getPath().back(); - Ogre::Vector3 currPathTarget(PathFinder::MakeOgreVector3(lastPt)); - dist = (newPathTarget - currPathTarget).length(); + // necessarily construct a new path + return true; } - else dist = 1e+38F; // necessarily construct a new path + } - float targetPosThreshold = (actor.getCell()->getCell()->isExterior())? 300.0f : 100.0f; + void AiCombat::buildNewPath(const MWWorld::Ptr& actor, const MWWorld::Ptr& target) + { + ESM::Pathgrid::Point newPathTarget = PathFinder::MakePathgridPoint(target.getRefData().getPosition()); //construct new path only if target has moved away more than on [targetPosThreshold] - if(dist > targetPosThreshold) + if (doesPathNeedRecalc(newPathTarget, actor.getCell()->getCell())) { - ESM::Position pos = actor.getRefData().getPosition(); - - ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(pos)); - - ESM::Pathgrid::Point dest(PathFinder::MakePathgridPoint(newPathTarget)); - - if(!mPathFinder.isPathConstructed()) - mPathFinder.buildPath(start, dest, actor.getCell(), false); - else - { - PathFinder newPathFinder; - newPathFinder.buildPath(start, dest, actor.getCell(), false); - - if(!mPathFinder.getPath().empty()) - { - newPathFinder.syncStart(mPathFinder.getPath()); - mPathFinder = newPathFinder; - } - } + ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(actor.getRefData().getPosition())); + mPathFinder.buildSyncedPath(start, newPathTarget, actor.getCell(), false); } } diff --git a/apps/openmw/mwmechanics/aicombat.hpp b/apps/openmw/mwmechanics/aicombat.hpp index 307df3872..8248975b5 100644 --- a/apps/openmw/mwmechanics/aicombat.hpp +++ b/apps/openmw/mwmechanics/aicombat.hpp @@ -53,6 +53,9 @@ namespace MWMechanics virtual void writeState(ESM::AiSequence::AiSequence &sequence) const; + protected: + virtual bool doesPathNeedRecalc(ESM::Pathgrid::Point dest, const ESM::Cell *cell); + private: int mTargetActorId; diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index 802a7723e..216bf7b09 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -68,7 +68,7 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, ESM::Pathgrid::Po if(mTimer > 0.25) { if (doesPathNeedRecalc(dest, cell)) { //Only rebuild path if it's moved - mPathFinder.buildPath(start, dest, actor.getCell(), true); //Rebuild path, in case the target has moved + mPathFinder.buildSyncedPath(start, dest, actor.getCell(), true); //Rebuild path, in case the target has moved mPrevDest = dest; } diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index 5795f818a..980de1bad 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -301,23 +301,35 @@ namespace MWMechanics return false; } - // used by AiCombat, see header for the rationale - bool PathFinder::syncStart(const std::list &path) + // see header for the rationale + void PathFinder::buildSyncedPath(const ESM::Pathgrid::Point &startPoint, + const ESM::Pathgrid::Point &endPoint, + const MWWorld::CellStore* cell, + bool allowShortcuts) { if (mPath.size() < 2) - return false; //nothing to pop - - std::list::const_iterator oldStart = path.begin(); - std::list::iterator iter = ++mPath.begin(); - - if( (*iter).mX == oldStart->mX - && (*iter).mY == oldStart->mY - && (*iter).mZ == oldStart->mZ) { - mPath.pop_front(); - return true; + // if path has one point, then it's the destination. + // don't need to worry about bad path for this case + buildPath(startPoint, endPoint, cell, allowShortcuts); + } + else + { + const ESM::Pathgrid::Point oldStart(*getPath().begin()); + buildPath(startPoint, endPoint, cell, allowShortcuts); + if (mPath.size() >= 2) + { + // if 2nd waypoint of new path == 1st waypoint of old, + // delete 1st waypoint of new path. + std::list::iterator iter = ++mPath.begin(); + if (iter->mX == oldStart.mX + && iter->mY == oldStart.mY + && iter->mZ == oldStart.mZ) + { + mPath.pop_front(); + } + } } - return false; } } diff --git a/apps/openmw/mwmechanics/pathfinding.hpp b/apps/openmw/mwmechanics/pathfinding.hpp index f48de6624..0f52a6e19 100644 --- a/apps/openmw/mwmechanics/pathfinding.hpp +++ b/apps/openmw/mwmechanics/pathfinding.hpp @@ -63,13 +63,13 @@ namespace MWMechanics /** Synchronize new path with old one to avoid visiting 1 waypoint 2 times @note - If the first point is chosen as the nearest one - the situation can occur when the 1st point of the new path is undesirable - (i.e. the 2nd point of new path == the 1st point of old path). - @param path - old path - @return true if such point was found and deleted + BuildPath() takes closest PathGrid point to NPC as first point of path. + This is undesireable if NPC has just passed a Pathgrid point, as this + makes the 2nd point of the new path == the 1st point of old path. + Which results in NPC "running in a circle" back to the just passed waypoint. */ - bool syncStart(const std::list &path); + void buildSyncedPath(const ESM::Pathgrid::Point &startPoint, const ESM::Pathgrid::Point &endPoint, + const MWWorld::CellStore* cell, bool allowShortcuts = true); void addPointToPath(ESM::Pathgrid::Point &point) { From c7493eb45c41637b623737d0c23828daff629af5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 11 Jun 2015 16:14:51 +0200 Subject: [PATCH 1481/3725] Fix bug with invisibility effect for meshes w/ vertex colors --- apps/openmw/mwrender/npcanimation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 7de3e1d5a..21ec8d535 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -1006,7 +1006,7 @@ void NpcAnimation::setAlpha(float alpha) // FIXME: overriding diffuse/ambient/emissive colors osg::Material* material (new osg::Material); - material->setColorMode(osg::Material::DIFFUSE); + material->setColorMode(osg::Material::OFF); material->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(1,1,1,alpha)); material->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(1,1,1,1)); stateset->setAttributeAndModes(material, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); From c94c87d40942ae63ebb5c8489019d32c823989fc Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 11 Jun 2015 16:22:09 +0200 Subject: [PATCH 1482/3725] Attach effects to the insert node instead of the object root (Bug #2654) --- apps/openmw/mwrender/animation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index d92e57f19..261ec6c5b 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1060,7 +1060,7 @@ namespace MWRender params.mModelName = model; osg::ref_ptr parentNode; if (bonename.empty()) - parentNode = mObjectRoot->asGroup(); + parentNode = mInsert; else { NodeMap::iterator found = mNodeMap.find(Misc::StringUtils::lowerCase(bonename)); From f81c3bcd6d3d7777fe1b281d3ab6cee9f2984042 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 11 Jun 2015 16:40:26 +0200 Subject: [PATCH 1483/3725] Fix for broken InitWorldSpaceParticles on projectile effects --- apps/openmw/mwworld/projectilemanager.cpp | 20 +++++++------------- apps/openmw/mwworld/projectilemanager.hpp | 2 +- 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 84d86fba7..d0a5de5b2 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -40,10 +40,12 @@ namespace MWWorld } - void ProjectileManager::createModel(State &state, const std::string &model) + void ProjectileManager::createModel(State &state, const std::string &model, const osg::Vec3f& pos, const osg::Quat& orient) { state.mNode = new osg::PositionAttitudeTransform; state.mNode->setNodeMask(MWRender::Mask_Effect); + state.mNode->setPosition(pos); + state.mNode->setAttitude(orient); mParent->addChild(state.mNode); mResourceSystem->getSceneManager()->createInstance(model, state.mNode); @@ -105,9 +107,7 @@ namespace MWWorld MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), model); MWWorld::Ptr ptr = ref.getPtr(); - createModel(state, ptr.getClass().getModel(ptr)); - state.mNode->setPosition(pos); - state.mNode->setAttitude(orient); + createModel(state, ptr.getClass().getModel(ptr), pos, orient); MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); state.mSound = sndMgr->playManualSound3D(pos, sound, 1.0f, 1.0f, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_Loop); @@ -127,9 +127,7 @@ namespace MWWorld MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), projectile.getCellRef().getRefId()); MWWorld::Ptr ptr = ref.getPtr(); - createModel(state, ptr.getClass().getModel(ptr)); - state.mNode->setPosition(pos); - state.mNode->setAttitude(orient); + createModel(state, ptr.getClass().getModel(ptr), pos, orient); mProjectiles.push_back(state); } @@ -342,9 +340,7 @@ namespace MWWorld return true; } - createModel(state, model); - state.mNode->setPosition(osg::Vec3f(esm.mPosition)); - state.mNode->setAttitude(osg::Quat(esm.mOrientation)); + createModel(state, model, osg::Vec3f(esm.mPosition), osg::Quat(esm.mOrientation)); mProjectiles.push_back(state); return true; @@ -375,9 +371,7 @@ namespace MWWorld return true; } - createModel(state, model); - state.mNode->setPosition(osg::Vec3f(esm.mPosition)); - state.mNode->setAttitude(osg::Quat(esm.mOrientation)); + createModel(state, model, osg::Vec3f(esm.mPosition), osg::Quat(esm.mOrientation)); MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); state.mSound = sndMgr->playManualSound3D(esm.mPosition, esm.mSound, 1.0f, 1.0f, diff --git a/apps/openmw/mwworld/projectilemanager.hpp b/apps/openmw/mwworld/projectilemanager.hpp index f42bc040f..68e408149 100644 --- a/apps/openmw/mwworld/projectilemanager.hpp +++ b/apps/openmw/mwworld/projectilemanager.hpp @@ -116,7 +116,7 @@ namespace MWWorld void moveProjectiles(float dt); void moveMagicBolts(float dt); - void createModel (State& state, const std::string& model); + void createModel (State& state, const std::string& model, const osg::Vec3f& pos, const osg::Quat& orient); void update (State& state, float duration); }; From cdc47fa874ec391384728fae082d822b0cd8ee09 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 11 Jun 2015 17:59:49 +0200 Subject: [PATCH 1484/3725] Remove BulletNifLoader dependency on keyframe manager This will make threaded loading easier. --- components/nifbullet/bulletnifloader.cpp | 23 +++++++++++++-------- components/nifbullet/bulletnifloader.hpp | 4 ---- components/nifbullet/bulletshapemanager.cpp | 13 ------------ 3 files changed, 14 insertions(+), 26 deletions(-) diff --git a/components/nifbullet/bulletnifloader.cpp b/components/nifbullet/bulletnifloader.cpp index 33c8c449d..495c6ba50 100644 --- a/components/nifbullet/bulletnifloader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -66,11 +66,6 @@ BulletNifLoader::~BulletNifLoader() { } -void BulletNifLoader::setAnimatedNodes(const std::set &animatedNodes) -{ - mAnimatedNodes = animatedNodes; -} - osg::ref_ptr BulletNifLoader::load(const Nif::NIFFilePtr nif) { mShape = new BulletShape; @@ -110,7 +105,20 @@ osg::ref_ptr BulletNifLoader::load(const Nif::NIFFilePtr nif) else { bool autogenerated = hasAutoGeneratedCollision(node); - handleNode(node, 0, autogenerated, false, autogenerated); + bool isAnimated = false; + + // files with the name convention xmodel.nif usually have keyframes stored in a separate file xmodel.kf (see Animation::addAnimSource). + // assume all nodes in the file will be animated + std::string filename = nif->getFilename(); + size_t slashpos = filename.find_last_of("/\\"); + if (slashpos == std::string::npos) + slashpos = 0; + if (slashpos+1 < filename.size() && (filename[slashpos+1] == 'x' || filename[slashpos+1] == 'X')) + { + isAnimated = true; + } + + handleNode(node, 0, autogenerated, isAnimated, autogenerated); if (mCompoundShape) { @@ -192,9 +200,6 @@ void BulletNifLoader::handleNode(const Nif::Node *node, int flags, && (node->controller->flags & Nif::NiNode::ControllerFlag_Active)) isAnimated = true; - if (mAnimatedNodes.find(node->name) != mAnimatedNodes.end()) - isAnimated = true; - isCollisionNode = isCollisionNode || (node->recType == Nif::RC_RootCollisionNode); // Don't collide with AvoidNode shapes diff --git a/components/nifbullet/bulletnifloader.hpp b/components/nifbullet/bulletnifloader.hpp index 0865b134a..52428cc74 100644 --- a/components/nifbullet/bulletnifloader.hpp +++ b/components/nifbullet/bulletnifloader.hpp @@ -91,8 +91,6 @@ public: abort(); } - void setAnimatedNodes(const std::set& animatedNodes); - osg::ref_ptr load(const Nif::NIFFilePtr file); private: @@ -108,8 +106,6 @@ private: btTriangleMesh* mStaticMesh; - std::set mAnimatedNodes; - osg::ref_ptr mShape; }; diff --git a/components/nifbullet/bulletshapemanager.cpp b/components/nifbullet/bulletshapemanager.cpp index e53a351cf..57848ab81 100644 --- a/components/nifbullet/bulletshapemanager.cpp +++ b/components/nifbullet/bulletshapemanager.cpp @@ -34,20 +34,7 @@ osg::ref_ptr BulletShapeManager::createInstance(const std:: // TODO: add support for non-NIF formats - std::string kfname = normalized; - if(kfname.size() > 4 && kfname.compare(kfname.size()-4, 4, ".nif") == 0) - kfname.replace(kfname.size()-4, 4, ".kf"); - std::set animatedNodes; - if (mVFS->exists(kfname)) - { - osg::ref_ptr keyframes = mSceneManager->getKeyframes(kfname); - for (NifOsg::KeyframeHolder::KeyframeControllerMap::const_iterator it = keyframes->mKeyframeControllers.begin(); - it != keyframes->mKeyframeControllers.end(); ++it) - animatedNodes.insert(it->first); - } - BulletNifLoader loader; - loader.setAnimatedNodes(animatedNodes); // might be worth sharing NIFFiles with SceneManager in some way shape = loader.load(Nif::NIFFilePtr(new Nif::NIFFile(file, normalized))); From 712cef36b0a9e920ddd203b4b1e1d94e56e49767 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 11 Jun 2015 18:01:00 +0200 Subject: [PATCH 1485/3725] Minor cleanup --- apps/openmw/mwphysics/physicssystem.cpp | 2 +- components/nifbullet/bulletshapemanager.cpp | 5 +---- components/nifbullet/bulletshapemanager.hpp | 4 +--- 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 6be42affb..2709ced4f 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -594,7 +594,7 @@ namespace MWPhysics // --------------------------------------------------------------- PhysicsSystem::PhysicsSystem(Resource::ResourceSystem* resourceSystem, osg::ref_ptr parentNode) - : mShapeManager(new NifBullet::BulletShapeManager(resourceSystem->getVFS(), resourceSystem->getSceneManager())) + : mShapeManager(new NifBullet::BulletShapeManager(resourceSystem->getVFS())) , mDebugDrawEnabled(false) , mTimeAccum(0.0f) , mWaterHeight(0) diff --git a/components/nifbullet/bulletshapemanager.cpp b/components/nifbullet/bulletshapemanager.cpp index 57848ab81..6acfdd408 100644 --- a/components/nifbullet/bulletshapemanager.cpp +++ b/components/nifbullet/bulletshapemanager.cpp @@ -4,14 +4,11 @@ #include -#include - namespace NifBullet { -BulletShapeManager::BulletShapeManager(const VFS::Manager* vfs, Resource::SceneManager* sceneManager) +BulletShapeManager::BulletShapeManager(const VFS::Manager* vfs) : mVFS(vfs) - , mSceneManager(sceneManager) { } diff --git a/components/nifbullet/bulletshapemanager.hpp b/components/nifbullet/bulletshapemanager.hpp index 9db674d6d..6b9ec60de 100644 --- a/components/nifbullet/bulletshapemanager.hpp +++ b/components/nifbullet/bulletshapemanager.hpp @@ -25,15 +25,13 @@ namespace NifBullet class BulletShapeManager { public: - BulletShapeManager(const VFS::Manager* vfs, Resource::SceneManager* sceneManager); + BulletShapeManager(const VFS::Manager* vfs); ~BulletShapeManager(); osg::ref_ptr createInstance(const std::string& name); private: const VFS::Manager* mVFS; - // need to load keyframes to know what nodes are going to be animated - Resource::SceneManager* mSceneManager; typedef std::map > Index; Index mIndex; From 6051c47eef9f88f65412b9f82f3fee7a895866f3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 11 Jun 2015 22:36:19 +0200 Subject: [PATCH 1486/3725] Fix for incorrect QString -> path conversion --- apps/opencs/editor.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 84849cbbb..efd7cf4ec 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -307,12 +307,12 @@ bool CS::Editor::makeIPCServer() mServer->close(); fullPath.remove(QRegExp("dummy$")); fullPath += mIpcServerName; - if(boost::filesystem::exists(fullPath.toStdString().c_str())) + if(boost::filesystem::exists(fullPath.toUtf8().constData())) { // TODO: compare pid of the current process with that in the file std::cout << "Detected unclean shutdown." << std::endl; // delete the stale file - if(remove(fullPath.toStdString().c_str())) + if(remove(fullPath.toUtf8().constData())) std::cerr << "ERROR removing stale connection file" << std::endl; } } From e257c915bfc75db5474d0e31d307664bbe745e60 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Fri, 12 Jun 2015 00:00:23 +0300 Subject: [PATCH 1487/3725] Add color picker popup to choose color --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/view/widget/coloreditor.cpp | 111 ++++++++++++++++++ apps/opencs/view/widget/coloreditor.hpp | 43 +++++++ apps/opencs/view/widget/colorpickerpopup.cpp | 63 ++++++++++ apps/opencs/view/widget/colorpickerpopup.hpp | 31 +++++ .../opencs/view/world/colorpickerdelegate.cpp | 8 +- 6 files changed, 253 insertions(+), 5 deletions(-) create mode 100644 apps/opencs/view/widget/coloreditor.cpp create mode 100644 apps/opencs/view/widget/coloreditor.hpp create mode 100644 apps/opencs/view/widget/colorpickerpopup.cpp create mode 100644 apps/opencs/view/widget/colorpickerpopup.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index f8f3ea036..83a20ecaa 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -75,7 +75,7 @@ opencs_units_noqt (view/world opencs_units (view/widget scenetoolbar scenetool scenetoolmode pushbutton scenetooltoggle scenetoolrun modebutton - scenetooltoggle2 completerpopup coloreditbutton + scenetooltoggle2 completerpopup coloreditor colorpickerpopup ) opencs_units (view/render diff --git a/apps/opencs/view/widget/coloreditor.cpp b/apps/opencs/view/widget/coloreditor.cpp new file mode 100644 index 000000000..bab98fcd5 --- /dev/null +++ b/apps/opencs/view/widget/coloreditor.cpp @@ -0,0 +1,111 @@ +#include "coloreditor.hpp" + +#include +#include +#include +#include +#include +#include + +#include "colorpickerpopup.hpp" + +CSVWidget::ColorEditor::ColorEditor(const QColor &color, + const QSize &coloredRectSize, + QWidget *parent) + : QPushButton(parent), + mColor(color), + mColoredRectSize(coloredRectSize), + mColorPicker(new ColorPickerPopup(this)) +{ + setCheckable(true); + connect(this, SIGNAL(clicked()), this, SLOT(showPicker())); + connect(mColorPicker, SIGNAL(hid()), this, SLOT(pickerHid())); + connect(mColorPicker, SIGNAL(colorChanged(const QColor &)), this, SLOT(pickerColorChanged(const QColor &))); +} + +void CSVWidget::ColorEditor::paintEvent(QPaintEvent *event) +{ + QPushButton::paintEvent(event); + + QRect buttonRect = rect(); + QRect coloredRect(buttonRect.x() + (buttonRect.width() - mColoredRectSize.width()) / 2, + buttonRect.y() + (buttonRect.height() - mColoredRectSize.height()) / 2, + mColoredRectSize.width(), + mColoredRectSize.height()); + QPainter painter(this); + painter.fillRect(coloredRect, mColor); +} + +QColor CSVWidget::ColorEditor::color() const +{ + return mColor; +} + +void CSVWidget::ColorEditor::setColor(const QColor &color) +{ + mColor = color; +} + +void CSVWidget::ColorEditor::setColoredRectSize(const QSize &size) +{ + mColoredRectSize = size; +} + +void CSVWidget::ColorEditor::showPicker() +{ + if (isChecked()) + { + mColorPicker->showPicker(calculatePopupPosition(), mColor); + } + else + { + mColorPicker->hide(); + } +} + +void CSVWidget::ColorEditor::pickerHid() +{ + // If the popup is hidden and mouse isn't above the editor, + // reset the editor checked state manually + QPoint globalEditorPosition = mapToGlobal(QPoint(0, 0)); + QRect globalEditorRect(globalEditorPosition, geometry().size()); + if (!globalEditorRect.contains(QCursor::pos())) + { + setChecked(false); + } +} + +void CSVWidget::ColorEditor::pickerColorChanged(const QColor &color) +{ + mColor = color; + update(); +} + +QPoint CSVWidget::ColorEditor::calculatePopupPosition() +{ + QRect editorGeometry = geometry(); + QRect popupGeometry = mColorPicker->geometry(); + QRect screenGeometry = QApplication::desktop()->screenGeometry(); + + // Center the popup horizontally relative to the editor + int localPopupX = (editorGeometry.width() - popupGeometry.width()) / 2; + // Popup position need to be specified in global coords + QPoint popupPosition = mapToGlobal(QPoint(localPopupX, editorGeometry.height())); + + // Make sure that the popup isn't out of the screen + if (popupPosition.x() < screenGeometry.left()) + { + popupPosition.setX(screenGeometry.left() + 1); + } + else if (popupPosition.x() + popupGeometry.width() > screenGeometry.right()) + { + popupPosition.setX(screenGeometry.right() - popupGeometry.width() - 1); + } + if (popupPosition.y() + popupGeometry.height() > screenGeometry.bottom()) + { + // Place the popup above the editor + popupPosition.setY(popupPosition.y() - popupGeometry.height() - editorGeometry.height() - 1); + } + + return popupPosition; +} diff --git a/apps/opencs/view/widget/coloreditor.hpp b/apps/opencs/view/widget/coloreditor.hpp new file mode 100644 index 000000000..a0fa497b6 --- /dev/null +++ b/apps/opencs/view/widget/coloreditor.hpp @@ -0,0 +1,43 @@ +#ifndef CSV_WIDGET_COLOREDITOR_HPP +#define CSV_WIDGET_COLOREDITOR_HPP + +#include + +class QColor; +class QPoint; +class QSize; + +namespace CSVWidget +{ + class ColorPickerPopup; + + class ColorEditor : public QPushButton + { + Q_OBJECT + + QColor mColor; + QSize mColoredRectSize; + ColorPickerPopup *mColorPicker; + + QPoint calculatePopupPosition(); + + public: + ColorEditor(const QColor &color, + const QSize &coloredRectSize, + QWidget *parent = 0); + + QColor color() const; + void setColor(const QColor &color); + void setColoredRectSize(const QSize &size); + + protected: + void paintEvent(QPaintEvent *event); + + private slots: + void showPicker(); + void pickerHid(); + void pickerColorChanged(const QColor &color); + }; +} + +#endif diff --git a/apps/opencs/view/widget/colorpickerpopup.cpp b/apps/opencs/view/widget/colorpickerpopup.cpp new file mode 100644 index 000000000..dd53f1bec --- /dev/null +++ b/apps/opencs/view/widget/colorpickerpopup.cpp @@ -0,0 +1,63 @@ +#include "colorpickerpopup.hpp" + +#include +#include +#include +#include + +CSVWidget::ColorPickerPopup::ColorPickerPopup(QWidget *parent) + : QFrame(parent) +{ + setWindowFlags(Qt::Popup); + setFrameStyle(QFrame::Box | QFrame::Plain); + hide(); + + mColorPicker = new QColorDialog(this); + mColorPicker->setWindowFlags(Qt::Widget); + mColorPicker->setOptions(QColorDialog::NoButtons | QColorDialog::DontUseNativeDialog); + mColorPicker->installEventFilter(this); + mColorPicker->open(); + connect(mColorPicker, + SIGNAL(currentColorChanged(const QColor &)), + this, + SIGNAL(colorChanged(const QColor &))); + + QVBoxLayout *layout = new QVBoxLayout(this); + layout->addWidget(mColorPicker); + layout->setAlignment(Qt::AlignTop | Qt::AlignLeft); + layout->setContentsMargins(0, 0, 0, 0); + setLayout(layout); + setFixedSize(mColorPicker->size()); +} + +void CSVWidget::ColorPickerPopup::showPicker(const QPoint &position, const QColor &initialColor) +{ + QRect geometry = this->geometry(); + geometry.moveTo(position); + setGeometry(geometry); + + mColorPicker->setCurrentColor(initialColor); + show(); +} + +void CSVWidget::ColorPickerPopup::hideEvent(QHideEvent *event) +{ + QFrame::hideEvent(event); + emit hid(); +} + +bool CSVWidget::ColorPickerPopup::eventFilter(QObject *object, QEvent *event) +{ + if (object == mColorPicker && event->type() == QEvent::KeyPress) + { + QKeyEvent *keyEvent = static_cast(event); + // Prevent QColorDialog from closing when Escape is pressed. + // Instead, hide the popup. + if (keyEvent->key() == Qt::Key_Escape) + { + hide(); + return true; + } + } + return QFrame::eventFilter(object, event); +} diff --git a/apps/opencs/view/widget/colorpickerpopup.hpp b/apps/opencs/view/widget/colorpickerpopup.hpp new file mode 100644 index 000000000..a7aec3bad --- /dev/null +++ b/apps/opencs/view/widget/colorpickerpopup.hpp @@ -0,0 +1,31 @@ +#ifndef CSVWIDGET_COLORPICKERPOPUP_HPP +#define CSVWIDGET_COLORPICKERPOPUP_HPP + +#include + +class QColorDialog; + +namespace CSVWidget +{ + class ColorPickerPopup : public QFrame + { + Q_OBJECT + + QColorDialog *mColorPicker; + + public: + explicit ColorPickerPopup(QWidget *parent); + + void showPicker(const QPoint &position, const QColor &initialColor); + + protected: + virtual void hideEvent(QHideEvent *event); + virtual bool eventFilter(QObject *object, QEvent *event); + + signals: + void hid(); + void colorChanged(const QColor &color); + }; +} + +#endif diff --git a/apps/opencs/view/world/colorpickerdelegate.cpp b/apps/opencs/view/world/colorpickerdelegate.cpp index c74a1828f..4491f392c 100644 --- a/apps/opencs/view/world/colorpickerdelegate.cpp +++ b/apps/opencs/view/world/colorpickerdelegate.cpp @@ -3,7 +3,7 @@ #include #include -#include "../widget/coloreditbutton.hpp" +#include "../widget/coloreditor.hpp" CSVWorld::ColorPickerDelegate::ColorPickerDelegate(CSMWorld::CommandDispatcher *dispatcher, CSMDoc::Document& document, @@ -28,9 +28,9 @@ QWidget *CSVWorld::ColorPickerDelegate::createEditor(QWidget *parent, throw std::logic_error("Wrong column for ColorPickerDelegate"); } - return new CSVWidget::ColorEditButton(index.data().value(), - getColoredRect(option).size(), - parent); + return new CSVWidget::ColorEditor(index.data().value(), + getColoredRect(option).size(), + parent); } void CSVWorld::ColorPickerDelegate::paint(QPainter *painter, From 76bdf7a5b714d859860f24d807117089ee43ec06 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 11 Jun 2015 23:16:05 +0200 Subject: [PATCH 1488/3725] Add night-eye effect --- apps/openmw/mwrender/renderingmanager.cpp | 23 ++++++++++++++++++++++- apps/openmw/mwrender/renderingmanager.hpp | 6 ++++++ apps/openmw/mwworld/worldimp.cpp | 2 ++ 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index d1811ed67..c8080cf16 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -118,6 +118,7 @@ namespace MWRender : mViewer(viewer) , mRootNode(rootNode) , mResourceSystem(resourceSystem) + , mNightEyeFactor(0.f) { osg::ref_ptr lightRoot = new SceneUtil::LightManager; mLightRoot = lightRoot; @@ -203,9 +204,19 @@ namespace MWRender return mResourceSystem; } + void RenderingManager::setNightEyeFactor(float factor) + { + if (factor != mNightEyeFactor) + { + mNightEyeFactor = factor; + updateAmbient(); + } + } + void RenderingManager::setAmbientColour(const osg::Vec4f &colour) { - mStateUpdater->setAmbientColor(colour); + mAmbientColor = colour; + updateAmbient(); } void RenderingManager::configureAmbient(const ESM::Cell *cell) @@ -653,6 +664,16 @@ namespace MWRender mViewer->startThreading(); } + void RenderingManager::updateAmbient() + { + osg::Vec4f color = mAmbientColor; + + if (mNightEyeFactor > 0.f) + color += osg::Vec4f(0.7, 0.7, 0.7, 0.0) * mNightEyeFactor; + + mStateUpdater->setAmbientColor(color); + } + void RenderingManager::setFogColor(const osg::Vec4f &color) { mViewer->getCamera()->setClearColor(color); diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 8ed590df4..a37203cc2 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -59,6 +59,8 @@ namespace MWRender Resource::ResourceSystem* getResourceSystem(); + void setNightEyeFactor(float factor); + void setAmbientColour(const osg::Vec4f& colour); void setSunDirection(const osg::Vec3f& direction); @@ -152,6 +154,7 @@ namespace MWRender private: void updateProjectionMatrix(); void updateTextureFiltering(); + void updateAmbient(); void setFogColor(const osg::Vec4f& color); osg::ref_ptr mViewer; @@ -175,6 +178,9 @@ namespace MWRender osg::Vec4f mFogColor; + osg::Vec4f mAmbientColor; + float mNightEyeFactor; + float mNearClip; float mViewDistance; float mFieldOfView; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 7b4c33fd8..16dcadb23 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1608,6 +1608,8 @@ namespace MWWorld int blind = static_cast(player.getClass().getCreatureStats(player).getMagicEffects().get(ESM::MagicEffect::Blind).getMagnitude()); MWBase::Environment::get().getWindowManager()->setBlindness(std::max(0, std::min(100, blind))); + int nightEye = static_cast(player.getClass().getCreatureStats(player).getMagicEffects().get(ESM::MagicEffect::NightEye).getMagnitude()); + mRendering->setNightEyeFactor(std::min(1.f, (nightEye/100.f))); mRendering->getCamera()->setCameraDistance(); if(!mRendering->getCamera()->isFirstPerson()) From d03880fbf04a001978c23c7acba0f11156512505 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 11 Jun 2015 23:25:26 +0200 Subject: [PATCH 1489/3725] Compile fix for old boost versions --- apps/opencs/model/doc/document.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 18a4f4878..b833b527f 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -2272,7 +2272,7 @@ CSMDoc::Document::Document (const Files::ConfigurationManager& configuration, if (boost::filesystem::exists (customFiltersPath)) { - destination << std::ifstream(customFiltersPath.c_str(), std::ios::binary).rdbuf(); + destination << std::ifstream(customFiltersPath.string().c_str(), std::ios::binary).rdbuf(); } else { From fc5176dc3882fe183809bb5060c519641aa2867d Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 11 Jun 2015 23:26:32 +0200 Subject: [PATCH 1490/3725] Refactor cmake scripts, reducing the amount of find_package(Qt4) --- CMakeLists.txt | 2 ++ apps/launcher/CMakeLists.txt | 4 ++-- apps/opencs/CMakeLists.txt | 5 +++-- apps/wizard/CMakeLists.txt | 4 ++-- components/CMakeLists.txt | 12 +++--------- 5 files changed, 12 insertions(+), 15 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ec69c5560..0a75976d4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -151,6 +151,8 @@ endif() # Dependencies +find_package(Qt4 REQUIRED COMPONENTS QtCore QtGui QtNetwork) + # Fix for not visible pthreads functions for linker with glibc 2.15 if (UNIX AND NOT APPLE) find_package (Threads) diff --git a/apps/launcher/CMakeLists.txt b/apps/launcher/CMakeLists.txt index 0de79f8f6..8be7a20b6 100644 --- a/apps/launcher/CMakeLists.txt +++ b/apps/launcher/CMakeLists.txt @@ -57,7 +57,6 @@ set(LAUNCHER_UI source_group(launcher FILES ${LAUNCHER} ${LAUNCHER_HEADER}) -find_package(Qt4 REQUIRED) set(QT_USE_QTGUI 1) # Set some platform specific settings @@ -92,7 +91,8 @@ target_link_libraries(openmw-launcher ${OGRE_LIBRARIES} ${OGRE_STATIC_PLUGINS} ${SDL2_LIBRARY_ONLY} - ${QT_LIBRARIES} + ${QT_QTGUI_LIBRARY} + ${QT_QTCORE_LIBRARY} components ) diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 37d13223a..044e8c4ee 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -160,7 +160,6 @@ endif(WIN32) find_package(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS}) -find_package(Qt4 COMPONENTS QtCore QtGui QtNetwork REQUIRED) include(${QT_USE_FILE}) qt4_wrap_ui(OPENCS_UI_HDR ${OPENCS_UI}) @@ -208,7 +207,9 @@ target_link_libraries(openmw-cs ${SHINY_LIBRARIES} ${Boost_LIBRARIES} ${BULLET_LIBRARIES} - ${QT_LIBRARIES} + ${QT_QTGUI_LIBRARY} + ${QT_QTCORE_LIBRARY} + ${QT_QTNETWORK_LIBRARY} components ) diff --git a/apps/wizard/CMakeLists.txt b/apps/wizard/CMakeLists.txt index b8cc3fda4..55f326a0c 100644 --- a/apps/wizard/CMakeLists.txt +++ b/apps/wizard/CMakeLists.txt @@ -81,7 +81,6 @@ endif (OPENMW_USE_UNSHIELD) source_group(wizard FILES ${WIZARD} ${WIZARD_HEADER}) -find_package(Qt4 REQUIRED) set(QT_USE_QTGUI 1) # Set some platform specific settings @@ -113,7 +112,8 @@ add_executable(openmw-wizard target_link_libraries(openmw-wizard ${Boost_LIBRARIES} - ${QT_LIBRARIES} + ${QT_QTGUI_LIBRARY} + ${QT_QTCORE_LIBRARY} components ) diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 01de1c28e..951a80509 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -126,11 +126,6 @@ add_component_dir (version set (ESM_UI ${CMAKE_SOURCE_DIR}/files/ui/contentselector.ui ) -find_package(Qt4 COMPONENTS QtCore QtGui) -if(MINGW) -find_package(Bullet REQUIRED COMPONENTS Collision) -endif() - if(QT_QTGUI_LIBRARY AND QT_QTCORE_LIBRARY) add_component_qt_dir (contentselector model/modelitem model/esmfile @@ -167,16 +162,15 @@ target_link_libraries(components ${Boost_LIBRARIES} ${OGRE_LIBRARIES} ${OENGINE_LIBRARY} + ${QT_QTCORE_LIBRARY} + ${QT_QTGUI_LIBRARY} + ${BULLET_LIBRARIES} ) if (GIT_CHECKOUT) add_dependencies (components git-version) endif (GIT_CHECKOUT) -if(MINGW) -target_link_libraries(components ${QT_LIBRARIES} ${BULLET_LIBRARIES}) -endif() - if (WIN32) target_link_libraries(components shlwapi) endif() From 800bd511f6048ff44cde28a5c4194feaa8f07636 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 12 Jun 2015 00:12:12 +0200 Subject: [PATCH 1491/3725] Set a sensible value for SDL_GL_DEPTH_SIZE (Bug #2649) --- apps/openmw/engine.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index eda33637b..aa00f5e9c 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -342,6 +342,12 @@ void OMW::Engine::createWindow(Settings::Manager& settings) SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, settings.getBool("minimize on focus loss", "Video") ? "1" : "0"); + SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 0); + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); + if (antialiasing > 0) { if (SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1) != 0) From 7407bbdac9dd8e354fc6626b826e4f4de69c7500 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 12 Jun 2015 01:08:58 +0200 Subject: [PATCH 1492/3725] Add a function for SDL error handling --- apps/openmw/engine.cpp | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index aa00f5e9c..01ecd3d11 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -55,6 +55,15 @@ #include "mwstate/statemanagerimp.hpp" +namespace +{ + void checkSDLError(int ret) + { + if (ret != 0) + std::cerr << "SDL error: " << SDL_GetError() << std::endl; + } +} + void OMW::Engine::executeLocalScripts() { MWWorld::LocalScripts& localScripts = MWBase::Environment::get().getWorld()->getLocalScripts(); @@ -342,18 +351,16 @@ void OMW::Engine::createWindow(Settings::Manager& settings) SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, settings.getBool("minimize on focus loss", "Video") ? "1" : "0"); - SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 0); - SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); + checkSDLError(SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8)); + checkSDLError(SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8)); + checkSDLError(SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8)); + checkSDLError(SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 0)); + checkSDLError(SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24)); if (antialiasing > 0) { - if (SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1) != 0) - std::cerr << "SDL error: " << SDL_GetError() << std::endl; - if (SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, antialiasing) != 0) - std::cerr << "SDL error: " << SDL_GetError() << std::endl; + checkSDLError(SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1)); + checkSDLError(SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, antialiasing)); } while (!mWindow) @@ -367,8 +374,7 @@ void OMW::Engine::createWindow(Settings::Manager& settings) std::cout << "Note: " << antialiasing << "x antialiasing not supported, trying " << antialiasing/2 << std::endl; antialiasing /= 2; Settings::Manager::setInt("antialiasing", "Video", antialiasing); - if (SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, antialiasing) != 0) - std::cerr << "SDL error: " << SDL_GetError() << std::endl; + checkSDLError(SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, antialiasing)); continue; } else From cf95d3fc356597eb5abb38e08bb4ebd091649f2f Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 11 Jun 2015 23:49:27 +0200 Subject: [PATCH 1493/3725] Refactor cmake scripts, reducing the amount of find_package(Boost) --- CMakeLists.txt | 2 +- apps/bsatool/CMakeLists.txt | 3 ++- apps/esmtool/CMakeLists.txt | 2 +- apps/essimporter/CMakeLists.txt | 3 ++- apps/launcher/CMakeLists.txt | 1 - apps/mwiniimporter/CMakeLists.txt | 3 ++- apps/opencs/CMakeLists.txt | 19 ++++++++++--------- apps/openmw/CMakeLists.txt | 17 +++++------------ apps/wizard/CMakeLists.txt | 1 - components/CMakeLists.txt | 6 +++++- extern/ogre-ffmpeg-videoplayer/CMakeLists.txt | 5 +---- 11 files changed, 29 insertions(+), 33 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0a75976d4..4b447a3e8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -173,7 +173,7 @@ if (HAVE_UNORDERED_MAP) endif () -set(BOOST_COMPONENTS system filesystem program_options) +set(BOOST_COMPONENTS system filesystem program_options thread wave) if(WIN32) set(BOOST_COMPONENTS ${BOOST_COMPONENTS} locale) endif(WIN32) diff --git a/apps/bsatool/CMakeLists.txt b/apps/bsatool/CMakeLists.txt index 3f1988a70..27baff815 100644 --- a/apps/bsatool/CMakeLists.txt +++ b/apps/bsatool/CMakeLists.txt @@ -9,7 +9,8 @@ add_executable(bsatool ) target_link_libraries(bsatool - ${Boost_LIBRARIES} + ${Boost_PROGRAM_OPTIONS_LIBRARY} + ${Boost_FILESYSTEM_LIBRARY} components ) diff --git a/apps/esmtool/CMakeLists.txt b/apps/esmtool/CMakeLists.txt index 1d0026215..1d5e662d8 100644 --- a/apps/esmtool/CMakeLists.txt +++ b/apps/esmtool/CMakeLists.txt @@ -13,7 +13,7 @@ add_executable(esmtool ) target_link_libraries(esmtool - ${Boost_LIBRARIES} + ${Boost_PROGRAM_OPTIONS_LIBRARY} components ) diff --git a/apps/essimporter/CMakeLists.txt b/apps/essimporter/CMakeLists.txt index 72ef364ee..84e31dad9 100644 --- a/apps/essimporter/CMakeLists.txt +++ b/apps/essimporter/CMakeLists.txt @@ -33,7 +33,8 @@ add_executable(openmw-essimporter ) target_link_libraries(openmw-essimporter - ${Boost_LIBRARIES} + ${Boost_PROGRAM_OPTIONS_LIBRARY} + ${Boost_FILESYSTEM_LIBRARY} components ) diff --git a/apps/launcher/CMakeLists.txt b/apps/launcher/CMakeLists.txt index 8be7a20b6..e392b8efc 100644 --- a/apps/launcher/CMakeLists.txt +++ b/apps/launcher/CMakeLists.txt @@ -87,7 +87,6 @@ add_executable(openmw-launcher ) target_link_libraries(openmw-launcher - ${Boost_LIBRARIES} ${OGRE_LIBRARIES} ${OGRE_STATIC_PLUGINS} ${SDL2_LIBRARY_ONLY} diff --git a/apps/mwiniimporter/CMakeLists.txt b/apps/mwiniimporter/CMakeLists.txt index 753c86fef..e522df6a1 100644 --- a/apps/mwiniimporter/CMakeLists.txt +++ b/apps/mwiniimporter/CMakeLists.txt @@ -14,7 +14,8 @@ add_executable(openmw-iniimporter ) target_link_libraries(openmw-iniimporter - ${Boost_LIBRARIES} + ${Boost_PROGRAM_OPTIONS_LIBRARY} + ${Boost_FILESYSTEM_LIBRARY} components ) diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 044e8c4ee..c011f4695 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -153,13 +153,6 @@ if(WIN32) set(QT_USE_QTMAIN TRUE) endif(WIN32) -set(BOOST_COMPONENTS system filesystem program_options thread wave) -if(WIN32) - set(BOOST_COMPONENTS ${BOOST_COMPONENTS} locale) -endif(WIN32) - -find_package(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS}) - include(${QT_USE_FILE}) qt4_wrap_ui(OPENCS_UI_HDR ${OPENCS_UI}) @@ -205,14 +198,22 @@ target_link_libraries(openmw-cs ${OGRE_Overlay_LIBRARIES} ${OGRE_STATIC_PLUGINS} ${SHINY_LIBRARIES} - ${Boost_LIBRARIES} - ${BULLET_LIBRARIES} + ${Boost_SYSTEM_LIBRARY} + ${Boost_FILESYSTEM_LIBRARY} + ${Boost_PROGRAM_OPTIONS_LIBRARY} + ${Boost_WAVE_LIBRARY} ${QT_QTGUI_LIBRARY} ${QT_QTCORE_LIBRARY} ${QT_QTNETWORK_LIBRARY} + ${BULLET_LIBRARIES} components ) +if (WIN32) + target_link_libraries(openmw-cs ${Boost_LOCALE_LIBRARY}) +endif() + + if(APPLE) INSTALL(TARGETS openmw-cs BUNDLE DESTINATION OpenMW COMPONENT BUNDLE) endif() diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index a183d172d..c7c701d20 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -91,17 +91,6 @@ add_openmw_dir (mwbase ) # Main executable -if (ANDROID) - set(BOOST_COMPONENTS system filesystem program_options thread wave atomic) -else () - set(BOOST_COMPONENTS system filesystem program_options thread wave) -endif () - -if(WIN32) - set(BOOST_COMPONENTS ${BOOST_COMPONENTS} locale) -endif(WIN32) - -find_package(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS}) if (NOT ANDROID) add_executable(openmw @@ -126,10 +115,14 @@ target_link_libraries(openmw ${OGRE_LIBRARIES} ${OGRE_STATIC_PLUGINS} ${SHINY_LIBRARIES} - ${Boost_LIBRARIES} ${OPENAL_LIBRARY} ${SOUND_INPUT_LIBRARY} ${BULLET_LIBRARIES} + ${Boost_SYSTEM_LIBRARY} + ${Boost_THREAD_LIBRARY} + ${Boost_FILESYSTEM_LIBRARY} + ${Boost_PROGRAM_OPTIONS_LIBRARY} + ${Boost_WAVE_LIBRARY} ${MYGUI_LIBRARIES} ${SDL2_LIBRARY} ${MYGUI_PLATFORM_LIBRARIES} diff --git a/apps/wizard/CMakeLists.txt b/apps/wizard/CMakeLists.txt index 55f326a0c..6506541ee 100644 --- a/apps/wizard/CMakeLists.txt +++ b/apps/wizard/CMakeLists.txt @@ -111,7 +111,6 @@ add_executable(openmw-wizard ) target_link_libraries(openmw-wizard - ${Boost_LIBRARIES} ${QT_QTGUI_LIBRARY} ${QT_QTCORE_LIBRARY} components diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 951a80509..a6ca2e86d 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -159,7 +159,11 @@ include_directories(${BULLET_INCLUDE_DIRS} ${CMAKE_CURRENT_BINARY_DIR}) add_library(components STATIC ${COMPONENT_FILES} ${MOC_SRCS} ${ESM_UI_HDR}) target_link_libraries(components - ${Boost_LIBRARIES} + ${Boost_SYSTEM_LIBRARY} + ${Boost_FILESYSTEM_LIBRARY} + ${Boost_THREAD_LIBRARY} + ${Boost_PROGRAM_OPTIONS_LIBRARY} + ${Boost_WAVE_LIBRARY} ${OGRE_LIBRARIES} ${OENGINE_LIBRARY} ${QT_QTCORE_LIBRARY} diff --git a/extern/ogre-ffmpeg-videoplayer/CMakeLists.txt b/extern/ogre-ffmpeg-videoplayer/CMakeLists.txt index 299a57799..4e8f55eb8 100644 --- a/extern/ogre-ffmpeg-videoplayer/CMakeLists.txt +++ b/extern/ogre-ffmpeg-videoplayer/CMakeLists.txt @@ -32,11 +32,8 @@ endif() include_directories(${FFMPEG_INCLUDE_DIRS}) # Find Boost -set(BOOST_COMPONENTS thread) -find_package(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS}) -include_directories(${Boost_INCLUDE_DIRS}) add_library(${OGRE_FFMPEG_VIDEOPLAYER_LIBRARY} STATIC ${OGRE_FFMPEG_VIDEOPLAYER_SOURCE_FILES}) -target_link_libraries(${OGRE_FFMPEG_VIDEOPLAYER_LIBRARY} ${VIDEO_FFMPEG_LIBRARIES} ${Boost_LIBRARIES}) +target_link_libraries(${OGRE_FFMPEG_VIDEOPLAYER_LIBRARY} ${VIDEO_FFMPEG_LIBRARIES} ${Boost_THREAD_LIBRARY}) link_directories(${CMAKE_CURRENT_BINARY_DIR}) From 45fcea929ace0facf156cf85457153e5ddfb66a3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 12 Jun 2015 01:45:48 +0200 Subject: [PATCH 1494/3725] Refactor cmake scripts, reducing the amount of find_package(FFmpeg) --- CMakeLists.txt | 15 ++++++++----- extern/ogre-ffmpeg-videoplayer/CMakeLists.txt | 22 +------------------ 2 files changed, 11 insertions(+), 26 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4b447a3e8..b9282faee 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -98,25 +98,30 @@ endif() cmake_minimum_required(VERSION 2.6) # Sound setup -set(FFmpeg_FIND_COMPONENTS AVCODEC AVFORMAT AVUTIL SWSCALE SWRESAMPLE AVRESAMPLE) unset(FFMPEG_LIBRARIES CACHE) -find_package(FFmpeg) + +find_package(FFmpeg REQUIRED) + +set (FFMPEG_LIBRARIES ${FFMPEG_LIBRARIES} ${SWSCALE_LIBRARY}) + +message(STATUS ${FFMPEG_LIBRARIES}) if ( NOT AVCODEC_FOUND OR NOT AVFORMAT_FOUND OR NOT AVUTIL_FOUND OR NOT SWSCALE_FOUND ) message(FATAL_ERROR "FFmpeg component required, but not found!") endif() set(SOUND_INPUT_INCLUDES ${FFMPEG_INCLUDE_DIRS}) -set(SOUND_INPUT_LIBRARY ${FFMPEG_LIBRARIES} ${SWSCALE_LIBRARIES}) if( SWRESAMPLE_FOUND ) add_definitions(-DHAVE_LIBSWRESAMPLE) - set(SOUND_INPUT_LIBRARY ${FFMPEG_LIBRARIES} ${SWRESAMPLE_LIBRARIES}) + set (FFMPEG_LIBRARIES ${FFMPEG_LIBRARIES} ${SWRESAMPLE_LIBRARIES}) else() if( AVRESAMPLE_FOUND ) - set(SOUND_INPUT_LIBRARY ${FFMPEG_LIBRARIES} ${AVRESAMPLE_LIBRARIES}) + set (FFMPEG_LIBRARIES ${FFMPEG_LIBRARIES} ${AVRESAMPLE_LIBRARIES}) else() message(FATAL_ERROR "Install either libswresample (FFmpeg) or libavresample (Libav).") endif() endif() +set(SOUND_INPUT_LIBRARY ${FFMPEG_LIBRARIES}) + # TinyXML option(USE_SYSTEM_TINYXML "Use system TinyXML library instead of internal." OFF) if(USE_SYSTEM_TINYXML) diff --git a/extern/ogre-ffmpeg-videoplayer/CMakeLists.txt b/extern/ogre-ffmpeg-videoplayer/CMakeLists.txt index 4e8f55eb8..cda3d39e8 100644 --- a/extern/ogre-ffmpeg-videoplayer/CMakeLists.txt +++ b/extern/ogre-ffmpeg-videoplayer/CMakeLists.txt @@ -11,29 +11,9 @@ set(OGRE_FFMPEG_VIDEOPLAYER_SOURCE_FILES audiofactory.hpp ) -# Find FFMPEG -set(FFmpeg_FIND_COMPONENTS AVCODEC AVFORMAT AVUTIL SWSCALE SWRESAMPLE AVRESAMPLE) -unset(FFMPEG_LIBRARIES CACHE) -find_package(FFmpeg) -if ( NOT AVCODEC_FOUND OR NOT AVFORMAT_FOUND OR NOT AVUTIL_FOUND OR NOT SWSCALE_FOUND ) - message(FATAL_ERROR "FFmpeg component required, but not found!") -endif() -set(VIDEO_FFMPEG_LIBRARIES ${FFMPEG_LIBRARIES} ${SWSCALE_LIBRARIES}) -if( SWRESAMPLE_FOUND ) - add_definitions(-DHAVE_LIBSWRESAMPLE) - set(VIDEO_FFMPEG_LIBRARIES ${FFMPEG_LIBRARIES} ${SWRESAMPLE_LIBRARIES}) -else() - if( AVRESAMPLE_FOUND ) - set(VIDEO_FFMPEG_LIBRARIES ${FFMPEG_LIBRARIES} ${AVRESAMPLE_LIBRARIES}) - else() - message(FATAL_ERROR "Install either libswresample (FFmpeg) or libavresample (Libav).") - endif() -endif() -include_directories(${FFMPEG_INCLUDE_DIRS}) - # Find Boost add_library(${OGRE_FFMPEG_VIDEOPLAYER_LIBRARY} STATIC ${OGRE_FFMPEG_VIDEOPLAYER_SOURCE_FILES}) -target_link_libraries(${OGRE_FFMPEG_VIDEOPLAYER_LIBRARY} ${VIDEO_FFMPEG_LIBRARIES} ${Boost_THREAD_LIBRARY}) +target_link_libraries(${OGRE_FFMPEG_VIDEOPLAYER_LIBRARY} ${FFMPEG_LIBRARIES} ${Boost_THREAD_LIBRARY}) link_directories(${CMAKE_CURRENT_BINARY_DIR}) From c04f6cf16766d37fb65d5081290d820e4ddab4d3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 12 Jun 2015 01:58:13 +0200 Subject: [PATCH 1495/3725] Remove unused code --- components/contentselector/model/contentmodel.cpp | 11 ----------- components/contentselector/model/contentmodel.hpp | 1 - 2 files changed, 12 deletions(-) diff --git a/components/contentselector/model/contentmodel.cpp b/components/contentselector/model/contentmodel.cpp index 62f6d9014..d000290e6 100644 --- a/components/contentselector/model/contentmodel.cpp +++ b/components/contentselector/model/contentmodel.cpp @@ -30,17 +30,6 @@ ContentSelectorModel::ContentModel::~ContentModel() void ContentSelectorModel::ContentModel::setEncoding(const QString &encoding) { mEncoding = encoding; - if (encoding == QLatin1String("win1252")) - mCodec = QTextCodec::codecForName("windows-1252"); - - else if (encoding == QLatin1String("win1251")) - mCodec = QTextCodec::codecForName("windows-1251"); - - else if (encoding == QLatin1String("win1250")) - mCodec = QTextCodec::codecForName("windows-1250"); - - else - return; // This should never happen; } int ContentSelectorModel::ContentModel::columnCount(const QModelIndex &parent) const diff --git a/components/contentselector/model/contentmodel.hpp b/components/contentselector/model/contentmodel.hpp index 658555852..ab965ad69 100644 --- a/components/contentselector/model/contentmodel.hpp +++ b/components/contentselector/model/contentmodel.hpp @@ -81,7 +81,6 @@ namespace ContentSelectorModel ContentFileList mFiles; QHash mCheckStates; QSet mPluginsWithLoadOrderError; - QTextCodec *mCodec; QString mEncoding; QIcon mWarningIcon; From 4b5c2398a10e57d74c73d888e386118b6227ccdc Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 12 Jun 2015 02:00:06 +0200 Subject: [PATCH 1496/3725] Remove QTextCodec::setCodecForCStrings Not needed, we're using QString::fromUtf8/toUtf8 to handle encodings correctly. --- apps/launcher/main.cpp | 3 --- apps/wizard/main.cpp | 3 --- 2 files changed, 6 deletions(-) diff --git a/apps/launcher/main.cpp b/apps/launcher/main.cpp index ba0686110..32fe8c93a 100644 --- a/apps/launcher/main.cpp +++ b/apps/launcher/main.cpp @@ -54,9 +54,6 @@ int main(int argc, char *argv[]) QDir::setCurrent(dir.absolutePath()); - // Support non-latin characters - QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8")); - Launcher::MainDialog mainWin; Launcher::FirstRunDialogResult result = mainWin.showFirstRunDialog(); diff --git a/apps/wizard/main.cpp b/apps/wizard/main.cpp index e6a94118a..c861a4ac8 100644 --- a/apps/wizard/main.cpp +++ b/apps/wizard/main.cpp @@ -38,9 +38,6 @@ int main(int argc, char *argv[]) QDir::setCurrent(dir.absolutePath()); - // Support non-latin characters - QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8")); - Wizard::MainWizard wizard; wizard.show(); From 40eb8b65c76e0bd0e487a47d06e06cafd8b76dec Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 12 Jun 2015 04:35:46 +0200 Subject: [PATCH 1497/3725] Revert the travis testing changes --- .travis.yml | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index d2b2ad079..1fc85dca3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,6 @@ language: cpp branches: only: - master - - osg - coverity_scan - /openmw-.*$/ env: @@ -49,9 +48,9 @@ notifications: email: on_success: change on_failure: always - #irc: - # channels: - # - "chat.freenode.net#openmw" - # on_success: change - # on_failure: always - # use_notice: true + irc: + channels: + - "chat.freenode.net#openmw" + on_success: change + on_failure: always + use_notice: true From d4c45efb2bca16b92ffc82e9c24336db003bca82 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 12 Jun 2015 04:39:44 +0200 Subject: [PATCH 1498/3725] Remove useless #undef's for windows now that we have NOMINMAX flag --- apps/openmw/mwgui/class.cpp | 3 --- apps/openmw/mwgui/review.cpp | 3 --- apps/openmw/mwgui/widgets.cpp | 3 --- apps/openmw/mwmechanics/stat.hpp | 3 --- 4 files changed, 12 deletions(-) diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index 3e8734c71..57cd9ca8e 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -11,9 +11,6 @@ #include "tooltips.hpp" -#undef min -#undef max - namespace { diff --git a/apps/openmw/mwgui/review.cpp b/apps/openmw/mwgui/review.cpp index 12957c2b0..fa07f1020 100644 --- a/apps/openmw/mwgui/review.cpp +++ b/apps/openmw/mwgui/review.cpp @@ -13,9 +13,6 @@ #include "tooltips.hpp" -#undef min -#undef max - namespace { void adjustButtonSize(MyGUI::Button *button) diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index 1fa5d9cbf..158d5fd5e 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -15,9 +15,6 @@ #include "controllers.hpp" -#undef min -#undef max - namespace MWGui { namespace Widgets diff --git a/apps/openmw/mwmechanics/stat.hpp b/apps/openmw/mwmechanics/stat.hpp index ffbc19e15..64cc66520 100644 --- a/apps/openmw/mwmechanics/stat.hpp +++ b/apps/openmw/mwmechanics/stat.hpp @@ -1,9 +1,6 @@ #ifndef GAME_MWMECHANICS_STAT_H #define GAME_MWMECHANICS_STAT_H -#undef min -#undef max - #include #include From 4096d2851c66a574743c4a6d2ca4c61305affdab Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Fri, 12 Jun 2015 14:09:25 +0300 Subject: [PATCH 1499/3725] Remove outdated ColorEditButton files --- apps/opencs/view/widget/coloreditbutton.cpp | 42 --------------------- apps/opencs/view/widget/coloreditbutton.hpp | 30 --------------- 2 files changed, 72 deletions(-) delete mode 100644 apps/opencs/view/widget/coloreditbutton.cpp delete mode 100644 apps/opencs/view/widget/coloreditbutton.hpp diff --git a/apps/opencs/view/widget/coloreditbutton.cpp b/apps/opencs/view/widget/coloreditbutton.cpp deleted file mode 100644 index 4960d1ef1..000000000 --- a/apps/opencs/view/widget/coloreditbutton.cpp +++ /dev/null @@ -1,42 +0,0 @@ -#include "coloreditbutton.hpp" - -#include -#include -#include - -CSVWidget::ColorEditButton::ColorEditButton(const QColor &color, - const QSize &coloredRectSize, - QWidget *parent) - : QPushButton(parent), - mColor(color), - mColoredRectSize(coloredRectSize) - -{} - -void CSVWidget::ColorEditButton::paintEvent(QPaintEvent *event) -{ - QPushButton::paintEvent(event); - - QRect buttonRect = rect(); - QRect coloredRect(buttonRect.x() + (buttonRect.width() - mColoredRectSize.width()) / 2, - buttonRect.y() + (buttonRect.height() - mColoredRectSize.height()) / 2, - mColoredRectSize.width(), - mColoredRectSize.height()); - QPainter painter(this); - painter.fillRect(coloredRect, mColor); -} - -QColor CSVWidget::ColorEditButton::color() const -{ - return mColor; -} - -void CSVWidget::ColorEditButton::setColor(const QColor &color) -{ - mColor = color; -} - -void CSVWidget::ColorEditButton::setColoredRectSize(const QSize &size) -{ - mColoredRectSize = size; -} \ No newline at end of file diff --git a/apps/opencs/view/widget/coloreditbutton.hpp b/apps/opencs/view/widget/coloreditbutton.hpp deleted file mode 100644 index e1a8cce9d..000000000 --- a/apps/opencs/view/widget/coloreditbutton.hpp +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef CSV_WIDGET_COLOREDITBUTTON_HPP -#define CSV_WIDGET_COLOREDITBUTTON_HPP - -#include - -class QColor; -class QSize; - -namespace CSVWidget -{ - class ColorEditButton : public QPushButton - { - QColor mColor; - QSize mColoredRectSize; - - public: - ColorEditButton(const QColor &color, - const QSize &coloredRectSize, - QWidget *parent = 0); - - QColor color() const; - void setColor(const QColor &color); - void setColoredRectSize(const QSize &size); - - protected: - void paintEvent(QPaintEvent *event); - }; -} - -#endif From e13a9388961039b0d8fe3b1e76e295e1c5054041 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 12 Jun 2015 15:10:12 +0200 Subject: [PATCH 1500/3725] Add support to build with Qt5 (Task #2665) Known issue: the render view doesn't work in Qt5. With the switch to OSG around the corner, this isn't worth fixing. --- CMakeLists.txt | 14 ++++- apps/launcher/CMakeLists.txt | 23 +++++--- apps/opencs/CMakeLists.txt | 27 +++++++--- apps/opencs/model/world/idtableproxymodel.cpp | 3 +- apps/opencs/view/doc/view.cpp | 2 +- apps/opencs/view/doc/viewmanager.cpp | 6 +-- .../view/render/unpagedworldspacewidget.cpp | 2 +- apps/opencs/view/render/worldspacewidget.cpp | 7 ++- apps/opencs/view/settings/dialog.cpp | 9 +--- apps/opencs/view/settings/dialog.hpp | 5 -- apps/opencs/view/tools/reporttable.cpp | 6 +++ apps/opencs/view/widget/scenetoolrun.cpp | 5 ++ apps/opencs/view/world/dragrecordtable.cpp | 1 + apps/opencs/view/world/dragrecordtable.hpp | 2 +- apps/opencs/view/world/nestedtable.cpp | 4 ++ apps/opencs/view/world/nestedtable.hpp | 2 +- apps/opencs/view/world/table.cpp | 4 ++ apps/opencs/view/world/table.hpp | 2 +- apps/opencs/view/world/tablesubview.cpp | 1 + apps/wizard/CMakeLists.txt | 25 ++++++--- apps/wizard/unshield/unshieldworker.cpp | 1 - apps/wizard/unshield/unshieldworker.hpp | 1 - components/CMakeLists.txt | 53 +++++++++++-------- 23 files changed, 133 insertions(+), 72 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b9282faee..5f3a0fcc1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -104,7 +104,6 @@ find_package(FFmpeg REQUIRED) set (FFMPEG_LIBRARIES ${FFMPEG_LIBRARIES} ${SWSCALE_LIBRARY}) -message(STATUS ${FFMPEG_LIBRARIES}) if ( NOT AVCODEC_FOUND OR NOT AVFORMAT_FOUND OR NOT AVUTIL_FOUND OR NOT SWSCALE_FOUND ) message(FATAL_ERROR "FFmpeg component required, but not found!") endif() @@ -156,7 +155,18 @@ endif() # Dependencies -find_package(Qt4 REQUIRED COMPONENTS QtCore QtGui QtNetwork) +set(DESIRED_QT_VERSION 4 CACHE STRING "The QT version OpenMW should use (4 or 5)") +message(STATUS "Using Qt${DESIRED_QT_VERSION}") + +if (DESIRED_QT_VERSION MATCHES 4) + find_package(Qt4 REQUIRED COMPONENTS QtCore QtGui QtNetwork) +else() + find_package(Qt5Widgets REQUIRED) + find_package(Qt5Core REQUIRED) + find_package(Qt5Network REQUIRED) + # Instruct CMake to run moc automatically when needed. + #set(CMAKE_AUTOMOC ON) +endif() # Fix for not visible pthreads functions for linker with glibc 2.15 if (UNIX AND NOT APPLE) diff --git a/apps/launcher/CMakeLists.txt b/apps/launcher/CMakeLists.txt index e392b8efc..66cc157d3 100644 --- a/apps/launcher/CMakeLists.txt +++ b/apps/launcher/CMakeLists.txt @@ -65,12 +65,17 @@ if(WIN32) set(QT_USE_QTMAIN TRUE) endif(WIN32) -QT4_ADD_RESOURCES(RCC_SRCS ${CMAKE_SOURCE_DIR}/files/launcher/launcher.qrc) -QT4_WRAP_CPP(MOC_SRCS ${LAUNCHER_HEADER_MOC}) -QT4_WRAP_UI(UI_HDRS ${LAUNCHER_UI}) - +if (DESIRED_QT_VERSION MATCHES 4) + include(${QT_USE_FILE}) + QT4_ADD_RESOURCES(RCC_SRCS ${CMAKE_SOURCE_DIR}/files/launcher/launcher.qrc) + QT4_WRAP_CPP(MOC_SRCS ${LAUNCHER_HEADER_MOC}) + QT4_WRAP_UI(UI_HDRS ${LAUNCHER_UI}) +else() + QT5_ADD_RESOURCES(RCC_SRCS ${CMAKE_SOURCE_DIR}/files/launcher/launcher.qrc) + QT5_WRAP_CPP(MOC_SRCS ${LAUNCHER_HEADER_MOC}) + QT5_WRAP_UI(UI_HDRS ${LAUNCHER_UI}) +endif() -include(${QT_USE_FILE}) include_directories(${CMAKE_CURRENT_BINARY_DIR}) if(NOT WIN32) include_directories(${LIBUNSHIELD_INCLUDE_DIR}) @@ -90,14 +95,18 @@ target_link_libraries(openmw-launcher ${OGRE_LIBRARIES} ${OGRE_STATIC_PLUGINS} ${SDL2_LIBRARY_ONLY} - ${QT_QTGUI_LIBRARY} - ${QT_QTCORE_LIBRARY} components ) +if (DESIRED_QT_VERSION MATCHES 4) + target_link_libraries(openmw-launcher ${QT_QTGUI_LIBRARY} ${QT_QTCORE_LIBRARY}) +else() + qt5_use_modules(openmw-launcher Widgets Core) +endif() if (BUILD_WITH_CODE_COVERAGE) add_definitions (--coverage) target_link_libraries(openmw-launcher gcov) endif() + diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index c011f4695..402bd335a 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -153,11 +153,16 @@ if(WIN32) set(QT_USE_QTMAIN TRUE) endif(WIN32) -include(${QT_USE_FILE}) - -qt4_wrap_ui(OPENCS_UI_HDR ${OPENCS_UI}) -qt4_wrap_cpp(OPENCS_MOC_SRC ${OPENCS_HDR_QT}) -qt4_add_resources(OPENCS_RES_SRC ${OPENCS_RES}) +if (DESIRED_QT_VERSION MATCHES 4) + include(${QT_USE_FILE}) + qt4_wrap_ui(OPENCS_UI_HDR ${OPENCS_UI}) + qt4_wrap_cpp(OPENCS_MOC_SRC ${OPENCS_HDR_QT}) + qt4_add_resources(OPENCS_RES_SRC ${OPENCS_RES}) +else() + qt5_wrap_ui(OPENCS_UI_HDR ${OPENCS_UI}) + qt5_wrap_cpp(OPENCS_MOC_SRC ${OPENCS_HDR_QT}) + qt5_add_resources(OPENCS_RES_SRC ${OPENCS_RES}) +endif() # for compiled .ui files include_directories(${CMAKE_CURRENT_BINARY_DIR}) @@ -202,13 +207,19 @@ target_link_libraries(openmw-cs ${Boost_FILESYSTEM_LIBRARY} ${Boost_PROGRAM_OPTIONS_LIBRARY} ${Boost_WAVE_LIBRARY} - ${QT_QTGUI_LIBRARY} - ${QT_QTCORE_LIBRARY} - ${QT_QTNETWORK_LIBRARY} ${BULLET_LIBRARIES} components ) +if (DESIRED_QT_VERSION MATCHES 4) + target_link_libraries(openmw-cs + ${QT_QTGUI_LIBRARY} + ${QT_QTCORE_LIBRARY} + ${QT_QTNETWORK_LIBRARY}) +else() + qt5_use_modules(openmw-cs Widgets Core Network) +endif() + if (WIN32) target_link_libraries(openmw-cs ${Boost_LOCALE_LIBRARY}) endif() diff --git a/apps/opencs/model/world/idtableproxymodel.cpp b/apps/opencs/model/world/idtableproxymodel.cpp index d8932d205..516644713 100644 --- a/apps/opencs/model/world/idtableproxymodel.cpp +++ b/apps/opencs/model/world/idtableproxymodel.cpp @@ -52,9 +52,10 @@ QModelIndex CSMWorld::IdTableProxyModel::getModelIndex (const std::string& id, i void CSMWorld::IdTableProxyModel::setFilter (const boost::shared_ptr& filter) { + beginResetModel(); mFilter = filter; updateColumnMap(); - reset(); + endResetModel(); } bool CSMWorld::IdTableProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 2485caa88..64b066eb1 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index b2f681df1..7c79302d7 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -6,6 +6,8 @@ #include #include +#include +#include #include "../../model/doc/documentmanager.hpp" #include "../../model/doc/document.hpp" @@ -24,10 +26,6 @@ #include "view.hpp" -#include -#include -#include - void CSVDoc::ViewManager::updateIndices() { std::map > documents; diff --git a/apps/opencs/view/render/unpagedworldspacewidget.cpp b/apps/opencs/view/render/unpagedworldspacewidget.cpp index 462b62b7a..383382938 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.cpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.cpp @@ -6,7 +6,7 @@ #include #include -#include +#include #include "../../model/doc/document.hpp" diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index e88814818..ba0ec8446 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -7,7 +7,12 @@ #include #include -#include +#include +#include +#include +#include +#include +#include #include "../../model/world/universalid.hpp" #include "../../model/world/idtable.hpp" diff --git a/apps/opencs/view/settings/dialog.cpp b/apps/opencs/view/settings/dialog.cpp index e8832e2bc..38eb7bbc7 100644 --- a/apps/opencs/view/settings/dialog.cpp +++ b/apps/opencs/view/settings/dialog.cpp @@ -8,19 +8,12 @@ #include #include #include +#include #include "../../model/settings/usersettings.hpp" #include "page.hpp" -#include - -#include -#include -#include - -#include -#include CSVSettings::Dialog::Dialog(QMainWindow *parent) : SettingWindow (parent), mStackedWidget (0), mDebugMode (false) diff --git a/apps/opencs/view/settings/dialog.hpp b/apps/opencs/view/settings/dialog.hpp index cb85bddb9..e3a3f575a 100644 --- a/apps/opencs/view/settings/dialog.hpp +++ b/apps/opencs/view/settings/dialog.hpp @@ -3,7 +3,6 @@ #include "settingwindow.hpp" #include "resizeablestackedwidget.hpp" -#include class QStackedWidget; class QListWidget; @@ -26,10 +25,6 @@ namespace CSVSettings { explicit Dialog (QMainWindow *parent = 0); - ///Enables setting debug mode. When the dialog opens, a page is created - ///which displays the SettingModel's contents in a Tree view. - void enableDebugMode (bool state, QStandardItemModel *model = 0); - protected: /// Settings are written on close diff --git a/apps/opencs/view/tools/reporttable.cpp b/apps/opencs/view/tools/reporttable.cpp index 7cfe8e4f0..c1c8a35dd 100644 --- a/apps/opencs/view/tools/reporttable.cpp +++ b/apps/opencs/view/tools/reporttable.cpp @@ -9,6 +9,8 @@ #include #include #include +#include +#include #include "../../model/tools/reportmodel.hpp" @@ -121,7 +123,11 @@ CSVTools::ReportTable::ReportTable (CSMDoc::Document& document, const CSMWorld::UniversalId& id, bool richTextDescription, QWidget *parent) : CSVWorld::DragRecordTable (document, parent), mModel (document.getReport (id)) { +#if QT_VERSION >= QT_VERSION_CHECK(5,0,0) + horizontalHeader()->setSectionResizeMode (QHeaderView::Interactive); +#else horizontalHeader()->setResizeMode (QHeaderView::Interactive); +#endif horizontalHeader()->setStretchLastSection (true); verticalHeader()->hide(); setSortingEnabled (true); diff --git a/apps/opencs/view/widget/scenetoolrun.cpp b/apps/opencs/view/widget/scenetoolrun.cpp index 8de334efe..4c9eb676e 100644 --- a/apps/opencs/view/widget/scenetoolrun.cpp +++ b/apps/opencs/view/widget/scenetoolrun.cpp @@ -65,8 +65,13 @@ CSVWidget::SceneToolRun::SceneToolRun (SceneToolbar *parent, const QString& tool mTable->setShowGrid (false); mTable->verticalHeader()->hide(); mTable->horizontalHeader()->hide(); +#if QT_VERSION >= QT_VERSION_CHECK(5,0,0) + mTable->horizontalHeader()->setSectionResizeMode (0, QHeaderView::Stretch); + mTable->horizontalHeader()->setSectionResizeMode (1, QHeaderView::ResizeToContents); +#else mTable->horizontalHeader()->setResizeMode (0, QHeaderView::Stretch); mTable->horizontalHeader()->setResizeMode (1, QHeaderView::ResizeToContents); +#endif mTable->setSelectionMode (QAbstractItemView::NoSelection); layout->addWidget (mTable); diff --git a/apps/opencs/view/world/dragrecordtable.cpp b/apps/opencs/view/world/dragrecordtable.cpp index 7032fee6d..2a1ae1f40 100644 --- a/apps/opencs/view/world/dragrecordtable.cpp +++ b/apps/opencs/view/world/dragrecordtable.cpp @@ -1,4 +1,5 @@ #include +#include #include "../../model/world/tablemimedata.hpp" #include "dragrecordtable.hpp" diff --git a/apps/opencs/view/world/dragrecordtable.hpp b/apps/opencs/view/world/dragrecordtable.hpp index 4996c03ac..48f9e2528 100644 --- a/apps/opencs/view/world/dragrecordtable.hpp +++ b/apps/opencs/view/world/dragrecordtable.hpp @@ -2,7 +2,7 @@ #define CSV_WORLD_DRAGRECORDTABLE_H #include -#include +#include class QWidget; class QAction; diff --git a/apps/opencs/view/world/nestedtable.cpp b/apps/opencs/view/world/nestedtable.cpp index 5c8762020..112873cb9 100644 --- a/apps/opencs/view/world/nestedtable.cpp +++ b/apps/opencs/view/world/nestedtable.cpp @@ -23,7 +23,11 @@ CSVWorld::NestedTable::NestedTable(CSMDoc::Document& document, setSelectionBehavior (QAbstractItemView::SelectRows); setSelectionMode (QAbstractItemView::ExtendedSelection); +#if QT_VERSION >= QT_VERSION_CHECK(5,0,0) + horizontalHeader()->setSectionResizeMode (QHeaderView::Interactive); +#else horizontalHeader()->setResizeMode (QHeaderView::Interactive); +#endif verticalHeader()->hide(); int columns = model->columnCount(QModelIndex()); diff --git a/apps/opencs/view/world/nestedtable.hpp b/apps/opencs/view/world/nestedtable.hpp index b8e91844c..5db977942 100644 --- a/apps/opencs/view/world/nestedtable.hpp +++ b/apps/opencs/view/world/nestedtable.hpp @@ -2,7 +2,7 @@ #define CSV_WORLD_NESTEDTABLE_H #include -#include +#include class QUndoStack; class QAction; diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index bb3dfa4d3..b4efbd3c8 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -282,7 +282,11 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id, mDispatcher = new CSMWorld::CommandDispatcher (document, id, this); setModel (mProxyModel); +#if QT_VERSION >= QT_VERSION_CHECK(5,0,0) + horizontalHeader()->setSectionResizeMode (QHeaderView::Interactive); +#else horizontalHeader()->setResizeMode (QHeaderView::Interactive); +#endif verticalHeader()->hide(); setSortingEnabled (sorting); setSelectionBehavior (QAbstractItemView::SelectRows); diff --git a/apps/opencs/view/world/table.hpp b/apps/opencs/view/world/table.hpp index becb21f65..67bf3fe85 100644 --- a/apps/opencs/view/world/table.hpp +++ b/apps/opencs/view/world/table.hpp @@ -4,7 +4,7 @@ #include #include -#include +#include #include "../../model/filter/node.hpp" #include "../../model/world/columnbase.hpp" diff --git a/apps/opencs/view/world/tablesubview.cpp b/apps/opencs/view/world/tablesubview.cpp index af0b64447..faff4c429 100644 --- a/apps/opencs/view/world/tablesubview.cpp +++ b/apps/opencs/view/world/tablesubview.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "../../model/doc/document.hpp" #include "../../model/world/tablemimedata.hpp" diff --git a/apps/wizard/CMakeLists.txt b/apps/wizard/CMakeLists.txt index 6506541ee..5cd874863 100644 --- a/apps/wizard/CMakeLists.txt +++ b/apps/wizard/CMakeLists.txt @@ -89,12 +89,17 @@ if(WIN32) set(QT_USE_QTMAIN TRUE) endif(WIN32) -QT4_ADD_RESOURCES(RCC_SRCS ${CMAKE_SOURCE_DIR}/files/wizard/wizard.qrc) -QT4_WRAP_CPP(MOC_SRCS ${WIZARD_HEADER_MOC}) -QT4_WRAP_UI(UI_HDRS ${WIZARD_UI}) - +if (DESIRED_QT_VERSION MATCHES 4) + include(${QT_USE_FILE}) + QT4_ADD_RESOURCES(RCC_SRCS ${CMAKE_SOURCE_DIR}/files/wizard/wizard.qrc) + QT4_WRAP_CPP(MOC_SRCS ${WIZARD_HEADER_MOC}) + QT4_WRAP_UI(UI_HDRS ${WIZARD_UI}) +else() + QT5_ADD_RESOURCES(RCC_SRCS ${CMAKE_SOURCE_DIR}/files/wizard/wizard.qrc) + QT5_WRAP_CPP(MOC_SRCS ${WIZARD_HEADER_MOC}) + QT5_WRAP_UI(UI_HDRS ${WIZARD_UI}) +endif() -include(${QT_USE_FILE}) include_directories(${CMAKE_CURRENT_BINARY_DIR}) if (OPENMW_USE_UNSHIELD) @@ -111,11 +116,17 @@ add_executable(openmw-wizard ) target_link_libraries(openmw-wizard - ${QT_QTGUI_LIBRARY} - ${QT_QTCORE_LIBRARY} components ) +if (DESIRED_QT_VERSION MATCHES 4) + target_link_libraries(openmw-wizard + ${QT_QTGUI_LIBRARY} + ${QT_QTCORE_LIBRARY}) +else() + qt5_use_modules(openmw-wizard Widgets Core) +endif() + if (OPENMW_USE_UNSHIELD) target_link_libraries(openmw-wizard ${LIBUNSHIELD_LIBRARY}) endif() diff --git a/apps/wizard/unshield/unshieldworker.cpp b/apps/wizard/unshield/unshieldworker.cpp index 11e090ed1..9daea2b71 100644 --- a/apps/wizard/unshield/unshieldworker.cpp +++ b/apps/wizard/unshield/unshieldworker.cpp @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include diff --git a/apps/wizard/unshield/unshieldworker.hpp b/apps/wizard/unshield/unshieldworker.hpp index 5ea7b04ae..c1d3cfff1 100644 --- a/apps/wizard/unshield/unshieldworker.hpp +++ b/apps/wizard/unshield/unshieldworker.hpp @@ -24,7 +24,6 @@ namespace Wizard class UnshieldWorker : public QObject { Q_OBJECT - Q_ENUMS(Wizard::Component) public: UnshieldWorker(QObject *parent = 0); diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index a6ca2e86d..cbb63bf07 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -126,27 +126,30 @@ add_component_dir (version set (ESM_UI ${CMAKE_SOURCE_DIR}/files/ui/contentselector.ui ) -if(QT_QTGUI_LIBRARY AND QT_QTCORE_LIBRARY) - add_component_qt_dir (contentselector - model/modelitem model/esmfile - model/naturalsort model/contentmodel - model/loadordererror - view/combobox view/contentselector - ) - add_component_qt_dir (config - gamesettings - launchersettings - settingsbase - ) - - add_component_qt_dir (process - processinvoker - ) - - include(${QT_USE_FILE}) +add_component_qt_dir (contentselector + model/modelitem model/esmfile + model/naturalsort model/contentmodel + model/loadordererror + view/combobox view/contentselector + ) +add_component_qt_dir (config + gamesettings + launchersettings + settingsbase + ) + +add_component_qt_dir (process + processinvoker +) + +if (DESIRED_QT_VERSION MATCHES 4) + include(${QT_USE_FILE}) QT4_WRAP_UI(ESM_UI_HDR ${ESM_UI}) - QT4_WRAP_CPP(MOC_SRCS ${COMPONENT_MOC_FILES}) -endif(QT_QTGUI_LIBRARY AND QT_QTCORE_LIBRARY) + QT4_WRAP_CPP(MOC_SRCS ${COMPONENT_MOC_FILES}) +else() + QT5_WRAP_UI(ESM_UI_HDR ${ESM_UI}) + QT5_WRAP_CPP(MOC_SRCS ${COMPONENT_MOC_FILES}) +endif() if (CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") if("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "x86_64" AND NOT APPLE) @@ -166,11 +169,17 @@ target_link_libraries(components ${Boost_WAVE_LIBRARY} ${OGRE_LIBRARIES} ${OENGINE_LIBRARY} - ${QT_QTCORE_LIBRARY} - ${QT_QTGUI_LIBRARY} ${BULLET_LIBRARIES} ) +if (DESIRED_QT_VERSION MATCHES 4) + target_link_libraries(components + ${QT_QTCORE_LIBRARY} + ${QT_QTGUI_LIBRARY}) +else() + qt5_use_modules(components Widgets Core) +endif() + if (GIT_CHECKOUT) add_dependencies (components git-version) endif (GIT_CHECKOUT) From 89c2a7e26b402e27224d414dc4cf33e2653288a7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 12 Jun 2015 15:22:19 +0200 Subject: [PATCH 1501/3725] Fix for possibly missing library on windows --- apps/mwiniimporter/CMakeLists.txt | 5 +++++ components/CMakeLists.txt | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/apps/mwiniimporter/CMakeLists.txt b/apps/mwiniimporter/CMakeLists.txt index e522df6a1..4024c0b42 100644 --- a/apps/mwiniimporter/CMakeLists.txt +++ b/apps/mwiniimporter/CMakeLists.txt @@ -19,6 +19,11 @@ target_link_libraries(openmw-iniimporter components ) +if (WIN32) + target_link_libraries(openmw-iniimporter + ${Boost_LOCALE_LIBRARY}) +endif() + if (MINGW) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -municode") endif() diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index cbb63bf07..1b33b10f6 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -172,6 +172,11 @@ target_link_libraries(components ${BULLET_LIBRARIES} ) +if (WIN32) + target_link_libraries(components + ${Boost_LOCALE_LIBRARY}) +endif() + if (DESIRED_QT_VERSION MATCHES 4) target_link_libraries(components ${QT_QTCORE_LIBRARY} From eb5180ba8696f043cf91381728a36a86f41f9d44 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Fri, 12 Jun 2015 18:33:55 +0300 Subject: [PATCH 1502/3725] Save selected color in a model when picking is finished --- apps/opencs/view/widget/coloreditor.cpp | 19 ++++------- apps/opencs/view/widget/coloreditor.hpp | 9 +++-- .../opencs/view/world/colorpickerdelegate.cpp | 33 ++++--------------- .../opencs/view/world/colorpickerdelegate.hpp | 9 ----- apps/opencs/view/world/dialoguesubview.cpp | 6 ++++ apps/opencs/view/world/util.cpp | 28 +++++++++++++--- 6 files changed, 45 insertions(+), 59 deletions(-) diff --git a/apps/opencs/view/widget/coloreditor.cpp b/apps/opencs/view/widget/coloreditor.cpp index bab98fcd5..eaef0f6d3 100644 --- a/apps/opencs/view/widget/coloreditor.cpp +++ b/apps/opencs/view/widget/coloreditor.cpp @@ -9,12 +9,9 @@ #include "colorpickerpopup.hpp" -CSVWidget::ColorEditor::ColorEditor(const QColor &color, - const QSize &coloredRectSize, - QWidget *parent) +CSVWidget::ColorEditor::ColorEditor(const QColor &color, QWidget *parent) : QPushButton(parent), mColor(color), - mColoredRectSize(coloredRectSize), mColorPicker(new ColorPickerPopup(this)) { setCheckable(true); @@ -28,10 +25,10 @@ void CSVWidget::ColorEditor::paintEvent(QPaintEvent *event) QPushButton::paintEvent(event); QRect buttonRect = rect(); - QRect coloredRect(buttonRect.x() + (buttonRect.width() - mColoredRectSize.width()) / 2, - buttonRect.y() + (buttonRect.height() - mColoredRectSize.height()) / 2, - mColoredRectSize.width(), - mColoredRectSize.height()); + QRect coloredRect(qRound(buttonRect.x() + buttonRect.width() / 4.0), + qRound(buttonRect.y() + buttonRect.height() / 4.0), + qRound(buttonRect.width() / 2.0), + qRound(buttonRect.height() / 2.0)); QPainter painter(this); painter.fillRect(coloredRect, mColor); } @@ -46,11 +43,6 @@ void CSVWidget::ColorEditor::setColor(const QColor &color) mColor = color; } -void CSVWidget::ColorEditor::setColoredRectSize(const QSize &size) -{ - mColoredRectSize = size; -} - void CSVWidget::ColorEditor::showPicker() { if (isChecked()) @@ -73,6 +65,7 @@ void CSVWidget::ColorEditor::pickerHid() { setChecked(false); } + emit pickingFinished(); } void CSVWidget::ColorEditor::pickerColorChanged(const QColor &color) diff --git a/apps/opencs/view/widget/coloreditor.hpp b/apps/opencs/view/widget/coloreditor.hpp index a0fa497b6..cca26fade 100644 --- a/apps/opencs/view/widget/coloreditor.hpp +++ b/apps/opencs/view/widget/coloreditor.hpp @@ -16,19 +16,15 @@ namespace CSVWidget Q_OBJECT QColor mColor; - QSize mColoredRectSize; ColorPickerPopup *mColorPicker; QPoint calculatePopupPosition(); public: - ColorEditor(const QColor &color, - const QSize &coloredRectSize, - QWidget *parent = 0); + ColorEditor(const QColor &color, QWidget *parent = 0); QColor color() const; void setColor(const QColor &color); - void setColoredRectSize(const QSize &size); protected: void paintEvent(QPaintEvent *event); @@ -37,6 +33,9 @@ namespace CSVWidget void showPicker(); void pickerHid(); void pickerColorChanged(const QColor &color); + + signals: + void pickingFinished(); }; } diff --git a/apps/opencs/view/world/colorpickerdelegate.cpp b/apps/opencs/view/world/colorpickerdelegate.cpp index 4491f392c..7490c07f5 100644 --- a/apps/opencs/view/world/colorpickerdelegate.cpp +++ b/apps/opencs/view/world/colorpickerdelegate.cpp @@ -11,41 +11,20 @@ CSVWorld::ColorPickerDelegate::ColorPickerDelegate(CSMWorld::CommandDispatcher * : CommandDelegate(dispatcher, document, parent) {} -QWidget *CSVWorld::ColorPickerDelegate::createEditor(QWidget *parent, - const QStyleOptionViewItem &option, - const QModelIndex &index) const -{ - return createEditor(parent, option, index, getDisplayTypeFromIndex(index)); -} - -QWidget *CSVWorld::ColorPickerDelegate::createEditor(QWidget *parent, - const QStyleOptionViewItem &option, - const QModelIndex &index, - CSMWorld::ColumnBase::Display display) const -{ - if (display != CSMWorld::ColumnBase::Display_Colour) - { - throw std::logic_error("Wrong column for ColorPickerDelegate"); - } - - return new CSVWidget::ColorEditor(index.data().value(), - getColoredRect(option).size(), - parent); -} - void CSVWorld::ColorPickerDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { - painter->fillRect(getColoredRect(option), index.data().value()); + QRect coloredRect = getColoredRect(option); + painter->fillRect(coloredRect, index.data().value()); } QRect CSVWorld::ColorPickerDelegate::getColoredRect(const QStyleOptionViewItem &option) const { - return QRect(option.rect.x() + option.rect.width() / 4, - option.rect.y() + option.rect.height() / 4, - option.rect.width() / 2, - option.rect.height() / 2); + return QRect(qRound(option.rect.x() + option.rect.width() / 4.0), + qRound(option.rect.y() + option.rect.height() / 4.0), + qRound(option.rect.width() / 2.0), + qRound(option.rect.height() / 2.0)); } CSVWorld::CommandDelegate *CSVWorld::ColorPickerDelegateFactory::makeDelegate(CSMWorld::CommandDispatcher *dispatcher, diff --git a/apps/opencs/view/world/colorpickerdelegate.hpp b/apps/opencs/view/world/colorpickerdelegate.hpp index 147c2f424..f17923648 100644 --- a/apps/opencs/view/world/colorpickerdelegate.hpp +++ b/apps/opencs/view/world/colorpickerdelegate.hpp @@ -21,15 +21,6 @@ namespace CSVWorld CSMDoc::Document& document, QObject *parent); - virtual QWidget *createEditor(QWidget *parent, - const QStyleOptionViewItem &option, - const QModelIndex &index) const; - - virtual QWidget *createEditor(QWidget *parent, - const QStyleOptionViewItem &option, - const QModelIndex &index, - CSMWorld::ColumnBase::Display display) const; - virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 66e8fcb7a..541cf050f 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -33,6 +33,8 @@ #include "../../model/world/commands.hpp" #include "../../model/doc/document.hpp" +#include "../widget/coloreditor.hpp" + #include "recordstatusdelegate.hpp" #include "util.hpp" #include "tablebottombox.hpp" @@ -331,6 +333,10 @@ QWidget* CSVWorld::DialogueDelegateDispatcher::makeEditor(CSMWorld::ColumnBase:: { connect(editor, SIGNAL(editingFinished()), proxy, SLOT(editorDataCommited())); } + else if (qobject_cast(editor)) + { + connect(editor, SIGNAL(pickingFinished()), proxy, SLOT(editorDataCommited())); + } else // throw an exception because this is a coding error throw std::logic_error ("Dialogue editor type missing"); diff --git a/apps/opencs/view/world/util.cpp b/apps/opencs/view/world/util.cpp index e1d165a24..de088bffc 100644 --- a/apps/opencs/view/world/util.cpp +++ b/apps/opencs/view/world/util.cpp @@ -17,6 +17,7 @@ #include "../../model/world/commands.hpp" #include "../../model/world/tablemimedata.hpp" #include "../../model/world/commanddispatcher.hpp" +#include "../widget/coloreditor.hpp" #include "dialoguespinbox.hpp" #include "scriptedit.hpp" @@ -123,10 +124,19 @@ void CSVWorld::CommandDelegate::setModelDataImp (QWidget *editor, QAbstractItemM if (!mCommandDispatcher) return; - NastyTableModelHack hack (*model); - QStyledItemDelegate::setModelData (editor, &hack, index); - - QVariant new_ = hack.getData(); + QVariant new_; + // Color columns use a custom editor, so we need explicitly extract a data from it + CSVWidget::ColorEditor *colorEditor = qobject_cast(editor); + if (colorEditor != NULL) + { + new_ = colorEditor->color(); + } + else + { + NastyTableModelHack hack (*model); + QStyledItemDelegate::setModelData (editor, &hack, index); + new_ = hack.getData(); + } if ((model->data (index)!=new_) && (model->flags(index) & Qt::ItemIsEditable)) mCommandDispatcher->executeModify (model, index, new_); @@ -184,7 +194,7 @@ QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleO { case CSMWorld::ColumnBase::Display_Colour: - return new QLineEdit(parent); + return new CSVWidget::ColorEditor(index.data().value(), parent); case CSMWorld::ColumnBase::Display_Integer: { @@ -284,6 +294,14 @@ void CSVWorld::CommandDelegate::setEditorData (QWidget *editor, const QModelInde } } + // Color columns use a custom editor, so we need explicitly set a data for it + CSVWidget::ColorEditor *colorEditor = qobject_cast(editor); + if (colorEditor != NULL) + { + colorEditor->setColor(index.data().value()); + return; + } + QByteArray n = editor->metaObject()->userProperty().name(); if (n == "dateTime") { From caeba1b8878a91504ac39ceba9eff2d96b6ff1ba Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Fri, 12 Jun 2015 20:34:35 +0300 Subject: [PATCH 1503/3725] Draw the frame around rect in ColorEditor and ColorPickerDelegate --- apps/opencs/view/widget/coloreditor.cpp | 2 ++ apps/opencs/view/world/colorpickerdelegate.cpp | 17 ++++++++--------- apps/opencs/view/world/colorpickerdelegate.hpp | 2 -- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/apps/opencs/view/widget/coloreditor.cpp b/apps/opencs/view/widget/coloreditor.cpp index eaef0f6d3..e6e3264be 100644 --- a/apps/opencs/view/widget/coloreditor.cpp +++ b/apps/opencs/view/widget/coloreditor.cpp @@ -31,6 +31,8 @@ void CSVWidget::ColorEditor::paintEvent(QPaintEvent *event) qRound(buttonRect.height() / 2.0)); QPainter painter(this); painter.fillRect(coloredRect, mColor); + painter.setPen(Qt::black); + painter.drawRect(coloredRect); } QColor CSVWidget::ColorEditor::color() const diff --git a/apps/opencs/view/world/colorpickerdelegate.cpp b/apps/opencs/view/world/colorpickerdelegate.cpp index 7490c07f5..4feaa170e 100644 --- a/apps/opencs/view/world/colorpickerdelegate.cpp +++ b/apps/opencs/view/world/colorpickerdelegate.cpp @@ -15,16 +15,15 @@ void CSVWorld::ColorPickerDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { - QRect coloredRect = getColoredRect(option); + QRect coloredRect(qRound(option.rect.x() + option.rect.width() / 4.0), + qRound(option.rect.y() + option.rect.height() / 4.0), + qRound(option.rect.width() / 2.0), + qRound(option.rect.height() / 2.0)); + painter->save(); painter->fillRect(coloredRect, index.data().value()); -} - -QRect CSVWorld::ColorPickerDelegate::getColoredRect(const QStyleOptionViewItem &option) const -{ - return QRect(qRound(option.rect.x() + option.rect.width() / 4.0), - qRound(option.rect.y() + option.rect.height() / 4.0), - qRound(option.rect.width() / 2.0), - qRound(option.rect.height() / 2.0)); + painter->setPen(Qt::black); + painter->drawRect(coloredRect); + painter->restore(); } CSVWorld::CommandDelegate *CSVWorld::ColorPickerDelegateFactory::makeDelegate(CSMWorld::CommandDispatcher *dispatcher, diff --git a/apps/opencs/view/world/colorpickerdelegate.hpp b/apps/opencs/view/world/colorpickerdelegate.hpp index f17923648..a8e6d87fc 100644 --- a/apps/opencs/view/world/colorpickerdelegate.hpp +++ b/apps/opencs/view/world/colorpickerdelegate.hpp @@ -14,8 +14,6 @@ namespace CSVWorld { class ColorPickerDelegate : public CommandDelegate { - QRect getColoredRect(const QStyleOptionViewItem &option) const; - public: ColorPickerDelegate(CSMWorld::CommandDispatcher *dispatcher, CSMDoc::Document& document, From e516d37cbf22e047cca941c2be7f48deab75dccd Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Fri, 12 Jun 2015 22:03:47 +0300 Subject: [PATCH 1504/3725] MapColourColumn::set() uses the correct color value --- apps/opencs/model/world/columnimp.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index 8758d924b..a8ae5dfa1 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -694,7 +694,7 @@ namespace CSMWorld QColor colour = data.value(); - record2.mMapColor = colour.rgb() & 0xffffff; + record2.mMapColor = (colour.blue() << 16) | (colour.green() << 8) | colour.red(); record.setModified (record2); } From 650e37dba1cf8feb922eda3b16c93048ddc8297b Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Fri, 12 Jun 2015 22:31:12 +0300 Subject: [PATCH 1505/3725] RegionMap uses proper colors --- apps/opencs/model/world/regionmap.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/world/regionmap.cpp b/apps/opencs/model/world/regionmap.cpp index f63426c04..42bde9c81 100644 --- a/apps/opencs/model/world/regionmap.cpp +++ b/apps/opencs/model/world/regionmap.cpp @@ -334,9 +334,9 @@ QVariant CSMWorld::RegionMap::data (const QModelIndex& index, int role) const mColours.find (Misc::StringUtils::lowerCase (cell->second.mRegion)); if (iter!=mColours.end()) - return QBrush ( - QColor (iter->second>>24, (iter->second>>16) & 255, (iter->second>>8) & 255, - iter->second & 255)); + return QBrush (QColor (iter->second & 0xff, + (iter->second >> 8) & 0xff, + (iter->second >> 16) & 0xff)); if (cell->second.mRegion.empty()) return QBrush (Qt::Dense6Pattern); // no region From f19d07b4047daad44c7add15784659c167c1531e Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Fri, 12 Jun 2015 23:09:31 +0300 Subject: [PATCH 1506/3725] Rename ColorPickerDelegate to ColorDelegate --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/view/doc/viewmanager.cpp | 4 +-- apps/opencs/view/world/colordelegate.cpp | 36 +++++++++++++++++++ ...orpickerdelegate.hpp => colordelegate.hpp} | 14 ++++---- .../opencs/view/world/colorpickerdelegate.cpp | 36 ------------------- 5 files changed, 46 insertions(+), 46 deletions(-) create mode 100644 apps/opencs/view/world/colordelegate.cpp rename apps/opencs/view/world/{colorpickerdelegate.hpp => colordelegate.hpp} (64%) delete mode 100644 apps/opencs/view/world/colorpickerdelegate.cpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 83a20ecaa..88edf7bb1 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -70,7 +70,7 @@ opencs_units (view/world opencs_units_noqt (view/world subviews enumdelegate vartypedelegate recordstatusdelegate idtypedelegate datadisplaydelegate scripthighlighter idvalidator dialoguecreator physicssystem idcompletiondelegate - colorpickerdelegate + colordelegate ) opencs_units (view/widget diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index e5bb7fe81..969914851 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -19,7 +19,7 @@ #include "../world/recordstatusdelegate.hpp" #include "../world/idtypedelegate.hpp" #include "../world/idcompletiondelegate.hpp" -#include "../world/colorpickerdelegate.hpp" +#include "../world/colordelegate.hpp" #include "../../model/settings/usersettings.hpp" @@ -65,7 +65,7 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) new CSVWorld::IdTypeDelegateFactory()); mDelegateFactories->add (CSMWorld::ColumnBase::Display_Colour, - new CSVWorld::ColorPickerDelegateFactory()); + new CSVWorld::ColorDelegateFactory()); std::vector idCompletionColumns = CSMWorld::IdCompletionManager::getDisplayTypes(); for (std::vector::const_iterator current = idCompletionColumns.begin(); diff --git a/apps/opencs/view/world/colordelegate.cpp b/apps/opencs/view/world/colordelegate.cpp new file mode 100644 index 000000000..ae71f965a --- /dev/null +++ b/apps/opencs/view/world/colordelegate.cpp @@ -0,0 +1,36 @@ +#include "colordelegate.hpp" + +#include +#include + +#include "../widget/coloreditor.hpp" + +CSVWorld::ColorDelegate::ColorDelegate(CSMWorld::CommandDispatcher *dispatcher, + CSMDoc::Document& document, + QObject *parent) + : CommandDelegate(dispatcher, document, parent) +{} + +void CSVWorld::ColorDelegate::paint(QPainter *painter, + const QStyleOptionViewItem &option, + const QModelIndex &index) const +{ + QRect coloredRect(qRound(option.rect.x() + option.rect.width() / 4.0), + qRound(option.rect.y() + option.rect.height() / 4.0), + qRound(option.rect.width() / 2.0), + qRound(option.rect.height() / 2.0)); + painter->save(); + painter->fillRect(coloredRect, index.data().value()); + painter->setPen(Qt::black); + painter->drawRect(coloredRect); + painter->restore(); +} + +CSVWorld::CommandDelegate *CSVWorld::ColorDelegateFactory::makeDelegate(CSMWorld::CommandDispatcher *dispatcher, + CSMDoc::Document &document, + QObject *parent) const +{ + return new ColorDelegate(dispatcher, document, parent); +} + + diff --git a/apps/opencs/view/world/colorpickerdelegate.hpp b/apps/opencs/view/world/colordelegate.hpp similarity index 64% rename from apps/opencs/view/world/colorpickerdelegate.hpp rename to apps/opencs/view/world/colordelegate.hpp index a8e6d87fc..87051e86d 100644 --- a/apps/opencs/view/world/colorpickerdelegate.hpp +++ b/apps/opencs/view/world/colordelegate.hpp @@ -1,5 +1,5 @@ -#ifndef CSV_WORLD_COLORPICKERDELEGATE_HPP -#define CSV_WORLD_COLORPICKERDELEGATE_HPP +#ifndef CSV_WORLD_COLORDELEGATE_HPP +#define CSV_WORLD_COLORDELEGATE_HPP #include "util.hpp" @@ -12,19 +12,19 @@ namespace CSVWidget namespace CSVWorld { - class ColorPickerDelegate : public CommandDelegate + class ColorDelegate : public CommandDelegate { public: - ColorPickerDelegate(CSMWorld::CommandDispatcher *dispatcher, - CSMDoc::Document& document, - QObject *parent); + ColorDelegate(CSMWorld::CommandDispatcher *dispatcher, + CSMDoc::Document& document, + QObject *parent); virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; }; - class ColorPickerDelegateFactory : public CommandDelegateFactory + class ColorDelegateFactory : public CommandDelegateFactory { public: virtual CommandDelegate *makeDelegate(CSMWorld::CommandDispatcher *dispatcher, diff --git a/apps/opencs/view/world/colorpickerdelegate.cpp b/apps/opencs/view/world/colorpickerdelegate.cpp deleted file mode 100644 index 4feaa170e..000000000 --- a/apps/opencs/view/world/colorpickerdelegate.cpp +++ /dev/null @@ -1,36 +0,0 @@ -#include "colorpickerdelegate.hpp" - -#include -#include - -#include "../widget/coloreditor.hpp" - -CSVWorld::ColorPickerDelegate::ColorPickerDelegate(CSMWorld::CommandDispatcher *dispatcher, - CSMDoc::Document& document, - QObject *parent) - : CommandDelegate(dispatcher, document, parent) -{} - -void CSVWorld::ColorPickerDelegate::paint(QPainter *painter, - const QStyleOptionViewItem &option, - const QModelIndex &index) const -{ - QRect coloredRect(qRound(option.rect.x() + option.rect.width() / 4.0), - qRound(option.rect.y() + option.rect.height() / 4.0), - qRound(option.rect.width() / 2.0), - qRound(option.rect.height() / 2.0)); - painter->save(); - painter->fillRect(coloredRect, index.data().value()); - painter->setPen(Qt::black); - painter->drawRect(coloredRect); - painter->restore(); -} - -CSVWorld::CommandDelegate *CSVWorld::ColorPickerDelegateFactory::makeDelegate(CSMWorld::CommandDispatcher *dispatcher, - CSMDoc::Document &document, - QObject *parent) const -{ - return new ColorPickerDelegate(dispatcher, document, parent); -} - - From b06d1f008f0aed4a6152ef7d0b28a99ad6c5b7eb Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Fri, 12 Jun 2015 23:34:08 +0300 Subject: [PATCH 1507/3725] Redraw the color editor immediately after the color is updated --- apps/opencs/view/widget/coloreditor.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/opencs/view/widget/coloreditor.cpp b/apps/opencs/view/widget/coloreditor.cpp index e6e3264be..f06187992 100644 --- a/apps/opencs/view/widget/coloreditor.cpp +++ b/apps/opencs/view/widget/coloreditor.cpp @@ -43,6 +43,7 @@ QColor CSVWidget::ColorEditor::color() const void CSVWidget::ColorEditor::setColor(const QColor &color) { mColor = color; + update(); } void CSVWidget::ColorEditor::showPicker() From a294e24a85672ee7c31c9d08f22d7aab6a4f6902 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sat, 13 Jun 2015 00:37:10 +0300 Subject: [PATCH 1508/3725] Reset ColorEditor checked state after the popup is hidden --- apps/opencs/view/widget/coloreditor.cpp | 9 +------- apps/opencs/view/widget/colorpickerpopup.cpp | 23 ++++++++++++++++++++ apps/opencs/view/widget/colorpickerpopup.hpp | 1 + 3 files changed, 25 insertions(+), 8 deletions(-) diff --git a/apps/opencs/view/widget/coloreditor.cpp b/apps/opencs/view/widget/coloreditor.cpp index f06187992..b31225962 100644 --- a/apps/opencs/view/widget/coloreditor.cpp +++ b/apps/opencs/view/widget/coloreditor.cpp @@ -60,14 +60,7 @@ void CSVWidget::ColorEditor::showPicker() void CSVWidget::ColorEditor::pickerHid() { - // If the popup is hidden and mouse isn't above the editor, - // reset the editor checked state manually - QPoint globalEditorPosition = mapToGlobal(QPoint(0, 0)); - QRect globalEditorRect(globalEditorPosition, geometry().size()); - if (!globalEditorRect.contains(QCursor::pos())) - { - setChecked(false); - } + setChecked(false); emit pickingFinished(); } diff --git a/apps/opencs/view/widget/colorpickerpopup.cpp b/apps/opencs/view/widget/colorpickerpopup.cpp index dd53f1bec..8e71ce39e 100644 --- a/apps/opencs/view/widget/colorpickerpopup.cpp +++ b/apps/opencs/view/widget/colorpickerpopup.cpp @@ -1,9 +1,12 @@ #include "colorpickerpopup.hpp" #include +#include #include #include +#include #include +#include CSVWidget::ColorPickerPopup::ColorPickerPopup(QWidget *parent) : QFrame(parent) @@ -40,6 +43,26 @@ void CSVWidget::ColorPickerPopup::showPicker(const QPoint &position, const QColo show(); } +void CSVWidget::ColorPickerPopup::mousePressEvent(QMouseEvent *event) +{ + QPushButton *button = qobject_cast(parentWidget()); + if (button != NULL) + { + QStyleOptionButton option; + option.init(button); + QRect buttonRect = option.rect; + buttonRect.moveTo(button->mapToGlobal(buttonRect.topLeft())); + + // If the mouse is pressed above the pop-up parent, + // the pop-up will be hidden and the pressed signal won't be repeated for the parent + if (buttonRect.contains(event->globalPos()) || buttonRect.contains(event->pos())) + { + setAttribute(Qt::WA_NoMouseReplay); + } + } + QFrame::mousePressEvent(event); +} + void CSVWidget::ColorPickerPopup::hideEvent(QHideEvent *event) { QFrame::hideEvent(event); diff --git a/apps/opencs/view/widget/colorpickerpopup.hpp b/apps/opencs/view/widget/colorpickerpopup.hpp index a7aec3bad..602bbdb6d 100644 --- a/apps/opencs/view/widget/colorpickerpopup.hpp +++ b/apps/opencs/view/widget/colorpickerpopup.hpp @@ -19,6 +19,7 @@ namespace CSVWidget void showPicker(const QPoint &position, const QColor &initialColor); protected: + virtual void mousePressEvent(QMouseEvent *event); virtual void hideEvent(QHideEvent *event); virtual bool eventFilter(QObject *object, QEvent *event); From b81454d226c2ea919b2a48eb6482f7b5553bd5a0 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 13 Jun 2015 14:37:47 +1000 Subject: [PATCH 1509/3725] Fix using wrong bit flag for NPC stats auto-calculation. Also set the corresponding mNpdtType which is used when determining which data structure to save. Should resolve Bug #2668. --- apps/esmtool/labels.cpp | 24 +++++++++---------- .../opencs/model/tools/referenceablecheck.cpp | 2 +- apps/opencs/model/world/refidadapterimp.cpp | 4 ++++ components/esm/loadnpc.hpp | 12 +++++----- 4 files changed, 23 insertions(+), 19 deletions(-) diff --git a/apps/esmtool/labels.cpp b/apps/esmtool/labels.cpp index 88e188df0..883a9e728 100644 --- a/apps/esmtool/labels.cpp +++ b/apps/esmtool/labels.cpp @@ -119,7 +119,7 @@ std::string clothingTypeLabel(int idx) } std::string armorTypeLabel(int idx) -{ +{ if (idx >= 0 && idx <= 10) { static const char *armorTypeLabels[] = { @@ -645,7 +645,7 @@ std::string ruleFunction(int idx) else return "Invalid"; } - + // The "unused flag bits" should probably be defined alongside the // defined bits in the ESM component. The names of the flag bits are // very inconsistent. @@ -653,7 +653,7 @@ std::string ruleFunction(int idx) std::string bodyPartFlags(int flags) { std::string properties = ""; - if (flags == 0) properties += "[None] "; + if (flags == 0) properties += "[None] "; if (flags & ESM::BodyPart::BPF_Female) properties += "Female "; if (flags & ESM::BodyPart::BPF_NotPlayable) properties += "NotPlayable "; int unused = (0xFFFFFFFF ^ @@ -667,7 +667,7 @@ std::string bodyPartFlags(int flags) std::string cellFlags(int flags) { std::string properties = ""; - if (flags == 0) properties += "[None] "; + if (flags == 0) properties += "[None] "; if (flags & ESM::Cell::HasWater) properties += "HasWater "; if (flags & ESM::Cell::Interior) properties += "Interior "; if (flags & ESM::Cell::NoSleep) properties += "NoSleep "; @@ -830,12 +830,12 @@ std::string npcFlags(int flags) std::string properties = ""; if (flags == 0) properties += "[None] "; // Mythicmods and the ESM component differ. Mythicmods says - // 0x8=None and 0x10=AutoCalc, while our code defines 0x8 as - // AutoCalc. The former seems to be correct. All Bethesda - // records have bit 0x8 set. A suspiciously large portion of - // females have autocalc turned off. - if (flags & ESM::NPC::Autocalc) properties += "Unknown "; - if (flags & 0x00000010) properties += "Autocalc "; + // 0x8=None and 0x10=AutoCalc, while our code previously defined + // 0x8 as AutoCalc. The former seems to be correct. All Bethesda + // records have bit 0x8 set. Previously, suspiciously large portion + // of females had autocalc turned off. + if (flags & 0x00000008) properties += "Unknown "; + if (flags & ESM::NPC::Autocalc) properties += "Autocalc "; if (flags & ESM::NPC::Female) properties += "Female "; if (flags & ESM::NPC::Respawn) properties += "Respawn "; if (flags & ESM::NPC::Essential) properties += "Essential "; @@ -847,8 +847,8 @@ std::string npcFlags(int flags) // however the only unknown bit occurs on ALL records, and // relatively few NPCs have this bit set. int unused = (0xFFFFFFFF ^ - (ESM::NPC::Autocalc| - 0x00000010| + (0x00000008| + ESM::NPC::Autocalc| ESM::NPC::Female| ESM::NPC::Respawn| ESM::NPC::Essential| diff --git a/apps/opencs/model/tools/referenceablecheck.cpp b/apps/opencs/model/tools/referenceablecheck.cpp index 548fcd36f..6b323547f 100644 --- a/apps/opencs/model/tools/referenceablecheck.cpp +++ b/apps/opencs/model/tools/referenceablecheck.cpp @@ -648,7 +648,7 @@ void CSMTools::ReferenceableCheckStage::npcCheck ( if (npc.mNpdtType == ESM::NPC::NPC_WITH_AUTOCALCULATED_STATS) //12 = autocalculated { - if ((npc.mFlags & ESM::NPC::Autocalc) == 0) //0x0008 = autocalculated flag + if ((npc.mFlags & ESM::NPC::Autocalc) == 0) //0x0010 = autocalculated flag { messages.push_back (std::make_pair (id, npc.mId + " mNpdtType or flags mismatch!")); //should not happend? return; diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index d31a9ceaa..cb71319c8 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -546,6 +546,10 @@ void CSMWorld::NpcRefIdAdapter::setData (const RefIdColumn *column, RefIdData& d record.get().mFlags |= iter->second; else record.get().mFlags &= ~iter->second; + + if (iter->second == ESM::NPC::Autocalc) + record.get().mNpdtType = (value.toInt() != 0) ? ESM::NPC::NPC_WITH_AUTOCALCULATED_STATS + : ESM::NPC::NPC_DEFAULT; } else ActorRefIdAdapter::setData (column, data, index, value); diff --git a/components/esm/loadnpc.hpp b/components/esm/loadnpc.hpp index b535b91b0..281020c98 100644 --- a/components/esm/loadnpc.hpp +++ b/components/esm/loadnpc.hpp @@ -52,12 +52,12 @@ struct NPC enum Flags { - Female = 0x0001, - Essential = 0x0002, - Respawn = 0x0004, - Autocalc = 0x0008, - Skeleton = 0x0400, // Skeleton blood effect (white) - Metal = 0x0800 // Metal blood effect (golden?) + Female = 0x0001, + Essential = 0x0002, + Respawn = 0x0004, + Autocalc = 0x0010, + Skeleton = 0x0400, // Skeleton blood effect (white) + Metal = 0x0800 // Metal blood effect (golden?) }; enum NpcType From 5b6984d8d844c812c16776298be6eab05a2e0615 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 13 Jun 2015 22:24:22 +1000 Subject: [PATCH 1510/3725] Set modified flag in setData() operations, without which the changes weren't being saved. Should resolve Bug #2656. --- apps/opencs/model/world/refidadapterimp.cpp | 169 +++++++++++++++----- 1 file changed, 128 insertions(+), 41 deletions(-) diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index cb71319c8..4c369ef24 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -37,10 +37,18 @@ void CSMWorld::PotionRefIdAdapter::setData (const RefIdColumn *column, RefIdData Record& record = static_cast&> ( data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Potion))); + ESM::Potion potion = record.get(); + if (column==mAutoCalc) - record.get().mData.mAutoCalc = value.toInt(); + potion.mData.mAutoCalc = value.toInt(); else + { InventoryRefIdAdapter::setData (column, data, index, value); + + return; + } + + record.setModified(potion); } @@ -71,12 +79,19 @@ void CSMWorld::ApparatusRefIdAdapter::setData (const RefIdColumn *column, RefIdD Record& record = static_cast&> ( data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Apparatus))); + ESM::Apparatus apparatus = record.get(); + if (column==mType) - record.get().mData.mType = value.toInt(); + apparatus.mData.mType = value.toInt(); else if (column==mQuality) - record.get().mData.mQuality = value.toFloat(); + apparatus.mData.mQuality = value.toFloat(); else + { InventoryRefIdAdapter::setData (column, data, index, value); + + return; + } + record.setModified(apparatus); } @@ -114,14 +129,22 @@ void CSMWorld::ArmorRefIdAdapter::setData (const RefIdColumn *column, RefIdData& Record& record = static_cast&> ( data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Armor))); + ESM::Armor armor = record.get(); + if (column==mType) - record.get().mData.mType = value.toInt(); + armor.mData.mType = value.toInt(); else if (column==mHealth) - record.get().mData.mHealth = value.toInt(); + armor.mData.mHealth = value.toInt(); else if (column==mArmor) - record.get().mData.mArmor = value.toInt(); + armor.mData.mArmor = value.toInt(); else + { EnchantableRefIdAdapter::setData (column, data, index, value); + + return; + } + + record.setModified(armor); } CSMWorld::BookRefIdAdapter::BookRefIdAdapter (const EnchantableColumns& columns, @@ -151,12 +174,20 @@ void CSMWorld::BookRefIdAdapter::setData (const RefIdColumn *column, RefIdData& Record& record = static_cast&> ( data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Book))); + ESM::Book book = record.get(); + if (column==mScroll) - record.get().mData.mIsScroll = value.toInt(); + book.mData.mIsScroll = value.toInt(); else if (column==mSkill) - record.get().mData.mSkillID = value.toInt(); + book.mData.mSkillID = value.toInt(); else + { EnchantableRefIdAdapter::setData (column, data, index, value); + + return; + } + + record.setModified(book); } CSMWorld::ClothingRefIdAdapter::ClothingRefIdAdapter (const EnchantableColumns& columns, @@ -186,10 +217,18 @@ void CSMWorld::ClothingRefIdAdapter::setData (const RefIdColumn *column, RefIdDa Record& record = static_cast&> ( data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Clothing))); + ESM::Clothing clothing = record.get(); + if (column==mType) - record.get().mData.mType = value.toInt(); + clothing.mData.mType = value.toInt(); else + { EnchantableRefIdAdapter::setData (column, data, index, value); + + return; + } + + record.setModified(clothing); } CSMWorld::ContainerRefIdAdapter::ContainerRefIdAdapter (const NameColumns& columns, @@ -226,24 +265,32 @@ void CSMWorld::ContainerRefIdAdapter::setData (const RefIdColumn *column, RefIdD Record& record = static_cast&> ( data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Container))); + ESM::Container container = record.get(); + if (column==mWeight) - record.get().mWeight = value.toFloat(); + container.mWeight = value.toFloat(); else if (column==mOrganic) { if (value.toInt()) - record.get().mFlags |= ESM::Container::Organic; + container.mFlags |= ESM::Container::Organic; else - record.get().mFlags &= ~ESM::Container::Organic; + container.mFlags &= ~ESM::Container::Organic; } else if (column==mRespawn) { if (value.toInt()) - record.get().mFlags |= ESM::Container::Respawn; + container.mFlags |= ESM::Container::Respawn; else - record.get().mFlags &= ~ESM::Container::Respawn; + container.mFlags &= ~ESM::Container::Respawn; } else + { NameRefIdAdapter::setData (column, data, index, value); + + return; + } + + record.setModified(container); } CSMWorld::CreatureColumns::CreatureColumns (const ActorColumns& actorColumns) @@ -303,20 +350,22 @@ void CSMWorld::CreatureRefIdAdapter::setData (const RefIdColumn *column, RefIdDa Record& record = static_cast&> ( data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Creature))); + ESM::Creature creature = record.get(); + if (column==mColumns.mType) - record.get().mData.mType = value.toInt(); + creature.mData.mType = value.toInt(); else if (column==mColumns.mSoul) - record.get().mData.mSoul = value.toInt(); + creature.mData.mSoul = value.toInt(); else if (column==mColumns.mScale) - record.get().mScale = value.toFloat(); + creature.mScale = value.toFloat(); else if (column==mColumns.mOriginal) - record.get().mOriginal = value.toString().toUtf8().constData(); + creature.mOriginal = value.toString().toUtf8().constData(); else if (column==mColumns.mCombat) - record.get().mData.mCombat = value.toInt(); + creature.mData.mCombat = value.toInt(); else if (column==mColumns.mMagic) - record.get().mData.mMagic = value.toInt(); + creature.mData.mMagic = value.toInt(); else if (column==mColumns.mStealth) - record.get().mData.mStealth = value.toInt(); + creature.mData.mStealth = value.toInt(); else { std::map::const_iterator iter = @@ -325,13 +374,19 @@ void CSMWorld::CreatureRefIdAdapter::setData (const RefIdColumn *column, RefIdDa if (iter!=mColumns.mFlags.end()) { if (value.toInt()!=0) - record.get().mFlags |= iter->second; + creature.mFlags |= iter->second; else - record.get().mFlags &= ~iter->second; + creature.mFlags &= ~iter->second; } else + { ActorRefIdAdapter::setData (column, data, index, value); + + return; + } } + + record.setModified(creature); } CSMWorld::DoorRefIdAdapter::DoorRefIdAdapter (const NameColumns& columns, @@ -361,12 +416,20 @@ void CSMWorld::DoorRefIdAdapter::setData (const RefIdColumn *column, RefIdData& Record& record = static_cast&> ( data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Door))); + ESM::Door door = record.get(); + if (column==mOpenSound) - record.get().mOpenSound = value.toString().toUtf8().constData(); + door.mOpenSound = value.toString().toUtf8().constData(); else if (column==mCloseSound) - record.get().mCloseSound = value.toString().toUtf8().constData(); + door.mCloseSound = value.toString().toUtf8().constData(); else + { NameRefIdAdapter::setData (column, data, index, value); + + return; + } + + record.setModified(door); } CSMWorld::LightColumns::LightColumns (const InventoryColumns& columns) @@ -409,14 +472,16 @@ void CSMWorld::LightRefIdAdapter::setData (const RefIdColumn *column, RefIdData& Record& record = static_cast&> ( data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Light))); + ESM::Light light = record.get(); + if (column==mColumns.mTime) - record.get().mData.mTime = value.toInt(); + light.mData.mTime = value.toInt(); else if (column==mColumns.mRadius) - record.get().mData.mRadius = value.toInt(); + light.mData.mRadius = value.toInt(); else if (column==mColumns.mColor) - record.get().mData.mColor = value.toInt(); + light.mData.mColor = value.toInt(); else if (column==mColumns.mSound) - record.get().mSound = value.toString().toUtf8().constData(); + light.mSound = value.toString().toUtf8().constData(); else { std::map::const_iterator iter = @@ -425,13 +490,19 @@ void CSMWorld::LightRefIdAdapter::setData (const RefIdColumn *column, RefIdData& if (iter!=mColumns.mFlags.end()) { if (value.toInt()!=0) - record.get().mData.mFlags |= iter->second; + light.mData.mFlags |= iter->second; else - record.get().mData.mFlags &= ~iter->second; + light.mData.mFlags &= ~iter->second; } else + { InventoryRefIdAdapter::setData (column, data, index, value); + + return; + } } + + record.setModified (light); } CSMWorld::MiscRefIdAdapter::MiscRefIdAdapter (const InventoryColumns& columns, const RefIdColumn *key) @@ -456,10 +527,18 @@ void CSMWorld::MiscRefIdAdapter::setData (const RefIdColumn *column, RefIdData& Record& record = static_cast&> ( data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Miscellaneous))); + ESM::Miscellaneous misc = record.get(); + if (column==mKey) - record.get().mData.mIsKey = value.toInt(); + misc.mData.mIsKey = value.toInt(); else + { InventoryRefIdAdapter::setData (column, data, index, value); + + return; + } + + record.setModified(misc); } CSMWorld::NpcColumns::NpcColumns (const ActorColumns& actorColumns) @@ -525,16 +604,18 @@ void CSMWorld::NpcRefIdAdapter::setData (const RefIdColumn *column, RefIdData& d Record& record = static_cast&> ( data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Npc))); + ESM::NPC npc = record.get(); + if (column==mColumns.mRace) - record.get().mRace = value.toString().toUtf8().constData(); + npc.mRace = value.toString().toUtf8().constData(); else if (column==mColumns.mClass) - record.get().mClass = value.toString().toUtf8().constData(); + npc.mClass = value.toString().toUtf8().constData(); else if (column==mColumns.mFaction) - record.get().mFaction = value.toString().toUtf8().constData(); + npc.mFaction = value.toString().toUtf8().constData(); else if (column==mColumns.mHair) - record.get().mHair = value.toString().toUtf8().constData(); + npc.mHair = value.toString().toUtf8().constData(); else if (column==mColumns.mHead) - record.get().mHead = value.toString().toUtf8().constData(); + npc.mHead = value.toString().toUtf8().constData(); else { std::map::const_iterator iter = @@ -543,17 +624,23 @@ void CSMWorld::NpcRefIdAdapter::setData (const RefIdColumn *column, RefIdData& d if (iter!=mColumns.mFlags.end()) { if (value.toInt()!=0) - record.get().mFlags |= iter->second; + npc.mFlags |= iter->second; else - record.get().mFlags &= ~iter->second; + npc.mFlags &= ~iter->second; if (iter->second == ESM::NPC::Autocalc) - record.get().mNpdtType = (value.toInt() != 0) ? ESM::NPC::NPC_WITH_AUTOCALCULATED_STATS - : ESM::NPC::NPC_DEFAULT; + npc.mNpdtType = (value.toInt() != 0) ? ESM::NPC::NPC_WITH_AUTOCALCULATED_STATS + : ESM::NPC::NPC_DEFAULT; } else + { ActorRefIdAdapter::setData (column, data, index, value); + + return; + } } + + record.setModified (npc); } CSMWorld::NpcAttributesRefIdAdapter::NpcAttributesRefIdAdapter () From 2c15ad5e0cae0a5b211ba59aed38a5810cc643e1 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sat, 13 Jun 2015 19:08:31 +0300 Subject: [PATCH 1511/3725] Add SoundGens verifier --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/tools/soundgencheck.cpp | 49 +++++++++++++++++++++++ apps/opencs/model/tools/soundgencheck.hpp | 30 ++++++++++++++ apps/opencs/model/tools/tools.cpp | 5 +++ 4 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 apps/opencs/model/tools/soundgencheck.cpp create mode 100644 apps/opencs/model/tools/soundgencheck.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 402bd335a..6a9318319 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -41,7 +41,7 @@ opencs_units (model/tools opencs_units_noqt (model/tools mandatoryid skillcheck classcheck factioncheck racecheck soundcheck regioncheck birthsigncheck spellcheck referencecheck referenceablecheck scriptcheck bodypartcheck - startscriptcheck search searchoperation searchstage pathgridcheck + startscriptcheck search searchoperation searchstage pathgridcheck soundgencheck ) diff --git a/apps/opencs/model/tools/soundgencheck.cpp b/apps/opencs/model/tools/soundgencheck.cpp new file mode 100644 index 000000000..68e5edefd --- /dev/null +++ b/apps/opencs/model/tools/soundgencheck.cpp @@ -0,0 +1,49 @@ +#include "soundgencheck.hpp" + +#include + +#include "../world/refiddata.hpp" +#include "../world/universalid.hpp" + +CSMTools::SoundGenCheckStage::SoundGenCheckStage(const CSMWorld::IdCollection &soundGens, + const CSMWorld::IdCollection &sounds, + const CSMWorld::RefIdCollection &referenceables) + : mSoundGens(soundGens), + mSounds(sounds), + mReferenceables(referenceables) +{} + +int CSMTools::SoundGenCheckStage::setup() +{ + return mSoundGens.getSize(); +} + +void CSMTools::SoundGenCheckStage::perform(int stage, CSMDoc::Messages &messages) +{ + const CSMWorld::Record &record = mSoundGens.getRecord(stage); + if (record.isDeleted()) + { + return; + } + + const ESM::SoundGenerator soundGen = record.get(); + CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_SoundGen, soundGen.mId); + + if (soundGen.mCreature != "") + { + CSMWorld::RefIdData::LocalIndex creatureIndex = mReferenceables.getDataSet().searchId(soundGen.mCreature); + if (creatureIndex.first == -1) + { + messages.push_back(std::make_pair(id, "No such creature '" + soundGen.mCreature + "'")); + } + else if (creatureIndex.second != CSMWorld::UniversalId::Type_Creature) + { + messages.push_back(std::make_pair(id, "'" + soundGen.mCreature + "' is not a creature")); + } + } + + if (mSounds.searchId(soundGen.mSound) == -1) + { + messages.push_back(std::make_pair(id, "No such sound '" + soundGen.mSound + "'")); + } +} diff --git a/apps/opencs/model/tools/soundgencheck.hpp b/apps/opencs/model/tools/soundgencheck.hpp new file mode 100644 index 000000000..91b08f979 --- /dev/null +++ b/apps/opencs/model/tools/soundgencheck.hpp @@ -0,0 +1,30 @@ +#ifndef CSM_TOOLS_SOUNDGENCHECK_HPP +#define CSM_TOOLS_SOUNDGENCHECK_HPP + +#include "../world/data.hpp" + +#include "../doc/stage.hpp" + +namespace CSMTools +{ + /// \brief VerifyStage: make sure that sound gen records are internally consistent + class SoundGenCheckStage : public CSMDoc::Stage + { + const CSMWorld::IdCollection &mSoundGens; + const CSMWorld::IdCollection &mSounds; + const CSMWorld::RefIdCollection &mReferenceables; + + public: + SoundGenCheckStage(const CSMWorld::IdCollection &soundGens, + const CSMWorld::IdCollection &sounds, + const CSMWorld::RefIdCollection &referenceables); + + virtual int setup(); + ///< \return number of steps + + virtual void perform(int stage, CSMDoc::Messages &messages); + ///< Messages resulting from this stage will be appended to \a messages. + }; +} + +#endif diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index 8d93a9433..7d70abae5 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -27,6 +27,7 @@ #include "startscriptcheck.hpp" #include "searchoperation.hpp" #include "pathgridcheck.hpp" +#include "soundgencheck.hpp" CSMDoc::OperationHolder *CSMTools::Tools::get (int type) { @@ -99,6 +100,10 @@ CSMDoc::OperationHolder *CSMTools::Tools::getVerifier() mVerifierOperation->appendStage (new PathgridCheckStage (mData.getPathgrids())); + mVerifierOperation->appendStage (new SoundGenCheckStage (mData.getSoundGens(), + mData.getSounds(), + mData.getReferenceables())); + mVerifier.setOperation (mVerifierOperation); } From 281088c93b5325b8726c4ca990ffed3d67819e70 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sat, 13 Jun 2015 19:47:39 +0300 Subject: [PATCH 1512/3725] Add check for an empty sound field to SoundGens verifier --- apps/opencs/model/tools/soundgencheck.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/tools/soundgencheck.cpp b/apps/opencs/model/tools/soundgencheck.cpp index 68e5edefd..bdf89f19d 100644 --- a/apps/opencs/model/tools/soundgencheck.cpp +++ b/apps/opencs/model/tools/soundgencheck.cpp @@ -29,7 +29,7 @@ void CSMTools::SoundGenCheckStage::perform(int stage, CSMDoc::Messages &messages const ESM::SoundGenerator soundGen = record.get(); CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_SoundGen, soundGen.mId); - if (soundGen.mCreature != "") + if (!soundGen.mCreature.empty()) { CSMWorld::RefIdData::LocalIndex creatureIndex = mReferenceables.getDataSet().searchId(soundGen.mCreature); if (creatureIndex.first == -1) @@ -42,7 +42,11 @@ void CSMTools::SoundGenCheckStage::perform(int stage, CSMDoc::Messages &messages } } - if (mSounds.searchId(soundGen.mSound) == -1) + if (soundGen.mSound.empty()) + { + messages.push_back(std::make_pair(id, "Sound is not specified")); + } + else if (mSounds.searchId(soundGen.mSound) == -1) { messages.push_back(std::make_pair(id, "No such sound '" + soundGen.mSound + "'")); } From b7cd62e4dee69a6496b8b8f609f83d115a46ac62 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 13 Jun 2015 23:49:27 +0200 Subject: [PATCH 1513/3725] Revert "Remove user preference setting option." This reverts commit d3b7cf44d391ba9624f28070e68784352e6f514d. --- apps/launcher/maindialog.cpp | 22 +++++++++++++++++++--- apps/launcher/settingspage.cpp | 8 ++++++++ files/ui/settingspage.ui | 10 ++++++++++ 3 files changed, 37 insertions(+), 3 deletions(-) diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index 2f7a9db33..27d37dbf0 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -490,7 +490,16 @@ bool Launcher::MainDialog::writeSettings() // Game settings QFile file(userPath + QString("openmw.cfg")); - if (!file.open(QIODevice::ReadWrite | QIODevice::Text)) { + QIODevice::OpenMode mode(0); + bool keepComments = mLauncherSettings.value(QString("Settings/keep-comments"), QString("true")) + == QLatin1String("true"); + + if (keepComments) + mode = QIODevice::ReadWrite | QIODevice::Text; + else + mode = QIODevice::ReadWrite | QIODevice::Text | QIODevice::Truncate; + + if (!file.open(mode)) { // File cannot be opened or created QMessageBox msgBox; msgBox.setWindowTitle(tr("Error writing OpenMW configuration file")); @@ -503,8 +512,16 @@ bool Launcher::MainDialog::writeSettings() return false; } + QTextStream stream(&file); + + if (keepComments) + mGameSettings.writeFileWithComments(file); + else + { + stream.setCodec(QTextCodec::codecForName("UTF-8")); + mGameSettings.writeFile(stream); + } - mGameSettings.writeFileWithComments(file); file.close(); // Graphics settings @@ -523,7 +540,6 @@ bool Launcher::MainDialog::writeSettings() return false; } - QTextStream stream(&file); stream.setDevice(&file); stream.setCodec(QTextCodec::codecForName("UTF-8")); diff --git a/apps/launcher/settingspage.cpp b/apps/launcher/settingspage.cpp index 843b51391..bc8ffe618 100644 --- a/apps/launcher/settingspage.cpp +++ b/apps/launcher/settingspage.cpp @@ -260,6 +260,10 @@ void Launcher::SettingsPage::saveSettings() } else { mGameSettings.setValue(QLatin1String("encoding"), QLatin1String("win1252")); } + + QString keepComments(saveCommentsCheckBox->isChecked() ? "true" : "false"); + + mLauncherSettings.setValue(QLatin1String("Settings/keep-comments"), keepComments); } bool Launcher::SettingsPage::loadSettings() @@ -271,5 +275,9 @@ bool Launcher::SettingsPage::loadSettings() if (index != -1) languageComboBox->setCurrentIndex(index); + QString keepComments(mLauncherSettings.value(QLatin1String("Settings/keep-comments"))); + + saveCommentsCheckBox->setChecked(keepComments == "true"); + return true; } diff --git a/files/ui/settingspage.ui b/files/ui/settingspage.ui index 7f5e4a7de..f38ba764c 100644 --- a/files/ui/settingspage.ui +++ b/files/ui/settingspage.ui @@ -40,6 +40,16 @@ + + + + Keep comments in openmw.cfg + + + false + + + From 3bfe167bc09353fd28c7f729b5d9174819bd4b8a Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 13 Jun 2015 23:49:29 +0200 Subject: [PATCH 1514/3725] Revert "Fix loop where there was a potential for double entry." This reverts commit a439f49c4db32a340826ae9b77c940ca59e79e5f. --- components/config/gamesettings.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/components/config/gamesettings.cpp b/components/config/gamesettings.cpp index 9af6c9714..c17a5c4f7 100644 --- a/components/config/gamesettings.cpp +++ b/components/config/gamesettings.cpp @@ -265,10 +265,7 @@ bool Config::GameSettings::writeFileWithComments(QFile &file) // Below is based on readFile() code, if that changes corresponding change may be // required (for example duplicates may be inserted if the rules don't match) if ((*iter).isEmpty() || (*iter).contains(QRegExp("^\\s*#"))) - { stream << *iter << "\n"; - continue; - } if (settingRegex.indexIn(*iter) == -1 || settingRegex.captureCount() < 2) continue; From c54a225467c6e7753dac8bafe6da26b04a8646d5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 13 Jun 2015 23:49:29 +0200 Subject: [PATCH 1515/3725] Revert "Allow space characters in front of comments." This reverts commit 4902c6679210dee8b5158d05d99b072c2f06a494. --- components/config/gamesettings.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/components/config/gamesettings.cpp b/components/config/gamesettings.cpp index c17a5c4f7..c0a3b82d1 100644 --- a/components/config/gamesettings.cpp +++ b/components/config/gamesettings.cpp @@ -180,7 +180,7 @@ bool Config::GameSettings::writeFile(QTextStream &stream) // // - If a line in file exists with matching key and first part of value (before ',', // '\n', etc) also matches, then replace the line with that of mUserSettings. -// - else remove line (TODO: maybe replace the line with '#' in front instead?) +// - else remove line (maybe replace the line with '#' in front instead?) // // - If there is no corresponding line in file, add at the end // @@ -224,10 +224,10 @@ bool Config::GameSettings::writeFileWithComments(QFile &file) } QString keyVal; - for (std::vector::iterator iter = fileCopy.begin(); iter != fileCopy.end(); ++iter) + for (std::vector::iterator iter = fileCopy.begin(); iter != fileCopy.end(); ++iter) { // skip empty or comment lines - if ((*iter).isEmpty() || (*iter).contains(QRegExp("^\\s*#"))) + if ((*iter).isEmpty() || (*iter).startsWith("#")) continue; // look for a key in the line @@ -257,14 +257,12 @@ bool Config::GameSettings::writeFileWithComments(QFile &file) // write the new config file QString key; QString value; - for (std::vector::iterator iter = fileCopy.begin(); iter != fileCopy.end(); ++iter) + for (std::vector::iterator iter = fileCopy.begin(); iter != fileCopy.end(); ++iter) { if ((*iter).isNull()) continue; - // Below is based on readFile() code, if that changes corresponding change may be - // required (for example duplicates may be inserted if the rules don't match) - if ((*iter).isEmpty() || (*iter).contains(QRegExp("^\\s*#"))) + if ((*iter).isEmpty() || (*iter).startsWith("#")) stream << *iter << "\n"; if (settingRegex.indexIn(*iter) == -1 || settingRegex.captureCount() < 2) From de98d991b40fdb54d808521a0ba4c39c44491467 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 13 Jun 2015 23:50:04 +0200 Subject: [PATCH 1516/3725] Revert "Allow comments (lines starting with # character) and blank lines in openmw.cfg. Should resolve Feature #2535." Breaks the saving of content= entry order. This reverts commit 15fe5d88e2b3c7d172a28bd453b3e0d5f89295aa. Conflicts: components/config/gamesettings.cpp --- apps/launcher/maindialog.cpp | 21 +---- apps/launcher/settingspage.cpp | 8 -- components/config/gamesettings.cpp | 128 ----------------------------- components/config/gamesettings.hpp | 2 - files/ui/settingspage.ui | 10 --- 5 files changed, 3 insertions(+), 166 deletions(-) diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index 27d37dbf0..fd36993bf 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -490,16 +490,7 @@ bool Launcher::MainDialog::writeSettings() // Game settings QFile file(userPath + QString("openmw.cfg")); - QIODevice::OpenMode mode(0); - bool keepComments = mLauncherSettings.value(QString("Settings/keep-comments"), QString("true")) - == QLatin1String("true"); - - if (keepComments) - mode = QIODevice::ReadWrite | QIODevice::Text; - else - mode = QIODevice::ReadWrite | QIODevice::Text | QIODevice::Truncate; - - if (!file.open(mode)) { + if (!file.open(QIODevice::ReadWrite | QIODevice::Text | QIODevice::Truncate)) { // File cannot be opened or created QMessageBox msgBox; msgBox.setWindowTitle(tr("Error writing OpenMW configuration file")); @@ -513,15 +504,9 @@ bool Launcher::MainDialog::writeSettings() } QTextStream stream(&file); + stream.setCodec(QTextCodec::codecForName("UTF-8")); - if (keepComments) - mGameSettings.writeFileWithComments(file); - else - { - stream.setCodec(QTextCodec::codecForName("UTF-8")); - mGameSettings.writeFile(stream); - } - + mGameSettings.writeFile(stream); file.close(); // Graphics settings diff --git a/apps/launcher/settingspage.cpp b/apps/launcher/settingspage.cpp index bc8ffe618..843b51391 100644 --- a/apps/launcher/settingspage.cpp +++ b/apps/launcher/settingspage.cpp @@ -260,10 +260,6 @@ void Launcher::SettingsPage::saveSettings() } else { mGameSettings.setValue(QLatin1String("encoding"), QLatin1String("win1252")); } - - QString keepComments(saveCommentsCheckBox->isChecked() ? "true" : "false"); - - mLauncherSettings.setValue(QLatin1String("Settings/keep-comments"), keepComments); } bool Launcher::SettingsPage::loadSettings() @@ -275,9 +271,5 @@ bool Launcher::SettingsPage::loadSettings() if (index != -1) languageComboBox->setCurrentIndex(index); - QString keepComments(mLauncherSettings.value(QLatin1String("Settings/keep-comments"))); - - saveCommentsCheckBox->setChecked(keepComments == "true"); - return true; } diff --git a/components/config/gamesettings.cpp b/components/config/gamesettings.cpp index c0a3b82d1..0481235c7 100644 --- a/components/config/gamesettings.cpp +++ b/components/config/gamesettings.cpp @@ -1,7 +1,6 @@ #include "gamesettings.hpp" #include "launchersettings.hpp" -#include #include #include #include @@ -174,133 +173,6 @@ bool Config::GameSettings::writeFile(QTextStream &stream) return true; } -// Policy: -// -// - Always ignore a line beginning with '#' or empty lines -// -// - If a line in file exists with matching key and first part of value (before ',', -// '\n', etc) also matches, then replace the line with that of mUserSettings. -// - else remove line (maybe replace the line with '#' in front instead?) -// -// - If there is no corresponding line in file, add at the end -// -bool Config::GameSettings::writeFileWithComments(QFile &file) -{ - QTextStream stream(&file); - stream.setCodec(QTextCodec::codecForName("UTF-8")); - - // slurp - std::vector fileCopy; - QString line = stream.readLine(); - while (!line.isNull()) - { - fileCopy.push_back(line); - line = stream.readLine(); - } - stream.seek(0); - - // empty file, no comments to keep - if (fileCopy.empty()) - return writeFile(stream); - - // Temp copy of settings to save, but with the keys appended with the first part of the value - // - // ATTENTION! - // - // A hack to avoid looping through each line, makes use of the fact that fallbacks values - // are comma separated. - QMap userSettingsCopy; - QRegExp settingRegex("^([^=]+)\\s*=\\s*([^,]+)(.*)$"); - QString settingLine; - QMap::const_iterator settingsIter = mUserSettings.begin(); - for (; settingsIter != mUserSettings.end(); ++settingsIter) - { - settingLine = settingsIter.key()+"="+settingsIter.value(); - if (settingRegex.indexIn(settingLine) != -1) - { - userSettingsCopy[settingRegex.cap(1)+"="+settingRegex.cap(2)] = - (settingRegex.captureCount() < 3) ? "" : settingRegex.cap(3); - } - } - - QString keyVal; - for (std::vector::iterator iter = fileCopy.begin(); iter != fileCopy.end(); ++iter) - { - // skip empty or comment lines - if ((*iter).isEmpty() || (*iter).startsWith("#")) - continue; - - // look for a key in the line - if (settingRegex.indexIn(*iter) == -1 || settingRegex.captureCount() < 2) - { - // no key or first part of value found in line, replace with a null string which - // will be remved later - *iter = QString(); - continue; - } - - // look for a matching key in user settings - keyVal = settingRegex.cap(1)+"="+settingRegex.cap(2); - QMap::iterator it = userSettingsCopy.find(keyVal); - if (it == userSettingsCopy.end()) - { - // no such key+valStart, replace with a null string which will be remved later - *iter = QString(); - } - else - { - *iter = QString(it.key()+it.value()); - userSettingsCopy.erase(it); - } - } - - // write the new config file - QString key; - QString value; - for (std::vector::iterator iter = fileCopy.begin(); iter != fileCopy.end(); ++iter) - { - if ((*iter).isNull()) - continue; - - if ((*iter).isEmpty() || (*iter).startsWith("#")) - stream << *iter << "\n"; - - if (settingRegex.indexIn(*iter) == -1 || settingRegex.captureCount() < 2) - continue; - - // Quote paths with spaces - key = settingRegex.cap(1); - value = settingRegex.cap(2)+settingRegex.cap(3); - if (key == QLatin1String("data") - || key == QLatin1String("data-local") - || key == QLatin1String("resources")) - { - if (value.contains(QChar(' '))) - { - value.remove(QChar('\"')); // Remove quotes - - stream << key << "=\"" << value << "\"\n"; - continue; - } - } - stream << key << "=" << value << "\n"; - } - - // new entries - if (!userSettingsCopy.empty()) - { - QMap::const_iterator it = userSettingsCopy.begin(); - for (; it != userSettingsCopy.end(); ++it) - { - stream << it.key() << it.value() << "\n"; - } - } - - file.resize(file.pos()); - - return true; -} - bool Config::GameSettings::hasMaster() { bool result = false; diff --git a/components/config/gamesettings.hpp b/components/config/gamesettings.hpp index 35614113f..cc5033f35 100644 --- a/components/config/gamesettings.hpp +++ b/components/config/gamesettings.hpp @@ -4,7 +4,6 @@ #include #include #include -#include #include #include @@ -67,7 +66,6 @@ namespace Config bool readUserFile(QTextStream &stream); bool writeFile(QTextStream &stream); - bool writeFileWithComments(QFile &file); void setContentList(const QStringList& fileNames); QStringList getContentList() const; diff --git a/files/ui/settingspage.ui b/files/ui/settingspage.ui index f38ba764c..7f5e4a7de 100644 --- a/files/ui/settingspage.ui +++ b/files/ui/settingspage.ui @@ -40,16 +40,6 @@ - - - - Keep comments in openmw.cfg - - - false - - - From bfff84ba8f76aed1f511870e76a0cc3dda631f46 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 14 Jun 2015 10:30:55 +1200 Subject: [PATCH 1517/3725] replaced #include with forward class declaration, as suggested by slaugherfish. --- apps/openmw/mwmechanics/aipackage.hpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/aipackage.hpp b/apps/openmw/mwmechanics/aipackage.hpp index 0370072a4..78a2bfd9f 100644 --- a/apps/openmw/mwmechanics/aipackage.hpp +++ b/apps/openmw/mwmechanics/aipackage.hpp @@ -4,8 +4,6 @@ #include "pathfinding.hpp" #include -#include "../mwworld/cellstore.hpp" - #include "obstacle.hpp" #include "aistate.hpp" @@ -16,6 +14,7 @@ namespace MWWorld namespace ESM { + struct Cell; namespace AiSequence { struct AiSequence; From 28caeadef4b61b9fe6fbf2fdd53c69a38a07d282 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 14 Jun 2015 02:31:00 +0200 Subject: [PATCH 1518/3725] Improve error message for not found records --- apps/openmw/mwworld/store.hpp | 6 +++--- components/esm/loadacti.hpp | 2 ++ components/esm/loadalch.hpp | 3 +++ components/esm/loadappa.hpp | 2 ++ components/esm/loadarmo.hpp | 2 ++ components/esm/loadbody.hpp | 2 ++ components/esm/loadbook.hpp | 2 ++ components/esm/loadbsgn.hpp | 2 ++ components/esm/loadcell.hpp | 2 ++ components/esm/loadclas.hpp | 2 ++ components/esm/loadclot.hpp | 2 ++ components/esm/loadcont.hpp | 2 ++ components/esm/loadcrea.hpp | 2 ++ components/esm/loaddial.hpp | 2 ++ components/esm/loaddoor.hpp | 2 ++ components/esm/loadench.hpp | 2 ++ components/esm/loadfact.hpp | 2 ++ components/esm/loadglob.hpp | 2 ++ components/esm/loadgmst.hpp | 2 ++ components/esm/loadinfo.hpp | 2 ++ components/esm/loadingr.hpp | 2 ++ components/esm/loadland.hpp | 2 ++ components/esm/loadlevlist.hpp | 4 ++++ components/esm/loadligh.hpp | 2 ++ components/esm/loadlock.hpp | 2 ++ components/esm/loadltex.hpp | 2 ++ components/esm/loadmgef.hpp | 2 ++ components/esm/loadmisc.hpp | 2 ++ components/esm/loadnpc.hpp | 2 ++ components/esm/loadpgrd.hpp | 2 ++ components/esm/loadprob.hpp | 2 ++ components/esm/loadrace.hpp | 2 ++ components/esm/loadregn.hpp | 2 ++ components/esm/loadrepa.hpp | 2 ++ components/esm/loadscpt.hpp | 2 ++ components/esm/loadskil.hpp | 2 ++ components/esm/loadsndg.hpp | 2 ++ components/esm/loadsoun.hpp | 2 ++ components/esm/loadspel.hpp | 2 ++ components/esm/loadsscr.hpp | 2 ++ components/esm/loadstat.hpp | 2 ++ components/esm/loadweap.hpp | 2 ++ 42 files changed, 88 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index ba8be733a..ab09782b1 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -188,7 +188,7 @@ namespace MWWorld const T *ptr = search(id); if (ptr == 0) { std::ostringstream msg; - msg << "Object '" << id << "' not found (const)"; + msg << T::getRecordType() << " '" << id << "' not found"; throw std::runtime_error(msg.str()); } return ptr; @@ -202,7 +202,7 @@ namespace MWWorld if(ptr == 0) { std::ostringstream msg; - msg << "Object starting with '"< CellRefTracker; struct Cell { static unsigned int sRecordId; + /// Return a string descriptor for this record type. Currently used for debugging / error logs only. + static std::string getRecordType() { return "Cell"; } enum Flags { diff --git a/components/esm/loadclas.hpp b/components/esm/loadclas.hpp index 3e489bb58..972b48e88 100644 --- a/components/esm/loadclas.hpp +++ b/components/esm/loadclas.hpp @@ -18,6 +18,8 @@ class ESMWriter; struct Class { static unsigned int sRecordId; + /// Return a string descriptor for this record type. Currently used for debugging / error logs only. + static std::string getRecordType() { return "Class"; } enum AutoCalc { diff --git a/components/esm/loadclot.hpp b/components/esm/loadclot.hpp index 50896622a..6945f224a 100644 --- a/components/esm/loadclot.hpp +++ b/components/esm/loadclot.hpp @@ -18,6 +18,8 @@ class ESMWriter; struct Clothing { static unsigned int sRecordId; + /// Return a string descriptor for this record type. Currently used for debugging / error logs only. + static std::string getRecordType() { return "Clothing"; } enum Type { diff --git a/components/esm/loadcont.hpp b/components/esm/loadcont.hpp index 76c522d74..ab587f935 100644 --- a/components/esm/loadcont.hpp +++ b/components/esm/loadcont.hpp @@ -36,6 +36,8 @@ struct InventoryList struct Container { static unsigned int sRecordId; + /// Return a string descriptor for this record type. Currently used for debugging / error logs only. + static std::string getRecordType() { return "Container"; } enum Flags { diff --git a/components/esm/loadcrea.hpp b/components/esm/loadcrea.hpp index 1b02aa0ab..47e5954a5 100644 --- a/components/esm/loadcrea.hpp +++ b/components/esm/loadcrea.hpp @@ -22,6 +22,8 @@ class ESMWriter; struct Creature { static unsigned int sRecordId; + /// Return a string descriptor for this record type. Currently used for debugging / error logs only. + static std::string getRecordType() { return "Creature"; } // Default is 0x48? enum Flags diff --git a/components/esm/loaddial.hpp b/components/esm/loaddial.hpp index d29948c63..58598d353 100644 --- a/components/esm/loaddial.hpp +++ b/components/esm/loaddial.hpp @@ -21,6 +21,8 @@ class ESMWriter; struct Dialogue { static unsigned int sRecordId; + /// Return a string descriptor for this record type. Currently used for debugging / error logs only. + static std::string getRecordType() { return "Dialogue"; } enum Type { diff --git a/components/esm/loaddoor.hpp b/components/esm/loaddoor.hpp index ee2b7f7ac..3073f4e9d 100644 --- a/components/esm/loaddoor.hpp +++ b/components/esm/loaddoor.hpp @@ -12,6 +12,8 @@ class ESMWriter; struct Door { static unsigned int sRecordId; + /// Return a string descriptor for this record type. Currently used for debugging / error logs only. + static std::string getRecordType() { return "Door"; } std::string mId, mName, mModel, mScript, mOpenSound, mCloseSound; diff --git a/components/esm/loadench.hpp b/components/esm/loadench.hpp index 3b7746812..cfcdd4edc 100644 --- a/components/esm/loadench.hpp +++ b/components/esm/loadench.hpp @@ -18,6 +18,8 @@ class ESMWriter; struct Enchantment { static unsigned int sRecordId; + /// Return a string descriptor for this record type. Currently used for debugging / error logs only. + static std::string getRecordType() { return "Enchantment"; } enum Type { diff --git a/components/esm/loadfact.hpp b/components/esm/loadfact.hpp index d31670fe2..8645e23fd 100644 --- a/components/esm/loadfact.hpp +++ b/components/esm/loadfact.hpp @@ -30,6 +30,8 @@ struct RankData struct Faction { static unsigned int sRecordId; + /// Return a string descriptor for this record type. Currently used for debugging / error logs only. + static std::string getRecordType() { return "Faction"; } std::string mId, mName; diff --git a/components/esm/loadglob.hpp b/components/esm/loadglob.hpp index 51b2e2dc9..cc5dbbdcf 100644 --- a/components/esm/loadglob.hpp +++ b/components/esm/loadglob.hpp @@ -18,6 +18,8 @@ class ESMWriter; struct Global { static unsigned int sRecordId; + /// Return a string descriptor for this record type. Currently used for debugging / error logs only. + static std::string getRecordType() { return "Global"; } std::string mId; Variant mValue; diff --git a/components/esm/loadgmst.hpp b/components/esm/loadgmst.hpp index 398b8047f..d9d9048b6 100644 --- a/components/esm/loadgmst.hpp +++ b/components/esm/loadgmst.hpp @@ -19,6 +19,8 @@ class ESMWriter; struct GameSetting { static unsigned int sRecordId; + /// Return a string descriptor for this record type. Currently used for debugging / error logs only. + static std::string getRecordType() { return "GameSetting"; } std::string mId; diff --git a/components/esm/loadinfo.hpp b/components/esm/loadinfo.hpp index 59b1af31a..54003b0d9 100644 --- a/components/esm/loadinfo.hpp +++ b/components/esm/loadinfo.hpp @@ -21,6 +21,8 @@ class ESMWriter; struct DialInfo { static unsigned int sRecordId; + /// Return a string descriptor for this record type. Currently used for debugging / error logs only. + static std::string getRecordType() { return "DialInfo"; } enum Gender { diff --git a/components/esm/loadingr.hpp b/components/esm/loadingr.hpp index 85f2d5e7d..5846a9780 100644 --- a/components/esm/loadingr.hpp +++ b/components/esm/loadingr.hpp @@ -16,6 +16,8 @@ class ESMWriter; struct Ingredient { static unsigned int sRecordId; + /// Return a string descriptor for this record type. Currently used for debugging / error logs only. + static std::string getRecordType() { return "Ingredient"; } struct IRDTstruct { diff --git a/components/esm/loadland.hpp b/components/esm/loadland.hpp index e510616af..7dc5e8adb 100644 --- a/components/esm/loadland.hpp +++ b/components/esm/loadland.hpp @@ -18,6 +18,8 @@ class ESMWriter; struct Land { static unsigned int sRecordId; + /// Return a string descriptor for this record type. Currently used for debugging / error logs only. + static std::string getRecordType() { return "Land"; } Land(); ~Land(); diff --git a/components/esm/loadlevlist.hpp b/components/esm/loadlevlist.hpp index bcea2b234..dc6fcda5e 100644 --- a/components/esm/loadlevlist.hpp +++ b/components/esm/loadlevlist.hpp @@ -46,6 +46,8 @@ struct LevelledListBase struct CreatureLevList: LevelledListBase { static unsigned int sRecordId; + /// Return a string descriptor for this record type. Currently used for debugging / error logs only. + static std::string getRecordType() { return "CreatureLevList"; } enum Flags { @@ -64,6 +66,8 @@ struct CreatureLevList: LevelledListBase struct ItemLevList: LevelledListBase { static unsigned int sRecordId; + /// Return a string descriptor for this record type. Currently used for debugging / error logs only. + static std::string getRecordType() { return "ItemLevList"; } enum Flags { diff --git a/components/esm/loadligh.hpp b/components/esm/loadligh.hpp index 2c83248f8..ed8c36665 100644 --- a/components/esm/loadligh.hpp +++ b/components/esm/loadligh.hpp @@ -17,6 +17,8 @@ class ESMWriter; struct Light { static unsigned int sRecordId; + /// Return a string descriptor for this record type. Currently used for debugging / error logs only. + static std::string getRecordType() { return "Light"; } enum Flags { diff --git a/components/esm/loadlock.hpp b/components/esm/loadlock.hpp index c44e2b006..0d678cd64 100644 --- a/components/esm/loadlock.hpp +++ b/components/esm/loadlock.hpp @@ -12,6 +12,8 @@ class ESMWriter; struct Lockpick { static unsigned int sRecordId; + /// Return a string descriptor for this record type. Currently used for debugging / error logs only. + static std::string getRecordType() { return "Lockpick"; } struct Data { diff --git a/components/esm/loadltex.hpp b/components/esm/loadltex.hpp index 8b45f8211..50a788105 100644 --- a/components/esm/loadltex.hpp +++ b/components/esm/loadltex.hpp @@ -28,6 +28,8 @@ class ESMWriter; struct LandTexture { static unsigned int sRecordId; + /// Return a string descriptor for this record type. Currently used for debugging / error logs only. + static std::string getRecordType() { return "LandTexture"; } std::string mId, mTexture; int mIndex; diff --git a/components/esm/loadmgef.hpp b/components/esm/loadmgef.hpp index e66322832..32b8a85a6 100644 --- a/components/esm/loadmgef.hpp +++ b/components/esm/loadmgef.hpp @@ -13,6 +13,8 @@ class ESMWriter; struct MagicEffect { static unsigned int sRecordId; + /// Return a string descriptor for this record type. Currently used for debugging / error logs only. + static std::string getRecordType() { return "MagicEffect"; } std::string mId; diff --git a/components/esm/loadmisc.hpp b/components/esm/loadmisc.hpp index 576bd18c0..6e0b4e01b 100644 --- a/components/esm/loadmisc.hpp +++ b/components/esm/loadmisc.hpp @@ -17,6 +17,8 @@ class ESMWriter; struct Miscellaneous { static unsigned int sRecordId; + /// Return a string descriptor for this record type. Currently used for debugging / error logs only. + static std::string getRecordType() { return "Miscellaneous"; } struct MCDTstruct { diff --git a/components/esm/loadnpc.hpp b/components/esm/loadnpc.hpp index b535b91b0..e8867110c 100644 --- a/components/esm/loadnpc.hpp +++ b/components/esm/loadnpc.hpp @@ -23,6 +23,8 @@ class ESMWriter; struct NPC { static unsigned int sRecordId; + /// Return a string descriptor for this record type. Currently used for debugging / error logs only. + static std::string getRecordType() { return "NPC"; } // Services enum Services diff --git a/components/esm/loadpgrd.hpp b/components/esm/loadpgrd.hpp index 256b86cda..f33ccbedf 100644 --- a/components/esm/loadpgrd.hpp +++ b/components/esm/loadpgrd.hpp @@ -16,6 +16,8 @@ class ESMWriter; struct Pathgrid { static unsigned int sRecordId; + /// Return a string descriptor for this record type. Currently used for debugging / error logs only. + static std::string getRecordType() { return "Pathgrid"; } struct DATAstruct { diff --git a/components/esm/loadprob.hpp b/components/esm/loadprob.hpp index b89b2ddeb..c737757aa 100644 --- a/components/esm/loadprob.hpp +++ b/components/esm/loadprob.hpp @@ -12,6 +12,8 @@ class ESMWriter; struct Probe { static unsigned int sRecordId; + /// Return a string descriptor for this record type. Currently used for debugging / error logs only. + static std::string getRecordType() { return "Probe"; } struct Data { diff --git a/components/esm/loadrace.hpp b/components/esm/loadrace.hpp index 7d5736d9b..553d2e68b 100644 --- a/components/esm/loadrace.hpp +++ b/components/esm/loadrace.hpp @@ -18,6 +18,8 @@ class ESMWriter; struct Race { static unsigned int sRecordId; + /// Return a string descriptor for this record type. Currently used for debugging / error logs only. + static std::string getRecordType() { return "Race"; } struct SkillBonus { diff --git a/components/esm/loadregn.hpp b/components/esm/loadregn.hpp index c231b6aa0..1e241fffb 100644 --- a/components/esm/loadregn.hpp +++ b/components/esm/loadregn.hpp @@ -19,6 +19,8 @@ class ESMWriter; struct Region { static unsigned int sRecordId; + /// Return a string descriptor for this record type. Currently used for debugging / error logs only. + static std::string getRecordType() { return "Region"; } #pragma pack(push) #pragma pack(1) diff --git a/components/esm/loadrepa.hpp b/components/esm/loadrepa.hpp index 5b404b0e4..e765bc93a 100644 --- a/components/esm/loadrepa.hpp +++ b/components/esm/loadrepa.hpp @@ -12,6 +12,8 @@ class ESMWriter; struct Repair { static unsigned int sRecordId; + /// Return a string descriptor for this record type. Currently used for debugging / error logs only. + static std::string getRecordType() { return "Repair"; } struct Data { diff --git a/components/esm/loadscpt.hpp b/components/esm/loadscpt.hpp index deb71de6a..56390f384 100644 --- a/components/esm/loadscpt.hpp +++ b/components/esm/loadscpt.hpp @@ -20,6 +20,8 @@ class Script { public: static unsigned int sRecordId; + /// Return a string descriptor for this record type. Currently used for debugging / error logs only. + static std::string getRecordType() { return "Script"; } struct SCHDstruct { diff --git a/components/esm/loadskil.hpp b/components/esm/loadskil.hpp index 1b9db5bcf..e00184297 100644 --- a/components/esm/loadskil.hpp +++ b/components/esm/loadskil.hpp @@ -20,6 +20,8 @@ class ESMWriter; struct Skill { static unsigned int sRecordId; + /// Return a string descriptor for this record type. Currently used for debugging / error logs only. + static std::string getRecordType() { return "Skill"; } std::string mId; diff --git a/components/esm/loadsndg.hpp b/components/esm/loadsndg.hpp index f89a11208..056958f0a 100644 --- a/components/esm/loadsndg.hpp +++ b/components/esm/loadsndg.hpp @@ -16,6 +16,8 @@ class ESMWriter; struct SoundGenerator { static unsigned int sRecordId; + /// Return a string descriptor for this record type. Currently used for debugging / error logs only. + static std::string getRecordType() { return "SoundGenerator"; } enum Type { diff --git a/components/esm/loadsoun.hpp b/components/esm/loadsoun.hpp index 04a0984fd..ff2202ca7 100644 --- a/components/esm/loadsoun.hpp +++ b/components/esm/loadsoun.hpp @@ -17,6 +17,8 @@ struct SOUNstruct struct Sound { static unsigned int sRecordId; + /// Return a string descriptor for this record type. Currently used for debugging / error logs only. + static std::string getRecordType() { return "Sound"; } SOUNstruct mData; std::string mId, mSound; diff --git a/components/esm/loadspel.hpp b/components/esm/loadspel.hpp index 4bd2210ec..491da1d17 100644 --- a/components/esm/loadspel.hpp +++ b/components/esm/loadspel.hpp @@ -14,6 +14,8 @@ class ESMWriter; struct Spell { static unsigned int sRecordId; + /// Return a string descriptor for this record type. Currently used for debugging / error logs only. + static std::string getRecordType() { return "Spell"; } enum SpellType { diff --git a/components/esm/loadsscr.hpp b/components/esm/loadsscr.hpp index 1420d16c4..dc7ad6a42 100644 --- a/components/esm/loadsscr.hpp +++ b/components/esm/loadsscr.hpp @@ -20,6 +20,8 @@ class ESMWriter; struct StartScript { static unsigned int sRecordId; + /// Return a string descriptor for this record type. Currently used for debugging / error logs only. + static std::string getRecordType() { return "StartScript"; } std::string mData; std::string mId; diff --git a/components/esm/loadstat.hpp b/components/esm/loadstat.hpp index 45b05136a..21a9e66e8 100644 --- a/components/esm/loadstat.hpp +++ b/components/esm/loadstat.hpp @@ -23,6 +23,8 @@ class ESMWriter; struct Static { static unsigned int sRecordId; + /// Return a string descriptor for this record type. Currently used for debugging / error logs only. + static std::string getRecordType() { return "Static"; } std::string mId, mModel; diff --git a/components/esm/loadweap.hpp b/components/esm/loadweap.hpp index 14ddb4708..f66e9f3a6 100644 --- a/components/esm/loadweap.hpp +++ b/components/esm/loadweap.hpp @@ -16,6 +16,8 @@ class ESMWriter; struct Weapon { static unsigned int sRecordId; + /// Return a string descriptor for this record type. Currently used for debugging / error logs only. + static std::string getRecordType() { return "Weapon"; } enum Type { From 520fbd63c4a50a56b79a49bd90b8da6f10c2e26a Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 14 Jun 2015 15:14:02 +1200 Subject: [PATCH 1519/3725] simplified pathfinding code. remove mIsPathConstructed. Instead call !mPath.empty(). --- apps/openmw/mwmechanics/pathfinding.cpp | 17 ++--------------- apps/openmw/mwmechanics/pathfinding.hpp | 4 +--- 2 files changed, 3 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index 980de1bad..fea993e23 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -114,8 +114,7 @@ namespace MWMechanics } PathFinder::PathFinder() - : mIsPathConstructed(false), - mPathgrid(NULL), + : mPathgrid(NULL), mCell(NULL) { } @@ -124,7 +123,6 @@ namespace MWMechanics { if(!mPath.empty()) mPath.clear(); - mIsPathConstructed = false; } /* @@ -180,7 +178,6 @@ namespace MWMechanics static_cast(endPoint.mX), static_cast(endPoint.mY), static_cast(endPoint.mZ))) { mPath.push_back(endPoint); - mIsPathConstructed = true; return; } } @@ -197,7 +194,6 @@ namespace MWMechanics if(!mPathgrid || mPathgrid->mPoints.empty()) { mPath.push_back(endPoint); - mIsPathConstructed = true; return; } @@ -235,7 +231,6 @@ namespace MWMechanics if(startNode == endNode.first) { mPath.push_back(endPoint); - mIsPathConstructed = true; return; } @@ -243,7 +238,6 @@ namespace MWMechanics if(!mPath.empty()) { - mIsPathConstructed = true; // Add the destination (which may be different to the closest // pathgrid point). However only add if endNode was the closest // point to endPoint. @@ -256,14 +250,8 @@ namespace MWMechanics if(endNode.second) mPath.push_back(endPoint); } - else - mIsPathConstructed = false; } - else - mIsPathConstructed = false; } - else - mIsPathConstructed = false; return; } @@ -271,7 +259,7 @@ namespace MWMechanics 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). + // isPathConstructed that prevents this call if otherwise). if(mPath.empty()) return 0.; @@ -293,7 +281,6 @@ namespace MWMechanics mPath.pop_front(); if(mPath.empty()) { - mIsPathConstructed = false; return true; } } diff --git a/apps/openmw/mwmechanics/pathfinding.hpp b/apps/openmw/mwmechanics/pathfinding.hpp index 0f52a6e19..644d79236 100644 --- a/apps/openmw/mwmechanics/pathfinding.hpp +++ b/apps/openmw/mwmechanics/pathfinding.hpp @@ -48,7 +48,7 @@ namespace MWMechanics bool isPathConstructed() const { - return mIsPathConstructed; + return !mPath.empty(); } int getPathSize() const @@ -96,8 +96,6 @@ namespace MWMechanics private: - bool mIsPathConstructed; - std::list mPath; const ESM::Pathgrid *mPathgrid; From 0efe8f5465d652d42a7191d8a7c5223dfa711466 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 14 Jun 2015 14:42:08 +1000 Subject: [PATCH 1520/3725] Fix broken launcher build for windows. --- apps/launcher/CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/launcher/CMakeLists.txt b/apps/launcher/CMakeLists.txt index 66cc157d3..3c7b39314 100644 --- a/apps/launcher/CMakeLists.txt +++ b/apps/launcher/CMakeLists.txt @@ -100,6 +100,9 @@ target_link_libraries(openmw-launcher if (DESIRED_QT_VERSION MATCHES 4) target_link_libraries(openmw-launcher ${QT_QTGUI_LIBRARY} ${QT_QTCORE_LIBRARY}) + if(WIN32) + target_link_libraries(openmw-launcher ${QT_QTMAIN_LIBRARY}) + endif(WIN32) else() qt5_use_modules(openmw-launcher Widgets Core) endif() From c22c9c271d6cfab22ac2f6c35714eeb266b2fa0c Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 14 Jun 2015 14:51:01 +1000 Subject: [PATCH 1521/3725] Allow comments (lines starting with # character) and blank lines in openmw.cfg. Should resolve Feature #2535. - allows moving various config entries up or down - comment lines above config entries stay as a pair --- apps/launcher/maindialog.cpp | 7 +- components/config/gamesettings.cpp | 209 +++++++++++++++++++++++++++++ components/config/gamesettings.hpp | 4 + 3 files changed, 216 insertions(+), 4 deletions(-) diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index fd36993bf..2f7a9db33 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -490,7 +490,7 @@ bool Launcher::MainDialog::writeSettings() // Game settings QFile file(userPath + QString("openmw.cfg")); - if (!file.open(QIODevice::ReadWrite | QIODevice::Text | QIODevice::Truncate)) { + if (!file.open(QIODevice::ReadWrite | QIODevice::Text)) { // File cannot be opened or created QMessageBox msgBox; msgBox.setWindowTitle(tr("Error writing OpenMW configuration file")); @@ -503,10 +503,8 @@ bool Launcher::MainDialog::writeSettings() return false; } - QTextStream stream(&file); - stream.setCodec(QTextCodec::codecForName("UTF-8")); - mGameSettings.writeFile(stream); + mGameSettings.writeFileWithComments(file); file.close(); // Graphics settings @@ -525,6 +523,7 @@ bool Launcher::MainDialog::writeSettings() return false; } + QTextStream stream(&file); stream.setDevice(&file); stream.setCodec(QTextCodec::codecForName("UTF-8")); diff --git a/components/config/gamesettings.cpp b/components/config/gamesettings.cpp index 0481235c7..4339369cf 100644 --- a/components/config/gamesettings.cpp +++ b/components/config/gamesettings.cpp @@ -1,6 +1,7 @@ #include "gamesettings.hpp" #include "launchersettings.hpp" +#include #include #include #include @@ -173,6 +174,214 @@ bool Config::GameSettings::writeFile(QTextStream &stream) return true; } +bool Config::GameSettings::isOrderedLine(const QString& line) const +{ + return line.contains(QRegExp("^\\s*fallback-archive\\s*=")) + || line.contains(QRegExp("^\\s*fallback\\s*=")) + || line.contains(QRegExp("^\\s*data\\s*=")) + || line.contains(QRegExp("^\\s*data-local\\s*=")) + || line.contains(QRegExp("^\\s*resources\\s*=")) + || line.contains(QRegExp("^\\s*content\\s*=")); +} + +// Policy: +// +// - Always ignore a line beginning with '#' or empty lines; added above a config +// entry. +// +// - If a line in file exists with matching key and first part of value (before ',', +// '\n', etc) also matches, then replace the line with that of mUserSettings. +// - else remove line +// +// - If there is no corresponding line in file, add at the end +// +bool Config::GameSettings::writeFileWithComments(QFile &file) +{ + QTextStream stream(&file); + stream.setCodec(QTextCodec::codecForName("UTF-8")); + + // slurp + std::vector fileCopy; + QString line = stream.readLine(); + while (!line.isNull()) + { + fileCopy.push_back(line); + line = stream.readLine(); + } + stream.seek(0); + + // empty file, no comments to keep + if (fileCopy.empty()) + return writeFile(stream); + + // start + // | + // | +----------------------------------------------------------+ + // | | | + // v v | + // skip non-"ordered" lines (remove "ordered" lines) | + // | ^ | + // | | | + // | non-"ordered" line, write saved comments | + // | ^ | + // v | | + // blank or comment line, save in temp buffer <--------+ | + // | | | | + // v +------- comment line ------+ | + // "ordered" line | + // | | + // v | + // save in a separate map of comments keyed by "ordered" line | + // | | + // +----------------------------------------------------------+ + // + // + QRegExp settingRegex("^([^=]+)\\s*=\\s*([^,]+)(.*)$"); + std::vector comments; + std::vector::iterator commentStart = fileCopy.end(); + std::map > commentsMap; + for (std::vector::iterator iter = fileCopy.begin(); iter != fileCopy.end(); ++iter) + { + if (isOrderedLine(*iter)) + { + // save in a separate map of comments keyed by "ordered" line + if (!comments.empty()) + { + if (settingRegex.indexIn(*iter) != -1) + { + commentsMap[settingRegex.cap(1)+"="+settingRegex.cap(2)] = comments; + comments.clear(); + commentStart = fileCopy.end(); + } + // else do nothing, malformed line + } + + *iter = QString(); // "ordered" lines to be removed later + } + else if ((*iter).isEmpty() || (*iter).contains(QRegExp("^\\s*#"))) + { + // comment line, save in temp buffer + if (comments.empty()) + commentStart = iter; + comments.push_back(*iter); + *iter = QString(); // assume to be deleted later + } + else + { + int index = settingRegex.indexIn(*iter); + + // blank or non-"ordered" line, write saved comments + if (!comments.empty() && index != -1 && settingRegex.captureCount() >= 2 && + mUserSettings.find(settingRegex.cap(1)) != mUserSettings.end()) + { + for (std::vector::const_iterator it = comments.begin(); it != comments.end(); ++it) + { + *commentStart = *it; + ++commentStart; + } + comments.clear(); + commentStart = fileCopy.end(); + } + + // keep blank lines and non-"ordered" lines other than comments + + // look for a key in the line + if (index == -1 || settingRegex.captureCount() < 2) + { + // no key or first part of value found in line, replace with a null string which + // will be remved later + *iter = QString(); + comments.clear(); + commentStart = fileCopy.end(); + continue; + } + + // look for a matching key in user settings + *iter = QString(); // assume no match + QString key = settingRegex.cap(1); + QString keyVal = settingRegex.cap(1)+"="+settingRegex.cap(2); + QMap::const_iterator i = mUserSettings.find(key); + while (i != mUserSettings.end() && i.key() == key) + { + QString settingLine = i.key() + "=" + i.value(); + if (settingRegex.indexIn(settingLine) != -1) + { + if ((settingRegex.cap(1)+"="+settingRegex.cap(2)) == keyVal) + { + *iter = settingLine; + break; + } + } + ++i; + } + } + } + + // comments at top of file + for (std::vector::iterator iter = fileCopy.begin(); iter != fileCopy.end(); ++iter) + { + if ((*iter).isNull()) + continue; + + // Below is based on readFile() code, if that changes corresponding change may be + // required (for example duplicates may be inserted if the rules don't match) + if (/*(*iter).isEmpty() ||*/ (*iter).contains(QRegExp("^\\s*#"))) + { + stream << *iter << "\n"; + continue; + } + } + + // Iterate in reverse order to preserve insertion order + QString settingLine; + QMapIterator it(mUserSettings); + it.toBack(); + + while (it.hasPrevious()) + { + it.previous(); + + // Quote paths with spaces + if ((it.key() == QLatin1String("data") + || it.key() == QLatin1String("data-local") + || it.key() == QLatin1String("resources")) && it.value().contains(QChar(' '))) + { + QString stripped = it.value(); + stripped.remove(QChar('\"')); // Remove quotes + + settingLine = it.key() + "=\"" + stripped + "\""; + } + else + settingLine = it.key() + "=" + it.value(); + + if (settingRegex.indexIn(settingLine) != -1) + { + std::map >::const_iterator i = + commentsMap.find(settingRegex.cap(1)+"="+settingRegex.cap(2)); + + if (i != commentsMap.end()) + { + std::vector cLines = i->second; + for (std::vector::const_iterator ci = cLines.begin(); ci != cLines.end(); ++ci) + stream << *ci << "\n"; + } + } + + stream << settingLine << "\n"; + } + + // flush any end comments + if (!comments.empty()) + { + for (std::vector::const_iterator ci = comments.begin(); ci != comments.end(); ++ci) + stream << *ci << "\n"; + } + + file.resize(file.pos()); + + return true; +} + bool Config::GameSettings::hasMaster() { bool result = false; diff --git a/components/config/gamesettings.hpp b/components/config/gamesettings.hpp index cc5033f35..992a3e565 100644 --- a/components/config/gamesettings.hpp +++ b/components/config/gamesettings.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -66,6 +67,7 @@ namespace Config bool readUserFile(QTextStream &stream); bool writeFile(QTextStream &stream); + bool writeFileWithComments(QFile &file); void setContentList(const QStringList& fileNames); QStringList getContentList() const; @@ -81,6 +83,8 @@ namespace Config QString mDataLocal; static const char sContentKey[]; + + bool isOrderedLine(const QString& line) const; }; } #endif // GAMESETTINGS_HPP From 195e1a84102ab994d395001dfcf69bd6323e09ec Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 14 Jun 2015 15:27:33 +0200 Subject: [PATCH 1522/3725] Fix the Viewer's FrameStamp not being set correctly during Engine::frame --- apps/openmw/engine.cpp | 25 +++++++++++++++---------- apps/openmw/engine.hpp | 4 +--- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 01ecd3d11..f8382f860 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -82,7 +82,7 @@ void OMW::Engine::executeLocalScripts() localScripts.setIgnore (MWWorld::Ptr()); } -double OMW::Engine::frame(float frametime) +void OMW::Engine::frame(float frametime) { try { @@ -101,17 +101,14 @@ double OMW::Engine::frame(float frametime) if (mUseSound) MWBase::Environment::get().getSoundManager()->update(frametime); - // GUI active? Most game processing will be paused, but scripts still run. - bool guiActive = MWBase::Environment::get().getWindowManager()->isGuiMode(); - if (!guiActive) - mSimulationTime += frametime; - // Main menu opened? Then scripts are also paused. bool paused = MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_MainMenu); // update game state MWBase::Environment::get().getStateManager()->update (frametime); + bool guiActive = MWBase::Environment::get().getWindowManager()->isGuiMode(); + osg::Timer_t beforeScriptTick = osg::Timer::instance()->tick(); if (MWBase::Environment::get().getStateManager()->getState()== MWBase::StateManager::State_Running) @@ -193,7 +190,6 @@ double OMW::Engine::frame(float frametime) { std::cerr << "Error in framelistener: " << e.what() << std::endl; } - return mSimulationTime; } OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) @@ -214,7 +210,6 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) , mFSStrict (false) , mScriptBlacklistUse (true) , mNewGame (false) - , mSimulationTime(0.0) , mCfgMgr(configurationManager) { Misc::Rng::init(); @@ -679,14 +674,24 @@ void OMW::Engine::go() // Start the main rendering loop osg::Timer frameTimer; + double simulationTime = 0.0; while (!mViewer->done() && !MWBase::Environment::get().getStateManager()->hasQuitRequest()) { double dt = frameTimer.time_s(); frameTimer.setStartTick(); dt = std::min(dt, 0.2); - double simulationTime = frame(dt); - mViewer->frame(simulationTime); + bool guiActive = MWBase::Environment::get().getWindowManager()->isGuiMode(); + if (!guiActive) + simulationTime += dt; + + mViewer->advance(simulationTime); + + frame(dt); + + mViewer->eventTraversal(); + mViewer->updateTraversal(); + mViewer->renderingTraversals(); } // Save user settings diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index 8ac6098b8..73de57dc4 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -106,7 +106,6 @@ namespace OMW bool mNewGame; osg::Timer_t mStartTick; - double mSimulationTime; // not implemented Engine (const Engine&); @@ -114,8 +113,7 @@ namespace OMW void executeLocalScripts(); - /// @return The new simulationTime - double frame (float dt); + void frame (float dt); /// Load settings from various files, returns the path to the user settings file std::string loadSettings (Settings::Manager & settings); From 2476cd4f9a2b0ea3ca23bbd6370284bd98015a75 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 14 Jun 2015 16:12:18 +0200 Subject: [PATCH 1523/3725] Error message fix --- apps/openmw/mwworld/scene.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 62bc1f47e..76c2f6eba 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -560,7 +560,7 @@ namespace MWWorld } catch (std::exception& e) { - std::cerr << "error during rendering: " << e.what() << std::endl; + std::cerr << "error during rendering '" << ptr.getCellRef().getRefId() << "': " << e.what() << std::endl; } } From 9fc2c2e8ee2fa7aedcd254d647e4650433e227e8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 14 Jun 2015 16:32:34 +0200 Subject: [PATCH 1524/3725] Don't advertise an alpha channel in GraphicsContext::traits (Bug #2677) --- apps/openmw/engine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index f8382f860..dc2cb8f37 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -393,7 +393,7 @@ void OMW::Engine::createWindow(Settings::Manager& settings) traits->red = 8; traits->green = 8; traits->blue = 8; - traits->alpha = 8; + traits->alpha = 0; // set to 0 to stop ScreenCaptureHandler reading the alpha channel traits->depth = 24; traits->stencil = 8; traits->vsync = vsync; From 30de47f858dc98ba2ecd8c2657ad33584585e440 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 14 Jun 2015 17:12:14 +0200 Subject: [PATCH 1525/3725] Reduce the number of jobs in .travis.yml Hopefully this fixes the occasional out-of-memory problems. Note travis-CI virtual machines just have 2 virtual cores according to http://docs.travis-ci.com/user/ci-environment/, so 4 jobs wouldn't improve build times anyway. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 1fc85dca3..6b03be114 100644 --- a/.travis.yml +++ b/.travis.yml @@ -38,7 +38,7 @@ before_script: - if [ "${TRAVIS_OS_NAME}" = "osx" ]; then ./CI/before_script.osx.sh; fi script: - cd ./build - - if [ "$COVERITY_SCAN_BRANCH" != 1 ]; then ${ANALYZE}make -j4; fi + - if [ "$COVERITY_SCAN_BRANCH" != 1 ]; then ${ANALYZE}make -j2; fi - if [ "$COVERITY_SCAN_BRANCH" != 1 ] && [ "${TRAVIS_OS_NAME}" = "osx" ]; then make package; fi after_script: - if [ "${TRAVIS_OS_NAME}" = "linux" ]; then ./openmw_test_suite; fi From b90fc8ad921e89059e7568523a7d15b237152ad9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 14 Jun 2015 18:19:53 +0200 Subject: [PATCH 1526/3725] Fix for various Viewer::frame calls resetting the simulationTime --- apps/openmw/mwgui/loadingscreen.cpp | 2 +- apps/openmw/mwgui/windowmanagerimp.cpp | 4 ++-- apps/openmw/mwrender/renderingmanager.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index 774faa003..7e733686d 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -259,7 +259,7 @@ namespace MWGui MWBase::Environment::get().getInputManager()->update(0, true, true); //osg::Timer timer; - mViewer->frame(); + mViewer->frame(mViewer->getFrameStamp()->getSimulationTime()); //std::cout << "frame took " << timer.time_m() << std::endl; //if (mViewer->getIncrementalCompileOperation()) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 298d4812e..515265bd9 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -851,7 +851,7 @@ namespace MWGui mMessageBoxManager->onFrame(0.f); MWBase::Environment::get().getInputManager()->update(0, true, false); - mViewer->frame(); + mViewer->frame(mViewer->getFrameStamp()->getSimulationTime()); } } } @@ -1744,7 +1744,7 @@ namespace MWGui { MWBase::Environment::get().getInputManager()->update(0, true, false); - mViewer->frame(); + mViewer->frame(mViewer->getFrameStamp()->getSimulationTime()); } mVideoWidget->stop(); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index c8080cf16..4db776783 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -432,7 +432,7 @@ namespace MWRender mRootNode->addChild(rttCamera); - mViewer->frame(); + mViewer->frame(mViewer->getFrameStamp()->getSimulationTime()); // The draw needs to complete before we can copy back our image. osg::ref_ptr callback (new NotifyDrawCompletedCallback); From 412e001edbce3fcbd9a2a26eb786946d0d242279 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 14 Jun 2015 19:19:23 +0200 Subject: [PATCH 1527/3725] Fix simulation time reset in OpenCS when opening a new view --- apps/opencs/view/render/scenewidget.cpp | 5 ++++- apps/opencs/view/render/scenewidget.hpp | 4 ++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index 6136abb40..208a7a5b7 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -95,6 +95,7 @@ void RenderWidget::setVisibilityMask(int mask) // -------------------------------------------------- CompositeViewer::CompositeViewer() + : mSimulationTime(0.0) { #if QT_VERSION >= 0x050000 // Qt5 is currently crashing and reporting "Cannot make QOpenGLContext current in a different thread" when the viewer is run multi-threaded, this is regression from Qt4 @@ -124,7 +125,9 @@ CompositeViewer &CompositeViewer::get() void CompositeViewer::update() { - frame(); + mSimulationTime += mFrameTimer.time_s(); + mFrameTimer.setStartTick(); + frame(mSimulationTime); } // --------------------------------------------------- diff --git a/apps/opencs/view/render/scenewidget.hpp b/apps/opencs/view/render/scenewidget.hpp index 58c376418..c269f355d 100644 --- a/apps/opencs/view/render/scenewidget.hpp +++ b/apps/opencs/view/render/scenewidget.hpp @@ -100,6 +100,10 @@ namespace CSVRender QTimer mTimer; + private: + osg::Timer mFrameTimer; + double mSimulationTime; + public slots: void update(); }; From 98571148b0937e22610abc17e1b37415a80a76aa Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 14 Jun 2015 20:44:29 +0200 Subject: [PATCH 1528/3725] Remove custom license for terrain code Now that it's no longer a stand-alone component, there's not much point in custom licensing it. --- components/terrain/buffercache.cpp | 21 --------------------- components/terrain/buffercache.hpp | 21 --------------------- components/terrain/defs.hpp | 21 --------------------- components/terrain/material.cpp | 21 --------------------- components/terrain/material.hpp | 21 --------------------- components/terrain/storage.cpp | 22 ---------------------- components/terrain/storage.hpp | 21 --------------------- components/terrain/terraingrid.cpp | 22 ---------------------- components/terrain/terraingrid.hpp | 21 --------------------- components/terrain/world.cpp | 21 --------------------- components/terrain/world.hpp | 21 --------------------- 11 files changed, 233 deletions(-) diff --git a/components/terrain/buffercache.cpp b/components/terrain/buffercache.cpp index dfb3eff88..a64f8ffd1 100644 --- a/components/terrain/buffercache.cpp +++ b/components/terrain/buffercache.cpp @@ -1,24 +1,3 @@ -/* - * Copyright (c) 2015 scrawl - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ #include "buffercache.hpp" #include diff --git a/components/terrain/buffercache.hpp b/components/terrain/buffercache.hpp index 575e9bca2..ca210f238 100644 --- a/components/terrain/buffercache.hpp +++ b/components/terrain/buffercache.hpp @@ -1,24 +1,3 @@ -/* - * Copyright (c) 2015 scrawl - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ #ifndef COMPONENTS_TERRAIN_BUFFERCACHE_H #define COMPONENTS_TERRAIN_BUFFERCACHE_H diff --git a/components/terrain/defs.hpp b/components/terrain/defs.hpp index 7b40ad479..234e05a98 100644 --- a/components/terrain/defs.hpp +++ b/components/terrain/defs.hpp @@ -1,24 +1,3 @@ -/* - * Copyright (c) 2015 scrawl - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ #ifndef COMPONENTS_TERRAIN_DEFS_HPP #define COMPONENTS_TERRAIN_DEFS_HPP diff --git a/components/terrain/material.cpp b/components/terrain/material.cpp index 2af8ddcda..2034883ed 100644 --- a/components/terrain/material.cpp +++ b/components/terrain/material.cpp @@ -1,24 +1,3 @@ -/* - * Copyright (c) 2015 scrawl - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ #include "material.hpp" #include diff --git a/components/terrain/material.hpp b/components/terrain/material.hpp index 47c5142c9..b423aa8b0 100644 --- a/components/terrain/material.hpp +++ b/components/terrain/material.hpp @@ -1,24 +1,3 @@ -/* - * Copyright (c) 2015 scrawl - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ #ifndef COMPONENTS_TERRAIN_MATERIAL_H #define COMPONENTS_TERRAIN_MATERIAL_H diff --git a/components/terrain/storage.cpp b/components/terrain/storage.cpp index 857713a82..bdc819481 100644 --- a/components/terrain/storage.cpp +++ b/components/terrain/storage.cpp @@ -1,23 +1 @@ -/* - * Copyright (c) 2015 scrawl - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - #include "storage.hpp" diff --git a/components/terrain/storage.hpp b/components/terrain/storage.hpp index a302c8f8c..bd5706b25 100644 --- a/components/terrain/storage.hpp +++ b/components/terrain/storage.hpp @@ -1,24 +1,3 @@ -/* - * Copyright (c) 2015 scrawl - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ #ifndef COMPONENTS_TERRAIN_STORAGE_H #define COMPONENTS_TERRAIN_STORAGE_H diff --git a/components/terrain/terraingrid.cpp b/components/terrain/terraingrid.cpp index 570461bba..5afb99176 100644 --- a/components/terrain/terraingrid.cpp +++ b/components/terrain/terraingrid.cpp @@ -1,25 +1,3 @@ -/* - * Copyright (c) 2015 scrawl - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - #include "terraingrid.hpp" #include diff --git a/components/terrain/terraingrid.hpp b/components/terrain/terraingrid.hpp index a697297b5..832b952e8 100644 --- a/components/terrain/terraingrid.hpp +++ b/components/terrain/terraingrid.hpp @@ -1,24 +1,3 @@ -/* - * Copyright (c) 2015 scrawl - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ #ifndef COMPONENTS_TERRAIN_TERRAINGRID_H #define COMPONENTS_TERRAIN_TERRAINGRID_H diff --git a/components/terrain/world.cpp b/components/terrain/world.cpp index 1cfcc80ac..2250b593d 100644 --- a/components/terrain/world.cpp +++ b/components/terrain/world.cpp @@ -1,24 +1,3 @@ -/* - * Copyright (c) 2015 scrawl - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ #include "world.hpp" #include diff --git a/components/terrain/world.hpp b/components/terrain/world.hpp index 70ec30410..4212f2a0c 100644 --- a/components/terrain/world.hpp +++ b/components/terrain/world.hpp @@ -1,24 +1,3 @@ -/* - * Copyright (c) 2015 scrawl - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ #ifndef COMPONENTS_TERRAIN_WORLD_H #define COMPONENTS_TERRAIN_WORLD_H From b204396b576b16d5e6fe2bf8eda090a4d0c97416 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 14 Jun 2015 21:04:59 +0200 Subject: [PATCH 1529/3725] Minor fix --- components/sceneutil/workqueue.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/components/sceneutil/workqueue.cpp b/components/sceneutil/workqueue.cpp index 9f23fba2d..b642687f0 100644 --- a/components/sceneutil/workqueue.cpp +++ b/components/sceneutil/workqueue.cpp @@ -17,8 +17,10 @@ void WorkTicket::waitTillDone() void WorkTicket::signalDone() { - OpenThreads::ScopedLock lock(mMutex); - mDone.exchange(1); + { + OpenThreads::ScopedLock lock(mMutex); + mDone.exchange(1); + } mCondition.broadcast(); } From 9e049894e8e06a16d833288aae69051b7a1a7ccc Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 14 Jun 2015 21:22:44 +0200 Subject: [PATCH 1530/3725] Reduce the number of StateSets created for NIF scene graphs The Material state is now set on the NiTriShape's node rather than the Geode, thus merged with other state like NiTexturingProperties, etc that are typically attached to the NiTriShape. Effectively cuts in half the number of StatSets for a NIF file, resulting in big speedup (~10%) in the Cull and Draw phases. --- components/nifosg/nifloader.cpp | 38 ++++++++++++++++----------------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index b95eeebfc..63121fda2 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -525,20 +525,20 @@ namespace NifOsg { const Nif::NiTriShape* triShape = static_cast(nifNode); if (triShape->skin.empty()) - handleTriShape(triShape, transformNode, boundTextures, animflags); + handleTriShape(triShape, transformNode, composite, boundTextures, animflags); else - handleSkinnedTriShape(triShape, transformNode, boundTextures, animflags); + handleSkinnedTriShape(triShape, transformNode, composite, boundTextures, animflags); if (!nifNode->controller.empty()) handleMeshControllers(nifNode, composite, boundTextures, animflags); } + if(nifNode->recType == Nif::RC_NiAutoNormalParticles || nifNode->recType == Nif::RC_NiRotatingParticles) + handleParticleSystem(nifNode, transformNode, composite, animflags, particleflags, rootNode); + if (composite->getNumControllers() > 0) transformNode->addUpdateCallback(composite); - if(nifNode->recType == Nif::RC_NiAutoNormalParticles || nifNode->recType == Nif::RC_NiRotatingParticles) - handleParticleSystem(nifNode, transformNode, animflags, particleflags, rootNode); - if (!nifNode->controller.empty()) handleNodeControllers(nifNode, transformNode, animflags); @@ -606,9 +606,8 @@ namespace NifOsg } } - static void handleMaterialControllers(const Nif::Property *materialProperty, osg::Node* node, int animflags) + static void handleMaterialControllers(const Nif::Property *materialProperty, osg::Node* node, SceneUtil::CompositeStateSetUpdater* composite, int animflags) { - osg::ref_ptr composite = new SceneUtil::CompositeStateSetUpdater; for (Nif::ControllerPtr ctrl = materialProperty->controller; !ctrl.empty(); ctrl = ctrl->next) { if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active)) @@ -630,8 +629,6 @@ namespace NifOsg else std::cerr << "Unexpected material controller " << ctrl->recType << std::endl; } - if (composite->getNumControllers() > 0) - node->addUpdateCallback(composite); } static void handleTextureControllers(const Nif::Property *texProperty, SceneUtil::CompositeStateSetUpdater* composite, Resource::TextureManager* textureManager, osg::StateSet *stateset, int animflags) @@ -789,7 +786,7 @@ namespace NifOsg return emitter; } - static void handleParticleSystem(const Nif::Node *nifNode, osg::Group *parentNode, int animflags, int particleflags, osg::Node* rootNode) + static void handleParticleSystem(const Nif::Node *nifNode, osg::Group *parentNode, SceneUtil::CompositeStateSetUpdater* composite, int animflags, int particleflags, osg::Node* rootNode) { osg::ref_ptr partsys (new ParticleSystem); partsys->setSortMode(osgParticle::ParticleSystem::SORT_BACK_TO_FRONT); @@ -863,10 +860,10 @@ namespace NifOsg std::vector materialProps; collectMaterialProperties(nifNode, materialProps); - applyMaterialProperties(geode, materialProps, true, animflags); + applyMaterialProperties(parentNode, materialProps, composite, true, animflags); // Particles don't have normals, so can't be diffuse lit. - osg::Material* mat = static_cast(geode->getStateSet()->getAttribute(osg::StateAttribute::MATERIAL)); + osg::Material* mat = static_cast(parentNode->getStateSet()->getAttribute(osg::StateAttribute::MATERIAL)); if (mat) { osg::Vec4f diffuse = mat->getDiffuse(osg::Material::FRONT_AND_BACK); @@ -891,7 +888,7 @@ namespace NifOsg } } - static void triShapeToGeometry(const Nif::NiTriShape *triShape, osg::Geometry *geometry, osg::Geode* parentGeode, const std::map& boundTextures, int animflags) + static void triShapeToGeometry(const Nif::NiTriShape *triShape, osg::Geometry *geometry, osg::Node* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::map& boundTextures, int animflags) { const Nif::NiTriShapeData* data = triShape->data.getPtr(); @@ -928,10 +925,10 @@ namespace NifOsg // above the actual renderable would be tedious. std::vector materialProps; collectMaterialProperties(triShape, materialProps); - applyMaterialProperties(parentGeode, materialProps, !data->colors.empty(), animflags); + applyMaterialProperties(parentNode, materialProps, composite, !data->colors.empty(), animflags); } - static void handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, const std::map& boundTextures, int animflags) + static void handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::map& boundTextures, int animflags) { osg::ref_ptr geometry; if(!triShape->controller.empty()) @@ -955,7 +952,7 @@ namespace NifOsg geometry = new osg::Geometry; osg::ref_ptr geode (new osg::Geode); - triShapeToGeometry(triShape, geometry, geode, boundTextures, animflags); + triShapeToGeometry(triShape, geometry, parentNode, composite, boundTextures, animflags); geode->addDrawable(geometry); @@ -1029,12 +1026,13 @@ namespace NifOsg return morphGeom; } - static void handleSkinnedTriShape(const Nif::NiTriShape *triShape, osg::Group *parentNode, const std::map& boundTextures, int animflags) + static void handleSkinnedTriShape(const Nif::NiTriShape *triShape, osg::Group *parentNode, SceneUtil::CompositeStateSetUpdater* composite, + const std::map& boundTextures, int animflags) { osg::ref_ptr geode (new osg::Geode); osg::ref_ptr geometry (new osg::Geometry); - triShapeToGeometry(triShape, geometry, geode, boundTextures, animflags); + triShapeToGeometry(triShape, geometry, parentNode, composite, boundTextures, animflags); osg::ref_ptr rig(new SceneUtil::RigGeometry); rig->setSourceGeometry(geometry); @@ -1275,7 +1273,7 @@ namespace NifOsg } } - static void applyMaterialProperties(osg::Node* node, const std::vector& properties, + static void applyMaterialProperties(osg::Node* node, const std::vector& properties, SceneUtil::CompositeStateSetUpdater* composite, bool hasVertexColors, int animflags) { osg::StateSet* stateset = node->getOrCreateStateSet(); @@ -1310,7 +1308,7 @@ namespace NifOsg mat->setShininess(osg::Material::FRONT_AND_BACK, matprop->data.glossiness); if (!matprop->controller.empty()) - handleMaterialControllers(matprop, node, animflags); + handleMaterialControllers(matprop, node, composite, animflags); break; } From f017fd6860dffd36a051e09824671ae5bdf19a92 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 14 Jun 2015 23:13:26 +0200 Subject: [PATCH 1531/3725] Reduce includes in animation.hpp --- apps/openmw/mwmechanics/character.cpp | 2 ++ apps/openmw/mwrender/animation.cpp | 30 +++++++++++++++++++++++ apps/openmw/mwrender/animation.hpp | 27 ++++++-------------- apps/openmw/mwrender/camera.cpp | 1 + apps/openmw/mwrender/characterpreview.cpp | 2 ++ 5 files changed, 42 insertions(+), 20 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index ea6b39481..c48599b46 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -19,6 +19,8 @@ #include "character.hpp" +#include + #include #include "movement.hpp" diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 261ec6c5b..4f0cde61d 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -17,6 +17,7 @@ #include #include // KeyframeHolder +#include #include @@ -204,6 +205,17 @@ namespace namespace MWRender { + struct Animation::AnimSource + { + osg::ref_ptr mKeyframes; + + typedef std::map > ControllerMap; + + ControllerMap mControllerMap[Animation::sNumGroups]; + + const std::multimap& getTextKeys(); + }; + class ResetAccumRootCallback : public osg::NodeCallback { public: @@ -1211,4 +1223,22 @@ namespace MWRender addExtraLight(getOrCreateObjectRoot(), ptr.get()->mBase); } + Animation::AnimState::~AnimState() + { + + } + + // ------------------------------ + + PartHolder::PartHolder(osg::ref_ptr node) + : mNode(node) + { + } + + PartHolder::~PartHolder() + { + if (mNode->getNumParents()) + mNode->getParent(0)->removeChild(mNode); + } + } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 419ae6bc0..d80fd96a4 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -3,7 +3,7 @@ #include "../mwworld/ptr.hpp" -#include +#include namespace ESM { @@ -18,6 +18,7 @@ namespace Resource namespace NifOsg { class KeyframeHolder; + class KeyframeController; } namespace MWRender @@ -43,16 +44,9 @@ public: class PartHolder { public: - PartHolder(osg::ref_ptr node) - : mNode(node) - { - } + PartHolder(osg::ref_ptr node); - ~PartHolder() - { - if (mNode->getNumParents()) - mNode->getParent(0)->removeChild(mNode); - } + ~PartHolder(); osg::ref_ptr getNode() { @@ -116,16 +110,7 @@ protected: } }; - struct AnimSource - { - osg::ref_ptr mKeyframes; - - typedef std::map > ControllerMap; - - ControllerMap mControllerMap[sNumGroups]; - - const std::multimap& getTextKeys(); - }; + struct AnimSource; struct AnimState { boost::shared_ptr mSource; @@ -150,6 +135,8 @@ protected: mPriority(0), mGroups(0), mAutoDisable(true) { } + ~AnimState(); + float getTime() const { return *mTime; diff --git a/apps/openmw/mwrender/camera.cpp b/apps/openmw/mwrender/camera.cpp index 9080d3164..316c9308b 100644 --- a/apps/openmw/mwrender/camera.cpp +++ b/apps/openmw/mwrender/camera.cpp @@ -1,6 +1,7 @@ #include "camera.hpp" #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index cdf99f0fc..d6c30da97 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -1,5 +1,7 @@ #include "characterpreview.hpp" +#include + #include #include #include From a5b72a358b6ed8a20663953027b446af499866f3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 14 Jun 2015 23:56:35 +0200 Subject: [PATCH 1532/3725] Prune empty nodes in RemoveDrawableVisitor Gets rid of 28 useless transform nodes in base_anim.1st.nif. --- apps/openmw/mwrender/animation.cpp | 7 ++++++- components/nifosg/nifloader.cpp | 16 ++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 4f0cde61d..62d50df0d 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -182,7 +182,12 @@ namespace virtual void apply(osg::Geode &node) { // Not safe to remove in apply(), since the visitor is still iterating the child list - mToRemove.push_back(&node); + osg::Group* parent = node.getParent(0); + // prune nodes that would be empty after the removal + if (parent->getNumChildren() == 1 && parent->getDataVariance() == osg::Object::STATIC) + mToRemove.push_back(parent); + else + mToRemove.push_back(&node); traverse(node); } diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 63121fda2..646a77f76 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -451,6 +451,22 @@ namespace NifOsg transformNode->addCullCallback(new BillboardCallback); } + // Set a default DataVariance (used as hint by optimization routines). + switch (nifNode->recType) + { + case Nif::RC_NiTriShape: + case Nif::RC_NiAutoNormalParticles: + case Nif::RC_NiRotatingParticles: + // Leaf nodes in the NIF hierarchy, so won't be able to dynamically attach children. + // No support for keyframe controllers (just crashes in the original engine). + transformNode->setDataVariance(osg::Object::STATIC); + break; + default: + // could have new children attached at any time, or added external keyframe controllers from .kf files + transformNode->setDataVariance(osg::Object::DYNAMIC); + break; + } + transformNode->setName(nifNode->name); if (parentNode) From 6a788c3462784b5d266540a580f69a7b5043a194 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 15 Jun 2015 01:29:32 +0200 Subject: [PATCH 1533/3725] Minor cleanup --- components/nifosg/nifloader.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 646a77f76..ed352c251 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -622,7 +622,7 @@ namespace NifOsg } } - static void handleMaterialControllers(const Nif::Property *materialProperty, osg::Node* node, SceneUtil::CompositeStateSetUpdater* composite, int animflags) + static void handleMaterialControllers(const Nif::Property *materialProperty, SceneUtil::CompositeStateSetUpdater* composite, int animflags) { for (Nif::ControllerPtr ctrl = materialProperty->controller; !ctrl.empty(); ctrl = ctrl->next) { @@ -1324,7 +1324,7 @@ namespace NifOsg mat->setShininess(osg::Material::FRONT_AND_BACK, matprop->data.glossiness); if (!matprop->controller.empty()) - handleMaterialControllers(matprop, node, composite, animflags); + handleMaterialControllers(matprop, composite, animflags); break; } From ab597f672e5aaeea3afa2d5526753101681fd552 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 15 Jun 2015 01:49:46 +0200 Subject: [PATCH 1534/3725] State the filename in NIF loader warning messages --- components/nifosg/nifloader.cpp | 213 +++++++++++++++++--------------- 1 file changed, 111 insertions(+), 102 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index ed352c251..7aec3385e 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -57,79 +57,6 @@ namespace } } - osg::BlendFunc::BlendFuncMode getBlendMode(int mode) - { - switch(mode) - { - case 0: return osg::BlendFunc::ONE; - case 1: return osg::BlendFunc::ZERO; - case 2: return osg::BlendFunc::SRC_COLOR; - case 3: return osg::BlendFunc::ONE_MINUS_SRC_COLOR; - case 4: return osg::BlendFunc::DST_COLOR; - case 5: return osg::BlendFunc::ONE_MINUS_DST_COLOR; - case 6: return osg::BlendFunc::SRC_ALPHA; - case 7: return osg::BlendFunc::ONE_MINUS_SRC_ALPHA; - case 8: return osg::BlendFunc::DST_ALPHA; - case 9: return osg::BlendFunc::ONE_MINUS_DST_ALPHA; - case 10: return osg::BlendFunc::SRC_ALPHA_SATURATE; - default: - std::cerr<< "Unexpected blend mode: "<< mode << std::endl; - return osg::BlendFunc::SRC_ALPHA; - } - } - - osg::AlphaFunc::ComparisonFunction getTestMode(int mode) - { - switch (mode) - { - case 0: return osg::AlphaFunc::ALWAYS; - case 1: return osg::AlphaFunc::LESS; - case 2: return osg::AlphaFunc::EQUAL; - case 3: return osg::AlphaFunc::LEQUAL; - case 4: return osg::AlphaFunc::GREATER; - case 5: return osg::AlphaFunc::NOTEQUAL; - case 6: return osg::AlphaFunc::GEQUAL; - case 7: return osg::AlphaFunc::NEVER; - default: - std::cerr << "Unexpected blend mode: " << mode << std::endl; - return osg::AlphaFunc::LEQUAL; - } - } - - osg::Stencil::Function getStencilFunction(int func) - { - switch (func) - { - case 0: return osg::Stencil::NEVER; - case 1: return osg::Stencil::LESS; - case 2: return osg::Stencil::EQUAL; - case 3: return osg::Stencil::LEQUAL; - case 4: return osg::Stencil::GREATER; - case 5: return osg::Stencil::NOTEQUAL; - case 6: return osg::Stencil::GEQUAL; - case 7: return osg::Stencil::NEVER; // NifSkope says this is GL_ALWAYS, but in MW it's GL_NEVER - default: - std::cerr << "Unexpected stencil function: " << func << std::endl; - return osg::Stencil::NEVER; - } - } - - osg::Stencil::Operation getStencilOperation(int op) - { - switch (op) - { - case 0: return osg::Stencil::KEEP; - case 1: return osg::Stencil::ZERO; - case 2: return osg::Stencil::REPLACE; - case 3: return osg::Stencil::INCR; - case 4: return osg::Stencil::DECR; - case 5: return osg::Stencil::INVERT; - default: - std::cerr << "Unexpected stencil operation: " << op << std::endl; - return osg::Stencil::KEEP; - } - } - // Collect all properties affecting the given node that should be applied to an osg::Material. void collectMaterialProperties(const Nif::Node* nifNode, std::vector& out) { @@ -341,6 +268,14 @@ namespace NifOsg class LoaderImpl { public: + /// @param filename used for warning messages. + LoaderImpl(const std::string& filename) + : mFilename(filename) + { + + } + std::string mFilename; + static void loadKf(Nif::NIFFilePtr nif, KeyframeHolder& target) { if(nif->numRoots() < 1) @@ -396,7 +331,7 @@ namespace NifOsg } } - static osg::ref_ptr load(Nif::NIFFilePtr nif, Resource::TextureManager* textureManager) + osg::ref_ptr load(Nif::NIFFilePtr nif, Resource::TextureManager* textureManager) { if (nif->numRoots() < 1) nif->fail("Found no root nodes"); @@ -422,7 +357,7 @@ namespace NifOsg return created; } - static void applyNodeProperties(const Nif::Node *nifNode, osg::Node *applyTo, SceneUtil::CompositeStateSetUpdater* composite, Resource::TextureManager* textureManager, std::map& boundTextures, int animflags) + void applyNodeProperties(const Nif::Node *nifNode, osg::Node *applyTo, SceneUtil::CompositeStateSetUpdater* composite, Resource::TextureManager* textureManager, std::map& boundTextures, int animflags) { const Nif::PropertyList& props = nifNode->props; for (size_t i = 0; i setFunction(boost::shared_ptr(new ControllerFunction(ctrl))); } - static osg::ref_ptr handleNode(const Nif::Node* nifNode, osg::Group* parentNode, Resource::TextureManager* textureManager, + osg::ref_ptr handleNode(const Nif::Node* nifNode, osg::Group* parentNode, Resource::TextureManager* textureManager, std::map boundTextures, int animflags, int particleflags, bool skipMeshes, TextKeyMap* textKeys, osg::Node* rootNode=NULL) { osg::ref_ptr transformNode = new osg::MatrixTransform(nifNode->trafo.toMatrix()); @@ -574,7 +509,7 @@ namespace NifOsg return transformNode; } - static void handleMeshControllers(const Nif::Node *nifNode, SceneUtil::CompositeStateSetUpdater* composite, const std::map &boundTextures, int animflags) + void handleMeshControllers(const Nif::Node *nifNode, SceneUtil::CompositeStateSetUpdater* composite, const std::map &boundTextures, int animflags) { for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next) { @@ -594,7 +529,7 @@ namespace NifOsg } } - static void handleNodeControllers(const Nif::Node* nifNode, osg::MatrixTransform* transformNode, int animflags) + void handleNodeControllers(const Nif::Node* nifNode, osg::MatrixTransform* transformNode, int animflags) { for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next) { @@ -622,7 +557,7 @@ namespace NifOsg } } - static void handleMaterialControllers(const Nif::Property *materialProperty, SceneUtil::CompositeStateSetUpdater* composite, int animflags) + void handleMaterialControllers(const Nif::Property *materialProperty, SceneUtil::CompositeStateSetUpdater* composite, int animflags) { for (Nif::ControllerPtr ctrl = materialProperty->controller; !ctrl.empty(); ctrl = ctrl->next) { @@ -643,11 +578,11 @@ namespace NifOsg composite->addController(ctrl); } else - std::cerr << "Unexpected material controller " << ctrl->recType << std::endl; + std::cerr << "Unexpected material controller " << ctrl->recType << " in " << mFilename << std::endl; } } - static void handleTextureControllers(const Nif::Property *texProperty, SceneUtil::CompositeStateSetUpdater* composite, Resource::TextureManager* textureManager, osg::StateSet *stateset, int animflags) + void handleTextureControllers(const Nif::Property *texProperty, SceneUtil::CompositeStateSetUpdater* composite, Resource::TextureManager* textureManager, osg::StateSet *stateset, int animflags) { for (Nif::ControllerPtr ctrl = texProperty->controller; !ctrl.empty(); ctrl = ctrl->next) { @@ -682,11 +617,11 @@ namespace NifOsg composite->addController(callback); } else - std::cerr << "Unexpected texture controller " << ctrl->recName << std::endl; + std::cerr << "Unexpected texture controller " << ctrl->recName << " in " << mFilename << std::endl; } } - static void handleParticlePrograms(Nif::ExtraPtr affectors, Nif::ExtraPtr colliders, osg::Group *attachTo, osgParticle::ParticleSystem* partsys, osgParticle::ParticleProcessor::ReferenceFrame rf) + void handleParticlePrograms(Nif::ExtraPtr affectors, Nif::ExtraPtr colliders, osg::Group *attachTo, osgParticle::ParticleSystem* partsys, osgParticle::ParticleProcessor::ReferenceFrame rf) { osgParticle::ModularProgram* program = new osgParticle::ModularProgram; attachTo->addChild(program); @@ -715,7 +650,7 @@ namespace NifOsg // unused } else - std::cerr << "Unhandled particle modifier " << affectors->recName << std::endl; + std::cerr << "Unhandled particle modifier " << affectors->recName << " in " << mFilename << std::endl; } for (; !colliders.empty(); colliders = colliders->extra) { @@ -728,7 +663,7 @@ namespace NifOsg } // Load the initial state of the particle system, i.e. the initial particles and their positions, velocity and colors. - static void handleParticleInitialState(const Nif::Node* nifNode, osgParticle::ParticleSystem* partsys, const Nif::NiParticleSystemController* partctrl) + void handleParticleInitialState(const Nif::Node* nifNode, osgParticle::ParticleSystem* partsys, const Nif::NiParticleSystemController* partctrl) { const Nif::NiAutoNormalParticlesData *particledata = NULL; if(nifNode->recType == Nif::RC_NiAutoNormalParticles) @@ -768,7 +703,7 @@ namespace NifOsg partsys->setInitialBound(box); } - static osg::ref_ptr handleParticleEmitter(const Nif::NiParticleSystemController* partctrl) + osg::ref_ptr handleParticleEmitter(const Nif::NiParticleSystemController* partctrl) { std::vector targets; if (partctrl->recType == Nif::RC_NiBSPArrayController) @@ -802,7 +737,7 @@ namespace NifOsg return emitter; } - static void handleParticleSystem(const Nif::Node *nifNode, osg::Group *parentNode, SceneUtil::CompositeStateSetUpdater* composite, int animflags, int particleflags, osg::Node* rootNode) + void handleParticleSystem(const Nif::Node *nifNode, osg::Group *parentNode, SceneUtil::CompositeStateSetUpdater* composite, int animflags, int particleflags, osg::Node* rootNode) { osg::ref_ptr partsys (new ParticleSystem); partsys->setSortMode(osgParticle::ParticleSystem::SORT_BACK_TO_FRONT); @@ -817,7 +752,7 @@ namespace NifOsg } if (!partctrl) { - std::cerr << "No particle controller found " << std::endl; + std::cerr << "No particle controller found in " << mFilename << std::endl; return; } @@ -853,7 +788,7 @@ namespace NifOsg rootNode->accept(find); if (!find.mFound) { - std::cerr << "can't find emitter node, wrong node order?" << std::endl; + std::cerr << "can't find emitter node, wrong node order? in " << mFilename << std::endl; return; } osg::Group* emitterNode = find.mFound; @@ -904,7 +839,7 @@ namespace NifOsg } } - static void triShapeToGeometry(const Nif::NiTriShape *triShape, osg::Geometry *geometry, osg::Node* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::map& boundTextures, int animflags) + void triShapeToGeometry(const Nif::NiTriShape *triShape, osg::Geometry *geometry, osg::Node* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::map& boundTextures, int animflags) { const Nif::NiTriShapeData* data = triShape->data.getPtr(); @@ -944,7 +879,7 @@ namespace NifOsg applyMaterialProperties(parentNode, materialProps, composite, !data->colors.empty(), animflags); } - static void handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::map& boundTextures, int animflags) + void handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::map& boundTextures, int animflags) { osg::ref_ptr geometry; if(!triShape->controller.empty()) @@ -987,7 +922,7 @@ namespace NifOsg parentNode->addChild(geode); } - static osg::ref_ptr handleMorphGeometry(const Nif::NiGeomMorpherController* morpher) + osg::ref_ptr handleMorphGeometry(const Nif::NiGeomMorpherController* morpher) { osg::ref_ptr morphGeom = new osgAnimation::MorphGeometry; morphGeom->setMethod(osgAnimation::MorphGeometry::RELATIVE); @@ -1042,7 +977,7 @@ namespace NifOsg return morphGeom; } - static void handleSkinnedTriShape(const Nif::NiTriShape *triShape, osg::Group *parentNode, SceneUtil::CompositeStateSetUpdater* composite, + void handleSkinnedTriShape(const Nif::NiTriShape *triShape, osg::Group *parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::map& boundTextures, int animflags) { osg::ref_ptr geode (new osg::Geode); @@ -1094,8 +1029,80 @@ namespace NifOsg parentNode->addChild(frameswitch); } + osg::BlendFunc::BlendFuncMode getBlendMode(int mode) + { + switch(mode) + { + case 0: return osg::BlendFunc::ONE; + case 1: return osg::BlendFunc::ZERO; + case 2: return osg::BlendFunc::SRC_COLOR; + case 3: return osg::BlendFunc::ONE_MINUS_SRC_COLOR; + case 4: return osg::BlendFunc::DST_COLOR; + case 5: return osg::BlendFunc::ONE_MINUS_DST_COLOR; + case 6: return osg::BlendFunc::SRC_ALPHA; + case 7: return osg::BlendFunc::ONE_MINUS_SRC_ALPHA; + case 8: return osg::BlendFunc::DST_ALPHA; + case 9: return osg::BlendFunc::ONE_MINUS_DST_ALPHA; + case 10: return osg::BlendFunc::SRC_ALPHA_SATURATE; + default: + std::cerr<< "Unexpected blend mode: "<< mode << " in " << mFilename << std::endl; + return osg::BlendFunc::SRC_ALPHA; + } + } + + osg::AlphaFunc::ComparisonFunction getTestMode(int mode) + { + switch (mode) + { + case 0: return osg::AlphaFunc::ALWAYS; + case 1: return osg::AlphaFunc::LESS; + case 2: return osg::AlphaFunc::EQUAL; + case 3: return osg::AlphaFunc::LEQUAL; + case 4: return osg::AlphaFunc::GREATER; + case 5: return osg::AlphaFunc::NOTEQUAL; + case 6: return osg::AlphaFunc::GEQUAL; + case 7: return osg::AlphaFunc::NEVER; + default: + std::cerr << "Unexpected blend mode: " << mode << " in " << mFilename << std::endl; + return osg::AlphaFunc::LEQUAL; + } + } + + osg::Stencil::Function getStencilFunction(int func) + { + switch (func) + { + case 0: return osg::Stencil::NEVER; + case 1: return osg::Stencil::LESS; + case 2: return osg::Stencil::EQUAL; + case 3: return osg::Stencil::LEQUAL; + case 4: return osg::Stencil::GREATER; + case 5: return osg::Stencil::NOTEQUAL; + case 6: return osg::Stencil::GEQUAL; + case 7: return osg::Stencil::NEVER; // NifSkope says this is GL_ALWAYS, but in MW it's GL_NEVER + default: + std::cerr << "Unexpected stencil function: " << func << " in " << mFilename << std::endl; + return osg::Stencil::NEVER; + } + } + + osg::Stencil::Operation getStencilOperation(int op) + { + switch (op) + { + case 0: return osg::Stencil::KEEP; + case 1: return osg::Stencil::ZERO; + case 2: return osg::Stencil::REPLACE; + case 3: return osg::Stencil::INCR; + case 4: return osg::Stencil::DECR; + case 5: return osg::Stencil::INVERT; + default: + std::cerr << "Unexpected stencil operation: " << op << " in " << mFilename << std::endl; + return osg::Stencil::KEEP; + } + } - static void handleProperty(const Nif::Property *property, + void handleProperty(const Nif::Property *property, osg::Node *node, SceneUtil::CompositeStateSetUpdater* composite, Resource::TextureManager* textureManager, std::map& boundTextures, int animflags) { switch (property->recType) @@ -1207,20 +1214,20 @@ namespace NifOsg && i != Nif::NiTexturingProperty::DarkTexture && i != Nif::NiTexturingProperty::DetailTexture) { - std::cerr << "Warning: unhandled texture stage " << i << std::endl; + std::cerr << "Warning: unhandled texture stage " << i << " in " << mFilename << std::endl; continue; } const Nif::NiTexturingProperty::Texture& tex = texprop->textures[i]; if(tex.texture.empty()) { - std::cerr << "Warning: texture layer " << i << " is in use but empty " << std::endl; + std::cerr << "Warning: texture layer " << i << " is in use but empty in " << mFilename << std::endl; continue; } const Nif::NiSourceTexture *st = tex.texture.getPtr(); if (!st->external) { - std::cerr << "Warning: unhandled internal texture " << std::endl; + std::cerr << "Warning: unhandled internal texture in " << mFilename << std::endl; continue; } @@ -1284,12 +1291,12 @@ namespace NifOsg break; } default: - std::cerr << "Unhandled " << property->recName << std::endl; + std::cerr << "Unhandled " << property->recName << " in " << mFilename << std::endl; break; } } - static void applyMaterialProperties(osg::Node* node, const std::vector& properties, SceneUtil::CompositeStateSetUpdater* composite, + void applyMaterialProperties(osg::Node* node, const std::vector& properties, SceneUtil::CompositeStateSetUpdater* composite, bool hasVertexColors, int animflags) { osg::StateSet* stateset = node->getOrCreateStateSet(); @@ -1359,12 +1366,14 @@ namespace NifOsg osg::ref_ptr Loader::load(Nif::NIFFilePtr file, Resource::TextureManager* textureManager) { - return LoaderImpl::load(file, textureManager); + LoaderImpl impl(file->getFilename()); + return impl.load(file, textureManager); } void Loader::loadKf(Nif::NIFFilePtr kf, KeyframeHolder& target) { - LoaderImpl::loadKf(kf, target); + LoaderImpl impl(kf->getFilename()); + impl.loadKf(kf, target); } } From 36aa4aa9bdeb50a3512d5f2212bb5daaa94477b2 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 15 Jun 2015 09:53:26 +1000 Subject: [PATCH 1535/3725] If a removed 'content=' item has comments, keep them in config file for later use. --- components/config/gamesettings.cpp | 47 ++++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 2 deletions(-) diff --git a/components/config/gamesettings.cpp b/components/config/gamesettings.cpp index 4339369cf..74d92d55d 100644 --- a/components/config/gamesettings.cpp +++ b/components/config/gamesettings.cpp @@ -195,6 +195,9 @@ bool Config::GameSettings::isOrderedLine(const QString& line) const // // - If there is no corresponding line in file, add at the end // +// - Removed content items are saved as comments if the item had any comments. +// Content items prepended with '##' are considered previously removed. +// bool Config::GameSettings::writeFileWithComments(QFile &file) { QTextStream stream(&file); @@ -227,7 +230,8 @@ bool Config::GameSettings::writeFileWithComments(QFile &file) // v | | // blank or comment line, save in temp buffer <--------+ | // | | | | - // v +------- comment line ------+ | + // | +------- comment line ------+ | + // v (special processing '##') | // "ordered" line | // | | // v | @@ -263,7 +267,20 @@ bool Config::GameSettings::writeFileWithComments(QFile &file) // comment line, save in temp buffer if (comments.empty()) commentStart = iter; - comments.push_back(*iter); + + // special removed content processing + if ((*iter).contains(QRegExp("^##content\\s*="))) + { + if (!comments.empty()) + { + commentsMap[*iter] = comments; + comments.clear(); + commentStart = fileCopy.end(); + } + } + else + comments.push_back(*iter); + *iter = QString(); // assume to be deleted later } else @@ -359,17 +376,43 @@ bool Config::GameSettings::writeFileWithComments(QFile &file) std::map >::const_iterator i = commentsMap.find(settingRegex.cap(1)+"="+settingRegex.cap(2)); + // check if previous removed content item with comments + if (i == commentsMap.end()) + i = commentsMap.find("##"+settingRegex.cap(1)+"="+settingRegex.cap(2)); + if (i != commentsMap.end()) { std::vector cLines = i->second; for (std::vector::const_iterator ci = cLines.begin(); ci != cLines.end(); ++ci) stream << *ci << "\n"; + + commentsMap.erase(i); } } stream << settingLine << "\n"; } + // flush any removed settings + if (!commentsMap.empty()) + { + std::map >::const_iterator i = commentsMap.begin(); + for (; i != commentsMap.end(); ++i) + { + if (i->first.contains(QRegExp("^\\s*content\\s*="))) + { + std::vector cLines = i->second; + for (std::vector::const_iterator ci = cLines.begin(); ci != cLines.end(); ++ci) + stream << *ci << "\n"; + + // mark the content line entry for future preocessing + stream << "##" << i->first << "\n"; + + //commentsMap.erase(i); + } + } + } + // flush any end comments if (!comments.empty()) { From ad46ff7a98fb2bd201e9309b76400f3a7fe61d4d Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 15 Jun 2015 02:06:04 +0200 Subject: [PATCH 1536/3725] Remove redundant Transform nodes for TriShapes/ParticleSystems with an identity transform --- components/nif/niftypes.hpp | 15 +++++++++++++++ components/nifosg/nifloader.cpp | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/components/nif/niftypes.hpp b/components/nif/niftypes.hpp index d95180145..5827448fd 100644 --- a/components/nif/niftypes.hpp +++ b/components/nif/niftypes.hpp @@ -42,6 +42,15 @@ struct Matrix3 for (int j=0;j<3;++j) mValues[i][j] = (i==j) ? 1.f : 0.f; } + + bool isIdentity() const + { + for (int i=0;i<3;++i) + for (int j=0;j<3;++j) + if ((i==j) != (mValues[i][j] == 1)) + return false; + return true; + } }; struct Transformation @@ -62,6 +71,12 @@ struct Transformation return transform; } + bool isIdentity() const + { + return pos == osg::Vec3f(0,0,0) + && rotation.isIdentity() && scale == 1.f; + } + static const Transformation& getIdentity() { static const Transformation identity = { diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 7aec3385e..7139bbcef 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -376,6 +376,32 @@ namespace NifOsg toSetup->setFunction(boost::shared_ptr(new ControllerFunction(ctrl))); } + void optimize (const Nif::Node* nifNode, osg::Group* node, bool skipMeshes) + { + // For nodes with an identity transform, remove the redundant Transform node + if (node->getDataVariance() == osg::Object::STATIC + // For TriShapes, we can only collapse the node, but not completely remove it, + // if the link to animated collision shapes is supposed to stay intact. + && (nifNode->recType != Nif::RC_NiTriShape || !skipMeshes)) + { + if (node->getNumParents() && nifNode->trafo.isIdentity()) + { + osg::Group* parent = node->getParent(0); + osg::Node* child = node->getChild(0); + child->setUpdateCallback(node->getUpdateCallback()); + child->setStateSet(node->getStateSet()); + child->setName(node->getName()); + // make sure to copy the UserDataContainer with the record index, so that connections to an animated collision shape don't break + child->setUserDataContainer(node->getUserDataContainer()); + parent->addChild(child); + node->removeChild(child); + parent->removeChild(node); + } + } + // For NiTriShapes *with* a valid transform, perhaps we could apply the transform to the vertices. + // Need to make sure that won't break transparency sorting. Check what the original engine is doing? + } + osg::ref_ptr handleNode(const Nif::Node* nifNode, osg::Group* parentNode, Resource::TextureManager* textureManager, std::map boundTextures, int animflags, int particleflags, bool skipMeshes, TextKeyMap* textKeys, osg::Node* rootNode=NULL) { @@ -490,9 +516,15 @@ namespace NifOsg if (composite->getNumControllers() > 0) transformNode->addUpdateCallback(composite); + + // Note: NiTriShapes are not allowed to have KeyframeControllers (the vanilla engine just crashes when there is one). + // We can take advantage of this constraint for optimizations later. if (!nifNode->controller.empty()) handleNodeControllers(nifNode, transformNode, animflags); + // Optimization pass + optimize(nifNode, transformNode, skipMeshes); + const Nif::NiNode *ninode = dynamic_cast(nifNode); if(ninode) { From ec25f1da95d0ce1879c1f165e6329bc0be8a70ea Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 15 Jun 2015 02:17:57 +0200 Subject: [PATCH 1537/3725] Fix ParticleSystem bug introduced by last commit --- components/nifosg/nifloader.cpp | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 7139bbcef..69e71cce4 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -387,14 +387,23 @@ namespace NifOsg if (node->getNumParents() && nifNode->trafo.isIdentity()) { osg::Group* parent = node->getParent(0); - osg::Node* child = node->getChild(0); - child->setUpdateCallback(node->getUpdateCallback()); - child->setStateSet(node->getStateSet()); - child->setName(node->getName()); - // make sure to copy the UserDataContainer with the record index, so that connections to an animated collision shape don't break - child->setUserDataContainer(node->getUserDataContainer()); - parent->addChild(child); - node->removeChild(child); + + // can be multiple children in case of ParticleSystems, with the extra ParticleSystemUpdater node + for (unsigned int i=0; igetNumChildren(); ++i) + { + osg::Node* child = node->getChild(i); + if (i == node->getNumChildren()-1) // FIXME: some nicer way to determine where our actual Drawable resides... + { + child->setUpdateCallback(node->getUpdateCallback()); + child->setStateSet(node->getStateSet()); + child->setName(node->getName()); + // make sure to copy the UserDataContainer with the record index, so that connections to an animated collision shape don't break + child->setUserDataContainer(node->getUserDataContainer()); + } + parent->addChild(child); + } + + node->removeChildren(0, node->getNumChildren()); parent->removeChild(node); } } From b79ab1a3b847e3f457b6c32c81f81f8f1fc0502b Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 15 Jun 2015 02:22:52 +0200 Subject: [PATCH 1538/3725] Fix InverseWorldMatrix bug introduced by last commit --- components/nifosg/nifloader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 69e71cce4..40eedad51 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -394,7 +394,7 @@ namespace NifOsg osg::Node* child = node->getChild(i); if (i == node->getNumChildren()-1) // FIXME: some nicer way to determine where our actual Drawable resides... { - child->setUpdateCallback(node->getUpdateCallback()); + child->addUpdateCallback(node->getUpdateCallback()); child->setStateSet(node->getStateSet()); child->setName(node->getName()); // make sure to copy the UserDataContainer with the record index, so that connections to an animated collision shape don't break From 6b28955f316d8e3261d68b99c48bd6ce8a8e3f48 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 15 Jun 2015 10:26:16 +1000 Subject: [PATCH 1539/3725] Fix attempt to erase using a const_iterator. --- components/config/gamesettings.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/config/gamesettings.cpp b/components/config/gamesettings.cpp index 74d92d55d..ca6bfd80d 100644 --- a/components/config/gamesettings.cpp +++ b/components/config/gamesettings.cpp @@ -373,7 +373,7 @@ bool Config::GameSettings::writeFileWithComments(QFile &file) if (settingRegex.indexIn(settingLine) != -1) { - std::map >::const_iterator i = + std::map >::iterator i = commentsMap.find(settingRegex.cap(1)+"="+settingRegex.cap(2)); // check if previous removed content item with comments From d7a4a9fd66f2eaf03da816692a07b6b621f7c86a Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 15 Jun 2015 15:25:45 +0200 Subject: [PATCH 1540/3725] Create NIF root nodes as Group instead of Transform when possible --- components/nifosg/nifloader.cpp | 56 +++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 24 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 40eedad51..91dea6ef2 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -414,12 +414,7 @@ namespace NifOsg osg::ref_ptr handleNode(const Nif::Node* nifNode, osg::Group* parentNode, Resource::TextureManager* textureManager, std::map boundTextures, int animflags, int particleflags, bool skipMeshes, TextKeyMap* textKeys, osg::Node* rootNode=NULL) { - osg::ref_ptr transformNode = new osg::MatrixTransform(nifNode->trafo.toMatrix()); - - if (nifNode->recType == Nif::RC_NiBillboardNode) - { - transformNode->addCullCallback(new BillboardCallback); - } + osg::ref_ptr node = new osg::MatrixTransform(nifNode->trafo.toMatrix()); // Set a default DataVariance (used as hint by optimization routines). switch (nifNode->recType) @@ -429,21 +424,34 @@ namespace NifOsg case Nif::RC_NiRotatingParticles: // Leaf nodes in the NIF hierarchy, so won't be able to dynamically attach children. // No support for keyframe controllers (just crashes in the original engine). - transformNode->setDataVariance(osg::Object::STATIC); + node->setDataVariance(osg::Object::STATIC); break; default: // could have new children attached at any time, or added external keyframe controllers from .kf files - transformNode->setDataVariance(osg::Object::DYNAMIC); + node->setDataVariance(osg::Object::DYNAMIC); break; } - transformNode->setName(nifNode->name); + if (nifNode->recType == Nif::RC_NiBillboardNode) + { + node->addCullCallback(new BillboardCallback); + } + else if (!rootNode && nifNode->controller.empty() && nifNode->trafo.isIdentity()) + { + // The Root node can be created as a Group if no transformation is required. + // This takes advantage of the fact root nodes can't have additional controllers + // loaded from an external .kf file (original engine just throws "can't find node" errors if you try). + node = new osg::Group; + node->setDataVariance(osg::Object::STATIC); + } + + node->setName(nifNode->name); if (parentNode) - parentNode->addChild(transformNode); + parentNode->addChild(node); if (!rootNode) - rootNode = transformNode; + rootNode = node; // UserData used for a variety of features: // - finding the correct emitter node for a particle system @@ -451,7 +459,7 @@ namespace NifOsg // - finding a random child NiNode in NiBspArrayController // - storing the previous 3x3 rotation and scale values for when a KeyframeController wants to // change only certain elements of the 4x4 transform - transformNode->getOrCreateUserDataContainer()->addUserObject( + node->getOrCreateUserDataContainer()->addUserObject( new NodeUserData(nifNode->recIndex, nifNode->trafo.scale, nifNode->trafo.rotation)); for (Nif::ExtraPtr e = nifNode->extra; !e.empty(); e = e->extra) @@ -485,7 +493,7 @@ namespace NifOsg { skipMeshes = true; // Leave mask for UpdateVisitor enabled - transformNode->setNodeMask(0x1); + node->setNodeMask(0x1); } // We can skip creating meshes for hidden nodes if they don't have a VisController that @@ -500,39 +508,39 @@ namespace NifOsg skipMeshes = true; // skip child meshes, but still create the child node hierarchy for animating collision shapes // now hide this node, but leave the mask for UpdateVisitor enabled so that KeyframeController works - transformNode->setNodeMask(0x1); + node->setNodeMask(0x1); } osg::ref_ptr composite = new SceneUtil::CompositeStateSetUpdater; - applyNodeProperties(nifNode, transformNode, composite, textureManager, boundTextures, animflags); + applyNodeProperties(nifNode, node, composite, textureManager, boundTextures, animflags); if (nifNode->recType == Nif::RC_NiTriShape && !skipMeshes) { const Nif::NiTriShape* triShape = static_cast(nifNode); if (triShape->skin.empty()) - handleTriShape(triShape, transformNode, composite, boundTextures, animflags); + handleTriShape(triShape, node, composite, boundTextures, animflags); else - handleSkinnedTriShape(triShape, transformNode, composite, boundTextures, animflags); + handleSkinnedTriShape(triShape, node, composite, boundTextures, animflags); if (!nifNode->controller.empty()) handleMeshControllers(nifNode, composite, boundTextures, animflags); } if(nifNode->recType == Nif::RC_NiAutoNormalParticles || nifNode->recType == Nif::RC_NiRotatingParticles) - handleParticleSystem(nifNode, transformNode, composite, animflags, particleflags, rootNode); + handleParticleSystem(nifNode, node, composite, animflags, particleflags, rootNode); if (composite->getNumControllers() > 0) - transformNode->addUpdateCallback(composite); + node->addUpdateCallback(composite); // Note: NiTriShapes are not allowed to have KeyframeControllers (the vanilla engine just crashes when there is one). // We can take advantage of this constraint for optimizations later. - if (!nifNode->controller.empty()) - handleNodeControllers(nifNode, transformNode, animflags); + if (!nifNode->controller.empty() && node->getDataVariance() == osg::Object::DYNAMIC) + handleNodeControllers(nifNode, static_cast(node.get()), animflags); // Optimization pass - optimize(nifNode, transformNode, skipMeshes); + optimize(nifNode, node, skipMeshes); const Nif::NiNode *ninode = dynamic_cast(nifNode); if(ninode) @@ -542,12 +550,12 @@ namespace NifOsg { if(!children[i].empty()) { - handleNode(children[i].getPtr(), transformNode, textureManager, boundTextures, animflags, particleflags, skipMeshes, textKeys, rootNode); + handleNode(children[i].getPtr(), node, textureManager, boundTextures, animflags, particleflags, skipMeshes, textKeys, rootNode); } } } - return transformNode; + return node; } void handleMeshControllers(const Nif::Node *nifNode, SceneUtil::CompositeStateSetUpdater* composite, const std::map &boundTextures, int animflags) From 07937c741a4321f57668d3a61701336fbfe77f7d Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 15 Jun 2015 16:19:05 +0200 Subject: [PATCH 1541/3725] Improve exception handling when starting a new game from the main menu --- apps/openmw/mwstate/statemanagerimp.cpp | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index ce4d8f958..7c111a090 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -139,11 +139,28 @@ void MWState::StateManager::newGame (bool bypass) if (!bypass) MWBase::Environment::get().getWindowManager()->setNewGame (true); - MWBase::Environment::get().getScriptManager()->getGlobalScripts().addStartup(); + try + { + MWBase::Environment::get().getScriptManager()->getGlobalScripts().addStartup(); - MWBase::Environment::get().getWorld()->startNewGame (bypass); + MWBase::Environment::get().getWorld()->startNewGame (bypass); - mState = State_Running; + mState = State_Running; + } + catch (std::exception& e) + { + std::stringstream error; + error << "Failed to start new game: " << e.what(); + + std::cerr << error.str() << std::endl; + cleanup (true); + + MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_MainMenu); + + std::vector buttons; + buttons.push_back("#{sOk}"); + MWBase::Environment::get().getWindowManager()->interactiveMessageBox(error.str(), buttons); + } } void MWState::StateManager::endGame() From 609e146a22f2e8b3c70cb15693b4976aba7141d5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 15 Jun 2015 14:16:14 +0200 Subject: [PATCH 1542/3725] Build fixes for windows --- apps/launcher/CMakeLists.txt | 3 +++ apps/opencs/CMakeLists.txt | 8 ++++++++ apps/wizard/CMakeLists.txt | 7 +++++++ extern/ogre-ffmpeg-videoplayer/CMakeLists.txt | 3 +-- 4 files changed, 19 insertions(+), 2 deletions(-) diff --git a/apps/launcher/CMakeLists.txt b/apps/launcher/CMakeLists.txt index 3c7b39314..caf96054e 100644 --- a/apps/launcher/CMakeLists.txt +++ b/apps/launcher/CMakeLists.txt @@ -105,6 +105,9 @@ if (DESIRED_QT_VERSION MATCHES 4) endif(WIN32) else() qt5_use_modules(openmw-launcher Widgets Core) + if (WIN32) + target_link_libraries(Qt5::WinMain) + endif() endif() if (BUILD_WITH_CODE_COVERAGE) diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 6a9318319..bf39b36c1 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -216,8 +216,16 @@ if (DESIRED_QT_VERSION MATCHES 4) ${QT_QTGUI_LIBRARY} ${QT_QTCORE_LIBRARY} ${QT_QTNETWORK_LIBRARY}) + + if (WIN32) + target_link_libraries(openmw-cs ${QT_QTMAIN_LIBRARY}) + endif() + else() qt5_use_modules(openmw-cs Widgets Core Network) + if (WIN32) + target_link_libraries(Qt5::WinMain) + endif() endif() if (WIN32) diff --git a/apps/wizard/CMakeLists.txt b/apps/wizard/CMakeLists.txt index 5cd874863..89438640c 100644 --- a/apps/wizard/CMakeLists.txt +++ b/apps/wizard/CMakeLists.txt @@ -123,8 +123,15 @@ if (DESIRED_QT_VERSION MATCHES 4) target_link_libraries(openmw-wizard ${QT_QTGUI_LIBRARY} ${QT_QTCORE_LIBRARY}) + + if (WIN32) + target_link_libraries(openmw-wizard ${QT_QTMAIN_LIBRARY}) + endif() else() qt5_use_modules(openmw-wizard Widgets Core) + if (WIN32) + target_link_libraries(Qt5::WinMain) + endif() endif() if (OPENMW_USE_UNSHIELD) diff --git a/extern/ogre-ffmpeg-videoplayer/CMakeLists.txt b/extern/ogre-ffmpeg-videoplayer/CMakeLists.txt index cda3d39e8..edd5575f4 100644 --- a/extern/ogre-ffmpeg-videoplayer/CMakeLists.txt +++ b/extern/ogre-ffmpeg-videoplayer/CMakeLists.txt @@ -11,8 +11,7 @@ set(OGRE_FFMPEG_VIDEOPLAYER_SOURCE_FILES audiofactory.hpp ) -# Find Boost - +include_directories(${FFMPEG_INCLUDE_DIRS}) add_library(${OGRE_FFMPEG_VIDEOPLAYER_LIBRARY} STATIC ${OGRE_FFMPEG_VIDEOPLAYER_SOURCE_FILES}) target_link_libraries(${OGRE_FFMPEG_VIDEOPLAYER_LIBRARY} ${FFMPEG_LIBRARIES} ${Boost_THREAD_LIBRARY}) From 1d198a5592e0d4d6f3a4d0b7388d87f5e29b3482 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 15 Jun 2015 18:09:01 +0200 Subject: [PATCH 1543/3725] Keep the light list StateSet cache for more than one frame --- components/sceneutil/lightmanager.cpp | 23 +++++++++++++++-------- components/sceneutil/lightmanager.hpp | 17 +++++++++-------- 2 files changed, 24 insertions(+), 16 deletions(-) diff --git a/components/sceneutil/lightmanager.cpp b/components/sceneutil/lightmanager.cpp index 6040f9536..65955d9af 100644 --- a/components/sceneutil/lightmanager.cpp +++ b/components/sceneutil/lightmanager.cpp @@ -145,7 +145,6 @@ namespace SceneUtil { mLightsInViewSpace = false; mLights.clear(); - mStateSetCache.clear(); } void LightManager::addLight(LightSource* lightSource, osg::Matrix worldMat) @@ -180,7 +179,7 @@ namespace SceneUtil // possible optimization: return a StateSet containing all requested lights plus some extra lights (if a suitable one exists) size_t hash = 0; for (unsigned int i=0; igetId()); LightStateSetMap::iterator found = mStateSetCache.find(hash); if (found != mStateSetCache.end()) @@ -190,10 +189,7 @@ namespace SceneUtil std::vector > lights; for (unsigned int i=0; igetLight()); - } + lights.push_back(lightList[i]->getLight()); osg::ref_ptr attr = new LightStateAttribute(mStartLight, lights); @@ -223,11 +219,22 @@ namespace SceneUtil return mStartLight; } + static int sLightId = 0; + LightSource::LightSource() : mRadius(0.f) { setNodeMask(Mask_Lit); setUpdateCallback(new CollectLightCallback); + mId = sLightId++; + } + + LightSource::LightSource(const LightSource ©, const osg::CopyOp ©op) + : osg::Node(copy, copyop) + , mLight(copy.mLight) + , mRadius(copy.mRadius) + { + mId = sLightId++; } void LightListCallback::operator()(osg::Node *node, osg::NodeVisitor *nv) @@ -282,12 +289,12 @@ namespace SceneUtil osg::Matrixf mat = *cv->getModelViewMatrix(); transformBoundingSphere(mat, nodeBound); - std::vector lightList; + std::vector lightList; for (unsigned int i=0; i& getLights() const; - // Stores indices into the mLights vector - typedef std::vector LightList; + typedef std::vector LightList; osg::ref_ptr getLightListStateSet(const LightList& lightList); From acf9fc2d370ef2b782937295def48c17a685ba8e Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 15 Jun 2015 18:15:26 +0200 Subject: [PATCH 1544/3725] Enable per-frame light list updates (Bug #2638, Bug #2654) The performance impact isn't so big anymore since the last commit. --- components/sceneutil/lightmanager.cpp | 65 +++++++++++---------------- 1 file changed, 25 insertions(+), 40 deletions(-) diff --git a/components/sceneutil/lightmanager.cpp b/components/sceneutil/lightmanager.cpp index 65955d9af..713524a41 100644 --- a/components/sceneutil/lightmanager.cpp +++ b/components/sceneutil/lightmanager.cpp @@ -274,59 +274,44 @@ namespace SceneUtil if (lights.size()) { + // we do the intersections in view space + osg::BoundingSphere nodeBound = node->getBound(); + osg::Matrixf mat = *cv->getModelViewMatrix(); + transformBoundingSphere(mat, nodeBound); - static std::map > statesets; - std::map >::iterator found = statesets.find(node); - osg::ref_ptr stateset; - if (found != statesets.end()) + std::vector lightList; + for (unsigned int i=0; isecond; + const LightManager::LightSourceTransform& l = lights[i]; + if (l.mViewBound.intersects(nodeBound)) + lightList.push_back(l.mLightSource); } - else{ - // we do the intersections in view space - osg::BoundingSphere nodeBound = node->getBound(); - osg::Matrixf mat = *cv->getModelViewMatrix(); - transformBoundingSphere(mat, nodeBound); - - std::vector lightList; - for (unsigned int i=0; i (8 - mLightManager->getStartLight()); + if (lightList.empty()) + { + traverse(node, nv); + return; + } - if (lightList.size() > maxLights) - { - //std::cerr << "More than 8 lights!" << std::endl; + unsigned int maxLights = static_cast (8 - mLightManager->getStartLight()); - // TODO: sort lights by certain criteria + if (lightList.size() > maxLights) + { + //std::cerr << "More than 8 lights!" << std::endl; - while (lightList.size() > maxLights) - lightList.pop_back(); - } + // TODO: sort lights by certain criteria - stateset = mLightManager->getLightListStateSet(lightList); - statesets[node] = stateset; + while (lightList.size() > maxLights) + lightList.pop_back(); } - if (stateset) - cv->pushStateSet(stateset); + osg::StateSet* stateset = mLightManager->getLightListStateSet(lightList); + + cv->pushStateSet(stateset); traverse(node, nv); - if (stateset) - cv->popStateSet(); + cv->popStateSet(); } else traverse(node, nv); From 18f4eaa8dcb188d7f9399352542326455c5ca577 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 15 Jun 2015 18:56:40 +0200 Subject: [PATCH 1545/3725] Preliminary handling for overflowing light lists --- components/sceneutil/lightmanager.cpp | 37 +++++++++++++++++++++------ components/sceneutil/lightmanager.hpp | 2 +- 2 files changed, 30 insertions(+), 9 deletions(-) diff --git a/components/sceneutil/lightmanager.cpp b/components/sceneutil/lightmanager.cpp index 713524a41..444530dbe 100644 --- a/components/sceneutil/lightmanager.cpp +++ b/components/sceneutil/lightmanager.cpp @@ -179,7 +179,7 @@ namespace SceneUtil // possible optimization: return a StateSet containing all requested lights plus some extra lights (if a suitable one exists) size_t hash = 0; for (unsigned int i=0; igetId()); + boost::hash_combine(hash, lightList[i]->mLightSource->getId()); LightStateSetMap::iterator found = mStateSetCache.find(hash); if (found != mStateSetCache.end()) @@ -189,7 +189,7 @@ namespace SceneUtil std::vector > lights; for (unsigned int i=0; igetLight()); + lights.push_back(lightList[i]->mLightSource->getLight()); osg::ref_ptr attr = new LightStateAttribute(mStartLight, lights); @@ -237,6 +237,12 @@ namespace SceneUtil mId = sLightId++; } + + bool sortLights (const LightManager::LightSourceTransform* left, const LightManager::LightSourceTransform* right) + { + return left->mViewBound.center().length2() < right->mViewBound.center().length2(); + } + void LightListCallback::operator()(osg::Node *node, osg::NodeVisitor *nv) { osgUtil::CullVisitor* cv = static_cast(nv); @@ -279,12 +285,12 @@ namespace SceneUtil osg::Matrixf mat = *cv->getModelViewMatrix(); transformBoundingSphere(mat, nodeBound); - std::vector lightList; + std::vector lightList; for (unsigned int i=0; i maxLights) { - //std::cerr << "More than 8 lights!" << std::endl; + // remove lights culled by this camera + for (LightManager::LightList::iterator it = lightList.begin(); it != lightList.end();) + { + osg::CullStack::CullingStack& stack = cv->getProjectionCullingStack(); - // TODO: sort lights by certain criteria + if (stack.back().isCulled(osg::BoundingSphere((*it)->mViewBound.center(), (*it)->mViewBound.radius()*2))) + { + it = lightList.erase(it); + continue; + } + else + ++it; + } - while (lightList.size() > maxLights) - lightList.pop_back(); + if (lightList.size() > maxLights) + { + // sort by proximity to camera, then get rid of furthest away lights + std::sort(lightList.begin(), lightList.end(), sortLights); + while (lightList.size() > maxLights) + lightList.pop_back(); + } } osg::StateSet* stateset = mLightManager->getLightListStateSet(lightList); diff --git a/components/sceneutil/lightmanager.hpp b/components/sceneutil/lightmanager.hpp index ac819958f..f338e42ec 100644 --- a/components/sceneutil/lightmanager.hpp +++ b/components/sceneutil/lightmanager.hpp @@ -85,7 +85,7 @@ namespace SceneUtil const std::vector& getLights() const; - typedef std::vector LightList; + typedef std::vector LightList; osg::ref_ptr getLightListStateSet(const LightList& lightList); From aad8e7b6d0a832e5aa9f874f65aa85a4dd133de7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 15 Jun 2015 19:37:44 +0200 Subject: [PATCH 1546/3725] Light culling fix --- components/sceneutil/lightmanager.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/components/sceneutil/lightmanager.cpp b/components/sceneutil/lightmanager.cpp index 444530dbe..bcdb4af88 100644 --- a/components/sceneutil/lightmanager.cpp +++ b/components/sceneutil/lightmanager.cpp @@ -145,6 +145,10 @@ namespace SceneUtil { mLightsInViewSpace = false; mLights.clear(); + + // do an occasional cleanup for orphaned lights + if (mStateSetCache.size() > 5000) + mStateSetCache.clear(); } void LightManager::addLight(LightSource* lightSource, osg::Matrix worldMat) @@ -304,11 +308,14 @@ namespace SceneUtil if (lightList.size() > maxLights) { // remove lights culled by this camera - for (LightManager::LightList::iterator it = lightList.begin(); it != lightList.end();) + for (LightManager::LightList::iterator it = lightList.begin(); it != lightList.end() && lightList.size() > maxLights; ) { - osg::CullStack::CullingStack& stack = cv->getProjectionCullingStack(); + osg::CullStack::CullingStack& stack = cv->getModelViewCullingStack(); - if (stack.back().isCulled(osg::BoundingSphere((*it)->mViewBound.center(), (*it)->mViewBound.radius()*2))) + osg::BoundingSphere bs = (*it)->mViewBound; + bs._radius = bs._radius*2; + osg::CullingSet& cullingSet = stack.front(); + if (cullingSet.isCulled(bs)) { it = lightList.erase(it); continue; From 98a77f68a335a7fc878e3c7dba4a509bad8e4e68 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 15 Jun 2015 20:04:36 +0200 Subject: [PATCH 1547/3725] Fix AiWander::fastForward using incorrect pathgrid coordinates when actor recently moved to a new cell --- apps/openmw/mwmechanics/aiwander.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 076636974..e6fd68469 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -669,6 +669,9 @@ namespace MWMechanics MWBase::Environment::get().getWorld()->moveObject(actor, static_cast(dest.mX), static_cast(dest.mY), static_cast(dest.mZ)); actor.getClass().adjustPosition(actor, false); + + // may have changed cell + mStoredAvailableNodes = false; } void AiWander::getAllowedNodes(const MWWorld::Ptr& actor, const ESM::Cell* cell) From 5347d407d805e234a4022896cf4d94e213aa2f8f Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 15 Jun 2015 20:05:12 +0200 Subject: [PATCH 1548/3725] Disallow AiWander fast-forward for water creatures Pathgrid nodes are usually above the water level, so appearing at a random node would have the creature break out of the water level it's supposed to be constrained to. --- apps/openmw/mwmechanics/aiwander.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index e6fd68469..1f4133c0a 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -651,6 +651,9 @@ namespace MWMechanics if (mAllowedNodes.empty()) return; + if (actor.getClass().isPureWaterCreature(actor)) + return; + state.moveIn(new AiWanderStorage()); int index = OEngine::Misc::Rng::rollDice(mAllowedNodes.size()); From 2d072aab2dee052e1657b9648d72d72c019c54c3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 15 Jun 2015 22:42:14 +0200 Subject: [PATCH 1549/3725] Broken bone references from .kf files are no longer a fatal error (Bug #2687) --- apps/openmw/mwrender/animation.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 62d50df0d..9337b5a51 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -347,7 +347,10 @@ namespace MWRender std::string bonename = Misc::StringUtils::lowerCase(it->first); NodeMap::const_iterator found = mNodeMap.find(bonename); if (found == mNodeMap.end()) - throw std::runtime_error("addAnimSource: can't find bone " + bonename); + { + std::cerr << "addAnimSource: can't find bone '" + bonename << "' in " << model << " (referenced by " << kfname << ")" << std::endl; + continue; + } osg::Node* node = found->second; From d906a9d7d10b0b9d7d16d65b7cf3c727ffe32c29 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Tue, 16 Jun 2015 00:19:51 +0300 Subject: [PATCH 1550/3725] DataDisplayDelegate doesn't draw a text outside a table cell --- .../opencs/view/world/datadisplaydelegate.cpp | 32 ++++++++++--------- .../opencs/view/world/datadisplaydelegate.hpp | 1 - 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/apps/opencs/view/world/datadisplaydelegate.cpp b/apps/opencs/view/world/datadisplaydelegate.cpp index b9df52bf7..71686d77d 100644 --- a/apps/opencs/view/world/datadisplaydelegate.cpp +++ b/apps/opencs/view/world/datadisplaydelegate.cpp @@ -15,8 +15,6 @@ CSVWorld::DataDisplayDelegate::DataDisplayDelegate(const ValueList &values, mIcons (icons), mIconSize (QSize(16, 16)), mIconLeftOffset(3), mTextLeftOffset(8), mSettingKey (pageName + '/' + settingName) { - mTextAlignment.setAlignment (Qt::AlignLeft | Qt::AlignVCenter ); - buildPixmaps(); QString value = @@ -81,24 +79,28 @@ void CSVWorld::DataDisplayDelegate::paint (QPainter *painter, const QStyleOption void CSVWorld::DataDisplayDelegate::paintIcon (QPainter *painter, const QStyleOptionViewItem &option, int index) const { - //function-level statics QRect iconRect = option.rect; QRect textRect = iconRect; - const QString &text = mValues.at(index).second; - - iconRect.setSize (mIconSize); - iconRect.translate(mIconLeftOffset, (option.rect.height() - iconRect.height())/2); - - if (mDisplayMode == Mode_IconAndText ) + iconRect.setLeft(iconRect.left() + mIconLeftOffset); + iconRect.setRight(option.rect.right()); + if (mDisplayMode == Mode_IconAndText) { - textRect.translate (iconRect.width() + mTextLeftOffset, 0 ); - painter->drawText (textRect, text, mTextAlignment); + iconRect.setWidth(mIconSize.width()); + textRect.setLeft(iconRect.right() + mTextLeftOffset); + textRect.setRight(option.rect.right()); + + QString text = option.fontMetrics.elidedText(mValues.at(index).second, + option.textElideMode, + textRect.width()); + QApplication::style()->drawItemText(painter, + textRect, + Qt::AlignLeft | Qt::AlignVCenter, + option.palette, + true, + text); } - else - iconRect.translate( (option.rect.width() - iconRect.width()) / 2, 0); - - painter->drawPixmap (iconRect, mPixmaps.at(index).second); + QApplication::style()->drawItemPixmap(painter, iconRect, Qt::AlignCenter, mPixmaps.at(index).second); } void CSVWorld::DataDisplayDelegate::updateUserSetting (const QString &name, diff --git a/apps/opencs/view/world/datadisplaydelegate.hpp b/apps/opencs/view/world/datadisplaydelegate.hpp index f6e4c2688..07fa1fd8d 100755 --- a/apps/opencs/view/world/datadisplaydelegate.hpp +++ b/apps/opencs/view/world/datadisplaydelegate.hpp @@ -30,7 +30,6 @@ namespace CSVWorld private: std::vector > mPixmaps; - QTextOption mTextAlignment; QSize mIconSize; int mIconLeftOffset; int mTextLeftOffset; From cccf6c6bdd272c28f848935023b9e9ac60401191 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Tue, 16 Jun 2015 12:48:45 +1000 Subject: [PATCH 1551/3725] Rebuild the list of available content files when opening the open/new dialogues. Should resolve Bug #2644. --- apps/opencs/editor.cpp | 14 ++++++++++++-- apps/opencs/editor.hpp | 2 +- apps/opencs/view/doc/filedialog.cpp | 8 ++++++-- apps/opencs/view/doc/filedialog.hpp | 1 + components/contentselector/model/contentmodel.cpp | 7 +++++++ components/contentselector/model/contentmodel.hpp | 1 + .../contentselector/view/contentselector.cpp | 5 +++++ .../contentselector/view/contentselector.hpp | 1 + components/files/configurationmanager.cpp | 6 +++++- components/files/configurationmanager.hpp | 2 +- 10 files changed, 40 insertions(+), 7 deletions(-) diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index efd7cf4ec..80d8b8a93 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -95,7 +95,7 @@ void CS::Editor::setupDataFiles (const Files::PathContainer& dataDirs) } } -std::pair > CS::Editor::readConfig() +std::pair > CS::Editor::readConfig(bool quiet) { boost::program_options::variables_map variables; boost::program_options::options_description desc("Syntax: openmw-cs \nAllowed options"); @@ -115,7 +115,7 @@ std::pair > CS::Editor::readConfi boost::program_options::notify(variables); - mCfgMgr.readConfiguration(variables, desc); + mCfgMgr.readConfiguration(variables, desc, /*quiet*/true); mDocumentManager.setEncoding ( ToUTF8::calculateEncoding (variables["encoding"].as())); @@ -195,6 +195,11 @@ void CS::Editor::cancelCreateGame() void CS::Editor::createAddon() { mStartup.hide(); + + mFileDialog.clearFiles(); + std::pair > config = readConfig(/*quiet*/true); + setupDataFiles (config.first); + mFileDialog.showDialog (CSVDoc::ContentAction_New); } @@ -215,6 +220,11 @@ void CS::Editor::cancelFileDialog() void CS::Editor::loadDocument() { mStartup.hide(); + + mFileDialog.clearFiles(); + std::pair > config = readConfig(/*quiet*/true); + setupDataFiles (config.first); + mFileDialog.showDialog (CSVDoc::ContentAction_Edit); } diff --git a/apps/opencs/editor.hpp b/apps/opencs/editor.hpp index eb85743a3..cbf306df8 100644 --- a/apps/opencs/editor.hpp +++ b/apps/opencs/editor.hpp @@ -62,7 +62,7 @@ namespace CS void setupDataFiles (const Files::PathContainer& dataDirs); - std::pair > readConfig(); + std::pair > readConfig(bool quiet=false); ///< \return data paths // not implemented diff --git a/apps/opencs/view/doc/filedialog.cpp b/apps/opencs/view/doc/filedialog.cpp index eeec81109..b6f4aaec3 100644 --- a/apps/opencs/view/doc/filedialog.cpp +++ b/apps/opencs/view/doc/filedialog.cpp @@ -33,6 +33,11 @@ void CSVDoc::FileDialog::addFiles(const QString &path) mSelector->addFiles(path); } +void CSVDoc::FileDialog::clearFiles() +{ + mSelector->clearFiles(); +} + QStringList CSVDoc::FileDialog::selectedFilePaths() { QStringList filePaths; @@ -105,7 +110,6 @@ void CSVDoc::FileDialog::buildNewFileView() connect (mFileWidget, SIGNAL (nameChanged(const QString &, bool)), this, SLOT (slotUpdateAcceptButton(const QString &, bool))); - } ui.projectGroupBoxLayout->insertWidget (0, mFileWidget); @@ -139,7 +143,7 @@ void CSVDoc::FileDialog::slotUpdateAcceptButton(int) { QString name = ""; - if (mAction == ContentAction_New) + if (mFileWidget && mAction == ContentAction_New) name = mFileWidget->getName(); slotUpdateAcceptButton (name, true); diff --git a/apps/opencs/view/doc/filedialog.hpp b/apps/opencs/view/doc/filedialog.hpp index 3c23a5cb5..648836565 100644 --- a/apps/opencs/view/doc/filedialog.hpp +++ b/apps/opencs/view/doc/filedialog.hpp @@ -45,6 +45,7 @@ namespace CSVDoc void showDialog (ContentAction action); void addFiles (const QString &path); + void clearFiles (); QString filename() const; QStringList selectedFilePaths(); diff --git a/components/contentselector/model/contentmodel.cpp b/components/contentselector/model/contentmodel.cpp index d000290e6..769afee37 100644 --- a/components/contentselector/model/contentmodel.cpp +++ b/components/contentselector/model/contentmodel.cpp @@ -473,6 +473,13 @@ void ContentSelectorModel::ContentModel::addFiles(const QString &path) sortFiles(); } +void ContentSelectorModel::ContentModel::clearFiles() +{ + beginRemoveRows(QModelIndex(), 0, mFiles.count()-1); + mFiles.clear(); + endRemoveRows(); +} + QStringList ContentSelectorModel::ContentModel::gameFiles() const { QStringList gameFiles; diff --git a/components/contentselector/model/contentmodel.hpp b/components/contentselector/model/contentmodel.hpp index ab965ad69..bc785a276 100644 --- a/components/contentselector/model/contentmodel.hpp +++ b/components/contentselector/model/contentmodel.hpp @@ -44,6 +44,7 @@ namespace ContentSelectorModel bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent); void addFiles(const QString &path); + void clearFiles(); QModelIndex indexFromItem(const EsmFile *item) const; const EsmFile *item(const QString &name) const; diff --git a/components/contentselector/view/contentselector.cpp b/components/contentselector/view/contentselector.cpp index 2fae8e74b..78aa20cd2 100644 --- a/components/contentselector/view/contentselector.cpp +++ b/components/contentselector/view/contentselector.cpp @@ -150,6 +150,11 @@ void ContentSelectorView::ContentSelector::addFiles(const QString &path) mContentModel->uncheckAll(); } +void ContentSelectorView::ContentSelector::clearFiles() +{ + mContentModel->clearFiles(); +} + QString ContentSelectorView::ContentSelector::currentFile() const { QModelIndex currentIdx = ui.addonView->currentIndex(); diff --git a/components/contentselector/view/contentselector.hpp b/components/contentselector/view/contentselector.hpp index e455807c9..4e9fcfb3c 100644 --- a/components/contentselector/view/contentselector.hpp +++ b/components/contentselector/view/contentselector.hpp @@ -29,6 +29,7 @@ namespace ContentSelectorView QString currentFile() const; void addFiles(const QString &path); + void clearFiles(); void setProfileContent (const QStringList &fileList); void clearCheckStates(); diff --git a/components/files/configurationmanager.cpp b/components/files/configurationmanager.cpp index e321b5814..dc6f02b60 100644 --- a/components/files/configurationmanager.cpp +++ b/components/files/configurationmanager.cpp @@ -52,8 +52,11 @@ void ConfigurationManager::setupTokensMapping() } void ConfigurationManager::readConfiguration(boost::program_options::variables_map& variables, - boost::program_options::options_description& description) + boost::program_options::options_description& description, bool quiet) { + bool silent = mSilent; + mSilent = quiet; + loadConfig(mFixedPath.getUserConfigPath(), variables, description); boost::program_options::notify(variables); @@ -62,6 +65,7 @@ void ConfigurationManager::readConfiguration(boost::program_options::variables_m loadConfig(mFixedPath.getGlobalConfigPath(), variables, description); boost::program_options::notify(variables); + mSilent = silent; } void ConfigurationManager::processPaths(Files::PathContainer& dataDirs, bool create) diff --git a/components/files/configurationmanager.hpp b/components/files/configurationmanager.hpp index 24b08c523..5f0062c2e 100644 --- a/components/files/configurationmanager.hpp +++ b/components/files/configurationmanager.hpp @@ -29,7 +29,7 @@ struct ConfigurationManager virtual ~ConfigurationManager(); void readConfiguration(boost::program_options::variables_map& variables, - boost::program_options::options_description& description); + boost::program_options::options_description& description, bool quiet=false); void processPaths(Files::PathContainer& dataDirs, bool create = false); ///< \param create Try creating the directory, if it does not exist. From 6a47ea9a676949c93dd1339f51a7b709b52ce81d Mon Sep 17 00:00:00 2001 From: cc9cii Date: Tue, 16 Jun 2015 13:09:44 +1000 Subject: [PATCH 1552/3725] fix typo --- apps/opencs/editor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 80d8b8a93..bd4f57304 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -115,7 +115,7 @@ std::pair > CS::Editor::readConfi boost::program_options::notify(variables); - mCfgMgr.readConfiguration(variables, desc, /*quiet*/true); + mCfgMgr.readConfiguration(variables, desc, quiet); mDocumentManager.setEncoding ( ToUTF8::calculateEncoding (variables["encoding"].as())); From 0ffb2bc6bc4527975ccb827a2d953d80761d7566 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Tue, 16 Jun 2015 14:18:47 +0300 Subject: [PATCH 1553/3725] Proper size hint for EnumDelegate --- apps/opencs/view/world/enumdelegate.cpp | 31 +++++++++++++++++++++++++ apps/opencs/view/world/enumdelegate.hpp | 2 ++ 2 files changed, 33 insertions(+) diff --git a/apps/opencs/view/world/enumdelegate.cpp b/apps/opencs/view/world/enumdelegate.cpp index 4b76bf9d6..b9eca670a 100644 --- a/apps/opencs/view/world/enumdelegate.cpp +++ b/apps/opencs/view/world/enumdelegate.cpp @@ -115,6 +115,37 @@ void CSVWorld::EnumDelegate::paint (QPainter *painter, const QStyleOptionViewIte } } +QSize CSVWorld::EnumDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const +{ + if (index.data().isValid()) + { + int value = index.data().toInt(); + + // Calculate the size hint as for a combobox. + // So, the whole text is visible (isn't elided) when the editor is created + QStyleOptionComboBox itemOption; + itemOption.fontMetrics = option.fontMetrics; + itemOption.palette = option.palette; + itemOption.rect = option.rect; + itemOption.state = option.state; + + std::vector >::const_iterator current = mValues.begin(); + std::vector >::const_iterator end = mValues.end(); + for (; current != end; ++current) + { + if (current->first == value) + { + QSize valueSize = QSize(itemOption.fontMetrics.width(current->second), + itemOption.fontMetrics.height()); + itemOption.currentText = current->second; + return QApplication::style()->sizeFromContents(QStyle::CT_ComboBox, + &itemOption, + valueSize); + } + } + } + return option.rect.size(); +} CSVWorld::EnumDelegateFactory::EnumDelegateFactory() {} diff --git a/apps/opencs/view/world/enumdelegate.hpp b/apps/opencs/view/world/enumdelegate.hpp index 82890c791..757dbf0b4 100644 --- a/apps/opencs/view/world/enumdelegate.hpp +++ b/apps/opencs/view/world/enumdelegate.hpp @@ -46,6 +46,8 @@ namespace CSVWorld virtual void paint (QPainter *painter, const QStyleOptionViewItem& option, const QModelIndex& index) const; + virtual QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const; + }; class EnumDelegateFactory : public CommandDelegateFactory From 2c1ca33a207c50e93c3c1527c2326bfb5090dd33 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Tue, 16 Jun 2015 15:39:54 +0300 Subject: [PATCH 1554/3725] Refactor Enum- and DataDisplayDelegate code --- .../opencs/view/world/datadisplaydelegate.cpp | 11 +-- apps/opencs/view/world/enumdelegate.cpp | 88 +++++++++---------- apps/opencs/view/world/enumdelegate.hpp | 2 + 3 files changed, 45 insertions(+), 56 deletions(-) diff --git a/apps/opencs/view/world/datadisplaydelegate.cpp b/apps/opencs/view/world/datadisplaydelegate.cpp index 71686d77d..5f23d95d9 100644 --- a/apps/opencs/view/world/datadisplaydelegate.cpp +++ b/apps/opencs/view/world/datadisplaydelegate.cpp @@ -62,16 +62,11 @@ void CSVWorld::DataDisplayDelegate::paint (QPainter *painter, const QStyleOption EnumDelegate::paint(painter, option, index); else { - unsigned int i = 0; - - for (; i < mValues.size(); ++i) + int valueIndex = getValueIndex(index); + if (valueIndex != -1) { - if (mValues.at(i).first == index.data().toInt()) - break; + paintIcon(painter, option, valueIndex); } - - if (i < mValues.size() ) - paintIcon (painter, option, i); } painter->restore(); diff --git a/apps/opencs/view/world/enumdelegate.cpp b/apps/opencs/view/world/enumdelegate.cpp index b9eca670a..2190a62c6 100644 --- a/apps/opencs/view/world/enumdelegate.cpp +++ b/apps/opencs/view/world/enumdelegate.cpp @@ -10,6 +10,24 @@ #include "../../model/world/commands.hpp" +int CSVWorld::EnumDelegate::getValueIndex(const QModelIndex &index, int role) const +{ + if (index.isValid() && index.data(role).isValid()) + { + int value = index.data(role).toInt(); + + int size = static_cast(mValues.size()); + for (int i = 0; i < size; ++i) + { + if (value == mValues.at(i).first) + { + return i; + } + } + } + return -1; +} + void CSVWorld::EnumDelegate::setModelDataImp (QWidget *editor, QAbstractItemModel *model, const QModelIndex& index) const { @@ -67,60 +85,43 @@ QWidget *CSVWorld::EnumDelegate::createEditor(QWidget *parent, const QStyleOptio void CSVWorld::EnumDelegate::setEditorData (QWidget *editor, const QModelIndex& index, bool tryDisplay) const { - if (QComboBox *comboBox = dynamic_cast (editor)) + if (QComboBox *comboBox = dynamic_cast(editor)) { - QVariant data = index.data (Qt::EditRole); - - if (tryDisplay && !data.isValid()) + int role = Qt::EditRole; + if (tryDisplay && !index.data(role).isValid()) { - data = index.data (Qt::DisplayRole); - if (!data.isValid()) + role = Qt::DisplayRole; + if (!index.data(role).isValid()) { return; } } - int value = data.toInt(); - - std::size_t size = mValues.size(); - - for (std::size_t i=0; isetCurrentIndex (i); - break; - } + int valueIndex = getValueIndex(index, role); + if (valueIndex != -1) + { + comboBox->setCurrentIndex(valueIndex); + } } } void CSVWorld::EnumDelegate::paint (QPainter *painter, const QStyleOptionViewItem& option, const QModelIndex& index) const { - if (index.data().isValid()) + int valueIndex = getValueIndex(index); + if (valueIndex != -1) { - QStyleOptionViewItemV4 option2 (option); - - int value = index.data().toInt(); - - for (std::vector >::const_iterator iter (mValues.begin()); - iter!=mValues.end(); ++iter) - if (iter->first==value) - { - option2.text = iter->second; - - QApplication::style()->drawControl (QStyle::CE_ItemViewItem, &option2, painter); - - break; - } + QStyleOptionViewItemV4 itemOption(option); + itemOption.text = mValues.at(valueIndex).second; + QApplication::style()->drawControl(QStyle::CE_ItemViewItem, &itemOption, painter); } } QSize CSVWorld::EnumDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const { - if (index.data().isValid()) + int valueIndex = getValueIndex(index); + if (valueIndex != -1) { - int value = index.data().toInt(); - // Calculate the size hint as for a combobox. // So, the whole text is visible (isn't elided) when the editor is created QStyleOptionComboBox itemOption; @@ -129,20 +130,11 @@ QSize CSVWorld::EnumDelegate::sizeHint(const QStyleOptionViewItem &option, const itemOption.rect = option.rect; itemOption.state = option.state; - std::vector >::const_iterator current = mValues.begin(); - std::vector >::const_iterator end = mValues.end(); - for (; current != end; ++current) - { - if (current->first == value) - { - QSize valueSize = QSize(itemOption.fontMetrics.width(current->second), - itemOption.fontMetrics.height()); - itemOption.currentText = current->second; - return QApplication::style()->sizeFromContents(QStyle::CT_ComboBox, - &itemOption, - valueSize); - } - } + const QString &valueText = mValues.at(valueIndex).second; + QSize valueSize = QSize(itemOption.fontMetrics.width(valueText), itemOption.fontMetrics.height()); + + itemOption.currentText = valueText; + return QApplication::style()->sizeFromContents(QStyle::CT_ComboBox, &itemOption, valueSize); } return option.rect.size(); } diff --git a/apps/opencs/view/world/enumdelegate.hpp b/apps/opencs/view/world/enumdelegate.hpp index 757dbf0b4..a31945427 100644 --- a/apps/opencs/view/world/enumdelegate.hpp +++ b/apps/opencs/view/world/enumdelegate.hpp @@ -19,6 +19,8 @@ namespace CSVWorld std::vector > mValues; + int getValueIndex(const QModelIndex &index, int role = Qt::DisplayRole) const; + private: virtual void setModelDataImp (QWidget *editor, QAbstractItemModel *model, From b73947033d2ca0494da5d4b56c8b592b4b02bc2d Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 16 Jun 2015 16:33:31 +0200 Subject: [PATCH 1555/3725] Rotate sky meshes --- apps/openmw/mwrender/sky.cpp | 75 +++++++++++++++++++----------------- apps/openmw/mwrender/sky.hpp | 6 ++- 2 files changed, 44 insertions(+), 37 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 0cd1f64d2..07e433208 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -204,20 +204,6 @@ public: } }; -class DisableCullingVisitor : public osg::NodeVisitor -{ -public: - DisableCullingVisitor() - : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) - { - } - - void apply(osg::Geode &geode) - { - geode.setCullingActive(false); - } -}; - class ModVertexAlphaVisitor : public osg::NodeVisitor { public: @@ -483,6 +469,7 @@ private: SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneManager) : mSceneManager(sceneManager) + , mAtmosphereNightRoll(0.f) , mCreated(false) , mMoonRed(false) , mIsStorm(false) @@ -528,14 +515,18 @@ void SkyManager::create() mAtmosphereUpdater = new AtmosphereUpdater; mAtmosphereDay->addUpdateCallback(mAtmosphereUpdater); + mAtmosphereNightNode = new osg::PositionAttitudeTransform; + mAtmosphereNightNode->setNodeMask(0); + mRootNode->addChild(mAtmosphereNightNode); + + osg::ref_ptr atmosphereNight; if (mSceneManager->getVFS()->exists("meshes/sky_night_02.nif")) - mAtmosphereNight = mSceneManager->createInstance("meshes/sky_night_02.nif", mRootNode); + atmosphereNight = mSceneManager->createInstance("meshes/sky_night_02.nif", mAtmosphereNightNode); else - mAtmosphereNight = mSceneManager->createInstance("meshes/sky_night_01.nif", mRootNode); - mAtmosphereNight->getOrCreateStateSet()->setAttributeAndModes(createAlphaTrackingUnlitMaterial(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + atmosphereNight = mSceneManager->createInstance("meshes/sky_night_01.nif", mAtmosphereNightNode); + atmosphereNight->getOrCreateStateSet()->setAttributeAndModes(createAlphaTrackingUnlitMaterial(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); ModVertexAlphaVisitor modStars(2); - mAtmosphereNight->accept(modStars); - mAtmosphereNight->setNodeMask(0); + atmosphereNight->accept(modStars); mSun.reset(new Sun(mRootNode, mSceneManager)); @@ -543,14 +534,16 @@ void SkyManager::create() mMasser.reset(new Moon(mRootNode, mSceneManager, fallback->getFallbackFloat("Moons_Masser_Size")/100, Moon::Type_Masser)); mSecunda.reset(new Moon(mRootNode, mSceneManager, fallback->getFallbackFloat("Moons_Secunda_Size")/100, Moon::Type_Secunda)); - mCloudNode = mSceneManager->createInstance("meshes/sky_clouds_01.nif", mRootNode); + mCloudNode = new osg::PositionAttitudeTransform; + mRootNode->addChild(mCloudNode); + osg::ref_ptr clouds = mSceneManager->createInstance("meshes/sky_clouds_01.nif", mCloudNode); ModVertexAlphaVisitor modClouds(1); - mCloudNode->accept(modClouds); + clouds->accept(modClouds); mCloudUpdater = new CloudUpdater; - mCloudNode->addUpdateCallback(mCloudUpdater); + clouds->addUpdateCallback(mCloudUpdater); - mCloudNode->getOrCreateStateSet()->setAttributeAndModes(createAlphaTrackingUnlitMaterial(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + clouds->getOrCreateStateSet()->setAttributeAndModes(createAlphaTrackingUnlitMaterial(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); osg::ref_ptr depth = new osg::Depth; depth->setWriteMask(false); @@ -594,12 +587,18 @@ void SkyManager::updateRain(float dt) void SkyManager::update(float duration) { if (!mEnabled) return; - //const MWWorld::Fallback* fallback=MWBase::Environment::get().getWorld()->getFallback(); - //if (mIsStorm) - // mCloudNode->setOrientation(Ogre::Vector3::UNIT_Y.getRotationTo(mStormDirection)); - //else - // mCloudNode->setOrientation(Ogre::Quaternion::IDENTITY); + if (mIsStorm) + { + osg::Quat quat; + quat.makeRotate(osg::Vec3f(0,1,0), mStormDirection); + + if (mParticleNode) + mParticleNode->setAttitude(quat); + mCloudNode->setAttitude(quat); + } + else + mCloudNode->setAttitude(osg::Quat()); updateRain(duration); @@ -611,6 +610,7 @@ void SkyManager::update(float duration) mMasser->setPhase( static_cast( (int) ((mDay % 32)/4.f)) ); mSecunda->setPhase ( static_cast( (int) ((mDay % 32)/4.f)) ); + //const MWWorld::Fallback* fallback=MWBase::Environment::get().getWorld()->getFallback(); //mSecunda->setColour ( mMoonRed ? fallback->getFallbackColour("Moons_Script_Color") : ColourValue(1,1,1,1)); //mMasser->setColour (ColourValue(1,1,1,1)); @@ -641,7 +641,9 @@ void SkyManager::update(float duration) } // rotate the stars by 360 degrees every 4 days - //mAtmosphereNight->roll(Degree(MWBase::Environment::get().getWorld()->getTimeScaleFactor()*duration*360 / (3600*96.f))); + mAtmosphereNightRoll += MWBase::Environment::get().getWorld()->getTimeScaleFactor()*duration*osg::DegreesToRadians(360.f) / (3600*96.f); + if (mAtmosphereNightNode->getNodeMask() != 0) + mAtmosphereNightNode->setAttitude(osg::Quat(mAtmosphereNightRoll, osg::Vec3f(0,0,1))); } void SkyManager::setEnabled(bool enabled) @@ -678,15 +680,18 @@ void SkyManager::setWeather(const MWWorld::WeatherResult& weather) if (mCurrentParticleEffect.empty()) { - if (mParticleEffect) - mRootNode->removeChild(mParticleEffect); + if (mParticleNode) + mRootNode->removeChild(mParticleNode); mParticleEffect = NULL; } else { - mParticleEffect = mSceneManager->createInstance(mCurrentParticleEffect, mRootNode); - DisableCullingVisitor visitor; - mParticleEffect->accept(visitor); + if (!mParticleNode) + { + mParticleNode = new osg::PositionAttitudeTransform; + mRootNode->addChild(mParticleNode); + } + mParticleEffect = mSceneManager->createInstance(mCurrentParticleEffect, mParticleNode); SceneUtil::AssignControllerSourcesVisitor assignVisitor(boost::shared_ptr(new SceneUtil::FrameTimeSource)); mParticleEffect->accept(assignVisitor); @@ -757,7 +762,7 @@ void SkyManager::setWeather(const MWWorld::WeatherResult& weather) } } - //mAtmosphereNight->setNodeMask((weather.mNight && mEnabled) ? ~0 : 0); + mAtmosphereNightNode->setNodeMask(weather.mNight ? ~0 : 0); /* diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index d7cd88de5..e11f20c18 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -93,15 +93,17 @@ namespace MWRender osg::ref_ptr mRootNode; + osg::ref_ptr mParticleNode; osg::ref_ptr mParticleEffect; - osg::ref_ptr mCloudNode; + osg::ref_ptr mCloudNode; osg::ref_ptr mCloudUpdater; osg::ref_ptr mAtmosphereDay; - osg::ref_ptr mAtmosphereNight; + osg::ref_ptr mAtmosphereNightNode; + float mAtmosphereNightRoll; osg::ref_ptr mAtmosphereUpdater; From 6cfee630aaa24edff56efa9fc1b124272c2e1f92 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Tue, 16 Jun 2015 21:25:06 +0300 Subject: [PATCH 1556/3725] Proper size hint for DataDisplayDelegate --- .../opencs/view/world/datadisplaydelegate.cpp | 37 +++++++++++++++---- .../opencs/view/world/datadisplaydelegate.hpp | 7 ++-- 2 files changed, 32 insertions(+), 12 deletions(-) diff --git a/apps/opencs/view/world/datadisplaydelegate.cpp b/apps/opencs/view/world/datadisplaydelegate.cpp index 5f23d95d9..77ed33daa 100644 --- a/apps/opencs/view/world/datadisplaydelegate.cpp +++ b/apps/opencs/view/world/datadisplaydelegate.cpp @@ -12,7 +12,8 @@ CSVWorld::DataDisplayDelegate::DataDisplayDelegate(const ValueList &values, const QString &settingName, QObject *parent) : EnumDelegate (values, dispatcher, document, parent), mDisplayMode (Mode_TextOnly), - mIcons (icons), mIconSize (QSize(16, 16)), mIconLeftOffset(3), + mIcons (icons), mIconSize (QSize(16, 16)), + mHorizontalMargin(QApplication::style()->pixelMetric(QStyle::PM_FocusFrameHMargin) + 1), mTextLeftOffset(8), mSettingKey (pageName + '/' + settingName) { buildPixmaps(); @@ -43,14 +44,34 @@ void CSVWorld::DataDisplayDelegate::setIconSize(const QSize& size) buildPixmaps(); } -void CSVWorld::DataDisplayDelegate::setIconLeftOffset(int offset) +void CSVWorld::DataDisplayDelegate::setTextLeftOffset(int offset) { - mIconLeftOffset = offset; + mTextLeftOffset = offset; } -void CSVWorld::DataDisplayDelegate::setTextLeftOffset(int offset) +QSize CSVWorld::DataDisplayDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const { - mTextLeftOffset = offset; + QSize size = EnumDelegate::sizeHint(option, index); + + int valueIndex = getValueIndex(index); + if (valueIndex != -1) + { + if (mDisplayMode == Mode_IconOnly) + { + size.setWidth(mIconSize.width() + 2 * mHorizontalMargin); + } + else if (mDisplayMode == Mode_IconAndText) + { + int valueWidth = option.fontMetrics.width(mValues.at(valueIndex).second); + size.setWidth(size.width() + mIconSize.width() + mTextLeftOffset); + } + + if (mDisplayMode != Mode_TextOnly) + { + size.setHeight(qMax(size.height(), mIconSize.height())); + } + } + return size; } void CSVWorld::DataDisplayDelegate::paint (QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const @@ -77,13 +98,13 @@ void CSVWorld::DataDisplayDelegate::paintIcon (QPainter *painter, const QStyleOp QRect iconRect = option.rect; QRect textRect = iconRect; - iconRect.setLeft(iconRect.left() + mIconLeftOffset); - iconRect.setRight(option.rect.right()); + iconRect.setLeft(iconRect.left() + mHorizontalMargin); + iconRect.setRight(option.rect.right() - mHorizontalMargin); if (mDisplayMode == Mode_IconAndText) { iconRect.setWidth(mIconSize.width()); textRect.setLeft(iconRect.right() + mTextLeftOffset); - textRect.setRight(option.rect.right()); + textRect.setRight(option.rect.right() - mHorizontalMargin); QString text = option.fontMetrics.elidedText(mValues.at(index).second, option.textElideMode, diff --git a/apps/opencs/view/world/datadisplaydelegate.hpp b/apps/opencs/view/world/datadisplaydelegate.hpp index 07fa1fd8d..e565a3469 100755 --- a/apps/opencs/view/world/datadisplaydelegate.hpp +++ b/apps/opencs/view/world/datadisplaydelegate.hpp @@ -31,7 +31,7 @@ namespace CSVWorld std::vector > mPixmaps; QSize mIconSize; - int mIconLeftOffset; + int mHorizontalMargin; int mTextLeftOffset; QString mSettingKey; @@ -45,12 +45,11 @@ namespace CSVWorld virtual void paint (QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; + virtual QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const; + /// pass a QSize defining height / width of icon. Default is QSize (16,16). void setIconSize (const QSize& icon); - /// offset the horizontal position of the icon from the left edge of the cell. Default is 3 pixels. - void setIconLeftOffset (int offset); - /// offset the horizontal position of the text from the right edge of the icon. Default is 8 pixels. void setTextLeftOffset (int offset); From 3da8f6e62ea87252daec614200c113ad386fe21b Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 16 Jun 2015 20:36:48 +0200 Subject: [PATCH 1557/3725] Water ripples --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwrender/renderingmanager.cpp | 29 +++- apps/openmw/mwrender/renderingmanager.hpp | 11 +- apps/openmw/mwrender/ripplesimulation.cpp | 202 ++++++++++++++++++++++ apps/openmw/mwrender/ripplesimulation.hpp | 76 ++++++++ apps/openmw/mwrender/water.cpp | 22 ++- apps/openmw/mwrender/water.hpp | 18 +- apps/openmw/mwworld/fallback.cpp | 1 + apps/openmw/mwworld/scene.cpp | 5 + apps/openmw/mwworld/worldimp.cpp | 3 +- 10 files changed, 355 insertions(+), 14 deletions(-) create mode 100644 apps/openmw/mwrender/ripplesimulation.cpp create mode 100644 apps/openmw/mwrender/ripplesimulation.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 265fb43e8..cd1ac31ec 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -22,7 +22,7 @@ source_group(game FILES ${GAME} ${GAME_HEADER}) add_openmw_dir (mwrender actors objects renderingmanager animation rotatecontroller sky npcanimation vismask creatureanimation effectmanager util renderinginterface pathgrid rendermode weaponanimation - bulletdebugdraw globalmap characterpreview camera localmap water terrainstorage + bulletdebugdraw globalmap characterpreview camera localmap water terrainstorage ripplesimulation ) add_openmw_dir (mwinput diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 4db776783..5cbcaab83 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -114,7 +114,7 @@ namespace MWRender bool mWireframe; }; - RenderingManager::RenderingManager(osgViewer::Viewer* viewer, osg::ref_ptr rootNode, Resource::ResourceSystem* resourceSystem) + RenderingManager::RenderingManager(osgViewer::Viewer* viewer, osg::ref_ptr rootNode, Resource::ResourceSystem* resourceSystem, const MWWorld::Fallback* fallback) : mViewer(viewer) , mRootNode(rootNode) , mResourceSystem(resourceSystem) @@ -136,7 +136,7 @@ namespace MWRender mEffectManager.reset(new EffectManager(lightRoot, mResourceSystem)); - mWater.reset(new Water(lightRoot, mResourceSystem, mViewer->getIncrementalCompileOperation())); + mWater.reset(new Water(lightRoot, mResourceSystem, mViewer->getIncrementalCompileOperation(), fallback)); mTerrain.reset(new Terrain::TerrainGrid(lightRoot, mResourceSystem, mViewer->getIncrementalCompileOperation(), new TerrainStorage(mResourceSystem->getVFS(), false), Mask_Terrain)); @@ -265,6 +265,8 @@ namespace MWRender if (store->getCell()->isExterior()) mTerrain->unloadCell(store->getCell()->getGridX(), store->getCell()->getGridY()); + + mWater->removeCell(store); } void RenderingManager::setSkyEnabled(bool enabled) @@ -330,6 +332,7 @@ namespace MWRender { mEffectManager->update(dt); mSky->update(dt); + mWater->update(dt); mCamera->update(dt, paused); osg::Vec3f focal, cameraPos; @@ -354,6 +357,11 @@ namespace MWRender mCamera->attachTo(ptr); } + void RenderingManager::removePlayer(const MWWorld::Ptr &player) + { + mWater->removeEmitter(player); + } + void RenderingManager::rotateObject(const MWWorld::Ptr &ptr, const osg::Quat& rot) { if(ptr == mCamera->getTrackingPtr() && @@ -378,6 +386,7 @@ namespace MWRender void RenderingManager::removeObject(const MWWorld::Ptr &ptr) { mObjects->removeObject(ptr); + mWater->removeEmitter(ptr); } void RenderingManager::setWaterEnabled(bool enabled) @@ -579,7 +588,7 @@ namespace MWRender void RenderingManager::notifyWorldSpaceChanged() { mEffectManager->clear(); - //mWater->clearRipples(); + mWater->clearRipples(); } void RenderingManager::clear() @@ -613,6 +622,8 @@ namespace MWRender mPlayerNode->getUserDataContainer()->addUserObject(new PtrHolder(player)); player.getRefData().setBaseNode(mPlayerNode); + + mWater->addEmitter(player); } void RenderingManager::renderPlayer(const MWWorld::Ptr &player) @@ -621,8 +632,6 @@ namespace MWRender mCamera->setAnimation(mPlayerAnimation.get()); mCamera->attachTo(player); - //mWater->removeEmitter(ptr); - //mWater->addEmitter(ptr); } void RenderingManager::rebuildPtr(const MWWorld::Ptr &ptr) @@ -643,6 +652,16 @@ namespace MWRender } } + void RenderingManager::addWaterRippleEmitter(const MWWorld::Ptr &ptr) + { + mWater->addEmitter(ptr); + } + + void RenderingManager::removeWaterRippleEmitter(const MWWorld::Ptr &ptr) + { + mWater->removeEmitter(ptr); + } + void RenderingManager::updateProjectionMatrix() { double aspect = mViewer->getCamera()->getViewport()->aspectRatio(); diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index a37203cc2..302073e4d 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -37,6 +37,11 @@ namespace Terrain class World; } +namespace MWWorld +{ + class Fallback; +} + namespace MWRender { @@ -52,7 +57,7 @@ namespace MWRender class RenderingManager : public MWRender::RenderingInterface { public: - RenderingManager(osgViewer::Viewer* viewer, osg::ref_ptr rootNode, Resource::ResourceSystem* resourceSystem); + RenderingManager(osgViewer::Viewer* viewer, osg::ref_ptr rootNode, Resource::ResourceSystem* resourceSystem, const MWWorld::Fallback* fallback); ~RenderingManager(); MWRender::Objects& getObjects(); @@ -125,8 +130,12 @@ namespace MWRender Animation* getAnimation(const MWWorld::Ptr& ptr); Animation* getPlayerAnimation(); + void addWaterRippleEmitter(const MWWorld::Ptr& ptr); + void removeWaterRippleEmitter(const MWWorld::Ptr& ptr); + void updatePlayerPtr(const MWWorld::Ptr &ptr); + void removePlayer(const MWWorld::Ptr& player); void setupPlayer(const MWWorld::Ptr& player); void renderPlayer(const MWWorld::Ptr& player); diff --git a/apps/openmw/mwrender/ripplesimulation.cpp b/apps/openmw/mwrender/ripplesimulation.cpp new file mode 100644 index 000000000..a3e96a5b1 --- /dev/null +++ b/apps/openmw/mwrender/ripplesimulation.cpp @@ -0,0 +1,202 @@ +#include "ripplesimulation.hpp" + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "vismask.hpp" + +#include "../mwbase/world.hpp" +#include "../mwbase/environment.hpp" + +#include "../mwworld/fallback.hpp" + +namespace +{ + void createWaterRippleStateSet(Resource::ResourceSystem* resourceSystem, const MWWorld::Fallback* fallback, osg::Node* node) + { + int rippleFrameCount = fallback->getFallbackInt("Water_RippleFrameCount"); + if (rippleFrameCount <= 0) + return; + + std::string tex = fallback->getFallbackString("Water_RippleTexture"); + + std::vector > textures; + for (int i=0; igetTextureManager()->getTexture2D(texname.str(), osg::Texture::REPEAT, osg::Texture::REPEAT)); + } + + osg::ref_ptr controller (new NifOsg::FlipController(0, 0.3f/rippleFrameCount, textures)); + controller->setSource(boost::shared_ptr(new SceneUtil::FrameTimeSource)); + node->addUpdateCallback(controller); + + osg::ref_ptr stateset (new osg::StateSet); + stateset->setMode(GL_BLEND, osg::StateAttribute::ON); + stateset->setMode(GL_CULL_FACE, osg::StateAttribute::OFF); + stateset->setTextureAttributeAndModes(0, textures[0], osg::StateAttribute::ON); + + osg::ref_ptr depth (new osg::Depth); + depth->setWriteMask(false); + stateset->setAttributeAndModes(depth, osg::StateAttribute::ON); + + stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); + + osg::ref_ptr mat (new osg::Material); + mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 1.f)); + mat->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 1.f)); + mat->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(1.f, 1.f, 1.f, 1.f)); + mat->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 0.f)); + mat->setColorMode(osg::Material::DIFFUSE); + stateset->setAttributeAndModes(mat, osg::StateAttribute::ON); + + node->setStateSet(stateset); + } +} + +namespace MWRender +{ + +RippleSimulation::RippleSimulation(osg::Group *parent, Resource::ResourceSystem* resourceSystem, const MWWorld::Fallback* fallback) + : mParent(parent) +{ + osg::ref_ptr geode (new osg::Geode); + + mParticleSystem = new osgParticle::ParticleSystem; + geode->addDrawable(mParticleSystem); + + mParticleSystem->setParticleAlignment(osgParticle::ParticleSystem::FIXED); + mParticleSystem->setAlignVectorX(osg::Vec3f(1,0,0)); + mParticleSystem->setAlignVectorY(osg::Vec3f(0,1,0)); + + osgParticle::Particle& particleTemplate = mParticleSystem->getDefaultParticleTemplate(); + particleTemplate.setSizeRange(osgParticle::rangef(15, 180)); + particleTemplate.setColorRange(osgParticle::rangev4(osg::Vec4f(1,1,1,0.7), osg::Vec4f(1,1,1,0.7))); + particleTemplate.setAlphaRange(osgParticle::rangef(1.f, 0.f)); + particleTemplate.setAngularVelocity(osg::Vec3f(0,0,fallback->getFallbackFloat("Water_RippleRotSpeed"))); + particleTemplate.setLifeTime(fallback->getFallbackFloat("Water_RippleLifetime")); + + osg::ref_ptr updater (new osgParticle::ParticleSystemUpdater); + updater->addParticleSystem(mParticleSystem); + + mParticleNode = new osg::PositionAttitudeTransform; + mParticleNode->addChild(updater); + mParticleNode->addChild(geode); + mParticleNode->setNodeMask(Mask_Effect); + + createWaterRippleStateSet(resourceSystem, fallback, mParticleNode); + + mParent->addChild(mParticleNode); +} + +RippleSimulation::~RippleSimulation() +{ + mParent->removeChild(mParticleNode); +} + +void RippleSimulation::update(float dt) +{ + for (std::vector::iterator it=mEmitters.begin(); it !=mEmitters.end(); ++it) + { + if (it->mPtr == MWBase::Environment::get().getWorld ()->getPlayerPtr()) + { + // fetch a new ptr (to handle cell change etc) + // for non-player actors this is done in updateObjectCell + it->mPtr = MWBase::Environment::get().getWorld ()->getPlayerPtr(); + } + + osg::Vec3f currentPos (it->mPtr.getRefData().getPosition().asVec3()); + currentPos.z() = 0; // Z is set by the Scene Node + + if ( (currentPos - it->mLastEmitPosition).length() > 10 + // Only emit when close to the water surface, not above it and not too deep in the water + && MWBase::Environment::get().getWorld ()->isUnderwater (it->mPtr.getCell(), it->mPtr.getRefData().getPosition().asVec3()) + && !MWBase::Environment::get().getWorld()->isSubmerged(it->mPtr)) + { + it->mLastEmitPosition = currentPos; + + if (mParticleSystem->numParticles()-mParticleSystem->numDeadParticles() > 500) + continue; // TODO: remove the oldest particle to make room? + + osgParticle::Particle* p = mParticleSystem->createParticle(NULL); + p->setPosition(currentPos); + p->setAngle(osg::Vec3f(0,0, Misc::Rng::rollProbability() * osg::PI * 2 - osg::PI)); + } + } +} + + +void RippleSimulation::addEmitter(const MWWorld::Ptr& ptr, float scale, float force) +{ + Emitter newEmitter; + newEmitter.mPtr = ptr; + newEmitter.mScale = scale; + newEmitter.mForce = force; + newEmitter.mLastEmitPosition = osg::Vec3f(0,0,0); + mEmitters.push_back (newEmitter); +} + +void RippleSimulation::removeEmitter (const MWWorld::Ptr& ptr) +{ + for (std::vector::iterator it = mEmitters.begin(); it != mEmitters.end(); ++it) + { + if (it->mPtr == ptr) + { + mEmitters.erase(it); + return; + } + } +} + +void RippleSimulation::updateEmitterPtr (const MWWorld::Ptr& old, const MWWorld::Ptr& ptr) +{ + for (std::vector::iterator it = mEmitters.begin(); it != mEmitters.end(); ++it) + { + if (it->mPtr == old) + { + it->mPtr = ptr; + return; + } + } +} + +void RippleSimulation::removeCell(const MWWorld::CellStore *store) +{ + for (std::vector::iterator it = mEmitters.begin(); it != mEmitters.end();) + { + if (it->mPtr.getCell() == store && it->mPtr != MWBase::Environment::get().getWorld()->getPlayerPtr()) + { + it = mEmitters.erase(it); + } + else + ++it; + } +} + +void RippleSimulation::setWaterHeight(float height) +{ + mParticleNode->setPosition(osg::Vec3f(0,0,height)); +} + +void RippleSimulation::clear() +{ + for (int i=0; inumParticles(); ++i) + mParticleSystem->destroyParticle(i); +} + + + +} diff --git a/apps/openmw/mwrender/ripplesimulation.hpp b/apps/openmw/mwrender/ripplesimulation.hpp new file mode 100644 index 000000000..98c8a707d --- /dev/null +++ b/apps/openmw/mwrender/ripplesimulation.hpp @@ -0,0 +1,76 @@ +#ifndef OPENMW_MWRENDER_RIPPLESIMULATION_H +#define OPENMW_MWRENDER_RIPPLESIMULATION_H + +#include + +#include "../mwworld/ptr.hpp" + +namespace osg +{ + class Group; +} + +namespace osgParticle +{ + class ParticleSystem; +} + +namespace Resource +{ + class ResourceSystem; +} + +namespace MWWorld +{ + class Fallback; +} + +namespace MWRender +{ + + struct Emitter + { + MWWorld::Ptr mPtr; + osg::Vec3f mLastEmitPosition; + float mScale; + float mForce; + }; + + class RippleSimulation + { + public: + RippleSimulation(osg::Group* parent, Resource::ResourceSystem* resourceSystem, const MWWorld::Fallback* fallback); + ~RippleSimulation(); + + /// @param dt Time since the last frame + void update(float dt); + + /// adds an emitter, position will be tracked automatically + void addEmitter (const MWWorld::Ptr& ptr, float scale = 1.f, float force = 1.f); + void removeEmitter (const MWWorld::Ptr& ptr); + void updateEmitterPtr (const MWWorld::Ptr& old, const MWWorld::Ptr& ptr); + void removeCell(const MWWorld::CellStore* store); + + /// Change the height of the water surface, thus moving all ripples with it + void setWaterHeight(float height); + + /// Remove all active ripples + void clear(); + + private: + osg::ref_ptr mParent; + Resource::ResourceSystem* mResourceSystem; + + osg::ref_ptr mParticleSystem; + osg::ref_ptr mParticleNode; + + std::vector mEmitters; + + float mRippleLifeTime; + float mRippleRotSpeed; + + }; + +} + +#endif diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index c2149358b..3b07f35ba 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -18,6 +18,7 @@ #include #include "vismask.hpp" +#include "ripplesimulation.hpp" namespace { @@ -107,13 +108,15 @@ namespace MWRender // -------------------------------------------------------------------------------------------------------------------------------- -Water::Water(osg::Group *parent, Resource::ResourceSystem *resourceSystem, osgUtil::IncrementalCompileOperation *ico) +Water::Water(osg::Group *parent, Resource::ResourceSystem *resourceSystem, osgUtil::IncrementalCompileOperation *ico, const MWWorld::Fallback* fallback) : mParent(parent) , mResourceSystem(resourceSystem) , mEnabled(true) , mToggled(true) , mTop(0) { + mSimulation.reset(new RippleSimulation(parent, resourceSystem, fallback)); + osg::ref_ptr waterGeom = createWaterGeometry(CELL_SIZE*150, 40, 900); osg::ref_ptr geode (new osg::Geode); @@ -161,6 +164,11 @@ void Water::setHeight(const float height) mWaterNode->setPosition(pos); } +void Water::update(float dt) +{ + mSimulation->update(dt); +} + void Water::updateVisible() { mWaterNode->setNodeMask(mEnabled && mToggled ? ~0 : 0); @@ -183,7 +191,6 @@ osg::Vec3f Water::getSceneNodeCoordinates(int gridX, int gridY) return osg::Vec3f(static_cast(gridX * CELL_SIZE + (CELL_SIZE / 2)), static_cast(gridY * CELL_SIZE + (CELL_SIZE / 2)), mTop); } -/* void Water::addEmitter (const MWWorld::Ptr& ptr, float scale, float force) { mSimulation->addEmitter (ptr, scale, force); @@ -198,6 +205,15 @@ void Water::updateEmitterPtr (const MWWorld::Ptr& old, const MWWorld::Ptr& ptr) { mSimulation->updateEmitterPtr(old, ptr); } -*/ + +void Water::removeCell(const MWWorld::CellStore *store) +{ + mSimulation->removeCell(store); +} + +void Water::clearRipples() +{ + mSimulation->clear(); +} } diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index d389392ba..519cd5181 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -21,9 +21,16 @@ namespace Resource class ResourceSystem; } +namespace MWWorld +{ + class Fallback; +} + namespace MWRender { + class RippleSimulation; + /// Water rendering class Water { @@ -34,6 +41,8 @@ namespace MWRender Resource::ResourceSystem* mResourceSystem; osg::ref_ptr mIncrementalCompileOperation; + std::auto_ptr mSimulation; + bool mEnabled; bool mToggled; float mTop; @@ -42,7 +51,7 @@ namespace MWRender void updateVisible(); public: - Water(osg::Group* parent, Resource::ResourceSystem* resourceSystem, osgUtil::IncrementalCompileOperation* ico); + Water(osg::Group* parent, Resource::ResourceSystem* resourceSystem, osgUtil::IncrementalCompileOperation* ico, const MWWorld::Fallback* fallback); ~Water(); void setEnabled(bool enabled); @@ -51,16 +60,19 @@ namespace MWRender bool isUnderwater(const osg::Vec3f& pos) const; - /* /// adds an emitter, position will be tracked automatically using its scene node void addEmitter (const MWWorld::Ptr& ptr, float scale = 1.f, float force = 1.f); void removeEmitter (const MWWorld::Ptr& ptr); void updateEmitterPtr (const MWWorld::Ptr& old, const MWWorld::Ptr& ptr); - */ + void removeCell(const MWWorld::CellStore* store); ///< remove all emitters in this cell + + void clearRipples(); void changeCell(const MWWorld::CellStore* store); void setHeight(const float height); + void update(float dt); + }; } diff --git a/apps/openmw/mwworld/fallback.cpp b/apps/openmw/mwworld/fallback.cpp index fd6022481..e810f8241 100644 --- a/apps/openmw/mwworld/fallback.cpp +++ b/apps/openmw/mwworld/fallback.cpp @@ -58,4 +58,5 @@ namespace MWWorld return osg::Vec4f(boost::lexical_cast(ret[0])/255.f,boost::lexical_cast(ret[1])/255.f,boost::lexical_cast(ret[2])/255.f, 1.f); } } + } diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 76c2f6eba..db26b4f2a 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -39,6 +39,9 @@ namespace model = ""; // marker objects that have a hardcoded function in the game logic, should be hidden from the player ptr.getClass().insertObjectRendering(ptr, model, rendering); ptr.getClass().insertObject (ptr, model, physics); + + if (ptr.getClass().isActor()) + rendering.addWaterRippleEmitter(ptr); } void updateObjectLocalRotation (const MWWorld::Ptr& ptr, MWPhysics::PhysicsSystem& physics, @@ -570,6 +573,8 @@ namespace MWWorld MWBase::Environment::get().getSoundManager()->stopSound3D (ptr); mPhysics->remove(ptr); mRendering.removeObject (ptr); + if (ptr.getClass().isActor()) + mRendering.removeWaterRippleEmitter(ptr); } bool Scene::isCellActive(const CellStore &cell) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 16dcadb23..4743b3ad9 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -161,7 +161,7 @@ namespace MWWorld { mPhysics = new MWPhysics::PhysicsSystem(resourceSystem, rootNode); mProjectileManager.reset(new ProjectileManager(rootNode, resourceSystem, mPhysics)); - mRendering = new MWRender::RenderingManager(viewer, rootNode, resourceSystem); + mRendering = new MWRender::RenderingManager(viewer, rootNode, resourceSystem, &mFallback); mWeatherManager = new MWWorld::WeatherManager(mRendering,&mFallback); @@ -2064,6 +2064,7 @@ namespace MWWorld // Remove the old CharacterController MWBase::Environment::get().getMechanicsManager()->remove(getPlayerPtr()); mPhysics->remove(getPlayerPtr()); + mRendering->removePlayer(getPlayerPtr()); mPlayer->set(player); } From 1e368de28938723a2102b99c8ba7c3e1d81235e1 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Tue, 16 Jun 2015 21:47:27 +0300 Subject: [PATCH 1558/3725] Adjust columns of nested tables when a dialog subview is opened --- apps/opencs/view/world/dialoguesubview.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 66e8fcb7a..fa3a3e27a 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -469,8 +469,7 @@ void CSVWorld::EditWidget::remake(int row) mTable->data (mTable->index (row, idColumn)).toString().toUtf8().constData()); NestedTable* table = new NestedTable(mDocument, id, mNestedModels.back(), this); - // FIXME: does not work well when enum delegates are used - //table->resizeColumnsToContents(); + table->resizeColumnsToContents(); if(mTable->index(row, i).data().type() == QVariant::UserType) { From 1c151f2f0a67f34db34a0a703112f7531f582f51 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 16 Jun 2015 20:56:48 +0200 Subject: [PATCH 1559/3725] Re-enable some outcommented sky code --- apps/openmw/mwrender/renderingmanager.cpp | 22 ++++++++++++++ apps/openmw/mwrender/renderingmanager.hpp | 5 ++++ apps/openmw/mwrender/sky.cpp | 6 ---- apps/openmw/mwrender/sky.hpp | 1 - apps/openmw/mwworld/worldimp.cpp | 35 +++++++---------------- 5 files changed, 37 insertions(+), 32 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 5cbcaab83..478cadb74 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -219,6 +219,26 @@ namespace MWRender updateAmbient(); } + void RenderingManager::skySetDate(int day, int month) + { + mSky->setDate(day, month); + } + + int RenderingManager::skyGetMasserPhase() const + { + return mSky->getMasserPhase(); + } + + int RenderingManager::skyGetSecundaPhase() const + { + return mSky->getSecundaPhase(); + } + + void RenderingManager::skySetMoonColour(bool red) + { + mSky->setMoonColour(red); + } + void RenderingManager::configureAmbient(const ESM::Cell *cell) { setAmbientColour(SceneUtil::colourFromRGB(cell->mAmbi.mAmbient)); @@ -593,6 +613,8 @@ namespace MWRender void RenderingManager::clear() { + mSky->setMoonColour(false); + notifyWorldSpaceChanged(); } diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 302073e4d..fc2f5a4f3 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -68,6 +68,11 @@ namespace MWRender void setAmbientColour(const osg::Vec4f& colour); + void skySetDate(int day, int month); + int skyGetMasserPhase() const; + int skyGetSecundaPhase() const; + void skySetMoonColour(bool red); + void setSunDirection(const osg::Vec3f& direction); void setSunColour(const osg::Vec4f& colour); diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 07e433208..4b70c81ab 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -473,7 +473,6 @@ SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneMana , mCreated(false) , mMoonRed(false) , mIsStorm(false) - , mHour(0.0f) , mDay(0) , mMonth(0) , mCloudAnimationTimer(0.f) @@ -886,11 +885,6 @@ void SkyManager::setSecundaFade(const float fade) mSecunda->setAlpha(fade); } -void SkyManager::setHour(double hour) -{ - mHour = static_cast(hour); -} - void SkyManager::setDate(int day, int month) { mDay = day; diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index e11f20c18..f097029d1 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -117,7 +117,6 @@ namespace MWRender bool mIsStorm; - float mHour; int mDay; int mMonth; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 4743b3ad9..0d6a8ef47 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -134,9 +134,8 @@ namespace MWWorld { if (mSky && (isCellExterior() || isCellQuasiExterior())) { - //mRendering->skySetHour (mGlobalVariables["gamehour"].getFloat()); - //mRendering->skySetDate (mGlobalVariables["day"].getInteger(), - // mGlobalVariables["month"].getInteger()); + mRendering->skySetDate (mGlobalVariables["day"].getInteger(), + mGlobalVariables["month"].getInteger()); mRendering->setSkyEnabled(true); } @@ -812,8 +811,6 @@ namespace MWWorld mGlobalVariables["gamehour"].setFloat(static_cast(hour)); - //mRendering->skySetHour (hour); - mWeatherManager->setHour(static_cast(hour)); if (days>0) @@ -849,7 +846,7 @@ namespace MWWorld mGlobalVariables["day"].setInteger (day); mGlobalVariables["month"].setInteger (month); - //mRendering->skySetDate (day, month); + mRendering->skySetDate(day, month); } void World::setMonth (int month) @@ -870,7 +867,7 @@ namespace MWWorld if (years>0) mGlobalVariables["year"].setInteger (years+mGlobalVariables["year"].getInteger()); - //mRendering->skySetDate (mGlobalVariables["day"].getInteger(), month); + mRendering->skySetDate (mGlobalVariables["day"].getInteger(), month); } int World::getDay() const @@ -916,36 +913,24 @@ namespace MWWorld bool World::toggleSky() { -#if 0 - if (mSky) - { - mSky = false; - mRendering->skyDisable(); - return false; - } - else - { - mSky = true; - mRendering->skyEnable(); - return true; - } -#endif - return 0; + mSky = !mSky; + mRendering->setSkyEnabled(mSky); + return mSky; } int World::getMasserPhase() const { - return 0;//mRendering->skyGetMasserPhase(); + return mRendering->skyGetMasserPhase(); } int World::getSecundaPhase() const { - return 0;//mRendering->skyGetSecundaPhase(); + return mRendering->skyGetSecundaPhase(); } void World::setMoonColour (bool red) { - //mRendering->skySetMoonColour (red); + mRendering->skySetMoonColour (red); } float World::getTimeScaleFactor() const From ed0942422370e5e99dc3f4eb6dfd4e74e38c0aff Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Wed, 17 Jun 2015 00:45:43 +0300 Subject: [PATCH 1560/3725] Correct the position of the colored rectangle in ColorEditor and ColorDelegate --- apps/opencs/view/widget/coloreditor.cpp | 8 ++++---- apps/opencs/view/world/colordelegate.cpp | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/opencs/view/widget/coloreditor.cpp b/apps/opencs/view/widget/coloreditor.cpp index b31225962..798502196 100644 --- a/apps/opencs/view/widget/coloreditor.cpp +++ b/apps/opencs/view/widget/coloreditor.cpp @@ -25,10 +25,10 @@ void CSVWidget::ColorEditor::paintEvent(QPaintEvent *event) QPushButton::paintEvent(event); QRect buttonRect = rect(); - QRect coloredRect(qRound(buttonRect.x() + buttonRect.width() / 4.0), - qRound(buttonRect.y() + buttonRect.height() / 4.0), - qRound(buttonRect.width() / 2.0), - qRound(buttonRect.height() / 2.0)); + QRect coloredRect(buttonRect.x() + qRound(buttonRect.width() / 4.0), + buttonRect.y() + qRound(buttonRect.height() / 4.0), + buttonRect.width() / 2, + buttonRect.height() / 2); QPainter painter(this); painter.fillRect(coloredRect, mColor); painter.setPen(Qt::black); diff --git a/apps/opencs/view/world/colordelegate.cpp b/apps/opencs/view/world/colordelegate.cpp index ae71f965a..1a89fc675 100644 --- a/apps/opencs/view/world/colordelegate.cpp +++ b/apps/opencs/view/world/colordelegate.cpp @@ -15,10 +15,10 @@ void CSVWorld::ColorDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { - QRect coloredRect(qRound(option.rect.x() + option.rect.width() / 4.0), - qRound(option.rect.y() + option.rect.height() / 4.0), - qRound(option.rect.width() / 2.0), - qRound(option.rect.height() / 2.0)); + QRect coloredRect(option.rect.x() + qRound(option.rect.width() / 4.0), + option.rect.y() + qRound(option.rect.height() / 4.0), + option.rect.width() / 2, + option.rect.height() / 2); painter->save(); painter->fillRect(coloredRect, index.data().value()); painter->setPen(Qt::black); From 6199c0bbc5049b8450e6c1b583ca027c876ce4da Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 16 Jun 2015 23:50:19 +0200 Subject: [PATCH 1561/3725] Use osgDB::SharedStateManager for sharing of StateSets across NIF files --- components/resource/scenemanager.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index bb4c57e4c..de4e2bd1c 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -8,6 +8,9 @@ #include +#include +#include + #include #include @@ -103,6 +106,9 @@ namespace Resource NifOsg::Loader loader; osg::ref_ptr loaded = loader.load(Nif::NIFFilePtr(new Nif::NIFFile(file, normalized)), mTextureManager); + osgDB::Registry::instance()->getOrCreateSharedStateManager()->share(loaded.get()); + // TODO: run SharedStateManager::prune on unload + if (mIncrementalCompileOperation) mIncrementalCompileOperation->add(loaded); From 7b35882814b9c3ff5e6dfd09c6bfe957832bfe02 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 17 Jun 2015 15:13:17 +0200 Subject: [PATCH 1562/3725] RemoveParticlesVisitor fix --- apps/openmw/mwrender/objects.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 2eb72dfd2..39e9f5652 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -35,12 +35,26 @@ namespace virtual void apply(osg::Node &node) { - if (dynamic_cast(&node) || dynamic_cast(&node)) + if (dynamic_cast(&node)) mToRemove.push_back(&node); traverse(node); } + virtual void apply(osg::Geode& geode) + { + std::vector partsysVector; + for (unsigned int i=0; i(drw)) + partsysVector.push_back(partsys); + } + + for (std::vector::iterator it = partsysVector.begin(); it != partsysVector.end(); ++it) + geode.removeDrawable(*it); + } + void remove() { for (std::vector >::iterator it = mToRemove.begin(); it != mToRemove.end(); ++it) From b648722d3b26f12649bc33dcb88e48e539db4ffa Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 17 Jun 2015 15:13:41 +0200 Subject: [PATCH 1563/3725] Don't use the ParticleSystem for computing placeable bounds (Bug #2700) --- apps/openmw/mwrender/vismask.hpp | 5 ++++- apps/openmw/mwworld/worldimp.cpp | 2 ++ components/resource/scenemanager.cpp | 1 + 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/vismask.hpp b/apps/openmw/mwrender/vismask.hpp index b794ac24a..38fcfe648 100644 --- a/apps/openmw/mwrender/vismask.hpp +++ b/apps/openmw/mwrender/vismask.hpp @@ -22,8 +22,11 @@ namespace MWRender Mask_Scene = (1<<8), Mask_GUI = (1<<9), + // Set on a Geode + Mask_ParticleSystem = (1<<10), + // Set on cameras within the main scene graph - Mask_RenderToTexture = (1<<10) + Mask_RenderToTexture = (1<<11) // reserved: (1<<16) for SceneUtil::Mask_Lit }; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 0d6a8ef47..6b43ae74f 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -37,6 +37,7 @@ #include "../mwrender/animation.hpp" #include "../mwrender/renderingmanager.hpp" #include "../mwrender/camera.hpp" +#include "../mwrender/vismask.hpp" #include "../mwscript/interpretercontext.hpp" #include "../mwscript/globalscripts.hpp" @@ -1862,6 +1863,7 @@ namespace MWWorld { // Adjust position so the location we wanted ends up in the middle of the object bounding box osg::ComputeBoundsVisitor computeBounds; + computeBounds.setTraversalMask(~MWRender::Mask_ParticleSystem); dropped.getRefData().getBaseNode()->accept(computeBounds); osg::BoundingBox bounds = computeBounds.getBoundingBox(); if (bounds.valid()) diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index de4e2bd1c..6f38c41c4 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -47,6 +47,7 @@ namespace if (geode->getNumParents() && geode->getParent(0)->getNumParents()) transformInitialParticles(partsys, geode->getParent(0)->getParent(0)); } + geode->setNodeMask((1<<10)); //MWRender::Mask_ParticleSystem } } } From 934166a853411279cb8ffefc6f81ea7dc2798f88 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 17 Jun 2015 17:55:15 +0200 Subject: [PATCH 1564/3725] Ignore the alpha value for particle materials (Bug #2699) --- components/nifosg/nifloader.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 91dea6ef2..e2db3d52b 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -866,8 +866,8 @@ namespace NifOsg osg::Material* mat = static_cast(parentNode->getStateSet()->getAttribute(osg::StateAttribute::MATERIAL)); if (mat) { - osg::Vec4f diffuse = mat->getDiffuse(osg::Material::FRONT_AND_BACK); - mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0,0,0,diffuse.a())); + // NB ignoring diffuse.a() + mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0,0,0,1)); mat->setColorMode(osg::Material::AMBIENT); } From b543308e3e63c21abe56e9ef570d3c4c830ad78f Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 17 Jun 2015 18:16:05 +0200 Subject: [PATCH 1565/3725] Remove an already resolved todo comment --- apps/openmw/mwrender/globalmap.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/openmw/mwrender/globalmap.cpp b/apps/openmw/mwrender/globalmap.cpp index 9109be799..890c8444a 100644 --- a/apps/openmw/mwrender/globalmap.cpp +++ b/apps/openmw/mwrender/globalmap.cpp @@ -274,7 +274,6 @@ namespace MWRender image->setDataType(mOverlayImage->getDataType()); camera->attach(osg::Camera::COLOR_BUFFER, image); - // FIXME: why does the image get slightly darker by the read back? ImageDest imageDest; imageDest.mImage = image; imageDest.mX = x; From 3ebfb4e0d9b8731b2cc0e6c72ad86496eb1bcdf3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 17 Jun 2015 18:22:31 +0200 Subject: [PATCH 1566/3725] Ignore particle systems in getScreenBounds --- apps/openmw/mwrender/animation.cpp | 1 + apps/openmw/mwrender/renderingmanager.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 9337b5a51..8c1b3c0a9 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1007,6 +1007,7 @@ namespace MWRender else { osg::ComputeBoundsVisitor computeBound; + computeBound.setTraversalMask(~Mask_ParticleSystem); parent->accept(computeBound); // PositionAttitudeTransform seems to be slightly faster than MatrixTransform diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 478cadb74..7f76adb28 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -484,6 +484,7 @@ namespace MWRender return osg::Vec4f(); osg::ComputeBoundsVisitor computeBoundsVisitor; + computeBoundsVisitor.setTraversalMask(~MWRender::Mask_ParticleSystem); ptr.getRefData().getBaseNode()->accept(computeBoundsVisitor); osg::Matrix viewProj = mViewer->getCamera()->getViewMatrix() * mViewer->getCamera()->getProjectionMatrix(); From 81a4a6da6bbde93bece0355e2310094714d6f14c Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 17 Jun 2015 20:32:10 +0200 Subject: [PATCH 1567/3725] Make better use of the available texture units (Bug #2702) Nvidia drivers only support a maximum of 4 fixed function texture units. To resolve this problem, bind texture units in order instead of binding to the NiTexturingProperty::TextureType unit. --- components/nifosg/nifloader.cpp | 52 ++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 23 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index e2db3d52b..d8920646d 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -344,7 +344,7 @@ namespace NifOsg osg::ref_ptr textkeys (new TextKeyMapHolder); - osg::ref_ptr created = handleNode(nifNode, NULL, textureManager, std::map(), 0, 0, false, &textkeys->mTextKeys); + osg::ref_ptr created = handleNode(nifNode, NULL, textureManager, std::vector(), 0, 0, false, &textkeys->mTextKeys); if (nif->getUseSkinning()) { @@ -357,7 +357,7 @@ namespace NifOsg return created; } - void applyNodeProperties(const Nif::Node *nifNode, osg::Node *applyTo, SceneUtil::CompositeStateSetUpdater* composite, Resource::TextureManager* textureManager, std::map& boundTextures, int animflags) + void applyNodeProperties(const Nif::Node *nifNode, osg::Node *applyTo, SceneUtil::CompositeStateSetUpdater* composite, Resource::TextureManager* textureManager, std::vector& boundTextures, int animflags) { const Nif::PropertyList& props = nifNode->props; for (size_t i = 0; i handleNode(const Nif::Node* nifNode, osg::Group* parentNode, Resource::TextureManager* textureManager, - std::map boundTextures, int animflags, int particleflags, bool skipMeshes, TextKeyMap* textKeys, osg::Node* rootNode=NULL) + std::vector boundTextures, int animflags, int particleflags, bool skipMeshes, TextKeyMap* textKeys, osg::Node* rootNode=NULL) { osg::ref_ptr node = new osg::MatrixTransform(nifNode->trafo.toMatrix()); @@ -558,7 +558,7 @@ namespace NifOsg return node; } - void handleMeshControllers(const Nif::Node *nifNode, SceneUtil::CompositeStateSetUpdater* composite, const std::map &boundTextures, int animflags) + void handleMeshControllers(const Nif::Node *nifNode, SceneUtil::CompositeStateSetUpdater* composite, const std::vector &boundTextures, int animflags) { for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next) { @@ -568,8 +568,8 @@ namespace NifOsg { const Nif::NiUVController *uvctrl = static_cast(ctrl.getPtr()); std::set texUnits; - for (std::map::const_iterator it = boundTextures.begin(); it != boundTextures.end(); ++it) - texUnits.insert(it->first); + for (unsigned int i=0; i ctrl = new UVController(uvctrl->data.getPtr(), texUnits); setupController(uvctrl, ctrl, animflags); @@ -888,7 +888,7 @@ namespace NifOsg } } - void triShapeToGeometry(const Nif::NiTriShape *triShape, osg::Geometry *geometry, osg::Node* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::map& boundTextures, int animflags) + void triShapeToGeometry(const Nif::NiTriShape *triShape, osg::Geometry *geometry, osg::Node* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::vector& boundTextures, int animflags) { const Nif::NiTriShapeData* data = triShape->data.getPtr(); @@ -898,10 +898,10 @@ namespace NifOsg geometry->setNormalArray(new osg::Vec3Array(data->normals.size(), &data->normals[0]), osg::Array::BIND_PER_VERTEX); } - for (std::map::const_iterator it = boundTextures.begin(); it != boundTextures.end(); ++it) + int textureStage = 0; + for (std::vector::const_iterator it = boundTextures.begin(); it != boundTextures.end(); ++it,++textureStage) { - int textureStage = it->first; - int uvSet = it->second; + int uvSet = *it; if (uvSet >= (int)data->uvlist.size()) { // Occurred in "ascendedsleeper.nif", but only for hidden Shadow nodes, apparently @@ -928,7 +928,7 @@ namespace NifOsg applyMaterialProperties(parentNode, materialProps, composite, !data->colors.empty(), animflags); } - void handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::map& boundTextures, int animflags) + void handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::vector& boundTextures, int animflags) { osg::ref_ptr geometry; if(!triShape->controller.empty()) @@ -1027,7 +1027,7 @@ namespace NifOsg } void handleSkinnedTriShape(const Nif::NiTriShape *triShape, osg::Group *parentNode, SceneUtil::CompositeStateSetUpdater* composite, - const std::map& boundTextures, int animflags) + const std::vector& boundTextures, int animflags) { osg::ref_ptr geode (new osg::Geode); @@ -1152,7 +1152,7 @@ namespace NifOsg } void handleProperty(const Nif::Property *property, - osg::Node *node, SceneUtil::CompositeStateSetUpdater* composite, Resource::TextureManager* textureManager, std::map& boundTextures, int animflags) + osg::Node *node, SceneUtil::CompositeStateSetUpdater* composite, Resource::TextureManager* textureManager, std::vector& boundTextures, int animflags) { switch (property->recType) { @@ -1254,6 +1254,15 @@ namespace NifOsg { const Nif::NiTexturingProperty* texprop = static_cast(property); osg::StateSet* stateset = node->getOrCreateStateSet(); + + if (boundTextures.size()) + { + // overriding a parent NiTexturingProperty, so remove what was previously bound + for (unsigned int i=0; isetTextureMode(i, GL_TEXTURE_2D, osg::StateAttribute::OFF); + boundTextures.clear(); + } + for (int i=0; itextures[i].inUse) @@ -1290,19 +1299,21 @@ namespace NifOsg wrapS ? osg::Texture::REPEAT : osg::Texture::CLAMP, wrapT ? osg::Texture::REPEAT : osg::Texture::CLAMP); - stateset->setTextureAttributeAndModes(i, texture2d, osg::StateAttribute::ON); + int texUnit = boundTextures.size(); + + stateset->setTextureAttributeAndModes(texUnit, texture2d, osg::StateAttribute::ON); if (i == Nif::NiTexturingProperty::GlowTexture) { osg::TexEnv* texEnv = new osg::TexEnv; texEnv->setMode(osg::TexEnv::ADD); - stateset->setTextureAttributeAndModes(i, texEnv, osg::StateAttribute::ON); + stateset->setTextureAttributeAndModes(texUnit, texEnv, osg::StateAttribute::ON); } else if (i == Nif::NiTexturingProperty::DarkTexture) { osg::TexEnv* texEnv = new osg::TexEnv; texEnv->setMode(osg::TexEnv::MODULATE); - stateset->setTextureAttributeAndModes(i, texEnv, osg::StateAttribute::ON); + stateset->setTextureAttributeAndModes(texUnit, texEnv, osg::StateAttribute::ON); } else if (i == Nif::NiTexturingProperty::DetailTexture) { @@ -1318,15 +1329,10 @@ namespace NifOsg texEnv->setOperand1_RGB(GL_SRC_COLOR); texEnv->setSource0_RGB(GL_PREVIOUS_ARB); texEnv->setSource1_RGB(GL_TEXTURE); - stateset->setTextureAttributeAndModes(i, texEnv, osg::StateAttribute::ON); + stateset->setTextureAttributeAndModes(texUnit, texEnv, osg::StateAttribute::ON); } - boundTextures[i] = tex.uvSet; - } - else if (boundTextures.find(i) != boundTextures.end()) - { - stateset->setTextureAttributeAndModes(i, new osg::Texture2D, osg::StateAttribute::OFF); - boundTextures.erase(i); + boundTextures.push_back(tex.uvSet); } handleTextureControllers(texprop, composite, textureManager, stateset, animflags); } From 6e5f3339ad0e6027e8845aebc0a67a9a35e72084 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 17 Jun 2015 20:49:01 +0200 Subject: [PATCH 1568/3725] Make sure to play IdleSwim when the character is swimming (Bug #2696) --- apps/openmw/mwmechanics/character.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index c48599b46..16d7387fd 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1768,7 +1768,7 @@ void CharacterController::update(float duration) if(movestate != CharState_None) clearAnimQueue(); - if(mAnimQueue.empty()) + if(mAnimQueue.empty() || inwater || sneak) { idlestate = (inwater ? CharState_IdleSwim : (sneak ? CharState_IdleSneak : CharState_Idle)); } From 2e40b68862256d63803f32eeba579b624adfdaa2 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Wed, 17 Jun 2015 22:47:39 +0300 Subject: [PATCH 1569/3725] Add a custom proxy model for Info tables --- apps/opencs/CMakeLists.txt | 2 +- .../model/world/infotableproxymodel.cpp | 40 +++++++++++++++++++ .../model/world/infotableproxymodel.hpp | 29 ++++++++++++++ 3 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 apps/opencs/model/world/infotableproxymodel.cpp create mode 100644 apps/opencs/model/world/infotableproxymodel.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index bf39b36c1..d49541590 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -18,7 +18,7 @@ opencs_hdrs_noqt (model/doc opencs_units (model/world - idtable idtableproxymodel regionmap data commanddispatcher idtablebase resourcetable nestedtableproxymodel idtree + idtable idtableproxymodel regionmap data commanddispatcher idtablebase resourcetable nestedtableproxymodel idtree infotableproxymodel ) diff --git a/apps/opencs/model/world/infotableproxymodel.cpp b/apps/opencs/model/world/infotableproxymodel.cpp new file mode 100644 index 000000000..1377ac20e --- /dev/null +++ b/apps/opencs/model/world/infotableproxymodel.cpp @@ -0,0 +1,40 @@ +#include "infotableproxymodel.hpp" + +#include "idtablebase.hpp" +#include "columns.hpp" + +CSMWorld::InfoTableProxyModel::InfoTableProxyModel(CSMWorld::UniversalId::Type type, QObject *parent) + : IdTableProxyModel(parent), + mType(type), + mSourceModel(NULL) +{ + Q_ASSERT(type == UniversalId::Type_TopicInfos || type == UniversalId::Type_JournalInfos); +} + +void CSMWorld::InfoTableProxyModel::setSourceModel(QAbstractItemModel *sourceModel) +{ + IdTableProxyModel::setSourceModel(sourceModel); + mSourceModel = dynamic_cast(sourceModel); +} + +bool CSMWorld::InfoTableProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const +{ + QModelIndex first = mSourceModel->index(getFirstInfoRow(left.row()), left.column()); + QModelIndex second = mSourceModel->index(getFirstInfoRow(right.row()), right.column()); + return IdTableProxyModel::lessThan(first, second); +} + +int CSMWorld::InfoTableProxyModel::getFirstInfoRow(int currentRow) const +{ + Columns::ColumnId columnId = Columns::ColumnId_Topic; + if (mType == UniversalId::Type_JournalInfos) + { + columnId = Columns::ColumnId_Journal; + } + + int column = mSourceModel->findColumnIndex(columnId); + QVariant info = mSourceModel->data(mSourceModel->index(currentRow, column)); + while (--currentRow >= 0 && + mSourceModel->data(mSourceModel->index(currentRow, column)) == info); + return currentRow + 1; +} diff --git a/apps/opencs/model/world/infotableproxymodel.hpp b/apps/opencs/model/world/infotableproxymodel.hpp new file mode 100644 index 000000000..a90607d34 --- /dev/null +++ b/apps/opencs/model/world/infotableproxymodel.hpp @@ -0,0 +1,29 @@ +#ifndef CSM_WORLD_INFOTABLEPROXYMODEL_HPP +#define CSM_WORLD_INFOTABLEPROXYMODEL_HPP + +#include "idtableproxymodel.hpp" +#include "universalid.hpp" + +namespace CSMWorld +{ + class IdTableBase; + + class InfoTableProxyModel : public IdTableProxyModel + { + UniversalId::Type mType; + IdTableBase *mSourceModel; + + int getFirstInfoRow(int currentRow) const; + ///< Finds the first row with the same topic (journal entry) as in \a currentRow + + public: + InfoTableProxyModel(UniversalId::Type type, QObject *parent = 0); + + void setSourceModel(QAbstractItemModel *sourceModel); + + protected: + virtual bool lessThan(const QModelIndex &left, const QModelIndex &right) const; + }; +} + +#endif From a6624ca576f6fd8b63097d0df99bdace6e244a7b Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Wed, 17 Jun 2015 23:46:51 +0300 Subject: [PATCH 1570/3725] Cache topic/journal first rows in InfoTableProxyModel --- .../model/world/infotableproxymodel.cpp | 22 +++++++++++++++++-- .../model/world/infotableproxymodel.hpp | 9 ++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/world/infotableproxymodel.cpp b/apps/opencs/model/world/infotableproxymodel.cpp index 1377ac20e..7522e492b 100644 --- a/apps/opencs/model/world/infotableproxymodel.cpp +++ b/apps/opencs/model/world/infotableproxymodel.cpp @@ -15,6 +15,11 @@ void CSMWorld::InfoTableProxyModel::setSourceModel(QAbstractItemModel *sourceMod { IdTableProxyModel::setSourceModel(sourceModel); mSourceModel = dynamic_cast(sourceModel); + connect(mSourceModel, + SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), + this, + SLOT(modelDataChanged(const QModelIndex &, const QModelIndex &))); + mFirstRowCache.clear(); } bool CSMWorld::InfoTableProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const @@ -33,8 +38,21 @@ int CSMWorld::InfoTableProxyModel::getFirstInfoRow(int currentRow) const } int column = mSourceModel->findColumnIndex(columnId); - QVariant info = mSourceModel->data(mSourceModel->index(currentRow, column)); - while (--currentRow >= 0 && + QString info = mSourceModel->data(mSourceModel->index(currentRow, column)).toString(); + + if (mFirstRowCache.contains(info)) + { + return mFirstRowCache[info]; + } + + while (--currentRow >= 0 && mSourceModel->data(mSourceModel->index(currentRow, column)) == info); + + mFirstRowCache[info] = currentRow + 1; return currentRow + 1; } + +void CSMWorld::InfoTableProxyModel::modelDataChanged(const QModelIndex &/*topLeft*/, const QModelIndex &/*bottomRight*/) +{ + mFirstRowCache.clear(); +} diff --git a/apps/opencs/model/world/infotableproxymodel.hpp b/apps/opencs/model/world/infotableproxymodel.hpp index a90607d34..322831626 100644 --- a/apps/opencs/model/world/infotableproxymodel.hpp +++ b/apps/opencs/model/world/infotableproxymodel.hpp @@ -1,6 +1,8 @@ #ifndef CSM_WORLD_INFOTABLEPROXYMODEL_HPP #define CSM_WORLD_INFOTABLEPROXYMODEL_HPP +#include + #include "idtableproxymodel.hpp" #include "universalid.hpp" @@ -10,9 +12,13 @@ namespace CSMWorld class InfoTableProxyModel : public IdTableProxyModel { + Q_OBJECT + UniversalId::Type mType; IdTableBase *mSourceModel; + mutable QHash mFirstRowCache; + int getFirstInfoRow(int currentRow) const; ///< Finds the first row with the same topic (journal entry) as in \a currentRow @@ -23,6 +29,9 @@ namespace CSMWorld protected: virtual bool lessThan(const QModelIndex &left, const QModelIndex &right) const; + + private slots: + void modelDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight); }; } From 0ffa1f964b06472c27f9bdf6589f65f1ddb0d337 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 17 Jun 2015 22:49:20 +0200 Subject: [PATCH 1571/3725] Fix water ripple height --- apps/openmw/mwrender/water.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 3b07f35ba..7cad745dd 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -159,6 +159,8 @@ void Water::setHeight(const float height) { mTop = height; + mSimulation->setWaterHeight(height); + osg::Vec3f pos = mWaterNode->getPosition(); pos.z() = height; mWaterNode->setPosition(pos); From c60fed89ace024cdfc086fe74a471cab1c436ac3 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Wed, 17 Jun 2015 23:50:18 +0300 Subject: [PATCH 1572/3725] Enable sorting for Info tables --- apps/opencs/view/world/subviews.cpp | 4 ++-- apps/opencs/view/world/table.cpp | 12 +++++++++++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp index cd9b37a64..e81da23e1 100644 --- a/apps/opencs/view/world/subviews.cpp +++ b/apps/opencs/view/world/subviews.cpp @@ -68,10 +68,10 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) new CSVDoc::SubViewFactoryWithCreator); manager.add (CSMWorld::UniversalId::Type_TopicInfos, - new CSVDoc::SubViewFactoryWithCreator > (false)); + new CSVDoc::SubViewFactoryWithCreator >); manager.add (CSMWorld::UniversalId::Type_JournalInfos, - new CSVDoc::SubViewFactoryWithCreator > (false)); + new CSVDoc::SubViewFactoryWithCreator >); // Subviews for resources tables manager.add (CSMWorld::UniversalId::Type_Meshes, diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index b4efbd3c8..072b645c4 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -13,6 +13,7 @@ #include "../../model/world/data.hpp" #include "../../model/world/commands.hpp" +#include "../../model/world/infotableproxymodel.hpp" #include "../../model/world/idtableproxymodel.hpp" #include "../../model/world/idtablebase.hpp" #include "../../model/world/idtable.hpp" @@ -276,7 +277,16 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id, mModel = &dynamic_cast (*mDocument.getData().getTableModel (id)); - mProxyModel = new CSMWorld::IdTableProxyModel (this); + bool isInfoTable = id.getType() == CSMWorld::UniversalId::Type_TopicInfos || + id.getType() == CSMWorld::UniversalId::Type_JournalInfos; + if (isInfoTable) + { + mProxyModel = new CSMWorld::InfoTableProxyModel(id.getType(), this); + } + else + { + mProxyModel = new CSMWorld::IdTableProxyModel (this); + } mProxyModel->setSourceModel (mModel); mDispatcher = new CSMWorld::CommandDispatcher (document, id, this); From fabc5126f3768ceb7a3af0bd195acd8a04a23f25 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 18 Jun 2015 00:30:51 +0200 Subject: [PATCH 1573/3725] Include cleanup --- apps/openmw/mwrender/sky.cpp | 1 + components/resource/scenemanager.hpp | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 4b70c81ab..0494b9544 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -24,6 +24,7 @@ #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" diff --git a/components/resource/scenemanager.hpp b/components/resource/scenemanager.hpp index f4ca0dea2..1dabe45e0 100644 --- a/components/resource/scenemanager.hpp +++ b/components/resource/scenemanager.hpp @@ -7,8 +7,6 @@ #include #include -#include - namespace Resource { class TextureManager; From 43384596d4835ac310a7d02295b228cc1d1477ab Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 18 Jun 2015 01:26:10 +0200 Subject: [PATCH 1574/3725] Style fix --- components/resource/scenemanager.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index 6f38c41c4..efaccec13 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -104,8 +104,7 @@ namespace Resource // TODO: add support for non-NIF formats - NifOsg::Loader loader; - osg::ref_ptr loaded = loader.load(Nif::NIFFilePtr(new Nif::NIFFile(file, normalized)), mTextureManager); + osg::ref_ptr loaded = NifOsg::Loader::load(Nif::NIFFilePtr(new Nif::NIFFile(file, normalized)), mTextureManager); osgDB::Registry::instance()->getOrCreateSharedStateManager()->share(loaded.get()); // TODO: run SharedStateManager::prune on unload @@ -144,9 +143,8 @@ namespace Resource { Files::IStreamPtr file = mVFS->get(normalized); - NifOsg::Loader loader; osg::ref_ptr loaded (new NifOsg::KeyframeHolder); - loader.loadKf(Nif::NIFFilePtr(new Nif::NIFFile(file, normalized)), *loaded.get()); + NifOsg::Loader::loadKf(Nif::NIFFilePtr(new Nif::NIFFile(file, normalized)), *loaded.get()); mKeyframeIndex[normalized] = loaded; return loaded; From a7c5beb7c5d495446e5d7facaa780fbf851d1848 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 18 Jun 2015 01:26:45 +0200 Subject: [PATCH 1575/3725] Remove redundant allocations for NIF meshes --- components/nif/data.cpp | 17 ++++++++-- components/nif/data.hpp | 13 +++++--- components/nif/nifstream.cpp | 32 +++++++++--------- components/nif/nifstream.hpp | 11 ++++--- components/nifbullet/bulletnifloader.cpp | 18 +++++----- components/nifosg/nifloader.cpp | 42 +++++++++++------------- 6 files changed, 76 insertions(+), 57 deletions(-) diff --git a/components/nif/data.cpp b/components/nif/data.cpp index fc0631b84..5a60ab8a5 100644 --- a/components/nif/data.cpp +++ b/components/nif/data.cpp @@ -1,6 +1,9 @@ #include "data.hpp" #include "node.hpp" +#include +#include + namespace Nif { void NiSkinInstance::read(NIFStream *nif) @@ -37,15 +40,18 @@ void ShapeData::read(NIFStream *nif) { int verts = nif->getUShort(); + vertices = new osg::Vec3Array; if(nif->getInt()) nif->getVector3s(vertices, verts); + normals = new osg::Vec3Array(osg::Array::BIND_PER_VERTEX); if(nif->getInt()) nif->getVector3s(normals, verts); center = nif->getVector3(); radius = nif->getFloat(); + colors = new osg::Vec4Array(osg::Array::BIND_PER_VERTEX); if(nif->getInt()) nif->getVector4s(colors, verts); @@ -58,7 +64,10 @@ void ShapeData::read(NIFStream *nif) { uvlist.resize(uvs); for(int i = 0;i < uvs;i++) + { + uvlist[i] = new osg::Vec2Array(osg::Array::BIND_PER_VERTEX); nif->getVector2s(uvlist[i], verts); + } } } @@ -71,6 +80,7 @@ void NiTriShapeData::read(NIFStream *nif) // We have three times as many vertices as triangles, so this // is always equal to tris*3. int cnt = nif->getInt(); + triangles = new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLES); nif->getUShorts(triangles, cnt); // Read the match list, which lists the vertices that are equal to @@ -97,8 +107,9 @@ void NiAutoNormalParticlesData::read(NIFStream *nif) if(nif->getInt()) { + int numVerts = vertices->size(); // Particle sizes - nif->getFloats(sizes, vertices.size()); + nif->getFloats(sizes, numVerts); } } @@ -108,8 +119,9 @@ void NiRotatingParticlesData::read(NIFStream *nif) if(nif->getInt()) { + int numVerts = vertices->size(); // Rotation quaternions. - nif->getQuaternions(rotations, vertices.size()); + nif->getQuaternions(rotations, numVerts); } } @@ -224,6 +236,7 @@ void NiMorphData::read(NIFStream *nif) { mMorphs[i].mKeyFrames.reset(new FloatKeyMap); mMorphs[i].mKeyFrames->read(nif, true); + mMorphs[i].mVertices = new osg::Vec3Array; nif->getVector3s(mMorphs[i].mVertices, vertCount); } } diff --git a/components/nif/data.hpp b/components/nif/data.hpp index 63dc42ade..95f244129 100644 --- a/components/nif/data.hpp +++ b/components/nif/data.hpp @@ -28,6 +28,8 @@ #include "niftypes.hpp" // Transformation +#include + namespace Nif { @@ -35,9 +37,10 @@ namespace Nif class ShapeData : public Record { public: - std::vector vertices, normals; - std::vector colors; - std::vector< std::vector > uvlist; + osg::ref_ptr vertices, normals; + osg::ref_ptr colors; + + std::vector< osg::ref_ptr > uvlist; osg::Vec3f center; float radius; @@ -48,7 +51,7 @@ class NiTriShapeData : public ShapeData { public: // Triangles, three vertex indices per triangle - std::vector triangles; + osg::ref_ptr triangles; void read(NIFStream *nif); }; @@ -166,7 +169,7 @@ struct NiMorphData : public Record { struct MorphData { FloatKeyMapPtr mKeyFrames; - std::vector mVertices; + osg::ref_ptr mVertices; }; std::vector mMorphs; diff --git a/components/nif/nifstream.cpp b/components/nif/nifstream.cpp index d0fc9bab0..5f49c2d21 100644 --- a/components/nif/nifstream.cpp +++ b/components/nif/nifstream.cpp @@ -103,11 +103,11 @@ std::string NIFStream::getVersionString() return result; } -void NIFStream::getUShorts(std::vector &vec, size_t size) +void NIFStream::getUShorts(osg::VectorGLushort* vec, size_t size) { - vec.resize(size); - for(size_t i = 0;i < vec.size();i++) - vec[i] = getUShort(); + vec->reserve(size); + for(size_t i = 0;i < size;i++) + vec->push_back(getUShort()); } void NIFStream::getFloats(std::vector &vec, size_t size) { @@ -115,23 +115,23 @@ void NIFStream::getFloats(std::vector &vec, size_t size) for(size_t i = 0;i < vec.size();i++) vec[i] = getFloat(); } -void NIFStream::getVector2s(std::vector &vec, size_t size) +void NIFStream::getVector2s(osg::Vec2Array* vec, size_t size) { - vec.resize(size); - for(size_t i = 0;i < vec.size();i++) - vec[i] = getVector2(); + vec->reserve(size); + for(size_t i = 0;i < size;i++) + vec->push_back(getVector2()); } -void NIFStream::getVector3s(std::vector &vec, size_t size) +void NIFStream::getVector3s(osg::Vec3Array* vec, size_t size) { - vec.resize(size); - for(size_t i = 0;i < vec.size();i++) - vec[i] = getVector3(); + vec->reserve(size); + for(size_t i = 0;i < size;i++) + vec->push_back(getVector3()); } -void NIFStream::getVector4s(std::vector &vec, size_t size) +void NIFStream::getVector4s(osg::Vec4Array* vec, size_t size) { - vec.resize(size); - for(size_t i = 0;i < vec.size();i++) - vec[i] = getVector4(); + vec->reserve(size); + for(size_t i = 0;i < size;i++) + vec->push_back(getVector4()); } void NIFStream::getQuaternions(std::vector &quat, size_t size) { diff --git a/components/nif/nifstream.hpp b/components/nif/nifstream.hpp index f4163ce47..f5d777bdf 100644 --- a/components/nif/nifstream.hpp +++ b/components/nif/nifstream.hpp @@ -12,9 +12,12 @@ #include #include #include +#include +#include #include "niftypes.hpp" + namespace Nif { @@ -59,11 +62,11 @@ public: ///This is special since the version string doesn't start with a number, and ends with "\n" std::string getVersionString(); - void getUShorts(std::vector &vec, size_t size); + void getUShorts(osg::VectorGLushort* vec, size_t size); void getFloats(std::vector &vec, size_t size); - void getVector2s(std::vector &vec, size_t size); - void getVector3s(std::vector &vec, size_t size); - void getVector4s(std::vector &vec, size_t size); + void getVector2s(osg::Vec2Array* vec, size_t size); + void getVector3s(osg::Vec3Array* vec, size_t size); + void getVector4s(osg::Vec4Array* vec, size_t size); void getQuaternions(std::vector &quat, size_t size); }; diff --git a/components/nifbullet/bulletnifloader.cpp b/components/nifbullet/bulletnifloader.cpp index 495c6ba50..adf961dc2 100644 --- a/components/nifbullet/bulletnifloader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -292,13 +292,14 @@ void BulletNifLoader::handleNiTriShape(const Nif::NiTriShape *shape, int flags, const Nif::NiTriShapeData *data = shape->data.getPtr(); - childMesh->preallocateVertices(data->vertices.size()); - childMesh->preallocateIndices(data->triangles.size()); + childMesh->preallocateVertices(data->vertices->size()); + childMesh->preallocateIndices(data->triangles->size()); - const std::vector &vertices = data->vertices; - const std::vector &triangles = data->triangles; + const osg::Vec3Array& vertices = *data->vertices; + const osg::DrawElementsUShort& triangles = *data->triangles; - for(size_t i = 0;i < data->triangles.size();i+=3) + size_t numtris = data->triangles->size(); + for(size_t i = 0;i < numtris;i+=3) { osg::Vec3f b1 = vertices[triangles[i+0]]; osg::Vec3f b2 = vertices[triangles[i+1]]; @@ -332,10 +333,11 @@ void BulletNifLoader::handleNiTriShape(const Nif::NiTriShape *shape, int flags, // Static shape, just transform all vertices into position const Nif::NiTriShapeData *data = shape->data.getPtr(); - const std::vector &vertices = data->vertices; - const std::vector &triangles = data->triangles; + const osg::Vec3Array& vertices = *data->vertices; + const osg::DrawElementsUShort& triangles = *data->triangles; - for(size_t i = 0;i < data->triangles.size();i+=3) + size_t numtris = data->triangles->size(); + for(size_t i = 0;i < numtris;i+=3) { osg::Vec3f b1 = vertices[triangles[i+0]]*transform; osg::Vec3f b2 = vertices[triangles[i+1]]*transform; diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index d8920646d..802ca5425 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -736,11 +736,11 @@ namespace NifOsg // Note this position and velocity is not correct for a particle system with absolute reference frame, // which can not be done in this loader since we are not attached to the scene yet. Will be fixed up post-load in the SceneManager. created->setVelocity(particle.velocity); - created->setPosition(particledata->vertices.at(particle.vertex)); + created->setPosition(particledata->vertices->at(particle.vertex)); osg::Vec4f partcolor (1.f,1.f,1.f,1.f); - if (particle.vertex < int(particledata->colors.size())) - partcolor = particledata->colors.at(particle.vertex); + if (particle.vertex < int(particledata->colors->size())) + partcolor = particledata->colors->at(particle.vertex); float size = particledata->sizes.at(particle.vertex) * partctrl->size; @@ -892,11 +892,10 @@ namespace NifOsg { const Nif::NiTriShapeData* data = triShape->data.getPtr(); - { - geometry->setVertexArray(new osg::Vec3Array(data->vertices.size(), &data->vertices[0])); - if (!data->normals.empty()) - geometry->setNormalArray(new osg::Vec3Array(data->normals.size(), &data->normals[0]), osg::Array::BIND_PER_VERTEX); - } + geometry->setVertexArray(data->vertices); + + if (!data->normals->empty()) + geometry->setNormalArray(data->normals); int textureStage = 0; for (std::vector::const_iterator it = boundTextures.begin(); it != boundTextures.end(); ++it,++textureStage) @@ -909,15 +908,14 @@ namespace NifOsg continue; } - geometry->setTexCoordArray(textureStage, new osg::Vec2Array(data->uvlist[uvSet].size(), &data->uvlist[uvSet][0]), osg::Array::BIND_PER_VERTEX); + geometry->setTexCoordArray(textureStage, data->uvlist[uvSet]); } - if (!data->colors.empty()) - geometry->setColorArray(new osg::Vec4Array(data->colors.size(), &data->colors[0]), osg::Array::BIND_PER_VERTEX); + if (!data->colors->empty()) + geometry->setColorArray(data->colors); - geometry->addPrimitiveSet(new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLES, - data->triangles.size(), - (unsigned short*)&data->triangles[0])); + if (!data->triangles->empty()) + geometry->addPrimitiveSet(data->triangles); // osg::Material properties are handled here for two reasons: // - if there are no vertex colors, we need to disable colorMode. @@ -925,7 +923,7 @@ namespace NifOsg // above the actual renderable would be tedious. std::vector materialProps; collectMaterialProperties(triShape, materialProps); - applyMaterialProperties(parentNode, materialProps, composite, !data->colors.empty(), animflags); + applyMaterialProperties(parentNode, materialProps, composite, !data->colors->empty(), animflags); } void handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::vector& boundTextures, int animflags) @@ -988,13 +986,13 @@ namespace NifOsg for (unsigned int i = 1; i < morphs.size(); ++i) { osg::ref_ptr morphTarget = new osg::Geometry; - morphTarget->setVertexArray(new osg::Vec3Array(morphs[i].mVertices.size(), &morphs[i].mVertices[0])); + morphTarget->setVertexArray(morphs[i].mVertices); morphGeom->addMorphTarget(morphTarget, 0.f); } // build the bounding box containing all possible morph combinations - std::vector vertBounds(morphs[0].mVertices.size()); + std::vector vertBounds(morphs[0].mVertices->size()); // Since we don't know what combinations of morphs are being applied we need to keep track of a bounding box for each vertex. // The minimum/maximum of the box is the minimum/maximum offset the vertex can have from its starting position. @@ -1005,19 +1003,19 @@ namespace NifOsg for (unsigned int i = 1; i < morphs.size(); ++i) { - for (unsigned int j=0; jsize() && vertBounds.size(); ++j) { osg::BoundingBox& bounds = vertBounds[j]; - bounds.expandBy(bounds._max + morphs[i].mVertices[j]); - bounds.expandBy(bounds._min + morphs[i].mVertices[j]); + bounds.expandBy(bounds._max + (*morphs[i].mVertices)[j]); + bounds.expandBy(bounds._min + (*morphs[i].mVertices)[j]); } } osg::BoundingBox box; for (unsigned int i=0; i Date: Thu, 18 Jun 2015 03:03:30 +0200 Subject: [PATCH 1576/3725] Re-enable a warning message --- components/nifosg/nifloader.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 802ca5425..c30ac671a 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -903,8 +903,7 @@ namespace NifOsg int uvSet = *it; if (uvSet >= (int)data->uvlist.size()) { - // Occurred in "ascendedsleeper.nif", but only for hidden Shadow nodes, apparently - //std::cerr << "Warning: using an undefined UV set " << uvSet << " on TriShape " << triShape->name << std::endl; + std::cerr << "Warning: using an undefined UV set " << uvSet << " on TriShape " << triShape->name << " in " << mFilename << std::endl; continue; } From 63d46f7e6627385f1aa18527865e5befd4534622 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 18 Jun 2015 10:26:35 +0200 Subject: [PATCH 1577/3725] removed an unused variable --- apps/opencs/view/world/datadisplaydelegate.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/opencs/view/world/datadisplaydelegate.cpp b/apps/opencs/view/world/datadisplaydelegate.cpp index 77ed33daa..72f45a18c 100644 --- a/apps/opencs/view/world/datadisplaydelegate.cpp +++ b/apps/opencs/view/world/datadisplaydelegate.cpp @@ -62,7 +62,6 @@ QSize CSVWorld::DataDisplayDelegate::sizeHint(const QStyleOptionViewItem &option } else if (mDisplayMode == Mode_IconAndText) { - int valueWidth = option.fontMetrics.width(mValues.at(valueIndex).second); size.setWidth(size.width() + mIconSize.width() + mTextLeftOffset); } From cf487581f79a917c4c68b1fe3b65d38110a3d520 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Thu, 18 Jun 2015 12:50:46 +0300 Subject: [PATCH 1578/3725] Show the pop-up of ColorEditor immediately after the editor creation in tables --- apps/opencs/view/widget/coloreditor.cpp | 17 +++++++++++++++-- apps/opencs/view/widget/coloreditor.hpp | 6 ++++-- apps/opencs/view/world/util.cpp | 6 ++++++ 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/apps/opencs/view/widget/coloreditor.cpp b/apps/opencs/view/widget/coloreditor.cpp index 798502196..7ef1ec7b1 100644 --- a/apps/opencs/view/widget/coloreditor.cpp +++ b/apps/opencs/view/widget/coloreditor.cpp @@ -6,13 +6,15 @@ #include #include #include +#include #include "colorpickerpopup.hpp" -CSVWidget::ColorEditor::ColorEditor(const QColor &color, QWidget *parent) +CSVWidget::ColorEditor::ColorEditor(const QColor &color, QWidget *parent, bool popupOnStart) : QPushButton(parent), mColor(color), - mColorPicker(new ColorPickerPopup(this)) + mColorPicker(new ColorPickerPopup(this)), + mPopupOnStart(popupOnStart) { setCheckable(true); connect(this, SIGNAL(clicked()), this, SLOT(showPicker())); @@ -35,6 +37,17 @@ void CSVWidget::ColorEditor::paintEvent(QPaintEvent *event) painter.drawRect(coloredRect); } +void CSVWidget::ColorEditor::showEvent(QShowEvent *event) +{ + QPushButton::showEvent(event); + if (isVisible() && mPopupOnStart) + { + setChecked(true); + showPicker(); + mPopupOnStart = false; + } +} + QColor CSVWidget::ColorEditor::color() const { return mColor; diff --git a/apps/opencs/view/widget/coloreditor.hpp b/apps/opencs/view/widget/coloreditor.hpp index cca26fade..61232cb13 100644 --- a/apps/opencs/view/widget/coloreditor.hpp +++ b/apps/opencs/view/widget/coloreditor.hpp @@ -17,17 +17,19 @@ namespace CSVWidget QColor mColor; ColorPickerPopup *mColorPicker; + bool mPopupOnStart; QPoint calculatePopupPosition(); public: - ColorEditor(const QColor &color, QWidget *parent = 0); + ColorEditor(const QColor &color, QWidget *parent = 0, bool popupOnStart = false); QColor color() const; void setColor(const QColor &color); protected: - void paintEvent(QPaintEvent *event); + virtual void paintEvent(QPaintEvent *event); + virtual void showEvent(QShowEvent *event); private slots: void showPicker(); diff --git a/apps/opencs/view/world/util.cpp b/apps/opencs/view/world/util.cpp index de088bffc..5974987c0 100644 --- a/apps/opencs/view/world/util.cpp +++ b/apps/opencs/view/world/util.cpp @@ -172,6 +172,12 @@ QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleO { return QStyledItemDelegate::createEditor(parent, option, index); } + // For tables the pop-up of the color editor should appear immediately after the editor creation + // (the third parameter of ColorEditor's constructor) + else if (display == CSMWorld::ColumnBase::Display_Colour) + { + return new CSVWidget::ColorEditor(index.data().value(), parent, true); + } return createEditor (parent, option, index, display); } From 76799982a5f73c94ae913047af820b4402f3c2dc Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 18 Jun 2015 14:56:43 +0200 Subject: [PATCH 1579/3725] Add missing include --- apps/opencs/view/render/object.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index 6ddea913a..ea27b1432 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -1,6 +1,7 @@ #include "object.hpp" #include +#include #include #include From 04010b8a1aee77a69fbd654ecaf1be2238c7a8a8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 18 Jun 2015 15:00:04 +0200 Subject: [PATCH 1580/3725] Set OnPcHitMe even for missed hits --- apps/openmw/mwclass/creature.cpp | 16 ++++++++-------- apps/openmw/mwclass/npc.cpp | 15 ++++++++------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index c88691515..5b5a3a0cb 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -345,6 +345,14 @@ namespace MWClass if(!object.isEmpty()) getCreatureStats(ptr).setLastHitAttemptObject(object.getClass().getId(object)); + if(setOnPcHitMe && !attacker.isEmpty() && attacker == MWBase::Environment::get().getWorld()->getPlayerPtr()) + { + const std::string &script = ptr.get()->mBase->mScript; + /* Set the OnPCHitMe script variable. The script is responsible for clearing it. */ + if(!script.empty()) + ptr.getRefData().getLocals().setVarByInt(script, "onpchitme", 1); + } + if(!successful) { // Missed @@ -355,14 +363,6 @@ namespace MWClass if(!object.isEmpty()) getCreatureStats(ptr).setLastHitObject(object.getClass().getId(object)); - if(setOnPcHitMe && !attacker.isEmpty() && attacker == MWBase::Environment::get().getWorld()->getPlayerPtr()) - { - const std::string &script = ptr.get()->mBase->mScript; - /* Set the OnPCHitMe script variable. The script is responsible for clearing it. */ - if(!script.empty()) - ptr.getRefData().getLocals().setVarByInt(script, "onpchitme", 1); - } - if (damage > 0.0f && !object.isEmpty()) MWMechanics::resistNormalWeapon(ptr, attacker, object, damage); diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index c9de1f6ff..b9ca69c63 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -610,6 +610,14 @@ namespace MWClass if(!object.isEmpty()) getCreatureStats(ptr).setLastHitAttemptObject(object.getClass().getId(object)); + if(setOnPcHitMe && !attacker.isEmpty() && attacker == MWBase::Environment::get().getWorld()->getPlayerPtr()) + { + const std::string &script = ptr.getClass().getScript(ptr); + /* Set the OnPCHitMe script variable. The script is responsible for clearing it. */ + if(!script.empty()) + ptr.getRefData().getLocals().setVarByInt(script, "onpchitme", 1); + } + if(!successful) { // Missed @@ -620,13 +628,6 @@ namespace MWClass if(!object.isEmpty()) getCreatureStats(ptr).setLastHitObject(object.getClass().getId(object)); - if(setOnPcHitMe && !attacker.isEmpty() && attacker == MWBase::Environment::get().getWorld()->getPlayerPtr()) - { - const std::string &script = ptr.getClass().getScript(ptr); - /* Set the OnPCHitMe script variable. The script is responsible for clearing it. */ - if(!script.empty()) - ptr.getRefData().getLocals().setVarByInt(script, "onpchitme", 1); - } if (damage > 0.0f && !object.isEmpty()) MWMechanics::resistNormalWeapon(ptr, attacker, object, damage); From 88d1f158d0978df8793af92069fbd128481451cb Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 18 Jun 2015 16:36:27 +0200 Subject: [PATCH 1581/3725] made double click behaviour in report tables configurable (Fixes #2622) --- apps/opencs/model/settings/usersettings.cpp | 41 +++++++++++++++ apps/opencs/view/tools/reporttable.cpp | 57 +++++++++++++++++++-- apps/opencs/view/tools/reporttable.hpp | 11 ++++ 3 files changed, 104 insertions(+), 5 deletions(-) diff --git a/apps/opencs/model/settings/usersettings.cpp b/apps/opencs/model/settings/usersettings.cpp index 5b6e7ab8b..d1dddf8ba 100644 --- a/apps/opencs/model/settings/usersettings.cpp +++ b/apps/opencs/model/settings/usersettings.cpp @@ -234,6 +234,47 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() jumpToAdded->setDeclaredValues (jumpValues); } + declareSection ("report-input", "Report Input"); + { + QString none ("None"); + QString edit ("Edit"); + QString remove ("Remove"); + QString editAndRemove ("Edit And Remove"); + + QStringList values; + values << none << edit << remove << editAndRemove; + + QString toolTip = "

    " + "
  • None
  • " + "
  • Edit: Open a table or dialogue suitable for addressing the listed report
  • " + "
  • Remove: Remove the report from the report table
  • " + "
  • Edit and Remove: Open a table or dialogue suitable for addressing the listed report, then remove the report from the report table
  • " + "
"; + + Setting *doubleClick = createSetting (Type_ComboBox, "double", "Double Click"); + doubleClick->setDeclaredValues (values); + doubleClick->setDefaultValue (edit); + doubleClick->setToolTip ("Action on double click in report table:

" + toolTip); + + Setting *shiftDoubleClick = createSetting (Type_ComboBox, "double-s", + "Shift Double Click"); + shiftDoubleClick->setDeclaredValues (values); + shiftDoubleClick->setDefaultValue (remove); + shiftDoubleClick->setToolTip ("Action on shift double click in report table:

" + toolTip); + + Setting *ctrlDoubleClick = createSetting (Type_ComboBox, "double-c", + "Control Double Click"); + ctrlDoubleClick->setDeclaredValues (values); + ctrlDoubleClick->setDefaultValue (editAndRemove); + ctrlDoubleClick->setToolTip ("Action on control double click in report table:

" + toolTip); + + Setting *shiftCtrlDoubleClick = createSetting (Type_ComboBox, "double-sc", + "Shift Control Double Click"); + shiftCtrlDoubleClick->setDeclaredValues (values); + shiftCtrlDoubleClick->setDefaultValue (none); + shiftCtrlDoubleClick->setToolTip ("Action on shift control double click in report table:

" + toolTip); + } + declareSection ("search", "Search & Replace"); { Setting *before = createSetting (Type_SpinBox, "char-before", diff --git a/apps/opencs/view/tools/reporttable.cpp b/apps/opencs/view/tools/reporttable.cpp index c1c8a35dd..e530e1159 100644 --- a/apps/opencs/view/tools/reporttable.cpp +++ b/apps/opencs/view/tools/reporttable.cpp @@ -96,21 +96,35 @@ void CSVTools::ReportTable::mouseDoubleClickEvent (QMouseEvent *event) selectionModel()->select (index, QItemSelectionModel::Clear | QItemSelectionModel::Select | QItemSelectionModel::Rows); - switch (modifiers) + std::map::iterator iter = + mDoubleClickActions.find (modifiers); + + if (iter==mDoubleClickActions.end()) + { + event->accept(); + return; + } + + switch (iter->second) { - case 0: + case Action_None: + + event->accept(); + break; + + case Action_Edit: event->accept(); showSelection(); break; - case Qt::ShiftModifier: + case Action_Remove: event->accept(); removeSelection(); break; - case Qt::ControlModifier: + case Action_EditAndRemove: event->accept(); showSelection(); @@ -155,7 +169,11 @@ CSVTools::ReportTable::ReportTable (CSMDoc::Document& document, mReplaceAction = new QAction (tr ("Replace"), this); connect (mReplaceAction, SIGNAL (triggered()), this, SIGNAL (replaceRequest())); - addAction (mReplaceAction); + addAction (mReplaceAction); + + mDoubleClickActions.insert (std::make_pair (Qt::NoModifier, Action_Edit)); + mDoubleClickActions.insert (std::make_pair (Qt::ShiftModifier, Action_Remove)); + mDoubleClickActions.insert (std::make_pair (Qt::ControlModifier, Action_EditAndRemove)); } std::vector CSVTools::ReportTable::getDraggedRecords() const @@ -176,6 +194,35 @@ std::vector CSVTools::ReportTable::getDraggedRecords() co void CSVTools::ReportTable::updateUserSetting (const QString& name, const QStringList& list) { mIdTypeDelegate->updateUserSetting (name, list); + + QString base ("report-input/double"); + if (name.startsWith (base)) + { + QString modifierString = name.mid (base.size()); + Qt::KeyboardModifiers modifiers = 0; + + if (modifierString=="-s") + modifiers = Qt::ShiftModifier; + else if (modifierString=="-c") + modifiers = Qt::ControlModifier; + else if (modifierString=="-sc") + modifiers = Qt::ShiftModifier | Qt::ControlModifier; + + DoubleClickAction action = Action_None; + + QString value = list.at (0); + + if (value=="Edit") + action = Action_Edit; + else if (value=="Remove") + action = Action_Remove; + else if (value=="Edit And Remove") + action = Action_EditAndRemove; + + mDoubleClickActions[modifiers] = action; + + return; + } } std::vector CSVTools::ReportTable::getReplaceIndices (bool selection) const diff --git a/apps/opencs/view/tools/reporttable.hpp b/apps/opencs/view/tools/reporttable.hpp index c4d5b414e..95ab07cbb 100644 --- a/apps/opencs/view/tools/reporttable.hpp +++ b/apps/opencs/view/tools/reporttable.hpp @@ -1,6 +1,8 @@ #ifndef CSV_TOOLS_REPORTTABLE_H #define CSV_TOOLS_REPORTTABLE_H +#include + #include "../world/dragrecordtable.hpp" class QAction; @@ -21,11 +23,20 @@ namespace CSVTools { Q_OBJECT + enum DoubleClickAction + { + Action_None, + Action_Edit, + Action_Remove, + Action_EditAndRemove + }; + CSMTools::ReportModel *mModel; CSVWorld::CommandDelegate *mIdTypeDelegate; QAction *mShowAction; QAction *mRemoveAction; QAction *mReplaceAction; + std::map mDoubleClickActions; private: From 36271f25ec1d228f7f990c15b509bafbb82df703 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Thu, 18 Jun 2015 22:59:40 +0300 Subject: [PATCH 1582/3725] Rework creator factories to accept Document as a parameter --- apps/opencs/view/world/creator.cpp | 4 ++-- apps/opencs/view/world/creator.hpp | 25 ++++++++-------------- apps/opencs/view/world/dialoguecreator.cpp | 14 ++++++------ apps/opencs/view/world/dialoguecreator.hpp | 6 ++---- apps/opencs/view/world/dialoguesubview.cpp | 3 +-- apps/opencs/view/world/genericcreator.hpp | 2 ++ apps/opencs/view/world/scenesubview.cpp | 4 +--- apps/opencs/view/world/tablebottombox.cpp | 8 ++++--- apps/opencs/view/world/tablebottombox.hpp | 11 +++++----- apps/opencs/view/world/tablesubview.cpp | 2 +- 10 files changed, 37 insertions(+), 42 deletions(-) diff --git a/apps/opencs/view/world/creator.cpp b/apps/opencs/view/world/creator.cpp index 2e7c7fe22..7a8c8d48f 100644 --- a/apps/opencs/view/world/creator.cpp +++ b/apps/opencs/view/world/creator.cpp @@ -15,8 +15,8 @@ void CSVWorld::Creator::setScope (unsigned int scope) CSVWorld::CreatorFactoryBase::~CreatorFactoryBase() {} -CSVWorld::Creator *CSVWorld::NullCreatorFactory::makeCreator (CSMWorld::Data& data, - QUndoStack& undoStack, const CSMWorld::UniversalId& id) const +CSVWorld::Creator *CSVWorld::NullCreatorFactory::makeCreator (CSMDoc::Document& document, + const CSMWorld::UniversalId& id) const { return 0; } diff --git a/apps/opencs/view/world/creator.hpp b/apps/opencs/view/world/creator.hpp index 506bdab2c..b2d80cf2f 100644 --- a/apps/opencs/view/world/creator.hpp +++ b/apps/opencs/view/world/creator.hpp @@ -5,16 +5,12 @@ #include -#include "../../model/world/universalid.hpp" - #include "../../model/world/scope.hpp" +#include "../../model/world/universalid.hpp" -class QUndoStack; - -namespace CSMWorld +namespace CSMDoc { - class Data; - class UniversalId; + class Document; } namespace CSVWorld @@ -59,8 +55,7 @@ namespace CSVWorld virtual ~CreatorFactoryBase(); - virtual Creator *makeCreator (CSMWorld::Data& data, QUndoStack& undoStack, - const CSMWorld::UniversalId& id) const = 0; + virtual Creator *makeCreator (CSMDoc::Document& document, const CSMWorld::UniversalId& id) const = 0; ///< The ownership of the returned Creator is transferred to the caller. /// /// \note The function can return a 0-pointer, which means no UI for creating/deleting @@ -72,8 +67,7 @@ namespace CSVWorld { public: - virtual Creator *makeCreator (CSMWorld::Data& data, QUndoStack& undoStack, - const CSMWorld::UniversalId& id) const; + virtual Creator *makeCreator (CSMDoc::Document& document, const CSMWorld::UniversalId& id) const; ///< The ownership of the returned Creator is transferred to the caller. /// /// \note The function always returns 0. @@ -84,8 +78,7 @@ namespace CSVWorld { public: - virtual Creator *makeCreator (CSMWorld::Data& data, QUndoStack& undoStack, - const CSMWorld::UniversalId& id) const; + virtual Creator *makeCreator (CSMDoc::Document& document, const CSMWorld::UniversalId& id) const; ///< The ownership of the returned Creator is transferred to the caller. /// /// \note The function can return a 0-pointer, which means no UI for creating/deleting @@ -93,10 +86,10 @@ namespace CSVWorld }; template - Creator *CreatorFactory::makeCreator (CSMWorld::Data& data, QUndoStack& undoStack, - const CSMWorld::UniversalId& id) const + Creator *CreatorFactory::makeCreator (CSMDoc::Document& document, + const CSMWorld::UniversalId& id) const { - std::auto_ptr creator (new CreatorT (data, undoStack, id)); + std::auto_ptr creator (new CreatorT (document.getData(), document.getUndoStack(), id)); creator->setScope (scope); diff --git a/apps/opencs/view/world/dialoguecreator.cpp b/apps/opencs/view/world/dialoguecreator.cpp index 956cd26df..3d451ed2d 100644 --- a/apps/opencs/view/world/dialoguecreator.cpp +++ b/apps/opencs/view/world/dialoguecreator.cpp @@ -3,6 +3,8 @@ #include +#include "../../model/doc/document.hpp" + #include "../../model/world/data.hpp" #include "../../model/world/commands.hpp" #include "../../model/world/columns.hpp" @@ -22,14 +24,14 @@ CSVWorld::DialogueCreator::DialogueCreator (CSMWorld::Data& data, QUndoStack& un : GenericCreator (data, undoStack, id, true), mType (type) {} -CSVWorld::Creator *CSVWorld::TopicCreatorFactory::makeCreator (CSMWorld::Data& data, - QUndoStack& undoStack, const CSMWorld::UniversalId& id) const +CSVWorld::Creator *CSVWorld::TopicCreatorFactory::makeCreator (CSMDoc::Document& document, + const CSMWorld::UniversalId& id) const { - return new DialogueCreator (data, undoStack, id, ESM::Dialogue::Topic); + return new DialogueCreator (document.getData(), document.getUndoStack(), id, ESM::Dialogue::Topic); } -CSVWorld::Creator *CSVWorld::JournalCreatorFactory::makeCreator (CSMWorld::Data& data, - QUndoStack& undoStack, const CSMWorld::UniversalId& id) const +CSVWorld::Creator *CSVWorld::JournalCreatorFactory::makeCreator (CSMDoc::Document& document, + const CSMWorld::UniversalId& id) const { - return new DialogueCreator (data, undoStack, id, ESM::Dialogue::Journal); + return new DialogueCreator (document.getData(), document.getUndoStack(), id, ESM::Dialogue::Journal); } diff --git a/apps/opencs/view/world/dialoguecreator.hpp b/apps/opencs/view/world/dialoguecreator.hpp index 26f866909..20430fdb6 100644 --- a/apps/opencs/view/world/dialoguecreator.hpp +++ b/apps/opencs/view/world/dialoguecreator.hpp @@ -23,8 +23,7 @@ namespace CSVWorld { public: - virtual Creator *makeCreator (CSMWorld::Data& data, QUndoStack& undoStack, - const CSMWorld::UniversalId& id) const; + virtual Creator *makeCreator (CSMDoc::Document& document, const CSMWorld::UniversalId& id) const; ///< The ownership of the returned Creator is transferred to the caller. }; @@ -32,8 +31,7 @@ namespace CSVWorld { public: - virtual Creator *makeCreator (CSMWorld::Data& data, QUndoStack& undoStack, - const CSMWorld::UniversalId& id) const; + virtual Creator *makeCreator (CSMDoc::Document& document, const CSMWorld::UniversalId& id) const; ///< The ownership of the returned Creator is transferred to the caller. }; } diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index ab466dfcd..5d9eda3f2 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -685,8 +685,7 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSM mMainLayout->addWidget(mEditWidget); mEditWidget->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); - mMainLayout->addWidget (mBottom = - new TableBottomBox (creatorFactory, document.getData(), document.getUndoStack(), id, this)); + mMainLayout->addWidget (mBottom = new TableBottomBox (creatorFactory, document, id, this)); mBottom->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed); diff --git a/apps/opencs/view/world/genericcreator.hpp b/apps/opencs/view/world/genericcreator.hpp index 1f854c69e..0d2a40486 100644 --- a/apps/opencs/view/world/genericcreator.hpp +++ b/apps/opencs/view/world/genericcreator.hpp @@ -13,10 +13,12 @@ class QLineEdit; class QHBoxLayout; class QComboBox; class QLabel; +class QUndoStack; namespace CSMWorld { class CreateCommand; + class Data; } namespace CSVWorld diff --git a/apps/opencs/view/world/scenesubview.cpp b/apps/opencs/view/world/scenesubview.cpp index aa2161259..397d24929 100644 --- a/apps/opencs/view/world/scenesubview.cpp +++ b/apps/opencs/view/world/scenesubview.cpp @@ -33,9 +33,7 @@ CSVWorld::SceneSubView::SceneSubView (const CSMWorld::UniversalId& id, CSMDoc::D layout->setContentsMargins (QMargins (0, 0, 0, 0)); - layout->addWidget (mBottom = - new TableBottomBox (NullCreatorFactory(), document.getData(), document.getUndoStack(), id, - this), 0); + layout->addWidget (mBottom = new TableBottomBox (NullCreatorFactory(), document, id, this), 0); mLayout->setContentsMargins (QMargins (0, 0, 0, 0)); diff --git a/apps/opencs/view/world/tablebottombox.cpp b/apps/opencs/view/world/tablebottombox.cpp index e9d644f61..dc3a6cc76 100644 --- a/apps/opencs/view/world/tablebottombox.cpp +++ b/apps/opencs/view/world/tablebottombox.cpp @@ -39,8 +39,10 @@ void CSVWorld::TableBottomBox::updateStatus() } } -CSVWorld::TableBottomBox::TableBottomBox (const CreatorFactoryBase& creatorFactory, - CSMWorld::Data& data, QUndoStack& undoStack, const CSMWorld::UniversalId& id, QWidget *parent) +CSVWorld::TableBottomBox::TableBottomBox (const CreatorFactoryBase& creatorFactory, + CSMDoc::Document& document, + const CSMWorld::UniversalId& id, + QWidget *parent) : QWidget (parent), mShowStatusBar (false), mCreating (false) { for (int i=0; i<4; ++i) @@ -61,7 +63,7 @@ CSVWorld::TableBottomBox::TableBottomBox (const CreatorFactoryBase& creatorFacto setLayout (mLayout); - mCreator = creatorFactory.makeCreator (data, undoStack, id); + mCreator = creatorFactory.makeCreator (document, id); if (mCreator) { diff --git a/apps/opencs/view/world/tablebottombox.hpp b/apps/opencs/view/world/tablebottombox.hpp index 8f0d85163..a7d009c42 100644 --- a/apps/opencs/view/world/tablebottombox.hpp +++ b/apps/opencs/view/world/tablebottombox.hpp @@ -9,10 +9,9 @@ class QStackedLayout; class QStatusBar; class QUndoStack; -namespace CSMWorld +namespace CSMDoc { - class Data; - class UniversalId; + class Document; } namespace CSVWorld @@ -42,8 +41,10 @@ namespace CSVWorld public: - TableBottomBox (const CreatorFactoryBase& creatorFactory, CSMWorld::Data& data, - QUndoStack& undoStack, const CSMWorld::UniversalId& id, QWidget *parent = 0); + TableBottomBox (const CreatorFactoryBase& creatorFactory, + CSMDoc::Document& document, + const CSMWorld::UniversalId& id, + QWidget *parent = 0); virtual ~TableBottomBox(); diff --git a/apps/opencs/view/world/tablesubview.cpp b/apps/opencs/view/world/tablesubview.cpp index faff4c429..75671a50c 100644 --- a/apps/opencs/view/world/tablesubview.cpp +++ b/apps/opencs/view/world/tablesubview.cpp @@ -26,7 +26,7 @@ CSVWorld::TableSubView::TableSubView (const CSMWorld::UniversalId& id, CSMDoc::D layout->setContentsMargins (QMargins (0, 0, 0, 0)); layout->addWidget (mBottom = - new TableBottomBox (creatorFactory, document.getData(), document.getUndoStack(), id, this), 0); + new TableBottomBox (creatorFactory, document, id, this), 0); layout->insertWidget (0, mTable = new Table (id, mBottom->canCreateAndDelete(), sorting, document), 2); From fb94395628895532b12380134e98889274b777b1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 18 Jun 2015 23:15:13 +0200 Subject: [PATCH 1583/3725] Fix atmosphere lighting --- apps/openmw/mwrender/sky.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 0494b9544..0032c4e4f 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -104,7 +104,7 @@ public: protected: virtual void setDefaults(osg::StateSet* stateset) { - stateset->setAttribute(createAlphaTrackingUnlitMaterial(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + stateset->setAttributeAndModes(createAlphaTrackingUnlitMaterial(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); } virtual void apply(osg::StateSet* stateset, osg::NodeVisitor* /*nv*/) @@ -224,9 +224,6 @@ public: if (!geom) continue; - // might want to use fog coordinates instead of vertex colors so we can apply a separate fade to the diffuse alpha - // (that isn't possible now, with the diffuse tracking the vertex colors) - osg::ref_ptr colors = new osg::Vec4Array(geom->getVertexArray()->getNumElements()); for (unsigned int i=0; isize(); ++i) { @@ -244,7 +241,7 @@ public: alpha = ((*origColors)[i].x() == 1.f) ? 1.f : 0.f; } - (*colors)[i] = osg::Vec4f(alpha, alpha, alpha, alpha); + (*colors)[i] = osg::Vec4f(0.f, 0.f, 0.f, alpha); } geom->setColorArray(colors, osg::Array::BIND_PER_VERTEX); From 0c4ebee6b36920d56c1ff9ecb2c5a8cda65466c1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 19 Jun 2015 01:03:12 +0200 Subject: [PATCH 1584/3725] Cloud opacity & cross-fading --- apps/openmw/mwrender/sky.cpp | 55 +++++++++++++++++++++++++++--------- apps/openmw/mwrender/sky.hpp | 3 ++ 2 files changed, 44 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 0032c4e4f..25b19465b 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -141,8 +141,24 @@ public: protected: virtual void setDefaults(osg::StateSet *stateset) { - stateset->setTextureAttributeAndModes(0, new osg::TexMat, osg::StateAttribute::ON); + osg::ref_ptr texmat (new osg::TexMat); + stateset->setTextureAttributeAndModes(0, texmat, osg::StateAttribute::ON); + stateset->setTextureAttributeAndModes(1, texmat, osg::StateAttribute::ON); stateset->setAttribute(createAlphaTrackingUnlitMaterial(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + + // need to set opacity on a separate texture unit, diffuse alpha is used by the vertex colors already + osg::ref_ptr texEnvCombine (new osg::TexEnvCombine); + texEnvCombine->setSource0_RGB(osg::TexEnvCombine::PREVIOUS); + texEnvCombine->setSource0_Alpha(osg::TexEnvCombine::PREVIOUS); + texEnvCombine->setSource1_Alpha(osg::TexEnvCombine::CONSTANT); + texEnvCombine->setConstantColor(osg::Vec4f(1,1,1,1)); + texEnvCombine->setCombine_Alpha(osg::TexEnvCombine::MODULATE); + texEnvCombine->setCombine_RGB(osg::TexEnvCombine::REPLACE); + + stateset->setTextureAttributeAndModes(1, texEnvCombine, osg::StateAttribute::ON); + + stateset->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + stateset->setTextureMode(1, GL_TEXTURE_2D, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); } virtual void apply(osg::StateSet *stateset, osg::NodeVisitor *nv) @@ -150,12 +166,14 @@ protected: osg::TexMat* texMat = static_cast(stateset->getTextureAttribute(0, osg::StateAttribute::TEXMAT)); texMat->setMatrix(osg::Matrix::translate(osg::Vec3f(0, mAnimationTimer, 0.f))); - stateset->setTextureAttributeAndModes(0, mTexture, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + stateset->setTextureAttribute(0, mTexture, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + stateset->setTextureAttribute(1, mTexture, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); osg::Material* mat = static_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); mat->setEmission(osg::Material::FRONT_AND_BACK, mEmissionColor); - // FIXME: handle opacity, will have to resort to either shaders or multitexturing? diffuse alpha is in use by the vertex colors already + osg::TexEnvCombine* texEnvCombine = static_cast(stateset->getTextureAttribute(1, osg::StateAttribute::TEXENV)); + texEnvCombine->setConstantColor(osg::Vec4f(1,1,1,mOpacity)); } private: @@ -533,14 +551,16 @@ void SkyManager::create() mCloudNode = new osg::PositionAttitudeTransform; mRootNode->addChild(mCloudNode); - osg::ref_ptr clouds = mSceneManager->createInstance("meshes/sky_clouds_01.nif", mCloudNode); + mCloudMesh = mSceneManager->createInstance("meshes/sky_clouds_01.nif", mCloudNode); ModVertexAlphaVisitor modClouds(1); - clouds->accept(modClouds); - + mCloudMesh->accept(modClouds); mCloudUpdater = new CloudUpdater; - clouds->addUpdateCallback(mCloudUpdater); + mCloudMesh->addUpdateCallback(mCloudUpdater); - clouds->getOrCreateStateSet()->setAttributeAndModes(createAlphaTrackingUnlitMaterial(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + mCloudMesh2 = mSceneManager->createInstance("meshes/sky_clouds_01.nif", mCloudNode); + mCloudMesh2->accept(modClouds); + mCloudUpdater2 = new CloudUpdater; + mCloudMesh2->addUpdateCallback(mCloudUpdater2); osg::ref_ptr depth = new osg::Depth; depth->setWriteMask(false); @@ -602,6 +622,7 @@ void SkyManager::update(float duration) // UV Scroll the clouds mCloudAnimationTimer += duration * mCloudSpeed * 0.003; mCloudUpdater->setAnimationTimer(mCloudAnimationTimer); + mCloudUpdater2->setAnimationTimer(mCloudAnimationTimer); /// \todo improve this mMasser->setPhase( static_cast( (int) ((mDay % 32)/4.f)) ); @@ -708,18 +729,23 @@ void SkyManager::setWeather(const MWWorld::WeatherResult& weather) if (mNextClouds != weather.mNextCloudTexture) { mNextClouds = weather.mNextCloudTexture; - } - if (mCloudBlendFactor != weather.mCloudBlendFactor) - { - mCloudBlendFactor = weather.mCloudBlendFactor; + std::string texture = Misc::ResourceHelpers::correctTexturePath(mNextClouds, mSceneManager->getVFS()); + + if (!texture.empty()) + mCloudUpdater2->setTexture(mSceneManager->getTextureManager()->getTexture2D(texture, + osg::Texture::REPEAT, osg::Texture::REPEAT)); } - if (mCloudOpacity != weather.mCloudOpacity) + if (mCloudBlendFactor != weather.mCloudBlendFactor + || mCloudOpacity != weather.mCloudOpacity) { + mCloudBlendFactor = weather.mCloudBlendFactor; mCloudOpacity = weather.mCloudOpacity; - mCloudUpdater->setOpacity(0.3); + mCloudUpdater->setOpacity(mCloudOpacity * (1.f-mCloudBlendFactor)); + mCloudUpdater2->setOpacity(mCloudOpacity * mCloudBlendFactor); + mCloudMesh2->setNodeMask(mCloudBlendFactor > 0.f ? ~0 : 0); } if (mCloudColour != weather.mSunColor) @@ -730,6 +756,7 @@ void SkyManager::setWeather(const MWWorld::WeatherResult& weather) weather.mSunColor.b()*0.7f + weather.mAmbientColor.b()*0.7f, 1.f); mCloudUpdater->setEmissionColor(clr); + mCloudUpdater2->setEmissionColor(clr); mCloudColour = weather.mSunColor; } diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index f097029d1..e7514e746 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -99,6 +99,9 @@ namespace MWRender osg::ref_ptr mCloudNode; osg::ref_ptr mCloudUpdater; + osg::ref_ptr mCloudUpdater2; + osg::ref_ptr mCloudMesh; + osg::ref_ptr mCloudMesh2; osg::ref_ptr mAtmosphereDay; From e0dfc1425eb6834f00707c296b187f467242c4e2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 19 Jun 2015 02:51:01 +0200 Subject: [PATCH 1585/3725] Correct moon blending --- apps/openmw/mwrender/sky.cpp | 107 ++++++++++++++++++++--------------- apps/openmw/mwrender/sky.hpp | 4 ++ 2 files changed, 64 insertions(+), 47 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 25b19465b..43ed80dbf 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -288,10 +288,11 @@ public: void setDirection(const osg::Vec3f& direction) { - mTransform->setPosition(direction*1000.f); + osg::Vec3f normalizedDirection = direction / direction.length(); + mTransform->setPosition(normalizedDirection*1000.f); osg::Quat quat; - quat.makeRotate(osg::Vec3f(0,0,1), direction); + quat.makeRotate(osg::Vec3f(0,0,1), normalizedDirection); mTransform->setAttitude(quat); } @@ -356,36 +357,13 @@ public: void setTextures(const std::string& phaseTex, const std::string& circleTex) { - osg::ref_ptr stateset = new osg::StateSet; - - osg::ref_ptr moonTex = mSceneManager->getTextureManager()->getTexture2D(circleTex, + osg::ref_ptr phaseTexPtr = mSceneManager->getTextureManager()->getTexture2D(phaseTex, osg::Texture::CLAMP, osg::Texture::CLAMP); - // stage 0: render the moon circle in atmosphere color - stateset->setTextureAttributeAndModes(0, moonTex, osg::StateAttribute::ON); - - osg::ref_ptr texEnv = new osg::TexEnvCombine; - texEnv->setSource0_RGB(osg::TexEnvCombine::CONSTANT); - texEnv->setConstantColor(osg::Vec4f(0.f, 0.f, 0.f, 1.f)); // atmospherecolor - - stateset->setTextureAttributeAndModes(0, texEnv, osg::StateAttribute::ON); - - // stage 1: render the "lit" side of the moon blended over the circle - osg::ref_ptr moonTex2 = mSceneManager->getTextureManager()->getTexture2D(phaseTex, + osg::ref_ptr circleTexPtr = mSceneManager->getTextureManager()->getTexture2D(circleTex, osg::Texture::CLAMP, osg::Texture::CLAMP); - stateset->setTextureAttributeAndModes(1, moonTex2, osg::StateAttribute::ON); - - osg::ref_ptr texEnv2 = new osg::TexEnvCombine; - texEnv2->setCombine_RGB(osg::TexEnvCombine::INTERPOLATE); - texEnv2->setCombine_Alpha(osg::TexEnvCombine::MODULATE); - texEnv2->setSource0_Alpha(osg::TexEnvCombine::CONSTANT); - texEnv2->setConstantColor(osg::Vec4f(1.f, 1.f, 1.f, 1.f)); - texEnv2->setSource2_RGB(osg::TexEnvCombine::TEXTURE); - - stateset->setTextureAttributeAndModes(1, texEnv2, osg::StateAttribute::ON); - - mTransform->setStateSet(stateset); + mUpdater->setTextures(phaseTexPtr, circleTexPtr); } void setPhase(const Phase& phase) @@ -425,43 +403,75 @@ public: { public: MoonUpdater() - : mAlpha(1.f) { } virtual void setDefaults(osg::StateSet *stateset) { + stateset->setTextureAttributeAndModes(0, mPhaseTex, osg::StateAttribute::ON); + osg::ref_ptr texEnv = new osg::TexEnvCombine; + texEnv->setCombine_RGB(osg::TexEnvCombine::MODULATE); + texEnv->setSource0_RGB(osg::TexEnvCombine::CONSTANT); + texEnv->setSource1_RGB(osg::TexEnvCombine::TEXTURE); + texEnv->setConstantColor(osg::Vec4f(1.f, 0.f, 0.f, 1.f)); // fade * MoonRedColor + stateset->setTextureAttributeAndModes(0, texEnv, osg::StateAttribute::ON); + + stateset->setTextureAttributeAndModes(1, mCircleTex, osg::StateAttribute::ON); + osg::ref_ptr texEnv2 = new osg::TexEnvCombine; + texEnv2->setCombine_RGB(osg::TexEnvCombine::ADD); + texEnv2->setCombine_Alpha(osg::TexEnvCombine::REPLACE); + texEnv2->setSource0_Alpha(osg::TexEnvCombine::TEXTURE); + texEnv2->setSource0_RGB(osg::TexEnvCombine::PREVIOUS); + texEnv2->setSource1_RGB(osg::TexEnvCombine::CONSTANT); + texEnv2->setConstantColor(osg::Vec4f(0.f, 0.f, 0.f, 1.f)); // atmospherecolor + stateset->setTextureAttributeAndModes(1, texEnv2, osg::StateAttribute::ON); + stateset->setAttributeAndModes(createUnlitMaterial(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); } virtual void apply(osg::StateSet *stateset, osg::NodeVisitor*) { - osg::Material* mat = static_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); - mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, mAlpha)); + osg::TexEnvCombine* texEnv = static_cast(stateset->getTextureAttribute(0, osg::StateAttribute::TEXENV)); + texEnv->setConstantColor(mMoonColor); + + osg::TexEnvCombine* texEnv2 = static_cast(stateset->getTextureAttribute(1, osg::StateAttribute::TEXENV)); + texEnv2->setConstantColor(mAtmosphereColor); } - void setAlpha(float alpha) + + void setAtmosphereColor(const osg::Vec4f& color) { - mAlpha = alpha; + mAtmosphereColor = color; + } + + void setMoonColor(const osg::Vec4f& color) + { + mMoonColor = color; + } + + void setTextures(osg::ref_ptr phaseTex, osg::ref_ptr circleTex) + { + mPhaseTex = phaseTex; + mCircleTex = circleTex; + reset(); } private: - float mAlpha; + osg::Vec4f mAtmosphereColor; + osg::Vec4f mMoonColor; + osg::ref_ptr mPhaseTex; + osg::ref_ptr mCircleTex; }; - void setAlpha(float alpha) - { - mUpdater->setAlpha(alpha); - } void setAtmosphereColor(const osg::Vec4f& color) { - // TODO + mUpdater->setAtmosphereColor(color); } void setColor(const osg::Vec4f& color) { - // TODO + mUpdater->setMoonColor(color); } unsigned int getPhaseInt() const @@ -508,6 +518,8 @@ SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneMana , mRainFrequency(1) , mEnabled(true) , mSunEnabled(true) + , mMasserFade(0.f) + , mSecundaFade(0.f) { osg::ref_ptr skyroot (new CameraRelativeTransform); skyroot->setNodeMask(Mask_Sky); @@ -568,6 +580,8 @@ void SkyManager::create() mRootNode->getOrCreateStateSet()->setMode(GL_BLEND, osg::StateAttribute::ON); mRootNode->getOrCreateStateSet()->setMode(GL_FOG, osg::StateAttribute::OFF); + mMoonScriptColor = fallback->getFallbackColour("Moons_Script_Color"); + mCreated = true; } @@ -628,9 +642,8 @@ void SkyManager::update(float duration) mMasser->setPhase( static_cast( (int) ((mDay % 32)/4.f)) ); mSecunda->setPhase ( static_cast( (int) ((mDay % 32)/4.f)) ); - //const MWWorld::Fallback* fallback=MWBase::Environment::get().getWorld()->getFallback(); - //mSecunda->setColour ( mMoonRed ? fallback->getFallbackColour("Moons_Script_Color") : ColourValue(1,1,1,1)); - //mMasser->setColour (ColourValue(1,1,1,1)); + mMasser->setColor(osg::Vec4f(mMasserFade,mMasserFade,mMasserFade,1)); + mSecunda->setColor(mMoonRed ? (mMoonScriptColor * mSecundaFade) : osg::Vec4f(mSecundaFade,mSecundaFade,mSecundaFade,1)); if (mSunEnabled) { @@ -766,6 +779,8 @@ void SkyManager::setWeather(const MWWorld::WeatherResult& weather) mSkyColour = weather.mSkyColor; mAtmosphereUpdater->setEmissionColor(mSkyColour); + mMasser->setAtmosphereColor(mSkyColour); + mSecunda->setAtmosphereColor(mSkyColour); } if (mFogColour != weather.mFogColor) @@ -900,14 +915,12 @@ void SkyManager::setLightningStrength(const float factor) void SkyManager::setMasserFade(const float fade) { - if (!mCreated) return; - mMasser->setAlpha(fade); + mMasserFade = fade; } void SkyManager::setSecundaFade(const float fade) { - if (!mCreated) return; - mSecunda->setAlpha(fade); + mSecundaFade = fade; } void SkyManager::setDate(int day, int month) diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index e7514e746..8251f39bd 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -154,6 +154,10 @@ namespace MWRender bool mEnabled; bool mSunEnabled; + + osg::Vec4f mMoonScriptColor; + float mMasserFade; + float mSecundaFade; }; } From 2b53e5d96573702697bc451eda27b0a8b8f008c6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 19 Jun 2015 03:32:48 +0200 Subject: [PATCH 1586/3725] Fix for explosion effects playing when the game is paused --- apps/openmw/mwrender/renderingmanager.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 7f76adb28..719ee6ebc 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -350,7 +350,9 @@ namespace MWRender void RenderingManager::update(float dt, bool paused) { - mEffectManager->update(dt); + if (!paused) + mEffectManager->update(dt); + mSky->update(dt); mWater->update(dt); mCamera->update(dt, paused); From a6734a0ea4857f28c5569e3bc9650b0e8f1e810a Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Fri, 19 Jun 2015 11:50:02 +0300 Subject: [PATCH 1587/3725] Add Cell Id completion to ReferenceCreator --- apps/opencs/view/world/referencecreator.cpp | 15 ++++++++++++++- apps/opencs/view/world/referencecreator.hpp | 16 +++++++++++++++- apps/opencs/view/world/subviews.cpp | 4 ++-- 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/apps/opencs/view/world/referencecreator.cpp b/apps/opencs/view/world/referencecreator.cpp index e9bb04ba7..81efb17ab 100644 --- a/apps/opencs/view/world/referencecreator.cpp +++ b/apps/opencs/view/world/referencecreator.cpp @@ -4,10 +4,13 @@ #include #include +#include "../../model/doc/document.hpp" + #include "../../model/world/data.hpp" #include "../../model/world/commands.hpp" #include "../../model/world/columns.hpp" #include "../../model/world/idtable.hpp" +#include "../../model/world/idcompletionmanager.hpp" std::string CSVWorld::ReferenceCreator::getId() const { @@ -71,13 +74,14 @@ int CSVWorld::ReferenceCreator::getRefNumCount() const } CSVWorld::ReferenceCreator::ReferenceCreator (CSMWorld::Data& data, QUndoStack& undoStack, - const CSMWorld::UniversalId& id) + const CSMWorld::UniversalId& id, CSMWorld::IdCompletionManager &completionManager) : GenericCreator (data, undoStack, id) { QLabel *label = new QLabel ("Cell", this); insertBeforeButtons (label, false); mCell = new QLineEdit (this); + mCell->setCompleter(completionManager.getCompleter(CSMWorld::ColumnBase::Display_Cell).get()); insertBeforeButtons (mCell, true); setManualEditing (false); @@ -142,3 +146,12 @@ void CSVWorld::ReferenceCreator::cloneMode(const std::string& originId, CSVWorld::GenericCreator::cloneMode(originId, type); cellChanged(); //otherwise ok button will remain disabled } + +CSVWorld::Creator *CSVWorld::ReferenceCreatorFactory::makeCreator (CSMDoc::Document& document, + const CSMWorld::UniversalId& id) const +{ + return new ReferenceCreator(document.getData(), + document.getUndoStack(), + id, + document.getIdCompletionManager()); +} diff --git a/apps/opencs/view/world/referencecreator.hpp b/apps/opencs/view/world/referencecreator.hpp index 877307c29..7f56143c9 100644 --- a/apps/opencs/view/world/referencecreator.hpp +++ b/apps/opencs/view/world/referencecreator.hpp @@ -5,8 +5,14 @@ class QLineEdit; +namespace CSMWorld +{ + class IdCompletionManager; +} + namespace CSVWorld { + class ReferenceCreator : public GenericCreator { Q_OBJECT @@ -28,7 +34,7 @@ namespace CSVWorld public: ReferenceCreator (CSMWorld::Data& data, QUndoStack& undoStack, - const CSMWorld::UniversalId& id); + const CSMWorld::UniversalId& id, CSMWorld::IdCompletionManager &completionManager); virtual void cloneMode(const std::string& originId, const CSMWorld::UniversalId::Type type); @@ -46,6 +52,14 @@ namespace CSVWorld void cellChanged(); }; + + class ReferenceCreatorFactory : public CreatorFactoryBase + { + public: + + virtual Creator *makeCreator (CSMDoc::Document& document, const CSMWorld::UniversalId& id) const; + ///< The ownership of the returned Creator is transferred to the caller. + }; } #endif diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp index e81da23e1..fa1b7cdc7 100644 --- a/apps/opencs/view/world/subviews.cpp +++ b/apps/opencs/view/world/subviews.cpp @@ -59,7 +59,7 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) new CSVDoc::SubViewFactoryWithCreator >); manager.add (CSMWorld::UniversalId::Type_References, - new CSVDoc::SubViewFactoryWithCreator >); + new CSVDoc::SubViewFactoryWithCreator); manager.add (CSMWorld::UniversalId::Type_Topics, new CSVDoc::SubViewFactoryWithCreator); @@ -147,7 +147,7 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) new CSVDoc::SubViewFactoryWithCreator > (false)); manager.add (CSMWorld::UniversalId::Type_Reference, - new CSVDoc::SubViewFactoryWithCreator > (false)); + new CSVDoc::SubViewFactoryWithCreator (false)); manager.add (CSMWorld::UniversalId::Type_Cell, new CSVDoc::SubViewFactoryWithCreator > (false)); From 581ba55db9f60e3edd027b7d5d18d6825b7ee9b8 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Fri, 19 Jun 2015 12:51:50 +0300 Subject: [PATCH 1588/3725] Add Topic/Journal Id completion to InfoCreator --- .../model/world/idcompletionmanager.cpp | 2 ++ apps/opencs/view/world/infocreator.cpp | 21 ++++++++++++++++++- apps/opencs/view/world/infocreator.hpp | 11 +++++++++- apps/opencs/view/world/subviews.cpp | 8 +++---- 4 files changed, 36 insertions(+), 6 deletions(-) diff --git a/apps/opencs/model/world/idcompletionmanager.cpp b/apps/opencs/model/world/idcompletionmanager.cpp index b59987cba..20cd8652c 100644 --- a/apps/opencs/model/world/idcompletionmanager.cpp +++ b/apps/opencs/model/world/idcompletionmanager.cpp @@ -24,6 +24,7 @@ namespace types[CSMWorld::ColumnBase::Display_Faction ] = CSMWorld::UniversalId::Type_Faction; types[CSMWorld::ColumnBase::Display_GlobalVariable ] = CSMWorld::UniversalId::Type_Global; types[CSMWorld::ColumnBase::Display_Icon ] = CSMWorld::UniversalId::Type_Icon; + types[CSMWorld::ColumnBase::Display_Journal ] = CSMWorld::UniversalId::Type_Journal; types[CSMWorld::ColumnBase::Display_Mesh ] = CSMWorld::UniversalId::Type_Mesh; types[CSMWorld::ColumnBase::Display_Miscellaneous ] = CSMWorld::UniversalId::Type_Referenceable; types[CSMWorld::ColumnBase::Display_Npc ] = CSMWorld::UniversalId::Type_Referenceable; @@ -37,6 +38,7 @@ namespace types[CSMWorld::ColumnBase::Display_Spell ] = CSMWorld::UniversalId::Type_Spell; types[CSMWorld::ColumnBase::Display_Static ] = CSMWorld::UniversalId::Type_Referenceable; types[CSMWorld::ColumnBase::Display_Texture ] = CSMWorld::UniversalId::Type_Texture; + types[CSMWorld::ColumnBase::Display_Topic ] = CSMWorld::UniversalId::Type_Topic; types[CSMWorld::ColumnBase::Display_Weapon ] = CSMWorld::UniversalId::Type_Referenceable; return types; diff --git a/apps/opencs/view/world/infocreator.cpp b/apps/opencs/view/world/infocreator.cpp index f88b9f0b9..7b8390900 100644 --- a/apps/opencs/view/world/infocreator.cpp +++ b/apps/opencs/view/world/infocreator.cpp @@ -9,10 +9,13 @@ #include +#include "../../model/doc/document.hpp" + #include "../../model/world/data.hpp" #include "../../model/world/commands.hpp" #include "../../model/world/columns.hpp" #include "../../model/world/idtable.hpp" +#include "../../model/world/idcompletionmanager.hpp" std::string CSVWorld::InfoCreator::getId() const { @@ -39,13 +42,20 @@ void CSVWorld::InfoCreator::configureCreateCommand (CSMWorld::CreateCommand& com } CSVWorld::InfoCreator::InfoCreator (CSMWorld::Data& data, QUndoStack& undoStack, - const CSMWorld::UniversalId& id) + const CSMWorld::UniversalId& id, CSMWorld::IdCompletionManager& completionManager) : GenericCreator (data, undoStack, id) { QLabel *label = new QLabel ("Topic", this); insertBeforeButtons (label, false); mTopic = new QLineEdit (this); + CSMWorld::ColumnBase::Display displayType = CSMWorld::ColumnBase::Display_Topic; + if (id.getType() == CSMWorld::UniversalId::Type_JournalInfo || // For Dialogue SubView + id.getType() == CSMWorld::UniversalId::Type_JournalInfos) // For Table SubView + { + displayType = CSMWorld::ColumnBase::Display_Journal; + } + mTopic->setCompleter(completionManager.getCompleter(displayType).get()); insertBeforeButtons (mTopic, true); setManualEditing (false); @@ -100,3 +110,12 @@ void CSVWorld::InfoCreator::topicChanged() { update(); } + +CSVWorld::Creator *CSVWorld::InfoCreatorFactory::makeCreator(CSMDoc::Document& document, + const CSMWorld::UniversalId& id) const +{ + return new InfoCreator(document.getData(), + document.getUndoStack(), + id, + document.getIdCompletionManager()); +} diff --git a/apps/opencs/view/world/infocreator.hpp b/apps/opencs/view/world/infocreator.hpp index edc12975c..1928004bb 100644 --- a/apps/opencs/view/world/infocreator.hpp +++ b/apps/opencs/view/world/infocreator.hpp @@ -8,6 +8,7 @@ class QLineEdit; namespace CSMWorld { class InfoCollection; + class IdCompletionManager; } namespace CSVWorld @@ -25,7 +26,7 @@ namespace CSVWorld public: InfoCreator (CSMWorld::Data& data, QUndoStack& undoStack, - const CSMWorld::UniversalId& id); + const CSMWorld::UniversalId& id, CSMWorld::IdCompletionManager& completionManager); virtual void cloneMode (const std::string& originId, const CSMWorld::UniversalId::Type type); @@ -43,6 +44,14 @@ namespace CSVWorld void topicChanged(); }; + + class InfoCreatorFactory : public CreatorFactoryBase + { + public: + + virtual Creator *makeCreator (CSMDoc::Document& document, const CSMWorld::UniversalId& id) const; + ///< The ownership of the returned Creator is transferred to the caller. + }; } #endif diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp index fa1b7cdc7..ba3ab1358 100644 --- a/apps/opencs/view/world/subviews.cpp +++ b/apps/opencs/view/world/subviews.cpp @@ -68,10 +68,10 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) new CSVDoc::SubViewFactoryWithCreator); manager.add (CSMWorld::UniversalId::Type_TopicInfos, - new CSVDoc::SubViewFactoryWithCreator >); + new CSVDoc::SubViewFactoryWithCreator); manager.add (CSMWorld::UniversalId::Type_JournalInfos, - new CSVDoc::SubViewFactoryWithCreator >); + new CSVDoc::SubViewFactoryWithCreator); // Subviews for resources tables manager.add (CSMWorld::UniversalId::Type_Meshes, @@ -153,10 +153,10 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) new CSVDoc::SubViewFactoryWithCreator > (false)); manager.add (CSMWorld::UniversalId::Type_JournalInfo, - new CSVDoc::SubViewFactoryWithCreator > (false)); + new CSVDoc::SubViewFactoryWithCreator (false)); manager.add (CSMWorld::UniversalId::Type_TopicInfo, - new CSVDoc::SubViewFactoryWithCreator >(false)); + new CSVDoc::SubViewFactoryWithCreator(false)); manager.add (CSMWorld::UniversalId::Type_Topic, new CSVDoc::SubViewFactoryWithCreator (false)); From e212414bc7825febb7f90b9a0aa47bd3d45f10b3 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Fri, 19 Jun 2015 13:48:58 +0300 Subject: [PATCH 1589/3725] Use an ID parent type as the collection ID in GenericCreator. Fix impossibility of creation/cloning records from Dialogue subviews in Info tables --- apps/opencs/view/world/genericcreator.cpp | 9 +++++++++ apps/opencs/view/world/infocreator.cpp | 3 +-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/world/genericcreator.cpp b/apps/opencs/view/world/genericcreator.cpp index a123e127f..c64109608 100644 --- a/apps/opencs/view/world/genericcreator.cpp +++ b/apps/opencs/view/world/genericcreator.cpp @@ -133,6 +133,15 @@ CSVWorld::GenericCreator::GenericCreator (CSMWorld::Data& data, QUndoStack& undo mClonedType (CSMWorld::UniversalId::Type_None), mScopes (CSMWorld::Scope_Content), mScope (0), mScopeLabel (0), mCloneMode (false) { + // If the collection ID has a parent type, use it instead. + // It will change IDs with Record/SubRecord class (used for creators in Dialogue subviews) + // to IDs with general RecordList class (used for creators in Table subviews). + CSMWorld::UniversalId::Type listParentType = CSMWorld::UniversalId::getParentType(mListId.getType()); + if (listParentType != CSMWorld::UniversalId::Type_None) + { + mListId = listParentType; + } + mLayout = new QHBoxLayout; mLayout->setContentsMargins (0, 0, 0, 0); diff --git a/apps/opencs/view/world/infocreator.cpp b/apps/opencs/view/world/infocreator.cpp index 7b8390900..916427fc2 100644 --- a/apps/opencs/view/world/infocreator.cpp +++ b/apps/opencs/view/world/infocreator.cpp @@ -50,8 +50,7 @@ CSVWorld::InfoCreator::InfoCreator (CSMWorld::Data& data, QUndoStack& undoStack, mTopic = new QLineEdit (this); CSMWorld::ColumnBase::Display displayType = CSMWorld::ColumnBase::Display_Topic; - if (id.getType() == CSMWorld::UniversalId::Type_JournalInfo || // For Dialogue SubView - id.getType() == CSMWorld::UniversalId::Type_JournalInfos) // For Table SubView + if (getCollectionId().getType() == CSMWorld::UniversalId::Type_JournalInfos) { displayType = CSMWorld::ColumnBase::Display_Journal; } From 7a5f220ac52ba29d4cc04f4a88f8afa9206ff398 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 19 Jun 2015 17:43:13 +0200 Subject: [PATCH 1590/3725] GlowTexture keeps the alpha channel from the previous texture stage --- components/nifosg/nifloader.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index c30ac671a..b5439afee 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -1302,8 +1302,13 @@ namespace NifOsg if (i == Nif::NiTexturingProperty::GlowTexture) { - osg::TexEnv* texEnv = new osg::TexEnv; - texEnv->setMode(osg::TexEnv::ADD); + osg::TexEnvCombine* texEnv = new osg::TexEnvCombine; + texEnv->setCombine_Alpha(osg::TexEnvCombine::REPLACE); + texEnv->setSource0_Alpha(osg::TexEnvCombine::PREVIOUS); + texEnv->setCombine_RGB(osg::TexEnvCombine::ADD); + texEnv->setSource0_RGB(osg::TexEnvCombine::PREVIOUS); + texEnv->setSource1_RGB(osg::TexEnvCombine::TEXTURE); + stateset->setTextureAttributeAndModes(texUnit, texEnv, osg::StateAttribute::ON); } else if (i == Nif::NiTexturingProperty::DarkTexture) From 38d90f47a63d8862e1b7ce96ba284e1fec341a18 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 19 Jun 2015 18:15:23 +0200 Subject: [PATCH 1591/3725] Moon fading fix (Bug #2713) --- apps/openmw/mwworld/weather.cpp | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 81497aa6c..70d6f1b36 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -495,8 +495,6 @@ void WeatherManager::update(float duration, bool paused) mRendering->getSkyManager()->setMasserDirection(masser); mRendering->getSkyManager()->setSecundaDirection(secunda); - mRendering->getSkyManager()->masserEnable(); - mRendering->getSkyManager()->secundaEnable(); float angle = (1-moonHeight) * 90.f * facing; float masserHourFade = calculateHourFade("Masser"); @@ -507,8 +505,22 @@ void WeatherManager::update(float duration, bool paused) masserAngleFade *= masserHourFade; secundaAngleFade *= secundaHourFade; - mRendering->getSkyManager()->setMasserFade(masserAngleFade); - mRendering->getSkyManager()->setSecundaFade(secundaAngleFade); + if (masserAngleFade > 0) + { + mRendering->getSkyManager()->setMasserFade(masserAngleFade); + mRendering->getSkyManager()->masserEnable(); + } + else + mRendering->getSkyManager()->masserDisable(); + + if (secundaAngleFade > 0) + { + mRendering->getSkyManager()->setSecundaFade(secundaAngleFade); + mRendering->getSkyManager()->secundaEnable(); + } + else + mRendering->getSkyManager()->secundaDisable(); + } else { From 1ed4e33815cd5a739ebb726ae7b3218292b1e475 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 19 Jun 2015 18:19:52 +0200 Subject: [PATCH 1592/3725] Fading for mooncircle texture --- apps/openmw/mwrender/sky.cpp | 40 +++++++++++++++++++++++++----------- apps/openmw/mwrender/sky.hpp | 4 ---- 2 files changed, 28 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 43ed80dbf..d40ae3549 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -403,6 +403,8 @@ public: { public: MoonUpdater() + : mFade(0.f) + , mMoonColor(1,1,1,1) { } @@ -419,8 +421,9 @@ public: stateset->setTextureAttributeAndModes(1, mCircleTex, osg::StateAttribute::ON); osg::ref_ptr texEnv2 = new osg::TexEnvCombine; texEnv2->setCombine_RGB(osg::TexEnvCombine::ADD); - texEnv2->setCombine_Alpha(osg::TexEnvCombine::REPLACE); + texEnv2->setCombine_Alpha(osg::TexEnvCombine::MODULATE); texEnv2->setSource0_Alpha(osg::TexEnvCombine::TEXTURE); + texEnv2->setSource1_Alpha(osg::TexEnvCombine::CONSTANT); texEnv2->setSource0_RGB(osg::TexEnvCombine::PREVIOUS); texEnv2->setSource1_RGB(osg::TexEnvCombine::CONSTANT); texEnv2->setConstantColor(osg::Vec4f(0.f, 0.f, 0.f, 1.f)); // atmospherecolor @@ -432,12 +435,22 @@ public: virtual void apply(osg::StateSet *stateset, osg::NodeVisitor*) { osg::TexEnvCombine* texEnv = static_cast(stateset->getTextureAttribute(0, osg::StateAttribute::TEXENV)); - texEnv->setConstantColor(mMoonColor); + texEnv->setConstantColor(mMoonColor * mFade); osg::TexEnvCombine* texEnv2 = static_cast(stateset->getTextureAttribute(1, osg::StateAttribute::TEXENV)); - texEnv2->setConstantColor(mAtmosphereColor); + const float backdropFadeThreshold = 0.03; + if (mFade <= backdropFadeThreshold) + { + texEnv2->setConstantColor(osg::Vec4f(mAtmosphereColor.x(), mAtmosphereColor.y(), mAtmosphereColor.z(), mFade / backdropFadeThreshold)); + } + else + texEnv2->setConstantColor(mAtmosphereColor); } + void setFade (const float fade) + { + mFade = fade; + } void setAtmosphereColor(const osg::Vec4f& color) { @@ -457,6 +470,7 @@ public: } private: + float mFade; osg::Vec4f mAtmosphereColor; osg::Vec4f mMoonColor; osg::ref_ptr mPhaseTex; @@ -474,6 +488,11 @@ public: mUpdater->setMoonColor(color); } + void setFade(const float fade) + { + mUpdater->setFade(fade); + } + unsigned int getPhaseInt() const { if (mPhase == Moon::Phase_New) return 0; @@ -497,7 +516,6 @@ SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneMana : mSceneManager(sceneManager) , mAtmosphereNightRoll(0.f) , mCreated(false) - , mMoonRed(false) , mIsStorm(false) , mDay(0) , mMonth(0) @@ -518,8 +536,6 @@ SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneMana , mRainFrequency(1) , mEnabled(true) , mSunEnabled(true) - , mMasserFade(0.f) - , mSecundaFade(0.f) { osg::ref_ptr skyroot (new CameraRelativeTransform); skyroot->setNodeMask(Mask_Sky); @@ -642,9 +658,6 @@ void SkyManager::update(float duration) mMasser->setPhase( static_cast( (int) ((mDay % 32)/4.f)) ); mSecunda->setPhase ( static_cast( (int) ((mDay % 32)/4.f)) ); - mMasser->setColor(osg::Vec4f(mMasserFade,mMasserFade,mMasserFade,1)); - mSecunda->setColor(mMoonRed ? (mMoonScriptColor * mSecundaFade) : osg::Vec4f(mSecundaFade,mSecundaFade,mSecundaFade,1)); - if (mSunEnabled) { // take 1/10 sec for fading the glare effect from invisible to full @@ -692,7 +705,8 @@ void SkyManager::setEnabled(bool enabled) void SkyManager::setMoonColour (bool red) { - mMoonRed = red; + if (!mCreated) return; + mSecunda->setColor(red ? mMoonScriptColor : osg::Vec4f(1,1,1,1)); } void SkyManager::setWeather(const MWWorld::WeatherResult& weather) @@ -915,12 +929,14 @@ void SkyManager::setLightningStrength(const float factor) void SkyManager::setMasserFade(const float fade) { - mMasserFade = fade; + if (!mCreated) return; + mMasser->setFade(fade); } void SkyManager::setSecundaFade(const float fade) { - mSecundaFade = fade; + if (!mCreated) return; + mSecunda->setFade(fade); } void SkyManager::setDate(int day, int month) diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index 8251f39bd..bb4d2e184 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -116,8 +116,6 @@ namespace MWRender bool mCreated; - bool mMoonRed; - bool mIsStorm; int mDay; @@ -156,8 +154,6 @@ namespace MWRender bool mSunEnabled; osg::Vec4f mMoonScriptColor; - float mMasserFade; - float mSecundaFade; }; } From 170692b48004a7ee7ed3a96027d34ef78d110a8f Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Fri, 19 Jun 2015 19:24:06 +0300 Subject: [PATCH 1593/3725] InfoTableProxyModel: invalidate first row cache after row insertion/deletion --- .../model/world/infotableproxymodel.cpp | 19 +++++++++++++------ .../model/world/infotableproxymodel.hpp | 2 +- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/apps/opencs/model/world/infotableproxymodel.cpp b/apps/opencs/model/world/infotableproxymodel.cpp index 7522e492b..5192dfec0 100644 --- a/apps/opencs/model/world/infotableproxymodel.cpp +++ b/apps/opencs/model/world/infotableproxymodel.cpp @@ -15,11 +15,18 @@ void CSMWorld::InfoTableProxyModel::setSourceModel(QAbstractItemModel *sourceMod { IdTableProxyModel::setSourceModel(sourceModel); mSourceModel = dynamic_cast(sourceModel); - connect(mSourceModel, - SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), - this, - SLOT(modelDataChanged(const QModelIndex &, const QModelIndex &))); - mFirstRowCache.clear(); + if (mSourceModel != NULL) + { + connect(mSourceModel, + SIGNAL(rowsInserted(const QModelIndex &, int, int)), + this, + SLOT(modelRowsChanged(const QModelIndex &, int, int))); + connect(mSourceModel, + SIGNAL(rowsRemoved(const QModelIndex &, int, int)), + this, + SLOT(modelRowsChanged(const QModelIndex &, int, int))); + mFirstRowCache.clear(); + } } bool CSMWorld::InfoTableProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const @@ -52,7 +59,7 @@ int CSMWorld::InfoTableProxyModel::getFirstInfoRow(int currentRow) const return currentRow + 1; } -void CSMWorld::InfoTableProxyModel::modelDataChanged(const QModelIndex &/*topLeft*/, const QModelIndex &/*bottomRight*/) +void CSMWorld::InfoTableProxyModel::modelRowsChanged(const QModelIndex &/*parent*/, int /*start*/, int /*end*/) { mFirstRowCache.clear(); } diff --git a/apps/opencs/model/world/infotableproxymodel.hpp b/apps/opencs/model/world/infotableproxymodel.hpp index 322831626..7b0cd8ede 100644 --- a/apps/opencs/model/world/infotableproxymodel.hpp +++ b/apps/opencs/model/world/infotableproxymodel.hpp @@ -31,7 +31,7 @@ namespace CSMWorld virtual bool lessThan(const QModelIndex &left, const QModelIndex &right) const; private slots: - void modelDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight); + void modelRowsChanged(const QModelIndex &parent, int start, int end); }; } From f5c50aa5815b1ed0e5f0bc3eb4f2dfcff01d67ed Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 19 Jun 2015 18:38:44 +0200 Subject: [PATCH 1594/3725] Disable FreezeOnCull for effect particles --- apps/openmw/mwrender/animation.cpp | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 8c1b3c0a9..3801cf6fc 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -10,6 +10,8 @@ #include #include +#include + #include #include @@ -1067,6 +1069,25 @@ namespace MWRender attachTo->addChild(lightSource); } + class DisableFreezeOnCullVisitor : public osg::NodeVisitor + { + public: + DisableFreezeOnCullVisitor() + : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) + { + } + + virtual void apply(osg::Geode &geode) + { + for (unsigned int i=0; i(drw)) + partsys->setFreezeOnCull(false); + } + } + }; + void Animation::addEffect (const std::string& model, int effectId, bool loop, const std::string& bonename, std::string texture) { if (!mObjectRoot.get()) @@ -1099,6 +1120,10 @@ namespace MWRender SceneUtil::FindMaxControllerLengthVisitor findMaxLengthVisitor; node->accept(findMaxLengthVisitor); + // FreezeOnCull doesn't work so well with effect particles, that tend to have moving emitters + DisableFreezeOnCullVisitor disableFreezeOnCullVisitor; + node->accept(disableFreezeOnCullVisitor); + params.mMaxControllerLength = findMaxLengthVisitor.getMaxLength(); node->setNodeMask(Mask_Effect); From 74260a9a44f159827316a1b325c56e0660a3d4af Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 19 Jun 2015 20:30:04 +0200 Subject: [PATCH 1595/3725] Tweak moon sizes --- apps/openmw/mwrender/sky.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index d40ae3549..206249c17 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -574,8 +574,8 @@ void SkyManager::create() mSun.reset(new Sun(mRootNode, mSceneManager)); const MWWorld::Fallback* fallback=MWBase::Environment::get().getWorld()->getFallback(); - mMasser.reset(new Moon(mRootNode, mSceneManager, fallback->getFallbackFloat("Moons_Masser_Size")/100, Moon::Type_Masser)); - mSecunda.reset(new Moon(mRootNode, mSceneManager, fallback->getFallbackFloat("Moons_Secunda_Size")/100, Moon::Type_Secunda)); + mMasser.reset(new Moon(mRootNode, mSceneManager, fallback->getFallbackFloat("Moons_Masser_Size")/125, Moon::Type_Masser)); + mSecunda.reset(new Moon(mRootNode, mSceneManager, fallback->getFallbackFloat("Moons_Secunda_Size")/125, Moon::Type_Secunda)); mCloudNode = new osg::PositionAttitudeTransform; mRootNode->addChild(mCloudNode); From efad4efe1961e823fda5876d0ed7454c925ba24e Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 19 Jun 2015 20:55:04 +0200 Subject: [PATCH 1596/3725] Star fading (Bug #2693) --- apps/openmw/mwrender/sky.cpp | 53 ++++++++++++++++++++++---- apps/openmw/mwrender/sky.hpp | 2 + components/resource/texturemanager.cpp | 5 +++ components/resource/texturemanager.hpp | 2 + 4 files changed, 54 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 206249c17..e2f3dd82b 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -96,7 +96,7 @@ namespace MWRender class AtmosphereUpdater : public SceneUtil::StateSetUpdater { public: - void setEmissionColor(osg::Vec4f emissionColor) + void setEmissionColor(const osg::Vec4f& emissionColor) { mEmissionColor = emissionColor; } @@ -117,6 +117,45 @@ private: osg::Vec4f mEmissionColor; }; +class AtmosphereNightUpdater : public SceneUtil::StateSetUpdater +{ +public: + AtmosphereNightUpdater(Resource::TextureManager* textureManager) + { + // we just need a texture, its contents don't really matter + mTexture = textureManager->getWarningTexture(); + } + + void setFade(const float fade) + { + mColor.a() = fade; + } + +protected: + virtual void setDefaults(osg::StateSet* stateset) + { + osg::ref_ptr texEnv (new osg::TexEnvCombine); + texEnv->setCombine_Alpha(osg::TexEnvCombine::MODULATE); + texEnv->setSource0_Alpha(osg::TexEnvCombine::PREVIOUS); + texEnv->setSource1_Alpha(osg::TexEnvCombine::CONSTANT); + texEnv->setCombine_RGB(osg::TexEnvCombine::REPLACE); + texEnv->setSource0_RGB(osg::TexEnvCombine::PREVIOUS); + + stateset->setTextureAttributeAndModes(1, mTexture, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + stateset->setTextureAttributeAndModes(1, texEnv, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + } + + virtual void apply(osg::StateSet* stateset, osg::NodeVisitor* /*nv*/) + { + osg::TexEnvCombine* texEnv = static_cast(stateset->getTextureAttribute(1, osg::StateAttribute::TEXENV)); + texEnv->setConstantColor(mColor); + } + + osg::ref_ptr mTexture; + + osg::Vec4f mColor; +}; + class CloudUpdater : public SceneUtil::StateSetUpdater { public: @@ -129,7 +168,7 @@ public: { mTexture = texture; } - void setEmissionColor(osg::Vec4f emissionColor) + void setEmissionColor(const osg::Vec4f& emissionColor) { mEmissionColor = emissionColor; } @@ -570,6 +609,8 @@ void SkyManager::create() atmosphereNight->getOrCreateStateSet()->setAttributeAndModes(createAlphaTrackingUnlitMaterial(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); ModVertexAlphaVisitor modStars(2); atmosphereNight->accept(modStars); + mAtmosphereNightUpdater = new AtmosphereNightUpdater(mSceneManager->getTextureManager()); + atmosphereNight->addUpdateCallback(mAtmosphereNightUpdater); mSun.reset(new Sun(mRootNode, mSceneManager)); @@ -806,13 +847,9 @@ void SkyManager::setWeather(const MWWorld::WeatherResult& weather) if (weather.mNight && mStarsOpacity != weather.mNightFade) { - if (weather.mNightFade != 0) - { - //sh::Factory::getInstance().setSharedParameter ("nightFade", - // sh::makeProperty(new sh::FloatValue(weather.mNightFade))); + mStarsOpacity = weather.mNightFade; - //mStarsOpacity = weather.mNightFade; - } + mAtmosphereNightUpdater->setFade(mStarsOpacity); } mAtmosphereNightNode->setNodeMask(weather.mNight ? ~0 : 0); diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index bb4d2e184..b05845e53 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -20,6 +20,7 @@ namespace Resource namespace MWRender { class AtmosphereUpdater; + class AtmosphereNightUpdater; class CloudUpdater; class Sun; class Moon; @@ -107,6 +108,7 @@ namespace MWRender osg::ref_ptr mAtmosphereNightNode; float mAtmosphereNightRoll; + osg::ref_ptr mAtmosphereNightUpdater; osg::ref_ptr mAtmosphereUpdater; diff --git a/components/resource/texturemanager.cpp b/components/resource/texturemanager.cpp index 50cfd9d57..62cbd6bb3 100644 --- a/components/resource/texturemanager.cpp +++ b/components/resource/texturemanager.cpp @@ -145,4 +145,9 @@ namespace Resource } } + osg::Texture2D* TextureManager::getWarningTexture() + { + return mWarningTexture.get(); + } + } diff --git a/components/resource/texturemanager.hpp b/components/resource/texturemanager.hpp index 5ff233348..2ee3baa77 100644 --- a/components/resource/texturemanager.hpp +++ b/components/resource/texturemanager.hpp @@ -38,6 +38,8 @@ namespace Resource const VFS::Manager* getVFS() { return mVFS; } + osg::Texture2D* getWarningTexture(); + private: const VFS::Manager* mVFS; From f1a38ffe930cb2ae13554543095ab0746edaf637 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sat, 20 Jun 2015 11:29:15 +0300 Subject: [PATCH 1597/3725] InfoTableProxyModel: ignore the letter case in the search of the first Topic/Journal row --- .../model/world/infotableproxymodel.cpp | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/apps/opencs/model/world/infotableproxymodel.cpp b/apps/opencs/model/world/infotableproxymodel.cpp index 5192dfec0..2812bae60 100644 --- a/apps/opencs/model/world/infotableproxymodel.cpp +++ b/apps/opencs/model/world/infotableproxymodel.cpp @@ -1,8 +1,18 @@ #include "infotableproxymodel.hpp" +#include + #include "idtablebase.hpp" #include "columns.hpp" +namespace +{ + QString toLower(const QString &str) + { + return Misc::StringUtils::lowerCase(str.toStdString()).c_str(); + } +} + CSMWorld::InfoTableProxyModel::InfoTableProxyModel(CSMWorld::UniversalId::Type type, QObject *parent) : IdTableProxyModel(parent), mType(type), @@ -45,7 +55,7 @@ int CSMWorld::InfoTableProxyModel::getFirstInfoRow(int currentRow) const } int column = mSourceModel->findColumnIndex(columnId); - QString info = mSourceModel->data(mSourceModel->index(currentRow, column)).toString(); + QString info = toLower(mSourceModel->data(mSourceModel->index(currentRow, column)).toString()); if (mFirstRowCache.contains(info)) { @@ -53,10 +63,11 @@ int CSMWorld::InfoTableProxyModel::getFirstInfoRow(int currentRow) const } while (--currentRow >= 0 && - mSourceModel->data(mSourceModel->index(currentRow, column)) == info); + toLower(mSourceModel->data(mSourceModel->index(currentRow, column)).toString()) == info); + ++currentRow; - mFirstRowCache[info] = currentRow + 1; - return currentRow + 1; + mFirstRowCache[info] = currentRow; + return currentRow; } void CSMWorld::InfoTableProxyModel::modelRowsChanged(const QModelIndex &/*parent*/, int /*start*/, int /*end*/) From 8aba52170f000c47960bbe854481c58a1050a6fd Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 20 Jun 2015 11:34:32 +0200 Subject: [PATCH 1598/3725] fixed a build error --- apps/opencs/view/world/creator.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/opencs/view/world/creator.hpp b/apps/opencs/view/world/creator.hpp index b2d80cf2f..b76348199 100644 --- a/apps/opencs/view/world/creator.hpp +++ b/apps/opencs/view/world/creator.hpp @@ -5,6 +5,8 @@ #include +#include "../../model/doc/document.hpp" + #include "../../model/world/scope.hpp" #include "../../model/world/universalid.hpp" From ced4e237a8e3c7069ebe769c0fea3fe2585d7e30 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sat, 20 Jun 2015 12:43:53 +0300 Subject: [PATCH 1599/3725] Fix the sorting of Info tables when new row are added --- apps/opencs/model/world/infotableproxymodel.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/apps/opencs/model/world/infotableproxymodel.cpp b/apps/opencs/model/world/infotableproxymodel.cpp index 2812bae60..3e564506c 100644 --- a/apps/opencs/model/world/infotableproxymodel.cpp +++ b/apps/opencs/model/world/infotableproxymodel.cpp @@ -43,6 +43,12 @@ bool CSMWorld::InfoTableProxyModel::lessThan(const QModelIndex &left, const QMod { QModelIndex first = mSourceModel->index(getFirstInfoRow(left.row()), left.column()); QModelIndex second = mSourceModel->index(getFirstInfoRow(right.row()), right.column()); + + // If both indexes are belonged to the same Topic/Journal, compare their original rows only + if (first.row() == second.row()) + { + return sortOrder() == Qt::AscendingOrder ? left.row() < right.row() : right.row() < left.row(); + } return IdTableProxyModel::lessThan(first, second); } From 1ee1934053e389f2e18f1c1e7bb67b1d239854c7 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 20 Jun 2015 14:21:52 +0200 Subject: [PATCH 1600/3725] framework for accessing user settings in operation stages --- apps/opencs/model/doc/operation.cpp | 32 ++++++++++++++++++++--- apps/opencs/model/doc/operation.hpp | 11 ++++++++ apps/opencs/model/doc/operationholder.cpp | 5 ++++ apps/opencs/model/doc/stage.cpp | 2 ++ apps/opencs/model/doc/stage.hpp | 5 ++++ 5 files changed, 52 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/doc/operation.cpp b/apps/opencs/model/doc/operation.cpp index 3f1674f50..4a39d2911 100644 --- a/apps/opencs/model/doc/operation.cpp +++ b/apps/opencs/model/doc/operation.cpp @@ -7,6 +7,7 @@ #include #include "../world/universalid.hpp" +#include "../settings/usersettings.hpp" #include "state.hpp" #include "stage.hpp" @@ -23,13 +24,16 @@ void CSMDoc::Operation::prepareStages() { iter->second = iter->first->setup(); mTotalSteps += iter->second; + + for (std::map::const_iterator iter2 (mSettings.begin()); iter2!=mSettings.end(); ++iter2) + iter->first->updateUserSetting (iter2->first, iter2->second); } } CSMDoc::Operation::Operation (int type, bool ordered, bool finalAlways) : mType (type), mStages(std::vector >()), mCurrentStage(mStages.begin()), mCurrentStep(0), mCurrentStepTotal(0), mTotalSteps(0), mOrdered (ordered), - mFinalAlways (finalAlways), mError(false), mConnected (false) + mFinalAlways (finalAlways), mError(false), mConnected (false), mPrepared (false) { mTimer = new QTimer (this); } @@ -49,8 +53,8 @@ void CSMDoc::Operation::run() connect (mTimer, SIGNAL (timeout()), this, SLOT (executeStage())); mConnected = true; } - - prepareStages(); + + mPrepared = false; mTimer->start (0); } @@ -60,6 +64,14 @@ void CSMDoc::Operation::appendStage (Stage *stage) mStages.push_back (std::make_pair (stage, 0)); } +void CSMDoc::Operation::configureSettings (const std::vector& settings) +{ + for (std::vector::const_iterator iter (settings.begin()); iter!=settings.end(); ++iter) + { + mSettings.insert (std::make_pair (*iter, CSMSettings::UserSettings::instance().definitions (*iter))); + } +} + bool CSMDoc::Operation::hasError() const { return mError; @@ -84,8 +96,22 @@ void CSMDoc::Operation::abort() mCurrentStage = mStages.end(); } +void CSMDoc::Operation::updateUserSetting (const QString& name, const QStringList& value) +{ + std::map::iterator iter = mSettings.find (name); + + if (iter!=mSettings.end()) + iter->second = value; +} + void CSMDoc::Operation::executeStage() { + if (!mPrepared) + { + prepareStages(); + mPrepared = true; + } + Messages messages; while (mCurrentStage!=mStages.end()) diff --git a/apps/opencs/model/doc/operation.hpp b/apps/opencs/model/doc/operation.hpp index a6217fe2d..6d6ed112b 100644 --- a/apps/opencs/model/doc/operation.hpp +++ b/apps/opencs/model/doc/operation.hpp @@ -2,9 +2,11 @@ #define CSM_DOC_OPERATION_H #include +#include #include #include +#include namespace CSMWorld { @@ -30,6 +32,8 @@ namespace CSMDoc bool mError; bool mConnected; QTimer *mTimer; + std::map mSettings; + bool mPrepared; void prepareStages(); @@ -46,6 +50,11 @@ namespace CSMDoc /// /// \attention Do no call this function while this Operation is running. + /// Specify settings to be passed on to stages. + /// + /// \attention Do no call this function while this Operation is running. + void configureSettings (const std::vector& settings); + bool hasError() const; signals: @@ -63,6 +72,8 @@ namespace CSMDoc void run(); + void updateUserSetting (const QString& name, const QStringList& value); + private slots: void executeStage(); diff --git a/apps/opencs/model/doc/operationholder.cpp b/apps/opencs/model/doc/operationholder.cpp index d79e14023..5157fd80c 100644 --- a/apps/opencs/model/doc/operationholder.cpp +++ b/apps/opencs/model/doc/operationholder.cpp @@ -1,6 +1,8 @@ #include "operationholder.hpp" +#include "../settings/usersettings.hpp" + #include "operation.hpp" CSMDoc::OperationHolder::OperationHolder (Operation *operation) : mRunning (false) @@ -29,6 +31,9 @@ void CSMDoc::OperationHolder::setOperation (Operation *operation) connect (this, SIGNAL (abortSignal()), mOperation, SLOT (abort())); connect (&mThread, SIGNAL (started()), mOperation, SLOT (run())); + + connect (&CSMSettings::UserSettings::instance(), SIGNAL (userSettingUpdated (const QString&, const QStringList&)), + mOperation, SLOT (updateUserSetting (const QString&, const QStringList&))); } bool CSMDoc::OperationHolder::isRunning() const diff --git a/apps/opencs/model/doc/stage.cpp b/apps/opencs/model/doc/stage.cpp index 1a2c5c721..78aa14574 100644 --- a/apps/opencs/model/doc/stage.cpp +++ b/apps/opencs/model/doc/stage.cpp @@ -2,3 +2,5 @@ #include "stage.hpp" CSMDoc::Stage::~Stage() {} + +void CSMDoc::Stage::updateUserSetting (const QString& name, const QStringList& value) {} diff --git a/apps/opencs/model/doc/stage.hpp b/apps/opencs/model/doc/stage.hpp index 126823ae9..e0328a91a 100644 --- a/apps/opencs/model/doc/stage.hpp +++ b/apps/opencs/model/doc/stage.hpp @@ -8,6 +8,8 @@ #include "messages.hpp" +class QString; + namespace CSMDoc { class Stage @@ -21,6 +23,9 @@ namespace CSMDoc virtual void perform (int stage, Messages& messages) = 0; ///< Messages resulting from this stage will be appended to \a messages. + + /// Default-implementation: ignore + virtual void updateUserSetting (const QString& name, const QStringList& value); }; } From 9a102f81c8e7956e85c8f7599c2293c76f579a32 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 20 Jun 2015 16:21:04 +0200 Subject: [PATCH 1601/3725] added setting for controlling script compiler warnings --- apps/opencs/model/settings/usersettings.cpp | 16 +++++++++++++++- apps/opencs/model/tools/scriptcheck.cpp | 20 +++++++++++++++++++- apps/opencs/model/tools/scriptcheck.hpp | 10 ++++++++++ apps/opencs/model/tools/tools.cpp | 5 +++++ 4 files changed, 49 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/settings/usersettings.cpp b/apps/opencs/model/settings/usersettings.cpp index d1dddf8ba..78db5313b 100644 --- a/apps/opencs/model/settings/usersettings.cpp +++ b/apps/opencs/model/settings/usersettings.cpp @@ -293,7 +293,7 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() autoDelete->setDefaultValue ("true"); } - declareSection ("script-editor", "Script Editor"); + declareSection ("script-editor", "Scripts"); { Setting *lineNum = createSetting (Type_CheckBox, "show-linenum", "Show Line Numbers"); lineNum->setDefaultValue ("true"); @@ -312,6 +312,20 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() "\nA name from the list of colors defined in the list of SVG color keyword names." "\nX11 color names may also work."; + QString modeIgnore ("Ignore"); + + QStringList modes; + modes << modeIgnore << "Strict"; + + Setting *warnings = createSetting (Type_ComboBox, "warnings", + "Warning Mode"); + warnings->setDeclaredValues (modes); + warnings->setDefaultValue (modeIgnore); + warnings->setToolTip ("

    How to handle warning messages during compilation:

    " + "

  • Ignore: Do not report warning
  • " + "
  • Strict: Promote warning to an error
  • " + "
"); + Setting *formatInt = createSetting (Type_LineEdit, "colour-int", "Highlight Colour: Int"); formatInt->setDefaultValues (QStringList() << "Dark magenta"); formatInt->setToolTip ("(Default: Green) Use one of the following formats:" + tooltip); diff --git a/apps/opencs/model/tools/scriptcheck.cpp b/apps/opencs/model/tools/scriptcheck.cpp index a70ee2ae4..33922e9cf 100644 --- a/apps/opencs/model/tools/scriptcheck.cpp +++ b/apps/opencs/model/tools/scriptcheck.cpp @@ -44,7 +44,7 @@ void CSMTools::ScriptCheckStage::report (const std::string& message, Type type) } CSMTools::ScriptCheckStage::ScriptCheckStage (const CSMDoc::Document& document) -: mDocument (document), mContext (document.getData()), mMessages (0) +: mDocument (document), mContext (document.getData()), mMessages (0), mWarningMode (Mode_Ignore) { /// \todo add an option to configure warning mode setWarningsMode (0); @@ -58,6 +58,7 @@ int CSMTools::ScriptCheckStage::setup() mContext.clear(); mMessages = 0; mId.clear(); + Compiler::ErrorHandler::reset(); return mDocument.getData().getScripts().getSize(); } @@ -72,6 +73,12 @@ void CSMTools::ScriptCheckStage::perform (int stage, CSMDoc::Messages& messages) mMessages = &messages; + switch (mWarningMode) + { + case Mode_Ignore: setWarningsMode (0); break; + case Mode_Strict: setWarningsMode (1); break; + } + try { const CSMWorld::Data& data = mDocument.getData(); @@ -99,3 +106,14 @@ void CSMTools::ScriptCheckStage::perform (int stage, CSMDoc::Messages& messages) mMessages = 0; } + +void CSMTools::ScriptCheckStage::updateUserSetting (const QString& name, const QStringList& value) +{ + if (name=="script-editor/warnings") + { + if (value.at (0)=="Ignore") + mWarningMode = Mode_Ignore; + else if (value.at (0)=="Strict") + mWarningMode = Mode_Strict; + } +} diff --git a/apps/opencs/model/tools/scriptcheck.hpp b/apps/opencs/model/tools/scriptcheck.hpp index 3fe12fc9a..0d42b275c 100644 --- a/apps/opencs/model/tools/scriptcheck.hpp +++ b/apps/opencs/model/tools/scriptcheck.hpp @@ -18,13 +18,21 @@ namespace CSMTools /// \brief VerifyStage: make sure that scripts compile class ScriptCheckStage : public CSMDoc::Stage, private Compiler::ErrorHandler { + enum WarningMode + { + Mode_Ignore, + Mode_Strict + }; + const CSMDoc::Document& mDocument; Compiler::Extensions mExtensions; CSMWorld::ScriptContext mContext; std::string mId; std::string mFile; CSMDoc::Messages *mMessages; + WarningMode mWarningMode; + virtual void report (const std::string& message, const Compiler::TokenLoc& loc, Type type); ///< Report error to the user. @@ -40,6 +48,8 @@ namespace CSMTools virtual void perform (int stage, CSMDoc::Messages& messages); ///< Messages resulting from this tage will be appended to \a messages. + + virtual void updateUserSetting (const QString& name, const QStringList& value); }; } diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index 7d70abae5..fda373bcf 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -51,6 +51,11 @@ CSMDoc::OperationHolder *CSMTools::Tools::getVerifier() { mVerifierOperation = new CSMDoc::Operation (CSMDoc::State_Verifying, false); + std::vector settings; + settings.push_back ("script-editor/warnings"); + + mVerifierOperation->configureSettings (settings); + connect (&mVerifier, SIGNAL (progress (int, int, int)), this, SIGNAL (progress (int, int, int))); connect (&mVerifier, SIGNAL (done (int, bool)), this, SIGNAL (done (int, bool))); connect (&mVerifier, From 27ece7f36aec12f14987227b37a3af45b1f7e81b Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sat, 20 Jun 2015 17:33:36 +0300 Subject: [PATCH 1602/3725] Rework DropLineEdit. Make it type-sensitive --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/view/widget/droplineedit.cpp | 82 +++++++++++++++++++ apps/opencs/view/widget/droplineedit.hpp | 50 +++++++++++ apps/opencs/view/world/dialoguesubview.cpp | 5 +- .../view/world/idcompletiondelegate.cpp | 4 +- apps/opencs/view/world/util.cpp | 31 +------ apps/opencs/view/world/util.hpp | 19 ----- 7 files changed, 143 insertions(+), 50 deletions(-) create mode 100644 apps/opencs/view/widget/droplineedit.cpp create mode 100644 apps/opencs/view/widget/droplineedit.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index d86798af9..fa703e497 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -75,7 +75,7 @@ opencs_units_noqt (view/world opencs_units (view/widget scenetoolbar scenetool scenetoolmode pushbutton scenetooltoggle scenetoolrun modebutton - scenetooltoggle2 completerpopup coloreditor colorpickerpopup + scenetooltoggle2 completerpopup coloreditor colorpickerpopup droplineedit ) opencs_units (view/render diff --git a/apps/opencs/view/widget/droplineedit.cpp b/apps/opencs/view/widget/droplineedit.cpp new file mode 100644 index 000000000..0b2ac6381 --- /dev/null +++ b/apps/opencs/view/widget/droplineedit.cpp @@ -0,0 +1,82 @@ +#include "droplineedit.hpp" + +#include + +#include "../../model/world/tablemimedata.hpp" + +namespace +{ + const CSMWorld::TableMimeData *getEventMimeData(QDropEvent *event) + { + Q_ASSERT(event != NULL); + return dynamic_cast(event->mimeData()); + } +} + +CSVWidget::DropLineEdit::DropLineEdit(QWidget *parent, CSMWorld::UniversalId::Type type) + : QLineEdit(parent), + mDropType(type) +{ + setAcceptDrops(true); +} + +void CSVWidget::DropLineEdit::dragEnterEvent(QDragEnterEvent *event) +{ + if (canAcceptEventData(event)) + { + event->acceptProposedAction(); + } +} + +void CSVWidget::DropLineEdit::dragMoveEvent(QDragMoveEvent *event) +{ + if (canAcceptEventData(event)) + { + event->accept(); + } +} + +void CSVWidget::DropLineEdit::dropEvent(QDropEvent *event) +{ + const CSMWorld::TableMimeData *data = getEventMimeData(event); + if (data == NULL) // May happen when non-records (e.g. plain text) are dragged and dropped + { + return; + } + + int dataIndex = getAcceptedDataIndex(*data); + if (dataIndex != -1) + { + setText(data->getData()[dataIndex].getId().c_str()); + emit tableMimeDataDropped(data->getData(), data->getDocumentPtr()); + } +} + +bool CSVWidget::DropLineEdit::canAcceptEventData(QDropEvent *event) const +{ + const CSMWorld::TableMimeData *data = getEventMimeData(event); + if (data == NULL) // May happen when non-records (e.g. plain text) are dragged and dropped + { + return false; + } + return getAcceptedDataIndex(*data) != -1; +} + +int CSVWidget::DropLineEdit::getAcceptedDataIndex(const CSMWorld::TableMimeData &data) const +{ + if (mDropType == CSMWorld::UniversalId::Type_None) + { + return 0; + } + + std::vector idData = data.getData(); + int size = static_cast(idData.size()); + for (int i = 0; i < size; ++i) + { + if (idData[i].getType() == mDropType) + { + return i; + } + } + return -1; +} diff --git a/apps/opencs/view/widget/droplineedit.hpp b/apps/opencs/view/widget/droplineedit.hpp new file mode 100644 index 000000000..e49c947b4 --- /dev/null +++ b/apps/opencs/view/widget/droplineedit.hpp @@ -0,0 +1,50 @@ +#ifndef CSV_WIDGET_DROPLINEEDIT_HPP +#define CSV_WIDGET_DROPLINEEDIT_HPP + +#include + +#include "../../model/world/universalid.hpp" + +namespace CSMDoc +{ + class Document; +} + +namespace CSMWorld +{ + class TableMimeData; +} + +namespace CSVWidget +{ + class DropLineEdit : public QLineEdit + { + Q_OBJECT + + CSMWorld::UniversalId::Type mDropType; + ///< The accepted ID type for this LineEdit. + ///< If \a mDropType has Type_None type, this LineEdit accepts all ID types + + bool canAcceptEventData(QDropEvent *event) const; + ///< Checks whether the \a event contains CSMWorld::TableMimeData with a proper ID type + + int getAcceptedDataIndex(const CSMWorld::TableMimeData &data) const; + ///< Checks whether the \a data has a proper type + ///< \return -1 if there is no suitable data (ID type) + + public: + DropLineEdit(QWidget *parent = 0, + CSMWorld::UniversalId::Type type = CSMWorld::UniversalId::Type_None); + + protected: + void dragEnterEvent(QDragEnterEvent *event); + void dragMoveEvent(QDragMoveEvent *event); + void dropEvent(QDropEvent *event); + + signals: + void tableMimeDataDropped(const std::vector &data, + const CSMDoc::Document *document); + }; +} + +#endif diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 5d9eda3f2..a1dbc902e 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -34,6 +34,7 @@ #include "../../model/doc/document.hpp" #include "../widget/coloreditor.hpp" +#include "../widget/droplineedit.hpp" #include "recordstatusdelegate.hpp" #include "util.hpp" @@ -306,7 +307,7 @@ QWidget* CSVWorld::DialogueDelegateDispatcher::makeEditor(CSMWorld::ColumnBase:: // NOTE: For each entry in CSVWorld::CommandDelegate::createEditor() a corresponding entry // is required here - if (qobject_cast(editor)) + if (qobject_cast(editor)) { connect(editor, SIGNAL(editingFinished()), proxy, SLOT(editorDataCommited())); @@ -850,7 +851,7 @@ void CSVWorld::DialogueSubView::tableMimeDataDropped (QWidget* editor, { if (document == &mDocument) { - qobject_cast(editor)->setText(id.getId().c_str()); + qobject_cast(editor)->setText(id.getId().c_str()); } } diff --git a/apps/opencs/view/world/idcompletiondelegate.cpp b/apps/opencs/view/world/idcompletiondelegate.cpp index 056026471..5c92e6576 100644 --- a/apps/opencs/view/world/idcompletiondelegate.cpp +++ b/apps/opencs/view/world/idcompletiondelegate.cpp @@ -2,6 +2,8 @@ #include "../../model/world/idcompletionmanager.hpp" +#include "../widget/droplineedit.hpp" + CSVWorld::IdCompletionDelegate::IdCompletionDelegate(CSMWorld::CommandDispatcher *dispatcher, CSMDoc::Document& document, QObject *parent) @@ -26,7 +28,7 @@ QWidget *CSVWorld::IdCompletionDelegate::createEditor(QWidget *parent, } CSMWorld::IdCompletionManager &completionManager = getDocument().getIdCompletionManager(); - DropLineEdit *editor = new DropLineEdit(parent); + CSVWidget::DropLineEdit *editor = new CSVWidget::DropLineEdit(parent); editor->setCompleter(completionManager.getCompleter(display).get()); return editor; } diff --git a/apps/opencs/view/world/util.cpp b/apps/opencs/view/world/util.cpp index 5974987c0..684327fc2 100644 --- a/apps/opencs/view/world/util.cpp +++ b/apps/opencs/view/world/util.cpp @@ -17,7 +17,10 @@ #include "../../model/world/commands.hpp" #include "../../model/world/tablemimedata.hpp" #include "../../model/world/commanddispatcher.hpp" + #include "../widget/coloreditor.hpp" +#include "../widget/droplineedit.hpp" + #include "dialoguespinbox.hpp" #include "scriptedit.hpp" @@ -250,7 +253,7 @@ QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleO case CSMWorld::ColumnBase::Display_Video: case CSMWorld::ColumnBase::Display_GlobalVariable: - return new DropLineEdit(parent); + return new CSVWidget::DropLineEdit(parent); case CSMWorld::ColumnBase::Display_ScriptLines: @@ -324,29 +327,3 @@ void CSVWorld::CommandDelegate::setEditorData (QWidget *editor, const QModelInde } } - -CSVWorld::DropLineEdit::DropLineEdit(QWidget* parent) : -QLineEdit(parent) -{ - setAcceptDrops(true); -} - -void CSVWorld::DropLineEdit::dragEnterEvent(QDragEnterEvent *event) -{ - event->acceptProposedAction(); -} - -void CSVWorld::DropLineEdit::dragMoveEvent(QDragMoveEvent *event) -{ - event->accept(); -} - -void CSVWorld::DropLineEdit::dropEvent(QDropEvent *event) -{ - const CSMWorld::TableMimeData* data(dynamic_cast(event->mimeData())); - if (!data) // May happen when non-records (e.g. plain text) are dragged and dropped - return; - - emit tableMimeDataDropped(data->getData(), data->getDocumentPtr()); - //WIP -} diff --git a/apps/opencs/view/world/util.hpp b/apps/opencs/view/world/util.hpp index 8355e971c..d695be0d7 100644 --- a/apps/opencs/view/world/util.hpp +++ b/apps/opencs/view/world/util.hpp @@ -5,7 +5,6 @@ #include #include -#include #include "../../model/world/columnbase.hpp" #include "../../model/doc/document.hpp" @@ -91,24 +90,6 @@ namespace CSVWorld }; - class DropLineEdit : public QLineEdit - { - Q_OBJECT - - public: - DropLineEdit(QWidget *parent); - - private: - void dragEnterEvent(QDragEnterEvent *event); - - void dragMoveEvent(QDragMoveEvent *event); - - void dropEvent(QDropEvent *event); - - signals: - void tableMimeDataDropped(const std::vector& data, const CSMDoc::Document* document); - }; - ///< \brief Use commands instead of manipulating the model directly class CommandDelegate : public QStyledItemDelegate { From 0e21c61297d8775740386634e28f60f51ee7dbe2 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 20 Jun 2015 16:55:34 +0200 Subject: [PATCH 1603/3725] replaced redundant CSMTools::ReportModel::Line struct with CSMDoc::Message struct --- apps/opencs/model/doc/messages.cpp | 13 +++++++------ apps/opencs/model/doc/messages.hpp | 18 ++++++++++++------ apps/opencs/model/tools/reportmodel.cpp | 9 ++------- apps/opencs/model/tools/reportmodel.hpp | 14 +++----------- 4 files changed, 24 insertions(+), 30 deletions(-) diff --git a/apps/opencs/model/doc/messages.cpp b/apps/opencs/model/doc/messages.cpp index 9b295fb28..3c709683e 100644 --- a/apps/opencs/model/doc/messages.cpp +++ b/apps/opencs/model/doc/messages.cpp @@ -1,15 +1,16 @@ #include "messages.hpp" +CSMDoc::Message::Message (const CSMWorld::UniversalId& id, const std::string& message, + const std::string& hint) +: mId (id), mMessage (message), mHint (hint) +{} + + void CSMDoc::Messages::add (const CSMWorld::UniversalId& id, const std::string& message, const std::string& hint) { - Message data; - data.mId = id; - data.mMessage = message; - data.mHint = hint; - - mMessages.push_back (data); + mMessages.push_back (Message (id, message, hint)); } void CSMDoc::Messages::push_back (const std::pair& data) diff --git a/apps/opencs/model/doc/messages.hpp b/apps/opencs/model/doc/messages.hpp index 0f36c73a7..4e143d869 100644 --- a/apps/opencs/model/doc/messages.hpp +++ b/apps/opencs/model/doc/messages.hpp @@ -8,16 +8,22 @@ namespace CSMDoc { + struct Message + { + CSMWorld::UniversalId mId; + std::string mMessage; + std::string mHint; + + Message (const CSMWorld::UniversalId& id, const std::string& message, + const std::string& hint); + }; + class Messages { public: - struct Message - { - CSMWorld::UniversalId mId; - std::string mMessage; - std::string mHint; - }; + // \deprecated Use CSMDoc::Message directly instead. + typedef CSMDoc::Message Message; typedef std::vector Collection; diff --git a/apps/opencs/model/tools/reportmodel.cpp b/apps/opencs/model/tools/reportmodel.cpp index 1248e202b..e661e9eac 100644 --- a/apps/opencs/model/tools/reportmodel.cpp +++ b/apps/opencs/model/tools/reportmodel.cpp @@ -6,11 +6,6 @@ #include "../world/columns.hpp" -CSMTools::ReportModel::Line::Line (const CSMWorld::UniversalId& id, const std::string& message, - const std::string& hint) -: mId (id), mMessage (message), mHint (hint) -{} - CSMTools::ReportModel::ReportModel (bool fieldColumn) { if (fieldColumn) @@ -137,14 +132,14 @@ void CSMTools::ReportModel::add (const CSMWorld::UniversalId& id, const std::str { beginInsertRows (QModelIndex(), mRows.size(), mRows.size()); - mRows.push_back (Line (id, message, hint)); + mRows.push_back (CSMDoc::Message (id, message, hint)); endInsertRows(); } void CSMTools::ReportModel::flagAsReplaced (int index) { - Line& line = mRows.at (index); + CSMDoc::Message& line = mRows.at (index); std::string hint = line.mHint; if (hint.empty() || hint[0]!='R') diff --git a/apps/opencs/model/tools/reportmodel.hpp b/apps/opencs/model/tools/reportmodel.hpp index 4d2d0542f..ff20f74a5 100644 --- a/apps/opencs/model/tools/reportmodel.hpp +++ b/apps/opencs/model/tools/reportmodel.hpp @@ -6,6 +6,8 @@ #include +#include "../doc/messages.hpp" + #include "../world/universalid.hpp" namespace CSMTools @@ -14,17 +16,7 @@ namespace CSMTools { Q_OBJECT - struct Line - { - Line (const CSMWorld::UniversalId& id, const std::string& message, - const std::string& hint); - - CSMWorld::UniversalId mId; - std::string mMessage; - std::string mHint; - }; - - std::vector mRows; + std::vector mRows; // Fixed columns enum Columns From ad6764fa6aebd377117921bbc945340cd59e179d Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 20 Jun 2015 17:08:46 +0200 Subject: [PATCH 1604/3725] Fix bug #2715 --- apps/openmw/mwrender/renderingmanager.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 719ee6ebc..2189f185b 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -351,9 +351,11 @@ namespace MWRender void RenderingManager::update(float dt, bool paused) { if (!paused) + { mEffectManager->update(dt); + mSky->update(dt); + } - mSky->update(dt); mWater->update(dt); mCamera->update(dt, paused); From 64701b273d041411bc75caaf9527ea2183ee6679 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sat, 20 Jun 2015 18:29:31 +0300 Subject: [PATCH 1605/3725] LineEdits for ID values accept drops with a proper type --- apps/opencs/view/widget/droplineedit.cpp | 9 ++++++++- apps/opencs/view/widget/droplineedit.hpp | 5 +++-- apps/opencs/view/world/idcompletiondelegate.cpp | 2 +- apps/opencs/view/world/util.cpp | 2 +- 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/apps/opencs/view/widget/droplineedit.cpp b/apps/opencs/view/widget/droplineedit.cpp index 0b2ac6381..f3500dcd2 100644 --- a/apps/opencs/view/widget/droplineedit.cpp +++ b/apps/opencs/view/widget/droplineedit.cpp @@ -13,13 +13,20 @@ namespace } } -CSVWidget::DropLineEdit::DropLineEdit(QWidget *parent, CSMWorld::UniversalId::Type type) +CSVWidget::DropLineEdit::DropLineEdit(CSMWorld::UniversalId::Type type, QWidget *parent) : QLineEdit(parent), mDropType(type) { setAcceptDrops(true); } +CSVWidget::DropLineEdit::DropLineEdit(CSMWorld::ColumnBase::Display display, QWidget *parent) + : QLineEdit(parent), + mDropType(CSMWorld::TableMimeData::convertEnums(display)) +{ + setAcceptDrops(true); +} + void CSVWidget::DropLineEdit::dragEnterEvent(QDragEnterEvent *event) { if (canAcceptEventData(event)) diff --git a/apps/opencs/view/widget/droplineedit.hpp b/apps/opencs/view/widget/droplineedit.hpp index e49c947b4..7ba0513cc 100644 --- a/apps/opencs/view/widget/droplineedit.hpp +++ b/apps/opencs/view/widget/droplineedit.hpp @@ -3,6 +3,7 @@ #include +#include "../../model/world/columnbase.hpp" #include "../../model/world/universalid.hpp" namespace CSMDoc @@ -33,8 +34,8 @@ namespace CSVWidget ///< \return -1 if there is no suitable data (ID type) public: - DropLineEdit(QWidget *parent = 0, - CSMWorld::UniversalId::Type type = CSMWorld::UniversalId::Type_None); + DropLineEdit(CSMWorld::UniversalId::Type type, QWidget *parent = 0); + DropLineEdit(CSMWorld::ColumnBase::Display display, QWidget *parent = 0); protected: void dragEnterEvent(QDragEnterEvent *event); diff --git a/apps/opencs/view/world/idcompletiondelegate.cpp b/apps/opencs/view/world/idcompletiondelegate.cpp index 5c92e6576..970490828 100644 --- a/apps/opencs/view/world/idcompletiondelegate.cpp +++ b/apps/opencs/view/world/idcompletiondelegate.cpp @@ -28,7 +28,7 @@ QWidget *CSVWorld::IdCompletionDelegate::createEditor(QWidget *parent, } CSMWorld::IdCompletionManager &completionManager = getDocument().getIdCompletionManager(); - CSVWidget::DropLineEdit *editor = new CSVWidget::DropLineEdit(parent); + CSVWidget::DropLineEdit *editor = new CSVWidget::DropLineEdit(display, parent); editor->setCompleter(completionManager.getCompleter(display).get()); return editor; } diff --git a/apps/opencs/view/world/util.cpp b/apps/opencs/view/world/util.cpp index 684327fc2..d3969dad4 100644 --- a/apps/opencs/view/world/util.cpp +++ b/apps/opencs/view/world/util.cpp @@ -253,7 +253,7 @@ QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleO case CSMWorld::ColumnBase::Display_Video: case CSMWorld::ColumnBase::Display_GlobalVariable: - return new CSVWidget::DropLineEdit(parent); + return new CSVWidget::DropLineEdit(CSMWorld::UniversalId::Type_None, parent); case CSMWorld::ColumnBase::Display_ScriptLines: From 8791832c865b01f1d32f6b49d76febdb99caf8e2 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 20 Jun 2015 17:56:42 +0200 Subject: [PATCH 1606/3725] standarised on the use of the Message struct when passing operations messages around --- apps/opencs/main.cpp | 3 +++ apps/opencs/model/doc/document.cpp | 9 ++++----- apps/opencs/model/doc/document.hpp | 3 +-- apps/opencs/model/doc/loader.cpp | 3 ++- apps/opencs/model/doc/messages.cpp | 2 ++ apps/opencs/model/doc/messages.hpp | 6 ++++++ apps/opencs/model/doc/operation.cpp | 4 ++-- apps/opencs/model/doc/operation.hpp | 5 +++-- apps/opencs/model/doc/operationholder.cpp | 4 ++-- apps/opencs/model/doc/operationholder.hpp | 5 +++-- apps/opencs/model/tools/reportmodel.cpp | 5 ++--- apps/opencs/model/tools/reportmodel.hpp | 3 +-- apps/opencs/model/tools/tools.cpp | 15 ++++++--------- apps/opencs/model/tools/tools.hpp | 3 +-- 14 files changed, 38 insertions(+), 32 deletions(-) diff --git a/apps/opencs/main.cpp b/apps/opencs/main.cpp index b11561c13..ce434fc43 100644 --- a/apps/opencs/main.cpp +++ b/apps/opencs/main.cpp @@ -13,6 +13,8 @@ #include +#include "model/doc/messages.hpp" + #include "model/world/universalid.hpp" #ifdef Q_OS_MAC @@ -52,6 +54,7 @@ int main(int argc, char *argv[]) qRegisterMetaType ("std::string"); qRegisterMetaType ("CSMWorld::UniversalId"); + qRegisterMetaType ("CSMDoc::Message"); OgreInit::OgreInit ogreInit; diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index b833b527f..1e6ae5455 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -2304,8 +2304,8 @@ CSMDoc::Document::Document (const Files::ConfigurationManager& configuration, connect (&mSaving, SIGNAL (done (int, bool)), this, SLOT (operationDone (int, bool))); connect ( - &mSaving, SIGNAL (reportMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int)), - this, SLOT (reportMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int))); + &mSaving, SIGNAL (reportMessage (const CSMDoc::Message&, int)), + this, SLOT (reportMessage (const CSMDoc::Message&, int))); connect (&mRunner, SIGNAL (runStateChanged()), this, SLOT (runStateChanged())); } @@ -2401,11 +2401,10 @@ void CSMDoc::Document::modificationStateChanged (bool clean) emit stateChanged (getState(), this); } -void CSMDoc::Document::reportMessage (const CSMWorld::UniversalId& id, const std::string& message, - const std::string& hint, int type) +void CSMDoc::Document::reportMessage (const CSMDoc::Message& message, int type) { /// \todo find a better way to get these messages to the user. - std::cout << message << std::endl; + std::cout << message.mMessage << std::endl; } void CSMDoc::Document::operationDone (int type, bool failed) diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp index 14daeeb75..4aaaf40b0 100644 --- a/apps/opencs/model/doc/document.hpp +++ b/apps/opencs/model/doc/document.hpp @@ -158,8 +158,7 @@ namespace CSMDoc void modificationStateChanged (bool clean); - void reportMessage (const CSMWorld::UniversalId& id, const std::string& message, - const std::string& hint, int type); + void reportMessage (const CSMDoc::Message& message, int type); void operationDone (int type, bool failed); diff --git a/apps/opencs/model/doc/loader.cpp b/apps/opencs/model/doc/loader.cpp index 43f3b850e..5cdade37e 100644 --- a/apps/opencs/model/doc/loader.cpp +++ b/apps/opencs/model/doc/loader.cpp @@ -68,7 +68,8 @@ void CSMDoc::Loader::load() for (CSMDoc::Messages::Iterator iter (messages.begin()); iter!=messages.end(); ++iter) { - document->getReport (log)->add (iter->mId, iter->mMessage); + document->getReport (log)->add ( + CSMDoc::Message (iter->mId, iter->mMessage, "")); emit loadMessage (document, iter->mMessage); } } diff --git a/apps/opencs/model/doc/messages.cpp b/apps/opencs/model/doc/messages.cpp index 3c709683e..07604cd85 100644 --- a/apps/opencs/model/doc/messages.cpp +++ b/apps/opencs/model/doc/messages.cpp @@ -1,6 +1,8 @@ #include "messages.hpp" +CSMDoc::Message::Message() {} + CSMDoc::Message::Message (const CSMWorld::UniversalId& id, const std::string& message, const std::string& hint) : mId (id), mMessage (message), mHint (hint) diff --git a/apps/opencs/model/doc/messages.hpp b/apps/opencs/model/doc/messages.hpp index 4e143d869..ecdb7e243 100644 --- a/apps/opencs/model/doc/messages.hpp +++ b/apps/opencs/model/doc/messages.hpp @@ -4,6 +4,8 @@ #include #include +#include + #include "../world/universalid.hpp" namespace CSMDoc @@ -14,6 +16,8 @@ namespace CSMDoc std::string mMessage; std::string mHint; + Message(); + Message (const CSMWorld::UniversalId& id, const std::string& message, const std::string& hint); }; @@ -47,4 +51,6 @@ namespace CSMDoc }; } +Q_DECLARE_METATYPE (CSMDoc::Message) + #endif diff --git a/apps/opencs/model/doc/operation.cpp b/apps/opencs/model/doc/operation.cpp index 4a39d2911..99d581a95 100644 --- a/apps/opencs/model/doc/operation.cpp +++ b/apps/opencs/model/doc/operation.cpp @@ -129,7 +129,7 @@ void CSMDoc::Operation::executeStage() } catch (const std::exception& e) { - emit reportMessage (CSMWorld::UniversalId(), e.what(), "", mType); + emit reportMessage (Message (CSMWorld::UniversalId(), e.what(), ""), mType); abort(); } @@ -141,7 +141,7 @@ void CSMDoc::Operation::executeStage() emit progress (mCurrentStepTotal, mTotalSteps ? mTotalSteps : 1, mType); for (Messages::Iterator iter (messages.begin()); iter!=messages.end(); ++iter) - emit reportMessage (iter->mId, iter->mMessage, iter->mHint, mType); + emit reportMessage (*iter, mType); if (mCurrentStage==mStages.end()) operationDone(); diff --git a/apps/opencs/model/doc/operation.hpp b/apps/opencs/model/doc/operation.hpp index 6d6ed112b..d90a1bf4f 100644 --- a/apps/opencs/model/doc/operation.hpp +++ b/apps/opencs/model/doc/operation.hpp @@ -8,6 +8,8 @@ #include #include +#include "messages.hpp" + namespace CSMWorld { class UniversalId; @@ -61,8 +63,7 @@ namespace CSMDoc void progress (int current, int max, int type); - void reportMessage (const CSMWorld::UniversalId& id, const std::string& message, - const std::string& hint, int type); + void reportMessage (const CSMDoc::Message& message, int type); void done (int type, bool failed); diff --git a/apps/opencs/model/doc/operationholder.cpp b/apps/opencs/model/doc/operationholder.cpp index 5157fd80c..25fc6fc26 100644 --- a/apps/opencs/model/doc/operationholder.cpp +++ b/apps/opencs/model/doc/operationholder.cpp @@ -21,8 +21,8 @@ void CSMDoc::OperationHolder::setOperation (Operation *operation) this, SIGNAL (progress (int, int, int))); connect ( - mOperation, SIGNAL (reportMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int)), - this, SIGNAL (reportMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int))); + mOperation, SIGNAL (reportMessage (const CSMDoc::Message&, int)), + this, SIGNAL (reportMessage (const CSMDoc::Message&, int))); connect ( mOperation, SIGNAL (done (int, bool)), diff --git a/apps/opencs/model/doc/operationholder.hpp b/apps/opencs/model/doc/operationholder.hpp index 6fe6df053..b73d61dab 100644 --- a/apps/opencs/model/doc/operationholder.hpp +++ b/apps/opencs/model/doc/operationholder.hpp @@ -4,6 +4,8 @@ #include #include +#include "messages.hpp" + namespace CSMWorld { class UniversalId; @@ -44,8 +46,7 @@ namespace CSMDoc void progress (int current, int max, int type); - void reportMessage (const CSMWorld::UniversalId& id, const std::string& message, - const std::string& hint, int type); + void reportMessage (const CSMDoc::Message& message, int type); void done (int type, bool failed); diff --git a/apps/opencs/model/tools/reportmodel.cpp b/apps/opencs/model/tools/reportmodel.cpp index e661e9eac..b44ad7b60 100644 --- a/apps/opencs/model/tools/reportmodel.cpp +++ b/apps/opencs/model/tools/reportmodel.cpp @@ -127,12 +127,11 @@ bool CSMTools::ReportModel::removeRows (int row, int count, const QModelIndex& p return true; } -void CSMTools::ReportModel::add (const CSMWorld::UniversalId& id, const std::string& message, - const std::string& hint) +void CSMTools::ReportModel::add (const CSMDoc::Message& message) { beginInsertRows (QModelIndex(), mRows.size(), mRows.size()); - mRows.push_back (CSMDoc::Message (id, message, hint)); + mRows.push_back (message); endInsertRows(); } diff --git a/apps/opencs/model/tools/reportmodel.hpp b/apps/opencs/model/tools/reportmodel.hpp index ff20f74a5..e9b6124b3 100644 --- a/apps/opencs/model/tools/reportmodel.hpp +++ b/apps/opencs/model/tools/reportmodel.hpp @@ -42,8 +42,7 @@ namespace CSMTools virtual bool removeRows (int row, int count, const QModelIndex& parent = QModelIndex()); - void add (const CSMWorld::UniversalId& id, const std::string& message, - const std::string& hint = ""); + void add (const CSMDoc::Message& message); void flagAsReplaced (int index); diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index fda373bcf..f46dbe6d3 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -58,9 +58,8 @@ CSMDoc::OperationHolder *CSMTools::Tools::getVerifier() connect (&mVerifier, SIGNAL (progress (int, int, int)), this, SIGNAL (progress (int, int, int))); connect (&mVerifier, SIGNAL (done (int, bool)), this, SIGNAL (done (int, bool))); - connect (&mVerifier, - SIGNAL (reportMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int)), - this, SLOT (verifierMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int))); + connect (&mVerifier, SIGNAL (reportMessage (const CSMDoc::Message&, int)), + this, SLOT (verifierMessage (const CSMDoc::Message&, int))); std::vector mandatoryIds; // I want C++11, damn it! mandatoryIds.push_back ("Day"); @@ -125,9 +124,8 @@ CSMTools::Tools::Tools (CSMDoc::Document& document) connect (&mSearch, SIGNAL (progress (int, int, int)), this, SIGNAL (progress (int, int, int))); connect (&mSearch, SIGNAL (done (int, bool)), this, SIGNAL (done (int, bool))); - connect (&mSearch, - SIGNAL (reportMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int)), - this, SLOT (verifierMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int))); + connect (&mSearch, SIGNAL (reportMessage (const CSMDoc::Message&, int)), + this, SLOT (verifierMessage (const CSMDoc::Message&, int))); } CSMTools::Tools::~Tools() @@ -215,12 +213,11 @@ CSMTools::ReportModel *CSMTools::Tools::getReport (const CSMWorld::UniversalId& return mReports.at (id.getIndex()); } -void CSMTools::Tools::verifierMessage (const CSMWorld::UniversalId& id, const std::string& message, - const std::string& hint, int type) +void CSMTools::Tools::verifierMessage (const CSMDoc::Message& message, int type) { std::map::iterator iter = mActiveReports.find (type); if (iter!=mActiveReports.end()) - mReports[iter->second]->add (id, message, hint); + mReports[iter->second]->add (message); } diff --git a/apps/opencs/model/tools/tools.hpp b/apps/opencs/model/tools/tools.hpp index 0f9e57044..2912fc471 100644 --- a/apps/opencs/model/tools/tools.hpp +++ b/apps/opencs/model/tools/tools.hpp @@ -75,8 +75,7 @@ namespace CSMTools private slots: - void verifierMessage (const CSMWorld::UniversalId& id, const std::string& message, - const std::string& hint, int type); + void verifierMessage (const CSMDoc::Message& message, int type); signals: From 197b8ec731671002b42976d9a2057ffae5c797a7 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 20 Jun 2015 19:04:19 +0200 Subject: [PATCH 1607/3725] added severity attribute for operation messages (Fixes #2717) --- apps/opencs/model/doc/loader.cpp | 5 +-- apps/opencs/model/doc/messages.cpp | 15 +++++-- apps/opencs/model/doc/messages.hpp | 19 ++++++++- apps/opencs/model/doc/operation.cpp | 12 ++++-- apps/opencs/model/doc/operation.hpp | 4 ++ apps/opencs/model/tools/reportmodel.cpp | 47 ++++++++++++++++----- apps/opencs/model/tools/reportmodel.hpp | 6 ++- apps/opencs/model/tools/scriptcheck.cpp | 30 ++++++++----- apps/opencs/model/tools/scriptcheck.hpp | 1 + apps/opencs/model/tools/search.cpp | 2 +- apps/opencs/model/tools/searchoperation.cpp | 2 + apps/opencs/model/tools/tools.cpp | 2 +- apps/opencs/model/world/data.cpp | 10 +++-- 13 files changed, 116 insertions(+), 39 deletions(-) diff --git a/apps/opencs/model/doc/loader.cpp b/apps/opencs/model/doc/loader.cpp index 5cdade37e..33725a6f9 100644 --- a/apps/opencs/model/doc/loader.cpp +++ b/apps/opencs/model/doc/loader.cpp @@ -52,7 +52,7 @@ void CSMDoc::Loader::load() { if (iter->second.mRecordsLeft) { - CSMDoc::Messages messages; + Messages messages (Message::Severity_Error); for (int i=0; igetData().continueLoading (messages)) { @@ -68,8 +68,7 @@ void CSMDoc::Loader::load() for (CSMDoc::Messages::Iterator iter (messages.begin()); iter!=messages.end(); ++iter) { - document->getReport (log)->add ( - CSMDoc::Message (iter->mId, iter->mMessage, "")); + document->getReport (log)->add (*iter); emit loadMessage (document, iter->mMessage); } } diff --git a/apps/opencs/model/doc/messages.cpp b/apps/opencs/model/doc/messages.cpp index 07604cd85..34157a05f 100644 --- a/apps/opencs/model/doc/messages.cpp +++ b/apps/opencs/model/doc/messages.cpp @@ -4,15 +4,22 @@ CSMDoc::Message::Message() {} CSMDoc::Message::Message (const CSMWorld::UniversalId& id, const std::string& message, - const std::string& hint) -: mId (id), mMessage (message), mHint (hint) + const std::string& hint, Severity severity) +: mId (id), mMessage (message), mHint (hint), mSeverity (severity) {} +CSMDoc::Messages::Messages (Message::Severity default_ = Message::Severity_Error) +: mDefault (default_) +{} + void CSMDoc::Messages::add (const CSMWorld::UniversalId& id, const std::string& message, - const std::string& hint) + const std::string& hint, Message::Severity severity) { - mMessages.push_back (Message (id, message, hint)); + if (severity==Message::Severity_Default) + severity = mDefault; + + mMessages.push_back (Message (id, message, hint, severity)); } void CSMDoc::Messages::push_back (const std::pair& data) diff --git a/apps/opencs/model/doc/messages.hpp b/apps/opencs/model/doc/messages.hpp index ecdb7e243..86f5feb15 100644 --- a/apps/opencs/model/doc/messages.hpp +++ b/apps/opencs/model/doc/messages.hpp @@ -12,14 +12,25 @@ namespace CSMDoc { struct Message { + enum Severity + { + Severity_Info = 0, // no problem + Severity_Warning = 1, // a potential problem, but we are probably fine + Severity_Error = 2, // an error; we are not fine + Severity_SeriousError = 3, // an error so bad we can't even be sure if we are + // reporting it correctly + Severity_Default = 4 + }; + CSMWorld::UniversalId mId; std::string mMessage; std::string mHint; + Severity mSeverity; Message(); Message (const CSMWorld::UniversalId& id, const std::string& message, - const std::string& hint); + const std::string& hint, Severity severity); }; class Messages @@ -36,11 +47,15 @@ namespace CSMDoc private: Collection mMessages; + Message::Severity mDefault; public: + Messages (Message::Severity default_); + void add (const CSMWorld::UniversalId& id, const std::string& message, - const std::string& hint = ""); + const std::string& hint = "", + Message::Severity severity = Message::Severity_Default); /// \deprecated Use add instead. void push_back (const std::pair& data); diff --git a/apps/opencs/model/doc/operation.cpp b/apps/opencs/model/doc/operation.cpp index 99d581a95..8b2717086 100644 --- a/apps/opencs/model/doc/operation.cpp +++ b/apps/opencs/model/doc/operation.cpp @@ -33,7 +33,8 @@ void CSMDoc::Operation::prepareStages() CSMDoc::Operation::Operation (int type, bool ordered, bool finalAlways) : mType (type), mStages(std::vector >()), mCurrentStage(mStages.begin()), mCurrentStep(0), mCurrentStepTotal(0), mTotalSteps(0), mOrdered (ordered), - mFinalAlways (finalAlways), mError(false), mConnected (false), mPrepared (false) + mFinalAlways (finalAlways), mError(false), mConnected (false), mPrepared (false), + mDefaultSeverity (Message::Severity_Error) { mTimer = new QTimer (this); } @@ -72,6 +73,11 @@ void CSMDoc::Operation::configureSettings (const std::vector& settings) } } +void CSMDoc::Operation::setDefaultSeverity (Message::Severity severity) +{ + mDefaultSeverity = severity; +} + bool CSMDoc::Operation::hasError() const { return mError; @@ -112,7 +118,7 @@ void CSMDoc::Operation::executeStage() mPrepared = true; } - Messages messages; + Messages messages (mDefaultSeverity); while (mCurrentStage!=mStages.end()) { @@ -129,7 +135,7 @@ void CSMDoc::Operation::executeStage() } catch (const std::exception& e) { - emit reportMessage (Message (CSMWorld::UniversalId(), e.what(), ""), mType); + emit reportMessage (Message (CSMWorld::UniversalId(), e.what(), "", Message::Severity_SeriousError), mType); abort(); } diff --git a/apps/opencs/model/doc/operation.hpp b/apps/opencs/model/doc/operation.hpp index d90a1bf4f..703f9d44b 100644 --- a/apps/opencs/model/doc/operation.hpp +++ b/apps/opencs/model/doc/operation.hpp @@ -36,6 +36,7 @@ namespace CSMDoc QTimer *mTimer; std::map mSettings; bool mPrepared; + Message::Severity mDefaultSeverity; void prepareStages(); @@ -57,6 +58,9 @@ namespace CSMDoc /// \attention Do no call this function while this Operation is running. void configureSettings (const std::vector& settings); + /// \attention Do no call this function while this Operation is running. + void setDefaultSeverity (Message::Severity severity); + bool hasError() const; signals: diff --git a/apps/opencs/model/tools/reportmodel.cpp b/apps/opencs/model/tools/reportmodel.cpp index b44ad7b60..480691710 100644 --- a/apps/opencs/model/tools/reportmodel.cpp +++ b/apps/opencs/model/tools/reportmodel.cpp @@ -6,19 +6,18 @@ #include "../world/columns.hpp" -CSMTools::ReportModel::ReportModel (bool fieldColumn) +CSMTools::ReportModel::ReportModel (bool fieldColumn, bool severityColumn) +: mColumnField (-1), mColumnSeverity (-1) { + int index = 3; + + if (severityColumn) + mColumnSeverity = index++; + if (fieldColumn) - { - mColumnField = 3; - mColumnDescription = 4; - } - else - { - mColumnDescription = 3; + mColumnField = index++; - mColumnField = -1; - } + mColumnDescription = index; } int CSMTools::ReportModel::rowCount (const QModelIndex & parent) const @@ -83,6 +82,18 @@ QVariant CSMTools::ReportModel::data (const QModelIndex & index, int role) const return QString::fromUtf8 (field.c_str()); } + + if (index.column()==mColumnSeverity) + { + switch (mRows.at (index.row()).mSeverity) + { + case CSMDoc::Message::Severity_Info: return "Information"; + case CSMDoc::Message::Severity_Warning: return "Warning"; + case CSMDoc::Message::Severity_Error: return "Error"; + case CSMDoc::Message::Severity_SeriousError: return "Serious Error"; + case CSMDoc::Message::Severity_Default: break; + } + } return QVariant(); } @@ -107,6 +118,9 @@ QVariant CSMTools::ReportModel::headerData (int section, Qt::Orientation orienta if (section==mColumnField) return "Field"; + if (section==mColumnSeverity) + return "Severity"; + return "-"; } @@ -170,3 +184,16 @@ void CSMTools::ReportModel::clear() endRemoveRows(); } } + +int CSMTools::ReportModel::countErrors() const +{ + int count = 0; + + for (std::vector::const_iterator iter (mRows.begin()); + iter!=mRows.end(); ++iter) + if (iter->mSeverity==CSMDoc::Message::Severity_Error || + iter->mSeverity==CSMDoc::Message::Severity_SeriousError) + ++count; + + return count; +} diff --git a/apps/opencs/model/tools/reportmodel.hpp b/apps/opencs/model/tools/reportmodel.hpp index e9b6124b3..5704970f5 100644 --- a/apps/opencs/model/tools/reportmodel.hpp +++ b/apps/opencs/model/tools/reportmodel.hpp @@ -27,10 +27,11 @@ namespace CSMTools // Configurable columns int mColumnDescription; int mColumnField; + int mColumnSeverity; public: - ReportModel (bool fieldColumn = false); + ReportModel (bool fieldColumn = false, bool severityColumn = true); virtual int rowCount (const QModelIndex & parent = QModelIndex()) const; @@ -51,6 +52,9 @@ namespace CSMTools std::string getHint (int row) const; void clear(); + + // Return number of messages with Error or SeriousError severity. + int countErrors() const; }; } diff --git a/apps/opencs/model/tools/scriptcheck.cpp b/apps/opencs/model/tools/scriptcheck.cpp index 33922e9cf..190b146c9 100644 --- a/apps/opencs/model/tools/scriptcheck.cpp +++ b/apps/opencs/model/tools/scriptcheck.cpp @@ -11,6 +11,17 @@ #include "../world/data.hpp" +CSMDoc::Message::Severity CSMTools::ScriptCheckStage::getSeverity (Type type) +{ + switch (type) + { + case WarningMessage: return CSMDoc::Message::Severity_Warning; + case ErrorMessage: return CSMDoc::Message::Severity_Error; + } + + return CSMDoc::Message::Severity_SeriousError; +} + void CSMTools::ScriptCheckStage::report (const std::string& message, const Compiler::TokenLoc& loc, Type type) { @@ -18,11 +29,6 @@ void CSMTools::ScriptCheckStage::report (const std::string& message, const Compi CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Script, mId); - if (type==ErrorMessage) - stream << "error "; - else - stream << "warning "; - stream << "script " << mFile << ", line " << loc.mLine << ", column " << loc.mColumn @@ -32,15 +38,17 @@ void CSMTools::ScriptCheckStage::report (const std::string& message, const Compi hintStream << "l:" << loc.mLine << " " << loc.mColumn; - mMessages->add (id, stream.str(), hintStream.str()); + mMessages->add (id, stream.str(), hintStream.str(), getSeverity (type)); } void CSMTools::ScriptCheckStage::report (const std::string& message, Type type) { CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Script, mId); - mMessages->push_back (std::make_pair (id, - (type==ErrorMessage ? "error: " : "warning: ") + message)); + std::ostringstream stream; + stream << "script " << mFile << ": " << message; + + mMessages->add (id, stream.str(), "", getSeverity (type)); } CSMTools::ScriptCheckStage::ScriptCheckStage (const CSMDoc::Document& document) @@ -100,8 +108,10 @@ void CSMTools::ScriptCheckStage::perform (int stage, CSMDoc::Messages& messages) { CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Script, mId); - messages.push_back (std::make_pair (id, - std::string ("Critical compile error: ") + error.what())); + std::ostringstream stream; + stream << "script " << mFile << ": " << error.what(); + + messages.add (id, stream.str(), "", CSMDoc::Message::Severity_SeriousError); } mMessages = 0; diff --git a/apps/opencs/model/tools/scriptcheck.hpp b/apps/opencs/model/tools/scriptcheck.hpp index 0d42b275c..97c50a1eb 100644 --- a/apps/opencs/model/tools/scriptcheck.hpp +++ b/apps/opencs/model/tools/scriptcheck.hpp @@ -32,6 +32,7 @@ namespace CSMTools CSMDoc::Messages *mMessages; WarningMode mWarningMode; + CSMDoc::Message::Severity getSeverity (Type type); virtual void report (const std::string& message, const Compiler::TokenLoc& loc, Type type); ///< Report error to the user. diff --git a/apps/opencs/model/tools/search.cpp b/apps/opencs/model/tools/search.cpp index 7eb531161..449df2c63 100644 --- a/apps/opencs/model/tools/search.cpp +++ b/apps/opencs/model/tools/search.cpp @@ -280,7 +280,7 @@ void CSMTools::Search::replace (CSMDoc::Document& document, CSMWorld::IdTableBas bool CSMTools::Search::verify (CSMDoc::Document& document, CSMWorld::IdTableBase *model, const CSMWorld::UniversalId& id, const std::string& messageHint) const { - CSMDoc::Messages messages; + CSMDoc::Messages messages (CSMDoc::Message::Severity_Info); int row = model->getModelIndex (id.getId(), model->findColumnIndex (CSMWorld::Columns::ColumnId_Id)).row(); diff --git a/apps/opencs/model/tools/searchoperation.cpp b/apps/opencs/model/tools/searchoperation.cpp index 4512de582..8cbc5dc8e 100644 --- a/apps/opencs/model/tools/searchoperation.cpp +++ b/apps/opencs/model/tools/searchoperation.cpp @@ -21,6 +21,8 @@ CSMTools::SearchOperation::SearchOperation (CSMDoc::Document& document) iter!=types.end(); ++iter) appendStage (new SearchStage (&dynamic_cast ( *document.getData().getTableModel (*iter)))); + + setDefaultSeverity (CSMDoc::Message::Severity_Info); } void CSMTools::SearchOperation::configure (const Search& search) diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index f46dbe6d3..f0d649f38 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -158,7 +158,7 @@ CSMWorld::UniversalId CSMTools::Tools::runVerifier() CSMWorld::UniversalId CSMTools::Tools::newSearch() { - mReports.insert (std::make_pair (mNextReportNumber++, new ReportModel (true))); + mReports.insert (std::make_pair (mNextReportNumber++, new ReportModel (true, false))); return CSMWorld::UniversalId (CSMWorld::UniversalId::Type_Search, mNextReportNumber-1); } diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 529c8f88f..5acd80339 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -923,7 +923,7 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Messages& messages) { // log an error and continue loading the refs to the last loaded cell CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_None); - messages.add (id, "Logic error: cell index out of bounds"); + messages.add (id, "Logic error: cell index out of bounds", "", CSMDoc::Message::Severity_Error); index = mCells.getSize()-1; } std::string cellId = Misc::StringUtils::lowerCase (mCells.getId (index)); @@ -984,7 +984,8 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Messages& messages) else { messages.add (UniversalId::Type_None, - "Trying to delete dialogue record " + id + " which does not exist"); + "Trying to delete dialogue record " + id + " which does not exist", + "", CSMDoc::Message::Severity_Warning); } } else @@ -1001,7 +1002,7 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Messages& messages) if (!mDialogue) { messages.add (UniversalId::Type_None, - "Found info record not following a dialogue record"); + "Found info record not following a dialogue record", "", CSMDoc::Message::Severity_Error); mReader->skipRecord(); break; @@ -1044,7 +1045,8 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Messages& messages) if (unhandledRecord) { - messages.add (UniversalId::Type_None, "Unsupported record type: " + n.toString()); + messages.add (UniversalId::Type_None, "Unsupported record type: " + n.toString(), "", + CSMDoc::Message::Severity_Error); mReader->skipRecord(); } From b9f6baf317bfc3f1cbabafe1d79749a5d83ca523 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 20 Jun 2015 19:16:15 +0200 Subject: [PATCH 1608/3725] add normal script warnings mode (Fixes #2642) --- apps/opencs/model/settings/usersettings.cpp | 7 ++++--- apps/opencs/model/tools/scriptcheck.cpp | 5 ++++- apps/opencs/model/tools/scriptcheck.hpp | 1 + 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/apps/opencs/model/settings/usersettings.cpp b/apps/opencs/model/settings/usersettings.cpp index 78db5313b..3e59d0582 100644 --- a/apps/opencs/model/settings/usersettings.cpp +++ b/apps/opencs/model/settings/usersettings.cpp @@ -312,17 +312,18 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() "\nA name from the list of colors defined in the list of SVG color keyword names." "\nX11 color names may also work."; - QString modeIgnore ("Ignore"); + QString modeNormal ("Normal"); QStringList modes; - modes << modeIgnore << "Strict"; + modes << "Ignore" << modeNormal << "Strict"; Setting *warnings = createSetting (Type_ComboBox, "warnings", "Warning Mode"); warnings->setDeclaredValues (modes); - warnings->setDefaultValue (modeIgnore); + warnings->setDefaultValue (modeNormal); warnings->setToolTip ("
    How to handle warning messages during compilation:

    " "

  • Ignore: Do not report warning
  • " + "
  • Normal: Report warning as a warning
  • " "
  • Strict: Promote warning to an error
  • " "
"); diff --git a/apps/opencs/model/tools/scriptcheck.cpp b/apps/opencs/model/tools/scriptcheck.cpp index 190b146c9..928ae156f 100644 --- a/apps/opencs/model/tools/scriptcheck.cpp +++ b/apps/opencs/model/tools/scriptcheck.cpp @@ -84,7 +84,8 @@ void CSMTools::ScriptCheckStage::perform (int stage, CSMDoc::Messages& messages) switch (mWarningMode) { case Mode_Ignore: setWarningsMode (0); break; - case Mode_Strict: setWarningsMode (1); break; + case Mode_Normal: setWarningsMode (1); break; + case Mode_Strict: setWarningsMode (2); break; } try @@ -123,6 +124,8 @@ void CSMTools::ScriptCheckStage::updateUserSetting (const QString& name, const Q { if (value.at (0)=="Ignore") mWarningMode = Mode_Ignore; + else if (value.at (0)=="Normal") + mWarningMode = Mode_Normal; else if (value.at (0)=="Strict") mWarningMode = Mode_Strict; } diff --git a/apps/opencs/model/tools/scriptcheck.hpp b/apps/opencs/model/tools/scriptcheck.hpp index 97c50a1eb..3f0276652 100644 --- a/apps/opencs/model/tools/scriptcheck.hpp +++ b/apps/opencs/model/tools/scriptcheck.hpp @@ -21,6 +21,7 @@ namespace CSMTools enum WarningMode { Mode_Ignore, + Mode_Normal, Mode_Strict }; From c644f15167b777323b165375c4728fcb877ea10a Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 20 Jun 2015 19:46:38 +0200 Subject: [PATCH 1609/3725] calm down travis --- apps/opencs/model/doc/messages.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/doc/messages.cpp b/apps/opencs/model/doc/messages.cpp index 34157a05f..bd6e808c8 100644 --- a/apps/opencs/model/doc/messages.cpp +++ b/apps/opencs/model/doc/messages.cpp @@ -9,7 +9,7 @@ CSMDoc::Message::Message (const CSMWorld::UniversalId& id, const std::string& me {} -CSMDoc::Messages::Messages (Message::Severity default_ = Message::Severity_Error) +CSMDoc::Messages::Messages (Message::Severity default_) : mDefault (default_) {} From 7dcdd130bb65be9fa79d8240946458420c2248d4 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sat, 20 Jun 2015 20:52:47 +0300 Subject: [PATCH 1610/3725] Rework Dialogue subview code according to DropLineEdit changes --- apps/opencs/view/widget/droplineedit.cpp | 9 ++- apps/opencs/view/widget/droplineedit.hpp | 3 +- apps/opencs/view/world/dialoguesubview.cpp | 70 +--------------------- apps/opencs/view/world/dialoguesubview.hpp | 20 ------- apps/opencs/view/world/util.cpp | 24 ++------ 5 files changed, 14 insertions(+), 112 deletions(-) diff --git a/apps/opencs/view/widget/droplineedit.cpp b/apps/opencs/view/widget/droplineedit.cpp index f3500dcd2..6dae15746 100644 --- a/apps/opencs/view/widget/droplineedit.cpp +++ b/apps/opencs/view/widget/droplineedit.cpp @@ -54,8 +54,9 @@ void CSVWidget::DropLineEdit::dropEvent(QDropEvent *event) int dataIndex = getAcceptedDataIndex(*data); if (dataIndex != -1) { - setText(data->getData()[dataIndex].getId().c_str()); - emit tableMimeDataDropped(data->getData(), data->getDocumentPtr()); + std::vector idData = data->getData(); + setText(idData[dataIndex].getId().c_str()); + emit tableMimeDataDropped(idData[dataIndex], data->getDocumentPtr()); } } @@ -76,11 +77,13 @@ int CSVWidget::DropLineEdit::getAcceptedDataIndex(const CSMWorld::TableMimeData return 0; } + bool isReferenceable = mDropType == CSMWorld::UniversalId::Type_Referenceable; std::vector idData = data.getData(); int size = static_cast(idData.size()); for (int i = 0; i < size; ++i) { - if (idData[i].getType() == mDropType) + CSMWorld::UniversalId::Type type = idData[i].getType(); + if (type == mDropType || isReferenceable && CSMWorld::TableMimeData::isReferencable(type)) { return i; } diff --git a/apps/opencs/view/widget/droplineedit.hpp b/apps/opencs/view/widget/droplineedit.hpp index 7ba0513cc..ce086b7dc 100644 --- a/apps/opencs/view/widget/droplineedit.hpp +++ b/apps/opencs/view/widget/droplineedit.hpp @@ -43,8 +43,7 @@ namespace CSVWidget void dropEvent(QDropEvent *event); signals: - void tableMimeDataDropped(const std::vector &data, - const CSMDoc::Document *document); + void tableMimeDataDropped(const CSMWorld::UniversalId &id, const CSMDoc::Document *document); }; } diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index a1dbc902e..284c5928b 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -130,52 +130,6 @@ QWidget* CSVWorld::DialogueDelegateDispatcherProxy::getEditor() const return mEditor; } -void CSVWorld::DialogueDelegateDispatcherProxy::tableMimeDataDropped(const std::vector& data, const CSMDoc::Document* document) -{ - QLineEdit* lineEdit = qobject_cast(mEditor); - { - if (!lineEdit || !mIndexWrapper.get()) - { - return; - } - } - for (unsigned i = 0; i < data.size(); ++i) - { - CSMWorld::UniversalId::Type type = data[i].getType(); - if (mDisplay == CSMWorld::ColumnBase::Display_Referenceable) - { - if (type == CSMWorld::UniversalId::Type_Activator - || type == CSMWorld::UniversalId::Type_Potion - || type == CSMWorld::UniversalId::Type_Apparatus - || type == CSMWorld::UniversalId::Type_Armor - || type == CSMWorld::UniversalId::Type_Book - || type == CSMWorld::UniversalId::Type_Clothing - || type == CSMWorld::UniversalId::Type_Container - || type == CSMWorld::UniversalId::Type_Creature - || type == CSMWorld::UniversalId::Type_Door - || type == CSMWorld::UniversalId::Type_Ingredient - || type == CSMWorld::UniversalId::Type_CreatureLevelledList - || type == CSMWorld::UniversalId::Type_ItemLevelledList - || type == CSMWorld::UniversalId::Type_Light - || type == CSMWorld::UniversalId::Type_Lockpick - || type == CSMWorld::UniversalId::Type_Miscellaneous - || type == CSMWorld::UniversalId::Type_Npc - || type == CSMWorld::UniversalId::Type_Probe - || type == CSMWorld::UniversalId::Type_Repair - || type == CSMWorld::UniversalId::Type_Static - || type == CSMWorld::UniversalId::Type_Weapon) - { - type = CSMWorld::UniversalId::Type_Referenceable; - } - } - if (mDisplay == CSMWorld::TableMimeData::convertEnums(type)) - { - emit tableMimeDataDropped(mEditor, mIndexWrapper->mIndex, data[i], document); - emit editorDataCommited(mEditor, mIndexWrapper->mIndex, mDisplay); - break; - } - } -} /* ==============================DialogueDelegateDispatcher========================================== */ @@ -311,12 +265,8 @@ QWidget* CSVWorld::DialogueDelegateDispatcher::makeEditor(CSMWorld::ColumnBase:: { connect(editor, SIGNAL(editingFinished()), proxy, SLOT(editorDataCommited())); - connect(editor, SIGNAL(tableMimeDataDropped(const std::vector&, const CSMDoc::Document*)), - proxy, SLOT(tableMimeDataDropped(const std::vector&, const CSMDoc::Document*))); - - connect(proxy, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*)), - this, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*))); - + connect(editor, SIGNAL(tableMimeDataDropped(const CSMWorld::UniversalId&, const CSMDoc::Document*)), + proxy, SLOT(editorDataCommited())); } else if (qobject_cast(editor)) { @@ -387,9 +337,6 @@ mCommandDispatcher (commandDispatcher), mDocument (document) { remake (row); - - connect(mDispatcher, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*)), - this, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*))); } void CSVWorld::EditWidget::remake(int row) @@ -680,8 +627,6 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSM mEditWidget = new EditWidget(mainWidget, mTable->getModelIndex(mCurrentId, 0).row(), mTable, mCommandDispatcher, document, false); - connect(mEditWidget, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*)), - this, SLOT(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*))); mMainLayout->addWidget(mEditWidget); mEditWidget->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); @@ -844,17 +789,6 @@ void CSVWorld::DialogueSubView::rowsAboutToBeRemoved(const QModelIndex &parent, } } -void CSVWorld::DialogueSubView::tableMimeDataDropped (QWidget* editor, - const QModelIndex& index, - const CSMWorld::UniversalId& id, - const CSMDoc::Document* document) -{ - if (document == &mDocument) - { - qobject_cast(editor)->setText(id.getId().c_str()); - } -} - void CSVWorld::DialogueSubView::requestFocus (const std::string& id) { changeCurrentId(id); diff --git a/apps/opencs/view/world/dialoguesubview.hpp b/apps/opencs/view/world/dialoguesubview.hpp index 6cbd8ad77..69e0dc864 100644 --- a/apps/opencs/view/world/dialoguesubview.hpp +++ b/apps/opencs/view/world/dialoguesubview.hpp @@ -86,18 +86,12 @@ namespace CSVWorld public slots: void editorDataCommited(); void setIndex(const QModelIndex& index); - void tableMimeDataDropped(const std::vector& data, - const CSMDoc::Document* document); signals: void editorDataCommited(QWidget* editor, const QModelIndex& index, CSMWorld::ColumnBase::Display display); - void tableMimeDataDropped(QWidget* editor, const QModelIndex& index, - const CSMWorld::UniversalId& id, - const CSMDoc::Document* document); - }; class DialogueDelegateDispatcher : public QAbstractItemDelegate @@ -153,11 +147,6 @@ namespace CSVWorld private slots: void editorDataCommited(QWidget* editor, const QModelIndex& index, CSMWorld::ColumnBase::Display display); - - signals: - void tableMimeDataDropped(QWidget* editor, const QModelIndex& index, - const CSMWorld::UniversalId& id, - const CSMDoc::Document* document); }; class EditWidget : public QScrollArea @@ -182,11 +171,6 @@ namespace CSVWorld virtual ~EditWidget(); void remake(int row); - - signals: - void tableMimeDataDropped(QWidget* editor, const QModelIndex& index, - const CSMWorld::UniversalId& id, - const CSMDoc::Document* document); }; class DialogueSubView : public CSVDoc::SubView @@ -230,10 +214,6 @@ namespace CSVWorld void dataChanged(const QModelIndex & index); ///\brief we need to care for deleting currently edited record - void tableMimeDataDropped(QWidget* editor, const QModelIndex& index, - const CSMWorld::UniversalId& id, - const CSMDoc::Document* document); - void requestFocus (const std::string& id); void rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end); diff --git a/apps/opencs/view/world/util.cpp b/apps/opencs/view/world/util.cpp index d3969dad4..815505589 100644 --- a/apps/opencs/view/world/util.cpp +++ b/apps/opencs/view/world/util.cpp @@ -236,29 +236,15 @@ QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleO return new QCheckBox(parent); - case CSMWorld::ColumnBase::Display_String: - case CSMWorld::ColumnBase::Display_Skill: - case CSMWorld::ColumnBase::Display_Script: - case CSMWorld::ColumnBase::Display_Race: - case CSMWorld::ColumnBase::Display_Region: - case CSMWorld::ColumnBase::Display_Class: - case CSMWorld::ColumnBase::Display_Faction: - case CSMWorld::ColumnBase::Display_Miscellaneous: - case CSMWorld::ColumnBase::Display_Sound: - case CSMWorld::ColumnBase::Display_Mesh: - case CSMWorld::ColumnBase::Display_Icon: - case CSMWorld::ColumnBase::Display_Music: - case CSMWorld::ColumnBase::Display_SoundRes: - case CSMWorld::ColumnBase::Display_Texture: - case CSMWorld::ColumnBase::Display_Video: - case CSMWorld::ColumnBase::Display_GlobalVariable: - - return new CSVWidget::DropLineEdit(CSMWorld::UniversalId::Type_None, parent); - case CSMWorld::ColumnBase::Display_ScriptLines: return new ScriptEdit (mDocument, ScriptHighlighter::Mode_Console, parent); + case CSMWorld::ColumnBase::Display_String: + // For other Display types (that represent record IDs) with drop support IdCompletionDelegate is used + + return new CSVWidget::DropLineEdit(CSMWorld::UniversalId::Type_None, parent); + default: return QStyledItemDelegate::createEditor (parent, option, index); From dc37aea8ebd678b9824f0558b48085b30c61fe0a Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sat, 20 Jun 2015 21:00:15 +0300 Subject: [PATCH 1611/3725] Add missing mappings to TableMimeData --- apps/opencs/model/world/tablemimedata.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/opencs/model/world/tablemimedata.cpp b/apps/opencs/model/world/tablemimedata.cpp index d40e0c217..101bbf9ba 100644 --- a/apps/opencs/model/world/tablemimedata.cpp +++ b/apps/opencs/model/world/tablemimedata.cpp @@ -264,6 +264,8 @@ namespace { CSMWorld::UniversalId::Type_Texture, CSMWorld::ColumnBase::Display_Texture }, { CSMWorld::UniversalId::Type_Video, CSMWorld::ColumnBase::Display_Video }, { CSMWorld::UniversalId::Type_Global, CSMWorld::ColumnBase::Display_GlobalVariable }, + { CSMWorld::UniversalId::Type_BodyPart, CSMWorld::ColumnBase::Display_BodyPart }, + { CSMWorld::UniversalId::Type_Enchantment, CSMWorld::ColumnBase::Display_Enchantment }, { CSMWorld::UniversalId::Type_None, CSMWorld::ColumnBase::Display_None } // end marker }; From c65e7a31e7272ac450fc792ecfe690075e7e643e Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 21 Jun 2015 16:23:40 +1200 Subject: [PATCH 1612/3725] Aquatic creatures no longer try to get onto land. AiWander for aquatic creatures no longer uses path grid points as they're usually on land. --- apps/openmw/mwmechanics/aiwander.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 1f4133c0a..d89a29e1d 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -651,9 +651,6 @@ namespace MWMechanics if (mAllowedNodes.empty()) return; - if (actor.getClass().isPureWaterCreature(actor)) - return; - state.moveIn(new AiWanderStorage()); int index = OEngine::Misc::Rng::rollDice(mAllowedNodes.size()); @@ -700,7 +697,8 @@ namespace MWMechanics // actor can wander from the spawn position. AiWander assumes that // pathgrid points are available, and uses them to randomly select wander // destinations within the allowed set of pathgrid points (nodes). - if(mDistance) + // ... pathgrids don't usually include water, so swimmers ignore them + if (mDistance && !actor.getClass().isPureWaterCreature(actor)) { float cellXOffset = 0; float cellYOffset = 0; From 256545205226c44320eb813397bd23021f0e8a31 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sun, 21 Jun 2015 17:08:10 +0300 Subject: [PATCH 1613/3725] Add some drag'n'drop utils to work with TableMimeData --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/view/world/dragdroputils.cpp | 26 ++++++++++++++++++++ apps/opencs/view/world/dragdroputils.hpp | 30 ++++++++++++++++++++++++ 3 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 apps/opencs/view/world/dragdroputils.cpp create mode 100644 apps/opencs/view/world/dragdroputils.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index fa703e497..5386da707 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -70,7 +70,7 @@ opencs_units (view/world opencs_units_noqt (view/world subviews enumdelegate vartypedelegate recordstatusdelegate idtypedelegate datadisplaydelegate scripthighlighter idvalidator dialoguecreator physicssystem idcompletiondelegate - colordelegate + colordelegate dragdroputils ) opencs_units (view/widget diff --git a/apps/opencs/view/world/dragdroputils.cpp b/apps/opencs/view/world/dragdroputils.cpp new file mode 100644 index 000000000..7f3974e53 --- /dev/null +++ b/apps/opencs/view/world/dragdroputils.cpp @@ -0,0 +1,26 @@ +#include "dragdroputils.hpp" + +#include + +#include "../../model/world/tablemimedata.hpp" + +const CSMWorld::TableMimeData *CSVWorld::DragDropUtils::getTableMimeData(const QDropEvent &event) +{ + return dynamic_cast(event.mimeData()); +} + +bool CSVWorld::DragDropUtils::canAcceptData(const QDropEvent &event, CSMWorld::ColumnBase::Display type) +{ + const CSMWorld::TableMimeData *data = getTableMimeData(event); + return data != NULL && data->holdsType(type); +} + +CSMWorld::UniversalId CSVWorld::DragDropUtils::getAcceptedData(const QDropEvent &event, + CSMWorld::ColumnBase::Display type) +{ + if (canAcceptData(event, type)) + { + return getTableMimeData(event)->returnMatching(type); + } + return CSMWorld::UniversalId::Type_None; +} diff --git a/apps/opencs/view/world/dragdroputils.hpp b/apps/opencs/view/world/dragdroputils.hpp new file mode 100644 index 000000000..88e2958a5 --- /dev/null +++ b/apps/opencs/view/world/dragdroputils.hpp @@ -0,0 +1,30 @@ +#ifndef CSV_WORLD_DRAGDROPUTILS_HPP +#define CSV_WORLD_DRAGDROPUTILS_HPP + +#include "../../model/world/columnbase.hpp" + +class QDropEvent; + +namespace CSMWorld +{ + class TableMimeData; + class UniversalId; +} + +namespace CSVWorld +{ + class DragDropUtils + { + public: + static const CSMWorld::TableMimeData *getTableMimeData(const QDropEvent &event); + + static bool canAcceptData(const QDropEvent &event, CSMWorld::ColumnBase::Display type); + ///< Checks whether the \a event contains a valid CSMWorld::TableMimeData that holds the \a type + + static CSMWorld::UniversalId getAcceptedData(const QDropEvent &event, CSMWorld::ColumnBase::Display type); + ///< Gets the accepted data from the \a event using the \a type + ///< \return Type_None if the \a event data doesn't holds the \a type + }; +} + +#endif From a23de394f8ef2dd4c5fdb28b03cf8527cd42e3e0 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sun, 21 Jun 2015 17:16:13 +0300 Subject: [PATCH 1614/3725] Refine DropLineEdit code --- apps/opencs/view/widget/droplineedit.cpp | 69 ++++-------------------- apps/opencs/view/widget/droplineedit.hpp | 17 ++---- apps/opencs/view/world/util.cpp | 2 +- 3 files changed, 14 insertions(+), 74 deletions(-) diff --git a/apps/opencs/view/widget/droplineedit.cpp b/apps/opencs/view/widget/droplineedit.cpp index 6dae15746..98f1d81c3 100644 --- a/apps/opencs/view/widget/droplineedit.cpp +++ b/apps/opencs/view/widget/droplineedit.cpp @@ -3,33 +3,20 @@ #include #include "../../model/world/tablemimedata.hpp" +#include "../../model/world/universalid.hpp" -namespace -{ - const CSMWorld::TableMimeData *getEventMimeData(QDropEvent *event) - { - Q_ASSERT(event != NULL); - return dynamic_cast(event->mimeData()); - } -} +#include "../world/dragdroputils.hpp" -CSVWidget::DropLineEdit::DropLineEdit(CSMWorld::UniversalId::Type type, QWidget *parent) +CSVWidget::DropLineEdit::DropLineEdit(CSMWorld::ColumnBase::Display type, QWidget *parent) : QLineEdit(parent), mDropType(type) { setAcceptDrops(true); } -CSVWidget::DropLineEdit::DropLineEdit(CSMWorld::ColumnBase::Display display, QWidget *parent) - : QLineEdit(parent), - mDropType(CSMWorld::TableMimeData::convertEnums(display)) -{ - setAcceptDrops(true); -} - void CSVWidget::DropLineEdit::dragEnterEvent(QDragEnterEvent *event) { - if (canAcceptEventData(event)) + if (CSVWorld::DragDropUtils::canAcceptData(*event, mDropType)) { event->acceptProposedAction(); } @@ -37,7 +24,7 @@ void CSVWidget::DropLineEdit::dragEnterEvent(QDragEnterEvent *event) void CSVWidget::DropLineEdit::dragMoveEvent(QDragMoveEvent *event) { - if (canAcceptEventData(event)) + if (CSVWorld::DragDropUtils::canAcceptData(*event, mDropType)) { event->accept(); } @@ -45,48 +32,10 @@ void CSVWidget::DropLineEdit::dragMoveEvent(QDragMoveEvent *event) void CSVWidget::DropLineEdit::dropEvent(QDropEvent *event) { - const CSMWorld::TableMimeData *data = getEventMimeData(event); - if (data == NULL) // May happen when non-records (e.g. plain text) are dragged and dropped - { - return; - } - - int dataIndex = getAcceptedDataIndex(*data); - if (dataIndex != -1) - { - std::vector idData = data->getData(); - setText(idData[dataIndex].getId().c_str()); - emit tableMimeDataDropped(idData[dataIndex], data->getDocumentPtr()); - } -} - -bool CSVWidget::DropLineEdit::canAcceptEventData(QDropEvent *event) const -{ - const CSMWorld::TableMimeData *data = getEventMimeData(event); - if (data == NULL) // May happen when non-records (e.g. plain text) are dragged and dropped - { - return false; - } - return getAcceptedDataIndex(*data) != -1; -} - -int CSVWidget::DropLineEdit::getAcceptedDataIndex(const CSMWorld::TableMimeData &data) const -{ - if (mDropType == CSMWorld::UniversalId::Type_None) - { - return 0; - } - - bool isReferenceable = mDropType == CSMWorld::UniversalId::Type_Referenceable; - std::vector idData = data.getData(); - int size = static_cast(idData.size()); - for (int i = 0; i < size; ++i) + if (CSVWorld::DragDropUtils::canAcceptData(*event, mDropType)) { - CSMWorld::UniversalId::Type type = idData[i].getType(); - if (type == mDropType || isReferenceable && CSMWorld::TableMimeData::isReferencable(type)) - { - return i; - } + CSMWorld::UniversalId id = CSVWorld::DragDropUtils::getAcceptedData(*event, mDropType); + setText(id.getId().c_str()); + emit tableMimeDataDropped(id, CSVWorld::DragDropUtils::getTableMimeData(*event)->getDocumentPtr()); } - return -1; } diff --git a/apps/opencs/view/widget/droplineedit.hpp b/apps/opencs/view/widget/droplineedit.hpp index ce086b7dc..60832e71b 100644 --- a/apps/opencs/view/widget/droplineedit.hpp +++ b/apps/opencs/view/widget/droplineedit.hpp @@ -4,7 +4,6 @@ #include #include "../../model/world/columnbase.hpp" -#include "../../model/world/universalid.hpp" namespace CSMDoc { @@ -14,6 +13,7 @@ namespace CSMDoc namespace CSMWorld { class TableMimeData; + class UniversalId; } namespace CSVWidget @@ -22,20 +22,11 @@ namespace CSVWidget { Q_OBJECT - CSMWorld::UniversalId::Type mDropType; - ///< The accepted ID type for this LineEdit. - ///< If \a mDropType has Type_None type, this LineEdit accepts all ID types - - bool canAcceptEventData(QDropEvent *event) const; - ///< Checks whether the \a event contains CSMWorld::TableMimeData with a proper ID type - - int getAcceptedDataIndex(const CSMWorld::TableMimeData &data) const; - ///< Checks whether the \a data has a proper type - ///< \return -1 if there is no suitable data (ID type) + CSMWorld::ColumnBase::Display mDropType; + ///< The accepted Display type for this LineEdit. public: - DropLineEdit(CSMWorld::UniversalId::Type type, QWidget *parent = 0); - DropLineEdit(CSMWorld::ColumnBase::Display display, QWidget *parent = 0); + DropLineEdit(CSMWorld::ColumnBase::Display type, QWidget *parent = 0); protected: void dragEnterEvent(QDragEnterEvent *event); diff --git a/apps/opencs/view/world/util.cpp b/apps/opencs/view/world/util.cpp index 815505589..62cde4608 100644 --- a/apps/opencs/view/world/util.cpp +++ b/apps/opencs/view/world/util.cpp @@ -243,7 +243,7 @@ QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleO case CSMWorld::ColumnBase::Display_String: // For other Display types (that represent record IDs) with drop support IdCompletionDelegate is used - return new CSVWidget::DropLineEdit(CSMWorld::UniversalId::Type_None, parent); + return new CSVWidget::DropLineEdit(display, parent); default: From 44582fe3b329d928934015cb2924daf52c964503 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 21 Jun 2015 17:27:52 +0200 Subject: [PATCH 1615/3725] Don't use separate werewolf skills/attributes for non-player werewolves Still need to deal with save files. --- apps/openmw/mwmechanics/creaturestats.cpp | 11 ++--- apps/openmw/mwmechanics/creaturestats.hpp | 4 -- apps/openmw/mwmechanics/npcstats.cpp | 53 +++++++++-------------- apps/openmw/mwmechanics/npcstats.hpp | 5 ++- apps/openmw/mwworld/player.cpp | 49 +++++++++++++++++++++ apps/openmw/mwworld/player.hpp | 13 ++++++ apps/openmw/mwworld/worldimp.cpp | 11 +++++ components/esm/npcstats.cpp | 4 -- 8 files changed, 101 insertions(+), 49 deletions(-) diff --git a/apps/openmw/mwmechanics/creaturestats.cpp b/apps/openmw/mwmechanics/creaturestats.cpp index 308e72027..e5cb561bf 100644 --- a/apps/openmw/mwmechanics/creaturestats.cpp +++ b/apps/openmw/mwmechanics/creaturestats.cpp @@ -20,7 +20,7 @@ namespace MWMechanics mKnockdown(false), mKnockdownOneFrame(false), mKnockdownOverOneFrame(false), mHitRecovery(false), mBlock(false), mMovementFlags(0), mAttackStrength(0.f), mFallHeight(0), mRecalcMagicka(false), mLastRestock(0,0), mGoldPool(0), mActorId(-1), - mDeathAnimation(0), mIsWerewolf(false), mLevel (0) + mDeathAnimation(0), mLevel (0) { for (int i=0; i<4; ++i) mAiSettings[i] = 0; @@ -55,7 +55,7 @@ namespace MWMechanics if (index < 0 || index > 7) { throw std::runtime_error("attribute index is out of range"); } - return (!mIsWerewolf ? mAttributes[index] : mWerewolfAttributes[index]); + return mAttributes[index]; } const DynamicStat &CreatureStats::getHealth() const @@ -139,14 +139,11 @@ namespace MWMechanics throw std::runtime_error("attribute index is out of range"); } - const AttributeValue& currentValue = !mIsWerewolf ? mAttributes[index] : mWerewolfAttributes[index]; + const AttributeValue& currentValue = mAttributes[index]; if (value != currentValue) { - if(!mIsWerewolf) - mAttributes[index] = value; - else - mWerewolfAttributes[index] = value; + mAttributes[index] = value; if (index == ESM::Attribute::Intelligence) mRecalcMagicka = true; diff --git a/apps/openmw/mwmechanics/creaturestats.hpp b/apps/openmw/mwmechanics/creaturestats.hpp index 145eb8a5b..146d9fb1e 100644 --- a/apps/openmw/mwmechanics/creaturestats.hpp +++ b/apps/openmw/mwmechanics/creaturestats.hpp @@ -77,10 +77,6 @@ namespace MWMechanics std::vector mSummonGraveyard; protected: - // These two are only set by NpcStats, but they are declared in CreatureStats to prevent using virtual methods. - bool mIsWerewolf; - AttributeValue mWerewolfAttributes[8]; - int mLevel; public: diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index 94819e626..577c76c97 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -32,6 +32,7 @@ MWMechanics::NpcStats::NpcStats() , mWerewolfKills (0) , mLevelProgress(0) , mTimeToStartDrowning(20.0) + , mIsWerewolf(false) { mSkillIncreases.resize (ESM::Attribute::Length, 0); } @@ -51,7 +52,7 @@ const MWMechanics::SkillValue& MWMechanics::NpcStats::getSkill (int index) const if (index<0 || index>=ESM::Skill::Length) throw std::runtime_error ("skill index out of range"); - return (!mIsWerewolf ? mSkill[index] : mWerewolfSkill[index]); + return mSkill[index]; } MWMechanics::SkillValue& MWMechanics::NpcStats::getSkill (int index) @@ -59,7 +60,15 @@ MWMechanics::SkillValue& MWMechanics::NpcStats::getSkill (int index) if (index<0 || index>=ESM::Skill::Length) throw std::runtime_error ("skill index out of range"); - return (!mIsWerewolf ? mSkill[index] : mWerewolfSkill[index]); + return mSkill[index]; +} + +void MWMechanics::NpcStats::setSkill(int index, const MWMechanics::SkillValue &value) +{ + if (index<0 || index>=ESM::Skill::Length) + throw std::runtime_error ("skill index out of range"); + + mSkill[index] = value; } const std::map& MWMechanics::NpcStats::getFactionRanks() const @@ -188,10 +197,6 @@ float MWMechanics::NpcStats::getSkillProgressRequirement (int skillIndex, const void MWMechanics::NpcStats::useSkill (int skillIndex, const ESM::Class& class_, int usageType, float extraFactor) { - // Don't increase skills as a werewolf - if(mIsWerewolf) - return; - const ESM::Skill *skill = MWBase::Environment::get().getWorld()->getStore().get().find (skillIndex); float skillGain = 1; @@ -403,34 +408,12 @@ bool MWMechanics::NpcStats::isWerewolf() const void MWMechanics::NpcStats::setWerewolf (bool set) { + if (mIsWerewolf == set) + return; + if(set != false) { - const MWWorld::Store &gmst = MWBase::Environment::get().getWorld()->getStore().get(); - mWerewolfKills = 0; - - for(size_t i = 0;i < ESM::Attribute::Length;i++) - { - mWerewolfAttributes[i] = getAttribute(i); - // Oh, Bethesda. It's "Intelligence". - std::string name = "fWerewolf"+((i==ESM::Attribute::Intelligence) ? std::string("Intellegence") : - ESM::Attribute::sAttributeNames[i]); - mWerewolfAttributes[i].setBase(int(gmst.find(name)->getFloat())); - } - - for(size_t i = 0;i < ESM::Skill::Length;i++) - { - mWerewolfSkill[i] = getSkill(i); - - // Acrobatics is set separately for some reason. - if(i == ESM::Skill::Acrobatics) - continue; - - // "Mercantile"! >_< - std::string name = "fWerewolf"+((i==ESM::Skill::Mercantile) ? std::string("Merchantile") : - ESM::Skill::sSkillNames[i]); - mWerewolfSkill[i].setBase(int(gmst.find(name)->getFloat())); - } } mIsWerewolf = set; } @@ -466,12 +449,14 @@ void MWMechanics::NpcStats::writeState (ESM::NpcStats& state) const for (int i=0; i& getFactionRanks() const; /// Increase the rank in this faction by 1, if such a rank exists. diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index 0b81532e1..d0d99bfcf 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -49,6 +49,55 @@ namespace MWWorld mPlayer.mData.setPosition(playerPos); } + void Player::saveSkillsAttributes() + { + MWMechanics::NpcStats& stats = getPlayer().getClass().getNpcStats(getPlayer()); + for (int i=0; i& gmst = MWBase::Environment::get().getWorld()->getStore().get(); + MWMechanics::NpcStats& stats = getPlayer().getClass().getNpcStats(getPlayer()); + for(size_t i = 0;i < ESM::Attribute::Length;++i) + { + // Oh, Bethesda. It's "Intelligence". + std::string name = "fWerewolf"+((i==ESM::Attribute::Intelligence) ? std::string("Intellegence") : + ESM::Attribute::sAttributeNames[i]); + + MWMechanics::AttributeValue value = stats.getAttribute(i); + value.setBase(int(gmst.find(name)->getFloat())); + stats.setAttribute(i, value); + } + + for(size_t i = 0;i < ESM::Skill::Length;i++) + { + // Acrobatics is set separately for some reason. + if(i == ESM::Skill::Acrobatics) + continue; + + // "Mercantile"! >_< + std::string name = "fWerewolf"+((i==ESM::Skill::Mercantile) ? std::string("Merchantile") : + ESM::Skill::sSkillNames[i]); + + MWMechanics::SkillValue value = stats.getSkill(i); + value.setBase(int(gmst.find(name)->getFloat())); + stats.setSkill(i, value); + } + } + void Player::set(const ESM::NPC *player) { mPlayer.mBase = player; diff --git a/apps/openmw/mwworld/player.hpp b/apps/openmw/mwworld/player.hpp index 25d8981cd..2845c5822 100644 --- a/apps/openmw/mwworld/player.hpp +++ b/apps/openmw/mwworld/player.hpp @@ -6,6 +6,11 @@ #include "../mwmechanics/drawstate.hpp" +#include "../mwmechanics/stat.hpp" + +#include +#include + #include namespace ESM @@ -50,10 +55,18 @@ namespace MWWorld int mCurrentCrimeId; // the id assigned witnesses int mPaidCrimeId; // the last id paid off (0 bounty) + // Saved skills and attributes prior to becoming a werewolf + MWMechanics::SkillValue mSaveSkills[ESM::Skill::Length]; + MWMechanics::AttributeValue mSaveAttributes[ESM::Attribute::Length]; + public: Player(const ESM::NPC *player, const MWBase::World& world); + void saveSkillsAttributes(); + void restoreSkillsAttributes(); + void setWerewolfSkillsAttributes(); + // For mark/recall magic effects void markPosition (CellStore* markedCell, ESM::Position markedPosition); void getMarkedPosition (CellStore*& markedCell, ESM::Position& markedPosition) const; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 0f33f3d59..f8de9f65b 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2485,6 +2485,17 @@ namespace MWWorld if (npcStats.isWerewolf() == werewolf) return; + if (actor == getPlayerPtr()) + { + if (werewolf) + { + mPlayer->saveSkillsAttributes(); + mPlayer->setWerewolfSkillsAttributes(); + } + else + mPlayer->restoreSkillsAttributes(); + } + npcStats.setWerewolf(werewolf); // This is a bit dangerous. Equipped items other than WerewolfRobe may reference diff --git a/components/esm/npcstats.cpp b/components/esm/npcstats.cpp index cc1d6b3dd..fa808b72f 100644 --- a/components/esm/npcstats.cpp +++ b/components/esm/npcstats.cpp @@ -117,10 +117,6 @@ void ESM::NpcStats::save (ESMWriter &esm) const mSkills[i].mWerewolf.save (esm); } - esm.writeHNT ("HWAT", true); - for (int i=0; i<8; ++i) - mWerewolfAttributes[i].save (esm); - if (mIsWerewolf) esm.writeHNT ("WOLF", mIsWerewolf); From d6a7255391425d34512b8b05ac27db1c6fdbf30f Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 21 Jun 2015 17:36:11 +0200 Subject: [PATCH 1616/3725] Loading/saving for player's original skills/attributes (prior to becoming a werewolf) --- apps/openmw/mwworld/player.cpp | 10 ++++++++++ components/esm/player.cpp | 13 +++++++++++++ components/esm/player.hpp | 6 ++++++ 3 files changed, 29 insertions(+) diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index d0d99bfcf..e681bd7c5 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -271,6 +271,11 @@ namespace MWWorld player.mAutoMove = mAutoMove ? 1 : 0; + for (int i=0; i mSaveAttributes[ESM::Attribute::Length]; + StatState mSaveSkills[ESM::Skill::Length]; + void load (ESMReader &esm); void save (ESMWriter &esm) const; }; From b9882eb59ab0c8a13d64b9ed7ffa7b1bdff0f12a Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sun, 21 Jun 2015 18:40:13 +0300 Subject: [PATCH 1617/3725] DragRecordTable checks drag type before accepting it --- apps/opencs/view/world/dragrecordtable.cpp | 53 +++++++++++++++++++++- apps/opencs/view/world/dragrecordtable.hpp | 7 +++ apps/opencs/view/world/table.cpp | 30 ------------ apps/opencs/view/world/table.hpp | 2 - 4 files changed, 58 insertions(+), 34 deletions(-) diff --git a/apps/opencs/view/world/dragrecordtable.cpp b/apps/opencs/view/world/dragrecordtable.cpp index 2a1ae1f40..3712348e2 100644 --- a/apps/opencs/view/world/dragrecordtable.cpp +++ b/apps/opencs/view/world/dragrecordtable.cpp @@ -1,8 +1,14 @@ +#include "dragrecordtable.hpp" + #include #include +#include "../../model/doc/document.hpp" + #include "../../model/world/tablemimedata.hpp" -#include "dragrecordtable.hpp" +#include "../../model/world/commands.hpp" + +#include "dragdroputils.hpp" void CSVWorld::DragRecordTable::startDragFromTable (const CSVWorld::DragRecordTable& table) { @@ -35,5 +41,48 @@ void CSVWorld::DragRecordTable::dragEnterEvent(QDragEnterEvent *event) void CSVWorld::DragRecordTable::dragMoveEvent(QDragMoveEvent *event) { - event->accept(); + QModelIndex index = indexAt(event->pos()); + if (CSVWorld::DragDropUtils::canAcceptData(*event, getIndexDisplayType(index))) + { + event->accept(); + } + else + { + event->ignore(); + } +} + +void CSVWorld::DragRecordTable::dropEvent(QDropEvent *event) +{ + QModelIndex index = indexAt(event->pos()); + CSMWorld::ColumnBase::Display display = getIndexDisplayType(index); + if (CSVWorld::DragDropUtils::canAcceptData(*event, display)) + { + const CSMWorld::TableMimeData *data = CSVWorld::DragDropUtils::getTableMimeData(*event); + if (data->fromDocument(mDocument)) + { + CSMWorld::UniversalId id = CSVWorld::DragDropUtils::getAcceptedData(*event, display); + QVariant newIndexData = QString::fromUtf8(id.getId().c_str()); + QVariant oldIndexData = index.data(Qt::EditRole); + if (newIndexData != oldIndexData) + { + mDocument.getUndoStack().push(new CSMWorld::ModifyCommand(*model(), index, newIndexData)); + } + } + } +} + +CSMWorld::ColumnBase::Display CSVWorld::DragRecordTable::getIndexDisplayType(const QModelIndex &index) const +{ + Q_ASSERT(model() != NULL); + + if (index.isValid()) + { + QVariant display = model()->headerData(index.column(), Qt::Horizontal, CSMWorld::ColumnBase::Role_Display); + if (display.isValid()) + { + return static_cast(display.toInt()); + } + } + return CSMWorld::ColumnBase::Display_None; } diff --git a/apps/opencs/view/world/dragrecordtable.hpp b/apps/opencs/view/world/dragrecordtable.hpp index 48f9e2528..560864ba5 100644 --- a/apps/opencs/view/world/dragrecordtable.hpp +++ b/apps/opencs/view/world/dragrecordtable.hpp @@ -4,6 +4,8 @@ #include #include +#include "../../model/world/columnbase.hpp" + class QWidget; class QAction; @@ -38,6 +40,11 @@ namespace CSVWorld void dragEnterEvent(QDragEnterEvent *event); void dragMoveEvent(QDragMoveEvent *event); + + void dropEvent(QDropEvent *event); + + private: + CSMWorld::ColumnBase::Display getIndexDisplayType(const QModelIndex &index) const; }; } diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index 072b645c4..0ec701a65 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -697,36 +697,6 @@ void CSVWorld::Table::mouseMoveEvent (QMouseEvent* event) } } -void CSVWorld::Table::dropEvent(QDropEvent *event) -{ - QModelIndex index = indexAt (event->pos()); - - if (!index.isValid()) - { - return; - } - - const CSMWorld::TableMimeData* mime = dynamic_cast (event->mimeData()); - if (!mime) // May happen when non-records (e.g. plain text) are dragged and dropped - return; - - if (mime->fromDocument (mDocument)) - { - CSMWorld::ColumnBase::Display display = static_cast - (mModel->headerData (index.column(), Qt::Horizontal, CSMWorld::ColumnBase::Role_Display).toInt()); - - if (mime->holdsType (display)) - { - CSMWorld::UniversalId record (mime->returnMatching (display)); - - std::auto_ptr command (new CSMWorld::ModifyCommand - (*mProxyModel, index, QVariant (QString::fromUtf8 (record.getId().c_str())))); - - mDocument.getUndoStack().push (command.release()); - } - } //TODO handle drops from different document -} - std::vector CSVWorld::Table::getColumnsWithDisplay(CSMWorld::ColumnBase::Display display) const { const int count = mModel->columnCount(); diff --git a/apps/opencs/view/world/table.hpp b/apps/opencs/view/world/table.hpp index 67bf3fe85..38fcd83bd 100644 --- a/apps/opencs/view/world/table.hpp +++ b/apps/opencs/view/world/table.hpp @@ -76,8 +76,6 @@ namespace CSVWorld void mouseMoveEvent(QMouseEvent *event); - void dropEvent(QDropEvent *event); - protected: virtual void mouseDoubleClickEvent (QMouseEvent *event); From 2ce269c0fc2eff88d0dc0e2f7ce971255e842f1e Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 21 Jun 2015 18:18:24 +0200 Subject: [PATCH 1618/3725] Werewolf stats compatibility with old save files --- apps/openmw/mwmechanics/npcstats.cpp | 23 +++------------- apps/openmw/mwworld/player.cpp | 6 +++++ components/esm/esmreader.cpp | 11 ++++++++ components/esm/esmreader.hpp | 2 ++ components/esm/npcstats.cpp | 40 +++++++++++++++++++++------- components/esm/npcstats.hpp | 11 +++----- 6 files changed, 56 insertions(+), 37 deletions(-) diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index 577c76c97..b9aa8b301 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -447,16 +447,8 @@ void MWMechanics::NpcStats::writeState (ESM::NpcStats& state) const state.mDisposition = mDisposition; for (int i=0; i > skills(mSkills, mSkills + sizeof(mSkills)/sizeof(mSkills[0])); + + for (int i=0; i<27; ++i) + { + ESM::StatState skill; + skill.load(esm); + skills.push_back(skill); + } + + int i=0; + for (std::vector >::iterator it = skills.begin(); it != skills.end(); ++i) + { + if (i%2 == 1) + it = skills.erase(it); + else + ++it; + } + assert(skills.size() == 27); + std::copy(skills.begin(), skills.end(), mSkills); } + // No longer used bool hasWerewolfAttributes = false; esm.getHNOT (hasWerewolfAttributes, "HWAT"); - if (hasWerewolfAttributes) { + ESM::StatState dummy; for (int i=0; i<8; ++i) - mWerewolfAttributes[i].load (esm); + dummy.load(esm); + mWerewolfDeprecatedData = true; } mIsWerewolf = false; @@ -112,10 +136,7 @@ void ESM::NpcStats::save (ESMWriter &esm) const esm.writeHNT ("DISP", mDisposition); for (int i=0; i<27; ++i) - { - mSkills[i].mRegular.save (esm); - mSkills[i].mWerewolf.save (esm); - } + mSkills[i].save (esm); if (mIsWerewolf) esm.writeHNT ("WOLF", mIsWerewolf); @@ -147,6 +168,7 @@ void ESM::NpcStats::save (ESMWriter &esm) const void ESM::NpcStats::blank() { + mWerewolfDeprecatedData = false; mIsWerewolf = false; mDisposition = 0; mBounty = 0; diff --git a/components/esm/npcstats.hpp b/components/esm/npcstats.hpp index 0138ab209..9b27f587c 100644 --- a/components/esm/npcstats.hpp +++ b/components/esm/npcstats.hpp @@ -16,12 +16,6 @@ namespace ESM struct NpcStats { - struct Skill - { - StatState mRegular; - StatState mWerewolf; - }; - struct Faction { bool mExpelled; @@ -31,12 +25,13 @@ namespace ESM Faction(); }; - StatState mWerewolfAttributes[8]; bool mIsWerewolf; + bool mWerewolfDeprecatedData; + std::map mFactions; // lower case IDs int mDisposition; - Skill mSkills[27]; + StatState mSkills[27]; int mBounty; int mReputation; int mWerewolfKills; From d606b62688e14ea214d0939fec908c6996cf6b82 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sun, 21 Jun 2015 21:35:00 +0300 Subject: [PATCH 1619/3725] Nested tables accept drops --- apps/opencs/view/world/dragrecordtable.cpp | 12 +++++++-- apps/opencs/view/world/nestedtable.cpp | 29 +++++++++------------- apps/opencs/view/world/nestedtable.hpp | 12 +++------ 3 files changed, 26 insertions(+), 27 deletions(-) diff --git a/apps/opencs/view/world/dragrecordtable.cpp b/apps/opencs/view/world/dragrecordtable.cpp index 3712348e2..8d01cff3e 100644 --- a/apps/opencs/view/world/dragrecordtable.cpp +++ b/apps/opencs/view/world/dragrecordtable.cpp @@ -12,7 +12,13 @@ void CSVWorld::DragRecordTable::startDragFromTable (const CSVWorld::DragRecordTable& table) { - CSMWorld::TableMimeData* mime = new CSMWorld::TableMimeData (table.getDraggedRecords(), mDocument); + std::vector records = table.getDraggedRecords(); + if (records.empty()) + { + return; + } + + CSMWorld::TableMimeData* mime = new CSMWorld::TableMimeData (records, mDocument); if (mime) { @@ -27,7 +33,9 @@ CSVWorld::DragRecordTable::DragRecordTable (CSMDoc::Document& document, QWidget* QTableView(parent), mDocument(document), mEditLock(false) -{} +{ + setAcceptDrops(true); +} void CSVWorld::DragRecordTable::setEditLock (bool locked) { diff --git a/apps/opencs/view/world/nestedtable.cpp b/apps/opencs/view/world/nestedtable.cpp index 112873cb9..92df59a5f 100644 --- a/apps/opencs/view/world/nestedtable.cpp +++ b/apps/opencs/view/world/nestedtable.cpp @@ -14,8 +14,7 @@ CSVWorld::NestedTable::NestedTable(CSMDoc::Document& document, CSMWorld::UniversalId id, CSMWorld::NestedTableProxyModel* model, QWidget* parent) - : QTableView(parent), - mUndoStack(document.getUndoStack()), + : DragRecordTable(document, parent), mModel(model) { mDispatcher = new CSMWorld::CommandDispatcher (document, id, this); @@ -47,8 +46,6 @@ CSVWorld::NestedTable::NestedTable(CSMDoc::Document& document, setModel(model); - setAcceptDrops(true); - mAddNewRowAction = new QAction (tr ("Add new row"), this); connect(mAddNewRowAction, SIGNAL(triggered()), @@ -60,12 +57,10 @@ CSVWorld::NestedTable::NestedTable(CSMDoc::Document& document, this, SLOT(removeRowActionTriggered())); } -void CSVWorld::NestedTable::dragEnterEvent(QDragEnterEvent *event) -{ -} - -void CSVWorld::NestedTable::dragMoveEvent(QDragMoveEvent *event) +std::vector CSVWorld::NestedTable::getDraggedRecords() const { + // No drag support for nested tables + return std::vector(); } void CSVWorld::NestedTable::contextMenuEvent (QContextMenuEvent *event) @@ -84,16 +79,16 @@ void CSVWorld::NestedTable::contextMenuEvent (QContextMenuEvent *event) void CSVWorld::NestedTable::removeRowActionTriggered() { - mUndoStack.push(new CSMWorld::DeleteNestedCommand(*(mModel->model()), - mModel->getParentId(), - selectionModel()->selectedRows().begin()->row(), - mModel->getParentColumn())); + mDocument.getUndoStack().push(new CSMWorld::DeleteNestedCommand(*(mModel->model()), + mModel->getParentId(), + selectionModel()->selectedRows().begin()->row(), + mModel->getParentColumn())); } void CSVWorld::NestedTable::addNewRowActionTriggered() { - mUndoStack.push(new CSMWorld::AddNestedCommand(*(mModel->model()), - mModel->getParentId(), - selectionModel()->selectedRows().size(), - mModel->getParentColumn())); + mDocument.getUndoStack().push(new CSMWorld::AddNestedCommand(*(mModel->model()), + mModel->getParentId(), + selectionModel()->selectedRows().size(), + mModel->getParentColumn())); } diff --git a/apps/opencs/view/world/nestedtable.hpp b/apps/opencs/view/world/nestedtable.hpp index 5db977942..112920401 100644 --- a/apps/opencs/view/world/nestedtable.hpp +++ b/apps/opencs/view/world/nestedtable.hpp @@ -1,10 +1,10 @@ #ifndef CSV_WORLD_NESTEDTABLE_H #define CSV_WORLD_NESTEDTABLE_H -#include #include -class QUndoStack; +#include "dragrecordtable.hpp" + class QAction; class QContextMenuEvent; @@ -22,13 +22,12 @@ namespace CSMDoc namespace CSVWorld { - class NestedTable : public QTableView + class NestedTable : public DragRecordTable { Q_OBJECT QAction *mAddNewRowAction; QAction *mRemoveRowAction; - QUndoStack& mUndoStack; CSMWorld::NestedTableProxyModel* mModel; CSMWorld::CommandDispatcher *mDispatcher; @@ -38,10 +37,7 @@ namespace CSVWorld CSMWorld::NestedTableProxyModel* model, QWidget* parent = NULL); - protected: - void dragEnterEvent(QDragEnterEvent *event); - - void dragMoveEvent(QDragMoveEvent *event); + virtual std::vector getDraggedRecords() const; private: void contextMenuEvent (QContextMenuEvent *event); From 3f54f77647923571a42b4ceb5c18295ce25496c0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 21 Jun 2015 22:15:35 +0200 Subject: [PATCH 1620/3725] essimporter build fix --- apps/essimporter/convertacdt.cpp | 6 +++--- apps/essimporter/convertplayer.cpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/essimporter/convertacdt.cpp b/apps/essimporter/convertacdt.cpp index 55a20ec3d..8f090b3fc 100644 --- a/apps/essimporter/convertacdt.cpp +++ b/apps/essimporter/convertacdt.cpp @@ -41,9 +41,9 @@ namespace ESSImport { for (int i=0; i Date: Mon, 22 Jun 2015 21:06:27 +0200 Subject: [PATCH 1621/3725] Move head tracking from NpcAnimation to Animation (Bug #2720) --- apps/openmw/mwrender/animation.cpp | 48 ++++++++++++++++++++++ apps/openmw/mwrender/animation.hpp | 15 ++++--- apps/openmw/mwrender/creatureanimation.cpp | 1 + apps/openmw/mwrender/npcanimation.cpp | 44 ++------------------ apps/openmw/mwrender/npcanimation.hpp | 10 ----- 5 files changed, 62 insertions(+), 56 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 3801cf6fc..5955fc4cf 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -41,6 +41,7 @@ #include "vismask.hpp" #include "util.hpp" +#include "rotatecontroller.hpp" namespace { @@ -257,6 +258,8 @@ namespace MWRender , mResourceSystem(resourceSystem) , mAccumulate(1.f, 1.f, 0.f) , mTextKeyListener(NULL) + , mHeadYawRadians(0.f) + , mHeadPitchRadians(0.f) { for(size_t i = 0;i < sNumGroups;i++) mAnimationTimePtr[i].reset(new AnimationTime); @@ -900,6 +903,15 @@ namespace MWRender updateEffects(duration); + if (mHeadController) + { + const float epsilon = 0.001f; + bool enable = (std::abs(mHeadPitchRadians) > epsilon || std::abs(mHeadYawRadians) > epsilon); + mHeadController->setEnabled(enable); + if (enable) + mHeadController->setRotate(osg::Quat(mHeadPitchRadians, osg::Vec3f(1,0,0)) * osg::Quat(mHeadYawRadians, osg::Vec3f(0,0,1))); + } + return movement; } @@ -1212,6 +1224,42 @@ namespace MWRender return found->second; } + void Animation::addControllers() + { + mHeadController = NULL; + + NodeMap::iterator found = mNodeMap.find("bip01 head"); + if (found != mNodeMap.end() && dynamic_cast(found->second.get())) + { + osg::Node* node = found->second; + mHeadController = new RotateController(mObjectRoot.get()); + node->addUpdateCallback(mHeadController); + mActiveControllers.insert(std::make_pair(node, mHeadController)); + } + } + + void Animation::setHeadPitch(float pitchRadians) + { + mHeadPitchRadians = pitchRadians; + } + + void Animation::setHeadYaw(float yawRadians) + { + mHeadYawRadians = yawRadians; + } + + float Animation::getHeadPitch() const + { + return mHeadPitchRadians; + } + + float Animation::getHeadYaw() const + { + return mHeadYawRadians; + } + + // ------------------------------------------------------ + float Animation::AnimationTime::getValue(osg::NodeVisitor*) { if (mTimePtr) diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index d80fd96a4..1140fb172 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -25,6 +25,7 @@ namespace MWRender { class ResetAccumRootCallback; +class RotateController; class EffectAnimationTime : public SceneUtil::ControllerSource { @@ -197,6 +198,10 @@ protected: TextKeyListener* mTextKeyListener; + osg::ref_ptr mHeadController; + float mHeadYawRadians; + float mHeadPitchRadians; + /* Sets the appropriate animations on the bone groups based on priority. */ void resetActiveGroups(); @@ -243,7 +248,7 @@ protected: * Provided to allow derived classes adding their own controllers. Note, the controllers must be added to mActiveControllers * so they get cleaned up properly on the next controller rebuild. A controller rebuild may be necessary to ensure correct ordering. */ - virtual void addControllers() {} + virtual void addControllers(); osg::Vec4f getEnchantmentColor(MWWorld::Ptr item); @@ -374,10 +379,10 @@ public: /// @param effect Controls the radius and intensity of the light. virtual void setLightEffect(float effect) {} - virtual void setHeadPitch(float pitchRadians) {} - virtual void setHeadYaw(float yawRadians) {} - virtual float getHeadPitch() const {return 0.f;} - virtual float getHeadYaw() const {return 0.f;} + virtual void setHeadPitch(float pitchRadians); + virtual void setHeadYaw(float yawRadians); + virtual float getHeadPitch() const; + virtual float getHeadYaw() const; private: Animation(const Animation&); diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index 9d1fccdb2..ec4ee99e4 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -174,6 +174,7 @@ Resource::ResourceSystem *CreatureWeaponAnimation::getResourceSystem() void CreatureWeaponAnimation::addControllers() { + Animation::addControllers(); WeaponAnimation::addControllers(mNodeMap, mActiveControllers, mObjectRoot.get()); } diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 21ec8d535..2f2015432 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -243,9 +243,7 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, osg::ref_ptr par mShowCarriedLeft(true), mNpcType(Type_Normal), mAlpha(1.f), - mSoundsDisabled(disableSounds), - mHeadYawRadians(0.f), - mHeadPitchRadians(0.f) + mSoundsDisabled(disableSounds) { mNpc = mPtr.get()->mBase; @@ -650,40 +648,11 @@ osg::Vec3f NpcAnimation::runAnimation(float timepassed) mFirstPersonNeckController->setOffset(mFirstPersonOffset); } - if (mHeadController) - { - const float epsilon = 0.001f; - bool enable = (std::abs(mHeadPitchRadians) > epsilon || std::abs(mHeadYawRadians) > epsilon); - mHeadController->setEnabled(enable); - if (enable) - mHeadController->setRotate(osg::Quat(mHeadPitchRadians, osg::Vec3f(1,0,0)) * osg::Quat(mHeadYawRadians, osg::Vec3f(0,0,1))); - } - WeaponAnimation::configureControllers(mPtr.getRefData().getPosition().rot[0]); return ret; } -void NpcAnimation::setHeadPitch(float pitchRadians) -{ - mHeadPitchRadians = pitchRadians; -} - -void NpcAnimation::setHeadYaw(float yawRadians) -{ - mHeadYawRadians = yawRadians; -} - -float NpcAnimation::getHeadPitch() const -{ - return mHeadPitchRadians; -} - -float NpcAnimation::getHeadYaw() const -{ - return mHeadYawRadians; -} - void NpcAnimation::removeIndividualPart(ESM::PartReferenceType type) { mPartPriorities[type] = 0; @@ -843,6 +812,8 @@ void NpcAnimation::addPartGroup(int group, int priority, const std::vector(found->second.get())) - { - osg::Node* node = found->second; - mHeadController = new RotateController(mObjectRoot.get()); - node->addUpdateCallback(mHeadController); - mActiveControllers.insert(std::make_pair(node, mHeadController)); - } - WeaponAnimation::addControllers(mNodeMap, mActiveControllers, mObjectRoot.get()); } } diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 3eb4c4754..726d88605 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -49,7 +49,6 @@ public: }; class NeckController; -class RotateController; class NpcAnimation : public Animation, public WeaponAnimation, public MWWorld::InventoryStoreListener { @@ -101,9 +100,6 @@ private: float mAlpha; bool mSoundsDisabled; - float mHeadYawRadians; - float mHeadPitchRadians; - void updateNpcBase(); PartHolderPtr insertBoundedPart(const std::string &model, const std::string &bonename, @@ -119,7 +115,6 @@ private: bool enchantedGlow=false, osg::Vec4f* glowColor=NULL); osg::ref_ptr mFirstPersonNeckController; - osg::ref_ptr mHeadController; protected: virtual void addControllers(); @@ -151,11 +146,6 @@ public: /// to indicate the facing orientation of the character. virtual void setPitchFactor(float factor) { mPitchFactor = factor; } - virtual void setHeadPitch(float pitchRadians); - virtual void setHeadYaw(float yawRadians); - virtual float getHeadPitch() const; - virtual float getHeadYaw() const; - virtual void showWeapons(bool showWeapon); virtual void showCarriedLeft(bool show); From d5b73f2a558a8aa92ec338a2899921ae20e4435e Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 22 Jun 2015 21:12:15 +0200 Subject: [PATCH 1622/3725] Move HeadAnimationTime to the implementation file --- apps/openmw/mwrender/npcanimation.cpp | 35 +++++++++++++++++++++++++++ apps/openmw/mwrender/npcanimation.hpp | 34 +------------------------- 2 files changed, 36 insertions(+), 33 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 2f2015432..81782873e 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -75,6 +75,41 @@ std::string getVampireHead(const std::string& race, bool female) namespace MWRender { +class HeadAnimationTime : public SceneUtil::ControllerSource +{ +private: + MWWorld::Ptr mReference; + float mTalkStart; + float mTalkStop; + float mBlinkStart; + float mBlinkStop; + + float mBlinkTimer; + + bool mEnabled; + + float mValue; +private: + void resetBlinkTimer(); +public: + HeadAnimationTime(MWWorld::Ptr reference); + + void updatePtr(const MWWorld::Ptr& updated); + + void update(float dt); + + void setEnabled(bool enabled); + + void setTalkStart(float value); + void setTalkStop(float value); + void setBlinkStart(float value); + void setBlinkStop(float value); + + virtual float getValue(osg::NodeVisitor* nv); +}; + +// -------------------------------------------------------------------------------- + /// Subclass RotateController to add a Z-offset for sneaking in first person mode. /// @note We use inheritance instead of adding another controller, so that we do not have to compute the worldOrient twice. /// @note Must be set on a MatrixTransform. diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 726d88605..493629bda 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -15,40 +15,8 @@ namespace ESM namespace MWRender { -class HeadAnimationTime : public SceneUtil::ControllerSource -{ -private: - MWWorld::Ptr mReference; - float mTalkStart; - float mTalkStop; - float mBlinkStart; - float mBlinkStop; - - float mBlinkTimer; - - bool mEnabled; - - float mValue; -private: - void resetBlinkTimer(); -public: - HeadAnimationTime(MWWorld::Ptr reference); - - void updatePtr(const MWWorld::Ptr& updated); - - void update(float dt); - - void setEnabled(bool enabled); - - void setTalkStart(float value); - void setTalkStop(float value); - void setBlinkStart(float value); - void setBlinkStop(float value); - - virtual float getValue(osg::NodeVisitor* nv); -}; - class NeckController; +class HeadAnimationTime; class NpcAnimation : public Animation, public WeaponAnimation, public MWWorld::InventoryStoreListener { From d7695f2560dd36ef3b488daf263abb839361a7aa Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 22 Jun 2015 21:14:44 +0200 Subject: [PATCH 1623/3725] Remove unused NpcAnimation visibilityFlags --- apps/openmw/mwrender/characterpreview.cpp | 2 +- apps/openmw/mwrender/npcanimation.cpp | 2 +- apps/openmw/mwrender/npcanimation.hpp | 5 +---- apps/openmw/mwrender/objects.cpp | 2 +- 4 files changed, 4 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index d6c30da97..32e51c4d6 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -158,7 +158,7 @@ namespace MWRender delete mAnimation; mAnimation = NULL; - mAnimation = new NpcAnimation(mCharacter, mNode, mResourceSystem, 0, true, true, + mAnimation = new NpcAnimation(mCharacter, mNode, mResourceSystem, true, true, (renderHeadOnly() ? NpcAnimation::VM_HeadOnly : NpcAnimation::VM_Normal)); onSetup(); diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 81782873e..0e16d8ecc 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -270,7 +270,7 @@ NpcAnimation::~NpcAnimation() mPtr.getClass().getInventoryStore(mPtr).setListener(NULL, mPtr); } -NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, osg::ref_ptr parentNode, Resource::ResourceSystem* resourceSystem, int visibilityFlags, bool disableListener, bool disableSounds, ViewMode viewMode) +NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, osg::ref_ptr parentNode, Resource::ResourceSystem* resourceSystem, bool disableListener, bool disableSounds, ViewMode viewMode) : Animation(ptr, parentNode, resourceSystem), mListenerDisabled(disableListener), mViewMode(viewMode), diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 493629bda..2c1c66b8e 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -90,8 +90,6 @@ protected: public: /** * @param ptr - * @param node - * @param visibilityFlags * @param disableListener Don't listen for equipment changes and magic effects. InventoryStore only supports * one listener at a time, so you shouldn't do this if creating several NpcAnimations * for the same Ptr, eg preview dolls for the player. @@ -99,8 +97,7 @@ public: * @param disableSounds Same as \a disableListener but for playing items sounds * @param viewMode */ - NpcAnimation(const MWWorld::Ptr& ptr, osg::ref_ptr parentNode, Resource::ResourceSystem* resourceSystem, - int visibilityFlags, bool disableListener = false, + NpcAnimation(const MWWorld::Ptr& ptr, osg::ref_ptr parentNode, Resource::ResourceSystem* resourceSystem, bool disableListener = false, bool disableSounds = false, ViewMode viewMode=VM_Normal); virtual ~NpcAnimation(); diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 39e9f5652..bdefdcafa 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -156,7 +156,7 @@ void Objects::insertNPC(const MWWorld::Ptr &ptr) insertBegin(ptr); ptr.getRefData().getBaseNode()->setNodeMask(Mask_Actor); - std::auto_ptr anim (new NpcAnimation(ptr, osg::ref_ptr(ptr.getRefData().getBaseNode()), mResourceSystem, 0)); + std::auto_ptr anim (new NpcAnimation(ptr, osg::ref_ptr(ptr.getRefData().getBaseNode()), mResourceSystem)); mObjects.insert(std::make_pair(ptr, anim.release())); } From d3ef0759521c0ae0657769a7d0f373b8aa6be89b Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 23 Jun 2015 05:06:49 +0200 Subject: [PATCH 1624/3725] Fix an uninitialized variable --- components/esm/npcstats.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/components/esm/npcstats.cpp b/components/esm/npcstats.cpp index 6394a29da..e854410b1 100644 --- a/components/esm/npcstats.cpp +++ b/components/esm/npcstats.cpp @@ -32,6 +32,7 @@ void ESM::NpcStats::load (ESMReader &esm) for (int i=0; i<27; ++i) mSkills[i].load (esm); + mWerewolfDeprecatedData = false; if (esm.peekNextSub("STBA")) { // we have deprecated werewolf skills, stored interleaved From 33a3dabc313665a83384b373a5f5decba8974e54 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 24 Jun 2015 03:50:36 +0200 Subject: [PATCH 1625/3725] An alchemy effect listed more than once in the same ingredient should not automatically create a potion of that effect (Bug #2722) --- apps/openmw/mwmechanics/alchemy.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/alchemy.cpp b/apps/openmw/mwmechanics/alchemy.cpp index 58c42ddb8..1d43c71ff 100644 --- a/apps/openmw/mwmechanics/alchemy.cpp +++ b/apps/openmw/mwmechanics/alchemy.cpp @@ -44,6 +44,8 @@ std::set MWMechanics::Alchemy::listEffects() const { const MWWorld::LiveCellRef *ingredient = iter->get(); + std::set seenEffects; + for (int i=0; i<4; ++i) if (ingredient->mBase->mData.mEffectID[i]!=-1) { @@ -51,7 +53,8 @@ std::set MWMechanics::Alchemy::listEffects() const ingredient->mBase->mData.mEffectID[i], ingredient->mBase->mData.mSkills[i]!=-1 ? ingredient->mBase->mData.mSkills[i] : ingredient->mBase->mData.mAttributes[i]); - ++effects[key]; + if (seenEffects.insert(key).second) + ++effects[key]; } } } From 6f34a0501a0d8a2562716fd009983644e9d4ca5b Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 24 Jun 2015 03:52:27 +0200 Subject: [PATCH 1626/3725] Attempting to make a potion with no effects removes the ingredients (Fixes #2722) --- apps/openmw/mwmechanics/alchemy.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwmechanics/alchemy.cpp b/apps/openmw/mwmechanics/alchemy.cpp index 1d43c71ff..2fc9fe42f 100644 --- a/apps/openmw/mwmechanics/alchemy.cpp +++ b/apps/openmw/mwmechanics/alchemy.cpp @@ -463,7 +463,10 @@ MWMechanics::Alchemy::Result MWMechanics::Alchemy::create (const std::string& na return Result_NoName; if (listEffects().empty()) + { + removeIngredients(); return Result_NoEffects; + } if (beginEffects() == endEffects()) { From d1339a643afced0d1e502eebe79c947b2c4ad953 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Wed, 24 Jun 2015 15:07:09 +0300 Subject: [PATCH 1627/3725] Fix for NestedTableProxyModel::forwardDataChanged() --- apps/opencs/model/world/nestedtableproxymodel.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/opencs/model/world/nestedtableproxymodel.cpp b/apps/opencs/model/world/nestedtableproxymodel.cpp index acf197716..052e629aa 100644 --- a/apps/opencs/model/world/nestedtableproxymodel.cpp +++ b/apps/opencs/model/world/nestedtableproxymodel.cpp @@ -192,4 +192,8 @@ void CSMWorld::NestedTableProxyModel::forwardDataChanged (const QModelIndex& top emit dataChanged(index(0,0), index(mMainModel->rowCount(parent)-1, mMainModel->columnCount(parent)-1)); } + else if (topLeft.parent() == parent && bottomRight.parent() == parent) + { + emit dataChanged(index(topLeft.row(), topLeft.column()), index(bottomRight.row(), bottomRight.column())); + } } From 270c17faa786917ac03f44906c055eec70da577d Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Wed, 24 Jun 2015 16:36:09 +0300 Subject: [PATCH 1628/3725] Prevent drops on non-editable table cells --- apps/opencs/view/world/dragrecordtable.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/opencs/view/world/dragrecordtable.cpp b/apps/opencs/view/world/dragrecordtable.cpp index 8d01cff3e..5e8ddae26 100644 --- a/apps/opencs/view/world/dragrecordtable.cpp +++ b/apps/opencs/view/world/dragrecordtable.cpp @@ -52,7 +52,10 @@ void CSVWorld::DragRecordTable::dragMoveEvent(QDragMoveEvent *event) QModelIndex index = indexAt(event->pos()); if (CSVWorld::DragDropUtils::canAcceptData(*event, getIndexDisplayType(index))) { - event->accept(); + if (index.flags() & Qt::ItemIsEditable) + { + event->accept(); + } } else { From a1e29162bdb6da9069394c439a90a7e96cfa4e01 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Wed, 24 Jun 2015 15:54:00 +0200 Subject: [PATCH 1629/3725] Bring Ogre pre-build script up to OSG standard --- CI/before_script.msvc.sh | 385 ++++++++++++++++++++++++++++----------- 1 file changed, 280 insertions(+), 105 deletions(-) diff --git a/CI/before_script.msvc.sh b/CI/before_script.msvc.sh index 66f74520c..ae74146bc 100644 --- a/CI/before_script.msvc.sh +++ b/CI/before_script.msvc.sh @@ -8,6 +8,15 @@ while [ $# -gt 0 ]; do -v ) VERBOSE=true ;; + -d ) + SKIP_DOWNLOAD=true ;; + + -e ) + SKIP_EXTRACT=true ;; + + -k ) + KEEP=true ;; + * ) echo "Unknown arg $ARG." exit 1 ;; @@ -61,29 +70,46 @@ run_cmd() { } download() { - if ! [ -f $2 ]; then - printf " Downloading $2... " + if [ $# -lt 3 ]; then + echo "Invalid parameters to download." + return 1 + fi - if [ -z $VERBOSE ]; then - curl --silent --retry 10 -kLy 5 -o $2 $1 - RET=$? - else - curl --retry 10 -kLy 5 -o $2 $1 - RET=$? - fi + NAME=$1 + shift - if [ $RET -ne 0 ]; then - echo "Failed!" + echo "$NAME..." + + while [ $# -gt 1 ]; do + URL=$1 + FILE=$2 + shift + shift + + if ! [ -f $FILE ]; then + printf " Downloading $FILE... " + + if [ -z $VERBOSE ]; then + curl --silent --retry 10 -kLy 5 -o $FILE $URL + RET=$? + else + curl --retry 10 -kLy 5 -o $FILE $URL + RET=$? + fi + + if [ $RET -ne 0 ]; then + echo "Failed!" + else + echo "Done." + fi else - echo "Done" + echo " $FILE exists, skipping." fi + done - return $RET - else - echo " $2 exists, skipping." + if [ $# -ne 0 ]; then + echo "Missing parameter." fi - - return 0 } real_pwd() { @@ -95,6 +121,11 @@ add_cmake_opts() { CMAKE_OPTS="$CMAKE_OPTS $@" } +RUNTIME_DLLS="" +add_runtime_dlls() { + RUNTIME_DLLS="$RUNTIME_DLLS $@" +} + if [ -z $PLATFORM ]; then PLATFORM=`uname -m` fi @@ -128,6 +159,21 @@ case $PLATFORM in ;; esac + +case $CONFIGURATION in + debug|Debug|DEBUG ) + CONFIGURATION=Debug + ;; + + release|Release|RELEASE ) + CONFIGURATION=Release + ;; + + relwithdebinfo|RelWithDebInfo|RELWITHDEBINFO ) + CONFIGURATION=RelWithDebInfo + ;; +esac + echo echo "==========================" echo "Starting prebuild on win$BITS" @@ -139,58 +185,71 @@ cd deps DEPS="`pwd`" -echo "Downloading dependency packages." -echo - -# Boost -if [ -z $APPVEYOR ]; then - echo "Boost 1.58.0..." - download http://sourceforge.net/projects/boost/files/boost-binaries/1.58.0/boost_1_58_0-msvc-12.0-$BITS.exe boost-1.58.0-win$BITS.exe +if [ -z $SKIP_DOWNLOAD ]; then + echo "Downloading dependency packages." echo -fi - -# Bullet -echo "Bullet 2.83.4..." -download http://www.lysator.liu.se/~ace/OpenMW/deps/Bullet-2.83.4-win$BITS.7z Bullet-2.83.4-win$BITS.7z -echo - -# FFmpeg -echo "FFmpeg 2.5.2..." -download http://ffmpeg.zeranoe.com/builds/win$BITS/shared/ffmpeg-2.5.2-win$BITS-shared.7z ffmpeg$BITS-2.5.2.7z -download http://ffmpeg.zeranoe.com/builds/win$BITS/dev/ffmpeg-2.5.2-win$BITS-dev.7z ffmpeg$BITS-2.5.2-dev.7z -echo -# MyGUI -echo "MyGUI 3.2.2..." -download http://www.lysator.liu.se/~ace/OpenMW/deps/MyGUI-3.2.2-win$BITS.7z MyGUI-3.2.2-win$BITS.7z -echo + # Boost + if [ -z $APPVEYOR ]; then + download "Boost 1.58.0" \ + http://sourceforge.net/projects/boost/files/boost-binaries/1.58.0/boost_1_58_0-msvc-12.0-$BITS.exe \ + boost-1.58.0-win$BITS.exe + fi -# Ogre -echo "Ogre 1.9..." -download http://www.lysator.liu.se/~ace/OpenMW/deps/Ogre-1.9-win$BITS.7z Ogre-1.9-win$BITS.7z -echo + # Bullet + download "Bullet 2.83.5" \ + http://www.lysator.liu.se/~ace/OpenMW/deps/Bullet-2.83.5-win$BITS.7z \ + Bullet-2.83.5-win$BITS.7z + + # FFmpeg + download "FFmpeg 2.5.2" \ + http://ffmpeg.zeranoe.com/builds/win$BITS/shared/ffmpeg-2.5.2-win$BITS-shared.7z \ + ffmpeg$BITS-2.5.2.7z \ + http://ffmpeg.zeranoe.com/builds/win$BITS/dev/ffmpeg-2.5.2-win$BITS-dev.7z \ + ffmpeg$BITS-2.5.2-dev.7z + + # MyGUI + download "MyGUI 3.2.2" \ + http://www.lysator.liu.se/~ace/OpenMW/deps/MyGUI-3.2.2-win$BITS.7z \ + MyGUI-3.2.2-win$BITS.7z + + # OpenAL + download "OpenAL-Soft 1.16.0" \ + http://kcat.strangesoft.net/openal-soft-1.16.0-bin.zip \ + OpenAL-Soft-1.16.0.zip + + # Ogre + download "Ogre 1.9" \ + http://www.lysator.liu.se/~ace/OpenMW/deps/Ogre-1.9-win$BITS.7z \ + Ogre-1.9-win$BITS.7z + + # Qt + download "Qt 4.8.6" \ + http://sourceforge.net/projects/qt64ng/files/qt/$ARCHNAME/4.8.6/msvc2013/qt-4.8.6-x$ARCHSUFFIX-msvc2013.7z \ + qt$BITS-4.8.6.7z + + # SDL2 + download "SDL 2.0.3" \ + https://www.libsdl.org/release/SDL2-devel-2.0.3-VC.zip \ + SDL2-2.0.3.zip +fi -# OpenAL -echo "OpenAL-Soft 1.16.0..." -download http://kcat.strangesoft.net/openal-soft-1.16.0-bin.zip OpenAL-Soft-1.16.0.zip -echo +cd .. -# Qt -echo "Qt 4.8.6..." -download http://sourceforge.net/projects/qt64ng/files/qt/$ARCHNAME/4.8.6/msvc2013/qt-4.8.6-x$ARCHSUFFIX-msvc2013.7z qt$BITS-4.8.6.7z -echo +# Set up dependencies +if [ -z $KEEP ]; then + echo + printf "Preparing build directory... " -# SDL2 -echo "SDL 2.0.3 binaries..." -download https://www.libsdl.org/release/SDL2-devel-2.0.3-VC.zip SDL2-2.0.3.zip -echo + rm -rf Build_$BITS + mkdir -p Build_$BITS/deps -cd .. + echo Done. +fi +mkdir -p Build_$BITS/deps +cd Build_$BITS/deps -# Set up dependencies -rm -rf build_$BITS -mkdir -p build_$BITS/deps -cd deps +DEPS_INSTALL=`pwd` echo echo "Extracting dependencies..." @@ -198,11 +257,16 @@ echo "Extracting dependencies..." # Boost if [ -z $APPVEYOR ]; then printf "Boost 1.58.0... " - cd ../build_$BITS/deps + cd $DEPS_INSTALL BOOST_SDK="`real_pwd`/Boost" - $DEPS/boost-1.58.0-win$BITS.exe //dir="$(echo $BOOST_SDK | sed s,/,\\\\,g)" //verysilent + if [ -d Boost ] && grep "BOOST_VERSION 105800" Boost/boost/version.hpp > /dev/null; then + printf "Exists. " + elif [ -z $SKIP_EXTRACT ]; then + rm -rf Boost + $DEPS/boost-1.58.0-win$BITS.exe //dir="$(echo $BOOST_SDK | sed s,/,\\\\,g)" //verysilent + fi add_cmake_opts -DBOOST_ROOT="$BOOST_SDK" \ -DBOOST_LIBRARYDIR="$BOOST_SDK/lib$BITS-msvc-12.0" @@ -218,11 +282,16 @@ else fi # Bullet -printf "Bullet 2.83.4... " -cd ../build_$BITS/deps - -eval 7z x -y $DEPS/Bullet-2.83.4-win$BITS.7z $STRIP -mv Bullet-2.83.4-win$BITS Bullet +printf "Bullet 2.83.5... " +cd $DEPS_INSTALL + +if [ -d Bullet ]; then + printf "Exists. (No version checking) " +elif [ -z $SKIP_EXTRACT ]; then + rm -rf Bullet + eval 7z x -y $DEPS/Bullet-2.83.5-win$BITS.7z $STRIP + mv Bullet-2.83.5-win$BITS Bullet +fi BULLET_SDK="`real_pwd`/Bullet" add_cmake_opts -DBULLET_INCLUDE_DIR="$BULLET_SDK/include/bullet" \ @@ -239,14 +308,20 @@ echo Done. # FFmpeg printf "FFmpeg 2.5.2... " -cd ../build_$BITS/deps +cd $DEPS_INSTALL + +if [ -d FFmpeg ] && grep "FFmpeg version: 2.5.2" FFmpeg/README.txt > /dev/null; then + printf "Exists. " +elif [ -z $SKIP_EXTRACT ]; then + rm -rf FFmpeg -eval 7z x -y $DEPS/ffmpeg$BITS-2.5.2.7z $STRIP -eval 7z x -y $DEPS/ffmpeg$BITS-2.5.2-dev.7z $STRIP + eval 7z x -y $DEPS/ffmpeg$BITS-2.5.2.7z $STRIP + eval 7z x -y $DEPS/ffmpeg$BITS-2.5.2-dev.7z $STRIP -mv ffmpeg-2.5.2-win$BITS-shared FFmpeg -cp -r ffmpeg-2.5.2-win$BITS-dev/* FFmpeg/ -rm -rf ffmpeg-2.5.2-win$BITS-dev + mv ffmpeg-2.5.2-win$BITS-shared FFmpeg + cp -r ffmpeg-2.5.2-win$BITS-dev/* FFmpeg/ + rm -rf ffmpeg-2.5.2-win$BITS-dev +fi FFMPEG_SDK="`real_pwd`/FFmpeg" add_cmake_opts -DAVCODEC_INCLUDE_DIRS="$FFMPEG_SDK/include" \ @@ -264,6 +339,8 @@ add_cmake_opts -DAVCODEC_INCLUDE_DIRS="$FFMPEG_SDK/include" \ -DSWSCALE_INCLUDE_DIRS="$FFMPEG_SDK/include" \ -DSWSCALE_LIBRARIES="$FFMPEG_SDK/lib/swscale.lib" +add_runtime_dlls `pwd`/FFmpeg/bin/{avcodec-56,avformat-56,avutil-54,swresample-1,swscale-3}.dll + if [ $BITS -eq 32 ]; then add_cmake_opts "-DCMAKE_EXE_LINKER_FLAGS=\"/machine:X86 /safeseh:no\"" fi @@ -272,34 +349,64 @@ cd $DEPS echo Done. -# Ogre -printf "Ogre 1.9... " -cd ../build_$BITS/deps +# MyGUI +printf "MyGUI 3.2.2... " +cd $DEPS_INSTALL + +if [ -d MyGUI ] && \ + grep "MYGUI_VERSION_MAJOR 3" MyGUI/include/MYGUI/MyGUI_Prerequest.h > /dev/null && \ + grep "MYGUI_VERSION_MINOR 2" MyGUI/include/MYGUI/MyGUI_Prerequest.h > /dev/null && \ + grep "MYGUI_VERSION_PATCH 2" MyGUI/include/MYGUI/MyGUI_Prerequest.h > /dev/null +then + printf "Exists. " +elif [ -z $SKIP_EXTRACT ]; then + rm -rf MyGUI + eval 7z x -y $DEPS/MyGUI-3.2.2-win$BITS.7z $STRIP + mv MyGUI-3.2.2-win$BITS MyGUI +fi -eval 7z x -y $DEPS/Ogre-1.9-win$BITS.7z $STRIP -mv Ogre-1.9-win$BITS Ogre +MYGUI_SDK="`real_pwd`/MyGUI" -OGRE_SDK="`real_pwd`/Ogre" +add_cmake_opts -DMYGUISDK="$MYGUI_SDK" \ + -DMYGUI_INCLUDE_DIRS="$MYGUI_SDK/include" \ + -DMYGUI_PLATFORM_INCLUDE_DIRS="$MYGUI_SDK/include/MYGUI" \ + -DMYGUI_PREQUEST_FILE="$MYGUI_SDK/include/MYGUI/MyGUI_Prerequest.h" -add_cmake_opts -DOGRE_SDK="$OGRE_SDK" +if [ $CONFIGURATION == "Debug" ]; then + SUFFIX="_d" +else + SUFFIX="" +fi +add_runtime_dlls `pwd`/MyGUI/bin/$CONFIGURATION/MyGUIEngine$SUFFIX.dll cd $DEPS echo Done. -# MyGUI -printf "MyGUI 3.2.2... " -cd ../build_$BITS/deps +# Ogre +printf "Ogre 1.9... " +cd $DEPS_INSTALL + +if [ -d Ogre ]; then + printf "Exists. (No version check) " +elif [ -z $SKIP_EXTRACT ]; then + rm -rf Ogre + eval 7z x -y $DEPS/Ogre-1.9-win$BITS.7z $STRIP + mv Ogre-1.9-win$BITS Ogre +fi -eval 7z x -y $DEPS/MyGUI-3.2.2-win$BITS.7z $STRIP -mv MyGUI-3.2.2-win$BITS MyGUI +OGRE_SDK="`real_pwd`/Ogre" -MYGUI_SDK="`real_pwd`/MyGUI" +add_cmake_opts -DOGRE_SDK="$OGRE_SDK" -add_cmake_opts -DMYGUISDK="$MYGUI_SDK" \ - -DMYGUI_PLATFORM_INCLUDE_DIRS="$MYGUI_SDK/include/MYGUI" \ - -DMYGUI_INCLUDE_DIRS="$MYGUI_SDK/include" \ - -DMYGUI_PREQUEST_FILE="$MYGUI_SDK/include/MYGUI/MyGUI_Prerequest.h" +if [ $CONFIGURATION == "Debug" ]; then + SUFFIX="_d" +else + SUFFIX="" +fi + +add_runtime_dlls `pwd`/Ogre/bin/$CONFIGURATION/cg.dll \ + `pwd`/Ogre/bin/$CONFIGURATION/{OgreMain,OgreOverlay,Plugin_CgProgramManager,Plugin_ParticleFX,RenderSystem_Direct3D9,RenderSystem_GL}$SUFFIX.dll cd $DEPS @@ -307,21 +414,33 @@ echo Done. # OpenAL printf "OpenAL-Soft 1.16.0... " -eval 7z x -y OpenAL-Soft-1.16.0.zip $STRIP +if [ -d openal-soft-1.16.0-bin ]; then + printf "Exists. " +elif [ -z $SKIP_EXTRACT ]; then + rm -rf openal-soft-1.16.0-bin + eval 7z x -y OpenAL-Soft-1.16.0.zip $STRIP +fi OPENAL_SDK="`real_pwd`/openal-soft-1.16.0-bin" -add_cmake_opts -DOPENAL_INCLUDE_DIR="$OPENAL_SDK/include" \ +add_cmake_opts -DOPENAL_INCLUDE_DIR="$OPENAL_SDK/include/AL" \ -DOPENAL_LIBRARY="$OPENAL_SDK/libs/Win$BITS/OpenAL32.lib" + + echo Done. # Qt printf "Qt 4.8.6... " -cd ../build_$BITS/deps - -eval 7z x -y $DEPS/qt$BITS-4.8.6.7z $STRIP -mv qt-4.8.6-* Qt +cd $DEPS_INSTALL + +if [ -d Qt ] && head -n2 Qt/BUILDINFO.txt | grep "4.8.6" > /dev/null; then + printf "Exists. " +elif [ -z $SKIP_EXTRACT ]; then + rm -rf Qt + eval 7z x -y $DEPS/qt$BITS-4.8.6.7z $STRIP + mv qt-4.8.6-* Qt +fi QT_SDK="`real_pwd`/Qt" @@ -330,13 +449,26 @@ eval qtbinpatcher.exe $STRIP add_cmake_opts -DQT_QMAKE_EXECUTABLE="$QT_SDK/bin/qmake.exe" +if [ $CONFIGURATION == "Debug" ]; then + SUFFIX="d4" +else + SUFFIX="4" +fi +add_runtime_dlls `pwd`/bin/Qt{Core,Gui,Network,OpenGL}$SUFFIX.dll + cd $DEPS echo Done. # SDL2 printf "SDL 2.0.3... " -eval 7z x -y SDL2-2.0.3.zip $STRIP + +if [ -d SDL2-2.0.3 ]; then + printf "Exists. " +elif [ -z $SKIP_EXTRACT ]; then + rm -rf SDL2-2.0.3 + eval 7z x -y SDL2-2.0.3.zip $STRIP +fi SDL_SDK="`real_pwd`/SDL2-2.0.3" add_cmake_opts -DSDL2_INCLUDE_DIR="$SDL_SDK/include" \ @@ -344,23 +476,59 @@ add_cmake_opts -DSDL2_INCLUDE_DIR="$SDL_SDK/include" \ -DSDL2_LIBRARY_PATH="$SDL_SDK/lib/x$ARCHSUFFIX/SDL2.lib" \ -DSDL2_LIBRARY_ONLY="$SDL_SDK/lib/x$ARCHSUFFIX/SDL2.lib" +add_runtime_dlls `pwd`/SDL2-2.0.3/lib/x$ARCHSUFFIX/SDL2.dll + cd $DEPS echo Done. echo -cd ../build_$BITS +cd $DEPS_INSTALL/.. -echo "Building OpenMW..." +echo "Setting up OpenMW build..." add_cmake_opts -DBUILD_BSATOOL=no \ -DBUILD_ESMTOOL=no \ -DBUILD_MYGUI_PLUGIN=no \ - -DBUILD_OPENCS=no \ - -DBUILD_WIZARD=no \ - -DBUILD_ESSIMPORTER=no \ - -DBUILD_LAUNCHER=no \ - -DBUILD_MWINIIMPORTER=no + -DOPENMW_MP_BUILD=yes + +if [ -z $APPVEYOR ]; then + echo " (Outside of AppVeyor, doing full build.)" +else + case $STEP in + components ) + echo " Subproject: Components." + add_cmake_opts -DBUILD_ESSIMPORTER=no \ + -DBUILD_LAUNCHER=no \ + -DBUILD_MWINIIMPORTER=no \ + -DBUILD_OPENCS=no \ + -DBUILD_OPENMW=no \ + -DBUILD_WIZARD=no + rm -rf components + ;; + openmw ) + echo " Subproject: OpenMW." + add_cmake_opts -DBUILD_ESSIMPORTER=no \ + -DBUILD_LAUNCHER=no \ + -DBUILD_MWINIIMPORTER=no \ + -DBUILD_OPENCS=no \ + -DBUILD_WIZARD=no + ;; + opencs ) + echo " Subproject: OpenCS." + add_cmake_opts -DBUILD_ESSIMPORTER=no \ + -DBUILD_LAUNCHER=no \ + -DBUILD_MWINIIMPORTER=no \ + -DBUILD_OPENMW=no \ + -DBUILD_WIZARD=no + ;; + misc ) + echo " Subproject: Misc." + add_cmake_opts -DBUILD_OPENCS=no \ + -DBUILD_OPENMW=no + ;; + esac +fi if [ -z $VERBOSE ]; then printf " Configuring... " @@ -378,4 +546,11 @@ fi echo +echo "Copying Runtime DLLs..." +mkdir -p $CONFIGURATION +for DLL in $RUNTIME_DLLS; do + echo " `basename $DLL`." + cp "$DLL" $CONFIGURATION/ +done + exit $RET From e29d9bcc8eac923ecf90c73733302033e01c2700 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 24 Jun 2015 17:29:47 +0200 Subject: [PATCH 1630/3725] use a namespace instead of a class with only static functions --- apps/opencs/view/world/dragdroputils.hpp | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/apps/opencs/view/world/dragdroputils.hpp b/apps/opencs/view/world/dragdroputils.hpp index 88e2958a5..d1d780708 100644 --- a/apps/opencs/view/world/dragdroputils.hpp +++ b/apps/opencs/view/world/dragdroputils.hpp @@ -13,18 +13,17 @@ namespace CSMWorld namespace CSVWorld { - class DragDropUtils + namespace DragDropUtils { - public: - static const CSMWorld::TableMimeData *getTableMimeData(const QDropEvent &event); + const CSMWorld::TableMimeData *getTableMimeData(const QDropEvent &event); - static bool canAcceptData(const QDropEvent &event, CSMWorld::ColumnBase::Display type); - ///< Checks whether the \a event contains a valid CSMWorld::TableMimeData that holds the \a type + bool canAcceptData(const QDropEvent &event, CSMWorld::ColumnBase::Display type); + ///< Checks whether the \a event contains a valid CSMWorld::TableMimeData that holds the \a type - static CSMWorld::UniversalId getAcceptedData(const QDropEvent &event, CSMWorld::ColumnBase::Display type); - ///< Gets the accepted data from the \a event using the \a type - ///< \return Type_None if the \a event data doesn't holds the \a type - }; + CSMWorld::UniversalId getAcceptedData(const QDropEvent &event, CSMWorld::ColumnBase::Display type); + ///< Gets the accepted data from the \a event using the \a type + ///< \return Type_None if the \a event data doesn't holds the \a type + } } #endif From 21f0b586ec1d09828cf75117804b09df3c480f64 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Wed, 24 Jun 2015 20:01:29 +0300 Subject: [PATCH 1631/3725] Rows with the same topic but in different letter case can be reordered --- apps/opencs/model/world/infocollection.cpp | 3 ++- apps/opencs/view/world/table.cpp | 21 +++++++++++++++------ 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/apps/opencs/model/world/infocollection.cpp b/apps/opencs/model/world/infocollection.cpp index a508d28f3..560be8131 100644 --- a/apps/opencs/model/world/infocollection.cpp +++ b/apps/opencs/model/world/infocollection.cpp @@ -97,7 +97,8 @@ bool CSMWorld::InfoCollection::reorderRows (int baseIndex, const std::vector #include +#include + #include "../../model/doc/document.hpp" #include "../../model/world/data.hpp" @@ -128,17 +130,24 @@ void CSVWorld::Table::contextMenuEvent (QContextMenuEvent *event) { int row = mProxyModel->mapToSource ( mProxyModel->index (selectedRows.begin()->row(), 0)).row(); + QString curData = mModel->data(mModel->index(row, column)).toString(); - if (row>0 && mModel->data (mModel->index (row, column))== - mModel->data (mModel->index (row-1, column))) + if (row > 0) { - menu.addAction (mMoveUpAction); + QString prevData = mModel->data(mModel->index(row - 1, column)).toString(); + if (Misc::StringUtils::ciEqual(curData.toStdString(), prevData.toStdString())) + { + menu.addAction(mMoveUpAction); + } } - if (rowrowCount()-1 && mModel->data (mModel->index (row, column))== - mModel->data (mModel->index (row+1, column))) + if (row < mModel->rowCount() - 1) { - menu.addAction (mMoveDownAction); + QString nextData = mModel->data(mModel->index(row + 1, column)).toString(); + if (Misc::StringUtils::ciEqual(curData.toStdString(), nextData.toStdString())) + { + menu.addAction(mMoveDownAction); + } } } } From 9b09c7bbb0e666aa29c40cfa74db0b2cd654cba0 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Thu, 25 Jun 2015 09:02:30 +0200 Subject: [PATCH 1632/3725] Test the pre-existing Qt 5.4.1 install on Appveyor --- CI/before_script.msvc.sh | 83 +++++++++++++++++++++++++--------------- 1 file changed, 52 insertions(+), 31 deletions(-) diff --git a/CI/before_script.msvc.sh b/CI/before_script.msvc.sh index ae74146bc..f3db64020 100644 --- a/CI/before_script.msvc.sh +++ b/CI/before_script.msvc.sh @@ -224,9 +224,11 @@ if [ -z $SKIP_DOWNLOAD ]; then Ogre-1.9-win$BITS.7z # Qt - download "Qt 4.8.6" \ - http://sourceforge.net/projects/qt64ng/files/qt/$ARCHNAME/4.8.6/msvc2013/qt-4.8.6-x$ARCHSUFFIX-msvc2013.7z \ - qt$BITS-4.8.6.7z + if [ -z $APPVEYOR ]; then + download "Qt 4.8.6" \ + http://sourceforge.net/projects/qt64ng/files/qt/$ARCHNAME/4.8.6/msvc2013/qt-4.8.6-x$ARCHSUFFIX-msvc2013.7z \ + qt$BITS-4.8.6.7z + fi # SDL2 download "SDL 2.0.3" \ @@ -281,6 +283,7 @@ else -DBOOST_LIBRARYDIR="$BOOST_SDK/lib$BITS-msvc-12.0" fi + # Bullet printf "Bullet 2.83.5... " cd $DEPS_INSTALL @@ -306,6 +309,7 @@ cd $DEPS echo Done. + # FFmpeg printf "FFmpeg 2.5.2... " cd $DEPS_INSTALL @@ -349,6 +353,7 @@ cd $DEPS echo Done. + # MyGUI printf "MyGUI 3.2.2... " cd $DEPS_INSTALL @@ -383,6 +388,7 @@ cd $DEPS echo Done. + # Ogre printf "Ogre 1.9... " cd $DEPS_INSTALL @@ -412,6 +418,7 @@ cd $DEPS echo Done. + # OpenAL printf "OpenAL-Soft 1.16.0... " if [ -d openal-soft-1.16.0-bin ]; then @@ -426,39 +433,51 @@ OPENAL_SDK="`real_pwd`/openal-soft-1.16.0-bin" add_cmake_opts -DOPENAL_INCLUDE_DIR="$OPENAL_SDK/include/AL" \ -DOPENAL_LIBRARY="$OPENAL_SDK/libs/Win$BITS/OpenAL32.lib" - - echo Done. + # Qt -printf "Qt 4.8.6... " -cd $DEPS_INSTALL +if [ -z $APPVEYOR ]; then + printf "Qt 4.8.6... " + cd $DEPS_INSTALL -if [ -d Qt ] && head -n2 Qt/BUILDINFO.txt | grep "4.8.6" > /dev/null; then - printf "Exists. " -elif [ -z $SKIP_EXTRACT ]; then - rm -rf Qt - eval 7z x -y $DEPS/qt$BITS-4.8.6.7z $STRIP - mv qt-4.8.6-* Qt -fi + if [ -d Qt ] && head -n2 Qt/BUILDINFO.txt | grep "4.8.6" > /dev/null; then + printf "Exists. " + elif [ -z $SKIP_EXTRACT ]; then + rm -rf Qt + eval 7z x -y $DEPS/qt$BITS-4.8.6.7z $STRIP + mv qt-4.8.6-* Qt + fi -QT_SDK="`real_pwd`/Qt" + QT_SDK="`real_pwd`/Qt" -cd $QT_SDK -eval qtbinpatcher.exe $STRIP + cd $QT_SDK + eval qtbinpatcher.exe $STRIP -add_cmake_opts -DQT_QMAKE_EXECUTABLE="$QT_SDK/bin/qmake.exe" + add_cmake_opts -DQT_QMAKE_EXECUTABLE="$QT_SDK/bin/qmake.exe" -if [ $CONFIGURATION == "Debug" ]; then - SUFFIX="d4" + if [ $CONFIGURATION == "Debug" ]; then + SUFFIX="d4" + else + SUFFIX="4" + fi + add_runtime_dlls `pwd`/bin/Qt{Core,Gui,Network,OpenGL}$SUFFIX.dll + + cd $DEPS + + echo Done. else - SUFFIX="4" -fi -add_runtime_dlls `pwd`/bin/Qt{Core,Gui,Network,OpenGL}$SUFFIX.dll + echo "Using Appveyor Qt 5 version." + if [ $PLATFORM == "win32" ]; then + QT_SDK="C:/Qt/5.4/msvc2013_opengl" + else + QT_SDK="C:/Qt/5.4/msvc2013_64_opengl" + fi -cd $DEPS + add_cmake_opts -DDESIRED_QT_VERSION=4 \ + -DQT_QMAKE_EXECUTABLE="$QT_SDK/bin/qmake.exe" +fi -echo Done. # SDL2 printf "SDL 2.0.3... " @@ -546,11 +565,13 @@ fi echo -echo "Copying Runtime DLLs..." -mkdir -p $CONFIGURATION -for DLL in $RUNTIME_DLLS; do - echo " `basename $DLL`." - cp "$DLL" $CONFIGURATION/ -done +if [ -z $APPVEYOR ]; then + echo "Copying Runtime DLLs..." + mkdir -p $CONFIGURATION + for DLL in $RUNTIME_DLLS; do + echo " `basename $DLL`." + cp "$DLL" $CONFIGURATION/ + done +fi exit $RET From 5b82b9d9d0efc0a395c289e546bd87cae00dcea3 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Thu, 25 Jun 2015 11:20:35 +0300 Subject: [PATCH 1633/3725] ReferenceCreator accepts drops of Cell ID --- apps/opencs/view/world/referencecreator.cpp | 5 +++-- apps/opencs/view/world/referencecreator.hpp | 9 ++++++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/apps/opencs/view/world/referencecreator.cpp b/apps/opencs/view/world/referencecreator.cpp index 81efb17ab..2b0d44df0 100644 --- a/apps/opencs/view/world/referencecreator.cpp +++ b/apps/opencs/view/world/referencecreator.cpp @@ -2,7 +2,6 @@ #include "referencecreator.hpp" #include -#include #include "../../model/doc/document.hpp" @@ -12,6 +11,8 @@ #include "../../model/world/idtable.hpp" #include "../../model/world/idcompletionmanager.hpp" +#include "../widget/droplineedit.hpp" + std::string CSVWorld::ReferenceCreator::getId() const { return mId; @@ -80,7 +81,7 @@ CSVWorld::ReferenceCreator::ReferenceCreator (CSMWorld::Data& data, QUndoStack& QLabel *label = new QLabel ("Cell", this); insertBeforeButtons (label, false); - mCell = new QLineEdit (this); + mCell = new CSVWidget::DropLineEdit(CSMWorld::ColumnBase::Display_Cell, this); mCell->setCompleter(completionManager.getCompleter(CSMWorld::ColumnBase::Display_Cell).get()); insertBeforeButtons (mCell, true); diff --git a/apps/opencs/view/world/referencecreator.hpp b/apps/opencs/view/world/referencecreator.hpp index 7f56143c9..c230d0126 100644 --- a/apps/opencs/view/world/referencecreator.hpp +++ b/apps/opencs/view/world/referencecreator.hpp @@ -3,13 +3,16 @@ #include "genericcreator.hpp" -class QLineEdit; - namespace CSMWorld { class IdCompletionManager; } +namespace CSVWidget +{ + class DropLineEdit; +} + namespace CSVWorld { @@ -17,7 +20,7 @@ namespace CSVWorld { Q_OBJECT - QLineEdit *mCell; + CSVWidget::DropLineEdit *mCell; std::string mId; private: From d282bead236fe73611dba32f15220e6b73a1ca10 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Thu, 25 Jun 2015 11:24:19 +0300 Subject: [PATCH 1634/3725] InfoCreator accepts drops of Topic/Journal ID --- apps/opencs/view/world/infocreator.cpp | 5 +++-- apps/opencs/view/world/infocreator.hpp | 9 ++++++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/apps/opencs/view/world/infocreator.cpp b/apps/opencs/view/world/infocreator.cpp index 916427fc2..268a82a28 100644 --- a/apps/opencs/view/world/infocreator.cpp +++ b/apps/opencs/view/world/infocreator.cpp @@ -4,7 +4,6 @@ #include #include -#include #include #include @@ -17,6 +16,8 @@ #include "../../model/world/idtable.hpp" #include "../../model/world/idcompletionmanager.hpp" +#include "../widget/droplineedit.hpp" + std::string CSVWorld::InfoCreator::getId() const { std::string id = Misc::StringUtils::lowerCase (mTopic->text().toUtf8().constData()); @@ -48,12 +49,12 @@ CSVWorld::InfoCreator::InfoCreator (CSMWorld::Data& data, QUndoStack& undoStack, QLabel *label = new QLabel ("Topic", this); insertBeforeButtons (label, false); - mTopic = new QLineEdit (this); CSMWorld::ColumnBase::Display displayType = CSMWorld::ColumnBase::Display_Topic; if (getCollectionId().getType() == CSMWorld::UniversalId::Type_JournalInfos) { displayType = CSMWorld::ColumnBase::Display_Journal; } + mTopic = new CSVWidget::DropLineEdit(displayType, this); mTopic->setCompleter(completionManager.getCompleter(displayType).get()); insertBeforeButtons (mTopic, true); diff --git a/apps/opencs/view/world/infocreator.hpp b/apps/opencs/view/world/infocreator.hpp index 1928004bb..d131e3fac 100644 --- a/apps/opencs/view/world/infocreator.hpp +++ b/apps/opencs/view/world/infocreator.hpp @@ -3,21 +3,24 @@ #include "genericcreator.hpp" -class QLineEdit; - namespace CSMWorld { class InfoCollection; class IdCompletionManager; } +namespace CSVWidget +{ + class DropLineEdit; +} + namespace CSVWorld { class InfoCreator : public GenericCreator { Q_OBJECT - QLineEdit *mTopic; + CSVWidget::DropLineEdit *mTopic; virtual std::string getId() const; From 6fbdbb11d5c332913aa20d57707063245fb36d92 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 25 Jun 2015 12:03:40 +0200 Subject: [PATCH 1635/3725] added refrash menu item to report table (Fixes #2620) --- apps/opencs/model/doc/document.cpp | 4 ++-- apps/opencs/model/doc/document.hpp | 2 +- apps/opencs/model/tools/tools.cpp | 13 +++++++++---- apps/opencs/model/tools/tools.hpp | 7 +++++-- apps/opencs/view/tools/reportsubview.cpp | 22 ++++++++++++++++++++-- apps/opencs/view/tools/reportsubview.hpp | 6 ++++++ apps/opencs/view/tools/reporttable.cpp | 18 ++++++++++++++++-- apps/opencs/view/tools/reporttable.hpp | 9 ++++++++- 8 files changed, 67 insertions(+), 14 deletions(-) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 1e6ae5455..cb349d8be 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -2369,9 +2369,9 @@ void CSMDoc::Document::save() emit stateChanged (getState(), this); } -CSMWorld::UniversalId CSMDoc::Document::verify() +CSMWorld::UniversalId CSMDoc::Document::verify (const CSMWorld::UniversalId& reportId) { - CSMWorld::UniversalId id = mTools.runVerifier(); + CSMWorld::UniversalId id = mTools.runVerifier (reportId); emit stateChanged (getState(), this); return id; } diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp index 4aaaf40b0..557f3cb23 100644 --- a/apps/opencs/model/doc/document.hpp +++ b/apps/opencs/model/doc/document.hpp @@ -120,7 +120,7 @@ namespace CSMDoc void save(); - CSMWorld::UniversalId verify(); + CSMWorld::UniversalId verify (const CSMWorld::UniversalId& reportId = CSMWorld::UniversalId()); CSMWorld::UniversalId newSearch(); diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index f0d649f38..c9c116091 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -146,14 +146,19 @@ CSMTools::Tools::~Tools() delete iter->second; } -CSMWorld::UniversalId CSMTools::Tools::runVerifier() +CSMWorld::UniversalId CSMTools::Tools::runVerifier (const CSMWorld::UniversalId& reportId) { - mReports.insert (std::make_pair (mNextReportNumber++, new ReportModel)); - mActiveReports[CSMDoc::State_Verifying] = mNextReportNumber-1; + int reportNumber = reportId.getType()==CSMWorld::UniversalId::Type_VerificationResults ? + reportId.getIndex() : mNextReportNumber++; + + if (mReports.find (reportNumber)==mReports.end()) + mReports.insert (std::make_pair (reportNumber, new ReportModel)); + + mActiveReports[CSMDoc::State_Verifying] = reportNumber; getVerifier()->start(); - return CSMWorld::UniversalId (CSMWorld::UniversalId::Type_VerificationResults, mNextReportNumber-1); + return CSMWorld::UniversalId (CSMWorld::UniversalId::Type_VerificationResults, reportNumber); } CSMWorld::UniversalId CSMTools::Tools::newSearch() diff --git a/apps/opencs/model/tools/tools.hpp b/apps/opencs/model/tools/tools.hpp index 2912fc471..78484d15d 100644 --- a/apps/opencs/model/tools/tools.hpp +++ b/apps/opencs/model/tools/tools.hpp @@ -57,8 +57,11 @@ namespace CSMTools virtual ~Tools(); - CSMWorld::UniversalId runVerifier(); - ///< \return ID of the report for this verification run + /// \param reportId If a valid VerificationResults ID, run verifier for the + /// specified report instead of creating a new one. + /// + /// \return ID of the report for this verification run + CSMWorld::UniversalId runVerifier (const CSMWorld::UniversalId& reportId = CSMWorld::UniversalId()); /// Return ID of the report for this search. CSMWorld::UniversalId newSearch(); diff --git a/apps/opencs/view/tools/reportsubview.cpp b/apps/opencs/view/tools/reportsubview.cpp index 492874c01..42c4d40da 100644 --- a/apps/opencs/view/tools/reportsubview.cpp +++ b/apps/opencs/view/tools/reportsubview.cpp @@ -4,12 +4,18 @@ #include "reporttable.hpp" CSVTools::ReportSubView::ReportSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) -: CSVDoc::SubView (id) +: CSVDoc::SubView (id), mDocument (document), mRefreshState (0) { - setWidget (mTable = new ReportTable (document, id, false, this)); + if (id.getType()==CSMWorld::UniversalId::Type_VerificationResults) + mRefreshState = CSMDoc::State_Verifying; + + setWidget (mTable = new ReportTable (document, id, false, mRefreshState, this)); connect (mTable, SIGNAL (editRequest (const CSMWorld::UniversalId&, const std::string&)), SIGNAL (focusId (const CSMWorld::UniversalId&, const std::string&))); + + if (mRefreshState==CSMDoc::State_Verifying) + connect (mTable, SIGNAL (refreshRequest()), this, SLOT (refreshRequest())); } void CSVTools::ReportSubView::setEditLock (bool locked) @@ -21,3 +27,15 @@ void CSVTools::ReportSubView::updateUserSetting (const QString &name, const QStr { mTable->updateUserSetting (name, list); } + +void CSVTools::ReportSubView::refreshRequest() +{ + if (!(mDocument.getState() & mRefreshState)) + { + if (mRefreshState==CSMDoc::State_Verifying) + { + mTable->clear(); + mDocument.verify (getUniversalId()); + } + } +} diff --git a/apps/opencs/view/tools/reportsubview.hpp b/apps/opencs/view/tools/reportsubview.hpp index 7e8a08e3c..b8eb2690a 100644 --- a/apps/opencs/view/tools/reportsubview.hpp +++ b/apps/opencs/view/tools/reportsubview.hpp @@ -20,6 +20,8 @@ namespace CSVTools Q_OBJECT ReportTable *mTable; + CSMDoc::Document& mDocument; + int mRefreshState; public: @@ -28,6 +30,10 @@ namespace CSVTools virtual void setEditLock (bool locked); virtual void updateUserSetting (const QString &, const QStringList &); + + private slots: + + void refreshRequest(); }; } diff --git a/apps/opencs/view/tools/reporttable.cpp b/apps/opencs/view/tools/reporttable.cpp index e530e1159..6ef88bfdd 100644 --- a/apps/opencs/view/tools/reporttable.cpp +++ b/apps/opencs/view/tools/reporttable.cpp @@ -74,7 +74,12 @@ void CSVTools::ReportTable::contextMenuEvent (QContextMenuEvent *event) if (found) menu.addAction (mReplaceAction); + } + if (mRefreshAction) + { + mRefreshAction->setEnabled ((mDocument.getState() & mRefreshState)==0); + menu.addAction (mRefreshAction); } menu.exec (event->globalPos()); @@ -134,8 +139,10 @@ void CSVTools::ReportTable::mouseDoubleClickEvent (QMouseEvent *event) } CSVTools::ReportTable::ReportTable (CSMDoc::Document& document, - const CSMWorld::UniversalId& id, bool richTextDescription, QWidget *parent) -: CSVWorld::DragRecordTable (document, parent), mModel (document.getReport (id)) + const CSMWorld::UniversalId& id, bool richTextDescription, int refreshState, + QWidget *parent) +: CSVWorld::DragRecordTable (document, parent), mModel (document.getReport (id)), + mRefreshAction (0), mRefreshState (refreshState) { #if QT_VERSION >= QT_VERSION_CHECK(5,0,0) horizontalHeader()->setSectionResizeMode (QHeaderView::Interactive); @@ -171,6 +178,13 @@ CSVTools::ReportTable::ReportTable (CSMDoc::Document& document, connect (mReplaceAction, SIGNAL (triggered()), this, SIGNAL (replaceRequest())); addAction (mReplaceAction); + if (mRefreshState) + { + mRefreshAction = new QAction (tr ("Refresh"), this); + connect (mRefreshAction, SIGNAL (triggered()), this, SIGNAL (refreshRequest())); + addAction (mRefreshAction); + } + mDoubleClickActions.insert (std::make_pair (Qt::NoModifier, Action_Edit)); mDoubleClickActions.insert (std::make_pair (Qt::ShiftModifier, Action_Remove)); mDoubleClickActions.insert (std::make_pair (Qt::ControlModifier, Action_EditAndRemove)); diff --git a/apps/opencs/view/tools/reporttable.hpp b/apps/opencs/view/tools/reporttable.hpp index 95ab07cbb..4f77a57c4 100644 --- a/apps/opencs/view/tools/reporttable.hpp +++ b/apps/opencs/view/tools/reporttable.hpp @@ -36,7 +36,9 @@ namespace CSVTools QAction *mShowAction; QAction *mRemoveAction; QAction *mReplaceAction; + QAction *mRefreshAction; std::map mDoubleClickActions; + int mRefreshState; private: @@ -49,8 +51,11 @@ namespace CSVTools public: /// \param richTextDescription Use rich text in the description column. + /// \param refreshState Document state to check for refresh function. If value is + /// 0 no refresh function exists. If the document current has the specified state + /// the refresh function is disabled. ReportTable (CSMDoc::Document& document, const CSMWorld::UniversalId& id, - bool richTextDescription, QWidget *parent = 0); + bool richTextDescription, int refreshState = 0, QWidget *parent = 0); virtual std::vector getDraggedRecords() const; @@ -76,6 +81,8 @@ namespace CSVTools void editRequest (const CSMWorld::UniversalId& id, const std::string& hint); void replaceRequest(); + + void refreshRequest(); }; } From 71f3b7ed4f6ab80592dfbf4ef03669e5909535b7 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Thu, 25 Jun 2015 20:21:51 +1000 Subject: [PATCH 1636/3725] Fix crash when user preference is missing. --- apps/opencs/model/tools/scriptcheck.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/tools/scriptcheck.cpp b/apps/opencs/model/tools/scriptcheck.cpp index 928ae156f..665edd7a3 100644 --- a/apps/opencs/model/tools/scriptcheck.cpp +++ b/apps/opencs/model/tools/scriptcheck.cpp @@ -120,7 +120,7 @@ void CSMTools::ScriptCheckStage::perform (int stage, CSMDoc::Messages& messages) void CSMTools::ScriptCheckStage::updateUserSetting (const QString& name, const QStringList& value) { - if (name=="script-editor/warnings") + if (name=="script-editor/warnings" && !value.isEmpty()) { if (value.at (0)=="Ignore") mWarningMode = Mode_Ignore; From c0f3d70f0662b79c2a8fd66fdef0f8ec61e61f50 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Thu, 25 Jun 2015 20:23:43 +1000 Subject: [PATCH 1637/3725] Use the new severity message attribute. --- apps/opencs/model/tools/pathgridcheck.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/apps/opencs/model/tools/pathgridcheck.cpp b/apps/opencs/model/tools/pathgridcheck.cpp index 76edeb573..69ee5a809 100644 --- a/apps/opencs/model/tools/pathgridcheck.cpp +++ b/apps/opencs/model/tools/pathgridcheck.cpp @@ -30,9 +30,9 @@ void CSMTools::PathgridCheckStage::perform (int stage, CSMDoc::Messages& message // check the number of pathgrid points if (pathgrid.mData.mS2 > static_cast(pathgrid.mPoints.size())) - messages.push_back (std::make_pair (id, pathgrid.mId + " has less points than expected")); + messages.add (id, pathgrid.mId + " has less points than expected", "", CSMDoc::Message::Severity_Error); else if (pathgrid.mData.mS2 > static_cast(pathgrid.mPoints.size())) - messages.push_back (std::make_pair (id, pathgrid.mId + " has more points than expected")); + messages.add (id, pathgrid.mId + " has more points than expected", "", CSMDoc::Message::Severity_Error); std::vector pointList(pathgrid.mPoints.size()); std::vector duplList; @@ -51,7 +51,7 @@ void CSMTools::PathgridCheckStage::perform (int stage, CSMDoc::Messages& message std::ostringstream ss; ss << "has a duplicate edge between points" << pathgrid.mEdges[i].mV0 << " and " << pathgrid.mEdges[i].mV1; - messages.push_back (std::make_pair (id, pathgrid.mId + ss.str())); + messages.add (id, pathgrid.mId + ss.str(), "", CSMDoc::Message::Severity_Error); break; } } @@ -64,7 +64,7 @@ void CSMTools::PathgridCheckStage::perform (int stage, CSMDoc::Messages& message { std::ostringstream ss; ss << " has an edge connecting a non-existent point " << pathgrid.mEdges[i].mV0; - messages.push_back (std::make_pair (id, pathgrid.mId + ss.str())); + messages.add (id, pathgrid.mId + ss.str(), "", CSMDoc::Message::Severity_Error); } } @@ -75,13 +75,13 @@ void CSMTools::PathgridCheckStage::perform (int stage, CSMDoc::Messages& message { std::ostringstream ss; ss << " has has less edges than expected for point " << i; - messages.push_back (std::make_pair (id, pathgrid.mId + ss.str())); + messages.add (id, pathgrid.mId + ss.str(), "", CSMDoc::Message::Severity_Error); } else if (pathgrid.mPoints[i].mConnectionNum < pointList[i].mConnectionNum) { std::ostringstream ss; ss << " has has more edges than expected for point " << i; - messages.push_back (std::make_pair (id, pathgrid.mId + ss.str())); + messages.add (id, pathgrid.mId + ss.str(), "", CSMDoc::Message::Severity_Error); } // check that edges are bidirectional @@ -101,7 +101,7 @@ void CSMTools::PathgridCheckStage::perform (int stage, CSMDoc::Messages& message { std::ostringstream ss; ss << " has a missing edge between points " << i << " and " << pointList[i].mOtherIndex[j]; - messages.push_back (std::make_pair (id, pathgrid.mId + ss.str())); + messages.add (id, pathgrid.mId + ss.str(), "", CSMDoc::Message::Severity_Error); } } @@ -124,7 +124,7 @@ void CSMTools::PathgridCheckStage::perform (int stage, CSMDoc::Messages& message << ") x=" << pathgrid.mPoints[i].mX << ", y=" << pathgrid.mPoints[i].mY << ", z=" << pathgrid.mPoints[i].mZ; - messages.push_back (std::make_pair (id, pathgrid.mId + ss.str())); + messages.add (id, pathgrid.mId + ss.str(), "", CSMDoc::Message::Severity_Warning); duplList.push_back(i); break; @@ -143,7 +143,7 @@ void CSMTools::PathgridCheckStage::perform (int stage, CSMDoc::Messages& message << ") x=" << pathgrid.mPoints[i].mX << ", y=" << pathgrid.mPoints[i].mY << ", z=" << pathgrid.mPoints[i].mZ; - messages.push_back (std::make_pair (id, pathgrid.mId + ss.str())); + messages.add (id, pathgrid.mId + ss.str(), "", CSMDoc::Message::Severity_Warning); } } From 69db0179ca104699d70142286a5a1d226177644f Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 25 Jun 2015 13:05:57 +0200 Subject: [PATCH 1638/3725] update refresh menu item on stateChanged signal instead of when opening the menu --- apps/opencs/view/tools/reportsubview.cpp | 5 +++++ apps/opencs/view/tools/reporttable.cpp | 10 +++++++--- apps/opencs/view/tools/reporttable.hpp | 4 ++++ 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/apps/opencs/view/tools/reportsubview.cpp b/apps/opencs/view/tools/reportsubview.cpp index 42c4d40da..e29447f25 100644 --- a/apps/opencs/view/tools/reportsubview.cpp +++ b/apps/opencs/view/tools/reportsubview.cpp @@ -15,7 +15,12 @@ CSVTools::ReportSubView::ReportSubView (const CSMWorld::UniversalId& id, CSMDoc: SIGNAL (focusId (const CSMWorld::UniversalId&, const std::string&))); if (mRefreshState==CSMDoc::State_Verifying) + { connect (mTable, SIGNAL (refreshRequest()), this, SLOT (refreshRequest())); + + connect (&document, SIGNAL (stateChanged (int, CSMDoc::Document *)), + mTable, SLOT (stateChanged (int, CSMDoc::Document *))); + } } void CSVTools::ReportSubView::setEditLock (bool locked) diff --git a/apps/opencs/view/tools/reporttable.cpp b/apps/opencs/view/tools/reporttable.cpp index 6ef88bfdd..ca6b0dabf 100644 --- a/apps/opencs/view/tools/reporttable.cpp +++ b/apps/opencs/view/tools/reporttable.cpp @@ -77,10 +77,7 @@ void CSVTools::ReportTable::contextMenuEvent (QContextMenuEvent *event) } if (mRefreshAction) - { - mRefreshAction->setEnabled ((mDocument.getState() & mRefreshState)==0); menu.addAction (mRefreshAction); - } menu.exec (event->globalPos()); } @@ -181,6 +178,7 @@ CSVTools::ReportTable::ReportTable (CSMDoc::Document& document, if (mRefreshState) { mRefreshAction = new QAction (tr ("Refresh"), this); + mRefreshAction->setEnabled (!(mDocument.getState() & mRefreshState)); connect (mRefreshAction, SIGNAL (triggered()), this, SIGNAL (refreshRequest())); addAction (mRefreshAction); } @@ -301,3 +299,9 @@ void CSVTools::ReportTable::clear() { mModel->clear(); } + +void CSVTools::ReportTable::stateChanged (int state, CSMDoc::Document *document) +{ + if (mRefreshAction) + mRefreshAction->setEnabled (!(state & mRefreshState)); +} diff --git a/apps/opencs/view/tools/reporttable.hpp b/apps/opencs/view/tools/reporttable.hpp index 4f77a57c4..e19b327e4 100644 --- a/apps/opencs/view/tools/reporttable.hpp +++ b/apps/opencs/view/tools/reporttable.hpp @@ -76,6 +76,10 @@ namespace CSVTools void removeSelection(); + public slots: + + void stateChanged (int state, CSMDoc::Document *document); + signals: void editRequest (const CSMWorld::UniversalId& id, const std::string& hint); From 3a21f05f6eb05623f8179b4e0ff889f7dbe258a9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 25 Jun 2015 17:23:01 +0200 Subject: [PATCH 1639/3725] Rain effect --- apps/openmw/mwrender/sky.cpp | 155 +++++++++++++++++++++++++++++++---- apps/openmw/mwrender/sky.hpp | 16 +++- 2 files changed, 152 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index e2f3dd82b..96771eaa3 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -7,10 +7,16 @@ #include #include #include - #include #include +#include +#include +#include +#include +#include +#include + #include #include @@ -573,6 +579,7 @@ SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneMana , mRainEnabled(false) , mRainSpeed(0) , mRainFrequency(1) + , mWindSpeed(0.f) , mEnabled(true) , mSunEnabled(true) { @@ -642,9 +649,112 @@ void SkyManager::create() mCreated = true; } +class RainShooter : public osgParticle::Shooter +{ +public: + RainShooter() + : mAngle(0.f) + { + } + + virtual void shoot(osgParticle::Particle* particle) const + { + particle->setVelocity(mVelocity); + particle->setAngle(osg::Vec3f(-mAngle, 0, (Misc::Rng::rollProbability() * 2 - 1) * osg::PI)); + } + + void setVelocity(const osg::Vec3f& velocity) + { + mVelocity = velocity; + } + + void setAngle(float angle) + { + mAngle = angle; + } + + virtual osg::Object* cloneType() const + { + return new RainShooter; + } + virtual osg::Object* clone(const osg::CopyOp &) const + { + return new RainShooter(*this); + } + +private: + osg::Vec3f mVelocity; + float mAngle; +}; + +void SkyManager::createRain() +{ + if (mRainNode) + return; + + mRainNode = new osg::Group; + + mRainParticleSystem = new osgParticle::ParticleSystem; + mRainParticleSystem->setParticleAlignment(osgParticle::ParticleSystem::FIXED); + mRainParticleSystem->setAlignVectorX(osg::Vec3f(0.1,0,0)); + mRainParticleSystem->setAlignVectorY(osg::Vec3f(0,0,-1)); + + osg::ref_ptr stateset (mRainParticleSystem->getOrCreateStateSet()); + stateset->setTextureAttributeAndModes(0, mSceneManager->getTextureManager()->getTexture2D("textures/tx_raindrop_01.dds", + osg::Texture::CLAMP, osg::Texture::CLAMP), osg::StateAttribute::ON); + stateset->setNestRenderBins(false); + stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); + stateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF); + stateset->setMode(GL_CULL_FACE, osg::StateAttribute::OFF); + + osgParticle::Particle& particleTemplate = mRainParticleSystem->getDefaultParticleTemplate(); + particleTemplate.setSizeRange(osgParticle::rangef(5.f, 15.f)); + particleTemplate.setAlphaRange(osgParticle::rangef(1.f, 1.f)); + particleTemplate.setLifeTime(1); + + osg::ref_ptr emitter (new osgParticle::ModularEmitter); + emitter->setParticleSystem(mRainParticleSystem); + + osg::ref_ptr placer (new osgParticle::BoxPlacer); + placer->setXRange(-300, 300); // Rain_Diameter + placer->setYRange(-300, 300); + placer->setZRange(300, 300); + emitter->setPlacer(placer); + + osg::ref_ptr counter (new osgParticle::ConstantRateCounter); + counter->setNumberOfParticlesPerSecondToCreate(600.0); + emitter->setCounter(counter); + + osg::ref_ptr shooter (new RainShooter); + mRainShooter = shooter; + emitter->setShooter(shooter); + + osg::ref_ptr updater (new osgParticle::ParticleSystemUpdater); + updater->addParticleSystem(mRainParticleSystem); + + osg::ref_ptr geode (new osg::Geode); + geode->addDrawable(mRainParticleSystem); + + mRainNode->addChild(emitter); + mRainNode->addChild(geode); + mRainNode->addChild(updater); + + mRootNode->addChild(mRainNode); +} + +void SkyManager::destroyRain() +{ + if (!mRainNode) + return; + + mRootNode->removeChild(mRainNode); + mRainNode = NULL; + mRainParticleSystem = NULL; + mRainShooter = NULL; +} + SkyManager::~SkyManager() { - clearRain(); if (mRootNode) { mRootNode->getParent(0)->removeChild(mRootNode); @@ -664,14 +774,6 @@ int SkyManager::getSecundaPhase() const return mSecunda->getPhaseInt(); } -void SkyManager::clearRain() -{ -} - -void SkyManager::updateRain(float dt) -{ -} - void SkyManager::update(float duration) { if (!mEnabled) return; @@ -688,8 +790,6 @@ void SkyManager::update(float duration) else mCloudNode->setAttitude(osg::Quat()); - updateRain(duration); - // UV Scroll the clouds mCloudAnimationTimer += duration * mCloudSpeed * 0.003; mCloudUpdater->setAnimationTimer(mCloudAnimationTimer); @@ -736,9 +836,6 @@ void SkyManager::setEnabled(bool enabled) if (enabled && !mCreated) create(); - if (!enabled) - clearRain(); - mRootNode->setNodeMask(enabled ? Mask_Sky : 0); mEnabled = enabled; @@ -750,14 +847,38 @@ void SkyManager::setMoonColour (bool red) mSecunda->setColor(red ? mMoonScriptColor : osg::Vec4f(1,1,1,1)); } +void SkyManager::updateRainParameters() +{ + if (mRainShooter) + { + float angle = mWindSpeed/2.f * osg::PI/4; + mRainShooter->setVelocity(osg::Vec3f(0, mRainSpeed * mWindSpeed / 2.f, -mRainSpeed)); + mRainShooter->setAngle(angle); + } +} + void SkyManager::setWeather(const MWWorld::WeatherResult& weather) { if (!mCreated) return; - mRainEffect = weather.mRainEffect; - mRainEnabled = !mRainEffect.empty(); + if (mRainEffect != weather.mRainEffect) + { + mRainEffect = weather.mRainEffect; + if (!mRainEffect.empty()) + { + createRain(); + } + else + { + destroyRain(); + } + } + mRainFrequency = weather.mRainFrequency; mRainSpeed = weather.mRainSpeed; + mWindSpeed = weather.mWindSpeed; + updateRainParameters(); + mIsStorm = weather.mIsStorm; if (mCurrentParticleEffect != weather.mParticleEffect) diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index b05845e53..f9b9407ec 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -12,6 +12,11 @@ namespace osg class Material; } +namespace osgParticle +{ + class ParticleSystem; +} + namespace Resource { class SceneManager; @@ -24,6 +29,7 @@ namespace MWRender class CloudUpdater; class Sun; class Moon; + class RainShooter; class SkyManager { @@ -87,8 +93,9 @@ namespace MWRender void create(); ///< no need to call this, automatically done on first enable() - void updateRain(float dt); - void clearRain(); + void createRain(); + void destroyRain(); + void updateRainParameters(); Resource::SceneManager* mSceneManager; @@ -116,6 +123,10 @@ namespace MWRender std::auto_ptr mMasser; std::auto_ptr mSecunda; + osg::ref_ptr mRainNode; + osg::ref_ptr mRainParticleSystem; + osg::ref_ptr mRainShooter; + bool mCreated; bool mIsStorm; @@ -151,6 +162,7 @@ namespace MWRender std::string mRainEffect; float mRainSpeed; float mRainFrequency; + float mWindSpeed; bool mEnabled; bool mSunEnabled; From 8a3889a81eef72e9113b4c9cb5b8090b933b0bcb Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 25 Jun 2015 17:38:08 +0200 Subject: [PATCH 1640/3725] Rain fading --- apps/openmw/mwrender/sky.cpp | 46 ++++++++++++++++++++++++++++++++---- apps/openmw/mwrender/sky.hpp | 2 ++ 2 files changed, 43 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 96771eaa3..e5563409d 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -687,6 +687,37 @@ private: float mAngle; }; +class RainFader : public SceneUtil::StateSetUpdater +{ +public: + RainFader() + : mAlpha(1.f) + { + } + + void setAlpha(float alpha) + { + mAlpha = alpha; + } + + virtual void setDefaults(osg::StateSet* stateset) + { + osg::ref_ptr mat (new osg::Material); + mat->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(1,1,1,1)); + mat->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(0,0,0,1)); + stateset->setAttributeAndModes(mat, osg::StateAttribute::ON); + } + + virtual void apply(osg::StateSet* stateset, osg::NodeVisitor* nv) + { + osg::Material* mat = static_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); + mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0,0,0,mAlpha)); + } + +private: + float mAlpha; +}; + void SkyManager::createRain() { if (mRainNode) @@ -704,7 +735,6 @@ void SkyManager::createRain() osg::Texture::CLAMP, osg::Texture::CLAMP), osg::StateAttribute::ON); stateset->setNestRenderBins(false); stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); - stateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF); stateset->setMode(GL_CULL_FACE, osg::StateAttribute::OFF); osgParticle::Particle& particleTemplate = mRainParticleSystem->getDefaultParticleTemplate(); @@ -739,6 +769,9 @@ void SkyManager::createRain() mRainNode->addChild(geode); mRainNode->addChild(updater); + mRainFader = new RainFader; + mRainNode->addUpdateCallback(mRainFader); + mRootNode->addChild(mRainNode); } @@ -751,6 +784,7 @@ void SkyManager::destroyRain() mRainNode = NULL; mRainParticleSystem = NULL; mRainShooter = NULL; + mRainFader = NULL; } SkyManager::~SkyManager() @@ -851,8 +885,9 @@ void SkyManager::updateRainParameters() { if (mRainShooter) { - float angle = mWindSpeed/2.f * osg::PI/4; - mRainShooter->setVelocity(osg::Vec3f(0, mRainSpeed * mWindSpeed / 2.f, -mRainSpeed)); + float windFactor = mWindSpeed/3.f; + float angle = windFactor * osg::PI/4; + mRainShooter->setVelocity(osg::Vec3f(0, mRainSpeed * windFactor, -mRainSpeed)); mRainShooter->setAngle(angle); } } @@ -991,9 +1026,10 @@ void SkyManager::setWeather(const MWWorld::WeatherResult& weather) if (mParticle.get()) setAlpha(mParticle, weather.mEffectFade); - for (std::map::iterator it = mRainModels.begin(); it != mRainModels.end(); ++it) - setAlpha(it->second, weather.mEffectFade); */ + + if (mRainFader) + mRainFader->setAlpha(weather.mEffectFade * 0.6); // * Rain_Threshold? } void SkyManager::setGlare(const float glare) diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index f9b9407ec..85174896b 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -30,6 +30,7 @@ namespace MWRender class Sun; class Moon; class RainShooter; + class RainFader; class SkyManager { @@ -126,6 +127,7 @@ namespace MWRender osg::ref_ptr mRainNode; osg::ref_ptr mRainParticleSystem; osg::ref_ptr mRainShooter; + osg::ref_ptr mRainFader; bool mCreated; From b93cba9a698e353f0da6d19fed41fcb7bdf773a2 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Thu, 25 Jun 2015 18:16:59 +0200 Subject: [PATCH 1641/3725] Push messages properly --- CI/before_script.msvc.sh | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/CI/before_script.msvc.sh b/CI/before_script.msvc.sh index f3db64020..2652e9898 100644 --- a/CI/before_script.msvc.sh +++ b/CI/before_script.msvc.sh @@ -51,12 +51,9 @@ run_cmd() { if [ $RET -ne 0 ]; then if [ -z $APPVEYOR ]; then echo "Command $CMD failed, output can be found in `real_pwd`/output.log" - exit $RET else - 7z a output.7z output.log > /dev/null 2>&1 - - appveyor PushArtifact output.7z -FileName $CMD-output.7z - appveyor AddMessage "Command $CMD failed (code $RET), output has been pushed as an artifact." -Category Error + appveyor AddMessage "Command $CMD failed." -Category Error -Details "$CMD $@" + while read in; do appveyor AddMessage "$in" -Category Error; done < output.log fi else rm output.log From 867ce686ae3bbd4b571c467502d035334f63304c Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Thu, 25 Jun 2015 19:30:53 +0300 Subject: [PATCH 1642/3725] Proper conversion to QString for DropLineEdit::dropEvent() --- apps/opencs/view/widget/droplineedit.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/view/widget/droplineedit.cpp b/apps/opencs/view/widget/droplineedit.cpp index 98f1d81c3..1df598cb8 100644 --- a/apps/opencs/view/widget/droplineedit.cpp +++ b/apps/opencs/view/widget/droplineedit.cpp @@ -35,7 +35,7 @@ void CSVWidget::DropLineEdit::dropEvent(QDropEvent *event) if (CSVWorld::DragDropUtils::canAcceptData(*event, mDropType)) { CSMWorld::UniversalId id = CSVWorld::DragDropUtils::getAcceptedData(*event, mDropType); - setText(id.getId().c_str()); + setText(QString::fromUtf8(id.getId().c_str())); emit tableMimeDataDropped(id, CSVWorld::DragDropUtils::getTableMimeData(*event)->getDocumentPtr()); } } From 844e5c504d6d9f00d93e083274243fb1730c5112 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Thu, 25 Jun 2015 19:41:26 +0300 Subject: [PATCH 1643/3725] Fix conversion to QString --- apps/opencs/model/world/infotableproxymodel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/world/infotableproxymodel.cpp b/apps/opencs/model/world/infotableproxymodel.cpp index 3e564506c..4ee9fa60c 100644 --- a/apps/opencs/model/world/infotableproxymodel.cpp +++ b/apps/opencs/model/world/infotableproxymodel.cpp @@ -9,7 +9,7 @@ namespace { QString toLower(const QString &str) { - return Misc::StringUtils::lowerCase(str.toStdString()).c_str(); + return QString::fromUtf8(Misc::StringUtils::lowerCase(str.toStdString()).c_str()); } } From ea97b0a20c3556f5f76d885677df2322ffe8cf04 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Thu, 25 Jun 2015 20:08:42 +0300 Subject: [PATCH 1644/3725] Refine InfoTableProxyModel::getFirstInfoRow() code --- .../model/world/infotableproxymodel.cpp | 25 ++++++++----------- .../model/world/infotableproxymodel.hpp | 3 +++ 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/apps/opencs/model/world/infotableproxymodel.cpp b/apps/opencs/model/world/infotableproxymodel.cpp index 4ee9fa60c..e34c50566 100644 --- a/apps/opencs/model/world/infotableproxymodel.cpp +++ b/apps/opencs/model/world/infotableproxymodel.cpp @@ -16,7 +16,9 @@ namespace CSMWorld::InfoTableProxyModel::InfoTableProxyModel(CSMWorld::UniversalId::Type type, QObject *parent) : IdTableProxyModel(parent), mType(type), - mSourceModel(NULL) + mSourceModel(NULL), + mInfoColumnId(type == UniversalId::Type_TopicInfos ? Columns::ColumnId_Topic : + Columns::ColumnId_Journal) { Q_ASSERT(type == UniversalId::Type_TopicInfos || type == UniversalId::Type_JournalInfos); } @@ -54,26 +56,21 @@ bool CSMWorld::InfoTableProxyModel::lessThan(const QModelIndex &left, const QMod int CSMWorld::InfoTableProxyModel::getFirstInfoRow(int currentRow) const { - Columns::ColumnId columnId = Columns::ColumnId_Topic; - if (mType == UniversalId::Type_JournalInfos) - { - columnId = Columns::ColumnId_Journal; - } - - int column = mSourceModel->findColumnIndex(columnId); - QString info = toLower(mSourceModel->data(mSourceModel->index(currentRow, column)).toString()); + int row = currentRow; + int column = mSourceModel->findColumnIndex(mInfoColumnId); + QString info = toLower(mSourceModel->data(mSourceModel->index(row, column)).toString()); if (mFirstRowCache.contains(info)) { return mFirstRowCache[info]; } - while (--currentRow >= 0 && - toLower(mSourceModel->data(mSourceModel->index(currentRow, column)).toString()) == info); - ++currentRow; + while (--row >= 0 && + toLower(mSourceModel->data(mSourceModel->index(row, column)).toString()) == info); + ++row; - mFirstRowCache[info] = currentRow; - return currentRow; + mFirstRowCache[info] = row; + return row; } void CSMWorld::InfoTableProxyModel::modelRowsChanged(const QModelIndex &/*parent*/, int /*start*/, int /*end*/) diff --git a/apps/opencs/model/world/infotableproxymodel.hpp b/apps/opencs/model/world/infotableproxymodel.hpp index 7b0cd8ede..28d6017b3 100644 --- a/apps/opencs/model/world/infotableproxymodel.hpp +++ b/apps/opencs/model/world/infotableproxymodel.hpp @@ -4,6 +4,7 @@ #include #include "idtableproxymodel.hpp" +#include "columns.hpp" #include "universalid.hpp" namespace CSMWorld @@ -16,6 +17,8 @@ namespace CSMWorld UniversalId::Type mType; IdTableBase *mSourceModel; + Columns::ColumnId mInfoColumnId; + ///< Contains ID for Topic or Journal ID mutable QHash mFirstRowCache; From 331d87d738f7a23c577b7955a7a72c13e8a9554f Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Thu, 25 Jun 2015 19:19:04 +0200 Subject: [PATCH 1645/3725] Bring over some more OSG changes to the Appveyor scripts, and properly use Qt --- CI/before_script.msvc.sh | 13 +++++++------ appveyor.yml | 27 +++++++++++++-------------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/CI/before_script.msvc.sh b/CI/before_script.msvc.sh index 2652e9898..06b14f2fe 100644 --- a/CI/before_script.msvc.sh +++ b/CI/before_script.msvc.sh @@ -52,8 +52,9 @@ run_cmd() { if [ -z $APPVEYOR ]; then echo "Command $CMD failed, output can be found in `real_pwd`/output.log" else - appveyor AddMessage "Command $CMD failed." -Category Error -Details "$CMD $@" - while read in; do appveyor AddMessage "$in" -Category Error; done < output.log + echo + echo "Command $CMD failed;" + cat output.log fi else rm output.log @@ -451,7 +452,8 @@ if [ -z $APPVEYOR ]; then cd $QT_SDK eval qtbinpatcher.exe $STRIP - add_cmake_opts -DQT_QMAKE_EXECUTABLE="$QT_SDK/bin/qmake.exe" + add_cmake_opts -DDESIRED_QT_VERSION=4 \ + -DQT_QMAKE_EXECUTABLE="$QT_SDK/bin/qmake.exe" if [ $CONFIGURATION == "Debug" ]; then SUFFIX="d4" @@ -471,7 +473,7 @@ else QT_SDK="C:/Qt/5.4/msvc2013_64_opengl" fi - add_cmake_opts -DDESIRED_QT_VERSION=4 \ + add_cmake_opts -DDESIRED_QT_VERSION=5 \ -DQT_QMAKE_EXECUTABLE="$QT_SDK/bin/qmake.exe" fi @@ -505,8 +507,7 @@ echo "Setting up OpenMW build..." add_cmake_opts -DBUILD_BSATOOL=no \ -DBUILD_ESMTOOL=no \ - -DBUILD_MYGUI_PLUGIN=no \ - -DOPENMW_MP_BUILD=yes + -DBUILD_MYGUI_PLUGIN=no if [ -z $APPVEYOR ]; then echo " (Outside of AppVeyor, doing full build.)" diff --git a/appveyor.yml b/appveyor.yml index e46dd3dd8..a71df2155 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -6,28 +6,25 @@ platform: configuration: - Debug - - Release + +environment: + matrix: + - STEP: openmw + - STEP: opencs + - STEP: misc matrix: fast_finish: true os: unstable -clone_depth: 5 +clone_depth: 1 cache: - - C:\projects\openmw\deps\Bullet-2.83.4-win32.7z -> CI/before_script.msvc.sh - - C:\projects\openmw\deps\Bullet-2.83.4-win64.7z -> CI/before_script.msvc.sh - - C:\projects\openmw\deps\MyGUI-3.2.2-win32.7z -> CI/before_script.msvc.sh - - C:\projects\openmw\deps\MyGUI-3.2.2-win64.7z -> CI/before_script.msvc.sh - - C:\projects\openmw\deps\Ogre-1.9-win32.7z -> CI/before_script.msvc.sh - - C:\projects\openmw\deps\Ogre-1.9-win64.7z -> CI/before_script.msvc.sh - - C:\projects\openmw\deps\ffmpeg32-2.5.2.7z -> CI/before_script.msvc.sh - - C:\projects\openmw\deps\ffmpeg64-2.5.2-dev.7z -> CI/before_script.msvc.sh - - C:\projects\openmw\deps\ffmpeg64-2.5.2.7z -> CI/before_script.msvc.sh - - C:\projects\openmw\deps\ffmpeg64-2.5.2-dev.7z -> CI/before_script.msvc.sh - - C:\projects\openmw\deps\OpenAL-Soft-1.16.0.zip -> CI/before_script.msvc.sh - - C:\projects\openmw\deps\SDL2-2.0.3.zip -> CI/before_script.msvc.sh + - C:\projects\openmw\deps\ffmpeg32-2.5.2.7z + - C:\projects\openmw\deps\ffmpeg32-2.5.2-dev.7z + - C:\projects\openmw\deps\ffmpeg64-2.5.2.7z + - C:\projects\openmw\deps\ffmpeg64-2.5.2-dev.7z init: - cmd: bash --version @@ -42,3 +39,5 @@ build_script: before_build: - cmd: bash --login C:\projects\openmw\CI\before_script.msvc.sh + +test: off From ea0339d471638b4718f0515fe7a58d0b15361d34 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 25 Jun 2015 21:45:59 +0200 Subject: [PATCH 1646/3725] Make the string argument to BetaComment optional --- apps/openmw/mwscript/docs/vmformat.txt | 6 ++++-- apps/openmw/mwscript/miscextensions.cpp | 20 ++++++++++++-------- components/compiler/extensions0.cpp | 4 ++-- components/compiler/opcodes.hpp | 4 ++-- 4 files changed, 20 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index 93720aef6..42c204ecb 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -58,6 +58,8 @@ op 0x20029: PCRaiseRank, explicit reference op 0x2002a: PCLowerRank, explicit reference op 0x2002b: PCJoinFaction, explicit reference op 0x2002c: MenuTest +op 0x2002d: BetaComment +op 0x2002e: BetaComment, explicit reference opcodes 0x2002d-0x3ffff unused Segment 4: @@ -396,8 +398,8 @@ op 0x2000243: GetFactionReaction op 0x2000244: Activate, explicit op 0x2000245: ClearInfoActor op 0x2000246: ClearInfoActor, explicit -op 0x2000247: BetaComment -op 0x2000248: BetaComment, explicit +op 0x2000247: (unused) +op 0x2000248: (unused) op 0x2000249: OnMurder op 0x200024a: OnMurder, explicit op 0x200024b: ToggleMenus diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index e706140fb..8409351aa 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -1016,10 +1016,10 @@ namespace MWScript }; template - class OpBetaComment : public Interpreter::Opcode0 + class OpBetaComment : public Interpreter::Opcode1 { public: - virtual void execute(Interpreter::Runtime &runtime) + virtual void execute(Interpreter::Runtime &runtime, unsigned int arg0) { MWWorld::Ptr ptr = R()(runtime); @@ -1052,10 +1052,14 @@ namespace MWScript msg << "Script: " << ptr.getClass().getScript(ptr) << std::endl; } - std::string notes = runtime.getStringLiteral (runtime[0].mInteger); - runtime.pop(); - if (!notes.empty()) - msg << "Notes: " << notes << std::endl; + while (arg0 > 0) + { + std::string notes = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + if (!notes.empty()) + msg << "Notes: " << notes << std::endl; + --arg0; + } runtime.getContext().report(msg.str()); } @@ -1221,8 +1225,8 @@ namespace MWScript interpreter.installSegment5 (Compiler::Misc::opcodeExplodeSpellExplicit, new OpExplodeSpell); interpreter.installSegment5 (Compiler::Misc::opcodeGetPcInJail, new OpGetPcInJail); interpreter.installSegment5 (Compiler::Misc::opcodeGetPcTraveling, new OpGetPcTraveling); - interpreter.installSegment5 (Compiler::Misc::opcodeBetaComment, new OpBetaComment); - interpreter.installSegment5 (Compiler::Misc::opcodeBetaCommentExplicit, new OpBetaComment); + interpreter.installSegment3 (Compiler::Misc::opcodeBetaComment, new OpBetaComment); + interpreter.installSegment3 (Compiler::Misc::opcodeBetaCommentExplicit, new OpBetaComment); interpreter.installSegment5 (Compiler::Misc::opcodeAddToLevCreature, new OpAddToLevCreature); interpreter.installSegment5 (Compiler::Misc::opcodeRemoveFromLevCreature, new OpRemoveFromLevCreature); interpreter.installSegment5 (Compiler::Misc::opcodeAddToLevItem, new OpAddToLevItem); diff --git a/components/compiler/extensions0.cpp b/components/compiler/extensions0.cpp index a16e653c3..61c9d9c20 100644 --- a/components/compiler/extensions0.cpp +++ b/components/compiler/extensions0.cpp @@ -308,8 +308,8 @@ namespace Compiler extensions.registerInstruction ("enablelevitation", "", opcodeEnableLevitation); extensions.registerFunction ("getpcinjail", 'l', "", opcodeGetPcInJail); extensions.registerFunction ("getpctraveling", 'l', "", opcodeGetPcTraveling); - extensions.registerInstruction ("betacomment", "S", opcodeBetaComment, opcodeBetaCommentExplicit); - extensions.registerInstruction ("bc", "S", opcodeBetaComment, opcodeBetaCommentExplicit); + extensions.registerInstruction ("betacomment", "/S", opcodeBetaComment, opcodeBetaCommentExplicit); + extensions.registerInstruction ("bc", "/S", opcodeBetaComment, opcodeBetaCommentExplicit); extensions.registerInstruction ("addtolevcreature", "ccl", opcodeAddToLevCreature); extensions.registerInstruction ("removefromlevcreature", "ccl", opcodeRemoveFromLevCreature); extensions.registerInstruction ("addtolevitem", "ccl", opcodeAddToLevItem); diff --git a/components/compiler/opcodes.hpp b/components/compiler/opcodes.hpp index a4aab8aa1..e7d51d934 100644 --- a/components/compiler/opcodes.hpp +++ b/components/compiler/opcodes.hpp @@ -228,8 +228,8 @@ namespace Compiler const int opcodeGetLockedExplicit = 0x20001c8; const int opcodeGetEffect = 0x20001cf; const int opcodeGetEffectExplicit = 0x20001d0; - const int opcodeBetaComment = 0x2000247; - const int opcodeBetaCommentExplicit = 0x2000248; + const int opcodeBetaComment = 0x2002d; + const int opcodeBetaCommentExplicit = 0x2002e; const int opcodeAddSoulGem = 0x20001f3; const int opcodeAddSoulGemExplicit = 0x20001f4; const int opcodeRemoveSoulGem = 0x20027; From 1d76607005e5cc5ead490fea13d3a5b0b89c931f Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 25 Jun 2015 21:48:47 +0200 Subject: [PATCH 1647/3725] Add ORI (ObjectReferenceInfo) alias for BetaComment (Fixes #2723) --- components/compiler/extensions0.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/components/compiler/extensions0.cpp b/components/compiler/extensions0.cpp index 61c9d9c20..cd645f0cf 100644 --- a/components/compiler/extensions0.cpp +++ b/components/compiler/extensions0.cpp @@ -310,6 +310,7 @@ namespace Compiler extensions.registerFunction ("getpctraveling", 'l', "", opcodeGetPcTraveling); extensions.registerInstruction ("betacomment", "/S", opcodeBetaComment, opcodeBetaCommentExplicit); extensions.registerInstruction ("bc", "/S", opcodeBetaComment, opcodeBetaCommentExplicit); + extensions.registerInstruction ("ori", "/S", opcodeBetaComment, opcodeBetaCommentExplicit); extensions.registerInstruction ("addtolevcreature", "ccl", opcodeAddToLevCreature); extensions.registerInstruction ("removefromlevcreature", "ccl", opcodeRemoveFromLevCreature); extensions.registerInstruction ("addtolevitem", "ccl", opcodeAddToLevItem); From 4ef6aa6b7f0856ead39121397282efdfe20875cd Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 26 Jun 2015 02:30:39 +0200 Subject: [PATCH 1648/3725] Fix weather particles disappearing --- apps/openmw/mwrender/sky.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index e5563409d..1aa2fd864 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -923,7 +923,10 @@ void SkyManager::setWeather(const MWWorld::WeatherResult& weather) if (mCurrentParticleEffect.empty()) { if (mParticleNode) + { mRootNode->removeChild(mParticleNode); + mParticleNode = NULL; + } mParticleEffect = NULL; } else From 5bc6513e2db74a40c5689bd974b338a486904fc8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 26 Jun 2015 02:32:41 +0200 Subject: [PATCH 1649/3725] Fix projectile hit bug where the incorrect attackStrength would be used if a new attack has been performed in the meantime --- apps/openmw/mwmechanics/combat.cpp | 8 +++----- apps/openmw/mwmechanics/combat.hpp | 2 +- apps/openmw/mwworld/projectilemanager.cpp | 5 ++++- apps/openmw/mwworld/projectilemanager.hpp | 1 + components/esm/projectilestate.cpp | 4 ++++ components/esm/projectilestate.hpp | 1 + 6 files changed, 14 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwmechanics/combat.cpp b/apps/openmw/mwmechanics/combat.cpp index b013dbb1b..27ef1a00f 100644 --- a/apps/openmw/mwmechanics/combat.cpp +++ b/apps/openmw/mwmechanics/combat.cpp @@ -166,13 +166,11 @@ namespace MWMechanics } void projectileHit(const MWWorld::Ptr &attacker, const MWWorld::Ptr &victim, MWWorld::Ptr weapon, const MWWorld::Ptr &projectile, - const osg::Vec3f& hitPosition) + const osg::Vec3f& hitPosition, float attackStrength) { MWBase::World *world = MWBase::Environment::get().getWorld(); const MWWorld::Store &gmst = world->getStore().get(); - MWMechanics::CreatureStats& attackerStats = attacker.getClass().getCreatureStats(attacker); - if(victim.isEmpty() || !victim.getClass().isActor() || victim.getClass().getCreatureStats(victim).isDead()) // Can't hit non-actors or dead actors { @@ -199,12 +197,12 @@ namespace MWMechanics const unsigned char* attack = weapon.get()->mBase->mData.mChop; - float damage = attack[0] + ((attack[1]-attack[0])*attackerStats.getAttackStrength()); // Bow/crossbow damage + float damage = attack[0] + ((attack[1]-attack[0])*attackStrength); // Bow/crossbow damage // Arrow/bolt damage // NB in case of thrown weapons, we are applying the damage twice since projectile == weapon attack = projectile.get()->mBase->mData.mChop; - damage += attack[0] + ((attack[1]-attack[0])*attackerStats.getAttackStrength()); + damage += attack[0] + ((attack[1]-attack[0])*attackStrength); adjustWeaponDamage(damage, weapon, attacker); reduceWeaponCondition(damage, true, weapon, attacker); diff --git a/apps/openmw/mwmechanics/combat.hpp b/apps/openmw/mwmechanics/combat.hpp index 9412f62e7..1fabc5772 100644 --- a/apps/openmw/mwmechanics/combat.hpp +++ b/apps/openmw/mwmechanics/combat.hpp @@ -14,7 +14,7 @@ void resistNormalWeapon (const MWWorld::Ptr& actor, const MWWorld::Ptr& attacker /// @note for a thrown weapon, \a weapon == \a projectile, for bows/crossbows, \a projectile is the arrow/bolt /// @note \a victim may be empty (e.g. for a hit on terrain), a non-actor (environment objects) or an actor void projectileHit (const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim, MWWorld::Ptr weapon, const MWWorld::Ptr& projectile, - const osg::Vec3f& hitPosition); + const osg::Vec3f& hitPosition, float attackStrength); /// Get the chance (in percent) for \a attacker to successfully hit \a victim with a given weapon skill value float getHitChance (const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim, int skillValue); diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index d0a5de5b2..16e1f6f47 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -123,6 +123,7 @@ namespace MWWorld state.mVelocity = orient * osg::Vec3f(0,1,0) * speed; state.mId = projectile.getCellRef().getRefId(); state.mCasterHandle = actor; + state.mAttackStrength = actor.getClass().getCreatureStats(actor).getAttackStrength(); MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), projectile.getCellRef().getRefId()); MWWorld::Ptr ptr = ref.getPtr(); @@ -245,7 +246,7 @@ namespace MWWorld if (caster.isEmpty()) caster = result.mHitObject; - MWMechanics::projectileHit(caster, result.mHitObject, bow, projectileRef.getPtr(), result.mHitPos); + MWMechanics::projectileHit(caster, result.mHitObject, bow, projectileRef.getPtr(), result.mHitPos, it->mAttackStrength); mParent->removeChild(it->mNode); @@ -286,6 +287,7 @@ namespace MWWorld state.mBowId = it->mBowId; state.mVelocity = it->mVelocity; + state.mAttackStrength = it->mAttackStrength; state.save(writer); @@ -327,6 +329,7 @@ namespace MWWorld state.mBowId = esm.mBowId; state.mVelocity = esm.mVelocity; state.mId = esm.mId; + state.mAttackStrength = esm.mAttackStrength; std::string model; try diff --git a/apps/openmw/mwworld/projectilemanager.hpp b/apps/openmw/mwworld/projectilemanager.hpp index 68e408149..57a6fb6a5 100644 --- a/apps/openmw/mwworld/projectilemanager.hpp +++ b/apps/openmw/mwworld/projectilemanager.hpp @@ -108,6 +108,7 @@ namespace MWWorld std::string mBowId; osg::Vec3f mVelocity; + float mAttackStrength; }; std::vector mMagicBolts; diff --git a/components/esm/projectilestate.cpp b/components/esm/projectilestate.cpp index 85c00025b..70ae4c5ee 100644 --- a/components/esm/projectilestate.cpp +++ b/components/esm/projectilestate.cpp @@ -52,6 +52,7 @@ namespace ESM esm.writeHNString ("BOW_", mBowId); esm.writeHNT ("VEL_", mVelocity); + esm.writeHNT ("STR_", mAttackStrength); } void ProjectileState::load(ESMReader &esm) @@ -60,6 +61,9 @@ namespace ESM mBowId = esm.getHNString ("BOW_"); esm.getHNT (mVelocity, "VEL_"); + + mAttackStrength = 1.f; + esm.getHNOT(mAttackStrength, "STR_"); } } diff --git a/components/esm/projectilestate.hpp b/components/esm/projectilestate.hpp index 38429e459..3471fbfc7 100644 --- a/components/esm/projectilestate.hpp +++ b/components/esm/projectilestate.hpp @@ -45,6 +45,7 @@ namespace ESM { std::string mBowId; Vector3 mVelocity; + float mAttackStrength; void load (ESMReader &esm); void save (ESMWriter &esm) const; From beb108626023e54a7a95f76db678ad31ad9e30e4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 26 Jun 2015 04:21:10 +0200 Subject: [PATCH 1650/3725] Fix attackStrength being unset for creatures with no weapons --- apps/openmw/mwmechanics/character.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 16d7387fd..28e19d395 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -991,6 +991,8 @@ bool CharacterController::updateCreatureState() 1, startKey, stopKey, 0.0f, 0); mUpperBodyState = UpperCharState_StartToMinAttack; + + stats.setAttackStrength(std::min(1.f, 0.1f + Misc::Rng::rollClosedProbability())); } } From 882e359008bc42a2216d18bf744dfe191716ca64 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 26 Jun 2015 05:15:07 +0200 Subject: [PATCH 1651/3725] Move attackStrength to the CharacterController, where it should have been to begin with Only relevant for actors in active cells, so doesn't belong in CreatureStats. This change should slightly reduce the game's memory usage. --- apps/openmw/mwbase/world.hpp | 2 +- apps/openmw/mwclass/creature.cpp | 12 ++++----- apps/openmw/mwclass/creature.hpp | 2 +- apps/openmw/mwclass/npc.cpp | 11 ++++---- apps/openmw/mwclass/npc.hpp | 2 +- apps/openmw/mwmechanics/character.cpp | 29 +++++++++++----------- apps/openmw/mwmechanics/character.hpp | 2 ++ apps/openmw/mwmechanics/combat.cpp | 14 +++++------ apps/openmw/mwmechanics/combat.hpp | 6 ++--- apps/openmw/mwmechanics/creaturestats.cpp | 14 +---------- apps/openmw/mwmechanics/creaturestats.hpp | 5 ---- apps/openmw/mwrender/animation.hpp | 2 +- apps/openmw/mwrender/creatureanimation.cpp | 4 +-- apps/openmw/mwrender/creatureanimation.hpp | 2 +- apps/openmw/mwrender/npcanimation.cpp | 4 +-- apps/openmw/mwrender/npcanimation.hpp | 2 +- apps/openmw/mwrender/weaponanimation.cpp | 13 +++++----- apps/openmw/mwrender/weaponanimation.hpp | 2 +- apps/openmw/mwworld/class.cpp | 2 +- apps/openmw/mwworld/class.hpp | 3 ++- apps/openmw/mwworld/projectilemanager.cpp | 4 +-- apps/openmw/mwworld/projectilemanager.hpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 4 +-- apps/openmw/mwworld/worldimp.hpp | 2 +- components/esm/creaturestats.cpp | 8 ++---- components/esm/creaturestats.hpp | 1 - components/esm/npcstats.cpp | 2 +- 27 files changed, 68 insertions(+), 88 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 95553de76..6e5029cc3 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -480,7 +480,7 @@ namespace MWBase float speed, bool stack, const ESM::EffectList& effects, const MWWorld::Ptr& caster, const std::string& sourceName, const osg::Vec3f& fallbackDirection) = 0; virtual void launchProjectile (MWWorld::Ptr actor, MWWorld::Ptr projectile, - const osg::Vec3f& worldPos, const osg::Quat& orient, MWWorld::Ptr bow, float speed) = 0; + const osg::Vec3f& worldPos, const osg::Quat& orient, MWWorld::Ptr bow, float speed, float attackStrength) = 0; virtual const std::vector& getContentFiles() const = 0; diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 5b5a3a0cb..946f024b8 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -209,7 +209,7 @@ namespace MWClass } - void Creature::hit(const MWWorld::Ptr& ptr, int type) const + void Creature::hit(const MWWorld::Ptr& ptr, float attackStrength, int type) const { MWWorld::LiveCellRef *ref = ptr.get(); @@ -229,7 +229,7 @@ namespace MWClass weapon = *weaponslot; } - MWMechanics::applyFatigueLoss(ptr, weapon); + MWMechanics::applyFatigueLoss(ptr, weapon, attackStrength); // TODO: where is the distance defined? float dist = 200.f; @@ -276,7 +276,7 @@ namespace MWClass break; } - float damage = min + (max - min) * stats.getAttackStrength(); + float damage = min + (max - min) * attackStrength; bool healthdmg = true; if (!weapon.isEmpty()) { @@ -289,7 +289,7 @@ namespace MWClass attack = weapon.get()->mBase->mData.mThrust; if(attack) { - damage = attack[0] + ((attack[1]-attack[0])*stats.getAttackStrength()); + damage = attack[0] + ((attack[1]-attack[0])*attackStrength); MWMechanics::adjustWeaponDamage(damage, weapon, ptr); MWMechanics::reduceWeaponCondition(damage, true, weapon, ptr); } @@ -310,12 +310,12 @@ namespace MWClass } else if (isBipedal(ptr)) { - MWMechanics::getHandToHandDamage(ptr, victim, damage, healthdmg); + MWMechanics::getHandToHandDamage(ptr, victim, damage, healthdmg, attackStrength); } MWMechanics::applyElementalShields(ptr, victim); - if (MWMechanics::blockMeleeAttack(ptr, victim, weapon, damage)) + if (MWMechanics::blockMeleeAttack(ptr, victim, weapon, damage, attackStrength)) damage = 0; if (damage > 0) diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index 93ef3959c..740552a60 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -66,7 +66,7 @@ namespace MWClass virtual MWMechanics::CreatureStats& getCreatureStats (const MWWorld::Ptr& ptr) const; ///< Return creature stats - virtual void hit(const MWWorld::Ptr& ptr, int type) const; + virtual void hit(const MWWorld::Ptr& ptr, float attackStrength, int type) const; virtual void block(const MWWorld::Ptr &ptr) const; diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index b9ca69c63..ac0d67269 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -470,7 +470,7 @@ namespace MWClass } - void Npc::hit(const MWWorld::Ptr& ptr, int type) const + void Npc::hit(const MWWorld::Ptr& ptr, float attackStrength, int type) const { MWBase::World *world = MWBase::Environment::get().getWorld(); @@ -483,7 +483,7 @@ namespace MWClass if(!weapon.isEmpty() && weapon.getTypeName() != typeid(ESM::Weapon).name()) weapon = MWWorld::Ptr(); - MWMechanics::applyFatigueLoss(ptr, weapon); + MWMechanics::applyFatigueLoss(ptr, weapon, attackStrength); const float fCombatDistance = store.find("fCombatDistance")->getFloat(); float dist = fCombatDistance * (!weapon.isEmpty() ? @@ -522,7 +522,6 @@ namespace MWClass bool healthdmg; float damage = 0.0f; - MWMechanics::NpcStats &stats = getNpcStats(ptr); if(!weapon.isEmpty()) { const unsigned char *attack = NULL; @@ -534,7 +533,7 @@ namespace MWClass attack = weapon.get()->mBase->mData.mThrust; if(attack) { - damage = attack[0] + ((attack[1]-attack[0])*stats.getAttackStrength()); + damage = attack[0] + ((attack[1]-attack[0])*attackStrength); } MWMechanics::adjustWeaponDamage(damage, weapon, ptr); MWMechanics::reduceWeaponCondition(damage, true, weapon, ptr); @@ -542,7 +541,7 @@ namespace MWClass } else { - MWMechanics::getHandToHandDamage(ptr, victim, damage, healthdmg); + MWMechanics::getHandToHandDamage(ptr, victim, damage, healthdmg, attackStrength); } if(ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) { @@ -579,7 +578,7 @@ namespace MWClass MWMechanics::applyElementalShields(ptr, victim); - if (MWMechanics::blockMeleeAttack(ptr, victim, weapon, damage)) + if (MWMechanics::blockMeleeAttack(ptr, victim, weapon, damage, attackStrength)) damage = 0; if (healthdmg && damage > 0) diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index b786286f7..f032ae77c 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -81,7 +81,7 @@ namespace MWClass virtual bool hasInventoryStore(const MWWorld::Ptr &ptr) const { return true; } - virtual void hit(const MWWorld::Ptr& ptr, int type) const; + virtual void hit(const MWWorld::Ptr& ptr, float attackStrength, int type) const; virtual void onHit(const MWWorld::Ptr &ptr, float damage, bool ishealth, const MWWorld::Ptr &object, const MWWorld::Ptr &attacker, bool successful) const; diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 28e19d395..c39b7dcef 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -649,6 +649,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim , mUpperBodyState(UpperCharState_Nothing) , mJumpState(JumpState_None) , mWeaponType(WeapType_None) + , mAttackStrength(0.f) , mSkipAnim(false) , mSecondsOfSwimming(0) , mSecondsOfRunning(0) @@ -782,21 +783,21 @@ void CharacterController::handleTextKey(const std::string &groupname, const std: else if(evt.compare(off, len, "unequip detach") == 0) mAnimation->showWeapons(false); else if(evt.compare(off, len, "chop hit") == 0) - mPtr.getClass().hit(mPtr, ESM::Weapon::AT_Chop); + mPtr.getClass().hit(mPtr, mAttackStrength, ESM::Weapon::AT_Chop); else if(evt.compare(off, len, "slash hit") == 0) - mPtr.getClass().hit(mPtr, ESM::Weapon::AT_Slash); + mPtr.getClass().hit(mPtr, mAttackStrength, ESM::Weapon::AT_Slash); else if(evt.compare(off, len, "thrust hit") == 0) - mPtr.getClass().hit(mPtr, ESM::Weapon::AT_Thrust); + mPtr.getClass().hit(mPtr, mAttackStrength, ESM::Weapon::AT_Thrust); else if(evt.compare(off, len, "hit") == 0) { if (groupname == "attack1") - mPtr.getClass().hit(mPtr, ESM::Weapon::AT_Chop); + mPtr.getClass().hit(mPtr, mAttackStrength, ESM::Weapon::AT_Chop); else if (groupname == "attack2") - mPtr.getClass().hit(mPtr, ESM::Weapon::AT_Slash); + mPtr.getClass().hit(mPtr, mAttackStrength, ESM::Weapon::AT_Slash); else if (groupname == "attack3") - mPtr.getClass().hit(mPtr, ESM::Weapon::AT_Thrust); + mPtr.getClass().hit(mPtr, mAttackStrength, ESM::Weapon::AT_Thrust); else - mPtr.getClass().hit(mPtr); + mPtr.getClass().hit(mPtr, mAttackStrength); } else if (!groupname.empty() && groupname.compare(0, groupname.size()-1, "attack") == 0 && evt.compare(off, len, "start") == 0) @@ -819,17 +820,17 @@ void CharacterController::handleTextKey(const std::string &groupname, const std: if (!hasHitKey) { if (groupname == "attack1") - mPtr.getClass().hit(mPtr, ESM::Weapon::AT_Chop); + mPtr.getClass().hit(mPtr, mAttackStrength, ESM::Weapon::AT_Chop); else if (groupname == "attack2") - mPtr.getClass().hit(mPtr, ESM::Weapon::AT_Slash); + mPtr.getClass().hit(mPtr, mAttackStrength, ESM::Weapon::AT_Slash); else if (groupname == "attack3") - mPtr.getClass().hit(mPtr, ESM::Weapon::AT_Thrust); + mPtr.getClass().hit(mPtr, mAttackStrength, ESM::Weapon::AT_Thrust); } } else if (evt.compare(off, len, "shoot attach") == 0) mAnimation->attachArrow(); else if (evt.compare(off, len, "shoot release") == 0) - mAnimation->releaseArrow(); + mAnimation->releaseArrow(mAttackStrength); else if (evt.compare(off, len, "shoot follow attach") == 0) mAnimation->attachArrow(); @@ -992,7 +993,7 @@ bool CharacterController::updateCreatureState() 0.0f, 0); mUpperBodyState = UpperCharState_StartToMinAttack; - stats.setAttackStrength(std::min(1.f, 0.1f + Misc::Rng::rollClosedProbability())); + mAttackStrength = std::min(1.f, 0.1f + Misc::Rng::rollClosedProbability()); } } @@ -1294,7 +1295,7 @@ bool CharacterController::updateWeaponState() sndMgr->playSound3D(mPtr, sound, 1.0f, 1.2f); //Strong attack } } - stats.setAttackStrength(attackStrength); + mAttackStrength = attackStrength; mAnimation->disable(mCurrentWeapon); mAnimation->play(mCurrentWeapon, Priority_Weapon, @@ -1418,7 +1419,7 @@ bool CharacterController::updateWeaponState() } else { - float str = stats.getAttackStrength(); + float str = mAttackStrength; start = mAttackType+((str < 0.5f) ? " small follow start" : (str < 1.0f) ? " medium follow start" : " large follow start"); diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 797c2e623..be8fb2bf6 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -167,6 +167,8 @@ class CharacterController : public MWRender::Animation::TextKeyListener WeaponType mWeaponType; std::string mCurrentWeapon; + float mAttackStrength; + bool mSkipAnim; // counted for skill increase diff --git a/apps/openmw/mwmechanics/combat.cpp b/apps/openmw/mwmechanics/combat.cpp index 27ef1a00f..097dcadc2 100644 --- a/apps/openmw/mwmechanics/combat.cpp +++ b/apps/openmw/mwmechanics/combat.cpp @@ -51,7 +51,7 @@ bool applyEnchantment (const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim, namespace MWMechanics { - bool blockMeleeAttack(const MWWorld::Ptr &attacker, const MWWorld::Ptr &blocker, const MWWorld::Ptr &weapon, float damage) + bool blockMeleeAttack(const MWWorld::Ptr &attacker, const MWWorld::Ptr &blocker, const MWWorld::Ptr &weapon, float damage, float attackStrength) { if (!blocker.getClass().hasInventoryStore(blocker)) return false; @@ -90,7 +90,7 @@ namespace MWMechanics float blockTerm = blocker.getClass().getSkill(blocker, ESM::Skill::Block) + 0.2f * blockerStats.getAttribute(ESM::Attribute::Agility).getModified() + 0.1f * blockerStats.getAttribute(ESM::Attribute::Luck).getModified(); - float enemySwing = attackerStats.getAttackStrength(); + float enemySwing = attackStrength; float swingTerm = enemySwing * gmst.find("fSwingBlockMult")->getFloat() + gmst.find("fSwingBlockBase")->getFloat(); float blockerTerm = blockTerm * swingTerm; @@ -131,7 +131,7 @@ namespace MWMechanics normalizedEncumbrance = std::min(1.f, normalizedEncumbrance); float fatigueLoss = fFatigueBlockBase + normalizedEncumbrance * fFatigueBlockMult; if (!weapon.isEmpty()) - fatigueLoss += weapon.getClass().getWeight(weapon) * attackerStats.getAttackStrength() * fWeaponFatigueBlockMult; + fatigueLoss += weapon.getClass().getWeight(weapon) * attackStrength * fWeaponFatigueBlockMult; fatigue.setCurrent(fatigue.getCurrent() - fatigueLoss); blockerStats.setFatigue(fatigue); @@ -363,7 +363,7 @@ namespace MWMechanics (attacker.getClass().getCreatureStats(attacker).getAttribute(ESM::Attribute::Strength).getModified() * fDamageStrengthMult * 0.1f); } - void getHandToHandDamage(const MWWorld::Ptr &attacker, const MWWorld::Ptr &victim, float &damage, bool &healthdmg) + void getHandToHandDamage(const MWWorld::Ptr &attacker, const MWWorld::Ptr &victim, float &damage, bool &healthdmg, float attackStrength) { // Note: MCP contains an option to include Strength in hand-to-hand damage // calculations. Some mods recommend using it, so we may want to include an @@ -372,7 +372,7 @@ namespace MWMechanics float minstrike = store.get().find("fMinHandToHandMult")->getFloat(); float maxstrike = store.get().find("fMaxHandToHandMult")->getFloat(); damage = static_cast(attacker.getClass().getSkill(attacker, ESM::Skill::HandToHand)); - damage *= minstrike + ((maxstrike-minstrike)*attacker.getClass().getCreatureStats(attacker).getAttackStrength()); + damage *= minstrike + ((maxstrike-minstrike)*attackStrength); MWMechanics::CreatureStats& otherstats = victim.getClass().getCreatureStats(victim); healthdmg = (otherstats.getMagicEffects().get(ESM::MagicEffect::Paralyze).getMagnitude() > 0) @@ -398,7 +398,7 @@ namespace MWMechanics sndMgr->playSound3D(victim, "Hand To Hand Hit", 1.0f, 1.0f); } - void applyFatigueLoss(const MWWorld::Ptr &attacker, const MWWorld::Ptr &weapon) + void applyFatigueLoss(const MWWorld::Ptr &attacker, const MWWorld::Ptr &weapon, float attackStrength) { // somewhat of a guess, but using the weapon weight makes sense const MWWorld::Store& store = MWBase::Environment::get().getWorld()->getStore().get(); @@ -410,7 +410,7 @@ namespace MWMechanics const float normalizedEncumbrance = attacker.getClass().getNormalizedEncumbrance(attacker); float fatigueLoss = fFatigueAttackBase + normalizedEncumbrance * fFatigueAttackMult; if (!weapon.isEmpty()) - fatigueLoss += weapon.getClass().getWeight(weapon) * stats.getAttackStrength() * fWeaponFatigueMult; + fatigueLoss += weapon.getClass().getWeight(weapon) * attackStrength * fWeaponFatigueMult; fatigue.setCurrent(fatigue.getCurrent() - fatigueLoss); stats.setFatigue(fatigue); } diff --git a/apps/openmw/mwmechanics/combat.hpp b/apps/openmw/mwmechanics/combat.hpp index 1fabc5772..ca78d7956 100644 --- a/apps/openmw/mwmechanics/combat.hpp +++ b/apps/openmw/mwmechanics/combat.hpp @@ -7,7 +7,7 @@ namespace MWMechanics { /// @return can we block the attack? -bool blockMeleeAttack (const MWWorld::Ptr& attacker, const MWWorld::Ptr& blocker, const MWWorld::Ptr& weapon, float damage); +bool blockMeleeAttack (const MWWorld::Ptr& attacker, const MWWorld::Ptr& blocker, const MWWorld::Ptr& weapon, float damage, float attackStrength); void resistNormalWeapon (const MWWorld::Ptr& actor, const MWWorld::Ptr& attacker, const MWWorld::Ptr& weapon, float& damage); @@ -31,10 +31,10 @@ void reduceWeaponCondition (float damage, bool hit, MWWorld::Ptr& weapon, const /// Adjust weapon damage based on its condition. A used weapon will be less effective. void adjustWeaponDamage (float& damage, const MWWorld::Ptr& weapon, const MWWorld::Ptr& attacker); -void getHandToHandDamage (const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim, float& damage, bool& healthdmg); +void getHandToHandDamage (const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim, float& damage, bool& healthdmg, float attackStrength); /// Apply the fatigue loss incurred by attacking with the given weapon (weapon may be empty = hand-to-hand) -void applyFatigueLoss(const MWWorld::Ptr& attacker, const MWWorld::Ptr& weapon); +void applyFatigueLoss(const MWWorld::Ptr& attacker, const MWWorld::Ptr& weapon, float attackStrength); /// Can attacker operate in victim's environment? /// e.g. If attacker is a fish, is victim in water? Or, if attacker can't swim, is victim on land? diff --git a/apps/openmw/mwmechanics/creaturestats.cpp b/apps/openmw/mwmechanics/creaturestats.cpp index e5cb561bf..5a09eb4ee 100644 --- a/apps/openmw/mwmechanics/creaturestats.cpp +++ b/apps/openmw/mwmechanics/creaturestats.cpp @@ -18,7 +18,7 @@ namespace MWMechanics : mDrawState (DrawState_Nothing), mDead (false), mDied (false), mMurdered(false), mFriendlyHits (0), mTalkedTo (false), mAlarmed (false), mAttacked (false), mAttackingOrSpell(false), mKnockdown(false), mKnockdownOneFrame(false), mKnockdownOverOneFrame(false), - mHitRecovery(false), mBlock(false), mMovementFlags(0), mAttackStrength(0.f), + mHitRecovery(false), mBlock(false), mMovementFlags(0), mFallHeight(0), mRecalcMagicka(false), mLastRestock(0,0), mGoldPool(0), mActorId(-1), mDeathAnimation(0), mLevel (0) { @@ -466,16 +466,6 @@ namespace MWMechanics mDrawState = state; } - float CreatureStats::getAttackStrength() const - { - return mAttackStrength; - } - - void CreatureStats::setAttackStrength(float value) - { - mAttackStrength = value; - } - void CreatureStats::writeState (ESM::CreatureStats& state) const { for (int i=0; i &gmst = MWBase::Environment::get().getWorld()->getStore().get(); - MWMechanics::applyFatigueLoss(actor, *weapon); + MWMechanics::applyFatigueLoss(actor, *weapon, attackStrength); if (weapon->get()->mBase->mData.mType == ESM::Weapon::MarksmanThrown) { @@ -121,10 +121,9 @@ void WeaponAnimation::releaseArrow(MWWorld::Ptr actor) float fThrownWeaponMinSpeed = gmst.find("fThrownWeaponMinSpeed")->getFloat(); float fThrownWeaponMaxSpeed = gmst.find("fThrownWeaponMaxSpeed")->getFloat(); - float speed = fThrownWeaponMinSpeed + (fThrownWeaponMaxSpeed - fThrownWeaponMinSpeed) * - actor.getClass().getCreatureStats(actor).getAttackStrength(); + float speed = fThrownWeaponMinSpeed + (fThrownWeaponMaxSpeed - fThrownWeaponMinSpeed) * attackStrength; - MWBase::Environment::get().getWorld()->launchProjectile(actor, *weapon, launchPos, orient, *weapon, speed); + MWBase::Environment::get().getWorld()->launchProjectile(actor, *weapon, launchPos, orient, *weapon, speed, attackStrength); showWeapon(false); @@ -148,9 +147,9 @@ void WeaponAnimation::releaseArrow(MWWorld::Ptr actor) float fProjectileMinSpeed = gmst.find("fProjectileMinSpeed")->getFloat(); float fProjectileMaxSpeed = gmst.find("fProjectileMaxSpeed")->getFloat(); - float speed = fProjectileMinSpeed + (fProjectileMaxSpeed - fProjectileMinSpeed) * actor.getClass().getCreatureStats(actor).getAttackStrength(); + float speed = fProjectileMinSpeed + (fProjectileMaxSpeed - fProjectileMinSpeed) * attackStrength; - MWBase::Environment::get().getWorld()->launchProjectile(actor, *ammo, launchPos, orient, *weapon, speed); + MWBase::Environment::get().getWorld()->launchProjectile(actor, *ammo, launchPos, orient, *weapon, speed, attackStrength); inv.remove(*ammo, 1, actor); mAmmunition.reset(); diff --git a/apps/openmw/mwrender/weaponanimation.hpp b/apps/openmw/mwrender/weaponanimation.hpp index 226d59c53..3bf0fb721 100644 --- a/apps/openmw/mwrender/weaponanimation.hpp +++ b/apps/openmw/mwrender/weaponanimation.hpp @@ -36,7 +36,7 @@ namespace MWRender void attachArrow(MWWorld::Ptr actor); /// @note If no weapon (or an invalid weapon) is equipped, this function is a no-op. - void releaseArrow(MWWorld::Ptr actor); + void releaseArrow(MWWorld::Ptr actor, float attackStrength); /// Add WeaponAnimation-related controllers to \a nodes and store the added controllers in \a map. void addControllers(const std::map >& nodes, diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index f6170da7f..5ec2d4e16 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -94,7 +94,7 @@ namespace MWWorld throw std::runtime_error ("class does not have item health"); } - void Class::hit(const Ptr& ptr, int type) const + void Class::hit(const Ptr& ptr, float attackStrength, int type) const { throw std::runtime_error("class cannot hit"); } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 87325144a..7ef173555 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -118,9 +118,10 @@ namespace MWWorld ///< Return item max health or throw an exception, if class does not have item health /// (default implementation: throw an exception) - virtual void hit(const Ptr& ptr, int type=-1) const; + virtual void hit(const Ptr& ptr, float attackStrength, int type=-1) const; ///< Execute a melee hit, using the current weapon. This will check the relevant skills /// of the given attacker, and whoever is hit. + /// \param attackStrength how long the attack was charged for, a value in 0-1 range. /// \param type - type of attack, one of the MWMechanics::CreatureStats::AttackType /// enums. ignored for creature attacks. /// (default implementation: throw an exception) diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 16e1f6f47..f083bcb4a 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -115,7 +115,7 @@ namespace MWWorld mMagicBolts.push_back(state); } - void ProjectileManager::launchProjectile(Ptr actor, Ptr projectile, const osg::Vec3f &pos, const osg::Quat &orient, Ptr bow, float speed) + void ProjectileManager::launchProjectile(Ptr actor, Ptr projectile, const osg::Vec3f &pos, const osg::Quat &orient, Ptr bow, float speed, float attackStrength) { ProjectileState state; state.mActorId = actor.getClass().getCreatureStats(actor).getActorId(); @@ -123,7 +123,7 @@ namespace MWWorld state.mVelocity = orient * osg::Vec3f(0,1,0) * speed; state.mId = projectile.getCellRef().getRefId(); state.mCasterHandle = actor; - state.mAttackStrength = actor.getClass().getCreatureStats(actor).getAttackStrength(); + state.mAttackStrength = attackStrength; MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), projectile.getCellRef().getRefId()); MWWorld::Ptr ptr = ref.getPtr(); diff --git a/apps/openmw/mwworld/projectilemanager.hpp b/apps/openmw/mwworld/projectilemanager.hpp index 57a6fb6a5..0aa2efded 100644 --- a/apps/openmw/mwworld/projectilemanager.hpp +++ b/apps/openmw/mwworld/projectilemanager.hpp @@ -52,7 +52,7 @@ namespace MWWorld const MWWorld::Ptr& caster, const std::string& sourceName, const osg::Vec3f& fallbackDirection); void launchProjectile (MWWorld::Ptr actor, MWWorld::Ptr projectile, - const osg::Vec3f& pos, const osg::Quat& orient, MWWorld::Ptr bow, float speed); + const osg::Vec3f& pos, const osg::Quat& orient, MWWorld::Ptr bow, float speed, float attackStrength); void update(float dt); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 323eabc10..6980a7e6f 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2677,9 +2677,9 @@ namespace MWWorld } void World::launchProjectile (MWWorld::Ptr actor, MWWorld::Ptr projectile, - const osg::Vec3f& worldPos, const osg::Quat& orient, MWWorld::Ptr bow, float speed) + const osg::Vec3f& worldPos, const osg::Quat& orient, MWWorld::Ptr bow, float speed, float attackStrength) { - mProjectileManager->launchProjectile(actor, projectile, worldPos, orient, bow, speed); + mProjectileManager->launchProjectile(actor, projectile, worldPos, orient, bow, speed, attackStrength); } void World::launchMagicBolt (const std::string& model, const std::string &sound, const std::string &spellId, diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 6b09fbb65..7964edf45 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -569,7 +569,7 @@ namespace MWWorld float speed, bool stack, const ESM::EffectList& effects, const MWWorld::Ptr& caster, const std::string& sourceName, const osg::Vec3f& fallbackDirection); virtual void launchProjectile (MWWorld::Ptr actor, MWWorld::Ptr projectile, - const osg::Vec3f& worldPos, const osg::Quat& orient, MWWorld::Ptr bow, float speed); + const osg::Vec3f& worldPos, const osg::Quat& orient, MWWorld::Ptr bow, float speed, float attackStrength); virtual const std::vector& getContentFiles() const; diff --git a/components/esm/creaturestats.cpp b/components/esm/creaturestats.cpp index 75c1c28bc..d0fe4be63 100644 --- a/components/esm/creaturestats.cpp +++ b/components/esm/creaturestats.cpp @@ -60,8 +60,8 @@ void ESM::CreatureStats::load (ESMReader &esm) mMovementFlags = 0; esm.getHNOT (mMovementFlags, "MOVE"); - mAttackStrength = 0; - esm.getHNOT (mAttackStrength, "ASTR"); + if (esm.isNextSub("ASTR")) + esm.skipHSub(); // attackStrength, no longer used mFallHeight = 0; esm.getHNOT (mFallHeight, "FALL"); @@ -170,9 +170,6 @@ void ESM::CreatureStats::save (ESMWriter &esm) const if (mMovementFlags) esm.writeHNT ("MOVE", mMovementFlags); - if (mAttackStrength) - esm.writeHNT ("ASTR", mAttackStrength); - if (mFallHeight) esm.writeHNT ("FALL", mFallHeight); @@ -242,7 +239,6 @@ void ESM::CreatureStats::blank() mHitRecovery = false; mBlock = false; mMovementFlags = 0; - mAttackStrength = 0.f; mFallHeight = 0.f; mRecalcDynamicStats = false; mDrawState = 0; diff --git a/components/esm/creaturestats.hpp b/components/esm/creaturestats.hpp index 2a03136d0..3b1d199e4 100644 --- a/components/esm/creaturestats.hpp +++ b/components/esm/creaturestats.hpp @@ -52,7 +52,6 @@ namespace ESM bool mHitRecovery; bool mBlock; unsigned int mMovementFlags; - float mAttackStrength; float mFallHeight; std::string mLastHitObject; std::string mLastHitAttemptObject; diff --git a/components/esm/npcstats.cpp b/components/esm/npcstats.cpp index e854410b1..10c0b6f16 100644 --- a/components/esm/npcstats.cpp +++ b/components/esm/npcstats.cpp @@ -86,7 +86,7 @@ void ESM::NpcStats::load (ESMReader &esm) if (esm.isNextSub("PROF")) esm.skipHSub(); // int profit - // No longer used. Now part of CreatureStats. + // No longer used if (esm.isNextSub("ASTR")) esm.skipHSub(); // attackStrength From a44be148d89cd7717708f74166388263726ba36b Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 26 Jun 2015 06:40:28 +0200 Subject: [PATCH 1652/3725] Fix door collisions --- apps/openmw/mwphysics/physicssystem.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 2709ced4f..2cb261851 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -887,12 +887,12 @@ namespace MWPhysics const btCollisionObjectWrapper* col0Wrap,int partId0,int index0, const btCollisionObjectWrapper* col1Wrap,int partId1,int index1) { - const btCollisionObject* collisionObject = col1Wrap->m_collisionObject; + const btCollisionObject* collisionObject = col0Wrap->m_collisionObject; #else virtual btScalar addSingleResult(btManifoldPoint& cp, const btCollisionObject* col0, int partId0, int index0, const btCollisionObject* col1, int partId1, int index1) { - const btCollisionObject* collisionObject = col1; + const btCollisionObject* collisionObject = col0; #endif const PtrHolder* holder = static_cast(collisionObject->getUserPointer()); if (holder) From f3ff90e1fde2f46d980a3f2525b79f34edcc151d Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 26 Jun 2015 13:01:25 +0200 Subject: [PATCH 1653/3725] moved meta data into a new single-row table --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/doc/document.cpp | 3 --- apps/opencs/model/world/data.cpp | 29 +++++++++++++------------ apps/opencs/model/world/data.hpp | 10 ++++----- apps/opencs/model/world/metadata.cpp | 27 +++++++++++++++++++++++ apps/opencs/model/world/metadata.hpp | 29 +++++++++++++++++++++++++ apps/opencs/model/world/universalid.cpp | 1 + apps/opencs/model/world/universalid.hpp | 1 + 8 files changed, 78 insertions(+), 24 deletions(-) create mode 100644 apps/opencs/model/world/metadata.cpp create mode 100644 apps/opencs/model/world/metadata.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 5386da707..3399b9ddd 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -26,7 +26,7 @@ opencs_units_noqt (model/world universalid record commands columnbase scriptcontext cell refidcollection refidadapter refiddata refidadapterimp ref collectionbase refcollection columns infocollection tablemimedata cellcoordinates cellselection resources resourcesmanager scope pathgrid landtexture land nestedtablewrapper nestedcollection nestedcoladapterimp nestedinfocollection - idcompletionmanager + idcompletionmanager metadata ) opencs_hdrs_noqt (model/world diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 1e6ae5455..34ae3dd8a 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -2282,9 +2282,6 @@ CSMDoc::Document::Document (const Files::ConfigurationManager& configuration, if (mNew) { - mData.setDescription (""); - mData.setAuthor (""); - if (mContentFiles.size()==1) createBase(); } diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 5acd80339..3bd892618 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -475,6 +475,8 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mDebugProfiles.addColumn (new ScriptColumn ( ScriptColumn::Type_Lines)); + mMetaData.appendBlankRecord ("sys::meta"); + addModel (new IdTable (&mGlobals), UniversalId::Type_Global); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmst); addModel (new IdTable (&mSkills), UniversalId::Type_Skill); @@ -515,6 +517,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc UniversalId::Type_Texture); addModel (new ResourceTable (&mResourcesManager.get (UniversalId::Type_Videos)), UniversalId::Type_Video); + addModel (new IdTable (&mMetaData), UniversalId::Type_MetaData); mRefLoadCache.clear(); // clear here rather than startLoading() and continueLoading() for multiple content files } @@ -803,6 +806,11 @@ const CSMWorld::Resources& CSMWorld::Data::getResources (const UniversalId& id) return mResourcesManager.get (id.getType()); } +const CSMWorld::MetaData& CSMWorld::Data::getMetaData() const +{ + return mMetaData.getRecord (0).get(); +} + QAbstractItemModel *CSMWorld::Data::getTableModel (const CSMWorld::UniversalId& id) { std::map::iterator iter = mModelIndex.find (id.getType()); @@ -847,9 +855,12 @@ int CSMWorld::Data::startLoading (const boost::filesystem::path& path, bool base mBase = base; mProject = project; - mAuthor = mReader->getAuthor(); - mDescription = mReader->getDesc(); + MetaData metaData; + metaData.mId = "sys::meta"; + metaData.load (*mReader); + mMetaData.setRecord (0, Record (RecordBase::State_ModifiedOnly, 0, &metaData)); + return mReader->getRecordCount(); } @@ -1103,24 +1114,14 @@ int CSMWorld::Data::count (RecordBase::State state) const count (state, mPathgrids); } -void CSMWorld::Data::setDescription (const std::string& description) -{ - mDescription = description; -} - std::string CSMWorld::Data::getDescription() const { - return mDescription; -} - -void CSMWorld::Data::setAuthor (const std::string& author) -{ - mAuthor = author; + return mMetaData.getRecord (0).get().mDescription; } std::string CSMWorld::Data::getAuthor() const { - return mAuthor; + return mMetaData.getRecord (0).get().mAuthor; } std::vector CSMWorld::Data::getIds (bool listDeleted) const diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 060e47bd9..edfd4bc31 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -44,6 +44,7 @@ #include "infocollection.hpp" #include "nestedinfocollection.hpp" #include "pathgrid.hpp" +#include "metadata.hpp" #ifndef Q_MOC_RUN #include "subcellcollection.hpp" #endif @@ -94,11 +95,10 @@ namespace CSMWorld RefIdCollection mReferenceables; RefCollection mRefs; IdCollection mFilters; + Collection mMetaData; const ResourcesManager& mResourcesManager; std::vector mModels; std::map mModelIndex; - std::string mAuthor; - std::string mDescription; ESM::ESMReader *mReader; const ESM::Dialogue *mDialogue; // last loaded dialogue bool mBase; @@ -238,6 +238,8 @@ namespace CSMWorld /// Throws an exception, if \a id does not match a resources list. const Resources& getResources (const UniversalId& id) const; + const MetaData& getMetaData() const; + QAbstractItemModel *getTableModel (const UniversalId& id); ///< If no table model is available for \a id, an exception is thrown. /// @@ -267,12 +269,8 @@ namespace CSMWorld int count (RecordBase::State state) const; ///< Return number of top-level records with the given \a state. - void setDescription (const std::string& description); - std::string getDescription() const; - void setAuthor (const std::string& author); - std::string getAuthor() const; signals: diff --git a/apps/opencs/model/world/metadata.cpp b/apps/opencs/model/world/metadata.cpp new file mode 100644 index 000000000..40b8e9519 --- /dev/null +++ b/apps/opencs/model/world/metadata.cpp @@ -0,0 +1,27 @@ + +#include "metadata.hpp" + +#include +#include +#include + +void CSMWorld::MetaData::blank() +{ + mFormat = ESM::Header::CurrentFormat; + mAuthor.clear(); + mDescription.clear(); +} + +void CSMWorld::MetaData::load (ESM::ESMReader& esm) +{ + mFormat = esm.getHeader().mFormat; + mAuthor = esm.getHeader().mData.author.toString(); + mDescription = esm.getHeader().mData.desc.toString(); +} + +void CSMWorld::MetaData::save (ESM::ESMWriter& esm) const +{ + esm.setFormat (mFormat); + esm.setAuthor (mAuthor); + esm.setDescription (mDescription); +} diff --git a/apps/opencs/model/world/metadata.hpp b/apps/opencs/model/world/metadata.hpp new file mode 100644 index 000000000..f8df2690e --- /dev/null +++ b/apps/opencs/model/world/metadata.hpp @@ -0,0 +1,29 @@ +#ifndef CSM_WOLRD_METADATA_H +#define CSM_WOLRD_METADATA_H + +#include + +namespace ESM +{ + class ESMReader; + class ESMWriter; +} + +namespace CSMWorld +{ + struct MetaData + { + std::string mId; + + int mFormat; + std::string mAuthor; + std::string mDescription; + + void blank(); + + void load (ESM::ESMReader& esm); + void save (ESM::ESMWriter& esm) const; + }; +} + +#endif diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index e496fe79b..584bf5e70 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -120,6 +120,7 @@ namespace { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_MagicEffect, "Magic Effect", 0 }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Pathgrid, "Pathgrid", 0 }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_StartScript, "Start Script", 0 }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_MetaData, "Meta Data", 0 }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0, 0 } // end marker }; diff --git a/apps/opencs/model/world/universalid.hpp b/apps/opencs/model/world/universalid.hpp index 0a9fa3847..752504bc4 100644 --- a/apps/opencs/model/world/universalid.hpp +++ b/apps/opencs/model/world/universalid.hpp @@ -131,6 +131,7 @@ namespace CSMWorld Type_StartScripts, Type_StartScript, Type_Search, + Type_MetaData, Type_RunLog }; From 1870b087e7b3f9454c5450cfdbe30f6b86358054 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 26 Jun 2015 13:13:22 +0200 Subject: [PATCH 1654/3725] ported setting of meta data for saving to the new mechanism --- apps/opencs/model/doc/savingstages.cpp | 6 ++---- apps/opencs/model/world/data.cpp | 10 ---------- apps/opencs/model/world/data.hpp | 4 ---- 3 files changed, 2 insertions(+), 18 deletions(-) diff --git a/apps/opencs/model/doc/savingstages.cpp b/apps/opencs/model/doc/savingstages.cpp index d6258da6a..f78c57ecd 100644 --- a/apps/opencs/model/doc/savingstages.cpp +++ b/apps/opencs/model/doc/savingstages.cpp @@ -53,18 +53,16 @@ void CSMDoc::WriteHeaderStage::perform (int stage, Messages& messages) mState.getWriter().clearMaster(); - mState.getWriter().setFormat (0); - if (mSimple) { mState.getWriter().setAuthor (""); mState.getWriter().setDescription (""); mState.getWriter().setRecordCount (0); + mState.getWriter().setFormat (ESM::Header::CurrentFormat); } else { - mState.getWriter().setAuthor (mDocument.getData().getAuthor()); - mState.getWriter().setDescription (mDocument.getData().getDescription()); + mDocument.getData().getMetaData().save (mState.getWriter()); mState.getWriter().setRecordCount ( mDocument.getData().count (CSMWorld::RecordBase::State_Modified) + mDocument.getData().count (CSMWorld::RecordBase::State_ModifiedOnly) + diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 3bd892618..368c7a766 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -1114,16 +1114,6 @@ int CSMWorld::Data::count (RecordBase::State state) const count (state, mPathgrids); } -std::string CSMWorld::Data::getDescription() const -{ - return mMetaData.getRecord (0).get().mDescription; -} - -std::string CSMWorld::Data::getAuthor() const -{ - return mMetaData.getRecord (0).get().mAuthor; -} - std::vector CSMWorld::Data::getIds (bool listDeleted) const { std::vector ids; diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index edfd4bc31..15e39b9ba 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -269,10 +269,6 @@ namespace CSMWorld int count (RecordBase::State state) const; ///< Return number of top-level records with the given \a state. - std::string getDescription() const; - - std::string getAuthor() const; - signals: void idListChanged(); From 5a37530c1c296b15b273b5da3cc53e10b6db7a63 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 26 Jun 2015 15:17:18 +0200 Subject: [PATCH 1655/3725] added missing MetaData table UniversalId type --- apps/opencs/model/world/universalid.cpp | 1 + apps/opencs/model/world/universalid.hpp | 1 + 2 files changed, 2 insertions(+) diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index 584bf5e70..73d893a26 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -56,6 +56,7 @@ namespace { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_MagicEffects, "Magic Effects", 0 }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Pathgrids, "Pathgrids", 0 }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_StartScripts, "Start Scripts", 0 }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_MetaDatas, "Meta Data Table", 0 }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0, 0 } // end marker }; diff --git a/apps/opencs/model/world/universalid.hpp b/apps/opencs/model/world/universalid.hpp index 752504bc4..e9104fc22 100644 --- a/apps/opencs/model/world/universalid.hpp +++ b/apps/opencs/model/world/universalid.hpp @@ -131,6 +131,7 @@ namespace CSMWorld Type_StartScripts, Type_StartScript, Type_Search, + Type_MetaDatas, Type_MetaData, Type_RunLog }; From 10fbe6aada504ebd0e5afebdc5569382f5051806 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 26 Jun 2015 15:17:47 +0200 Subject: [PATCH 1656/3725] split DialogueSubView in SimpleDialogueSubView and DialogueSubView --- apps/opencs/view/world/dialoguesubview.cpp | 336 ++++++++++++--------- apps/opencs/view/world/dialoguesubview.hpp | 55 +++- 2 files changed, 226 insertions(+), 165 deletions(-) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 284c5928b..d588c2edb 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -548,12 +548,38 @@ void CSVWorld::EditWidget::remake(int row) this->setWidgetResizable(true); } -/* -==============================DialogueSubView========================================== -*/ -CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document, - const CreatorFactoryBase& creatorFactory, bool sorting) : +QVBoxLayout& CSVWorld::SimpleDialogueSubView::getMainLayout() +{ + return *mMainLayout; +} + +CSMWorld::IdTable& CSVWorld::SimpleDialogueSubView::getTable() +{ + return *mTable; +} + +CSMWorld::CommandDispatcher& CSVWorld::SimpleDialogueSubView::getCommandDispatcher() +{ + return mCommandDispatcher; +} + +std::string CSVWorld::SimpleDialogueSubView::getCurrentId() const +{ + return mCurrentId; +} + +CSVWorld::EditWidget& CSVWorld::SimpleDialogueSubView::getEditWidget() +{ + return *mEditWidget; +} + +bool CSVWorld::SimpleDialogueSubView::isLocked() const +{ + return mLocked; +} + +CSVWorld::SimpleDialogueSubView::SimpleDialogueSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) : SubView (id), mEditWidget(0), mMainLayout(NULL), @@ -570,42 +596,150 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSM QWidget *mainWidget = new QWidget(this); + mMainLayout = new QVBoxLayout(mainWidget); + setWidget (mainWidget); + + mEditWidget = new EditWidget(mainWidget, + mTable->getModelIndex(mCurrentId, 0).row(), mTable, mCommandDispatcher, document, false); + + mMainLayout->addWidget(mEditWidget); + mEditWidget->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); + + dataChanged(mTable->getModelIndex (mCurrentId, 0)); +} + +void CSVWorld::SimpleDialogueSubView::setEditLock (bool locked) +{ + if (!mEditWidget) // hack to indicate that mCurrentId is no longer valid + return; + + mLocked = locked; + QModelIndex currentIndex(mTable->getModelIndex(mCurrentId, 0)); + + if (currentIndex.isValid()) + { + CSMWorld::RecordBase::State state = static_cast(mTable->data (mTable->index (currentIndex.row(), 1)).toInt()); + + mEditWidget->setDisabled (state==CSMWorld::RecordBase::State_Deleted || locked); + + mCommandDispatcher.setEditLock (locked); + } + +} + +void CSVWorld::SimpleDialogueSubView::dataChanged (const QModelIndex & index) +{ + QModelIndex currentIndex(mTable->getModelIndex(mCurrentId, 0)); + + if (currentIndex.isValid() && + (index.parent().isValid() ? index.parent().row() : index.row()) == currentIndex.row()) + { + CSMWorld::RecordBase::State state = static_cast(mTable->data (mTable->index (currentIndex.row(), 1)).toInt()); + + mEditWidget->setDisabled (state==CSMWorld::RecordBase::State_Deleted || mLocked); + + // Check if the changed data should force refresh (rebuild) the dialogue subview + int flags = 0; + if (index.parent().isValid()) // TODO: check that index is topLeft + { + flags = static_cast(mTable)->nestedHeaderData (index.parent().column(), + index.column(), Qt::Horizontal, CSMWorld::ColumnBase::Role_Flags).toInt(); + } + else + { + flags = mTable->headerData (index.column(), + Qt::Horizontal, CSMWorld::ColumnBase::Role_Flags).toInt(); + } + + if (flags & CSMWorld::ColumnBase::Flag_Dialogue_Refresh) + { + int y = mEditWidget->verticalScrollBar()->value(); + mEditWidget->remake (index.parent().isValid() ? index.parent().row() : index.row()); + mEditWidget->verticalScrollBar()->setValue(y); + } + } +} + +void CSVWorld::SimpleDialogueSubView::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) +{ + QModelIndex currentIndex(mTable->getModelIndex(mCurrentId, 0)); + + if (currentIndex.isValid() && currentIndex.row() >= start && currentIndex.row() <= end) + { + if(mEditWidget) + { + delete mEditWidget; + mEditWidget = 0; + } + emit closeRequest(this); + } +} + +void CSVWorld::SimpleDialogueSubView::requestFocus (const std::string& id) +{ + changeCurrentId(id); + + mEditWidget->remake(mTable->getModelIndex (id, 0).row()); +} + +void CSVWorld::SimpleDialogueSubView::changeCurrentId (const std::string& newId) +{ + std::vector selection; + mCurrentId = std::string(newId); + + selection.push_back(mCurrentId); + mCommandDispatcher.setSelection(selection); +} + + +CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, + CSMDoc::Document& document, const CreatorFactoryBase& creatorFactory, bool sorting) +: SimpleDialogueSubView (id, document) +{ + // bottom box + getMainLayout().addWidget (mBottom = new TableBottomBox (creatorFactory, document, id, this)); + + mBottom->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed); + + connect(mBottom, SIGNAL(requestFocus(const std::string&)), this, SLOT(requestFocus(const std::string&))); + + // buttons QHBoxLayout *buttonsLayout = new QHBoxLayout; - QToolButton* prevButton = new QToolButton(mainWidget); + QToolButton* prevButton = new QToolButton (this); prevButton->setIcon(QIcon(":/go-previous.png")); prevButton->setToolTip ("Switch to previous record"); - QToolButton* nextButton = new QToolButton(mainWidget); + QToolButton* nextButton = new QToolButton (this); nextButton->setIcon(QIcon(":/go-next.png")); nextButton->setToolTip ("Switch to next record"); buttonsLayout->addWidget(prevButton, 0); buttonsLayout->addWidget(nextButton, 1); buttonsLayout->addStretch(2); - QToolButton* cloneButton = new QToolButton(mainWidget); + QToolButton* cloneButton = new QToolButton (this); cloneButton->setIcon(QIcon(":/edit-clone.png")); cloneButton->setToolTip ("Clone record"); - QToolButton* addButton = new QToolButton(mainWidget); + QToolButton* addButton = new QToolButton (this); addButton->setIcon(QIcon(":/add.png")); addButton->setToolTip ("Add new record"); - QToolButton* deleteButton = new QToolButton(mainWidget); + QToolButton* deleteButton = new QToolButton (this); deleteButton->setIcon(QIcon(":/edit-delete.png")); deleteButton->setToolTip ("Delete record"); - QToolButton* revertButton = new QToolButton(mainWidget); + QToolButton* revertButton = new QToolButton (this); revertButton->setIcon(QIcon(":/edit-undo.png")); revertButton->setToolTip ("Revert record"); - if (mTable->getFeatures() & CSMWorld::IdTable::Feature_Preview) + if (getTable().getFeatures() & CSMWorld::IdTable::Feature_Preview) { - QToolButton* previewButton = new QToolButton(mainWidget); + QToolButton* previewButton = new QToolButton (this); previewButton->setIcon(QIcon(":/edit-preview.png")); previewButton->setToolTip ("Open a preview of this record"); buttonsLayout->addWidget(previewButton); connect(previewButton, SIGNAL(clicked()), this, SLOT(showPreview())); } - if (mTable->getFeatures() & CSMWorld::IdTable::Feature_View) + if (getTable().getFeatures() & CSMWorld::IdTable::Feature_View) { - QToolButton* viewButton = new QToolButton(mainWidget); + QToolButton* viewButton = new QToolButton (this); viewButton->setIcon(QIcon(":/cell.png")); viewButton->setToolTip ("Open a scene view of the cell this record is located in"); buttonsLayout->addWidget(viewButton); @@ -620,22 +754,8 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSM connect(nextButton, SIGNAL(clicked()), this, SLOT(nextId())); connect(prevButton, SIGNAL(clicked()), this, SLOT(prevId())); connect(cloneButton, SIGNAL(clicked()), this, SLOT(cloneRequest())); - connect(revertButton, SIGNAL(clicked()), &mCommandDispatcher, SLOT(executeRevert())); - connect(deleteButton, SIGNAL(clicked()), &mCommandDispatcher, SLOT(executeDelete())); - - mMainLayout = new QVBoxLayout(mainWidget); - - mEditWidget = new EditWidget(mainWidget, - mTable->getModelIndex(mCurrentId, 0).row(), mTable, mCommandDispatcher, document, false); - - mMainLayout->addWidget(mEditWidget); - mEditWidget->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); - - mMainLayout->addWidget (mBottom = new TableBottomBox (creatorFactory, document, id, this)); - - mBottom->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed); - - connect(mBottom, SIGNAL(requestFocus(const std::string&)), this, SLOT(requestFocus(const std::string&))); + connect(revertButton, SIGNAL(clicked()), &getCommandDispatcher(), SLOT(executeRevert())); + connect(deleteButton, SIGNAL(clicked()), &getCommandDispatcher(), SLOT(executeDelete())); connect(addButton, SIGNAL(clicked()), mBottom, SLOT(createRequest())); @@ -646,14 +766,19 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSM deleteButton->setDisabled (true); } - dataChanged(mTable->getModelIndex (mCurrentId, 0)); - mMainLayout->addLayout (buttonsLayout); - setWidget (mainWidget); + getMainLayout().addLayout (buttonsLayout); } -void CSVWorld::DialogueSubView::prevId () +void CSVWorld::DialogueSubView::cloneRequest() { - int newRow = mTable->getModelIndex(mCurrentId, 0).row() - 1; + mBottom->cloneRequest (getCurrentId(), + static_cast (getTable(). + data (getTable().getModelIndex(getCurrentId(), 2)).toInt())); +} + +void CSVWorld::DialogueSubView::prevId() +{ + int newRow = getTable().getModelIndex (getCurrentId(), 0).row() - 1; if (newRow < 0) { @@ -661,26 +786,26 @@ void CSVWorld::DialogueSubView::prevId () } while (newRow >= 0) { - QModelIndex newIndex(mTable->index(newRow, 0)); + QModelIndex newIndex (getTable().index(newRow, 0)); if (!newIndex.isValid()) { return; } - CSMWorld::RecordBase::State state = static_cast(mTable->data (mTable->index (newRow, 1)).toInt()); + CSMWorld::RecordBase::State state = static_cast (getTable().data (getTable().index (newRow, 1)).toInt()); if (!(state == CSMWorld::RecordBase::State_Deleted || state == CSMWorld::RecordBase::State_Erased)) { - mEditWidget->remake(newRow); + getEditWidget().remake (newRow); - setUniversalId(CSMWorld::UniversalId (static_cast (mTable->data (mTable->index (newRow, 2)).toInt()), - mTable->data (mTable->index (newRow, 0)).toString().toUtf8().constData())); + setUniversalId(CSMWorld::UniversalId (static_cast (getTable().data (getTable().index (newRow, 2)).toInt()), + getTable().data (getTable().index (newRow, 0)).toString().toUtf8().constData())); - changeCurrentId(std::string(mTable->data (mTable->index (newRow, 0)).toString().toUtf8().constData())); + changeCurrentId(std::string (getTable().data (getTable().index (newRow, 0)).toString().toUtf8().constData())); - mEditWidget->setDisabled(mLocked); + getEditWidget().setDisabled (isLocked()); - return; + return; } --newRow; } @@ -688,150 +813,63 @@ void CSVWorld::DialogueSubView::prevId () void CSVWorld::DialogueSubView::nextId () { - int newRow = mTable->getModelIndex(mCurrentId, 0).row() + 1; + int newRow = getTable().getModelIndex (getCurrentId(), 0).row() + 1; - if (newRow >= mTable->rowCount()) + if (newRow >= getTable().rowCount()) { return; } - while (newRow < mTable->rowCount()) + while (newRow < getTable().rowCount()) { - QModelIndex newIndex(mTable->index(newRow, 0)); + QModelIndex newIndex (getTable().index(newRow, 0)); if (!newIndex.isValid()) { return; } - CSMWorld::RecordBase::State state = static_cast(mTable->data (mTable->index (newRow, 1)).toInt()); + CSMWorld::RecordBase::State state = static_cast (getTable().data (getTable().index (newRow, 1)).toInt()); if (!(state == CSMWorld::RecordBase::State_Deleted)) { - mEditWidget->remake(newRow); + getEditWidget().remake(newRow); - setUniversalId(CSMWorld::UniversalId (static_cast (mTable->data (mTable->index (newRow, 2)).toInt()), - mTable->data (mTable->index (newRow, 0)).toString().toUtf8().constData())); + setUniversalId(CSMWorld::UniversalId (static_cast (getTable().data (getTable().index (newRow, 2)).toInt()), + getTable().data (getTable().index (newRow, 0)).toString().toUtf8().constData())); - changeCurrentId(std::string(mTable->data (mTable->index (newRow, 0)).toString().toUtf8().constData())); + changeCurrentId(std::string (getTable().data (getTable().index (newRow, 0)).toString().toUtf8().constData())); - mEditWidget->setDisabled(mLocked); + getEditWidget().setDisabled (isLocked()); - return; + return; } ++newRow; } } -void CSVWorld::DialogueSubView::setEditLock (bool locked) -{ - if (!mEditWidget) // hack to indicate that mCurrentId is no longer valid - return; - - mLocked = locked; - QModelIndex currentIndex(mTable->getModelIndex(mCurrentId, 0)); - - if (currentIndex.isValid()) - { - CSMWorld::RecordBase::State state = static_cast(mTable->data (mTable->index (currentIndex.row(), 1)).toInt()); - - mEditWidget->setDisabled (state==CSMWorld::RecordBase::State_Deleted || locked); - - mCommandDispatcher.setEditLock (locked); - } - -} - -void CSVWorld::DialogueSubView::dataChanged (const QModelIndex & index) -{ - QModelIndex currentIndex(mTable->getModelIndex(mCurrentId, 0)); - - if (currentIndex.isValid() && - (index.parent().isValid() ? index.parent().row() : index.row()) == currentIndex.row()) - { - CSMWorld::RecordBase::State state = static_cast(mTable->data (mTable->index (currentIndex.row(), 1)).toInt()); - - mEditWidget->setDisabled (state==CSMWorld::RecordBase::State_Deleted || mLocked); - - // Check if the changed data should force refresh (rebuild) the dialogue subview - int flags = 0; - if (index.parent().isValid()) // TODO: check that index is topLeft - { - flags = static_cast(mTable)->nestedHeaderData (index.parent().column(), - index.column(), Qt::Horizontal, CSMWorld::ColumnBase::Role_Flags).toInt(); - } - else - { - flags = mTable->headerData (index.column(), - Qt::Horizontal, CSMWorld::ColumnBase::Role_Flags).toInt(); - } - - if (flags & CSMWorld::ColumnBase::Flag_Dialogue_Refresh) - { - int y = mEditWidget->verticalScrollBar()->value(); - mEditWidget->remake (index.parent().isValid() ? index.parent().row() : index.row()); - mEditWidget->verticalScrollBar()->setValue(y); - } - } -} - -void CSVWorld::DialogueSubView::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) -{ - QModelIndex currentIndex(mTable->getModelIndex(mCurrentId, 0)); - - if (currentIndex.isValid() && currentIndex.row() >= start && currentIndex.row() <= end) - { - if(mEditWidget) - { - delete mEditWidget; - mEditWidget = 0; - } - emit closeRequest(this); - } -} - -void CSVWorld::DialogueSubView::requestFocus (const std::string& id) -{ - changeCurrentId(id); - - mEditWidget->remake(mTable->getModelIndex (id, 0).row()); -} - -void CSVWorld::DialogueSubView::cloneRequest () -{ - mBottom->cloneRequest(mCurrentId, static_cast(mTable->data(mTable->getModelIndex(mCurrentId, 2)).toInt())); -} void CSVWorld::DialogueSubView::showPreview () { - QModelIndex currentIndex(mTable->getModelIndex(mCurrentId, 0)); + QModelIndex currentIndex (getTable().getModelIndex (getCurrentId(), 0)); if (currentIndex.isValid() && - mTable->getFeatures() & CSMWorld::IdTable::Feature_Preview && - currentIndex.row() < mTable->rowCount()) + getTable().getFeatures() & CSMWorld::IdTable::Feature_Preview && + currentIndex.row() < getTable().rowCount()) { - emit focusId(CSMWorld::UniversalId(CSMWorld::UniversalId::Type_Preview, mCurrentId), ""); + emit focusId(CSMWorld::UniversalId(CSMWorld::UniversalId::Type_Preview, getCurrentId()), ""); } } void CSVWorld::DialogueSubView::viewRecord () { - QModelIndex currentIndex(mTable->getModelIndex (mCurrentId, 0)); + QModelIndex currentIndex (getTable().getModelIndex (getCurrentId(), 0)); if (currentIndex.isValid() && - currentIndex.row() < mTable->rowCount()) + currentIndex.row() < getTable().rowCount()) { - std::pair params = mTable->view (currentIndex.row()); + std::pair params = getTable().view (currentIndex.row()); if (params.first.getType()!=CSMWorld::UniversalId::Type_None) emit focusId (params.first, params.second); } } - -void CSVWorld::DialogueSubView::changeCurrentId (const std::string& newId) -{ - std::vector selection; - mCurrentId = std::string(newId); - - selection.push_back(mCurrentId); - mCommandDispatcher.setSelection(selection); -} diff --git a/apps/opencs/view/world/dialoguesubview.hpp b/apps/opencs/view/world/dialoguesubview.hpp index 69e0dc864..5d6915d42 100644 --- a/apps/opencs/view/world/dialoguesubview.hpp +++ b/apps/opencs/view/world/dialoguesubview.hpp @@ -173,7 +173,7 @@ namespace CSVWorld void remake(int row); }; - class DialogueSubView : public CSVDoc::SubView + class SimpleDialogueSubView : public CSVDoc::SubView { Q_OBJECT @@ -184,32 +184,31 @@ namespace CSVWorld std::string mCurrentId; bool mLocked; const CSMDoc::Document& mDocument; - TableBottomBox* mBottom; CSMWorld::CommandDispatcher mCommandDispatcher; - public: + protected: - DialogueSubView (const CSMWorld::UniversalId& id, - CSMDoc::Document& document, - const CreatorFactoryBase& creatorFactory, - bool sorting = false); + QVBoxLayout& getMainLayout(); - virtual void setEditLock (bool locked); + CSMWorld::IdTable& getTable(); - private: - void changeCurrentId(const std::string& newCurrent); + CSMWorld::CommandDispatcher& getCommandDispatcher(); - private slots: + std::string getCurrentId() const; - void nextId(); + EditWidget& getEditWidget(); - void prevId(); + void changeCurrentId(const std::string& newCurrent); - void showPreview(); + bool isLocked() const; + + public: - void viewRecord(); + SimpleDialogueSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document); - void cloneRequest(); + virtual void setEditLock (bool locked); + + private slots: void dataChanged(const QModelIndex & index); ///\brief we need to care for deleting currently edited record @@ -218,6 +217,30 @@ namespace CSVWorld void rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end); }; + + class DialogueSubView : public SimpleDialogueSubView + { + Q_OBJECT + + TableBottomBox* mBottom; + + public: + + DialogueSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document, + const CreatorFactoryBase& creatorFactory, bool sorting = false); + + private slots: + + void cloneRequest(); + + void nextId(); + + void prevId(); + + void showPreview(); + + void viewRecord(); + }; } #endif From 57015f366609f57a0ac727796585a2bace3915aa Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 26 Jun 2015 15:50:36 +0200 Subject: [PATCH 1657/3725] fixed handling of numeric read-only fields in dialogue sub views --- apps/opencs/view/world/dialoguesubview.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index d588c2edb..99650834e 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -64,16 +64,24 @@ void CSVWorld::NotEditableSubDelegate::setEditorData (QWidget* editor, const QMo } } + CSMWorld::Columns::ColumnId columnId = static_cast ( + mTable->getColumnId (index.column())); + if (QVariant::String == v.type()) { label->setText(v.toString()); } - else //else we are facing enums + else if (CSMWorld::Columns::hasEnums (columnId)) { int data = v.toInt(); - std::vector enumNames (CSMWorld::Columns::getEnums (static_cast (mTable->getColumnId (index.column())))); + std::vector enumNames (CSMWorld::Columns::getEnums (columnId)); + label->setText(QString::fromUtf8(enumNames.at(data).c_str())); } + else + { + label->setText (v.toString()); + } } void CSVWorld::NotEditableSubDelegate::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const From 1e033fa8fe87f8eac5b6414b697d5a55b066bead Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 26 Jun 2015 16:11:00 +0200 Subject: [PATCH 1658/3725] added meta data dialogue sub view --- apps/opencs/model/world/columnimp.hpp | 72 +++++++++++++++++++++++++++ apps/opencs/model/world/columns.cpp | 4 ++ apps/opencs/model/world/columns.hpp | 4 ++ apps/opencs/model/world/data.cpp | 8 ++- apps/opencs/view/doc/view.cpp | 9 ++++ apps/opencs/view/doc/view.hpp | 2 + apps/opencs/view/world/subviews.cpp | 3 ++ 7 files changed, 101 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index a8ae5dfa1..ba23a3603 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -2308,6 +2308,78 @@ namespace CSMWorld return true; } }; + + template + struct FormatColumn : public Column + { + FormatColumn() + : Column (Columns::ColumnId_FileFormat, ColumnBase::Display_Integer) + {} + + virtual QVariant get (const Record& record) const + { + return record.get().mFormat; + } + + virtual bool isEditable() const + { + return false; + } + }; + + template + struct AuthorColumn : public Column + { + AuthorColumn() + : Column (Columns::ColumnId_Author, ColumnBase::Display_String) + {} + + virtual QVariant get (const Record& record) const + { + return QString::fromUtf8 (record.get().mAuthor.c_str()); + } + + virtual void set (Record& record, const QVariant& data) + { + ESXRecordT record2 = record.get(); + + record2.mAuthor = data.toString().toUtf8().constData(); + + record.setModified (record2); + } + + virtual bool isEditable() const + { + return true; + } + }; + + template + struct FileDescriptionColumn : public Column + { + FileDescriptionColumn() + : Column (Columns::ColumnId_FileDescription, ColumnBase::Display_LongString) + {} + + virtual QVariant get (const Record& record) const + { + return QString::fromUtf8 (record.get().mDescription.c_str()); + } + + virtual void set (Record& record, const QVariant& data) + { + ESXRecordT record2 = record.get(); + + record2.mDescription = data.toString().toUtf8().constData(); + + record.setModified (record2); + } + + virtual bool isEditable() const + { + return true; + } + }; } #endif diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 9491c3246..d6e27caeb 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -311,6 +311,10 @@ namespace CSMWorld { ColumnId_WaterLevel, "Water Level" }, { ColumnId_MapColor, "Map Color" }, + { ColumnId_FileFormat, "File Format" }, + { ColumnId_FileDescription, "File Description" }, + { ColumnId_Author, "Author" }, + { ColumnId_UseValue1, "Use value 1" }, { ColumnId_UseValue2, "Use value 2" }, { ColumnId_UseValue3, "Use value 3" }, diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 191bbdea8..d699c67b7 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -302,6 +302,10 @@ namespace CSMWorld ColumnId_WaterLevel = 273, ColumnId_MapColor = 274, + ColumnId_FileFormat = 275, + ColumnId_FileDescription = 276, + ColumnId_Author = 277, + // Allocated to a separate value range, so we don't get a collision should we ever need // to extend the number of use values. ColumnId_UseValue1 = 0x10000, diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 368c7a766..29f7fa9b8 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -476,7 +476,13 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc ScriptColumn::Type_Lines)); mMetaData.appendBlankRecord ("sys::meta"); - + + mMetaData.addColumn (new StringIdColumn (true)); + mMetaData.addColumn (new RecordStateColumn); + mMetaData.addColumn (new FormatColumn); + mMetaData.addColumn (new AuthorColumn); + mMetaData.addColumn (new FileDescriptionColumn); + addModel (new IdTable (&mGlobals), UniversalId::Type_Global); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmst); addModel (new IdTable (&mSkills), UniversalId::Type_Skill); diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 64b066eb1..c4abb2622 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -70,6 +70,10 @@ void CSVDoc::View::setupFileMenu() connect (loadErrors, SIGNAL (triggered()), this, SLOT (loadErrorLog())); file->addAction (loadErrors); + QAction *meta = new QAction (tr ("Meta Data"), this); + connect (meta, SIGNAL (triggered()), this, SLOT (addMetaDataSubView())); + file->addAction (meta); + QAction *close = new QAction (tr ("&Close"), this); connect (close, SIGNAL (triggered()), this, SLOT (close())); file->addAction(close); @@ -813,6 +817,11 @@ void CSVDoc::View::addSearchSubView() addSubView (mDocument->newSearch()); } +void CSVDoc::View::addMetaDataSubView() +{ + addSubView (CSMWorld::UniversalId (CSMWorld::UniversalId::Type_MetaData, "sys::meta")); +} + void CSVDoc::View::abortOperation (int type) { mDocument->abortOperation (type); diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index 814dabc6b..7f4255f8f 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -224,6 +224,8 @@ namespace CSVDoc void addSearchSubView(); + void addMetaDataSubView(); + void toggleShowStatusBar (bool show); void loadErrorLog(); diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp index ba3ab1358..b8a6ba429 100644 --- a/apps/opencs/view/world/subviews.cpp +++ b/apps/opencs/view/world/subviews.cpp @@ -170,6 +170,9 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) manager.add (CSMWorld::UniversalId::Type_Filter, new CSVDoc::SubViewFactoryWithCreator > (false)); + manager.add (CSMWorld::UniversalId::Type_MetaData, + new CSVDoc::SubViewFactory); + //preview manager.add (CSMWorld::UniversalId::Type_Preview, new CSVDoc::SubViewFactory); } From a4c2c75d1fafd5458bfae3d555f55b8ab4a00844 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 26 Jun 2015 16:22:06 +0200 Subject: [PATCH 1659/3725] fixed overwriting of meta data when loading project file --- apps/opencs/model/world/data.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 29f7fa9b8..b38607748 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -861,11 +861,14 @@ int CSMWorld::Data::startLoading (const boost::filesystem::path& path, bool base mBase = base; mProject = project; - MetaData metaData; - metaData.mId = "sys::meta"; - metaData.load (*mReader); + if (!mProject && !mBase) + { + MetaData metaData; + metaData.mId = "sys::meta"; + metaData.load (*mReader); - mMetaData.setRecord (0, Record (RecordBase::State_ModifiedOnly, 0, &metaData)); + mMetaData.setRecord (0, Record (RecordBase::State_ModifiedOnly, 0, &metaData)); + } return mReader->getRecordCount(); } From 59db9664ba4b7111c496e1a7eee9fbe176bf5648 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 26 Jun 2015 17:47:04 +0200 Subject: [PATCH 1660/3725] Pass the CharacterController to AiPackage::execute --- apps/openmw/mwmechanics/actors.cpp | 2 +- apps/openmw/mwmechanics/aiactivate.cpp | 2 +- apps/openmw/mwmechanics/aiactivate.hpp | 2 +- apps/openmw/mwmechanics/aiavoiddoor.cpp | 2 +- apps/openmw/mwmechanics/aiavoiddoor.hpp | 2 +- apps/openmw/mwmechanics/aicombat.cpp | 2 +- apps/openmw/mwmechanics/aicombat.hpp | 2 +- apps/openmw/mwmechanics/aiescort.cpp | 2 +- apps/openmw/mwmechanics/aiescort.hpp | 2 +- apps/openmw/mwmechanics/aifollow.cpp | 2 +- apps/openmw/mwmechanics/aifollow.hpp | 2 +- apps/openmw/mwmechanics/aipackage.hpp | 4 +++- apps/openmw/mwmechanics/aipursue.cpp | 2 +- apps/openmw/mwmechanics/aipursue.hpp | 2 +- apps/openmw/mwmechanics/aisequence.cpp | 4 ++-- apps/openmw/mwmechanics/aisequence.hpp | 3 ++- apps/openmw/mwmechanics/aitravel.cpp | 2 +- apps/openmw/mwmechanics/aitravel.hpp | 2 +- apps/openmw/mwmechanics/aiwander.cpp | 2 +- apps/openmw/mwmechanics/aiwander.hpp | 2 +- 20 files changed, 24 insertions(+), 21 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 03ab3d020..2c53c00b7 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1124,7 +1124,7 @@ namespace MWMechanics { CreatureStats &stats = iter->first.getClass().getCreatureStats(iter->first); if (isConscious(iter->first)) - stats.getAiSequence().execute(iter->first,iter->second->getAiState(), duration); + stats.getAiSequence().execute(iter->first, *iter->second->getCharacterController(), iter->second->getAiState(), duration); if (stats.getAiSequence().isInCombat() && !stats.isDead()) hostilesCount++; } diff --git a/apps/openmw/mwmechanics/aiactivate.cpp b/apps/openmw/mwmechanics/aiactivate.cpp index 9e25084d3..b0621c805 100644 --- a/apps/openmw/mwmechanics/aiactivate.cpp +++ b/apps/openmw/mwmechanics/aiactivate.cpp @@ -21,7 +21,7 @@ MWMechanics::AiActivate *MWMechanics::AiActivate::clone() const { return new AiActivate(*this); } -bool MWMechanics::AiActivate::execute (const MWWorld::Ptr& actor, AiState& state, float duration) +bool MWMechanics::AiActivate::execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) { ESM::Position pos = actor.getRefData().getPosition(); //position of the actor const MWWorld::Ptr target = MWBase::Environment::get().getWorld()->searchPtr(mObjectId, false); //The target to follow diff --git a/apps/openmw/mwmechanics/aiactivate.hpp b/apps/openmw/mwmechanics/aiactivate.hpp index e25afe285..2ca985be9 100644 --- a/apps/openmw/mwmechanics/aiactivate.hpp +++ b/apps/openmw/mwmechanics/aiactivate.hpp @@ -28,7 +28,7 @@ namespace MWMechanics AiActivate(const ESM::AiSequence::AiActivate* activate); virtual AiActivate *clone() const; - virtual bool execute (const MWWorld::Ptr& actor, AiState& state, float duration); + virtual bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration); virtual int getTypeId() const; virtual void writeState(ESM::AiSequence::AiSequence& sequence) const; diff --git a/apps/openmw/mwmechanics/aiavoiddoor.cpp b/apps/openmw/mwmechanics/aiavoiddoor.cpp index 29bf19942..457c9a95c 100644 --- a/apps/openmw/mwmechanics/aiavoiddoor.cpp +++ b/apps/openmw/mwmechanics/aiavoiddoor.cpp @@ -17,7 +17,7 @@ MWMechanics::AiAvoidDoor::AiAvoidDoor(const MWWorld::Ptr& doorPtr) } -bool MWMechanics::AiAvoidDoor::execute (const MWWorld::Ptr& actor, AiState& state, float duration) +bool MWMechanics::AiAvoidDoor::execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) { ESM::Position pos = actor.getRefData().getPosition(); diff --git a/apps/openmw/mwmechanics/aiavoiddoor.hpp b/apps/openmw/mwmechanics/aiavoiddoor.hpp index 7590c8fcb..1ad945bca 100644 --- a/apps/openmw/mwmechanics/aiavoiddoor.hpp +++ b/apps/openmw/mwmechanics/aiavoiddoor.hpp @@ -20,7 +20,7 @@ namespace MWMechanics virtual AiAvoidDoor *clone() const; - virtual bool execute (const MWWorld::Ptr& actor, AiState& state, float duration); + virtual bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration); virtual int getTypeId() const; diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 032c304ae..56dd11b99 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -181,7 +181,7 @@ namespace MWMechanics * Use the Observer Pattern to co-ordinate attacks, provide intelligence on * whether the target was hit, etc. */ - bool AiCombat::execute (const MWWorld::Ptr& actor, AiState& state, float duration) + bool AiCombat::execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) { // get or create temporary storage AiCombatStorage& storage = state.get(); diff --git a/apps/openmw/mwmechanics/aicombat.hpp b/apps/openmw/mwmechanics/aicombat.hpp index 94c7beb3a..083f23384 100644 --- a/apps/openmw/mwmechanics/aicombat.hpp +++ b/apps/openmw/mwmechanics/aicombat.hpp @@ -40,7 +40,7 @@ namespace MWMechanics virtual AiCombat *clone() const; - virtual bool execute (const MWWorld::Ptr& actor, AiState& state, float duration); + virtual bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration); virtual int getTypeId() const; diff --git a/apps/openmw/mwmechanics/aiescort.cpp b/apps/openmw/mwmechanics/aiescort.cpp index f9ebefe13..593f9f173 100644 --- a/apps/openmw/mwmechanics/aiescort.cpp +++ b/apps/openmw/mwmechanics/aiescort.cpp @@ -63,7 +63,7 @@ namespace MWMechanics return new AiEscort(*this); } - bool AiEscort::execute (const MWWorld::Ptr& actor, AiState& state, float duration) + bool AiEscort::execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) { // If AiEscort has ran for as long or longer then the duration specified // and the duration is not infinite, the package is complete. diff --git a/apps/openmw/mwmechanics/aiescort.hpp b/apps/openmw/mwmechanics/aiescort.hpp index f02cdba22..9f6335b93 100644 --- a/apps/openmw/mwmechanics/aiescort.hpp +++ b/apps/openmw/mwmechanics/aiescort.hpp @@ -33,7 +33,7 @@ namespace MWMechanics virtual AiEscort *clone() const; - virtual bool execute (const MWWorld::Ptr& actor, AiState& state, float duration); + virtual bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration); virtual int getTypeId() const; diff --git a/apps/openmw/mwmechanics/aifollow.cpp b/apps/openmw/mwmechanics/aifollow.cpp index 524a7f904..a92e9eedc 100644 --- a/apps/openmw/mwmechanics/aifollow.cpp +++ b/apps/openmw/mwmechanics/aifollow.cpp @@ -54,7 +54,7 @@ AiFollow::AiFollow(const ESM::AiSequence::AiFollow *follow) } -bool AiFollow::execute (const MWWorld::Ptr& actor, AiState& state, float duration) +bool AiFollow::execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) { MWWorld::Ptr target = getTarget(); diff --git a/apps/openmw/mwmechanics/aifollow.hpp b/apps/openmw/mwmechanics/aifollow.hpp index 68a1f0ea5..8555f9bc4 100644 --- a/apps/openmw/mwmechanics/aifollow.hpp +++ b/apps/openmw/mwmechanics/aifollow.hpp @@ -35,7 +35,7 @@ namespace MWMechanics virtual AiFollow *clone() const; - virtual bool execute (const MWWorld::Ptr& actor, AiState& state, float duration); + virtual bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration); virtual int getTypeId() const; diff --git a/apps/openmw/mwmechanics/aipackage.hpp b/apps/openmw/mwmechanics/aipackage.hpp index 78a2bfd9f..da43dc6da 100644 --- a/apps/openmw/mwmechanics/aipackage.hpp +++ b/apps/openmw/mwmechanics/aipackage.hpp @@ -25,6 +25,8 @@ namespace ESM namespace MWMechanics { + class CharacterController; + /// \brief Base class for AI packages class AiPackage { @@ -53,7 +55,7 @@ namespace MWMechanics /// Updates and runs the package (Should run every frame) /// \return Package completed? - virtual bool execute (const MWWorld::Ptr& actor, AiState& state, float duration) = 0; + virtual bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) = 0; /// Returns the TypeID of the AiPackage /// \see enum TypeId diff --git a/apps/openmw/mwmechanics/aipursue.cpp b/apps/openmw/mwmechanics/aipursue.cpp index 8c31a10db..ac6b23ef6 100644 --- a/apps/openmw/mwmechanics/aipursue.cpp +++ b/apps/openmw/mwmechanics/aipursue.cpp @@ -30,7 +30,7 @@ AiPursue *MWMechanics::AiPursue::clone() const { return new AiPursue(*this); } -bool AiPursue::execute (const MWWorld::Ptr& actor, AiState& state, float duration) +bool AiPursue::execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) { if(actor.getClass().getCreatureStats(actor).isDead()) return true; diff --git a/apps/openmw/mwmechanics/aipursue.hpp b/apps/openmw/mwmechanics/aipursue.hpp index 493a27985..813b87cff 100644 --- a/apps/openmw/mwmechanics/aipursue.hpp +++ b/apps/openmw/mwmechanics/aipursue.hpp @@ -31,7 +31,7 @@ namespace MWMechanics AiPursue(const ESM::AiSequence::AiPursue* pursue); virtual AiPursue *clone() const; - virtual bool execute (const MWWorld::Ptr& actor, AiState& state, float duration); + virtual bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration); virtual int getTypeId() const; MWWorld::Ptr getTarget() const; diff --git a/apps/openmw/mwmechanics/aisequence.cpp b/apps/openmw/mwmechanics/aisequence.cpp index 0606e5146..3e1f89624 100644 --- a/apps/openmw/mwmechanics/aisequence.cpp +++ b/apps/openmw/mwmechanics/aisequence.cpp @@ -150,7 +150,7 @@ bool AiSequence::isPackageDone() const return mDone; } -void AiSequence::execute (const MWWorld::Ptr& actor, AiState& state,float duration) +void AiSequence::execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) { if(actor != MWBase::Environment::get().getWorld()->getPlayerPtr()) { @@ -211,7 +211,7 @@ void AiSequence::execute (const MWWorld::Ptr& actor, AiState& state,float durati } } - if (package->execute (actor,state,duration)) + if (package->execute (actor,characterController,state,duration)) { // To account for the rare case where AiPackage::execute() queued another AI package // (e.g. AiPursue executing a dialogue script that uses startCombat) diff --git a/apps/openmw/mwmechanics/aisequence.hpp b/apps/openmw/mwmechanics/aisequence.hpp index 19f1e1454..1eefe7c69 100644 --- a/apps/openmw/mwmechanics/aisequence.hpp +++ b/apps/openmw/mwmechanics/aisequence.hpp @@ -24,6 +24,7 @@ namespace ESM namespace MWMechanics { class AiPackage; + class CharacterController; template< class Base > class DerivedClassStorage; struct AiTemporaryBase; @@ -95,7 +96,7 @@ namespace MWMechanics void stopPursuit(); /// Execute current package, switching if needed. - void execute (const MWWorld::Ptr& actor, MWMechanics::AiState& state, float duration); + void execute (const MWWorld::Ptr& actor, CharacterController& characterController, MWMechanics::AiState& state, float duration); /// Simulate the passing of time using the currently active AI package void fastForward(const MWWorld::Ptr &actor, AiState &state); diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index fb6e89cf6..f192bed63 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -47,7 +47,7 @@ namespace MWMechanics return new AiTravel(*this); } - bool AiTravel::execute (const MWWorld::Ptr& actor, AiState& state, float duration) + bool AiTravel::execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) { ESM::Position pos = actor.getRefData().getPosition(); diff --git a/apps/openmw/mwmechanics/aitravel.hpp b/apps/openmw/mwmechanics/aitravel.hpp index a5a4577e6..9f263fd46 100644 --- a/apps/openmw/mwmechanics/aitravel.hpp +++ b/apps/openmw/mwmechanics/aitravel.hpp @@ -30,7 +30,7 @@ namespace MWMechanics virtual AiTravel *clone() const; - virtual bool execute (const MWWorld::Ptr& actor, AiState& state, float duration); + virtual bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration); virtual int getTypeId() const; diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 7e55ac9a2..41cfb9df4 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -168,7 +168,7 @@ namespace MWMechanics * actors will enter combat (i.e. no longer wandering) and different pathfinding * will kick in. */ - bool AiWander::execute (const MWWorld::Ptr& actor, AiState& state, float duration) + bool AiWander::execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) { // get or create temporary storage AiWanderStorage& storage = state.get(); diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 4b83179d5..13e3e571f 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -46,7 +46,7 @@ namespace MWMechanics virtual AiPackage *clone() const; - virtual bool execute (const MWWorld::Ptr& actor, AiState& state, float duration); + virtual bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration); virtual int getTypeId() const; From 4487bda702da64a34913219ccf22a318e0545a21 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 26 Jun 2015 18:19:00 +0200 Subject: [PATCH 1661/3725] size limits for meta data strings --- apps/opencs/model/world/columnbase.cpp | 3 ++- apps/opencs/model/world/columnbase.hpp | 2 ++ apps/opencs/model/world/columnimp.hpp | 4 ++-- apps/opencs/view/world/util.cpp | 16 ++++++++++++++++ 4 files changed, 22 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/world/columnbase.cpp b/apps/opencs/model/world/columnbase.cpp index 938503875..f209e48c6 100644 --- a/apps/opencs/model/world/columnbase.cpp +++ b/apps/opencs/model/world/columnbase.cpp @@ -100,7 +100,8 @@ bool CSMWorld::ColumnBase::isId (Display display) bool CSMWorld::ColumnBase::isText (Display display) { - return display==Display_String || display==Display_LongString; + return display==Display_String || display==Display_LongString || + display==Display_String32 || display==Display_LongString256; } bool CSMWorld::ColumnBase::isScript (Display display) diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index 789823d5c..59f2836c2 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -123,6 +123,8 @@ namespace CSMWorld Display_InfoCondVar, Display_InfoCondComp, Display_RaceSkill, + Display_String32, + Display_LongString256, //top level columns that nest other columns Display_NestedHeader diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index ba23a3603..15dd2c15b 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -2331,7 +2331,7 @@ namespace CSMWorld struct AuthorColumn : public Column { AuthorColumn() - : Column (Columns::ColumnId_Author, ColumnBase::Display_String) + : Column (Columns::ColumnId_Author, ColumnBase::Display_String32) {} virtual QVariant get (const Record& record) const @@ -2358,7 +2358,7 @@ namespace CSMWorld struct FileDescriptionColumn : public Column { FileDescriptionColumn() - : Column (Columns::ColumnId_FileDescription, ColumnBase::Display_LongString) + : Column (Columns::ColumnId_FileDescription, ColumnBase::Display_LongString256) {} virtual QVariant get (const Record& record) const diff --git a/apps/opencs/view/world/util.cpp b/apps/opencs/view/world/util.cpp index 62cde4608..f21658581 100644 --- a/apps/opencs/view/world/util.cpp +++ b/apps/opencs/view/world/util.cpp @@ -232,6 +232,14 @@ QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleO return edit; } + case CSMWorld::ColumnBase::Display_LongString256: + { + /// \todo implement size limit. QPlainTextEdit does not support a size limit. + QPlainTextEdit *edit = new QPlainTextEdit(parent); + edit->setUndoRedoEnabled (false); + return edit; + } + case CSMWorld::ColumnBase::Display_Boolean: return new QCheckBox(parent); @@ -245,6 +253,14 @@ QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleO return new CSVWidget::DropLineEdit(display, parent); + case CSMWorld::ColumnBase::Display_String32: + { + // For other Display types (that represent record IDs) with drop support IdCompletionDelegate is used + CSVWidget::DropLineEdit *widget = new CSVWidget::DropLineEdit(display, parent); + widget->setMaxLength (32); + return widget; + } + default: return QStyledItemDelegate::createEditor (parent, option, index); From 6d5823e8aabefc0031a65c6157fa66de0afcd03c Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 26 Jun 2015 18:54:49 +0200 Subject: [PATCH 1662/3725] killed some tabs --- apps/opencs/model/world/infotableproxymodel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/world/infotableproxymodel.cpp b/apps/opencs/model/world/infotableproxymodel.cpp index e34c50566..6216291d0 100644 --- a/apps/opencs/model/world/infotableproxymodel.cpp +++ b/apps/opencs/model/world/infotableproxymodel.cpp @@ -9,7 +9,7 @@ namespace { QString toLower(const QString &str) { - return QString::fromUtf8(Misc::StringUtils::lowerCase(str.toStdString()).c_str()); + return QString::fromUtf8(Misc::StringUtils::lowerCase(str.toStdString()).c_str()); } } From 502cc852da0f10dae95ba10ec363a2be66707304 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 26 Jun 2015 20:16:32 +0200 Subject: [PATCH 1663/3725] Handle encoding conversions when saving TES3 header (Fixes #2727) --- components/esm/esmwriter.cpp | 9 +++++++++ components/esm/esmwriter.hpp | 1 + components/esm/loadtes3.cpp | 8 +++++++- 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/components/esm/esmwriter.cpp b/components/esm/esmwriter.cpp index c64678e70..4d9999143 100644 --- a/components/esm/esmwriter.cpp +++ b/components/esm/esmwriter.cpp @@ -174,6 +174,15 @@ namespace ESM endRecord(name); } + void ESMWriter::writeFixedSizeString(const std::string &data, int size) + { + std::string string; + if (!data.empty()) + string = mEncoder ? mEncoder->getLegacyEnc(data) : data; + string.resize(size); + write(string.c_str(), string.size()); + } + void ESMWriter::writeHString(const std::string& data) { if (data.size() == 0) diff --git a/components/esm/esmwriter.hpp b/components/esm/esmwriter.hpp index 30cec58b4..d11b3c940 100644 --- a/components/esm/esmwriter.hpp +++ b/components/esm/esmwriter.hpp @@ -120,6 +120,7 @@ public: void startSubRecord(const std::string& name); void endRecord(const std::string& name); void endRecord(uint32_t name); + void writeFixedSizeString(const std::string& data, int size); void writeHString(const std::string& data); void writeHCString(const std::string& data); void writeName(const std::string& data); diff --git a/components/esm/loadtes3.cpp b/components/esm/loadtes3.cpp index 9c0c55b8f..7d749c4d9 100644 --- a/components/esm/loadtes3.cpp +++ b/components/esm/loadtes3.cpp @@ -71,7 +71,13 @@ void ESM::Header::save (ESMWriter &esm) if (mFormat>0) esm.writeHNT ("FORM", mFormat); - esm.writeHNT ("HEDR", mData, 300); + esm.startSubRecord("HEDR"); + esm.writeT(mData.version); + esm.writeT(mData.type); + esm.writeFixedSizeString(mData.author.toString(), 32); + esm.writeFixedSizeString(mData.desc.toString(), 256); + esm.writeT(mData.records); + esm.endRecord("HEDR"); for (std::vector::iterator iter = mMaster.begin(); iter != mMaster.end(); ++iter) From a7f31988d17d20cb9abcf89267641dc82a4d89b8 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Fri, 26 Jun 2015 22:14:11 +0300 Subject: [PATCH 1664/3725] Add the ability to search a nested column index --- apps/opencs/model/world/idtree.cpp | 10 ++++++++ apps/opencs/model/world/idtree.hpp | 6 +++++ apps/opencs/model/world/nestedcollection.cpp | 25 ++++++++++++++++++++ apps/opencs/model/world/nestedcollection.hpp | 8 +++++++ 4 files changed, 49 insertions(+) diff --git a/apps/opencs/model/world/idtree.cpp b/apps/opencs/model/world/idtree.cpp index 1e81d6ac2..9dbe7e002 100644 --- a/apps/opencs/model/world/idtree.cpp +++ b/apps/opencs/model/world/idtree.cpp @@ -261,3 +261,13 @@ CSMWorld::NestedTableWrapperBase* CSMWorld::IdTree::nestedTable(const QModelInde return mNestedCollection->nestedTable(index.row(), index.column()); } + +int CSMWorld::IdTree::searchNestedColumnIndex(int parentColumn, Columns::ColumnId id) +{ + return mNestedCollection->searchNestedColumnIndex(parentColumn, id); +} + +int CSMWorld::IdTree::findNestedColumnIndex(int parentColumn, Columns::ColumnId id) +{ + return mNestedCollection->findNestedColumnIndex(parentColumn, id); +} diff --git a/apps/opencs/model/world/idtree.hpp b/apps/opencs/model/world/idtree.hpp index 5337ed82b..79e93fc3d 100644 --- a/apps/opencs/model/world/idtree.hpp +++ b/apps/opencs/model/world/idtree.hpp @@ -73,6 +73,12 @@ namespace CSMWorld virtual bool hasChildren (const QModelIndex& index) const; + virtual int searchNestedColumnIndex(int parentColumn, Columns::ColumnId id); + ///< \return the column index or -1 if the requested column wasn't found. + + virtual int findNestedColumnIndex(int parentColumn, Columns::ColumnId id); + ///< \return the column index or throws an exception if the requested column wasn't found. + signals: void resetStart(const QString& id); diff --git a/apps/opencs/model/world/nestedcollection.cpp b/apps/opencs/model/world/nestedcollection.cpp index 937ad6ad6..850d8c385 100644 --- a/apps/opencs/model/world/nestedcollection.cpp +++ b/apps/opencs/model/world/nestedcollection.cpp @@ -15,3 +15,28 @@ int CSMWorld::NestedCollection::getNestedColumnsCount(int row, int column) const { return 0; } + +int CSMWorld::NestedCollection::searchNestedColumnIndex(int parentColumn, Columns::ColumnId id) +{ + // Assumed that the parentColumn is always a valid index + const NestableColumn *parent = getNestableColumn(parentColumn); + int nestedColumnCount = getNestedColumnsCount(0, parentColumn); + for (int i = 0; i < nestedColumnCount; ++i) + { + if (parent->nestedColumn(i).mColumnId == id) + { + return i; + } + } + return -1; +} + +int CSMWorld::NestedCollection::findNestedColumnIndex(int parentColumn, Columns::ColumnId id) +{ + int index = searchNestedColumnIndex(parentColumn, id); + if (index == -1) + { + throw std::logic_error("CSMWorld::NestedCollection: No such nested column"); + } + return index; +} diff --git a/apps/opencs/model/world/nestedcollection.hpp b/apps/opencs/model/world/nestedcollection.hpp index b075f53c4..4548cfb2b 100644 --- a/apps/opencs/model/world/nestedcollection.hpp +++ b/apps/opencs/model/world/nestedcollection.hpp @@ -1,6 +1,8 @@ #ifndef CSM_WOLRD_NESTEDCOLLECTION_H #define CSM_WOLRD_NESTEDCOLLECTION_H +#include "columns.hpp" + class QVariant; namespace CSMWorld @@ -33,6 +35,12 @@ namespace CSMWorld virtual int getNestedColumnsCount(int row, int column) const; virtual NestableColumn *getNestableColumn(int column) = 0; + + virtual int searchNestedColumnIndex(int parentColumn, Columns::ColumnId id); + ///< \return the column index or -1 if the requested column wasn't found. + + virtual int findNestedColumnIndex(int parentColumn, Columns::ColumnId id); + ///< \return the column index or throws an exception if the requested column wasn't found. }; } From f3bb00e3d9949c9bf24426551c665d4cbb893825 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Fri, 26 Jun 2015 22:16:12 +0300 Subject: [PATCH 1665/3725] Add the ability to add nested values to the Create command --- apps/opencs/model/world/commands.cpp | 24 ++++++++++++++++++++++++ apps/opencs/model/world/commands.hpp | 5 +++++ 2 files changed, 29 insertions(+) diff --git a/apps/opencs/model/world/commands.cpp b/apps/opencs/model/world/commands.cpp index a44d8770f..5e0cc8f88 100644 --- a/apps/opencs/model/world/commands.cpp +++ b/apps/opencs/model/world/commands.cpp @@ -58,6 +58,25 @@ void CSMWorld::CreateCommand::applyModifications() { for (std::map::const_iterator iter (mValues.begin()); iter!=mValues.end(); ++iter) mModel.setData (mModel.getModelIndex (mId, iter->first), iter->second); + + if (!mNestedValues.empty()) + { + CSMWorld::IdTree *tree = dynamic_cast(&mModel); + if (tree == NULL) + { + throw std::logic_error("CSMWorld::CreateCommand: Attempt to add nested values to the non-nested model"); + } + + std::map >::const_iterator current = mNestedValues.begin(); + std::map >::const_iterator end = mNestedValues.end(); + for (; current != end; ++current) + { + QModelIndex index = tree->index(0, + current->second.first, + tree->getNestedModelIndex(mId, current->first)); + tree->setData(index, current->second.second); + } + } } CSMWorld::CreateCommand::CreateCommand (IdTable& model, const std::string& id, QUndoCommand* parent) @@ -71,6 +90,11 @@ void CSMWorld::CreateCommand::addValue (int column, const QVariant& value) mValues[column] = value; } +void CSMWorld::CreateCommand::addNestedValue(int parentColumn, int nestedColumn, const QVariant &value) +{ + mNestedValues[parentColumn] = std::make_pair(nestedColumn, value); +} + void CSMWorld::CreateCommand::setType (UniversalId::Type type) { mType = type; diff --git a/apps/opencs/model/world/commands.hpp b/apps/opencs/model/world/commands.hpp index cdd398153..81c40d0ab 100644 --- a/apps/opencs/model/world/commands.hpp +++ b/apps/opencs/model/world/commands.hpp @@ -48,6 +48,9 @@ namespace CSMWorld class CreateCommand : public QUndoCommand { std::map mValues; + std::map > mNestedValues; + ///< Parameter order: a parent column, a nested column, a data. + ///< A nested row has index of 0. protected: @@ -68,6 +71,8 @@ namespace CSMWorld void addValue (int column, const QVariant& value); + void addNestedValue(int parentColumn, int nestedColumn, const QVariant &value); + virtual void redo(); virtual void undo(); From 5761ec428d9c56edd9bca7895422127301a6c935 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Fri, 26 Jun 2015 23:38:20 +0300 Subject: [PATCH 1666/3725] Creating/cloning Cell sets the proper Interior flag --- apps/opencs/view/world/cellcreator.cpp | 12 ++++++++++++ apps/opencs/view/world/cellcreator.hpp | 3 +++ 2 files changed, 15 insertions(+) diff --git a/apps/opencs/view/world/cellcreator.cpp b/apps/opencs/view/world/cellcreator.cpp index cdeee5655..5dfb6af45 100644 --- a/apps/opencs/view/world/cellcreator.cpp +++ b/apps/opencs/view/world/cellcreator.cpp @@ -8,6 +8,9 @@ #include #include +#include "../../model/world/commands.hpp" +#include "../../model/world/idtree.hpp" + std::string CSVWorld::CellCreator::getId() const { if (mType->currentIndex()==0) @@ -20,6 +23,15 @@ std::string CSVWorld::CellCreator::getId() const return stream.str(); } +void CSVWorld::CellCreator::configureCreateCommand(CSMWorld::CreateCommand& command) const +{ + CSMWorld::IdTree *model = dynamic_cast(getData().getTableModel(getCollectionId())); + Q_ASSERT(model != NULL); + int parentIndex = model->findColumnIndex(CSMWorld::Columns::ColumnId_Cell); + int index = model->findNestedColumnIndex(parentIndex, CSMWorld::Columns::ColumnId_Interior); + command.addNestedValue(parentIndex, index, mType->currentIndex() == 0); +} + CSVWorld::CellCreator::CellCreator (CSMWorld::Data& data, QUndoStack& undoStack, const CSMWorld::UniversalId& id) : GenericCreator (data, undoStack, id) diff --git a/apps/opencs/view/world/cellcreator.hpp b/apps/opencs/view/world/cellcreator.hpp index db9fbf8a3..4d5314f23 100644 --- a/apps/opencs/view/world/cellcreator.hpp +++ b/apps/opencs/view/world/cellcreator.hpp @@ -23,6 +23,9 @@ namespace CSVWorld virtual std::string getId() const; + /// Allow subclasses to add additional data to \a command. + virtual void configureCreateCommand(CSMWorld::CreateCommand& command) const; + public: CellCreator (CSMWorld::Data& data, QUndoStack& undoStack, const CSMWorld::UniversalId& id); From cad4ce4e0f137b85922be69093061def2f5e7020 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sat, 27 Jun 2015 11:47:59 +0300 Subject: [PATCH 1667/3725] Cell type can be changed when cloning a cell --- apps/opencs/view/world/cellcreator.cpp | 7 ------- apps/opencs/view/world/cellcreator.hpp | 2 -- 2 files changed, 9 deletions(-) diff --git a/apps/opencs/view/world/cellcreator.cpp b/apps/opencs/view/world/cellcreator.cpp index 5dfb6af45..45fac2c5f 100644 --- a/apps/opencs/view/world/cellcreator.cpp +++ b/apps/opencs/view/world/cellcreator.cpp @@ -106,10 +106,3 @@ void CSVWorld::CellCreator::cloneMode(const std::string& originId, mType->setCurrentIndex(0); } } - - -void CSVWorld::CellCreator::toggleWidgets(bool active) -{ - CSVWorld::GenericCreator::toggleWidgets(active); - mType->setEnabled(active); -} diff --git a/apps/opencs/view/world/cellcreator.hpp b/apps/opencs/view/world/cellcreator.hpp index 4d5314f23..b633ca06e 100644 --- a/apps/opencs/view/world/cellcreator.hpp +++ b/apps/opencs/view/world/cellcreator.hpp @@ -32,8 +32,6 @@ namespace CSVWorld virtual void reset(); - virtual void toggleWidgets(bool active = true); - virtual void cloneMode(const std::string& originId, const CSMWorld::UniversalId::Type type); From cbb124ab4f05a15d186f481090debae3b4b54753 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sat, 27 Jun 2015 12:26:19 +0300 Subject: [PATCH 1668/3725] Close the creator when the original record is removed (in clone mode) --- apps/opencs/view/world/genericcreator.cpp | 11 +++++++++++ apps/opencs/view/world/genericcreator.hpp | 2 ++ 2 files changed, 13 insertions(+) diff --git a/apps/opencs/view/world/genericcreator.cpp b/apps/opencs/view/world/genericcreator.cpp index c64109608..5f04d9a7a 100644 --- a/apps/opencs/view/world/genericcreator.cpp +++ b/apps/opencs/view/world/genericcreator.cpp @@ -161,6 +161,8 @@ CSVWorld::GenericCreator::GenericCreator (CSMWorld::Data& data, QUndoStack& undo connect (mCreate, SIGNAL (clicked (bool)), this, SLOT (create())); connect (mId, SIGNAL (textChanged (const QString&)), this, SLOT (textChanged (const QString&))); + + connect (&mData, SIGNAL (idListChanged()), this, SLOT (dataIdListChanged())); } void CSVWorld::GenericCreator::setEditLock (bool locked) @@ -291,3 +293,12 @@ void CSVWorld::GenericCreator::scopeChanged (int index) update(); updateNamespace(); } + +void CSVWorld::GenericCreator::dataIdListChanged() +{ + // If the original ID of cloned record was removed, cancel the creator + if (mCloneMode && !mData.hasId(mClonedId)) + { + emit done(); + } +} diff --git a/apps/opencs/view/world/genericcreator.hpp b/apps/opencs/view/world/genericcreator.hpp index 0d2a40486..471d0622e 100644 --- a/apps/opencs/view/world/genericcreator.hpp +++ b/apps/opencs/view/world/genericcreator.hpp @@ -113,6 +113,8 @@ namespace CSVWorld void create(); void scopeChanged (int index); + + void dataIdListChanged(); }; } From 49dc30683f1e0d9366ab3afa65419e8f9d14c57d Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 27 Jun 2015 12:49:56 +0200 Subject: [PATCH 1669/3725] refactored dialogue subview button bar into a new class --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/view/world/dialoguesubview.cpp | 74 +++------------ apps/opencs/view/world/recordbuttonbar.cpp | 100 +++++++++++++++++++++ apps/opencs/view/world/recordbuttonbar.hpp | 54 +++++++++++ 4 files changed, 166 insertions(+), 64 deletions(-) create mode 100644 apps/opencs/view/world/recordbuttonbar.cpp create mode 100644 apps/opencs/view/world/recordbuttonbar.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 3399b9ddd..0607f67ee 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -64,7 +64,7 @@ opencs_units (view/world table tablesubview scriptsubview util regionmapsubview tablebottombox creator genericcreator cellcreator referenceablecreator referencecreator scenesubview infocreator scriptedit dialoguesubview previewsubview regionmap dragrecordtable nestedtable - dialoguespinbox + dialoguespinbox recordbuttonbar ) opencs_units_noqt (view/world diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 99650834e..a2f25df44 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -40,6 +40,7 @@ #include "util.hpp" #include "tablebottombox.hpp" #include "nestedtable.hpp" +#include "recordbuttonbar.hpp" /* ==============================NotEditableSubDelegate========================================== */ @@ -712,69 +713,16 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, connect(mBottom, SIGNAL(requestFocus(const std::string&)), this, SLOT(requestFocus(const std::string&))); // buttons - QHBoxLayout *buttonsLayout = new QHBoxLayout; - QToolButton* prevButton = new QToolButton (this); - prevButton->setIcon(QIcon(":/go-previous.png")); - prevButton->setToolTip ("Switch to previous record"); - QToolButton* nextButton = new QToolButton (this); - nextButton->setIcon(QIcon(":/go-next.png")); - nextButton->setToolTip ("Switch to next record"); - buttonsLayout->addWidget(prevButton, 0); - buttonsLayout->addWidget(nextButton, 1); - buttonsLayout->addStretch(2); - - QToolButton* cloneButton = new QToolButton (this); - cloneButton->setIcon(QIcon(":/edit-clone.png")); - cloneButton->setToolTip ("Clone record"); - QToolButton* addButton = new QToolButton (this); - addButton->setIcon(QIcon(":/add.png")); - addButton->setToolTip ("Add new record"); - QToolButton* deleteButton = new QToolButton (this); - deleteButton->setIcon(QIcon(":/edit-delete.png")); - deleteButton->setToolTip ("Delete record"); - QToolButton* revertButton = new QToolButton (this); - revertButton->setIcon(QIcon(":/edit-undo.png")); - revertButton->setToolTip ("Revert record"); - - if (getTable().getFeatures() & CSMWorld::IdTable::Feature_Preview) - { - QToolButton* previewButton = new QToolButton (this); - previewButton->setIcon(QIcon(":/edit-preview.png")); - previewButton->setToolTip ("Open a preview of this record"); - buttonsLayout->addWidget(previewButton); - connect(previewButton, SIGNAL(clicked()), this, SLOT(showPreview())); - } - - if (getTable().getFeatures() & CSMWorld::IdTable::Feature_View) - { - QToolButton* viewButton = new QToolButton (this); - viewButton->setIcon(QIcon(":/cell.png")); - viewButton->setToolTip ("Open a scene view of the cell this record is located in"); - buttonsLayout->addWidget(viewButton); - connect(viewButton, SIGNAL(clicked()), this, SLOT(viewRecord())); - } - - buttonsLayout->addWidget(cloneButton); - buttonsLayout->addWidget(addButton); - buttonsLayout->addWidget(deleteButton); - buttonsLayout->addWidget(revertButton); - - connect(nextButton, SIGNAL(clicked()), this, SLOT(nextId())); - connect(prevButton, SIGNAL(clicked()), this, SLOT(prevId())); - connect(cloneButton, SIGNAL(clicked()), this, SLOT(cloneRequest())); - connect(revertButton, SIGNAL(clicked()), &getCommandDispatcher(), SLOT(executeRevert())); - connect(deleteButton, SIGNAL(clicked()), &getCommandDispatcher(), SLOT(executeDelete())); - - connect(addButton, SIGNAL(clicked()), mBottom, SLOT(createRequest())); - - if(!mBottom->canCreateAndDelete()) - { - cloneButton->setDisabled (true); - addButton->setDisabled (true); - deleteButton->setDisabled (true); - } - - getMainLayout().addLayout (buttonsLayout); + RecordButtonBar *buttons = new RecordButtonBar (getTable(), mBottom, + &getCommandDispatcher(), this); + + getMainLayout().addWidget (buttons); + + connect (buttons, SIGNAL(nextId()), this, SLOT(nextId())); + connect (buttons, SIGNAL (prevId()), this, SLOT(prevId())); + connect (buttons, SIGNAL (cloneRequest()), this, SLOT(cloneRequest())); + connect (buttons, SIGNAL (showPreview()), this, SLOT(showPreview())); + connect (buttons, SIGNAL (viewRecord()), this, SLOT(viewRecord())); } void CSVWorld::DialogueSubView::cloneRequest() diff --git a/apps/opencs/view/world/recordbuttonbar.cpp b/apps/opencs/view/world/recordbuttonbar.cpp new file mode 100644 index 000000000..2f5395317 --- /dev/null +++ b/apps/opencs/view/world/recordbuttonbar.cpp @@ -0,0 +1,100 @@ + +#include "recordbuttonbar.hpp" + +#include +#include + +#include "../../model/world/idtable.hpp" +#include "../../model/world/commanddispatcher.hpp" + +#include "../world/tablebottombox.hpp" + +CSVWorld::RecordButtonBar::RecordButtonBar (CSMWorld::IdTable& table, TableBottomBox *bottomBox, + CSMWorld::CommandDispatcher *commandDispatcher, QWidget *parent) +: QWidget (parent), mTable (table), mBottom (bottomBox), mCommandDispatcher (commandDispatcher) +{ + QHBoxLayout *buttonsLayout = new QHBoxLayout; + buttonsLayout->setContentsMargins (0, 0, 0, 0); + + // left section + QToolButton* prevButton = new QToolButton (this); + prevButton->setIcon(QIcon(":/go-previous.png")); + prevButton->setToolTip ("Switch to previous record"); + buttonsLayout->addWidget (prevButton, 0); + + QToolButton* nextButton = new QToolButton (this); + nextButton->setIcon(QIcon(":/go-next.png")); + nextButton->setToolTip ("Switch to next record"); + buttonsLayout->addWidget (nextButton, 1); + + buttonsLayout->addStretch(2); + + // optional buttons of the right section + if (mTable.getFeatures() & CSMWorld::IdTable::Feature_Preview) + { + QToolButton* previewButton = new QToolButton (this); + previewButton->setIcon(QIcon(":/edit-preview.png")); + previewButton->setToolTip ("Open a preview of this record"); + buttonsLayout->addWidget(previewButton); + connect (previewButton, SIGNAL(clicked()), this, SIGNAL (showPreview())); + } + + if (mTable.getFeatures() & CSMWorld::IdTable::Feature_View) + { + QToolButton* viewButton = new QToolButton (this); + viewButton->setIcon(QIcon(":/cell.png")); + viewButton->setToolTip ("Open a scene view of the cell this record is located in"); + buttonsLayout->addWidget(viewButton); + connect (viewButton, SIGNAL(clicked()), this, SIGNAL (viewRecord())); + } + + // right section + QToolButton* cloneButton = new QToolButton (this); + cloneButton->setIcon(QIcon(":/edit-clone.png")); + cloneButton->setToolTip ("Clone record"); + buttonsLayout->addWidget(cloneButton); + + QToolButton* addButton = new QToolButton (this); + addButton->setIcon(QIcon(":/add.png")); + addButton->setToolTip ("Add new record"); + buttonsLayout->addWidget(addButton); + + QToolButton* deleteButton = new QToolButton (this); + deleteButton->setIcon(QIcon(":/edit-delete.png")); + deleteButton->setToolTip ("Delete record"); + buttonsLayout->addWidget(deleteButton); + + QToolButton* revertButton = new QToolButton (this); + revertButton->setIcon(QIcon(":/edit-undo.png")); + revertButton->setToolTip ("Revert record"); + buttonsLayout->addWidget(revertButton); + + setLayout (buttonsLayout); + + // disabling and connections + if(!mBottom || !mBottom->canCreateAndDelete()) + { + cloneButton->setDisabled (true); + addButton->setDisabled (true); + deleteButton->setDisabled (true); + } + else + { + connect (addButton, SIGNAL (clicked()), mBottom, SLOT (createRequest())); + connect (cloneButton, SIGNAL (clicked()), this, SIGNAL (cloneRequest())); + } + + connect (nextButton, SIGNAL (clicked()), this, SIGNAL (nextId())); + connect (prevButton, SIGNAL (clicked()), this, SIGNAL (prevId())); + + if (!mCommandDispatcher) + { + revertButton->setDisabled (true); + deleteButton->setDisabled (true); + } + else + { + connect (revertButton, SIGNAL (clicked()), mCommandDispatcher, SLOT (executeRevert())); + connect (deleteButton, SIGNAL (clicked()), mCommandDispatcher, SLOT (executeDelete())); + } +} diff --git a/apps/opencs/view/world/recordbuttonbar.hpp b/apps/opencs/view/world/recordbuttonbar.hpp new file mode 100644 index 000000000..28e59407f --- /dev/null +++ b/apps/opencs/view/world/recordbuttonbar.hpp @@ -0,0 +1,54 @@ +#ifndef CSV_WORLD_RECORDBUTTONBAR_H +#define CSV_WORLD_RECORDBUTTONBAR_H + +#include + +namespace CSMWorld +{ + class IdTable; + class CommandDispatcher; +} + +namespace CSVWorld +{ + class TableBottomBox; + + /// \brief Button bar for use in dialogue-type subviews + /// + /// Contains the following buttons: + /// - next/prev + /// - clone + /// - add + /// - delete + /// - revert + /// - preview (optional) + /// - view (optional) + class RecordButtonBar : public QWidget + { + Q_OBJECT + + CSMWorld::IdTable& mTable; + TableBottomBox *mBottom; + CSMWorld::CommandDispatcher *mCommandDispatcher; + + public: + + RecordButtonBar (CSMWorld::IdTable& table, TableBottomBox *bottomBox = 0, + CSMWorld::CommandDispatcher *commandDispatcher = 0, QWidget *parent = 0); + + signals: + + void showPreview(); + + void viewRecord(); + + void nextId(); + + void prevId(); + + void cloneRequest(); + + }; +} + +#endif From 7f1129df3b22334f6531d82f9dee95f26bb860e3 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 27 Jun 2015 12:53:46 +0200 Subject: [PATCH 1670/3725] cleaned up DialogueSubView constructor; moved bottom box below button bar --- apps/opencs/view/world/dialoguesubview.cpp | 26 +++++++++++++--------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index a2f25df44..5669d9680 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -706,23 +706,27 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, : SimpleDialogueSubView (id, document) { // bottom box - getMainLayout().addWidget (mBottom = new TableBottomBox (creatorFactory, document, id, this)); + mBottom = new TableBottomBox (creatorFactory, document, id, this); - mBottom->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed); + mBottom->setSizePolicy (QSizePolicy::Ignored, QSizePolicy::Fixed); - connect(mBottom, SIGNAL(requestFocus(const std::string&)), this, SLOT(requestFocus(const std::string&))); + connect (mBottom, SIGNAL (requestFocus (const std::string&)), + this, SLOT (requestFocus (const std::string&))); - // buttons + // button bar RecordButtonBar *buttons = new RecordButtonBar (getTable(), mBottom, &getCommandDispatcher(), this); - - getMainLayout().addWidget (buttons); - connect (buttons, SIGNAL(nextId()), this, SLOT(nextId())); - connect (buttons, SIGNAL (prevId()), this, SLOT(prevId())); - connect (buttons, SIGNAL (cloneRequest()), this, SLOT(cloneRequest())); - connect (buttons, SIGNAL (showPreview()), this, SLOT(showPreview())); - connect (buttons, SIGNAL (viewRecord()), this, SLOT(viewRecord())); + // layout + getMainLayout().addWidget (buttons); + getMainLayout().addWidget (mBottom); + + // connections + connect (buttons, SIGNAL (nextId()), this, SLOT (nextId())); + connect (buttons, SIGNAL (prevId()), this, SLOT (prevId())); + connect (buttons, SIGNAL (cloneRequest()), this, SLOT (cloneRequest())); + connect (buttons, SIGNAL (showPreview()), this, SLOT (showPreview())); + connect (buttons, SIGNAL (viewRecord()), this, SLOT (viewRecord())); } void CSVWorld::DialogueSubView::cloneRequest() From 67694793586200ec9b2ff48ceacccdeda65d89ee Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 27 Jun 2015 13:47:07 +0200 Subject: [PATCH 1671/3725] moved code for initiating record cloning from DialogueSubView to RecordButtonBar --- apps/opencs/view/doc/subview.cpp | 1 + apps/opencs/view/doc/subview.hpp | 2 ++ apps/opencs/view/world/dialoguesubview.cpp | 12 +++------ apps/opencs/view/world/dialoguesubview.hpp | 2 -- apps/opencs/view/world/recordbuttonbar.cpp | 30 +++++++++++++++++++--- apps/opencs/view/world/recordbuttonbar.hpp | 17 +++++++++--- 6 files changed, 46 insertions(+), 18 deletions(-) diff --git a/apps/opencs/view/doc/subview.cpp b/apps/opencs/view/doc/subview.cpp index f4f0c6afe..e0c2fbc46 100644 --- a/apps/opencs/view/doc/subview.cpp +++ b/apps/opencs/view/doc/subview.cpp @@ -45,6 +45,7 @@ void CSVDoc::SubView::setUniversalId (const CSMWorld::UniversalId& id) { mUniversalId = id; setWindowTitle (QString::fromUtf8(mUniversalId.toString().c_str())); + emit universalIdChanged (mUniversalId); } void CSVDoc::SubView::closeEvent (QCloseEvent *event) diff --git a/apps/opencs/view/doc/subview.hpp b/apps/opencs/view/doc/subview.hpp index b323f9ed9..189bb40eb 100644 --- a/apps/opencs/view/doc/subview.hpp +++ b/apps/opencs/view/doc/subview.hpp @@ -68,6 +68,8 @@ namespace CSVDoc void updateSubViewIndicies (SubView *view = 0); + void universalIdChanged (const CSMWorld::UniversalId& universalId); + protected slots: void closeRequest(); diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 5669d9680..92b9807e8 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -714,7 +714,7 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, this, SLOT (requestFocus (const std::string&))); // button bar - RecordButtonBar *buttons = new RecordButtonBar (getTable(), mBottom, + RecordButtonBar *buttons = new RecordButtonBar (id, getTable(), mBottom, &getCommandDispatcher(), this); // layout @@ -724,16 +724,10 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, // connections connect (buttons, SIGNAL (nextId()), this, SLOT (nextId())); connect (buttons, SIGNAL (prevId()), this, SLOT (prevId())); - connect (buttons, SIGNAL (cloneRequest()), this, SLOT (cloneRequest())); connect (buttons, SIGNAL (showPreview()), this, SLOT (showPreview())); connect (buttons, SIGNAL (viewRecord()), this, SLOT (viewRecord())); -} - -void CSVWorld::DialogueSubView::cloneRequest() -{ - mBottom->cloneRequest (getCurrentId(), - static_cast (getTable(). - data (getTable().getModelIndex(getCurrentId(), 2)).toInt())); + connect (this, SIGNAL (universalIdChanged (const CSMWorld::UniversalId&)), + buttons, SLOT (universalIdChanged (const CSMWorld::UniversalId&))); } void CSVWorld::DialogueSubView::prevId() diff --git a/apps/opencs/view/world/dialoguesubview.hpp b/apps/opencs/view/world/dialoguesubview.hpp index 5d6915d42..6c0fcc59b 100644 --- a/apps/opencs/view/world/dialoguesubview.hpp +++ b/apps/opencs/view/world/dialoguesubview.hpp @@ -231,8 +231,6 @@ namespace CSVWorld private slots: - void cloneRequest(); - void nextId(); void prevId(); diff --git a/apps/opencs/view/world/recordbuttonbar.cpp b/apps/opencs/view/world/recordbuttonbar.cpp index 2f5395317..1560a31a5 100644 --- a/apps/opencs/view/world/recordbuttonbar.cpp +++ b/apps/opencs/view/world/recordbuttonbar.cpp @@ -9,9 +9,11 @@ #include "../world/tablebottombox.hpp" -CSVWorld::RecordButtonBar::RecordButtonBar (CSMWorld::IdTable& table, TableBottomBox *bottomBox, +CSVWorld::RecordButtonBar::RecordButtonBar (const CSMWorld::UniversalId& id, + CSMWorld::IdTable& table, TableBottomBox *bottomBox, CSMWorld::CommandDispatcher *commandDispatcher, QWidget *parent) -: QWidget (parent), mTable (table), mBottom (bottomBox), mCommandDispatcher (commandDispatcher) +: QWidget (parent), mId (id), mTable (table), mBottom (bottomBox), + mCommandDispatcher (commandDispatcher) { QHBoxLayout *buttonsLayout = new QHBoxLayout; buttonsLayout->setContentsMargins (0, 0, 0, 0); @@ -81,7 +83,7 @@ CSVWorld::RecordButtonBar::RecordButtonBar (CSMWorld::IdTable& table, TableBotto else { connect (addButton, SIGNAL (clicked()), mBottom, SLOT (createRequest())); - connect (cloneButton, SIGNAL (clicked()), this, SIGNAL (cloneRequest())); + connect (cloneButton, SIGNAL (clicked()), this, SLOT (cloneRequest())); } connect (nextButton, SIGNAL (clicked()), this, SIGNAL (nextId())); @@ -98,3 +100,25 @@ CSVWorld::RecordButtonBar::RecordButtonBar (CSMWorld::IdTable& table, TableBotto connect (deleteButton, SIGNAL (clicked()), mCommandDispatcher, SLOT (executeDelete())); } } + +void CSVWorld::RecordButtonBar::universalIdChanged (const CSMWorld::UniversalId& id) +{ + mId = id; +} + +void CSVWorld::RecordButtonBar::cloneRequest() +{ + if (mBottom) + { + int typeColumn = mTable.searchColumnIndex (CSMWorld::Columns::ColumnId_RecordType); + + if (typeColumn!=-1) + { + QModelIndex typeIndex = mTable.getModelIndex (mId.getId(), typeColumn); + CSMWorld::UniversalId::Type type = static_cast ( + mTable.data (typeIndex).toInt()); + + mBottom->cloneRequest (mId.getId(), type); + } + } +} diff --git a/apps/opencs/view/world/recordbuttonbar.hpp b/apps/opencs/view/world/recordbuttonbar.hpp index 28e59407f..08f16a687 100644 --- a/apps/opencs/view/world/recordbuttonbar.hpp +++ b/apps/opencs/view/world/recordbuttonbar.hpp @@ -3,6 +3,8 @@ #include +#include "../../model/world/universalid.hpp" + namespace CSMWorld { class IdTable; @@ -27,15 +29,25 @@ namespace CSVWorld { Q_OBJECT + CSMWorld::UniversalId mId; CSMWorld::IdTable& mTable; TableBottomBox *mBottom; CSMWorld::CommandDispatcher *mCommandDispatcher; public: - RecordButtonBar (CSMWorld::IdTable& table, TableBottomBox *bottomBox = 0, + RecordButtonBar (const CSMWorld::UniversalId& id, + CSMWorld::IdTable& table, TableBottomBox *bottomBox = 0, CSMWorld::CommandDispatcher *commandDispatcher = 0, QWidget *parent = 0); + public slots: + + void universalIdChanged (const CSMWorld::UniversalId& id); + + private slots: + + void cloneRequest(); + signals: void showPreview(); @@ -45,9 +57,6 @@ namespace CSVWorld void nextId(); void prevId(); - - void cloneRequest(); - }; } From d5e6d8a58bf666518cb21e7508e8f28b335effd4 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 27 Jun 2015 14:25:48 +0200 Subject: [PATCH 1672/3725] disable dialogue subview buttons while document is locked --- apps/opencs/view/world/dialoguesubview.cpp | 20 ++++-- apps/opencs/view/world/dialoguesubview.hpp | 5 ++ apps/opencs/view/world/recordbuttonbar.cpp | 81 ++++++++++++---------- apps/opencs/view/world/recordbuttonbar.hpp | 13 ++++ 4 files changed, 77 insertions(+), 42 deletions(-) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 92b9807e8..ffb606497 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -714,20 +714,26 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, this, SLOT (requestFocus (const std::string&))); // button bar - RecordButtonBar *buttons = new RecordButtonBar (id, getTable(), mBottom, + mButtons = new RecordButtonBar (id, getTable(), mBottom, &getCommandDispatcher(), this); // layout - getMainLayout().addWidget (buttons); + getMainLayout().addWidget (mButtons); getMainLayout().addWidget (mBottom); // connections - connect (buttons, SIGNAL (nextId()), this, SLOT (nextId())); - connect (buttons, SIGNAL (prevId()), this, SLOT (prevId())); - connect (buttons, SIGNAL (showPreview()), this, SLOT (showPreview())); - connect (buttons, SIGNAL (viewRecord()), this, SLOT (viewRecord())); + connect (mButtons, SIGNAL (nextId()), this, SLOT (nextId())); + connect (mButtons, SIGNAL (prevId()), this, SLOT (prevId())); + connect (mButtons, SIGNAL (showPreview()), this, SLOT (showPreview())); + connect (mButtons, SIGNAL (viewRecord()), this, SLOT (viewRecord())); connect (this, SIGNAL (universalIdChanged (const CSMWorld::UniversalId&)), - buttons, SLOT (universalIdChanged (const CSMWorld::UniversalId&))); + mButtons, SLOT (universalIdChanged (const CSMWorld::UniversalId&))); +} + +void CSVWorld::DialogueSubView::setEditLock (bool locked) +{ + SimpleDialogueSubView::setEditLock (locked); + mButtons->setEditLock (locked); } void CSVWorld::DialogueSubView::prevId() diff --git a/apps/opencs/view/world/dialoguesubview.hpp b/apps/opencs/view/world/dialoguesubview.hpp index 6c0fcc59b..63b25d06e 100644 --- a/apps/opencs/view/world/dialoguesubview.hpp +++ b/apps/opencs/view/world/dialoguesubview.hpp @@ -218,17 +218,22 @@ namespace CSVWorld void rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end); }; + class RecordButtonBar; + class DialogueSubView : public SimpleDialogueSubView { Q_OBJECT TableBottomBox* mBottom; + RecordButtonBar *mButtons; public: DialogueSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document, const CreatorFactoryBase& creatorFactory, bool sorting = false); + virtual void setEditLock (bool locked); + private slots: void nextId(); diff --git a/apps/opencs/view/world/recordbuttonbar.cpp b/apps/opencs/view/world/recordbuttonbar.cpp index 1560a31a5..93a6a5823 100644 --- a/apps/opencs/view/world/recordbuttonbar.cpp +++ b/apps/opencs/view/world/recordbuttonbar.cpp @@ -9,11 +9,25 @@ #include "../world/tablebottombox.hpp" +void CSVWorld::RecordButtonBar::updateModificationButtons() +{ + bool createAndDeleteDisabled = !mBottom || !mBottom->canCreateAndDelete() || mLocked; + + mCloneButton->setDisabled (createAndDeleteDisabled); + mAddButton->setDisabled (createAndDeleteDisabled); + mDeleteButton->setDisabled (createAndDeleteDisabled); + + bool commandDisabled = !mCommandDispatcher || mLocked; + + mRevertButton->setDisabled (commandDisabled); + mDeleteButton->setDisabled (commandDisabled); +} + CSVWorld::RecordButtonBar::RecordButtonBar (const CSMWorld::UniversalId& id, CSMWorld::IdTable& table, TableBottomBox *bottomBox, CSMWorld::CommandDispatcher *commandDispatcher, QWidget *parent) : QWidget (parent), mId (id), mTable (table), mBottom (bottomBox), - mCommandDispatcher (commandDispatcher) + mCommandDispatcher (commandDispatcher), mLocked (false) { QHBoxLayout *buttonsLayout = new QHBoxLayout; buttonsLayout->setContentsMargins (0, 0, 0, 0); @@ -51,54 +65,51 @@ CSVWorld::RecordButtonBar::RecordButtonBar (const CSMWorld::UniversalId& id, } // right section - QToolButton* cloneButton = new QToolButton (this); - cloneButton->setIcon(QIcon(":/edit-clone.png")); - cloneButton->setToolTip ("Clone record"); - buttonsLayout->addWidget(cloneButton); + mCloneButton = new QToolButton (this); + mCloneButton->setIcon(QIcon(":/edit-clone.png")); + mCloneButton->setToolTip ("Clone record"); + buttonsLayout->addWidget(mCloneButton); - QToolButton* addButton = new QToolButton (this); - addButton->setIcon(QIcon(":/add.png")); - addButton->setToolTip ("Add new record"); - buttonsLayout->addWidget(addButton); + mAddButton = new QToolButton (this); + mAddButton->setIcon(QIcon(":/add.png")); + mAddButton->setToolTip ("Add new record"); + buttonsLayout->addWidget(mAddButton); - QToolButton* deleteButton = new QToolButton (this); - deleteButton->setIcon(QIcon(":/edit-delete.png")); - deleteButton->setToolTip ("Delete record"); - buttonsLayout->addWidget(deleteButton); + mDeleteButton = new QToolButton (this); + mDeleteButton->setIcon(QIcon(":/edit-delete.png")); + mDeleteButton->setToolTip ("Delete record"); + buttonsLayout->addWidget(mDeleteButton); - QToolButton* revertButton = new QToolButton (this); - revertButton->setIcon(QIcon(":/edit-undo.png")); - revertButton->setToolTip ("Revert record"); - buttonsLayout->addWidget(revertButton); + mRevertButton = new QToolButton (this); + mRevertButton->setIcon(QIcon(":/edit-undo.png")); + mRevertButton->setToolTip ("Revert record"); + buttonsLayout->addWidget(mRevertButton); setLayout (buttonsLayout); - // disabling and connections - if(!mBottom || !mBottom->canCreateAndDelete()) - { - cloneButton->setDisabled (true); - addButton->setDisabled (true); - deleteButton->setDisabled (true); - } - else + // connections + if(mBottom && mBottom->canCreateAndDelete()) { - connect (addButton, SIGNAL (clicked()), mBottom, SLOT (createRequest())); - connect (cloneButton, SIGNAL (clicked()), this, SLOT (cloneRequest())); + connect (mAddButton, SIGNAL (clicked()), mBottom, SLOT (createRequest())); + connect (mCloneButton, SIGNAL (clicked()), this, SLOT (cloneRequest())); } connect (nextButton, SIGNAL (clicked()), this, SIGNAL (nextId())); connect (prevButton, SIGNAL (clicked()), this, SIGNAL (prevId())); - if (!mCommandDispatcher) - { - revertButton->setDisabled (true); - deleteButton->setDisabled (true); - } - else + if (mCommandDispatcher) { - connect (revertButton, SIGNAL (clicked()), mCommandDispatcher, SLOT (executeRevert())); - connect (deleteButton, SIGNAL (clicked()), mCommandDispatcher, SLOT (executeDelete())); + connect (mRevertButton, SIGNAL (clicked()), mCommandDispatcher, SLOT (executeRevert())); + connect (mDeleteButton, SIGNAL (clicked()), mCommandDispatcher, SLOT (executeDelete())); } + + updateModificationButtons(); +} + +void CSVWorld::RecordButtonBar::setEditLock (bool locked) +{ + mLocked = locked; + updateModificationButtons(); } void CSVWorld::RecordButtonBar::universalIdChanged (const CSMWorld::UniversalId& id) diff --git a/apps/opencs/view/world/recordbuttonbar.hpp b/apps/opencs/view/world/recordbuttonbar.hpp index 08f16a687..95b567594 100644 --- a/apps/opencs/view/world/recordbuttonbar.hpp +++ b/apps/opencs/view/world/recordbuttonbar.hpp @@ -5,6 +5,8 @@ #include "../../model/world/universalid.hpp" +class QToolButton; + namespace CSMWorld { class IdTable; @@ -33,13 +35,24 @@ namespace CSVWorld CSMWorld::IdTable& mTable; TableBottomBox *mBottom; CSMWorld::CommandDispatcher *mCommandDispatcher; + QToolButton *mCloneButton; + QToolButton *mAddButton; + QToolButton *mDeleteButton; + QToolButton *mRevertButton; + bool mLocked; + + private: + void updateModificationButtons(); + public: RecordButtonBar (const CSMWorld::UniversalId& id, CSMWorld::IdTable& table, TableBottomBox *bottomBox = 0, CSMWorld::CommandDispatcher *commandDispatcher = 0, QWidget *parent = 0); + void setEditLock (bool locked); + public slots: void universalIdChanged (const CSMWorld::UniversalId& id); From a8c26ec0c11a5252de2e75fd26d9d83ef1afc13e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 27 Jun 2015 14:42:22 +0200 Subject: [PATCH 1673/3725] moved most of the code for next/prev buttons from DialogueSubView to RecordBUttonBar --- apps/opencs/view/world/dialoguesubview.cpp | 88 ++++------------------ apps/opencs/view/world/dialoguesubview.hpp | 6 +- apps/opencs/view/world/recordbuttonbar.cpp | 28 ++++++- apps/opencs/view/world/recordbuttonbar.hpp | 8 +- 4 files changed, 47 insertions(+), 83 deletions(-) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index ffb606497..cf9d69f02 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -722,10 +722,10 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, getMainLayout().addWidget (mBottom); // connections - connect (mButtons, SIGNAL (nextId()), this, SLOT (nextId())); - connect (mButtons, SIGNAL (prevId()), this, SLOT (prevId())); connect (mButtons, SIGNAL (showPreview()), this, SLOT (showPreview())); connect (mButtons, SIGNAL (viewRecord()), this, SLOT (viewRecord())); + connect (mButtons, SIGNAL (switchToRow (int)), this, SLOT (switchToRow (int))); + connect (this, SIGNAL (universalIdChanged (const CSMWorld::UniversalId&)), mButtons, SLOT (universalIdChanged (const CSMWorld::UniversalId&))); } @@ -736,78 +736,6 @@ void CSVWorld::DialogueSubView::setEditLock (bool locked) mButtons->setEditLock (locked); } -void CSVWorld::DialogueSubView::prevId() -{ - int newRow = getTable().getModelIndex (getCurrentId(), 0).row() - 1; - - if (newRow < 0) - { - return; - } - while (newRow >= 0) - { - QModelIndex newIndex (getTable().index(newRow, 0)); - - if (!newIndex.isValid()) - { - return; - } - - CSMWorld::RecordBase::State state = static_cast (getTable().data (getTable().index (newRow, 1)).toInt()); - if (!(state == CSMWorld::RecordBase::State_Deleted || state == CSMWorld::RecordBase::State_Erased)) - { - getEditWidget().remake (newRow); - - setUniversalId(CSMWorld::UniversalId (static_cast (getTable().data (getTable().index (newRow, 2)).toInt()), - getTable().data (getTable().index (newRow, 0)).toString().toUtf8().constData())); - - changeCurrentId(std::string (getTable().data (getTable().index (newRow, 0)).toString().toUtf8().constData())); - - getEditWidget().setDisabled (isLocked()); - - return; - } - --newRow; - } -} - -void CSVWorld::DialogueSubView::nextId () -{ - int newRow = getTable().getModelIndex (getCurrentId(), 0).row() + 1; - - if (newRow >= getTable().rowCount()) - { - return; - } - - while (newRow < getTable().rowCount()) - { - QModelIndex newIndex (getTable().index(newRow, 0)); - - if (!newIndex.isValid()) - { - return; - } - - CSMWorld::RecordBase::State state = static_cast (getTable().data (getTable().index (newRow, 1)).toInt()); - if (!(state == CSMWorld::RecordBase::State_Deleted)) - { - getEditWidget().remake(newRow); - - setUniversalId(CSMWorld::UniversalId (static_cast (getTable().data (getTable().index (newRow, 2)).toInt()), - getTable().data (getTable().index (newRow, 0)).toString().toUtf8().constData())); - - changeCurrentId(std::string (getTable().data (getTable().index (newRow, 0)).toString().toUtf8().constData())); - - getEditWidget().setDisabled (isLocked()); - - return; - } - ++newRow; - } -} - - void CSVWorld::DialogueSubView::showPreview () { QModelIndex currentIndex (getTable().getModelIndex (getCurrentId(), 0)); @@ -833,3 +761,15 @@ void CSVWorld::DialogueSubView::viewRecord () emit focusId (params.first, params.second); } } + +void CSVWorld::DialogueSubView::switchToRow (int row) +{ + getEditWidget().remake (row); + + setUniversalId (CSMWorld::UniversalId (static_cast (getTable().data (getTable().index (row, 2)).toInt()), + getTable().data (getTable().index (row, 0)).toString().toUtf8().constData())); + + changeCurrentId(std::string (getTable().data (getTable().index (row, 0)).toString().toUtf8().constData())); + + getEditWidget().setDisabled (isLocked()); +} diff --git a/apps/opencs/view/world/dialoguesubview.hpp b/apps/opencs/view/world/dialoguesubview.hpp index 63b25d06e..ff70a37d3 100644 --- a/apps/opencs/view/world/dialoguesubview.hpp +++ b/apps/opencs/view/world/dialoguesubview.hpp @@ -236,13 +236,11 @@ namespace CSVWorld private slots: - void nextId(); - - void prevId(); - void showPreview(); void viewRecord(); + + void switchToRow (int row); }; } diff --git a/apps/opencs/view/world/recordbuttonbar.cpp b/apps/opencs/view/world/recordbuttonbar.cpp index 93a6a5823..375ab68c3 100644 --- a/apps/opencs/view/world/recordbuttonbar.cpp +++ b/apps/opencs/view/world/recordbuttonbar.cpp @@ -94,8 +94,8 @@ CSVWorld::RecordButtonBar::RecordButtonBar (const CSMWorld::UniversalId& id, connect (mCloneButton, SIGNAL (clicked()), this, SLOT (cloneRequest())); } - connect (nextButton, SIGNAL (clicked()), this, SIGNAL (nextId())); - connect (prevButton, SIGNAL (clicked()), this, SIGNAL (prevId())); + connect (nextButton, SIGNAL (clicked()), this, SLOT (nextId())); + connect (prevButton, SIGNAL (clicked()), this, SLOT (prevId())); if (mCommandDispatcher) { @@ -133,3 +133,27 @@ void CSVWorld::RecordButtonBar::cloneRequest() } } } + +void CSVWorld::RecordButtonBar::nextId() +{ + int newRow = mTable.getModelIndex (mId.getId(), 0).row() + 1; + + if (newRow >= mTable.rowCount()) + { + return; + } + + emit switchToRow (newRow); +} + +void CSVWorld::RecordButtonBar::prevId() +{ + int newRow = mTable.getModelIndex (mId.getId(), 0).row() - 1; + + if (newRow < 0) + { + return; + } + + emit switchToRow (newRow); +} diff --git a/apps/opencs/view/world/recordbuttonbar.hpp b/apps/opencs/view/world/recordbuttonbar.hpp index 95b567594..6a5fadca5 100644 --- a/apps/opencs/view/world/recordbuttonbar.hpp +++ b/apps/opencs/view/world/recordbuttonbar.hpp @@ -60,6 +60,10 @@ namespace CSVWorld private slots: void cloneRequest(); + + void nextId(); + + void prevId(); signals: @@ -67,9 +71,7 @@ namespace CSVWorld void viewRecord(); - void nextId(); - - void prevId(); + void switchToRow (int row); }; } From 9aa153984aa0e5b8cfe347eadada6b1be262b0c4 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 27 Jun 2015 15:02:50 +0200 Subject: [PATCH 1674/3725] fixed inconsistent handling of deleted records in dialogue; general cleanup --- apps/opencs/view/world/dialoguesubview.cpp | 19 ++++++++++++++----- apps/opencs/view/world/recordbuttonbar.cpp | 17 +++++++---------- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index cf9d69f02..4ef06766c 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -764,12 +764,21 @@ void CSVWorld::DialogueSubView::viewRecord () void CSVWorld::DialogueSubView::switchToRow (int row) { - getEditWidget().remake (row); + int idColumn = getTable().findColumnIndex (CSMWorld::Columns::ColumnId_Id); + std::string id = getTable().data (getTable().index (row, idColumn)).toString().toUtf8().constData(); + + int typeColumn = getTable().findColumnIndex (CSMWorld::Columns::ColumnId_RecordType); + CSMWorld::UniversalId::Type type = static_cast ( + getTable().data (getTable().index (row, typeColumn)).toInt()); - setUniversalId (CSMWorld::UniversalId (static_cast (getTable().data (getTable().index (row, 2)).toInt()), - getTable().data (getTable().index (row, 0)).toString().toUtf8().constData())); + setUniversalId (CSMWorld::UniversalId (type, id)); + changeCurrentId (id); + + getEditWidget().remake (row); - changeCurrentId(std::string (getTable().data (getTable().index (row, 0)).toString().toUtf8().constData())); + int stateColumn = getTable().findColumnIndex (CSMWorld::Columns::ColumnId_Modification); + CSMWorld::RecordBase::State state = static_cast ( + getTable().data (getTable().index (row, stateColumn)).toInt()); - getEditWidget().setDisabled (isLocked()); + getEditWidget().setDisabled (isLocked() || state==CSMWorld::RecordBase::State_Deleted); } diff --git a/apps/opencs/view/world/recordbuttonbar.cpp b/apps/opencs/view/world/recordbuttonbar.cpp index 375ab68c3..db2320341 100644 --- a/apps/opencs/view/world/recordbuttonbar.cpp +++ b/apps/opencs/view/world/recordbuttonbar.cpp @@ -121,16 +121,13 @@ void CSVWorld::RecordButtonBar::cloneRequest() { if (mBottom) { - int typeColumn = mTable.searchColumnIndex (CSMWorld::Columns::ColumnId_RecordType); - - if (typeColumn!=-1) - { - QModelIndex typeIndex = mTable.getModelIndex (mId.getId(), typeColumn); - CSMWorld::UniversalId::Type type = static_cast ( - mTable.data (typeIndex).toInt()); - - mBottom->cloneRequest (mId.getId(), type); - } + int typeColumn = mTable.findColumnIndex (CSMWorld::Columns::ColumnId_RecordType); + + QModelIndex typeIndex = mTable.getModelIndex (mId.getId(), typeColumn); + CSMWorld::UniversalId::Type type = static_cast ( + mTable.data (typeIndex).toInt()); + + mBottom->cloneRequest (mId.getId(), type); } } From 95522fcad29cd72a58c16fa064b5bd9553689642 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 27 Jun 2015 15:29:54 +0200 Subject: [PATCH 1675/3725] more general cleanup --- apps/opencs/view/world/dialoguesubview.cpp | 51 +++++++++------------- apps/opencs/view/world/dialoguesubview.hpp | 24 +++++----- 2 files changed, 31 insertions(+), 44 deletions(-) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 4ef06766c..69255f821 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -17,8 +17,6 @@ #include #include #include -#include -#include #include #include @@ -573,11 +571,6 @@ CSMWorld::CommandDispatcher& CSVWorld::SimpleDialogueSubView::getCommandDispatch return mCommandDispatcher; } -std::string CSVWorld::SimpleDialogueSubView::getCurrentId() const -{ - return mCurrentId; -} - CSVWorld::EditWidget& CSVWorld::SimpleDialogueSubView::getEditWidget() { return *mEditWidget; @@ -593,7 +586,6 @@ CSVWorld::SimpleDialogueSubView::SimpleDialogueSubView (const CSMWorld::Universa mEditWidget(0), mMainLayout(NULL), mTable(dynamic_cast(document.getData().getTableModel(id))), - mUndoStack(document.getUndoStack()), mLocked(false), mDocument(document), mCommandDispatcher (document, CSMWorld::UniversalId::getParentType (id.getType())) @@ -601,7 +593,7 @@ CSVWorld::SimpleDialogueSubView::SimpleDialogueSubView (const CSMWorld::Universa connect(mTable, SIGNAL(dataChanged (const QModelIndex&, const QModelIndex&)), this, SLOT(dataChanged(const QModelIndex&))); connect(mTable, SIGNAL(rowsAboutToBeRemoved(const QModelIndex&, int, int)), this, SLOT(rowsAboutToBeRemoved(const QModelIndex&, int, int))); - changeCurrentId(id.getId()); + updateCurrentId(); QWidget *mainWidget = new QWidget(this); @@ -609,21 +601,21 @@ CSVWorld::SimpleDialogueSubView::SimpleDialogueSubView (const CSMWorld::Universa setWidget (mainWidget); mEditWidget = new EditWidget(mainWidget, - mTable->getModelIndex(mCurrentId, 0).row(), mTable, mCommandDispatcher, document, false); + mTable->getModelIndex(getUniversalId().getId(), 0).row(), mTable, mCommandDispatcher, document, false); mMainLayout->addWidget(mEditWidget); mEditWidget->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); - dataChanged(mTable->getModelIndex (mCurrentId, 0)); + dataChanged(mTable->getModelIndex (getUniversalId().getId(), 0)); } void CSVWorld::SimpleDialogueSubView::setEditLock (bool locked) { - if (!mEditWidget) // hack to indicate that mCurrentId is no longer valid + if (!mEditWidget) // hack to indicate that getUniversalId().getId() is no longer valid return; mLocked = locked; - QModelIndex currentIndex(mTable->getModelIndex(mCurrentId, 0)); + QModelIndex currentIndex(mTable->getModelIndex(getUniversalId().getId(), 0)); if (currentIndex.isValid()) { @@ -638,7 +630,7 @@ void CSVWorld::SimpleDialogueSubView::setEditLock (bool locked) void CSVWorld::SimpleDialogueSubView::dataChanged (const QModelIndex & index) { - QModelIndex currentIndex(mTable->getModelIndex(mCurrentId, 0)); + QModelIndex currentIndex(mTable->getModelIndex(getUniversalId().getId(), 0)); if (currentIndex.isValid() && (index.parent().isValid() ? index.parent().row() : index.row()) == currentIndex.row()) @@ -671,7 +663,7 @@ void CSVWorld::SimpleDialogueSubView::dataChanged (const QModelIndex & index) void CSVWorld::SimpleDialogueSubView::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) { - QModelIndex currentIndex(mTable->getModelIndex(mCurrentId, 0)); + QModelIndex currentIndex(mTable->getModelIndex(getUniversalId().getId(), 0)); if (currentIndex.isValid() && currentIndex.row() >= start && currentIndex.row() <= end) { @@ -684,19 +676,10 @@ void CSVWorld::SimpleDialogueSubView::rowsAboutToBeRemoved(const QModelIndex &pa } } -void CSVWorld::SimpleDialogueSubView::requestFocus (const std::string& id) -{ - changeCurrentId(id); - - mEditWidget->remake(mTable->getModelIndex (id, 0).row()); -} - -void CSVWorld::SimpleDialogueSubView::changeCurrentId (const std::string& newId) +void CSVWorld::SimpleDialogueSubView::updateCurrentId() { std::vector selection; - mCurrentId = std::string(newId); - - selection.push_back(mCurrentId); + selection.push_back (getUniversalId().getId()); mCommandDispatcher.setSelection(selection); } @@ -738,19 +721,19 @@ void CSVWorld::DialogueSubView::setEditLock (bool locked) void CSVWorld::DialogueSubView::showPreview () { - QModelIndex currentIndex (getTable().getModelIndex (getCurrentId(), 0)); + QModelIndex currentIndex (getTable().getModelIndex (getUniversalId().getId(), 0)); if (currentIndex.isValid() && getTable().getFeatures() & CSMWorld::IdTable::Feature_Preview && currentIndex.row() < getTable().rowCount()) { - emit focusId(CSMWorld::UniversalId(CSMWorld::UniversalId::Type_Preview, getCurrentId()), ""); + emit focusId(CSMWorld::UniversalId(CSMWorld::UniversalId::Type_Preview, getUniversalId().getId()), ""); } } void CSVWorld::DialogueSubView::viewRecord () { - QModelIndex currentIndex (getTable().getModelIndex (getCurrentId(), 0)); + QModelIndex currentIndex (getTable().getModelIndex (getUniversalId().getId(), 0)); if (currentIndex.isValid() && currentIndex.row() < getTable().rowCount()) @@ -772,7 +755,7 @@ void CSVWorld::DialogueSubView::switchToRow (int row) getTable().data (getTable().index (row, typeColumn)).toInt()); setUniversalId (CSMWorld::UniversalId (type, id)); - changeCurrentId (id); + updateCurrentId(); getEditWidget().remake (row); @@ -782,3 +765,11 @@ void CSVWorld::DialogueSubView::switchToRow (int row) getEditWidget().setDisabled (isLocked() || state==CSMWorld::RecordBase::State_Deleted); } + +void CSVWorld::DialogueSubView::requestFocus (const std::string& id) +{ + QModelIndex index = getTable().getModelIndex (id, 0); + + if (index.isValid()) + switchToRow (index.row()); +} diff --git a/apps/opencs/view/world/dialoguesubview.hpp b/apps/opencs/view/world/dialoguesubview.hpp index ff70a37d3..aec98d69c 100644 --- a/apps/opencs/view/world/dialoguesubview.hpp +++ b/apps/opencs/view/world/dialoguesubview.hpp @@ -175,16 +175,14 @@ namespace CSVWorld class SimpleDialogueSubView : public CSVDoc::SubView { - Q_OBJECT + Q_OBJECT - EditWidget* mEditWidget; - QVBoxLayout* mMainLayout; - CSMWorld::IdTable* mTable; - QUndoStack& mUndoStack; - std::string mCurrentId; - bool mLocked; - const CSMDoc::Document& mDocument; - CSMWorld::CommandDispatcher mCommandDispatcher; + EditWidget* mEditWidget; + QVBoxLayout* mMainLayout; + CSMWorld::IdTable* mTable; + bool mLocked; + const CSMDoc::Document& mDocument; + CSMWorld::CommandDispatcher mCommandDispatcher; protected: @@ -194,11 +192,9 @@ namespace CSVWorld CSMWorld::CommandDispatcher& getCommandDispatcher(); - std::string getCurrentId() const; - EditWidget& getEditWidget(); - void changeCurrentId(const std::string& newCurrent); + void updateCurrentId(); bool isLocked() const; @@ -213,8 +209,6 @@ namespace CSVWorld void dataChanged(const QModelIndex & index); ///\brief we need to care for deleting currently edited record - void requestFocus (const std::string& id); - void rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end); }; @@ -241,6 +235,8 @@ namespace CSVWorld void viewRecord(); void switchToRow (int row); + + void requestFocus (const std::string& id); }; } From e27a75bd103430a3b88190b4e63612706116ba24 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 27 Jun 2015 15:56:41 +0200 Subject: [PATCH 1676/3725] added user setting for cyclic prev/next --- apps/opencs/model/settings/usersettings.cpp | 8 ++++++++ apps/opencs/view/world/recordbuttonbar.cpp | 16 +++++++++++++--- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/settings/usersettings.cpp b/apps/opencs/model/settings/usersettings.cpp index 3e59d0582..bcf7c3ba9 100644 --- a/apps/opencs/model/settings/usersettings.cpp +++ b/apps/opencs/model/settings/usersettings.cpp @@ -356,6 +356,14 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() formatId->setToolTip ("(Default: Blue) Use one of the following formats:" + tooltip); } + declareSection ("general-input", "General Input"); + { + Setting *cycle = createSetting (Type_CheckBox, "cycle", "Cyclic next/previous"); + cycle->setDefaultValue ("false"); + cycle->setToolTip ("When using next/previous functions at the last/first item of a " + "list go to the first/last item"); + } + { /****************************************************************** * There are three types of values: diff --git a/apps/opencs/view/world/recordbuttonbar.cpp b/apps/opencs/view/world/recordbuttonbar.cpp index db2320341..5dcc1d5cd 100644 --- a/apps/opencs/view/world/recordbuttonbar.cpp +++ b/apps/opencs/view/world/recordbuttonbar.cpp @@ -7,6 +7,8 @@ #include "../../model/world/idtable.hpp" #include "../../model/world/commanddispatcher.hpp" +#include "../../model/settings/usersettings.hpp" + #include "../world/tablebottombox.hpp" void CSVWorld::RecordButtonBar::updateModificationButtons() @@ -132,12 +134,16 @@ void CSVWorld::RecordButtonBar::cloneRequest() } void CSVWorld::RecordButtonBar::nextId() -{ +{ int newRow = mTable.getModelIndex (mId.getId(), 0).row() + 1; if (newRow >= mTable.rowCount()) { - return; + if (CSMSettings::UserSettings::instance().settingValue ("general-input/cycle") + =="true") + newRow = 0; + else + return; } emit switchToRow (newRow); @@ -149,7 +155,11 @@ void CSVWorld::RecordButtonBar::prevId() if (newRow < 0) { - return; + if (CSMSettings::UserSettings::instance().settingValue ("general-input/cycle") + =="true") + newRow = mTable.rowCount()-1; + else + return; } emit switchToRow (newRow); From 15bb2855a99d548b3f13aa799dc188dd0dab2b56 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 27 Jun 2015 16:57:45 +0200 Subject: [PATCH 1677/3725] disable prev/next buttons if there is no previous/next record --- apps/opencs/view/world/dialoguesubview.cpp | 6 +++ apps/opencs/view/world/dialoguesubview.hpp | 2 + apps/opencs/view/world/recordbuttonbar.cpp | 61 ++++++++++++++++++---- apps/opencs/view/world/recordbuttonbar.hpp | 11 +++- 4 files changed, 69 insertions(+), 11 deletions(-) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 69255f821..1d3eb5313 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -719,6 +719,12 @@ void CSVWorld::DialogueSubView::setEditLock (bool locked) mButtons->setEditLock (locked); } +void CSVWorld::DialogueSubView::updateUserSetting (const QString& name, const QStringList& value) +{ + SimpleDialogueSubView::updateUserSetting (name, value); + mButtons->updateUserSetting (name, value); +} + void CSVWorld::DialogueSubView::showPreview () { QModelIndex currentIndex (getTable().getModelIndex (getUniversalId().getId(), 0)); diff --git a/apps/opencs/view/world/dialoguesubview.hpp b/apps/opencs/view/world/dialoguesubview.hpp index aec98d69c..be58be5ad 100644 --- a/apps/opencs/view/world/dialoguesubview.hpp +++ b/apps/opencs/view/world/dialoguesubview.hpp @@ -228,6 +228,8 @@ namespace CSVWorld virtual void setEditLock (bool locked); + virtual void updateUserSetting (const QString& name, const QStringList& value); + private slots: void showPreview(); diff --git a/apps/opencs/view/world/recordbuttonbar.cpp b/apps/opencs/view/world/recordbuttonbar.cpp index 5dcc1d5cd..63c0dd0a1 100644 --- a/apps/opencs/view/world/recordbuttonbar.cpp +++ b/apps/opencs/view/world/recordbuttonbar.cpp @@ -25,6 +25,29 @@ void CSVWorld::RecordButtonBar::updateModificationButtons() mDeleteButton->setDisabled (commandDisabled); } +void CSVWorld::RecordButtonBar::updatePrevNextButtons() +{ + int rows = mTable.rowCount(); + + if (rows<=1) + { + mPrevButton->setDisabled (true); + mNextButton->setDisabled (true); + } + else if (CSMSettings::UserSettings::instance().settingValue ("general-input/cycle")=="true") + { + mPrevButton->setDisabled (false); + mNextButton->setDisabled (false); + } + else + { + int row = mTable.getModelIndex (mId.getId(), 0).row(); + + mPrevButton->setDisabled (row<=0); + mNextButton->setDisabled (row>=rows-1); + } +} + CSVWorld::RecordButtonBar::RecordButtonBar (const CSMWorld::UniversalId& id, CSMWorld::IdTable& table, TableBottomBox *bottomBox, CSMWorld::CommandDispatcher *commandDispatcher, QWidget *parent) @@ -35,15 +58,15 @@ CSVWorld::RecordButtonBar::RecordButtonBar (const CSMWorld::UniversalId& id, buttonsLayout->setContentsMargins (0, 0, 0, 0); // left section - QToolButton* prevButton = new QToolButton (this); - prevButton->setIcon(QIcon(":/go-previous.png")); - prevButton->setToolTip ("Switch to previous record"); - buttonsLayout->addWidget (prevButton, 0); + mPrevButton = new QToolButton (this); + mPrevButton->setIcon(QIcon(":/go-previous.png")); + mPrevButton->setToolTip ("Switch to previous record"); + buttonsLayout->addWidget (mPrevButton, 0); - QToolButton* nextButton = new QToolButton (this); - nextButton->setIcon(QIcon(":/go-next.png")); - nextButton->setToolTip ("Switch to next record"); - buttonsLayout->addWidget (nextButton, 1); + mNextButton = new QToolButton (this); + mNextButton->setIcon(QIcon(":/go-next.png")); + mNextButton->setToolTip ("Switch to next record"); + buttonsLayout->addWidget (mNextButton, 1); buttonsLayout->addStretch(2); @@ -96,8 +119,8 @@ CSVWorld::RecordButtonBar::RecordButtonBar (const CSMWorld::UniversalId& id, connect (mCloneButton, SIGNAL (clicked()), this, SLOT (cloneRequest())); } - connect (nextButton, SIGNAL (clicked()), this, SLOT (nextId())); - connect (prevButton, SIGNAL (clicked()), this, SLOT (prevId())); + connect (mNextButton, SIGNAL (clicked()), this, SLOT (nextId())); + connect (mPrevButton, SIGNAL (clicked()), this, SLOT (prevId())); if (mCommandDispatcher) { @@ -105,7 +128,13 @@ CSVWorld::RecordButtonBar::RecordButtonBar (const CSMWorld::UniversalId& id, connect (mDeleteButton, SIGNAL (clicked()), mCommandDispatcher, SLOT (executeDelete())); } + connect (&mTable, SIGNAL (rowsInserted (const QModelIndex&, int, int)), + this, SLOT (rowNumberChanged (const QModelIndex&, int, int))); + connect (&mTable, SIGNAL (rowsRemoved (const QModelIndex&, int, int)), + this, SLOT (rowNumberChanged (const QModelIndex&, int, int))); + updateModificationButtons(); + updatePrevNextButtons(); } void CSVWorld::RecordButtonBar::setEditLock (bool locked) @@ -114,9 +143,16 @@ void CSVWorld::RecordButtonBar::setEditLock (bool locked) updateModificationButtons(); } +void CSVWorld::RecordButtonBar::updateUserSetting (const QString& name, const QStringList& value) +{ + if (name=="general-input/cycle") + updatePrevNextButtons(); +} + void CSVWorld::RecordButtonBar::universalIdChanged (const CSMWorld::UniversalId& id) { mId = id; + updatePrevNextButtons(); } void CSVWorld::RecordButtonBar::cloneRequest() @@ -164,3 +200,8 @@ void CSVWorld::RecordButtonBar::prevId() emit switchToRow (newRow); } + +void CSVWorld::RecordButtonBar::rowNumberChanged (const QModelIndex& parent, int start, int end) +{ + updatePrevNextButtons(); +} diff --git a/apps/opencs/view/world/recordbuttonbar.hpp b/apps/opencs/view/world/recordbuttonbar.hpp index 6a5fadca5..93ca45518 100644 --- a/apps/opencs/view/world/recordbuttonbar.hpp +++ b/apps/opencs/view/world/recordbuttonbar.hpp @@ -6,6 +6,7 @@ #include "../../model/world/universalid.hpp" class QToolButton; +class QModelIndex; namespace CSMWorld { @@ -35,6 +36,8 @@ namespace CSVWorld CSMWorld::IdTable& mTable; TableBottomBox *mBottom; CSMWorld::CommandDispatcher *mCommandDispatcher; + QToolButton *mPrevButton; + QToolButton *mNextButton; QToolButton *mCloneButton; QToolButton *mAddButton; QToolButton *mDeleteButton; @@ -44,6 +47,8 @@ namespace CSVWorld private: void updateModificationButtons(); + + void updatePrevNextButtons(); public: @@ -52,7 +57,9 @@ namespace CSVWorld CSMWorld::CommandDispatcher *commandDispatcher = 0, QWidget *parent = 0); void setEditLock (bool locked); - + + void updateUserSetting (const QString& name, const QStringList& value); + public slots: void universalIdChanged (const CSMWorld::UniversalId& id); @@ -64,6 +71,8 @@ namespace CSVWorld void nextId(); void prevId(); + + void rowNumberChanged (const QModelIndex& parent, int start, int end); signals: From 81c7ce5b06783e26b174ab2003d37cd503422f2c Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sat, 27 Jun 2015 21:59:16 +0300 Subject: [PATCH 1678/3725] Add the proper getErrors() method to CellCreator. Fix the impossibility of the Exterior Cell creation. --- apps/opencs/view/world/cellcreator.cpp | 14 ++++++++++++++ apps/opencs/view/world/cellcreator.hpp | 4 ++++ 2 files changed, 18 insertions(+) diff --git a/apps/opencs/view/world/cellcreator.cpp b/apps/opencs/view/world/cellcreator.cpp index 45fac2c5f..c7d909f4c 100644 --- a/apps/opencs/view/world/cellcreator.cpp +++ b/apps/opencs/view/world/cellcreator.cpp @@ -106,3 +106,17 @@ void CSVWorld::CellCreator::cloneMode(const std::string& originId, mType->setCurrentIndex(0); } } + +std::string CSVWorld::CellCreator::getErrors() const +{ + std::string errors; + if (mType->currentIndex() == 0) + { + errors = GenericCreator::getErrors(); + } + else if (getData().hasId(getId())) + { + errors = "The Exterior Cell is already exist"; + } + return errors; +} diff --git a/apps/opencs/view/world/cellcreator.hpp b/apps/opencs/view/world/cellcreator.hpp index b633ca06e..6c682c6cd 100644 --- a/apps/opencs/view/world/cellcreator.hpp +++ b/apps/opencs/view/world/cellcreator.hpp @@ -35,6 +35,10 @@ namespace CSVWorld virtual void cloneMode(const std::string& originId, const CSMWorld::UniversalId::Type type); + virtual std::string getErrors() const; + ///< Return formatted error descriptions for the current state of the creator. if an empty + /// string is returned, there is no error. + private slots: void setType (int index); From e4d52ff9b0056a7824c797af144e7364bd6aac98 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sun, 28 Jun 2015 00:31:41 +0300 Subject: [PATCH 1679/3725] Deleted records can be cloned --- apps/opencs/view/world/table.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index d757d5bbe..ba691131b 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -447,7 +447,7 @@ void CSVWorld::Table::cloneRecord() { QModelIndexList selectedRows = selectionModel()->selectedRows(); const CSMWorld::UniversalId& toClone = getUniversalId(selectedRows.begin()->row()); - if (selectedRows.size()==1 && !mModel->isDeleted (toClone.getId())) + if (selectedRows.size() == 1) { emit cloneRequest (toClone); } From cd2e6d44367e84d94373bfec68fcb24992d5ea50 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 28 Jun 2015 05:53:03 +0200 Subject: [PATCH 1680/3725] Move the __STDC_CONSTANT_MACROS define to cmakelists --- CMakeLists.txt | 2 ++ apps/openmw/mwsound/ffmpeg_decoder.hpp | 6 ------ apps/openmw/mwsound/libavwrapper.cpp | 3 --- extern/osg-ffmpeg-videoplayer/audiodecoder.hpp | 3 --- extern/osg-ffmpeg-videoplayer/libavwrapper.cpp | 3 --- extern/osg-ffmpeg-videoplayer/videoplayer.hpp | 6 ------ extern/osg-ffmpeg-videoplayer/videostate.hpp | 3 --- 7 files changed, 2 insertions(+), 24 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7bcdf35e2..a133a8d6a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -120,6 +120,8 @@ else() message(FATAL_ERROR "Install either libswresample (FFmpeg) or libavresample (Libav).") endif() endif() +# Required for building the FFmpeg headers +add_definitions(-D__STDC_CONSTANT_MACROS) set(SOUND_INPUT_LIBRARY ${FFMPEG_LIBRARIES}) diff --git a/apps/openmw/mwsound/ffmpeg_decoder.hpp b/apps/openmw/mwsound/ffmpeg_decoder.hpp index 3abf7c474..da8e58964 100644 --- a/apps/openmw/mwsound/ffmpeg_decoder.hpp +++ b/apps/openmw/mwsound/ffmpeg_decoder.hpp @@ -1,12 +1,6 @@ #ifndef GAME_SOUND_FFMPEG_DECODER_H #define GAME_SOUND_FFMPEG_DECODER_H -// FIXME: This can't be right? The headers refuse to build without UINT64_C, -// which only gets defined in stdint.h in either C99 mode or with this macro -// defined... -#ifndef __STDC_CONSTANT_MACROS -#define __STDC_CONSTANT_MACROS -#endif #include extern "C" { diff --git a/apps/openmw/mwsound/libavwrapper.cpp b/apps/openmw/mwsound/libavwrapper.cpp index a7a3245da..40be67176 100644 --- a/apps/openmw/mwsound/libavwrapper.cpp +++ b/apps/openmw/mwsound/libavwrapper.cpp @@ -1,9 +1,6 @@ #ifndef HAVE_LIBSWRESAMPLE extern "C" { -#ifndef __STDC_CONSTANT_MACROS -#define __STDC_CONSTANT_MACROS -#endif #include #include diff --git a/extern/osg-ffmpeg-videoplayer/audiodecoder.hpp b/extern/osg-ffmpeg-videoplayer/audiodecoder.hpp index fe36ec39f..a592b02d3 100644 --- a/extern/osg-ffmpeg-videoplayer/audiodecoder.hpp +++ b/extern/osg-ffmpeg-videoplayer/audiodecoder.hpp @@ -1,9 +1,6 @@ #ifndef VIDEOPLAYER_AUDIODECODER_H #define VIDEOPLAYER_AUDIODECODER_H -#ifndef __STDC_CONSTANT_MACROS -#define __STDC_CONSTANT_MACROS -#endif #include #include diff --git a/extern/osg-ffmpeg-videoplayer/libavwrapper.cpp b/extern/osg-ffmpeg-videoplayer/libavwrapper.cpp index 6edc36207..26a7b6370 100644 --- a/extern/osg-ffmpeg-videoplayer/libavwrapper.cpp +++ b/extern/osg-ffmpeg-videoplayer/libavwrapper.cpp @@ -3,9 +3,6 @@ #ifndef HAVE_LIBSWRESAMPLE extern "C" { -#ifndef __STDC_CONSTANT_MACROS -#define __STDC_CONSTANT_MACROS -#endif #include #include diff --git a/extern/osg-ffmpeg-videoplayer/videoplayer.hpp b/extern/osg-ffmpeg-videoplayer/videoplayer.hpp index 79f9edb1c..c118ddb7f 100644 --- a/extern/osg-ffmpeg-videoplayer/videoplayer.hpp +++ b/extern/osg-ffmpeg-videoplayer/videoplayer.hpp @@ -1,12 +1,6 @@ #ifndef VIDEOPLAYER_H #define VIDEOPLAYER_H -// FIXME: This can't be right? The ffmpeg headers refuse to build without UINT64_C, -// which only gets defined in stdint.h in either C99 mode or with this macro -// defined... -#ifndef __STDC_CONSTANT_MACROS -#define __STDC_CONSTANT_MACROS -#endif #include #include diff --git a/extern/osg-ffmpeg-videoplayer/videostate.hpp b/extern/osg-ffmpeg-videoplayer/videostate.hpp index 247e04ec4..72a2aab18 100644 --- a/extern/osg-ffmpeg-videoplayer/videostate.hpp +++ b/extern/osg-ffmpeg-videoplayer/videostate.hpp @@ -1,9 +1,6 @@ #ifndef VIDEOPLAYER_VIDEOSTATE_H #define VIDEOPLAYER_VIDEOSTATE_H -#ifndef __STDC_CONSTANT_MACROS -#define __STDC_CONSTANT_MACROS -#endif #include #include From bbf4927a10db240cac09fc77a53fcd4b9f4ba5b7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 28 Jun 2015 16:38:11 +0200 Subject: [PATCH 1681/3725] Disable OSX travis for now, needs to be updated with an OSG package --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 6b03be114..d3b54b179 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ os: - linux - - osx +# - osx language: cpp branches: only: From 017c9f7ac9f2f6b7f8adac319e5bb6e9b71d28f7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 29 Jun 2015 20:19:46 +0200 Subject: [PATCH 1682/3725] Fading for weather particle effects --- apps/openmw/mwrender/sky.cpp | 81 ++++++++++++++++++++++++++++++------ apps/openmw/mwrender/sky.hpp | 2 + 2 files changed, 70 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 1aa2fd864..56afaadf1 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -687,10 +687,11 @@ private: float mAngle; }; -class RainFader : public SceneUtil::StateSetUpdater +// Updater for alpha value on a node's StateSet. Assumes the node has an existing Material StateAttribute. +class AlphaFader : public SceneUtil::StateSetUpdater { public: - RainFader() + AlphaFader() : mAlpha(1.f) { } @@ -700,20 +701,71 @@ public: mAlpha = alpha; } + virtual void apply(osg::StateSet* stateset, osg::NodeVisitor* nv) + { + osg::Material* mat = static_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); + mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0,0,0,mAlpha)); + } + + // Helper for adding AlphaFader to a subgraph + class SetupVisitor : public osg::NodeVisitor + { + public: + SetupVisitor() + : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) + { + mAlphaFader = new AlphaFader; + } + + virtual void apply(osg::Node &node) + { + if (osg::StateSet* stateset = node.getStateSet()) + { + if (stateset->getAttribute(osg::StateAttribute::MATERIAL)) + { + SceneUtil::CompositeStateSetUpdater* composite = NULL; + osg::NodeCallback* callback = node.getUpdateCallback(); + while (callback) + { + if ((composite = dynamic_cast(callback))) + break; + callback = callback->getNestedCallback(); + } + + if (composite) + composite->addController(mAlphaFader); + else + node.addUpdateCallback(mAlphaFader); + } + } + traverse(node); + } + + osg::ref_ptr getAlphaFader() + { + return mAlphaFader; + } + + private: + osg::ref_ptr mAlphaFader; + }; + +private: + float mAlpha; +}; + +class RainFader : public AlphaFader +{ +public: virtual void setDefaults(osg::StateSet* stateset) { osg::ref_ptr mat (new osg::Material); mat->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(1,1,1,1)); mat->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(0,0,0,1)); + mat->setColorMode(osg::Material::OFF); stateset->setAttributeAndModes(mat, osg::StateAttribute::ON); } - virtual void apply(osg::StateSet* stateset, osg::NodeVisitor* nv) - { - osg::Material* mat = static_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); - mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0,0,0,mAlpha)); - } - private: float mAlpha; }; @@ -928,6 +980,7 @@ void SkyManager::setWeather(const MWWorld::WeatherResult& weather) mParticleNode = NULL; } mParticleEffect = NULL; + mParticleFader = NULL; } else { @@ -940,6 +993,10 @@ void SkyManager::setWeather(const MWWorld::WeatherResult& weather) SceneUtil::AssignControllerSourcesVisitor assignVisitor(boost::shared_ptr(new SceneUtil::FrameTimeSource)); mParticleEffect->accept(assignVisitor); + + AlphaFader::SetupVisitor alphaFaderSetupVisitor; + mParticleEffect->accept(alphaFaderSetupVisitor); + mParticleFader = alphaFaderSetupVisitor.getAlphaFader(); } } @@ -1025,14 +1082,12 @@ void SkyManager::setWeather(const MWWorld::WeatherResult& weather) mSunGlare->setVisibility(weather.mGlareView * mGlareFade * strength); mSun->setVisibility(weather.mGlareView * strength); - - - if (mParticle.get()) - setAlpha(mParticle, weather.mEffectFade); - */ + */ if (mRainFader) mRainFader->setAlpha(weather.mEffectFade * 0.6); // * Rain_Threshold? + if (mParticleFader) + mParticleFader->setAlpha(weather.mEffectFade); } void SkyManager::setGlare(const float glare) diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index 85174896b..4d1c73e44 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -31,6 +31,7 @@ namespace MWRender class Moon; class RainShooter; class RainFader; + class AlphaFader; class SkyManager { @@ -104,6 +105,7 @@ namespace MWRender osg::ref_ptr mParticleNode; osg::ref_ptr mParticleEffect; + osg::ref_ptr mParticleFader; osg::ref_ptr mCloudNode; From e2103287aa0a9114b8e6b401aa3a699577aeec47 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Mon, 29 Jun 2015 22:45:34 +0300 Subject: [PATCH 1683/3725] Not accepted drag event must be ignored --- apps/opencs/view/world/dragrecordtable.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/apps/opencs/view/world/dragrecordtable.cpp b/apps/opencs/view/world/dragrecordtable.cpp index 5e8ddae26..a5f933283 100644 --- a/apps/opencs/view/world/dragrecordtable.cpp +++ b/apps/opencs/view/world/dragrecordtable.cpp @@ -55,12 +55,10 @@ void CSVWorld::DragRecordTable::dragMoveEvent(QDragMoveEvent *event) if (index.flags() & Qt::ItemIsEditable) { event->accept(); + return; } } - else - { - event->ignore(); - } + event->ignore(); } void CSVWorld::DragRecordTable::dropEvent(QDropEvent *event) From d5a47cfafee1c7929635365f6587f31e7990f8f9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 30 Jun 2015 01:41:03 +0200 Subject: [PATCH 1684/3725] Include cleanup --- apps/openmw/mwrender/sky.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 56afaadf1..dc43783ff 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -5,7 +5,6 @@ #include #include #include -#include #include #include #include @@ -17,8 +16,6 @@ #include #include -#include - #include #include From 4b2391c60fc11ada92b484f96c7edfc910a23c70 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 30 Jun 2015 02:51:32 +0200 Subject: [PATCH 1685/3725] Ignore effect meshes in getScreenBounds --- apps/openmw/mwrender/renderingmanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 2189f185b..d85c1c006 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -488,7 +488,7 @@ namespace MWRender return osg::Vec4f(); osg::ComputeBoundsVisitor computeBoundsVisitor; - computeBoundsVisitor.setTraversalMask(~MWRender::Mask_ParticleSystem); + computeBoundsVisitor.setTraversalMask(~(Mask_ParticleSystem|Mask_Effect)); ptr.getRefData().getBaseNode()->accept(computeBoundsVisitor); osg::Matrix viewProj = mViewer->getCamera()->getViewMatrix() * mViewer->getCamera()->getProjectionMatrix(); From ca21e9ecb174fb4ab2bd86803a35677d762471c4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 30 Jun 2015 02:52:09 +0200 Subject: [PATCH 1686/3725] Fix magic hit VFX showing when casting on a static object --- apps/openmw/mwworld/worldimp.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 6980a7e6f..d8f331c62 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2653,6 +2653,10 @@ namespace MWWorld target = result.mHitObject; hitPosition = result.mHitPos; + // don't allow casting on non-activatable objects + if (!target.isEmpty() && !target.getClass().isActor() && target.getClass().getName(target).empty()) + target = MWWorld::Ptr(); + std::string selectedSpell = stats.getSpells().getSelectedSpell(); MWMechanics::CastSpell cast(actor, target); From 43f9c7f2954fcc78e93e8a504328739a03807398 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 30 Jun 2015 03:25:30 +0200 Subject: [PATCH 1687/3725] Skip the Update traversal for inactive skeletons --- components/sceneutil/skeleton.cpp | 7 +++++++ components/sceneutil/skeleton.hpp | 2 ++ 2 files changed, 9 insertions(+) diff --git a/components/sceneutil/skeleton.cpp b/components/sceneutil/skeleton.cpp index 96941126b..5c2af4397 100644 --- a/components/sceneutil/skeleton.cpp +++ b/components/sceneutil/skeleton.cpp @@ -133,6 +133,13 @@ bool Skeleton::getActive() const return mActive; } +void Skeleton::traverse(osg::NodeVisitor& nv) +{ + if (!mActive && nv.getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR && mLastFrameNumber != 0) + return; + osg::Group::traverse(nv); +} + Bone::Bone() : mNode(NULL) { diff --git a/components/sceneutil/skeleton.hpp b/components/sceneutil/skeleton.hpp index 1987fd4e8..d4418fa27 100644 --- a/components/sceneutil/skeleton.hpp +++ b/components/sceneutil/skeleton.hpp @@ -53,6 +53,8 @@ namespace SceneUtil bool getActive() const; + void traverse(osg::NodeVisitor& nv); + private: // The root bone is not a "real" bone, it has no corresponding node in the scene graph. // As far as the scene graph goes we support multiple root bones. From 4eaaa5e855d8a362b1385ade296835abf26f298c Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 30 Jun 2015 03:54:56 +0200 Subject: [PATCH 1688/3725] Increment save file version and mark it as used, will be used in next commit --- apps/openmw/mwstate/statemanagerimp.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 7c111a090..313279063 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -218,8 +218,9 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot writer.setFormat (ESM::Header::CurrentFormat); + writer.setVersion(1); + // all unused - writer.setVersion(0); writer.setType(0); writer.setAuthor(""); writer.setDescription(""); From 463775060148a6b9a53676846a5ea31c4b38b423 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 30 Jun 2015 03:58:23 +0200 Subject: [PATCH 1689/3725] Savegame loading optimization --- apps/openmw/mwclass/creature.cpp | 30 ++++++++++++++---------------- apps/openmw/mwclass/npc.cpp | 19 +++++++++---------- components/esm/objectstate.cpp | 2 ++ components/esm/objectstate.hpp | 4 +++- 4 files changed, 28 insertions(+), 27 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 946f024b8..f312a41c7 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -798,27 +798,25 @@ namespace MWClass const ESM::CreatureState& state2 = dynamic_cast (state); - ensureCustomData(ptr); - - // If we do the following instead we get a sizable speedup, but this causes compatibility issues - // with 0.30 savegames, where some state in CreatureStats was not saved yet, - // and therefore needs to be loaded from ESM records. TODO: re-enable this in a future release. - /* - if (!ptr.getRefData().getCustomData()) + if (state.mVersion > 0) { - // Create a CustomData, but don't fill it from ESM records (not needed) - std::auto_ptr data (new CreatureCustomData); + if (!ptr.getRefData().getCustomData()) + { + // Create a CustomData, but don't fill it from ESM records (not needed) + std::auto_ptr data (new CreatureCustomData); - MWWorld::LiveCellRef *ref = ptr.get(); + MWWorld::LiveCellRef *ref = ptr.get(); - if (ref->mBase->mFlags & ESM::Creature::Weapon) - data->mContainerStore = new MWWorld::InventoryStore(); - else - data->mContainerStore = new MWWorld::ContainerStore(); + if (ref->mBase->mFlags & ESM::Creature::Weapon) + data->mContainerStore = new MWWorld::InventoryStore(); + else + data->mContainerStore = new MWWorld::ContainerStore(); - ptr.getRefData().setCustomData (data.release()); + ptr.getRefData().setCustomData (data.release()); + } } - */ + else + ensureCustomData(ptr); // in openmw 0.30 savegames not all state was saved yet, so need to load it regardless. CreatureCustomData& customData = dynamic_cast (*ptr.getRefData().getCustomData()); diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index ac0d67269..c7b407fb8 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -1233,18 +1233,17 @@ namespace MWClass const ESM::NpcState& state2 = dynamic_cast (state); - ensureCustomData(ptr); - // If we do the following instead we get a sizable speedup, but this causes compatibility issues - // with 0.30 savegames, where some state in CreatureStats was not saved yet, - // and therefore needs to be loaded from ESM records. TODO: re-enable this in a future release. - /* - if (!ptr.getRefData().getCustomData()) + if (state.mVersion > 0) { - // Create a CustomData, but don't fill it from ESM records (not needed) - std::auto_ptr data (new NpcCustomData); - ptr.getRefData().setCustomData (data.release()); + if (!ptr.getRefData().getCustomData()) + { + // Create a CustomData, but don't fill it from ESM records (not needed) + std::auto_ptr data (new NpcCustomData); + ptr.getRefData().setCustomData (data.release()); + } } - */ + else + ensureCustomData(ptr); // in openmw 0.30 savegames not all state was saved yet, so need to load it regardless. NpcCustomData& customData = dynamic_cast (*ptr.getRefData().getCustomData()); diff --git a/components/esm/objectstate.cpp b/components/esm/objectstate.cpp index 9ef1ccf80..8d73b10c6 100644 --- a/components/esm/objectstate.cpp +++ b/components/esm/objectstate.cpp @@ -6,6 +6,8 @@ void ESM::ObjectState::load (ESMReader &esm) { + mVersion = esm.getVer(); + mRef.loadData(esm); mHasLocals = 0; diff --git a/components/esm/objectstate.hpp b/components/esm/objectstate.hpp index d1077733a..674bcb8fc 100644 --- a/components/esm/objectstate.hpp +++ b/components/esm/objectstate.hpp @@ -29,7 +29,9 @@ namespace ESM // Is there any class-specific state following the ObjectState bool mHasCustomState; - ObjectState() : mHasCustomState(true) + unsigned int mVersion; + + ObjectState() : mHasCustomState(true), mVersion(0) {} /// @note Does not load the CellRef ID, it should already be loaded before calling this method From a081d402c571c88ea69d8e6044a862f781fbf3f3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 30 Jun 2015 17:26:33 +0200 Subject: [PATCH 1690/3725] Use the format field instead of version field --- apps/openmw/mwstate/statemanagerimp.cpp | 5 ++--- components/esm/objectstate.cpp | 2 +- components/esm/savedgame.cpp | 1 + components/esm/savedgame.hpp | 2 ++ 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 313279063..2c0540fbc 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -216,11 +216,10 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot ++iter) writer.addMaster (*iter, 0); // not using the size information anyway -> use value of 0 - writer.setFormat (ESM::Header::CurrentFormat); - - writer.setVersion(1); + writer.setFormat (ESM::SavedGame::sCurrentFormat); // all unused + writer.setVersion(0); writer.setType(0); writer.setAuthor(""); writer.setDescription(""); diff --git a/components/esm/objectstate.cpp b/components/esm/objectstate.cpp index 8d73b10c6..0ae690ee8 100644 --- a/components/esm/objectstate.cpp +++ b/components/esm/objectstate.cpp @@ -6,7 +6,7 @@ void ESM::ObjectState::load (ESMReader &esm) { - mVersion = esm.getVer(); + mVersion = esm.getFormat(); mRef.loadData(esm); diff --git a/components/esm/savedgame.cpp b/components/esm/savedgame.cpp index b5e0810db..9cdb28766 100644 --- a/components/esm/savedgame.cpp +++ b/components/esm/savedgame.cpp @@ -6,6 +6,7 @@ #include "defs.hpp" unsigned int ESM::SavedGame::sRecordId = ESM::REC_SAVE; +int ESM::SavedGame::sCurrentFormat = 1; void ESM::SavedGame::load (ESMReader &esm) { diff --git a/components/esm/savedgame.hpp b/components/esm/savedgame.hpp index 3e7cae775..aa0429657 100644 --- a/components/esm/savedgame.hpp +++ b/components/esm/savedgame.hpp @@ -15,6 +15,8 @@ namespace ESM { static unsigned int sRecordId; + static int sCurrentFormat; + struct TimeStamp { float mGameHour; From 20d03c7e39ebf9f09570be0a5a3e1029a8001bd4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 30 Jun 2015 17:26:42 +0200 Subject: [PATCH 1691/3725] Refuse loading save games of unknown format --- apps/openmw/mwstate/character.cpp | 3 --- apps/openmw/mwstate/statemanagerimp.cpp | 5 +++-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwstate/character.cpp b/apps/openmw/mwstate/character.cpp index f190565da..fcd1ca19e 100644 --- a/apps/openmw/mwstate/character.cpp +++ b/apps/openmw/mwstate/character.cpp @@ -29,9 +29,6 @@ void MWState::Character::addSlot (const boost::filesystem::path& path, const std ESM::ESMReader reader; reader.open (slot.mPath.string()); - if (reader.getFormat()>ESM::Header::CurrentFormat) - return; // format is too new -> ignore - if (reader.getRecName()!=ESM::REC_SAVE) return; // invalid save file -> ignore diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 2c0540fbc..192ad45fb 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -325,8 +325,6 @@ void MWState::StateManager::loadGame(const std::string& filepath) // have to peek into the save file to get the player name ESM::ESMReader reader; reader.open (filepath); - if (reader.getFormat()>ESM::Header::CurrentFormat) - return; // format is too new -> ignore if (reader.getRecName()!=ESM::REC_SAVE) return; // invalid save file -> ignore reader.getRecHeader(); @@ -348,6 +346,9 @@ void MWState::StateManager::loadGame (const Character *character, const std::str ESM::ESMReader reader; reader.open (filepath); + if (reader.getFormat() > ESM::SavedGame::sCurrentFormat) + throw std::runtime_error("This save file was created using a newer version of OpenMW and is thus not supported. Please upgrade to the newest OpenMW version to load this file."); + std::map contentFileMap = buildContentFileIndexMap (reader); Loading::Listener& listener = *MWBase::Environment::get().getWindowManager()->getLoadingScreen(); From 2065e0fa2d700163bbf9bbeb8eec5e0ccf84976a Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 30 Jun 2015 17:43:22 +0200 Subject: [PATCH 1692/3725] Use the correct format specifier for ess-imported savegames --- apps/essimporter/importer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/essimporter/importer.cpp b/apps/essimporter/importer.cpp index 65f318297..32ad1816c 100644 --- a/apps/essimporter/importer.cpp +++ b/apps/essimporter/importer.cpp @@ -327,7 +327,7 @@ namespace ESSImport ESM::ESMWriter writer; - writer.setFormat (ESM::Header::CurrentFormat); + writer.setFormat (ESM::SavedGame::sCurrentFormat); std::ofstream stream(mOutFile.c_str(), std::ios::binary); // all unused From 277113f75bac985fe7f7b0c88101bea558a5ea58 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 30 Jun 2015 18:05:48 +0200 Subject: [PATCH 1693/3725] Fix number of jobs in coverity script --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index d3b54b179..0029863d3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,7 +19,7 @@ addons: description: "" notification_email: scrawl@baseoftrash.de build_command_prepend: "cmake ." - build_command: "make -j3" + build_command: "make -j2" branch_pattern: coverity_scan matrix: include: From c30936c19b2c4cb12fd5c319f7d65361f48f6fa6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 30 Jun 2015 20:52:03 +0200 Subject: [PATCH 1694/3725] Reduce number of jobs in coverity script further --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 0029863d3..998d0d9d0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,7 +19,7 @@ addons: description: "" notification_email: scrawl@baseoftrash.de build_command_prepend: "cmake ." - build_command: "make -j2" + build_command: "make" branch_pattern: coverity_scan matrix: include: From 65ba072dcd69794ec86acb0a0987bede6862e94a Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 1 Jul 2015 02:09:13 +0200 Subject: [PATCH 1695/3725] Disable most targets except for OpenMW in coverity script --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 998d0d9d0..cbfc5d489 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,7 +18,7 @@ addons: name: "OpenMW/openmw" description: "" notification_email: scrawl@baseoftrash.de - build_command_prepend: "cmake ." + build_command_prepend: "cmake . -DBUILD_OPENCS=FALSE -DBUILD_UNITTESTS=FALSE -DBUILD_WIZARD=FALSE -DBUILD_BSATOOL=FALSE -DBUILD_ESMTOOL=FALSE -DBUILD_LAUNCHER=FALSE -DBUILD_MWINIIMPORTER=FALSE" build_command: "make" branch_pattern: coverity_scan matrix: From 5d2409136429cc870ab9f3c09167dc92358a8f5c Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Wed, 1 Jul 2015 15:06:38 +0200 Subject: [PATCH 1696/3725] Fix build error and a pair of warnings The error was about casting between osg::Callback* and osg::NodeCallback* The warnings are both about virtual classes with non-virtual destructors --- apps/openmw/mwrender/animation.hpp | 1 + apps/openmw/mwrender/sky.cpp | 4 ++-- apps/openmw/mwrender/weaponanimation.hpp | 2 ++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 73079e9a9..d45d19cf9 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -93,6 +93,7 @@ protected: boost::shared_ptr mTimePtr; public: + virtual ~AnimationTime() { } void setTimePtr(boost::shared_ptr time) { mTimePtr = time; } diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index dc43783ff..c7b0d3e41 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -721,12 +721,12 @@ public: if (stateset->getAttribute(osg::StateAttribute::MATERIAL)) { SceneUtil::CompositeStateSetUpdater* composite = NULL; - osg::NodeCallback* callback = node.getUpdateCallback(); + osg::NodeCallback* callback = dynamic_cast(node.getUpdateCallback()); while (callback) { if ((composite = dynamic_cast(callback))) break; - callback = callback->getNestedCallback(); + callback = dynamic_cast(callback->getNestedCallback()); } if (composite) diff --git a/apps/openmw/mwrender/weaponanimation.hpp b/apps/openmw/mwrender/weaponanimation.hpp index 3bf0fb721..fae459611 100644 --- a/apps/openmw/mwrender/weaponanimation.hpp +++ b/apps/openmw/mwrender/weaponanimation.hpp @@ -19,6 +19,8 @@ namespace MWRender float mStartTime; public: WeaponAnimationTime(Animation* animation) : mAnimation(animation), mStartTime(0) {} + virtual ~WeaponAnimationTime() { } + void setGroup(const std::string& group); void updateStartTime(); From 1afa22f443e05656c4b36e85c2e1d3eac4ca94e1 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Tue, 30 Jun 2015 23:35:54 +0300 Subject: [PATCH 1697/3725] Add the RecordType column to the MetaData table --- apps/opencs/model/world/data.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index e999b4650..a92a7ad79 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -479,6 +479,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mMetaData.addColumn (new StringIdColumn (true)); mMetaData.addColumn (new RecordStateColumn); + mMetaData.addColumn (new FixedRecordTypeColumn (UniversalId::Type_MetaData)); mMetaData.addColumn (new FormatColumn); mMetaData.addColumn (new AuthorColumn); mMetaData.addColumn (new FileDescriptionColumn); From 1949fe4bf9e132e208766142400bf0d18d6762ce Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Thu, 2 Jul 2015 15:47:12 +0300 Subject: [PATCH 1698/3725] Add the configuration widget for extended commands --- apps/opencs/CMakeLists.txt | 2 +- .../world/extendedcommandconfigurator.cpp | 184 ++++++++++++++++++ .../world/extendedcommandconfigurator.hpp | 68 +++++++ 3 files changed, 253 insertions(+), 1 deletion(-) create mode 100644 apps/opencs/view/world/extendedcommandconfigurator.cpp create mode 100644 apps/opencs/view/world/extendedcommandconfigurator.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index dc042cb99..c933cbf9d 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -64,7 +64,7 @@ opencs_units (view/world table tablesubview scriptsubview util regionmapsubview tablebottombox creator genericcreator cellcreator referenceablecreator referencecreator scenesubview infocreator scriptedit dialoguesubview previewsubview regionmap dragrecordtable nestedtable - dialoguespinbox recordbuttonbar + dialoguespinbox recordbuttonbar extendedcommandconfigurator ) opencs_units_noqt (view/world diff --git a/apps/opencs/view/world/extendedcommandconfigurator.cpp b/apps/opencs/view/world/extendedcommandconfigurator.cpp new file mode 100644 index 000000000..dfdb5f573 --- /dev/null +++ b/apps/opencs/view/world/extendedcommandconfigurator.cpp @@ -0,0 +1,184 @@ +#include "extendedcommandconfigurator.hpp" + +#include +#include +#include +#include + +#include "../../model/world/commanddispatcher.hpp" +#include "../../model/world/universalid.hpp" + +namespace +{ + QString getTypeGroupTitle(CSVWorld::ExtendedCommandConfigurator::Mode mode) + { + static const QString title = "Tables affected by "; + QString titleSuffix = "Extended Delete"; + if (mode == CSVWorld::ExtendedCommandConfigurator::Mode_Revert) + { + titleSuffix = "Extended Revert"; + } + return title + titleSuffix; + } +} + +CSVWorld::ExtendedCommandConfigurator::ExtendedCommandConfigurator(CSMDoc::Document &document, + const CSMWorld::UniversalId &id, + QWidget *parent) + : QWidget(parent), + mNumUsedCheckBoxes(0), + mMode(Mode_None) +{ + mCommandDispatcher = new CSMWorld::CommandDispatcher(document, id, this); + + mPerformButton = new QPushButton("Perform", this); + mPerformButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + connect(mPerformButton, SIGNAL(clicked(bool)), this, SLOT(performExtendedCommand())); + + mCancelButton = new QPushButton("Cancel", this); + mCancelButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + connect(mCancelButton, SIGNAL(clicked(bool)), this, SLOT(done())); + + mButtonLayout = new QHBoxLayout(); + mButtonLayout->setAlignment(Qt::AlignCenter); + mButtonLayout->addWidget(mPerformButton); + mButtonLayout->addWidget(mCancelButton); + + mTypeGroup = new QGroupBox(this); + + QGridLayout *groupLayout = new QGridLayout(mTypeGroup); + groupLayout->setAlignment(Qt::AlignCenter); + mTypeGroup->setLayout(groupLayout); + + QVBoxLayout *mainLayout = new QVBoxLayout(this); + mainLayout->setSizeConstraint(QLayout::SetNoConstraint); + mainLayout->addWidget(mTypeGroup); + mainLayout->addLayout(mButtonLayout); +} + +CSVWorld::ExtendedCommandConfigurator::~ExtendedCommandConfigurator() +{ + delete mButtonLayout; +} + +void CSVWorld::ExtendedCommandConfigurator::configure(CSVWorld::ExtendedCommandConfigurator::Mode mode) +{ + mMode = mode; + if (mMode != Mode_None) + { + mTypeGroup->setTitle(getTypeGroupTitle(mMode)); + setupCheckBoxes(mCommandDispatcher->getExtendedTypes()); + setupGroupLayout(); + } +} + +void CSVWorld::ExtendedCommandConfigurator::resizeEvent(QResizeEvent *event) +{ + QWidget::resizeEvent(event); + setupGroupLayout(); +} + +void CSVWorld::ExtendedCommandConfigurator::setupGroupLayout() +{ + if (mMode == Mode_None) + { + return; + } + + int groupWidth = mTypeGroup->geometry().width(); + QGridLayout *layout = qobject_cast(mTypeGroup->layout()); + + // One row of checkboxes with enough space - the setup is over + if (mNumUsedCheckBoxes > 0 && layout->rowCount() == 1 && groupWidth >= mTypeGroup->sizeHint().width()) + { + return; + } + + // Find the optimal number of rows to place the checkboxes within the available space + int divider = 1; + do + { + while (layout->itemAt(0) != NULL) + { + layout->removeItem(layout->itemAt(0)); + } + + int counter = 0; + int itemsPerRow = mNumUsedCheckBoxes / divider; + CheckBoxMap::const_iterator current = mTypeCheckBoxes.begin(); + CheckBoxMap::const_iterator end = mTypeCheckBoxes.end(); + for (; current != end; ++current) + { + if (current->first->isVisible()) + { + int row = counter / itemsPerRow; + int column = counter - (counter / itemsPerRow) * itemsPerRow; + layout->addWidget(current->first, row, column); + } + ++counter; + } + divider *= 2; + } + while (groupWidth < mTypeGroup->sizeHint().width()); +} + +void CSVWorld::ExtendedCommandConfigurator::setupCheckBoxes(const std::vector &types) +{ + // Make sure that we have enough checkboxes + int numTypes = static_cast(types.size()); + int numCheckBoxes = static_cast(mTypeCheckBoxes.size()); + if (numTypes > numCheckBoxes) + { + for (int i = numTypes - numCheckBoxes; i > 0; --i) + { + mTypeCheckBoxes.insert(std::make_pair(new QCheckBox(this), CSMWorld::UniversalId::Type_None)); + } + } + + // Set up the checkboxes + int counter = 0; + CheckBoxMap::iterator current = mTypeCheckBoxes.begin(); + CheckBoxMap::iterator end = mTypeCheckBoxes.end(); + for (; current != end; ++current) + { + if (counter < numTypes) + { + CSMWorld::UniversalId type = types[counter]; + current->first->setText(QString::fromUtf8(type.getTypeName().c_str())); + current->first->setChecked(true); + current->second = type; + ++counter; + } + else + { + current->first->hide(); + } + } + mNumUsedCheckBoxes = counter - 1; +} + +void CSVWorld::ExtendedCommandConfigurator::performExtendedCommand() +{ + std::vector types; + + CheckBoxMap::const_iterator current = mTypeCheckBoxes.begin(); + CheckBoxMap::const_iterator end = mTypeCheckBoxes.end(); + for (; current != end; ++current) + { + if (current->first->isChecked()) + { + types.push_back(current->second); + } + } + + mCommandDispatcher->setExtendedTypes(types); + if (mMode == Mode_Delete) + { + mCommandDispatcher->executeExtendedDelete(); + } + else + { + mCommandDispatcher->executeExtendedRevert(); + } + emit done(); +} diff --git a/apps/opencs/view/world/extendedcommandconfigurator.hpp b/apps/opencs/view/world/extendedcommandconfigurator.hpp new file mode 100644 index 000000000..2feec14a7 --- /dev/null +++ b/apps/opencs/view/world/extendedcommandconfigurator.hpp @@ -0,0 +1,68 @@ +#ifndef CSVWORLD_EXTENDEDCOMMANDCONFIGURATOR_HPP +#define CSVWORLD_EXTENDEDCOMMANDCONFIGURATOR_HPP + +#include + +#include + +class QPushButton; +class QGroupBox; +class QCheckBox; +class QHBoxLayout; + +namespace CSMDoc +{ + class Document; +} + +namespace CSMWorld +{ + class CommandDispatcher; + class UniversalId; +} + +namespace CSVWorld +{ + class ExtendedCommandConfigurator : public QWidget + { + Q_OBJECT + + public: + enum Mode { Mode_None, Mode_Delete, Mode_Revert }; + + private: + typedef std::map CheckBoxMap; + + QPushButton *mPerformButton; + QPushButton *mCancelButton; + QHBoxLayout *mButtonLayout; + QGroupBox *mTypeGroup; + CheckBoxMap mTypeCheckBoxes; + int mNumUsedCheckBoxes; + + Mode mMode; + CSMWorld::CommandDispatcher *mCommandDispatcher; + + void setupGroupLayout(); + void setupCheckBoxes(const std::vector &types); + + public: + ExtendedCommandConfigurator(CSMDoc::Document &document, + const CSMWorld::UniversalId &id, + QWidget *parent = 0); + virtual ~ExtendedCommandConfigurator(); + + void configure(Mode mode); + + protected: + virtual void resizeEvent(QResizeEvent *event); + + private slots: + void performExtendedCommand(); + + signals: + void done(); + }; +} + +#endif From ba762ec1c1739bf0c86f727e8875efd7a2f3c4bf Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Thu, 2 Jul 2015 17:21:47 +0300 Subject: [PATCH 1699/3725] Add the configuration widget to the bottom box --- apps/opencs/view/world/tablebottombox.cpp | 37 ++++++++++++++++++----- apps/opencs/view/world/tablebottombox.hpp | 17 +++++++++-- 2 files changed, 43 insertions(+), 11 deletions(-) diff --git a/apps/opencs/view/world/tablebottombox.cpp b/apps/opencs/view/world/tablebottombox.cpp index dc3a6cc76..eab6b07b3 100644 --- a/apps/opencs/view/world/tablebottombox.cpp +++ b/apps/opencs/view/world/tablebottombox.cpp @@ -39,11 +39,19 @@ void CSVWorld::TableBottomBox::updateStatus() } } +void CSVWorld::TableBottomBox::extendedConfigRequest(CSVWorld::ExtendedCommandConfigurator::Mode mode) +{ + mExtendedConfigurator->configure (mode); + mLayout->setCurrentWidget (mExtendedConfigurator); + mEditMode = EditMode_ExtendedConfig; + setVisible (true); +} + CSVWorld::TableBottomBox::TableBottomBox (const CreatorFactoryBase& creatorFactory, CSMDoc::Document& document, const CSMWorld::UniversalId& id, QWidget *parent) -: QWidget (parent), mShowStatusBar (false), mCreating (false) +: QWidget (parent), mShowStatusBar (false), mEditMode(EditMode_None) { for (int i=0; i<4; ++i) mStatusCount[i] = 0; @@ -69,11 +77,15 @@ CSVWorld::TableBottomBox::TableBottomBox (const CreatorFactoryBase& creatorFacto { mLayout->addWidget (mCreator); - connect (mCreator, SIGNAL (done()), this, SLOT (createRequestDone())); + connect (mCreator, SIGNAL (done()), this, SLOT (requestDone())); connect (mCreator, SIGNAL (requestFocus (const std::string&)), this, SIGNAL (requestFocus (const std::string&))); } + + mExtendedConfigurator = new ExtendedCommandConfigurator (document, id, this); + mLayout->addWidget (mExtendedConfigurator); + connect (mExtendedConfigurator, SIGNAL (done()), this, SLOT (requestDone())); } void CSVWorld::TableBottomBox::setEditLock (bool locked) @@ -91,7 +103,7 @@ void CSVWorld::TableBottomBox::setStatusBar (bool show) { if (show!=mShowStatusBar) { - setVisible (show || mCreating); + setVisible (show || (mEditMode != EditMode_None)); mShowStatusBar = show; @@ -105,7 +117,7 @@ bool CSVWorld::TableBottomBox::canCreateAndDelete() const return mCreator; } -void CSVWorld::TableBottomBox::createRequestDone() +void CSVWorld::TableBottomBox::requestDone() { if (!mShowStatusBar) setVisible (false); @@ -113,8 +125,7 @@ void CSVWorld::TableBottomBox::createRequestDone() updateStatus(); mLayout->setCurrentWidget (mStatusBar); - - mCreating = false; + mEditMode = EditMode_None; } void CSVWorld::TableBottomBox::selectionSizeChanged (int size) @@ -158,7 +169,7 @@ void CSVWorld::TableBottomBox::createRequest() mCreator->toggleWidgets(true); mLayout->setCurrentWidget (mCreator); setVisible (true); - mCreating = true; + mEditMode = EditMode_Creation; mCreator->focus(); } @@ -170,6 +181,16 @@ void CSVWorld::TableBottomBox::cloneRequest(const std::string& id, mLayout->setCurrentWidget(mCreator); mCreator->toggleWidgets(false); setVisible (true); - mCreating = true; + mEditMode = EditMode_Creation; mCreator->focus(); } + +void CSVWorld::TableBottomBox::extendedDeleteConfigRequest() +{ + extendedConfigRequest(ExtendedCommandConfigurator::Mode_Delete); +} + +void CSVWorld::TableBottomBox::extendedRevertConfigRequest() +{ + extendedConfigRequest(ExtendedCommandConfigurator::Mode_Revert); +} diff --git a/apps/opencs/view/world/tablebottombox.hpp b/apps/opencs/view/world/tablebottombox.hpp index a7d009c42..d2fb865e7 100644 --- a/apps/opencs/view/world/tablebottombox.hpp +++ b/apps/opencs/view/world/tablebottombox.hpp @@ -4,10 +4,11 @@ #include #include +#include "extendedcommandconfigurator.hpp" + class QLabel; class QStackedLayout; class QStatusBar; -class QUndoStack; namespace CSMDoc { @@ -23,12 +24,17 @@ namespace CSVWorld { Q_OBJECT + enum EditMode { EditMode_None, EditMode_Creation, EditMode_ExtendedConfig }; + bool mShowStatusBar; QLabel *mStatus; QStatusBar *mStatusBar; int mStatusCount[4]; + + EditMode mEditMode; Creator *mCreator; - bool mCreating; + ExtendedCommandConfigurator *mExtendedConfigurator; + QStackedLayout *mLayout; private: @@ -39,6 +45,8 @@ namespace CSVWorld void updateStatus(); + void extendedConfigRequest(ExtendedCommandConfigurator::Mode mode); + public: TableBottomBox (const CreatorFactoryBase& creatorFactory, @@ -65,7 +73,7 @@ namespace CSVWorld private slots: - void createRequestDone(); + void requestDone(); ///< \note This slot being called does not imply success. public slots: @@ -80,6 +88,9 @@ namespace CSVWorld void createRequest(); void cloneRequest(const std::string& id, const CSMWorld::UniversalId::Type type); + + void extendedDeleteConfigRequest(); + void extendedRevertConfigRequest(); }; } From 519fb9482aa36e9e07d544f16325aa9fee14dd01 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 2 Jul 2015 18:11:24 +0200 Subject: [PATCH 1700/3725] Minor cleanup --- apps/openmw/mwworld/player.cpp | 2 +- apps/openmw/mwworld/player.hpp | 8 +------- apps/openmw/mwworld/worldimp.cpp | 2 +- 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index 0b00f211e..48d69e4de 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -28,7 +28,7 @@ namespace MWWorld { - Player::Player (const ESM::NPC *player, const MWBase::World& world) + Player::Player (const ESM::NPC *player) : mCellStore(0), mLastKnownExteriorPosition(0,0,0), mMarkedCell(NULL), diff --git a/apps/openmw/mwworld/player.hpp b/apps/openmw/mwworld/player.hpp index d5376c40d..bd5a74187 100644 --- a/apps/openmw/mwworld/player.hpp +++ b/apps/openmw/mwworld/player.hpp @@ -17,12 +17,6 @@ namespace ESM class ESMReader; } -namespace MWBase -{ - class World; - class Ptr; -} - namespace Loading { class Listener; @@ -58,7 +52,7 @@ namespace MWWorld public: - Player(const ESM::NPC *player, const MWBase::World& world); + Player(const ESM::NPC *player); void saveSkillsAttributes(); void restoreSkillsAttributes(); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index d8f331c62..4b14ea602 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2045,7 +2045,7 @@ namespace MWWorld { const ESM::NPC *player = mStore.get().find("player"); if (!mPlayer) - mPlayer = new MWWorld::Player(player, *this); + mPlayer = new MWWorld::Player(player); else { // Remove the old CharacterController From a1432b0255dd65999d9b148c690b793735c8111b Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 2 Jul 2015 19:14:28 +0200 Subject: [PATCH 1701/3725] Move attackingOrSpell flag to the CharacterController --- apps/openmw/mwinput/inputmanagerimp.cpp | 2 +- apps/openmw/mwmechanics/actors.cpp | 3 +++ apps/openmw/mwmechanics/aicombat.cpp | 5 ++--- apps/openmw/mwmechanics/character.cpp | 14 ++++++++++---- apps/openmw/mwmechanics/character.hpp | 5 +++++ apps/openmw/mwmechanics/creaturestats.cpp | 14 +------------- apps/openmw/mwmechanics/creaturestats.hpp | 1 - apps/openmw/mwworld/player.cpp | 13 ++++++++++++- apps/openmw/mwworld/player.hpp | 5 +++++ components/esm/creaturestats.cpp | 8 ++------ components/esm/creaturestats.hpp | 1 - 11 files changed, 41 insertions(+), 30 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 7ef26f703..f47283062 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -207,7 +207,7 @@ namespace MWInput if (mControlSwitch["playercontrols"]) { if (action == A_Use) - mPlayer->getPlayer().getClass().getCreatureStats(mPlayer->getPlayer()).setAttackingOrSpell(currentValue != 0); + mPlayer->setAttackingOrSpell(currentValue != 0); else if (action == A_Jump) mAttemptJump = (currentValue == 1.0 && previousValue == 0.0); } diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 2c53c00b7..f0b47ac7b 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1086,6 +1086,9 @@ namespace MWMechanics iter->second->getCharacterController()->setActive(inProcessingRange); + if (iter->first == player) + iter->second->getCharacterController()->setAttackingOrSpell(MWBase::Environment::get().getWorld()->getPlayer().getAttackingOrSpell()); + if (!iter->first.getClass().getCreatureStats(iter->first).isDead()) { updateActor(iter->first, duration); diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 56dd11b99..35d1f5376 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -269,8 +269,7 @@ namespace MWMechanics attack = false; } - actorClass.getCreatureStats(actor).setAttackingOrSpell(attack); - + characterController.setAttackingOrSpell(attack); float& actionCooldown = storage.mActionCooldown; actionCooldown -= duration; @@ -476,7 +475,7 @@ namespace MWMechanics movement.mPosition[1] = 0; movement.mPosition[2] = 0; readyToAttack = false; - actorClass.getCreatureStats(actor).setAttackingOrSpell(false); + characterController.setAttackingOrSpell(false); return false; } diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index c39b7dcef..a3d69c059 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -654,6 +654,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim , mSecondsOfSwimming(0) , mSecondsOfRunning(0) , mTurnAnimationThreshold(0) + , mAttackingOrSpell(false) { if(!mAnimation) return; @@ -937,7 +938,7 @@ bool CharacterController::updateCreatureState() mAnimation->disable(mCurrentWeapon); } - if(stats.getAttackingOrSpell()) + if(mAttackingOrSpell) { if(mUpperBodyState == UpperCharState_Nothing && mHitState == CharState_None) { @@ -997,7 +998,7 @@ bool CharacterController::updateCreatureState() } } - stats.setAttackingOrSpell(false); + mAttackingOrSpell = false; } bool animPlaying = mAnimation->getInfo(mCurrentWeapon); @@ -1142,7 +1143,7 @@ bool CharacterController::updateWeaponState() float complete; bool animPlaying; - if(stats.getAttackingOrSpell()) + if(mAttackingOrSpell) { if(mUpperBodyState == UpperCharState_WeapEquiped && mHitState == CharState_None) { @@ -1152,7 +1153,7 @@ bool CharacterController::updateWeaponState() { // Unset casting flag, otherwise pressing the mouse button down would // continue casting every frame if there is no animation - stats.setAttackingOrSpell(false); + mAttackingOrSpell = false; const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); @@ -2041,6 +2042,11 @@ bool CharacterController::isKnockedOut() const return mHitState == CharState_KnockOut; } +void CharacterController::setAttackingOrSpell(bool attackingOrSpell) +{ + mAttackingOrSpell = attackingOrSpell; +} + void CharacterController::setActive(bool active) { mAnimation->setActive(active); diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index be8fb2bf6..0a8771fb4 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -180,6 +180,9 @@ class CharacterController : public MWRender::Animation::TextKeyListener float mTurnAnimationThreshold; // how long to continue playing turning animation after actor stopped turning std::string mAttackType; // slash, chop or thrust + + bool mAttackingOrSpell; + void determineAttackType(); void refreshCurrentAnims(CharacterState idle, CharacterState movement, bool force=false); @@ -235,6 +238,8 @@ public: bool isReadyToBlock() const; bool isKnockedOut() const; + void setAttackingOrSpell(bool attackingOrSpell); + /// @see Animation::setActive void setActive(bool active); diff --git a/apps/openmw/mwmechanics/creaturestats.cpp b/apps/openmw/mwmechanics/creaturestats.cpp index 5a09eb4ee..f480efc71 100644 --- a/apps/openmw/mwmechanics/creaturestats.cpp +++ b/apps/openmw/mwmechanics/creaturestats.cpp @@ -16,7 +16,7 @@ namespace MWMechanics CreatureStats::CreatureStats() : mDrawState (DrawState_Nothing), mDead (false), mDied (false), mMurdered(false), mFriendlyHits (0), - mTalkedTo (false), mAlarmed (false), mAttacked (false), mAttackingOrSpell(false), + mTalkedTo (false), mAlarmed (false), mAttacked (false), mKnockdown(false), mKnockdownOneFrame(false), mKnockdownOverOneFrame(false), mHitRecovery(false), mBlock(false), mMovementFlags(0), mFallHeight(0), mRecalcMagicka(false), mLastRestock(0,0), mGoldPool(0), mActorId(-1), @@ -88,11 +88,6 @@ namespace MWMechanics return mMagicEffects; } - bool CreatureStats::getAttackingOrSpell() const - { - return mAttackingOrSpell; - } - int CreatureStats::getLevel() const { return mLevel; @@ -212,11 +207,6 @@ namespace MWMechanics mMagicEffects.setModifiers(effects); } - void CreatureStats::setAttackingOrSpell(bool attackingOrSpell) - { - mAttackingOrSpell = attackingOrSpell; - } - void CreatureStats::setAiSetting (AiSetting index, Stat value) { mAiSettings[index] = value; @@ -487,7 +477,6 @@ namespace MWMechanics state.mTalkedTo = mTalkedTo; state.mAlarmed = mAlarmed; state.mAttacked = mAttacked; - state.mAttackingOrSpell = mAttackingOrSpell; // TODO: rewrite. does this really need 3 separate bools? state.mKnockdown = mKnockdown; state.mKnockdownOneFrame = mKnockdownOneFrame; @@ -534,7 +523,6 @@ namespace MWMechanics mTalkedTo = state.mTalkedTo; mAlarmed = state.mAlarmed; mAttacked = state.mAttacked; - mAttackingOrSpell = state.mAttackingOrSpell; // TODO: rewrite. does this really need 3 separate bools? mKnockdown = state.mKnockdown; mKnockdownOneFrame = state.mKnockdownOneFrame; diff --git a/apps/openmw/mwmechanics/creaturestats.hpp b/apps/openmw/mwmechanics/creaturestats.hpp index 0e91cd149..5d22da7cc 100644 --- a/apps/openmw/mwmechanics/creaturestats.hpp +++ b/apps/openmw/mwmechanics/creaturestats.hpp @@ -40,7 +40,6 @@ namespace MWMechanics bool mTalkedTo; bool mAlarmed; bool mAttacked; - bool mAttackingOrSpell; bool mKnockdown; bool mKnockdownOneFrame; bool mKnockdownOverOneFrame; diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index 48d69e4de..b17b8e1f0 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -36,7 +36,8 @@ namespace MWWorld mForwardBackward(0), mTeleported(false), mCurrentCrimeId(-1), - mPaidCrimeId(-1) + mPaidCrimeId(-1), + mAttackingOrSpell(false) { ESM::CellRef cellRef; cellRef.blank(); @@ -216,6 +217,16 @@ namespace MWWorld mTeleported = teleported; } + void Player::setAttackingOrSpell(bool attackingOrSpell) + { + mAttackingOrSpell = attackingOrSpell; + } + + bool Player::getAttackingOrSpell() const + { + return mAttackingOrSpell; + } + bool Player::isInCombat() { return MWBase::Environment::get().getMechanicsManager()->getActorsFighting(getPlayer()).size() != 0; } diff --git a/apps/openmw/mwworld/player.hpp b/apps/openmw/mwworld/player.hpp index bd5a74187..f0ae13daa 100644 --- a/apps/openmw/mwworld/player.hpp +++ b/apps/openmw/mwworld/player.hpp @@ -50,6 +50,8 @@ namespace MWWorld MWMechanics::SkillValue mSaveSkills[ESM::Skill::Length]; MWMechanics::AttributeValue mSaveAttributes[ESM::Attribute::Length]; + bool mAttackingOrSpell; + public: Player(const ESM::NPC *player); @@ -98,6 +100,9 @@ namespace MWWorld bool wasTeleported() const; void setTeleported(bool teleported); + void setAttackingOrSpell(bool attackingOrSpell); + bool getAttackingOrSpell() const; + ///Checks all nearby actors to see if anyone has an aipackage against you bool isInCombat(); diff --git a/components/esm/creaturestats.cpp b/components/esm/creaturestats.cpp index d0fe4be63..89d865c1d 100644 --- a/components/esm/creaturestats.cpp +++ b/components/esm/creaturestats.cpp @@ -39,8 +39,8 @@ void ESM::CreatureStats::load (ESMReader &esm) if (esm.isNextSub("HOST")) esm.skipHSub(); // Hostile, no longer used - mAttackingOrSpell = false; - esm.getHNOT (mAttackingOrSpell, "ATCK"); + if (esm.isNextSub("ATCK")) + esm.skipHSub(); // attackingOrSpell, no longer used mKnockdown = false; esm.getHNOT (mKnockdown, "KNCK"); @@ -149,9 +149,6 @@ void ESM::CreatureStats::save (ESMWriter &esm) const if (mAttacked) esm.writeHNT ("ATKD", mAttacked); - if (mAttackingOrSpell) - esm.writeHNT ("ATCK", mAttackingOrSpell); - if (mKnockdown) esm.writeHNT ("KNCK", mKnockdown); @@ -232,7 +229,6 @@ void ESM::CreatureStats::blank() mTalkedTo = false; mAlarmed = false; mAttacked = false; - mAttackingOrSpell = false; mKnockdown = false; mKnockdownOneFrame = false; mKnockdownOverOneFrame = false; diff --git a/components/esm/creaturestats.hpp b/components/esm/creaturestats.hpp index 3b1d199e4..426e89055 100644 --- a/components/esm/creaturestats.hpp +++ b/components/esm/creaturestats.hpp @@ -45,7 +45,6 @@ namespace ESM bool mTalkedTo; bool mAlarmed; bool mAttacked; - bool mAttackingOrSpell; bool mKnockdown; bool mKnockdownOneFrame; bool mKnockdownOverOneFrame; From 6691891beeca866d13e73e1e7cdb9982f95bf61f Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 2 Jul 2015 19:16:44 +0200 Subject: [PATCH 1702/3725] Include cleanup --- apps/openmw/mwinput/inputmanagerimp.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index f47283062..09e0b638b 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -1,7 +1,6 @@ #include "inputmanagerimp.hpp" #include -#include #include @@ -22,7 +21,6 @@ #include "../mwbase/windowmanager.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwbase/statemanager.hpp" -#include "../mwbase/mechanicsmanager.hpp" #include "../mwworld/player.hpp" #include "../mwworld/class.hpp" @@ -31,8 +29,6 @@ #include "../mwmechanics/npcstats.hpp" -#include "../mwdialogue/dialoguemanagerimp.hpp" - using namespace ICS; namespace MWInput From fcf69555f4bf382aa808179a5fafb89df7feaaa1 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Thu, 2 Jul 2015 20:41:32 +0300 Subject: [PATCH 1703/3725] Add the user setting for enabling the configuration of extended commands --- apps/opencs/model/settings/usersettings.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/apps/opencs/model/settings/usersettings.cpp b/apps/opencs/model/settings/usersettings.cpp index 1bfc6e85b..cb001fea9 100644 --- a/apps/opencs/model/settings/usersettings.cpp +++ b/apps/opencs/model/settings/usersettings.cpp @@ -215,6 +215,12 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() "Jump to the added or cloned record."); jumpToAdded->setDefaultValue (defaultValue); jumpToAdded->setDeclaredValues (jumpValues); + + Setting *extendedConfig = createSetting (Type_CheckBox, "extended-config", + "Enable configuration of the extended delete/revert"); + extendedConfig->setDefaultValue("false"); + extendedConfig->setToolTip("Enables the ability to specify tables that will be affected by " + "the extended delete/revert command"); } declareSection ("report-input", "Report Input"); From b8772c6902ec22f80a3f1d4850db626417c1898b Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Thu, 2 Jul 2015 20:44:59 +0300 Subject: [PATCH 1704/3725] Add the ability to configure extended commands for tables --- .../world/extendedcommandconfigurator.cpp | 6 +- .../world/extendedcommandconfigurator.hpp | 2 +- apps/opencs/view/world/table.cpp | 70 +++++++++++++------ apps/opencs/view/world/table.hpp | 10 +++ apps/opencs/view/world/tablebottombox.cpp | 13 ++-- apps/opencs/view/world/tablebottombox.hpp | 7 +- apps/opencs/view/world/tablesubview.cpp | 5 ++ 7 files changed, 79 insertions(+), 34 deletions(-) diff --git a/apps/opencs/view/world/extendedcommandconfigurator.cpp b/apps/opencs/view/world/extendedcommandconfigurator.cpp index dfdb5f573..6ba26634b 100644 --- a/apps/opencs/view/world/extendedcommandconfigurator.cpp +++ b/apps/opencs/view/world/extendedcommandconfigurator.cpp @@ -37,7 +37,7 @@ CSVWorld::ExtendedCommandConfigurator::ExtendedCommandConfigurator(CSMDoc::Docum mCancelButton = new QPushButton("Cancel", this); mCancelButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - connect(mCancelButton, SIGNAL(clicked(bool)), this, SLOT(done())); + connect(mCancelButton, SIGNAL(clicked(bool)), this, SIGNAL(done())); mButtonLayout = new QHBoxLayout(); mButtonLayout->setAlignment(Qt::AlignCenter); @@ -61,12 +61,14 @@ CSVWorld::ExtendedCommandConfigurator::~ExtendedCommandConfigurator() delete mButtonLayout; } -void CSVWorld::ExtendedCommandConfigurator::configure(CSVWorld::ExtendedCommandConfigurator::Mode mode) +void CSVWorld::ExtendedCommandConfigurator::configure(CSVWorld::ExtendedCommandConfigurator::Mode mode, + const std::vector &selectedIds) { mMode = mode; if (mMode != Mode_None) { mTypeGroup->setTitle(getTypeGroupTitle(mMode)); + mCommandDispatcher->setSelection(selectedIds); setupCheckBoxes(mCommandDispatcher->getExtendedTypes()); setupGroupLayout(); } diff --git a/apps/opencs/view/world/extendedcommandconfigurator.hpp b/apps/opencs/view/world/extendedcommandconfigurator.hpp index 2feec14a7..dd2477444 100644 --- a/apps/opencs/view/world/extendedcommandconfigurator.hpp +++ b/apps/opencs/view/world/extendedcommandconfigurator.hpp @@ -52,7 +52,7 @@ namespace CSVWorld QWidget *parent = 0); virtual ~ExtendedCommandConfigurator(); - void configure(Mode mode); + void configure(Mode mode, const std::vector &selectedIds); protected: virtual void resizeEvent(QResizeEvent *event); diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index ba691131b..353bd50d2 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -32,28 +32,14 @@ void CSVWorld::Table::contextMenuEvent (QContextMenuEvent *event) { // configure dispatcher - QModelIndexList selectedRows = selectionModel()->selectedRows(); - - std::vector records; - - int columnIndex = mModel->findColumnIndex (CSMWorld::Columns::ColumnId_Id); - - for (QModelIndexList::const_iterator iter (selectedRows.begin()); iter!=selectedRows.end(); - ++iter) - { - int row = mProxyModel->mapToSource (mProxyModel->index (iter->row(), 0)).row(); - - records.push_back (mModel->data ( - mModel->index (row, columnIndex)).toString().toUtf8().constData()); - } - - mDispatcher->setSelection (records); + mDispatcher->setSelection (getSelectedIds()); std::vector extendedTypes = mDispatcher->getExtendedTypes(); mDispatcher->setExtendedTypes (extendedTypes); // create context menu + QModelIndexList selectedRows = selectionModel()->selectedRows(); QMenu menu (this); /// \todo add menu items for select all and clear selection @@ -375,16 +361,12 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id, connect (mPreviewAction, SIGNAL (triggered()), this, SLOT (previewRecord())); addAction (mPreviewAction); - /// \todo add a user option, that redirects the extended action to an input panel (in - /// the bottom bar) that lets the user select which record collections should be - /// modified. - mExtendedDeleteAction = new QAction (tr ("Extended Delete Record"), this); - connect (mExtendedDeleteAction, SIGNAL (triggered()), mDispatcher, SLOT (executeExtendedDelete())); + connect (mExtendedDeleteAction, SIGNAL (triggered()), this, SLOT (executeExtendedDelete())); addAction (mExtendedDeleteAction); mExtendedRevertAction = new QAction (tr ("Extended Revert Record"), this); - connect (mExtendedRevertAction, SIGNAL (triggered()), mDispatcher, SLOT (executeExtendedRevert())); + connect (mExtendedRevertAction, SIGNAL (triggered()), this, SLOT (executeExtendedRevert())); addAction (mExtendedRevertAction); connect (mProxyModel, SIGNAL (rowsRemoved (const QModelIndex&, int, int)), @@ -430,6 +412,22 @@ CSMWorld::UniversalId CSVWorld::Table::getUniversalId (int row) const mModel->data (mModel->index (row, idColumn)).toString().toUtf8().constData()); } +std::vector CSVWorld::Table::getSelectedIds() const +{ + std::vector ids; + QModelIndexList selectedRows = selectionModel()->selectedRows(); + int columnIndex = mModel->findColumnIndex (CSMWorld::Columns::ColumnId_Id); + + for (QModelIndexList::const_iterator iter (selectedRows.begin()); + iter != selectedRows.end(); + ++iter) + { + int row = mProxyModel->mapToSource (mProxyModel->index (iter->row(), 0)).row(); + ids.push_back (mModel->data (mModel->index (row, columnIndex)).toString().toUtf8().constData()); + } + return ids; +} + void CSVWorld::Table::editRecord() { if (!mEditLock || (mModel->getFeatures() & CSMWorld::IdTableBase::Feature_Constant)) @@ -562,6 +560,34 @@ void CSVWorld::Table::previewRecord() } } +void CSVWorld::Table::executeExtendedDelete() +{ + CSMSettings::UserSettings &settings = CSMSettings::UserSettings::instance(); + QString configSetting = settings.settingValue ("table-input/extended-config"); + if (configSetting == "true") + { + emit extendedDeleteConfigRequest(getSelectedIds()); + } + else + { + QMetaObject::invokeMethod(mDispatcher, "executeExtendedDelete", Qt::QueuedConnection); + } +} + +void CSVWorld::Table::executeExtendedRevert() +{ + CSMSettings::UserSettings &settings = CSMSettings::UserSettings::instance(); + QString configSetting = settings.settingValue ("table-input/extended-config"); + if (configSetting == "true") + { + emit extendedRevertConfigRequest(getSelectedIds()); + } + else + { + QMetaObject::invokeMethod(mDispatcher, "executeExtendedRevert", Qt::QueuedConnection); + } +} + void CSVWorld::Table::updateUserSetting (const QString &name, const QStringList &list) { if (name=="table-input/jump-to-added") diff --git a/apps/opencs/view/world/table.hpp b/apps/opencs/view/world/table.hpp index 38fcd83bd..7efc3ad34 100644 --- a/apps/opencs/view/world/table.hpp +++ b/apps/opencs/view/world/table.hpp @@ -93,6 +93,8 @@ namespace CSVWorld std::vector getColumnsWithDisplay(CSMWorld::ColumnBase::Display display) const; + std::vector getSelectedIds() const; + virtual std::vector getDraggedRecords() const; signals: @@ -112,6 +114,10 @@ namespace CSVWorld void closeRequest(); + void extendedDeleteConfigRequest(const std::vector &selectedIds); + + void extendedRevertConfigRequest(const std::vector &selectedIds); + private slots: void editCell(); @@ -128,6 +134,10 @@ namespace CSVWorld void previewRecord(); + void executeExtendedDelete(); + + void executeExtendedRevert(); + public slots: void tableSizeUpdate(); diff --git a/apps/opencs/view/world/tablebottombox.cpp b/apps/opencs/view/world/tablebottombox.cpp index eab6b07b3..bfd56b326 100644 --- a/apps/opencs/view/world/tablebottombox.cpp +++ b/apps/opencs/view/world/tablebottombox.cpp @@ -39,9 +39,10 @@ void CSVWorld::TableBottomBox::updateStatus() } } -void CSVWorld::TableBottomBox::extendedConfigRequest(CSVWorld::ExtendedCommandConfigurator::Mode mode) +void CSVWorld::TableBottomBox::extendedConfigRequest(CSVWorld::ExtendedCommandConfigurator::Mode mode, + const std::vector &selectedIds) { - mExtendedConfigurator->configure (mode); + mExtendedConfigurator->configure (mode, selectedIds); mLayout->setCurrentWidget (mExtendedConfigurator); mEditMode = EditMode_ExtendedConfig; setVisible (true); @@ -185,12 +186,12 @@ void CSVWorld::TableBottomBox::cloneRequest(const std::string& id, mCreator->focus(); } -void CSVWorld::TableBottomBox::extendedDeleteConfigRequest() +void CSVWorld::TableBottomBox::extendedDeleteConfigRequest(const std::vector &selectedIds) { - extendedConfigRequest(ExtendedCommandConfigurator::Mode_Delete); + extendedConfigRequest(ExtendedCommandConfigurator::Mode_Delete, selectedIds); } -void CSVWorld::TableBottomBox::extendedRevertConfigRequest() +void CSVWorld::TableBottomBox::extendedRevertConfigRequest(const std::vector &selectedIds) { - extendedConfigRequest(ExtendedCommandConfigurator::Mode_Revert); + extendedConfigRequest(ExtendedCommandConfigurator::Mode_Revert, selectedIds); } diff --git a/apps/opencs/view/world/tablebottombox.hpp b/apps/opencs/view/world/tablebottombox.hpp index d2fb865e7..fded912fe 100644 --- a/apps/opencs/view/world/tablebottombox.hpp +++ b/apps/opencs/view/world/tablebottombox.hpp @@ -45,7 +45,8 @@ namespace CSVWorld void updateStatus(); - void extendedConfigRequest(ExtendedCommandConfigurator::Mode mode); + void extendedConfigRequest(ExtendedCommandConfigurator::Mode mode, + const std::vector &selectedIds); public: @@ -89,8 +90,8 @@ namespace CSVWorld void cloneRequest(const std::string& id, const CSMWorld::UniversalId::Type type); - void extendedDeleteConfigRequest(); - void extendedRevertConfigRequest(); + void extendedDeleteConfigRequest(const std::vector &selectedIds); + void extendedRevertConfigRequest(const std::vector &selectedIds); }; } diff --git a/apps/opencs/view/world/tablesubview.cpp b/apps/opencs/view/world/tablesubview.cpp index 75671a50c..abae6115a 100644 --- a/apps/opencs/view/world/tablesubview.cpp +++ b/apps/opencs/view/world/tablesubview.cpp @@ -71,6 +71,11 @@ CSVWorld::TableSubView::TableSubView (const CSMWorld::UniversalId& id, CSMDoc::D connect (this, SIGNAL(cloneRequest(const std::string&, const CSMWorld::UniversalId::Type)), mBottom, SLOT(cloneRequest(const std::string&, const CSMWorld::UniversalId::Type))); + + connect (mTable, SIGNAL(extendedDeleteConfigRequest(const std::vector &)), + mBottom, SLOT(extendedDeleteConfigRequest(const std::vector &))); + connect (mTable, SIGNAL(extendedRevertConfigRequest(const std::vector &)), + mBottom, SLOT(extendedRevertConfigRequest(const std::vector &))); } connect (mBottom, SIGNAL (requestFocus (const std::string&)), mTable, SLOT (requestFocus (const std::string&))); From dcb8fbc69ce0948dda528731f7026b872f62c583 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 1 Jul 2015 03:21:39 +0200 Subject: [PATCH 1705/3725] Accurate handling of fog depth/density (Fixes #2752) --- apps/openmw/mwrender/renderingmanager.cpp | 17 ++++++++++++++--- apps/openmw/mwrender/renderingmanager.hpp | 1 + 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index d85c1c006..c861119b5 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -46,7 +46,8 @@ namespace MWRender { public: StateUpdater() - : mFogEnd(0.f) + : mFogStart(0.f) + , mFogEnd(0.f) , mWireframe(false) { } @@ -56,7 +57,6 @@ namespace MWRender osg::LightModel* lightModel = new osg::LightModel; stateset->setAttribute(lightModel, osg::StateAttribute::ON); osg::Fog* fog = new osg::Fog; - fog->setStart(1); fog->setMode(osg::Fog::LINEAR); stateset->setAttributeAndModes(fog, osg::StateAttribute::ON); if (mWireframe) @@ -75,6 +75,7 @@ namespace MWRender lightModel->setAmbientIntensity(mAmbientColor); osg::Fog* fog = static_cast(stateset->getAttribute(osg::StateAttribute::FOG)); fog->setColor(mFogColor); + fog->setStart(mFogStart); fog->setEnd(mFogEnd); } @@ -88,6 +89,11 @@ namespace MWRender mFogColor = col; } + void setFogStart(float start) + { + mFogStart = start; + } + void setFogEnd(float end) { mFogEnd = end; @@ -110,6 +116,7 @@ namespace MWRender private: osg::Vec4f mAmbientColor; osg::Vec4f mFogColor; + float mFogStart; float mFogEnd; bool mWireframe; }; @@ -118,6 +125,7 @@ namespace MWRender : mViewer(viewer) , mRootNode(rootNode) , mResourceSystem(resourceSystem) + , mFogDepth(0.f) , mNightEyeFactor(0.f) { osg::ref_ptr lightRoot = new SceneUtil::LightManager; @@ -338,8 +346,9 @@ namespace MWRender configureFog (cell->mAmbi.mFogDensity, color); } - void RenderingManager::configureFog(float /* fogDepth */, const osg::Vec4f &color) + void RenderingManager::configureFog(float fogDepth, const osg::Vec4f &color) { + mFogDepth = fogDepth; mFogColor = color; } @@ -364,11 +373,13 @@ namespace MWRender if (mWater->isUnderwater(cameraPos)) { setFogColor(osg::Vec4f(0.090195f, 0.115685f, 0.12745f, 1.f)); + mStateUpdater->setFogStart(0.f); mStateUpdater->setFogEnd(1000); } else { setFogColor(mFogColor); + mStateUpdater->setFogStart(mViewDistance * (1 - mFogDepth)); mStateUpdater->setFogEnd(mViewDistance); } } diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index fc2f5a4f3..def3ea4bb 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -190,6 +190,7 @@ namespace MWRender osg::ref_ptr mStateUpdater; + float mFogDepth; osg::Vec4f mFogColor; osg::Vec4f mAmbientColor; From bf9c62fa4224722edcc222184e66afe13f7568f6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 1 Jul 2015 03:42:04 +0200 Subject: [PATCH 1706/3725] Fix for some coverity scan defects --- apps/openmw/mwgui/mapwindow.hpp | 5 +++++ apps/openmw/mwrender/globalmap.hpp | 3 ++- apps/openmw/mwrender/ripplesimulation.hpp | 4 ---- apps/openmw/mwrender/sky.cpp | 9 ++++++--- components/myguiplatform/myguirendermanager.cpp | 2 ++ components/nifosg/controller.cpp | 2 ++ components/nifosg/particle.cpp | 2 +- 7 files changed, 18 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwgui/mapwindow.hpp b/apps/openmw/mwgui/mapwindow.hpp index bea3d33b9..388103b5d 100644 --- a/apps/openmw/mwgui/mapwindow.hpp +++ b/apps/openmw/mwgui/mapwindow.hpp @@ -72,6 +72,11 @@ namespace MWGui { MarkerUserData(MWRender::LocalMap* map) : mLocalMapRender(map) + , interior(false) + , cellX(0) + , cellY(0) + , nX(0.f) + , nY(0.f) { } diff --git a/apps/openmw/mwrender/globalmap.hpp b/apps/openmw/mwrender/globalmap.hpp index 7adb8218a..91c17c06f 100644 --- a/apps/openmw/mwrender/globalmap.hpp +++ b/apps/openmw/mwrender/globalmap.hpp @@ -88,7 +88,8 @@ namespace MWRender struct ImageDest { ImageDest() - : mFramesUntilDone(3) // wait an extra frame to ensure the draw thread has completed its frame. + : mX(0), mY(0) + , mFramesUntilDone(3) // wait an extra frame to ensure the draw thread has completed its frame. { } diff --git a/apps/openmw/mwrender/ripplesimulation.hpp b/apps/openmw/mwrender/ripplesimulation.hpp index 98c8a707d..8e591a5db 100644 --- a/apps/openmw/mwrender/ripplesimulation.hpp +++ b/apps/openmw/mwrender/ripplesimulation.hpp @@ -65,10 +65,6 @@ namespace MWRender osg::ref_ptr mParticleNode; std::vector mEmitters; - - float mRippleLifeTime; - float mRippleRotSpeed; - }; } diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index dc43783ff..db7e5462e 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -162,6 +162,12 @@ protected: class CloudUpdater : public SceneUtil::StateSetUpdater { public: + CloudUpdater() + : mAnimationTimer(0.f) + , mOpacity(0.f) + { + } + void setAnimationTimer(float timer) { mAnimationTimer = timer; @@ -762,9 +768,6 @@ public: mat->setColorMode(osg::Material::OFF); stateset->setAttributeAndModes(mat, osg::StateAttribute::ON); } - -private: - float mAlpha; }; void SkyManager::createRain() diff --git a/components/myguiplatform/myguirendermanager.cpp b/components/myguiplatform/myguirendermanager.cpp index 773c58a59..4979d6451 100644 --- a/components/myguiplatform/myguirendermanager.cpp +++ b/components/myguiplatform/myguirendermanager.cpp @@ -165,6 +165,8 @@ public: Drawable(const Drawable ©, const osg::CopyOp ©op=osg::CopyOp::SHALLOW_COPY) : osg::Drawable(copy, copyop) , mParent(copy.mParent) + , mWriteTo(0) + , mReadFrom(0) { } diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index a314910c5..5e7e55004 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -407,6 +407,7 @@ FlipController::FlipController(int texSlot, float delta, std::vectorgetNodePath(); path.pop_back(); - osg::MatrixTransform* trans = dynamic_cast(node); + osg::MatrixTransform* trans = static_cast(node); osg::Matrix mat = osg::computeLocalToWorld( path ); mat.orthoNormalize(mat); // don't undo the scale From 631cec7304d0a87bfb980aed1577648f9a6cf65b Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 2 Jul 2015 17:19:07 +0200 Subject: [PATCH 1707/3725] Take the radius of lights into account when sorting --- components/sceneutil/lightmanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/sceneutil/lightmanager.cpp b/components/sceneutil/lightmanager.cpp index bcdb4af88..039d556d1 100644 --- a/components/sceneutil/lightmanager.cpp +++ b/components/sceneutil/lightmanager.cpp @@ -244,7 +244,7 @@ namespace SceneUtil bool sortLights (const LightManager::LightSourceTransform* left, const LightManager::LightSourceTransform* right) { - return left->mViewBound.center().length2() < right->mViewBound.center().length2(); + return left->mViewBound.center().length2() - left->mViewBound.radius2()/4.f < right->mViewBound.center().length2() - right->mViewBound.radius2()/4.f; } void LightListCallback::operator()(osg::Node *node, osg::NodeVisitor *nv) From 672458577777ed9400f6668889c0dea00d2c4220 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 2 Jul 2015 17:19:30 +0200 Subject: [PATCH 1708/3725] Light magic effect Notable change compared to the old (Ogre) effect: uses the ambient instead of diffuse term (Fixes #2364) --- apps/openmw/mwrender/animation.cpp | 32 ++++++++++++++++++++++++++++++ apps/openmw/mwrender/animation.hpp | 9 ++++++++- 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 5955fc4cf..91f459ff2 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -267,6 +267,8 @@ namespace MWRender Animation::~Animation() { + setLightEffect(0.f); + if (mObjectRoot) mInsert->removeChild(mObjectRoot); } @@ -1224,6 +1226,36 @@ namespace MWRender return found->second; } + void Animation::setLightEffect(float effect) + { + if (effect == 0) + { + if (mGlowLight) + { + mInsert->removeChild(mGlowLight); + mGlowLight = NULL; + } + } + else + { + if (!mGlowLight) + { + mGlowLight = new SceneUtil::LightSource; + mGlowLight->setLight(new osg::Light); + osg::Light* light = mGlowLight->getLight(); + light->setDiffuse(osg::Vec4f(0,0,0,0)); + light->setSpecular(osg::Vec4f(0,0,0,0)); + light->setAmbient(osg::Vec4f(1.5f,1.5f,1.5f,1.f)); + mInsert->addChild(mGlowLight); + } + + effect += 3; + osg::Light* light = mGlowLight->getLight(); + mGlowLight->setRadius(effect * 66.f); + light->setLinearAttenuation(0.5f/effect); + } + } + void Animation::addControllers() { mHeadController = NULL; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 73079e9a9..d23a62954 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -21,6 +21,11 @@ namespace NifOsg class KeyframeController; } +namespace SceneUtil +{ + class LightSource; +} + namespace MWRender { @@ -202,6 +207,8 @@ protected: float mHeadYawRadians; float mHeadPitchRadians; + osg::ref_ptr mGlowLight; + /* Sets the appropriate animations on the bone groups based on priority. */ void resetActiveGroups(); @@ -377,7 +384,7 @@ public: // TODO: move outside of this class /// Makes this object glow, by placing a Light in its center. /// @param effect Controls the radius and intensity of the light. - virtual void setLightEffect(float effect) {} + virtual void setLightEffect(float effect); virtual void setHeadPitch(float pitchRadians); virtual void setHeadYaw(float yawRadians); From 12bf3694bdd5320dcc843a82b75d244e0e9ed975 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Thu, 2 Jul 2015 22:05:45 +0300 Subject: [PATCH 1709/3725] Rework widget layout of ExtendedCommandConfigurator --- .../world/extendedcommandconfigurator.cpp | 36 ++++++++----------- .../world/extendedcommandconfigurator.hpp | 4 +-- 2 files changed, 16 insertions(+), 24 deletions(-) diff --git a/apps/opencs/view/world/extendedcommandconfigurator.cpp b/apps/opencs/view/world/extendedcommandconfigurator.cpp index 6ba26634b..9f067545c 100644 --- a/apps/opencs/view/world/extendedcommandconfigurator.cpp +++ b/apps/opencs/view/world/extendedcommandconfigurator.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include "../../model/world/commanddispatcher.hpp" @@ -39,10 +40,8 @@ CSVWorld::ExtendedCommandConfigurator::ExtendedCommandConfigurator(CSMDoc::Docum mCancelButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); connect(mCancelButton, SIGNAL(clicked(bool)), this, SIGNAL(done())); - mButtonLayout = new QHBoxLayout(); - mButtonLayout->setAlignment(Qt::AlignCenter); - mButtonLayout->addWidget(mPerformButton); - mButtonLayout->addWidget(mCancelButton); + mCommandTitle = new QLabel(this); + mCommandTitle->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); mTypeGroup = new QGroupBox(this); @@ -50,15 +49,12 @@ CSVWorld::ExtendedCommandConfigurator::ExtendedCommandConfigurator(CSMDoc::Docum groupLayout->setAlignment(Qt::AlignCenter); mTypeGroup->setLayout(groupLayout); - QVBoxLayout *mainLayout = new QVBoxLayout(this); + QHBoxLayout *mainLayout = new QHBoxLayout(this); mainLayout->setSizeConstraint(QLayout::SetNoConstraint); + mainLayout->addWidget(mCommandTitle); mainLayout->addWidget(mTypeGroup); - mainLayout->addLayout(mButtonLayout); -} - -CSVWorld::ExtendedCommandConfigurator::~ExtendedCommandConfigurator() -{ - delete mButtonLayout; + mainLayout->addWidget(mPerformButton); + mainLayout->addWidget(mCancelButton); } void CSVWorld::ExtendedCommandConfigurator::configure(CSVWorld::ExtendedCommandConfigurator::Mode mode, @@ -67,7 +63,9 @@ void CSVWorld::ExtendedCommandConfigurator::configure(CSVWorld::ExtendedCommandC mMode = mode; if (mMode != Mode_None) { - mTypeGroup->setTitle(getTypeGroupTitle(mMode)); + QString title = (mMode == Mode_Delete) ? "Extended Delete" : "Extended Revert"; + title.append(" from:"); + mCommandTitle->setText(title); mCommandDispatcher->setSelection(selectedIds); setupCheckBoxes(mCommandDispatcher->getExtendedTypes()); setupGroupLayout(); @@ -90,12 +88,6 @@ void CSVWorld::ExtendedCommandConfigurator::setupGroupLayout() int groupWidth = mTypeGroup->geometry().width(); QGridLayout *layout = qobject_cast(mTypeGroup->layout()); - // One row of checkboxes with enough space - the setup is over - if (mNumUsedCheckBoxes > 0 && layout->rowCount() == 1 && groupWidth >= mTypeGroup->sizeHint().width()) - { - return; - } - // Find the optimal number of rows to place the checkboxes within the available space int divider = 1; do @@ -111,7 +103,7 @@ void CSVWorld::ExtendedCommandConfigurator::setupGroupLayout() CheckBoxMap::const_iterator end = mTypeCheckBoxes.end(); for (; current != end; ++current) { - if (current->first->isVisible()) + if (counter < mNumUsedCheckBoxes) { int row = counter / itemsPerRow; int column = counter - (counter / itemsPerRow) * itemsPerRow; @@ -121,7 +113,7 @@ void CSVWorld::ExtendedCommandConfigurator::setupGroupLayout() } divider *= 2; } - while (groupWidth < mTypeGroup->sizeHint().width()); + while (groupWidth < mTypeGroup->sizeHint().width() && divider <= mNumUsedCheckBoxes); } void CSVWorld::ExtendedCommandConfigurator::setupCheckBoxes(const std::vector &types) @@ -133,7 +125,7 @@ void CSVWorld::ExtendedCommandConfigurator::setupCheckBoxes(const std::vector 0; --i) { - mTypeCheckBoxes.insert(std::make_pair(new QCheckBox(this), CSMWorld::UniversalId::Type_None)); + mTypeCheckBoxes.insert(std::make_pair(new QCheckBox(mTypeGroup), CSMWorld::UniversalId::Type_None)); } } @@ -156,7 +148,7 @@ void CSVWorld::ExtendedCommandConfigurator::setupCheckBoxes(const std::vectorfirst->hide(); } } - mNumUsedCheckBoxes = counter - 1; + mNumUsedCheckBoxes = numTypes; } void CSVWorld::ExtendedCommandConfigurator::performExtendedCommand() diff --git a/apps/opencs/view/world/extendedcommandconfigurator.hpp b/apps/opencs/view/world/extendedcommandconfigurator.hpp index dd2477444..8efe36fa7 100644 --- a/apps/opencs/view/world/extendedcommandconfigurator.hpp +++ b/apps/opencs/view/world/extendedcommandconfigurator.hpp @@ -8,6 +8,7 @@ class QPushButton; class QGroupBox; class QCheckBox; +class QLabel; class QHBoxLayout; namespace CSMDoc @@ -35,7 +36,7 @@ namespace CSVWorld QPushButton *mPerformButton; QPushButton *mCancelButton; - QHBoxLayout *mButtonLayout; + QLabel *mCommandTitle; QGroupBox *mTypeGroup; CheckBoxMap mTypeCheckBoxes; int mNumUsedCheckBoxes; @@ -50,7 +51,6 @@ namespace CSVWorld ExtendedCommandConfigurator(CSMDoc::Document &document, const CSMWorld::UniversalId &id, QWidget *parent = 0); - virtual ~ExtendedCommandConfigurator(); void configure(Mode mode, const std::vector &selectedIds); From 520a832a9a7072b8bf306d94bc9b1d1666e615d2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 2 Jul 2015 22:24:23 +0200 Subject: [PATCH 1710/3725] Remove an already resolved todo comment --- apps/openmw/mwmechanics/aicombat.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 35d1f5376..88d4167ab 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -333,9 +333,6 @@ namespace MWMechanics // Get weapon characteristics if (actorClass.hasInventoryStore(actor)) { - // TODO: Check equipped weapon and equip a different one if we can't attack with it - // (e.g. no ammunition, or wrong type of ammunition equipped, etc. autoEquip is not very smart in this regard)) - //Get weapon speed and range MWWorld::ContainerStoreIterator weaponSlot = MWMechanics::getActiveWeapon(actorClass.getCreatureStats(actor), actorClass.getInventoryStore(actor), &weaptype); From d07b176b368ac0fd7df95c3240e27b97b6a13813 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 2 Jul 2015 22:25:19 +0200 Subject: [PATCH 1711/3725] Take into account hit recovery, knockdown and other animations for AiCombat attack timing --- apps/openmw/mwmechanics/aicombat.cpp | 10 +--------- apps/openmw/mwmechanics/character.cpp | 5 +++++ apps/openmw/mwmechanics/character.hpp | 2 ++ 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 88d4167ab..d8b2dc9ac 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -300,10 +300,6 @@ namespace MWMechanics currentCell = actor.getCell(); } - MWRender::Animation* anim = MWBase::Environment::get().getWorld()->getAnimation(actor); - if (!anim) // shouldn't happen - return false; - actorClass.getCreatureStats(actor).setMovementFlag(CreatureStats::Flag_Run, true); if (actionCooldown > 0) @@ -312,11 +308,7 @@ namespace MWMechanics float rangeAttack = 0; float rangeFollow = 0; boost::shared_ptr& currentAction = storage.mCurrentAction; - // TODO: upperBodyReady() works fine for checking if we can start an attack, - // but doesn't work properly for checking if the attack is finished (as things like hit recovery or knockdown also play on the upper body) - // Only a minor problem, but can mess with the actionCooldown timer. - // To fix this the AI needs to be brought closer to the CharacterController, so we can simply check if a weapon animation is playing. - if (anim->upperBodyReady()) + if (characterController.readyToPrepareAttack()) { currentAction = prepareNextAction(actor, target); actionCooldown = currentAction->getActionCooldown(); diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index a3d69c059..ec1e0e81b 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -2047,6 +2047,11 @@ void CharacterController::setAttackingOrSpell(bool attackingOrSpell) mAttackingOrSpell = attackingOrSpell; } +bool CharacterController::readyToPrepareAttack() const +{ + return mHitState == CharState_None && mUpperBodyState <= UpperCharState_WeapEquiped; +} + void CharacterController::setActive(bool active) { mAnimation->setActive(active); diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 0a8771fb4..6a5e0593d 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -240,6 +240,8 @@ public: void setAttackingOrSpell(bool attackingOrSpell); + bool readyToPrepareAttack() const; + /// @see Animation::setActive void setActive(bool active); From 82740c164501a629ec08213cad2c49b52a919b33 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 3 Jul 2015 02:29:42 +0200 Subject: [PATCH 1712/3725] Remove completely broken code --- apps/openmw/mwmechanics/aicombat.cpp | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index d8b2dc9ac..85a88e546 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -640,24 +640,6 @@ namespace MWMechanics } } - // TODO: Add a parameter to vary DURATION_SAME_SPOT? - if((distToTarget > rangeAttack || followTarget) && - mObstacleCheck.check(actor, tReaction)) // check if evasive action needed - { - // probably walking into another NPC TODO: untested in combat situation - // TODO: diagonal should have same animation as walk forward - // but doesn't seem to do that? - actor.getClass().getMovementSettings(actor).mPosition[0] = 1; - actor.getClass().getMovementSettings(actor).mPosition[1] = 0.1f; - // change the angle a bit, too - if(mPathFinder.isPathConstructed()) - zTurn(actor, osg::DegreesToRadians(mPathFinder.getZAngleToNext(pos.pos[0] + 1, pos.pos[1]))); - - if(followTarget) - followTarget = false; - // FIXME: can fool actors to stay behind doors, etc. - // Related to Bug#1102 and to some degree #1155 as well - } return false; } From 2385938485a1e4638151df2d0fd52515cf9e0b41 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 3 Jul 2015 02:42:40 +0200 Subject: [PATCH 1713/3725] Fix a typo --- apps/opencs/model/world/columns.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index d6e27caeb..7aec68309 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -92,7 +92,7 @@ namespace CSMWorld { ColumnId_Trainer, "Trainer" }, { ColumnId_Spellmaking, "Spellmaking" }, { ColumnId_EnchantingService, "Enchanting Service" }, - { ColumnId_RepairService, "Repair Serivce" }, + { ColumnId_RepairService, "Repair Service" }, { ColumnId_ApparatusType, "Apparatus Type" }, { ColumnId_ArmorType, "Armor Type" }, { ColumnId_Health, "Health" }, From 741e5db862d23f845dd93b96605093055b31f236 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 3 Jul 2015 05:37:18 +0200 Subject: [PATCH 1714/3725] Fix for non-bipedal creatures that use weapons, e.g. rieklings --- apps/openmw/mwmechanics/character.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index ec1e0e81b..cf963e8aa 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1789,7 +1789,8 @@ void CharacterController::update(float duration) } } - if(cls.isBipedal(mPtr)) + // bipedal means hand-to-hand could be used (which is handled in updateWeaponState). an existing InventoryStore means an actual weapon could be used. + if(cls.isBipedal(mPtr) || cls.hasInventoryStore(mPtr)) forcestateupdate = updateWeaponState() || forcestateupdate; else forcestateupdate = updateCreatureState() || forcestateupdate; From a7bd050928b746386d5ba35425eb0d1c040a4896 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 3 Jul 2015 05:58:12 +0200 Subject: [PATCH 1715/3725] Accurate attack timings in AiCombat --- apps/openmw/mwmechanics/aicombat.cpp | 169 +++----------------------- apps/openmw/mwmechanics/character.cpp | 18 +++ apps/openmw/mwmechanics/character.hpp | 4 +- 3 files changed, 36 insertions(+), 155 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 85a88e546..c0d2bc90d 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -31,8 +31,6 @@ namespace //chooses an attack depending on probability to avoid uniformity ESM::Weapon::AttackType chooseBestAttack(const ESM::Weapon* weapon, MWMechanics::Movement &movement); - void getMinMaxAttackDuration(const MWWorld::Ptr& actor, float (*fMinMaxDurations)[2]); - osg::Vec3f AimDirToMovingTarget(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, const osg::Vec3f& vLastTargetPos, float duration, int weapType, float strength); @@ -83,7 +81,6 @@ namespace MWMechanics /// \brief This class holds the variables AiCombat needs which are deleted if the package becomes inactive. struct AiCombatStorage : AiTemporaryBase { - float mTimerAttack; float mTimerReact; float mTimerCombatMove; bool mReadyToAttack; @@ -95,15 +92,12 @@ namespace MWMechanics boost::shared_ptr mCurrentAction; float mActionCooldown; float mStrength; - float mMinMaxAttackDuration[3][2]; - bool mMinMaxAttackDurationInitialised; bool mForceNoShortcut; ESM::Position mShortcutFailPos; osg::Vec3f mLastActorPos; MWMechanics::Movement mMovement; AiCombatStorage(): - mTimerAttack(0), mTimerReact(0), mTimerCombatMove(0), mReadyToAttack(false), @@ -115,7 +109,6 @@ namespace MWMechanics mCurrentAction(), mActionCooldown(0), mStrength(), - mMinMaxAttackDurationInitialised(false), mForceNoShortcut(false), mLastActorPos(0,0,0), mMovement(){} @@ -233,41 +226,12 @@ namespace MWMechanics { if(smoothTurn(actor, osg::DegreesToRadians(movement.mRotation[0]), 0)) movement.mRotation[0] = 0; } - - float attacksPeriod = 1.0f; - - ESM::Weapon::AttackType attackType; - - - bool& attack = storage.mAttack; bool& readyToAttack = storage.mReadyToAttack; - float& timerAttack = storage.mTimerAttack; - - bool& minMaxAttackDurationInitialised = storage.mMinMaxAttackDurationInitialised; - float (&minMaxAttackDuration)[3][2] = storage.mMinMaxAttackDuration; - - if(readyToAttack) - { - - if (!minMaxAttackDurationInitialised) - { - // TODO: this must be updated when a different weapon is equipped - // TODO: it would be much easier to ask the CharacterController about the current % completion of the weapon wind-up animation - getMinMaxAttackDuration(actor, minMaxAttackDuration); - minMaxAttackDurationInitialised = true; - } - if (timerAttack < 0) attack = false; - - timerAttack -= duration; - } - else - { - timerAttack = -attacksPeriod; + if (attack && (characterController.getAttackStrength() >= storage.mStrength || characterController.readyToPrepareAttack())) attack = false; - } characterController.setAttackingOrSpell(attack); @@ -372,32 +336,26 @@ namespace MWMechanics } - float& strength = storage.mStrength; + float& strength = storage.mStrength; // start new attack - if(readyToAttack) + if(readyToAttack && characterController.readyToStartAttack()) { - if(timerAttack <= -attacksPeriod) - { - attack = true; // attack starts just now - - if (!distantCombat) attackType = chooseBestAttack(weapon, movement); - else attackType = ESM::Weapon::AT_Chop; // cause it's =0 + attack = true; // attack starts just now + characterController.setAttackingOrSpell(attack); - strength = Misc::Rng::rollClosedProbability(); + if (!distantCombat) + chooseBestAttack(weapon, movement); - // Note: may be 0 for some animations - timerAttack = minMaxAttackDuration[attackType][0] + - (minMaxAttackDuration[attackType][1] - minMaxAttackDuration[attackType][0]) * strength; + strength = Misc::Rng::rollClosedProbability(); - //say a provoking combat phrase - if (actor.getClass().isNpc()) + //say a provoking combat phrase + if (actor.getClass().isNpc()) + { + const MWWorld::ESMStore &store = world->getStore(); + int chance = store.get().find("iVoiceAttackOdds")->getInt(); + if (Misc::Rng::roll0to99() < chance) { - const MWWorld::ESMStore &store = world->getStore(); - int chance = store.get().find("iVoiceAttackOdds")->getInt(); - if (Misc::Rng::roll0to99() < chance) - { - MWBase::Environment::get().getDialogueManager()->say(actor, "attack"); - } + MWBase::Environment::get().getDialogueManager()->say(actor, "attack"); } } } @@ -607,39 +565,6 @@ namespace MWMechanics readyToAttack = false; } - if(!isStuck && distToTarget > rangeAttack && !distantCombat) - { - //special run attack; it shouldn't affect melee combat tactics - if(actorClass.getMovementSettings(actor).mPosition[1] == 1) - { - /* check if actor can overcome the distance = distToTarget - attackerWeapRange - less than in time of swinging with weapon (t_swing), then start attacking - */ - float speed1 = actorClass.getSpeed(actor); - float speed2 = target.getClass().getSpeed(target); - if(target.getClass().getMovementSettings(target).mPosition[0] == 0 - && target.getClass().getMovementSettings(target).mPosition[1] == 0) - speed2 = 0; - - float s1 = distToTarget - weapRange; - float t = s1/speed1; - float s2 = speed2 * t; - float t_swing = - minMaxAttackDuration[ESM::Weapon::AT_Thrust][0] + - (minMaxAttackDuration[ESM::Weapon::AT_Thrust][1] - minMaxAttackDuration[ESM::Weapon::AT_Thrust][0]) * Misc::Rng::rollClosedProbability(); - - if (t + s2/speed1 <= t_swing) - { - readyToAttack = true; - if(timerAttack <= -attacksPeriod) - { - timerAttack = t_swing; - attack = true; - } - } - } - } - return false; } @@ -765,70 +690,6 @@ ESM::Weapon::AttackType chooseBestAttack(const ESM::Weapon* weapon, MWMechanics: return attackType; } -void getMinMaxAttackDuration(const MWWorld::Ptr& actor, float (*fMinMaxDurations)[2]) -{ - if (!actor.getClass().hasInventoryStore(actor)) // creatures - { - fMinMaxDurations[0][0] = fMinMaxDurations[0][1] = 0.1f; - fMinMaxDurations[1][0] = fMinMaxDurations[1][1] = 0.1f; - fMinMaxDurations[2][0] = fMinMaxDurations[2][1] = 0.1f; - - return; - } - - // get weapon information: type and speed - const ESM::Weapon *weapon = NULL; - MWMechanics::WeaponType weaptype = MWMechanics::WeapType_None; - - MWWorld::ContainerStoreIterator weaponSlot = - MWMechanics::getActiveWeapon(actor.getClass().getCreatureStats(actor), actor.getClass().getInventoryStore(actor), &weaptype); - - float weapSpeed; - if (weaptype != MWMechanics::WeapType_HandToHand - && weaptype != MWMechanics::WeapType_Spell - && weaptype != MWMechanics::WeapType_None) - { - weapon = weaponSlot->get()->mBase; - weapSpeed = weapon->mData.mSpeed; - } - else weapSpeed = 1.0f; - - MWRender::Animation *anim = MWBase::Environment::get().getWorld()->getAnimation(actor); - - std::string weapGroup; - MWMechanics::getWeaponGroup(weaptype, weapGroup); - weapGroup = weapGroup + ": "; - - bool bRangedWeap = (weaptype >= MWMechanics::WeapType_BowAndArrow && weaptype <= MWMechanics::WeapType_Thrown); - - const char *attackType[] = {"chop ", "slash ", "thrust ", "shoot "}; - - std::string textKey = "start"; - std::string textKey2; - - // get durations for each attack type - for (int i = 0; i < (bRangedWeap ? 1 : 3); i++) - { - float start1 = anim->getTextKeyTime(weapGroup + (bRangedWeap ? attackType[3] : attackType[i]) + textKey); - - if (start1 < 0) - { - fMinMaxDurations[i][0] = fMinMaxDurations[i][1] = 0.1f; - continue; - } - - textKey2 = "min attack"; - float start2 = anim->getTextKeyTime(weapGroup + (bRangedWeap ? attackType[3] : attackType[i]) + textKey2); - - fMinMaxDurations[i][0] = (start2 - start1) / weapSpeed; - - textKey2 = "max attack"; - start1 = anim->getTextKeyTime(weapGroup + (bRangedWeap ? attackType[3] : attackType[i]) + textKey2); - - fMinMaxDurations[i][1] = fMinMaxDurations[i][0] + (start1 - start2) / weapSpeed; - } -} - osg::Vec3f AimDirToMovingTarget(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, const osg::Vec3f& vLastTargetPos, float duration, int weapType, float strength) { diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index cf963e8aa..4b2ce9f4c 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1259,6 +1259,8 @@ bool CharacterController::updateWeaponState() } animPlaying = mAnimation->getInfo(mCurrentWeapon, &complete); + if(mUpperBodyState == UpperCharState_MinAttackToMaxAttack && mHitState != CharState_KnockDown) + mAttackStrength = complete; } else { @@ -2053,6 +2055,22 @@ bool CharacterController::readyToPrepareAttack() const return mHitState == CharState_None && mUpperBodyState <= UpperCharState_WeapEquiped; } +bool CharacterController::readyToStartAttack() const +{ + if (mHitState != CharState_None) + return false; + + if (mPtr.getClass().hasInventoryStore(mPtr) || mPtr.getClass().isBipedal(mPtr)) + return mUpperBodyState == UpperCharState_WeapEquiped; + else + return mUpperBodyState == UpperCharState_Nothing; +} + +float CharacterController::getAttackStrength() const +{ + return mAttackStrength; +} + void CharacterController::setActive(bool active) { mAnimation->setActive(active); diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 6a5e0593d..b239b4a92 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -241,6 +241,9 @@ public: void setAttackingOrSpell(bool attackingOrSpell); bool readyToPrepareAttack() const; + bool readyToStartAttack() const; + + float getAttackStrength() const; /// @see Animation::setActive void setActive(bool active); @@ -249,7 +252,6 @@ public: void setHeadTrackTarget(const MWWorld::Ptr& target); }; - void getWeaponGroup(WeaponType weaptype, std::string &group); MWWorld::ContainerStoreIterator getActiveWeapon(CreatureStats &stats, MWWorld::InventoryStore &inv, WeaponType *weaptype); } From 382cdb8c60536a4808b08e3af294d965dfa8f71c Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 3 Jul 2015 10:45:08 +0200 Subject: [PATCH 1716/3725] implemented sorting in report views (Fixes #2540) --- apps/opencs/view/tools/reporttable.cpp | 59 ++++++++++++++++++-------- apps/opencs/view/tools/reporttable.hpp | 17 +++++--- 2 files changed, 52 insertions(+), 24 deletions(-) diff --git a/apps/opencs/view/tools/reporttable.cpp b/apps/opencs/view/tools/reporttable.cpp index ca6b0dabf..550c53969 100644 --- a/apps/opencs/view/tools/reporttable.cpp +++ b/apps/opencs/view/tools/reporttable.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include "../../model/tools/reportmodel.hpp" @@ -23,7 +24,7 @@ namespace CSVTools public: RichTextDelegate (QObject *parent = 0); - + virtual void paint(QPainter *painter, const QStyleOptionViewItem& option, const QModelIndex& index) const; }; @@ -63,7 +64,7 @@ void CSVTools::ReportTable::contextMenuEvent (QContextMenuEvent *event) for (QModelIndexList::const_iterator iter (selectedRows.begin()); iter!=selectedRows.end(); ++iter) { - QString hint = mModel->data (mModel->index (iter->row(), 2)).toString(); + QString hint = mProxyModel->data (mProxyModel->index (iter->row(), 2)).toString(); if (!hint.isEmpty() && hint[0]=='R') { @@ -78,7 +79,7 @@ void CSVTools::ReportTable::contextMenuEvent (QContextMenuEvent *event) if (mRefreshAction) menu.addAction (mRefreshAction); - + menu.exec (event->globalPos()); } @@ -106,14 +107,14 @@ void CSVTools::ReportTable::mouseDoubleClickEvent (QMouseEvent *event) event->accept(); return; } - + switch (iter->second) { case Action_None: event->accept(); break; - + case Action_Edit: event->accept(); @@ -152,7 +153,10 @@ CSVTools::ReportTable::ReportTable (CSMDoc::Document& document, setSelectionBehavior (QAbstractItemView::SelectRows); setSelectionMode (QAbstractItemView::ExtendedSelection); - setModel (mModel); + mProxyModel = new QSortFilterProxyModel (this); + mProxyModel->setSourceModel (mModel); + + setModel (mProxyModel); setColumnHidden (2, true); mIdTypeDelegate = CSVWorld::IdTypeDelegateFactory().makeDelegate (0, @@ -162,7 +166,7 @@ CSVTools::ReportTable::ReportTable (CSMDoc::Document& document, if (richTextDescription) setItemDelegateForColumn (mModel->columnCount()-1, new RichTextDelegate (this)); - + mShowAction = new QAction (tr ("Show"), this); connect (mShowAction, SIGNAL (triggered()), this, SLOT (showSelection())); addAction (mShowAction); @@ -182,10 +186,10 @@ CSVTools::ReportTable::ReportTable (CSMDoc::Document& document, connect (mRefreshAction, SIGNAL (triggered()), this, SIGNAL (refreshRequest())); addAction (mRefreshAction); } - + mDoubleClickActions.insert (std::make_pair (Qt::NoModifier, Action_Edit)); mDoubleClickActions.insert (std::make_pair (Qt::ShiftModifier, Action_Remove)); - mDoubleClickActions.insert (std::make_pair (Qt::ControlModifier, Action_EditAndRemove)); + mDoubleClickActions.insert (std::make_pair (Qt::ControlModifier, Action_EditAndRemove)); } std::vector CSVTools::ReportTable::getDraggedRecords() const @@ -197,7 +201,7 @@ std::vector CSVTools::ReportTable::getDraggedRecords() co for (QModelIndexList::const_iterator iter (selectedRows.begin()); iter!=selectedRows.end(); ++iter) { - ids.push_back (mModel->getUniversalId (iter->row())); + ids.push_back (mModel->getUniversalId (mProxyModel->mapToSource (*iter).row())); } return ids; @@ -234,7 +238,7 @@ void CSVTools::ReportTable::updateUserSetting (const QString& name, const QStrin mDoubleClickActions[modifiers] = action; return; - } + } } std::vector CSVTools::ReportTable::getReplaceIndices (bool selection) const @@ -245,13 +249,22 @@ std::vector CSVTools::ReportTable::getReplaceIndices (bool selection) const { QModelIndexList selectedRows = selectionModel()->selectedRows(); + std::vector rows; + for (QModelIndexList::const_iterator iter (selectedRows.begin()); iter!=selectedRows.end(); ++iter) { - QString hint = mModel->data (mModel->index (iter->row(), 2)).toString(); + rows.push_back (mProxyModel->mapToSource (*iter).row()); + } + + std::sort (rows.begin(), rows.end()); + + for (std::vector::const_iterator iter (rows.begin()); iter!=rows.end(); ++iter) + { + QString hint = mModel->data (mModel->index (*iter, 2)).toString(); if (!hint.isEmpty() && hint[0]=='R') - indices.push_back (iter->row()); + indices.push_back (*iter); } } else @@ -272,25 +285,35 @@ void CSVTools::ReportTable::flagAsReplaced (int index) { mModel->flagAsReplaced (index); } - + void CSVTools::ReportTable::showSelection() { QModelIndexList selectedRows = selectionModel()->selectedRows(); for (QModelIndexList::const_iterator iter (selectedRows.begin()); iter!=selectedRows.end(); ++iter) - emit editRequest (mModel->getUniversalId (iter->row()), mModel->getHint (iter->row())); + { + int row = mProxyModel->mapToSource (*iter).row(); + emit editRequest (mModel->getUniversalId (row), mModel->getHint (row)); + } } void CSVTools::ReportTable::removeSelection() { QModelIndexList selectedRows = selectionModel()->selectedRows(); - std::reverse (selectedRows.begin(), selectedRows.end()); + std::vector rows; - for (QModelIndexList::const_iterator iter (selectedRows.begin()); iter!=selectedRows.end(); + for (QModelIndexList::iterator iter (selectedRows.begin()); iter!=selectedRows.end(); ++iter) - mModel->removeRows (iter->row(), 1); + { + rows.push_back (mProxyModel->mapToSource (*iter).row()); + } + + std::sort (rows.begin(), rows.end()); + + for (std::vector::const_reverse_iterator iter (rows.rbegin()); iter!=rows.rend(); ++iter) + mProxyModel->removeRows (*iter, 1); selectionModel()->clear(); } diff --git a/apps/opencs/view/tools/reporttable.hpp b/apps/opencs/view/tools/reporttable.hpp index e19b327e4..c847b2d47 100644 --- a/apps/opencs/view/tools/reporttable.hpp +++ b/apps/opencs/view/tools/reporttable.hpp @@ -6,6 +6,7 @@ #include "../world/dragrecordtable.hpp" class QAction; +class QSortFilterProxyModel; namespace CSMTools { @@ -30,7 +31,8 @@ namespace CSVTools Action_Remove, Action_EditAndRemove }; - + + QSortFilterProxyModel *mProxyModel; CSMTools::ReportModel *mModel; CSVWorld::CommandDelegate *mIdTypeDelegate; QAction *mShowAction; @@ -63,11 +65,14 @@ namespace CSVTools void clear(); - // Return indices of rows that are suitable for replacement. - // - // \param selection Only list selected rows. + /// Return indices of rows that are suitable for replacement. + /// + /// \param selection Only list selected rows. + /// + /// \return rows in the original model std::vector getReplaceIndices (bool selection) const; + /// \param index row in the original model void flagAsReplaced (int index); private slots: @@ -78,8 +83,8 @@ namespace CSVTools public slots: - void stateChanged (int state, CSMDoc::Document *document); - + void stateChanged (int state, CSMDoc::Document *document); + signals: void editRequest (const CSMWorld::UniversalId& id, const std::string& hint); From 47b66b57ae52972ff514509270b1d12cd0a23beb Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Fri, 3 Jul 2015 15:37:10 +0300 Subject: [PATCH 1717/3725] Create a context menu handler for dialogue editors with ID information --- apps/opencs/view/world/dialoguesubview.cpp | 69 ++++++++++++++++++++++ apps/opencs/view/world/dialoguesubview.hpp | 24 ++++++++ 2 files changed, 93 insertions(+) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 1d3eb5313..70a3cd37c 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include "../../model/world/nestedtableproxymodel.hpp" #include "../../model/world/columnbase.hpp" @@ -314,6 +315,74 @@ CSVWorld::DialogueDelegateDispatcher::~DialogueDelegateDispatcher() } } + +CSVWorld::IdContextMenu::IdContextMenu(QWidget *widget, CSMWorld::ColumnBase::Display display) + : QObject(widget), + mWidget(widget), + mIdType(CSMWorld::TableMimeData::convertEnums(display)) +{ + Q_ASSERT(mWidget != NULL); + Q_ASSERT(CSMWorld::ColumnBase::isId(display)); + Q_ASSERT(mIdType != CSMWorld::UniversalId::Type_None); + + mWidget->setContextMenuPolicy(Qt::CustomContextMenu); + connect(mWidget, + SIGNAL(customContextMenuRequested(const QPoint &)), + this, + SLOT(showContextMenu(const QPoint &))); + + mEditIdAction = new QAction(this); + + QLineEdit *lineEdit = qobject_cast(mWidget); + if (lineEdit != NULL) + { + mContextMenu = lineEdit->createStandardContextMenu(); + mContextMenu->setParent(mWidget); + + QAction *action = mContextMenu->actions().first(); + mContextMenu->insertAction(action, mEditIdAction); + mContextMenu->insertSeparator(action); + } + else + { + mContextMenu = new QMenu(mWidget); + mContextMenu->addAction(mEditIdAction); + } +} + +QString CSVWorld::IdContextMenu::getWidgetValue() const +{ + static QLineEdit *lineEdit = qobject_cast(mWidget); + static QLabel *label = qobject_cast(mWidget); + + QString value = ""; + if (lineEdit != NULL) + { + value = lineEdit->text(); + } + else if (label != NULL) + { + value = label->text(); + } + return value; +} + +void CSVWorld::IdContextMenu::showContextMenu(const QPoint &pos) +{ + QString value = getWidgetValue(); + if (!value.isEmpty()) + { + mEditIdAction->setText("Edit '" + value + "'"); + + QAction *selectedAction = mContextMenu->exec(mWidget->mapToGlobal(pos)); + if (selectedAction != NULL && selectedAction == mEditIdAction) + { + CSMWorld::UniversalId editId(mIdType, value.toUtf8().constData()); + emit editIdRequest(editId, ""); + } + } +} + /* =============================================================EditWidget===================================================== */ diff --git a/apps/opencs/view/world/dialoguesubview.hpp b/apps/opencs/view/world/dialoguesubview.hpp index be58be5ad..f33c6d9d2 100644 --- a/apps/opencs/view/world/dialoguesubview.hpp +++ b/apps/opencs/view/world/dialoguesubview.hpp @@ -11,12 +11,14 @@ #include "../../model/world/columnbase.hpp" #include "../../model/world/commanddispatcher.hpp" +#include "../../model/world/universalid.hpp" class QDataWidgetMapper; class QSize; class QEvent; class QLabel; class QVBoxLayout; +class QMenu; namespace CSMWorld { @@ -149,6 +151,28 @@ namespace CSVWorld CSMWorld::ColumnBase::Display display); }; + class IdContextMenu : public QObject + { + Q_OBJECT + + QWidget *mWidget; + CSMWorld::UniversalId::Type mIdType; + + QMenu *mContextMenu; + QAction *mEditIdAction; + + QString getWidgetValue() const; + + public: + IdContextMenu(QWidget *widget, CSMWorld::ColumnBase::Display display); + + private slots: + void showContextMenu(const QPoint &pos); + + signals: + void editIdRequest(const CSMWorld::UniversalId &id, const std::string &hint); + }; + class EditWidget : public QScrollArea { Q_OBJECT From e8e34f37dd04e25d6fa6ffe26d286a5e95dc5edf Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Fri, 3 Jul 2015 16:24:08 +0300 Subject: [PATCH 1718/3725] Edit 'ID' action is available in dialogue sub-views (for LineEdits and Labels) --- apps/opencs/view/world/dialoguesubview.cpp | 33 ++++++++++++++++------ apps/opencs/view/world/dialoguesubview.hpp | 4 +++ 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 70a3cd37c..da325f6c3 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -332,6 +332,7 @@ CSVWorld::IdContextMenu::IdContextMenu(QWidget *widget, CSMWorld::ColumnBase::Di SLOT(showContextMenu(const QPoint &))); mEditIdAction = new QAction(this); + connect(mEditIdAction, SIGNAL(triggered()), this, SLOT(editIdRequest())); QLineEdit *lineEdit = qobject_cast(mWidget); if (lineEdit != NULL) @@ -352,8 +353,8 @@ CSVWorld::IdContextMenu::IdContextMenu(QWidget *widget, CSMWorld::ColumnBase::Di QString CSVWorld::IdContextMenu::getWidgetValue() const { - static QLineEdit *lineEdit = qobject_cast(mWidget); - static QLabel *label = qobject_cast(mWidget); + QLineEdit *lineEdit = qobject_cast(mWidget); + QLabel *label = qobject_cast(mWidget); QString value = ""; if (lineEdit != NULL) @@ -373,16 +374,16 @@ void CSVWorld::IdContextMenu::showContextMenu(const QPoint &pos) if (!value.isEmpty()) { mEditIdAction->setText("Edit '" + value + "'"); - - QAction *selectedAction = mContextMenu->exec(mWidget->mapToGlobal(pos)); - if (selectedAction != NULL && selectedAction == mEditIdAction) - { - CSMWorld::UniversalId editId(mIdType, value.toUtf8().constData()); - emit editIdRequest(editId, ""); - } + mContextMenu->exec(mWidget->mapToGlobal(pos)); } } +void CSVWorld::IdContextMenu::editIdRequest() +{ + CSMWorld::UniversalId editId(mIdType, getWidgetValue().toUtf8().constData()); + emit editIdRequest(editId, ""); +} + /* =============================================================EditWidget===================================================== */ @@ -557,6 +558,15 @@ void CSVWorld::EditWidget::remake(int row) editor->setEnabled(false); label->setEnabled(false); } + + if (CSMWorld::ColumnBase::isId(display)) + { + IdContextMenu *menu = new IdContextMenu(editor, display); + connect(menu, + SIGNAL(editIdRequest(const CSMWorld::UniversalId &, const std::string &)), + this, + SIGNAL(editIdRequest(const CSMWorld::UniversalId &, const std::string &))); + } } } else @@ -676,6 +686,11 @@ CSVWorld::SimpleDialogueSubView::SimpleDialogueSubView (const CSMWorld::Universa mEditWidget->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); dataChanged(mTable->getModelIndex (getUniversalId().getId(), 0)); + + connect(mEditWidget, + SIGNAL(editIdRequest(const CSMWorld::UniversalId &, const std::string &)), + this, + SIGNAL(focusId(const CSMWorld::UniversalId &, const std::string &))); } void CSVWorld::SimpleDialogueSubView::setEditLock (bool locked) diff --git a/apps/opencs/view/world/dialoguesubview.hpp b/apps/opencs/view/world/dialoguesubview.hpp index f33c6d9d2..f4331abb2 100644 --- a/apps/opencs/view/world/dialoguesubview.hpp +++ b/apps/opencs/view/world/dialoguesubview.hpp @@ -168,6 +168,7 @@ namespace CSVWorld private slots: void showContextMenu(const QPoint &pos); + void editIdRequest(); signals: void editIdRequest(const CSMWorld::UniversalId &id, const std::string &hint); @@ -195,6 +196,9 @@ namespace CSVWorld virtual ~EditWidget(); void remake(int row); + + signals: + void editIdRequest(const CSMWorld::UniversalId &id, const std::string &hint); }; class SimpleDialogueSubView : public CSVDoc::SubView From 149cb9d00489bd43631f4ec14e03189487aa4498 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Fri, 3 Jul 2015 16:51:47 +0300 Subject: [PATCH 1719/3725] IdContextMenu: if the ID field is empty show the standard context menu (if available) --- apps/opencs/view/world/dialoguesubview.cpp | 48 ++++++++++++++++++---- apps/opencs/view/world/dialoguesubview.hpp | 2 + 2 files changed, 43 insertions(+), 7 deletions(-) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index da325f6c3..bfd01b14c 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -338,16 +338,10 @@ CSVWorld::IdContextMenu::IdContextMenu(QWidget *widget, CSMWorld::ColumnBase::Di if (lineEdit != NULL) { mContextMenu = lineEdit->createStandardContextMenu(); - mContextMenu->setParent(mWidget); - - QAction *action = mContextMenu->actions().first(); - mContextMenu->insertAction(action, mEditIdAction); - mContextMenu->insertSeparator(action); } else { mContextMenu = new QMenu(mWidget); - mContextMenu->addAction(mEditIdAction); } } @@ -368,12 +362,52 @@ QString CSVWorld::IdContextMenu::getWidgetValue() const return value; } +void CSVWorld::IdContextMenu::addEditIdActionToMenu(const QString &text) +{ + mEditIdAction->setText(text); + if (mContextMenu->actions().isEmpty()) + { + mContextMenu->addAction(mEditIdAction); + } + else + { + QAction *action = mContextMenu->actions().first(); + mContextMenu->insertAction(action, mEditIdAction); + mContextMenu->insertSeparator(action); + } +} + +void CSVWorld::IdContextMenu::removeEditIdActionFromMenu() +{ + if (mContextMenu->actions().isEmpty()) + { + return; + } + + if (mContextMenu->actions().first() == mEditIdAction) + { + mContextMenu->removeAction(mEditIdAction); + if (!mContextMenu->actions().isEmpty() && mContextMenu->actions().first()->isSeparator()) + { + mContextMenu->removeAction(mContextMenu->actions().first()); + } + } +} + void CSVWorld::IdContextMenu::showContextMenu(const QPoint &pos) { QString value = getWidgetValue(); if (!value.isEmpty()) { - mEditIdAction->setText("Edit '" + value + "'"); + addEditIdActionToMenu("Edit '" + value + "'"); + } + else + { + removeEditIdActionFromMenu(); + } + + if (!mContextMenu->actions().isEmpty()) + { mContextMenu->exec(mWidget->mapToGlobal(pos)); } } diff --git a/apps/opencs/view/world/dialoguesubview.hpp b/apps/opencs/view/world/dialoguesubview.hpp index f4331abb2..ddb6e5056 100644 --- a/apps/opencs/view/world/dialoguesubview.hpp +++ b/apps/opencs/view/world/dialoguesubview.hpp @@ -162,6 +162,8 @@ namespace CSVWorld QAction *mEditIdAction; QString getWidgetValue() const; + void addEditIdActionToMenu(const QString &text); + void removeEditIdActionFromMenu(); public: IdContextMenu(QWidget *widget, CSMWorld::ColumnBase::Display display); From 61ab0ba4821a18c77ba732707f4c370b463f6e12 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Fri, 3 Jul 2015 18:48:13 +0300 Subject: [PATCH 1720/3725] Prevent the Edit 'ID' action for the current ID of the dialogue subview --- apps/opencs/view/world/dialoguesubview.cpp | 13 ++++++++++++- apps/opencs/view/world/dialoguesubview.hpp | 6 ++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index bfd01b14c..505f84227 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -345,6 +345,11 @@ CSVWorld::IdContextMenu::IdContextMenu(QWidget *widget, CSMWorld::ColumnBase::Di } } +void CSVWorld::IdContextMenu::excludeId(const std::string &id) +{ + mExcludedIds.insert(id); +} + QString CSVWorld::IdContextMenu::getWidgetValue() const { QLineEdit *lineEdit = qobject_cast(mWidget); @@ -397,7 +402,8 @@ void CSVWorld::IdContextMenu::removeEditIdActionFromMenu() void CSVWorld::IdContextMenu::showContextMenu(const QPoint &pos) { QString value = getWidgetValue(); - if (!value.isEmpty()) + bool isExcludedId = mExcludedIds.find(value.toUtf8().constData()) != mExcludedIds.end(); + if (!value.isEmpty() && !isExcludedId) { addEditIdActionToMenu("Edit '" + value + "'"); } @@ -595,7 +601,12 @@ void CSVWorld::EditWidget::remake(int row) if (CSMWorld::ColumnBase::isId(display)) { + int idColumn = mTable->findColumnIndex(CSMWorld::Columns::ColumnId_Id); + QString id = mTable->data(mTable->index(row, idColumn)).toString(); + IdContextMenu *menu = new IdContextMenu(editor, display); + // Current ID is already opened, so no need to create Edit 'ID' action for it + menu->excludeId(id.toUtf8().constData()); connect(menu, SIGNAL(editIdRequest(const CSMWorld::UniversalId &, const std::string &)), this, diff --git a/apps/opencs/view/world/dialoguesubview.hpp b/apps/opencs/view/world/dialoguesubview.hpp index ddb6e5056..91be5588f 100644 --- a/apps/opencs/view/world/dialoguesubview.hpp +++ b/apps/opencs/view/world/dialoguesubview.hpp @@ -1,6 +1,7 @@ #ifndef CSV_WORLD_DIALOGUESUBVIEW_H #define CSV_WORLD_DIALOGUESUBVIEW_H +#include #include #include @@ -151,12 +152,15 @@ namespace CSVWorld CSMWorld::ColumnBase::Display display); }; + /// A context menu with "Edit 'ID'" action for editors in the dialogue subview class IdContextMenu : public QObject { Q_OBJECT QWidget *mWidget; CSMWorld::UniversalId::Type mIdType; + std::set mExcludedIds; + ///< A list of IDs that should not have the Edit 'ID' action. QMenu *mContextMenu; QAction *mEditIdAction; @@ -168,6 +172,8 @@ namespace CSVWorld public: IdContextMenu(QWidget *widget, CSMWorld::ColumnBase::Display display); + void excludeId(const std::string &id); + private slots: void showContextMenu(const QPoint &pos); void editIdRequest(); From d73fd471c3948b1e6b3db1eefa75a7273869f9c3 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Fri, 3 Jul 2015 19:07:44 +0300 Subject: [PATCH 1721/3725] IdContextMenu: don't add Edit action if it's already in the context menu --- apps/opencs/view/world/dialoguesubview.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 505f84227..283cdfa58 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -374,7 +374,7 @@ void CSVWorld::IdContextMenu::addEditIdActionToMenu(const QString &text) { mContextMenu->addAction(mEditIdAction); } - else + else if (mContextMenu->actions().first() != mEditIdAction) { QAction *action = mContextMenu->actions().first(); mContextMenu->insertAction(action, mEditIdAction); From 260f6f22aecfa6722e103620ed657c33549de597 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Fri, 3 Jul 2015 22:07:37 +0300 Subject: [PATCH 1722/3725] TableBottomBox adjusts its size according to the current widget size --- apps/opencs/view/world/tablebottombox.cpp | 22 ++++++++++++++++++++++ apps/opencs/view/world/tablebottombox.hpp | 4 ++++ 2 files changed, 26 insertions(+) diff --git a/apps/opencs/view/world/tablebottombox.cpp b/apps/opencs/view/world/tablebottombox.cpp index bfd56b326..eee25b1bf 100644 --- a/apps/opencs/view/world/tablebottombox.cpp +++ b/apps/opencs/view/world/tablebottombox.cpp @@ -9,6 +9,20 @@ #include "creator.hpp" +void CSVWorld::TableBottomBox::updateSize() +{ + // Make sure that the size of the bottom box is determined by the currently visible widget + for (int i = 0; i < mLayout->count(); ++i) + { + QSizePolicy::Policy verPolicy = QSizePolicy::Ignored; + if (mLayout->widget(i) == mLayout->currentWidget()) + { + verPolicy = QSizePolicy::Expanding; + } + mLayout->widget(i)->setSizePolicy(QSizePolicy::Expanding, verPolicy); + } +} + void CSVWorld::TableBottomBox::updateStatus() { if (mShowStatusBar) @@ -61,6 +75,7 @@ CSVWorld::TableBottomBox::TableBottomBox (const CreatorFactoryBase& creatorFacto mLayout = new QStackedLayout; mLayout->setContentsMargins (0, 0, 0, 0); + connect (mLayout, SIGNAL (currentChanged (int)), this, SLOT (currentWidgetChanged (int))); mStatus = new QLabel; @@ -87,6 +102,8 @@ CSVWorld::TableBottomBox::TableBottomBox (const CreatorFactoryBase& creatorFacto mExtendedConfigurator = new ExtendedCommandConfigurator (document, id, this); mLayout->addWidget (mExtendedConfigurator); connect (mExtendedConfigurator, SIGNAL (done()), this, SLOT (requestDone())); + + updateSize(); } void CSVWorld::TableBottomBox::setEditLock (bool locked) @@ -129,6 +146,11 @@ void CSVWorld::TableBottomBox::requestDone() mEditMode = EditMode_None; } +void CSVWorld::TableBottomBox::currentWidgetChanged(int /*index*/) +{ + updateSize(); +} + void CSVWorld::TableBottomBox::selectionSizeChanged (int size) { if (mStatusCount[3]!=size) diff --git a/apps/opencs/view/world/tablebottombox.hpp b/apps/opencs/view/world/tablebottombox.hpp index fded912fe..15ae2924c 100644 --- a/apps/opencs/view/world/tablebottombox.hpp +++ b/apps/opencs/view/world/tablebottombox.hpp @@ -43,6 +43,8 @@ namespace CSVWorld TableBottomBox (const TableBottomBox&); TableBottomBox& operator= (const TableBottomBox&); + void updateSize(); + void updateStatus(); void extendedConfigRequest(ExtendedCommandConfigurator::Mode mode, @@ -77,6 +79,8 @@ namespace CSVWorld void requestDone(); ///< \note This slot being called does not imply success. + void currentWidgetChanged(int index); + public slots: void selectionSizeChanged (int size); From 95d16b24c05142943b22c31162bebc1b7b46a82f Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Fri, 3 Jul 2015 22:25:56 +0300 Subject: [PATCH 1723/3725] ExtendedCommandConfigurator: disable the perform button when all tables are unchecked --- .../world/extendedcommandconfigurator.cpp | 24 +++++++++++++++++-- .../world/extendedcommandconfigurator.hpp | 2 ++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/world/extendedcommandconfigurator.cpp b/apps/opencs/view/world/extendedcommandconfigurator.cpp index 9f067545c..257e9c4f0 100644 --- a/apps/opencs/view/world/extendedcommandconfigurator.cpp +++ b/apps/opencs/view/world/extendedcommandconfigurator.cpp @@ -28,6 +28,7 @@ CSVWorld::ExtendedCommandConfigurator::ExtendedCommandConfigurator(CSMDoc::Docum QWidget *parent) : QWidget(parent), mNumUsedCheckBoxes(0), + mNumChecked(0), mMode(Mode_None) { mCommandDispatcher = new CSMWorld::CommandDispatcher(document, id, this); @@ -125,7 +126,9 @@ void CSVWorld::ExtendedCommandConfigurator::setupCheckBoxes(const std::vector 0; --i) { - mTypeCheckBoxes.insert(std::make_pair(new QCheckBox(mTypeGroup), CSMWorld::UniversalId::Type_None)); + QCheckBox *checkBox = new QCheckBox(mTypeGroup); + connect(checkBox, SIGNAL(stateChanged(int)), this, SLOT(checkBoxStateChanged(int))); + mTypeCheckBoxes.insert(std::make_pair(checkBox, CSMWorld::UniversalId::Type_None)); } } @@ -148,7 +151,7 @@ void CSVWorld::ExtendedCommandConfigurator::setupCheckBoxes(const std::vectorfirst->hide(); } } - mNumUsedCheckBoxes = numTypes; + mNumChecked = mNumUsedCheckBoxes = numTypes; } void CSVWorld::ExtendedCommandConfigurator::performExtendedCommand() @@ -176,3 +179,20 @@ void CSVWorld::ExtendedCommandConfigurator::performExtendedCommand() } emit done(); } + +void CSVWorld::ExtendedCommandConfigurator::checkBoxStateChanged(int state) +{ + switch (state) + { + case Qt::Unchecked: + --mNumChecked; + break; + case Qt::Checked: + ++mNumChecked; + break; + case Qt::PartiallyChecked: // Not used + break; + } + + mPerformButton->setEnabled(mNumChecked > 0); +} diff --git a/apps/opencs/view/world/extendedcommandconfigurator.hpp b/apps/opencs/view/world/extendedcommandconfigurator.hpp index 8efe36fa7..6a5e1e2e7 100644 --- a/apps/opencs/view/world/extendedcommandconfigurator.hpp +++ b/apps/opencs/view/world/extendedcommandconfigurator.hpp @@ -40,6 +40,7 @@ namespace CSVWorld QGroupBox *mTypeGroup; CheckBoxMap mTypeCheckBoxes; int mNumUsedCheckBoxes; + int mNumChecked; Mode mMode; CSMWorld::CommandDispatcher *mCommandDispatcher; @@ -59,6 +60,7 @@ namespace CSVWorld private slots: void performExtendedCommand(); + void checkBoxStateChanged(int state); signals: void done(); From 05cc130212162195f2f09143000f1fb49d38442f Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Fri, 3 Jul 2015 22:31:38 +0300 Subject: [PATCH 1724/3725] The configuration panel gets a focus when opening --- apps/opencs/view/world/tablebottombox.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/opencs/view/world/tablebottombox.cpp b/apps/opencs/view/world/tablebottombox.cpp index eee25b1bf..3a7fa8e8a 100644 --- a/apps/opencs/view/world/tablebottombox.cpp +++ b/apps/opencs/view/world/tablebottombox.cpp @@ -60,6 +60,7 @@ void CSVWorld::TableBottomBox::extendedConfigRequest(CSVWorld::ExtendedCommandCo mLayout->setCurrentWidget (mExtendedConfigurator); mEditMode = EditMode_ExtendedConfig; setVisible (true); + mExtendedConfigurator->setFocus(); } CSVWorld::TableBottomBox::TableBottomBox (const CreatorFactoryBase& creatorFactory, From e664ef75785929d5657986bd2cacace7779c627b Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Fri, 3 Jul 2015 23:15:26 +0300 Subject: [PATCH 1725/3725] ExtendedCommandConfigurator: the perform button takes the name of the command that is executed --- .../world/extendedcommandconfigurator.cpp | 24 ++----------------- .../world/extendedcommandconfigurator.hpp | 1 - 2 files changed, 2 insertions(+), 23 deletions(-) diff --git a/apps/opencs/view/world/extendedcommandconfigurator.cpp b/apps/opencs/view/world/extendedcommandconfigurator.cpp index 257e9c4f0..36bff7d59 100644 --- a/apps/opencs/view/world/extendedcommandconfigurator.cpp +++ b/apps/opencs/view/world/extendedcommandconfigurator.cpp @@ -9,20 +9,6 @@ #include "../../model/world/commanddispatcher.hpp" #include "../../model/world/universalid.hpp" -namespace -{ - QString getTypeGroupTitle(CSVWorld::ExtendedCommandConfigurator::Mode mode) - { - static const QString title = "Tables affected by "; - QString titleSuffix = "Extended Delete"; - if (mode == CSVWorld::ExtendedCommandConfigurator::Mode_Revert) - { - titleSuffix = "Extended Revert"; - } - return title + titleSuffix; - } -} - CSVWorld::ExtendedCommandConfigurator::ExtendedCommandConfigurator(CSMDoc::Document &document, const CSMWorld::UniversalId &id, QWidget *parent) @@ -33,7 +19,7 @@ CSVWorld::ExtendedCommandConfigurator::ExtendedCommandConfigurator(CSMDoc::Docum { mCommandDispatcher = new CSMWorld::CommandDispatcher(document, id, this); - mPerformButton = new QPushButton("Perform", this); + mPerformButton = new QPushButton(this); mPerformButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); connect(mPerformButton, SIGNAL(clicked(bool)), this, SLOT(performExtendedCommand())); @@ -41,9 +27,6 @@ CSVWorld::ExtendedCommandConfigurator::ExtendedCommandConfigurator(CSMDoc::Docum mCancelButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); connect(mCancelButton, SIGNAL(clicked(bool)), this, SIGNAL(done())); - mCommandTitle = new QLabel(this); - mCommandTitle->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - mTypeGroup = new QGroupBox(this); QGridLayout *groupLayout = new QGridLayout(mTypeGroup); @@ -52,7 +35,6 @@ CSVWorld::ExtendedCommandConfigurator::ExtendedCommandConfigurator(CSMDoc::Docum QHBoxLayout *mainLayout = new QHBoxLayout(this); mainLayout->setSizeConstraint(QLayout::SetNoConstraint); - mainLayout->addWidget(mCommandTitle); mainLayout->addWidget(mTypeGroup); mainLayout->addWidget(mPerformButton); mainLayout->addWidget(mCancelButton); @@ -64,9 +46,7 @@ void CSVWorld::ExtendedCommandConfigurator::configure(CSVWorld::ExtendedCommandC mMode = mode; if (mMode != Mode_None) { - QString title = (mMode == Mode_Delete) ? "Extended Delete" : "Extended Revert"; - title.append(" from:"); - mCommandTitle->setText(title); + mPerformButton->setText((mMode == Mode_Delete) ? "Extended Delete" : "Extended Revert"); mCommandDispatcher->setSelection(selectedIds); setupCheckBoxes(mCommandDispatcher->getExtendedTypes()); setupGroupLayout(); diff --git a/apps/opencs/view/world/extendedcommandconfigurator.hpp b/apps/opencs/view/world/extendedcommandconfigurator.hpp index 6a5e1e2e7..9ed16aa1e 100644 --- a/apps/opencs/view/world/extendedcommandconfigurator.hpp +++ b/apps/opencs/view/world/extendedcommandconfigurator.hpp @@ -36,7 +36,6 @@ namespace CSVWorld QPushButton *mPerformButton; QPushButton *mCancelButton; - QLabel *mCommandTitle; QGroupBox *mTypeGroup; CheckBoxMap mTypeCheckBoxes; int mNumUsedCheckBoxes; From ff3c9a6fb28bcddfdc73da2b0a3eaa23e8ffd0b0 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Fri, 3 Jul 2015 23:35:00 +0300 Subject: [PATCH 1726/3725] ExtendedCommandConfigurator: the perform button is now the default for the widget --- apps/opencs/view/world/extendedcommandconfigurator.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/opencs/view/world/extendedcommandconfigurator.cpp b/apps/opencs/view/world/extendedcommandconfigurator.cpp index 36bff7d59..85c5a2bda 100644 --- a/apps/opencs/view/world/extendedcommandconfigurator.cpp +++ b/apps/opencs/view/world/extendedcommandconfigurator.cpp @@ -20,6 +20,7 @@ CSVWorld::ExtendedCommandConfigurator::ExtendedCommandConfigurator(CSMDoc::Docum mCommandDispatcher = new CSMWorld::CommandDispatcher(document, id, this); mPerformButton = new QPushButton(this); + mPerformButton->setDefault(true); mPerformButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); connect(mPerformButton, SIGNAL(clicked(bool)), this, SLOT(performExtendedCommand())); From 1f826476ff6fc3627c9968cc78912d3dde087b1b Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sat, 4 Jul 2015 02:02:22 +0300 Subject: [PATCH 1727/3725] Fix build error --- apps/opencs/view/world/extendedcommandconfigurator.cpp | 1 - apps/opencs/view/world/extendedcommandconfigurator.hpp | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/world/extendedcommandconfigurator.cpp b/apps/opencs/view/world/extendedcommandconfigurator.cpp index 85c5a2bda..d3b97b127 100644 --- a/apps/opencs/view/world/extendedcommandconfigurator.cpp +++ b/apps/opencs/view/world/extendedcommandconfigurator.cpp @@ -7,7 +7,6 @@ #include #include "../../model/world/commanddispatcher.hpp" -#include "../../model/world/universalid.hpp" CSVWorld::ExtendedCommandConfigurator::ExtendedCommandConfigurator(CSMDoc::Document &document, const CSMWorld::UniversalId &id, diff --git a/apps/opencs/view/world/extendedcommandconfigurator.hpp b/apps/opencs/view/world/extendedcommandconfigurator.hpp index 9ed16aa1e..590cabab1 100644 --- a/apps/opencs/view/world/extendedcommandconfigurator.hpp +++ b/apps/opencs/view/world/extendedcommandconfigurator.hpp @@ -5,6 +5,8 @@ #include +#include "../../model/world/universalid.hpp" + class QPushButton; class QGroupBox; class QCheckBox; @@ -19,7 +21,6 @@ namespace CSMDoc namespace CSMWorld { class CommandDispatcher; - class UniversalId; } namespace CSVWorld From 6bcea21e144467b0e0cc2709341e66917aab49f9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 4 Jul 2015 05:19:05 +0200 Subject: [PATCH 1728/3725] Use fCombatDelayCreature, fCombatDelayNpc for random delays between aicombat attacks (Bug #1876) --- apps/openmw/mwmechanics/aicombat.cpp | 34 +++++++++++++++++++--------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index c0d2bc90d..4eeea6f1f 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -81,6 +81,7 @@ namespace MWMechanics /// \brief This class holds the variables AiCombat needs which are deleted if the package becomes inactive. struct AiCombatStorage : AiTemporaryBase { + float mAttackCooldown; float mTimerReact; float mTimerCombatMove; bool mReadyToAttack; @@ -98,6 +99,7 @@ namespace MWMechanics MWMechanics::Movement mMovement; AiCombatStorage(): + mAttackCooldown(0), mTimerReact(0), mTimerCombatMove(0), mReadyToAttack(false), @@ -340,24 +342,34 @@ namespace MWMechanics // start new attack if(readyToAttack && characterController.readyToStartAttack()) { - attack = true; // attack starts just now - characterController.setAttackingOrSpell(attack); + if (storage.mAttackCooldown <= 0) + { + attack = true; // attack starts just now + characterController.setAttackingOrSpell(attack); - if (!distantCombat) - chooseBestAttack(weapon, movement); + if (!distantCombat) + chooseBestAttack(weapon, movement); - strength = Misc::Rng::rollClosedProbability(); + strength = Misc::Rng::rollClosedProbability(); - //say a provoking combat phrase - if (actor.getClass().isNpc()) - { const MWWorld::ESMStore &store = world->getStore(); - int chance = store.get().find("iVoiceAttackOdds")->getInt(); - if (Misc::Rng::roll0to99() < chance) + + //say a provoking combat phrase + if (actor.getClass().isNpc()) { - MWBase::Environment::get().getDialogueManager()->say(actor, "attack"); + int chance = store.get().find("iVoiceAttackOdds")->getInt(); + if (Misc::Rng::roll0to99() < chance) + { + MWBase::Environment::get().getDialogueManager()->say(actor, "attack"); + } } + float baseDelay = store.get().find("fCombatDelayCreature")->getFloat(); + if (actor.getClass().isNpc()) + baseDelay = store.get().find("fCombatDelayNPC")->getFloat(); + storage.mAttackCooldown = std::min(baseDelay + 0.01 * Misc::Rng::roll0to99(), baseDelay + 0.9); } + else + storage.mAttackCooldown -= tReaction; } From 164994f3d33c9554022502aee976164d303df843 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sat, 4 Jul 2015 18:47:26 +1200 Subject: [PATCH 1729/3725] Made PathFinder::buildPath() private. Now all paths are built by calling PathFinder::buildSyncedPath(). Also removed useless comment. --- apps/openmw/mwmechanics/aiwander.cpp | 11 ++--------- apps/openmw/mwmechanics/pathfinding.hpp | 5 ++--- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 41cfb9df4..298cda961 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -410,7 +410,7 @@ namespace MWMechanics ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(pos)); // don't take shortcuts for wandering - storage.mPathFinder.buildPath(start, dest, actor.getCell(), false); + storage.mPathFinder.buildSyncedPath(start, dest, actor.getCell(), false); if(storage.mPathFinder.isPathConstructed()) { @@ -510,17 +510,10 @@ namespace MWMechanics ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(pos)); // don't take shortcuts for wandering - storage.mPathFinder.buildPath(start, dest, actor.getCell(), false); + storage.mPathFinder.buildSyncedPath(start, dest, actor.getCell(), false); if(storage.mPathFinder.isPathConstructed()) { - // buildPath inserts dest in case it is not a pathgraph point - // index which is a duplicate for AiWander. However below code - // does not work since getPath() returns a copy of path not a - // reference - //if(storage.mPathFinder.getPathSize() > 1) - //storage.mPathFinder.getPath().pop_back(); - // Remove this node as an option and add back the previously used node (stops NPC from picking the same node): ESM::Pathgrid::Point temp = mAllowedNodes[randNode]; mAllowedNodes.erase(mAllowedNodes.begin() + randNode); diff --git a/apps/openmw/mwmechanics/pathfinding.hpp b/apps/openmw/mwmechanics/pathfinding.hpp index 6de4db1d0..45d9dd973 100644 --- a/apps/openmw/mwmechanics/pathfinding.hpp +++ b/apps/openmw/mwmechanics/pathfinding.hpp @@ -35,9 +35,6 @@ namespace MWMechanics void clearPath(); - void buildPath(const ESM::Pathgrid::Point &startPoint, const ESM::Pathgrid::Point &endPoint, - const MWWorld::CellStore* cell, bool allowShortcuts = true); - bool checkPathCompleted(float x, float y, float tolerance=32.f); ///< \Returns true if we are within \a tolerance units of the last path point. @@ -92,6 +89,8 @@ namespace MWMechanics } private: + void buildPath(const ESM::Pathgrid::Point &startPoint, const ESM::Pathgrid::Point &endPoint, + const MWWorld::CellStore* cell, bool allowShortcuts = true); std::list mPath; From 46a654286b2ebc21931e0486504d7872cf2d5270 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sat, 4 Jul 2015 18:57:56 +1200 Subject: [PATCH 1730/3725] Remove fix for #1317 Expanding the AiWander distance for path grid nodes causes bigger problems than it solved. --- apps/openmw/mwmechanics/aiwander.cpp | 26 -------------------------- apps/openmw/mwmechanics/aiwander.hpp | 7 ------- 2 files changed, 33 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 298cda961..6c529f925 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -719,36 +719,10 @@ namespace MWMechanics mCurrentNode = mAllowedNodes[index]; mAllowedNodes.erase(mAllowedNodes.begin() + index); } - - // In vanilla Morrowind, sometimes distance is too small to include at least two points, - // in which case, we will take the two closest points regardless of the wander distance - // This is a backup option, as std::sort is potentially O(n^2) in time. - if (mAllowedNodes.empty()) - { - // Start with list of PathGrid nodes, sorted by distance from actor - std::vector nodeDistances; - for (unsigned int counter = 0; counter < pathgrid->mPoints.size(); counter++) - { - float distance = (npcPos - PathFinder::MakeOsgVec3(pathgrid->mPoints[counter])).length2(); - nodeDistances.push_back(std::make_pair(distance, &pathgrid->mPoints.at(counter))); - } - std::sort(nodeDistances.begin(), nodeDistances.end(), sortByDistance); - - // make closest node the current node - mCurrentNode = *nodeDistances[0].second; - - // give Actor a 2nd node to walk to - mAllowedNodes.push_back(*nodeDistances[1].second); - } mStoredAvailableNodes = true; // set only if successful in finding allowed nodes } } - bool AiWander::sortByDistance(const PathDistance& left, const PathDistance& right) - { - return left.first < right.first; - } - void AiWander::writeState(ESM::AiSequence::AiSequence &sequence) const { std::auto_ptr wander(new ESM::AiSequence::AiWander()); diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 13e3e571f..75b223094 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -120,13 +120,6 @@ namespace MWMechanics /// lookup table for converting idleSelect value to groupName static const std::string sIdleSelectToGroupName[GroupIndex_MaxIdle - GroupIndex_MinIdle + 1]; - - /// record distances of pathgrid point nodes to actor - /// first value is distance between actor and node, second value is PathGrid node - typedef std::pair PathDistance; - - /// used to sort array of PathDistance objects into ascending order - static bool sortByDistance(const PathDistance& left, const PathDistance& right); }; From fae93e3d8235ef4f745a75a37092cf04d46cacd5 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sat, 4 Jul 2015 19:00:27 +1200 Subject: [PATCH 1731/3725] Bugfix: was not resetting mStuckCount. --- apps/openmw/mwmechanics/aiwander.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 6c529f925..f32636b23 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -267,6 +267,7 @@ namespace MWMechanics moveNow = false; walking = false; chooseAction = true; + mStuckCount = 0; } //#endif } From 6b348451686674e48aa1140628514afc505d8b0f Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sat, 4 Jul 2015 18:49:32 +0300 Subject: [PATCH 1732/3725] Create a separate class for Edit 'ID' action to use in tables' context menus --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/view/world/tableeditidaction.cpp | 42 ++++++++++++++++++++ apps/opencs/view/world/tableeditidaction.hpp | 31 +++++++++++++++ 3 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 apps/opencs/view/world/tableeditidaction.cpp create mode 100644 apps/opencs/view/world/tableeditidaction.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index dc042cb99..4c7801d46 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -64,7 +64,7 @@ opencs_units (view/world table tablesubview scriptsubview util regionmapsubview tablebottombox creator genericcreator cellcreator referenceablecreator referencecreator scenesubview infocreator scriptedit dialoguesubview previewsubview regionmap dragrecordtable nestedtable - dialoguespinbox recordbuttonbar + dialoguespinbox recordbuttonbar tableeditidaction ) opencs_units_noqt (view/world diff --git a/apps/opencs/view/world/tableeditidaction.cpp b/apps/opencs/view/world/tableeditidaction.cpp new file mode 100644 index 000000000..7ce726e41 --- /dev/null +++ b/apps/opencs/view/world/tableeditidaction.cpp @@ -0,0 +1,42 @@ +#include "tableeditidaction.hpp" + +#include + +#include "../../model/world/tablemimedata.hpp" + +CSVWorld::TableEditIdAction::CellData CSVWorld::TableEditIdAction::getCellData(int row, int column) const +{ + QModelIndex index = mTable.model()->index(row, column); + if (index.isValid()) + { + QVariant display = mTable.model()->data(index, CSMWorld::ColumnBase::Role_Display); + QString value = mTable.model()->data(index).toString(); + return std::make_pair(static_cast(display.toInt()), value); + } + return std::make_pair(CSMWorld::ColumnBase::Display_None, ""); +} + +CSVWorld::TableEditIdAction::TableEditIdAction(const QTableView &table, QWidget *parent) + : QAction(parent), + mTable(table), + mCurrentId(CSMWorld::UniversalId::Type_None) +{} + +void CSVWorld::TableEditIdAction::setCell(int row, int column) +{ + CellData data = getCellData(row, column); + mCurrentId = CSMWorld::UniversalId(CSMWorld::TableMimeData::convertEnums(data.first), + data.second.toUtf8().constData()); + setText("Edit '" + data.second + "'"); +} + +CSMWorld::UniversalId CSVWorld::TableEditIdAction::getCurrentId() const +{ + return mCurrentId; +} + +bool CSVWorld::TableEditIdAction::isValidIdCell(int row, int column) const +{ + CellData data = getCellData(row, column); + return CSMWorld::ColumnBase::isId(data.first) && !data.second.isEmpty(); +} diff --git a/apps/opencs/view/world/tableeditidaction.hpp b/apps/opencs/view/world/tableeditidaction.hpp new file mode 100644 index 000000000..f2cf0b7bd --- /dev/null +++ b/apps/opencs/view/world/tableeditidaction.hpp @@ -0,0 +1,31 @@ +#ifndef CSVWORLD_TABLEEDITIDACTION_HPP +#define CSVWORLD_TABLEEDITIDACTION_HPP + +#include + +#include "../../model/world/columnbase.hpp" +#include "../../model/world/universalid.hpp" + +class QTableView; + +namespace CSVWorld +{ + class TableEditIdAction : public QAction + { + const QTableView &mTable; + CSMWorld::UniversalId mCurrentId; + + typedef std::pair CellData; + CellData getCellData(int row, int column) const; + + public: + TableEditIdAction(const QTableView &table, QWidget *parent = 0); + + void setCell(int row, int column); + + CSMWorld::UniversalId getCurrentId() const; + bool isValidIdCell(int row, int column) const; + }; +} + +#endif From 464e674a817e9ecb5c034953977cdeee6c6037db Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sat, 4 Jul 2015 18:51:39 +0300 Subject: [PATCH 1733/3725] Rework Table (view) code to use a TableEditIdAction --- apps/opencs/view/world/table.cpp | 43 +++++++++----------------------- apps/opencs/view/world/table.hpp | 4 +-- 2 files changed, 14 insertions(+), 33 deletions(-) diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index ba691131b..74343a5f6 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -27,6 +27,7 @@ #include "../../model/settings/usersettings.hpp" #include "recordstatusdelegate.hpp" +#include "tableeditidaction.hpp" #include "util.hpp" void CSVWorld::Table::contextMenuEvent (QContextMenuEvent *event) @@ -58,33 +59,13 @@ void CSVWorld::Table::contextMenuEvent (QContextMenuEvent *event) /// \todo add menu items for select all and clear selection + int currentRow = rowAt(event->y()); + int currentColumn = columnAt(event->x()); + if (mEditIdAction->isValidIdCell(currentRow, currentColumn)) { - // Request UniversalId editing from table columns. - - int currRow = rowAt( event->y() ), - currCol = columnAt( event->x() ); - - currRow = mProxyModel->mapToSource(mProxyModel->index( currRow, 0 )).row(); - - CSMWorld::ColumnBase::Display colDisplay = - static_cast( - mModel->headerData( - currCol, - Qt::Horizontal, - CSMWorld::ColumnBase::Role_Display ).toInt()); - - QString cellData = mModel->data(mModel->index( currRow, currCol )).toString(); - CSMWorld::UniversalId::Type colType = CSMWorld::TableMimeData::convertEnums( colDisplay ); - - if ( !cellData.isEmpty() - && colType != CSMWorld::UniversalId::Type_None ) - { - mEditCellAction->setText(tr("Edit '").append(cellData).append("'")); - - menu.addAction( mEditCellAction ); - - mEditCellId = CSMWorld::UniversalId( colType, cellData.toUtf8().constData() ); - } + mEditIdAction->setCell(currentRow, currentColumn); + menu.addAction(mEditIdAction); + menu.addSeparator(); } if (!mEditLock && !(mModel->getFeatures() & CSMWorld::IdTableBase::Feature_Constant)) @@ -363,10 +344,6 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id, connect (mMoveDownAction, SIGNAL (triggered()), this, SLOT (moveDownRecord())); addAction (mMoveDownAction); - mEditCellAction = new QAction( tr("Edit Cell"), this ); - connect( mEditCellAction, SIGNAL(triggered()), this, SLOT(editCell()) ); - addAction( mEditCellAction ); - mViewAction = new QAction (tr ("View"), this); connect (mViewAction, SIGNAL (triggered()), this, SLOT (viewRecord())); addAction (mViewAction); @@ -387,6 +364,10 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id, connect (mExtendedRevertAction, SIGNAL (triggered()), mDispatcher, SLOT (executeExtendedRevert())); addAction (mExtendedRevertAction); + mEditIdAction = new TableEditIdAction (*this, this); + connect (mEditIdAction, SIGNAL (triggered()), this, SLOT (editCell())); + addAction (mEditIdAction); + connect (mProxyModel, SIGNAL (rowsRemoved (const QModelIndex&, int, int)), this, SLOT (tableSizeUpdate())); @@ -522,7 +503,7 @@ void CSVWorld::Table::moveDownRecord() void CSVWorld::Table::editCell() { - emit editRequest( mEditCellId, std::string() ); + emit editRequest(mEditIdAction->getCurrentId(), ""); } void CSVWorld::Table::viewRecord() diff --git a/apps/opencs/view/world/table.hpp b/apps/opencs/view/world/table.hpp index 38fcd83bd..adacd3a9d 100644 --- a/apps/opencs/view/world/table.hpp +++ b/apps/opencs/view/world/table.hpp @@ -30,6 +30,7 @@ namespace CSMWorld namespace CSVWorld { class CommandDelegate; + class TableEditIdAction; ///< Table widget class Table : public DragRecordTable @@ -57,15 +58,14 @@ namespace CSVWorld QAction *mMoveUpAction; QAction *mMoveDownAction; QAction *mViewAction; - QAction *mEditCellAction; QAction *mPreviewAction; QAction *mExtendedDeleteAction; QAction *mExtendedRevertAction; + TableEditIdAction *mEditIdAction; CSMWorld::IdTableProxyModel *mProxyModel; CSMWorld::IdTableBase *mModel; int mRecordStatusDisplay; CSMWorld::CommandDispatcher *mDispatcher; - CSMWorld::UniversalId mEditCellId; std::map mDoubleClickActions; bool mJumpToAddedRecord; bool mUnselectAfterJump; From 86dc5a2c6702c28b9d3a89c2655db115b4bfe92e Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sat, 4 Jul 2015 19:27:42 +0300 Subject: [PATCH 1734/3725] Add Edit 'ID' action for nested tables --- apps/opencs/view/world/dialoguesubview.cpp | 5 ++++ apps/opencs/view/world/nestedtable.cpp | 30 ++++++++++++++++++---- apps/opencs/view/world/nestedtable.hpp | 8 ++++++ 3 files changed, 38 insertions(+), 5 deletions(-) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 283cdfa58..4a463ecaa 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -565,6 +565,11 @@ void CSVWorld::EditWidget::remake(int row) tablesLayout->addWidget(label); tablesLayout->addWidget(table); + + connect(table, + SIGNAL(editRequest(const CSMWorld::UniversalId &, const std::string &)), + this, + SIGNAL(editIdRequest(const CSMWorld::UniversalId &, const std::string &))); } else if (!(flags & CSMWorld::ColumnBase::Flag_Dialogue_List)) { diff --git a/apps/opencs/view/world/nestedtable.cpp b/apps/opencs/view/world/nestedtable.cpp index 92df59a5f..0876b2ce7 100644 --- a/apps/opencs/view/world/nestedtable.cpp +++ b/apps/opencs/view/world/nestedtable.cpp @@ -1,15 +1,18 @@ #include "nestedtable.hpp" -#include "../../model/world/nestedtableproxymodel.hpp" -#include "../../model/world/universalid.hpp" -#include "../../model/world/commands.hpp" -#include "../../model/world/commanddispatcher.hpp" -#include "util.hpp" #include #include #include #include +#include "../../model/world/nestedtableproxymodel.hpp" +#include "../../model/world/universalid.hpp" +#include "../../model/world/commands.hpp" +#include "../../model/world/commanddispatcher.hpp" + +#include "tableeditidaction.hpp" +#include "util.hpp" + CSVWorld::NestedTable::NestedTable(CSMDoc::Document& document, CSMWorld::UniversalId id, CSMWorld::NestedTableProxyModel* model, @@ -55,6 +58,9 @@ CSVWorld::NestedTable::NestedTable(CSMDoc::Document& document, connect(mRemoveRowAction, SIGNAL(triggered()), this, SLOT(removeRowActionTriggered())); + + mEditIdAction = new TableEditIdAction(*this, this); + connect(mEditIdAction, SIGNAL(triggered()), this, SLOT(editCell())); } std::vector CSVWorld::NestedTable::getDraggedRecords() const @@ -69,6 +75,15 @@ void CSVWorld::NestedTable::contextMenuEvent (QContextMenuEvent *event) QMenu menu(this); + int currentRow = rowAt(event->y()); + int currentColumn = columnAt(event->x()); + if (mEditIdAction->isValidIdCell(currentRow, currentColumn)) + { + mEditIdAction->setCell(currentRow, currentColumn); + menu.addAction(mEditIdAction); + menu.addSeparator(); + } + if (selectionModel()->selectedRows().size() == 1) menu.addAction(mRemoveRowAction); @@ -92,3 +107,8 @@ void CSVWorld::NestedTable::addNewRowActionTriggered() selectionModel()->selectedRows().size(), mModel->getParentColumn())); } + +void CSVWorld::NestedTable::editCell() +{ + emit editRequest(mEditIdAction->getCurrentId(), ""); +} diff --git a/apps/opencs/view/world/nestedtable.hpp b/apps/opencs/view/world/nestedtable.hpp index 112920401..ba8b6c0e3 100644 --- a/apps/opencs/view/world/nestedtable.hpp +++ b/apps/opencs/view/world/nestedtable.hpp @@ -22,12 +22,15 @@ namespace CSMDoc namespace CSVWorld { + class TableEditIdAction; + class NestedTable : public DragRecordTable { Q_OBJECT QAction *mAddNewRowAction; QAction *mRemoveRowAction; + TableEditIdAction *mEditIdAction; CSMWorld::NestedTableProxyModel* mModel; CSMWorld::CommandDispatcher *mDispatcher; @@ -46,6 +49,11 @@ namespace CSVWorld void removeRowActionTriggered(); void addNewRowActionTriggered(); + + void editCell(); + + signals: + void editRequest(const CSMWorld::UniversalId &id, const std::string &hint); }; } From 30fd711a4799310dcdfd031c863c956d27b8f9ce Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sat, 4 Jul 2015 19:39:53 +0300 Subject: [PATCH 1735/3725] TableEditIdAction: prevent creation of a UniversalId with Type_None --- apps/opencs/view/world/tableeditidaction.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/apps/opencs/view/world/tableeditidaction.cpp b/apps/opencs/view/world/tableeditidaction.cpp index 7ce726e41..4dfc537cc 100644 --- a/apps/opencs/view/world/tableeditidaction.cpp +++ b/apps/opencs/view/world/tableeditidaction.cpp @@ -25,9 +25,13 @@ CSVWorld::TableEditIdAction::TableEditIdAction(const QTableView &table, QWidget void CSVWorld::TableEditIdAction::setCell(int row, int column) { CellData data = getCellData(row, column); - mCurrentId = CSMWorld::UniversalId(CSMWorld::TableMimeData::convertEnums(data.first), - data.second.toUtf8().constData()); - setText("Edit '" + data.second + "'"); + CSMWorld::UniversalId::Type idType = CSMWorld::TableMimeData::convertEnums(data.first); + + if (idType != CSMWorld::UniversalId::Type_None) + { + mCurrentId = CSMWorld::UniversalId(idType, data.second.toUtf8().constData()); + setText("Edit '" + data.second + "'"); + } } CSMWorld::UniversalId CSVWorld::TableEditIdAction::getCurrentId() const @@ -38,5 +42,8 @@ CSMWorld::UniversalId CSVWorld::TableEditIdAction::getCurrentId() const bool CSVWorld::TableEditIdAction::isValidIdCell(int row, int column) const { CellData data = getCellData(row, column); - return CSMWorld::ColumnBase::isId(data.first) && !data.second.isEmpty(); + CSMWorld::UniversalId::Type idType = CSMWorld::TableMimeData::convertEnums(data.first); + return CSMWorld::ColumnBase::isId(data.first) && + idType != CSMWorld::UniversalId::Type_None && + !data.second.isEmpty(); } From c1b06538dc26cc915276f154d087abc1c1549b9e Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sat, 4 Jul 2015 19:55:48 +0300 Subject: [PATCH 1736/3725] Add Edit 'ID' action for nested fields --- apps/opencs/view/world/dialoguesubview.cpp | 38 ++++++++++++++-------- apps/opencs/view/world/dialoguesubview.hpp | 3 ++ 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 4a463ecaa..ed50b81cd 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -428,6 +428,28 @@ void CSVWorld::IdContextMenu::editIdRequest() =============================================================EditWidget===================================================== */ +void CSVWorld::EditWidget::createEditorContextMenu(QWidget *editor, + CSMWorld::ColumnBase::Display display, + int currentRow) const +{ + Q_ASSERT(editor != NULL); + + if (CSMWorld::ColumnBase::isId(display) && + CSMWorld::TableMimeData::convertEnums(display) != CSMWorld::UniversalId::Type_None) + { + int idColumn = mTable->findColumnIndex(CSMWorld::Columns::ColumnId_Id); + QString id = mTable->data(mTable->index(currentRow, idColumn)).toString(); + + IdContextMenu *menu = new IdContextMenu(editor, display); + // Current ID is already opened, so no need to create Edit 'ID' action for it + menu->excludeId(id.toUtf8().constData()); + connect(menu, + SIGNAL(editIdRequest(const CSMWorld::UniversalId &, const std::string &)), + this, + SIGNAL(editIdRequest(const CSMWorld::UniversalId &, const std::string &))); + } +} + CSVWorld::EditWidget::~EditWidget() { for (unsigned i = 0; i < mNestedModels.size(); ++i) @@ -604,19 +626,7 @@ void CSVWorld::EditWidget::remake(int row) label->setEnabled(false); } - if (CSMWorld::ColumnBase::isId(display)) - { - int idColumn = mTable->findColumnIndex(CSMWorld::Columns::ColumnId_Id); - QString id = mTable->data(mTable->index(row, idColumn)).toString(); - - IdContextMenu *menu = new IdContextMenu(editor, display); - // Current ID is already opened, so no need to create Edit 'ID' action for it - menu->excludeId(id.toUtf8().constData()); - connect(menu, - SIGNAL(editIdRequest(const CSMWorld::UniversalId &, const std::string &)), - this, - SIGNAL(editIdRequest(const CSMWorld::UniversalId &, const std::string &))); - } + createEditorContextMenu(editor, display, row); } } else @@ -668,6 +678,8 @@ void CSVWorld::EditWidget::remake(int row) editor->setEnabled(false); label->setEnabled(false); } + + createEditorContextMenu(editor, display, row); } } mNestedTableMapper->setCurrentModelIndex(tree->index(0, 0, tree->index(row, i))); diff --git a/apps/opencs/view/world/dialoguesubview.hpp b/apps/opencs/view/world/dialoguesubview.hpp index 91be5588f..d82936e45 100644 --- a/apps/opencs/view/world/dialoguesubview.hpp +++ b/apps/opencs/view/world/dialoguesubview.hpp @@ -195,6 +195,9 @@ namespace CSVWorld CSMDoc::Document& mDocument; std::vector mNestedModels; //Plain, raw C pointers, deleted in the dtor + void createEditorContextMenu(QWidget *editor, + CSMWorld::ColumnBase::Display display, + int currentRow) const; public: EditWidget (QWidget *parent, int row, CSMWorld::IdTable* table, From 880bc31ddf0bb287aff8252e9b04eb17d26236b4 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sat, 4 Jul 2015 20:30:02 +0300 Subject: [PATCH 1737/3725] TableBottomBox: Creator/Configurator can be closed via Escape --- apps/opencs/view/world/tablebottombox.cpp | 18 ++++++++++++++++++ apps/opencs/view/world/tablebottombox.hpp | 2 ++ 2 files changed, 20 insertions(+) diff --git a/apps/opencs/view/world/tablebottombox.cpp b/apps/opencs/view/world/tablebottombox.cpp index 3a7fa8e8a..d02b76fdc 100644 --- a/apps/opencs/view/world/tablebottombox.cpp +++ b/apps/opencs/view/world/tablebottombox.cpp @@ -6,6 +6,8 @@ #include #include #include +#include +#include #include "creator.hpp" @@ -92,6 +94,7 @@ CSVWorld::TableBottomBox::TableBottomBox (const CreatorFactoryBase& creatorFacto if (mCreator) { + mCreator->installEventFilter(this); mLayout->addWidget (mCreator); connect (mCreator, SIGNAL (done()), this, SLOT (requestDone())); @@ -101,6 +104,7 @@ CSVWorld::TableBottomBox::TableBottomBox (const CreatorFactoryBase& creatorFacto } mExtendedConfigurator = new ExtendedCommandConfigurator (document, id, this); + mExtendedConfigurator->installEventFilter(this); mLayout->addWidget (mExtendedConfigurator); connect (mExtendedConfigurator, SIGNAL (done()), this, SLOT (requestDone())); @@ -118,6 +122,20 @@ CSVWorld::TableBottomBox::~TableBottomBox() delete mCreator; } +bool CSVWorld::TableBottomBox::eventFilter(QObject *object, QEvent *event) +{ + if (event->type() == QEvent::KeyPress) + { + QKeyEvent *keyEvent = static_cast(event); + if (keyEvent->key() == Qt::Key_Escape) + { + requestDone(); + return true; + } + } + return QWidget::eventFilter(object, event); +} + void CSVWorld::TableBottomBox::setStatusBar (bool show) { if (show!=mShowStatusBar) diff --git a/apps/opencs/view/world/tablebottombox.hpp b/apps/opencs/view/world/tablebottombox.hpp index 15ae2924c..a24844890 100644 --- a/apps/opencs/view/world/tablebottombox.hpp +++ b/apps/opencs/view/world/tablebottombox.hpp @@ -59,6 +59,8 @@ namespace CSVWorld virtual ~TableBottomBox(); + virtual bool eventFilter(QObject *object, QEvent *event); + void setEditLock (bool locked); void setStatusBar (bool show); From 4fbd24206b49e4dd981caaae47d3f39b62edeb97 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sat, 4 Jul 2015 20:47:10 +0300 Subject: [PATCH 1738/3725] ExtendedCommandConfigurator: layout changes --- apps/opencs/view/world/extendedcommandconfigurator.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/opencs/view/world/extendedcommandconfigurator.cpp b/apps/opencs/view/world/extendedcommandconfigurator.cpp index d3b97b127..b9b2fa10c 100644 --- a/apps/opencs/view/world/extendedcommandconfigurator.cpp +++ b/apps/opencs/view/world/extendedcommandconfigurator.cpp @@ -30,11 +30,12 @@ CSVWorld::ExtendedCommandConfigurator::ExtendedCommandConfigurator(CSMDoc::Docum mTypeGroup = new QGroupBox(this); QGridLayout *groupLayout = new QGridLayout(mTypeGroup); - groupLayout->setAlignment(Qt::AlignCenter); + groupLayout->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); mTypeGroup->setLayout(groupLayout); QHBoxLayout *mainLayout = new QHBoxLayout(this); mainLayout->setSizeConstraint(QLayout::SetNoConstraint); + mainLayout->setContentsMargins(0, 0, 0, 0); mainLayout->addWidget(mTypeGroup); mainLayout->addWidget(mPerformButton); mainLayout->addWidget(mCancelButton); From c90841d64952cc245c1e8f10d7e61fbef78d01b1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 4 Jul 2015 21:00:01 +0200 Subject: [PATCH 1739/3725] Fix head tracking for NPCs --- apps/openmw/mwrender/npcanimation.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index becfd8f6e..6252d392b 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -850,7 +850,6 @@ void NpcAnimation::addControllers() Animation::addControllers(); mFirstPersonNeckController = NULL; - mHeadController = NULL; WeaponAnimation::deleteControllers(); if (mViewMode == VM_FirstPerson) From 9a02a85a244fc5738dd12de0307256ff81285c47 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 5 Jul 2015 18:07:14 +1200 Subject: [PATCH 1740/3725] Pulled duplicate code into function. --- apps/openmw/mwmechanics/aiwander.cpp | 24 +++++++++++------------- apps/openmw/mwmechanics/aiwander.hpp | 3 +++ 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index f32636b23..3c69a2f5e 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -498,14 +498,8 @@ namespace MWMechanics { assert(mAllowedNodes.size()); unsigned int randNode = Misc::Rng::rollDice(mAllowedNodes.size()); - // NOTE: initially constructed with local (i.e. cell) co-ordinates - // convert dest to use world co-ordinates ESM::Pathgrid::Point dest(mAllowedNodes[randNode]); - if (currentCell->getCell()->isExterior()) - { - dest.mX += currentCell->getCell()->mData.mX * ESM::Land::REAL_SIZE; - dest.mY += currentCell->getCell()->mData.mY * ESM::Land::REAL_SIZE; - } + ToWorldCoordinates(dest, currentCell->getCell()); // actor position is already in world co-ordinates ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(pos)); @@ -537,6 +531,15 @@ namespace MWMechanics return false; // AiWander package not yet completed } + void AiWander::ToWorldCoordinates(ESM::Pathgrid::Point& point, const ESM::Cell * cell) + { + if (cell->isExterior()) + { + point.mX += cell->mData.mX * ESM::Land::REAL_SIZE; + point.mY += cell->mData.mY * ESM::Land::REAL_SIZE; + } + } + void AiWander::trimAllowedNodes(std::vector& nodes, const PathFinder& pathfinder) { @@ -643,12 +646,7 @@ namespace MWMechanics // apply a slight offset to prevent overcrowding dest.mX += static_cast(Misc::Rng::rollProbability() * 128 - 64); dest.mY += static_cast(Misc::Rng::rollProbability() * 128 - 64); - - if (actor.getCell()->isExterior()) - { - dest.mX += actor.getCell()->getCell()->mData.mX * ESM::Land::REAL_SIZE; - dest.mY += actor.getCell()->getCell()->mData.mY * ESM::Land::REAL_SIZE; - } + ToWorldCoordinates(dest, actor.getCell()->getCell()); MWBase::Environment::get().getWorld()->moveObject(actor, static_cast(dest.mX), static_cast(dest.mY), static_cast(dest.mZ)); diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 75b223094..d69a72585 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -118,6 +118,9 @@ namespace MWMechanics GroupIndex_MaxIdle = 9 }; + /// convert point from local (i.e. cell) to world co-ordinates + void ToWorldCoordinates(ESM::Pathgrid::Point& point, const ESM::Cell * cell); + /// lookup table for converting idleSelect value to groupName static const std::string sIdleSelectToGroupName[GroupIndex_MaxIdle - GroupIndex_MinIdle + 1]; }; From f942db2b2761483b9e262fbdfd50302f9c2903b5 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 5 Jul 2015 18:08:09 +1200 Subject: [PATCH 1741/3725] Simplified code. --- apps/openmw/mwmechanics/aiwander.cpp | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 3c69a2f5e..1567f48f6 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -682,19 +682,14 @@ namespace MWMechanics // ... pathgrids don't usually include water, so swimmers ignore them if (mDistance && !actor.getClass().isPureWaterCreature(actor)) { - float cellXOffset = 0; - float cellYOffset = 0; + // get NPC's position in local (i.e. cell) co-ordinates + osg::Vec3f npcPos(mInitialActorPosition); if(cell->isExterior()) { - cellXOffset = static_cast(cell->mData.mX * ESM::Land::REAL_SIZE); - cellYOffset = static_cast(cell->mData.mY * ESM::Land::REAL_SIZE); + npcPos[0] = npcPos[0] - static_cast(cell->mData.mX * ESM::Land::REAL_SIZE); + npcPos[1] = npcPos[1] - static_cast(cell->mData.mY * ESM::Land::REAL_SIZE); } - // convert npcPos to local (i.e. cell) co-ordinates - osg::Vec3f npcPos(mInitialActorPosition); - npcPos[0] = npcPos[0] - cellXOffset; - npcPos[1] = npcPos[1] - cellYOffset; - // mAllowedNodes for this actor with pathgrid point indexes based on mDistance // NOTE: mPoints and mAllowedNodes are in local co-ordinates for(unsigned int counter = 0; counter < pathgrid->mPoints.size(); counter++) From 0095737c407e9513cea0b294338ce84807be8704 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 5 Jul 2015 18:09:14 +1200 Subject: [PATCH 1742/3725] Use correct type of variable. Remove unnecessary casts. --- apps/openmw/mwmechanics/pathgrid.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwmechanics/pathgrid.cpp b/apps/openmw/mwmechanics/pathgrid.cpp index 4e9bc8904..66af864ea 100644 --- a/apps/openmw/mwmechanics/pathgrid.cpp +++ b/apps/openmw/mwmechanics/pathgrid.cpp @@ -313,27 +313,27 @@ namespace MWMechanics return path; // for some reason couldn't build a path // reconstruct path to return, using world co-ordinates - float xCell = 0; - float yCell = 0; + int xCell = 0; + int yCell = 0; if (mIsExterior) { - xCell = static_cast(mPathgrid->mData.mX * ESM::Land::REAL_SIZE); - yCell = static_cast(mPathgrid->mData.mY * ESM::Land::REAL_SIZE); + xCell = mPathgrid->mData.mX * ESM::Land::REAL_SIZE; + yCell = mPathgrid->mData.mY * ESM::Land::REAL_SIZE; } while(graphParent[current] != -1) { ESM::Pathgrid::Point pt = mPathgrid->mPoints[current]; - pt.mX += static_cast(xCell); - pt.mY += static_cast(yCell); + pt.mX += xCell; + pt.mY += yCell; path.push_front(pt); current = graphParent[current]; } // add first node to path explicitly ESM::Pathgrid::Point pt = mPathgrid->mPoints[start]; - pt.mX += static_cast(xCell); - pt.mY += static_cast(yCell); + pt.mX += xCell; + pt.mY += yCell; path.push_front(pt); return path; } From 76f20b8b2024ca59ba0349f9c9988c4abafa81fb Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 5 Jul 2015 18:10:02 +1200 Subject: [PATCH 1743/3725] fix 'WIN32_LEAN_AND_MEAN' macro redefinition warning. --- apps/openmw/main.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index dc58daed9..85a0dbe55 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -14,7 +14,9 @@ #if defined(_WIN32) // For OutputDebugString +#ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN +#endif #include // makes __argc and __argv available on windows #include From eb2aa965b9fece4dbae0b414e0a737a8ca6e43f5 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 5 Jul 2015 18:17:18 +1200 Subject: [PATCH 1744/3725] Extracted function SetCurrentNodeToClosestAllowedNode() --- apps/openmw/mwmechanics/aiwander.cpp | 33 ++++++++++++++++++---------- apps/openmw/mwmechanics/aiwander.hpp | 2 ++ 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 1567f48f6..6f2c6969c 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -1,5 +1,7 @@ #include "aiwander.hpp" +#include + #include #include @@ -700,23 +702,30 @@ namespace MWMechanics } if(!mAllowedNodes.empty()) { - osg::Vec3f firstNodePos(PathFinder::MakeOsgVec3(mAllowedNodes[0])); - float closestNode = (npcPos - firstNodePos).length2(); - unsigned int index = 0; - for(unsigned int counterThree = 1; counterThree < mAllowedNodes.size(); counterThree++) - { - osg::Vec3f nodePos(PathFinder::MakeOsgVec3(mAllowedNodes[counterThree])); - float tempDist = (npcPos - nodePos).length2(); - if(tempDist < closestNode) - index = counterThree; - } - mCurrentNode = mAllowedNodes[index]; - mAllowedNodes.erase(mAllowedNodes.begin() + index); + SetCurrentNodeToClosestAllowedNode(npcPos); } mStoredAvailableNodes = true; // set only if successful in finding allowed nodes } } + void AiWander::SetCurrentNodeToClosestAllowedNode(osg::Vec3f npcPos) + { + float distanceToClosestNode = FLT_MAX; + unsigned int index = 0; + for (unsigned int counterThree = 0; counterThree < mAllowedNodes.size(); counterThree++) + { + osg::Vec3f nodePos(PathFinder::MakeOsgVec3(mAllowedNodes[counterThree])); + float tempDist = (npcPos - nodePos).length2(); + if (tempDist < distanceToClosestNode) + { + index = counterThree; + distanceToClosestNode = tempDist; + } + } + mCurrentNode = mAllowedNodes[index]; + mAllowedNodes.erase(mAllowedNodes.begin() + index); + } + void AiWander::writeState(ESM::AiSequence::AiSequence &sequence) const { std::auto_ptr wander(new ESM::AiSequence::AiWander()); diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index d69a72585..94758afc8 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -121,6 +121,8 @@ namespace MWMechanics /// convert point from local (i.e. cell) to world co-ordinates void ToWorldCoordinates(ESM::Pathgrid::Point& point, const ESM::Cell * cell); + void SetCurrentNodeToClosestAllowedNode(osg::Vec3f npcPos); + /// lookup table for converting idleSelect value to groupName static const std::string sIdleSelectToGroupName[GroupIndex_MaxIdle - GroupIndex_MinIdle + 1]; }; From 1239667cb415835d2d4cb6f3aba941c92e4fecaa Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 5 Jul 2015 18:21:35 +1200 Subject: [PATCH 1745/3725] AiWander uses points between PathGrid points (Fixes #1317) When there is only on PathGrid point within a NPC's wander distance, expand possible wander destinations by using positions between PathGrid points. --- apps/openmw/mwmechanics/aiwander.cpp | 44 ++++++++++++++++++++++++- apps/openmw/mwmechanics/aiwander.hpp | 4 +++ apps/openmw/mwmechanics/pathfinding.hpp | 4 ++- 3 files changed, 50 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 6f2c6969c..25ed4694b 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -216,7 +216,7 @@ namespace MWMechanics // Are we there yet? bool& chooseAction = storage.mChooseAction; if(walking && - storage.mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], 64.f)) + storage.mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1])) { stopWalking(actor, storage); moveNow = false; @@ -694,11 +694,19 @@ namespace MWMechanics // mAllowedNodes for this actor with pathgrid point indexes based on mDistance // NOTE: mPoints and mAllowedNodes are in local co-ordinates + int pointIndex = 0; for(unsigned int counter = 0; counter < pathgrid->mPoints.size(); counter++) { osg::Vec3f nodePos(PathFinder::MakeOsgVec3(pathgrid->mPoints[counter])); if((npcPos - nodePos).length2() <= mDistance * mDistance) + { mAllowedNodes.push_back(pathgrid->mPoints[counter]); + pointIndex = counter; + } + } + if (mAllowedNodes.size() == 1) + { + AddNonPathGridAllowedPoints(npcPos, pathgrid, pointIndex); } if(!mAllowedNodes.empty()) { @@ -708,6 +716,40 @@ namespace MWMechanics } } + // When only one path grid point in wander distance, + // additional points for NPC to wander to are: + // 1. NPC's initial location + // 2. Partway along the path between the point and its connected points. + void AiWander::AddNonPathGridAllowedPoints(osg::Vec3f npcPos, const ESM::Pathgrid * pathGrid, int pointIndex) + { + mAllowedNodes.push_back(PathFinder::MakePathgridPoint(npcPos)); + for (std::vector::const_iterator it = pathGrid->mEdges.begin(); it != pathGrid->mEdges.end(); ++it) + { + if (it->mV0 == pointIndex) + { + AddPointBetweenPathGridPoints(pathGrid->mPoints[it->mV0], pathGrid->mPoints[it->mV1]); + } + } + } + + void AiWander::AddPointBetweenPathGridPoints(const ESM::Pathgrid::Point& start, const ESM::Pathgrid::Point& end) + { + osg::Vec3f vectorStart = PathFinder::MakeOsgVec3(start); + osg::Vec3f delta = PathFinder::MakeOsgVec3(end) - vectorStart; + float length = delta.length(); + delta.normalize(); + + // destination must be far enough away that NPC will need to move to get there. + const int threshold = PathFinder::PathTolerance * 2; + int distance = std::max(mDistance / 2, threshold); + + // must not travel more than 1/2 way between waypoints, + // otherwise, NPC goes to far endpoint then comes back. Looks weird. + distance = std::min(distance, static_cast(length / 2)); + delta *= distance; + mAllowedNodes.push_back(PathFinder::MakePathgridPoint(vectorStart + delta)); + } + void AiWander::SetCurrentNodeToClosestAllowedNode(osg::Vec3f npcPos) { float distanceToClosestNode = FLT_MAX; diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 94758afc8..18f98cfd5 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -123,6 +123,10 @@ namespace MWMechanics void SetCurrentNodeToClosestAllowedNode(osg::Vec3f npcPos); + void AddNonPathGridAllowedPoints(osg::Vec3f npcPos, const ESM::Pathgrid * pathGrid, int pointIndex); + + void AddPointBetweenPathGridPoints(const ESM::Pathgrid::Point& start, const ESM::Pathgrid::Point& end); + /// lookup table for converting idleSelect value to groupName static const std::string sIdleSelectToGroupName[GroupIndex_MaxIdle - GroupIndex_MinIdle + 1]; }; diff --git a/apps/openmw/mwmechanics/pathfinding.hpp b/apps/openmw/mwmechanics/pathfinding.hpp index 45d9dd973..a4886a840 100644 --- a/apps/openmw/mwmechanics/pathfinding.hpp +++ b/apps/openmw/mwmechanics/pathfinding.hpp @@ -19,6 +19,8 @@ namespace MWMechanics public: PathFinder(); + static const int PathTolerance = 32; + static float sgn(float val) { if(val > 0) @@ -35,7 +37,7 @@ namespace MWMechanics void clearPath(); - bool checkPathCompleted(float x, float y, float tolerance=32.f); + bool checkPathCompleted(float x, float y, float tolerance = PathTolerance); ///< \Returns true if we are within \a tolerance units of the last path point. /// In degrees From 3ffa0aa1858c6b5ab9c1cb871a09fbc4d1601336 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sun, 5 Jul 2015 15:36:41 +0300 Subject: [PATCH 1746/3725] Count of nested columns can be retrieved for a collection with no records --- apps/opencs/model/world/nestedidcollection.hpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/world/nestedidcollection.hpp b/apps/opencs/model/world/nestedidcollection.hpp index 792a13b7d..56b112365 100644 --- a/apps/opencs/model/world/nestedidcollection.hpp +++ b/apps/opencs/model/world/nestedidcollection.hpp @@ -161,8 +161,19 @@ namespace CSMWorld template int NestedIdCollection::getNestedColumnsCount(int row, int column) const { - return getAdapter(Collection::getColumn(column)).getColumnsCount( - Collection::getRecord(row)); + const ColumnBase &nestedColumn = Collection::getColumn(column); + int numRecords = Collection::getSize(); + if (row >= 0 && row < numRecords) + { + const Record& record = Collection::getRecord(row); + return getAdapter(nestedColumn).getColumnsCount(record); + } + else + { + // If the row is invalid (or there no records), retrieve the column count using a blank record + const Record record; + return getAdapter(nestedColumn).getColumnsCount(record); + } } template From 531bca1273e7b9dbd98b34a5f3747a3099467d71 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 5 Jul 2015 18:09:13 +0200 Subject: [PATCH 1747/3725] Add a threshold for changing aicombat targets (Fixes #2755) --- apps/openmw/mwmechanics/aisequence.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/openmw/mwmechanics/aisequence.cpp b/apps/openmw/mwmechanics/aisequence.cpp index 3e1f89624..fb6450d16 100644 --- a/apps/openmw/mwmechanics/aisequence.cpp +++ b/apps/openmw/mwmechanics/aisequence.cpp @@ -184,6 +184,11 @@ void AiSequence::execute (const MWWorld::Ptr& actor, CharacterController& charac const ESM::Position &targetPos = target.getRefData().getPosition(); float distTo = (targetPos.asVec3() - vActorPos).length(); + + // Small threshold for changing target + if (it == mPackages.begin()) + distTo = std::max(0.f, distTo - 50.f); + if (distTo < nearestDist) { nearestDist = distTo; From ceb3dea55cc70d3518d1253b00ff45ecc21ffc5f Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sun, 5 Jul 2015 20:11:21 +0300 Subject: [PATCH 1748/3725] Rewording of the user setting for extended configuration --- apps/opencs/model/settings/usersettings.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/settings/usersettings.cpp b/apps/opencs/model/settings/usersettings.cpp index cb001fea9..05b06d562 100644 --- a/apps/opencs/model/settings/usersettings.cpp +++ b/apps/opencs/model/settings/usersettings.cpp @@ -217,10 +217,13 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() jumpToAdded->setDeclaredValues (jumpValues); Setting *extendedConfig = createSetting (Type_CheckBox, "extended-config", - "Enable configuration of the extended delete/revert"); + "Manually specify affected record types for an extended delete/revert"); extendedConfig->setDefaultValue("false"); - extendedConfig->setToolTip("Enables the ability to specify tables that will be affected by " - "the extended delete/revert command"); + extendedConfig->setToolTip("Delete and revert commands have an extended form that also affects " + "associated records.\n\n" + "If this option is enabled, types of affected records are selected " + "manually before a command execution.\nOtherwise, all associated " + "records are deleted/reverted immediately."); } declareSection ("report-input", "Report Input"); From 3c6bc7406219e1fec46fe79fa9fde76a7dc999c5 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sun, 5 Jul 2015 22:10:37 +0300 Subject: [PATCH 1749/3725] Close the extended configurator when all respective records were removed outside --- .../world/extendedcommandconfigurator.cpp | 40 ++++++++++++++++++- .../world/extendedcommandconfigurator.hpp | 4 ++ 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/world/extendedcommandconfigurator.cpp b/apps/opencs/view/world/extendedcommandconfigurator.cpp index b9b2fa10c..d243ff256 100644 --- a/apps/opencs/view/world/extendedcommandconfigurator.cpp +++ b/apps/opencs/view/world/extendedcommandconfigurator.cpp @@ -1,12 +1,17 @@ #include "extendedcommandconfigurator.hpp" +#include + #include #include #include #include #include +#include "../../model/doc/document.hpp" + #include "../../model/world/commanddispatcher.hpp" +#include "../../model/world/data.hpp" CSVWorld::ExtendedCommandConfigurator::ExtendedCommandConfigurator(CSMDoc::Document &document, const CSMWorld::UniversalId &id, @@ -14,10 +19,13 @@ CSVWorld::ExtendedCommandConfigurator::ExtendedCommandConfigurator(CSMDoc::Docum : QWidget(parent), mNumUsedCheckBoxes(0), mNumChecked(0), - mMode(Mode_None) + mMode(Mode_None), + mData(document.getData()) { mCommandDispatcher = new CSMWorld::CommandDispatcher(document, id, this); + connect(&mData, SIGNAL(idListChanged()), this, SLOT(dataIdListChanged())); + mPerformButton = new QPushButton(this); mPerformButton->setDefault(true); mPerformButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); @@ -48,7 +56,8 @@ void CSVWorld::ExtendedCommandConfigurator::configure(CSVWorld::ExtendedCommandC if (mMode != Mode_None) { mPerformButton->setText((mMode == Mode_Delete) ? "Extended Delete" : "Extended Revert"); - mCommandDispatcher->setSelection(selectedIds); + mSelectedIds = selectedIds; + mCommandDispatcher->setSelection(mSelectedIds); setupCheckBoxes(mCommandDispatcher->getExtendedTypes()); setupGroupLayout(); } @@ -177,3 +186,30 @@ void CSVWorld::ExtendedCommandConfigurator::checkBoxStateChanged(int state) mPerformButton->setEnabled(mNumChecked > 0); } + +void CSVWorld::ExtendedCommandConfigurator::dataIdListChanged() +{ + bool idsRemoved = false; + for (int i = 0; i < static_cast(mSelectedIds.size()); ++i) + { + if (!mData.hasId(mSelectedIds[i])) + { + std::swap(mSelectedIds[i], mSelectedIds.back()); + mSelectedIds.pop_back(); + idsRemoved = true; + --i; + } + } + + // If all selected IDs were removed, cancel the configurator + if (mSelectedIds.empty()) + { + emit done(); + return; + } + + if (idsRemoved) + { + mCommandDispatcher->setSelection(mSelectedIds); + } +} diff --git a/apps/opencs/view/world/extendedcommandconfigurator.hpp b/apps/opencs/view/world/extendedcommandconfigurator.hpp index 590cabab1..2e06e9c9c 100644 --- a/apps/opencs/view/world/extendedcommandconfigurator.hpp +++ b/apps/opencs/view/world/extendedcommandconfigurator.hpp @@ -21,6 +21,7 @@ namespace CSMDoc namespace CSMWorld { class CommandDispatcher; + class Data; } namespace CSVWorld @@ -44,6 +45,8 @@ namespace CSVWorld Mode mMode; CSMWorld::CommandDispatcher *mCommandDispatcher; + CSMWorld::Data &mData; + std::vector mSelectedIds; void setupGroupLayout(); void setupCheckBoxes(const std::vector &types); @@ -61,6 +64,7 @@ namespace CSVWorld private slots: void performExtendedCommand(); void checkBoxStateChanged(int state); + void dataIdListChanged(); signals: void done(); From 47d21ff4b34c1192746ba7533d6c0815e7afc194 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sun, 5 Jul 2015 22:49:48 +0300 Subject: [PATCH 1750/3725] Add edit locking to ExtendedCommandConfigurator --- .../world/extendedcommandconfigurator.cpp | 26 ++++++++++++++++++- .../world/extendedcommandconfigurator.hpp | 4 +++ apps/opencs/view/world/tablebottombox.cpp | 1 + 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/apps/opencs/view/world/extendedcommandconfigurator.cpp b/apps/opencs/view/world/extendedcommandconfigurator.cpp index d243ff256..2cf6222a6 100644 --- a/apps/opencs/view/world/extendedcommandconfigurator.cpp +++ b/apps/opencs/view/world/extendedcommandconfigurator.cpp @@ -20,7 +20,8 @@ CSVWorld::ExtendedCommandConfigurator::ExtendedCommandConfigurator(CSMDoc::Docum mNumUsedCheckBoxes(0), mNumChecked(0), mMode(Mode_None), - mData(document.getData()) + mData(document.getData()), + mEditLock(false) { mCommandDispatcher = new CSMWorld::CommandDispatcher(document, id, this); @@ -58,8 +59,19 @@ void CSVWorld::ExtendedCommandConfigurator::configure(CSVWorld::ExtendedCommandC mPerformButton->setText((mMode == Mode_Delete) ? "Extended Delete" : "Extended Revert"); mSelectedIds = selectedIds; mCommandDispatcher->setSelection(mSelectedIds); + setupCheckBoxes(mCommandDispatcher->getExtendedTypes()); setupGroupLayout(); + lockWidgets(mEditLock); + } +} + +void CSVWorld::ExtendedCommandConfigurator::setEditLock(bool locked) +{ + if (mEditLock != locked) + { + mEditLock = locked; + lockWidgets(mEditLock); } } @@ -144,6 +156,18 @@ void CSVWorld::ExtendedCommandConfigurator::setupCheckBoxes(const std::vectorsetEnabled(!mEditLock && mNumChecked > 0); + + CheckBoxMap::const_iterator current = mTypeCheckBoxes.begin(); + CheckBoxMap::const_iterator end = mTypeCheckBoxes.end(); + for (int i = 0; current != end && i < mNumUsedCheckBoxes; ++current, ++i) + { + current->first->setEnabled(!mEditLock); + } +} + void CSVWorld::ExtendedCommandConfigurator::performExtendedCommand() { std::vector types; diff --git a/apps/opencs/view/world/extendedcommandconfigurator.hpp b/apps/opencs/view/world/extendedcommandconfigurator.hpp index 2e06e9c9c..641b4a524 100644 --- a/apps/opencs/view/world/extendedcommandconfigurator.hpp +++ b/apps/opencs/view/world/extendedcommandconfigurator.hpp @@ -48,8 +48,11 @@ namespace CSVWorld CSMWorld::Data &mData; std::vector mSelectedIds; + bool mEditLock; + void setupGroupLayout(); void setupCheckBoxes(const std::vector &types); + void lockWidgets(bool locked); public: ExtendedCommandConfigurator(CSMDoc::Document &document, @@ -57,6 +60,7 @@ namespace CSVWorld QWidget *parent = 0); void configure(Mode mode, const std::vector &selectedIds); + void setEditLock(bool locked); protected: virtual void resizeEvent(QResizeEvent *event); diff --git a/apps/opencs/view/world/tablebottombox.cpp b/apps/opencs/view/world/tablebottombox.cpp index d02b76fdc..225ff32a4 100644 --- a/apps/opencs/view/world/tablebottombox.cpp +++ b/apps/opencs/view/world/tablebottombox.cpp @@ -115,6 +115,7 @@ void CSVWorld::TableBottomBox::setEditLock (bool locked) { if (mCreator) mCreator->setEditLock (locked); + mExtendedConfigurator->setEditLock (locked); } CSVWorld::TableBottomBox::~TableBottomBox() From aaaee74a4db0cc3ba1c5760b91efff1066d99b4f Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Sun, 5 Jul 2015 21:44:17 +0200 Subject: [PATCH 1751/3725] Fix the comments --- apps/openmw/mwrender/animation.hpp | 1 - apps/openmw/mwrender/sky.cpp | 9 +++++++-- apps/openmw/mwrender/weaponanimation.hpp | 2 -- components/sceneutil/controller.hpp | 1 + 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index d45d19cf9..73079e9a9 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -93,7 +93,6 @@ protected: boost::shared_ptr mTimePtr; public: - virtual ~AnimationTime() { } void setTimePtr(boost::shared_ptr time) { mTimePtr = time; } diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index c7b0d3e41..d9a212889 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -721,12 +722,16 @@ public: if (stateset->getAttribute(osg::StateAttribute::MATERIAL)) { SceneUtil::CompositeStateSetUpdater* composite = NULL; - osg::NodeCallback* callback = dynamic_cast(node.getUpdateCallback()); +#if OSG_MIN_VERSION_REQUIRED(3,3,3) + osg::Callback* callback = node.getUpdateCallback(); +#else + osg::NodeCallback* callback = node.getUpdateCallback(); +#endif while (callback) { if ((composite = dynamic_cast(callback))) break; - callback = dynamic_cast(callback->getNestedCallback()); + callback = callback->getNestedCallback(); } if (composite) diff --git a/apps/openmw/mwrender/weaponanimation.hpp b/apps/openmw/mwrender/weaponanimation.hpp index fae459611..3bf0fb721 100644 --- a/apps/openmw/mwrender/weaponanimation.hpp +++ b/apps/openmw/mwrender/weaponanimation.hpp @@ -19,8 +19,6 @@ namespace MWRender float mStartTime; public: WeaponAnimationTime(Animation* animation) : mAnimation(animation), mStartTime(0) {} - virtual ~WeaponAnimationTime() { } - void setGroup(const std::string& group); void updateStartTime(); diff --git a/components/sceneutil/controller.hpp b/components/sceneutil/controller.hpp index 0ef1356e7..7399ecad5 100644 --- a/components/sceneutil/controller.hpp +++ b/components/sceneutil/controller.hpp @@ -11,6 +11,7 @@ namespace SceneUtil class ControllerSource { public: + virtual ~ControllerSource() { } virtual float getValue(osg::NodeVisitor* nv) = 0; }; From 8c6ba01c0846ef28759b1090a692ca322acdd966 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Mon, 6 Jul 2015 10:59:40 +0200 Subject: [PATCH 1752/3725] Fix a few merge issues --- CI/before_script.msvc.sh | 46 +++++----------------------------------- 1 file changed, 5 insertions(+), 41 deletions(-) diff --git a/CI/before_script.msvc.sh b/CI/before_script.msvc.sh index c5c15008c..a53b6d795 100644 --- a/CI/before_script.msvc.sh +++ b/CI/before_script.msvc.sh @@ -222,9 +222,11 @@ if [ -z $SKIP_DOWNLOAD ]; then OSG-3.3.8-win$BITS.7z # Qt - download "Qt 4.8.6" \ - http://sourceforge.net/projects/qt64ng/files/qt/$ARCHNAME/4.8.6/msvc2013/qt-4.8.6-x$ARCHSUFFIX-msvc2013.7z \ - qt$BITS-4.8.6.7z + if [ -z $APPVEYOR ]; then + download "Qt 4.8.6" \ + http://sourceforge.net/projects/qt64ng/files/qt/$ARCHNAME/4.8.6/msvc2013/qt-4.8.6-x$ARCHSUFFIX-msvc2013.7z \ + qt$BITS-4.8.6.7z + fi # SDL2 download "SDL 2.0.3" \ @@ -557,44 +559,6 @@ else esac fi -if [ -z $APPVEYOR ]; then - echo " (Outside of AppVeyor, doing full build.)" -else - case $STEP in - components ) - echo " Subproject: Components." - add_cmake_opts -DBUILD_ESSIMPORTER=no \ - -DBUILD_LAUNCHER=no \ - -DBUILD_MWINIIMPORTER=no \ - -DBUILD_OPENCS=no \ - -DBUILD_OPENMW=no \ - -DBUILD_WIZARD=no - rm -rf components - ;; - openmw ) - echo " Subproject: OpenMW." - add_cmake_opts -DBUILD_ESSIMPORTER=no \ - -DBUILD_LAUNCHER=no \ - -DBUILD_MWINIIMPORTER=no \ - -DBUILD_OPENCS=no \ - -DBUILD_WIZARD=no - ;; - opencs ) - echo " Subproject: OpenCS." - add_cmake_opts -DBUILD_ESSIMPORTER=no \ - -DBUILD_LAUNCHER=no \ - -DBUILD_MWINIIMPORTER=no \ - -DBUILD_OPENMW=no \ - -DBUILD_WIZARD=no - ;; - misc ) - echo " Subproject: Misc." - add_cmake_opts -DBUILD_OPENCS=no \ - -DBUILD_OPENMW=no - ;; - esac -fi - if [ -z $VERBOSE ]; then printf " Configuring... " else From 13f289d1a513735bd3bd13b865f02f3a3b912b56 Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Mon, 6 Jul 2015 16:35:45 +0200 Subject: [PATCH 1753/3725] Fix calculation of selected blocks in ScriptEdit --- apps/opencs/view/world/scriptedit.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/opencs/view/world/scriptedit.cpp b/apps/opencs/view/world/scriptedit.cpp index ad2cddbf8..25f4fd077 100644 --- a/apps/opencs/view/world/scriptedit.cpp +++ b/apps/opencs/view/world/scriptedit.cpp @@ -276,11 +276,11 @@ void CSVWorld::ScriptEdit::lineNumberAreaPaintEvent(QPaintEvent *event) if(textCursor().hasSelection()) { QString str = textCursor().selection().toPlainText(); - int selectedLines = str.count("\n")+1; + int offset = str.count("\n"); if(textCursor().position() < textCursor().anchor()) - endBlock += selectedLines; + endBlock += offset; else - startBlock -= selectedLines; + startBlock -= offset; } painter.setBackgroundMode(Qt::OpaqueMode); QFont font = painter.font(); From ad47fb7b518db892c70e769c2f58933a572f926f Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Tue, 7 Jul 2015 15:50:40 +0200 Subject: [PATCH 1754/3725] Fix build script --- CI/before_script.msvc.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/CI/before_script.msvc.sh b/CI/before_script.msvc.sh index 06b14f2fe..7c544ad54 100644 --- a/CI/before_script.msvc.sh +++ b/CI/before_script.msvc.sh @@ -474,7 +474,8 @@ else fi add_cmake_opts -DDESIRED_QT_VERSION=5 \ - -DQT_QMAKE_EXECUTABLE="$QT_SDK/bin/qmake.exe" + -DQT_QMAKE_EXECUTABLE="$QT_SDK/bin/qmake.exe" \ + -DCMAKE_PREFIX_PATH="$QT_SDK" fi @@ -507,7 +508,8 @@ echo "Setting up OpenMW build..." add_cmake_opts -DBUILD_BSATOOL=no \ -DBUILD_ESMTOOL=no \ - -DBUILD_MYGUI_PLUGIN=no + -DBUILD_MYGUI_PLUGIN=no \ + -DOPENMW_MP_BUILD=on if [ -z $APPVEYOR ]; then echo " (Outside of AppVeyor, doing full build.)" From f8485211a1ea5c00310fdbf7bd7ad0fa5dcd32d6 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Tue, 7 Jul 2015 15:54:03 +0200 Subject: [PATCH 1755/3725] Fix merge issue --- CI/before_script.msvc.sh | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/CI/before_script.msvc.sh b/CI/before_script.msvc.sh index a25e238d0..6543df4d3 100644 --- a/CI/before_script.msvc.sh +++ b/CI/before_script.msvc.sh @@ -222,9 +222,11 @@ if [ -z $SKIP_DOWNLOAD ]; then OSG-3.3.8-win$BITS.7z # Qt - download "Qt 4.8.6" \ - http://sourceforge.net/projects/qt64ng/files/qt/$ARCHNAME/4.8.6/msvc2013/qt-4.8.6-x$ARCHSUFFIX-msvc2013.7z \ - qt$BITS-4.8.6.7z + if [ -z $APPVEYOR ]; then + download "Qt 4.8.6" \ + http://sourceforge.net/projects/qt64ng/files/qt/$ARCHNAME/4.8.6/msvc2013/qt-4.8.6-x$ARCHSUFFIX-msvc2013.7z \ + qt$BITS-4.8.6.7z + fi # SDL2 download "SDL 2.0.3" \ From a831e89a43cc72c1bd8ffefb7570a7c73be45c38 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Tue, 7 Jul 2015 16:21:56 +0200 Subject: [PATCH 1756/3725] Fix MyGUI include dir, and properly return error codes --- CI/before_script.msvc.sh | 3 +-- CI/build.msvc.sh | 8 ++++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/CI/before_script.msvc.sh b/CI/before_script.msvc.sh index 6543df4d3..0d72806fb 100644 --- a/CI/before_script.msvc.sh +++ b/CI/before_script.msvc.sh @@ -372,8 +372,7 @@ fi MYGUI_SDK="`real_pwd`/MyGUI" add_cmake_opts -DMYGUISDK="$MYGUI_SDK" \ - -DMYGUI_INCLUDE_DIRS="$MYGUI_SDK/include" \ - -DMYGUI_PLATFORM_INCLUDE_DIRS="$MYGUI_SDK/include/MYGUI" \ + -DMYGUI_INCLUDE_DIRS="$MYGUI_SDK/include/MYGUI" \ -DMYGUI_PREQUEST_FILE="$MYGUI_SDK/include/MYGUI/MyGUI_Prerequest.h" if [ $CONFIGURATION == "Debug" ]; then diff --git a/CI/build.msvc.sh b/CI/build.msvc.sh index d426ef90d..731c51eda 100644 --- a/CI/build.msvc.sh +++ b/CI/build.msvc.sh @@ -50,6 +50,10 @@ else msbuild OpenMW.sln //t:Build //m:8 //logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" fi -if [ ! -z $PACKAGE ]; then +RET=$? +if [ $RET -eq 0 ] && [ ! -z $PACKAGE ]; then msbuild PACKAGE.vcxproj //t:Build //m:8 -fi \ No newline at end of file + RET=$? +fi + +exit $RET From 3655ef16af864b7c50c003e2c8905f06b7bb15cf Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Tue, 7 Jul 2015 19:16:32 +0200 Subject: [PATCH 1757/3725] Explicitly instantiate ESM::StatState --- apps/essimporter/convertplayer.cpp | 2 + apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 1 + apps/openmw/mwgui/inventorywindow.cpp | 2 + apps/openmw/mwgui/mapwindow.cpp | 1 + apps/openmw/mwgui/quickkeysmenu.cpp | 1 + apps/openmw/mwgui/windowmanagerimp.cpp | 3 ++ apps/openmw/mwmechanics/actors.cpp | 2 + apps/openmw/mwmechanics/creaturestats.cpp | 2 + .../mwmechanics/mechanicsmanagerimp.cpp | 1 + apps/openmw/mwmechanics/stat.hpp | 1 + apps/openmw/mwworld/cellstore.cpp | 1 + apps/openmw/mwworld/projectilemanager.cpp | 1 + apps/openmw/mwworld/worldimp.cpp | 3 ++ components/esm/creaturestats.cpp | 2 + components/esm/statstate.cpp | 52 +++++++++++++++++++ components/esm/statstate.hpp | 48 ++--------------- 16 files changed, 78 insertions(+), 45 deletions(-) create mode 100644 components/esm/statstate.cpp diff --git a/apps/essimporter/convertplayer.cpp b/apps/essimporter/convertplayer.cpp index af0119a46..5718201f7 100644 --- a/apps/essimporter/convertplayer.cpp +++ b/apps/essimporter/convertplayer.cpp @@ -1,5 +1,7 @@ #include "convertplayer.hpp" +#include + namespace ESSImport { diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 139862a5a..042267ebe 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 3ecfc64b2..52ff2ee10 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -10,6 +10,8 @@ #include +#include + #include #include diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 3e855c4d0..442fbeb08 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -12,6 +12,7 @@ #include #include +#include #include #include diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index 01d0a339b..8c919e8bd 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include "../mwworld/inventorystore.hpp" diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 515265bd9..9cf957522 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -22,6 +22,9 @@ #include +#include +#include + #include #include diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index f0b47ac7b..5f8b70651 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -4,6 +4,8 @@ #include +#include +#include #include #include "../mwworld/esmstore.hpp" diff --git a/apps/openmw/mwmechanics/creaturestats.cpp b/apps/openmw/mwmechanics/creaturestats.cpp index f480efc71..48374c173 100644 --- a/apps/openmw/mwmechanics/creaturestats.cpp +++ b/apps/openmw/mwmechanics/creaturestats.cpp @@ -3,6 +3,8 @@ #include #include +#include +#include #include "../mwworld/esmstore.hpp" diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 7bc6a34ae..fef99dc61 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -6,6 +6,7 @@ #include +#include #include #include "../mwworld/esmstore.hpp" diff --git a/apps/openmw/mwmechanics/stat.hpp b/apps/openmw/mwmechanics/stat.hpp index 64cc66520..0820d2015 100644 --- a/apps/openmw/mwmechanics/stat.hpp +++ b/apps/openmw/mwmechanics/stat.hpp @@ -1,6 +1,7 @@ #ifndef GAME_MWMECHANICS_STAT_H #define GAME_MWMECHANICS_STAT_H +#include #include #include diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 4e6c6f116..b33a6f8db 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include #include diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index f083bcb4a..6295ed159 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -2,6 +2,7 @@ #include +#include #include #include #include diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 4b14ea602..ff82160d1 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -12,6 +12,9 @@ #include #include +#include +#include + #include #include diff --git a/components/esm/creaturestats.cpp b/components/esm/creaturestats.cpp index 89d865c1d..9bdbf9668 100644 --- a/components/esm/creaturestats.cpp +++ b/components/esm/creaturestats.cpp @@ -1,4 +1,6 @@ #include "creaturestats.hpp" +#include "esmreader.hpp" +#include "esmwriter.hpp" void ESM::CreatureStats::load (ESMReader &esm) { diff --git a/components/esm/statstate.cpp b/components/esm/statstate.cpp new file mode 100644 index 000000000..e95295cc9 --- /dev/null +++ b/components/esm/statstate.cpp @@ -0,0 +1,52 @@ +#include "statstate.hpp" + +#include "esmreader.hpp" +#include "esmwriter.hpp" + +namespace ESM +{ + template + StatState::StatState() : mBase(0), mMod(0), mCurrent(0), mDamage(0), mProgress(0) {} + + template + void StatState::load(ESMReader &esm) + { + esm.getHNT(mBase, "STBA"); + + mMod = 0; + esm.getHNOT(mMod, "STMO"); + mCurrent = 0; + esm.getHNOT(mCurrent, "STCU"); + + // mDamage was changed to a float; ensure backwards compatibility + T oldDamage = 0; + esm.getHNOT(oldDamage, "STDA"); + mDamage = static_cast(oldDamage); + + esm.getHNOT(mDamage, "STDF"); + + mProgress = 0; + esm.getHNOT(mProgress, "STPR"); + } + + template + void StatState::save(ESMWriter &esm) const + { + esm.writeHNT("STBA", mBase); + + if (mMod != 0) + esm.writeHNT("STMO", mMod); + + if (mCurrent) + esm.writeHNT("STCU", mCurrent); + + if (mDamage) + esm.writeHNT("STDF", mDamage); + + if (mProgress) + esm.writeHNT("STPR", mProgress); + } + + template class StatState; + template class StatState; +} diff --git a/components/esm/statstate.hpp b/components/esm/statstate.hpp index f57ba9f30..47aeb0331 100644 --- a/components/esm/statstate.hpp +++ b/components/esm/statstate.hpp @@ -1,11 +1,11 @@ #ifndef OPENMW_ESM_STATSTATE_H #define OPENMW_ESM_STATSTATE_H -#include "esmreader.hpp" -#include "esmwriter.hpp" - namespace ESM { + class ESMReader; + class ESMWriter; + // format 0, saved games only template @@ -23,48 +23,6 @@ namespace ESM void load (ESMReader &esm); void save (ESMWriter &esm) const; }; - - template - StatState::StatState() : mBase (0), mMod (0), mCurrent (0), mDamage (0), mProgress (0) {} - - template - void StatState::load (ESMReader &esm) - { - esm.getHNT (mBase, "STBA"); - - mMod = 0; - esm.getHNOT (mMod, "STMO"); - mCurrent = 0; - esm.getHNOT (mCurrent, "STCU"); - - // mDamage was changed to a float; ensure backwards compatibility - T oldDamage = 0; - esm.getHNOT(oldDamage, "STDA"); - mDamage = static_cast(oldDamage); - - esm.getHNOT (mDamage, "STDF"); - - mProgress = 0; - esm.getHNOT (mProgress, "STPR"); - } - - template - void StatState::save (ESMWriter &esm) const - { - esm.writeHNT ("STBA", mBase); - - if (mMod != 0) - esm.writeHNT ("STMO", mMod); - - if (mCurrent) - esm.writeHNT ("STCU", mCurrent); - - if (mDamage) - esm.writeHNT ("STDF", mDamage); - - if (mProgress) - esm.writeHNT ("STPR", mProgress); - } } #endif From 52cf8541f5d02677a893bfda0542267df1249568 Mon Sep 17 00:00:00 2001 From: dteviot Date: Wed, 8 Jul 2015 18:41:03 +1200 Subject: [PATCH 1758/3725] End point tolerance restored to 64 units. Corrected problem pointed out by Scrawl. Destination needs tolerance of 64 to avoid overcrowding. --- apps/openmw/mwmechanics/aiwander.cpp | 21 +++++++++++---------- apps/openmw/mwmechanics/aiwander.hpp | 8 ++++++++ 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 25ed4694b..31687edf2 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -216,7 +216,7 @@ namespace MWMechanics // Are we there yet? bool& chooseAction = storage.mChooseAction; if(walking && - storage.mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1])) + storage.mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], DestinationTolerance)) { stopWalking(actor, storage); moveNow = false; @@ -645,9 +645,8 @@ namespace MWMechanics int index = Misc::Rng::rollDice(mAllowedNodes.size()); ESM::Pathgrid::Point dest = mAllowedNodes[index]; - // apply a slight offset to prevent overcrowding - dest.mX += static_cast(Misc::Rng::rollProbability() * 128 - 64); - dest.mY += static_cast(Misc::Rng::rollProbability() * 128 - 64); + dest.mX += OffsetToPreventOvercrowding(); + dest.mY += OffsetToPreventOvercrowding(); ToWorldCoordinates(dest, actor.getCell()->getCell()); MWBase::Environment::get().getWorld()->moveObject(actor, static_cast(dest.mX), @@ -658,6 +657,11 @@ namespace MWMechanics mStoredAvailableNodes = false; } + int AiWander::OffsetToPreventOvercrowding() + { + return static_cast(DestinationTolerance * (Misc::Rng::rollProbability() * 2.0f - 1.0f)); + } + void AiWander::getAllowedNodes(const MWWorld::Ptr& actor, const ESM::Cell* cell) { if (!mStoredInitialActorPosition) @@ -739,13 +743,10 @@ namespace MWMechanics float length = delta.length(); delta.normalize(); - // destination must be far enough away that NPC will need to move to get there. - const int threshold = PathFinder::PathTolerance * 2; - int distance = std::max(mDistance / 2, threshold); + int distance = std::max(mDistance / 2, MinimumWanderDistance); - // must not travel more than 1/2 way between waypoints, - // otherwise, NPC goes to far endpoint then comes back. Looks weird. - distance = std::min(distance, static_cast(length / 2)); + // must not travel longer than distance between waypoints or NPC goes past waypoint + distance = std::min(distance, static_cast(length)); delta *= distance; mAllowedNodes.push_back(PathFinder::MakePathgridPoint(vectorStart + delta)); } diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 18f98cfd5..c15ec7c3c 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -118,6 +118,12 @@ namespace MWMechanics GroupIndex_MaxIdle = 9 }; + // to prevent overcrowding + static const int DestinationTolerance = 64; + + // distance must be long enough that NPC will need to move to get there. + static const int MinimumWanderDistance = DestinationTolerance * 2; + /// convert point from local (i.e. cell) to world co-ordinates void ToWorldCoordinates(ESM::Pathgrid::Point& point, const ESM::Cell * cell); @@ -129,6 +135,8 @@ namespace MWMechanics /// lookup table for converting idleSelect value to groupName static const std::string sIdleSelectToGroupName[GroupIndex_MaxIdle - GroupIndex_MinIdle + 1]; + + static int OffsetToPreventOvercrowding(); }; From f1774ee7c37b89ad03508fa040b482d0662aee6b Mon Sep 17 00:00:00 2001 From: dteviot Date: Wed, 8 Jul 2015 19:34:33 +1200 Subject: [PATCH 1759/3725] Fixed compile failing on OSX and Linux. --- apps/openmw/mwmechanics/aiwander.cpp | 12 +++++++++--- apps/openmw/mwmechanics/aiwander.hpp | 6 ------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 31687edf2..4aef8f8ba 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -30,6 +30,12 @@ namespace MWMechanics static const int GREETING_SHOULD_START = 4; //how many reaction intervals should pass before NPC can greet player static const int GREETING_SHOULD_END = 10; + // to prevent overcrowding + static const int DESTINATION_TOLERANCE = 64; + + // distance must be long enough that NPC will need to move to get there. + static const int MINIMUM_WANDER_DISTANCE = DESTINATION_TOLERANCE * 2; + const std::string AiWander::sIdleSelectToGroupName[GroupIndex_MaxIdle - GroupIndex_MinIdle + 1] = { std::string("idle2"), @@ -216,7 +222,7 @@ namespace MWMechanics // Are we there yet? bool& chooseAction = storage.mChooseAction; if(walking && - storage.mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], DestinationTolerance)) + storage.mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], DESTINATION_TOLERANCE)) { stopWalking(actor, storage); moveNow = false; @@ -659,7 +665,7 @@ namespace MWMechanics int AiWander::OffsetToPreventOvercrowding() { - return static_cast(DestinationTolerance * (Misc::Rng::rollProbability() * 2.0f - 1.0f)); + return static_cast(DESTINATION_TOLERANCE * (Misc::Rng::rollProbability() * 2.0f - 1.0f)); } void AiWander::getAllowedNodes(const MWWorld::Ptr& actor, const ESM::Cell* cell) @@ -743,7 +749,7 @@ namespace MWMechanics float length = delta.length(); delta.normalize(); - int distance = std::max(mDistance / 2, MinimumWanderDistance); + int distance = std::max(mDistance / 2, MINIMUM_WANDER_DISTANCE); // must not travel longer than distance between waypoints or NPC goes past waypoint distance = std::min(distance, static_cast(length)); diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index c15ec7c3c..926017b46 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -118,12 +118,6 @@ namespace MWMechanics GroupIndex_MaxIdle = 9 }; - // to prevent overcrowding - static const int DestinationTolerance = 64; - - // distance must be long enough that NPC will need to move to get there. - static const int MinimumWanderDistance = DestinationTolerance * 2; - /// convert point from local (i.e. cell) to world co-ordinates void ToWorldCoordinates(ESM::Pathgrid::Point& point, const ESM::Cell * cell); From b1cc74dd9a6b05d6bbe728b7601afd0cda972c62 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Thu, 9 Jul 2015 14:41:37 +0200 Subject: [PATCH 1760/3725] Explicity instantiate MWMechanics::Stat --- apps/openmw/mwgui/inventorywindow.cpp | 2 + apps/openmw/mwmechanics/actors.cpp | 1 + apps/openmw/mwmechanics/stat.cpp | 290 ++++++++++++++++++++++++-- apps/openmw/mwmechanics/stat.hpp | 219 +++++-------------- apps/openmw/mwworld/worldimp.cpp | 1 + 5 files changed, 321 insertions(+), 192 deletions(-) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 52ff2ee10..392a4a84a 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -16,6 +16,8 @@ #include +#include + #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/soundmanager.hpp" diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 5f8b70651..d9a8ce72f 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include "../mwworld/esmstore.hpp" #include "../mwworld/class.hpp" diff --git a/apps/openmw/mwmechanics/stat.cpp b/apps/openmw/mwmechanics/stat.cpp index 1b909d579..6eb5e0246 100644 --- a/apps/openmw/mwmechanics/stat.cpp +++ b/apps/openmw/mwmechanics/stat.cpp @@ -1,28 +1,276 @@ - #include "stat.hpp" -void MWMechanics::AttributeValue::writeState (ESM::StatState& state) const -{ - state.mBase = mBase; - state.mMod = mModifier; - state.mDamage = mDamage; -} +#include -void MWMechanics::AttributeValue::readState (const ESM::StatState& state) +namespace MWMechanics { - mBase = state.mBase; - mModifier = state.mMod; - mDamage = state.mDamage; -} + template + Stat::Stat() : mBase (0), mModified (0) {} + template + Stat::Stat(T base) : mBase (base), mModified (base) {} + template + Stat::Stat(T base, T modified) : mBase (base), mModified (modified) {} -void MWMechanics::SkillValue::writeState (ESM::StatState& state) const -{ - AttributeValue::writeState (state); - state.mProgress = mProgress; -} + template + const T& Stat::getBase() const + { + return mBase; + } -void MWMechanics::SkillValue::readState (const ESM::StatState& state) -{ - AttributeValue::readState (state); - mProgress = state.mProgress; + template + T Stat::getModified() const + { + return std::max(static_cast(0), mModified); + } + template + T Stat::getModifier() const + { + return mModified-mBase; + } + template + void Stat::set (const T& value) + { + mBase = mModified = value; + } + template + void Stat::modify(const T& diff) + { + mBase += diff; + if(mBase >= static_cast(0)) + mModified += diff; + else + { + mModified += diff - mBase; + mBase = static_cast(0); + } + } + template + void Stat::setBase (const T& value) + { + T diff = value - mBase; + mBase = value; + mModified += diff; + } + template + void Stat::setModified (T value, const T& min, const T& max) + { + T diff = value - mModified; + + if (mBase+diffmax) + { + value = max + (mModified - mBase); + diff = value - mModified; + } + + mModified = value; + mBase += diff; + } + template + void Stat::setModifier (const T& modifier) + { + mModified = mBase + modifier; + } + + template + void Stat::writeState (ESM::StatState& state) const + { + state.mBase = mBase; + state.mMod = mModified; + } + template + void Stat::readState (const ESM::StatState& state) + { + mBase = state.mBase; + mModified = state.mMod; + } + + + template + DynamicStat::DynamicStat() : mStatic (0), mCurrent (0) {} + template + DynamicStat::DynamicStat(T base) : mStatic (base), mCurrent (base) {} + template + DynamicStat::DynamicStat(T base, T modified, T current) : mStatic(base, modified), mCurrent (current) {} + template + DynamicStat::DynamicStat(const Stat &stat, T current) : mStatic(stat), mCurrent (current) {} + + + template + const T& DynamicStat::getBase() const + { + return mStatic.getBase(); + } + template + T DynamicStat::getModified() const + { + return mStatic.getModified(); + } + template + const T& DynamicStat::getCurrent() const + { + return mCurrent; + } + + template + void DynamicStat::set (const T& value) + { + mStatic.set (value); + mCurrent = value; + } + template + void DynamicStat::setBase (const T& value) + { + mStatic.setBase (value); + + if (mCurrent>getModified()) + mCurrent = getModified(); + } + template + void DynamicStat::setModified (T value, const T& min, const T& max) + { + mStatic.setModified (value, min, max); + + if (mCurrent>getModified()) + mCurrent = getModified(); + } + template + void DynamicStat::modify (const T& diff, bool allowCurrentDecreaseBelowZero) + { + mStatic.modify (diff); + setCurrent (getCurrent()+diff, allowCurrentDecreaseBelowZero); + } + template + void DynamicStat::setCurrent (const T& value, bool allowDecreaseBelowZero) + { + if (value > mCurrent) + { + // increase + mCurrent = value; + + if (mCurrent > getModified()) + mCurrent = getModified(); + } + else if (value > 0 || allowDecreaseBelowZero) + { + // allowed decrease + mCurrent = value; + } + else if (mCurrent > 0) + { + // capped decrease + mCurrent = 0; + } + } + template + void DynamicStat::setModifier (const T& modifier, bool allowCurrentDecreaseBelowZero) + { + T diff = modifier - mStatic.getModifier(); + mStatic.setModifier (modifier); + setCurrent (getCurrent()+diff, allowCurrentDecreaseBelowZero); + } + + template + void DynamicStat::writeState (ESM::StatState& state) const + { + mStatic.writeState (state); + state.mCurrent = mCurrent; + } + template + void DynamicStat::readState (const ESM::StatState& state) + { + mStatic.readState (state); + mCurrent = state.mCurrent; + } + + AttributeValue::AttributeValue() : + mBase(0), mModifier(0), mDamage(0) + { + } + + int AttributeValue::getModified() const + { + return std::max(0, mBase - (int) mDamage + mModifier); + } + int AttributeValue::getBase() const + { + return mBase; + } + int AttributeValue::getModifier() const + { + return mModifier; + } + + void AttributeValue::setBase(int base) + { + mBase = std::max(0, base); + } + + void AttributeValue::setModifier(int mod) + { + mModifier = mod; + } + + void AttributeValue::damage(float damage) + { + mDamage += std::min(damage, (float)getModified()); + } + void AttributeValue::restore(float amount) + { + mDamage -= std::min(mDamage, amount); + } + + float AttributeValue::getDamage() const + { + return mDamage; + } + + void AttributeValue::writeState (ESM::StatState& state) const + { + state.mBase = mBase; + state.mMod = mModifier; + state.mDamage = mDamage; + } + + void AttributeValue::readState (const ESM::StatState& state) + { + mBase = state.mBase; + mModifier = state.mMod; + mDamage = state.mDamage; + } + + SkillValue::SkillValue() : + mProgress(0) + { + } + + float SkillValue::getProgress() const + { + return mProgress; + } + void SkillValue::setProgress(float progress) + { + mProgress = progress; + } + + void SkillValue::writeState (ESM::StatState& state) const + { + AttributeValue::writeState (state); + state.mProgress = mProgress; + } + + void SkillValue::readState (const ESM::StatState& state) + { + AttributeValue::readState (state); + mProgress = state.mProgress; + } } + +template class MWMechanics::Stat; +template class MWMechanics::Stat; +template class MWMechanics::DynamicStat; +template class MWMechanics::DynamicStat; diff --git a/apps/openmw/mwmechanics/stat.hpp b/apps/openmw/mwmechanics/stat.hpp index 0820d2015..c075f5fa7 100644 --- a/apps/openmw/mwmechanics/stat.hpp +++ b/apps/openmw/mwmechanics/stat.hpp @@ -4,7 +4,11 @@ #include #include -#include +namespace ESM +{ + template + struct StatState; +} namespace MWMechanics { @@ -17,87 +21,28 @@ namespace MWMechanics public: typedef T Type; - Stat() : mBase (0), mModified (0) {} - Stat(T base) : mBase (base), mModified (base) {} - Stat(T base, T modified) : mBase (base), mModified (modified) {} - - const T& getBase() const - { - return mBase; - } + Stat(); + Stat(T base); + Stat(T base, T modified); - T getModified() const - { - return std::max(static_cast(0), mModified); - } + const T& getBase() const; - T getModifier() const - { - return mModified-mBase; - } + T getModified() const; + T getModifier() const; /// Set base and modified to \a value. - void set (const T& value) - { - 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); - } - } + void set (const T& value); + void modify(const T& diff); /// Set base and adjust modified accordingly. - void setBase (const T& value) - { - T diff = value - mBase; - mBase = value; - mModified += diff; - } + void setBase (const T& value); /// Set modified value an adjust base accordingly. - void setModified (T value, const T& min, const T& max = std::numeric_limits::max()) - { - T diff = value - mModified; - - if (mBase+diffmax) - { - value = max + (mModified - mBase); - diff = value - mModified; - } - - mModified = value; - mBase += diff; - } - - void setModifier (const T& modifier) - { - mModified = mBase + modifier; - } - - void writeState (ESM::StatState& state) const - { - state.mBase = mBase; - state.mMod = mModified; - } - - void readState (const ESM::StatState& state) - { - mBase = state.mBase; - mModified = state.mMod; - } + void setModified (T value, const T& min, const T& max = std::numeric_limits::max()); + void setModifier (const T& modifier); + + void writeState (ESM::StatState& state) const; + void readState (const ESM::StatState& state); }; template @@ -122,98 +67,32 @@ namespace MWMechanics public: typedef T Type; - DynamicStat() : mStatic (0), mCurrent (0) {} - DynamicStat(T base) : mStatic (base), mCurrent (base) {} - DynamicStat(T base, T modified, T current) : mStatic(base, modified), mCurrent (current) {} - DynamicStat(const Stat &stat, T current) : mStatic(stat), mCurrent (current) {} - - const T& getBase() const - { - return mStatic.getBase(); - } - - T getModified() const - { - return mStatic.getModified(); - } + DynamicStat(); + DynamicStat(T base); + DynamicStat(T base, T modified, T current); + DynamicStat(const Stat &stat, T current); - const T& getCurrent() const - { - return mCurrent; - } + const T& getBase() const; + T getModified() const; + const T& getCurrent() const; /// Set base, modified and current to \a value. - void set (const T& value) - { - mStatic.set (value); - mCurrent = value; - } + void set (const T& value); /// Set base and adjust modified accordingly. - void setBase (const T& value) - { - mStatic.setBase (value); - - if (mCurrent>getModified()) - mCurrent = getModified(); - } + void setBase (const T& value); /// Set modified value an adjust base accordingly. - void setModified (T value, const T& min, const T& max = std::numeric_limits::max()) - { - mStatic.setModified (value, min, max); - - if (mCurrent>getModified()) - mCurrent = getModified(); - } + void setModified (T value, const T& min, const T& max = std::numeric_limits::max()); /// Change modified relatively. - void modify (const T& diff, bool allowCurrentDecreaseBelowZero=false) - { - mStatic.modify (diff); - setCurrent (getCurrent()+diff, allowCurrentDecreaseBelowZero); - } - - void setCurrent (const T& value, bool allowDecreaseBelowZero = false) - { - if (value > mCurrent) - { - // increase - mCurrent = value; - - if (mCurrent > getModified()) - mCurrent = getModified(); - } - else if (value > 0 || allowDecreaseBelowZero) - { - // allowed decrease - mCurrent = value; - } - else if (mCurrent > 0) - { - // capped decrease - mCurrent = 0; - } - } - - void setModifier (const T& modifier, bool allowCurrentDecreaseBelowZero=false) - { - T diff = modifier - mStatic.getModifier(); - mStatic.setModifier (modifier); - setCurrent (getCurrent()+diff, allowCurrentDecreaseBelowZero); - } - - void writeState (ESM::StatState& state) const - { - mStatic.writeState (state); - state.mCurrent = mCurrent; - } - - void readState (const ESM::StatState& state) - { - mStatic.readState (state); - mCurrent = state.mCurrent; - } + void modify (const T& diff, bool allowCurrentDecreaseBelowZero=false); + + void setCurrent (const T& value, bool allowDecreaseBelowZero = false); + void setModifier (const T& modifier, bool allowCurrentDecreaseBelowZero=false); + + void writeState (ESM::StatState& state) const; + void readState (const ESM::StatState& state); }; template @@ -237,26 +116,25 @@ namespace MWMechanics float mDamage; // needs to be float to allow continuous damage public: - AttributeValue() : mBase(0), mModifier(0), mDamage(0) {} + AttributeValue(); - int getModified() const { return std::max(0, mBase - (int) mDamage + mModifier); } - int getBase() const { return mBase; } - int getModifier() const { return mModifier; } + int getModified() const; + int getBase() const; + int getModifier() const; - void setBase(int base) { mBase = std::max(0, base); } + void setBase(int base); - void setModifier(int mod) { mModifier = mod; } + void setModifier(int mod); // Maximum attribute damage is limited to the modified value. // Note: I think MW applies damage directly to mModified, since you can also // "restore" drained attributes. We need to rewrite the magic effect system to support this. - void damage(float damage) { mDamage += std::min(damage, (float)getModified()); } - void restore(float amount) { mDamage -= std::min(mDamage, amount); } + void damage(float damage); + void restore(float amount); - float getDamage() const { return mDamage; } + float getDamage() const; void writeState (ESM::StatState& state) const; - void readState (const ESM::StatState& state); }; @@ -264,12 +142,11 @@ namespace MWMechanics { float mProgress; public: - SkillValue() : mProgress(0) {} - float getProgress() const { return mProgress; } - void setProgress(float progress) { mProgress = progress; } + SkillValue(); + float getProgress() const; + void setProgress(float progress); void writeState (ESM::StatState& state) const; - void readState (const ESM::StatState& state); }; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index ff82160d1..3b57e22c5 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include From b3b55a584265b8a7e0a7453ddc3448277633d276 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Thu, 9 Jul 2015 19:22:04 +0200 Subject: [PATCH 1761/3725] Explicitly instantiate MWWorld::Store --- apps/openmw/mwmechanics/spells.cpp | 1 + apps/openmw/mwscript/globalscripts.cpp | 1 + apps/openmw/mwstate/statemanagerimp.cpp | 2 + apps/openmw/mwworld/cells.cpp | 1 + apps/openmw/mwworld/esmstore.cpp | 1 + apps/openmw/mwworld/esmstore.hpp | 1 + apps/openmw/mwworld/inventorystore.cpp | 1 + apps/openmw/mwworld/scene.cpp | 1 + apps/openmw/mwworld/store.cpp | 1181 +++++++++++++++++++++-- apps/openmw/mwworld/store.hpp | 932 +++--------------- apps/openmw/mwworld/weather.cpp | 1 + apps/openmw/mwworld/worldimp.hpp | 5 + 12 files changed, 1205 insertions(+), 923 deletions(-) diff --git a/apps/openmw/mwmechanics/spells.cpp b/apps/openmw/mwmechanics/spells.cpp index e3646d829..fe0f892db 100644 --- a/apps/openmw/mwmechanics/spells.cpp +++ b/apps/openmw/mwmechanics/spells.cpp @@ -5,6 +5,7 @@ #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" diff --git a/apps/openmw/mwscript/globalscripts.cpp b/apps/openmw/mwscript/globalscripts.cpp index a6ad2cc11..44d96e949 100644 --- a/apps/openmw/mwscript/globalscripts.cpp +++ b/apps/openmw/mwscript/globalscripts.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include "../mwworld/esmstore.hpp" diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 192ad45fb..ac8dc863a 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -6,6 +6,8 @@ #include #include +#include + #include #include diff --git a/apps/openmw/mwworld/cells.cpp b/apps/openmw/mwworld/cells.cpp index 2aa817fa5..b096301fd 100644 --- a/apps/openmw/mwworld/cells.cpp +++ b/apps/openmw/mwworld/cells.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index 5d9beecb6..dea468d22 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -8,6 +8,7 @@ #include #include +#include namespace MWWorld { diff --git a/apps/openmw/mwworld/esmstore.hpp b/apps/openmw/mwworld/esmstore.hpp index 05b633956..a14f6368e 100644 --- a/apps/openmw/mwworld/esmstore.hpp +++ b/apps/openmw/mwworld/esmstore.hpp @@ -1,6 +1,7 @@ #ifndef OPENMW_MWWORLD_ESMSTORE_H #define OPENMW_MWWORLD_ESMSTORE_H +#include #include #include diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 3fe86a511..6c283bb3e 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -6,6 +6,7 @@ #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index db26b4f2a..8029cb773 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -3,6 +3,7 @@ #include #include +#include #include #include #include diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index cdcc00b4d..96c711896 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -2,126 +2,1105 @@ #include "esmstore.hpp" #include +#include -namespace MWWorld { +#include +#include -void Store::handleMovedCellRefs(ESM::ESMReader& esm, ESM::Cell* cell) +#include +#include + +namespace { - //Handling MovedCellRefs, there is no way to do it inside loadcell - while (esm.isNextSub("MVRF")) { - ESM::CellRef ref; - ESM::MovedCellRef cMRef; - cell->getNextMVRF(esm, cMRef); - - ESM::Cell *cellAlt = const_cast(searchOrCreate(cMRef.mTarget[0], cMRef.mTarget[1])); - - // Get regular moved reference data. Adapted from CellStore::loadRefs. Maybe we can optimize the following - // implementation when the oher implementation works as well. - bool deleted = false; - cell->getNextRef(esm, ref, deleted); - - // Add data required to make reference appear in the correct cell. - // We should not need to test for duplicates, as this part of the code is pre-cell merge. - cell->mMovedRefs.push_back(cMRef); - // But there may be duplicates here! - if (!deleted) + template + class GetRecords + { + const std::string mFind; + std::vector *mRecords; + + public: + GetRecords(const std::string &str, std::vector *records) + : mFind(Misc::StringUtils::lowerCase(str)), mRecords(records) + { } + + void operator()(const T *item) { - ESM::CellRefTracker::iterator iter = std::find(cellAlt->mLeasedRefs.begin(), cellAlt->mLeasedRefs.end(), ref.mRefNum); - if (iter == cellAlt->mLeasedRefs.end()) - cellAlt->mLeasedRefs.push_back(ref); - else - *iter = ref; + if(Misc::StringUtils::ciCompareLen(mFind, item->mId, mFind.size()) == 0) + mRecords->push_back(item); } - } + }; + + struct Compare + { + bool operator()(const ESM::Land *x, const ESM::Land *y) { + if (x->mX == y->mX) { + return x->mY < y->mY; + } + return x->mX < y->mX; + } + }; } -void Store::load(ESM::ESMReader &esm, const std::string &id) +namespace MWWorld { - // Don't automatically assume that a new cell must be spawned. Multiple plugins write to the same cell, - // and we merge all this data into one Cell object. However, we can't simply search for the cell id, - // as many exterior cells do not have a name. Instead, we need to search by (x,y) coordinates - and they - // are not available until both cells have been loaded at least partially! - - // All cells have a name record, even nameless exterior cells. - std::string idLower = Misc::StringUtils::lowerCase(id); - ESM::Cell cell; - cell.mName = id; - - // Load the (x,y) coordinates of the cell, if it is an exterior cell, - // so we can find the cell we need to merge with - cell.loadData(esm); - - if(cell.mData.mFlags & ESM::Cell::Interior) - { - // Store interior cell by name, try to merge with existing parent data. - ESM::Cell *oldcell = const_cast(search(idLower)); - if (oldcell) { - // merge new cell into old cell - // push the new references on the list of references to manage (saveContext = true) - oldcell->mData = cell.mData; - oldcell->mName = cell.mName; // merge name just to be sure (ID will be the same, but case could have been changed) - oldcell->loadCell(esm, true); - } else + template + IndexedStore::IndexedStore() + { + } + template + typename IndexedStore::iterator IndexedStore::begin() const + { + return mStatic.begin(); + } + template + typename IndexedStore::iterator IndexedStore::end() const + { + return mStatic.end(); + } + template + void IndexedStore::load(ESM::ESMReader &esm) + { + T record; + record.load(esm); + + // Try to overwrite existing record + std::pair ret = mStatic.insert(std::make_pair(record.mIndex, record)); + if (!ret.second) + ret.first->second = record; + } + template + int IndexedStore::getSize() const + { + return mStatic.size(); + } + template + void IndexedStore::setUp() + { + } + template + const T *IndexedStore::search(int index) const + { + typename Static::const_iterator it = mStatic.find(index); + if (it != mStatic.end()) + return &(it->second); + return NULL; + } + template + const T *IndexedStore::find(int index) const + { + const T *ptr = search(index); + if (ptr == 0) { + std::ostringstream msg; + msg << T::getRecordType() << " with index " << index << " not found"; + throw std::runtime_error(msg.str()); + } + return ptr; + } + + // Need to instantiate these before they're used + template class IndexedStore; + template class IndexedStore; + + template + Store::Store() + { + } + + template + Store::Store(const Store& orig) + : mStatic(orig.mStatic) + { + } + + template + void Store::clearDynamic() + { + // remove the dynamic part of mShared + assert(mShared.size() >= mStatic.size()); + mShared.erase(mShared.begin() + mStatic.size(), mShared.end()); + mDynamic.clear(); + } + + template + const T *Store::search(const std::string &id) const + { + T item; + item.mId = Misc::StringUtils::lowerCase(id); + + typename Dynamic::const_iterator dit = mDynamic.find(item.mId); + if (dit != mDynamic.end()) { + return &dit->second; + } + + typename std::map::const_iterator it = mStatic.find(item.mId); + + if (it != mStatic.end() && Misc::StringUtils::ciEqual(it->second.mId, id)) { + return &(it->second); + } + + return 0; + } + template + bool Store::isDynamic(const std::string &id) const + { + typename Dynamic::const_iterator dit = mDynamic.find(id); + return (dit != mDynamic.end()); + } + template + const T *Store::searchRandom(const std::string &id) const + { + std::vector results; + std::for_each(mShared.begin(), mShared.end(), GetRecords(id, &results)); + if(!results.empty()) + return results[Misc::Rng::rollDice(results.size())]; + return NULL; + } + template + const T *Store::find(const std::string &id) const + { + const T *ptr = search(id); + if (ptr == 0) { + std::ostringstream msg; + msg << T::getRecordType() << " '" << id << "' not found"; + throw std::runtime_error(msg.str()); + } + return ptr; + } + template + const T *Store::findRandom(const std::string &id) const + { + const T *ptr = searchRandom(id); + if(ptr == 0) { - // spawn a new cell - cell.loadCell(esm, true); - - mInt[idLower] = cell; - } - } - else - { - // Store exterior cells by grid position, try to merge with existing parent data. - ESM::Cell *oldcell = const_cast(search(cell.getGridX(), cell.getGridY())); - if (oldcell) { - // merge new cell into old cell - oldcell->mData = cell.mData; - oldcell->mName = cell.mName; - oldcell->loadCell(esm, false); - - // handle moved ref (MVRF) subrecords - handleMovedCellRefs (esm, &cell); - - // push the new references on the list of references to manage - oldcell->postLoad(esm); - - // merge lists of leased references, use newer data in case of conflict - for (ESM::MovedCellRefTracker::const_iterator it = cell.mMovedRefs.begin(); it != cell.mMovedRefs.end(); ++it) { - // remove reference from current leased ref tracker and add it to new cell - ESM::MovedCellRefTracker::iterator itold = std::find(oldcell->mMovedRefs.begin(), oldcell->mMovedRefs.end(), it->mRefNum); - if (itold != oldcell->mMovedRefs.end()) { - ESM::MovedCellRef target0 = *itold; - ESM::Cell *wipecell = const_cast(search(target0.mTarget[0], target0.mTarget[1])); - ESM::CellRefTracker::iterator it_lease = std::find(wipecell->mLeasedRefs.begin(), wipecell->mLeasedRefs.end(), it->mRefNum); - wipecell->mLeasedRefs.erase(it_lease); - *itold = *it; + std::ostringstream msg; + msg << T::getRecordType() << " starting with '"< + void Store::load(ESM::ESMReader &esm, const std::string &id) + { + std::string idLower = Misc::StringUtils::lowerCase(id); + + std::pair inserted = mStatic.insert(std::make_pair(idLower, T())); + if (inserted.second) + mShared.push_back(&inserted.first->second); + + inserted.first->second.mId = idLower; + inserted.first->second.load(esm); + } + template + void Store::setUp() + { + } + + template + typename Store::iterator Store::begin() const + { + return mShared.begin(); + } + template + typename Store::iterator Store::end() const + { + return mShared.end(); + } + + template + size_t Store::getSize() const + { + return mShared.size(); + } + + template + int Store::getDynamicSize() const + { + return mDynamic.size(); + } + template + void Store::listIdentifier(std::vector &list) const + { + list.reserve(list.size() + getSize()); + typename std::vector::const_iterator it = mShared.begin(); + for (; it != mShared.end(); ++it) { + list.push_back((*it)->mId); + } + } + template + T *Store::insert(const T &item) + { + std::string id = Misc::StringUtils::lowerCase(item.mId); + std::pair result = + mDynamic.insert(std::pair(id, item)); + T *ptr = &result.first->second; + if (result.second) { + mShared.push_back(ptr); + } else { + *ptr = item; + } + return ptr; + } + template + T *Store::insertStatic(const T &item) + { + std::string id = Misc::StringUtils::lowerCase(item.mId); + std::pair result = + mStatic.insert(std::pair(id, item)); + T *ptr = &result.first->second; + if (result.second) { + mShared.push_back(ptr); + } else { + *ptr = item; + } + return ptr; + } + template + bool Store::eraseStatic(const std::string &id) + { + T item; + item.mId = Misc::StringUtils::lowerCase(id); + + typename std::map::iterator it = mStatic.find(item.mId); + + if (it != mStatic.end() && Misc::StringUtils::ciEqual(it->second.mId, id)) { + // delete from the static part of mShared + typename std::vector::iterator sharedIter = mShared.begin(); + typename std::vector::iterator end = sharedIter + mStatic.size(); + + while (sharedIter != mShared.end() && sharedIter != end) { + if((*sharedIter)->mId == item.mId) { + mShared.erase(sharedIter); + break; } + ++sharedIter; + } + mStatic.erase(it); + } + + return true; + } + + template + bool Store::erase(const std::string &id) + { + std::string key = Misc::StringUtils::lowerCase(id); + typename Dynamic::iterator it = mDynamic.find(key); + if (it == mDynamic.end()) { + return false; + } + mDynamic.erase(it); + + // have to reinit the whole shared part + assert(mShared.size() >= mStatic.size()); + mShared.erase(mShared.begin() + mStatic.size(), mShared.end()); + for (it = mDynamic.begin(); it != mDynamic.end(); ++it) { + mShared.push_back(&it->second); + } + return true; + } + template + bool Store::erase(const T &item) + { + return erase(item.mId); + } + template + void Store::write (ESM::ESMWriter& writer, Loading::Listener& progress) const + { + for (typename Dynamic::const_iterator iter (mDynamic.begin()); iter!=mDynamic.end(); + ++iter) + { + writer.startRecord (T::sRecordId); + writer.writeHNString ("NAME", iter->second.mId); + iter->second.save (writer); + writer.endRecord (T::sRecordId); + } + } + template + void Store::read(ESM::ESMReader& reader, const std::string& id) + { + T record; + record.mId = id; + record.load (reader); + insert (record); + } + + + // LandTexture + //========================================================================= + Store::Store() + { + mStatic.push_back(LandTextureList()); + LandTextureList <exl = mStatic[0]; + // More than enough to hold Morrowind.esm. Extra lists for plugins will we + // added on-the-fly in a different method. + ltexl.reserve(128); + } + const ESM::LandTexture *Store::search(size_t index, size_t plugin) const + { + assert(plugin < mStatic.size()); + const LandTextureList <exl = mStatic[plugin]; + + assert(index < ltexl.size()); + return <exl.at(index); + } + const ESM::LandTexture *Store::find(size_t index, size_t plugin) const + { + const ESM::LandTexture *ptr = search(index, plugin); + if (ptr == 0) { + std::ostringstream msg; + msg << "Land texture with index " << index << " not found"; + throw std::runtime_error(msg.str()); + } + return ptr; + } + size_t Store::getSize() const + { + return mStatic.size(); + } + size_t Store::getSize(size_t plugin) const + { + assert(plugin < mStatic.size()); + return mStatic[plugin].size(); + } + void Store::load(ESM::ESMReader &esm, const std::string &id, size_t plugin) + { + ESM::LandTexture lt; + lt.load(esm); + lt.mId = id; + + // Make sure we have room for the structure + if (plugin >= mStatic.size()) { + mStatic.resize(plugin+1); + } + LandTextureList <exl = mStatic[plugin]; + if(lt.mIndex + 1 > (int)ltexl.size()) + ltexl.resize(lt.mIndex+1); + + // Store it + ltexl[lt.mIndex] = lt; + } + void Store::load(ESM::ESMReader &esm, const std::string &id) + { + load(esm, id, esm.getIndex()); + } + Store::iterator Store::begin(size_t plugin) const + { + assert(plugin < mStatic.size()); + return mStatic[plugin].begin(); + } + Store::iterator Store::end(size_t plugin) const + { + assert(plugin < mStatic.size()); + return mStatic[plugin].end(); + } + + + // Land + //========================================================================= + Store::~Store() + { + for (std::vector::const_iterator it = + mStatic.begin(); it != mStatic.end(); ++it) + { + delete *it; + } + + } + size_t Store::getSize() const + { + return mStatic.size(); + } + Store::iterator Store::begin() const + { + return iterator(mStatic.begin()); + } + Store::iterator Store::end() const + { + return iterator(mStatic.end()); + } + ESM::Land *Store::search(int x, int y) const + { + ESM::Land land; + land.mX = x, land.mY = y; + + std::vector::const_iterator it = + std::lower_bound(mStatic.begin(), mStatic.end(), &land, Compare()); + + if (it != mStatic.end() && (*it)->mX == x && (*it)->mY == y) { + return const_cast(*it); + } + return 0; + } + ESM::Land *Store::find(int x, int y) const + { + ESM::Land *ptr = search(x, y); + if (ptr == 0) { + std::ostringstream msg; + msg << "Land at (" << x << ", " << y << ") not found"; + throw std::runtime_error(msg.str()); + } + return ptr; + } + void Store::load(ESM::ESMReader &esm, const std::string &id) + { + ESM::Land *ptr = new ESM::Land(); + ptr->load(esm); + + // Same area defined in multiple plugins? -> last plugin wins + // Can't use search() because we aren't sorted yet - is there any other way to speed this up? + for (std::vector::iterator it = mStatic.begin(); it != mStatic.end(); ++it) + { + if ((*it)->mX == ptr->mX && (*it)->mY == ptr->mY) + { + delete *it; + mStatic.erase(it); + break; + } + } + + mStatic.push_back(ptr); + } + void Store::setUp() + { + std::sort(mStatic.begin(), mStatic.end(), Compare()); + } + + + // Cell + //========================================================================= + + const ESM::Cell *Store::search(const ESM::Cell &cell) const + { + if (cell.isExterior()) { + return search(cell.getGridX(), cell.getGridY()); + } + return search(cell.mName); + } + void Store::handleMovedCellRefs(ESM::ESMReader& esm, ESM::Cell* cell) + { + //Handling MovedCellRefs, there is no way to do it inside loadcell + while (esm.isNextSub("MVRF")) { + ESM::CellRef ref; + ESM::MovedCellRef cMRef; + cell->getNextMVRF(esm, cMRef); + + ESM::Cell *cellAlt = const_cast(searchOrCreate(cMRef.mTarget[0], cMRef.mTarget[1])); + + // Get regular moved reference data. Adapted from CellStore::loadRefs. Maybe we can optimize the following + // implementation when the oher implementation works as well. + bool deleted = false; + cell->getNextRef(esm, ref, deleted); + + // Add data required to make reference appear in the correct cell. + // We should not need to test for duplicates, as this part of the code is pre-cell merge. + cell->mMovedRefs.push_back(cMRef); + // But there may be duplicates here! + if (!deleted) + { + ESM::CellRefTracker::iterator iter = std::find(cellAlt->mLeasedRefs.begin(), cellAlt->mLeasedRefs.end(), ref.mRefNum); + if (iter == cellAlt->mLeasedRefs.end()) + cellAlt->mLeasedRefs.push_back(ref); else - oldcell->mMovedRefs.push_back(*it); + *iter = ref; + } + } + } + const ESM::Cell *Store::search(const std::string &id) const + { + ESM::Cell cell; + cell.mName = Misc::StringUtils::lowerCase(id); + + std::map::const_iterator it = mInt.find(cell.mName); + + if (it != mInt.end() && Misc::StringUtils::ciEqual(it->second.mName, id)) { + return &(it->second); + } + + DynamicInt::const_iterator dit = mDynamicInt.find(cell.mName); + if (dit != mDynamicInt.end()) { + return &dit->second; + } + + return 0; + } + const ESM::Cell *Store::search(int x, int y) const + { + ESM::Cell cell; + cell.mData.mX = x, cell.mData.mY = y; + + std::pair key(x, y); + DynamicExt::const_iterator it = mExt.find(key); + if (it != mExt.end()) { + return &(it->second); + } + + DynamicExt::const_iterator dit = mDynamicExt.find(key); + if (dit != mDynamicExt.end()) { + return &dit->second; + } + + return 0; + } + const ESM::Cell *Store::searchOrCreate(int x, int y) + { + std::pair key(x, y); + DynamicExt::const_iterator it = mExt.find(key); + if (it != mExt.end()) { + return &(it->second); + } + + DynamicExt::const_iterator dit = mDynamicExt.find(key); + if (dit != mDynamicExt.end()) { + return &dit->second; + } + + ESM::Cell newCell; + newCell.mData.mX = x; + newCell.mData.mY = y; + newCell.mData.mFlags = ESM::Cell::HasWater; + newCell.mAmbi.mAmbient = 0; + newCell.mAmbi.mSunlight = 0; + newCell.mAmbi.mFog = 0; + newCell.mAmbi.mFogDensity = 0; + return &mExt.insert(std::make_pair(key, newCell)).first->second; + } + const ESM::Cell *Store::find(const std::string &id) const + { + const ESM::Cell *ptr = search(id); + if (ptr == 0) { + std::ostringstream msg; + msg << "Interior cell '" << id << "' not found"; + throw std::runtime_error(msg.str()); + } + return ptr; + } + const ESM::Cell *Store::find(int x, int y) const + { + const ESM::Cell *ptr = search(x, y); + if (ptr == 0) { + std::ostringstream msg; + msg << "Exterior at (" << x << ", " << y << ") not found"; + throw std::runtime_error(msg.str()); + } + return ptr; + } + void Store::setUp() + { + typedef DynamicExt::iterator ExtIterator; + typedef std::map::iterator IntIterator; + + mSharedInt.clear(); + mSharedInt.reserve(mInt.size()); + for (IntIterator it = mInt.begin(); it != mInt.end(); ++it) { + mSharedInt.push_back(&(it->second)); + } + + mSharedExt.clear(); + mSharedExt.reserve(mExt.size()); + for (ExtIterator it = mExt.begin(); it != mExt.end(); ++it) { + mSharedExt.push_back(&(it->second)); + } + } + void Store::load(ESM::ESMReader &esm, const std::string &id) + { + // Don't automatically assume that a new cell must be spawned. Multiple plugins write to the same cell, + // and we merge all this data into one Cell object. However, we can't simply search for the cell id, + // as many exterior cells do not have a name. Instead, we need to search by (x,y) coordinates - and they + // are not available until both cells have been loaded at least partially! + + // All cells have a name record, even nameless exterior cells. + std::string idLower = Misc::StringUtils::lowerCase(id); + ESM::Cell cell; + cell.mName = id; + + // Load the (x,y) coordinates of the cell, if it is an exterior cell, + // so we can find the cell we need to merge with + cell.loadData(esm); + + if(cell.mData.mFlags & ESM::Cell::Interior) + { + // Store interior cell by name, try to merge with existing parent data. + ESM::Cell *oldcell = const_cast(search(idLower)); + if (oldcell) { + // merge new cell into old cell + // push the new references on the list of references to manage (saveContext = true) + oldcell->mData = cell.mData; + oldcell->mName = cell.mName; // merge name just to be sure (ID will be the same, but case could have been changed) + oldcell->loadCell(esm, true); + } else + { + // spawn a new cell + cell.loadCell(esm, true); + + mInt[idLower] = cell; + } + } + else + { + // Store exterior cells by grid position, try to merge with existing parent data. + ESM::Cell *oldcell = const_cast(search(cell.getGridX(), cell.getGridY())); + if (oldcell) { + // merge new cell into old cell + oldcell->mData = cell.mData; + oldcell->mName = cell.mName; + oldcell->loadCell(esm, false); + + // handle moved ref (MVRF) subrecords + handleMovedCellRefs (esm, &cell); + + // push the new references on the list of references to manage + oldcell->postLoad(esm); + + // merge lists of leased references, use newer data in case of conflict + for (ESM::MovedCellRefTracker::const_iterator it = cell.mMovedRefs.begin(); it != cell.mMovedRefs.end(); ++it) { + // remove reference from current leased ref tracker and add it to new cell + ESM::MovedCellRefTracker::iterator itold = std::find(oldcell->mMovedRefs.begin(), oldcell->mMovedRefs.end(), it->mRefNum); + if (itold != oldcell->mMovedRefs.end()) { + ESM::MovedCellRef target0 = *itold; + ESM::Cell *wipecell = const_cast(search(target0.mTarget[0], target0.mTarget[1])); + ESM::CellRefTracker::iterator it_lease = std::find(wipecell->mLeasedRefs.begin(), wipecell->mLeasedRefs.end(), it->mRefNum); + wipecell->mLeasedRefs.erase(it_lease); + *itold = *it; + } + else + oldcell->mMovedRefs.push_back(*it); + } + + // We don't need to merge mLeasedRefs of cell / oldcell. This list is filled when another cell moves a + // reference to this cell, so the list for the new cell should be empty. The list for oldcell, + // however, could have leased refs in it and so should be kept. + } else + { + // spawn a new cell + cell.loadCell(esm, false); + + // handle moved ref (MVRF) subrecords + handleMovedCellRefs (esm, &cell); + + // push the new references on the list of references to manage + cell.postLoad(esm); + + mExt[std::make_pair(cell.mData.mX, cell.mData.mY)] = cell; + } + } + } + Store::iterator Store::intBegin() const + { + return iterator(mSharedInt.begin()); + } + Store::iterator Store::intEnd() const + { + return iterator(mSharedInt.end()); + } + Store::iterator Store::extBegin() const + { + return iterator(mSharedExt.begin()); + } + Store::iterator Store::extEnd() const + { + return iterator(mSharedExt.end()); + } + const ESM::Cell *Store::searchExtByName(const std::string &id) const + { + ESM::Cell *cell = 0; + std::vector::const_iterator it = mSharedExt.begin(); + for (; it != mSharedExt.end(); ++it) { + if (Misc::StringUtils::ciEqual((*it)->mName, id)) { + if ( cell == 0 || + ( (*it)->mData.mX > cell->mData.mX ) || + ( (*it)->mData.mX == cell->mData.mX && (*it)->mData.mY > cell->mData.mY ) ) + { + cell = *it; + } } + } + return cell; + } + const ESM::Cell *Store::searchExtByRegion(const std::string &id) const + { + ESM::Cell *cell = 0; + std::vector::const_iterator it = mSharedExt.begin(); + for (; it != mSharedExt.end(); ++it) { + if (Misc::StringUtils::ciEqual((*it)->mRegion, id)) { + if ( cell == 0 || + ( (*it)->mData.mX > cell->mData.mX ) || + ( (*it)->mData.mX == cell->mData.mX && (*it)->mData.mY > cell->mData.mY ) ) + { + cell = *it; + } + } + } + return cell; + } + size_t Store::getSize() const + { + return mSharedInt.size() + mSharedExt.size(); + } + void Store::listIdentifier(std::vector &list) const + { + list.reserve(list.size() + mSharedInt.size()); + + std::vector::const_iterator it = mSharedInt.begin(); + for (; it != mSharedInt.end(); ++it) { + list.push_back((*it)->mName); + } + } + ESM::Cell *Store::insert(const ESM::Cell &cell) + { + if (search(cell) != 0) { + std::ostringstream msg; + msg << "Failed to create "; + msg << ((cell.isExterior()) ? "exterior" : "interior"); + msg << " cell"; + + throw std::runtime_error(msg.str()); + } + ESM::Cell *ptr; + if (cell.isExterior()) { + std::pair key(cell.getGridX(), cell.getGridY()); + + // duplicate insertions are avoided by search(ESM::Cell &) + std::pair result = + mDynamicExt.insert(std::make_pair(key, cell)); + + ptr = &result.first->second; + mSharedExt.push_back(ptr); + } else { + std::string key = Misc::StringUtils::lowerCase(cell.mName); + + // duplicate insertions are avoided by search(ESM::Cell &) + std::pair result = + mDynamicInt.insert(std::make_pair(key, cell)); + + ptr = &result.first->second; + mSharedInt.push_back(ptr); + } + return ptr; + } + bool Store::erase(const ESM::Cell &cell) + { + if (cell.isExterior()) { + return erase(cell.getGridX(), cell.getGridY()); + } + return erase(cell.mName); + } + bool Store::erase(const std::string &id) + { + std::string key = Misc::StringUtils::lowerCase(id); + DynamicInt::iterator it = mDynamicInt.find(key); + + if (it == mDynamicInt.end()) { + return false; + } + mDynamicInt.erase(it); + mSharedInt.erase( + mSharedInt.begin() + mSharedInt.size(), + mSharedInt.end() + ); + + for (it = mDynamicInt.begin(); it != mDynamicInt.end(); ++it) { + mSharedInt.push_back(&it->second); + } + + return true; + } + bool Store::erase(int x, int y) + { + std::pair key(x, y); + DynamicExt::iterator it = mDynamicExt.find(key); + + if (it == mDynamicExt.end()) { + return false; + } + mDynamicExt.erase(it); + mSharedExt.erase( + mSharedExt.begin() + mSharedExt.size(), + mSharedExt.end() + ); - // We don't need to merge mLeasedRefs of cell / oldcell. This list is filled when another cell moves a - // reference to this cell, so the list for the new cell should be empty. The list for oldcell, - // however, could have leased refs in it and so should be kept. - } else + for (it = mDynamicExt.begin(); it != mDynamicExt.end(); ++it) { + mSharedExt.push_back(&it->second); + } + + return true; + } + + + // Pathgrid + //========================================================================= + + Store::Store() + : mCells(NULL) + { + } + + void Store::setCells(Store& cells) + { + mCells = &cells; + } + void Store::load(ESM::ESMReader &esm, const std::string &id) + { + ESM::Pathgrid pathgrid; + pathgrid.load(esm); + + // Unfortunately the Pathgrid record model does not specify whether the pathgrid belongs to an interior or exterior cell. + // For interior cells, mCell is the cell name, but for exterior cells it is either the cell name or if that doesn't exist, the cell's region name. + // mX and mY will be (0,0) for interior cells, but there is also an exterior cell with the coordinates of (0,0), so that doesn't help. + // Check whether mCell is an interior cell. This isn't perfect, will break if a Region with the same name as an interior cell is created. + // A proper fix should be made for future versions of the file format. + bool interior = mCells->search(pathgrid.mCell) != NULL; + + // Try to overwrite existing record + if (interior) + { + std::pair ret = mInt.insert(std::make_pair(pathgrid.mCell, pathgrid)); + if (!ret.second) + ret.first->second = pathgrid; + } + else { - // spawn a new cell - cell.loadCell(esm, false); + std::pair ret = mExt.insert(std::make_pair(std::make_pair(pathgrid.mData.mX, pathgrid.mData.mY), pathgrid)); + if (!ret.second) + ret.first->second = pathgrid; + } + } + size_t Store::getSize() const + { + return mInt.size() + mExt.size(); + } + void Store::setUp() + { + } + const ESM::Pathgrid *Store::search(int x, int y) const + { + Exterior::const_iterator it = mExt.find(std::make_pair(x,y)); + if (it != mExt.end()) + return &(it->second); + return NULL; + } + const ESM::Pathgrid *Store::search(const std::string& name) const + { + Interior::const_iterator it = mInt.find(name); + if (it != mInt.end()) + return &(it->second); + return NULL; + } + const ESM::Pathgrid *Store::find(int x, int y) const + { + const ESM::Pathgrid* pathgrid = search(x,y); + if (!pathgrid) + { + std::ostringstream msg; + msg << "Pathgrid in cell '" << x << " " << y << "' not found"; + throw std::runtime_error(msg.str()); + } + return pathgrid; + } + const ESM::Pathgrid* Store::find(const std::string& name) const + { + const ESM::Pathgrid* pathgrid = search(name); + if (!pathgrid) + { + std::ostringstream msg; + msg << "Pathgrid in cell '" << name << "' not found"; + throw std::runtime_error(msg.str()); + } + return pathgrid; + } + const ESM::Pathgrid *Store::search(const ESM::Cell &cell) const + { + if (!(cell.mData.mFlags & ESM::Cell::Interior)) + return search(cell.mData.mX, cell.mData.mY); + else + return search(cell.mName); + } + const ESM::Pathgrid *Store::find(const ESM::Cell &cell) const + { + if (!(cell.mData.mFlags & ESM::Cell::Interior)) + return find(cell.mData.mX, cell.mData.mY); + else + return find(cell.mName); + } - // handle moved ref (MVRF) subrecords - handleMovedCellRefs (esm, &cell); - // push the new references on the list of references to manage - cell.postLoad(esm); + // Skill + //========================================================================= + + Store::Store() + { + } + + + // Magic effect + //========================================================================= + + Store::Store() + { + } + - mExt[std::make_pair(cell.mData.mX, cell.mData.mY)] = cell; + // Attribute + //========================================================================= + + Store::Store() + { + mStatic.reserve(ESM::Attribute::Length); + } + const ESM::Attribute *Store::search(size_t index) const + { + if (index >= mStatic.size()) { + return 0; } + return &mStatic.at(index); } -} -void Store::load(ESM::ESMReader &esm, const std::string &id) -{ - load(esm, id, esm.getIndex()); -} + const ESM::Attribute *Store::find(size_t index) const + { + const ESM::Attribute *ptr = search(index); + if (ptr == 0) { + std::ostringstream msg; + msg << "Attribute with index " << index << " not found"; + throw std::runtime_error(msg.str()); + } + return ptr; + } + void Store::setUp() + { + for (int i = 0; i < ESM::Attribute::Length; ++i) { + mStatic.push_back( + ESM::Attribute( + ESM::Attribute::sAttributeIds[i], + ESM::Attribute::sGmstAttributeIds[i], + ESM::Attribute::sGmstAttributeDescIds[i] + ) + ); + } + } + size_t Store::getSize() const + { + return mStatic.size(); + } + Store::iterator Store::begin() const + { + return mStatic.begin(); + } + Store::iterator Store::end() const + { + return mStatic.end(); + } + + + // Dialogue + //========================================================================= + + + template<> + inline void Store::setUp() + { + // DialInfos marked as deleted are kept during the loading phase, so that the linked list + // structure is kept intact for inserting further INFOs. Delete them now that loading is done. + for (Static::iterator it = mStatic.begin(); it != mStatic.end(); ++it) + { + ESM::Dialogue& dial = it->second; + dial.clearDeletedInfos(); + } + + mShared.clear(); + mShared.reserve(mStatic.size()); + std::map::iterator it = mStatic.begin(); + for (; it != mStatic.end(); ++it) { + mShared.push_back(&(it->second)); + } + } + + template <> + inline void Store::load(ESM::ESMReader &esm, const std::string &id) { + std::string idLower = Misc::StringUtils::lowerCase(id); + + std::map::iterator it = mStatic.find(idLower); + if (it == mStatic.end()) { + it = mStatic.insert( std::make_pair( idLower, ESM::Dialogue() ) ).first; + it->second.mId = id; // don't smash case here, as this line is printed + } + + it->second.load(esm); + } + + // Script + //========================================================================= + + template <> + inline void Store::load(ESM::ESMReader &esm, const std::string &id) { + ESM::Script scpt; + scpt.load(esm); + Misc::StringUtils::toLower(scpt.mId); + + std::pair inserted = mStatic.insert(std::make_pair(scpt.mId, scpt)); + if (inserted.second) + mShared.push_back(&inserted.first->second); + else + inserted.first->second = scpt; + } + + + // StartScript + //========================================================================= + + template <> + inline void Store::load(ESM::ESMReader &esm, const std::string &id) + { + ESM::StartScript s; + s.load(esm); + s.mId = Misc::StringUtils::toLower(s.mId); + std::pair inserted = mStatic.insert(std::make_pair(s.mId, s)); + if (inserted.second) + mShared.push_back(&inserted.first->second); + else + inserted.first->second = s; + } } + +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; + diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index 2d73d5312..02fb983cd 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -4,16 +4,18 @@ #include #include #include -#include -#include -#include - -#include +#include "recordcmp.hpp" -#include +namespace ESM +{ + struct Land; +} -#include "recordcmp.hpp" +namespace Loading +{ + class Listener; +} namespace MWWorld { @@ -37,6 +39,30 @@ namespace MWWorld ///< Read into dynamic storage }; + template + class IndexedStore + { + protected: + typedef typename std::map Static; + Static mStatic; + + public: + typedef typename std::map::const_iterator iterator; + + IndexedStore(); + + iterator begin() const; + iterator end() const; + + void load(ESM::ESMReader &esm); + + int getSize() const; + void setUp(); + + const T *search(int index) const; + const T *find(int index) const; + }; + template class SharedIterator { @@ -110,275 +136,54 @@ namespace MWWorld typedef std::map Dynamic; typedef std::map Static; - class GetRecords { - const std::string mFind; - std::vector *mRecords; - - public: - GetRecords(const std::string &str, std::vector *records) - : mFind(Misc::StringUtils::lowerCase(str)), mRecords(records) - { } - - void operator()(const T *item) - { - if(Misc::StringUtils::ciCompareLen(mFind, item->mId, mFind.size()) == 0) - mRecords->push_back(item); - } - }; - - friend class ESMStore; public: - Store() - {} - - Store(const Store &orig) - : mStatic(orig.mData) - {} + Store(); + Store(const Store &orig); typedef SharedIterator iterator; // setUp needs to be called again after - virtual void clearDynamic() - { - // remove the dynamic part of mShared - assert(mShared.size() >= mStatic.size()); - mShared.erase(mShared.begin() + mStatic.size(), mShared.end()); - mDynamic.clear(); - } - - const T *search(const std::string &id) const { - T item; - item.mId = Misc::StringUtils::lowerCase(id); - - typename Dynamic::const_iterator dit = mDynamic.find(item.mId); - if (dit != mDynamic.end()) { - return &dit->second; - } + virtual void clearDynamic(); + void setUp(); - typename std::map::const_iterator it = mStatic.find(item.mId); - - if (it != mStatic.end() && Misc::StringUtils::ciEqual(it->second.mId, id)) { - return &(it->second); - } - - return 0; - } + const T *search(const std::string &id) const; /** * Does the record with this ID come from the dynamic store? */ - bool isDynamic(const std::string &id) const { - typename Dynamic::const_iterator dit = mDynamic.find(id); - return (dit != mDynamic.end()); - } + bool isDynamic(const std::string &id) const; /** Returns a random record that starts with the named ID, or NULL if not found. */ - const T *searchRandom(const std::string &id) const - { - std::vector results; - std::for_each(mShared.begin(), mShared.end(), GetRecords(id, &results)); - if(!results.empty()) - return results[Misc::Rng::rollDice(results.size())]; - return NULL; - } + const T *searchRandom(const std::string &id) const; - const T *find(const std::string &id) const { - const T *ptr = search(id); - if (ptr == 0) { - std::ostringstream msg; - msg << T::getRecordType() << " '" << id << "' not found"; - throw std::runtime_error(msg.str()); - } - return ptr; - } + const T *find(const std::string &id) const; /** Returns a random record that starts with the named ID. An exception is thrown if none * are found. */ - const T *findRandom(const std::string &id) const - { - const T *ptr = searchRandom(id); - if(ptr == 0) - { - std::ostringstream msg; - msg << T::getRecordType() << " starting with '"< inserted = mStatic.insert(std::make_pair(idLower, T())); - if (inserted.second) - mShared.push_back(&inserted.first->second); - - inserted.first->second.mId = idLower; - inserted.first->second.load(esm); - } - - void setUp() { - } - - iterator begin() const { - return mShared.begin(); - } - - iterator end() const { - return mShared.end(); - } - - size_t getSize() const { - return mShared.size(); - } - - int getDynamicSize() const - { - return static_cast (mDynamic.size()); // truncated from unsigned __int64 if _MSC_VER && _WIN64 - } - - void listIdentifier(std::vector &list) const { - list.reserve(list.size() + getSize()); - typename std::vector::const_iterator it = mShared.begin(); - for (; it != mShared.end(); ++it) { - list.push_back((*it)->mId); - } - } - - T *insert(const T &item) { - std::string id = Misc::StringUtils::lowerCase(item.mId); - std::pair result = - mDynamic.insert(std::pair(id, item)); - T *ptr = &result.first->second; - if (result.second) { - mShared.push_back(ptr); - } else { - *ptr = item; - } - return ptr; - } - - T *insertStatic(const T &item) { - std::string id = Misc::StringUtils::lowerCase(item.mId); - std::pair result = - mStatic.insert(std::pair(id, item)); - T *ptr = &result.first->second; - if (result.second) { - mShared.push_back(ptr); - } else { - *ptr = item; - } - return ptr; - } - - - bool eraseStatic(const std::string &id) { - T item; - item.mId = Misc::StringUtils::lowerCase(id); + const T *findRandom(const std::string &id) const; - typename std::map::iterator it = mStatic.find(item.mId); + iterator begin() const; + iterator end() const; - if (it != mStatic.end() && Misc::StringUtils::ciEqual(it->second.mId, id)) { - // delete from the static part of mShared - typename std::vector::iterator sharedIter = mShared.begin(); - typename std::vector::iterator end = sharedIter + mStatic.size(); - - while (sharedIter != mShared.end() && sharedIter != end) { - if((*sharedIter)->mId == item.mId) { - mShared.erase(sharedIter); - break; - } - ++sharedIter; - } - mStatic.erase(it); - } - - return true; - } - - bool erase(const std::string &id) { - std::string key = Misc::StringUtils::lowerCase(id); - typename Dynamic::iterator it = mDynamic.find(key); - if (it == mDynamic.end()) { - return false; - } - mDynamic.erase(it); + size_t getSize() const; + int getDynamicSize() const; - // have to reinit the whole shared part - assert(mShared.size() >= mStatic.size()); - mShared.erase(mShared.begin() + mStatic.size(), mShared.end()); - for (it = mDynamic.begin(); it != mDynamic.end(); ++it) { - mShared.push_back(&it->second); - } - return true; - } + void listIdentifier(std::vector &list) const; - bool erase(const T &item) { - return erase(item.mId); - } + T *insert(const T &item); + T *insertStatic(const T &item); - void write (ESM::ESMWriter& writer, Loading::Listener& progress) const - { - for (typename Dynamic::const_iterator iter (mDynamic.begin()); iter!=mDynamic.end(); - ++iter) - { - writer.startRecord (T::sRecordId); - writer.writeHNString ("NAME", iter->second.mId); - iter->second.save (writer); - writer.endRecord (T::sRecordId); - } - } + bool eraseStatic(const std::string &id); + bool erase(const std::string &id); + bool erase(const T &item); - void read (ESM::ESMReader& reader, const std::string& id) - { - T record; - record.mId = id; - record.load (reader); - insert (record); - } + void load(ESM::ESMReader &esm, const std::string &id); + void write(ESM::ESMWriter& writer, Loading::Listener& progress) const; + void read(ESM::ESMReader& reader, const std::string& id); }; - template <> - inline void Store::load(ESM::ESMReader &esm, const std::string &id) { - std::string idLower = Misc::StringUtils::lowerCase(id); - - std::map::iterator it = mStatic.find(idLower); - if (it == mStatic.end()) { - it = mStatic.insert( std::make_pair( idLower, ESM::Dialogue() ) ).first; - it->second.mId = id; // don't smash case here, as this line is printed - } - - it->second.load(esm); - } - - template <> - inline void Store::load(ESM::ESMReader &esm, const std::string &id) { - ESM::Script scpt; - scpt.load(esm); - Misc::StringUtils::toLower(scpt.mId); - - std::pair inserted = mStatic.insert(std::make_pair(scpt.mId, scpt)); - if (inserted.second) - mShared.push_back(&inserted.first->second); - else - inserted.first->second = scpt; - } - - template <> - inline void Store::load(ESM::ESMReader &esm, const std::string &id) - { - ESM::StartScript s; - s.load(esm); - s.mId = Misc::StringUtils::toLower(s.mId); - std::pair inserted = mStatic.insert(std::make_pair(s.mId, s)); - if (inserted.second) - mShared.push_back(&inserted.first->second); - else - inserted.first->second = s; - } - template <> class Store : public StoreBase { @@ -387,73 +192,23 @@ namespace MWWorld std::vector mStatic; public: - Store() { - mStatic.push_back(LandTextureList()); - LandTextureList <exl = mStatic[0]; - // More than enough to hold Morrowind.esm. Extra lists for plugins will we - // added on-the-fly in a different method. - ltexl.reserve(128); - } + Store(); typedef std::vector::const_iterator iterator; // Must be threadsafe! Called from terrain background loading threads. // Not a big deal here, since ESM::LandTexture can never be modified or inserted/erased - const ESM::LandTexture *search(size_t index, size_t plugin) const { - assert(plugin < mStatic.size()); - const LandTextureList <exl = mStatic[plugin]; - - assert(index < ltexl.size()); - return <exl.at(index); - } - - const ESM::LandTexture *find(size_t index, size_t plugin) const { - const ESM::LandTexture *ptr = search(index, plugin); - if (ptr == 0) { - std::ostringstream msg; - msg << "Land texture with index " << index << " not found"; - throw std::runtime_error(msg.str()); - } - return ptr; - } - - size_t getSize() const { - return mStatic.size(); - } - - size_t getSize(size_t plugin) const { - assert(plugin < mStatic.size()); - return mStatic[plugin].size(); - } + const ESM::LandTexture *search(size_t index, size_t plugin) const; + const ESM::LandTexture *find(size_t index, size_t plugin) const; - void load(ESM::ESMReader &esm, const std::string &id, size_t plugin) { - ESM::LandTexture lt; - lt.load(esm); - lt.mId = id; - - // Make sure we have room for the structure - if (plugin >= mStatic.size()) { - mStatic.resize(plugin+1); - } - LandTextureList <exl = mStatic[plugin]; - if(lt.mIndex + 1 > (int)ltexl.size()) - ltexl.resize(lt.mIndex+1); - - // Store it - ltexl[lt.mIndex] = lt; - } + size_t getSize() const; + size_t getSize(size_t plugin) const; + void load(ESM::ESMReader &esm, const std::string &id, size_t plugin); void load(ESM::ESMReader &esm, const std::string &id); - iterator begin(size_t plugin) const { - assert(plugin < mStatic.size()); - return mStatic[plugin].begin(); - } - - iterator end(size_t plugin) const { - assert(plugin < mStatic.size()); - return mStatic[plugin].end(); - } + iterator begin(size_t plugin) const; + iterator end(size_t plugin) const; }; template <> @@ -461,88 +216,22 @@ namespace MWWorld { std::vector mStatic; - struct Compare - { - bool operator()(const ESM::Land *x, const ESM::Land *y) { - if (x->mX == y->mX) { - return x->mY < y->mY; - } - return x->mX < y->mX; - } - }; - public: typedef SharedIterator iterator; - virtual ~Store() - { - for (std::vector::const_iterator it = - mStatic.begin(); it != mStatic.end(); ++it) - { - delete *it; - } + virtual ~Store(); - } - - size_t getSize() const { - return mStatic.size(); - } - - iterator begin() const { - return iterator(mStatic.begin()); - } - - iterator end() const { - return iterator(mStatic.end()); - } + size_t getSize() const; + iterator begin() const; + iterator end() const; // Must be threadsafe! Called from terrain background loading threads. // Not a big deal here, since ESM::Land can never be modified or inserted/erased - ESM::Land *search(int x, int y) const { - ESM::Land land; - land.mX = x, land.mY = y; - - std::vector::const_iterator it = - std::lower_bound(mStatic.begin(), mStatic.end(), &land, Compare()); - - if (it != mStatic.end() && (*it)->mX == x && (*it)->mY == y) { - return const_cast(*it); - } - return 0; - } + ESM::Land *search(int x, int y) const; + ESM::Land *find(int x, int y) const; - ESM::Land *find(int x, int y) const{ - ESM::Land *ptr = search(x, y); - if (ptr == 0) { - std::ostringstream msg; - msg << "Land at (" << x << ", " << y << ") not found"; - throw std::runtime_error(msg.str()); - } - return ptr; - } - - void load(ESM::ESMReader &esm, const std::string &id) { - ESM::Land *ptr = new ESM::Land(); - ptr->load(esm); - - // Same area defined in multiple plugins? -> last plugin wins - // Can't use search() because we aren't sorted yet - is there any other way to speed this up? - for (std::vector::iterator it = mStatic.begin(); it != mStatic.end(); ++it) - { - if ((*it)->mX == ptr->mX && (*it)->mY == ptr->mY) - { - delete *it; - mStatic.erase(it); - break; - } - } - - mStatic.push_back(ptr); - } - - void setUp() { - std::sort(mStatic.begin(), mStatic.end(), Compare()); - } + void load(ESM::ESMReader &esm, const std::string &id); + void setUp(); }; template <> @@ -576,261 +265,44 @@ namespace MWWorld DynamicInt mDynamicInt; DynamicExt mDynamicExt; - const ESM::Cell *search(const ESM::Cell &cell) const { - if (cell.isExterior()) { - return search(cell.getGridX(), cell.getGridY()); - } - return search(cell.mName); - } - + const ESM::Cell *search(const ESM::Cell &cell) const; void handleMovedCellRefs(ESM::ESMReader& esm, ESM::Cell* cell); public: typedef SharedIterator iterator; - const ESM::Cell *search(const std::string &id) const { - ESM::Cell cell; - cell.mName = Misc::StringUtils::lowerCase(id); - - std::map::const_iterator it = mInt.find(cell.mName); - - if (it != mInt.end() && Misc::StringUtils::ciEqual(it->second.mName, id)) { - return &(it->second); - } - - DynamicInt::const_iterator dit = mDynamicInt.find(cell.mName); - if (dit != mDynamicInt.end()) { - return &dit->second; - } - - return 0; - } + const ESM::Cell *search(const std::string &id) const; + const ESM::Cell *search(int x, int y) const; + const ESM::Cell *searchOrCreate(int x, int y); - const ESM::Cell *search(int x, int y) const { - ESM::Cell cell; - cell.mData.mX = x, cell.mData.mY = y; + const ESM::Cell *find(const std::string &id) const; + const ESM::Cell *find(int x, int y) const; - std::pair key(x, y); - DynamicExt::const_iterator it = mExt.find(key); - if (it != mExt.end()) { - return &(it->second); - } - - DynamicExt::const_iterator dit = mDynamicExt.find(key); - if (dit != mDynamicExt.end()) { - return &dit->second; - } - - return 0; - } - - const ESM::Cell *searchOrCreate(int x, int y) { - std::pair key(x, y); - DynamicExt::const_iterator it = mExt.find(key); - if (it != mExt.end()) { - return &(it->second); - } + void setUp(); - DynamicExt::const_iterator dit = mDynamicExt.find(key); - if (dit != mDynamicExt.end()) { - return &dit->second; - } - - ESM::Cell newCell; - newCell.mData.mX = x; - newCell.mData.mY = y; - newCell.mData.mFlags = ESM::Cell::HasWater; - newCell.mAmbi.mAmbient = 0; - newCell.mAmbi.mSunlight = 0; - newCell.mAmbi.mFog = 0; - newCell.mAmbi.mFogDensity = 0; - return &mExt.insert(std::make_pair(key, newCell)).first->second; - } - - const ESM::Cell *find(const std::string &id) const { - const ESM::Cell *ptr = search(id); - if (ptr == 0) { - std::ostringstream msg; - msg << "Interior cell '" << id << "' not found"; - throw std::runtime_error(msg.str()); - } - return ptr; - } - - const ESM::Cell *find(int x, int y) const { - const ESM::Cell *ptr = search(x, y); - if (ptr == 0) { - std::ostringstream msg; - msg << "Exterior at (" << x << ", " << y << ") not found"; - throw std::runtime_error(msg.str()); - } - return ptr; - } - - void setUp() { - typedef DynamicExt::iterator ExtIterator; - typedef std::map::iterator IntIterator; - - mSharedInt.clear(); - mSharedInt.reserve(mInt.size()); - for (IntIterator it = mInt.begin(); it != mInt.end(); ++it) { - mSharedInt.push_back(&(it->second)); - } - - mSharedExt.clear(); - mSharedExt.reserve(mExt.size()); - for (ExtIterator it = mExt.begin(); it != mExt.end(); ++it) { - mSharedExt.push_back(&(it->second)); - } - } - - // HACK: Method implementation had to be moved to a separate cpp file, as we would otherwise get - // errors related to the compare operator used in std::find for ESM::MovedCellRefTracker::find. - // There some nasty three-way cyclic header dependency involved, which I could only fix by moving - // this method. void load(ESM::ESMReader &esm, const std::string &id); - iterator intBegin() const { - return iterator(mSharedInt.begin()); - } - - iterator intEnd() const { - return iterator(mSharedInt.end()); - } - - iterator extBegin() const { - return iterator(mSharedExt.begin()); - } - - iterator extEnd() const { - return iterator(mSharedExt.end()); - } + iterator intBegin() const; + iterator intEnd() const; + iterator extBegin() const; + iterator extEnd() const; // Return the northernmost cell in the easternmost column. - const ESM::Cell *searchExtByName(const std::string &id) const { - ESM::Cell *cell = 0; - std::vector::const_iterator it = mSharedExt.begin(); - for (; it != mSharedExt.end(); ++it) { - if (Misc::StringUtils::ciEqual((*it)->mName, id)) { - if ( cell == 0 || - ( (*it)->mData.mX > cell->mData.mX ) || - ( (*it)->mData.mX == cell->mData.mX && (*it)->mData.mY > cell->mData.mY ) ) - { - cell = *it; - } - } - } - return cell; - } + const ESM::Cell *searchExtByName(const std::string &id) const; // Return the northernmost cell in the easternmost column. - const ESM::Cell *searchExtByRegion(const std::string &id) const { - ESM::Cell *cell = 0; - std::vector::const_iterator it = mSharedExt.begin(); - for (; it != mSharedExt.end(); ++it) { - if (Misc::StringUtils::ciEqual((*it)->mRegion, id)) { - if ( cell == 0 || - ( (*it)->mData.mX > cell->mData.mX ) || - ( (*it)->mData.mX == cell->mData.mX && (*it)->mData.mY > cell->mData.mY ) ) - { - cell = *it; - } - } - } - return cell; - } - - size_t getSize() const { - return mSharedInt.size() + mSharedExt.size(); - } + const ESM::Cell *searchExtByRegion(const std::string &id) const; - void listIdentifier(std::vector &list) const { - list.reserve(list.size() + mSharedInt.size()); - - std::vector::const_iterator it = mSharedInt.begin(); - for (; it != mSharedInt.end(); ++it) { - list.push_back((*it)->mName); - } - } - - ESM::Cell *insert(const ESM::Cell &cell) { - if (search(cell) != 0) { - std::ostringstream msg; - msg << "Failed to create "; - msg << ((cell.isExterior()) ? "exterior" : "interior"); - msg << " cell"; - - throw std::runtime_error(msg.str()); - } - ESM::Cell *ptr; - if (cell.isExterior()) { - std::pair key(cell.getGridX(), cell.getGridY()); + size_t getSize() const; - // duplicate insertions are avoided by search(ESM::Cell &) - std::pair result = - mDynamicExt.insert(std::make_pair(key, cell)); + void listIdentifier(std::vector &list) const; - ptr = &result.first->second; - mSharedExt.push_back(ptr); - } else { - std::string key = Misc::StringUtils::lowerCase(cell.mName); + ESM::Cell *insert(const ESM::Cell &cell); - // duplicate insertions are avoided by search(ESM::Cell &) - std::pair result = - mDynamicInt.insert(std::make_pair(key, cell)); + bool erase(const ESM::Cell &cell); + bool erase(const std::string &id); - ptr = &result.first->second; - mSharedInt.push_back(ptr); - } - return ptr; - } - - bool erase(const ESM::Cell &cell) { - if (cell.isExterior()) { - return erase(cell.getGridX(), cell.getGridY()); - } - return erase(cell.mName); - } - - bool erase(const std::string &id) { - std::string key = Misc::StringUtils::lowerCase(id); - DynamicInt::iterator it = mDynamicInt.find(key); - - if (it == mDynamicInt.end()) { - return false; - } - mDynamicInt.erase(it); - mSharedInt.erase( - mSharedInt.begin() + mSharedInt.size(), - mSharedInt.end() - ); - - for (it = mDynamicInt.begin(); it != mDynamicInt.end(); ++it) { - mSharedInt.push_back(&it->second); - } - - return true; - } - - bool erase(int x, int y) { - std::pair key(x, y); - DynamicExt::iterator it = mDynamicExt.find(key); - - if (it == mDynamicExt.end()) { - return false; - } - mDynamicExt.erase(it); - mSharedExt.erase( - mSharedExt.begin() + mSharedExt.size(), - mSharedExt.end() - ); - - for (it = mDynamicExt.begin(); it != mDynamicExt.end(); ++it) { - mSharedExt.push_back(&it->second); - } - - return true; - } + bool erase(int x, int y); }; template <> @@ -847,165 +319,33 @@ namespace MWWorld public: - Store() - : mCells(NULL) - { - } - - void setCells(Store& cells) - { - mCells = &cells; - } - - void load(ESM::ESMReader &esm, const std::string &id) { - ESM::Pathgrid pathgrid; - pathgrid.load(esm); - - // Unfortunately the Pathgrid record model does not specify whether the pathgrid belongs to an interior or exterior cell. - // For interior cells, mCell is the cell name, but for exterior cells it is either the cell name or if that doesn't exist, the cell's region name. - // mX and mY will be (0,0) for interior cells, but there is also an exterior cell with the coordinates of (0,0), so that doesn't help. - // Check whether mCell is an interior cell. This isn't perfect, will break if a Region with the same name as an interior cell is created. - // A proper fix should be made for future versions of the file format. - bool interior = mCells->search(pathgrid.mCell) != NULL; - - // Try to overwrite existing record - if (interior) - { - std::pair ret = mInt.insert(std::make_pair(pathgrid.mCell, pathgrid)); - if (!ret.second) - ret.first->second = pathgrid; - } - else - { - std::pair ret = mExt.insert(std::make_pair(std::make_pair(pathgrid.mData.mX, pathgrid.mData.mY), pathgrid)); - if (!ret.second) - ret.first->second = pathgrid; - } - } + Store(); - size_t getSize() const { - return mInt.size() + mExt.size(); - } - - void setUp() { - } - - const ESM::Pathgrid *search(int x, int y) const { - Exterior::const_iterator it = mExt.find(std::make_pair(x,y)); - if (it != mExt.end()) - return &(it->second); - return NULL; - } - - const ESM::Pathgrid *search(const std::string& name) const { - Interior::const_iterator it = mInt.find(name); - if (it != mInt.end()) - return &(it->second); - return NULL; - } - - const ESM::Pathgrid *find(int x, int y) const { - const ESM::Pathgrid* pathgrid = search(x,y); - if (!pathgrid) - { - std::ostringstream msg; - msg << "Pathgrid in cell '" << x << " " << y << "' not found"; - throw std::runtime_error(msg.str()); - } - return pathgrid; - } + void setCells(Store& cells); + void load(ESM::ESMReader &esm, const std::string &id); + size_t getSize() const; - const ESM::Pathgrid* find(const std::string& name) const { - const ESM::Pathgrid* pathgrid = search(name); - if (!pathgrid) - { - std::ostringstream msg; - msg << "Pathgrid in cell '" << name << "' not found"; - throw std::runtime_error(msg.str()); - } - return pathgrid; - } + void setUp(); - const ESM::Pathgrid *search(const ESM::Cell &cell) const { - if (!(cell.mData.mFlags & ESM::Cell::Interior)) - return search(cell.mData.mX, cell.mData.mY); - else - return search(cell.mName); - } - - const ESM::Pathgrid *find(const ESM::Cell &cell) const { - if (!(cell.mData.mFlags & ESM::Cell::Interior)) - return find(cell.mData.mX, cell.mData.mY); - else - return find(cell.mName); - } + const ESM::Pathgrid *search(int x, int y) const; + const ESM::Pathgrid *search(const std::string& name) const; + const ESM::Pathgrid *find(int x, int y) const; + const ESM::Pathgrid* find(const std::string& name) const; + const ESM::Pathgrid *search(const ESM::Cell &cell) const; + const ESM::Pathgrid *find(const ESM::Cell &cell) const; }; - template - class IndexedStore - { - protected: - typedef typename std::map Static; - Static mStatic; - - public: - typedef typename std::map::const_iterator iterator; - - IndexedStore() {} - - iterator begin() const { - return mStatic.begin(); - } - - iterator end() const { - return mStatic.end(); - } - - void load(ESM::ESMReader &esm) { - T record; - record.load(esm); - - // Try to overwrite existing record - std::pair ret = mStatic.insert(std::make_pair(record.mIndex, record)); - if (!ret.second) - ret.first->second = record; - } - - int getSize() const { - return mStatic.size(); - } - - void setUp() { - } - - const T *search(int index) const { - typename Static::const_iterator it = mStatic.find(index); - if (it != mStatic.end()) - return &(it->second); - return NULL; - } - - const T *find(int index) const { - const T *ptr = search(index); - if (ptr == 0) { - std::ostringstream msg; - msg << T::getRecordType() << " with index " << index << " not found"; - throw std::runtime_error(msg.str()); - } - return ptr; - } - }; template <> struct Store : public IndexedStore { - Store() {} + Store(); }; template <> struct Store : public IndexedStore { - Store() {} + Store(); }; template <> @@ -1016,70 +356,18 @@ namespace MWWorld public: typedef std::vector::const_iterator iterator; - Store() { - mStatic.reserve(ESM::Attribute::Length); - } + Store(); - const ESM::Attribute *search(size_t index) const { - if (index >= mStatic.size()) { - return 0; - } - return &mStatic.at(index); - } - - const ESM::Attribute *find(size_t index) const { - const ESM::Attribute *ptr = search(index); - if (ptr == 0) { - std::ostringstream msg; - msg << "Attribute with index " << index << " not found"; - throw std::runtime_error(msg.str()); - } - return ptr; - } + const ESM::Attribute *search(size_t index) const; + const ESM::Attribute *find(size_t index) const; - void setUp() { - for (int i = 0; i < ESM::Attribute::Length; ++i) { - mStatic.push_back( - ESM::Attribute( - ESM::Attribute::sAttributeIds[i], - ESM::Attribute::sGmstAttributeIds[i], - ESM::Attribute::sGmstAttributeDescIds[i] - ) - ); - } - } - - size_t getSize() const { - return mStatic.size(); - } + void setUp(); - iterator begin() const { - return mStatic.begin(); - } - - iterator end() const { - return mStatic.end(); - } + size_t getSize() const; + iterator begin() const; + iterator end() const; }; - template<> - inline void Store::setUp() - { - // DialInfos marked as deleted are kept during the loading phase, so that the linked list - // structure is kept intact for inserting further INFOs. Delete them now that loading is done. - for (Static::iterator it = mStatic.begin(); it != mStatic.end(); ++it) - { - ESM::Dialogue& dial = it->second; - dial.clearDeletedInfos(); - } - - mShared.clear(); - mShared.reserve(mStatic.size()); - std::map::iterator it = mStatic.begin(); - for (; it != mStatic.end(); ++it) { - mShared.push_back(&(it->second)); - } - } } //end namespace diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 70d6f1b36..f51cfd59b 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -5,6 +5,7 @@ #include +#include #include #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 7964edf45..5251427c5 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -52,6 +52,11 @@ namespace MWRender class Camera; } +namespace ToUTF8 +{ + class Utf8Encoder; +} + struct ContentLoader; namespace MWWorld From 3a0293480e73b29a2548b76ea3da5ecf8e2cbab9 Mon Sep 17 00:00:00 2001 From: Scott Howard Date: Thu, 9 Jul 2015 15:32:15 -0400 Subject: [PATCH 1762/3725] Update boost in travis-ci to fix build failure --- CI/before_install.linux.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CI/before_install.linux.sh b/CI/before_install.linux.sh index 2408a5822..2efb6e2bb 100755 --- a/CI/before_install.linux.sh +++ b/CI/before_install.linux.sh @@ -10,9 +10,10 @@ fi echo "yes" | sudo add-apt-repository "deb http://archive.ubuntu.com/ubuntu `lsb_release -sc` main universe restricted multiverse" echo "yes" | sudo apt-add-repository ppa:openmw/openmw +echo "yes" | sudo apt-add-repository ppa:boost-latest/ppa sudo apt-get update -qq sudo apt-get install -qq libgtest-dev google-mock -sudo apt-get install -qq libboost-filesystem-dev libboost-program-options-dev libboost-system-dev libboost-thread-dev +sudo apt-get install -qq libboost-filesystem1.55-dev libboost-program-options1.55-dev libboost-system1.55-dev libboost-thread1.55-dev sudo apt-get install -qq libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libavresample-dev sudo apt-get install -qq libbullet-dev libopenscenegraph-dev libmygui-dev libsdl2-dev libunshield-dev libtinyxml-dev libopenal-dev libqt4-dev sudo apt-get install -qq cmake-data #workaround for broken osgqt cmake script in ubuntu 12.04 From 2bebfea38da9d1cdfa0613a96a4d5d18bc2c33ee Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Thu, 9 Jul 2015 22:45:25 +0200 Subject: [PATCH 1763/3725] Instantiate struct as a struct --- components/esm/statstate.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/esm/statstate.cpp b/components/esm/statstate.cpp index e95295cc9..c17bedd81 100644 --- a/components/esm/statstate.cpp +++ b/components/esm/statstate.cpp @@ -46,7 +46,7 @@ namespace ESM if (mProgress) esm.writeHNT("STPR", mProgress); } - - template class StatState; - template class StatState; } + +template struct ESM::StatState; +template struct ESM::StatState; From 926c825d0c7f0a373fb6bd22d88d0df850407f3c Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Tue, 7 Jul 2015 15:37:42 +0300 Subject: [PATCH 1764/3725] Add NAME and DELE handling to ESM records. Changed records are those where DELE is located after NAME sub-record. And DELE is the last sub-record. --- components/esm/loadacti.cpp | 15 +++++++++++++++ components/esm/loadacti.hpp | 2 ++ components/esm/loadalch.cpp | 16 ++++++++++++++++ components/esm/loadalch.hpp | 2 ++ components/esm/loadappa.cpp | 15 +++++++++++++++ components/esm/loadappa.hpp | 2 ++ components/esm/loadarmo.cpp | 16 ++++++++++++++++ components/esm/loadarmo.hpp | 2 ++ components/esm/loadbody.cpp | 16 ++++++++++++++++ components/esm/loadbody.hpp | 2 ++ components/esm/loadbook.cpp | 15 +++++++++++++++ components/esm/loadbook.hpp | 2 ++ components/esm/loadclas.cpp | 16 ++++++++++++++++ components/esm/loadclas.hpp | 2 ++ components/esm/loadclot.cpp | 16 ++++++++++++++++ components/esm/loadclot.hpp | 2 ++ components/esm/loadcont.cpp | 16 ++++++++++++++++ components/esm/loadcont.hpp | 2 ++ components/esm/loadcrea.cpp | 15 +++++++++++++++ components/esm/loadcrea.hpp | 3 ++- components/esm/loaddoor.cpp | 15 +++++++++++++++ components/esm/loaddoor.hpp | 2 ++ components/esm/loadench.cpp | 17 +++++++++++++++++ components/esm/loadench.hpp | 2 ++ components/esm/loadfact.cpp | 16 ++++++++++++++++ components/esm/loadfact.hpp | 2 ++ components/esm/loadingr.cpp | 16 ++++++++++++++++ components/esm/loadingr.hpp | 2 ++ components/esm/loadlevlist.cpp | 15 +++++++++++++++ components/esm/loadlevlist.hpp | 2 ++ components/esm/loadligh.cpp | 15 +++++++++++++++ components/esm/loadligh.hpp | 2 ++ components/esm/loadlock.cpp | 15 +++++++++++++++ components/esm/loadlock.hpp | 2 ++ components/esm/loadmisc.cpp | 15 +++++++++++++++ components/esm/loadmisc.hpp | 2 ++ components/esm/loadnpc.cpp | 15 +++++++++++++++ components/esm/loadnpc.hpp | 2 ++ components/esm/loadprob.cpp | 15 +++++++++++++++ components/esm/loadprob.hpp | 2 ++ components/esm/loadrepa.cpp | 15 +++++++++++++++ components/esm/loadrepa.hpp | 2 ++ components/esm/loadsndg.cpp | 15 +++++++++++++++ components/esm/loadsndg.hpp | 2 ++ components/esm/loadsoun.cpp | 16 ++++++++++++++++ components/esm/loadsoun.hpp | 2 ++ components/esm/loadspel.cpp | 17 +++++++++++++++++ components/esm/loadspel.hpp | 2 ++ components/esm/loadstat.cpp | 15 +++++++++++++++ components/esm/loadstat.hpp | 2 ++ components/esm/loadweap.cpp | 16 ++++++++++++++++ components/esm/loadweap.hpp | 2 ++ components/esm/util.cpp | 20 ++++++++++++++++++++ components/esm/util.hpp | 9 +++++++++ 54 files changed, 485 insertions(+), 1 deletion(-) create mode 100644 components/esm/util.cpp diff --git a/components/esm/loadacti.cpp b/components/esm/loadacti.cpp index b5adce550..295d35f7e 100644 --- a/components/esm/loadacti.cpp +++ b/components/esm/loadacti.cpp @@ -3,6 +3,7 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" +#include "util.hpp" namespace ESM { @@ -10,6 +11,12 @@ namespace ESM void Activator::load(ESMReader &esm) { + mId = esm.getHNString("NAME"); + if (mIsDeleted = readDeleSubRecord(esm)) + { + return; + } + while (esm.hasMoreSubs()) { esm.getSubName(); @@ -32,6 +39,13 @@ namespace ESM } void Activator::save(ESMWriter &esm) const { + esm.writeHNCString("NAME", mId); + if (mIsDeleted) + { + writeDeleSubRecord(esm); + return; + } + esm.writeHNCString("MODL", mModel); esm.writeHNOCString("FNAM", mName); esm.writeHNOCString("SCRI", mScript); @@ -42,5 +56,6 @@ namespace ESM mName.clear(); mScript.clear(); mModel.clear(); + mIsDeleted = false; } } diff --git a/components/esm/loadacti.hpp b/components/esm/loadacti.hpp index d9a55023b..406512a22 100644 --- a/components/esm/loadacti.hpp +++ b/components/esm/loadacti.hpp @@ -17,6 +17,8 @@ struct Activator std::string mId, mName, mScript, mModel; + bool mIsDeleted; + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadalch.cpp b/components/esm/loadalch.cpp index 18db512c0..12078a5f7 100644 --- a/components/esm/loadalch.cpp +++ b/components/esm/loadalch.cpp @@ -3,6 +3,7 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" +#include "util.hpp" namespace ESM { @@ -11,6 +12,13 @@ namespace ESM void Potion::load(ESMReader &esm) { mEffects.mList.clear(); + + mId = esm.getHNString("NAME"); + if (mIsDeleted = readDeleSubRecord(esm)) + { + return; + } + bool hasData = false; while (esm.hasMoreSubs()) { @@ -46,6 +54,13 @@ namespace ESM } void Potion::save(ESMWriter &esm) const { + esm.writeHNCString("NAME", mId); + if (mIsDeleted) + { + writeDeleSubRecord(esm); + return; + } + esm.writeHNCString("MODL", mModel); esm.writeHNOCString("TEXT", mIcon); esm.writeHNOCString("SCRI", mScript); @@ -64,5 +79,6 @@ namespace ESM mIcon.clear(); mScript.clear(); mEffects.mList.clear(); + mIsDeleted = false; } } diff --git a/components/esm/loadalch.hpp b/components/esm/loadalch.hpp index b90a7c448..3d1e6dee7 100644 --- a/components/esm/loadalch.hpp +++ b/components/esm/loadalch.hpp @@ -33,6 +33,8 @@ struct Potion std::string mId, mName, mModel, mIcon, mScript; EffectList mEffects; + bool mIsDeleted; + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadappa.cpp b/components/esm/loadappa.cpp index f2c82aacf..9107e5a8e 100644 --- a/components/esm/loadappa.cpp +++ b/components/esm/loadappa.cpp @@ -3,6 +3,7 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" +#include "util.hpp" namespace ESM { @@ -10,6 +11,12 @@ namespace ESM void Apparatus::load(ESMReader &esm) { + mId = esm.getHNString("NAME"); + if (mIsDeleted = readDeleSubRecord(esm)) + { + return; + } + bool hasData = false; while (esm.hasMoreSubs()) { @@ -43,6 +50,13 @@ void Apparatus::load(ESMReader &esm) void Apparatus::save(ESMWriter &esm) const { + esm.writeHNCString("NAME", mId); + if (mIsDeleted) + { + writeDeleSubRecord(esm); + return; + } + esm.writeHNCString("MODL", mModel); esm.writeHNCString("FNAM", mName); esm.writeHNT("AADT", mData, 16); @@ -60,5 +74,6 @@ void Apparatus::save(ESMWriter &esm) const mIcon.clear(); mScript.clear(); mName.clear(); + mIsDeleted = false; } } diff --git a/components/esm/loadappa.hpp b/components/esm/loadappa.hpp index f18b04648..62d8561a1 100644 --- a/components/esm/loadappa.hpp +++ b/components/esm/loadappa.hpp @@ -38,6 +38,8 @@ struct Apparatus AADTstruct mData; std::string mId, mModel, mIcon, mScript, mName; + bool mIsDeleted; + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadarmo.cpp b/components/esm/loadarmo.cpp index 066551d6f..626893d00 100644 --- a/components/esm/loadarmo.cpp +++ b/components/esm/loadarmo.cpp @@ -3,6 +3,7 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" +#include "util.hpp" namespace ESM { @@ -41,6 +42,13 @@ namespace ESM void Armor::load(ESMReader &esm) { mParts.mParts.clear(); + + mId = esm.getHNString("NAME"); + if (mIsDeleted = readDeleSubRecord(esm)) + { + return; + } + bool hasData = false; while (esm.hasMoreSubs()) { @@ -80,6 +88,13 @@ namespace ESM void Armor::save(ESMWriter &esm) const { + esm.writeHNCString("NAME", mId); + if (mIsDeleted) + { + writeDeleSubRecord(esm); + return; + } + esm.writeHNCString("MODL", mModel); esm.writeHNOCString("FNAM", mName); esm.writeHNOCString("SCRI", mScript); @@ -103,5 +118,6 @@ namespace ESM mIcon.clear(); mScript.clear(); mEnchant.clear(); + mIsDeleted = false; } } diff --git a/components/esm/loadarmo.hpp b/components/esm/loadarmo.hpp index 54416fd31..eb911254f 100644 --- a/components/esm/loadarmo.hpp +++ b/components/esm/loadarmo.hpp @@ -96,6 +96,8 @@ struct Armor std::string mId, mName, mModel, mIcon, mScript, mEnchant; + bool mIsDeleted; + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadbody.cpp b/components/esm/loadbody.cpp index ed24ded57..644eb3b50 100644 --- a/components/esm/loadbody.cpp +++ b/components/esm/loadbody.cpp @@ -3,6 +3,7 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" +#include "util.hpp" namespace ESM { @@ -11,6 +12,12 @@ namespace ESM void BodyPart::load(ESMReader &esm) { + mId = esm.getHNString("NAME"); + if (mIsDeleted = readDeleSubRecord(esm)) + { + return; + } + bool hasData = false; while (esm.hasMoreSubs()) { @@ -38,6 +45,13 @@ void BodyPart::load(ESMReader &esm) } void BodyPart::save(ESMWriter &esm) const { + esm.writeHNCString("NAME", mId); + if (mIsDeleted) + { + writeDeleSubRecord(esm); + return; + } + esm.writeHNCString("MODL", mModel); esm.writeHNOCString("FNAM", mRace); esm.writeHNT("BYDT", mData, 4); @@ -52,5 +66,7 @@ void BodyPart::save(ESMWriter &esm) const mModel.clear(); mRace.clear(); + + mIsDeleted = false; } } diff --git a/components/esm/loadbody.hpp b/components/esm/loadbody.hpp index c48c31305..8e1e81f82 100644 --- a/components/esm/loadbody.hpp +++ b/components/esm/loadbody.hpp @@ -60,6 +60,8 @@ struct BodyPart BYDTstruct mData; std::string mId, mModel, mRace; + bool mIsDeleted; + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadbook.cpp b/components/esm/loadbook.cpp index 47f52fc31..aec361873 100644 --- a/components/esm/loadbook.cpp +++ b/components/esm/loadbook.cpp @@ -3,6 +3,7 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" +#include "util.hpp" namespace ESM { @@ -10,6 +11,12 @@ namespace ESM void Book::load(ESMReader &esm) { + mId = esm.getHNString("NAME"); + if (mIsDeleted = readDeleSubRecord(esm)) + { + return; + } + bool hasData = false; while (esm.hasMoreSubs()) { @@ -48,6 +55,13 @@ namespace ESM } void Book::save(ESMWriter &esm) const { + esm.writeHNCString("NAME", mId); + if (mIsDeleted) + { + writeDeleSubRecord(esm); + return; + } + esm.writeHNCString("MODL", mModel); esm.writeHNOCString("FNAM", mName); esm.writeHNT("BKDT", mData, 20); @@ -70,5 +84,6 @@ namespace ESM mScript.clear(); mEnchant.clear(); mText.clear(); + mIsDeleted = false; } } diff --git a/components/esm/loadbook.hpp b/components/esm/loadbook.hpp index 6211b3e45..2f374c4b2 100644 --- a/components/esm/loadbook.hpp +++ b/components/esm/loadbook.hpp @@ -28,6 +28,8 @@ struct Book std::string mName, mModel, mIcon, mScript, mEnchant, mText; std::string mId; + bool mIsDeleted; + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadclas.cpp b/components/esm/loadclas.cpp index 66acaea72..df47a1a33 100644 --- a/components/esm/loadclas.cpp +++ b/components/esm/loadclas.cpp @@ -5,6 +5,7 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" +#include "util.hpp" namespace ESM { @@ -41,6 +42,12 @@ namespace ESM void Class::load(ESMReader &esm) { + mId = esm.getHNString("NAME"); + if (mIsDeleted = readDeleSubRecord(esm)) + { + return; + } + bool hasData = false; while (esm.hasMoreSubs()) { @@ -69,6 +76,13 @@ namespace ESM } void Class::save(ESMWriter &esm) const { + esm.writeHNCString("NAME", mId); + if (mIsDeleted) + { + writeDeleSubRecord(esm); + return; + } + esm.writeHNOCString("FNAM", mName); esm.writeHNT("CLDT", mData, 60); esm.writeHNOString("DESC", mDescription); @@ -87,5 +101,7 @@ namespace ESM for (int i=0; i<5; ++i) for (int i2=0; i2<2; ++i2) mData.mSkills[i][i2] = 0; + + mIsDeleted = false; } } diff --git a/components/esm/loadclas.hpp b/components/esm/loadclas.hpp index 972b48e88..b61913734 100644 --- a/components/esm/loadclas.hpp +++ b/components/esm/loadclas.hpp @@ -73,6 +73,8 @@ struct Class std::string mId, mName, mDescription; CLDTstruct mData; + bool mIsDeleted; + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadclot.cpp b/components/esm/loadclot.cpp index 5f49b5e70..1c73c4f21 100644 --- a/components/esm/loadclot.cpp +++ b/components/esm/loadclot.cpp @@ -3,6 +3,7 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" +#include "util.hpp" namespace ESM { @@ -11,6 +12,13 @@ namespace ESM void Clothing::load(ESMReader &esm) { mParts.mParts.clear(); + + mId = esm.getHNString("NAME"); + if (mIsDeleted = readDeleSubRecord(esm)) + { + return; + } + bool hasData = false; while (esm.hasMoreSubs()) { @@ -50,6 +58,13 @@ namespace ESM void Clothing::save(ESMWriter &esm) const { + esm.writeHNCString("NAME", mId); + if (mIsDeleted) + { + writeDeleSubRecord(esm); + return; + } + esm.writeHNCString("MODL", mModel); esm.writeHNOCString("FNAM", mName); esm.writeHNT("CTDT", mData, 12); @@ -74,5 +89,6 @@ namespace ESM mIcon.clear(); mEnchant.clear(); mScript.clear(); + mIsDeleted = false; } } diff --git a/components/esm/loadclot.hpp b/components/esm/loadclot.hpp index 6945f224a..8b4a8b3bb 100644 --- a/components/esm/loadclot.hpp +++ b/components/esm/loadclot.hpp @@ -48,6 +48,8 @@ struct Clothing std::string mId, mName, mModel, mIcon, mEnchant, mScript; + bool mIsDeleted; + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadcont.cpp b/components/esm/loadcont.cpp index 3481189c3..f54fe66e2 100644 --- a/components/esm/loadcont.cpp +++ b/components/esm/loadcont.cpp @@ -3,6 +3,7 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" +#include "util.hpp" namespace ESM { @@ -27,6 +28,13 @@ namespace ESM void Container::load(ESMReader &esm) { mInventory.mList.clear(); + + mId = esm.getHNString("NAME"); + if (mIsDeleted = readDeleSubRecord(esm)) + { + return; + } + bool hasWeight = false; bool hasFlags = false; while (esm.hasMoreSubs()) @@ -71,6 +79,13 @@ namespace ESM void Container::save(ESMWriter &esm) const { + esm.writeHNCString("NAME", mId); + if (mIsDeleted) + { + writeDeleSubRecord(esm); + return; + } + esm.writeHNCString("MODL", mModel); esm.writeHNOCString("FNAM", mName); esm.writeHNT("CNDT", mWeight, 4); @@ -89,5 +104,6 @@ namespace ESM mWeight = 0; mFlags = 0x8; // set default flag value mInventory.mList.clear(); + mIsDeleted = false; } } diff --git a/components/esm/loadcont.hpp b/components/esm/loadcont.hpp index ab587f935..51166b8d4 100644 --- a/components/esm/loadcont.hpp +++ b/components/esm/loadcont.hpp @@ -52,6 +52,8 @@ struct Container int mFlags; InventoryList mInventory; + bool mIsDeleted; + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadcrea.cpp b/components/esm/loadcrea.cpp index 50c47349c..6da32eed7 100644 --- a/components/esm/loadcrea.cpp +++ b/components/esm/loadcrea.cpp @@ -3,6 +3,7 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" +#include "util.hpp" namespace ESM { @@ -17,6 +18,12 @@ namespace ESM { mSpells.mList.clear(); mTransport.mList.clear(); + mId = esm.getHNString("NAME"); + if (mIsDeleted = readDeleSubRecord(esm)) + { + return; + } + mScale = 1.f; mHasAI = false; bool hasNpdt = false; @@ -84,6 +91,13 @@ namespace ESM { void Creature::save(ESMWriter &esm) const { + esm.writeHNCString("NAME", mId); + if (mIsDeleted) + { + writeDeleSubRecord(esm); + return; + } + esm.writeHNCString("MODL", mModel); esm.writeHNOCString("CNAM", mOriginal); esm.writeHNOCString("FNAM", mName); @@ -127,6 +141,7 @@ namespace ESM { mAiData.mServices = 0; mAiPackage.mList.clear(); mTransport.mList.clear(); + mIsDeleted = false; } const std::vector& Creature::getTransport() const diff --git a/components/esm/loadcrea.hpp b/components/esm/loadcrea.hpp index 47e5954a5..fb43f6272 100644 --- a/components/esm/loadcrea.hpp +++ b/components/esm/loadcrea.hpp @@ -91,12 +91,13 @@ struct Creature InventoryList mInventory; SpellList mSpells; - bool mHasAI; AIData mAiData; AIPackageList mAiPackage; Transport mTransport; + bool mIsDeleted; + const std::vector& getTransport() const; void load(ESMReader &esm); diff --git a/components/esm/loaddoor.cpp b/components/esm/loaddoor.cpp index f446eed61..6ee43fd1a 100644 --- a/components/esm/loaddoor.cpp +++ b/components/esm/loaddoor.cpp @@ -3,6 +3,7 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" +#include "util.hpp" namespace ESM { @@ -10,6 +11,12 @@ namespace ESM void Door::load(ESMReader &esm) { + mId = esm.getHNString("NAME"); + if (mIsDeleted = readDeleSubRecord(esm)) + { + return; + } + while (esm.hasMoreSubs()) { esm.getSubName(); @@ -39,6 +46,13 @@ namespace ESM void Door::save(ESMWriter &esm) const { + esm.writeHNCString("NAME", mId); + if (mIsDeleted) + { + writeDeleSubRecord(esm); + return; + } + esm.writeHNCString("MODL", mModel); esm.writeHNOCString("FNAM", mName); esm.writeHNOCString("SCRI", mScript); @@ -53,5 +67,6 @@ namespace ESM mScript.clear(); mOpenSound.clear(); mCloseSound.clear(); + mIsDeleted = false; } } diff --git a/components/esm/loaddoor.hpp b/components/esm/loaddoor.hpp index 3073f4e9d..b0326a744 100644 --- a/components/esm/loaddoor.hpp +++ b/components/esm/loaddoor.hpp @@ -17,6 +17,8 @@ struct Door std::string mId, mName, mModel, mScript, mOpenSound, mCloseSound; + bool mIsDeleted; + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadench.cpp b/components/esm/loadench.cpp index 54690d9a0..88d9e0f2e 100644 --- a/components/esm/loadench.cpp +++ b/components/esm/loadench.cpp @@ -3,6 +3,7 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" +#include "util.hpp" namespace ESM { @@ -11,6 +12,13 @@ namespace ESM void Enchantment::load(ESMReader &esm) { mEffects.mList.clear(); + + mId = esm.getHNString("NAME"); + if (mIsDeleted = readDeleSubRecord(esm)) + { + return; + } + bool hasData = false; while (esm.hasMoreSubs()) { @@ -36,6 +44,13 @@ void Enchantment::load(ESMReader &esm) void Enchantment::save(ESMWriter &esm) const { + esm.writeHNCString("NAME", mId); + if (mIsDeleted) + { + writeDeleSubRecord(esm); + return; + } + esm.writeHNT("ENDT", mData, 16); mEffects.save(esm); } @@ -48,5 +63,7 @@ void Enchantment::save(ESMWriter &esm) const mData.mAutocalc = 0; mEffects.mList.clear(); + + mIsDeleted = false; } } diff --git a/components/esm/loadench.hpp b/components/esm/loadench.hpp index cfcdd4edc..c9b19e31b 100644 --- a/components/esm/loadench.hpp +++ b/components/esm/loadench.hpp @@ -42,6 +42,8 @@ struct Enchantment ENDTstruct mData; EffectList mEffects; + bool mIsDeleted; + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadfact.cpp b/components/esm/loadfact.cpp index 006ca0ce0..9149c2a30 100644 --- a/components/esm/loadfact.cpp +++ b/components/esm/loadfact.cpp @@ -5,6 +5,7 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" +#include "util.hpp" namespace ESM { @@ -32,6 +33,12 @@ void Faction::load(ESMReader &esm) for (int i=0;i<10;++i) mRanks[i].clear(); + mId = esm.getHNString("NAME"); + if (mIsDeleted = readDeleSubRecord(esm)) + { + return; + } + int rankCounter=0; bool hasData = false; while (esm.hasMoreSubs()) @@ -71,6 +78,13 @@ void Faction::load(ESMReader &esm) } void Faction::save(ESMWriter &esm) const { + esm.writeHNCString("NAME", mId); + if (mIsDeleted) + { + writeDeleSubRecord(esm); + return; + } + esm.writeHNOCString("FNAM", mName); for (int i = 0; i < 10; i++) @@ -109,5 +123,7 @@ void Faction::save(ESMWriter &esm) const mData.mSkills[i] = 0; mReactions.clear(); + + mIsDeleted = false; } } diff --git a/components/esm/loadfact.hpp b/components/esm/loadfact.hpp index 8645e23fd..fec13b1ca 100644 --- a/components/esm/loadfact.hpp +++ b/components/esm/loadfact.hpp @@ -62,6 +62,8 @@ struct Faction // Name of faction ranks (may be empty for NPC factions) std::string mRanks[10]; + bool mIsDeleted; + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadingr.cpp b/components/esm/loadingr.cpp index 7e0cc3168..8bf0278f7 100644 --- a/components/esm/loadingr.cpp +++ b/components/esm/loadingr.cpp @@ -3,6 +3,7 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" +#include "util.hpp" namespace ESM { @@ -10,6 +11,12 @@ namespace ESM void Ingredient::load(ESMReader &esm) { + mId = esm.getHNString("NAME"); + if (mIsDeleted = readDeleSubRecord(esm)) + { + return; + } + bool hasData = false; while (esm.hasMoreSubs()) { @@ -67,6 +74,13 @@ namespace ESM void Ingredient::save(ESMWriter &esm) const { + esm.writeHNCString("NAME", mId); + if (mIsDeleted) + { + writeDeleSubRecord(esm); + return; + } + esm.writeHNCString("MODL", mModel); esm.writeHNOCString("FNAM", mName); esm.writeHNT("IRDT", mData, 56); @@ -89,5 +103,7 @@ namespace ESM mModel.clear(); mIcon.clear(); mScript.clear(); + + mIsDeleted = false; } } diff --git a/components/esm/loadingr.hpp b/components/esm/loadingr.hpp index 5846a9780..69a650180 100644 --- a/components/esm/loadingr.hpp +++ b/components/esm/loadingr.hpp @@ -31,6 +31,8 @@ struct Ingredient IRDTstruct mData; std::string mId, mName, mModel, mIcon, mScript; + bool mIsDeleted; + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadlevlist.cpp b/components/esm/loadlevlist.cpp index ca5c5d74d..c8cb110a6 100644 --- a/components/esm/loadlevlist.cpp +++ b/components/esm/loadlevlist.cpp @@ -3,12 +3,19 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" +#include "util.hpp" namespace ESM { void LevelledListBase::load(ESMReader &esm) { + mId = esm.getHNString("NAME"); + if (mIsDeleted = readDeleSubRecord(esm)) + { + return; + } + esm.getHNT(mFlags, "DATA"); esm.getHNT(mChanceNone, "NNAM"); @@ -42,6 +49,13 @@ namespace ESM } void LevelledListBase::save(ESMWriter &esm) const { + esm.writeHNCString("NAME", mId); + if (mIsDeleted) + { + writeDeleSubRecord(esm); + return; + } + esm.writeHNT("DATA", mFlags); esm.writeHNT("NNAM", mChanceNone); esm.writeHNT("INDX", mList.size()); @@ -58,6 +72,7 @@ namespace ESM mFlags = 0; mChanceNone = 0; mList.clear(); + mIsDeleted = false; } unsigned int CreatureLevList::sRecordId = REC_LEVC; diff --git a/components/esm/loadlevlist.hpp b/components/esm/loadlevlist.hpp index dc6fcda5e..4165275b2 100644 --- a/components/esm/loadlevlist.hpp +++ b/components/esm/loadlevlist.hpp @@ -36,6 +36,8 @@ struct LevelledListBase std::vector mList; + bool mIsDeleted; + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadligh.cpp b/components/esm/loadligh.cpp index 26d70d964..bd91e096c 100644 --- a/components/esm/loadligh.cpp +++ b/components/esm/loadligh.cpp @@ -3,6 +3,7 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" +#include "util.hpp" namespace ESM { @@ -10,6 +11,12 @@ namespace ESM void Light::load(ESMReader &esm) { + mId = esm.getHNString("NAME"); + if (mIsDeleted = readDeleSubRecord(esm)) + { + return; + } + bool hasData = false; while (esm.hasMoreSubs()) { @@ -45,6 +52,13 @@ namespace ESM } void Light::save(ESMWriter &esm) const { + esm.writeHNCString("NAME", mId); + if (mIsDeleted) + { + writeDeleSubRecord(esm); + return; + } + esm.writeHNCString("MODL", mModel); esm.writeHNOCString("FNAM", mName); esm.writeHNOCString("ITEX", mIcon); @@ -66,5 +80,6 @@ namespace ESM mModel.clear(); mIcon.clear(); mName.clear(); + mIsDeleted = false; } } diff --git a/components/esm/loadligh.hpp b/components/esm/loadligh.hpp index ed8c36665..76274e6f4 100644 --- a/components/esm/loadligh.hpp +++ b/components/esm/loadligh.hpp @@ -47,6 +47,8 @@ struct Light std::string mSound, mScript, mModel, mIcon, mName, mId; + bool mIsDeleted; + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadlock.cpp b/components/esm/loadlock.cpp index 2747a6f78..c1e866b58 100644 --- a/components/esm/loadlock.cpp +++ b/components/esm/loadlock.cpp @@ -3,6 +3,7 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" +#include "util.hpp" namespace ESM { @@ -10,6 +11,12 @@ namespace ESM void Lockpick::load(ESMReader &esm) { + mId = esm.getHNString("NAME"); + if (mIsDeleted = readDeleSubRecord(esm)) + { + return; + } + bool hasData = true; while (esm.hasMoreSubs()) { @@ -43,6 +50,13 @@ namespace ESM void Lockpick::save(ESMWriter &esm) const { + esm.writeHNCString("NAME", mId); + if (mIsDeleted) + { + writeDeleSubRecord(esm); + return; + } + esm.writeHNCString("MODL", mModel); esm.writeHNOCString("FNAM", mName); @@ -61,5 +75,6 @@ namespace ESM mModel.clear(); mIcon.clear(); mScript.clear(); + mIsDeleted = false; } } diff --git a/components/esm/loadlock.hpp b/components/esm/loadlock.hpp index 0d678cd64..af18773ed 100644 --- a/components/esm/loadlock.hpp +++ b/components/esm/loadlock.hpp @@ -27,6 +27,8 @@ struct Lockpick Data mData; std::string mId, mName, mModel, mIcon, mScript; + bool mIsDeleted; + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadmisc.cpp b/components/esm/loadmisc.cpp index 81c094f2b..11d2f2a05 100644 --- a/components/esm/loadmisc.cpp +++ b/components/esm/loadmisc.cpp @@ -3,6 +3,7 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" +#include "util.hpp" namespace ESM { @@ -10,6 +11,12 @@ namespace ESM void Miscellaneous::load(ESMReader &esm) { + mId = esm.getHNString("NAME"); + if (mIsDeleted = readDeleSubRecord(esm)) + { + return; + } + bool hasData = false; while (esm.hasMoreSubs()) { @@ -41,6 +48,13 @@ namespace ESM void Miscellaneous::save(ESMWriter &esm) const { + esm.writeHNCString("NAME", mId); + if (mIsDeleted) + { + writeDeleSubRecord(esm); + return; + } + esm.writeHNCString("MODL", mModel); esm.writeHNOCString("FNAM", mName); esm.writeHNT("MCDT", mData, 12); @@ -57,5 +71,6 @@ namespace ESM mModel.clear(); mIcon.clear(); mScript.clear(); + mIsDeleted = false; } } diff --git a/components/esm/loadmisc.hpp b/components/esm/loadmisc.hpp index 6e0b4e01b..5d5e9f66f 100644 --- a/components/esm/loadmisc.hpp +++ b/components/esm/loadmisc.hpp @@ -32,6 +32,8 @@ struct Miscellaneous std::string mId, mName, mModel, mIcon, mScript; + bool mIsDeleted; + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadnpc.cpp b/components/esm/loadnpc.cpp index 44d298785..280db0791 100644 --- a/components/esm/loadnpc.cpp +++ b/components/esm/loadnpc.cpp @@ -3,6 +3,7 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" +#include "util.hpp" namespace ESM { @@ -17,6 +18,12 @@ namespace ESM mTransport.mList.clear(); mAiPackage.mList.clear(); + mId = esm.getHNString("NAME"); + if (mIsDeleted = readDeleSubRecord(esm)) + { + return; + } + bool hasNpdt = false; bool hasFlags = false; mHasAI = false; @@ -103,6 +110,13 @@ namespace ESM } void NPC::save(ESMWriter &esm) const { + esm.writeHNCString("NAME", mId); + if (mIsDeleted) + { + writeDeleSubRecord(esm); + return; + } + esm.writeHNOCString("MODL", mModel); esm.writeHNOCString("FNAM", mName); esm.writeHNCString("RNAM", mRace); @@ -178,6 +192,7 @@ namespace ESM mScript.clear(); mHair.clear(); mHead.clear(); + mIsDeleted = false; } int NPC::getFactionRank() const diff --git a/components/esm/loadnpc.hpp b/components/esm/loadnpc.hpp index 9bda9560e..7b75cb178 100644 --- a/components/esm/loadnpc.hpp +++ b/components/esm/loadnpc.hpp @@ -130,6 +130,8 @@ struct NPC // body parts std::string mHair, mHead; + bool mIsDeleted; + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadprob.cpp b/components/esm/loadprob.cpp index c5f80c584..12f7ad00a 100644 --- a/components/esm/loadprob.cpp +++ b/components/esm/loadprob.cpp @@ -3,6 +3,7 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" +#include "util.hpp" namespace ESM { @@ -10,6 +11,12 @@ namespace ESM void Probe::load(ESMReader &esm) { + mId = esm.getHNString("NAME"); + if (mIsDeleted = readDeleSubRecord(esm)) + { + return; + } + bool hasData = true; while (esm.hasMoreSubs()) { @@ -43,6 +50,13 @@ namespace ESM void Probe::save(ESMWriter &esm) const { + esm.writeHNCString("NAME", mId); + if (mIsDeleted) + { + writeDeleSubRecord(esm); + return; + } + esm.writeHNCString("MODL", mModel); esm.writeHNOCString("FNAM", mName); @@ -61,5 +75,6 @@ namespace ESM mModel.clear(); mIcon.clear(); mScript.clear(); + mIsDeleted = false; } } diff --git a/components/esm/loadprob.hpp b/components/esm/loadprob.hpp index c737757aa..9daab6b1b 100644 --- a/components/esm/loadprob.hpp +++ b/components/esm/loadprob.hpp @@ -27,6 +27,8 @@ struct Probe Data mData; std::string mId, mName, mModel, mIcon, mScript; + bool mIsDeleted; + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadrepa.cpp b/components/esm/loadrepa.cpp index f90f9e39d..608536f02 100644 --- a/components/esm/loadrepa.cpp +++ b/components/esm/loadrepa.cpp @@ -3,6 +3,7 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" +#include "util.hpp" namespace ESM { @@ -10,6 +11,12 @@ namespace ESM void Repair::load(ESMReader &esm) { + mId = esm.getHNString("NAME"); + if (mIsDeleted = readDeleSubRecord(esm)) + { + return; + } + bool hasData = true; while (esm.hasMoreSubs()) { @@ -43,6 +50,13 @@ void Repair::load(ESMReader &esm) void Repair::save(ESMWriter &esm) const { + esm.writeHNCString("NAME", mId); + if (mIsDeleted) + { + writeDeleSubRecord(esm); + return; + } + esm.writeHNCString("MODL", mModel); esm.writeHNOCString("FNAM", mName); @@ -61,5 +75,6 @@ void Repair::save(ESMWriter &esm) const mModel.clear(); mIcon.clear(); mScript.clear(); + mIsDeleted = false; } } diff --git a/components/esm/loadrepa.hpp b/components/esm/loadrepa.hpp index e765bc93a..a660574be 100644 --- a/components/esm/loadrepa.hpp +++ b/components/esm/loadrepa.hpp @@ -27,6 +27,8 @@ struct Repair Data mData; std::string mId, mName, mModel, mIcon, mScript; + bool mIsDeleted; + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadsndg.cpp b/components/esm/loadsndg.cpp index 5ee6f5245..f92c4eee8 100644 --- a/components/esm/loadsndg.cpp +++ b/components/esm/loadsndg.cpp @@ -3,6 +3,7 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" +#include "util.hpp" namespace ESM { @@ -10,6 +11,12 @@ namespace ESM void SoundGenerator::load(ESMReader &esm) { + mId = esm.getHNString("NAME"); + if (mIsDeleted = readDeleSubRecord(esm)) + { + return; + } + bool hasData = false; while (esm.hasMoreSubs()) { @@ -36,6 +43,13 @@ namespace ESM } void SoundGenerator::save(ESMWriter &esm) const { + esm.writeHNCString("NAME", mId); + if (mIsDeleted) + { + writeDeleSubRecord(esm); + return; + } + esm.writeHNT("DATA", mType, 4); esm.writeHNOCString("CNAM", mCreature); esm.writeHNOCString("SNAM", mSound); @@ -46,5 +60,6 @@ namespace ESM mType = LeftFoot; mCreature.clear(); mSound.clear(); + mIsDeleted = false; } } diff --git a/components/esm/loadsndg.hpp b/components/esm/loadsndg.hpp index 056958f0a..e486976f5 100644 --- a/components/esm/loadsndg.hpp +++ b/components/esm/loadsndg.hpp @@ -36,6 +36,8 @@ struct SoundGenerator std::string mId, mCreature, mSound; + bool mIsDeleted; + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadsoun.cpp b/components/esm/loadsoun.cpp index 690c1b448..19e8a5d80 100644 --- a/components/esm/loadsoun.cpp +++ b/components/esm/loadsoun.cpp @@ -3,6 +3,7 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" +#include "util.hpp" namespace ESM { @@ -10,6 +11,12 @@ namespace ESM void Sound::load(ESMReader &esm) { + mId = esm.getHNString("NAME"); + if (mIsDeleted = readDeleSubRecord(esm)) + { + return; + } + bool hasData = false; while (esm.hasMoreSubs()) { @@ -34,6 +41,13 @@ namespace ESM void Sound::save(ESMWriter &esm) const { + esm.writeHNCString("NAME", mId); + if (mIsDeleted) + { + writeDeleSubRecord(esm); + return; + } + esm.writeHNOCString("FNAM", mSound); esm.writeHNT("DATA", mData, 3); } @@ -45,5 +59,7 @@ namespace ESM mData.mVolume = 128; mData.mMinRange = 0; mData.mMaxRange = 255; + + mIsDeleted = false; } } diff --git a/components/esm/loadsoun.hpp b/components/esm/loadsoun.hpp index ff2202ca7..95c89b29d 100644 --- a/components/esm/loadsoun.hpp +++ b/components/esm/loadsoun.hpp @@ -23,6 +23,8 @@ struct Sound SOUNstruct mData; std::string mId, mSound; + bool mIsDeleted; + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadspel.cpp b/components/esm/loadspel.cpp index 96c048e0a..cac06b200 100644 --- a/components/esm/loadspel.cpp +++ b/components/esm/loadspel.cpp @@ -3,6 +3,7 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" +#include "util.hpp" namespace ESM { @@ -11,6 +12,13 @@ namespace ESM void Spell::load(ESMReader &esm) { mEffects.mList.clear(); + + mId = esm.getHNString("NAME"); + if (mIsDeleted = readDeleSubRecord(esm)) + { + return; + } + bool hasData = false; while (esm.hasMoreSubs()) { @@ -39,6 +47,13 @@ namespace ESM void Spell::save(ESMWriter &esm) const { + esm.writeHNCString("NAME", mId); + if (mIsDeleted) + { + writeDeleSubRecord(esm); + return; + } + esm.writeHNOCString("FNAM", mName); esm.writeHNT("SPDT", mData, 12); mEffects.save(esm); @@ -53,5 +68,7 @@ namespace ESM mName.clear(); mEffects.mList.clear(); + + mIsDeleted = false; } } diff --git a/components/esm/loadspel.hpp b/components/esm/loadspel.hpp index 491da1d17..2aba131ad 100644 --- a/components/esm/loadspel.hpp +++ b/components/esm/loadspel.hpp @@ -45,6 +45,8 @@ struct Spell std::string mId, mName; EffectList mEffects; + bool mIsDeleted; + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadstat.cpp b/components/esm/loadstat.cpp index b0ab89bed..a49caba89 100644 --- a/components/esm/loadstat.cpp +++ b/components/esm/loadstat.cpp @@ -3,6 +3,7 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" +#include "util.hpp" namespace ESM { @@ -10,15 +11,29 @@ namespace ESM void Static::load(ESMReader &esm) { + mId = esm.getHNString("NAME"); + if (mIsDeleted = readDeleSubRecord(esm)) + { + return; + } + mModel = esm.getHNString("MODL"); } void Static::save(ESMWriter &esm) const { + esm.writeHNCString("NAME", mId); + if (mIsDeleted) + { + writeDeleSubRecord(esm); + return; + } + esm.writeHNCString("MODL", mModel); } void Static::blank() { mModel.clear(); + mIsDeleted = false; } } diff --git a/components/esm/loadstat.hpp b/components/esm/loadstat.hpp index aa4fe67b8..c4306ad8f 100644 --- a/components/esm/loadstat.hpp +++ b/components/esm/loadstat.hpp @@ -28,6 +28,8 @@ struct Static std::string mId, mModel; + bool mIsDeleted; + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadweap.cpp b/components/esm/loadweap.cpp index 981a5815a..66d65d0f5 100644 --- a/components/esm/loadweap.cpp +++ b/components/esm/loadweap.cpp @@ -3,6 +3,7 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" +#include "util.hpp" namespace ESM { @@ -10,6 +11,12 @@ namespace ESM void Weapon::load(ESMReader &esm) { + mId = esm.getHNString("NAME"); + if (mIsDeleted = readDeleSubRecord(esm)) + { + return; + } + bool hasData = false; while (esm.hasMoreSubs()) { @@ -45,6 +52,13 @@ namespace ESM } void Weapon::save(ESMWriter &esm) const { + esm.writeHNCString("NAME", mId); + if (mIsDeleted) + { + writeDeleSubRecord(esm); + return; + } + esm.writeHNCString("MODL", mModel); esm.writeHNOCString("FNAM", mName); esm.writeHNT("WPDT", mData, 32); @@ -72,5 +86,7 @@ namespace ESM mIcon.clear(); mEnchant.clear(); mScript.clear(); + + mIsDeleted = false; } } diff --git a/components/esm/loadweap.hpp b/components/esm/loadweap.hpp index f66e9f3a6..30dfbc92a 100644 --- a/components/esm/loadweap.hpp +++ b/components/esm/loadweap.hpp @@ -69,6 +69,8 @@ struct Weapon std::string mId, mName, mModel, mIcon, mEnchant, mScript; + bool mIsDeleted; + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/util.cpp b/components/esm/util.cpp new file mode 100644 index 000000000..c20bd4d51 --- /dev/null +++ b/components/esm/util.cpp @@ -0,0 +1,20 @@ +#include "util.hpp" + +namespace ESM +{ + bool readDeleSubRecord(ESMReader &esm) + { + if (esm.isNextSub("DELE")) + { + esm.getSubName(); + esm.skipHSub(); + return true; + } + return false; + } + + void writeDeleSubRecord(ESMWriter &esm) + { + esm.writeHNString("DELE", ""); + } +} diff --git a/components/esm/util.hpp b/components/esm/util.hpp index a80df2456..c670fb23a 100644 --- a/components/esm/util.hpp +++ b/components/esm/util.hpp @@ -1,9 +1,15 @@ #ifndef OPENMW_ESM_UTIL_H #define OPENMW_ESM_UTIL_H +#include + #include #include +#include "esmreader.hpp" +#include "esmwriter.hpp" +#include "loadbsgn.hpp" + namespace ESM { @@ -48,6 +54,9 @@ struct Vector3 } }; +bool readDeleSubRecord(ESMReader &esm); +void writeDeleSubRecord(ESMWriter &esm); + } #endif From 9ac20a33552e61182dbb90c5e2f0b34683720583 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Tue, 7 Jul 2015 15:49:55 +0300 Subject: [PATCH 1765/3725] Add NAME and DELE handling to ESM records. Changed records are those where DELE is inserted at the beginning of a record (before NAME). The record has all required sub-records in this case. --- components/esm/loadbsgn.cpp | 11 +++++++++++ components/esm/loadbsgn.hpp | 2 ++ components/esm/loadltex.cpp | 9 +++++++++ components/esm/loadltex.hpp | 2 ++ components/esm/loadregn.cpp | 10 ++++++++++ components/esm/loadregn.hpp | 2 ++ 6 files changed, 36 insertions(+) diff --git a/components/esm/loadbsgn.cpp b/components/esm/loadbsgn.cpp index e0cd83ea0..7892bfc68 100644 --- a/components/esm/loadbsgn.cpp +++ b/components/esm/loadbsgn.cpp @@ -3,6 +3,7 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" +#include "util.hpp" namespace ESM { @@ -11,6 +12,10 @@ namespace ESM void BirthSign::load(ESMReader &esm) { mPowers.mList.clear(); + + mIsDeleted = readDeleSubRecord(esm); + mId = esm.getHNString("NAME"); + while (esm.hasMoreSubs()) { esm.getSubName(); @@ -37,6 +42,11 @@ void BirthSign::load(ESMReader &esm) void BirthSign::save(ESMWriter &esm) const { + if (mIsDeleted) + { + writeDeleSubRecord(esm); + } + esm.writeHNCString("NAME", mId); esm.writeHNOCString("FNAM", mName); esm.writeHNOCString("TNAM", mTexture); esm.writeHNOCString("DESC", mDescription); @@ -50,6 +60,7 @@ void BirthSign::save(ESMWriter &esm) const mDescription.clear(); mTexture.clear(); mPowers.mList.clear(); + mIsDeleted = false; } } diff --git a/components/esm/loadbsgn.hpp b/components/esm/loadbsgn.hpp index f91f91c97..41c70fb24 100644 --- a/components/esm/loadbsgn.hpp +++ b/components/esm/loadbsgn.hpp @@ -22,6 +22,8 @@ struct BirthSign // List of powers and abilities that come with this birth sign. SpellList mPowers; + bool mIsDeleted; + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadltex.cpp b/components/esm/loadltex.cpp index c3e2d50ff..0ee30b11c 100644 --- a/components/esm/loadltex.cpp +++ b/components/esm/loadltex.cpp @@ -3,6 +3,7 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" +#include "util.hpp" namespace ESM { @@ -10,11 +11,18 @@ namespace ESM void LandTexture::load(ESMReader &esm) { + mIsDeleted = readDeleSubRecord(esm); + mId = esm.getHNString("NAME"); esm.getHNT(mIndex, "INTV"); mTexture = esm.getHNString("DATA"); } void LandTexture::save(ESMWriter &esm) const { + if (mIsDeleted) + { + writeDeleSubRecord(esm); + } + esm.writeHNCString("NAME", mId); esm.writeHNT("INTV", mIndex); esm.writeHNCString("DATA", mTexture); } @@ -23,6 +31,7 @@ void LandTexture::blank() { mTexture.clear(); mIndex = -1; + mIsDeleted = false; } } diff --git a/components/esm/loadltex.hpp b/components/esm/loadltex.hpp index 50a788105..e019e269e 100644 --- a/components/esm/loadltex.hpp +++ b/components/esm/loadltex.hpp @@ -34,6 +34,8 @@ struct LandTexture std::string mId, mTexture; int mIndex; + bool mIsDeleted; + void blank(); ///< Set record to default state (does not touch the ID). diff --git a/components/esm/loadregn.cpp b/components/esm/loadregn.cpp index 1b08b7217..b0adc6f58 100644 --- a/components/esm/loadregn.cpp +++ b/components/esm/loadregn.cpp @@ -3,6 +3,7 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" +#include "util.hpp" namespace ESM { @@ -10,6 +11,8 @@ namespace ESM void Region::load(ESMReader &esm) { + mIsDeleted = readDeleSubRecord(esm); + mId = esm.getHNString("NAME"); mName = esm.getHNOString("FNAM"); esm.getSubNameIs("WEAT"); @@ -49,6 +52,11 @@ void Region::load(ESMReader &esm) } void Region::save(ESMWriter &esm) const { + if (mIsDeleted) + { + writeDeleSubRecord(esm); + } + esm.writeHNString("NAME", mId); esm.writeHNOCString("FNAM", mName); if (esm.getVersion() == VER_12) @@ -77,5 +85,7 @@ void Region::save(ESMWriter &esm) const mName.clear(); mSleepList.clear(); mSoundList.clear(); + + mIsDeleted = false; } } diff --git a/components/esm/loadregn.hpp b/components/esm/loadregn.hpp index 1e241fffb..921ab887b 100644 --- a/components/esm/loadregn.hpp +++ b/components/esm/loadregn.hpp @@ -51,6 +51,8 @@ struct Region std::vector mSoundList; + bool mIsDeleted; + void load(ESMReader &esm); void save(ESMWriter &esm) const; From d2c15647a3f1a03ad3c34dd7eaf6fe6cfbcd35ab Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Tue, 7 Jul 2015 17:00:40 +0300 Subject: [PATCH 1766/3725] Add NAME and DELE handling to Script record --- components/esm/loadscpt.cpp | 12 ++++++++++++ components/esm/loadscpt.hpp | 2 ++ 2 files changed, 14 insertions(+) diff --git a/components/esm/loadscpt.cpp b/components/esm/loadscpt.cpp index fd807ddd3..67c1b8f6f 100644 --- a/components/esm/loadscpt.cpp +++ b/components/esm/loadscpt.cpp @@ -3,6 +3,7 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" +#include "util.hpp" #include @@ -65,6 +66,10 @@ namespace ESM mData = data.mData; mId = data.mName.toString(); + // In scripts DELE sub-record appears after a header. + // The script data is following after DELE in this case. + mIsDeleted = readDeleSubRecord(esm); + mVarNames.clear(); while (esm.hasMoreSubs()) @@ -106,6 +111,11 @@ namespace ESM esm.writeHNT("SCHD", data, 52); + if (mIsDeleted) + { + writeDeleSubRecord(esm); + } + if (!mVarNames.empty()) { esm.startSubRecord("SCVR"); @@ -136,6 +146,8 @@ namespace ESM mScriptText = "Begin \"" + mId + "\"\n\nEnd " + mId + "\n"; else mScriptText = "Begin " + mId + "\n\nEnd " + mId + "\n"; + + mIsDeleted = false; } } diff --git a/components/esm/loadscpt.hpp b/components/esm/loadscpt.hpp index 56390f384..401dfe105 100644 --- a/components/esm/loadscpt.hpp +++ b/components/esm/loadscpt.hpp @@ -50,6 +50,8 @@ public: /// Script source code std::string mScriptText; + bool mIsDeleted; + void load(ESMReader &esm); void save(ESMWriter &esm) const; From 19ac4e942a9efb329143415a46aabaaf51cbe8ef Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Tue, 7 Jul 2015 19:18:42 +0300 Subject: [PATCH 1767/3725] Change DELE sub-record value to 0 (4 bytes) --- components/esm/util.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/components/esm/util.cpp b/components/esm/util.cpp index c20bd4d51..892113cda 100644 --- a/components/esm/util.cpp +++ b/components/esm/util.cpp @@ -1,5 +1,7 @@ #include "util.hpp" +#include + namespace ESM { bool readDeleSubRecord(ESMReader &esm) @@ -15,6 +17,6 @@ namespace ESM void writeDeleSubRecord(ESMWriter &esm) { - esm.writeHNString("DELE", ""); + esm.writeHNT("DELE", static_cast(0)); } } From 0b537186e5b513cf7d6045a7c88e8c6b4d4afc7c Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Tue, 7 Jul 2015 19:42:24 +0300 Subject: [PATCH 1768/3725] Add NAME and DELE handling to Dialogue record --- components/esm/loaddial.cpp | 27 +++++++++++++++++---------- components/esm/loaddial.hpp | 5 +++-- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/components/esm/loaddial.cpp b/components/esm/loaddial.cpp index f2da8f377..77a04ca01 100644 --- a/components/esm/loaddial.cpp +++ b/components/esm/loaddial.cpp @@ -2,9 +2,12 @@ #include +#include + #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" +#include "util.hpp" namespace ESM { @@ -12,18 +15,19 @@ namespace ESM void Dialogue::load(ESMReader &esm) { + mIsDeleted = false; + + mId = esm.getHNString("NAME"); esm.getSubNameIs("DATA"); esm.getSubHeader(); int si = esm.getSubSize(); if (si == 1) esm.getT(mType); - else if (si == 4) + else if (si == 4) // The dialogue is deleted { - // These are just markers, their values are not used. - int i; - esm.getT(i); - esm.getHNT(i, "DELE"); - mType = Deleted; + int32_t empty; + esm.getT(empty); // Skip an empty DATA + mIsDeleted = readDeleSubRecord(esm); } else esm.fail("Unknown sub record size"); @@ -31,12 +35,15 @@ void Dialogue::load(ESMReader &esm) void Dialogue::save(ESMWriter &esm) const { - if (mType != Deleted) - esm.writeHNT("DATA", mType); + esm.writeHNCString("NAME", mId); + if (mIsDeleted) + { + esm.writeHNT("DATA", static_cast(0)); + writeDeleSubRecord(esm); + } else { - esm.writeHNT("DATA", (int)1); - esm.writeHNT("DELE", (int)1); + esm.writeHNT("DATA", mType); } } diff --git a/components/esm/loaddial.hpp b/components/esm/loaddial.hpp index 58598d353..ab8cf4bff 100644 --- a/components/esm/loaddial.hpp +++ b/components/esm/loaddial.hpp @@ -30,8 +30,7 @@ struct Dialogue Voice = 1, Greeting = 2, Persuasion = 3, - Journal = 4, - Deleted = -1 + Journal = 4 }; std::string mId; @@ -46,6 +45,8 @@ struct Dialogue // This is only used during the loading phase to speed up DialInfo merging. LookupMap mLookup; + bool mIsDeleted; + void load(ESMReader &esm); void save(ESMWriter &esm) const; From 847614c26f372d5483bb96a3b30e90dd9358b28f Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Tue, 7 Jul 2015 19:57:08 +0300 Subject: [PATCH 1769/3725] Add DELE handling to Info record --- components/esm/loadinfo.cpp | 21 ++++++++++++++++++--- components/esm/loadinfo.hpp | 2 ++ 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/components/esm/loadinfo.cpp b/components/esm/loadinfo.cpp index a2bade1c5..3394ddbad 100644 --- a/components/esm/loadinfo.cpp +++ b/components/esm/loadinfo.cpp @@ -3,6 +3,7 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" +#include "util.hpp" namespace ESM { @@ -19,11 +20,18 @@ void DialInfo::load(ESMReader &esm) // Since there's no way to mark selects as "deleted", we have to clear the SelectStructs from all previous loadings mSelects.clear(); - // Not present if deleted - if (esm.isNextSub("DATA")) { - esm.getHT(mData, 12); + // If the info is deleted, NAME and DELE sub-records are followed after NNAM + if (esm.isNextSub("NAME")) + { + esm.getSubName(); + mResponse = esm.getHString(); + mIsDeleted = readDeleSubRecord(esm); + return; } + esm.getSubNameIs("DATA"); + esm.getHT(mData, 12); + if (!esm.hasMoreSubs()) return; @@ -131,6 +139,13 @@ void DialInfo::save(ESMWriter &esm) const { esm.writeHNCString("PNAM", mPrev); esm.writeHNCString("NNAM", mNext); + if (mIsDeleted) + { + esm.writeHNCString("NAME", mResponse); + writeDeleSubRecord(esm); + return; + } + esm.writeHNT("DATA", mData, 12); esm.writeHNOCString("ONAM", mActor); esm.writeHNOCString("RNAM", mRace); diff --git a/components/esm/loadinfo.hpp b/components/esm/loadinfo.hpp index 54003b0d9..8b4fae761 100644 --- a/components/esm/loadinfo.hpp +++ b/components/esm/loadinfo.hpp @@ -106,6 +106,8 @@ struct DialInfo REC_DELE = 0x454c4544 }; + bool mIsDeleted; + void load(ESMReader &esm); void save(ESMWriter &esm) const; From b667338a8fe5ffb78bc28151948f31e03dc99407 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Tue, 7 Jul 2015 20:41:39 +0300 Subject: [PATCH 1770/3725] Add NAME and DELE handling to Cell record --- components/esm/loadcell.cpp | 23 +++++++++++++++-------- components/esm/loadcell.hpp | 3 +++ 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index 94f4b0b6e..86b4e4edb 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -12,6 +12,7 @@ #include "esmwriter.hpp" #include "defs.hpp" #include "cellid.hpp" +#include "util.hpp" namespace { @@ -54,10 +55,17 @@ namespace ESM void Cell::load(ESMReader &esm, bool saveContext) { + loadName(esm); loadData(esm); loadCell(esm, saveContext); } +void Cell::loadName(ESMReader &esm) +{ + mName = esm.getHNString("NAME"); + mIsDeleted = readDeleSubRecord(esm); +} + void Cell::loadCell(ESMReader &esm, bool saveContext) { mRefNumCounter = 0; @@ -105,13 +113,6 @@ void Cell::loadCell(ESMReader &esm, bool saveContext) void Cell::loadData(ESMReader &esm) { - // Ignore this for now, it might mean we should delete the entire - // cell? - // TODO: treat the special case "another plugin moved this ref, but we want to delete it"! - if (esm.isNextSub("DELE")) { - esm.skipHSub(); - } - esm.getHNT(mData, "DATA", 12); } @@ -124,6 +125,12 @@ void Cell::postLoad(ESMReader &esm) void Cell::save(ESMWriter &esm) const { + esm.writeHNCString("NAME", mName); + if (mIsDeleted) + { + writeDeleSubRecord(esm); + } + esm.writeHNT("DATA", mData, 12); if (mData.mFlags & Interior) { @@ -147,7 +154,7 @@ void Cell::save(ESMWriter &esm) const esm.writeHNT("NAM5", mMapColor); } - if (mRefNumCounter != 0) + if (mRefNumCounter != 0 && !mIsDeleted) esm.writeHNT("NAM0", mRefNumCounter); } diff --git a/components/esm/loadcell.hpp b/components/esm/loadcell.hpp index 12fb8c068..b313435d6 100644 --- a/components/esm/loadcell.hpp +++ b/components/esm/loadcell.hpp @@ -112,11 +112,14 @@ struct Cell CellRefTracker mLeasedRefs; MovedCellRefTracker mMovedRefs; + bool mIsDeleted; + void postLoad(ESMReader &esm); // This method is left in for compatibility with esmtool. Parsing moved references currently requires // passing ESMStore, bit it does not know about this parameter, so we do it this way. void load(ESMReader &esm, bool saveContext = true); // Load everything (except references) + void loadName(ESMReader &esm); // Load NAME and checks for DELE void loadData(ESMReader &esm); // Load DATAstruct only void loadCell(ESMReader &esm, bool saveContext = true); // Load everything, except DATAstruct and references From 8c3654af11e21ec8ca068c1581e69de707000f67 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Tue, 7 Jul 2015 20:56:26 +0300 Subject: [PATCH 1771/3725] Add NAME handling to Race record --- components/esm/loadrace.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/components/esm/loadrace.cpp b/components/esm/loadrace.cpp index e88454d4c..3feb06c92 100644 --- a/components/esm/loadrace.cpp +++ b/components/esm/loadrace.cpp @@ -22,6 +22,8 @@ void Race::load(ESMReader &esm) { mPowers.mList.clear(); + mId = esm.getHNString("NAME"); + bool hasData = false; while (esm.hasMoreSubs()) { @@ -51,6 +53,7 @@ void Race::load(ESMReader &esm) } void Race::save(ESMWriter &esm) const { + esm.writeHNCString("NAME", mId); esm.writeHNOCString("FNAM", mName); esm.writeHNT("RADT", mData, 140); mPowers.save(esm); From 30b42bf4c0a3c953703987ec333bd89ecd667f7e Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Tue, 7 Jul 2015 21:24:35 +0300 Subject: [PATCH 1772/3725] Remove redundant code --- components/esm/loadinfo.cpp | 1 - components/esm/util.cpp | 1 - 2 files changed, 2 deletions(-) diff --git a/components/esm/loadinfo.cpp b/components/esm/loadinfo.cpp index 3394ddbad..3b5e0ea3a 100644 --- a/components/esm/loadinfo.cpp +++ b/components/esm/loadinfo.cpp @@ -23,7 +23,6 @@ void DialInfo::load(ESMReader &esm) // If the info is deleted, NAME and DELE sub-records are followed after NNAM if (esm.isNextSub("NAME")) { - esm.getSubName(); mResponse = esm.getHString(); mIsDeleted = readDeleSubRecord(esm); return; diff --git a/components/esm/util.cpp b/components/esm/util.cpp index 892113cda..ff2436544 100644 --- a/components/esm/util.cpp +++ b/components/esm/util.cpp @@ -8,7 +8,6 @@ namespace ESM { if (esm.isNextSub("DELE")) { - esm.getSubName(); esm.skipHSub(); return true; } From 09a33580170076f14b2d46d72ad93d60fe52fc07 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Wed, 8 Jul 2015 00:04:14 +0300 Subject: [PATCH 1773/3725] Add NAME and DELE handling to Global record --- components/esm/loadglob.cpp | 16 ++++++++++++++++ components/esm/loadglob.hpp | 2 ++ 2 files changed, 18 insertions(+) diff --git a/components/esm/loadglob.cpp b/components/esm/loadglob.cpp index a78ed1a1b..6cc37d675 100644 --- a/components/esm/loadglob.cpp +++ b/components/esm/loadglob.cpp @@ -1,6 +1,9 @@ #include "loadglob.hpp" +#include "esmreader.hpp" +#include "esmwriter.hpp" #include "defs.hpp" +#include "util.hpp" namespace ESM { @@ -8,11 +11,24 @@ namespace ESM void Global::load (ESMReader &esm) { + mId = esm.getHNString("NAME"); + if (mIsDeleted = readDeleSubRecord(esm)) + { + return; + } + mValue.read (esm, ESM::Variant::Format_Global); } void Global::save (ESMWriter &esm) const { + esm.writeHNCString("NAME", mId); + if (mIsDeleted) + { + writeDeleSubRecord(esm); + return; + } + mValue.write (esm, ESM::Variant::Format_Global); } diff --git a/components/esm/loadglob.hpp b/components/esm/loadglob.hpp index cc5dbbdcf..45b47a3bc 100644 --- a/components/esm/loadglob.hpp +++ b/components/esm/loadglob.hpp @@ -24,6 +24,8 @@ struct Global std::string mId; Variant mValue; + bool mIsDeleted; + void load(ESMReader &esm); void save(ESMWriter &esm) const; From b2f3ccb080b459f212280cc2565110a0343645ec Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Wed, 8 Jul 2015 21:17:59 +0300 Subject: [PATCH 1774/3725] Add NAME handling to GameSetting record --- components/esm/loadgmst.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/components/esm/loadgmst.cpp b/components/esm/loadgmst.cpp index 21d66339a..9e2a80270 100644 --- a/components/esm/loadgmst.cpp +++ b/components/esm/loadgmst.cpp @@ -1,5 +1,7 @@ #include "loadgmst.hpp" +#include "esmreader.hpp" +#include "esmwriter.hpp" #include "defs.hpp" namespace ESM @@ -8,11 +10,13 @@ namespace ESM void GameSetting::load (ESMReader &esm) { + mId = esm.getHNString("NAME"); mValue.read (esm, ESM::Variant::Format_Gmst); } void GameSetting::save (ESMWriter &esm) const { + esm.writeHNCString("NAME", mId); mValue.write (esm, ESM::Variant::Format_Gmst); } From 89e44c8f1fcb02a0ea78b468402a2c8e96d5465c Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Wed, 8 Jul 2015 21:24:05 +0300 Subject: [PATCH 1775/3725] Remove explicit record ID in load/read methods of MWWorld::Store --- apps/openmw/mwworld/store.cpp | 10 ++-- apps/openmw/mwworld/store.hpp | 110 +++++++++++++++++++++++----------- components/esm/util.cpp | 18 ++++++ components/esm/util.hpp | 27 ++++++++- 4 files changed, 123 insertions(+), 42 deletions(-) diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index cdcc00b4d..767a33b13 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -35,7 +35,7 @@ void Store::handleMovedCellRefs(ESM::ESMReader& esm, ESM::Cell* cell) } } -void Store::load(ESM::ESMReader &esm, const std::string &id) +void Store::load(ESM::ESMReader &esm) { // Don't automatically assume that a new cell must be spawned. Multiple plugins write to the same cell, // and we merge all this data into one Cell object. However, we can't simply search for the cell id, @@ -43,9 +43,9 @@ void Store::load(ESM::ESMReader &esm, const std::string &id) // are not available until both cells have been loaded at least partially! // All cells have a name record, even nameless exterior cells. - std::string idLower = Misc::StringUtils::lowerCase(id); ESM::Cell cell; - cell.mName = id; + cell.loadName(esm); + std::string idLower = Misc::StringUtils::lowerCase(cell.mName); // Load the (x,y) coordinates of the cell, if it is an exterior cell, // so we can find the cell we need to merge with @@ -119,9 +119,9 @@ void Store::load(ESM::ESMReader &esm, const std::string &id) } } -void Store::load(ESM::ESMReader &esm, const std::string &id) +void Store::load(ESM::ESMReader &esm) { - load(esm, id, esm.getIndex()); + load(esm, esm.getIndex()); } } diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index 2d73d5312..a61cbd2ac 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -10,6 +10,7 @@ #include #include +#include #include @@ -26,15 +27,19 @@ namespace MWWorld virtual size_t getSize() const = 0; virtual int getDynamicSize() const { return 0; } - virtual void load(ESM::ESMReader &esm, const std::string &id) = 0; + virtual void load(ESM::ESMReader &esm) = 0; virtual bool eraseStatic(const std::string &id) {return false;} virtual void clearDynamic() {} virtual void write (ESM::ESMWriter& writer, Loading::Listener& progress) const {} - virtual void read (ESM::ESMReader& reader, const std::string& id) {} + virtual void read (ESM::ESMReader& reader) {} ///< Read into dynamic storage + + virtual std::string getLastAddedRecordId() const { return ""; } + ///< Returns the last loaded/read ID or empty string if a loaded record has no ID + virtual bool isLastAddedRecordDeleted() const { return false; } }; template @@ -126,6 +131,7 @@ namespace MWWorld } }; + T mLastAddedRecord; friend class ESMStore; @@ -208,15 +214,16 @@ namespace MWWorld return ptr; } - void load(ESM::ESMReader &esm, const std::string &id) { - std::string idLower = Misc::StringUtils::lowerCase(id); + void load(ESM::ESMReader &esm) { + T record; + record.load(esm); - std::pair inserted = mStatic.insert(std::make_pair(idLower, T())); + std::string idLower = Misc::StringUtils::lowerCase(record.mId); + std::pair inserted = mStatic.insert(std::make_pair(idLower, record)); if (inserted.second) mShared.push_back(&inserted.first->second); - inserted.first->second.mId = idLower; - inserted.first->second.load(esm); + mLastAddedRecord = record; } void setUp() { @@ -325,58 +332,79 @@ namespace MWWorld ++iter) { writer.startRecord (T::sRecordId); - writer.writeHNString ("NAME", iter->second.mId); iter->second.save (writer); writer.endRecord (T::sRecordId); } } - void read (ESM::ESMReader& reader, const std::string& id) + void read (ESM::ESMReader& reader) { T record; - record.mId = id; record.load (reader); insert (record); + + mLastAddedRecord = record; + } + + std::string getLastAddedRecordId() const + { + return ESM::getRecordId(mLastAddedRecord); + } + + bool isLastAddedRecordDeleted() const + { + return ESM::isRecordDeleted(mLastAddedRecord); } }; template <> - inline void Store::load(ESM::ESMReader &esm, const std::string &id) { - std::string idLower = Misc::StringUtils::lowerCase(id); + inline void Store::load(ESM::ESMReader &esm) { + ESM::Dialogue dialogue; + dialogue.load(esm); - std::map::iterator it = mStatic.find(idLower); - if (it == mStatic.end()) { - it = mStatic.insert( std::make_pair( idLower, ESM::Dialogue() ) ).first; - it->second.mId = id; // don't smash case here, as this line is printed + std::string idLower = Misc::StringUtils::lowerCase(dialogue.mId); + std::map::iterator found = mStatic.find(idLower); + if (found == mStatic.end()) + { + mStatic.insert(std::make_pair(idLower, dialogue)); } - - it->second.load(esm); + else + { + found->second = dialogue; + } + + mLastAddedRecord = dialogue; } template <> - inline void Store::load(ESM::ESMReader &esm, const std::string &id) { - ESM::Script scpt; - scpt.load(esm); - Misc::StringUtils::toLower(scpt.mId); + inline void Store::load(ESM::ESMReader &esm) { + ESM::Script script; + script.load(esm); - std::pair inserted = mStatic.insert(std::make_pair(scpt.mId, scpt)); + std::string idLower = Misc::StringUtils::toLower(script.mId); + std::pair inserted = mStatic.insert(std::make_pair(idLower, script)); if (inserted.second) mShared.push_back(&inserted.first->second); else - inserted.first->second = scpt; + inserted.first->second = script; + + mLastAddedRecord = script; } template <> - inline void Store::load(ESM::ESMReader &esm, const std::string &id) + inline void Store::load(ESM::ESMReader &esm) { - ESM::StartScript s; - s.load(esm); - s.mId = Misc::StringUtils::toLower(s.mId); - std::pair inserted = mStatic.insert(std::make_pair(s.mId, s)); + ESM::StartScript script; + script.load(esm); + + std::string idLower = Misc::StringUtils::toLower(script.mId); + std::pair inserted = mStatic.insert(std::make_pair(idLower, script)); if (inserted.second) mShared.push_back(&inserted.first->second); else - inserted.first->second = s; + inserted.first->second = script; + + mLastAddedRecord = script; } template <> @@ -385,6 +413,7 @@ namespace MWWorld // For multiple ESM/ESP files we need one list per file. typedef std::vector LandTextureList; std::vector mStatic; + ESM::LandTexture mLastLoadedTexture; public: Store() { @@ -426,10 +455,9 @@ namespace MWWorld return mStatic[plugin].size(); } - void load(ESM::ESMReader &esm, const std::string &id, size_t plugin) { + void load(ESM::ESMReader &esm, size_t plugin) { ESM::LandTexture lt; lt.load(esm); - lt.mId = id; // Make sure we have room for the structure if (plugin >= mStatic.size()) { @@ -443,7 +471,7 @@ namespace MWWorld ltexl[lt.mIndex] = lt; } - void load(ESM::ESMReader &esm, const std::string &id); + void load(ESM::ESMReader &esm); iterator begin(size_t plugin) const { assert(plugin < mStatic.size()); @@ -454,6 +482,16 @@ namespace MWWorld assert(plugin < mStatic.size()); return mStatic[plugin].end(); } + + std::string getLastAddedRecordId() const + { + return ESM::getRecordId(mLastLoadedTexture); + } + + bool isLastAddedRecordDeleted() const + { + return ESM::isRecordDeleted(mLastLoadedTexture); + } }; template <> @@ -521,7 +559,7 @@ namespace MWWorld return ptr; } - void load(ESM::ESMReader &esm, const std::string &id) { + void load(ESM::ESMReader &esm) { ESM::Land *ptr = new ESM::Land(); ptr->load(esm); @@ -688,7 +726,7 @@ namespace MWWorld // errors related to the compare operator used in std::find for ESM::MovedCellRefTracker::find. // There some nasty three-way cyclic header dependency involved, which I could only fix by moving // this method. - void load(ESM::ESMReader &esm, const std::string &id); + void load(ESM::ESMReader &esm); iterator intBegin() const { return iterator(mSharedInt.begin()); @@ -857,7 +895,7 @@ namespace MWWorld mCells = &cells; } - void load(ESM::ESMReader &esm, const std::string &id) { + void load(ESM::ESMReader &esm) { ESM::Pathgrid pathgrid; pathgrid.load(esm); diff --git a/components/esm/util.cpp b/components/esm/util.cpp index ff2436544..4cfe644e8 100644 --- a/components/esm/util.cpp +++ b/components/esm/util.cpp @@ -18,4 +18,22 @@ namespace ESM { esm.writeHNT("DELE", static_cast(0)); } + + template <> + bool isRecordDeleted(const StartScript &script) + { + return false; + } + + template <> + bool isRecordDeleted(const Race &race) + { + return false; + } + + template <> + bool isRecordDeleted(const GameSetting &gmst) + { + return false; + } } diff --git a/components/esm/util.hpp b/components/esm/util.hpp index c670fb23a..94a7956ef 100644 --- a/components/esm/util.hpp +++ b/components/esm/util.hpp @@ -8,7 +8,10 @@ #include "esmreader.hpp" #include "esmwriter.hpp" -#include "loadbsgn.hpp" +#include "loadsscr.hpp" +#include "loadglob.hpp" +#include "loadrace.hpp" +#include "loadgmst.hpp" namespace ESM { @@ -57,6 +60,28 @@ struct Vector3 bool readDeleSubRecord(ESMReader &esm); void writeDeleSubRecord(ESMWriter &esm); +template +std::string getRecordId(const RecordT &record) +{ + return record.mId; +} + +template +bool isRecordDeleted(const RecordT &record) +{ + return record.mIsDeleted; +} + +// The following records can't be deleted (for now) +template <> +bool isRecordDeleted(const StartScript &script); + +template <> +bool isRecordDeleted(const Race &race); + +template <> +bool isRecordDeleted(const GameSetting &gmst); + } #endif From 9301bc148e9fa10e58519debdc7103a9babae07b Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Wed, 8 Jul 2015 21:26:20 +0300 Subject: [PATCH 1776/3725] Remove NAME handling from MWWorld::ESMStore --- apps/openmw/mwworld/esmstore.cpp | 29 +++++++++-------------------- 1 file changed, 9 insertions(+), 20 deletions(-) diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index 5d9beecb6..50a7e3376 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -95,23 +95,12 @@ void ESMStore::load(ESM::ESMReader &esm, Loading::Listener* listener) throw std::runtime_error(error.str()); } } else { - // Load it - std::string id = esm.getHNOString("NAME"); - // ... unless it got deleted! This means that the following record - // has been deleted, and trying to load it using standard assumptions - // on the structure will (probably) fail. - if (esm.isNextSub("DELE")) { - esm.skipRecord(); - it->second->eraseStatic(id); - continue; - } - it->second->load(esm, id); - - // DELE can also occur after the usual subrecords - if (esm.isNextSub("DELE")) { - esm.skipRecord(); - it->second->eraseStatic(id); - continue; + it->second->load(esm); + std::string id = it->second->getLastAddedRecordId(); + if (it->second->isLastAddedRecordDeleted()) + { + it->second->eraseStatic(id); + continue; } if (n.val==ESM::REC_DIAL) { @@ -194,13 +183,13 @@ void ESMStore::setUp() case ESM::REC_LEVC: { - std::string id = reader.getHNString ("NAME"); - mStores[type]->read (reader, id); + StoreBase *store = mStores[type]; + store->read (reader); // FIXME: there might be stale dynamic IDs in mIds from an earlier savegame // that really should be cleared instead of just overwritten - mIds[id] = type; + mIds[store->getLastAddedRecordId()] = type; } if (type==ESM::REC_NPC_) From 897a52cdda1cec48833af47c2798b6836c9f4d36 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Wed, 8 Jul 2015 21:40:01 +0300 Subject: [PATCH 1777/3725] Remove NAME handling from MWWorld::Globals --- apps/openmw/mwworld/globals.cpp | 26 ++++++++++++-------------- apps/openmw/mwworld/globals.hpp | 4 ++-- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwworld/globals.cpp b/apps/openmw/mwworld/globals.cpp index e7cb04590..671793a17 100644 --- a/apps/openmw/mwworld/globals.cpp +++ b/apps/openmw/mwworld/globals.cpp @@ -14,7 +14,7 @@ namespace MWWorld { Globals::Collection::const_iterator Globals::find (const std::string& name) const { - Collection::const_iterator iter = mVariables.find (name); + Collection::const_iterator iter = mVariables.find (Misc::StringUtils::lowerCase (name)); if (iter==mVariables.end()) throw std::runtime_error ("unknown global variable: " + name); @@ -24,7 +24,7 @@ namespace MWWorld Globals::Collection::iterator Globals::find (const std::string& name) { - Collection::iterator iter = mVariables.find (name); + Collection::iterator iter = mVariables.find (Misc::StringUtils::lowerCase (name)); if (iter==mVariables.end()) throw std::runtime_error ("unknown global variable: " + name); @@ -41,28 +41,28 @@ namespace MWWorld for (MWWorld::Store::iterator iter = globals.begin(); iter!=globals.end(); ++iter) { - mVariables.insert (std::make_pair (iter->mId, iter->mValue)); + mVariables.insert (std::make_pair (Misc::StringUtils::lowerCase (iter->mId), *iter)); } } const ESM::Variant& Globals::operator[] (const std::string& name) const { - return find (name)->second; + return find (Misc::StringUtils::lowerCase (name))->second.mValue; } ESM::Variant& Globals::operator[] (const std::string& name) { - return find (name)->second; + return find (Misc::StringUtils::lowerCase (name))->second.mValue; } char Globals::getType (const std::string& name) const { - Collection::const_iterator iter = mVariables.find (name); + Collection::const_iterator iter = mVariables.find (Misc::StringUtils::lowerCase (name)); if (iter==mVariables.end()) return ' '; - switch (iter->second.getType()) + switch (iter->second.mValue.getType()) { case ESM::VT_Short: return 's'; case ESM::VT_Long: return 'l'; @@ -82,8 +82,7 @@ namespace MWWorld for (Collection::const_iterator iter (mVariables.begin()); iter!=mVariables.end(); ++iter) { writer.startRecord (ESM::REC_GLOB); - writer.writeHNString ("NAME", iter->first); - iter->second.write (writer, ESM::Variant::Format_Global); + iter->second.save (writer); writer.endRecord (ESM::REC_GLOB); } } @@ -92,14 +91,13 @@ namespace MWWorld { if (type==ESM::REC_GLOB) { - std::string id = reader.getHNString ("NAME"); + ESM::Global global; + global.load(reader); - Collection::iterator iter = mVariables.find (Misc::StringUtils::lowerCase (id)); + Collection::iterator iter = mVariables.find (Misc::StringUtils::lowerCase (global.mId)); if (iter!=mVariables.end()) - iter->second.read (reader, ESM::Variant::Format_Global); - else - reader.skipRecord(); + iter->second = global; return true; } diff --git a/apps/openmw/mwworld/globals.hpp b/apps/openmw/mwworld/globals.hpp index bb4ab13d9..3468c2e71 100644 --- a/apps/openmw/mwworld/globals.hpp +++ b/apps/openmw/mwworld/globals.hpp @@ -8,7 +8,7 @@ #include #include -#include +#include namespace ESM { @@ -29,7 +29,7 @@ namespace MWWorld { private: - typedef std::map Collection; + typedef std::map Collection; Collection mVariables; // type, value From 00bf87b5611d7dbc8fc8e7d5add1a4a236071733 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Thu, 9 Jul 2015 15:17:38 +0300 Subject: [PATCH 1778/3725] Convert IDs of loaded records to lower case in MWWorld::Store --- apps/openmw/mwworld/store.hpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index a61cbd2ac..c482486d8 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -217,9 +217,9 @@ namespace MWWorld void load(ESM::ESMReader &esm) { T record; record.load(esm); + Misc::StringUtils::toLower(record.mId); - std::string idLower = Misc::StringUtils::lowerCase(record.mId); - std::pair inserted = mStatic.insert(std::make_pair(idLower, record)); + std::pair inserted = mStatic.insert(std::make_pair(record.mId, record)); if (inserted.second) mShared.push_back(&inserted.first->second); @@ -359,6 +359,7 @@ namespace MWWorld template <> inline void Store::load(ESM::ESMReader &esm) { + // The original letter case of a dialogue ID is saved, because it's printed ESM::Dialogue dialogue; dialogue.load(esm); @@ -380,9 +381,9 @@ namespace MWWorld inline void Store::load(ESM::ESMReader &esm) { ESM::Script script; script.load(esm); + Misc::StringUtils::toLower(script.mId); - std::string idLower = Misc::StringUtils::toLower(script.mId); - std::pair inserted = mStatic.insert(std::make_pair(idLower, script)); + std::pair inserted = mStatic.insert(std::make_pair(script.mId, script)); if (inserted.second) mShared.push_back(&inserted.first->second); else @@ -396,9 +397,9 @@ namespace MWWorld { ESM::StartScript script; script.load(esm); + Misc::StringUtils::toLower(script.mId); - std::string idLower = Misc::StringUtils::toLower(script.mId); - std::pair inserted = mStatic.insert(std::make_pair(idLower, script)); + std::pair inserted = mStatic.insert(std::make_pair(script.mId, script)); if (inserted.second) mShared.push_back(&inserted.first->second); else From 20723581a102f021ba04296096d5cd0c715f0d66 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Thu, 9 Jul 2015 21:10:57 +0300 Subject: [PATCH 1779/3725] Letter case fix for MWWorld::Globals --- apps/openmw/mwworld/globals.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/globals.cpp b/apps/openmw/mwworld/globals.cpp index 671793a17..668a33f09 100644 --- a/apps/openmw/mwworld/globals.cpp +++ b/apps/openmw/mwworld/globals.cpp @@ -93,9 +93,9 @@ namespace MWWorld { ESM::Global global; global.load(reader); + Misc::StringUtils::toLower(global.mId); - Collection::iterator iter = mVariables.find (Misc::StringUtils::lowerCase (global.mId)); - + Collection::iterator iter = mVariables.find (global.mId); if (iter!=mVariables.end()) iter->second = global; From 7ecb54a776a298bee470397c40ce64945a2b0174 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Thu, 9 Jul 2015 21:45:24 +0300 Subject: [PATCH 1780/3725] Set Deleted flag to false when initializing ESM records --- components/esm/loadacti.cpp | 4 + components/esm/loadacti.hpp | 2 + components/esm/loadalch.cpp | 4 + components/esm/loadalch.hpp | 2 + components/esm/loadappa.cpp | 96 ++++++----- components/esm/loadappa.hpp | 2 + components/esm/loadarmo.cpp | 4 + components/esm/loadarmo.hpp | 2 + components/esm/loadbody.cpp | 80 ++++----- components/esm/loadbody.hpp | 2 + components/esm/loadbook.cpp | 4 + components/esm/loadbook.hpp | 2 + components/esm/loadbsgn.cpp | 76 +++++---- components/esm/loadbsgn.hpp | 2 + components/esm/loadcell.hpp | 3 +- components/esm/loadclas.cpp | 3 + components/esm/loadclas.hpp | 2 + components/esm/loadclot.cpp | 4 + components/esm/loadclot.hpp | 2 + components/esm/loadcont.cpp | 4 + components/esm/loadcont.hpp | 2 + components/esm/loadcrea.cpp | 4 + components/esm/loadcrea.hpp | 2 + components/esm/loaddial.cpp | 207 +++++++++++----------- components/esm/loaddial.hpp | 2 + components/esm/loaddoor.cpp | 4 + components/esm/loaddoor.hpp | 2 + components/esm/loadench.cpp | 76 +++++---- components/esm/loadench.hpp | 2 + components/esm/loadfact.cpp | 129 +++++++------- components/esm/loadfact.hpp | 2 + components/esm/loadglob.cpp | 4 + components/esm/loadglob.hpp | 2 + components/esm/loadinfo.cpp | 302 +++++++++++++++++---------------- components/esm/loadinfo.hpp | 2 + components/esm/loadingr.cpp | 4 + components/esm/loadingr.hpp | 2 + components/esm/loadlevlist.cpp | 3 + components/esm/loadlevlist.hpp | 2 + components/esm/loadligh.cpp | 4 + components/esm/loadligh.hpp | 2 + components/esm/loadlock.cpp | 4 + components/esm/loadlock.hpp | 2 + components/esm/loadltex.cpp | 47 ++--- components/esm/loadltex.hpp | 6 +- components/esm/loadmisc.cpp | 4 + components/esm/loadmisc.hpp | 2 + components/esm/loadnpc.cpp | 4 + components/esm/loadnpc.hpp | 2 + components/esm/loadprob.cpp | 4 + components/esm/loadprob.hpp | 2 + components/esm/loadregn.cpp | 101 +++++------ components/esm/loadregn.hpp | 2 + components/esm/loadrepa.cpp | 96 ++++++----- components/esm/loadrepa.hpp | 2 + components/esm/loadscpt.cpp | 5 +- components/esm/loadscpt.hpp | 2 + components/esm/loadsndg.cpp | 4 + components/esm/loadsndg.hpp | 2 + components/esm/loadsoun.cpp | 4 + components/esm/loadsoun.hpp | 2 + components/esm/loadspel.cpp | 4 + components/esm/loadspel.hpp | 2 + components/esm/loadstat.cpp | 4 + components/esm/loadstat.hpp | 2 + components/esm/loadweap.cpp | 4 + components/esm/loadweap.hpp | 2 + 67 files changed, 785 insertions(+), 589 deletions(-) diff --git a/components/esm/loadacti.cpp b/components/esm/loadacti.cpp index 295d35f7e..14a3abe54 100644 --- a/components/esm/loadacti.cpp +++ b/components/esm/loadacti.cpp @@ -9,6 +9,10 @@ namespace ESM { unsigned int Activator::sRecordId = REC_ACTI; + Activator::Activator() + : mIsDeleted(false) + {} + void Activator::load(ESMReader &esm) { mId = esm.getHNString("NAME"); diff --git a/components/esm/loadacti.hpp b/components/esm/loadacti.hpp index 406512a22..93de07b25 100644 --- a/components/esm/loadacti.hpp +++ b/components/esm/loadacti.hpp @@ -19,6 +19,8 @@ struct Activator bool mIsDeleted; + Activator(); + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadalch.cpp b/components/esm/loadalch.cpp index 12078a5f7..5faeb99e1 100644 --- a/components/esm/loadalch.cpp +++ b/components/esm/loadalch.cpp @@ -9,6 +9,10 @@ namespace ESM { unsigned int Potion::sRecordId = REC_ALCH; + Potion::Potion() + : mIsDeleted(false) + {} + void Potion::load(ESMReader &esm) { mEffects.mList.clear(); diff --git a/components/esm/loadalch.hpp b/components/esm/loadalch.hpp index 3d1e6dee7..921585a9d 100644 --- a/components/esm/loadalch.hpp +++ b/components/esm/loadalch.hpp @@ -35,6 +35,8 @@ struct Potion bool mIsDeleted; + Potion(); + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadappa.cpp b/components/esm/loadappa.cpp index 9107e5a8e..ea375aa7f 100644 --- a/components/esm/loadappa.cpp +++ b/components/esm/loadappa.cpp @@ -9,60 +9,64 @@ namespace ESM { unsigned int Apparatus::sRecordId = REC_APPA; -void Apparatus::load(ESMReader &esm) -{ - mId = esm.getHNString("NAME"); - if (mIsDeleted = readDeleSubRecord(esm)) - { - return; - } + Apparatus::Apparatus() + : mIsDeleted(false) + {} - bool hasData = false; - while (esm.hasMoreSubs()) + void Apparatus::load(ESMReader &esm) { - esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + mId = esm.getHNString("NAME"); + if (mIsDeleted = readDeleSubRecord(esm)) { - case ESM::FourCC<'M','O','D','L'>::value: - mModel = esm.getHString(); - break; - case ESM::FourCC<'F','N','A','M'>::value: - mName = esm.getHString(); - break; - case ESM::FourCC<'A','A','D','T'>::value: - esm.getHT(mData); - hasData = true; - break; - case ESM::FourCC<'S','C','R','I'>::value: - mScript = esm.getHString(); - break; - case ESM::FourCC<'I','T','E','X'>::value: - mIcon = esm.getHString(); - break; - default: - esm.fail("Unknown subrecord"); + return; } + + bool hasData = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'A','A','D','T'>::value: + esm.getHT(mData); + hasData = true; + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + case ESM::FourCC<'I','T','E','X'>::value: + mIcon = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasData) + esm.fail("Missing AADT"); } - if (!hasData) - esm.fail("Missing AADT"); -} -void Apparatus::save(ESMWriter &esm) const -{ - esm.writeHNCString("NAME", mId); - if (mIsDeleted) + void Apparatus::save(ESMWriter &esm) const { - writeDeleSubRecord(esm); - return; - } + esm.writeHNCString("NAME", mId); + if (mIsDeleted) + { + writeDeleSubRecord(esm); + return; + } - esm.writeHNCString("MODL", mModel); - esm.writeHNCString("FNAM", mName); - esm.writeHNT("AADT", mData, 16); - esm.writeHNOCString("SCRI", mScript); - esm.writeHNCString("ITEX", mIcon); -} + esm.writeHNCString("MODL", mModel); + esm.writeHNCString("FNAM", mName); + esm.writeHNT("AADT", mData, 16); + esm.writeHNOCString("SCRI", mScript); + esm.writeHNCString("ITEX", mIcon); + } void Apparatus::blank() { diff --git a/components/esm/loadappa.hpp b/components/esm/loadappa.hpp index 62d8561a1..2dac37995 100644 --- a/components/esm/loadappa.hpp +++ b/components/esm/loadappa.hpp @@ -40,6 +40,8 @@ struct Apparatus bool mIsDeleted; + Apparatus(); + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadarmo.cpp b/components/esm/loadarmo.cpp index 626893d00..d23a71cac 100644 --- a/components/esm/loadarmo.cpp +++ b/components/esm/loadarmo.cpp @@ -39,6 +39,10 @@ namespace ESM unsigned int Armor::sRecordId = REC_ARMO; + Armor::Armor() + : mIsDeleted(false) + {} + void Armor::load(ESMReader &esm) { mParts.mParts.clear(); diff --git a/components/esm/loadarmo.hpp b/components/esm/loadarmo.hpp index eb911254f..4ebe181a7 100644 --- a/components/esm/loadarmo.hpp +++ b/components/esm/loadarmo.hpp @@ -98,6 +98,8 @@ struct Armor bool mIsDeleted; + Armor(); + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadbody.cpp b/components/esm/loadbody.cpp index 644eb3b50..e0ebfd539 100644 --- a/components/esm/loadbody.cpp +++ b/components/esm/loadbody.cpp @@ -9,53 +9,57 @@ namespace ESM { unsigned int BodyPart::sRecordId = REC_BODY; + BodyPart::BodyPart() + : mIsDeleted(false) + {} -void BodyPart::load(ESMReader &esm) -{ - mId = esm.getHNString("NAME"); - if (mIsDeleted = readDeleSubRecord(esm)) + void BodyPart::load(ESMReader &esm) { - return; - } + mId = esm.getHNString("NAME"); + if (mIsDeleted = readDeleSubRecord(esm)) + { + return; + } - bool hasData = false; - while (esm.hasMoreSubs()) - { - esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + bool hasData = false; + while (esm.hasMoreSubs()) { - case ESM::FourCC<'M','O','D','L'>::value: - mModel = esm.getHString(); - break; - case ESM::FourCC<'F','N','A','M'>::value: - mRace = esm.getHString(); - break; - case ESM::FourCC<'B','Y','D','T'>::value: - esm.getHT(mData, 4); - hasData = true; - break; - default: - esm.fail("Unknown subrecord"); + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mRace = esm.getHString(); + break; + case ESM::FourCC<'B','Y','D','T'>::value: + esm.getHT(mData, 4); + hasData = true; + break; + default: + esm.fail("Unknown subrecord"); + } } + + if (!hasData) + esm.fail("Missing BYDT subrecord"); } - if (!hasData) - esm.fail("Missing BYDT subrecord"); -} -void BodyPart::save(ESMWriter &esm) const -{ - esm.writeHNCString("NAME", mId); - if (mIsDeleted) + void BodyPart::save(ESMWriter &esm) const { - writeDeleSubRecord(esm); - return; - } + esm.writeHNCString("NAME", mId); + if (mIsDeleted) + { + writeDeleSubRecord(esm); + return; + } - esm.writeHNCString("MODL", mModel); - esm.writeHNOCString("FNAM", mRace); - esm.writeHNT("BYDT", mData, 4); -} + esm.writeHNCString("MODL", mModel); + esm.writeHNOCString("FNAM", mRace); + esm.writeHNT("BYDT", mData, 4); + } void BodyPart::blank() { diff --git a/components/esm/loadbody.hpp b/components/esm/loadbody.hpp index 8e1e81f82..f32d2fb58 100644 --- a/components/esm/loadbody.hpp +++ b/components/esm/loadbody.hpp @@ -62,6 +62,8 @@ struct BodyPart bool mIsDeleted; + BodyPart(); + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadbook.cpp b/components/esm/loadbook.cpp index aec361873..2824b6200 100644 --- a/components/esm/loadbook.cpp +++ b/components/esm/loadbook.cpp @@ -9,6 +9,10 @@ namespace ESM { unsigned int Book::sRecordId = REC_BOOK; + Book::Book() + : mIsDeleted(false) + {} + void Book::load(ESMReader &esm) { mId = esm.getHNString("NAME"); diff --git a/components/esm/loadbook.hpp b/components/esm/loadbook.hpp index 2f374c4b2..931f813c0 100644 --- a/components/esm/loadbook.hpp +++ b/components/esm/loadbook.hpp @@ -30,6 +30,8 @@ struct Book bool mIsDeleted; + Book(); + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadbsgn.cpp b/components/esm/loadbsgn.cpp index 7892bfc68..8cdeed3f6 100644 --- a/components/esm/loadbsgn.cpp +++ b/components/esm/loadbsgn.cpp @@ -9,50 +9,54 @@ namespace ESM { unsigned int BirthSign::sRecordId = REC_BSGN; -void BirthSign::load(ESMReader &esm) -{ - mPowers.mList.clear(); - - mIsDeleted = readDeleSubRecord(esm); - mId = esm.getHNString("NAME"); + BirthSign::BirthSign() + : mIsDeleted(false) + {} - while (esm.hasMoreSubs()) + void BirthSign::load(ESMReader &esm) { - esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + mPowers.mList.clear(); + + mIsDeleted = readDeleSubRecord(esm); + mId = esm.getHNString("NAME"); + + while (esm.hasMoreSubs()) { - case ESM::FourCC<'F','N','A','M'>::value: - mName = esm.getHString(); - break; - case ESM::FourCC<'T','N','A','M'>::value: - mTexture = esm.getHString(); - break; - case ESM::FourCC<'D','E','S','C'>::value: - mDescription = esm.getHString(); - break; - case ESM::FourCC<'N','P','C','S'>::value: - mPowers.add(esm); - break; - default: - esm.fail("Unknown subrecord"); + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'T','N','A','M'>::value: + mTexture = esm.getHString(); + break; + case ESM::FourCC<'D','E','S','C'>::value: + mDescription = esm.getHString(); + break; + case ESM::FourCC<'N','P','C','S'>::value: + mPowers.add(esm); + break; + default: + esm.fail("Unknown subrecord"); + } } } -} -void BirthSign::save(ESMWriter &esm) const -{ - if (mIsDeleted) + void BirthSign::save(ESMWriter &esm) const { - writeDeleSubRecord(esm); - } - esm.writeHNCString("NAME", mId); - esm.writeHNOCString("FNAM", mName); - esm.writeHNOCString("TNAM", mTexture); - esm.writeHNOCString("DESC", mDescription); + if (mIsDeleted) + { + writeDeleSubRecord(esm); + } + esm.writeHNCString("NAME", mId); + esm.writeHNOCString("FNAM", mName); + esm.writeHNOCString("TNAM", mTexture); + esm.writeHNOCString("DESC", mDescription); - mPowers.save(esm); -} + mPowers.save(esm); + } void BirthSign::blank() { diff --git a/components/esm/loadbsgn.hpp b/components/esm/loadbsgn.hpp index 41c70fb24..685ade82f 100644 --- a/components/esm/loadbsgn.hpp +++ b/components/esm/loadbsgn.hpp @@ -24,6 +24,8 @@ struct BirthSign bool mIsDeleted; + BirthSign(); + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadcell.hpp b/components/esm/loadcell.hpp index b313435d6..bf65c5fa8 100644 --- a/components/esm/loadcell.hpp +++ b/components/esm/loadcell.hpp @@ -85,7 +85,8 @@ struct Cell mWater(0), mWaterInt(false), mMapColor(0), - mRefNumCounter(0) + mRefNumCounter(0), + mIsDeleted(false) {} // Interior cells are indexed by this (it's the 'id'), for exterior diff --git a/components/esm/loadclas.cpp b/components/esm/loadclas.cpp index df47a1a33..1384a6280 100644 --- a/components/esm/loadclas.cpp +++ b/components/esm/loadclas.cpp @@ -23,6 +23,9 @@ namespace ESM "sSpecializationStealth" }; + Class::Class() + : mIsDeleted(false) + {} int& Class::CLDTstruct::getSkill (int index, bool major) { diff --git a/components/esm/loadclas.hpp b/components/esm/loadclas.hpp index b61913734..399e93c24 100644 --- a/components/esm/loadclas.hpp +++ b/components/esm/loadclas.hpp @@ -75,6 +75,8 @@ struct Class bool mIsDeleted; + Class(); + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadclot.cpp b/components/esm/loadclot.cpp index 1c73c4f21..88f2e5715 100644 --- a/components/esm/loadclot.cpp +++ b/components/esm/loadclot.cpp @@ -9,6 +9,10 @@ namespace ESM { unsigned int Clothing::sRecordId = REC_CLOT; + Clothing::Clothing() + : mIsDeleted(false) + {} + void Clothing::load(ESMReader &esm) { mParts.mParts.clear(); diff --git a/components/esm/loadclot.hpp b/components/esm/loadclot.hpp index 8b4a8b3bb..202c1ec45 100644 --- a/components/esm/loadclot.hpp +++ b/components/esm/loadclot.hpp @@ -50,6 +50,8 @@ struct Clothing bool mIsDeleted; + Clothing(); + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadcont.cpp b/components/esm/loadcont.cpp index f54fe66e2..3d3d7fced 100644 --- a/components/esm/loadcont.cpp +++ b/components/esm/loadcont.cpp @@ -25,6 +25,10 @@ namespace ESM unsigned int Container::sRecordId = REC_CONT; + Container::Container() + : mIsDeleted(false) + {} + void Container::load(ESMReader &esm) { mInventory.mList.clear(); diff --git a/components/esm/loadcont.hpp b/components/esm/loadcont.hpp index 51166b8d4..31c7e1815 100644 --- a/components/esm/loadcont.hpp +++ b/components/esm/loadcont.hpp @@ -54,6 +54,8 @@ struct Container bool mIsDeleted; + Container(); + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadcrea.cpp b/components/esm/loadcrea.cpp index 6da32eed7..57e911e70 100644 --- a/components/esm/loadcrea.cpp +++ b/components/esm/loadcrea.cpp @@ -9,6 +9,10 @@ namespace ESM { unsigned int Creature::sRecordId = REC_CREA; + Creature::Creature() + : mIsDeleted(false) + {} + void Creature::load(ESMReader &esm) { mPersistent = (esm.getRecordFlags() & 0x0400) != 0; diff --git a/components/esm/loadcrea.hpp b/components/esm/loadcrea.hpp index fb43f6272..22e834e45 100644 --- a/components/esm/loadcrea.hpp +++ b/components/esm/loadcrea.hpp @@ -98,6 +98,8 @@ struct Creature bool mIsDeleted; + Creature(); + const std::vector& getTransport() const; void load(ESMReader &esm); diff --git a/components/esm/loaddial.cpp b/components/esm/loaddial.cpp index 77a04ca01..667afc75c 100644 --- a/components/esm/loaddial.cpp +++ b/components/esm/loaddial.cpp @@ -13,125 +13,128 @@ namespace ESM { unsigned int Dialogue::sRecordId = REC_DIAL; -void Dialogue::load(ESMReader &esm) -{ - mIsDeleted = false; - - mId = esm.getHNString("NAME"); - esm.getSubNameIs("DATA"); - esm.getSubHeader(); - int si = esm.getSubSize(); - if (si == 1) - esm.getT(mType); - else if (si == 4) // The dialogue is deleted - { - int32_t empty; - esm.getT(empty); // Skip an empty DATA - mIsDeleted = readDeleSubRecord(esm); - } - else - esm.fail("Unknown sub record size"); -} + Dialogue::Dialogue() + : mIsDeleted(false) + {} -void Dialogue::save(ESMWriter &esm) const -{ - esm.writeHNCString("NAME", mId); - if (mIsDeleted) + void Dialogue::load(ESMReader &esm) { - esm.writeHNT("DATA", static_cast(0)); - writeDeleSubRecord(esm); - } - else - { - esm.writeHNT("DATA", mType); - } -} - -void Dialogue::blank() -{ - mInfo.clear(); -} - -void Dialogue::readInfo(ESMReader &esm, bool merge) -{ - const std::string& id = esm.getHNOString("INAM"); - - if (!merge || mInfo.empty()) - { - ESM::DialInfo info; - info.mId = id; - info.load(esm); - mLookup[id] = mInfo.insert(mInfo.end(), info); - return; + mIsDeleted = false; + + mId = esm.getHNString("NAME"); + esm.getSubNameIs("DATA"); + esm.getSubHeader(); + int si = esm.getSubSize(); + if (si == 1) + esm.getT(mType); + else if (si == 4) // The dialogue is deleted + { + int32_t empty; + esm.getT(empty); // Skip an empty DATA + mIsDeleted = readDeleSubRecord(esm); + } + else + esm.fail("Unknown sub record size"); } - ESM::Dialogue::InfoContainer::iterator it = mInfo.end(); - - std::map::iterator lookup; - - lookup = mLookup.find(id); - - ESM::DialInfo info; - if (lookup != mLookup.end()) - { - it = lookup->second; - - // Merge with existing record. Only the subrecords that are present in - // the new record will be overwritten. - it->load(esm); - info = *it; - - // Since the record merging may have changed the next/prev linked list connection, we need to re-insert the record - mInfo.erase(it); - mLookup.erase(lookup); - } - else + void Dialogue::save(ESMWriter &esm) const { - info.mId = id; - info.load(esm); + esm.writeHNCString("NAME", mId); + if (mIsDeleted) + { + esm.writeHNT("DATA", static_cast(0)); + writeDeleSubRecord(esm); + } + else + { + esm.writeHNT("DATA", mType); + } } - if (info.mNext.empty()) + void Dialogue::blank() { - mLookup[id] = mInfo.insert(mInfo.end(), info); - return; - } - if (info.mPrev.empty()) - { - mLookup[id] = mInfo.insert(mInfo.begin(), info); - return; + mInfo.clear(); } - lookup = mLookup.find(info.mPrev); - if (lookup != mLookup.end()) + void Dialogue::readInfo(ESMReader &esm, bool merge) { - it = lookup->second; + const std::string& id = esm.getHNOString("INAM"); - mLookup[id] = mInfo.insert(++it, info); - return; - } + if (!merge || mInfo.empty()) + { + ESM::DialInfo info; + info.mId = id; + info.load(esm); + mLookup[id] = mInfo.insert(mInfo.end(), info); + return; + } - lookup = mLookup.find(info.mNext); - if (lookup != mLookup.end()) - { - it = lookup->second; + ESM::Dialogue::InfoContainer::iterator it = mInfo.end(); - mLookup[id] = mInfo.insert(it, info); - return; - } + std::map::iterator lookup; - std::cerr << "Failed to insert info " << id << std::endl; -} + lookup = mLookup.find(id); -void Dialogue::clearDeletedInfos() -{ - for (InfoContainer::iterator it = mInfo.begin(); it != mInfo.end(); ) - { - if (it->mQuestStatus == DialInfo::QS_Deleted) - it = mInfo.erase(it); + ESM::DialInfo info; + if (lookup != mLookup.end()) + { + it = lookup->second; + + // Merge with existing record. Only the subrecords that are present in + // the new record will be overwritten. + it->load(esm); + info = *it; + + // Since the record merging may have changed the next/prev linked list connection, we need to re-insert the record + mInfo.erase(it); + mLookup.erase(lookup); + } else - ++it; + { + info.mId = id; + info.load(esm); + } + + if (info.mNext.empty()) + { + mLookup[id] = mInfo.insert(mInfo.end(), info); + return; + } + if (info.mPrev.empty()) + { + mLookup[id] = mInfo.insert(mInfo.begin(), info); + return; + } + + lookup = mLookup.find(info.mPrev); + if (lookup != mLookup.end()) + { + it = lookup->second; + + mLookup[id] = mInfo.insert(++it, info); + return; + } + + lookup = mLookup.find(info.mNext); + if (lookup != mLookup.end()) + { + it = lookup->second; + + mLookup[id] = mInfo.insert(it, info); + return; + } + + std::cerr << "Failed to insert info " << id << std::endl; } -} + void Dialogue::clearDeletedInfos() + { + for (InfoContainer::iterator it = mInfo.begin(); it != mInfo.end(); ) + { + if (it->mQuestStatus == DialInfo::QS_Deleted) + it = mInfo.erase(it); + else + ++it; + } + } } diff --git a/components/esm/loaddial.hpp b/components/esm/loaddial.hpp index ab8cf4bff..5e7d09871 100644 --- a/components/esm/loaddial.hpp +++ b/components/esm/loaddial.hpp @@ -47,6 +47,8 @@ struct Dialogue bool mIsDeleted; + Dialogue(); + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loaddoor.cpp b/components/esm/loaddoor.cpp index 6ee43fd1a..87382fa7b 100644 --- a/components/esm/loaddoor.cpp +++ b/components/esm/loaddoor.cpp @@ -9,6 +9,10 @@ namespace ESM { unsigned int Door::sRecordId = REC_DOOR; + Door::Door() + : mIsDeleted(false) + {} + void Door::load(ESMReader &esm) { mId = esm.getHNString("NAME"); diff --git a/components/esm/loaddoor.hpp b/components/esm/loaddoor.hpp index b0326a744..546471ed3 100644 --- a/components/esm/loaddoor.hpp +++ b/components/esm/loaddoor.hpp @@ -19,6 +19,8 @@ struct Door bool mIsDeleted; + Door(); + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadench.cpp b/components/esm/loadench.cpp index 88d9e0f2e..1518e0385 100644 --- a/components/esm/loadench.cpp +++ b/components/esm/loadench.cpp @@ -9,51 +9,55 @@ namespace ESM { unsigned int Enchantment::sRecordId = REC_ENCH; -void Enchantment::load(ESMReader &esm) -{ - mEffects.mList.clear(); + Enchantment::Enchantment() + : mIsDeleted(false) + {} - mId = esm.getHNString("NAME"); - if (mIsDeleted = readDeleSubRecord(esm)) + void Enchantment::load(ESMReader &esm) { - return; - } + mEffects.mList.clear(); - bool hasData = false; - while (esm.hasMoreSubs()) - { - esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + mId = esm.getHNString("NAME"); + if (mIsDeleted = readDeleSubRecord(esm)) + { + return; + } + + bool hasData = false; + while (esm.hasMoreSubs()) { - case ESM::FourCC<'E','N','D','T'>::value: - esm.getHT(mData, 16); - hasData = true; - break; - case ESM::FourCC<'E','N','A','M'>::value: - mEffects.add(esm); - break; - default: - esm.fail("Unknown subrecord"); - break; + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'E','N','D','T'>::value: + esm.getHT(mData, 16); + hasData = true; + break; + case ESM::FourCC<'E','N','A','M'>::value: + mEffects.add(esm); + break; + default: + esm.fail("Unknown subrecord"); + break; + } } + if (!hasData) + esm.fail("Missing ENDT subrecord"); } - if (!hasData) - esm.fail("Missing ENDT subrecord"); -} -void Enchantment::save(ESMWriter &esm) const -{ - esm.writeHNCString("NAME", mId); - if (mIsDeleted) + void Enchantment::save(ESMWriter &esm) const { - writeDeleSubRecord(esm); - return; - } + esm.writeHNCString("NAME", mId); + if (mIsDeleted) + { + writeDeleSubRecord(esm); + return; + } - esm.writeHNT("ENDT", mData, 16); - mEffects.save(esm); -} + esm.writeHNT("ENDT", mData, 16); + mEffects.save(esm); + } void Enchantment::blank() { diff --git a/components/esm/loadench.hpp b/components/esm/loadench.hpp index c9b19e31b..6ebe8e940 100644 --- a/components/esm/loadench.hpp +++ b/components/esm/loadench.hpp @@ -44,6 +44,8 @@ struct Enchantment bool mIsDeleted; + Enchantment(); + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadfact.cpp b/components/esm/loadfact.cpp index 9149c2a30..53f3aa5a6 100644 --- a/components/esm/loadfact.cpp +++ b/components/esm/loadfact.cpp @@ -11,6 +11,10 @@ namespace ESM { unsigned int Faction::sRecordId = REC_FACT; + Faction::Faction() + : mIsDeleted(false) + {} + int& Faction::FADTstruct::getSkill (int index, bool ignored) { if (index<0 || index>=7) @@ -27,82 +31,83 @@ namespace ESM return mSkills[index]; } -void Faction::load(ESMReader &esm) -{ - mReactions.clear(); - for (int i=0;i<10;++i) - mRanks[i].clear(); - - mId = esm.getHNString("NAME"); - if (mIsDeleted = readDeleSubRecord(esm)) + void Faction::load(ESMReader &esm) { - return; - } + mReactions.clear(); + for (int i=0;i<10;++i) + mRanks[i].clear(); - int rankCounter=0; - bool hasData = false; - while (esm.hasMoreSubs()) - { - esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + mId = esm.getHNString("NAME"); + if (mIsDeleted = readDeleSubRecord(esm)) { - case ESM::FourCC<'F','N','A','M'>::value: - mName = esm.getHString(); - break; - case ESM::FourCC<'R','N','A','M'>::value: - if (rankCounter >= 10) - esm.fail("Rank out of range"); - mRanks[rankCounter++] = esm.getHString(); - break; - case ESM::FourCC<'F','A','D','T'>::value: - esm.getHT(mData, 240); - if (mData.mIsHidden > 1) - esm.fail("Unknown flag!"); - hasData = true; - break; - case ESM::FourCC<'A','N','A','M'>::value: + return; + } + + int rankCounter=0; + bool hasData = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) { - std::string faction = esm.getHString(); - int reaction; - esm.getHNT(reaction, "INTV"); - mReactions[faction] = reaction; - break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'R','N','A','M'>::value: + if (rankCounter >= 10) + esm.fail("Rank out of range"); + mRanks[rankCounter++] = esm.getHString(); + break; + case ESM::FourCC<'F','A','D','T'>::value: + esm.getHT(mData, 240); + if (mData.mIsHidden > 1) + esm.fail("Unknown flag!"); + hasData = true; + break; + case ESM::FourCC<'A','N','A','M'>::value: + { + std::string faction = esm.getHString(); + int reaction; + esm.getHNT(reaction, "INTV"); + mReactions[faction] = reaction; + break; + } + default: + esm.fail("Unknown subrecord"); } - default: - esm.fail("Unknown subrecord"); } + if (!hasData) + esm.fail("Missing FADT subrecord"); } - if (!hasData) - esm.fail("Missing FADT subrecord"); -} -void Faction::save(ESMWriter &esm) const -{ - esm.writeHNCString("NAME", mId); - if (mIsDeleted) + + void Faction::save(ESMWriter &esm) const { - writeDeleSubRecord(esm); - return; - } + esm.writeHNCString("NAME", mId); + if (mIsDeleted) + { + writeDeleSubRecord(esm); + return; + } - esm.writeHNOCString("FNAM", mName); + esm.writeHNOCString("FNAM", mName); - for (int i = 0; i < 10; i++) - { - if (mRanks[i].empty()) - break; + for (int i = 0; i < 10; i++) + { + if (mRanks[i].empty()) + break; - esm.writeHNString("RNAM", mRanks[i], 32); - } + esm.writeHNString("RNAM", mRanks[i], 32); + } - esm.writeHNT("FADT", mData, 240); + esm.writeHNT("FADT", mData, 240); - for (std::map::const_iterator it = mReactions.begin(); it != mReactions.end(); ++it) - { - esm.writeHNString("ANAM", it->first); - esm.writeHNT("INTV", it->second); + for (std::map::const_iterator it = mReactions.begin(); it != mReactions.end(); ++it) + { + esm.writeHNString("ANAM", it->first); + esm.writeHNT("INTV", it->second); + } } -} void Faction::blank() { diff --git a/components/esm/loadfact.hpp b/components/esm/loadfact.hpp index fec13b1ca..96c02028b 100644 --- a/components/esm/loadfact.hpp +++ b/components/esm/loadfact.hpp @@ -64,6 +64,8 @@ struct Faction bool mIsDeleted; + Faction(); + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadglob.cpp b/components/esm/loadglob.cpp index 6cc37d675..392df02b5 100644 --- a/components/esm/loadglob.cpp +++ b/components/esm/loadglob.cpp @@ -9,6 +9,10 @@ namespace ESM { unsigned int Global::sRecordId = REC_GLOB; + Global::Global() + : mIsDeleted(false) + {} + void Global::load (ESMReader &esm) { mId = esm.getHNString("NAME"); diff --git a/components/esm/loadglob.hpp b/components/esm/loadglob.hpp index 45b47a3bc..c0219c0ba 100644 --- a/components/esm/loadglob.hpp +++ b/components/esm/loadglob.hpp @@ -26,6 +26,8 @@ struct Global bool mIsDeleted; + Global(); + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadinfo.cpp b/components/esm/loadinfo.cpp index 3b5e0ea3a..4c997213a 100644 --- a/components/esm/loadinfo.cpp +++ b/components/esm/loadinfo.cpp @@ -9,169 +9,173 @@ namespace ESM { unsigned int DialInfo::sRecordId = REC_INFO; -void DialInfo::load(ESMReader &esm) -{ - mQuestStatus = QS_None; - mFactionLess = false; - - mPrev = esm.getHNString("PNAM"); - mNext = esm.getHNString("NNAM"); + DialInfo::DialInfo() + : mIsDeleted(false) + {} - // Since there's no way to mark selects as "deleted", we have to clear the SelectStructs from all previous loadings - mSelects.clear(); - - // If the info is deleted, NAME and DELE sub-records are followed after NNAM - if (esm.isNextSub("NAME")) + void DialInfo::load(ESMReader &esm) { - mResponse = esm.getHString(); - mIsDeleted = readDeleSubRecord(esm); - return; - } - - esm.getSubNameIs("DATA"); - esm.getHT(mData, 12); - - if (!esm.hasMoreSubs()) - return; - - // What follows is somewhat spaghetti-ish, but it's worth if for - // an extra speedup. INFO is by far the most common record type. + mQuestStatus = QS_None; + mFactionLess = false; - // subName is a reference to the original, so it changes whenever - // a new sub name is read. esm.isEmptyOrGetName() will get the - // next name for us, or return true if there are no more records. - esm.getSubName(); - const NAME &subName = esm.retSubName(); + mPrev = esm.getHNString("PNAM"); + mNext = esm.getHNString("NNAM"); - if (subName.val == REC_ONAM) - { - mActor = esm.getHString(); - if (esm.isEmptyOrGetName()) - return; - } - if (subName.val == REC_RNAM) - { - mRace = esm.getHString(); - if (esm.isEmptyOrGetName()) - return; - } - if (subName.val == REC_CNAM) - { - mClass = esm.getHString(); - if (esm.isEmptyOrGetName()) - return; - } + // Since there's no way to mark selects as "deleted", we have to clear the SelectStructs from all previous loadings + mSelects.clear(); - if (subName.val == REC_FNAM) - { - mFaction = esm.getHString(); - if (mFaction == "FFFF") - mFactionLess = true; - if (esm.isEmptyOrGetName()) - return; - } - if (subName.val == REC_ANAM) - { - mCell = esm.getHString(); - if (esm.isEmptyOrGetName()) - return; - } - if (subName.val == REC_DNAM) - { - mPcFaction = esm.getHString(); - if (esm.isEmptyOrGetName()) + // If the info is deleted, NAME and DELE sub-records are followed after NNAM + if (esm.isNextSub("NAME")) + { + mResponse = esm.getHString(); + mIsDeleted = readDeleSubRecord(esm); return; - } - if (subName.val == REC_SNAM) - { - mSound = esm.getHString(); - if (esm.isEmptyOrGetName()) - return; - } - if (subName.val == REC_NAME) - { - mResponse = esm.getHString(); - if (esm.isEmptyOrGetName()) - return; - } + } - while (subName.val == REC_SCVR) - { - SelectStruct ss; - - ss.mSelectRule = esm.getHString(); - - ss.mValue.read (esm, Variant::Format_Info); - - mSelects.push_back(ss); - - if (esm.isEmptyOrGetName()) - return; - } + esm.getSubNameIs("DATA"); + esm.getHT(mData, 12); - if (subName.val == REC_BNAM) - { - mResultScript = esm.getHString(); - if (esm.isEmptyOrGetName()) + if (!esm.hasMoreSubs()) return; - } - if (subName.val == REC_QSTN) - mQuestStatus = QS_Name; - else if (subName.val == REC_QSTF) - mQuestStatus = QS_Finished; - else if (subName.val == REC_QSTR) - mQuestStatus = QS_Restart; - else if (subName.val == REC_DELE) - mQuestStatus = QS_Deleted; - else - esm.fail( - "Don't know what to do with " + subName.toString() - + " in INFO " + mId); - - if (mQuestStatus != QS_None) - // Skip rest of record - esm.skipRecord(); -} - -void DialInfo::save(ESMWriter &esm) const -{ - esm.writeHNCString("PNAM", mPrev); - esm.writeHNCString("NNAM", mNext); - if (mIsDeleted) - { - esm.writeHNCString("NAME", mResponse); - writeDeleSubRecord(esm); - return; + // What follows is somewhat spaghetti-ish, but it's worth if for + // an extra speedup. INFO is by far the most common record type. + + // subName is a reference to the original, so it changes whenever + // a new sub name is read. esm.isEmptyOrGetName() will get the + // next name for us, or return true if there are no more records. + esm.getSubName(); + const NAME &subName = esm.retSubName(); + + if (subName.val == REC_ONAM) + { + mActor = esm.getHString(); + if (esm.isEmptyOrGetName()) + return; + } + if (subName.val == REC_RNAM) + { + mRace = esm.getHString(); + if (esm.isEmptyOrGetName()) + return; + } + if (subName.val == REC_CNAM) + { + mClass = esm.getHString(); + if (esm.isEmptyOrGetName()) + return; + } + + if (subName.val == REC_FNAM) + { + mFaction = esm.getHString(); + if (mFaction == "FFFF") + mFactionLess = true; + if (esm.isEmptyOrGetName()) + return; + } + if (subName.val == REC_ANAM) + { + mCell = esm.getHString(); + if (esm.isEmptyOrGetName()) + return; + } + if (subName.val == REC_DNAM) + { + mPcFaction = esm.getHString(); + if (esm.isEmptyOrGetName()) + return; + } + if (subName.val == REC_SNAM) + { + mSound = esm.getHString(); + if (esm.isEmptyOrGetName()) + return; + } + if (subName.val == REC_NAME) + { + mResponse = esm.getHString(); + if (esm.isEmptyOrGetName()) + return; + } + + while (subName.val == REC_SCVR) + { + SelectStruct ss; + + ss.mSelectRule = esm.getHString(); + + ss.mValue.read (esm, Variant::Format_Info); + + mSelects.push_back(ss); + + if (esm.isEmptyOrGetName()) + return; + } + + if (subName.val == REC_BNAM) + { + mResultScript = esm.getHString(); + if (esm.isEmptyOrGetName()) + return; + } + + if (subName.val == REC_QSTN) + mQuestStatus = QS_Name; + else if (subName.val == REC_QSTF) + mQuestStatus = QS_Finished; + else if (subName.val == REC_QSTR) + mQuestStatus = QS_Restart; + else if (subName.val == REC_DELE) + mQuestStatus = QS_Deleted; + else + esm.fail( + "Don't know what to do with " + subName.toString() + + " in INFO " + mId); + + if (mQuestStatus != QS_None) + // Skip rest of record + esm.skipRecord(); } - esm.writeHNT("DATA", mData, 12); - esm.writeHNOCString("ONAM", mActor); - esm.writeHNOCString("RNAM", mRace); - esm.writeHNOCString("CNAM", mClass); - esm.writeHNOCString("FNAM", mFaction); - esm.writeHNOCString("ANAM", mCell); - esm.writeHNOCString("DNAM", mPcFaction); - esm.writeHNOCString("SNAM", mSound); - esm.writeHNOString("NAME", mResponse); - - for (std::vector::const_iterator it = mSelects.begin(); it != mSelects.end(); ++it) + void DialInfo::save(ESMWriter &esm) const { - esm.writeHNString("SCVR", it->mSelectRule); - it->mValue.write (esm, Variant::Format_Info); - } - - esm.writeHNOString("BNAM", mResultScript); - - switch(mQuestStatus) - { - case QS_Name: esm.writeHNT("QSTN",'\1'); break; - case QS_Finished: esm.writeHNT("QSTF", '\1'); break; - case QS_Restart: esm.writeHNT("QSTR", '\1'); break; - case QS_Deleted: esm.writeHNT("DELE", '\1'); break; - default: break; + esm.writeHNCString("PNAM", mPrev); + esm.writeHNCString("NNAM", mNext); + if (mIsDeleted) + { + esm.writeHNCString("NAME", mResponse); + writeDeleSubRecord(esm); + return; + } + + esm.writeHNT("DATA", mData, 12); + esm.writeHNOCString("ONAM", mActor); + esm.writeHNOCString("RNAM", mRace); + esm.writeHNOCString("CNAM", mClass); + esm.writeHNOCString("FNAM", mFaction); + esm.writeHNOCString("ANAM", mCell); + esm.writeHNOCString("DNAM", mPcFaction); + esm.writeHNOCString("SNAM", mSound); + esm.writeHNOString("NAME", mResponse); + + for (std::vector::const_iterator it = mSelects.begin(); it != mSelects.end(); ++it) + { + esm.writeHNString("SCVR", it->mSelectRule); + it->mValue.write (esm, Variant::Format_Info); + } + + esm.writeHNOString("BNAM", mResultScript); + + switch(mQuestStatus) + { + case QS_Name: esm.writeHNT("QSTN",'\1'); break; + case QS_Finished: esm.writeHNT("QSTF", '\1'); break; + case QS_Restart: esm.writeHNT("QSTR", '\1'); break; + case QS_Deleted: esm.writeHNT("DELE", '\1'); break; + default: break; + } } -} void DialInfo::blank() { diff --git a/components/esm/loadinfo.hpp b/components/esm/loadinfo.hpp index 8b4fae761..fbb7e36a5 100644 --- a/components/esm/loadinfo.hpp +++ b/components/esm/loadinfo.hpp @@ -108,6 +108,8 @@ struct DialInfo bool mIsDeleted; + DialInfo(); + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadingr.cpp b/components/esm/loadingr.cpp index 8bf0278f7..a7018b36d 100644 --- a/components/esm/loadingr.cpp +++ b/components/esm/loadingr.cpp @@ -9,6 +9,10 @@ namespace ESM { unsigned int Ingredient::sRecordId = REC_INGR; + Ingredient::Ingredient() + : mIsDeleted(false) + {} + void Ingredient::load(ESMReader &esm) { mId = esm.getHNString("NAME"); diff --git a/components/esm/loadingr.hpp b/components/esm/loadingr.hpp index 69a650180..c92f28f18 100644 --- a/components/esm/loadingr.hpp +++ b/components/esm/loadingr.hpp @@ -33,6 +33,8 @@ struct Ingredient bool mIsDeleted; + Ingredient(); + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadlevlist.cpp b/components/esm/loadlevlist.cpp index c8cb110a6..1e07086bc 100644 --- a/components/esm/loadlevlist.cpp +++ b/components/esm/loadlevlist.cpp @@ -7,6 +7,9 @@ namespace ESM { + LevelledListBase::LevelledListBase() + : mIsDeleted(false) + {} void LevelledListBase::load(ESMReader &esm) { diff --git a/components/esm/loadlevlist.hpp b/components/esm/loadlevlist.hpp index 4165275b2..14ebc9937 100644 --- a/components/esm/loadlevlist.hpp +++ b/components/esm/loadlevlist.hpp @@ -38,6 +38,8 @@ struct LevelledListBase bool mIsDeleted; + LevelledListBase(); + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadligh.cpp b/components/esm/loadligh.cpp index bd91e096c..a153d500a 100644 --- a/components/esm/loadligh.cpp +++ b/components/esm/loadligh.cpp @@ -9,6 +9,10 @@ namespace ESM { unsigned int Light::sRecordId = REC_LIGH; + Light::Light() + : mIsDeleted(false) + {} + void Light::load(ESMReader &esm) { mId = esm.getHNString("NAME"); diff --git a/components/esm/loadligh.hpp b/components/esm/loadligh.hpp index 76274e6f4..d4d3418d8 100644 --- a/components/esm/loadligh.hpp +++ b/components/esm/loadligh.hpp @@ -49,6 +49,8 @@ struct Light bool mIsDeleted; + Light(); + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadlock.cpp b/components/esm/loadlock.cpp index c1e866b58..3b169af33 100644 --- a/components/esm/loadlock.cpp +++ b/components/esm/loadlock.cpp @@ -9,6 +9,10 @@ namespace ESM { unsigned int Lockpick::sRecordId = REC_LOCK; + Lockpick::Lockpick() + : mIsDeleted(false) + {} + void Lockpick::load(ESMReader &esm) { mId = esm.getHNString("NAME"); diff --git a/components/esm/loadlock.hpp b/components/esm/loadlock.hpp index af18773ed..ce7de2c06 100644 --- a/components/esm/loadlock.hpp +++ b/components/esm/loadlock.hpp @@ -29,6 +29,8 @@ struct Lockpick bool mIsDeleted; + Lockpick(); + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadltex.cpp b/components/esm/loadltex.cpp index 0ee30b11c..13315e684 100644 --- a/components/esm/loadltex.cpp +++ b/components/esm/loadltex.cpp @@ -9,29 +9,32 @@ namespace ESM { unsigned int LandTexture::sRecordId = REC_LTEX; -void LandTexture::load(ESMReader &esm) -{ - mIsDeleted = readDeleSubRecord(esm); - mId = esm.getHNString("NAME"); - esm.getHNT(mIndex, "INTV"); - mTexture = esm.getHNString("DATA"); -} -void LandTexture::save(ESMWriter &esm) const -{ - if (mIsDeleted) + LandTexture::LandTexture() + : mIsDeleted(false) + {} + + void LandTexture::load(ESMReader &esm) { - writeDeleSubRecord(esm); + mIsDeleted = readDeleSubRecord(esm); + mId = esm.getHNString("NAME"); + esm.getHNT(mIndex, "INTV"); + mTexture = esm.getHNString("DATA"); + } + void LandTexture::save(ESMWriter &esm) const + { + if (mIsDeleted) + { + writeDeleSubRecord(esm); + } + esm.writeHNCString("NAME", mId); + esm.writeHNT("INTV", mIndex); + esm.writeHNCString("DATA", mTexture); } - esm.writeHNCString("NAME", mId); - esm.writeHNT("INTV", mIndex); - esm.writeHNCString("DATA", mTexture); -} - -void LandTexture::blank() -{ - mTexture.clear(); - mIndex = -1; - mIsDeleted = false; -} + void LandTexture::blank() + { + mTexture.clear(); + mIndex = -1; + mIsDeleted = false; + } } diff --git a/components/esm/loadltex.hpp b/components/esm/loadltex.hpp index e019e269e..33af77612 100644 --- a/components/esm/loadltex.hpp +++ b/components/esm/loadltex.hpp @@ -36,11 +36,13 @@ struct LandTexture bool mIsDeleted; - void blank(); - ///< Set record to default state (does not touch the ID). + LandTexture(); void load(ESMReader &esm); void save(ESMWriter &esm) const; + + void blank(); + ///< Set record to default state (does not touch the ID). }; } #endif diff --git a/components/esm/loadmisc.cpp b/components/esm/loadmisc.cpp index 11d2f2a05..08cbcf741 100644 --- a/components/esm/loadmisc.cpp +++ b/components/esm/loadmisc.cpp @@ -9,6 +9,10 @@ namespace ESM { unsigned int Miscellaneous::sRecordId = REC_MISC; + Miscellaneous::Miscellaneous() + : mIsDeleted(false) + {} + void Miscellaneous::load(ESMReader &esm) { mId = esm.getHNString("NAME"); diff --git a/components/esm/loadmisc.hpp b/components/esm/loadmisc.hpp index 5d5e9f66f..82018cd72 100644 --- a/components/esm/loadmisc.hpp +++ b/components/esm/loadmisc.hpp @@ -34,6 +34,8 @@ struct Miscellaneous bool mIsDeleted; + Miscellaneous(); + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadnpc.cpp b/components/esm/loadnpc.cpp index 280db0791..eadf23a21 100644 --- a/components/esm/loadnpc.cpp +++ b/components/esm/loadnpc.cpp @@ -9,6 +9,10 @@ namespace ESM { unsigned int NPC::sRecordId = REC_NPC_; + NPC::NPC() + : mIsDeleted(false) + {} + void NPC::load(ESMReader &esm) { mPersistent = (esm.getRecordFlags() & 0x0400) != 0; diff --git a/components/esm/loadnpc.hpp b/components/esm/loadnpc.hpp index 7b75cb178..263752752 100644 --- a/components/esm/loadnpc.hpp +++ b/components/esm/loadnpc.hpp @@ -132,6 +132,8 @@ struct NPC bool mIsDeleted; + NPC(); + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadprob.cpp b/components/esm/loadprob.cpp index 12f7ad00a..f5287f986 100644 --- a/components/esm/loadprob.cpp +++ b/components/esm/loadprob.cpp @@ -9,6 +9,10 @@ namespace ESM { unsigned int Probe::sRecordId = REC_PROB; + Probe::Probe() + : mIsDeleted(false) + {} + void Probe::load(ESMReader &esm) { mId = esm.getHNString("NAME"); diff --git a/components/esm/loadprob.hpp b/components/esm/loadprob.hpp index 9daab6b1b..748d498fc 100644 --- a/components/esm/loadprob.hpp +++ b/components/esm/loadprob.hpp @@ -29,6 +29,8 @@ struct Probe bool mIsDeleted; + Probe(); + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadregn.cpp b/components/esm/loadregn.cpp index b0adc6f58..2d99947b0 100644 --- a/components/esm/loadregn.cpp +++ b/components/esm/loadregn.cpp @@ -9,69 +9,74 @@ namespace ESM { unsigned int Region::sRecordId = REC_REGN; -void Region::load(ESMReader &esm) -{ - mIsDeleted = readDeleSubRecord(esm); - mId = esm.getHNString("NAME"); - mName = esm.getHNOString("FNAM"); + Region::Region() + : mIsDeleted(false) + {} - esm.getSubNameIs("WEAT"); - esm.getSubHeader(); - if (esm.getVer() == VER_12) - { - mData.mA = 0; - mData.mB = 0; - esm.getExact(&mData, sizeof(mData) - 2); - } - else if (esm.getVer() == VER_13) + void Region::load(ESMReader &esm) { - // May include the additional two bytes (but not necessarily) - if (esm.getSubSize() == sizeof(mData)) - esm.getExact(&mData, sizeof(mData)); - else + mIsDeleted = readDeleSubRecord(esm); + mId = esm.getHNString("NAME"); + mName = esm.getHNOString("FNAM"); + + esm.getSubNameIs("WEAT"); + esm.getSubHeader(); + if (esm.getVer() == VER_12) { mData.mA = 0; mData.mB = 0; - esm.getExact(&mData, sizeof(mData)-2); + esm.getExact(&mData, sizeof(mData) - 2); } - } - else - esm.fail("Don't know what to do in this version"); + else if (esm.getVer() == VER_13) + { + // May include the additional two bytes (but not necessarily) + if (esm.getSubSize() == sizeof(mData)) + esm.getExact(&mData, sizeof(mData)); + else + { + mData.mA = 0; + mData.mB = 0; + esm.getExact(&mData, sizeof(mData)-2); + } + } + else + esm.fail("Don't know what to do in this version"); - mSleepList = esm.getHNOString("BNAM"); + mSleepList = esm.getHNOString("BNAM"); - esm.getHNT(mMapColor, "CNAM"); + esm.getHNT(mMapColor, "CNAM"); - mSoundList.clear(); - while (esm.hasMoreSubs()) - { - SoundRef sr; - esm.getHNT(sr, "SNAM", 33); - mSoundList.push_back(sr); + mSoundList.clear(); + while (esm.hasMoreSubs()) + { + SoundRef sr; + esm.getHNT(sr, "SNAM", 33); + mSoundList.push_back(sr); + } } -} -void Region::save(ESMWriter &esm) const -{ - if (mIsDeleted) + + void Region::save(ESMWriter &esm) const { - writeDeleSubRecord(esm); - } - esm.writeHNString("NAME", mId); - esm.writeHNOCString("FNAM", mName); + if (mIsDeleted) + { + writeDeleSubRecord(esm); + } + esm.writeHNString("NAME", mId); + esm.writeHNOCString("FNAM", mName); - if (esm.getVersion() == VER_12) - esm.writeHNT("WEAT", mData, sizeof(mData) - 2); - else - esm.writeHNT("WEAT", mData); + if (esm.getVersion() == VER_12) + esm.writeHNT("WEAT", mData, sizeof(mData) - 2); + else + esm.writeHNT("WEAT", mData); - esm.writeHNOCString("BNAM", mSleepList); + esm.writeHNOCString("BNAM", mSleepList); - esm.writeHNT("CNAM", mMapColor); - for (std::vector::const_iterator it = mSoundList.begin(); it != mSoundList.end(); ++it) - { - esm.writeHNT("SNAM", *it); + esm.writeHNT("CNAM", mMapColor); + for (std::vector::const_iterator it = mSoundList.begin(); it != mSoundList.end(); ++it) + { + esm.writeHNT("SNAM", *it); + } } -} void Region::blank() { diff --git a/components/esm/loadregn.hpp b/components/esm/loadregn.hpp index 921ab887b..9082437fe 100644 --- a/components/esm/loadregn.hpp +++ b/components/esm/loadregn.hpp @@ -53,6 +53,8 @@ struct Region bool mIsDeleted; + Region(); + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadrepa.cpp b/components/esm/loadrepa.cpp index 608536f02..fb213efd8 100644 --- a/components/esm/loadrepa.cpp +++ b/components/esm/loadrepa.cpp @@ -9,61 +9,65 @@ namespace ESM { unsigned int Repair::sRecordId = REC_REPA; -void Repair::load(ESMReader &esm) -{ - mId = esm.getHNString("NAME"); - if (mIsDeleted = readDeleSubRecord(esm)) - { - return; - } + Repair::Repair() + : mIsDeleted(false) + {} - bool hasData = true; - while (esm.hasMoreSubs()) + void Repair::load(ESMReader &esm) { - esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + mId = esm.getHNString("NAME"); + if (mIsDeleted = readDeleSubRecord(esm)) { - case ESM::FourCC<'M','O','D','L'>::value: - mModel = esm.getHString(); - break; - case ESM::FourCC<'F','N','A','M'>::value: - mName = esm.getHString(); - break; - case ESM::FourCC<'R','I','D','T'>::value: - esm.getHT(mData, 16); - hasData = true; - break; - case ESM::FourCC<'S','C','R','I'>::value: - mScript = esm.getHString(); - break; - case ESM::FourCC<'I','T','E','X'>::value: - mIcon = esm.getHString(); - break; - default: - esm.fail("Unknown subrecord"); + return; } + + bool hasData = true; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'R','I','D','T'>::value: + esm.getHT(mData, 16); + hasData = true; + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + case ESM::FourCC<'I','T','E','X'>::value: + mIcon = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasData) + esm.fail("Missing RIDT subrecord"); } - if (!hasData) - esm.fail("Missing RIDT subrecord"); -} -void Repair::save(ESMWriter &esm) const -{ - esm.writeHNCString("NAME", mId); - if (mIsDeleted) + void Repair::save(ESMWriter &esm) const { - writeDeleSubRecord(esm); - return; - } + esm.writeHNCString("NAME", mId); + if (mIsDeleted) + { + writeDeleSubRecord(esm); + return; + } - esm.writeHNCString("MODL", mModel); - esm.writeHNOCString("FNAM", mName); + esm.writeHNCString("MODL", mModel); + esm.writeHNOCString("FNAM", mName); - esm.writeHNT("RIDT", mData, 16); - esm.writeHNOString("SCRI", mScript); - esm.writeHNOCString("ITEX", mIcon); -} + esm.writeHNT("RIDT", mData, 16); + esm.writeHNOString("SCRI", mScript); + esm.writeHNOCString("ITEX", mIcon); + } void Repair::blank() { diff --git a/components/esm/loadrepa.hpp b/components/esm/loadrepa.hpp index a660574be..1448f9c77 100644 --- a/components/esm/loadrepa.hpp +++ b/components/esm/loadrepa.hpp @@ -29,6 +29,8 @@ struct Repair bool mIsDeleted; + Repair(); + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadscpt.cpp b/components/esm/loadscpt.cpp index 67c1b8f6f..529f0a66d 100644 --- a/components/esm/loadscpt.cpp +++ b/components/esm/loadscpt.cpp @@ -9,9 +9,12 @@ namespace ESM { - unsigned int Script::sRecordId = REC_SCPT; + Script::Script() + : mIsDeleted(false) + {} + void Script::loadSCVR(ESMReader &esm) { int s = mData.mStringTableSize; diff --git a/components/esm/loadscpt.hpp b/components/esm/loadscpt.hpp index 401dfe105..58b5842e8 100644 --- a/components/esm/loadscpt.hpp +++ b/components/esm/loadscpt.hpp @@ -52,6 +52,8 @@ public: bool mIsDeleted; + Script(); + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadsndg.cpp b/components/esm/loadsndg.cpp index f92c4eee8..261087be0 100644 --- a/components/esm/loadsndg.cpp +++ b/components/esm/loadsndg.cpp @@ -9,6 +9,10 @@ namespace ESM { unsigned int SoundGenerator::sRecordId = REC_SNDG; + SoundGenerator::SoundGenerator() + : mIsDeleted(false) + {} + void SoundGenerator::load(ESMReader &esm) { mId = esm.getHNString("NAME"); diff --git a/components/esm/loadsndg.hpp b/components/esm/loadsndg.hpp index e486976f5..13eb18072 100644 --- a/components/esm/loadsndg.hpp +++ b/components/esm/loadsndg.hpp @@ -38,6 +38,8 @@ struct SoundGenerator bool mIsDeleted; + SoundGenerator(); + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadsoun.cpp b/components/esm/loadsoun.cpp index 19e8a5d80..9a1a52b1e 100644 --- a/components/esm/loadsoun.cpp +++ b/components/esm/loadsoun.cpp @@ -9,6 +9,10 @@ namespace ESM { unsigned int Sound::sRecordId = REC_SOUN; + Sound::Sound() + : mIsDeleted(false) + {} + void Sound::load(ESMReader &esm) { mId = esm.getHNString("NAME"); diff --git a/components/esm/loadsoun.hpp b/components/esm/loadsoun.hpp index 95c89b29d..0b40ae751 100644 --- a/components/esm/loadsoun.hpp +++ b/components/esm/loadsoun.hpp @@ -25,6 +25,8 @@ struct Sound bool mIsDeleted; + Sound(); + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadspel.cpp b/components/esm/loadspel.cpp index cac06b200..d2d8c7d6d 100644 --- a/components/esm/loadspel.cpp +++ b/components/esm/loadspel.cpp @@ -9,6 +9,10 @@ namespace ESM { unsigned int Spell::sRecordId = REC_SPEL; + Spell::Spell() + : mIsDeleted(false) + {} + void Spell::load(ESMReader &esm) { mEffects.mList.clear(); diff --git a/components/esm/loadspel.hpp b/components/esm/loadspel.hpp index 2aba131ad..327e94d8f 100644 --- a/components/esm/loadspel.hpp +++ b/components/esm/loadspel.hpp @@ -47,6 +47,8 @@ struct Spell bool mIsDeleted; + Spell(); + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadstat.cpp b/components/esm/loadstat.cpp index a49caba89..2fde46bd2 100644 --- a/components/esm/loadstat.cpp +++ b/components/esm/loadstat.cpp @@ -9,6 +9,10 @@ namespace ESM { unsigned int Static::sRecordId = REC_STAT; + Static::Static() + : mIsDeleted(false) + {} + void Static::load(ESMReader &esm) { mId = esm.getHNString("NAME"); diff --git a/components/esm/loadstat.hpp b/components/esm/loadstat.hpp index c4306ad8f..f88ad671b 100644 --- a/components/esm/loadstat.hpp +++ b/components/esm/loadstat.hpp @@ -30,6 +30,8 @@ struct Static bool mIsDeleted; + Static(); + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadweap.cpp b/components/esm/loadweap.cpp index 66d65d0f5..38fb94adb 100644 --- a/components/esm/loadweap.cpp +++ b/components/esm/loadweap.cpp @@ -9,6 +9,10 @@ namespace ESM { unsigned int Weapon::sRecordId = REC_WEAP; + Weapon::Weapon() + : mIsDeleted(false) + {} + void Weapon::load(ESMReader &esm) { mId = esm.getHNString("NAME"); diff --git a/components/esm/loadweap.hpp b/components/esm/loadweap.hpp index 30dfbc92a..ce61eeb72 100644 --- a/components/esm/loadweap.hpp +++ b/components/esm/loadweap.hpp @@ -71,6 +71,8 @@ struct Weapon bool mIsDeleted; + Weapon(); + void load(ESMReader &esm); void save(ESMWriter &esm) const; From f12619b86a149f17aaa136456d6fd97061fec0f1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 10 Jul 2015 02:34:00 +0200 Subject: [PATCH 1781/3725] Implement fStromWindSpeed (Fixes #2764) --- apps/openmw/mwworld/weather.cpp | 9 ++++++--- apps/openmw/mwworld/weather.hpp | 4 +++- apps/openmw/mwworld/worldimp.cpp | 6 +++--- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 70d6f1b36..2d2b3e20d 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -66,6 +66,10 @@ void WeatherManager::setFallbackWeather(Weather& weather,const std::string& name weather.mGlareView = mFallback->getFallbackFloat("Weather_"+upper+"_Glare_View"); weather.mCloudTexture = mFallback->getFallbackString("Weather_"+upper+"_Cloud_Texture"); + static const float fStromWindSpeed = mStore->get().find("fStromWindSpeed")->getFloat(); + + weather.mIsStorm = weather.mWindSpeed > fStromWindSpeed; + bool usesPrecip = mFallback->getFallbackBool("Weather_"+upper+"_Using_Precip"); if (usesPrecip) weather.mRainEffect = "meshes\\raindrop.nif"; @@ -79,7 +83,6 @@ Rain Height Max=700 ? Rain Threshold=0.6 ? Max Raindrops=650 ? */ - weather.mIsStorm = (name == "ashstorm" || name == "blight"); mWeatherSettings[name] = weather; } @@ -112,8 +115,8 @@ float WeatherManager::calculateAngleFade (const std::string& moonName, float ang return 1.f; } -WeatherManager::WeatherManager(MWRender::RenderingManager* rendering,MWWorld::Fallback* fallback) : - mHour(14), mWindSpeed(0.f), mIsStorm(false), mStormDirection(0,1,0), mFallback(fallback), +WeatherManager::WeatherManager(MWRender::RenderingManager* rendering, MWWorld::Fallback* fallback, MWWorld::ESMStore* store) : + mHour(14), mWindSpeed(0.f), mIsStorm(false), mStormDirection(0,1,0), mFallback(fallback), mStore(store), mRendering(rendering), mCurrentWeather("clear"), mNextWeather(""), mFirstUpdate(true), mRemainingTransitionTime(0), mThunderFlash(0), mThunderChance(0), mThunderChanceNeeded(50), mTimePassed(0), mWeatherUpdateTime(0), mThunderSoundDelay(0) diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index d7dfee99b..efe69f17c 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -156,7 +156,8 @@ namespace MWWorld class WeatherManager { public: - WeatherManager(MWRender::RenderingManager*,MWWorld::Fallback* fallback); + // Have to pass fallback and Store, can't use singleton since World isn't fully constructed yet at the time + WeatherManager(MWRender::RenderingManager*, MWWorld::Fallback* fallback, MWWorld::ESMStore* store); ~WeatherManager(); /** @@ -210,6 +211,7 @@ namespace MWWorld std::string mPlayingSoundID; MWWorld::Fallback* mFallback; + MWWorld::ESMStore* mStore; void setFallbackWeather(Weather& weather,const std::string& name); MWRender::RenderingManager* mRendering; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 4b14ea602..a2c7c3a79 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -163,8 +163,6 @@ namespace MWWorld mProjectileManager.reset(new ProjectileManager(rootNode, resourceSystem, mPhysics)); mRendering = new MWRender::RenderingManager(viewer, rootNode, resourceSystem, &mFallback); - mWeatherManager = new MWWorld::WeatherManager(mRendering,&mFallback); - mEsm.resize(contentFiles.size()); Loading::Listener* listener = MWBase::Environment::get().getWindowManager()->getLoadingScreen(); listener->loadingOn(); @@ -193,6 +191,8 @@ namespace MWWorld mGlobalVariables.fill (mStore); + mWeatherManager = new MWWorld::WeatherManager(mRendering,&mFallback,&mStore); + mWorldScene = new Scene(*mRendering, mPhysics); } @@ -265,7 +265,7 @@ namespace MWWorld // we don't want old weather to persist on a new game delete mWeatherManager; mWeatherManager = 0; - mWeatherManager = new MWWorld::WeatherManager(mRendering,&mFallback); + mWeatherManager = new MWWorld::WeatherManager(mRendering,&mFallback,&mStore); if (!mStartupScript.empty()) MWBase::Environment::get().getWindowManager()->executeInConsole(mStartupScript); From 72686c32ae18a1e5afb89478849b15bd4cfcc881 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 10 Jul 2015 03:03:17 +0200 Subject: [PATCH 1782/3725] Fix runtime exceptions on MyGUI debug builds --- components/myguiplatform/myguirendermanager.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/components/myguiplatform/myguirendermanager.cpp b/components/myguiplatform/myguirendermanager.cpp index 4979d6451..89d55f5c1 100644 --- a/components/myguiplatform/myguirendermanager.cpp +++ b/components/myguiplatform/myguirendermanager.cpp @@ -523,12 +523,8 @@ void RenderManager::destroyAllResources() bool RenderManager::checkTexture(MyGUI::ITexture* _texture) { - for (MapTexture::const_iterator item = mTextures.begin(); item != mTextures.end(); ++item) - { - if (item->second == _texture) - return true; - } - return false; + // We support external textures that aren't registered via this manager, so can't implement this method sensibly. + return true; } } From 12f413ba9b8c6fbbf81af8dd1a6fd4eca193eaaf Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Fri, 10 Jul 2015 20:21:55 +0200 Subject: [PATCH 1783/3725] Don't instantiate specialized templates This fixes the VS2012 build issue --- apps/openmw/mwworld/store.cpp | 12 ++++++------ apps/openmw/mwworld/store.hpp | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index 96c711896..d873ab468 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -1064,11 +1064,11 @@ namespace MWWorld template class MWWorld::Store; template class MWWorld::Store; template class MWWorld::Store; -template class MWWorld::Store; +//template class MWWorld::Store; template class MWWorld::Store; template class MWWorld::Store; template class MWWorld::Store; -template class MWWorld::Store; +//template class MWWorld::Store; template class MWWorld::Store; template class MWWorld::Store; template class MWWorld::Store; @@ -1082,21 +1082,21 @@ template class MWWorld::Store; template class MWWorld::Store; template class MWWorld::Store; template class MWWorld::Store; -template class MWWorld::Store; +//template class MWWorld::Store; template class MWWorld::Store; template class MWWorld::Store; template class MWWorld::Store; -template class MWWorld::Store; +//template class MWWorld::Store; template class MWWorld::Store; template class MWWorld::Store; -template class MWWorld::Store; +//template class MWWorld::Store; template class MWWorld::Store; template class MWWorld::Store; template class MWWorld::Store; template class MWWorld::Store; template class MWWorld::Store; template class MWWorld::Store; -template class MWWorld::Store; +//template class MWWorld::Store; template class MWWorld::Store; template class MWWorld::Store; template class MWWorld::Store; diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index 02fb983cd..3cbd8d3ac 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -319,7 +319,7 @@ namespace MWWorld public: - Store(); + Store(); void setCells(Store& cells); void load(ESM::ESMReader &esm, const std::string &id); From 4b002863c899d22c2a060773e39034a69a7b3e13 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 11 Jul 2015 00:45:11 +0200 Subject: [PATCH 1784/3725] Re-enabled a few build targets --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index cbfc5d489..a0a6f0746 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,7 +18,7 @@ addons: name: "OpenMW/openmw" description: "" notification_email: scrawl@baseoftrash.de - build_command_prepend: "cmake . -DBUILD_OPENCS=FALSE -DBUILD_UNITTESTS=FALSE -DBUILD_WIZARD=FALSE -DBUILD_BSATOOL=FALSE -DBUILD_ESMTOOL=FALSE -DBUILD_LAUNCHER=FALSE -DBUILD_MWINIIMPORTER=FALSE" + build_command_prepend: "cmake . -DBUILD_UNITTESTS=FALSE -DBUILD_WIZARD=FALSE -DBUILD_LAUNCHER=FALSE -DBUILD_MWINIIMPORTER=FALSE" build_command: "make" branch_pattern: coverity_scan matrix: From 3d3b37324d95e3e774e00db58d1e5e68e22035cb Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 11 Jul 2015 01:38:20 +0200 Subject: [PATCH 1785/3725] Change build targets again --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index a0a6f0746..80277f8ba 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,7 +18,7 @@ addons: name: "OpenMW/openmw" description: "" notification_email: scrawl@baseoftrash.de - build_command_prepend: "cmake . -DBUILD_UNITTESTS=FALSE -DBUILD_WIZARD=FALSE -DBUILD_LAUNCHER=FALSE -DBUILD_MWINIIMPORTER=FALSE" + build_command_prepend: "cmake . -DBUILD_UNITTESTS=FALSE -DBUILD_OPENCS=FALSE" build_command: "make" branch_pattern: coverity_scan matrix: From ebdd5dc9939b40aa3503b37dc9785b8206f810b1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 11 Jul 2015 03:06:53 +0200 Subject: [PATCH 1786/3725] Fix code that I forgot to uncomment (thanks coverity) --- apps/openmw/mwrender/npcanimation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 6252d392b..fc1a19391 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -459,7 +459,7 @@ void NpcAnimation::updateParts() }; static const size_t slotlistsize = sizeof(slotlist)/sizeof(slotlist[0]); - bool wasArrowAttached = 0;//(mAmmunition.get() != NULL); + bool wasArrowAttached = (mAmmunition.get() != NULL); MWWorld::InventoryStore& inv = mPtr.getClass().getInventoryStore(mPtr); for(size_t i = 0;i < slotlistsize && mViewMode != VM_HeadOnly;i++) From 667c80fb2acc4809493fc912e82a72e66797b461 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 11 Jul 2015 03:09:50 +0200 Subject: [PATCH 1787/3725] Add brackets around a correct expression to fix coverity warning --- apps/openmw/mwrender/npcanimation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index fc1a19391..6417bc812 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -622,7 +622,7 @@ void NpcAnimation::updateParts() continue; } - if (!mNpc->isMale() != (bodypart.mData.mFlags & ESM::BodyPart::BPF_Female)) + if ((!mNpc->isMale()) != (bodypart.mData.mFlags & ESM::BodyPart::BPF_Female)) { // Allow opposite gender's parts as fallback if parts for our gender are missing BodyPartMapType::const_iterator bIt = sBodyPartMap.lower_bound(BodyPartMapType::key_type(bodypart.mData.mPart)); From 24ae1d5acea04696ee3eec79c15ec0de90a49345 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 11 Jul 2015 03:33:31 +0200 Subject: [PATCH 1788/3725] Fix some issues found by coverity --- apps/essimporter/importer.cpp | 15 +++++++++++++++ apps/essimporter/importercontext.hpp | 4 ++++ apps/openmw/mwdialogue/filter.cpp | 2 ++ apps/openmw/mwgui/windowmanagerimp.cpp | 3 +++ apps/openmw/mwrender/ripplesimulation.hpp | 1 - components/myguiplatform/myguirendermanager.cpp | 2 +- components/nifosg/controller.cpp | 3 ++- 7 files changed, 27 insertions(+), 3 deletions(-) diff --git a/apps/essimporter/importer.cpp b/apps/essimporter/importer.cpp index 32ad1816c..27b70a06e 100644 --- a/apps/essimporter/importer.cpp +++ b/apps/essimporter/importer.cpp @@ -166,7 +166,9 @@ namespace ESSImport if (i >= file2.mRecords.size()) { + std::ios::fmtflags f(std::cout.flags()); std::cout << "Record in file1 not present in file2: (1) 0x" << std::hex << rec.mFileOffset << std::endl; + std::cout.flags(f); return; } @@ -174,7 +176,9 @@ namespace ESSImport if (rec.mName != rec2.mName) { + std::ios::fmtflags f(std::cout.flags()); std::cout << "Different record name at (2) 0x" << std::hex << rec2.mFileOffset << std::endl; + std::cout.flags(f); return; // TODO: try to recover } @@ -185,7 +189,9 @@ namespace ESSImport if (j >= rec2.mSubrecords.size()) { + std::ios::fmtflags f(std::cout.flags()); std::cout << "Subrecord in file1 not present in file2: (1) 0x" << std::hex << sub.mFileOffset << std::endl; + std::cout.flags(f); return; } @@ -193,8 +199,10 @@ namespace ESSImport if (sub.mName != sub2.mName) { + std::ios::fmtflags f(std::cout.flags()); std::cout << "Different subrecord name (" << rec.mName << "." << sub.mName << " vs. " << sub2.mName << ") at (1) 0x" << std::hex << sub.mFileOffset << " (2) 0x" << sub2.mFileOffset << std::endl; + std::cout.flags(f); break; // TODO: try to recover } @@ -203,6 +211,8 @@ namespace ESSImport if (blacklist.find(std::make_pair(rec.mName, sub.mName)) != blacklist.end()) continue; + std::ios::fmtflags f(std::cout.flags()); + std::cout << "Different subrecord data for " << rec.mName << "." << sub.mName << " at (1) 0x" << std::hex << sub.mFileOffset << " (2) 0x" << sub2.mFileOffset << std::endl; @@ -235,6 +245,7 @@ namespace ESSImport std::cout << "\033[0m"; } std::cout << std::endl; + std::cout.flags(f); } } } @@ -319,7 +330,11 @@ namespace ESSImport else { if (unknownRecords.insert(n.val).second) + { + std::ios::fmtflags f(std::cout.flags()); std::cerr << "unknown record " << n.toString() << " (0x" << std::hex << esm.getFileOffset() << ")" << std::endl; + std::cout.flags(f); + } esm.skipRecord(); } diff --git a/apps/essimporter/importercontext.hpp b/apps/essimporter/importercontext.hpp index 3b010cb8f..c93dff269 100644 --- a/apps/essimporter/importercontext.hpp +++ b/apps/essimporter/importercontext.hpp @@ -49,6 +49,10 @@ namespace ESSImport std::map mNpcs; Context() + : mDay(0) + , mMonth(0) + , mYear(0) + , mHour(0.f) { mPlayer.mAutoMove = 0; ESM::CellId playerCellId; diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index adb7d3892..29fac1c67 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -203,6 +203,8 @@ bool MWDialogue::Filter::testSelectStructNumeric (const SelectWrapper& select) c return false; // script does not have a variable of this name. int index = localDefs.getIndex (name); + if (index < 0) + return false; // shouldn't happen, we checked that variable has a type above, so must exist const MWScript::Locals& locals = mActor.getRefData().getLocals(); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 9cf957522..582519b19 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -896,6 +896,9 @@ namespace MWGui void WindowManager::updateMap() { + if (!mLocalMapRender) + return; + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); osg::Vec3f playerPosition = player.getRefData().getPosition().asVec3(); diff --git a/apps/openmw/mwrender/ripplesimulation.hpp b/apps/openmw/mwrender/ripplesimulation.hpp index 8e591a5db..1717cca57 100644 --- a/apps/openmw/mwrender/ripplesimulation.hpp +++ b/apps/openmw/mwrender/ripplesimulation.hpp @@ -59,7 +59,6 @@ namespace MWRender private: osg::ref_ptr mParent; - Resource::ResourceSystem* mResourceSystem; osg::ref_ptr mParticleSystem; osg::ref_ptr mParticleNode; diff --git a/components/myguiplatform/myguirendermanager.cpp b/components/myguiplatform/myguirendermanager.cpp index 89d55f5c1..160d659bd 100644 --- a/components/myguiplatform/myguirendermanager.cpp +++ b/components/myguiplatform/myguirendermanager.cpp @@ -119,7 +119,7 @@ class Drawable : public osg::Drawable { // VBOs disabled due to crash in OSG: http://forum.openscenegraph.org/viewtopic.php?t=14909 osg::GLBufferObject* bufferobject = 0;//state->isVertexBufferObjectSupported() ? vbo->getOrCreateGLBufferObject(state->getContextID()) : 0; - if (bufferobject) + if (0)//bufferobject) { state->bindVertexBufferObject(bufferobject); diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index 5e7e55004..83ecc0fa9 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -407,7 +407,8 @@ FlipController::FlipController(int texSlot, float delta, std::vector Date: Sat, 11 Jul 2015 04:27:35 +0200 Subject: [PATCH 1789/3725] Fix cout/cerr mixup --- apps/essimporter/importer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/essimporter/importer.cpp b/apps/essimporter/importer.cpp index 27b70a06e..624241039 100644 --- a/apps/essimporter/importer.cpp +++ b/apps/essimporter/importer.cpp @@ -331,9 +331,9 @@ namespace ESSImport { if (unknownRecords.insert(n.val).second) { - std::ios::fmtflags f(std::cout.flags()); + std::ios::fmtflags f(std::cerr.flags()); std::cerr << "unknown record " << n.toString() << " (0x" << std::hex << esm.getFileOffset() << ")" << std::endl; - std::cout.flags(f); + std::cerr.flags(f); } esm.skipRecord(); From b97a4cee44676ec44934dac69b1e16d2370492c1 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 11 Jul 2015 16:09:13 +0200 Subject: [PATCH 1790/3725] added button bar to script subview --- apps/opencs/view/world/scriptsubview.cpp | 61 ++++++++++++++++++------ apps/opencs/view/world/scriptsubview.hpp | 7 +++ 2 files changed, 54 insertions(+), 14 deletions(-) diff --git a/apps/opencs/view/world/scriptsubview.cpp b/apps/opencs/view/world/scriptsubview.cpp index 411eb3660..dc079c3a9 100644 --- a/apps/opencs/view/world/scriptsubview.cpp +++ b/apps/opencs/view/world/scriptsubview.cpp @@ -15,26 +15,20 @@ #include "../../model/settings/usersettings.hpp" #include "scriptedit.hpp" +#include "recordbuttonbar.hpp" CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) -: SubView (id), mDocument (document), mColumn (-1), mBottom(0), mStatus(0) +: SubView (id), mDocument (document), mColumn (-1), mBottom(0), mStatus(0), + mCommandDispatcher (document, CSMWorld::UniversalId::getParentType (id.getType())) { - QVBoxLayout *layout = new QVBoxLayout; - layout->setContentsMargins (QMargins (0, 0, 0, 0)); + std::vector selection (1, id.getId()); + mCommandDispatcher.setSelection (selection); - mBottom = new QWidget(this); - QStackedLayout *bottmLayout = new QStackedLayout(mBottom); - bottmLayout->setContentsMargins (0, 0, 0, 0); - QStatusBar *statusBar = new QStatusBar(mBottom); - mStatus = new QLabel(mBottom); - statusBar->addWidget (mStatus); - bottmLayout->addWidget (statusBar); - mBottom->setLayout (bottmLayout); + QVBoxLayout *layout = new QVBoxLayout; - layout->addWidget (mBottom, 0); - layout->insertWidget (0, mEditor = new ScriptEdit (mDocument, ScriptHighlighter::Mode_General, this), 2); + layout->addWidget (mEditor = new ScriptEdit (mDocument, ScriptHighlighter::Mode_General, this), 2); - QWidget *widget = new QWidget; + QWidget *widget = new QWidget (this);; widget->setLayout (layout); setWidget (widget); @@ -54,6 +48,25 @@ CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc: mEditor->setPlainText (mModel->data (mModel->getModelIndex (id.getId(), mColumn)).toString()); + // buttons + mButtons = new RecordButtonBar (id, *mModel, 0, &mCommandDispatcher, this); + + layout->addWidget (mButtons); + + // status bar + QStatusBar *statusBar = new QStatusBar(mBottom); + mStatus = new QLabel(mBottom); + statusBar->addWidget (mStatus); + + mBottom = new QWidget(this); + QStackedLayout *bottmLayout = new QStackedLayout(mBottom); + bottmLayout->setContentsMargins (0, 0, 0, 0); + bottmLayout->addWidget (statusBar); + mBottom->setLayout (bottmLayout); + + layout->addWidget (mBottom, 0); + + // signals connect (mEditor, SIGNAL (textChanged()), this, SLOT (textChanged())); connect (mModel, SIGNAL (dataChanged (const QModelIndex&, const QModelIndex&)), @@ -62,6 +75,11 @@ CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc: connect (mModel, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)), this, SLOT (rowsAboutToBeRemoved (const QModelIndex&, int, int))); + connect (mButtons, SIGNAL (switchToRow (int)), this, SLOT (switchToRow (int))); + + connect (this, SIGNAL (universalIdChanged (const CSMWorld::UniversalId&)), + mButtons, SLOT (universalIdChanged (const CSMWorld::UniversalId&))); + updateStatusBar(); connect(mEditor, SIGNAL(cursorPositionChanged()), this, SLOT(updateStatusBar())); } @@ -78,6 +96,8 @@ void CSVWorld::ScriptSubView::updateUserSetting (const QString& name, const QStr { mEditor->setMonoFont(value.at(0).toStdString() == "true"); } + + mButtons->updateUserSetting (name, value); } void CSVWorld::ScriptSubView::updateStatusBar () @@ -93,6 +113,8 @@ void CSVWorld::ScriptSubView::updateStatusBar () void CSVWorld::ScriptSubView::setEditLock (bool locked) { mEditor->setReadOnly (locked); + mButtons->setEditLock (locked); + mCommandDispatcher.setEditLock (locked); } void CSVWorld::ScriptSubView::useHint (const std::string& hint) @@ -159,3 +181,14 @@ void CSVWorld::ScriptSubView::rowsAboutToBeRemoved (const QModelIndex& parent, i emit closeRequest(); } +void CSVWorld::ScriptSubView::switchToRow (int row) +{ + int idColumn = mModel->findColumnIndex (CSMWorld::Columns::ColumnId_Id); + std::string id = mModel->data (mModel->index (row, idColumn)).toString().toUtf8().constData(); + setUniversalId (CSMWorld::UniversalId (CSMWorld::UniversalId::Type_Script, id)); + + mEditor->setPlainText (mModel->data (mModel->index (row, mColumn)).toString()); + + std::vector selection (1, id); + mCommandDispatcher.setSelection (selection); +} diff --git a/apps/opencs/view/world/scriptsubview.hpp b/apps/opencs/view/world/scriptsubview.hpp index 1c6474e54..0479e6ad8 100644 --- a/apps/opencs/view/world/scriptsubview.hpp +++ b/apps/opencs/view/world/scriptsubview.hpp @@ -1,6 +1,8 @@ #ifndef CSV_WORLD_SCRIPTSUBVIEW_H #define CSV_WORLD_SCRIPTSUBVIEW_H +#include "../../model/world/commanddispatcher.hpp" + #include "../doc/subview.hpp" class QModelIndex; @@ -19,6 +21,7 @@ namespace CSMWorld namespace CSVWorld { class ScriptEdit; + class RecordButtonBar; class ScriptSubView : public CSVDoc::SubView { @@ -30,6 +33,8 @@ namespace CSVWorld int mColumn; QWidget *mBottom; QLabel *mStatus; + RecordButtonBar *mButtons; + CSMWorld::CommandDispatcher mCommandDispatcher; public: @@ -52,6 +57,8 @@ namespace CSVWorld private slots: void updateStatusBar(); + + void switchToRow (int row); }; } From e0983c815c32c9b79d340100ab2b4b6750820554 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sat, 11 Jul 2015 22:17:53 +0300 Subject: [PATCH 1791/3725] Some fixes for ESM Dialogues and Infos --- apps/openmw/mwworld/store.hpp | 3 ++- components/esm/loaddial.cpp | 2 ++ components/esm/loaddial.hpp | 3 ++- components/esm/loadinfo.cpp | 3 +++ 4 files changed, 9 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index c482486d8..ff0ca0159 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -371,7 +371,8 @@ namespace MWWorld } else { - found->second = dialogue; + found->second.mIsDeleted = dialogue.mIsDeleted; + found->second.mType = dialogue.mType; } mLastAddedRecord = dialogue; diff --git a/components/esm/loaddial.cpp b/components/esm/loaddial.cpp index 667afc75c..aeec46872 100644 --- a/components/esm/loaddial.cpp +++ b/components/esm/loaddial.cpp @@ -32,6 +32,7 @@ namespace ESM int32_t empty; esm.getT(empty); // Skip an empty DATA mIsDeleted = readDeleSubRecord(esm); + mType = Unknown; } else esm.fail("Unknown sub record size"); @@ -54,6 +55,7 @@ namespace ESM void Dialogue::blank() { mInfo.clear(); + mIsDeleted = false; } void Dialogue::readInfo(ESMReader &esm, bool merge) diff --git a/components/esm/loaddial.hpp b/components/esm/loaddial.hpp index 5e7d09871..8fc7e14e9 100644 --- a/components/esm/loaddial.hpp +++ b/components/esm/loaddial.hpp @@ -30,7 +30,8 @@ struct Dialogue Voice = 1, Greeting = 2, Persuasion = 3, - Journal = 4 + Journal = 4, + Unknown = -1 // Used for deleted dialogues }; std::string mId; diff --git a/components/esm/loadinfo.cpp b/components/esm/loadinfo.cpp index 4c997213a..c1b12e24c 100644 --- a/components/esm/loadinfo.cpp +++ b/components/esm/loadinfo.cpp @@ -17,6 +17,7 @@ namespace ESM { mQuestStatus = QS_None; mFactionLess = false; + mIsDeleted = false; mPrev = esm.getHNString("PNAM"); mNext = esm.getHNString("NNAM"); @@ -142,6 +143,7 @@ namespace ESM { esm.writeHNCString("PNAM", mPrev); esm.writeHNCString("NNAM", mNext); + if (mIsDeleted) { esm.writeHNCString("NAME", mResponse); @@ -200,5 +202,6 @@ namespace ESM mResultScript.clear(); mFactionLess = false; mQuestStatus = QS_None; + mIsDeleted = false; } } From adec0cb61df161e4bb25d0387d7a1ecde21363cb Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sun, 12 Jul 2015 00:19:04 +0300 Subject: [PATCH 1792/3725] Add removing of deleted Infos to Dialogue::clearDeletedInfos() --- components/esm/loaddial.cpp | 2 +- components/esm/loaddial.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/components/esm/loaddial.cpp b/components/esm/loaddial.cpp index aeec46872..dfac0ce63 100644 --- a/components/esm/loaddial.cpp +++ b/components/esm/loaddial.cpp @@ -133,7 +133,7 @@ namespace ESM { for (InfoContainer::iterator it = mInfo.begin(); it != mInfo.end(); ) { - if (it->mQuestStatus == DialInfo::QS_Deleted) + if (it->mIsDeleted || it->mQuestStatus == DialInfo::QS_Deleted) it = mInfo.erase(it); else ++it; diff --git a/components/esm/loaddial.hpp b/components/esm/loaddial.hpp index 8fc7e14e9..e80a7b0b2 100644 --- a/components/esm/loaddial.hpp +++ b/components/esm/loaddial.hpp @@ -53,7 +53,7 @@ struct Dialogue void load(ESMReader &esm); void save(ESMWriter &esm) const; - /// Remove all INFOs marked as QS_Deleted from mInfos. + /// Remove all INFOs that are deleted or marked as QS_Deleted from mInfos. void clearDeletedInfos(); /// Read the next info record From 27a4af26abdb65e32eed89af1f2ca3d8b6cedc61 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Sun, 12 Jul 2015 00:45:42 +0200 Subject: [PATCH 1793/3725] Cleaning up AppVeyor scripts --- CI/before_script.msvc.sh | 401 ++++++++++++++++++++------------------- appveyor.yml | 31 +-- 2 files changed, 221 insertions(+), 211 deletions(-) diff --git a/CI/before_script.msvc.sh b/CI/before_script.msvc.sh index 0d72806fb..d23e3013f 100644 --- a/CI/before_script.msvc.sh +++ b/CI/before_script.msvc.sh @@ -124,6 +124,11 @@ add_runtime_dlls() { RUNTIME_DLLS="$RUNTIME_DLLS $@" } +OSG_PLUGINS="" +add_osg_dlls() { + OSG_PLUGINS="$OSG_PLUGINS $@" +} + if [ -z $PLATFORM ]; then PLATFORM=`uname -m` fi @@ -250,270 +255,274 @@ mkdir -p Build_$BITS/deps cd Build_$BITS/deps DEPS_INSTALL=`pwd` +cd $DEPS echo echo "Extracting dependencies..." # Boost -if [ -z $APPVEYOR ]; then - printf "Boost 1.58.0... " - cd $DEPS_INSTALL +printf "Boost 1.58.0... " +{ + if [ -z $APPVEYOR ]; then + cd $DEPS_INSTALL - BOOST_SDK="`real_pwd`/Boost" + BOOST_SDK="`real_pwd`/Boost" - if [ -d Boost ] && grep "BOOST_VERSION 105800" Boost/boost/version.hpp > /dev/null; then - printf "Exists. " - elif [ -z $SKIP_EXTRACT ]; then - rm -rf Boost - $DEPS/boost-1.58.0-win$BITS.exe //dir="$(echo $BOOST_SDK | sed s,/,\\\\,g)" //verysilent - fi - - add_cmake_opts -DBOOST_ROOT="$BOOST_SDK" \ - -DBOOST_LIBRARYDIR="$BOOST_SDK/lib$BITS-msvc-12.0" + if [ -d Boost ] && grep "BOOST_VERSION 105800" Boost/boost/version.hpp > /dev/null; then + printf "Exists. " + elif [ -z $SKIP_EXTRACT ]; then + rm -rf Boost + $DEPS/boost-1.58.0-win$BITS.exe //dir="$(echo $BOOST_SDK | sed s,/,\\\\,g)" //verysilent + fi - cd $DEPS + add_cmake_opts -DBOOST_ROOT="$BOOST_SDK" \ + -DBOOST_LIBRARYDIR="$BOOST_SDK/lib$BITS-msvc-12.0" - echo Done. -else - # Appveyor unstable has all the boost we need already - BOOST_SDK="c:/Libraries/boost" - add_cmake_opts -DBOOST_ROOT="$BOOST_SDK" \ - -DBOOST_LIBRARYDIR="$BOOST_SDK/lib$BITS-msvc-12.0" -fi + echo Done. + else + # Appveyor unstable has all the boost we need already + BOOST_SDK="c:/Libraries/boost" + add_cmake_opts -DBOOST_ROOT="$BOOST_SDK" \ + -DBOOST_LIBRARYDIR="$BOOST_SDK/lib$BITS-msvc-12.0" + echo AppVeyor. + fi +} +cd $DEPS # Bullet printf "Bullet 2.83.5... " -cd $DEPS_INSTALL - -if [ -d Bullet ]; then - printf "Exists. (No version checking) " -elif [ -z $SKIP_EXTRACT ]; then - rm -rf Bullet - eval 7z x -y $DEPS/Bullet-2.83.5-win$BITS.7z $STRIP - mv Bullet-2.83.5-win$BITS Bullet -fi - -BULLET_SDK="`real_pwd`/Bullet" -add_cmake_opts -DBULLET_INCLUDE_DIR="$BULLET_SDK/include/bullet" \ - -DBULLET_COLLISION_LIBRARY="$BULLET_SDK/lib/BulletCollision.lib" \ - -DBULLET_COLLISION_LIBRARY_DEBUG="$BULLET_SDK/lib/BulletCollision_Debug.lib" \ - -DBULLET_DYNAMICS_LIBRARY="$BULLET_SDK/lib/BulletDynamics.lib" \ - -DBULLET_DYNAMICS_LIBRARY_DEBUG="$BULLET_SDK/lib/BulletDynamics_Debug.lib" \ - -DBULLET_MATH_LIBRARY="$BULLET_SDK/lib/LinearMath.lib" \ - -DBULLET_MATH_LIBRARY_DEBUG="$BULLET_SDK/lib/LinearMath_Debug.lib" +{ + cd $DEPS_INSTALL -cd $DEPS + if [ -d Bullet ]; then + printf "Exists. (No version checking) " + elif [ -z $SKIP_EXTRACT ]; then + rm -rf Bullet + eval 7z x -y $DEPS/Bullet-2.83.5-win$BITS.7z $STRIP + mv Bullet-2.83.5-win$BITS Bullet + fi -echo Done. + BULLET_SDK="`real_pwd`/Bullet" + add_cmake_opts -DBULLET_INCLUDE_DIR="$BULLET_SDK/include/bullet" \ + -DBULLET_COLLISION_LIBRARY="$BULLET_SDK/lib/BulletCollision.lib" \ + -DBULLET_COLLISION_LIBRARY_DEBUG="$BULLET_SDK/lib/BulletCollision_Debug.lib" \ + -DBULLET_MATH_LIBRARY="$BULLET_SDK/lib/LinearMath.lib" \ + -DBULLET_MATH_LIBRARY_DEBUG="$BULLET_SDK/lib/LinearMath_Debug.lib" + echo Done. +} +cd $DEPS # FFmpeg printf "FFmpeg 2.5.2... " -cd $DEPS_INSTALL +{ + cd $DEPS_INSTALL -if [ -d FFmpeg ] && grep "FFmpeg version: 2.5.2" FFmpeg/README.txt > /dev/null; then - printf "Exists. " -elif [ -z $SKIP_EXTRACT ]; then - rm -rf FFmpeg + if [ -d FFmpeg ] && grep "FFmpeg version: 2.5.2" FFmpeg/README.txt > /dev/null; then + printf "Exists. " + elif [ -z $SKIP_EXTRACT ]; then + rm -rf FFmpeg - eval 7z x -y $DEPS/ffmpeg$BITS-2.5.2.7z $STRIP - eval 7z x -y $DEPS/ffmpeg$BITS-2.5.2-dev.7z $STRIP + eval 7z x -y $DEPS/ffmpeg$BITS-2.5.2.7z $STRIP + eval 7z x -y $DEPS/ffmpeg$BITS-2.5.2-dev.7z $STRIP - mv ffmpeg-2.5.2-win$BITS-shared FFmpeg - cp -r ffmpeg-2.5.2-win$BITS-dev/* FFmpeg/ - rm -rf ffmpeg-2.5.2-win$BITS-dev -fi + mv ffmpeg-2.5.2-win$BITS-shared FFmpeg + cp -r ffmpeg-2.5.2-win$BITS-dev/* FFmpeg/ + rm -rf ffmpeg-2.5.2-win$BITS-dev + fi -FFMPEG_SDK="`real_pwd`/FFmpeg" -add_cmake_opts -DAVCODEC_INCLUDE_DIRS="$FFMPEG_SDK/include" \ - -DAVCODEC_LIBRARIES="$FFMPEG_SDK/lib/avcodec.lib" \ - -DAVDEVICE_INCLUDE_DIRS="$FFMPEG_SDK/include" \ - -DAVDEVICE_LIBRARIES="$FFMPEG_SDK/lib/avdevice.lib" \ - -DAVFORMAT_INCLUDE_DIRS="$FFMPEG_SDK/include" \ - -DAVFORMAT_LIBRARIES="$FFMPEG_SDK/lib/avformat.lib" \ - -DAVUTIL_INCLUDE_DIRS="$FFMPEG_SDK/include" \ - -DAVUTIL_LIBRARIES="$FFMPEG_SDK/lib/avutil.lib" \ - -DPOSTPROC_INCLUDE_DIRS="$FFMPEG_SDK/include" \ - -DPOSTPROC_LIBRARIES="$FFMPEG_SDK/lib/postproc.lib" \ - -DSWRESAMPLE_INCLUDE_DIRS="$FFMPEG_SDK/include" \ - -DSWRESAMPLE_LIBRARIES="$FFMPEG_SDK/lib/swresample.lib" \ - -DSWSCALE_INCLUDE_DIRS="$FFMPEG_SDK/include" \ - -DSWSCALE_LIBRARIES="$FFMPEG_SDK/lib/swscale.lib" - -add_runtime_dlls `pwd`/FFmpeg/bin/{avcodec-56,avformat-56,avutil-54,swresample-1,swscale-3}.dll - -if [ $BITS -eq 32 ]; then - add_cmake_opts "-DCMAKE_EXE_LINKER_FLAGS=\"/machine:X86 /safeseh:no\"" -fi + FFMPEG_SDK="`real_pwd`/FFmpeg" + add_cmake_opts -DAVCODEC_INCLUDE_DIRS="$FFMPEG_SDK/include" \ + -DAVCODEC_LIBRARIES="$FFMPEG_SDK/lib/avcodec.lib" \ + -DAVDEVICE_INCLUDE_DIRS="$FFMPEG_SDK/include" \ + -DAVDEVICE_LIBRARIES="$FFMPEG_SDK/lib/avdevice.lib" \ + -DAVFORMAT_INCLUDE_DIRS="$FFMPEG_SDK/include" \ + -DAVFORMAT_LIBRARIES="$FFMPEG_SDK/lib/avformat.lib" \ + -DAVUTIL_INCLUDE_DIRS="$FFMPEG_SDK/include" \ + -DAVUTIL_LIBRARIES="$FFMPEG_SDK/lib/avutil.lib" \ + -DPOSTPROC_INCLUDE_DIRS="$FFMPEG_SDK/include" \ + -DPOSTPROC_LIBRARIES="$FFMPEG_SDK/lib/postproc.lib" \ + -DSWRESAMPLE_INCLUDE_DIRS="$FFMPEG_SDK/include" \ + -DSWRESAMPLE_LIBRARIES="$FFMPEG_SDK/lib/swresample.lib" \ + -DSWSCALE_INCLUDE_DIRS="$FFMPEG_SDK/include" \ + -DSWSCALE_LIBRARIES="$FFMPEG_SDK/lib/swscale.lib" + + add_runtime_dlls `pwd`/FFmpeg/bin/{avcodec-56,avformat-56,avutil-54,swresample-1,swscale-3}.dll + + if [ $BITS -eq 32 ]; then + add_cmake_opts "-DCMAKE_EXE_LINKER_FLAGS=\"/machine:X86 /safeseh:no\"" + fi + echo Done. +} cd $DEPS -echo Done. - - # MyGUI printf "MyGUI 3.2.2... " -cd $DEPS_INSTALL - -if [ -d MyGUI ] && \ - grep "MYGUI_VERSION_MAJOR 3" MyGUI/include/MYGUI/MyGUI_Prerequest.h > /dev/null && \ - grep "MYGUI_VERSION_MINOR 2" MyGUI/include/MYGUI/MyGUI_Prerequest.h > /dev/null && \ - grep "MYGUI_VERSION_PATCH 2" MyGUI/include/MYGUI/MyGUI_Prerequest.h > /dev/null -then - printf "Exists. " -elif [ -z $SKIP_EXTRACT ]; then - rm -rf MyGUI - eval 7z x -y $DEPS/MyGUI-3.2.2-win$BITS.7z $STRIP - mv MyGUI-3.2.2-win$BITS MyGUI -fi - -MYGUI_SDK="`real_pwd`/MyGUI" +{ + cd $DEPS_INSTALL -add_cmake_opts -DMYGUISDK="$MYGUI_SDK" \ - -DMYGUI_INCLUDE_DIRS="$MYGUI_SDK/include/MYGUI" \ - -DMYGUI_PREQUEST_FILE="$MYGUI_SDK/include/MYGUI/MyGUI_Prerequest.h" + if [ -d MyGUI ] && \ + grep "MYGUI_VERSION_MAJOR 3" MyGUI/include/MYGUI/MyGUI_Prerequest.h > /dev/null && \ + grep "MYGUI_VERSION_MINOR 2" MyGUI/include/MYGUI/MyGUI_Prerequest.h > /dev/null && \ + grep "MYGUI_VERSION_PATCH 2" MyGUI/include/MYGUI/MyGUI_Prerequest.h > /dev/null + then + printf "Exists. " + elif [ -z $SKIP_EXTRACT ]; then + rm -rf MyGUI + eval 7z x -y $DEPS/MyGUI-3.2.2-win$BITS.7z $STRIP + mv MyGUI-3.2.2-win$BITS MyGUI + fi -if [ $CONFIGURATION == "Debug" ]; then - SUFFIX="_d" -else - SUFFIX="" -fi -add_runtime_dlls `pwd`/MyGUI/bin/$CONFIGURATION/MyGUIEngine$SUFFIX.dll + MYGUI_SDK="`real_pwd`/MyGUI" -cd $DEPS + add_cmake_opts -DMYGUISDK="$MYGUI_SDK" \ + -DMYGUI_INCLUDE_DIRS="$MYGUI_SDK/include/MYGUI" \ + -DMYGUI_PREQUEST_FILE="$MYGUI_SDK/include/MYGUI/MyGUI_Prerequest.h" -echo Done. + if [ $CONFIGURATION == "Debug" ]; then + SUFFIX="_d" + else + SUFFIX="" + fi + add_runtime_dlls `pwd`/MyGUI/bin/$CONFIGURATION/MyGUIEngine$SUFFIX.dll + echo Done. +} +cd $DEPS # OpenAL printf "OpenAL-Soft 1.16.0... " -if [ -d openal-soft-1.16.0-bin ]; then - printf "Exists. " -elif [ -z $SKIP_EXTRACT ]; then - rm -rf openal-soft-1.16.0-bin - eval 7z x -y OpenAL-Soft-1.16.0.zip $STRIP -fi - -OPENAL_SDK="`real_pwd`/openal-soft-1.16.0-bin" +{ + if [ -d openal-soft-1.16.0-bin ]; then + printf "Exists. " + elif [ -z $SKIP_EXTRACT ]; then + rm -rf openal-soft-1.16.0-bin + eval 7z x -y OpenAL-Soft-1.16.0.zip $STRIP + fi -add_cmake_opts -DOPENAL_INCLUDE_DIR="$OPENAL_SDK/include/AL" \ - -DOPENAL_LIBRARY="$OPENAL_SDK/libs/Win$BITS/OpenAL32.lib" + OPENAL_SDK="`real_pwd`/openal-soft-1.16.0-bin" -echo Done. + add_cmake_opts -DOPENAL_INCLUDE_DIR="$OPENAL_SDK/include/AL" \ + -DOPENAL_LIBRARY="$OPENAL_SDK/libs/Win$BITS/OpenAL32.lib" + echo Done. +} +cd $DEPS # OSG printf "OSG 3.3.8... " -cd $DEPS_INSTALL - -if [ -d OSG ] && \ - grep "OPENSCENEGRAPH_MAJOR_VERSION 3" OSG/include/osg/Version > /dev/null && \ - grep "OPENSCENEGRAPH_MINOR_VERSION 3" OSG/include/osg/Version > /dev/null && \ - grep "OPENSCENEGRAPH_PATCH_VERSION 8" OSG/include/osg/Version > /dev/null -then - printf "Exists. " -elif [ -z $SKIP_EXTRACT ]; then - rm -rf OSG - eval 7z x -y $DEPS/OSG-3.3.8-win$BITS.7z $STRIP - mv OSG-3.3.8-win$BITS OSG -fi - -OSG_SDK="`real_pwd`/OSG" +{ + cd $DEPS_INSTALL -add_cmake_opts -DOSG_DIR="$OSG_SDK" + if [ -d OSG ] && \ + grep "OPENSCENEGRAPH_MAJOR_VERSION 3" OSG/include/osg/Version > /dev/null && \ + grep "OPENSCENEGRAPH_MINOR_VERSION 3" OSG/include/osg/Version > /dev/null && \ + grep "OPENSCENEGRAPH_PATCH_VERSION 8" OSG/include/osg/Version > /dev/null + then + printf "Exists. " + elif [ -z $SKIP_EXTRACT ]; then + rm -rf OSG + eval 7z x -y $DEPS/OSG-3.3.8-win$BITS.7z $STRIP + mv OSG-3.3.8-win$BITS OSG + fi -if [ $CONFIGURATION == "Debug" ]; then - SUFFIX="d" -else - SUFFIX="" -fi -add_runtime_dlls `pwd`/OSG/bin/{OpenThreads,zlib}$SUFFIX.dll \ - `pwd`/OSG/bin/osg{,Animation,DB,FX,GA,Particle,Qt,Text,Util,Viewer}$SUFFIX.dll + OSG_SDK="`real_pwd`/OSG" -OSG_PLUGINS="" -add_osg_dlls() { - OSG_PLUGINS="$OSG_PLUGINS $@" -} + add_cmake_opts -DOSG_DIR="$OSG_SDK" -add_osg_dlls `pwd`/OSG/bin/osgPlugins-3.3.8/osgdb_{bmp,dds,gif,jpeg,png,tga}$SUFFIX.dll + if [ $CONFIGURATION == "Debug" ]; then + SUFFIX="d" + else + SUFFIX="" + fi -cd $DEPS + add_runtime_dlls `pwd`/OSG/bin/{OpenThreads,zlib}$SUFFIX.dll \ + `pwd`/OSG/bin/osg{,Animation,DB,FX,GA,Particle,Qt,Text,Util,Viewer}$SUFFIX.dll -echo Done. + add_osg_dlls `pwd`/OSG/bin/osgPlugins-3.3.8/osgdb_{bmp,dds,gif,jpeg,png,tga}$SUFFIX.dll + echo Done. +} +cd $DEPS # Qt if [ -z $APPVEYOR ]; then printf "Qt 4.8.6... " - cd $DEPS_INSTALL +else + printf "Qt 5.4... " +fi +{ + if [ -z $APPVEYOR ]; then + cd $DEPS_INSTALL + QT_SDK="`real_pwd`/Qt" + + if [ -d Qt ] && head -n2 Qt/BUILDINFO.txt | grep "4.8.6" > /dev/null; then + printf "Exists. " + elif [ -z $SKIP_EXTRACT ]; then + rm -rf Qt + eval 7z x -y $DEPS/qt$BITS-4.8.6.7z $STRIP + mv qt-4.8.6-* Qt + ( + cd $QT_SDK + eval qtbinpatcher.exe $STRIP + ) + fi - if [ -d Qt ] && head -n2 Qt/BUILDINFO.txt | grep "4.8.6" > /dev/null; then - printf "Exists. " - elif [ -z $SKIP_EXTRACT ]; then - rm -rf Qt - eval 7z x -y $DEPS/qt$BITS-4.8.6.7z $STRIP - mv qt-4.8.6-* Qt - fi + cd $QT_SDK - QT_SDK="`real_pwd`/Qt" + add_cmake_opts -DDESIRED_QT_VERSION=4 \ + -DQT_QMAKE_EXECUTABLE="$QT_SDK/bin/qmake.exe" - cd $QT_SDK - eval qtbinpatcher.exe $STRIP + if [ $CONFIGURATION == "Debug" ]; then + SUFFIX="d4" + else + SUFFIX="4" + fi - add_cmake_opts -DDESIRED_QT_VERSION=4 \ - -DQT_QMAKE_EXECUTABLE="$QT_SDK/bin/qmake.exe" + add_runtime_dlls `pwd`/bin/Qt{Core,Gui,Network,OpenGL}$SUFFIX.dll - if [ $CONFIGURATION == "Debug" ]; then - SUFFIX="d4" + echo Done. else - SUFFIX="4" - fi - add_runtime_dlls `pwd`/bin/Qt{Core,Gui,Network,OpenGL}$SUFFIX.dll - - cd $DEPS + if [ $BITS -eq 32 ]; then + QT_SDK="C:/Qt/5.4/msvc2013_opengl" + else + QT_SDK="C:/Qt/5.4/msvc2013_64_opengl" + fi - echo Done. -else - echo "Using Appveyor Qt 5 version." - if [ $PLATFORM == "win32" ]; then - QT_SDK="C:/Qt/5.4/msvc2013_opengl" - else - QT_SDK="C:/Qt/5.4/msvc2013_64_opengl" + add_cmake_opts -DDESIRED_QT_VERSION=5 \ + -DQT_QMAKE_EXECUTABLE="$QT_SDK/bin/qmake.exe" \ + -DCMAKE_PREFIX_PATH="$QT_SDK" fi - - add_cmake_opts -DDESIRED_QT_VERSION=5 \ - -DQT_QMAKE_EXECUTABLE="$QT_SDK/bin/qmake.exe" \ - -DCMAKE_PREFIX_PATH="$QT_SDK" -fi - +} +cd $DEPS # SDL2 printf "SDL 2.0.3... " +{ + if [ -d SDL2-2.0.3 ]; then + printf "Exists. " + elif [ -z $SKIP_EXTRACT ]; then + rm -rf SDL2-2.0.3 + eval 7z x -y SDL2-2.0.3.zip $STRIP + fi -if [ -d SDL2-2.0.3 ]; then - printf "Exists. " -elif [ -z $SKIP_EXTRACT ]; then - rm -rf SDL2-2.0.3 - eval 7z x -y SDL2-2.0.3.zip $STRIP -fi - -SDL_SDK="`real_pwd`/SDL2-2.0.3" -add_cmake_opts -DSDL2_INCLUDE_DIR="$SDL_SDK/include" \ - -DSDL2MAIN_LIBRARY="$SDL_SDK/lib/x$ARCHSUFFIX/SDL2main.lib" \ - -DSDL2_LIBRARY_PATH="$SDL_SDK/lib/x$ARCHSUFFIX/SDL2.lib" \ - -DSDL2_LIBRARY_ONLY="$SDL_SDK/lib/x$ARCHSUFFIX/SDL2.lib" + SDL_SDK="`real_pwd`/SDL2-2.0.3" + add_cmake_opts -DSDL2_INCLUDE_DIR="$SDL_SDK/include" \ + -DSDL2MAIN_LIBRARY="$SDL_SDK/lib/x$ARCHSUFFIX/SDL2main.lib" \ + -DSDL2_LIBRARY_PATH="$SDL_SDK/lib/x$ARCHSUFFIX/SDL2.lib" -add_runtime_dlls `pwd`/SDL2-2.0.3/lib/x$ARCHSUFFIX/SDL2.dll + add_runtime_dlls `pwd`/SDL2-2.0.3/lib/x$ARCHSUFFIX/SDL2.dll -cd $DEPS + echo Done. +} -echo Done. -echo cd $DEPS_INSTALL/.. +echo echo "Setting up OpenMW build..." add_cmake_opts -DBUILD_BSATOOL=no \ @@ -521,8 +530,8 @@ add_cmake_opts -DBUILD_BSATOOL=no \ -DBUILD_MYGUI_PLUGIN=no \ -DOPENMW_MP_BUILD=on -if [ -z $APPVEYOR ]; then - echo " (Outside of AppVeyor, doing full build.)" +if [ -z $CI ]; then + echo " (Outside of CI, doing full build.)" else case $STEP in components ) @@ -533,7 +542,6 @@ else -DBUILD_OPENCS=no \ -DBUILD_OPENMW=no \ -DBUILD_WIZARD=no - rm -rf components ;; openmw ) echo " Subproject: OpenMW." @@ -575,7 +583,8 @@ fi echo -if [ -z $APPVEYOR ]; then +# NOTE: Disable this when/if we want to run test cases +if [ -z $CI ]; then echo "Copying Runtime DLLs..." mkdir -p $CONFIGURATION for DLL in $RUNTIME_DLLS; do diff --git a/appveyor.yml b/appveyor.yml index 926aaff68..d5ad13430 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,17 +1,22 @@ version: "{build}" +branches: + only: + - appveyor + platform: - Win32 - x64 -configuration: - - Debug +configuration: Debug environment: matrix: - - STEP: openmw - - STEP: opencs - - STEP: misc + - STEP: misc +# - STEP: components # misc builds this too +# Build takes too long for these, ignore for now +# - STEP: openmw +# - STEP: opencs matrix: fast_finish: true @@ -32,18 +37,14 @@ cache: - C:\projects\openmw\deps\ffmpeg64-2.5.2.7z - C:\projects\openmw\deps\ffmpeg64-2.5.2-dev.7z -init: - - cmd: bash --version - - cmd: cmake --version - - cmd: msbuild /version - - cmd: echo. - clone_folder: C:\projects\openmw -build_script: - - cmd: bash --login C:\projects\openmw\CI\build.msvc.sh - before_build: - - cmd: bash --login C:\projects\openmw\CI\before_script.msvc.sh + - cmd: sh %APPVEYOR_BUILD_FOLDER%\CI\before_script.msvc.sh + +build_script: + - cmd: if %PLATFORM%==Win32 set build=Build_32 + - cmd: if %PLATFORM%==x64 set build=Build_64 + - cmd: msbuild %build%\OpenMW.sln /t:Build /p:Configuration=%configuration% /m:2 /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" test: off From b508846a644f58264f84fb1a041f56d133260f65 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 12 Jul 2015 16:32:48 +1200 Subject: [PATCH 1794/3725] Renamed mStoredAvailableNodes to mPopulateAvailableNodes. Don't call getAllowedNodes() needlessly. --- apps/openmw/mwmechanics/aiwander.cpp | 13 +++++++------ apps/openmw/mwmechanics/aiwander.hpp | 4 ++-- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 4aef8f8ba..3da02306b 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -117,7 +117,7 @@ namespace MWMechanics mStartTime = MWBase::Environment::get().getWorld()->getTimeStamp(); - mStoredAvailableNodes = false; + mPopulateAvailableNodes = true; } @@ -191,7 +191,7 @@ namespace MWMechanics if(!currentCell || cellChange) { currentCell = actor.getCell(); - mStoredAvailableNodes = false; // prob. not needed since mDistance = 0 + mPopulateAvailableNodes = true; } cStats.setDrawState(DrawState_Nothing); @@ -390,7 +390,7 @@ namespace MWMechanics } // Initialization to discover & store allowed node points for this actor. - if(!mStoredAvailableNodes) + if (mPopulateAvailableNodes) { getAllowedNodes(actor, currentCell->getCell()); } @@ -640,7 +640,7 @@ namespace MWMechanics if (mDistance == 0) return; - if (!mStoredAvailableNodes) + if (mPopulateAvailableNodes) getAllowedNodes(actor, actor.getCell()->getCell()); if (mAllowedNodes.empty()) @@ -660,7 +660,7 @@ namespace MWMechanics actor.getClass().adjustPosition(actor, false); // may have changed cell - mStoredAvailableNodes = false; + mPopulateAvailableNodes = true; } int AiWander::OffsetToPreventOvercrowding() @@ -722,8 +722,9 @@ namespace MWMechanics { SetCurrentNodeToClosestAllowedNode(npcPos); } - mStoredAvailableNodes = true; // set only if successful in finding allowed nodes } + + mPopulateAvailableNodes = false; } // When only one path grid point in wander distance, diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 926017b46..fb1ed0b7e 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -88,8 +88,8 @@ namespace MWMechanics - // if false triggers calculating allowed nodes based on mDistance - bool mStoredAvailableNodes; + // do we need to calculate allowed nodes based on mDistance + bool mPopulateAvailableNodes; From df421fce9265cee142eee278610f927a466b40fb Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 12 Jul 2015 16:35:15 +1200 Subject: [PATCH 1795/3725] extracted function setPathToAnAllowedNode() --- apps/openmw/mwmechanics/aiwander.cpp | 61 ++++++++++++++++------------ apps/openmw/mwmechanics/aiwander.hpp | 1 + 2 files changed, 35 insertions(+), 27 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 3da02306b..17d125209 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -504,41 +504,48 @@ namespace MWMechanics // Construct a new path if there isn't one if(!storage.mPathFinder.isPathConstructed()) { - assert(mAllowedNodes.size()); - unsigned int randNode = Misc::Rng::rollDice(mAllowedNodes.size()); - ESM::Pathgrid::Point dest(mAllowedNodes[randNode]); - ToWorldCoordinates(dest, currentCell->getCell()); - - // actor position is already in world co-ordinates - ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(pos)); - - // don't take shortcuts for wandering - storage.mPathFinder.buildSyncedPath(start, dest, actor.getCell(), false); - - if(storage.mPathFinder.isPathConstructed()) + if (mAllowedNodes.size()) { - // Remove this node as an option and add back the previously used node (stops NPC from picking the same node): - ESM::Pathgrid::Point temp = mAllowedNodes[randNode]; - mAllowedNodes.erase(mAllowedNodes.begin() + randNode); - // check if mCurrentNode was taken out of mAllowedNodes - if(mTrimCurrentNode && mAllowedNodes.size() > 1) - mTrimCurrentNode = false; - else - mAllowedNodes.push_back(mCurrentNode); - mCurrentNode = temp; - - moveNow = false; - walking = true; + setPathToAnAllowedNode(actor, storage, pos); } - // Choose a different node and delete this one from possible nodes because it is uncreachable: - else - mAllowedNodes.erase(mAllowedNodes.begin() + randNode); } } return false; // AiWander package not yet completed } + void AiWander::setPathToAnAllowedNode(const MWWorld::Ptr& actor, AiWanderStorage& storage, const ESM::Position& actorPos) + { + unsigned int randNode = Misc::Rng::rollDice(mAllowedNodes.size()); + ESM::Pathgrid::Point dest(mAllowedNodes[randNode]); + ToWorldCoordinates(dest, storage.mCell->getCell()); + + // actor position is already in world co-ordinates + ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(actorPos)); + + // don't take shortcuts for wandering + storage.mPathFinder.buildSyncedPath(start, dest, actor.getCell(), false); + + if (storage.mPathFinder.isPathConstructed()) + { + // Remove this node as an option and add back the previously used node (stops NPC from picking the same node): + ESM::Pathgrid::Point temp = mAllowedNodes[randNode]; + mAllowedNodes.erase(mAllowedNodes.begin() + randNode); + // check if mCurrentNode was taken out of mAllowedNodes + if (mTrimCurrentNode && mAllowedNodes.size() > 1) + mTrimCurrentNode = false; + else + mAllowedNodes.push_back(mCurrentNode); + mCurrentNode = temp; + + storage.mMoveNow = false; + storage.mWalking = true; + } + // Choose a different node and delete this one from possible nodes because it is uncreachable: + else + mAllowedNodes.erase(mAllowedNodes.begin() + randNode); + } + void AiWander::ToWorldCoordinates(ESM::Pathgrid::Point& point, const ESM::Cell * cell) { if (cell->isExterior()) diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index fb1ed0b7e..9f68ee171 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -71,6 +71,7 @@ namespace MWMechanics void playIdle(const MWWorld::Ptr& actor, unsigned short idleSelect); bool checkIdle(const MWWorld::Ptr& actor, unsigned short idleSelect); void getRandomIdle(unsigned short& playedIdle); + void setPathToAnAllowedNode(const MWWorld::Ptr& actor, AiWanderStorage& storage, const ESM::Position& actorPos); int mDistance; // how far the actor can wander from the spawn point int mDuration; From 1ef78b1e568f21638a9c87d11e8813332841a556 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 12 Jul 2015 16:37:31 +1200 Subject: [PATCH 1796/3725] extracted playGreetingIfPlayerGetsTooClose() --- apps/openmw/mwmechanics/aiwander.cpp | 136 ++++++++++++++------------- apps/openmw/mwmechanics/aiwander.hpp | 1 + 2 files changed, 72 insertions(+), 65 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 17d125209..753e6ef68 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -432,71 +432,7 @@ namespace MWMechanics // Allow interrupting a walking actor to trigger a greeting if(idleNow || walking) { - // Play a random voice greeting if the player gets too close - int hello = cStats.getAiSetting(CreatureStats::AI_Hello).getModified(); - float helloDistance = static_cast(hello); - static int iGreetDistanceMultiplier =MWBase::Environment::get().getWorld()->getStore() - .get().find("iGreetDistanceMultiplier")->getInt(); - - helloDistance *= iGreetDistanceMultiplier; - - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); - osg::Vec3f playerPos(player.getRefData().getPosition().asVec3()); - osg::Vec3f actorPos(actor.getRefData().getPosition().asVec3()); - float playerDistSqr = (playerPos - actorPos).length2(); - - int& greetingTimer = storage.mGreetingTimer; - if (greetingState == Greet_None) - { - if ((playerDistSqr <= helloDistance*helloDistance) && - !player.getClass().getCreatureStats(player).isDead() && MWBase::Environment::get().getWorld()->getLOS(player, actor) - && MWBase::Environment::get().getMechanicsManager()->awarenessCheck(player, actor)) - greetingTimer++; - - if (greetingTimer >= GREETING_SHOULD_START) - { - greetingState = Greet_InProgress; - MWBase::Environment::get().getDialogueManager()->say(actor, "hello"); - greetingTimer = 0; - } - } - - if(greetingState == Greet_InProgress) - { - greetingTimer++; - - if(walking) - { - stopWalking(actor, storage); - moveNow = false; - walking = false; - mObstacleCheck.clear(); - idleNow = true; - getRandomIdle(playedIdle); - } - - if(!rotate) - { - osg::Vec3f dir = playerPos - actorPos; - - float faceAngleRadians = std::atan2(dir.x(), dir.y()); - targetAngleRadians = faceAngleRadians; - rotate = true; - } - - if (greetingTimer >= GREETING_SHOULD_END) - { - greetingState = Greet_Done; - greetingTimer = 0; - } - } - - if (greetingState == MWMechanics::AiWander::Greet_Done) - { - float resetDist = 2*helloDistance; - if (playerDistSqr >= resetDist*resetDist) - greetingState = Greet_None; - } + playGreetingIfPlayerGetsTooClose(actor, storage); } if(moveNow && mDistance) @@ -514,6 +450,76 @@ namespace MWMechanics return false; // AiWander package not yet completed } + void AiWander::playGreetingIfPlayerGetsTooClose(const MWWorld::Ptr& actor, AiWanderStorage& storage) + { + // Play a random voice greeting if the player gets too close + int hello = actor.getClass().getCreatureStats(actor).getAiSetting(CreatureStats::AI_Hello).getModified(); + float helloDistance = static_cast(hello); + static int iGreetDistanceMultiplier = MWBase::Environment::get().getWorld()->getStore() + .get().find("iGreetDistanceMultiplier")->getInt(); + + helloDistance *= iGreetDistanceMultiplier; + + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + osg::Vec3f playerPos(player.getRefData().getPosition().asVec3()); + osg::Vec3f actorPos(actor.getRefData().getPosition().asVec3()); + float playerDistSqr = (playerPos - actorPos).length2(); + + int& greetingTimer = storage.mGreetingTimer; + GreetingState& greetingState = storage.mSaidGreeting; + if (greetingState == Greet_None) + { + if ((playerDistSqr <= helloDistance*helloDistance) && + !player.getClass().getCreatureStats(player).isDead() && MWBase::Environment::get().getWorld()->getLOS(player, actor) + && MWBase::Environment::get().getMechanicsManager()->awarenessCheck(player, actor)) + greetingTimer++; + + if (greetingTimer >= GREETING_SHOULD_START) + { + greetingState = Greet_InProgress; + MWBase::Environment::get().getDialogueManager()->say(actor, "hello"); + greetingTimer = 0; + } + } + + if (greetingState == Greet_InProgress) + { + greetingTimer++; + + if (storage.mWalking) + { + stopWalking(actor, storage); + storage.mMoveNow = false; + storage.mWalking = false; + mObstacleCheck.clear(); + storage.mIdleNow = true; + getRandomIdle(storage.mPlayedIdle); + } + + if (!storage.mRotate) + { + osg::Vec3f dir = playerPos - actorPos; + + float faceAngleRadians = std::atan2(dir.x(), dir.y()); + storage.mTargetAngleRadians = faceAngleRadians; + storage.mRotate = true; + } + + if (greetingTimer >= GREETING_SHOULD_END) + { + greetingState = Greet_Done; + greetingTimer = 0; + } + } + + if (greetingState == MWMechanics::AiWander::Greet_Done) + { + float resetDist = 2 * helloDistance; + if (playerDistSqr >= resetDist*resetDist) + greetingState = Greet_None; + } + } + void AiWander::setPathToAnAllowedNode(const MWWorld::Ptr& actor, AiWanderStorage& storage, const ESM::Position& actorPos) { unsigned int randNode = Misc::Rng::rollDice(mAllowedNodes.size()); diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 9f68ee171..0451ec700 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -72,6 +72,7 @@ namespace MWMechanics bool checkIdle(const MWWorld::Ptr& actor, unsigned short idleSelect); void getRandomIdle(unsigned short& playedIdle); void setPathToAnAllowedNode(const MWWorld::Ptr& actor, AiWanderStorage& storage, const ESM::Position& actorPos); + void playGreetingIfPlayerGetsTooClose(const MWWorld::Ptr& actor, AiWanderStorage& storage); int mDistance; // how far the actor can wander from the spawn point int mDuration; From 0b089a55640f1c1184c68cbea15a63f9303f6e69 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 12 Jul 2015 16:38:36 +1200 Subject: [PATCH 1797/3725] extracted function evadeObstacles() --- apps/openmw/mwmechanics/aiwander.cpp | 83 +++++++++++++++------------- apps/openmw/mwmechanics/aiwander.hpp | 1 + 2 files changed, 45 insertions(+), 39 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 753e6ef68..a2388320c 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -239,45 +239,7 @@ namespace MWMechanics zTurn(actor, osg::DegreesToRadians(storage.mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]))); actor.getClass().getMovementSettings(actor).mPosition[1] = 1; - // Returns true if evasive action needs to be taken - if(mObstacleCheck.check(actor, duration)) - { - // first check if we're walking into a door - if(proximityToDoor(actor)) // NOTE: checks interior cells only - { - // remove allowed points then select another random destination - mTrimCurrentNode = true; - trimAllowedNodes(mAllowedNodes, storage.mPathFinder); - mObstacleCheck.clear(); - storage.mPathFinder.clearPath(); - walking = false; - moveNow = true; - } - else // probably walking into another NPC - { - // TODO: diagonal should have same animation as walk forward - // but doesn't seem to do that? - actor.getClass().getMovementSettings(actor).mPosition[0] = 1; - actor.getClass().getMovementSettings(actor).mPosition[1] = 0.1f; - // change the angle a bit, too - zTurn(actor, osg::DegreesToRadians(storage.mPathFinder.getZAngleToNext(pos.pos[0] + 1, pos.pos[1]))); - } - mStuckCount++; // TODO: maybe no longer needed - } -//#if 0 - // TODO: maybe no longer needed - if(mStuckCount >= COUNT_BEFORE_RESET) // something has gone wrong, reset - { - //std::cout << "Reset \""<< cls.getName(actor) << "\"" << std::endl; - mObstacleCheck.clear(); - - stopWalking(actor, storage); - moveNow = false; - walking = false; - chooseAction = true; - mStuckCount = 0; - } -//#endif + evadeObstacles(actor, storage, duration); } @@ -450,6 +412,49 @@ namespace MWMechanics return false; // AiWander package not yet completed } + void AiWander::evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration) + { + if (mObstacleCheck.check(actor, duration)) + { + // first check if we're walking into a door + if (proximityToDoor(actor)) // NOTE: checks interior cells only + { + // remove allowed points then select another random destination + mTrimCurrentNode = true; + trimAllowedNodes(mAllowedNodes, storage.mPathFinder); + mObstacleCheck.clear(); + storage.mPathFinder.clearPath(); + storage.mWalking = false; + storage.mMoveNow = true; + } + else // probably walking into another NPC + { + // TODO: diagonal should have same animation as walk forward + // but doesn't seem to do that? + actor.getClass().getMovementSettings(actor).mPosition[0] = 1; + actor.getClass().getMovementSettings(actor).mPosition[1] = 0.1f; + // change the angle a bit, too + const ESM::Position& pos = actor.getRefData().getPosition(); + zTurn(actor, osg::DegreesToRadians(storage.mPathFinder.getZAngleToNext(pos.pos[0] + 1, pos.pos[1]))); + } + mStuckCount++; // TODO: maybe no longer needed + } +//#if 0 + // TODO: maybe no longer needed + if (mStuckCount >= COUNT_BEFORE_RESET) // something has gone wrong, reset + { + //std::cout << "Reset \""<< cls.getName(actor) << "\"" << std::endl; + mObstacleCheck.clear(); + + stopWalking(actor, storage); + storage.mMoveNow = false; + storage.mWalking = false; + storage.mChooseAction = true; + mStuckCount = 0; + } +//#endif + } + void AiWander::playGreetingIfPlayerGetsTooClose(const MWWorld::Ptr& actor, AiWanderStorage& storage) { // Play a random voice greeting if the player gets too close diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 0451ec700..5196bca00 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -73,6 +73,7 @@ namespace MWMechanics void getRandomIdle(unsigned short& playedIdle); void setPathToAnAllowedNode(const MWWorld::Ptr& actor, AiWanderStorage& storage, const ESM::Position& actorPos); void playGreetingIfPlayerGetsTooClose(const MWWorld::Ptr& actor, AiWanderStorage& storage); + void evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration); int mDistance; // how far the actor can wander from the spawn point int mDuration; From 22059d68f6e70df4cb3764a0742e172888ab4b53 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 12 Jul 2015 17:14:48 +1200 Subject: [PATCH 1798/3725] Remove duplicated code. --- apps/openmw/mwmechanics/aiwander.cpp | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index a2388320c..a17f7a1f6 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -225,8 +225,6 @@ namespace MWMechanics storage.mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], DESTINATION_TOLERANCE)) { stopWalking(actor, storage); - moveNow = false; - walking = false; chooseAction = true; mHasReturnPosition = false; } @@ -329,17 +327,8 @@ namespace MWMechanics { // End package if duration is complete or mid-night hits: MWWorld::TimeStamp currentTime = world->getTimeStamp(); - if(currentTime.getHour() >= mStartTime.getHour() + mDuration) - { - if(!mRepeat) - { - stopWalking(actor, storage); - return true; - } - else - mStartTime = currentTime; - } - else if(int(currentTime.getHour()) == 0 && currentTime.getDay() != mStartTime.getDay()) + if((currentTime.getHour() >= mStartTime.getHour() + mDuration) || + (int(currentTime.getHour()) == 0 && currentTime.getDay() != mStartTime.getDay())) { if(!mRepeat) { @@ -447,8 +436,6 @@ namespace MWMechanics mObstacleCheck.clear(); stopWalking(actor, storage); - storage.mMoveNow = false; - storage.mWalking = false; storage.mChooseAction = true; mStuckCount = 0; } @@ -494,8 +481,6 @@ namespace MWMechanics if (storage.mWalking) { stopWalking(actor, storage); - storage.mMoveNow = false; - storage.mWalking = false; mObstacleCheck.clear(); storage.mIdleNow = true; getRandomIdle(storage.mPlayedIdle); @@ -601,6 +586,8 @@ namespace MWMechanics { storage.mPathFinder.clearPath(); actor.getClass().getMovementSettings(actor).mPosition[1] = 0; + storage.mMoveNow = false; + storage.mWalking = false; } void AiWander::playIdle(const MWWorld::Ptr& actor, unsigned short idleSelect) From e294cd95cd2cb155c5fede771592fc3c4a7eab11 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 12 Jul 2015 17:15:14 +1200 Subject: [PATCH 1799/3725] extracted function playIdleDialogueRandomly() --- apps/openmw/mwmechanics/aiwander.cpp | 57 +++++++++++++++------------- apps/openmw/mwmechanics/aiwander.hpp | 1 + 2 files changed, 32 insertions(+), 26 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index a17f7a1f6..1375b5807 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -285,32 +285,7 @@ namespace MWMechanics } } - // Play idle voiced dialogue entries randomly - int hello = cStats.getAiSetting(CreatureStats::AI_Hello).getModified(); - if (hello > 0 && !MWBase::Environment::get().getWorld()->isSwimming(actor) - && MWBase::Environment::get().getSoundManager()->sayDone(actor)) - { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); - - static float fVoiceIdleOdds = MWBase::Environment::get().getWorld()->getStore() - .get().find("fVoiceIdleOdds")->getFloat(); - - float roll = Misc::Rng::rollProbability() * 10000.0f; - - // In vanilla MW the chance was FPS dependent, and did not allow proper changing of fVoiceIdleOdds - // due to the roll being an integer. - // Our implementation does not have these issues, so needs to be recalibrated. We chose to - // use the chance MW would have when run at 60 FPS with the default value of the GMST for calibration. - float x = fVoiceIdleOdds * 0.6f * (MWBase::Environment::get().getFrameDuration() / 0.1f); - - // Only say Idle voices when player is in LOS - // A bit counterintuitive, likely vanilla did this to reduce the appearance of - // voices going through walls? - if (roll < x && (player.getRefData().getPosition().asVec3() - pos.asVec3()).length2() - < 3000*3000 // maybe should be fAudioVoiceDefaultMaxDistance*fAudioMaxDistanceMult instead - && MWBase::Environment::get().getWorld()->getLOS(player, actor)) - MWBase::Environment::get().getDialogueManager()->say(actor, "idle"); - } + playIdleDialogueRandomly(actor); float& lastReaction = storage.mReaction; lastReaction += duration; @@ -442,6 +417,36 @@ namespace MWMechanics //#endif } + void AiWander::playIdleDialogueRandomly(const MWWorld::Ptr& actor) + { + int hello = actor.getClass().getCreatureStats(actor).getAiSetting(CreatureStats::AI_Hello).getModified(); + if (hello > 0 && !MWBase::Environment::get().getWorld()->isSwimming(actor) + && MWBase::Environment::get().getSoundManager()->sayDone(actor)) + { + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + + static float fVoiceIdleOdds = MWBase::Environment::get().getWorld()->getStore() + .get().find("fVoiceIdleOdds")->getFloat(); + + float roll = Misc::Rng::rollProbability() * 10000.0f; + + // In vanilla MW the chance was FPS dependent, and did not allow proper changing of fVoiceIdleOdds + // due to the roll being an integer. + // Our implementation does not have these issues, so needs to be recalibrated. We chose to + // use the chance MW would have when run at 60 FPS with the default value of the GMST for calibration. + float x = fVoiceIdleOdds * 0.6f * (MWBase::Environment::get().getFrameDuration() / 0.1f); + + // Only say Idle voices when player is in LOS + // A bit counterintuitive, likely vanilla did this to reduce the appearance of + // voices going through walls? + const ESM::Position& pos = actor.getRefData().getPosition(); + if (roll < x && (player.getRefData().getPosition().asVec3() - pos.asVec3()).length2() + < 3000 * 3000 // maybe should be fAudioVoiceDefaultMaxDistance*fAudioMaxDistanceMult instead + && MWBase::Environment::get().getWorld()->getLOS(player, actor)) + MWBase::Environment::get().getDialogueManager()->say(actor, "idle"); + } + } + void AiWander::playGreetingIfPlayerGetsTooClose(const MWWorld::Ptr& actor, AiWanderStorage& storage) { // Play a random voice greeting if the player gets too close diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 5196bca00..82baeedf3 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -74,6 +74,7 @@ namespace MWMechanics void setPathToAnAllowedNode(const MWWorld::Ptr& actor, AiWanderStorage& storage, const ESM::Position& actorPos); void playGreetingIfPlayerGetsTooClose(const MWWorld::Ptr& actor, AiWanderStorage& storage); void evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration); + void playIdleDialogueRandomly(const MWWorld::Ptr& actor); int mDistance; // how far the actor can wander from the spawn point int mDuration; From ddeabcdfbe006c2f23eb682bf8c611505a3e84f8 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 12 Jul 2015 17:15:41 +1200 Subject: [PATCH 1800/3725] Removed unused field that was giving compiler warning. --- apps/openmw/mwrender/ripplesimulation.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/openmw/mwrender/ripplesimulation.hpp b/apps/openmw/mwrender/ripplesimulation.hpp index 8e591a5db..1717cca57 100644 --- a/apps/openmw/mwrender/ripplesimulation.hpp +++ b/apps/openmw/mwrender/ripplesimulation.hpp @@ -59,7 +59,6 @@ namespace MWRender private: osg::ref_ptr mParent; - Resource::ResourceSystem* mResourceSystem; osg::ref_ptr mParticleSystem; osg::ref_ptr mParticleNode; From c266315a355480ad6e4bc665e5d4150c6c8de8f3 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sun, 12 Jul 2015 15:20:22 +0300 Subject: [PATCH 1801/3725] Load/read methods in MWWorld::Store return a pair (record ID, deleted flag) --- apps/openmw/mwworld/esmstore.cpp | 18 ++++----- apps/openmw/mwworld/store.cpp | 67 +++++++++++++------------------- apps/openmw/mwworld/store.hpp | 39 ++++++++----------- components/esm/util.hpp | 6 --- 4 files changed, 53 insertions(+), 77 deletions(-) diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index 99d32d06b..50324f3e8 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -96,22 +96,21 @@ void ESMStore::load(ESM::ESMReader &esm, Loading::Listener* listener) throw std::runtime_error(error.str()); } } else { - it->second->load(esm); - std::string id = it->second->getLastAddedRecordId(); - if (it->second->isLastAddedRecordDeleted()) + RecordId id = it->second->load(esm); + if (id.mIsDeleted) { - it->second->eraseStatic(id); + it->second->eraseStatic(id.mId); continue; } if (n.val==ESM::REC_DIAL) { - dialogue = const_cast(mDialogs.find(id)); + dialogue = const_cast(mDialogs.find(id.mId)); } else { dialogue = 0; } // Insert the reference into the global lookup - if (!id.empty() && isCacheableRecord(n.val)) { - mIds[Misc::StringUtils::lowerCase (id)] = n.val; + if (!id.mId.empty() && isCacheableRecord(n.val)) { + mIds[Misc::StringUtils::lowerCase (id.mId)] = n.val; } } listener->setProgress(static_cast(esm.getFileOffset() / (float)esm.getFileSize() * 1000)); @@ -184,13 +183,12 @@ void ESMStore::setUp() case ESM::REC_LEVC: { - StoreBase *store = mStores[type]; - store->read (reader); + RecordId id = mStores[type]->read (reader); // FIXME: there might be stale dynamic IDs in mIds from an earlier savegame // that really should be cleared instead of just overwritten - mIds[store->getLastAddedRecordId()] = type; + mIds[id.mId] = type; } if (type==ESM::REC_NPC_) diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index aeb96dcab..c8c42d17d 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -44,6 +44,10 @@ namespace namespace MWWorld { + RecordId::RecordId(const std::string &id, bool isDeleted) + : mId(id), mIsDeleted(isDeleted) + {} + template IndexedStore::IndexedStore() { @@ -180,7 +184,7 @@ namespace MWWorld return ptr; } template - void Store::load(ESM::ESMReader &esm) + RecordId Store::load(ESM::ESMReader &esm) { T record; record.load(esm); @@ -190,7 +194,7 @@ namespace MWWorld if (inserted.second) mShared.push_back(&inserted.first->second); - mLastAddedRecord = record; + return RecordId(record.mId, ESM::isRecordDeleted(record)); } template void Store::setUp() @@ -317,25 +321,13 @@ namespace MWWorld } } template - void Store::read(ESM::ESMReader& reader) + RecordId Store::read(ESM::ESMReader& reader) { T record; record.load (reader); insert (record); - mLastAddedRecord = record; - } - - - template - std::string Store::getLastAddedRecordId() const - { - return ESM::getRecordId(mLastAddedRecord); - } - template - bool Store::isLastAddedRecordDeleted() const - { - return ESM::isRecordDeleted(mLastAddedRecord); + return RecordId(record.mId, ESM::isRecordDeleted(record)); } // LandTexture @@ -375,7 +367,7 @@ namespace MWWorld assert(plugin < mStatic.size()); return mStatic[plugin].size(); } - void Store::load(ESM::ESMReader &esm, size_t plugin) + RecordId Store::load(ESM::ESMReader &esm, size_t plugin) { ESM::LandTexture lt; lt.load(esm); @@ -389,11 +381,13 @@ namespace MWWorld ltexl.resize(lt.mIndex+1); // Store it - ltexl[lt.mIndex] = mLastAddedRecord = lt; + ltexl[lt.mIndex] = lt; + + return RecordId(lt.mId, lt.mIsDeleted); } - void Store::load(ESM::ESMReader &esm) + RecordId Store::load(ESM::ESMReader &esm) { - load(esm, esm.getIndex()); + return load(esm, esm.getIndex()); } Store::iterator Store::begin(size_t plugin) const { @@ -405,16 +399,6 @@ namespace MWWorld assert(plugin < mStatic.size()); return mStatic[plugin].end(); } - - std::string Store::getLastAddedRecordId() const - { - return ESM::getRecordId(mLastAddedRecord); - } - - bool Store::isLastAddedRecordDeleted() const - { - return ESM::isRecordDeleted(mLastAddedRecord); - } // Land //========================================================================= @@ -462,7 +446,7 @@ namespace MWWorld } return ptr; } - void Store::load(ESM::ESMReader &esm) + RecordId Store::load(ESM::ESMReader &esm) { ESM::Land *ptr = new ESM::Land(); ptr->load(esm); @@ -480,6 +464,8 @@ namespace MWWorld } mStatic.push_back(ptr); + + return RecordId(); // No ID and can't be deleted (for now) } void Store::setUp() { @@ -622,7 +608,7 @@ namespace MWWorld mSharedExt.push_back(&(it->second)); } } - void Store::load(ESM::ESMReader &esm) + RecordId Store::load(ESM::ESMReader &esm) { // Don't automatically assume that a new cell must be spawned. Multiple plugins write to the same cell, // and we merge all this data into one Cell object. However, we can't simply search for the cell id, @@ -704,6 +690,7 @@ namespace MWWorld mExt[std::make_pair(cell.mData.mX, cell.mData.mY)] = cell; } } + return RecordId("", cell.mIsDeleted); } Store::iterator Store::intBegin() const { @@ -859,7 +846,7 @@ namespace MWWorld { mCells = &cells; } - void Store::load(ESM::ESMReader &esm) + RecordId Store::load(ESM::ESMReader &esm) { ESM::Pathgrid pathgrid; pathgrid.load(esm); @@ -884,6 +871,8 @@ namespace MWWorld if (!ret.second) ret.first->second = pathgrid; } + + return RecordId(); // No ID and can't be deleted (for now) } size_t Store::getSize() const { @@ -1035,7 +1024,7 @@ namespace MWWorld } template <> - inline void Store::load(ESM::ESMReader &esm) { + inline RecordId Store::load(ESM::ESMReader &esm) { // The original letter case of a dialogue ID is saved, because it's printed ESM::Dialogue dialogue; dialogue.load(esm); @@ -1053,7 +1042,7 @@ namespace MWWorld found->second.mType = dialogue.mType; } - mLastAddedRecord = dialogue; + return RecordId(dialogue.mId, dialogue.mIsDeleted); } @@ -1061,7 +1050,7 @@ namespace MWWorld //========================================================================= template <> - inline void Store::load(ESM::ESMReader &esm) { + inline RecordId Store::load(ESM::ESMReader &esm) { ESM::Script script; script.load(esm); Misc::StringUtils::toLower(script.mId); @@ -1072,7 +1061,7 @@ namespace MWWorld else inserted.first->second = script; - mLastAddedRecord = script; + return RecordId(script.mId, script.mIsDeleted); } @@ -1080,7 +1069,7 @@ namespace MWWorld //========================================================================= template <> - inline void Store::load(ESM::ESMReader &esm) + inline RecordId Store::load(ESM::ESMReader &esm) { ESM::StartScript script; script.load(esm); @@ -1092,7 +1081,7 @@ namespace MWWorld else inserted.first->second = script; - mLastAddedRecord = script; + return RecordId(script.mId); } } diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index 0fdfffd41..bbbd30cd0 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -19,6 +19,14 @@ namespace Loading namespace MWWorld { + struct RecordId + { + std::string mId; + bool mIsDeleted; + + RecordId(const std::string &id = "", bool isDeleted = false); + }; + struct StoreBase { virtual ~StoreBase() {} @@ -28,19 +36,15 @@ namespace MWWorld virtual size_t getSize() const = 0; virtual int getDynamicSize() const { return 0; } - virtual void load(ESM::ESMReader &esm) = 0; + virtual RecordId load(ESM::ESMReader &esm) = 0; virtual bool eraseStatic(const std::string &id) {return false;} virtual void clearDynamic() {} virtual void write (ESM::ESMWriter& writer, Loading::Listener& progress) const {} - virtual void read (ESM::ESMReader& reader) {} + virtual RecordId read (ESM::ESMReader& reader) { return RecordId(); } ///< Read into dynamic storage - - virtual std::string getLastAddedRecordId() const { return ""; } - ///< Returns the last loaded/read ID or empty string if a loaded record has no ID - virtual bool isLastAddedRecordDeleted() const { return false; } }; template @@ -137,8 +141,6 @@ namespace MWWorld // for heads/hairs in the character creation) std::map mDynamic; - T mLastAddedRecord; - typedef std::map Dynamic; typedef std::map Static; @@ -185,12 +187,9 @@ namespace MWWorld bool erase(const std::string &id); bool erase(const T &item); - void load(ESM::ESMReader &esm); + RecordId load(ESM::ESMReader &esm); void write(ESM::ESMWriter& writer, Loading::Listener& progress) const; - void read(ESM::ESMReader& reader); - - std::string getLastAddedRecordId() const; - bool isLastAddedRecordDeleted() const; + RecordId read(ESM::ESMReader& reader); }; template <> @@ -199,7 +198,6 @@ namespace MWWorld // For multiple ESM/ESP files we need one list per file. typedef std::vector LandTextureList; std::vector mStatic; - ESM::LandTexture mLastAddedRecord; public: Store(); @@ -214,14 +212,11 @@ namespace MWWorld size_t getSize() const; size_t getSize(size_t plugin) const; - void load(ESM::ESMReader &esm, size_t plugin); - void load(ESM::ESMReader &esm); + RecordId load(ESM::ESMReader &esm, size_t plugin); + RecordId load(ESM::ESMReader &esm); iterator begin(size_t plugin) const; iterator end(size_t plugin) const; - - std::string getLastAddedRecordId() const; - bool isLastAddedRecordDeleted() const; }; template <> @@ -243,7 +238,7 @@ namespace MWWorld ESM::Land *search(int x, int y) const; ESM::Land *find(int x, int y) const; - void load(ESM::ESMReader &esm); + RecordId load(ESM::ESMReader &esm); void setUp(); }; @@ -293,7 +288,7 @@ namespace MWWorld void setUp(); - void load(ESM::ESMReader &esm); + RecordId load(ESM::ESMReader &esm); iterator intBegin() const; iterator intEnd() const; @@ -335,7 +330,7 @@ namespace MWWorld Store(); void setCells(Store& cells); - void load(ESM::ESMReader &esm); + RecordId load(ESM::ESMReader &esm); size_t getSize() const; void setUp(); diff --git a/components/esm/util.hpp b/components/esm/util.hpp index 94a7956ef..ca6917fd1 100644 --- a/components/esm/util.hpp +++ b/components/esm/util.hpp @@ -60,12 +60,6 @@ struct Vector3 bool readDeleSubRecord(ESMReader &esm); void writeDeleSubRecord(ESMWriter &esm); -template -std::string getRecordId(const RecordT &record) -{ - return record.mId; -} - template bool isRecordDeleted(const RecordT &record) { From 42f9136141657cbe3fd0801c579e37dd1ff47a30 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sun, 12 Jul 2015 15:22:51 +0300 Subject: [PATCH 1802/3725] Remove DELE and NAME handling from RefIdCollection and RefIdData --- apps/opencs/model/world/refidcollection.cpp | 56 +----------- apps/opencs/model/world/refiddata.cpp | 12 +-- apps/opencs/model/world/refiddata.hpp | 96 +++++++++++++++++---- 3 files changed, 87 insertions(+), 77 deletions(-) diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 5495926b4..0ca050e18 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -767,61 +767,7 @@ const CSMWorld::RecordBase& CSMWorld::RefIdCollection::getRecord (int index) con void CSMWorld::RefIdCollection::load (ESM::ESMReader& reader, bool base, UniversalId::Type type) { - std::string id = reader.getHNOString ("NAME"); - - int index = searchId (id); - - if (reader.isNextSub ("DELE")) - { - reader.skipRecord(); - - if (index==-1) - { - // deleting a record that does not exist - - // ignore it for now - - /// \todo report the problem to the user - } - else if (base) - { - mData.erase (index, 1); - } - else - { - mData.getRecord (mData.globalToLocalIndex (index)).mState = RecordBase::State_Deleted; - } - } - else - { - if (index==-1) - { - // new record - int index = mData.getAppendIndex (type); - mData.appendRecord (type, id, base); - - RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (index); - - mData.load (localIndex, reader, base); - - mData.getRecord (localIndex).mState = - base ? RecordBase::State_BaseOnly : RecordBase::State_ModifiedOnly; - } - else - { - // old record - RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (index); - - if (!base) - if (mData.getRecord (localIndex).mState==RecordBase::State_Erased) - throw std::logic_error ("attempt to access a deleted record"); - - mData.load (localIndex, reader, base); - - if (!base) - mData.getRecord (localIndex).mState = RecordBase::State_Modified; - } - } + mData.load(reader, base, type); } int CSMWorld::RefIdCollection::getAppendIndex (const std::string& id, UniversalId::Type type) const diff --git a/apps/opencs/model/world/refiddata.cpp b/apps/opencs/model/world/refiddata.cpp index 7f5c25f36..68f3fc4ad 100644 --- a/apps/opencs/model/world/refiddata.cpp +++ b/apps/opencs/model/world/refiddata.cpp @@ -161,15 +161,15 @@ int CSMWorld::RefIdData::getAppendIndex (UniversalId::Type type) const return index; } -void CSMWorld::RefIdData::load (const LocalIndex& index, ESM::ESMReader& reader, bool base) +void CSMWorld::RefIdData::load (ESM::ESMReader& reader, bool base, CSMWorld::UniversalId::Type type) { - std::map::iterator iter = - mRecordContainers.find (index.second); + std::map::iterator found = + mRecordContainers.find (type); - if (iter==mRecordContainers.end()) - throw std::logic_error ("invalid local index type"); + if (found == mRecordContainers.end()) + throw std::logic_error ("Invalid type for an Object (Reference ID)"); - iter->second->load (index.first, reader, base); + found->second->load(reader, base); } void CSMWorld::RefIdData::erase (const LocalIndex& index, int count) diff --git a/apps/opencs/model/world/refiddata.hpp b/apps/opencs/model/world/refiddata.hpp index 85d16a6eb..17d913911 100644 --- a/apps/opencs/model/world/refiddata.hpp +++ b/apps/opencs/model/world/refiddata.hpp @@ -49,7 +49,7 @@ namespace CSMWorld virtual void insertRecord (RecordBase& record) = 0; - virtual void load (int index, ESM::ESMReader& reader, bool base) = 0; + virtual void load (ESM::ESMReader& reader, bool base) = 0; virtual void erase (int index, int count) = 0; @@ -73,7 +73,7 @@ namespace CSMWorld virtual void insertRecord (RecordBase& record); - virtual void load (int index, ESM::ESMReader& reader, bool base); + virtual void load (ESM::ESMReader& reader, bool base); virtual void erase (int index, int count); @@ -122,9 +122,67 @@ namespace CSMWorld } template - void RefIdDataContainer::load (int index, ESM::ESMReader& reader, bool base) + void RefIdDataContainer::load (ESM::ESMReader& reader, bool base) { - (base ? mContainer.at (index).mBase : mContainer.at (index).mModified).load (reader); + RecordT record; + record.load(reader); + + typename std::vector >::iterator found = mContainer.begin(); + for (; found != mContainer.end(); ++found) + { + if (found->get().mId == record.mId) + { + break; + } + } + + if (record.mIsDeleted) + { + if (found == mContainer.end()) + { + // deleting a record that does not exist + // ignore it for now + /// \todo report the problem to the user + return; + } + + if (base) + { + mContainer.erase(found); + } + else + { + found->mState = RecordBase::State_Deleted; + } + } + else + { + if (found == mContainer.end()) + { + appendRecord(record.mId, base); + if (base) + { + mContainer.back().mBase = record; + } + else + { + mContainer.back().mModified = record; + } + } + else + { + if (!base) + { + if (found->mState == RecordBase::State_Erased) + { + throw std::logic_error("Attempt to access a deleted record"); + } + + found->mState = RecordBase::State_Modified; + found->mModified = record; + } + } + } } template @@ -145,20 +203,26 @@ namespace CSMWorld template void RefIdDataContainer::save (int index, ESM::ESMWriter& writer) const { - CSMWorld::RecordBase::State state = mContainer.at (index).mState; + Record record = mContainer.at(index); + RecordT esmRecord; - if (state==CSMWorld::RecordBase::State_Modified || - state==CSMWorld::RecordBase::State_ModifiedOnly) + switch (record.mState) { - writer.startRecord (mContainer.at (index).mModified.sRecordId); - writer.writeHNCString ("NAME", getId (index)); - mContainer.at (index).mModified.save (writer); - writer.endRecord (mContainer.at (index).mModified.sRecordId); - } - else if (state==CSMWorld::RecordBase::State_Deleted) - { - /// \todo write record with delete flag + case RecordBase::State_Modified: + case RecordBase::State_ModifiedOnly: + esmRecord = record.mModified; + break; + case RecordBase::State_Deleted: + esmRecord = record.mBase; + esmRecord.mIsDeleted = true; + break; + default: + break; } + + writer.startRecord(esmRecord.sRecordId); + esmRecord.save(writer); + writer.endRecord(esmRecord.sRecordId); } @@ -220,7 +284,7 @@ namespace CSMWorld int getAppendIndex (UniversalId::Type type) const; - void load (const LocalIndex& index, ESM::ESMReader& reader, bool base); + void load (ESM::ESMReader& reader, bool base, UniversalId::Type type); int getSize() const; From 74a055f3ccbe25e50d2947d6fe639a84e3138ec7 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Mon, 13 Jul 2015 10:40:11 +0300 Subject: [PATCH 1803/3725] Remove NAME and DELE handling from IdCollection --- apps/opencs/model/world/cell.cpp | 5 +- apps/opencs/model/world/data.cpp | 32 +++++------ apps/opencs/model/world/idcollection.hpp | 69 ++++++++---------------- apps/opencs/model/world/land.hpp | 10 ++++ apps/opencs/model/world/pathgrid.hpp | 10 ++++ components/esm/util.cpp | 36 +++++++++++++ components/esm/util.hpp | 24 +++++++++ 7 files changed, 119 insertions(+), 67 deletions(-) diff --git a/apps/opencs/model/world/cell.cpp b/apps/opencs/model/world/cell.cpp index 40520a9ba..8816cd35e 100644 --- a/apps/opencs/model/world/cell.cpp +++ b/apps/opencs/model/world/cell.cpp @@ -5,16 +5,13 @@ void CSMWorld::Cell::load (ESM::ESMReader &esm) { - mName = mId; - ESM::Cell::load (esm, false); + mId = mName; if (!(mData.mFlags & Interior)) { std::ostringstream stream; - stream << "#" << mData.mX << " " << mData.mY; - mId = stream.str(); } } diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index a92a7ad79..348656a7c 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -988,41 +988,41 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Messages& messages) case ESM::REC_DIAL: { - std::string id = mReader->getHNOString ("NAME"); - ESM::Dialogue record; - record.mId = id; record.load (*mReader); - if (record.mType==ESM::Dialogue::Journal) - { - mJournals.load (record, mBase); - mDialogue = &mJournals.getRecord (id).get(); - } - else if (record.mType==ESM::Dialogue::Deleted) + if (record.mIsDeleted) { - mDialogue = 0; // record vector can be shuffled around which would make pointer - // to record invalid + // record vector can be shuffled around which would make pointer to record invalid + mDialogue = 0; - if (mJournals.tryDelete (id)) + if (mJournals.tryDelete (record.mId)) { /// \todo handle info records } - else if (mTopics.tryDelete (id)) + else if (mTopics.tryDelete (record.mId)) { /// \todo handle info records } else { messages.add (UniversalId::Type_None, - "Trying to delete dialogue record " + id + " which does not exist", + "Trying to delete dialogue record " + record.mId + " which does not exist", "", CSMDoc::Message::Severity_Warning); } } else { - mTopics.load (record, mBase); - mDialogue = &mTopics.getRecord (id).get(); + if (record.mType == ESM::Dialogue::Journal) + { + mJournals.load (record, mBase); + mDialogue = &mJournals.getRecord (record.mId).get(); + } + else + { + mTopics.load (record, mBase); + mDialogue = &mTopics.getRecord (record.mId).get(); + } } break; diff --git a/apps/opencs/model/world/idcollection.hpp b/apps/opencs/model/world/idcollection.hpp index 4eafc59bd..41ce59702 100644 --- a/apps/opencs/model/world/idcollection.hpp +++ b/apps/opencs/model/world/idcollection.hpp @@ -2,6 +2,7 @@ #define CSM_WOLRD_IDCOLLECTION_H #include +#include #include "collection.hpp" @@ -41,69 +42,43 @@ namespace CSMWorld template int IdCollection::load (ESM::ESMReader& reader, bool base) { - std::string id = reader.getHNOString ("NAME"); + ESXRecordT record; + loadRecord (record, reader); - if (reader.isNextSub ("DELE")) - { - int index = Collection::searchId (id); - - reader.skipRecord(); + std::string id = IdAccessorT().getId (record); + int index = searchId (id); + if (ESM::isRecordDeleted (record)) + { if (index==-1) { // deleting a record that does not exist - // ignore it for now - /// \todo report the problem to the user + return -1; } - else if (base) + + if (base) { - Collection::removeRows (index, 1); + removeRows (index, 1); } else { - Record record = Collection::getRecord (index); - record.mState = RecordBase::State_Deleted; - this->setRecord (index, record); + Record baseRecord = getRecord (index); + baseRecord.mState = RecordBase::State_Deleted; + this->setRecord (index, baseRecord); } return -1; } - else - { - ESXRecordT record; - - // Sometimes id (i.e. NAME of the cell) may be different to the id we stored - // earlier. e.g. NAME == "Vivec, Arena" but id == "#-4 11". Sometime NAME is - // missing altogether for scripts or cells. - // - // In such cases the returned index will be -1. We then try updating the - // IdAccessor's id manually (e.g. set mId of the record to "Vivec, Arena") - // and try getting the index once more after loading the record. The mId of the - // record would have changed to "#-4 11" after the load, and searchId() should find - // it (if this is a modify) - int index = this->searchId (id); - - if (index==-1) - IdAccessorT().getId (record) = id; - else - { - record = this->getRecord (index).get(); - } - - loadRecord (record, reader); - - if (index==-1) - { - std::string newId = IdAccessorT().getId(record); - int newIndex = this->searchId(newId); - if (newIndex != -1 && id != newId) - index = newIndex; - } - - return load (record, base, index); - } + // + //if (index != -1) + //{ + // ESXRecordT existedRecord = getRecord(index).get(); + // IdAccessorT().getId(record) = IdAccessorT().getId(existedRecord); + //} + + return load (record, base, index); } template diff --git a/apps/opencs/model/world/land.hpp b/apps/opencs/model/world/land.hpp index e97a2d7dd..adf5c0331 100644 --- a/apps/opencs/model/world/land.hpp +++ b/apps/opencs/model/world/land.hpp @@ -4,6 +4,7 @@ #include #include #include +#include namespace CSMWorld { @@ -26,4 +27,13 @@ namespace CSMWorld }; } +namespace ESM +{ + template <> + bool isRecordDeleted(const CSMWorld::Land &land) + { + return false; + } +} + #endif diff --git a/apps/opencs/model/world/pathgrid.hpp b/apps/opencs/model/world/pathgrid.hpp index 7e7b7c3bb..cd5e472c8 100644 --- a/apps/opencs/model/world/pathgrid.hpp +++ b/apps/opencs/model/world/pathgrid.hpp @@ -5,6 +5,7 @@ #include #include +#include namespace CSMWorld { @@ -26,4 +27,13 @@ namespace CSMWorld }; } +namespace ESM +{ + template <> + bool isRecordDeleted(const CSMWorld::Pathgrid &pgrd) + { + return false; + } +} + #endif diff --git a/components/esm/util.cpp b/components/esm/util.cpp index 4cfe644e8..a5ec377a3 100644 --- a/components/esm/util.cpp +++ b/components/esm/util.cpp @@ -36,4 +36,40 @@ namespace ESM { return false; } + + template <> + bool isRecordDeleted(const Skill &skill) + { + return false; + } + + template <> + bool isRecordDeleted(const MagicEffect &mgef) + { + return false; + } + + template <> + bool isRecordDeleted(const Pathgrid &pgrd) + { + return false; + } + + template <> + bool isRecordDeleted(const Land &land) + { + return false; + } + + template <> + bool isRecordDeleted(const DebugProfile &profile) + { + return false; + } + + template <> + bool isRecordDeleted(const Filter &filter) + { + return false; + } } diff --git a/components/esm/util.hpp b/components/esm/util.hpp index ca6917fd1..531e7eb76 100644 --- a/components/esm/util.hpp +++ b/components/esm/util.hpp @@ -12,6 +12,12 @@ #include "loadglob.hpp" #include "loadrace.hpp" #include "loadgmst.hpp" +#include "loadskil.hpp" +#include "loadmgef.hpp" +#include "loadland.hpp" +#include "loadpgrd.hpp" +#include "debugprofile.hpp" +#include "filter.hpp" namespace ESM { @@ -76,6 +82,24 @@ bool isRecordDeleted(const Race &race); template <> bool isRecordDeleted(const GameSetting &gmst); +template <> +bool isRecordDeleted(const Skill &skill); + +template <> +bool isRecordDeleted(const MagicEffect &mgef); + +template <> +bool isRecordDeleted(const Pathgrid &pgrd); + +template <> +bool isRecordDeleted(const Land &land); + +template <> +bool isRecordDeleted(const DebugProfile &profile); + +template <> +bool isRecordDeleted(const Filter &filter); + } #endif From 749eff5259269a3fced49098ca39517c06f6a582 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 13 Jul 2015 09:42:16 +0200 Subject: [PATCH 1804/3725] renaming a few user settings categories --- apps/opencs/model/settings/usersettings.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/opencs/model/settings/usersettings.cpp b/apps/opencs/model/settings/usersettings.cpp index 1bfc6e85b..11fc8bfeb 100644 --- a/apps/opencs/model/settings/usersettings.cpp +++ b/apps/opencs/model/settings/usersettings.cpp @@ -162,7 +162,7 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() ritd->setDeclaredValues (values); } - declareSection ("table-input", "Table Input"); + declareSection ("table-input", "ID Tables"); { QString inPlaceEdit ("Edit in Place"); QString editRecord ("Edit Record"); @@ -217,7 +217,7 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() jumpToAdded->setDeclaredValues (jumpValues); } - declareSection ("report-input", "Report Input"); + declareSection ("report-input", "Reports"); { QString none ("None"); QString edit ("Edit"); @@ -257,7 +257,7 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() shiftCtrlDoubleClick->setDefaultValue (none); shiftCtrlDoubleClick->setToolTip ("Action on shift control double click in report table:

" + toolTip); } - + declareSection ("search", "Search & Replace"); { Setting *before = createSetting (Type_SpinBox, "char-before", @@ -299,7 +299,7 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() QStringList modes; modes << "Ignore" << modeNormal << "Strict"; - + Setting *warnings = createSetting (Type_ComboBox, "warnings", "Warning Mode"); warnings->setDeclaredValues (modes); @@ -309,7 +309,7 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() "

  • Normal: Report warning as a warning
  • " "
  • Strict: Promote warning to an error
  • " ""); - + Setting *formatInt = createSetting (Type_LineEdit, "colour-int", "Highlight Colour: Int"); formatInt->setDefaultValues (QStringList() << "Dark magenta"); formatInt->setToolTip ("(Default: Green) Use one of the following formats:" + tooltip); @@ -346,7 +346,7 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() cycle->setToolTip ("When using next/previous functions at the last/first item of a " "list go to the first/last item"); } - + { /****************************************************************** * There are three types of values: From c8c79dc1efa5682c52ead7221628812638a55fed Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Mon, 13 Jul 2015 10:53:31 +0300 Subject: [PATCH 1805/3725] Move ID loading into a separate method for Dialogue and DialInfo records --- apps/openmw/mwworld/store.cpp | 8 +++---- components/esm/loaddial.cpp | 39 ++++++++++++++++++++--------------- components/esm/loaddial.hpp | 6 ++++++ components/esm/loadinfo.cpp | 14 ++++++++++++- components/esm/loadinfo.hpp | 6 ++++++ 5 files changed, 51 insertions(+), 22 deletions(-) diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index c8c42d17d..8f55bb466 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -1027,19 +1027,19 @@ namespace MWWorld inline RecordId Store::load(ESM::ESMReader &esm) { // The original letter case of a dialogue ID is saved, because it's printed ESM::Dialogue dialogue; - dialogue.load(esm); + dialogue.loadId(esm); std::string idLower = Misc::StringUtils::lowerCase(dialogue.mId); std::map::iterator found = mStatic.find(idLower); if (found == mStatic.end()) { + dialogue.loadData(esm); mStatic.insert(std::make_pair(idLower, dialogue)); } else { - // Update only read fields (don't touching the Info list) - found->second.mIsDeleted = dialogue.mIsDeleted; - found->second.mType = dialogue.mType; + found->second.loadData(esm); + dialogue = found->second; } return RecordId(dialogue.mId, dialogue.mIsDeleted); diff --git a/components/esm/loaddial.cpp b/components/esm/loaddial.cpp index dfac0ce63..fcdb57c8d 100644 --- a/components/esm/loaddial.cpp +++ b/components/esm/loaddial.cpp @@ -19,9 +19,18 @@ namespace ESM void Dialogue::load(ESMReader &esm) { - mIsDeleted = false; + loadId(esm); + loadData(esm); + } + void Dialogue::loadId(ESMReader &esm) + { + mIsDeleted = false; mId = esm.getHNString("NAME"); + } + + void Dialogue::loadData(ESMReader &esm) + { esm.getSubNameIs("DATA"); esm.getSubHeader(); int si = esm.getSubSize(); @@ -60,31 +69,28 @@ namespace ESM void Dialogue::readInfo(ESMReader &esm, bool merge) { - const std::string& id = esm.getHNOString("INAM"); + ESM::DialInfo info; + info.loadId(esm); if (!merge || mInfo.empty()) { - ESM::DialInfo info; - info.mId = id; - info.load(esm); - mLookup[id] = mInfo.insert(mInfo.end(), info); + info.loadInfo(esm); + mLookup[info.mId] = mInfo.insert(mInfo.end(), info); return; } ESM::Dialogue::InfoContainer::iterator it = mInfo.end(); std::map::iterator lookup; + lookup = mLookup.find(info.mId); - lookup = mLookup.find(id); - - ESM::DialInfo info; if (lookup != mLookup.end()) { it = lookup->second; // Merge with existing record. Only the subrecords that are present in // the new record will be overwritten. - it->load(esm); + it->loadInfo(esm); info = *it; // Since the record merging may have changed the next/prev linked list connection, we need to re-insert the record @@ -93,18 +99,17 @@ namespace ESM } else { - info.mId = id; - info.load(esm); + info.loadInfo(esm); } if (info.mNext.empty()) { - mLookup[id] = mInfo.insert(mInfo.end(), info); + mLookup[info.mId] = mInfo.insert(mInfo.end(), info); return; } if (info.mPrev.empty()) { - mLookup[id] = mInfo.insert(mInfo.begin(), info); + mLookup[info.mId] = mInfo.insert(mInfo.begin(), info); return; } @@ -113,7 +118,7 @@ namespace ESM { it = lookup->second; - mLookup[id] = mInfo.insert(++it, info); + mLookup[info.mId] = mInfo.insert(++it, info); return; } @@ -122,11 +127,11 @@ namespace ESM { it = lookup->second; - mLookup[id] = mInfo.insert(it, info); + mLookup[info.mId] = mInfo.insert(it, info); return; } - std::cerr << "Failed to insert info " << id << std::endl; + std::cerr << "Failed to insert info " << info.mId << std::endl; } void Dialogue::clearDeletedInfos() diff --git a/components/esm/loaddial.hpp b/components/esm/loaddial.hpp index e80a7b0b2..73bf16974 100644 --- a/components/esm/loaddial.hpp +++ b/components/esm/loaddial.hpp @@ -51,6 +51,12 @@ struct Dialogue Dialogue(); void load(ESMReader &esm); + ///< Loads all sub-records of Dialogue record + void loadId(ESMReader &esm); + ///< Loads NAME sub-record of Dialogue record + void loadData(ESMReader &esm); + ///< Loads all sub-records of Dialogue record, except NAME sub-record + void save(ESMWriter &esm) const; /// Remove all INFOs that are deleted or marked as QS_Deleted from mInfos. diff --git a/components/esm/loadinfo.cpp b/components/esm/loadinfo.cpp index c1b12e24c..8f5f0f28b 100644 --- a/components/esm/loadinfo.cpp +++ b/components/esm/loadinfo.cpp @@ -14,10 +14,21 @@ namespace ESM {} void DialInfo::load(ESMReader &esm) + { + loadId(esm); + loadInfo(esm); + } + + void DialInfo::loadId(ESMReader &esm) + { + mIsDeleted = false; + mId = esm.getHNString("INAM"); + } + + void DialInfo::loadInfo(ESMReader &esm) { mQuestStatus = QS_None; mFactionLess = false; - mIsDeleted = false; mPrev = esm.getHNString("PNAM"); mNext = esm.getHNString("NNAM"); @@ -141,6 +152,7 @@ namespace ESM void DialInfo::save(ESMWriter &esm) const { + esm.writeHNCString("INAM", mId); esm.writeHNCString("PNAM", mPrev); esm.writeHNCString("NNAM", mNext); diff --git a/components/esm/loadinfo.hpp b/components/esm/loadinfo.hpp index fbb7e36a5..c243cd50e 100644 --- a/components/esm/loadinfo.hpp +++ b/components/esm/loadinfo.hpp @@ -111,6 +111,12 @@ struct DialInfo DialInfo(); void load(ESMReader &esm); + ///< Loads all sub-records of Info record + void loadId(ESMReader &esm); + ///< Loads only Id of Info record (INAM sub-record) + void loadInfo(ESMReader &esm); + ///< Loads all sub-records of Info record, except INAM sub-record + void save(ESMWriter &esm) const; void blank(); From 71e5fc7f0458f77e94879399a39e36393ed19409 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Mon, 13 Jul 2015 11:19:14 +0300 Subject: [PATCH 1806/3725] Remove INAM handling from InfoCollection --- apps/opencs/model/world/infocollection.cpp | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/apps/opencs/model/world/infocollection.cpp b/apps/opencs/model/world/infocollection.cpp index 560be8131..1b95c1505 100644 --- a/apps/opencs/model/world/infocollection.cpp +++ b/apps/opencs/model/world/infocollection.cpp @@ -107,21 +107,18 @@ bool CSMWorld::InfoCollection::reorderRows (int baseIndex, const std::vector Date: Mon, 13 Jul 2015 12:52:18 +0200 Subject: [PATCH 1807/3725] added user settings option to toggle toolbars in single-record subviews --- apps/opencs/model/settings/usersettings.cpp | 9 +++ apps/opencs/view/world/dialoguesubview.cpp | 86 ++++++++++++++------- apps/opencs/view/world/dialoguesubview.hpp | 16 ++-- apps/opencs/view/world/scriptsubview.cpp | 63 ++++++++++----- apps/opencs/view/world/scriptsubview.hpp | 8 ++ 5 files changed, 131 insertions(+), 51 deletions(-) diff --git a/apps/opencs/model/settings/usersettings.cpp b/apps/opencs/model/settings/usersettings.cpp index 11fc8bfeb..673db4057 100644 --- a/apps/opencs/model/settings/usersettings.cpp +++ b/apps/opencs/model/settings/usersettings.cpp @@ -217,6 +217,12 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() jumpToAdded->setDeclaredValues (jumpValues); } + declareSection ("dialogues", "ID Dialogues"); + { + Setting *toolbar = createSetting (Type_CheckBox, "toolbar", "Show toolbar"); + toolbar->setDefaultValue ("true"); + } + declareSection ("report-input", "Reports"); { QString none ("None"); @@ -310,6 +316,9 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() "
  • Strict: Promote warning to an error
  • " ""); + Setting *toolbar = createSetting (Type_CheckBox, "toolbar", "Show toolbar"); + toolbar->setDefaultValue ("true"); + Setting *formatInt = createSetting (Type_LineEdit, "colour-int", "Highlight Colour: Int"); formatInt->setDefaultValues (QStringList() << "Dark magenta"); formatInt->setToolTip ("(Default: Green) Use one of the following formats:" + tooltip); diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index ed50b81cd..edd9cc1e2 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -31,6 +31,7 @@ #include "../../model/world/idtree.hpp" #include "../../model/world/commands.hpp" #include "../../model/doc/document.hpp" +#include "../../model/settings/usersettings.hpp" #include "../widget/coloreditor.hpp" #include "../widget/droplineedit.hpp" @@ -66,7 +67,7 @@ void CSVWorld::NotEditableSubDelegate::setEditorData (QWidget* editor, const QMo CSMWorld::Columns::ColumnId columnId = static_cast ( mTable->getColumnId (index.column())); - + if (QVariant::String == v.type()) { label->setText(v.toString()); @@ -75,7 +76,7 @@ void CSVWorld::NotEditableSubDelegate::setEditorData (QWidget* editor, const QMo { int data = v.toInt(); std::vector enumNames (CSMWorld::Columns::getEnums (columnId)); - + label->setText(QString::fromUtf8(enumNames.at(data).c_str())); } else @@ -324,11 +325,11 @@ CSVWorld::IdContextMenu::IdContextMenu(QWidget *widget, CSMWorld::ColumnBase::Di Q_ASSERT(mWidget != NULL); Q_ASSERT(CSMWorld::ColumnBase::isId(display)); Q_ASSERT(mIdType != CSMWorld::UniversalId::Type_None); - + mWidget->setContextMenuPolicy(Qt::CustomContextMenu); - connect(mWidget, - SIGNAL(customContextMenuRequested(const QPoint &)), - this, + connect(mWidget, + SIGNAL(customContextMenuRequested(const QPoint &)), + this, SLOT(showContextMenu(const QPoint &))); mEditIdAction = new QAction(this); @@ -352,7 +353,7 @@ void CSVWorld::IdContextMenu::excludeId(const std::string &id) QString CSVWorld::IdContextMenu::getWidgetValue() const { - QLineEdit *lineEdit = qobject_cast(mWidget); + QLineEdit *lineEdit = qobject_cast(mWidget); QLabel *label = qobject_cast(mWidget); QString value = ""; @@ -411,7 +412,7 @@ void CSVWorld::IdContextMenu::showContextMenu(const QPoint &pos) { removeEditIdActionFromMenu(); } - + if (!mContextMenu->actions().isEmpty()) { mContextMenu->exec(mWidget->mapToGlobal(pos)); @@ -588,9 +589,9 @@ void CSVWorld::EditWidget::remake(int row) tablesLayout->addWidget(label); tablesLayout->addWidget(table); - connect(table, - SIGNAL(editRequest(const CSMWorld::UniversalId &, const std::string &)), - this, + connect(table, + SIGNAL(editRequest(const CSMWorld::UniversalId &, const std::string &)), + this, SIGNAL(editIdRequest(const CSMWorld::UniversalId &, const std::string &))); } else if (!(flags & CSMWorld::ColumnBase::Flag_Dialogue_List)) @@ -830,9 +831,28 @@ void CSVWorld::SimpleDialogueSubView::updateCurrentId() } +void CSVWorld::DialogueSubView::addButtonBar() +{ + if (mButtons) + return; + + mButtons = new RecordButtonBar (getUniversalId(), getTable(), mBottom, + &getCommandDispatcher(), this); + + getMainLayout().insertWidget (1, mButtons); + + // connections + connect (mButtons, SIGNAL (showPreview()), this, SLOT (showPreview())); + connect (mButtons, SIGNAL (viewRecord()), this, SLOT (viewRecord())); + connect (mButtons, SIGNAL (switchToRow (int)), this, SLOT (switchToRow (int))); + + connect (this, SIGNAL (universalIdChanged (const CSMWorld::UniversalId&)), + mButtons, SLOT (universalIdChanged (const CSMWorld::UniversalId&))); +} + CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document, const CreatorFactoryBase& creatorFactory, bool sorting) -: SimpleDialogueSubView (id, document) +: SimpleDialogueSubView (id, document), mButtons (0) { // bottom box mBottom = new TableBottomBox (creatorFactory, document, id, this); @@ -843,32 +863,44 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, this, SLOT (requestFocus (const std::string&))); // button bar - mButtons = new RecordButtonBar (id, getTable(), mBottom, - &getCommandDispatcher(), this); + if (CSMSettings::UserSettings::instance().setting ("dialogues/toolbar", QString("true")) == "true") + addButtonBar(); // layout - getMainLayout().addWidget (mButtons); getMainLayout().addWidget (mBottom); - - // connections - connect (mButtons, SIGNAL (showPreview()), this, SLOT (showPreview())); - connect (mButtons, SIGNAL (viewRecord()), this, SLOT (viewRecord())); - connect (mButtons, SIGNAL (switchToRow (int)), this, SLOT (switchToRow (int))); - - connect (this, SIGNAL (universalIdChanged (const CSMWorld::UniversalId&)), - mButtons, SLOT (universalIdChanged (const CSMWorld::UniversalId&))); } void CSVWorld::DialogueSubView::setEditLock (bool locked) { SimpleDialogueSubView::setEditLock (locked); - mButtons->setEditLock (locked); + + if (mButtons) + mButtons->setEditLock (locked); } void CSVWorld::DialogueSubView::updateUserSetting (const QString& name, const QStringList& value) { SimpleDialogueSubView::updateUserSetting (name, value); - mButtons->updateUserSetting (name, value); + + if (name=="dialogues/toolbar") + { + if (value.at(0)==QString ("true")) + { + addButtonBar(); + } + else + { + if (mButtons) + { + getMainLayout().removeWidget (mButtons); + delete mButtons; + mButtons = 0; + } + } + } + + if (mButtons) + mButtons->updateUserSetting (name, value); } void CSVWorld::DialogueSubView::showPreview () @@ -908,7 +940,7 @@ void CSVWorld::DialogueSubView::switchToRow (int row) setUniversalId (CSMWorld::UniversalId (type, id)); updateCurrentId(); - + getEditWidget().remake (row); int stateColumn = getTable().findColumnIndex (CSMWorld::Columns::ColumnId_Modification); @@ -923,5 +955,5 @@ void CSVWorld::DialogueSubView::requestFocus (const std::string& id) QModelIndex index = getTable().getModelIndex (id, 0); if (index.isValid()) - switchToRow (index.row()); + switchToRow (index.row()); } diff --git a/apps/opencs/view/world/dialoguesubview.hpp b/apps/opencs/view/world/dialoguesubview.hpp index d82936e45..2ae0f9720 100644 --- a/apps/opencs/view/world/dialoguesubview.hpp +++ b/apps/opencs/view/world/dialoguesubview.hpp @@ -195,8 +195,8 @@ namespace CSVWorld CSMDoc::Document& mDocument; std::vector mNestedModels; //Plain, raw C pointers, deleted in the dtor - void createEditorContextMenu(QWidget *editor, - CSMWorld::ColumnBase::Display display, + void createEditorContextMenu(QWidget *editor, + CSMWorld::ColumnBase::Display display, int currentRow) const; public: @@ -236,7 +236,7 @@ namespace CSVWorld void updateCurrentId(); bool isLocked() const; - + public: SimpleDialogueSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document); @@ -256,10 +256,14 @@ namespace CSVWorld class DialogueSubView : public SimpleDialogueSubView { Q_OBJECT - + TableBottomBox* mBottom; RecordButtonBar *mButtons; + private: + + void addButtonBar(); + public: DialogueSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document, @@ -268,14 +272,14 @@ namespace CSVWorld virtual void setEditLock (bool locked); virtual void updateUserSetting (const QString& name, const QStringList& value); - + private slots: void showPreview(); void viewRecord(); - void switchToRow (int row); + void switchToRow (int row); void requestFocus (const std::string& id); }; diff --git a/apps/opencs/view/world/scriptsubview.cpp b/apps/opencs/view/world/scriptsubview.cpp index dc079c3a9..0f5d5014a 100644 --- a/apps/opencs/view/world/scriptsubview.cpp +++ b/apps/opencs/view/world/scriptsubview.cpp @@ -17,19 +17,32 @@ #include "scriptedit.hpp" #include "recordbuttonbar.hpp" +void CSVWorld::ScriptSubView::addButtonBar() +{ + if (mButtons) + return; + + mButtons = new RecordButtonBar (getUniversalId(), *mModel, 0, &mCommandDispatcher, this); + + mLayout.insertWidget (1, mButtons); + + connect (mButtons, SIGNAL (switchToRow (int)), this, SLOT (switchToRow (int))); + + connect (this, SIGNAL (universalIdChanged (const CSMWorld::UniversalId&)), + mButtons, SLOT (universalIdChanged (const CSMWorld::UniversalId&))); +} + CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) -: SubView (id), mDocument (document), mColumn (-1), mBottom(0), mStatus(0), +: SubView (id), mDocument (document), mColumn (-1), mBottom(0), mStatus(0), mButtons (0), mCommandDispatcher (document, CSMWorld::UniversalId::getParentType (id.getType())) { std::vector selection (1, id.getId()); mCommandDispatcher.setSelection (selection); - QVBoxLayout *layout = new QVBoxLayout; - - layout->addWidget (mEditor = new ScriptEdit (mDocument, ScriptHighlighter::Mode_General, this), 2); + mLayout.addWidget (mEditor = new ScriptEdit (mDocument, ScriptHighlighter::Mode_General, this), 2); QWidget *widget = new QWidget (this);; - widget->setLayout (layout); + widget->setLayout (&mLayout); setWidget (widget); mModel = &dynamic_cast ( @@ -49,9 +62,8 @@ CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc: mEditor->setPlainText (mModel->data (mModel->getModelIndex (id.getId(), mColumn)).toString()); // buttons - mButtons = new RecordButtonBar (id, *mModel, 0, &mCommandDispatcher, this); - - layout->addWidget (mButtons); + if (CSMSettings::UserSettings::instance().setting ("script-editor/toolbar", QString("true")) == "true") + addButtonBar(); // status bar QStatusBar *statusBar = new QStatusBar(mBottom); @@ -64,7 +76,7 @@ CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc: bottmLayout->addWidget (statusBar); mBottom->setLayout (bottmLayout); - layout->addWidget (mBottom, 0); + mLayout.addWidget (mBottom, 0); // signals connect (mEditor, SIGNAL (textChanged()), this, SLOT (textChanged())); @@ -75,11 +87,6 @@ CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc: connect (mModel, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)), this, SLOT (rowsAboutToBeRemoved (const QModelIndex&, int, int))); - connect (mButtons, SIGNAL (switchToRow (int)), this, SLOT (switchToRow (int))); - - connect (this, SIGNAL (universalIdChanged (const CSMWorld::UniversalId&)), - mButtons, SLOT (universalIdChanged (const CSMWorld::UniversalId&))); - updateStatusBar(); connect(mEditor, SIGNAL(cursorPositionChanged()), this, SLOT(updateStatusBar())); } @@ -88,16 +95,33 @@ void CSVWorld::ScriptSubView::updateUserSetting (const QString& name, const QStr { if (name == "script-editor/show-linenum") { - std::string showLinenum = value.at(0).toStdString(); + std::string showLinenum = value.at(0).toUtf8().constData(); mEditor->showLineNum(showLinenum == "true"); mBottom->setVisible(showLinenum == "true"); } else if (name == "script-editor/mono-font") { - mEditor->setMonoFont(value.at(0).toStdString() == "true"); + mEditor->setMonoFont (value.at(0)==QString ("true")); + } + else if (name=="script-editor/toolbar") + { + if (value.at(0)==QString ("true")) + { + addButtonBar(); + } + else + { + if (mButtons) + { + mLayout.removeWidget (mButtons); + delete mButtons; + mButtons = 0; + } + } } - mButtons->updateUserSetting (name, value); + if (mButtons) + mButtons->updateUserSetting (name, value); } void CSVWorld::ScriptSubView::updateStatusBar () @@ -113,7 +137,10 @@ void CSVWorld::ScriptSubView::updateStatusBar () void CSVWorld::ScriptSubView::setEditLock (bool locked) { mEditor->setReadOnly (locked); - mButtons->setEditLock (locked); + + if (mButtons) + mButtons->setEditLock (locked); + mCommandDispatcher.setEditLock (locked); } diff --git a/apps/opencs/view/world/scriptsubview.hpp b/apps/opencs/view/world/scriptsubview.hpp index 0479e6ad8..370754ebe 100644 --- a/apps/opencs/view/world/scriptsubview.hpp +++ b/apps/opencs/view/world/scriptsubview.hpp @@ -1,12 +1,15 @@ #ifndef CSV_WORLD_SCRIPTSUBVIEW_H #define CSV_WORLD_SCRIPTSUBVIEW_H +#include + #include "../../model/world/commanddispatcher.hpp" #include "../doc/subview.hpp" class QModelIndex; class QLabel; +class QVBoxLayout; namespace CSMDoc { @@ -35,6 +38,11 @@ namespace CSVWorld QLabel *mStatus; RecordButtonBar *mButtons; CSMWorld::CommandDispatcher mCommandDispatcher; + QVBoxLayout mLayout; + + private: + + void addButtonBar(); public: From 5a0af772dda52209ffe92b26bbfbb6aa4e1ea68a Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 13 Jul 2015 17:40:03 +0200 Subject: [PATCH 1808/3725] Update README.md - Remove "an attempt at". I think we are far enough into the project to say that the "attempt" has been successful, at least to a degree. ;) - Added Current Status section. - Added line about OpenMW-CS. --- README.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f62800e1f..5b986e007 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,9 @@ OpenMW [![Build Status](https://img.shields.io/travis/OpenMW/openmw.svg)](https://travis-ci.org/OpenMW/openmw) [![Coverity Scan Build Status](https://scan.coverity.com/projects/3740/badge.svg)](https://scan.coverity.com/projects/3740) -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. +OpenMW is a recreation of 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. + +OpenMW also comes with OpenMW-CS, a replacement for Morrowind's TES Construction Set. * Version: 0.36.0 * License: GPL (see docs/license/GPL3.txt for more information) @@ -14,6 +15,13 @@ Morrowind by Bethesda Softworks. You need to own and install the original game f Font Licenses: * DejaVuLGCSansMono.ttf: custom (see docs/license/DejaVu Font License.txt for more information) +Current Status +-------------- + +The main quests in Morrowind, Tribunal and Bloodmoon are all completable. Some issues with side quests are to be expected (but rare). Check the [bug tracker](https://bugs.openmw.org/versions/21) for a list of issues we need to resolve before the "1.0" release. Even before the "1.0" release however, OpenMW boasts some new [features](https://wiki.openmw.org/index.php?title=Features), such as improved graphics and user interfaces. + +Pre-existing modifications created for the original Morrowind engine can be hit-and-miss. The OpenMW script compiler performs more thorough error-checking than Morrowind does, meaning that a mod created for Morrowind may not necessarily run in OpenMW. Some mods also rely on quirky behaviour or engine bugs in order to work. We are considering such compatibility issues on a case-by-case basis - in some cases adding a workaround to OpenMW may be feasible, in other cases fixing the mod will be the only option. If you know of any mods that work or don't work, feel free to add them to the [Mod status](https://wiki.openmw.org/index.php?title=Mod_status) wiki page. + Getting Started --------------- From f1b52c964a2da506aefdc7b404bd00fee766b273 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 13 Jul 2015 18:00:41 +0200 Subject: [PATCH 1809/3725] Select the current resolution in resolution list on game start (Fixes #2768) --- apps/openmw/mwgui/settingswindow.cpp | 21 +++++++++++++++++++++ apps/openmw/mwgui/settingswindow.hpp | 1 + 2 files changed, 22 insertions(+) diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index df5aa1a40..3ab2a6ce3 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -233,6 +233,7 @@ namespace MWGui if (mResolutionList->findItemIndexWith(str) == MyGUI::ITEM_NONE) mResolutionList->addItem(str); } + highlightCurrentResolution(); std::string tf = Settings::Manager::getString("texture filtering", "General"); mTextureFilteringButton->setCaption(textureFilteringToStr(tf)); @@ -299,8 +300,28 @@ namespace MWGui } void SettingsWindow::onResolutionCancel() + { + highlightCurrentResolution(); + } + + void SettingsWindow::highlightCurrentResolution() { mResolutionList->setIndexSelected(MyGUI::ITEM_NONE); + + int currentX = Settings::Manager::getInt("resolution x", "Video"); + int currentY = Settings::Manager::getInt("resolution y", "Video"); + + for (size_t i=0; igetItemCount(); ++i) + { + int resX, resY; + parseResolution (resX, resY, mResolutionList->getItemNameAt(i)); + + if (resX == currentX && resY == currentY) + { + mResolutionList->setIndexSelected(i); + break; + } + } } void SettingsWindow::onShadowTextureSizeChanged(MyGUI::ComboBox *_sender, size_t pos) diff --git a/apps/openmw/mwgui/settingswindow.hpp b/apps/openmw/mwgui/settingswindow.hpp index 45d489284..79487c54b 100644 --- a/apps/openmw/mwgui/settingswindow.hpp +++ b/apps/openmw/mwgui/settingswindow.hpp @@ -59,6 +59,7 @@ namespace MWGui void onResolutionSelected(MyGUI::ListBox* _sender, size_t index); void onResolutionAccept(); void onResolutionCancel(); + void highlightCurrentResolution(); void onShadowTextureSizeChanged(MyGUI::ComboBox* _sender, size_t pos); From dca4704b4b665f0853917150f7902e0c29607e58 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 13 Jul 2015 18:40:05 +0200 Subject: [PATCH 1810/3725] Print exceptions in CharacterCreation::spawnDialog --- apps/openmw/mwgui/charactercreation.cpp | 233 ++++++++++++------------ 1 file changed, 120 insertions(+), 113 deletions(-) diff --git a/apps/openmw/mwgui/charactercreation.cpp b/apps/openmw/mwgui/charactercreation.cpp index 73b950a6a..d0a050526 100644 --- a/apps/openmw/mwgui/charactercreation.cpp +++ b/apps/openmw/mwgui/charactercreation.cpp @@ -132,134 +132,141 @@ namespace MWGui void CharacterCreation::spawnDialog(const char id) { - switch (id) + try { - case GM_Name: - MWBase::Environment::get().getWindowManager()->removeDialog(mNameDialog); - mNameDialog = 0; - mNameDialog = new TextInputDialog(); - mNameDialog->setTextLabel(MWBase::Environment::get().getWindowManager()->getGameSettingString("sName", "Name")); - mNameDialog->setTextInput(mPlayerName); - mNameDialog->setNextButtonShow(mCreationStage >= CSE_NameChosen); - mNameDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onNameDialogDone); - mNameDialog->setVisible(true); - break; + switch (id) + { + case GM_Name: + MWBase::Environment::get().getWindowManager()->removeDialog(mNameDialog); + mNameDialog = 0; + mNameDialog = new TextInputDialog(); + mNameDialog->setTextLabel(MWBase::Environment::get().getWindowManager()->getGameSettingString("sName", "Name")); + mNameDialog->setTextInput(mPlayerName); + mNameDialog->setNextButtonShow(mCreationStage >= CSE_NameChosen); + mNameDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onNameDialogDone); + mNameDialog->setVisible(true); + break; - case GM_Race: - MWBase::Environment::get().getWindowManager()->removeDialog(mRaceDialog); - mRaceDialog = 0; - mRaceDialog = new RaceDialog(mViewer, mResourceSystem); - mRaceDialog->setNextButtonShow(mCreationStage >= CSE_RaceChosen); - mRaceDialog->setRaceId(mPlayerRaceId); - mRaceDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onRaceDialogDone); - mRaceDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onRaceDialogBack); - mRaceDialog->setVisible(true); - if (mCreationStage < CSE_NameChosen) - mCreationStage = CSE_NameChosen; - break; + case GM_Race: + MWBase::Environment::get().getWindowManager()->removeDialog(mRaceDialog); + mRaceDialog = 0; + mRaceDialog = new RaceDialog(mViewer, mResourceSystem); + mRaceDialog->setNextButtonShow(mCreationStage >= CSE_RaceChosen); + mRaceDialog->setRaceId(mPlayerRaceId); + mRaceDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onRaceDialogDone); + mRaceDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onRaceDialogBack); + mRaceDialog->setVisible(true); + if (mCreationStage < CSE_NameChosen) + mCreationStage = CSE_NameChosen; + break; - case GM_Class: - MWBase::Environment::get().getWindowManager()->removeDialog(mClassChoiceDialog); - mClassChoiceDialog = 0; - mClassChoiceDialog = new ClassChoiceDialog(); - mClassChoiceDialog->eventButtonSelected += MyGUI::newDelegate(this, &CharacterCreation::onClassChoice); - mClassChoiceDialog->setVisible(true); - if (mCreationStage < CSE_RaceChosen) - mCreationStage = CSE_RaceChosen; - break; + case GM_Class: + MWBase::Environment::get().getWindowManager()->removeDialog(mClassChoiceDialog); + mClassChoiceDialog = 0; + mClassChoiceDialog = new ClassChoiceDialog(); + mClassChoiceDialog->eventButtonSelected += MyGUI::newDelegate(this, &CharacterCreation::onClassChoice); + mClassChoiceDialog->setVisible(true); + if (mCreationStage < CSE_RaceChosen) + mCreationStage = CSE_RaceChosen; + break; - case GM_ClassPick: - MWBase::Environment::get().getWindowManager()->removeDialog(mPickClassDialog); - mPickClassDialog = 0; - mPickClassDialog = new PickClassDialog(); - mPickClassDialog->setNextButtonShow(mCreationStage >= CSE_ClassChosen); - mPickClassDialog->setClassId(mPlayerClass.mName); - mPickClassDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onPickClassDialogDone); - mPickClassDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onPickClassDialogBack); - mPickClassDialog->setVisible(true); - if (mCreationStage < CSE_RaceChosen) - mCreationStage = CSE_RaceChosen; - break; + case GM_ClassPick: + MWBase::Environment::get().getWindowManager()->removeDialog(mPickClassDialog); + mPickClassDialog = 0; + mPickClassDialog = new PickClassDialog(); + mPickClassDialog->setNextButtonShow(mCreationStage >= CSE_ClassChosen); + mPickClassDialog->setClassId(mPlayerClass.mName); + mPickClassDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onPickClassDialogDone); + mPickClassDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onPickClassDialogBack); + mPickClassDialog->setVisible(true); + if (mCreationStage < CSE_RaceChosen) + mCreationStage = CSE_RaceChosen; + break; - case GM_Birth: - MWBase::Environment::get().getWindowManager()->removeDialog(mBirthSignDialog); - mBirthSignDialog = 0; - mBirthSignDialog = new BirthDialog(); - mBirthSignDialog->setNextButtonShow(mCreationStage >= CSE_BirthSignChosen); - mBirthSignDialog->setBirthId(mPlayerBirthSignId); - mBirthSignDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onBirthSignDialogDone); - mBirthSignDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onBirthSignDialogBack); - mBirthSignDialog->setVisible(true); - if (mCreationStage < CSE_ClassChosen) - mCreationStage = CSE_ClassChosen; - break; + case GM_Birth: + MWBase::Environment::get().getWindowManager()->removeDialog(mBirthSignDialog); + mBirthSignDialog = 0; + mBirthSignDialog = new BirthDialog(); + mBirthSignDialog->setNextButtonShow(mCreationStage >= CSE_BirthSignChosen); + mBirthSignDialog->setBirthId(mPlayerBirthSignId); + mBirthSignDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onBirthSignDialogDone); + mBirthSignDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onBirthSignDialogBack); + mBirthSignDialog->setVisible(true); + if (mCreationStage < CSE_ClassChosen) + mCreationStage = CSE_ClassChosen; + break; - case GM_ClassCreate: - if (!mCreateClassDialog) - { - mCreateClassDialog = new CreateClassDialog(); - mCreateClassDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onCreateClassDialogDone); - mCreateClassDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onCreateClassDialogBack); - } - mCreateClassDialog->setNextButtonShow(mCreationStage >= CSE_ClassChosen); - mCreateClassDialog->setVisible(true); - if (mCreationStage < CSE_RaceChosen) - mCreationStage = CSE_RaceChosen; - break; - case GM_ClassGenerate: - mGenerateClassStep = 0; - mGenerateClass = ""; - mGenerateClassSpecializations[0] = 0; - mGenerateClassSpecializations[1] = 0; - mGenerateClassSpecializations[2] = 0; - showClassQuestionDialog(); - if (mCreationStage < CSE_RaceChosen) - mCreationStage = CSE_RaceChosen; - break; - case GM_Review: - MWBase::Environment::get().getWindowManager()->removeDialog(mReviewDialog); - mReviewDialog = 0; - mReviewDialog = new ReviewDialog(); - mReviewDialog->setPlayerName(mPlayerName); - mReviewDialog->setRace(mPlayerRaceId); - mReviewDialog->setClass(mPlayerClass); - mReviewDialog->setBirthSign(mPlayerBirthSignId); + case GM_ClassCreate: + if (!mCreateClassDialog) + { + mCreateClassDialog = new CreateClassDialog(); + mCreateClassDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onCreateClassDialogDone); + mCreateClassDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onCreateClassDialogBack); + } + mCreateClassDialog->setNextButtonShow(mCreationStage >= CSE_ClassChosen); + mCreateClassDialog->setVisible(true); + if (mCreationStage < CSE_RaceChosen) + mCreationStage = CSE_RaceChosen; + break; + case GM_ClassGenerate: + mGenerateClassStep = 0; + mGenerateClass = ""; + mGenerateClassSpecializations[0] = 0; + mGenerateClassSpecializations[1] = 0; + mGenerateClassSpecializations[2] = 0; + showClassQuestionDialog(); + if (mCreationStage < CSE_RaceChosen) + mCreationStage = CSE_RaceChosen; + break; + case GM_Review: + MWBase::Environment::get().getWindowManager()->removeDialog(mReviewDialog); + mReviewDialog = 0; + mReviewDialog = new ReviewDialog(); + mReviewDialog->setPlayerName(mPlayerName); + mReviewDialog->setRace(mPlayerRaceId); + mReviewDialog->setClass(mPlayerClass); + mReviewDialog->setBirthSign(mPlayerBirthSignId); - { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); - const MWMechanics::CreatureStats& stats = player.getClass().getCreatureStats(player); + { + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + const MWMechanics::CreatureStats& stats = player.getClass().getCreatureStats(player); - mReviewDialog->setHealth ( stats.getHealth() ); - mReviewDialog->setMagicka( stats.getMagicka() ); - mReviewDialog->setFatigue( stats.getFatigue() ); - } + mReviewDialog->setHealth ( stats.getHealth() ); + mReviewDialog->setMagicka( stats.getMagicka() ); + mReviewDialog->setFatigue( stats.getFatigue() ); + } - { - std::map attributes = MWBase::Environment::get().getWindowManager()->getPlayerAttributeValues(); - for (std::map::iterator it = attributes.begin(); - it != attributes.end(); ++it) { - mReviewDialog->setAttribute(static_cast (it->first), it->second); + std::map attributes = MWBase::Environment::get().getWindowManager()->getPlayerAttributeValues(); + for (std::map::iterator it = attributes.begin(); + it != attributes.end(); ++it) + { + mReviewDialog->setAttribute(static_cast (it->first), it->second); + } } - } - { - std::map skills = MWBase::Environment::get().getWindowManager()->getPlayerSkillValues(); - for (std::map::iterator it = skills.begin(); - it != skills.end(); ++it) { - mReviewDialog->setSkillValue(static_cast (it->first), it->second); + std::map skills = MWBase::Environment::get().getWindowManager()->getPlayerSkillValues(); + for (std::map::iterator it = skills.begin(); + it != skills.end(); ++it) + { + mReviewDialog->setSkillValue(static_cast (it->first), it->second); + } + mReviewDialog->configureSkills(MWBase::Environment::get().getWindowManager()->getPlayerMajorSkills(), MWBase::Environment::get().getWindowManager()->getPlayerMinorSkills()); } - mReviewDialog->configureSkills(MWBase::Environment::get().getWindowManager()->getPlayerMajorSkills(), MWBase::Environment::get().getWindowManager()->getPlayerMinorSkills()); - } - mReviewDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onReviewDialogDone); - mReviewDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onReviewDialogBack); - mReviewDialog->eventActivateDialog += MyGUI::newDelegate(this, &CharacterCreation::onReviewActivateDialog); - mReviewDialog->setVisible(true); - if (mCreationStage < CSE_BirthSignChosen) - mCreationStage = CSE_BirthSignChosen; - break; + mReviewDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onReviewDialogDone); + mReviewDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onReviewDialogBack); + mReviewDialog->eventActivateDialog += MyGUI::newDelegate(this, &CharacterCreation::onReviewActivateDialog); + mReviewDialog->setVisible(true); + if (mCreationStage < CSE_BirthSignChosen) + mCreationStage = CSE_BirthSignChosen; + break; + } + } + catch (std::exception& e) + { + std::cerr << "Failed to create chargen window: " << e.what() << std::endl; } } From c4866bdfc63e28ceff2573dabb643fafc4283360 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 13 Jul 2015 19:13:26 +0200 Subject: [PATCH 1811/3725] Disable mipmaps for GUI textures For some reason, the mipmap generator seems to be broken on Linux Intel graphics (works on Nvidia). This was breaking the scrollbar arrows, which are minified enough to show using a mipmap. --- components/myguiplatform/myguitexture.cpp | 2 ++ components/resource/texturemanager.cpp | 25 ++++++++++++++++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/components/myguiplatform/myguitexture.cpp b/components/myguiplatform/myguitexture.cpp index 0a846b227..50ac5c1f3 100644 --- a/components/myguiplatform/myguitexture.cpp +++ b/components/myguiplatform/myguitexture.cpp @@ -87,6 +87,8 @@ namespace osgMyGUI throw std::runtime_error("No texturemanager set"); mTexture = mTextureManager->getTexture2D(fname, osg::Texture2D::CLAMP_TO_EDGE, osg::Texture2D::CLAMP_TO_EDGE); + // disable mip-maps + mTexture->setFilter(osg::Texture2D::MIN_FILTER, osg::Texture2D::LINEAR); // FIXME mFormat = MyGUI::PixelFormat::R8G8B8; diff --git a/components/resource/texturemanager.cpp b/components/resource/texturemanager.cpp index 62cbd6bb3..ae8d16102 100644 --- a/components/resource/texturemanager.cpp +++ b/components/resource/texturemanager.cpp @@ -64,7 +64,30 @@ namespace Resource for (std::map >::iterator it = mTextures.begin(); it != mTextures.end(); ++it) { osg::ref_ptr tex = it->second; - tex->setFilter(osg::Texture::MIN_FILTER, mMinFilter); + + // Keep mip-mapping disabled if the texture creator explicitely requested it. + osg::Texture::FilterMode oldMin = tex->getFilter(osg::Texture::MIN_FILTER); + if (oldMin == osg::Texture::LINEAR || oldMin == osg::Texture::NEAREST) + { + osg::Texture::FilterMode newMin = osg::Texture::LINEAR; + switch (mMinFilter) + { + case osg::Texture::LINEAR: + case osg::Texture::LINEAR_MIPMAP_LINEAR: + case osg::Texture::LINEAR_MIPMAP_NEAREST: + newMin = osg::Texture::LINEAR; + break; + case osg::Texture::NEAREST: + case osg::Texture::NEAREST_MIPMAP_LINEAR: + case osg::Texture::NEAREST_MIPMAP_NEAREST: + newMin = osg::Texture::NEAREST; + break; + } + tex->setFilter(osg::Texture::MIN_FILTER, newMin); + } + else + tex->setFilter(osg::Texture::MIN_FILTER, mMinFilter); + tex->setFilter(osg::Texture::MAG_FILTER, mMagFilter); tex->setMaxAnisotropy(static_cast(mMaxAnisotropy)); } From b55a4999caf2150afa6bc26d3ccc303a684131a0 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Mon, 13 Jul 2015 22:37:14 +0300 Subject: [PATCH 1812/3725] Add NAME handling to DebugProfile and Filter records --- components/esm/debugprofile.cpp | 2 ++ components/esm/filter.cpp | 2 ++ 2 files changed, 4 insertions(+) diff --git a/components/esm/debugprofile.cpp b/components/esm/debugprofile.cpp index 6c05fac2a..9c8164d29 100644 --- a/components/esm/debugprofile.cpp +++ b/components/esm/debugprofile.cpp @@ -9,6 +9,7 @@ unsigned int ESM::DebugProfile::sRecordId = REC_DBGP; void ESM::DebugProfile::load (ESMReader& esm) { + mId = esm.getHNString ("NAME"); mDescription = esm.getHNString ("DESC"); mScriptText = esm.getHNString ("SCRP"); esm.getHNT (mFlags, "FLAG"); @@ -16,6 +17,7 @@ void ESM::DebugProfile::load (ESMReader& esm) void ESM::DebugProfile::save (ESMWriter& esm) const { + esm.writeHNCString ("NAME", mId); esm.writeHNCString ("DESC", mDescription); esm.writeHNCString ("SCRP", mScriptText); esm.writeHNT ("FLAG", mFlags); diff --git a/components/esm/filter.cpp b/components/esm/filter.cpp index a80427bbe..ee2c67869 100644 --- a/components/esm/filter.cpp +++ b/components/esm/filter.cpp @@ -9,12 +9,14 @@ unsigned int ESM::Filter::sRecordId = REC_FILT; void ESM::Filter::load (ESMReader& esm) { + mId = esm.getHNString ("NAME"); mFilter = esm.getHNString ("FILT"); mDescription = esm.getHNString ("DESC"); } void ESM::Filter::save (ESMWriter& esm) const { + esm.writeHNCString ("NAME", mId); esm.writeHNCString ("FILT", mFilter); esm.writeHNCString ("DESC", mDescription); } From de6dc21552d0a5c190f2930df6090fdaeb66dbe6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 13 Jul 2015 23:36:25 +0200 Subject: [PATCH 1813/3725] Create hardware cursors in advance (Fixes #2660) --- apps/openmw/mwgui/windowmanagerimp.cpp | 56 +++++++++++++------------ apps/openmw/mwgui/windowmanagerimp.hpp | 1 + components/sdlutil/sdlcursormanager.cpp | 13 ++---- components/sdlutil/sdlcursormanager.hpp | 6 +-- 4 files changed, 36 insertions(+), 40 deletions(-) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 582519b19..a2a826161 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -235,8 +235,9 @@ namespace MWGui MyGUI::InputManager::getInstance().eventChangeKeyFocus += MyGUI::newDelegate(this, &WindowManager::onKeyFocusChanged); + // Create all cursors in advance + createCursors(); onCursorChange(MyGUI::PointerManager::getInstance().getDefaultPointer()); - mCursorManager->setEnabled(true); // hide mygui's pointer @@ -1181,31 +1182,7 @@ namespace MWGui void WindowManager::onCursorChange(const std::string &name) { - if(!mCursorManager->cursorChanged(name)) - return; //the cursor manager doesn't want any more info about this cursor - //See if we can get the information we need out of the cursor resource - ResourceImageSetPointerFix* imgSetPtr = dynamic_cast(MyGUI::PointerManager::getInstance().getByName(name)); - if(imgSetPtr != NULL) - { - MyGUI::ResourceImageSet* imgSet = imgSetPtr->getImageSet(); - - std::string tex_name = imgSet->getIndexInfo(0,0).texture; - - osg::ref_ptr tex = mResourceSystem->getTextureManager()->getTexture2D(tex_name, osg::Texture::CLAMP, osg::Texture::CLAMP); - tex->setUnRefImageDataAfterApply(false); // FIXME? - - //everything looks good, send it to the cursor manager - if(tex.valid()) - { - Uint8 size_x = imgSetPtr->getSize().width; - Uint8 size_y = imgSetPtr->getSize().height; - Uint8 hotspot_x = imgSetPtr->getHotSpot().left; - Uint8 hotspot_y = imgSetPtr->getHotSpot().top; - int rotation = imgSetPtr->getRotation(); - - mCursorManager->receiveCursorInfo(name, rotation, tex->getImage(), size_x, size_y, hotspot_x, hotspot_y); - } - } + mCursorManager->cursorChanged(name); } void WindowManager::popGuiMode() @@ -1963,6 +1940,33 @@ namespace MWGui return Misc::ResourceHelpers::correctTexturePath(path, mResourceSystem->getVFS()); } + void WindowManager::createCursors() + { + MyGUI::ResourceManager::EnumeratorPtr enumerator = MyGUI::ResourceManager::getInstance().getEnumerator(); + while (enumerator.next()) + { + MyGUI::IResource* resource = enumerator.current().second; + ResourceImageSetPointerFix* imgSetPointer = dynamic_cast(resource); + if (!imgSetPointer) + continue; + std::string tex_name = imgSetPointer->getImageSet()->getIndexInfo(0,0).texture; + + osg::ref_ptr tex = mResourceSystem->getTextureManager()->getTexture2D(tex_name, osg::Texture::CLAMP, osg::Texture::CLAMP); + + if(tex.valid()) + { + //everything looks good, send it to the cursor manager + Uint8 size_x = imgSetPointer->getSize().width; + Uint8 size_y = imgSetPointer->getSize().height; + Uint8 hotspot_x = imgSetPointer->getHotSpot().left; + Uint8 hotspot_y = imgSetPointer->getHotSpot().top; + int rotation = imgSetPointer->getRotation(); + + mCursorManager->createCursor(imgSetPointer->getResourceName(), rotation, tex->getImage(), size_x, size_y, hotspot_x, hotspot_y); + } + } + } + void WindowManager::createTextures() { { diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index c275a9f62..e6c8d0a81 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -511,6 +511,7 @@ namespace MWGui void onClipboardRequested(const std::string& _type, std::string& _data); void createTextures(); + void createCursors(); void setMenuTransparency(float value); }; } diff --git a/components/sdlutil/sdlcursormanager.cpp b/components/sdlutil/sdlcursormanager.cpp index a8a48f4f8..d8d4b0b50 100644 --- a/components/sdlutil/sdlcursormanager.cpp +++ b/components/sdlutil/sdlcursormanager.cpp @@ -175,23 +175,16 @@ namespace SDLUtil } } - bool SDLCursorManager::cursorChanged(const std::string& name) + void SDLCursorManager::cursorChanged(const std::string& name) { mCurrentCursor = name; CursorMap::const_iterator curs_iter = mCursorMap.find(name); - //we have this cursor if(curs_iter != mCursorMap.end()) { + //we have this cursor _setGUICursor(name); - - return false; - } - else - { - //they should get back to us with more info - return true; } } @@ -200,7 +193,7 @@ namespace SDLUtil SDL_SetCursor(mCursorMap.find(name)->second); } - void SDLCursorManager::receiveCursorInfo(const std::string& name, int rotDegrees, osg::Image* image, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y) + void SDLCursorManager::createCursor(const std::string& name, int rotDegrees, osg::Image* image, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y) { _createCursorFromResource(name, rotDegrees, image, size_x, size_y, hotspot_x, hotspot_y); } diff --git a/components/sdlutil/sdlcursormanager.hpp b/components/sdlutil/sdlcursormanager.hpp index 646f548e3..0db578039 100644 --- a/components/sdlutil/sdlcursormanager.hpp +++ b/components/sdlutil/sdlcursormanager.hpp @@ -27,11 +27,9 @@ namespace SDLUtil /// \brief Tell the manager that the cursor has changed, giving the /// name of the cursor we changed to ("arrow", "ibeam", etc) - /// \return Whether the manager is interested in more information about the cursor - virtual bool cursorChanged(const std::string &name); + virtual void cursorChanged(const std::string &name); - /// \brief Follow up a cursorChanged() call with enough info to create an cursor. - virtual void receiveCursorInfo(const std::string &name, int rotDegrees, osg::Image* image, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y); + virtual void createCursor(const std::string &name, int rotDegrees, osg::Image* image, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y); private: void _createCursorFromResource(const std::string &name, int rotDegrees, osg::Image* image, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y); From 2202973c2462b9299480c9106904383a113fb89d Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 14 Jul 2015 10:05:45 +0200 Subject: [PATCH 1814/3725] replaced the script subview status bar with a bottom box (including a status bar) --- apps/opencs/view/world/dialoguesubview.cpp | 2 -- apps/opencs/view/world/scriptsubview.cpp | 33 +++++++++----------- apps/opencs/view/world/scriptsubview.hpp | 6 ++-- apps/opencs/view/world/tablebottombox.cpp | 36 ++++++++++++++++++---- apps/opencs/view/world/tablebottombox.hpp | 13 ++++++-- 5 files changed, 59 insertions(+), 31 deletions(-) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index edd9cc1e2..5a44708c1 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -857,8 +857,6 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, // bottom box mBottom = new TableBottomBox (creatorFactory, document, id, this); - mBottom->setSizePolicy (QSizePolicy::Ignored, QSizePolicy::Fixed); - connect (mBottom, SIGNAL (requestFocus (const std::string&)), this, SLOT (requestFocus (const std::string&))); diff --git a/apps/opencs/view/world/scriptsubview.cpp b/apps/opencs/view/world/scriptsubview.cpp index 0f5d5014a..f65f77285 100644 --- a/apps/opencs/view/world/scriptsubview.cpp +++ b/apps/opencs/view/world/scriptsubview.cpp @@ -4,7 +4,6 @@ #include #include -#include #include "../../model/doc/document.hpp" #include "../../model/world/universalid.hpp" @@ -16,6 +15,8 @@ #include "scriptedit.hpp" #include "recordbuttonbar.hpp" +#include "tablebottombox.hpp" +#include "genericcreator.hpp" void CSVWorld::ScriptSubView::addButtonBar() { @@ -33,7 +34,7 @@ void CSVWorld::ScriptSubView::addButtonBar() } CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) -: SubView (id), mDocument (document), mColumn (-1), mBottom(0), mStatus(0), mButtons (0), +: SubView (id), mDocument (document), mColumn (-1), mBottom(0), mButtons (0), mCommandDispatcher (document, CSMWorld::UniversalId::getParentType (id.getType())) { std::vector selection (1, id.getId()); @@ -65,18 +66,13 @@ CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc: if (CSMSettings::UserSettings::instance().setting ("script-editor/toolbar", QString("true")) == "true") addButtonBar(); - // status bar - QStatusBar *statusBar = new QStatusBar(mBottom); - mStatus = new QLabel(mBottom); - statusBar->addWidget (mStatus); + // bottom box + mBottom = new TableBottomBox (CreatorFactory(), document, id, this); - mBottom = new QWidget(this); - QStackedLayout *bottmLayout = new QStackedLayout(mBottom); - bottmLayout->setContentsMargins (0, 0, 0, 0); - bottmLayout->addWidget (statusBar); - mBottom->setLayout (bottmLayout); + connect (mBottom, SIGNAL (requestFocus (const std::string&)), + this, SLOT (requestFocus (const std::string&))); - mLayout.addWidget (mBottom, 0); + mLayout.addWidget (mBottom); // signals connect (mEditor, SIGNAL (textChanged()), this, SLOT (textChanged())); @@ -124,14 +120,15 @@ void CSVWorld::ScriptSubView::updateUserSetting (const QString& name, const QStr mButtons->updateUserSetting (name, value); } -void CSVWorld::ScriptSubView::updateStatusBar () +void CSVWorld::ScriptSubView::setStatusBar (bool show) { - std::ostringstream stream; - - stream << "(" << mEditor->textCursor().blockNumber() + 1 << ", " - << mEditor->textCursor().columnNumber() + 1 << ")"; + mBottom->setStatusBar (show); +} - mStatus->setText (QString::fromUtf8 (stream.str().c_str())); +void CSVWorld::ScriptSubView::updateStatusBar () +{ + mBottom->positionChanged (mEditor->textCursor().blockNumber() + 1, + mEditor->textCursor().columnNumber() + 1); } void CSVWorld::ScriptSubView::setEditLock (bool locked) diff --git a/apps/opencs/view/world/scriptsubview.hpp b/apps/opencs/view/world/scriptsubview.hpp index 370754ebe..09f7907ee 100644 --- a/apps/opencs/view/world/scriptsubview.hpp +++ b/apps/opencs/view/world/scriptsubview.hpp @@ -25,6 +25,7 @@ namespace CSVWorld { class ScriptEdit; class RecordButtonBar; + class TableBottomBox; class ScriptSubView : public CSVDoc::SubView { @@ -34,8 +35,7 @@ namespace CSVWorld CSMDoc::Document& mDocument; CSMWorld::IdTable *mModel; int mColumn; - QWidget *mBottom; - QLabel *mStatus; + TableBottomBox *mBottom; RecordButtonBar *mButtons; CSMWorld::CommandDispatcher mCommandDispatcher; QVBoxLayout mLayout; @@ -54,6 +54,8 @@ namespace CSVWorld virtual void updateUserSetting (const QString& name, const QStringList& value); + virtual void setStatusBar (bool show); + public slots: void textChanged(); diff --git a/apps/opencs/view/world/tablebottombox.cpp b/apps/opencs/view/world/tablebottombox.cpp index dc3a6cc76..12226450b 100644 --- a/apps/opencs/view/world/tablebottombox.cpp +++ b/apps/opencs/view/world/tablebottombox.cpp @@ -35,15 +35,23 @@ void CSVWorld::TableBottomBox::updateStatus() } } + if (mHasPosition) + { + if (!first) + stream << " -- "; + + stream << "(" << mRow << ", " << mColumn << ")"; + } + mStatus->setText (QString::fromUtf8 (stream.str().c_str())); } } -CSVWorld::TableBottomBox::TableBottomBox (const CreatorFactoryBase& creatorFactory, - CSMDoc::Document& document, - const CSMWorld::UniversalId& id, +CSVWorld::TableBottomBox::TableBottomBox (const CreatorFactoryBase& creatorFactory, + CSMDoc::Document& document, + const CSMWorld::UniversalId& id, QWidget *parent) -: QWidget (parent), mShowStatusBar (false), mCreating (false) +: QWidget (parent), mShowStatusBar (false), mCreating (false), mHasPosition (false) { for (int i=0; i<4; ++i) mStatusCount[i] = 0; @@ -74,6 +82,8 @@ CSVWorld::TableBottomBox::TableBottomBox (const CreatorFactoryBase& creatorFacto connect (mCreator, SIGNAL (requestFocus (const std::string&)), this, SIGNAL (requestFocus (const std::string&))); } + + setSizePolicy (QSizePolicy::Ignored, QSizePolicy::Fixed); } void CSVWorld::TableBottomBox::setEditLock (bool locked) @@ -152,6 +162,20 @@ void CSVWorld::TableBottomBox::tableSizeChanged (int size, int deleted, int modi updateStatus(); } +void CSVWorld::TableBottomBox::positionChanged (int row, int column) +{ + mRow = row; + mColumn = column; + mHasPosition = true; + updateStatus(); +} + +void CSVWorld::TableBottomBox::noMorePosition() +{ + mHasPosition = false; + updateStatus(); +} + void CSVWorld::TableBottomBox::createRequest() { mCreator->reset(); @@ -162,8 +186,8 @@ void CSVWorld::TableBottomBox::createRequest() mCreator->focus(); } -void CSVWorld::TableBottomBox::cloneRequest(const std::string& id, - const CSMWorld::UniversalId::Type type) +void CSVWorld::TableBottomBox::cloneRequest(const std::string& id, + const CSMWorld::UniversalId::Type type) { mCreator->reset(); mCreator->cloneMode(id, type); diff --git a/apps/opencs/view/world/tablebottombox.hpp b/apps/opencs/view/world/tablebottombox.hpp index a7d009c42..6e68553bc 100644 --- a/apps/opencs/view/world/tablebottombox.hpp +++ b/apps/opencs/view/world/tablebottombox.hpp @@ -30,6 +30,9 @@ namespace CSVWorld Creator *mCreator; bool mCreating; QStackedLayout *mLayout; + bool mHasPosition; + int mRow; + int mColumn; private: @@ -41,9 +44,9 @@ namespace CSVWorld public: - TableBottomBox (const CreatorFactoryBase& creatorFactory, - CSMDoc::Document& document, - const CSMWorld::UniversalId& id, + TableBottomBox (const CreatorFactoryBase& creatorFactory, + CSMDoc::Document& document, + const CSMWorld::UniversalId& id, QWidget *parent = 0); virtual ~TableBottomBox(); @@ -77,6 +80,10 @@ namespace CSVWorld /// \param deleted Number of deleted records /// \param modified Number of added and modified records + void positionChanged (int row, int column); + + void noMorePosition(); + void createRequest(); void cloneRequest(const std::string& id, const CSMWorld::UniversalId::Type type); From 0860c27b039465e4505f5211a9bcbb9ddedf773e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 14 Jul 2015 11:49:41 +0200 Subject: [PATCH 1815/3725] improving consistency of subview layouts --- apps/opencs/view/tools/searchsubview.cpp | 20 +++++++++----------- apps/opencs/view/world/previewsubview.cpp | 2 -- apps/opencs/view/world/scenesubview.cpp | 2 -- apps/opencs/view/world/tablesubview.cpp | 3 --- 4 files changed, 9 insertions(+), 18 deletions(-) diff --git a/apps/opencs/view/tools/searchsubview.cpp b/apps/opencs/view/tools/searchsubview.cpp index dc670af40..8b35db6ae 100644 --- a/apps/opencs/view/tools/searchsubview.cpp +++ b/apps/opencs/view/tools/searchsubview.cpp @@ -16,7 +16,7 @@ void CSVTools::SearchSubView::replace (bool selection) { if (mLocked) return; - + std::vector indices = mTable->getReplaceIndices (selection); std::string replace = mSearchBox.getReplaceText(); @@ -29,7 +29,7 @@ void CSVTools::SearchSubView::replace (bool selection) CSMTools::Search search (mSearch); CSMWorld::IdTableBase *currentTable = 0; - + // We are running through the indices in reverse order to avoid messing up multiple results // in a single string. for (std::vector::const_reverse_iterator iter (indices.rbegin()); iter!=indices.rend(); ++iter) @@ -46,7 +46,7 @@ void CSVTools::SearchSubView::replace (bool selection) search.configure (table); currentTable = table; } - + std::string hint = model.getHint (*iter); if (search.verify (mDocument, table, id, hint)) @@ -63,7 +63,7 @@ void CSVTools::SearchSubView::replace (bool selection) void CSVTools::SearchSubView::showEvent (QShowEvent *event) { CSVDoc::SubView::showEvent (event); - mSearchBox.focus(); + mSearchBox.focus(); } CSVTools::SearchSubView::SearchSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) @@ -71,25 +71,23 @@ CSVTools::SearchSubView::SearchSubView (const CSMWorld::UniversalId& id, CSMDoc: { QVBoxLayout *layout = new QVBoxLayout; - layout->setContentsMargins (QMargins (0, 0, 0, 0)); - layout->addWidget (&mSearchBox); - + layout->addWidget (mTable = new ReportTable (document, id, true), 2); QWidget *widget = new QWidget; - + widget->setLayout (layout); setWidget (widget); stateChanged (document.getState(), &document); - + connect (mTable, SIGNAL (editRequest (const CSMWorld::UniversalId&, const std::string&)), SIGNAL (focusId (const CSMWorld::UniversalId&, const std::string&))); connect (mTable, SIGNAL (replaceRequest()), this, SLOT (replaceRequest())); - + connect (&document, SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (stateChanged (int, CSMDoc::Document *))); @@ -124,7 +122,7 @@ void CSVTools::SearchSubView::startSearch (const CSMTools::Search& search) mSearch = search; mSearch.setPadding (paddingBefore, paddingAfter); - + mTable->clear(); mDocument.runSearch (getUniversalId(), mSearch); } diff --git a/apps/opencs/view/world/previewsubview.cpp b/apps/opencs/view/world/previewsubview.cpp index 1c2d6b95c..756e79fe6 100644 --- a/apps/opencs/view/world/previewsubview.cpp +++ b/apps/opencs/view/world/previewsubview.cpp @@ -13,8 +13,6 @@ CSVWorld::PreviewSubView::PreviewSubView (const CSMWorld::UniversalId& id, CSMDo { QHBoxLayout *layout = new QHBoxLayout; - layout->setContentsMargins (QMargins (0, 0, 0, 0)); - if (document.getData().getReferenceables().searchId (id.getId())==-1) { std::string referenceableId = diff --git a/apps/opencs/view/world/scenesubview.cpp b/apps/opencs/view/world/scenesubview.cpp index 397d24929..b7a795e23 100644 --- a/apps/opencs/view/world/scenesubview.cpp +++ b/apps/opencs/view/world/scenesubview.cpp @@ -31,8 +31,6 @@ CSVWorld::SceneSubView::SceneSubView (const CSMWorld::UniversalId& id, CSMDoc::D { QVBoxLayout *layout = new QVBoxLayout; - layout->setContentsMargins (QMargins (0, 0, 0, 0)); - layout->addWidget (mBottom = new TableBottomBox (NullCreatorFactory(), document, id, this), 0); mLayout->setContentsMargins (QMargins (0, 0, 0, 0)); diff --git a/apps/opencs/view/world/tablesubview.cpp b/apps/opencs/view/world/tablesubview.cpp index 75671a50c..e2c9e2fb1 100644 --- a/apps/opencs/view/world/tablesubview.cpp +++ b/apps/opencs/view/world/tablesubview.cpp @@ -23,8 +23,6 @@ CSVWorld::TableSubView::TableSubView (const CSMWorld::UniversalId& id, CSMDoc::D { QVBoxLayout *layout = new QVBoxLayout; - layout->setContentsMargins (QMargins (0, 0, 0, 0)); - layout->addWidget (mBottom = new TableBottomBox (creatorFactory, document, id, this), 0); @@ -166,4 +164,3 @@ bool CSVWorld::TableSubView::eventFilter (QObject* object, QEvent* event) } return false; } - From cf1fb76bb4cdb3e08f8b4a71e682681a811fe64b Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 14 Jul 2015 13:34:13 +0200 Subject: [PATCH 1816/3725] fixed deleted button sensitivity state --- apps/opencs/view/world/recordbuttonbar.cpp | 29 +++++++++++----------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/apps/opencs/view/world/recordbuttonbar.cpp b/apps/opencs/view/world/recordbuttonbar.cpp index 63c0dd0a1..9cae0d0c9 100644 --- a/apps/opencs/view/world/recordbuttonbar.cpp +++ b/apps/opencs/view/world/recordbuttonbar.cpp @@ -17,18 +17,17 @@ void CSVWorld::RecordButtonBar::updateModificationButtons() mCloneButton->setDisabled (createAndDeleteDisabled); mAddButton->setDisabled (createAndDeleteDisabled); - mDeleteButton->setDisabled (createAndDeleteDisabled); bool commandDisabled = !mCommandDispatcher || mLocked; - + mRevertButton->setDisabled (commandDisabled); - mDeleteButton->setDisabled (commandDisabled); + mDeleteButton->setDisabled (commandDisabled || createAndDeleteDisabled); } void CSVWorld::RecordButtonBar::updatePrevNextButtons() { int rows = mTable.rowCount(); - + if (rows<=1) { mPrevButton->setDisabled (true); @@ -62,12 +61,12 @@ CSVWorld::RecordButtonBar::RecordButtonBar (const CSMWorld::UniversalId& id, mPrevButton->setIcon(QIcon(":/go-previous.png")); mPrevButton->setToolTip ("Switch to previous record"); buttonsLayout->addWidget (mPrevButton, 0); - + mNextButton = new QToolButton (this); mNextButton->setIcon(QIcon(":/go-next.png")); mNextButton->setToolTip ("Switch to next record"); buttonsLayout->addWidget (mNextButton, 1); - + buttonsLayout->addStretch(2); // optional buttons of the right section @@ -94,22 +93,22 @@ CSVWorld::RecordButtonBar::RecordButtonBar (const CSMWorld::UniversalId& id, mCloneButton->setIcon(QIcon(":/edit-clone.png")); mCloneButton->setToolTip ("Clone record"); buttonsLayout->addWidget(mCloneButton); - + mAddButton = new QToolButton (this); mAddButton->setIcon(QIcon(":/add.png")); mAddButton->setToolTip ("Add new record"); buttonsLayout->addWidget(mAddButton); - + mDeleteButton = new QToolButton (this); mDeleteButton->setIcon(QIcon(":/edit-delete.png")); mDeleteButton->setToolTip ("Delete record"); buttonsLayout->addWidget(mDeleteButton); - + mRevertButton = new QToolButton (this); mRevertButton->setIcon(QIcon(":/edit-undo.png")); mRevertButton->setToolTip ("Revert record"); buttonsLayout->addWidget(mRevertButton); - + setLayout (buttonsLayout); // connections @@ -132,7 +131,7 @@ CSVWorld::RecordButtonBar::RecordButtonBar (const CSMWorld::UniversalId& id, this, SLOT (rowNumberChanged (const QModelIndex&, int, int))); connect (&mTable, SIGNAL (rowsRemoved (const QModelIndex&, int, int)), this, SLOT (rowNumberChanged (const QModelIndex&, int, int))); - + updateModificationButtons(); updatePrevNextButtons(); } @@ -170,7 +169,7 @@ void CSVWorld::RecordButtonBar::cloneRequest() } void CSVWorld::RecordButtonBar::nextId() -{ +{ int newRow = mTable.getModelIndex (mId.getId(), 0).row() + 1; if (newRow >= mTable.rowCount()) @@ -180,8 +179,8 @@ void CSVWorld::RecordButtonBar::nextId() newRow = 0; else return; - } - + } + emit switchToRow (newRow); } @@ -197,7 +196,7 @@ void CSVWorld::RecordButtonBar::prevId() else return; } - + emit switchToRow (newRow); } From df027b3498f1730cfda5daed06052c04a64456d9 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 14 Jul 2015 13:52:48 +0200 Subject: [PATCH 1817/3725] hooked up script subview buttons to bottom box (enables add and clone) --- apps/opencs/view/world/scriptsubview.cpp | 15 +++++++++------ apps/opencs/view/world/scriptsubview.hpp | 2 ++ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/apps/opencs/view/world/scriptsubview.cpp b/apps/opencs/view/world/scriptsubview.cpp index f65f77285..181400c88 100644 --- a/apps/opencs/view/world/scriptsubview.cpp +++ b/apps/opencs/view/world/scriptsubview.cpp @@ -23,7 +23,7 @@ void CSVWorld::ScriptSubView::addButtonBar() if (mButtons) return; - mButtons = new RecordButtonBar (getUniversalId(), *mModel, 0, &mCommandDispatcher, this); + mButtons = new RecordButtonBar (getUniversalId(), *mModel, mBottom, &mCommandDispatcher, this); mLayout.insertWidget (1, mButtons); @@ -61,16 +61,14 @@ CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc: throw std::logic_error ("Can't find script column"); mEditor->setPlainText (mModel->data (mModel->getModelIndex (id.getId(), mColumn)).toString()); + // bottom box and buttons + mBottom = new TableBottomBox (CreatorFactory(), document, id, this); - // buttons if (CSMSettings::UserSettings::instance().setting ("script-editor/toolbar", QString("true")) == "true") addButtonBar(); - // bottom box - mBottom = new TableBottomBox (CreatorFactory(), document, id, this); - connect (mBottom, SIGNAL (requestFocus (const std::string&)), - this, SLOT (requestFocus (const std::string&))); + this, SLOT (switchToId (const std::string&))); mLayout.addWidget (mBottom); @@ -216,3 +214,8 @@ void CSVWorld::ScriptSubView::switchToRow (int row) std::vector selection (1, id); mCommandDispatcher.setSelection (selection); } + +void CSVWorld::ScriptSubView::switchToId (const std::string& id) +{ + switchToRow (mModel->getModelIndex (id, 0).row()); +} diff --git a/apps/opencs/view/world/scriptsubview.hpp b/apps/opencs/view/world/scriptsubview.hpp index 09f7907ee..6e5276c68 100644 --- a/apps/opencs/view/world/scriptsubview.hpp +++ b/apps/opencs/view/world/scriptsubview.hpp @@ -69,6 +69,8 @@ namespace CSVWorld void updateStatusBar(); void switchToRow (int row); + + void switchToId (const std::string& id); }; } From 90af7060ea2c5a17e0fdbcf00d7e926a0e232a86 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Tue, 14 Jul 2015 16:26:32 +0200 Subject: [PATCH 1818/3725] Forgot an echo --- CI/before_script.msvc.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CI/before_script.msvc.sh b/CI/before_script.msvc.sh index d23e3013f..cd47cbf8d 100644 --- a/CI/before_script.msvc.sh +++ b/CI/before_script.msvc.sh @@ -495,6 +495,8 @@ fi add_cmake_opts -DDESIRED_QT_VERSION=5 \ -DQT_QMAKE_EXECUTABLE="$QT_SDK/bin/qmake.exe" \ -DCMAKE_PREFIX_PATH="$QT_SDK" + + echo AppVeyor. fi } cd $DEPS From 73731d27e9e32f26e154b16fd1eb4543f84ea917 Mon Sep 17 00:00:00 2001 From: Koncord Date: Tue, 14 Jul 2015 23:54:47 +0900 Subject: [PATCH 1819/3725] Add ${MYGUI_LIBRARIES} to components/CMakeLists.txt --- components/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 3224d0989..d91bb5c30 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -180,6 +180,7 @@ target_link_libraries(components ${SDL2_LIBRARY} # For MyGUI platform ${OPENGL_gl_LIBRARY} + ${MYGUI_LIBRARIES} ) if (WIN32) From 5e623a2a1d06d5679f214cad95123a1d3bd88b34 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Tue, 14 Jul 2015 16:18:33 +0300 Subject: [PATCH 1820/3725] Rework RefIdData code. Update the index map when a new record is loaded --- apps/opencs/model/world/refiddata.cpp | 30 +++++++++-- apps/opencs/model/world/refiddata.hpp | 73 +++++++++++---------------- 2 files changed, 55 insertions(+), 48 deletions(-) diff --git a/apps/opencs/model/world/refiddata.cpp b/apps/opencs/model/world/refiddata.cpp index 68f3fc4ad..e7b36015e 100644 --- a/apps/opencs/model/world/refiddata.cpp +++ b/apps/opencs/model/world/refiddata.cpp @@ -3,10 +3,20 @@ #include -#include - CSMWorld::RefIdDataContainerBase::~RefIdDataContainerBase() {} + +std::string CSMWorld::RefIdData::getRecordId(const CSMWorld::RefIdData::LocalIndex &index) const +{ + std::map::const_iterator found = + mRecordContainers.find (index.second); + + if (found == mRecordContainers.end()) + throw std::logic_error ("invalid local index type"); + + return found->second->getId(index.first); +} + CSMWorld::RefIdData::RefIdData() { mRecordContainers.insert (std::make_pair (UniversalId::Type_Activator, &mActivators)); @@ -167,9 +177,21 @@ void CSMWorld::RefIdData::load (ESM::ESMReader& reader, bool base, CSMWorld::Uni mRecordContainers.find (type); if (found == mRecordContainers.end()) - throw std::logic_error ("Invalid type for an Object (Reference ID)"); + throw std::logic_error ("Invalid Referenceable ID type"); - found->second->load(reader, base); + int index = found->second->load(reader, base); + if (index != -1) + { + LocalIndex localIndex = LocalIndex(index, type); + if (base && getRecord(localIndex).mState == RecordBase::State_Deleted) + { + erase(localIndex, 1); + } + else + { + mIndex[Misc::StringUtils::lowerCase(getRecordId(localIndex))] = localIndex; + } + } } void CSMWorld::RefIdData::erase (const LocalIndex& index, int count) diff --git a/apps/opencs/model/world/refiddata.hpp b/apps/opencs/model/world/refiddata.hpp index 17d913911..195244ba8 100644 --- a/apps/opencs/model/world/refiddata.hpp +++ b/apps/opencs/model/world/refiddata.hpp @@ -25,6 +25,8 @@ #include #include +#include + #include "record.hpp" #include "universalid.hpp" @@ -49,7 +51,8 @@ namespace CSMWorld virtual void insertRecord (RecordBase& record) = 0; - virtual void load (ESM::ESMReader& reader, bool base) = 0; + virtual int load (ESM::ESMReader& reader, bool base) = 0; + ///< \return index of a loaded record or -1 if no record was loaded virtual void erase (int index, int count) = 0; @@ -73,7 +76,8 @@ namespace CSMWorld virtual void insertRecord (RecordBase& record); - virtual void load (ESM::ESMReader& reader, bool base); + virtual int load (ESM::ESMReader& reader, bool base); + ///< \return index of a loaded record or -1 if no record was loaded virtual void erase (int index, int count); @@ -122,15 +126,16 @@ namespace CSMWorld } template - void RefIdDataContainer::load (ESM::ESMReader& reader, bool base) + int RefIdDataContainer::load (ESM::ESMReader& reader, bool base) { RecordT record; record.load(reader); - typename std::vector >::iterator found = mContainer.begin(); - for (; found != mContainer.end(); ++found) + int index = 0; + int numRecords = static_cast(mContainer.size()); + for (; index < numRecords; ++index) { - if (found->get().mId == record.mId) + if (Misc::StringUtils::ciEqual(mContainer[index].get().mId, record.mId)) { break; } @@ -138,26 +143,21 @@ namespace CSMWorld if (record.mIsDeleted) { - if (found == mContainer.end()) + if (index == numRecords) { // deleting a record that does not exist // ignore it for now /// \todo report the problem to the user - return; + return -1; } - if (base) - { - mContainer.erase(found); - } - else - { - found->mState = RecordBase::State_Deleted; - } + // Flag the record as Deleted even for a base content file. + // RefIdData is responsible for its erasure. + mContainer[index].mState = RecordBase::State_Deleted; } else { - if (found == mContainer.end()) + if (index == numRecords) { appendRecord(record.mId, base); if (base) @@ -169,20 +169,13 @@ namespace CSMWorld mContainer.back().mModified = record; } } - else + else if (!base) { - if (!base) - { - if (found->mState == RecordBase::State_Erased) - { - throw std::logic_error("Attempt to access a deleted record"); - } - - found->mState = RecordBase::State_Modified; - found->mModified = record; - } + mContainer[index].setModified(record); } } + + return index; } template @@ -204,25 +197,15 @@ namespace CSMWorld void RefIdDataContainer::save (int index, ESM::ESMWriter& writer) const { Record record = mContainer.at(index); - RecordT esmRecord; + RecordT esmRecord = record.get(); - switch (record.mState) + if (record.isModified() || record.mState == RecordBase::State_Deleted) { - case RecordBase::State_Modified: - case RecordBase::State_ModifiedOnly: - esmRecord = record.mModified; - break; - case RecordBase::State_Deleted: - esmRecord = record.mBase; - esmRecord.mIsDeleted = true; - break; - default: - break; + esmRecord.mIsDeleted = (record.mState == RecordBase::State_Deleted); + writer.startRecord(esmRecord.sRecordId); + esmRecord.save(writer); + writer.endRecord(esmRecord.sRecordId); } - - writer.startRecord(esmRecord.sRecordId); - esmRecord.save(writer); - writer.endRecord(esmRecord.sRecordId); } @@ -262,6 +245,8 @@ namespace CSMWorld void erase (const LocalIndex& index, int count); ///< Must not spill over into another type. + std::string getRecordId(const LocalIndex &index) const; + public: RefIdData(); From a1389b87bacd08f54c4c146c7a0b6d1ed51edc54 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Tue, 14 Jul 2015 23:31:16 +0300 Subject: [PATCH 1821/3725] Return a correct index for a loaded record that was deleted --- apps/opencs/model/world/idcollection.hpp | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/apps/opencs/model/world/idcollection.hpp b/apps/opencs/model/world/idcollection.hpp index 41ce59702..d08abce5b 100644 --- a/apps/opencs/model/world/idcollection.hpp +++ b/apps/opencs/model/world/idcollection.hpp @@ -61,22 +61,14 @@ namespace CSMWorld if (base) { removeRows (index, 1); - } - else - { - Record baseRecord = getRecord (index); - baseRecord.mState = RecordBase::State_Deleted; - this->setRecord (index, baseRecord); + return -1; } - return -1; + Record baseRecord = getRecord (index); + baseRecord.mState = RecordBase::State_Deleted; + setRecord (index, baseRecord); + return index; } - // - //if (index != -1) - //{ - // ESXRecordT existedRecord = getRecord(index).get(); - // IdAccessorT().getId(record) = IdAccessorT().getId(existedRecord); - //} return load (record, base, index); } From 335ef97cf561e4655363e16041aaf119cde375db Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 9 Jul 2015 18:47:11 +0200 Subject: [PATCH 1822/3725] Rename Animation::Group to Animation::BlendMask The old naming is problematic, because the term group was being used for another feature (text key groups) already. --- apps/openmw/mwmechanics/character.cpp | 70 +++++++++++------------ apps/openmw/mwrender/animation.cpp | 42 +++++++------- apps/openmw/mwrender/animation.hpp | 30 +++++----- apps/openmw/mwrender/characterpreview.cpp | 6 +- 4 files changed, 74 insertions(+), 74 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 4b2ce9f4c..bd15b6a73 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -251,26 +251,26 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat { mHitState = CharState_KnockOut; mCurrentHit = "knockout"; - mAnimation->play(mCurrentHit, Priority_Knockdown, MWRender::Animation::Group_All, false, 1, "start", "stop", 0.0f, ~0ul); + mAnimation->play(mCurrentHit, Priority_Knockdown, MWRender::Animation::BlendMask_All, false, 1, "start", "stop", 0.0f, ~0ul); mPtr.getClass().getCreatureStats(mPtr).setKnockedDown(true); } else if(knockdown) { mHitState = CharState_KnockDown; mCurrentHit = "knockdown"; - mAnimation->play(mCurrentHit, Priority_Knockdown, MWRender::Animation::Group_All, true, 1, "start", "stop", 0.0f, 0); + mAnimation->play(mCurrentHit, Priority_Knockdown, MWRender::Animation::BlendMask_All, true, 1, "start", "stop", 0.0f, 0); } else if (recovery) { mHitState = CharState_Hit; mCurrentHit = chooseRandomGroup("hit"); - mAnimation->play(mCurrentHit, Priority_Hit, MWRender::Animation::Group_All, true, 1, "start", "stop", 0.0f, 0); + mAnimation->play(mCurrentHit, Priority_Hit, MWRender::Animation::BlendMask_All, true, 1, "start", "stop", 0.0f, 0); } else if (block) { mHitState = CharState_Block; mCurrentHit = "shield"; - mAnimation->play(mCurrentHit, Priority_Hit, MWRender::Animation::Group_All, true, 1, "block start", "block stop", 0.0f, 0); + mAnimation->play(mCurrentHit, Priority_Hit, MWRender::Animation::BlendMask_All, true, 1, "block start", "block stop", 0.0f, 0); } // Cancel upper body animations @@ -303,7 +303,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat { mHitState = CharState_KnockDown; mAnimation->disable(mCurrentHit); - mAnimation->play(mCurrentHit, Priority_Knockdown, MWRender::Animation::Group_All, true, 1, "loop stop", "stop", 0.0f, 0); + mAnimation->play(mCurrentHit, Priority_Knockdown, MWRender::Animation::BlendMask_All, true, 1, "loop stop", "stop", 0.0f, 0); } } @@ -314,7 +314,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat if(force && mJumpState != JumpState_None) { std::string jump; - MWRender::Animation::Group jumpgroup = MWRender::Animation::Group_All; + MWRender::Animation::BlendMask jumpmask = MWRender::Animation::BlendMask_All; if(mJumpState != JumpState_None) { jump = "jump"; @@ -323,7 +323,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat jump += weap->shortgroup; if(!mAnimation->hasAnimation(jump)) { - jumpgroup = MWRender::Animation::Group_LowerBody; + jumpmask = MWRender::Animation::BlendMask_LowerBody; jump = "jump"; } } @@ -336,7 +336,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat mAnimation->disable(mCurrentJump); mCurrentJump = jump; if (mAnimation->hasAnimation("jump")) - mAnimation->play(mCurrentJump, Priority_Jump, jumpgroup, false, + mAnimation->play(mCurrentJump, Priority_Jump, jumpmask, false, 1.0f, ((mode!=2)?"start":"loop start"), "stop", 0.0f, ~0ul); } else @@ -344,7 +344,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat mAnimation->disable(mCurrentJump); mCurrentJump.clear(); if (mAnimation->hasAnimation("jump")) - mAnimation->play(jump, Priority_Jump, jumpgroup, true, + mAnimation->play(jump, Priority_Jump, jumpmask, true, 1.0f, "loop stop", "stop", 0.0f, 0); } } @@ -354,7 +354,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat mMovementState = movement; std::string movement; - MWRender::Animation::Group movegroup = MWRender::Animation::Group_All; + MWRender::Animation::BlendMask movemask = MWRender::Animation::BlendMask_All; const StateInfo *movestate = std::find_if(sMovementList, sMovementListEnd, FindCharState(mMovementState)); if(movestate != sMovementListEnd) { @@ -364,7 +364,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat movement += weap->shortgroup; if(!mAnimation->hasAnimation(movement)) { - movegroup = MWRender::Animation::Group_LowerBody; + movemask = MWRender::Animation::BlendMask_LowerBody; movement = movestate->groupname; } } @@ -386,7 +386,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat } else { - movegroup = MWRender::Animation::Group_LowerBody; + movemask = MWRender::Animation::BlendMask_LowerBody; movement.erase(swimpos, 4); if(!mAnimation->hasAnimation(movement)) movement.clear(); @@ -447,7 +447,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat } } - mAnimation->play(mCurrentMovement, Priority_Movement, movegroup, false, + mAnimation->play(mCurrentMovement, Priority_Movement, movemask, false, speedmult, ((mode!=2)?"start":"loop start"), "stop", 0.0f, ~0ul); } } @@ -486,7 +486,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat mAnimation->disable(mCurrentIdle); mCurrentIdle = idle; if(!mCurrentIdle.empty()) - mAnimation->play(mCurrentIdle, Priority_Default, MWRender::Animation::Group_All, false, + mAnimation->play(mCurrentIdle, Priority_Default, MWRender::Animation::BlendMask_All, false, 1.0f, "start", "stop", 0.0f, ~0ul, true); } @@ -602,7 +602,7 @@ void CharacterController::playDeath(float startpoint, CharacterState death) mCurrentJump = ""; mMovementAnimationControlled = true; - mAnimation->play(mCurrentDeath, Priority_Death, MWRender::Animation::Group_All, + mAnimation->play(mCurrentDeath, Priority_Death, MWRender::Animation::BlendMask_All, false, 1.0f, "start", "stop", startpoint, 0); } @@ -868,10 +868,10 @@ void CharacterController::updateIdleStormState() mAnimation->getInfo("idlestorm", &complete); if (complete == 0) - mAnimation->play("idlestorm", Priority_Storm, MWRender::Animation::Group_RightArm, false, + mAnimation->play("idlestorm", Priority_Storm, MWRender::Animation::BlendMask_RightArm, false, 1.0f, "start", "loop start", 0.0f, 0); else if (complete == 1) - mAnimation->play("idlestorm", Priority_Storm, MWRender::Animation::Group_RightArm, false, + mAnimation->play("idlestorm", Priority_Storm, MWRender::Animation::BlendMask_RightArm, false, 1.0f, "loop start", "loop stop", 0.0f, ~0ul); } else @@ -882,7 +882,7 @@ void CharacterController::updateIdleStormState() { if (mAnimation->getCurrentTime("idlestorm") < mAnimation->getTextKeyTime("idlestorm: loop stop")) { - mAnimation->play("idlestorm", Priority_Storm, MWRender::Animation::Group_RightArm, true, + mAnimation->play("idlestorm", Priority_Storm, MWRender::Animation::BlendMask_RightArm, true, 1.0f, "loop stop", "stop", 0.0f, 0); } } @@ -989,7 +989,7 @@ bool CharacterController::updateCreatureState() if (!mCurrentWeapon.empty()) { mAnimation->play(mCurrentWeapon, Priority_Weapon, - MWRender::Animation::Group_All, true, + MWRender::Animation::BlendMask_All, true, 1, startKey, stopKey, 0.0f, 0); mUpperBodyState = UpperCharState_StartToMinAttack; @@ -1064,7 +1064,7 @@ bool CharacterController::updateWeaponState() { getWeaponGroup(mWeaponType, weapgroup); mAnimation->play(weapgroup, Priority_Weapon, - MWRender::Animation::Group_UpperBody, true, + MWRender::Animation::BlendMask_UpperBody, true, 1.0f, "unequip start", "unequip stop", 0.0f, 0); mUpperBodyState = UpperCharState_UnEquipingWeap; } @@ -1075,7 +1075,7 @@ bool CharacterController::updateWeaponState() mAnimation->setWeaponGroup(weapgroup); mAnimation->play(weapgroup, Priority_Weapon, - MWRender::Animation::Group_UpperBody, true, + MWRender::Animation::BlendMask_UpperBody, true, 1.0f, "equip start", "equip stop", 0.0f, 0); mUpperBodyState = UpperCharState_EquipingWeap; @@ -1192,7 +1192,7 @@ bool CharacterController::updateWeaponState() } mAnimation->play(mCurrentWeapon, Priority_Weapon, - MWRender::Animation::Group_UpperBody, true, + MWRender::Animation::BlendMask_UpperBody, true, weapSpeed, mAttackType+" start", mAttackType+" stop", 0.0f, 0); mUpperBodyState = UpperCharState_CastingSpell; @@ -1224,7 +1224,7 @@ bool CharacterController::updateWeaponState() Security(mPtr).probeTrap(target, item, resultMessage, resultSound); } mAnimation->play(mCurrentWeapon, Priority_Weapon, - MWRender::Animation::Group_UpperBody, true, + MWRender::Animation::BlendMask_UpperBody, true, 1.0f, "start", "stop", 0.0, 0); mUpperBodyState = UpperCharState_FollowStartToFollowStop; @@ -1251,7 +1251,7 @@ bool CharacterController::updateWeaponState() } mAnimation->play(mCurrentWeapon, Priority_Weapon, - MWRender::Animation::Group_UpperBody, false, + MWRender::Animation::BlendMask_UpperBody, false, weapSpeed, mAttackType+" start", mAttackType+" min attack", 0.0f, 0); mUpperBodyState = UpperCharState_StartToMinAttack; @@ -1302,7 +1302,7 @@ bool CharacterController::updateWeaponState() mAnimation->disable(mCurrentWeapon); mAnimation->play(mCurrentWeapon, Priority_Weapon, - MWRender::Animation::Group_UpperBody, false, + MWRender::Animation::BlendMask_UpperBody, false, weapSpeed, mAttackType+" max attack", mAttackType+" min hit", 1.0f-complete, 0); @@ -1374,7 +1374,7 @@ bool CharacterController::updateWeaponState() //don't allow to continue playing hit animation on UpperBody after actor had attacked during it if(mHitState == CharState_Hit) { - mAnimation->changeGroups(mCurrentHit, MWRender::Animation::Group_LowerBody); + mAnimation->changeBlendMask(mCurrentHit, MWRender::Animation::BlendMask_LowerBody); //commenting out following 2 lines will give a bit different combat dynamics(slower) mHitState = CharState_None; mCurrentHit.clear(); @@ -1398,7 +1398,7 @@ bool CharacterController::updateWeaponState() //hack to avoid body pos desync when jumping/sneaking in 'max attack' state if(!mAnimation->isPlaying(mCurrentWeapon)) mAnimation->play(mCurrentWeapon, Priority_Weapon, - MWRender::Animation::Group_UpperBody, false, + MWRender::Animation::BlendMask_UpperBody, false, 0, mAttackType+" min attack", mAttackType+" max attack", 0.999f, 0); break; case UpperCharState_MaxAttackToMinHit: @@ -1441,11 +1441,11 @@ bool CharacterController::updateWeaponState() mAnimation->disable(mCurrentWeapon); if (mUpperBodyState == UpperCharState_FollowStartToFollowStop) mAnimation->play(mCurrentWeapon, Priority_Weapon, - MWRender::Animation::Group_UpperBody, true, + MWRender::Animation::BlendMask_UpperBody, true, weapSpeed, start, stop, 0.0f, 0); else mAnimation->play(mCurrentWeapon, Priority_Weapon, - MWRender::Animation::Group_UpperBody, false, + MWRender::Animation::BlendMask_UpperBody, false, weapSpeed, start, stop, 0.0f, 0); } } @@ -1459,11 +1459,11 @@ bool CharacterController::updateWeaponState() MWBase::Environment::get().getWorld()->isSwimming(mPtr) || cls.getCreatureStats(mPtr).getMovementFlag(CreatureStats::Flag_Sneak)) { - mAnimation->changeGroups(mCurrentWeapon, MWRender::Animation::Group_UpperBody); + mAnimation->changeBlendMask(mCurrentWeapon, MWRender::Animation::BlendMask_UpperBody); } else { - mAnimation->changeGroups(mCurrentWeapon, MWRender::Animation::Group_All); + mAnimation->changeBlendMask(mCurrentWeapon, MWRender::Animation::BlendMask_All); } } @@ -1475,7 +1475,7 @@ bool CharacterController::updateWeaponState() && updateCarriedLeftVisible(mWeaponType)) { - mAnimation->play("torch", Priority_Torch, MWRender::Animation::Group_LeftArm, + mAnimation->play("torch", Priority_Torch, MWRender::Animation::BlendMask_LeftArm, false, 1.0f, "start", "stop", 0.0f, (~(size_t)0), true); } else if (mAnimation->isPlaying("torch")) @@ -1505,7 +1505,7 @@ void CharacterController::update(float duration) mAnimQueue.pop_front(); mAnimation->play(mAnimQueue.front().first, Priority_Default, - MWRender::Animation::Group_All, false, + MWRender::Animation::BlendMask_All, false, 1.0f, "start", "stop", 0.0f, mAnimQueue.front().second); } } @@ -1786,7 +1786,7 @@ void CharacterController::update(float duration) mAnimQueue.pop_front(); mAnimation->play(mAnimQueue.front().first, Priority_Default, - MWRender::Animation::Group_All, false, + MWRender::Animation::BlendMask_All, false, 1.0f, "start", "stop", 0.0f, mAnimQueue.front().second); } } @@ -1894,7 +1894,7 @@ void CharacterController::playGroup(const std::string &groupname, int mode, int mIdleState = CharState_SpecialIdle; mAnimation->play(groupname, Priority_Default, - MWRender::Animation::Group_All, false, 1.0f, + MWRender::Animation::BlendMask_All, false, 1.0f, ((mode==2) ? "loop start" : "start"), "stop", 0.0f, count-1); } else if(mode == 0) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 91f459ff2..097a4febf 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -219,7 +219,7 @@ namespace MWRender typedef std::map > ControllerMap; - ControllerMap mControllerMap[Animation::sNumGroups]; + ControllerMap mControllerMap[Animation::sNumBlendMasks]; const std::multimap& getTextKeys(); }; @@ -261,7 +261,7 @@ namespace MWRender , mHeadYawRadians(0.f) , mHeadPitchRadians(0.f) { - for(size_t i = 0;i < sNumGroups;i++) + for(size_t i = 0;i < sNumBlendMasks;i++) mAnimationTimePtr[i].reset(new AnimationTime); } @@ -299,9 +299,9 @@ namespace MWRender mResetAccumRootCallback->setAccumulate(mAccumulate); } - size_t Animation::detectAnimGroup(osg::Node* node) + size_t Animation::detectBlendMask(osg::Node* node) { - static const char sGroupRoots[sNumGroups][32] = { + static const char sBlendMaskRoots[sNumBlendMasks][32] = { "", /* Lower body / character root */ "Bip01 Spine1", /* Torso */ "Bip01 L Clavicle", /* Left arm */ @@ -311,9 +311,9 @@ namespace MWRender while(node != mObjectRoot) { const std::string &name = node->getName(); - for(size_t i = 1;i < sNumGroups;i++) + for(size_t i = 1;i < sNumBlendMasks;i++) { - if(name == sGroupRoots[i]) + if(name == sBlendMaskRoots[i]) return i; } @@ -361,13 +361,13 @@ namespace MWRender osg::Node* node = found->second; - size_t group = detectAnimGroup(node); + size_t blendMask = detectBlendMask(node); // clone the controller, because each Animation needs its own ControllerSource osg::ref_ptr cloned = osg::clone(it->second.get(), osg::CopyOp::DEEP_COPY_ALL); - cloned->setSource(mAnimationTimePtr[group]); + cloned->setSource(mAnimationTimePtr[blendMask]); - animsrc->mControllerMap[group].insert(std::make_pair(bonename, cloned)); + animsrc->mControllerMap[blendMask].insert(std::make_pair(bonename, cloned)); } mAnimSources.push_back(animsrc); @@ -390,7 +390,7 @@ namespace MWRender { mStates.clear(); - for(size_t i = 0;i < sNumGroups;i++) + for(size_t i = 0;i < sNumBlendMasks;i++) mAnimationTimePtr[i]->setTimePtr(boost::shared_ptr()); mAccumCtrl = NULL; @@ -461,7 +461,7 @@ namespace MWRender mTextKeyListener->handleTextKey(groupname, key, map); } - void Animation::play(const std::string &groupname, int priority, int groups, bool autodisable, float speedmult, + void Animation::play(const std::string &groupname, int priority, int blendMask, bool autodisable, float speedmult, const std::string &start, const std::string &stop, float startpoint, size_t loops, bool loopfallback) { if(!mObjectRoot || mAnimSources.empty()) @@ -505,7 +505,7 @@ namespace MWRender state.mLoopCount = loops; state.mPlaying = (state.getTime() < state.mStopTime); state.mPriority = priority; - state.mGroups = groups; + state.mBlendMask = blendMask; state.mAutoDisable = autodisable; mStates[groupname] = state; @@ -643,35 +643,35 @@ namespace MWRender mAccumCtrl = NULL; - for(size_t grp = 0;grp < sNumGroups;grp++) + for(size_t blendMask = 0;blendMask < sNumBlendMasks;blendMask++) { AnimStateMap::const_iterator active = mStates.end(); AnimStateMap::const_iterator state = mStates.begin(); for(;state != mStates.end();++state) { - if(!(state->second.mGroups&(1<second.mBlendMask&(1<second.mPriority < state->second.mPriority) active = state; } - mAnimationTimePtr[grp]->setTimePtr(active == mStates.end() ? boost::shared_ptr() : active->second.mTime); + mAnimationTimePtr[blendMask]->setTimePtr(active == mStates.end() ? boost::shared_ptr() : active->second.mTime); - // add external controllers for the AnimSource active in this group + // add external controllers for the AnimSource active in this blend mask if (active != mStates.end()) { boost::shared_ptr animsrc = active->second.mSource; - for (AnimSource::ControllerMap::iterator it = animsrc->mControllerMap[grp].begin(); it != animsrc->mControllerMap[grp].end(); ++it) + for (AnimSource::ControllerMap::iterator it = animsrc->mControllerMap[blendMask].begin(); it != animsrc->mControllerMap[blendMask].end(); ++it) { osg::ref_ptr node = mNodeMap.at(it->first); // this should not throw, we already checked for the node existing in addAnimSource node->addUpdateCallback(it->second); mActiveControllers.insert(std::make_pair(node, it->second)); - if (grp == 0 && node == mAccumRoot) + if (blendMask == 0 && node == mAccumRoot) { mAccumCtrl = it->second; @@ -690,14 +690,14 @@ namespace MWRender addControllers(); } - void Animation::changeGroups(const std::string &groupname, int groups) + void Animation::changeBlendMask(const std::string &groupname, int mask) { AnimStateMap::iterator stateiter = mStates.find(groupname); if(stateiter != mStates.end()) { - if(stateiter->second.mGroups != groups) + if(stateiter->second.mBlendMask != mask) { - stateiter->second.mGroups = groups; + stateiter->second.mBlendMask = mask; resetActiveGroups(); } return; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index d23a62954..0a90489cf 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -67,16 +67,16 @@ typedef boost::shared_ptr PartHolderPtr; class Animation { public: - enum Group { - Group_LowerBody = 1<<0, + enum BlendMask { + BlendMask_LowerBody = 1<<0, - Group_Torso = 1<<1, - Group_LeftArm = 1<<2, - Group_RightArm = 1<<3, + BlendMask_Torso = 1<<1, + BlendMask_LeftArm = 1<<2, + BlendMask_RightArm = 1<<3, - Group_UpperBody = Group_Torso | Group_LeftArm | Group_RightArm, + BlendMask_UpperBody = BlendMask_Torso | BlendMask_LeftArm | BlendMask_RightArm, - Group_All = Group_LowerBody | Group_UpperBody + BlendMask_All = BlendMask_LowerBody | BlendMask_UpperBody }; class TextKeyListener @@ -90,7 +90,7 @@ public: protected: /* This is the number of *discrete* groups. */ - static const size_t sNumGroups = 4; + static const size_t sNumBlendMasks = 4; class AnimationTime : public SceneUtil::ControllerSource { @@ -133,12 +133,12 @@ protected: size_t mLoopCount; int mPriority; - int mGroups; + int mBlendMask; bool mAutoDisable; AnimState() : mStartTime(0.0f), mLoopStartTime(0.0f), mLoopStopTime(0.0f), mStopTime(0.0f), mTime(new float), mSpeedMult(1.0f), mPlaying(false), mLoopCount(0), - mPriority(0), mGroups(0), mAutoDisable(true) + mPriority(0), mBlendMask(0), mAutoDisable(true) { } ~AnimState(); @@ -176,7 +176,7 @@ protected: typedef std::multimap, osg::ref_ptr > ControllerMap; ControllerMap mActiveControllers; - boost::shared_ptr mAnimationTimePtr[sNumGroups]; + boost::shared_ptr mAnimationTimePtr[sNumBlendMasks]; // Stored in all lowercase for a case-insensitive lookup typedef std::map > NodeMap; @@ -213,7 +213,7 @@ protected: */ void resetActiveGroups(); - size_t detectAnimGroup(osg::Node* node); + size_t detectBlendMask(osg::Node* node); /* Updates the position of the accum root node for the given time, and * returns the wanted movement vector from the previous time. */ @@ -304,7 +304,7 @@ public: * \param priority Priority of the animation. The animation will play on * bone groups that don't have another animation set of a * higher priority. - * \param groups Bone groups to play the animation on. + * \param blendMask Bone groups to play the animation on. * \param autodisable Automatically disable the animation when it stops * playing. * \param speedmult Speed multiplier for the animation. @@ -319,7 +319,7 @@ public: * \param loopFallback Allow looping an animation that has no loop keys, i.e. fall back to use * the "start" and "stop" keys for looping? */ - void play(const std::string &groupname, int priority, int groups, bool autodisable, + void play(const std::string &groupname, int priority, int blendMask, bool autodisable, float speedmult, const std::string &start, const std::string &stop, float startpoint, size_t loops, bool loopfallback=false); @@ -358,7 +358,7 @@ public: * \param groupname Animation group to disable. */ void disable(const std::string &groupname); - void changeGroups(const std::string &groupname, int group); + void changeBlendMask(const std::string &groupname, int mask); /** Retrieves the velocity (in units per second) that the animation will move. */ float getVelocity(const std::string &groupname) const; diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 32e51c4d6..b4e1189f7 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -241,13 +241,13 @@ namespace MWRender mAnimation->showCarriedLeft(showCarriedLeft); mCurrentAnimGroup = groupname; - mAnimation->play(mCurrentAnimGroup, 1, Animation::Group_All, false, 1.0f, "start", "stop", 0.0f, 0); + mAnimation->play(mCurrentAnimGroup, 1, Animation::BlendMask_All, false, 1.0f, "start", "stop", 0.0f, 0); MWWorld::ContainerStoreIterator torch = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft); if(torch != inv.end() && torch->getTypeName() == typeid(ESM::Light).name() && showCarriedLeft) { if(!mAnimation->getInfo("torch")) - mAnimation->play("torch", 2, MWRender::Animation::Group_LeftArm, false, + mAnimation->play("torch", 2, Animation::BlendMask_LeftArm, false, 1.0f, "start", "stop", 0.0f, ~0ul, true); } else if(mAnimation->getInfo("torch")) @@ -357,7 +357,7 @@ namespace MWRender void RaceSelectionPreview::onSetup () { - mAnimation->play("idle", 1, Animation::Group_All, false, 1.0f, "start", "stop", 0.0f, 0); + mAnimation->play("idle", 1, Animation::BlendMask_All, false, 1.0f, "start", "stop", 0.0f, 0); mAnimation->runAnimation(0.f); // attach camera to follow the head node From e93a578f237b67f9e6d5da361220589895f08dde Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 15 Jul 2015 14:18:31 +0200 Subject: [PATCH 1823/3725] Extend the animation priority system to one priority value per bone group / distinct blend mask --- apps/openmw/mwrender/animation.cpp | 14 ++++++------- apps/openmw/mwrender/animation.hpp | 33 ++++++++++++++++++++++++++++-- 2 files changed, 38 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 097a4febf..2be2165ea 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -461,7 +461,7 @@ namespace MWRender mTextKeyListener->handleTextKey(groupname, key, map); } - void Animation::play(const std::string &groupname, int priority, int blendMask, bool autodisable, float speedmult, + void Animation::play(const std::string &groupname, AnimPriority priority, int blendMask, bool autodisable, float speedmult, const std::string &start, const std::string &stop, float startpoint, size_t loops, bool loopfallback) { if(!mObjectRoot || mAnimSources.empty()) @@ -473,8 +473,6 @@ namespace MWRender return; } - priority = std::max(0, priority); - AnimStateMap::iterator stateiter = mStates.begin(); while(stateiter != mStates.end()) { @@ -653,7 +651,7 @@ namespace MWRender if(!(state->second.mBlendMask&(1<second.mPriority < state->second.mPriority) + if(active == mStates.end() || active->second.mPriority.mPriority[blendMask] < state->second.mPriority.mPriority[blendMask]) active = state; } @@ -690,6 +688,7 @@ namespace MWRender addControllers(); } + // TODO: remove void Animation::changeBlendMask(const std::string &groupname, int mask) { AnimStateMap::iterator stateiter = mStates.find(groupname); @@ -1208,9 +1207,10 @@ namespace MWRender { for (AnimStateMap::const_iterator stateiter = mStates.begin(); stateiter != mStates.end(); ++stateiter) { - if((stateiter->second.mPriority > MWMechanics::Priority_Movement - && stateiter->second.mPriority < MWMechanics::Priority_Torch) - || stateiter->second.mPriority == MWMechanics::Priority_Death) + if (stateiter->second.mPriority.contains(int(MWMechanics::Priority_Hit)) + || stateiter->second.mPriority.contains(int(MWMechanics::Priority_Weapon)) + || stateiter->second.mPriority.contains(int(MWMechanics::Priority_Knockdown)) + || stateiter->second.mPriority.contains(int(MWMechanics::Priority_Death))) return false; } return true; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 0a90489cf..90d2a68a3 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -118,6 +118,35 @@ protected: struct AnimSource; + /// Holds an animation priority value for each distinct bone blendmask. + struct AnimPriority + { + /// Convenience constructor, initialises all priorities to the same value. + AnimPriority(int priority) + { + for (unsigned int i=0; i mSource; float mStartTime; @@ -132,7 +161,7 @@ protected: bool mPlaying; size_t mLoopCount; - int mPriority; + AnimPriority mPriority; int mBlendMask; bool mAutoDisable; @@ -319,7 +348,7 @@ public: * \param loopFallback Allow looping an animation that has no loop keys, i.e. fall back to use * the "start" and "stop" keys for looping? */ - void play(const std::string &groupname, int priority, int blendMask, bool autodisable, + void play(const std::string &groupname, AnimPriority priority, int blendMask, bool autodisable, float speedmult, const std::string &start, const std::string &stop, float startpoint, size_t loops, bool loopfallback=false); From 50db6ed3968df6b3e16cf9315b6f3a47d8ac8227 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 15 Jul 2015 14:40:36 +0200 Subject: [PATCH 1824/3725] Use the extended animation priority for weapon animations --- apps/openmw/mwmechanics/character.cpp | 56 ++++++++------------- apps/openmw/mwrender/animation.hpp | 71 ++++++++++++++------------- 2 files changed, 59 insertions(+), 68 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index bd15b6a73..8f813ceb1 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1051,6 +1051,9 @@ bool CharacterController::updateWeaponState() } } + MWRender::Animation::AnimPriority priorityWeapon(Priority_Weapon); + priorityWeapon.mPriority[MWRender::Animation::BoneGroup_LowerBody] = 0; + bool forcestateupdate = false; if(weaptype != mWeaponType && mHitState != CharState_KnockDown && mHitState != CharState_KnockOut && mHitState != CharState_Hit) @@ -1063,8 +1066,8 @@ bool CharacterController::updateWeaponState() if(weaptype == WeapType_None) { getWeaponGroup(mWeaponType, weapgroup); - mAnimation->play(weapgroup, Priority_Weapon, - MWRender::Animation::BlendMask_UpperBody, true, + mAnimation->play(weapgroup, priorityWeapon, + MWRender::Animation::BlendMask_All, true, 1.0f, "unequip start", "unequip stop", 0.0f, 0); mUpperBodyState = UpperCharState_UnEquipingWeap; } @@ -1074,8 +1077,8 @@ bool CharacterController::updateWeaponState() mAnimation->showWeapons(false); mAnimation->setWeaponGroup(weapgroup); - mAnimation->play(weapgroup, Priority_Weapon, - MWRender::Animation::BlendMask_UpperBody, true, + mAnimation->play(weapgroup, priorityWeapon, + MWRender::Animation::BlendMask_All, true, 1.0f, "equip start", "equip stop", 0.0f, 0); mUpperBodyState = UpperCharState_EquipingWeap; @@ -1191,8 +1194,8 @@ bool CharacterController::updateWeaponState() case 2: mAttackType = "target"; break; } - mAnimation->play(mCurrentWeapon, Priority_Weapon, - MWRender::Animation::BlendMask_UpperBody, true, + mAnimation->play(mCurrentWeapon, priorityWeapon, + MWRender::Animation::BlendMask_All, true, weapSpeed, mAttackType+" start", mAttackType+" stop", 0.0f, 0); mUpperBodyState = UpperCharState_CastingSpell; @@ -1223,8 +1226,8 @@ bool CharacterController::updateWeaponState() else if(item.getTypeName() == typeid(ESM::Probe).name()) Security(mPtr).probeTrap(target, item, resultMessage, resultSound); } - mAnimation->play(mCurrentWeapon, Priority_Weapon, - MWRender::Animation::BlendMask_UpperBody, true, + mAnimation->play(mCurrentWeapon, priorityWeapon, + MWRender::Animation::BlendMask_All, true, 1.0f, "start", "stop", 0.0, 0); mUpperBodyState = UpperCharState_FollowStartToFollowStop; @@ -1250,8 +1253,8 @@ bool CharacterController::updateWeaponState() determineAttackType(); } - mAnimation->play(mCurrentWeapon, Priority_Weapon, - MWRender::Animation::BlendMask_UpperBody, false, + mAnimation->play(mCurrentWeapon, priorityWeapon, + MWRender::Animation::BlendMask_All, false, weapSpeed, mAttackType+" start", mAttackType+" min attack", 0.0f, 0); mUpperBodyState = UpperCharState_StartToMinAttack; @@ -1301,8 +1304,8 @@ bool CharacterController::updateWeaponState() mAttackStrength = attackStrength; mAnimation->disable(mCurrentWeapon); - mAnimation->play(mCurrentWeapon, Priority_Weapon, - MWRender::Animation::BlendMask_UpperBody, false, + mAnimation->play(mCurrentWeapon, priorityWeapon, + MWRender::Animation::BlendMask_All, false, weapSpeed, mAttackType+" max attack", mAttackType+" min hit", 1.0f-complete, 0); @@ -1397,8 +1400,8 @@ bool CharacterController::updateWeaponState() case UpperCharState_MinAttackToMaxAttack: //hack to avoid body pos desync when jumping/sneaking in 'max attack' state if(!mAnimation->isPlaying(mCurrentWeapon)) - mAnimation->play(mCurrentWeapon, Priority_Weapon, - MWRender::Animation::BlendMask_UpperBody, false, + mAnimation->play(mCurrentWeapon, priorityWeapon, + MWRender::Animation::BlendMask_All, false, 0, mAttackType+" min attack", mAttackType+" max attack", 0.999f, 0); break; case UpperCharState_MaxAttackToMinHit: @@ -1440,33 +1443,16 @@ bool CharacterController::updateWeaponState() { mAnimation->disable(mCurrentWeapon); if (mUpperBodyState == UpperCharState_FollowStartToFollowStop) - mAnimation->play(mCurrentWeapon, Priority_Weapon, - MWRender::Animation::BlendMask_UpperBody, true, + mAnimation->play(mCurrentWeapon, priorityWeapon, + MWRender::Animation::BlendMask_All, true, weapSpeed, start, stop, 0.0f, 0); else - mAnimation->play(mCurrentWeapon, Priority_Weapon, - MWRender::Animation::BlendMask_UpperBody, false, + mAnimation->play(mCurrentWeapon, priorityWeapon, + MWRender::Animation::BlendMask_All, false, weapSpeed, start, stop, 0.0f, 0); } } - //if playing combat animation and lowerbody is not busy switch to whole body animation - if((weaptype != WeapType_None || mUpperBodyState == UpperCharState_UnEquipingWeap) && animPlaying) - { - if( mMovementState != CharState_None || - mJumpState != JumpState_None || - mHitState != CharState_None || - MWBase::Environment::get().getWorld()->isSwimming(mPtr) || - cls.getCreatureStats(mPtr).getMovementFlag(CreatureStats::Flag_Sneak)) - { - mAnimation->changeBlendMask(mCurrentWeapon, MWRender::Animation::BlendMask_UpperBody); - } - else - { - mAnimation->changeBlendMask(mCurrentWeapon, MWRender::Animation::BlendMask_All); - } - } - if (mPtr.getClass().hasInventoryStore(mPtr)) { MWWorld::InventoryStore& inv = mPtr.getClass().getInventoryStore(mPtr); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 90d2a68a3..35c0b5346 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -67,9 +67,15 @@ typedef boost::shared_ptr PartHolderPtr; class Animation { public: + enum BoneGroup { + BoneGroup_LowerBody = 0, + BoneGroup_Torso, + BoneGroup_LeftArm, + BoneGroup_RightArm + }; + enum BlendMask { BlendMask_LowerBody = 1<<0, - BlendMask_Torso = 1<<1, BlendMask_LeftArm = 1<<2, BlendMask_RightArm = 1<<3, @@ -78,6 +84,37 @@ public: BlendMask_All = BlendMask_LowerBody | BlendMask_UpperBody }; + /* This is the number of *discrete* blend masks. */ + static const size_t sNumBlendMasks = 4; + + /// Holds an animation priority value for each BoneGroup. + struct AnimPriority + { + /// Convenience constructor, initialises all priorities to the same value. + AnimPriority(int priority) + { + for (unsigned int i=0; i mSource; float mStartTime; From cf14d1748c50dad6a64c8a7019c7fe454b09652a Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 15 Jul 2015 14:47:29 +0200 Subject: [PATCH 1825/3725] Use the extended animation priority for Hit animations --- apps/openmw/mwmechanics/character.cpp | 9 --------- 1 file changed, 9 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 8f813ceb1..ea0d4f322 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1374,15 +1374,6 @@ bool CharacterController::updateWeaponState() mAnimation->attachArrow(); mUpperBodyState = UpperCharState_WeapEquiped; - //don't allow to continue playing hit animation on UpperBody after actor had attacked during it - if(mHitState == CharState_Hit) - { - mAnimation->changeBlendMask(mCurrentHit, MWRender::Animation::BlendMask_LowerBody); - //commenting out following 2 lines will give a bit different combat dynamics(slower) - mHitState = CharState_None; - mCurrentHit.clear(); - mPtr.getClass().getCreatureStats(mPtr).setHitRecovery(false); - } } else if(mUpperBodyState == UpperCharState_UnEquipingWeap) mUpperBodyState = UpperCharState_Nothing; From 83cceeee7283183db18e40b1890a20c55dae4ad3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 15 Jul 2015 14:54:37 +0200 Subject: [PATCH 1826/3725] Use the extended animation priority for Block animations, allow starting attacks during a block animation (Fixes #2761) --- apps/openmw/mwmechanics/character.cpp | 11 +++++++---- apps/openmw/mwmechanics/character.hpp | 1 + 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index ea0d4f322..a71f8d160 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -270,7 +270,9 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat { mHitState = CharState_Block; mCurrentHit = "shield"; - mAnimation->play(mCurrentHit, Priority_Hit, MWRender::Animation::BlendMask_All, true, 1, "block start", "block stop", 0.0f, 0); + MWRender::Animation::AnimPriority priorityBlock (Priority_Hit); + priorityBlock.mPriority[MWRender::Animation::BoneGroup_LeftArm] = Priority_Block; + mAnimation->play(mCurrentHit, priorityBlock, MWRender::Animation::BlendMask_All, true, 1, "block start", "block stop", 0.0f, 0); } // Cancel upper body animations @@ -1148,7 +1150,7 @@ bool CharacterController::updateWeaponState() bool animPlaying; if(mAttackingOrSpell) { - if(mUpperBodyState == UpperCharState_WeapEquiped && mHitState == CharState_None) + if(mUpperBodyState == UpperCharState_WeapEquiped && (mHitState == CharState_None || mHitState == CharState_Block)) { MWBase::Environment::get().getWorld()->breakInvisibility(mPtr); mAttackType.clear(); @@ -2029,12 +2031,13 @@ void CharacterController::setAttackingOrSpell(bool attackingOrSpell) bool CharacterController::readyToPrepareAttack() const { - return mHitState == CharState_None && mUpperBodyState <= UpperCharState_WeapEquiped; + return (mHitState == CharState_None || mHitState == CharState_Block) + && mUpperBodyState <= UpperCharState_WeapEquiped; } bool CharacterController::readyToStartAttack() const { - if (mHitState != CharState_None) + if (mHitState != CharState_None && mHitState != CharState_Block) return false; if (mPtr.getClass().hasInventoryStore(mPtr) || mPtr.getClass().isBipedal(mPtr)) diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index b239b4a92..6b530ae2a 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -32,6 +32,7 @@ enum Priority { Priority_Movement, Priority_Hit, Priority_Weapon, + Priority_Block, Priority_Knockdown, Priority_Torch, Priority_Storm, From 3656851750b089a897d5b0077f0177808d7412f1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 15 Jul 2015 14:55:33 +0200 Subject: [PATCH 1827/3725] Remove the now unused changeBlendMask --- apps/openmw/mwrender/animation.cpp | 15 --------------- apps/openmw/mwrender/animation.hpp | 1 - 2 files changed, 16 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 2be2165ea..84f46c4ab 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -688,21 +688,6 @@ namespace MWRender addControllers(); } - // TODO: remove - void Animation::changeBlendMask(const std::string &groupname, int mask) - { - AnimStateMap::iterator stateiter = mStates.find(groupname); - if(stateiter != mStates.end()) - { - if(stateiter->second.mBlendMask != mask) - { - stateiter->second.mBlendMask = mask; - resetActiveGroups(); - } - return; - } - } - void Animation::stopLooping(const std::string& groupname) { AnimStateMap::iterator stateiter = mStates.find(groupname); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 35c0b5346..1cf2ce9ba 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -392,7 +392,6 @@ public: * \param groupname Animation group to disable. */ void disable(const std::string &groupname); - void changeBlendMask(const std::string &groupname, int mask); /** Retrieves the velocity (in units per second) that the animation will move. */ float getVelocity(const std::string &groupname) const; From 17ada63fcb87d45b5da89d1efa33d24e229236e8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 15 Jul 2015 15:46:31 +0200 Subject: [PATCH 1828/3725] Don't play turning animations on the upperbody when in first person mode (Fixes #2287) --- apps/openmw/mwmechanics/character.cpp | 50 ++++++++++++++++----------- 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index a71f8d160..95546dca9 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -355,55 +355,55 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat { mMovementState = movement; - std::string movement; + std::string movementAnimName; MWRender::Animation::BlendMask movemask = MWRender::Animation::BlendMask_All; const StateInfo *movestate = std::find_if(sMovementList, sMovementListEnd, FindCharState(mMovementState)); if(movestate != sMovementListEnd) { - movement = movestate->groupname; - if(weap != sWeaponTypeListEnd && movement.find("swim") == std::string::npos) + movementAnimName = movestate->groupname; + if(weap != sWeaponTypeListEnd && movementAnimName.find("swim") == std::string::npos) { - movement += weap->shortgroup; - if(!mAnimation->hasAnimation(movement)) + movementAnimName += weap->shortgroup; + if(!mAnimation->hasAnimation(movementAnimName)) { movemask = MWRender::Animation::BlendMask_LowerBody; - movement = movestate->groupname; + movementAnimName = movestate->groupname; } } - if(!mAnimation->hasAnimation(movement)) + if(!mAnimation->hasAnimation(movementAnimName)) { - std::string::size_type swimpos = movement.find("swim"); + std::string::size_type swimpos = movementAnimName.find("swim"); if(swimpos == std::string::npos) { - std::string::size_type runpos = movement.find("run"); + std::string::size_type runpos = movementAnimName.find("run"); if (runpos != std::string::npos) { - movement.replace(runpos, runpos+3, "walk"); - if (!mAnimation->hasAnimation(movement)) - movement.clear(); + movementAnimName.replace(runpos, runpos+3, "walk"); + if (!mAnimation->hasAnimation(movementAnimName)) + movementAnimName.clear(); } else - movement.clear(); + movementAnimName.clear(); } else { movemask = MWRender::Animation::BlendMask_LowerBody; - movement.erase(swimpos, 4); - if(!mAnimation->hasAnimation(movement)) - movement.clear(); + movementAnimName.erase(swimpos, 4); + if(!mAnimation->hasAnimation(movementAnimName)) + movementAnimName.clear(); } } } /* If we're playing the same animation, restart from the loop start instead of the * beginning. */ - int mode = ((movement == mCurrentMovement) ? 2 : 1); + int mode = ((movementAnimName == mCurrentMovement) ? 2 : 1); mMovementAnimationControlled = true; mAnimation->disable(mCurrentMovement); - mCurrentMovement = movement; + mCurrentMovement = movementAnimName; if(!mCurrentMovement.empty()) { float vel, speedmult = 1.0f; @@ -449,7 +449,17 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat } } - mAnimation->play(mCurrentMovement, Priority_Movement, movemask, false, + MWRender::Animation::AnimPriority priorityMovement (Priority_Movement); + if ((movement == CharState_TurnLeft || movement == CharState_TurnRight) + && mPtr == MWBase::Environment::get().getWorld()->getPlayerPtr() + && MWBase::Environment::get().getWorld()->isFirstPerson()) + { + priorityMovement.mPriority[MWRender::Animation::BoneGroup_Torso] = 0; + priorityMovement.mPriority[MWRender::Animation::BoneGroup_LeftArm] = 0; + priorityMovement.mPriority[MWRender::Animation::BoneGroup_RightArm] = 0; + } + + mAnimation->play(mCurrentMovement, priorityMovement, movemask, false, speedmult, ((mode!=2)?"start":"loop start"), "stop", 0.0f, ~0ul); } } @@ -458,7 +468,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat // FIXME: if one of the below states is close to their last animation frame (i.e. will be disabled in the coming update), // the idle animation should be displayed if ((mUpperBodyState != UpperCharState_Nothing - || mMovementState != CharState_None + || (mMovementState != CharState_None && mMovementState != CharState_TurnLeft && mMovementState != CharState_TurnRight) || mHitState != CharState_None) && !mPtr.getClass().isBipedal(mPtr)) idle = CharState_None; From e8a9567be30fb35e78e252bf52e95bcebe76a109 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Wed, 15 Jul 2015 19:39:01 +0300 Subject: [PATCH 1829/3725] Move DELE handling to CellRef record --- apps/openmw/mwworld/cellreflist.hpp | 2 +- apps/openmw/mwworld/cellstore.cpp | 58 ++++++++++++++--------------- apps/openmw/mwworld/cellstore.hpp | 2 +- components/esm/cellref.cpp | 21 +++++++++++ components/esm/cellref.hpp | 4 ++ components/esm/loadcell.cpp | 12 ++---- components/esm/loadcell.hpp | 3 +- 7 files changed, 59 insertions(+), 43 deletions(-) diff --git a/apps/openmw/mwworld/cellreflist.hpp b/apps/openmw/mwworld/cellreflist.hpp index 49197d167..0ce603224 100644 --- a/apps/openmw/mwworld/cellreflist.hpp +++ b/apps/openmw/mwworld/cellreflist.hpp @@ -22,7 +22,7 @@ namespace MWWorld /// and the build will fail with an ugly three-way cyclic header dependence /// so we need to pass the instantiation of the method to the linker, when /// all methods are known. - void load (ESM::CellRef &ref, bool deleted, const MWWorld::ESMStore &esmStore); + void load (ESM::CellRef &ref, const MWWorld::ESMStore &esmStore); LiveRef *find (const std::string& name) { diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index b33a6f8db..a51672581 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -147,7 +147,7 @@ namespace MWWorld { template - void CellRefList::load(ESM::CellRef &ref, bool deleted, const MWWorld::ESMStore &esmStore) + void CellRefList::load(ESM::CellRef &ref, const MWWorld::ESMStore &esmStore) { const MWWorld::Store &store = esmStore.get(); @@ -158,7 +158,7 @@ namespace MWWorld LiveRef liveCellRef (ref, ptr); - if (deleted) + if (ref.mIsDeleted) liveCellRef.mData.setDeleted(true); if (iter != mList.end()) @@ -374,10 +374,9 @@ namespace MWWorld ESM::CellRef ref; // Get each reference in turn - bool deleted = false; - while (mCell->getNextRef (esm[index], ref, deleted)) + while (mCell->getNextRef (esm[index], ref)) { - if (deleted) + if (ref.mIsDeleted) continue; // Don't list reference if it was moved to a different cell. @@ -420,8 +419,7 @@ namespace MWWorld ref.mRefNum.mContentFile = ESM::RefNum::RefNum_NoContentFile; // Get each reference in turn - bool deleted = false; - while(mCell->getNextRef(esm[index], ref, deleted)) + while(mCell->getNextRef(esm[index], ref)) { // Don't load reference if it was moved to a different cell. ESM::MovedCellRefTracker::const_iterator iter = @@ -430,7 +428,7 @@ namespace MWWorld continue; } - loadRef (ref, deleted, store); + loadRef (ref, store); } } @@ -439,7 +437,7 @@ namespace MWWorld { ESM::CellRef &ref = const_cast(*it); - loadRef (ref, false, store); + loadRef (ref, store); } } @@ -468,32 +466,32 @@ namespace MWWorld return Ptr(); } - void CellStore::loadRef (ESM::CellRef& ref, bool deleted, const ESMStore& store) + void CellStore::loadRef (ESM::CellRef& ref, const ESMStore& store) { Misc::StringUtils::toLower (ref.mRefID); switch (store.find (ref.mRefID)) { - case ESM::REC_ACTI: mActivators.load(ref, deleted, store); break; - case ESM::REC_ALCH: mPotions.load(ref, deleted, store); break; - case ESM::REC_APPA: mAppas.load(ref, deleted, store); break; - case ESM::REC_ARMO: mArmors.load(ref, deleted, store); break; - case ESM::REC_BOOK: mBooks.load(ref, deleted, store); break; - case ESM::REC_CLOT: mClothes.load(ref, deleted, store); break; - case ESM::REC_CONT: mContainers.load(ref, deleted, store); break; - case ESM::REC_CREA: mCreatures.load(ref, deleted, store); break; - case ESM::REC_DOOR: mDoors.load(ref, deleted, store); break; - case ESM::REC_INGR: mIngreds.load(ref, deleted, store); break; - case ESM::REC_LEVC: mCreatureLists.load(ref, deleted, store); break; - case ESM::REC_LEVI: mItemLists.load(ref, deleted, store); break; - case ESM::REC_LIGH: mLights.load(ref, deleted, store); break; - case ESM::REC_LOCK: mLockpicks.load(ref, deleted, store); break; - case ESM::REC_MISC: mMiscItems.load(ref, deleted, store); break; - case ESM::REC_NPC_: mNpcs.load(ref, deleted, store); break; - case ESM::REC_PROB: mProbes.load(ref, deleted, store); break; - case ESM::REC_REPA: mRepairs.load(ref, deleted, store); break; - case ESM::REC_STAT: mStatics.load(ref, deleted, store); break; - case ESM::REC_WEAP: mWeapons.load(ref, deleted, store); break; + case ESM::REC_ACTI: mActivators.load(ref, store); break; + case ESM::REC_ALCH: mPotions.load(ref,store); break; + case ESM::REC_APPA: mAppas.load(ref, store); break; + case ESM::REC_ARMO: mArmors.load(ref, store); break; + case ESM::REC_BOOK: mBooks.load(ref, store); break; + case ESM::REC_CLOT: mClothes.load(ref, store); break; + case ESM::REC_CONT: mContainers.load(ref, store); break; + case ESM::REC_CREA: mCreatures.load(ref, store); break; + case ESM::REC_DOOR: mDoors.load(ref, store); break; + case ESM::REC_INGR: mIngreds.load(ref, store); break; + case ESM::REC_LEVC: mCreatureLists.load(ref, store); break; + case ESM::REC_LEVI: mItemLists.load(ref, store); break; + case ESM::REC_LIGH: mLights.load(ref, store); break; + case ESM::REC_LOCK: mLockpicks.load(ref, store); break; + case ESM::REC_MISC: mMiscItems.load(ref, store); break; + case ESM::REC_NPC_: mNpcs.load(ref, store); break; + case ESM::REC_PROB: mProbes.load(ref, store); break; + case ESM::REC_REPA: mRepairs.load(ref, store); break; + case ESM::REC_STAT: mStatics.load(ref, store); break; + case ESM::REC_WEAP: mWeapons.load(ref, store); break; case 0: std::cerr << "Cell reference " + ref.mRefID + " not found!\n"; break; diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index f879343d9..5caa4eeea 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -214,7 +214,7 @@ namespace MWWorld void loadRefs(const MWWorld::ESMStore &store, std::vector &esm); - void loadRef (ESM::CellRef& ref, bool deleted, const ESMStore& store); + void loadRef (ESM::CellRef& ref, const ESMStore& store); ///< Make case-adjustments to \a ref and insert it into the respective container. /// /// Invalid \a ref objects are silently dropped. diff --git a/components/esm/cellref.cpp b/components/esm/cellref.cpp index c3b889df5..e43a37b66 100644 --- a/components/esm/cellref.cpp +++ b/components/esm/cellref.cpp @@ -3,6 +3,17 @@ #include "esmreader.hpp" #include "esmwriter.hpp" +#include "util.hpp" + +ESM::CellRef::CellRef() + : mScale(1.0f), + mFactionRank(-2), + mEnchantmentCharge(-1), + mGoldValue(1), + mChargeInt(-1), + mLockLevel(0), + mIsDeleted(false) +{} void ESM::RefNum::load (ESMReader& esm, bool wide) { @@ -27,6 +38,7 @@ void ESM::RefNum::save (ESMWriter &esm, bool wide, const std::string& tag) const void ESM::CellRef::load (ESMReader& esm, bool wideRefNum) { + mIsDeleted = false; loadId(esm, wideRefNum); loadData(esm); } @@ -97,6 +109,8 @@ void ESM::CellRef::loadData(ESMReader &esm) if (esm.isNextSub("NAM0")) esm.skipHSub(); + + mIsDeleted = readDeleSubRecord (esm); } void ESM::CellRef::save (ESMWriter &esm, bool wideRefNum, bool inInventory) const @@ -149,6 +163,11 @@ void ESM::CellRef::save (ESMWriter &esm, bool wideRefNum, bool inInventory) cons if (!inInventory) esm.writeHNT("DATA", mPos, 24); + + if (mIsDeleted) + { + writeDeleSubRecord(esm); + } } void ESM::CellRef::blank() @@ -178,6 +197,8 @@ void ESM::CellRef::blank() mPos.pos[i] = 0; mPos.rot[i] = 0; } + + mIsDeleted = false; } bool ESM::operator== (const RefNum& left, const RefNum& right) diff --git a/components/esm/cellref.hpp b/components/esm/cellref.hpp index e9959611b..553dbaae3 100644 --- a/components/esm/cellref.hpp +++ b/components/esm/cellref.hpp @@ -99,6 +99,10 @@ namespace ESM // Position and rotation of this object within the cell Position mPos; + bool mIsDeleted; + + CellRef(); + /// Calls loadId and loadData void load (ESMReader& esm, bool wideRefNum = false); diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index 86b4e4edb..67701a5b7 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -177,7 +177,7 @@ std::string Cell::getDescription() const } } -bool Cell::getNextRef(ESMReader &esm, CellRef &ref, bool& deleted, bool ignoreMoves, MovedCellRef *mref) +bool Cell::getNextRef(ESMReader &esm, CellRef &ref, bool ignoreMoves, MovedCellRef *mref) { // TODO: Try and document reference numbering, I don't think this has been done anywhere else. if (!esm.hasMoreSubs()) @@ -206,14 +206,6 @@ bool Cell::getNextRef(ESMReader &esm, CellRef &ref, bool& deleted, bool ignoreMo // Identify references belonging to a parent file and adapt the ID accordingly. adjustRefNum (ref.mRefNum, esm); - if (esm.isNextSub("DELE")) - { - esm.skipHSub(); - deleted = true; - } - else - deleted = false; - return true; } @@ -244,6 +236,8 @@ bool Cell::getNextMVRF(ESMReader &esm, MovedCellRef &mref) mAmbi.mSunlight = 0; mAmbi.mFog = 0; mAmbi.mFogDensity = 0; + + mIsDeleted = false; } CellId Cell::getCellId() const diff --git a/components/esm/loadcell.hpp b/components/esm/loadcell.hpp index bf65c5fa8..a1a758e3b 100644 --- a/components/esm/loadcell.hpp +++ b/components/esm/loadcell.hpp @@ -163,8 +163,7 @@ struct Cell reuse one memory location without blanking it between calls. */ /// \param ignoreMoves ignore MVRF record and read reference like a regular CellRef. - static bool getNextRef(ESMReader &esm, - CellRef &ref, bool& deleted, bool ignoreMoves = false, MovedCellRef *mref = 0); + static bool getNextRef(ESMReader &esm, CellRef &ref, bool ignoreMoves = false, MovedCellRef *mref = 0); /* This fetches an MVRF record, which is used to track moved references. * Since they are comparably rare, we use a separate method for this. From 992b7703155300f6a0c83b47f78f6513561f0a66 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 15 Jul 2015 18:52:23 +0200 Subject: [PATCH 1830/3725] Don't set OnPcEquip for items that failed to equip (Fixes #2776) --- apps/openmw/mwgui/inventorywindow.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 392a4a84a..39f476403 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -436,6 +436,20 @@ namespace MWGui { const std::string& script = ptr.getClass().getScript(ptr); + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + + // early-out for items that need to be equipped, but can't be equipped: we don't want to set OnPcEquip in that case + if (!ptr.getClass().getEquipmentSlots(ptr).first.empty()) + { + std::pair canEquip = ptr.getClass().canBeEquipped(ptr, player); + if (canEquip.first == 0) + { + MWBase::Environment::get().getWindowManager()->messageBox(canEquip.second); + updateItemView(); + return; + } + } + // If the item has a script, set its OnPcEquip to 1 if (!script.empty() // Another morrowind oddity: when an item has skipped equipping and pcskipequip is reset to 0 afterwards, @@ -455,7 +469,7 @@ namespace MWGui { boost::shared_ptr action = ptr.getClass().use(ptr); - action->execute (MWBase::Environment::get().getWorld()->getPlayerPtr()); + action->execute (player); mSkippedToEquip = MWWorld::Ptr(); } From f8d360190d7443337e5a1d48d8b0505491c5fd73 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 15 Jul 2015 19:10:09 +0200 Subject: [PATCH 1831/3725] Remove an unneeded virtual --- apps/openmw/mwgui/windowbase.hpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwgui/windowbase.hpp b/apps/openmw/mwgui/windowbase.hpp index 195b6c384..43fb8901e 100644 --- a/apps/openmw/mwgui/windowbase.hpp +++ b/apps/openmw/mwgui/windowbase.hpp @@ -21,16 +21,16 @@ namespace MWGui // Events typedef MyGUI::delegates::CMultiDelegate1 EventHandle_WindowBase; - ///Unhides the window + /// Notify that window has been made visible virtual void open() {} - ///Hides the window + /// Notify that window has been hidden virtual void close () {} - ///Gracefully exits the window + /// Gracefully exits the window virtual void exit() {} - ///Sets the visibility of the window + /// Sets the visibility of the window virtual void setVisible(bool visible); - ///Returns the visibility state of the window - virtual bool isVisible(); + /// Returns the visibility state of the window + bool isVisible(); void center(); }; From 3ba73f5fd9feb9727b56f32767c848e520d9a94c Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Wed, 15 Jul 2015 20:53:08 +0300 Subject: [PATCH 1832/3725] Handle deleted records in RefCollection --- apps/opencs/model/world/refcollection.cpp | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/apps/opencs/model/world/refcollection.cpp b/apps/opencs/model/world/refcollection.cpp index ff30dafae..d32f21d0a 100644 --- a/apps/opencs/model/world/refcollection.cpp +++ b/apps/opencs/model/world/refcollection.cpp @@ -20,12 +20,10 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool Cell& cell2 = base ? cell.mBase : cell.mModified; CellRef ref; - - bool deleted = false; ESM::MovedCellRef mref; // hack to initialise mindex - while (!(mref.mRefNum.mIndex = 0) && ESM::Cell::getNextRef(reader, ref, deleted, true, &mref)) + while (!(mref.mRefNum.mIndex = 0) && ESM::Cell::getNextRef(reader, ref, true, &mref)) { // Keep mOriginalCell empty when in modified (as an indicator that the // original cell will always be equal the current cell). @@ -50,17 +48,6 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool // https://forum.openmw.org/viewtopic.php?f=6&t=577&start=30 ref.mOriginalCell = cell2.mId; - if (deleted) - { - // FIXME: how to mark the record deleted? - CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Cell, - mCells.getId (cellIndex)); - - messages.add (id, "Moved reference "+ref.mRefID+" is in DELE state"); - - continue; - } - // It is not always possibe to ignore moved references sub-record and // calculate from coordinates. Some mods may place the ref in positions // outside normal bounds, resulting in non sensical cell id's. This often @@ -92,7 +79,7 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool break; } - if (deleted) + if (ref.mIsDeleted) { if (iter==cache.end()) { @@ -100,7 +87,6 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool mCells.getId (cellIndex)); messages.add (id, "Attempt to delete a non-existing reference"); - continue; } @@ -108,7 +94,7 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool Record record = getRecord (index); - if (record.mState==RecordBase::State_BaseOnly) + if (base) { removeRows (index, 1); cache.erase (iter); From 2016ff773fbf0376c28dfaa9df0ff65d47052f84 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 16 Jul 2015 12:36:20 +0200 Subject: [PATCH 1833/3725] display script errors in script subview --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/view/world/scripterrortable.cpp | 87 +++++++++++++++++++++ apps/opencs/view/world/scripterrortable.hpp | 45 +++++++++++ apps/opencs/view/world/scriptsubview.cpp | 33 +++++++- apps/opencs/view/world/scriptsubview.hpp | 4 + 5 files changed, 166 insertions(+), 5 deletions(-) create mode 100644 apps/opencs/view/world/scripterrortable.cpp create mode 100644 apps/opencs/view/world/scripterrortable.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 4c7801d46..96e5a5b32 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -64,7 +64,7 @@ opencs_units (view/world table tablesubview scriptsubview util regionmapsubview tablebottombox creator genericcreator cellcreator referenceablecreator referencecreator scenesubview infocreator scriptedit dialoguesubview previewsubview regionmap dragrecordtable nestedtable - dialoguespinbox recordbuttonbar tableeditidaction + dialoguespinbox recordbuttonbar tableeditidaction scripterrortable ) opencs_units_noqt (view/world diff --git a/apps/opencs/view/world/scripterrortable.cpp b/apps/opencs/view/world/scripterrortable.cpp new file mode 100644 index 000000000..0c97339dc --- /dev/null +++ b/apps/opencs/view/world/scripterrortable.cpp @@ -0,0 +1,87 @@ + +#include "scripterrortable.hpp" + +#include + +#include +#include +#include +#include +#include + +#include "../../model/doc/document.hpp" + + +void CSVWorld::ScriptErrorTable::report (const std::string& message, const Compiler::TokenLoc& loc, Type type) +{ + addMessage (message, type==Compiler::ErrorHandler::WarningMessage ? + CSMDoc::Message::Severity_Warning : CSMDoc::Message::Severity_Error, loc.mLine); +} + +void CSVWorld::ScriptErrorTable::report (const std::string& message, Type type) +{ + addMessage (message, type==Compiler::ErrorHandler::WarningMessage ? + CSMDoc::Message::Severity_Warning : CSMDoc::Message::Severity_Error); +} + +void CSVWorld::ScriptErrorTable::addMessage (const std::string& message, + CSMDoc::Message::Severity severity, int line) +{ + int row = rowCount(); + + setRowCount (row+1); + + setItem (row, 0, new QTableWidgetItem ("")); + + if (line!=-1) + { + QTableWidgetItem *item = new QTableWidgetItem; + item->setData (Qt::DisplayRole, line+1); + setItem (row, 1, item); + } + + setItem (row, 2, new QTableWidgetItem (QString::fromUtf8 (message.c_str()))); +} + +CSVWorld::ScriptErrorTable::ScriptErrorTable (const CSMDoc::Document& document, QWidget *parent) +: QTableWidget (parent), mContext (document.getData()) +{ + setColumnCount (3); + + QStringList headers; + headers << "Severity" << "Line" << "Description"; + setHorizontalHeaderLabels (headers); + horizontalHeader()->setStretchLastSection (true); + + Compiler::registerExtensions (mExtensions); + mContext.setExtensions (&mExtensions); +} + +void CSVWorld::ScriptErrorTable::updateUserSetting (const QString& name, const QStringList& value) +{ + +} + +void CSVWorld::ScriptErrorTable::update (const std::string& source) +{ + setRowCount (0); + + try + { + std::istringstream input (source); + + Compiler::Scanner scanner (*this, input, mContext.getExtensions()); + + Compiler::FileParser parser (*this, mContext); + + scanner.scan (parser); + } + catch (const Compiler::SourceException&) + { + // error has already been reported via error handler + } + catch (const std::exception& error) + { + addMessage (error.what(), CSMDoc::Message::Severity_SeriousError); + } +} diff --git a/apps/opencs/view/world/scripterrortable.hpp b/apps/opencs/view/world/scripterrortable.hpp new file mode 100644 index 000000000..791125c12 --- /dev/null +++ b/apps/opencs/view/world/scripterrortable.hpp @@ -0,0 +1,45 @@ +#ifndef CSV_WORLD_SCRIPTERRORTABLE_H +#define CSV_WORLD_SCRIPTERRORTABLE_H + +#include + +#include +#include + +#include "../../model/world/scriptcontext.hpp" +#include "../../model/doc/messages.hpp" + +namespace CSMDoc +{ + class Document; +} + +namespace CSVWorld +{ + class ScriptErrorTable : public QTableWidget, private Compiler::ErrorHandler + { + Q_OBJECT + + Compiler::Extensions mExtensions; + CSMWorld::ScriptContext mContext; + + virtual void report (const std::string& message, const Compiler::TokenLoc& loc, Type type); + ///< Report error to the user. + + virtual void report (const std::string& message, Type type); + ///< Report a file related error + + void addMessage (const std::string& message, CSMDoc::Message::Severity severity, + int line = -1); + + public: + + ScriptErrorTable (const CSMDoc::Document& document, QWidget *parent = 0); + + void updateUserSetting (const QString& name, const QStringList& value); + + void update (const std::string& source); + }; +} + +#endif diff --git a/apps/opencs/view/world/scriptsubview.cpp b/apps/opencs/view/world/scriptsubview.cpp index 181400c88..d48e647d9 100644 --- a/apps/opencs/view/world/scriptsubview.cpp +++ b/apps/opencs/view/world/scriptsubview.cpp @@ -4,6 +4,7 @@ #include #include +#include #include "../../model/doc/document.hpp" #include "../../model/world/universalid.hpp" @@ -17,6 +18,7 @@ #include "recordbuttonbar.hpp" #include "tablebottombox.hpp" #include "genericcreator.hpp" +#include "scripterrortable.hpp" void CSVWorld::ScriptSubView::addButtonBar() { @@ -40,7 +42,16 @@ CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc: std::vector selection (1, id.getId()); mCommandDispatcher.setSelection (selection); - mLayout.addWidget (mEditor = new ScriptEdit (mDocument, ScriptHighlighter::Mode_General, this), 2); + mMain = new QSplitter (this); + mMain->setOrientation (Qt::Vertical); + mLayout.addWidget (mMain, 2); + + mEditor = new ScriptEdit (mDocument, ScriptHighlighter::Mode_General, this); + mMain->addWidget (mEditor); + mMain->setCollapsible (0, false); + + mErrors = new ScriptErrorTable (document, this); + mMain->addWidget (mErrors); QWidget *widget = new QWidget (this);; widget->setLayout (&mLayout); @@ -60,7 +71,9 @@ CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc: if (mColumn==-1) throw std::logic_error ("Can't find script column"); - mEditor->setPlainText (mModel->data (mModel->getModelIndex (id.getId(), mColumn)).toString()); + QString source = mModel->data (mModel->getModelIndex (id.getId(), mColumn)).toString(); + + mEditor->setPlainText (source); // bottom box and buttons mBottom = new TableBottomBox (CreatorFactory(), document, id, this); @@ -83,6 +96,8 @@ CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc: updateStatusBar(); connect(mEditor, SIGNAL(cursorPositionChanged()), this, SLOT(updateStatusBar())); + + mErrors->update (source.toUtf8().constData()); } void CSVWorld::ScriptSubView::updateUserSetting (const QString& name, const QStringList& value) @@ -116,6 +131,8 @@ void CSVWorld::ScriptSubView::updateUserSetting (const QString& name, const QStr if (mButtons) mButtons->updateUserSetting (name, value); + + mErrors->updateUserSetting (name, value); } void CSVWorld::ScriptSubView::setStatusBar (bool show) @@ -173,8 +190,12 @@ void CSVWorld::ScriptSubView::textChanged() ScriptEdit::ChangeLock lock (*mEditor); + QString source = mEditor->toPlainText(); + mDocument.getUndoStack().push (new CSMWorld::ModifyCommand (*mModel, - mModel->getModelIndex (getUniversalId().getId(), mColumn), mEditor->toPlainText())); + mModel->getModelIndex (getUniversalId().getId(), mColumn), source)); + + mErrors->update (source.toUtf8().constData()); } void CSVWorld::ScriptSubView::dataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) @@ -189,9 +210,13 @@ void CSVWorld::ScriptSubView::dataChanged (const QModelIndex& topLeft, const QMo if (index.row()>=topLeft.row() && index.row()<=bottomRight.row() && index.column()>=topLeft.column() && index.column()<=bottomRight.column()) { + QString source = mModel->data (index).toString(); + QTextCursor cursor = mEditor->textCursor(); - mEditor->setPlainText (mModel->data (index).toString()); + mEditor->setPlainText (source); mEditor->setTextCursor (cursor); + + mErrors->update (source.toUtf8().constData()); } } diff --git a/apps/opencs/view/world/scriptsubview.hpp b/apps/opencs/view/world/scriptsubview.hpp index 6e5276c68..0b6f4d923 100644 --- a/apps/opencs/view/world/scriptsubview.hpp +++ b/apps/opencs/view/world/scriptsubview.hpp @@ -10,6 +10,7 @@ class QModelIndex; class QLabel; class QVBoxLayout; +class QSplitter; namespace CSMDoc { @@ -26,6 +27,7 @@ namespace CSVWorld class ScriptEdit; class RecordButtonBar; class TableBottomBox; + class ScriptErrorTable; class ScriptSubView : public CSVDoc::SubView { @@ -39,6 +41,8 @@ namespace CSVWorld RecordButtonBar *mButtons; CSMWorld::CommandDispatcher mCommandDispatcher; QVBoxLayout mLayout; + QSplitter *mMain; + ScriptErrorTable *mErrors; private: From 2d8a78726dbab573041cd97d922a4814bc3471ff Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 16 Jul 2015 14:09:14 +0200 Subject: [PATCH 1834/3725] improved error reporting --- apps/opencs/view/world/scripterrortable.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/opencs/view/world/scripterrortable.cpp b/apps/opencs/view/world/scripterrortable.cpp index 0c97339dc..cb793237a 100644 --- a/apps/opencs/view/world/scripterrortable.cpp +++ b/apps/opencs/view/world/scripterrortable.cpp @@ -14,7 +14,10 @@ void CSVWorld::ScriptErrorTable::report (const std::string& message, const Compiler::TokenLoc& loc, Type type) { - addMessage (message, type==Compiler::ErrorHandler::WarningMessage ? + std::ostringstream stream; + stream << message << " (" << loc.mLiteral << ")"; + + addMessage (stream.str(), type==Compiler::ErrorHandler::WarningMessage ? CSMDoc::Message::Severity_Warning : CSMDoc::Message::Severity_Error, loc.mLine); } From 9b12b4f1e25dff384137a8915ddc460acdbd749e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 16 Jul 2015 14:46:02 +0200 Subject: [PATCH 1835/3725] refactored mapping from message severity enum to string --- apps/opencs/model/doc/messages.cpp | 16 +++++++++++++++- apps/opencs/model/doc/messages.hpp | 8 +++++--- apps/opencs/model/tools/reportmodel.cpp | 20 +++++++------------- apps/opencs/view/world/scripterrortable.cpp | 2 +- 4 files changed, 28 insertions(+), 18 deletions(-) diff --git a/apps/opencs/model/doc/messages.cpp b/apps/opencs/model/doc/messages.cpp index bd6e808c8..c8d26d39b 100644 --- a/apps/opencs/model/doc/messages.cpp +++ b/apps/opencs/model/doc/messages.cpp @@ -8,6 +8,20 @@ CSMDoc::Message::Message (const CSMWorld::UniversalId& id, const std::string& me : mId (id), mMessage (message), mHint (hint), mSeverity (severity) {} +std::string CSMDoc::Message::toString (Severity severity) +{ + switch (severity) + { + case CSMDoc::Message::Severity_Info: return "Information"; + case CSMDoc::Message::Severity_Warning: return "Warning"; + case CSMDoc::Message::Severity_Error: return "Error"; + case CSMDoc::Message::Severity_SeriousError: return "Serious Error"; + case CSMDoc::Message::Severity_Default: break; + } + + return ""; +} + CSMDoc::Messages::Messages (Message::Severity default_) : mDefault (default_) @@ -18,7 +32,7 @@ void CSMDoc::Messages::add (const CSMWorld::UniversalId& id, const std::string& { if (severity==Message::Severity_Default) severity = mDefault; - + mMessages.push_back (Message (id, message, hint, severity)); } diff --git a/apps/opencs/model/doc/messages.hpp b/apps/opencs/model/doc/messages.hpp index 86f5feb15..429feae4e 100644 --- a/apps/opencs/model/doc/messages.hpp +++ b/apps/opencs/model/doc/messages.hpp @@ -21,18 +21,20 @@ namespace CSMDoc // reporting it correctly Severity_Default = 4 }; - + CSMWorld::UniversalId mId; std::string mMessage; std::string mHint; Severity mSeverity; Message(); - + Message (const CSMWorld::UniversalId& id, const std::string& message, const std::string& hint, Severity severity); + + static std::string toString (Severity severity); }; - + class Messages { public: diff --git a/apps/opencs/model/tools/reportmodel.cpp b/apps/opencs/model/tools/reportmodel.cpp index 480691710..4bf7d1581 100644 --- a/apps/opencs/model/tools/reportmodel.cpp +++ b/apps/opencs/model/tools/reportmodel.cpp @@ -13,7 +13,7 @@ CSMTools::ReportModel::ReportModel (bool fieldColumn, bool severityColumn) if (severityColumn) mColumnSeverity = index++; - + if (fieldColumn) mColumnField = index++; @@ -46,7 +46,7 @@ QVariant CSMTools::ReportModel::data (const QModelIndex & index, int role) const case Column_Type: return static_cast (mRows.at (index.row()).mId.getType()); - + case Column_Id: { CSMWorld::UniversalId id = mRows.at (index.row()).mId; @@ -56,7 +56,7 @@ QVariant CSMTools::ReportModel::data (const QModelIndex & index, int role) const return QString ("-"); } - + case Column_Hint: return QString::fromUtf8 (mRows.at (index.row()).mHint.c_str()); @@ -85,16 +85,10 @@ QVariant CSMTools::ReportModel::data (const QModelIndex & index, int role) const if (index.column()==mColumnSeverity) { - switch (mRows.at (index.row()).mSeverity) - { - case CSMDoc::Message::Severity_Info: return "Information"; - case CSMDoc::Message::Severity_Warning: return "Warning"; - case CSMDoc::Message::Severity_Error: return "Error"; - case CSMDoc::Message::Severity_SeriousError: return "Serious Error"; - case CSMDoc::Message::Severity_Default: break; - } + return QString::fromUtf8 ( + CSMDoc::Message::toString (mRows.at (index.row()).mSeverity).c_str()); } - + return QVariant(); } @@ -144,7 +138,7 @@ bool CSMTools::ReportModel::removeRows (int row, int count, const QModelIndex& p void CSMTools::ReportModel::add (const CSMDoc::Message& message) { beginInsertRows (QModelIndex(), mRows.size(), mRows.size()); - + mRows.push_back (message); endInsertRows(); diff --git a/apps/opencs/view/world/scripterrortable.cpp b/apps/opencs/view/world/scripterrortable.cpp index cb793237a..dfa036824 100644 --- a/apps/opencs/view/world/scripterrortable.cpp +++ b/apps/opencs/view/world/scripterrortable.cpp @@ -34,7 +34,7 @@ void CSVWorld::ScriptErrorTable::addMessage (const std::string& message, setRowCount (row+1); - setItem (row, 0, new QTableWidgetItem ("")); + setItem (row, 0, new QTableWidgetItem (QString::fromUtf8 (CSMDoc::Message::toString (severity).c_str()))); if (line!=-1) { From f6f82d433c77cb68b16d88785ed210179287addd Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 16 Jul 2015 19:55:05 +0200 Subject: [PATCH 1836/3725] Fix bug with loop key assignment Animations with time of "loop start" == time of "loop stop" were not getting their loop times assigned correctly. This fixes incorrect playing of the jump animation, one aspect of Bug #2286. --- apps/openmw/mwrender/animation.cpp | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 84f46c4ab..dab289f6c 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -598,23 +598,20 @@ namespace MWRender state.setTime(state.mStartTime + ((state.mStopTime - state.mStartTime) * startpoint)); // mLoopStartTime and mLoopStopTime normally get assigned when encountering these keys while playing the animation - // (see handleTextKey). But if startpoint is already past these keys, we need to assign them now. - if(state.getTime() > state.mStartTime) - { - const std::string loopstarttag = groupname+": loop start"; - const std::string loopstoptag = groupname+": loop stop"; + // (see handleTextKey). But if startpoint is already past these keys, or start time is == stop time, we need to assign them now. + const std::string loopstarttag = groupname+": loop start"; + const std::string loopstoptag = groupname+": loop stop"; - NifOsg::TextKeyMap::const_reverse_iterator key(groupend); - for (; key != startkey && key != keys.rend(); ++key) - { - if (key->first > state.getTime()) - continue; + NifOsg::TextKeyMap::const_reverse_iterator key(groupend); + for (; key != startkey && key != keys.rend(); ++key) + { + if (key->first > state.getTime()) + continue; - if (key->second == loopstarttag) - state.mLoopStartTime = key->first; - else if (key->second == loopstoptag) - state.mLoopStopTime = key->first; - } + if (key->second == loopstarttag) + state.mLoopStartTime = key->first; + else if (key->second == loopstoptag) + state.mLoopStopTime = key->first; } return true; From b5c79738f10822f0814e3244100ed5ade56bb99b Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 16 Jul 2015 19:56:09 +0200 Subject: [PATCH 1837/3725] Fix enchantments casting more than once per button press, broken by a1432b0255dd659 --- apps/openmw/mwmechanics/character.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 95546dca9..9ccee84f6 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -43,6 +43,7 @@ #include "../mwworld/class.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwworld/esmstore.hpp" +#include "../mwworld/player.hpp" namespace { @@ -1169,6 +1170,10 @@ bool CharacterController::updateWeaponState() // Unset casting flag, otherwise pressing the mouse button down would // continue casting every frame if there is no animation mAttackingOrSpell = false; + if (mPtr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + { + MWBase::Environment::get().getWorld()->getPlayer().setAttackingOrSpell(false); + } const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); From cc59493cb2e227561eea680c5e34c8dc794cbf2d Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 16 Jul 2015 20:03:16 +0200 Subject: [PATCH 1838/3725] Don't restart the jump animation when equipping a different weapon (Fixes #2286) --- apps/openmw/mwmechanics/character.cpp | 39 ++++++++++++++------------- apps/openmw/mwmechanics/character.hpp | 2 +- 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 9ccee84f6..8fa02c3cd 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -237,7 +237,7 @@ std::string CharacterController::chooseRandomGroup (const std::string& prefix, i return prefix + toString(roll); } -void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterState movement, bool force) +void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterState movement, JumpingState jump, bool force) { // hit recoils/knockdown animations handling if(mPtr.getClass().isActor()) @@ -314,40 +314,41 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat if (!mPtr.getClass().isBipedal(mPtr)) weap = sWeaponTypeListEnd; - if(force && mJumpState != JumpState_None) + if(force || jump != mJumpState) { - std::string jump; + bool startAtLoop = (jump == mJumpState); + mJumpState = jump; + + std::string jumpAnimName; MWRender::Animation::BlendMask jumpmask = MWRender::Animation::BlendMask_All; if(mJumpState != JumpState_None) { - jump = "jump"; + jumpAnimName = "jump"; if(weap != sWeaponTypeListEnd) { - jump += weap->shortgroup; - if(!mAnimation->hasAnimation(jump)) + jumpAnimName += weap->shortgroup; + if(!mAnimation->hasAnimation(jumpAnimName)) { jumpmask = MWRender::Animation::BlendMask_LowerBody; - jump = "jump"; + jumpAnimName = "jump"; } } } if(mJumpState == JumpState_InAir) { - int mode = ((jump == mCurrentJump) ? 2 : 1); - mAnimation->disable(mCurrentJump); - mCurrentJump = jump; + mCurrentJump = jumpAnimName; if (mAnimation->hasAnimation("jump")) mAnimation->play(mCurrentJump, Priority_Jump, jumpmask, false, - 1.0f, ((mode!=2)?"start":"loop start"), "stop", 0.0f, ~0ul); + 1.0f, (startAtLoop?"loop start":"start"), "stop", 0.0f, ~0ul); } else { mAnimation->disable(mCurrentJump); mCurrentJump.clear(); if (mAnimation->hasAnimation("jump")) - mAnimation->play(jump, Priority_Jump, jumpmask, true, + mAnimation->play(jumpAnimName, Priority_Jump, jumpmask, true, 1.0f, "loop stop", "stop", 0.0f, 0); } } @@ -717,7 +718,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim if(mDeathState == CharState_None) - refreshCurrentAnims(mIdleState, mMovementState, true); + refreshCurrentAnims(mIdleState, mMovementState, mJumpState, true); mAnimation->runAnimation(0.f); } @@ -1556,6 +1557,8 @@ void CharacterController::update(float duration) CharacterState movestate = CharState_None; CharacterState idlestate = CharState_SpecialIdle; + JumpingState jumpstate = JumpState_None; + bool forcestateupdate = false; mHasMovedInXY = std::abs(vec.x())+std::abs(vec.y()) > 0.0f; @@ -1638,7 +1641,7 @@ void CharacterController::update(float duration) } forcestateupdate = (mJumpState != JumpState_InAir); - mJumpState = JumpState_InAir; + jumpstate = JumpState_InAir; static const float fJumpMoveBase = gmst.find("fJumpMoveBase")->getFloat(); static const float fJumpMoveMult = gmst.find("fJumpMoveMult")->getFloat(); @@ -1683,7 +1686,7 @@ void CharacterController::update(float duration) else if(mJumpState == JumpState_InAir) { forcestateupdate = true; - mJumpState = JumpState_Landing; + jumpstate = JumpState_Landing; vec.z() = 0.0f; float height = cls.getCreatureStats(mPtr).land(); @@ -1714,7 +1717,7 @@ void CharacterController::update(float duration) } else { - mJumpState = JumpState_None; + jumpstate = JumpState_None; vec.z() = 0.0f; inJump = false; @@ -1792,7 +1795,7 @@ void CharacterController::update(float duration) forcestateupdate = updateCreatureState() || forcestateupdate; if (!mSkipAnim) - refreshCurrentAnims(idlestate, movestate, forcestateupdate); + refreshCurrentAnims(idlestate, movestate, jumpstate, forcestateupdate); if (inJump) mMovementAnimationControlled = false; @@ -1928,7 +1931,7 @@ void CharacterController::forceStateUpdate() return; clearAnimQueue(); - refreshCurrentAnims(mIdleState, mMovementState, true); + refreshCurrentAnims(mIdleState, mMovementState, mJumpState, true); if(mDeathState != CharState_None) { playRandomDeath(); diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 6b530ae2a..f37afd996 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -186,7 +186,7 @@ class CharacterController : public MWRender::Animation::TextKeyListener void determineAttackType(); - void refreshCurrentAnims(CharacterState idle, CharacterState movement, bool force=false); + void refreshCurrentAnims(CharacterState idle, CharacterState movement, JumpingState jump, bool force=false); void clearAnimQueue(); From 9a115fedbc724ce29e3cae8da6a19d24c28a0fa3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 16 Jul 2015 20:11:33 +0200 Subject: [PATCH 1839/3725] Add ability to copy&paste the version label in the main menu --- files/mygui/openmw_mainmenu.layout | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/files/mygui/openmw_mainmenu.layout b/files/mygui/openmw_mainmenu.layout index f4c7142ce..c4d88ff85 100644 --- a/files/mygui/openmw_mainmenu.layout +++ b/files/mygui/openmw_mainmenu.layout @@ -3,10 +3,12 @@ - + + + From 660e7f5d893ffde813df4f178b891797caa35102 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 17 Jul 2015 03:28:17 +0200 Subject: [PATCH 1840/3725] Don't update animation states in skipAnim mode (Fixes #2782) --- apps/openmw/mwmechanics/character.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 8fa02c3cd..50faaa91b 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1788,14 +1788,17 @@ void CharacterController::update(float duration) } } - // bipedal means hand-to-hand could be used (which is handled in updateWeaponState). an existing InventoryStore means an actual weapon could be used. - if(cls.isBipedal(mPtr) || cls.hasInventoryStore(mPtr)) - forcestateupdate = updateWeaponState() || forcestateupdate; - else - forcestateupdate = updateCreatureState() || forcestateupdate; - if (!mSkipAnim) + { + // bipedal means hand-to-hand could be used (which is handled in updateWeaponState). an existing InventoryStore means an actual weapon could be used. + if(cls.isBipedal(mPtr) || cls.hasInventoryStore(mPtr)) + forcestateupdate = updateWeaponState() || forcestateupdate; + else + forcestateupdate = updateCreatureState() || forcestateupdate; + refreshCurrentAnims(idlestate, movestate, jumpstate, forcestateupdate); + } + if (inJump) mMovementAnimationControlled = false; From 91d71d0fcd690559a47dec6a889ca189ee09a199 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 17 Jul 2015 03:39:09 +0200 Subject: [PATCH 1841/3725] Disable MyGUI's scrollbar autorepeat (Fixes #2779) We are currently using a custom implementation so as to support MyGUI version 3.2.1. When compiled with 3.2.2 or later, we need to disable MyGUI's autorepeat so that it doesn't interfere with ours. --- apps/openmw/mwgui/widgets.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index 158d5fd5e..481ffaade 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -539,6 +539,9 @@ namespace MWGui , mRepeatStepTime(0.1f) , mIsIncreasing(true) { +#if MYGUI_VERSION >= MYGUI_DEFINE_VERSION(3,2,2) + ScrollBar::setRepeatEnabled(false); +#endif } MWScrollBar::~MWScrollBar() From 83ef1f7eea99d02be09408398437682f72e0cacf Mon Sep 17 00:00:00 2001 From: slothlife Date: Fri, 17 Jul 2015 00:56:15 -0500 Subject: [PATCH 1842/3725] Add support for linking OpenSceneGraph statically Added some basic support for linking to OpenSceneGraph and its plugins statically. Also added a library necessary to statically link MyGUI (previously Ogre pulled it in). --- CMakeLists.txt | 62 +++++++++++++++++++++++++- cmake/FindMyGUI.cmake | 1 + components/resource/texturemanager.cpp | 13 ++++++ 3 files changed, 75 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a133a8d6a..a151c8503 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -56,6 +56,8 @@ configure_file ("${OpenMW_SOURCE_DIR}/docs/mainpage.hpp.cmake" "${OpenMW_BINARY_ option(MYGUI_STATIC "Link static build of Mygui into the binaries" FALSE) option(BOOST_STATIC "Link static build of Boost into the binaries" FALSE) option(SDL2_STATIC "Link static build of SDL into the binaries" FALSE) +option(OSG_STATIC "Link static build of OpenSceneGraph into the binaries" FALSE) +option(QT_STATIC "Link static build of QT into the binaries" FALSE) option(OPENMW_UNITY_BUILD "Use fewer compilation units to speed up compile time" FALSE) @@ -199,9 +201,67 @@ IF(BOOST_STATIC) set(Boost_USE_STATIC_LIBS ON) endif() -find_package(OpenSceneGraph 3.2.0 REQUIRED osgDB osgViewer osgGA osgAnimation osgParticle osgQt osgUtil osgFX) +find_package(OpenSceneGraph 3.2.0 REQUIRED osgDB osgViewer osgText osgGA osgAnimation osgParticle osgQt osgUtil osgFX) include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS}) +if(OSG_STATIC) + macro(use_static_osg_plugin_library PLUGIN_NAME) + set(PLUGIN_NAME_DBG ${PLUGIN_NAME}d ${PLUGIN_NAME}D ${PLUGIN_NAME}_d ${PLUGIN_NAME}_D ${PLUGIN_NAME}_debug ${PLUGIN_NAME}) + + # For now, users wishing to do a static build will need to pass the path to where the plugins reside + # More clever logic would need to deduce the path, probably installed under /lib/osgPlugins- + find_library(${PLUGIN_NAME}_LIBRARY_REL NAMES ${PLUGIN_NAME} HINTS ${OSG_PLUGIN_LIB_SEARCH_PATH}) + find_library(${PLUGIN_NAME}_LIBRARY_DBG NAMES ${PLUGIN_NAME_DBG} HINTS ${OSG_PLUGIN_LIB_SEARCH_PATH}) + make_library_set(${PLUGIN_NAME}_LIBRARY) + + if("${${PLUGIN_NAME}_LIBRARY}" STREQUAL "") + message(FATAL_ERROR "Unable to find static OpenSceneGraph plugin: ${PLUGIN_NAME}") + endif() + + set(OPENSCENEGRAPH_LIBRARIES ${OPENSCENEGRAPH_LIBRARIES} ${${PLUGIN_NAME}_LIBRARY}) + endmacro() + + macro(use_static_osg_plugin_dep DEPENDENCY) + find_package(${DEPENDENCY} REQUIRED) + + set(OPENSCENEGRAPH_LIBRARIES ${OPENSCENEGRAPH_LIBRARIES} ${${DEPENDENCY}_LIBRARIES}) + endmacro() + + add_definitions(-DOSG_LIBRARY_STATIC) + + set(PLUGIN_LIST + osgdb_png # depends on libpng, zlib + osgdb_tga + osgdb_dds + osgdb_jpeg # depends on libjpeg + ) + + foreach(PLUGIN ${PLUGIN_LIST}) + use_static_osg_plugin_library(${PLUGIN}) + endforeach() + + # OSG static plugins need to linked against their respective dependencies + set(PLUGIN_DEPS_LIST + PNG # needed by osgdb_png + ZLIB # needed by osgdb_png + JPEG # needed by osgdb_jpeg + ) + + foreach(DEPENDENCY ${PLUGIN_DEPS_LIST}) + use_static_osg_plugin_dep(${DEPENDENCY}) + endforeach() +endif() + +if(QT_STATIC) + if(WIN32) + if(DESIRED_QT_VERSION MATCHES 4) + # QtCore needs WSAAsyncSelect from Ws2_32.lib + set(QT_QTCORE_LIBRARY ${QT_QTCORE_LIBRARY} Ws2_32.lib) + message("QT_QTCORE_LIBRARY: ${QT_QTCORE_LIBRARY}") + endif() + endif() +endif() + find_package(MyGUI REQUIRED) if (${MYGUI_VERSION} VERSION_LESS "3.2.1") message(FATAL_ERROR "OpenMW requires MyGUI 3.2.1 or later, please install the latest version from http://mygui.info") diff --git a/cmake/FindMyGUI.cmake b/cmake/FindMyGUI.cmake index 320765b53..f85b6ba52 100644 --- a/cmake/FindMyGUI.cmake +++ b/cmake/FindMyGUI.cmake @@ -54,6 +54,7 @@ IF (WIN32) #Windows if ( MYGUI_STATIC ) set(LIB_SUFFIX "Static") + find_package(freetype) endif ( MYGUI_STATIC ) find_library ( MYGUI_LIBRARIES_REL NAMES MyGUIEngine${LIB_SUFFIX}.lib HINTS ${MYGUI_LIB_DIR} PATH_SUFFIXES "" release relwithdebinfo minsizerel ) diff --git a/components/resource/texturemanager.cpp b/components/resource/texturemanager.cpp index 62cbd6bb3..eca711b3c 100644 --- a/components/resource/texturemanager.cpp +++ b/components/resource/texturemanager.cpp @@ -1,11 +1,24 @@ #include "texturemanager.hpp" #include +#include #include #include +#ifdef OSG_LIBRARY_STATIC +// This list of plugins should match with the list in the top-level CMakelists.txt. +USE_OSGPLUGIN(png) +USE_OSGPLUGIN(tga) +USE_OSGPLUGIN(dds) +USE_OSGPLUGIN(jpeg) + +// Sets the default windowing system interface according to the OS. +// Necessary for OpenSceneGraph to do some things, like decompression. +USE_GRAPHICSWINDOW() +#endif + namespace { From eab1ec9160674db02c5b701479e86d5acb8c3f43 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 17 Jul 2015 11:52:59 +0200 Subject: [PATCH 1843/3725] consider script warning settings for script subview --- apps/opencs/view/world/scripterrortable.cpp | 19 +++++++++++++++++-- apps/opencs/view/world/scripterrortable.hpp | 2 ++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/world/scripterrortable.cpp b/apps/opencs/view/world/scripterrortable.cpp index dfa036824..29f1d6820 100644 --- a/apps/opencs/view/world/scripterrortable.cpp +++ b/apps/opencs/view/world/scripterrortable.cpp @@ -10,7 +10,7 @@ #include #include "../../model/doc/document.hpp" - +#include "../../model/settings/usersettings.hpp" void CSVWorld::ScriptErrorTable::report (const std::string& message, const Compiler::TokenLoc& loc, Type type) { @@ -44,6 +44,18 @@ void CSVWorld::ScriptErrorTable::addMessage (const std::string& message, } setItem (row, 2, new QTableWidgetItem (QString::fromUtf8 (message.c_str()))); + + +} + +void CSVWorld::ScriptErrorTable::setWarningsMode (const QString& value) +{ + if (value=="Ignore") + Compiler::ErrorHandler::setWarningsMode (0); + else if (value=="Normal") + Compiler::ErrorHandler::setWarningsMode (1); + else if (value=="Strict") + Compiler::ErrorHandler::setWarningsMode (2); } CSVWorld::ScriptErrorTable::ScriptErrorTable (const CSMDoc::Document& document, QWidget *parent) @@ -58,11 +70,14 @@ CSVWorld::ScriptErrorTable::ScriptErrorTable (const CSMDoc::Document& document, Compiler::registerExtensions (mExtensions); mContext.setExtensions (&mExtensions); + + setWarningsMode (CSMSettings::UserSettings::instance().settingValue ("script-editor/warnings")); } void CSVWorld::ScriptErrorTable::updateUserSetting (const QString& name, const QStringList& value) { - + if (name=="script-editor/warnings" && !value.isEmpty()) + setWarningsMode (value.at (0)); } void CSVWorld::ScriptErrorTable::update (const std::string& source) diff --git a/apps/opencs/view/world/scripterrortable.hpp b/apps/opencs/view/world/scripterrortable.hpp index 791125c12..99557fb0d 100644 --- a/apps/opencs/view/world/scripterrortable.hpp +++ b/apps/opencs/view/world/scripterrortable.hpp @@ -32,6 +32,8 @@ namespace CSVWorld void addMessage (const std::string& message, CSMDoc::Message::Severity severity, int line = -1); + void setWarningsMode (const QString& value); + public: ScriptErrorTable (const CSMDoc::Document& document, QWidget *parent = 0); From 56ed0926bd9360365214450f61e3166f952f8ef3 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 17 Jul 2015 12:45:08 +0200 Subject: [PATCH 1844/3725] improved error table layout --- apps/opencs/view/world/scripterrortable.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/opencs/view/world/scripterrortable.cpp b/apps/opencs/view/world/scripterrortable.cpp index 29f1d6820..dc28b8907 100644 --- a/apps/opencs/view/world/scripterrortable.cpp +++ b/apps/opencs/view/world/scripterrortable.cpp @@ -66,7 +66,10 @@ CSVWorld::ScriptErrorTable::ScriptErrorTable (const CSMDoc::Document& document, QStringList headers; headers << "Severity" << "Line" << "Description"; setHorizontalHeaderLabels (headers); + horizontalHeader()->setResizeMode (0, QHeaderView::ResizeToContents); + horizontalHeader()->setResizeMode (1, QHeaderView::ResizeToContents); horizontalHeader()->setStretchLastSection (true); + verticalHeader()->hide(); Compiler::registerExtensions (mExtensions); mContext.setExtensions (&mExtensions); From 100af80388c197e191e71b6d6e533395b006d427 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 17 Jul 2015 13:06:51 +0200 Subject: [PATCH 1845/3725] made error table read only --- apps/opencs/view/world/scripterrortable.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/apps/opencs/view/world/scripterrortable.cpp b/apps/opencs/view/world/scripterrortable.cpp index dc28b8907..460bedefc 100644 --- a/apps/opencs/view/world/scripterrortable.cpp +++ b/apps/opencs/view/world/scripterrortable.cpp @@ -34,16 +34,22 @@ void CSVWorld::ScriptErrorTable::addMessage (const std::string& message, setRowCount (row+1); - setItem (row, 0, new QTableWidgetItem (QString::fromUtf8 (CSMDoc::Message::toString (severity).c_str()))); + QTableWidgetItem *severityItem = new QTableWidgetItem ( + QString::fromUtf8 (CSMDoc::Message::toString (severity).c_str())); + severityItem->setFlags (severityItem->flags() ^ Qt::ItemIsEditable); + setItem (row, 0, severityItem); if (line!=-1) { - QTableWidgetItem *item = new QTableWidgetItem; - item->setData (Qt::DisplayRole, line+1); - setItem (row, 1, item); + QTableWidgetItem *lineItem = new QTableWidgetItem; + lineItem->setData (Qt::DisplayRole, line+1); + lineItem->setFlags (lineItem->flags() ^ Qt::ItemIsEditable); + setItem (row, 1, lineItem); } - setItem (row, 2, new QTableWidgetItem (QString::fromUtf8 (message.c_str()))); + QTableWidgetItem *messageItem = new QTableWidgetItem (QString::fromUtf8 (message.c_str())); + messageItem->setFlags (messageItem->flags() ^ Qt::ItemIsEditable); + setItem (row, 2, messageItem); } From 0abd29a3b455e9fa0f55be0565ee8a1723473816 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 17 Jul 2015 13:42:25 +0200 Subject: [PATCH 1846/3725] jump to line in source text when clicking on an error in error table --- apps/opencs/view/world/scripterrortable.cpp | 10 ++++++++++ apps/opencs/view/world/scripterrortable.hpp | 8 ++++++++ apps/opencs/view/world/scriptsubview.cpp | 16 ++++++++++++++++ apps/opencs/view/world/scriptsubview.hpp | 2 ++ 4 files changed, 36 insertions(+) diff --git a/apps/opencs/view/world/scripterrortable.cpp b/apps/opencs/view/world/scripterrortable.cpp index 460bedefc..242d6c8ac 100644 --- a/apps/opencs/view/world/scripterrortable.cpp +++ b/apps/opencs/view/world/scripterrortable.cpp @@ -77,10 +77,14 @@ CSVWorld::ScriptErrorTable::ScriptErrorTable (const CSMDoc::Document& document, horizontalHeader()->setStretchLastSection (true); verticalHeader()->hide(); + setSelectionMode (QAbstractItemView::NoSelection); + Compiler::registerExtensions (mExtensions); mContext.setExtensions (&mExtensions); setWarningsMode (CSMSettings::UserSettings::instance().settingValue ("script-editor/warnings")); + + connect (this, SIGNAL (cellClicked (int, int)), this, SLOT (cellClicked (int, int))); } void CSVWorld::ScriptErrorTable::updateUserSetting (const QString& name, const QStringList& value) @@ -112,3 +116,9 @@ void CSVWorld::ScriptErrorTable::update (const std::string& source) addMessage (error.what(), CSMDoc::Message::Severity_SeriousError); } } + +void CSVWorld::ScriptErrorTable::cellClicked (int row, int column) +{ + int line = item (row, 1)->data (Qt::DisplayRole).toInt(); + emit highlightError (line-1); +} diff --git a/apps/opencs/view/world/scripterrortable.hpp b/apps/opencs/view/world/scripterrortable.hpp index 99557fb0d..5c6e75164 100644 --- a/apps/opencs/view/world/scripterrortable.hpp +++ b/apps/opencs/view/world/scripterrortable.hpp @@ -41,6 +41,14 @@ namespace CSVWorld void updateUserSetting (const QString& name, const QStringList& value); void update (const std::string& source); + + private slots: + + void cellClicked (int row, int column); + + signals: + + void highlightError (int line); }; } diff --git a/apps/opencs/view/world/scriptsubview.cpp b/apps/opencs/view/world/scriptsubview.cpp index d48e647d9..36e21d53b 100644 --- a/apps/opencs/view/world/scriptsubview.cpp +++ b/apps/opencs/view/world/scriptsubview.cpp @@ -98,6 +98,8 @@ CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc: connect(mEditor, SIGNAL(cursorPositionChanged()), this, SLOT(updateStatusBar())); mErrors->update (source.toUtf8().constData()); + + connect (mErrors, SIGNAL (highlightError (int)), this, SLOT (highlightError (int))); } void CSVWorld::ScriptSubView::updateUserSetting (const QString& name, const QStringList& value) @@ -244,3 +246,17 @@ void CSVWorld::ScriptSubView::switchToId (const std::string& id) { switchToRow (mModel->getModelIndex (id, 0).row()); } + +void CSVWorld::ScriptSubView::highlightError (int line) +{ + QTextCursor cursor = mEditor->textCursor(); + + cursor.movePosition (QTextCursor::Start); + if (cursor.movePosition (QTextCursor::Down, QTextCursor::MoveAnchor, line)) + { +// cursor.movePosition (QTextCursor::Right, QTextCursor::MoveAnchor, column); + } + + mEditor->setFocus(); + mEditor->setTextCursor (cursor); +} diff --git a/apps/opencs/view/world/scriptsubview.hpp b/apps/opencs/view/world/scriptsubview.hpp index 0b6f4d923..6be943bb8 100644 --- a/apps/opencs/view/world/scriptsubview.hpp +++ b/apps/opencs/view/world/scriptsubview.hpp @@ -75,6 +75,8 @@ namespace CSVWorld void switchToRow (int row); void switchToId (const std::string& id); + + void highlightError (int line); }; } From f665919046bf1b923424ad0af7944f60f8a5d47b Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 17 Jul 2015 13:53:22 +0200 Subject: [PATCH 1847/3725] consider column when jumping to error in source text --- apps/opencs/view/world/scripterrortable.cpp | 20 +++++++++++++------- apps/opencs/view/world/scripterrortable.hpp | 4 ++-- apps/opencs/view/world/scriptsubview.cpp | 9 ++++----- apps/opencs/view/world/scriptsubview.hpp | 2 +- 4 files changed, 20 insertions(+), 15 deletions(-) diff --git a/apps/opencs/view/world/scripterrortable.cpp b/apps/opencs/view/world/scripterrortable.cpp index 242d6c8ac..ec84a8328 100644 --- a/apps/opencs/view/world/scripterrortable.cpp +++ b/apps/opencs/view/world/scripterrortable.cpp @@ -18,7 +18,8 @@ void CSVWorld::ScriptErrorTable::report (const std::string& message, const Compi stream << message << " (" << loc.mLiteral << ")"; addMessage (stream.str(), type==Compiler::ErrorHandler::WarningMessage ? - CSMDoc::Message::Severity_Warning : CSMDoc::Message::Severity_Error, loc.mLine); + CSMDoc::Message::Severity_Warning : CSMDoc::Message::Severity_Error, + loc.mLine, loc.mColumn-loc.mLiteral.length()); } void CSVWorld::ScriptErrorTable::report (const std::string& message, Type type) @@ -28,7 +29,7 @@ void CSVWorld::ScriptErrorTable::report (const std::string& message, Type type) } void CSVWorld::ScriptErrorTable::addMessage (const std::string& message, - CSMDoc::Message::Severity severity, int line) + CSMDoc::Message::Severity severity, int line, int column) { int row = rowCount(); @@ -45,13 +46,16 @@ void CSVWorld::ScriptErrorTable::addMessage (const std::string& message, lineItem->setData (Qt::DisplayRole, line+1); lineItem->setFlags (lineItem->flags() ^ Qt::ItemIsEditable); setItem (row, 1, lineItem); + + QTableWidgetItem *columnItem = new QTableWidgetItem; + columnItem->setData (Qt::DisplayRole, column); + columnItem->setFlags (columnItem->flags() ^ Qt::ItemIsEditable); + setItem (row, 3, columnItem); } QTableWidgetItem *messageItem = new QTableWidgetItem (QString::fromUtf8 (message.c_str())); messageItem->setFlags (messageItem->flags() ^ Qt::ItemIsEditable); setItem (row, 2, messageItem); - - } void CSVWorld::ScriptErrorTable::setWarningsMode (const QString& value) @@ -67,7 +71,7 @@ void CSVWorld::ScriptErrorTable::setWarningsMode (const QString& value) CSVWorld::ScriptErrorTable::ScriptErrorTable (const CSMDoc::Document& document, QWidget *parent) : QTableWidget (parent), mContext (document.getData()) { - setColumnCount (3); + setColumnCount (4); QStringList headers; headers << "Severity" << "Line" << "Description"; @@ -76,6 +80,7 @@ CSVWorld::ScriptErrorTable::ScriptErrorTable (const CSMDoc::Document& document, horizontalHeader()->setResizeMode (1, QHeaderView::ResizeToContents); horizontalHeader()->setStretchLastSection (true); verticalHeader()->hide(); + setColumnHidden (3, true); setSelectionMode (QAbstractItemView::NoSelection); @@ -119,6 +124,7 @@ void CSVWorld::ScriptErrorTable::update (const std::string& source) void CSVWorld::ScriptErrorTable::cellClicked (int row, int column) { - int line = item (row, 1)->data (Qt::DisplayRole).toInt(); - emit highlightError (line-1); + int scriptLine = item (row, 1)->data (Qt::DisplayRole).toInt(); + int scriptColumn = item (row, 3)->data (Qt::DisplayRole).toInt(); + emit highlightError (scriptLine-1, scriptColumn); } diff --git a/apps/opencs/view/world/scripterrortable.hpp b/apps/opencs/view/world/scripterrortable.hpp index 5c6e75164..f16a96a74 100644 --- a/apps/opencs/view/world/scripterrortable.hpp +++ b/apps/opencs/view/world/scripterrortable.hpp @@ -30,7 +30,7 @@ namespace CSVWorld ///< Report a file related error void addMessage (const std::string& message, CSMDoc::Message::Severity severity, - int line = -1); + int line = -1, int column = -1); void setWarningsMode (const QString& value); @@ -48,7 +48,7 @@ namespace CSVWorld signals: - void highlightError (int line); + void highlightError (int line, int column); }; } diff --git a/apps/opencs/view/world/scriptsubview.cpp b/apps/opencs/view/world/scriptsubview.cpp index 36e21d53b..7b5b1131e 100644 --- a/apps/opencs/view/world/scriptsubview.cpp +++ b/apps/opencs/view/world/scriptsubview.cpp @@ -99,7 +99,8 @@ CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc: mErrors->update (source.toUtf8().constData()); - connect (mErrors, SIGNAL (highlightError (int)), this, SLOT (highlightError (int))); + connect (mErrors, SIGNAL (highlightError (int, int)), + this, SLOT (highlightError (int, int))); } void CSVWorld::ScriptSubView::updateUserSetting (const QString& name, const QStringList& value) @@ -247,15 +248,13 @@ void CSVWorld::ScriptSubView::switchToId (const std::string& id) switchToRow (mModel->getModelIndex (id, 0).row()); } -void CSVWorld::ScriptSubView::highlightError (int line) +void CSVWorld::ScriptSubView::highlightError (int line, int column) { QTextCursor cursor = mEditor->textCursor(); cursor.movePosition (QTextCursor::Start); if (cursor.movePosition (QTextCursor::Down, QTextCursor::MoveAnchor, line)) - { -// cursor.movePosition (QTextCursor::Right, QTextCursor::MoveAnchor, column); - } + cursor.movePosition (QTextCursor::Right, QTextCursor::MoveAnchor, column); mEditor->setFocus(); mEditor->setTextCursor (cursor); diff --git a/apps/opencs/view/world/scriptsubview.hpp b/apps/opencs/view/world/scriptsubview.hpp index 6be943bb8..a9c8dccb3 100644 --- a/apps/opencs/view/world/scriptsubview.hpp +++ b/apps/opencs/view/world/scriptsubview.hpp @@ -76,7 +76,7 @@ namespace CSVWorld void switchToId (const std::string& id); - void highlightError (int line); + void highlightError (int line, int column); }; } From 5febb96012ea68dda6cb367a18e1fe59a41cb39d Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 17 Jul 2015 13:59:50 +0200 Subject: [PATCH 1848/3725] do not try to jump to source location for errors that do not have a source location --- apps/opencs/view/world/scripterrortable.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/apps/opencs/view/world/scripterrortable.cpp b/apps/opencs/view/world/scripterrortable.cpp index ec84a8328..20b197c54 100644 --- a/apps/opencs/view/world/scripterrortable.cpp +++ b/apps/opencs/view/world/scripterrortable.cpp @@ -124,7 +124,10 @@ void CSVWorld::ScriptErrorTable::update (const std::string& source) void CSVWorld::ScriptErrorTable::cellClicked (int row, int column) { - int scriptLine = item (row, 1)->data (Qt::DisplayRole).toInt(); - int scriptColumn = item (row, 3)->data (Qt::DisplayRole).toInt(); - emit highlightError (scriptLine-1, scriptColumn); + if (item (row, 1)) + { + int scriptLine = item (row, 1)->data (Qt::DisplayRole).toInt(); + int scriptColumn = item (row, 3)->data (Qt::DisplayRole).toInt(); + emit highlightError (scriptLine-1, scriptColumn); + } } From 72728b9c01058ee2d2a6625fd0e542eeb45b14db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ji=C5=99=C3=AD=20Kune=C5=A1?= Date: Fri, 17 Jul 2015 16:32:35 +0200 Subject: [PATCH 1849/3725] disable cusor when item/container is owned --- apps/openmw/mwgui/tooltips.cpp | 22 +++++++++++++++++++ .../mwmechanics/mechanicsmanagerimp.hpp | 6 +++-- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 526cbaabe..18f65e3ba 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -17,6 +17,7 @@ #include "../mwworld/class.hpp" #include "../mwworld/esmstore.hpp" #include "../mwmechanics/spellcasting.hpp" +#include "../mwmechanics/mechanicsmanagerimp.hpp" #include "mapwindow.hpp" #include "inventorywindow.hpp" @@ -342,6 +343,27 @@ namespace MWGui if (!image) info.icon = ""; tooltipSize = createToolTip(info); + + // start owned check + MWWorld::CellRef& cellref = mFocusObject.getCellRef(); + MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr victim; + + MWMechanics::MechanicsManager* mm = new MWMechanics::MechanicsManager; + bool allowed = mm->isAllowedToUse(ptr, cellref, victim); // 0 - owned, 1 - not owned + + MWBase::WindowManager *wm = MWBase::Environment::get().getWindowManager(); + if(allowed) + { + // if 'item' is not owned + wm->showCrosshair(true); + } + else + { + // if 'item' is owned + wm->showCrosshair(false); + } + } return tooltipSize; diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index 5cc2ce254..392d7fbbe 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -175,13 +175,15 @@ namespace MWMechanics /// Has the player stolen this item from the given owner? virtual bool isItemStolenFrom(const std::string& itemid, const std::string& ownerid); + + /// @return is \a ptr allowed to take/use \a cellref or is it a crime? + virtual bool isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::CellRef& cellref, MWWorld::Ptr& victim); private: void reportCrime (const MWWorld::Ptr& ptr, const MWWorld::Ptr& victim, OffenseType type, int arg=0); - /// @return is \a ptr allowed to take/use \a cellref or is it a crime? - virtual bool isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::CellRef& cellref, MWWorld::Ptr& victim); + }; } From df99d5a59d98410391cd2bfe70290db79748b7d9 Mon Sep 17 00:00:00 2001 From: slothlife Date: Fri, 17 Jul 2015 09:56:21 -0500 Subject: [PATCH 1850/3725] Move setup code for OSG when statically linked --- components/resource/texturemanager.cpp | 13 ------------- components/sdlutil/sdlcursormanager.cpp | 14 ++++++++++++++ 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/components/resource/texturemanager.cpp b/components/resource/texturemanager.cpp index eca711b3c..62cbd6bb3 100644 --- a/components/resource/texturemanager.cpp +++ b/components/resource/texturemanager.cpp @@ -1,24 +1,11 @@ #include "texturemanager.hpp" #include -#include #include #include -#ifdef OSG_LIBRARY_STATIC -// This list of plugins should match with the list in the top-level CMakelists.txt. -USE_OSGPLUGIN(png) -USE_OSGPLUGIN(tga) -USE_OSGPLUGIN(dds) -USE_OSGPLUGIN(jpeg) - -// Sets the default windowing system interface according to the OS. -// Necessary for OpenSceneGraph to do some things, like decompression. -USE_GRAPHICSWINDOW() -#endif - namespace { diff --git a/components/sdlutil/sdlcursormanager.cpp b/components/sdlutil/sdlcursormanager.cpp index d8d4b0b50..508d72589 100644 --- a/components/sdlutil/sdlcursormanager.cpp +++ b/components/sdlutil/sdlcursormanager.cpp @@ -10,9 +10,23 @@ #include #include #include +#include +#include #include "imagetosurface.hpp" +#ifdef OSG_LIBRARY_STATIC +// This list of plugins should match with the list in the top-level CMakelists.txt. +USE_OSGPLUGIN(png) +USE_OSGPLUGIN(tga) +USE_OSGPLUGIN(dds) +USE_OSGPLUGIN(jpeg) + +// Sets the default windowing system interface according to the OS. +// Necessary for OpenSceneGraph to do some things, like decompression. +USE_GRAPHICSWINDOW() +#endif + namespace { From 66edae9b932988fbe0fff29260c3d5bf82d88bc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ji=C5=99=C3=AD=20Kune=C5=A1?= Date: Fri, 17 Jul 2015 17:29:00 +0200 Subject: [PATCH 1851/3725] change collor of crosshair --- apps/openmw/mwbase/windowmanager.hpp | 1 + apps/openmw/mwgui/hud.cpp | 16 +++++++++++- apps/openmw/mwgui/hud.hpp | 1 + apps/openmw/mwgui/tooltips.cpp | 36 ++++++++++++++------------ apps/openmw/mwgui/tooltips.hpp | 3 +++ apps/openmw/mwgui/windowmanagerimp.cpp | 6 +++++ apps/openmw/mwgui/windowmanagerimp.hpp | 1 + 7 files changed, 47 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index f8bf157c2..86b42c9f9 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -219,6 +219,7 @@ namespace MWBase virtual void unsetSelectedWeapon() = 0; virtual void showCrosshair(bool show) = 0; + virtual void setCrosshairOwned(bool owned) = 0; virtual bool getSubtitlesEnabled() = 0; virtual bool toggleGui() = 0; diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 76a7248ee..0f107f4e3 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -518,7 +518,21 @@ namespace MWGui { mCrosshair->setVisible (visible); } - + + void HUD::setCrosshairOwned(bool owned) + { + MyGUI::Colour red = MyGUI::Colour(1.0, 0, 0); + MyGUI::Colour white = MyGUI::Colour(1.0, 1.0, 1.0); + if(owned) + { + mCrosshair->setColour(red); + } + else + { + mCrosshair->setColour(white); + } + } + void HUD::setHmsVisible(bool visible) { mHealth->setVisible(visible); diff --git a/apps/openmw/mwgui/hud.hpp b/apps/openmw/mwgui/hud.hpp index 72fc06f6a..629613c98 100644 --- a/apps/openmw/mwgui/hud.hpp +++ b/apps/openmw/mwgui/hud.hpp @@ -47,6 +47,7 @@ namespace MWGui void unsetSelectedWeapon(); void setCrosshairVisible(bool visible); + void setCrosshairOwned(bool owned); void onFrame(float dt); diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 18f65e3ba..34762de5a 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -299,7 +299,10 @@ namespace MWGui tooltipSize.height); mDynamicToolTipBox->setVisible(true); + } + + checkOwned(); } } @@ -344,29 +347,30 @@ namespace MWGui info.icon = ""; tooltipSize = createToolTip(info); - // start owned check + } + + return tooltipSize; + } + + void ToolTips::checkOwned() + { + MWBase::WindowManager *wm = MWBase::Environment::get().getWindowManager(); + + if(!mFocusObject.isEmpty()) + { MWWorld::CellRef& cellref = mFocusObject.getCellRef(); MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr(); MWWorld::Ptr victim; MWMechanics::MechanicsManager* mm = new MWMechanics::MechanicsManager; bool allowed = mm->isAllowedToUse(ptr, cellref, victim); // 0 - owned, 1 - not owned - - MWBase::WindowManager *wm = MWBase::Environment::get().getWindowManager(); - if(allowed) - { - // if 'item' is not owned - wm->showCrosshair(true); - } - else - { - // if 'item' is owned - wm->showCrosshair(false); - } - - } - return tooltipSize; + wm->setCrosshairOwned(!allowed); + } + else + { + wm->setCrosshairOwned(false); + } } MyGUI::IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info) diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp index d14993639..a54888780 100644 --- a/apps/openmw/mwgui/tooltips.hpp +++ b/apps/openmw/mwgui/tooltips.hpp @@ -95,6 +95,9 @@ namespace MWGui MyGUI::IntSize getToolTipViaPtr (bool image=true); ///< @return requested tooltip size + + void checkOwned(); + /// Checks if object is owned and sets correct crosshair mode MyGUI::IntSize createToolTip(const ToolTipInfo& info); ///< @return requested tooltip size diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index a2a826161..2588f2d86 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1423,6 +1423,12 @@ namespace MWGui if (mHud) mHud->setCrosshairVisible (show && mCrosshairEnabled); } + + void WindowManager::setCrosshairOwned (bool owned) + { + if (mHud) + mHud->setCrosshairOwned (owned); + } void WindowManager::activateQuickKey (int index) { diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index e6c8d0a81..94538840b 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -233,6 +233,7 @@ namespace MWGui virtual void unsetSelectedWeapon(); virtual void showCrosshair(bool show); + virtual void setCrosshairOwned(bool owned); virtual bool getSubtitlesEnabled(); /// Turn visibility of *all* GUI elements on or off (HUD and all windows, except the console) From 15107ca5cf4085792a57e10dbcdb7974e8d675b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ji=C5=99=C3=AD=20Kune=C5=A1?= Date: Fri, 17 Jul 2015 17:48:38 +0200 Subject: [PATCH 1852/3725] crosshair owned - settings option --- apps/openmw/mwgui/tooltips.cpp | 29 ++++++++++++++++------------- files/settings-default.cfg | 3 +++ 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 34762de5a..51bdd97f9 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -354,22 +354,25 @@ namespace MWGui void ToolTips::checkOwned() { - MWBase::WindowManager *wm = MWBase::Environment::get().getWindowManager(); - - if(!mFocusObject.isEmpty()) + if(Settings::Manager::getBool("show owned", "Game")) { - MWWorld::CellRef& cellref = mFocusObject.getCellRef(); - MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr(); - MWWorld::Ptr victim; + MWBase::WindowManager *wm = MWBase::Environment::get().getWindowManager(); - MWMechanics::MechanicsManager* mm = new MWMechanics::MechanicsManager; - bool allowed = mm->isAllowedToUse(ptr, cellref, victim); // 0 - owned, 1 - not owned + if(!mFocusObject.isEmpty()) + { + MWWorld::CellRef& cellref = mFocusObject.getCellRef(); + MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr victim; + + MWMechanics::MechanicsManager* mm = new MWMechanics::MechanicsManager; + bool allowed = mm->isAllowedToUse(ptr, cellref, victim); // 0 - owned, 1 - not owned - wm->setCrosshairOwned(!allowed); - } - else - { - wm->setCrosshairOwned(false); + wm->setCrosshairOwned(!allowed); + } + else + { + wm->setCrosshairOwned(false); + } } } diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 0581d7356..4ec0c2480 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -162,6 +162,9 @@ best attack = false difficulty = 0 +# change crosshair color when pointing on owned object +show owned = false + [Saves] character = # Save when resting From c019f8e23dcef0a38ac9d934eb639eab2cf5cf21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ji=C5=99=C3=AD=20Kune=C5=A1?= Date: Fri, 17 Jul 2015 18:49:47 +0200 Subject: [PATCH 1853/3725] use correct mechanics manager --- apps/openmw/mwbase/mechanicsmanager.hpp | 4 ++++ apps/openmw/mwgui/tooltips.cpp | 3 +-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index 1d3619d3d..7889988e9 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -6,6 +6,8 @@ #include #include +#include "../mwworld/ptr.hpp" + namespace osg { class Vec3f; @@ -211,6 +213,8 @@ namespace MWBase /// Has the player stolen this item from the given owner? virtual bool isItemStolenFrom(const std::string& itemid, const std::string& ownerid) = 0; + + virtual bool isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::CellRef& cellref, MWWorld::Ptr& victim) = 0; }; } diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 51bdd97f9..40df4a4b4 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -17,7 +17,6 @@ #include "../mwworld/class.hpp" #include "../mwworld/esmstore.hpp" #include "../mwmechanics/spellcasting.hpp" -#include "../mwmechanics/mechanicsmanagerimp.hpp" #include "mapwindow.hpp" #include "inventorywindow.hpp" @@ -364,7 +363,7 @@ namespace MWGui MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr(); MWWorld::Ptr victim; - MWMechanics::MechanicsManager* mm = new MWMechanics::MechanicsManager; + MWBase::MechanicsManager* mm = MWBase::Environment::get().getMechanicsManager(); bool allowed = mm->isAllowedToUse(ptr, cellref, victim); // 0 - owned, 1 - not owned wm->setCrosshairOwned(!allowed); From e68b388d161030ca1122bbebd4772017701b8dfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ji=C5=99=C3=AD=20Kune=C5=A1?= Date: Fri, 17 Jul 2015 19:13:45 +0200 Subject: [PATCH 1854/3725] removed setCrosshairOwned from windowmanager --- apps/openmw/mwbase/windowmanager.hpp | 1 - apps/openmw/mwgui/tooltips.cpp | 32 +++++++++++--------------- apps/openmw/mwgui/tooltips.hpp | 6 ++--- apps/openmw/mwgui/windowmanagerimp.cpp | 12 +++++----- apps/openmw/mwgui/windowmanagerimp.hpp | 1 - 5 files changed, 22 insertions(+), 30 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 86b42c9f9..f8bf157c2 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -219,7 +219,6 @@ namespace MWBase virtual void unsetSelectedWeapon() = 0; virtual void showCrosshair(bool show) = 0; - virtual void setCrosshairOwned(bool owned) = 0; virtual bool getSubtitlesEnabled() = 0; virtual bool toggleGui() = 0; diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 40df4a4b4..28ff47260 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -300,8 +300,6 @@ namespace MWGui mDynamicToolTipBox->setVisible(true); } - - checkOwned(); } } @@ -351,27 +349,23 @@ namespace MWGui return tooltipSize; } - void ToolTips::checkOwned() + bool ToolTips::checkOwned() { - if(Settings::Manager::getBool("show owned", "Game")) + // true=owned, false=notOwned + if(!mFocusObject.isEmpty()) { - MWBase::WindowManager *wm = MWBase::Environment::get().getWindowManager(); + MWWorld::CellRef& cellref = mFocusObject.getCellRef(); + MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr victim; - if(!mFocusObject.isEmpty()) - { - MWWorld::CellRef& cellref = mFocusObject.getCellRef(); - MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr(); - MWWorld::Ptr victim; - - MWBase::MechanicsManager* mm = MWBase::Environment::get().getMechanicsManager(); - bool allowed = mm->isAllowedToUse(ptr, cellref, victim); // 0 - owned, 1 - not owned + MWBase::MechanicsManager* mm = MWBase::Environment::get().getMechanicsManager(); + bool allowed = mm->isAllowedToUse(ptr, cellref, victim); - wm->setCrosshairOwned(!allowed); - } - else - { - wm->setCrosshairOwned(false); - } + return !allowed; + } + else + { + return false; } } diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp index a54888780..26a4fe2c7 100644 --- a/apps/openmw/mwgui/tooltips.hpp +++ b/apps/openmw/mwgui/tooltips.hpp @@ -87,6 +87,9 @@ namespace MWGui static void createRaceToolTip(MyGUI::Widget* widget, const ESM::Race* playerRace); static void createClassToolTip(MyGUI::Widget* widget, const ESM::Class& playerClass); static void createMagicEffectToolTip(MyGUI::Widget* widget, short id); + + bool checkOwned(); + /// Checks if object is owned and sets correct crosshair mode private: MyGUI::Widget* mDynamicToolTipBox; @@ -95,9 +98,6 @@ namespace MWGui MyGUI::IntSize getToolTipViaPtr (bool image=true); ///< @return requested tooltip size - - void checkOwned(); - /// Checks if object is owned and sets correct crosshair mode MyGUI::IntSize createToolTip(const ToolTipInfo& info); ///< @return requested tooltip size diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 2588f2d86..2f8cfbf62 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1038,6 +1038,12 @@ namespace MWGui void WindowManager::setFocusObject(const MWWorld::Ptr& focus) { mToolTips->setFocusObject(focus); + + if(Settings::Manager::getBool("show owned", "Game") && mHud) + { + bool owned = mToolTips->checkOwned(); + mHud->setCrosshairOwned(owned); + } } void WindowManager::setFocusObjectScreenCoords(float min_x, float min_y, float max_x, float max_y) @@ -1423,12 +1429,6 @@ namespace MWGui if (mHud) mHud->setCrosshairVisible (show && mCrosshairEnabled); } - - void WindowManager::setCrosshairOwned (bool owned) - { - if (mHud) - mHud->setCrosshairOwned (owned); - } void WindowManager::activateQuickKey (int index) { diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 94538840b..e6c8d0a81 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -233,7 +233,6 @@ namespace MWGui virtual void unsetSelectedWeapon(); virtual void showCrosshair(bool show); - virtual void setCrosshairOwned(bool owned); virtual bool getSubtitlesEnabled(); /// Turn visibility of *all* GUI elements on or off (HUD and all windows, except the console) From 4a6d80612729e58d0a8c6441e39035423194ac7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ji=C5=99=C3=AD=20Kune=C5=A1?= Date: Fri, 17 Jul 2015 20:30:00 +0200 Subject: [PATCH 1855/3725] fixed comment, save settings to member variable, removed usless include, changed variable to const --- apps/openmw/mwbase/mechanicsmanager.hpp | 3 +-- apps/openmw/mwgui/tooltips.cpp | 5 +---- apps/openmw/mwgui/tooltips.hpp | 4 ++-- apps/openmw/mwgui/windowmanagerimp.cpp | 5 ++++- apps/openmw/mwgui/windowmanagerimp.hpp | 2 ++ 5 files changed, 10 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index 7889988e9..b66e60e1d 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -6,8 +6,6 @@ #include #include -#include "../mwworld/ptr.hpp" - namespace osg { class Vec3f; @@ -25,6 +23,7 @@ namespace MWWorld { class Ptr; class CellStore; + class CellRef; } namespace Loading diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 28ff47260..22d5d14f7 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -298,7 +298,6 @@ namespace MWGui tooltipSize.height); mDynamicToolTipBox->setVisible(true); - } } } @@ -343,7 +342,6 @@ namespace MWGui if (!image) info.icon = ""; tooltipSize = createToolTip(info); - } return tooltipSize; @@ -351,10 +349,9 @@ namespace MWGui bool ToolTips::checkOwned() { - // true=owned, false=notOwned if(!mFocusObject.isEmpty()) { - MWWorld::CellRef& cellref = mFocusObject.getCellRef(); + const MWWorld::CellRef& cellref = mFocusObject.getCellRef(); MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr(); MWWorld::Ptr victim; diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp index 26a4fe2c7..bd4a81c32 100644 --- a/apps/openmw/mwgui/tooltips.hpp +++ b/apps/openmw/mwgui/tooltips.hpp @@ -89,8 +89,8 @@ namespace MWGui static void createMagicEffectToolTip(MyGUI::Widget* widget, short id); bool checkOwned(); - /// Checks if object is owned and sets correct crosshair mode - + /// Returns True if taking mFocusObject would be crime + private: MyGUI::Widget* mDynamicToolTipBox; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 2f8cfbf62..cb5d4442f 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -187,6 +187,7 @@ namespace MWGui , mRestAllowed(true) , mFPS(0.0f) , mFallbackMap(fallbackMap) + , mShowOwned(false) { float uiScale = Settings::Manager::getFloat("scaling factor", "GUI"); mGuiPlatform = new osgMyGUI::Platform(viewer, guiRoot, resourceSystem->getTextureManager(), uiScale); @@ -261,6 +262,8 @@ namespace MWGui MyGUI::ClipboardManager::getInstance().eventClipboardChanged += MyGUI::newDelegate(this, &WindowManager::onClipboardChanged); MyGUI::ClipboardManager::getInstance().eventClipboardRequested += MyGUI::newDelegate(this, &WindowManager::onClipboardRequested); + + mShowOwned = Settings::Manager::getBool("show owned", "Game"); } void WindowManager::initUI() @@ -1039,7 +1042,7 @@ namespace MWGui { mToolTips->setFocusObject(focus); - if(Settings::Manager::getBool("show owned", "Game") && mHud) + if(mShowOwned && mHud) { bool owned = mToolTips->checkOwned(); mHud->setCrosshairOwned(owned); diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index e6c8d0a81..5c4b2d447 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -486,6 +486,8 @@ namespace MWGui float mFPS; std::map mFallbackMap; + + bool mShowOwned; /** * Called when MyGUI tries to retrieve a tag's value. Tags must be denoted in #{tag} notation and will be replaced upon setting a user visible text/property. From 41bed4c7d9c2a1dc4a7f3e4444433a0d50df4a16 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 17 Jul 2015 20:49:10 +0200 Subject: [PATCH 1856/3725] Use multimap to speed up custom map marker code --- apps/openmw/mwgui/mapwindow.cpp | 120 ++++++++++++++----------- apps/openmw/mwgui/mapwindow.hpp | 12 ++- apps/openmw/mwgui/windowmanagerimp.cpp | 4 +- components/esm/cellid.cpp | 23 +++++ components/esm/cellid.hpp | 1 + 5 files changed, 101 insertions(+), 59 deletions(-) diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 442fbeb08..7778569d2 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -92,31 +92,41 @@ namespace MWGui void CustomMarkerCollection::addMarker(const ESM::CustomMarker &marker, bool triggerEvent) { - mMarkers.push_back(marker); + mMarkers.insert(std::make_pair(marker.mCell, marker)); if (triggerEvent) eventMarkersChanged(); } void CustomMarkerCollection::deleteMarker(const ESM::CustomMarker &marker) { - std::vector::iterator it = std::find(mMarkers.begin(), mMarkers.end(), marker); - if (it != mMarkers.end()) - mMarkers.erase(it); - else - throw std::runtime_error("can't find marker to delete"); + std::pair range = mMarkers.equal_range(marker.mCell); - eventMarkersChanged(); + for (ContainerType::iterator it = range.first; it != range.second; ++it) + { + if (it->second == marker) + { + mMarkers.erase(it); + eventMarkersChanged(); + return; + } + } + throw std::runtime_error("can't find marker to delete"); } void CustomMarkerCollection::updateMarker(const ESM::CustomMarker &marker, const std::string &newNote) { - std::vector::iterator it = std::find(mMarkers.begin(), mMarkers.end(), marker); - if (it != mMarkers.end()) - it->mNote = newNote; - else - throw std::runtime_error("can't find marker to update"); + std::pair range = mMarkers.equal_range(marker.mCell); - eventMarkersChanged(); + for (ContainerType::iterator it = range.first; it != range.second; ++it) + { + if (it->second == marker) + { + it->second.mNote = newNote; + eventMarkersChanged(); + return; + } + } + throw std::runtime_error("can't find marker to update"); } void CustomMarkerCollection::clear() @@ -125,16 +135,21 @@ namespace MWGui eventMarkersChanged(); } - std::vector::const_iterator CustomMarkerCollection::begin() const + CustomMarkerCollection::ContainerType::const_iterator CustomMarkerCollection::begin() const { return mMarkers.begin(); } - std::vector::const_iterator CustomMarkerCollection::end() const + CustomMarkerCollection::ContainerType::const_iterator CustomMarkerCollection::end() const { return mMarkers.end(); } + CustomMarkerCollection::RangeType CustomMarkerCollection::getMarkers(const ESM::CellId &cellId) const + { + return mMarkers.equal_range(cellId); + } + size_t CustomMarkerCollection::size() const { return mMarkers.size(); @@ -299,44 +314,43 @@ namespace MWGui MyGUI::Gui::getInstance().destroyWidget(*it); mCustomMarkerWidgets.clear(); - for (std::vector::const_iterator it = mCustomMarkers.begin(); it != mCustomMarkers.end(); ++it) + for (int dX = -1; dX <= 1; ++dX) { - const ESM::CustomMarker& marker = *it; - - if (marker.mCell.mPaged != !mInterior) - continue; - if (mInterior) - { - if (marker.mCell.mWorldspace != mPrefix) - continue; - } - else + for (int dY =-1; dY <= 1; ++dY) { - if (std::abs(marker.mCell.mIndex.mX - mCurX) > 1) - continue; - if (std::abs(marker.mCell.mIndex.mY - mCurY) > 1) - continue; + ESM::CellId cellId; + cellId.mPaged = !mInterior; + cellId.mWorldspace = (mInterior ? mPrefix : "sys::default"); + cellId.mIndex.mX = mCurX+dX; + cellId.mIndex.mY = mCurY+dY; + + CustomMarkerCollection::RangeType markers = mCustomMarkers.getMarkers(cellId); + for (CustomMarkerCollection::ContainerType::const_iterator it = markers.first; it != markers.second; ++it) + { + const ESM::CustomMarker& marker = it->second; + + MarkerUserData markerPos (mLocalMapRender); + MyGUI::IntPoint widgetPos = getMarkerPosition(marker.mWorldX, marker.mWorldY, markerPos); + + MyGUI::IntCoord widgetCoord(widgetPos.left - 8, + widgetPos.top - 8, + 16, 16); + MarkerWidget* markerWidget = mLocalMap->createWidget("CustomMarkerButton", + widgetCoord, MyGUI::Align::Default); + markerWidget->setDepth(Local_MarkerAboveFogLayer); + markerWidget->setUserString("ToolTipType", "Layout"); + markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine"); + markerWidget->setUserString("Caption_TextOneLine", MyGUI::TextIterator::toTagsString(marker.mNote)); + markerWidget->setNormalColour(MyGUI::Colour(0.6f, 0.6f, 0.6f)); + markerWidget->setHoverColour(MyGUI::Colour(1.0f, 1.0f, 1.0f)); + markerWidget->setUserData(marker); + markerWidget->setNeedMouseFocus(true); + customMarkerCreated(markerWidget); + mCustomMarkerWidgets.push_back(markerWidget); + } } - - MarkerUserData markerPos (mLocalMapRender); - MyGUI::IntPoint widgetPos = getMarkerPosition(marker.mWorldX, marker.mWorldY, markerPos); - - MyGUI::IntCoord widgetCoord(widgetPos.left - 8, - widgetPos.top - 8, - 16, 16); - MarkerWidget* markerWidget = mLocalMap->createWidget("CustomMarkerButton", - widgetCoord, MyGUI::Align::Default); - markerWidget->setDepth(Local_MarkerAboveFogLayer); - markerWidget->setUserString("ToolTipType", "Layout"); - markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine"); - markerWidget->setUserString("Caption_TextOneLine", MyGUI::TextIterator::toTagsString(marker.mNote)); - markerWidget->setNormalColour(MyGUI::Colour(0.6f, 0.6f, 0.6f)); - markerWidget->setHoverColour(MyGUI::Colour(1.0f, 1.0f, 1.0f)); - markerWidget->setUserData(marker); - markerWidget->setNeedMouseFocus(true); - customMarkerCreated(markerWidget); - mCustomMarkerWidgets.push_back(markerWidget); } + redraw(); } @@ -411,11 +425,9 @@ namespace MWGui MWBase::World::DoorMarker marker = *it; std::vector destNotes; - for (std::vector::const_iterator it = mCustomMarkers.begin(); it != mCustomMarkers.end(); ++it) - { - if (it->mCell == marker.dest) - destNotes.push_back(it->mNote); - } + CustomMarkerCollection::RangeType markers = mCustomMarkers.getMarkers(marker.dest); + for (CustomMarkerCollection::ContainerType::const_iterator it = markers.first; it != markers.second; ++it) + destNotes.push_back(it->second.mNote); MarkerUserData data (mLocalMapRender); data.notes = destNotes; diff --git a/apps/openmw/mwgui/mapwindow.hpp b/apps/openmw/mwgui/mapwindow.hpp index 388103b5d..ec4298786 100644 --- a/apps/openmw/mwgui/mapwindow.hpp +++ b/apps/openmw/mwgui/mapwindow.hpp @@ -42,14 +42,20 @@ namespace MWGui size_t size() const; - std::vector::const_iterator begin() const; - std::vector::const_iterator end() const; + typedef std::multimap ContainerType; + + typedef std::pair RangeType; + + ContainerType::const_iterator begin() const; + ContainerType::const_iterator end() const; + + RangeType getMarkers(const ESM::CellId& cellId) const; typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void; EventHandle_Void eventMarkersChanged; private: - std::vector mMarkers; + ContainerType mMarkers; }; class LocalMapBase diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 582519b19..4dbef8a74 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1672,10 +1672,10 @@ namespace MWGui writer.endRecord(ESM::REC_ASPL); } - for (std::vector::const_iterator it = mCustomMarkers.begin(); it != mCustomMarkers.end(); ++it) + for (CustomMarkerCollection::ContainerType::const_iterator it = mCustomMarkers.begin(); it != mCustomMarkers.end(); ++it) { writer.startRecord(ESM::REC_MARK); - (*it).save(writer); + it->second.save(writer); writer.endRecord(ESM::REC_MARK); } } diff --git a/components/esm/cellid.cpp b/components/esm/cellid.cpp index 3c6e23ffd..c77b27b22 100644 --- a/components/esm/cellid.cpp +++ b/components/esm/cellid.cpp @@ -35,3 +35,26 @@ bool ESM::operator!= (const CellId& left, const CellId& right) { return !(left==right); } + +bool ESM::operator < (const CellId& left, const CellId& right) +{ + if (left.mPaged < right.mPaged) + return true; + if (left.mPaged > right.mPaged) + return false; + + if (left.mPaged) + { + if (left.mIndex.mX < right.mIndex.mX) + return true; + if (left.mIndex.mX > right.mIndex.mX) + return false; + + if (left.mIndex.mY < right.mIndex.mY) + return true; + if (left.mIndex.mY > right.mIndex.mY) + return false; + } + + return left.mWorldspace < right.mWorldspace; +} diff --git a/components/esm/cellid.hpp b/components/esm/cellid.hpp index 44a1b387a..56d5a674e 100644 --- a/components/esm/cellid.hpp +++ b/components/esm/cellid.hpp @@ -26,6 +26,7 @@ namespace ESM bool operator== (const CellId& left, const CellId& right); bool operator!= (const CellId& left, const CellId& right); + bool operator< (const CellId& left, const CellId& right); } #endif From 1b3cc957f836195cac56b0f7275ee0a646712c72 Mon Sep 17 00:00:00 2001 From: slothlife Date: Fri, 17 Jul 2015 15:13:43 -0500 Subject: [PATCH 1857/3725] Move some OSG static library setup code --- components/resource/texturemanager.cpp | 8 ++++++++ components/sdlutil/sdlcursormanager.cpp | 6 ------ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/components/resource/texturemanager.cpp b/components/resource/texturemanager.cpp index 62cbd6bb3..5da0a008a 100644 --- a/components/resource/texturemanager.cpp +++ b/components/resource/texturemanager.cpp @@ -6,6 +6,14 @@ #include +#ifdef OSG_LIBRARY_STATIC +// This list of plugins should match with the list in the top-level CMakelists.txt. +USE_OSGPLUGIN(png) +USE_OSGPLUGIN(tga) +USE_OSGPLUGIN(dds) +USE_OSGPLUGIN(jpeg) +#endif + namespace { diff --git a/components/sdlutil/sdlcursormanager.cpp b/components/sdlutil/sdlcursormanager.cpp index 508d72589..2004e806c 100644 --- a/components/sdlutil/sdlcursormanager.cpp +++ b/components/sdlutil/sdlcursormanager.cpp @@ -16,12 +16,6 @@ #include "imagetosurface.hpp" #ifdef OSG_LIBRARY_STATIC -// This list of plugins should match with the list in the top-level CMakelists.txt. -USE_OSGPLUGIN(png) -USE_OSGPLUGIN(tga) -USE_OSGPLUGIN(dds) -USE_OSGPLUGIN(jpeg) - // Sets the default windowing system interface according to the OS. // Necessary for OpenSceneGraph to do some things, like decompression. USE_GRAPHICSWINDOW() From 420789baa9f8418c146f0532d84171d697ec2f61 Mon Sep 17 00:00:00 2001 From: slothlife Date: Fri, 17 Jul 2015 15:26:04 -0500 Subject: [PATCH 1858/3725] Remove an unused include --- components/sdlutil/sdlcursormanager.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/components/sdlutil/sdlcursormanager.cpp b/components/sdlutil/sdlcursormanager.cpp index 2004e806c..89928d165 100644 --- a/components/sdlutil/sdlcursormanager.cpp +++ b/components/sdlutil/sdlcursormanager.cpp @@ -10,7 +10,6 @@ #include #include #include -#include #include #include "imagetosurface.hpp" From 6e493500c9099a646598ae92984cd66f54aa6ca7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 18 Jul 2015 00:14:11 +0200 Subject: [PATCH 1859/3725] Show custom map markers on the tooltip of the world map marker (Fixes #2711) --- apps/openmw/mwgui/mapwindow.cpp | 57 +++++++++++++++++++++++++++++---- apps/openmw/mwgui/mapwindow.hpp | 7 ++-- 2 files changed, 56 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 7778569d2..2485f3c94 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -783,15 +783,19 @@ namespace MWGui MyGUI::Widget* markerWidget = mGlobalMap->createWidget("MarkerButton", widgetCoord, MyGUI::Align::Default); + + markerWidget->setUserString("Caption_TextOneLine", name); + + setGlobalMapMarkerTooltip(markerWidget, x, y); + + markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine"); + markerWidget->setNeedMouseFocus(true); markerWidget->setColour(MyGUI::Colour::parse(MyGUI::LanguageManager::getInstance().replaceTags("#{fontcolour=normal}"))); - markerWidget->setUserString("ToolTipType", "Layout"); - markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine"); - markerWidget->setUserString("Caption_TextOneLine", name); markerWidget->setDepth(Global_MarkerLayer); markerWidget->eventMouseDrag += MyGUI::newDelegate(this, &MapWindow::onMouseDrag); markerWidget->eventMouseButtonPressed += MyGUI::newDelegate(this, &MapWindow::onDragStart); - mGlobalMapMarkers.push_back(markerWidget); + mGlobalMapMarkers[std::make_pair(x,y)] = markerWidget; } } @@ -816,6 +820,45 @@ namespace MWGui NoDrop::onFrame(dt); } + void MapWindow::setGlobalMapMarkerTooltip(MyGUI::Widget* markerWidget, int x, int y) + { + ESM::CellId cellId; + cellId.mIndex.mX = x; + cellId.mIndex.mY = y; + cellId.mWorldspace = "sys::default"; + cellId.mPaged = true; + CustomMarkerCollection::RangeType markers = mCustomMarkers.getMarkers(cellId); + std::vector destNotes; + for (CustomMarkerCollection::ContainerType::const_iterator it = markers.first; it != markers.second; ++it) + destNotes.push_back(it->second.mNote); + + if (!destNotes.empty()) + { + MarkerUserData data (NULL); + data.notes = destNotes; + data.caption = markerWidget->getUserString("Caption_TextOneLine"); + markerWidget->setUserData(data); + markerWidget->setUserString("ToolTipType", "MapMarker"); + } + else + { + markerWidget->setUserString("ToolTipType", "Layout"); + } + } + + void MapWindow::updateCustomMarkers() + { + LocalMapBase::updateCustomMarkers(); + + for (std::map, MyGUI::Widget*>::iterator widgetIt = mGlobalMapMarkers.begin(); widgetIt != mGlobalMapMarkers.end(); ++widgetIt) + { + int x = widgetIt->first.first; + int y = widgetIt->first.second; + MyGUI::Widget* markerWidget = widgetIt->second; + setGlobalMapMarkerTooltip(markerWidget, x, y); + } + } + void MapWindow::onDragStart(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id) { if (_id!=MyGUI::MouseButton::Left) return; @@ -913,8 +956,8 @@ namespace MWGui mGlobalMapRender->clear(); mChanged = true; - for (std::vector::iterator it = mGlobalMapMarkers.begin(); it != mGlobalMapMarkers.end(); ++it) - MyGUI::Gui::getInstance().destroyWidget(*it); + for (std::map, MyGUI::Widget*>::iterator it = mGlobalMapMarkers.begin(); it != mGlobalMapMarkers.end(); ++it) + MyGUI::Gui::getInstance().destroyWidget(it->second); mGlobalMapMarkers.clear(); } @@ -1034,6 +1077,8 @@ namespace MWGui bool LocalMapBase::MarkerUserData::isPositionExplored() const { + if (!mLocalMapRender) + return true; return mLocalMapRender->isPositionExplored(nX, nY, cellX, cellY, interior); } diff --git a/apps/openmw/mwgui/mapwindow.hpp b/apps/openmw/mwgui/mapwindow.hpp index ec4298786..a5594bee8 100644 --- a/apps/openmw/mwgui/mapwindow.hpp +++ b/apps/openmw/mwgui/mapwindow.hpp @@ -126,7 +126,7 @@ namespace MWGui std::vector mMagicMarkerWidgets; std::vector mCustomMarkerWidgets; - void updateCustomMarkers(); + virtual void updateCustomMarkers(); void applyFogOfWar(); @@ -203,6 +203,8 @@ namespace MWGui void onFrame(float dt); + virtual void updateCustomMarkers(); + /// Clear all savegame-specific data void clear(); @@ -221,6 +223,7 @@ namespace MWGui void onNoteDoubleClicked(MyGUI::Widget* sender); void onChangeScrollWindowCoord(MyGUI::Widget* sender); void globalMapUpdatePlayer(); + void setGlobalMapMarkerTooltip(MyGUI::Widget* widget, int x, int y); MyGUI::ScrollView* mGlobalMap; std::auto_ptr mGlobalMapTexture; @@ -248,7 +251,7 @@ namespace MWGui MWRender::GlobalMap* mGlobalMapRender; - std::vector mGlobalMapMarkers; + std::map, MyGUI::Widget*> mGlobalMapMarkers; EditNoteDialog mEditNoteDialog; ESM::CustomMarker mEditingMarker; From c783b50a8399411f705cad3c4fc91a0e60f13144 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 18 Jul 2015 01:38:35 +0200 Subject: [PATCH 1860/3725] Fix config file priority in the launcher to match OpenMW --- apps/launcher/maindialog.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index 4b7c0504f..99c40b88b 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -309,11 +309,11 @@ bool Launcher::MainDialog::setupGameSettings() mGameSettings.readUserFile(stream); } - // Now the rest + // Now the rest - priority: user > local > global QStringList paths; - paths.append(userPath + QString("openmw.cfg")); - paths.append(QString("openmw.cfg")); paths.append(globalPath + QString("openmw.cfg")); + paths.append(QString("openmw.cfg")); + paths.append(userPath + QString("openmw.cfg")); foreach (const QString &path, paths) { qDebug() << "Loading config file:" << qPrintable(path); From f09e4620b6a730f0f2bbf660e18dd65d13a94d9f Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 18 Jul 2015 03:01:06 +0200 Subject: [PATCH 1861/3725] Move OpenMW version information to a textfile instead of compiling it in Now we don't need to recompile 3 .cpp files and re-link whenever the current git HEAD changes. --- .gitignore | 1 - CMakeLists.txt | 2 ++ apps/launcher/maindialog.cpp | 47 +++++++++++++++----------- apps/launcher/maindialog.hpp | 2 ++ apps/openmw/engine.cpp | 5 +-- apps/openmw/main.cpp | 14 +++----- apps/openmw/mwgui/mainmenu.cpp | 19 ++--------- apps/openmw/mwgui/mainmenu.hpp | 2 +- apps/openmw/mwgui/windowmanagerimp.cpp | 5 +-- apps/openmw/mwgui/windowmanagerimp.hpp | 4 ++- cmake/GitVersion.cmake | 2 +- components/CMakeLists.txt | 26 +++++++------- components/version/version.cpp | 41 ++++++++++++++++++++++ components/version/version.hpp | 28 +++++++++++++++ components/version/version.hpp.cmake | 13 ------- files/version.in | 3 ++ 16 files changed, 134 insertions(+), 80 deletions(-) create mode 100644 components/version/version.cpp create mode 100644 components/version/version.hpp delete mode 100644 components/version/version.hpp.cmake create mode 100644 files/version.in diff --git a/.gitignore b/.gitignore index 944fb8418..88f591aae 100644 --- a/.gitignore +++ b/.gitignore @@ -41,7 +41,6 @@ resources ## generated objects apps/openmw/config.hpp -components/version/version.hpp docs/mainpage.hpp moc_*.cxx *.cxx_parameters diff --git a/CMakeLists.txt b/CMakeLists.txt index a133a8d6a..37680c13e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -366,6 +366,7 @@ IF(NOT WIN32 AND NOT APPLE) # Install global configuration files INSTALL(FILES "${OpenMW_BINARY_DIR}/settings-default.cfg" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw") INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" DESTINATION "${SYSCONFDIR}" RENAME "openmw.cfg" COMPONENT "openmw") + INSTALL(FILES "${OpenMW_BINARY_DIR}/resources/version" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw") INSTALL(FILES "${OpenMW_BINARY_DIR}/gamecontrollerdb.txt" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw") IF(BUILD_OPENCS) @@ -381,6 +382,7 @@ if(WIN32) FILE(GLOB dll_files "${OpenMW_BINARY_DIR}/Release/*.dll") INSTALL(FILES ${dll_files} DESTINATION ".") INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" DESTINATION "." RENAME "openmw.cfg") + INSTALL(FILES "${OpenMW_BINARY_DIR}/resources/version" DESTINATION ".") INSTALL(FILES "${OpenMW_SOURCE_DIR}/CHANGELOG.md" DESTINATION "." RENAME "CHANGELOG.txt") INSTALL(FILES "${OpenMW_SOURCE_DIR}/README.md" DESTINATION "." RENAME "README.txt") INSTALL(FILES diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index 99c40b88b..c18c26cdd 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -57,26 +57,6 @@ Launcher::MainDialog::MainDialog(QWidget *parent) // Remove what's this? button setWindowFlags(this->windowFlags() & ~Qt::WindowContextHelpButtonHint); - // Add version information to bottom of the window - QString revision(OPENMW_VERSION_COMMITHASH); - QString tag(OPENMW_VERSION_TAGHASH); - - versionLabel->setTextInteractionFlags(Qt::TextSelectableByMouse); - if (!revision.isEmpty() && !tag.isEmpty()) - { - if (revision == tag) { - versionLabel->setText(tr("OpenMW %1 release").arg(OPENMW_VERSION)); - } else { - versionLabel->setText(tr("OpenMW development (%1)").arg(revision.left(10))); - } - - // Add the compile date and time - versionLabel->setToolTip(tr("Compiled on %1 %2").arg(QLocale(QLocale::C).toDate(QString(__DATE__).simplified(), - QLatin1String("MMM d yyyy")).toString(Qt::SystemLocaleLongDate), - QLocale(QLocale::C).toTime(QString(__TIME__).simplified(), - QLatin1String("hh:mm:ss")).toString(Qt::SystemLocaleShortDate))); - } - createIcons(); } @@ -186,11 +166,38 @@ Launcher::FirstRunDialogResult Launcher::MainDialog::showFirstRunDialog() return setup() ? FirstRunDialogResultContinue : FirstRunDialogResultFailure; } +void Launcher::MainDialog::setVersionLabel() +{ + // Add version information to bottom of the window + Version::Version v = Version::getOpenmwVersion(mGameSettings.value("resources").toUtf8().constData()); + + QString revision(QString::fromUtf8(v.mCommitHash.c_str())); + QString tag(QString::fromUtf8(v.mTagHash.c_str())); + + versionLabel->setTextInteractionFlags(Qt::TextSelectableByMouse); + if (!revision.isEmpty() && !tag.isEmpty()) + { + if (revision == tag) { + versionLabel->setText(tr("OpenMW %1 release").arg(QString::fromUtf8(v.mVersion.c_str()))); + } else { + versionLabel->setText(tr("OpenMW development (%1)").arg(revision.left(10))); + } + + // Add the compile date and time + versionLabel->setToolTip(tr("Compiled on %1 %2").arg(QLocale(QLocale::C).toDate(QString(__DATE__).simplified(), + QLatin1String("MMM d yyyy")).toString(Qt::SystemLocaleLongDate), + QLocale(QLocale::C).toTime(QString(__TIME__).simplified(), + QLatin1String("hh:mm:ss")).toString(Qt::SystemLocaleShortDate))); + } +} + bool Launcher::MainDialog::setup() { if (!setupGameSettings()) return false; + setVersionLabel(); + mLauncherSettings.setContentList(mGameSettings); if (!setupGraphicsSettings()) diff --git a/apps/launcher/maindialog.hpp b/apps/launcher/maindialog.hpp index c90309990..298682d20 100644 --- a/apps/launcher/maindialog.hpp +++ b/apps/launcher/maindialog.hpp @@ -72,6 +72,8 @@ namespace Launcher bool setupGameSettings(); bool setupGraphicsSettings(); + void setVersionLabel(); + void loadSettings(); void saveSettings(); diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index dc2cb8f37..fb879d273 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -27,7 +27,7 @@ #include #include -#include +#include #include "mwinput/inputmanagerimp.hpp" @@ -493,7 +493,8 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) rootNode->addChild(guiRoot); MWGui::WindowManager* window = new MWGui::WindowManager(mViewer, guiRoot, mResourceSystem.get(), mCfgMgr.getLogPath().string() + std::string("/"), myguiResources, - mScriptConsoleMode, mTranslationDataStorage, mEncoding, mExportFonts, mFallbackMap); + mScriptConsoleMode, mTranslationDataStorage, mEncoding, mExportFonts, mFallbackMap, + Version::getOpenmwVersionDescription(mResDir.string())); mEnvironment.setWindowManager (window); // Create sound system diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 85a0dbe55..3d631c743 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -199,18 +199,14 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat return false; } - std::cout << "OpenMW version " << OPENMW_VERSION; - std::string rev = OPENMW_VERSION_COMMITHASH; - std::string tag = OPENMW_VERSION_TAGHASH; - if (!rev.empty() && !tag.empty()) + if (variables.count ("version")) { - rev = rev.substr(0, 10); - std::cout << " (revision " << rev << ")"; - } - std::cout << std::endl; + cfgMgr.readConfiguration(variables, desc, true); - if (variables.count ("version")) + Version::Version v = Version::getOpenmwVersion(variables["resources"].as()); + std::cout << v.describe() << std::endl; return false; + } cfgMgr.readConfiguration(variables, desc); diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index e24894e89..409306986 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -4,8 +4,6 @@ #include #include -#include - #include #include #include @@ -28,7 +26,7 @@ namespace MWGui { - MainMenu::MainMenu(int w, int h, const VFS::Manager* vfs) + MainMenu::MainMenu(int w, int h, const VFS::Manager* vfs, const std::string& versionDescription) : Layout("openmw_mainmenu.layout") , mWidth (w), mHeight (h) , mVFS(vfs), mButtonBox(0) @@ -38,20 +36,7 @@ namespace MWGui , mSaveGameDialog(NULL) { getWidget(mVersionText, "VersionText"); - std::stringstream sstream; - sstream << "OpenMW Version: " << OPENMW_VERSION; - - // adding info about git hash if available - std::string rev = OPENMW_VERSION_COMMITHASH; - std::string tag = OPENMW_VERSION_TAGHASH; - if (!rev.empty() && !tag.empty()) - { - rev = rev.substr(0,10); - sstream << "\nRevision: " << rev; - } - - std::string output = sstream.str(); - mVersionText->setCaption(output); + mVersionText->setCaption(versionDescription); mHasAnimatedMenu = mVFS->exists("video/menu_background.bik"); diff --git a/apps/openmw/mwgui/mainmenu.hpp b/apps/openmw/mwgui/mainmenu.hpp index d01f67fbd..fe256dc8e 100644 --- a/apps/openmw/mwgui/mainmenu.hpp +++ b/apps/openmw/mwgui/mainmenu.hpp @@ -29,7 +29,7 @@ namespace MWGui public: - MainMenu(int w, int h, const VFS::Manager* vfs); + MainMenu(int w, int h, const VFS::Manager* vfs, const std::string& versionDescription); ~MainMenu(); void onResChange(int w, int h); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index a2a826161..a739ea6e7 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -113,7 +113,7 @@ namespace MWGui WindowManager::WindowManager( osgViewer::Viewer* viewer, osg::Group* guiRoot, Resource::ResourceSystem* resourceSystem , const std::string& logpath, const std::string& resourcePath, bool consoleOnlyScripts, - Translation::Storage& translationDataStorage, ToUTF8::FromType encoding, bool exportFonts, const std::map& fallbackMap) + Translation::Storage& translationDataStorage, ToUTF8::FromType encoding, bool exportFonts, const std::map& fallbackMap, const std::string& versionDescription) : mResourceSystem(resourceSystem) , mViewer(viewer) , mConsoleOnlyScripts(consoleOnlyScripts) @@ -187,6 +187,7 @@ namespace MWGui , mRestAllowed(true) , mFPS(0.0f) , mFallbackMap(fallbackMap) + , mVersionDescription(versionDescription) { float uiScale = Settings::Manager::getFloat("scaling factor", "GUI"); mGuiPlatform = new osgMyGUI::Platform(viewer, guiRoot, resourceSystem->getTextureManager(), uiScale); @@ -272,7 +273,7 @@ namespace MWGui mDragAndDrop = new DragAndDrop(); mRecharge = new Recharge(); - mMenu = new MainMenu(w, h, mResourceSystem->getVFS()); + mMenu = new MainMenu(w, h, mResourceSystem->getVFS(), mVersionDescription); mLocalMapRender = new MWRender::LocalMap(mViewer); mMap = new MapWindow(mCustomMarkers, mDragAndDrop, mLocalMapRender); trackWindow(mMap, "map"); diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index e6c8d0a81..38af1a79e 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -116,7 +116,7 @@ namespace MWGui WindowManager(osgViewer::Viewer* viewer, osg::Group* guiRoot, Resource::ResourceSystem* resourceSystem, const std::string& logpath, const std::string& cacheDir, bool consoleOnlyScripts, - Translation::Storage& translationDataStorage, ToUTF8::FromType encoding, bool exportFonts, const std::map& fallbackMap); + Translation::Storage& translationDataStorage, ToUTF8::FromType encoding, bool exportFonts, const std::map& fallbackMap, const std::string& versionDescription); virtual ~WindowManager(); void initUI(); @@ -487,6 +487,8 @@ namespace MWGui std::map mFallbackMap; + std::string mVersionDescription; + /** * Called when MyGUI tries to retrieve a tag's value. Tags must be denoted in #{tag} notation and will be replaced upon setting a user visible text/property. * Supported syntax: diff --git a/cmake/GitVersion.cmake b/cmake/GitVersion.cmake index 0087461a1..0679e406c 100644 --- a/cmake/GitVersion.cmake +++ b/cmake/GitVersion.cmake @@ -21,4 +21,4 @@ else (SUCCESS) message(WARNING "Failed to get valid version information from Git") endif (SUCCESS) -configure_file(${VERSION_HPP_IN} ${VERSION_HPP}) +configure_file(${VERSION_IN_FILE} ${VERSION_FILE}) diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index d91bb5c30..85e61cee5 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -1,23 +1,23 @@ project (Components) # Version file -set (VERSION_HPP_IN ${CMAKE_CURRENT_SOURCE_DIR}/version/version.hpp.cmake) -set (VERSION_HPP ${CMAKE_CURRENT_SOURCE_DIR}/version/version.hpp) +set (VERSION_IN_FILE "${OpenMW_SOURCE_DIR}/files/version.in") +set (VERSION_FILE "${OpenMW_BINARY_DIR}/resources/version") if (GIT_CHECKOUT) - add_custom_target (git-version - COMMAND ${CMAKE_COMMAND} - -DGIT_EXECUTABLE=${GIT_EXECUTABLE} + add_custom_target (git-version + COMMAND ${CMAKE_COMMAND} + -DGIT_EXECUTABLE=${GIT_EXECUTABLE} -DPROJECT_SOURCE_DIR=${PROJECT_SOURCE_DIR} - -DVERSION_HPP_IN=${VERSION_HPP_IN} - -DVERSION_HPP=${VERSION_HPP} - -DOPENMW_VERSION_MAJOR=${OPENMW_VERSION_MAJOR} - -DOPENMW_VERSION_MINOR=${OPENMW_VERSION_MINOR} - -DOPENMW_VERSION_RELEASE=${OPENMW_VERSION_RELEASE} - -DOPENMW_VERSION=${OPENMW_VERSION} + -DVERSION_IN_FILE=${VERSION_IN_FILE} + -DVERSION_FILE=${VERSION_FILE} + -DOPENMW_VERSION_MAJOR=${OPENMW_VERSION_MAJOR} + -DOPENMW_VERSION_MINOR=${OPENMW_VERSION_MINOR} + -DOPENMW_VERSION_RELEASE=${OPENMW_VERSION_RELEASE} + -DOPENMW_VERSION=${OPENMW_VERSION} -P ${CMAKE_CURRENT_SOURCE_DIR}/../cmake/GitVersion.cmake - VERBATIM) + VERBATIM) else (GIT_CHECKOUT) - configure_file(${VERSION_HPP_IN} ${VERSION_HPP}) + configure_file(${VERSION_IN_FILE} ${VERSION_FILE}) endif (GIT_CHECKOUT) find_package(OpenGL REQUIRED) diff --git a/components/version/version.cpp b/components/version/version.cpp new file mode 100644 index 000000000..c87943f9e --- /dev/null +++ b/components/version/version.cpp @@ -0,0 +1,41 @@ +#include "version.hpp" + +#include +#include + +namespace Version +{ + +Version getOpenmwVersion(const std::string &resourcePath) +{ + boost::filesystem::path path (resourcePath + "/version"); + + boost::filesystem::ifstream stream (path); + + Version v; + std::getline(stream, v.mVersion); + std::getline(stream, v.mCommitHash); + std::getline(stream, v.mTagHash); + return v; +} + +std::string Version::describe() +{ + std::string str = "OpenMW version " + mVersion; + std::string rev = mCommitHash; + std::string tag = mTagHash; + if (!rev.empty() && !tag.empty()) + { + rev = rev.substr(0, 10); + str += "\nRevision: " + rev; + } + return str; +} + +std::string getOpenmwVersionDescription(const std::string &resourcePath) +{ + Version v = getOpenmwVersion(resourcePath); + return v.describe(); +} + +} diff --git a/components/version/version.hpp b/components/version/version.hpp new file mode 100644 index 000000000..7371e786e --- /dev/null +++ b/components/version/version.hpp @@ -0,0 +1,28 @@ +#ifndef VERSION_HPP +#define VERSION_HPP + +#include + +namespace Version +{ + + struct Version + { + std::string mVersion; + std::string mCommitHash; + std::string mTagHash; + + std::string describe(); + }; + + /// Read OpenMW version from the version file located in resourcePath. + Version getOpenmwVersion(const std::string& resourcePath); + + /// Helper function to getOpenmwVersion and describe() it + std::string getOpenmwVersionDescription(const std::string& resourcePath); + +} + + +#endif // VERSION_HPP + diff --git a/components/version/version.hpp.cmake b/components/version/version.hpp.cmake deleted file mode 100644 index 4cdfa32f0..000000000 --- a/components/version/version.hpp.cmake +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef VERSION_HPP -#define VERSION_HPP - -#define OPENMW_VERSION_MAJOR @OPENMW_VERSION_MAJOR@ -#define OPENMW_VERSION_MINOR @OPENMW_VERSION_MINOR@ -#define OPENMW_VERSION_RELEASE @OPENMW_VERSION_RELEASE@ -#define OPENMW_VERSION "@OPENMW_VERSION@" - -#define OPENMW_VERSION_COMMITHASH "@OPENMW_VERSION_COMMITHASH@" -#define OPENMW_VERSION_TAGHASH "@OPENMW_VERSION_TAGHASH@" - -#endif // VERSION_HPP - diff --git a/files/version.in b/files/version.in new file mode 100644 index 000000000..f894d3b4a --- /dev/null +++ b/files/version.in @@ -0,0 +1,3 @@ +@OPENMW_VERSION@ +@OPENMW_VERSION_COMMITHASH@ +@OPENMW_VERSION_TAGHASH@ From a33ca75742cc0be779041f236fcba2a3ef9f7320 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 18 Jul 2015 03:23:41 +0200 Subject: [PATCH 1862/3725] Pass AnimPriority by const reference --- apps/openmw/mwrender/animation.cpp | 2 +- apps/openmw/mwrender/animation.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index dab289f6c..ee0ce6df1 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -461,7 +461,7 @@ namespace MWRender mTextKeyListener->handleTextKey(groupname, key, map); } - void Animation::play(const std::string &groupname, AnimPriority priority, int blendMask, bool autodisable, float speedmult, + void Animation::play(const std::string &groupname, const AnimPriority& priority, int blendMask, bool autodisable, float speedmult, const std::string &start, const std::string &stop, float startpoint, size_t loops, bool loopfallback) { if(!mObjectRoot || mAnimSources.empty()) diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 1cf2ce9ba..23f807238 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -353,7 +353,7 @@ public: * \param loopFallback Allow looping an animation that has no loop keys, i.e. fall back to use * the "start" and "stop" keys for looping? */ - void play(const std::string &groupname, AnimPriority priority, int blendMask, bool autodisable, + void play(const std::string &groupname, const AnimPriority& priority, int blendMask, bool autodisable, float speedmult, const std::string &start, const std::string &stop, float startpoint, size_t loops, bool loopfallback=false); From 58720e6a28400a935733a3999229bceeb39c7a5b Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 18 Jul 2015 03:52:38 +0200 Subject: [PATCH 1863/3725] Fix the OpenCS rendering crash on exit (Fixes #2735) --- apps/opencs/model/world/data.cpp | 10 +++++----- apps/opencs/model/world/data.hpp | 6 +++--- apps/opencs/view/render/cell.cpp | 2 +- apps/opencs/view/render/object.cpp | 2 +- apps/opencs/view/render/previewwidget.cpp | 2 +- apps/opencs/view/render/scenewidget.cpp | 7 ++++--- apps/opencs/view/render/scenewidget.hpp | 8 +++++--- apps/opencs/view/render/worldspacewidget.cpp | 2 +- 8 files changed, 21 insertions(+), 18 deletions(-) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index a92a7ad79..3714117b6 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -62,7 +62,7 @@ int CSMWorld::Data::count (RecordBase::State state, const CollectionBase& collec CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourcesManager) : mEncoder (encoding), mPathgrids (mCells), mRefs (mCells), - mResourcesManager (resourcesManager), mReader (0), mDialogue (0), mReaderIndex(0), mResourceSystem(resourcesManager.getVFS()) + mResourcesManager (resourcesManager), mReader (0), mDialogue (0), mReaderIndex(0), mResourceSystem(new Resource::ResourceSystem(resourcesManager.getVFS())) { int index = 0; @@ -537,14 +537,14 @@ CSMWorld::Data::~Data() delete mReader; } -Resource::ResourceSystem* CSMWorld::Data::getResourceSystem() +boost::shared_ptr CSMWorld::Data::getResourceSystem() { - return &mResourceSystem; + return mResourceSystem; } -const Resource::ResourceSystem* CSMWorld::Data::getResourceSystem() const +boost::shared_ptr CSMWorld::Data::getResourceSystem() const { - return &mResourceSystem; + return mResourceSystem; } const CSMWorld::IdCollection& CSMWorld::Data::getGlobals() const diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 6e651b374..06f76607f 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -113,7 +113,7 @@ namespace CSMWorld std::map > mRefLoadCache; int mReaderIndex; - Resource::ResourceSystem mResourceSystem; + boost::shared_ptr mResourceSystem; std::vector > mReaders; @@ -138,9 +138,9 @@ namespace CSMWorld const VFS::Manager* getVFS() const; - Resource::ResourceSystem* getResourceSystem(); + boost::shared_ptr getResourceSystem(); - const Resource::ResourceSystem* getResourceSystem() const; + boost::shared_ptr getResourceSystem() const; const IdCollection& getGlobals() const; diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index 063413248..fe2eab066 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -71,7 +71,7 @@ CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::st const ESM::Land* esmLand = land.getRecord(mId).get().mLand.get(); if(esmLand && esmLand->mDataTypes&ESM::Land::DATA_VHGT) { - mTerrain.reset(new Terrain::TerrainGrid(mCellNode, data.getResourceSystem(), NULL, new TerrainStorage(mData), Element_Terrain<<1)); + mTerrain.reset(new Terrain::TerrainGrid(mCellNode, data.getResourceSystem().get(), NULL, new TerrainStorage(mData), Element_Terrain<<1)); mTerrain->loadCell(esmLand->mX, esmLand->mY); diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index ea27b1432..973893a71 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -116,7 +116,7 @@ const CSMWorld::CellRef& CSVRender::Object::getReference() const CSVRender::Object::Object (CSMWorld::Data& data, osg::Group* parentNode, const std::string& id, bool referenceable, bool forceBaseToZero) -: mData (data), mBaseNode(0), mParentNode(parentNode), mResourceSystem(data.getResourceSystem()), mForceBaseToZero (forceBaseToZero) +: mData (data), mBaseNode(0), mParentNode(parentNode), mResourceSystem(data.getResourceSystem().get()), mForceBaseToZero (forceBaseToZero) { mBaseNode = new osg::PositionAttitudeTransform; parentNode->addChild(mBaseNode); diff --git a/apps/opencs/view/render/previewwidget.cpp b/apps/opencs/view/render/previewwidget.cpp index f0cbc939a..f512a8bb6 100644 --- a/apps/opencs/view/render/previewwidget.cpp +++ b/apps/opencs/view/render/previewwidget.cpp @@ -8,7 +8,7 @@ CSVRender::PreviewWidget::PreviewWidget (CSMWorld::Data& data, const std::string& id, bool referenceable, QWidget *parent) -: SceneWidget (data.getResourceSystem()->getSceneManager(), parent), mData (data), mObject(data, mRootNode, id, referenceable) +: SceneWidget (data.getResourceSystem(), parent), mData (data), mObject(data, mRootNode, id, referenceable) { mView->setCameraManipulator(new osgGA::TrackballManipulator); diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index 208a7a5b7..d91c075e1 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -13,6 +13,7 @@ #include #include +#include #include "../widget/scenetoolmode.hpp" #include "../../model/settings/usersettings.hpp" @@ -132,9 +133,9 @@ void CompositeViewer::update() // --------------------------------------------------- -SceneWidget::SceneWidget(Resource::SceneManager* sceneManager, QWidget *parent, Qt::WindowFlags f) +SceneWidget::SceneWidget(boost::shared_ptr resourceSystem, QWidget *parent, Qt::WindowFlags f) : RenderWidget(parent, f) - , mSceneManager(sceneManager) + , mResourceSystem(resourceSystem) , mLighting(NULL) , mHasDefaultAmbient(false) { @@ -147,7 +148,7 @@ SceneWidget::SceneWidget(Resource::SceneManager* sceneManager, QWidget *parent, SceneWidget::~SceneWidget() { // Since we're holding on to the scene templates past the existance of this graphics context, we'll need to manually release the created objects - mSceneManager->releaseGLObjects(mView->getCamera()->getGraphicsContext()->getState()); + mResourceSystem->getSceneManager()->releaseGLObjects(mView->getCamera()->getGraphicsContext()->getState()); } void SceneWidget::setLighting(Lighting *lighting) diff --git a/apps/opencs/view/render/scenewidget.hpp b/apps/opencs/view/render/scenewidget.hpp index c269f355d..f5c36b641 100644 --- a/apps/opencs/view/render/scenewidget.hpp +++ b/apps/opencs/view/render/scenewidget.hpp @@ -4,6 +4,8 @@ #include #include +#include + #include "lightingday.hpp" #include "lightingnight.hpp" #include "lightingbright.hpp" @@ -13,7 +15,7 @@ namespace Resource { - class SceneManager; + class ResourceSystem; } namespace osg @@ -57,7 +59,7 @@ namespace CSVRender { Q_OBJECT public: - SceneWidget(Resource::SceneManager* sceneManager, QWidget* parent = 0, Qt::WindowFlags f = 0); + SceneWidget(boost::shared_ptr resourceSystem, QWidget* parent = 0, Qt::WindowFlags f = 0); virtual ~SceneWidget(); CSVWidget::SceneToolMode *makeLightingSelector (CSVWidget::SceneToolbar *parent); @@ -73,7 +75,7 @@ namespace CSVRender void setAmbient(const osg::Vec4f& ambient); - Resource::SceneManager* mSceneManager; + boost::shared_ptr mResourceSystem; Lighting* mLighting; diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 3a70b7844..39ce09f31 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -24,7 +24,7 @@ #include "editmode.hpp" CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidget* parent) -: SceneWidget (document.getData().getResourceSystem()->getSceneManager(), parent), mSceneElements(0), mRun(0), mDocument(document), +: SceneWidget (document.getData().getResourceSystem(), parent), mSceneElements(0), mRun(0), mDocument(document), mInteractionMask (0) { setAcceptDrops(true); From f8f03804138ad6f5c7e0422fe89b251b998b7a62 Mon Sep 17 00:00:00 2001 From: slothlife Date: Fri, 17 Jul 2015 21:41:53 -0500 Subject: [PATCH 1864/3725] Fix for loading window icon on Windows --- apps/openmw/engine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index dc2cb8f37..bfb8c7113 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -414,7 +414,7 @@ void OMW::Engine::setWindowIcon() { boost::filesystem::ifstream windowIconStream; std::string windowIcon = (mResDir / "mygui" / "openmw.png").string(); - windowIconStream.open(windowIcon); + windowIconStream.open(windowIcon, std::ios_base::in | std::ios_base::binary); if (windowIconStream.fail()) std::cerr << "Failed to open " << windowIcon << std::endl; osgDB::ReaderWriter* reader = osgDB::Registry::instance()->getReaderWriterForExtension("png"); From 39ab9948f637d5d30cf5ac780a5de2756ab1b053 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 18 Jul 2015 11:40:18 +0200 Subject: [PATCH 1865/3725] updated credits file --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index ce76c104e..7774b5afa 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -59,6 +59,7 @@ Programmers Julien Voisin (jvoisin/ap0) Karl-Felix Glatzer (k1ll) Kevin Poitra (PuppyKevin) + kunesj Lars Söderberg (Lazaroth) lazydev Leon Saunders (emoose) From 73b6df8280dee4ad747c5f296401f63eab9f1efd Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 18 Jul 2015 13:09:17 +0200 Subject: [PATCH 1866/3725] put script compilation in script subview behind a timer --- apps/opencs/view/world/scriptsubview.cpp | 29 ++++++++++++++++++++++-- apps/opencs/view/world/scriptsubview.hpp | 6 +++++ 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/world/scriptsubview.cpp b/apps/opencs/view/world/scriptsubview.cpp index 7b5b1131e..dfdca8b48 100644 --- a/apps/opencs/view/world/scriptsubview.cpp +++ b/apps/opencs/view/world/scriptsubview.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include "../../model/doc/document.hpp" #include "../../model/world/universalid.hpp" @@ -35,6 +36,12 @@ void CSVWorld::ScriptSubView::addButtonBar() mButtons, SLOT (universalIdChanged (const CSMWorld::UniversalId&))); } +void CSVWorld::ScriptSubView::recompile() +{ + if (!mCompileDelay->isActive()) + mCompileDelay->start (5000); +} + CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) : SubView (id), mDocument (document), mColumn (-1), mBottom(0), mButtons (0), mCommandDispatcher (document, CSMWorld::UniversalId::getParentType (id.getType())) @@ -101,6 +108,12 @@ CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc: connect (mErrors, SIGNAL (highlightError (int, int)), this, SLOT (highlightError (int, int))); + + mCompileDelay = new QTimer (this); + mCompileDelay->setSingleShot (true); + connect (mCompileDelay, SIGNAL (timeout()), this, SLOT (updateRequest())); + + recompile(); } void CSVWorld::ScriptSubView::updateUserSetting (const QString& name, const QStringList& value) @@ -136,6 +149,9 @@ void CSVWorld::ScriptSubView::updateUserSetting (const QString& name, const QStr mButtons->updateUserSetting (name, value); mErrors->updateUserSetting (name, value); + + if (name=="script-editor/warnings") + recompile(); } void CSVWorld::ScriptSubView::setStatusBar (bool show) @@ -198,7 +214,7 @@ void CSVWorld::ScriptSubView::textChanged() mDocument.getUndoStack().push (new CSMWorld::ModifyCommand (*mModel, mModel->getModelIndex (getUniversalId().getId(), mColumn), source)); - mErrors->update (source.toUtf8().constData()); + recompile(); } void CSVWorld::ScriptSubView::dataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) @@ -219,7 +235,7 @@ void CSVWorld::ScriptSubView::dataChanged (const QModelIndex& topLeft, const QMo mEditor->setPlainText (source); mEditor->setTextCursor (cursor); - mErrors->update (source.toUtf8().constData()); + recompile(); } } @@ -259,3 +275,12 @@ void CSVWorld::ScriptSubView::highlightError (int line, int column) mEditor->setFocus(); mEditor->setTextCursor (cursor); } + +void CSVWorld::ScriptSubView::updateRequest() +{ + QModelIndex index = mModel->getModelIndex (getUniversalId().getId(), mColumn); + + QString source = mModel->data (index).toString(); + + mErrors->update (source.toUtf8().constData()); +} diff --git a/apps/opencs/view/world/scriptsubview.hpp b/apps/opencs/view/world/scriptsubview.hpp index a9c8dccb3..3481989f1 100644 --- a/apps/opencs/view/world/scriptsubview.hpp +++ b/apps/opencs/view/world/scriptsubview.hpp @@ -11,6 +11,7 @@ class QModelIndex; class QLabel; class QVBoxLayout; class QSplitter; +class QTime; namespace CSMDoc { @@ -43,11 +44,14 @@ namespace CSVWorld QVBoxLayout mLayout; QSplitter *mMain; ScriptErrorTable *mErrors; + QTimer *mCompileDelay; private: void addButtonBar(); + void recompile(); + public: ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document); @@ -77,6 +81,8 @@ namespace CSVWorld void switchToId (const std::string& id); void highlightError (int line, int column); + + void updateRequest(); }; } From 8763a3b3c3e9250bd3399102b0f27fce102d7610 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 18 Jul 2015 15:32:38 +0200 Subject: [PATCH 1867/3725] make compilation delay configurable via a user setting --- apps/opencs/model/settings/usersettings.cpp | 6 ++++++ apps/opencs/view/world/scriptsubview.cpp | 7 ++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/settings/usersettings.cpp b/apps/opencs/model/settings/usersettings.cpp index 673db4057..5a4b58266 100644 --- a/apps/opencs/model/settings/usersettings.cpp +++ b/apps/opencs/model/settings/usersettings.cpp @@ -319,6 +319,12 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() Setting *toolbar = createSetting (Type_CheckBox, "toolbar", "Show toolbar"); toolbar->setDefaultValue ("true"); + Setting *delay = createSetting (Type_SpinBox, "compile-delay", + "Delay between updating of source errors"); + delay->setDefaultValue (100); + delay->setRange (0, 10000); + delay->setToolTip ("Delay in milliseconds"); + Setting *formatInt = createSetting (Type_LineEdit, "colour-int", "Highlight Colour: Int"); formatInt->setDefaultValues (QStringList() << "Dark magenta"); formatInt->setToolTip ("(Default: Green) Use one of the following formats:" + tooltip); diff --git a/apps/opencs/view/world/scriptsubview.cpp b/apps/opencs/view/world/scriptsubview.cpp index dfdca8b48..ee0adb6f5 100644 --- a/apps/opencs/view/world/scriptsubview.cpp +++ b/apps/opencs/view/world/scriptsubview.cpp @@ -39,7 +39,8 @@ void CSVWorld::ScriptSubView::addButtonBar() void CSVWorld::ScriptSubView::recompile() { if (!mCompileDelay->isActive()) - mCompileDelay->start (5000); + mCompileDelay->start ( + CSMSettings::UserSettings::instance().setting ("script-editor/compile-delay").toInt()); } CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) @@ -144,6 +145,10 @@ void CSVWorld::ScriptSubView::updateUserSetting (const QString& name, const QStr } } } + else if (name=="script-editor/compile-delay") + { + mCompileDelay->setInterval (value.at (0).toInt()); + } if (mButtons) mButtons->updateUserSetting (name, value); From df077f8649b89a0f85e2c6b3db4c355e92dd8c7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ji=C5=99=C3=AD=20Kune=C5=A1?= Date: Sat, 18 Jul 2015 16:56:57 +0200 Subject: [PATCH 1868/3725] color tooltip red when taking item would result in crime --- apps/openmw/mwgui/tooltips.cpp | 9 +++++++++ files/mygui/openmw_hud_box.skin.xml | 12 ++++++++++++ files/mygui/openmw_windows.skin.xml | 8 ++++++++ 3 files changed, 29 insertions(+) diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 22d5d14f7..e901714a5 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -369,6 +369,15 @@ namespace MWGui MyGUI::IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info) { mDynamicToolTipBox->setVisible(true); + + if(checkOwned()) + { + mDynamicToolTipBox->changeWidgetSkin("HUD_Box_NoTransp_R"); + } + else + { + mDynamicToolTipBox->changeWidgetSkin("HUD_Box_NoTransp"); + } std::string caption = info.caption; std::string image = info.icon; diff --git a/files/mygui/openmw_hud_box.skin.xml b/files/mygui/openmw_hud_box.skin.xml index 4e6349768..7019351bd 100644 --- a/files/mygui/openmw_hud_box.skin.xml +++ b/files/mygui/openmw_hud_box.skin.xml @@ -31,5 +31,17 @@
    + + + + + + + + + + + +
    diff --git a/files/mygui/openmw_windows.skin.xml b/files/mygui/openmw_windows.skin.xml index e74038391..29299dc06 100644 --- a/files/mygui/openmw_windows.skin.xml +++ b/files/mygui/openmw_windows.skin.xml @@ -128,6 +128,14 @@
    + + + + + + + + From f1ac440b7832dce0745c2e35bfa8c40ca4c66c36 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 18 Jul 2015 17:00:00 +0200 Subject: [PATCH 1869/3725] do not allow editing of deleted scripts --- apps/opencs/view/world/scripterrortable.cpp | 7 ++- apps/opencs/view/world/scripterrortable.hpp | 2 + apps/opencs/view/world/scriptsubview.cpp | 57 ++++++++++++++------- apps/opencs/view/world/scriptsubview.hpp | 5 ++ 4 files changed, 51 insertions(+), 20 deletions(-) diff --git a/apps/opencs/view/world/scripterrortable.cpp b/apps/opencs/view/world/scripterrortable.cpp index 20b197c54..3e80c5bd4 100644 --- a/apps/opencs/view/world/scripterrortable.cpp +++ b/apps/opencs/view/world/scripterrortable.cpp @@ -100,7 +100,7 @@ void CSVWorld::ScriptErrorTable::updateUserSetting (const QString& name, const Q void CSVWorld::ScriptErrorTable::update (const std::string& source) { - setRowCount (0); + clear(); try { @@ -122,6 +122,11 @@ void CSVWorld::ScriptErrorTable::update (const std::string& source) } } +void CSVWorld::ScriptErrorTable::clear() +{ + setRowCount (0); +} + void CSVWorld::ScriptErrorTable::cellClicked (int row, int column) { if (item (row, 1)) diff --git a/apps/opencs/view/world/scripterrortable.hpp b/apps/opencs/view/world/scripterrortable.hpp index f16a96a74..98db425cf 100644 --- a/apps/opencs/view/world/scripterrortable.hpp +++ b/apps/opencs/view/world/scripterrortable.hpp @@ -42,6 +42,8 @@ namespace CSVWorld void update (const std::string& source); + void clear(); + private slots: void cellClicked (int row, int column); diff --git a/apps/opencs/view/world/scriptsubview.cpp b/apps/opencs/view/world/scriptsubview.cpp index ee0adb6f5..d405d1765 100644 --- a/apps/opencs/view/world/scriptsubview.cpp +++ b/apps/opencs/view/world/scriptsubview.cpp @@ -38,11 +38,31 @@ void CSVWorld::ScriptSubView::addButtonBar() void CSVWorld::ScriptSubView::recompile() { - if (!mCompileDelay->isActive()) + if (!mCompileDelay->isActive() && !isDeleted()) mCompileDelay->start ( CSMSettings::UserSettings::instance().setting ("script-editor/compile-delay").toInt()); } +bool CSVWorld::ScriptSubView::isDeleted() const +{ + return mModel->data (mModel->getModelIndex (getUniversalId().getId(), mStateColumn)).toInt() + ==CSMWorld::RecordBase::State_Deleted; +} + +void CSVWorld::ScriptSubView::updateDeletedState() +{ + if (isDeleted()) + { + mErrors->clear(); + mEditor->setEnabled (false); + } + else + { + mEditor->setEnabled (true); + recompile(); + } +} + CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) : SubView (id), mDocument (document), mColumn (-1), mBottom(0), mButtons (0), mCommandDispatcher (document, CSMWorld::UniversalId::getParentType (id.getType())) @@ -68,16 +88,8 @@ CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc: mModel = &dynamic_cast ( *document.getData().getTableModel (CSMWorld::UniversalId::Type_Scripts)); - for (int i=0; icolumnCount(); ++i) - if (mModel->headerData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Display)== - CSMWorld::ColumnBase::Display_ScriptFile) - { - mColumn = i; - break; - } - - if (mColumn==-1) - throw std::logic_error ("Can't find script column"); + mColumn = mModel->findColumnIndex (CSMWorld::Columns::ColumnId_ScriptText); + mStateColumn = mModel->findColumnIndex (CSMWorld::Columns::ColumnId_Modification); QString source = mModel->data (mModel->getModelIndex (id.getId(), mColumn)).toString(); @@ -114,7 +126,7 @@ CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc: mCompileDelay->setSingleShot (true); connect (mCompileDelay, SIGNAL (timeout()), this, SLOT (updateRequest())); - recompile(); + updateDeletedState(); } void CSVWorld::ScriptSubView::updateUserSetting (const QString& name, const QStringList& value) @@ -231,16 +243,21 @@ void CSVWorld::ScriptSubView::dataChanged (const QModelIndex& topLeft, const QMo QModelIndex index = mModel->getModelIndex (getUniversalId().getId(), mColumn); - if (index.row()>=topLeft.row() && index.row()<=bottomRight.row() && - index.column()>=topLeft.column() && index.column()<=bottomRight.column()) + if (index.row()>=topLeft.row() && index.row()<=bottomRight.row()) { - QString source = mModel->data (index).toString(); + if (mStateColumn>=topLeft.column() && mStateColumn<=bottomRight.column()) + updateDeletedState(); - QTextCursor cursor = mEditor->textCursor(); - mEditor->setPlainText (source); - mEditor->setTextCursor (cursor); + if (mColumn>=topLeft.column() && mColumn<=bottomRight.column()) + { + QString source = mModel->data (index).toString(); - recompile(); + QTextCursor cursor = mEditor->textCursor(); + mEditor->setPlainText (source); + mEditor->setTextCursor (cursor); + + recompile(); + } } } @@ -262,6 +279,8 @@ void CSVWorld::ScriptSubView::switchToRow (int row) std::vector selection (1, id); mCommandDispatcher.setSelection (selection); + + updateDeletedState(); } void CSVWorld::ScriptSubView::switchToId (const std::string& id) diff --git a/apps/opencs/view/world/scriptsubview.hpp b/apps/opencs/view/world/scriptsubview.hpp index 3481989f1..6125dd259 100644 --- a/apps/opencs/view/world/scriptsubview.hpp +++ b/apps/opencs/view/world/scriptsubview.hpp @@ -38,6 +38,7 @@ namespace CSVWorld CSMDoc::Document& mDocument; CSMWorld::IdTable *mModel; int mColumn; + int mStateColumn; TableBottomBox *mBottom; RecordButtonBar *mButtons; CSMWorld::CommandDispatcher mCommandDispatcher; @@ -52,6 +53,10 @@ namespace CSVWorld void recompile(); + bool isDeleted() const; + + void updateDeletedState(); + public: ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document); From 75f59728984df63a43d9eaa2e42dee572738cb70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ji=C5=99=C3=AD=20Kune=C5=A1?= Date: Sat, 18 Jul 2015 17:13:20 +0200 Subject: [PATCH 1870/3725] show owned - better settings --- apps/openmw/mwgui/tooltips.cpp | 18 ++++++++++++------ apps/openmw/mwgui/tooltips.hpp | 2 ++ apps/openmw/mwgui/windowmanagerimp.cpp | 6 +++--- apps/openmw/mwgui/windowmanagerimp.hpp | 2 +- files/mygui/openmw_windows.skin.xml | 2 +- files/settings-default.cfg | 8 ++++++-- 6 files changed, 25 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index e901714a5..a51c68acf 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -38,6 +38,7 @@ namespace MWGui , mLastMouseY(0) , mEnabled(true) , mFullHelp(false) + , mShowOwned(0) { getWidget(mDynamicToolTipBox, "DynamicToolTipBox"); @@ -55,6 +56,8 @@ namespace MWGui { mMainWidget->getChildAt(i)->setVisible(false); } + + mShowOwned = Settings::Manager::getInt("show owned", "Game"); } void ToolTips::setEnabled(bool enabled) @@ -370,13 +373,16 @@ namespace MWGui { mDynamicToolTipBox->setVisible(true); - if(checkOwned()) + if(mShowOwned == 1 || mShowOwned == 3) { - mDynamicToolTipBox->changeWidgetSkin("HUD_Box_NoTransp_R"); - } - else - { - mDynamicToolTipBox->changeWidgetSkin("HUD_Box_NoTransp"); + if(checkOwned()) + { + mDynamicToolTipBox->changeWidgetSkin("HUD_Box_NoTransp_R"); + } + else + { + mDynamicToolTipBox->changeWidgetSkin("HUD_Box_NoTransp"); + } } std::string caption = info.caption; diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp index bd4a81c32..b2f172076 100644 --- a/apps/openmw/mwgui/tooltips.hpp +++ b/apps/openmw/mwgui/tooltips.hpp @@ -122,6 +122,8 @@ namespace MWGui bool mEnabled; bool mFullHelp; + + int mShowOwned; }; } #endif diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 44eed6623..7b618efa7 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -187,7 +187,7 @@ namespace MWGui , mRestAllowed(true) , mFPS(0.0f) , mFallbackMap(fallbackMap) - , mShowOwned(false) + , mShowOwned(0) , mVersionDescription(versionDescription) { float uiScale = Settings::Manager::getFloat("scaling factor", "GUI"); @@ -264,7 +264,7 @@ namespace MWGui MyGUI::ClipboardManager::getInstance().eventClipboardChanged += MyGUI::newDelegate(this, &WindowManager::onClipboardChanged); MyGUI::ClipboardManager::getInstance().eventClipboardRequested += MyGUI::newDelegate(this, &WindowManager::onClipboardRequested); - mShowOwned = Settings::Manager::getBool("show owned", "Game"); + mShowOwned = Settings::Manager::getInt("show owned", "Game"); } void WindowManager::initUI() @@ -1043,7 +1043,7 @@ namespace MWGui { mToolTips->setFocusObject(focus); - if(mShowOwned && mHud) + if(mHud && (mShowOwned == 2 || mShowOwned == 3)) { bool owned = mToolTips->checkOwned(); mHud->setCrosshairOwned(owned); diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 7dae50209..af82c27c0 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -487,7 +487,7 @@ namespace MWGui std::map mFallbackMap; - bool mShowOwned; + int mShowOwned; std::string mVersionDescription; diff --git a/files/mygui/openmw_windows.skin.xml b/files/mygui/openmw_windows.skin.xml index 29299dc06..47f8cada8 100644 --- a/files/mygui/openmw_windows.skin.xml +++ b/files/mygui/openmw_windows.skin.xml @@ -131,7 +131,7 @@ - + diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 4ec0c2480..d84291a24 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -162,8 +162,12 @@ best attack = false difficulty = 0 -# change crosshair color when pointing on owned object -show owned = false +# Change crosshair/toolTip color when pointing on owned object +#0: nothing changed +#1: tint toolTip +#2: tint crosshair +#3: both +show owned = 0 [Saves] character = From cdfa3006a3b94e8cf2f1b0ca50acf783aaa3ec45 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 18 Jul 2015 17:47:50 +0200 Subject: [PATCH 1871/3725] incorrect sBribe GMSTs for new omwgame files (Fixes #2785) --- apps/opencs/model/doc/document.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 215dbd304..44e6142b0 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -798,9 +798,9 @@ void CSMDoc::Document::addGmsts() "sBookSkillMessage", "sBounty", "sBreath", - "sBribe", - "sBribe", - "sBribe", + "sBribe 10 Gold", + "sBribe 100 Gold", + "sBribe 1000 Gold", "sBribeFail", "sBribeSuccess", "sBuy", From 77f1387da8180c2e8603d6642bc41e366effa7c6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 18 Jul 2015 19:40:31 +0200 Subject: [PATCH 1872/3725] Include cleanup --- apps/openmw/mwgui/birth.cpp | 2 -- apps/openmw/mwgui/companionitemmodel.cpp | 1 - apps/openmw/mwgui/companionwindow.cpp | 3 --- apps/openmw/mwgui/container.cpp | 2 -- apps/openmw/mwgui/dialogue.cpp | 4 ++-- apps/openmw/mwgui/enchantingdialog.cpp | 1 - apps/openmw/mwgui/hud.cpp | 1 - apps/openmw/mwgui/inventoryitemmodel.cpp | 2 -- apps/openmw/mwgui/inventorywindow.cpp | 4 +--- apps/openmw/mwgui/loadingscreen.cpp | 2 -- apps/openmw/mwgui/mainmenu.cpp | 4 ---- apps/openmw/mwgui/mapwindow.cpp | 1 - apps/openmw/mwgui/pickpocketitemmodel.cpp | 2 +- apps/openmw/mwgui/quickkeysmenu.cpp | 5 +---- apps/openmw/mwgui/recharge.cpp | 2 -- apps/openmw/mwgui/spellbuyingwindow.cpp | 1 - apps/openmw/mwgui/tradewindow.cpp | 1 - apps/openmw/mwgui/windowmanagerimp.cpp | 3 +-- apps/openmw/mwmechanics/actors.cpp | 4 +--- 19 files changed, 7 insertions(+), 38 deletions(-) diff --git a/apps/openmw/mwgui/birth.cpp b/apps/openmw/mwgui/birth.cpp index 1122a4069..de8614004 100644 --- a/apps/openmw/mwgui/birth.cpp +++ b/apps/openmw/mwgui/birth.cpp @@ -4,8 +4,6 @@ #include #include -#include - #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" diff --git a/apps/openmw/mwgui/companionitemmodel.cpp b/apps/openmw/mwgui/companionitemmodel.cpp index 983ef5017..0ff0b648e 100644 --- a/apps/openmw/mwgui/companionitemmodel.cpp +++ b/apps/openmw/mwgui/companionitemmodel.cpp @@ -1,6 +1,5 @@ #include "companionitemmodel.hpp" -#include "../mwmechanics/npcstats.hpp" #include "../mwworld/class.hpp" namespace diff --git a/apps/openmw/mwgui/companionwindow.cpp b/apps/openmw/mwgui/companionwindow.cpp index b61d46400..fc4a98489 100644 --- a/apps/openmw/mwgui/companionwindow.cpp +++ b/apps/openmw/mwgui/companionwindow.cpp @@ -3,11 +3,8 @@ #include #include "../mwbase/environment.hpp" -#include "../mwbase/dialoguemanager.hpp" #include "../mwbase/windowmanager.hpp" -#include "../mwmechanics/npcstats.hpp" - #include "../mwworld/class.hpp" #include "messagebox.hpp" diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 2f874119d..b2cc09b43 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -11,13 +11,11 @@ #include "../mwbase/mechanicsmanager.hpp" #include "../mwworld/class.hpp" -#include "../mwworld/containerstore.hpp" #include "../mwmechanics/pickpocket.hpp" #include "../mwmechanics/creaturestats.hpp" #include "countdialog.hpp" -#include "tradewindow.hpp" #include "inventorywindow.hpp" #include "itemview.hpp" diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 0cb0475c9..ce33a74dd 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -16,12 +16,12 @@ #include "../mwbase/soundmanager.hpp" #include "../mwbase/dialoguemanager.hpp" -#include "../mwmechanics/npcstats.hpp" - #include "../mwworld/class.hpp" #include "../mwworld/containerstore.hpp" #include "../mwworld/esmstore.hpp" +#include "../mwmechanics/creaturestats.hpp" + #include "widgets.hpp" #include "bookpage.hpp" diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 43f2493a9..61a935a6f 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -7,7 +7,6 @@ #include #include -#include #include #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 0f107f4e3..7307e6f87 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -10,7 +10,6 @@ #include #include "../mwbase/environment.hpp" -#include "../mwbase/soundmanager.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwbase/world.hpp" diff --git a/apps/openmw/mwgui/inventoryitemmodel.cpp b/apps/openmw/mwgui/inventoryitemmodel.cpp index e8354b740..b80850ba1 100644 --- a/apps/openmw/mwgui/inventoryitemmodel.cpp +++ b/apps/openmw/mwgui/inventoryitemmodel.cpp @@ -4,8 +4,6 @@ #include "../mwworld/class.hpp" #include "../mwworld/inventorystore.hpp" -#include "../mwmechanics/creaturestats.hpp" - namespace MWGui { diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 39f476403..9c9138ed5 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -16,19 +16,17 @@ #include -#include - #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" +#include "../mwbase/scriptmanager.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwworld/class.hpp" #include "../mwworld/action.hpp" #include "../mwscript/interpretercontext.hpp" -#include "../mwbase/scriptmanager.hpp" #include "../mwrender/characterpreview.hpp" #include "itemview.hpp" diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index 7e733686d..9b99ad7bf 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -17,9 +17,7 @@ #include #include "../mwbase/environment.hpp" -#include "../mwbase/world.hpp" #include "../mwbase/statemanager.hpp" - #include "../mwbase/windowmanager.hpp" #include "../mwbase/inputmanager.hpp" diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index 409306986..258f0dfb0 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -12,12 +12,8 @@ #include "../mwbase/windowmanager.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwbase/world.hpp" -#include "../mwbase/journal.hpp" -#include "../mwbase/dialoguemanager.hpp" #include "../mwbase/statemanager.hpp" -#include "../mwstate/character.hpp" - #include "savegamedialog.hpp" #include "confirmationdialog.hpp" #include "backgroundimage.hpp" diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 2485f3c94..d564dfcbc 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -27,7 +27,6 @@ #include "../mwrender/globalmap.hpp" #include "../mwrender/localmap.hpp" -#include "widgets.hpp" #include "confirmationdialog.hpp" #include "tooltips.hpp" diff --git a/apps/openmw/mwgui/pickpocketitemmodel.cpp b/apps/openmw/mwgui/pickpocketitemmodel.cpp index a0550ae25..ab0d02f95 100644 --- a/apps/openmw/mwgui/pickpocketitemmodel.cpp +++ b/apps/openmw/mwgui/pickpocketitemmodel.cpp @@ -1,8 +1,8 @@ #include "pickpocketitemmodel.hpp" #include +#include -#include "../mwmechanics/npcstats.hpp" #include "../mwworld/class.hpp" namespace MWGui diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index 8c919e8bd..3f896bae2 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -15,18 +15,15 @@ #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" +#include "../mwbase/windowmanager.hpp" #include "../mwmechanics/spellcasting.hpp" #include "../mwmechanics/creaturestats.hpp" #include "../mwgui/inventorywindow.hpp" -#include "windowmanagerimp.hpp" #include "itemselection.hpp" - #include "spellview.hpp" - - #include "itemwidget.hpp" #include "sortfilteritemmodel.hpp" diff --git a/apps/openmw/mwgui/recharge.cpp b/apps/openmw/mwgui/recharge.cpp index 76961af5d..69c5c61c4 100644 --- a/apps/openmw/mwgui/recharge.cpp +++ b/apps/openmw/mwgui/recharge.cpp @@ -7,8 +7,6 @@ #include -#include - #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" diff --git a/apps/openmw/mwgui/spellbuyingwindow.cpp b/apps/openmw/mwgui/spellbuyingwindow.cpp index ae7b7588a..61dd599e7 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.cpp +++ b/apps/openmw/mwgui/spellbuyingwindow.cpp @@ -12,7 +12,6 @@ #include "../mwworld/class.hpp" #include "../mwworld/containerstore.hpp" -#include "../mwworld/containerstore.hpp" #include "../mwworld/esmstore.hpp" #include "../mwmechanics/creaturestats.hpp" diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 1c5dc4632..0ae661eb3 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -15,7 +15,6 @@ #include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/dialoguemanager.hpp" -#include "../mwworld/manualref.hpp" #include "../mwworld/class.hpp" #include "../mwworld/containerstore.hpp" #include "../mwworld/esmstore.hpp" diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 44eed6623..31eef5c01 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -45,6 +45,7 @@ #include "../mwbase/inputmanager.hpp" #include "../mwbase/statemanager.hpp" +#include "../mwbase/soundmanager.hpp" #include "../mwrender/vismask.hpp" @@ -58,8 +59,6 @@ #include "../mwrender/localmap.hpp" -#include "../mwsound/soundmanagerimp.hpp" - #include "console.hpp" #include "journalwindow.hpp" #include "journalviewmodel.hpp" diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index d9a8ce72f..d436eca31 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -7,12 +7,10 @@ #include #include #include -#include #include "../mwworld/esmstore.hpp" #include "../mwworld/class.hpp" #include "../mwworld/inventorystore.hpp" -#include "../mwworld/manualref.hpp" #include "../mwworld/actionequip.hpp" #include "../mwworld/player.hpp" @@ -22,7 +20,7 @@ #include "../mwbase/soundmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" -#include "../mwrender/animation.hpp" +#include "../mwmechanics/spellcasting.hpp" #include "npcstats.hpp" #include "creaturestats.hpp" From 278a078e9d39340fbf907ba156931b00bf0c0376 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 18 Jul 2015 20:39:45 +0200 Subject: [PATCH 1873/3725] Unify magic effect tick functions - Removes duplicated code - Handle some zero-duration instant effects that were not handled before (disintegrate, sun damage, elemental damage) --- apps/openmw/mwbase/mechanicsmanager.hpp | 5 + apps/openmw/mwclass/npc.cpp | 7 +- apps/openmw/mwmechanics/actors.cpp | 165 ++----------- .../mwmechanics/mechanicsmanagerimp.cpp | 21 ++ .../mwmechanics/mechanicsmanagerimp.hpp | 5 + apps/openmw/mwmechanics/spellcasting.cpp | 228 ++++++++++++++---- apps/openmw/mwmechanics/spellcasting.hpp | 3 + 7 files changed, 229 insertions(+), 205 deletions(-) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index b66e60e1d..2c4a22c07 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -129,6 +129,11 @@ namespace MWBase OffenseType type, int arg=0, bool victimAware=false) = 0; /// @return false if the attack was considered a "friendly hit" and forgiven virtual bool actorAttacked (const MWWorld::Ptr& victim, const MWWorld::Ptr& attacker) = 0; + + /// Notify that actor was killed, add a murder bounty if applicable + /// @note No-op for non-player attackers + virtual void actorKilled (const MWWorld::Ptr& victim, const MWWorld::Ptr& attacker) = 0; + /// Utility to check if taking this item is illegal and calling commitCrime if so /// @param container The container the item is in; may be empty for an item in the world virtual void itemTaken (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, const MWWorld::Ptr& container, diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index c7b407fb8..d0dd9f994 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -751,12 +751,7 @@ namespace MWClass attacker.getClass().getNpcStats(attacker).addWerewolfKill(); } - // Simple check for who attacked first: if the player attacked first, a crimeId should be set - // Doesn't handle possible edge case where no one reported the assault, but in such a case, - // for bystanders it is not possible to tell who attacked first, anyway. - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); - if (attacker == player && ptr.getClass().getNpcStats(ptr).getCrimeId() != -1 && ptr != player) - MWBase::Environment::get().getMechanicsManager()->commitCrime(player, ptr, MWBase::MechanicsManager::OT_Murder); + MWBase::Environment::get().getMechanicsManager()->actorKilled(ptr, attacker); } } diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index d436eca31..4a08176d1 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -67,44 +67,6 @@ void adjustBoundItem (const std::string& item, bool bound, const MWWorld::Ptr& a } } -bool disintegrateSlot (MWWorld::Ptr ptr, int slot, float disintegrate) -{ - if (ptr.getClass().hasInventoryStore(ptr)) - { - MWWorld::InventoryStore& inv = ptr.getClass().getInventoryStore(ptr); - MWWorld::ContainerStoreIterator item = - inv.getSlot(slot); - if (item != inv.end()) - { - if (!item->getClass().hasItemHealth(*item)) - return false; - int charge = item->getClass().getItemHealth(*item); - - if (charge == 0) - return false; - - // FIXME: charge should be a float, not int so that damage < 1 per frame can be applied. - // This was also a bug in the original engine. - charge -= - std::min(static_cast(disintegrate), - charge); - item->getCellRef().setCharge(charge); - - if (charge == 0) - { - // Will unequip the broken item and try to find a replacement - if (ptr != MWBase::Environment::get().getWorld()->getPlayerPtr()) - inv.autoEquip(ptr); - else - inv.unequipItem(*item, ptr); - } - - return true; - } - } - return false; -} - class CheckActorCommanded : public MWMechanics::EffectSourceVisitor { MWWorld::Ptr mActor; @@ -516,8 +478,12 @@ namespace MWMechanics bool wasDead = creatureStats.isDead(); - // FIXME: effect ticks should go into separate functions so they can be used with either - // magnitude (instant effect) or magnitude*duration + // tickable effects (i.e. effects having a lasting impact after expiry) + // these effects can be applied as "instant" (handled in spellcasting.cpp) or with a duration, handled here + for (MagicEffects::Collection::const_iterator it = effects.begin(); it != effects.end(); ++it) + { + effectTick(creatureStats, ptr, it->first, it->second.getMagnitude() * duration); + } // attributes for(int i = 0;i < ESM::Attribute::Length;++i) @@ -527,9 +493,6 @@ namespace MWMechanics effects.get(EffectKey(ESM::MagicEffect::DrainAttribute, i)).getMagnitude() - effects.get(EffectKey(ESM::MagicEffect::AbsorbAttribute, i)).getMagnitude())); - stat.damage(effects.get(EffectKey(ESM::MagicEffect::DamageAttribute, i)).getMagnitude() * duration); - stat.restore(effects.get(EffectKey(ESM::MagicEffect::RestoreAttribute, i)).getMagnitude() * duration); - creatureStats.setAttribute(i, stat); } @@ -559,12 +522,6 @@ namespace MWMechanics // Fatigue can be decreased below zero meaning the actor will be knocked out i == 2); - - float currentDiff = creatureStats.getMagicEffects().get(ESM::MagicEffect::RestoreHealth+i).getMagnitude() - - creatureStats.getMagicEffects().get(ESM::MagicEffect::DamageHealth+i).getMagnitude() - - creatureStats.getMagicEffects().get(ESM::MagicEffect::AbsorbHealth+i).getMagnitude(); - stat.setCurrent(stat.getCurrent() + currentDiff * duration, i == 2); - creatureStats.setDynamic(i, stat); } @@ -592,90 +549,11 @@ namespace MWMechanics creatureStats.setAiSetting(CreatureStats::AI_Flee, stat); } - // Apply disintegration (reduces item health) - float disintegrateWeapon = effects.get(ESM::MagicEffect::DisintegrateWeapon).getMagnitude(); - if (disintegrateWeapon > 0) - disintegrateSlot(ptr, MWWorld::InventoryStore::Slot_CarriedRight, disintegrateWeapon*duration); - float disintegrateArmor = effects.get(ESM::MagicEffect::DisintegrateArmor).getMagnitude(); - if (disintegrateArmor > 0) - { - // According to UESP - int priorities[] = { - MWWorld::InventoryStore::Slot_CarriedLeft, - MWWorld::InventoryStore::Slot_Cuirass, - MWWorld::InventoryStore::Slot_LeftPauldron, - MWWorld::InventoryStore::Slot_RightPauldron, - MWWorld::InventoryStore::Slot_LeftGauntlet, - MWWorld::InventoryStore::Slot_RightGauntlet, - MWWorld::InventoryStore::Slot_Helmet, - MWWorld::InventoryStore::Slot_Greaves, - MWWorld::InventoryStore::Slot_Boots - }; - - for (unsigned int i=0; i 0.0f - || creatureStats.getMagicEffects().get(ESM::MagicEffect::AbsorbHealth).getMagnitude() > 0.0f) - receivedMagicDamage = true; - - // Apply damage ticks - int damageEffects[] = { - ESM::MagicEffect::FireDamage, ESM::MagicEffect::ShockDamage, ESM::MagicEffect::FrostDamage, ESM::MagicEffect::Poison, - ESM::MagicEffect::SunDamage - }; - - DynamicStat health = creatureStats.getHealth(); - for (unsigned int i=0; iisExterior()) - continue; - float time = MWBase::Environment::get().getWorld()->getTimeStamp().getHour(); - float timeDiff = std::min(7.f, std::max(0.f, std::abs(time - 13))); - float damageScale = 1.f - timeDiff / 7.f; - // When cloudy, the sun damage effect is halved - static float fMagicSunBlockedMult = MWBase::Environment::get().getWorld()->getStore().get().find( - "fMagicSunBlockedMult")->getFloat(); - - int weather = MWBase::Environment::get().getWorld()->getCurrentWeather(); - if (weather > 1) - damageScale *= fMagicSunBlockedMult; - health.setCurrent(health.getCurrent() - magnitude * duration * damageScale); - - if (magnitude * damageScale > 0.0f) - receivedMagicDamage = true; - } - else - { - health.setCurrent(health.getCurrent() - magnitude * duration); - - if (magnitude > 0.0f) - receivedMagicDamage = true; - } - } - - if (receivedMagicDamage && ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) - MWBase::Environment::get().getWindowManager()->activateHitOverlay(false); - - creatureStats.setHealth(health); - if (!wasDead && creatureStats.isDead()) { // The actor was killed by a magic effect. Figure out if the player was responsible for it. const ActiveSpells& spells = creatureStats.getActiveSpells(); bool killedByPlayer = false; - bool murderedByPlayer = false; MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); for (ActiveSpells::TIterator it = spells.begin(); it != spells.end(); ++it) { @@ -685,33 +563,29 @@ namespace MWMechanics { int effectId = effectIt->mEffectId; bool isDamageEffect = false; + + int damageEffects[] = { + ESM::MagicEffect::FireDamage, ESM::MagicEffect::ShockDamage, ESM::MagicEffect::FrostDamage, ESM::MagicEffect::Poison, + ESM::MagicEffect::SunDamage, ESM::MagicEffect::DamageHealth, ESM::MagicEffect::AbsorbHealth + }; + for (unsigned int i=0; isearchPtrViaActorId(spell.mCasterActorId); if (isDamageEffect && caster == player) - { killedByPlayer = true; - // Simple check for who attacked first: if the player attacked first, a crimeId should be set - // Doesn't handle possible edge case where no one reported the assault, but in such a case, - // for bystanders it is not possible to tell who attacked first, anyway. - if (ptr.getClass().isNpc() && ptr.getClass().getNpcStats(ptr).getCrimeId() != -1 - && ptr != player) - murderedByPlayer = true; - } } } - if (murderedByPlayer) - MWBase::Environment::get().getMechanicsManager()->commitCrime(player, ptr, MWBase::MechanicsManager::OT_Murder); - if (killedByPlayer && player.getClass().getNpcStats(player).isWerewolf()) - player.getClass().getNpcStats(player).addWerewolfKill(); + if (killedByPlayer) + { + MWBase::Environment::get().getMechanicsManager()->actorKilled(ptr, player); + if (player.getClass().getNpcStats(player).isWerewolf()) + player.getClass().getNpcStats(player).addWerewolfKill(); + } } // TODO: dirty flag for magic effects to avoid some unnecessary work below? @@ -795,9 +669,6 @@ namespace MWMechanics skill.setModifier(static_cast(effects.get(EffectKey(ESM::MagicEffect::FortifySkill, i)).getMagnitude() - effects.get(EffectKey(ESM::MagicEffect::DrainSkill, i)).getMagnitude() - effects.get(EffectKey(ESM::MagicEffect::AbsorbSkill, i)).getMagnitude())); - - skill.damage(effects.get(EffectKey(ESM::MagicEffect::DamageSkill, i)).getMagnitude() * duration); - skill.restore(effects.get(EffectKey(ESM::MagicEffect::RestoreSkill, i)).getMagnitude() * duration); } } diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index fef99dc61..e9ef99454 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1330,6 +1330,27 @@ namespace MWMechanics return true; } + void MechanicsManager::actorKilled(const MWWorld::Ptr &victim, const MWWorld::Ptr &attacker) + { + if (attacker.isEmpty() || attacker != MWBase::Environment::get().getWorld()->getPlayerPtr()) + return; + + if (victim == attacker) + return; // known to happen + + if (!victim.getClass().isNpc()) + return; // TODO: implement animal rights + + const MWMechanics::NpcStats& victimStats = victim.getClass().getNpcStats(victim); + + // Simple check for who attacked first: if the player attacked first, a crimeId should be set + // Doesn't handle possible edge case where no one reported the assault, but in such a case, + // for bystanders it is not possible to tell who attacked first, anyway. + if (victimStats.getCrimeId() != -1) + MWBase::Environment::get().getMechanicsManager()->commitCrime(attacker, victim, MWBase::MechanicsManager::OT_Murder); + + } + bool MechanicsManager::awarenessCheck(const MWWorld::Ptr &ptr, const MWWorld::Ptr &observer) { if (observer.getClass().getCreatureStats(observer).isDead() || !observer.getRefData().isEnabled()) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index 392d7fbbe..6386b4a2a 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -120,6 +120,11 @@ namespace MWMechanics OffenseType type, int arg=0, bool victimAware=false); /// @return false if the attack was considered a "friendly hit" and forgiven virtual bool actorAttacked (const MWWorld::Ptr& victim, const MWWorld::Ptr& attacker); + + /// Notify that actor was killed, add a murder bounty if applicable + /// @note No-op for non-player attackers + virtual void actorKilled (const MWWorld::Ptr& victim, const MWWorld::Ptr& attacker); + /// Utility to check if taking this item is illegal and calling commitCrime if so /// @param container The container the item is in; may be empty for an item in the world virtual void itemTaken (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, const MWWorld::Ptr& container, diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index a47da7bf4..1613300d7 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -19,6 +19,8 @@ #include "../mwworld/cellstore.hpp" #include "../mwworld/esmstore.hpp" +#include "../mwworld/inventorystore.hpp" + #include "../mwrender/animation.hpp" #include "magiceffects.hpp" @@ -65,57 +67,6 @@ namespace target.getClass().getCreatureStats(target).setDynamic(attribute, value); } - // TODO: refactor the effect tick functions in Actors so they can be reused here - void applyInstantEffectTick(MWMechanics::EffectKey effect, const MWWorld::Ptr& target, float magnitude) - { - int effectId = effect.mId; - if (effectId == ESM::MagicEffect::DamageHealth) - { - applyDynamicStatsEffect(0, target, magnitude * -1); - } - else if (effectId == ESM::MagicEffect::RestoreHealth) - { - applyDynamicStatsEffect(0, target, magnitude); - } - else if (effectId == ESM::MagicEffect::DamageFatigue) - { - applyDynamicStatsEffect(2, target, magnitude * -1); - } - else if (effectId == ESM::MagicEffect::RestoreFatigue) - { - applyDynamicStatsEffect(2, target, magnitude); - } - else if (effectId == ESM::MagicEffect::DamageMagicka) - { - applyDynamicStatsEffect(1, target, magnitude * -1); - } - else if (effectId == ESM::MagicEffect::RestoreMagicka) - { - applyDynamicStatsEffect(1, target, magnitude); - } - else if (effectId == ESM::MagicEffect::DamageAttribute || effectId == ESM::MagicEffect::RestoreAttribute) - { - int attribute = effect.mArg; - MWMechanics::AttributeValue value = target.getClass().getCreatureStats(target).getAttribute(attribute); - if (effectId == ESM::MagicEffect::DamageAttribute) - value.damage(magnitude); - else - value.restore(magnitude); - target.getClass().getCreatureStats(target).setAttribute(attribute, value); - } - else if (effectId == ESM::MagicEffect::DamageSkill || effectId == ESM::MagicEffect::RestoreSkill) - { - if (target.getTypeName() != typeid(ESM::NPC).name()) - return; - int skill = effect.mArg; - MWMechanics::SkillValue& value = target.getClass().getNpcStats(target).getSkill(skill); - if (effectId == ESM::MagicEffect::DamageSkill) - value.damage(magnitude); - else - value.restore(magnitude); - } - } - } namespace MWMechanics @@ -530,7 +481,14 @@ namespace MWMechanics else { if (hasDuration && target.getClass().isActor()) - applyInstantEffectTick(EffectKey(*effectIt), target, magnitude); + { + bool wasDead = target.getClass().getCreatureStats(target).isDead(); + effectTick(target.getClass().getCreatureStats(target), target, EffectKey(*effectIt), magnitude); + bool isDead = target.getClass().getCreatureStats(target).isDead(); + + if (!wasDead && isDead) + MWBase::Environment::get().getMechanicsManager()->actorKilled(target, caster); + } else applyInstantEffect(target, caster, EffectKey(*effectIt), magnitude); } @@ -960,4 +918,170 @@ namespace MWMechanics || (effectId >= ESM::MagicEffect::SummonFabricant && effectId <= ESM::MagicEffect::SummonCreature05)); } + + bool disintegrateSlot (MWWorld::Ptr ptr, int slot, float disintegrate) + { + if (ptr.getClass().hasInventoryStore(ptr)) + { + MWWorld::InventoryStore& inv = ptr.getClass().getInventoryStore(ptr); + MWWorld::ContainerStoreIterator item = + inv.getSlot(slot); + if (item != inv.end()) + { + if (!item->getClass().hasItemHealth(*item)) + return false; + int charge = item->getClass().getItemHealth(*item); + + if (charge == 0) + return false; + + // FIXME: charge should be a float, not int so that damage < 1 per frame can be applied. + // This was also a bug in the original engine. + charge -= + std::min(static_cast(disintegrate), + charge); + item->getCellRef().setCharge(charge); + + if (charge == 0) + { + // Will unequip the broken item and try to find a replacement + if (ptr != MWBase::Environment::get().getWorld()->getPlayerPtr()) + inv.autoEquip(ptr); + else + inv.unequipItem(*item, ptr); + } + + return true; + } + } + return false; + } + + void adjustDynamicStat(CreatureStats& creatureStats, int index, float magnitude) + { + DynamicStat stat = creatureStats.getDynamic(index); + stat.setCurrent(stat.getCurrent() + magnitude, index == 2); + creatureStats.setDynamic(index, stat); + } + + void effectTick(CreatureStats& creatureStats, const MWWorld::Ptr& actor, const EffectKey &effectKey, float magnitude) + { + if (magnitude == 0.f) + return; + + bool receivedMagicDamage = false; + + switch (effectKey.mId) + { + case ESM::MagicEffect::DamageAttribute: + { + AttributeValue attr = creatureStats.getAttribute(effectKey.mArg); + attr.damage(magnitude); + creatureStats.setAttribute(effectKey.mArg, attr); + break; + } + case ESM::MagicEffect::RestoreAttribute: + { + AttributeValue attr = creatureStats.getAttribute(effectKey.mArg); + attr.restore(magnitude); + creatureStats.setAttribute(effectKey.mArg, attr); + break; + } + case ESM::MagicEffect::RestoreHealth: + case ESM::MagicEffect::RestoreMagicka: + case ESM::MagicEffect::RestoreFatigue: + adjustDynamicStat(creatureStats, effectKey.mId-ESM::MagicEffect::RestoreHealth, magnitude); + break; + case ESM::MagicEffect::DamageHealth: + case ESM::MagicEffect::DamageMagicka: + case ESM::MagicEffect::DamageFatigue: + receivedMagicDamage = true; + adjustDynamicStat(creatureStats, effectKey.mId-ESM::MagicEffect::DamageHealth, -magnitude); + break; + case ESM::MagicEffect::AbsorbHealth: + case ESM::MagicEffect::AbsorbMagicka: + case ESM::MagicEffect::AbsorbFatigue: + if (magnitude > 0.f) + receivedMagicDamage = true; + adjustDynamicStat(creatureStats, effectKey.mId-ESM::MagicEffect::AbsorbHealth, -magnitude); + break; + + case ESM::MagicEffect::DisintegrateArmor: + { + // According to UESP + int priorities[] = { + MWWorld::InventoryStore::Slot_CarriedLeft, + MWWorld::InventoryStore::Slot_Cuirass, + MWWorld::InventoryStore::Slot_LeftPauldron, + MWWorld::InventoryStore::Slot_RightPauldron, + MWWorld::InventoryStore::Slot_LeftGauntlet, + MWWorld::InventoryStore::Slot_RightGauntlet, + MWWorld::InventoryStore::Slot_Helmet, + MWWorld::InventoryStore::Slot_Greaves, + MWWorld::InventoryStore::Slot_Boots + }; + + for (unsigned int i=0; iisExterior()) + break; + float time = MWBase::Environment::get().getWorld()->getTimeStamp().getHour(); + float timeDiff = std::min(7.f, std::max(0.f, std::abs(time - 13))); + float damageScale = 1.f - timeDiff / 7.f; + // When cloudy, the sun damage effect is halved + static float fMagicSunBlockedMult = MWBase::Environment::get().getWorld()->getStore().get().find( + "fMagicSunBlockedMult")->getFloat(); + + int weather = MWBase::Environment::get().getWorld()->getCurrentWeather(); + if (weather > 1) + damageScale *= fMagicSunBlockedMult; + + adjustDynamicStat(creatureStats, 0, -magnitude * damageScale); + if (magnitude * damageScale > 0.f) + receivedMagicDamage = true; + break; + } + + case ESM::MagicEffect::FireDamage: + case ESM::MagicEffect::ShockDamage: + case ESM::MagicEffect::FrostDamage: + case ESM::MagicEffect::Poison: + { + adjustDynamicStat(creatureStats, 0, -magnitude); + receivedMagicDamage = true; + break; + } + + case ESM::MagicEffect::DamageSkill: + case ESM::MagicEffect::RestoreSkill: + { + if (!actor.getClass().isNpc()) + break; + NpcStats &npcStats = actor.getClass().getNpcStats(actor); + SkillValue& skill = npcStats.getSkill(effectKey.mArg); + if (effectKey.mId == ESM::MagicEffect::RestoreSkill) + skill.restore(magnitude); + else + skill.damage(magnitude); + break; + } + + } + + if (receivedMagicDamage && actor == MWBase::Environment::get().getWorld()->getPlayerPtr()) + MWBase::Environment::get().getWindowManager()->activateHitOverlay(false); + } + } diff --git a/apps/openmw/mwmechanics/spellcasting.hpp b/apps/openmw/mwmechanics/spellcasting.hpp index 2540b87db..418e9f56d 100644 --- a/apps/openmw/mwmechanics/spellcasting.hpp +++ b/apps/openmw/mwmechanics/spellcasting.hpp @@ -17,6 +17,7 @@ namespace MWMechanics { struct EffectKey; class MagicEffects; + class CreatureStats; ESM::Skill::SkillEnum spellSchoolToSkill(int school); @@ -60,6 +61,8 @@ namespace MWMechanics int getEffectiveEnchantmentCastCost (float castCost, const MWWorld::Ptr& actor); + void effectTick(CreatureStats& creatureStats, const MWWorld::Ptr& actor, const MWMechanics::EffectKey& effectKey, float magnitude); + class CastSpell { private: From cbc44b33ba01ae4aa4eac7386fcde048b7eeb613 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ji=C5=99=C3=AD=20Kune=C5=A1?= Date: Sat, 18 Jul 2015 21:29:38 +0200 Subject: [PATCH 1874/3725] define crosshair owned colour in openmw_hud_box.skin.xml --- AUTHORS.md | 2 +- apps/openmw/mwgui/hud.cpp | 6 ++---- apps/openmw/mwgui/tooltips.cpp | 2 +- files/mygui/openmw_hud.layout | 3 +-- files/mygui/openmw_hud_box.skin.xml | 19 +++++++++++++++++-- files/mygui/openmw_windows.skin.xml | 5 +++-- 6 files changed, 25 insertions(+), 12 deletions(-) diff --git a/AUTHORS.md b/AUTHORS.md index 7774b5afa..2bd96e3a1 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -52,6 +52,7 @@ Programmers jeaye Jeffrey Haines (Jyby) Jengerer + Jiří Kuneš (kunesj) Joel Graff (graffy) John Blomberg (fstp) Jordan Ayers @@ -59,7 +60,6 @@ Programmers Julien Voisin (jvoisin/ap0) Karl-Felix Glatzer (k1ll) Kevin Poitra (PuppyKevin) - kunesj Lars Söderberg (Lazaroth) lazydev Leon Saunders (emoose) diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 0f107f4e3..c8d8b61d5 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -521,15 +521,13 @@ namespace MWGui void HUD::setCrosshairOwned(bool owned) { - MyGUI::Colour red = MyGUI::Colour(1.0, 0, 0); - MyGUI::Colour white = MyGUI::Colour(1.0, 1.0, 1.0); if(owned) { - mCrosshair->setColour(red); + mCrosshair->changeWidgetSkin("HUD_Crosshair_Owned"); } else { - mCrosshair->setColour(white); + mCrosshair->changeWidgetSkin("HUD_Crosshair"); } } diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index a51c68acf..dbf27ad91 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -377,7 +377,7 @@ namespace MWGui { if(checkOwned()) { - mDynamicToolTipBox->changeWidgetSkin("HUD_Box_NoTransp_R"); + mDynamicToolTipBox->changeWidgetSkin("HUD_Box_NoTransp_Owned"); } else { diff --git a/files/mygui/openmw_hud.layout b/files/mygui/openmw_hud.layout index dd114097e..97b018469 100644 --- a/files/mygui/openmw_hud.layout +++ b/files/mygui/openmw_hud.layout @@ -122,8 +122,7 @@
    - - + diff --git a/files/mygui/openmw_hud_box.skin.xml b/files/mygui/openmw_hud_box.skin.xml index 7019351bd..dfe717c6f 100644 --- a/files/mygui/openmw_hud_box.skin.xml +++ b/files/mygui/openmw_hud_box.skin.xml @@ -32,16 +32,31 @@ - + - + + + + + + + + + + + + + + + +
    diff --git a/files/mygui/openmw_windows.skin.xml b/files/mygui/openmw_windows.skin.xml index 47f8cada8..c9a1f1ccc 100644 --- a/files/mygui/openmw_windows.skin.xml +++ b/files/mygui/openmw_windows.skin.xml @@ -129,9 +129,10 @@ - - + + + From a5b4e087c56518c6e0a75413f9c7f5cfa9f377a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ji=C5=99=C3=AD=20Kune=C5=A1?= Date: Sat, 18 Jul 2015 22:17:46 +0200 Subject: [PATCH 1875/3725] define owned colours in settings.cfg --- apps/openmw/mwgui/windowmanagerimp.cpp | 15 +++++++++++++-- files/mygui/openmw_hud_box.skin.xml | 2 +- files/mygui/openmw_windows.skin.xml | 3 +-- files/settings-default.cfg | 4 ++++ 4 files changed, 19 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 7b618efa7..0fe71632a 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1095,11 +1095,22 @@ namespace MWGui void WindowManager::onRetrieveTag(const MyGUI::UString& _tag, MyGUI::UString& _result) { std::string tag(_tag); + + std::string MyGuiPrefix = "setting="; + size_t MyGuiPrefixLength = MyGuiPrefix.length(); std::string tokenToFind = "sCell="; size_t tokenLength = tokenToFind.length(); - - if (tag.compare(0, tokenLength, tokenToFind) == 0) + + if(tag.compare(0, MyGuiPrefixLength, MyGuiPrefix) == 0) + { + tag = tag.substr(MyGuiPrefixLength, tag.length()); + std::string settingSection = tag.substr(0, tag.find(",")); + std::string settingTag = tag.substr(tag.find(",")+1, tag.length()); + + _result = Settings::Manager::getString(settingTag, settingSection); + } + else if (tag.compare(0, tokenLength, tokenToFind) == 0) { _result = mTranslationDataStorage.translateCellName(tag.substr(tokenLength)); } diff --git a/files/mygui/openmw_hud_box.skin.xml b/files/mygui/openmw_hud_box.skin.xml index dfe717c6f..33199d6ae 100644 --- a/files/mygui/openmw_hud_box.skin.xml +++ b/files/mygui/openmw_hud_box.skin.xml @@ -53,7 +53,7 @@ - + diff --git a/files/mygui/openmw_windows.skin.xml b/files/mygui/openmw_windows.skin.xml index c9a1f1ccc..682d89ebc 100644 --- a/files/mygui/openmw_windows.skin.xml +++ b/files/mygui/openmw_windows.skin.xml @@ -131,8 +131,7 @@ - - + diff --git a/files/settings-default.cfg b/files/settings-default.cfg index d84291a24..dcb9b8893 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -36,6 +36,10 @@ werewolf overlay = true stretch menu background = false +# colour definitions (red green blue alpha) +color background owned = 0.15 0 0 1 +color crosshair owned = 1 0.15 0.15 1 + [General] # Camera field of view field of view = 55 From 115666884308dca010d2ce60c8e40b25d0b88e9a Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 19 Jul 2015 00:45:02 +0200 Subject: [PATCH 1876/3725] Render certain map markers on top of the player arrow (Fixes #2559) --- apps/openmw/mwgui/mapwindow.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index d564dfcbc..e26c076e7 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -37,8 +37,8 @@ namespace enum LocalMapWidgetDepth { - Local_CompassLayer = 0, - Local_MarkerAboveFogLayer = 1, + Local_MarkerAboveFogLayer = 0, + Local_CompassLayer = 1, Local_FogLayer = 2, Local_MarkerLayer = 3, Local_MapLayer = 4 From b01abe4d19c32e15945c9193c032ca7a141f8df8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 19 Jul 2015 02:08:24 +0200 Subject: [PATCH 1877/3725] Stop title music when the game starts (Fixes #2468) --- apps/openmw/engine.cpp | 3 --- apps/openmw/mwmechanics/actors.cpp | 10 +++++----- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 001ce2750..8d25a923f 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -646,9 +646,6 @@ void OMW::Engine::go() prepareEngine (settings); - // Play some good 'ol tunes - MWBase::Environment::get().getSoundManager()->playPlaylist(std::string("Explore")); - if (!mSaveGameFile.empty()) { MWBase::Environment::get().getStateManager()->loadGame(mSaveGameFile); diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index d9a8ce72f..ee3f4b8f4 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1200,18 +1200,18 @@ namespace MWMechanics killDeadActors(); // check if we still have any player enemies to switch music - static bool isBattleMusic = false; + static int currentMusic = 0; - if (isBattleMusic && hostilesCount == 0 && !(player.getClass().getCreatureStats(player).isDead() && + if (currentMusic != 1 && hostilesCount == 0 && !(player.getClass().getCreatureStats(player).isDead() && MWBase::Environment::get().getSoundManager()->isMusicPlaying())) { MWBase::Environment::get().getSoundManager()->playPlaylist(std::string("Explore")); - isBattleMusic = false; + currentMusic = 1; } - else if (!isBattleMusic && hostilesCount > 0) + else if (currentMusic != 2 && hostilesCount > 0) { MWBase::Environment::get().getSoundManager()->playPlaylist(std::string("Battle")); - isBattleMusic = true; + currentMusic = 2; } static float sneakTimer = 0.f; // times update of sneak icon From 3ebe9fb34f99c59979adbb68df1d6621e5d9b931 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 19 Jul 2015 18:00:49 +1200 Subject: [PATCH 1878/3725] renamed mRotate to mTurnActorGivingGreetingToFacePlayer --- apps/openmw/mwmechanics/aiwander.cpp | 32 ++++++++++++++-------------- apps/openmw/mwmechanics/aiwander.hpp | 1 + 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 1375b5807..43fd67be1 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -51,10 +51,10 @@ namespace MWMechanics /// \brief This class holds the variables AiWander needs which are deleted if the package becomes inactive. struct AiWanderStorage : AiTemporaryBase { - // the z rotation angle (degrees) we want to reach - // used every frame when mRotate is true + // the z rotation angle to reach + // when mTurnActorGivingGreetingToFacePlayer is true float mTargetAngleRadians; - bool mRotate; + bool mTurnActorGivingGreetingToFacePlayer; float mReaction; // update some actions infrequently @@ -75,7 +75,7 @@ namespace MWMechanics AiWanderStorage(): mTargetAngleRadians(0), - mRotate(false), + mTurnActorGivingGreetingToFacePlayer(false), mReaction(0), mSaidGreeting(AiWander::Greet_None), mGreetingTimer(0), @@ -240,15 +240,13 @@ namespace MWMechanics evadeObstacles(actor, storage, duration); } - - float& targetAngleRadians = storage.mTargetAngleRadians; - bool& rotate = storage.mRotate; + bool& rotate = storage.mTurnActorGivingGreetingToFacePlayer; if (rotate) { // Reduce the turning animation glitch by using a *HUGE* value of // epsilon... TODO: a proper fix might be in either the physics or the // animation subsystem - if (zTurn(actor, targetAngleRadians, osg::DegreesToRadians(5.f))) + if (zTurn(actor, storage.mTargetAngleRadians, osg::DegreesToRadians(5.f))) rotate = false; } @@ -491,14 +489,7 @@ namespace MWMechanics getRandomIdle(storage.mPlayedIdle); } - if (!storage.mRotate) - { - osg::Vec3f dir = playerPos - actorPos; - - float faceAngleRadians = std::atan2(dir.x(), dir.y()); - storage.mTargetAngleRadians = faceAngleRadians; - storage.mRotate = true; - } + turnActorToFacePlayer(actorPos, playerPos, storage); if (greetingTimer >= GREETING_SHOULD_END) { @@ -515,6 +506,15 @@ namespace MWMechanics } } + void AiWander::turnActorToFacePlayer(const osg::Vec3f& actorPosition, const osg::Vec3f& playerPosition, AiWanderStorage& storage) + { + osg::Vec3f dir = playerPosition - actorPosition; + + float faceAngleRadians = std::atan2(dir.x(), dir.y()); + storage.mTargetAngleRadians = faceAngleRadians; + storage.mTurnActorGivingGreetingToFacePlayer = true; + } + void AiWander::setPathToAnAllowedNode(const MWWorld::Ptr& actor, AiWanderStorage& storage, const ESM::Position& actorPos) { unsigned int randNode = Misc::Rng::rollDice(mAllowedNodes.size()); diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 82baeedf3..d06887600 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -75,6 +75,7 @@ namespace MWMechanics void playGreetingIfPlayerGetsTooClose(const MWWorld::Ptr& actor, AiWanderStorage& storage); void evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration); void playIdleDialogueRandomly(const MWWorld::Ptr& actor); + void turnActorToFacePlayer(const osg::Vec3f& actorPosition, const osg::Vec3f& playerPosition, AiWanderStorage& storage); int mDistance; // how far the actor can wander from the spawn point int mDuration; From 1ed6e95c07d4eab8fb2e95eb980215695710ab64 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 19 Jul 2015 18:01:25 +1200 Subject: [PATCH 1879/3725] Got rid of some radians to degrees to radians conversions. --- apps/openmw/mwmechanics/aicombat.cpp | 8 ++++---- apps/openmw/mwmechanics/aipackage.cpp | 4 ++-- apps/openmw/mwmechanics/aiwander.cpp | 4 ++-- apps/openmw/mwmechanics/pathfinding.cpp | 2 +- apps/openmw/mwmechanics/pathfinding.hpp | 2 +- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 4eeea6f1f..6a39178ce 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -36,13 +36,13 @@ namespace float getZAngleToDir(const osg::Vec3f& dir) { - return osg::RadiansToDegrees(std::atan2(dir.x(), dir.y())); + return std::atan2(dir.x(), dir.y()); } float getXAngleToDir(const osg::Vec3f& dir, float dirLen = 0.0f) { float len = (dirLen > 0.0f)? dirLen : dir.length(); - return osg::RadiansToDegrees(-std::asin(dir.z() / len)); + return -std::asin(dir.z() / len); } @@ -221,12 +221,12 @@ namespace MWMechanics if(movement.mRotation[2] != 0) { - if(zTurn(actor, osg::DegreesToRadians(movement.mRotation[2]))) movement.mRotation[2] = 0; + if(zTurn(actor, movement.mRotation[2])) movement.mRotation[2] = 0; } if(movement.mRotation[0] != 0) { - if(smoothTurn(actor, osg::DegreesToRadians(movement.mRotation[0]), 0)) movement.mRotation[0] = 0; + if(smoothTurn(actor, movement.mRotation[0], 0)) movement.mRotation[0] = 0; } bool& attack = storage.mAttack; diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index 22c907588..0e68d9d79 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -104,7 +104,7 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, ESM::Pathgrid::Po actor.getClass().getMovementSettings(actor).mPosition[0] = 1; actor.getClass().getMovementSettings(actor).mPosition[1] = 1; // change the angle a bit, too - zTurn(actor, osg::DegreesToRadians(mPathFinder.getZAngleToNext(pos.pos[0] + 1, pos.pos[1]))); + zTurn(actor, mPathFinder.getZAngleToNext(pos.pos[0] + 1, pos.pos[1])); } } else { //Not stuck, so reset things @@ -117,7 +117,7 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, ESM::Pathgrid::Po actor.getClass().getMovementSettings(actor).mPosition[1] = 1; //Just run forward the rest of the time } - zTurn(actor, osg::DegreesToRadians(mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]))); + zTurn(actor, mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1])); return false; } diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 43fd67be1..9f50d07b4 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -234,7 +234,7 @@ namespace MWMechanics if(walking) // have not yet reached the destination { // turn towards the next point in mPath - zTurn(actor, osg::DegreesToRadians(storage.mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]))); + zTurn(actor, storage.mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1])); actor.getClass().getMovementSettings(actor).mPosition[1] = 1; evadeObstacles(actor, storage, duration); @@ -397,7 +397,7 @@ namespace MWMechanics actor.getClass().getMovementSettings(actor).mPosition[1] = 0.1f; // change the angle a bit, too const ESM::Position& pos = actor.getRefData().getPosition(); - zTurn(actor, osg::DegreesToRadians(storage.mPathFinder.getZAngleToNext(pos.pos[0] + 1, pos.pos[1]))); + zTurn(actor, storage.mPathFinder.getZAngleToNext(pos.pos[0] + 1, pos.pos[1])); } mStuckCount++; // TODO: maybe no longer needed } diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index 3c1a40fe0..79cee9f32 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -264,7 +264,7 @@ namespace MWMechanics float directionX = nextPoint.mX - x; float directionY = nextPoint.mY - y; - return osg::RadiansToDegrees(std::atan2(directionX, directionY)); + return std::atan2(directionX, directionY); } bool PathFinder::checkPathCompleted(float x, float y, float tolerance) diff --git a/apps/openmw/mwmechanics/pathfinding.hpp b/apps/openmw/mwmechanics/pathfinding.hpp index a4886a840..4000f5d80 100644 --- a/apps/openmw/mwmechanics/pathfinding.hpp +++ b/apps/openmw/mwmechanics/pathfinding.hpp @@ -40,7 +40,7 @@ namespace MWMechanics bool checkPathCompleted(float x, float y, float tolerance = PathTolerance); ///< \Returns true if we are within \a tolerance units of the last path point. - /// In degrees + /// In radians float getZAngleToNext(float x, float y) const; bool isPathConstructed() const From 22f49128ccb2a6e12a36fb31f992155a6a967c38 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 19 Jul 2015 18:02:13 +1200 Subject: [PATCH 1880/3725] replaced multiple booleans with single state variable. --- apps/openmw/mwmechanics/aiwander.cpp | 65 ++++++++++------------------ apps/openmw/mwmechanics/aiwander.hpp | 7 +++ 2 files changed, 29 insertions(+), 43 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 9f50d07b4..fc730cc89 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -64,10 +64,7 @@ namespace MWMechanics const MWWorld::CellStore* mCell; // for detecting cell change // AiWander states - bool mChooseAction; - bool mIdleNow; - bool mMoveNow; - bool mWalking; + AiWander::WanderState mState; unsigned short mPlayedIdle; @@ -80,10 +77,7 @@ namespace MWMechanics mSaidGreeting(AiWander::Greet_None), mGreetingTimer(0), mCell(NULL), - mChooseAction(true), - mIdleNow(false), - mMoveNow(false), - mWalking(false), + mState(AiWander::Wander_ChooseAction), mPlayedIdle(0) {}; }; @@ -200,38 +194,33 @@ namespace MWMechanics ESM::Position pos = actor.getRefData().getPosition(); - bool& idleNow = storage.mIdleNow; - bool& moveNow = storage.mMoveNow; - bool& walking = storage.mWalking; + WanderState& wanderState = storage.mState; // Check if an idle actor is too close to a door - if so start walking mDoorCheckDuration += duration; if(mDoorCheckDuration >= DOOR_CHECK_INTERVAL) { mDoorCheckDuration = 0; // restart timer if(mDistance && // actor is not intended to be stationary - idleNow && // but is in idle - !walking && // FIXME: some actors are idle while walking + (wanderState == Wander_IdleNow) && // but is in idle proximityToDoor(actor, MIN_DIST_TO_DOOR_SQUARED*1.6f*1.6f)) // NOTE: checks interior cells only { - idleNow = false; - moveNow = true; + wanderState = Wander_MoveNow; mTrimCurrentNode = false; // just in case } } // Are we there yet? - bool& chooseAction = storage.mChooseAction; - if(walking && + if ((wanderState == Wander_Walking) && storage.mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], DESTINATION_TOLERANCE)) { stopWalking(actor, storage); - chooseAction = true; + wanderState = Wander_ChooseAction; mHasReturnPosition = false; } - if(walking) // have not yet reached the destination + if (wanderState == Wander_Walking) // have not yet reached the destination { // turn towards the next point in mPath zTurn(actor, storage.mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1])); @@ -253,24 +242,23 @@ namespace MWMechanics // Check if idle animation finished short unsigned& playedIdle = storage.mPlayedIdle; GreetingState& greetingState = storage.mSaidGreeting; - if(idleNow && !checkIdle(actor, playedIdle) && (greetingState == Greet_Done || greetingState == Greet_None)) + if ((wanderState == Wander_IdleNow) && + !checkIdle(actor, playedIdle) && (greetingState == Greet_Done || greetingState == Greet_None)) { playedIdle = 0; - idleNow = false; - chooseAction = true; + wanderState = Wander_ChooseAction; } MWBase::World *world = MWBase::Environment::get().getWorld(); - if(chooseAction) + if (wanderState == Wander_ChooseAction) { playedIdle = 0; getRandomIdle(playedIdle); // NOTE: sets mPlayedIdle with a random selection if(!playedIdle && mDistance) { - chooseAction = false; - moveNow = true; + wanderState = Wander_MoveNow; } else { @@ -278,8 +266,7 @@ namespace MWMechanics MWWorld::TimeStamp currentTime = world->getTimeStamp(); mStartTime = currentTime; playIdle(actor, playedIdle); - chooseAction = false; - idleNow = true; + wanderState = Wander_IdleNow; } } @@ -332,9 +319,6 @@ namespace MWMechanics mHasReturnPosition = false; if (mDistance == 0 && mHasReturnPosition && (pos.asVec3() - mReturnPosition).length2() > 20*20) { - chooseAction = false; - idleNow = false; - if (!storage.mPathFinder.isPathConstructed()) { ESM::Pathgrid::Point dest(PathFinder::MakePathgridPoint(mReturnPosition)); @@ -347,19 +331,18 @@ namespace MWMechanics if(storage.mPathFinder.isPathConstructed()) { - moveNow = false; - walking = true; + wanderState = Wander_Walking; } } } // Allow interrupting a walking actor to trigger a greeting - if(idleNow || walking) + if ((wanderState == Wander_IdleNow) || (wanderState == Wander_Walking)) { playGreetingIfPlayerGetsTooClose(actor, storage); } - if(moveNow && mDistance) + if ((wanderState == Wander_MoveNow) && mDistance) { // Construct a new path if there isn't one if(!storage.mPathFinder.isPathConstructed()) @@ -386,8 +369,7 @@ namespace MWMechanics trimAllowedNodes(mAllowedNodes, storage.mPathFinder); mObstacleCheck.clear(); storage.mPathFinder.clearPath(); - storage.mWalking = false; - storage.mMoveNow = true; + storage.mState = Wander_MoveNow; } else // probably walking into another NPC { @@ -409,7 +391,7 @@ namespace MWMechanics mObstacleCheck.clear(); stopWalking(actor, storage); - storage.mChooseAction = true; + storage.mState = Wander_ChooseAction; mStuckCount = 0; } //#endif @@ -481,11 +463,11 @@ namespace MWMechanics { greetingTimer++; - if (storage.mWalking) + if (storage.mState == Wander_Walking) { stopWalking(actor, storage); mObstacleCheck.clear(); - storage.mIdleNow = true; + storage.mState = Wander_IdleNow; getRandomIdle(storage.mPlayedIdle); } @@ -539,8 +521,7 @@ namespace MWMechanics mAllowedNodes.push_back(mCurrentNode); mCurrentNode = temp; - storage.mMoveNow = false; - storage.mWalking = true; + storage.mState = Wander_Walking; } // Choose a different node and delete this one from possible nodes because it is uncreachable: else @@ -591,8 +572,6 @@ namespace MWMechanics { storage.mPathFinder.clearPath(); actor.getClass().getMovementSettings(actor).mPosition[1] = 0; - storage.mMoveNow = false; - storage.mWalking = false; } void AiWander::playIdle(const MWWorld::Ptr& actor, unsigned short idleSelect) diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index d06887600..8a4921b83 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -63,6 +63,13 @@ namespace MWMechanics Greet_InProgress, Greet_Done }; + + enum WanderState { + Wander_ChooseAction, + Wander_IdleNow, + Wander_MoveNow, + Wander_Walking, + }; private: // NOTE: mDistance and mDuration must be set already void init(); From 00eef585afde4b0a2ef532a06a82938d7cc1d43c Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 19 Jul 2015 18:04:42 +1200 Subject: [PATCH 1881/3725] renamed mPlayedIdle to mIdleAnimation. --- apps/openmw/mwmechanics/aiwander.cpp | 23 +++++++++++------------ apps/openmw/mwmechanics/aiwander.hpp | 2 +- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index fc730cc89..5c9949a5a 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -66,7 +66,7 @@ namespace MWMechanics // AiWander states AiWander::WanderState mState; - unsigned short mPlayedIdle; + unsigned short mIdleAnimation; PathFinder mPathFinder; @@ -78,7 +78,7 @@ namespace MWMechanics mGreetingTimer(0), mCell(NULL), mState(AiWander::Wander_ChooseAction), - mPlayedIdle(0) + mIdleAnimation(0) {}; }; @@ -240,12 +240,11 @@ namespace MWMechanics } // Check if idle animation finished - short unsigned& playedIdle = storage.mPlayedIdle; + short unsigned& idleAnimation = storage.mIdleAnimation; GreetingState& greetingState = storage.mSaidGreeting; if ((wanderState == Wander_IdleNow) && - !checkIdle(actor, playedIdle) && (greetingState == Greet_Done || greetingState == Greet_None)) + !checkIdle(actor, idleAnimation) && (greetingState == Greet_Done || greetingState == Greet_None)) { - playedIdle = 0; wanderState = Wander_ChooseAction; } @@ -253,10 +252,9 @@ namespace MWMechanics if (wanderState == Wander_ChooseAction) { - playedIdle = 0; - getRandomIdle(playedIdle); // NOTE: sets mPlayedIdle with a random selection + idleAnimation = getRandomIdle(); - if(!playedIdle && mDistance) + if(!idleAnimation && mDistance) { wanderState = Wander_MoveNow; } @@ -265,7 +263,7 @@ namespace MWMechanics // Play idle animation and recreate vanilla (broken?) behavior of resetting start time of AIWander: MWWorld::TimeStamp currentTime = world->getTimeStamp(); mStartTime = currentTime; - playIdle(actor, playedIdle); + playIdle(actor, idleAnimation); wanderState = Wander_IdleNow; } } @@ -468,7 +466,6 @@ namespace MWMechanics stopWalking(actor, storage); mObstacleCheck.clear(); storage.mState = Wander_IdleNow; - getRandomIdle(storage.mPlayedIdle); } turnActorToFacePlayer(actorPos, playerPos, storage); @@ -605,9 +602,10 @@ namespace MWMechanics } } - void AiWander::getRandomIdle(short unsigned& playedIdle) + short unsigned AiWander::getRandomIdle() { unsigned short idleRoll = 0; + short unsigned selectedAnimation = 0; for(unsigned int counter = 0; counter < mIdle.size(); counter++) { @@ -618,10 +616,11 @@ namespace MWMechanics unsigned short randSelect = (int)(Misc::Rng::rollProbability() * int(100 / fIdleChanceMultiplier)); if(randSelect < idleChance && randSelect > idleRoll) { - playedIdle = counter+2; + selectedAnimation = counter + GroupIndex_MinIdle; idleRoll = randSelect; } } + return selectedAnimation; } void AiWander::fastForward(const MWWorld::Ptr& actor, AiState &state) diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 8a4921b83..df389a34e 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -77,7 +77,7 @@ namespace MWMechanics void stopWalking(const MWWorld::Ptr& actor, AiWanderStorage& storage); void playIdle(const MWWorld::Ptr& actor, unsigned short idleSelect); bool checkIdle(const MWWorld::Ptr& actor, unsigned short idleSelect); - void getRandomIdle(unsigned short& playedIdle); + short unsigned getRandomIdle(); void setPathToAnAllowedNode(const MWWorld::Ptr& actor, AiWanderStorage& storage, const ESM::Position& actorPos); void playGreetingIfPlayerGetsTooClose(const MWWorld::Ptr& actor, AiWanderStorage& storage); void evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration); From ad353e6dd0b41e388e2ec3fbcc4bf15d1ef71e57 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Thu, 16 Jul 2015 19:52:31 +0300 Subject: [PATCH 1882/3725] Refine DELE handling in ESM records. Add position-independent DELE search --- components/esm/cellref.cpp | 126 +++++++++++++--------- components/esm/esmreader.cpp | 5 + components/esm/esmreader.hpp | 3 + components/esm/loadacti.cpp | 23 ++-- components/esm/loadalch.cpp | 28 +++-- components/esm/loadappa.cpp | 27 +++-- components/esm/loadarmo.cpp | 26 +++-- components/esm/loadbody.cpp | 24 +++-- components/esm/loadbook.cpp | 25 +++-- components/esm/loadbsgn.cpp | 20 +++- components/esm/loadclas.cpp | 25 +++-- components/esm/loadclot.cpp | 26 +++-- components/esm/loadcont.cpp | 32 ++++-- components/esm/loadcrea.cpp | 33 ++++-- components/esm/loaddial.cpp | 46 +++++--- components/esm/loaddoor.cpp | 23 ++-- components/esm/loadench.cpp | 25 +++-- components/esm/loadfact.cpp | 28 +++-- components/esm/loadglob.cpp | 29 +++-- components/esm/loadinfo.cpp | 189 +++++++++++++-------------------- components/esm/loadinfo.hpp | 3 +- components/esm/loadingr.cpp | 24 +++-- components/esm/loadlevlist.cpp | 85 +++++++++------ components/esm/loadligh.cpp | 25 +++-- components/esm/loadlock.cpp | 26 +++-- components/esm/loadltex.cpp | 43 ++++++-- components/esm/loadmisc.cpp | 27 +++-- components/esm/loadnpc.cpp | 34 +++--- components/esm/loadprob.cpp | 27 +++-- components/esm/loadregn.cpp | 101 ++++++++++++------ components/esm/loadrepa.cpp | 27 +++-- components/esm/loadscpt.cpp | 29 +++-- components/esm/loadsndg.cpp | 38 ++++--- components/esm/loadsoun.cpp | 27 +++-- components/esm/loadspel.cpp | 30 ++++-- components/esm/loadstat.cpp | 39 +++++-- components/esm/loadweap.cpp | 24 +++-- 37 files changed, 857 insertions(+), 515 deletions(-) diff --git a/components/esm/cellref.cpp b/components/esm/cellref.cpp index e43a37b66..c6fb899b3 100644 --- a/components/esm/cellref.cpp +++ b/components/esm/cellref.cpp @@ -3,7 +3,6 @@ #include "esmreader.hpp" #include "esmwriter.hpp" -#include "util.hpp" ESM::CellRef::CellRef() : mScale(1.0f), @@ -38,7 +37,6 @@ void ESM::RefNum::save (ESMWriter &esm, bool wide, const std::string& tag) const void ESM::CellRef::load (ESMReader& esm, bool wideRefNum) { - mIsDeleted = false; loadId(esm, wideRefNum); loadData(esm); } @@ -55,62 +53,90 @@ void ESM::CellRef::loadId (ESMReader& esm, bool wideRefNum) mRefNum.load (esm, wideRefNum); mRefID = esm.getHNString ("NAME"); + mIsDeleted = false; } void ESM::CellRef::loadData(ESMReader &esm) { - // Again, UNAM sometimes appears after NAME and sometimes later. - // Or perhaps this UNAM means something different? - mReferenceBlocked = -1; - esm.getHNOT (mReferenceBlocked, "UNAM"); - - mScale = 1.0; - esm.getHNOT (mScale, "XSCL"); - - mOwner = esm.getHNOString ("ANAM"); - mGlobalVariable = esm.getHNOString ("BNAM"); - mSoul = esm.getHNOString ("XSOL"); - - mFaction = esm.getHNOString ("CNAM"); + mScale = 1.0f; mFactionRank = -2; - esm.getHNOT (mFactionRank, "INDX"); - - mGoldValue = 1; mChargeInt = -1; mEnchantmentCharge = -1; + mGoldValue = 1; + mLockLevel = 0; + mReferenceBlocked = -1; + mTeleport = false; + mIsDeleted = false; - esm.getHNOT (mEnchantmentCharge, "XCHG"); - - esm.getHNOT (mChargeInt, "INTV"); - - esm.getHNOT (mGoldValue, "NAM9"); - - // Present for doors that teleport you to another cell. - if (esm.isNextSub ("DODT")) + bool isLoaded = false; + while (!isLoaded && esm.hasMoreSubs()) { - mTeleport = true; - esm.getHT (mDoorDest); - mDestCell = esm.getHNOString ("DNAM"); + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'U','N','A','M'>::value: + esm.getHT(mReferenceBlocked); + break; + case ESM::FourCC<'X','S','C','L'>::value: + esm.getHT(mScale); + break; + case ESM::FourCC<'A','N','A','M'>::value: + mOwner = esm.getHString(); + break; + case ESM::FourCC<'B','N','A','M'>::value: + mGlobalVariable = esm.getHString(); + break; + case ESM::FourCC<'X','S','O','L'>::value: + mSoul = esm.getHString(); + break; + case ESM::FourCC<'C','N','A','M'>::value: + mFaction = esm.getHString(); + break; + case ESM::FourCC<'I','N','D','X'>::value: + esm.getHT(mFactionRank); + break; + case ESM::FourCC<'X','C','H','G'>::value: + esm.getHT(mEnchantmentCharge); + break; + case ESM::FourCC<'I','N','T','V'>::value: + esm.getHT(mChargeInt); + break; + case ESM::FourCC<'N','A','M','9'>::value: + esm.getHT(mGoldValue); + break; + case ESM::FourCC<'D','O','D','T'>::value: + esm.getHT(mDoorDest); + mTeleport = true; + break; + case ESM::FourCC<'D','N','A','M'>::value: + mDestCell = esm.getHString(); + break; + case ESM::FourCC<'F','L','T','V'>::value: + esm.getHT(mLockLevel); + break; + case ESM::FourCC<'K','N','A','M'>::value: + mKey = esm.getHString(); + break; + case ESM::FourCC<'T','N','A','M'>::value: + mTrap = esm.getHString(); + break; + case ESM::FourCC<'D','A','T','A'>::value: + esm.getHT(mPos, 24); + break; + case ESM::FourCC<'N','A','M','0'>::value: + esm.skipHSub(); + break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + mIsDeleted = true; + break; + default: + esm.cacheSubName(); + isLoaded = true; + break; + } } - else - mTeleport = false; - - mLockLevel = 0; //Set to 0 to indicate no lock - esm.getHNOT (mLockLevel, "FLTV"); - - mKey = esm.getHNOString ("KNAM"); - mTrap = esm.getHNOString ("TNAM"); - - esm.getHNOT (mReferenceBlocked, "UNAM"); - if (esm.isNextSub("FLTV")) // no longer used - esm.skipHSub(); - - esm.getHNOT(mPos, "DATA", 24); - - if (esm.isNextSub("NAM0")) - esm.skipHSub(); - - mIsDeleted = readDeleSubRecord (esm); } void ESM::CellRef::save (ESMWriter &esm, bool wideRefNum, bool inInventory) const @@ -149,7 +175,7 @@ void ESM::CellRef::save (ESMWriter &esm, bool wideRefNum, bool inInventory) cons } if (!inInventory && mLockLevel != 0) { - esm.writeHNT("FLTV", mLockLevel); + esm.writeHNT("FLTV", mLockLevel); } if (!inInventory) @@ -166,7 +192,7 @@ void ESM::CellRef::save (ESMWriter &esm, bool wideRefNum, bool inInventory) cons if (mIsDeleted) { - writeDeleSubRecord(esm); + esm.writeHNCString("DELE", ""); } } diff --git a/components/esm/esmreader.cpp b/components/esm/esmreader.cpp index 4be334970..1bf176842 100644 --- a/components/esm/esmreader.cpp +++ b/components/esm/esmreader.cpp @@ -187,6 +187,11 @@ bool ESMReader::peekNextSub(const char *name) return mCtx.subName == name; } +void ESMReader::cacheSubName() +{ + mCtx.subCached = true; +} + // Read subrecord name. This gets called a LOT, so I've optimized it // slightly. void ESMReader::getSubName() diff --git a/components/esm/esmreader.hpp b/components/esm/esmreader.hpp index c3e6bbbd3..4772aeb6f 100644 --- a/components/esm/esmreader.hpp +++ b/components/esm/esmreader.hpp @@ -185,6 +185,9 @@ public: bool peekNextSub(const char* name); + // Store the current subrecord name for the next call of getSubName() + void cacheSubName(); + // Read subrecord name. This gets called a LOT, so I've optimized it // slightly. void getSubName(); diff --git a/components/esm/loadacti.cpp b/components/esm/loadacti.cpp index 14a3abe54..c32cea1a6 100644 --- a/components/esm/loadacti.cpp +++ b/components/esm/loadacti.cpp @@ -3,7 +3,6 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" -#include "util.hpp" namespace ESM { @@ -15,18 +14,23 @@ namespace ESM void Activator::load(ESMReader &esm) { - mId = esm.getHNString("NAME"); - if (mIsDeleted = readDeleSubRecord(esm)) - { - return; - } + mIsDeleted = false; + bool hasName = false; while (esm.hasMoreSubs()) { esm.getSubName(); uint32_t name = esm.retSubName().val; switch (name) { + case ESM::FourCC<'N','A','M','E'>::value: + mId = esm.getHString(); + hasName = true; + break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + mIsDeleted = true; + break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; @@ -38,15 +42,20 @@ namespace ESM break; default: esm.fail("Unknown subrecord"); + break; } } + + if (!hasName) + esm.fail("Missing NAME subrecord"); } void Activator::save(ESMWriter &esm) const { esm.writeHNCString("NAME", mId); + if (mIsDeleted) { - writeDeleSubRecord(esm); + esm.writeHNCString("DELE", ""); return; } diff --git a/components/esm/loadalch.cpp b/components/esm/loadalch.cpp index 5faeb99e1..c1213583d 100644 --- a/components/esm/loadalch.cpp +++ b/components/esm/loadalch.cpp @@ -3,7 +3,6 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" -#include "util.hpp" namespace ESM { @@ -16,13 +15,9 @@ namespace ESM void Potion::load(ESMReader &esm) { mEffects.mList.clear(); + mIsDeleted = false; - mId = esm.getHNString("NAME"); - if (mIsDeleted = readDeleSubRecord(esm)) - { - return; - } - + bool hasName = false; bool hasData = false; while (esm.hasMoreSubs()) { @@ -30,6 +25,14 @@ namespace ESM uint32_t name = esm.retSubName().val; switch (name) { + case ESM::FourCC<'N','A','M','E'>::value: + mId = esm.getHString(); + hasName = true; + break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + mIsDeleted = true; + break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; @@ -51,17 +54,22 @@ namespace ESM break; default: esm.fail("Unknown subrecord"); + break; } } - if (!hasData) - esm.fail("Missing ALDT"); + + if (!hasName) + esm.fail("Missing NAME subrecord"); + if (!hasData && !mIsDeleted) + esm.fail("Missing ALDT subrecord"); } void Potion::save(ESMWriter &esm) const { esm.writeHNCString("NAME", mId); + if (mIsDeleted) { - writeDeleSubRecord(esm); + esm.writeHNCString("DELE", ""); return; } diff --git a/components/esm/loadappa.cpp b/components/esm/loadappa.cpp index ea375aa7f..edf1f473b 100644 --- a/components/esm/loadappa.cpp +++ b/components/esm/loadappa.cpp @@ -3,7 +3,6 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" -#include "util.hpp" namespace ESM { @@ -15,12 +14,9 @@ namespace ESM void Apparatus::load(ESMReader &esm) { - mId = esm.getHNString("NAME"); - if (mIsDeleted = readDeleSubRecord(esm)) - { - return; - } + mIsDeleted = false; + bool hasName = false; bool hasData = false; while (esm.hasMoreSubs()) { @@ -28,6 +24,14 @@ namespace ESM uint32_t name = esm.retSubName().val; switch (name) { + case ESM::FourCC<'N','A','M','E'>::value: + mId = esm.getHString(); + hasName = true; + break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + mIsDeleted = true; + break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; @@ -46,18 +50,23 @@ namespace ESM break; default: esm.fail("Unknown subrecord"); + break; } } - if (!hasData) - esm.fail("Missing AADT"); + + if (!hasName) + esm.fail("Missing NAME subrecord"); + if (!hasData && !mIsDeleted) + esm.fail("Missing AADT subrecord"); } void Apparatus::save(ESMWriter &esm) const { esm.writeHNCString("NAME", mId); + if (mIsDeleted) { - writeDeleSubRecord(esm); + esm.writeHNCString("DELE", ""); return; } diff --git a/components/esm/loadarmo.cpp b/components/esm/loadarmo.cpp index d23a71cac..d5b9fdd44 100644 --- a/components/esm/loadarmo.cpp +++ b/components/esm/loadarmo.cpp @@ -3,7 +3,6 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" -#include "util.hpp" namespace ESM { @@ -46,13 +45,9 @@ namespace ESM void Armor::load(ESMReader &esm) { mParts.mParts.clear(); + mIsDeleted = false; - mId = esm.getHNString("NAME"); - if (mIsDeleted = readDeleSubRecord(esm)) - { - return; - } - + bool hasName = false; bool hasData = false; while (esm.hasMoreSubs()) { @@ -60,6 +55,14 @@ namespace ESM uint32_t name = esm.retSubName().val; switch (name) { + case ESM::FourCC<'N','A','M','E'>::value: + mId = esm.getHString(); + hasName = true; + break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + mIsDeleted = true; + break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; @@ -84,18 +87,23 @@ namespace ESM break; default: esm.fail("Unknown subrecord"); + break; } } - if (!hasData) + + if (!hasName) + esm.fail("Missing NAME subrecord"); + if (!hasData && !mIsDeleted) esm.fail("Missing CTDT subrecord"); } void Armor::save(ESMWriter &esm) const { esm.writeHNCString("NAME", mId); + if (mIsDeleted) { - writeDeleSubRecord(esm); + esm.writeHNCString("DELE", ""); return; } diff --git a/components/esm/loadbody.cpp b/components/esm/loadbody.cpp index e0ebfd539..e2c6ad7b2 100644 --- a/components/esm/loadbody.cpp +++ b/components/esm/loadbody.cpp @@ -3,7 +3,6 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" -#include "util.hpp" namespace ESM { @@ -15,12 +14,9 @@ namespace ESM void BodyPart::load(ESMReader &esm) { - mId = esm.getHNString("NAME"); - if (mIsDeleted = readDeleSubRecord(esm)) - { - return; - } + mIsDeleted = false; + bool hasName = false; bool hasData = false; while (esm.hasMoreSubs()) { @@ -28,6 +24,14 @@ namespace ESM uint32_t name = esm.retSubName().val; switch (name) { + case ESM::FourCC<'N','A','M','E'>::value: + mId = esm.getHString(); + hasName = true; + break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + mIsDeleted = true; + break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; @@ -40,19 +44,23 @@ namespace ESM break; default: esm.fail("Unknown subrecord"); + break; } } - if (!hasData) + if (!hasName) + esm.fail("Missing NAME subrecord"); + if (!hasData && !mIsDeleted) esm.fail("Missing BYDT subrecord"); } void BodyPart::save(ESMWriter &esm) const { esm.writeHNCString("NAME", mId); + if (mIsDeleted) { - writeDeleSubRecord(esm); + esm.writeHNCString("DELE", ""); return; } diff --git a/components/esm/loadbook.cpp b/components/esm/loadbook.cpp index 2824b6200..2d0d3ce75 100644 --- a/components/esm/loadbook.cpp +++ b/components/esm/loadbook.cpp @@ -3,7 +3,6 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" -#include "util.hpp" namespace ESM { @@ -15,12 +14,9 @@ namespace ESM void Book::load(ESMReader &esm) { - mId = esm.getHNString("NAME"); - if (mIsDeleted = readDeleSubRecord(esm)) - { - return; - } + mIsDeleted = false; + bool hasName = false; bool hasData = false; while (esm.hasMoreSubs()) { @@ -28,6 +24,14 @@ namespace ESM uint32_t name = esm.retSubName().val; switch (name) { + case ESM::FourCC<'N','A','M','E'>::value: + mId = esm.getHString(); + hasName = true; + break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + mIsDeleted = true; + break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; @@ -52,17 +56,22 @@ namespace ESM break; default: esm.fail("Unknown subrecord"); + break; } } - if (!hasData) + + if (!hasName) + esm.fail("Missing NAME subrecord"); + if (!hasData && !mIsDeleted) esm.fail("Missing BKDT subrecord"); } void Book::save(ESMWriter &esm) const { esm.writeHNCString("NAME", mId); + if (mIsDeleted) { - writeDeleSubRecord(esm); + esm.writeHNCString("DELE", ""); return; } diff --git a/components/esm/loadbsgn.cpp b/components/esm/loadbsgn.cpp index 8cdeed3f6..9f5cd7270 100644 --- a/components/esm/loadbsgn.cpp +++ b/components/esm/loadbsgn.cpp @@ -16,16 +16,23 @@ namespace ESM void BirthSign::load(ESMReader &esm) { mPowers.mList.clear(); + mIsDeleted = false; - mIsDeleted = readDeleSubRecord(esm); - mId = esm.getHNString("NAME"); - + bool hasName = false; while (esm.hasMoreSubs()) { esm.getSubName(); uint32_t name = esm.retSubName().val; switch (name) { + case ESM::FourCC<'N','A','M','E'>::value: + mId = esm.getHString(); + hasName = true; + break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + mIsDeleted = true; + break; case ESM::FourCC<'F','N','A','M'>::value: mName = esm.getHString(); break; @@ -40,16 +47,21 @@ namespace ESM break; default: esm.fail("Unknown subrecord"); + break; } } + + if (!hasName) + esm.fail("Missing NAME subrecord"); } void BirthSign::save(ESMWriter &esm) const { if (mIsDeleted) { - writeDeleSubRecord(esm); + esm.writeHNCString("DELE", ""); } + esm.writeHNCString("NAME", mId); esm.writeHNOCString("FNAM", mName); esm.writeHNOCString("TNAM", mTexture); diff --git a/components/esm/loadclas.cpp b/components/esm/loadclas.cpp index 1384a6280..b58c35d90 100644 --- a/components/esm/loadclas.cpp +++ b/components/esm/loadclas.cpp @@ -5,7 +5,6 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" -#include "util.hpp" namespace ESM { @@ -45,12 +44,9 @@ namespace ESM void Class::load(ESMReader &esm) { - mId = esm.getHNString("NAME"); - if (mIsDeleted = readDeleSubRecord(esm)) - { - return; - } + mIsDeleted = false; + bool hasName = false; bool hasData = false; while (esm.hasMoreSubs()) { @@ -58,6 +54,14 @@ namespace ESM uint32_t name = esm.retSubName().val; switch (name) { + case ESM::FourCC<'N','A','M','E'>::value: + mId = esm.getHString(); + hasName = true; + break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + mIsDeleted = true; + break; case ESM::FourCC<'F','N','A','M'>::value: mName = esm.getHString(); break; @@ -72,17 +76,22 @@ namespace ESM break; default: esm.fail("Unknown subrecord"); + break; } } - if (!hasData) + + if (!hasName) + esm.fail("Missing NAME subrecord"); + if (!hasData && !mIsDeleted) esm.fail("Missing CLDT subrecord"); } void Class::save(ESMWriter &esm) const { esm.writeHNCString("NAME", mId); + if (mIsDeleted) { - writeDeleSubRecord(esm); + esm.writeHNCString("DELE", ""); return; } diff --git a/components/esm/loadclot.cpp b/components/esm/loadclot.cpp index 88f2e5715..18f7cd44f 100644 --- a/components/esm/loadclot.cpp +++ b/components/esm/loadclot.cpp @@ -3,7 +3,6 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" -#include "util.hpp" namespace ESM { @@ -16,13 +15,9 @@ namespace ESM void Clothing::load(ESMReader &esm) { mParts.mParts.clear(); + mIsDeleted = false; - mId = esm.getHNString("NAME"); - if (mIsDeleted = readDeleSubRecord(esm)) - { - return; - } - + bool hasName = false; bool hasData = false; while (esm.hasMoreSubs()) { @@ -30,6 +25,14 @@ namespace ESM uint32_t name = esm.retSubName().val; switch (name) { + case ESM::FourCC<'N','A','M','E'>::value: + mId = esm.getHString(); + hasName = true; + break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + mIsDeleted = true; + break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; @@ -54,18 +57,23 @@ namespace ESM break; default: esm.fail("Unknown subrecord"); + break; } } - if (!hasData) + + if (!hasName) + esm.fail("Missing NAME subrecord"); + if (!hasData && !mIsDeleted) esm.fail("Missing CTDT subrecord"); } void Clothing::save(ESMWriter &esm) const { esm.writeHNCString("NAME", mId); + if (mIsDeleted) { - writeDeleSubRecord(esm); + esm.writeHNCString("DELE", ""); return; } diff --git a/components/esm/loadcont.cpp b/components/esm/loadcont.cpp index 3d3d7fced..fadfe5f0f 100644 --- a/components/esm/loadcont.cpp +++ b/components/esm/loadcont.cpp @@ -3,7 +3,6 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" -#include "util.hpp" namespace ESM { @@ -26,19 +25,17 @@ namespace ESM unsigned int Container::sRecordId = REC_CONT; Container::Container() - : mIsDeleted(false) + : mWeight(0), + mFlags(0x8), + mIsDeleted(false) {} void Container::load(ESMReader &esm) { mInventory.mList.clear(); + mIsDeleted = false; - mId = esm.getHNString("NAME"); - if (mIsDeleted = readDeleSubRecord(esm)) - { - return; - } - + bool hasName = false; bool hasWeight = false; bool hasFlags = false; while (esm.hasMoreSubs()) @@ -47,6 +44,14 @@ namespace ESM uint32_t name = esm.retSubName().val; switch (name) { + case ESM::FourCC<'N','A','M','E'>::value: + mId = esm.getHString(); + hasName = true; + break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + mIsDeleted = true; + break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; @@ -73,20 +78,25 @@ namespace ESM break; default: esm.fail("Unknown subrecord"); + break; } } - if (!hasWeight) + + if (!hasName) + esm.fail("Missing NAME subrecord"); + if (!hasWeight && !mIsDeleted) esm.fail("Missing CNDT subrecord"); - if (!hasFlags) + if (!hasFlags && !mIsDeleted) esm.fail("Missing FLAG subrecord"); } void Container::save(ESMWriter &esm) const { esm.writeHNCString("NAME", mId); + if (mIsDeleted) { - writeDeleSubRecord(esm); + esm.writeHNCString("DELE", ""); return; } diff --git a/components/esm/loadcrea.cpp b/components/esm/loadcrea.cpp index 57e911e70..f360c8748 100644 --- a/components/esm/loadcrea.cpp +++ b/components/esm/loadcrea.cpp @@ -3,14 +3,15 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" -#include "util.hpp" namespace ESM { unsigned int Creature::sRecordId = REC_CREA; Creature::Creature() - : mIsDeleted(false) + : mFlags(0), + mScale(0.0f), + mIsDeleted(false) {} void Creature::load(ESMReader &esm) @@ -22,14 +23,11 @@ namespace ESM { mSpells.mList.clear(); mTransport.mList.clear(); - mId = esm.getHNString("NAME"); - if (mIsDeleted = readDeleSubRecord(esm)) - { - return; - } - mScale = 1.f; mHasAI = false; + mIsDeleted = false; + + bool hasName = false; bool hasNpdt = false; bool hasFlags = false; while (esm.hasMoreSubs()) @@ -38,6 +36,14 @@ namespace ESM { uint32_t name = esm.retSubName().val; switch (name) { + case ESM::FourCC<'N','A','M','E'>::value: + mId = esm.getHString(); + hasName = true; + break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + mIsDeleted = true; + break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; @@ -85,20 +91,25 @@ namespace ESM { break; default: esm.fail("Unknown subrecord"); + break; } } - if (!hasNpdt) + + if (!hasName) + esm.fail("Missing NAME subrecord"); + if (!hasNpdt && !mIsDeleted) esm.fail("Missing NPDT subrecord"); - if (!hasFlags) + if (!hasFlags && !mIsDeleted) esm.fail("Missing FLAG subrecord"); } void Creature::save(ESMWriter &esm) const { esm.writeHNCString("NAME", mId); + if (mIsDeleted) { - writeDeleSubRecord(esm); + esm.writeHNCString("DELE", ""); return; } diff --git a/components/esm/loaddial.cpp b/components/esm/loaddial.cpp index fcdb57c8d..c517dc722 100644 --- a/components/esm/loaddial.cpp +++ b/components/esm/loaddial.cpp @@ -7,7 +7,6 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" -#include "util.hpp" namespace ESM { @@ -31,20 +30,36 @@ namespace ESM void Dialogue::loadData(ESMReader &esm) { - esm.getSubNameIs("DATA"); - esm.getSubHeader(); - int si = esm.getSubSize(); - if (si == 1) - esm.getT(mType); - else if (si == 4) // The dialogue is deleted + while (esm.hasMoreSubs()) { - int32_t empty; - esm.getT(empty); // Skip an empty DATA - mIsDeleted = readDeleSubRecord(esm); - mType = Unknown; + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'D','A','T','A'>::value: + { + esm.getSubHeader(); + int size = esm.getSubSize(); + if (size == 1) + { + esm.getT(mType); + } + else + { + esm.skip(size); + } + break; + } + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + mType = Unknown; + mIsDeleted = true; + break; + default: + esm.fail("Unknown subrecord"); + break; + } } - else - esm.fail("Unknown sub record size"); } void Dialogue::save(ESMWriter &esm) const @@ -52,8 +67,7 @@ namespace ESM esm.writeHNCString("NAME", mId); if (mIsDeleted) { - esm.writeHNT("DATA", static_cast(0)); - writeDeleSubRecord(esm); + esm.writeHNCString("DELE", ""); } else { @@ -138,7 +152,7 @@ namespace ESM { for (InfoContainer::iterator it = mInfo.begin(); it != mInfo.end(); ) { - if (it->mIsDeleted || it->mQuestStatus == DialInfo::QS_Deleted) + if (it->mIsDeleted) it = mInfo.erase(it); else ++it; diff --git a/components/esm/loaddoor.cpp b/components/esm/loaddoor.cpp index 87382fa7b..4f58a4261 100644 --- a/components/esm/loaddoor.cpp +++ b/components/esm/loaddoor.cpp @@ -3,7 +3,6 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" -#include "util.hpp" namespace ESM { @@ -15,18 +14,23 @@ namespace ESM void Door::load(ESMReader &esm) { - mId = esm.getHNString("NAME"); - if (mIsDeleted = readDeleSubRecord(esm)) - { - return; - } + mIsDeleted = false; + bool hasName = false; while (esm.hasMoreSubs()) { esm.getSubName(); uint32_t name = esm.retSubName().val; switch (name) { + case ESM::FourCC<'N','A','M','E'>::value: + mId = esm.getHString(); + hasName = true; + break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + mIsDeleted = true; + break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; @@ -44,16 +48,21 @@ namespace ESM break; default: esm.fail("Unknown subrecord"); + break; } } + + if (!hasName) + esm.fail("Missing NAME subrecord"); } void Door::save(ESMWriter &esm) const { esm.writeHNCString("NAME", mId); + if (mIsDeleted) { - writeDeleSubRecord(esm); + esm.writeHNCString("DELE", ""); return; } diff --git a/components/esm/loadench.cpp b/components/esm/loadench.cpp index 1518e0385..0e480c379 100644 --- a/components/esm/loadench.cpp +++ b/components/esm/loadench.cpp @@ -3,7 +3,6 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" -#include "util.hpp" namespace ESM { @@ -16,13 +15,9 @@ namespace ESM void Enchantment::load(ESMReader &esm) { mEffects.mList.clear(); + mIsDeleted = false; - mId = esm.getHNString("NAME"); - if (mIsDeleted = readDeleSubRecord(esm)) - { - return; - } - + bool hasName = false; bool hasData = false; while (esm.hasMoreSubs()) { @@ -30,6 +25,14 @@ namespace ESM uint32_t name = esm.retSubName().val; switch (name) { + case ESM::FourCC<'N','A','M','E'>::value: + mId = esm.getHString(); + hasName = true; + break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + mIsDeleted = true; + break; case ESM::FourCC<'E','N','D','T'>::value: esm.getHT(mData, 16); hasData = true; @@ -42,16 +45,20 @@ namespace ESM break; } } - if (!hasData) + + if (!hasName) + esm.fail("Missing NAME subrecord"); + if (!hasData && !mIsDeleted) esm.fail("Missing ENDT subrecord"); } void Enchantment::save(ESMWriter &esm) const { esm.writeHNCString("NAME", mId); + if (mIsDeleted) { - writeDeleSubRecord(esm); + esm.writeHNCString("DELE", ""); return; } diff --git a/components/esm/loadfact.cpp b/components/esm/loadfact.cpp index 53f3aa5a6..8538b0b95 100644 --- a/components/esm/loadfact.cpp +++ b/components/esm/loadfact.cpp @@ -5,7 +5,6 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" -#include "util.hpp" namespace ESM { @@ -33,17 +32,13 @@ namespace ESM void Faction::load(ESMReader &esm) { + mIsDeleted = false; mReactions.clear(); for (int i=0;i<10;++i) mRanks[i].clear(); - mId = esm.getHNString("NAME"); - if (mIsDeleted = readDeleSubRecord(esm)) - { - return; - } - - int rankCounter=0; + int rankCounter = 0; + bool hasName = false; bool hasData = false; while (esm.hasMoreSubs()) { @@ -51,6 +46,14 @@ namespace ESM uint32_t name = esm.retSubName().val; switch (name) { + case ESM::FourCC<'N','A','M','E'>::value: + mId = esm.getHString(); + hasName = true; + break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + mIsDeleted = true; + break; case ESM::FourCC<'F','N','A','M'>::value: mName = esm.getHString(); break; @@ -75,18 +78,23 @@ namespace ESM } default: esm.fail("Unknown subrecord"); + break; } } - if (!hasData) + + if (!hasName) + esm.fail("Missing NAME subrecord"); + if (!hasData && !mIsDeleted) esm.fail("Missing FADT subrecord"); } void Faction::save(ESMWriter &esm) const { esm.writeHNCString("NAME", mId); + if (mIsDeleted) { - writeDeleSubRecord(esm); + esm.writeHNCString("DELE", ""); return; } diff --git a/components/esm/loadglob.cpp b/components/esm/loadglob.cpp index 392df02b5..5f96aff1f 100644 --- a/components/esm/loadglob.cpp +++ b/components/esm/loadglob.cpp @@ -3,7 +3,6 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" -#include "util.hpp" namespace ESM { @@ -15,30 +14,38 @@ namespace ESM void Global::load (ESMReader &esm) { - mId = esm.getHNString("NAME"); - if (mIsDeleted = readDeleSubRecord(esm)) + mIsDeleted = false; + mId = esm.getHNString ("NAME"); + + if (esm.isNextSub ("DELE")) { - return; + esm.skipHSub(); + mIsDeleted = true; + } + else + { + mValue.read (esm, ESM::Variant::Format_Global); } - - mValue.read (esm, ESM::Variant::Format_Global); } void Global::save (ESMWriter &esm) const { - esm.writeHNCString("NAME", mId); + esm.writeHNCString ("NAME", mId); + if (mIsDeleted) { - writeDeleSubRecord(esm); - return; + esm.writeHNCString ("DELE", ""); + } + else + { + mValue.write (esm, ESM::Variant::Format_Global); } - - mValue.write (esm, ESM::Variant::Format_Global); } void Global::blank() { mValue.setType (ESM::VT_None); + mIsDeleted = false; } bool operator== (const Global& left, const Global& right) diff --git a/components/esm/loadinfo.cpp b/components/esm/loadinfo.cpp index 8f5f0f28b..89fd4e0cd 100644 --- a/components/esm/loadinfo.cpp +++ b/components/esm/loadinfo.cpp @@ -3,14 +3,15 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" -#include "util.hpp" namespace ESM { unsigned int DialInfo::sRecordId = REC_INFO; DialInfo::DialInfo() - : mIsDeleted(false) + : mFactionLess(false), + mQuestStatus(QS_None), + mIsDeleted(false) {} void DialInfo::load(ESMReader &esm) @@ -29,6 +30,7 @@ namespace ESM { mQuestStatus = QS_None; mFactionLess = false; + mIsDeleted = false; mPrev = esm.getHNString("PNAM"); mNext = esm.getHNString("NNAM"); @@ -36,118 +38,77 @@ namespace ESM // Since there's no way to mark selects as "deleted", we have to clear the SelectStructs from all previous loadings mSelects.clear(); - // If the info is deleted, NAME and DELE sub-records are followed after NNAM - if (esm.isNextSub("NAME")) - { - mResponse = esm.getHString(); - mIsDeleted = readDeleSubRecord(esm); - return; - } - - esm.getSubNameIs("DATA"); - esm.getHT(mData, 12); - - if (!esm.hasMoreSubs()) - return; - - // What follows is somewhat spaghetti-ish, but it's worth if for - // an extra speedup. INFO is by far the most common record type. - - // subName is a reference to the original, so it changes whenever - // a new sub name is read. esm.isEmptyOrGetName() will get the - // next name for us, or return true if there are no more records. - esm.getSubName(); - const NAME &subName = esm.retSubName(); - - if (subName.val == REC_ONAM) - { - mActor = esm.getHString(); - if (esm.isEmptyOrGetName()) - return; - } - if (subName.val == REC_RNAM) - { - mRace = esm.getHString(); - if (esm.isEmptyOrGetName()) - return; - } - if (subName.val == REC_CNAM) - { - mClass = esm.getHString(); - if (esm.isEmptyOrGetName()) - return; - } - - if (subName.val == REC_FNAM) - { - mFaction = esm.getHString(); - if (mFaction == "FFFF") - mFactionLess = true; - if (esm.isEmptyOrGetName()) - return; - } - if (subName.val == REC_ANAM) - { - mCell = esm.getHString(); - if (esm.isEmptyOrGetName()) - return; - } - if (subName.val == REC_DNAM) - { - mPcFaction = esm.getHString(); - if (esm.isEmptyOrGetName()) - return; - } - if (subName.val == REC_SNAM) - { - mSound = esm.getHString(); - if (esm.isEmptyOrGetName()) - return; - } - if (subName.val == REC_NAME) - { - mResponse = esm.getHString(); - if (esm.isEmptyOrGetName()) - return; - } - - while (subName.val == REC_SCVR) + while (esm.hasMoreSubs()) { - SelectStruct ss; - - ss.mSelectRule = esm.getHString(); - - ss.mValue.read (esm, Variant::Format_Info); - - mSelects.push_back(ss); - - if (esm.isEmptyOrGetName()) - return; + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + mIsDeleted = true; + break; + case ESM::FourCC<'D','A','T','A'>::value: + esm.getHT(mData, 12); + break; + case ESM::FourCC<'O','N','A','M'>::value: + mActor = esm.getHString(); + break; + case ESM::FourCC<'R','N','A','M'>::value: + mRace = esm.getHString(); + break; + case ESM::FourCC<'C','N','A','M'>::value: + mClass = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + { + mFaction = esm.getHString(); + if (mFaction == "FFFF") + { + mFactionLess = true; + } + break; + } + case ESM::FourCC<'A','N','A','M'>::value: + mCell = esm.getHString(); + break; + case ESM::FourCC<'D','N','A','M'>::value: + mPcFaction = esm.getHString(); + break; + case ESM::FourCC<'S','N','A','M'>::value: + mSound = esm.getHString(); + break; + case ESM::FourCC<'N','A','M','E'>::value: + mResponse = esm.getHString(); + break; + case ESM::FourCC<'S','C','V','R'>::value: + { + SelectStruct ss; + ss.mSelectRule = esm.getHString(); + ss.mValue.read(esm, Variant::Format_Info); + mSelects.push_back(ss); + break; + } + case ESM::FourCC<'B','N','A','M'>::value: + mResultScript = esm.getHString(); + break; + case ESM::FourCC<'Q','S','T','N'>::value: + mQuestStatus = QS_Name; + esm.skipRecord(); + break; + case ESM::FourCC<'Q','S','T','F'>::value: + mQuestStatus = QS_Finished; + esm.skipRecord(); + break; + case ESM::FourCC<'Q','S','T','R'>::value: + mQuestStatus = QS_Restart; + esm.skipRecord(); + break; + default: + esm.fail("Unknown subrecord"); + break; + } } - - if (subName.val == REC_BNAM) - { - mResultScript = esm.getHString(); - if (esm.isEmptyOrGetName()) - return; - } - - if (subName.val == REC_QSTN) - mQuestStatus = QS_Name; - else if (subName.val == REC_QSTF) - mQuestStatus = QS_Finished; - else if (subName.val == REC_QSTR) - mQuestStatus = QS_Restart; - else if (subName.val == REC_DELE) - mQuestStatus = QS_Deleted; - else - esm.fail( - "Don't know what to do with " + subName.toString() - + " in INFO " + mId); - - if (mQuestStatus != QS_None) - // Skip rest of record - esm.skipRecord(); } void DialInfo::save(ESMWriter &esm) const @@ -158,8 +119,7 @@ namespace ESM if (mIsDeleted) { - esm.writeHNCString("NAME", mResponse); - writeDeleSubRecord(esm); + esm.writeHNCString("DELE", ""); return; } @@ -186,7 +146,6 @@ namespace ESM case QS_Name: esm.writeHNT("QSTN",'\1'); break; case QS_Finished: esm.writeHNT("QSTF", '\1'); break; case QS_Restart: esm.writeHNT("QSTR", '\1'); break; - case QS_Deleted: esm.writeHNT("DELE", '\1'); break; default: break; } } diff --git a/components/esm/loadinfo.hpp b/components/esm/loadinfo.hpp index c243cd50e..65363d1be 100644 --- a/components/esm/loadinfo.hpp +++ b/components/esm/loadinfo.hpp @@ -59,8 +59,7 @@ struct DialInfo QS_None = 0, QS_Name = 1, QS_Finished = 2, - QS_Restart = 3, - QS_Deleted + QS_Restart = 3 }; // Rules for when to include this item in the final list of options diff --git a/components/esm/loadingr.cpp b/components/esm/loadingr.cpp index a7018b36d..51a1f4805 100644 --- a/components/esm/loadingr.cpp +++ b/components/esm/loadingr.cpp @@ -3,7 +3,6 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" -#include "util.hpp" namespace ESM { @@ -15,12 +14,9 @@ namespace ESM void Ingredient::load(ESMReader &esm) { - mId = esm.getHNString("NAME"); - if (mIsDeleted = readDeleSubRecord(esm)) - { - return; - } + mIsDeleted = false; + bool hasName = false; bool hasData = false; while (esm.hasMoreSubs()) { @@ -28,6 +24,14 @@ namespace ESM uint32_t name = esm.retSubName().val; switch (name) { + case ESM::FourCC<'N','A','M','E'>::value: + mId = esm.getHString(); + hasName = true; + break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + mIsDeleted = true; + break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; @@ -46,10 +50,13 @@ namespace ESM break; default: esm.fail("Unknown subrecord"); + break; } } - if (!hasData) + if (!hasName) + esm.fail("Missing NAME subrecord"); + if (!hasData && !mIsDeleted) esm.fail("Missing IRDT subrecord"); // horrible hack to fix broken data in records @@ -79,9 +86,10 @@ namespace ESM void Ingredient::save(ESMWriter &esm) const { esm.writeHNCString("NAME", mId); + if (mIsDeleted) { - writeDeleSubRecord(esm); + esm.writeHNCString("DELE", ""); return; } diff --git a/components/esm/loadlevlist.cpp b/components/esm/loadlevlist.cpp index 1e07086bc..9c34ef657 100644 --- a/components/esm/loadlevlist.cpp +++ b/components/esm/loadlevlist.cpp @@ -3,7 +3,6 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" -#include "util.hpp" namespace ESM { @@ -13,49 +12,67 @@ namespace ESM void LevelledListBase::load(ESMReader &esm) { - mId = esm.getHNString("NAME"); - if (mIsDeleted = readDeleSubRecord(esm)) - { - return; - } - - esm.getHNT(mFlags, "DATA"); - esm.getHNT(mChanceNone, "NNAM"); + mIsDeleted = false; - if (esm.isNextSub("INDX")) - { - int len; - esm.getHT(len); - mList.resize(len); - } - else + bool hasName = false; + while (esm.hasMoreSubs()) { - // Original engine ignores rest of the record, even if there are items following - mList.clear(); - esm.skipRecord(); - return; - } + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'N','A','M','E'>::value: + mId = esm.getHString(); + hasName = true; + break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + mIsDeleted = true; + break; + case ESM::FourCC<'D','A','T','A'>::value: + esm.getHT(mFlags); + break; + case ESM::FourCC<'N','N','A','M'>::value: + esm.getHT(mChanceNone); + break; + case ESM::FourCC<'I','N','D','X'>::value: + { + int length = 0; + esm.getHT(length); + mList.resize(length); - // If this levelled list was already loaded by a previous content file, - // we overwrite the list. Merging lists should probably be left to external tools, - // with the limited amount of information there is in the records, all merging methods - // will be flawed in some way. For a proper fix the ESM format would have to be changed - // to actually track list changes instead of including the whole list for every file - // that does something with that list. - - for (size_t i = 0; i < mList.size(); i++) - { - LevelItem &li = mList[i]; - li.mId = esm.getHNString(mRecName); - esm.getHNT(li.mLevel, "INTV"); + // If this levelled list was already loaded by a previous content file, + // we overwrite the list. Merging lists should probably be left to external tools, + // with the limited amount of information there is in the records, all merging methods + // will be flawed in some way. For a proper fix the ESM format would have to be changed + // to actually track list changes instead of including the whole list for every file + // that does something with that list. + for (size_t i = 0; i < mList.size(); i++) + { + LevelItem &li = mList[i]; + li.mId = esm.getHNString(mRecName); + esm.getHNT(li.mLevel, "INTV"); + } + break; + } + default: + mList.clear(); + esm.skipRecord(); + break; + } } + + if (!hasName) + esm.fail("Missing NAME subrecord"); } + void LevelledListBase::save(ESMWriter &esm) const { esm.writeHNCString("NAME", mId); + if (mIsDeleted) { - writeDeleSubRecord(esm); + esm.writeHNCString("DELE", ""); return; } diff --git a/components/esm/loadligh.cpp b/components/esm/loadligh.cpp index a153d500a..441e96d0a 100644 --- a/components/esm/loadligh.cpp +++ b/components/esm/loadligh.cpp @@ -3,7 +3,6 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" -#include "util.hpp" namespace ESM { @@ -15,12 +14,9 @@ namespace ESM void Light::load(ESMReader &esm) { - mId = esm.getHNString("NAME"); - if (mIsDeleted = readDeleSubRecord(esm)) - { - return; - } + mIsDeleted = false; + bool hasName = false; bool hasData = false; while (esm.hasMoreSubs()) { @@ -28,6 +24,14 @@ namespace ESM uint32_t name = esm.retSubName().val; switch (name) { + case ESM::FourCC<'N','A','M','E'>::value: + mId = esm.getHString(); + hasName = true; + break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + mIsDeleted = true; + break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; @@ -49,17 +53,22 @@ namespace ESM break; default: esm.fail("Unknown subrecord"); + break; } } - if (!hasData) + + if (!hasName) + esm.fail("Missing NAME subrecord"); + if (!hasData && !mIsDeleted) esm.fail("Missing LHDT subrecord"); } void Light::save(ESMWriter &esm) const { esm.writeHNCString("NAME", mId); + if (mIsDeleted) { - writeDeleSubRecord(esm); + esm.writeHNCString("DELE", ""); return; } diff --git a/components/esm/loadlock.cpp b/components/esm/loadlock.cpp index 3b169af33..5ee041dab 100644 --- a/components/esm/loadlock.cpp +++ b/components/esm/loadlock.cpp @@ -3,7 +3,6 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" -#include "util.hpp" namespace ESM { @@ -15,19 +14,23 @@ namespace ESM void Lockpick::load(ESMReader &esm) { - mId = esm.getHNString("NAME"); - if (mIsDeleted = readDeleSubRecord(esm)) - { - return; - } + mIsDeleted = false; - bool hasData = true; + bool hasName = false; + bool hasData = false; while (esm.hasMoreSubs()) { esm.getSubName(); uint32_t name = esm.retSubName().val; switch (name) { + case ESM::FourCC<'N','A','M','E'>::value: + mId = esm.getHString(); + break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + mIsDeleted = true; + break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; @@ -46,18 +49,23 @@ namespace ESM break; default: esm.fail("Unknown subrecord"); + break; } } - if (!hasData) + + if (!hasName) + esm.fail("Missing NAME subrecord"); + if (!hasData && !mIsDeleted) esm.fail("Missing LKDT subrecord"); } void Lockpick::save(ESMWriter &esm) const { esm.writeHNCString("NAME", mId); + if (mIsDeleted) { - writeDeleSubRecord(esm); + esm.writeHNCString("DELE", ""); return; } diff --git a/components/esm/loadltex.cpp b/components/esm/loadltex.cpp index 13315e684..7c14536ed 100644 --- a/components/esm/loadltex.cpp +++ b/components/esm/loadltex.cpp @@ -3,7 +3,6 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" -#include "util.hpp" namespace ESM { @@ -15,17 +14,49 @@ namespace ESM void LandTexture::load(ESMReader &esm) { - mIsDeleted = readDeleSubRecord(esm); - mId = esm.getHNString("NAME"); - esm.getHNT(mIndex, "INTV"); - mTexture = esm.getHNString("DATA"); + mIsDeleted = false; + + bool hasName = false; + bool hasIndex = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'N','A','M','E'>::value: + mId = esm.getHString(); + hasName = false; + break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + mIsDeleted = true; + break; + case ESM::FourCC<'I','N','T','V'>::value: + esm.getHT(mIndex); + hasIndex = true; + break; + case ESM::FourCC<'D','A','T','A'>::value: + mTexture = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + break; + } + } + + if (!hasName) + esm.fail("Missing NAME subrecord"); + if (!hasIndex) + esm.fail("Missing INTV subrecord"); } void LandTexture::save(ESMWriter &esm) const { if (mIsDeleted) { - writeDeleSubRecord(esm); + esm.writeHNCString("DELE", ""); } + esm.writeHNCString("NAME", mId); esm.writeHNT("INTV", mIndex); esm.writeHNCString("DATA", mTexture); diff --git a/components/esm/loadmisc.cpp b/components/esm/loadmisc.cpp index 08cbcf741..de9ccdd6a 100644 --- a/components/esm/loadmisc.cpp +++ b/components/esm/loadmisc.cpp @@ -3,7 +3,6 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" -#include "util.hpp" namespace ESM { @@ -15,12 +14,9 @@ namespace ESM void Miscellaneous::load(ESMReader &esm) { - mId = esm.getHNString("NAME"); - if (mIsDeleted = readDeleSubRecord(esm)) - { - return; - } + mIsDeleted = false; + bool hasName = false; bool hasData = false; while (esm.hasMoreSubs()) { @@ -28,6 +24,14 @@ namespace ESM uint32_t name = esm.retSubName().val; switch (name) { + case ESM::FourCC<'N','A','M','E'>::value: + mId = esm.getHString(); + hasName = true; + break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + mIsDeleted = true; + break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; @@ -44,18 +48,25 @@ namespace ESM case ESM::FourCC<'I','T','E','X'>::value: mIcon = esm.getHString(); break; + default: + esm.fail("Unknown subrecord"); + break; } } - if (!hasData) + + if (!hasName) + esm.fail("Missing NAME subrecord"); + if (!hasData && !mIsDeleted) esm.fail("Missing MCDT subrecord"); } void Miscellaneous::save(ESMWriter &esm) const { esm.writeHNCString("NAME", mId); + if (mIsDeleted) { - writeDeleSubRecord(esm); + esm.writeHNCString("DELE", ""); return; } diff --git a/components/esm/loadnpc.cpp b/components/esm/loadnpc.cpp index eadf23a21..ff3213ee9 100644 --- a/components/esm/loadnpc.cpp +++ b/components/esm/loadnpc.cpp @@ -3,40 +3,45 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" -#include "util.hpp" namespace ESM { unsigned int NPC::sRecordId = REC_NPC_; NPC::NPC() - : mIsDeleted(false) + : mFlags(0), + mHasAI(false), + mIsDeleted(false) {} void NPC::load(ESMReader &esm) { + mIsDeleted = false; mPersistent = (esm.getRecordFlags() & 0x0400) != 0; mSpells.mList.clear(); mInventory.mList.clear(); mTransport.mList.clear(); mAiPackage.mList.clear(); + mHasAI = false; - mId = esm.getHNString("NAME"); - if (mIsDeleted = readDeleSubRecord(esm)) - { - return; - } - + bool hasName = false; bool hasNpdt = false; bool hasFlags = false; - mHasAI = false; while (esm.hasMoreSubs()) { esm.getSubName(); uint32_t name = esm.retSubName().val; switch (name) { + case ESM::FourCC<'N','A','M','E'>::value: + mId = esm.getHString(); + hasName = true; + break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + mIsDeleted = true; + break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; @@ -105,19 +110,24 @@ namespace ESM break; default: esm.fail("Unknown subrecord"); + break; } } - if (!hasNpdt) + + if (!hasName) + esm.fail("Missing NAME subrecord"); + if (!hasNpdt && !mIsDeleted) esm.fail("Missing NPDT subrecord"); - if (!hasFlags) + if (!hasFlags && !mIsDeleted) esm.fail("Missing FLAG subrecord"); } void NPC::save(ESMWriter &esm) const { esm.writeHNCString("NAME", mId); + if (mIsDeleted) { - writeDeleSubRecord(esm); + esm.writeHNCString("DELE", ""); return; } diff --git a/components/esm/loadprob.cpp b/components/esm/loadprob.cpp index f5287f986..4ce9b9d9c 100644 --- a/components/esm/loadprob.cpp +++ b/components/esm/loadprob.cpp @@ -3,7 +3,6 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" -#include "util.hpp" namespace ESM { @@ -15,19 +14,24 @@ namespace ESM void Probe::load(ESMReader &esm) { - mId = esm.getHNString("NAME"); - if (mIsDeleted = readDeleSubRecord(esm)) - { - return; - } + mIsDeleted = false; - bool hasData = true; + bool hasName = false; + bool hasData = false; while (esm.hasMoreSubs()) { esm.getSubName(); uint32_t name = esm.retSubName().val; switch (name) { + case ESM::FourCC<'N','A','M','E'>::value: + mId = esm.getHString(); + hasName = true; + break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + mIsDeleted = true; + break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; @@ -46,18 +50,23 @@ namespace ESM break; default: esm.fail("Unknown subrecord"); + break; } } - if (!hasData) + + if (!hasName) + esm.fail("Missing NAME subrecord"); + if (!hasData && !mIsDeleted) esm.fail("Missing PBDT subrecord"); } void Probe::save(ESMWriter &esm) const { esm.writeHNCString("NAME", mId); + if (mIsDeleted) { - writeDeleSubRecord(esm); + esm.writeHNCString("DELE", ""); return; } diff --git a/components/esm/loadregn.cpp b/components/esm/loadregn.cpp index 2d99947b0..b48ffa4b7 100644 --- a/components/esm/loadregn.cpp +++ b/components/esm/loadregn.cpp @@ -3,64 +3,95 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" -#include "util.hpp" namespace ESM { unsigned int Region::sRecordId = REC_REGN; Region::Region() - : mIsDeleted(false) + : mMapColor(0), + mIsDeleted(false) {} void Region::load(ESMReader &esm) { - mIsDeleted = readDeleSubRecord(esm); - mId = esm.getHNString("NAME"); - mName = esm.getHNOString("FNAM"); + mIsDeleted = false; - esm.getSubNameIs("WEAT"); - esm.getSubHeader(); - if (esm.getVer() == VER_12) - { - mData.mA = 0; - mData.mB = 0; - esm.getExact(&mData, sizeof(mData) - 2); - } - else if (esm.getVer() == VER_13) + bool hasName = false; + while (esm.hasMoreSubs()) { - // May include the additional two bytes (but not necessarily) - if (esm.getSubSize() == sizeof(mData)) - esm.getExact(&mData, sizeof(mData)); - else + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) { - mData.mA = 0; - mData.mB = 0; - esm.getExact(&mData, sizeof(mData)-2); + case ESM::FourCC<'N','A','M','E'>::value: + mId = esm.getHString(); + hasName = true; + break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + mIsDeleted = true; + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'W','E','A','T'>::value: + { + esm.getSubHeader(); + if (esm.getVer() == VER_12) + { + mData.mA = 0; + mData.mB = 0; + esm.getExact(&mData, sizeof(mData) - 2); + } + else if (esm.getVer() == VER_13) + { + // May include the additional two bytes (but not necessarily) + if (esm.getSubSize() == sizeof(mData)) + { + esm.getExact(&mData, sizeof(mData)); + } + else + { + mData.mA = 0; + mData.mB = 0; + esm.getExact(&mData, sizeof(mData)-2); + } + } + else + { + esm.fail("Don't know what to do in this version"); + } + break; + } + case ESM::FourCC<'B','N','A','M'>::value: + mSleepList = esm.getHString(); + break; + case ESM::FourCC<'C','N','A','M'>::value: + esm.getHT(mMapColor); + break; + case ESM::FourCC<'S','N','A','M'>::value: + SoundRef sr; + esm.getHT(sr, 33); + mSoundList.push_back(sr); + break; + default: + esm.fail("Unknown subrecord"); + break; } } - else - esm.fail("Don't know what to do in this version"); - - mSleepList = esm.getHNOString("BNAM"); - esm.getHNT(mMapColor, "CNAM"); - - mSoundList.clear(); - while (esm.hasMoreSubs()) - { - SoundRef sr; - esm.getHNT(sr, "SNAM", 33); - mSoundList.push_back(sr); - } + if (!hasName) + esm.fail("Missing NAME subrecord"); } void Region::save(ESMWriter &esm) const { if (mIsDeleted) { - writeDeleSubRecord(esm); + esm.writeHNCString("DELE", ""); } + esm.writeHNString("NAME", mId); esm.writeHNOCString("FNAM", mName); diff --git a/components/esm/loadrepa.cpp b/components/esm/loadrepa.cpp index fb213efd8..74e682d63 100644 --- a/components/esm/loadrepa.cpp +++ b/components/esm/loadrepa.cpp @@ -3,7 +3,6 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" -#include "util.hpp" namespace ESM { @@ -15,19 +14,24 @@ namespace ESM void Repair::load(ESMReader &esm) { - mId = esm.getHNString("NAME"); - if (mIsDeleted = readDeleSubRecord(esm)) - { - return; - } + mIsDeleted = false; - bool hasData = true; + bool hasName = false; + bool hasData = false; while (esm.hasMoreSubs()) { esm.getSubName(); uint32_t name = esm.retSubName().val; switch (name) { + case ESM::FourCC<'N','A','M','E'>::value: + mId = esm.getHString(); + hasName = true; + break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + mIsDeleted = true; + break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; @@ -46,18 +50,23 @@ namespace ESM break; default: esm.fail("Unknown subrecord"); + break; } } - if (!hasData) + + if (!hasName) + esm.fail("Missing NAME subrecord"); + if (!hasData && !mIsDeleted) esm.fail("Missing RIDT subrecord"); } void Repair::save(ESMWriter &esm) const { esm.writeHNCString("NAME", mId); + if (mIsDeleted) { - writeDeleSubRecord(esm); + esm.writeHNCString("DELE", ""); return; } diff --git a/components/esm/loadscpt.cpp b/components/esm/loadscpt.cpp index 529f0a66d..333389ba4 100644 --- a/components/esm/loadscpt.cpp +++ b/components/esm/loadscpt.cpp @@ -3,7 +3,6 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" -#include "util.hpp" #include @@ -64,23 +63,27 @@ namespace ESM void Script::load(ESMReader &esm) { - SCHD data; - esm.getHNT(data, "SCHD", 52); - mData = data.mData; - mId = data.mName.toString(); - - // In scripts DELE sub-record appears after a header. - // The script data is following after DELE in this case. - mIsDeleted = readDeleSubRecord(esm); - mVarNames.clear(); + mIsDeleted = false; + bool hasHeader = false; while (esm.hasMoreSubs()) { esm.getSubName(); uint32_t name = esm.retSubName().val; switch (name) { + case ESM::FourCC<'S','C','H','D'>::value: + SCHD data; + esm.getHT(data, 52); + mData = data.mData; + mId = data.mName.toString(); + hasHeader = true; + break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + mIsDeleted = true; + break; case ESM::FourCC<'S','C','V','R'>::value: // list of local variables loadSCVR(esm); @@ -95,8 +98,12 @@ namespace ESM break; default: esm.fail("Unknown subrecord"); + break; } } + + if (!hasHeader) + esm.fail("Missing SCHD subrecord"); } void Script::save(ESMWriter &esm) const @@ -116,7 +123,7 @@ namespace ESM if (mIsDeleted) { - writeDeleSubRecord(esm); + esm.writeHNCString("DELE", ""); } if (!mVarNames.empty()) diff --git a/components/esm/loadsndg.cpp b/components/esm/loadsndg.cpp index 261087be0..a20e6ee51 100644 --- a/components/esm/loadsndg.cpp +++ b/components/esm/loadsndg.cpp @@ -3,24 +3,21 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" -#include "util.hpp" namespace ESM { unsigned int SoundGenerator::sRecordId = REC_SNDG; SoundGenerator::SoundGenerator() - : mIsDeleted(false) + : mType(LeftFoot), + mIsDeleted(false) {} void SoundGenerator::load(ESMReader &esm) { - mId = esm.getHNString("NAME"); - if (mIsDeleted = readDeleSubRecord(esm)) - { - return; - } + mIsDeleted = false; + bool hasName = false; bool hasData = false; while (esm.hasMoreSubs()) { @@ -28,6 +25,14 @@ namespace ESM uint32_t name = esm.retSubName().val; switch (name) { + case ESM::FourCC<'N','A','M','E'>::value: + mId = esm.getHString(); + hasName = true; + break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + mIsDeleted = true; + break; case ESM::FourCC<'D','A','T','A'>::value: esm.getHT(mType, 4); hasData = true; @@ -40,23 +45,26 @@ namespace ESM break; default: esm.fail("Unknown subrecord"); + break; } } - if (!hasData) - esm.fail("Missing DATA"); + + if (!hasName) + esm.fail("Missing NAME subrecord"); + if (!hasData && !mIsDeleted) + esm.fail("Missing DATA subrecord"); } void SoundGenerator::save(ESMWriter &esm) const { esm.writeHNCString("NAME", mId); - if (mIsDeleted) - { - writeDeleSubRecord(esm); - return; - } - esm.writeHNT("DATA", mType, 4); esm.writeHNOCString("CNAM", mCreature); esm.writeHNOCString("SNAM", mSound); + + if (mIsDeleted) + { + esm.writeHNCString("DELE", ""); + } } void SoundGenerator::blank() diff --git a/components/esm/loadsoun.cpp b/components/esm/loadsoun.cpp index 9a1a52b1e..55fe69292 100644 --- a/components/esm/loadsoun.cpp +++ b/components/esm/loadsoun.cpp @@ -3,7 +3,6 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" -#include "util.hpp" namespace ESM { @@ -15,12 +14,9 @@ namespace ESM void Sound::load(ESMReader &esm) { - mId = esm.getHNString("NAME"); - if (mIsDeleted = readDeleSubRecord(esm)) - { - return; - } + mIsDeleted = false; + bool hasName = false; bool hasData = false; while (esm.hasMoreSubs()) { @@ -28,6 +24,14 @@ namespace ESM uint32_t name = esm.retSubName().val; switch (name) { + case ESM::FourCC<'N','A','M','E'>::value: + mId = esm.getHString(); + hasName = true; + break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + mIsDeleted = true; + break; case ESM::FourCC<'F','N','A','M'>::value: mSound = esm.getHString(); break; @@ -37,18 +41,23 @@ namespace ESM break; default: esm.fail("Unknown subrecord"); + break; } } - if (!hasData) - esm.fail("Missing DATA"); + + if (!hasName) + esm.fail("Missing NAME subrecord"); + if (!hasData && !mIsDeleted) + esm.fail("Missing DATA subrecord"); } void Sound::save(ESMWriter &esm) const { esm.writeHNCString("NAME", mId); + if (mIsDeleted) { - writeDeleSubRecord(esm); + esm.writeHNCString("DELE", ""); return; } diff --git a/components/esm/loadspel.cpp b/components/esm/loadspel.cpp index d2d8c7d6d..28feffd20 100644 --- a/components/esm/loadspel.cpp +++ b/components/esm/loadspel.cpp @@ -3,7 +3,6 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" -#include "util.hpp" namespace ESM { @@ -16,13 +15,9 @@ namespace ESM void Spell::load(ESMReader &esm) { mEffects.mList.clear(); + mIsDeleted = false; - mId = esm.getHNString("NAME"); - if (mIsDeleted = readDeleSubRecord(esm)) - { - return; - } - + bool hasName = false; bool hasData = false; while (esm.hasMoreSubs()) { @@ -31,6 +26,14 @@ namespace ESM switch (val) { + case ESM::FourCC<'N','A','M','E'>::value: + mId = esm.getHString(); + hasName = true; + break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + mIsDeleted = true; + break; case ESM::FourCC<'F','N','A','M'>::value: mName = esm.getHString(); break; @@ -43,18 +46,25 @@ namespace ESM esm.getHT(s, 24); mEffects.mList.push_back(s); break; + default: + esm.fail("Unknown subrecord"); + break; } } - if (!hasData) + + if (!hasName) + esm.fail("Missing NAME subrecord"); + if (!hasData && !mIsDeleted) esm.fail("Missing SPDT subrecord"); } void Spell::save(ESMWriter &esm) const { esm.writeHNCString("NAME", mId); + if (mIsDeleted) { - writeDeleSubRecord(esm); + esm.writeHNCString("DELE", ""); return; } @@ -70,9 +80,7 @@ namespace ESM mData.mFlags = 0; mName.clear(); - mEffects.mList.clear(); - mIsDeleted = false; } } diff --git a/components/esm/loadstat.cpp b/components/esm/loadstat.cpp index 2fde46bd2..9a146a370 100644 --- a/components/esm/loadstat.cpp +++ b/components/esm/loadstat.cpp @@ -3,7 +3,6 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" -#include "util.hpp" namespace ESM { @@ -15,24 +14,46 @@ namespace ESM void Static::load(ESMReader &esm) { - mId = esm.getHNString("NAME"); - if (mIsDeleted = readDeleSubRecord(esm)) + mIsDeleted = false; + + bool hasName = false; + while (esm.hasMoreSubs()) { - return; + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'N','A','M','E'>::value: + mId = esm.getHString(); + hasName = true; + break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + mIsDeleted = true; + break; + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + break; + } } - mModel = esm.getHNString("MODL"); + if (!hasName) + esm.fail("Missing NAME subrecord"); } void Static::save(ESMWriter &esm) const { esm.writeHNCString("NAME", mId); if (mIsDeleted) { - writeDeleSubRecord(esm); - return; + esm.writeHNCString("DELE", ""); + } + else + { + esm.writeHNCString("MODL", mModel); } - - esm.writeHNCString("MODL", mModel); } void Static::blank() diff --git a/components/esm/loadweap.cpp b/components/esm/loadweap.cpp index 38fb94adb..98302c13d 100644 --- a/components/esm/loadweap.cpp +++ b/components/esm/loadweap.cpp @@ -3,7 +3,6 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" -#include "util.hpp" namespace ESM { @@ -15,12 +14,9 @@ namespace ESM void Weapon::load(ESMReader &esm) { - mId = esm.getHNString("NAME"); - if (mIsDeleted = readDeleSubRecord(esm)) - { - return; - } + mIsDeleted = false; + bool hasName = false; bool hasData = false; while (esm.hasMoreSubs()) { @@ -28,6 +24,14 @@ namespace ESM uint32_t name = esm.retSubName().val; switch (name) { + case ESM::FourCC<'N','A','M','E'>::value: + mId = esm.getHString(); + hasName = true; + break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + mIsDeleted = true; + break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; @@ -51,15 +55,19 @@ namespace ESM esm.fail("Unknown subrecord"); } } - if (!hasData) + + if (!hasName) + esm.fail("Missing NAME subrecord"); + if (!hasData && !mIsDeleted) esm.fail("Missing WPDT subrecord"); } void Weapon::save(ESMWriter &esm) const { esm.writeHNCString("NAME", mId); + if (mIsDeleted) { - writeDeleSubRecord(esm); + esm.writeHNCString("DELE", ""); return; } From e65ff723ce6e71da7d00e68820250682512418c1 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Thu, 16 Jul 2015 22:17:49 +0300 Subject: [PATCH 1883/3725] More ESM records have DELE handling. Changed records: Race, Land, Pathgrid, StartScript, DebugProfile, Filter --- components/esm/debugprofile.cpp | 45 +++- components/esm/debugprofile.hpp | 4 + components/esm/filter.cpp | 41 +++- components/esm/filter.hpp | 4 + components/esm/loadland.cpp | 361 +++++++++++++++++--------------- components/esm/loadland.hpp | 4 +- components/esm/loadpgrd.cpp | 186 +++++++++------- components/esm/loadpgrd.hpp | 4 + components/esm/loadrace.cpp | 92 ++++---- components/esm/loadrace.hpp | 4 + components/esm/loadsscr.cpp | 18 ++ components/esm/loadsscr.hpp | 4 + 12 files changed, 482 insertions(+), 285 deletions(-) diff --git a/components/esm/debugprofile.cpp b/components/esm/debugprofile.cpp index 9c8164d29..d1e27debc 100644 --- a/components/esm/debugprofile.cpp +++ b/components/esm/debugprofile.cpp @@ -7,17 +7,53 @@ unsigned int ESM::DebugProfile::sRecordId = REC_DBGP; +ESM::DebugProfile::DebugProfile() + : mIsDeleted(false) +{} + void ESM::DebugProfile::load (ESMReader& esm) { - mId = esm.getHNString ("NAME"); - mDescription = esm.getHNString ("DESC"); - mScriptText = esm.getHNString ("SCRP"); - esm.getHNT (mFlags, "FLAG"); + mIsDeleted = false; + + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'N','A','M','E'>::value: + mId = esm.getHString(); + break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + mIsDeleted = true; + break; + case ESM::FourCC<'D','E','S','C'>::value: + mDescription = esm.getHString(); + break; + case ESM::FourCC<'S','C','R','P'>::value: + mScriptText = esm.getHString(); + break; + case ESM::FourCC<'F','L','A','G'>::value: + esm.getHT(mFlags); + break; + default: + esm.fail("Unknown subrecord"); + break; + } + } } void ESM::DebugProfile::save (ESMWriter& esm) const { esm.writeHNCString ("NAME", mId); + + if (mIsDeleted) + { + esm.writeHNCString("DELE", ""); + return; + } + esm.writeHNCString ("DESC", mDescription); esm.writeHNCString ("SCRP", mScriptText); esm.writeHNT ("FLAG", mFlags); @@ -28,4 +64,5 @@ void ESM::DebugProfile::blank() mDescription.clear(); mScriptText.clear(); mFlags = 0; + mIsDeleted = false; } diff --git a/components/esm/debugprofile.hpp b/components/esm/debugprofile.hpp index b54e8ff5f..1709136f5 100644 --- a/components/esm/debugprofile.hpp +++ b/components/esm/debugprofile.hpp @@ -27,6 +27,10 @@ namespace ESM unsigned int mFlags; + bool mIsDeleted; + + DebugProfile(); + void load (ESMReader& esm); void save (ESMWriter& esm) const; diff --git a/components/esm/filter.cpp b/components/esm/filter.cpp index ee2c67869..57cb59454 100644 --- a/components/esm/filter.cpp +++ b/components/esm/filter.cpp @@ -7,16 +7,50 @@ unsigned int ESM::Filter::sRecordId = REC_FILT; +ESM::Filter::Filter() + : mIsDeleted(false) +{} + void ESM::Filter::load (ESMReader& esm) { - mId = esm.getHNString ("NAME"); - mFilter = esm.getHNString ("FILT"); - mDescription = esm.getHNString ("DESC"); + mIsDeleted = false; + + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'N','A','M','E'>::value: + mId = esm.getHString(); + break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + mIsDeleted = true; + break; + case ESM::FourCC<'F','I','L','T'>::value: + mFilter = esm.getHString(); + break; + case ESM::FourCC<'D','E','S','C'>::value: + mDescription = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + break; + } + } } void ESM::Filter::save (ESMWriter& esm) const { esm.writeHNCString ("NAME", mId); + + if (mIsDeleted) + { + esm.writeHNCString("DELE", ""); + return; + } + esm.writeHNCString ("FILT", mFilter); esm.writeHNCString ("DESC", mDescription); } @@ -25,4 +59,5 @@ void ESM::Filter::blank() { mFilter.clear(); mDescription.clear(); + mIsDeleted = false; } diff --git a/components/esm/filter.hpp b/components/esm/filter.hpp index bc3dd7bdc..1a8af9229 100644 --- a/components/esm/filter.hpp +++ b/components/esm/filter.hpp @@ -18,6 +18,10 @@ namespace ESM std::string mFilter; + bool mIsDeleted; + + Filter(); + void load (ESMReader& esm); void save (ESMWriter& esm) const; diff --git a/components/esm/loadland.cpp b/components/esm/loadland.cpp index b0897ec67..6acaa6e6a 100644 --- a/components/esm/loadland.cpp +++ b/components/esm/loadland.cpp @@ -8,211 +8,234 @@ namespace ESM { unsigned int Land::sRecordId = REC_LAND; -void Land::LandData::save(ESMWriter &esm) -{ - if (mDataTypes & Land::DATA_VNML) { - esm.writeHNT("VNML", mNormals, sizeof(mNormals)); - } - if (mDataTypes & Land::DATA_VHGT) { - VHGT offsets; - offsets.mHeightOffset = mHeights[0] / HEIGHT_SCALE; - offsets.mUnk1 = mUnk1; - offsets.mUnk2 = mUnk2; - - float prevY = mHeights[0]; - int number = 0; // avoid multiplication - for (int i = 0; i < LAND_SIZE; ++i) { - float diff = (mHeights[number] - prevY) / HEIGHT_SCALE; - offsets.mHeightData[number] = - (diff >= 0) ? (int8_t) (diff + 0.5) : (int8_t) (diff - 0.5); - - float prevX = prevY = mHeights[number]; - ++number; - - for (int j = 1; j < LAND_SIZE; ++j) { - diff = (mHeights[number] - prevX) / HEIGHT_SCALE; + void Land::LandData::save(ESMWriter &esm) + { + if (mDataTypes & Land::DATA_VNML) { + esm.writeHNT("VNML", mNormals, sizeof(mNormals)); + } + if (mDataTypes & Land::DATA_VHGT) { + VHGT offsets; + offsets.mHeightOffset = mHeights[0] / HEIGHT_SCALE; + offsets.mUnk1 = mUnk1; + offsets.mUnk2 = mUnk2; + + float prevY = mHeights[0]; + int number = 0; // avoid multiplication + for (int i = 0; i < LAND_SIZE; ++i) { + float diff = (mHeights[number] - prevY) / HEIGHT_SCALE; offsets.mHeightData[number] = (diff >= 0) ? (int8_t) (diff + 0.5) : (int8_t) (diff - 0.5); - prevX = mHeights[number]; + float prevX = prevY = mHeights[number]; ++number; + + for (int j = 1; j < LAND_SIZE; ++j) { + diff = (mHeights[number] - prevX) / HEIGHT_SCALE; + offsets.mHeightData[number] = + (diff >= 0) ? (int8_t) (diff + 0.5) : (int8_t) (diff - 0.5); + + prevX = mHeights[number]; + ++number; + } } + esm.writeHNT("VHGT", offsets, sizeof(VHGT)); + } + if (mDataTypes & Land::DATA_WNAM) { + esm.writeHNT("WNAM", mWnam, 81); + } + if (mDataTypes & Land::DATA_VCLR) { + esm.writeHNT("VCLR", mColours, 3*LAND_NUM_VERTS); + } + if (mDataTypes & Land::DATA_VTEX) { + static uint16_t vtex[LAND_NUM_TEXTURES]; + transposeTextureData(mTextures, vtex); + esm.writeHNT("VTEX", vtex, sizeof(vtex)); } - esm.writeHNT("VHGT", offsets, sizeof(VHGT)); - } - if (mDataTypes & Land::DATA_WNAM) { - esm.writeHNT("WNAM", mWnam, 81); - } - if (mDataTypes & Land::DATA_VCLR) { - esm.writeHNT("VCLR", mColours, 3*LAND_NUM_VERTS); - } - if (mDataTypes & Land::DATA_VTEX) { - static uint16_t vtex[LAND_NUM_TEXTURES]; - transposeTextureData(mTextures, vtex); - esm.writeHNT("VTEX", vtex, sizeof(vtex)); } -} - -void Land::LandData::transposeTextureData(uint16_t *in, uint16_t *out) -{ - int readPos = 0; //bit ugly, but it works - for ( int y1 = 0; y1 < 4; y1++ ) - for ( int x1 = 0; x1 < 4; x1++ ) - for ( int y2 = 0; y2 < 4; y2++) - for ( int x2 = 0; x2 < 4; x2++ ) - out[(y1*4+y2)*16+(x1*4+x2)] = in[readPos++]; -} - -Land::Land() - : mFlags(0) - , mX(0) - , mY(0) - , mPlugin(0) - , mEsm(NULL) - , mDataTypes(0) - , mDataLoaded(false) - , mLandData(NULL) -{ -} -Land::~Land() -{ - delete mLandData; -} - -void Land::load(ESMReader &esm) -{ - mEsm = &esm; - mPlugin = mEsm->getIndex(); - - // Get the grid location - esm.getSubNameIs("INTV"); - esm.getSubHeaderIs(8); - esm.getT(mX); - esm.getT(mY); - - esm.getHNT(mFlags, "DATA"); - - // Store the file position - mContext = esm.getContext(); - - // Skip these here. Load the actual data when the cell is loaded. - if (esm.isNextSub("VNML")) - { - esm.skipHSubSize(12675); - mDataTypes |= DATA_VNML; - } - if (esm.isNextSub("VHGT")) + void Land::LandData::transposeTextureData(uint16_t *in, uint16_t *out) { - esm.skipHSubSize(4232); - mDataTypes |= DATA_VHGT; - } - if (esm.isNextSub("WNAM")) + int readPos = 0; //bit ugly, but it works + for ( int y1 = 0; y1 < 4; y1++ ) + for ( int x1 = 0; x1 < 4; x1++ ) + for ( int y2 = 0; y2 < 4; y2++) + for ( int x2 = 0; x2 < 4; x2++ ) + out[(y1*4+y2)*16+(x1*4+x2)] = in[readPos++]; + } + + Land::Land() + : mFlags(0) + , mX(0) + , mY(0) + , mPlugin(0) + , mEsm(NULL) + , mDataTypes(0) + , mDataLoaded(false) + , mLandData(NULL) + , mIsDeleted(false) { - esm.skipHSubSize(81); - mDataTypes |= DATA_WNAM; } - if (esm.isNextSub("VCLR")) + + Land::~Land() { - esm.skipHSubSize(12675); - mDataTypes |= DATA_VCLR; + delete mLandData; } - if (esm.isNextSub("VTEX")) + + void Land::load(ESMReader &esm) { - esm.skipHSubSize(512); - mDataTypes |= DATA_VTEX; + mEsm = &esm; + mPlugin = mEsm->getIndex(); + mIsDeleted = false; + + // Get the grid location + esm.getSubNameIs("INTV"); + esm.getSubHeaderIs(8); + esm.getT(mX); + esm.getT(mY); + + esm.getHNT(mFlags, "DATA"); + + if (esm.isNextSub("DELE")) + { + esm.skipHSub(); + mIsDeleted = true; + } + + // Store the file position + mContext = esm.getContext(); + + // Skip these here. Load the actual data when the cell is loaded. + if (esm.isNextSub("VNML")) + { + esm.skipHSubSize(12675); + mDataTypes |= DATA_VNML; + } + if (esm.isNextSub("VHGT")) + { + esm.skipHSubSize(4232); + mDataTypes |= DATA_VHGT; + } + if (esm.isNextSub("WNAM")) + { + esm.skipHSubSize(81); + mDataTypes |= DATA_WNAM; + } + if (esm.isNextSub("VCLR")) + { + esm.skipHSubSize(12675); + mDataTypes |= DATA_VCLR; + } + if (esm.isNextSub("VTEX")) + { + esm.skipHSubSize(512); + mDataTypes |= DATA_VTEX; + } + + mDataLoaded = 0; + mLandData = NULL; } - mDataLoaded = 0; - mLandData = NULL; -} + void Land::save(ESMWriter &esm) const + { + esm.startSubRecord("INTV"); + esm.writeT(mX); + esm.writeT(mY); + esm.endRecord("INTV"); -void Land::save(ESMWriter &esm) const -{ - esm.startSubRecord("INTV"); - esm.writeT(mX); - esm.writeT(mY); - esm.endRecord("INTV"); + esm.writeHNT("DATA", mFlags); - esm.writeHNT("DATA", mFlags); -} + if (mIsDeleted) + { + esm.writeHNCString("DELE", ""); + } -void Land::loadData(int flags) -{ - // Try to load only available data - flags = flags & mDataTypes; - // Return if all required data is loaded - if ((mDataLoaded & flags) == flags) { - return; - } - // Create storage if nothing is loaded - if (mLandData == NULL) { - mLandData = new LandData; - mLandData->mDataTypes = mDataTypes; + if (mLandData != NULL) + { + mLandData->save(esm); + } } - mEsm->restoreContext(mContext); - if (mEsm->isNextSub("VNML")) { - condLoad(flags, DATA_VNML, mLandData->mNormals, sizeof(mLandData->mNormals)); + void Land::blank() + { + mIsDeleted = false; } - if (mEsm->isNextSub("VHGT")) { - static VHGT vhgt; - if (condLoad(flags, DATA_VHGT, &vhgt, sizeof(vhgt))) { - float rowOffset = vhgt.mHeightOffset; - for (int y = 0; y < LAND_SIZE; y++) { - rowOffset += vhgt.mHeightData[y * LAND_SIZE]; + void Land::loadData(int flags) + { + // Try to load only available data + flags = flags & mDataTypes; + // Return if all required data is loaded + if ((mDataLoaded & flags) == flags) { + return; + } + // Create storage if nothing is loaded + if (mLandData == NULL) { + mLandData = new LandData; + mLandData->mDataTypes = mDataTypes; + } + mEsm->restoreContext(mContext); + + if (mEsm->isNextSub("VNML")) { + condLoad(flags, DATA_VNML, mLandData->mNormals, sizeof(mLandData->mNormals)); + } + + if (mEsm->isNextSub("VHGT")) { + static VHGT vhgt; + if (condLoad(flags, DATA_VHGT, &vhgt, sizeof(vhgt))) { + float rowOffset = vhgt.mHeightOffset; + for (int y = 0; y < LAND_SIZE; y++) { + rowOffset += vhgt.mHeightData[y * LAND_SIZE]; - mLandData->mHeights[y * LAND_SIZE] = rowOffset * HEIGHT_SCALE; + mLandData->mHeights[y * LAND_SIZE] = rowOffset * HEIGHT_SCALE; - float colOffset = rowOffset; - for (int x = 1; x < LAND_SIZE; x++) { - colOffset += vhgt.mHeightData[y * LAND_SIZE + x]; - mLandData->mHeights[x + y * LAND_SIZE] = colOffset * HEIGHT_SCALE; + float colOffset = rowOffset; + for (int x = 1; x < LAND_SIZE; x++) { + colOffset += vhgt.mHeightData[y * LAND_SIZE + x]; + mLandData->mHeights[x + y * LAND_SIZE] = colOffset * HEIGHT_SCALE; + } } + mLandData->mUnk1 = vhgt.mUnk1; + mLandData->mUnk2 = vhgt.mUnk2; } - mLandData->mUnk1 = vhgt.mUnk1; - mLandData->mUnk2 = vhgt.mUnk2; } - } - if (mEsm->isNextSub("WNAM")) { - condLoad(flags, DATA_WNAM, mLandData->mWnam, 81); - } - if (mEsm->isNextSub("VCLR")) - condLoad(flags, DATA_VCLR, mLandData->mColours, 3 * LAND_NUM_VERTS); - if (mEsm->isNextSub("VTEX")) { - static uint16_t vtex[LAND_NUM_TEXTURES]; - if (condLoad(flags, DATA_VTEX, vtex, sizeof(vtex))) { - LandData::transposeTextureData(vtex, mLandData->mTextures); + if (mEsm->isNextSub("WNAM")) { + condLoad(flags, DATA_WNAM, mLandData->mWnam, 81); + } + if (mEsm->isNextSub("VCLR")) + condLoad(flags, DATA_VCLR, mLandData->mColours, 3 * LAND_NUM_VERTS); + if (mEsm->isNextSub("VTEX")) { + static uint16_t vtex[LAND_NUM_TEXTURES]; + if (condLoad(flags, DATA_VTEX, vtex, sizeof(vtex))) { + LandData::transposeTextureData(vtex, mLandData->mTextures); + } } } -} -void Land::unloadData() -{ - if (mDataLoaded) + void Land::unloadData() { - delete mLandData; - mLandData = NULL; - mDataLoaded = 0; + if (mDataLoaded) + { + delete mLandData; + mLandData = NULL; + mDataLoaded = 0; + } } -} -bool Land::condLoad(int flags, int dataFlag, void *ptr, unsigned int size) -{ - if ((mDataLoaded & dataFlag) == 0 && (flags & dataFlag) != 0) { - mEsm->getHExact(ptr, size); - mDataLoaded |= dataFlag; - return true; + bool Land::condLoad(int flags, int dataFlag, void *ptr, unsigned int size) + { + if ((mDataLoaded & dataFlag) == 0 && (flags & dataFlag) != 0) { + mEsm->getHExact(ptr, size); + mDataLoaded |= dataFlag; + return true; + } + mEsm->skipHSubSize(size); + return false; } - mEsm->skipHSubSize(size); - return false; -} -bool Land::isDataLoaded(int flags) const -{ - return (mDataLoaded & flags) == (flags & mDataTypes); -} + bool Land::isDataLoaded(int flags) const + { + return (mDataLoaded & flags) == (flags & mDataTypes); + } } diff --git a/components/esm/loadland.hpp b/components/esm/loadland.hpp index 61ce4855e..d9ee0015a 100644 --- a/components/esm/loadland.hpp +++ b/components/esm/loadland.hpp @@ -97,10 +97,12 @@ struct Land LandData *mLandData; + bool mIsDeleted; + void load(ESMReader &esm); void save(ESMWriter &esm) const; - void blank() {} + void blank(); /** * Actually loads data diff --git a/components/esm/loadpgrd.cpp b/components/esm/loadpgrd.cpp index fc0974c9d..5e8de9d57 100644 --- a/components/esm/loadpgrd.cpp +++ b/components/esm/loadpgrd.cpp @@ -32,98 +32,137 @@ namespace ESM { } -void Pathgrid::load(ESMReader &esm) -{ - esm.getHNT(mData, "DATA", 12); - mCell = esm.getHNString("NAME"); + Pathgrid::Pathgrid() + : mIsDeleted(false) + {} - mPoints.clear(); - mEdges.clear(); + void Pathgrid::load(ESMReader &esm) + { + mPoints.clear(); + mEdges.clear(); - // keep track of total connections so we can reserve edge vector size - int edgeCount = 0; + // keep track of total connections so we can reserve edge vector size + int edgeCount = 0; - if (esm.isNextSub("PGRP")) - { - esm.getSubHeader(); - int size = esm.getSubSize(); - // Check that the sizes match up. Size = 16 * s2 (path points) - if (size != static_cast (sizeof(Point) * mData.mS2)) - esm.fail("Path point subrecord size mismatch"); - else + bool hasData = false; + bool hasName = false; + while (esm.hasMoreSubs()) { - int pointCount = mData.mS2; - mPoints.reserve(pointCount); - for (int i = 0; i < pointCount; ++i) + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) { - Point p; - esm.getExact(&p, sizeof(Point)); - mPoints.push_back(p); - edgeCount += p.mConnectionNum; + case ESM::FourCC<'D','A','T','A'>::value: + esm.getHT(mData, 12); + hasData = true; + break; + case ESM::FourCC<'N','A','M','E'>::value: + mCell = esm.getHString(); + hasName = true; + break; + case ESM::FourCC<'P','G','R','P'>::value: + { + esm.getSubHeader(); + int size = esm.getSubSize(); + // Check that the sizes match up. Size = 16 * s2 (path points) + if (size != static_cast (sizeof(Point) * mData.mS2)) + esm.fail("Path point subrecord size mismatch"); + else + { + int pointCount = mData.mS2; + mPoints.reserve(pointCount); + for (int i = 0; i < pointCount; ++i) + { + Point p; + esm.getExact(&p, sizeof(Point)); + mPoints.push_back(p); + edgeCount += p.mConnectionNum; + } + } + break; + } + case ESM::FourCC<'P','G','R','C'>::value: + { + esm.getSubHeader(); + int size = esm.getSubSize(); + if (size % sizeof(int) != 0) + esm.fail("PGRC size not a multiple of 4"); + else + { + int rawConnNum = size / sizeof(int); + std::vector rawConnections; + rawConnections.reserve(rawConnNum); + for (int i = 0; i < rawConnNum; ++i) + { + int currentValue; + esm.getT(currentValue); + rawConnections.push_back(currentValue); + } + + std::vector::const_iterator rawIt = rawConnections.begin(); + int pointIndex = 0; + mEdges.reserve(edgeCount); + for(PointList::const_iterator it = mPoints.begin(); it != mPoints.end(); ++it, ++pointIndex) + { + unsigned char connectionNum = (*it).mConnectionNum; + for (int i = 0; i < connectionNum; ++i) { + Edge edge; + edge.mV0 = pointIndex; + edge.mV1 = *rawIt; + ++rawIt; + mEdges.push_back(edge); + } + } + } + break; + } + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + mIsDeleted = true; + break; + default: + esm.fail("Unknown subrecord"); + break; } } + + if (!hasData) + esm.fail("Missing DATA subrecord"); + if (!hasName) + esm.fail("Missing NAME subrecord"); } - if (esm.isNextSub("PGRC")) + void Pathgrid::save(ESMWriter &esm) const { - esm.getSubHeader(); - int size = esm.getSubSize(); - if (size % sizeof(int) != 0) - esm.fail("PGRC size not a multiple of 4"); - else - { - int rawConnNum = size / sizeof(int); - std::vector rawConnections; - rawConnections.reserve(rawConnNum); - for (int i = 0; i < rawConnNum; ++i) - { - int currentValue; - esm.getT(currentValue); - rawConnections.push_back(currentValue); - } + esm.writeHNT("DATA", mData, 12); + esm.writeHNCString("NAME", mCell); - std::vector::const_iterator rawIt = rawConnections.begin(); - int pointIndex = 0; - mEdges.reserve(edgeCount); - for(PointList::const_iterator it = mPoints.begin(); it != mPoints.end(); ++it, ++pointIndex) - { - unsigned char connectionNum = (*it).mConnectionNum; - for (int i = 0; i < connectionNum; ++i) { - Edge edge; - edge.mV0 = pointIndex; - edge.mV1 = *rawIt; - ++rawIt; - mEdges.push_back(edge); - } - } + if (mIsDeleted) + { + esm.writeHNCString("DELE", ""); + return; } - } -} -void Pathgrid::save(ESMWriter &esm) const -{ - esm.writeHNT("DATA", mData, 12); - esm.writeHNCString("NAME", mCell); - if (!mPoints.empty()) - { - esm.startSubRecord("PGRP"); - for (PointList::const_iterator it = mPoints.begin(); it != mPoints.end(); ++it) + if (!mPoints.empty()) { - esm.writeT(*it); + esm.startSubRecord("PGRP"); + for (PointList::const_iterator it = mPoints.begin(); it != mPoints.end(); ++it) + { + esm.writeT(*it); + } + esm.endRecord("PGRP"); } - esm.endRecord("PGRP"); - } - if (!mEdges.empty()) - { - esm.startSubRecord("PGRC"); - for (std::vector::const_iterator it = mEdges.begin(); it != mEdges.end(); ++it) + if (!mEdges.empty()) { - esm.writeT(it->mV1); + esm.startSubRecord("PGRC"); + for (std::vector::const_iterator it = mEdges.begin(); it != mEdges.end(); ++it) + { + esm.writeT(it->mV1); + } + esm.endRecord("PGRC"); } - esm.endRecord("PGRC"); } -} void Pathgrid::blank() { @@ -134,5 +173,6 @@ void Pathgrid::save(ESMWriter &esm) const mData.mS2 = 0; mPoints.clear(); mEdges.clear(); + mIsDeleted = false; } } diff --git a/components/esm/loadpgrd.hpp b/components/esm/loadpgrd.hpp index f33ccbedf..4b82d9571 100644 --- a/components/esm/loadpgrd.hpp +++ b/components/esm/loadpgrd.hpp @@ -53,6 +53,10 @@ struct Pathgrid typedef std::vector EdgeList; EdgeList mEdges; + bool mIsDeleted; + + Pathgrid(); + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadrace.cpp b/components/esm/loadrace.cpp index 3feb06c92..12762bda3 100644 --- a/components/esm/loadrace.cpp +++ b/components/esm/loadrace.cpp @@ -8,6 +8,10 @@ namespace ESM { unsigned int Race::sRecordId = REC_RACE; + Race::Race() + : mIsDeleted(false) + {} + int Race::MaleFemale::getValue (bool male) const { return male ? mMale : mFemale; @@ -18,47 +22,65 @@ namespace ESM return static_cast(male ? mMale : mFemale); } -void Race::load(ESMReader &esm) -{ - mPowers.mList.clear(); + void Race::load(ESMReader &esm) + { + mPowers.mList.clear(); + mIsDeleted = false; - mId = esm.getHNString("NAME"); + bool hasName = false; + bool hasData = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'N','A','M','E'>::value: + mId = esm.getHString(); + hasName = true; + break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + mIsDeleted = true; + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'R','A','D','T'>::value: + esm.getHT(mData, 140); + hasData = true; + break; + case ESM::FourCC<'D','E','S','C'>::value: + mDescription = esm.getHString(); + break; + case ESM::FourCC<'N','P','C','S'>::value: + mPowers.add(esm); + break; + default: + esm.fail("Unknown subrecord"); + } + } - bool hasData = false; - while (esm.hasMoreSubs()) + if (!hasName) + esm.fail("Missing NAME subrecord"); + if (!hasData && !mIsDeleted) + esm.fail("Missing RADT subrecord"); + } + void Race::save(ESMWriter &esm) const { - esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + esm.writeHNCString("NAME", mId); + + if (mIsDeleted) { - case ESM::FourCC<'F','N','A','M'>::value: - mName = esm.getHString(); - break; - case ESM::FourCC<'R','A','D','T'>::value: - esm.getHT(mData, 140); - hasData = true; - break; - case ESM::FourCC<'D','E','S','C'>::value: - mDescription = esm.getHString(); - break; - case ESM::FourCC<'N','P','C','S'>::value: - mPowers.add(esm); - break; - default: - esm.fail("Unknown subrecord"); + esm.writeHNCString("DELE", ""); + return; } + + esm.writeHNOCString("FNAM", mName); + esm.writeHNT("RADT", mData, 140); + mPowers.save(esm); + esm.writeHNOString("DESC", mDescription); } - if (!hasData) - esm.fail("Missing RADT subrecord"); -} -void Race::save(ESMWriter &esm) const -{ - esm.writeHNCString("NAME", mId); - esm.writeHNOCString("FNAM", mName); - esm.writeHNT("RADT", mData, 140); - mPowers.save(esm); - esm.writeHNOString("DESC", mDescription); -} void Race::blank() { diff --git a/components/esm/loadrace.hpp b/components/esm/loadrace.hpp index 553d2e68b..e8e9a442b 100644 --- a/components/esm/loadrace.hpp +++ b/components/esm/loadrace.hpp @@ -68,6 +68,10 @@ struct Race std::string mId, mName, mDescription; SpellList mPowers; + bool mIsDeleted; + + Race(); + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadsscr.cpp b/components/esm/loadsscr.cpp index 7380dd0a7..076f73742 100644 --- a/components/esm/loadsscr.cpp +++ b/components/esm/loadsscr.cpp @@ -8,8 +8,14 @@ namespace ESM { unsigned int StartScript::sRecordId = REC_SSCR; + StartScript::StartScript() + : mIsDeleted(false) + {} + void StartScript::load(ESMReader &esm) { + mIsDeleted = false; + bool hasData = false; bool hasName = false; while (esm.hasMoreSubs()) @@ -26,10 +32,16 @@ namespace ESM mId = esm.getHString(); hasName = true; break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + mIsDeleted = true; + break; default: esm.fail("Unknown subrecord"); + break; } } + if (!hasData) esm.fail("Missing DATA"); if (!hasName) @@ -39,10 +51,16 @@ namespace ESM { esm.writeHNString("DATA", mData); esm.writeHNString("NAME", mId); + + if (mIsDeleted) + { + esm.writeHNCString("DELE", ""); + } } void StartScript::blank() { mData.clear(); + mIsDeleted = false; } } diff --git a/components/esm/loadsscr.hpp b/components/esm/loadsscr.hpp index dc7ad6a42..e475abd86 100644 --- a/components/esm/loadsscr.hpp +++ b/components/esm/loadsscr.hpp @@ -26,6 +26,10 @@ struct StartScript std::string mData; std::string mId; + bool mIsDeleted; + + StartScript(); + // Load a record and add it to the list void load(ESMReader &esm); void save(ESMWriter &esm) const; From 5fd48efd28e45336a03f5ee2f5b68f799159650e Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Thu, 16 Jul 2015 22:31:59 +0300 Subject: [PATCH 1884/3725] Some refactoring. Remove unused code --- apps/openmw/mwworld/store.cpp | 33 ++++- components/esm/loadbsgn.cpp | 1 - components/esm/loadcell.cpp | 258 +++++++++++++++++----------------- components/esm/loadlock.cpp | 1 + components/esm/loadltex.cpp | 2 +- components/esm/util.cpp | 75 ---------- components/esm/util.hpp | 47 ------- 7 files changed, 165 insertions(+), 252 deletions(-) delete mode 100644 components/esm/util.cpp diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index 8f55bb466..55fb43e00 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -194,7 +194,7 @@ namespace MWWorld if (inserted.second) mShared.push_back(&inserted.first->second); - return RecordId(record.mId, ESM::isRecordDeleted(record)); + return RecordId(record.mId, record.mIsDeleted); } template void Store::setUp() @@ -327,7 +327,7 @@ namespace MWWorld record.load (reader); insert (record); - return RecordId(record.mId, ESM::isRecordDeleted(record)); + return RecordId(record.mId, record.mIsDeleted); } // LandTexture @@ -1083,6 +1083,35 @@ namespace MWWorld return RecordId(script.mId); } + + // GameSetting + // Need to specialize load() and read() methods, because GameSetting can't + // be deleted (has no mIsDeleted flag) + //========================================================================= + + template <> + inline RecordId Store::load(ESM::ESMReader &reader) + { + ESM::GameSetting setting; + setting.load(reader); + Misc::StringUtils::toLower(setting.mId); + + std::pair inserted = mStatic.insert(std::make_pair(setting.mId, setting)); + if (inserted.second) + mShared.push_back(&inserted.first->second); + + return RecordId(setting.mId); + } + + template <> + inline RecordId Store::read(ESM::ESMReader &reader) + { + ESM::GameSetting setting; + setting.load(reader); + insert(setting); + + return RecordId(setting.mId); + } } template class MWWorld::Store; diff --git a/components/esm/loadbsgn.cpp b/components/esm/loadbsgn.cpp index 9f5cd7270..54de009aa 100644 --- a/components/esm/loadbsgn.cpp +++ b/components/esm/loadbsgn.cpp @@ -3,7 +3,6 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" -#include "util.hpp" namespace ESM { diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index 67701a5b7..7e02f0f85 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -12,7 +12,6 @@ #include "esmwriter.hpp" #include "defs.hpp" #include "cellid.hpp" -#include "util.hpp" namespace { @@ -53,171 +52,178 @@ namespace ESM return ref.mRefNum == refNum; } -void Cell::load(ESMReader &esm, bool saveContext) -{ - loadName(esm); - loadData(esm); - loadCell(esm, saveContext); -} + void Cell::load(ESMReader &esm, bool saveContext) + { + loadName(esm); + loadData(esm); + loadCell(esm, saveContext); + } -void Cell::loadName(ESMReader &esm) -{ - mName = esm.getHNString("NAME"); - mIsDeleted = readDeleSubRecord(esm); -} + void Cell::loadName(ESMReader &esm) + { + mName = esm.getHNString("NAME"); -void Cell::loadCell(ESMReader &esm, bool saveContext) -{ - mRefNumCounter = 0; + mIsDeleted = false; + if (esm.isNextSub("DELE")) + { + esm.skipHSub(); + mIsDeleted = true; + } + } - if (mData.mFlags & Interior) + void Cell::loadCell(ESMReader &esm, bool saveContext) { - // Interior cells - if (esm.isNextSub("INTV")) + mRefNumCounter = 0; + + if (mData.mFlags & Interior) { - int waterl; - esm.getHT(waterl); - mWater = (float) waterl; - mWaterInt = true; + // Interior cells + if (esm.isNextSub("INTV")) + { + int waterl; + esm.getHT(waterl); + mWater = (float) waterl; + mWaterInt = true; + } + else if (esm.isNextSub("WHGT")) + { + esm.getHT(mWater); + } + + // Quasi-exterior cells have a region (which determines the + // weather), pure interior cells have ambient lighting + // instead. + if (mData.mFlags & QuasiEx) + mRegion = esm.getHNOString("RGNN"); + else if (esm.isNextSub("AMBI")) + esm.getHT(mAmbi); } - else if (esm.isNextSub("WHGT")) + else { - esm.getHT(mWater); + // Exterior cells + mRegion = esm.getHNOString("RGNN"); + + mMapColor = 0; + esm.getHNOT(mMapColor, "NAM5"); + } + if (esm.isNextSub("NAM0")) { + esm.getHT(mRefNumCounter); } - // Quasi-exterior cells have a region (which determines the - // weather), pure interior cells have ambient lighting - // instead. - if (mData.mFlags & QuasiEx) - mRegion = esm.getHNOString("RGNN"); - else if (esm.isNextSub("AMBI")) - esm.getHT(mAmbi); + if (saveContext) { + mContextList.push_back(esm.getContext()); + esm.skipRecord(); + } } - else - { - // Exterior cells - mRegion = esm.getHNOString("RGNN"); - mMapColor = 0; - esm.getHNOT(mMapColor, "NAM5"); - } - if (esm.isNextSub("NAM0")) { - esm.getHT(mRefNumCounter); + void Cell::loadData(ESMReader &esm) + { + esm.getHNT(mData, "DATA", 12); } - if (saveContext) { + void Cell::postLoad(ESMReader &esm) + { + // Save position of the cell references and move on mContextList.push_back(esm.getContext()); esm.skipRecord(); } -} -void Cell::loadData(ESMReader &esm) -{ - esm.getHNT(mData, "DATA", 12); -} - -void Cell::postLoad(ESMReader &esm) -{ - // Save position of the cell references and move on - mContextList.push_back(esm.getContext()); - esm.skipRecord(); -} - -void Cell::save(ESMWriter &esm) const -{ - esm.writeHNCString("NAME", mName); - if (mIsDeleted) + void Cell::save(ESMWriter &esm) const { - writeDeleSubRecord(esm); - } + esm.writeHNCString("NAME", mName); - esm.writeHNT("DATA", mData, 12); - if (mData.mFlags & Interior) - { - if (mWaterInt) { - int water = - (mWater >= 0) ? (int) (mWater + 0.5) : (int) (mWater - 0.5); - esm.writeHNT("INTV", water); - } else { - esm.writeHNT("WHGT", mWater); + if (mIsDeleted) + { + esm.writeHNCString("DELE", ""); } - if (mData.mFlags & QuasiEx) - esm.writeHNOCString("RGNN", mRegion); + esm.writeHNT("DATA", mData, 12); + if (mData.mFlags & Interior) + { + if (mWaterInt) { + int water = + (mWater >= 0) ? (int) (mWater + 0.5) : (int) (mWater - 0.5); + esm.writeHNT("INTV", water); + } else { + esm.writeHNT("WHGT", mWater); + } + + if (mData.mFlags & QuasiEx) + esm.writeHNOCString("RGNN", mRegion); + else + esm.writeHNT("AMBI", mAmbi, 16); + } else - esm.writeHNT("AMBI", mAmbi, 16); - } - else - { - esm.writeHNOCString("RGNN", mRegion); - if (mMapColor != 0) - esm.writeHNT("NAM5", mMapColor); - } - - if (mRefNumCounter != 0 && !mIsDeleted) - esm.writeHNT("NAM0", mRefNumCounter); -} - -void Cell::restore(ESMReader &esm, int iCtx) const -{ - esm.restoreContext(mContextList.at (iCtx)); -} + { + esm.writeHNOCString("RGNN", mRegion); + if (mMapColor != 0) + esm.writeHNT("NAM5", mMapColor); + } -std::string Cell::getDescription() const -{ - if (mData.mFlags & Interior) - { - return mName; + if (mRefNumCounter != 0) + esm.writeHNT("NAM0", mRefNumCounter); } - else + + void Cell::restore(ESMReader &esm, int iCtx) const { - std::ostringstream stream; - stream << mData.mX << ", " << mData.mY; - return stream.str(); + esm.restoreContext(mContextList.at (iCtx)); } -} -bool Cell::getNextRef(ESMReader &esm, CellRef &ref, bool ignoreMoves, MovedCellRef *mref) -{ - // TODO: Try and document reference numbering, I don't think this has been done anywhere else. - if (!esm.hasMoreSubs()) - return false; - - // NOTE: We should not need this check. It is a safety check until we have checked - // more plugins, and how they treat these moved references. - if (esm.isNextSub("MVRF")) + std::string Cell::getDescription() const { - if (ignoreMoves) + if (mData.mFlags & Interior) { - esm.getHT (mref->mRefNum.mIndex); - esm.getHNOT (mref->mTarget, "CNDT"); - adjustRefNum (mref->mRefNum, esm); + return mName; } else { - // skip rest of cell record (moved references), they are handled elsewhere - esm.skipRecord(); // skip MVRF, CNDT - return false; + std::ostringstream stream; + stream << mData.mX << ", " << mData.mY; + return stream.str(); } } - ref.load (esm); + bool Cell::getNextRef(ESMReader &esm, CellRef &ref, bool ignoreMoves, MovedCellRef *mref) + { + // TODO: Try and document reference numbering, I don't think this has been done anywhere else. + if (!esm.hasMoreSubs()) + return false; - // Identify references belonging to a parent file and adapt the ID accordingly. - adjustRefNum (ref.mRefNum, esm); + // NOTE: We should not need this check. It is a safety check until we have checked + // more plugins, and how they treat these moved references. + if (esm.isNextSub("MVRF")) + { + if (ignoreMoves) + { + esm.getHT (mref->mRefNum.mIndex); + esm.getHNOT (mref->mTarget, "CNDT"); + adjustRefNum (mref->mRefNum, esm); + } + else + { + // skip rest of cell record (moved references), they are handled elsewhere + esm.skipRecord(); // skip MVRF, CNDT + return false; + } + } - return true; -} + ref.load (esm); -bool Cell::getNextMVRF(ESMReader &esm, MovedCellRef &mref) -{ - esm.getHT(mref.mRefNum.mIndex); - esm.getHNOT(mref.mTarget, "CNDT"); + // Identify references belonging to a parent file and adapt the ID accordingly. + adjustRefNum (ref.mRefNum, esm); - adjustRefNum (mref.mRefNum, esm); + return true; + } - return true; -} + bool Cell::getNextMVRF(ESMReader &esm, MovedCellRef &mref) + { + esm.getHT(mref.mRefNum.mIndex); + esm.getHNOT(mref.mTarget, "CNDT"); + + adjustRefNum (mref.mRefNum, esm); + + return true; + } void Cell::blank() { diff --git a/components/esm/loadlock.cpp b/components/esm/loadlock.cpp index 5ee041dab..2cfe43743 100644 --- a/components/esm/loadlock.cpp +++ b/components/esm/loadlock.cpp @@ -26,6 +26,7 @@ namespace ESM { case ESM::FourCC<'N','A','M','E'>::value: mId = esm.getHString(); + hasName = true; break; case ESM::FourCC<'D','E','L','E'>::value: esm.skipHSub(); diff --git a/components/esm/loadltex.cpp b/components/esm/loadltex.cpp index 7c14536ed..6bd48d801 100644 --- a/components/esm/loadltex.cpp +++ b/components/esm/loadltex.cpp @@ -26,7 +26,7 @@ namespace ESM { case ESM::FourCC<'N','A','M','E'>::value: mId = esm.getHString(); - hasName = false; + hasName = true; break; case ESM::FourCC<'D','E','L','E'>::value: esm.skipHSub(); diff --git a/components/esm/util.cpp b/components/esm/util.cpp deleted file mode 100644 index a5ec377a3..000000000 --- a/components/esm/util.cpp +++ /dev/null @@ -1,75 +0,0 @@ -#include "util.hpp" - -#include - -namespace ESM -{ - bool readDeleSubRecord(ESMReader &esm) - { - if (esm.isNextSub("DELE")) - { - esm.skipHSub(); - return true; - } - return false; - } - - void writeDeleSubRecord(ESMWriter &esm) - { - esm.writeHNT("DELE", static_cast(0)); - } - - template <> - bool isRecordDeleted(const StartScript &script) - { - return false; - } - - template <> - bool isRecordDeleted(const Race &race) - { - return false; - } - - template <> - bool isRecordDeleted(const GameSetting &gmst) - { - return false; - } - - template <> - bool isRecordDeleted(const Skill &skill) - { - return false; - } - - template <> - bool isRecordDeleted(const MagicEffect &mgef) - { - return false; - } - - template <> - bool isRecordDeleted(const Pathgrid &pgrd) - { - return false; - } - - template <> - bool isRecordDeleted(const Land &land) - { - return false; - } - - template <> - bool isRecordDeleted(const DebugProfile &profile) - { - return false; - } - - template <> - bool isRecordDeleted(const Filter &filter) - { - return false; - } -} diff --git a/components/esm/util.hpp b/components/esm/util.hpp index 531e7eb76..e16603b84 100644 --- a/components/esm/util.hpp +++ b/components/esm/util.hpp @@ -8,16 +8,6 @@ #include "esmreader.hpp" #include "esmwriter.hpp" -#include "loadsscr.hpp" -#include "loadglob.hpp" -#include "loadrace.hpp" -#include "loadgmst.hpp" -#include "loadskil.hpp" -#include "loadmgef.hpp" -#include "loadland.hpp" -#include "loadpgrd.hpp" -#include "debugprofile.hpp" -#include "filter.hpp" namespace ESM { @@ -63,43 +53,6 @@ struct Vector3 } }; -bool readDeleSubRecord(ESMReader &esm); -void writeDeleSubRecord(ESMWriter &esm); - -template -bool isRecordDeleted(const RecordT &record) -{ - return record.mIsDeleted; -} - -// The following records can't be deleted (for now) -template <> -bool isRecordDeleted(const StartScript &script); - -template <> -bool isRecordDeleted(const Race &race); - -template <> -bool isRecordDeleted(const GameSetting &gmst); - -template <> -bool isRecordDeleted(const Skill &skill); - -template <> -bool isRecordDeleted(const MagicEffect &mgef); - -template <> -bool isRecordDeleted(const Pathgrid &pgrd); - -template <> -bool isRecordDeleted(const Land &land); - -template <> -bool isRecordDeleted(const DebugProfile &profile); - -template <> -bool isRecordDeleted(const Filter &filter); - } #endif From a4d3e59e5c7380ffb27b4d17d4574009e2b45379 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sat, 18 Jul 2015 15:55:24 +0300 Subject: [PATCH 1885/3725] Add a separate method to check whether a record is deleted or not for IdCollection --- apps/opencs/model/world/idcollection.cpp | 3 +++ apps/opencs/model/world/idcollection.hpp | 4 ++-- apps/opencs/model/world/land.hpp | 10 ---------- apps/opencs/model/world/pathgrid.hpp | 10 ---------- apps/opencs/model/world/record.cpp | 24 ++++++++++++++++++++++++ apps/opencs/model/world/record.hpp | 23 +++++++++++++++++++++++ 6 files changed, 52 insertions(+), 22 deletions(-) create mode 100644 apps/opencs/model/world/idcollection.cpp diff --git a/apps/opencs/model/world/idcollection.cpp b/apps/opencs/model/world/idcollection.cpp new file mode 100644 index 000000000..9571ed773 --- /dev/null +++ b/apps/opencs/model/world/idcollection.cpp @@ -0,0 +1,3 @@ +#include "idcollection.hpp" + + diff --git a/apps/opencs/model/world/idcollection.hpp b/apps/opencs/model/world/idcollection.hpp index d08abce5b..4acfdc474 100644 --- a/apps/opencs/model/world/idcollection.hpp +++ b/apps/opencs/model/world/idcollection.hpp @@ -2,9 +2,9 @@ #define CSM_WOLRD_IDCOLLECTION_H #include -#include #include "collection.hpp" +#include "record.hpp" namespace CSMWorld { @@ -48,7 +48,7 @@ namespace CSMWorld std::string id = IdAccessorT().getId (record); int index = searchId (id); - if (ESM::isRecordDeleted (record)) + if (isRecordDeleted(record)) { if (index==-1) { diff --git a/apps/opencs/model/world/land.hpp b/apps/opencs/model/world/land.hpp index adf5c0331..e97a2d7dd 100644 --- a/apps/opencs/model/world/land.hpp +++ b/apps/opencs/model/world/land.hpp @@ -4,7 +4,6 @@ #include #include #include -#include namespace CSMWorld { @@ -27,13 +26,4 @@ namespace CSMWorld }; } -namespace ESM -{ - template <> - bool isRecordDeleted(const CSMWorld::Land &land) - { - return false; - } -} - #endif diff --git a/apps/opencs/model/world/pathgrid.hpp b/apps/opencs/model/world/pathgrid.hpp index cd5e472c8..7e7b7c3bb 100644 --- a/apps/opencs/model/world/pathgrid.hpp +++ b/apps/opencs/model/world/pathgrid.hpp @@ -5,7 +5,6 @@ #include #include -#include namespace CSMWorld { @@ -27,13 +26,4 @@ namespace CSMWorld }; } -namespace ESM -{ - template <> - bool isRecordDeleted(const CSMWorld::Pathgrid &pgrd) - { - return false; - } -} - #endif diff --git a/apps/opencs/model/world/record.cpp b/apps/opencs/model/world/record.cpp index ef2f4d320..87f5090fe 100644 --- a/apps/opencs/model/world/record.cpp +++ b/apps/opencs/model/world/record.cpp @@ -19,3 +19,27 @@ bool CSMWorld::RecordBase::isModified() const { return mState==State_Modified || mState==State_ModifiedOnly; } + +template<> +bool CSMWorld::isRecordDeleted(const CSMWorld::Land &land) +{ + return land.mLand->mIsDeleted; +} + +template<> +bool CSMWorld::isRecordDeleted(const ESM::GameSetting &setting) +{ + return false; +} + +template<> +bool CSMWorld::isRecordDeleted(const ESM::MagicEffect &effect) +{ + return false; +} + +template<> +bool CSMWorld::isRecordDeleted(const ESM::Skill &skill) +{ + return false; +} diff --git a/apps/opencs/model/world/record.hpp b/apps/opencs/model/world/record.hpp index 3362f9f96..c43a8b6ca 100644 --- a/apps/opencs/model/world/record.hpp +++ b/apps/opencs/model/world/record.hpp @@ -3,6 +3,12 @@ #include +#include +#include +#include + +#include "land.hpp" + namespace CSMWorld { struct RecordBase @@ -154,6 +160,23 @@ namespace CSMWorld mState = State_Erased; } } + + // Not all records can be deleted (may be changed in the future), + // so we need to use a separate method to check whether a record is deleted or not. + template + bool isRecordDeleted(const ESXRecordT &record) + { + return record.mIsDeleted; + } + + template<> + bool isRecordDeleted(const Land &land); + template<> + bool isRecordDeleted(const ESM::GameSetting &setting); + template<> + bool isRecordDeleted(const ESM::MagicEffect &effect); + template<> + bool isRecordDeleted(const ESM::Skill &skill); } #endif From e04e32bcffa3c95f7c2a007d5fcf09641fff0b03 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sat, 18 Jul 2015 20:32:10 +0300 Subject: [PATCH 1886/3725] Delete infos of deleted dialogue when loading a content file --- apps/opencs/model/world/data.cpp | 4 +-- apps/opencs/model/world/infocollection.cpp | 36 ++++++++++++++++++++++ apps/opencs/model/world/infocollection.hpp | 2 ++ 3 files changed, 40 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 348656a7c..91ccda73c 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -998,11 +998,11 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Messages& messages) if (mJournals.tryDelete (record.mId)) { - /// \todo handle info records + mJournalInfos.removeDialogueInfos(record.mId); } else if (mTopics.tryDelete (record.mId)) { - /// \todo handle info records + mTopicInfos.removeDialogueInfos(record.mId); } else { diff --git a/apps/opencs/model/world/infocollection.cpp b/apps/opencs/model/world/infocollection.cpp index 1b95c1505..665b497d0 100644 --- a/apps/opencs/model/world/infocollection.cpp +++ b/apps/opencs/model/world/infocollection.cpp @@ -188,3 +188,39 @@ CSMWorld::InfoCollection::Range CSMWorld::InfoCollection::getTopicRange (const s return Range (begin, end); } + +void CSMWorld::InfoCollection::removeDialogueInfos(const std::string& dialogueId) +{ + std::string id = Misc::StringUtils::lowerCase(dialogueId); + std::vector erasedRecords; + + std::map::const_iterator current = getIdMap().lower_bound(id); + std::map::const_iterator end = getIdMap().end(); + for (; current != end; ++current) + { + Record record = getRecord(current->second); + + if (Misc::StringUtils::ciEqual(dialogueId, record.get().mTopicId)) + { + if (record.mState == RecordBase::State_ModifiedOnly) + { + erasedRecords.push_back(current->second); + } + else + { + record.mState = RecordBase::State_Deleted; + setRecord(current->second, record); + } + } + else + { + break; + } + } + + while (!erasedRecords.empty()) + { + removeRows(erasedRecords.back(), 1); + erasedRecords.pop_back(); + } +} diff --git a/apps/opencs/model/world/infocollection.hpp b/apps/opencs/model/world/infocollection.hpp index 6db47373d..e5a5575c7 100644 --- a/apps/opencs/model/world/infocollection.hpp +++ b/apps/opencs/model/world/infocollection.hpp @@ -44,6 +44,8 @@ namespace CSMWorld Range getTopicRange (const std::string& topic) const; ///< Return iterators that point to the beginning and past the end of the range for /// the given topic. + + void removeDialogueInfos(const std::string& dialogueId); }; } From 8e6a7be6f543a112c6aa3e814f572a9d2839ab15 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sun, 19 Jul 2015 11:42:05 +0300 Subject: [PATCH 1887/3725] Implement saving of deleted records --- apps/opencs/model/doc/savingstages.cpp | 176 ++++++++++--------------- apps/opencs/model/doc/savingstages.hpp | 26 ++-- apps/opencs/model/world/collection.hpp | 6 + apps/opencs/model/world/record.cpp | 24 ++++ apps/opencs/model/world/record.hpp | 16 +++ 5 files changed, 125 insertions(+), 123 deletions(-) diff --git a/apps/opencs/model/doc/savingstages.cpp b/apps/opencs/model/doc/savingstages.cpp index f78c57ecd..dbfa4651b 100644 --- a/apps/opencs/model/doc/savingstages.cpp +++ b/apps/opencs/model/doc/savingstages.cpp @@ -100,84 +100,72 @@ int CSMDoc::WriteDialogueCollectionStage::setup() void CSMDoc::WriteDialogueCollectionStage::perform (int stage, Messages& messages) { + ESM::ESMWriter& writer = mState.getWriter(); const CSMWorld::Record& topic = mTopics.getRecord (stage); - CSMWorld::RecordBase::State state = topic.mState; - - if (state==CSMWorld::RecordBase::State_Deleted) + if (topic.mState == CSMWorld::RecordBase::State_Deleted) { // if the topic is deleted, we do not need to bother with INFO records. + ESM::Dialogue dialogue = topic.get(); + dialogue.mIsDeleted = true; - /// \todo wrote record with delete flag - + writer.startRecord(dialogue.sRecordId); + dialogue.save(writer); + writer.endRecord(dialogue.sRecordId); return; } // Test, if we need to save anything associated info records. bool infoModified = false; - CSMWorld::InfoCollection::Range range = mInfos.getTopicRange (topic.get().mId); for (CSMWorld::InfoCollection::RecordConstIterator iter (range.first); iter!=range.second; ++iter) { - CSMWorld::RecordBase::State state = iter->mState; - - if (state==CSMWorld::RecordBase::State_Modified || - state==CSMWorld::RecordBase::State_ModifiedOnly || - state==CSMWorld::RecordBase::State_Deleted) + if (topic.isModified() || iter->mState == CSMWorld::RecordBase::State_Deleted) { infoModified = true; break; } } - if (state==CSMWorld::RecordBase::State_Modified || - state==CSMWorld::RecordBase::State_ModifiedOnly || - infoModified) + if (topic.isModified() || infoModified) { - mState.getWriter().startRecord (topic.mModified.sRecordId); - mState.getWriter().writeHNCString ("NAME", topic.mModified.mId); - topic.mModified.save (mState.getWriter()); - mState.getWriter().endRecord (topic.mModified.sRecordId); + ESM::Dialogue dialogue = topic.get(); + + writer.startRecord (dialogue.sRecordId); + dialogue.save (writer); + writer.endRecord (dialogue.sRecordId); // write modified selected info records - for (CSMWorld::InfoCollection::RecordConstIterator iter (range.first); iter!=range.second; - ++iter) + for (CSMWorld::InfoCollection::RecordConstIterator iter (range.first); iter!=range.second; ++iter) { - CSMWorld::RecordBase::State state = iter->mState; - - if (state==CSMWorld::RecordBase::State_Deleted) - { - /// \todo wrote record with delete flag - } - else if (state==CSMWorld::RecordBase::State_Modified || - state==CSMWorld::RecordBase::State_ModifiedOnly) + if (iter->isModified() || iter->mState == CSMWorld::RecordBase::State_Deleted) { ESM::DialInfo info = iter->get(); info.mId = info.mId.substr (info.mId.find_last_of ('#')+1); + info.mIsDeleted = (iter->mState == CSMWorld::RecordBase::State_Deleted); + info.mPrev = ""; if (iter!=range.first) { CSMWorld::InfoCollection::RecordConstIterator prev = iter; --prev; - info.mPrev = - prev->mModified.mId.substr (prev->mModified.mId.find_last_of ('#')+1); + info.mPrev = prev->get().mId.substr (prev->get().mId.find_last_of ('#')+1); } CSMWorld::InfoCollection::RecordConstIterator next = iter; ++next; + info.mNext = ""; if (next!=range.second) { - info.mNext = - next->mModified.mId.substr (next->mModified.mId.find_last_of ('#')+1); + info.mNext = next->get().mId.substr (next->get().mId.find_last_of ('#')+1); } - mState.getWriter().startRecord (info.sRecordId); - mState.getWriter().writeHNCString ("INAM", info.mId); - info.save (mState.getWriter()); - mState.getWriter().endRecord (info.sRecordId); + writer.startRecord (info.sRecordId); + info.save (writer); + writer.endRecord (info.sRecordId); } } } @@ -269,36 +257,35 @@ int CSMDoc::WriteCellCollectionStage::setup() void CSMDoc::WriteCellCollectionStage::perform (int stage, Messages& messages) { - const CSMWorld::Record& cell = - mDocument.getData().getCells().getRecord (stage); + ESM::ESMWriter& writer = mState.getWriter(); + const CSMWorld::Record& cell = mDocument.getData().getCells().getRecord (stage); std::map >::const_iterator references = mState.getSubRecords().find (Misc::StringUtils::lowerCase (cell.get().mId)); - if (cell.mState==CSMWorld::RecordBase::State_Modified || - cell.mState==CSMWorld::RecordBase::State_ModifiedOnly || + if (cell.isModified() || + cell.mState == CSMWorld::RecordBase::State_Deleted || references!=mState.getSubRecords().end()) { - bool interior = cell.get().mId.substr (0, 1)!="#"; + CSMWorld::Cell cellRecord = cell.get(); + bool interior = cellRecord.mId.substr (0, 1)!="#"; // write cell data - mState.getWriter().startRecord (cell.mModified.sRecordId); - - mState.getWriter().writeHNOCString ("NAME", cell.get().mName); - - ESM::Cell cell2 = cell.get(); + writer.startRecord (cellRecord.sRecordId); if (interior) - cell2.mData.mFlags |= ESM::Cell::Interior; + cellRecord.mData.mFlags |= ESM::Cell::Interior; else { - cell2.mData.mFlags &= ~ESM::Cell::Interior; + cellRecord.mData.mFlags &= ~ESM::Cell::Interior; - std::istringstream stream (cell.get().mId.c_str()); + std::istringstream stream (cellRecord.mId.c_str()); char ignore; - stream >> ignore >> cell2.mData.mX >> cell2.mData.mY; + stream >> ignore >> cellRecord.mData.mX >> cellRecord.mData.mY; } - cell2.save (mState.getWriter()); + + cellRecord.mIsDeleted = (cell.mState == CSMWorld::RecordBase::State_Deleted); + cellRecord.save (writer); // write references if (references!=mState.getSubRecords().end()) @@ -309,24 +296,25 @@ void CSMDoc::WriteCellCollectionStage::perform (int stage, Messages& messages) const CSMWorld::Record& ref = mDocument.getData().getReferences().getRecord (*iter); - if (ref.mState==CSMWorld::RecordBase::State_Modified || - ref.mState==CSMWorld::RecordBase::State_ModifiedOnly) + if (ref.isModified() || ref.mState == CSMWorld::RecordBase::State_Deleted) { + CSMWorld::CellRef refRecord = ref.get(); + // recalculate the ref's cell location std::ostringstream stream; if (!interior) { - std::pair index = ref.get().getCellIndex(); + std::pair index = refRecord.getCellIndex(); stream << "#" << index.first << " " << index.second; } // An empty mOriginalCell is meant to indicate that it is the same as // the current cell. It is possible that a moved ref is moved again. - if ((ref.get().mOriginalCell.empty() ? ref.get().mCell : ref.get().mOriginalCell) + if ((refRecord.mOriginalCell.empty() ? refRecord.mCell : refRecord.mOriginalCell) != stream.str() && !interior) { ESM::MovedCellRef moved; - moved.mRefNum = ref.get().mRefNum; + moved.mRefNum = refRecord.mRefNum; // Need to fill mTarget with the ref's new position. std::istringstream istream (stream.str().c_str()); @@ -334,24 +322,17 @@ void CSMDoc::WriteCellCollectionStage::perform (int stage, Messages& messages) char ignore; istream >> ignore >> moved.mTarget[0] >> moved.mTarget[1]; - ref.get().mRefNum.save (mState.getWriter(), false, "MVRF"); - mState.getWriter().writeHNT ("CNDT", moved.mTarget, 8); + refRecord.mRefNum.save (writer, false, "MVRF"); + writer.writeHNT ("CNDT", moved.mTarget, 8); } - ref.get().save (mState.getWriter()); - } - else if (ref.mState==CSMWorld::RecordBase::State_Deleted) - { - /// \todo write record with delete flag + refRecord.mIsDeleted = (ref.mState == CSMWorld::RecordBase::State_Deleted); + refRecord.save (writer); } } } - mState.getWriter().endRecord (cell.mModified.sRecordId); - } - else if (cell.mState==CSMWorld::RecordBase::State_Deleted) - { - /// \todo write record with delete flag + writer.endRecord (cellRecord.sRecordId); } } @@ -368,11 +349,11 @@ int CSMDoc::WritePathgridCollectionStage::setup() void CSMDoc::WritePathgridCollectionStage::perform (int stage, Messages& messages) { - const CSMWorld::Record& pathgrid = + ESM::ESMWriter& writer = mState.getWriter(); + const CSMWorld::Record& pathgrid = mDocument.getData().getPathgrids().getRecord (stage); - if (pathgrid.mState==CSMWorld::RecordBase::State_Modified || - pathgrid.mState==CSMWorld::RecordBase::State_ModifiedOnly) + if (pathgrid.isModified() || pathgrid.mState == CSMWorld::RecordBase::State_Deleted) { CSMWorld::Pathgrid record = pathgrid.get(); @@ -385,15 +366,10 @@ void CSMDoc::WritePathgridCollectionStage::perform (int stage, Messages& message else record.mCell = record.mId; - mState.getWriter().startRecord (record.sRecordId); - - record.save (mState.getWriter()); - - mState.getWriter().endRecord (record.sRecordId); - } - else if (pathgrid.mState==CSMWorld::RecordBase::State_Deleted) - { - /// \todo write record with delete flag + record.mIsDeleted = (pathgrid.mState == CSMWorld::RecordBase::State_Deleted); + writer.startRecord (record.sRecordId); + record.save (writer); + writer.endRecord (record.sRecordId); } } @@ -410,25 +386,18 @@ int CSMDoc::WriteLandCollectionStage::setup() void CSMDoc::WriteLandCollectionStage::perform (int stage, Messages& messages) { - const CSMWorld::Record& land = + ESM::ESMWriter& writer = mState.getWriter(); + const CSMWorld::Record& land = mDocument.getData().getLand().getRecord (stage); - if (land.mState==CSMWorld::RecordBase::State_Modified || - land.mState==CSMWorld::RecordBase::State_ModifiedOnly) + if (land.isModified() || land.mState == CSMWorld::RecordBase::State_Deleted) { CSMWorld::Land record = land.get(); - mState.getWriter().startRecord (record.mLand->sRecordId); - - record.mLand->save (mState.getWriter()); - if(record.mLand->mLandData) - record.mLand->mLandData->save (mState.getWriter()); - - mState.getWriter().endRecord (record.mLand->sRecordId); - } - else if (land.mState==CSMWorld::RecordBase::State_Deleted) - { - /// \todo write record with delete flag + record.mLand->mIsDeleted = (land.mState == CSMWorld::RecordBase::State_Deleted); + writer.startRecord (record.mLand->sRecordId); + record.mLand->save (writer); + writer.endRecord (record.mLand->sRecordId); } } @@ -445,23 +414,18 @@ int CSMDoc::WriteLandTextureCollectionStage::setup() void CSMDoc::WriteLandTextureCollectionStage::perform (int stage, Messages& messages) { - const CSMWorld::Record& landTexture = + ESM::ESMWriter& writer = mState.getWriter(); + const CSMWorld::Record& landTexture = mDocument.getData().getLandTextures().getRecord (stage); - if (landTexture.mState==CSMWorld::RecordBase::State_Modified || - landTexture.mState==CSMWorld::RecordBase::State_ModifiedOnly) + if (landTexture.isModified() || landTexture.mState == CSMWorld::RecordBase::State_Deleted) { CSMWorld::LandTexture record = landTexture.get(); + record.mIsDeleted = (landTexture.mState == CSMWorld::RecordBase::State_Deleted); - mState.getWriter().startRecord (record.sRecordId); - - record.save (mState.getWriter()); - - mState.getWriter().endRecord (record.sRecordId); - } - else if (landTexture.mState==CSMWorld::RecordBase::State_Deleted) - { - /// \todo write record with delete flag + writer.startRecord (record.sRecordId); + record.save (writer); + writer.endRecord (record.sRecordId); } } diff --git a/apps/opencs/model/doc/savingstages.hpp b/apps/opencs/model/doc/savingstages.hpp index 188f22f96..9dbb5bee3 100644 --- a/apps/opencs/model/doc/savingstages.hpp +++ b/apps/opencs/model/doc/savingstages.hpp @@ -100,26 +100,18 @@ namespace CSMDoc if (CSMWorld::getScopeFromId (mCollection.getRecord (stage).get().mId)!=mScope) return; + ESM::ESMWriter& writer = mState.getWriter(); CSMWorld::RecordBase::State state = mCollection.getRecord (stage).mState; + CollectionT::ESXRecord record = mCollection.getRecord (stage).get(); - if (state==CSMWorld::RecordBase::State_Modified || - state==CSMWorld::RecordBase::State_ModifiedOnly) + if (state == CSMWorld::RecordBase::State_Modified || + state == CSMWorld::RecordBase::State_ModifiedOnly || + state == CSMWorld::RecordBase::State_Deleted) { - // FIXME: A quick Workaround to support records which should not write - // NAME, including SKIL, MGEF and SCPT. If there are many more - // idcollection records that doesn't use NAME then a more generic - // solution may be required. - uint32_t name = mCollection.getRecord (stage).mModified.sRecordId; - mState.getWriter().startRecord (name); - - if(name != ESM::REC_SKIL && name != ESM::REC_MGEF && name != ESM::REC_SCPT) - mState.getWriter().writeHNCString ("NAME", mCollection.getId (stage)); - mCollection.getRecord (stage).mModified.save (mState.getWriter()); - mState.getWriter().endRecord (mCollection.getRecord (stage).mModified.sRecordId); - } - else if (state==CSMWorld::RecordBase::State_Deleted) - { - /// \todo write record with delete flag + CSMWorld::setRecordDeleted (record, state == CSMWorld::RecordBase::State_Deleted); + writer.startRecord (record.sRecordId); + record.save (writer); + writer.endRecord (record.sRecordId); } } diff --git a/apps/opencs/model/world/collection.hpp b/apps/opencs/model/world/collection.hpp index b0571bbed..16f5ce51f 100644 --- a/apps/opencs/model/world/collection.hpp +++ b/apps/opencs/model/world/collection.hpp @@ -43,6 +43,12 @@ namespace CSMWorld template > class Collection : public CollectionBase { + public: + + typedef ESXRecordT ESXRecord; + + private: + std::vector > mRecords; std::map mIndex; std::vector *> mColumns; diff --git a/apps/opencs/model/world/record.cpp b/apps/opencs/model/world/record.cpp index 87f5090fe..7563c4cfd 100644 --- a/apps/opencs/model/world/record.cpp +++ b/apps/opencs/model/world/record.cpp @@ -43,3 +43,27 @@ bool CSMWorld::isRecordDeleted(const ESM::Skill &skill) { return false; } + +template<> +void CSMWorld::setRecordDeleted(CSMWorld::Land &land, bool isDeleted) +{ + land.mLand->mIsDeleted = isDeleted; +} + +template<> +void CSMWorld::setRecordDeleted(ESM::GameSetting &setting, bool isDeleted) +{ + // GameSetting doesn't have a Deleted flag +} + +template<> +void CSMWorld::setRecordDeleted(ESM::MagicEffect &effect, bool isDeleted) +{ + // MagicEffect doesn't have a Deleted flag +} + +template<> +void CSMWorld::setRecordDeleted(ESM::Skill &skill, bool isDeleted) +{ + // Skill doesn't have a Deleted flag +} diff --git a/apps/opencs/model/world/record.hpp b/apps/opencs/model/world/record.hpp index c43a8b6ca..8e39cd705 100644 --- a/apps/opencs/model/world/record.hpp +++ b/apps/opencs/model/world/record.hpp @@ -177,6 +177,22 @@ namespace CSMWorld bool isRecordDeleted(const ESM::MagicEffect &effect); template<> bool isRecordDeleted(const ESM::Skill &skill); + + // ... and also a separate method for setting the deleted flag of a record + template + void setRecordDeleted(ESXRecordT &record, bool isDeleted = false) + { + record.mIsDeleted = isDeleted; + } + + template<> + void setRecordDeleted(Land &land, bool isDeleted); + template<> + void setRecordDeleted(ESM::GameSetting &setting, bool isDeleted); + template<> + void setRecordDeleted(ESM::MagicEffect &effect, bool isDeleted); + template<> + void setRecordDeleted(ESM::Skill &skill, bool isDeleted); } #endif From ede4bfcf52a77f371058e0fdce655534d6879056 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sun, 19 Jul 2015 14:55:54 +0300 Subject: [PATCH 1888/3725] Rework EsmTool code. Remove explicit NAME handling --- apps/esmtool/esmtool.cpp | 93 +++++++++++++++++----------------------- apps/esmtool/record.cpp | 75 +++++++++++++++++++++++++++++++- apps/esmtool/record.hpp | 18 +++++--- 3 files changed, 124 insertions(+), 62 deletions(-) diff --git a/apps/esmtool/esmtool.cpp b/apps/esmtool/esmtool.cpp index 5b6e50b96..c2507ccdc 100644 --- a/apps/esmtool/esmtool.cpp +++ b/apps/esmtool/esmtool.cpp @@ -251,8 +251,7 @@ void loadCell(ESM::Cell &cell, ESM::ESMReader &esm, Arguments& info) ESM::CellRef ref; if(!quiet) std::cout << " References:\n"; - bool deleted = false; - while(cell.getNextRef(esm, ref, deleted)) + while(cell.getNextRef(esm, ref)) { if (save) { info.data.mCellRefs[&cell].push_back(ref); @@ -270,7 +269,7 @@ void loadCell(ESM::Cell &cell, ESM::ESMReader &esm, Arguments& info) std::cout << " Uses/health: '" << ref.mChargeInt << "'\n"; std::cout << " Gold value: '" << ref.mGoldValue << "'\n"; std::cout << " Blocked: '" << static_cast(ref.mReferenceBlocked) << "'" << std::endl; - std::cout << " Deleted: " << deleted << std::endl; + std::cout << " Deleted: " << ref.mIsDeleted << std::endl; if (!ref.mKey.empty()) std::cout << " Key: '" << ref.mKey << "'" << std::endl; } @@ -352,61 +351,58 @@ int load(Arguments& info) uint32_t flags; esm.getRecHeader(flags); + EsmTool::RecordBase *record = EsmTool::RecordBase::create(n); + if (record == 0) + { + if (std::find(skipped.begin(), skipped.end(), n.val) == skipped.end()) + { + std::cout << "Skipping " << n.toString() << " records." << std::endl; + skipped.push_back(n.val); + } + + esm.skipRecord(); + if (quiet) break; + std::cout << " Skipping\n"; + + continue; + } + + record->setFlags(static_cast(flags)); + record->setPrintPlain(info.plain_given); + record->load(esm); + // Is the user interested in this record type? bool interested = true; if (!info.types.empty()) { std::vector::iterator match; - match = std::find(info.types.begin(), info.types.end(), - n.toString()); + match = std::find(info.types.begin(), info.types.end(), n.toString()); if (match == info.types.end()) interested = false; } - std::string id = esm.getHNOString("NAME"); - if (id.empty()) - id = esm.getHNOString("INAM"); - - if (!info.name.empty() && !Misc::StringUtils::ciEqual(info.name, id)) + if (!info.name.empty() && !Misc::StringUtils::ciEqual(info.name, record->getId())) interested = false; if(!quiet && interested) - std::cout << "\nRecord: " << n.toString() - << " '" << id << "'\n"; - - EsmTool::RecordBase *record = EsmTool::RecordBase::create(n); - - if (record == 0) { - if (std::find(skipped.begin(), skipped.end(), n.val) == skipped.end()) - { - std::cout << "Skipping " << n.toString() << " records." << std::endl; - skipped.push_back(n.val); - } + { + std::cout << "\nRecord: " << n.toString() << " '" << record->getId() << "'\n"; + record->print(); + } - esm.skipRecord(); - if (quiet) break; - std::cout << " Skipping\n"; - } else { - if (record->getType().val == ESM::REC_GMST) { - // preset id for GameSetting record - record->cast()->get().mId = id; - } - record->setId(id); - record->setFlags((int) flags); - record->setPrintPlain(info.plain_given); - record->load(esm); - if (!quiet && interested) record->print(); - - if (record->getType().val == ESM::REC_CELL && loadCells && interested) { - loadCell(record->cast()->get(), esm, info); - } + if (record->getType().val == ESM::REC_CELL && loadCells && interested) + { + loadCell(record->cast()->get(), esm, info); + } - if (save) { - info.data.mRecords.push_back(record); - } else { - delete record; - } - ++info.data.mRecordStats[n.val]; + if (save) + { + info.data.mRecords.push_back(record); + } + else + { + delete record; } + ++info.data.mRecordStats[n.val]; } } catch(std::exception &e) { @@ -493,20 +489,11 @@ int clone(Arguments& info) for (Records::iterator it = records.begin(); it != records.end() && i > 0; ++it) { EsmTool::RecordBase *record = *it; - name.val = record->getType().val; esm.startRecord(name.toString(), record->getFlags()); - // TODO wrap this with std::set - if (ESMData::sLabeledRec.count(name.val) > 0) { - esm.writeHNCString("NAME", record->getId()); - } else { - esm.writeHNOString("NAME", record->getId()); - } - record->save(esm); - if (name.val == ESM::REC_CELL) { ESM::Cell *ptr = &record->cast()->get(); if (!info.data.mCellRefs[ptr].empty()) { diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index 2ee6c54bb..a03318262 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -405,6 +405,7 @@ void Record::print() std::cout << " Name: " << mData.mName << std::endl; std::cout << " Model: " << mData.mModel << std::endl; std::cout << " Script: " << mData.mScript << std::endl; + std::cout << " Deleted: " << mData.mIsDeleted << std::endl; } template<> @@ -419,6 +420,7 @@ void Record::print() std::cout << " Value: " << mData.mData.mValue << std::endl; std::cout << " AutoCalc: " << mData.mData.mAutoCalc << std::endl; printEffectList(mData.mEffects); + std::cout << " Deleted: " << mData.mIsDeleted << std::endl; } template<> @@ -447,6 +449,7 @@ void Record::print() if (pit->mFemale != "") std::cout << " Female Name: " << pit->mFemale << std::endl; } + std::cout << " Deleted: " << mData.mIsDeleted << std::endl; } template<> @@ -461,6 +464,7 @@ void Record::print() std::cout << " Weight: " << mData.mData.mWeight << std::endl; std::cout << " Value: " << mData.mData.mValue << std::endl; std::cout << " Quality: " << mData.mData.mQuality << std::endl; + std::cout << " Deleted: " << mData.mIsDeleted << std::endl; } template<> @@ -474,6 +478,7 @@ void Record::print() std::cout << " Part: " << meshPartLabel(mData.mData.mPart) << " (" << (int)mData.mData.mPart << ")" << std::endl; std::cout << " Vampire: " << (int)mData.mData.mVampire << std::endl; + std::cout << " Deleted: " << mData.mIsDeleted << std::endl; } template<> @@ -502,6 +507,7 @@ void Record::print() { std::cout << " Text: [skipped]" << std::endl; } + std::cout << " Deleted: " << mData.mIsDeleted << std::endl; } template<> @@ -513,6 +519,7 @@ void Record::print() std::vector::iterator pit; for (pit = mData.mPowers.mList.begin(); pit != mData.mPowers.mList.end(); ++pit) std::cout << " Power: " << *pit << std::endl; + std::cout << " Deleted: " << mData.mIsDeleted << std::endl; } template<> @@ -541,6 +548,7 @@ void Record::print() std::cout << " Map Color: " << boost::format("0x%08X") % mData.mMapColor << std::endl; std::cout << " Water Level Int: " << mData.mWaterInt << std::endl; std::cout << " RefId counter: " << mData.mRefNumCounter << std::endl; + std::cout << " Deleted: " << mData.mIsDeleted << std::endl; } @@ -563,6 +571,7 @@ void Record::print() for (int i = 0; i != 5; i++) std::cout << " Major Skill: " << skillLabel(mData.mData.mSkills[i][1]) << " (" << mData.mData.mSkills[i][1] << ")" << std::endl; + std::cout << " Deleted: " << mData.mIsDeleted << std::endl; } template<> @@ -589,6 +598,7 @@ void Record::print() if (pit->mFemale != "") std::cout << " Female Name: " << pit->mFemale << std::endl; } + std::cout << " Deleted: " << mData.mIsDeleted << std::endl; } template<> @@ -604,6 +614,7 @@ void Record::print() for (cit = mData.mInventory.mList.begin(); cit != mData.mInventory.mList.end(); ++cit) std::cout << " Inventory: Count: " << boost::format("%4d") % cit->mCount << " Item: " << cit->mItem.toString() << std::endl; + std::cout << " Deleted: " << mData.mIsDeleted << std::endl; } template<> @@ -670,6 +681,7 @@ void Record::print() std::vector::iterator pit; for (pit = mData.mAiPackage.mList.begin(); pit != mData.mAiPackage.mList.end(); ++pit) printAIPackage(*pit); + std::cout << " Deleted: " << mData.mIsDeleted << std::endl; } template<> @@ -677,6 +689,7 @@ void Record::print() { std::cout << " Type: " << dialogTypeLabel(mData.mType) << " (" << (int)mData.mType << ")" << std::endl; + std::cout << " Deleted: " << mData.mIsDeleted << std::endl; // Sadly, there are no DialInfos, because the loader dumps as it // loads, rather than loading and then dumping. :-( Anyone mind if // I change this? @@ -693,6 +706,7 @@ void Record::print() std::cout << " Script: " << mData.mScript << std::endl; std::cout << " OpenSound: " << mData.mOpenSound << std::endl; std::cout << " CloseSound: " << mData.mCloseSound << std::endl; + std::cout << " Deleted: " << mData.mIsDeleted << std::endl; } template<> @@ -704,6 +718,7 @@ void Record::print() std::cout << " Charge: " << mData.mData.mCharge << std::endl; std::cout << " AutoCalc: " << mData.mData.mAutocalc << std::endl; printEffectList(mData.mEffects); + std::cout << " Deleted: " << mData.mIsDeleted << std::endl; } template<> @@ -737,12 +752,14 @@ void Record::print() std::map::iterator rit; for (rit = mData.mReactions.begin(); rit != mData.mReactions.end(); ++rit) std::cout << " Reaction: " << rit->second << " = " << rit->first << std::endl; + std::cout << " Deleted: " << mData.mIsDeleted << std::endl; } template<> void Record::print() { std::cout << " " << mData.mValue << std::endl; + std::cout << " Deleted: " << mData.mIsDeleted << std::endl; } template<> @@ -809,6 +826,7 @@ void Record::print() std::cout << " Result Script: [skipped]" << std::endl; } } + std::cout << " Deleted: " << mData.mIsDeleted << std::endl; } template<> @@ -832,6 +850,7 @@ void Record::print() std::cout << " Attribute: " << attributeLabel(mData.mData.mAttributes[i]) << " (" << mData.mData.mAttributes[i] << ")" << std::endl; } + std::cout << " Deleted: " << mData.mIsDeleted << std::endl; } template<> @@ -854,6 +873,7 @@ void Record::print() std::cout << " Unknown2: " << mData.mLandData->mUnk2 << std::endl; } if (!wasLoaded) mData.unloadData(); + std::cout << " Deleted: " << mData.mIsDeleted << std::endl; } template<> @@ -866,6 +886,7 @@ void Record::print() for (iit = mData.mList.begin(); iit != mData.mList.end(); ++iit) std::cout << " Creature: Level: " << iit->mLevel << " Creature: " << iit->mId << std::endl; + std::cout << " Deleted: " << mData.mIsDeleted << std::endl; } template<> @@ -878,6 +899,7 @@ void Record::print() for (iit = mData.mList.begin(); iit != mData.mList.end(); ++iit) std::cout << " Inventory: Level: " << iit->mLevel << " Item: " << iit->mId << std::endl; + std::cout << " Deleted: " << mData.mIsDeleted << std::endl; } template<> @@ -898,6 +920,7 @@ void Record::print() std::cout << " Duration: " << mData.mData.mTime << std::endl; std::cout << " Radius: " << mData.mData.mRadius << std::endl; std::cout << " Color: " << mData.mData.mColor << std::endl; + std::cout << " Deleted: " << mData.mIsDeleted << std::endl; } template<> @@ -912,6 +935,7 @@ void Record::print() std::cout << " Value: " << mData.mData.mValue << std::endl; std::cout << " Quality: " << mData.mData.mQuality << std::endl; std::cout << " Uses: " << mData.mData.mUses << std::endl; + std::cout << " Deleted: " << mData.mIsDeleted << std::endl; } template<> @@ -926,6 +950,7 @@ void Record::print() std::cout << " Value: " << mData.mData.mValue << std::endl; std::cout << " Quality: " << mData.mData.mQuality << std::endl; std::cout << " Uses: " << mData.mData.mUses << std::endl; + std::cout << " Deleted: " << mData.mIsDeleted << std::endl; } template<> @@ -940,6 +965,7 @@ void Record::print() std::cout << " Value: " << mData.mData.mValue << std::endl; std::cout << " Quality: " << mData.mData.mQuality << std::endl; std::cout << " Uses: " << mData.mData.mUses << std::endl; + std::cout << " Deleted: " << mData.mIsDeleted << std::endl; } template<> @@ -948,6 +974,7 @@ void Record::print() std::cout << " Id: " << mData.mId << std::endl; std::cout << " Index: " << mData.mIndex << std::endl; std::cout << " Texture: " << mData.mTexture << std::endl; + std::cout << " Deleted: " << mData.mIsDeleted << std::endl; } template<> @@ -998,6 +1025,7 @@ void Record::print() std::cout << " Weight: " << mData.mData.mWeight << std::endl; std::cout << " Value: " << mData.mData.mValue << std::endl; std::cout << " Is Key: " << mData.mData.mIsKey << std::endl; + std::cout << " Deleted: " << mData.mIsDeleted << std::endl; } template<> @@ -1083,6 +1111,8 @@ void Record::print() std::vector::iterator pit; for (pit = mData.mAiPackage.mList.begin(); pit != mData.mAiPackage.mList.end(); ++pit) printAIPackage(*pit); + + std::cout << " Deleted: " << mData.mIsDeleted << std::endl; } template<> @@ -1117,6 +1147,8 @@ void Record::print() std::cout << " BAD POINT IN EDGE!" << std::endl; i++; } + + std::cout << " Deleted: " << mData.mIsDeleted << std::endl; } template<> @@ -1157,6 +1189,8 @@ void Record::print() std::vector::iterator sit; for (sit = mData.mPowers.mList.begin(); sit != mData.mPowers.mList.end(); ++sit) std::cout << " Power: " << *sit << std::endl; + + std::cout << " Deleted: " << mData.mIsDeleted << std::endl; } template<> @@ -1216,6 +1250,8 @@ void Record::print() { std::cout << " Script: [skipped]" << std::endl; } + + std::cout << " Deleted: " << mData.mIsDeleted << std::endl; } template<> @@ -1239,6 +1275,7 @@ void Record::print() std::cout << " Sound: " << mData.mSound << std::endl; std::cout << " Type: " << soundTypeLabel(mData.mType) << " (" << mData.mType << ")" << std::endl; + std::cout << " Deleted: " << mData.mIsDeleted << std::endl; } template<> @@ -1249,6 +1286,7 @@ void Record::print() if (mData.mData.mMinRange != 0 && mData.mData.mMaxRange != 0) std::cout << " Range: " << (int)mData.mData.mMinRange << " - " << (int)mData.mData.mMaxRange << std::endl; + std::cout << " Deleted: " << mData.mIsDeleted << std::endl; } template<> @@ -1260,13 +1298,15 @@ void Record::print() std::cout << " Flags: " << spellFlags(mData.mData.mFlags) << std::endl; std::cout << " Cost: " << mData.mData.mCost << std::endl; printEffectList(mData.mEffects); + std::cout << " Deleted: " << mData.mIsDeleted << std::endl; } template<> void Record::print() { - std::cout << "Start Script: " << mData.mId << std::endl; - std::cout << "Start Data: " << mData.mData << std::endl; + std::cout << " Start Script: " << mData.mId << std::endl; + std::cout << " Start Data: " << mData.mData << std::endl; + std::cout << " Deleted: " << mData.mIsDeleted << std::endl; } template<> @@ -1307,6 +1347,37 @@ void Record::print() if (mData.mData.mThrust[0] != 0 && mData.mData.mThrust[1] != 0) std::cout << " Thrust: " << (int)mData.mData.mThrust[0] << "-" << (int)mData.mData.mThrust[1] << std::endl; + std::cout << " Deleted: " << mData.mIsDeleted << std::endl; +} + +template<> +std::string Record::getId() const +{ + return mData.mName; +} + +template<> +std::string Record::getId() const +{ + return ""; // No ID for Land record +} + +template<> +std::string Record::getId() const +{ + return ""; // No ID for MagicEffect record +} + +template<> +std::string Record::getId() const +{ + return ""; // No ID for Pathgrid record +} + +template<> +std::string Record::getId() const +{ + return ""; // No ID for Skill record } } // end namespace diff --git a/apps/esmtool/record.hpp b/apps/esmtool/record.hpp index c1b90ac2b..a10fda40b 100644 --- a/apps/esmtool/record.hpp +++ b/apps/esmtool/record.hpp @@ -32,13 +32,7 @@ namespace EsmTool virtual ~RecordBase() {} - const std::string &getId() const { - return mId; - } - - void setId(const std::string &id) { - mId = id; - } + virtual std::string getId() const = 0; uint32_t getFlags() const { return mFlags; @@ -75,6 +69,10 @@ namespace EsmTool T mData; public: + std::string getId() const { + return mData.mId; + } + T &get() { return mData; } @@ -89,6 +87,12 @@ namespace EsmTool void print(); }; + + template<> std::string Record::getId() const; + template<> std::string Record::getId() const; + template<> std::string Record::getId() const; + template<> std::string Record::getId() const; + template<> std::string Record::getId() const; template<> void Record::print(); template<> void Record::print(); From 6b21da7f8e6b50de71047248c36d4ee9ec51751e Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sun, 19 Jul 2015 16:07:56 +0300 Subject: [PATCH 1889/3725] Rework ESS importer code. Remove explicit NAME handling for ESM records --- apps/essimporter/converter.cpp | 6 ++---- apps/essimporter/converter.hpp | 36 +++++++++++++--------------------- apps/essimporter/importer.cpp | 2 +- 3 files changed, 17 insertions(+), 27 deletions(-) diff --git a/apps/essimporter/converter.cpp b/apps/essimporter/converter.cpp index 2ef10ee34..982753134 100644 --- a/apps/essimporter/converter.cpp +++ b/apps/essimporter/converter.cpp @@ -158,8 +158,6 @@ namespace ESSImport void ConvertCell::read(ESM::ESMReader &esm) { ESM::Cell cell; - std::string id = esm.getHNString("NAME"); - cell.mName = id; cell.load(esm, false); // I wonder what 0x40 does? @@ -169,7 +167,7 @@ namespace ESSImport } // note if the player is in a nameless exterior cell, we will assign the cellId later based on player position - if (id == mContext->mPlayerCellName) + if (cell.mName == mContext->mPlayerCellName) { mContext->mPlayer.mCellId = cell.getCellId(); } @@ -277,7 +275,7 @@ namespace ESSImport if (cell.isExterior()) mExtCells[std::make_pair(cell.mData.mX, cell.mData.mY)] = newcell; else - mIntCells[id] = newcell; + mIntCells[cell.mName] = newcell; } void ConvertCell::writeCell(const Cell &cell, ESM::ESMWriter& esm) diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index fb8fb8c9f..3bb5d2eae 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -78,10 +78,9 @@ public: virtual void read(ESM::ESMReader& esm) { - std::string id = esm.getHNString("NAME"); T record; record.load(esm); - mRecords[id] = record; + mRecords[record.mId] = record; } virtual void write(ESM::ESMWriter& esm) @@ -89,7 +88,6 @@ public: for (typename std::map::const_iterator it = mRecords.begin(); it != mRecords.end(); ++it) { esm.startRecord(T::sRecordId); - esm.writeHNString("NAME", it->first); it->second.save(esm); esm.endRecord(T::sRecordId); } @@ -105,14 +103,13 @@ public: virtual void read(ESM::ESMReader &esm) { ESM::NPC npc; - std::string id = esm.getHNString("NAME"); npc.load(esm); - if (id != "player") + if (npc.mId != "player") { // Handles changes to the NPC struct, but since there is no index here // it will apply to ALL instances of the class. seems to be the reason for the // "feature" in MW where changing AI settings of one guard will change it for all guards of that refID. - mContext->mNpcs[Misc::StringUtils::lowerCase(id)] = npc; + mContext->mNpcs[Misc::StringUtils::lowerCase(npc.mId)] = npc; } else { @@ -142,9 +139,8 @@ public: { // See comment in ConvertNPC ESM::Creature creature; - std::string id = esm.getHNString("NAME"); creature.load(esm); - mContext->mCreatures[Misc::StringUtils::lowerCase(id)] = creature; + mContext->mCreatures[Misc::StringUtils::lowerCase(creature.mId)] = creature; } }; @@ -157,18 +153,17 @@ class ConvertGlobal : public DefaultConverter public: virtual void read(ESM::ESMReader &esm) { - std::string id = esm.getHNString("NAME"); ESM::Global global; global.load(esm); - if (Misc::StringUtils::ciEqual(id, "gamehour")) + if (Misc::StringUtils::ciEqual(global.mId, "gamehour")) mContext->mHour = global.mValue.getFloat(); - if (Misc::StringUtils::ciEqual(id, "day")) + if (Misc::StringUtils::ciEqual(global.mId, "day")) mContext->mDay = global.mValue.getInteger(); - if (Misc::StringUtils::ciEqual(id, "month")) + if (Misc::StringUtils::ciEqual(global.mId, "month")) mContext->mMonth = global.mValue.getInteger(); - if (Misc::StringUtils::ciEqual(id, "year")) + if (Misc::StringUtils::ciEqual(global.mId, "year")) mContext->mYear = global.mValue.getInteger(); - mRecords[id] = global; + mRecords[global.mId] = global; } }; @@ -177,14 +172,13 @@ class ConvertClass : public DefaultConverter public: virtual void read(ESM::ESMReader &esm) { - std::string id = esm.getHNString("NAME"); ESM::Class class_; class_.load(esm); - if (id == "NEWCLASSID_CHARGEN") + if (class_.mId == "NEWCLASSID_CHARGEN") mContext->mCustomPlayerClassName = class_.mName; - mRecords[id] = class_; + mRecords[class_.mId] = class_; } }; @@ -193,13 +187,12 @@ class ConvertBook : public DefaultConverter public: virtual void read(ESM::ESMReader &esm) { - std::string id = esm.getHNString("NAME"); ESM::Book book; book.load(esm); if (book.mData.mSkillID == -1) - mContext->mPlayer.mObject.mNpcStats.mUsedIds.push_back(Misc::StringUtils::lowerCase(id)); + mContext->mPlayer.mObject.mNpcStats.mUsedIds.push_back(Misc::StringUtils::lowerCase(book.mId)); - mRecords[id] = book; + mRecords[book.mId] = book; } }; @@ -371,11 +364,10 @@ class ConvertFACT : public Converter public: virtual void read(ESM::ESMReader& esm) { - std::string id = esm.getHNString("NAME"); ESM::Faction faction; faction.load(esm); + std::string id = Misc::StringUtils::toLower(faction.mId); - Misc::StringUtils::toLower(id); for (std::map::const_iterator it = faction.mReactions.begin(); it != faction.mReactions.end(); ++it) { std::string faction2 = Misc::StringUtils::lowerCase(it->first); diff --git a/apps/essimporter/importer.cpp b/apps/essimporter/importer.cpp index 624241039..4fbf06217 100644 --- a/apps/essimporter/importer.cpp +++ b/apps/essimporter/importer.cpp @@ -394,7 +394,7 @@ namespace ESSImport } writer.startRecord(ESM::REC_NPC_); - writer.writeHNString("NAME", "player"); + context.mPlayerBase.mId = "player"; context.mPlayerBase.save(writer); writer.endRecord(ESM::REC_NPC_); From 7924ecef3e640f68ddd3ddf5d59bff97713af3b5 Mon Sep 17 00:00:00 2001 From: Koncord Date: Sun, 19 Jul 2015 23:37:20 +0900 Subject: [PATCH 1890/3725] Fix definition conflict --- components/CMakeLists.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 85e61cee5..cf0c83fbd 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -201,7 +201,10 @@ if (GIT_CHECKOUT) endif (GIT_CHECKOUT) if (WIN32) -target_link_libraries(components shlwapi) + target_link_libraries(components shlwapi) + if(MINGW) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DNOGDI") + endif(MINGW) endif() # Fix for not visible pthreads functions for linker with glibc 2.15 From a14a3c82ded2f4d2702abaeefd74905b35e21e34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ji=C5=99=C3=AD=20Kune=C5=A1?= Date: Sun, 19 Jul 2015 19:52:50 +0200 Subject: [PATCH 1891/3725] added description of new syntax to the onRetrieveTag function comment --- apps/openmw/mwgui/windowmanagerimp.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index af82c27c0..336a2a19a 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -495,6 +495,7 @@ namespace MWGui * Called when MyGUI tries to retrieve a tag's value. Tags must be denoted in #{tag} notation and will be replaced upon setting a user visible text/property. * Supported syntax: * #{GMSTName}: retrieves String value of the GMST called GMSTName + * #{setting=CATEGORY_NAME,SETTING_NAME}: retrieves String value of SETTING_NAME under category CATEGORY_NAME from settings.cfg * #{sCell=CellID}: retrieves translated name of the given CellID (used only by some Morrowind localisations, in others cell ID is == cell name) * #{fontcolour=FontColourName}: retrieves the value of the fallback setting "FontColor_color_" from openmw.cfg, * in the format "r g b a", float values in range 0-1. Useful for "Colour" and "TextColour" properties in skins. From f5745749a6e7875c487ac417dead00446af805c2 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sun, 19 Jul 2015 22:50:42 +0300 Subject: [PATCH 1892/3725] Remove include file from loaddial.cpp --- components/esm/loaddial.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/components/esm/loaddial.cpp b/components/esm/loaddial.cpp index c517dc722..74a708805 100644 --- a/components/esm/loaddial.cpp +++ b/components/esm/loaddial.cpp @@ -2,8 +2,6 @@ #include -#include - #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" From 1e8182220ae7c14de13ab634c82f2b14444c0e69 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sun, 19 Jul 2015 23:27:51 +0300 Subject: [PATCH 1893/3725] Fix build errors & warnings --- apps/opencs/model/doc/savingstages.hpp | 2 +- apps/opencs/model/world/idcollection.hpp | 8 ++++---- components/esm/cellref.cpp | 6 ++++-- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/apps/opencs/model/doc/savingstages.hpp b/apps/opencs/model/doc/savingstages.hpp index 9dbb5bee3..a7d9704b0 100644 --- a/apps/opencs/model/doc/savingstages.hpp +++ b/apps/opencs/model/doc/savingstages.hpp @@ -102,7 +102,7 @@ namespace CSMDoc ESM::ESMWriter& writer = mState.getWriter(); CSMWorld::RecordBase::State state = mCollection.getRecord (stage).mState; - CollectionT::ESXRecord record = mCollection.getRecord (stage).get(); + typename CollectionT::ESXRecord record = mCollection.getRecord (stage).get(); if (state == CSMWorld::RecordBase::State_Modified || state == CSMWorld::RecordBase::State_ModifiedOnly || diff --git a/apps/opencs/model/world/idcollection.hpp b/apps/opencs/model/world/idcollection.hpp index 4acfdc474..9d3ec990e 100644 --- a/apps/opencs/model/world/idcollection.hpp +++ b/apps/opencs/model/world/idcollection.hpp @@ -46,7 +46,7 @@ namespace CSMWorld loadRecord (record, reader); std::string id = IdAccessorT().getId (record); - int index = searchId (id); + int index = this->searchId (id); if (isRecordDeleted(record)) { @@ -60,13 +60,13 @@ namespace CSMWorld if (base) { - removeRows (index, 1); + this->removeRows (index, 1); return -1; } - Record baseRecord = getRecord (index); + Record baseRecord = this->getRecord (index); baseRecord.mState = RecordBase::State_Deleted; - setRecord (index, baseRecord); + this->setRecord (index, baseRecord); return index; } diff --git a/components/esm/cellref.cpp b/components/esm/cellref.cpp index c6fb899b3..bcf3de807 100644 --- a/components/esm/cellref.cpp +++ b/components/esm/cellref.cpp @@ -7,10 +7,12 @@ ESM::CellRef::CellRef() : mScale(1.0f), mFactionRank(-2), - mEnchantmentCharge(-1), - mGoldValue(1), mChargeInt(-1), + mEnchantmentCharge(-1.0f), + mGoldValue(1), + mTeleport(false), mLockLevel(0), + mReferenceBlocked(-1), mIsDeleted(false) {} From 75e50235904d1394f95269d3a98db950bdce0ec4 Mon Sep 17 00:00:00 2001 From: Koncord Date: Mon, 20 Jul 2015 08:05:52 +0900 Subject: [PATCH 1894/3725] fix code duplication --- apps/openmw/mwclass/misc.cpp | 20 ++++++++------------ apps/openmw/mwclass/misc.hpp | 2 ++ apps/openmw/mwworld/containerstore.cpp | 8 +++----- 3 files changed, 13 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index b7c39b50a..0c80209f2 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -25,20 +25,16 @@ #include -namespace -{ -bool isGold (const MWWorld::Ptr& ptr) -{ - return Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_001") - || Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_005") - || Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_010") - || Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_025") - || Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_100"); -} -} - namespace MWClass { + bool Miscellaneous::isGold (const MWWorld::Ptr& ptr) const + { + return Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_001") + || Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_005") + || Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_010") + || Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_025") + || Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_100"); + } std::string Miscellaneous::getId (const MWWorld::Ptr& ptr) const { return ptr.get()->mBase->mId; diff --git a/apps/openmw/mwclass/misc.hpp b/apps/openmw/mwclass/misc.hpp index 66699f9df..394c9ffc0 100644 --- a/apps/openmw/mwclass/misc.hpp +++ b/apps/openmw/mwclass/misc.hpp @@ -62,6 +62,8 @@ namespace MWClass virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; virtual bool isKey (const MWWorld::Ptr &ptr) const; + + virtual bool isGold (const MWWorld::Ptr& ptr) const; }; } diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index d4aadc6c7..26fcc33cb 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -13,6 +13,8 @@ #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/levelledlist.hpp" +#include "../mwclass/misc.hpp" + #include "manualref.hpp" #include "refdata.hpp" #include "class.hpp" @@ -298,11 +300,7 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::addImp (const Ptr& ptr, // gold needs special handling: when it is inserted into a container, the base object automatically becomes Gold_001 // this ensures that gold piles of different sizes stack with each other (also, several scripts rely on Gold_001 for detecting player gold) - if (Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_001") - || Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_005") - || Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_010") - || Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_025") - || Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_100")) + if(MWClass::Miscellaneous().isGold(ptr)) { int realCount = count * ptr.getClass().getValue(ptr); From aefcd1ad07181b92d1daaebdb2e504efb42d81ad Mon Sep 17 00:00:00 2001 From: Koncord Date: Mon, 20 Jul 2015 08:20:28 +0900 Subject: [PATCH 1895/3725] Fix "additem gold_100" behavior --- apps/openmw/mwworld/containerstore.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 26fcc33cb..9d4ec552e 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -302,20 +302,18 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::addImp (const Ptr& ptr, // this ensures that gold piles of different sizes stack with each other (also, several scripts rely on Gold_001 for detecting player gold) if(MWClass::Miscellaneous().isGold(ptr)) { - int realCount = count * ptr.getClass().getValue(ptr); - for (MWWorld::ContainerStoreIterator iter (begin(type)); iter!=end(); ++iter) { if (Misc::StringUtils::ciEqual((*iter).getCellRef().getRefId(), MWWorld::ContainerStore::sGoldId)) { - iter->getRefData().setCount(iter->getRefData().getCount() + realCount); + iter->getRefData().setCount(iter->getRefData().getCount() + count); flagAsModified(); return iter; } } - MWWorld::ManualRef ref(esmStore, MWWorld::ContainerStore::sGoldId, realCount); - return addNewStack(ref.getPtr(), realCount); + MWWorld::ManualRef ref(esmStore, MWWorld::ContainerStore::sGoldId, count); + return addNewStack(ref.getPtr(), count); } // determine whether to stack or not From 9485aa5e44dfb1cec74f2d36156fbd7e5b3251ed Mon Sep 17 00:00:00 2001 From: Koncord Date: Mon, 20 Jul 2015 09:53:08 +0900 Subject: [PATCH 1896/3725] Fix "removeitem gold_100" behavior --- apps/openmw/mwworld/containerstore.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 9d4ec552e..c21fdd662 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -362,8 +362,18 @@ int MWWorld::ContainerStore::remove(const std::string& itemId, int count, const { int toRemove = count; + std::string id = itemId; + + if(Misc::StringUtils::ciEqual(itemId, "gold_005") + || Misc::StringUtils::ciEqual(itemId, "gold_010") + || Misc::StringUtils::ciEqual(itemId, "gold_025") + || Misc::StringUtils::ciEqual(itemId, "gold_100")) + { + id = MWWorld::ContainerStore::sGoldId; + } + for (ContainerStoreIterator iter(begin()); iter != end() && toRemove > 0; ++iter) - if (Misc::StringUtils::ciEqual(iter->getCellRef().getRefId(), itemId)) + if (Misc::StringUtils::ciEqual(iter->getCellRef().getRefId(), id)) toRemove -= remove(*iter, toRemove, actor); flagAsModified(); From a24df8cb66e68eca2b665d25121d7cfb5989fb5b Mon Sep 17 00:00:00 2001 From: Koncord Date: Mon, 20 Jul 2015 12:43:58 +0900 Subject: [PATCH 1897/3725] Revert addImp() and remove() add isGold() in MWWorld::Class --- apps/openmw/mwworld/class.hpp | 2 ++ apps/openmw/mwworld/containerstore.cpp | 22 +++++++--------------- 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 7ef173555..3f091380f 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -284,6 +284,8 @@ namespace MWWorld virtual bool isKey (const MWWorld::Ptr& ptr) const { return false; } + virtual bool isGold(const MWWorld::Ptr& ptr) const { return false; }; + /// Get a blood texture suitable for \a ptr (see Blood Texture 0-2 in Morrowind.ini) virtual int getBloodTexture (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index c21fdd662..f7ede6c98 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -300,20 +300,22 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::addImp (const Ptr& ptr, // gold needs special handling: when it is inserted into a container, the base object automatically becomes Gold_001 // this ensures that gold piles of different sizes stack with each other (also, several scripts rely on Gold_001 for detecting player gold) - if(MWClass::Miscellaneous().isGold(ptr)) + if(ptr.getClass().isGold(ptr)) { + int realCount = count * ptr.getClass().getValue(ptr); + for (MWWorld::ContainerStoreIterator iter (begin(type)); iter!=end(); ++iter) { if (Misc::StringUtils::ciEqual((*iter).getCellRef().getRefId(), MWWorld::ContainerStore::sGoldId)) { - iter->getRefData().setCount(iter->getRefData().getCount() + count); + iter->getRefData().setCount(iter->getRefData().getCount() + realCount); flagAsModified(); return iter; } } - MWWorld::ManualRef ref(esmStore, MWWorld::ContainerStore::sGoldId, count); - return addNewStack(ref.getPtr(), count); + MWWorld::ManualRef ref(esmStore, MWWorld::ContainerStore::sGoldId, realCount); + return addNewStack(ref.getPtr(), realCount); } // determine whether to stack or not @@ -362,18 +364,8 @@ int MWWorld::ContainerStore::remove(const std::string& itemId, int count, const { int toRemove = count; - std::string id = itemId; - - if(Misc::StringUtils::ciEqual(itemId, "gold_005") - || Misc::StringUtils::ciEqual(itemId, "gold_010") - || Misc::StringUtils::ciEqual(itemId, "gold_025") - || Misc::StringUtils::ciEqual(itemId, "gold_100")) - { - id = MWWorld::ContainerStore::sGoldId; - } - for (ContainerStoreIterator iter(begin()); iter != end() && toRemove > 0; ++iter) - if (Misc::StringUtils::ciEqual(iter->getCellRef().getRefId(), id)) + if (Misc::StringUtils::ciEqual(iter->getCellRef().getRefId(), itemId)) toRemove -= remove(*iter, toRemove, actor); flagAsModified(); From 7a86c8d8b6e880cd1212cc07bcd40efa6d098f42 Mon Sep 17 00:00:00 2001 From: Koncord Date: Mon, 20 Jul 2015 12:48:19 +0900 Subject: [PATCH 1898/3725] Fix OpAddItem, OpGetItemCount and OpRemoveItem. --- apps/openmw/mwscript/containerextensions.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/apps/openmw/mwscript/containerextensions.cpp b/apps/openmw/mwscript/containerextensions.cpp index 70475d8e2..ac9bbef66 100644 --- a/apps/openmw/mwscript/containerextensions.cpp +++ b/apps/openmw/mwscript/containerextensions.cpp @@ -56,6 +56,12 @@ namespace MWScript if (count == 0) return; + if(Misc::StringUtils::ciEqual(item, "gold_005") + || Misc::StringUtils::ciEqual(item, "gold_010") + || Misc::StringUtils::ciEqual(item, "gold_025") + || Misc::StringUtils::ciEqual(item, "gold_100")) + item = "gold_001"; + MWWorld::Ptr itemPtr = *ptr.getClass().getContainerStore (ptr).add (item, count, ptr); // Spawn a messagebox (only for items added to player's inventory and if player is talking to someone) @@ -91,6 +97,12 @@ namespace MWScript std::string item = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); + if(Misc::StringUtils::ciEqual(item, "gold_005") + || Misc::StringUtils::ciEqual(item, "gold_010") + || Misc::StringUtils::ciEqual(item, "gold_025") + || Misc::StringUtils::ciEqual(item, "gold_100")) + item = "gold_001"; + MWWorld::ContainerStore& store = ptr.getClass().getContainerStore (ptr); runtime.push (store.count(item)); @@ -119,6 +131,12 @@ namespace MWScript if (count == 0) return; + if(Misc::StringUtils::ciEqual(item, "gold_005") + || Misc::StringUtils::ciEqual(item, "gold_010") + || Misc::StringUtils::ciEqual(item, "gold_025") + || Misc::StringUtils::ciEqual(item, "gold_100")) + item = "gold_001"; + MWWorld::ContainerStore& store = ptr.getClass().getContainerStore (ptr); std::string itemName; From 2a4d35b98c0ad0fcab06f25bd8ba113dcf87ab41 Mon Sep 17 00:00:00 2001 From: dteviot Date: Mon, 20 Jul 2015 18:20:57 +1200 Subject: [PATCH 1899/3725] fixed "comma at end of enumerator list" warning. --- apps/openmw/mwmechanics/aiwander.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index df389a34e..d1dab3f50 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -68,7 +68,7 @@ namespace MWMechanics Wander_ChooseAction, Wander_IdleNow, Wander_MoveNow, - Wander_Walking, + Wander_Walking }; private: // NOTE: mDistance and mDuration must be set already From 6c3c85f0d4f0ebead4fbf0856e98ace2b2b888e0 Mon Sep 17 00:00:00 2001 From: Koncord Date: Mon, 20 Jul 2015 21:53:20 +0900 Subject: [PATCH 1900/3725] Fix indent Remove misc.hpp in containerstore.cpp --- apps/openmw/mwscript/containerextensions.cpp | 8 ++++---- apps/openmw/mwworld/containerstore.cpp | 2 -- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwscript/containerextensions.cpp b/apps/openmw/mwscript/containerextensions.cpp index ac9bbef66..ba18d8e37 100644 --- a/apps/openmw/mwscript/containerextensions.cpp +++ b/apps/openmw/mwscript/containerextensions.cpp @@ -132,10 +132,10 @@ namespace MWScript return; if(Misc::StringUtils::ciEqual(item, "gold_005") - || Misc::StringUtils::ciEqual(item, "gold_010") - || Misc::StringUtils::ciEqual(item, "gold_025") - || Misc::StringUtils::ciEqual(item, "gold_100")) - item = "gold_001"; + || Misc::StringUtils::ciEqual(item, "gold_010") + || Misc::StringUtils::ciEqual(item, "gold_025") + || Misc::StringUtils::ciEqual(item, "gold_100")) + item = "gold_001"; MWWorld::ContainerStore& store = ptr.getClass().getContainerStore (ptr); diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index f7ede6c98..3a7c02332 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -13,8 +13,6 @@ #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/levelledlist.hpp" -#include "../mwclass/misc.hpp" - #include "manualref.hpp" #include "refdata.hpp" #include "class.hpp" From 3c3bd7976ecd5a43c9eddf1fb45e3a25967ca7d3 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 22 Jul 2015 08:36:06 +0200 Subject: [PATCH 1901/3725] updated credits file --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index 2bd96e3a1..def0b2b89 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -60,6 +60,7 @@ Programmers Julien Voisin (jvoisin/ap0) Karl-Felix Glatzer (k1ll) Kevin Poitra (PuppyKevin) + Koncord Lars Söderberg (Lazaroth) lazydev Leon Saunders (emoose) From 4a16eba716d6795bb9aadc492c4417d1a05828ef Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Mon, 20 Jul 2015 17:23:14 +0300 Subject: [PATCH 1902/3725] Make deleted flag a parameter of load/save methods (instead of a record member) in ESM records --- components/esm/cellref.cpp | 93 +++++++++------------- components/esm/cellref.hpp | 12 ++- components/esm/debugprofile.cpp | 24 +++--- components/esm/debugprofile.hpp | 8 +- components/esm/esmreader.cpp | 1 + components/esm/filter.cpp | 21 ++--- components/esm/filter.hpp | 8 +- components/esm/loadacti.cpp | 24 +++--- components/esm/loadacti.hpp | 8 +- components/esm/loadalch.cpp | 27 +++---- components/esm/loadalch.hpp | 8 +- components/esm/loadappa.cpp | 26 +++--- components/esm/loadappa.hpp | 8 +- components/esm/loadarmo.cpp | 27 +++---- components/esm/loadarmo.hpp | 8 +- components/esm/loadbody.cpp | 27 +++---- components/esm/loadbody.hpp | 8 +- components/esm/loadbook.cpp | 26 +++--- components/esm/loadbook.hpp | 8 +- components/esm/loadbsgn.cpp | 25 +++--- components/esm/loadbsgn.hpp | 8 +- components/esm/loadcell.cpp | 136 +++++++++++++++++++------------- components/esm/loadcell.hpp | 20 ++--- components/esm/loadclas.cpp | 27 +++---- components/esm/loadclas.hpp | 8 +- components/esm/loadclot.cpp | 27 +++---- components/esm/loadclot.hpp | 8 +- components/esm/loadcont.cpp | 31 +++----- components/esm/loadcont.hpp | 8 +- components/esm/loadcrea.cpp | 31 +++----- components/esm/loadcrea.hpp | 8 +- components/esm/loaddial.cpp | 64 +++++++-------- components/esm/loaddial.hpp | 16 ++-- components/esm/loaddoor.cpp | 24 +++--- components/esm/loaddoor.hpp | 8 +- components/esm/loadench.cpp | 27 +++---- components/esm/loadench.hpp | 8 +- components/esm/loadfact.cpp | 28 +++---- components/esm/loadfact.hpp | 8 +- components/esm/loadglob.cpp | 16 ++-- components/esm/loadglob.hpp | 8 +- components/esm/loadgmst.cpp | 6 +- components/esm/loadgmst.hpp | 4 +- components/esm/loadinfo.cpp | 32 +++----- components/esm/loadinfo.hpp | 10 +-- components/esm/loadingr.cpp | 27 +++---- components/esm/loadingr.hpp | 8 +- components/esm/loadland.cpp | 109 ++++++++++++++----------- components/esm/loadland.hpp | 8 +- components/esm/loadlevlist.cpp | 41 ++++++---- components/esm/loadlevlist.hpp | 8 +- components/esm/loadligh.cpp | 26 +++--- components/esm/loadligh.hpp | 8 +- components/esm/loadlock.cpp | 26 +++--- components/esm/loadlock.hpp | 8 +- components/esm/loadltex.cpp | 24 +++--- components/esm/loadltex.hpp | 8 +- components/esm/loadmgef.cpp | 9 ++- components/esm/loadmgef.hpp | 4 +- components/esm/loadmisc.cpp | 26 +++--- components/esm/loadmisc.hpp | 8 +- components/esm/loadnpc.cpp | 31 +++----- components/esm/loadnpc.hpp | 8 +- components/esm/loadpgrd.cpp | 18 ++--- components/esm/loadpgrd.hpp | 8 +- components/esm/loadprob.cpp | 26 +++--- components/esm/loadprob.hpp | 8 +- components/esm/loadrace.cpp | 26 +++--- components/esm/loadrace.hpp | 8 +- components/esm/loadregn.cpp | 24 ++---- components/esm/loadregn.hpp | 8 +- components/esm/loadrepa.cpp | 26 +++--- components/esm/loadrepa.hpp | 8 +- components/esm/loadscpt.cpp | 26 +++--- components/esm/loadscpt.hpp | 8 +- components/esm/loadskil.cpp | 9 ++- components/esm/loadskil.hpp | 4 +- components/esm/loadsndg.cpp | 27 +++---- components/esm/loadsndg.hpp | 8 +- components/esm/loadsoun.cpp | 27 +++---- components/esm/loadsoun.hpp | 8 +- components/esm/loadspel.cpp | 28 +++---- components/esm/loadspel.hpp | 8 +- components/esm/loadsscr.cpp | 18 ++--- components/esm/loadsscr.hpp | 8 +- components/esm/loadstat.cpp | 24 +++--- components/esm/loadstat.hpp | 8 +- components/esm/loadweap.cpp | 27 +++---- components/esm/loadweap.hpp | 8 +- components/esm/objectstate.cpp | 3 +- 90 files changed, 714 insertions(+), 1050 deletions(-) diff --git a/components/esm/cellref.cpp b/components/esm/cellref.cpp index bcf3de807..9a0c8f1cc 100644 --- a/components/esm/cellref.cpp +++ b/components/esm/cellref.cpp @@ -4,18 +4,6 @@ #include "esmreader.hpp" #include "esmwriter.hpp" -ESM::CellRef::CellRef() - : mScale(1.0f), - mFactionRank(-2), - mChargeInt(-1), - mEnchantmentCharge(-1.0f), - mGoldValue(1), - mTeleport(false), - mLockLevel(0), - mReferenceBlocked(-1), - mIsDeleted(false) -{} - void ESM::RefNum::load (ESMReader& esm, bool wide) { if (wide) @@ -37,10 +25,37 @@ void ESM::RefNum::save (ESMWriter &esm, bool wide, const std::string& tag) const } -void ESM::CellRef::load (ESMReader& esm, bool wideRefNum) +void ESM::CellRef::clearData() +{ + mScale = 1; + mOwner.clear(); + mGlobalVariable.clear(); + mSoul.clear(); + mFaction.clear(); + mFactionRank = -2; + mChargeInt = -1; + mEnchantmentCharge = -1; + mGoldValue = 0; + mDestCell.clear(); + mLockLevel = 0; + mKey.clear(); + mTrap.clear(); + mReferenceBlocked = -1; + mTeleport = false; + + for (int i=0; i<3; ++i) + { + mDoorDest.pos[i] = 0; + mDoorDest.rot[i] = 0; + mPos.pos[i] = 0; + mPos.rot[i] = 0; + } +} + +void ESM::CellRef::load (ESMReader& esm, bool &isDeleted, bool wideRefNum) { loadId(esm, wideRefNum); - loadData(esm); + loadData(esm, isDeleted); } void ESM::CellRef::loadId (ESMReader& esm, bool wideRefNum) @@ -55,27 +70,19 @@ void ESM::CellRef::loadId (ESMReader& esm, bool wideRefNum) mRefNum.load (esm, wideRefNum); mRefID = esm.getHNString ("NAME"); - mIsDeleted = false; } -void ESM::CellRef::loadData(ESMReader &esm) +void ESM::CellRef::loadData(ESMReader &esm, bool &isDeleted) { - mScale = 1.0f; - mFactionRank = -2; - mChargeInt = -1; - mEnchantmentCharge = -1; - mGoldValue = 1; - mLockLevel = 0; - mReferenceBlocked = -1; - mTeleport = false; - mIsDeleted = false; + isDeleted = false; + + clearData(); bool isLoaded = false; while (!isLoaded && esm.hasMoreSubs()) { esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + switch (esm.retSubName().val) { case ESM::FourCC<'U','N','A','M'>::value: esm.getHT(mReferenceBlocked); @@ -131,7 +138,7 @@ void ESM::CellRef::loadData(ESMReader &esm) break; case ESM::FourCC<'D','E','L','E'>::value: esm.skipHSub(); - mIsDeleted = true; + isDeleted = true; break; default: esm.cacheSubName(); @@ -141,7 +148,7 @@ void ESM::CellRef::loadData(ESMReader &esm) } } -void ESM::CellRef::save (ESMWriter &esm, bool wideRefNum, bool inInventory) const +void ESM::CellRef::save (ESMWriter &esm, bool wideRefNum, bool inInventory, bool isDeleted) const { mRefNum.save (esm, wideRefNum); @@ -192,7 +199,7 @@ void ESM::CellRef::save (ESMWriter &esm, bool wideRefNum, bool inInventory) cons if (!inInventory) esm.writeHNT("DATA", mPos, 24); - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); } @@ -202,31 +209,7 @@ void ESM::CellRef::blank() { mRefNum.unset(); mRefID.clear(); - mScale = 1; - mOwner.clear(); - mGlobalVariable.clear(); - mSoul.clear(); - mFaction.clear(); - mFactionRank = -2; - mChargeInt = -1; - mEnchantmentCharge = -1; - mGoldValue = 0; - mDestCell.clear(); - mLockLevel = 0; - mKey.clear(); - mTrap.clear(); - mReferenceBlocked = -1; - mTeleport = false; - - for (int i=0; i<3; ++i) - { - mDoorDest.pos[i] = 0; - mDoorDest.rot[i] = 0; - mPos.pos[i] = 0; - mPos.rot[i] = 0; - } - - mIsDeleted = false; + clearData(); } bool ESM::operator== (const RefNum& left, const RefNum& right) diff --git a/components/esm/cellref.hpp b/components/esm/cellref.hpp index 553dbaae3..a9edd291e 100644 --- a/components/esm/cellref.hpp +++ b/components/esm/cellref.hpp @@ -33,6 +33,8 @@ namespace ESM class CellRef { + void clearData(); + public: // Reference number @@ -99,19 +101,15 @@ namespace ESM // Position and rotation of this object within the cell Position mPos; - bool mIsDeleted; - - CellRef(); - /// Calls loadId and loadData - void load (ESMReader& esm, bool wideRefNum = false); + void load (ESMReader& esm, bool &isDeleted, bool wideRefNum = false); void loadId (ESMReader& esm, bool wideRefNum = false); /// Implicitly called by load - void loadData (ESMReader& esm); + void loadData (ESMReader& esm, bool &isDeleted); - void save (ESMWriter &esm, bool wideRefNum = false, bool inInventory = false) const; + void save (ESMWriter &esm, bool wideRefNum = false, bool inInventory = false, bool isDeleted = false) const; void blank(); }; diff --git a/components/esm/debugprofile.cpp b/components/esm/debugprofile.cpp index d1e27debc..16fc90eec 100644 --- a/components/esm/debugprofile.cpp +++ b/components/esm/debugprofile.cpp @@ -7,27 +7,18 @@ unsigned int ESM::DebugProfile::sRecordId = REC_DBGP; -ESM::DebugProfile::DebugProfile() - : mIsDeleted(false) -{} - -void ESM::DebugProfile::load (ESMReader& esm) +void ESM::DebugProfile::load (ESMReader& esm, bool &isDeleted) { - mIsDeleted = false; + isDeleted = false; while (esm.hasMoreSubs()) { esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + switch (esm.retSubName().val) { case ESM::FourCC<'N','A','M','E'>::value: mId = esm.getHString(); break; - case ESM::FourCC<'D','E','L','E'>::value: - esm.skipHSub(); - mIsDeleted = true; - break; case ESM::FourCC<'D','E','S','C'>::value: mDescription = esm.getHString(); break; @@ -37,6 +28,10 @@ void ESM::DebugProfile::load (ESMReader& esm) case ESM::FourCC<'F','L','A','G'>::value: esm.getHT(mFlags); break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + isDeleted = true; + break; default: esm.fail("Unknown subrecord"); break; @@ -44,11 +39,11 @@ void ESM::DebugProfile::load (ESMReader& esm) } } -void ESM::DebugProfile::save (ESMWriter& esm) const +void ESM::DebugProfile::save (ESMWriter& esm, bool isDeleted) const { esm.writeHNCString ("NAME", mId); - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); return; @@ -64,5 +59,4 @@ void ESM::DebugProfile::blank() mDescription.clear(); mScriptText.clear(); mFlags = 0; - mIsDeleted = false; } diff --git a/components/esm/debugprofile.hpp b/components/esm/debugprofile.hpp index 1709136f5..c056750a8 100644 --- a/components/esm/debugprofile.hpp +++ b/components/esm/debugprofile.hpp @@ -27,12 +27,8 @@ namespace ESM unsigned int mFlags; - bool mIsDeleted; - - DebugProfile(); - - void load (ESMReader& esm); - void save (ESMWriter& esm) const; + void load (ESMReader& esm, bool &isDeleted); + void save (ESMWriter& esm, bool isDeleted = false) const; /// Set record to default state (does not touch the ID). void blank(); diff --git a/components/esm/esmreader.cpp b/components/esm/esmreader.cpp index 1bf176842..6ef14a70e 100644 --- a/components/esm/esmreader.cpp +++ b/components/esm/esmreader.cpp @@ -281,6 +281,7 @@ void ESMReader::skipRecord() { skip(mCtx.leftRec); mCtx.leftRec = 0; + mCtx.subCached = false; } void ESMReader::getRecHeader(uint32_t &flags) diff --git a/components/esm/filter.cpp b/components/esm/filter.cpp index 57cb59454..b485169f2 100644 --- a/components/esm/filter.cpp +++ b/components/esm/filter.cpp @@ -7,13 +7,9 @@ unsigned int ESM::Filter::sRecordId = REC_FILT; -ESM::Filter::Filter() - : mIsDeleted(false) -{} - -void ESM::Filter::load (ESMReader& esm) +void ESM::Filter::load (ESMReader& esm, bool &isDeleted) { - mIsDeleted = false; + isDeleted = false; while (esm.hasMoreSubs()) { @@ -24,16 +20,16 @@ void ESM::Filter::load (ESMReader& esm) case ESM::FourCC<'N','A','M','E'>::value: mId = esm.getHString(); break; - case ESM::FourCC<'D','E','L','E'>::value: - esm.skipHSub(); - mIsDeleted = true; - break; case ESM::FourCC<'F','I','L','T'>::value: mFilter = esm.getHString(); break; case ESM::FourCC<'D','E','S','C'>::value: mDescription = esm.getHString(); break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + isDeleted = true; + break; default: esm.fail("Unknown subrecord"); break; @@ -41,11 +37,11 @@ void ESM::Filter::load (ESMReader& esm) } } -void ESM::Filter::save (ESMWriter& esm) const +void ESM::Filter::save (ESMWriter& esm, bool isDeleted) const { esm.writeHNCString ("NAME", mId); - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); return; @@ -59,5 +55,4 @@ void ESM::Filter::blank() { mFilter.clear(); mDescription.clear(); - mIsDeleted = false; } diff --git a/components/esm/filter.hpp b/components/esm/filter.hpp index 1a8af9229..b1c511ebb 100644 --- a/components/esm/filter.hpp +++ b/components/esm/filter.hpp @@ -18,12 +18,8 @@ namespace ESM std::string mFilter; - bool mIsDeleted; - - Filter(); - - void load (ESMReader& esm); - void save (ESMWriter& esm) const; + void load (ESMReader& esm, bool &isDeleted); + void save (ESMWriter& esm, bool isDeleted = false) const; void blank(); ///< Set record to default state (does not touch the ID). diff --git a/components/esm/loadacti.cpp b/components/esm/loadacti.cpp index c32cea1a6..14db45c34 100644 --- a/components/esm/loadacti.cpp +++ b/components/esm/loadacti.cpp @@ -8,29 +8,20 @@ namespace ESM { unsigned int Activator::sRecordId = REC_ACTI; - Activator::Activator() - : mIsDeleted(false) - {} - - void Activator::load(ESMReader &esm) + void Activator::load(ESMReader &esm, bool &isDeleted) { - mIsDeleted = false; + isDeleted = false; bool hasName = false; while (esm.hasMoreSubs()) { esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + switch (esm.retSubName().val) { case ESM::FourCC<'N','A','M','E'>::value: mId = esm.getHString(); hasName = true; break; - case ESM::FourCC<'D','E','L','E'>::value: - esm.skipHSub(); - mIsDeleted = true; - break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; @@ -40,6 +31,10 @@ namespace ESM case ESM::FourCC<'S','C','R','I'>::value: mScript = esm.getHString(); break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + isDeleted = true; + break; default: esm.fail("Unknown subrecord"); break; @@ -49,11 +44,11 @@ namespace ESM if (!hasName) esm.fail("Missing NAME subrecord"); } - void Activator::save(ESMWriter &esm) const + void Activator::save(ESMWriter &esm, bool isDeleted) const { esm.writeHNCString("NAME", mId); - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); return; @@ -69,6 +64,5 @@ namespace ESM mName.clear(); mScript.clear(); mModel.clear(); - mIsDeleted = false; } } diff --git a/components/esm/loadacti.hpp b/components/esm/loadacti.hpp index 93de07b25..4cc72d528 100644 --- a/components/esm/loadacti.hpp +++ b/components/esm/loadacti.hpp @@ -17,12 +17,8 @@ struct Activator std::string mId, mName, mScript, mModel; - bool mIsDeleted; - - Activator(); - - void load(ESMReader &esm); - void save(ESMWriter &esm) const; + void load(ESMReader &esm, bool &isDeleted); + void save(ESMWriter &esm, bool isDeleted = false) const; void blank(); ///< Set record to default state (does not touch the ID). diff --git a/components/esm/loadalch.cpp b/components/esm/loadalch.cpp index c1213583d..ceff4ba7d 100644 --- a/components/esm/loadalch.cpp +++ b/components/esm/loadalch.cpp @@ -8,31 +8,23 @@ namespace ESM { unsigned int Potion::sRecordId = REC_ALCH; - Potion::Potion() - : mIsDeleted(false) - {} - - void Potion::load(ESMReader &esm) + void Potion::load(ESMReader &esm, bool &isDeleted) { + isDeleted = false; + mEffects.mList.clear(); - mIsDeleted = false; bool hasName = false; bool hasData = false; while (esm.hasMoreSubs()) { esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + switch (esm.retSubName().val) { case ESM::FourCC<'N','A','M','E'>::value: mId = esm.getHString(); hasName = true; break; - case ESM::FourCC<'D','E','L','E'>::value: - esm.skipHSub(); - mIsDeleted = true; - break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; @@ -52,6 +44,10 @@ namespace ESM case ESM::FourCC<'E','N','A','M'>::value: mEffects.add(esm); break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + isDeleted = true; + break; default: esm.fail("Unknown subrecord"); break; @@ -60,14 +56,14 @@ namespace ESM if (!hasName) esm.fail("Missing NAME subrecord"); - if (!hasData && !mIsDeleted) + if (!hasData && !isDeleted) esm.fail("Missing ALDT subrecord"); } - void Potion::save(ESMWriter &esm) const + void Potion::save(ESMWriter &esm, bool isDeleted) const { esm.writeHNCString("NAME", mId); - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); return; @@ -91,6 +87,5 @@ namespace ESM mIcon.clear(); mScript.clear(); mEffects.mList.clear(); - mIsDeleted = false; } } diff --git a/components/esm/loadalch.hpp b/components/esm/loadalch.hpp index 921585a9d..9ef390ebd 100644 --- a/components/esm/loadalch.hpp +++ b/components/esm/loadalch.hpp @@ -33,12 +33,8 @@ struct Potion std::string mId, mName, mModel, mIcon, mScript; EffectList mEffects; - bool mIsDeleted; - - Potion(); - - void load(ESMReader &esm); - void save(ESMWriter &esm) const; + void load(ESMReader &esm, bool &isDeleted); + void save(ESMWriter &esm, bool isDeleted = false) const; void blank(); ///< Set record to default state (does not touch the ID). diff --git a/components/esm/loadappa.cpp b/components/esm/loadappa.cpp index edf1f473b..7a77ba421 100644 --- a/components/esm/loadappa.cpp +++ b/components/esm/loadappa.cpp @@ -8,30 +8,21 @@ namespace ESM { unsigned int Apparatus::sRecordId = REC_APPA; - Apparatus::Apparatus() - : mIsDeleted(false) - {} - - void Apparatus::load(ESMReader &esm) + void Apparatus::load(ESMReader &esm, bool &isDeleted) { - mIsDeleted = false; + isDeleted = false; bool hasName = false; bool hasData = false; while (esm.hasMoreSubs()) { esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + switch (esm.retSubName().val) { case ESM::FourCC<'N','A','M','E'>::value: mId = esm.getHString(); hasName = true; break; - case ESM::FourCC<'D','E','L','E'>::value: - esm.skipHSub(); - mIsDeleted = true; - break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; @@ -48,6 +39,10 @@ namespace ESM case ESM::FourCC<'I','T','E','X'>::value: mIcon = esm.getHString(); break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + isDeleted = true; + break; default: esm.fail("Unknown subrecord"); break; @@ -56,15 +51,15 @@ namespace ESM if (!hasName) esm.fail("Missing NAME subrecord"); - if (!hasData && !mIsDeleted) + if (!hasData && !isDeleted) esm.fail("Missing AADT subrecord"); } - void Apparatus::save(ESMWriter &esm) const + void Apparatus::save(ESMWriter &esm, bool isDeleted) const { esm.writeHNCString("NAME", mId); - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); return; @@ -87,6 +82,5 @@ namespace ESM mIcon.clear(); mScript.clear(); mName.clear(); - mIsDeleted = false; } } diff --git a/components/esm/loadappa.hpp b/components/esm/loadappa.hpp index 2dac37995..0590d33ed 100644 --- a/components/esm/loadappa.hpp +++ b/components/esm/loadappa.hpp @@ -38,12 +38,8 @@ struct Apparatus AADTstruct mData; std::string mId, mModel, mIcon, mScript, mName; - bool mIsDeleted; - - Apparatus(); - - void load(ESMReader &esm); - void save(ESMWriter &esm) const; + void load(ESMReader &esm, bool &isDeleted); + void save(ESMWriter &esm, bool isDeleted = false) const; void blank(); ///< Set record to default state (does not touch the ID). diff --git a/components/esm/loadarmo.cpp b/components/esm/loadarmo.cpp index d5b9fdd44..600c417be 100644 --- a/components/esm/loadarmo.cpp +++ b/components/esm/loadarmo.cpp @@ -38,31 +38,23 @@ namespace ESM unsigned int Armor::sRecordId = REC_ARMO; - Armor::Armor() - : mIsDeleted(false) - {} - - void Armor::load(ESMReader &esm) + void Armor::load(ESMReader &esm, bool &isDeleted) { + isDeleted = false; + mParts.mParts.clear(); - mIsDeleted = false; bool hasName = false; bool hasData = false; while (esm.hasMoreSubs()) { esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + switch (esm.retSubName().val) { case ESM::FourCC<'N','A','M','E'>::value: mId = esm.getHString(); hasName = true; break; - case ESM::FourCC<'D','E','L','E'>::value: - esm.skipHSub(); - mIsDeleted = true; - break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; @@ -85,6 +77,10 @@ namespace ESM case ESM::FourCC<'I','N','D','X'>::value: mParts.add(esm); break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + isDeleted = true; + break; default: esm.fail("Unknown subrecord"); break; @@ -93,15 +89,15 @@ namespace ESM if (!hasName) esm.fail("Missing NAME subrecord"); - if (!hasData && !mIsDeleted) + if (!hasData && !isDeleted) esm.fail("Missing CTDT subrecord"); } - void Armor::save(ESMWriter &esm) const + void Armor::save(ESMWriter &esm, bool isDeleted) const { esm.writeHNCString("NAME", mId); - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); return; @@ -130,6 +126,5 @@ namespace ESM mIcon.clear(); mScript.clear(); mEnchant.clear(); - mIsDeleted = false; } } diff --git a/components/esm/loadarmo.hpp b/components/esm/loadarmo.hpp index 4ebe181a7..ef3bb734c 100644 --- a/components/esm/loadarmo.hpp +++ b/components/esm/loadarmo.hpp @@ -96,12 +96,8 @@ struct Armor std::string mId, mName, mModel, mIcon, mScript, mEnchant; - bool mIsDeleted; - - Armor(); - - void load(ESMReader &esm); - void save(ESMWriter &esm) const; + void load(ESMReader &esm, bool &isDeleted); + void save(ESMWriter &esm, bool isDeleted = false) const; void blank(); ///< Set record to default state (does not touch the ID). diff --git a/components/esm/loadbody.cpp b/components/esm/loadbody.cpp index e2c6ad7b2..20d6b35cf 100644 --- a/components/esm/loadbody.cpp +++ b/components/esm/loadbody.cpp @@ -8,30 +8,21 @@ namespace ESM { unsigned int BodyPart::sRecordId = REC_BODY; - BodyPart::BodyPart() - : mIsDeleted(false) - {} - - void BodyPart::load(ESMReader &esm) + void BodyPart::load(ESMReader &esm, bool &isDeleted) { - mIsDeleted = false; + isDeleted = false; bool hasName = false; bool hasData = false; while (esm.hasMoreSubs()) { esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + switch (esm.retSubName().val) { case ESM::FourCC<'N','A','M','E'>::value: mId = esm.getHString(); hasName = true; break; - case ESM::FourCC<'D','E','L','E'>::value: - esm.skipHSub(); - mIsDeleted = true; - break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; @@ -42,6 +33,10 @@ namespace ESM esm.getHT(mData, 4); hasData = true; break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + isDeleted = true; + break; default: esm.fail("Unknown subrecord"); break; @@ -50,15 +45,15 @@ namespace ESM if (!hasName) esm.fail("Missing NAME subrecord"); - if (!hasData && !mIsDeleted) + if (!hasData && !isDeleted) esm.fail("Missing BYDT subrecord"); } - void BodyPart::save(ESMWriter &esm) const + void BodyPart::save(ESMWriter &esm, bool isDeleted) const { esm.writeHNCString("NAME", mId); - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); return; @@ -78,7 +73,5 @@ namespace ESM mModel.clear(); mRace.clear(); - - mIsDeleted = false; } } diff --git a/components/esm/loadbody.hpp b/components/esm/loadbody.hpp index f32d2fb58..bf320330f 100644 --- a/components/esm/loadbody.hpp +++ b/components/esm/loadbody.hpp @@ -60,12 +60,8 @@ struct BodyPart BYDTstruct mData; std::string mId, mModel, mRace; - bool mIsDeleted; - - BodyPart(); - - void load(ESMReader &esm); - void save(ESMWriter &esm) const; + void load(ESMReader &esm, bool &isDeleted); + void save(ESMWriter &esm, bool isDeleted = false) const; void blank(); ///< Set record to default state (does not touch the ID). diff --git a/components/esm/loadbook.cpp b/components/esm/loadbook.cpp index 2d0d3ce75..b08b12f50 100644 --- a/components/esm/loadbook.cpp +++ b/components/esm/loadbook.cpp @@ -8,30 +8,21 @@ namespace ESM { unsigned int Book::sRecordId = REC_BOOK; - Book::Book() - : mIsDeleted(false) - {} - - void Book::load(ESMReader &esm) + void Book::load(ESMReader &esm, bool &isDeleted) { - mIsDeleted = false; + isDeleted = false; bool hasName = false; bool hasData = false; while (esm.hasMoreSubs()) { esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + switch (esm.retSubName().val) { case ESM::FourCC<'N','A','M','E'>::value: mId = esm.getHString(); hasName = true; break; - case ESM::FourCC<'D','E','L','E'>::value: - esm.skipHSub(); - mIsDeleted = true; - break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; @@ -54,6 +45,10 @@ namespace ESM case ESM::FourCC<'T','E','X','T'>::value: mText = esm.getHString(); break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + isDeleted = true; + break; default: esm.fail("Unknown subrecord"); break; @@ -62,14 +57,14 @@ namespace ESM if (!hasName) esm.fail("Missing NAME subrecord"); - if (!hasData && !mIsDeleted) + if (!hasData && !isDeleted) esm.fail("Missing BKDT subrecord"); } - void Book::save(ESMWriter &esm) const + void Book::save(ESMWriter &esm, bool isDeleted) const { esm.writeHNCString("NAME", mId); - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); return; @@ -97,6 +92,5 @@ namespace ESM mScript.clear(); mEnchant.clear(); mText.clear(); - mIsDeleted = false; } } diff --git a/components/esm/loadbook.hpp b/components/esm/loadbook.hpp index 931f813c0..3d50356ae 100644 --- a/components/esm/loadbook.hpp +++ b/components/esm/loadbook.hpp @@ -28,12 +28,8 @@ struct Book std::string mName, mModel, mIcon, mScript, mEnchant, mText; std::string mId; - bool mIsDeleted; - - Book(); - - void load(ESMReader &esm); - void save(ESMWriter &esm) const; + void load(ESMReader &esm, bool &isDeleted); + void save(ESMWriter &esm, bool isDeleted = false) const; void blank(); ///< Set record to default state (does not touch the ID). diff --git a/components/esm/loadbsgn.cpp b/components/esm/loadbsgn.cpp index 54de009aa..56dc1897c 100644 --- a/components/esm/loadbsgn.cpp +++ b/components/esm/loadbsgn.cpp @@ -8,30 +8,22 @@ namespace ESM { unsigned int BirthSign::sRecordId = REC_BSGN; - BirthSign::BirthSign() - : mIsDeleted(false) - {} - - void BirthSign::load(ESMReader &esm) + void BirthSign::load(ESMReader &esm, bool &isDeleted) { + isDeleted = false; + mPowers.mList.clear(); - mIsDeleted = false; bool hasName = false; while (esm.hasMoreSubs()) { esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + switch (esm.retSubName().val) { case ESM::FourCC<'N','A','M','E'>::value: mId = esm.getHString(); hasName = true; break; - case ESM::FourCC<'D','E','L','E'>::value: - esm.skipHSub(); - mIsDeleted = true; - break; case ESM::FourCC<'F','N','A','M'>::value: mName = esm.getHString(); break; @@ -44,6 +36,10 @@ namespace ESM case ESM::FourCC<'N','P','C','S'>::value: mPowers.add(esm); break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + isDeleted = true; + break; default: esm.fail("Unknown subrecord"); break; @@ -54,9 +50,9 @@ namespace ESM esm.fail("Missing NAME subrecord"); } - void BirthSign::save(ESMWriter &esm) const + void BirthSign::save(ESMWriter &esm, bool isDeleted) const { - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); } @@ -75,7 +71,6 @@ namespace ESM mDescription.clear(); mTexture.clear(); mPowers.mList.clear(); - mIsDeleted = false; } } diff --git a/components/esm/loadbsgn.hpp b/components/esm/loadbsgn.hpp index 685ade82f..24d27a7f8 100644 --- a/components/esm/loadbsgn.hpp +++ b/components/esm/loadbsgn.hpp @@ -22,12 +22,8 @@ struct BirthSign // List of powers and abilities that come with this birth sign. SpellList mPowers; - bool mIsDeleted; - - BirthSign(); - - void load(ESMReader &esm); - void save(ESMWriter &esm) const; + void load(ESMReader &esm, bool &isDeleted); + void save(ESMWriter &esm, bool isDeleted = false) const; void blank(); ///< Set record to default state (does not touch the ID/index). diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index 7e02f0f85..2d8daa584 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -52,75 +52,98 @@ namespace ESM return ref.mRefNum == refNum; } - void Cell::load(ESMReader &esm, bool saveContext) + void Cell::load(ESMReader &esm, bool &isDeleted, bool saveContext) { - loadName(esm); - loadData(esm); + loadNameAndData(esm, isDeleted); loadCell(esm, saveContext); } - void Cell::loadName(ESMReader &esm) + void Cell::loadNameAndData(ESMReader &esm, bool &isDeleted) { - mName = esm.getHNString("NAME"); + isDeleted = false; - mIsDeleted = false; - if (esm.isNextSub("DELE")) + bool hasName = false; + bool hasData = false; + bool isLoaded = false; + while (!isLoaded && esm.hasMoreSubs()) { - esm.skipHSub(); - mIsDeleted = true; + esm.getSubName(); + switch (esm.retSubName().val) + { + case ESM::FourCC<'N','A','M','E'>::value: + mName = esm.getHString(); + hasName = true; + break; + case ESM::FourCC<'D','A','T','A'>::value: + esm.getHT(mData, 12); + hasData = true; + break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + isDeleted = true; + break; + default: + esm.cacheSubName(); + isLoaded = true; + break; + } } + + if (!hasName) + esm.fail("Missing NAME subrecord"); + if (!hasData) + esm.fail("Missing DATA subrecord"); } void Cell::loadCell(ESMReader &esm, bool saveContext) { + mWater = 0.0f; + mWaterInt = false; + mMapColor = 0; + mRegion.clear(); mRefNumCounter = 0; - if (mData.mFlags & Interior) + bool isLoaded = false; + while (!isLoaded && esm.hasMoreSubs()) { - // Interior cells - if (esm.isNextSub("INTV")) + esm.getSubName(); + switch (esm.retSubName().val) { - int waterl; - esm.getHT(waterl); - mWater = (float) waterl; - mWaterInt = true; + case ESM::FourCC<'I','N','T','V'>::value: + int waterl; + esm.getHT(waterl); + mWater = static_cast(waterl); + mWaterInt = true; + break; + case ESM::FourCC<'W','H','G','T'>::value: + esm.getHT(mWater); + break; + case ESM::FourCC<'A','M','B','I'>::value: + esm.getHT(mAmbi); + break; + case ESM::FourCC<'R','G','N','N'>::value: + mRegion = esm.getHString(); + break; + case ESM::FourCC<'N','A','M','5'>::value: + esm.getHT(mMapColor); + break; + case ESM::FourCC<'N','A','M','0'>::value: + esm.getHT(mRefNumCounter); + break; + default: + esm.cacheSubName(); + isLoaded = true; + break; } - else if (esm.isNextSub("WHGT")) - { - esm.getHT(mWater); - } - - // Quasi-exterior cells have a region (which determines the - // weather), pure interior cells have ambient lighting - // instead. - if (mData.mFlags & QuasiEx) - mRegion = esm.getHNOString("RGNN"); - else if (esm.isNextSub("AMBI")) - esm.getHT(mAmbi); - } - else - { - // Exterior cells - mRegion = esm.getHNOString("RGNN"); - - mMapColor = 0; - esm.getHNOT(mMapColor, "NAM5"); - } - if (esm.isNextSub("NAM0")) { - esm.getHT(mRefNumCounter); } - if (saveContext) { + if (saveContext) + { mContextList.push_back(esm.getContext()); esm.skipRecord(); } } - void Cell::loadData(ESMReader &esm) - { - esm.getHNT(mData, "DATA", 12); - } - void Cell::postLoad(ESMReader &esm) { // Save position of the cell references and move on @@ -128,11 +151,11 @@ namespace ESM esm.skipRecord(); } - void Cell::save(ESMWriter &esm) const + void Cell::save(ESMWriter &esm, bool isDeleted) const { esm.writeHNCString("NAME", mName); - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); } @@ -183,8 +206,10 @@ namespace ESM } } - bool Cell::getNextRef(ESMReader &esm, CellRef &ref, bool ignoreMoves, MovedCellRef *mref) + bool Cell::getNextRef(ESMReader &esm, CellRef &ref, bool &isDeleted, bool ignoreMoves, MovedCellRef *mref) { + isDeleted = false; + // TODO: Try and document reference numbering, I don't think this has been done anywhere else. if (!esm.hasMoreSubs()) return false; @@ -207,12 +232,15 @@ namespace ESM } } - ref.load (esm); - - // Identify references belonging to a parent file and adapt the ID accordingly. - adjustRefNum (ref.mRefNum, esm); + if (esm.peekNextSub("FRMR")) + { + ref.load (esm, isDeleted); - return true; + // Identify references belonging to a parent file and adapt the ID accordingly. + adjustRefNum (ref.mRefNum, esm); + return true; + } + return false; } bool Cell::getNextMVRF(ESMReader &esm, MovedCellRef &mref) @@ -242,8 +270,6 @@ namespace ESM mAmbi.mSunlight = 0; mAmbi.mFog = 0; mAmbi.mFogDensity = 0; - - mIsDeleted = false; } CellId Cell::getCellId() const diff --git a/components/esm/loadcell.hpp b/components/esm/loadcell.hpp index a1a758e3b..2a7a78a54 100644 --- a/components/esm/loadcell.hpp +++ b/components/esm/loadcell.hpp @@ -85,8 +85,7 @@ struct Cell mWater(0), mWaterInt(false), mMapColor(0), - mRefNumCounter(0), - mIsDeleted(false) + mRefNumCounter(0) {} // Interior cells are indexed by this (it's the 'id'), for exterior @@ -113,18 +112,15 @@ struct Cell CellRefTracker mLeasedRefs; MovedCellRefTracker mMovedRefs; - bool mIsDeleted; - void postLoad(ESMReader &esm); // This method is left in for compatibility with esmtool. Parsing moved references currently requires // passing ESMStore, bit it does not know about this parameter, so we do it this way. - void load(ESMReader &esm, bool saveContext = true); // Load everything (except references) - void loadName(ESMReader &esm); // Load NAME and checks for DELE - void loadData(ESMReader &esm); // Load DATAstruct only - void loadCell(ESMReader &esm, bool saveContext = true); // Load everything, except DATAstruct and references + void load(ESMReader &esm, bool &isDeleted, bool saveContext = true); // Load everything (except references) + void loadNameAndData(ESMReader &esm, bool &isDeleted); // Load NAME and DATAstruct + void loadCell(ESMReader &esm, bool saveContext = true); // Load everything, except NAME, DATAstruct and references - void save(ESMWriter &esm) const; + void save(ESMWriter &esm, bool isDeleted = false) const; bool isExterior() const { @@ -163,7 +159,11 @@ struct Cell reuse one memory location without blanking it between calls. */ /// \param ignoreMoves ignore MVRF record and read reference like a regular CellRef. - static bool getNextRef(ESMReader &esm, CellRef &ref, bool ignoreMoves = false, MovedCellRef *mref = 0); + static bool getNextRef(ESMReader &esm, + CellRef &ref, + bool &isDeleted, + bool ignoreMoves = false, + MovedCellRef *mref = 0); /* This fetches an MVRF record, which is used to track moved references. * Since they are comparably rare, we use a separate method for this. diff --git a/components/esm/loadclas.cpp b/components/esm/loadclas.cpp index b58c35d90..2ad14b9f2 100644 --- a/components/esm/loadclas.cpp +++ b/components/esm/loadclas.cpp @@ -22,10 +22,6 @@ namespace ESM "sSpecializationStealth" }; - Class::Class() - : mIsDeleted(false) - {} - int& Class::CLDTstruct::getSkill (int index, bool major) { if (index<0 || index>=5) @@ -42,26 +38,21 @@ namespace ESM return mSkills[index][major ? 1 : 0]; } - void Class::load(ESMReader &esm) + void Class::load(ESMReader &esm, bool &isDeleted) { - mIsDeleted = false; + isDeleted = false; bool hasName = false; bool hasData = false; while (esm.hasMoreSubs()) { esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + switch (esm.retSubName().val) { case ESM::FourCC<'N','A','M','E'>::value: mId = esm.getHString(); hasName = true; break; - case ESM::FourCC<'D','E','L','E'>::value: - esm.skipHSub(); - mIsDeleted = true; - break; case ESM::FourCC<'F','N','A','M'>::value: mName = esm.getHString(); break; @@ -74,6 +65,10 @@ namespace ESM case ESM::FourCC<'D','E','S','C'>::value: mDescription = esm.getHString(); break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + isDeleted = true; + break; default: esm.fail("Unknown subrecord"); break; @@ -82,14 +77,14 @@ namespace ESM if (!hasName) esm.fail("Missing NAME subrecord"); - if (!hasData && !mIsDeleted) + if (!hasData && !isDeleted) esm.fail("Missing CLDT subrecord"); } - void Class::save(ESMWriter &esm) const + void Class::save(ESMWriter &esm, bool isDeleted) const { esm.writeHNCString("NAME", mId); - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); return; @@ -113,7 +108,5 @@ namespace ESM for (int i=0; i<5; ++i) for (int i2=0; i2<2; ++i2) mData.mSkills[i][i2] = 0; - - mIsDeleted = false; } } diff --git a/components/esm/loadclas.hpp b/components/esm/loadclas.hpp index 399e93c24..833dd6757 100644 --- a/components/esm/loadclas.hpp +++ b/components/esm/loadclas.hpp @@ -73,12 +73,8 @@ struct Class std::string mId, mName, mDescription; CLDTstruct mData; - bool mIsDeleted; - - Class(); - - void load(ESMReader &esm); - void save(ESMWriter &esm) const; + void load(ESMReader &esm, bool &isDeleted); + void save(ESMWriter &esm, bool isDeleted = false) const; void blank(); ///< Set record to default state (does not touch the ID/index). diff --git a/components/esm/loadclot.cpp b/components/esm/loadclot.cpp index 18f7cd44f..8a88e6d7a 100644 --- a/components/esm/loadclot.cpp +++ b/components/esm/loadclot.cpp @@ -8,31 +8,23 @@ namespace ESM { unsigned int Clothing::sRecordId = REC_CLOT; - Clothing::Clothing() - : mIsDeleted(false) - {} - - void Clothing::load(ESMReader &esm) + void Clothing::load(ESMReader &esm, bool &isDeleted) { + isDeleted = false; + mParts.mParts.clear(); - mIsDeleted = false; bool hasName = false; bool hasData = false; while (esm.hasMoreSubs()) { esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + switch (esm.retSubName().val) { case ESM::FourCC<'N','A','M','E'>::value: mId = esm.getHString(); hasName = true; break; - case ESM::FourCC<'D','E','L','E'>::value: - esm.skipHSub(); - mIsDeleted = true; - break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; @@ -55,6 +47,10 @@ namespace ESM case ESM::FourCC<'I','N','D','X'>::value: mParts.add(esm); break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + isDeleted = true; + break; default: esm.fail("Unknown subrecord"); break; @@ -63,15 +59,15 @@ namespace ESM if (!hasName) esm.fail("Missing NAME subrecord"); - if (!hasData && !mIsDeleted) + if (!hasData && !isDeleted) esm.fail("Missing CTDT subrecord"); } - void Clothing::save(ESMWriter &esm) const + void Clothing::save(ESMWriter &esm, bool isDeleted) const { esm.writeHNCString("NAME", mId); - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); return; @@ -101,6 +97,5 @@ namespace ESM mIcon.clear(); mEnchant.clear(); mScript.clear(); - mIsDeleted = false; } } diff --git a/components/esm/loadclot.hpp b/components/esm/loadclot.hpp index 202c1ec45..39e5ea672 100644 --- a/components/esm/loadclot.hpp +++ b/components/esm/loadclot.hpp @@ -48,12 +48,8 @@ struct Clothing std::string mId, mName, mModel, mIcon, mEnchant, mScript; - bool mIsDeleted; - - Clothing(); - - void load(ESMReader &esm); - void save(ESMWriter &esm) const; + void load(ESMReader &esm, bool &isDeleted); + void save(ESMWriter &esm, bool isDeleted = false) const; void blank(); ///< Set record to default state (does not touch the ID). diff --git a/components/esm/loadcont.cpp b/components/esm/loadcont.cpp index fadfe5f0f..372683750 100644 --- a/components/esm/loadcont.cpp +++ b/components/esm/loadcont.cpp @@ -24,16 +24,11 @@ namespace ESM unsigned int Container::sRecordId = REC_CONT; - Container::Container() - : mWeight(0), - mFlags(0x8), - mIsDeleted(false) - {} - - void Container::load(ESMReader &esm) + void Container::load(ESMReader &esm, bool &isDeleted) { + isDeleted = false; + mInventory.mList.clear(); - mIsDeleted = false; bool hasName = false; bool hasWeight = false; @@ -41,17 +36,12 @@ namespace ESM while (esm.hasMoreSubs()) { esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + switch (esm.retSubName().val) { case ESM::FourCC<'N','A','M','E'>::value: mId = esm.getHString(); hasName = true; break; - case ESM::FourCC<'D','E','L','E'>::value: - esm.skipHSub(); - mIsDeleted = true; - break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; @@ -76,6 +66,10 @@ namespace ESM case ESM::FourCC<'N','P','C','O'>::value: mInventory.add(esm); break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + isDeleted = true; + break; default: esm.fail("Unknown subrecord"); break; @@ -84,17 +78,17 @@ namespace ESM if (!hasName) esm.fail("Missing NAME subrecord"); - if (!hasWeight && !mIsDeleted) + if (!hasWeight && !isDeleted) esm.fail("Missing CNDT subrecord"); - if (!hasFlags && !mIsDeleted) + if (!hasFlags && !isDeleted) esm.fail("Missing FLAG subrecord"); } - void Container::save(ESMWriter &esm) const + void Container::save(ESMWriter &esm, bool isDeleted) const { esm.writeHNCString("NAME", mId); - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); return; @@ -118,6 +112,5 @@ namespace ESM mWeight = 0; mFlags = 0x8; // set default flag value mInventory.mList.clear(); - mIsDeleted = false; } } diff --git a/components/esm/loadcont.hpp b/components/esm/loadcont.hpp index 31c7e1815..4c847f4e2 100644 --- a/components/esm/loadcont.hpp +++ b/components/esm/loadcont.hpp @@ -52,12 +52,8 @@ struct Container int mFlags; InventoryList mInventory; - bool mIsDeleted; - - Container(); - - void load(ESMReader &esm); - void save(ESMWriter &esm) const; + void load(ESMReader &esm, bool &isDeleted); + void save(ESMWriter &esm, bool isDeleted = false) const; void blank(); ///< Set record to default state (does not touch the ID). diff --git a/components/esm/loadcrea.cpp b/components/esm/loadcrea.cpp index f360c8748..67c0ba31d 100644 --- a/components/esm/loadcrea.cpp +++ b/components/esm/loadcrea.cpp @@ -8,14 +8,10 @@ namespace ESM { unsigned int Creature::sRecordId = REC_CREA; - Creature::Creature() - : mFlags(0), - mScale(0.0f), - mIsDeleted(false) - {} - - void Creature::load(ESMReader &esm) + void Creature::load(ESMReader &esm, bool &isDeleted) { + isDeleted = false; + mPersistent = (esm.getRecordFlags() & 0x0400) != 0; mAiPackage.mList.clear(); @@ -25,7 +21,6 @@ namespace ESM { mScale = 1.f; mHasAI = false; - mIsDeleted = false; bool hasName = false; bool hasNpdt = false; @@ -33,17 +28,12 @@ namespace ESM { while (esm.hasMoreSubs()) { esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + switch (esm.retSubName().val) { case ESM::FourCC<'N','A','M','E'>::value: mId = esm.getHString(); hasName = true; break; - case ESM::FourCC<'D','E','L','E'>::value: - esm.skipHSub(); - mIsDeleted = true; - break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; @@ -89,6 +79,10 @@ namespace ESM { case AI_CNDT: mAiPackage.add(esm); break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + isDeleted = true; + break; default: esm.fail("Unknown subrecord"); break; @@ -97,17 +91,17 @@ namespace ESM { if (!hasName) esm.fail("Missing NAME subrecord"); - if (!hasNpdt && !mIsDeleted) + if (!hasNpdt && !isDeleted) esm.fail("Missing NPDT subrecord"); - if (!hasFlags && !mIsDeleted) + if (!hasFlags && !isDeleted) esm.fail("Missing FLAG subrecord"); } - void Creature::save(ESMWriter &esm) const + void Creature::save(ESMWriter &esm, bool isDeleted) const { esm.writeHNCString("NAME", mId); - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); return; @@ -156,7 +150,6 @@ namespace ESM { mAiData.mServices = 0; mAiPackage.mList.clear(); mTransport.mList.clear(); - mIsDeleted = false; } const std::vector& Creature::getTransport() const diff --git a/components/esm/loadcrea.hpp b/components/esm/loadcrea.hpp index 22e834e45..a5147619c 100644 --- a/components/esm/loadcrea.hpp +++ b/components/esm/loadcrea.hpp @@ -96,14 +96,10 @@ struct Creature AIPackageList mAiPackage; Transport mTransport; - bool mIsDeleted; - - Creature(); - const std::vector& getTransport() const; - void load(ESMReader &esm); - void save(ESMWriter &esm) const; + void load(ESMReader &esm, bool &isDeleted); + void save(ESMWriter &esm, bool isDeleted = false) const; void blank(); ///< Set record to default state (does not touch the ID). diff --git a/components/esm/loaddial.cpp b/components/esm/loaddial.cpp index 74a708805..30fa3cfef 100644 --- a/components/esm/loaddial.cpp +++ b/components/esm/loaddial.cpp @@ -10,29 +10,25 @@ namespace ESM { unsigned int Dialogue::sRecordId = REC_DIAL; - Dialogue::Dialogue() - : mIsDeleted(false) - {} - - void Dialogue::load(ESMReader &esm) + void Dialogue::load(ESMReader &esm, bool &isDeleted) { loadId(esm); - loadData(esm); + loadData(esm, isDeleted); } void Dialogue::loadId(ESMReader &esm) { - mIsDeleted = false; mId = esm.getHNString("NAME"); } - void Dialogue::loadData(ESMReader &esm) + void Dialogue::loadData(ESMReader &esm, bool &isDeleted) { + isDeleted = false; + while (esm.hasMoreSubs()) { esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + switch (esm.retSubName().val) { case ESM::FourCC<'D','A','T','A'>::value: { @@ -51,7 +47,7 @@ namespace ESM case ESM::FourCC<'D','E','L','E'>::value: esm.skipHSub(); mType = Unknown; - mIsDeleted = true; + isDeleted = true; break; default: esm.fail("Unknown subrecord"); @@ -60,10 +56,10 @@ namespace ESM } } - void Dialogue::save(ESMWriter &esm) const + void Dialogue::save(ESMWriter &esm, bool isDeleted) const { esm.writeHNCString("NAME", mId); - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); } @@ -76,7 +72,6 @@ namespace ESM void Dialogue::blank() { mInfo.clear(); - mIsDeleted = false; } void Dialogue::readInfo(ESMReader &esm, bool merge) @@ -84,25 +79,27 @@ namespace ESM ESM::DialInfo info; info.loadId(esm); + bool isDeleted = false; if (!merge || mInfo.empty()) { - info.loadInfo(esm); - mLookup[info.mId] = mInfo.insert(mInfo.end(), info); + info.loadData(esm, isDeleted); + mLookup[info.mId] = std::make_pair(mInfo.insert(mInfo.end(), info), isDeleted); + return; } - ESM::Dialogue::InfoContainer::iterator it = mInfo.end(); + InfoContainer::iterator it = mInfo.end(); - std::map::iterator lookup; + LookupMap::iterator lookup; lookup = mLookup.find(info.mId); if (lookup != mLookup.end()) { - it = lookup->second; + it = lookup->second.first; // Merge with existing record. Only the subrecords that are present in // the new record will be overwritten. - it->loadInfo(esm); + it->loadData(esm, isDeleted); info = *it; // Since the record merging may have changed the next/prev linked list connection, we need to re-insert the record @@ -111,35 +108,35 @@ namespace ESM } else { - info.loadInfo(esm); + info.loadData(esm, isDeleted); } if (info.mNext.empty()) { - mLookup[info.mId] = mInfo.insert(mInfo.end(), info); + mLookup[info.mId] = std::make_pair(mInfo.insert(mInfo.end(), info), isDeleted); return; } if (info.mPrev.empty()) { - mLookup[info.mId] = mInfo.insert(mInfo.begin(), info); + mLookup[info.mId] = std::make_pair(mInfo.insert(mInfo.begin(), info), isDeleted); return; } lookup = mLookup.find(info.mPrev); if (lookup != mLookup.end()) { - it = lookup->second; + it = lookup->second.first; - mLookup[info.mId] = mInfo.insert(++it, info); + mLookup[info.mId] = std::make_pair(mInfo.insert(++it, info), isDeleted); return; } lookup = mLookup.find(info.mNext); if (lookup != mLookup.end()) { - it = lookup->second; + it = lookup->second.first; - mLookup[info.mId] = mInfo.insert(it, info); + mLookup[info.mId] = std::make_pair(mInfo.insert(it, info), isDeleted); return; } @@ -148,12 +145,15 @@ namespace ESM void Dialogue::clearDeletedInfos() { - for (InfoContainer::iterator it = mInfo.begin(); it != mInfo.end(); ) + LookupMap::const_iterator current = mLookup.begin(); + LookupMap::const_iterator end = mLookup.end(); + for (; current != end; ++current) { - if (it->mIsDeleted) - it = mInfo.erase(it); - else - ++it; + if (current->second.second) + { + mInfo.erase(current->second.first); + } } + mLookup.clear(); } } diff --git a/components/esm/loaddial.hpp b/components/esm/loaddial.hpp index 73bf16974..e517fc86f 100644 --- a/components/esm/loaddial.hpp +++ b/components/esm/loaddial.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include "loadinfo.hpp" @@ -39,27 +40,24 @@ struct Dialogue typedef std::list InfoContainer; - typedef std::map LookupMap; + // Parameters: Info ID, (Info iterator, Deleted flag) + typedef std::map > LookupMap; InfoContainer mInfo; // This is only used during the loading phase to speed up DialInfo merging. LookupMap mLookup; - bool mIsDeleted; - - Dialogue(); - - void load(ESMReader &esm); + void load(ESMReader &esm, bool &isDeleted); ///< Loads all sub-records of Dialogue record void loadId(ESMReader &esm); ///< Loads NAME sub-record of Dialogue record - void loadData(ESMReader &esm); + void loadData(ESMReader &esm, bool &isDeleted); ///< Loads all sub-records of Dialogue record, except NAME sub-record - void save(ESMWriter &esm) const; + void save(ESMWriter &esm, bool isDeleted = false) const; - /// Remove all INFOs that are deleted or marked as QS_Deleted from mInfos. + /// Remove all INFOs that are deleted void clearDeletedInfos(); /// Read the next info record diff --git a/components/esm/loaddoor.cpp b/components/esm/loaddoor.cpp index 4f58a4261..706e938e8 100644 --- a/components/esm/loaddoor.cpp +++ b/components/esm/loaddoor.cpp @@ -8,29 +8,20 @@ namespace ESM { unsigned int Door::sRecordId = REC_DOOR; - Door::Door() - : mIsDeleted(false) - {} - - void Door::load(ESMReader &esm) + void Door::load(ESMReader &esm, bool &isDeleted) { - mIsDeleted = false; + isDeleted = false; bool hasName = false; while (esm.hasMoreSubs()) { esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + switch (esm.retSubName().val) { case ESM::FourCC<'N','A','M','E'>::value: mId = esm.getHString(); hasName = true; break; - case ESM::FourCC<'D','E','L','E'>::value: - esm.skipHSub(); - mIsDeleted = true; - break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; @@ -46,6 +37,10 @@ namespace ESM case ESM::FourCC<'A','N','A','M'>::value: mCloseSound = esm.getHString(); break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + isDeleted = true; + break; default: esm.fail("Unknown subrecord"); break; @@ -56,11 +51,11 @@ namespace ESM esm.fail("Missing NAME subrecord"); } - void Door::save(ESMWriter &esm) const + void Door::save(ESMWriter &esm, bool isDeleted) const { esm.writeHNCString("NAME", mId); - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); return; @@ -80,6 +75,5 @@ namespace ESM mScript.clear(); mOpenSound.clear(); mCloseSound.clear(); - mIsDeleted = false; } } diff --git a/components/esm/loaddoor.hpp b/components/esm/loaddoor.hpp index 546471ed3..3afe5d5e4 100644 --- a/components/esm/loaddoor.hpp +++ b/components/esm/loaddoor.hpp @@ -17,12 +17,8 @@ struct Door std::string mId, mName, mModel, mScript, mOpenSound, mCloseSound; - bool mIsDeleted; - - Door(); - - void load(ESMReader &esm); - void save(ESMWriter &esm) const; + void load(ESMReader &esm, bool &isDeleted); + void save(ESMWriter &esm, bool isDeleted = false) const; void blank(); ///< Set record to default state (does not touch the ID). diff --git a/components/esm/loadench.cpp b/components/esm/loadench.cpp index 0e480c379..5580ef222 100644 --- a/components/esm/loadench.cpp +++ b/components/esm/loadench.cpp @@ -8,31 +8,22 @@ namespace ESM { unsigned int Enchantment::sRecordId = REC_ENCH; - Enchantment::Enchantment() - : mIsDeleted(false) - {} - - void Enchantment::load(ESMReader &esm) + void Enchantment::load(ESMReader &esm, bool &isDeleted) { + isDeleted = false; mEffects.mList.clear(); - mIsDeleted = false; bool hasName = false; bool hasData = false; while (esm.hasMoreSubs()) { esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + switch (esm.retSubName().val) { case ESM::FourCC<'N','A','M','E'>::value: mId = esm.getHString(); hasName = true; break; - case ESM::FourCC<'D','E','L','E'>::value: - esm.skipHSub(); - mIsDeleted = true; - break; case ESM::FourCC<'E','N','D','T'>::value: esm.getHT(mData, 16); hasData = true; @@ -40,6 +31,10 @@ namespace ESM case ESM::FourCC<'E','N','A','M'>::value: mEffects.add(esm); break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + isDeleted = true; + break; default: esm.fail("Unknown subrecord"); break; @@ -48,15 +43,15 @@ namespace ESM if (!hasName) esm.fail("Missing NAME subrecord"); - if (!hasData && !mIsDeleted) + if (!hasData && !isDeleted) esm.fail("Missing ENDT subrecord"); } - void Enchantment::save(ESMWriter &esm) const + void Enchantment::save(ESMWriter &esm, bool isDeleted) const { esm.writeHNCString("NAME", mId); - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); return; @@ -74,7 +69,5 @@ namespace ESM mData.mAutocalc = 0; mEffects.mList.clear(); - - mIsDeleted = false; } } diff --git a/components/esm/loadench.hpp b/components/esm/loadench.hpp index 6ebe8e940..7b93b519c 100644 --- a/components/esm/loadench.hpp +++ b/components/esm/loadench.hpp @@ -42,12 +42,8 @@ struct Enchantment ENDTstruct mData; EffectList mEffects; - bool mIsDeleted; - - Enchantment(); - - void load(ESMReader &esm); - void save(ESMWriter &esm) const; + void load(ESMReader &esm, bool &isDeleted); + void save(ESMWriter &esm, bool isDeleted = false) const; void blank(); ///< Set record to default state (does not touch the ID). diff --git a/components/esm/loadfact.cpp b/components/esm/loadfact.cpp index 8538b0b95..f550a5538 100644 --- a/components/esm/loadfact.cpp +++ b/components/esm/loadfact.cpp @@ -10,10 +10,6 @@ namespace ESM { unsigned int Faction::sRecordId = REC_FACT; - Faction::Faction() - : mIsDeleted(false) - {} - int& Faction::FADTstruct::getSkill (int index, bool ignored) { if (index<0 || index>=7) @@ -30,9 +26,10 @@ namespace ESM return mSkills[index]; } - void Faction::load(ESMReader &esm) + void Faction::load(ESMReader &esm, bool &isDeleted) { - mIsDeleted = false; + isDeleted = false; + mReactions.clear(); for (int i=0;i<10;++i) mRanks[i].clear(); @@ -43,17 +40,12 @@ namespace ESM while (esm.hasMoreSubs()) { esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + switch (esm.retSubName().val) { case ESM::FourCC<'N','A','M','E'>::value: mId = esm.getHString(); hasName = true; break; - case ESM::FourCC<'D','E','L','E'>::value: - esm.skipHSub(); - mIsDeleted = true; - break; case ESM::FourCC<'F','N','A','M'>::value: mName = esm.getHString(); break; @@ -76,6 +68,10 @@ namespace ESM mReactions[faction] = reaction; break; } + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + isDeleted = true; + break; default: esm.fail("Unknown subrecord"); break; @@ -84,15 +80,15 @@ namespace ESM if (!hasName) esm.fail("Missing NAME subrecord"); - if (!hasData && !mIsDeleted) + if (!hasData && !isDeleted) esm.fail("Missing FADT subrecord"); } - void Faction::save(ESMWriter &esm) const + void Faction::save(ESMWriter &esm, bool isDeleted) const { esm.writeHNCString("NAME", mId); - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); return; @@ -136,7 +132,5 @@ namespace ESM mData.mSkills[i] = 0; mReactions.clear(); - - mIsDeleted = false; } } diff --git a/components/esm/loadfact.hpp b/components/esm/loadfact.hpp index 96c02028b..cc715d266 100644 --- a/components/esm/loadfact.hpp +++ b/components/esm/loadfact.hpp @@ -62,12 +62,8 @@ struct Faction // Name of faction ranks (may be empty for NPC factions) std::string mRanks[10]; - bool mIsDeleted; - - Faction(); - - void load(ESMReader &esm); - void save(ESMWriter &esm) const; + void load(ESMReader &esm, bool &isDeleted); + void save(ESMWriter &esm, bool isDeleted = false) const; void blank(); ///< Set record to default state (does not touch the ID/index). diff --git a/components/esm/loadglob.cpp b/components/esm/loadglob.cpp index 5f96aff1f..72ecce503 100644 --- a/components/esm/loadglob.cpp +++ b/components/esm/loadglob.cpp @@ -8,19 +8,16 @@ namespace ESM { unsigned int Global::sRecordId = REC_GLOB; - Global::Global() - : mIsDeleted(false) - {} - - void Global::load (ESMReader &esm) + void Global::load (ESMReader &esm, bool &isDeleted) { - mIsDeleted = false; + isDeleted = false; + mId = esm.getHNString ("NAME"); if (esm.isNextSub ("DELE")) { esm.skipHSub(); - mIsDeleted = true; + isDeleted = true; } else { @@ -28,11 +25,11 @@ namespace ESM } } - void Global::save (ESMWriter &esm) const + void Global::save (ESMWriter &esm, bool isDeleted) const { esm.writeHNCString ("NAME", mId); - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString ("DELE", ""); } @@ -45,7 +42,6 @@ namespace ESM void Global::blank() { mValue.setType (ESM::VT_None); - mIsDeleted = false; } bool operator== (const Global& left, const Global& right) diff --git a/components/esm/loadglob.hpp b/components/esm/loadglob.hpp index c0219c0ba..0533cc95e 100644 --- a/components/esm/loadglob.hpp +++ b/components/esm/loadglob.hpp @@ -24,12 +24,8 @@ struct Global std::string mId; Variant mValue; - bool mIsDeleted; - - Global(); - - void load(ESMReader &esm); - void save(ESMWriter &esm) const; + void load(ESMReader &esm, bool &isDeleted); + void save(ESMWriter &esm, bool isDeleted = false) const; void blank(); ///< Set record to default state (does not touch the ID). diff --git a/components/esm/loadgmst.cpp b/components/esm/loadgmst.cpp index 9e2a80270..1ebb002e6 100644 --- a/components/esm/loadgmst.cpp +++ b/components/esm/loadgmst.cpp @@ -8,13 +8,15 @@ namespace ESM { unsigned int GameSetting::sRecordId = REC_GMST; - void GameSetting::load (ESMReader &esm) + void GameSetting::load (ESMReader &esm, bool &isDeleted) { + isDeleted = false; // GameSetting record can't be deleted now (may be changed in the future) + mId = esm.getHNString("NAME"); mValue.read (esm, ESM::Variant::Format_Gmst); } - void GameSetting::save (ESMWriter &esm) const + void GameSetting::save (ESMWriter &esm, bool /*isDeleted*/) const { esm.writeHNCString("NAME", mId); mValue.write (esm, ESM::Variant::Format_Gmst); diff --git a/components/esm/loadgmst.hpp b/components/esm/loadgmst.hpp index d9d9048b6..73a723e81 100644 --- a/components/esm/loadgmst.hpp +++ b/components/esm/loadgmst.hpp @@ -26,7 +26,7 @@ struct GameSetting Variant mValue; - void load(ESMReader &esm); + void load(ESMReader &esm, bool &isDeleted); /// \todo remove the get* functions (redundant, since mValue has equivalent functions now). @@ -39,7 +39,7 @@ struct GameSetting std::string getString() const; ///< Throwns an exception if GMST is not of type string. - void save(ESMWriter &esm) const; + void save(ESMWriter &esm, bool isDeleted = false) const; void blank(); ///< Set record to default state (does not touch the ID). diff --git a/components/esm/loadinfo.cpp b/components/esm/loadinfo.cpp index 89fd4e0cd..d1f20a3d4 100644 --- a/components/esm/loadinfo.cpp +++ b/components/esm/loadinfo.cpp @@ -8,29 +8,23 @@ namespace ESM { unsigned int DialInfo::sRecordId = REC_INFO; - DialInfo::DialInfo() - : mFactionLess(false), - mQuestStatus(QS_None), - mIsDeleted(false) - {} - - void DialInfo::load(ESMReader &esm) + void DialInfo::load(ESMReader &esm, bool &isDeleted) { loadId(esm); - loadInfo(esm); + loadData(esm, isDeleted); } void DialInfo::loadId(ESMReader &esm) { - mIsDeleted = false; mId = esm.getHNString("INAM"); } - void DialInfo::loadInfo(ESMReader &esm) + void DialInfo::loadData(ESMReader &esm, bool &isDeleted) { + isDeleted = false; + mQuestStatus = QS_None; mFactionLess = false; - mIsDeleted = false; mPrev = esm.getHNString("PNAM"); mNext = esm.getHNString("NNAM"); @@ -41,13 +35,8 @@ namespace ESM while (esm.hasMoreSubs()) { esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + switch (esm.retSubName().val) { - case ESM::FourCC<'D','E','L','E'>::value: - esm.skipHSub(); - mIsDeleted = true; - break; case ESM::FourCC<'D','A','T','A'>::value: esm.getHT(mData, 12); break; @@ -104,6 +93,10 @@ namespace ESM mQuestStatus = QS_Restart; esm.skipRecord(); break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + isDeleted = true; + break; default: esm.fail("Unknown subrecord"); break; @@ -111,13 +104,13 @@ namespace ESM } } - void DialInfo::save(ESMWriter &esm) const + void DialInfo::save(ESMWriter &esm, bool isDeleted) const { esm.writeHNCString("INAM", mId); esm.writeHNCString("PNAM", mPrev); esm.writeHNCString("NNAM", mNext); - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); return; @@ -173,6 +166,5 @@ namespace ESM mResultScript.clear(); mFactionLess = false; mQuestStatus = QS_None; - mIsDeleted = false; } } diff --git a/components/esm/loadinfo.hpp b/components/esm/loadinfo.hpp index 65363d1be..8123a9ace 100644 --- a/components/esm/loadinfo.hpp +++ b/components/esm/loadinfo.hpp @@ -105,18 +105,14 @@ struct DialInfo REC_DELE = 0x454c4544 }; - bool mIsDeleted; - - DialInfo(); - - void load(ESMReader &esm); + void load(ESMReader &esm, bool &isDeleted); ///< Loads all sub-records of Info record void loadId(ESMReader &esm); ///< Loads only Id of Info record (INAM sub-record) - void loadInfo(ESMReader &esm); + void loadData(ESMReader &esm, bool &isDeleted); ///< Loads all sub-records of Info record, except INAM sub-record - void save(ESMWriter &esm) const; + void save(ESMWriter &esm, bool isDeleted = false) const; void blank(); ///< Set record to default state (does not touch the ID). diff --git a/components/esm/loadingr.cpp b/components/esm/loadingr.cpp index 51a1f4805..a481d5b79 100644 --- a/components/esm/loadingr.cpp +++ b/components/esm/loadingr.cpp @@ -8,30 +8,21 @@ namespace ESM { unsigned int Ingredient::sRecordId = REC_INGR; - Ingredient::Ingredient() - : mIsDeleted(false) - {} - - void Ingredient::load(ESMReader &esm) + void Ingredient::load(ESMReader &esm, bool &isDeleted) { - mIsDeleted = false; + isDeleted = false; bool hasName = false; bool hasData = false; while (esm.hasMoreSubs()) { esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + switch (esm.retSubName().val) { case ESM::FourCC<'N','A','M','E'>::value: mId = esm.getHString(); hasName = true; break; - case ESM::FourCC<'D','E','L','E'>::value: - esm.skipHSub(); - mIsDeleted = true; - break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; @@ -48,6 +39,10 @@ namespace ESM case ESM::FourCC<'I','T','E','X'>::value: mIcon = esm.getHString(); break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + isDeleted = true; + break; default: esm.fail("Unknown subrecord"); break; @@ -56,7 +51,7 @@ namespace ESM if (!hasName) esm.fail("Missing NAME subrecord"); - if (!hasData && !mIsDeleted) + if (!hasData && !isDeleted) esm.fail("Missing IRDT subrecord"); // horrible hack to fix broken data in records @@ -83,11 +78,11 @@ namespace ESM } } - void Ingredient::save(ESMWriter &esm) const + void Ingredient::save(ESMWriter &esm, bool isDeleted) const { esm.writeHNCString("NAME", mId); - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); return; @@ -115,7 +110,5 @@ namespace ESM mModel.clear(); mIcon.clear(); mScript.clear(); - - mIsDeleted = false; } } diff --git a/components/esm/loadingr.hpp b/components/esm/loadingr.hpp index c92f28f18..c0f445023 100644 --- a/components/esm/loadingr.hpp +++ b/components/esm/loadingr.hpp @@ -31,12 +31,8 @@ struct Ingredient IRDTstruct mData; std::string mId, mName, mModel, mIcon, mScript; - bool mIsDeleted; - - Ingredient(); - - void load(ESMReader &esm); - void save(ESMWriter &esm) const; + void load(ESMReader &esm, bool &isDeleted); + void save(ESMWriter &esm, bool isDeleted = false) const; void blank(); ///< Set record to default state (does not touch the ID). diff --git a/components/esm/loadland.cpp b/components/esm/loadland.cpp index 6acaa6e6a..2ffd2a21b 100644 --- a/components/esm/loadland.cpp +++ b/components/esm/loadland.cpp @@ -72,7 +72,6 @@ namespace ESM , mDataTypes(0) , mDataLoaded(false) , mLandData(NULL) - , mIsDeleted(false) { } @@ -81,61 +80,82 @@ namespace ESM delete mLandData; } - void Land::load(ESMReader &esm) + void Land::load(ESMReader &esm, bool &isDeleted) { + isDeleted = false; + mEsm = &esm; mPlugin = mEsm->getIndex(); - mIsDeleted = false; - - // Get the grid location - esm.getSubNameIs("INTV"); - esm.getSubHeaderIs(8); - esm.getT(mX); - esm.getT(mY); - - esm.getHNT(mFlags, "DATA"); - if (esm.isNextSub("DELE")) + bool hasLocation = false; + bool isLoaded = false; + while (!isLoaded && esm.hasMoreSubs()) { - esm.skipHSub(); - mIsDeleted = true; + esm.getSubName(); + switch (esm.retSubName().val) + { + case ESM::FourCC<'I','N','T','V'>::value: + esm.getSubHeaderIs(8); + esm.getT(mX); + esm.getT(mY); + hasLocation = true; + break; + case ESM::FourCC<'D','A','T','A'>::value: + esm.getHT(mFlags); + break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + isDeleted = true; + break; + default: + esm.cacheSubName(); + isLoaded = true; + break; + } } - // Store the file position + if (!hasLocation) + esm.fail("Missing INTV subrecord"); + mContext = esm.getContext(); - // Skip these here. Load the actual data when the cell is loaded. - if (esm.isNextSub("VNML")) - { - esm.skipHSubSize(12675); - mDataTypes |= DATA_VNML; - } - if (esm.isNextSub("VHGT")) - { - esm.skipHSubSize(4232); - mDataTypes |= DATA_VHGT; - } - if (esm.isNextSub("WNAM")) + // Skip the land data here. Load it when the cell is loaded. + while (esm.hasMoreSubs()) { - esm.skipHSubSize(81); - mDataTypes |= DATA_WNAM; - } - if (esm.isNextSub("VCLR")) - { - esm.skipHSubSize(12675); - mDataTypes |= DATA_VCLR; - } - if (esm.isNextSub("VTEX")) - { - esm.skipHSubSize(512); - mDataTypes |= DATA_VTEX; + esm.getSubName(); + switch (esm.retSubName().val) + { + case ESM::FourCC<'V','N','M','L'>::value: + esm.skipHSub(); + mDataTypes |= DATA_VNML; + break; + case ESM::FourCC<'V','H','G','T'>::value: + esm.skipHSub(); + mDataTypes |= DATA_VHGT; + break; + case ESM::FourCC<'W','N','A','M'>::value: + esm.skipHSub(); + mDataTypes |= DATA_WNAM; + break; + case ESM::FourCC<'V','C','L','R'>::value: + esm.skipHSub(); + mDataTypes |= DATA_VCLR; + break; + case ESM::FourCC<'V','T','E','X'>::value: + esm.skipHSub(); + mDataTypes |= DATA_VTEX; + break; + default: + esm.fail("Unknown subrecord"); + break; + } } mDataLoaded = 0; mLandData = NULL; } - void Land::save(ESMWriter &esm) const + void Land::save(ESMWriter &esm, bool isDeleted) const { esm.startSubRecord("INTV"); esm.writeT(mX); @@ -144,22 +164,17 @@ namespace ESM esm.writeHNT("DATA", mFlags); - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); } - if (mLandData != NULL) + if (mLandData) { mLandData->save(esm); } } - void Land::blank() - { - mIsDeleted = false; - } - void Land::loadData(int flags) { // Try to load only available data diff --git a/components/esm/loadland.hpp b/components/esm/loadland.hpp index d9ee0015a..ddb00f394 100644 --- a/components/esm/loadland.hpp +++ b/components/esm/loadland.hpp @@ -97,12 +97,10 @@ struct Land LandData *mLandData; - bool mIsDeleted; + void load(ESMReader &esm, bool &isDeleted); + void save(ESMWriter &esm, bool isDeleted = false) const; - void load(ESMReader &esm); - void save(ESMWriter &esm) const; - - void blank(); + void blank() {} /** * Actually loads data diff --git a/components/esm/loadlevlist.cpp b/components/esm/loadlevlist.cpp index 9c34ef657..6245ec856 100644 --- a/components/esm/loadlevlist.cpp +++ b/components/esm/loadlevlist.cpp @@ -6,29 +6,21 @@ namespace ESM { - LevelledListBase::LevelledListBase() - : mIsDeleted(false) - {} - - void LevelledListBase::load(ESMReader &esm) + void LevelledListBase::load(ESMReader &esm, bool &isDeleted) { - mIsDeleted = false; + isDeleted = false; bool hasName = false; + bool hasList = false; while (esm.hasMoreSubs()) { esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + switch (esm.retSubName().val) { case ESM::FourCC<'N','A','M','E'>::value: mId = esm.getHString(); hasName = true; break; - case ESM::FourCC<'D','E','L','E'>::value: - esm.skipHSub(); - mIsDeleted = true; - break; case ESM::FourCC<'D','A','T','A'>::value: esm.getHT(mFlags); break; @@ -53,12 +45,28 @@ namespace ESM li.mId = esm.getHNString(mRecName); esm.getHNT(li.mLevel, "INTV"); } + + hasList = true; break; } + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + isDeleted = true; + break; default: - mList.clear(); - esm.skipRecord(); + { + if (!hasList) + { + // Original engine ignores rest of the record, even if there are items following + mList.clear(); + esm.skipRecord(); + } + else + { + esm.fail("Unknown subrecord"); + } break; + } } } @@ -66,11 +74,11 @@ namespace ESM esm.fail("Missing NAME subrecord"); } - void LevelledListBase::save(ESMWriter &esm) const + void LevelledListBase::save(ESMWriter &esm, bool isDeleted) const { esm.writeHNCString("NAME", mId); - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); return; @@ -92,7 +100,6 @@ namespace ESM mFlags = 0; mChanceNone = 0; mList.clear(); - mIsDeleted = false; } unsigned int CreatureLevList::sRecordId = REC_LEVC; diff --git a/components/esm/loadlevlist.hpp b/components/esm/loadlevlist.hpp index 14ebc9937..ed4131c16 100644 --- a/components/esm/loadlevlist.hpp +++ b/components/esm/loadlevlist.hpp @@ -36,12 +36,8 @@ struct LevelledListBase std::vector mList; - bool mIsDeleted; - - LevelledListBase(); - - void load(ESMReader &esm); - void save(ESMWriter &esm) const; + void load(ESMReader &esm, bool &isDeleted); + void save(ESMWriter &esm, bool isDeleted = false) const; void blank(); ///< Set record to default state (does not touch the ID). diff --git a/components/esm/loadligh.cpp b/components/esm/loadligh.cpp index 441e96d0a..a0fedc3ad 100644 --- a/components/esm/loadligh.cpp +++ b/components/esm/loadligh.cpp @@ -8,30 +8,21 @@ namespace ESM { unsigned int Light::sRecordId = REC_LIGH; - Light::Light() - : mIsDeleted(false) - {} - - void Light::load(ESMReader &esm) + void Light::load(ESMReader &esm, bool &isDeleted) { - mIsDeleted = false; + isDeleted = false; bool hasName = false; bool hasData = false; while (esm.hasMoreSubs()) { esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + switch (esm.retSubName().val) { case ESM::FourCC<'N','A','M','E'>::value: mId = esm.getHString(); hasName = true; break; - case ESM::FourCC<'D','E','L','E'>::value: - esm.skipHSub(); - mIsDeleted = true; - break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; @@ -51,6 +42,10 @@ namespace ESM case ESM::FourCC<'S','N','A','M'>::value: mSound = esm.getHString(); break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + isDeleted = true; + break; default: esm.fail("Unknown subrecord"); break; @@ -59,14 +54,14 @@ namespace ESM if (!hasName) esm.fail("Missing NAME subrecord"); - if (!hasData && !mIsDeleted) + if (!hasData && !isDeleted) esm.fail("Missing LHDT subrecord"); } - void Light::save(ESMWriter &esm) const + void Light::save(ESMWriter &esm, bool isDeleted) const { esm.writeHNCString("NAME", mId); - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); return; @@ -93,6 +88,5 @@ namespace ESM mModel.clear(); mIcon.clear(); mName.clear(); - mIsDeleted = false; } } diff --git a/components/esm/loadligh.hpp b/components/esm/loadligh.hpp index d4d3418d8..8509c64b6 100644 --- a/components/esm/loadligh.hpp +++ b/components/esm/loadligh.hpp @@ -47,12 +47,8 @@ struct Light std::string mSound, mScript, mModel, mIcon, mName, mId; - bool mIsDeleted; - - Light(); - - void load(ESMReader &esm); - void save(ESMWriter &esm) const; + void load(ESMReader &esm, bool &isDeleted); + void save(ESMWriter &esm, bool isDeleted = false) const; void blank(); ///< Set record to default state (does not touch the ID). diff --git a/components/esm/loadlock.cpp b/components/esm/loadlock.cpp index 2cfe43743..be93eaa0e 100644 --- a/components/esm/loadlock.cpp +++ b/components/esm/loadlock.cpp @@ -8,30 +8,21 @@ namespace ESM { unsigned int Lockpick::sRecordId = REC_LOCK; - Lockpick::Lockpick() - : mIsDeleted(false) - {} - - void Lockpick::load(ESMReader &esm) + void Lockpick::load(ESMReader &esm, bool &isDeleted) { - mIsDeleted = false; + isDeleted = false; bool hasName = false; bool hasData = false; while (esm.hasMoreSubs()) { esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + switch (esm.retSubName().val) { case ESM::FourCC<'N','A','M','E'>::value: mId = esm.getHString(); hasName = true; break; - case ESM::FourCC<'D','E','L','E'>::value: - esm.skipHSub(); - mIsDeleted = true; - break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; @@ -48,6 +39,10 @@ namespace ESM case ESM::FourCC<'I','T','E','X'>::value: mIcon = esm.getHString(); break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + isDeleted = true; + break; default: esm.fail("Unknown subrecord"); break; @@ -56,15 +51,15 @@ namespace ESM if (!hasName) esm.fail("Missing NAME subrecord"); - if (!hasData && !mIsDeleted) + if (!hasData && !isDeleted) esm.fail("Missing LKDT subrecord"); } - void Lockpick::save(ESMWriter &esm) const + void Lockpick::save(ESMWriter &esm, bool isDeleted) const { esm.writeHNCString("NAME", mId); - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); return; @@ -88,6 +83,5 @@ namespace ESM mModel.clear(); mIcon.clear(); mScript.clear(); - mIsDeleted = false; } } diff --git a/components/esm/loadlock.hpp b/components/esm/loadlock.hpp index ce7de2c06..9db41af97 100644 --- a/components/esm/loadlock.hpp +++ b/components/esm/loadlock.hpp @@ -27,12 +27,8 @@ struct Lockpick Data mData; std::string mId, mName, mModel, mIcon, mScript; - bool mIsDeleted; - - Lockpick(); - - void load(ESMReader &esm); - void save(ESMWriter &esm) const; + void load(ESMReader &esm, bool &isDeleted); + void save(ESMWriter &esm, bool isDeleted = false) const; void blank(); ///< Set record to default state (does not touch the ID). diff --git a/components/esm/loadltex.cpp b/components/esm/loadltex.cpp index 6bd48d801..cf026dbf1 100644 --- a/components/esm/loadltex.cpp +++ b/components/esm/loadltex.cpp @@ -8,30 +8,21 @@ namespace ESM { unsigned int LandTexture::sRecordId = REC_LTEX; - LandTexture::LandTexture() - : mIsDeleted(false) - {} - - void LandTexture::load(ESMReader &esm) + void LandTexture::load(ESMReader &esm, bool &isDeleted) { - mIsDeleted = false; + isDeleted = false; bool hasName = false; bool hasIndex = false; while (esm.hasMoreSubs()) { esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + switch (esm.retSubName().val) { case ESM::FourCC<'N','A','M','E'>::value: mId = esm.getHString(); hasName = true; break; - case ESM::FourCC<'D','E','L','E'>::value: - esm.skipHSub(); - mIsDeleted = true; - break; case ESM::FourCC<'I','N','T','V'>::value: esm.getHT(mIndex); hasIndex = true; @@ -39,6 +30,10 @@ namespace ESM case ESM::FourCC<'D','A','T','A'>::value: mTexture = esm.getHString(); break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + isDeleted = true; + break; default: esm.fail("Unknown subrecord"); break; @@ -50,9 +45,9 @@ namespace ESM if (!hasIndex) esm.fail("Missing INTV subrecord"); } - void LandTexture::save(ESMWriter &esm) const + void LandTexture::save(ESMWriter &esm, bool isDeleted) const { - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); } @@ -66,6 +61,5 @@ namespace ESM { mTexture.clear(); mIndex = -1; - mIsDeleted = false; } } diff --git a/components/esm/loadltex.hpp b/components/esm/loadltex.hpp index 33af77612..2cb5abf0c 100644 --- a/components/esm/loadltex.hpp +++ b/components/esm/loadltex.hpp @@ -34,12 +34,8 @@ struct LandTexture std::string mId, mTexture; int mIndex; - bool mIsDeleted; - - LandTexture(); - - void load(ESMReader &esm); - void save(ESMWriter &esm) const; + void load(ESMReader &esm, bool &isDeleted); + void save(ESMWriter &esm, bool isDeleted = false) const; void blank(); ///< Set record to default state (does not touch the ID). diff --git a/components/esm/loadmgef.cpp b/components/esm/loadmgef.cpp index 6f859ab3c..eef58aa2f 100644 --- a/components/esm/loadmgef.cpp +++ b/components/esm/loadmgef.cpp @@ -189,8 +189,10 @@ namespace ESM { unsigned int MagicEffect::sRecordId = REC_MGEF; -void MagicEffect::load(ESMReader &esm) +void MagicEffect::load(ESMReader &esm, bool &isDeleted) { + isDeleted = false; // MagicEffect record can't be deleted now (may be changed in the future) + esm.getHNT(mIndex, "INDX"); mId = indexToId (mIndex); @@ -209,8 +211,7 @@ void MagicEffect::load(ESMReader &esm) while (esm.hasMoreSubs()) { esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + switch (esm.retSubName().val) { case ESM::FourCC<'I','T','E','X'>::value: mIcon = esm.getHString(); @@ -250,7 +251,7 @@ void MagicEffect::load(ESMReader &esm) } } } -void MagicEffect::save(ESMWriter &esm) const +void MagicEffect::save(ESMWriter &esm, bool /*isDeleted*/) const { esm.writeHNT("INDX", mIndex); diff --git a/components/esm/loadmgef.hpp b/components/esm/loadmgef.hpp index 32b8a85a6..24d4c9e2b 100644 --- a/components/esm/loadmgef.hpp +++ b/components/esm/loadmgef.hpp @@ -96,8 +96,8 @@ struct MagicEffect // sMagicCreature04ID/05ID. int mIndex; - void load(ESMReader &esm); - void save(ESMWriter &esm) const; + void load(ESMReader &esm, bool &isDeleted); + void save(ESMWriter &esm, bool isDeleted = false) const; /// Set record to default state (does not touch the ID/index). void blank(); diff --git a/components/esm/loadmisc.cpp b/components/esm/loadmisc.cpp index de9ccdd6a..f03cb9a85 100644 --- a/components/esm/loadmisc.cpp +++ b/components/esm/loadmisc.cpp @@ -8,30 +8,21 @@ namespace ESM { unsigned int Miscellaneous::sRecordId = REC_MISC; - Miscellaneous::Miscellaneous() - : mIsDeleted(false) - {} - - void Miscellaneous::load(ESMReader &esm) + void Miscellaneous::load(ESMReader &esm, bool &isDeleted) { - mIsDeleted = false; + isDeleted = false; bool hasName = false; bool hasData = false; while (esm.hasMoreSubs()) { esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + switch (esm.retSubName().val) { case ESM::FourCC<'N','A','M','E'>::value: mId = esm.getHString(); hasName = true; break; - case ESM::FourCC<'D','E','L','E'>::value: - esm.skipHSub(); - mIsDeleted = true; - break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; @@ -48,6 +39,10 @@ namespace ESM case ESM::FourCC<'I','T','E','X'>::value: mIcon = esm.getHString(); break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + isDeleted = true; + break; default: esm.fail("Unknown subrecord"); break; @@ -56,15 +51,15 @@ namespace ESM if (!hasName) esm.fail("Missing NAME subrecord"); - if (!hasData && !mIsDeleted) + if (!hasData && !isDeleted) esm.fail("Missing MCDT subrecord"); } - void Miscellaneous::save(ESMWriter &esm) const + void Miscellaneous::save(ESMWriter &esm, bool isDeleted) const { esm.writeHNCString("NAME", mId); - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); return; @@ -86,6 +81,5 @@ namespace ESM mModel.clear(); mIcon.clear(); mScript.clear(); - mIsDeleted = false; } } diff --git a/components/esm/loadmisc.hpp b/components/esm/loadmisc.hpp index 82018cd72..e7a323904 100644 --- a/components/esm/loadmisc.hpp +++ b/components/esm/loadmisc.hpp @@ -32,12 +32,8 @@ struct Miscellaneous std::string mId, mName, mModel, mIcon, mScript; - bool mIsDeleted; - - Miscellaneous(); - - void load(ESMReader &esm); - void save(ESMWriter &esm) const; + void load(ESMReader &esm, bool &isDeleted); + void save(ESMWriter &esm, bool isDeleted = false) const; void blank(); ///< Set record to default state (does not touch the ID). diff --git a/components/esm/loadnpc.cpp b/components/esm/loadnpc.cpp index ff3213ee9..939801e74 100644 --- a/components/esm/loadnpc.cpp +++ b/components/esm/loadnpc.cpp @@ -8,15 +8,10 @@ namespace ESM { unsigned int NPC::sRecordId = REC_NPC_; - NPC::NPC() - : mFlags(0), - mHasAI(false), - mIsDeleted(false) - {} - - void NPC::load(ESMReader &esm) + void NPC::load(ESMReader &esm, bool &isDeleted) { - mIsDeleted = false; + isDeleted = false; + mPersistent = (esm.getRecordFlags() & 0x0400) != 0; mSpells.mList.clear(); @@ -31,17 +26,12 @@ namespace ESM while (esm.hasMoreSubs()) { esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + switch (esm.retSubName().val) { case ESM::FourCC<'N','A','M','E'>::value: mId = esm.getHString(); hasName = true; break; - case ESM::FourCC<'D','E','L','E'>::value: - esm.skipHSub(); - mIsDeleted = true; - break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; @@ -108,6 +98,10 @@ namespace ESM case AI_CNDT: mAiPackage.add(esm); break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + isDeleted = true; + break; default: esm.fail("Unknown subrecord"); break; @@ -116,16 +110,16 @@ namespace ESM if (!hasName) esm.fail("Missing NAME subrecord"); - if (!hasNpdt && !mIsDeleted) + if (!hasNpdt && !isDeleted) esm.fail("Missing NPDT subrecord"); - if (!hasFlags && !mIsDeleted) + if (!hasFlags && !isDeleted) esm.fail("Missing FLAG subrecord"); } - void NPC::save(ESMWriter &esm) const + void NPC::save(ESMWriter &esm, bool isDeleted) const { esm.writeHNCString("NAME", mId); - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); return; @@ -206,7 +200,6 @@ namespace ESM mScript.clear(); mHair.clear(); mHead.clear(); - mIsDeleted = false; } int NPC::getFactionRank() const diff --git a/components/esm/loadnpc.hpp b/components/esm/loadnpc.hpp index 263752752..5b89f4055 100644 --- a/components/esm/loadnpc.hpp +++ b/components/esm/loadnpc.hpp @@ -130,12 +130,8 @@ struct NPC // body parts std::string mHair, mHead; - bool mIsDeleted; - - NPC(); - - void load(ESMReader &esm); - void save(ESMWriter &esm) const; + void load(ESMReader &esm, bool &isDeleted); + void save(ESMWriter &esm, bool isDeleted = false) const; bool isMale() const; diff --git a/components/esm/loadpgrd.cpp b/components/esm/loadpgrd.cpp index 5e8de9d57..8027be91c 100644 --- a/components/esm/loadpgrd.cpp +++ b/components/esm/loadpgrd.cpp @@ -32,12 +32,10 @@ namespace ESM { } - Pathgrid::Pathgrid() - : mIsDeleted(false) - {} - - void Pathgrid::load(ESMReader &esm) + void Pathgrid::load(ESMReader &esm, bool &isDeleted) { + isDeleted = false; + mPoints.clear(); mEdges.clear(); @@ -49,8 +47,7 @@ namespace ESM while (esm.hasMoreSubs()) { esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + switch (esm.retSubName().val) { case ESM::FourCC<'D','A','T','A'>::value: esm.getHT(mData, 12); @@ -118,7 +115,7 @@ namespace ESM } case ESM::FourCC<'D','E','L','E'>::value: esm.skipHSub(); - mIsDeleted = true; + isDeleted = true; break; default: esm.fail("Unknown subrecord"); @@ -132,12 +129,12 @@ namespace ESM esm.fail("Missing NAME subrecord"); } - void Pathgrid::save(ESMWriter &esm) const + void Pathgrid::save(ESMWriter &esm, bool isDeleted) const { esm.writeHNT("DATA", mData, 12); esm.writeHNCString("NAME", mCell); - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); return; @@ -173,6 +170,5 @@ namespace ESM mData.mS2 = 0; mPoints.clear(); mEdges.clear(); - mIsDeleted = false; } } diff --git a/components/esm/loadpgrd.hpp b/components/esm/loadpgrd.hpp index 4b82d9571..d1003eb86 100644 --- a/components/esm/loadpgrd.hpp +++ b/components/esm/loadpgrd.hpp @@ -53,12 +53,8 @@ struct Pathgrid typedef std::vector EdgeList; EdgeList mEdges; - bool mIsDeleted; - - Pathgrid(); - - void load(ESMReader &esm); - void save(ESMWriter &esm) const; + void load(ESMReader &esm, bool &isDeleted); + void save(ESMWriter &esm, bool isDeleted = false) const; void blank(); }; diff --git a/components/esm/loadprob.cpp b/components/esm/loadprob.cpp index 4ce9b9d9c..31caeff41 100644 --- a/components/esm/loadprob.cpp +++ b/components/esm/loadprob.cpp @@ -8,30 +8,21 @@ namespace ESM { unsigned int Probe::sRecordId = REC_PROB; - Probe::Probe() - : mIsDeleted(false) - {} - - void Probe::load(ESMReader &esm) + void Probe::load(ESMReader &esm, bool &isDeleted) { - mIsDeleted = false; + isDeleted = false; bool hasName = false; bool hasData = false; while (esm.hasMoreSubs()) { esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + switch (esm.retSubName().val) { case ESM::FourCC<'N','A','M','E'>::value: mId = esm.getHString(); hasName = true; break; - case ESM::FourCC<'D','E','L','E'>::value: - esm.skipHSub(); - mIsDeleted = true; - break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; @@ -48,6 +39,10 @@ namespace ESM case ESM::FourCC<'I','T','E','X'>::value: mIcon = esm.getHString(); break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + isDeleted = true; + break; default: esm.fail("Unknown subrecord"); break; @@ -56,15 +51,15 @@ namespace ESM if (!hasName) esm.fail("Missing NAME subrecord"); - if (!hasData && !mIsDeleted) + if (!hasData && !isDeleted) esm.fail("Missing PBDT subrecord"); } - void Probe::save(ESMWriter &esm) const + void Probe::save(ESMWriter &esm, bool isDeleted) const { esm.writeHNCString("NAME", mId); - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); return; @@ -88,6 +83,5 @@ namespace ESM mModel.clear(); mIcon.clear(); mScript.clear(); - mIsDeleted = false; } } diff --git a/components/esm/loadprob.hpp b/components/esm/loadprob.hpp index 748d498fc..da203b456 100644 --- a/components/esm/loadprob.hpp +++ b/components/esm/loadprob.hpp @@ -27,12 +27,8 @@ struct Probe Data mData; std::string mId, mName, mModel, mIcon, mScript; - bool mIsDeleted; - - Probe(); - - void load(ESMReader &esm); - void save(ESMWriter &esm) const; + void load(ESMReader &esm, bool &isDeleted); + void save(ESMWriter &esm, bool isDeleted = false) const; void blank(); ///< Set record to default state (does not touch the ID). diff --git a/components/esm/loadrace.cpp b/components/esm/loadrace.cpp index 12762bda3..d5172a133 100644 --- a/components/esm/loadrace.cpp +++ b/components/esm/loadrace.cpp @@ -8,10 +8,6 @@ namespace ESM { unsigned int Race::sRecordId = REC_RACE; - Race::Race() - : mIsDeleted(false) - {} - int Race::MaleFemale::getValue (bool male) const { return male ? mMale : mFemale; @@ -22,27 +18,23 @@ namespace ESM return static_cast(male ? mMale : mFemale); } - void Race::load(ESMReader &esm) + void Race::load(ESMReader &esm, bool &isDeleted) { + isDeleted = false; + mPowers.mList.clear(); - mIsDeleted = false; bool hasName = false; bool hasData = false; while (esm.hasMoreSubs()) { esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + switch (esm.retSubName().val) { case ESM::FourCC<'N','A','M','E'>::value: mId = esm.getHString(); hasName = true; break; - case ESM::FourCC<'D','E','L','E'>::value: - esm.skipHSub(); - mIsDeleted = true; - break; case ESM::FourCC<'F','N','A','M'>::value: mName = esm.getHString(); break; @@ -56,6 +48,10 @@ namespace ESM case ESM::FourCC<'N','P','C','S'>::value: mPowers.add(esm); break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + isDeleted = true; + break; default: esm.fail("Unknown subrecord"); } @@ -63,14 +59,14 @@ namespace ESM if (!hasName) esm.fail("Missing NAME subrecord"); - if (!hasData && !mIsDeleted) + if (!hasData && !isDeleted) esm.fail("Missing RADT subrecord"); } - void Race::save(ESMWriter &esm) const + void Race::save(ESMWriter &esm, bool isDeleted) const { esm.writeHNCString("NAME", mId); - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); return; diff --git a/components/esm/loadrace.hpp b/components/esm/loadrace.hpp index e8e9a442b..bf0573075 100644 --- a/components/esm/loadrace.hpp +++ b/components/esm/loadrace.hpp @@ -68,12 +68,8 @@ struct Race std::string mId, mName, mDescription; SpellList mPowers; - bool mIsDeleted; - - Race(); - - void load(ESMReader &esm); - void save(ESMWriter &esm) const; + void load(ESMReader &esm, bool &isDeleted); + void save(ESMWriter &esm, bool isDeleted = false) const; void blank(); ///< Set record to default state (does not touch the ID/index). diff --git a/components/esm/loadregn.cpp b/components/esm/loadregn.cpp index b48ffa4b7..b04e6ee3b 100644 --- a/components/esm/loadregn.cpp +++ b/components/esm/loadregn.cpp @@ -8,29 +8,20 @@ namespace ESM { unsigned int Region::sRecordId = REC_REGN; - Region::Region() - : mMapColor(0), - mIsDeleted(false) - {} - - void Region::load(ESMReader &esm) + void Region::load(ESMReader &esm, bool &isDeleted) { - mIsDeleted = false; + isDeleted = false; bool hasName = false; while (esm.hasMoreSubs()) { esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + switch (esm.retSubName().val) { case ESM::FourCC<'N','A','M','E'>::value: mId = esm.getHString(); hasName = true; break; - case ESM::FourCC<'D','E','L','E'>::value: - esm.skipHSub(); - mIsDeleted = true; break; case ESM::FourCC<'F','N','A','M'>::value: mName = esm.getHString(); @@ -75,6 +66,9 @@ namespace ESM esm.getHT(sr, 33); mSoundList.push_back(sr); break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + isDeleted = true; default: esm.fail("Unknown subrecord"); break; @@ -85,9 +79,9 @@ namespace ESM esm.fail("Missing NAME subrecord"); } - void Region::save(ESMWriter &esm) const + void Region::save(ESMWriter &esm, bool isDeleted) const { - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); } @@ -121,7 +115,5 @@ namespace ESM mName.clear(); mSleepList.clear(); mSoundList.clear(); - - mIsDeleted = false; } } diff --git a/components/esm/loadregn.hpp b/components/esm/loadregn.hpp index 9082437fe..3d914bd17 100644 --- a/components/esm/loadregn.hpp +++ b/components/esm/loadregn.hpp @@ -51,12 +51,8 @@ struct Region std::vector mSoundList; - bool mIsDeleted; - - Region(); - - void load(ESMReader &esm); - void save(ESMWriter &esm) const; + void load(ESMReader &esm, bool &isDeleted); + void save(ESMWriter &esm, bool isDeleted = false) const; void blank(); ///< Set record to default state (does not touch the ID/index). diff --git a/components/esm/loadrepa.cpp b/components/esm/loadrepa.cpp index 74e682d63..00d2ebf08 100644 --- a/components/esm/loadrepa.cpp +++ b/components/esm/loadrepa.cpp @@ -8,30 +8,21 @@ namespace ESM { unsigned int Repair::sRecordId = REC_REPA; - Repair::Repair() - : mIsDeleted(false) - {} - - void Repair::load(ESMReader &esm) + void Repair::load(ESMReader &esm, bool &isDeleted) { - mIsDeleted = false; + isDeleted = false; bool hasName = false; bool hasData = false; while (esm.hasMoreSubs()) { esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + switch (esm.retSubName().val) { case ESM::FourCC<'N','A','M','E'>::value: mId = esm.getHString(); hasName = true; break; - case ESM::FourCC<'D','E','L','E'>::value: - esm.skipHSub(); - mIsDeleted = true; - break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; @@ -48,6 +39,10 @@ namespace ESM case ESM::FourCC<'I','T','E','X'>::value: mIcon = esm.getHString(); break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + isDeleted = true; + break; default: esm.fail("Unknown subrecord"); break; @@ -56,15 +51,15 @@ namespace ESM if (!hasName) esm.fail("Missing NAME subrecord"); - if (!hasData && !mIsDeleted) + if (!hasData && !isDeleted) esm.fail("Missing RIDT subrecord"); } - void Repair::save(ESMWriter &esm) const + void Repair::save(ESMWriter &esm, bool isDeleted) const { esm.writeHNCString("NAME", mId); - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); return; @@ -88,6 +83,5 @@ namespace ESM mModel.clear(); mIcon.clear(); mScript.clear(); - mIsDeleted = false; } } diff --git a/components/esm/loadrepa.hpp b/components/esm/loadrepa.hpp index 1448f9c77..2537c53cb 100644 --- a/components/esm/loadrepa.hpp +++ b/components/esm/loadrepa.hpp @@ -27,12 +27,8 @@ struct Repair Data mData; std::string mId, mName, mModel, mIcon, mScript; - bool mIsDeleted; - - Repair(); - - void load(ESMReader &esm); - void save(ESMWriter &esm) const; + void load(ESMReader &esm, bool &isDeleted); + void save(ESMWriter &esm, bool isDeleted = false) const; void blank(); ///< Set record to default state (does not touch the ID). diff --git a/components/esm/loadscpt.cpp b/components/esm/loadscpt.cpp index 333389ba4..e433ddede 100644 --- a/components/esm/loadscpt.cpp +++ b/components/esm/loadscpt.cpp @@ -10,10 +10,6 @@ namespace ESM { unsigned int Script::sRecordId = REC_SCPT; - Script::Script() - : mIsDeleted(false) - {} - void Script::loadSCVR(ESMReader &esm) { int s = mData.mStringTableSize; @@ -61,17 +57,17 @@ namespace ESM } } - void Script::load(ESMReader &esm) + void Script::load(ESMReader &esm, bool &isDeleted) { + isDeleted = false; + mVarNames.clear(); - mIsDeleted = false; bool hasHeader = false; while (esm.hasMoreSubs()) { esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + switch (esm.retSubName().val) { case ESM::FourCC<'S','C','H','D'>::value: SCHD data; @@ -80,10 +76,6 @@ namespace ESM mId = data.mName.toString(); hasHeader = true; break; - case ESM::FourCC<'D','E','L','E'>::value: - esm.skipHSub(); - mIsDeleted = true; - break; case ESM::FourCC<'S','C','V','R'>::value: // list of local variables loadSCVR(esm); @@ -96,6 +88,10 @@ namespace ESM case ESM::FourCC<'S','C','T','X'>::value: mScriptText = esm.getHString(); break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + isDeleted = true; + break; default: esm.fail("Unknown subrecord"); break; @@ -106,7 +102,7 @@ namespace ESM esm.fail("Missing SCHD subrecord"); } - void Script::save(ESMWriter &esm) const + void Script::save(ESMWriter &esm, bool isDeleted) const { std::string varNameString; if (!mVarNames.empty()) @@ -121,7 +117,7 @@ namespace ESM esm.writeHNT("SCHD", data, 52); - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); } @@ -156,8 +152,6 @@ namespace ESM mScriptText = "Begin \"" + mId + "\"\n\nEnd " + mId + "\n"; else mScriptText = "Begin " + mId + "\n\nEnd " + mId + "\n"; - - mIsDeleted = false; } } diff --git a/components/esm/loadscpt.hpp b/components/esm/loadscpt.hpp index 58b5842e8..b8a06406d 100644 --- a/components/esm/loadscpt.hpp +++ b/components/esm/loadscpt.hpp @@ -50,12 +50,8 @@ public: /// Script source code std::string mScriptText; - bool mIsDeleted; - - Script(); - - void load(ESMReader &esm); - void save(ESMWriter &esm) const; + void load(ESMReader &esm, bool &isDeleted); + void save(ESMWriter &esm, bool isDeleted = false) const; void blank(); ///< Set record to default state (does not touch the ID/index). diff --git a/components/esm/loadskil.cpp b/components/esm/loadskil.cpp index 7883b8a1a..c52089791 100644 --- a/components/esm/loadskil.cpp +++ b/components/esm/loadskil.cpp @@ -129,15 +129,16 @@ namespace ESM unsigned int Skill::sRecordId = REC_SKIL; - void Skill::load(ESMReader &esm) + void Skill::load(ESMReader &esm, bool &isDeleted) { + isDeleted = false; // Skill record can't be deleted now (may be changed in the future) + bool hasIndex = false; bool hasData = false; while (esm.hasMoreSubs()) { esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + switch (esm.retSubName().val) { case ESM::FourCC<'I','N','D','X'>::value: esm.getHT(mIndex); @@ -164,7 +165,7 @@ namespace ESM mId = indexToId (mIndex); } - void Skill::save(ESMWriter &esm) const + void Skill::save(ESMWriter &esm, bool /*isDeleted*/) const { esm.writeHNT("INDX", mIndex); esm.writeHNT("SKDT", mData, 24); diff --git a/components/esm/loadskil.hpp b/components/esm/loadskil.hpp index e00184297..5430b422d 100644 --- a/components/esm/loadskil.hpp +++ b/components/esm/loadskil.hpp @@ -78,8 +78,8 @@ struct Skill static const std::string sIconNames[Length]; static const boost::array sSkillIds; - void load(ESMReader &esm); - void save(ESMWriter &esm) const; + void load(ESMReader &esm, bool &isDeleted); + void save(ESMWriter &esm, bool isDeleted = false) const; void blank(); ///< Set record to default state (does not touch the ID/index). diff --git a/components/esm/loadsndg.cpp b/components/esm/loadsndg.cpp index a20e6ee51..400b1072b 100644 --- a/components/esm/loadsndg.cpp +++ b/components/esm/loadsndg.cpp @@ -8,31 +8,21 @@ namespace ESM { unsigned int SoundGenerator::sRecordId = REC_SNDG; - SoundGenerator::SoundGenerator() - : mType(LeftFoot), - mIsDeleted(false) - {} - - void SoundGenerator::load(ESMReader &esm) + void SoundGenerator::load(ESMReader &esm, bool &isDeleted) { - mIsDeleted = false; + isDeleted = false; bool hasName = false; bool hasData = false; while (esm.hasMoreSubs()) { esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + switch (esm.retSubName().val) { case ESM::FourCC<'N','A','M','E'>::value: mId = esm.getHString(); hasName = true; break; - case ESM::FourCC<'D','E','L','E'>::value: - esm.skipHSub(); - mIsDeleted = true; - break; case ESM::FourCC<'D','A','T','A'>::value: esm.getHT(mType, 4); hasData = true; @@ -43,6 +33,10 @@ namespace ESM case ESM::FourCC<'S','N','A','M'>::value: mSound = esm.getHString(); break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + isDeleted = true; + break; default: esm.fail("Unknown subrecord"); break; @@ -51,17 +45,17 @@ namespace ESM if (!hasName) esm.fail("Missing NAME subrecord"); - if (!hasData && !mIsDeleted) + if (!hasData && !isDeleted) esm.fail("Missing DATA subrecord"); } - void SoundGenerator::save(ESMWriter &esm) const + void SoundGenerator::save(ESMWriter &esm, bool isDeleted) const { esm.writeHNCString("NAME", mId); esm.writeHNT("DATA", mType, 4); esm.writeHNOCString("CNAM", mCreature); esm.writeHNOCString("SNAM", mSound); - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); } @@ -72,6 +66,5 @@ namespace ESM mType = LeftFoot; mCreature.clear(); mSound.clear(); - mIsDeleted = false; } } diff --git a/components/esm/loadsndg.hpp b/components/esm/loadsndg.hpp index 13eb18072..70b221e98 100644 --- a/components/esm/loadsndg.hpp +++ b/components/esm/loadsndg.hpp @@ -36,12 +36,8 @@ struct SoundGenerator std::string mId, mCreature, mSound; - bool mIsDeleted; - - SoundGenerator(); - - void load(ESMReader &esm); - void save(ESMWriter &esm) const; + void load(ESMReader &esm, bool &isDeleted); + void save(ESMWriter &esm, bool isDeleted = false) const; void blank(); }; diff --git a/components/esm/loadsoun.cpp b/components/esm/loadsoun.cpp index 55fe69292..d3a82e198 100644 --- a/components/esm/loadsoun.cpp +++ b/components/esm/loadsoun.cpp @@ -8,30 +8,21 @@ namespace ESM { unsigned int Sound::sRecordId = REC_SOUN; - Sound::Sound() - : mIsDeleted(false) - {} - - void Sound::load(ESMReader &esm) + void Sound::load(ESMReader &esm, bool &isDeleted) { - mIsDeleted = false; + isDeleted = false; bool hasName = false; bool hasData = false; while (esm.hasMoreSubs()) { esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + switch (esm.retSubName().val) { case ESM::FourCC<'N','A','M','E'>::value: mId = esm.getHString(); hasName = true; break; - case ESM::FourCC<'D','E','L','E'>::value: - esm.skipHSub(); - mIsDeleted = true; - break; case ESM::FourCC<'F','N','A','M'>::value: mSound = esm.getHString(); break; @@ -39,6 +30,10 @@ namespace ESM esm.getHT(mData, 3); hasData = true; break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + isDeleted = true; + break; default: esm.fail("Unknown subrecord"); break; @@ -47,15 +42,15 @@ namespace ESM if (!hasName) esm.fail("Missing NAME subrecord"); - if (!hasData && !mIsDeleted) + if (!hasData && !isDeleted) esm.fail("Missing DATA subrecord"); } - void Sound::save(ESMWriter &esm) const + void Sound::save(ESMWriter &esm, bool isDeleted) const { esm.writeHNCString("NAME", mId); - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); return; @@ -72,7 +67,5 @@ namespace ESM mData.mVolume = 128; mData.mMinRange = 0; mData.mMaxRange = 255; - - mIsDeleted = false; } } diff --git a/components/esm/loadsoun.hpp b/components/esm/loadsoun.hpp index 0b40ae751..937e22be8 100644 --- a/components/esm/loadsoun.hpp +++ b/components/esm/loadsoun.hpp @@ -23,12 +23,8 @@ struct Sound SOUNstruct mData; std::string mId, mSound; - bool mIsDeleted; - - Sound(); - - void load(ESMReader &esm); - void save(ESMWriter &esm) const; + void load(ESMReader &esm, bool &isDeleted); + void save(ESMWriter &esm, bool isDeleted = false) const; void blank(); ///< Set record to default state (does not touch the ID/index). diff --git a/components/esm/loadspel.cpp b/components/esm/loadspel.cpp index 28feffd20..16ffb63ff 100644 --- a/components/esm/loadspel.cpp +++ b/components/esm/loadspel.cpp @@ -8,32 +8,23 @@ namespace ESM { unsigned int Spell::sRecordId = REC_SPEL; - Spell::Spell() - : mIsDeleted(false) - {} - - void Spell::load(ESMReader &esm) + void Spell::load(ESMReader &esm, bool &isDeleted) { + isDeleted = false; + mEffects.mList.clear(); - mIsDeleted = false; bool hasName = false; bool hasData = false; while (esm.hasMoreSubs()) { esm.getSubName(); - uint32_t val = esm.retSubName().val; - - switch (val) + switch (esm.retSubName().val) { case ESM::FourCC<'N','A','M','E'>::value: mId = esm.getHString(); hasName = true; break; - case ESM::FourCC<'D','E','L','E'>::value: - esm.skipHSub(); - mIsDeleted = true; - break; case ESM::FourCC<'F','N','A','M'>::value: mName = esm.getHString(); break; @@ -46,6 +37,10 @@ namespace ESM esm.getHT(s, 24); mEffects.mList.push_back(s); break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + isDeleted = true; + break; default: esm.fail("Unknown subrecord"); break; @@ -54,15 +49,15 @@ namespace ESM if (!hasName) esm.fail("Missing NAME subrecord"); - if (!hasData && !mIsDeleted) + if (!hasData && !isDeleted) esm.fail("Missing SPDT subrecord"); } - void Spell::save(ESMWriter &esm) const + void Spell::save(ESMWriter &esm, bool isDeleted) const { esm.writeHNCString("NAME", mId); - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); return; @@ -81,6 +76,5 @@ namespace ESM mName.clear(); mEffects.mList.clear(); - mIsDeleted = false; } } diff --git a/components/esm/loadspel.hpp b/components/esm/loadspel.hpp index 327e94d8f..1763d0991 100644 --- a/components/esm/loadspel.hpp +++ b/components/esm/loadspel.hpp @@ -45,12 +45,8 @@ struct Spell std::string mId, mName; EffectList mEffects; - bool mIsDeleted; - - Spell(); - - void load(ESMReader &esm); - void save(ESMWriter &esm) const; + void load(ESMReader &esm, bool &isDeleted); + void save(ESMWriter &esm, bool isDeleted = false) const; void blank(); ///< Set record to default state (does not touch the ID/index). diff --git a/components/esm/loadsscr.cpp b/components/esm/loadsscr.cpp index 076f73742..6af6c96dc 100644 --- a/components/esm/loadsscr.cpp +++ b/components/esm/loadsscr.cpp @@ -8,21 +8,16 @@ namespace ESM { unsigned int StartScript::sRecordId = REC_SSCR; - StartScript::StartScript() - : mIsDeleted(false) - {} - - void StartScript::load(ESMReader &esm) + void StartScript::load(ESMReader &esm, bool &isDeleted) { - mIsDeleted = false; + isDeleted = false; bool hasData = false; bool hasName = false; while (esm.hasMoreSubs()) { esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + switch (esm.retSubName().val) { case ESM::FourCC<'D','A','T','A'>::value: mData = esm.getHString(); @@ -34,7 +29,7 @@ namespace ESM break; case ESM::FourCC<'D','E','L','E'>::value: esm.skipHSub(); - mIsDeleted = true; + isDeleted = true; break; default: esm.fail("Unknown subrecord"); @@ -47,12 +42,12 @@ namespace ESM if (!hasName) esm.fail("Missing NAME"); } - void StartScript::save(ESMWriter &esm) const + void StartScript::save(ESMWriter &esm, bool isDeleted) const { esm.writeHNString("DATA", mData); esm.writeHNString("NAME", mId); - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); } @@ -61,6 +56,5 @@ namespace ESM void StartScript::blank() { mData.clear(); - mIsDeleted = false; } } diff --git a/components/esm/loadsscr.hpp b/components/esm/loadsscr.hpp index e475abd86..ce2ff49e7 100644 --- a/components/esm/loadsscr.hpp +++ b/components/esm/loadsscr.hpp @@ -26,13 +26,9 @@ struct StartScript std::string mData; std::string mId; - bool mIsDeleted; - - StartScript(); - // Load a record and add it to the list - void load(ESMReader &esm); - void save(ESMWriter &esm) const; + void load(ESMReader &esm, bool &isDeleted); + void save(ESMWriter &esm, bool isDeleted = false) const; void blank(); }; diff --git a/components/esm/loadstat.cpp b/components/esm/loadstat.cpp index 9a146a370..eee7a50f5 100644 --- a/components/esm/loadstat.cpp +++ b/components/esm/loadstat.cpp @@ -8,32 +8,27 @@ namespace ESM { unsigned int Static::sRecordId = REC_STAT; - Static::Static() - : mIsDeleted(false) - {} - - void Static::load(ESMReader &esm) + void Static::load(ESMReader &esm, bool &isDeleted) { - mIsDeleted = false; + isDeleted = false; bool hasName = false; while (esm.hasMoreSubs()) { esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + switch (esm.retSubName().val) { case ESM::FourCC<'N','A','M','E'>::value: mId = esm.getHString(); hasName = true; break; - case ESM::FourCC<'D','E','L','E'>::value: - esm.skipHSub(); - mIsDeleted = true; - break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + isDeleted = true; + break; default: esm.fail("Unknown subrecord"); break; @@ -43,10 +38,10 @@ namespace ESM if (!hasName) esm.fail("Missing NAME subrecord"); } - void Static::save(ESMWriter &esm) const + void Static::save(ESMWriter &esm, bool isDeleted) const { esm.writeHNCString("NAME", mId); - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); } @@ -59,6 +54,5 @@ namespace ESM void Static::blank() { mModel.clear(); - mIsDeleted = false; } } diff --git a/components/esm/loadstat.hpp b/components/esm/loadstat.hpp index f88ad671b..930cdb849 100644 --- a/components/esm/loadstat.hpp +++ b/components/esm/loadstat.hpp @@ -28,12 +28,8 @@ struct Static std::string mId, mModel; - bool mIsDeleted; - - Static(); - - void load(ESMReader &esm); - void save(ESMWriter &esm) const; + void load(ESMReader &esm, bool &isDeleted); + void save(ESMWriter &esm, bool isDeleted = false) const; void blank(); ///< Set record to default state (does not touch the ID). diff --git a/components/esm/loadweap.cpp b/components/esm/loadweap.cpp index 98302c13d..b0bc1dad6 100644 --- a/components/esm/loadweap.cpp +++ b/components/esm/loadweap.cpp @@ -8,30 +8,21 @@ namespace ESM { unsigned int Weapon::sRecordId = REC_WEAP; - Weapon::Weapon() - : mIsDeleted(false) - {} - - void Weapon::load(ESMReader &esm) + void Weapon::load(ESMReader &esm, bool &isDeleted) { - mIsDeleted = false; + isDeleted = false; bool hasName = false; bool hasData = false; while (esm.hasMoreSubs()) { esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + switch (esm.retSubName().val) { case ESM::FourCC<'N','A','M','E'>::value: mId = esm.getHString(); hasName = true; break; - case ESM::FourCC<'D','E','L','E'>::value: - esm.skipHSub(); - mIsDeleted = true; - break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; @@ -51,6 +42,10 @@ namespace ESM case ESM::FourCC<'E','N','A','M'>::value: mEnchant = esm.getHString(); break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + isDeleted = true; + break; default: esm.fail("Unknown subrecord"); } @@ -58,14 +53,14 @@ namespace ESM if (!hasName) esm.fail("Missing NAME subrecord"); - if (!hasData && !mIsDeleted) + if (!hasData && !isDeleted) esm.fail("Missing WPDT subrecord"); } - void Weapon::save(ESMWriter &esm) const + void Weapon::save(ESMWriter &esm, bool isDeleted) const { esm.writeHNCString("NAME", mId); - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); return; @@ -98,7 +93,5 @@ namespace ESM mIcon.clear(); mEnchant.clear(); mScript.clear(); - - mIsDeleted = false; } } diff --git a/components/esm/loadweap.hpp b/components/esm/loadweap.hpp index ce61eeb72..eddcaee4f 100644 --- a/components/esm/loadweap.hpp +++ b/components/esm/loadweap.hpp @@ -69,12 +69,8 @@ struct Weapon std::string mId, mName, mModel, mIcon, mEnchant, mScript; - bool mIsDeleted; - - Weapon(); - - void load(ESMReader &esm); - void save(ESMWriter &esm) const; + void load(ESMReader &esm, bool &isDeleted); + void save(ESMWriter &esm, bool isDeleted = false) const; void blank(); ///< Set record to default state (does not touch the ID). diff --git a/components/esm/objectstate.cpp b/components/esm/objectstate.cpp index 0ae690ee8..575826ef3 100644 --- a/components/esm/objectstate.cpp +++ b/components/esm/objectstate.cpp @@ -8,7 +8,8 @@ void ESM::ObjectState::load (ESMReader &esm) { mVersion = esm.getFormat(); - mRef.loadData(esm); + bool isDeleted; + mRef.loadData(esm, isDeleted); mHasLocals = 0; esm.getHNOT (mHasLocals, "HLOC"); From 67c8f95c4e85466a7c802f4cced117ade2378184 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Tue, 21 Jul 2015 13:17:03 +0300 Subject: [PATCH 1903/3725] Load/read methods (for ESM records) accept a deleted flag in OpenMW --- apps/openmw/mwworld/cellreflist.hpp | 2 +- apps/openmw/mwworld/cellstore.cpp | 58 +++++++++--------- apps/openmw/mwworld/cellstore.hpp | 2 +- apps/openmw/mwworld/globals.cpp | 6 +- apps/openmw/mwworld/store.cpp | 94 +++++++++++++---------------- 5 files changed, 79 insertions(+), 83 deletions(-) diff --git a/apps/openmw/mwworld/cellreflist.hpp b/apps/openmw/mwworld/cellreflist.hpp index 0ce603224..49197d167 100644 --- a/apps/openmw/mwworld/cellreflist.hpp +++ b/apps/openmw/mwworld/cellreflist.hpp @@ -22,7 +22,7 @@ namespace MWWorld /// and the build will fail with an ugly three-way cyclic header dependence /// so we need to pass the instantiation of the method to the linker, when /// all methods are known. - void load (ESM::CellRef &ref, const MWWorld::ESMStore &esmStore); + void load (ESM::CellRef &ref, bool deleted, const MWWorld::ESMStore &esmStore); LiveRef *find (const std::string& name) { diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index a51672581..e9f9c5cd1 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -147,7 +147,7 @@ namespace MWWorld { template - void CellRefList::load(ESM::CellRef &ref, const MWWorld::ESMStore &esmStore) + void CellRefList::load(ESM::CellRef &ref, bool deleted, const MWWorld::ESMStore &esmStore) { const MWWorld::Store &store = esmStore.get(); @@ -158,7 +158,7 @@ namespace MWWorld LiveRef liveCellRef (ref, ptr); - if (ref.mIsDeleted) + if (deleted) liveCellRef.mData.setDeleted(true); if (iter != mList.end()) @@ -374,9 +374,10 @@ namespace MWWorld ESM::CellRef ref; // Get each reference in turn - while (mCell->getNextRef (esm[index], ref)) + bool deleted = false; + while (mCell->getNextRef (esm[index], ref, deleted)) { - if (ref.mIsDeleted) + if (deleted) continue; // Don't list reference if it was moved to a different cell. @@ -419,7 +420,8 @@ namespace MWWorld ref.mRefNum.mContentFile = ESM::RefNum::RefNum_NoContentFile; // Get each reference in turn - while(mCell->getNextRef(esm[index], ref)) + bool deleted = false; + while(mCell->getNextRef(esm[index], ref, deleted)) { // Don't load reference if it was moved to a different cell. ESM::MovedCellRefTracker::const_iterator iter = @@ -428,7 +430,7 @@ namespace MWWorld continue; } - loadRef (ref, store); + loadRef (ref, deleted, store); } } @@ -437,7 +439,7 @@ namespace MWWorld { ESM::CellRef &ref = const_cast(*it); - loadRef (ref, store); + loadRef (ref, false, store); } } @@ -466,32 +468,32 @@ namespace MWWorld return Ptr(); } - void CellStore::loadRef (ESM::CellRef& ref, const ESMStore& store) + void CellStore::loadRef (ESM::CellRef& ref, bool deleted, const ESMStore& store) { Misc::StringUtils::toLower (ref.mRefID); switch (store.find (ref.mRefID)) { - case ESM::REC_ACTI: mActivators.load(ref, store); break; - case ESM::REC_ALCH: mPotions.load(ref,store); break; - case ESM::REC_APPA: mAppas.load(ref, store); break; - case ESM::REC_ARMO: mArmors.load(ref, store); break; - case ESM::REC_BOOK: mBooks.load(ref, store); break; - case ESM::REC_CLOT: mClothes.load(ref, store); break; - case ESM::REC_CONT: mContainers.load(ref, store); break; - case ESM::REC_CREA: mCreatures.load(ref, store); break; - case ESM::REC_DOOR: mDoors.load(ref, store); break; - case ESM::REC_INGR: mIngreds.load(ref, store); break; - case ESM::REC_LEVC: mCreatureLists.load(ref, store); break; - case ESM::REC_LEVI: mItemLists.load(ref, store); break; - case ESM::REC_LIGH: mLights.load(ref, store); break; - case ESM::REC_LOCK: mLockpicks.load(ref, store); break; - case ESM::REC_MISC: mMiscItems.load(ref, store); break; - case ESM::REC_NPC_: mNpcs.load(ref, store); break; - case ESM::REC_PROB: mProbes.load(ref, store); break; - case ESM::REC_REPA: mRepairs.load(ref, store); break; - case ESM::REC_STAT: mStatics.load(ref, store); break; - case ESM::REC_WEAP: mWeapons.load(ref, store); break; + case ESM::REC_ACTI: mActivators.load(ref, deleted, store); break; + case ESM::REC_ALCH: mPotions.load(ref, deleted,store); break; + case ESM::REC_APPA: mAppas.load(ref, deleted, store); break; + case ESM::REC_ARMO: mArmors.load(ref, deleted, store); break; + case ESM::REC_BOOK: mBooks.load(ref, deleted, store); break; + case ESM::REC_CLOT: mClothes.load(ref, deleted, store); break; + case ESM::REC_CONT: mContainers.load(ref, deleted, store); break; + case ESM::REC_CREA: mCreatures.load(ref, deleted, store); break; + case ESM::REC_DOOR: mDoors.load(ref, deleted, store); break; + case ESM::REC_INGR: mIngreds.load(ref, deleted, store); break; + case ESM::REC_LEVC: mCreatureLists.load(ref, deleted, store); break; + case ESM::REC_LEVI: mItemLists.load(ref, deleted, store); break; + case ESM::REC_LIGH: mLights.load(ref, deleted, store); break; + case ESM::REC_LOCK: mLockpicks.load(ref, deleted, store); break; + case ESM::REC_MISC: mMiscItems.load(ref, deleted, store); break; + case ESM::REC_NPC_: mNpcs.load(ref, deleted, store); break; + case ESM::REC_PROB: mProbes.load(ref, deleted, store); break; + case ESM::REC_REPA: mRepairs.load(ref, deleted, store); break; + case ESM::REC_STAT: mStatics.load(ref, deleted, store); break; + case ESM::REC_WEAP: mWeapons.load(ref, deleted, store); break; case 0: std::cerr << "Cell reference " + ref.mRefID + " not found!\n"; break; diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index 5caa4eeea..f879343d9 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -214,7 +214,7 @@ namespace MWWorld void loadRefs(const MWWorld::ESMStore &store, std::vector &esm); - void loadRef (ESM::CellRef& ref, const ESMStore& store); + void loadRef (ESM::CellRef& ref, bool deleted, const ESMStore& store); ///< Make case-adjustments to \a ref and insert it into the respective container. /// /// Invalid \a ref objects are silently dropped. diff --git a/apps/openmw/mwworld/globals.cpp b/apps/openmw/mwworld/globals.cpp index 668a33f09..87070a712 100644 --- a/apps/openmw/mwworld/globals.cpp +++ b/apps/openmw/mwworld/globals.cpp @@ -92,7 +92,11 @@ namespace MWWorld if (type==ESM::REC_GLOB) { ESM::Global global; - global.load(reader); + bool isDeleted = false; + + // This readRecord() method is used when reading a saved game. + // Deleted globals can't appear there, so isDeleted will be ignored here. + global.load(reader, isDeleted); Misc::StringUtils::toLower(global.mId); Collection::iterator iter = mVariables.find (global.mId); diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index 55fb43e00..cd9290bfc 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -66,7 +66,9 @@ namespace MWWorld void IndexedStore::load(ESM::ESMReader &esm) { T record; - record.load(esm); + bool isDeleted = false; + + record.load(esm, isDeleted); // Try to overwrite existing record std::pair ret = mStatic.insert(std::make_pair(record.mIndex, record)); @@ -187,14 +189,16 @@ namespace MWWorld RecordId Store::load(ESM::ESMReader &esm) { T record; - record.load(esm); + bool isDeleted = false; + + record.load(esm, isDeleted); Misc::StringUtils::toLower(record.mId); std::pair inserted = mStatic.insert(std::make_pair(record.mId, record)); if (inserted.second) mShared.push_back(&inserted.first->second); - return RecordId(record.mId, record.mIsDeleted); + return RecordId(record.mId, isDeleted); } template void Store::setUp() @@ -324,10 +328,12 @@ namespace MWWorld RecordId Store::read(ESM::ESMReader& reader) { T record; - record.load (reader); + bool isDeleted = false; + + record.load (reader, isDeleted); insert (record); - return RecordId(record.mId, record.mIsDeleted); + return RecordId(record.mId, isDeleted); } // LandTexture @@ -370,7 +376,9 @@ namespace MWWorld RecordId Store::load(ESM::ESMReader &esm, size_t plugin) { ESM::LandTexture lt; - lt.load(esm); + bool isDeleted = false; + + lt.load(esm, isDeleted); // Make sure we have room for the structure if (plugin >= mStatic.size()) { @@ -383,7 +391,7 @@ namespace MWWorld // Store it ltexl[lt.mIndex] = lt; - return RecordId(lt.mId, lt.mIsDeleted); + return RecordId(lt.mId, isDeleted); } RecordId Store::load(ESM::ESMReader &esm) { @@ -449,7 +457,9 @@ namespace MWWorld RecordId Store::load(ESM::ESMReader &esm) { ESM::Land *ptr = new ESM::Land(); - ptr->load(esm); + bool isDeleted = false; + + ptr->load(esm, isDeleted); // Same area defined in multiple plugins? -> last plugin wins // Can't use search() because we aren't sorted yet - is there any other way to speed this up? @@ -465,7 +475,7 @@ namespace MWWorld mStatic.push_back(ptr); - return RecordId(); // No ID and can't be deleted (for now) + return RecordId("", isDeleted); } void Store::setUp() { @@ -617,12 +627,12 @@ namespace MWWorld // All cells have a name record, even nameless exterior cells. ESM::Cell cell; - cell.loadName(esm); - std::string idLower = Misc::StringUtils::lowerCase(cell.mName); + bool isDeleted = false; - // Load the (x,y) coordinates of the cell, if it is an exterior cell, + // Load the (x,y) coordinates of the cell, if it is an exterior cell, // so we can find the cell we need to merge with - cell.loadData(esm); + cell.loadNameAndData(esm, isDeleted); + std::string idLower = Misc::StringUtils::lowerCase(cell.mName); if(cell.mData.mFlags & ESM::Cell::Interior) { @@ -690,7 +700,8 @@ namespace MWWorld mExt[std::make_pair(cell.mData.mX, cell.mData.mY)] = cell; } } - return RecordId("", cell.mIsDeleted); + + return RecordId(cell.mName, isDeleted); } Store::iterator Store::intBegin() const { @@ -849,7 +860,9 @@ namespace MWWorld RecordId Store::load(ESM::ESMReader &esm) { ESM::Pathgrid pathgrid; - pathgrid.load(esm); + bool isDeleted = false; + + pathgrid.load(esm, isDeleted); // Unfortunately the Pathgrid record model does not specify whether the pathgrid belongs to an interior or exterior cell. // For interior cells, mCell is the cell name, but for exterior cells it is either the cell name or if that doesn't exist, the cell's region name. @@ -872,7 +885,7 @@ namespace MWWorld ret.first->second = pathgrid; } - return RecordId(); // No ID and can't be deleted (for now) + return RecordId("", isDeleted); } size_t Store::getSize() const { @@ -1027,22 +1040,24 @@ namespace MWWorld inline RecordId Store::load(ESM::ESMReader &esm) { // The original letter case of a dialogue ID is saved, because it's printed ESM::Dialogue dialogue; + bool isDeleted = false; + dialogue.loadId(esm); std::string idLower = Misc::StringUtils::lowerCase(dialogue.mId); std::map::iterator found = mStatic.find(idLower); if (found == mStatic.end()) { - dialogue.loadData(esm); + dialogue.loadData(esm, isDeleted); mStatic.insert(std::make_pair(idLower, dialogue)); } else { - found->second.loadData(esm); + found->second.loadData(esm, isDeleted); dialogue = found->second; } - return RecordId(dialogue.mId, dialogue.mIsDeleted); + return RecordId(dialogue.mId, isDeleted); } @@ -1052,7 +1067,9 @@ namespace MWWorld template <> inline RecordId Store::load(ESM::ESMReader &esm) { ESM::Script script; - script.load(esm); + bool isDeleted = false; + + script.load(esm, isDeleted); Misc::StringUtils::toLower(script.mId); std::pair inserted = mStatic.insert(std::make_pair(script.mId, script)); @@ -1061,7 +1078,7 @@ namespace MWWorld else inserted.first->second = script; - return RecordId(script.mId, script.mIsDeleted); + return RecordId(script.mId, isDeleted); } @@ -1072,7 +1089,9 @@ namespace MWWorld inline RecordId Store::load(ESM::ESMReader &esm) { ESM::StartScript script; - script.load(esm); + bool isDeleted = false; + + script.load(esm, isDeleted); Misc::StringUtils::toLower(script.mId); std::pair inserted = mStatic.insert(std::make_pair(script.mId, script)); @@ -1081,36 +1100,7 @@ namespace MWWorld else inserted.first->second = script; - return RecordId(script.mId); - } - - // GameSetting - // Need to specialize load() and read() methods, because GameSetting can't - // be deleted (has no mIsDeleted flag) - //========================================================================= - - template <> - inline RecordId Store::load(ESM::ESMReader &reader) - { - ESM::GameSetting setting; - setting.load(reader); - Misc::StringUtils::toLower(setting.mId); - - std::pair inserted = mStatic.insert(std::make_pair(setting.mId, setting)); - if (inserted.second) - mShared.push_back(&inserted.first->second); - - return RecordId(setting.mId); - } - - template <> - inline RecordId Store::read(ESM::ESMReader &reader) - { - ESM::GameSetting setting; - setting.load(reader); - insert(setting); - - return RecordId(setting.mId); + return RecordId(script.mId, isDeleted); } } From 13bb6be2383c808084eabed0cb1bfb3b9749e55a Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Tue, 21 Jul 2015 20:25:43 +0300 Subject: [PATCH 1904/3725] Load methods (for ESM records) accept a deleted flag in OpenCS --- apps/opencs/model/doc/savingstages.cpp | 31 ++++-------- apps/opencs/model/doc/savingstages.hpp | 3 +- apps/opencs/model/world/cell.cpp | 6 +-- apps/opencs/model/world/cell.hpp | 2 +- apps/opencs/model/world/data.cpp | 6 ++- apps/opencs/model/world/idcollection.cpp | 3 -- apps/opencs/model/world/idcollection.hpp | 13 +++-- apps/opencs/model/world/infocollection.cpp | 6 ++- apps/opencs/model/world/land.cpp | 5 +- apps/opencs/model/world/land.hpp | 2 +- apps/opencs/model/world/landtexture.cpp | 8 +--- apps/opencs/model/world/landtexture.hpp | 2 +- apps/opencs/model/world/pathgrid.cpp | 15 ++---- apps/opencs/model/world/pathgrid.hpp | 5 +- apps/opencs/model/world/record.cpp | 48 ------------------- apps/opencs/model/world/record.hpp | 39 --------------- apps/opencs/model/world/refcollection.cpp | 5 +- apps/opencs/model/world/refiddata.hpp | 11 +++-- apps/opencs/model/world/subcellcollection.hpp | 7 +-- 19 files changed, 56 insertions(+), 161 deletions(-) delete mode 100644 apps/opencs/model/world/idcollection.cpp diff --git a/apps/opencs/model/doc/savingstages.cpp b/apps/opencs/model/doc/savingstages.cpp index dbfa4651b..87f7ea16a 100644 --- a/apps/opencs/model/doc/savingstages.cpp +++ b/apps/opencs/model/doc/savingstages.cpp @@ -107,10 +107,8 @@ void CSMDoc::WriteDialogueCollectionStage::perform (int stage, Messages& message { // if the topic is deleted, we do not need to bother with INFO records. ESM::Dialogue dialogue = topic.get(); - dialogue.mIsDeleted = true; - writer.startRecord(dialogue.sRecordId); - dialogue.save(writer); + dialogue.save(writer, true); writer.endRecord(dialogue.sRecordId); return; } @@ -121,7 +119,7 @@ void CSMDoc::WriteDialogueCollectionStage::perform (int stage, Messages& message for (CSMWorld::InfoCollection::RecordConstIterator iter (range.first); iter!=range.second; ++iter) { - if (topic.isModified() || iter->mState == CSMWorld::RecordBase::State_Deleted) + if (iter->isModified() || iter->mState == CSMWorld::RecordBase::State_Deleted) { infoModified = true; break; @@ -131,7 +129,6 @@ void CSMDoc::WriteDialogueCollectionStage::perform (int stage, Messages& message if (topic.isModified() || infoModified) { ESM::Dialogue dialogue = topic.get(); - writer.startRecord (dialogue.sRecordId); dialogue.save (writer); writer.endRecord (dialogue.sRecordId); @@ -143,7 +140,6 @@ void CSMDoc::WriteDialogueCollectionStage::perform (int stage, Messages& message { ESM::DialInfo info = iter->get(); info.mId = info.mId.substr (info.mId.find_last_of ('#')+1); - info.mIsDeleted = (iter->mState == CSMWorld::RecordBase::State_Deleted); info.mPrev = ""; if (iter!=range.first) @@ -164,7 +160,7 @@ void CSMDoc::WriteDialogueCollectionStage::perform (int stage, Messages& message } writer.startRecord (info.sRecordId); - info.save (writer); + info.save (writer, iter->mState == CSMWorld::RecordBase::State_Deleted); writer.endRecord (info.sRecordId); } } @@ -213,9 +209,7 @@ void CSMDoc::CollectionReferencesStage::perform (int stage, Messages& messages) const CSMWorld::Record& record = mDocument.getData().getReferences().getRecord (i); - if (record.mState==CSMWorld::RecordBase::State_Deleted || - record.mState==CSMWorld::RecordBase::State_Modified || - record.mState==CSMWorld::RecordBase::State_ModifiedOnly) + if (record.isModified() || record.mState == CSMWorld::RecordBase::State_Deleted) { std::string cellId = record.get().mOriginalCell.empty() ? record.get().mCell : record.get().mOriginalCell; @@ -284,8 +278,7 @@ void CSMDoc::WriteCellCollectionStage::perform (int stage, Messages& messages) stream >> ignore >> cellRecord.mData.mX >> cellRecord.mData.mY; } - cellRecord.mIsDeleted = (cell.mState == CSMWorld::RecordBase::State_Deleted); - cellRecord.save (writer); + cellRecord.save (writer, cell.mState == CSMWorld::RecordBase::State_Deleted); // write references if (references!=mState.getSubRecords().end()) @@ -326,8 +319,7 @@ void CSMDoc::WriteCellCollectionStage::perform (int stage, Messages& messages) writer.writeHNT ("CNDT", moved.mTarget, 8); } - refRecord.mIsDeleted = (ref.mState == CSMWorld::RecordBase::State_Deleted); - refRecord.save (writer); + refRecord.save (writer, false, false, ref.mState == CSMWorld::RecordBase::State_Deleted); } } } @@ -366,9 +358,8 @@ void CSMDoc::WritePathgridCollectionStage::perform (int stage, Messages& message else record.mCell = record.mId; - record.mIsDeleted = (pathgrid.mState == CSMWorld::RecordBase::State_Deleted); writer.startRecord (record.sRecordId); - record.save (writer); + record.save (writer, pathgrid.mState == CSMWorld::RecordBase::State_Deleted); writer.endRecord (record.sRecordId); } } @@ -393,10 +384,8 @@ void CSMDoc::WriteLandCollectionStage::perform (int stage, Messages& messages) if (land.isModified() || land.mState == CSMWorld::RecordBase::State_Deleted) { CSMWorld::Land record = land.get(); - - record.mLand->mIsDeleted = (land.mState == CSMWorld::RecordBase::State_Deleted); writer.startRecord (record.mLand->sRecordId); - record.mLand->save (writer); + record.mLand->save (writer, land.mState == CSMWorld::RecordBase::State_Deleted); writer.endRecord (record.mLand->sRecordId); } } @@ -421,10 +410,8 @@ void CSMDoc::WriteLandTextureCollectionStage::perform (int stage, Messages& mess if (landTexture.isModified() || landTexture.mState == CSMWorld::RecordBase::State_Deleted) { CSMWorld::LandTexture record = landTexture.get(); - record.mIsDeleted = (landTexture.mState == CSMWorld::RecordBase::State_Deleted); - writer.startRecord (record.sRecordId); - record.save (writer); + record.save (writer, landTexture.mState == CSMWorld::RecordBase::State_Deleted); writer.endRecord (record.sRecordId); } } diff --git a/apps/opencs/model/doc/savingstages.hpp b/apps/opencs/model/doc/savingstages.hpp index a7d9704b0..64afd0dd8 100644 --- a/apps/opencs/model/doc/savingstages.hpp +++ b/apps/opencs/model/doc/savingstages.hpp @@ -108,9 +108,8 @@ namespace CSMDoc state == CSMWorld::RecordBase::State_ModifiedOnly || state == CSMWorld::RecordBase::State_Deleted) { - CSMWorld::setRecordDeleted (record, state == CSMWorld::RecordBase::State_Deleted); writer.startRecord (record.sRecordId); - record.save (writer); + record.save (writer, state == CSMWorld::RecordBase::State_Deleted); writer.endRecord (record.sRecordId); } } diff --git a/apps/opencs/model/world/cell.cpp b/apps/opencs/model/world/cell.cpp index 8816cd35e..be64061be 100644 --- a/apps/opencs/model/world/cell.cpp +++ b/apps/opencs/model/world/cell.cpp @@ -3,12 +3,12 @@ #include -void CSMWorld::Cell::load (ESM::ESMReader &esm) +void CSMWorld::Cell::load (ESM::ESMReader &esm, bool &isDeleted) { - ESM::Cell::load (esm, false); + ESM::Cell::load (esm, isDeleted, false); mId = mName; - if (!(mData.mFlags & Interior)) + if (isExterior()) { std::ostringstream stream; stream << "#" << mData.mX << " " << mData.mY; diff --git a/apps/opencs/model/world/cell.hpp b/apps/opencs/model/world/cell.hpp index f393e2cf9..160610874 100644 --- a/apps/opencs/model/world/cell.hpp +++ b/apps/opencs/model/world/cell.hpp @@ -16,7 +16,7 @@ namespace CSMWorld { std::string mId; - void load (ESM::ESMReader &esm); + void load (ESM::ESMReader &esm, bool &isDeleted); }; } diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 91ccda73c..32255cb1a 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -989,9 +989,11 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Messages& messages) case ESM::REC_DIAL: { ESM::Dialogue record; - record.load (*mReader); + bool isDeleted = false; - if (record.mIsDeleted) + record.load (*mReader, isDeleted); + + if (isDeleted) { // record vector can be shuffled around which would make pointer to record invalid mDialogue = 0; diff --git a/apps/opencs/model/world/idcollection.cpp b/apps/opencs/model/world/idcollection.cpp deleted file mode 100644 index 9571ed773..000000000 --- a/apps/opencs/model/world/idcollection.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include "idcollection.hpp" - - diff --git a/apps/opencs/model/world/idcollection.hpp b/apps/opencs/model/world/idcollection.hpp index 9d3ec990e..c79b4e020 100644 --- a/apps/opencs/model/world/idcollection.hpp +++ b/apps/opencs/model/world/idcollection.hpp @@ -12,7 +12,7 @@ namespace CSMWorld template > class IdCollection : public Collection { - virtual void loadRecord (ESXRecordT& record, ESM::ESMReader& reader); + virtual void loadRecord (ESXRecordT& record, ESM::ESMReader& reader, bool& isDeleted); public: @@ -34,21 +34,24 @@ namespace CSMWorld template void IdCollection::loadRecord (ESXRecordT& record, - ESM::ESMReader& reader) + ESM::ESMReader& reader, + bool& isDeleted) { - record.load (reader); + record.load (reader, isDeleted); } template int IdCollection::load (ESM::ESMReader& reader, bool base) { ESXRecordT record; - loadRecord (record, reader); + bool isDeleted = false; + + loadRecord (record, reader, isDeleted); std::string id = IdAccessorT().getId (record); int index = this->searchId (id); - if (isRecordDeleted(record)) + if (isDeleted) { if (index==-1) { diff --git a/apps/opencs/model/world/infocollection.cpp b/apps/opencs/model/world/infocollection.cpp index 665b497d0..81f3ac143 100644 --- a/apps/opencs/model/world/infocollection.cpp +++ b/apps/opencs/model/world/infocollection.cpp @@ -108,10 +108,12 @@ bool CSMWorld::InfoCollection::reorderRows (int baseIndex, const std::vectorload(esm); + mLand->load(esm, isDeleted); std::ostringstream stream; stream << "#" << mLand->mX << " " << mLand->mY; - mId = stream.str(); } diff --git a/apps/opencs/model/world/land.hpp b/apps/opencs/model/world/land.hpp index e97a2d7dd..c006f2a4d 100644 --- a/apps/opencs/model/world/land.hpp +++ b/apps/opencs/model/world/land.hpp @@ -20,7 +20,7 @@ namespace CSMWorld std::string mId; /// Loads the metadata and ID - void load (ESM::ESMReader &esm); + void load (ESM::ESMReader &esm, bool &isDeleted); void blank(); }; diff --git a/apps/opencs/model/world/landtexture.cpp b/apps/opencs/model/world/landtexture.cpp index 4725866a5..9e8dcff9f 100644 --- a/apps/opencs/model/world/landtexture.cpp +++ b/apps/opencs/model/world/landtexture.cpp @@ -4,17 +4,13 @@ namespace CSMWorld { - - void LandTexture::load(ESM::ESMReader &esm) + void LandTexture::load(ESM::ESMReader &esm, bool &isDeleted) { - ESM::LandTexture::load(esm); - + ESM::LandTexture::load(esm, isDeleted); int plugin = esm.getIndex(); std::ostringstream stream; - stream << mIndex << "_" << plugin; - mId = stream.str(); } diff --git a/apps/opencs/model/world/landtexture.hpp b/apps/opencs/model/world/landtexture.hpp index b13903186..e18f0277c 100644 --- a/apps/opencs/model/world/landtexture.hpp +++ b/apps/opencs/model/world/landtexture.hpp @@ -15,7 +15,7 @@ namespace CSMWorld { std::string mId; - void load (ESM::ESMReader &esm); + void load (ESM::ESMReader &esm, bool &isDeleted); }; } diff --git a/apps/opencs/model/world/pathgrid.cpp b/apps/opencs/model/world/pathgrid.cpp index 5c66e7d8e..c995bd8f0 100644 --- a/apps/opencs/model/world/pathgrid.cpp +++ b/apps/opencs/model/world/pathgrid.cpp @@ -4,33 +4,28 @@ #include -void CSMWorld::Pathgrid::load (ESM::ESMReader &esm, const IdCollection& cells) +void CSMWorld::Pathgrid::load (ESM::ESMReader &esm, bool &isDeleted, const IdCollection& cells) { - load (esm); + load (esm, isDeleted); // correct ID if (!mId.empty() && mId[0]!='#' && cells.searchId (mId)==-1) { std::ostringstream stream; - stream << "#" << mData.mX << " " << mData.mY; - mId = stream.str(); } } -void CSMWorld::Pathgrid::load (ESM::ESMReader &esm) +void CSMWorld::Pathgrid::load (ESM::ESMReader &esm, bool &isDeleted) { - ESM::Pathgrid::load (esm); + ESM::Pathgrid::load (esm, isDeleted); + mId = mCell; if (mCell.empty()) { std::ostringstream stream; - stream << "#" << mData.mX << " " << mData.mY; - mId = stream.str(); } - else - mId = mCell; } diff --git a/apps/opencs/model/world/pathgrid.hpp b/apps/opencs/model/world/pathgrid.hpp index 7e7b7c3bb..22d01b071 100644 --- a/apps/opencs/model/world/pathgrid.hpp +++ b/apps/opencs/model/world/pathgrid.hpp @@ -20,9 +20,8 @@ namespace CSMWorld { std::string mId; - void load (ESM::ESMReader &esm, const IdCollection& cells); - - void load (ESM::ESMReader &esm); + void load (ESM::ESMReader &esm, bool &isDeleted, const IdCollection& cells); + void load (ESM::ESMReader &esm, bool &isDeleted); }; } diff --git a/apps/opencs/model/world/record.cpp b/apps/opencs/model/world/record.cpp index 7563c4cfd..ef2f4d320 100644 --- a/apps/opencs/model/world/record.cpp +++ b/apps/opencs/model/world/record.cpp @@ -19,51 +19,3 @@ bool CSMWorld::RecordBase::isModified() const { return mState==State_Modified || mState==State_ModifiedOnly; } - -template<> -bool CSMWorld::isRecordDeleted(const CSMWorld::Land &land) -{ - return land.mLand->mIsDeleted; -} - -template<> -bool CSMWorld::isRecordDeleted(const ESM::GameSetting &setting) -{ - return false; -} - -template<> -bool CSMWorld::isRecordDeleted(const ESM::MagicEffect &effect) -{ - return false; -} - -template<> -bool CSMWorld::isRecordDeleted(const ESM::Skill &skill) -{ - return false; -} - -template<> -void CSMWorld::setRecordDeleted(CSMWorld::Land &land, bool isDeleted) -{ - land.mLand->mIsDeleted = isDeleted; -} - -template<> -void CSMWorld::setRecordDeleted(ESM::GameSetting &setting, bool isDeleted) -{ - // GameSetting doesn't have a Deleted flag -} - -template<> -void CSMWorld::setRecordDeleted(ESM::MagicEffect &effect, bool isDeleted) -{ - // MagicEffect doesn't have a Deleted flag -} - -template<> -void CSMWorld::setRecordDeleted(ESM::Skill &skill, bool isDeleted) -{ - // Skill doesn't have a Deleted flag -} diff --git a/apps/opencs/model/world/record.hpp b/apps/opencs/model/world/record.hpp index 8e39cd705..3362f9f96 100644 --- a/apps/opencs/model/world/record.hpp +++ b/apps/opencs/model/world/record.hpp @@ -3,12 +3,6 @@ #include -#include -#include -#include - -#include "land.hpp" - namespace CSMWorld { struct RecordBase @@ -160,39 +154,6 @@ namespace CSMWorld mState = State_Erased; } } - - // Not all records can be deleted (may be changed in the future), - // so we need to use a separate method to check whether a record is deleted or not. - template - bool isRecordDeleted(const ESXRecordT &record) - { - return record.mIsDeleted; - } - - template<> - bool isRecordDeleted(const Land &land); - template<> - bool isRecordDeleted(const ESM::GameSetting &setting); - template<> - bool isRecordDeleted(const ESM::MagicEffect &effect); - template<> - bool isRecordDeleted(const ESM::Skill &skill); - - // ... and also a separate method for setting the deleted flag of a record - template - void setRecordDeleted(ESXRecordT &record, bool isDeleted = false) - { - record.mIsDeleted = isDeleted; - } - - template<> - void setRecordDeleted(Land &land, bool isDeleted); - template<> - void setRecordDeleted(ESM::GameSetting &setting, bool isDeleted); - template<> - void setRecordDeleted(ESM::MagicEffect &effect, bool isDeleted); - template<> - void setRecordDeleted(ESM::Skill &skill, bool isDeleted); } #endif diff --git a/apps/opencs/model/world/refcollection.cpp b/apps/opencs/model/world/refcollection.cpp index d32f21d0a..39af9b408 100644 --- a/apps/opencs/model/world/refcollection.cpp +++ b/apps/opencs/model/world/refcollection.cpp @@ -21,9 +21,10 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool CellRef ref; ESM::MovedCellRef mref; + bool isDeleted = false; // hack to initialise mindex - while (!(mref.mRefNum.mIndex = 0) && ESM::Cell::getNextRef(reader, ref, true, &mref)) + while (!(mref.mRefNum.mIndex = 0) && ESM::Cell::getNextRef(reader, ref, isDeleted, true, &mref)) { // Keep mOriginalCell empty when in modified (as an indicator that the // original cell will always be equal the current cell). @@ -79,7 +80,7 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool break; } - if (ref.mIsDeleted) + if (isDeleted) { if (iter==cache.end()) { diff --git a/apps/opencs/model/world/refiddata.hpp b/apps/opencs/model/world/refiddata.hpp index 195244ba8..0c9239d59 100644 --- a/apps/opencs/model/world/refiddata.hpp +++ b/apps/opencs/model/world/refiddata.hpp @@ -129,7 +129,9 @@ namespace CSMWorld int RefIdDataContainer::load (ESM::ESMReader& reader, bool base) { RecordT record; - record.load(reader); + bool isDeleted = false; + + record.load(reader, isDeleted); int index = 0; int numRecords = static_cast(mContainer.size()); @@ -141,7 +143,7 @@ namespace CSMWorld } } - if (record.mIsDeleted) + if (isDeleted) { if (index == numRecords) { @@ -197,13 +199,12 @@ namespace CSMWorld void RefIdDataContainer::save (int index, ESM::ESMWriter& writer) const { Record record = mContainer.at(index); - RecordT esmRecord = record.get(); if (record.isModified() || record.mState == RecordBase::State_Deleted) { - esmRecord.mIsDeleted = (record.mState == RecordBase::State_Deleted); + RecordT esmRecord = record.get(); writer.startRecord(esmRecord.sRecordId); - esmRecord.save(writer); + esmRecord.save(writer, record.mState == RecordBase::State_Deleted); writer.endRecord(esmRecord.sRecordId); } } diff --git a/apps/opencs/model/world/subcellcollection.hpp b/apps/opencs/model/world/subcellcollection.hpp index df1f8a12e..496cb0643 100644 --- a/apps/opencs/model/world/subcellcollection.hpp +++ b/apps/opencs/model/world/subcellcollection.hpp @@ -20,7 +20,7 @@ namespace CSMWorld { const IdCollection& mCells; - virtual void loadRecord (ESXRecordT& record, ESM::ESMReader& reader); + virtual void loadRecord (ESXRecordT& record, ESM::ESMReader& reader, bool& isDeleted); public: @@ -29,9 +29,10 @@ namespace CSMWorld template void SubCellCollection::loadRecord (ESXRecordT& record, - ESM::ESMReader& reader) + ESM::ESMReader& reader, + bool& isDeleted) { - record.load (reader, mCells); + record.load (reader, isDeleted, mCells); } template From 8243fb2479a18cd47e03e9ffcff87020a9c1446f Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Tue, 21 Jul 2015 20:47:02 +0300 Subject: [PATCH 1905/3725] Load methods (for ESM records) accept a deleted flag in ESMTool --- apps/esmtool/esmtool.cpp | 14 ++++---- apps/esmtool/record.cpp | 74 ++++++++++++++++++++-------------------- apps/esmtool/record.hpp | 9 +++-- 3 files changed, 52 insertions(+), 45 deletions(-) diff --git a/apps/esmtool/esmtool.cpp b/apps/esmtool/esmtool.cpp index c2507ccdc..be90afec3 100644 --- a/apps/esmtool/esmtool.cpp +++ b/apps/esmtool/esmtool.cpp @@ -27,7 +27,8 @@ struct ESMData std::vector masters; std::deque mRecords; - std::map > mCellRefs; + // Value: (Reference, Deleted flag) + std::map > > mCellRefs; std::map mRecordStats; static const std::set sLabeledRec; @@ -251,10 +252,11 @@ void loadCell(ESM::Cell &cell, ESM::ESMReader &esm, Arguments& info) ESM::CellRef ref; if(!quiet) std::cout << " References:\n"; - while(cell.getNextRef(esm, ref)) + bool deleted = false; + while(cell.getNextRef(esm, ref, deleted)) { if (save) { - info.data.mCellRefs[&cell].push_back(ref); + info.data.mCellRefs[&cell].push_back(std::make_pair(ref, deleted)); } if(quiet) continue; @@ -269,7 +271,7 @@ void loadCell(ESM::Cell &cell, ESM::ESMReader &esm, Arguments& info) std::cout << " Uses/health: '" << ref.mChargeInt << "'\n"; std::cout << " Gold value: '" << ref.mGoldValue << "'\n"; std::cout << " Blocked: '" << static_cast(ref.mReferenceBlocked) << "'" << std::endl; - std::cout << " Deleted: " << ref.mIsDeleted << std::endl; + std::cout << " Deleted: " << deleted << std::endl; if (!ref.mKey.empty()) std::cout << " Key: '" << ref.mKey << "'" << std::endl; } @@ -497,11 +499,11 @@ int clone(Arguments& info) if (name.val == ESM::REC_CELL) { ESM::Cell *ptr = &record->cast()->get(); if (!info.data.mCellRefs[ptr].empty()) { - typedef std::deque RefList; + typedef std::deque > RefList; RefList &refs = info.data.mCellRefs[ptr]; for (RefList::iterator refIt = refs.begin(); refIt != refs.end(); ++refIt) { - refIt->save(esm); + refIt->first.save(esm, refIt->second); } } } diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index a03318262..728c5dc91 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -405,7 +405,7 @@ void Record::print() std::cout << " Name: " << mData.mName << std::endl; std::cout << " Model: " << mData.mModel << std::endl; std::cout << " Script: " << mData.mScript << std::endl; - std::cout << " Deleted: " << mData.mIsDeleted << std::endl; + std::cout << " Deleted: " << mIsDeleted << std::endl; } template<> @@ -420,7 +420,7 @@ void Record::print() std::cout << " Value: " << mData.mData.mValue << std::endl; std::cout << " AutoCalc: " << mData.mData.mAutoCalc << std::endl; printEffectList(mData.mEffects); - std::cout << " Deleted: " << mData.mIsDeleted << std::endl; + std::cout << " Deleted: " << mIsDeleted << std::endl; } template<> @@ -449,7 +449,7 @@ void Record::print() if (pit->mFemale != "") std::cout << " Female Name: " << pit->mFemale << std::endl; } - std::cout << " Deleted: " << mData.mIsDeleted << std::endl; + std::cout << " Deleted: " << mIsDeleted << std::endl; } template<> @@ -464,7 +464,7 @@ void Record::print() std::cout << " Weight: " << mData.mData.mWeight << std::endl; std::cout << " Value: " << mData.mData.mValue << std::endl; std::cout << " Quality: " << mData.mData.mQuality << std::endl; - std::cout << " Deleted: " << mData.mIsDeleted << std::endl; + std::cout << " Deleted: " << mIsDeleted << std::endl; } template<> @@ -478,7 +478,7 @@ void Record::print() std::cout << " Part: " << meshPartLabel(mData.mData.mPart) << " (" << (int)mData.mData.mPart << ")" << std::endl; std::cout << " Vampire: " << (int)mData.mData.mVampire << std::endl; - std::cout << " Deleted: " << mData.mIsDeleted << std::endl; + std::cout << " Deleted: " << mIsDeleted << std::endl; } template<> @@ -507,7 +507,7 @@ void Record::print() { std::cout << " Text: [skipped]" << std::endl; } - std::cout << " Deleted: " << mData.mIsDeleted << std::endl; + std::cout << " Deleted: " << mIsDeleted << std::endl; } template<> @@ -519,7 +519,7 @@ void Record::print() std::vector::iterator pit; for (pit = mData.mPowers.mList.begin(); pit != mData.mPowers.mList.end(); ++pit) std::cout << " Power: " << *pit << std::endl; - std::cout << " Deleted: " << mData.mIsDeleted << std::endl; + std::cout << " Deleted: " << mIsDeleted << std::endl; } template<> @@ -548,7 +548,7 @@ void Record::print() std::cout << " Map Color: " << boost::format("0x%08X") % mData.mMapColor << std::endl; std::cout << " Water Level Int: " << mData.mWaterInt << std::endl; std::cout << " RefId counter: " << mData.mRefNumCounter << std::endl; - std::cout << " Deleted: " << mData.mIsDeleted << std::endl; + std::cout << " Deleted: " << mIsDeleted << std::endl; } @@ -571,7 +571,7 @@ void Record::print() for (int i = 0; i != 5; i++) std::cout << " Major Skill: " << skillLabel(mData.mData.mSkills[i][1]) << " (" << mData.mData.mSkills[i][1] << ")" << std::endl; - std::cout << " Deleted: " << mData.mIsDeleted << std::endl; + std::cout << " Deleted: " << mIsDeleted << std::endl; } template<> @@ -598,7 +598,7 @@ void Record::print() if (pit->mFemale != "") std::cout << " Female Name: " << pit->mFemale << std::endl; } - std::cout << " Deleted: " << mData.mIsDeleted << std::endl; + std::cout << " Deleted: " << mIsDeleted << std::endl; } template<> @@ -614,7 +614,7 @@ void Record::print() for (cit = mData.mInventory.mList.begin(); cit != mData.mInventory.mList.end(); ++cit) std::cout << " Inventory: Count: " << boost::format("%4d") % cit->mCount << " Item: " << cit->mItem.toString() << std::endl; - std::cout << " Deleted: " << mData.mIsDeleted << std::endl; + std::cout << " Deleted: " << mIsDeleted << std::endl; } template<> @@ -681,7 +681,7 @@ void Record::print() std::vector::iterator pit; for (pit = mData.mAiPackage.mList.begin(); pit != mData.mAiPackage.mList.end(); ++pit) printAIPackage(*pit); - std::cout << " Deleted: " << mData.mIsDeleted << std::endl; + std::cout << " Deleted: " << mIsDeleted << std::endl; } template<> @@ -689,7 +689,7 @@ void Record::print() { std::cout << " Type: " << dialogTypeLabel(mData.mType) << " (" << (int)mData.mType << ")" << std::endl; - std::cout << " Deleted: " << mData.mIsDeleted << std::endl; + std::cout << " Deleted: " << mIsDeleted << std::endl; // Sadly, there are no DialInfos, because the loader dumps as it // loads, rather than loading and then dumping. :-( Anyone mind if // I change this? @@ -706,7 +706,7 @@ void Record::print() std::cout << " Script: " << mData.mScript << std::endl; std::cout << " OpenSound: " << mData.mOpenSound << std::endl; std::cout << " CloseSound: " << mData.mCloseSound << std::endl; - std::cout << " Deleted: " << mData.mIsDeleted << std::endl; + std::cout << " Deleted: " << mIsDeleted << std::endl; } template<> @@ -718,7 +718,7 @@ void Record::print() std::cout << " Charge: " << mData.mData.mCharge << std::endl; std::cout << " AutoCalc: " << mData.mData.mAutocalc << std::endl; printEffectList(mData.mEffects); - std::cout << " Deleted: " << mData.mIsDeleted << std::endl; + std::cout << " Deleted: " << mIsDeleted << std::endl; } template<> @@ -752,14 +752,14 @@ void Record::print() std::map::iterator rit; for (rit = mData.mReactions.begin(); rit != mData.mReactions.end(); ++rit) std::cout << " Reaction: " << rit->second << " = " << rit->first << std::endl; - std::cout << " Deleted: " << mData.mIsDeleted << std::endl; + std::cout << " Deleted: " << mIsDeleted << std::endl; } template<> void Record::print() { std::cout << " " << mData.mValue << std::endl; - std::cout << " Deleted: " << mData.mIsDeleted << std::endl; + std::cout << " Deleted: " << mIsDeleted << std::endl; } template<> @@ -826,7 +826,7 @@ void Record::print() std::cout << " Result Script: [skipped]" << std::endl; } } - std::cout << " Deleted: " << mData.mIsDeleted << std::endl; + std::cout << " Deleted: " << mIsDeleted << std::endl; } template<> @@ -850,7 +850,7 @@ void Record::print() std::cout << " Attribute: " << attributeLabel(mData.mData.mAttributes[i]) << " (" << mData.mData.mAttributes[i] << ")" << std::endl; } - std::cout << " Deleted: " << mData.mIsDeleted << std::endl; + std::cout << " Deleted: " << mIsDeleted << std::endl; } template<> @@ -873,7 +873,7 @@ void Record::print() std::cout << " Unknown2: " << mData.mLandData->mUnk2 << std::endl; } if (!wasLoaded) mData.unloadData(); - std::cout << " Deleted: " << mData.mIsDeleted << std::endl; + std::cout << " Deleted: " << mIsDeleted << std::endl; } template<> @@ -886,7 +886,7 @@ void Record::print() for (iit = mData.mList.begin(); iit != mData.mList.end(); ++iit) std::cout << " Creature: Level: " << iit->mLevel << " Creature: " << iit->mId << std::endl; - std::cout << " Deleted: " << mData.mIsDeleted << std::endl; + std::cout << " Deleted: " << mIsDeleted << std::endl; } template<> @@ -899,7 +899,7 @@ void Record::print() for (iit = mData.mList.begin(); iit != mData.mList.end(); ++iit) std::cout << " Inventory: Level: " << iit->mLevel << " Item: " << iit->mId << std::endl; - std::cout << " Deleted: " << mData.mIsDeleted << std::endl; + std::cout << " Deleted: " << mIsDeleted << std::endl; } template<> @@ -920,7 +920,7 @@ void Record::print() std::cout << " Duration: " << mData.mData.mTime << std::endl; std::cout << " Radius: " << mData.mData.mRadius << std::endl; std::cout << " Color: " << mData.mData.mColor << std::endl; - std::cout << " Deleted: " << mData.mIsDeleted << std::endl; + std::cout << " Deleted: " << mIsDeleted << std::endl; } template<> @@ -935,7 +935,7 @@ void Record::print() std::cout << " Value: " << mData.mData.mValue << std::endl; std::cout << " Quality: " << mData.mData.mQuality << std::endl; std::cout << " Uses: " << mData.mData.mUses << std::endl; - std::cout << " Deleted: " << mData.mIsDeleted << std::endl; + std::cout << " Deleted: " << mIsDeleted << std::endl; } template<> @@ -950,7 +950,7 @@ void Record::print() std::cout << " Value: " << mData.mData.mValue << std::endl; std::cout << " Quality: " << mData.mData.mQuality << std::endl; std::cout << " Uses: " << mData.mData.mUses << std::endl; - std::cout << " Deleted: " << mData.mIsDeleted << std::endl; + std::cout << " Deleted: " << mIsDeleted << std::endl; } template<> @@ -965,7 +965,7 @@ void Record::print() std::cout << " Value: " << mData.mData.mValue << std::endl; std::cout << " Quality: " << mData.mData.mQuality << std::endl; std::cout << " Uses: " << mData.mData.mUses << std::endl; - std::cout << " Deleted: " << mData.mIsDeleted << std::endl; + std::cout << " Deleted: " << mIsDeleted << std::endl; } template<> @@ -974,7 +974,7 @@ void Record::print() std::cout << " Id: " << mData.mId << std::endl; std::cout << " Index: " << mData.mIndex << std::endl; std::cout << " Texture: " << mData.mTexture << std::endl; - std::cout << " Deleted: " << mData.mIsDeleted << std::endl; + std::cout << " Deleted: " << mIsDeleted << std::endl; } template<> @@ -1025,7 +1025,7 @@ void Record::print() std::cout << " Weight: " << mData.mData.mWeight << std::endl; std::cout << " Value: " << mData.mData.mValue << std::endl; std::cout << " Is Key: " << mData.mData.mIsKey << std::endl; - std::cout << " Deleted: " << mData.mIsDeleted << std::endl; + std::cout << " Deleted: " << mIsDeleted << std::endl; } template<> @@ -1112,7 +1112,7 @@ void Record::print() for (pit = mData.mAiPackage.mList.begin(); pit != mData.mAiPackage.mList.end(); ++pit) printAIPackage(*pit); - std::cout << " Deleted: " << mData.mIsDeleted << std::endl; + std::cout << " Deleted: " << mIsDeleted << std::endl; } template<> @@ -1148,7 +1148,7 @@ void Record::print() i++; } - std::cout << " Deleted: " << mData.mIsDeleted << std::endl; + std::cout << " Deleted: " << mIsDeleted << std::endl; } template<> @@ -1190,7 +1190,7 @@ void Record::print() for (sit = mData.mPowers.mList.begin(); sit != mData.mPowers.mList.end(); ++sit) std::cout << " Power: " << *sit << std::endl; - std::cout << " Deleted: " << mData.mIsDeleted << std::endl; + std::cout << " Deleted: " << mIsDeleted << std::endl; } template<> @@ -1251,7 +1251,7 @@ void Record::print() std::cout << " Script: [skipped]" << std::endl; } - std::cout << " Deleted: " << mData.mIsDeleted << std::endl; + std::cout << " Deleted: " << mIsDeleted << std::endl; } template<> @@ -1275,7 +1275,7 @@ void Record::print() std::cout << " Sound: " << mData.mSound << std::endl; std::cout << " Type: " << soundTypeLabel(mData.mType) << " (" << mData.mType << ")" << std::endl; - std::cout << " Deleted: " << mData.mIsDeleted << std::endl; + std::cout << " Deleted: " << mIsDeleted << std::endl; } template<> @@ -1286,7 +1286,7 @@ void Record::print() if (mData.mData.mMinRange != 0 && mData.mData.mMaxRange != 0) std::cout << " Range: " << (int)mData.mData.mMinRange << " - " << (int)mData.mData.mMaxRange << std::endl; - std::cout << " Deleted: " << mData.mIsDeleted << std::endl; + std::cout << " Deleted: " << mIsDeleted << std::endl; } template<> @@ -1298,7 +1298,7 @@ void Record::print() std::cout << " Flags: " << spellFlags(mData.mData.mFlags) << std::endl; std::cout << " Cost: " << mData.mData.mCost << std::endl; printEffectList(mData.mEffects); - std::cout << " Deleted: " << mData.mIsDeleted << std::endl; + std::cout << " Deleted: " << mIsDeleted << std::endl; } template<> @@ -1306,7 +1306,7 @@ void Record::print() { std::cout << " Start Script: " << mData.mId << std::endl; std::cout << " Start Data: " << mData.mData << std::endl; - std::cout << " Deleted: " << mData.mIsDeleted << std::endl; + std::cout << " Deleted: " << mIsDeleted << std::endl; } template<> @@ -1347,7 +1347,7 @@ void Record::print() if (mData.mData.mThrust[0] != 0 && mData.mData.mThrust[1] != 0) std::cout << " Thrust: " << (int)mData.mData.mThrust[0] << "-" << (int)mData.mData.mThrust[1] << std::endl; - std::cout << " Deleted: " << mData.mIsDeleted << std::endl; + std::cout << " Deleted: " << mIsDeleted << std::endl; } template<> diff --git a/apps/esmtool/record.hpp b/apps/esmtool/record.hpp index a10fda40b..d0c113279 100644 --- a/apps/esmtool/record.hpp +++ b/apps/esmtool/record.hpp @@ -67,8 +67,13 @@ namespace EsmTool class Record : public RecordBase { T mData; + bool mIsDeleted; public: + Record() + : mIsDeleted(false) + {} + std::string getId() const { return mData.mId; } @@ -78,11 +83,11 @@ namespace EsmTool } void save(ESM::ESMWriter &esm) { - mData.save(esm); + mData.save(esm, mIsDeleted); } void load(ESM::ESMReader &esm) { - mData.load(esm); + mData.load(esm, mIsDeleted); } void print(); From 0c6ab6cc9449e14fe30d1f9baa3424b92eee9ba8 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Tue, 21 Jul 2015 21:49:36 +0300 Subject: [PATCH 1906/3725] Load methods (for ESM records) accept a deleted flag in ESSImporter --- apps/essimporter/converter.cpp | 4 +++- apps/essimporter/converter.hpp | 29 +++++++++++++++++++++------- apps/essimporter/importacdt.cpp | 3 ++- apps/essimporter/importinventory.cpp | 3 ++- 4 files changed, 29 insertions(+), 10 deletions(-) diff --git a/apps/essimporter/converter.cpp b/apps/essimporter/converter.cpp index 982753134..1d1942a3e 100644 --- a/apps/essimporter/converter.cpp +++ b/apps/essimporter/converter.cpp @@ -158,7 +158,9 @@ namespace ESSImport void ConvertCell::read(ESM::ESMReader &esm) { ESM::Cell cell; - cell.load(esm, false); + bool isDeleted = false; + + cell.load(esm, isDeleted, false); // I wonder what 0x40 does? if (cell.isExterior() && cell.mData.mFlags & 0x20) diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index 3bb5d2eae..1c6783539 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -54,6 +54,8 @@ public: void setContext(Context& context) { mContext = &context; } + /// @note The load method of ESM records accept the deleted flag as a parameter. + /// I don't know can the DELE sub-record appear in saved games, so the deleted flag will be ignored. virtual void read(ESM::ESMReader& esm) { } @@ -79,7 +81,9 @@ public: virtual void read(ESM::ESMReader& esm) { T record; - record.load(esm); + bool isDeleted = false; + + record.load(esm, isDeleted); mRecords[record.mId] = record; } @@ -103,7 +107,9 @@ public: virtual void read(ESM::ESMReader &esm) { ESM::NPC npc; - npc.load(esm); + bool isDeleted = false; + + npc.load(esm, isDeleted); if (npc.mId != "player") { // Handles changes to the NPC struct, but since there is no index here @@ -139,7 +145,9 @@ public: { // See comment in ConvertNPC ESM::Creature creature; - creature.load(esm); + bool isDeleted = false; + + creature.load(esm, isDeleted); mContext->mCreatures[Misc::StringUtils::lowerCase(creature.mId)] = creature; } }; @@ -154,7 +162,9 @@ public: virtual void read(ESM::ESMReader &esm) { ESM::Global global; - global.load(esm); + bool isDeleted = false; + + global.load(esm, isDeleted); if (Misc::StringUtils::ciEqual(global.mId, "gamehour")) mContext->mHour = global.mValue.getFloat(); if (Misc::StringUtils::ciEqual(global.mId, "day")) @@ -173,8 +183,9 @@ public: virtual void read(ESM::ESMReader &esm) { ESM::Class class_; - class_.load(esm); + bool isDeleted = false; + class_.load(esm, isDeleted); if (class_.mId == "NEWCLASSID_CHARGEN") mContext->mCustomPlayerClassName = class_.mName; @@ -188,7 +199,9 @@ public: virtual void read(ESM::ESMReader &esm) { ESM::Book book; - book.load(esm); + bool isDeleted = false; + + book.load(esm, isDeleted); if (book.mData.mSkillID == -1) mContext->mPlayer.mObject.mNpcStats.mUsedIds.push_back(Misc::StringUtils::lowerCase(book.mId)); @@ -365,7 +378,9 @@ public: virtual void read(ESM::ESMReader& esm) { ESM::Faction faction; - faction.load(esm); + bool isDeleted = false; + + faction.load(esm, isDeleted); std::string id = Misc::StringUtils::toLower(faction.mId); for (std::map::const_iterator it = faction.mReactions.begin(); it != faction.mReactions.end(); ++it) diff --git a/apps/essimporter/importacdt.cpp b/apps/essimporter/importacdt.cpp index 9d881515d..1602aa784 100644 --- a/apps/essimporter/importacdt.cpp +++ b/apps/essimporter/importacdt.cpp @@ -18,7 +18,8 @@ namespace ESSImport if (esm.isNextSub("MNAM")) esm.skipHSub(); - ESM::CellRef::loadData(esm); + bool isDeleted = false; + ESM::CellRef::loadData(esm, isDeleted); mHasACDT = false; if (esm.isNextSub("ACDT")) diff --git a/apps/essimporter/importinventory.cpp b/apps/essimporter/importinventory.cpp index d27cd5c8c..3ec640d3d 100644 --- a/apps/essimporter/importinventory.cpp +++ b/apps/essimporter/importinventory.cpp @@ -32,7 +32,8 @@ namespace ESSImport item.mSCRI.load(esm); // for XSOL and XCHG seen so far, but probably others too - item.ESM::CellRef::loadData(esm); + bool isDeleted = false; + item.ESM::CellRef::loadData(esm, isDeleted); int charge=-1; esm.getHNOT(charge, "XHLT"); From daaff1284e26d13358b130d7b44721ced210066d Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Wed, 22 Jul 2015 22:02:01 +0300 Subject: [PATCH 1907/3725] Remove unused includes --- apps/opencs/model/world/idcollection.hpp | 1 - apps/openmw/mwworld/store.cpp | 1 - components/esm/loaddial.hpp | 1 - components/esm/util.hpp | 5 ----- 4 files changed, 8 deletions(-) diff --git a/apps/opencs/model/world/idcollection.hpp b/apps/opencs/model/world/idcollection.hpp index c79b4e020..ea6eefb88 100644 --- a/apps/opencs/model/world/idcollection.hpp +++ b/apps/opencs/model/world/idcollection.hpp @@ -4,7 +4,6 @@ #include #include "collection.hpp" -#include "record.hpp" namespace CSMWorld { diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index cd9290bfc..a8b0af88a 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -3,7 +3,6 @@ #include #include -#include #include #include diff --git a/components/esm/loaddial.hpp b/components/esm/loaddial.hpp index e517fc86f..b80cbd74c 100644 --- a/components/esm/loaddial.hpp +++ b/components/esm/loaddial.hpp @@ -4,7 +4,6 @@ #include #include #include -#include #include "loadinfo.hpp" diff --git a/components/esm/util.hpp b/components/esm/util.hpp index e16603b84..a80df2456 100644 --- a/components/esm/util.hpp +++ b/components/esm/util.hpp @@ -1,14 +1,9 @@ #ifndef OPENMW_ESM_UTIL_H #define OPENMW_ESM_UTIL_H -#include - #include #include -#include "esmreader.hpp" -#include "esmwriter.hpp" - namespace ESM { From 8286dc6c5aaa2f9f5c6c5aff4644f93d9bbdcdb0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 19 Jul 2015 16:37:19 +0200 Subject: [PATCH 1908/3725] Player followers don't report crimes (Fixes #2457) --- .../mwmechanics/mechanicsmanagerimp.cpp | 30 +++++++++++++++---- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index e9ef99454..07fa6d592 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1049,6 +1049,19 @@ namespace MWMechanics commitCrime(ptr, victim, OT_Theft, item.getClass().getValue(item) * count); } + + void getFollowers (const MWWorld::Ptr& actor, std::set& out) + { + std::list followers = MWBase::Environment::get().getMechanicsManager()->getActorsFollowing(actor); + for(std::list::iterator it = followers.begin();it != followers.end();++it) + { + if (out.insert(*it).second) + { + getFollowers(*it, out); + } + } + } + bool MechanicsManager::commitCrime(const MWWorld::Ptr &player, const MWWorld::Ptr &victim, OffenseType type, int arg, bool victimAware) { // NOTE: victim may be empty @@ -1070,6 +1083,10 @@ namespace MWMechanics if (!victim.isEmpty() && (from - victim.getRefData().getPosition().asVec3()).length2() > radius*radius) neighbors.push_back(victim); + // get the player's followers / allies (works recursively) that will not report crimes + std::set playerFollowers; + getFollowers(player, playerFollowers); + // Did anyone see it? bool crimeSeen = false; for (std::vector::iterator it = neighbors.begin(); it != neighbors.end(); ++it) @@ -1085,11 +1102,6 @@ namespace MWMechanics // TODO: Add mod support for stealth executions! || (type == OT_Murder && *it != victim)) { - if (type == OT_Theft || type == OT_Pickpocket) - MWBase::Environment::get().getDialogueManager()->say(*it, "thief"); - else if (type == OT_Trespassing) - MWBase::Environment::get().getDialogueManager()->say(*it, "intruder"); - // Crime reporting only applies to NPCs if (!it->getClass().isNpc()) continue; @@ -1097,6 +1109,14 @@ namespace MWMechanics if (it->getClass().getCreatureStats(*it).getAiSequence().isInCombat(victim)) continue; + if (playerFollowers.find(*it) != playerFollowers.end()) + continue; + + if (type == OT_Theft || type == OT_Pickpocket) + MWBase::Environment::get().getDialogueManager()->say(*it, "thief"); + else if (type == OT_Trespassing) + MWBase::Environment::get().getDialogueManager()->say(*it, "intruder"); + crimeSeen = true; } } From 7900631d51be62726598bd70177b182b0992783c Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 19 Jul 2015 16:39:22 +0200 Subject: [PATCH 1909/3725] Print the missing player cell to error output --- apps/openmw/mwworld/player.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index b17b8e1f0..d3c0110ac 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -1,7 +1,7 @@ - #include "player.hpp" #include +#include #include #include @@ -19,7 +19,6 @@ #include "../mwmechanics/movement.hpp" #include "../mwmechanics/npcstats.hpp" -#include "../mwmechanics/actors.hpp" #include "class.hpp" #include "ptr.hpp" @@ -327,6 +326,7 @@ namespace MWWorld } catch (...) { + std::cerr << "Player cell '" << player.mCellId.mWorldspace << "' no longer exists" << std::endl; // Cell no longer exists. Place the player in a default cell. ESM::Position pos = mPlayer.mData.getPosition(); MWBase::Environment::get().getWorld()->indexToPosition(0, 0, pos.pos[0], pos.pos[1], true); From 7e4e59efb9640135d2ea265f458cfd1cbb6425d6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 23 Jul 2015 02:28:38 +0200 Subject: [PATCH 1910/3725] Fix excessive auto-equipping in InventoryStore::removeItem (Fixes #2792) --- apps/openmw/mwworld/inventorystore.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 6c283bb3e..2fe914a4e 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -490,6 +490,7 @@ int MWWorld::InventoryStore::remove(const Ptr& item, int count, const Ptr& actor { int retCount = ContainerStore::remove(item, count, actor); + bool wasEquipped = false; if (!item.getRefData().getCount()) { for (int slot=0; slot < MWWorld::InventoryStore::Slots; ++slot) @@ -500,6 +501,7 @@ int MWWorld::InventoryStore::remove(const Ptr& item, int count, const Ptr& actor if (*mSlots[slot] == item) { unequipSlot(slot, actor); + wasEquipped = true; break; } } @@ -507,7 +509,7 @@ int MWWorld::InventoryStore::remove(const Ptr& item, int count, const Ptr& actor // If an armor/clothing item is removed, try to find a replacement, // but not for the player nor werewolves. - if ((actor != MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (wasEquipped && (actor != MWBase::Environment::get().getWorld()->getPlayerPtr()) && !(actor.getClass().isNpc() && actor.getClass().getNpcStats(actor).isWerewolf())) { std::string type = item.getTypeName(); From a7b3248ee7a042d4c481c8215ab850cfb9891dc1 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Thu, 23 Jul 2015 20:35:16 +0300 Subject: [PATCH 1911/3725] Proper sorting of columns with enum values --- apps/opencs/model/world/idtableproxymodel.cpp | 14 ++++++++++++++ apps/opencs/model/world/idtableproxymodel.hpp | 7 +++++++ 2 files changed, 21 insertions(+) diff --git a/apps/opencs/model/world/idtableproxymodel.cpp b/apps/opencs/model/world/idtableproxymodel.cpp index 516644713..1f8f2e4b4 100644 --- a/apps/opencs/model/world/idtableproxymodel.cpp +++ b/apps/opencs/model/world/idtableproxymodel.cpp @@ -60,6 +60,20 @@ void CSMWorld::IdTableProxyModel::setFilter (const boost::shared_ptr(left.data(ColumnBase::Role_ColumnId).toInt()); + EnumColumnCache::const_iterator valuesIt = mEnumColumnCache.find(id); + if (valuesIt == mEnumColumnCache.end()) + { + if (Columns::hasEnums(id)) + { + valuesIt = mEnumColumnCache.insert(std::make_pair(id, Columns::getEnums(id))).first; + } + } + + if (valuesIt != mEnumColumnCache.end()) + { + return valuesIt->second[left.data().toInt()] < valuesIt->second[right.data().toInt()]; + } return QSortFilterProxyModel::lessThan(left, right); } diff --git a/apps/opencs/model/world/idtableproxymodel.hpp b/apps/opencs/model/world/idtableproxymodel.hpp index d2a240529..decad157c 100644 --- a/apps/opencs/model/world/idtableproxymodel.hpp +++ b/apps/opencs/model/world/idtableproxymodel.hpp @@ -11,6 +11,8 @@ #include "../filter/node.hpp" +#include "columns.hpp" + namespace CSMWorld { class IdTableProxyModel : public QSortFilterProxyModel @@ -20,6 +22,11 @@ namespace CSMWorld boost::shared_ptr mFilter; std::map mColumnMap; // column ID, column index in this model (or -1) + // Cache of enum values for enum columns (e.g. Modified, Record Type). + // Used to speed up comparisons during the sort by such columns. + typedef std::map > EnumColumnCache; + mutable EnumColumnCache mEnumColumnCache; + private: void updateColumnMap(); From f5b1447c9226adb89db38ea52b7435d4e2072cc6 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Thu, 23 Jul 2015 21:05:00 +0300 Subject: [PATCH 1912/3725] IdTableProxyModel refreshes the filter when the source model data or rows changed --- apps/opencs/model/world/idtableproxymodel.cpp | 28 +++++++++++++++++++ apps/opencs/model/world/idtableproxymodel.hpp | 8 ++++++ apps/opencs/view/world/table.cpp | 4 --- 3 files changed, 36 insertions(+), 4 deletions(-) diff --git a/apps/opencs/model/world/idtableproxymodel.cpp b/apps/opencs/model/world/idtableproxymodel.cpp index 1f8f2e4b4..ce9d44ed6 100644 --- a/apps/opencs/model/world/idtableproxymodel.cpp +++ b/apps/opencs/model/world/idtableproxymodel.cpp @@ -50,6 +50,24 @@ QModelIndex CSMWorld::IdTableProxyModel::getModelIndex (const std::string& id, i return mapFromSource (dynamic_cast (*sourceModel()).getModelIndex (id, column)); } +void CSMWorld::IdTableProxyModel::setSourceModel(QAbstractItemModel *model) +{ + QSortFilterProxyModel::setSourceModel(model); + + connect(sourceModel(), + SIGNAL(rowsRemoved(const QModelIndex &, int, int)), + this, + SLOT(sourceRowsChanged(const QModelIndex &, int, int))); + connect(sourceModel(), + SIGNAL(rowsInserted(const QModelIndex &, int, int)), + this, + SLOT(sourceRowsChanged(const QModelIndex &, int, int))); + connect(sourceModel(), + SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), + this, + SLOT(sourceDataChanged(const QModelIndex &, const QModelIndex &))); +} + void CSMWorld::IdTableProxyModel::setFilter (const boost::shared_ptr& filter) { beginResetModel(); @@ -82,3 +100,13 @@ void CSMWorld::IdTableProxyModel::refreshFilter() updateColumnMap(); invalidateFilter(); } + +void CSMWorld::IdTableProxyModel::sourceRowsChanged(const QModelIndex &/*parent*/, int /*start*/, int /*end*/) +{ + refreshFilter(); +} + +void CSMWorld::IdTableProxyModel::sourceDataChanged(const QModelIndex &/*topLeft*/, const QModelIndex &/*bottomRight*/) +{ + refreshFilter(); +} diff --git a/apps/opencs/model/world/idtableproxymodel.hpp b/apps/opencs/model/world/idtableproxymodel.hpp index decad157c..17c30361a 100644 --- a/apps/opencs/model/world/idtableproxymodel.hpp +++ b/apps/opencs/model/world/idtableproxymodel.hpp @@ -37,6 +37,8 @@ namespace CSMWorld virtual QModelIndex getModelIndex (const std::string& id, int column) const; + virtual void setSourceModel(QAbstractItemModel *model); + void setFilter (const boost::shared_ptr& filter); void refreshFilter(); @@ -46,6 +48,12 @@ namespace CSMWorld bool lessThan(const QModelIndex &left, const QModelIndex &right) const; virtual bool filterAcceptsRow (int sourceRow, const QModelIndex& sourceParent) const; + + private slots: + + void sourceRowsChanged(const QModelIndex &parent, int start, int end); + + void sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight); }; } diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index 74343a5f6..5a2a572e2 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -653,10 +653,6 @@ void CSVWorld::Table::tableSizeUpdate() } emit tableSizeChanged (size, deleted, modified); - - // not really related to tableSizeUpdate() but placed here for convenience rather than - // creating a bunch of extra connections & slot - mProxyModel->refreshFilter(); } void CSVWorld::Table::selectionSizeUpdate() From 6d2d32485fa051260dfe3643786891d070f21480 Mon Sep 17 00:00:00 2001 From: Rohit Nirmal Date: Thu, 23 Jul 2015 22:22:22 -0500 Subject: [PATCH 1913/3725] Fix building OpenCS with Qt 5. --- apps/opencs/view/world/scripterrortable.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/opencs/view/world/scripterrortable.cpp b/apps/opencs/view/world/scripterrortable.cpp index 3e80c5bd4..415e6c9dc 100644 --- a/apps/opencs/view/world/scripterrortable.cpp +++ b/apps/opencs/view/world/scripterrortable.cpp @@ -76,8 +76,13 @@ CSVWorld::ScriptErrorTable::ScriptErrorTable (const CSMDoc::Document& document, QStringList headers; headers << "Severity" << "Line" << "Description"; setHorizontalHeaderLabels (headers); +#if QT_VERSION >= QT_VERSION_CHECK(5,0,0) + horizontalHeader()->setSectionResizeMode (0, QHeaderView::ResizeToContents); + horizontalHeader()->setSectionResizeMode (1, QHeaderView::ResizeToContents); +#else horizontalHeader()->setResizeMode (0, QHeaderView::ResizeToContents); horizontalHeader()->setResizeMode (1, QHeaderView::ResizeToContents); +#endif horizontalHeader()->setStretchLastSection (true); verticalHeader()->hide(); setColumnHidden (3, true); From 71bc22401f103532e8ad4eec3b0a8140f60226f3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 24 Jul 2015 18:23:23 +0200 Subject: [PATCH 1914/3725] Include cleanup --- apps/openmw/mwworld/actioneat.cpp | 2 -- apps/openmw/mwworld/worldimp.cpp | 4 +--- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/apps/openmw/mwworld/actioneat.cpp b/apps/openmw/mwworld/actioneat.cpp index 660915523..8bb80b564 100644 --- a/apps/openmw/mwworld/actioneat.cpp +++ b/apps/openmw/mwworld/actioneat.cpp @@ -1,8 +1,6 @@ #include "actioneat.hpp" -#include - #include #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 8011f81ce..15c8cbeb2 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -14,13 +14,11 @@ #include #include +#include #include #include -#include -#include -#include #include #include From 7f66339790a8f25aedeb610cb792ad043af8caf6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 24 Jul 2015 20:23:27 +0200 Subject: [PATCH 1915/3725] Remove a redundant function --- apps/openmw/mwclass/creature.cpp | 26 ++++---------------------- apps/openmw/mwclass/creature.hpp | 2 -- apps/openmw/mwclass/npc.cpp | 25 +++---------------------- apps/openmw/mwclass/npc.hpp | 2 -- apps/openmw/mwmechanics/actors.cpp | 4 +++- apps/openmw/mwworld/class.cpp | 5 ----- apps/openmw/mwworld/class.hpp | 6 ------ 7 files changed, 10 insertions(+), 60 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index f312a41c7..8b7bcf6b9 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -394,8 +394,10 @@ namespace MWClass damage = scaleDamage(damage, attacker, ptr); MWBase::Environment::get().getSoundManager()->playSound3D(ptr, "Health Damage", 1.0f, 1.0f); - float health = getCreatureStats(ptr).getHealth().getCurrent() - damage; - setActorHealth(ptr, health, attacker); + + MWMechanics::DynamicStat health(getCreatureStats(ptr).getHealth()); + health.setCurrent(health.getCurrent() - damage); + getCreatureStats(ptr).setHealth(health); } else { @@ -430,26 +432,6 @@ namespace MWClass } } - void Creature::setActorHealth(const MWWorld::Ptr& ptr, float health, const MWWorld::Ptr& attacker) const - { - MWMechanics::CreatureStats &crstats = getCreatureStats(ptr); - bool wasDead = crstats.isDead(); - - MWMechanics::DynamicStat stat(crstats.getHealth()); - stat.setCurrent(health); - crstats.setHealth(stat); - - if(!wasDead && crstats.isDead()) - { - // actor was just killed - } - else if(wasDead && !crstats.isDead()) - { - // actor was just resurrected - } - } - - boost::shared_ptr Creature::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const { diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index 740552a60..b2a333beb 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -72,8 +72,6 @@ namespace MWClass virtual void onHit(const MWWorld::Ptr &ptr, float damage, bool ishealth, const MWWorld::Ptr &object, const MWWorld::Ptr &attacker, bool successful) const; - virtual void setActorHealth(const MWWorld::Ptr& ptr, float health, const MWWorld::Ptr& attacker) const; - virtual boost::shared_ptr activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const; ///< Generate action for activation diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index d0dd9f994..75b612dad 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -733,8 +733,9 @@ namespace MWClass if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) MWBase::Environment::get().getWindowManager()->activateHitOverlay(); } - float health = getCreatureStats(ptr).getHealth().getCurrent() - damage; - setActorHealth(ptr, health, attacker); + MWMechanics::DynamicStat health(getCreatureStats(ptr).getHealth()); + health.setCurrent(health.getCurrent() - damage); + getCreatureStats(ptr).setHealth(health); } else { @@ -779,26 +780,6 @@ namespace MWClass } } - void Npc::setActorHealth(const MWWorld::Ptr& ptr, float health, const MWWorld::Ptr& attacker) const - { - MWMechanics::CreatureStats &crstats = getCreatureStats(ptr); - bool wasDead = crstats.isDead(); - - MWMechanics::DynamicStat stat(crstats.getHealth()); - stat.setCurrent(health); - crstats.setHealth(stat); - - if(!wasDead && crstats.isDead()) - { - // actor was just killed - } - else if(wasDead && !crstats.isDead()) - { - // actor was just resurrected - } - } - - boost::shared_ptr Npc::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const { diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index f032ae77c..b12b7b13f 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -87,8 +87,6 @@ namespace MWClass virtual void block(const MWWorld::Ptr &ptr) const; - virtual void setActorHealth(const MWWorld::Ptr& ptr, float health, const MWWorld::Ptr& attacker) const; - virtual boost::shared_ptr activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const; ///< Generate action for activation diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 14561b4bb..c135811dd 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -699,7 +699,9 @@ namespace MWMechanics { // If drowning, apply 3 points of damage per second static const float fSuffocationDamage = world->getStore().get().find("fSuffocationDamage")->getFloat(); - ptr.getClass().setActorHealth(ptr, stats.getHealth().getCurrent() - fSuffocationDamage*duration); + DynamicStat health = stats.getHealth(); + health.setCurrent(health.getCurrent() - fSuffocationDamage*duration); + stats.setHealth(health); // Play a drowning sound MWBase::SoundManager *sndmgr = MWBase::Environment::get().getSoundManager(); diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 5ec2d4e16..180cba332 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -109,11 +109,6 @@ namespace MWWorld throw std::runtime_error("class cannot be hit"); } - void Class::setActorHealth(const Ptr& ptr, float health, const Ptr& attacker) const - { - throw std::runtime_error("class does not have actor health"); - } - boost::shared_ptr Class::activate (const Ptr& ptr, const Ptr& actor) const { return boost::shared_ptr (new NullAction); diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 3f091380f..cd05b471b 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -136,12 +136,6 @@ namespace MWWorld ///< Play the appropriate sound for a blocked attack, depending on the currently equipped shield /// (default implementation: throw an exception) - virtual void setActorHealth(const Ptr& ptr, float health, const Ptr& attacker=Ptr()) const; - ///< Sets a new current health value for the actor, optionally specifying the object causing - /// the change. Use this instead of using CreatureStats directly as this will make sure the - /// correct dialog and actor states are properly handled when being hurt or healed. - /// (default implementation: throw an exception) - virtual boost::shared_ptr activate (const Ptr& ptr, const Ptr& actor) const; ///< Generate action for activation (default implementation: return a null action). From 47922f6c35a9f88374ff0f6301b5706f43e3e9af Mon Sep 17 00:00:00 2001 From: Pawel Kubik Date: Fri, 24 Jul 2015 21:54:58 +0200 Subject: [PATCH 1916/3725] Changed a settings variable responsible for number of loaded exterior cells. --- apps/openmw/mwworld/scene.cpp | 2 +- files/settings-default.cfg | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 8029cb773..13e6593e5 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -327,7 +327,7 @@ namespace MWWorld std::string loadingExteriorText = "#{sLoadingMessage3}"; loadingListener->setLabel(loadingExteriorText); - const int halfGridSize = Settings::Manager::getInt("exterior grid size", "Cells")/2; + const int halfGridSize = Settings::Manager::getInt("exterior cell load distance", "Cells"); CellStoreCollection::iterator active = mActiveCells.begin(); while (active!=mActiveCells.end()) diff --git a/files/settings-default.cfg b/files/settings-default.cfg index dcb9b8893..0f7349eb9 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -101,7 +101,7 @@ local map widget size = 512 local map hud widget size = 256 [Cells] -exterior grid size = 3 +exterior cell load distance = 1 [Camera] near clip = 5 From 4f6e5345ccd831169bfec8432cebce6f125942a1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 24 Jul 2015 23:28:36 +0200 Subject: [PATCH 1917/3725] Include cleanup --- apps/openmw/mwworld/cellstore.hpp | 1 - apps/openmw/mwworld/manualref.cpp | 1 - apps/openmw/mwworld/player.cpp | 1 - apps/openmw/mwworld/scene.cpp | 5 +---- apps/openmw/mwworld/store.cpp | 1 - 5 files changed, 1 insertion(+), 8 deletions(-) diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index f879343d9..fd3f364e9 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -10,7 +10,6 @@ #include "livecellref.hpp" #include "cellreflist.hpp" -#include #include #include "../mwmechanics/pathgrid.hpp" // TODO: maybe belongs in mwworld diff --git a/apps/openmw/mwworld/manualref.cpp b/apps/openmw/mwworld/manualref.cpp index b926c5799..d6e40ad09 100644 --- a/apps/openmw/mwworld/manualref.cpp +++ b/apps/openmw/mwworld/manualref.cpp @@ -1,7 +1,6 @@ #include "manualref.hpp" #include "esmstore.hpp" -#include "cellstore.hpp" namespace { diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index d3c0110ac..6bfdd2986 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -22,7 +22,6 @@ #include "class.hpp" #include "ptr.hpp" -#include "inventorystore.hpp" #include "cellstore.hpp" namespace MWWorld diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 8029cb773..1c51d4570 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -1,15 +1,12 @@ #include "scene.hpp" #include +#include -#include #include #include #include #include -#include - -#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index d873ab468..29187f950 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -1,5 +1,4 @@ #include "store.hpp" -#include "esmstore.hpp" #include #include From 3f3c3d0ad354b12309a6f023d8885fee61a3cd50 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 24 Jul 2015 23:28:43 +0200 Subject: [PATCH 1918/3725] Remove an already resolved todo comment --- apps/openmw/mwworld/inventorystore.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/openmw/mwworld/inventorystore.hpp b/apps/openmw/mwworld/inventorystore.hpp index a60d1f464..95c16c115 100644 --- a/apps/openmw/mwworld/inventorystore.hpp +++ b/apps/openmw/mwworld/inventorystore.hpp @@ -87,7 +87,6 @@ namespace MWWorld float mMultiplier; }; - // TODO: store in savegame typedef std::map > TEffectMagnitudes; TEffectMagnitudes mPermanentMagicEffectMagnitudes; From e6b28d84f0b58317a73ec6b20964da8bb9f76dfa Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 25 Jul 2015 00:28:47 +0200 Subject: [PATCH 1919/3725] Outdated comment fix --- apps/openmw/mwmechanics/aicombat.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 6a39178ce..f0bb198a0 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -20,7 +20,7 @@ #include "creaturestats.hpp" #include "steering.hpp" #include "movement.hpp" -#include "character.hpp" // fixme: for getActiveWeapon +#include "character.hpp" #include "aicombataction.hpp" #include "combat.hpp" @@ -291,7 +291,7 @@ namespace MWMechanics // Get weapon characteristics if (actorClass.hasInventoryStore(actor)) { - //Get weapon speed and range + //Get weapon range MWWorld::ContainerStoreIterator weaponSlot = MWMechanics::getActiveWeapon(actorClass.getCreatureStats(actor), actorClass.getInventoryStore(actor), &weaptype); From b3f5ac5dbb227233bb88cd1cc9b7d996abecfc20 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 25 Jul 2015 01:48:34 +0200 Subject: [PATCH 1920/3725] Include cleanup --- apps/opencs/model/world/refidadapterimp.hpp | 1 - apps/openmw/mwmechanics/aiactivate.cpp | 1 - apps/openmw/mwmechanics/aiavoiddoor.cpp | 3 +-- apps/openmw/mwmechanics/aicombat.cpp | 5 ----- apps/openmw/mwmechanics/aiescort.cpp | 1 - apps/openmw/mwmechanics/aifollow.cpp | 2 -- components/compiler/fileparser.cpp | 2 -- components/esmterrain/storage.cpp | 2 -- components/files/constrainedfilestream.cpp | 1 - components/interpreter/interpreter.cpp | 1 - components/nifbullet/bulletnifloader.cpp | 1 - components/sceneutil/attach.cpp | 1 - components/sceneutil/lightmanager.cpp | 5 ++--- components/terrain/material.cpp | 2 -- 14 files changed, 3 insertions(+), 25 deletions(-) diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index 869996da5..4066b5646 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -2,7 +2,6 @@ #define CSM_WOLRD_REFIDADAPTERIMP_H #include -#include #include diff --git a/apps/openmw/mwmechanics/aiactivate.cpp b/apps/openmw/mwmechanics/aiactivate.cpp index b0621c805..8761ca37f 100644 --- a/apps/openmw/mwmechanics/aiactivate.cpp +++ b/apps/openmw/mwmechanics/aiactivate.cpp @@ -8,7 +8,6 @@ #include "../mwmechanics/creaturestats.hpp" #include "../mwworld/class.hpp" -#include "../mwworld/cellstore.hpp" #include "steering.hpp" #include "movement.hpp" diff --git a/apps/openmw/mwmechanics/aiavoiddoor.cpp b/apps/openmw/mwmechanics/aiavoiddoor.cpp index 457c9a95c..b3aa346ce 100644 --- a/apps/openmw/mwmechanics/aiavoiddoor.cpp +++ b/apps/openmw/mwmechanics/aiavoiddoor.cpp @@ -1,10 +1,9 @@ #include "aiavoiddoor.hpp" -#include + #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/mechanicsmanager.hpp" #include "../mwworld/class.hpp" -#include "../mwworld/cellstore.hpp" #include "creaturestats.hpp" #include "movement.hpp" diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index f0bb198a0..b2f938b9e 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -5,18 +5,13 @@ #include #include "../mwworld/class.hpp" -#include "../mwworld/timestamp.hpp" -#include "../mwworld/inventorystore.hpp" #include "../mwworld/esmstore.hpp" -#include "../mwworld/cellstore.hpp" #include "../mwbase/environment.hpp" -#include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/dialoguemanager.hpp" #include "../mwrender/animation.hpp" - #include "creaturestats.hpp" #include "steering.hpp" #include "movement.hpp" diff --git a/apps/openmw/mwmechanics/aiescort.cpp b/apps/openmw/mwmechanics/aiescort.cpp index 593f9f173..f75fc22ad 100644 --- a/apps/openmw/mwmechanics/aiescort.cpp +++ b/apps/openmw/mwmechanics/aiescort.cpp @@ -6,7 +6,6 @@ #include "../mwbase/environment.hpp" #include "../mwbase/mechanicsmanager.hpp" -#include "../mwworld/cellstore.hpp" #include "../mwworld/class.hpp" #include "../mwmechanics/creaturestats.hpp" diff --git a/apps/openmw/mwmechanics/aifollow.cpp b/apps/openmw/mwmechanics/aifollow.cpp index a92e9eedc..8e111be61 100644 --- a/apps/openmw/mwmechanics/aifollow.cpp +++ b/apps/openmw/mwmechanics/aifollow.cpp @@ -1,7 +1,5 @@ #include "aifollow.hpp" -#include - #include #include "../mwbase/world.hpp" diff --git a/components/compiler/fileparser.cpp b/components/compiler/fileparser.cpp index 423841ac3..c8a512340 100644 --- a/components/compiler/fileparser.cpp +++ b/components/compiler/fileparser.cpp @@ -1,7 +1,5 @@ #include "fileparser.hpp" -#include - #include "tokenloc.hpp" #include "scanner.hpp" diff --git a/components/esmterrain/storage.cpp b/components/esmterrain/storage.cpp index 1811f58e6..10b75bb74 100644 --- a/components/esmterrain/storage.cpp +++ b/components/esmterrain/storage.cpp @@ -5,8 +5,6 @@ #include #include -#include - #include #include diff --git a/components/files/constrainedfilestream.cpp b/components/files/constrainedfilestream.cpp index 3e5d0c245..cd9a3c8f5 100644 --- a/components/files/constrainedfilestream.cpp +++ b/components/files/constrainedfilestream.cpp @@ -1,7 +1,6 @@ #include "constrainedfilestream.hpp" #include -#include #include "lowlevelfile.hpp" diff --git a/components/interpreter/interpreter.cpp b/components/interpreter/interpreter.cpp index ea1e9fc91..f5dee0dba 100644 --- a/components/interpreter/interpreter.cpp +++ b/components/interpreter/interpreter.cpp @@ -2,7 +2,6 @@ #include "interpreter.hpp" #include -#include #include #include diff --git a/components/nifbullet/bulletnifloader.cpp b/components/nifbullet/bulletnifloader.cpp index adf961dc2..2496c68cd 100644 --- a/components/nifbullet/bulletnifloader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -3,7 +3,6 @@ #include #include #include -#include #include #include diff --git a/components/sceneutil/attach.cpp b/components/sceneutil/attach.cpp index 2432b5eb2..d8cfa428a 100644 --- a/components/sceneutil/attach.cpp +++ b/components/sceneutil/attach.cpp @@ -1,7 +1,6 @@ #include "attach.hpp" #include -#include #include #include diff --git a/components/sceneutil/lightmanager.cpp b/components/sceneutil/lightmanager.cpp index 039d556d1..07ec0aff6 100644 --- a/components/sceneutil/lightmanager.cpp +++ b/components/sceneutil/lightmanager.cpp @@ -1,5 +1,7 @@ #include "lightmanager.hpp" +#include + #include #include @@ -9,9 +11,6 @@ #include -#include -#include - namespace SceneUtil { diff --git a/components/terrain/material.cpp b/components/terrain/material.cpp index 2034883ed..df45b6ec2 100644 --- a/components/terrain/material.cpp +++ b/components/terrain/material.cpp @@ -1,7 +1,5 @@ #include "material.hpp" -#include - #include #include #include From 3bca3e73d439b3202ce86853ad061c68d25c7fbf Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 25 Jul 2015 02:11:59 +0200 Subject: [PATCH 1921/3725] Fix GetWeaponDrawn and GetSpellReadied script functions for creatures --- apps/openmw/mwscript/miscextensions.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 8409351aa..9a9127977 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -567,7 +567,8 @@ namespace MWScript { MWWorld::Ptr ptr = R()(runtime); - runtime.push(ptr.getClass().getNpcStats (ptr).getDrawState () == MWMechanics::DrawState_Weapon); + runtime.push((ptr.getClass().hasInventoryStore(ptr) || ptr.getClass().isBipedal(ptr)) && + ptr.getClass().getCreatureStats (ptr).getDrawState () == MWMechanics::DrawState_Weapon); } }; @@ -580,7 +581,7 @@ namespace MWScript { MWWorld::Ptr ptr = R()(runtime); - runtime.push(ptr.getClass().getNpcStats (ptr).getDrawState () == MWMechanics::DrawState_Spell); + runtime.push(ptr.getClass().getCreatureStats (ptr).getDrawState () == MWMechanics::DrawState_Spell); } }; From 278076e609573ac4c0367a5f4f9d6693c01a2a73 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 25 Jul 2015 04:14:22 +0200 Subject: [PATCH 1922/3725] Include cleanup --- apps/openmw/mwmechanics/aifollow.cpp | 1 + apps/openmw/mwmechanics/aipackage.cpp | 5 ++++- apps/openmw/mwmechanics/aipursue.cpp | 2 +- apps/openmw/mwmechanics/aisequence.cpp | 6 ++---- apps/openmw/mwmechanics/aitravel.cpp | 1 + apps/openmw/mwmechanics/obstacle.cpp | 2 ++ apps/openmw/mwrender/localmap.cpp | 1 + apps/openmw/mwrender/water.cpp | 2 ++ apps/openmw/mwworld/cellstore.hpp | 22 +++++++++++++++++++++- 9 files changed, 35 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwmechanics/aifollow.cpp b/apps/openmw/mwmechanics/aifollow.cpp index 8e111be61..cd67c6058 100644 --- a/apps/openmw/mwmechanics/aifollow.cpp +++ b/apps/openmw/mwmechanics/aifollow.cpp @@ -1,6 +1,7 @@ #include "aifollow.hpp" #include +#include #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index 0e68d9d79..77efe62a8 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -1,7 +1,10 @@ - #include "aipackage.hpp" #include + +#include +#include + #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" #include "../mwworld/class.hpp" diff --git a/apps/openmw/mwmechanics/aipursue.cpp b/apps/openmw/mwmechanics/aipursue.cpp index ac6b23ef6..e936505c9 100644 --- a/apps/openmw/mwmechanics/aipursue.cpp +++ b/apps/openmw/mwmechanics/aipursue.cpp @@ -1,12 +1,12 @@ #include "aipursue.hpp" #include +#include #include "../mwbase/environment.hpp" #include "../mwworld/class.hpp" #include "../mwworld/action.hpp" -#include "../mwworld/cellstore.hpp" #include "../mwmechanics/creaturestats.hpp" diff --git a/apps/openmw/mwmechanics/aisequence.cpp b/apps/openmw/mwmechanics/aisequence.cpp index fb6450d16..a750860ca 100644 --- a/apps/openmw/mwmechanics/aisequence.cpp +++ b/apps/openmw/mwmechanics/aisequence.cpp @@ -1,6 +1,7 @@ - #include "aisequence.hpp" +#include + #include "aipackage.hpp" #include "aistate.hpp" @@ -14,9 +15,6 @@ #include -#include "../mwworld/class.hpp" -#include "creaturestats.hpp" -#include "npcstats.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index f192bed63..1585a3007 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -1,6 +1,7 @@ #include "aitravel.hpp" #include +#include #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwmechanics/obstacle.cpp b/apps/openmw/mwmechanics/obstacle.cpp index 3d2ab7d3d..25bd06301 100644 --- a/apps/openmw/mwmechanics/obstacle.cpp +++ b/apps/openmw/mwmechanics/obstacle.cpp @@ -1,5 +1,7 @@ #include "obstacle.hpp" +#include + #include "../mwbase/world.hpp" #include "../mwworld/class.hpp" #include "../mwworld/cellstore.hpp" diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 6ce54a4ba..d307e990a 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -12,6 +12,7 @@ #include #include +#include #include #include #include diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 7cad745dd..b5f141963 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -17,6 +17,8 @@ #include #include +#include + #include "vismask.hpp" #include "ripplesimulation.hpp" diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index fd3f364e9..f88bf0958 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -5,12 +5,32 @@ #include #include #include +#include + #include #include "livecellref.hpp" #include "cellreflist.hpp" -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include "../mwmechanics/pathgrid.hpp" // TODO: maybe belongs in mwworld From c088cd4fa9d0286124bf3ad7c553150cdb842bbe Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sat, 25 Jul 2015 17:57:40 +0300 Subject: [PATCH 1923/3725] Proper index creation for nested data --- apps/opencs/model/world/idtree.cpp | 4 ++-- apps/opencs/model/world/nestedtableproxymodel.cpp | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/opencs/model/world/idtree.cpp b/apps/opencs/model/world/idtree.cpp index 9dbe7e002..5a7d10c6e 100644 --- a/apps/opencs/model/world/idtree.cpp +++ b/apps/opencs/model/world/idtree.cpp @@ -171,10 +171,10 @@ QModelIndex CSMWorld::IdTree::index (int row, int column, const QModelIndex& par encodedId = this->foldIndexAddress(parent); } - if (row<0 || row>=idCollection()->getSize()) + if (row < 0 || row >= rowCount(parent)) return QModelIndex(); - if (column<0 || column>=idCollection()->getColumns()) + if (column < 0 || column >= columnCount(parent)) return QModelIndex(); return createIndex(row, column, encodedId); // store internal id diff --git a/apps/opencs/model/world/nestedtableproxymodel.cpp b/apps/opencs/model/world/nestedtableproxymodel.cpp index 052e629aa..edcc7a070 100644 --- a/apps/opencs/model/world/nestedtableproxymodel.cpp +++ b/apps/opencs/model/world/nestedtableproxymodel.cpp @@ -75,10 +75,10 @@ QModelIndex CSMWorld::NestedTableProxyModel::index(int row, int column, const QM { assert (!parent.isValid()); - int rows = mMainModel->rowCount(parent); - int columns = mMainModel->columnCount(parent); + int numRows = rowCount(parent); + int numColumns = columnCount(parent); - if (row < 0 || row >= rows || column < 0 || column >= columns) + if (row < 0 || row >= numRows || column < 0 || column >= numColumns) return QModelIndex(); return createIndex(row, column); From e0ee2fc01b3fb8db478bb88e6211065cc775c8e0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 25 Jul 2015 18:22:48 +0200 Subject: [PATCH 1924/3725] Adjust the movement animation speed every frame (Fixes #1921) --- apps/openmw/mwmechanics/character.cpp | 43 ++++++++++++++------------- apps/openmw/mwmechanics/character.hpp | 3 +- 2 files changed, 24 insertions(+), 22 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 50faaa91b..066489e8e 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -408,14 +408,13 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat mCurrentMovement = movementAnimName; if(!mCurrentMovement.empty()) { - float vel, speedmult = 1.0f; - bool isrunning = mPtr.getClass().getCreatureStats(mPtr).getStance(MWMechanics::CreatureStats::Stance_Run) && !MWBase::Environment::get().getWorld()->isFlying(mPtr); // For non-flying creatures, MW uses the Walk animation to calculate the animation velocity // even if we are running. This must be replicated, otherwise the observed speed would differ drastically. std::string anim = mCurrentMovement; + mAdjustMovementAnimSpeed = true; if (mPtr.getClass().getTypeName() == typeid(ESM::Creature).name() && !(mPtr.get()->mBase->mFlags & ESM::Creature::Flies)) { @@ -423,30 +422,28 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat const StateInfo *stateinfo = std::find_if(sMovementList, sMovementListEnd, FindCharState(walkState)); anim = stateinfo->groupname; - if (mMovementSpeed > 0.0f && (vel=mAnimation->getVelocity(anim)) > 1.0f) - speedmult = mMovementSpeed / vel; - else + mMovementAnimSpeed = mAnimation->getVelocity(anim); + if (mMovementAnimSpeed <= 1.0f) + { // Another bug: when using a fallback animation (e.g. RunForward as fallback to SwimRunForward), // then the equivalent Walk animation will not use a fallback, and if that animation doesn't exist // we will play without any scaling. // Makes the speed attribute of most water creatures totally useless. // And again, this can not be fixed without patching game data. - speedmult = 1.f; + mAdjustMovementAnimSpeed = false; + mMovementAnimSpeed = 1.f; + } } else { - if(mMovementSpeed > 0.0f && (vel=mAnimation->getVelocity(anim)) > 1.0f) - { - speedmult = mMovementSpeed / vel; - } - else if (mMovementState == CharState_TurnLeft || mMovementState == CharState_TurnRight) - speedmult = 1.f; // adjusted each frame - else if (mMovementSpeed > 0.0f) + mMovementAnimSpeed = mAnimation->getVelocity(anim); + + if (mMovementAnimSpeed <= 1.0f) { // The first person anims don't have any velocity to calculate a speed multiplier from. // We use the third person velocities instead. // FIXME: should be pulled from the actual animation, but it is not presently loaded. - speedmult = mMovementSpeed / (isrunning ? 222.857f : 154.064f); + mMovementAnimSpeed = (isrunning ? 222.857f : 154.064f); mMovementAnimationControlled = false; } } @@ -462,7 +459,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat } mAnimation->play(mCurrentMovement, priorityMovement, movemask, false, - speedmult, ((mode!=2)?"start":"loop start"), "stop", 0.0f, ~0ul); + 1.f, ((mode!=2)?"start":"loop start"), "stop", 0.0f, ~0ul); } } @@ -655,7 +652,6 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim , mAnimation(anim) , mIdleState(CharState_None) , mMovementState(CharState_None) - , mMovementSpeed(0.0f) , mHasMovedInXY(false) , mMovementAnimationControlled(true) , mDeathState(CharState_None) @@ -1487,6 +1483,7 @@ void CharacterController::update(float duration) MWBase::World *world = MWBase::Environment::get().getWorld(); const MWWorld::Class &cls = mPtr.getClass(); osg::Vec3f movement(0.f, 0.f, 0.f); + float speed = 0.f; updateMagicEffects(); @@ -1550,10 +1547,10 @@ void CharacterController::update(float duration) vec = osg::Vec3f(0.f, 0.f, 0.f); osg::Vec3f rot = cls.getRotationVector(mPtr); - mMovementSpeed = cls.getSpeed(mPtr); + speed = cls.getSpeed(mPtr); - vec.x() *= mMovementSpeed; - vec.y() *= mMovementSpeed; + vec.x() *= speed; + vec.y() *= speed; CharacterState movestate = CharState_None; CharacterState idlestate = CharState_SpecialIdle; @@ -1807,6 +1804,11 @@ void CharacterController::update(float duration) if (duration > 0) mAnimation->adjustSpeedMult(mCurrentMovement, std::min(1.5f, std::abs(rot.z()) / duration / static_cast(osg::PI))); } + else if (mMovementState != CharState_None && mAdjustMovementAnimSpeed) + { + float speedmult = speed / mMovementAnimSpeed; + mAnimation->adjustSpeedMult(mCurrentMovement, speedmult); + } if (!mSkipAnim) { @@ -1845,7 +1847,7 @@ void CharacterController::update(float duration) moved = osg::Vec3f(0.f, 0.f, 0.f); // Ensure we're moving in generally the right direction... - if(mMovementSpeed > 0.f) + if(speed > 0.f) { float l = moved.length(); @@ -1927,7 +1929,6 @@ void CharacterController::clearAnimQueue() mAnimQueue.clear(); } - void CharacterController::forceStateUpdate() { if(!mAnimation) diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index f37afd996..1f9b524e5 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -150,7 +150,8 @@ class CharacterController : public MWRender::Animation::TextKeyListener CharacterState mMovementState; std::string mCurrentMovement; - float mMovementSpeed; + float mMovementAnimSpeed; + bool mAdjustMovementAnimSpeed; bool mHasMovedInXY; bool mMovementAnimationControlled; From 41996b0aad06bd402b69f40b1855bec927c87ba4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 25 Jul 2015 18:59:16 +0200 Subject: [PATCH 1925/3725] Don't play turning animations in first person mode --- apps/openmw/mwmechanics/character.cpp | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 066489e8e..cf8b0284e 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -448,17 +448,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat } } - MWRender::Animation::AnimPriority priorityMovement (Priority_Movement); - if ((movement == CharState_TurnLeft || movement == CharState_TurnRight) - && mPtr == MWBase::Environment::get().getWorld()->getPlayerPtr() - && MWBase::Environment::get().getWorld()->isFirstPerson()) - { - priorityMovement.mPriority[MWRender::Animation::BoneGroup_Torso] = 0; - priorityMovement.mPriority[MWRender::Animation::BoneGroup_LeftArm] = 0; - priorityMovement.mPriority[MWRender::Animation::BoneGroup_RightArm] = 0; - } - - mAnimation->play(mCurrentMovement, priorityMovement, movemask, false, + mAnimation->play(mCurrentMovement, Priority_Movement, movemask, false, 1.f, ((mode!=2)?"start":"loop start"), "stop", 0.0f, ~0ul); } } @@ -1741,10 +1731,7 @@ void CharacterController::update(float duration) : (sneak ? CharState_SneakBack : (isrunning ? CharState_RunBack : CharState_WalkBack))); } - // Don't play turning animations during attack. It would break positioning of the arrow bone when releasing a shot. - // Actually, in vanilla the turning animation is not even played when merely having equipped the weapon, - // but I don't think we need to go as far as that. - else if(rot.z() != 0.0f && !inwater && !sneak && mUpperBodyState < UpperCharState_StartToMinAttack) + else if(rot.z() != 0.0f && !inwater && !sneak && !MWBase::Environment::get().getWorld()->isFirstPerson()) { if(rot.z() > 0.0f) movestate = CharState_TurnRight; From aba72258173db213bdccc82682ca1938a88d7559 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 26 Jul 2015 11:15:21 +1200 Subject: [PATCH 1926/3725] Removed some duplicated operations. --- apps/openmw/mwmechanics/aicombat.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 6a39178ce..bdd09a1a8 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -181,13 +181,15 @@ namespace MWMechanics // get or create temporary storage AiCombatStorage& storage = state.get(); + const MWWorld::Class& actorClass = actor.getClass(); //General description - if(actor.getClass().getCreatureStats(actor).isDead()) + if (actorClass.getCreatureStats(actor).isDead()) return true; - MWWorld::Ptr target = MWBase::Environment::get().getWorld()->searchPtrViaActorId(mTargetActorId); + MWBase::World* world = MWBase::Environment::get().getWorld(); + MWWorld::Ptr target = world->searchPtrViaActorId(mTargetActorId); if (target.isEmpty()) return false; @@ -196,9 +198,6 @@ namespace MWMechanics || target.getClass().getCreatureStats(target).isDead()) return true; - const MWWorld::Class& actorClass = actor.getClass(); - MWBase::World* world = MWBase::Environment::get().getWorld(); - //Update every frame bool& combatMove = storage.mCombatMove; From dff84adf7e254c819943104d870d59a8e55d924d Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 26 Jul 2015 01:35:36 +0200 Subject: [PATCH 1927/3725] Fix weapon animation priority --- apps/openmw/mwmechanics/character.cpp | 2 +- apps/openmw/mwmechanics/character.hpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index cf8b0284e..9d5f7137f 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1052,7 +1052,7 @@ bool CharacterController::updateWeaponState() } MWRender::Animation::AnimPriority priorityWeapon(Priority_Weapon); - priorityWeapon.mPriority[MWRender::Animation::BoneGroup_LowerBody] = 0; + priorityWeapon.mPriority[MWRender::Animation::BoneGroup_LowerBody] = Priority_WeaponLowerBody; bool forcestateupdate = false; if(weaptype != mWeaponType && mHitState != CharState_KnockDown && mHitState != CharState_KnockOut diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 1f9b524e5..d647cae22 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -28,6 +28,7 @@ class CreatureStats; enum Priority { Priority_Default, + Priority_WeaponLowerBody, Priority_Jump, Priority_Movement, Priority_Hit, From b3d5b47fea3b949d632f9168dd8cd5f273dc8b00 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 26 Jul 2015 17:23:45 +1200 Subject: [PATCH 1928/3725] extracted function UpdateActorsMovement(). --- apps/openmw/mwmechanics/aicombat.cpp | 37 ++++++++++++++++++---------- apps/openmw/mwmechanics/aicombat.hpp | 5 ++++ 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index bdd09a1a8..1beb0024c 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -214,20 +214,8 @@ namespace MWMechanics } } - actorClass.getMovementSettings(actor) = movement; - actorClass.getMovementSettings(actor).mRotation[0] = 0; - actorClass.getMovementSettings(actor).mRotation[2] = 0; + UpdateActorsMovement(actor, movement); - if(movement.mRotation[2] != 0) - { - if(zTurn(actor, movement.mRotation[2])) movement.mRotation[2] = 0; - } - - if(movement.mRotation[0] != 0) - { - if(smoothTurn(actor, movement.mRotation[0], 0)) movement.mRotation[0] = 0; - } - bool& attack = storage.mAttack; bool& readyToAttack = storage.mReadyToAttack; @@ -579,6 +567,29 @@ namespace MWMechanics return false; } + void AiCombat::UpdateActorsMovement(const MWWorld::Ptr& actor, MWMechanics::Movement& desiredMovement) + { + MWMechanics::Movement& actorMovementSettings = actor.getClass().getMovementSettings(actor); + actorMovementSettings = desiredMovement; + RotateActorOnAxis(actor, 2, actorMovementSettings, desiredMovement); + RotateActorOnAxis(actor, 0, actorMovementSettings, desiredMovement); + } + + void AiCombat::RotateActorOnAxis(const MWWorld::Ptr& actor, int axis, + MWMechanics::Movement& actorMovementSettings, MWMechanics::Movement& desiredMovement) + { + actorMovementSettings.mRotation[axis] = 0; + float& targetAngleRadians = desiredMovement.mRotation[axis]; + if (targetAngleRadians != 0) + { + if (smoothTurn(actor, targetAngleRadians, axis)) + { + // actor now facing desired direction, no need to turn any more + targetAngleRadians = 0; + } + } + } + bool AiCombat::doesPathNeedRecalc(ESM::Pathgrid::Point dest, const ESM::Cell *cell) { if (!mPathFinder.getPath().empty()) diff --git a/apps/openmw/mwmechanics/aicombat.hpp b/apps/openmw/mwmechanics/aicombat.hpp index 083f23384..c81ad0544 100644 --- a/apps/openmw/mwmechanics/aicombat.hpp +++ b/apps/openmw/mwmechanics/aicombat.hpp @@ -60,6 +60,11 @@ namespace MWMechanics void buildNewPath(const MWWorld::Ptr& actor, const MWWorld::Ptr& target); + + /// Transfer desired movement (from AiCombatStorage) to Actor + void UpdateActorsMovement(const MWWorld::Ptr& actor, MWMechanics::Movement& movement); + void RotateActorOnAxis(const MWWorld::Ptr& actor, int axis, + MWMechanics::Movement& actorMovementSettings, MWMechanics::Movement& desiredMovement); }; From 5ec310dfbab45a6952cb8fcb94b64f6f8b364a7f Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 26 Jul 2015 17:24:33 +1200 Subject: [PATCH 1929/3725] extract function onIdleStatePerFrameActions(). --- apps/openmw/mwmechanics/aiwander.cpp | 68 ++++++++++++++++------------ apps/openmw/mwmechanics/aiwander.hpp | 1 + 2 files changed, 39 insertions(+), 30 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 5c9949a5a..8b05299a4 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -195,18 +195,10 @@ namespace MWMechanics WanderState& wanderState = storage.mState; - // Check if an idle actor is too close to a door - if so start walking - mDoorCheckDuration += duration; - if(mDoorCheckDuration >= DOOR_CHECK_INTERVAL) + + if (wanderState == Wander_IdleNow) { - mDoorCheckDuration = 0; // restart timer - if(mDistance && // actor is not intended to be stationary - (wanderState == Wander_IdleNow) && // but is in idle - proximityToDoor(actor, MIN_DIST_TO_DOOR_SQUARED*1.6f*1.6f)) // NOTE: checks interior cells only - { - wanderState = Wander_MoveNow; - mTrimCurrentNode = false; // just in case - } + onIdleStatePerFrameActions(actor, duration, storage); } // Are we there yet? @@ -229,29 +221,11 @@ namespace MWMechanics evadeObstacles(actor, storage, duration); } - bool& rotate = storage.mTurnActorGivingGreetingToFacePlayer; - if (rotate) - { - // Reduce the turning animation glitch by using a *HUGE* value of - // epsilon... TODO: a proper fix might be in either the physics or the - // animation subsystem - if (zTurn(actor, storage.mTargetAngleRadians, osg::DegreesToRadians(5.f))) - rotate = false; - } - - // Check if idle animation finished - short unsigned& idleAnimation = storage.mIdleAnimation; - GreetingState& greetingState = storage.mSaidGreeting; - if ((wanderState == Wander_IdleNow) && - !checkIdle(actor, idleAnimation) && (greetingState == Greet_Done || greetingState == Greet_None)) - { - wanderState = Wander_ChooseAction; - } - MWBase::World *world = MWBase::Environment::get().getWorld(); if (wanderState == Wander_ChooseAction) { + short unsigned& idleAnimation = storage.mIdleAnimation; idleAnimation = getRandomIdle(); if(!idleAnimation && mDistance) @@ -355,6 +329,40 @@ namespace MWMechanics return false; // AiWander package not yet completed } + void AiWander::onIdleStatePerFrameActions(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage) + { + // Check if an idle actor is too close to a door - if so start walking + mDoorCheckDuration += duration; + if (mDoorCheckDuration >= DOOR_CHECK_INTERVAL) + { + mDoorCheckDuration = 0; // restart timer + if (mDistance && // actor is not intended to be stationary + proximityToDoor(actor, MIN_DIST_TO_DOOR_SQUARED*1.6f*1.6f)) // NOTE: checks interior cells only + { + storage.mState = Wander_MoveNow; + mTrimCurrentNode = false; // just in case + return; + } + } + + bool& rotate = storage.mTurnActorGivingGreetingToFacePlayer; + if (rotate) + { + // Reduce the turning animation glitch by using a *HUGE* value of + // epsilon... TODO: a proper fix might be in either the physics or the + // animation subsystem + if (zTurn(actor, storage.mTargetAngleRadians, osg::DegreesToRadians(5.f))) + rotate = false; + } + + // Check if idle animation finished + GreetingState& greetingState = storage.mSaidGreeting; + if (!checkIdle(actor, storage.mIdleAnimation) && (greetingState == Greet_Done || greetingState == Greet_None)) + { + storage.mState = Wander_ChooseAction; + } + } + void AiWander::evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration) { if (mObstacleCheck.check(actor, duration)) diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index d1dab3f50..92af5b717 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -83,6 +83,7 @@ namespace MWMechanics void evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration); void playIdleDialogueRandomly(const MWWorld::Ptr& actor); void turnActorToFacePlayer(const osg::Vec3f& actorPosition, const osg::Vec3f& playerPosition, AiWanderStorage& storage); + void onIdleStatePerFrameActions(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage); int mDistance; // how far the actor can wander from the spawn point int mDuration; From 76f95eafe7c4db0ecb7a223465c5d010d2be0742 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 26 Jul 2015 17:25:00 +1200 Subject: [PATCH 1930/3725] extract function onWalkingStatePerFrameActions(). --- apps/openmw/mwmechanics/aiwander.cpp | 40 ++++++++++++++++------------ apps/openmw/mwmechanics/aiwander.hpp | 1 + 2 files changed, 24 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 8b05299a4..77cd9e137 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -201,26 +201,11 @@ namespace MWMechanics onIdleStatePerFrameActions(actor, duration, storage); } - // Are we there yet? - if ((wanderState == Wander_Walking) && - storage.mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], DESTINATION_TOLERANCE)) + if (wanderState == Wander_Walking) { - stopWalking(actor, storage); - wanderState = Wander_ChooseAction; - mHasReturnPosition = false; + onWalkingStatePerFrameActions(actor, duration, storage, pos); } - - - if (wanderState == Wander_Walking) // have not yet reached the destination - { - // turn towards the next point in mPath - zTurn(actor, storage.mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1])); - actor.getClass().getMovementSettings(actor).mPosition[1] = 1; - - evadeObstacles(actor, storage, duration); - } - MWBase::World *world = MWBase::Environment::get().getWorld(); if (wanderState == Wander_ChooseAction) @@ -363,6 +348,27 @@ namespace MWMechanics } } + void AiWander::onWalkingStatePerFrameActions(const MWWorld::Ptr& actor, + float duration, AiWanderStorage& storage, ESM::Position& pos) + { + // Are we there yet? + if (storage.mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], DESTINATION_TOLERANCE)) + { + stopWalking(actor, storage); + storage.mState = Wander_ChooseAction; + mHasReturnPosition = false; + } + else + { + // have not yet reached the destination + //... turn towards the next point in mPath + zTurn(actor, storage.mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1])); + actor.getClass().getMovementSettings(actor).mPosition[1] = 1; + + evadeObstacles(actor, storage, duration); + } + } + void AiWander::evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration) { if (mObstacleCheck.check(actor, duration)) diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 92af5b717..4750df1dc 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -84,6 +84,7 @@ namespace MWMechanics void playIdleDialogueRandomly(const MWWorld::Ptr& actor); void turnActorToFacePlayer(const osg::Vec3f& actorPosition, const osg::Vec3f& playerPosition, AiWanderStorage& storage); void onIdleStatePerFrameActions(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage); + void onWalkingStatePerFrameActions(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage, ESM::Position& pos); int mDistance; // how far the actor can wander from the spawn point int mDuration; From 9c0e3d6c28bd66717d8cd385e5e9099a1a01ad56 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 26 Jul 2015 17:25:44 +1200 Subject: [PATCH 1931/3725] extracted functions doPerFrameActionsForState() and onChooseActionStatePerFrameActions(). --- apps/openmw/mwmechanics/aiwander.cpp | 85 ++++++++++++++++------------ apps/openmw/mwmechanics/aiwander.hpp | 2 + 2 files changed, 52 insertions(+), 35 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 77cd9e137..e6d7d4422 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -193,39 +193,7 @@ namespace MWMechanics ESM::Position pos = actor.getRefData().getPosition(); - - WanderState& wanderState = storage.mState; - - if (wanderState == Wander_IdleNow) - { - onIdleStatePerFrameActions(actor, duration, storage); - } - - if (wanderState == Wander_Walking) - { - onWalkingStatePerFrameActions(actor, duration, storage, pos); - } - - MWBase::World *world = MWBase::Environment::get().getWorld(); - - if (wanderState == Wander_ChooseAction) - { - short unsigned& idleAnimation = storage.mIdleAnimation; - idleAnimation = getRandomIdle(); - - if(!idleAnimation && mDistance) - { - wanderState = Wander_MoveNow; - } - else - { - // Play idle animation and recreate vanilla (broken?) behavior of resetting start time of AIWander: - MWWorld::TimeStamp currentTime = world->getTimeStamp(); - mStartTime = currentTime; - playIdle(actor, idleAnimation); - wanderState = Wander_IdleNow; - } - } + doPerFrameActionsForState(actor, duration, storage, pos); playIdleDialogueRandomly(actor); @@ -243,7 +211,7 @@ namespace MWMechanics if(mDuration) { // End package if duration is complete or mid-night hits: - MWWorld::TimeStamp currentTime = world->getTimeStamp(); + MWWorld::TimeStamp currentTime = MWBase::Environment::get().getWorld()->getTimeStamp(); if((currentTime.getHour() >= mStartTime.getHour() + mDuration) || (int(currentTime.getHour()) == 0 && currentTime.getDay() != mStartTime.getDay())) { @@ -288,12 +256,13 @@ namespace MWMechanics if(storage.mPathFinder.isPathConstructed()) { - wanderState = Wander_Walking; + storage.mState = Wander_Walking; } } } // Allow interrupting a walking actor to trigger a greeting + WanderState& wanderState = storage.mState; if ((wanderState == Wander_IdleNow) || (wanderState == Wander_Walking)) { playGreetingIfPlayerGetsTooClose(actor, storage); @@ -314,6 +283,32 @@ namespace MWMechanics return false; // AiWander package not yet completed } + void AiWander::doPerFrameActionsForState(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage, ESM::Position& pos) + { + switch (storage.mState) + { + case Wander_IdleNow: + onIdleStatePerFrameActions(actor, duration, storage); + break; + + case Wander_Walking: + onWalkingStatePerFrameActions(actor, duration, storage, pos); + break; + + case Wander_ChooseAction: + onChooseActionStatePerFrameActions(actor, storage); + break; + + case Wander_MoveNow: + break; // nothing to do + + default: + // should never get here + assert(false); + break; + } + } + void AiWander::onIdleStatePerFrameActions(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage) { // Check if an idle actor is too close to a door - if so start walking @@ -369,6 +364,26 @@ namespace MWMechanics } } + void AiWander::onChooseActionStatePerFrameActions(const MWWorld::Ptr& actor, AiWanderStorage& storage) + { + + short unsigned& idleAnimation = storage.mIdleAnimation; + idleAnimation = getRandomIdle(); + + if (!idleAnimation && mDistance) + { + storage.mState = Wander_MoveNow; + } + else + { + // Play idle animation and recreate vanilla (broken?) behavior of resetting start time of AIWander: + MWWorld::TimeStamp currentTime = MWBase::Environment::get().getWorld()->getTimeStamp(); + mStartTime = currentTime; + playIdle(actor, idleAnimation); + storage.mState = Wander_IdleNow; + } + } + void AiWander::evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration) { if (mObstacleCheck.check(actor, duration)) diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 4750df1dc..9b21415c4 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -83,8 +83,10 @@ namespace MWMechanics void evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration); void playIdleDialogueRandomly(const MWWorld::Ptr& actor); void turnActorToFacePlayer(const osg::Vec3f& actorPosition, const osg::Vec3f& playerPosition, AiWanderStorage& storage); + void doPerFrameActionsForState(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage, ESM::Position& pos); void onIdleStatePerFrameActions(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage); void onWalkingStatePerFrameActions(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage, ESM::Position& pos); + void onChooseActionStatePerFrameActions(const MWWorld::Ptr& actor, AiWanderStorage& storage); int mDistance; // how far the actor can wander from the spawn point int mDuration; From ad0d8071037d4fda4e8b5151f5e6c9ec561d9af3 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 26 Jul 2015 17:28:32 +1200 Subject: [PATCH 1932/3725] extracted function reactionTimeActions(). --- apps/openmw/mwmechanics/aiwander.cpp | 13 ++++++++----- apps/openmw/mwmechanics/aiwander.hpp | 2 ++ 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index e6d7d4422..228f4b32d 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -199,15 +199,18 @@ namespace MWMechanics float& lastReaction = storage.mReaction; lastReaction += duration; - if(lastReaction < REACTION_INTERVAL) + if (REACTION_INTERVAL <= lastReaction) { - return false; + lastReaction = 0; + return reactionTimeActions(actor, storage, currentCell, cellChange, pos); } else - lastReaction = 0; - - // NOTE: everything below get updated every REACTION_INTERVAL seconds + return false; + } + bool AiWander::reactionTimeActions(const MWWorld::Ptr& actor, AiWanderStorage& storage, + const MWWorld::CellStore*& currentCell, bool cellChange, ESM::Position& pos) + { if(mDuration) { // End package if duration is complete or mid-night hits: diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 9b21415c4..3468c212d 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -87,6 +87,8 @@ namespace MWMechanics void onIdleStatePerFrameActions(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage); void onWalkingStatePerFrameActions(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage, ESM::Position& pos); void onChooseActionStatePerFrameActions(const MWWorld::Ptr& actor, AiWanderStorage& storage); + bool reactionTimeActions(const MWWorld::Ptr& actor, AiWanderStorage& storage, + const MWWorld::CellStore*& currentCell, bool cellChange, ESM::Position& pos); int mDistance; // how far the actor can wander from the spawn point int mDuration; From 5e519ef550abbceda13d501cccb83d07d1f1dba8 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 26 Jul 2015 17:29:01 +1200 Subject: [PATCH 1933/3725] extract function isPackageFinished(). --- apps/openmw/mwmechanics/aiwander.cpp | 40 ++++++++++++++++++---------- apps/openmw/mwmechanics/aiwander.hpp | 1 + 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 228f4b32d..ff26bc116 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -211,21 +211,9 @@ namespace MWMechanics bool AiWander::reactionTimeActions(const MWWorld::Ptr& actor, AiWanderStorage& storage, const MWWorld::CellStore*& currentCell, bool cellChange, ESM::Position& pos) { - if(mDuration) + if (isPackageCompleted(actor, storage)) { - // End package if duration is complete or mid-night hits: - MWWorld::TimeStamp currentTime = MWBase::Environment::get().getWorld()->getTimeStamp(); - if((currentTime.getHour() >= mStartTime.getHour() + mDuration) || - (int(currentTime.getHour()) == 0 && currentTime.getDay() != mStartTime.getDay())) - { - if(!mRepeat) - { - stopWalking(actor, storage); - return true; - } - else - mStartTime = currentTime; - } + return true; } // Initialization to discover & store allowed node points for this actor. @@ -286,6 +274,30 @@ namespace MWMechanics return false; // AiWander package not yet completed } + bool AiWander::isPackageCompleted(const MWWorld::Ptr& actor, AiWanderStorage& storage) + { + if (mDuration) + { + // End package if duration is complete or mid-night hits: + MWWorld::TimeStamp currentTime = MWBase::Environment::get().getWorld()->getTimeStamp(); + if ((currentTime.getHour() >= mStartTime.getHour() + mDuration) || + (int(currentTime.getHour()) == 0 && currentTime.getDay() != mStartTime.getDay())) + { + if (!mRepeat) + { + stopWalking(actor, storage); + return true; + } + else + { + mStartTime = currentTime; + } + } + } + // if get here, not yet completed + return false; + } + void AiWander::doPerFrameActionsForState(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage, ESM::Position& pos) { switch (storage.mState) diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 3468c212d..2364ac543 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -89,6 +89,7 @@ namespace MWMechanics void onChooseActionStatePerFrameActions(const MWWorld::Ptr& actor, AiWanderStorage& storage); bool reactionTimeActions(const MWWorld::Ptr& actor, AiWanderStorage& storage, const MWWorld::CellStore*& currentCell, bool cellChange, ESM::Position& pos); + bool isPackageCompleted(const MWWorld::Ptr& actor, AiWanderStorage& storage); int mDistance; // how far the actor can wander from the spawn point int mDuration; From c7aacaee706a9226ff947a038cdbae519920e708 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 26 Jul 2015 17:29:32 +1200 Subject: [PATCH 1934/3725] extracted function returnToStartLocation(). --- apps/openmw/mwmechanics/aiwander.cpp | 38 ++++++++++++++++------------ apps/openmw/mwmechanics/aiwander.hpp | 1 + 2 files changed, 23 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index ff26bc116..e230998eb 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -233,23 +233,10 @@ namespace MWMechanics // For stationary NPCs, move back to the starting location if another AiPackage moved us elsewhere if (cellChange) mHasReturnPosition = false; - if (mDistance == 0 && mHasReturnPosition && (pos.asVec3() - mReturnPosition).length2() > 20*20) + if (mDistance == 0 && mHasReturnPosition + && (pos.asVec3() - mReturnPosition).length2() > (DESTINATION_TOLERANCE * DESTINATION_TOLERANCE)) { - if (!storage.mPathFinder.isPathConstructed()) - { - ESM::Pathgrid::Point dest(PathFinder::MakePathgridPoint(mReturnPosition)); - - // actor position is already in world co-ordinates - ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(pos)); - - // don't take shortcuts for wandering - storage.mPathFinder.buildSyncedPath(start, dest, actor.getCell(), false); - - if(storage.mPathFinder.isPathConstructed()) - { - storage.mState = Wander_Walking; - } - } + returnToStartLocation(actor, storage, pos); } // Allow interrupting a walking actor to trigger a greeting @@ -298,6 +285,25 @@ namespace MWMechanics return false; } + void AiWander::returnToStartLocation(const MWWorld::Ptr& actor, AiWanderStorage& storage, ESM::Position& pos) + { + if (!storage.mPathFinder.isPathConstructed()) + { + ESM::Pathgrid::Point dest(PathFinder::MakePathgridPoint(mReturnPosition)); + + // actor position is already in world co-ordinates + ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(pos)); + + // don't take shortcuts for wandering + storage.mPathFinder.buildSyncedPath(start, dest, actor.getCell(), false); + + if (storage.mPathFinder.isPathConstructed()) + { + storage.mState = Wander_Walking; + } + } + } + void AiWander::doPerFrameActionsForState(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage, ESM::Position& pos) { switch (storage.mState) diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 2364ac543..8a489c783 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -90,6 +90,7 @@ namespace MWMechanics bool reactionTimeActions(const MWWorld::Ptr& actor, AiWanderStorage& storage, const MWWorld::CellStore*& currentCell, bool cellChange, ESM::Position& pos); bool isPackageCompleted(const MWWorld::Ptr& actor, AiWanderStorage& storage); + void returnToStartLocation(const MWWorld::Ptr& actor, AiWanderStorage& storage, ESM::Position& pos); int mDistance; // how far the actor can wander from the spawn point int mDuration; From 04aee1fe20a1d742292ac09d0c162dc9a30c3de2 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 26 Jul 2015 17:32:29 +1200 Subject: [PATCH 1935/3725] extracted function reactionTimeActions(). --- apps/openmw/mwmechanics/aicombat.cpp | 54 +++++++++++++++------------- apps/openmw/mwmechanics/aicombat.hpp | 5 ++- 2 files changed, 34 insertions(+), 25 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 1beb0024c..fc1c31c26 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -45,6 +45,7 @@ namespace return -std::asin(dir.z() / len); } + const float REACTION_INTERVAL = 0.25f; const float PATHFIND_Z_REACH = 50.0f; // distance at which actor pays more attention to decide whether to shortcut or stick to pathgrid @@ -181,15 +182,11 @@ namespace MWMechanics // get or create temporary storage AiCombatStorage& storage = state.get(); - const MWWorld::Class& actorClass = actor.getClass(); - - //General description - if (actorClass.getCreatureStats(actor).isDead()) + if (actor.getClass().getCreatureStats(actor).isDead()) return true; - MWBase::World* world = MWBase::Environment::get().getWorld(); - MWWorld::Ptr target = world->searchPtrViaActorId(mTargetActorId); + MWWorld::Ptr target = MWBase::Environment::get().getWorld()->searchPtrViaActorId(mTargetActorId); if (target.isEmpty()) return false; @@ -217,8 +214,6 @@ namespace MWMechanics UpdateActorsMovement(actor, movement); bool& attack = storage.mAttack; - bool& readyToAttack = storage.mReadyToAttack; - if (attack && (characterController.getAttackStrength() >= storage.mStrength || characterController.readyToPrepareAttack())) attack = false; @@ -228,14 +223,22 @@ namespace MWMechanics actionCooldown -= duration; float& timerReact = storage.mTimerReact; - float tReaction = 0.25f; - if(timerReact < tReaction) + if(timerReact < REACTION_INTERVAL) { timerReact += duration; return false; } + else + { + timerReact = 0; + return reactionTimeActions(actor, characterController, storage, target); + } + } - //Update with period = tReaction + bool AiCombat::reactionTimeActions(const MWWorld::Ptr& actor, CharacterController& characterController, + AiCombatStorage& storage, MWWorld::Ptr target) + { + MWMechanics::Movement& movement = storage.mMovement; // Stop attacking if target is not seen if (target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::Invisibility).getMagnitude() > 0 @@ -245,7 +248,6 @@ namespace MWMechanics return false; // TODO: run away instead of doing nothing } - timerReact = 0; const MWWorld::CellStore*& currentCell = storage.mCell; bool cellChange = currentCell && (actor.getCell() != currentCell); if(!currentCell || cellChange) @@ -253,8 +255,10 @@ namespace MWMechanics currentCell = actor.getCell(); } + const MWWorld::Class& actorClass = actor.getClass(); actorClass.getCreatureStats(actor).setMovementFlag(CreatureStats::Flag_Run, true); + float& actionCooldown = storage.mActionCooldown; if (actionCooldown > 0) return false; @@ -276,6 +280,7 @@ namespace MWMechanics float weapRange = 1.0f; // Get weapon characteristics + MWBase::World* world = MWBase::Environment::get().getWorld(); if (actorClass.hasInventoryStore(actor)) { //Get weapon speed and range @@ -326,13 +331,14 @@ namespace MWMechanics float& strength = storage.mStrength; + bool& readyToAttack = storage.mReadyToAttack; // start new attack if(readyToAttack && characterController.readyToStartAttack()) { if (storage.mAttackCooldown <= 0) { - attack = true; // attack starts just now - characterController.setAttackingOrSpell(attack); + storage.mAttack = true; // attack starts just now + characterController.setAttackingOrSpell(true); if (!distantCombat) chooseBestAttack(weapon, movement); @@ -356,7 +362,7 @@ namespace MWMechanics storage.mAttackCooldown = std::min(baseDelay + 0.01 * Misc::Rng::roll0to99(), baseDelay + 0.9); } else - storage.mAttackCooldown -= tReaction; + storage.mAttackCooldown -= REACTION_INTERVAL; } @@ -400,7 +406,7 @@ namespace MWMechanics bool isStuck = false; float speed = 0.0f; - if(movement.mPosition[1] && (lastActorPos - vActorPos).length() < (speed = actorClass.getSpeed(actor)) * tReaction / 2) + if(movement.mPosition[1] && (lastActorPos - vActorPos).length() < (speed = actorClass.getSpeed(actor)) * REACTION_INTERVAL / 2) isStuck = true; lastActorPos = vActorPos; @@ -437,7 +443,7 @@ namespace MWMechanics if (distantCombat) { osg::Vec3f& lastTargetPos = storage.mLastTargetPos; - osg::Vec3f vAimDir = AimDirToMovingTarget(actor, target, lastTargetPos, tReaction, weaptype, strength); + osg::Vec3f vAimDir = AimDirToMovingTarget(actor, target, lastTargetPos, REACTION_INTERVAL, weaptype, strength); lastTargetPos = vTargetPos; movement.mRotation[0] = getXAngleToDir(vAimDir); movement.mRotation[2] = getZAngleToDir(vAimDir); @@ -458,8 +464,8 @@ namespace MWMechanics { if(movement.mPosition[0] || movement.mPosition[1]) { - timerCombatMove = 0.1f + 0.1f * Misc::Rng::rollClosedProbability(); - combatMove = true; + storage.mTimerCombatMove = 0.1f + 0.1f * Misc::Rng::rollClosedProbability(); + storage.mCombatMove = true; } // only NPCs are smart enough to use dodge movements else if(actorClass.isNpc() && (!distantCombat || (distantCombat && distToTarget < rangeAttack/2))) @@ -468,8 +474,8 @@ namespace MWMechanics if (Misc::Rng::rollClosedProbability() < 0.25) { movement.mPosition[0] = Misc::Rng::rollProbability() < 0.5 ? 1.0f : -1.0f; - timerCombatMove = 0.05f + 0.15f * Misc::Rng::rollClosedProbability(); - combatMove = true; + storage.mTimerCombatMove = 0.05f + 0.15f * Misc::Rng::rollClosedProbability(); + storage.mCombatMove = true; } } @@ -497,7 +503,7 @@ namespace MWMechanics { if(speed == 0.0f) speed = actorClass.getSpeed(actor); // maximum dist before pit/obstacle for actor to avoid them depending on his speed - float maxAvoidDist = tReaction * speed + speed / MAX_VEL_ANGULAR_RADIANS * 2; // *2 - for reliability + float maxAvoidDist = REACTION_INTERVAL * speed + speed / MAX_VEL_ANGULAR_RADIANS * 2; // *2 - for reliability preferShortcut = checkWayIsClear(vActorPos, vTargetPos, osg::Vec3f(vDirToTarget.x(), vDirToTarget.y(), 0).length() > maxAvoidDist*1.5? maxAvoidDist : maxAvoidDist/2); } @@ -558,8 +564,8 @@ namespace MWMechanics if (readyToAttack) { // to stop possible sideway moving after target moved out of attack range - combatMove = true; - timerCombatMove = 0; + storage.mCombatMove = true; + storage.mTimerCombatMove = 0; } readyToAttack = false; } diff --git a/apps/openmw/mwmechanics/aicombat.hpp b/apps/openmw/mwmechanics/aicombat.hpp index c81ad0544..4e4060819 100644 --- a/apps/openmw/mwmechanics/aicombat.hpp +++ b/apps/openmw/mwmechanics/aicombat.hpp @@ -26,6 +26,8 @@ namespace MWMechanics { class Action; + struct AiCombatStorage; + /// \brief Causes the actor to fight another actor class AiCombat : public AiPackage { @@ -58,8 +60,9 @@ namespace MWMechanics int mTargetActorId; - void buildNewPath(const MWWorld::Ptr& actor, const MWWorld::Ptr& target); + bool reactionTimeActions(const MWWorld::Ptr& actor, CharacterController& characterController, + AiCombatStorage& storage, MWWorld::Ptr target); /// Transfer desired movement (from AiCombatStorage) to Actor void UpdateActorsMovement(const MWWorld::Ptr& actor, MWMechanics::Movement& movement); From 6a1e1a07cbb52250cdd6b0c73c574e3f98b55862 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 26 Jul 2015 11:02:22 +0200 Subject: [PATCH 1936/3725] updated credits file --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index def0b2b89..291b0d56c 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -88,6 +88,7 @@ Programmers Nolan Poe (nopoe) Paul McElroy (Greendogo) Pieter van der Kloet (pvdk) + pkubik Radu-Marius Popovici (rpopovici) rdimesio riothamus From 9a8ca819073e54406daafd04319299429c089c4e Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sun, 26 Jul 2015 13:54:36 +0300 Subject: [PATCH 1937/3725] Fix missing break in switch statement --- components/esm/loadregn.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esm/loadregn.cpp b/components/esm/loadregn.cpp index b04e6ee3b..add821c3e 100644 --- a/components/esm/loadregn.cpp +++ b/components/esm/loadregn.cpp @@ -22,7 +22,6 @@ namespace ESM mId = esm.getHString(); hasName = true; break; - break; case ESM::FourCC<'F','N','A','M'>::value: mName = esm.getHString(); break; @@ -69,6 +68,7 @@ namespace ESM case ESM::FourCC<'D','E','L','E'>::value: esm.skipHSub(); isDeleted = true; + break; default: esm.fail("Unknown subrecord"); break; From 37fd733debc8c8d98220a6a920b14328ec5ab038 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sun, 26 Jul 2015 20:06:30 +0300 Subject: [PATCH 1938/3725] Create a custom signal to inform about a row addition in IdTableProxyModel --- apps/opencs/model/world/idtableproxymodel.cpp | 53 ++++++++++++------- apps/opencs/model/world/idtableproxymodel.hpp | 20 +++++-- 2 files changed, 51 insertions(+), 22 deletions(-) diff --git a/apps/opencs/model/world/idtableproxymodel.cpp b/apps/opencs/model/world/idtableproxymodel.cpp index ce9d44ed6..8beccd497 100644 --- a/apps/opencs/model/world/idtableproxymodel.cpp +++ b/apps/opencs/model/world/idtableproxymodel.cpp @@ -7,23 +7,23 @@ void CSMWorld::IdTableProxyModel::updateColumnMap() { - mColumnMap.clear(); + Q_ASSERT(mSourceModel != NULL); + mColumnMap.clear(); if (mFilter) { std::vector columns = mFilter->getReferencedColumns(); - - const IdTableBase& table = dynamic_cast (*sourceModel()); - for (std::vector::const_iterator iter (columns.begin()); iter!=columns.end(); ++iter) - mColumnMap.insert (std::make_pair (*iter, - table.searchColumnIndex (static_cast (*iter)))); + mColumnMap.insert (std::make_pair (*iter, + mSourceModel->searchColumnIndex (static_cast (*iter)))); } } bool CSMWorld::IdTableProxyModel::filterAcceptsRow (int sourceRow, const QModelIndex& sourceParent) const { + Q_ASSERT(mSourceModel != NULL); + // It is not possible to use filterAcceptsColumn() and check for // sourceModel()->headerData (sourceColumn, Qt::Horizontal, CSMWorld::ColumnBase::Role_Flags) // because the sourceColumn parameter excludes the hidden columns, i.e. wrong columns can @@ -35,34 +35,37 @@ bool CSMWorld::IdTableProxyModel::filterAcceptsRow (int sourceRow, const QModelI if (!mFilter) return true; - return mFilter->test ( - dynamic_cast (*sourceModel()), sourceRow, mColumnMap); + return mFilter->test (*mSourceModel, sourceRow, mColumnMap); } CSMWorld::IdTableProxyModel::IdTableProxyModel (QObject *parent) -: QSortFilterProxyModel (parent) + : QSortFilterProxyModel (parent), + mSourceModel(NULL) { setSortCaseSensitivity (Qt::CaseInsensitive); } QModelIndex CSMWorld::IdTableProxyModel::getModelIndex (const std::string& id, int column) const { - return mapFromSource (dynamic_cast (*sourceModel()).getModelIndex (id, column)); + Q_ASSERT(mSourceModel != NULL); + + return mapFromSource(mSourceModel->getModelIndex (id, column)); } void CSMWorld::IdTableProxyModel::setSourceModel(QAbstractItemModel *model) { QSortFilterProxyModel::setSourceModel(model); - connect(sourceModel(), - SIGNAL(rowsRemoved(const QModelIndex &, int, int)), - this, - SLOT(sourceRowsChanged(const QModelIndex &, int, int))); - connect(sourceModel(), + mSourceModel = dynamic_cast(sourceModel()); + connect(mSourceModel, SIGNAL(rowsInserted(const QModelIndex &, int, int)), this, - SLOT(sourceRowsChanged(const QModelIndex &, int, int))); - connect(sourceModel(), + SLOT(sourceRowsInserted(const QModelIndex &, int, int))); + connect(mSourceModel, + SIGNAL(rowsRemoved(const QModelIndex &, int, int)), + this, + SLOT(sourceRowsRemoved(const QModelIndex &, int, int))); + connect(mSourceModel, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), this, SLOT(sourceDataChanged(const QModelIndex &, const QModelIndex &))); @@ -95,13 +98,27 @@ bool CSMWorld::IdTableProxyModel::lessThan(const QModelIndex &left, const QModel return QSortFilterProxyModel::lessThan(left, right); } +QString CSMWorld::IdTableProxyModel::getRecordId(int sourceRow) const +{ + Q_ASSERT(mSourceModel != NULL); + + int idColumn = mSourceModel->findColumnIndex(Columns::ColumnId_Id); + return mSourceModel->data(mSourceModel->index(sourceRow, idColumn)).toString(); +} + void CSMWorld::IdTableProxyModel::refreshFilter() { updateColumnMap(); invalidateFilter(); } -void CSMWorld::IdTableProxyModel::sourceRowsChanged(const QModelIndex &/*parent*/, int /*start*/, int /*end*/) +void CSMWorld::IdTableProxyModel::sourceRowsInserted(const QModelIndex &/*parent*/, int /*start*/, int end) +{ + refreshFilter(); + emit rowAdded(getRecordId(end).toUtf8().constData()); +} + +void CSMWorld::IdTableProxyModel::sourceRowsRemoved(const QModelIndex &/*parent*/, int /*start*/, int /*end*/) { refreshFilter(); } diff --git a/apps/opencs/model/world/idtableproxymodel.hpp b/apps/opencs/model/world/idtableproxymodel.hpp index 17c30361a..cf31b5c11 100644 --- a/apps/opencs/model/world/idtableproxymodel.hpp +++ b/apps/opencs/model/world/idtableproxymodel.hpp @@ -27,6 +27,10 @@ namespace CSMWorld typedef std::map > EnumColumnCache; mutable EnumColumnCache mEnumColumnCache; + protected: + + IdTableBase *mSourceModel; + private: void updateColumnMap(); @@ -45,15 +49,23 @@ namespace CSMWorld protected: - bool lessThan(const QModelIndex &left, const QModelIndex &right) const; + virtual bool lessThan(const QModelIndex &left, const QModelIndex &right) const; virtual bool filterAcceptsRow (int sourceRow, const QModelIndex& sourceParent) const; - private slots: + QString getRecordId(int sourceRow) const; + + protected slots: + + virtual void sourceRowsInserted(const QModelIndex &parent, int start, int end); + + virtual void sourceRowsRemoved(const QModelIndex &parent, int start, int end); + + virtual void sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight); - void sourceRowsChanged(const QModelIndex &parent, int start, int end); + signals: - void sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight); + void rowAdded(const std::string &id); }; } From 86b7d2a43d2842eaab0938afbab699dcce4684e0 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sun, 26 Jul 2015 20:07:36 +0300 Subject: [PATCH 1939/3725] Inform about a row addition after re-sorting in InfoTableProxyModel --- .../model/world/infotableproxymodel.cpp | 56 ++++++++++++++----- .../model/world/infotableproxymodel.hpp | 12 ++-- 2 files changed, 50 insertions(+), 18 deletions(-) diff --git a/apps/opencs/model/world/infotableproxymodel.cpp b/apps/opencs/model/world/infotableproxymodel.cpp index 6216291d0..c6216ba5d 100644 --- a/apps/opencs/model/world/infotableproxymodel.cpp +++ b/apps/opencs/model/world/infotableproxymodel.cpp @@ -9,16 +9,17 @@ namespace { QString toLower(const QString &str) { - return QString::fromUtf8(Misc::StringUtils::lowerCase(str.toStdString()).c_str()); + return QString::fromUtf8(Misc::StringUtils::lowerCase(str.toUtf8().constData()).c_str()); } } CSMWorld::InfoTableProxyModel::InfoTableProxyModel(CSMWorld::UniversalId::Type type, QObject *parent) : IdTableProxyModel(parent), mType(type), - mSourceModel(NULL), mInfoColumnId(type == UniversalId::Type_TopicInfos ? Columns::ColumnId_Topic : - Columns::ColumnId_Journal) + Columns::ColumnId_Journal), + mInfoColumnIndex(-1), + mLastAddedSourceRow(-1) { Q_ASSERT(type == UniversalId::Type_TopicInfos || type == UniversalId::Type_JournalInfos); } @@ -26,23 +27,18 @@ CSMWorld::InfoTableProxyModel::InfoTableProxyModel(CSMWorld::UniversalId::Type t void CSMWorld::InfoTableProxyModel::setSourceModel(QAbstractItemModel *sourceModel) { IdTableProxyModel::setSourceModel(sourceModel); - mSourceModel = dynamic_cast(sourceModel); + if (mSourceModel != NULL) { - connect(mSourceModel, - SIGNAL(rowsInserted(const QModelIndex &, int, int)), - this, - SLOT(modelRowsChanged(const QModelIndex &, int, int))); - connect(mSourceModel, - SIGNAL(rowsRemoved(const QModelIndex &, int, int)), - this, - SLOT(modelRowsChanged(const QModelIndex &, int, int))); + mInfoColumnIndex = mSourceModel->findColumnIndex(mInfoColumnId); mFirstRowCache.clear(); } } bool CSMWorld::InfoTableProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const { + Q_ASSERT(mSourceModel != NULL); + QModelIndex first = mSourceModel->index(getFirstInfoRow(left.row()), left.column()); QModelIndex second = mSourceModel->index(getFirstInfoRow(right.row()), right.column()); @@ -56,8 +52,10 @@ bool CSMWorld::InfoTableProxyModel::lessThan(const QModelIndex &left, const QMod int CSMWorld::InfoTableProxyModel::getFirstInfoRow(int currentRow) const { + Q_ASSERT(mSourceModel != NULL); + int row = currentRow; - int column = mSourceModel->findColumnIndex(mInfoColumnId); + int column = mInfoColumnIndex; QString info = toLower(mSourceModel->data(mSourceModel->index(row, column)).toString()); if (mFirstRowCache.contains(info)) @@ -73,7 +71,37 @@ int CSMWorld::InfoTableProxyModel::getFirstInfoRow(int currentRow) const return row; } -void CSMWorld::InfoTableProxyModel::modelRowsChanged(const QModelIndex &/*parent*/, int /*start*/, int /*end*/) +void CSMWorld::InfoTableProxyModel::sourceRowsRemoved(const QModelIndex &/*parent*/, int /*start*/, int /*end*/) +{ + refreshFilter(); + mFirstRowCache.clear(); +} + +void CSMWorld::InfoTableProxyModel::sourceRowsInserted(const QModelIndex &/*parent*/, int /*start*/, int end) { + refreshFilter(); mFirstRowCache.clear(); + // We can't re-sort the model here, because the topic of the added row isn't set yet. + // Store the row index for using in the first dataChanged() after this row insertion. + mLastAddedSourceRow = end; +} + +void CSMWorld::InfoTableProxyModel::sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight) +{ + refreshFilter(); + + if (mLastAddedSourceRow != -1 && + topLeft.row() <= mLastAddedSourceRow && bottomRight.row() >= mLastAddedSourceRow) + { + // Now the topic of the last added row is set, + // so we can re-sort the model to ensure the corrent position of this row + int column = sortColumn(); + Qt::SortOrder order = sortOrder(); + sort(mInfoColumnIndex); // Restore the correct position of an added row + sort(column, order); // Restore the original sort order + emit rowAdded(getRecordId(mLastAddedSourceRow).toUtf8().constData()); + + // Make sure that we perform a re-sorting only in the first dataChanged() after a row insertion + mLastAddedSourceRow = -1; + } } diff --git a/apps/opencs/model/world/infotableproxymodel.hpp b/apps/opencs/model/world/infotableproxymodel.hpp index 28d6017b3..51d93f9a1 100644 --- a/apps/opencs/model/world/infotableproxymodel.hpp +++ b/apps/opencs/model/world/infotableproxymodel.hpp @@ -16,25 +16,29 @@ namespace CSMWorld Q_OBJECT UniversalId::Type mType; - IdTableBase *mSourceModel; Columns::ColumnId mInfoColumnId; ///< Contains ID for Topic or Journal ID + int mInfoColumnIndex; + int mLastAddedSourceRow; mutable QHash mFirstRowCache; int getFirstInfoRow(int currentRow) const; ///< Finds the first row with the same topic (journal entry) as in \a currentRow + ///< \a currentRow is a row of the source model. public: InfoTableProxyModel(UniversalId::Type type, QObject *parent = 0); - void setSourceModel(QAbstractItemModel *sourceModel); + virtual void setSourceModel(QAbstractItemModel *sourceModel); protected: virtual bool lessThan(const QModelIndex &left, const QModelIndex &right) const; - private slots: - void modelRowsChanged(const QModelIndex &parent, int start, int end); + protected slots: + virtual void sourceRowsInserted(const QModelIndex &parent, int start, int end); + virtual void sourceRowsRemoved(const QModelIndex &parent, int start, int end); + virtual void sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight); }; } From 2471e4d67a343ef8f64eb324feb08c8629f9d673 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sun, 26 Jul 2015 20:09:31 +0300 Subject: [PATCH 1940/3725] Rework Table to use rowAdded() signal of a proxy model --- apps/opencs/view/world/table.cpp | 11 +++++++---- apps/opencs/view/world/table.hpp | 2 +- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index 5a2a572e2..02a9bb07f 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -371,8 +371,10 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id, connect (mProxyModel, SIGNAL (rowsRemoved (const QModelIndex&, int, int)), this, SLOT (tableSizeUpdate())); - connect (mProxyModel, SIGNAL (rowsInserted (const QModelIndex&, int, int)), - this, SLOT (rowsInsertedEvent(const QModelIndex&, int, int))); + //connect (mProxyModel, SIGNAL (rowsInserted (const QModelIndex&, int, int)), + // this, SLOT (rowsInsertedEvent(const QModelIndex&, int, int))); + connect (mProxyModel, SIGNAL (rowAdded (const std::string &)), + this, SLOT (rowAdded (const std::string &))); /// \note This signal could instead be connected to a slot that filters out changes not affecting /// the records status column (for permanence reasons) @@ -714,12 +716,13 @@ std::vector< CSMWorld::UniversalId > CSVWorld::Table::getDraggedRecords() const return idToDrag; } -void CSVWorld::Table::rowsInsertedEvent(const QModelIndex& parent, int start, int end) +void CSVWorld::Table::rowAdded(const std::string &id) { tableSizeUpdate(); if(mJumpToAddedRecord) { - selectRow(end); + int idColumn = mModel->findColumnIndex(CSMWorld::Columns::ColumnId_Id); + selectRow(mProxyModel->getModelIndex(id, idColumn).row()); if(mUnselectAfterJump) clearSelection(); diff --git a/apps/opencs/view/world/table.hpp b/apps/opencs/view/world/table.hpp index adacd3a9d..7ddeff0a5 100644 --- a/apps/opencs/view/world/table.hpp +++ b/apps/opencs/view/world/table.hpp @@ -140,7 +140,7 @@ namespace CSVWorld void updateUserSetting (const QString &name, const QStringList &list); - void rowsInsertedEvent(const QModelIndex& parent, int start, int end); + void rowAdded(const std::string &id); }; } From 812fffbadcc4ef8c69cf7382ab0e4c8939a8ef9f Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sun, 26 Jul 2015 20:25:46 +0300 Subject: [PATCH 1941/3725] Don't inform about a nested row addition in proxy models for top-level tables --- apps/opencs/model/world/idtableproxymodel.cpp | 7 +++++-- apps/opencs/model/world/infotableproxymodel.cpp | 14 +++++++++----- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/apps/opencs/model/world/idtableproxymodel.cpp b/apps/opencs/model/world/idtableproxymodel.cpp index 8beccd497..10fd92b46 100644 --- a/apps/opencs/model/world/idtableproxymodel.cpp +++ b/apps/opencs/model/world/idtableproxymodel.cpp @@ -112,10 +112,13 @@ void CSMWorld::IdTableProxyModel::refreshFilter() invalidateFilter(); } -void CSMWorld::IdTableProxyModel::sourceRowsInserted(const QModelIndex &/*parent*/, int /*start*/, int end) +void CSMWorld::IdTableProxyModel::sourceRowsInserted(const QModelIndex &parent, int /*start*/, int end) { refreshFilter(); - emit rowAdded(getRecordId(end).toUtf8().constData()); + if (!parent.isValid()) + { + emit rowAdded(getRecordId(end).toUtf8().constData()); + } } void CSMWorld::IdTableProxyModel::sourceRowsRemoved(const QModelIndex &/*parent*/, int /*start*/, int /*end*/) diff --git a/apps/opencs/model/world/infotableproxymodel.cpp b/apps/opencs/model/world/infotableproxymodel.cpp index c6216ba5d..f55f775ab 100644 --- a/apps/opencs/model/world/infotableproxymodel.cpp +++ b/apps/opencs/model/world/infotableproxymodel.cpp @@ -77,13 +77,17 @@ void CSMWorld::InfoTableProxyModel::sourceRowsRemoved(const QModelIndex &/*paren mFirstRowCache.clear(); } -void CSMWorld::InfoTableProxyModel::sourceRowsInserted(const QModelIndex &/*parent*/, int /*start*/, int end) +void CSMWorld::InfoTableProxyModel::sourceRowsInserted(const QModelIndex &parent, int /*start*/, int end) { refreshFilter(); - mFirstRowCache.clear(); - // We can't re-sort the model here, because the topic of the added row isn't set yet. - // Store the row index for using in the first dataChanged() after this row insertion. - mLastAddedSourceRow = end; + + if (!parent.isValid()) + { + mFirstRowCache.clear(); + // We can't re-sort the model here, because the topic of the added row isn't set yet. + // Store the row index for using in the first dataChanged() after this row insertion. + mLastAddedSourceRow = end; + } } void CSMWorld::InfoTableProxyModel::sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight) From ac1f64b5593f742fe34017dd07077a6c0da71956 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 28 Jul 2015 03:20:18 +0200 Subject: [PATCH 1942/3725] Fix StencilProperty front face mixup (Fixes #2802) --- components/nifosg/nifloader.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index b5439afee..6824c0afd 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -1159,11 +1159,11 @@ namespace NifOsg osg::FrontFace* frontFace = new osg::FrontFace; switch (stencilprop->data.drawMode) { - case 1: + case 2: frontFace->setMode(osg::FrontFace::CLOCKWISE); break; case 0: - case 2: + case 1: default: frontFace->setMode(osg::FrontFace::COUNTER_CLOCKWISE); break; From 26656707dd16a0ffd1be105ce3b34cdb0d55b8c4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 27 Jul 2015 22:59:20 +0200 Subject: [PATCH 1943/3725] Use marker_error.nif as replacement when a mesh fails to load --- components/resource/scenemanager.cpp | 15 ++++++++++++--- components/resource/scenemanager.hpp | 4 ++++ 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index efaccec13..08fa7bc9b 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -100,11 +100,20 @@ namespace Resource Index::iterator it = mIndex.find(normalized); if (it == mIndex.end()) { - Files::IStreamPtr file = mVFS->get(normalized); - // TODO: add support for non-NIF formats + osg::ref_ptr loaded; + try + { + Files::IStreamPtr file = mVFS->get(normalized); - osg::ref_ptr loaded = NifOsg::Loader::load(Nif::NIFFilePtr(new Nif::NIFFile(file, normalized)), mTextureManager); + loaded = NifOsg::Loader::load(Nif::NIFFilePtr(new Nif::NIFFile(file, normalized)), mTextureManager); + } + catch (std::exception& e) + { + std::cerr << "Failed to load '" << name << "': " << e.what() << ", using marker_error.nif instead" << std::endl; + Files::IStreamPtr file = mVFS->get("meshes/marker_error.nif"); + loaded = NifOsg::Loader::load(Nif::NIFFilePtr(new Nif::NIFFile(file, normalized)), mTextureManager); + } osgDB::Registry::instance()->getOrCreateSharedStateManager()->share(loaded.get()); // TODO: run SharedStateManager::prune on unload diff --git a/components/resource/scenemanager.hpp b/components/resource/scenemanager.hpp index 1dabe45e0..168247a15 100644 --- a/components/resource/scenemanager.hpp +++ b/components/resource/scenemanager.hpp @@ -38,12 +38,16 @@ namespace Resource ~SceneManager(); /// Get a read-only copy of this scene "template" + /// @note If the given filename does not exist or fails to load, an error marker mesh will be used instead. + /// If even the error marker mesh can not be found, an exception is thrown. osg::ref_ptr getTemplate(const std::string& name); /// Create an instance of the given scene template + /// @see getTemplate osg::ref_ptr createInstance(const std::string& name); /// Create an instance of the given scene template and immediately attach it to a parent node + /// @see getTemplate osg::ref_ptr createInstance(const std::string& name, osg::Group* parentNode); /// Attach the given scene instance to the given parent node From 7ba399fc92fd676a0c1f896fa9521c4d9acdea8a Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 27 Jul 2015 23:19:35 +0200 Subject: [PATCH 1944/3725] Change a message to upper case spelling More consistent with other loading messages --- apps/openmw/mwworld/scene.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 9ffc4071d..48e346c14 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -233,7 +233,7 @@ namespace MWWorld if(result.second) { - std::cout << "loading cell " << cell->getCell()->getDescription() << std::endl; + std::cout << "Loading cell " << cell->getCell()->getDescription() << std::endl; float verts = ESM::Land::LAND_SIZE; float worldsize = ESM::Land::REAL_SIZE; From 2a653e45fd443fa58702f3505115aad713a00018 Mon Sep 17 00:00:00 2001 From: Arthur Moore Date: Tue, 21 Jul 2015 22:08:37 -0400 Subject: [PATCH 1945/3725] (Re) Wrote a tool to test NIF files in BSAs and on the filesystem. Just give it a set of files, one file per argument, and it will make sure openmw can read them. --- CMakeLists.txt | 8 ++++ apps/niftest/CMakeLists.txt | 19 ++++++++ apps/niftest/find_bad_nifs.sh | 28 +++++++++++ apps/niftest/niftest.cpp | 87 +++++++++++++++++++++++++++++++++++ 4 files changed, 142 insertions(+) create mode 100644 apps/niftest/CMakeLists.txt create mode 100755 apps/niftest/find_bad_nifs.sh create mode 100644 apps/niftest/niftest.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 656602b9e..a14beb423 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -72,6 +72,7 @@ option(BUILD_OPENCS "build OpenMW Construction Set" ON) option(BUILD_WIZARD "build Installation Wizard" ON) option(BUILD_WITH_CODE_COVERAGE "Enable code coverage with gconv" OFF) option(BUILD_UNITTESTS "Enable Unittests with Google C++ Unittest" OFF) +option(BUILD_NIFTEST "build nif file tester" OFF) option(BUILD_MYGUI_PLUGIN "build MyGUI plugin for OpenMW resources, to use with MyGUI tools" ON) # OS X deployment @@ -396,6 +397,9 @@ IF(NOT WIN32 AND NOT APPLE) IF(BUILD_ESMTOOL) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/esmtool" DESTINATION "${BINDIR}" ) ENDIF(BUILD_ESMTOOL) + IF(BUILD_NIFTEST) + INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/niftest" DESTINATION "${BINDIR}" ) + ENDIF(BUILD_NIFTEST) IF(BUILD_MWINIIMPORTER) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/openmw-iniimporter" DESTINATION "${BINDIR}" ) ENDIF(BUILD_MWINIIMPORTER) @@ -581,6 +585,10 @@ if (BUILD_WIZARD) add_subdirectory(apps/wizard) endif() +if (BUILD_NIFTEST) + add_subdirectory(apps/niftest) +endif(BUILD_NIFTEST) + # UnitTests if (BUILD_UNITTESTS) add_subdirectory( apps/openmw_test_suite ) diff --git a/apps/niftest/CMakeLists.txt b/apps/niftest/CMakeLists.txt new file mode 100644 index 000000000..d7f0200d2 --- /dev/null +++ b/apps/niftest/CMakeLists.txt @@ -0,0 +1,19 @@ +set(NIFTEST + niftest.cpp +) +source_group(components\\nif\\tests FILES ${NIFTEST}) + +# Main executable +add_executable(niftest + ${NIFTEST} +) + +target_link_libraries(niftest + ${Boost_FILESYSTEM_LIBRARY} + components +) + +if (BUILD_WITH_CODE_COVERAGE) + add_definitions (--coverage) + target_link_libraries(niftest gcov) +endif() diff --git a/apps/niftest/find_bad_nifs.sh b/apps/niftest/find_bad_nifs.sh new file mode 100755 index 000000000..4b599f442 --- /dev/null +++ b/apps/niftest/find_bad_nifs.sh @@ -0,0 +1,28 @@ +#!/bin/bash +#Script to test all nif files (both loose, and in BSA archives) in data files directory + +#The user input as an absolute path +DATAFILESDIR="`readlink -m "$1"`" +#Program used to test +TEST_PROG="`pwd`/niftest" + +#Make sure our files don't bother anyone +NIFTEST_TMP_DIR="/tmp/niftest_$RANDOM/" +mkdir "$NIFTEST_TMP_DIR" +cd "$NIFTEST_TMP_DIR" + +find "$DATAFILESDIR" -iname *bsa > nifs.txt +find "$DATAFILESDIR" -iname *nif >> nifs.txt + +sed -e 's/.*/\"&\"/' nifs.txt > quoted_nifs.txt + +xargs --arg-file=quoted_nifs.txt "$TEST_PROG" 2>&1 | tee nif_out.txt +# xargs --arg-file=quoted_nifs.txt "$TEST_PROG" 2> nif_out.txt >/dev/null + +echo "List of bad NIF Files:" +cat nif_out.txt|grep File:|cut -d ' ' -f 2- + +rm nifs.txt +rm quoted_nifs.txt +rm nif_out.txt +rmdir "$NIFTEST_TMP_DIR" diff --git a/apps/niftest/niftest.cpp b/apps/niftest/niftest.cpp new file mode 100644 index 000000000..20c8597f3 --- /dev/null +++ b/apps/niftest/niftest.cpp @@ -0,0 +1,87 @@ +///Program to test .nif files both on the FileSystem and in BSA archives. + +#include +#include + +#include +#include +#include +#include + + +///See if the file has the named extension +bool hasExtension(std::string filename, std::string extensionToFind) +{ + std::string extension = filename.substr(filename.find_last_of(".")+1); + + //Convert strings to lower case for comparison + std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower); + std::transform(extensionToFind.begin(), extensionToFind.end(), extensionToFind.begin(), ::tolower); + + if(extension == extensionToFind) + return true; + else + return false; +} + +///See if the file has the "nif" extension. +bool isNIF(std::string filename) +{ + return hasExtension(filename,"nif"); +} +///See if the file has the "bsa" extension. +bool isBSA(std::string filename) +{ + return hasExtension(filename,"bsa"); +} + +///Check all the nif files in the given BSA archive +void readBSA(std::string filename) +{ + VFS::Manager myManager(false); + myManager.addArchive(new VFS::BsaArchive(filename)); + myManager.buildIndex(); + + std::map files=myManager.getIndex(); + for(std::map::const_iterator it=files.begin(); it!=files.end(); ++it) + { + std::string name = it->first; + if(isNIF(name)) + { +// std::cout << "Decoding: " << name << std::endl; + Nif::NIFFile temp_nif(myManager.get(name),name); + } + } +} + +int main(int argc, char **argv) +{ + + std::cout << "Reading Files" << std::endl; + for(int i = 1; i Date: Tue, 28 Jul 2015 15:04:22 +0300 Subject: [PATCH 1946/3725] Make saving of deleted ESM records more consistent --- components/esm/cellref.cpp | 67 +++++++++++++++++-------------------- components/esm/cellref.hpp | 3 -- components/esm/loadbsgn.cpp | 5 +-- components/esm/loadcell.cpp | 18 ++++------ components/esm/loadland.cpp | 1 + components/esm/loadltex.cpp | 8 ++--- components/esm/loadpgrd.cpp | 12 +++---- components/esm/loadregn.cpp | 4 ++- components/esm/loadscpt.cpp | 1 + components/esm/loadsndg.cpp | 11 +++--- components/esm/loadsscr.cpp | 20 ++++++----- 11 files changed, 71 insertions(+), 79 deletions(-) diff --git a/components/esm/cellref.cpp b/components/esm/cellref.cpp index 9a0c8f1cc..7cd8186bd 100644 --- a/components/esm/cellref.cpp +++ b/components/esm/cellref.cpp @@ -25,33 +25,6 @@ void ESM::RefNum::save (ESMWriter &esm, bool wide, const std::string& tag) const } -void ESM::CellRef::clearData() -{ - mScale = 1; - mOwner.clear(); - mGlobalVariable.clear(); - mSoul.clear(); - mFaction.clear(); - mFactionRank = -2; - mChargeInt = -1; - mEnchantmentCharge = -1; - mGoldValue = 0; - mDestCell.clear(); - mLockLevel = 0; - mKey.clear(); - mTrap.clear(); - mReferenceBlocked = -1; - mTeleport = false; - - for (int i=0; i<3; ++i) - { - mDoorDest.pos[i] = 0; - mDoorDest.rot[i] = 0; - mPos.pos[i] = 0; - mPos.rot[i] = 0; - } -} - void ESM::CellRef::load (ESMReader& esm, bool &isDeleted, bool wideRefNum) { loadId(esm, wideRefNum); @@ -67,6 +40,8 @@ void ESM::CellRef::loadId (ESMReader& esm, bool wideRefNum) if (esm.isNextSub ("NAM0")) esm.skipHSub(); + blank(); + mRefNum.load (esm, wideRefNum); mRefID = esm.getHNString ("NAME"); @@ -76,8 +51,6 @@ void ESM::CellRef::loadData(ESMReader &esm, bool &isDeleted) { isDeleted = false; - clearData(); - bool isLoaded = false; while (!isLoaded && esm.hasMoreSubs()) { @@ -154,6 +127,11 @@ void ESM::CellRef::save (ESMWriter &esm, bool wideRefNum, bool inInventory, bool esm.writeHNCString("NAME", mRefID); + if (isDeleted) { + esm.writeHNCString("DELE", ""); + return; + } + if (mScale != 1.0) { esm.writeHNT("XSCL", mScale); } @@ -198,18 +176,35 @@ void ESM::CellRef::save (ESMWriter &esm, bool wideRefNum, bool inInventory, bool if (!inInventory) esm.writeHNT("DATA", mPos, 24); - - if (isDeleted) - { - esm.writeHNCString("DELE", ""); - } } void ESM::CellRef::blank() { mRefNum.unset(); - mRefID.clear(); - clearData(); + mRefID.clear(); + mScale = 1; + mOwner.clear(); + mGlobalVariable.clear(); + mSoul.clear(); + mFaction.clear(); + mFactionRank = -2; + mChargeInt = -1; + mEnchantmentCharge = -1; + mGoldValue = 0; + mDestCell.clear(); + mLockLevel = 0; + mKey.clear(); + mTrap.clear(); + mReferenceBlocked = -1; + mTeleport = false; + + for (int i=0; i<3; ++i) + { + mDoorDest.pos[i] = 0; + mDoorDest.rot[i] = 0; + mPos.pos[i] = 0; + mPos.rot[i] = 0; + } } bool ESM::operator== (const RefNum& left, const RefNum& right) diff --git a/components/esm/cellref.hpp b/components/esm/cellref.hpp index a9edd291e..c371a4f01 100644 --- a/components/esm/cellref.hpp +++ b/components/esm/cellref.hpp @@ -33,10 +33,7 @@ namespace ESM class CellRef { - void clearData(); - public: - // Reference number // Note: Currently unused for items in containers RefNum mRefNum; diff --git a/components/esm/loadbsgn.cpp b/components/esm/loadbsgn.cpp index 56dc1897c..0413a8610 100644 --- a/components/esm/loadbsgn.cpp +++ b/components/esm/loadbsgn.cpp @@ -52,12 +52,13 @@ namespace ESM void BirthSign::save(ESMWriter &esm, bool isDeleted) const { + esm.writeHNCString("NAME", mId); + if (isDeleted) { esm.writeHNCString("DELE", ""); + return; } - - esm.writeHNCString("NAME", mId); esm.writeHNOCString("FNAM", mName); esm.writeHNOCString("TNAM", mTexture); esm.writeHNOCString("DESC", mDescription); diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index 2d8daa584..703a4f4cb 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -62,7 +62,8 @@ namespace ESM { isDeleted = false; - bool hasName = false; + blank(); + bool hasData = false; bool isLoaded = false; while (!isLoaded && esm.hasMoreSubs()) @@ -72,7 +73,6 @@ namespace ESM { case ESM::FourCC<'N','A','M','E'>::value: mName = esm.getHString(); - hasName = true; break; case ESM::FourCC<'D','A','T','A'>::value: esm.getHT(mData, 12); @@ -89,20 +89,12 @@ namespace ESM } } - if (!hasName) - esm.fail("Missing NAME subrecord"); if (!hasData) esm.fail("Missing DATA subrecord"); } void Cell::loadCell(ESMReader &esm, bool saveContext) { - mWater = 0.0f; - mWaterInt = false; - mMapColor = 0; - mRegion.clear(); - mRefNumCounter = 0; - bool isLoaded = false; while (!isLoaded && esm.hasMoreSubs()) { @@ -117,6 +109,7 @@ namespace ESM break; case ESM::FourCC<'W','H','G','T'>::value: esm.getHT(mWater); + mWaterInt = false; break; case ESM::FourCC<'A','M','B','I'>::value: esm.getHT(mAmbi); @@ -153,14 +146,15 @@ namespace ESM void Cell::save(ESMWriter &esm, bool isDeleted) const { - esm.writeHNCString("NAME", mName); + esm.writeHNOCString("NAME", mName); + esm.writeHNT("DATA", mData, 12); if (isDeleted) { esm.writeHNCString("DELE", ""); + return; } - esm.writeHNT("DATA", mData, 12); if (mData.mFlags & Interior) { if (mWaterInt) { diff --git a/components/esm/loadland.cpp b/components/esm/loadland.cpp index 2ffd2a21b..1317fc71c 100644 --- a/components/esm/loadland.cpp +++ b/components/esm/loadland.cpp @@ -167,6 +167,7 @@ namespace ESM if (isDeleted) { esm.writeHNCString("DELE", ""); + return; } if (mLandData) diff --git a/components/esm/loadltex.cpp b/components/esm/loadltex.cpp index cf026dbf1..e9cd4578d 100644 --- a/components/esm/loadltex.cpp +++ b/components/esm/loadltex.cpp @@ -47,14 +47,14 @@ namespace ESM } void LandTexture::save(ESMWriter &esm, bool isDeleted) const { + esm.writeHNCString("NAME", mId); + esm.writeHNT("INTV", mIndex); + esm.writeHNCString("DATA", mTexture); + if (isDeleted) { esm.writeHNCString("DELE", ""); } - - esm.writeHNCString("NAME", mId); - esm.writeHNT("INTV", mIndex); - esm.writeHNCString("DATA", mTexture); } void LandTexture::blank() diff --git a/components/esm/loadpgrd.cpp b/components/esm/loadpgrd.cpp index 8027be91c..95e6a906f 100644 --- a/components/esm/loadpgrd.cpp +++ b/components/esm/loadpgrd.cpp @@ -43,20 +43,18 @@ namespace ESM int edgeCount = 0; bool hasData = false; - bool hasName = false; while (esm.hasMoreSubs()) { esm.getSubName(); switch (esm.retSubName().val) { + case ESM::FourCC<'N','A','M','E'>::value: + mCell = esm.getHString(); + break; case ESM::FourCC<'D','A','T','A'>::value: esm.getHT(mData, 12); hasData = true; break; - case ESM::FourCC<'N','A','M','E'>::value: - mCell = esm.getHString(); - hasName = true; - break; case ESM::FourCC<'P','G','R','P'>::value: { esm.getSubHeader(); @@ -125,14 +123,12 @@ namespace ESM if (!hasData) esm.fail("Missing DATA subrecord"); - if (!hasName) - esm.fail("Missing NAME subrecord"); } void Pathgrid::save(ESMWriter &esm, bool isDeleted) const { - esm.writeHNT("DATA", mData, 12); esm.writeHNCString("NAME", mCell); + esm.writeHNT("DATA", mData, 12); if (isDeleted) { diff --git a/components/esm/loadregn.cpp b/components/esm/loadregn.cpp index add821c3e..9f3089763 100644 --- a/components/esm/loadregn.cpp +++ b/components/esm/loadregn.cpp @@ -81,12 +81,14 @@ namespace ESM void Region::save(ESMWriter &esm, bool isDeleted) const { + esm.writeHNCString("NAME", mId); + if (isDeleted) { esm.writeHNCString("DELE", ""); + return; } - esm.writeHNString("NAME", mId); esm.writeHNOCString("FNAM", mName); if (esm.getVersion() == VER_12) diff --git a/components/esm/loadscpt.cpp b/components/esm/loadscpt.cpp index e433ddede..2a0542138 100644 --- a/components/esm/loadscpt.cpp +++ b/components/esm/loadscpt.cpp @@ -120,6 +120,7 @@ namespace ESM if (isDeleted) { esm.writeHNCString("DELE", ""); + return; } if (!mVarNames.empty()) diff --git a/components/esm/loadsndg.cpp b/components/esm/loadsndg.cpp index 400b1072b..189cc97df 100644 --- a/components/esm/loadsndg.cpp +++ b/components/esm/loadsndg.cpp @@ -51,14 +51,17 @@ namespace ESM void SoundGenerator::save(ESMWriter &esm, bool isDeleted) const { esm.writeHNCString("NAME", mId); - esm.writeHNT("DATA", mType, 4); - esm.writeHNOCString("CNAM", mCreature); - esm.writeHNOCString("SNAM", mSound); - + if (isDeleted) { esm.writeHNCString("DELE", ""); + return; } + + esm.writeHNT("DATA", mType, 4); + esm.writeHNOCString("CNAM", mCreature); + esm.writeHNOCString("SNAM", mSound); + } void SoundGenerator::blank() diff --git a/components/esm/loadsscr.cpp b/components/esm/loadsscr.cpp index 6af6c96dc..a211a99bf 100644 --- a/components/esm/loadsscr.cpp +++ b/components/esm/loadsscr.cpp @@ -19,14 +19,14 @@ namespace ESM esm.getSubName(); switch (esm.retSubName().val) { - case ESM::FourCC<'D','A','T','A'>::value: - mData = esm.getHString(); - hasData = true; - break; case ESM::FourCC<'N','A','M','E'>::value: mId = esm.getHString(); hasName = true; break; + case ESM::FourCC<'D','A','T','A'>::value: + mData = esm.getHString(); + hasData = true; + break; case ESM::FourCC<'D','E','L','E'>::value: esm.skipHSub(); isDeleted = true; @@ -37,20 +37,22 @@ namespace ESM } } - if (!hasData) - esm.fail("Missing DATA"); if (!hasName) esm.fail("Missing NAME"); + if (!hasData && !isDeleted) + esm.fail("Missing DATA"); } void StartScript::save(ESMWriter &esm, bool isDeleted) const { - esm.writeHNString("DATA", mData); - esm.writeHNString("NAME", mId); - + esm.writeHNCString("NAME", mId); if (isDeleted) { esm.writeHNCString("DELE", ""); } + else + { + esm.writeHNString("DATA", mData); + } } void StartScript::blank() From 3a7d0d8dc8a6f2c5d066cbdd7775cc72dfdda0cc Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 28 Jul 2015 23:34:36 +0200 Subject: [PATCH 1947/3725] Remove a file that isn't in use yet from build --- components/CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index cf0c83fbd..946c3af16 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -41,7 +41,9 @@ add_component_dir (resource ) add_component_dir (sceneutil - clone attach lightmanager visitor util statesetupdater controller skeleton riggeometry lightcontroller workqueue + clone attach lightmanager visitor util statesetupdater controller skeleton riggeometry lightcontroller + # not used yet + #workqueue ) add_component_dir (nif From d7ad0ee14895c1aba8168fef40494bb0fb0ef61c Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 28 Jul 2015 23:35:10 +0200 Subject: [PATCH 1948/3725] Print a sensible error message when S3TC support is missing (Fixes #2800) --- components/resource/texturemanager.cpp | 33 +++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/components/resource/texturemanager.cpp b/components/resource/texturemanager.cpp index 87431ffcd..4bd712ea5 100644 --- a/components/resource/texturemanager.cpp +++ b/components/resource/texturemanager.cpp @@ -1,6 +1,7 @@ #include "texturemanager.hpp" #include +#include #include @@ -73,7 +74,7 @@ namespace Resource { osg::ref_ptr tex = it->second; - // Keep mip-mapping disabled if the texture creator explicitely requested it. + // Keep mip-mapping disabled if the texture creator explicitely requested no mipmapping. osg::Texture::FilterMode oldMin = tex->getFilter(osg::Texture::MIN_FILTER); if (oldMin == osg::Texture::LINEAR || oldMin == osg::Texture::NEAREST) { @@ -108,6 +109,32 @@ namespace Resource } */ + bool checkSupported(osg::Image* image, const std::string& filename) + { + switch(image->getPixelFormat()) + { + case(GL_COMPRESSED_RGB_S3TC_DXT1_EXT): + case(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT): + case(GL_COMPRESSED_RGBA_S3TC_DXT3_EXT): + case(GL_COMPRESSED_RGBA_S3TC_DXT5_EXT): + { + osg::Texture::Extensions* exts = osg::Texture::getExtensions(0, false); + if (exts && !exts->isTextureCompressionS3TCSupported() + // This one works too. Should it be included in isTextureCompressionS3TCSupported()? Submitted as a patch to OSG. + && !osg::isGLExtensionSupported(0, "GL_S3_s3tc")) + { + std::cerr << "Error loading " << filename << ": no S3TC texture compression support installed" << std::endl; + return false; + } + break; + } + // not bothering with checks for other compression formats right now, we are unlikely to ever use those anyway + default: + return true; + } + return true; + } + osg::ref_ptr TextureManager::getTexture2D(const std::string &filename, osg::Texture::WrapMode wrapS, osg::Texture::WrapMode wrapT) { std::string normalized = filename; @@ -152,6 +179,10 @@ namespace Resource } osg::Image* image = result.getImage(); + if (!checkSupported(image, filename)) + { + return mWarningTexture; + } // We need to flip images, because the Morrowind texture coordinates use the DirectX convention (top-left image origin), // but OpenGL uses bottom left as the image origin. From 2d93a6f6cb906dea5a4207cd65d786a5dcfc8fc0 Mon Sep 17 00:00:00 2001 From: Arthur Moore Date: Tue, 28 Jul 2015 18:46:11 -0400 Subject: [PATCH 1949/3725] Be more verbose when dealing with unhandled nif texture properties --- components/nifosg/nifloader.cpp | 35 ++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 6824c0afd..c98008394 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -903,7 +903,7 @@ namespace NifOsg int uvSet = *it; if (uvSet >= (int)data->uvlist.size()) { - std::cerr << "Warning: using an undefined UV set " << uvSet << " on TriShape " << triShape->name << " in " << mFilename << std::endl; + std::cerr << "Warning: using an undefined UV set " << uvSet << " on TriShape \"" << triShape->name << "\" in " << mFilename << std::endl; continue; } @@ -1264,13 +1264,34 @@ namespace NifOsg { if (texprop->textures[i].inUse) { - if (i != Nif::NiTexturingProperty::BaseTexture - && i != Nif::NiTexturingProperty::GlowTexture - && i != Nif::NiTexturingProperty::DarkTexture - && i != Nif::NiTexturingProperty::DetailTexture) + switch(i) { - std::cerr << "Warning: unhandled texture stage " << i << " in " << mFilename << std::endl; - continue; + //These are handled later on + case Nif::NiTexturingProperty::BaseTexture: + case Nif::NiTexturingProperty::GlowTexture: + case Nif::NiTexturingProperty::DarkTexture: + case Nif::NiTexturingProperty::DetailTexture: + break; + case Nif::NiTexturingProperty::GlossTexture: + { + std::cerr << "NiTexturingProperty::GlossTexture in " << mFilename << " not currently used." << std::endl; + continue; + } + case Nif::NiTexturingProperty::BumpTexture: + { + std::cerr << "NiTexturingProperty::BumpTexture in " << mFilename << " not currently used." << std::endl; + continue; + } + case Nif::NiTexturingProperty::DecalTexture: + { + std::cerr << "NiTexturingProperty::DecalTexture in " << mFilename << " not currently used." << std::endl; + continue; + } + default: + { + std::cerr << "Warning: unhandled texture stage " << i << " in " << mFilename << std::endl; + continue; + } } const Nif::NiTexturingProperty::Texture& tex = texprop->textures[i]; From 20106bb90f4c21ba47d28db0675ad5292107df7f Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 29 Jul 2015 14:45:56 +0200 Subject: [PATCH 1950/3725] allow keywords in quotes (Fixes #2794) --- components/compiler/scanner.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/components/compiler/scanner.cpp b/components/compiler/scanner.cpp index 83d435962..de7f7e1e1 100644 --- a/components/compiler/scanner.cpp +++ b/components/compiler/scanner.cpp @@ -281,8 +281,10 @@ namespace Compiler if (name.size()>=2 && name[0]=='"' && name[name.size()-1]=='"') { name = name.substr (1, name.size()-2); - cont = parser.parseName (name, loc, *this); - return true; +// allow keywords enclosed in "" +/// \todo optionally disable +// cont = parser.parseName (name, loc, *this); +// return true; } int i = 0; From 24ba54f4feb65161e306cba91b3270aa6efcdbfb Mon Sep 17 00:00:00 2001 From: slothlife Date: Wed, 29 Jul 2015 23:57:45 -0500 Subject: [PATCH 1951/3725] Implement accurate moon settings (fixes #672) --- apps/openmw/mwrender/sky.cpp | 164 ++++++++------------ apps/openmw/mwrender/sky.hpp | 37 +++-- apps/openmw/mwworld/weather.cpp | 264 ++++++++++++++++++++------------ apps/openmw/mwworld/weather.hpp | 35 ++++- 4 files changed, 291 insertions(+), 209 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 49c00c33d..cf20bc4c6 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1,5 +1,8 @@ #include "sky.hpp" +#define _USE_MATH_DEFINES +#include + #include #include #include @@ -383,26 +386,29 @@ public: Moon(osg::Group* parentNode, Resource::SceneManager* sceneManager, float scaleFactor, Type type) : CelestialBody(parentNode, sceneManager, scaleFactor, 2) , mType(type) - , mPhase(Phase_Unspecified) + , mPhase(MoonState::Phase_Unspecified) { mUpdater = new MoonUpdater; mGeode->addUpdateCallback(mUpdater); - setPhase(Phase_WaxingCrescent); + setPhase(MoonState::Phase_Full); + setVisible(true); } - enum Phase - { - Phase_New = 0, - Phase_WaxingCrescent, - Phase_WaxingHalf, - Phase_WaxingGibbous, - Phase_Full, - Phase_WaningGibbous, - Phase_WaningHalf, - Phase_WaningCrescent, - Phase_Unspecified - }; + void setState(const MoonState& state) + { + float radsX = ((state.mRotationFromHorizon) * M_PI) / 180.0f; + float radsY = 0; + float radsZ = ((state.mRotationFromNorth) * M_PI) / 180.0f; + + osg::Quat rotation(radsX, osg::Vec3f(1.0f, 0.0f, 0.0f), + radsY, osg::Vec3f(0.0f, 1.0f, 0.0f), + radsZ, osg::Vec3f(0.0f, 0.0f, 1.0f)); + setDirection(rotation * osg::Vec3f(0.0f, 1.0f, 0.0f)); + setPhase(state.mPhase); + setTransparency(state.mMoonAlpha); + setShadowBlend(state.mShadowBlend); + } void setTextures(const std::string& phaseTex, const std::string& circleTex) { @@ -415,7 +421,7 @@ public: mUpdater->setTextures(phaseTexPtr, circleTexPtr); } - void setPhase(const Phase& phase) + void setPhase(const MoonState::Phase& phase) { if (mPhase == phase) return; @@ -426,14 +432,14 @@ public: if (mType == Moon::Type_Secunda) textureName += "secunda_"; else textureName += "masser_"; - if (phase == Moon::Phase_New) textureName += "new"; - else if (phase == Moon::Phase_WaxingCrescent) textureName += "one_wax"; - else if (phase == Moon::Phase_WaxingHalf) textureName += "half_wax"; - else if (phase == Moon::Phase_WaxingGibbous) textureName += "three_wax"; - else if (phase == Moon::Phase_WaningCrescent) textureName += "one_wan"; - else if (phase == Moon::Phase_WaningHalf) textureName += "half_wan"; - else if (phase == Moon::Phase_WaningGibbous) textureName += "three_wan"; - else if (phase == Moon::Phase_Full) textureName += "full"; + if (phase == MoonState::Phase_New) textureName += "new"; + else if (phase == MoonState::Phase_WaxingCrescent) textureName += "one_wax"; + else if (phase == MoonState::Phase_FirstQuarter) textureName += "half_wax"; + else if (phase == MoonState::Phase_WaxingGibbous) textureName += "three_wax"; + else if (phase == MoonState::Phase_WaningCrescent) textureName += "one_wan"; + else if (phase == MoonState::Phase_ThirdQuarter) textureName += "half_wan"; + else if (phase == MoonState::Phase_WaningGibbous) textureName += "three_wan"; + else if (phase == MoonState::Phase_Full) textureName += "full"; textureName += ".dds"; @@ -452,7 +458,8 @@ public: { public: MoonUpdater() - : mFade(0.f) + : mTransparency(1.0f) + , mShadowBlend(1.0f) , mMoonColor(1,1,1,1) { } @@ -464,7 +471,7 @@ public: texEnv->setCombine_RGB(osg::TexEnvCombine::MODULATE); texEnv->setSource0_RGB(osg::TexEnvCombine::CONSTANT); texEnv->setSource1_RGB(osg::TexEnvCombine::TEXTURE); - texEnv->setConstantColor(osg::Vec4f(1.f, 0.f, 0.f, 1.f)); // fade * MoonRedColor + texEnv->setConstantColor(osg::Vec4f(1.f, 0.f, 0.f, 1.f)); // mShadowBlend * mMoonColor stateset->setTextureAttributeAndModes(0, texEnv, osg::StateAttribute::ON); stateset->setTextureAttributeAndModes(1, mCircleTex, osg::StateAttribute::ON); @@ -475,7 +482,7 @@ public: texEnv2->setSource1_Alpha(osg::TexEnvCombine::CONSTANT); texEnv2->setSource0_RGB(osg::TexEnvCombine::PREVIOUS); texEnv2->setSource1_RGB(osg::TexEnvCombine::CONSTANT); - texEnv2->setConstantColor(osg::Vec4f(0.f, 0.f, 0.f, 1.f)); // atmospherecolor + texEnv2->setConstantColor(osg::Vec4f(0.f, 0.f, 0.f, 1.f)); // mAtmosphereColor.rgb, mTransparency stateset->setTextureAttributeAndModes(1, texEnv2, osg::StateAttribute::ON); stateset->setAttributeAndModes(createUnlitMaterial(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); @@ -484,21 +491,20 @@ public: virtual void apply(osg::StateSet *stateset, osg::NodeVisitor*) { osg::TexEnvCombine* texEnv = static_cast(stateset->getTextureAttribute(0, osg::StateAttribute::TEXENV)); - texEnv->setConstantColor(mMoonColor * mFade); + texEnv->setConstantColor(mMoonColor * mShadowBlend); osg::TexEnvCombine* texEnv2 = static_cast(stateset->getTextureAttribute(1, osg::StateAttribute::TEXENV)); - const float backdropFadeThreshold = 0.03; - if (mFade <= backdropFadeThreshold) - { - texEnv2->setConstantColor(osg::Vec4f(mAtmosphereColor.x(), mAtmosphereColor.y(), mAtmosphereColor.z(), mFade / backdropFadeThreshold)); - } - else - texEnv2->setConstantColor(mAtmosphereColor); + texEnv2->setConstantColor(osg::Vec4f(mAtmosphereColor.x(), mAtmosphereColor.y(), mAtmosphereColor.z(), mTransparency)); } - void setFade (const float fade) + void setTransparency(const float ratio) { - mFade = fade; + mTransparency = ratio; + } + + void setShadowBlend(const float blendFactor) + { + mShadowBlend = blendFactor; } void setAtmosphereColor(const osg::Vec4f& color) @@ -519,7 +525,8 @@ public: } private: - float mFade; + float mTransparency; + float mShadowBlend; osg::Vec4f mAtmosphereColor; osg::Vec4f mMoonColor; osg::ref_ptr mPhaseTex; @@ -537,27 +544,32 @@ public: mUpdater->setMoonColor(color); } - void setFade(const float fade) + void setTransparency(const float ratio) + { + mUpdater->setTransparency(ratio); + } + + void setShadowBlend(const float blendFactor) { - mUpdater->setFade(fade); + mUpdater->setShadowBlend(blendFactor); } unsigned int getPhaseInt() const { - if (mPhase == Moon::Phase_New) return 0; - else if (mPhase == Moon::Phase_WaxingCrescent) return 1; - else if (mPhase == Moon::Phase_WaningCrescent) return 1; - else if (mPhase == Moon::Phase_WaxingHalf) return 2; - else if (mPhase == Moon::Phase_WaningHalf) return 2; - else if (mPhase == Moon::Phase_WaxingGibbous) return 3; - else if (mPhase == Moon::Phase_WaningGibbous) return 3; - else if (mPhase == Moon::Phase_Full) return 4; + if (mPhase == MoonState::Phase_New) return 0; + else if (mPhase == MoonState::Phase_WaxingCrescent) return 1; + else if (mPhase == MoonState::Phase_WaningCrescent) return 1; + else if (mPhase == MoonState::Phase_FirstQuarter) return 2; + else if (mPhase == MoonState::Phase_ThirdQuarter) return 2; + else if (mPhase == MoonState::Phase_WaxingGibbous) return 3; + else if (mPhase == MoonState::Phase_WaningGibbous) return 3; + else if (mPhase == MoonState::Phase_Full) return 4; return 0; } private: Type mType; - Phase mPhase; + MoonState::Phase mPhase; osg::ref_ptr mUpdater; }; @@ -886,10 +898,6 @@ void SkyManager::update(float duration) mCloudUpdater->setAnimationTimer(mCloudAnimationTimer); mCloudUpdater2->setAnimationTimer(mCloudAnimationTimer); - /// \todo improve this - mMasser->setPhase( static_cast( (int) ((mDay % 32)/4.f)) ); - mSecunda->setPhase ( static_cast( (int) ((mDay % 32)/4.f)) ); - if (mSunEnabled) { // take 1/10 sec for fading the glare effect from invisible to full @@ -1128,46 +1136,18 @@ void SkyManager::setSunDirection(const osg::Vec3f& direction) //mSunGlare->setPosition(direction); } -void SkyManager::setMasserDirection(const osg::Vec3f& direction) -{ - if (!mCreated) return; - - mMasser->setDirection(direction); -} - -void SkyManager::setSecundaDirection(const osg::Vec3f& direction) -{ - if (!mCreated) return; - - mSecunda->setDirection(direction); -} - -void SkyManager::masserEnable() -{ - if (!mCreated) return; - - mMasser->setVisible(true); -} - -void SkyManager::secundaEnable() -{ - if (!mCreated) return; - - mSecunda->setVisible(true); -} - -void SkyManager::masserDisable() +void SkyManager::setMasserState(const MoonState& state) { - if (!mCreated) return; + if(!mCreated) return; - mMasser->setVisible(false); + mMasser->setState(state); } -void SkyManager::secundaDisable() +void SkyManager::setSecundaState(const MoonState& state) { - if (!mCreated) return; + if(!mCreated) return; - mSecunda->setVisible(false); + mSecunda->setState(state); } void SkyManager::setLightningStrength(const float factor) @@ -1184,18 +1164,6 @@ void SkyManager::setLightningStrength(const float factor) */ } -void SkyManager::setMasserFade(const float fade) -{ - if (!mCreated) return; - mMasser->setFade(fade); -} - -void SkyManager::setSecundaFade(const float fade) -{ - if (!mCreated) return; - mSecunda->setFade(fade); -} - void SkyManager::setDate(int day, int month) { mDay = day; diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index 4d1c73e44..eb953d128 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -33,6 +33,28 @@ namespace MWRender class RainFader; class AlphaFader; + struct MoonState + { + enum Phase + { + Phase_Full = 0, + Phase_WaningGibbous, + Phase_ThirdQuarter, + Phase_WaningCrescent, + Phase_New, + Phase_WaxingCrescent, + Phase_FirstQuarter, + Phase_WaxingGibbous, + Phase_Unspecified + }; + + float mRotationFromHorizon; + float mRotationFromNorth; + Phase mPhase; + float mShadowBlend; + float mMoonAlpha; + }; + class SkyManager { public: @@ -72,19 +94,8 @@ namespace MWRender void setSunDirection(const osg::Vec3f& direction); - void setMasserDirection(const osg::Vec3f& direction); - - void setSecundaDirection(const osg::Vec3f& direction); - - void setMasserFade(const float fade); - - void setSecundaFade(const float fade); - - void masserEnable(); - void masserDisable(); - - void secundaEnable(); - void secundaDisable(); + void setMasserState(const MoonState& state); + void setSecundaState(const MoonState& state); void setLightningStrength(const float factor); diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 970e8b455..f98aa24c1 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -37,6 +37,170 @@ namespace } } +MoonModel::MoonModel(const std::string& name, MWWorld::Fallback& fallback) + : mFadeInStart(fallback.getFallbackFloat("Moons_" + name + "_Fade_In_Start")) + , mFadeInFinish(fallback.getFallbackFloat("Moons_" + name + "_Fade_In_Finish")) + , mFadeOutStart(fallback.getFallbackFloat("Moons_" + name + "_Fade_Out_Start")) + , mFadeOutFinish(fallback.getFallbackFloat("Moons_" + name + "_Fade_Out_Finish")) + , mAxisOffset(fallback.getFallbackFloat("Moons_" + name + "_Axis_Offset")) + , mSpeed(fallback.getFallbackFloat("Moons_" + name + "_Speed")) + , mDailyIncrement(fallback.getFallbackFloat("Moons_" + name + "_Daily_Increment")) + , mFadeStartAngle(fallback.getFallbackFloat("Moons_" + name + "_Fade_Start_Angle")) + , mFadeEndAngle(fallback.getFallbackFloat("Moons_" + name + "_Fade_End_Angle")) + , mMoonShadowEarlyFadeAngle(fallback.getFallbackFloat("Moons_" + name + "_Moon_Shadow_Early_Fade_Angle")) +{ + // Morrowind appears to have a minimum speed in order to avoid situations where the moon couldn't conceivably + // complete a rotation in a single 24 hour period. The value of 180/23 was deduced from reverse engineering. + mSpeed = std::min(mSpeed, 180.0f / 23.0f); +} + +MWRender::MoonState MoonModel::calculateState(unsigned int daysPassed, float gameHour) +{ + float rotationFromHorizon = angle(daysPassed, gameHour); + MWRender::MoonState state = + { + rotationFromHorizon, + mAxisOffset, // Reverse engineered from Morrowind's scene graph rotation matrices. + static_cast(phase(daysPassed)), + shadowBlend(rotationFromHorizon), + earlyMoonShadowAlpha(rotationFromHorizon) * hourlyAlpha(gameHour) + }; + + return state; +} + +inline float MoonModel::angle(unsigned int daysPassed, float gameHour) +{ + // Morrowind's moons start travel on one side of the horizon (let's call it H-rise) and travel 180 degrees to the + // opposite horizon (let's call it H-set). Upon reaching H-set, they reset to H-rise until the next moon rise. + + // When calculating the angle of the moon, several cases have to be taken into account: + // 1. Moon rises and then sets in one day. + // 2. Moon sets and doesn't rise in one day (occurs when the moon rise hour is >= 24). + // 3. Moon sets and then rises in one day. + float moonRiseHourToday = moonRiseHour(daysPassed); + float moonRiseAngleToday = 0; + + if(gameHour < moonRiseHourToday) + { + float moonRiseHourYesterday = moonRiseHour(daysPassed - 1); + if(moonRiseHourYesterday < 24) + { + float moonRiseAngleYesterday = rotation(24 - moonRiseHourYesterday); + if(moonRiseAngleYesterday < 180) + { + // The moon rose but did not set yesterday, so accumulate yesterday's angle with how much we've travelled today. + moonRiseAngleToday = rotation(gameHour) + moonRiseAngleYesterday; + } + } + } + else + { + moonRiseAngleToday = rotation(gameHour - moonRiseHourToday); + } + + if(moonRiseAngleToday >= 180) + { + // The moon set today, reset the angle to the horizon. + moonRiseAngleToday = 0; + } + + return moonRiseAngleToday; +} + +inline float MoonModel::moonRiseHour(unsigned int daysPassed) +{ + // This arises from the start date of 16 Last Seed, 427 + // TODO: Find an alternate formula that doesn't rely on this day being fixed. + static const unsigned int startDay = 16; + + // This odd formula arises from the fact that on 16 Last Seed, 17 increments have occurred, meaning + // that upon starting a new game, it must only calculate the moon phase as far back as 1 Last Seed. + // Note that we don't modulo after adding the latest daily increment because other calculations need to + // know if doing so would cause the moon rise to be postponed until the next day (which happens when + // the moon rise hour is >= 24 in Morrowind). + return mDailyIncrement + std::fmod((daysPassed - 1 + startDay) * mDailyIncrement, 24.0f); +} + +inline float MoonModel::rotation(float hours) +{ + // 15 degrees per hour was reverse engineered from the rotation matrices of the Morrowind scene graph. + // Note that this correlates to 360 / 24, which is a full rotation every 24 hours, so speed is a measure + // of whole rotations that could be completed in a day. + return 15.0f * mSpeed * hours; +} + +inline unsigned int MoonModel::phase(unsigned int daysPassed) +{ + // Morrowind starts with a full moon on 16 Last Seed and then begins to wane 17 Last Seed, working on 3 day phase cycle. + // Note: this is an internal helper, and as such we don't want to return MWRender::MoonState::Phase since we can't + // forward declare it (C++11 strongly typed enums solve this). + return ((daysPassed + 1) / 3) % 8; +} + +inline float MoonModel::shadowBlend(float angle) +{ + // The Fade End Angle and Fade Start Angle describe a region where the moon transitions from a solid disk + // that is roughly the color of the sky, to a textured surface. + // Depending on the current angle, the following values describe the ratio between the textured moon + // and the solid disk: + // 1. From Fade End Angle 1 to Fade Start Angle 1 (during moon rise): 0..1 + // 2. From Fade Start Angle 1 to Fade Start Angle 2 (between moon rise and moon set): 1 (textured) + // 3. From Fade Start Angle 2 to Fade End Angle 2 (during moon set): 1..0 + // 4. From Fade End Angle 2 to Fade End Angle 1 (between moon set and moon rise): 0 (solid disk) + float fadeAngle = mFadeStartAngle - mFadeEndAngle; + float fadeEndAngle2 = 180.0f - mFadeEndAngle; + float fadeStartAngle2 = 180.0f - mFadeStartAngle; + if((angle >= mFadeEndAngle) && (angle < mFadeStartAngle)) + return (angle - mFadeEndAngle) / fadeAngle; + else if((angle >= mFadeStartAngle) && (angle < fadeStartAngle2)) + return 1.0f; + else if((angle >= fadeStartAngle2) && (angle < fadeEndAngle2)) + return (fadeEndAngle2 - angle) / fadeAngle; + else + return 0.0f; +} + +inline float MoonModel::hourlyAlpha(float gameHour) +{ + // The Fade Out Start / Finish and Fade In Start / Finish describe the hours at which the moon + // appears and disappears. + // Depending on the current hour, the following values describe how transparent the moon is. + // 1. From Fade Out Start to Fade Out Finish: 1..0 + // 2. From Fade Out Finish to Fade In Start: 0 (transparent) + // 3. From Fade In Start to Fade In Finish: 0..1 + // 4. From Fade In Finish to Fade Out Start: 1 (solid) + if((gameHour >= mFadeOutStart) && (gameHour < mFadeOutFinish)) + return (mFadeOutFinish - gameHour) / (mFadeOutFinish - mFadeOutStart); + else if((gameHour >= mFadeOutFinish) && (gameHour < mFadeInStart)) + return 0.0f; + else if((gameHour >= mFadeInStart) && (gameHour < mFadeInFinish)) + return (gameHour - mFadeInStart) / (mFadeInFinish - mFadeInStart); + else + return 1.0f; +} + +inline float MoonModel::earlyMoonShadowAlpha(float angle) +{ + // The Moon Shadow Early Fade Angle describes an arc relative to Fade End Angle. + // Depending on the current angle, the following values describe how transparent the moon is. + // 1. From Moon Shadow Early Fade Angle 1 to Fade End Angle 1 (during moon rise): 0..1 + // 2. From Fade End Angle 1 to Fade End Angle 2 (between moon rise and moon set): 1 (solid) + // 3. From Fade End Angle 2 to Moon Shadow Early Fade Angle 2 (during moon set): 1..0 + // 4. From Moon Shadow Early Fade Angle 2 to Moon Shadow Early Fade Angle 1: 0 (transparent) + float moonShadowEarlyFadeAngle1 = mFadeEndAngle - mMoonShadowEarlyFadeAngle; + float fadeEndAngle2 = 180.0f - mFadeEndAngle; + float moonShadowEarlyFadeAngle2 = fadeEndAngle2 + mMoonShadowEarlyFadeAngle; + if((angle >= moonShadowEarlyFadeAngle1) && (angle < mFadeEndAngle)) + return (angle - moonShadowEarlyFadeAngle1) / mMoonShadowEarlyFadeAngle; + else if((angle >= mFadeEndAngle) && (angle < fadeEndAngle2)) + return 1.0f; + else if((angle >= fadeEndAngle2) && (angle < moonShadowEarlyFadeAngle2)) + return (moonShadowEarlyFadeAngle2 - angle) / mMoonShadowEarlyFadeAngle; + else + return 0.0f; +} + void WeatherManager::setFallbackWeather(Weather& weather,const std::string& name) { std::string upper=name; @@ -88,39 +252,12 @@ Max Raindrops=650 ? mWeatherSettings[name] = weather; } - -float WeatherManager::calculateHourFade (const std::string& moonName) const -{ - float fadeOutStart=mFallback->getFallbackFloat("Moons_"+moonName+"_Fade_Out_Start"); - float fadeOutFinish=mFallback->getFallbackFloat("Moons_"+moonName+"_Fade_Out_Finish"); - float fadeInStart=mFallback->getFallbackFloat("Moons_"+moonName+"_Fade_In_Start"); - float fadeInFinish=mFallback->getFallbackFloat("Moons_"+moonName+"_Fade_In_Finish"); - - if (mHour >= fadeOutStart && mHour <= fadeOutFinish) - return (1 - ((mHour - fadeOutStart) / (fadeOutFinish - fadeOutStart))); - if (mHour >= fadeInStart && mHour <= fadeInFinish) - return (1 - ((mHour - fadeInStart) / (fadeInFinish - fadeInStart))); - else - return 1; -} - -float WeatherManager::calculateAngleFade (const std::string& moonName, float angle) const -{ - float endAngle=mFallback->getFallbackFloat("Moons_"+moonName+"_Fade_End_Angle"); - float startAngle=mFallback->getFallbackFloat("Moons_"+moonName+"_Fade_Start_Angle"); - if (angle <= startAngle && angle >= endAngle) - return (1 - ((angle - endAngle)/(startAngle-endAngle))); - else if (angle > startAngle) - return 0.f; - else - return 1.f; -} - WeatherManager::WeatherManager(MWRender::RenderingManager* rendering, MWWorld::Fallback* fallback, MWWorld::ESMStore* store) : mHour(14), mWindSpeed(0.f), mIsStorm(false), mStormDirection(0,1,0), mFallback(fallback), mStore(store), mRendering(rendering), mCurrentWeather("clear"), mNextWeather(""), mFirstUpdate(true), mRemainingTransitionTime(0), mThunderFlash(0), mThunderChance(0), mThunderChanceNeeded(50), - mTimePassed(0), mWeatherUpdateTime(0), mThunderSoundDelay(0) + mTimePassed(0), mWeatherUpdateTime(0), mThunderSoundDelay(0), + mMasser("Masser", *fallback), mSecunda("Secunda", *fallback) { //Globals mThunderSoundID0 = mFallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_0"); @@ -465,72 +602,9 @@ void WeatherManager::update(float duration, bool paused) mRendering->setSunDirection( final * -1 ); } - /* - * TODO: import separated fadeInStart/Finish, fadeOutStart/Finish - * for masser and secunda - */ - - float fadeOutFinish=mFallback->getFallbackFloat("Moons_Masser_Fade_Out_Finish"); - float fadeInStart=mFallback->getFallbackFloat("Moons_Masser_Fade_In_Start"); - - //moon calculations - float moonHeight; - if (mHour >= fadeInStart) - moonHeight = mHour - fadeInStart; - else if (mHour <= fadeOutFinish) - moonHeight = mHour + fadeOutFinish; - else - moonHeight = 0; - - moonHeight /= (24.f - (fadeInStart - fadeOutFinish)); - - if (moonHeight != 0) - { - int facing = (moonHeight <= 1) ? 1 : -1; - osg::Vec3f masser( - (moonHeight - 1) * facing, - (1 - moonHeight) * facing, - moonHeight); - - osg::Vec3f secunda( - (moonHeight - 1) * facing * 1.25f, - (1 - moonHeight) * facing * 0.8f, - moonHeight); - - mRendering->getSkyManager()->setMasserDirection(masser); - mRendering->getSkyManager()->setSecundaDirection(secunda); - - float angle = (1-moonHeight) * 90.f * facing; - float masserHourFade = calculateHourFade("Masser"); - float secundaHourFade = calculateHourFade("Secunda"); - float masserAngleFade = calculateAngleFade("Masser", angle); - float secundaAngleFade = calculateAngleFade("Secunda", angle); - - masserAngleFade *= masserHourFade; - secundaAngleFade *= secundaHourFade; - - if (masserAngleFade > 0) - { - mRendering->getSkyManager()->setMasserFade(masserAngleFade); - mRendering->getSkyManager()->masserEnable(); - } - else - mRendering->getSkyManager()->masserDisable(); - - if (secundaAngleFade > 0) - { - mRendering->getSkyManager()->setSecundaFade(secundaAngleFade); - mRendering->getSkyManager()->secundaEnable(); - } - else - mRendering->getSkyManager()->secundaDisable(); - - } - else - { - mRendering->getSkyManager()->masserDisable(); - mRendering->getSkyManager()->secundaDisable(); - } + TimeStamp time = MWBase::Environment::get().getWorld()->getTimeStamp(); + mRendering->getSkyManager()->setMasserState(mMasser.calculateState(time.getDay(), time.getHour())); + mRendering->getSkyManager()->setSecundaState(mSecunda.calculateState(time.getDay(), time.getHour())); if (!paused) { diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index efe69f17c..93cfed68b 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -19,6 +19,7 @@ namespace ESM namespace MWRender { class RenderingManager; + class MoonState; } namespace Loading @@ -150,6 +151,35 @@ namespace MWWorld // is broken in the vanilla game and was disabled. }; + class MoonModel + { + public: + MoonModel(const std::string& name, MWWorld::Fallback& fallback); + + MWRender::MoonState calculateState(unsigned int daysPassed, float gameHour); + + private: + float mSize; + float mFadeInStart; + float mFadeInFinish; + float mFadeOutStart; + float mFadeOutFinish; + float mAxisOffset; + float mSpeed; + float mDailyIncrement; + float mFadeStartAngle; + float mFadeEndAngle; + float mMoonShadowEarlyFadeAngle; + + float angle(unsigned int daysPassed, float gameHour); + float moonRiseHour(unsigned int daysPassed); + float rotation(float hours); + unsigned int phase(unsigned int daysPassed); + float shadowBlend(float angle); + float hourlyAlpha(float gameHour); + float earlyMoonShadowAlpha(float angle); + }; + /// /// Interface for weather settings /// @@ -237,9 +267,6 @@ namespace MWWorld void transition(const float factor); void setResult(const std::string& weatherType); - float calculateHourFade (const std::string& moonName) const; - float calculateAngleFade (const std::string& moonName, float angle) const; - void setWeather(const std::string& weatherType, bool instant=false); std::string nextWeather(const ESM::Region* region) const; WeatherResult mResult; @@ -265,6 +292,8 @@ namespace MWWorld std::string mThunderSoundID1; std::string mThunderSoundID2; std::string mThunderSoundID3; + MoonModel mMasser; + MoonModel mSecunda; }; } From 8dc7e158c675832a9cc4a3948a470d8dbb96f4a4 Mon Sep 17 00:00:00 2001 From: slothlife Date: Thu, 30 Jul 2015 00:18:56 -0500 Subject: [PATCH 1952/3725] Fix forward declaration of MoonState --- apps/openmw/mwworld/weather.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index 93cfed68b..4290b21aa 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -19,7 +19,7 @@ namespace ESM namespace MWRender { class RenderingManager; - class MoonState; + struct MoonState; } namespace Loading From a4e1630ec249ce15dbfa71f12cee801d38031bf7 Mon Sep 17 00:00:00 2001 From: slothlife Date: Thu, 30 Jul 2015 00:41:30 -0500 Subject: [PATCH 1953/3725] Remove unreferenced member in MoonModel --- apps/openmw/mwworld/weather.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index 4290b21aa..faa6355ce 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -159,7 +159,6 @@ namespace MWWorld MWRender::MoonState calculateState(unsigned int daysPassed, float gameHour); private: - float mSize; float mFadeInStart; float mFadeInFinish; float mFadeOutStart; From e9ffbcc1b0aa771ca627a26acb6565b6b5e85555 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Thu, 30 Jul 2015 11:45:10 +0200 Subject: [PATCH 1954/3725] OSG 3.3.3 moves GL extensions out of osg::Texture --- components/resource/texturemanager.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/components/resource/texturemanager.cpp b/components/resource/texturemanager.cpp index 4bd712ea5..252456fb1 100644 --- a/components/resource/texturemanager.cpp +++ b/components/resource/texturemanager.cpp @@ -118,10 +118,17 @@ namespace Resource case(GL_COMPRESSED_RGBA_S3TC_DXT3_EXT): case(GL_COMPRESSED_RGBA_S3TC_DXT5_EXT): { +#if OSG_MIN_VERSION_REQUIRED(3, 3, 3) + osg::GLExtensions* exts = osg::GLExtensions::Get(0, false); + if (exts && !exts->isTextureCompressionS3TCSupported + // This one works too. Should it be included in isTextureCompressionS3TCSupported()? Submitted as a patch to OSG. + && !osg::isGLExtensionSupported(0, "GL_S3_s3tc")) +#else osg::Texture::Extensions* exts = osg::Texture::getExtensions(0, false); if (exts && !exts->isTextureCompressionS3TCSupported() // This one works too. Should it be included in isTextureCompressionS3TCSupported()? Submitted as a patch to OSG. && !osg::isGLExtensionSupported(0, "GL_S3_s3tc")) +#endif { std::cerr << "Error loading " << filename << ": no S3TC texture compression support installed" << std::endl; return false; From 6a9218ee07a81c9ca56faf8661c9d38e84ba3028 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 30 Jul 2015 11:49:24 +0200 Subject: [PATCH 1955/3725] replaced State_Compiling (not requried anymore) with State_Merging --- apps/opencs/model/doc/state.hpp | 2 +- apps/opencs/view/doc/operation.cpp | 3 ++- apps/opencs/view/doc/view.cpp | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/doc/state.hpp b/apps/opencs/model/doc/state.hpp index 78f468101..7352b4b99 100644 --- a/apps/opencs/model/doc/state.hpp +++ b/apps/opencs/model/doc/state.hpp @@ -12,7 +12,7 @@ namespace CSMDoc State_Saving = 16, State_Verifying = 32, - State_Compiling = 64, // not implemented yet + State_Merging = 64, State_Searching = 128, State_Loading = 256 // pseudo-state; can not be encountered in a loaded document }; diff --git a/apps/opencs/view/doc/operation.cpp b/apps/opencs/view/doc/operation.cpp index 95cbf012d..e5c1e7b89 100644 --- a/apps/opencs/view/doc/operation.cpp +++ b/apps/opencs/view/doc/operation.cpp @@ -19,6 +19,7 @@ void CSVDoc::Operation::updateLabel (int threads) case CSMDoc::State_Saving: name = "saving"; break; case CSMDoc::State_Verifying: name = "verifying"; break; case CSMDoc::State_Searching: name = "searching"; break; + case CSMDoc::State_Merging: name = "merging"; break; } std::ostringstream stream; @@ -122,7 +123,7 @@ void CSVDoc::Operation::setBarColor (int type) bottomColor = "#9ECB2D"; //green gloss break; - case CSMDoc::State_Compiling: + case CSMDoc::State_Merging: topColor = "#F3E2C7"; midTopColor = "#C19E67"; diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index c4abb2622..05c98b11f 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -471,6 +471,7 @@ void CSVDoc::View::updateDocumentState() static const int operations[] = { CSMDoc::State_Saving, CSMDoc::State_Verifying, CSMDoc::State_Searching, + CSMDoc::State_Merging, -1 // end marker }; From 77a3a52b4e5d154d55c50c728410c809aa137a8c Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Thu, 30 Jul 2015 12:16:15 +0200 Subject: [PATCH 1956/3725] What's wrong with this statement? --- components/resource/texturemanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/resource/texturemanager.cpp b/components/resource/texturemanager.cpp index 252456fb1..750dfaab7 100644 --- a/components/resource/texturemanager.cpp +++ b/components/resource/texturemanager.cpp @@ -118,7 +118,7 @@ namespace Resource case(GL_COMPRESSED_RGBA_S3TC_DXT3_EXT): case(GL_COMPRESSED_RGBA_S3TC_DXT5_EXT): { -#if OSG_MIN_VERSION_REQUIRED(3, 3, 3) +#if OSG_MIN_VERSION_REQUIRED(3,3,3) osg::GLExtensions* exts = osg::GLExtensions::Get(0, false); if (exts && !exts->isTextureCompressionS3TCSupported // This one works too. Should it be included in isTextureCompressionS3TCSupported()? Submitted as a patch to OSG. From 1f78ebd3c98bf9759f5573a76279e44eab8cec61 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Thu, 30 Jul 2015 12:22:51 +0200 Subject: [PATCH 1957/3725] Oops? --- components/resource/texturemanager.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/components/resource/texturemanager.cpp b/components/resource/texturemanager.cpp index 750dfaab7..d29aa2812 100644 --- a/components/resource/texturemanager.cpp +++ b/components/resource/texturemanager.cpp @@ -2,6 +2,7 @@ #include #include +#include #include From 5e6fcc2aefbf2eccf5e16deeb2f064c66efcb497 Mon Sep 17 00:00:00 2001 From: Arthur Moore Date: Wed, 29 Jul 2015 14:15:06 -0400 Subject: [PATCH 1958/3725] Alert the user if attempting to play an animation fails This is mostly propogating the error up the stack so the game can do something about it. Working on avoiding log spam from calling an animation that doesn't exist every frame. --- apps/openmw/mwbase/mechanicsmanager.hpp | 3 ++- apps/openmw/mwmechanics/actors.cpp | 12 ++++++++++-- apps/openmw/mwmechanics/actors.hpp | 2 +- apps/openmw/mwmechanics/character.cpp | 6 +++++- apps/openmw/mwmechanics/character.hpp | 2 +- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 6 +++--- apps/openmw/mwmechanics/mechanicsmanagerimp.hpp | 4 +++- apps/openmw/mwmechanics/objects.cpp | 13 +++++++++++-- apps/openmw/mwmechanics/objects.hpp | 2 +- 9 files changed, 37 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index 2c4a22c07..63ad1d32f 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -160,12 +160,13 @@ namespace MWBase virtual void forceStateUpdate(const MWWorld::Ptr &ptr) = 0; ///< Forces an object to refresh its animation state. - virtual void playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number=1) = 0; + virtual bool playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number=1) = 0; ///< Run animation for a MW-reference. Calls to this function for references that are currently not /// in the scene should be ignored. /// /// \param mode 0 normal, 1 immediate start, 2 immediate loop /// \param count How many times the animation should be run + /// \return Success or error virtual void skipAnimation(const MWWorld::Ptr& ptr) = 0; ///< Skip the animation for the given MW-reference for one frame. Calls to this function for diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index c135811dd..dd2fe3cad 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1,6 +1,7 @@ #include "actors.hpp" #include +#include #include @@ -1241,11 +1242,18 @@ namespace MWMechanics iter->second->getCharacterController()->forceStateUpdate(); } - void Actors::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number) + bool Actors::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number) { PtrActorMap::iterator iter = mActors.find(ptr); if(iter != mActors.end()) - iter->second->getCharacterController()->playGroup(groupName, mode, number); + { + return iter->second->getCharacterController()->playGroup(groupName, mode, number); + } + else + { + std::cerr<< "Error in Actors::playAnimationGroup: Unable to find " << ptr.getTypeName() << std::endl; + return false; + } } void Actors::skipAnimation(const MWWorld::Ptr& ptr) { diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index 4baaea28d..a16b80884 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -105,7 +105,7 @@ namespace MWMechanics void forceStateUpdate(const MWWorld::Ptr &ptr); - void playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number); + bool playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number); void skipAnimation(const MWWorld::Ptr& ptr); bool checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string& groupName); diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 9d5f7137f..1bd12b53f 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1866,10 +1866,13 @@ void CharacterController::update(float duration) } -void CharacterController::playGroup(const std::string &groupname, int mode, int count) +bool CharacterController::playGroup(const std::string &groupname, int mode, int count) { if(!mAnimation || !mAnimation->hasAnimation(groupname)) + { std::cerr<< "Animation "< + #include "movement.hpp" #include "../mwbase/environment.hpp" @@ -77,11 +79,18 @@ void Objects::update(float duration, bool paused) } } -void Objects::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number) +bool Objects::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number) { PtrControllerMap::iterator iter = mObjects.find(ptr); if(iter != mObjects.end()) - iter->second->playGroup(groupName, mode, number); + { + return iter->second->playGroup(groupName, mode, number); + } + else + { + std::cerr<< "Error in Objects::playAnimationGroup: Unable to find " << ptr.getTypeName() << std::endl; + return false; + } } void Objects::skipAnimation(const MWWorld::Ptr& ptr) { diff --git a/apps/openmw/mwmechanics/objects.hpp b/apps/openmw/mwmechanics/objects.hpp index 6e22c0582..07e00675c 100644 --- a/apps/openmw/mwmechanics/objects.hpp +++ b/apps/openmw/mwmechanics/objects.hpp @@ -38,7 +38,7 @@ namespace MWMechanics void update(float duration, bool paused); ///< Update object animations - void playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number); + bool playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number); void skipAnimation(const MWWorld::Ptr& ptr); void getObjectsInRange (const osg::Vec3f& position, float radius, std::vector& out); From f69de1f2636f6627a25e1c026e7d176cf7e6108e Mon Sep 17 00:00:00 2001 From: Arthur Moore Date: Thu, 30 Jul 2015 08:08:58 -0400 Subject: [PATCH 1959/3725] Alert the user if trying to play a non-idle animation Continue to propagate success/failure up the call stack. --- apps/openmw/mwmechanics/aiwander.cpp | 10 ++++++++-- apps/openmw/mwmechanics/aiwander.hpp | 5 ++++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index e230998eb..e3ce4ae2a 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -1,6 +1,7 @@ #include "aiwander.hpp" #include +#include #include @@ -621,12 +622,17 @@ namespace MWMechanics actor.getClass().getMovementSettings(actor).mPosition[1] = 0; } - void AiWander::playIdle(const MWWorld::Ptr& actor, unsigned short idleSelect) + bool AiWander::playIdle(const MWWorld::Ptr& actor, unsigned short idleSelect) { if ((GroupIndex_MinIdle <= idleSelect) && (idleSelect <= GroupIndex_MaxIdle)) { const std::string& groupName = sIdleSelectToGroupName[idleSelect - GroupIndex_MinIdle]; - MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, groupName, 0, 1); + return MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, groupName, 0, 1); + } + else + { + std::cerr<< "Attempted to play out of range idle animation \""< Date: Thu, 30 Jul 2015 08:15:45 -0400 Subject: [PATCH 1960/3725] Refactor onChooseActionStatePerFrameActions This prevents playIdle errors from tyring to play idleAnimation 0 --- apps/openmw/mwmechanics/aiwander.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index e3ce4ae2a..f05040b66 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -392,18 +392,24 @@ namespace MWMechanics short unsigned& idleAnimation = storage.mIdleAnimation; idleAnimation = getRandomIdle(); + //If we should be moving if (!idleAnimation && mDistance) { storage.mState = Wander_MoveNow; } else { - // Play idle animation and recreate vanilla (broken?) behavior of resetting start time of AIWander: + //Recreate vanilla (broken?) behavior of resetting start time of AIWander: MWWorld::TimeStamp currentTime = MWBase::Environment::get().getWorld()->getTimeStamp(); mStartTime = currentTime; - playIdle(actor, idleAnimation); storage.mState = Wander_IdleNow; } + + //If we aren't going to just stand + if(idleAnimation) + { + playIdle(actor, idleAnimation); + } } void AiWander::evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration) From f15adb4e4f18e9f5509c95a065001f85a4e0dd82 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Thu, 30 Jul 2015 14:43:36 +0300 Subject: [PATCH 1961/3725] Store::load() overwrites loaded records with the same IDs --- apps/openmw/mwworld/store.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index a8b0af88a..5c1b2c6e3 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -196,6 +196,8 @@ namespace MWWorld std::pair inserted = mStatic.insert(std::make_pair(record.mId, record)); if (inserted.second) mShared.push_back(&inserted.first->second); + else + inserted.first->second = record; return RecordId(record.mId, isDeleted); } From d13766cb3c185ecce9b95518d1367b2cf2d2812d Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Thu, 30 Jul 2015 15:36:17 +0300 Subject: [PATCH 1962/3725] Remove redundant template specializations --- apps/openmw/mwworld/store.cpp | 43 ----------------------------------- 1 file changed, 43 deletions(-) diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index 5c1b2c6e3..98138147d 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -1060,49 +1060,6 @@ namespace MWWorld return RecordId(dialogue.mId, isDeleted); } - - - // Script - //========================================================================= - - template <> - inline RecordId Store::load(ESM::ESMReader &esm) { - ESM::Script script; - bool isDeleted = false; - - script.load(esm, isDeleted); - Misc::StringUtils::toLower(script.mId); - - std::pair inserted = mStatic.insert(std::make_pair(script.mId, script)); - if (inserted.second) - mShared.push_back(&inserted.first->second); - else - inserted.first->second = script; - - return RecordId(script.mId, isDeleted); - } - - - // StartScript - //========================================================================= - - template <> - inline RecordId Store::load(ESM::ESMReader &esm) - { - ESM::StartScript script; - bool isDeleted = false; - - script.load(esm, isDeleted); - Misc::StringUtils::toLower(script.mId); - - std::pair inserted = mStatic.insert(std::make_pair(script.mId, script)); - if (inserted.second) - mShared.push_back(&inserted.first->second); - else - inserted.first->second = script; - - return RecordId(script.mId, isDeleted); - } } template class MWWorld::Store; From 67a63cc6622c5b2d2f24fc8fdc8dc5f40aa22222 Mon Sep 17 00:00:00 2001 From: slothlife Date: Thu, 30 Jul 2015 14:00:08 -0500 Subject: [PATCH 1963/3725] Add some const correctness to MoonModel --- apps/openmw/mwworld/weather.cpp | 18 +++++++++--------- apps/openmw/mwworld/weather.hpp | 18 +++++++++--------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index f98aa24c1..0e78edce7 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -37,7 +37,7 @@ namespace } } -MoonModel::MoonModel(const std::string& name, MWWorld::Fallback& fallback) +MoonModel::MoonModel(const std::string& name, const MWWorld::Fallback& fallback) : mFadeInStart(fallback.getFallbackFloat("Moons_" + name + "_Fade_In_Start")) , mFadeInFinish(fallback.getFallbackFloat("Moons_" + name + "_Fade_In_Finish")) , mFadeOutStart(fallback.getFallbackFloat("Moons_" + name + "_Fade_Out_Start")) @@ -54,7 +54,7 @@ MoonModel::MoonModel(const std::string& name, MWWorld::Fallback& fallback) mSpeed = std::min(mSpeed, 180.0f / 23.0f); } -MWRender::MoonState MoonModel::calculateState(unsigned int daysPassed, float gameHour) +MWRender::MoonState MoonModel::calculateState(unsigned int daysPassed, float gameHour) const { float rotationFromHorizon = angle(daysPassed, gameHour); MWRender::MoonState state = @@ -69,7 +69,7 @@ MWRender::MoonState MoonModel::calculateState(unsigned int daysPassed, float gam return state; } -inline float MoonModel::angle(unsigned int daysPassed, float gameHour) +inline float MoonModel::angle(unsigned int daysPassed, float gameHour) const { // Morrowind's moons start travel on one side of the horizon (let's call it H-rise) and travel 180 degrees to the // opposite horizon (let's call it H-set). Upon reaching H-set, they reset to H-rise until the next moon rise. @@ -108,7 +108,7 @@ inline float MoonModel::angle(unsigned int daysPassed, float gameHour) return moonRiseAngleToday; } -inline float MoonModel::moonRiseHour(unsigned int daysPassed) +inline float MoonModel::moonRiseHour(unsigned int daysPassed) const { // This arises from the start date of 16 Last Seed, 427 // TODO: Find an alternate formula that doesn't rely on this day being fixed. @@ -122,7 +122,7 @@ inline float MoonModel::moonRiseHour(unsigned int daysPassed) return mDailyIncrement + std::fmod((daysPassed - 1 + startDay) * mDailyIncrement, 24.0f); } -inline float MoonModel::rotation(float hours) +inline float MoonModel::rotation(float hours) const { // 15 degrees per hour was reverse engineered from the rotation matrices of the Morrowind scene graph. // Note that this correlates to 360 / 24, which is a full rotation every 24 hours, so speed is a measure @@ -130,7 +130,7 @@ inline float MoonModel::rotation(float hours) return 15.0f * mSpeed * hours; } -inline unsigned int MoonModel::phase(unsigned int daysPassed) +inline unsigned int MoonModel::phase(unsigned int daysPassed) const { // Morrowind starts with a full moon on 16 Last Seed and then begins to wane 17 Last Seed, working on 3 day phase cycle. // Note: this is an internal helper, and as such we don't want to return MWRender::MoonState::Phase since we can't @@ -138,7 +138,7 @@ inline unsigned int MoonModel::phase(unsigned int daysPassed) return ((daysPassed + 1) / 3) % 8; } -inline float MoonModel::shadowBlend(float angle) +inline float MoonModel::shadowBlend(float angle) const { // The Fade End Angle and Fade Start Angle describe a region where the moon transitions from a solid disk // that is roughly the color of the sky, to a textured surface. @@ -161,7 +161,7 @@ inline float MoonModel::shadowBlend(float angle) return 0.0f; } -inline float MoonModel::hourlyAlpha(float gameHour) +inline float MoonModel::hourlyAlpha(float gameHour) const { // The Fade Out Start / Finish and Fade In Start / Finish describe the hours at which the moon // appears and disappears. @@ -180,7 +180,7 @@ inline float MoonModel::hourlyAlpha(float gameHour) return 1.0f; } -inline float MoonModel::earlyMoonShadowAlpha(float angle) +inline float MoonModel::earlyMoonShadowAlpha(float angle) const { // The Moon Shadow Early Fade Angle describes an arc relative to Fade End Angle. // Depending on the current angle, the following values describe how transparent the moon is. diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index faa6355ce..8f7634fbb 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -154,9 +154,9 @@ namespace MWWorld class MoonModel { public: - MoonModel(const std::string& name, MWWorld::Fallback& fallback); + MoonModel(const std::string& name, const MWWorld::Fallback& fallback); - MWRender::MoonState calculateState(unsigned int daysPassed, float gameHour); + MWRender::MoonState calculateState(unsigned int daysPassed, float gameHour) const; private: float mFadeInStart; @@ -170,13 +170,13 @@ namespace MWWorld float mFadeEndAngle; float mMoonShadowEarlyFadeAngle; - float angle(unsigned int daysPassed, float gameHour); - float moonRiseHour(unsigned int daysPassed); - float rotation(float hours); - unsigned int phase(unsigned int daysPassed); - float shadowBlend(float angle); - float hourlyAlpha(float gameHour); - float earlyMoonShadowAlpha(float angle); + float angle(unsigned int daysPassed, float gameHour) const; + float moonRiseHour(unsigned int daysPassed) const; + float rotation(float hours) const; + unsigned int phase(unsigned int daysPassed) const; + float shadowBlend(float angle) const; + float hourlyAlpha(float gameHour) const; + float earlyMoonShadowAlpha(float angle) const; }; /// From de479e35c8e39f6097148d17b5631630333cd1b4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 30 Jul 2015 23:51:37 +0200 Subject: [PATCH 1964/3725] Fix AlphaController affecting all instances of the StateSet --- components/nifosg/controller.cpp | 7 +++++++ components/nifosg/controller.hpp | 2 ++ 2 files changed, 9 insertions(+) diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index 83ecc0fa9..e66713c17 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -353,6 +353,13 @@ AlphaController::AlphaController(const AlphaController ©, const osg::CopyOp { } +void AlphaController::setDefaults(osg::StateSet *stateset) +{ + // need to create a deep copy of StateAttributes we will modify + osg::Material* mat = static_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); + stateset->setAttribute(osg::clone(mat, osg::CopyOp::DEEP_COPY_ALL), osg::StateAttribute::ON); +} + void AlphaController::apply(osg::StateSet *stateset, osg::NodeVisitor *nv) { if (hasInput()) diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index 4877c83db..500a5cc17 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -189,6 +189,8 @@ namespace NifOsg AlphaController(); AlphaController(const AlphaController& copy, const osg::CopyOp& copyop); + virtual void setDefaults(osg::StateSet* stateset); + virtual void apply(osg::StateSet* stateset, osg::NodeVisitor* nv); META_Object(NifOsg, AlphaController) From 16b8ef3164c28f829bbe76b3ac1a21a3bb53715c Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 31 Jul 2015 00:01:55 +0200 Subject: [PATCH 1965/3725] Don't use a shared Material in MaterialColorController --- components/nifosg/controller.cpp | 7 +++++++ components/nifosg/controller.hpp | 2 ++ 2 files changed, 9 insertions(+) diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index e66713c17..bb698ed63 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -387,6 +387,13 @@ MaterialColorController::MaterialColorController(const MaterialColorController & { } +void MaterialColorController::setDefaults(osg::StateSet *stateset) +{ + // need to create a deep copy of StateAttributes we will modify + osg::Material* mat = static_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); + stateset->setAttribute(osg::clone(mat, osg::CopyOp::DEEP_COPY_ALL), osg::StateAttribute::ON); +} + void MaterialColorController::apply(osg::StateSet *stateset, osg::NodeVisitor *nv) { if (hasInput()) diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index 500a5cc17..58870317e 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -208,6 +208,8 @@ namespace NifOsg META_Object(NifOsg, MaterialColorController) + virtual void setDefaults(osg::StateSet* stateset); + virtual void apply(osg::StateSet* stateset, osg::NodeVisitor* nv); }; From 1f755a2bc0d99f1ad5e3fe1a32e645a6a4d77694 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 31 Jul 2015 00:03:01 +0200 Subject: [PATCH 1966/3725] Don't use a shared Material in AlphaFader --- apps/openmw/mwrender/sky.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 49c00c33d..2009232c5 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -705,6 +705,13 @@ public: mAlpha = alpha; } + virtual void setDefaults(osg::StateSet* stateset) + { + // need to create a deep copy of StateAttributes we will modify + osg::Material* mat = static_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); + stateset->setAttribute(osg::clone(mat, osg::CopyOp::DEEP_COPY_ALL), osg::StateAttribute::ON); + } + virtual void apply(osg::StateSet* stateset, osg::NodeVisitor* nv) { osg::Material* mat = static_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); From e8cbdcfb1e98956b86df8d80eb268882d951864b Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 31 Jul 2015 00:35:17 +0200 Subject: [PATCH 1967/3725] Play swimming animation fallback on the upper body when possible --- apps/openmw/mwmechanics/character.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 9d5f7137f..ae4412dbf 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -390,7 +390,8 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat } else { - movemask = MWRender::Animation::BlendMask_LowerBody; + if (weap != sWeaponTypeListEnd) + movemask = MWRender::Animation::BlendMask_LowerBody; movementAnimName.erase(swimpos, 4); if(!mAnimation->hasAnimation(movementAnimName)) movementAnimName.clear(); From f326b8e5d28e5a8a68098bdb60a96fc382d0a3fc Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 31 Jul 2015 00:52:34 +0200 Subject: [PATCH 1968/3725] Fix weapon animations playing on the lowerbody when swimming --- apps/openmw/mwmechanics/character.cpp | 6 +++++- apps/openmw/mwmechanics/character.hpp | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index ae4412dbf..44fcf1c57 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -468,10 +468,14 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat mIdleState = idle; std::string idle; + MWRender::Animation::AnimPriority idlePriority (Priority_Default); // Only play "idleswim" or "idlesneak" if they exist. Otherwise, fallback to // "idle"+weapon or "idle". if(mIdleState == CharState_IdleSwim && mAnimation->hasAnimation("idleswim")) + { idle = "idleswim"; + idlePriority = Priority_SwimIdle; + } else if(mIdleState == CharState_IdleSneak && mAnimation->hasAnimation("idlesneak")) idle = "idlesneak"; else if(mIdleState != CharState_None) @@ -488,7 +492,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat mAnimation->disable(mCurrentIdle); mCurrentIdle = idle; if(!mCurrentIdle.empty()) - mAnimation->play(mCurrentIdle, Priority_Default, MWRender::Animation::BlendMask_All, false, + mAnimation->play(mCurrentIdle, idlePriority, MWRender::Animation::BlendMask_All, false, 1.0f, "start", "stop", 0.0f, ~0ul, true); } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index d647cae22..3ada5e65e 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -29,6 +29,7 @@ class CreatureStats; enum Priority { Priority_Default, Priority_WeaponLowerBody, + Priority_SwimIdle, Priority_Jump, Priority_Movement, Priority_Hit, From 7644a46deddc25367dfa6d50f6c51a74a32566f4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 31 Jul 2015 01:26:26 +0200 Subject: [PATCH 1969/3725] Creatures with no movement should not attempt to start combat (Fixes #2786) --- apps/openmw/mwmechanics/actors.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index c135811dd..75d501ff1 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -291,6 +291,10 @@ namespace MWMechanics return; } + // no combat for totally static creatures (they have no movement or attack animations anyway) + if (!actor1.getClass().isMobile(actor1)) + return; + bool aggressive; if (againstPlayer) From 61c38356378fb4ab0de5bf4a23cd828b40ab7a29 Mon Sep 17 00:00:00 2001 From: Arthur Moore Date: Thu, 30 Jul 2015 08:20:16 -0400 Subject: [PATCH 1970/3725] Don't try to play animations we know are bad Prevents log spam --- apps/openmw/mwmechanics/aiwander.cpp | 34 +++++++++++++++++----------- apps/openmw/mwmechanics/aiwander.hpp | 4 ++-- 2 files changed, 23 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index f05040b66..331ec8b9d 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -58,7 +58,6 @@ namespace MWMechanics bool mTurnActorGivingGreetingToFacePlayer; float mReaction; // update some actions infrequently - AiWander::GreetingState mSaidGreeting; int mGreetingTimer; @@ -68,6 +67,7 @@ namespace MWMechanics AiWander::WanderState mState; unsigned short mIdleAnimation; + std::vector mBadIdles; //Idle animations that when called cause errors PathFinder mPathFinder; @@ -79,7 +79,8 @@ namespace MWMechanics mGreetingTimer(0), mCell(NULL), mState(AiWander::Wander_ChooseAction), - mIdleAnimation(0) + mIdleAnimation(0), + mBadIdles() {}; }; @@ -392,24 +393,31 @@ namespace MWMechanics short unsigned& idleAnimation = storage.mIdleAnimation; idleAnimation = getRandomIdle(); - //If we should be moving + // If we should be moving if (!idleAnimation && mDistance) { storage.mState = Wander_MoveNow; + return; } - else - { - //Recreate vanilla (broken?) behavior of resetting start time of AIWander: - MWWorld::TimeStamp currentTime = MWBase::Environment::get().getWorld()->getTimeStamp(); - mStartTime = currentTime; - storage.mState = Wander_IdleNow; - } - - //If we aren't going to just stand + // If we aren't going to just stand if(idleAnimation) { - playIdle(actor, idleAnimation); + // If the idle animation actually exists + if(std::find(storage.mBadIdles.begin(), storage.mBadIdles.end(), idleAnimation)==storage.mBadIdles.end()) + { + if(!playIdle(actor, idleAnimation)) + { + std::cerr<< "Unable to play idle animation "<getTimeStamp(); + storage.mState = Wander_IdleNow; + return; } void AiWander::evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration) diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index c03cdfaa2..27e6fe9fb 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -76,8 +76,8 @@ namespace MWMechanics void stopWalking(const MWWorld::Ptr& actor, AiWanderStorage& storage); - ///Have the given actor play an idle animation - ///@return Success or error + /// Have the given actor play an idle animation + /// @return Success or error bool playIdle(const MWWorld::Ptr& actor, unsigned short idleSelect); bool checkIdle(const MWWorld::Ptr& actor, unsigned short idleSelect); short unsigned getRandomIdle(); From 6fce49bfb5e6a32127852193dc9413bec59488c5 Mon Sep 17 00:00:00 2001 From: Arthur Moore Date: Fri, 31 Jul 2015 18:00:17 -0400 Subject: [PATCH 1971/3725] Don't warn twice when unable to play an idle animation --- apps/openmw/mwmechanics/aiwander.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 331ec8b9d..b356c6e7d 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -407,7 +407,6 @@ namespace MWMechanics { if(!playIdle(actor, idleAnimation)) { - std::cerr<< "Unable to play idle animation "< Date: Fri, 31 Jul 2015 18:23:07 -0400 Subject: [PATCH 1972/3725] Remove more comments --- apps/openmw/mwmechanics/aiwander.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index b356c6e7d..440814fb7 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -67,7 +67,7 @@ namespace MWMechanics AiWander::WanderState mState; unsigned short mIdleAnimation; - std::vector mBadIdles; //Idle animations that when called cause errors + std::vector mBadIdles; // Idle animations that when called cause errors PathFinder mPathFinder; @@ -393,16 +393,13 @@ namespace MWMechanics short unsigned& idleAnimation = storage.mIdleAnimation; idleAnimation = getRandomIdle(); - // If we should be moving if (!idleAnimation && mDistance) { storage.mState = Wander_MoveNow; return; } - // If we aren't going to just stand if(idleAnimation) { - // If the idle animation actually exists if(std::find(storage.mBadIdles.begin(), storage.mBadIdles.end(), idleAnimation)==storage.mBadIdles.end()) { if(!playIdle(actor, idleAnimation)) @@ -416,7 +413,6 @@ namespace MWMechanics // Recreate vanilla (broken?) behavior of resetting start time of AIWander: mStartTime = MWBase::Environment::get().getWorld()->getTimeStamp(); storage.mState = Wander_IdleNow; - return; } void AiWander::evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration) From 0244a9b32950c8a2caa777a21f6ec73894146e80 Mon Sep 17 00:00:00 2001 From: slothlife Date: Sat, 1 Aug 2015 07:57:05 -0500 Subject: [PATCH 1973/3725] Correct moon texture with respect to trajectory --- apps/openmw/mwrender/sky.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index cf20bc4c6..ea3f8e8bf 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -398,13 +398,19 @@ public: void setState(const MoonState& state) { float radsX = ((state.mRotationFromHorizon) * M_PI) / 180.0f; - float radsY = 0; float radsZ = ((state.mRotationFromNorth) * M_PI) / 180.0f; - osg::Quat rotation(radsX, osg::Vec3f(1.0f, 0.0f, 0.0f), - radsY, osg::Vec3f(0.0f, 1.0f, 0.0f), - radsZ, osg::Vec3f(0.0f, 0.0f, 1.0f)); - setDirection(rotation * osg::Vec3f(0.0f, 1.0f, 0.0f)); + osg::Quat rotX(radsX, osg::Vec3f(1.0f, 0.0f, 0.0f)); + osg::Quat rotZ(radsZ, osg::Vec3f(0.0f, 0.0f, 1.0f)); + + osg::Vec3f direction = rotX * rotZ * osg::Vec3f(0.0f, 1.0f, 0.0f); + mTransform->setPosition(direction * 1000.0f); + + // The moon quad is initially oriented facing down, so we need to offset its X-axis + // rotation to rotate it to face the camera when sitting at the horizon. + osg::Quat attX((-M_PI / 2.0f) + radsX, osg::Vec3f(1,0,0)); + mTransform->setAttitude(attX * rotZ); + setPhase(state.mPhase); setTransparency(state.mMoonAlpha); setShadowBlend(state.mShadowBlend); From afb36b73eb3edc81947a8b409197d8afc2cfa857 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sun, 2 Aug 2015 15:03:27 +0300 Subject: [PATCH 1974/3725] Proper index for Modified column in ModifyCommand --- apps/opencs/model/world/commands.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/world/commands.cpp b/apps/opencs/model/world/commands.cpp index 5e0cc8f88..019ffe7b2 100644 --- a/apps/opencs/model/world/commands.cpp +++ b/apps/opencs/model/world/commands.cpp @@ -33,7 +33,14 @@ CSMWorld::ModifyCommand::ModifyCommand (QAbstractItemModel& model, const QModelI { mHasRecordState = true; int stateColumnIndex = table->findColumnIndex(Columns::ColumnId_Modification); - mRecordStateIndex = table->index(mIndex.row(), stateColumnIndex); + + int rowIndex = mIndex.row(); + if (mIndex.parent().isValid()) + { + rowIndex = mIndex.parent().row(); + } + + mRecordStateIndex = table->index(rowIndex, stateColumnIndex); mOldRecordState = static_cast(table->data(mRecordStateIndex).toInt()); } } From 25b653e316ddfe92754aa22cb6cf468edda44e66 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sun, 2 Aug 2015 15:06:56 +0300 Subject: [PATCH 1975/3725] Inform about Modified status change when modifying a value of a model --- apps/opencs/model/world/idtable.cpp | 6 +++++- apps/opencs/model/world/idtree.cpp | 8 +++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 8ca19f7e9..bdbc5e0c4 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -77,7 +77,11 @@ bool CSMWorld::IdTable::setData (const QModelIndex &index, const QVariant &value { mIdCollection->setData (index.row(), index.column(), value); - emit dataChanged (index, index); + // Modifying a value can also change the Modified status of a record. + // To track this, we inform about the change of a whole row. + QModelIndex rowStart = this->index(index.row(), 0); + QModelIndex rowEnd = this->index(index.row(), columnCount(index.parent()) - 1); + emit dataChanged(rowStart, rowEnd); return true; } diff --git a/apps/opencs/model/world/idtree.cpp b/apps/opencs/model/world/idtree.cpp index 5a7d10c6e..0b027cdab 100644 --- a/apps/opencs/model/world/idtree.cpp +++ b/apps/opencs/model/world/idtree.cpp @@ -96,7 +96,13 @@ bool CSMWorld::IdTree::setData (const QModelIndex &index, const QVariant &value, mNestedCollection->setNestedData(parentAddress.first, parentAddress.second, value, index.row(), index.column()); - emit dataChanged (index, index); + emit dataChanged(index, index); + + // Modifying a value can also change the Modified status of a record (located in the parent row). + // To track this, we inform about the change of a whole parent row. + QModelIndex parentRowStart = this->index(index.parent().row(), 0); + QModelIndex parentRowEnd = this->index(index.parent().row(), columnCount(index.parent()) - 1); + emit dataChanged(parentRowStart, parentRowEnd); return true; } From 88c61ed2b6dabb11ae2760cf3095fd2004a4e031 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 2 Aug 2015 17:57:50 +0200 Subject: [PATCH 1976/3725] Fix NotifyDrawCompletedCallback in single threaded mode --- apps/openmw/mwrender/renderingmanager.cpp | 29 ++++++++++++++++++----- 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index c861119b5..54c6315fc 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -437,12 +437,31 @@ namespace MWRender class NotifyDrawCompletedCallback : public osg::Camera::DrawCallback { public: + NotifyDrawCompletedCallback() + : mDone(false) + { + } + virtual void operator () (osg::RenderInfo& renderInfo) const { + mMutex.lock(); + mDone = true; + mMutex.unlock(); mCondition.signal(); } + void waitTillDone() + { + mMutex.lock(); + if (mDone) + return; + mCondition.wait(&mMutex); + mMutex.unlock(); + } + mutable OpenThreads::Condition mCondition; + mutable OpenThreads::Mutex mMutex; + mutable bool mDone; }; void RenderingManager::screenshot(osg::Image *image, int w, int h) @@ -476,15 +495,13 @@ namespace MWRender mRootNode->addChild(rttCamera); - mViewer->frame(mViewer->getFrameStamp()->getSimulationTime()); - // The draw needs to complete before we can copy back our image. osg::ref_ptr callback (new NotifyDrawCompletedCallback); rttCamera->setFinalDrawCallback(callback); - OpenThreads::Mutex m; - m.lock(); - callback->mCondition.wait(&m); - m.unlock(); + + mViewer->frame(mViewer->getFrameStamp()->getSimulationTime()); + + callback->waitTillDone(); rttCamera->removeChildren(0, rttCamera->getNumChildren()); rttCamera->setGraphicsContext(NULL); From 664ae079db5db64e91ed152c0d69651a03ca066d Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 2 Aug 2015 18:05:15 +0200 Subject: [PATCH 1977/3725] Improve setting of culling mask for the savegame screenshot camera --- apps/openmw/mwrender/renderingmanager.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 54c6315fc..b01095f12 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -466,9 +466,6 @@ namespace MWRender void RenderingManager::screenshot(osg::Image *image, int w, int h) { - int oldCullMask = mViewer->getCamera()->getCullMask(); - mViewer->getCamera()->setCullMask(oldCullMask & (~Mask_GUI)); - osg::ref_ptr rttCamera (new osg::Camera); rttCamera->setNodeMask(Mask_RenderToTexture); rttCamera->attach(osg::Camera::COLOR_BUFFER, image); @@ -492,6 +489,7 @@ namespace MWRender image->setPixelFormat(texture->getInternalFormat()); rttCamera->addChild(mLightRoot); + rttCamera->setCullMask(mViewer->getCamera()->getCullMask() & (~Mask_GUI)); mRootNode->addChild(rttCamera); @@ -506,8 +504,6 @@ namespace MWRender rttCamera->removeChildren(0, rttCamera->getNumChildren()); rttCamera->setGraphicsContext(NULL); mRootNode->removeChild(rttCamera); - - mViewer->getCamera()->setCullMask(oldCullMask); } osg::Vec4f RenderingManager::getScreenBounds(const MWWorld::Ptr& ptr) From 33042c14644532ae53f18fa2c60bd7aacd42357a Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sun, 2 Aug 2015 17:16:06 +0300 Subject: [PATCH 1978/3725] Restore Modified status of a record when adding/removing nested rows --- apps/opencs/model/world/columnbase.hpp | 6 ++++++ apps/opencs/model/world/commands.cpp | 22 ++++++++++++++-------- apps/opencs/model/world/commands.hpp | 6 ++++++ 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index 59f2836c2..c4789ed22 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -192,6 +192,12 @@ namespace CSMWorld ColumnBase::Display_NestedHeader, flags) {} + virtual void set (Record& record, const QVariant& data) + { + // There is nothing to do here. + // This prevents exceptions from parent's implementation + } + virtual QVariant get (const Record& record) const { return true; // required by IdTree::hasChildren() diff --git a/apps/opencs/model/world/commands.cpp b/apps/opencs/model/world/commands.cpp index 019ffe7b2..7673e6bc9 100644 --- a/apps/opencs/model/world/commands.cpp +++ b/apps/opencs/model/world/commands.cpp @@ -289,21 +289,24 @@ CSMWorld::DeleteNestedCommand::DeleteNestedCommand (IdTree& model, std::string title = model.headerData(parentColumn, Qt::Horizontal, Qt::DisplayRole).toString().toUtf8().constData(); setText (("Delete row in " + title + " sub-table of " + mId).c_str()); + + QModelIndex parentIndex = mModel.getModelIndex(mId, mParentColumn); + mModifyParentCommand = new ModifyCommand(mModel, parentIndex, parentIndex.data(Qt::EditRole), this); } void CSMWorld::DeleteNestedCommand::redo() { - const QModelIndex& parentIndex = mModel.getModelIndex(mId, mParentColumn); - + QModelIndex parentIndex = mModel.getModelIndex(mId, mParentColumn); mModel.removeRows (mNestedRow, 1, parentIndex); + mModifyParentCommand->redo(); } void CSMWorld::DeleteNestedCommand::undo() { - const QModelIndex& parentIndex = mModel.getModelIndex(mId, mParentColumn); - + QModelIndex parentIndex = mModel.getModelIndex(mId, mParentColumn); mModel.setNestedTable(parentIndex, getOld()); + mModifyParentCommand->undo(); } CSMWorld::AddNestedCommand::AddNestedCommand(IdTree& model, const std::string& id, int nestedRow, int parentColumn, QUndoCommand* parent) @@ -317,20 +320,23 @@ CSMWorld::AddNestedCommand::AddNestedCommand(IdTree& model, const std::string& i std::string title = model.headerData(parentColumn, Qt::Horizontal, Qt::DisplayRole).toString().toUtf8().constData(); setText (("Add row in " + title + " sub-table of " + mId).c_str()); + + QModelIndex parentIndex = mModel.getModelIndex(mId, mParentColumn); + mModifyParentCommand = new ModifyCommand(mModel, parentIndex, parentIndex.data(Qt::EditRole), this); } void CSMWorld::AddNestedCommand::redo() { - const QModelIndex& parentIndex = mModel.getModelIndex(mId, mParentColumn); - + QModelIndex parentIndex = mModel.getModelIndex(mId, mParentColumn); mModel.addNestedRow (parentIndex, mNewRow); + mModifyParentCommand->redo(); } void CSMWorld::AddNestedCommand::undo() { - const QModelIndex& parentIndex = mModel.getModelIndex(mId, mParentColumn); - + QModelIndex parentIndex = mModel.getModelIndex(mId, mParentColumn); mModel.setNestedTable(parentIndex, getOld()); + mModifyParentCommand->undo(); } CSMWorld::NestedTableStoring::NestedTableStoring(const IdTree& model, const std::string& id, int parentColumn) diff --git a/apps/opencs/model/world/commands.hpp b/apps/opencs/model/world/commands.hpp index 81c40d0ab..23ffccbd7 100644 --- a/apps/opencs/model/world/commands.hpp +++ b/apps/opencs/model/world/commands.hpp @@ -200,6 +200,9 @@ namespace CSMWorld int mNestedRow; + // The command to redo/undo the Modified status of a record + ModifyCommand *mModifyParentCommand; + public: DeleteNestedCommand (IdTree& model, const std::string& id, int nestedRow, int parentColumn, QUndoCommand* parent = 0); @@ -219,6 +222,9 @@ namespace CSMWorld int mParentColumn; + // The command to redo/undo the Modified status of a record + ModifyCommand *mModifyParentCommand; + public: AddNestedCommand(IdTree& model, const std::string& id, int nestedRow, int parentColumn, QUndoCommand* parent = 0); From 1590a04d03a8385e7c4e496f32613e76ec339f7f Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sun, 2 Aug 2015 22:39:41 +0300 Subject: [PATCH 1979/3725] Close EditWidget when a proper row removed --- apps/opencs/view/world/dialoguesubview.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 5a44708c1..d537f2eb1 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -811,8 +811,13 @@ void CSVWorld::SimpleDialogueSubView::dataChanged (const QModelIndex & index) void CSVWorld::SimpleDialogueSubView::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) { QModelIndex currentIndex(mTable->getModelIndex(getUniversalId().getId(), 0)); + + if (!currentIndex.isValid()) + { + return; + } - if (currentIndex.isValid() && currentIndex.row() >= start && currentIndex.row() <= end) + if (currentIndex.parent() == parent && currentIndex.row() >= start && currentIndex.row() <= end) { if(mEditWidget) { From 6b3de5c72025140868e763f81204728e49156ed3 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sun, 2 Aug 2015 22:53:40 +0300 Subject: [PATCH 1980/3725] Activate editing of nested table cells by a double click --- apps/opencs/view/world/dialoguesubview.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index d537f2eb1..5ad2f76e2 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -570,8 +570,6 @@ void CSVWorld::EditWidget::remake(int row) table->setEditTriggers(QAbstractItemView::NoEditTriggers); table->setEnabled(false); } - else - table->setEditTriggers(QAbstractItemView::SelectedClicked | QAbstractItemView::CurrentChanged); int rows = mTable->rowCount(mTable->index(row, i)); int rowHeight = (rows == 0) ? table->horizontalHeader()->height() : table->rowHeight(0); From 0ea4d1981a6c01cf780948dbad8e9f1840004efc Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Mon, 3 Aug 2015 19:08:01 +0300 Subject: [PATCH 1981/3725] Add magic effect verifier --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/tools/magiceffectcheck.cpp | 137 +++++++++++++++++++ apps/opencs/model/tools/magiceffectcheck.hpp | 50 +++++++ apps/opencs/model/tools/tools.cpp | 7 + 4 files changed, 195 insertions(+), 1 deletion(-) create mode 100644 apps/opencs/model/tools/magiceffectcheck.cpp create mode 100644 apps/opencs/model/tools/magiceffectcheck.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 1a51d2d8d..e6dd045e1 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -41,7 +41,7 @@ opencs_units (model/tools opencs_units_noqt (model/tools mandatoryid skillcheck classcheck factioncheck racecheck soundcheck regioncheck birthsigncheck spellcheck referencecheck referenceablecheck scriptcheck bodypartcheck - startscriptcheck search searchoperation searchstage pathgridcheck soundgencheck + startscriptcheck search searchoperation searchstage pathgridcheck soundgencheck magiceffectcheck ) diff --git a/apps/opencs/model/tools/magiceffectcheck.cpp b/apps/opencs/model/tools/magiceffectcheck.cpp new file mode 100644 index 000000000..22620929c --- /dev/null +++ b/apps/opencs/model/tools/magiceffectcheck.cpp @@ -0,0 +1,137 @@ +#include "magiceffectcheck.hpp" + +#include + +#include "../world/resources.hpp" +#include "../world/data.hpp" + +namespace +{ + void addMessageIfNotEmpty(CSMDoc::Messages &messages, const CSMWorld::UniversalId &id, const std::string text) + { + if (!text.empty()) + { + messages.push_back(std::make_pair(id, text)); + } + } +} + +bool CSMTools::MagicEffectCheckStage::isTextureExists(const std::string &texture, bool isIcon) const +{ + const CSMWorld::Resources &textures = isIcon ? mIcons : mTextures; + bool exists = false; + + if (textures.searchId(texture) != -1) + { + exists = true; + } + else + { + std::string ddsTexture = texture; + if (Misc::ResourceHelpers::changeExtensionToDds(ddsTexture) && textures.searchId(ddsTexture) != -1) + { + exists = true; + } + } + + return exists; +} + +std::string CSMTools::MagicEffectCheckStage::checkReferenceable(const std::string &id, + const CSMWorld::UniversalId &type, + const std::string &column) const +{ + std::string error; + if (!id.empty()) + { + CSMWorld::RefIdData::LocalIndex index = mReferenceables.getDataSet().searchId(id); + if (index.first == -1) + { + error = "No such " + column + " '" + id + "'"; + } + else if (index.second != type.getType()) + { + error = column + " is not of type " + type.getTypeName(); + } + } + return error; +} + +std::string CSMTools::MagicEffectCheckStage::checkSound(const std::string &id, const std::string &column) const +{ + std::string error; + if (!id.empty() && mSounds.searchId(id) == -1) + { + error = "No such " + column + " '" + id + "'"; + } + return error; +} + +CSMTools::MagicEffectCheckStage::MagicEffectCheckStage(const CSMWorld::IdCollection &effects, + const CSMWorld::IdCollection &sounds, + const CSMWorld::RefIdCollection &referenceables, + const CSMWorld::Resources &icons, + const CSMWorld::Resources &textures) + : mMagicEffects(effects), + mSounds(sounds), + mReferenceables(referenceables), + mIcons(icons), + mTextures(textures) +{} + +int CSMTools::MagicEffectCheckStage::setup() +{ + return mMagicEffects.getSize(); +} + +void CSMTools::MagicEffectCheckStage::perform(int stage, CSMDoc::Messages &messages) +{ + ESM::MagicEffect effect = mMagicEffects.getRecord(stage).get(); + CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_MagicEffect, effect.mId); + + if (effect.mData.mBaseCost < 0.0f) + { + messages.push_back(std::make_pair(id, "Base Cost is negative")); + } + + if (effect.mIcon.empty()) + { + messages.push_back(std::make_pair(id, "Icon is not specified")); + } + else if (!isTextureExists(effect.mIcon, true)) + { + messages.push_back(std::make_pair(id, "No such Icon '" + effect.mIcon + "'")); + } + + if (effect.mParticle.empty()) + { + messages.push_back(std::make_pair(id, "Particle is not specified")); + } + else if (!isTextureExists(effect.mParticle, false)) + { + messages.push_back(std::make_pair(id, "No such Particle '" + effect.mParticle + "'")); + } + + addMessageIfNotEmpty(messages, + id, + checkReferenceable(effect.mCasting, CSMWorld::UniversalId::Type_Static, "Casting Object")); + addMessageIfNotEmpty(messages, + id, + checkReferenceable(effect.mHit, CSMWorld::UniversalId::Type_Static, "Hit Object")); + addMessageIfNotEmpty(messages, + id, + checkReferenceable(effect.mArea, CSMWorld::UniversalId::Type_Static, "Area Object")); + addMessageIfNotEmpty(messages, + id, + checkReferenceable(effect.mBolt, CSMWorld::UniversalId::Type_Weapon, "Bolt Object")); + + addMessageIfNotEmpty(messages, id, checkSound(effect.mCastSound, "Casting Sound")); + addMessageIfNotEmpty(messages, id, checkSound(effect.mHitSound, "Hit Sound")); + addMessageIfNotEmpty(messages, id, checkSound(effect.mAreaSound, "Area Sound")); + addMessageIfNotEmpty(messages, id, checkSound(effect.mBoltSound, "Bolt Sound")); + + if (effect.mDescription.empty()) + { + messages.push_back(std::make_pair(id, "Description is empty")); + } +} diff --git a/apps/opencs/model/tools/magiceffectcheck.hpp b/apps/opencs/model/tools/magiceffectcheck.hpp new file mode 100644 index 000000000..0ad6760d3 --- /dev/null +++ b/apps/opencs/model/tools/magiceffectcheck.hpp @@ -0,0 +1,50 @@ +#ifndef CSM_TOOLS_MAGICEFFECTCHECK_HPP +#define CSM_TOOLS_MAGICEFFECTCHECK_HPP + +#include +#include + +#include "../world/idcollection.hpp" +#include "../world/refidcollection.hpp" + +#include "../doc/stage.hpp" + +namespace CSMWorld +{ + class Resources; +} + +namespace CSMTools +{ + /// \brief VerifyStage: make sure that magic effect records are internally consistent + class MagicEffectCheckStage : public CSMDoc::Stage + { + const CSMWorld::IdCollection &mMagicEffects; + const CSMWorld::IdCollection &mSounds; + const CSMWorld::RefIdCollection &mReferenceables; + const CSMWorld::Resources &mIcons; + const CSMWorld::Resources &mTextures; + + private: + bool isTextureExists(const std::string &texture, bool isIcon) const; + + std::string checkReferenceable(const std::string &id, + const CSMWorld::UniversalId &type, + const std::string &column) const; + std::string checkSound(const std::string &id, const std::string &column) const; + + public: + MagicEffectCheckStage(const CSMWorld::IdCollection &effects, + const CSMWorld::IdCollection &sounds, + const CSMWorld::RefIdCollection &referenceables, + const CSMWorld::Resources &icons, + const CSMWorld::Resources &textures); + + virtual int setup(); + ///< \return number of steps + virtual void perform (int stage, CSMDoc::Messages &messages); + ///< Messages resulting from this tage will be appended to \a messages. + }; +} + +#endif diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index c9c116091..97943b1fb 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -28,6 +28,7 @@ #include "searchoperation.hpp" #include "pathgridcheck.hpp" #include "soundgencheck.hpp" +#include "magiceffectcheck.hpp" CSMDoc::OperationHolder *CSMTools::Tools::get (int type) { @@ -108,6 +109,12 @@ CSMDoc::OperationHolder *CSMTools::Tools::getVerifier() mData.getSounds(), mData.getReferenceables())); + mVerifierOperation->appendStage (new MagicEffectCheckStage (mData.getMagicEffects(), + mData.getSounds(), + mData.getReferenceables(), + mData.getResources (CSMWorld::UniversalId::Type_Icons), + mData.getResources (CSMWorld::UniversalId::Type_Textures))); + mVerifier.setOperation (mVerifierOperation); } From 8da9eecea755e19b8d1719e0183243a517a36591 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Mon, 3 Aug 2015 19:24:00 +0300 Subject: [PATCH 1982/3725] Correct comparison of enum values in IdTableProxyModel --- apps/opencs/model/world/idtableproxymodel.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/world/idtableproxymodel.cpp b/apps/opencs/model/world/idtableproxymodel.cpp index 10fd92b46..757285412 100644 --- a/apps/opencs/model/world/idtableproxymodel.cpp +++ b/apps/opencs/model/world/idtableproxymodel.cpp @@ -5,6 +5,18 @@ #include "idtablebase.hpp" +namespace +{ + std::string getEnumValue(const std::vector &values, int index) + { + if (index < 0 || index >= static_cast(values.size())) + { + return ""; + } + return values[index]; + } +} + void CSMWorld::IdTableProxyModel::updateColumnMap() { Q_ASSERT(mSourceModel != NULL); @@ -93,7 +105,9 @@ bool CSMWorld::IdTableProxyModel::lessThan(const QModelIndex &left, const QModel if (valuesIt != mEnumColumnCache.end()) { - return valuesIt->second[left.data().toInt()] < valuesIt->second[right.data().toInt()]; + std::string first = getEnumValue(valuesIt->second, left.data().toInt()); + std::string second = getEnumValue(valuesIt->second, right.data().toInt()); + return first < second; } return QSortFilterProxyModel::lessThan(left, right); } From 21e249cb9234b6b40a9e5e15ceb92ab7e3d3c0b4 Mon Sep 17 00:00:00 2001 From: dteviot Date: Tue, 4 Aug 2015 18:14:36 +1200 Subject: [PATCH 1983/3725] pass parameters as const & --- apps/openmw/mwmechanics/pathfinding.cpp | 8 ++++---- apps/openmw/mwmechanics/pathfinding.hpp | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index 79cee9f32..c7d71e13e 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -87,14 +87,14 @@ namespace namespace MWMechanics { - float sqrDistanceIgnoreZ(ESM::Pathgrid::Point point, float x, float y) + float sqrDistanceIgnoreZ(const ESM::Pathgrid::Point& point, float x, float y) { x -= point.mX; y -= point.mY; return (x * x + y * y); } - float distance(ESM::Pathgrid::Point point, float x, float y, float z) + float distance(const ESM::Pathgrid::Point& point, float x, float y, float z) { x -= point.mX; y -= point.mY; @@ -102,7 +102,7 @@ namespace MWMechanics return sqrt(x * x + y * y + z * z); } - float distance(ESM::Pathgrid::Point a, ESM::Pathgrid::Point b) + float distance(const ESM::Pathgrid::Point& a, const ESM::Pathgrid::Point& b) { float x = static_cast(a.mX - b.mX); float y = static_cast(a.mY - b.mY); @@ -272,7 +272,7 @@ namespace MWMechanics if(mPath.empty()) return true; - ESM::Pathgrid::Point nextPoint = *mPath.begin(); + const ESM::Pathgrid::Point& nextPoint = *mPath.begin(); if (sqrDistanceIgnoreZ(nextPoint, x, y) < tolerance*tolerance) { mPath.pop_front(); diff --git a/apps/openmw/mwmechanics/pathfinding.hpp b/apps/openmw/mwmechanics/pathfinding.hpp index 4000f5d80..1765a5cc5 100644 --- a/apps/openmw/mwmechanics/pathfinding.hpp +++ b/apps/openmw/mwmechanics/pathfinding.hpp @@ -12,8 +12,8 @@ namespace MWWorld namespace MWMechanics { - float distance(ESM::Pathgrid::Point point, float x, float y, float); - float distance(ESM::Pathgrid::Point a, ESM::Pathgrid::Point b); + float distance(const ESM::Pathgrid::Point& point, float x, float y, float); + float distance(const ESM::Pathgrid::Point& a, const ESM::Pathgrid::Point& b); class PathFinder { public: From 4256e151b131453ca045fae270565e6a71e656b9 Mon Sep 17 00:00:00 2001 From: dteviot Date: Tue, 4 Aug 2015 18:15:58 +1200 Subject: [PATCH 1984/3725] Fixed error in deciding type of attack --- apps/openmw/mwmechanics/aicombat.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index dd843b9a3..776641e60 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -689,16 +689,14 @@ ESM::Weapon::AttackType chooseBestAttack(const ESM::Weapon* weapon, MWMechanics: int chop = (weapon->mData.mChop[0] + weapon->mData.mChop[1])/2; int thrust = (weapon->mData.mThrust[0] + weapon->mData.mThrust[1])/2; - float total = static_cast(slash + chop + thrust); - - float roll = Misc::Rng::rollClosedProbability(); - if(roll <= (slash/total)) + float roll = Misc::Rng::rollClosedProbability() * (slash + chop + thrust); + if(roll <= slash) { movement.mPosition[0] = (Misc::Rng::rollClosedProbability() < 0.5f) ? 1.0f : -1.0f; movement.mPosition[1] = 0; attackType = ESM::Weapon::AT_Slash; } - else if(roll <= (slash + (thrust/total))) + else if(roll <= (slash + thrust)) { movement.mPosition[1] = 1; attackType = ESM::Weapon::AT_Thrust; From ad9bab0b68f91a59d93f4b538d7575481149c466 Mon Sep 17 00:00:00 2001 From: dteviot Date: Tue, 4 Aug 2015 18:17:08 +1200 Subject: [PATCH 1985/3725] Removed redundant if. --- apps/openmw/mwmechanics/aicombat.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 776641e60..560be888c 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -503,12 +503,14 @@ namespace MWMechanics } // don't use pathgrid when actor can move in 3 dimensions - if(canMoveByZ) preferShortcut = true; + if (canMoveByZ) + { + preferShortcut = true; + movement.mRotation[0] = getXAngleToDir(vDirToTarget, distToTarget); + } if(preferShortcut) { - if (canMoveByZ) - movement.mRotation[0] = getXAngleToDir(vDirToTarget, distToTarget); movement.mRotation[2] = getZAngleToDir(vDirToTarget); forceNoShortcut = false; shortcutFailPos.pos[0] = shortcutFailPos.pos[1] = shortcutFailPos.pos[2] = 0; From 58f732ebc9f1cd88f04814caa8b7af66ce5a86fe Mon Sep 17 00:00:00 2001 From: dteviot Date: Tue, 4 Aug 2015 18:20:05 +1200 Subject: [PATCH 1986/3725] Update path following checks each frame in AiCombat. --- apps/openmw/mwmechanics/aicombat.cpp | 38 ++++++++++++++++++---------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 560be888c..f386ec81b 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -429,6 +429,7 @@ namespace MWMechanics // (within attack dist) || (not quite attack dist while following) if(inLOS && (distToTarget < rangeAttack || (distToTarget <= rangeFollow && followTarget && !isStuck))) { + mPathFinder.clearPath(); //Melee and Close-up combat // getXAngleToDir determines vertical angle to target: @@ -528,9 +529,7 @@ namespace MWMechanics buildNewPath(actor, target); //may fail to build a path, check before use - //delete visited path node - mPathFinder.checkPathCompleted(pos.pos[0],pos.pos[1]); - + // if current actor pos is closer to target then last point of path (excluding target itself) then go straight on target // This works on the borders between the path grid and areas with no waypoints. if(inLOS && mPathFinder.getPath().size() > 1) { @@ -539,21 +538,16 @@ namespace MWMechanics --pntIter; osg::Vec3f vBeforeTarget(PathFinder::MakeOsgVec3(*pntIter)); - // if current actor pos is closer to target then last point of path (excluding target itself) then go straight on target if(distToTarget <= (vTargetPos - vBeforeTarget).length()) { - movement.mRotation[2] = getZAngleToDir(vDirToTarget); - preferShortcut = true; + mPathFinder.clearPath(); } } // if there is no new path, then go straight on target - if(!preferShortcut) + if (!mPathFinder.isPathConstructed()) { - if(!mPathFinder.getPath().empty()) - movement.mRotation[2] = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]); - else - movement.mRotation[2] = getZAngleToDir(vDirToTarget); + movement.mRotation[2] = getZAngleToDir(vDirToTarget); } } @@ -573,9 +567,25 @@ namespace MWMechanics void AiCombat::UpdateActorsMovement(const MWWorld::Ptr& actor, MWMechanics::Movement& desiredMovement) { MWMechanics::Movement& actorMovementSettings = actor.getClass().getMovementSettings(actor); - actorMovementSettings = desiredMovement; - RotateActorOnAxis(actor, 2, actorMovementSettings, desiredMovement); - RotateActorOnAxis(actor, 0, actorMovementSettings, desiredMovement); + if (mPathFinder.isPathConstructed()) + { + const ESM::Position& pos = actor.getRefData().getPosition(); + if (mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1])) + { + actorMovementSettings.mPosition[1] = 0; + } + else + { + zTurn(actor, mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1])); + actorMovementSettings.mPosition[1] = 1; + } + } + else + { + actorMovementSettings = desiredMovement; + RotateActorOnAxis(actor, 2, actorMovementSettings, desiredMovement); + RotateActorOnAxis(actor, 0, actorMovementSettings, desiredMovement); + } } void AiCombat::RotateActorOnAxis(const MWWorld::Ptr& actor, int axis, From 581ea2660522dbefedd197753dac380298e001d2 Mon Sep 17 00:00:00 2001 From: Alexandre Moine Date: Tue, 4 Aug 2015 13:05:29 +0200 Subject: [PATCH 1987/3725] Add appdata file for openmw and install it --- CMakeLists.txt | 3 +++ files/openmw.appdata.xml | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 files/openmw.appdata.xml diff --git a/CMakeLists.txt b/CMakeLists.txt index a14beb423..99fb56fbe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -334,6 +334,8 @@ configure_file(${OpenMW_SOURCE_DIR}/files/gamecontrollerdb.txt if (NOT WIN32 AND NOT APPLE) configure_file(${OpenMW_SOURCE_DIR}/files/openmw.desktop "${OpenMW_BINARY_DIR}/openmw.desktop") + configure_file(${OpenMW_SOURCE_DIR}/files/openmw.appdata.xml + "${OpenMW_BINARY_DIR}/openmw.appdata.xml") configure_file(${OpenMW_SOURCE_DIR}/files/openmw-cs.desktop "${OpenMW_BINARY_DIR}/openmw-cs.desktop") endif() @@ -422,6 +424,7 @@ IF(NOT WIN32 AND NOT APPLE) # Install icon and desktop file INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.desktop" DESTINATION "${DATAROOTDIR}/applications" COMPONENT "openmw") INSTALL(FILES "${OpenMW_SOURCE_DIR}/files/launcher/images/openmw.png" DESTINATION "${ICONDIR}" COMPONENT "openmw") + INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.appdata.xml" DESTINATION "${DATAROOTDIR}/appdata" COMPONENT "openmw") IF(BUILD_OPENCS) INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw-cs.desktop" DESTINATION "${DATAROOTDIR}/applications" COMPONENT "opencs") INSTALL(FILES "${OpenMW_SOURCE_DIR}/files/opencs/openmw-cs.png" DESTINATION "${ICONDIR}" COMPONENT "opencs") diff --git a/files/openmw.appdata.xml b/files/openmw.appdata.xml new file mode 100644 index 000000000..150eea984 --- /dev/null +++ b/files/openmw.appdata.xml @@ -0,0 +1,39 @@ + + + + openmw.desktop + CC0-1.0 + GPL-3.0 and MIT and zlib + OpenMW + Unofficial open source engine re-implementation of the game Morrowind + +

    + OpenMW is a recreation of 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. +

    +

    + The main quests in Morrowind, Tribunal and Bloodmoon are all completable. Some issues with side quests are to be expected (but rare). +

    +

    + Pre-existing modifications created for the original Morrowind engine can be hit-and-miss, but a mod created for Morrowind may not necessarily run in OpenMW. +

    +
    + + + + http://wiki.openmw.org/images/b/b2/Openmw_0.11.1_launcher_1.png + The OpenMW launcher + + + http://wiki.openmw.org/images/f/f1/Screenshot_mournhold_plaza_0.35.png + The Mournhold's plaza on OpenMW + + + http://wiki.openmw.org/images/5/5b/Screenshot_Vivec_seen_from_Ebonheart_0.35.png + Vivec seen from Ebonheart on OpenMW + + +nobrakal@gmail.com + https://openmw.org + https://bugs.openmw.org/ + https://openmw.org/faq/ +
    From cbc8309289c9f4dc9fe4603cb04565e878b6addc Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Tue, 4 Aug 2015 16:19:00 +0300 Subject: [PATCH 1988/3725] Don't allow empty value of School field in Magic Effects table --- apps/opencs/view/doc/viewmanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 7aec001cf..0db51dfd2 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -97,7 +97,7 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) { CSMWorld::ColumnBase::Display_MeshType, CSMWorld::Columns::ColumnId_MeshType, false }, { CSMWorld::ColumnBase::Display_Gender, CSMWorld::Columns::ColumnId_Gender, true }, { CSMWorld::ColumnBase::Display_SoundGeneratorType, CSMWorld::Columns::ColumnId_SoundGeneratorType, false }, - { CSMWorld::ColumnBase::Display_School, CSMWorld::Columns::ColumnId_School, true }, + { CSMWorld::ColumnBase::Display_School, CSMWorld::Columns::ColumnId_School, false }, { CSMWorld::ColumnBase::Display_SkillImpact, CSMWorld::Columns::ColumnId_SkillImpact, true }, { CSMWorld::ColumnBase::Display_EffectRange, CSMWorld::Columns::ColumnId_EffectRange, false }, { CSMWorld::ColumnBase::Display_EffectId, CSMWorld::Columns::ColumnId_EffectId, false }, From 8ae7c63c456985cea6198e9085023c5d7ce03c4b Mon Sep 17 00:00:00 2001 From: "taras.kudryavtsev" Date: Tue, 4 Aug 2015 16:56:05 +0300 Subject: [PATCH 1989/3725] #2730 and #2725 --- apps/opencs/model/world/columnbase.cpp | 1 - apps/opencs/model/world/columnbase.hpp | 1 - apps/opencs/model/world/refidcollection.cpp | 2 +- apps/opencs/view/doc/viewmanager.cpp | 2 +- apps/opencs/view/world/dialoguesubview.cpp | 24 ++++++++++++++------- 5 files changed, 18 insertions(+), 12 deletions(-) diff --git a/apps/opencs/model/world/columnbase.cpp b/apps/opencs/model/world/columnbase.cpp index f209e48c6..2143ec730 100644 --- a/apps/opencs/model/world/columnbase.cpp +++ b/apps/opencs/model/world/columnbase.cpp @@ -82,7 +82,6 @@ bool CSMWorld::ColumnBase::isId (Display display) Display_EffectId, Display_PartRefType, Display_AiPackageType, - Display_YesNo, Display_InfoCondFunc, Display_InfoCondVar, Display_InfoCondComp, diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index c4789ed22..400e31333 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -118,7 +118,6 @@ namespace CSMWorld Display_EffectId, Display_PartRefType, Display_AiPackageType, - Display_YesNo, Display_InfoCondFunc, Display_InfoCondVar, Display_InfoCondComp, diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 5495926b4..947454d77 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -198,7 +198,7 @@ CSMWorld::RefIdCollection::RefIdCollection() mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_AiWanderIdle, CSMWorld::ColumnBase::Display_Integer)); mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_AiWanderRepeat, CSMWorld::ColumnBase::Display_YesNo)); + new RefIdColumn (Columns::ColumnId_AiWanderRepeat, CSMWorld::ColumnBase::Display_Boolean)); mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_AiActivateName, CSMWorld::ColumnBase::Display_String)); mColumns.back().addColumn( diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 7aec001cf..cc91a5d72 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -103,7 +103,7 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) { CSMWorld::ColumnBase::Display_EffectId, CSMWorld::Columns::ColumnId_EffectId, false }, { CSMWorld::ColumnBase::Display_PartRefType, CSMWorld::Columns::ColumnId_PartRefType, false }, { CSMWorld::ColumnBase::Display_AiPackageType, CSMWorld::Columns::ColumnId_AiPackageType, false }, - { CSMWorld::ColumnBase::Display_YesNo, CSMWorld::Columns::ColumnId_AiWanderRepeat, false }, + { CSMWorld::ColumnBase::Display_Boolean, CSMWorld::Columns::ColumnId_AiWanderRepeat, false }, { CSMWorld::ColumnBase::Display_InfoCondFunc, CSMWorld::Columns::ColumnId_InfoCondFunc, false }, { CSMWorld::ColumnBase::Display_InfoCondComp, CSMWorld::Columns::ColumnId_InfoCondComp, false }, { CSMWorld::ColumnBase::Display_RaceSkill, CSMWorld::Columns::ColumnId_RaceSkill, true }, diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 5ad2f76e2..2bfde4b22 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -740,13 +740,15 @@ CSVWorld::SimpleDialogueSubView::SimpleDialogueSubView (const CSMWorld::Universa mMainLayout = new QVBoxLayout(mainWidget); setWidget (mainWidget); + int idColumn = getTable().findColumnIndex (CSMWorld::Columns::ColumnId_Id); + mEditWidget = new EditWidget(mainWidget, - mTable->getModelIndex(getUniversalId().getId(), 0).row(), mTable, mCommandDispatcher, document, false); + mTable->getModelIndex(getUniversalId().getId(), idColumn).row(), mTable, mCommandDispatcher, document, false); mMainLayout->addWidget(mEditWidget); mEditWidget->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); - dataChanged(mTable->getModelIndex (getUniversalId().getId(), 0)); + dataChanged(mTable->getModelIndex (getUniversalId().getId(), idColumn)); connect(mEditWidget, SIGNAL(editIdRequest(const CSMWorld::UniversalId &, const std::string &)), @@ -759,8 +761,9 @@ void CSVWorld::SimpleDialogueSubView::setEditLock (bool locked) if (!mEditWidget) // hack to indicate that getUniversalId().getId() is no longer valid return; + int idColumn = getTable().findColumnIndex (CSMWorld::Columns::ColumnId_Id); mLocked = locked; - QModelIndex currentIndex(mTable->getModelIndex(getUniversalId().getId(), 0)); + QModelIndex currentIndex(mTable->getModelIndex(getUniversalId().getId(), idColumn)); if (currentIndex.isValid()) { @@ -775,7 +778,8 @@ void CSVWorld::SimpleDialogueSubView::setEditLock (bool locked) void CSVWorld::SimpleDialogueSubView::dataChanged (const QModelIndex & index) { - QModelIndex currentIndex(mTable->getModelIndex(getUniversalId().getId(), 0)); + int idColumn = getTable().findColumnIndex (CSMWorld::Columns::ColumnId_Id); + QModelIndex currentIndex(mTable->getModelIndex(getUniversalId().getId(), idColumn)); if (currentIndex.isValid() && (index.parent().isValid() ? index.parent().row() : index.row()) == currentIndex.row()) @@ -808,7 +812,8 @@ void CSVWorld::SimpleDialogueSubView::dataChanged (const QModelIndex & index) void CSVWorld::SimpleDialogueSubView::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) { - QModelIndex currentIndex(mTable->getModelIndex(getUniversalId().getId(), 0)); + int idColumn = getTable().findColumnIndex (CSMWorld::Columns::ColumnId_Id); + QModelIndex currentIndex(mTable->getModelIndex(getUniversalId().getId(), idColumn)); if (!currentIndex.isValid()) { @@ -906,7 +911,8 @@ void CSVWorld::DialogueSubView::updateUserSetting (const QString& name, const QS void CSVWorld::DialogueSubView::showPreview () { - QModelIndex currentIndex (getTable().getModelIndex (getUniversalId().getId(), 0)); + int idColumn = getTable().findColumnIndex (CSMWorld::Columns::ColumnId_Id); + QModelIndex currentIndex (getTable().getModelIndex (getUniversalId().getId(), idColumn)); if (currentIndex.isValid() && getTable().getFeatures() & CSMWorld::IdTable::Feature_Preview && @@ -918,7 +924,8 @@ void CSVWorld::DialogueSubView::showPreview () void CSVWorld::DialogueSubView::viewRecord () { - QModelIndex currentIndex (getTable().getModelIndex (getUniversalId().getId(), 0)); + int idColumn = getTable().findColumnIndex (CSMWorld::Columns::ColumnId_Id); + QModelIndex currentIndex (getTable().getModelIndex (getUniversalId().getId(), idColumn)); if (currentIndex.isValid() && currentIndex.row() < getTable().rowCount()) @@ -953,7 +960,8 @@ void CSVWorld::DialogueSubView::switchToRow (int row) void CSVWorld::DialogueSubView::requestFocus (const std::string& id) { - QModelIndex index = getTable().getModelIndex (id, 0); + int idColumn = getTable().findColumnIndex (CSMWorld::Columns::ColumnId_Id); + QModelIndex index = getTable().getModelIndex (id, idColumn); if (index.isValid()) switchToRow (index.row()); From 8c8c5328dc8f8c96a70ebe0eb765fae573f1922a Mon Sep 17 00:00:00 2001 From: Alexandre Moine Date: Tue, 4 Aug 2015 22:50:53 +0200 Subject: [PATCH 1990/3725] Rewrite of the description --- files/openmw.appdata.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/files/openmw.appdata.xml b/files/openmw.appdata.xml index 150eea984..1c16cb9a4 100644 --- a/files/openmw.appdata.xml +++ b/files/openmw.appdata.xml @@ -8,13 +8,13 @@ Unofficial open source engine re-implementation of the game Morrowind

    - OpenMW is a recreation of 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. + OpenMW is a new engine for 2002's Game of the Year, The Elder Scrolls 3: Morrowind.

    - The main quests in Morrowind, Tribunal and Bloodmoon are all completable. Some issues with side quests are to be expected (but rare). + It aims to be a fully playable (and improved!), open source implementation of the game's engine and functionality (including mods).

    - Pre-existing modifications created for the original Morrowind engine can be hit-and-miss, but a mod created for Morrowind may not necessarily run in OpenMW. + You will still need the original game data to play OpenMW.

    From ea2f88a355f7c1aeaad26fced87a70863f72ad6a Mon Sep 17 00:00:00 2001 From: slothlife Date: Tue, 4 Aug 2015 21:07:42 -0500 Subject: [PATCH 1991/3725] Fix several sky rendering bugs, maybe also #639 Added code to hide the moons, sun, and stars for certain weather effects. Lightly refactored CelestialBody and derived classes. Fixed moons switching phase at 24:00. --- apps/openmw/mwrender/sky.cpp | 318 ++++++++++++++++---------------- apps/openmw/mwrender/sky.hpp | 58 +++++- apps/openmw/mwworld/weather.cpp | 37 +++- apps/openmw/mwworld/weather.hpp | 54 +----- 4 files changed, 248 insertions(+), 219 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 8330835a6..3a2da230f 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include @@ -322,11 +321,12 @@ private: int mMeshType; }; -class CelestialBody +// A base class for the sun and moons. Must be stored in an osg::ref_ptr due to being +// derived from osg::Referenced. +class CelestialBody : public SceneUtil::StateSetUpdater { public: - CelestialBody(osg::Group* parentNode, Resource::SceneManager* sceneManager, float scaleFactor = 1.f, int numUvSets=1) - : mSceneManager(sceneManager) + CelestialBody(osg::Group* parentNode, float scaleFactor = 1.f, int numUvSets=1) { mGeode = new osg::Geode; osg::ref_ptr geom = createTexturedQuad(numUvSets); @@ -336,42 +336,85 @@ public: mTransform->addChild(mGeode); parentNode->addChild(mTransform); + + mGeode->addUpdateCallback(this); } - void setDirection(const osg::Vec3f& direction) + virtual ~CelestialBody() { - osg::Vec3f normalizedDirection = direction / direction.length(); - mTransform->setPosition(normalizedDirection*1000.f); - - osg::Quat quat; - quat.makeRotate(osg::Vec3f(0,0,1), normalizedDirection); - mTransform->setAttitude(quat); + mGeode->removeUpdateCallback(this); } + virtual void adjustTransparency(const float ratio) = 0; + void setVisible(bool visible) { mTransform->setNodeMask(visible ? ~0 : 0); } protected: + static const float mDistance; osg::ref_ptr mTransform; osg::ref_ptr mGeode; - Resource::SceneManager* mSceneManager; - }; +const float CelestialBody::mDistance = 1000.0f; + class Sun : public CelestialBody { public: - Sun(osg::Group* parentNode, Resource::SceneManager* sceneManager) - : CelestialBody(parentNode, sceneManager, 1.f, 1) + Sun(osg::Group* parentNode, Resource::TextureManager& textureManager) + : CelestialBody(parentNode, 1.0f, 1) + , mColor(1.0f, 1.0f, 1.0f, 1.0f) + , mDummyTexture(textureManager.getWarningTexture()) { - osg::ref_ptr tex = mSceneManager->getTextureManager()->getTexture2D("textures/tx_sun_05.dds", - osg::Texture::CLAMP, osg::Texture::CLAMP); + osg::ref_ptr tex = textureManager.getTexture2D("textures/tx_sun_05.dds", + osg::Texture::CLAMP, + osg::Texture::CLAMP); mTransform->getOrCreateStateSet()->setTextureAttributeAndModes(0, tex, osg::StateAttribute::ON); mTransform->getOrCreateStateSet()->setAttributeAndModes(createUnlitMaterial(), osg::StateAttribute::ON); } + + virtual void setDefaults(osg::StateSet* stateset) + { + osg::ref_ptr texEnv(new osg::TexEnvCombine); + texEnv->setCombine_Alpha(osg::TexEnvCombine::MODULATE); + texEnv->setSource0_Alpha(osg::TexEnvCombine::PREVIOUS); + texEnv->setSource1_Alpha(osg::TexEnvCombine::CONSTANT); + texEnv->setCombine_RGB(osg::TexEnvCombine::REPLACE); + texEnv->setSource0_RGB(osg::TexEnvCombine::PREVIOUS); + texEnv->setConstantColor(osg::Vec4f(1.0f, 1.0f, 1.0f, 1.0f)); + + stateset->setTextureAttributeAndModes(1, mDummyTexture, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + stateset->setTextureAttributeAndModes(1, texEnv, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + } + + virtual void apply(osg::StateSet* stateset, osg::NodeVisitor*) + { + osg::TexEnvCombine* texEnv = static_cast(stateset->getTextureAttribute(1, osg::StateAttribute::TEXENV)); + texEnv->setConstantColor(mColor); + } + + virtual void adjustTransparency(const float ratio) + { + mColor.a() = ratio; + } + + void setDirection(const osg::Vec3f& direction) + { + osg::Vec3f normalizedDirection = direction / direction.length(); + mTransform->setPosition(normalizedDirection * mDistance); + + osg::Quat quat; + quat.makeRotate(osg::Vec3f(0.0f, 0.0f, 1.0f), normalizedDirection); + mTransform->setAttitude(quat); + } + +private: + + osg::Vec4f mColor; + osg::ref_ptr mDummyTexture; }; class Moon : public CelestialBody @@ -383,18 +426,57 @@ public: Type_Secunda }; - Moon(osg::Group* parentNode, Resource::SceneManager* sceneManager, float scaleFactor, Type type) - : CelestialBody(parentNode, sceneManager, scaleFactor, 2) + Moon(osg::Group* parentNode, Resource::TextureManager& textureManager, float scaleFactor, Type type) + : CelestialBody(parentNode, scaleFactor, 2) + , mTextureManager(textureManager) , mType(type) , mPhase(MoonState::Phase_Unspecified) + , mTransparency(1.0f) + , mShadowBlend(1.0f) + , mMoonColor(1.0f, 1.0f, 1.0f, 1.0f) { - mUpdater = new MoonUpdater; - mGeode->addUpdateCallback(mUpdater); - setPhase(MoonState::Phase_Full); setVisible(true); } + virtual void setDefaults(osg::StateSet *stateset) + { + stateset->setTextureAttributeAndModes(0, mPhaseTex, osg::StateAttribute::ON); + osg::ref_ptr texEnv = new osg::TexEnvCombine; + texEnv->setCombine_RGB(osg::TexEnvCombine::MODULATE); + texEnv->setSource0_RGB(osg::TexEnvCombine::CONSTANT); + texEnv->setSource1_RGB(osg::TexEnvCombine::TEXTURE); + texEnv->setConstantColor(osg::Vec4f(1.f, 0.f, 0.f, 1.f)); // mShadowBlend * mMoonColor + stateset->setTextureAttributeAndModes(0, texEnv, osg::StateAttribute::ON); + + stateset->setTextureAttributeAndModes(1, mCircleTex, osg::StateAttribute::ON); + osg::ref_ptr texEnv2 = new osg::TexEnvCombine; + texEnv2->setCombine_RGB(osg::TexEnvCombine::ADD); + texEnv2->setCombine_Alpha(osg::TexEnvCombine::MODULATE); + texEnv2->setSource0_Alpha(osg::TexEnvCombine::TEXTURE); + texEnv2->setSource1_Alpha(osg::TexEnvCombine::CONSTANT); + texEnv2->setSource0_RGB(osg::TexEnvCombine::PREVIOUS); + texEnv2->setSource1_RGB(osg::TexEnvCombine::CONSTANT); + texEnv2->setConstantColor(osg::Vec4f(0.f, 0.f, 0.f, 1.f)); // mAtmosphereColor.rgb, mTransparency + stateset->setTextureAttributeAndModes(1, texEnv2, osg::StateAttribute::ON); + + stateset->setAttributeAndModes(createUnlitMaterial(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + } + + virtual void apply(osg::StateSet *stateset, osg::NodeVisitor*) + { + osg::TexEnvCombine* texEnv = static_cast(stateset->getTextureAttribute(0, osg::StateAttribute::TEXENV)); + texEnv->setConstantColor(mMoonColor * mShadowBlend); + + osg::TexEnvCombine* texEnv2 = static_cast(stateset->getTextureAttribute(1, osg::StateAttribute::TEXENV)); + texEnv2->setConstantColor(osg::Vec4f(mAtmosphereColor.x(), mAtmosphereColor.y(), mAtmosphereColor.z(), mTransparency)); + } + + virtual void adjustTransparency(const float ratio) + { + mTransparency *= ratio; + } + void setState(const MoonState& state) { float radsX = ((state.mRotationFromHorizon) * M_PI) / 180.0f; @@ -404,27 +486,59 @@ public: osg::Quat rotZ(radsZ, osg::Vec3f(0.0f, 0.0f, 1.0f)); osg::Vec3f direction = rotX * rotZ * osg::Vec3f(0.0f, 1.0f, 0.0f); - mTransform->setPosition(direction * 1000.0f); + mTransform->setPosition(direction * mDistance); // The moon quad is initially oriented facing down, so we need to offset its X-axis // rotation to rotate it to face the camera when sitting at the horizon. - osg::Quat attX((-M_PI / 2.0f) + radsX, osg::Vec3f(1,0,0)); + osg::Quat attX((-M_PI / 2.0f) + radsX, osg::Vec3f(1.0f, 0.0f, 0.0f)); mTransform->setAttitude(attX * rotZ); setPhase(state.mPhase); - setTransparency(state.mMoonAlpha); - setShadowBlend(state.mShadowBlend); + mTransparency = state.mMoonAlpha; + mShadowBlend = state.mShadowBlend; } - void setTextures(const std::string& phaseTex, const std::string& circleTex) + void setAtmosphereColor(const osg::Vec4f& color) { - osg::ref_ptr phaseTexPtr = mSceneManager->getTextureManager()->getTexture2D(phaseTex, - osg::Texture::CLAMP, osg::Texture::CLAMP); + mAtmosphereColor = color; + } - osg::ref_ptr circleTexPtr = mSceneManager->getTextureManager()->getTexture2D(circleTex, - osg::Texture::CLAMP, osg::Texture::CLAMP); + void setColor(const osg::Vec4f& color) + { + mMoonColor = color; + } - mUpdater->setTextures(phaseTexPtr, circleTexPtr); + unsigned int getPhaseInt() const + { + if (mPhase == MoonState::Phase_New) return 0; + else if (mPhase == MoonState::Phase_WaxingCrescent) return 1; + else if (mPhase == MoonState::Phase_WaningCrescent) return 1; + else if (mPhase == MoonState::Phase_FirstQuarter) return 2; + else if (mPhase == MoonState::Phase_ThirdQuarter) return 2; + else if (mPhase == MoonState::Phase_WaxingGibbous) return 3; + else if (mPhase == MoonState::Phase_WaningGibbous) return 3; + else if (mPhase == MoonState::Phase_Full) return 4; + return 0; + } + +private: + + Resource::TextureManager& mTextureManager; + Type mType; + MoonState::Phase mPhase; + float mTransparency; + float mShadowBlend; + osg::Vec4f mAtmosphereColor; + osg::Vec4f mMoonColor; + osg::ref_ptr mPhaseTex; + osg::ref_ptr mCircleTex; + + void setTextures(const std::string& phaseTex, const std::string& circleTex) + { + mPhaseTex = mTextureManager.getTexture2D(phaseTex, osg::Texture::CLAMP, osg::Texture::CLAMP); + mCircleTex = mTextureManager.getTexture2D(circleTex, osg::Texture::CLAMP, osg::Texture::CLAMP); + + reset(); } void setPhase(const MoonState::Phase& phase) @@ -454,129 +568,6 @@ public: else setTextures(textureName, "textures/tx_mooncircle_full_m.dds"); } - - void setType(const Type& type) - { - mType = type; - } - - class MoonUpdater : public SceneUtil::StateSetUpdater - { - public: - MoonUpdater() - : mTransparency(1.0f) - , mShadowBlend(1.0f) - , mMoonColor(1,1,1,1) - { - } - - virtual void setDefaults(osg::StateSet *stateset) - { - stateset->setTextureAttributeAndModes(0, mPhaseTex, osg::StateAttribute::ON); - osg::ref_ptr texEnv = new osg::TexEnvCombine; - texEnv->setCombine_RGB(osg::TexEnvCombine::MODULATE); - texEnv->setSource0_RGB(osg::TexEnvCombine::CONSTANT); - texEnv->setSource1_RGB(osg::TexEnvCombine::TEXTURE); - texEnv->setConstantColor(osg::Vec4f(1.f, 0.f, 0.f, 1.f)); // mShadowBlend * mMoonColor - stateset->setTextureAttributeAndModes(0, texEnv, osg::StateAttribute::ON); - - stateset->setTextureAttributeAndModes(1, mCircleTex, osg::StateAttribute::ON); - osg::ref_ptr texEnv2 = new osg::TexEnvCombine; - texEnv2->setCombine_RGB(osg::TexEnvCombine::ADD); - texEnv2->setCombine_Alpha(osg::TexEnvCombine::MODULATE); - texEnv2->setSource0_Alpha(osg::TexEnvCombine::TEXTURE); - texEnv2->setSource1_Alpha(osg::TexEnvCombine::CONSTANT); - texEnv2->setSource0_RGB(osg::TexEnvCombine::PREVIOUS); - texEnv2->setSource1_RGB(osg::TexEnvCombine::CONSTANT); - texEnv2->setConstantColor(osg::Vec4f(0.f, 0.f, 0.f, 1.f)); // mAtmosphereColor.rgb, mTransparency - stateset->setTextureAttributeAndModes(1, texEnv2, osg::StateAttribute::ON); - - stateset->setAttributeAndModes(createUnlitMaterial(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); - } - - virtual void apply(osg::StateSet *stateset, osg::NodeVisitor*) - { - osg::TexEnvCombine* texEnv = static_cast(stateset->getTextureAttribute(0, osg::StateAttribute::TEXENV)); - texEnv->setConstantColor(mMoonColor * mShadowBlend); - - osg::TexEnvCombine* texEnv2 = static_cast(stateset->getTextureAttribute(1, osg::StateAttribute::TEXENV)); - texEnv2->setConstantColor(osg::Vec4f(mAtmosphereColor.x(), mAtmosphereColor.y(), mAtmosphereColor.z(), mTransparency)); - } - - void setTransparency(const float ratio) - { - mTransparency = ratio; - } - - void setShadowBlend(const float blendFactor) - { - mShadowBlend = blendFactor; - } - - void setAtmosphereColor(const osg::Vec4f& color) - { - mAtmosphereColor = color; - } - - void setMoonColor(const osg::Vec4f& color) - { - mMoonColor = color; - } - - void setTextures(osg::ref_ptr phaseTex, osg::ref_ptr circleTex) - { - mPhaseTex = phaseTex; - mCircleTex = circleTex; - reset(); - } - - private: - float mTransparency; - float mShadowBlend; - osg::Vec4f mAtmosphereColor; - osg::Vec4f mMoonColor; - osg::ref_ptr mPhaseTex; - osg::ref_ptr mCircleTex; - }; - - - void setAtmosphereColor(const osg::Vec4f& color) - { - mUpdater->setAtmosphereColor(color); - } - - void setColor(const osg::Vec4f& color) - { - mUpdater->setMoonColor(color); - } - - void setTransparency(const float ratio) - { - mUpdater->setTransparency(ratio); - } - - void setShadowBlend(const float blendFactor) - { - mUpdater->setShadowBlend(blendFactor); - } - - unsigned int getPhaseInt() const - { - if (mPhase == MoonState::Phase_New) return 0; - else if (mPhase == MoonState::Phase_WaxingCrescent) return 1; - else if (mPhase == MoonState::Phase_WaningCrescent) return 1; - else if (mPhase == MoonState::Phase_FirstQuarter) return 2; - else if (mPhase == MoonState::Phase_ThirdQuarter) return 2; - else if (mPhase == MoonState::Phase_WaxingGibbous) return 3; - else if (mPhase == MoonState::Phase_WaningGibbous) return 3; - else if (mPhase == MoonState::Phase_Full) return 4; - return 0; - } - -private: - Type mType; - MoonState::Phase mPhase; - osg::ref_ptr mUpdater; }; SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneManager) @@ -641,11 +632,11 @@ void SkyManager::create() mAtmosphereNightUpdater = new AtmosphereNightUpdater(mSceneManager->getTextureManager()); atmosphereNight->addUpdateCallback(mAtmosphereNightUpdater); - mSun.reset(new Sun(mRootNode, mSceneManager)); + mSun = new Sun(mRootNode, *mSceneManager->getTextureManager()); const MWWorld::Fallback* fallback=MWBase::Environment::get().getWorld()->getFallback(); - mMasser.reset(new Moon(mRootNode, mSceneManager, fallback->getFallbackFloat("Moons_Masser_Size")/125, Moon::Type_Masser)); - mSecunda.reset(new Moon(mRootNode, mSceneManager, fallback->getFallbackFloat("Moons_Secunda_Size")/125, Moon::Type_Secunda)); + mMasser = new Moon(mRootNode, *mSceneManager->getTextureManager(), fallback->getFallbackFloat("Moons_Masser_Size")/125, Moon::Type_Masser); + mSecunda = new Moon(mRootNode, *mSceneManager->getTextureManager(), fallback->getFallbackFloat("Moons_Secunda_Size")/125, Moon::Type_Secunda); mCloudNode = new osg::PositionAttitudeTransform; mRootNode->addChild(mCloudNode); @@ -970,7 +961,7 @@ void SkyManager::updateRainParameters() } } -void SkyManager::setWeather(const MWWorld::WeatherResult& weather) +void SkyManager::setWeather(const WeatherResult& weather) { if (!mCreated) return; @@ -1087,9 +1078,14 @@ void SkyManager::setWeather(const MWWorld::WeatherResult& weather) mCloudSpeed = weather.mCloudSpeed; - if (weather.mNight && mStarsOpacity != weather.mNightFade) + mMasser->adjustTransparency(weather.mCelestialBodyTransparency); + mSecunda->adjustTransparency(weather.mCelestialBodyTransparency); + mSun->adjustTransparency(weather.mCelestialBodyTransparency); + + float nextStarsOpacity = weather.mNightFade * weather.mCelestialBodyTransparency; + if(weather.mNight && mStarsOpacity != nextStarsOpacity) { - mStarsOpacity = weather.mNightFade; + mStarsOpacity = nextStarsOpacity; mAtmosphereNightUpdater->setFade(mStarsOpacity); } diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index eb953d128..16509ef32 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -1,9 +1,11 @@ #ifndef OPENMW_MWRENDER_SKY_H #define OPENMW_MWRENDER_SKY_H -#include +#include -#include "../mwworld/weather.hpp" +#include +#include +#include namespace osg { @@ -33,6 +35,50 @@ namespace MWRender class RainFader; class AlphaFader; + struct WeatherResult + { + std::string mCloudTexture; + std::string mNextCloudTexture; + float mCloudBlendFactor; + + osg::Vec4f mFogColor; + + osg::Vec4f mAmbientColor; + + osg::Vec4f mSkyColor; + + osg::Vec4f mSunColor; + + osg::Vec4f mSunDiscColor; + + float mFogDepth; + + float mWindSpeed; + + float mCloudSpeed; + + float mCloudOpacity; + + float mGlareView; + + bool mNight; // use night skybox + float mNightFade; // fading factor for night skybox + + bool mIsStorm; + + std::string mAmbientLoopSoundID; + float mAmbientSoundVolume; + + std::string mParticleEffect; + std::string mRainEffect; + float mEffectFade; + + float mRainSpeed; + float mRainFrequency; + + float mCelestialBodyTransparency; + }; + struct MoonState { enum Phase @@ -82,7 +128,7 @@ namespace MWRender void setMoonColour (bool red); ///< change Secunda colour to red - void setWeather(const MWWorld::WeatherResult& weather); + void setWeather(const WeatherResult& weather); void sunEnable(); @@ -133,9 +179,9 @@ namespace MWRender osg::ref_ptr mAtmosphereUpdater; - std::auto_ptr mSun; - std::auto_ptr mMasser; - std::auto_ptr mSecunda; + osg::ref_ptr mSun; + osg::ref_ptr mMasser; + osg::ref_ptr mSecunda; osg::ref_ptr mRainNode; osg::ref_ptr mRainParticleSystem; diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 0e78edce7..679565e45 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -61,7 +61,7 @@ MWRender::MoonState MoonModel::calculateState(unsigned int daysPassed, float gam { rotationFromHorizon, mAxisOffset, // Reverse engineered from Morrowind's scene graph rotation matrices. - static_cast(phase(daysPassed)), + static_cast(phase(daysPassed, gameHour)), shadowBlend(rotationFromHorizon), earlyMoonShadowAlpha(rotationFromHorizon) * hourlyAlpha(gameHour) }; @@ -130,12 +130,17 @@ inline float MoonModel::rotation(float hours) const return 15.0f * mSpeed * hours; } -inline unsigned int MoonModel::phase(unsigned int daysPassed) const +inline unsigned int MoonModel::phase(unsigned int daysPassed, float gameHour) const { // Morrowind starts with a full moon on 16 Last Seed and then begins to wane 17 Last Seed, working on 3 day phase cycle. // Note: this is an internal helper, and as such we don't want to return MWRender::MoonState::Phase since we can't // forward declare it (C++11 strongly typed enums solve this). - return ((daysPassed + 1) / 3) % 8; + + // If the moon didn't rise yet today, use yesterday's moon phase. + if(gameHour < moonRiseHour(daysPassed)) + return (daysPassed / 3) % 8; + else + return ((daysPassed + 1) / 3) % 8; } inline float MoonModel::shadowBlend(float angle) const @@ -289,44 +294,54 @@ WeatherManager::WeatherManager(MWRender::RenderingManager* rendering, MWWorld::F //Weather Weather clear; + clear.mObstructsCelestialBodies = false; setFallbackWeather(clear,"clear"); Weather cloudy; + cloudy.mObstructsCelestialBodies = false; setFallbackWeather(cloudy,"cloudy"); Weather foggy; + foggy.mObstructsCelestialBodies = false; setFallbackWeather(foggy,"foggy"); Weather thunderstorm; thunderstorm.mAmbientLoopSoundID = "rain heavy"; thunderstorm.mRainEffect = "meshes\\raindrop.nif"; + thunderstorm.mObstructsCelestialBodies = true; setFallbackWeather(thunderstorm,"thunderstorm"); Weather rain; rain.mAmbientLoopSoundID = "rain"; rain.mRainEffect = "meshes\\raindrop.nif"; + rain.mObstructsCelestialBodies = true; setFallbackWeather(rain,"rain"); Weather overcast; + overcast.mObstructsCelestialBodies = true; setFallbackWeather(overcast,"overcast"); Weather ashstorm; ashstorm.mAmbientLoopSoundID = "ashstorm"; ashstorm.mParticleEffect = "meshes\\ashcloud.nif"; + ashstorm.mObstructsCelestialBodies = true; setFallbackWeather(ashstorm,"ashstorm"); Weather blight; blight.mAmbientLoopSoundID = "blight"; blight.mParticleEffect = "meshes\\blightcloud.nif"; + blight.mObstructsCelestialBodies = true; setFallbackWeather(blight,"blight"); Weather snow; snow.mParticleEffect = "meshes\\snow.nif"; + snow.mObstructsCelestialBodies = true; setFallbackWeather(snow, "snow"); Weather blizzard; blizzard.mAmbientLoopSoundID = "BM Blizzard"; blizzard.mParticleEffect = "meshes\\blizzard.nif"; + blizzard.mObstructsCelestialBodies = true; setFallbackWeather(blizzard,"blizzard"); } @@ -460,14 +475,16 @@ void WeatherManager::setResult(const std::string& weatherType) mResult.mNightFade = factor; } } + + mResult.mCelestialBodyTransparency = current.mObstructsCelestialBodies ? 0.0f : 1.0f; } void WeatherManager::transition(float factor) { setResult(mCurrentWeather); - const WeatherResult current = mResult; + const MWRender::WeatherResult current = mResult; setResult(mNextWeather); - const WeatherResult other = mResult; + const MWRender::WeatherResult other = mResult; mResult.mCloudTexture = current.mCloudTexture; mResult.mNextCloudTexture = other.mCloudTexture; @@ -513,6 +530,16 @@ void WeatherManager::transition(float factor) mResult.mEffectFade = mResult.mAmbientSoundVolume; mResult.mAmbientLoopSoundID = other.mAmbientLoopSoundID; } + + const Weather& currentSettings = mWeatherSettings[mCurrentWeather]; + const Weather& nextSettings = mWeatherSettings[mNextWeather]; + + if(currentSettings.mObstructsCelestialBodies && !nextSettings.mObstructsCelestialBodies) + mResult.mCelestialBodyTransparency = factor; + else if(!currentSettings.mObstructsCelestialBodies && nextSettings.mObstructsCelestialBodies) + mResult.mCelestialBodyTransparency = 1 - factor; + else + mResult.mCelestialBodyTransparency = current.mCelestialBodyTransparency; } void WeatherManager::update(float duration, bool paused) diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index 8f7634fbb..1bc3bc357 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -9,6 +9,8 @@ #include "../mwbase/soundmanager.hpp" +#include "../mwrender/sky.hpp" + namespace ESM { struct Region; @@ -19,7 +21,6 @@ namespace ESM namespace MWRender { class RenderingManager; - struct MoonState; } namespace Loading @@ -31,50 +32,6 @@ namespace MWWorld { class Fallback; - /// Defines the actual weather that results from weather setting (see below), time of day and weather transition - struct WeatherResult - { - std::string mCloudTexture; - std::string mNextCloudTexture; - float mCloudBlendFactor; - - osg::Vec4f mFogColor; - - osg::Vec4f mAmbientColor; - - osg::Vec4f mSkyColor; - - osg::Vec4f mSunColor; - - osg::Vec4f mSunDiscColor; - - float mFogDepth; - - float mWindSpeed; - - float mCloudSpeed; - - float mCloudOpacity; - - float mGlareView; - - bool mNight; // use night skybox - float mNightFade; // fading factor for night skybox - - bool mIsStorm; - - std::string mAmbientLoopSoundID; - float mAmbientSoundVolume; - - std::string mParticleEffect; - std::string mRainEffect; - float mEffectFade; - - float mRainSpeed; - float mRainFrequency; - }; - - /// Defines a single weather setting (according to INI) struct Weather { @@ -149,6 +106,9 @@ namespace MWWorld // Note: For Weather Blight, there is a "Disease Chance" (=0.1) setting. But according to MWSFD this feature // is broken in the vanilla game and was disabled. + + // Some weather patterns will obstruct the moons, sun, and stars. + bool mObstructsCelestialBodies; }; class MoonModel @@ -173,7 +133,7 @@ namespace MWWorld float angle(unsigned int daysPassed, float gameHour) const; float moonRiseHour(unsigned int daysPassed) const; float rotation(float hours) const; - unsigned int phase(unsigned int daysPassed) const; + unsigned int phase(unsigned int daysPassed, float gameHour) const; float shadowBlend(float angle) const; float hourlyAlpha(float gameHour) const; float earlyMoonShadowAlpha(float angle) const; @@ -268,7 +228,7 @@ namespace MWWorld void setWeather(const std::string& weatherType, bool instant=false); std::string nextWeather(const ESM::Region* region) const; - WeatherResult mResult; + MWRender::WeatherResult mResult; typedef std::map > RegionModMap; RegionModMap mRegionMods; From 46ce04a65b00e4efe2f344e104373063a49f7742 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Wed, 5 Aug 2015 17:10:35 +0200 Subject: [PATCH 1992/3725] Don't package duplicate version for Windows The real version file is in the resources folder, and that's where it's read from. So the extra file is unused, and redundant. --- CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 99fb56fbe..84fd16e33 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -449,7 +449,6 @@ if(WIN32) FILE(GLOB dll_files "${OpenMW_BINARY_DIR}/Release/*.dll") INSTALL(FILES ${dll_files} DESTINATION ".") INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" DESTINATION "." RENAME "openmw.cfg") - INSTALL(FILES "${OpenMW_BINARY_DIR}/resources/version" DESTINATION ".") INSTALL(FILES "${OpenMW_SOURCE_DIR}/CHANGELOG.md" DESTINATION "." RENAME "CHANGELOG.txt") INSTALL(FILES "${OpenMW_SOURCE_DIR}/README.md" DESTINATION "." RENAME "README.txt") INSTALL(FILES From cbf9f83b855e382375c17c2fc64eec582e31714a Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 5 Aug 2015 17:20:01 +0200 Subject: [PATCH 1993/3725] allow use of IDs as function arguments, even if the ID matches a keyword (Fixes #2830) --- components/compiler/exprparser.cpp | 5 ++++- components/compiler/lineparser.cpp | 17 +++++++++++++++++ components/compiler/stringparser.cpp | 24 +++++++++++++++++++++++- components/compiler/stringparser.hpp | 4 ++++ 4 files changed, 48 insertions(+), 2 deletions(-) diff --git a/components/compiler/exprparser.cpp b/components/compiler/exprparser.cpp index dc36b58d8..1818d04df 100644 --- a/components/compiler/exprparser.cpp +++ b/components/compiler/exprparser.cpp @@ -353,7 +353,10 @@ namespace Compiler if (extensions->isInstruction (keyword, argumentType, hasExplicit)) { // pretend this is not a keyword - return parseName (loc.mLiteral, loc, scanner); + std::string name = loc.mLiteral; + if (name.size()>=2 && name[0]=='"' && name[name.size()-1]=='"') + name = name.substr (1, name.size()-2); + return parseName (name, loc, scanner); } } diff --git a/components/compiler/lineparser.cpp b/components/compiler/lineparser.cpp index a71672916..4d6e147fc 100644 --- a/components/compiler/lineparser.cpp +++ b/components/compiler/lineparser.cpp @@ -222,6 +222,23 @@ namespace Compiler bool LineParser::parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner) { + if (mState==MessageState || mState==MessageCommaState) + { + if (const Extensions *extensions = getContext().getExtensions()) + { + std::string argumentType; // ignored + bool hasExplicit = false; // ignored + if (extensions->isInstruction (keyword, argumentType, hasExplicit)) + { + // pretend this is not a keyword + std::string name = loc.mLiteral; + if (name.size()>=2 && name[0]=='"' && name[name.size()-1]=='"') + name = name.substr (1, name.size()-2); + return parseName (name, loc, scanner); + } + } + } + if (mState==SetMemberVarState) { mMemberName = loc.mLiteral; diff --git a/components/compiler/stringparser.cpp b/components/compiler/stringparser.cpp index a86c15794..7a2098fb3 100644 --- a/components/compiler/stringparser.cpp +++ b/components/compiler/stringparser.cpp @@ -4,9 +4,12 @@ #include #include +#include + #include "scanner.hpp" #include "generator.hpp" -#include +#include "context.hpp" +#include "extensions.hpp" namespace Compiler { @@ -33,6 +36,25 @@ namespace Compiler return Parser::parseName (name, loc, scanner); } + bool StringParser::parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner) + { + if (const Extensions *extensions = getContext().getExtensions()) + { + std::string argumentType; // ignored + bool hasExplicit = false; // ignored + if (extensions->isInstruction (keyword, argumentType, hasExplicit)) + { + // pretend this is not a keyword + std::string name = loc.mLiteral; + if (name.size()>=2 && name[0]=='"' && name[name.size()-1]=='"') + name = name.substr (1, name.size()-2); + return parseName (name, loc, scanner); + } + } + + return Parser::parseKeyword (keyword, loc, scanner); + } + bool StringParser::parseSpecial (int code, const TokenLoc& loc, Scanner& scanner) { if (code==Scanner::S_comma && mState==StartState) diff --git a/components/compiler/stringparser.hpp b/components/compiler/stringparser.hpp index 3859a2496..52469128f 100644 --- a/components/compiler/stringparser.hpp +++ b/components/compiler/stringparser.hpp @@ -32,6 +32,10 @@ namespace Compiler ///< Handle a name token. /// \return fetch another token? + virtual bool parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner); + ///< Handle a keyword token. + /// \return fetch another token? + virtual bool parseSpecial (int code, const TokenLoc& loc, Scanner& scanner); ///< Handle a special character token. /// \return fetch another token? From 5602cd9b7b6f954d953ed90ed1131aac8a3df32b Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 6 Aug 2015 02:54:47 +0200 Subject: [PATCH 1994/3725] Fix the launcher's version label for builds with no git commit info --- apps/launcher/maindialog.cpp | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index c18c26cdd..9a6f91a0f 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -175,20 +175,16 @@ void Launcher::MainDialog::setVersionLabel() QString tag(QString::fromUtf8(v.mTagHash.c_str())); versionLabel->setTextInteractionFlags(Qt::TextSelectableByMouse); - if (!revision.isEmpty() && !tag.isEmpty()) - { - if (revision == tag) { - versionLabel->setText(tr("OpenMW %1 release").arg(QString::fromUtf8(v.mVersion.c_str()))); - } else { - versionLabel->setText(tr("OpenMW development (%1)").arg(revision.left(10))); - } - - // Add the compile date and time - versionLabel->setToolTip(tr("Compiled on %1 %2").arg(QLocale(QLocale::C).toDate(QString(__DATE__).simplified(), - QLatin1String("MMM d yyyy")).toString(Qt::SystemLocaleLongDate), - QLocale(QLocale::C).toTime(QString(__TIME__).simplified(), - QLatin1String("hh:mm:ss")).toString(Qt::SystemLocaleShortDate))); - } + if (!v.mVersion.empty() && (revision.isEmpty() || revision == tag)) + versionLabel->setText(tr("OpenMW %1 release").arg(QString::fromUtf8(v.mVersion.c_str()))); + else + versionLabel->setText(tr("OpenMW development (%1)").arg(revision.left(10))); + + // Add the compile date and time + versionLabel->setToolTip(tr("Compiled on %1 %2").arg(QLocale(QLocale::C).toDate(QString(__DATE__).simplified(), + QLatin1String("MMM d yyyy")).toString(Qt::SystemLocaleLongDate), + QLocale(QLocale::C).toTime(QString(__TIME__).simplified(), + QLatin1String("hh:mm:ss")).toString(Qt::SystemLocaleShortDate))); } bool Launcher::MainDialog::setup() From f2e51b0579fb44ea391ed439ca4c9010cd098953 Mon Sep 17 00:00:00 2001 From: slothlife Date: Wed, 5 Aug 2015 21:03:21 -0500 Subject: [PATCH 1995/3725] Use diffuse alpha to fade Sun --- apps/openmw/mwrender/sky.cpp | 39 +++++++++++++----------------------- 1 file changed, 14 insertions(+), 25 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 3a2da230f..38b6b9193 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -321,12 +321,12 @@ private: int mMeshType; }; -// A base class for the sun and moons. Must be stored in an osg::ref_ptr due to being -// derived from osg::Referenced. +/// A base class for the sun and moons. +/// \note Must be stored in an osg::ref_ptr due to being derived from osg::Referenced. class CelestialBody : public SceneUtil::StateSetUpdater { public: - CelestialBody(osg::Group* parentNode, float scaleFactor = 1.f, int numUvSets=1) + CelestialBody(osg::Group* parentNode, float scaleFactor, int numUvSets) { mGeode = new osg::Geode; osg::ref_ptr geom = createTexturedQuad(numUvSets); @@ -365,35 +365,26 @@ class Sun : public CelestialBody public: Sun(osg::Group* parentNode, Resource::TextureManager& textureManager) : CelestialBody(parentNode, 1.0f, 1) - , mColor(1.0f, 1.0f, 1.0f, 1.0f) - , mDummyTexture(textureManager.getWarningTexture()) + , mTextureManager(textureManager) + , mColor(0.0f, 0.0f, 0.0f, 1.0f) { - osg::ref_ptr tex = textureManager.getTexture2D("textures/tx_sun_05.dds", - osg::Texture::CLAMP, - osg::Texture::CLAMP); - - mTransform->getOrCreateStateSet()->setTextureAttributeAndModes(0, tex, osg::StateAttribute::ON); - mTransform->getOrCreateStateSet()->setAttributeAndModes(createUnlitMaterial(), osg::StateAttribute::ON); } virtual void setDefaults(osg::StateSet* stateset) { - osg::ref_ptr texEnv(new osg::TexEnvCombine); - texEnv->setCombine_Alpha(osg::TexEnvCombine::MODULATE); - texEnv->setSource0_Alpha(osg::TexEnvCombine::PREVIOUS); - texEnv->setSource1_Alpha(osg::TexEnvCombine::CONSTANT); - texEnv->setCombine_RGB(osg::TexEnvCombine::REPLACE); - texEnv->setSource0_RGB(osg::TexEnvCombine::PREVIOUS); - texEnv->setConstantColor(osg::Vec4f(1.0f, 1.0f, 1.0f, 1.0f)); + osg::ref_ptr tex = mTextureManager.getTexture2D("textures/tx_sun_05.dds", + osg::Texture::CLAMP, + osg::Texture::CLAMP); - stateset->setTextureAttributeAndModes(1, mDummyTexture, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); - stateset->setTextureAttributeAndModes(1, texEnv, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + stateset->setTextureAttributeAndModes(0, tex, osg::StateAttribute::ON); + stateset->setAttributeAndModes(createAlphaTrackingUnlitMaterial(), + osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); } virtual void apply(osg::StateSet* stateset, osg::NodeVisitor*) { - osg::TexEnvCombine* texEnv = static_cast(stateset->getTextureAttribute(1, osg::StateAttribute::TEXENV)); - texEnv->setConstantColor(mColor); + osg::Material* mat = static_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); + mat->setDiffuse(osg::Material::FRONT_AND_BACK, mColor); } virtual void adjustTransparency(const float ratio) @@ -412,9 +403,8 @@ public: } private: - + Resource::TextureManager& mTextureManager; osg::Vec4f mColor; - osg::ref_ptr mDummyTexture; }; class Moon : public CelestialBody @@ -522,7 +512,6 @@ public: } private: - Resource::TextureManager& mTextureManager; Type mType; MoonState::Phase mPhase; From 238ae419a363ef263ffbba13307671a5d30e73f9 Mon Sep 17 00:00:00 2001 From: slothlife Date: Wed, 5 Aug 2015 22:02:54 -0500 Subject: [PATCH 1996/3725] Fix use of incorrect material for Sun --- apps/openmw/mwrender/sky.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 38b6b9193..f16f97bc2 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -377,7 +377,7 @@ public: osg::Texture::CLAMP); stateset->setTextureAttributeAndModes(0, tex, osg::StateAttribute::ON); - stateset->setAttributeAndModes(createAlphaTrackingUnlitMaterial(), + stateset->setAttributeAndModes(createUnlitMaterial(), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); } From 469a896ca16cf59a29ea6cb33b9e9b7d42241871 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 6 Aug 2015 08:45:38 +0200 Subject: [PATCH 1997/3725] make non-editable fields in dialogue sub view selectable (Fixes #2818) --- apps/opencs/view/world/dialoguesubview.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 5ad2f76e2..b2f2355ef 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -104,7 +104,9 @@ QWidget* CSVWorld::NotEditableSubDelegate::createEditor (QWidget *parent, const QStyleOptionViewItem& option, const QModelIndex& index) const { - return new QLabel(parent); + QLabel *label = new QLabel(parent); + label->setTextInteractionFlags (Qt::TextSelectableByMouse); + return label; } /* @@ -809,7 +811,7 @@ void CSVWorld::SimpleDialogueSubView::dataChanged (const QModelIndex & index) void CSVWorld::SimpleDialogueSubView::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) { QModelIndex currentIndex(mTable->getModelIndex(getUniversalId().getId(), 0)); - + if (!currentIndex.isValid()) { return; From b83f9445a96fda4dc14e43a2db363a748344227f Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 6 Aug 2015 12:52:10 +0200 Subject: [PATCH 1998/3725] added UI for merge tool (merge tool itself is still missing) --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/editor.cpp | 16 +++ apps/opencs/editor.hpp | 12 +++ apps/opencs/model/doc/documentmanager.cpp | 2 + apps/opencs/model/doc/documentmanager.hpp | 2 + apps/opencs/view/doc/filewidget.cpp | 8 ++ apps/opencs/view/doc/filewidget.hpp | 4 + apps/opencs/view/doc/view.cpp | 11 ++ apps/opencs/view/doc/view.hpp | 5 + apps/opencs/view/doc/viewmanager.cpp | 1 + apps/opencs/view/doc/viewmanager.hpp | 2 + apps/opencs/view/tools/merge.cpp | 123 ++++++++++++++++++++++ apps/opencs/view/tools/merge.hpp | 60 +++++++++++ 13 files changed, 247 insertions(+), 1 deletion(-) create mode 100644 apps/opencs/view/tools/merge.cpp create mode 100644 apps/opencs/view/tools/merge.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 1a51d2d8d..91c778c06 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -94,7 +94,7 @@ opencs_hdrs_noqt (view/render opencs_units (view/tools - reportsubview reporttable searchsubview searchbox + reportsubview reporttable searchsubview searchbox merge ) opencs_units_noqt (view/tools diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 9450aa4bf..170e88320 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -40,9 +40,12 @@ CS::Editor::Editor () mNewGame.setLocalData (mLocal); mFileDialog.setLocalData (mLocal); + mMerge.setLocalData (mLocal); connect (&mDocumentManager, SIGNAL (documentAdded (CSMDoc::Document *)), this, SLOT (documentAdded (CSMDoc::Document *))); + connect (&mDocumentManager, SIGNAL (documentAboutToBeRemoved (CSMDoc::Document *)), + this, SLOT (documentAboutToBeRemoved (CSMDoc::Document *))); connect (&mDocumentManager, SIGNAL (lastDocumentDeleted()), this, SLOT (lastDocumentDeleted())); @@ -50,6 +53,7 @@ CS::Editor::Editor () connect (&mViewManager, SIGNAL (newAddonRequest ()), this, SLOT (createAddon ())); connect (&mViewManager, SIGNAL (loadDocumentRequest ()), this, SLOT (loadDocument ())); connect (&mViewManager, SIGNAL (editSettingsRequest()), this, SLOT (showSettings ())); + connect (&mViewManager, SIGNAL (mergeDocument (CSMDoc::Document *)), this, SLOT (mergeDocument (CSMDoc::Document *))); connect (&mStartup, SIGNAL (createGame()), this, SLOT (createGame ())); connect (&mStartup, SIGNAL (createAddon()), this, SLOT (createAddon ())); @@ -360,7 +364,19 @@ void CS::Editor::documentAdded (CSMDoc::Document *document) mViewManager.addView (document); } +void CS::Editor::documentAboutToBeRemoved (CSMDoc::Document *document) +{ + if (mMerge.getDocument()==document) + mMerge.cancel(); +} + void CS::Editor::lastDocumentDeleted() { QApplication::quit(); } + +void CS::Editor::mergeDocument (CSMDoc::Document *document) +{ + mMerge.configure (document); + mMerge.show(); +} diff --git a/apps/opencs/editor.hpp b/apps/opencs/editor.hpp index 0464fb7eb..ac403b1ee 100644 --- a/apps/opencs/editor.hpp +++ b/apps/opencs/editor.hpp @@ -27,11 +27,18 @@ #include "view/settings/dialog.hpp" +#include "view/tools/merge.hpp" + namespace VFS { class Manager; } +namespace CSMDoc +{ + class Document; +} + namespace CS { class Editor : public QObject @@ -55,6 +62,7 @@ namespace CS boost::interprocess::file_lock mLock; boost::filesystem::ofstream mPidFile; bool mFsStrict; + CSVTools::Merge mMerge; void setupDataFiles (const Files::PathContainer& dataDirs); @@ -94,8 +102,12 @@ namespace CS void documentAdded (CSMDoc::Document *document); + void documentAboutToBeRemoved (CSMDoc::Document *document); + void lastDocumentDeleted(); + void mergeDocument (CSMDoc::Document *document); + private: QString mIpcServerName; diff --git a/apps/opencs/model/doc/documentmanager.cpp b/apps/opencs/model/doc/documentmanager.cpp index 5a5f50159..02d4ab5c0 100644 --- a/apps/opencs/model/doc/documentmanager.cpp +++ b/apps/opencs/model/doc/documentmanager.cpp @@ -73,6 +73,8 @@ void CSMDoc::DocumentManager::removeDocument (CSMDoc::Document *document) if (iter==mDocuments.end()) throw std::runtime_error ("removing invalid document"); + emit documentAboutToBeRemoved (document); + mDocuments.erase (iter); document->deleteLater(); diff --git a/apps/opencs/model/doc/documentmanager.hpp b/apps/opencs/model/doc/documentmanager.hpp index b61656d4b..f9b18bfe6 100644 --- a/apps/opencs/model/doc/documentmanager.hpp +++ b/apps/opencs/model/doc/documentmanager.hpp @@ -88,6 +88,8 @@ namespace CSMDoc void documentAdded (CSMDoc::Document *document); + void documentAboutToBeRemoved (CSMDoc::Document *document); + void loadRequest (CSMDoc::Document *document); void lastDocumentDeleted(); diff --git a/apps/opencs/view/doc/filewidget.cpp b/apps/opencs/view/doc/filewidget.cpp index f18fe695a..3e5c08788 100644 --- a/apps/opencs/view/doc/filewidget.cpp +++ b/apps/opencs/view/doc/filewidget.cpp @@ -56,3 +56,11 @@ void CSVDoc::FileWidget::extensionLabelIsVisible(bool visible) { mType->setVisible(visible); } + +void CSVDoc::FileWidget::setName (const std::string& text) +{ + QString text2 = QString::fromUtf8 (text.c_str()); + + mInput->setText (text2); + textChanged (text2); +} diff --git a/apps/opencs/view/doc/filewidget.hpp b/apps/opencs/view/doc/filewidget.hpp index ff09d71a3..ab06f37f1 100644 --- a/apps/opencs/view/doc/filewidget.hpp +++ b/apps/opencs/view/doc/filewidget.hpp @@ -3,6 +3,8 @@ #include +#include + class QLabel; class QString; class QLineEdit; @@ -29,6 +31,8 @@ namespace CSVDoc void extensionLabelIsVisible(bool visible); + void setName (const std::string& text); + private slots: void textChanged (const QString& text); diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 05c98b11f..df7421a14 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -66,6 +66,10 @@ void CSVDoc::View::setupFileMenu() connect (mVerify, SIGNAL (triggered()), this, SLOT (verify())); file->addAction (mVerify); + mMerge = new QAction (tr ("Merge"), this); + connect (mMerge, SIGNAL (triggered()), this, SLOT (merge())); + file->addAction (mMerge); + QAction *loadErrors = new QAction (tr ("Load Error Log"), this); connect (loadErrors, SIGNAL (triggered()), this, SLOT (loadErrorLog())); file->addAction (loadErrors); @@ -393,6 +397,8 @@ void CSVDoc::View::updateActions() mGlobalDebugProfileMenu->updateActions (running); mStopDebug->setEnabled (running); + + mMerge->setEnabled (mDocument->getContentFiles().size()>1); } CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews) @@ -969,3 +975,8 @@ void CSVDoc::View::updateScrollbar() else mSubViewWindow.setMinimumWidth(0); } + +void CSVDoc::View::merge() +{ + emit mergeDocument (mDocument); +} diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index 7f4255f8f..adda73526 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -43,6 +43,7 @@ namespace CSVDoc QAction *mVerify; QAction *mShowStatusBar; QAction *mStopDebug; + QAction *mMerge; std::vector mEditingActions; Operations *mOperations; SubViewFactoryManager mSubViewFactory; @@ -129,6 +130,8 @@ namespace CSVDoc void editSettingsRequest(); + void mergeDocument (CSMDoc::Document *document); + public slots: void addSubView (const CSMWorld::UniversalId& id, const std::string& hint = ""); @@ -237,6 +240,8 @@ namespace CSVDoc void closeRequest (SubView *subView); void moveScrollBarToEnd(int min, int max); + + void merge(); }; } diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 7aec001cf..265c1f832 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -175,6 +175,7 @@ CSVDoc::View *CSVDoc::ViewManager::addView (CSMDoc::Document *document) connect (view, SIGNAL (newAddonRequest ()), this, SIGNAL (newAddonRequest())); connect (view, SIGNAL (loadDocumentRequest ()), this, SIGNAL (loadDocumentRequest())); connect (view, SIGNAL (editSettingsRequest()), this, SIGNAL (editSettingsRequest())); + connect (view, SIGNAL (mergeDocument (CSMDoc::Document *)), this, SIGNAL (mergeDocument (CSMDoc::Document *))); connect (&CSMSettings::UserSettings::instance(), SIGNAL (userSettingUpdated(const QString &, const QStringList &)), diff --git a/apps/opencs/view/doc/viewmanager.hpp b/apps/opencs/view/doc/viewmanager.hpp index cdd5ac768..70431107f 100644 --- a/apps/opencs/view/doc/viewmanager.hpp +++ b/apps/opencs/view/doc/viewmanager.hpp @@ -77,6 +77,8 @@ namespace CSVDoc void editSettingsRequest(); + void mergeDocument (CSMDoc::Document *document); + public slots: void exitApplication (CSVDoc::View *view); diff --git a/apps/opencs/view/tools/merge.cpp b/apps/opencs/view/tools/merge.cpp new file mode 100644 index 000000000..baadd9179 --- /dev/null +++ b/apps/opencs/view/tools/merge.cpp @@ -0,0 +1,123 @@ + +#include "merge.hpp" + +#include +#include +#include +#include +#include +#include + +#include "../../model/doc/document.hpp" + +#include "../doc/filewidget.hpp" +#include "../doc/adjusterwidget.hpp" + +CSVTools::Merge::Merge (QWidget *parent) +: QDialog (parent), mDocument (0) +{ + setWindowTitle ("Merge Content Files into a new Game File"); + + QVBoxLayout *mainLayout = new QVBoxLayout; + setLayout (mainLayout); + + QSplitter *splitter = new QSplitter (Qt::Horizontal, this); + + mainLayout->addWidget (splitter, 1); + + // left panel (files to be merged) + QWidget *left = new QWidget (this); + left->setContentsMargins (0, 0, 0, 0); + splitter->addWidget (left); + + QVBoxLayout *leftLayout = new QVBoxLayout; + left->setLayout (leftLayout); + + leftLayout->addWidget (new QLabel ("Files to be merged", this)); + + mFiles = new QListWidget (this); + leftLayout->addWidget (mFiles, 1); + + // right panel (new game file) + QWidget *right = new QWidget (this); + right->setContentsMargins (0, 0, 0, 0); + splitter->addWidget (right); + + QVBoxLayout *rightLayout = new QVBoxLayout; + rightLayout->setAlignment (Qt::AlignTop); + right->setLayout (rightLayout); + + rightLayout->addWidget (new QLabel ("New game file", this)); + + mNewFile = new CSVDoc::FileWidget (this); + mNewFile->setType (false); + mNewFile->extensionLabelIsVisible (true); + rightLayout->addWidget (mNewFile); + + mAdjuster = new CSVDoc::AdjusterWidget (this); + + rightLayout->addWidget (mAdjuster); + + connect (mNewFile, SIGNAL (nameChanged (const QString&, bool)), + mAdjuster, SLOT (setName (const QString&, bool))); + connect (mAdjuster, SIGNAL (stateChanged (bool)), this, SLOT (stateChanged (bool))); + + // buttons + QDialogButtonBox *buttons = new QDialogButtonBox (QDialogButtonBox::Cancel, Qt::Horizontal, this); + + connect (buttons->button (QDialogButtonBox::Cancel), SIGNAL (clicked()), this, SLOT (reject())); + mOkay = new QPushButton ("Merge", this); + mOkay->setDefault (true); + buttons->addButton (mOkay, QDialogButtonBox::AcceptRole); + + mainLayout->addWidget (buttons); +} + +void CSVTools::Merge::configure (CSMDoc::Document *document) +{ + mDocument = document; + + mNewFile->setName (""); + + // content files + while (mFiles->count()) + delete mFiles->takeItem (0); + + std::vector files = document->getContentFiles(); + + for (std::vector::const_iterator iter (files.begin()); + iter!=files.end(); ++iter) + mFiles->addItem (QString::fromUtf8 (iter->filename().string().c_str())); +} + +void CSVTools::Merge::setLocalData (const boost::filesystem::path& localData) +{ + mAdjuster->setLocalData (localData); +} + +CSMDoc::Document *CSVTools::Merge::getDocument() const +{ + return mDocument; +} + +void CSVTools::Merge::cancel() +{ + mDocument = 0; + hide(); +} + +void CSVTools::Merge::accept() +{ + QDialog::accept(); +} + +void CSVTools::Merge::reject() +{ + QDialog::reject(); + cancel(); +} + +void CSVTools::Merge::stateChanged (bool valid) +{ + mOkay->setEnabled (valid); +} diff --git a/apps/opencs/view/tools/merge.hpp b/apps/opencs/view/tools/merge.hpp new file mode 100644 index 000000000..4538baebe --- /dev/null +++ b/apps/opencs/view/tools/merge.hpp @@ -0,0 +1,60 @@ +#ifndef CSV_TOOLS_REPORTTABLE_H +#define CSV_TOOLS_REPORTTABLE_H + +#include + +#include + +class QPushButton; +class QListWidget; + +namespace CSMDoc +{ + class Document; +} + +namespace CSVDoc +{ + class FileWidget; + class AdjusterWidget; +} + +namespace CSVTools +{ + class Merge : public QDialog + { + Q_OBJECT + + CSMDoc::Document *mDocument; + QPushButton *mOkay; + QListWidget *mFiles; + CSVDoc::FileWidget *mNewFile; + CSVDoc::AdjusterWidget *mAdjuster; + + public: + + Merge (QWidget *parent = 0); + + /// Configure dialogue for a new merge + void configure (CSMDoc::Document *document); + + void setLocalData (const boost::filesystem::path& localData); + + CSMDoc::Document *getDocument() const; + + void cancel(); + + public slots: + + virtual void accept(); + + virtual void reject(); + + private slots: + + void stateChanged (bool valid); + + }; +} + +#endif From 4fd3097c1cf2329cef071aee7a1b149e280e4974 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 6 Aug 2015 12:58:52 +0200 Subject: [PATCH 1999/3725] improved adjuster widget problem reporting --- apps/opencs/view/doc/adjusterwidget.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/opencs/view/doc/adjusterwidget.cpp b/apps/opencs/view/doc/adjusterwidget.cpp index 6571ad7c8..6dc95a338 100644 --- a/apps/opencs/view/doc/adjusterwidget.cpp +++ b/apps/opencs/view/doc/adjusterwidget.cpp @@ -64,6 +64,7 @@ void CSVDoc::AdjusterWidget::setName (const QString& name, bool addon) QString message; mValid = (!name.isEmpty()); + bool warning = false; if (!mValid) { @@ -106,13 +107,14 @@ void CSVDoc::AdjusterWidget::setName (const QString& name, bool addon) { /// \todo add an user setting to make this an error. message += "

    A file with the same name already exists. If you continue, it will be overwritten."; + warning = true; } } } mMessage->setText (message); mIcon->setPixmap (style()->standardIcon ( - mValid ? QStyle::SP_MessageBoxInformation : QStyle::SP_MessageBoxWarning). + mValid ? (warning ? QStyle::SP_MessageBoxWarning : QStyle::SP_MessageBoxInformation) : QStyle::SP_MessageBoxCritical). pixmap (QSize (16, 16))); emit stateChanged (mValid); From ff2dab8d5657331b824b017908ca490ad8aa8216 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Thu, 6 Aug 2015 14:17:42 +0300 Subject: [PATCH 2000/3725] Remove check for an empty Particle from Magic effects verifier --- apps/opencs/model/tools/magiceffectcheck.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/apps/opencs/model/tools/magiceffectcheck.cpp b/apps/opencs/model/tools/magiceffectcheck.cpp index 22620929c..5435881b3 100644 --- a/apps/opencs/model/tools/magiceffectcheck.cpp +++ b/apps/opencs/model/tools/magiceffectcheck.cpp @@ -103,11 +103,7 @@ void CSMTools::MagicEffectCheckStage::perform(int stage, CSMDoc::Messages &messa messages.push_back(std::make_pair(id, "No such Icon '" + effect.mIcon + "'")); } - if (effect.mParticle.empty()) - { - messages.push_back(std::make_pair(id, "Particle is not specified")); - } - else if (!isTextureExists(effect.mParticle, false)) + if (!effect.mParticle.empty() && !isTextureExists(effect.mParticle, false)) { messages.push_back(std::make_pair(id, "No such Particle '" + effect.mParticle + "'")); } From 3235cecddfe11a1bbe70b231b7e1fa8fb716b1db Mon Sep 17 00:00:00 2001 From: slothlife Date: Fri, 7 Aug 2015 00:08:18 -0500 Subject: [PATCH 2001/3725] Use Glare View for visibility of celestial bodies Fixed memory leak from Sun and Moon objects by pulling Updaters back out into separate objects. Removed code related to mCelestialBodyTransparency. --- apps/openmw/mwrender/sky.cpp | 233 ++++++++++++++++++-------------- apps/openmw/mwrender/sky.hpp | 9 +- apps/openmw/mwworld/weather.cpp | 22 --- apps/openmw/mwworld/weather.hpp | 6 +- 4 files changed, 139 insertions(+), 131 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index f16f97bc2..788848cc4 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -322,8 +322,7 @@ private: }; /// A base class for the sun and moons. -/// \note Must be stored in an osg::ref_ptr due to being derived from osg::Referenced. -class CelestialBody : public SceneUtil::StateSetUpdater +class CelestialBody { public: CelestialBody(osg::Group* parentNode, float scaleFactor, int numUvSets) @@ -336,14 +335,9 @@ public: mTransform->addChild(mGeode); parentNode->addChild(mTransform); - - mGeode->addUpdateCallback(this); } - virtual ~CelestialBody() - { - mGeode->removeUpdateCallback(this); - } + virtual ~CelestialBody() {} virtual void adjustTransparency(const float ratio) = 0; @@ -365,31 +359,19 @@ class Sun : public CelestialBody public: Sun(osg::Group* parentNode, Resource::TextureManager& textureManager) : CelestialBody(parentNode, 1.0f, 1) - , mTextureManager(textureManager) - , mColor(0.0f, 0.0f, 0.0f, 1.0f) + , mUpdater(new Updater(textureManager)) { + mGeode->addUpdateCallback(mUpdater); } - virtual void setDefaults(osg::StateSet* stateset) + ~Sun() { - osg::ref_ptr tex = mTextureManager.getTexture2D("textures/tx_sun_05.dds", - osg::Texture::CLAMP, - osg::Texture::CLAMP); - - stateset->setTextureAttributeAndModes(0, tex, osg::StateAttribute::ON); - stateset->setAttributeAndModes(createUnlitMaterial(), - osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); - } - - virtual void apply(osg::StateSet* stateset, osg::NodeVisitor*) - { - osg::Material* mat = static_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); - mat->setDiffuse(osg::Material::FRONT_AND_BACK, mColor); + mGeode->removeUpdateCallback(mUpdater); } virtual void adjustTransparency(const float ratio) { - mColor.a() = ratio; + mUpdater->mColor.a() = ratio; } void setDirection(const osg::Vec3f& direction) @@ -403,8 +385,36 @@ public: } private: - Resource::TextureManager& mTextureManager; - osg::Vec4f mColor; + struct Updater : public SceneUtil::StateSetUpdater + { + Resource::TextureManager& mTextureManager; + osg::Vec4f mColor; + + Updater(Resource::TextureManager& textureManager) + : mTextureManager(textureManager) + , mColor(0.0f, 0.0f, 0.0f, 1.0f) + { + } + + virtual void setDefaults(osg::StateSet* stateset) + { + osg::ref_ptr tex = mTextureManager.getTexture2D("textures/tx_sun_05.dds", + osg::Texture::CLAMP, + osg::Texture::CLAMP); + + stateset->setTextureAttributeAndModes(0, tex, osg::StateAttribute::ON); + stateset->setAttributeAndModes(createUnlitMaterial(), + osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); + } + + virtual void apply(osg::StateSet* stateset, osg::NodeVisitor*) + { + osg::Material* mat = static_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); + mat->setDiffuse(osg::Material::FRONT_AND_BACK, mColor); + } + }; + + osg::ref_ptr mUpdater; }; class Moon : public CelestialBody @@ -418,53 +428,24 @@ public: Moon(osg::Group* parentNode, Resource::TextureManager& textureManager, float scaleFactor, Type type) : CelestialBody(parentNode, scaleFactor, 2) - , mTextureManager(textureManager) , mType(type) , mPhase(MoonState::Phase_Unspecified) - , mTransparency(1.0f) - , mShadowBlend(1.0f) - , mMoonColor(1.0f, 1.0f, 1.0f, 1.0f) + , mUpdater(new Updater(textureManager)) { setPhase(MoonState::Phase_Full); setVisible(true); - } - virtual void setDefaults(osg::StateSet *stateset) - { - stateset->setTextureAttributeAndModes(0, mPhaseTex, osg::StateAttribute::ON); - osg::ref_ptr texEnv = new osg::TexEnvCombine; - texEnv->setCombine_RGB(osg::TexEnvCombine::MODULATE); - texEnv->setSource0_RGB(osg::TexEnvCombine::CONSTANT); - texEnv->setSource1_RGB(osg::TexEnvCombine::TEXTURE); - texEnv->setConstantColor(osg::Vec4f(1.f, 0.f, 0.f, 1.f)); // mShadowBlend * mMoonColor - stateset->setTextureAttributeAndModes(0, texEnv, osg::StateAttribute::ON); - - stateset->setTextureAttributeAndModes(1, mCircleTex, osg::StateAttribute::ON); - osg::ref_ptr texEnv2 = new osg::TexEnvCombine; - texEnv2->setCombine_RGB(osg::TexEnvCombine::ADD); - texEnv2->setCombine_Alpha(osg::TexEnvCombine::MODULATE); - texEnv2->setSource0_Alpha(osg::TexEnvCombine::TEXTURE); - texEnv2->setSource1_Alpha(osg::TexEnvCombine::CONSTANT); - texEnv2->setSource0_RGB(osg::TexEnvCombine::PREVIOUS); - texEnv2->setSource1_RGB(osg::TexEnvCombine::CONSTANT); - texEnv2->setConstantColor(osg::Vec4f(0.f, 0.f, 0.f, 1.f)); // mAtmosphereColor.rgb, mTransparency - stateset->setTextureAttributeAndModes(1, texEnv2, osg::StateAttribute::ON); - - stateset->setAttributeAndModes(createUnlitMaterial(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + mGeode->addUpdateCallback(mUpdater); } - virtual void apply(osg::StateSet *stateset, osg::NodeVisitor*) + ~Moon() { - osg::TexEnvCombine* texEnv = static_cast(stateset->getTextureAttribute(0, osg::StateAttribute::TEXENV)); - texEnv->setConstantColor(mMoonColor * mShadowBlend); - - osg::TexEnvCombine* texEnv2 = static_cast(stateset->getTextureAttribute(1, osg::StateAttribute::TEXENV)); - texEnv2->setConstantColor(osg::Vec4f(mAtmosphereColor.x(), mAtmosphereColor.y(), mAtmosphereColor.z(), mTransparency)); + mGeode->removeUpdateCallback(mUpdater); } virtual void adjustTransparency(const float ratio) { - mTransparency *= ratio; + mUpdater->mTransparency *= ratio; } void setState(const MoonState& state) @@ -484,18 +465,18 @@ public: mTransform->setAttitude(attX * rotZ); setPhase(state.mPhase); - mTransparency = state.mMoonAlpha; - mShadowBlend = state.mShadowBlend; + mUpdater->mTransparency = state.mMoonAlpha; + mUpdater->mShadowBlend = state.mShadowBlend; } void setAtmosphereColor(const osg::Vec4f& color) { - mAtmosphereColor = color; + mUpdater->mAtmosphereColor = color; } void setColor(const osg::Vec4f& color) { - mMoonColor = color; + mUpdater->mMoonColor = color; } unsigned int getPhaseInt() const @@ -512,50 +493,102 @@ public: } private: - Resource::TextureManager& mTextureManager; - Type mType; - MoonState::Phase mPhase; - float mTransparency; - float mShadowBlend; - osg::Vec4f mAtmosphereColor; - osg::Vec4f mMoonColor; - osg::ref_ptr mPhaseTex; - osg::ref_ptr mCircleTex; + struct Updater : public SceneUtil::StateSetUpdater + { + Resource::TextureManager& mTextureManager; + osg::ref_ptr mPhaseTex; + osg::ref_ptr mCircleTex; + float mTransparency; + float mShadowBlend; + osg::Vec4f mAtmosphereColor; + osg::Vec4f mMoonColor; + + Updater(Resource::TextureManager& textureManager) + : mTextureManager(textureManager) + , mPhaseTex() + , mCircleTex() + , mTransparency(1.0f) + , mShadowBlend(1.0f) + , mAtmosphereColor(1.0f, 1.0f, 1.0f, 1.0f) + , mMoonColor(1.0f, 1.0f, 1.0f, 1.0f) + { + } - void setTextures(const std::string& phaseTex, const std::string& circleTex) - { - mPhaseTex = mTextureManager.getTexture2D(phaseTex, osg::Texture::CLAMP, osg::Texture::CLAMP); - mCircleTex = mTextureManager.getTexture2D(circleTex, osg::Texture::CLAMP, osg::Texture::CLAMP); + virtual void setDefaults(osg::StateSet* stateset) + { + stateset->setTextureAttributeAndModes(0, mPhaseTex, osg::StateAttribute::ON); + osg::ref_ptr texEnv = new osg::TexEnvCombine; + texEnv->setCombine_RGB(osg::TexEnvCombine::MODULATE); + texEnv->setSource0_RGB(osg::TexEnvCombine::CONSTANT); + texEnv->setSource1_RGB(osg::TexEnvCombine::TEXTURE); + texEnv->setConstantColor(osg::Vec4f(1.f, 0.f, 0.f, 1.f)); // mShadowBlend * mMoonColor + stateset->setTextureAttributeAndModes(0, texEnv, osg::StateAttribute::ON); + + stateset->setTextureAttributeAndModes(1, mCircleTex, osg::StateAttribute::ON); + osg::ref_ptr texEnv2 = new osg::TexEnvCombine; + texEnv2->setCombine_RGB(osg::TexEnvCombine::ADD); + texEnv2->setCombine_Alpha(osg::TexEnvCombine::MODULATE); + texEnv2->setSource0_Alpha(osg::TexEnvCombine::TEXTURE); + texEnv2->setSource1_Alpha(osg::TexEnvCombine::CONSTANT); + texEnv2->setSource0_RGB(osg::TexEnvCombine::PREVIOUS); + texEnv2->setSource1_RGB(osg::TexEnvCombine::CONSTANT); + texEnv2->setConstantColor(osg::Vec4f(0.f, 0.f, 0.f, 1.f)); // mAtmosphereColor.rgb, mTransparency + stateset->setTextureAttributeAndModes(1, texEnv2, osg::StateAttribute::ON); + + stateset->setAttributeAndModes(createUnlitMaterial(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + } - reset(); - } + virtual void apply(osg::StateSet* stateset, osg::NodeVisitor*) + { + osg::TexEnvCombine* texEnv = static_cast(stateset->getTextureAttribute(0, osg::StateAttribute::TEXENV)); + texEnv->setConstantColor(mMoonColor * mShadowBlend); + + osg::TexEnvCombine* texEnv2 = static_cast(stateset->getTextureAttribute(1, osg::StateAttribute::TEXENV)); + texEnv2->setConstantColor(osg::Vec4f(mAtmosphereColor.x(), mAtmosphereColor.y(), mAtmosphereColor.z(), mTransparency)); + } + + void setTextures(const std::string& phaseTex, const std::string& circleTex) + { + mPhaseTex = mTextureManager.getTexture2D(phaseTex, osg::Texture::CLAMP, osg::Texture::CLAMP); + mCircleTex = mTextureManager.getTexture2D(circleTex, osg::Texture::CLAMP, osg::Texture::CLAMP); + + reset(); + } + }; + + Type mType; + MoonState::Phase mPhase; + osg::ref_ptr mUpdater; void setPhase(const MoonState::Phase& phase) { - if (mPhase == phase) + if(mPhase == phase) return; + mPhase = phase; std::string textureName = "textures/tx_"; - if (mType == Moon::Type_Secunda) textureName += "secunda_"; - else textureName += "masser_"; + if (mType == Moon::Type_Secunda) + textureName += "secunda_"; + else + textureName += "masser_"; - if (phase == MoonState::Phase_New) textureName += "new"; - else if (phase == MoonState::Phase_WaxingCrescent) textureName += "one_wax"; - else if (phase == MoonState::Phase_FirstQuarter) textureName += "half_wax"; - else if (phase == MoonState::Phase_WaxingGibbous) textureName += "three_wax"; - else if (phase == MoonState::Phase_WaningCrescent) textureName += "one_wan"; - else if (phase == MoonState::Phase_ThirdQuarter) textureName += "half_wan"; - else if (phase == MoonState::Phase_WaningGibbous) textureName += "three_wan"; - else if (phase == MoonState::Phase_Full) textureName += "full"; + if (phase == MoonState::Phase_New) textureName += "new"; + else if(phase == MoonState::Phase_WaxingCrescent) textureName += "one_wax"; + else if(phase == MoonState::Phase_FirstQuarter) textureName += "half_wax"; + else if(phase == MoonState::Phase_WaxingGibbous) textureName += "three_wax"; + else if(phase == MoonState::Phase_WaningCrescent) textureName += "one_wan"; + else if(phase == MoonState::Phase_ThirdQuarter) textureName += "half_wan"; + else if(phase == MoonState::Phase_WaningGibbous) textureName += "three_wan"; + else if(phase == MoonState::Phase_Full) textureName += "full"; textureName += ".dds"; if (mType == Moon::Type_Secunda) - setTextures(textureName, "textures/tx_mooncircle_full_s.dds"); + mUpdater->setTextures(textureName, "textures/tx_mooncircle_full_s.dds"); else - setTextures(textureName, "textures/tx_mooncircle_full_m.dds"); + mUpdater->setTextures(textureName, "textures/tx_mooncircle_full_m.dds"); } }; @@ -621,11 +654,11 @@ void SkyManager::create() mAtmosphereNightUpdater = new AtmosphereNightUpdater(mSceneManager->getTextureManager()); atmosphereNight->addUpdateCallback(mAtmosphereNightUpdater); - mSun = new Sun(mRootNode, *mSceneManager->getTextureManager()); + mSun.reset(new Sun(mRootNode, *mSceneManager->getTextureManager())); const MWWorld::Fallback* fallback=MWBase::Environment::get().getWorld()->getFallback(); - mMasser = new Moon(mRootNode, *mSceneManager->getTextureManager(), fallback->getFallbackFloat("Moons_Masser_Size")/125, Moon::Type_Masser); - mSecunda = new Moon(mRootNode, *mSceneManager->getTextureManager(), fallback->getFallbackFloat("Moons_Secunda_Size")/125, Moon::Type_Secunda); + mMasser.reset(new Moon(mRootNode, *mSceneManager->getTextureManager(), fallback->getFallbackFloat("Moons_Masser_Size")/125, Moon::Type_Masser)); + mSecunda.reset(new Moon(mRootNode, *mSceneManager->getTextureManager(), fallback->getFallbackFloat("Moons_Secunda_Size")/125, Moon::Type_Secunda)); mCloudNode = new osg::PositionAttitudeTransform; mRootNode->addChild(mCloudNode); @@ -1067,11 +1100,11 @@ void SkyManager::setWeather(const WeatherResult& weather) mCloudSpeed = weather.mCloudSpeed; - mMasser->adjustTransparency(weather.mCelestialBodyTransparency); - mSecunda->adjustTransparency(weather.mCelestialBodyTransparency); - mSun->adjustTransparency(weather.mCelestialBodyTransparency); + mMasser->adjustTransparency(weather.mGlareView); + mSecunda->adjustTransparency(weather.mGlareView); + mSun->adjustTransparency(weather.mGlareView); - float nextStarsOpacity = weather.mNightFade * weather.mCelestialBodyTransparency; + float nextStarsOpacity = weather.mNightFade * weather.mGlareView; if(weather.mNight && mStarsOpacity != nextStarsOpacity) { mStarsOpacity = nextStarsOpacity; diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index 16509ef32..4b1acadc3 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -2,6 +2,7 @@ #define OPENMW_MWRENDER_SKY_H #include +#include #include #include @@ -75,8 +76,6 @@ namespace MWRender float mRainSpeed; float mRainFrequency; - - float mCelestialBodyTransparency; }; struct MoonState @@ -179,9 +178,9 @@ namespace MWRender osg::ref_ptr mAtmosphereUpdater; - osg::ref_ptr mSun; - osg::ref_ptr mMasser; - osg::ref_ptr mSecunda; + std::auto_ptr mSun; + std::auto_ptr mMasser; + std::auto_ptr mSecunda; osg::ref_ptr mRainNode; osg::ref_ptr mRainParticleSystem; diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 679565e45..c571b1d1d 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -294,54 +294,44 @@ WeatherManager::WeatherManager(MWRender::RenderingManager* rendering, MWWorld::F //Weather Weather clear; - clear.mObstructsCelestialBodies = false; setFallbackWeather(clear,"clear"); Weather cloudy; - cloudy.mObstructsCelestialBodies = false; setFallbackWeather(cloudy,"cloudy"); Weather foggy; - foggy.mObstructsCelestialBodies = false; setFallbackWeather(foggy,"foggy"); Weather thunderstorm; thunderstorm.mAmbientLoopSoundID = "rain heavy"; thunderstorm.mRainEffect = "meshes\\raindrop.nif"; - thunderstorm.mObstructsCelestialBodies = true; setFallbackWeather(thunderstorm,"thunderstorm"); Weather rain; rain.mAmbientLoopSoundID = "rain"; rain.mRainEffect = "meshes\\raindrop.nif"; - rain.mObstructsCelestialBodies = true; setFallbackWeather(rain,"rain"); Weather overcast; - overcast.mObstructsCelestialBodies = true; setFallbackWeather(overcast,"overcast"); Weather ashstorm; ashstorm.mAmbientLoopSoundID = "ashstorm"; ashstorm.mParticleEffect = "meshes\\ashcloud.nif"; - ashstorm.mObstructsCelestialBodies = true; setFallbackWeather(ashstorm,"ashstorm"); Weather blight; blight.mAmbientLoopSoundID = "blight"; blight.mParticleEffect = "meshes\\blightcloud.nif"; - blight.mObstructsCelestialBodies = true; setFallbackWeather(blight,"blight"); Weather snow; snow.mParticleEffect = "meshes\\snow.nif"; - snow.mObstructsCelestialBodies = true; setFallbackWeather(snow, "snow"); Weather blizzard; blizzard.mAmbientLoopSoundID = "BM Blizzard"; blizzard.mParticleEffect = "meshes\\blizzard.nif"; - blizzard.mObstructsCelestialBodies = true; setFallbackWeather(blizzard,"blizzard"); } @@ -475,8 +465,6 @@ void WeatherManager::setResult(const std::string& weatherType) mResult.mNightFade = factor; } } - - mResult.mCelestialBodyTransparency = current.mObstructsCelestialBodies ? 0.0f : 1.0f; } void WeatherManager::transition(float factor) @@ -530,16 +518,6 @@ void WeatherManager::transition(float factor) mResult.mEffectFade = mResult.mAmbientSoundVolume; mResult.mAmbientLoopSoundID = other.mAmbientLoopSoundID; } - - const Weather& currentSettings = mWeatherSettings[mCurrentWeather]; - const Weather& nextSettings = mWeatherSettings[mNextWeather]; - - if(currentSettings.mObstructsCelestialBodies && !nextSettings.mObstructsCelestialBodies) - mResult.mCelestialBodyTransparency = factor; - else if(!currentSettings.mObstructsCelestialBodies && nextSettings.mObstructsCelestialBodies) - mResult.mCelestialBodyTransparency = 1 - factor; - else - mResult.mCelestialBodyTransparency = current.mCelestialBodyTransparency; } void WeatherManager::update(float duration, bool paused) diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index 1bc3bc357..d5ac6d801 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -80,7 +80,8 @@ namespace MWWorld // Multiplier for clouds transparency float mCloudsMaximumPercent; - // Value between 0 and 1, defines the strength of the sun glare effect + // Value between 0 and 1, defines the strength of the sun glare effect. + // Also appears to modify how visible the sun, moons, and stars are for various weather effects. float mGlareView; // Sound effect @@ -106,9 +107,6 @@ namespace MWWorld // Note: For Weather Blight, there is a "Disease Chance" (=0.1) setting. But according to MWSFD this feature // is broken in the vanilla game and was disabled. - - // Some weather patterns will obstruct the moons, sun, and stars. - bool mObstructsCelestialBodies; }; class MoonModel From 56b7196beaeb3c1ec8712605fa9d2ca9266f467a Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 7 Aug 2015 15:34:01 +0200 Subject: [PATCH 2002/3725] Remove incorrect implementation of "Clouds Maximum Percent" weather setting --- apps/openmw/mwrender/sky.cpp | 12 ++++++------ apps/openmw/mwrender/sky.hpp | 3 --- apps/openmw/mwworld/weather.cpp | 3 --- apps/openmw/mwworld/weather.hpp | 2 +- 4 files changed, 7 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 788848cc4..138365ae4 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -605,7 +605,6 @@ SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneMana , mClouds() , mNextClouds() , mCloudBlendFactor(0.0f) - , mCloudOpacity(0.0f) , mCloudSpeed(0.0f) , mStarsOpacity(0.0f) , mRemainingTransitionTime(0.0f) @@ -666,12 +665,15 @@ void SkyManager::create() ModVertexAlphaVisitor modClouds(1); mCloudMesh->accept(modClouds); mCloudUpdater = new CloudUpdater; + mCloudUpdater->setOpacity(1.f); mCloudMesh->addUpdateCallback(mCloudUpdater); mCloudMesh2 = mSceneManager->createInstance("meshes/sky_clouds_01.nif", mCloudNode); mCloudMesh2->accept(modClouds); mCloudUpdater2 = new CloudUpdater; + mCloudUpdater2->setOpacity(0.f); mCloudMesh2->addUpdateCallback(mCloudUpdater2); + mCloudMesh2->setNodeMask(0); osg::ref_ptr depth = new osg::Depth; depth->setWriteMask(false); @@ -1060,14 +1062,12 @@ void SkyManager::setWeather(const WeatherResult& weather) osg::Texture::REPEAT, osg::Texture::REPEAT)); } - if (mCloudBlendFactor != weather.mCloudBlendFactor - || mCloudOpacity != weather.mCloudOpacity) + if (mCloudBlendFactor != weather.mCloudBlendFactor) { mCloudBlendFactor = weather.mCloudBlendFactor; - mCloudOpacity = weather.mCloudOpacity; - mCloudUpdater->setOpacity(mCloudOpacity * (1.f-mCloudBlendFactor)); - mCloudUpdater2->setOpacity(mCloudOpacity * mCloudBlendFactor); + mCloudUpdater->setOpacity((1.f-mCloudBlendFactor)); + mCloudUpdater2->setOpacity(mCloudBlendFactor); mCloudMesh2->setNodeMask(mCloudBlendFactor > 0.f ? ~0 : 0); } diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index 4b1acadc3..3855136a9 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -58,8 +58,6 @@ namespace MWRender float mCloudSpeed; - float mCloudOpacity; - float mGlareView; bool mNight; // use night skybox @@ -204,7 +202,6 @@ namespace MWRender std::string mClouds; std::string mNextClouds; float mCloudBlendFactor; - float mCloudOpacity; float mCloudSpeed; float mStarsOpacity; osg::Vec4f mCloudColour; diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index c571b1d1d..8d78b969e 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -374,7 +374,6 @@ void WeatherManager::setResult(const std::string& weatherType) mResult.mCloudTexture = current.mCloudTexture; mResult.mCloudBlendFactor = 0; - mResult.mCloudOpacity = current.mCloudsMaximumPercent; mResult.mWindSpeed = current.mWindSpeed; mResult.mCloudSpeed = current.mCloudSpeed; mResult.mGlareView = current.mGlareView; @@ -478,7 +477,6 @@ void WeatherManager::transition(float factor) mResult.mNextCloudTexture = other.mCloudTexture; mResult.mCloudBlendFactor = factor; - mResult.mCloudOpacity = lerp(current.mCloudOpacity, other.mCloudOpacity, factor); mResult.mFogColor = lerp(current.mFogColor, other.mFogColor, factor); mResult.mSunColor = lerp(current.mSunColor, other.mSunColor, factor); mResult.mSkyColor = lerp(current.mSkyColor, other.mSkyColor, factor); @@ -488,7 +486,6 @@ void WeatherManager::transition(float factor) mResult.mFogDepth = lerp(current.mFogDepth, other.mFogDepth, factor); mResult.mWindSpeed = lerp(current.mWindSpeed, other.mWindSpeed, factor); mResult.mCloudSpeed = lerp(current.mCloudSpeed, other.mCloudSpeed, factor); - mResult.mCloudOpacity = lerp(current.mCloudOpacity, other.mCloudOpacity, factor); mResult.mGlareView = lerp(current.mGlareView, other.mGlareView, factor); mResult.mNightFade = lerp(current.mNightFade, other.mNightFade, factor); diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index d5ac6d801..7f4858bc8 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -77,7 +77,7 @@ namespace MWWorld // Cloud animation speed multiplier float mCloudSpeed; - // Multiplier for clouds transparency + // TODO: What is this supposed to do? float mCloudsMaximumPercent; // Value between 0 and 1, defines the strength of the sun glare effect. From 865491d1012c5bc2291fb7463f483c2cd045c244 Mon Sep 17 00:00:00 2001 From: Arthur Moore Date: Fri, 7 Aug 2015 20:06:33 -0400 Subject: [PATCH 2003/3725] Added a help message to niftest Now using the boost argument parser. --- apps/niftest/niftest.cpp | 66 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 63 insertions(+), 3 deletions(-) diff --git a/apps/niftest/niftest.cpp b/apps/niftest/niftest.cpp index 20c8597f3..fd060447c 100644 --- a/apps/niftest/niftest.cpp +++ b/apps/niftest/niftest.cpp @@ -2,12 +2,17 @@ #include #include +#include #include #include #include #include +#include + +// Create local aliases for brevity +namespace bpo = boost::program_options; ///See if the file has the named extension bool hasExtension(std::string filename, std::string extensionToFind) @@ -54,13 +59,68 @@ void readBSA(std::string filename) } } +std::vector parseOptions (int argc, char** argv) +{ + bpo::options_description desc("Ensure that OpenMW can use the provided NIF and BSA files\n\n" + "Usages:\n" + " niftool \n" + " Scan the file for read errors.\n\n" + "Allowed options"); + desc.add_options() + ("help,h", "print help message.") + ("input-file", bpo::value< std::vector >(), "input file") + ; + + //Default option if none provided + bpo::positional_options_description p; + p.add("input-file", -1); + + bpo::variables_map variables; + try + { + bpo::parsed_options valid_opts = bpo::command_line_parser(argc, argv). + options(desc).positional(p).run(); + bpo::store(valid_opts, variables); + } + catch(std::exception &e) + { + std::cout << "ERROR parsing arguments: " << e.what() << "\n\n" + << desc << std::endl; + exit(1); + } + + bpo::notify(variables); + if (variables.count ("help")) + { + std::cout << desc << std::endl; + exit(1); + } + if (variables.count("input-file")) + { + std::vector files = variables["input-file"].as< std::vector >(); + + std::cout << "Input files are:"; + for(std::vector::const_iterator it=files.begin(); it!=files.end(); ++it) + { + std::cout <<" "<< *it; + } + std::cout << std::endl; + return files; + } + + std::cout << "No input files or directories specified!" << std::endl; + std::cout << desc << std::endl; + exit(1); +} + int main(int argc, char **argv) { + std::vector files = parseOptions (argc, argv); std::cout << "Reading Files" << std::endl; - for(int i = 1; i::const_iterator it=files.begin(); it!=files.end(); ++it) + { + std::string name = *it; try{ if(isNIF(name)) From efadce3e906ccb0f23cca3554ea8e21efe9ce20c Mon Sep 17 00:00:00 2001 From: Arthur Moore Date: Fri, 7 Aug 2015 20:20:31 -0400 Subject: [PATCH 2004/3725] Have niftest handle directories as well Note: BSA files within the directory must be passed manually. --- apps/niftest/niftest.cpp | 48 +++++++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/apps/niftest/niftest.cpp b/apps/niftest/niftest.cpp index fd060447c..c138e4551 100644 --- a/apps/niftest/niftest.cpp +++ b/apps/niftest/niftest.cpp @@ -8,11 +8,14 @@ #include #include #include +#include #include +#include // Create local aliases for brevity namespace bpo = boost::program_options; +namespace bfs = boost::filesystem; ///See if the file has the named extension bool hasExtension(std::string filename, std::string extensionToFind) @@ -40,22 +43,30 @@ bool isBSA(std::string filename) return hasExtension(filename,"bsa"); } -///Check all the nif files in the given BSA archive -void readBSA(std::string filename) +/// Check all the nif files in a given VFS::Archive +/// \note Takes ownership! +void readVFS(VFS::Archive* anArchive) { VFS::Manager myManager(false); - myManager.addArchive(new VFS::BsaArchive(filename)); + myManager.addArchive(anArchive); myManager.buildIndex(); std::map files=myManager.getIndex(); for(std::map::const_iterator it=files.begin(); it!=files.end(); ++it) { - std::string name = it->first; - if(isNIF(name)) - { -// std::cout << "Decoding: " << name << std::endl; - Nif::NIFFile temp_nif(myManager.get(name),name); - } + std::string name = it->first; + + try{ + if(isNIF(name)) + { + // std::cout << "Decoding: " << name << std::endl; + Nif::NIFFile temp_nif(myManager.get(name),name); + } + } + catch (std::exception& e) + { + std::cerr << "ERROR, an exception has occurred: " << e.what() << std::endl; + } } } @@ -97,15 +108,7 @@ std::vector parseOptions (int argc, char** argv) } if (variables.count("input-file")) { - std::vector files = variables["input-file"].as< std::vector >(); - - std::cout << "Input files are:"; - for(std::vector::const_iterator it=files.begin(); it!=files.end(); ++it) - { - std::cout <<" "<< *it; - } - std::cout << std::endl; - return files; + return variables["input-file"].as< std::vector >(); } std::cout << "No input files or directories specified!" << std::endl; @@ -131,11 +134,16 @@ int main(int argc, char **argv) else if(isBSA(name)) { std::cout << "Reading BSA File: " << name << std::endl; - readBSA(name); + readVFS(new VFS::BsaArchive(name)); + } + else if(bfs::is_directory(bfs::path(name))) + { + std::cout << "Reading All Files in: " << name << std::endl; + readVFS(new VFS::FileSystemArchive(name)); } else { - std::cerr << "ERROR: \"" << name << "\" is not a nif or bsa file!" << std::endl; + std::cerr << "ERROR: \"" << name << "\" is not a nif file, bsa file, or directory!" << std::endl; } } catch (std::exception& e) From 6a6da42b85ed7a3cce05348b2f4b9b614539fe2f Mon Sep 17 00:00:00 2001 From: Arthur Moore Date: Fri, 7 Aug 2015 20:22:18 -0400 Subject: [PATCH 2005/3725] Updated niftest's help message --- apps/niftest/niftest.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/niftest/niftest.cpp b/apps/niftest/niftest.cpp index c138e4551..c50e664b0 100644 --- a/apps/niftest/niftest.cpp +++ b/apps/niftest/niftest.cpp @@ -74,8 +74,8 @@ std::vector parseOptions (int argc, char** argv) { bpo::options_description desc("Ensure that OpenMW can use the provided NIF and BSA files\n\n" "Usages:\n" - " niftool \n" - " Scan the file for read errors.\n\n" + " niftool \n" + " Scan the file or directories for nif errors.\n\n" "Allowed options"); desc.add_options() ("help,h", "print help message.") From 3d78ee0c2b9fff9e7dc801091f3c0a00fa159d91 Mon Sep 17 00:00:00 2001 From: Arthur Moore Date: Fri, 7 Aug 2015 20:39:43 -0400 Subject: [PATCH 2006/3725] niftest now scans BSA files in directories for nif errors The program is explicit so the user knows exactly where the bad file is. --- apps/niftest/niftest.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/apps/niftest/niftest.cpp b/apps/niftest/niftest.cpp index c50e664b0..6229d1e83 100644 --- a/apps/niftest/niftest.cpp +++ b/apps/niftest/niftest.cpp @@ -45,9 +45,9 @@ bool isBSA(std::string filename) /// Check all the nif files in a given VFS::Archive /// \note Takes ownership! -void readVFS(VFS::Archive* anArchive) +void readVFS(VFS::Archive* anArchive,std::string archivePath = "") { - VFS::Manager myManager(false); + VFS::Manager myManager(true); myManager.addArchive(anArchive); myManager.buildIndex(); @@ -62,6 +62,15 @@ void readVFS(VFS::Archive* anArchive) // std::cout << "Decoding: " << name << std::endl; Nif::NIFFile temp_nif(myManager.get(name),name); } + else if(isBSA(name)) + { + if(!archivePath.empty()) + { + std::cout << "Reading BSA File: " << name << std::endl; + readVFS(new VFS::BsaArchive(archivePath+name)); + std::cout << "Done with BSA File: " << name << std::endl; + } + } } catch (std::exception& e) { @@ -139,7 +148,7 @@ int main(int argc, char **argv) else if(bfs::is_directory(bfs::path(name))) { std::cout << "Reading All Files in: " << name << std::endl; - readVFS(new VFS::FileSystemArchive(name)); + readVFS(new VFS::FileSystemArchive(name),name); } else { From c7b97ee9bab59c5e11c7237505c108fac58b1692 Mon Sep 17 00:00:00 2001 From: Arthur Moore Date: Fri, 7 Aug 2015 20:49:52 -0400 Subject: [PATCH 2007/3725] Cleaned up niftest's output A bad file inside of a bsa archive now looks like: /Data Files/TR_Data.bsa/meshes/tr/x/tr_act_ind_mark_alm.nif --- apps/niftest/niftest.cpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/apps/niftest/niftest.cpp b/apps/niftest/niftest.cpp index 6229d1e83..72393db40 100644 --- a/apps/niftest/niftest.cpp +++ b/apps/niftest/niftest.cpp @@ -45,6 +45,7 @@ bool isBSA(std::string filename) /// Check all the nif files in a given VFS::Archive /// \note Takes ownership! +/// \note Can not read a bsa file inside of a bsa file. void readVFS(VFS::Archive* anArchive,std::string archivePath = "") { VFS::Manager myManager(true); @@ -60,15 +61,15 @@ void readVFS(VFS::Archive* anArchive,std::string archivePath = "") if(isNIF(name)) { // std::cout << "Decoding: " << name << std::endl; - Nif::NIFFile temp_nif(myManager.get(name),name); + Nif::NIFFile temp_nif(myManager.get(name),archivePath+name); } else if(isBSA(name)) { - if(!archivePath.empty()) + if(!archivePath.empty() && !isBSA(archivePath)) { - std::cout << "Reading BSA File: " << name << std::endl; - readVFS(new VFS::BsaArchive(archivePath+name)); - std::cout << "Done with BSA File: " << name << std::endl; +// std::cout << "Reading BSA File: " << name << std::endl; + readVFS(new VFS::BsaArchive(archivePath+name),archivePath+name+"/"); +// std::cout << "Done with BSA File: " << name << std::endl; } } } @@ -129,7 +130,7 @@ int main(int argc, char **argv) { std::vector files = parseOptions (argc, argv); - std::cout << "Reading Files" << std::endl; +// std::cout << "Reading Files" << std::endl; for(std::vector::const_iterator it=files.begin(); it!=files.end(); ++it) { std::string name = *it; @@ -142,12 +143,12 @@ int main(int argc, char **argv) } else if(isBSA(name)) { - std::cout << "Reading BSA File: " << name << std::endl; +// std::cout << "Reading BSA File: " << name << std::endl; readVFS(new VFS::BsaArchive(name)); } else if(bfs::is_directory(bfs::path(name))) { - std::cout << "Reading All Files in: " << name << std::endl; +// std::cout << "Reading All Files in: " << name << std::endl; readVFS(new VFS::FileSystemArchive(name),name); } else From 20078c41c36dfb7d2f482f2c0078cd73d1fb4bf9 Mon Sep 17 00:00:00 2001 From: Arthur Moore Date: Fri, 7 Aug 2015 20:53:43 -0400 Subject: [PATCH 2008/3725] Removed now unneeded script --- apps/niftest/find_bad_nifs.sh | 28 ---------------------------- 1 file changed, 28 deletions(-) delete mode 100755 apps/niftest/find_bad_nifs.sh diff --git a/apps/niftest/find_bad_nifs.sh b/apps/niftest/find_bad_nifs.sh deleted file mode 100755 index 4b599f442..000000000 --- a/apps/niftest/find_bad_nifs.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/bash -#Script to test all nif files (both loose, and in BSA archives) in data files directory - -#The user input as an absolute path -DATAFILESDIR="`readlink -m "$1"`" -#Program used to test -TEST_PROG="`pwd`/niftest" - -#Make sure our files don't bother anyone -NIFTEST_TMP_DIR="/tmp/niftest_$RANDOM/" -mkdir "$NIFTEST_TMP_DIR" -cd "$NIFTEST_TMP_DIR" - -find "$DATAFILESDIR" -iname *bsa > nifs.txt -find "$DATAFILESDIR" -iname *nif >> nifs.txt - -sed -e 's/.*/\"&\"/' nifs.txt > quoted_nifs.txt - -xargs --arg-file=quoted_nifs.txt "$TEST_PROG" 2>&1 | tee nif_out.txt -# xargs --arg-file=quoted_nifs.txt "$TEST_PROG" 2> nif_out.txt >/dev/null - -echo "List of bad NIF Files:" -cat nif_out.txt|grep File:|cut -d ' ' -f 2- - -rm nifs.txt -rm quoted_nifs.txt -rm nif_out.txt -rmdir "$NIFTEST_TMP_DIR" From 3046795a9c1197ed7fc9766fe78de84e37da1672 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 8 Aug 2015 11:01:08 +0200 Subject: [PATCH 2009/3725] updated credits file --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index 291b0d56c..16c888239 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -29,6 +29,7 @@ Programmers Cory F. Cohen (cfcohen) Cris Mihalache (Mirceam) darkf + Dieho Dmitry Shkurskiy (endorph) Douglas Diniz (Dgdiniz) Douglas Mencken (dougmencken) From 708cacdec403793a0337c6e536a1ecf53a58bd6e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 8 Aug 2015 16:47:58 +0200 Subject: [PATCH 2010/3725] disable merge menu item when a merge is already in progress --- apps/opencs/view/doc/view.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index df7421a14..ea11bb0f9 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -398,7 +398,8 @@ void CSVDoc::View::updateActions() mGlobalDebugProfileMenu->updateActions (running); mStopDebug->setEnabled (running); - mMerge->setEnabled (mDocument->getContentFiles().size()>1); + mMerge->setEnabled (mDocument->getContentFiles().size()>1 && + !(mDocument->getState() & CSMDoc::State_Merging)); } CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews) From 1676bf917e60f8a0d0614d628be779b0f65d6e28 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 9 Aug 2015 14:06:52 +1200 Subject: [PATCH 2011/3725] CombatMove logic moved into AiCombatStorage. Basically, copied from mrcheko's 1d4be08f6e4c2dbd89cc0c3408a8231ee4497277 --- apps/openmw/mwmechanics/aicombat.cpp | 91 +++++++++++++++++----------- 1 file changed, 54 insertions(+), 37 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index f386ec81b..c8876c842 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -110,6 +110,10 @@ namespace MWMechanics mForceNoShortcut(false), mLastActorPos(0,0,0), mMovement(){} + + void startCombatMove(bool isNpc, bool isDistantCombat, float distToTarget, float rangeAttack); + void updateCombatMove(float duration); + void stopCombatMove(); }; AiCombat::AiCombat(const MWWorld::Ptr& actor) : @@ -192,19 +196,8 @@ namespace MWMechanics //Update every frame - bool& combatMove = storage.mCombatMove; - float& timerCombatMove = storage.mTimerCombatMove; + storage.updateCombatMove(duration); MWMechanics::Movement& movement = storage.mMovement; - if(combatMove) - { - timerCombatMove -= duration; - if( timerCombatMove <= 0) - { - timerCombatMove = 0; - movement.mPosition[1] = movement.mPosition[0] = 0; - combatMove = false; - } - } UpdateActorsMovement(actor, movement); @@ -454,31 +447,12 @@ namespace MWMechanics if (followTarget && distToTarget > rangeAttack) { //Close-up combat: just run up on target + storage.stopCombatMove(); movement.mPosition[1] = 1; } else // (within attack dist) { - if(movement.mPosition[0] || movement.mPosition[1]) - { - storage.mTimerCombatMove = 0.1f + 0.1f * Misc::Rng::rollClosedProbability(); - storage.mCombatMove = true; - } - // only NPCs are smart enough to use dodge movements - else if(actorClass.isNpc() && (!distantCombat || (distantCombat && distToTarget < rangeAttack/2))) - { - //apply sideway movement (kind of dodging) with some probability - if (Misc::Rng::rollClosedProbability() < 0.25) - { - movement.mPosition[0] = Misc::Rng::rollProbability() < 0.5 ? 1.0f : -1.0f; - storage.mTimerCombatMove = 0.05f + 0.15f * Misc::Rng::rollClosedProbability(); - storage.mCombatMove = true; - } - } - - if(distantCombat && distToTarget < rangeAttack/4) - { - movement.mPosition[1] = -1; - } + storage.startCombatMove(actorClass.isNpc(), distantCombat, distToTarget, rangeAttack); readyToAttack = true; //only once got in melee combat, actor is allowed to use close-up shortcutting @@ -551,14 +525,13 @@ namespace MWMechanics } } - movement.mPosition[1] = 1; if (readyToAttack) { // to stop possible sideway moving after target moved out of attack range - storage.mCombatMove = true; - storage.mTimerCombatMove = 0; + storage.stopCombatMove(); + readyToAttack = false; } - readyToAttack = false; + movement.mPosition[1] = 1; } return false; @@ -663,6 +636,50 @@ namespace MWMechanics package.mPackage = combat.release(); sequence.mPackages.push_back(package); } + + void AiCombatStorage::startCombatMove(bool isNpc, bool isDistantCombat, float distToTarget, float rangeAttack) + { + if (mMovement.mPosition[0] || mMovement.mPosition[1]) + { + mTimerCombatMove = 0.1f + 0.1f * Misc::Rng::rollClosedProbability(); + mCombatMove = true; + } + // only NPCs are smart enough to use dodge movements + else if (isNpc && (!isDistantCombat || (distToTarget < rangeAttack / 2))) + { + //apply sideway movement (kind of dodging) with some probability + if (Misc::Rng::rollClosedProbability() < 0.25) + { + mMovement.mPosition[0] = Misc::Rng::rollProbability() < 0.5 ? 1.0f : -1.0f; + mTimerCombatMove = 0.05f + 0.15f * Misc::Rng::rollClosedProbability(); + mCombatMove = true; + } + } + + if (isDistantCombat && distToTarget < rangeAttack / 4) + { + mMovement.mPosition[1] = -1; + } + } + + void AiCombatStorage::updateCombatMove(float duration) + { + if (mCombatMove) + { + mTimerCombatMove -= duration; + if (mTimerCombatMove <= 0) + { + stopCombatMove(); + } + } + } + + void AiCombatStorage::stopCombatMove() + { + mTimerCombatMove = 0; + mMovement.mPosition[1] = mMovement.mPosition[0] = 0; + mCombatMove = false; + } } From 0735e3e06e3c3a1241ea78ec402a28e38f8331e1 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 9 Aug 2015 14:08:42 +1200 Subject: [PATCH 2012/3725] move start attack logic to AiCombatStorage. Basically, copied from mrchenko's 1d4be08f6e4c2dbd89cc0c3408a8231ee4497277 --- apps/openmw/mwmechanics/aicombat.cpp | 82 +++++++++++++++------------- 1 file changed, 44 insertions(+), 38 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index c8876c842..03dc91c0a 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -114,6 +114,8 @@ namespace MWMechanics void startCombatMove(bool isNpc, bool isDistantCombat, float distToTarget, float rangeAttack); void updateCombatMove(float duration); void stopCombatMove(); + void startAttackIfReady(const MWWorld::Ptr& actor, CharacterController& characterController, + const ESM::Weapon* weapon, bool distantCombat); }; AiCombat::AiCombat(const MWWorld::Ptr& actor) : @@ -194,7 +196,6 @@ namespace MWMechanics || target.getClass().getCreatureStats(target).isDead()) return true; - //Update every frame storage.updateCombatMove(duration); MWMechanics::Movement& movement = storage.mMovement; @@ -318,41 +319,9 @@ namespace MWMechanics } - float& strength = storage.mStrength; bool& readyToAttack = storage.mReadyToAttack; // start new attack - if(readyToAttack && characterController.readyToStartAttack()) - { - if (storage.mAttackCooldown <= 0) - { - storage.mAttack = true; // attack starts just now - characterController.setAttackingOrSpell(true); - - if (!distantCombat) - chooseBestAttack(weapon, movement); - - strength = Misc::Rng::rollClosedProbability(); - - const MWWorld::ESMStore &store = world->getStore(); - - //say a provoking combat phrase - if (actor.getClass().isNpc()) - { - int chance = store.get().find("iVoiceAttackOdds")->getInt(); - if (Misc::Rng::roll0to99() < chance) - { - MWBase::Environment::get().getDialogueManager()->say(actor, "attack"); - } - } - float baseDelay = store.get().find("fCombatDelayCreature")->getFloat(); - if (actor.getClass().isNpc()) - baseDelay = store.get().find("fCombatDelayNPC")->getFloat(); - storage.mAttackCooldown = std::min(baseDelay + 0.01 * Misc::Rng::roll0to99(), baseDelay + 0.9); - } - else - storage.mAttackCooldown -= REACTION_INTERVAL; - } - + storage.startAttackIfReady(actor, characterController, weapon, distantCombat); /* * Some notes on meanings of variables: @@ -403,9 +372,6 @@ namespace MWMechanics bool canMoveByZ = (actorClass.canSwim(actor) && world->isSwimming(actor)) || world->isFlying(actor); - // for distant combat we should know if target is in LOS even if distToTarget < rangeAttack - bool inLOS = distantCombat ? world->getLOS(actor, target) : true; - // can't fight if attacker can't go where target is. E.g. A fish can't attack person on land. if (distToTarget >= rangeAttack && !actorClass.isNpc() && !MWMechanics::isEnvironmentCompatible(actor, target)) @@ -419,6 +385,9 @@ namespace MWMechanics return false; } + // for distant combat we should know if target is in LOS even if distToTarget < rangeAttack + bool inLOS = distantCombat ? world->getLOS(actor, target) : true; + // (within attack dist) || (not quite attack dist while following) if(inLOS && (distToTarget < rangeAttack || (distToTarget <= rangeFollow && followTarget && !isStuck))) { @@ -432,7 +401,8 @@ namespace MWMechanics if (distantCombat) { osg::Vec3f& lastTargetPos = storage.mLastTargetPos; - osg::Vec3f vAimDir = AimDirToMovingTarget(actor, target, lastTargetPos, REACTION_INTERVAL, weaptype, strength); + osg::Vec3f vAimDir = AimDirToMovingTarget(actor, target, lastTargetPos, REACTION_INTERVAL, weaptype, + storage.mStrength); lastTargetPos = vTargetPos; movement.mRotation[0] = getXAngleToDir(vAimDir); movement.mRotation[2] = getZAngleToDir(vAimDir); @@ -680,6 +650,42 @@ namespace MWMechanics mMovement.mPosition[1] = mMovement.mPosition[0] = 0; mCombatMove = false; } + + void AiCombatStorage::startAttackIfReady(const MWWorld::Ptr& actor, CharacterController& characterController, + const ESM::Weapon* weapon, bool distantCombat) + { + if (mReadyToAttack && characterController.readyToStartAttack()) + { + if (mAttackCooldown <= 0) + { + mAttack = true; // attack starts just now + characterController.setAttackingOrSpell(true); + + if (!distantCombat) + chooseBestAttack(weapon, mMovement); + + mStrength = Misc::Rng::rollClosedProbability(); + + const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); + + float baseDelay = store.get().find("fCombatDelayCreature")->getFloat(); + if (actor.getClass().isNpc()) + { + baseDelay = store.get().find("fCombatDelayNPC")->getFloat(); + + //say a provoking combat phrase + int chance = store.get().find("iVoiceAttackOdds")->getInt(); + if (Misc::Rng::roll0to99() < chance) + { + MWBase::Environment::get().getDialogueManager()->say(actor, "attack"); + } + } + mAttackCooldown = std::min(baseDelay + 0.01 * Misc::Rng::roll0to99(), baseDelay + 0.9); + } + else + mAttackCooldown -= REACTION_INTERVAL; + } + } } From 50ddcd19532756016d668f38baa071009f98d208 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 9 Aug 2015 14:10:08 +1200 Subject: [PATCH 2013/3725] more attack logic moved into AiCombatStorage. --- apps/openmw/mwmechanics/aicombat.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 03dc91c0a..a5a48991a 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -116,6 +116,7 @@ namespace MWMechanics void stopCombatMove(); void startAttackIfReady(const MWWorld::Ptr& actor, CharacterController& characterController, const ESM::Weapon* weapon, bool distantCombat); + void updateAttack(CharacterController& characterController); }; AiCombat::AiCombat(const MWWorld::Ptr& actor) : @@ -201,12 +202,7 @@ namespace MWMechanics MWMechanics::Movement& movement = storage.mMovement; UpdateActorsMovement(actor, movement); - - bool& attack = storage.mAttack; - if (attack && (characterController.getAttackStrength() >= storage.mStrength || characterController.readyToPrepareAttack())) - attack = false; - - characterController.setAttackingOrSpell(attack); + storage.updateAttack(characterController); float& actionCooldown = storage.mActionCooldown; actionCooldown -= duration; @@ -686,6 +682,15 @@ namespace MWMechanics mAttackCooldown -= REACTION_INTERVAL; } } + + void AiCombatStorage::updateAttack(CharacterController& characterController) + { + if (mAttack && (characterController.getAttackStrength() >= mStrength || characterController.readyToPrepareAttack())) + { + mAttack = false; + } + characterController.setAttackingOrSpell(mAttack); + } } From 038851420d5615d7ce470bd83312e0b3d00ee180 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 9 Aug 2015 14:18:55 +1200 Subject: [PATCH 2014/3725] Removed unneeded temp variables. Corrected case of function names. --- apps/openmw/mwmechanics/aicombat.cpp | 16 ++++++---------- apps/openmw/mwmechanics/aicombat.hpp | 4 ++-- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index a5a48991a..b1889605d 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -199,13 +199,9 @@ namespace MWMechanics //Update every frame storage.updateCombatMove(duration); - MWMechanics::Movement& movement = storage.mMovement; - - UpdateActorsMovement(actor, movement); + updateActorsMovement(actor, storage.mMovement); storage.updateAttack(characterController); - - float& actionCooldown = storage.mActionCooldown; - actionCooldown -= duration; + storage.mActionCooldown -= duration; float& timerReact = storage.mTimerReact; if(timerReact < REACTION_INTERVAL) @@ -503,7 +499,7 @@ namespace MWMechanics return false; } - void AiCombat::UpdateActorsMovement(const MWWorld::Ptr& actor, MWMechanics::Movement& desiredMovement) + void AiCombat::updateActorsMovement(const MWWorld::Ptr& actor, MWMechanics::Movement& desiredMovement) { MWMechanics::Movement& actorMovementSettings = actor.getClass().getMovementSettings(actor); if (mPathFinder.isPathConstructed()) @@ -522,12 +518,12 @@ namespace MWMechanics else { actorMovementSettings = desiredMovement; - RotateActorOnAxis(actor, 2, actorMovementSettings, desiredMovement); - RotateActorOnAxis(actor, 0, actorMovementSettings, desiredMovement); + rotateActorOnAxis(actor, 2, actorMovementSettings, desiredMovement); + rotateActorOnAxis(actor, 0, actorMovementSettings, desiredMovement); } } - void AiCombat::RotateActorOnAxis(const MWWorld::Ptr& actor, int axis, + void AiCombat::rotateActorOnAxis(const MWWorld::Ptr& actor, int axis, MWMechanics::Movement& actorMovementSettings, MWMechanics::Movement& desiredMovement) { actorMovementSettings.mRotation[axis] = 0; diff --git a/apps/openmw/mwmechanics/aicombat.hpp b/apps/openmw/mwmechanics/aicombat.hpp index 4e4060819..73d0254f3 100644 --- a/apps/openmw/mwmechanics/aicombat.hpp +++ b/apps/openmw/mwmechanics/aicombat.hpp @@ -65,8 +65,8 @@ namespace MWMechanics AiCombatStorage& storage, MWWorld::Ptr target); /// Transfer desired movement (from AiCombatStorage) to Actor - void UpdateActorsMovement(const MWWorld::Ptr& actor, MWMechanics::Movement& movement); - void RotateActorOnAxis(const MWWorld::Ptr& actor, int axis, + void updateActorsMovement(const MWWorld::Ptr& actor, MWMechanics::Movement& movement); + void rotateActorOnAxis(const MWWorld::Ptr& actor, int axis, MWMechanics::Movement& actorMovementSettings, MWMechanics::Movement& desiredMovement); }; From 0884a3796f7e6174bf93b1b4311680faa1c67b0a Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 9 Aug 2015 14:20:55 +1200 Subject: [PATCH 2015/3725] extracted function isTargetMagicallyHidden(). --- apps/openmw/mwmechanics/aicombat.cpp | 3 +-- apps/openmw/mwmechanics/aipackage.cpp | 8 ++++++++ apps/openmw/mwmechanics/aipackage.hpp | 2 ++ apps/openmw/mwmechanics/aipursue.cpp | 3 +-- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index b1889605d..8a51a4cb0 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -222,8 +222,7 @@ namespace MWMechanics MWMechanics::Movement& movement = storage.mMovement; // Stop attacking if target is not seen - if (target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::Invisibility).getMagnitude() > 0 - || target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::Chameleon).getMagnitude() > 75) + if (isTargetMagicallyHidden(target)) { movement.mPosition[1] = movement.mPosition[0] = 0; return false; // TODO: run away instead of doing nothing diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index 77efe62a8..d10edd589 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -4,6 +4,7 @@ #include #include +#include #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" @@ -129,3 +130,10 @@ bool MWMechanics::AiPackage::doesPathNeedRecalc(ESM::Pathgrid::Point dest, const { return distance(mPrevDest, dest) > 10; } + +bool MWMechanics::AiPackage::isTargetMagicallyHidden(const MWWorld::Ptr& target) +{ + MagicEffects& magicEffects(target.getClass().getCreatureStats(target).getMagicEffects()); + return (magicEffects.get(ESM::MagicEffect::Invisibility).getMagnitude() > 0) + || (magicEffects.get(ESM::MagicEffect::Chameleon).getMagnitude() > 75); +} diff --git a/apps/openmw/mwmechanics/aipackage.hpp b/apps/openmw/mwmechanics/aipackage.hpp index da43dc6da..d73833b94 100644 --- a/apps/openmw/mwmechanics/aipackage.hpp +++ b/apps/openmw/mwmechanics/aipackage.hpp @@ -69,6 +69,8 @@ namespace MWMechanics /// Simulates the passing of time virtual void fastForward(const MWWorld::Ptr& actor, AiState& state) {} + bool isTargetMagicallyHidden(const MWWorld::Ptr& target); + protected: /// Causes the actor to attempt to walk to the specified location /** \return If the actor has arrived at his destination **/ diff --git a/apps/openmw/mwmechanics/aipursue.cpp b/apps/openmw/mwmechanics/aipursue.cpp index e936505c9..055801fde 100644 --- a/apps/openmw/mwmechanics/aipursue.cpp +++ b/apps/openmw/mwmechanics/aipursue.cpp @@ -43,8 +43,7 @@ bool AiPursue::execute (const MWWorld::Ptr& actor, CharacterController& characte ) return true; //Target doesn't exist - if (target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::Invisibility).getMagnitude() > 0 - || target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::Chameleon).getMagnitude() > 75) + if (isTargetMagicallyHidden(target)) return true; if(target.getClass().getCreatureStats(target).isDead()) From 2b9e22f593ebc862cfdc1df070249725e760a460 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 9 Aug 2015 14:29:38 +1200 Subject: [PATCH 2016/3725] extracted function stopAttack(). --- apps/openmw/mwmechanics/aicombat.cpp | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 8a51a4cb0..5ea3ba6a3 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -117,6 +117,7 @@ namespace MWMechanics void startAttackIfReady(const MWWorld::Ptr& actor, CharacterController& characterController, const ESM::Weapon* weapon, bool distantCombat); void updateAttack(CharacterController& characterController); + void stopAttack(); }; AiCombat::AiCombat(const MWWorld::Ptr& actor) : @@ -221,10 +222,9 @@ namespace MWMechanics { MWMechanics::Movement& movement = storage.mMovement; - // Stop attacking if target is not seen if (isTargetMagicallyHidden(target)) { - movement.mPosition[1] = movement.mPosition[0] = 0; + storage.stopAttack(); return false; // TODO: run away instead of doing nothing } @@ -368,11 +368,7 @@ namespace MWMechanics && !actorClass.isNpc() && !MWMechanics::isEnvironmentCompatible(actor, target)) { // TODO: start fleeing? - movement.mPosition[0] = 0; - movement.mPosition[1] = 0; - movement.mPosition[2] = 0; - readyToAttack = false; - characterController.setAttackingOrSpell(false); + storage.stopAttack(); return false; } @@ -686,6 +682,15 @@ namespace MWMechanics } characterController.setAttackingOrSpell(mAttack); } + + void AiCombatStorage::stopAttack() + { + mMovement.mPosition[0] = 0; + mMovement.mPosition[1] = 0; + mMovement.mPosition[2] = 0; + mReadyToAttack = false; + mAttack = false; + } } From e42a2478dcae9445d72c48384658c682acc11f42 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 9 Aug 2015 17:58:40 +1200 Subject: [PATCH 2017/3725] Removed tests that are not necessary. --- apps/openmw/mwmechanics/pathfinding.cpp | 80 ++++++++++++------------- 1 file changed, 37 insertions(+), 43 deletions(-) diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index c7d71e13e..f469832a5 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -51,8 +51,7 @@ namespace const MWWorld::CellStore *cell, const osg::Vec3f pos, int start) { - if(!grid || grid->mPoints.empty()) - return std::pair (-1, false); + assert(grid && !grid->mPoints.empty()); float distanceBetween = distanceSquared(grid->mPoints[0], pos); int closestIndex = 0; @@ -76,8 +75,6 @@ namespace // AiWander has logic that depends on whether a path was created, deleting // allowed nodes if not. Hence a path needs to be created even if the start // and the end points are the same. - //if(start == closestReachableIndex) - //closestReachableIndex = -1; // couldn't find anyting other than start return std::pair (closestReachableIndex, closestReachableIndex == closestIndex); @@ -110,6 +107,11 @@ namespace MWMechanics return sqrt(x * x + y * y + z * z); } + osg::Vec3f ToLocalCoordinates(const ESM::Pathgrid::Point &point, float xCell, float yCell) + { + return osg::Vec3f(point.mX - xCell, point.mY - yCell, static_cast(point.mZ)); + } + PathFinder::PathFinder() : mPathgrid(NULL), mCell(NULL) @@ -139,8 +141,6 @@ namespace MWMechanics * pathgrid point (e.g. wander) then it may be worth while to call * pop_back() to remove the redundant entry. * - * mPathConstructed is set true if successful, false if not - * * NOTE: co-ordinates must be converted prior to calling getClosestPoint() * * | @@ -208,46 +208,40 @@ namespace MWMechanics // outside an area enclosed by walls, but there is a pathgrid // point right behind the wall that is closer than any pathgrid // point outside the wall - int startNode = getClosestPoint(mPathgrid, - osg::Vec3f(startPoint.mX - xCell, startPoint.mY - yCell, static_cast(startPoint.mZ))); - // Some cells don't have any pathgrids at all - if(startNode != -1) + osg::Vec3f startPointInLocalCoords(ToLocalCoordinates(startPoint, xCell, yCell)); + int startNode = getClosestPoint(mPathgrid, startPointInLocalCoords); + + osg::Vec3f endPointInLocalCoords(ToLocalCoordinates(endPoint, xCell, yCell)); + std::pair endNode = getClosestReachablePoint(mPathgrid, cell, + endPointInLocalCoords, + startNode); + + // AiWander has logic that depends on whether a path was created, + // deleting allowed nodes if not. Hence a path needs to be created + // even if the start and the end points are the same. + // NOTE: aStarSearch will return an empty path if the start and end + // nodes are the same + if(startNode == endNode.first) { - std::pair endNode = getClosestReachablePoint(mPathgrid, cell, - osg::Vec3f(endPoint.mX - xCell, endPoint.mY - yCell, static_cast(endPoint.mZ)), - startNode); - - // this shouldn't really happen, but just in case - if(endNode.first != -1) - { - // AiWander has logic that depends on whether a path was created, - // deleting allowed nodes if not. Hence a path needs to be created - // even if the start and the end points are the same. - // NOTE: aStarSearch will return an empty path if the start and end - // nodes are the same - if(startNode == endNode.first) - { - mPath.push_back(endPoint); - return; - } + mPath.push_back(endPoint); + return; + } - mPath = mCell->aStarSearch(startNode, endNode.first); + mPath = mCell->aStarSearch(startNode, endNode.first); - if(!mPath.empty()) - { - // Add the destination (which may be different to the closest - // pathgrid point). However only add if endNode was the closest - // point to endPoint. - // - // This logic can fail in the opposite situate, e.g. endPoint may - // have been reachable but happened to be very close to an - // unreachable pathgrid point. - // - // The AI routines will have to deal with such situations. - if(endNode.second) - mPath.push_back(endPoint); - } - } + if(!mPath.empty()) + { + // Add the destination (which may be different to the closest + // pathgrid point). However only add if endNode was the closest + // point to endPoint. + // + // This logic can fail in the opposite situate, e.g. endPoint may + // have been reachable but happened to be very close to an + // unreachable pathgrid point. + // + // The AI routines will have to deal with such situations. + if(endNode.second) + mPath.push_back(endPoint); } return; From 55e3aaaa35c491ecd24edc74094c66c42ab3c3ef Mon Sep 17 00:00:00 2001 From: dteviot Date: Mon, 10 Aug 2015 20:30:43 +1200 Subject: [PATCH 2018/3725] made variable const. --- apps/openmw/mwmechanics/aipackage.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index d10edd589..1ab3264b7 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -133,7 +133,7 @@ bool MWMechanics::AiPackage::doesPathNeedRecalc(ESM::Pathgrid::Point dest, const bool MWMechanics::AiPackage::isTargetMagicallyHidden(const MWWorld::Ptr& target) { - MagicEffects& magicEffects(target.getClass().getCreatureStats(target).getMagicEffects()); + const MagicEffects& magicEffects(target.getClass().getCreatureStats(target).getMagicEffects()); return (magicEffects.get(ESM::MagicEffect::Invisibility).getMagnitude() > 0) || (magicEffects.get(ESM::MagicEffect::Chameleon).getMagnitude() > 75); } From 5fba7400a6320b5b8e943635719be9384d3ada7c Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Mon, 3 Aug 2015 19:17:26 +0200 Subject: [PATCH 2019/3725] Borrow modified bundle utilities from https://github.com/Slicer/Slicer They support dependencies with @rpath --- cmake/BundleUtilitiesWithRPath.cmake | 961 +++++++++++++++++++++++++ cmake/COPYING-CMAKE-SCRIPTS | 266 +++++++ cmake/GetPrerequisitesWithRPath.cmake | 990 ++++++++++++++++++++++++++ 3 files changed, 2217 insertions(+) create mode 100644 cmake/BundleUtilitiesWithRPath.cmake create mode 100644 cmake/GetPrerequisitesWithRPath.cmake diff --git a/cmake/BundleUtilitiesWithRPath.cmake b/cmake/BundleUtilitiesWithRPath.cmake new file mode 100644 index 000000000..5254e1a52 --- /dev/null +++ b/cmake/BundleUtilitiesWithRPath.cmake @@ -0,0 +1,961 @@ +#.rst: +# BundleUtilities +# --------------- +# +# Functions to help assemble a standalone bundle application. +# +# A collection of CMake utility functions useful for dealing with .app +# bundles on the Mac and bundle-like directories on any OS. +# +# The following functions are provided by this module: +# +# :: +# +# fixup_bundle +# copy_and_fixup_bundle +# verify_app +# get_bundle_main_executable +# get_dotapp_dir +# get_bundle_and_executable +# get_bundle_all_executables +# get_item_key +# clear_bundle_keys +# set_bundle_key_values +# get_bundle_keys +# copy_resolved_item_into_bundle +# copy_resolved_framework_into_bundle +# fixup_bundle_item +# verify_bundle_prerequisites +# verify_bundle_symlinks +# +# Requires CMake 2.6 or greater because it uses function, break and +# PARENT_SCOPE. Also depends on GetPrerequisites.cmake. +# +# :: +# +# FIXUP_BUNDLE( ) +# +# Fix up a bundle in-place and make it standalone, such that it can be +# drag-n-drop copied to another machine and run on that machine as long +# as all of the system libraries are compatible. +# +# If you pass plugins to fixup_bundle as the libs parameter, you should +# install them or copy them into the bundle before calling fixup_bundle. +# The "libs" parameter is a list of libraries that must be fixed up, but +# that cannot be determined by otool output analysis. (i.e., plugins) +# +# Gather all the keys for all the executables and libraries in a bundle, +# and then, for each key, copy each prerequisite into the bundle. Then +# fix each one up according to its own list of prerequisites. +# +# Then clear all the keys and call verify_app on the final bundle to +# ensure that it is truly standalone. +# +# :: +# +# COPY_AND_FIXUP_BUNDLE( ) +# +# Makes a copy of the bundle at location and then fixes up +# the new copied bundle in-place at ... +# +# :: +# +# VERIFY_APP() +# +# Verifies that an application appears valid based on running +# analysis tools on it. Calls "message(FATAL_ERROR" if the application +# is not verified. +# +# :: +# +# GET_BUNDLE_MAIN_EXECUTABLE( ) +# +# The result will be the full path name of the bundle's main executable +# file or an "error:" prefixed string if it could not be determined. +# +# :: +# +# GET_DOTAPP_DIR( ) +# +# Returns the nearest parent dir whose name ends with ".app" given the +# full path to an executable. If there is no such parent dir, then +# simply return the dir containing the executable. +# +# The returned directory may or may not exist. +# +# :: +# +# GET_BUNDLE_AND_EXECUTABLE( ) +# +# Takes either a ".app" directory name or the name of an executable +# nested inside a ".app" directory and returns the path to the ".app" +# directory in and the path to its main executable in +# +# +# :: +# +# GET_BUNDLE_ALL_EXECUTABLES( ) +# +# Scans the given bundle recursively for all executable files and +# accumulates them into a variable. +# +# :: +# +# GET_ITEM_KEY( ) +# +# Given a file (item) name, generate a key that should be unique +# considering the set of libraries that need copying or fixing up to +# make a bundle standalone. This is essentially the file name including +# extension with "." replaced by "_" +# +# This key is used as a prefix for CMake variables so that we can +# associate a set of variables with a given item based on its key. +# +# :: +# +# CLEAR_BUNDLE_KEYS() +# +# Loop over the list of keys, clearing all the variables associated with +# each key. After the loop, clear the list of keys itself. +# +# Caller of get_bundle_keys should call clear_bundle_keys when done with +# list of keys. +# +# :: +# +# SET_BUNDLE_KEY_VALUES( +# ) +# +# Add a key to the list (if necessary) for the given item. If added, +# also set all the variables associated with that key. +# +# :: +# +# GET_BUNDLE_KEYS( ) +# +# Loop over all the executable and library files within the bundle (and +# given as extra ) and accumulate a list of keys representing +# them. Set values associated with each key such that we can loop over +# all of them and copy prerequisite libs into the bundle and then do +# appropriate install_name_tool fixups. +# +# :: +# +# COPY_RESOLVED_ITEM_INTO_BUNDLE( ) +# +# Copy a resolved item into the bundle if necessary. Copy is not +# necessary if the resolved_item is "the same as" the +# resolved_embedded_item. +# +# :: +# +# COPY_RESOLVED_FRAMEWORK_INTO_BUNDLE( ) +# +# Copy a resolved framework into the bundle if necessary. Copy is not +# necessary if the resolved_item is "the same as" the +# resolved_embedded_item. +# +# By default, BU_COPY_FULL_FRAMEWORK_CONTENTS is not set. If you want +# full frameworks embedded in your bundles, set +# BU_COPY_FULL_FRAMEWORK_CONTENTS to ON before calling fixup_bundle. By +# default, COPY_RESOLVED_FRAMEWORK_INTO_BUNDLE copies the framework +# dylib itself plus the framework Resources directory. +# +# :: +# +# IS_RESOLVED_ITEM_EMBEDDED( ) +# +# Set variable to True if the resolved item is +# embedded into the bundle. The function does NOT check for the existence of the +# item, instead if checks if the provided path would correspond to an embeddable +# item. If is True, extra information will be displayed in case the item +# is not embedded. +# +# :: +# +# FIXUP_BUNDLE_ITEM( ) +# +# Get the direct/non-system prerequisites of the resolved embedded item. +# For each prerequisite, change the way it is referenced to the value of +# the _EMBEDDED_ITEM keyed variable for that prerequisite. (Most likely +# changing to an "@executable_path" style reference.) +# +# This function requires that the resolved_embedded_item be "inside" the +# bundle already. In other words, if you pass plugins to fixup_bundle +# as the libs parameter, you should install them or copy them into the +# bundle before calling fixup_bundle. The "libs" parameter is a list of +# libraries that must be fixed up, but that cannot be determined by +# otool output analysis. (i.e., plugins) +# +# Also, change the id of the item being fixed up to its own +# _EMBEDDED_ITEM value. +# +# Accumulate changes in a local variable and make *one* call to +# install_name_tool at the end of the function with all the changes at +# once. +# +# If the BU_CHMOD_BUNDLE_ITEMS variable is set then bundle items will be +# marked writable before install_name_tool tries to change them. +# +# :: +# +# VERIFY_BUNDLE_PREREQUISITES( ) +# +# Verifies that the sum of all prerequisites of all files inside the +# bundle are contained within the bundle or are "system" libraries, +# presumed to exist everywhere. +# +# :: +# +# VERIFY_BUNDLE_SYMLINKS( ) +# +# Verifies that any symlinks found in the bundle point to other files +# that are already also in the bundle... Anything that points to an +# external file causes this function to fail the verification. + +#============================================================================= +# Copyright 2008-2009 Kitware, Inc. +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + +# Copyright (c) 2015 BWH and 3D Slicer contributors, http://slicer.org +# +# Redistribution AND use is allowed according to the terms of the +# BSD-style license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + +# The functions defined in this file depend on the get_prerequisites function +# (and possibly others) found in: +# +get_filename_component(BundleUtilities_cmake_dir "${CMAKE_CURRENT_LIST_FILE}" PATH) +include("${BundleUtilities_cmake_dir}/GetPrerequisitesWithRPath.cmake") + + +function(get_bundle_main_executable bundle result_var) + set(result "error: '${bundle}/Contents/Info.plist' file does not exist") + + if(EXISTS "${bundle}/Contents/Info.plist") + set(result "error: no CFBundleExecutable in '${bundle}/Contents/Info.plist' file") + set(line_is_main_executable 0) + set(bundle_executable "") + + # Read Info.plist as a list of lines: + # + set(eol_char "E") + file(READ "${bundle}/Contents/Info.plist" info_plist) + string(REPLACE ";" "\\;" info_plist "${info_plist}") + string(REPLACE "\n" "${eol_char};" info_plist "${info_plist}") + string(REPLACE "\r" "${eol_char};" info_plist "${info_plist}") + + # Scan the lines for "CFBundleExecutable" - the line after that + # is the name of the main executable. + # + foreach(line ${info_plist}) + if(line_is_main_executable) + string(REGEX REPLACE "^.*(.*).*$" "\\1" bundle_executable "${line}") + break() + endif() + + if(line MATCHES "CFBundleExecutable") + set(line_is_main_executable 1) + endif() + endforeach() + + if(NOT "${bundle_executable}" STREQUAL "") + if(EXISTS "${bundle}/Contents/MacOS/${bundle_executable}") + set(result "${bundle}/Contents/MacOS/${bundle_executable}") + else() + + # Ultimate goal: + # If not in "Contents/MacOS" then scan the bundle for matching files. If + # there is only one executable file that matches, then use it, otherwise + # it's an error... + # + #file(GLOB_RECURSE file_list "${bundle}/${bundle_executable}") + + # But for now, pragmatically, it's an error. Expect the main executable + # for the bundle to be in Contents/MacOS, it's an error if it's not: + # + set(result "error: '${bundle}/Contents/MacOS/${bundle_executable}' does not exist") + endif() + endif() + else() + # + # More inclusive technique... (This one would work on Windows and Linux + # too, if a developer followed the typical Mac bundle naming convention...) + # + # If there is no Info.plist file, try to find an executable with the same + # base name as the .app directory: + # + endif() + + set(${result_var} "${result}" PARENT_SCOPE) +endfunction() + + +function(get_dotapp_dir exe dotapp_dir_var) + set(s "${exe}") + + if(s MATCHES "/.*\\.app/") + # If there is a ".app" parent directory, + # ascend until we hit it: + # (typical of a Mac bundle executable) + # + set(done 0) + while(NOT ${done}) + get_filename_component(snamewe "${s}" NAME_WE) + get_filename_component(sname "${s}" NAME) + get_filename_component(sdir "${s}" PATH) + set(s "${sdir}") + if(sname MATCHES "\\.app$") + set(done 1) + set(dotapp_dir "${sdir}/${sname}") + endif() + endwhile() + else() + # Otherwise use a directory containing the exe + # (typical of a non-bundle executable on Mac, Windows or Linux) + # + is_file_executable("${s}" is_executable) + if(is_executable) + get_filename_component(sdir "${s}" PATH) + set(dotapp_dir "${sdir}") + else() + set(dotapp_dir "${s}") + endif() + endif() + + + set(${dotapp_dir_var} "${dotapp_dir}" PARENT_SCOPE) +endfunction() + + +function(get_bundle_and_executable app bundle_var executable_var valid_var) + set(valid 0) + + if(EXISTS "${app}") + # Is it a directory ending in .app? + if(IS_DIRECTORY "${app}") + if(app MATCHES "\\.app$") + get_bundle_main_executable("${app}" executable) + if(EXISTS "${app}" AND EXISTS "${executable}") + set(${bundle_var} "${app}" PARENT_SCOPE) + set(${executable_var} "${executable}" PARENT_SCOPE) + set(valid 1) + #message(STATUS "info: handled .app directory case...") + else() + message(STATUS "warning: *NOT* handled - .app directory case...") + endif() + else() + message(STATUS "warning: *NOT* handled - directory but not .app case...") + endif() + else() + # Is it an executable file? + is_file_executable("${app}" is_executable) + if(is_executable) + get_dotapp_dir("${app}" dotapp_dir) + if(EXISTS "${dotapp_dir}") + set(${bundle_var} "${dotapp_dir}" PARENT_SCOPE) + set(${executable_var} "${app}" PARENT_SCOPE) + set(valid 1) + #message(STATUS "info: handled executable file in .app dir case...") + else() + get_filename_component(app_dir "${app}" PATH) + set(${bundle_var} "${app_dir}" PARENT_SCOPE) + set(${executable_var} "${app}" PARENT_SCOPE) + set(valid 1) + #message(STATUS "info: handled executable file in any dir case...") + endif() + else() + message(STATUS "warning: *NOT* handled - not .app dir, not executable file...") + endif() + endif() + else() + message(STATUS "warning: *NOT* handled - directory/file does not exist...") + endif() + + if(NOT valid) + set(${bundle_var} "error: not a bundle" PARENT_SCOPE) + set(${executable_var} "error: not a bundle" PARENT_SCOPE) + endif() + + set(${valid_var} ${valid} PARENT_SCOPE) +endfunction() + + +function(get_bundle_all_executables bundle exes_var) + set(exes "") + + file(GLOB_RECURSE file_list "${bundle}/*") + if(UNIX) + find_program(find_cmd "find") + mark_as_advanced(find_cmd) + endif() + + # find command is much quicker than checking every file one by one on Unix + # which can take long time for large bundles, and since anyway we expect + # executable to have execute flag set we can narrow the list much quicker. + if(find_cmd) + execute_process(COMMAND "${find_cmd}" "${bundle}" + -type f \( -perm -0100 -o -perm -0010 -o -perm -0001 \) + OUTPUT_VARIABLE file_list + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + string(REPLACE "\n" ";" file_list "${file_list}") + else() + file(GLOB_RECURSE file_list "${bundle}/*") + endif() + + foreach(f ${file_list}) + is_file_executable("${f}" is_executable) + if(is_executable) + set(exes ${exes} "${f}") + endif() + endforeach() + + set(${exes_var} "${exes}" PARENT_SCOPE) +endfunction() + + +function(get_item_key item key_var) + get_filename_component(item_name "${item}" NAME) + if(WIN32) + string(TOLOWER "${item_name}" item_name) + endif() + string(REPLACE "." "_" ${key_var} "${item_name}") + set(${key_var} ${${key_var}} PARENT_SCOPE) +endfunction() + + +function(clear_bundle_keys keys_var) + foreach(key ${${keys_var}}) + set(${key}_ITEM PARENT_SCOPE) + set(${key}_RESOLVED_ITEM PARENT_SCOPE) + set(${key}_DEFAULT_EMBEDDED_PATH PARENT_SCOPE) + set(${key}_EMBEDDED_ITEM PARENT_SCOPE) + set(${key}_RESOLVED_EMBEDDED_ITEM PARENT_SCOPE) + set(${key}_COPYFLAG PARENT_SCOPE) + endforeach() + set(${keys_var} PARENT_SCOPE) +endfunction() + + +function(set_bundle_key_values keys_var context item exepath dirs copyflag) + get_filename_component(item_name "${item}" NAME) + + get_item_key("${item}" key) + + list(LENGTH ${keys_var} length_before) + gp_append_unique(${keys_var} "${key}") + list(LENGTH ${keys_var} length_after) + + if(NOT length_before EQUAL length_after) + gp_resolve_item("${context}" "${item}" "${exepath}" "${dirs}" resolved_item) + + gp_item_default_embedded_path("${item}" default_embedded_path) + + if(item MATCHES "[^/]+\\.framework/") + # For frameworks, construct the name under the embedded path from the + # opening "${item_name}.framework/" to the closing "/${item_name}": + # + string(REGEX REPLACE "^.*(${item_name}.framework/.*/?${item_name}).*$" "${default_embedded_path}/\\1" embedded_item "${item}") + else() + # For other items, just use the same name as the original, but in the + # embedded path: + # + set(embedded_item "${default_embedded_path}/${item_name}") + + if(APPLE) + # For executables inside the bundle, extract the expected path. + # This remove the hack introduced in commit 6f8bdd27 consisting in + # reseting the value of 'resolved_embedded_item' with 'resolved_item'. + get_dotapp_dir("${exepath}" exe_dotapp_dir) + if(NOT DEFINED gp_bundle_executables) + get_bundle_all_executables("${exe_dotapp_dir}" gp_bundle_executables) + endif() + foreach(exe ${gp_bundle_executables}) + get_item_key("${exe}" exe_key) + list(APPEND exe_keys ${exe_key}) + endforeach() + list(FIND exe_keys ${key} is_executable) + if(NOT is_executable EQUAL "-1") + get_filename_component(resolved_item_path ${resolved_item} PATH) + file(RELATIVE_PATH exe_relative_path_from_dir ${exe_dotapp_dir} ${resolved_item_path}) + # For example, if input variables are: + # resolved_item: /path/to/MyApp.app/Contents/bin/myapp + # exe_dotapp_dir: /path/to/MyApp.app + # Computed variables will be: + # resolved_item_path: /path/to/MyApp.app/Contents/bin + # exe_relative_path_from_dir: Contents/bin + set(embedded_item "@executable_path/../../${exe_relative_path_from_dir}/${item_name}") + set(show_status 0) + if(show_status) + message(STATUS "resolved_item='${resolved_item}'") + message(STATUS "exe_dotapp_dir='${exe_dotapp_dir}'") + message(STATUS "exe_relative_path_from_dir='${exe_relative_path_from_dir}'") + message(STATUS "item_name='${item_name}'") + message(STATUS "embedded_item='${embedded_item}'") + message(STATUS "") + endif() + endif() + endif() + endif() + + gp_resolve_embedded_item("${context}" "${embedded_item}" "${exepath}" resolved_embedded_item) + get_filename_component(resolved_embedded_item "${resolved_embedded_item}" ABSOLUTE) + + # Do not copy already embedded item + set(verbose 0) + is_resolved_item_embedded("${resolved_embedded_item}" "${exepath}" "${verbose}" is_embedded) + if(EXISTS "${resolved_embedded_item}" AND is_embedded) + set(copyflag 0) + set(resolved_item "${resolved_embedded_item}") + endif() + + set(${keys_var} ${${keys_var}} PARENT_SCOPE) + set(${key}_ITEM "${item}" PARENT_SCOPE) + set(${key}_RESOLVED_ITEM "${resolved_item}" PARENT_SCOPE) + set(${key}_DEFAULT_EMBEDDED_PATH "${default_embedded_path}" PARENT_SCOPE) + set(${key}_EMBEDDED_ITEM "${embedded_item}" PARENT_SCOPE) + set(${key}_RESOLVED_EMBEDDED_ITEM "${resolved_embedded_item}" PARENT_SCOPE) + set(${key}_COPYFLAG "${copyflag}" PARENT_SCOPE) + else() + #message("warning: item key '${key}' already in the list, subsequent references assumed identical to first") + endif() +endfunction() + + +function(get_bundle_keys app libs dirs keys_var) + set(${keys_var} PARENT_SCOPE) + + get_bundle_and_executable("${app}" bundle executable valid) + if(valid) + # Always use the exepath of the main bundle executable for @executable_path + # replacements: + # + get_filename_component(exepath "${executable}" PATH) + + # But do fixups on all executables in the bundle: + # + get_bundle_all_executables("${bundle}" gp_bundle_executables) + + # For each extra lib, accumulate a key as well and then also accumulate + # any of its prerequisites. (Extra libs are typically dynamically loaded + # plugins: libraries that are prerequisites for full runtime functionality + # but that do not show up in otool -L output...) + # + foreach(lib ${libs}) + set_bundle_key_values(${keys_var} "${lib}" "${lib}" "${exepath}" "${dirs}" 0) + + set(prereqs "") + get_prerequisites("${lib}" prereqs 1 1 "${exepath}" "${dirs}") + foreach(pr ${prereqs}) + set_bundle_key_values(${keys_var} "${lib}" "${pr}" "${exepath}" "${dirs}" 1) + endforeach() + endforeach() + + # For each executable found in the bundle, accumulate keys as we go. + # The list of keys should be complete when all prerequisites of all + # binaries in the bundle have been analyzed. + # + foreach(exe ${gp_bundle_executables}) + # Add the exe itself to the keys: + # + set_bundle_key_values(${keys_var} "${exe}" "${exe}" "${exepath}" "${dirs}" 0) + + # Add each prerequisite to the keys: + # + set(prereqs "") + get_prerequisites("${exe}" prereqs 1 1 "${exepath}" "${dirs}") + foreach(pr ${prereqs}) + set_bundle_key_values(${keys_var} "${exe}" "${pr}" "${exepath}" "${dirs}" 1) + endforeach() + endforeach() + + # Propagate values to caller's scope: + # + set(${keys_var} ${${keys_var}} PARENT_SCOPE) + foreach(key ${${keys_var}}) + set(${key}_ITEM "${${key}_ITEM}" PARENT_SCOPE) + set(${key}_RESOLVED_ITEM "${${key}_RESOLVED_ITEM}" PARENT_SCOPE) + set(${key}_DEFAULT_EMBEDDED_PATH "${${key}_DEFAULT_EMBEDDED_PATH}" PARENT_SCOPE) + set(${key}_EMBEDDED_ITEM "${${key}_EMBEDDED_ITEM}" PARENT_SCOPE) + set(${key}_RESOLVED_EMBEDDED_ITEM "${${key}_RESOLVED_EMBEDDED_ITEM}" PARENT_SCOPE) + set(${key}_COPYFLAG "${${key}_COPYFLAG}" PARENT_SCOPE) + endforeach() + endif() +endfunction() + + +function(copy_resolved_item_into_bundle resolved_item resolved_embedded_item) + if(WIN32) + # ignore case on Windows + string(TOLOWER "${resolved_item}" resolved_item_compare) + string(TOLOWER "${resolved_embedded_item}" resolved_embedded_item_compare) + else() + set(resolved_item_compare "${resolved_item}") + set(resolved_embedded_item_compare "${resolved_embedded_item}") + endif() + + if("${resolved_item_compare}" STREQUAL "${resolved_embedded_item_compare}") + message(STATUS "warning: resolved_item == resolved_embedded_item - not copying...") + else() + #message(STATUS "copying COMMAND ${CMAKE_COMMAND} -E copy ${resolved_item} ${resolved_embedded_item}") + execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${resolved_item}" "${resolved_embedded_item}") + if(UNIX AND NOT APPLE) + file(RPATH_REMOVE FILE "${resolved_embedded_item}") + endif() + endif() + +endfunction() + + +function(copy_resolved_framework_into_bundle resolved_item resolved_embedded_item) + if(WIN32) + # ignore case on Windows + string(TOLOWER "${resolved_item}" resolved_item_compare) + string(TOLOWER "${resolved_embedded_item}" resolved_embedded_item_compare) + else() + set(resolved_item_compare "${resolved_item}") + set(resolved_embedded_item_compare "${resolved_embedded_item}") + endif() + + if("${resolved_item_compare}" STREQUAL "${resolved_embedded_item_compare}") + message(STATUS "warning: resolved_item == resolved_embedded_item - not copying...") + else() + if(BU_COPY_FULL_FRAMEWORK_CONTENTS) + # Full Framework (everything): + get_filename_component(resolved_dir "${resolved_item}" PATH) + get_filename_component(resolved_dir "${resolved_dir}/../.." ABSOLUTE) + get_filename_component(resolved_embedded_dir "${resolved_embedded_item}" PATH) + get_filename_component(resolved_embedded_dir "${resolved_embedded_dir}/../.." ABSOLUTE) + #message(STATUS "copying COMMAND ${CMAKE_COMMAND} -E copy_directory '${resolved_dir}' '${resolved_embedded_dir}'") + execute_process(COMMAND ${CMAKE_COMMAND} -E copy_directory "${resolved_dir}" "${resolved_embedded_dir}") + else() + # Framework lib itself: + #message(STATUS "copying COMMAND ${CMAKE_COMMAND} -E copy ${resolved_item} ${resolved_embedded_item}") + execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${resolved_item}" "${resolved_embedded_item}") + + # Plus Resources, if they exist: + string(REGEX REPLACE "^(.*)/[^/]+$" "\\1/Resources" resolved_resources "${resolved_item}") + string(REGEX REPLACE "^(.*)/[^/]+$" "\\1/Resources" resolved_embedded_resources "${resolved_embedded_item}") + if(EXISTS "${resolved_resources}") + #message(STATUS "copying COMMAND ${CMAKE_COMMAND} -E copy_directory '${resolved_resources}' '${resolved_embedded_resources}'") + execute_process(COMMAND ${CMAKE_COMMAND} -E copy_directory "${resolved_resources}" "${resolved_embedded_resources}") + endif() + + # Some frameworks e.g. Qt put Info.plist in wrong place, so when it is + # missing in resources, copy it from other well known incorrect locations: + if(NOT EXISTS "${resolved_resources}/Info.plist") + # Check for Contents/Info.plist in framework root (older Qt SDK): + string(REGEX REPLACE "^(.*)/[^/]+/[^/]+/[^/]+$" "\\1/Contents/Info.plist" resolved_info_plist "${resolved_item}") + string(REGEX REPLACE "^(.*)/[^/]+$" "\\1/Resources/Info.plist" resolved_embedded_info_plist "${resolved_embedded_item}") + if(EXISTS "${resolved_info_plist}") + #message(STATUS "copying COMMAND ${CMAKE_COMMAND} -E copy_directory '${resolved_info_plist}' '${resolved_embedded_info_plist}'") + execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${resolved_info_plist}" "${resolved_embedded_info_plist}") + endif() + endif() + + # Check if framework is versioned and fix it layout + string(REGEX REPLACE "^.*/([^/]+)/[^/]+$" "\\1" resolved_embedded_version "${resolved_embedded_item}") + string(REGEX REPLACE "^(.*)/[^/]+/[^/]+$" "\\1" resolved_embedded_versions "${resolved_embedded_item}") + string(REGEX REPLACE "^.*/([^/]+)/[^/]+/[^/]+$" "\\1" resolved_embedded_versions_basename "${resolved_embedded_item}") + if(resolved_embedded_versions_basename STREQUAL "Versions") + # Ensure Current symlink points to the framework version + if(NOT EXISTS "${resolved_embedded_versions}/Current") + execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink "${resolved_embedded_version}" "${resolved_embedded_versions}/Current") + endif() + # Restore symlinks in framework root pointing to current framework + # binary and resources: + string(REGEX REPLACE "^(.*)/[^/]+/[^/]+/[^/]+$" "\\1" resolved_embedded_root "${resolved_embedded_item}") + string(REGEX REPLACE "^.*/([^/]+)$" "\\1" resolved_embedded_item_basename "${resolved_embedded_item}") + if(NOT EXISTS "${resolved_embedded_root}/${resolved_embedded_item_basename}") + execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink "Versions/Current/${resolved_embedded_item_basename}" "${resolved_embedded_root}/${resolved_embedded_item_basename}") + endif() + if(NOT EXISTS "${resolved_embedded_root}/Resources") + execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink "Versions/Current/Resources" "${resolved_embedded_root}/Resources") + endif() + endif() + endif() + if(UNIX AND NOT APPLE) + file(RPATH_REMOVE FILE "${resolved_embedded_item}") + endif() + endif() + +endfunction() + +function(is_resolved_item_embedded resolved_item exepath verbose is_embedded_var) + get_dotapp_dir("${exepath}" exe_dotapp_dir) + string(LENGTH "${exe_dotapp_dir}/" exe_dotapp_dir_length) + string(LENGTH "${resolved_item}" resolved_item_length) + set(path_too_short 0) + set(is_embedded 0) + if(${resolved_item_length} LESS ${exe_dotapp_dir_length}) + set(path_too_short 1) + endif() + if(NOT path_too_short) + string(SUBSTRING "${resolved_item}" 0 ${exe_dotapp_dir_length} item_substring) + if("${exe_dotapp_dir}/" STREQUAL "${item_substring}") + set(is_embedded 1) + endif() + endif() + if(verbose AND NOT is_embedded) + message(" exe_dotapp_dir/='${exe_dotapp_dir}/'") + message(" item_substring='${item_substring}'") + message(" resolved_item='${resolved_item}'") + message("") + endif() + set(${is_embedded_var} ${is_embedded} PARENT_SCOPE) +endfunction() + +function(fixup_bundle_item resolved_embedded_item exepath dirs) + # This item's key is "ikey": + # + get_item_key("${resolved_embedded_item}" ikey) + + # Ensure the item is "inside the .app bundle" -- it should not be fixed up if + # it is not in the .app bundle... Otherwise, we'll modify files in the build + # tree, or in other varied locations around the file system, with our call to + # install_name_tool. Make sure that doesn't happen here: + # + set(verbose 1) + is_resolved_item_embedded("${resolved_embedded_item}" "${exepath}" "${verbose}" is_embedded) + if(NOT is_embedded) + message("Install or copy the item into the bundle before calling fixup_bundle.") + message("Or maybe there's a typo or incorrect path in one of the args to fixup_bundle?") + message("") + message(FATAL_ERROR "cannot fixup an item that is not in the bundle...") + endif() + + set(prereqs "") + get_prerequisites("${resolved_embedded_item}" prereqs 1 0 "${exepath}" "${dirs}") + + set(changes "") + + foreach(pr ${prereqs}) + # Each referenced item's key is "rkey" in the loop: + # + get_item_key("${pr}" rkey) + + if(NOT "${${rkey}_EMBEDDED_ITEM}" STREQUAL "") + set(changes ${changes} "-change" "${pr}" "${${rkey}_EMBEDDED_ITEM}") + else() + message("warning: unexpected reference to '${pr}'") + endif() + endforeach() + + if(BU_CHMOD_BUNDLE_ITEMS) + execute_process(COMMAND chmod u+w "${resolved_embedded_item}") + endif() + + # Change this item's id and all of its references in one call + # to install_name_tool: + # + execute_process(COMMAND install_name_tool + ${changes} -id "${${ikey}_EMBEDDED_ITEM}" "${resolved_embedded_item}" + ) +endfunction() + + +function(fixup_bundle app libs dirs) + message(STATUS "fixup_bundle") + message(STATUS " app='${app}'") + message(STATUS " libs='${libs}'") + message(STATUS " dirs='${dirs}'") + + get_bundle_and_executable("${app}" bundle executable valid) + message(STATUS " bundle='${bundle}'") + message(STATUS " executable='${executable}'") + if(valid) + get_filename_component(exepath "${executable}" PATH) + + # TODO: Extract list of rpath dirs automatically. On MacOSX, the following could be + # done: otool -l path/to/executable | grep -A 3 LC_RPATH | grep path + # See http://www.mikeash.com/pyblog/friday-qa-2009-11-06-linking-and-install-names.html#comment-87ea054b4839586412727dcfc94c79d2 + set(GP_RPATH_DIR ${bundle}/Contents) + message(STATUS " GP_RPATH_DIR='${GP_RPATH_DIR}'") + + message(STATUS "fixup_bundle: preparing...") + get_bundle_keys("${app}" "${libs}" "${dirs}" keys) + + message(STATUS "fixup_bundle: copying...") + list(LENGTH keys n) + math(EXPR n ${n}*2) + + set(i 0) + foreach(key ${keys}) + math(EXPR i ${i}+1) + if(${${key}_COPYFLAG}) + message(STATUS "${i}/${n}: copying '${${key}_RESOLVED_ITEM}'") + else() + message(STATUS "${i}/${n}: *NOT* copying '${${key}_RESOLVED_ITEM}'") + endif() + + set(show_status 0) + if(show_status) + message(STATUS "key='${key}'") + message(STATUS "item='${${key}_ITEM}'") + message(STATUS "resolved_item='${${key}_RESOLVED_ITEM}'") + message(STATUS "default_embedded_path='${${key}_DEFAULT_EMBEDDED_PATH}'") + message(STATUS "embedded_item='${${key}_EMBEDDED_ITEM}'") + message(STATUS "resolved_embedded_item='${${key}_RESOLVED_EMBEDDED_ITEM}'") + message(STATUS "copyflag='${${key}_COPYFLAG}'") + message(STATUS "") + endif() + + if(${${key}_COPYFLAG}) + set(item "${${key}_ITEM}") + if(item MATCHES "[^/]+\\.framework/") + copy_resolved_framework_into_bundle("${${key}_RESOLVED_ITEM}" + "${${key}_RESOLVED_EMBEDDED_ITEM}") + else() + copy_resolved_item_into_bundle("${${key}_RESOLVED_ITEM}" + "${${key}_RESOLVED_EMBEDDED_ITEM}") + endif() + endif() + endforeach() + + message(STATUS "fixup_bundle: fixing...") + foreach(key ${keys}) + math(EXPR i ${i}+1) + if(APPLE) + message(STATUS "${i}/${n}: fixing up '${${key}_RESOLVED_EMBEDDED_ITEM}'") + fixup_bundle_item("${${key}_RESOLVED_EMBEDDED_ITEM}" "${exepath}" "${dirs}") + else() + message(STATUS "${i}/${n}: fix-up not required on this platform '${${key}_RESOLVED_EMBEDDED_ITEM}'") + endif() + endforeach() + + message(STATUS "fixup_bundle: cleaning up...") + clear_bundle_keys(keys) + + message(STATUS "fixup_bundle: verifying...") + verify_app("${app}") + else() + message(SEND_ERROR "error: fixup_bundle: not a valid bundle") + endif() + + message(STATUS "fixup_bundle: done") +endfunction() + + +function(copy_and_fixup_bundle src dst libs dirs) + execute_process(COMMAND ${CMAKE_COMMAND} -E copy_directory "${src}" "${dst}") + fixup_bundle("${dst}" "${libs}" "${dirs}") +endfunction() + + +function(verify_bundle_prerequisites bundle result_var info_var) + set(result 1) + set(info "") + set(count 0) + + get_bundle_main_executable("${bundle}" main_bundle_exe) + + file(GLOB_RECURSE file_list "${bundle}/*") + foreach(f ${file_list}) + is_file_executable("${f}" is_executable) + if(is_executable) + get_filename_component(exepath "${f}" PATH) + math(EXPR count "${count} + 1") + + message(STATUS "executable file ${count}: ${f}") + + set(prereqs "") + get_prerequisites("${f}" prereqs 1 1 "${exepath}" "") + + # On the Mac, + # "embedded" and "system" prerequisites are fine... anything else means + # the bundle's prerequisites are not verified (i.e., the bundle is not + # really "standalone") + # + # On Windows (and others? Linux/Unix/...?) + # "local" and "system" prereqs are fine... + # + set(external_prereqs "") + + foreach(p ${prereqs}) + set(p_type "") + gp_file_type("${f}" "${p}" p_type) + + if(APPLE) + if(NOT "${p_type}" STREQUAL "embedded" AND NOT "${p_type}" STREQUAL "system") + set(external_prereqs ${external_prereqs} "${p}") + endif() + else() + if(NOT "${p_type}" STREQUAL "local" AND NOT "${p_type}" STREQUAL "system") + set(external_prereqs ${external_prereqs} "${p}") + endif() + endif() + endforeach() + + if(external_prereqs) + # Found non-system/somehow-unacceptable prerequisites: + set(result 0) + set(info ${info} "external prerequisites found:\nf='${f}'\nexternal_prereqs='${external_prereqs}'\n") + endif() + endif() + endforeach() + + if(result) + set(info "Verified ${count} executable files in '${bundle}'") + endif() + + set(${result_var} "${result}" PARENT_SCOPE) + set(${info_var} "${info}" PARENT_SCOPE) +endfunction() + + +function(verify_bundle_symlinks bundle result_var info_var) + set(result 1) + set(info "") + set(count 0) + + # TODO: implement this function for real... + # Right now, it is just a stub that verifies unconditionally... + + set(${result_var} "${result}" PARENT_SCOPE) + set(${info_var} "${info}" PARENT_SCOPE) +endfunction() + + +function(verify_app app) + set(verified 0) + set(info "") + + get_bundle_and_executable("${app}" bundle executable valid) + + message(STATUS "===========================================================================") + message(STATUS "Analyzing app='${app}'") + message(STATUS "bundle='${bundle}'") + message(STATUS "executable='${executable}'") + message(STATUS "valid='${valid}'") + + # Verify that the bundle does not have any "external" prerequisites: + # + verify_bundle_prerequisites("${bundle}" verified info) + message(STATUS "verified='${verified}'") + message(STATUS "info='${info}'") + message(STATUS "") + + if(verified) + # Verify that the bundle does not have any symlinks to external files: + # + verify_bundle_symlinks("${bundle}" verified info) + message(STATUS "verified='${verified}'") + message(STATUS "info='${info}'") + message(STATUS "") + endif() + + if(NOT verified) + message(FATAL_ERROR "error: verify_app failed") + endif() +endfunction() diff --git a/cmake/COPYING-CMAKE-SCRIPTS b/cmake/COPYING-CMAKE-SCRIPTS index d33c6f33b..21f1dbf7d 100644 --- a/cmake/COPYING-CMAKE-SCRIPTS +++ b/cmake/COPYING-CMAKE-SCRIPTS @@ -25,3 +25,269 @@ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +The following files are derived from the Slicer project +(https://github.com/Slicer/Slicer), which in turn derived from CMake project (http://cmake.org) and are covered under the licenses below. + +BundleUtilitiesWithRPath.cmake, GetPrerequisitesWithRPath.cmake + +# Slicer + +For more information, please see: + + http://www.slicer.org + +The 3D Slicer license below is a BSD style license, with extensions +to cover contributions and other issues specific to 3D Slicer. + + +3D Slicer Contribution and Software License Agreement ("Agreement") +Version 1.0 (December 20, 2005) + +This Agreement covers contributions to and downloads from the 3D +Slicer project ("Slicer") maintained by The Brigham and Women's +Hospital, Inc. ("Brigham"). Part A of this Agreement applies to +contributions of software and/or data to Slicer (including making +revisions of or additions to code and/or data already in Slicer). Part +B of this Agreement applies to downloads of software and/or data from +Slicer. Part C of this Agreement applies to all transactions with +Slicer. If you distribute Software (as defined below) downloaded from +Slicer, all of the paragraphs of Part B of this Agreement must be +included with and apply to such Software. + +Your contribution of software and/or data to Slicer (including prior +to the date of the first publication of this Agreement, each a +"Contribution") and/or downloading, copying, modifying, displaying, +distributing or use of any software and/or data from Slicer +(collectively, the "Software") constitutes acceptance of all of the +terms and conditions of this Agreement. If you do not agree to such +terms and conditions, you have no right to contribute your +Contribution, or to download, copy, modify, display, distribute or use +the Software. + +PART A. CONTRIBUTION AGREEMENT - License to Brigham with Right to +Sublicense ("Contribution Agreement"). + +1. As used in this Contribution Agreement, "you" means the individual + contributing the Contribution to Slicer and the institution or + entity which employs or is otherwise affiliated with such + individual in connection with such Contribution. + +2. This Contribution Agreement applies to all Contributions made to + Slicer, including without limitation Contributions made prior to + the date of first publication of this Agreement. If at any time you + make a Contribution to Slicer, you represent that (i) you are + legally authorized and entitled to make such Contribution and to + grant all licenses granted in this Contribution Agreement with + respect to such Contribution; (ii) if your Contribution includes + any patient data, all such data is de-identified in accordance with + U.S. confidentiality and security laws and requirements, including + but not limited to the Health Insurance Portability and + Accountability Act (HIPAA) and its regulations, and your disclosure + of such data for the purposes contemplated by this Agreement is + properly authorized and in compliance with all applicable laws and + regulations; and (iii) you have preserved in the Contribution all + applicable attributions, copyright notices and licenses for any + third party software or data included in the Contribution. + +3. Except for the licenses granted in this Agreement, you reserve all + right, title and interest in your Contribution. + +4. You hereby grant to Brigham, with the right to sublicense, a + perpetual, worldwide, non-exclusive, no charge, royalty-free, + irrevocable license to use, reproduce, make derivative works of, + display and distribute the Contribution. If your Contribution is + protected by patent, you hereby grant to Brigham, with the right to + sublicense, a perpetual, worldwide, non-exclusive, no-charge, + royalty-free, irrevocable license under your interest in patent + rights covering the Contribution, to make, have made, use, sell and + otherwise transfer your Contribution, alone or in combination with + any other code. + +5. You acknowledge and agree that Brigham may incorporate your + Contribution into Slicer and may make Slicer available to members + of the public on an open source basis under terms substantially in + accordance with the Software License set forth in Part B of this + Agreement. You further acknowledge and agree that Brigham shall + have no liability arising in connection with claims resulting from + your breach of any of the terms of this Agreement. + +6. YOU WARRANT THAT TO THE BEST OF YOUR KNOWLEDGE YOUR CONTRIBUTION + DOES NOT CONTAIN ANY CODE THAT REQURES OR PRESCRIBES AN "OPEN + SOURCE LICENSE" FOR DERIVATIVE WORKS (by way of non-limiting + example, the GNU General Public License or other so-called + "reciprocal" license that requires any derived work to be licensed + under the GNU General Public License or other "open source + license"). + +PART B. DOWNLOADING AGREEMENT - License from Brigham with Right to +Sublicense ("Software License"). + +1. As used in this Software License, "you" means the individual + downloading and/or using, reproducing, modifying, displaying and/or + distributing the Software and the institution or entity which + employs or is otherwise affiliated with such individual in + connection therewith. The Brigham and Women?s Hospital, + Inc. ("Brigham") hereby grants you, with right to sublicense, with + respect to Brigham's rights in the software, and data, if any, + which is the subject of this Software License (collectively, the + "Software"), a royalty-free, non-exclusive license to use, + reproduce, make derivative works of, display and distribute the + Software, provided that: + +(a) you accept and adhere to all of the terms and conditions of this +Software License; + +(b) in connection with any copy of or sublicense of all or any portion +of the Software, all of the terms and conditions in this Software +License shall appear in and shall apply to such copy and such +sublicense, including without limitation all source and executable +forms and on any user documentation, prefaced with the following +words: "All or portions of this licensed product (such portions are +the "Software") have been obtained under license from The Brigham and +Women's Hospital, Inc. and are subject to the following terms and +conditions:" + +(c) you preserve and maintain all applicable attributions, copyright +notices and licenses included in or applicable to the Software; + +(d) modified versions of the Software must be clearly identified and +marked as such, and must not be misrepresented as being the original +Software; and + +(e) you consider making, but are under no obligation to make, the +source code of any of your modifications to the Software freely +available to others on an open source basis. + +2. The license granted in this Software License includes without + limitation the right to (i) incorporate the Software into + proprietary programs (subject to any restrictions applicable to + such programs), (ii) add your own copyright statement to your + modifications of the Software, and (iii) provide additional or + different license terms and conditions in your sublicenses of + modifications of the Software; provided that in each case your use, + reproduction or distribution of such modifications otherwise + complies with the conditions stated in this Software License. + +3. This Software License does not grant any rights with respect to + third party software, except those rights that Brigham has been + authorized by a third party to grant to you, and accordingly you + are solely responsible for (i) obtaining any permissions from third + parties that you need to use, reproduce, make derivative works of, + display and distribute the Software, and (ii) informing your + sublicensees, including without limitation your end-users, of their + obligations to secure any such required permissions. + +4. The Software has been designed for research purposes only and has + not been reviewed or approved by the Food and Drug Administration + or by any other agency. YOU ACKNOWLEDGE AND AGREE THAT CLINICAL + APPLICATIONS ARE NEITHER RECOMMENDED NOR ADVISED. Any + commercialization of the Software is at the sole risk of the party + or parties engaged in such commercialization. You further agree to + use, reproduce, make derivative works of, display and distribute + the Software in compliance with all applicable governmental laws, + regulations and orders, including without limitation those relating + to export and import control. + +5. The Software is provided "AS IS" and neither Brigham nor any + contributor to the software (each a "Contributor") shall have any + obligation to provide maintenance, support, updates, enhancements + or modifications thereto. BRIGHAM AND ALL CONTRIBUTORS SPECIFICALLY + DISCLAIM ALL EXPRESS AND IMPLIED WARRANTIES OF ANY KIND INCLUDING, + BUT NOT LIMITED TO, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR + A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + BRIGHAM OR ANY CONTRIBUTOR BE LIABLE TO ANY PARTY FOR DIRECT, + INDIRECT, SPECIAL, INCIDENTAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY ARISING IN ANY WAY + RELATED TO THE SOFTWARE, EVEN IF BRIGHAM OR ANY CONTRIBUTOR HAS + BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. TO THE MAXIMUM + EXTENT NOT PROHIBITED BY LAW OR REGULATION, YOU FURTHER ASSUME ALL + LIABILITY FOR YOUR USE, REPRODUCTION, MAKING OF DERIVATIVE WORKS, + DISPLAY, LICENSE OR DISTRIBUTION OF THE SOFTWARE AND AGREE TO + INDEMNIFY AND HOLD HARMLESS BRIGHAM AND ALL CONTRIBUTORS FROM AND + AGAINST ANY AND ALL CLAIMS, SUITS, ACTIONS, DEMANDS AND JUDGMENTS + ARISING THEREFROM. + +6. None of the names, logos or trademarks of Brigham or any of + Brigham's affiliates or any of the Contributors, or any funding + agency, may be used to endorse or promote products produced in + whole or in part by operation of the Software or derived from or + based on the Software without specific prior written permission + from the applicable party. + +7. Any use, reproduction or distribution of the Software which is not + in accordance with this Software License shall automatically revoke + all rights granted to you under this Software License and render + Paragraphs 1 and 2 of this Software License null and void. + +8. This Software License does not grant any rights in or to any + intellectual property owned by Brigham or any Contributor except + those rights expressly granted hereunder. + +PART C. MISCELLANEOUS + +This Agreement shall be governed by and construed in accordance with +the laws of The Commonwealth of Massachusetts without regard to +principles of conflicts of law. This Agreement shall supercede and +replace any license terms that you may have agreed to previously with +respect to Slicer. + +# CMake + +CMake - Cross Platform Makefile Generator +Copyright 2000-2015 Kitware, Inc. +Copyright 2000-2011 Insight Software Consortium +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +* Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +* Neither the names of Kitware, Inc., the Insight Software Consortium, + nor the names of their contributors may be used to endorse or promote + products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +------------------------------------------------------------------------------ + +The above copyright and license notice applies to distributions of +CMake in source and binary form. Some source files contain additional +notices of original copyright by their contributors; see each source +for details. Third-party software packages supplied with CMake under +compatible licenses provide their own copyright notices documented in +corresponding subdirectories. + +------------------------------------------------------------------------------ + +CMake was initially developed by Kitware with the following sponsorship: + + * National Library of Medicine at the National Institutes of Health + as part of the Insight Segmentation and Registration Toolkit (ITK). + + * US National Labs (Los Alamos, Livermore, Sandia) ASC Parallel + Visualization Initiative. + + * National Alliance for Medical Image Computing (NAMIC) is funded by the + National Institutes of Health through the NIH Roadmap for Medical Research, + Grant U54 EB005149. + + * Kitware, Inc. diff --git a/cmake/GetPrerequisitesWithRPath.cmake b/cmake/GetPrerequisitesWithRPath.cmake new file mode 100644 index 000000000..b57295b3d --- /dev/null +++ b/cmake/GetPrerequisitesWithRPath.cmake @@ -0,0 +1,990 @@ +# - Functions to analyze and list executable file prerequisites. +# This module provides functions to list the .dll, .dylib or .so +# files that an executable or shared library file depends on. (Its +# prerequisites.) +# +# It uses various tools to obtain the list of required shared library files: +# dumpbin (Windows) +# objdump (MinGW on Windows) +# ldd (Linux/Unix) +# otool (Mac OSX) +# The following functions are provided by this module: +# get_prerequisites +# list_prerequisites +# list_prerequisites_by_glob +# gp_append_unique +# is_file_executable +# gp_item_default_embedded_path +# (projects can override with gp_item_default_embedded_path_override) +# gp_resolve_item +# (projects can override with gp_resolve_item_override) +# gp_resolve_embedded_item +# (projects can override with gp_resolve_embedded_item_override) +# gp_resolved_file_type +# (projects can override with gp_resolved_file_type_override) +# gp_file_type +# Requires CMake 2.6 or greater because it uses function, break, return and +# PARENT_SCOPE. +# +# GET_PREREQUISITES( +# ) +# Get the list of shared library files required by . The list in +# the variable named should be empty on first entry to +# this function. On exit, will contain the list of +# required shared library files. +# +# is the full path to an executable file. is the +# name of a CMake variable to contain the results. must be 0 +# or 1 indicating whether to include or exclude "system" prerequisites. If +# is set to 1 all prerequisites will be found recursively, if set to +# 0 only direct prerequisites are listed. is the path to the top +# level executable used for @executable_path replacment on the Mac. is +# a list of paths where libraries might be found: these paths are searched +# first when a target without any path info is given. Then standard system +# locations are also searched: PATH, Framework locations, /usr/lib... +# +# LIST_PREREQUISITES( [ [ []]]) +# Print a message listing the prerequisites of . +# +# is the name of a shared library or executable target or the full +# path to a shared library or executable file. If is set to 1 all +# prerequisites will be found recursively, if set to 0 only direct +# prerequisites are listed. must be 0 or 1 indicating whether +# to include or exclude "system" prerequisites. With set to 0 only +# the full path names of the prerequisites are printed, set to 1 extra +# informatin will be displayed. +# +# LIST_PREREQUISITES_BY_GLOB( ) +# Print the prerequisites of shared library and executable files matching a +# globbing pattern. is GLOB or GLOB_RECURSE and is a +# globbing expression used with "file(GLOB" or "file(GLOB_RECURSE" to retrieve +# a list of matching files. If a matching file is executable, its prerequisites +# are listed. +# +# Any additional (optional) arguments provided are passed along as the +# optional arguments to the list_prerequisites calls. +# +# GP_APPEND_UNIQUE( ) +# Append to the list variable only if the value is not +# already in the list. +# +# IS_FILE_EXECUTABLE( ) +# Return 1 in if is a binary executable, 0 otherwise. +# +# GP_IS_FILE_EXECUTABLE_EXCLUDE_REGEX can be set to a regular expression used +# to give a hint to identify more quickly if a given file is an executable or not. +# This is particularly useful on unix platform where it can avoid a lot of +# time-consuming call to "file" external process. For packages bundling hundreds +# of libraries, executables, resources and data, it largely speeds up the function +# "get_bundle_all_executables". +# On unix, a convenient command line allowing to collect recursively all file extensions +# useful to generate a regular expression like "\\.(dylib|py|pyc|so)$" is: +# find . -type f -name '*.*' | sed 's@.*/.*\.@@' | sort | uniq | tr "\\n" "|" +# +# GP_ITEM_DEFAULT_EMBEDDED_PATH( ) +# Return the path that others should refer to the item by when the item +# is embedded inside a bundle. +# +# Override on a per-project basis by providing a project-specific +# gp_item_default_embedded_path_override function. +# +# GP_RESOLVE_ITEM( ) +# Resolve an item into an existing full path file. +# +# Override on a per-project basis by providing a project-specific +# gp_resolve_item_override function. +# +# GP_RESOLVE_EMBEDDED_ITEM( ) +# Resolve an embedded item into the full path within the full path. Since the item can be +# copied later, it doesn't have to exist when calling this function. +# +# Override on a per-project basis by providing a project-specific +# gp_resolve_embedded_item_override function. +# +# If GP_RPATH_DIR variable is set then item matching '@rpath' are +# resolved using the provided directory. Currently setting this variable +# has an effect only on MacOSX when fixing up application bundle. The directory +# are also assumed to be located within the application bundle. It is +# usually the directory passed to the 'rpath' linker option. +# +# GP_RESOLVED_FILE_TYPE( ) +# Return the type of with respect to . String +# describing type of prerequisite is returned in variable named . +# +# Use and if necessary to resolve non-absolute +# values -- but only for non-embedded items. +# +# Possible types are: +# system +# local +# embedded +# other +# Override on a per-project basis by providing a project-specific +# gp_resolved_file_type_override function. +# +# GP_FILE_TYPE( ) +# Return the type of with respect to . String +# describing type of prerequisite is returned in variable named . +# +# Possible types are: +# system +# local +# embedded +# other + +#============================================================================= +# Copyright 2008-2009 Kitware, Inc. +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + +# Copyright (c) 2015 BWH and 3D Slicer contributors, http://slicer.org +# +# Redistribution AND use is allowed according to the terms of the +# BSD-style license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + +function(gp_append_unique list_var value) + set(contains 0) + + foreach(item ${${list_var}}) + if("${item}" STREQUAL "${value}") + set(contains 1) + break() + endif() + endforeach() + + if(NOT contains) + set(${list_var} ${${list_var}} "${value}" PARENT_SCOPE) + endif() +endfunction() + + +function(is_file_executable file result_var) + # + # A file is not executable until proven otherwise: + # + set(${result_var} 0 PARENT_SCOPE) + + get_filename_component(file_full "${file}" ABSOLUTE) + string(TOLOWER "${file_full}" file_full_lower) + + # If file name ends in .exe on Windows, *assume* executable: + # + if(WIN32 AND NOT UNIX) + if("${file_full_lower}" MATCHES "\\.exe$") + set(${result_var} 1 PARENT_SCOPE) + return() + endif() + + # A clause could be added here that uses output or return value of dumpbin + # to determine ${result_var}. In 99%+? practical cases, the exe name + # match will be sufficient... + # + endif() + + # Use the information returned from the Unix shell command "file" to + # determine if ${file_full} should be considered an executable file... + # + # If the file command's output contains "executable" and does *not* contain + # "text" then it is likely an executable suitable for prerequisite analysis + # via the get_prerequisites macro. + # + if(UNIX) + + if(NOT "${GP_IS_FILE_EXECUTABLE_EXCLUDE_REGEX}" STREQUAL "") + if(${file_full} MATCHES "${GP_IS_FILE_EXECUTABLE_EXCLUDE_REGEX}") + set(${result_var} 0 PARENT_SCOPE) + return() + endif() + endif() + + if(NOT file_cmd) + find_program(file_cmd "file") + mark_as_advanced(file_cmd) + endif() + + if(file_cmd) + execute_process(COMMAND "${file_cmd}" "${file_full}" + OUTPUT_VARIABLE file_ov + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + + # Replace the name of the file in the output with a placeholder token + # (the string " _file_full_ ") so that just in case the path name of + # the file contains the word "text" or "executable" we are not fooled + # into thinking "the wrong thing" because the file name matches the + # other 'file' command output we are looking for... + # + string(REPLACE "${file_full}" " _file_full_ " file_ov "${file_ov}") + string(TOLOWER "${file_ov}" file_ov) + + #message(STATUS "file_ov='${file_ov}'") + if("${file_ov}" MATCHES "executable") + #message(STATUS "executable!") + if("${file_ov}" MATCHES "text") + #message(STATUS "but text, so *not* a binary executable!") + else() + set(${result_var} 1 PARENT_SCOPE) + return() + endif() + endif() + + # Also detect position independent executables on Linux, + # where "file" gives "shared object ... (uses shared libraries)" + if("${file_ov}" MATCHES "shared object.*\(uses shared libs\)") + set(${result_var} 1 PARENT_SCOPE) + return() + endif() + + else() + message(STATUS "warning: No 'file' command, skipping execute_process...") + endif() + endif() +endfunction() + + +function(gp_item_default_embedded_path item default_embedded_path_var) + + # On Windows and Linux, "embed" prerequisites in the same directory + # as the executable by default: + # + set(path "@executable_path") + set(overridden 0) + + # On the Mac, relative to the executable depending on the type + # of the thing we are embedding: + # + if(APPLE) + # + # The assumption here is that all executables in the bundle will be + # in same-level-directories inside the bundle. The parent directory + # of an executable inside the bundle should be MacOS or a sibling of + # MacOS and all embedded paths returned from here will begin with + # "@executable_path/../" and will work from all executables in all + # such same-level-directories inside the bundle. + # + + # By default, embed things right next to the main bundle executable: + # + set(path "@executable_path/../../Contents/MacOS") + + # Embed .dylibs right next to the main bundle executable: + # + if(item MATCHES "\\.dylib$") + set(path "@executable_path/../MacOS") + set(overridden 1) + endif() + + # Embed frameworks in the embedded "Frameworks" directory (sibling of MacOS): + # + if(NOT overridden) + if(item MATCHES "[^/]+\\.framework/") + set(path "@executable_path/../Frameworks") + set(overridden 1) + endif() + endif() + endif() + + # Provide a hook so that projects can override the default embedded location + # of any given library by whatever logic they choose: + # + if(COMMAND gp_item_default_embedded_path_override) + gp_item_default_embedded_path_override("${item}" path) + endif() + + set(${default_embedded_path_var} "${path}" PARENT_SCOPE) +endfunction() + + +function(gp_resolve_item context item exepath dirs resolved_item_var) + set(resolved 0) + set(resolved_item "${item}") + + # Is it already resolved? + # + if(IS_ABSOLUTE "${resolved_item}" AND EXISTS "${resolved_item}") + set(resolved 1) + endif() + + if(NOT resolved) + if(item MATCHES "@executable_path") + # + # @executable_path references are assumed relative to exepath + # + string(REPLACE "@executable_path" "${exepath}" ri "${item}") + get_filename_component(ri "${ri}" ABSOLUTE) + + if(EXISTS "${ri}") + #message(STATUS "info: embedded item exists (${ri})") + set(resolved 1) + set(resolved_item "${ri}") + else() + message(STATUS "warning: embedded item does not exist '${ri}'") + endif() + endif() + endif() + + if(NOT resolved) + if(item MATCHES "@loader_path") + # + # @loader_path references are assumed relative to the + # PATH of the given "context" (presumably another library) + # + get_filename_component(contextpath "${context}" PATH) + string(REPLACE "@loader_path" "${contextpath}" ri "${item}") + get_filename_component(ri "${ri}" ABSOLUTE) + + if(EXISTS "${ri}") + #message(STATUS "info: embedded item exists (${ri})") + set(resolved 1) + set(resolved_item "${ri}") + else() + message(STATUS "warning: embedded item does not exist '${ri}'") + endif() + endif() + endif() + + if(NOT resolved) + if(item MATCHES "@rpath") + # + # @rpath references are relative to the paths built into the binaries with -rpath + # We handle this case like we do for other Unixes. + # + # Two cases of item resolution are considered: + # + # (1) item has been copied into the bundle + # + # (2) item has NOT been copied into the bundle: Since the item can exist in a build or + # install tree outside of the bundle, the item is resolved using its name and the + # passed list of directories. + # + string(REPLACE "@rpath/" "" norpath_item "${item}") + + set(ri "ri-NOTFOUND") + if(EXISTS ${GP_RPATH_DIR}/${norpath_item}) + set(ri ${GP_RPATH_DIR}/${norpath_item}) + set(_msg "'find_file' in GP_RPATH_DIR (${ri})") + else() + get_filename_component(norpath_item_name ${norpath_item} NAME) + find_file(ri "${norpath_item_name}" ${exepath} ${dirs} NO_DEFAULT_PATH) + set(_msg "'find_file' in exepath/dirs (${ri})") + endif() + if(ri) + #message(STATUS "info: ${_msg}") + set(resolved 1) + set(resolved_item "${ri}") + set(ri "ri-NOTFOUND") + endif() + + endif() + endif() + + if(NOT resolved) + set(ri "ri-NOTFOUND") + find_file(ri "${item}" ${exepath} ${dirs} NO_DEFAULT_PATH) + find_file(ri "${item}" ${exepath} ${dirs} /usr/lib) + if(ri) + #message(STATUS "info: 'find_file' in exepath/dirs (${ri})") + set(resolved 1) + set(resolved_item "${ri}") + set(ri "ri-NOTFOUND") + endif() + endif() + + if(NOT resolved) + if(item MATCHES "[^/]+\\.framework/") + set(fw "fw-NOTFOUND") + find_file(fw "${item}" + "~/Library/Frameworks" + "/Library/Frameworks" + "/System/Library/Frameworks" + ) + if(fw) + #message(STATUS "info: 'find_file' found framework (${fw})") + set(resolved 1) + set(resolved_item "${fw}") + set(fw "fw-NOTFOUND") + endif() + endif() + endif() + + # Using find_program on Windows will find dll files that are in the PATH. + # (Converting simple file names into full path names if found.) + # + if(WIN32 AND NOT UNIX) + if(NOT resolved) + set(ri "ri-NOTFOUND") + find_program(ri "${item}" PATHS "${exepath};${dirs}" NO_DEFAULT_PATH) + find_program(ri "${item}" PATHS "${exepath};${dirs}") + if(ri) + #message(STATUS "info: 'find_program' in exepath/dirs (${ri})") + set(resolved 1) + set(resolved_item "${ri}") + set(ri "ri-NOTFOUND") + endif() + endif() + endif() + + # Provide a hook so that projects can override item resolution + # by whatever logic they choose: + # + if(COMMAND gp_resolve_item_override) + gp_resolve_item_override("${context}" "${item}" "${exepath}" "${dirs}" resolved_item resolved) + endif() + + if(NOT resolved) + message(STATUS " +warning: cannot resolve item '${item}' + + possible problems: + need more directories? + need to use InstallRequiredSystemLibraries? + run in install tree instead of build tree? +") +# message(STATUS " +#****************************************************************************** +#warning: cannot resolve item '${item}' +# +# possible problems: +# need more directories? +# need to use InstallRequiredSystemLibraries? +# run in install tree instead of build tree? +# +# context='${context}' +# item='${item}' +# exepath='${exepath}' +# dirs='${dirs}' +# resolved_item_var='${resolved_item_var}' +#****************************************************************************** +#") + endif() + + set(${resolved_item_var} "${resolved_item}" PARENT_SCOPE) +endfunction() + +function(gp_resolve_embedded_item context embedded_item exepath resolved_embedded_item_var) + #message(STATUS "**") + set(resolved 0) + set(resolved_embedded_item "${embedded_item}") + + if(embedded_item MATCHES "@executable_path") + string(REPLACE "@executable_path" "${exepath}" resolved_embedded_item "${embedded_item}") + set(resolved 1) + endif() + if(EXISTS "${GP_RPATH_DIR}" AND embedded_item MATCHES "@rpath") + string(REPLACE "@rpath" "${GP_RPATH_DIR}" resolved_embedded_item "${embedded_item}") + set(resolved 1) + endif() + + # Provide a hook so that projects can override embedded item resolution + # by whatever logic they choose: + # + if(COMMAND gp_resolve_embedded_item_override) + gp_resolve_embedded_item_override( + "${context}" "${embedded_item}" "${exepath}" resolved_embedded_item resolved) + endif() + + if(NOT resolved) + message(STATUS " +warning: cannot resolve embedded item '${embedded_item}' + possible problems: + need more directories? + need to use InstallRequiredSystemLibraries? + run in install tree instead of build tree? + + context='${context}' + embedded_item='${embedded_item}' + GP_RPATH_DIR='${GP_RPATH_DIR}' + exepath='${exepath}' + resolved_embedded_item_var='${resolved_embedded_item_var}' +") + endif() + + set(${resolved_embedded_item_var} "${resolved_embedded_item}" PARENT_SCOPE) +endfunction() + +function(gp_resolved_file_type original_file file exepath dirs type_var) + #message(STATUS "**") + + if(NOT IS_ABSOLUTE "${original_file}") + message(STATUS "warning: gp_resolved_file_type expects absolute full path for first arg original_file") + endif() + + set(is_embedded 0) + set(is_local 0) + set(is_system 0) + + set(resolved_file "${file}") + + if("${file}" MATCHES "^@(executable_|loader_|r)path") + set(is_embedded 1) + endif() + + if(NOT is_embedded) + if(NOT IS_ABSOLUTE "${file}") + gp_resolve_item("${original_file}" "${file}" "${exepath}" "${dirs}" resolved_file) + endif() + + string(TOLOWER "${original_file}" original_lower) + string(TOLOWER "${resolved_file}" lower) + + if(UNIX) + if(resolved_file MATCHES "^(/lib/|/lib32/|/lib64/|/usr/lib/|/usr/lib32/|/usr/lib64/|/usr/X11/|/usr/X11R6/|/usr/bin/|/usr/.*/lib/)") + set(is_system 1) + endif() + endif() + + if(APPLE) + if(resolved_file MATCHES "^(/System/Library/|/usr/lib/|/opt/X11/)") + set(is_system 1) + endif() + endif() + + if(WIN32) + string(TOLOWER "$ENV{SystemRoot}" sysroot) + string(REGEX REPLACE "\\\\" "/" sysroot "${sysroot}") + + string(TOLOWER "$ENV{windir}" windir) + string(REGEX REPLACE "\\\\" "/" windir "${windir}") + + if(lower MATCHES "^(${sysroot}/sys(tem|wow)|${windir}/sys(tem|wow)|(.*/)*msvc[^/]+dll)") + set(is_system 1) + endif() + + if(UNIX) + # if cygwin, we can get the properly formed windows paths from cygpath + find_program(CYGPATH_EXECUTABLE cygpath) + + if(CYGPATH_EXECUTABLE) + execute_process(COMMAND ${CYGPATH_EXECUTABLE} -W + OUTPUT_VARIABLE env_windir + OUTPUT_STRIP_TRAILING_WHITESPACE) + execute_process(COMMAND ${CYGPATH_EXECUTABLE} -S + OUTPUT_VARIABLE env_sysdir + OUTPUT_STRIP_TRAILING_WHITESPACE) + string(TOLOWER "${env_windir}" windir) + string(TOLOWER "${env_sysdir}" sysroot) + + if(lower MATCHES "^(${sysroot}/sys(tem|wow)|${windir}/sys(tem|wow)|(.*/)*msvc[^/]+dll)") + set(is_system 1) + endif() + endif() + endif() + endif() + + if(NOT is_system) + get_filename_component(original_path "${original_lower}" PATH) + get_filename_component(path "${lower}" PATH) + if("${original_path}" STREQUAL "${path}") + set(is_local 1) + else() + string(LENGTH "${original_path}/" original_length) + string(LENGTH "${lower}" path_length) + if(${path_length} GREATER ${original_length}) + string(SUBSTRING "${lower}" 0 ${original_length} path) + if("${original_path}/" STREQUAL "${path}") + set(is_embedded 1) + endif() + endif() + endif() + endif() + endif() + + # Return type string based on computed booleans: + # + set(type "other") + + if(is_system) + set(type "system") + elseif(is_embedded) + set(type "embedded") + elseif(is_local) + set(type "local") + endif() + + #message(STATUS "gp_resolved_file_type: '${file}' '${resolved_file}'") + #message(STATUS " type: '${type}'") + + if(NOT is_embedded) + if(NOT IS_ABSOLUTE "${resolved_file}") + if(lower MATCHES "^msvc[^/]+dll" AND is_system) + message(STATUS "info: non-absolute msvc file '${file}' returning type '${type}'") + else() + message(STATUS "warning: gp_resolved_file_type non-absolute file '${file}' returning type '${type}' -- possibly incorrect") + endif() + endif() + endif() + + # Provide a hook so that projects can override the decision on whether a + # library belongs to the system or not by whatever logic they choose: + # + if(COMMAND gp_resolved_file_type_override) + gp_resolved_file_type_override("${resolved_file}" type) + endif() + + set(${type_var} "${type}" PARENT_SCOPE) + + #message(STATUS "**") +endfunction() + + +function(gp_file_type original_file file type_var) + if(NOT IS_ABSOLUTE "${original_file}") + message(STATUS "warning: gp_file_type expects absolute full path for first arg original_file") + endif() + + get_filename_component(exepath "${original_file}" PATH) + + set(type "") + gp_resolved_file_type("${original_file}" "${file}" "${exepath}" "" type) + + set(${type_var} "${type}" PARENT_SCOPE) +endfunction() + + +function(get_prerequisites target prerequisites_var exclude_system recurse exepath dirs) + set(verbose 0) + set(eol_char "E") + + if(NOT IS_ABSOLUTE "${target}") + message("warning: target '${target}' is not absolute...") + endif() + + if(NOT EXISTS "${target}") + message("warning: target '${target}' does not exist...") + endif() + + set(gp_cmd_paths ${gp_cmd_paths} + "C:/Program Files/Microsoft Visual Studio 9.0/VC/bin" + "C:/Program Files (x86)/Microsoft Visual Studio 9.0/VC/bin" + "C:/Program Files/Microsoft Visual Studio 8/VC/BIN" + "C:/Program Files (x86)/Microsoft Visual Studio 8/VC/BIN" + "C:/Program Files/Microsoft Visual Studio .NET 2003/VC7/BIN" + "C:/Program Files (x86)/Microsoft Visual Studio .NET 2003/VC7/BIN" + "/usr/local/bin" + "/usr/bin" + ) + + # + # + # Try to choose the right tool by default. Caller can set gp_tool prior to + # calling this function to force using a different tool. + # + if("${gp_tool}" STREQUAL "") + set(gp_tool "ldd") + + if(APPLE) + set(gp_tool "otool") + endif() + + if(WIN32 AND NOT UNIX) # This is how to check for cygwin, har! + find_program(gp_dumpbin "dumpbin" PATHS ${gp_cmd_paths}) + if(gp_dumpbin) + set(gp_tool "dumpbin") + else() # Try harder. Maybe we're on MinGW + set(gp_tool "objdump") + endif() + endif() + endif() + + find_program(gp_cmd ${gp_tool} PATHS ${gp_cmd_paths}) + + if(NOT gp_cmd) + message(STATUS "warning: could not find '${gp_tool}' - cannot analyze prerequisites...") + return() + endif() + + set(gp_tool_known 0) + + if("${gp_tool}" STREQUAL "ldd") + set(gp_cmd_args "") + set(gp_regex "^[\t ]*[^\t ]+ => ([^\t\(]+) .*${eol_char}$") + set(gp_regex_error "not found${eol_char}$") + set(gp_regex_fallback "^[\t ]*([^\t ]+) => ([^\t ]+).*${eol_char}$") + set(gp_regex_cmp_count 1) + set(gp_tool_known 1) + endif() + + if("${gp_tool}" STREQUAL "otool") + set(gp_cmd_args "-L") + set(gp_regex "^\t([^\t]+) \\(compatibility version ([0-9]+.[0-9]+.[0-9]+), current version ([0-9]+.[0-9]+.[0-9]+)\\)${eol_char}$") + set(gp_regex_error "") + set(gp_regex_fallback "") + set(gp_regex_cmp_count 3) + set(gp_tool_known 1) + endif() + + if("${gp_tool}" STREQUAL "dumpbin") + set(gp_cmd_args "/dependents") + set(gp_regex "^ ([^ ].*[Dd][Ll][Ll])${eol_char}$") + set(gp_regex_error "") + set(gp_regex_fallback "") + set(gp_regex_cmp_count 1) + set(gp_tool_known 1) + set(ENV{VS_UNICODE_OUTPUT} "") # Block extra output from inside VS IDE. + endif() + + if("${gp_tool}" STREQUAL "objdump") + set(gp_cmd_args "-p") + set(gp_regex "^\t*DLL Name: (.*\\.[Dd][Ll][Ll])${eol_char}$") + set(gp_regex_error "") + set(gp_regex_fallback "") + set(gp_regex_cmp_count 1) + set(gp_tool_known 1) + endif() + + if(NOT gp_tool_known) + message(STATUS "warning: gp_tool='${gp_tool}' is an unknown tool...") + message(STATUS "CMake function get_prerequisites needs more code to handle '${gp_tool}'") + message(STATUS "Valid gp_tool values are dumpbin, ldd, objdump and otool.") + return() + endif() + + + if("${gp_tool}" STREQUAL "dumpbin") + # When running dumpbin, it also needs the "Common7/IDE" directory in the + # PATH. It will already be in the PATH if being run from a Visual Studio + # command prompt. Add it to the PATH here in case we are running from a + # different command prompt. + # + get_filename_component(gp_cmd_dir "${gp_cmd}" PATH) + get_filename_component(gp_cmd_dlls_dir "${gp_cmd_dir}/../../Common7/IDE" ABSOLUTE) + # Use cmake paths as a user may have a PATH element ending with a backslash. + # This will escape the list delimiter and create havoc! + if(EXISTS "${gp_cmd_dlls_dir}") + # only add to the path if it is not already in the path + set(gp_found_cmd_dlls_dir 0) + file(TO_CMAKE_PATH "$ENV{PATH}" env_path) + foreach(gp_env_path_element ${env_path}) + if("${gp_env_path_element}" STREQUAL "${gp_cmd_dlls_dir}") + set(gp_found_cmd_dlls_dir 1) + endif() + endforeach() + + if(NOT gp_found_cmd_dlls_dir) + file(TO_NATIVE_PATH "${gp_cmd_dlls_dir}" gp_cmd_dlls_dir) + set(ENV{PATH} "$ENV{PATH};${gp_cmd_dlls_dir}") + endif() + endif() + endif() + # + # + + if("${gp_tool}" STREQUAL "ldd") + set(old_ld_env "$ENV{LD_LIBRARY_PATH}") + foreach(dir ${exepath} ${dirs}) + set(ENV{LD_LIBRARY_PATH} "${dir}:$ENV{LD_LIBRARY_PATH}") + endforeach() + endif() + + + # Track new prerequisites at each new level of recursion. Start with an + # empty list at each level: + # + set(unseen_prereqs) + + # Run gp_cmd on the target: + # + execute_process( + COMMAND ${gp_cmd} ${gp_cmd_args} ${target} + OUTPUT_VARIABLE gp_cmd_ov + ) + + if("${gp_tool}" STREQUAL "ldd") + set(ENV{LD_LIBRARY_PATH} "${old_ld_env}") + endif() + + if(verbose) + message(STATUS "") + message(STATUS "gp_cmd_ov='${gp_cmd_ov}'") + message(STATUS "") + endif() + + get_filename_component(target_dir "${target}" PATH) + + # Convert to a list of lines: + # + string(REGEX REPLACE ";" "\\\\;" candidates "${gp_cmd_ov}") + string(REGEX REPLACE "\n" "${eol_char};" candidates "${candidates}") + + # check for install id and remove it from list, since otool -L can include a + # reference to itself + set(gp_install_id) + if("${gp_tool}" STREQUAL "otool") + execute_process( + COMMAND otool -D ${target} + OUTPUT_VARIABLE gp_install_id_ov + ) + # second line is install name + string(REGEX REPLACE ".*:\n" "" gp_install_id "${gp_install_id_ov}") + if(gp_install_id) + # trim + string(REGEX MATCH "[^\n ].*[^\n ]" gp_install_id "${gp_install_id}") + #message("INSTALL ID is \"${gp_install_id}\"") + endif() + endif() + + # Analyze each line for file names that match the regular expression: + # + foreach(candidate ${candidates}) + if("${candidate}" MATCHES "${gp_regex}") + + # Extract information from each candidate: + if(gp_regex_error AND "${candidate}" MATCHES "${gp_regex_error}") + string(REGEX REPLACE "${gp_regex_fallback}" "\\1" raw_item "${candidate}") + else() + string(REGEX REPLACE "${gp_regex}" "\\1" raw_item "${candidate}") + endif() + + if(gp_regex_cmp_count GREATER 1) + string(REGEX REPLACE "${gp_regex}" "\\2" raw_compat_version "${candidate}") + string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\1" compat_major_version "${raw_compat_version}") + string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\2" compat_minor_version "${raw_compat_version}") + string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\3" compat_patch_version "${raw_compat_version}") + endif() + + if(gp_regex_cmp_count GREATER 2) + string(REGEX REPLACE "${gp_regex}" "\\3" raw_current_version "${candidate}") + string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\1" current_major_version "${raw_current_version}") + string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\2" current_minor_version "${raw_current_version}") + string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\3" current_patch_version "${raw_current_version}") + endif() + + # Use the raw_item as the list entries returned by this function. Use the + # gp_resolve_item function to resolve it to an actual full path file if + # necessary. + # + set(item "${raw_item}") + + # Add each item unless it is excluded: + # + set(add_item 1) + + if("${item}" STREQUAL "${gp_install_id}") + set(add_item 0) + endif() + + if(add_item AND ${exclude_system}) + set(type "") + gp_resolved_file_type("${target}" "${item}" "${exepath}" "${dirs}" type) + + if("${type}" STREQUAL "system") + set(add_item 0) + endif() + endif() + + if(add_item) + list(LENGTH ${prerequisites_var} list_length_before_append) + gp_append_unique(${prerequisites_var} "${item}") + list(LENGTH ${prerequisites_var} list_length_after_append) + + if(${recurse}) + # If item was really added, this is the first time we have seen it. + # Add it to unseen_prereqs so that we can recursively add *its* + # prerequisites... + # + # But first: resolve its name to an absolute full path name such + # that the analysis tools can simply accept it as input. + # + if(NOT list_length_before_append EQUAL list_length_after_append) + gp_resolve_item("${target}" "${item}" "${exepath}" "${dirs}" resolved_item) + set(unseen_prereqs ${unseen_prereqs} "${resolved_item}") + endif() + endif() + endif() + else() + if(verbose) + message(STATUS "ignoring non-matching line: '${candidate}'") + endif() + endif() + endforeach() + + list(LENGTH ${prerequisites_var} prerequisites_var_length) + if(prerequisites_var_length GREATER 0) + list(SORT ${prerequisites_var}) + endif() + if(${recurse}) + set(more_inputs ${unseen_prereqs}) + foreach(input ${more_inputs}) + get_prerequisites("${input}" ${prerequisites_var} ${exclude_system} ${recurse} "${exepath}" "${dirs}") + endforeach() + endif() + + set(${prerequisites_var} ${${prerequisites_var}} PARENT_SCOPE) +endfunction() + + +function(list_prerequisites target) + if("${ARGV1}" STREQUAL "") + set(all 1) + else() + set(all "${ARGV1}") + endif() + + if("${ARGV2}" STREQUAL "") + set(exclude_system 0) + else() + set(exclude_system "${ARGV2}") + endif() + + if("${ARGV3}" STREQUAL "") + set(verbose 0) + else() + set(verbose "${ARGV3}") + endif() + + set(count 0) + set(count_str "") + set(print_count "${verbose}") + set(print_prerequisite_type "${verbose}") + set(print_target "${verbose}") + set(type_str "") + + get_filename_component(exepath "${target}" PATH) + + set(prereqs "") + get_prerequisites("${target}" prereqs ${exclude_system} ${all} "${exepath}" "") + + if(print_target) + message(STATUS "File '${target}' depends on:") + endif() + + foreach(d ${prereqs}) + math(EXPR count "${count} + 1") + + if(print_count) + set(count_str "${count}. ") + endif() + + if(print_prerequisite_type) + gp_file_type("${target}" "${d}" type) + set(type_str " (${type})") + endif() + + message(STATUS "${count_str}${d}${type_str}") + endforeach() +endfunction() + + +function(list_prerequisites_by_glob glob_arg glob_exp) + message(STATUS "=============================================================================") + message(STATUS "List prerequisites of executables matching ${glob_arg} '${glob_exp}'") + message(STATUS "") + file(${glob_arg} file_list ${glob_exp}) + foreach(f ${file_list}) + is_file_executable("${f}" is_f_executable) + if(is_f_executable) + message(STATUS "=============================================================================") + list_prerequisites("${f}" ${ARGN}) + message(STATUS "") + endif() + endforeach() +endfunction() From c868010c20f1aa01b1a5fe66375340e4b12a9ada Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Mon, 3 Aug 2015 19:21:02 +0200 Subject: [PATCH 2020/3725] OS X: don't consider libs from `/usr/local` as "system dependencies" during packaging Otherwise they won't be moved into final application bundle. --- cmake/GetPrerequisitesWithRPath.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/GetPrerequisitesWithRPath.cmake b/cmake/GetPrerequisitesWithRPath.cmake index b57295b3d..5b5751ead 100644 --- a/cmake/GetPrerequisitesWithRPath.cmake +++ b/cmake/GetPrerequisitesWithRPath.cmake @@ -537,7 +537,7 @@ function(gp_resolved_file_type original_file file exepath dirs type_var) string(TOLOWER "${resolved_file}" lower) if(UNIX) - if(resolved_file MATCHES "^(/lib/|/lib32/|/lib64/|/usr/lib/|/usr/lib32/|/usr/lib64/|/usr/X11/|/usr/X11R6/|/usr/bin/|/usr/.*/lib/)") + if(resolved_file MATCHES "^(/lib/|/lib32/|/lib64/|/usr/lib/|/usr/lib32/|/usr/lib64/|/usr/X11/|/usr/X11R6/|/usr/bin/)") set(is_system 1) endif() endif() From 2ded28f6aaf8da8ab6d069f3125e4eb53fdd58a9 Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Mon, 3 Aug 2015 19:21:35 +0200 Subject: [PATCH 2021/3725] OS X: reintroduce packaging code It's much simpler now thanks to bundle utilities with @rpath support. --- CMakeLists.txt | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a14beb423..f7c458da5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -736,13 +736,18 @@ if (APPLE) install(CODE " set(BU_CHMOD_BUNDLE_ITEMS ON) - include(BundleUtilities) + set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH}) + include(BundleUtilitiesWithRPath) " COMPONENT Runtime) - #For now, search unresolved dependencies only in default system paths, so if you put unresolveable (i.e. with @executable_path in id name) lib or framework somewhere else, it would fail - set(DIRS "") + set(DIRS "${CMAKE_PREFIX_PATH}/lib") - include(CPack) + install(CODE " + cmake_policy(SET CMP0009 OLD) + fixup_bundle(\"${OPENMW_APP}\" \"\" \"${DIRS}\") + fixup_bundle(\"${OPENCS_APP}\" \"\" \"${DIRS}\") + " COMPONENT Runtime) + include(CPack) endif (APPLE) # Doxygen Target -- simply run 'make doc' or 'make doc_pages' From 34d601360f5daad9bfc67afe67ff1ca9ec5ae34c Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Sat, 8 Aug 2015 17:19:26 +0200 Subject: [PATCH 2022/3725] OS X: setup OSG plugins packaging --- CMakeLists.txt | 56 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 54 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f7c458da5..9e966cf6d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -306,6 +306,11 @@ add_subdirectory(files/) if (APPLE) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${APP_BUNDLE_DIR}/Contents/MacOS") set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${APP_BUNDLE_DIR}/Contents/MacOS") + + if (OPENMW_OSX_DEPLOYMENT) + SET(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) + SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH FALSE) + endif() else (APPLE) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${OpenMW_BINARY_DIR}") set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${OpenMW_BINARY_DIR}") @@ -740,12 +745,59 @@ if (APPLE) include(BundleUtilitiesWithRPath) " COMPONENT Runtime) + set(ABSOLUTE_PLUGINS "") + set(USED_OSG_PLUGINS + osgdb_tga + osgdb_dds + osgdb_imageio + ) + + foreach (PLUGIN_NAME ${USED_OSG_PLUGINS}) + set(PLUGIN_ABS "${OSG_PLUGIN_LIB_SEARCH_PATH}/${PLUGIN_NAME}.so") + set(ABSOLUTE_PLUGINS ${PLUGIN_ABS} ${ABSOLUTE_PLUGINS}) + endforeach () + + get_filename_component(PLUGIN_PREFIX_DIR "${OSG_PLUGIN_LIB_SEARCH_PATH}" NAME) + + # installs used plugins in bundle at given path (bundle_path must be relative to ${CMAKE_INSTALL_PREFIX}) + # and returns list of install paths for all installed plugins + function (install_plugins_for_bundle bundle_path plugins_var) + set(RELATIVE_PLUGIN_INSTALL_BASE "${bundle_path}/Contents/PlugIns/${PLUGIN_PREFIX_DIR}") + + set(PLUGINS "") + set(PLUGIN_INSTALL_BASE "\${CMAKE_INSTALL_PREFIX}/${RELATIVE_PLUGIN_INSTALL_BASE}") + + foreach (PLUGIN ${ABSOLUTE_PLUGINS}) + get_filename_component(PLUGIN_RELATIVE ${PLUGIN} NAME) + get_filename_component(PLUGIN_RELATIVE_WE ${PLUGIN} NAME_WE) + + set(PLUGIN_DYLIB_IN_BUNDLE "${PLUGIN_INSTALL_BASE}/${PLUGIN_RELATIVE}") + set(PLUGINS ${PLUGINS} "${PLUGIN_DYLIB_IN_BUNDLE}") + + install(CODE " + copy_resolved_item_into_bundle(\"${PLUGIN}\" \"${PLUGIN_DYLIB_IN_BUNDLE}\") + " COMPONENT Runtime) + endforeach () + + set(${plugins_var} ${PLUGINS} PARENT_SCOPE) + endfunction (install_plugins_for_bundle) + + install_plugins_for_bundle("${INSTALL_SUBDIR}/${APP_BUNDLE_NAME}" PLUGINS) + install_plugins_for_bundle("${INSTALL_SUBDIR}/${OPENCS_BUNDLE_NAME}" OPENCS_PLUGINS) + set(DIRS "${CMAKE_PREFIX_PATH}/lib") install(CODE " + function(gp_item_default_embedded_path_override item default_embedded_path_var) + if (\${item} MATCHES ${PLUGIN_PREFIX_DIR}) + set(path \"@executable_path/../PlugIns/${PLUGIN_PREFIX_DIR}\") + set(\${default_embedded_path_var} \"\${path}\" PARENT_SCOPE) + endif() + endfunction() + cmake_policy(SET CMP0009 OLD) - fixup_bundle(\"${OPENMW_APP}\" \"\" \"${DIRS}\") - fixup_bundle(\"${OPENCS_APP}\" \"\" \"${DIRS}\") + fixup_bundle(\"${OPENMW_APP}\" \"${PLUGINS}\" \"${DIRS}\") + fixup_bundle(\"${OPENCS_APP}\" \"${OPENCS_PLUGINS}\" \"${DIRS}\") " COMPONENT Runtime) include(CPack) endif (APPLE) From d9b11f963ad733d0ee105cd777202179e0b33658 Mon Sep 17 00:00:00 2001 From: Rohit Nirmal Date: Tue, 11 Aug 2015 21:45:02 -0500 Subject: [PATCH 2023/3725] Gamepad: Slow down simulated mouse with right trigger in menus. --- apps/openmw/mwinput/inputmanagerimp.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 09e0b638b..2d767c6f5 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -370,6 +370,9 @@ namespace MWInput float zAxis = mInputBinder->getChannel(A_LookUpDown)->getValue()*2.0f-1.0f; const MyGUI::IntSize& viewSize = MyGUI::RenderManager::getInstance().getViewSize(); + xAxis *= (1.5f - mInputBinder->getChannel(A_Use)->getValue()); + yAxis *= (1.5f - mInputBinder->getChannel(A_Use)->getValue()); + // We keep track of our own mouse position, so that moving the mouse while in // game mode does not move the position of the GUI cursor mGuiCursorX += xAxis * dt * 1500.0f * mInvUiScalingFactor; From 904ad949524864239f4b1f428d03a947360728a0 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 13 Aug 2015 12:03:20 +0200 Subject: [PATCH 2024/3725] added merge operation (doesn't do anything yet) --- apps/opencs/CMakeLists.txt | 1 + apps/opencs/model/doc/document.cpp | 6 +++++ apps/opencs/model/doc/document.hpp | 5 ++-- apps/opencs/model/tools/mergeoperation.cpp | 15 +++++++++++ apps/opencs/model/tools/mergeoperation.hpp | 28 +++++++++++++++++++ apps/opencs/model/tools/tools.cpp | 31 +++++++++++++++++++--- apps/opencs/model/tools/tools.hpp | 11 ++++++-- apps/opencs/view/tools/merge.cpp | 8 ++++++ 8 files changed, 97 insertions(+), 8 deletions(-) create mode 100644 apps/opencs/model/tools/mergeoperation.cpp create mode 100644 apps/opencs/model/tools/mergeoperation.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 91c778c06..833ca6551 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -42,6 +42,7 @@ opencs_units_noqt (model/tools mandatoryid skillcheck classcheck factioncheck racecheck soundcheck regioncheck birthsigncheck spellcheck referencecheck referenceablecheck scriptcheck bodypartcheck startscriptcheck search searchoperation searchstage pathgridcheck soundgencheck + mergeoperation ) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 44e6142b0..a331706bc 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -2388,6 +2388,12 @@ void CSMDoc::Document::runSearch (const CSMWorld::UniversalId& searchId, const C emit stateChanged (getState(), this); } +void CSMDoc::Document::runMerge (const boost::filesystem::path& target) +{ + mTools.runMerge (target); + emit stateChanged (getState(), this); +} + void CSMDoc::Document::abortOperation (int type) { if (type==State_Saving) diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp index c9271fa54..901a8e3e4 100644 --- a/apps/opencs/model/doc/document.hpp +++ b/apps/opencs/model/doc/document.hpp @@ -129,7 +129,9 @@ namespace CSMDoc CSMWorld::UniversalId newSearch(); void runSearch (const CSMWorld::UniversalId& searchId, const CSMTools::Search& search); - + + void runMerge (const boost::filesystem::path& target); + void abortOperation (int type); const CSMWorld::Data& getData() const; @@ -173,4 +175,3 @@ namespace CSMDoc } #endif - diff --git a/apps/opencs/model/tools/mergeoperation.cpp b/apps/opencs/model/tools/mergeoperation.cpp new file mode 100644 index 000000000..65cfdb4ff --- /dev/null +++ b/apps/opencs/model/tools/mergeoperation.cpp @@ -0,0 +1,15 @@ + +#include "mergeoperation.hpp" + +#include "../doc/state.hpp" + +CSMTools::MergeOperation::MergeOperation (CSMDoc::Document& document) +: CSMDoc::Operation (CSMDoc::State_Merging, true) +{ + +} + +void CSMTools::MergeOperation::setTarget (const boost::filesystem::path& target) +{ + +} diff --git a/apps/opencs/model/tools/mergeoperation.hpp b/apps/opencs/model/tools/mergeoperation.hpp new file mode 100644 index 000000000..84526b2f2 --- /dev/null +++ b/apps/opencs/model/tools/mergeoperation.hpp @@ -0,0 +1,28 @@ +#ifndef CSM_TOOLS_MERGEOPERATION_H +#define CSM_TOOLS_MERGEOPERATION_H + +#include + +#include "../doc/operation.hpp" + +namespace CSMDoc +{ + class Document; +} + +namespace CSMTools +{ + class MergeOperation : public CSMDoc::Operation + { + + + public: + + MergeOperation (CSMDoc::Document& document); + + /// \attention Do not call this function while a merge is running. + void setTarget (const boost::filesystem::path& target); + }; +} + +#endif diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index c9c116091..ba894a867 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -28,6 +28,7 @@ #include "searchoperation.hpp" #include "pathgridcheck.hpp" #include "soundgencheck.hpp" +#include "mergeoperation.hpp" CSMDoc::OperationHolder *CSMTools::Tools::get (int type) { @@ -35,6 +36,7 @@ CSMDoc::OperationHolder *CSMTools::Tools::get (int type) { case CSMDoc::State_Verifying: return &mVerifier; case CSMDoc::State_Searching: return &mSearch; + case CSMDoc::State_Merging: return &mMerge; } return 0; @@ -53,7 +55,7 @@ CSMDoc::OperationHolder *CSMTools::Tools::getVerifier() std::vector settings; settings.push_back ("script-editor/warnings"); - + mVerifierOperation->configureSettings (settings); connect (&mVerifier, SIGNAL (progress (int, int, int)), this, SIGNAL (progress (int, int, int))); @@ -116,7 +118,7 @@ CSMDoc::OperationHolder *CSMTools::Tools::getVerifier() CSMTools::Tools::Tools (CSMDoc::Document& document) : mDocument (document), mData (document.getData()), mVerifierOperation (0), - mSearchOperation (0), mNextReportNumber (0) + mSearchOperation (0), mMergeOperation (0), mNextReportNumber (0) { // index 0: load error log mReports.insert (std::make_pair (mNextReportNumber++, new ReportModel)); @@ -142,6 +144,12 @@ CSMTools::Tools::~Tools() delete mSearchOperation; } + if (mMergeOperation) + { + mMerge.abortAndWait(); + delete mMergeOperation; + } + for (std::map::iterator iter (mReports.begin()); iter!=mReports.end(); ++iter) delete iter->second; } @@ -153,7 +161,7 @@ CSMWorld::UniversalId CSMTools::Tools::runVerifier (const CSMWorld::UniversalId& if (mReports.find (reportNumber)==mReports.end()) mReports.insert (std::make_pair (reportNumber, new ReportModel)); - + mActiveReports[CSMDoc::State_Verifying] = reportNumber; getVerifier()->start(); @@ -183,6 +191,21 @@ void CSMTools::Tools::runSearch (const CSMWorld::UniversalId& searchId, const Se mSearch.start(); } +void CSMTools::Tools::runMerge (const boost::filesystem::path& target) +{ + // not setting an active report, because merge does not produce messages + + if (!mMergeOperation) + { + mMergeOperation = new MergeOperation (mDocument); + mMerge.setOperation (mMergeOperation); + } + + mMergeOperation->setTarget (target); + + mMerge.start(); +} + void CSMTools::Tools::abortOperation (int type) { if (CSMDoc::OperationHolder *operation = get (type)) @@ -195,6 +218,7 @@ int CSMTools::Tools::getRunningOperations() const { CSMDoc::State_Verifying, CSMDoc::State_Searching, + CSMDoc::State_Merging, -1 }; @@ -225,4 +249,3 @@ void CSMTools::Tools::verifierMessage (const CSMDoc::Message& message, int type) if (iter!=mActiveReports.end()) mReports[iter->second]->add (message); } - diff --git a/apps/opencs/model/tools/tools.hpp b/apps/opencs/model/tools/tools.hpp index 78484d15d..952099928 100644 --- a/apps/opencs/model/tools/tools.hpp +++ b/apps/opencs/model/tools/tools.hpp @@ -1,9 +1,11 @@ #ifndef CSM_TOOLS_TOOLS_H #define CSM_TOOLS_TOOLS_H +#include + #include -#include +#include #include "../doc/operationholder.hpp" @@ -24,6 +26,7 @@ namespace CSMTools class ReportModel; class Search; class SearchOperation; + class MergeOperation; class Tools : public QObject { @@ -35,6 +38,8 @@ namespace CSMTools CSMDoc::OperationHolder mVerifier; SearchOperation *mSearchOperation; CSMDoc::OperationHolder mSearch; + MergeOperation *mMergeOperation; + CSMDoc::OperationHolder mMerge; std::map mReports; int mNextReportNumber; std::map mActiveReports; // type, report number @@ -67,7 +72,9 @@ namespace CSMTools CSMWorld::UniversalId newSearch(); void runSearch (const CSMWorld::UniversalId& searchId, const Search& search); - + + void runMerge (const boost::filesystem::path& target); + void abortOperation (int type); ///< \attention The operation is not aborted immediately. diff --git a/apps/opencs/view/tools/merge.cpp b/apps/opencs/view/tools/merge.cpp index baadd9179..faf7be3b4 100644 --- a/apps/opencs/view/tools/merge.cpp +++ b/apps/opencs/view/tools/merge.cpp @@ -66,7 +66,9 @@ CSVTools::Merge::Merge (QWidget *parent) QDialogButtonBox *buttons = new QDialogButtonBox (QDialogButtonBox::Cancel, Qt::Horizontal, this); connect (buttons->button (QDialogButtonBox::Cancel), SIGNAL (clicked()), this, SLOT (reject())); + mOkay = new QPushButton ("Merge", this); + connect (mOkay, SIGNAL (clicked()), this, SLOT (accept())); mOkay->setDefault (true); buttons->addButton (mOkay, QDialogButtonBox::AcceptRole); @@ -109,6 +111,12 @@ void CSVTools::Merge::cancel() void CSVTools::Merge::accept() { QDialog::accept(); + + if ((mDocument->getState() & CSMDoc::State_Merging)==0) + { + mDocument->runMerge (mAdjuster->getPath()); + hide(); + } } void CSVTools::Merge::reject() From e2377396a7cf7b9cd1ec91e0f385721a124a49cc Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 13 Aug 2015 12:53:00 +0200 Subject: [PATCH 2025/3725] inheriting Merge from QWidget instead of QDialog, because QDialog is bloody useless for non-modal dialogues (which makes the class completely useless, since modal dialogues are the spawn of Satan) --- apps/opencs/editor.cpp | 2 ++ apps/opencs/view/tools/merge.cpp | 24 ++++++++++++++---------- apps/opencs/view/tools/merge.hpp | 15 +++++++-------- 3 files changed, 23 insertions(+), 18 deletions(-) diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 170e88320..0b385f275 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -379,4 +379,6 @@ void CS::Editor::mergeDocument (CSMDoc::Document *document) { mMerge.configure (document); mMerge.show(); + mMerge.raise(); + mMerge.activateWindow(); } diff --git a/apps/opencs/view/tools/merge.cpp b/apps/opencs/view/tools/merge.cpp index faf7be3b4..f775390ee 100644 --- a/apps/opencs/view/tools/merge.cpp +++ b/apps/opencs/view/tools/merge.cpp @@ -7,14 +7,26 @@ #include #include #include +#include #include "../../model/doc/document.hpp" #include "../doc/filewidget.hpp" #include "../doc/adjusterwidget.hpp" +void CSVTools::Merge::keyPressEvent (QKeyEvent *event) +{ + if (event->key()==Qt::Key_Escape) + { + event->accept(); + cancel(); + } + else + QWidget::keyPressEvent (event); +} + CSVTools::Merge::Merge (QWidget *parent) -: QDialog (parent), mDocument (0) +: QWidget (parent), mDocument (0) { setWindowTitle ("Merge Content Files into a new Game File"); @@ -65,7 +77,7 @@ CSVTools::Merge::Merge (QWidget *parent) // buttons QDialogButtonBox *buttons = new QDialogButtonBox (QDialogButtonBox::Cancel, Qt::Horizontal, this); - connect (buttons->button (QDialogButtonBox::Cancel), SIGNAL (clicked()), this, SLOT (reject())); + connect (buttons->button (QDialogButtonBox::Cancel), SIGNAL (clicked()), this, SLOT (cancel())); mOkay = new QPushButton ("Merge", this); connect (mOkay, SIGNAL (clicked()), this, SLOT (accept())); @@ -110,8 +122,6 @@ void CSVTools::Merge::cancel() void CSVTools::Merge::accept() { - QDialog::accept(); - if ((mDocument->getState() & CSMDoc::State_Merging)==0) { mDocument->runMerge (mAdjuster->getPath()); @@ -119,12 +129,6 @@ void CSVTools::Merge::accept() } } -void CSVTools::Merge::reject() -{ - QDialog::reject(); - cancel(); -} - void CSVTools::Merge::stateChanged (bool valid) { mOkay->setEnabled (valid); diff --git a/apps/opencs/view/tools/merge.hpp b/apps/opencs/view/tools/merge.hpp index 4538baebe..b8369ffa3 100644 --- a/apps/opencs/view/tools/merge.hpp +++ b/apps/opencs/view/tools/merge.hpp @@ -1,7 +1,7 @@ #ifndef CSV_TOOLS_REPORTTABLE_H #define CSV_TOOLS_REPORTTABLE_H -#include +#include #include @@ -21,7 +21,7 @@ namespace CSVDoc namespace CSVTools { - class Merge : public QDialog + class Merge : public QWidget { Q_OBJECT @@ -31,6 +31,8 @@ namespace CSVTools CSVDoc::FileWidget *mNewFile; CSVDoc::AdjusterWidget *mAdjuster; + void keyPressEvent (QKeyEvent *event); + public: Merge (QWidget *parent = 0); @@ -42,18 +44,15 @@ namespace CSVTools CSMDoc::Document *getDocument() const; - void cancel(); - public slots: - virtual void accept(); - - virtual void reject(); + void cancel(); private slots: - void stateChanged (bool valid); + void accept(); + void stateChanged (bool valid); }; } From d8655f2ff862dbaf90fb285ef01cdf6891cdbea6 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 13 Aug 2015 14:49:32 +0200 Subject: [PATCH 2026/3725] forgot to connect merge operation signals --- apps/opencs/model/tools/tools.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index ba894a867..681f74404 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -128,6 +128,10 @@ CSMTools::Tools::Tools (CSMDoc::Document& document) connect (&mSearch, SIGNAL (done (int, bool)), this, SIGNAL (done (int, bool))); connect (&mSearch, SIGNAL (reportMessage (const CSMDoc::Message&, int)), this, SLOT (verifierMessage (const CSMDoc::Message&, int))); + + connect (&mMerge, SIGNAL (progress (int, int, int)), this, SIGNAL (progress (int, int, int))); + connect (&mMerge, SIGNAL (done (int, bool)), this, SIGNAL (done (int, bool))); + // don't need to connect report message, since there are no messages for merge } CSMTools::Tools::~Tools() From c07ced4c8fe626ab74f2c554504aefc55a86fb78 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 13 Aug 2015 17:01:25 +0200 Subject: [PATCH 2027/3725] Editor: fix magic effect magnitudes incorrectly labelled as Min/Max Range --- apps/opencs/model/world/columns.cpp | 2 ++ apps/opencs/model/world/columns.hpp | 3 +++ apps/opencs/model/world/data.cpp | 8 ++++---- apps/opencs/model/world/refidcollection.cpp | 4 ++-- 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 7aec68309..579bc9899 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -35,6 +35,8 @@ namespace CSMWorld { ColumnId_Volume, "Volume" }, { ColumnId_MinRange, "Min Range" }, { ColumnId_MaxRange, "Max Range" }, + { ColumnId_MinMagnitude, "Min Magnitude" }, + { ColumnId_MaxMagnitude, "Max Magnitude" }, { ColumnId_SoundFile, "Sound File" }, { ColumnId_MapColour, "Map Colour" }, { ColumnId_SleepEncounter, "Sleep Encounter" }, diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index d699c67b7..5dfa479f6 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -306,6 +306,9 @@ namespace CSMWorld ColumnId_FileDescription = 276, ColumnId_Author = 277, + ColumnId_MinMagnitude = 278, + ColumnId_MaxMagnitude = 279, + // Allocated to a separate value range, so we don't get a collision should we ever need // to extend the number of use values. ColumnId_UseValue1 = 0x10000, diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 3714117b6..25a04715d 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -224,9 +224,9 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mSpells.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_Duration, ColumnBase::Display_Integer)); // reuse from light mSpells.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_MinRange, ColumnBase::Display_Integer)); // reuse from sound + new NestedChildColumn (Columns::ColumnId_MinMagnitude, ColumnBase::Display_Integer)); mSpells.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_MaxRange, ColumnBase::Display_Integer)); // reuse from sound + new NestedChildColumn (Columns::ColumnId_MaxMagnitude, ColumnBase::Display_Integer)); mTopics.addColumn (new StringIdColumn); mTopics.addColumn (new RecordStateColumn); @@ -340,9 +340,9 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mEnchantments.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_Duration, ColumnBase::Display_Integer)); // reuse from light mEnchantments.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_MinRange, ColumnBase::Display_Integer)); // reuse from sound + new NestedChildColumn (Columns::ColumnId_MinMagnitude, ColumnBase::Display_Integer)); mEnchantments.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_MaxRange, ColumnBase::Display_Integer)); // reuse from sound + new NestedChildColumn (Columns::ColumnId_MaxMagnitude, ColumnBase::Display_Integer)); mBodyParts.addColumn (new StringIdColumn); mBodyParts.addColumn (new RecordStateColumn); diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 947454d77..5b2d184a7 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -93,9 +93,9 @@ CSMWorld::RefIdCollection::RefIdCollection() mColumns.back().addColumn( new NestedChildColumn (Columns::ColumnId_Duration, ColumnBase::Display_Integer)); // reuse from light mColumns.back().addColumn( - new NestedChildColumn (Columns::ColumnId_MinRange, ColumnBase::Display_Integer)); // reuse from sound + new NestedChildColumn (Columns::ColumnId_MinMagnitude, ColumnBase::Display_Integer)); mColumns.back().addColumn( - new NestedChildColumn (Columns::ColumnId_MaxRange, ColumnBase::Display_Integer)); // reuse from sound + new NestedChildColumn (Columns::ColumnId_MaxMagnitude, ColumnBase::Display_Integer)); EnchantableColumns enchantableColumns (inventoryColumns); From 86f0e505e956583e9d62f13fd565a30f4a8f388f Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 28 Jul 2015 23:27:25 +0200 Subject: [PATCH 2028/3725] Add a fixPosition for the --start exterior cell (Fixes #2790) --- apps/openmw/mwworld/worldimp.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 15c8cbeb2..a97c8f0d4 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -228,6 +228,7 @@ namespace MWWorld if (findExteriorPosition (mStartCell, pos)) { changeToExteriorCell (pos); + fixPosition(getPlayerPtr()); } else { From 0d8f07d5634a8127c350d3418e5b9dd836e67aa2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 31 Jul 2015 20:55:31 +0200 Subject: [PATCH 2029/3725] Properly apply changes when backing out of chargen dialogs (Fixes #2627) --- apps/openmw/mwgui/charactercreation.cpp | 101 +++++++++++------------- apps/openmw/mwgui/charactercreation.hpp | 5 ++ 2 files changed, 53 insertions(+), 53 deletions(-) diff --git a/apps/openmw/mwgui/charactercreation.cpp b/apps/openmw/mwgui/charactercreation.cpp index d0a050526..6585a0dd0 100644 --- a/apps/openmw/mwgui/charactercreation.cpp +++ b/apps/openmw/mwgui/charactercreation.cpp @@ -312,7 +312,7 @@ namespace MWGui }; } - void CharacterCreation::onPickClassDialogDone(WindowBase* parWindow) + void CharacterCreation::selectPickedClass() { if (mPickClassDialog) { @@ -332,20 +332,18 @@ namespace MWGui } updatePlayerHealth(); + } + + void CharacterCreation::onPickClassDialogDone(WindowBase* parWindow) + { + selectPickedClass(); handleDialogDone(CSE_ClassChosen, GM_Birth); } void CharacterCreation::onPickClassDialogBack() { - if (mPickClassDialog) - { - const std::string classId = mPickClassDialog->getClassId(); - if (!classId.empty()) - MWBase::Environment::get().getMechanicsManager()->setPlayerClass(classId); - MWBase::Environment::get().getWindowManager()->removeDialog(mPickClassDialog); - mPickClassDialog = 0; - } + selectPickedClass(); MWBase::Environment::get().getWindowManager()->popGuiMode(); MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); @@ -390,7 +388,7 @@ namespace MWGui handleDialogDone(CSE_NameChosen, GM_Race); } - void CharacterCreation::onRaceDialogBack() + void CharacterCreation::selectRace() { if (mRaceDialog) { @@ -404,40 +402,31 @@ namespace MWGui data.mHair ); } + MWBase::Environment::get().getWindowManager()->getInventoryWindow()->rebuildAvatar(); + MWBase::Environment::get().getWindowManager()->removeDialog(mRaceDialog); mRaceDialog = 0; } + updatePlayerHealth(); + } + + void CharacterCreation::onRaceDialogBack() + { + selectRace(); + MWBase::Environment::get().getWindowManager()->popGuiMode(); MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Name); } void CharacterCreation::onRaceDialogDone(WindowBase* parWindow) { - if (mRaceDialog) - { - const ESM::NPC &data = mRaceDialog->getResult(); - mPlayerRaceId = data.mRace; - if (!mPlayerRaceId.empty()) { - MWBase::Environment::get().getMechanicsManager()->setPlayerRace( - data.mRace, - data.isMale(), - data.mHead, - data.mHair - ); - } - MWBase::Environment::get().getWindowManager()->getInventoryWindow()->rebuildAvatar(); - - MWBase::Environment::get().getWindowManager()->removeDialog(mRaceDialog); - mRaceDialog = 0; - } - - updatePlayerHealth(); + selectRace(); handleDialogDone(CSE_RaceChosen, GM_Class); } - void CharacterCreation::onBirthSignDialogDone(WindowBase* parWindow) + void CharacterCreation::selectBirthSign() { if (mBirthSignDialog) { @@ -449,24 +438,24 @@ namespace MWGui } updatePlayerHealth(); + } + + void CharacterCreation::onBirthSignDialogDone(WindowBase* parWindow) + { + selectBirthSign(); handleDialogDone(CSE_BirthSignChosen, GM_Review); } void CharacterCreation::onBirthSignDialogBack() { - if (mBirthSignDialog) - { - MWBase::Environment::get().getMechanicsManager()->setPlayerBirthsign(mBirthSignDialog->getBirthId()); - MWBase::Environment::get().getWindowManager()->removeDialog(mBirthSignDialog); - mBirthSignDialog = 0; - } + selectBirthSign(); MWBase::Environment::get().getWindowManager()->popGuiMode(); MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); } - void CharacterCreation::onCreateClassDialogDone(WindowBase* parWindow) + void CharacterCreation::selectCreatedClass() { if (mCreateClassDialog) { @@ -495,19 +484,23 @@ namespace MWGui mPlayerClass = klass; MWBase::Environment::get().getWindowManager()->setPlayerClass(klass); - // Do not delete dialog, so that choices are rembered in case we want to go back and adjust them later + // Do not delete dialog, so that choices are remembered in case we want to go back and adjust them later mCreateClassDialog->setVisible(false); } - updatePlayerHealth(); + } + + void CharacterCreation::onCreateClassDialogDone(WindowBase* parWindow) + { + selectCreatedClass(); handleDialogDone(CSE_ClassChosen, GM_Birth); } void CharacterCreation::onCreateClassDialogBack() { - // Do not delete dialog, so that choices are rembered in case we want to go back and adjust them later - mCreateClassDialog->setVisible(false); + // not done in MW, but we do it for consistency with the other dialogs + selectCreatedClass(); MWBase::Environment::get().getWindowManager()->popGuiMode(); MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); @@ -631,18 +624,7 @@ namespace MWGui MWBase::Environment::get().getSoundManager()->say(sGenerateClassSteps(mGenerateClassStep).mSound); } - void CharacterCreation::onGenerateClassBack() - { - MWBase::Environment::get().getWindowManager()->removeDialog(mGenerateClassResultDialog); - mGenerateClassResultDialog = 0; - - MWBase::Environment::get().getMechanicsManager()->setPlayerClass(mGenerateClass); - - MWBase::Environment::get().getWindowManager()->popGuiMode(); - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); - } - - void CharacterCreation::onGenerateClassDone(WindowBase* parWindow) + void CharacterCreation::selectGeneratedClass() { MWBase::Environment::get().getWindowManager()->removeDialog(mGenerateClassResultDialog); mGenerateClassResultDialog = 0; @@ -656,6 +638,19 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->setPlayerClass(mPlayerClass); updatePlayerHealth(); + } + + void CharacterCreation::onGenerateClassBack() + { + selectGeneratedClass(); + + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); + } + + void CharacterCreation::onGenerateClassDone(WindowBase* parWindow) + { + selectGeneratedClass(); handleDialogDone(CSE_ClassChosen, GM_Birth); } diff --git a/apps/openmw/mwgui/charactercreation.hpp b/apps/openmw/mwgui/charactercreation.hpp index f6e7c6c92..7fb67caf6 100644 --- a/apps/openmw/mwgui/charactercreation.hpp +++ b/apps/openmw/mwgui/charactercreation.hpp @@ -83,6 +83,7 @@ namespace MWGui //Race dialog void onRaceDialogDone(WindowBase* parWindow); void onRaceDialogBack(); + void selectRace(); //Class dialogs void onClassChoice(int _index); @@ -94,10 +95,14 @@ namespace MWGui void onClassQuestionChosen(int _index); void onGenerateClassBack(); void onGenerateClassDone(WindowBase* parWindow); + void selectGeneratedClass(); + void selectCreatedClass(); + void selectPickedClass(); //Birthsign dialog void onBirthSignDialogDone(WindowBase* parWindow); void onBirthSignDialogBack(); + void selectBirthSign(); //Review dialog void onReviewDialogDone(WindowBase* parWindow); From 211deeb63e2c5f70dd3a8a78dcb8f16cd17b2c5d Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 4 Aug 2015 17:33:34 +0200 Subject: [PATCH 2030/3725] Don't attempt to lock or unlock unsuitable objects (Fixes #2826) --- apps/openmw/mwclass/container.cpp | 13 +++++++------ apps/openmw/mwclass/container.hpp | 2 ++ apps/openmw/mwclass/door.cpp | 5 +++++ apps/openmw/mwclass/door.hpp | 2 ++ apps/openmw/mwmechanics/security.cpp | 2 +- apps/openmw/mwmechanics/spellcasting.cpp | 6 +++--- apps/openmw/mwworld/class.cpp | 5 +++++ apps/openmw/mwworld/class.hpp | 2 ++ 8 files changed, 27 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index 862ae6c5d..830493627 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -281,9 +281,12 @@ namespace MWClass ptr.getCellRef().setLockLevel(-abs(ptr.getCellRef().getLockLevel())); //Makes lockLevel negative } + bool Container::canLock(const MWWorld::Ptr &ptr) const + { + return true; + } - MWWorld::Ptr - Container::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const + MWWorld::Ptr Container::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const { MWWorld::LiveCellRef *ref = ptr.get(); @@ -291,8 +294,7 @@ namespace MWClass return MWWorld::Ptr(&cell.get().insert(*ref), &cell); } - void Container::readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state) - const + void Container::readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state) const { const ESM::ContainerState& state2 = dynamic_cast (state); @@ -307,8 +309,7 @@ namespace MWClass readState (state2.mInventory); } - void Container::writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state) - const + void Container::writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state) const { ESM::ContainerState& state2 = dynamic_cast (state); diff --git a/apps/openmw/mwclass/container.hpp b/apps/openmw/mwclass/container.hpp index 3268d45d1..3541937d1 100644 --- a/apps/openmw/mwclass/container.hpp +++ b/apps/openmw/mwclass/container.hpp @@ -57,6 +57,8 @@ namespace MWClass virtual void unlock (const MWWorld::Ptr& ptr) const; ///< Unlock object + virtual bool canLock(const MWWorld::Ptr &ptr) const; + virtual void readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state) const; ///< Read additional state from \a state into \a ptr. diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 5a8c736d9..5062cc557 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -207,6 +207,11 @@ namespace MWClass ptr.getCellRef().setLockLevel(-abs(ptr.getCellRef().getLockLevel())); //Makes lockLevel negative } + bool Door::canLock(const MWWorld::Ptr &ptr) const + { + return true; + } + std::string Door::getScript (const MWWorld::Ptr& ptr) const { MWWorld::LiveCellRef *ref = diff --git a/apps/openmw/mwclass/door.hpp b/apps/openmw/mwclass/door.hpp index 9cfb46509..db5a7f32a 100644 --- a/apps/openmw/mwclass/door.hpp +++ b/apps/openmw/mwclass/door.hpp @@ -47,6 +47,8 @@ namespace MWClass virtual void unlock (const MWWorld::Ptr& ptr) const; ///< Unlock object + virtual bool canLock(const MWWorld::Ptr &ptr) const; + virtual std::string getScript (const MWWorld::Ptr& ptr) const; ///< Return name of the script attached to ptr diff --git a/apps/openmw/mwmechanics/security.cpp b/apps/openmw/mwmechanics/security.cpp index 9eab5bfef..97878db87 100644 --- a/apps/openmw/mwmechanics/security.cpp +++ b/apps/openmw/mwmechanics/security.cpp @@ -31,7 +31,7 @@ namespace MWMechanics void Security::pickLock(const MWWorld::Ptr &lock, const MWWorld::Ptr &lockpick, std::string& resultMessage, std::string& resultSound) { - if (!(lock.getCellRef().getLockLevel() > 0)) //If it's unlocked back out immediately + if (!(lock.getCellRef().getLockLevel() > 0) || !lock.getClass().canLock(lock)) //If it's unlocked back out immediately return; int lockStrength = lock.getCellRef().getLockLevel(); diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 1613300d7..675177508 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -562,7 +562,7 @@ namespace MWMechanics void CastSpell::applyInstantEffect(const MWWorld::Ptr &target, const MWWorld::Ptr &caster, const MWMechanics::EffectKey& effect, float magnitude) { short effectId = effect.mId; - if (!target.getClass().isActor()) + if (target.getClass().canLock(target)) { if (effectId == ESM::MagicEffect::Lock) { @@ -570,7 +570,7 @@ namespace MWMechanics { if (caster == MWBase::Environment::get().getWorld()->getPlayerPtr()) MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicLockSuccess}"); - target.getCellRef().setLockLevel(static_cast(magnitude)); + target.getClass().lock(target, static_cast(magnitude)); } } else if (effectId == ESM::MagicEffect::Open) @@ -586,7 +586,7 @@ namespace MWMechanics if (caster == MWBase::Environment::get().getWorld()->getPlayerPtr()) MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicOpenSuccess}"); } - target.getCellRef().setLockLevel(-abs(target.getCellRef().getLockLevel())); + target.getClass().unlock(target); } else MWBase::Environment::get().getSoundManager()->playSound3D(target, "Open Lock Fail", 1.f, 1.f); diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 180cba332..18200e33b 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -144,6 +144,11 @@ namespace MWWorld throw std::runtime_error ("class does not support unlocking"); } + bool Class::canLock(const Ptr &ptr) const + { + return false; + } + void Class::setRemainingUsageTime (const Ptr& ptr, float duration) const { throw std::runtime_error ("class does not support time-based uses"); diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index cd05b471b..1157db670 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -161,6 +161,8 @@ namespace MWWorld virtual void unlock (const Ptr& ptr) const; ///< Unlock object (default implementation: throw an exception) + virtual bool canLock (const Ptr& ptr) const; + virtual void setRemainingUsageTime (const Ptr& ptr, float duration) const; ///< Sets the remaining duration of the object, such as an equippable light /// source. (default implementation: throw an exception) From 1e18a73b1c7ba1551a2eecbd1c4b45fd4298dd9a Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 4 Aug 2015 17:55:38 +0200 Subject: [PATCH 2031/3725] Don't play magic effect sounds & visual effects for unsuitable targets (Fixes #2811) --- apps/openmw/mwmechanics/spellcasting.cpp | 43 ++++++++++++++++-------- apps/openmw/mwmechanics/spellcasting.hpp | 3 +- apps/openmw/mwworld/worldimp.cpp | 4 --- 3 files changed, 31 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 675177508..eacd674ed 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -489,8 +489,8 @@ namespace MWMechanics if (!wasDead && isDead) MWBase::Environment::get().getMechanicsManager()->actorKilled(target, caster); } - else - applyInstantEffect(target, caster, EffectKey(*effectIt), magnitude); + else if (!applyInstantEffect(target, caster, EffectKey(*effectIt), magnitude)) + continue; } // Re-casting a summon effect will remove the creature from previous castings of that effect. @@ -559,7 +559,7 @@ namespace MWMechanics target.getClass().onHit(target, 0.f, true, MWWorld::Ptr(), caster, true); } - void CastSpell::applyInstantEffect(const MWWorld::Ptr &target, const MWWorld::Ptr &caster, const MWMechanics::EffectKey& effect, float magnitude) + bool CastSpell::applyInstantEffect(const MWWorld::Ptr &target, const MWWorld::Ptr &caster, const MWMechanics::EffectKey& effect, float magnitude) { short effectId = effect.mId; if (target.getClass().canLock(target)) @@ -572,6 +572,7 @@ namespace MWMechanics MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicLockSuccess}"); target.getClass().lock(target, static_cast(magnitude)); } + return true; } else if (effectId == ESM::MagicEffect::Open) { @@ -590,43 +591,55 @@ namespace MWMechanics } else MWBase::Environment::get().getSoundManager()->playSound3D(target, "Open Lock Fail", 1.f, 1.f); + return true; } } - else + else if (target.getClass().isActor()) { - if (effectId == ESM::MagicEffect::CurePoison) + switch (effectId) + { + case ESM::MagicEffect::CurePoison: target.getClass().getCreatureStats(target).getActiveSpells().purgeEffect(ESM::MagicEffect::Poison); - else if (effectId == ESM::MagicEffect::CureParalyzation) + return true; + case ESM::MagicEffect::CureParalyzation: target.getClass().getCreatureStats(target).getActiveSpells().purgeEffect(ESM::MagicEffect::Paralyze); - else if (effectId == ESM::MagicEffect::CureCommonDisease) + return true; + case ESM::MagicEffect::CureCommonDisease: target.getClass().getCreatureStats(target).getSpells().purgeCommonDisease(); - else if (effectId == ESM::MagicEffect::CureBlightDisease) + return true; + case ESM::MagicEffect::CureBlightDisease: target.getClass().getCreatureStats(target).getSpells().purgeBlightDisease(); - else if (effectId == ESM::MagicEffect::CureCorprusDisease) + return true; + case ESM::MagicEffect::CureCorprusDisease: target.getClass().getCreatureStats(target).getSpells().purgeCorprusDisease(); - else if (effectId == ESM::MagicEffect::Dispel) + return true; + case ESM::MagicEffect::Dispel: target.getClass().getCreatureStats(target).getActiveSpells().purgeAll(magnitude); - else if (effectId == ESM::MagicEffect::RemoveCurse) + return true; + case ESM::MagicEffect::RemoveCurse: target.getClass().getCreatureStats(target).getSpells().purgeCurses(); + return true; + } if (target != MWBase::Environment::get().getWorld()->getPlayerPtr()) - return; - if (!MWBase::Environment::get().getWorld()->isTeleportingEnabled()) - return; + return false; if (effectId == ESM::MagicEffect::DivineIntervention) { MWBase::Environment::get().getWorld()->teleportToClosestMarker(target, "divinemarker"); + return true; } else if (effectId == ESM::MagicEffect::AlmsiviIntervention) { MWBase::Environment::get().getWorld()->teleportToClosestMarker(target, "templemarker"); + return true; } else if (effectId == ESM::MagicEffect::Mark) { MWBase::Environment::get().getWorld()->getPlayer().markPosition( target.getCell(), target.getRefData().getPosition()); + return true; } else if (effectId == ESM::MagicEffect::Recall) { @@ -640,8 +653,10 @@ namespace MWMechanics markedPosition, false); action.execute(target); } + return true; } } + return false; } diff --git a/apps/openmw/mwmechanics/spellcasting.hpp b/apps/openmw/mwmechanics/spellcasting.hpp index 418e9f56d..5b48bd4a8 100644 --- a/apps/openmw/mwmechanics/spellcasting.hpp +++ b/apps/openmw/mwmechanics/spellcasting.hpp @@ -97,7 +97,8 @@ namespace MWMechanics const ESM::EffectList& effects, ESM::RangeType range, bool reflected=false, bool exploded=false); /// @note \a caster can be any type of object, or even an empty object. - void applyInstantEffect (const MWWorld::Ptr& target, const MWWorld::Ptr& caster, const MWMechanics::EffectKey& effect, float magnitude); + /// @return was the target suitable for the effect? + bool applyInstantEffect (const MWWorld::Ptr& target, const MWWorld::Ptr& caster, const MWMechanics::EffectKey& effect, float magnitude); }; } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index a97c8f0d4..fb2778940 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2656,10 +2656,6 @@ namespace MWWorld target = result.mHitObject; hitPosition = result.mHitPos; - // don't allow casting on non-activatable objects - if (!target.isEmpty() && !target.getClass().isActor() && target.getClass().getName(target).empty()) - target = MWWorld::Ptr(); - std::string selectedSpell = stats.getSpells().getSelectedSpell(); MWMechanics::CastSpell cast(actor, target); From e8c9d3ea2ae72fe72ae974e69a24490ab9c361a9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 6 Aug 2015 23:29:19 +0200 Subject: [PATCH 2032/3725] Fix cell names on world map not always being translated (Fixes #2832) --- apps/openmw/mwgui/mapwindow.cpp | 2 +- apps/openmw/mwgui/mapwindow.hpp | 3 ++- apps/openmw/mwgui/windowmanagerimp.cpp | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index e26c076e7..2df1c8f3c 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -783,7 +783,7 @@ namespace MWGui MyGUI::Widget* markerWidget = mGlobalMap->createWidget("MarkerButton", widgetCoord, MyGUI::Align::Default); - markerWidget->setUserString("Caption_TextOneLine", name); + markerWidget->setUserString("Caption_TextOneLine", "#{sCell=" + name + "}"); setGlobalMapMarkerTooltip(markerWidget, x, y); diff --git a/apps/openmw/mwgui/mapwindow.hpp b/apps/openmw/mwgui/mapwindow.hpp index a5594bee8..a41d5d527 100644 --- a/apps/openmw/mwgui/mapwindow.hpp +++ b/apps/openmw/mwgui/mapwindow.hpp @@ -190,7 +190,8 @@ namespace MWGui void renderGlobalMap(Loading::Listener* loadingListener); - // adds the marker to the global map + /// adds the marker to the global map + /// @param name The ESM::Cell::mName void addVisitedLocation(const std::string& name, int x, int y); // reveals this cell's map on the global map diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 4552c42f2..db5593704 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -993,7 +993,7 @@ namespace MWGui if (cell->getCell()->isExterior()) { if (!cell->getCell()->mName.empty()) - mMap->addVisitedLocation ("#{sCell=" + name + "}", cell->getCell()->getGridX (), cell->getCell()->getGridY ()); + mMap->addVisitedLocation (name, cell->getCell()->getGridX (), cell->getCell()->getGridY ()); mMap->cellExplored (cell->getCell()->getGridX(), cell->getCell()->getGridY()); } From d76fb2d26601bf6d082762b68b157860d41fec0a Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 14 Aug 2015 13:38:39 +0200 Subject: [PATCH 2033/3725] Apply disintegrate only to weapons and armor (Fixes #2853) --- apps/openmw/mwmechanics/spellcasting.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index eacd674ed..b98bf9f96 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -941,7 +941,8 @@ namespace MWMechanics MWWorld::InventoryStore& inv = ptr.getClass().getInventoryStore(ptr); MWWorld::ContainerStoreIterator item = inv.getSlot(slot); - if (item != inv.end()) + + if (item != inv.end() && (item.getType() == MWWorld::ContainerStore::Type_Armor || item.getType() == MWWorld::ContainerStore::Type_Weapon)) { if (!item->getClass().hasItemHealth(*item)) return false; From c57e72fe03c35e3c888e7e894f718914ef71744d Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 15 Aug 2015 16:09:53 +0200 Subject: [PATCH 2034/3725] Adjust the sleep interruption chance (Fixes #2781) --- apps/openmw/mwgui/waitdialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index 4aeec146f..37a827745 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -157,7 +157,7 @@ namespace MWGui // figure out if player will be woken while sleeping int x = Misc::Rng::rollDice(hoursToWait); float fSleepRandMod = world->getStore().get().find("fSleepRandMod")->getFloat(); - if (x < fSleepRandMod * hoursToWait) + if (x < static_cast(fSleepRandMod * hoursToWait)) { float fSleepRestMod = world->getStore().get().find("fSleepRestMod")->getFloat(); mInterruptAt = hoursToWait - int(fSleepRestMod * hoursToWait); From e36ebc77d57e48973b9514e31a0d82aa02547fa5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 15 Aug 2015 18:39:00 +0200 Subject: [PATCH 2035/3725] Editor: remove creature flag of unknown purpose from the UI --- apps/opencs/model/world/columns.cpp | 1 - apps/opencs/model/world/columns.hpp | 2 +- apps/opencs/model/world/refidcollection.cpp | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 579bc9899..177fb59ce 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -109,7 +109,6 @@ namespace CSMWorld { ColumnId_OriginalCreature, "Original Creature" }, { ColumnId_Biped, "Biped" }, { ColumnId_HasWeapon, "Has Weapon" }, - { ColumnId_NoMovement, "No Movement" }, { ColumnId_Swims, "Swims" }, { ColumnId_Flies, "Flies" }, { ColumnId_Walks, "Walks" }, diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 5dfa479f6..2f66542b1 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -102,7 +102,7 @@ namespace CSMWorld ColumnId_OriginalCreature = 87, ColumnId_Biped = 88, ColumnId_HasWeapon = 89, - ColumnId_NoMovement = 90, + // unused ColumnId_Swims = 91, ColumnId_Flies = 92, ColumnId_Walks = 93, diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 5b2d184a7..16da4aad9 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -321,7 +321,6 @@ CSMWorld::RefIdCollection::RefIdCollection() { { Columns::ColumnId_Biped, ESM::Creature::Bipedal }, { Columns::ColumnId_HasWeapon, ESM::Creature::Weapon }, - { Columns::ColumnId_NoMovement, ESM::Creature::None }, { Columns::ColumnId_Swims, ESM::Creature::Swims }, { Columns::ColumnId_Flies, ESM::Creature::Flies }, { Columns::ColumnId_Walks, ESM::Creature::Walks }, From 58cd2b1a84828f406e2970b7d688fc1e01b0ba38 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 15 Aug 2015 19:01:21 +0200 Subject: [PATCH 2036/3725] Remove "Tri Bip*" nodes in creature meshes (meant for debugging)? (Fixes #2148) --- apps/openmw/mwrender/animation.cpp | 43 +++++++++++++++++++++- apps/openmw/mwrender/animation.hpp | 2 +- apps/openmw/mwrender/creatureanimation.cpp | 4 +- apps/openmw/mwrender/npcanimation.cpp | 2 +- 4 files changed, 45 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index ee0ce6df1..c1ae5fed5 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -208,6 +208,38 @@ namespace std::vector mToRemove; }; + class RemoveTriBipVisitor : public osg::NodeVisitor + { + public: + RemoveTriBipVisitor() + : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) + { + } + + virtual void apply(osg::Geode &node) + { + const std::string toFind = "tri bip"; + if (Misc::StringUtils::ciCompareLen(node.getName(), toFind, toFind.size()) == 0) + { + // Not safe to remove in apply(), since the visitor is still iterating the child list + mToRemove.push_back(&node); + } + } + + void remove() + { + for (std::vector::iterator it = mToRemove.begin(); it != mToRemove.end(); ++it) + { + osg::Node* node = *it; + if (node->getNumParents()) + node->getParent(0)->removeChild(node); + } + } + + private: + std::vector mToRemove; + }; + } namespace MWRender @@ -898,7 +930,7 @@ namespace MWRender return movement; } - void Animation::setObjectRoot(const std::string &model, bool forceskeleton, bool baseonly) + void Animation::setObjectRoot(const std::string &model, bool forceskeleton, bool baseonly, bool isCreature) { if (mObjectRoot) { @@ -933,6 +965,13 @@ namespace MWRender removeDrawableVisitor.remove(); } + if (isCreature) + { + RemoveTriBipVisitor removeTriBipVisitor; + mObjectRoot->accept(removeTriBipVisitor); + removeTriBipVisitor.remove(); + } + NodeMapVisitor visitor; mObjectRoot->accept(visitor); mNodeMap = visitor.getNodeMap(); @@ -1308,7 +1347,7 @@ namespace MWRender { if (!model.empty()) { - setObjectRoot(model, false, false); + setObjectRoot(model, false, false, false); if (animated) addAnimSource(model); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 23f807238..30b6d156a 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -273,7 +273,7 @@ protected: * @param baseonly If true, then any meshes or particle systems in the model are ignored * (useful for NPCs, where only the skeleton is needed for the root, and the actual NPC parts are then assembled from separate files). */ - void setObjectRoot(const std::string &model, bool forceskeleton, bool baseonly); + void setObjectRoot(const std::string &model, bool forceskeleton, bool baseonly, bool isCreature); /* Adds the keyframe controllers in the specified model as a new animation source. Note that * the filename portion of the provided model name will be prepended with 'x', and the .nif diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index 35294b1b5..f46736a39 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -24,7 +24,7 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr, if(!model.empty()) { - setObjectRoot(model, false, false); + setObjectRoot(model, false, false, true); if((ref->mBase->mFlags&ESM::Creature::Bipedal)) addAnimSource("meshes\\xbase_anim.nif"); @@ -42,7 +42,7 @@ CreatureWeaponAnimation::CreatureWeaponAnimation(const MWWorld::Ptr &ptr, const if(!model.empty()) { - setObjectRoot(model, true, false); + setObjectRoot(model, true, false, true); if((ref->mBase->mFlags&ESM::Creature::Bipedal)) addAnimSource("meshes\\xbase_anim.nif"); diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 6417bc812..c5a107837 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -378,7 +378,7 @@ void NpcAnimation::updateNpcBase() : "meshes\\wolf\\skin.1st.nif"); smodel = Misc::ResourceHelpers::correctActorModelPath(smodel, mResourceSystem->getVFS()); - setObjectRoot(smodel, true, true); + setObjectRoot(smodel, true, true, false); if(mViewMode != VM_FirstPerson) { From 7dd09dd637c317d3d94497b9d1cca4e1c4e54420 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 15 Aug 2015 20:44:15 +0200 Subject: [PATCH 2037/3725] Fix being able to flip journal pages with the mousewheel when the options overlay is active (Fixes #2855) --- apps/openmw/mwgui/journalwindow.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index 4cfcc8064..8238f6585 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -61,6 +61,7 @@ namespace DisplayStateStack mStates; Book mTopicIndexBook; bool mQuestMode; + bool mOptionsMode; bool mAllQuests; template @@ -182,6 +183,7 @@ namespace mQuestMode = false; mAllQuests = false; + mOptionsMode = false; } void adjustButton (char const * name, bool optional = false) @@ -244,6 +246,7 @@ namespace void setBookMode () { + mOptionsMode = false; setVisible (OptionsBTN, true); setVisible (OptionsOverlay, false); @@ -253,6 +256,8 @@ namespace void setOptionsMode () { + mOptionsMode = true; + setVisible (OptionsBTN, false); setVisible (OptionsOverlay, true); @@ -508,6 +513,8 @@ namespace void notifyNextPage(MyGUI::Widget* _sender) { + if (mOptionsMode) + return; if (!mStates.empty ()) { unsigned int & page = mStates.top ().mPage; @@ -523,6 +530,8 @@ namespace void notifyPrevPage(MyGUI::Widget* _sender) { + if (mOptionsMode) + return; if (!mStates.empty ()) { unsigned int & page = mStates.top ().mPage; From 47ac20af40a8d322380e0e6d81a22812466e4666 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 15 Aug 2015 22:28:59 +0200 Subject: [PATCH 2038/3725] Workaround flipped cursor on OS X --- components/sdlutil/sdlcursormanager.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/components/sdlutil/sdlcursormanager.cpp b/components/sdlutil/sdlcursormanager.cpp index 89928d165..70a159306 100644 --- a/components/sdlutil/sdlcursormanager.cpp +++ b/components/sdlutil/sdlcursormanager.cpp @@ -126,7 +126,13 @@ namespace glViewport(0, 0, width, height); +#if defined(__APPLE__) + // FIXME: why are the extra flips needed on Mac? glReadPixels bug? + osg::ref_ptr geom = osg::createTexturedQuadGeometry(osg::Vec3(-1,1,0), osg::Vec3(2,0,0), osg::Vec3(0,-2,0)); +#else osg::ref_ptr geom = osg::createTexturedQuadGeometry(osg::Vec3(-1,-1,0), osg::Vec3(2,0,0), osg::Vec3(0,2,0)); +#endif + geom->drawImplementation(renderInfo); glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, resultImage->data()); From dbcce482a686f1b568663585d01e99b6fcab6447 Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Wed, 12 Aug 2015 00:38:02 +0200 Subject: [PATCH 2039/3725] OS X: enable high resolution mode for OpenMW & OpenCS We don't support retina completely yet, but it's still better than blurry mess, and Qt does pretty good job for OpenCS already. --- CMakeLists.txt | 2 +- apps/opencs/CMakeLists.txt | 1 + .../mac/{Info.plist => openmw-Info.plist.in} | 2 + files/mac/openmw-cs-Info.plist.in | 38 +++++++++++++++++++ 4 files changed, 42 insertions(+), 1 deletion(-) rename files/mac/{Info.plist => openmw-Info.plist.in} (95%) create mode 100644 files/mac/openmw-cs-Info.plist.in diff --git a/CMakeLists.txt b/CMakeLists.txt index ad3c21e53..1e966a163 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -289,7 +289,7 @@ if(MYGUI_STATIC) endif (MYGUI_STATIC) if (APPLE) - configure_file(${OpenMW_SOURCE_DIR}/files/mac/Info.plist + configure_file(${OpenMW_SOURCE_DIR}/files/mac/openmw-Info.plist.in "${APP_BUNDLE_DIR}/Contents/Info.plist") configure_file(${OpenMW_SOURCE_DIR}/files/mac/openmw.icns diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index e6dd045e1..b1953ee97 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -192,6 +192,7 @@ if(APPLE) MACOSX_BUNDLE_GUI_IDENTIFIER "org.openmw.opencs" MACOSX_BUNDLE_SHORT_VERSION_STRING ${OPENMW_VERSION} MACOSX_BUNDLE_BUNDLE_VERSION ${OPENMW_VERSION} + MACOSX_BUNDLE_INFO_PLIST "${CMAKE_SOURCE_DIR}/files/mac/openmw-cs-Info.plist.in" ) set_source_files_properties(${OPENCS_MAC_ICON} PROPERTIES diff --git a/files/mac/Info.plist b/files/mac/openmw-Info.plist.in similarity index 95% rename from files/mac/Info.plist rename to files/mac/openmw-Info.plist.in index f832b09c9..efd55ee5c 100644 --- a/files/mac/Info.plist +++ b/files/mac/openmw-Info.plist.in @@ -26,5 +26,7 @@ NSHumanReadableCopyright + NSHighResolutionCapable + diff --git a/files/mac/openmw-cs-Info.plist.in b/files/mac/openmw-cs-Info.plist.in new file mode 100644 index 000000000..684ad7908 --- /dev/null +++ b/files/mac/openmw-cs-Info.plist.in @@ -0,0 +1,38 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${MACOSX_BUNDLE_EXECUTABLE_NAME} + CFBundleGetInfoString + ${MACOSX_BUNDLE_INFO_STRING} + CFBundleIconFile + ${MACOSX_BUNDLE_ICON_FILE} + CFBundleIdentifier + ${MACOSX_BUNDLE_GUI_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleLongVersionString + ${MACOSX_BUNDLE_LONG_VERSION_STRING} + CFBundleName + ${MACOSX_BUNDLE_BUNDLE_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + ${MACOSX_BUNDLE_SHORT_VERSION_STRING} + CFBundleSignature + ???? + CFBundleVersion + ${MACOSX_BUNDLE_BUNDLE_VERSION} + CSResourcesFileMapped + + LSRequiresCarbon + + NSHumanReadableCopyright + ${MACOSX_BUNDLE_COPYRIGHT} + NSHighResolutionCapable + + + From af5ffa554821b4263c9a28ec279a48b1bd5937b2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 15 Aug 2015 22:53:29 +0200 Subject: [PATCH 2040/3725] Don't warn about SDL touch events --- components/sdlutil/sdlinputwrapper.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/components/sdlutil/sdlinputwrapper.cpp b/components/sdlutil/sdlinputwrapper.cpp index f607b7046..200d19bd8 100644 --- a/components/sdlutil/sdlinputwrapper.cpp +++ b/components/sdlutil/sdlinputwrapper.cpp @@ -138,6 +138,16 @@ InputWrapper::InputWrapper(SDL_Window* window, osg::ref_ptr v break; case SDL_CLIPBOARDUPDATE: break; // We don't need this event, clipboard is retrieved on demand + + case SDL_FINGERDOWN: + case SDL_FINGERUP: + case SDL_FINGERMOTION: + case SDL_DOLLARGESTURE: + case SDL_DOLLARRECORD: + case SDL_MULTIGESTURE: + // No use for touch & gesture events + break; + default: std::ios::fmtflags f(std::cerr.flags()); std::cerr << "Unhandled SDL event of type 0x" << std::hex << evt.type << std::endl; From 82419763687c7afea51ec807324099bff925d77a Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 15 Aug 2015 23:27:37 +0200 Subject: [PATCH 2041/3725] Don't attempt to play non-existing hit animations (Fixes #2856) --- apps/openmw/mwmechanics/character.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 22ddf1fb7..3959c413a 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -247,15 +247,16 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat bool block = mPtr.getClass().getCreatureStats(mPtr).getBlock(); if(mHitState == CharState_None) { - if (mPtr.getClass().getCreatureStats(mPtr).getFatigue().getCurrent() < 0 + if ((mPtr.getClass().getCreatureStats(mPtr).getFatigue().getCurrent() < 0 || mPtr.getClass().getCreatureStats(mPtr).getFatigue().getBase() == 0) + && mAnimation->hasAnimation("knockout")) { mHitState = CharState_KnockOut; mCurrentHit = "knockout"; mAnimation->play(mCurrentHit, Priority_Knockdown, MWRender::Animation::BlendMask_All, false, 1, "start", "stop", 0.0f, ~0ul); mPtr.getClass().getCreatureStats(mPtr).setKnockedDown(true); } - else if(knockdown) + else if(knockdown && mAnimation->hasAnimation("knockdown")) { mHitState = CharState_KnockDown; mCurrentHit = "knockdown"; @@ -263,11 +264,15 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat } else if (recovery) { - mHitState = CharState_Hit; - mCurrentHit = chooseRandomGroup("hit"); - mAnimation->play(mCurrentHit, Priority_Hit, MWRender::Animation::BlendMask_All, true, 1, "start", "stop", 0.0f, 0); + std::string anim = chooseRandomGroup("hit"); + if (mAnimation->hasAnimation(anim)) + { + mHitState = CharState_Hit; + mCurrentHit = anim; + mAnimation->play(mCurrentHit, Priority_Hit, MWRender::Animation::BlendMask_All, true, 1, "start", "stop", 0.0f, 0); + } } - else if (block) + else if (block && mAnimation->hasAnimation("shield")) { mHitState = CharState_Block; mCurrentHit = "shield"; From c25dacb4802c97761e66b9d5f157d847951774b6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 16 Aug 2015 01:50:44 +0200 Subject: [PATCH 2042/3725] Fix "Level" string in the save/load menu not being localised (Bug #2840) --- apps/openmw/mwgui/savegamedialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index d490d49cd..ae36cbacc 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -347,7 +347,7 @@ namespace MWGui char buffer[size]; if (std::strftime(buffer, size, "%x %X", timeinfo) > 0) text << buffer << "\n"; - text << "Level " << mCurrentSlot->mProfile.mPlayerLevel << "\n"; + text << "#{sLevel} " << mCurrentSlot->mProfile.mPlayerLevel << "\n"; text << mCurrentSlot->mProfile.mPlayerCell << "\n"; // text << "Time played: " << slot->mProfile.mTimePlayed << "\n"; From afb3d94ba41263127d90416302ed26f97885fc98 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 16 Aug 2015 01:55:14 +0200 Subject: [PATCH 2043/3725] Fix cell names in the save/load menu not being localised (Fixes #2840) --- apps/openmw/mwgui/savegamedialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index ae36cbacc..82dd0d8a9 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -348,7 +348,7 @@ namespace MWGui if (std::strftime(buffer, size, "%x %X", timeinfo) > 0) text << buffer << "\n"; text << "#{sLevel} " << mCurrentSlot->mProfile.mPlayerLevel << "\n"; - text << mCurrentSlot->mProfile.mPlayerCell << "\n"; + text << "#{sCell=" << mCurrentSlot->mProfile.mPlayerCell << "}\n"; // text << "Time played: " << slot->mProfile.mTimePlayed << "\n"; int hour = int(mCurrentSlot->mProfile.mInGameTime.mGameHour); From 8426d376f02765a5e446c818a1f2d0b40c481f3a Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 16 Aug 2015 02:06:04 +0200 Subject: [PATCH 2044/3725] Use separate touch spell raycasts for actors and objects (Fixes #2849) --- apps/openmw/mwworld/worldimp.cpp | 34 ++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index fb2778940..f1bcec731 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2624,12 +2624,10 @@ namespace MWWorld { MWMechanics::CreatureStats& stats = actor.getClass().getCreatureStats(actor); - // Get the target to use for "on touch" effects + // Get the target to use for "on touch" effects, using the facing direction from Head node MWWorld::Ptr target; float distance = 192.f; // ?? osg::Vec3f hitPosition = actor.getRefData().getPosition().asVec3(); - - // For NPCs use facing direction from Head node osg::Vec3f origin(actor.getRefData().getPosition().asVec3()); MWRender::Animation* anim = mRendering->getAnimation(actor); @@ -2652,9 +2650,33 @@ namespace MWWorld osg::Vec3f direction = orient * osg::Vec3f(0,1,0); osg::Vec3f dest = origin + direction * distance; - MWPhysics::PhysicsSystem::RayResult result = mPhysics->castRay(origin, dest, actor); - target = result.mHitObject; - hitPosition = result.mHitPos; + // For actor targets, we want to use bounding boxes (physics raycast). + // This is to give a slight tolerance for errors, especially with creatures like the Skeleton that would be very hard to aim at otherwise. + // For object targets, we want the detailed shapes (rendering raycast). + // If we used the bounding boxes for static objects, then we would not be able to target e.g. objects lying on a shelf. + + MWPhysics::PhysicsSystem::RayResult result1 = mPhysics->castRay(origin, dest, actor, MWPhysics::CollisionType_Actor); + + MWRender::RenderingManager::RayResult result2 = mRendering->castRay(origin, dest, true, true); + + float dist1 = FLT_MAX; + float dist2 = FLT_MAX; + + if (result1.mHit) + dist1 = (origin - result1.mHitPos).length(); + if (result2.mHit) + dist2 = (origin - result2.mHitPointWorld).length(); + + if (dist1 <= dist2 && result1.mHit) + { + target = result1.mHitObject; + hitPosition = result1.mHitPos; + } + else if (result2.mHit) + { + target = result2.mHitObject; + hitPosition = result2.mHitPointWorld; + } std::string selectedSpell = stats.getSpells().getSelectedSpell(); From 3d419a612a1898847e5a536462072dae34ec0345 Mon Sep 17 00:00:00 2001 From: slothlife Date: Sat, 15 Aug 2015 23:38:49 -0500 Subject: [PATCH 2045/3725] Corrected some weather transition calculations Reversed some formulas for Transition Delta and Clouds Maximum Percent and implemented them. Refactored Weather some to encapsulate those formulas (to more closely match MoonModel). Did some small cleanup of WeatherManager. --- apps/openmw/mwworld/weather.cpp | 222 ++++++++++++++++---------------- apps/openmw/mwworld/weather.hpp | 68 ++++++---- 2 files changed, 153 insertions(+), 137 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 8d78b969e..99193de67 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -37,6 +37,68 @@ namespace } } +Weather::Weather(const std::string& name, + const MWWorld::Fallback& fallback, + float stormWindSpeed, + float rainSpeed, + const std::string& ambientLoopSoundID, + const std::string& particleEffect) + : mCloudTexture(fallback.getFallbackString("Weather_" + name + "_Cloud_Texture")) + , mSkySunriseColor(fallback.getFallbackColour("Weather_" + name +"_Sky_Sunrise_Color")) + , mSkyDayColor(fallback.getFallbackColour("Weather_" + name + "_Sky_Day_Color")) + , mSkySunsetColor(fallback.getFallbackColour("Weather_" + name + "_Sky_Sunset_Color")) + , mSkyNightColor(fallback.getFallbackColour("Weather_" + name + "_Sky_Night_Color")) + , mFogSunriseColor(fallback.getFallbackColour("Weather_" + name + "_Fog_Sunrise_Color")) + , mFogDayColor(fallback.getFallbackColour("Weather_" + name + "_Fog_Day_Color")) + , mFogSunsetColor(fallback.getFallbackColour("Weather_" + name + "_Fog_Sunset_Color")) + , mFogNightColor(fallback.getFallbackColour("Weather_" + name + "_Fog_Night_Color")) + , mAmbientSunriseColor(fallback.getFallbackColour("Weather_" + name + "_Ambient_Sunrise_Color")) + , mAmbientDayColor(fallback.getFallbackColour("Weather_" + name + "_Ambient_Day_Color")) + , mAmbientSunsetColor(fallback.getFallbackColour("Weather_" + name + "_Ambient_Sunset_Color")) + , mAmbientNightColor(fallback.getFallbackColour("Weather_" + name + "_Ambient_Night_Color")) + , mSunSunriseColor(fallback.getFallbackColour("Weather_" + name + "_Sun_Sunrise_Color")) + , mSunDayColor(fallback.getFallbackColour("Weather_" + name + "_Sun_Day_Color")) + , mSunSunsetColor(fallback.getFallbackColour("Weather_" + name + "_Sun_Sunset_Color")) + , mSunNightColor(fallback.getFallbackColour("Weather_" + name + "_Sun_Night_Color")) + , mLandFogDayDepth(fallback.getFallbackFloat("Weather_" + name + "_Land_Fog_Day_Depth")) + , mLandFogNightDepth(fallback.getFallbackFloat("Weather_" + name + "_Land_Fog_Night_Depth")) + , mSunDiscSunsetColor(fallback.getFallbackColour("Weather_" + name + "_Sun_Disc_Sunset_Color")) + , mWindSpeed(fallback.getFallbackFloat("Weather_" + name + "_Wind_Speed")) + , mCloudSpeed(fallback.getFallbackFloat("Weather_" + name + "_Cloud_Speed")) + , mGlareView(fallback.getFallbackFloat("Weather_" + name + "_Glare_View")) + , mAmbientLoopSoundID(ambientLoopSoundID) + , mIsStorm(mWindSpeed > stormWindSpeed) + , mRainSpeed(rainSpeed) + , mRainFrequency(fallback.getFallbackFloat("Weather_" + name + "_Rain_Entrance_Speed")) + , mParticleEffect(particleEffect) + , mRainEffect(fallback.getFallbackBool("Weather_" + name + "_Using_Precip") ? "meshes\\raindrop.nif" : "") + , mTransitionDelta(fallback.getFallbackFloat("Weather_" + name + "_Transition_Delta")) + , mCloudsMaximumPercent(fallback.getFallbackFloat("Weather_" + name + "_Clouds_Maximum_Percent")) +{ +/* +Unhandled: +Rain Diameter=600 ? +Rain Height Min=200 ? +Rain Height Max=700 ? +Rain Threshold=0.6 ? +Max Raindrops=650 ? +*/ +} + +float Weather::transitionSeconds() const +{ + // This formula is reversed from Morrowind by observing different Transition Delta values with Clouds + // Maximum Percent set to 1.0, and watching for when the light from the sun was no longer visible. + static const float deltasPerHour = 0.00835; + return (deltasPerHour / mTransitionDelta) * 60.0f * 60.0f; +} + +float Weather::cloudBlendFactor(float transitionRatio) const +{ + // Clouds Maximum Percent affects how quickly the sky transitions from one sky texture to the next. + return transitionRatio / mCloudsMaximumPercent; +} + MoonModel::MoonModel(const std::string& name, const MWWorld::Fallback& fallback) : mFadeInStart(fallback.getFallbackFloat("Moons_" + name + "_Fade_In_Start")) , mFadeInFinish(fallback.getFallbackFloat("Moons_" + name + "_Fade_In_Finish")) @@ -206,80 +268,29 @@ inline float MoonModel::earlyMoonShadowAlpha(float angle) const return 0.0f; } -void WeatherManager::setFallbackWeather(Weather& weather,const std::string& name) -{ - std::string upper=name; - upper[0]=toupper(name[0]); - weather.mCloudsMaximumPercent = mFallback->getFallbackFloat("Weather_"+upper+"_Clouds_Maximum_Percent"); - weather.mTransitionDelta = mFallback->getFallbackFloat("Weather_"+upper+"_Transition_Delta"); - weather.mSkySunriseColor=mFallback->getFallbackColour("Weather_"+upper+"_Sky_Sunrise_Color"); - weather.mSkyDayColor = mFallback->getFallbackColour("Weather_"+upper+"_Sky_Day_Color"); - weather.mSkySunsetColor = mFallback->getFallbackColour("Weather_"+upper+"_Sky_Sunset_Color"); - weather.mSkyNightColor = mFallback->getFallbackColour("Weather_"+upper+"_Sky_Night_Color"); - weather.mFogSunriseColor = mFallback->getFallbackColour("Weather_"+upper+"_Fog_Sunrise_Color"); - weather.mFogDayColor = mFallback->getFallbackColour("Weather_"+upper+"_Fog_Day_Color"); - weather.mFogSunsetColor = mFallback->getFallbackColour("Weather_"+upper+"_Fog_Sunset_Color"); - weather.mFogNightColor = mFallback->getFallbackColour("Weather_"+upper+"_Fog_Night_Color"); - weather.mAmbientSunriseColor = mFallback->getFallbackColour("Weather_"+upper+"_Ambient_Sunrise_Color"); - weather.mAmbientDayColor = mFallback->getFallbackColour("Weather_"+upper+"_Ambient_Day_Color"); - weather.mAmbientSunsetColor = mFallback->getFallbackColour("Weather_"+upper+"_Ambient_Sunset_Color"); - weather.mAmbientNightColor = mFallback->getFallbackColour("Weather_"+upper+"_Ambient_Night_Color"); - weather.mSunSunriseColor = mFallback->getFallbackColour("Weather_"+upper+"_Sun_Sunrise_Color"); - weather.mSunDayColor = mFallback->getFallbackColour("Weather_"+upper+"_Sun_Day_Color"); - weather.mSunSunsetColor = mFallback->getFallbackColour("Weather_"+upper+"_Sun_Sunset_Color"); - weather.mSunNightColor = mFallback->getFallbackColour("Weather_"+upper+"_Sun_Night_Color"); - weather.mSunDiscSunsetColor = mFallback->getFallbackColour("Weather_"+upper+"_Sun_Disc_Sunset_Color"); - weather.mLandFogDayDepth = mFallback->getFallbackFloat("Weather_"+upper+"_Land_Fog_Day_Depth"); - weather.mLandFogNightDepth = mFallback->getFallbackFloat("Weather_"+upper+"_Land_Fog_Night_Depth"); - weather.mWindSpeed = mFallback->getFallbackFloat("Weather_"+upper+"_Wind_Speed"); - weather.mCloudSpeed = mFallback->getFallbackFloat("Weather_"+upper+"_Cloud_Speed"); - weather.mGlareView = mFallback->getFallbackFloat("Weather_"+upper+"_Glare_View"); - weather.mCloudTexture = mFallback->getFallbackString("Weather_"+upper+"_Cloud_Texture"); - - static const float fStromWindSpeed = mStore->get().find("fStromWindSpeed")->getFloat(); - - weather.mIsStorm = weather.mWindSpeed > fStromWindSpeed; - - bool usesPrecip = mFallback->getFallbackBool("Weather_"+upper+"_Using_Precip"); - if (usesPrecip) - weather.mRainEffect = "meshes\\raindrop.nif"; - weather.mRainSpeed = mRainSpeed; - weather.mRainFrequency = mFallback->getFallbackFloat("Weather_"+upper+"_Rain_Entrance_Speed"); - /* -Unhandled: -Rain Diameter=600 ? -Rain Height Min=200 ? -Rain Height Max=700 ? -Rain Threshold=0.6 ? -Max Raindrops=650 ? -*/ - - mWeatherSettings[name] = weather; -} - WeatherManager::WeatherManager(MWRender::RenderingManager* rendering, MWWorld::Fallback* fallback, MWWorld::ESMStore* store) : - mHour(14), mWindSpeed(0.f), mIsStorm(false), mStormDirection(0,1,0), mFallback(fallback), mStore(store), + mHour(14), mWindSpeed(0.f), mIsStorm(false), mStormDirection(0,1,0), mStore(store), mRendering(rendering), mCurrentWeather("clear"), mNextWeather(""), mFirstUpdate(true), mRemainingTransitionTime(0), mThunderFlash(0), mThunderChance(0), mThunderChanceNeeded(50), mTimePassed(0), mWeatherUpdateTime(0), mThunderSoundDelay(0), mMasser("Masser", *fallback), mSecunda("Secunda", *fallback) { //Globals - mThunderSoundID0 = mFallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_0"); - mThunderSoundID1 = mFallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_1"); - mThunderSoundID2 = mFallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_2"); - mThunderSoundID3 = mFallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_3"); - mSunriseTime = mFallback->getFallbackFloat("Weather_Sunrise_Time"); - mSunsetTime = mFallback->getFallbackFloat("Weather_Sunset_Time"); - mSunriseDuration = mFallback->getFallbackFloat("Weather_Sunrise_Duration"); - mSunsetDuration = mFallback->getFallbackFloat("Weather_Sunset_Duration"); - mHoursBetweenWeatherChanges = mFallback->getFallbackFloat("Weather_Hours_Between_Weather_Changes"); + mThunderSoundID0 = fallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_0"); + mThunderSoundID1 = fallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_1"); + mThunderSoundID2 = fallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_2"); + mThunderSoundID3 = fallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_3"); + mSunriseTime = fallback->getFallbackFloat("Weather_Sunrise_Time"); + mSunsetTime = fallback->getFallbackFloat("Weather_Sunset_Time"); + mSunriseDuration = fallback->getFallbackFloat("Weather_Sunrise_Duration"); + mSunsetDuration = fallback->getFallbackFloat("Weather_Sunset_Duration"); + mHoursBetweenWeatherChanges = fallback->getFallbackFloat("Weather_Hours_Between_Weather_Changes"); mWeatherUpdateTime = mHoursBetweenWeatherChanges * 3600; - mThunderFrequency = mFallback->getFallbackFloat("Weather_Thunderstorm_Thunder_Frequency"); - mThunderThreshold = mFallback->getFallbackFloat("Weather_Thunderstorm_Thunder_Threshold"); + mThunderFrequency = fallback->getFallbackFloat("Weather_Thunderstorm_Thunder_Frequency"); + mThunderThreshold = fallback->getFallbackFloat("Weather_Thunderstorm_Thunder_Threshold"); mThunderSoundDelay = 0.25; - mRainSpeed = mFallback->getFallbackFloat("Weather_Precip_Gravity"); + mRainSpeed = fallback->getFallbackFloat("Weather_Precip_Gravity"); //Some useful values /* TODO: Use pre-sunrise_time, pre-sunset_time, @@ -292,47 +303,16 @@ WeatherManager::WeatherManager(MWRender::RenderingManager* rendering, MWWorld::F mDayStart = mSunriseTime + mSunriseDuration; mDayEnd = mSunsetTime; - //Weather - Weather clear; - setFallbackWeather(clear,"clear"); - - Weather cloudy; - setFallbackWeather(cloudy,"cloudy"); - - Weather foggy; - setFallbackWeather(foggy,"foggy"); - - Weather thunderstorm; - thunderstorm.mAmbientLoopSoundID = "rain heavy"; - thunderstorm.mRainEffect = "meshes\\raindrop.nif"; - setFallbackWeather(thunderstorm,"thunderstorm"); - - Weather rain; - rain.mAmbientLoopSoundID = "rain"; - rain.mRainEffect = "meshes\\raindrop.nif"; - setFallbackWeather(rain,"rain"); - - Weather overcast; - setFallbackWeather(overcast,"overcast"); - - Weather ashstorm; - ashstorm.mAmbientLoopSoundID = "ashstorm"; - ashstorm.mParticleEffect = "meshes\\ashcloud.nif"; - setFallbackWeather(ashstorm,"ashstorm"); - - Weather blight; - blight.mAmbientLoopSoundID = "blight"; - blight.mParticleEffect = "meshes\\blightcloud.nif"; - setFallbackWeather(blight,"blight"); - - Weather snow; - snow.mParticleEffect = "meshes\\snow.nif"; - setFallbackWeather(snow, "snow"); - - Weather blizzard; - blizzard.mAmbientLoopSoundID = "BM Blizzard"; - blizzard.mParticleEffect = "meshes\\blizzard.nif"; - setFallbackWeather(blizzard,"blizzard"); + addWeather("Clear", *fallback); + addWeather("Cloudy", *fallback); + addWeather("Foggy", *fallback); + addWeather("Overcast", *fallback); + addWeather("Rain", *fallback, "rain"); + addWeather("Thunderstorm", *fallback, "rain heavy"); + addWeather("Ashstorm", *fallback, "ashstorm", "meshes\\ashcloud.nif"); + addWeather("Blight", *fallback, "blight", "meshes\\blightcloud.nif"); + addWeather("Snow", *fallback, "", "meshes\\snow.nif"); + addWeather("Blizzard", *fallback, "BM Blizzard", "meshes\\blizzard.nif"); } WeatherManager::~WeatherManager() @@ -358,19 +338,19 @@ void WeatherManager::setWeather(const std::string& weather, bool instant) if (mNextWeather != "") { // transition more than 50% finished? - if (mRemainingTransitionTime/(mWeatherSettings[mCurrentWeather].mTransitionDelta * 24.f * 3600) <= 0.5) + if (mRemainingTransitionTime / (findWeather(mCurrentWeather).transitionSeconds()) <= 0.5) mCurrentWeather = mNextWeather; } mNextWeather = weather; - mRemainingTransitionTime = mWeatherSettings[mCurrentWeather].mTransitionDelta * 24.f * 3600.f; + mRemainingTransitionTime = findWeather(mCurrentWeather).transitionSeconds(); } mFirstUpdate = false; } void WeatherManager::setResult(const std::string& weatherType) { - const Weather& current = mWeatherSettings[weatherType]; + const Weather& current = findWeather(weatherType); mResult.mCloudTexture = current.mCloudTexture; mResult.mCloudBlendFactor = 0; @@ -473,9 +453,11 @@ void WeatherManager::transition(float factor) setResult(mNextWeather); const MWRender::WeatherResult other = mResult; + const Weather& nextWeather = findWeather(mNextWeather); + mResult.mCloudTexture = current.mCloudTexture; mResult.mNextCloudTexture = other.mCloudTexture; - mResult.mCloudBlendFactor = factor; + mResult.mCloudBlendFactor = nextWeather.cloudBlendFactor(factor); mResult.mFogColor = lerp(current.mFogColor, other.mFogColor, factor); mResult.mSunColor = lerp(current.mSunColor, other.mSunColor, factor); @@ -547,7 +529,7 @@ void WeatherManager::update(float duration, bool paused) } if (mNextWeather != "") - transition(1 - (mRemainingTransitionTime / (mWeatherSettings[mCurrentWeather].mTransitionDelta * 24.f * 3600))); + transition(1 - (mRemainingTransitionTime / (findWeather(mCurrentWeather).transitionSeconds()))); else setResult(mCurrentWeather); @@ -945,3 +927,23 @@ void WeatherManager::advanceTime(double hours) { mTimePassed += hours*3600; } + +inline void WeatherManager::addWeather(const std::string& name, + const MWWorld::Fallback& fallback, + const std::string& ambientLoopSoundID, + const std::string& particleEffect) +{ + static const float fStromWindSpeed = mStore->get().find("fStromWindSpeed")->getFloat(); + + Weather weather(name, fallback, fStromWindSpeed, mRainSpeed, ambientLoopSoundID, particleEffect); + + std::string lower = name; + lower[0] = tolower(lower[0]); + mWeatherSettings.insert(std::make_pair(lower, weather)); +} + +inline Weather& WeatherManager::findWeather(const std::string& name) +{ + return mWeatherSettings.at(name); +} + diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index 7f4858bc8..710e45d9b 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -33,53 +33,55 @@ namespace MWWorld class Fallback; /// Defines a single weather setting (according to INI) - struct Weather + class Weather { + public: + Weather(const std::string& name, + const MWWorld::Fallback& fallback, + float stormWindSpeed, + float rainSpeed, + const std::string& ambientLoopSoundID, + const std::string& particleEffect); + std::string mCloudTexture; // Sky (atmosphere) colors - osg::Vec4f mSkySunriseColor, - mSkyDayColor, - mSkySunsetColor, - mSkyNightColor; + osg::Vec4f mSkySunriseColor; + osg::Vec4f mSkyDayColor; + osg::Vec4f mSkySunsetColor; + osg::Vec4f mSkyNightColor; // Fog colors - osg::Vec4f mFogSunriseColor, - mFogDayColor, - mFogSunsetColor, - mFogNightColor; + osg::Vec4f mFogSunriseColor; + osg::Vec4f mFogDayColor; + osg::Vec4f mFogSunsetColor; + osg::Vec4f mFogNightColor; // Ambient lighting colors - osg::Vec4f mAmbientSunriseColor, - mAmbientDayColor, - mAmbientSunsetColor, - mAmbientNightColor; + osg::Vec4f mAmbientSunriseColor; + osg::Vec4f mAmbientDayColor; + osg::Vec4f mAmbientSunsetColor; + osg::Vec4f mAmbientNightColor; // Sun (directional) lighting colors - osg::Vec4f mSunSunriseColor, - mSunDayColor, - mSunSunsetColor, - mSunNightColor; + osg::Vec4f mSunSunriseColor; + osg::Vec4f mSunDayColor; + osg::Vec4f mSunSunsetColor; + osg::Vec4f mSunNightColor; // Fog depth/density - float mLandFogDayDepth, - mLandFogNightDepth; + float mLandFogDayDepth; + float mLandFogNightDepth; // Color modulation for the sun itself during sunset (not completely sure) osg::Vec4f mSunDiscSunsetColor; - // Duration of weather transition (in days) - float mTransitionDelta; - // Used by scripts to animate signs, etc based on the wind (GetWindSpeed) float mWindSpeed; // Cloud animation speed multiplier float mCloudSpeed; - // TODO: What is this supposed to do? - float mCloudsMaximumPercent; - // Value between 0 and 1, defines the strength of the sun glare effect. // Also appears to modify how visible the sun, moons, and stars are for various weather effects. float mGlareView; @@ -107,6 +109,13 @@ namespace MWWorld // Note: For Weather Blight, there is a "Disease Chance" (=0.1) setting. But according to MWSFD this feature // is broken in the vanilla game and was disabled. + + float transitionSeconds() const; + float cloudBlendFactor(float transitionRatio) const; + + private: + float mTransitionDelta; + float mCloudsMaximumPercent; }; class MoonModel @@ -197,9 +206,7 @@ namespace MWWorld MWBase::SoundPtr mAmbientSound; std::string mPlayingSoundID; - MWWorld::Fallback* mFallback; MWWorld::ESMStore* mStore; - void setFallbackWeather(Weather& weather,const std::string& name); MWRender::RenderingManager* mRendering; std::map mWeatherSettings; @@ -251,6 +258,13 @@ namespace MWWorld std::string mThunderSoundID3; MoonModel mMasser; MoonModel mSecunda; + + void addWeather(const std::string& name, + const MWWorld::Fallback& fallback, + const std::string& ambientLoopSoundID = "", + const std::string& particleEffect = ""); + + Weather& findWeather(const std::string& name); }; } From 5049c9ab6a85a58c0b56c2498ea55f36e359a397 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 16 Aug 2015 17:41:33 +1200 Subject: [PATCH 2046/3725] removed unnecessary tests. --- apps/openmw/mwmechanics/pathfinding.cpp | 34 ++++++++++++------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index f469832a5..d8e6a37b7 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -25,8 +25,7 @@ namespace // int getClosestPoint(const ESM::Pathgrid* grid, const osg::Vec3f& pos) { - if(!grid || grid->mPoints.empty()) - return -1; + assert(grid && !grid->mPoints.empty()); float distanceBetween = distanceSquared(grid->mPoints[0], pos); int closestIndex = 0; @@ -228,21 +227,22 @@ namespace MWMechanics } mPath = mCell->aStarSearch(startNode, endNode.first); - - if(!mPath.empty()) - { - // Add the destination (which may be different to the closest - // pathgrid point). However only add if endNode was the closest - // point to endPoint. - // - // This logic can fail in the opposite situate, e.g. endPoint may - // have been reachable but happened to be very close to an - // unreachable pathgrid point. - // - // The AI routines will have to deal with such situations. - if(endNode.second) - mPath.push_back(endPoint); - } + assert(!mPath.empty()); + + // If endNode found is NOT the closest PathGrid point to the endPoint, + // assume endPoint is not reachable from endNode. In which case, + // path ends at endNode. + // + // So only add the destination (which may be different to the closest + // pathgrid point) when endNode was the closest point to endPoint. + // + // This logic can fail in the opposite situate, e.g. endPoint may + // have been reachable but happened to be very close to an + // unreachable pathgrid point. + // + // The AI routines will have to deal with such situations. + if(endNode.second) + mPath.push_back(endPoint); return; } From 942a987d528de8202e15c63607a20539675d3b85 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 16 Aug 2015 18:55:02 +1200 Subject: [PATCH 2047/3725] centralize the world/cell coordinate conversion logic. --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwmechanics/aiwander.cpp | 13 ++---- .../mwmechanics/coordinateconverter.cpp | 43 +++++++++++++++++++ .../mwmechanics/coordinateconverter.hpp | 37 ++++++++++++++++ apps/openmw/mwmechanics/pathfinding.cpp | 24 +++++------ apps/openmw/mwmechanics/pathgrid.cpp | 20 ++------- apps/openmw/mwrender/pathgrid.cpp | 7 +-- 7 files changed, 99 insertions(+), 47 deletions(-) create mode 100644 apps/openmw/mwmechanics/coordinateconverter.cpp create mode 100644 apps/openmw/mwmechanics/coordinateconverter.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index cd1ac31ec..c33b711e6 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -82,7 +82,7 @@ add_openmw_dir (mwmechanics drawstate spells activespells npcstats aipackage aisequence aipursue alchemy aiwander aitravel aifollow aiavoiddoor aiescort aiactivate aicombat repair enchanting pathfinding pathgrid security spellsuccess spellcasting disease pickpocket levelledlist combat steering obstacle autocalcspell difficultyscaling aicombataction actor summoning - character actors objects aistate + character actors objects aistate coordinateconverter ) add_openmw_dir (mwstate diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 440814fb7..afe34218e 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -20,6 +20,7 @@ #include "creaturestats.hpp" #include "steering.hpp" #include "movement.hpp" +#include "coordinateconverter.hpp" @@ -587,11 +588,7 @@ namespace MWMechanics void AiWander::ToWorldCoordinates(ESM::Pathgrid::Point& point, const ESM::Cell * cell) { - if (cell->isExterior()) - { - point.mX += cell->mData.mX * ESM::Land::REAL_SIZE; - point.mY += cell->mData.mY * ESM::Land::REAL_SIZE; - } + CoordinateConverter(cell).ToWorld(point); } void AiWander::trimAllowedNodes(std::vector& nodes, @@ -749,11 +746,7 @@ namespace MWMechanics { // get NPC's position in local (i.e. cell) co-ordinates osg::Vec3f npcPos(mInitialActorPosition); - if(cell->isExterior()) - { - npcPos[0] = npcPos[0] - static_cast(cell->mData.mX * ESM::Land::REAL_SIZE); - npcPos[1] = npcPos[1] - static_cast(cell->mData.mY * ESM::Land::REAL_SIZE); - } + CoordinateConverter(cell).ToLocal(npcPos); // mAllowedNodes for this actor with pathgrid point indexes based on mDistance // NOTE: mPoints and mAllowedNodes are in local co-ordinates diff --git a/apps/openmw/mwmechanics/coordinateconverter.cpp b/apps/openmw/mwmechanics/coordinateconverter.cpp new file mode 100644 index 000000000..583ac41c5 --- /dev/null +++ b/apps/openmw/mwmechanics/coordinateconverter.cpp @@ -0,0 +1,43 @@ +#include "coordinateconverter.hpp" + +#include +#include + +namespace MWMechanics +{ + CoordinateConverter::CoordinateConverter(const ESM::Cell* cell) + : mCellX(0), mCellY(0) + { + if (cell->isExterior()) + { + mCellX = cell->mData.mX * ESM::Land::REAL_SIZE; + mCellY = cell->mData.mY * ESM::Land::REAL_SIZE; + } + } + + void CoordinateConverter::ToWorld(ESM::Pathgrid::Point& point) + { + point.mX += mCellX; + point.mY += mCellY; + } + + void CoordinateConverter::ToWorld(osg::Vec3f& point) + { + point.x() += static_cast(mCellX); + point.y() += static_cast(mCellY); + } + + void CoordinateConverter::ToLocal(osg::Vec3f& point) + { + point.x() -= static_cast(mCellX); + point.y() -= static_cast(mCellY); + } + + osg::Vec3f CoordinateConverter::ToLocalVec3(const ESM::Pathgrid::Point& point) + { + return osg::Vec3f( + static_cast(point.mX - mCellX), + static_cast(point.mY - mCellY), + static_cast(point.mZ)); + } +} diff --git a/apps/openmw/mwmechanics/coordinateconverter.hpp b/apps/openmw/mwmechanics/coordinateconverter.hpp new file mode 100644 index 000000000..2c4d3d3ba --- /dev/null +++ b/apps/openmw/mwmechanics/coordinateconverter.hpp @@ -0,0 +1,37 @@ +#ifndef GAME_MWMECHANICS_COORDINATECONVERTER_H +#define GAME_MWMECHANICS_COORDINATECONVERTER_H + +#include +#include + +namespace ESM +{ + struct Cell; +} + +namespace MWMechanics +{ + /// \brief convert coordinates between world and local cell + class CoordinateConverter + { + public: + CoordinateConverter(const ESM::Cell* cell); + + /// in-place conversion from local to world + void ToWorld(ESM::Pathgrid::Point& point); + + /// in-place conversion from local to world + void ToWorld(osg::Vec3f& point); + + /// in-place conversion from world to local + void ToLocal(osg::Vec3f& point); + + osg::Vec3f ToLocalVec3(const ESM::Pathgrid::Point& point); + + private: + int mCellX; + int mCellY; + }; +} + +#endif diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index d8e6a37b7..1147371b1 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -5,6 +5,7 @@ #include "../mwworld/esmstore.hpp" #include "../mwworld/cellstore.hpp" +#include "coordinateconverter.hpp" namespace { @@ -106,11 +107,6 @@ namespace MWMechanics return sqrt(x * x + y * y + z * z); } - osg::Vec3f ToLocalCoordinates(const ESM::Pathgrid::Point &point, float xCell, float yCell) - { - return osg::Vec3f(point.mX - xCell, point.mY - yCell, static_cast(point.mZ)); - } - PathFinder::PathFinder() : mPathgrid(NULL), mCell(NULL) @@ -194,23 +190,17 @@ namespace MWMechanics } // NOTE: getClosestPoint expects local co-ordinates - float xCell = 0; - float yCell = 0; - if (mCell->isExterior()) - { - xCell = static_cast(mCell->getCell()->mData.mX * ESM::Land::REAL_SIZE); - yCell = static_cast(mCell->getCell()->mData.mY * ESM::Land::REAL_SIZE); - } + CoordinateConverter converter(mCell->getCell()); // NOTE: It is possible that getClosestPoint returns a pathgrind point index // that is unreachable in some situations. e.g. actor is standing // outside an area enclosed by walls, but there is a pathgrid // point right behind the wall that is closer than any pathgrid // point outside the wall - osg::Vec3f startPointInLocalCoords(ToLocalCoordinates(startPoint, xCell, yCell)); + osg::Vec3f startPointInLocalCoords(converter.ToLocalVec3(startPoint)); int startNode = getClosestPoint(mPathgrid, startPointInLocalCoords); - osg::Vec3f endPointInLocalCoords(ToLocalCoordinates(endPoint, xCell, yCell)); + osg::Vec3f endPointInLocalCoords(converter.ToLocalVec3(endPoint)); std::pair endNode = getClosestReachablePoint(mPathgrid, cell, endPointInLocalCoords, startNode); @@ -229,6 +219,12 @@ namespace MWMechanics mPath = mCell->aStarSearch(startNode, endNode.first); assert(!mPath.empty()); + // convert supplied path to world co-ordinates + for (std::list::iterator iter(mPath.begin()); iter != mPath.end(); ++iter) + { + converter.ToWorld(*iter); + } + // If endNode found is NOT the closest PathGrid point to the endPoint, // assume endPoint is not reachable from endNode. In which case, // path ends at endNode. diff --git a/apps/openmw/mwmechanics/pathgrid.cpp b/apps/openmw/mwmechanics/pathgrid.cpp index 66af864ea..871baecdc 100644 --- a/apps/openmw/mwmechanics/pathgrid.cpp +++ b/apps/openmw/mwmechanics/pathgrid.cpp @@ -312,29 +312,15 @@ namespace MWMechanics if(current != goal) return path; // for some reason couldn't build a path - // reconstruct path to return, using world co-ordinates - int xCell = 0; - int yCell = 0; - if (mIsExterior) - { - xCell = mPathgrid->mData.mX * ESM::Land::REAL_SIZE; - yCell = mPathgrid->mData.mY * ESM::Land::REAL_SIZE; - } - + // reconstruct path to return, using local co-ordinates while(graphParent[current] != -1) { - ESM::Pathgrid::Point pt = mPathgrid->mPoints[current]; - pt.mX += xCell; - pt.mY += yCell; - path.push_front(pt); + path.push_front(mPathgrid->mPoints[current]); current = graphParent[current]; } // add first node to path explicitly - ESM::Pathgrid::Point pt = mPathgrid->mPoints[start]; - pt.mX += xCell; - pt.mY += yCell; - path.push_front(pt); + path.push_front(mPathgrid->mPoints[start]); return path; } } diff --git a/apps/openmw/mwrender/pathgrid.cpp b/apps/openmw/mwrender/pathgrid.cpp index 9fffd76d1..bd22446de 100644 --- a/apps/openmw/mwrender/pathgrid.cpp +++ b/apps/openmw/mwrender/pathgrid.cpp @@ -17,6 +17,7 @@ #include "../mwworld/cellstore.hpp" #include "../mwworld/esmstore.hpp" #include "../mwmechanics/pathfinding.hpp" +#include "../mwmechanics/coordinateconverter.hpp" #include "vismask.hpp" @@ -207,11 +208,7 @@ void Pathgrid::enableCellPathgrid(const MWWorld::CellStore *store) if (!pathgrid) return; osg::Vec3f cellPathGridPos(0, 0, 0); - if (store->getCell()->isExterior()) - { - cellPathGridPos.x() = static_cast(store->getCell()->mData.mX * ESM::Land::REAL_SIZE); - cellPathGridPos.y() = static_cast(store->getCell()->mData.mY * ESM::Land::REAL_SIZE); - } + MWMechanics::CoordinateConverter(store->getCell()).ToWorld(cellPathGridPos); osg::ref_ptr cellPathGrid = new osg::PositionAttitudeTransform; cellPathGrid->setPosition(cellPathGridPos); From 4d9d8a060d6821744e03ea5ddbfcd298885219c2 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 16 Aug 2015 18:56:28 +1200 Subject: [PATCH 2048/3725] Pathing bugfix. When path contains one one point from path grid, point is no longer being discarded. --- apps/openmw/mwmechanics/pathfinding.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index 1147371b1..777ccacae 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -212,6 +212,10 @@ namespace MWMechanics // nodes are the same if(startNode == endNode.first) { + ESM::Pathgrid::Point temp(mPathgrid->mPoints[startNode]); + converter.ToWorld(temp); + mPath.push_back(temp); + mPath.push_back(endPoint); return; } From 1b663f01aff94811a46825467cad8f38ed025b24 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 16 Aug 2015 15:24:48 +0200 Subject: [PATCH 2049/3725] create merged document and open a view for it (document is still empty at this point) --- apps/opencs/CMakeLists.txt | 8 +++++-- apps/opencs/editor.cpp | 3 ++- apps/opencs/model/doc/document.cpp | 4 +++- apps/opencs/model/doc/document.hpp | 6 ++++- apps/opencs/model/doc/documentmanager.cpp | 16 ++++++++++++- apps/opencs/model/doc/documentmanager.hpp | 13 +++++++++++ apps/opencs/model/doc/operation.hpp | 4 +++- apps/opencs/model/tools/mergeoperation.cpp | 15 +++++++++++-- apps/opencs/model/tools/mergeoperation.hpp | 19 ++++++++++++++-- apps/opencs/model/tools/mergestages.cpp | 18 +++++++++++++++ apps/opencs/model/tools/mergestages.hpp | 26 ++++++++++++++++++++++ apps/opencs/model/tools/mergestate.hpp | 20 +++++++++++++++++ apps/opencs/model/tools/tools.cpp | 4 +++- apps/opencs/model/tools/tools.hpp | 7 +++++- apps/opencs/view/tools/merge.cpp | 13 ++++++++--- apps/opencs/view/tools/merge.hpp | 4 +++- 16 files changed, 163 insertions(+), 17 deletions(-) create mode 100644 apps/opencs/model/tools/mergestages.cpp create mode 100644 apps/opencs/model/tools/mergestages.hpp create mode 100644 apps/opencs/model/tools/mergestate.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 833ca6551..091b566d1 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -35,14 +35,18 @@ opencs_hdrs_noqt (model/world opencs_units (model/tools - tools reportmodel + tools reportmodel mergeoperation ) opencs_units_noqt (model/tools mandatoryid skillcheck classcheck factioncheck racecheck soundcheck regioncheck birthsigncheck spellcheck referencecheck referenceablecheck scriptcheck bodypartcheck startscriptcheck search searchoperation searchstage pathgridcheck soundgencheck - mergeoperation + mergestages + ) + +opencs_hdrs_noqt (model/tools + mergestate ) diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 0b385f275..7f9e2746e 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -21,7 +21,8 @@ CS::Editor::Editor () : mUserSettings (mCfgMgr), mDocumentManager (mCfgMgr), mViewManager (mDocumentManager), mPid(""), - mLock(), mIpcServerName ("org.openmw.OpenCS"), mServer(NULL), mClientSocket(NULL) + mLock(), mMerge (mDocumentManager), + mIpcServerName ("org.openmw.OpenCS"), mServer(NULL), mClientSocket(NULL) { std::pair > config = readConfig(); diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index a331706bc..67ecbd641 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -2294,6 +2294,8 @@ CSMDoc::Document::Document (const VFS::Manager* vfs, const Files::ConfigurationM connect (&mTools, SIGNAL (progress (int, int, int)), this, SLOT (progress (int, int, int))); connect (&mTools, SIGNAL (done (int, bool)), this, SLOT (operationDone (int, bool))); + connect (&mTools, SIGNAL (mergeDone (CSMDoc::Document*)), + this, SIGNAL (mergeDone (CSMDoc::Document*))); connect (&mSaving, SIGNAL (progress (int, int, int)), this, SLOT (progress (int, int, int))); connect (&mSaving, SIGNAL (done (int, bool)), this, SLOT (operationDone (int, bool))); @@ -2388,7 +2390,7 @@ void CSMDoc::Document::runSearch (const CSMWorld::UniversalId& searchId, const C emit stateChanged (getState(), this); } -void CSMDoc::Document::runMerge (const boost::filesystem::path& target) +void CSMDoc::Document::runMerge (std::auto_ptr target) { mTools.runMerge (target); emit stateChanged (getState(), this); diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp index 901a8e3e4..3eaa5bb14 100644 --- a/apps/opencs/model/doc/document.hpp +++ b/apps/opencs/model/doc/document.hpp @@ -130,7 +130,7 @@ namespace CSMDoc void runSearch (const CSMWorld::UniversalId& searchId, const CSMTools::Search& search); - void runMerge (const boost::filesystem::path& target); + void runMerge (std::auto_ptr target); void abortOperation (int type); @@ -158,6 +158,10 @@ namespace CSMDoc void progress (int current, int max, int type, int threads, CSMDoc::Document *document); + /// \attention When this signal is emitted, *this hands over the ownership of the + /// document. This signal must be handled to avoid a leak. + void mergeDone (CSMDoc::Document *document); + private slots: void modificationStateChanged (bool clean); diff --git a/apps/opencs/model/doc/documentmanager.cpp b/apps/opencs/model/doc/documentmanager.cpp index 02d4ab5c0..03758dc6a 100644 --- a/apps/opencs/model/doc/documentmanager.cpp +++ b/apps/opencs/model/doc/documentmanager.cpp @@ -57,10 +57,24 @@ bool CSMDoc::DocumentManager::isEmpty() void CSMDoc::DocumentManager::addDocument (const std::vector& files, const boost::filesystem::path& savePath, bool new_) { - Document *document = new Document (mVFS, mConfiguration, files, new_, savePath, mResDir, mEncoding, mResourcesManager, mBlacklistedScripts); + Document *document = makeDocument (files, savePath, new_); + insertDocument (document); +} + +CSMDoc::Document *CSMDoc::DocumentManager::makeDocument ( + const std::vector< boost::filesystem::path >& files, + const boost::filesystem::path& savePath, bool new_) +{ + return new Document (mVFS, mConfiguration, files, new_, savePath, mResDir, mEncoding, mResourcesManager, mBlacklistedScripts); +} +void CSMDoc::DocumentManager::insertDocument (CSMDoc::Document *document) +{ mDocuments.push_back (document); + connect (document, SIGNAL (mergeDone (CSMDoc::Document*)), + this, SLOT (insertDocument (CSMDoc::Document*))); + emit loadRequest (document); mLoader.hasThingsToDo().wakeAll(); diff --git a/apps/opencs/model/doc/documentmanager.hpp b/apps/opencs/model/doc/documentmanager.hpp index f9b18bfe6..4f6b2b2c9 100644 --- a/apps/opencs/model/doc/documentmanager.hpp +++ b/apps/opencs/model/doc/documentmanager.hpp @@ -56,6 +56,15 @@ namespace CSMDoc ///< \param new_ Do not load the last content file in \a files and instead create in an /// appropriate way. + /// Create a new document. The ownership of the created document is transferred to + /// the calling function. The DocumentManager does not manage it. Loading has not + /// taken place at the point when the document is returned. + /// + /// \param new_ Do not load the last content file in \a files and instead create in an + /// appropriate way. + Document *makeDocument (const std::vector< boost::filesystem::path >& files, + const boost::filesystem::path& savePath, bool new_); + void setResourceDir (const boost::filesystem::path& parResDir); void setEncoding (ToUTF8::FromType encoding); @@ -84,6 +93,10 @@ namespace CSMDoc void removeDocument (CSMDoc::Document *document); ///< Emits the lastDocumentDeleted signal, if applicable. + /// Hand over document to *this. The ownership is transferred. The DocumentManager + /// will initiate the load procedure, if necessary + void insertDocument (CSMDoc::Document *document); + signals: void documentAdded (CSMDoc::Document *document); diff --git a/apps/opencs/model/doc/operation.hpp b/apps/opencs/model/doc/operation.hpp index 703f9d44b..3c86a6e23 100644 --- a/apps/opencs/model/doc/operation.hpp +++ b/apps/opencs/model/doc/operation.hpp @@ -83,7 +83,9 @@ namespace CSMDoc void executeStage(); - void operationDone(); + protected slots: + + virtual void operationDone(); }; } diff --git a/apps/opencs/model/tools/mergeoperation.cpp b/apps/opencs/model/tools/mergeoperation.cpp index 65cfdb4ff..c93452dad 100644 --- a/apps/opencs/model/tools/mergeoperation.cpp +++ b/apps/opencs/model/tools/mergeoperation.cpp @@ -2,14 +2,25 @@ #include "mergeoperation.hpp" #include "../doc/state.hpp" +#include "../doc/document.hpp" + +#include "mergestages.hpp" CSMTools::MergeOperation::MergeOperation (CSMDoc::Document& document) -: CSMDoc::Operation (CSMDoc::State_Merging, true) +: CSMDoc::Operation (CSMDoc::State_Merging, true), mState (document) { + appendStage (new FinishMergedDocumentStage (mState)); +} +void CSMTools::MergeOperation::setTarget (std::auto_ptr document) +{ + mState.mTarget = document; } -void CSMTools::MergeOperation::setTarget (const boost::filesystem::path& target) +void CSMTools::MergeOperation::operationDone() { + CSMDoc::Operation::operationDone(); + if (mState.mCompleted) + emit mergeDone (mState.mTarget.release()); } diff --git a/apps/opencs/model/tools/mergeoperation.hpp b/apps/opencs/model/tools/mergeoperation.hpp index 84526b2f2..dc958d31b 100644 --- a/apps/opencs/model/tools/mergeoperation.hpp +++ b/apps/opencs/model/tools/mergeoperation.hpp @@ -1,10 +1,12 @@ #ifndef CSM_TOOLS_MERGEOPERATION_H #define CSM_TOOLS_MERGEOPERATION_H -#include +#include #include "../doc/operation.hpp" +#include "mergestate.hpp" + namespace CSMDoc { class Document; @@ -14,14 +16,27 @@ namespace CSMTools { class MergeOperation : public CSMDoc::Operation { + Q_OBJECT + MergeState mState; public: MergeOperation (CSMDoc::Document& document); /// \attention Do not call this function while a merge is running. - void setTarget (const boost::filesystem::path& target); + void setTarget (std::auto_ptr document); + + protected slots: + + virtual void operationDone(); + + signals: + + /// \attention When this signal is emitted, *this hands over the ownership of the + /// document. This signal must be handled to avoid a leak. + void mergeDone (CSMDoc::Document *document); + }; } diff --git a/apps/opencs/model/tools/mergestages.cpp b/apps/opencs/model/tools/mergestages.cpp new file mode 100644 index 000000000..16ea0495a --- /dev/null +++ b/apps/opencs/model/tools/mergestages.cpp @@ -0,0 +1,18 @@ + +#include "mergestages.hpp" + +#include "mergestate.hpp" + +CSMTools::FinishMergedDocumentStage::FinishMergedDocumentStage (MergeState& state) +: mState (state) +{} + +int CSMTools::FinishMergedDocumentStage::setup() +{ + return 1; +} + +void CSMTools::FinishMergedDocumentStage::perform (int stage, CSMDoc::Messages& messages) +{ + mState.mCompleted = true; +} diff --git a/apps/opencs/model/tools/mergestages.hpp b/apps/opencs/model/tools/mergestages.hpp new file mode 100644 index 000000000..138b89d72 --- /dev/null +++ b/apps/opencs/model/tools/mergestages.hpp @@ -0,0 +1,26 @@ +#ifndef CSM_TOOLS_MERGESTAGES_H +#define CSM_TOOLS_MERGESTAGES_H + +#include "../doc/stage.hpp" + +namespace CSMTools +{ + struct MergeState; + + class FinishMergedDocumentStage : public CSMDoc::Stage + { + MergeState& mState; + + public: + + FinishMergedDocumentStage (MergeState& state); + + virtual int setup(); + ///< \return number of steps + + virtual void perform (int stage, CSMDoc::Messages& messages); + ///< Messages resulting from this stage will be appended to \a messages. + }; +} + +#endif diff --git a/apps/opencs/model/tools/mergestate.hpp b/apps/opencs/model/tools/mergestate.hpp new file mode 100644 index 000000000..4482ba6f4 --- /dev/null +++ b/apps/opencs/model/tools/mergestate.hpp @@ -0,0 +1,20 @@ +#ifndef CSM_TOOLS_MERGESTATE_H +#define CSM_TOOLS_MERGESTATE_H + +#include + +#include "../doc/document.hpp" + +namespace CSMTools +{ + struct MergeState + { + std::auto_ptr mTarget; + CSMDoc::Document& mSource; + bool mCompleted; + + MergeState (CSMDoc::Document& source) : mSource (source), mCompleted (false) {} + }; +} + +#endif diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index 681f74404..78b052813 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -195,7 +195,7 @@ void CSMTools::Tools::runSearch (const CSMWorld::UniversalId& searchId, const Se mSearch.start(); } -void CSMTools::Tools::runMerge (const boost::filesystem::path& target) +void CSMTools::Tools::runMerge (std::auto_ptr target) { // not setting an active report, because merge does not produce messages @@ -203,6 +203,8 @@ void CSMTools::Tools::runMerge (const boost::filesystem::path& target) { mMergeOperation = new MergeOperation (mDocument); mMerge.setOperation (mMergeOperation); + connect (mMergeOperation, SIGNAL (mergeDone (CSMDoc::Document*)), + this, SIGNAL (mergeDone (CSMDoc::Document*))); } mMergeOperation->setTarget (target); diff --git a/apps/opencs/model/tools/tools.hpp b/apps/opencs/model/tools/tools.hpp index 952099928..2302fe2e0 100644 --- a/apps/opencs/model/tools/tools.hpp +++ b/apps/opencs/model/tools/tools.hpp @@ -1,6 +1,7 @@ #ifndef CSM_TOOLS_TOOLS_H #define CSM_TOOLS_TOOLS_H +#include #include #include @@ -73,7 +74,7 @@ namespace CSMTools void runSearch (const CSMWorld::UniversalId& searchId, const Search& search); - void runMerge (const boost::filesystem::path& target); + void runMerge (std::auto_ptr target); void abortOperation (int type); ///< \attention The operation is not aborted immediately. @@ -92,6 +93,10 @@ namespace CSMTools void progress (int current, int max, int type); void done (int type, bool failed); + + /// \attention When this signal is emitted, *this hands over the ownership of the + /// document. This signal must be handled to avoid a leak. + void mergeDone (CSMDoc::Document *document); }; } diff --git a/apps/opencs/view/tools/merge.cpp b/apps/opencs/view/tools/merge.cpp index f775390ee..566a5ee06 100644 --- a/apps/opencs/view/tools/merge.cpp +++ b/apps/opencs/view/tools/merge.cpp @@ -10,6 +10,7 @@ #include #include "../../model/doc/document.hpp" +#include "../../model/doc/documentmanager.hpp" #include "../doc/filewidget.hpp" #include "../doc/adjusterwidget.hpp" @@ -25,8 +26,8 @@ void CSVTools::Merge::keyPressEvent (QKeyEvent *event) QWidget::keyPressEvent (event); } -CSVTools::Merge::Merge (QWidget *parent) -: QWidget (parent), mDocument (0) +CSVTools::Merge::Merge (CSMDoc::DocumentManager& documentManager, QWidget *parent) +: QWidget (parent), mDocument (0), mDocumentManager (documentManager) { setWindowTitle ("Merge Content Files into a new Game File"); @@ -124,7 +125,13 @@ void CSVTools::Merge::accept() { if ((mDocument->getState() & CSMDoc::State_Merging)==0) { - mDocument->runMerge (mAdjuster->getPath()); + std::vector< boost::filesystem::path > files (1, mAdjuster->getPath()); + + std::auto_ptr target ( + mDocumentManager.makeDocument (files, files[0], true)); + + mDocument->runMerge (target); + hide(); } } diff --git a/apps/opencs/view/tools/merge.hpp b/apps/opencs/view/tools/merge.hpp index b8369ffa3..d4ed7e34b 100644 --- a/apps/opencs/view/tools/merge.hpp +++ b/apps/opencs/view/tools/merge.hpp @@ -11,6 +11,7 @@ class QListWidget; namespace CSMDoc { class Document; + class DocumentManager; } namespace CSVDoc @@ -30,12 +31,13 @@ namespace CSVTools QListWidget *mFiles; CSVDoc::FileWidget *mNewFile; CSVDoc::AdjusterWidget *mAdjuster; + CSMDoc::DocumentManager& mDocumentManager; void keyPressEvent (QKeyEvent *event); public: - Merge (QWidget *parent = 0); + Merge (CSMDoc::DocumentManager& documentManager, QWidget *parent = 0); /// Configure dialogue for a new merge void configure (CSMDoc::Document *document); From c8d6679a25130a3085a8563c3d7411aa46ead54c Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 16 Aug 2015 17:40:20 +0200 Subject: [PATCH 2050/3725] Remove an unused function --- apps/openmw/mwgui/sortfilteritemmodel.cpp | 4 ---- apps/openmw/mwgui/sortfilteritemmodel.hpp | 2 -- 2 files changed, 6 deletions(-) diff --git a/apps/openmw/mwgui/sortfilteritemmodel.cpp b/apps/openmw/mwgui/sortfilteritemmodel.cpp index 183ab07ff..1d086f2ee 100644 --- a/apps/openmw/mwgui/sortfilteritemmodel.cpp +++ b/apps/openmw/mwgui/sortfilteritemmodel.cpp @@ -71,7 +71,6 @@ namespace MWGui SortFilterItemModel::SortFilterItemModel(ItemModel *sourceModel) : mCategory(Category_All) , mFilter(0) - , mShowEquipped(true) , mSortByType(true) { mSourceModel = sourceModel; @@ -91,9 +90,6 @@ namespace MWGui { MWWorld::Ptr base = item.mBase; - if (item.mType == ItemStack::Type_Equipped && !mShowEquipped) - return false; - int category = 0; if (base.getTypeName() == typeid(ESM::Armor).name() || base.getTypeName() == typeid(ESM::Clothing).name()) diff --git a/apps/openmw/mwgui/sortfilteritemmodel.hpp b/apps/openmw/mwgui/sortfilteritemmodel.hpp index 1b68bdd4f..064f62e77 100644 --- a/apps/openmw/mwgui/sortfilteritemmodel.hpp +++ b/apps/openmw/mwgui/sortfilteritemmodel.hpp @@ -24,7 +24,6 @@ namespace MWGui void setCategory (int category); void setFilter (int filter); - void setShowEquipped (bool show) { mShowEquipped = show; } /// Use ItemStack::Type for sorting? void setSortByType(bool sort) { mSortByType = sort; } @@ -49,7 +48,6 @@ namespace MWGui int mCategory; int mFilter; - bool mShowEquipped; bool mSortByType; }; From 9fad33cd14b33c7fde4523a1189801b7e6689e1b Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 16 Aug 2015 17:49:37 +0200 Subject: [PATCH 2051/3725] Don't reset the item model's sort/filter options in updatePlayer (Fixes #2863) --- apps/openmw/mwgui/inventorywindow.cpp | 7 ++++++- apps/openmw/mwgui/itemmodel.cpp | 19 +++++++++++++++++++ apps/openmw/mwgui/itemmodel.hpp | 4 ++++ apps/openmw/mwgui/itemview.cpp | 4 ++++ 4 files changed, 33 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 9c9138ed5..580e583c9 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -119,7 +119,12 @@ namespace MWGui { mPtr = MWBase::Environment::get().getWorld ()->getPlayerPtr(); mTradeModel = new TradeItemModel(new InventoryItemModel(mPtr), MWWorld::Ptr()); - mSortModel = new SortFilterItemModel(mTradeModel); + + if (mSortModel) // reuse existing SortModel when possible to keep previous category/filter settings + mSortModel->setSourceModel(mTradeModel); + else + mSortModel = new SortFilterItemModel(mTradeModel); + mItemView->setModel(mSortModel); mPreview->updatePtr(mPtr); diff --git a/apps/openmw/mwgui/itemmodel.cpp b/apps/openmw/mwgui/itemmodel.cpp index 9fce6e84d..a1e36bce6 100644 --- a/apps/openmw/mwgui/itemmodel.cpp +++ b/apps/openmw/mwgui/itemmodel.cpp @@ -120,6 +120,11 @@ namespace MWGui } + ProxyItemModel::ProxyItemModel() + : mSourceModel(NULL) + { + } + ProxyItemModel::~ProxyItemModel() { delete mSourceModel; @@ -164,4 +169,18 @@ namespace MWGui return mSourceModel->getIndex(item); } + void ProxyItemModel::setSourceModel(ItemModel *sourceModel) + { + if (mSourceModel == sourceModel) + return; + + if (mSourceModel) + { + delete mSourceModel; + mSourceModel = NULL; + } + + mSourceModel = sourceModel; + } + } diff --git a/apps/openmw/mwgui/itemmodel.hpp b/apps/openmw/mwgui/itemmodel.hpp index 53c7018e2..2019c1042 100644 --- a/apps/openmw/mwgui/itemmodel.hpp +++ b/apps/openmw/mwgui/itemmodel.hpp @@ -80,11 +80,15 @@ namespace MWGui class ProxyItemModel : public ItemModel { public: + ProxyItemModel(); virtual ~ProxyItemModel(); virtual MWWorld::Ptr copyItem (const ItemStack& item, size_t count, bool setNewOwner=false); virtual void removeItem (const ItemStack& item, size_t count); virtual ModelIndex getIndex (ItemStack item); + /// @note Takes ownership of the passed pointer. + void setSourceModel(ItemModel* sourceModel); + ModelIndex mapToSource (ModelIndex index); ModelIndex mapFromSource (ModelIndex index); protected: diff --git a/apps/openmw/mwgui/itemview.cpp b/apps/openmw/mwgui/itemview.cpp index df44eb33c..2cdfcada4 100644 --- a/apps/openmw/mwgui/itemview.cpp +++ b/apps/openmw/mwgui/itemview.cpp @@ -30,8 +30,12 @@ ItemView::~ItemView() void ItemView::setModel(ItemModel *model) { + if (mModel == model) + return; + delete mModel; mModel = model; + update(); } From 47dd9505a9464dc5c947f409c3c4a80cf4d8e395 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 16 Aug 2015 18:27:17 +0200 Subject: [PATCH 2052/3725] copy meta data from game file when merging --- apps/opencs/model/doc/document.cpp | 2 +- apps/opencs/model/tools/mergeoperation.cpp | 4 ++-- apps/opencs/model/tools/mergeoperation.hpp | 4 +++- apps/opencs/model/tools/mergestages.cpp | 27 ++++++++++++++++++++-- apps/opencs/model/tools/mergestages.hpp | 5 +++- apps/opencs/model/tools/tools.cpp | 6 ++--- apps/opencs/model/tools/tools.hpp | 5 +++- apps/opencs/model/world/data.cpp | 10 ++++++-- apps/opencs/model/world/data.hpp | 2 ++ 9 files changed, 52 insertions(+), 13 deletions(-) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 67ecbd641..8d5580bcf 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -2250,7 +2250,7 @@ CSMDoc::Document::Document (const VFS::Manager* vfs, const Files::ConfigurationM ToUTF8::FromType encoding, const CSMWorld::ResourcesManager& resourcesManager, const std::vector& blacklistedScripts) : mVFS(vfs), mSavePath (savePath), mContentFiles (files), mNew (new_), mData (encoding, resourcesManager), - mTools (*this), + mTools (*this, encoding), mProjectPath ((configuration.getUserDataPath() / "projects") / (savePath.filename().string() + ".project")), mSavingOperation (*this, mProjectPath, encoding), diff --git a/apps/opencs/model/tools/mergeoperation.cpp b/apps/opencs/model/tools/mergeoperation.cpp index c93452dad..9e5fb2745 100644 --- a/apps/opencs/model/tools/mergeoperation.cpp +++ b/apps/opencs/model/tools/mergeoperation.cpp @@ -6,10 +6,10 @@ #include "mergestages.hpp" -CSMTools::MergeOperation::MergeOperation (CSMDoc::Document& document) +CSMTools::MergeOperation::MergeOperation (CSMDoc::Document& document, ToUTF8::FromType encoding) : CSMDoc::Operation (CSMDoc::State_Merging, true), mState (document) { - appendStage (new FinishMergedDocumentStage (mState)); + appendStage (new FinishMergedDocumentStage (mState, encoding)); } void CSMTools::MergeOperation::setTarget (std::auto_ptr document) diff --git a/apps/opencs/model/tools/mergeoperation.hpp b/apps/opencs/model/tools/mergeoperation.hpp index dc958d31b..bdaeb2ccd 100644 --- a/apps/opencs/model/tools/mergeoperation.hpp +++ b/apps/opencs/model/tools/mergeoperation.hpp @@ -3,6 +3,8 @@ #include +#include + #include "../doc/operation.hpp" #include "mergestate.hpp" @@ -22,7 +24,7 @@ namespace CSMTools public: - MergeOperation (CSMDoc::Document& document); + MergeOperation (CSMDoc::Document& document, ToUTF8::FromType encoding); /// \attention Do not call this function while a merge is running. void setTarget (std::auto_ptr document); diff --git a/apps/opencs/model/tools/mergestages.cpp b/apps/opencs/model/tools/mergestages.cpp index 16ea0495a..776808b26 100644 --- a/apps/opencs/model/tools/mergestages.cpp +++ b/apps/opencs/model/tools/mergestages.cpp @@ -3,8 +3,11 @@ #include "mergestate.hpp" -CSMTools::FinishMergedDocumentStage::FinishMergedDocumentStage (MergeState& state) -: mState (state) +#include "../doc/document.hpp" +#include "../world/data.hpp" + +CSMTools::FinishMergedDocumentStage::FinishMergedDocumentStage (MergeState& state, ToUTF8::FromType encoding) +: mState (state), mEncoder (encoding) {} int CSMTools::FinishMergedDocumentStage::setup() @@ -14,5 +17,25 @@ int CSMTools::FinishMergedDocumentStage::setup() void CSMTools::FinishMergedDocumentStage::perform (int stage, CSMDoc::Messages& messages) { + // We know that the content file list contains at least two entries and that the first one + // does exist on disc (otherwise it would have been impossible to initiate a merge on that + // document). + boost::filesystem::path path = mState.mSource.getContentFiles()[0]; + + ESM::ESMReader reader; + reader.setEncoder (&mEncoder); + reader.open (path.string()); + + CSMWorld::MetaData source; + source.mId = "sys::meta"; + source.load (reader); + + CSMWorld::MetaData target = mState.mTarget->getData().getMetaData(); + + target.mAuthor = source.mAuthor; + target.mDescription = source.mDescription; + + mState.mTarget->getData().setMetaData (target); + mState.mCompleted = true; } diff --git a/apps/opencs/model/tools/mergestages.hpp b/apps/opencs/model/tools/mergestages.hpp index 138b89d72..9844feaca 100644 --- a/apps/opencs/model/tools/mergestages.hpp +++ b/apps/opencs/model/tools/mergestages.hpp @@ -1,6 +1,8 @@ #ifndef CSM_TOOLS_MERGESTAGES_H #define CSM_TOOLS_MERGESTAGES_H +#include + #include "../doc/stage.hpp" namespace CSMTools @@ -10,10 +12,11 @@ namespace CSMTools class FinishMergedDocumentStage : public CSMDoc::Stage { MergeState& mState; + ToUTF8::Utf8Encoder mEncoder; public: - FinishMergedDocumentStage (MergeState& state); + FinishMergedDocumentStage (MergeState& state, ToUTF8::FromType encoding); virtual int setup(); ///< \return number of steps diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index 78b052813..c4ff6868b 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -116,9 +116,9 @@ CSMDoc::OperationHolder *CSMTools::Tools::getVerifier() return &mVerifier; } -CSMTools::Tools::Tools (CSMDoc::Document& document) +CSMTools::Tools::Tools (CSMDoc::Document& document, ToUTF8::FromType encoding) : mDocument (document), mData (document.getData()), mVerifierOperation (0), - mSearchOperation (0), mMergeOperation (0), mNextReportNumber (0) + mSearchOperation (0), mMergeOperation (0), mNextReportNumber (0), mEncoding (encoding) { // index 0: load error log mReports.insert (std::make_pair (mNextReportNumber++, new ReportModel)); @@ -201,7 +201,7 @@ void CSMTools::Tools::runMerge (std::auto_ptr target) if (!mMergeOperation) { - mMergeOperation = new MergeOperation (mDocument); + mMergeOperation = new MergeOperation (mDocument, mEncoding); mMerge.setOperation (mMergeOperation); connect (mMergeOperation, SIGNAL (mergeDone (CSMDoc::Document*)), this, SIGNAL (mergeDone (CSMDoc::Document*))); diff --git a/apps/opencs/model/tools/tools.hpp b/apps/opencs/model/tools/tools.hpp index 2302fe2e0..e16a3854c 100644 --- a/apps/opencs/model/tools/tools.hpp +++ b/apps/opencs/model/tools/tools.hpp @@ -4,6 +4,8 @@ #include #include +#include + #include #include @@ -44,6 +46,7 @@ namespace CSMTools std::map mReports; int mNextReportNumber; std::map mActiveReports; // type, report number + ToUTF8::FromType mEncoding; // not implemented Tools (const Tools&); @@ -59,7 +62,7 @@ namespace CSMTools public: - Tools (CSMDoc::Document& document); + Tools (CSMDoc::Document& document, ToUTF8::FromType encoding); virtual ~Tools(); diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 3714117b6..d8999d950 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -483,7 +483,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mMetaData.addColumn (new FormatColumn); mMetaData.addColumn (new AuthorColumn); mMetaData.addColumn (new FileDescriptionColumn); - + addModel (new IdTable (&mGlobals), UniversalId::Type_Global); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmst); addModel (new IdTable (&mSkills), UniversalId::Type_Skill); @@ -828,6 +828,12 @@ const CSMWorld::MetaData& CSMWorld::Data::getMetaData() const return mMetaData.getRecord (0).get(); } +void CSMWorld::Data::setMetaData (const MetaData& metaData) +{ + Record record (RecordBase::State_ModifiedOnly, 0, &metaData); + mMetaData.setRecord (0, record); +} + QAbstractItemModel *CSMWorld::Data::getTableModel (const CSMWorld::UniversalId& id) { std::map::iterator iter = mModelIndex.find (id.getType()); @@ -880,7 +886,7 @@ int CSMWorld::Data::startLoading (const boost::filesystem::path& path, bool base mMetaData.setRecord (0, Record (RecordBase::State_ModifiedOnly, 0, &metaData)); } - + return mReader->getRecordCount(); } diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 06f76607f..5706b005b 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -255,6 +255,8 @@ namespace CSMWorld const MetaData& getMetaData() const; + void setMetaData (const MetaData& metaData); + QAbstractItemModel *getTableModel (const UniversalId& id); ///< If no table model is available for \a id, an exception is thrown. /// From d1e1c0f38bfd2f94b6120571bb49ead59e298e87 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 16 Aug 2015 23:42:08 +0200 Subject: [PATCH 2053/3725] Editor: fix a typo in ESM::Light flag mappings --- apps/opencs/model/world/refidcollection.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 16da4aad9..85ddbacdb 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -380,7 +380,7 @@ CSMWorld::RefIdCollection::RefIdCollection() { Columns::ColumnId_Portable, ESM::Light::Carry }, { Columns::ColumnId_NegativeLight, ESM::Light::Negative }, { Columns::ColumnId_Flickering, ESM::Light::Flicker }, - { Columns::ColumnId_SlowFlickering, ESM::Light::Flicker }, + { Columns::ColumnId_SlowFlickering, ESM::Light::FlickerSlow }, { Columns::ColumnId_Pulsing, ESM::Light::Pulse }, { Columns::ColumnId_SlowPulsing, ESM::Light::PulseSlow }, { Columns::ColumnId_Fire, ESM::Light::Fire }, From be7bd9529d312c64de2c5d1329dfbe8caefc02e8 Mon Sep 17 00:00:00 2001 From: Jordan Ayers Date: Sun, 16 Aug 2015 16:56:44 -0500 Subject: [PATCH 2054/3725] Classes shouldn't use MWBase::Environment to access their own members. --- apps/openmw/engine.cpp | 74 +++++++++---------- .../mwmechanics/mechanicsmanagerimp.cpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 6 +- 3 files changed, 41 insertions(+), 41 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 8d25a923f..95851b75f 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -66,7 +66,7 @@ namespace void OMW::Engine::executeLocalScripts() { - MWWorld::LocalScripts& localScripts = MWBase::Environment::get().getWorld()->getLocalScripts(); + MWWorld::LocalScripts& localScripts = mEnvironment.getWorld()->getLocalScripts(); localScripts.startIteration(); @@ -76,7 +76,7 @@ void OMW::Engine::executeLocalScripts() MWScript::InterpreterContext interpreterContext ( &script.second.getRefData().getLocals(), script.second); - MWBase::Environment::get().getScriptManager()->run (script.first, interpreterContext); + mEnvironment.getScriptManager()->run (script.first, interpreterContext); } localScripts.setIgnore (MWWorld::Ptr()); @@ -90,7 +90,7 @@ void OMW::Engine::frame(float frametime) mEnvironment.setFrameDuration (frametime); // update input - MWBase::Environment::get().getInputManager()->update(frametime, false); + mEnvironment.getInputManager()->update(frametime, false); // When the window is minimized, pause everything. Currently this *has* to be here to work around a MyGUI bug. // If we are not currently rendering, then RenderItems will not be reused resulting in a memory leak upon changing widget textures. @@ -99,76 +99,76 @@ void OMW::Engine::frame(float frametime) // sound if (mUseSound) - MWBase::Environment::get().getSoundManager()->update(frametime); + mEnvironment.getSoundManager()->update(frametime); // Main menu opened? Then scripts are also paused. - bool paused = MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_MainMenu); + bool paused = mEnvironment.getWindowManager()->containsMode(MWGui::GM_MainMenu); // update game state - MWBase::Environment::get().getStateManager()->update (frametime); + mEnvironment.getStateManager()->update (frametime); - bool guiActive = MWBase::Environment::get().getWindowManager()->isGuiMode(); + bool guiActive = mEnvironment.getWindowManager()->isGuiMode(); osg::Timer_t beforeScriptTick = osg::Timer::instance()->tick(); - if (MWBase::Environment::get().getStateManager()->getState()== + if (mEnvironment.getStateManager()->getState()== MWBase::StateManager::State_Running) { if (!paused) { - if (MWBase::Environment::get().getWorld()->getScriptsEnabled()) + if (mEnvironment.getWorld()->getScriptsEnabled()) { // local scripts executeLocalScripts(); // global scripts - MWBase::Environment::get().getScriptManager()->getGlobalScripts().run(); + mEnvironment.getScriptManager()->getGlobalScripts().run(); } - MWBase::Environment::get().getWorld()->markCellAsUnchanged(); + mEnvironment.getWorld()->markCellAsUnchanged(); } if (!guiActive) - MWBase::Environment::get().getWorld()->advanceTime( - frametime*MWBase::Environment::get().getWorld()->getTimeScaleFactor()/3600); + mEnvironment.getWorld()->advanceTime( + frametime*mEnvironment.getWorld()->getTimeScaleFactor()/3600); } osg::Timer_t afterScriptTick = osg::Timer::instance()->tick(); // update actors osg::Timer_t beforeMechanicsTick = osg::Timer::instance()->tick(); - if (MWBase::Environment::get().getStateManager()->getState()!= + if (mEnvironment.getStateManager()->getState()!= MWBase::StateManager::State_NoGame) { - MWBase::Environment::get().getMechanicsManager()->update(frametime, + mEnvironment.getMechanicsManager()->update(frametime, guiActive); } osg::Timer_t afterMechanicsTick = osg::Timer::instance()->tick(); - if (MWBase::Environment::get().getStateManager()->getState()== + if (mEnvironment.getStateManager()->getState()== MWBase::StateManager::State_Running) { MWWorld::Ptr player = mEnvironment.getWorld()->getPlayerPtr(); if(!guiActive && player.getClass().getCreatureStats(player).isDead()) - MWBase::Environment::get().getStateManager()->endGame(); + mEnvironment.getStateManager()->endGame(); } // update world osg::Timer_t beforePhysicsTick = osg::Timer::instance()->tick();; - if (MWBase::Environment::get().getStateManager()->getState()!= + if (mEnvironment.getStateManager()->getState()!= MWBase::StateManager::State_NoGame) { - MWBase::Environment::get().getWorld()->update(frametime, guiActive); + mEnvironment.getWorld()->update(frametime, guiActive); } osg::Timer_t afterPhysicsTick = osg::Timer::instance()->tick(); // update GUI - MWBase::Environment::get().getWindowManager()->onFrame(frametime); - if (MWBase::Environment::get().getStateManager()->getState()!= + mEnvironment.getWindowManager()->onFrame(frametime); + if (mEnvironment.getStateManager()->getState()!= MWBase::StateManager::State_NoGame) { #if 0 - MWBase::Environment::get().getWindowManager()->wmUpdateFps(fps); + mEnvironment.getWindowManager()->wmUpdateFps(fps); #endif - MWBase::Environment::get().getWindowManager()->update(); + mEnvironment.getWindowManager()->update(); } int frameNumber = mViewer->getFrameStamp()->getFrameNumber(); @@ -511,7 +511,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) mEnvironment.setWorld( new MWWorld::World (mViewer, rootNode, mResourceSystem.get(), mFileCollections, mContentFiles, mEncoder, mFallbackMap, mActivationDistanceOverride, mCellName, mStartupScript)); - MWBase::Environment::get().getWorld()->setupPlayer(); + mEnvironment.getWorld()->setupPlayer(); input->setPlayer(&mEnvironment.getWorld()->getPlayer()); window->initUI(); @@ -528,7 +528,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) mScriptContext = new MWScript::CompilerContext (MWScript::CompilerContext::Type_Full); mScriptContext->setExtensions (&mExtensions); - mEnvironment.setScriptManager (new MWScript::ScriptManager (MWBase::Environment::get().getWorld()->getStore(), + mEnvironment.setScriptManager (new MWScript::ScriptManager (mEnvironment.getWorld()->getStore(), mVerboseScripts, *mScriptContext, mWarningsMode, mScriptBlacklistUse ? mScriptBlacklist : std::vector())); @@ -543,7 +543,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) // scripts if (mCompileAll) { - std::pair result = MWBase::Environment::get().getScriptManager()->compileAll(); + std::pair result = mEnvironment.getScriptManager()->compileAll(); if (result.first) std::cout << "compiled " << result.second << " of " << result.first << " scripts (" @@ -648,38 +648,38 @@ void OMW::Engine::go() if (!mSaveGameFile.empty()) { - MWBase::Environment::get().getStateManager()->loadGame(mSaveGameFile); + mEnvironment.getStateManager()->loadGame(mSaveGameFile); } else if (!mSkipMenu) { // start in main menu - MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_MainMenu); + mEnvironment.getWindowManager()->pushGuiMode (MWGui::GM_MainMenu); try { // Is there an ini setting for this filename or something? - MWBase::Environment::get().getSoundManager()->streamMusic("Special/morrowind title.mp3"); + mEnvironment.getSoundManager()->streamMusic("Special/morrowind title.mp3"); std::string logo = mFallbackMap["Movies_Morrowind_Logo"]; if (!logo.empty()) - MWBase::Environment::get().getWindowManager()->playVideo(logo, true); + mEnvironment.getWindowManager()->playVideo(logo, true); } catch (...) {} } else { - MWBase::Environment::get().getStateManager()->newGame (!mNewGame); + mEnvironment.getStateManager()->newGame (!mNewGame); } // Start the main rendering loop osg::Timer frameTimer; double simulationTime = 0.0; - while (!mViewer->done() && !MWBase::Environment::get().getStateManager()->hasQuitRequest()) + while (!mViewer->done() && !mEnvironment.getStateManager()->hasQuitRequest()) { double dt = frameTimer.time_s(); frameTimer.setStartTick(); dt = std::min(dt, 0.2); - bool guiActive = MWBase::Environment::get().getWindowManager()->isGuiMode(); + bool guiActive = mEnvironment.getWindowManager()->isGuiMode(); if (!guiActive) simulationTime += dt; @@ -700,15 +700,15 @@ void OMW::Engine::go() void OMW::Engine::activate() { - if (MWBase::Environment::get().getWindowManager()->isGuiMode()) + if (mEnvironment.getWindowManager()->isGuiMode()) return; - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = mEnvironment.getWorld()->getPlayerPtr(); if (player.getClass().getCreatureStats(player).getMagicEffects().get(ESM::MagicEffect::Paralyze).getMagnitude() > 0 || player.getClass().getCreatureStats(player).getKnockedDown()) return; - MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getFacedObject(); + MWWorld::Ptr ptr = mEnvironment.getWorld()->getFacedObject(); if (ptr.isEmpty()) return; @@ -724,7 +724,7 @@ void OMW::Engine::activate() return; } - MWBase::Environment::get().getWorld()->activate(ptr, MWBase::Environment::get().getWorld()->getPlayerPtr()); + mEnvironment.getWorld()->activate(ptr, mEnvironment.getWorld()->getPlayerPtr()); } void OMW::Engine::screenshot() diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index b2cd8414e..9436e35d2 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1367,7 +1367,7 @@ namespace MWMechanics // Doesn't handle possible edge case where no one reported the assault, but in such a case, // for bystanders it is not possible to tell who attacked first, anyway. if (victimStats.getCrimeId() != -1) - MWBase::Environment::get().getMechanicsManager()->commitCrime(attacker, victim, MWBase::MechanicsManager::OT_Murder); + commitCrime(attacker, victim, MWBase::MechanicsManager::OT_Murder); } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 15c8cbeb2..1738878ea 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1421,7 +1421,7 @@ namespace MWWorld if (ptr.getClass().isActor()) { // Collided with actor, ask actor to try to avoid door - if(ptr != MWBase::Environment::get().getWorld()->getPlayerPtr() ) { + if(ptr != getPlayerPtr() ) { MWMechanics::AiSequence& seq = ptr.getClass().getCreatureStats(ptr).getAiSequence(); if(seq.getTypeId() != MWMechanics::AiPackage::TypeIdAvoidDoor) //Only add it once seq.stack(MWMechanics::AiAvoidDoor(it->first),ptr); @@ -1738,7 +1738,7 @@ namespace MWWorld else { cellid.mPaged = true; - MWBase::Environment::get().getWorld()->positionToIndex( + positionToIndex( ref.mRef.getDoorDest().pos[0], ref.mRef.getDoorDest().pos[1], cellid.mIndex.mX, @@ -2516,7 +2516,7 @@ namespace MWWorld if (reported) { npcStats.setBounty(npcStats.getBounty()+ - MWBase::Environment::get().getWorld()->getStore().get().find("iWereWolfBounty")->getInt()); + mStore.get().find("iWereWolfBounty")->getInt()); windowManager->messageBox("#{sCrimeMessage}"); } } From b583a2ec330592ca1cf38d260640e2782dd121ff Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 17 Aug 2015 00:05:57 +0200 Subject: [PATCH 2055/3725] Make SetDelete a no-op for items in containers (Fixes #2864) --- apps/openmw/mwbase/world.hpp | 1 + apps/openmw/mwworld/worldimp.cpp | 2 +- apps/openmw/mwworld/worldimp.hpp | 2 ++ 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 6e5029cc3..d345cdf7e 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -256,6 +256,7 @@ namespace MWBase virtual void fixPosition (const MWWorld::Ptr& actor) = 0; ///< Attempt to fix position so that the Ptr is no longer inside collision geometry. + /// @note No-op for items in containers. Use ContainerStore::removeItem instead. virtual void deleteObject (const MWWorld::Ptr& ptr) = 0; virtual void undeleteObject (const MWWorld::Ptr& ptr) = 0; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 15c8cbeb2..e1de0f07a 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1050,7 +1050,7 @@ namespace MWWorld void World::deleteObject (const Ptr& ptr) { - if (!ptr.getRefData().isDeleted()) + if (!ptr.getRefData().isDeleted() && ptr.getContainerStore() == NULL) { ptr.getRefData().setCount(0); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 5251427c5..35e433549 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -336,7 +336,9 @@ namespace MWWorld /// use the "Head" node as a basis. virtual std::pair getHitContact(const MWWorld::Ptr &ptr, float distance); + /// @note No-op for items in containers. Use ContainerStore::removeItem instead. virtual void deleteObject (const Ptr& ptr); + virtual void undeleteObject (const Ptr& ptr); virtual MWWorld::Ptr moveObject (const Ptr& ptr, float x, float y, float z); From dca08b0b42e1151e598d0e4cf95c4cb4306b508e Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 18 Aug 2015 14:51:32 +0200 Subject: [PATCH 2056/3725] Remove a firing assert (Fixes #2871) --- apps/openmw/mwmechanics/pathfinding.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index 777ccacae..798a0ea21 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -221,7 +221,8 @@ namespace MWMechanics } mPath = mCell->aStarSearch(startNode, endNode.first); - assert(!mPath.empty()); + if (mPath.empty()) + return; // convert supplied path to world co-ordinates for (std::list::iterator iter(mPath.begin()); iter != mPath.end(); ++iter) From 67bd6cd70837605e1acebe41048b0f7ff88190ec Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 18 Aug 2015 23:06:12 +0200 Subject: [PATCH 2057/3725] Remove empty line at the beginning of files git ls-files -z | xargs -0 sed -i '1{/^$/d}' --- apps/opencs/editor.cpp | 1 - apps/opencs/main.cpp | 1 - apps/opencs/model/doc/blacklist.cpp | 1 - apps/opencs/model/doc/documentmanager.cpp | 1 - apps/opencs/model/doc/loader.cpp | 1 - apps/opencs/model/doc/messages.cpp | 1 - apps/opencs/model/doc/operation.cpp | 1 - apps/opencs/model/doc/operationholder.cpp | 1 - apps/opencs/model/doc/runner.cpp | 1 - apps/opencs/model/doc/saving.cpp | 1 - apps/opencs/model/doc/savingstages.cpp | 1 - apps/opencs/model/doc/savingstate.cpp | 1 - apps/opencs/model/doc/stage.cpp | 1 - apps/opencs/model/filter/andnode.cpp | 1 - apps/opencs/model/filter/booleannode.cpp | 1 - apps/opencs/model/filter/leafnode.cpp | 1 - apps/opencs/model/filter/narynode.cpp | 1 - apps/opencs/model/filter/node.cpp | 1 - apps/opencs/model/filter/notnode.cpp | 1 - apps/opencs/model/filter/ornode.cpp | 1 - apps/opencs/model/filter/parser.cpp | 1 - apps/opencs/model/filter/textnode.cpp | 1 - apps/opencs/model/filter/unarynode.cpp | 1 - apps/opencs/model/filter/valuenode.cpp | 1 - apps/opencs/model/tools/birthsigncheck.cpp | 1 - apps/opencs/model/tools/classcheck.cpp | 1 - apps/opencs/model/tools/factioncheck.cpp | 1 - apps/opencs/model/tools/mandatoryid.cpp | 1 - apps/opencs/model/tools/racecheck.cpp | 1 - apps/opencs/model/tools/regioncheck.cpp | 1 - apps/opencs/model/tools/reportmodel.cpp | 1 - apps/opencs/model/tools/scriptcheck.cpp | 1 - apps/opencs/model/tools/search.cpp | 1 - apps/opencs/model/tools/searchoperation.cpp | 1 - apps/opencs/model/tools/searchstage.cpp | 1 - apps/opencs/model/tools/skillcheck.cpp | 1 - apps/opencs/model/tools/soundcheck.cpp | 1 - apps/opencs/model/tools/spellcheck.cpp | 1 - apps/opencs/model/tools/startscriptcheck.cpp | 1 - apps/opencs/model/tools/tools.cpp | 1 - apps/opencs/model/world/cell.cpp | 1 - apps/opencs/model/world/cellcoordinates.cpp | 1 - apps/opencs/model/world/cellselection.cpp | 1 - apps/opencs/model/world/collectionbase.cpp | 1 - apps/opencs/model/world/columns.cpp | 1 - apps/opencs/model/world/commanddispatcher.cpp | 1 - apps/opencs/model/world/data.cpp | 1 - apps/opencs/model/world/idtablebase.cpp | 1 - apps/opencs/model/world/idtableproxymodel.cpp | 1 - apps/opencs/model/world/infocollection.cpp | 1 - apps/opencs/model/world/metadata.cpp | 1 - apps/opencs/model/world/record.cpp | 1 - apps/opencs/model/world/ref.cpp | 1 - apps/opencs/model/world/refcollection.cpp | 1 - apps/opencs/model/world/refiddata.cpp | 1 - apps/opencs/model/world/regionmap.cpp | 1 - apps/opencs/model/world/resources.cpp | 1 - apps/opencs/model/world/resourcesmanager.cpp | 1 - apps/opencs/model/world/resourcetable.cpp | 1 - apps/opencs/model/world/scope.cpp | 1 - apps/opencs/model/world/scriptcontext.cpp | 1 - apps/opencs/model/world/tablemimedata.hpp | 1 - apps/opencs/model/world/universalid.cpp | 1 - apps/opencs/view/doc/adjusterwidget.cpp | 1 - apps/opencs/view/doc/filewidget.cpp | 1 - apps/opencs/view/doc/globaldebugprofilemenu.cpp | 1 - apps/opencs/view/doc/loader.cpp | 1 - apps/opencs/view/doc/newgame.cpp | 1 - apps/opencs/view/doc/runlogsubview.cpp | 1 - apps/opencs/view/doc/startup.cpp | 1 - apps/opencs/view/doc/subviewfactory.cpp | 1 - apps/opencs/view/doc/viewmanager.cpp | 1 - apps/opencs/view/filter/editwidget.cpp | 1 - apps/opencs/view/filter/filterbox.cpp | 1 - apps/opencs/view/filter/recordfilterbox.cpp | 1 - apps/opencs/view/render/cell.cpp | 1 - apps/opencs/view/render/editmode.cpp | 1 - apps/opencs/view/render/lightingbright.cpp | 1 - apps/opencs/view/render/pagedworldspacewidget.cpp | 1 - apps/opencs/view/render/previewwidget.cpp | 1 - apps/opencs/view/render/unpagedworldspacewidget.cpp | 1 - apps/opencs/view/render/worldspacewidget.cpp | 1 - apps/opencs/view/tools/reportsubview.cpp | 1 - apps/opencs/view/tools/reporttable.cpp | 1 - apps/opencs/view/tools/searchbox.cpp | 1 - apps/opencs/view/tools/searchsubview.cpp | 1 - apps/opencs/view/tools/subviews.cpp | 1 - apps/opencs/view/widget/modebutton.cpp | 1 - apps/opencs/view/widget/pushbutton.cpp | 1 - apps/opencs/view/widget/scenetool.cpp | 1 - apps/opencs/view/widget/scenetoolbar.cpp | 1 - apps/opencs/view/widget/scenetoolmode.cpp | 1 - apps/opencs/view/widget/scenetoolrun.cpp | 1 - apps/opencs/view/widget/scenetooltoggle.cpp | 1 - apps/opencs/view/widget/scenetooltoggle2.cpp | 1 - apps/opencs/view/world/cellcreator.cpp | 1 - apps/opencs/view/world/creator.cpp | 1 - apps/opencs/view/world/dialoguecreator.cpp | 1 - apps/opencs/view/world/enumdelegate.cpp | 1 - apps/opencs/view/world/genericcreator.cpp | 1 - apps/opencs/view/world/idvalidator.cpp | 1 - apps/opencs/view/world/infocreator.cpp | 1 - apps/opencs/view/world/previewsubview.cpp | 1 - apps/opencs/view/world/recordbuttonbar.cpp | 1 - apps/opencs/view/world/referenceablecreator.cpp | 1 - apps/opencs/view/world/referencecreator.cpp | 1 - apps/opencs/view/world/regionmap.cpp | 1 - apps/opencs/view/world/regionmapsubview.cpp | 1 - apps/opencs/view/world/scenesubview.cpp | 1 - apps/opencs/view/world/scripterrortable.cpp | 1 - apps/opencs/view/world/scripthighlighter.cpp | 1 - apps/opencs/view/world/subviews.cpp | 1 - apps/opencs/view/world/table.cpp | 1 - apps/opencs/view/world/tablebottombox.cpp | 1 - apps/opencs/view/world/tablesubview.cpp | 1 - apps/opencs/view/world/util.cpp | 1 - apps/opencs/view/world/vartypedelegate.cpp | 1 - apps/openmw/android_commandLine.h | 1 - apps/openmw/mwbase/environment.cpp | 1 - apps/openmw/mwclass/activator.cpp | 1 - apps/openmw/mwclass/apparatus.cpp | 1 - apps/openmw/mwclass/armor.cpp | 1 - apps/openmw/mwclass/classes.cpp | 1 - apps/openmw/mwclass/clothing.cpp | 1 - apps/openmw/mwclass/container.cpp | 1 - apps/openmw/mwclass/creature.cpp | 1 - apps/openmw/mwclass/creaturelevlist.cpp | 1 - apps/openmw/mwclass/door.cpp | 1 - apps/openmw/mwclass/ingredient.cpp | 1 - apps/openmw/mwclass/itemlevlist.cpp | 1 - apps/openmw/mwclass/light.cpp | 1 - apps/openmw/mwclass/lockpick.cpp | 1 - apps/openmw/mwclass/misc.cpp | 1 - apps/openmw/mwclass/npc.cpp | 1 - apps/openmw/mwclass/potion.cpp | 1 - apps/openmw/mwclass/probe.cpp | 1 - apps/openmw/mwclass/repair.cpp | 1 - apps/openmw/mwclass/static.cpp | 1 - apps/openmw/mwclass/weapon.cpp | 1 - apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 1 - apps/openmw/mwdialogue/filter.cpp | 1 - apps/openmw/mwdialogue/journalentry.cpp | 1 - apps/openmw/mwdialogue/journalimp.cpp | 1 - apps/openmw/mwdialogue/quest.cpp | 1 - apps/openmw/mwdialogue/selectwrapper.cpp | 1 - apps/openmw/mwdialogue/topic.cpp | 1 - apps/openmw/mwgui/tooltips.hpp | 1 - apps/openmw/mwmechanics/alchemy.cpp | 1 - apps/openmw/mwmechanics/magiceffects.cpp | 1 - apps/openmw/mwmechanics/npcstats.cpp | 1 - apps/openmw/mwmechanics/spells.cpp | 1 - apps/openmw/mwscript/aiextensions.cpp | 1 - apps/openmw/mwscript/animationextensions.cpp | 1 - apps/openmw/mwscript/compilercontext.cpp | 1 - apps/openmw/mwscript/consoleextensions.cpp | 1 - apps/openmw/mwscript/containerextensions.cpp | 1 - apps/openmw/mwscript/controlextensions.cpp | 1 - apps/openmw/mwscript/dialogueextensions.cpp | 1 - apps/openmw/mwscript/extensions.cpp | 1 - apps/openmw/mwscript/globalscripts.cpp | 1 - apps/openmw/mwscript/guiextensions.cpp | 1 - apps/openmw/mwscript/interpretercontext.cpp | 1 - apps/openmw/mwscript/miscextensions.cpp | 1 - apps/openmw/mwscript/scriptmanagerimp.cpp | 1 - apps/openmw/mwscript/skyextensions.cpp | 1 - apps/openmw/mwscript/soundextensions.cpp | 1 - apps/openmw/mwscript/userextensions.cpp | 1 - apps/openmw/mwstate/character.cpp | 1 - apps/openmw/mwstate/charactermanager.cpp | 1 - apps/openmw/mwstate/statemanagerimp.cpp | 1 - apps/openmw/mwworld/action.cpp | 1 - apps/openmw/mwworld/actionapply.cpp | 1 - apps/openmw/mwworld/actioneat.cpp | 1 - apps/openmw/mwworld/actionopen.hpp | 1 - apps/openmw/mwworld/actiontake.cpp | 1 - apps/openmw/mwworld/actiontalk.cpp | 1 - apps/openmw/mwworld/class.cpp | 1 - apps/openmw/mwworld/containerstore.cpp | 1 - apps/openmw/mwworld/globals.cpp | 1 - apps/openmw/mwworld/inventorystore.cpp | 1 - apps/openmw/mwworld/ptr.cpp | 1 - apps/openmw/mwworld/refdata.cpp | 1 - components/compiler/controlparser.cpp | 1 - components/compiler/declarationparser.cpp | 1 - components/compiler/discardparser.cpp | 1 - components/compiler/errorhandler.cpp | 1 - components/compiler/errorhandler.hpp | 1 - components/compiler/exprparser.cpp | 1 - components/compiler/extensions.cpp | 1 - components/compiler/generator.cpp | 1 - components/compiler/junkparser.cpp | 1 - components/compiler/lineparser.cpp | 1 - components/compiler/literals.cpp | 1 - components/compiler/locals.cpp | 1 - components/compiler/nullerrorhandler.cpp | 1 - components/compiler/nullerrorhandler.hpp | 1 - components/compiler/output.cpp | 1 - components/compiler/parser.cpp | 1 - components/compiler/quickfileparser.cpp | 1 - components/compiler/scanner.cpp | 1 - components/compiler/scriptparser.cpp | 1 - components/compiler/skipparser.cpp | 1 - components/compiler/streamerrorhandler.cpp | 1 - components/compiler/streamerrorhandler.hpp | 1 - components/compiler/stringparser.cpp | 1 - components/esm/cellid.cpp | 1 - components/esm/cellref.cpp | 1 - components/esm/cellstate.cpp | 1 - components/esm/containerstate.cpp | 1 - components/esm/creaturestate.cpp | 1 - components/esm/debugprofile.cpp | 1 - components/esm/dialoguestate.cpp | 1 - components/esm/filter.cpp | 1 - components/esm/globalscript.cpp | 1 - components/esm/inventorystate.cpp | 1 - components/esm/journalentry.cpp | 1 - components/esm/loadtes3.cpp | 1 - components/esm/locals.cpp | 1 - components/esm/npcstate.cpp | 1 - components/esm/objectstate.cpp | 1 - components/esm/player.cpp | 1 - components/esm/queststate.cpp | 1 - components/esm/savedgame.cpp | 1 - components/esm/variantimp.cpp | 1 - components/files/multidircollection.cpp | 1 - components/interpreter/installopcodes.cpp | 1 - components/interpreter/interpreter.cpp | 1 - components/interpreter/runtime.cpp | 1 - files/mygui/CMakeLists.txt | 1 - 229 files changed, 229 deletions(-) diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 9450aa4bf..e4c65907e 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -1,4 +1,3 @@ - #include "editor.hpp" #include diff --git a/apps/opencs/main.cpp b/apps/opencs/main.cpp index fd7370a40..de2e6e83e 100644 --- a/apps/opencs/main.cpp +++ b/apps/opencs/main.cpp @@ -1,4 +1,3 @@ - #include "editor.hpp" #include diff --git a/apps/opencs/model/doc/blacklist.cpp b/apps/opencs/model/doc/blacklist.cpp index 083726412..b1d402c69 100644 --- a/apps/opencs/model/doc/blacklist.cpp +++ b/apps/opencs/model/doc/blacklist.cpp @@ -1,4 +1,3 @@ - #include "blacklist.hpp" #include diff --git a/apps/opencs/model/doc/documentmanager.cpp b/apps/opencs/model/doc/documentmanager.cpp index 5a5f50159..3a31e8687 100644 --- a/apps/opencs/model/doc/documentmanager.cpp +++ b/apps/opencs/model/doc/documentmanager.cpp @@ -1,4 +1,3 @@ - #include "documentmanager.hpp" #include diff --git a/apps/opencs/model/doc/loader.cpp b/apps/opencs/model/doc/loader.cpp index 33725a6f9..cb3ff2cd0 100644 --- a/apps/opencs/model/doc/loader.cpp +++ b/apps/opencs/model/doc/loader.cpp @@ -1,4 +1,3 @@ - #include "loader.hpp" #include diff --git a/apps/opencs/model/doc/messages.cpp b/apps/opencs/model/doc/messages.cpp index c8d26d39b..86e96a88d 100644 --- a/apps/opencs/model/doc/messages.cpp +++ b/apps/opencs/model/doc/messages.cpp @@ -1,4 +1,3 @@ - #include "messages.hpp" CSMDoc::Message::Message() {} diff --git a/apps/opencs/model/doc/operation.cpp b/apps/opencs/model/doc/operation.cpp index 8b2717086..cb9b7ec29 100644 --- a/apps/opencs/model/doc/operation.cpp +++ b/apps/opencs/model/doc/operation.cpp @@ -1,4 +1,3 @@ - #include "operation.hpp" #include diff --git a/apps/opencs/model/doc/operationholder.cpp b/apps/opencs/model/doc/operationholder.cpp index 25fc6fc26..db0d1a9a4 100644 --- a/apps/opencs/model/doc/operationholder.cpp +++ b/apps/opencs/model/doc/operationholder.cpp @@ -1,4 +1,3 @@ - #include "operationholder.hpp" #include "../settings/usersettings.hpp" diff --git a/apps/opencs/model/doc/runner.cpp b/apps/opencs/model/doc/runner.cpp index 14fe0cda8..5a0bc39be 100644 --- a/apps/opencs/model/doc/runner.cpp +++ b/apps/opencs/model/doc/runner.cpp @@ -1,4 +1,3 @@ - #include "runner.hpp" #include diff --git a/apps/opencs/model/doc/saving.cpp b/apps/opencs/model/doc/saving.cpp index 9f6e469b8..25372f1a6 100644 --- a/apps/opencs/model/doc/saving.cpp +++ b/apps/opencs/model/doc/saving.cpp @@ -1,4 +1,3 @@ - #include "saving.hpp" #include "../world/data.hpp" diff --git a/apps/opencs/model/doc/savingstages.cpp b/apps/opencs/model/doc/savingstages.cpp index f78c57ecd..ef3b23ec8 100644 --- a/apps/opencs/model/doc/savingstages.cpp +++ b/apps/opencs/model/doc/savingstages.cpp @@ -1,4 +1,3 @@ - #include "savingstages.hpp" #include diff --git a/apps/opencs/model/doc/savingstate.cpp b/apps/opencs/model/doc/savingstate.cpp index e7ad551b2..10539c1b5 100644 --- a/apps/opencs/model/doc/savingstate.cpp +++ b/apps/opencs/model/doc/savingstate.cpp @@ -1,4 +1,3 @@ - #include "savingstate.hpp" #include "operation.hpp" diff --git a/apps/opencs/model/doc/stage.cpp b/apps/opencs/model/doc/stage.cpp index 78aa14574..c8da86069 100644 --- a/apps/opencs/model/doc/stage.cpp +++ b/apps/opencs/model/doc/stage.cpp @@ -1,4 +1,3 @@ - #include "stage.hpp" CSMDoc::Stage::~Stage() {} diff --git a/apps/opencs/model/filter/andnode.cpp b/apps/opencs/model/filter/andnode.cpp index 4249fc228..908662799 100644 --- a/apps/opencs/model/filter/andnode.cpp +++ b/apps/opencs/model/filter/andnode.cpp @@ -1,4 +1,3 @@ - #include "andnode.hpp" #include diff --git a/apps/opencs/model/filter/booleannode.cpp b/apps/opencs/model/filter/booleannode.cpp index 35fc98e08..ee7ddc1c0 100644 --- a/apps/opencs/model/filter/booleannode.cpp +++ b/apps/opencs/model/filter/booleannode.cpp @@ -1,4 +1,3 @@ - #include "booleannode.hpp" CSMFilter::BooleanNode::BooleanNode (bool true_) : mTrue (true_) {} diff --git a/apps/opencs/model/filter/leafnode.cpp b/apps/opencs/model/filter/leafnode.cpp index 055a1747c..6745e165e 100644 --- a/apps/opencs/model/filter/leafnode.cpp +++ b/apps/opencs/model/filter/leafnode.cpp @@ -1,4 +1,3 @@ - #include "leafnode.hpp" std::vector CSMFilter::LeafNode::getReferencedColumns() const diff --git a/apps/opencs/model/filter/narynode.cpp b/apps/opencs/model/filter/narynode.cpp index 98f706c87..f2e0e5cb2 100644 --- a/apps/opencs/model/filter/narynode.cpp +++ b/apps/opencs/model/filter/narynode.cpp @@ -1,4 +1,3 @@ - #include "narynode.hpp" #include diff --git a/apps/opencs/model/filter/node.cpp b/apps/opencs/model/filter/node.cpp index 091dc4698..e25610675 100644 --- a/apps/opencs/model/filter/node.cpp +++ b/apps/opencs/model/filter/node.cpp @@ -1,4 +1,3 @@ - #include "node.hpp" CSMFilter::Node::Node() {} diff --git a/apps/opencs/model/filter/notnode.cpp b/apps/opencs/model/filter/notnode.cpp index b5d9da7b7..ba5302bbe 100644 --- a/apps/opencs/model/filter/notnode.cpp +++ b/apps/opencs/model/filter/notnode.cpp @@ -1,4 +1,3 @@ - #include "notnode.hpp" CSMFilter::NotNode::NotNode (boost::shared_ptr child) : UnaryNode (child, "not") {} diff --git a/apps/opencs/model/filter/ornode.cpp b/apps/opencs/model/filter/ornode.cpp index c5d15a384..41ec7b5cf 100644 --- a/apps/opencs/model/filter/ornode.cpp +++ b/apps/opencs/model/filter/ornode.cpp @@ -1,4 +1,3 @@ - #include "ornode.hpp" #include diff --git a/apps/opencs/model/filter/parser.cpp b/apps/opencs/model/filter/parser.cpp index 51338dfc9..7936a1ae2 100644 --- a/apps/opencs/model/filter/parser.cpp +++ b/apps/opencs/model/filter/parser.cpp @@ -1,4 +1,3 @@ - #include "parser.hpp" #include diff --git a/apps/opencs/model/filter/textnode.cpp b/apps/opencs/model/filter/textnode.cpp index 73c378f11..246ebae24 100644 --- a/apps/opencs/model/filter/textnode.cpp +++ b/apps/opencs/model/filter/textnode.cpp @@ -1,4 +1,3 @@ - #include "textnode.hpp" #include diff --git a/apps/opencs/model/filter/unarynode.cpp b/apps/opencs/model/filter/unarynode.cpp index c40d191b6..cbdadf6fc 100644 --- a/apps/opencs/model/filter/unarynode.cpp +++ b/apps/opencs/model/filter/unarynode.cpp @@ -1,4 +1,3 @@ - #include "unarynode.hpp" CSMFilter::UnaryNode::UnaryNode (boost::shared_ptr child, const std::string& name) diff --git a/apps/opencs/model/filter/valuenode.cpp b/apps/opencs/model/filter/valuenode.cpp index 6fdb5cb02..85c5a8e27 100644 --- a/apps/opencs/model/filter/valuenode.cpp +++ b/apps/opencs/model/filter/valuenode.cpp @@ -1,4 +1,3 @@ - #include "valuenode.hpp" #include diff --git a/apps/opencs/model/tools/birthsigncheck.cpp b/apps/opencs/model/tools/birthsigncheck.cpp index 4e6da4631..9898352f1 100644 --- a/apps/opencs/model/tools/birthsigncheck.cpp +++ b/apps/opencs/model/tools/birthsigncheck.cpp @@ -1,4 +1,3 @@ - #include "birthsigncheck.hpp" #include diff --git a/apps/opencs/model/tools/classcheck.cpp b/apps/opencs/model/tools/classcheck.cpp index be57a3729..e4964d4e3 100644 --- a/apps/opencs/model/tools/classcheck.cpp +++ b/apps/opencs/model/tools/classcheck.cpp @@ -1,4 +1,3 @@ - #include "classcheck.hpp" #include diff --git a/apps/opencs/model/tools/factioncheck.cpp b/apps/opencs/model/tools/factioncheck.cpp index 0dfdee775..621b28070 100644 --- a/apps/opencs/model/tools/factioncheck.cpp +++ b/apps/opencs/model/tools/factioncheck.cpp @@ -1,4 +1,3 @@ - #include "factioncheck.hpp" #include diff --git a/apps/opencs/model/tools/mandatoryid.cpp b/apps/opencs/model/tools/mandatoryid.cpp index 4c97d2266..23adb9d37 100644 --- a/apps/opencs/model/tools/mandatoryid.cpp +++ b/apps/opencs/model/tools/mandatoryid.cpp @@ -1,4 +1,3 @@ - #include "mandatoryid.hpp" #include "../world/collectionbase.hpp" diff --git a/apps/opencs/model/tools/racecheck.cpp b/apps/opencs/model/tools/racecheck.cpp index 3b2c8d290..b30088620 100644 --- a/apps/opencs/model/tools/racecheck.cpp +++ b/apps/opencs/model/tools/racecheck.cpp @@ -1,4 +1,3 @@ - #include "racecheck.hpp" #include diff --git a/apps/opencs/model/tools/regioncheck.cpp b/apps/opencs/model/tools/regioncheck.cpp index 42abc35c9..2fdff5f38 100644 --- a/apps/opencs/model/tools/regioncheck.cpp +++ b/apps/opencs/model/tools/regioncheck.cpp @@ -1,4 +1,3 @@ - #include "regioncheck.hpp" #include diff --git a/apps/opencs/model/tools/reportmodel.cpp b/apps/opencs/model/tools/reportmodel.cpp index 4bf7d1581..77a14de84 100644 --- a/apps/opencs/model/tools/reportmodel.cpp +++ b/apps/opencs/model/tools/reportmodel.cpp @@ -1,4 +1,3 @@ - #include "reportmodel.hpp" #include diff --git a/apps/opencs/model/tools/scriptcheck.cpp b/apps/opencs/model/tools/scriptcheck.cpp index 665edd7a3..d7c41cfcf 100644 --- a/apps/opencs/model/tools/scriptcheck.cpp +++ b/apps/opencs/model/tools/scriptcheck.cpp @@ -1,4 +1,3 @@ - #include "scriptcheck.hpp" #include diff --git a/apps/opencs/model/tools/search.cpp b/apps/opencs/model/tools/search.cpp index 449df2c63..0409199af 100644 --- a/apps/opencs/model/tools/search.cpp +++ b/apps/opencs/model/tools/search.cpp @@ -1,4 +1,3 @@ - #include "search.hpp" #include diff --git a/apps/opencs/model/tools/searchoperation.cpp b/apps/opencs/model/tools/searchoperation.cpp index 8cbc5dc8e..8fba1cc1e 100644 --- a/apps/opencs/model/tools/searchoperation.cpp +++ b/apps/opencs/model/tools/searchoperation.cpp @@ -1,4 +1,3 @@ - #include "searchoperation.hpp" #include "../doc/state.hpp" diff --git a/apps/opencs/model/tools/searchstage.cpp b/apps/opencs/model/tools/searchstage.cpp index 17859d930..3db10b0c3 100644 --- a/apps/opencs/model/tools/searchstage.cpp +++ b/apps/opencs/model/tools/searchstage.cpp @@ -1,4 +1,3 @@ - #include "searchstage.hpp" #include "../world/idtablebase.hpp" diff --git a/apps/opencs/model/tools/skillcheck.cpp b/apps/opencs/model/tools/skillcheck.cpp index 2b55526e0..77ba8d4a2 100644 --- a/apps/opencs/model/tools/skillcheck.cpp +++ b/apps/opencs/model/tools/skillcheck.cpp @@ -1,4 +1,3 @@ - #include "skillcheck.hpp" #include diff --git a/apps/opencs/model/tools/soundcheck.cpp b/apps/opencs/model/tools/soundcheck.cpp index f78932a32..6a059bee2 100644 --- a/apps/opencs/model/tools/soundcheck.cpp +++ b/apps/opencs/model/tools/soundcheck.cpp @@ -1,4 +1,3 @@ - #include "soundcheck.hpp" #include diff --git a/apps/opencs/model/tools/spellcheck.cpp b/apps/opencs/model/tools/spellcheck.cpp index bd076d2a5..91aed37ed 100644 --- a/apps/opencs/model/tools/spellcheck.cpp +++ b/apps/opencs/model/tools/spellcheck.cpp @@ -1,4 +1,3 @@ - #include "spellcheck.hpp" #include diff --git a/apps/opencs/model/tools/startscriptcheck.cpp b/apps/opencs/model/tools/startscriptcheck.cpp index e3c01368b..220751797 100644 --- a/apps/opencs/model/tools/startscriptcheck.cpp +++ b/apps/opencs/model/tools/startscriptcheck.cpp @@ -1,4 +1,3 @@ - #include "startscriptcheck.hpp" #include diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index 97943b1fb..0c6e36a61 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -1,4 +1,3 @@ - #include "tools.hpp" #include diff --git a/apps/opencs/model/world/cell.cpp b/apps/opencs/model/world/cell.cpp index 40520a9ba..91becdb74 100644 --- a/apps/opencs/model/world/cell.cpp +++ b/apps/opencs/model/world/cell.cpp @@ -1,4 +1,3 @@ - #include "cell.hpp" #include diff --git a/apps/opencs/model/world/cellcoordinates.cpp b/apps/opencs/model/world/cellcoordinates.cpp index b1c8441e6..95e206e2d 100644 --- a/apps/opencs/model/world/cellcoordinates.cpp +++ b/apps/opencs/model/world/cellcoordinates.cpp @@ -1,4 +1,3 @@ - #include "cellcoordinates.hpp" #include diff --git a/apps/opencs/model/world/cellselection.cpp b/apps/opencs/model/world/cellselection.cpp index 73b5196f1..c6988e488 100644 --- a/apps/opencs/model/world/cellselection.cpp +++ b/apps/opencs/model/world/cellselection.cpp @@ -1,4 +1,3 @@ - #include "cellselection.hpp" #include diff --git a/apps/opencs/model/world/collectionbase.cpp b/apps/opencs/model/world/collectionbase.cpp index b8eed4192..6134dc172 100644 --- a/apps/opencs/model/world/collectionbase.cpp +++ b/apps/opencs/model/world/collectionbase.cpp @@ -1,4 +1,3 @@ - #include "collectionbase.hpp" #include diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 177fb59ce..1fcf0ae41 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -1,4 +1,3 @@ - #include "columns.hpp" #include diff --git a/apps/opencs/model/world/commanddispatcher.cpp b/apps/opencs/model/world/commanddispatcher.cpp index b9d5bd7fe..0b1af0e84 100644 --- a/apps/opencs/model/world/commanddispatcher.cpp +++ b/apps/opencs/model/world/commanddispatcher.cpp @@ -1,4 +1,3 @@ - #include "commanddispatcher.hpp" #include diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 25a04715d..12ff1a38c 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -1,4 +1,3 @@ - #include "data.hpp" #include diff --git a/apps/opencs/model/world/idtablebase.cpp b/apps/opencs/model/world/idtablebase.cpp index 389f5396e..274446b79 100644 --- a/apps/opencs/model/world/idtablebase.cpp +++ b/apps/opencs/model/world/idtablebase.cpp @@ -1,4 +1,3 @@ - #include "idtablebase.hpp" CSMWorld::IdTableBase::IdTableBase (unsigned int features) : mFeatures (features) {} diff --git a/apps/opencs/model/world/idtableproxymodel.cpp b/apps/opencs/model/world/idtableproxymodel.cpp index 757285412..fbf7b6cf3 100644 --- a/apps/opencs/model/world/idtableproxymodel.cpp +++ b/apps/opencs/model/world/idtableproxymodel.cpp @@ -1,4 +1,3 @@ - #include "idtableproxymodel.hpp" #include diff --git a/apps/opencs/model/world/infocollection.cpp b/apps/opencs/model/world/infocollection.cpp index 560be8131..60c613041 100644 --- a/apps/opencs/model/world/infocollection.cpp +++ b/apps/opencs/model/world/infocollection.cpp @@ -1,4 +1,3 @@ - #include "infocollection.hpp" #include diff --git a/apps/opencs/model/world/metadata.cpp b/apps/opencs/model/world/metadata.cpp index 40b8e9519..960fdc9e4 100644 --- a/apps/opencs/model/world/metadata.cpp +++ b/apps/opencs/model/world/metadata.cpp @@ -1,4 +1,3 @@ - #include "metadata.hpp" #include diff --git a/apps/opencs/model/world/record.cpp b/apps/opencs/model/world/record.cpp index ef2f4d320..f13a36afc 100644 --- a/apps/opencs/model/world/record.cpp +++ b/apps/opencs/model/world/record.cpp @@ -1,4 +1,3 @@ - #include "record.hpp" CSMWorld::RecordBase::~RecordBase() {} diff --git a/apps/opencs/model/world/ref.cpp b/apps/opencs/model/world/ref.cpp index 13706c950..638f7ec9c 100644 --- a/apps/opencs/model/world/ref.cpp +++ b/apps/opencs/model/world/ref.cpp @@ -1,4 +1,3 @@ - #include "ref.hpp" #include diff --git a/apps/opencs/model/world/refcollection.cpp b/apps/opencs/model/world/refcollection.cpp index ff30dafae..f8818807b 100644 --- a/apps/opencs/model/world/refcollection.cpp +++ b/apps/opencs/model/world/refcollection.cpp @@ -1,4 +1,3 @@ - #include "refcollection.hpp" #include diff --git a/apps/opencs/model/world/refiddata.cpp b/apps/opencs/model/world/refiddata.cpp index 7f5c25f36..c391201e6 100644 --- a/apps/opencs/model/world/refiddata.cpp +++ b/apps/opencs/model/world/refiddata.cpp @@ -1,4 +1,3 @@ - #include "refiddata.hpp" #include diff --git a/apps/opencs/model/world/regionmap.cpp b/apps/opencs/model/world/regionmap.cpp index 42bde9c81..10c67c909 100644 --- a/apps/opencs/model/world/regionmap.cpp +++ b/apps/opencs/model/world/regionmap.cpp @@ -1,4 +1,3 @@ - #include "regionmap.hpp" #include diff --git a/apps/opencs/model/world/resources.cpp b/apps/opencs/model/world/resources.cpp index 4dd480e77..b31e211ee 100644 --- a/apps/opencs/model/world/resources.cpp +++ b/apps/opencs/model/world/resources.cpp @@ -1,4 +1,3 @@ - #include "resources.hpp" #include diff --git a/apps/opencs/model/world/resourcesmanager.cpp b/apps/opencs/model/world/resourcesmanager.cpp index 3e2f72d93..2ec661cb1 100644 --- a/apps/opencs/model/world/resourcesmanager.cpp +++ b/apps/opencs/model/world/resourcesmanager.cpp @@ -1,4 +1,3 @@ - #include "resourcesmanager.hpp" #include diff --git a/apps/opencs/model/world/resourcetable.cpp b/apps/opencs/model/world/resourcetable.cpp index 2cd44781a..5227ec3e6 100644 --- a/apps/opencs/model/world/resourcetable.cpp +++ b/apps/opencs/model/world/resourcetable.cpp @@ -1,4 +1,3 @@ - #include "resourcetable.hpp" #include diff --git a/apps/opencs/model/world/scope.cpp b/apps/opencs/model/world/scope.cpp index 6e4ce4c02..b026c34c3 100644 --- a/apps/opencs/model/world/scope.cpp +++ b/apps/opencs/model/world/scope.cpp @@ -1,4 +1,3 @@ - #include "scope.hpp" #include diff --git a/apps/opencs/model/world/scriptcontext.cpp b/apps/opencs/model/world/scriptcontext.cpp index a8c2c9452..bcbca4b28 100644 --- a/apps/opencs/model/world/scriptcontext.cpp +++ b/apps/opencs/model/world/scriptcontext.cpp @@ -1,4 +1,3 @@ - #include "scriptcontext.hpp" #include diff --git a/apps/opencs/model/world/tablemimedata.hpp b/apps/opencs/model/world/tablemimedata.hpp index 06d252435..a42e97561 100644 --- a/apps/opencs/model/world/tablemimedata.hpp +++ b/apps/opencs/model/world/tablemimedata.hpp @@ -1,4 +1,3 @@ - #ifndef TABLEMIMEDATA_H #define TABLEMIMEDATA_H diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index 73d893a26..77db2be10 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -1,4 +1,3 @@ - #include "universalid.hpp" #include diff --git a/apps/opencs/view/doc/adjusterwidget.cpp b/apps/opencs/view/doc/adjusterwidget.cpp index 6571ad7c8..ba5dd90f8 100644 --- a/apps/opencs/view/doc/adjusterwidget.cpp +++ b/apps/opencs/view/doc/adjusterwidget.cpp @@ -1,4 +1,3 @@ - #include "adjusterwidget.hpp" #include diff --git a/apps/opencs/view/doc/filewidget.cpp b/apps/opencs/view/doc/filewidget.cpp index f18fe695a..bbb824823 100644 --- a/apps/opencs/view/doc/filewidget.cpp +++ b/apps/opencs/view/doc/filewidget.cpp @@ -1,4 +1,3 @@ - #include "filewidget.hpp" #include diff --git a/apps/opencs/view/doc/globaldebugprofilemenu.cpp b/apps/opencs/view/doc/globaldebugprofilemenu.cpp index b88381385..f0d9655dd 100644 --- a/apps/opencs/view/doc/globaldebugprofilemenu.cpp +++ b/apps/opencs/view/doc/globaldebugprofilemenu.cpp @@ -1,4 +1,3 @@ - #include "globaldebugprofilemenu.hpp" #include diff --git a/apps/opencs/view/doc/loader.cpp b/apps/opencs/view/doc/loader.cpp index 30235d0f5..713295d70 100644 --- a/apps/opencs/view/doc/loader.cpp +++ b/apps/opencs/view/doc/loader.cpp @@ -1,4 +1,3 @@ - #include "loader.hpp" #include diff --git a/apps/opencs/view/doc/newgame.cpp b/apps/opencs/view/doc/newgame.cpp index 32b483728..b3e2a4f63 100644 --- a/apps/opencs/view/doc/newgame.cpp +++ b/apps/opencs/view/doc/newgame.cpp @@ -1,4 +1,3 @@ - #include "newgame.hpp" #include diff --git a/apps/opencs/view/doc/runlogsubview.cpp b/apps/opencs/view/doc/runlogsubview.cpp index 129396999..2b7182228 100644 --- a/apps/opencs/view/doc/runlogsubview.cpp +++ b/apps/opencs/view/doc/runlogsubview.cpp @@ -1,4 +1,3 @@ - #include "runlogsubview.hpp" #include diff --git a/apps/opencs/view/doc/startup.cpp b/apps/opencs/view/doc/startup.cpp index 58a46c603..a9d697f1c 100644 --- a/apps/opencs/view/doc/startup.cpp +++ b/apps/opencs/view/doc/startup.cpp @@ -1,4 +1,3 @@ - #include "startup.hpp" #include diff --git a/apps/opencs/view/doc/subviewfactory.cpp b/apps/opencs/view/doc/subviewfactory.cpp index 3137f7e32..82a8aeb05 100644 --- a/apps/opencs/view/doc/subviewfactory.cpp +++ b/apps/opencs/view/doc/subviewfactory.cpp @@ -1,4 +1,3 @@ - #include "subviewfactory.hpp" #include diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 7914d2d8c..7c9686277 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -1,4 +1,3 @@ - #include "viewmanager.hpp" #include diff --git a/apps/opencs/view/filter/editwidget.cpp b/apps/opencs/view/filter/editwidget.cpp index bc7f9b5a1..657a47750 100644 --- a/apps/opencs/view/filter/editwidget.cpp +++ b/apps/opencs/view/filter/editwidget.cpp @@ -1,4 +1,3 @@ - #include "editwidget.hpp" #include diff --git a/apps/opencs/view/filter/filterbox.cpp b/apps/opencs/view/filter/filterbox.cpp index 7a42ef0a5..c6c6cc6cc 100644 --- a/apps/opencs/view/filter/filterbox.cpp +++ b/apps/opencs/view/filter/filterbox.cpp @@ -1,4 +1,3 @@ - #include "filterbox.hpp" #include diff --git a/apps/opencs/view/filter/recordfilterbox.cpp b/apps/opencs/view/filter/recordfilterbox.cpp index 97490d508..2bf589215 100644 --- a/apps/opencs/view/filter/recordfilterbox.cpp +++ b/apps/opencs/view/filter/recordfilterbox.cpp @@ -1,4 +1,3 @@ - #include "recordfilterbox.hpp" #include diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index fe2eab066..77bcff4fd 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -1,4 +1,3 @@ - #include "cell.hpp" #include diff --git a/apps/opencs/view/render/editmode.cpp b/apps/opencs/view/render/editmode.cpp index 9361030a3..8a99ba049 100644 --- a/apps/opencs/view/render/editmode.cpp +++ b/apps/opencs/view/render/editmode.cpp @@ -1,4 +1,3 @@ - #include "editmode.hpp" #include "worldspacewidget.hpp" diff --git a/apps/opencs/view/render/lightingbright.cpp b/apps/opencs/view/render/lightingbright.cpp index 00c4fb815..07900d6b0 100644 --- a/apps/opencs/view/render/lightingbright.cpp +++ b/apps/opencs/view/render/lightingbright.cpp @@ -1,4 +1,3 @@ - #include "lightingbright.hpp" #include diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index 2b53483ad..274c77620 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -1,4 +1,3 @@ - #include "pagedworldspacewidget.hpp" #include diff --git a/apps/opencs/view/render/previewwidget.cpp b/apps/opencs/view/render/previewwidget.cpp index f512a8bb6..a03b277d3 100644 --- a/apps/opencs/view/render/previewwidget.cpp +++ b/apps/opencs/view/render/previewwidget.cpp @@ -1,4 +1,3 @@ - #include "previewwidget.hpp" #include diff --git a/apps/opencs/view/render/unpagedworldspacewidget.cpp b/apps/opencs/view/render/unpagedworldspacewidget.cpp index 8e6e72cba..a5733ad10 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.cpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.cpp @@ -1,4 +1,3 @@ - #include "unpagedworldspacewidget.hpp" #include diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 39ce09f31..d45fc45a8 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -1,4 +1,3 @@ - #include "worldspacewidget.hpp" #include diff --git a/apps/opencs/view/tools/reportsubview.cpp b/apps/opencs/view/tools/reportsubview.cpp index e29447f25..a7316359e 100644 --- a/apps/opencs/view/tools/reportsubview.cpp +++ b/apps/opencs/view/tools/reportsubview.cpp @@ -1,4 +1,3 @@ - #include "reportsubview.hpp" #include "reporttable.hpp" diff --git a/apps/opencs/view/tools/reporttable.cpp b/apps/opencs/view/tools/reporttable.cpp index 550c53969..d4cecc971 100644 --- a/apps/opencs/view/tools/reporttable.cpp +++ b/apps/opencs/view/tools/reporttable.cpp @@ -1,4 +1,3 @@ - #include "reporttable.hpp" #include diff --git a/apps/opencs/view/tools/searchbox.cpp b/apps/opencs/view/tools/searchbox.cpp index 1307c1aab..d98044760 100644 --- a/apps/opencs/view/tools/searchbox.cpp +++ b/apps/opencs/view/tools/searchbox.cpp @@ -1,4 +1,3 @@ - #include "searchbox.hpp" #include diff --git a/apps/opencs/view/tools/searchsubview.cpp b/apps/opencs/view/tools/searchsubview.cpp index 8b35db6ae..d3fdbbf5d 100644 --- a/apps/opencs/view/tools/searchsubview.cpp +++ b/apps/opencs/view/tools/searchsubview.cpp @@ -1,4 +1,3 @@ - #include "searchsubview.hpp" #include diff --git a/apps/opencs/view/tools/subviews.cpp b/apps/opencs/view/tools/subviews.cpp index 8a343ebe8..8c3d6d50e 100644 --- a/apps/opencs/view/tools/subviews.cpp +++ b/apps/opencs/view/tools/subviews.cpp @@ -1,4 +1,3 @@ - #include "subviews.hpp" #include "../doc/subviewfactoryimp.hpp" diff --git a/apps/opencs/view/widget/modebutton.cpp b/apps/opencs/view/widget/modebutton.cpp index 56896b422..7c62f6bb1 100644 --- a/apps/opencs/view/widget/modebutton.cpp +++ b/apps/opencs/view/widget/modebutton.cpp @@ -1,4 +1,3 @@ - #include "modebutton.hpp" CSVWidget::ModeButton::ModeButton (const QIcon& icon, const QString& tooltip, QWidget *parent) diff --git a/apps/opencs/view/widget/pushbutton.cpp b/apps/opencs/view/widget/pushbutton.cpp index 1baeb7ca2..424aaf68a 100644 --- a/apps/opencs/view/widget/pushbutton.cpp +++ b/apps/opencs/view/widget/pushbutton.cpp @@ -1,4 +1,3 @@ - #include "pushbutton.hpp" #include diff --git a/apps/opencs/view/widget/scenetool.cpp b/apps/opencs/view/widget/scenetool.cpp index b8e9f895f..796b98567 100644 --- a/apps/opencs/view/widget/scenetool.cpp +++ b/apps/opencs/view/widget/scenetool.cpp @@ -1,4 +1,3 @@ - #include "scenetool.hpp" #include diff --git a/apps/opencs/view/widget/scenetoolbar.cpp b/apps/opencs/view/widget/scenetoolbar.cpp index f7023b31f..b2e988dc9 100644 --- a/apps/opencs/view/widget/scenetoolbar.cpp +++ b/apps/opencs/view/widget/scenetoolbar.cpp @@ -1,4 +1,3 @@ - #include "scenetoolbar.hpp" #include diff --git a/apps/opencs/view/widget/scenetoolmode.cpp b/apps/opencs/view/widget/scenetoolmode.cpp index 39e051c48..9f963873c 100644 --- a/apps/opencs/view/widget/scenetoolmode.cpp +++ b/apps/opencs/view/widget/scenetoolmode.cpp @@ -1,4 +1,3 @@ - #include "scenetoolmode.hpp" #include diff --git a/apps/opencs/view/widget/scenetoolrun.cpp b/apps/opencs/view/widget/scenetoolrun.cpp index 4c9eb676e..1e2d44e7a 100644 --- a/apps/opencs/view/widget/scenetoolrun.cpp +++ b/apps/opencs/view/widget/scenetoolrun.cpp @@ -1,4 +1,3 @@ - #include "scenetoolrun.hpp" #include diff --git a/apps/opencs/view/widget/scenetooltoggle.cpp b/apps/opencs/view/widget/scenetooltoggle.cpp index 07c448e45..d7251882a 100644 --- a/apps/opencs/view/widget/scenetooltoggle.cpp +++ b/apps/opencs/view/widget/scenetooltoggle.cpp @@ -1,4 +1,3 @@ - #include "scenetooltoggle.hpp" #include diff --git a/apps/opencs/view/widget/scenetooltoggle2.cpp b/apps/opencs/view/widget/scenetooltoggle2.cpp index 313e519cb..e0431476e 100644 --- a/apps/opencs/view/widget/scenetooltoggle2.cpp +++ b/apps/opencs/view/widget/scenetooltoggle2.cpp @@ -1,4 +1,3 @@ - #include "scenetooltoggle2.hpp" #include diff --git a/apps/opencs/view/world/cellcreator.cpp b/apps/opencs/view/world/cellcreator.cpp index c7d909f4c..2a710a940 100644 --- a/apps/opencs/view/world/cellcreator.cpp +++ b/apps/opencs/view/world/cellcreator.cpp @@ -1,4 +1,3 @@ - #include "cellcreator.hpp" #include diff --git a/apps/opencs/view/world/creator.cpp b/apps/opencs/view/world/creator.cpp index 7a8c8d48f..7a93339c5 100644 --- a/apps/opencs/view/world/creator.cpp +++ b/apps/opencs/view/world/creator.cpp @@ -1,4 +1,3 @@ - #include "creator.hpp" #include diff --git a/apps/opencs/view/world/dialoguecreator.cpp b/apps/opencs/view/world/dialoguecreator.cpp index 3d451ed2d..7c6fb2e81 100644 --- a/apps/opencs/view/world/dialoguecreator.cpp +++ b/apps/opencs/view/world/dialoguecreator.cpp @@ -1,4 +1,3 @@ - #include "dialoguecreator.hpp" #include diff --git a/apps/opencs/view/world/enumdelegate.cpp b/apps/opencs/view/world/enumdelegate.cpp index 2190a62c6..e582e3356 100644 --- a/apps/opencs/view/world/enumdelegate.cpp +++ b/apps/opencs/view/world/enumdelegate.cpp @@ -1,4 +1,3 @@ - #include "enumdelegate.hpp" #include diff --git a/apps/opencs/view/world/genericcreator.cpp b/apps/opencs/view/world/genericcreator.cpp index 5f04d9a7a..8ed52bf80 100644 --- a/apps/opencs/view/world/genericcreator.cpp +++ b/apps/opencs/view/world/genericcreator.cpp @@ -1,4 +1,3 @@ - #include "genericcreator.hpp" #include diff --git a/apps/opencs/view/world/idvalidator.cpp b/apps/opencs/view/world/idvalidator.cpp index 13b05d2d1..1092d7217 100644 --- a/apps/opencs/view/world/idvalidator.cpp +++ b/apps/opencs/view/world/idvalidator.cpp @@ -1,4 +1,3 @@ - #include "idvalidator.hpp" #include diff --git a/apps/opencs/view/world/infocreator.cpp b/apps/opencs/view/world/infocreator.cpp index 268a82a28..1139afd69 100644 --- a/apps/opencs/view/world/infocreator.cpp +++ b/apps/opencs/view/world/infocreator.cpp @@ -1,4 +1,3 @@ - #include "infocreator.hpp" #include diff --git a/apps/opencs/view/world/previewsubview.cpp b/apps/opencs/view/world/previewsubview.cpp index 756e79fe6..f3312bb20 100644 --- a/apps/opencs/view/world/previewsubview.cpp +++ b/apps/opencs/view/world/previewsubview.cpp @@ -1,4 +1,3 @@ - #include "previewsubview.hpp" #include diff --git a/apps/opencs/view/world/recordbuttonbar.cpp b/apps/opencs/view/world/recordbuttonbar.cpp index 9cae0d0c9..1a838a3b3 100644 --- a/apps/opencs/view/world/recordbuttonbar.cpp +++ b/apps/opencs/view/world/recordbuttonbar.cpp @@ -1,4 +1,3 @@ - #include "recordbuttonbar.hpp" #include diff --git a/apps/opencs/view/world/referenceablecreator.cpp b/apps/opencs/view/world/referenceablecreator.cpp index e8055ed31..1357ca46f 100644 --- a/apps/opencs/view/world/referenceablecreator.cpp +++ b/apps/opencs/view/world/referenceablecreator.cpp @@ -1,4 +1,3 @@ - #include "referenceablecreator.hpp" #include diff --git a/apps/opencs/view/world/referencecreator.cpp b/apps/opencs/view/world/referencecreator.cpp index 2b0d44df0..73ca62e02 100644 --- a/apps/opencs/view/world/referencecreator.cpp +++ b/apps/opencs/view/world/referencecreator.cpp @@ -1,4 +1,3 @@ - #include "referencecreator.hpp" #include diff --git a/apps/opencs/view/world/regionmap.cpp b/apps/opencs/view/world/regionmap.cpp index bc96b0952..49764bd17 100644 --- a/apps/opencs/view/world/regionmap.cpp +++ b/apps/opencs/view/world/regionmap.cpp @@ -1,4 +1,3 @@ - #include "regionmap.hpp" #include diff --git a/apps/opencs/view/world/regionmapsubview.cpp b/apps/opencs/view/world/regionmapsubview.cpp index 411e24e75..996d1dc8b 100644 --- a/apps/opencs/view/world/regionmapsubview.cpp +++ b/apps/opencs/view/world/regionmapsubview.cpp @@ -1,4 +1,3 @@ - #include "regionmapsubview.hpp" #include "regionmap.hpp" diff --git a/apps/opencs/view/world/scenesubview.cpp b/apps/opencs/view/world/scenesubview.cpp index b7a795e23..2ca2548c0 100644 --- a/apps/opencs/view/world/scenesubview.cpp +++ b/apps/opencs/view/world/scenesubview.cpp @@ -1,4 +1,3 @@ - #include "scenesubview.hpp" #include diff --git a/apps/opencs/view/world/scripterrortable.cpp b/apps/opencs/view/world/scripterrortable.cpp index 415e6c9dc..b44e1c0bd 100644 --- a/apps/opencs/view/world/scripterrortable.cpp +++ b/apps/opencs/view/world/scripterrortable.cpp @@ -1,4 +1,3 @@ - #include "scripterrortable.hpp" #include diff --git a/apps/opencs/view/world/scripthighlighter.cpp b/apps/opencs/view/world/scripthighlighter.cpp index 4923a44d8..487b5b139 100644 --- a/apps/opencs/view/world/scripthighlighter.cpp +++ b/apps/opencs/view/world/scripthighlighter.cpp @@ -1,4 +1,3 @@ - #include "scripthighlighter.hpp" #include diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp index b8a6ba429..299ac6ebe 100644 --- a/apps/opencs/view/world/subviews.cpp +++ b/apps/opencs/view/world/subviews.cpp @@ -1,4 +1,3 @@ - #include "subviews.hpp" #include "../doc/subviewfactoryimp.hpp" diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index 41c33761e..72e0c82d0 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -1,4 +1,3 @@ - #include "table.hpp" #include diff --git a/apps/opencs/view/world/tablebottombox.cpp b/apps/opencs/view/world/tablebottombox.cpp index 7e66106fc..eed522227 100644 --- a/apps/opencs/view/world/tablebottombox.cpp +++ b/apps/opencs/view/world/tablebottombox.cpp @@ -1,4 +1,3 @@ - #include "tablebottombox.hpp" #include diff --git a/apps/opencs/view/world/tablesubview.cpp b/apps/opencs/view/world/tablesubview.cpp index 5fd094506..81b269993 100644 --- a/apps/opencs/view/world/tablesubview.cpp +++ b/apps/opencs/view/world/tablesubview.cpp @@ -1,4 +1,3 @@ - #include "tablesubview.hpp" #include diff --git a/apps/opencs/view/world/util.cpp b/apps/opencs/view/world/util.cpp index f21658581..2654644c4 100644 --- a/apps/opencs/view/world/util.cpp +++ b/apps/opencs/view/world/util.cpp @@ -1,4 +1,3 @@ - #include "util.hpp" #include diff --git a/apps/opencs/view/world/vartypedelegate.cpp b/apps/opencs/view/world/vartypedelegate.cpp index 90a686a67..a63e6028c 100644 --- a/apps/opencs/view/world/vartypedelegate.cpp +++ b/apps/opencs/view/world/vartypedelegate.cpp @@ -1,4 +1,3 @@ - #include "vartypedelegate.hpp" #include diff --git a/apps/openmw/android_commandLine.h b/apps/openmw/android_commandLine.h index 21d1064c6..5ca79c2d0 100644 --- a/apps/openmw/android_commandLine.h +++ b/apps/openmw/android_commandLine.h @@ -1,5 +1,4 @@ - /* DO NOT EDIT THIS FILE - it is machine generated */ #include #ifndef _Included_ui_activity_GameActivity_commandLine diff --git a/apps/openmw/mwbase/environment.cpp b/apps/openmw/mwbase/environment.cpp index a90eec5bf..4efa7c273 100644 --- a/apps/openmw/mwbase/environment.cpp +++ b/apps/openmw/mwbase/environment.cpp @@ -1,4 +1,3 @@ - #include "environment.hpp" #include diff --git a/apps/openmw/mwclass/activator.cpp b/apps/openmw/mwclass/activator.cpp index 4cf33ceb8..3a0f1b951 100644 --- a/apps/openmw/mwclass/activator.cpp +++ b/apps/openmw/mwclass/activator.cpp @@ -1,4 +1,3 @@ - #include "activator.hpp" #include diff --git a/apps/openmw/mwclass/apparatus.cpp b/apps/openmw/mwclass/apparatus.cpp index 6f11a36c7..f93556ef9 100644 --- a/apps/openmw/mwclass/apparatus.cpp +++ b/apps/openmw/mwclass/apparatus.cpp @@ -1,4 +1,3 @@ - #include "apparatus.hpp" #include diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index 04c98e437..2ba8ba03b 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -1,4 +1,3 @@ - #include "armor.hpp" #include diff --git a/apps/openmw/mwclass/classes.cpp b/apps/openmw/mwclass/classes.cpp index e9538a6cb..c303b23af 100644 --- a/apps/openmw/mwclass/classes.cpp +++ b/apps/openmw/mwclass/classes.cpp @@ -1,4 +1,3 @@ - #include "classes.hpp" #include "activator.hpp" diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index 8964b65e0..cea30d561 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -1,4 +1,3 @@ - #include "clothing.hpp" #include diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index 830493627..f785797c1 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -1,4 +1,3 @@ - #include "container.hpp" #include diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 8b7bcf6b9..60874bb5e 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -1,4 +1,3 @@ - #include "creature.hpp" #include diff --git a/apps/openmw/mwclass/creaturelevlist.cpp b/apps/openmw/mwclass/creaturelevlist.cpp index dbc4b6af7..433e5fcea 100644 --- a/apps/openmw/mwclass/creaturelevlist.cpp +++ b/apps/openmw/mwclass/creaturelevlist.cpp @@ -1,4 +1,3 @@ - #include "creaturelevlist.hpp" #include diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 5062cc557..6749afa6b 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -1,4 +1,3 @@ - #include "door.hpp" #include diff --git a/apps/openmw/mwclass/ingredient.cpp b/apps/openmw/mwclass/ingredient.cpp index fb409cb55..c9e6e70f2 100644 --- a/apps/openmw/mwclass/ingredient.cpp +++ b/apps/openmw/mwclass/ingredient.cpp @@ -1,4 +1,3 @@ - #include "ingredient.hpp" #include diff --git a/apps/openmw/mwclass/itemlevlist.cpp b/apps/openmw/mwclass/itemlevlist.cpp index d31080bb2..a70f31115 100644 --- a/apps/openmw/mwclass/itemlevlist.cpp +++ b/apps/openmw/mwclass/itemlevlist.cpp @@ -1,4 +1,3 @@ - #include "itemlevlist.hpp" #include diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 1e882b568..c532b5d65 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -1,4 +1,3 @@ - #include "light.hpp" #include diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index 8f22c3fa1..5cffdf13a 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -1,4 +1,3 @@ - #include "lockpick.hpp" #include diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index 0c80209f2..98b4faab9 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -1,4 +1,3 @@ - #include "misc.hpp" #include diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 75b612dad..e2b714a64 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -1,4 +1,3 @@ - #include "npc.hpp" #include diff --git a/apps/openmw/mwclass/potion.cpp b/apps/openmw/mwclass/potion.cpp index 647f83f67..cf6b0919b 100644 --- a/apps/openmw/mwclass/potion.cpp +++ b/apps/openmw/mwclass/potion.cpp @@ -1,4 +1,3 @@ - #include "potion.hpp" #include diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index cb43ccce6..ff717c506 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -1,4 +1,3 @@ - #include "probe.hpp" #include diff --git a/apps/openmw/mwclass/repair.cpp b/apps/openmw/mwclass/repair.cpp index 0bc64a99e..e6baea2e0 100644 --- a/apps/openmw/mwclass/repair.cpp +++ b/apps/openmw/mwclass/repair.cpp @@ -1,4 +1,3 @@ - #include "repair.hpp" #include diff --git a/apps/openmw/mwclass/static.cpp b/apps/openmw/mwclass/static.cpp index 6438046de..9755df28e 100644 --- a/apps/openmw/mwclass/static.cpp +++ b/apps/openmw/mwclass/static.cpp @@ -1,4 +1,3 @@ - #include "static.hpp" #include diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index 8c3d7fb10..da4c7deb2 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -1,4 +1,3 @@ - #include "weapon.hpp" #include diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 042267ebe..35f205eb8 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -1,4 +1,3 @@ - #include "dialoguemanagerimp.hpp" #include diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index 29fac1c67..5e6b83b50 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -1,4 +1,3 @@ - #include "filter.hpp" #include diff --git a/apps/openmw/mwdialogue/journalentry.cpp b/apps/openmw/mwdialogue/journalentry.cpp index 9f07f7b6f..2f5f02b01 100644 --- a/apps/openmw/mwdialogue/journalentry.cpp +++ b/apps/openmw/mwdialogue/journalentry.cpp @@ -1,4 +1,3 @@ - #include "journalentry.hpp" #include diff --git a/apps/openmw/mwdialogue/journalimp.cpp b/apps/openmw/mwdialogue/journalimp.cpp index 99dab0cf8..e6ffe22ab 100644 --- a/apps/openmw/mwdialogue/journalimp.cpp +++ b/apps/openmw/mwdialogue/journalimp.cpp @@ -1,4 +1,3 @@ - #include "journalimp.hpp" #include diff --git a/apps/openmw/mwdialogue/quest.cpp b/apps/openmw/mwdialogue/quest.cpp index a9e39b379..846597886 100644 --- a/apps/openmw/mwdialogue/quest.cpp +++ b/apps/openmw/mwdialogue/quest.cpp @@ -1,4 +1,3 @@ - #include "quest.hpp" #include diff --git a/apps/openmw/mwdialogue/selectwrapper.cpp b/apps/openmw/mwdialogue/selectwrapper.cpp index fa0fbfe13..a4eba30ae 100644 --- a/apps/openmw/mwdialogue/selectwrapper.cpp +++ b/apps/openmw/mwdialogue/selectwrapper.cpp @@ -1,4 +1,3 @@ - #include "selectwrapper.hpp" #include diff --git a/apps/openmw/mwdialogue/topic.cpp b/apps/openmw/mwdialogue/topic.cpp index c1a45f841..eb7fbdc1d 100644 --- a/apps/openmw/mwdialogue/topic.cpp +++ b/apps/openmw/mwdialogue/topic.cpp @@ -1,4 +1,3 @@ - #include "topic.hpp" #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp index b2f172076..384bccfea 100644 --- a/apps/openmw/mwgui/tooltips.hpp +++ b/apps/openmw/mwgui/tooltips.hpp @@ -1,4 +1,3 @@ - #ifndef MWGUI_TOOLTIPS_H #define MWGUI_TOOLTIPS_H diff --git a/apps/openmw/mwmechanics/alchemy.cpp b/apps/openmw/mwmechanics/alchemy.cpp index dd25e5a55..38d85a7cd 100644 --- a/apps/openmw/mwmechanics/alchemy.cpp +++ b/apps/openmw/mwmechanics/alchemy.cpp @@ -1,4 +1,3 @@ - #include "alchemy.hpp" #include diff --git a/apps/openmw/mwmechanics/magiceffects.cpp b/apps/openmw/mwmechanics/magiceffects.cpp index 0b19df0a8..021691d6a 100644 --- a/apps/openmw/mwmechanics/magiceffects.cpp +++ b/apps/openmw/mwmechanics/magiceffects.cpp @@ -1,4 +1,3 @@ - #include "magiceffects.hpp" #include diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index b9aa8b301..10d603ff1 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -1,4 +1,3 @@ - #include "npcstats.hpp" #include diff --git a/apps/openmw/mwmechanics/spells.cpp b/apps/openmw/mwmechanics/spells.cpp index fe0f892db..6d7673a59 100644 --- a/apps/openmw/mwmechanics/spells.cpp +++ b/apps/openmw/mwmechanics/spells.cpp @@ -1,4 +1,3 @@ - #include "spells.hpp" #include diff --git a/apps/openmw/mwscript/aiextensions.cpp b/apps/openmw/mwscript/aiextensions.cpp index 4a7952c44..78c84141a 100644 --- a/apps/openmw/mwscript/aiextensions.cpp +++ b/apps/openmw/mwscript/aiextensions.cpp @@ -1,4 +1,3 @@ - #include "aiextensions.hpp" #include diff --git a/apps/openmw/mwscript/animationextensions.cpp b/apps/openmw/mwscript/animationextensions.cpp index c43cdf565..07a8a300a 100644 --- a/apps/openmw/mwscript/animationextensions.cpp +++ b/apps/openmw/mwscript/animationextensions.cpp @@ -1,4 +1,3 @@ - #include "animationextensions.hpp" #include diff --git a/apps/openmw/mwscript/compilercontext.cpp b/apps/openmw/mwscript/compilercontext.cpp index 3ff75eeae..083f463bc 100644 --- a/apps/openmw/mwscript/compilercontext.cpp +++ b/apps/openmw/mwscript/compilercontext.cpp @@ -1,4 +1,3 @@ - #include "compilercontext.hpp" #include "../mwworld/esmstore.hpp" diff --git a/apps/openmw/mwscript/consoleextensions.cpp b/apps/openmw/mwscript/consoleextensions.cpp index 30956d429..d2e07d3e1 100644 --- a/apps/openmw/mwscript/consoleextensions.cpp +++ b/apps/openmw/mwscript/consoleextensions.cpp @@ -1,4 +1,3 @@ - #include "consoleextensions.hpp" #include diff --git a/apps/openmw/mwscript/containerextensions.cpp b/apps/openmw/mwscript/containerextensions.cpp index ba18d8e37..674973978 100644 --- a/apps/openmw/mwscript/containerextensions.cpp +++ b/apps/openmw/mwscript/containerextensions.cpp @@ -1,4 +1,3 @@ - #include "containerextensions.hpp" #include diff --git a/apps/openmw/mwscript/controlextensions.cpp b/apps/openmw/mwscript/controlextensions.cpp index 904e0ee85..626fafb5a 100644 --- a/apps/openmw/mwscript/controlextensions.cpp +++ b/apps/openmw/mwscript/controlextensions.cpp @@ -1,4 +1,3 @@ - #include "controlextensions.hpp" #include diff --git a/apps/openmw/mwscript/dialogueextensions.cpp b/apps/openmw/mwscript/dialogueextensions.cpp index 8b6805264..c305fb81f 100644 --- a/apps/openmw/mwscript/dialogueextensions.cpp +++ b/apps/openmw/mwscript/dialogueextensions.cpp @@ -1,4 +1,3 @@ - #include "dialogueextensions.hpp" #include diff --git a/apps/openmw/mwscript/extensions.cpp b/apps/openmw/mwscript/extensions.cpp index 2170ba4fb..12bf3413a 100644 --- a/apps/openmw/mwscript/extensions.cpp +++ b/apps/openmw/mwscript/extensions.cpp @@ -1,4 +1,3 @@ - #include "extensions.hpp" #include diff --git a/apps/openmw/mwscript/globalscripts.cpp b/apps/openmw/mwscript/globalscripts.cpp index 44d96e949..f339fa520 100644 --- a/apps/openmw/mwscript/globalscripts.cpp +++ b/apps/openmw/mwscript/globalscripts.cpp @@ -1,4 +1,3 @@ - #include "globalscripts.hpp" #include diff --git a/apps/openmw/mwscript/guiextensions.cpp b/apps/openmw/mwscript/guiextensions.cpp index 40c555f50..f48360c04 100644 --- a/apps/openmw/mwscript/guiextensions.cpp +++ b/apps/openmw/mwscript/guiextensions.cpp @@ -1,4 +1,3 @@ - #include "guiextensions.hpp" #include diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index df675aebb..b0d4d3f2d 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -1,4 +1,3 @@ - #include "interpretercontext.hpp" #include diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 9a9127977..faf574993 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -1,4 +1,3 @@ - #include "miscextensions.hpp" #include diff --git a/apps/openmw/mwscript/scriptmanagerimp.cpp b/apps/openmw/mwscript/scriptmanagerimp.cpp index 5f755e542..084beb812 100644 --- a/apps/openmw/mwscript/scriptmanagerimp.cpp +++ b/apps/openmw/mwscript/scriptmanagerimp.cpp @@ -1,4 +1,3 @@ - #include "scriptmanagerimp.hpp" #include diff --git a/apps/openmw/mwscript/skyextensions.cpp b/apps/openmw/mwscript/skyextensions.cpp index d28d01b63..e0fccd16d 100644 --- a/apps/openmw/mwscript/skyextensions.cpp +++ b/apps/openmw/mwscript/skyextensions.cpp @@ -1,4 +1,3 @@ - #include "skyextensions.hpp" #include diff --git a/apps/openmw/mwscript/soundextensions.cpp b/apps/openmw/mwscript/soundextensions.cpp index 606de7aa0..a9896d203 100644 --- a/apps/openmw/mwscript/soundextensions.cpp +++ b/apps/openmw/mwscript/soundextensions.cpp @@ -1,4 +1,3 @@ - #include "extensions.hpp" #include diff --git a/apps/openmw/mwscript/userextensions.cpp b/apps/openmw/mwscript/userextensions.cpp index 538133c65..165a93062 100644 --- a/apps/openmw/mwscript/userextensions.cpp +++ b/apps/openmw/mwscript/userextensions.cpp @@ -1,4 +1,3 @@ - #include "userextensions.hpp" #include diff --git a/apps/openmw/mwstate/character.cpp b/apps/openmw/mwstate/character.cpp index fcd1ca19e..733ac1171 100644 --- a/apps/openmw/mwstate/character.cpp +++ b/apps/openmw/mwstate/character.cpp @@ -1,4 +1,3 @@ - #include "character.hpp" #include diff --git a/apps/openmw/mwstate/charactermanager.cpp b/apps/openmw/mwstate/charactermanager.cpp index 70e9f0925..22192c355 100644 --- a/apps/openmw/mwstate/charactermanager.cpp +++ b/apps/openmw/mwstate/charactermanager.cpp @@ -1,4 +1,3 @@ - #include "charactermanager.hpp" #include diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index ac8dc863a..f4a7ee9f2 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -1,4 +1,3 @@ - #include "statemanagerimp.hpp" #include diff --git a/apps/openmw/mwworld/action.cpp b/apps/openmw/mwworld/action.cpp index 5e1fb41a6..fb2059de9 100644 --- a/apps/openmw/mwworld/action.cpp +++ b/apps/openmw/mwworld/action.cpp @@ -1,4 +1,3 @@ - #include "action.hpp" #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwworld/actionapply.cpp b/apps/openmw/mwworld/actionapply.cpp index bfd64c85d..00c9628ce 100644 --- a/apps/openmw/mwworld/actionapply.cpp +++ b/apps/openmw/mwworld/actionapply.cpp @@ -1,4 +1,3 @@ - #include "actionapply.hpp" #include "class.hpp" diff --git a/apps/openmw/mwworld/actioneat.cpp b/apps/openmw/mwworld/actioneat.cpp index 8bb80b564..d9ca4aaf5 100644 --- a/apps/openmw/mwworld/actioneat.cpp +++ b/apps/openmw/mwworld/actioneat.cpp @@ -1,4 +1,3 @@ - #include "actioneat.hpp" #include diff --git a/apps/openmw/mwworld/actionopen.hpp b/apps/openmw/mwworld/actionopen.hpp index 8578995ae..454cc09f1 100644 --- a/apps/openmw/mwworld/actionopen.hpp +++ b/apps/openmw/mwworld/actionopen.hpp @@ -1,4 +1,3 @@ - #ifndef GAME_MWWORLD_ACTIONOPEN_H #define GAME_MWWORLD_ACTIONOPEN_H diff --git a/apps/openmw/mwworld/actiontake.cpp b/apps/openmw/mwworld/actiontake.cpp index 269d941dc..4e6135764 100644 --- a/apps/openmw/mwworld/actiontake.cpp +++ b/apps/openmw/mwworld/actiontake.cpp @@ -1,4 +1,3 @@ - #include "actiontake.hpp" #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwworld/actiontalk.cpp b/apps/openmw/mwworld/actiontalk.cpp index 905497f85..051380ff5 100644 --- a/apps/openmw/mwworld/actiontalk.cpp +++ b/apps/openmw/mwworld/actiontalk.cpp @@ -1,4 +1,3 @@ - #include "actiontalk.hpp" #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 18200e33b..4c73c603b 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -1,4 +1,3 @@ - #include "class.hpp" #include diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 3a7c02332..05ae4f134 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -1,4 +1,3 @@ - #include "containerstore.hpp" #include diff --git a/apps/openmw/mwworld/globals.cpp b/apps/openmw/mwworld/globals.cpp index e7cb04590..dcd7924a2 100644 --- a/apps/openmw/mwworld/globals.cpp +++ b/apps/openmw/mwworld/globals.cpp @@ -1,4 +1,3 @@ - #include "globals.hpp" #include diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 2fe914a4e..2dbc22234 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -1,4 +1,3 @@ - #include "inventorystore.hpp" #include diff --git a/apps/openmw/mwworld/ptr.cpp b/apps/openmw/mwworld/ptr.cpp index 1cf22744a..4d74c3c58 100644 --- a/apps/openmw/mwworld/ptr.cpp +++ b/apps/openmw/mwworld/ptr.cpp @@ -1,4 +1,3 @@ - #include "ptr.hpp" #include diff --git a/apps/openmw/mwworld/refdata.cpp b/apps/openmw/mwworld/refdata.cpp index c4f63137a..2062e78d9 100644 --- a/apps/openmw/mwworld/refdata.cpp +++ b/apps/openmw/mwworld/refdata.cpp @@ -1,4 +1,3 @@ - #include "refdata.hpp" #include diff --git a/components/compiler/controlparser.cpp b/components/compiler/controlparser.cpp index aefe6d16d..b202467db 100644 --- a/components/compiler/controlparser.cpp +++ b/components/compiler/controlparser.cpp @@ -1,4 +1,3 @@ - #include "controlparser.hpp" #include diff --git a/components/compiler/declarationparser.cpp b/components/compiler/declarationparser.cpp index 7961b8f41..ffac252d5 100644 --- a/components/compiler/declarationparser.cpp +++ b/components/compiler/declarationparser.cpp @@ -1,4 +1,3 @@ - #include "declarationparser.hpp" #include diff --git a/components/compiler/discardparser.cpp b/components/compiler/discardparser.cpp index 6028968bb..da114fb3d 100644 --- a/components/compiler/discardparser.cpp +++ b/components/compiler/discardparser.cpp @@ -1,4 +1,3 @@ - #include "discardparser.hpp" #include "scanner.hpp" diff --git a/components/compiler/errorhandler.cpp b/components/compiler/errorhandler.cpp index bcd30ef2d..a987a86da 100644 --- a/components/compiler/errorhandler.cpp +++ b/components/compiler/errorhandler.cpp @@ -1,4 +1,3 @@ - #include "errorhandler.hpp" namespace Compiler diff --git a/components/compiler/errorhandler.hpp b/components/compiler/errorhandler.hpp index c92e7bb8d..ea904e385 100644 --- a/components/compiler/errorhandler.hpp +++ b/components/compiler/errorhandler.hpp @@ -1,4 +1,3 @@ - #ifndef COMPILER_ERRORHANDLER_H_INCLUDED #define COMPILER_ERRORHANDLER_H_INCLUDED diff --git a/components/compiler/exprparser.cpp b/components/compiler/exprparser.cpp index 1818d04df..b588b6196 100644 --- a/components/compiler/exprparser.cpp +++ b/components/compiler/exprparser.cpp @@ -1,4 +1,3 @@ - #include "exprparser.hpp" #include diff --git a/components/compiler/extensions.cpp b/components/compiler/extensions.cpp index c2b11c615..dbb953e20 100644 --- a/components/compiler/extensions.cpp +++ b/components/compiler/extensions.cpp @@ -1,4 +1,3 @@ - #include "extensions.hpp" #include diff --git a/components/compiler/generator.cpp b/components/compiler/generator.cpp index ead0c7290..7e6437e20 100644 --- a/components/compiler/generator.cpp +++ b/components/compiler/generator.cpp @@ -1,4 +1,3 @@ - #include "generator.hpp" #include diff --git a/components/compiler/junkparser.cpp b/components/compiler/junkparser.cpp index cfa94044e..7608e9bab 100644 --- a/components/compiler/junkparser.cpp +++ b/components/compiler/junkparser.cpp @@ -1,4 +1,3 @@ - #include "junkparser.hpp" #include "scanner.hpp" diff --git a/components/compiler/lineparser.cpp b/components/compiler/lineparser.cpp index 4d6e147fc..032af7d65 100644 --- a/components/compiler/lineparser.cpp +++ b/components/compiler/lineparser.cpp @@ -1,4 +1,3 @@ - #include "lineparser.hpp" #include diff --git a/components/compiler/literals.cpp b/components/compiler/literals.cpp index 626b03afb..ee2c4d345 100644 --- a/components/compiler/literals.cpp +++ b/components/compiler/literals.cpp @@ -1,4 +1,3 @@ - #include "literals.hpp" #include diff --git a/components/compiler/locals.cpp b/components/compiler/locals.cpp index 60a5704bf..768fc077c 100644 --- a/components/compiler/locals.cpp +++ b/components/compiler/locals.cpp @@ -1,4 +1,3 @@ - #include "locals.hpp" #include diff --git a/components/compiler/nullerrorhandler.cpp b/components/compiler/nullerrorhandler.cpp index ee2884705..a0db53a00 100644 --- a/components/compiler/nullerrorhandler.cpp +++ b/components/compiler/nullerrorhandler.cpp @@ -1,4 +1,3 @@ - #include "nullerrorhandler.hpp" void Compiler::NullErrorHandler::report (const std::string& message, const TokenLoc& loc, Type type) {} diff --git a/components/compiler/nullerrorhandler.hpp b/components/compiler/nullerrorhandler.hpp index bb4db99a2..3dcff9250 100644 --- a/components/compiler/nullerrorhandler.hpp +++ b/components/compiler/nullerrorhandler.hpp @@ -1,4 +1,3 @@ - #ifndef COMPILER_NULLERRORHANDLER_H_INCLUDED #define COMPILER_NULLERRORHANDLER_H_INCLUDED diff --git a/components/compiler/output.cpp b/components/compiler/output.cpp index 46e04b8dc..785b2ce84 100644 --- a/components/compiler/output.cpp +++ b/components/compiler/output.cpp @@ -1,4 +1,3 @@ - #include "output.hpp" #include diff --git a/components/compiler/parser.cpp b/components/compiler/parser.cpp index 0f442c350..fe019718a 100644 --- a/components/compiler/parser.cpp +++ b/components/compiler/parser.cpp @@ -1,4 +1,3 @@ - #include "parser.hpp" #include diff --git a/components/compiler/quickfileparser.cpp b/components/compiler/quickfileparser.cpp index 4e9f76e13..53aaf96e5 100644 --- a/components/compiler/quickfileparser.cpp +++ b/components/compiler/quickfileparser.cpp @@ -1,4 +1,3 @@ - #include "quickfileparser.hpp" #include "skipparser.hpp" diff --git a/components/compiler/scanner.cpp b/components/compiler/scanner.cpp index de7f7e1e1..5af396d27 100644 --- a/components/compiler/scanner.cpp +++ b/components/compiler/scanner.cpp @@ -1,4 +1,3 @@ - #include "scanner.hpp" #include diff --git a/components/compiler/scriptparser.cpp b/components/compiler/scriptparser.cpp index ea11be5f0..a3bf23288 100644 --- a/components/compiler/scriptparser.cpp +++ b/components/compiler/scriptparser.cpp @@ -1,4 +1,3 @@ - #include "scriptparser.hpp" #include "scanner.hpp" diff --git a/components/compiler/skipparser.cpp b/components/compiler/skipparser.cpp index c7cb31f58..3e704253d 100644 --- a/components/compiler/skipparser.cpp +++ b/components/compiler/skipparser.cpp @@ -1,4 +1,3 @@ - #include "skipparser.hpp" #include "scanner.hpp" diff --git a/components/compiler/streamerrorhandler.cpp b/components/compiler/streamerrorhandler.cpp index fc1a05943..9ca8aa74b 100644 --- a/components/compiler/streamerrorhandler.cpp +++ b/components/compiler/streamerrorhandler.cpp @@ -1,4 +1,3 @@ - #include "streamerrorhandler.hpp" #include "tokenloc.hpp" diff --git a/components/compiler/streamerrorhandler.hpp b/components/compiler/streamerrorhandler.hpp index 96e02b588..85de1833a 100644 --- a/components/compiler/streamerrorhandler.hpp +++ b/components/compiler/streamerrorhandler.hpp @@ -1,4 +1,3 @@ - #ifndef COMPILER_STREAMERRORHANDLER_H_INCLUDED #define COMPILER_STREAMERRORHANDLER_H_INCLUDED diff --git a/components/compiler/stringparser.cpp b/components/compiler/stringparser.cpp index 7a2098fb3..f8798eccd 100644 --- a/components/compiler/stringparser.cpp +++ b/components/compiler/stringparser.cpp @@ -1,4 +1,3 @@ - #include "stringparser.hpp" #include diff --git a/components/esm/cellid.cpp b/components/esm/cellid.cpp index c77b27b22..f77e2eb55 100644 --- a/components/esm/cellid.cpp +++ b/components/esm/cellid.cpp @@ -1,4 +1,3 @@ - #include "cellid.hpp" #include "esmreader.hpp" diff --git a/components/esm/cellref.cpp b/components/esm/cellref.cpp index c3b889df5..33ac4a91e 100644 --- a/components/esm/cellref.cpp +++ b/components/esm/cellref.cpp @@ -1,4 +1,3 @@ - #include "cellref.hpp" #include "esmreader.hpp" diff --git a/components/esm/cellstate.cpp b/components/esm/cellstate.cpp index 4df04d0e5..83b130dcd 100644 --- a/components/esm/cellstate.cpp +++ b/components/esm/cellstate.cpp @@ -1,4 +1,3 @@ - #include "cellstate.hpp" #include "esmreader.hpp" diff --git a/components/esm/containerstate.cpp b/components/esm/containerstate.cpp index 80ad5cbdc..301549d59 100644 --- a/components/esm/containerstate.cpp +++ b/components/esm/containerstate.cpp @@ -1,4 +1,3 @@ - #include "containerstate.hpp" void ESM::ContainerState::load (ESMReader &esm) diff --git a/components/esm/creaturestate.cpp b/components/esm/creaturestate.cpp index c15becd98..bffa4e5e4 100644 --- a/components/esm/creaturestate.cpp +++ b/components/esm/creaturestate.cpp @@ -1,4 +1,3 @@ - #include "creaturestate.hpp" void ESM::CreatureState::load (ESMReader &esm) diff --git a/components/esm/debugprofile.cpp b/components/esm/debugprofile.cpp index 6c05fac2a..9d605a6af 100644 --- a/components/esm/debugprofile.cpp +++ b/components/esm/debugprofile.cpp @@ -1,4 +1,3 @@ - #include "debugprofile.hpp" #include "esmreader.hpp" diff --git a/components/esm/dialoguestate.cpp b/components/esm/dialoguestate.cpp index f302e36dc..2b1887e4e 100644 --- a/components/esm/dialoguestate.cpp +++ b/components/esm/dialoguestate.cpp @@ -1,4 +1,3 @@ - #include "dialoguestate.hpp" #include "esmreader.hpp" diff --git a/components/esm/filter.cpp b/components/esm/filter.cpp index a80427bbe..5bc768f72 100644 --- a/components/esm/filter.cpp +++ b/components/esm/filter.cpp @@ -1,4 +1,3 @@ - #include "filter.hpp" #include "esmreader.hpp" diff --git a/components/esm/globalscript.cpp b/components/esm/globalscript.cpp index 0129f8eb7..a42cdc230 100644 --- a/components/esm/globalscript.cpp +++ b/components/esm/globalscript.cpp @@ -1,4 +1,3 @@ - #include "globalscript.hpp" #include "esmreader.hpp" diff --git a/components/esm/inventorystate.cpp b/components/esm/inventorystate.cpp index 4eaaa9f9f..e7257ae53 100644 --- a/components/esm/inventorystate.cpp +++ b/components/esm/inventorystate.cpp @@ -1,4 +1,3 @@ - #include "inventorystate.hpp" #include "esmreader.hpp" diff --git a/components/esm/journalentry.cpp b/components/esm/journalentry.cpp index 445213de4..93011e581 100644 --- a/components/esm/journalentry.cpp +++ b/components/esm/journalentry.cpp @@ -1,4 +1,3 @@ - #include "journalentry.hpp" #include "esmreader.hpp" diff --git a/components/esm/loadtes3.cpp b/components/esm/loadtes3.cpp index 7d749c4d9..df35a2579 100644 --- a/components/esm/loadtes3.cpp +++ b/components/esm/loadtes3.cpp @@ -1,4 +1,3 @@ - #include "loadtes3.hpp" #include "esmcommon.hpp" diff --git a/components/esm/locals.cpp b/components/esm/locals.cpp index f0cfd49f0..bd51be08f 100644 --- a/components/esm/locals.cpp +++ b/components/esm/locals.cpp @@ -1,4 +1,3 @@ - #include "locals.hpp" #include "esmreader.hpp" diff --git a/components/esm/npcstate.cpp b/components/esm/npcstate.cpp index 724d67326..6c9988d50 100644 --- a/components/esm/npcstate.cpp +++ b/components/esm/npcstate.cpp @@ -1,4 +1,3 @@ - #include "npcstate.hpp" void ESM::NpcState::load (ESMReader &esm) diff --git a/components/esm/objectstate.cpp b/components/esm/objectstate.cpp index 0ae690ee8..62aa0452a 100644 --- a/components/esm/objectstate.cpp +++ b/components/esm/objectstate.cpp @@ -1,4 +1,3 @@ - #include "objectstate.hpp" #include "esmreader.hpp" diff --git a/components/esm/player.cpp b/components/esm/player.cpp index e64cefc30..9ec53240a 100644 --- a/components/esm/player.cpp +++ b/components/esm/player.cpp @@ -1,4 +1,3 @@ - #include "player.hpp" #include "esmreader.hpp" diff --git a/components/esm/queststate.cpp b/components/esm/queststate.cpp index c8cff7adc..5408cd2ff 100644 --- a/components/esm/queststate.cpp +++ b/components/esm/queststate.cpp @@ -1,4 +1,3 @@ - #include "queststate.hpp" #include "esmreader.hpp" diff --git a/components/esm/savedgame.cpp b/components/esm/savedgame.cpp index 9cdb28766..2e5509b7a 100644 --- a/components/esm/savedgame.cpp +++ b/components/esm/savedgame.cpp @@ -1,4 +1,3 @@ - #include "savedgame.hpp" #include "esmreader.hpp" diff --git a/components/esm/variantimp.cpp b/components/esm/variantimp.cpp index eeb0bf04f..aeea5017e 100644 --- a/components/esm/variantimp.cpp +++ b/components/esm/variantimp.cpp @@ -1,4 +1,3 @@ - #include "variantimp.hpp" #include diff --git a/components/files/multidircollection.cpp b/components/files/multidircollection.cpp index 1abbae3ae..7b3b0c440 100644 --- a/components/files/multidircollection.cpp +++ b/components/files/multidircollection.cpp @@ -1,4 +1,3 @@ - #include "multidircollection.hpp" #include diff --git a/components/interpreter/installopcodes.cpp b/components/interpreter/installopcodes.cpp index d705a109c..31e911f8b 100644 --- a/components/interpreter/installopcodes.cpp +++ b/components/interpreter/installopcodes.cpp @@ -1,4 +1,3 @@ - #include "installopcodes.hpp" #include diff --git a/components/interpreter/interpreter.cpp b/components/interpreter/interpreter.cpp index f5dee0dba..263cea9a5 100644 --- a/components/interpreter/interpreter.cpp +++ b/components/interpreter/interpreter.cpp @@ -1,4 +1,3 @@ - #include "interpreter.hpp" #include diff --git a/components/interpreter/runtime.cpp b/components/interpreter/runtime.cpp index dc3da07a8..6599882f1 100644 --- a/components/interpreter/runtime.cpp +++ b/components/interpreter/runtime.cpp @@ -1,4 +1,3 @@ - #include "runtime.hpp" #include diff --git a/files/mygui/CMakeLists.txt b/files/mygui/CMakeLists.txt index 602397743..dc9e8ea84 100644 --- a/files/mygui/CMakeLists.txt +++ b/files/mygui/CMakeLists.txt @@ -1,4 +1,3 @@ - # Copy resource files into the build directory set(SDIR ${CMAKE_CURRENT_SOURCE_DIR}) set(DDIR ${OpenMW_BINARY_DIR}/resources/mygui) From 681183df31a1b695b119a6ab6049a4083b796aaf Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 19 Aug 2015 01:13:14 +0200 Subject: [PATCH 2058/3725] Restore handling of fog depth == 0 values (Bug #1549) --- apps/openmw/mwrender/renderingmanager.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index b01095f12..bac8fca6c 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -379,8 +379,17 @@ namespace MWRender else { setFogColor(mFogColor); - mStateUpdater->setFogStart(mViewDistance * (1 - mFogDepth)); - mStateUpdater->setFogEnd(mViewDistance); + + if (mFogDepth == 0.f) + { + mStateUpdater->setFogStart(0.f); + mStateUpdater->setFogEnd(FLT_MAX); + } + else + { + mStateUpdater->setFogStart(mViewDistance * (1 - mFogDepth)); + mStateUpdater->setFogEnd(mViewDistance); + } } } From 232dfdc07e978a690d0320915684af403ce9b7d2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 19 Aug 2015 01:24:54 +0200 Subject: [PATCH 2059/3725] Make an error message slightly more helpful --- apps/openmw/mwmechanics/actors.cpp | 2 +- apps/openmw/mwmechanics/objects.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 83931ba15..9efb866d4 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1255,7 +1255,7 @@ namespace MWMechanics } else { - std::cerr<< "Error in Actors::playAnimationGroup: Unable to find " << ptr.getTypeName() << std::endl; + std::cerr<< "Error in Actors::playAnimationGroup: Unable to find " << ptr.getCellRef().getRefId() << std::endl; return false; } } diff --git a/apps/openmw/mwmechanics/objects.cpp b/apps/openmw/mwmechanics/objects.cpp index a0e9cd242..94b552a38 100644 --- a/apps/openmw/mwmechanics/objects.cpp +++ b/apps/openmw/mwmechanics/objects.cpp @@ -88,7 +88,7 @@ bool Objects::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& gro } else { - std::cerr<< "Error in Objects::playAnimationGroup: Unable to find " << ptr.getTypeName() << std::endl; + std::cerr<< "Error in Objects::playAnimationGroup: Unable to find " << ptr.getCellRef().getRefId() << std::endl; return false; } } From e1baf1ea48526c8b5e5d1ffe005573ca3b70676f Mon Sep 17 00:00:00 2001 From: Jeffrey Haines Date: Wed, 19 Aug 2015 09:51:04 -0400 Subject: [PATCH 2060/3725] NPCs scream when they die --- apps/openmw/mwmechanics/actors.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 9efb866d4..f6ad5906b 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -18,6 +18,7 @@ #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwbase/dialoguemanager.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" @@ -1175,6 +1176,12 @@ namespace MWMechanics if (iter->second->getCharacterController()->kill()) { + // TODO: It's not known whether the soundgen tags scream, roar, and moan are reliable + // for NPCs since some of the npc death animation files are missing them. + + // Play dying words + MWBase::Environment::get().getDialogueManager()->say(iter->first, "hit"); + iter->first.getClass().getCreatureStats(iter->first).notifyDied(); ++mDeathCount[Misc::StringUtils::lowerCase(iter->first.getCellRef().getRefId())]; From e86891d6e16508229732dfb55dd9bae27780ceb7 Mon Sep 17 00:00:00 2001 From: Jeffrey Haines Date: Wed, 19 Aug 2015 10:05:08 -0400 Subject: [PATCH 2061/3725] Time played displayed in save/load menus --- apps/openmw/mwgui/savegamedialog.cpp | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index 82dd0d8a9..4559fc695 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -1,5 +1,8 @@ #include "savegamedialog.hpp" +#include +#include + #include #include #include @@ -309,6 +312,21 @@ namespace MWGui onSlotSelected(mSaveList, MyGUI::ITEM_NONE); } + std::string formatTimeplayed(const long int timePlayed) + { + int days = timePlayed / 60 / 60 / 24; + int hours = (timePlayed / 60 / 60) % 24; + int minutes = (timePlayed / 60) % 60; + int seconds = timePlayed % 60; + + std::stringstream stream; + stream << std::setfill('0') << std::setw(2) << days << ":"; + stream << std::setfill('0') << std::setw(2) << hours << ":"; + stream << std::setfill('0') << std::setw(2) << minutes << ":"; + stream << std::setfill('0') << std::setw(2) << seconds; + return stream.str(); + } + void SaveGameDialog::onSlotSelected(MyGUI::ListBox *sender, size_t pos) { mOkButton->setEnabled(pos != MyGUI::ITEM_NONE || mSaving); @@ -349,7 +367,6 @@ namespace MWGui text << buffer << "\n"; text << "#{sLevel} " << mCurrentSlot->mProfile.mPlayerLevel << "\n"; text << "#{sCell=" << mCurrentSlot->mProfile.mPlayerCell << "}\n"; - // text << "Time played: " << slot->mProfile.mTimePlayed << "\n"; int hour = int(mCurrentSlot->mProfile.mInGameTime.mGameHour); bool pm = hour >= 12; @@ -359,7 +376,9 @@ namespace MWGui text << mCurrentSlot->mProfile.mInGameTime.mDay << " " << MWBase::Environment::get().getWorld()->getMonthName(mCurrentSlot->mProfile.mInGameTime.mMonth) - << " " << hour << " " << (pm ? "#{sSaveMenuHelp05}" : "#{sSaveMenuHelp04}"); + << " " << hour << " " << (pm ? "#{sSaveMenuHelp05}" : "#{sSaveMenuHelp04}")<< "\n"; + + text << "Time played: " << formatTimeplayed((int)floor(mCurrentSlot->mProfile.mTimePlayed)); mInfoText->setCaptionWithReplacing(text.str()); From 69729046bf669235e69f0de7b750358da1b9f769 Mon Sep 17 00:00:00 2001 From: Jeffrey Haines Date: Wed, 19 Aug 2015 10:11:40 -0400 Subject: [PATCH 2062/3725] Updated parameter name to reflect units --- apps/openmw/mwgui/savegamedialog.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index 4559fc695..83b458a2b 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -312,12 +312,12 @@ namespace MWGui onSlotSelected(mSaveList, MyGUI::ITEM_NONE); } - std::string formatTimeplayed(const long int timePlayed) + std::string formatTimeplayed(const long int timeInSeconds) { - int days = timePlayed / 60 / 60 / 24; - int hours = (timePlayed / 60 / 60) % 24; - int minutes = (timePlayed / 60) % 60; - int seconds = timePlayed % 60; + int days = timeInSeconds / 60 / 60 / 24; + int hours = (timeInSeconds / 60 / 60) % 24; + int minutes = (timeInSeconds / 60) % 60; + int seconds = timeInSeconds % 60; std::stringstream stream; stream << std::setfill('0') << std::setw(2) << days << ":"; From d91f197119ac6cfb1ed6002c48ff1c50f83674c3 Mon Sep 17 00:00:00 2001 From: Jeffrey Haines Date: Wed, 19 Aug 2015 11:31:43 -0400 Subject: [PATCH 2063/3725] Time played display setting --- apps/openmw/mwgui/savegamedialog.cpp | 7 +++++-- files/settings-default.cfg | 2 ++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index 83b458a2b..0375bfda3 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -376,9 +376,12 @@ namespace MWGui text << mCurrentSlot->mProfile.mInGameTime.mDay << " " << MWBase::Environment::get().getWorld()->getMonthName(mCurrentSlot->mProfile.mInGameTime.mMonth) - << " " << hour << " " << (pm ? "#{sSaveMenuHelp05}" : "#{sSaveMenuHelp04}")<< "\n"; + << " " << hour << " " << (pm ? "#{sSaveMenuHelp05}" : "#{sSaveMenuHelp04}"); - text << "Time played: " << formatTimeplayed((int)floor(mCurrentSlot->mProfile.mTimePlayed)); + if (Settings::Manager::getBool("timeplayed","Saves")) + { + text << "\n" << "Time played: " << formatTimeplayed((int)floor(mCurrentSlot->mProfile.mTimePlayed)); + } mInfoText->setCaptionWithReplacing(text.str()); diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 0f7349eb9..f2b6aa34f 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -177,6 +177,8 @@ show owned = 0 character = # Save when resting autosave = true +# display time played +timeplayed = false [Windows] inventory x = 0 From 4a68ceaeb7561f6d00cd25d80b075956c8f6fd39 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 19 Aug 2015 19:06:24 +0200 Subject: [PATCH 2064/3725] Restrict the OS X cursor workaround to Intel graphics systems --- components/sdlutil/sdlcursormanager.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/components/sdlutil/sdlcursormanager.cpp b/components/sdlutil/sdlcursormanager.cpp index 70a159306..b64b68132 100644 --- a/components/sdlutil/sdlcursormanager.cpp +++ b/components/sdlutil/sdlcursormanager.cpp @@ -127,11 +127,13 @@ namespace glViewport(0, 0, width, height); #if defined(__APPLE__) - // FIXME: why are the extra flips needed on Mac? glReadPixels bug? - osg::ref_ptr geom = osg::createTexturedQuadGeometry(osg::Vec3(-1,1,0), osg::Vec3(2,0,0), osg::Vec3(0,-2,0)); -#else - osg::ref_ptr geom = osg::createTexturedQuadGeometry(osg::Vec3(-1,-1,0), osg::Vec3(2,0,0), osg::Vec3(0,2,0)); + // Extra flip needed on Intel graphics OS X systems due to a driver bug + std::string vendorString = (const char*)glGetString(GL_VENDOR); + if (vendorString.find("Intel") != std::string::npos) + osg::ref_ptr geom = osg::createTexturedQuadGeometry(osg::Vec3(-1,1,0), osg::Vec3(2,0,0), osg::Vec3(0,-2,0)); + else #endif + osg::ref_ptr geom = osg::createTexturedQuadGeometry(osg::Vec3(-1,-1,0), osg::Vec3(2,0,0), osg::Vec3(0,2,0)); geom->drawImplementation(renderInfo); From 61bb55aff40d9efb594ced44799b7bda98d2ca23 Mon Sep 17 00:00:00 2001 From: Jeffrey Haines Date: Wed, 19 Aug 2015 13:23:40 -0400 Subject: [PATCH 2065/3725] Removed long int parameter --- apps/openmw/mwgui/savegamedialog.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index 0375bfda3..3d509e9fd 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -1,5 +1,6 @@ #include "savegamedialog.hpp" +#include #include #include @@ -312,12 +313,13 @@ namespace MWGui onSlotSelected(mSaveList, MyGUI::ITEM_NONE); } - std::string formatTimeplayed(const long int timeInSeconds) + std::string formatTimeplayed(const double timeInSeconds) { - int days = timeInSeconds / 60 / 60 / 24; - int hours = (timeInSeconds / 60 / 60) % 24; - int minutes = (timeInSeconds / 60) % 60; - int seconds = timeInSeconds % 60; + int timePlayed = (int)floor(timeInSeconds); + int days = timePlayed / 60 / 60 / 24; + int hours = (timePlayed / 60 / 60) % 24; + int minutes = (timePlayed / 60) % 60; + int seconds = timePlayed % 60; std::stringstream stream; stream << std::setfill('0') << std::setw(2) << days << ":"; @@ -380,7 +382,7 @@ namespace MWGui if (Settings::Manager::getBool("timeplayed","Saves")) { - text << "\n" << "Time played: " << formatTimeplayed((int)floor(mCurrentSlot->mProfile.mTimePlayed)); + text << "\n" << "Time played: " << formatTimeplayed(mCurrentSlot->mProfile.mTimePlayed); } mInfoText->setCaptionWithReplacing(text.str()); From f94d3237fcb9bae1a51e8f442029b2d4496060cb Mon Sep 17 00:00:00 2001 From: Jeffrey Haines Date: Wed, 19 Aug 2015 13:28:01 -0400 Subject: [PATCH 2066/3725] Removed unused cmake import --- apps/openmw/mwgui/savegamedialog.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index 3d509e9fd..be9ef2139 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -1,6 +1,5 @@ #include "savegamedialog.hpp" -#include #include #include From 166df28906dcfa1e7758d9e97e5e4e0b6de781f7 Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Wed, 19 Aug 2015 21:23:16 +0200 Subject: [PATCH 2067/3725] OS X cursor workaround build fix --- components/sdlutil/sdlcursormanager.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/components/sdlutil/sdlcursormanager.cpp b/components/sdlutil/sdlcursormanager.cpp index b64b68132..e1a67aff8 100644 --- a/components/sdlutil/sdlcursormanager.cpp +++ b/components/sdlutil/sdlcursormanager.cpp @@ -126,14 +126,16 @@ namespace glViewport(0, 0, width, height); + osg::ref_ptr geom; + #if defined(__APPLE__) // Extra flip needed on Intel graphics OS X systems due to a driver bug std::string vendorString = (const char*)glGetString(GL_VENDOR); if (vendorString.find("Intel") != std::string::npos) - osg::ref_ptr geom = osg::createTexturedQuadGeometry(osg::Vec3(-1,1,0), osg::Vec3(2,0,0), osg::Vec3(0,-2,0)); + geom = osg::createTexturedQuadGeometry(osg::Vec3(-1,1,0), osg::Vec3(2,0,0), osg::Vec3(0,-2,0)); else #endif - osg::ref_ptr geom = osg::createTexturedQuadGeometry(osg::Vec3(-1,-1,0), osg::Vec3(2,0,0), osg::Vec3(0,2,0)); + geom = osg::createTexturedQuadGeometry(osg::Vec3(-1,-1,0), osg::Vec3(2,0,0), osg::Vec3(0,2,0)); geom->drawImplementation(renderInfo); From ff5ef7055e843797a65d5174b9cd8f14d389ef4f Mon Sep 17 00:00:00 2001 From: dteviot Date: Thu, 20 Aug 2015 18:12:37 +1200 Subject: [PATCH 2068/3725] extracted function CreatureStats::isParalyzed() --- apps/openmw/engine.cpp | 4 ++-- apps/openmw/mwmechanics/actors.cpp | 5 ++--- apps/openmw/mwmechanics/combat.cpp | 6 +++--- apps/openmw/mwmechanics/creaturestats.cpp | 5 +++++ apps/openmw/mwmechanics/creaturestats.hpp | 2 ++ apps/openmw/mwworld/worldimp.cpp | 5 ++--- 6 files changed, 16 insertions(+), 11 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 95851b75f..6b393ebcb 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -704,8 +704,8 @@ void OMW::Engine::activate() return; MWWorld::Ptr player = mEnvironment.getWorld()->getPlayerPtr(); - if (player.getClass().getCreatureStats(player).getMagicEffects().get(ESM::MagicEffect::Paralyze).getMagnitude() > 0 - || player.getClass().getCreatureStats(player).getKnockedDown()) + const MWMechanics::NpcStats &playerStats = player.getClass().getNpcStats(player); + if (playerStats.isParalyzed() || playerStats.getKnockedDown()) return; MWWorld::Ptr ptr = mEnvironment.getWorld()->getFacedObject(); diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 9efb866d4..2abd94eb3 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1037,8 +1037,7 @@ namespace MWMechanics > sqrProcessingDistance) continue; - if (iter->first.getClass().getCreatureStats(iter->first).getMagicEffects().get( - ESM::MagicEffect::Paralyze).getMagnitude() > 0) + if (iter->first.getClass().getCreatureStats(iter->first).isParalyzed()) iter->second->getCharacterController()->skipAnim(); // Handle player last, in case a cell transition occurs by casting a teleportation spell @@ -1426,7 +1425,7 @@ namespace MWMechanics MWWorld::Ptr ptr = it->first; if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr() || !isConscious(ptr) - || ptr.getClass().getCreatureStats(ptr).getMagicEffects().get(ESM::MagicEffect::Paralyze).getMagnitude() > 0) + || ptr.getClass().getCreatureStats(ptr).isParalyzed()) continue; MWMechanics::AiSequence& seq = ptr.getClass().getCreatureStats(ptr).getAiSequence(); seq.fastForward(ptr, it->second->getAiState()); diff --git a/apps/openmw/mwmechanics/combat.cpp b/apps/openmw/mwmechanics/combat.cpp index 097dcadc2..11619e4c3 100644 --- a/apps/openmw/mwmechanics/combat.cpp +++ b/apps/openmw/mwmechanics/combat.cpp @@ -60,7 +60,7 @@ namespace MWMechanics if (blockerStats.getKnockedDown() // Used for both knockout or knockdown || blockerStats.getHitRecovery() - || blockerStats.getMagicEffects().get(ESM::MagicEffect::Paralyze).getMagnitude() > 0) + || blockerStats.isParalyzed()) return false; if (!MWBase::Environment::get().getMechanicsManager()->isReadyToBlock(blocker)) @@ -250,7 +250,7 @@ namespace MWMechanics && (attacker == MWBase::Environment::get().getWorld()->getPlayerPtr()) && (!MWBase::Environment::get().getMechanicsManager()->awarenessCheck(attacker, victim)); if (!(victimStats.getKnockedDown() || - victimStats.getMagicEffects().get(ESM::MagicEffect::Paralyze).getMagnitude() > 0 + victimStats.isParalyzed() || unaware )) { defenseTerm = victimStats.getEvasion(); @@ -375,7 +375,7 @@ namespace MWMechanics damage *= minstrike + ((maxstrike-minstrike)*attackStrength); MWMechanics::CreatureStats& otherstats = victim.getClass().getCreatureStats(victim); - healthdmg = (otherstats.getMagicEffects().get(ESM::MagicEffect::Paralyze).getMagnitude() > 0) + healthdmg = otherstats.isParalyzed() || otherstats.getKnockedDown(); bool isWerewolf = (attacker.getClass().isNpc() && attacker.getClass().getNpcStats(attacker).isWerewolf()); if(isWerewolf) diff --git a/apps/openmw/mwmechanics/creaturestats.cpp b/apps/openmw/mwmechanics/creaturestats.cpp index 48374c173..0638637fa 100644 --- a/apps/openmw/mwmechanics/creaturestats.cpp +++ b/apps/openmw/mwmechanics/creaturestats.cpp @@ -221,6 +221,11 @@ namespace MWMechanics setAiSetting(index, stat); } + bool CreatureStats::isParalyzed() const + { + return mMagicEffects.get(ESM::MagicEffect::Paralyze).getMagnitude() > 0; + } + bool CreatureStats::isDead() const { return mDead; diff --git a/apps/openmw/mwmechanics/creaturestats.hpp b/apps/openmw/mwmechanics/creaturestats.hpp index 5d22da7cc..46c5bab31 100644 --- a/apps/openmw/mwmechanics/creaturestats.hpp +++ b/apps/openmw/mwmechanics/creaturestats.hpp @@ -155,6 +155,8 @@ namespace MWMechanics float getFatigueTerm() const; ///< Return effective fatigue + bool isParalyzed() const; + bool isDead() const; void notifyDied(); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 1eed841bd..4c9074eee 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1927,16 +1927,15 @@ namespace MWWorld bool World::isFlying(const MWWorld::Ptr &ptr) const { const MWMechanics::CreatureStats &stats = ptr.getClass().getCreatureStats(ptr); - bool isParalyzed = (stats.getMagicEffects().get(ESM::MagicEffect::Paralyze).getMagnitude() > 0); if(!ptr.getClass().isActor()) return false; - if (ptr.getClass().getCreatureStats(ptr).isDead()) + if (stats.isDead()) return false; if (ptr.getClass().canFly(ptr)) - return !isParalyzed; + return !stats.isParalyzed(); if(stats.getMagicEffects().get(ESM::MagicEffect::Levitate).getMagnitude() > 0 && isLevitationEnabled()) From 0ee7407101aedf4a0fa3910d437842399b7a452a Mon Sep 17 00:00:00 2001 From: dteviot Date: Thu, 20 Aug 2015 18:17:02 +1200 Subject: [PATCH 2069/3725] extracted common sub-expressions. --- apps/openmw/mwclass/creature.cpp | 8 +++----- apps/openmw/mwmechanics/actors.cpp | 16 ++++++++-------- apps/openmw/mwmechanics/combat.cpp | 10 +++++----- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 11 ++++++----- apps/openmw/mwmechanics/spellcasting.cpp | 7 ++++--- apps/openmw/mwscript/statsextensions.cpp | 14 +++++++------- 6 files changed, 33 insertions(+), 33 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 60874bb5e..5604aa783 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -603,11 +603,9 @@ namespace MWClass { float weight = getContainerStore (ptr).getWeight(); - const MWMechanics::CreatureStats& stats = getCreatureStats (ptr); - - weight -= stats.getMagicEffects().get (MWMechanics::EffectKey (ESM::MagicEffect::Feather)).getMagnitude(); - - weight += stats.getMagicEffects().get (MWMechanics::EffectKey (ESM::MagicEffect::Burden)).getMagnitude(); + const MWMechanics::MagicEffects& effects = getCreatureStats(ptr).getMagicEffects(); + weight -= effects.get(ESM::MagicEffect::Feather).getMagnitude(); + weight += effects.get(ESM::MagicEffect::Burden).getMagnitude(); if (weight<0) weight = 0; diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 2abd94eb3..584c4c320 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -538,19 +538,19 @@ namespace MWMechanics if (!creature || ptr.get()->mBase->mData.mType == ESM::Creature::Creatures) { Stat stat = creatureStats.getAiSetting(CreatureStats::AI_Fight); - stat.setModifier(static_cast(creatureStats.getMagicEffects().get(ESM::MagicEffect::FrenzyHumanoid + creature).getMagnitude() - - creatureStats.getMagicEffects().get(ESM::MagicEffect::CalmHumanoid+creature).getMagnitude())); + stat.setModifier(static_cast(effects.get(ESM::MagicEffect::FrenzyHumanoid + creature).getMagnitude() + - effects.get(ESM::MagicEffect::CalmHumanoid+creature).getMagnitude())); creatureStats.setAiSetting(CreatureStats::AI_Fight, stat); stat = creatureStats.getAiSetting(CreatureStats::AI_Flee); - stat.setModifier(static_cast(creatureStats.getMagicEffects().get(ESM::MagicEffect::DemoralizeHumanoid + creature).getMagnitude() - - creatureStats.getMagicEffects().get(ESM::MagicEffect::RallyHumanoid+creature).getMagnitude())); + stat.setModifier(static_cast(effects.get(ESM::MagicEffect::DemoralizeHumanoid + creature).getMagnitude() + - effects.get(ESM::MagicEffect::RallyHumanoid+creature).getMagnitude())); creatureStats.setAiSetting(CreatureStats::AI_Flee, stat); } if (creature && ptr.get()->mBase->mData.mType == ESM::Creature::Undead) { Stat stat = creatureStats.getAiSetting(CreatureStats::AI_Flee); - stat.setModifier(static_cast(creatureStats.getMagicEffects().get(ESM::MagicEffect::TurnUndead).getMagnitude())); + stat.setModifier(static_cast(effects.get(ESM::MagicEffect::TurnUndead).getMagnitude())); creatureStats.setAiSetting(CreatureStats::AI_Flee, stat); } @@ -596,8 +596,8 @@ namespace MWMechanics // TODO: dirty flag for magic effects to avoid some unnecessary work below? // any value of calm > 0 will stop the actor from fighting - if ((creatureStats.getMagicEffects().get(ESM::MagicEffect::CalmHumanoid).getMagnitude() > 0 && ptr.getClass().isNpc()) - || (creatureStats.getMagicEffects().get(ESM::MagicEffect::CalmCreature).getMagnitude() > 0 && !ptr.getClass().isNpc())) + if ((effects.get(ESM::MagicEffect::CalmHumanoid).getMagnitude() > 0 && ptr.getClass().isNpc()) + || (effects.get(ESM::MagicEffect::CalmCreature).getMagnitude() > 0 && !ptr.getClass().isNpc())) { for (std::list::const_iterator it = creatureStats.getAiSequence().begin(); it != creatureStats.getAiSequence().end(); ) { @@ -630,7 +630,7 @@ namespace MWMechanics for (std::map::iterator it = boundItemsMap.begin(); it != boundItemsMap.end(); ++it) { bool found = creatureStats.mBoundItems.find(it->first) != creatureStats.mBoundItems.end(); - float magnitude = creatureStats.getMagicEffects().get(it->first).getMagnitude(); + float magnitude = effects.get(it->first).getMagnitude(); if (found != (magnitude > 0)) { std::string itemGmst = it->second; diff --git a/apps/openmw/mwmechanics/combat.cpp b/apps/openmw/mwmechanics/combat.cpp index 11619e4c3..2e20d0e1f 100644 --- a/apps/openmw/mwmechanics/combat.cpp +++ b/apps/openmw/mwmechanics/combat.cpp @@ -147,9 +147,9 @@ namespace MWMechanics void resistNormalWeapon(const MWWorld::Ptr &actor, const MWWorld::Ptr& attacker, const MWWorld::Ptr &weapon, float &damage) { - MWMechanics::CreatureStats& stats = actor.getClass().getCreatureStats(actor); - float resistance = std::min(100.f, stats.getMagicEffects().get(ESM::MagicEffect::ResistNormalWeapons).getMagnitude() - - stats.getMagicEffects().get(ESM::MagicEffect::WeaknessToNormalWeapons).getMagnitude()); + const MWMechanics::MagicEffects& effects = actor.getClass().getCreatureStats(actor).getMagicEffects(); + float resistance = std::min(100.f, effects.get(ESM::MagicEffect::ResistNormalWeapons).getMagnitude() + - effects.get(ESM::MagicEffect::WeaknessToNormalWeapons).getMagnitude()); float multiplier = 1.f - resistance / 100.f; @@ -242,9 +242,9 @@ namespace MWMechanics const MWWorld::Store &gmst = world->getStore().get(); float defenseTerm = 0; - if (victim.getClass().getCreatureStats(victim).getFatigue().getCurrent() >= 0) + MWMechanics::CreatureStats& victimStats = victim.getClass().getCreatureStats(victim); + if (victimStats.getFatigue().getCurrent() >= 0) { - MWMechanics::CreatureStats& victimStats = victim.getClass().getCreatureStats(victim); // Maybe we should keep an aware state for actors updated every so often instead of testing every time bool unaware = (!victimStats.getAiSequence().isInCombat()) && (attacker == MWBase::Environment::get().getWorld()->getPlayerPtr()) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 9436e35d2..075747ffe 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1310,11 +1310,12 @@ namespace MWMechanics return false; std::list followers = getActorsFollowing(attacker); + MWMechanics::CreatureStats& targetStats = ptr.getClass().getCreatureStats(ptr); if (std::find(followers.begin(), followers.end(), ptr) != followers.end()) { - ptr.getClass().getCreatureStats(ptr).friendlyHit(); + targetStats.friendlyHit(); - if (ptr.getClass().getCreatureStats(ptr).getFriendlyHits() < 4) + if (targetStats.getFriendlyHits() < 4) { MWBase::Environment::get().getDialogueManager()->say(ptr, "hit"); return false; @@ -1322,7 +1323,7 @@ namespace MWMechanics } // Attacking an NPC that is already in combat with any other NPC is not a crime - AiSequence& seq = ptr.getClass().getCreatureStats(ptr).getAiSequence(); + AiSequence& seq = targetStats.getAiSequence(); bool isFightingNpc = false; for (std::list::const_iterator it = seq.begin(); it != seq.end(); ++it) { @@ -1334,13 +1335,13 @@ namespace MWMechanics } } - if (ptr.getClass().isNpc() && !attacker.isEmpty() && !ptr.getClass().getCreatureStats(ptr).getAiSequence().isInCombat(attacker) + if (ptr.getClass().isNpc() && !attacker.isEmpty() && !seq.isInCombat(attacker) && !isAggressive(ptr, attacker) && !isFightingNpc) commitCrime(attacker, ptr, MWBase::MechanicsManager::OT_Assault); if (!attacker.isEmpty() && (attacker.getClass().getCreatureStats(attacker).getAiSequence().isInCombat(ptr) || attacker == MWBase::Environment::get().getWorld()->getPlayerPtr()) - && !ptr.getClass().getCreatureStats(ptr).getAiSequence().isInCombat(attacker)) + && !seq.isInCombat(attacker)) { // Attacker is in combat with us, but we are not in combat with the attacker yet. Time to fight back. // Note: accidental or collateral damage attacks are ignored. diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index b98bf9f96..12ed04428 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -332,9 +332,10 @@ namespace MWMechanics const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get().search (mId); if (spell && (spell->mData.mType == ESM::Spell::ST_Disease || spell->mData.mType == ESM::Spell::ST_Blight)) { - float x = (spell->mData.mType == ESM::Spell::ST_Disease) ? - target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::ResistCommonDisease).getMagnitude() - : target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::ResistBlightDisease).getMagnitude(); + int requiredResistance = (spell->mData.mType == ESM::Spell::ST_Disease) ? + ESM::MagicEffect::ResistCommonDisease + : ESM::MagicEffect::ResistBlightDisease; + float x = target.getClass().getCreatureStats(target).getMagicEffects().get(requiredResistance).getMagnitude(); if (Misc::Rng::roll0to99() <= x) { diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index 61a31e115..112e7c77f 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -1159,10 +1159,10 @@ namespace MWScript { MWWorld::Ptr ptr = R()(runtime); - MWMechanics::CreatureStats& stats = ptr.getClass().getCreatureStats(ptr); - float currentValue = stats.getMagicEffects().get(mPositiveEffect).getMagnitude(); + const MWMechanics::MagicEffects& effects = ptr.getClass().getCreatureStats(ptr).getMagicEffects(); + float currentValue = effects.get(mPositiveEffect).getMagnitude(); if (mNegativeEffect != -1) - currentValue -= stats.getMagicEffects().get(mNegativeEffect).getMagnitude(); + currentValue -= effects.get(mNegativeEffect).getMagnitude(); int ret = static_cast(currentValue); runtime.push(ret); @@ -1185,14 +1185,14 @@ namespace MWScript virtual void execute(Interpreter::Runtime &runtime) { MWWorld::Ptr ptr = R()(runtime); - MWMechanics::CreatureStats& stats = ptr.getClass().getCreatureStats(ptr); - float currentValue = stats.getMagicEffects().get(mPositiveEffect).getMagnitude(); + MWMechanics::MagicEffects& effects = ptr.getClass().getCreatureStats(ptr).getMagicEffects(); + float currentValue = effects.get(mPositiveEffect).getMagnitude(); if (mNegativeEffect != -1) - currentValue -= stats.getMagicEffects().get(mNegativeEffect).getMagnitude(); + currentValue -= effects.get(mNegativeEffect).getMagnitude(); int arg = runtime[0].mInteger; runtime.pop(); - stats.getMagicEffects().modifyBase(mPositiveEffect, (arg - static_cast(currentValue))); + effects.modifyBase(mPositiveEffect, (arg - static_cast(currentValue))); } }; From c0d3804b4f3371d4498b771943121a1d249d4c62 Mon Sep 17 00:00:00 2001 From: dteviot Date: Thu, 20 Aug 2015 21:50:58 +1200 Subject: [PATCH 2070/3725] Correctly handle disjoint pathgrid (Fixes #2871) Bugfix: When 1. Cell has multiple subgrids (i.e. path grid is disjoint) 2. Distance between destination and pathgrid point 0 is less than distance to points of subgrid closest to start point Then getClosestReachablePoint() returns pathgrid point 0 as the end point. This is invalid, this end point cannot be reached from the start point. --- apps/openmw/mwmechanics/pathfinding.cpp | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index 798a0ea21..9013d3269 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -53,7 +53,8 @@ namespace { assert(grid && !grid->mPoints.empty()); - float distanceBetween = distanceSquared(grid->mPoints[0], pos); + float closestDistanceBetween = distanceSquared(grid->mPoints[0], pos); + float closestDistanceReachable = closestDistanceBetween; int closestIndex = 0; int closestReachableIndex = 0; // TODO: if this full scan causes performance problems mapping pathgrid @@ -61,17 +62,25 @@ namespace for(unsigned int counter = 1; counter < grid->mPoints.size(); counter++) { float potentialDistBetween = distanceSquared(grid->mPoints[counter], pos); - if(potentialDistBetween < distanceBetween) + if (potentialDistBetween < closestDistanceReachable) { // found a closer one - distanceBetween = potentialDistBetween; - closestIndex = counter; if (cell->isPointConnected(start, counter)) { + closestDistanceReachable = potentialDistBetween; closestReachableIndex = counter; } + if (potentialDistBetween < closestDistanceBetween) + { + closestDistanceBetween = potentialDistBetween; + closestIndex = counter; + } } } + + // invariant: start and endpoint must be connected + assert(cell->isPointConnected(start, closestReachableIndex)); + // AiWander has logic that depends on whether a path was created, deleting // allowed nodes if not. Hence a path needs to be created even if the start // and the end points are the same. From 3b231b85bb1c7ed8c00cf7f1a5a583299e23e3bc Mon Sep 17 00:00:00 2001 From: dteviot Date: Fri, 21 Aug 2015 06:55:54 +1200 Subject: [PATCH 2071/3725] removed incorrect optimization. Now it fixes #2871 --- apps/openmw/mwmechanics/pathfinding.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index 9013d3269..9c9c11106 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -53,13 +53,13 @@ namespace { assert(grid && !grid->mPoints.empty()); - float closestDistanceBetween = distanceSquared(grid->mPoints[0], pos); - float closestDistanceReachable = closestDistanceBetween; + float closestDistanceBetween = FLT_MAX; + float closestDistanceReachable = FLT_MAX; int closestIndex = 0; int closestReachableIndex = 0; // TODO: if this full scan causes performance problems mapping pathgrid // points to a quadtree may help - for(unsigned int counter = 1; counter < grid->mPoints.size(); counter++) + for(unsigned int counter = 0; counter < grid->mPoints.size(); counter++) { float potentialDistBetween = distanceSquared(grid->mPoints[counter], pos); if (potentialDistBetween < closestDistanceReachable) From af3b0cd883f784d111d65b2ed33871ddeb260e18 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 21 Aug 2015 00:31:43 +0200 Subject: [PATCH 2072/3725] Improve some error messages --- apps/essimporter/converter.cpp | 2 +- apps/openmw/engine.cpp | 4 ++-- apps/openmw/mwgui/savegamedialog.cpp | 2 +- apps/openmw/mwrender/globalmap.cpp | 4 ++-- apps/openmw/mwrender/localmap.cpp | 4 ++-- apps/openmw/mwstate/statemanagerimp.cpp | 2 +- components/resource/texturemanager.cpp | 2 +- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/apps/essimporter/converter.cpp b/apps/essimporter/converter.cpp index 2ef10ee34..6267ef91e 100644 --- a/apps/essimporter/converter.cpp +++ b/apps/essimporter/converter.cpp @@ -143,7 +143,7 @@ namespace ESSImport osgDB::ReaderWriter::WriteResult result = readerwriter->writeImage(*image2, ostream); if (!result.success()) { - std::cerr << "can't write global map image: " << result.message() << std::endl; + std::cerr << "can't write global map image: " << result.message() << " code " << result.status() << std::endl; return; } diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 95851b75f..d0a993b73 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -425,7 +425,7 @@ void OMW::Engine::setWindowIcon() } osgDB::ReaderWriter::ReadResult result = reader->readImage(windowIconStream); if (!result.success()) - std::cerr << "Failed to read " << windowIcon << ": " << result.message() << std::endl; + std::cerr << "Failed to read " << windowIcon << ": " << result.message() << " code " << result.status() << std::endl; else { osg::ref_ptr image = result.getImage(); @@ -602,7 +602,7 @@ public: osgDB::ReaderWriter::WriteResult result = readerwriter->writeImage(image, outStream); if (!result.success()) { - std::cerr << "Can't write screenshot: " << result.message() << std::endl; + std::cerr << "Can't write screenshot: " << result.message() << " code " << result.status() << std::endl; } } diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index be9ef2139..816fc0fa8 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -401,7 +401,7 @@ namespace MWGui osgDB::ReaderWriter::ReadResult result = readerwriter->readImage(instream); if (!result.success()) { - std::cerr << "Failed to read savegame screenshot: " << result.message() << std::endl; + std::cerr << "Failed to read savegame screenshot: " << result.message() << " code " << result.status() << std::endl; return; } diff --git a/apps/openmw/mwrender/globalmap.cpp b/apps/openmw/mwrender/globalmap.cpp index 890c8444a..f6fb83c94 100644 --- a/apps/openmw/mwrender/globalmap.cpp +++ b/apps/openmw/mwrender/globalmap.cpp @@ -361,7 +361,7 @@ namespace MWRender osgDB::ReaderWriter::WriteResult result = readerwriter->writeImage(*mOverlayImage, ostream); if (!result.success()) { - std::cerr << "Can't write map overlay: " << result.message() << std::endl; + std::cerr << "Can't write map overlay: " << result.message() << " code " << result.status() << std::endl; return; } @@ -411,7 +411,7 @@ namespace MWRender osgDB::ReaderWriter::ReadResult result = readerwriter->readImage(istream); if (!result.success()) { - std::cerr << "Can't read map overlay: " << result.message() << std::endl; + std::cerr << "Can't read map overlay: " << result.message() << " code " << result.status() << std::endl; return; } diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index d307e990a..02ca0cb4c 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -645,7 +645,7 @@ void LocalMap::MapSegment::loadFogOfWar(const ESM::FogTexture &esm) osgDB::ReaderWriter::ReadResult result = readerwriter->readImage(in); if (!result.success()) { - std::cerr << "Failed to read fog: " << result.message() << std::endl; + std::cerr << "Failed to read fog: " << result.message() << " code " << result.status() << std::endl; return; } @@ -677,7 +677,7 @@ void LocalMap::MapSegment::saveFogOfWar(ESM::FogTexture &fog) const osgDB::ReaderWriter::WriteResult result = readerwriter->writeImage(*mFogOfWarImage, ostream); if (!result.success()) { - std::cerr << "Unable to write fog: " << result.message() << std::endl; + std::cerr << "Unable to write fog: " << result.message() << " code " << result.status() << std::endl; return; } mFogOfWarImage->flipVertical(); diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index f4a7ee9f2..df433ad6a 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -606,7 +606,7 @@ void MWState::StateManager::writeScreenshot(std::vector &imageData) const osgDB::ReaderWriter::WriteResult result = readerwriter->writeImage(*screenshot, ostream); if (!result.success()) { - std::cerr << "Unable to write screenshot: " << result.message() << std::endl; + std::cerr << "Unable to write screenshot: " << result.message() << " code " << result.status() << std::endl; return; } diff --git a/components/resource/texturemanager.cpp b/components/resource/texturemanager.cpp index d29aa2812..c2f76a527 100644 --- a/components/resource/texturemanager.cpp +++ b/components/resource/texturemanager.cpp @@ -182,7 +182,7 @@ namespace Resource osgDB::ReaderWriter::ReadResult result = reader->readImage(*stream, opts); if (!result.success()) { - std::cerr << "Error loading " << filename << ": " << result.message() << std::endl; + std::cerr << "Error loading " << filename << ": " << result.message() << " code " << result.status() << std::endl; return mWarningTexture; } From 85bc41dedb9db07da2c4609ea39be95b508bb5e2 Mon Sep 17 00:00:00 2001 From: dteviot Date: Fri, 21 Aug 2015 19:34:28 +1200 Subject: [PATCH 2073/3725] replaced FLT_MAX with numeric_limits. --- apps/openmw/mwmechanics/aiwander.cpp | 2 +- apps/openmw/mwmechanics/autocalcspell.cpp | 2 +- apps/openmw/mwmechanics/pathfinding.cpp | 6 +++--- apps/openmw/mwmechanics/spellcasting.cpp | 2 +- apps/openmw/mwrender/renderingmanager.cpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 6 +++--- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index afe34218e..7b846cb97 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -806,7 +806,7 @@ namespace MWMechanics void AiWander::SetCurrentNodeToClosestAllowedNode(osg::Vec3f npcPos) { - float distanceToClosestNode = FLT_MAX; + float distanceToClosestNode = std::numeric_limits::max(); unsigned int index = 0; for (unsigned int counterThree = 0; counterThree < mAllowedNodes.size(); counterThree++) { diff --git a/apps/openmw/mwmechanics/autocalcspell.cpp b/apps/openmw/mwmechanics/autocalcspell.cpp index e4b143826..5dfe388a8 100644 --- a/apps/openmw/mwmechanics/autocalcspell.cpp +++ b/apps/openmw/mwmechanics/autocalcspell.cpp @@ -181,7 +181,7 @@ namespace MWMechanics void calcWeakestSchool (const ESM::Spell* spell, const int* actorSkills, int& effectiveSchool, float& skillTerm) { - float minChance = FLT_MAX; + float minChance = std::numeric_limits::max(); const ESM::EffectList& effects = spell->mEffects; for (std::vector::const_iterator it = effects.mList.begin(); it != effects.mList.end(); ++it) diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index 9c9c11106..f40624ae8 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -53,8 +53,8 @@ namespace { assert(grid && !grid->mPoints.empty()); - float closestDistanceBetween = FLT_MAX; - float closestDistanceReachable = FLT_MAX; + float closestDistanceBetween = std::numeric_limits::max(); + float closestDistanceReachable = std::numeric_limits::max(); int closestIndex = 0; int closestReachableIndex = 0; // TODO: if this full scan causes performance problems mapping pathgrid @@ -78,7 +78,7 @@ namespace } } - // invariant: start and endpoint must be connected + // post-condition: start and endpoint must be connected assert(cell->isPointConnected(start, closestReachableIndex)); // AiWander has logic that depends on whether a path was created, deleting diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index b98bf9f96..59410001f 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -92,7 +92,7 @@ namespace MWMechanics if (stats.getMagicEffects().get(ESM::MagicEffect::Silence).getMagnitude()) return 0; - float y = FLT_MAX; + float y = std::numeric_limits::max(); float lowestSkill = 0; for (std::vector::const_iterator it = spell->mEffects.mList.begin(); it != spell->mEffects.mList.end(); ++it) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index bac8fca6c..1a1b04d18 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -383,7 +383,7 @@ namespace MWRender if (mFogDepth == 0.f) { mStateUpdater->setFogStart(0.f); - mStateUpdater->setFogEnd(FLT_MAX); + mStateUpdater->setFogEnd(std::numeric_limits::max()); } else { diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 1eed841bd..36f275cf4 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2659,8 +2659,8 @@ namespace MWWorld MWRender::RenderingManager::RayResult result2 = mRendering->castRay(origin, dest, true, true); - float dist1 = FLT_MAX; - float dist2 = FLT_MAX; + float dist1 = std::numeric_limits::max(); + float dist2 = std::numeric_limits::max(); if (result1.mHit) dist1 = (origin - result1.mHitPos).length(); @@ -2853,7 +2853,7 @@ namespace MWWorld MWWorld::Ptr World::getClosestMarkerFromExteriorPosition( const osg::Vec3f& worldPos, const std::string &id ) { MWWorld::Ptr closestMarker; - float closestDistance = FLT_MAX; + float closestDistance = std::numeric_limits::max(); std::vector markers; mCells.getExteriorPtrs(id, markers); From 77a1d947cc6796d3878f96af8d618a692957c381 Mon Sep 17 00:00:00 2001 From: dteviot Date: Fri, 21 Aug 2015 21:12:39 +1200 Subject: [PATCH 2074/3725] extracted MWMechanics::getPlayer() --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwclass/armor.cpp | 3 +- apps/openmw/mwclass/creature.cpp | 3 +- apps/openmw/mwclass/door.cpp | 4 ++- apps/openmw/mwclass/npc.cpp | 15 +++++----- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 3 +- apps/openmw/mwdialogue/filter.cpp | 13 +++++---- apps/openmw/mwgui/alchemywindow.cpp | 7 +++-- apps/openmw/mwgui/bookwindow.cpp | 4 ++- apps/openmw/mwgui/charactercreation.cpp | 5 ++-- apps/openmw/mwgui/container.cpp | 7 +++-- apps/openmw/mwgui/dialogue.cpp | 3 +- apps/openmw/mwgui/enchantingdialog.cpp | 10 ++++--- apps/openmw/mwgui/hud.cpp | 7 +++-- apps/openmw/mwgui/inventorywindow.cpp | 16 +++++----- apps/openmw/mwgui/jailscreen.cpp | 5 ++-- apps/openmw/mwgui/levelupdialog.cpp | 3 +- apps/openmw/mwgui/merchantrepair.cpp | 5 ++-- apps/openmw/mwgui/quickkeysmenu.cpp | 9 +++--- apps/openmw/mwgui/recharge.cpp | 5 ++-- apps/openmw/mwgui/referenceinterface.cpp | 4 ++- apps/openmw/mwgui/repair.cpp | 4 ++- apps/openmw/mwgui/scrollwindow.cpp | 4 ++- apps/openmw/mwgui/spellbuyingwindow.cpp | 9 +++--- apps/openmw/mwgui/spellcreationdialog.cpp | 7 +++-- apps/openmw/mwgui/spellicons.cpp | 3 +- apps/openmw/mwgui/spellwindow.cpp | 11 +++---- apps/openmw/mwgui/statswindow.cpp | 7 +++-- apps/openmw/mwgui/tooltips.cpp | 5 ++-- apps/openmw/mwgui/tradewindow.cpp | 5 ++-- apps/openmw/mwgui/trainingwindow.cpp | 3 +- apps/openmw/mwgui/travelwindow.cpp | 3 +- apps/openmw/mwgui/waitdialog.cpp | 5 ++-- apps/openmw/mwgui/windowmanagerimp.cpp | 5 ++-- apps/openmw/mwinput/inputmanagerimp.cpp | 5 ++-- apps/openmw/mwmechanics/actors.cpp | 23 ++++++++------- apps/openmw/mwmechanics/actorutil.cpp | 12 ++++++++ apps/openmw/mwmechanics/actorutil.hpp | 14 +++++++++ apps/openmw/mwmechanics/aiavoiddoor.cpp | 3 +- apps/openmw/mwmechanics/aipackage.cpp | 3 +- apps/openmw/mwmechanics/aisequence.cpp | 5 ++-- apps/openmw/mwmechanics/aiwander.cpp | 5 ++-- apps/openmw/mwmechanics/character.cpp | 21 +++++++------- apps/openmw/mwmechanics/combat.cpp | 13 +++++---- apps/openmw/mwmechanics/difficultyscaling.cpp | 4 ++- apps/openmw/mwmechanics/disease.hpp | 8 +++-- apps/openmw/mwmechanics/enchanting.cpp | 7 +++-- apps/openmw/mwmechanics/levelledlist.hpp | 5 ++-- .../mwmechanics/mechanicsmanagerimp.cpp | 29 ++++++++++--------- apps/openmw/mwmechanics/repair.cpp | 9 +++--- apps/openmw/mwmechanics/spellcasting.cpp | 29 ++++++++++--------- apps/openmw/mwphysics/physicssystem.cpp | 3 +- apps/openmw/mwrender/characterpreview.cpp | 4 ++- apps/openmw/mwrender/npcanimation.cpp | 3 +- apps/openmw/mwrender/ripplesimulation.cpp | 4 ++- apps/openmw/mwscript/cellextensions.cpp | 22 +++++++------- apps/openmw/mwscript/containerextensions.cpp | 6 ++-- apps/openmw/mwscript/guiextensions.cpp | 4 ++- apps/openmw/mwscript/miscextensions.cpp | 7 +++-- apps/openmw/mwscript/statsextensions.cpp | 29 ++++++++++--------- .../mwscript/transformationextensions.cpp | 18 +++++++----- apps/openmw/mwsound/soundmanagerimp.cpp | 6 ++-- apps/openmw/mwstate/statemanagerimp.cpp | 5 ++-- apps/openmw/mwworld/action.cpp | 4 ++- apps/openmw/mwworld/actionequip.cpp | 4 ++- apps/openmw/mwworld/containerstore.cpp | 5 ++-- apps/openmw/mwworld/failedaction.cpp | 3 +- apps/openmw/mwworld/inventorystore.cpp | 9 +++--- apps/openmw/mwworld/projectilemanager.cpp | 3 +- apps/openmw/mwworld/weather.cpp | 4 ++- 70 files changed, 327 insertions(+), 215 deletions(-) create mode 100644 apps/openmw/mwmechanics/actorutil.cpp create mode 100644 apps/openmw/mwmechanics/actorutil.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index c33b711e6..a0f9e8e13 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -78,7 +78,7 @@ add_openmw_dir (mwclass ) add_openmw_dir (mwmechanics - mechanicsmanagerimp stat creaturestats magiceffects movement + mechanicsmanagerimp stat creaturestats magiceffects movement actorutil drawstate spells activespells npcstats aipackage aisequence aipursue alchemy aiwander aitravel aifollow aiavoiddoor aiescort aiactivate aicombat repair enchanting pathfinding pathgrid security spellsuccess spellcasting disease pickpocket levelledlist combat steering obstacle autocalcspell difficultyscaling aicombataction actor summoning diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index 2ba8ba03b..324dd32ee 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -20,6 +20,7 @@ #include "../mwrender/objects.hpp" #include "../mwrender/renderinginterface.hpp" +#include "../mwmechanics/actorutil.hpp" #include "../mwgui/tooltips.hpp" @@ -244,7 +245,7 @@ namespace MWClass typeText = "#{sHeavy}"; text += "\n#{sArmorRating}: " + MWGui::ToolTips::toString(getEffectiveArmorRating(ptr, - MWBase::Environment::get().getWorld()->getPlayerPtr())); + MWMechanics::getPlayer())); int remainingHealth = getItemHealth(ptr); text += "\n#{sCondition}: " + MWGui::ToolTips::toString(remainingHealth) + "/" diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 5604aa783..ff09282c1 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -36,6 +36,7 @@ #include "../mwmechanics/npcstats.hpp" #include "../mwmechanics/combat.hpp" +#include "../mwmechanics/actorutil.hpp" namespace { @@ -344,7 +345,7 @@ namespace MWClass if(!object.isEmpty()) getCreatureStats(ptr).setLastHitAttemptObject(object.getClass().getId(object)); - if(setOnPcHitMe && !attacker.isEmpty() && attacker == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if(setOnPcHitMe && !attacker.isEmpty() && attacker == MWMechanics::getPlayer()) { const std::string &script = ptr.get()->mBase->mScript; /* Set the OnPCHitMe script variable. The script is responsible for clearing it. */ diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 6749afa6b..18c381e13 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -26,6 +26,8 @@ #include "../mwrender/objects.hpp" #include "../mwrender/renderinginterface.hpp" +#include "../mwmechanics/actorutil.hpp" + namespace { struct DoorCustomData : public MWWorld::CustomData @@ -126,7 +128,7 @@ namespace MWClass if (needKey && hasKey) { - if(actor == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if(actor == MWMechanics::getPlayer()) MWBase::Environment::get().getWindowManager()->messageBox(keyName + " #{sKeyUsed}"); unlock(ptr); //Call the function here. because that makes sense. // using a key disarms the trap diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index e2b714a64..5f166b3e3 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -24,6 +24,7 @@ #include "../mwmechanics/autocalcspell.hpp" #include "../mwmechanics/difficultyscaling.hpp" #include "../mwmechanics/character.hpp" +#include "../mwmechanics/actorutil.hpp" #include "../mwworld/ptr.hpp" #include "../mwworld/actiontalk.hpp" @@ -503,7 +504,7 @@ namespace MWClass if(otherstats.isDead()) // Can't hit dead actors return; - if(ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if(ptr == MWMechanics::getPlayer()) MWBase::Environment::get().getWindowManager()->setEnemy(victim); int weapskill = ESM::Skill::HandToHand; @@ -542,7 +543,7 @@ namespace MWClass { MWMechanics::getHandToHandDamage(ptr, victim, damage, healthdmg, attackStrength); } - if(ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if(ptr == MWMechanics::getPlayer()) { skillUsageSucceeded(ptr, weapskill, 0); @@ -608,7 +609,7 @@ namespace MWClass if(!object.isEmpty()) getCreatureStats(ptr).setLastHitAttemptObject(object.getClass().getId(object)); - if(setOnPcHitMe && !attacker.isEmpty() && attacker == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if(setOnPcHitMe && !attacker.isEmpty() && attacker == MWMechanics::getPlayer()) { const std::string &script = ptr.getClass().getScript(ptr); /* Set the OnPCHitMe script variable. The script is responsible for clearing it. */ @@ -700,7 +701,7 @@ namespace MWClass if (armorhealth == 0) armor = *inv.unequipItem(armor, ptr); - if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (ptr == MWMechanics::getPlayer()) skillUsageSucceeded(ptr, armor.getClass().getEquipmentSkill(armor), 0); switch(armor.getClass().getEquipmentSkill(armor)) @@ -716,7 +717,7 @@ namespace MWClass break; } } - else if(ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + else if(ptr == MWMechanics::getPlayer()) skillUsageSucceeded(ptr, ESM::Skill::Unarmored, 0); } } @@ -729,7 +730,7 @@ namespace MWClass if(damage > 0.0f) { sndMgr->playSound3D(ptr, "Health Damage", 1.0f, 1.0f); - if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (ptr == MWMechanics::getPlayer()) MWBase::Environment::get().getWindowManager()->activateHitOverlay(); } MWMechanics::DynamicStat health(getCreatureStats(ptr).getHealth()); @@ -783,7 +784,7 @@ namespace MWClass const MWWorld::Ptr& actor) const { // player got activated by another NPC - if(ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if(ptr == MWMechanics::getPlayer()) return boost::shared_ptr(new MWWorld::ActionTalk(actor)); // Werewolfs can't activate NPCs diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 35f205eb8..993dde6e4 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -41,6 +41,7 @@ #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/npcstats.hpp" +#include "../mwmechanics/actorutil.hpp" #include "filter.hpp" #include "hypertextparser.hpp" @@ -532,7 +533,7 @@ namespace MWDialogue else if (curDisp + mTemporaryDispositionChange > 100) mTemporaryDispositionChange = 100 - curDisp; - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); player.getClass().skillUsageSucceeded(player, ESM::Skill::Speechcraft, success ? 0 : 1); if (success) diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index 5e6b83b50..e3a773b05 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -17,6 +17,7 @@ #include "../mwmechanics/npcstats.hpp" #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/magiceffects.hpp" +#include "../mwmechanics/actorutil.hpp" #include "selectwrapper.hpp" @@ -97,7 +98,7 @@ bool MWDialogue::Filter::testActor (const ESM::DialInfo& info) const bool MWDialogue::Filter::testPlayer (const ESM::DialInfo& info) const { - const MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + const MWWorld::Ptr player = MWMechanics::getPlayer(); // check player faction if (!info.mPcFaction.empty()) @@ -219,7 +220,7 @@ bool MWDialogue::Filter::testSelectStructNumeric (const SelectWrapper& select) c case SelectWrapper::Function_PcHealthPercent: { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); float ratio = player.getClass().getCreatureStats (player).getHealth().getCurrent() / player.getClass().getCreatureStats (player).getHealth().getModified(); @@ -229,7 +230,7 @@ bool MWDialogue::Filter::testSelectStructNumeric (const SelectWrapper& select) c case SelectWrapper::Function_PcDynamicStat: { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); float value = player.getClass().getCreatureStats (player). getDynamic (select.getArgument()).getCurrent(); @@ -253,7 +254,7 @@ bool MWDialogue::Filter::testSelectStructNumeric (const SelectWrapper& select) c int MWDialogue::Filter::getSelectStructInteger (const SelectWrapper& select) const { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); switch (select.getFunction()) { @@ -429,7 +430,7 @@ int MWDialogue::Filter::getSelectStructInteger (const SelectWrapper& select) con bool MWDialogue::Filter::getSelectStructBoolean (const SelectWrapper& select) const { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); switch (select.getFunction()) { @@ -532,7 +533,7 @@ bool MWDialogue::Filter::getSelectStructBoolean (const SelectWrapper& select) co case SelectWrapper::Function_ShouldAttack: return MWBase::Environment::get().getMechanicsManager()->isAggressive(mActor, - MWBase::Environment::get().getWorld()->getPlayerPtr()); + MWMechanics::getPlayer()); case SelectWrapper::Function_Werewolf: diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index 768ad82e4..60bd70c04 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -11,6 +11,7 @@ #include "../mwmechanics/magiceffects.hpp" #include "../mwmechanics/alchemy.hpp" +#include "../mwmechanics/actorutil.hpp" #include "../mwworld/class.hpp" #include "../mwworld/esmstore.hpp" @@ -124,9 +125,9 @@ namespace MWGui void AlchemyWindow::open() { - mAlchemy->setAlchemist (MWBase::Environment::get().getWorld()->getPlayerPtr()); + mAlchemy->setAlchemist (MWMechanics::getPlayer()); - InventoryItemModel* model = new InventoryItemModel(MWBase::Environment::get().getWorld()->getPlayerPtr()); + InventoryItemModel* model = new InventoryItemModel(MWMechanics::getPlayer()); mSortModel = new SortFilterItemModel(model); mSortModel->setFilter(SortFilterItemModel::Filter_OnlyIngredients); mItemView->setModel (mSortModel); @@ -136,7 +137,7 @@ namespace MWGui int index = 0; - mAlchemy->setAlchemist (MWBase::Environment::get().getWorld()->getPlayerPtr()); + mAlchemy->setAlchemist (MWMechanics::getPlayer()); for (MWMechanics::Alchemy::TToolsIterator iter (mAlchemy->beginTools()); iter!=mAlchemy->endTools() && index (mApparatus.size()); ++iter, ++index) diff --git a/apps/openmw/mwgui/bookwindow.cpp b/apps/openmw/mwgui/bookwindow.cpp index 44a988523..f3cefb787 100644 --- a/apps/openmw/mwgui/bookwindow.cpp +++ b/apps/openmw/mwgui/bookwindow.cpp @@ -9,6 +9,8 @@ #include "../mwbase/soundmanager.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwmechanics/actorutil.hpp" + #include "../mwworld/actiontake.hpp" #include "formatting.hpp" @@ -123,7 +125,7 @@ namespace MWGui MWBase::Environment::get().getSoundManager()->playSound("Item Book Up", 1.0, 1.0); MWWorld::ActionTake take(mBook); - take.execute (MWBase::Environment::get().getWorld()->getPlayerPtr()); + take.execute (MWMechanics::getPlayer()); MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Book); } diff --git a/apps/openmw/mwgui/charactercreation.cpp b/apps/openmw/mwgui/charactercreation.cpp index 6585a0dd0..d2ce35509 100644 --- a/apps/openmw/mwgui/charactercreation.cpp +++ b/apps/openmw/mwgui/charactercreation.cpp @@ -7,6 +7,7 @@ #include "../mwbase/windowmanager.hpp" #include "../mwmechanics/npcstats.hpp" +#include "../mwmechanics/actorutil.hpp" #include "../mwworld/class.hpp" #include "../mwworld/fallback.hpp" @@ -51,7 +52,7 @@ namespace void updatePlayerHealth() { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); MWMechanics::NpcStats& npcStats = player.getClass().getNpcStats(player); npcStats.updateHealth(); } @@ -228,7 +229,7 @@ namespace MWGui mReviewDialog->setBirthSign(mPlayerBirthSignId); { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); const MWMechanics::CreatureStats& stats = player.getClass().getCreatureStats(player); mReviewDialog->setHealth ( stats.getHealth() ); diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index b2cc09b43..5d71fc445 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -9,6 +9,7 @@ #include "../mwbase/windowmanager.hpp" #include "../mwbase/dialoguemanager.hpp" #include "../mwbase/mechanicsmanager.hpp" +#include "../mwmechanics/actorutil.hpp" #include "../mwworld/class.hpp" @@ -137,7 +138,7 @@ namespace MWGui if (mPtr.getTypeName() == typeid(ESM::NPC).name() && !loot) { // we are stealing stuff - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); mModel = new PickpocketItemModel(player, new InventoryItemModel(container), !mPtr.getClass().getCreatureStats(mPtr).getKnockedDown()); } @@ -183,7 +184,7 @@ namespace MWGui && !mPickpocketDetected ) { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); MWMechanics::Pickpocket pickpocket(player, mPtr); if (pickpocket.finish()) { @@ -260,7 +261,7 @@ namespace MWGui bool ContainerWindow::onTakeItem(const ItemStack &item, int count) { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); // TODO: move to ItemModels if (dynamic_cast(mModel) && !mPtr.getClass().getCreatureStats(mPtr).getKnockedDown()) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index ce33a74dd..a6000a739 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -21,6 +21,7 @@ #include "../mwworld/esmstore.hpp" #include "../mwmechanics/creaturestats.hpp" +#include "../mwmechanics/actorutil.hpp" #include "widgets.hpp" #include "bookpage.hpp" @@ -89,7 +90,7 @@ namespace MWGui WindowModal::open(); center(); - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); int playerGold = player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId); mBribe10Button->setEnabled (playerGold >= 10); diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 61a935a6f..c182a0a52 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -18,6 +18,8 @@ #include "../mwworld/containerstore.hpp" #include "../mwworld/esmstore.hpp" +#include "../mwmechanics/actorutil.hpp" + #include "itemselection.hpp" #include "itemwidget.hpp" @@ -160,7 +162,7 @@ namespace MWGui void EnchantingDialog::startSelfEnchanting(MWWorld::Ptr soulgem) { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); mEnchanting.setSelfEnchanting(true); mEnchanting.setEnchanter(player); @@ -208,7 +210,7 @@ namespace MWGui mItemSelectionDialog->eventItemSelected += MyGUI::newDelegate(this, &EnchantingDialog::onItemSelected); mItemSelectionDialog->eventDialogCanceled += MyGUI::newDelegate(this, &EnchantingDialog::onItemCancel); mItemSelectionDialog->setVisible(true); - mItemSelectionDialog->openContainer(MWBase::Environment::get().getWorld()->getPlayerPtr()); + mItemSelectionDialog->openContainer(MWMechanics::getPlayer()); mItemSelectionDialog->setFilter(SortFilterItemModel::Filter_OnlyEnchantable); } else @@ -263,7 +265,7 @@ namespace MWGui mItemSelectionDialog->eventItemSelected += MyGUI::newDelegate(this, &EnchantingDialog::onSoulSelected); mItemSelectionDialog->eventDialogCanceled += MyGUI::newDelegate(this, &EnchantingDialog::onSoulCancel); mItemSelectionDialog->setVisible(true); - mItemSelectionDialog->openContainer(MWBase::Environment::get().getWorld()->getPlayerPtr()); + mItemSelectionDialog->openContainer(MWMechanics::getPlayer()); mItemSelectionDialog->setFilter(SortFilterItemModel::Filter_OnlyChargedSoulstones); //MWBase::Environment::get().getWindowManager()->messageBox("#{sInventorySelectNoSoul}"); @@ -324,7 +326,7 @@ namespace MWGui mEnchanting.setNewItemName(mName->getCaption()); mEnchanting.setEffect(mEffectList); - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); int playerGold = player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId); if (mPtr != player && mEnchanting.getEnchantPrice() > playerGold) { diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 1acbea6d7..a93bb47e9 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -18,6 +18,7 @@ #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/npcstats.hpp" +#include "../mwmechanics/actorutil.hpp" #include "inventorywindow.hpp" #include "spellicons.hpp" @@ -259,7 +260,7 @@ namespace MWGui { // drop item into the gameworld MWBase::Environment::get().getWorld()->breakInvisibility( - MWBase::Environment::get().getWorld()->getPlayerPtr()); + MWMechanics::getPlayer()); MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize(); MyGUI::IntPoint cursorPosition = MyGUI::InputManager::getInstance().getMousePosition(); @@ -338,7 +339,7 @@ namespace MWGui void HUD::onWeaponClicked(MyGUI::Widget* _sender) { - const MWWorld::Ptr& player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + const MWWorld::Ptr& player = MWMechanics::getPlayer(); if (player.getClass().getNpcStats(player).isWerewolf()) { MWBase::Environment::get().getWindowManager()->messageBox("#{sWerewolfRefusal}"); @@ -350,7 +351,7 @@ namespace MWGui void HUD::onMagicClicked(MyGUI::Widget* _sender) { - const MWWorld::Ptr& player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + const MWWorld::Ptr& player = MWMechanics::getPlayer(); if (player.getClass().getNpcStats(player).isWerewolf()) { MWBase::Environment::get().getWindowManager()->messageBox("#{sWerewolfRefusal}"); diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 580e583c9..f5a5f023f 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -29,6 +29,8 @@ #include "../mwscript/interpretercontext.hpp" #include "../mwrender/characterpreview.hpp" +#include "../mwmechanics/actorutil.hpp" + #include "itemview.hpp" #include "inventoryitemmodel.hpp" #include "sortfilteritemmodel.hpp" @@ -63,7 +65,7 @@ namespace MWGui , mGuiMode(GM_Inventory) , mLastXSize(0) , mLastYSize(0) - , mPreview(new MWRender::InventoryPreview(viewer, resourceSystem, MWBase::Environment::get().getWorld()->getPlayerPtr())) + , mPreview(new MWRender::InventoryPreview(viewer, resourceSystem, MWMechanics::getPlayer())) , mTrading(false) { mPreviewTexture.reset(new osgMyGUI::OSGTexture(mPreview->getTexture())); @@ -333,7 +335,7 @@ namespace MWGui void InventoryWindow::open() { - mPtr = MWBase::Environment::get().getWorld()->getPlayerPtr(); + mPtr = MWMechanics::getPlayer(); updateEncumbranceBar(); @@ -439,7 +441,7 @@ namespace MWGui { const std::string& script = ptr.getClass().getScript(ptr); - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); // early-out for items that need to be equipped, but can't be equipped: we don't want to set OnPcEquip in that case if (!ptr.getClass().getEquipmentSlots(ptr).first.empty()) @@ -549,7 +551,7 @@ namespace MWGui void InventoryWindow::updateEncumbranceBar() { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); float capacity = player.getClass().getCapacity(player); float encumbrance = player.getClass().getEncumbrance(player); @@ -583,7 +585,7 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->updateSpellWindow(); MWBase::Environment::get().getMechanicsManager()->updateMagicEffects( - MWBase::Environment::get().getWorld()->getPlayerPtr()); + MWMechanics::getPlayer()); dirtyPreview(); } @@ -614,7 +616,7 @@ namespace MWGui int count = object.getRefData().getCount(); - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); MWBase::Environment::get().getWorld()->breakInvisibility(player); MWBase::Environment::get().getMechanicsManager()->itemTaken(player, object, MWWorld::Ptr(), count); @@ -644,7 +646,7 @@ namespace MWGui { ItemModel::ModelIndex selected = -1; // not using mSortFilterModel as we only need sorting, not filtering - SortFilterItemModel model(new InventoryItemModel(MWBase::Environment::get().getWorld()->getPlayerPtr())); + SortFilterItemModel model(new InventoryItemModel(MWMechanics::getPlayer())); model.setSortByType(false); model.update(); if (model.getItemCount() == 0) diff --git a/apps/openmw/mwgui/jailscreen.cpp b/apps/openmw/mwgui/jailscreen.cpp index e4a3a3147..7eaf5eb30 100644 --- a/apps/openmw/mwgui/jailscreen.cpp +++ b/apps/openmw/mwgui/jailscreen.cpp @@ -8,6 +8,7 @@ #include "../mwbase/environment.hpp" #include "../mwmechanics/npcstats.hpp" +#include "../mwmechanics/actorutil.hpp" #include "../mwworld/esmstore.hpp" #include "../mwworld/store.hpp" @@ -57,7 +58,7 @@ namespace MWGui if (mFadeTimeRemaining <= 0) { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); MWBase::Environment::get().getWorld()->teleportToClosestMarker(player, "prisonmarker"); setVisible(true); @@ -76,7 +77,7 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Jail); MWBase::Environment::get().getWindowManager()->fadeScreenIn(0.5); - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); MWBase::Environment::get().getWorld()->advanceTime(mDays * 24); for (int i=0; igetPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); MWMechanics::NpcStats& pcStats = player.getClass().getNpcStats (player); if (mSpentAttributes.size() < mCoinCount) diff --git a/apps/openmw/mwgui/merchantrepair.cpp b/apps/openmw/mwgui/merchantrepair.cpp index 862b719d4..481e1ceb4 100644 --- a/apps/openmw/mwgui/merchantrepair.cpp +++ b/apps/openmw/mwgui/merchantrepair.cpp @@ -13,6 +13,7 @@ #include "../mwbase/soundmanager.hpp" #include "../mwmechanics/creaturestats.hpp" +#include "../mwmechanics/actorutil.hpp" #include "../mwworld/class.hpp" #include "../mwworld/containerstore.hpp" @@ -40,7 +41,7 @@ void MerchantRepair::startRepair(const MWWorld::Ptr &actor) int currentY = 0; - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); int playerGold = player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId); MWWorld::ContainerStore& store = player.getClass().getContainerStore(player); @@ -125,7 +126,7 @@ void MerchantRepair::exit() void MerchantRepair::onRepairButtonClick(MyGUI::Widget *sender) { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); int price = MyGUI::utility::parseInt(sender->getUserString("Price")); if (price > player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId)) diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index 3f896bae2..d25151816 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -19,6 +19,7 @@ #include "../mwmechanics/spellcasting.hpp" #include "../mwmechanics/creaturestats.hpp" +#include "../mwmechanics/actorutil.hpp" #include "../mwgui/inventorywindow.hpp" @@ -147,7 +148,7 @@ namespace MWGui mItemSelectionDialog->eventDialogCanceled += MyGUI::newDelegate(this, &QuickKeysMenu::onAssignItemCancel); } mItemSelectionDialog->setVisible(true); - mItemSelectionDialog->openContainer(MWBase::Environment::get().getWorld()->getPlayerPtr()); + mItemSelectionDialog->openContainer(MWMechanics::getPlayer()); mItemSelectionDialog->setFilter(SortFilterItemModel::Filter_OnlyUsableItems); mAssignDialog->setVisible (false); @@ -262,7 +263,7 @@ namespace MWGui QuickKeyType type = mAssigned[index-1]; - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); MWWorld::InventoryStore& store = player.getClass().getInventoryStore(player); if (type == Type_Item || type == Type_MagicItem) @@ -473,7 +474,7 @@ namespace MWGui case Type_MagicItem: { // Find the item by id - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); MWWorld::InventoryStore& store = player.getClass().getInventoryStore(player); MWWorld::Ptr item; for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it) @@ -543,7 +544,7 @@ namespace MWGui { WindowModal::open(); - mMagicList->setModel(new SpellModel(MWBase::Environment::get().getWorld()->getPlayerPtr())); + mMagicList->setModel(new SpellModel(MWMechanics::getPlayer())); mMagicList->resetScrollbars(); } diff --git a/apps/openmw/mwgui/recharge.cpp b/apps/openmw/mwgui/recharge.cpp index 69c5c61c4..1dac7138f 100644 --- a/apps/openmw/mwgui/recharge.cpp +++ b/apps/openmw/mwgui/recharge.cpp @@ -17,6 +17,7 @@ #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/npcstats.hpp" +#include "../mwmechanics/actorutil.hpp" #include "widgets.hpp" #include "itemwidget.hpp" @@ -92,7 +93,7 @@ void Recharge::updateView() int currentY = 0; - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); MWWorld::ContainerStore& store = player.getClass().getContainerStore(player); for (MWWorld::ContainerStoreIterator iter (store.begin()); iter!=store.end(); ++iter) @@ -147,7 +148,7 @@ void Recharge::onItemClicked(MyGUI::Widget *sender) MWWorld::Ptr item = *sender->getUserData(); - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); MWMechanics::CreatureStats& stats = player.getClass().getCreatureStats(player); MWMechanics::NpcStats& npcStats = player.getClass().getNpcStats(player); diff --git a/apps/openmw/mwgui/referenceinterface.cpp b/apps/openmw/mwgui/referenceinterface.cpp index 2ea0db64a..76bb4f53f 100644 --- a/apps/openmw/mwgui/referenceinterface.cpp +++ b/apps/openmw/mwgui/referenceinterface.cpp @@ -3,6 +3,8 @@ #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" +#include "../mwmechanics/actorutil.hpp" + namespace MWGui { ReferenceInterface::ReferenceInterface() @@ -16,7 +18,7 @@ namespace MWGui void ReferenceInterface::checkReferenceAvailable() { - MWWorld::CellStore* playerCell = MWBase::Environment::get().getWorld()->getPlayerPtr().getCell(); + MWWorld::CellStore* playerCell = MWMechanics::getPlayer().getCell(); // check if player has changed cell, or count of the reference has become 0 if ((playerCell != mCurrentPlayerCell && mCurrentPlayerCell != NULL) diff --git a/apps/openmw/mwgui/repair.cpp b/apps/openmw/mwgui/repair.cpp index 534226aeb..49d5735a4 100644 --- a/apps/openmw/mwgui/repair.cpp +++ b/apps/openmw/mwgui/repair.cpp @@ -9,6 +9,8 @@ #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwmechanics/actorutil.hpp" + #include "../mwworld/containerstore.hpp" #include "../mwworld/class.hpp" @@ -94,7 +96,7 @@ void Repair::updateRepairView() int currentY = 0; - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); MWWorld::ContainerStore& store = player.getClass().getContainerStore(player); int categories = MWWorld::ContainerStore::Type_Weapon | MWWorld::ContainerStore::Type_Armor; for (MWWorld::ContainerStoreIterator iter (store.begin(categories)); diff --git a/apps/openmw/mwgui/scrollwindow.cpp b/apps/openmw/mwgui/scrollwindow.cpp index 01ce7767e..ccc07174d 100644 --- a/apps/openmw/mwgui/scrollwindow.cpp +++ b/apps/openmw/mwgui/scrollwindow.cpp @@ -10,6 +10,8 @@ #include "../mwbase/soundmanager.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwmechanics/actorutil.hpp" + #include "../mwworld/actiontake.hpp" #include "formatting.hpp" @@ -103,7 +105,7 @@ namespace MWGui MWBase::Environment::get().getSoundManager()->playSound("Item Book Up", 1.0, 1.0); MWWorld::ActionTake take(mScroll); - take.execute (MWBase::Environment::get().getWorld()->getPlayerPtr()); + take.execute (MWMechanics::getPlayer()); MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Scroll); } diff --git a/apps/openmw/mwgui/spellbuyingwindow.cpp b/apps/openmw/mwgui/spellbuyingwindow.cpp index 61dd599e7..8c4520662 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.cpp +++ b/apps/openmw/mwgui/spellbuyingwindow.cpp @@ -15,6 +15,7 @@ #include "../mwworld/esmstore.hpp" #include "../mwmechanics/creaturestats.hpp" +#include "../mwmechanics/actorutil.hpp" namespace MWGui { @@ -48,7 +49,7 @@ namespace MWGui int price = static_cast(spell->mData.mCost*store.get().find("fSpellValueMult")->getFloat()); price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr,price,true); - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); int playerGold = player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId); // TODO: refactor to use MyGUI::ListBox @@ -125,7 +126,7 @@ namespace MWGui bool SpellBuyingWindow::playerHasSpell(const std::string &id) { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); return player.getClass().getCreatureStats(player).getSpells().hasSpell(id); } @@ -133,7 +134,7 @@ namespace MWGui { int price = *_sender->getUserData(); - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); if (price > player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId)) return; @@ -158,7 +159,7 @@ namespace MWGui void SpellBuyingWindow::updateLabels() { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); int playerGold = player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId); mPlayerGold->setCaptionWithReplacing("#{sGold}: " + MyGUI::utility::toString(playerGold)); diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index 57563be22..ff5a27abe 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -19,6 +19,7 @@ #include "../mwmechanics/spellcasting.hpp" #include "../mwmechanics/spells.hpp" #include "../mwmechanics/creaturestats.hpp" +#include "../mwmechanics/actorutil.hpp" #include "tooltips.hpp" #include "class.hpp" @@ -376,7 +377,7 @@ namespace MWGui return; } - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); int playerGold = player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId); if (MyGUI::utility::parseInt(mPriceLabel->getCaption()) > playerGold) @@ -474,7 +475,7 @@ namespace MWGui mPriceLabel->setCaption(MyGUI::utility::toString(int(price))); - float chance = MWMechanics::getSpellSuccessChance(&mSpell, MWBase::Environment::get().getWorld()->getPlayerPtr()); + float chance = MWMechanics::getSpellSuccessChance(&mSpell, MWMechanics::getPlayer()); mSuccessChance->setCaption(MyGUI::utility::toString(int(chance))); } @@ -507,7 +508,7 @@ namespace MWGui { // get the list of magic effects that are known to the player - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); MWMechanics::CreatureStats& stats = player.getClass().getCreatureStats(player); MWMechanics::Spells& spells = stats.getSpells(); diff --git a/apps/openmw/mwgui/spellicons.cpp b/apps/openmw/mwgui/spellicons.cpp index db0453623..b2995af3c 100644 --- a/apps/openmw/mwgui/spellicons.cpp +++ b/apps/openmw/mwgui/spellicons.cpp @@ -16,6 +16,7 @@ #include "../mwworld/inventorystore.hpp" #include "../mwmechanics/creaturestats.hpp" +#include "../mwmechanics/actorutil.hpp" #include "tooltips.hpp" @@ -43,7 +44,7 @@ namespace MWGui { // TODO: Tracking add/remove/expire would be better than force updating every frame - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); const MWMechanics::CreatureStats& stats = player.getClass().getCreatureStats(player); diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index d2ea67ea9..68a604256 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -15,6 +15,7 @@ #include "../mwmechanics/spellcasting.hpp" #include "../mwmechanics/spells.hpp" #include "../mwmechanics/creaturestats.hpp" +#include "../mwmechanics/actorutil.hpp" #include "spellicons.hpp" #include "inventorywindow.hpp" @@ -79,12 +80,12 @@ namespace MWGui { mSpellIcons->updateWidgets(mEffectBox, false); - mSpellView->setModel(new SpellModel(MWBase::Environment::get().getWorld()->getPlayerPtr())); + mSpellView->setModel(new SpellModel(MWMechanics::getPlayer())); } void SpellWindow::onEnchantedItemSelected(MWWorld::Ptr item, bool alreadyEquipped) { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); MWWorld::InventoryStore& store = player.getClass().getInventoryStore(player); // retrieve ContainerStoreIterator to the item @@ -159,7 +160,7 @@ namespace MWGui void SpellWindow::onSpellSelected(const std::string& spellId) { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); MWWorld::InventoryStore& store = player.getClass().getInventoryStore(player); store.setSelectedEnchantItem(store.end()); MWBase::Environment::get().getWindowManager()->setSelectedSpell(spellId, int(MWMechanics::getSpellSuccessChance(spellId, player))); @@ -169,7 +170,7 @@ namespace MWGui void SpellWindow::onDeleteSpellAccept() { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); MWMechanics::CreatureStats& stats = player.getClass().getCreatureStats(player); MWMechanics::Spells& spells = stats.getSpells(); @@ -183,7 +184,7 @@ namespace MWGui void SpellWindow::cycle(bool next) { - mSpellView->setModel(new SpellModel(MWBase::Environment::get().getWorld()->getPlayerPtr())); + mSpellView->setModel(new SpellModel(MWMechanics::getPlayer())); SpellModel::ModelIndex selected = 0; for (SpellModel::ModelIndex i = 0; igetModel()->getItemCount()); ++i) diff --git a/apps/openmw/mwgui/statswindow.cpp b/apps/openmw/mwgui/statswindow.cpp index cb1bf6f37..efbbeb29a 100644 --- a/apps/openmw/mwgui/statswindow.cpp +++ b/apps/openmw/mwgui/statswindow.cpp @@ -15,6 +15,7 @@ #include "../mwworld/esmstore.hpp" #include "../mwmechanics/npcstats.hpp" +#include "../mwmechanics/actorutil.hpp" #include "tooltips.hpp" @@ -234,7 +235,7 @@ namespace MWGui NoDrop::onFrame(dt); - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); const MWMechanics::NpcStats &PCstats = player.getClass().getNpcStats(player); // level progress @@ -383,7 +384,7 @@ namespace MWGui int base = stat.getBase(); int modified = stat.getModified(); - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); const MWWorld::ESMStore &esmStore = MWBase::Environment::get().getWorld()->getStore(); @@ -493,7 +494,7 @@ namespace MWGui if (!mFactions.empty()) { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); const MWMechanics::NpcStats &PCstats = player.getClass().getNpcStats(player); const std::set &expelled = PCstats.getExpelled(); diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index dbf27ad91..7c7f951af 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -17,6 +17,7 @@ #include "../mwworld/class.hpp" #include "../mwworld/esmstore.hpp" #include "../mwmechanics/spellcasting.hpp" +#include "../mwmechanics/actorutil.hpp" #include "mapwindow.hpp" #include "inventorywindow.hpp" @@ -234,7 +235,7 @@ namespace MWGui } if (MWMechanics::spellIncreasesSkill(spell)) // display school of spells that contribute to skill progress { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); int school = MWMechanics::getSpellSchool(spell, player); info.text = "#{sSchool}: " + sSchoolNames[school]; } @@ -355,7 +356,7 @@ namespace MWGui if(!mFocusObject.isEmpty()) { const MWWorld::CellRef& cellref = mFocusObject.getCellRef(); - MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr ptr = MWMechanics::getPlayer(); MWWorld::Ptr victim; MWBase::MechanicsManager* mm = MWBase::Environment::get().getMechanicsManager(); diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 0ae661eb3..6f45ed005 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -20,6 +20,7 @@ #include "../mwworld/esmstore.hpp" #include "../mwmechanics/creaturestats.hpp" +#include "../mwmechanics/actorutil.hpp" #include "inventorywindow.hpp" #include "itemview.hpp" @@ -282,7 +283,7 @@ namespace MWGui return; } - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); int playerGold = player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId); // check if the player can afford this @@ -490,7 +491,7 @@ namespace MWGui void TradeWindow::updateLabels() { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); int playerGold = player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId); mPlayerGold->setCaptionWithReplacing("#{sYourGold} " + MyGUI::utility::toString(playerGold)); diff --git a/apps/openmw/mwgui/trainingwindow.cpp b/apps/openmw/mwgui/trainingwindow.cpp index 6376ced57..30ad27e46 100644 --- a/apps/openmw/mwgui/trainingwindow.cpp +++ b/apps/openmw/mwgui/trainingwindow.cpp @@ -13,6 +13,7 @@ #include "../mwworld/esmstore.hpp" #include "../mwmechanics/npcstats.hpp" +#include "../mwmechanics/actorutil.hpp" #include "tooltips.hpp" @@ -68,7 +69,7 @@ namespace MWGui { mPtr = actor; - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); int playerGold = player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId); mPlayerGold->setCaptionWithReplacing("#{sGold}: " + MyGUI::utility::toString(playerGold)); diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index 6ea6301ad..8c55c3732 100644 --- a/apps/openmw/mwgui/travelwindow.cpp +++ b/apps/openmw/mwgui/travelwindow.cpp @@ -12,6 +12,7 @@ #include "../mwbase/dialoguemanager.hpp" #include "../mwmechanics/creaturestats.hpp" +#include "../mwmechanics/actorutil.hpp" #include "../mwworld/class.hpp" #include "../mwworld/containerstore.hpp" @@ -144,7 +145,7 @@ namespace MWGui int price; iss >> price; - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); int playerGold = player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId); if (playerGoldgetPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); const MWMechanics::NpcStats &pcstats = player.getClass().getNpcStats(player); // trigger levelup if possible @@ -213,7 +214,7 @@ namespace MWGui void WaitDialog::setCanRest (bool canRest) { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); MWMechanics::CreatureStats& stats = player.getClass().getCreatureStats(player); bool full = (stats.getHealth().getCurrent() >= stats.getHealth().getModified()) && (stats.getMagicka().getCurrent() >= stats.getMagicka().getModified()); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index db5593704..01bf2e7c6 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -56,6 +56,7 @@ #include "../mwmechanics/stat.hpp" #include "../mwmechanics/npcstats.hpp" +#include "../mwmechanics/actorutil.hpp" #include "../mwrender/localmap.hpp" @@ -903,7 +904,7 @@ namespace MWGui if (!mLocalMapRender) return; - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); osg::Vec3f playerPosition = player.getRefData().getPosition().asVec3(); osg::Quat playerOrientation (-player.getRefData().getPosition().rot[2], osg::Vec3(0,0,1)); @@ -1547,7 +1548,7 @@ namespace MWGui { mInventoryWindow->updatePlayer(); - const MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + const MWWorld::Ptr player = MWMechanics::getPlayer(); if (player.getClass().getNpcStats(player).isWerewolf()) { setWerewolfOverlay(true); diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 2d767c6f5..74842e3e3 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -28,6 +28,7 @@ #include "../mwworld/esmstore.hpp" #include "../mwmechanics/npcstats.hpp" +#include "../mwmechanics/actorutil.hpp" using namespace ICS; @@ -1012,7 +1013,7 @@ namespace MWInput { if (!mControlSwitch["playercontrols"]) return; - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); if (player.getClass().getNpcStats(player).isWerewolf()) { // Cannot use items or spells while in werewolf form @@ -1029,7 +1030,7 @@ namespace MWInput if (!MWBase::Environment::get().getWindowManager()->isGuiMode () && MWBase::Environment::get().getWorld()->getGlobalFloat ("chargenstate")==-1) { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); if (player.getClass().getNpcStats(player).isWerewolf()) { // Cannot use items or spells while in werewolf form diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 584c4c320..a323028c0 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -33,6 +33,7 @@ #include "actor.hpp" #include "summoning.hpp" #include "combat.hpp" +#include "actorutil.hpp" namespace { @@ -55,7 +56,7 @@ void adjustBoundItem (const std::string& item, bool bound, const MWWorld::Ptr& a action.execute(actor); MWWorld::ContainerStoreIterator rightHand = store.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); // change draw state only if the item is in player's right hand - if (actor == MWBase::Environment::get().getWorld()->getPlayerPtr() + if (actor == MWMechanics::getPlayer() && rightHand != store.end() && newPtr == *rightHand) { MWBase::Environment::get().getWorld()->getPlayer().setDrawState(MWMechanics::DrawState_Weapon); @@ -81,7 +82,7 @@ public: const std::string& sourceName, const std::string& sourceId, int casterActorId, float magnitude, float remainingTime = -1, float totalTime = -1) { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); if ( ((key.mId == ESM::MagicEffect::CommandHumanoid && mActor.getClass().isNpc()) || (key.mId == ESM::MagicEffect::CommandCreature && mActor.getTypeName() == typeid(ESM::Creature).name())) && casterActorId == player.getClass().getCreatureStats(player).getActorId() @@ -202,7 +203,7 @@ namespace MWMechanics gem->getContainerStore()->unstack(*gem, caster); gem->getCellRef().setSoul(mCreature.getCellRef().getRefId()); - if (caster == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (caster == getPlayer()) MWBase::Environment::get().getWindowManager()->messageBox("#{sSoultrapSuccess}"); const ESM::Static* fx = MWBase::Environment::get().getWorld()->getStore().get() @@ -400,7 +401,7 @@ namespace MWMechanics int intelligence = creatureStats.getAttribute(ESM::Attribute::Intelligence).getModified(); float base = 1.f; - if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (ptr == getPlayer()) base = MWBase::Environment::get().getWorld()->getStore().get().find("fPCbaseMagickaMult")->getFloat(); else base = MWBase::Environment::get().getWorld()->getStore().get().find("fNPCbaseMagickaMult")->getFloat(); @@ -511,7 +512,7 @@ namespace MWMechanics { spells.worsenCorprus(it->first); - if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (ptr == getPlayer()) MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicCorprusWorsens}"); } } @@ -559,7 +560,7 @@ namespace MWMechanics // The actor was killed by a magic effect. Figure out if the player was responsible for it. const ActiveSpells& spells = creatureStats.getActiveSpells(); bool killedByPlayer = false; - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = getPlayer(); for (ActiveSpells::TIterator it = spells.begin(); it != spells.end(); ++it) { const ActiveSpells::ActiveSpellParams& spell = it->second; @@ -726,7 +727,7 @@ namespace MWMechanics void Actors::updateEquippedLight (const MWWorld::Ptr& ptr, float duration) { - bool isPlayer = (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()); + bool isPlayer = (ptr == getPlayer()); MWWorld::InventoryStore &inventoryStore = ptr.getClass().getInventoryStore(ptr); MWWorld::ContainerStoreIterator heldIter = @@ -823,7 +824,7 @@ namespace MWMechanics void Actors::updateCrimePersuit(const MWWorld::Ptr& ptr, float duration) { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = getPlayer(); if (ptr != player && ptr.getClass().isNpc()) { // get stats of witness @@ -945,7 +946,7 @@ namespace MWMechanics if (timerUpdateAITargets >= 1.0f) timerUpdateAITargets = 0; if (timerUpdateHeadTrack >= 0.3f) timerUpdateHeadTrack = 0; - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = getPlayer(); int hostilesCount = 0; // need to know this to play Battle music @@ -1042,7 +1043,7 @@ namespace MWMechanics // Handle player last, in case a cell transition occurs by casting a teleportation spell // (would invalidate the iterator) - if (iter->first == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (iter->first == getPlayer()) { playerCharacter = iter->second->getCharacterController(); continue; @@ -1423,7 +1424,7 @@ namespace MWMechanics for (PtrActorMap::iterator it = map.begin(); it != map.end(); ++it) { MWWorld::Ptr ptr = it->first; - if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr() + if (ptr == getPlayer() || !isConscious(ptr) || ptr.getClass().getCreatureStats(ptr).isParalyzed()) continue; diff --git a/apps/openmw/mwmechanics/actorutil.cpp b/apps/openmw/mwmechanics/actorutil.cpp new file mode 100644 index 000000000..dc3770556 --- /dev/null +++ b/apps/openmw/mwmechanics/actorutil.cpp @@ -0,0 +1,12 @@ +#include "actorutil.hpp" + +#include "../mwbase/world.hpp" +#include "../mwbase/environment.hpp" + +namespace MWMechanics +{ + MWWorld::Ptr getPlayer() + { + return MWBase::Environment::get().getWorld()->getPlayerPtr(); + } +} diff --git a/apps/openmw/mwmechanics/actorutil.hpp b/apps/openmw/mwmechanics/actorutil.hpp new file mode 100644 index 000000000..95172b9f9 --- /dev/null +++ b/apps/openmw/mwmechanics/actorutil.hpp @@ -0,0 +1,14 @@ +#ifndef OPENMW_MWMECHANICS_ACTORUTIL_H +#define OPENMW_MWMECHANICS_ACTORUTIL_H + +namespace MWWorld +{ + class Ptr; +} + +namespace MWMechanics +{ + MWWorld::Ptr getPlayer(); +} + +#endif diff --git a/apps/openmw/mwmechanics/aiavoiddoor.cpp b/apps/openmw/mwmechanics/aiavoiddoor.cpp index b3aa346ce..409f7b9c4 100644 --- a/apps/openmw/mwmechanics/aiavoiddoor.cpp +++ b/apps/openmw/mwmechanics/aiavoiddoor.cpp @@ -6,6 +6,7 @@ #include "../mwworld/class.hpp" #include "creaturestats.hpp" #include "movement.hpp" +#include "actorutil.hpp" #include "steering.hpp" @@ -63,7 +64,7 @@ bool MWMechanics::AiAvoidDoor::execute (const MWWorld::Ptr& actor, CharacterCont std::vector actors; MWBase::Environment::get().getMechanicsManager()->getActorsInRange(pos.asVec3(),100,actors); for(std::vector::iterator it = actors.begin(); it != actors.end(); ++it) { - if(*it != MWBase::Environment::get().getWorld()->getPlayerPtr()) { //Not the player + if(*it != getPlayer()) { //Not the player MWMechanics::AiSequence& seq = it->getClass().getCreatureStats(*it).getAiSequence(); if(seq.getTypeId() != MWMechanics::AiPackage::TypeIdAvoidDoor) { //Only add it once seq.stack(MWMechanics::AiAvoidDoor(mDoorPtr),*it); diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index 1ab3264b7..2c8c57c56 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -15,6 +15,7 @@ #include "../mwworld/action.hpp" #include "steering.hpp" +#include "actorutil.hpp" MWMechanics::AiPackage::~AiPackage() {} @@ -34,7 +35,7 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, ESM::Pathgrid::Po /// Stops the actor when it gets too close to a unloaded cell const ESM::Cell *cell = actor.getCell()->getCell(); { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = getPlayer(); Movement &movement = actor.getClass().getMovementSettings(actor); //Ensure pursuer doesn't leave loaded cells diff --git a/apps/openmw/mwmechanics/aisequence.cpp b/apps/openmw/mwmechanics/aisequence.cpp index a750860ca..a1c5ab14f 100644 --- a/apps/openmw/mwmechanics/aisequence.cpp +++ b/apps/openmw/mwmechanics/aisequence.cpp @@ -12,6 +12,7 @@ #include "aiactivate.hpp" #include "aicombat.hpp" #include "aipursue.hpp" +#include "actorutil.hpp" #include @@ -150,7 +151,7 @@ bool AiSequence::isPackageDone() const void AiSequence::execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) { - if(actor != MWBase::Environment::get().getWorld()->getPlayerPtr()) + if(actor != getPlayer()) { if (!mPackages.empty()) { @@ -242,7 +243,7 @@ void AiSequence::clear() void AiSequence::stack (const AiPackage& package, const MWWorld::Ptr& actor) { - if (actor == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (actor == getPlayer()) throw std::runtime_error("Can't add AI packages to player"); if (package.getTypeId() == AiPackage::TypeIdCombat || package.getTypeId() == AiPackage::TypeIdPursue) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index afe34218e..f3f808a2e 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -21,6 +21,7 @@ #include "steering.hpp" #include "movement.hpp" #include "coordinateconverter.hpp" +#include "actorutil.hpp" @@ -462,7 +463,7 @@ namespace MWMechanics if (hello > 0 && !MWBase::Environment::get().getWorld()->isSwimming(actor) && MWBase::Environment::get().getSoundManager()->sayDone(actor)) { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = getPlayer(); static float fVoiceIdleOdds = MWBase::Environment::get().getWorld()->getStore() .get().find("fVoiceIdleOdds")->getFloat(); @@ -496,7 +497,7 @@ namespace MWMechanics helloDistance *= iGreetDistanceMultiplier; - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = getPlayer(); osg::Vec3f playerPos(player.getRefData().getPosition().asVec3()); osg::Vec3f actorPos(actor.getRefData().getPosition().asVec3()); float playerDistSqr = (playerPos - actorPos).length2(); diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 3959c413a..3837e9a75 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -27,6 +27,7 @@ #include "npcstats.hpp" #include "creaturestats.hpp" #include "security.hpp" +#include "actorutil.hpp" #include @@ -619,7 +620,7 @@ void CharacterController::playDeath(float startpoint, CharacterState death) void CharacterController::playRandomDeath(float startpoint) { - if (mPtr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (mPtr == getPlayer()) { // The first-person animations do not include death, so we need to // force-switch to third person before playing the death animation. @@ -1167,7 +1168,7 @@ bool CharacterController::updateWeaponState() // Unset casting flag, otherwise pressing the mouse button down would // continue casting every frame if there is no animation mAttackingOrSpell = false; - if (mPtr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (mPtr == getPlayer()) { MWBase::Environment::get().getWorld()->getPlayer().setAttackingOrSpell(false); } @@ -1177,7 +1178,7 @@ bool CharacterController::updateWeaponState() // For the player, set the spell we want to cast // This has to be done at the start of the casting animation, // *not* when selecting a spell in the GUI (otherwise you could change the spell mid-animation) - if (mPtr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (mPtr == getPlayer()) { std::string selectedSpell = MWBase::Environment::get().getWindowManager()->getSelectedSpell(); stats.getSpells().setSelectedSpell(selectedSpell); @@ -1257,7 +1258,7 @@ bool CharacterController::updateWeaponState() mAttackType = "shoot"; else { - if(isWeapon && mPtr == MWBase::Environment::get().getWorld()->getPlayerPtr() && + if(isWeapon && mPtr == getPlayer() && Settings::Manager::getBool("best attack", "Game")) { MWWorld::ContainerStoreIterator weapon = mPtr.getClass().getInventoryStore(mPtr).getSlot(MWWorld::InventoryStore::Slot_CarriedRight); @@ -1563,7 +1564,7 @@ void CharacterController::update(float duration) // advance athletics - if(mHasMovedInXY && mPtr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if(mHasMovedInXY && mPtr == getPlayer()) { if(inwater) { @@ -1664,7 +1665,7 @@ void CharacterController::update(float duration) } // advance acrobatics - if (mPtr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (mPtr == getPlayer()) cls.skillUsageSucceeded(mPtr, ESM::Skill::Acrobatics, 0); // decrease fatigue @@ -1707,7 +1708,7 @@ void CharacterController::update(float duration) else { // report acrobatics progression - if (mPtr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (mPtr == getPlayer()) cls.skillUsageSucceeded(mPtr, ESM::Skill::Acrobatics, 1); } } @@ -1949,7 +1950,7 @@ bool CharacterController::kill() { if( isDead() ) { - if( mPtr == MWBase::Environment::get().getWorld()->getPlayerPtr() && !isAnimPlaying(mCurrentDeath) ) + if( mPtr == getPlayer() && !isAnimPlaying(mCurrentDeath) ) { //player's death animation is over MWBase::Environment::get().getStateManager()->askLoadRecent(); @@ -1965,7 +1966,7 @@ bool CharacterController::kill() mCurrentIdle.clear(); // Play Death Music if it was the player dying - if(mPtr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if(mPtr == getPlayer()) MWBase::Environment::get().getSoundManager()->streamMusic("Special/MW_Death.mp3"); return true; @@ -2006,7 +2007,7 @@ void CharacterController::updateMagicEffects() float alpha = 1.f; if (mPtr.getClass().getCreatureStats(mPtr).getMagicEffects().get(ESM::MagicEffect::Invisibility).getMagnitude()) { - if (mPtr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (mPtr == getPlayer()) alpha = 0.4f; else alpha = 0.f; diff --git a/apps/openmw/mwmechanics/combat.cpp b/apps/openmw/mwmechanics/combat.cpp index 2e20d0e1f..f11e6bcfd 100644 --- a/apps/openmw/mwmechanics/combat.cpp +++ b/apps/openmw/mwmechanics/combat.cpp @@ -19,6 +19,7 @@ #include "../mwworld/esmstore.hpp" #include "../mwbase/windowmanager.hpp" +#include "actorutil.hpp" namespace { @@ -137,7 +138,7 @@ namespace MWMechanics blockerStats.setBlock(true); - if (blocker == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (blocker == getPlayer()) blocker.getClass().skillUsageSucceeded(blocker, ESM::Skill::Block, 0); return true; @@ -161,7 +162,7 @@ namespace MWMechanics && actor.getClass().isNpc() && actor.getClass().getNpcStats(actor).isWerewolf()) damage *= MWBase::Environment::get().getWorld()->getStore().get().find("fWereWolfSilverWeaponDamageMult")->getFloat(); - if (damage == 0 && attacker == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (damage == 0 && attacker == getPlayer()) MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicTargetResistsWeapons}"); } @@ -178,7 +179,7 @@ namespace MWMechanics return; } - if(attacker == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if(attacker == getPlayer()) MWBase::Environment::get().getWindowManager()->setEnemy(victim); int weapskill = ESM::Skill::Marksman; @@ -207,7 +208,7 @@ namespace MWMechanics adjustWeaponDamage(damage, weapon, attacker); reduceWeaponCondition(damage, true, weapon, attacker); - if(attacker == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if(attacker == getPlayer()) attacker.getClass().skillUsageSucceeded(attacker, weapskill, 0); if (victim.getClass().getCreatureStats(victim).getKnockedDown()) @@ -222,7 +223,7 @@ namespace MWMechanics MWBase::Environment::get().getWorld()->spawnBloodEffect(victim, hitPosition); // Non-enchanted arrows shot at enemies have a chance to turn up in their inventory - if (victim != MWBase::Environment::get().getWorld()->getPlayerPtr() + if (victim != getPlayer() && !appliedEnchantment) { float fProjectileThrownStoreChance = gmst.find("fProjectileThrownStoreChance")->getFloat(); @@ -247,7 +248,7 @@ namespace MWMechanics { // Maybe we should keep an aware state for actors updated every so often instead of testing every time bool unaware = (!victimStats.getAiSequence().isInCombat()) - && (attacker == MWBase::Environment::get().getWorld()->getPlayerPtr()) + && (attacker == getPlayer()) && (!MWBase::Environment::get().getMechanicsManager()->awarenessCheck(attacker, victim)); if (!(victimStats.getKnockedDown() || victimStats.isParalyzed() diff --git a/apps/openmw/mwmechanics/difficultyscaling.cpp b/apps/openmw/mwmechanics/difficultyscaling.cpp index 05ab12ccd..950fe33cf 100644 --- a/apps/openmw/mwmechanics/difficultyscaling.cpp +++ b/apps/openmw/mwmechanics/difficultyscaling.cpp @@ -6,9 +6,11 @@ #include +#include "actorutil.hpp" + float scaleDamage(float damage, const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim) { - const MWWorld::Ptr& player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + const MWWorld::Ptr& player = MWMechanics::getPlayer(); // [-100, 100] int difficultySetting = Settings::Manager::getInt("difficulty", "Game"); diff --git a/apps/openmw/mwmechanics/disease.hpp b/apps/openmw/mwmechanics/disease.hpp index cf21f3806..27c19364f 100644 --- a/apps/openmw/mwmechanics/disease.hpp +++ b/apps/openmw/mwmechanics/disease.hpp @@ -9,8 +9,10 @@ #include "../mwworld/ptr.hpp" #include "../mwworld/class.hpp" #include "../mwworld/esmstore.hpp" -#include "../mwmechanics/spells.hpp" -#include "../mwmechanics/creaturestats.hpp" +#include "spells.hpp" +#include "creaturestats.hpp" +#include "actorutil.hpp" + namespace MWMechanics { @@ -20,7 +22,7 @@ namespace MWMechanics /// @param carrier The disease carrier. inline void diseaseContact (MWWorld::Ptr actor, MWWorld::Ptr carrier) { - if (!carrier.getClass().isActor() || actor != MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (!carrier.getClass().isActor() || actor != getPlayer()) return; float fDiseaseXferChance = diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp index 2cb963e28..102e3787a 100644 --- a/apps/openmw/mwmechanics/enchanting.cpp +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -11,6 +11,7 @@ #include "creaturestats.hpp" #include "npcstats.hpp" #include "spellcasting.hpp" +#include "actorutil.hpp" namespace MWMechanics { @@ -54,7 +55,7 @@ namespace MWMechanics bool Enchanting::create() { - const MWWorld::Ptr& player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + const MWWorld::Ptr& player = getPlayer(); MWWorld::ContainerStore& store = player.getClass().getContainerStore(player); ESM::Enchantment enchantment; enchantment.mData.mCharge = getGemCharge(); @@ -217,7 +218,7 @@ namespace MWMechanics int Enchanting::getEffectiveCastCost() const { int baseCost = getBaseCastCost(); - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = getPlayer(); return getEffectiveEnchantmentCastCost(static_cast(baseCost), player); } @@ -291,7 +292,7 @@ namespace MWMechanics void Enchanting::payForEnchantment() const { - const MWWorld::Ptr& player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + const MWWorld::Ptr& player = getPlayer(); MWWorld::ContainerStore& store = player.getClass().getContainerStore(player); store.remove(MWWorld::ContainerStore::sGoldId, getEnchantPrice(), player); diff --git a/apps/openmw/mwmechanics/levelledlist.hpp b/apps/openmw/mwmechanics/levelledlist.hpp index f2f0c7cab..edfef5358 100644 --- a/apps/openmw/mwmechanics/levelledlist.hpp +++ b/apps/openmw/mwmechanics/levelledlist.hpp @@ -11,7 +11,8 @@ #include "../mwworld/class.hpp" #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" -#include "../mwmechanics/creaturestats.hpp" +#include "creaturestats.hpp" +#include "actorutil.hpp" namespace MWMechanics { @@ -21,7 +22,7 @@ namespace MWMechanics { const std::vector& items = levItem->mList; - const MWWorld::Ptr& player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + const MWWorld::Ptr& player = getPlayer(); int playerLevel = player.getClass().getCreatureStats(player).getLevel(); failChance += levItem->mChanceNone; diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 075747ffe..711ecdbd2 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -26,6 +26,7 @@ #include "spellcasting.hpp" #include "autocalcspell.hpp" #include "npcstats.hpp" +#include "actorutil.hpp" namespace { @@ -83,7 +84,7 @@ namespace MWMechanics { void MechanicsManager::buildPlayer() { - MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr ptr = getPlayer(); MWMechanics::CreatureStats& creatureStats = ptr.getClass().getCreatureStats (ptr); MWMechanics::NpcStats& npcStats = ptr.getClass().getNpcStats (ptr); @@ -361,7 +362,7 @@ namespace MWMechanics { // Uses ingame time, but scaled to real time duration /= MWBase::Environment::get().getWorld()->getTimeScaleFactor(); - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = getPlayer(); player.getClass().getInventoryStore(player).rechargeItems(duration); } @@ -489,7 +490,7 @@ namespace MWMechanics // HACK? The player has been changed, so a new Animation object may // have been made for them. Make sure they're properly updated. - MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr ptr = getPlayer(); mActors.removeActor(ptr); mActors.addActor(ptr, true); } @@ -586,7 +587,7 @@ namespace MWMechanics float x = static_cast(npcSkill.getBaseDisposition()); MWWorld::LiveCellRef* npc = ptr.get(); - MWWorld::Ptr playerPtr = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr playerPtr = getPlayer(); MWWorld::LiveCellRef* player = playerPtr.get(); const MWMechanics::NpcStats &playerStats = playerPtr.getClass().getNpcStats(playerPtr); @@ -663,7 +664,7 @@ namespace MWMechanics const MWMechanics::NpcStats &sellerStats = ptr.getClass().getNpcStats(ptr); - MWWorld::Ptr playerPtr = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr playerPtr = getPlayer(); const MWMechanics::NpcStats &playerStats = playerPtr.getClass().getNpcStats(playerPtr); // I suppose the temporary disposition change _has_ to be considered here, @@ -707,7 +708,7 @@ namespace MWMechanics MWMechanics::NpcStats& npcStats = npc.getClass().getNpcStats(npc); - MWWorld::Ptr playerPtr = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr playerPtr = getPlayer(); const MWMechanics::NpcStats &playerStats = playerPtr.getClass().getNpcStats(playerPtr); float npcRating1, npcRating2, npcRating3; @@ -1010,7 +1011,7 @@ namespace MWMechanics void MechanicsManager::itemTaken(const MWWorld::Ptr &ptr, const MWWorld::Ptr &item, const MWWorld::Ptr& container, int count) { - if (ptr != MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (ptr != getPlayer()) return; MWWorld::Ptr victim; @@ -1067,7 +1068,7 @@ namespace MWMechanics // NOTE: victim may be empty // Only player can commit crime - if (player != MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (player != getPlayer()) return false; // Find all the actors within the alarm radius @@ -1306,7 +1307,7 @@ namespace MWMechanics bool MechanicsManager::actorAttacked(const MWWorld::Ptr &ptr, const MWWorld::Ptr &attacker) { - if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (ptr == getPlayer()) return false; std::list followers = getActorsFollowing(attacker); @@ -1340,7 +1341,7 @@ namespace MWMechanics commitCrime(attacker, ptr, MWBase::MechanicsManager::OT_Assault); if (!attacker.isEmpty() && (attacker.getClass().getCreatureStats(attacker).getAiSequence().isInCombat(ptr) - || attacker == MWBase::Environment::get().getWorld()->getPlayerPtr()) + || attacker == getPlayer()) && !seq.isInCombat(attacker)) { // Attacker is in combat with us, but we are not in combat with the attacker yet. Time to fight back. @@ -1353,7 +1354,7 @@ namespace MWMechanics void MechanicsManager::actorKilled(const MWWorld::Ptr &victim, const MWWorld::Ptr &attacker) { - if (attacker.isEmpty() || attacker != MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (attacker.isEmpty() || attacker != getPlayer()) return; if (victim == attacker) @@ -1450,7 +1451,7 @@ namespace MWMechanics if (ptr.getClass().getCreatureStats(ptr).getAiSequence().isInCombat(target)) return; ptr.getClass().getCreatureStats(ptr).getAiSequence().stack(MWMechanics::AiCombat(target), ptr); - if (target == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (target == getPlayer()) { // if guard starts combat with player, guards pursuing player should do the same if (ptr.getClass().isClass(ptr, "Guard")) @@ -1547,7 +1548,7 @@ namespace MWMechanics if (ptr.getClass().isNpc() && target.getClass().isNpc()) { if (target.getClass().getNpcStats(target).isWerewolf() || - (target == MWBase::Environment::get().getWorld()->getPlayerPtr() && + (target == getPlayer() && MWBase::Environment::get().getWorld()->getGlobalInt("pcknownwerewolf"))) { const ESM::GameSetting * iWerewolfFightMod = MWBase::Environment::get().getWorld()->getStore().get().search("iWerewolfFightMod"); @@ -1560,7 +1561,7 @@ namespace MWMechanics void MechanicsManager::keepPlayerAlive() { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = getPlayer(); CreatureStats& stats = player.getClass().getCreatureStats(player); if (stats.isDead()) { diff --git a/apps/openmw/mwmechanics/repair.cpp b/apps/openmw/mwmechanics/repair.cpp index fa429bbee..581ba3a84 100644 --- a/apps/openmw/mwmechanics/repair.cpp +++ b/apps/openmw/mwmechanics/repair.cpp @@ -14,15 +14,16 @@ #include "../mwworld/class.hpp" #include "../mwworld/esmstore.hpp" -#include "../mwmechanics/creaturestats.hpp" -#include "../mwmechanics/npcstats.hpp" +#include "creaturestats.hpp" +#include "npcstats.hpp" +#include "actorutil.hpp" namespace MWMechanics { void Repair::repair(const MWWorld::Ptr &itemToRepair) { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = getPlayer(); MWWorld::LiveCellRef *ref = mTool.get(); @@ -82,7 +83,7 @@ void Repair::repair(const MWWorld::Ptr &itemToRepair) // tool used up? if (mTool.getCellRef().getCharge() == 0) { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = getPlayer(); MWWorld::ContainerStore& store = player.getClass().getContainerStore(player); store.remove(mTool, 1, player); diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 12ed04428..cbd0b8731 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -26,6 +26,7 @@ #include "magiceffects.hpp" #include "npcstats.hpp" #include "summoning.hpp" +#include "actorutil.hpp" namespace { @@ -133,7 +134,7 @@ namespace MWMechanics int actorLuck = stats.getAttribute(ESM::Attribute::Luck).getModified(); float castChance = (lowestSkill - spell->mData.mCost + castBonus + 0.2f * actorWillpower + 0.1f * actorLuck) * stats.getFatigueTerm(); - if (MWBase::Environment::get().getWorld()->getGodModeState() && actor == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (MWBase::Environment::get().getWorld()->getGodModeState() && actor == getPlayer()) castChance = 100; if (!cap) @@ -340,7 +341,7 @@ namespace MWMechanics if (Misc::Rng::roll0to99() <= x) { // Fully resisted, show message - if (target == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (target == getPlayer()) MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicPCResisted}"); return; } @@ -358,7 +359,7 @@ namespace MWMechanics if (target.getClass().isActor()) targetEffects += target.getClass().getCreatureStats(target).getMagicEffects(); - bool castByPlayer = (!caster.isEmpty() && caster == MWBase::Environment::get().getWorld()->getPlayerPtr()); + bool castByPlayer = (!caster.isEmpty() && caster == getPlayer()); // Try absorbing if it's a spell // NOTE: Vanilla does this once per effect source instead of adding the % from all sources together, not sure @@ -433,7 +434,7 @@ namespace MWMechanics if (magnitudeMult == 0) { // Fully resisted, show message - if (target == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (target == getPlayer()) MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicPCResisted}"); else if (castByPlayer) MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicTargetResisted}"); @@ -569,7 +570,7 @@ namespace MWMechanics { if (target.getCellRef().getLockLevel() < magnitude) //If the door is not already locked to a higher value, lock it to spell magnitude { - if (caster == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (caster == getPlayer()) MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicLockSuccess}"); target.getClass().lock(target, static_cast(magnitude)); } @@ -585,7 +586,7 @@ namespace MWMechanics if (!caster.isEmpty() && caster.getClass().isActor()) MWBase::Environment::get().getMechanicsManager()->objectOpened(caster, target); - if (caster == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (caster == getPlayer()) MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicOpenSuccess}"); } target.getClass().unlock(target); @@ -622,7 +623,7 @@ namespace MWMechanics return true; } - if (target != MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (target != getPlayer()) return false; if (effectId == ESM::MagicEffect::DivineIntervention) @@ -701,7 +702,7 @@ namespace MWMechanics if (item.getCellRef().getEnchantmentCharge() < castCost) { - if (mCaster == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (mCaster == getPlayer()) MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicInsufficientCharge}"); // Failure sound @@ -725,14 +726,14 @@ namespace MWMechanics if (enchantment->mData.mType == ESM::Enchantment::WhenUsed) { - if (mCaster == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (mCaster == getPlayer()) mCaster.getClass().skillUsageSucceeded (mCaster, ESM::Skill::Enchant, 1); } if (enchantment->mData.mType == ESM::Enchantment::CastOnce) item.getContainerStore()->remove(item, 1, mCaster); else if (enchantment->mData.mType != ESM::Enchantment::WhenStrikes) { - if (mCaster == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (mCaster == getPlayer()) { mCaster.getClass().skillUsageSucceeded (mCaster, ESM::Skill::Enchant, 3); } @@ -799,7 +800,7 @@ namespace MWMechanics float successChance = getSpellSuccessChance(spell, mCaster); if (Misc::Rng::roll0to99() >= successChance) { - if (mCaster == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (mCaster == getPlayer()) MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicSkillFail}"); fail = true; } @@ -817,7 +818,7 @@ namespace MWMechanics } } - if (mCaster == MWBase::Environment::get().getWorld()->getPlayerPtr() && spellIncreasesSkill(spell)) + if (mCaster == getPlayer() && spellIncreasesSkill(spell)) mCaster.getClass().skillUsageSucceeded(mCaster, spellSchoolToSkill(school), 0); @@ -962,7 +963,7 @@ namespace MWMechanics if (charge == 0) { // Will unequip the broken item and try to find a replacement - if (ptr != MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (ptr != getPlayer()) inv.autoEquip(ptr); else inv.unequipItem(*item, ptr); @@ -1097,7 +1098,7 @@ namespace MWMechanics } - if (receivedMagicDamage && actor == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (receivedMagicDamage && actor == getPlayer()) MWBase::Environment::get().getWindowManager()->activateHitOverlay(false); } diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 2cb261851..77e2f6803 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -30,6 +30,7 @@ #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/movement.hpp" +#include "../mwmechanics/actorutil.hpp" #include "../mwworld/esmstore.hpp" #include "../mwworld/cellstore.hpp" @@ -1091,7 +1092,7 @@ namespace MWPhysics bool PhysicsSystem::toggleCollisionMode() { - ActorMap::iterator found = mActors.find(MWBase::Environment::get().getWorld()->getPlayerPtr()); + ActorMap::iterator found = mActors.find(MWMechanics::getPlayer()); if (found != mActors.end()) { bool cmode = found->second->getCollisionMode(); diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index b4e1189f7..93afeda25 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -17,6 +17,8 @@ #include "../mwworld/class.hpp" #include "../mwworld/inventorystore.hpp" +#include "../mwmechanics/actorutil.hpp" + #include "npcanimation.hpp" #include "vismask.hpp" @@ -295,7 +297,7 @@ namespace MWRender // -------------------------------------------------------------------------------------------------- RaceSelectionPreview::RaceSelectionPreview(osgViewer::Viewer* viewer, Resource::ResourceSystem* resourceSystem) - : CharacterPreview(viewer, resourceSystem, MWBase::Environment::get().getWorld()->getPlayerPtr(), + : CharacterPreview(viewer, resourceSystem, MWMechanics::getPlayer(), 512, 512, osg::Vec3f(0, 125, 8), osg::Vec3f(0,0,8)) , mBase (*mCharacter.get()->mBase) , mRef(&mBase) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index c5a107837..66a3d3ec6 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -21,6 +21,7 @@ #include "../mwworld/class.hpp" #include "../mwmechanics/npcstats.hpp" +#include "../mwmechanics/actorutil.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -1039,7 +1040,7 @@ void NpcAnimation::setVampire(bool vampire) return; if ((mNpcType == Type_Vampire) != vampire) { - if (mPtr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (mPtr == MWMechanics::getPlayer()) MWBase::Environment::get().getWorld()->reattachPlayerCamera(); else rebuild(); diff --git a/apps/openmw/mwrender/ripplesimulation.cpp b/apps/openmw/mwrender/ripplesimulation.cpp index a3e96a5b1..a7637f2e1 100644 --- a/apps/openmw/mwrender/ripplesimulation.cpp +++ b/apps/openmw/mwrender/ripplesimulation.cpp @@ -22,6 +22,8 @@ #include "../mwworld/fallback.hpp" +#include "../mwmechanics/actorutil.hpp" + namespace { void createWaterRippleStateSet(Resource::ResourceSystem* resourceSystem, const MWWorld::Fallback* fallback, osg::Node* node) @@ -177,7 +179,7 @@ void RippleSimulation::removeCell(const MWWorld::CellStore *store) { for (std::vector::iterator it = mEmitters.begin(); it != mEmitters.end();) { - if (it->mPtr.getCell() == store && it->mPtr != MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (it->mPtr.getCell() == store && it->mPtr != MWMechanics::getPlayer()) { it = mEmitters.erase(it); } diff --git a/apps/openmw/mwscript/cellextensions.cpp b/apps/openmw/mwscript/cellextensions.cpp index 8af2e5ef3..5dd3cf411 100644 --- a/apps/openmw/mwscript/cellextensions.cpp +++ b/apps/openmw/mwscript/cellextensions.cpp @@ -16,6 +16,8 @@ #include "../mwworld/player.hpp" #include "../mwworld/cellstore.hpp" +#include "../mwmechanics/actorutil.hpp" + #include "interpretercontext.hpp" namespace MWScript @@ -91,14 +93,14 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { - if (!MWBase::Environment::get().getWorld()->getPlayerPtr().isInCell()) + if (!MWMechanics::getPlayer().isInCell()) { runtime.push (0); return; } bool interior = - !MWBase::Environment::get().getWorld()->getPlayerPtr().getCell()->getCell()->isExterior(); + !MWMechanics::getPlayer().getCell()->getCell()->isExterior(); runtime.push (interior ? 1 : 0); } @@ -113,12 +115,12 @@ namespace MWScript std::string name = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); - if (!MWBase::Environment::get().getWorld()->getPlayerPtr().isInCell()) + if (!MWMechanics::getPlayer().isInCell()) { runtime.push(0); return; } - const MWWorld::CellStore *cell = MWBase::Environment::get().getWorld()->getPlayerPtr().getCell(); + const MWWorld::CellStore *cell = MWMechanics::getPlayer().getCell(); std::string current = MWBase::Environment::get().getWorld()->getCellName(cell); Misc::StringUtils::toLower(current); @@ -136,12 +138,12 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { - if (!MWBase::Environment::get().getWorld()->getPlayerPtr().isInCell()) + if (!MWMechanics::getPlayer().isInCell()) { runtime.push(0.f); return; } - MWWorld::CellStore *cell = MWBase::Environment::get().getWorld()->getPlayerPtr().getCell(); + MWWorld::CellStore *cell = MWMechanics::getPlayer().getCell(); if (cell->getCell()->hasWater()) runtime.push (cell->getWaterLevel()); else @@ -157,12 +159,12 @@ namespace MWScript { Interpreter::Type_Float level = runtime[0].mFloat; - if (!MWBase::Environment::get().getWorld()->getPlayerPtr().isInCell()) + if (!MWMechanics::getPlayer().isInCell()) { return; } - MWWorld::CellStore *cell = MWBase::Environment::get().getWorld()->getPlayerPtr().getCell(); + MWWorld::CellStore *cell = MWMechanics::getPlayer().getCell(); if (cell->getCell()->isExterior()) throw std::runtime_error("Can't set water level in exterior cell"); @@ -180,12 +182,12 @@ namespace MWScript { Interpreter::Type_Float level = runtime[0].mFloat; - if (!MWBase::Environment::get().getWorld()->getPlayerPtr().isInCell()) + if (!MWMechanics::getPlayer().isInCell()) { return; } - MWWorld::CellStore *cell = MWBase::Environment::get().getWorld()->getPlayerPtr().getCell(); + MWWorld::CellStore *cell = MWMechanics::getPlayer().getCell(); if (cell->getCell()->isExterior()) throw std::runtime_error("Can't set water level in exterior cell"); diff --git a/apps/openmw/mwscript/containerextensions.cpp b/apps/openmw/mwscript/containerextensions.cpp index 674973978..20ca2b580 100644 --- a/apps/openmw/mwscript/containerextensions.cpp +++ b/apps/openmw/mwscript/containerextensions.cpp @@ -26,6 +26,8 @@ #include "../mwworld/actionequip.hpp" #include "../mwworld/inventorystore.hpp" +#include "../mwmechanics/actorutil.hpp" + #include "interpretercontext.hpp" #include "ref.hpp" @@ -147,7 +149,7 @@ namespace MWScript // Spawn a messagebox (only for items removed from player's inventory) if ((numRemoved > 0) - && (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr())) + && (ptr == MWMechanics::getPlayer())) { // The two GMST entries below expand to strings informing the player of what, and how many of it has been removed from their inventory std::string msgBox; @@ -192,7 +194,7 @@ namespace MWScript MWWorld::ActionEquip action (*it); action.execute(ptr); - if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr() && !ptr.getClass().getScript(ptr).empty()) + if (ptr == MWMechanics::getPlayer() && !ptr.getClass().getScript(ptr).empty()) ptr.getRefData().getLocals().setVarByInt(ptr.getClass().getScript(ptr), "onpcequip", 1); } }; diff --git a/apps/openmw/mwscript/guiextensions.cpp b/apps/openmw/mwscript/guiextensions.cpp index f48360c04..397e0cac5 100644 --- a/apps/openmw/mwscript/guiextensions.cpp +++ b/apps/openmw/mwscript/guiextensions.cpp @@ -14,6 +14,8 @@ #include "../mwbase/world.hpp" #include "../mwbase/mechanicsmanager.hpp" +#include "../mwmechanics/actorutil.hpp" + #include "interpretercontext.hpp" #include "ref.hpp" @@ -53,7 +55,7 @@ namespace MWScript { MWWorld::Ptr bed = R()(runtime, false); - if (bed.isEmpty() || !MWBase::Environment::get().getMechanicsManager()->sleepInBed(MWBase::Environment::get().getWorld()->getPlayerPtr(), + if (bed.isEmpty() || !MWBase::Environment::get().getMechanicsManager()->sleepInBed(MWMechanics::getPlayer(), bed)) MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_RestBed); } diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index faf574993..32d86f55a 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -27,6 +27,7 @@ #include "../mwmechanics/npcstats.hpp" #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/spellcasting.hpp" +#include "../mwmechanics/actorutil.hpp" #include "interpretercontext.hpp" #include "ref.hpp" @@ -156,7 +157,7 @@ namespace MWScript MWWorld::Ptr ptr = R()(runtime); - context.executeActivation(ptr, MWBase::Environment::get().getWorld()->getPlayerPtr()); + context.executeActivation(ptr, MWMechanics::getPlayer()); } }; @@ -976,7 +977,7 @@ namespace MWScript public: virtual void execute(Interpreter::Runtime &runtime) { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); player.getClass().getNpcStats(player).setBounty(0); MWBase::Environment::get().getWorld()->confiscateStolenItems(player); MWBase::Environment::get().getWorld()->getPlayer().recordCrimeId(); @@ -988,7 +989,7 @@ namespace MWScript public: virtual void execute(Interpreter::Runtime &runtime) { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); player.getClass().getNpcStats(player).setBounty(0); MWBase::Environment::get().getWorld()->getPlayer().recordCrimeId(); } diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index 112e7c77f..4debb24fe 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -25,6 +25,7 @@ #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/npcstats.hpp" +#include "../mwmechanics/actorutil.hpp" #include "interpretercontext.hpp" #include "ref.hpp" @@ -460,7 +461,7 @@ namespace MWScript MWBase::WindowManager *wm = MWBase::Environment::get().getWindowManager(); - if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr() && + if (ptr == MWMechanics::getPlayer() && id == wm->getSelectedSpell()) { wm->unsetSelectedSpell(); @@ -548,7 +549,7 @@ namespace MWScript if(factionID != "") { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); player.getClass().getNpcStats(player).joinFaction(factionID); } } @@ -580,7 +581,7 @@ namespace MWScript if(factionID != "") { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); if(player.getClass().getNpcStats(player).getFactionRanks().find(factionID) == player.getClass().getNpcStats(player).getFactionRanks().end()) { player.getClass().getNpcStats(player).joinFaction(factionID); @@ -619,7 +620,7 @@ namespace MWScript if(factionID != "") { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); player.getClass().getNpcStats(player).lowerRank(factionID); } } @@ -648,7 +649,7 @@ namespace MWScript // Make sure this faction exists MWBase::Environment::get().getWorld()->getStore().get().find(factionID); - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); if(factionID!="") { if(player.getClass().getNpcStats(player).getFactionRanks().find(factionID) != player.getClass().getNpcStats(player).getFactionRanks().end()) @@ -757,7 +758,7 @@ namespace MWScript ::Misc::StringUtils::toLower (factionId); - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); runtime.push ( player.getClass().getNpcStats (player).getFactionReputation (factionId)); } @@ -792,7 +793,7 @@ namespace MWScript ::Misc::StringUtils::toLower (factionId); - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); player.getClass().getNpcStats (player).setFactionReputation (factionId, value); } }; @@ -826,7 +827,7 @@ namespace MWScript ::Misc::StringUtils::toLower (factionId); - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); player.getClass().getNpcStats (player).setFactionReputation (factionId, player.getClass().getNpcStats (player).getFactionReputation (factionId)+ value); @@ -911,7 +912,7 @@ namespace MWScript factionID = ptr.getClass().getPrimaryFaction(ptr); } ::Misc::StringUtils::toLower(factionID); - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); if(factionID!="") { runtime.push(player.getClass().getNpcStats(player).getExpelled(factionID)); @@ -942,7 +943,7 @@ namespace MWScript { factionID = ptr.getClass().getPrimaryFaction(ptr); } - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); if(factionID!="") { player.getClass().getNpcStats(player).expell(factionID); @@ -969,7 +970,7 @@ namespace MWScript { factionID = ptr.getClass().getPrimaryFaction(ptr); } - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); if(factionID!="") player.getClass().getNpcStats(player).clearExpelled(factionID); } @@ -988,7 +989,7 @@ namespace MWScript if(factionID.empty()) return; - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); // no-op when executed on the player if (ptr == player) @@ -1011,7 +1012,7 @@ namespace MWScript if(factionID.empty()) return; - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); // no-op when executed on the player if (ptr == player) @@ -1120,7 +1121,7 @@ namespace MWScript { MWWorld::Ptr ptr = R()(runtime); - if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (ptr == MWMechanics::getPlayer()) ptr.getClass().getCreatureStats(ptr).resurrect(); else if (ptr.getClass().getCreatureStats(ptr).isDead()) { diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 0f9faa11a..679a8d2de 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -20,6 +20,8 @@ #include "../mwworld/player.hpp" #include "../mwworld/esmstore.hpp" +#include "../mwmechanics/actorutil.hpp" + #include "interpretercontext.hpp" #include "ref.hpp" @@ -214,7 +216,7 @@ namespace MWScript if (!ptr.isInCell()) return; - if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (ptr == MWMechanics::getPlayer()) { MWBase::Environment::get().getWorld()->getPlayer().setTeleported(true); } @@ -289,7 +291,7 @@ namespace MWScript if (ptr.getContainerStore()) return; - if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (ptr == MWMechanics::getPlayer()) { MWBase::Environment::get().getWorld()->getPlayer().setTeleported(true); } @@ -333,7 +335,7 @@ namespace MWScript // Note that you must specify ZRot in minutes (1 degree = 60 minutes; north = 0, east = 5400, south = 10800, west = 16200) // except for when you position the player, then degrees must be used. // See "Morrowind Scripting for Dummies (9th Edition)" pages 50 and 54 for reference. - if(ptr != MWBase::Environment::get().getWorld()->getPlayerPtr()) + if(ptr != MWMechanics::getPlayer()) zRot = zRot/60.0f; MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay,zRot); @@ -354,7 +356,7 @@ namespace MWScript if (!ptr.isInCell()) return; - if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (ptr == MWMechanics::getPlayer()) { MWBase::Environment::get().getWorld()->getPlayer().setTeleported(true); } @@ -372,7 +374,7 @@ namespace MWScript // another morrowind oddity: player will be moved to the exterior cell at this location, // non-player actors will move within the cell they are in. - if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (ptr == MWMechanics::getPlayer()) { MWWorld::CellStore* cell = MWBase::Environment::get().getWorld()->getExterior(cx,cy); MWBase::Environment::get().getWorld()->moveObject(ptr,cell,x,y,z); @@ -389,7 +391,7 @@ namespace MWScript // Note that you must specify ZRot in minutes (1 degree = 60 minutes; north = 0, east = 5400, south = 10800, west = 16200) // except for when you position the player, then degrees must be used. // See "Morrowind Scripting for Dummies (9th Edition)" pages 50 and 54 for reference. - if(ptr != MWBase::Environment::get().getWorld()->getPlayerPtr()) + if(ptr != MWMechanics::getPlayer()) zRot = zRot/60.0f; MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay,zRot); ptr.getClass().adjustPosition(ptr, false); @@ -469,7 +471,7 @@ namespace MWScript Interpreter::Type_Float zRot = runtime[0].mFloat; runtime.pop(); - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); MWWorld::CellStore* store = NULL; if (player.getCell()->isExterior()) { @@ -501,7 +503,7 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { MWWorld::Ptr actor = pc - ? MWBase::Environment::get().getWorld()->getPlayerPtr() + ? MWMechanics::getPlayer() : R()(runtime); std::string itemID = runtime.getStringLiteral (runtime[0].mInteger); diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 1f73fc1fc..bc97f1601 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -15,6 +15,8 @@ #include "../mwworld/esmstore.hpp" #include "../mwworld/cellstore.hpp" +#include "../mwmechanics/actorutil.hpp" + #include "sound_output.hpp" #include "sound_decoder.hpp" #include "sound.hpp" @@ -490,7 +492,7 @@ namespace MWSound while(snditer != mActiveSounds.end()) { if(snditer->second.first != MWWorld::Ptr() && - snditer->second.first != MWBase::Environment::get().getWorld()->getPlayerPtr() && + snditer->second.first != MWMechanics::getPlayer() && snditer->second.first.getCell() == cell) { snditer->first->stop(); @@ -735,7 +737,7 @@ namespace MWSound mListenerUp = up; MWWorld::Ptr player = - MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWMechanics::getPlayer(); const MWWorld::CellStore *cell = player.getCell(); mListenerUnderwater = ((cell->getCell()->mData.mFlags&ESM::Cell::HasWater) && mListenerPos.z() < cell->getWaterLevel()); diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index f4a7ee9f2..6995e24be 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -36,6 +36,7 @@ #include "../mwmechanics/npcstats.hpp" #include "../mwmechanics/creaturestats.hpp" +#include "../mwmechanics/actorutil.hpp" #include "../mwscript/globalscripts.hpp" @@ -472,7 +473,7 @@ void MWState::StateManager::loadGame (const Character *character, const std::str if (firstPersonCam != MWBase::Environment::get().getWorld()->isFirstPerson()) MWBase::Environment::get().getWorld()->togglePOV(); - MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr ptr = MWMechanics::getPlayer(); ESM::CellId cellId = ptr.getCell()->getCell()->getCellId(); @@ -519,7 +520,7 @@ void MWState::StateManager::deleteGame(const MWState::Character *character, cons MWState::Character *MWState::StateManager::getCurrentCharacter (bool create) { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); std::string name = player.get()->mBase->mName; return mCharacterManager.getCurrentCharacter (create, name); diff --git a/apps/openmw/mwworld/action.cpp b/apps/openmw/mwworld/action.cpp index fb2059de9..6361b3404 100644 --- a/apps/openmw/mwworld/action.cpp +++ b/apps/openmw/mwworld/action.cpp @@ -5,6 +5,8 @@ #include "../mwbase/soundmanager.hpp" +#include "../mwmechanics/actorutil.hpp" + const MWWorld::Ptr& MWWorld::Action::getTarget() const { return mTarget; @@ -19,7 +21,7 @@ void MWWorld::Action::execute (const Ptr& actor) { if (!mSoundId.empty()) { - if (mKeepSound && actor == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (mKeepSound && actor == MWMechanics::getPlayer()) MWBase::Environment::get().getSoundManager()->playSound(mSoundId, 1.0, 1.0, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_Normal,mSoundOffset); else diff --git a/apps/openmw/mwworld/actionequip.cpp b/apps/openmw/mwworld/actionequip.cpp index 87a4c6308..147f22963 100644 --- a/apps/openmw/mwworld/actionequip.cpp +++ b/apps/openmw/mwworld/actionequip.cpp @@ -4,6 +4,8 @@ #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwmechanics/actorutil.hpp" + #include #include "inventorystore.hpp" @@ -24,7 +26,7 @@ namespace MWWorld std::pair result = object.getClass().canBeEquipped (object, actor); // display error message if the player tried to equip something - if (!result.second.empty() && actor == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (!result.second.empty() && actor == MWMechanics::getPlayer()) MWBase::Environment::get().getWindowManager()->messageBox(result.second); switch(result.first) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 05ae4f134..8c6f7d259 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -11,6 +11,7 @@ #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/levelledlist.hpp" +#include "../mwmechanics/actorutil.hpp" #include "manualref.hpp" #include "refdata.hpp" @@ -209,7 +210,7 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add(const std::string & { MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), id, count); // a bit pointless to set owner for the player - if (actorPtr != MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (actorPtr != MWMechanics::getPlayer()) return add(ref.getPtr(), count, actorPtr, true); else return add(ref.getPtr(), count, actorPtr, false); @@ -224,7 +225,7 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& itemPtr // HACK: Set owner on the original item, then reset it after we have copied it // If we set the owner on the copied item, it would not stack correctly... std::string oldOwner = itemPtr.getCellRef().getOwner(); - if (!setOwner || actorPtr == MWBase::Environment::get().getWorld()->getPlayerPtr()) // No point in setting owner to the player - NPCs will not respect this anyway + if (!setOwner || actorPtr == MWMechanics::getPlayer()) // No point in setting owner to the player - NPCs will not respect this anyway { itemPtr.getCellRef().setOwner(""); } diff --git a/apps/openmw/mwworld/failedaction.cpp b/apps/openmw/mwworld/failedaction.cpp index cf5a2a5c2..49ca9dae0 100644 --- a/apps/openmw/mwworld/failedaction.cpp +++ b/apps/openmw/mwworld/failedaction.cpp @@ -4,6 +4,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwmechanics/actorutil.hpp" namespace MWWorld { @@ -13,7 +14,7 @@ namespace MWWorld void FailedAction::executeImp(const Ptr &actor) { - if(actor == MWBase::Environment::get().getWorld()->getPlayerPtr() && !mMessage.empty()) + if(actor == MWMechanics::getPlayer() && !mMessage.empty()) MWBase::Environment::get().getWindowManager()->messageBox(mMessage); } } diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 2dbc22234..0755c1555 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -16,6 +16,7 @@ #include "../mwmechanics/npcstats.hpp" #include "../mwmechanics/spellcasting.hpp" +#include "../mwmechanics/actorutil.hpp" #include "esmstore.hpp" @@ -136,7 +137,7 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::add(const Ptr& itemPtr, const MWWorld::ContainerStoreIterator& retVal = MWWorld::ContainerStore::add(itemPtr, count, actorPtr, setOwner); // Auto-equip items if an armor/clothing or weapon item is added, but not for the player nor werewolves - if (actorPtr != MWBase::Environment::get().getWorld()->getPlayerPtr() + if (actorPtr != MWMechanics::getPlayer() && !(actorPtr.getClass().isNpc() && actorPtr.getClass().getNpcStats(actorPtr).isWerewolf())) { std::string type = itemPtr.getTypeName(); @@ -508,7 +509,7 @@ int MWWorld::InventoryStore::remove(const Ptr& item, int count, const Ptr& actor // If an armor/clothing item is removed, try to find a replacement, // but not for the player nor werewolves. - if (wasEquipped && (actor != MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (wasEquipped && (actor != MWMechanics::getPlayer()) && !(actor.getClass().isNpc() && actor.getClass().getNpcStats(actor).isWerewolf())) { std::string type = item.getTypeName(); @@ -540,7 +541,7 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::unequipSlot(int slot, c { retval = restack(*it); - if (actor == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (actor == MWMechanics::getPlayer()) { // Unset OnPCEquip Variable on item's script, if it has a script with that variable declared const std::string& script = it->getClass().getScript(*it); @@ -595,7 +596,7 @@ void MWWorld::InventoryStore::fireEquipmentChangedEvent(const Ptr& actor) // if player, update inventory window /* - if (actor == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (actor == MWMechanics::getPlayer()) { MWBase::Environment::get().getWindowManager()->getInventoryWindow()->updateItemView(); } diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 6295ed159..3e9f17278 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -20,6 +20,7 @@ #include "../mwmechanics/combat.hpp" #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/spellcasting.hpp" +#include "../mwmechanics/actorutil.hpp" #include "../mwrender/effectmanager.hpp" #include "../mwrender/animation.hpp" @@ -187,7 +188,7 @@ namespace MWWorld } // Explodes when hitting water - if (MWBase::Environment::get().getWorld()->isUnderwater(MWBase::Environment::get().getWorld()->getPlayerPtr().getCell(), newPos)) + if (MWBase::Environment::get().getWorld()->isUnderwater(MWMechanics::getPlayer().getCell(), newPos)) hit = true; if (hit) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 99193de67..cc5b726af 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -12,6 +12,8 @@ #include "../mwbase/world.hpp" #include "../mwbase/soundmanager.hpp" +#include "../mwmechanics/actorutil.hpp" + #include "../mwsound/sound.hpp" #include "../mwrender/renderingmanager.hpp" @@ -798,7 +800,7 @@ void WeatherManager::changeWeather(const std::string& region, const unsigned int mRegionOverrides[Misc::StringUtils::lowerCase(region)] = weather; - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); if (player.isInCell()) { std::string playerRegion = player.getCell()->getCell()->mRegion; From 3fa5c6a0e781e7cd4f659694f56a71d2671bf06b Mon Sep 17 00:00:00 2001 From: dteviot Date: Fri, 21 Aug 2015 22:00:08 +1200 Subject: [PATCH 2075/3725] fixed travis build failure --- apps/openmw/mwrender/renderingmanager.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 1a1b04d18..f4b8aa451 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -1,6 +1,7 @@ #include "renderingmanager.hpp" #include +#include #include #include From 5dd0ad684123f9e9fcee602c37ed30f8747f9ecf Mon Sep 17 00:00:00 2001 From: dteviot Date: Fri, 21 Aug 2015 22:41:31 +1200 Subject: [PATCH 2076/3725] Fixed rest of travis errors. --- apps/openmw/mwmechanics/autocalcspell.cpp | 1 + apps/openmw/mwmechanics/pathfinding.cpp | 1 + apps/openmw/mwmechanics/spellcasting.cpp | 1 + 3 files changed, 3 insertions(+) diff --git a/apps/openmw/mwmechanics/autocalcspell.cpp b/apps/openmw/mwmechanics/autocalcspell.cpp index 5dfe388a8..b798ff5dc 100644 --- a/apps/openmw/mwmechanics/autocalcspell.cpp +++ b/apps/openmw/mwmechanics/autocalcspell.cpp @@ -1,6 +1,7 @@ #include "autocalcspell.hpp" #include +#include #include "../mwworld/esmstore.hpp" diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index f40624ae8..f53badbf4 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -1,4 +1,5 @@ #include "pathfinding.hpp" +#include #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 59410001f..99625e90a 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -1,6 +1,7 @@ #include "spellcasting.hpp" #include +#include #include From 3902513e65206908c0f0f54db213a7c9ea7f2fd0 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 21 Aug 2015 14:02:32 +0200 Subject: [PATCH 2077/3725] merge id collections --- apps/opencs/model/tools/mergeoperation.cpp | 23 ++++++++++ apps/opencs/model/tools/mergestages.hpp | 53 +++++++++++++++++++++- 2 files changed, 74 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/tools/mergeoperation.cpp b/apps/opencs/model/tools/mergeoperation.cpp index 9e5fb2745..4a85eca79 100644 --- a/apps/opencs/model/tools/mergeoperation.cpp +++ b/apps/opencs/model/tools/mergeoperation.cpp @@ -10,6 +10,29 @@ CSMTools::MergeOperation::MergeOperation (CSMDoc::Document& document, ToUTF8::Fr : CSMDoc::Operation (CSMDoc::State_Merging, true), mState (document) { appendStage (new FinishMergedDocumentStage (mState, encoding)); + appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getGlobals)); + appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getGmsts)); + appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getSkills)); + appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getClasses)); + appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getFactions)); + appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getRaces)); + appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getSounds)); + appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getScripts)); + appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getRegions)); + appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getBirthsigns)); + appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getSpells)); + appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getTopics)); + appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getJournals)); + appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getCells)); + appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getFilters)); + appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getEnchantments)); + appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getBodyParts)); + appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getDebugProfiles)); + appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getSoundGens)); + appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getMagicEffects)); + appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getStartScripts)); + + /// \todo TopicInfo, JournalInfo, Referencables, References, Land, LandTextures, Pathgrids } void CSMTools::MergeOperation::setTarget (std::auto_ptr document) diff --git a/apps/opencs/model/tools/mergestages.hpp b/apps/opencs/model/tools/mergestages.hpp index 9844feaca..749fab18c 100644 --- a/apps/opencs/model/tools/mergestages.hpp +++ b/apps/opencs/model/tools/mergestages.hpp @@ -5,10 +5,12 @@ #include "../doc/stage.hpp" +#include "../world/data.hpp" + +#include "mergestate.hpp" + namespace CSMTools { - struct MergeState; - class FinishMergedDocumentStage : public CSMDoc::Stage { MergeState& mState; @@ -24,6 +26,53 @@ namespace CSMTools virtual void perform (int stage, CSMDoc::Messages& messages); ///< Messages resulting from this stage will be appended to \a messages. }; + + template + class MergeIdCollectionStage : public CSMDoc::Stage + { + typedef typename CSMWorld::IdCollection Collection; + + MergeState& mState; + Collection& (CSMWorld::Data::*mAccessor)(); + + public: + + MergeIdCollectionStage (MergeState& state, Collection& (CSMWorld::Data::*accessor)()); + + virtual int setup(); + ///< \return number of steps + + virtual void perform (int stage, CSMDoc::Messages& messages); + ///< Messages resulting from this stage will be appended to \a messages. + }; + + template + MergeIdCollectionStage::MergeIdCollectionStage (MergeState& state, Collection& (CSMWorld::Data::*accessor)()) + : mState (state), mAccessor (accessor) + {} + + template + int MergeIdCollectionStage::setup() + { + return 1; + } + + template + void MergeIdCollectionStage::perform (int stage, CSMDoc::Messages& messages) + { + const Collection& source = (mState.mSource.getData().*mAccessor)(); + Collection& target = (mState.mTarget->getData().*mAccessor)(); + + int size = source.getSize(); + + for (int i=0; i& record = source.getRecord (i); + + if (!record.isDeleted()) + target.appendRecord (CSMWorld::Record (CSMWorld::RecordBase::State_BaseOnly, &record.get())); + } + } } #endif From 52d8bc555c10b1ef8ac263856ff2e8d4131c7160 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 21 Aug 2015 14:24:34 +0200 Subject: [PATCH 2078/3725] Add missing checks to see if spell still exists when loading a savegame (Bug #2883) --- apps/openmw/mwgui/quickkeysmenu.cpp | 3 ++- apps/openmw/mwgui/windowmanagerimp.cpp | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index 3f896bae2..89e6e59be 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -467,7 +467,8 @@ namespace MWGui switch (keyType) { case Type_Magic: - onAssignMagic(id); + if (MWBase::Environment::get().getWorld()->getStore().get().search(id)) + onAssignMagic(id); break; case Type_Item: case Type_MagicItem: diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index db5593704..7f9302bf2 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1686,7 +1686,9 @@ namespace MWGui else if (type == ESM::REC_ASPL) { reader.getSubNameIs("ID__"); - mSelectedSpell = reader.getHString(); + std::string spell = reader.getHString(); + if (MWBase::Environment::get().getWorld()->getStore().get().search(spell)) + mSelectedSpell = spell; } else if (type == ESM::REC_MARK) { From ba8e4c22aa51efa5f689dfecfe0673b96c56a57a Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 21 Aug 2015 20:17:42 +0200 Subject: [PATCH 2079/3725] Avoid using loops to wrap angle values (Fixes #2882) --- apps/openmw/mwworld/worldimp.cpp | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 1eed841bd..aa444cb14 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1213,7 +1213,6 @@ namespace MWWorld void World::rotateObjectImp (const Ptr& ptr, const osg::Vec3f& rot, bool adjust) { const float pi = static_cast(osg::PI); - const float two_pi = pi*2.f; ESM::Position pos = ptr.getRefData().getPosition(); float *objRot = pos.rot; @@ -1243,15 +1242,11 @@ namespace MWWorld } else { - while(objRot[0] < -pi) objRot[0] += two_pi; - while(objRot[0] > pi) objRot[0] -= two_pi; + wrap(objRot[0]); } - while(objRot[1] < -pi) objRot[1] += two_pi; - while(objRot[1] > pi) objRot[1] -= two_pi; - - while(objRot[2] < -pi) objRot[2] += two_pi; - while(objRot[2] > pi) objRot[2] -= two_pi; + wrap(objRot[1]); + wrap(objRot[2]); ptr.getRefData().setPosition(pos); From d038ac2da092629e7b08379ae938f2666073b574 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Fri, 21 Aug 2015 21:38:28 +0300 Subject: [PATCH 2080/3725] Sort tables by ID in the ascending order initially --- apps/opencs/view/world/table.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index 72e0c82d0..73bef7b26 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -273,12 +273,16 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id, horizontalHeader()->setResizeMode (QHeaderView::Interactive); #endif verticalHeader()->hide(); - setSortingEnabled (sorting); setSelectionBehavior (QAbstractItemView::SelectRows); setSelectionMode (QAbstractItemView::ExtendedSelection); - int columns = mModel->columnCount(); + setSortingEnabled (sorting); + if (sorting) + { + sortByColumn (mModel->findColumnIndex(CSMWorld::Columns::ColumnId_Id), Qt::AscendingOrder); + } + int columns = mModel->columnCount(); for (int i=0; iheaderData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Flags).toInt(); From e14aedc7cde788e3a9d67c555a749fd319a2e656 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Fri, 21 Aug 2015 21:47:29 +0300 Subject: [PATCH 2081/3725] ModifyCommand uses a proper name of a modified nested value --- apps/opencs/model/world/commands.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/opencs/model/world/commands.cpp b/apps/opencs/model/world/commands.cpp index 7673e6bc9..d510cd103 100644 --- a/apps/opencs/model/world/commands.cpp +++ b/apps/opencs/model/world/commands.cpp @@ -21,12 +21,17 @@ CSMWorld::ModifyCommand::ModifyCommand (QAbstractItemModel& model, const QModelI // Replace proxy with actual model mIndex = proxy->mapToSource (index); mModel = proxy->sourceModel(); + } + if (mIndex.parent().isValid()) + { setText ("Modify " + dynamic_cast(mModel)->nestedHeaderData ( mIndex.parent().column(), mIndex.column(), Qt::Horizontal, Qt::DisplayRole).toString()); } else + { setText ("Modify " + mModel->headerData (mIndex.column(), Qt::Horizontal, Qt::DisplayRole).toString()); + } // Remember record state before the modification if (CSMWorld::IdTable *table = dynamic_cast(mModel)) From aeb1acca514d86e8cb4fcc41c1045f4b1f1886a0 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Fri, 21 Aug 2015 22:05:40 +0300 Subject: [PATCH 2082/3725] Remove enum names for AiWanderRepeat column --- apps/opencs/model/world/columns.cpp | 6 ------ apps/opencs/view/doc/viewmanager.cpp | 1 - 2 files changed, 7 deletions(-) diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 1fcf0ae41..045438bef 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -536,11 +536,6 @@ namespace "AI Wander", "AI Travel", "AI Follow", "AI Escort", "AI Activate", 0 }; - static const char *sAiWanderRepeat[] = - { - "No", "Yes", 0 - }; - static const char *sInfoCondFunc[] = { " ", "Function", "Global", "Local", "Journal", @@ -580,7 +575,6 @@ namespace case CSMWorld::Columns::ColumnId_EffectId: return sEffectId; case CSMWorld::Columns::ColumnId_PartRefType: return sPartRefType; case CSMWorld::Columns::ColumnId_AiPackageType: return sAiPackageType; - case CSMWorld::Columns::ColumnId_AiWanderRepeat: return sAiWanderRepeat; case CSMWorld::Columns::ColumnId_InfoCondFunc: return sInfoCondFunc; // FIXME: don't have dynamic value enum delegate, use Display_String for now //case CSMWorld::Columns::ColumnId_InfoCond: return sInfoCond; diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 7c9686277..3e832bdcf 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -102,7 +102,6 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) { CSMWorld::ColumnBase::Display_EffectId, CSMWorld::Columns::ColumnId_EffectId, false }, { CSMWorld::ColumnBase::Display_PartRefType, CSMWorld::Columns::ColumnId_PartRefType, false }, { CSMWorld::ColumnBase::Display_AiPackageType, CSMWorld::Columns::ColumnId_AiPackageType, false }, - { CSMWorld::ColumnBase::Display_Boolean, CSMWorld::Columns::ColumnId_AiWanderRepeat, false }, { CSMWorld::ColumnBase::Display_InfoCondFunc, CSMWorld::Columns::ColumnId_InfoCondFunc, false }, { CSMWorld::ColumnBase::Display_InfoCondComp, CSMWorld::Columns::ColumnId_InfoCondComp, false }, { CSMWorld::ColumnBase::Display_RaceSkill, CSMWorld::Columns::ColumnId_RaceSkill, true }, From b7295e263210ce0a6c1f46c61189b44c1d188951 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Fri, 21 Aug 2015 22:36:53 +0300 Subject: [PATCH 2083/3725] Columns with Display_Boolean use Combobox editor even for non-boolean values --- apps/opencs/view/world/util.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/opencs/view/world/util.cpp b/apps/opencs/view/world/util.cpp index 2654644c4..b87d6b4f4 100644 --- a/apps/opencs/view/world/util.cpp +++ b/apps/opencs/view/world/util.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include "../../model/world/commands.hpp" #include "../../model/world/tablemimedata.hpp" @@ -172,7 +173,7 @@ QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleO // TODO: Find a better solution? if (display == CSMWorld::ColumnBase::Display_Boolean) { - return QStyledItemDelegate::createEditor(parent, option, index); + return QItemEditorFactory::defaultFactory()->createEditor(QVariant::Bool, parent); } // For tables the pop-up of the color editor should appear immediately after the editor creation // (the third parameter of ColorEditor's constructor) From 031d64d0d34f6ac72520ffcdf5634454e34f475a Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 22 Aug 2015 12:57:39 +0200 Subject: [PATCH 2084/3725] Adjust OpenCS saving stages order to stop vanilla MW complaining about missing records --- apps/opencs/model/doc/saving.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/apps/opencs/model/doc/saving.cpp b/apps/opencs/model/doc/saving.cpp index 25372f1a6..95a2feaf2 100644 --- a/apps/opencs/model/doc/saving.cpp +++ b/apps/opencs/model/doc/saving.cpp @@ -80,22 +80,25 @@ CSMDoc::Saving::Saving (Document& document, const boost::filesystem::path& proje appendStage (new WriteCollectionStage > (mDocument.getData().getStartScripts(), mState)); - appendStage (new WriteDialogueCollectionStage (mDocument, mState, false)); - - appendStage (new WriteDialogueCollectionStage (mDocument, mState, true)); - appendStage (new WriteRefIdCollectionStage (mDocument, mState)); appendStage (new CollectionReferencesStage (mDocument, mState)); appendStage (new WriteCellCollectionStage (mDocument, mState)); - appendStage (new WritePathgridCollectionStage (mDocument, mState)); + // Dialogue can reference objects and cells so must be written after these records for vanilla-compatible files - appendStage (new WriteLandCollectionStage (mDocument, mState)); + appendStage (new WriteDialogueCollectionStage (mDocument, mState, false)); + + appendStage (new WriteDialogueCollectionStage (mDocument, mState, true)); + + appendStage (new WritePathgridCollectionStage (mDocument, mState)); appendStage (new WriteLandTextureCollectionStage (mDocument, mState)); + // references Land Textures + appendStage (new WriteLandCollectionStage (mDocument, mState)); + // close file and clean up appendStage (new CloseSaveStage (mState)); From 32ad8c86bf6c3414651c899d6859ed2463e4afca Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 22 Aug 2015 13:10:54 +0200 Subject: [PATCH 2085/3725] Fix the ESM::LandTexture NAME being discarded on loading --- apps/opencs/model/doc/savingstages.cpp | 2 ++ apps/opencs/model/world/landtexture.cpp | 8 +------- apps/opencs/model/world/landtexture.hpp | 7 ++----- apps/opencs/view/render/terrainstorage.cpp | 16 ++++++++++++---- 4 files changed, 17 insertions(+), 16 deletions(-) diff --git a/apps/opencs/model/doc/savingstages.cpp b/apps/opencs/model/doc/savingstages.cpp index ef3b23ec8..01d260d68 100644 --- a/apps/opencs/model/doc/savingstages.cpp +++ b/apps/opencs/model/doc/savingstages.cpp @@ -454,6 +454,8 @@ void CSMDoc::WriteLandTextureCollectionStage::perform (int stage, Messages& mess mState.getWriter().startRecord (record.sRecordId); + mState.getWriter().writeHNString("NAME", record.mId); + record.save (mState.getWriter()); mState.getWriter().endRecord (record.sRecordId); diff --git a/apps/opencs/model/world/landtexture.cpp b/apps/opencs/model/world/landtexture.cpp index 4725866a5..e7772129c 100644 --- a/apps/opencs/model/world/landtexture.cpp +++ b/apps/opencs/model/world/landtexture.cpp @@ -9,13 +9,7 @@ namespace CSMWorld { ESM::LandTexture::load(esm); - int plugin = esm.getIndex(); - - std::ostringstream stream; - - stream << mIndex << "_" << plugin; - - mId = stream.str(); + mPluginIndex = esm.getIndex(); } } diff --git a/apps/opencs/model/world/landtexture.hpp b/apps/opencs/model/world/landtexture.hpp index b13903186..c0b6eeba9 100644 --- a/apps/opencs/model/world/landtexture.hpp +++ b/apps/opencs/model/world/landtexture.hpp @@ -7,13 +7,10 @@ namespace CSMWorld { - /// \brief Wrapper for LandTexture record. Encodes mIndex and the plugin index (obtained from ESMReader) - /// in the ID. - /// - /// \attention The mId field of the ESM::LandTexture struct is not used. + /// \brief Wrapper for LandTexture record, providing info which plugin the LandTexture was loaded from. struct LandTexture : public ESM::LandTexture { - std::string mId; + int mPluginIndex; void load (ESM::ESMReader &esm); }; diff --git a/apps/opencs/view/render/terrainstorage.cpp b/apps/opencs/view/render/terrainstorage.cpp index fe302cef1..3d9d1ee97 100644 --- a/apps/opencs/view/render/terrainstorage.cpp +++ b/apps/opencs/view/render/terrainstorage.cpp @@ -29,10 +29,18 @@ namespace CSVRender const ESM::LandTexture* TerrainStorage::getLandTexture(int index, short plugin) { - std::ostringstream stream; - stream << index << "_" << plugin; - - return &mData.getLandTextures().getRecord(stream.str()).get(); + int numRecords = mData.getLandTextures().getSize(); + + for (int i=0; imIndex == index && ltex->mPluginIndex == plugin) + return ltex; + } + + std::stringstream error; + error << "Can't find LandTexture " << index << " from plugin " << plugin; + throw std::runtime_error(error.str()); } void TerrainStorage::getBounds(float &minX, float &maxX, float &minY, float &maxY) From 6d81ca07b5d765fcf479480896f8bc2d2eb6cfd4 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Fri, 21 Aug 2015 22:55:58 +0300 Subject: [PATCH 2086/3725] Convert AiWanderRepeat to bool in ActorAiRefIdAdapter::getNestedData() --- apps/opencs/model/world/refidadapterimp.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index 4066b5646..5ceb3325a 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -1566,7 +1566,7 @@ namespace CSMWorld return QVariant(); case 5: // wander repeat if (content.mType == ESM::AI_Wander) - return content.mWander.mShouldRepeat; + return content.mWander.mShouldRepeat != 0; else return QVariant(); case 6: // activate name From 4d24eff859aec2b8f5c901b35bae11e0e30c068c Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sat, 22 Aug 2015 00:01:27 +0300 Subject: [PATCH 2087/3725] Show race only when mesh type is Skin (in BodyParts table) --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/world/columnimp.cpp | 28 +++++++++++++++++++++++++++ apps/opencs/model/world/columnimp.hpp | 19 +++++++++++++++--- apps/opencs/model/world/data.cpp | 7 +++++-- 4 files changed, 50 insertions(+), 6 deletions(-) create mode 100644 apps/opencs/model/world/columnimp.cpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index b1953ee97..9dd7e8c8e 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -23,7 +23,7 @@ opencs_units (model/world opencs_units_noqt (model/world - universalid record commands columnbase scriptcontext cell refidcollection + universalid record commands columnbase columnimp scriptcontext cell refidcollection refidadapter refiddata refidadapterimp ref collectionbase refcollection columns infocollection tablemimedata cellcoordinates cellselection resources resourcesmanager scope pathgrid landtexture land nestedtablewrapper nestedcollection nestedcoladapterimp nestedinfocollection idcompletionmanager metadata diff --git a/apps/opencs/model/world/columnimp.cpp b/apps/opencs/model/world/columnimp.cpp new file mode 100644 index 000000000..dc3d39edb --- /dev/null +++ b/apps/opencs/model/world/columnimp.cpp @@ -0,0 +1,28 @@ +#include "columnimp.hpp" + +CSMWorld::BodyPartRaceColumn::BodyPartRaceColumn(const MeshTypeColumn *meshType) + : mMeshType(meshType) +{} + +QVariant CSMWorld::BodyPartRaceColumn::get(const Record &record) const +{ + if (mMeshType != NULL && mMeshType->get(record) == ESM::BodyPart::MT_Skin) + { + return QString::fromUtf8(record.get().mRace.c_str()); + } + return QVariant(QVariant::UserType); +} + +void CSMWorld::BodyPartRaceColumn::set(Record &record, const QVariant &data) +{ + ESM::BodyPart record2 = record.get(); + + record2.mRace = data.toString().toUtf8().constData(); + + record.setModified(record2); +} + +bool CSMWorld::BodyPartRaceColumn::isEditable() const +{ + return true; +} diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index 15dd2c15b..824196c88 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -9,6 +9,8 @@ #include +#include + #include "columnbase.hpp" #include "columns.hpp" #include "info.hpp" @@ -1911,8 +1913,8 @@ namespace CSMWorld template struct MeshTypeColumn : public Column { - MeshTypeColumn() - : Column (Columns::ColumnId_MeshType, ColumnBase::Display_MeshType) + MeshTypeColumn(int flags = ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue) + : Column (Columns::ColumnId_MeshType, ColumnBase::Display_MeshType, flags) {} virtual QVariant get (const Record& record) const @@ -2379,7 +2381,18 @@ namespace CSMWorld { return true; } - }; + }; + + struct BodyPartRaceColumn : public RaceColumn + { + const MeshTypeColumn *mMeshType; + + BodyPartRaceColumn(const MeshTypeColumn *meshType); + + virtual QVariant get(const Record &record) const; + virtual void set(Record &record, const QVariant &data); + virtual bool isEditable() const; + }; } #endif diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 12ff1a38c..94312ae7d 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -351,9 +351,12 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mBodyParts.addColumn (new FlagColumn (Columns::ColumnId_Female, ESM::BodyPart::BPF_Female)); mBodyParts.addColumn (new FlagColumn (Columns::ColumnId_Playable, ESM::BodyPart::BPF_NotPlayable, ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue, true)); - mBodyParts.addColumn (new MeshTypeColumn); + + int meshTypeFlags = ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue | ColumnBase::Flag_Dialogue_Refresh; + MeshTypeColumn *meshTypeColumn = new MeshTypeColumn(meshTypeFlags); + mBodyParts.addColumn (meshTypeColumn); mBodyParts.addColumn (new ModelColumn); - mBodyParts.addColumn (new RaceColumn); + mBodyParts.addColumn (new BodyPartRaceColumn(meshTypeColumn)); mSoundGens.addColumn (new StringIdColumn); mSoundGens.addColumn (new RecordStateColumn); From 720aca8f3dae258cc23ae7c28307ef5ab47637d1 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sat, 22 Aug 2015 13:38:38 +0300 Subject: [PATCH 2088/3725] Inform about State change (not a whole row) when modifying a table value --- apps/opencs/model/world/idtable.cpp | 11 +++++++---- apps/opencs/model/world/idtree.cpp | 13 +++++++------ 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index bdbc5e0c4..bd1179cea 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -76,12 +76,15 @@ bool CSMWorld::IdTable::setData (const QModelIndex &index, const QVariant &value if (mIdCollection->getColumn (index.column()).isEditable() && role==Qt::EditRole) { mIdCollection->setData (index.row(), index.column(), value); + emit dataChanged(index, index); // Modifying a value can also change the Modified status of a record. - // To track this, we inform about the change of a whole row. - QModelIndex rowStart = this->index(index.row(), 0); - QModelIndex rowEnd = this->index(index.row(), columnCount(index.parent()) - 1); - emit dataChanged(rowStart, rowEnd); + int stateColumn = searchColumnIndex(Columns::ColumnId_Modification); + if (stateColumn != -1) + { + QModelIndex stateIndex = this->index(index.row(), stateColumn); + emit dataChanged(stateIndex, stateIndex); + } return true; } diff --git a/apps/opencs/model/world/idtree.cpp b/apps/opencs/model/world/idtree.cpp index 0b027cdab..124a94e8c 100644 --- a/apps/opencs/model/world/idtree.cpp +++ b/apps/opencs/model/world/idtree.cpp @@ -95,14 +95,15 @@ bool CSMWorld::IdTree::setData (const QModelIndex &index, const QVariant &value, const std::pair& parentAddress(unfoldIndexAddress(index.internalId())); mNestedCollection->setNestedData(parentAddress.first, parentAddress.second, value, index.row(), index.column()); - emit dataChanged(index, index); - // Modifying a value can also change the Modified status of a record (located in the parent row). - // To track this, we inform about the change of a whole parent row. - QModelIndex parentRowStart = this->index(index.parent().row(), 0); - QModelIndex parentRowEnd = this->index(index.parent().row(), columnCount(index.parent()) - 1); - emit dataChanged(parentRowStart, parentRowEnd); + // Modifying a value can also change the Modified status of a record. + int stateColumn = searchColumnIndex(Columns::ColumnId_Modification); + if (stateColumn != -1) + { + QModelIndex stateIndex = this->index(index.parent().row(), stateColumn); + emit dataChanged(stateIndex, stateIndex); + } return true; } From ba4b7df99dc2d0e1b3f6189158c5c4f1aaab57ee Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sat, 22 Aug 2015 14:34:05 +0300 Subject: [PATCH 2089/3725] Add missing includes to columnimp.hpp --- apps/opencs/model/world/columnimp.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index 824196c88..4e608dbbd 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -10,6 +10,8 @@ #include #include +#include +#include #include "columnbase.hpp" #include "columns.hpp" From 542c648e6986160c7590703a6c1811ec06e34c8a Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 22 Aug 2015 22:53:06 +0200 Subject: [PATCH 2090/3725] Fix incorrect assignment of PcRace, need to sort race IDs (Fixes #2884) --- apps/openmw/mwworld/store.hpp | 1 + apps/openmw/mwworld/worldimp.cpp | 2 ++ 2 files changed, 3 insertions(+) diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index 3cbd8d3ac..47c87f742 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -170,6 +170,7 @@ namespace MWWorld size_t getSize() const; int getDynamicSize() const; + /// @note The record identifiers are listed in the order that the records were defined by the content files. void listIdentifier(std::vector &list) const; T *insert(const T &item); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 5b2624f4c..8b53d1675 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1496,6 +1496,8 @@ namespace MWWorld std::vector ids; getStore().get().listIdentifier(ids); + std::sort(ids.begin(), ids.end()); + unsigned int i=0; for (; i Date: Sun, 23 Aug 2015 12:37:45 +0200 Subject: [PATCH 2091/3725] flag newly merged documents as dirty (triggering an 'are you sure' dialogue when closing without saving first) --- apps/opencs/model/doc/document.cpp | 12 ++++++++++-- apps/opencs/model/doc/document.hpp | 3 +++ apps/opencs/model/tools/tools.cpp | 2 ++ 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 8d5580bcf..2cff89389 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -2256,7 +2256,7 @@ CSMDoc::Document::Document (const VFS::Manager* vfs, const Files::ConfigurationM mSavingOperation (*this, mProjectPath, encoding), mSaving (&mSavingOperation), mResDir(resDir), - mRunner (mProjectPath), mIdCompletionManager(mData) + mRunner (mProjectPath), mIdCompletionManager(mData), mDirty (false) { if (mContentFiles.empty()) throw std::runtime_error ("Empty content file sequence"); @@ -2325,7 +2325,7 @@ int CSMDoc::Document::getState() const { int state = 0; - if (!mUndoStack.isClean()) + if (!mUndoStack.isClean() || mDirty) state |= State_Modified; if (mSaving.isRunning()) @@ -2417,6 +2417,9 @@ void CSMDoc::Document::reportMessage (const CSMDoc::Message& message, int type) void CSMDoc::Document::operationDone (int type, bool failed) { + if (type==CSMDoc::State_Saving && !failed) + mDirty = false; + emit stateChanged (getState(), this); } @@ -2493,3 +2496,8 @@ CSMWorld::IdCompletionManager &CSMDoc::Document::getIdCompletionManager() { return mIdCompletionManager; } + +void CSMDoc::Document::flagAsDirty() +{ + mDirty = true; +} diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp index 3eaa5bb14..0e8ae6d45 100644 --- a/apps/opencs/model/doc/document.hpp +++ b/apps/opencs/model/doc/document.hpp @@ -68,6 +68,7 @@ namespace CSMDoc boost::filesystem::path mResDir; Blacklist mBlacklist; Runner mRunner; + bool mDirty; CSMWorld::IdCompletionManager mIdCompletionManager; @@ -152,6 +153,8 @@ namespace CSMDoc CSMWorld::IdCompletionManager &getIdCompletionManager(); + void flagAsDirty(); + signals: void stateChanged (int state, CSMDoc::Document *document); diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index c4ff6868b..cabd53937 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -207,6 +207,8 @@ void CSMTools::Tools::runMerge (std::auto_ptr target) this, SIGNAL (mergeDone (CSMDoc::Document*))); } + target->flagAsDirty(); + mMergeOperation->setTarget (target); mMerge.start(); From 103073150e87d62582649ea6943fdc510eb5ca59 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 23 Aug 2015 12:58:49 +0200 Subject: [PATCH 2092/3725] added info tables and pathgrid table to merge operation --- apps/opencs/model/tools/mergeoperation.cpp | 5 ++++- apps/opencs/model/tools/mergestages.hpp | 16 +++++++--------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/apps/opencs/model/tools/mergeoperation.cpp b/apps/opencs/model/tools/mergeoperation.cpp index 4a85eca79..d010e343b 100644 --- a/apps/opencs/model/tools/mergeoperation.cpp +++ b/apps/opencs/model/tools/mergeoperation.cpp @@ -31,8 +31,11 @@ CSMTools::MergeOperation::MergeOperation (CSMDoc::Document& document, ToUTF8::Fr appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getSoundGens)); appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getMagicEffects)); appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getStartScripts)); + appendStage (new MergeIdCollectionStage > (mState, &CSMWorld::Data::getPathgrids)); + appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getTopicInfos)); + appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getJournalInfos)); - /// \todo TopicInfo, JournalInfo, Referencables, References, Land, LandTextures, Pathgrids + /// \todo Referencables, References, Land, LandTextures } void CSMTools::MergeOperation::setTarget (std::auto_ptr document) diff --git a/apps/opencs/model/tools/mergestages.hpp b/apps/opencs/model/tools/mergestages.hpp index 749fab18c..f9d29420b 100644 --- a/apps/opencs/model/tools/mergestages.hpp +++ b/apps/opencs/model/tools/mergestages.hpp @@ -27,11 +27,9 @@ namespace CSMTools ///< Messages resulting from this stage will be appended to \a messages. }; - template + template > class MergeIdCollectionStage : public CSMDoc::Stage { - typedef typename CSMWorld::IdCollection Collection; - MergeState& mState; Collection& (CSMWorld::Data::*mAccessor)(); @@ -46,19 +44,19 @@ namespace CSMTools ///< Messages resulting from this stage will be appended to \a messages. }; - template - MergeIdCollectionStage::MergeIdCollectionStage (MergeState& state, Collection& (CSMWorld::Data::*accessor)()) + template + MergeIdCollectionStage::MergeIdCollectionStage (MergeState& state, Collection& (CSMWorld::Data::*accessor)()) : mState (state), mAccessor (accessor) {} - template - int MergeIdCollectionStage::setup() + template + int MergeIdCollectionStage::setup() { return 1; } - template - void MergeIdCollectionStage::perform (int stage, CSMDoc::Messages& messages) + template + void MergeIdCollectionStage::perform (int stage, CSMDoc::Messages& messages) { const Collection& source = (mState.mSource.getData().*mAccessor)(); Collection& target = (mState.mTarget->getData().*mAccessor)(); From 16dda281cee3fb1bab7276cc21448b754d5db3c5 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 23 Aug 2015 13:04:42 +0200 Subject: [PATCH 2093/3725] made merge operation more fluent --- apps/opencs/model/tools/mergestages.hpp | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/tools/mergestages.hpp b/apps/opencs/model/tools/mergestages.hpp index f9d29420b..af7f06d60 100644 --- a/apps/opencs/model/tools/mergestages.hpp +++ b/apps/opencs/model/tools/mergestages.hpp @@ -1,6 +1,8 @@ #ifndef CSM_TOOLS_MERGESTAGES_H #define CSM_TOOLS_MERGESTAGES_H +#include + #include #include "../doc/stage.hpp" @@ -33,6 +35,8 @@ namespace CSMTools MergeState& mState; Collection& (CSMWorld::Data::*mAccessor)(); + static const int stepSize = 1000; + public: MergeIdCollectionStage (MergeState& state, Collection& (CSMWorld::Data::*accessor)()); @@ -52,7 +56,16 @@ namespace CSMTools template int MergeIdCollectionStage::setup() { - return 1; + const Collection& source = (mState.mSource.getData().*mAccessor)(); + + int size = source.getSize(); + + int steps = size / stepSize; + + if (size % stepSize) + ++steps; + + return steps; } template @@ -61,9 +74,10 @@ namespace CSMTools const Collection& source = (mState.mSource.getData().*mAccessor)(); Collection& target = (mState.mTarget->getData().*mAccessor)(); - int size = source.getSize(); + int begin = stage * stepSize; + int end = std::min ((stage+1) * stepSize, source.getSize()); - for (int i=0; i& record = source.getRecord (i); From b509a18065959b0e65bceb737655d5968d9fa3da Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 23 Aug 2015 14:05:46 +0200 Subject: [PATCH 2094/3725] Remove code setting PcRace (Fixes #2886) This is already handled by the RaceCheck script. --- apps/openmw/mwworld/worldimp.cpp | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 40a929cda..7d4ab0c95 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -216,7 +216,6 @@ namespace MWWorld { // set new game mark mGlobalVariables["chargenstate"].setInteger (1); - mGlobalVariables["pcrace"].setInteger (3); } else mGlobalVariables["chargenstate"].setInteger (-1); @@ -1493,19 +1492,6 @@ namespace MWWorld if (Misc::StringUtils::ciEqual(record.mId, "player")) { - std::vector ids; - getStore().get().listIdentifier(ids); - - std::sort(ids.begin(), ids.end()); - - unsigned int i=0; - - for (; igetPlayer().get()->mBase; From bb54bbd2736d8440e639066bc459ec56173786de Mon Sep 17 00:00:00 2001 From: dteviot Date: Mon, 24 Aug 2015 19:54:02 +1200 Subject: [PATCH 2095/3725] Pulled duplicated functions into common base class --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwclass/creature.cpp | 70 ------------------------- apps/openmw/mwclass/creature.hpp | 22 +------- apps/openmw/mwclass/mobile.cpp | 87 ++++++++++++++++++++++++++++++++ apps/openmw/mwclass/mobile.hpp | 47 +++++++++++++++++ apps/openmw/mwclass/npc.cpp | 66 +----------------------- apps/openmw/mwclass/npc.hpp | 18 +------ 7 files changed, 140 insertions(+), 172 deletions(-) create mode 100644 apps/openmw/mwclass/mobile.cpp create mode 100644 apps/openmw/mwclass/mobile.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index a0f9e8e13..9054e53c9 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -74,7 +74,7 @@ add_openmw_dir (mwphysics add_openmw_dir (mwclass classes activator creature npc weapon armor potion apparatus book clothing container door - ingredient creaturelevlist itemlevlist light lockpick misc probe repair static + ingredient creaturelevlist itemlevlist light lockpick misc probe repair static mobile ) add_openmw_dir (mwmechanics diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index ff09282c1..e14d9f8ba 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -156,11 +156,6 @@ namespace MWClass return ref->mBase->mId; } - void Creature::adjustPosition(const MWWorld::Ptr& ptr, bool force) const - { - MWBase::Environment::get().getWorld()->adjustPosition(ptr, force); - } - void Creature::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { MWWorld::LiveCellRef *ref = ptr.get(); @@ -169,17 +164,6 @@ namespace MWClass objects.insertCreature(ptr, model, (ref->mBase->mFlags & ESM::Creature::Weapon) != 0); } - void Creature::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const - { - if(!model.empty()) - { - physics.addActor(ptr, model); - if (getCreatureStats(ptr).isDead()) - MWBase::Environment::get().getWorld()->enableActorCollision(ptr, false); - } - MWBase::Environment::get().getMechanicsManager()->add(ptr); - } - std::string Creature::getModel(const MWWorld::Ptr &ptr) const { MWWorld::LiveCellRef *ref = @@ -408,30 +392,6 @@ namespace MWClass } } - void Creature::block(const MWWorld::Ptr &ptr) const - { - MWWorld::InventoryStore& inv = getInventoryStore(ptr); - MWWorld::ContainerStoreIterator shield = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft); - if (shield == inv.end()) - return; - - MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); - switch(shield->getClass().getEquipmentSkill(*shield)) - { - case ESM::Skill::LightArmor: - sndMgr->playSound3D(ptr, "Light Armor Hit", 1.0f, 1.0f); - break; - case ESM::Skill::MediumArmor: - sndMgr->playSound3D(ptr, "Medium Armor Hit", 1.0f, 1.0f); - break; - case ESM::Skill::HeavyArmor: - sndMgr->playSound3D(ptr, "Heavy Armor Hit", 1.0f, 1.0f); - break; - default: - return; - } - } - boost::shared_ptr Creature::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const { @@ -499,11 +459,6 @@ namespace MWClass registerClass (typeid (ESM::Creature).name(), instance); } - bool Creature::hasToolTip (const MWWorld::Ptr& ptr) const - { - return !ptr.getClass().getCreatureStats(ptr).getAiSequence().isInCombat() || getCreatureStats(ptr).isDead(); - } - float Creature::getSpeed(const MWWorld::Ptr &ptr) const { MWMechanics::CreatureStats& stats = getCreatureStats(ptr); @@ -562,16 +517,6 @@ namespace MWClass return dynamic_cast (*ptr.getRefData().getCustomData()).mMovement; } - osg::Vec3f Creature::getRotationVector (const MWWorld::Ptr& ptr) const - { - MWMechanics::Movement &movement = getMovementSettings(ptr); - osg::Vec3f vec(movement.mRotation[0], movement.mRotation[1], movement.mRotation[2]); - movement.mRotation[0] = 0.0f; - movement.mRotation[1] = 0.0f; - movement.mRotation[2] = 0.0f; - return vec; - } - MWGui::ToolTipInfo Creature::getToolTipInfo (const MWWorld::Ptr& ptr) const { MWWorld::LiveCellRef *ref = @@ -600,21 +545,6 @@ namespace MWClass return static_cast(stats.getAttribute(0).getModified() * 5); } - float Creature::getEncumbrance (const MWWorld::Ptr& ptr) const - { - float weight = getContainerStore (ptr).getWeight(); - - const MWMechanics::MagicEffects& effects = getCreatureStats(ptr).getMagicEffects(); - weight -= effects.get(ESM::MagicEffect::Feather).getMagnitude(); - weight += effects.get(ESM::MagicEffect::Burden).getMagnitude(); - - if (weight<0) - weight = 0; - - return weight; - } - - int Creature::getServices(const MWWorld::Ptr &actor) const { MWWorld::LiveCellRef* ref = actor.get(); diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index b2a333beb..3881c1d40 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -1,7 +1,7 @@ #ifndef GAME_MWCLASS_CREATURE_H #define GAME_MWCLASS_CREATURE_H -#include "../mwworld/class.hpp" +#include "mobile.hpp" namespace ESM { @@ -10,7 +10,7 @@ namespace ESM namespace MWClass { - class Creature : public MWWorld::Class + class Creature : public Mobile { void ensureCustomData (const MWWorld::Ptr& ptr) const; @@ -47,19 +47,10 @@ namespace MWClass virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; - - virtual void adjustPosition(const MWWorld::Ptr& ptr, bool force) const; - ///< Adjust position to stand on ground. Must be called post model load - /// @param force do this even if the ptr is flying - virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. - virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; - ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. @@ -68,8 +59,6 @@ namespace MWClass virtual void hit(const MWWorld::Ptr& ptr, float attackStrength, int type) const; - virtual void block(const MWWorld::Ptr &ptr) const; - virtual void onHit(const MWWorld::Ptr &ptr, float damage, bool ishealth, const MWWorld::Ptr &object, const MWWorld::Ptr &attacker, bool successful) const; virtual boost::shared_ptr activate (const MWWorld::Ptr& ptr, @@ -92,10 +81,6 @@ namespace MWClass ///< Return total weight that fits into the object. Throws an exception, if the object can't /// hold other objects. - virtual float getEncumbrance (const MWWorld::Ptr& ptr) const; - ///< Returns total weight of objects inside this object (including modifications from magic - /// effects). Throws an exception, if the object can't hold other objects. - virtual float getArmorRating (const MWWorld::Ptr& ptr) const; ///< @return combined armor rating of this actor @@ -111,9 +96,6 @@ namespace MWClass virtual MWMechanics::Movement& getMovementSettings (const MWWorld::Ptr& ptr) const; ///< Return desired movement. - virtual osg::Vec3f getRotationVector (const MWWorld::Ptr& ptr) const; - ///< Return desired rotations, as euler angles. - float getSpeed (const MWWorld::Ptr& ptr) const; static void registerSelf(); diff --git a/apps/openmw/mwclass/mobile.cpp b/apps/openmw/mwclass/mobile.cpp new file mode 100644 index 000000000..9cd5510e2 --- /dev/null +++ b/apps/openmw/mwclass/mobile.cpp @@ -0,0 +1,87 @@ +#include "mobile.hpp" + +#include + +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" +#include "../mwbase/mechanicsmanager.hpp" +#include "../mwbase/soundmanager.hpp" + +#include "../mwmechanics/creaturestats.hpp" +#include "../mwmechanics/movement.hpp" +#include "../mwmechanics/magiceffects.hpp" + +#include "../mwphysics/physicssystem.hpp" + +#include "../mwworld/inventorystore.hpp" + +namespace MWClass +{ + Mobile::Mobile() {} + + Mobile::~Mobile() {} + + void Mobile::adjustPosition(const MWWorld::Ptr& ptr, bool force) const + { + MWBase::Environment::get().getWorld()->adjustPosition(ptr, force); + } + + void Mobile::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const + { + if (!model.empty()) + { + physics.addActor(ptr, model); + if (getCreatureStats(ptr).isDead()) + MWBase::Environment::get().getWorld()->enableActorCollision(ptr, false); + } + MWBase::Environment::get().getMechanicsManager()->add(ptr); + } + + void Mobile::block(const MWWorld::Ptr &ptr) const + { + MWWorld::InventoryStore& inv = getInventoryStore(ptr); + MWWorld::ContainerStoreIterator shield = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft); + if (shield == inv.end()) + return; + + MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); + switch (shield->getClass().getEquipmentSkill(*shield)) + { + case ESM::Skill::LightArmor: + sndMgr->playSound3D(ptr, "Light Armor Hit", 1.0f, 1.0f); + break; + case ESM::Skill::MediumArmor: + sndMgr->playSound3D(ptr, "Medium Armor Hit", 1.0f, 1.0f); + break; + case ESM::Skill::HeavyArmor: + sndMgr->playSound3D(ptr, "Heavy Armor Hit", 1.0f, 1.0f); + break; + default: + return; + } + } + + bool Mobile::hasToolTip(const MWWorld::Ptr& ptr) const + { + return !ptr.getClass().getCreatureStats(ptr).getAiSequence().isInCombat() || getCreatureStats(ptr).isDead(); + } + + osg::Vec3f Mobile::getRotationVector(const MWWorld::Ptr& ptr) const + { + MWMechanics::Movement &movement = getMovementSettings(ptr); + osg::Vec3f vec(movement.mRotation[0], movement.mRotation[1], movement.mRotation[2]); + movement.mRotation[0] = 0.0f; + movement.mRotation[1] = 0.0f; + movement.mRotation[2] = 0.0f; + return vec; + } + + float Mobile::getEncumbrance(const MWWorld::Ptr& ptr) const + { + float weight = getContainerStore(ptr).getWeight(); + const MWMechanics::MagicEffects& effects = getCreatureStats(ptr).getMagicEffects(); + weight -= effects.get(MWMechanics::EffectKey(ESM::MagicEffect::Feather)).getMagnitude(); + weight += effects.get(MWMechanics::EffectKey(ESM::MagicEffect::Burden)).getMagnitude(); + return (weight < 0) ? 0.0f : weight; + } +} diff --git a/apps/openmw/mwclass/mobile.hpp b/apps/openmw/mwclass/mobile.hpp new file mode 100644 index 000000000..5b1eeae9d --- /dev/null +++ b/apps/openmw/mwclass/mobile.hpp @@ -0,0 +1,47 @@ +#ifndef GAME_MWCLASS_MOBILE_H +#define GAME_MWCLASS_MOBILE_H + +#include "../mwworld/class.hpp" + +namespace ESM +{ + struct GameSetting; +} + +namespace MWClass +{ + /// \brief Class holding functionality common to Creature and NPC + class Mobile : public MWWorld::Class + { + protected: + + Mobile(); + + public: + ~Mobile(); + + virtual void adjustPosition(const MWWorld::Ptr& ptr, bool force) const; + ///< Adjust position to stand on ground. Must be called post model load + /// @param force do this even if the ptr is flying + + virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; + + virtual void block(const MWWorld::Ptr &ptr) const; + + virtual bool hasToolTip(const MWWorld::Ptr& ptr) const; + ///< @return true if this object has a tooltip when focused (default implementation: false) + + virtual osg::Vec3f getRotationVector(const MWWorld::Ptr& ptr) const; + ///< Return desired rotations, as euler angles. + + virtual float getEncumbrance(const MWWorld::Ptr& ptr) const; + ///< Returns total weight of objects inside this object (including modifications from magic + /// effects). Throws an exception, if the object can't hold other objects. + + // not implemented + Mobile(const Mobile&); + Mobile& operator= (const Mobile&); + }; +} + +#endif diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 5f166b3e3..bd1579d9e 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -402,24 +402,11 @@ namespace MWClass return ref->mBase->mId; } - void Npc::adjustPosition(const MWWorld::Ptr& ptr, bool force) const - { - MWBase::Environment::get().getWorld()->adjustPosition(ptr, force); - } - void Npc::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { renderingInterface.getObjects().insertNPC(ptr); } - void Npc::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const - { - physics.addActor(ptr, model); - MWBase::Environment::get().getMechanicsManager()->add(ptr); - if (getCreatureStats(ptr).isDead()) - MWBase::Environment::get().getWorld()->enableActorCollision(ptr, false); - } - bool Npc::isPersistent(const MWWorld::Ptr &actor) const { MWWorld::LiveCellRef* ref = actor.get(); @@ -756,30 +743,6 @@ namespace MWClass } } - void Npc::block(const MWWorld::Ptr &ptr) const - { - MWWorld::InventoryStore& inv = getInventoryStore(ptr); - MWWorld::ContainerStoreIterator shield = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft); - if (shield == inv.end()) - return; - - MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); - switch(shield->getClass().getEquipmentSkill(*shield)) - { - case ESM::Skill::LightArmor: - sndMgr->playSound3D(ptr, "Light Armor Hit", 1.0f, 1.0f); - break; - case ESM::Skill::MediumArmor: - sndMgr->playSound3D(ptr, "Medium Armor Hit", 1.0f, 1.0f); - break; - case ESM::Skill::HeavyArmor: - sndMgr->playSound3D(ptr, "Heavy Armor Hit", 1.0f, 1.0f); - break; - default: - return; - } - } - boost::shared_ptr Npc::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const { @@ -937,16 +900,6 @@ namespace MWClass return dynamic_cast (*ptr.getRefData().getCustomData()).mMovement; } - osg::Vec3f Npc::getRotationVector (const MWWorld::Ptr& ptr) const - { - MWMechanics::Movement &movement = getMovementSettings(ptr); - osg::Vec3f vec(movement.mRotation[0], movement.mRotation[1], movement.mRotation[2]); - movement.mRotation[0] = 0.0f; - movement.mRotation[1] = 0.0f; - movement.mRotation[2] = 0.0f; - return vec; - } - bool Npc::isEssential (const MWWorld::Ptr& ptr) const { MWWorld::LiveCellRef *ref = @@ -961,11 +914,6 @@ namespace MWClass registerClass (typeid (ESM::NPC).name(), instance); } - bool Npc::hasToolTip (const MWWorld::Ptr& ptr) const - { - return !ptr.getClass().getCreatureStats(ptr).getAiSequence().isInCombat() || getCreatureStats(ptr).isDead(); - } - MWGui::ToolTipInfo Npc::getToolTipInfo (const MWWorld::Ptr& ptr) const { MWWorld::LiveCellRef *ref = ptr.get(); @@ -996,21 +944,9 @@ namespace MWClass float Npc::getEncumbrance (const MWWorld::Ptr& ptr) const { - const MWMechanics::NpcStats &stats = getNpcStats(ptr); - // According to UESP, inventory weight is ignored in werewolf form. Does that include // feather and burden effects? - float weight = 0.0f; - if(!stats.isWerewolf()) - { - weight = getContainerStore(ptr).getWeight(); - weight -= stats.getMagicEffects().get(ESM::MagicEffect::Feather).getMagnitude(); - weight += stats.getMagicEffects().get(ESM::MagicEffect::Burden).getMagnitude(); - if(weight < 0.0f) - weight = 0.0f; - } - - return weight; + return getNpcStats(ptr).isWerewolf() ? 0.0f : Mobile::getEncumbrance(ptr); } bool Npc::apply (const MWWorld::Ptr& ptr, const std::string& id, diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index b12b7b13f..16dd4f8bd 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -1,7 +1,7 @@ #ifndef GAME_MWCLASS_NPC_H #define GAME_MWCLASS_NPC_H -#include "../mwworld/class.hpp" +#include "mobile.hpp" namespace ESM { @@ -10,7 +10,7 @@ namespace ESM namespace MWClass { - class Npc : public MWWorld::Class + class Npc : public Mobile { void ensureCustomData (const MWWorld::Ptr& ptr) const; @@ -51,12 +51,6 @@ namespace MWClass virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; - - virtual void adjustPosition(const MWWorld::Ptr& ptr, bool force) const; - ///< Adjust position to stand on ground. Must be called post model load - /// @param force do this even if the ptr is flying - virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. @@ -70,9 +64,6 @@ namespace MWClass virtual MWWorld::ContainerStore& getContainerStore (const MWWorld::Ptr& ptr) const; ///< Return container store - virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; - ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. @@ -85,8 +76,6 @@ namespace MWClass virtual void onHit(const MWWorld::Ptr &ptr, float damage, bool ishealth, const MWWorld::Ptr &object, const MWWorld::Ptr &attacker, bool successful) const; - virtual void block(const MWWorld::Ptr &ptr) const; - virtual boost::shared_ptr activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const; ///< Generate action for activation @@ -103,9 +92,6 @@ namespace MWClass virtual MWMechanics::Movement& getMovementSettings (const MWWorld::Ptr& ptr) const; ///< Return desired movement. - virtual osg::Vec3f getRotationVector (const MWWorld::Ptr& ptr) const; - ///< Return desired rotations, as euler angles. - virtual float getCapacity (const MWWorld::Ptr& ptr) const; ///< Return total weight that fits into the object. Throws an exception, if the object can't /// hold other objects. From cd5bef958f5fc163fd6609661a4e251e1ffb315c Mon Sep 17 00:00:00 2001 From: Jordan Ayers Date: Mon, 17 Aug 2015 20:32:23 -0500 Subject: [PATCH 2096/3725] Remove dead code from alchemywindow. Also align some braces. --- apps/openmw/mwgui/alchemywindow.cpp | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index 60bd70c04..d12c22e06 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -1,7 +1,5 @@ #include "alchemywindow.hpp" -#include - #include #include "../mwbase/environment.hpp" @@ -67,9 +65,6 @@ namespace MWGui void AlchemyWindow::onCreateButtonClicked(MyGUI::Widget* _sender) { - std::string name = mNameEdit->getCaption(); - boost::algorithm::trim(name); - MWMechanics::Alchemy::Result result = mAlchemy->create (mNameEdit->getCaption ()); if (result == MWMechanics::Alchemy::Result_NoName) @@ -118,7 +113,7 @@ namespace MWGui MWWorld::Ptr ingred = *mIngredients[i]->getUserData(); if (ingred.getRefData().getCount() == 0) removeIngredient(mIngredients[i]); - } + } update(); } @@ -136,9 +131,6 @@ namespace MWGui mNameEdit->setCaption(""); int index = 0; - - mAlchemy->setAlchemist (MWMechanics::getPlayer()); - for (MWMechanics::Alchemy::TToolsIterator iter (mAlchemy->beginTools()); iter!=mAlchemy->endTools() && index (mApparatus.size()); ++iter, ++index) { From 541d7fb4fb9db72ed30bdbebd9d59aa1b810886b Mon Sep 17 00:00:00 2001 From: dteviot Date: Tue, 25 Aug 2015 18:19:16 +1200 Subject: [PATCH 2097/3725] Fixed assorted issues * destructor is virtual * renamed class to Actor * corrected indentation of case statement --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwclass/{mobile.cpp => actor.cpp} | 40 +++++++++---------- apps/openmw/mwclass/{mobile.hpp => actor.hpp} | 10 ++--- apps/openmw/mwclass/creature.hpp | 4 +- apps/openmw/mwclass/npc.cpp | 2 +- apps/openmw/mwclass/npc.hpp | 4 +- 6 files changed, 31 insertions(+), 31 deletions(-) rename apps/openmw/mwclass/{mobile.cpp => actor.cpp} (68%) rename apps/openmw/mwclass/{mobile.hpp => actor.hpp} (89%) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 9054e53c9..2dd16a4e6 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -74,7 +74,7 @@ add_openmw_dir (mwphysics add_openmw_dir (mwclass classes activator creature npc weapon armor potion apparatus book clothing container door - ingredient creaturelevlist itemlevlist light lockpick misc probe repair static mobile + ingredient creaturelevlist itemlevlist light lockpick misc probe repair static actor ) add_openmw_dir (mwmechanics diff --git a/apps/openmw/mwclass/mobile.cpp b/apps/openmw/mwclass/actor.cpp similarity index 68% rename from apps/openmw/mwclass/mobile.cpp rename to apps/openmw/mwclass/actor.cpp index 9cd5510e2..d58047d06 100644 --- a/apps/openmw/mwclass/mobile.cpp +++ b/apps/openmw/mwclass/actor.cpp @@ -1,4 +1,4 @@ -#include "mobile.hpp" +#include "actor.hpp" #include @@ -17,16 +17,16 @@ namespace MWClass { - Mobile::Mobile() {} + Actor::Actor() {} - Mobile::~Mobile() {} + Actor::~Actor() {} - void Mobile::adjustPosition(const MWWorld::Ptr& ptr, bool force) const + void Actor::adjustPosition(const MWWorld::Ptr& ptr, bool force) const { MWBase::Environment::get().getWorld()->adjustPosition(ptr, force); } - void Mobile::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const + void Actor::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const { if (!model.empty()) { @@ -37,7 +37,7 @@ namespace MWClass MWBase::Environment::get().getMechanicsManager()->add(ptr); } - void Mobile::block(const MWWorld::Ptr &ptr) const + void Actor::block(const MWWorld::Ptr &ptr) const { MWWorld::InventoryStore& inv = getInventoryStore(ptr); MWWorld::ContainerStoreIterator shield = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft); @@ -47,26 +47,26 @@ namespace MWClass MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); switch (shield->getClass().getEquipmentSkill(*shield)) { - case ESM::Skill::LightArmor: - sndMgr->playSound3D(ptr, "Light Armor Hit", 1.0f, 1.0f); - break; - case ESM::Skill::MediumArmor: - sndMgr->playSound3D(ptr, "Medium Armor Hit", 1.0f, 1.0f); - break; - case ESM::Skill::HeavyArmor: - sndMgr->playSound3D(ptr, "Heavy Armor Hit", 1.0f, 1.0f); - break; - default: - return; + case ESM::Skill::LightArmor: + sndMgr->playSound3D(ptr, "Light Armor Hit", 1.0f, 1.0f); + break; + case ESM::Skill::MediumArmor: + sndMgr->playSound3D(ptr, "Medium Armor Hit", 1.0f, 1.0f); + break; + case ESM::Skill::HeavyArmor: + sndMgr->playSound3D(ptr, "Heavy Armor Hit", 1.0f, 1.0f); + break; + default: + return; } } - bool Mobile::hasToolTip(const MWWorld::Ptr& ptr) const + bool Actor::hasToolTip(const MWWorld::Ptr& ptr) const { return !ptr.getClass().getCreatureStats(ptr).getAiSequence().isInCombat() || getCreatureStats(ptr).isDead(); } - osg::Vec3f Mobile::getRotationVector(const MWWorld::Ptr& ptr) const + osg::Vec3f Actor::getRotationVector(const MWWorld::Ptr& ptr) const { MWMechanics::Movement &movement = getMovementSettings(ptr); osg::Vec3f vec(movement.mRotation[0], movement.mRotation[1], movement.mRotation[2]); @@ -76,7 +76,7 @@ namespace MWClass return vec; } - float Mobile::getEncumbrance(const MWWorld::Ptr& ptr) const + float Actor::getEncumbrance(const MWWorld::Ptr& ptr) const { float weight = getContainerStore(ptr).getWeight(); const MWMechanics::MagicEffects& effects = getCreatureStats(ptr).getMagicEffects(); diff --git a/apps/openmw/mwclass/mobile.hpp b/apps/openmw/mwclass/actor.hpp similarity index 89% rename from apps/openmw/mwclass/mobile.hpp rename to apps/openmw/mwclass/actor.hpp index 5b1eeae9d..3f795dff9 100644 --- a/apps/openmw/mwclass/mobile.hpp +++ b/apps/openmw/mwclass/actor.hpp @@ -11,14 +11,14 @@ namespace ESM namespace MWClass { /// \brief Class holding functionality common to Creature and NPC - class Mobile : public MWWorld::Class + class Actor : public MWWorld::Class { protected: - Mobile(); + Actor(); public: - ~Mobile(); + virtual ~Actor(); virtual void adjustPosition(const MWWorld::Ptr& ptr, bool force) const; ///< Adjust position to stand on ground. Must be called post model load @@ -39,8 +39,8 @@ namespace MWClass /// effects). Throws an exception, if the object can't hold other objects. // not implemented - Mobile(const Mobile&); - Mobile& operator= (const Mobile&); + Actor(const Actor&); + Actor& operator= (const Actor&); }; } diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index 3881c1d40..c4ea09255 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -1,7 +1,7 @@ #ifndef GAME_MWCLASS_CREATURE_H #define GAME_MWCLASS_CREATURE_H -#include "mobile.hpp" +#include "actor.hpp" namespace ESM { @@ -10,7 +10,7 @@ namespace ESM namespace MWClass { - class Creature : public Mobile + class Creature : public Actor { void ensureCustomData (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index bd1579d9e..9fa2cc603 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -946,7 +946,7 @@ namespace MWClass { // According to UESP, inventory weight is ignored in werewolf form. Does that include // feather and burden effects? - return getNpcStats(ptr).isWerewolf() ? 0.0f : Mobile::getEncumbrance(ptr); + return getNpcStats(ptr).isWerewolf() ? 0.0f : Actor::getEncumbrance(ptr); } bool Npc::apply (const MWWorld::Ptr& ptr, const std::string& id, diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index 16dd4f8bd..d919131db 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -1,7 +1,7 @@ #ifndef GAME_MWCLASS_NPC_H #define GAME_MWCLASS_NPC_H -#include "mobile.hpp" +#include "actor.hpp" namespace ESM { @@ -10,7 +10,7 @@ namespace ESM namespace MWClass { - class Npc : public Mobile + class Npc : public Actor { void ensureCustomData (const MWWorld::Ptr& ptr) const; From 40753aa9a3759e247b1fc907f5ef61af2656d533 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 25 Aug 2015 08:43:03 +0200 Subject: [PATCH 2098/3725] simplifying merge stage --- apps/opencs/model/tools/mergestages.hpp | 25 ++++--------------------- 1 file changed, 4 insertions(+), 21 deletions(-) diff --git a/apps/opencs/model/tools/mergestages.hpp b/apps/opencs/model/tools/mergestages.hpp index af7f06d60..c0ed16787 100644 --- a/apps/opencs/model/tools/mergestages.hpp +++ b/apps/opencs/model/tools/mergestages.hpp @@ -35,8 +35,6 @@ namespace CSMTools MergeState& mState; Collection& (CSMWorld::Data::*mAccessor)(); - static const int stepSize = 1000; - public: MergeIdCollectionStage (MergeState& state, Collection& (CSMWorld::Data::*accessor)()); @@ -56,16 +54,7 @@ namespace CSMTools template int MergeIdCollectionStage::setup() { - const Collection& source = (mState.mSource.getData().*mAccessor)(); - - int size = source.getSize(); - - int steps = size / stepSize; - - if (size % stepSize) - ++steps; - - return steps; + return (mState.mSource.getData().*mAccessor)().getSize(); } template @@ -74,16 +63,10 @@ namespace CSMTools const Collection& source = (mState.mSource.getData().*mAccessor)(); Collection& target = (mState.mTarget->getData().*mAccessor)(); - int begin = stage * stepSize; - int end = std::min ((stage+1) * stepSize, source.getSize()); - - for (int i=begin; i& record = source.getRecord (i); + const CSMWorld::Record& record = source.getRecord (stage); - if (!record.isDeleted()) - target.appendRecord (CSMWorld::Record (CSMWorld::RecordBase::State_BaseOnly, &record.get())); - } + if (!record.isDeleted()) + target.appendRecord (CSMWorld::Record (CSMWorld::RecordBase::State_BaseOnly, &record.get())); } } From 9cf793c0b519143fd7d3ac3cfb7beb82f65b72f3 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 25 Aug 2015 11:39:43 +0200 Subject: [PATCH 2099/3725] silenced a warning --- apps/opencs/model/doc/document.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 2cff89389..0e2d4e7d1 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -2256,7 +2256,7 @@ CSMDoc::Document::Document (const VFS::Manager* vfs, const Files::ConfigurationM mSavingOperation (*this, mProjectPath, encoding), mSaving (&mSavingOperation), mResDir(resDir), - mRunner (mProjectPath), mIdCompletionManager(mData), mDirty (false) + mRunner (mProjectPath), mDirty (false), mIdCompletionManager(mData) { if (mContentFiles.empty()) throw std::runtime_error ("Empty content file sequence"); From f95950e8d815997da34eb9939b81cd27afb62dbb Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 25 Aug 2015 11:54:16 +0200 Subject: [PATCH 2100/3725] merge referenceables table --- apps/opencs/model/tools/mergeoperation.cpp | 3 ++- apps/opencs/model/tools/mergestages.cpp | 14 ++++++++++++++ apps/opencs/model/tools/mergestages.hpp | 16 ++++++++++++++++ apps/opencs/model/world/refidcollection.cpp | 5 +++++ apps/opencs/model/world/refidcollection.hpp | 1 + apps/opencs/model/world/refiddata.cpp | 11 +++++++++++ apps/opencs/model/world/refiddata.hpp | 6 ++---- 7 files changed, 51 insertions(+), 5 deletions(-) diff --git a/apps/opencs/model/tools/mergeoperation.cpp b/apps/opencs/model/tools/mergeoperation.cpp index d010e343b..0f128e86e 100644 --- a/apps/opencs/model/tools/mergeoperation.cpp +++ b/apps/opencs/model/tools/mergeoperation.cpp @@ -34,8 +34,9 @@ CSMTools::MergeOperation::MergeOperation (CSMDoc::Document& document, ToUTF8::Fr appendStage (new MergeIdCollectionStage > (mState, &CSMWorld::Data::getPathgrids)); appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getTopicInfos)); appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getJournalInfos)); + appendStage (new MergeRefIdsStage (mState)); - /// \todo Referencables, References, Land, LandTextures + /// \todo References, Land, LandTextures } void CSMTools::MergeOperation::setTarget (std::auto_ptr document) diff --git a/apps/opencs/model/tools/mergestages.cpp b/apps/opencs/model/tools/mergestages.cpp index 776808b26..d8bd93824 100644 --- a/apps/opencs/model/tools/mergestages.cpp +++ b/apps/opencs/model/tools/mergestages.cpp @@ -39,3 +39,17 @@ void CSMTools::FinishMergedDocumentStage::perform (int stage, CSMDoc::Messages& mState.mCompleted = true; } + + +CSMTools::MergeRefIdsStage::MergeRefIdsStage (MergeState& state) : mState (state) {} + +int CSMTools::MergeRefIdsStage::setup() +{ + return mState.mSource.getData().getReferenceables().getSize(); +} + +void CSMTools::MergeRefIdsStage::perform (int stage, CSMDoc::Messages& messages) +{ + mState.mSource.getData().getReferenceables().copyTo ( + stage, mState.mTarget->getData().getReferenceables()); +} diff --git a/apps/opencs/model/tools/mergestages.hpp b/apps/opencs/model/tools/mergestages.hpp index c0ed16787..308ebe1c3 100644 --- a/apps/opencs/model/tools/mergestages.hpp +++ b/apps/opencs/model/tools/mergestages.hpp @@ -68,6 +68,22 @@ namespace CSMTools if (!record.isDeleted()) target.appendRecord (CSMWorld::Record (CSMWorld::RecordBase::State_BaseOnly, &record.get())); } + + + class MergeRefIdsStage : public CSMDoc::Stage + { + MergeState& mState; + + public: + + MergeRefIdsStage (MergeState& state); + + virtual int setup(); + ///< \return number of steps + + virtual void perform (int stage, CSMDoc::Messages& messages); + ///< Messages resulting from this stage will be appended to \a messages. + }; } #endif diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 5495926b4..c50f8c1f1 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -914,3 +914,8 @@ const CSMWorld::NestedRefIdAdapterBase& CSMWorld::RefIdCollection::getNestedAdap } throw std::runtime_error("No such column in the nestedadapters"); } + +void CSMWorld::RefIdCollection::copyTo (int index, RefIdCollection& target) const +{ + mData.copyTo (index, target.mData); +} diff --git a/apps/opencs/model/world/refidcollection.hpp b/apps/opencs/model/world/refidcollection.hpp index 4d511d12d..de5a709c6 100644 --- a/apps/opencs/model/world/refidcollection.hpp +++ b/apps/opencs/model/world/refidcollection.hpp @@ -138,6 +138,7 @@ namespace CSMWorld void save (int index, ESM::ESMWriter& writer) const; const RefIdData& getDataSet() const; //I can't figure out a better name for this one :( + void copyTo (int index, RefIdCollection& target) const; }; } diff --git a/apps/opencs/model/world/refiddata.cpp b/apps/opencs/model/world/refiddata.cpp index 7f5c25f36..70d968efb 100644 --- a/apps/opencs/model/world/refiddata.cpp +++ b/apps/opencs/model/world/refiddata.cpp @@ -358,3 +358,14 @@ void CSMWorld::RefIdData::insertRecord(CSMWorld::RecordBase& record, CSMWorld::U mIndex.insert (std::make_pair (Misc::StringUtils::lowerCase (id), LocalIndex (iter->second->getSize()-1, type))); } + +void CSMWorld::RefIdData::copyTo (int index, RefIdData& target) const +{ + LocalIndex localIndex = globalToLocalIndex (index); + + RefIdDataContainerBase *source = mRecordContainers.find (localIndex.second)->second; + + std::string id = source->getId (localIndex.first); + + target.insertRecord (source->getRecord (localIndex.first), localIndex.second, id); +} diff --git a/apps/opencs/model/world/refiddata.hpp b/apps/opencs/model/world/refiddata.hpp index 85d16a6eb..4507f6028 100644 --- a/apps/opencs/model/world/refiddata.hpp +++ b/apps/opencs/model/world/refiddata.hpp @@ -252,11 +252,9 @@ namespace CSMWorld const RefIdDataContainer& getProbes() const; const RefIdDataContainer& getRepairs() const; const RefIdDataContainer& getStatics() const; + + void copyTo (int index, RefIdData& target) const; }; } #endif - - - - From 845cafd61c12142a353119a6304845370037d7a5 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 25 Aug 2015 12:40:40 +0200 Subject: [PATCH 2101/3725] fixed record state issues after merge --- apps/opencs/model/tools/mergestages.hpp | 2 +- apps/opencs/model/world/refiddata.cpp | 7 +++++-- apps/opencs/model/world/refiddata.hpp | 3 ++- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/apps/opencs/model/tools/mergestages.hpp b/apps/opencs/model/tools/mergestages.hpp index 308ebe1c3..5c2243d43 100644 --- a/apps/opencs/model/tools/mergestages.hpp +++ b/apps/opencs/model/tools/mergestages.hpp @@ -66,7 +66,7 @@ namespace CSMTools const CSMWorld::Record& record = source.getRecord (stage); if (!record.isDeleted()) - target.appendRecord (CSMWorld::Record (CSMWorld::RecordBase::State_BaseOnly, &record.get())); + target.appendRecord (CSMWorld::Record (CSMWorld::RecordBase::State_ModifiedOnly, 0, &record.get())); } diff --git a/apps/opencs/model/world/refiddata.cpp b/apps/opencs/model/world/refiddata.cpp index 70d968efb..14f580d39 100644 --- a/apps/opencs/model/world/refiddata.cpp +++ b/apps/opencs/model/world/refiddata.cpp @@ -2,6 +2,7 @@ #include "refiddata.hpp" #include +#include #include @@ -345,7 +346,7 @@ const CSMWorld::RefIdDataContainer< ESM::Static >& CSMWorld::RefIdData::getStati return mStatics; } -void CSMWorld::RefIdData::insertRecord(CSMWorld::RecordBase& record, CSMWorld::UniversalId::Type type, const std::string& id) +void CSMWorld::RefIdData::insertRecord (CSMWorld::RecordBase& record, CSMWorld::UniversalId::Type type, const std::string& id) { std::map::iterator iter = mRecordContainers.find (type); @@ -367,5 +368,7 @@ void CSMWorld::RefIdData::copyTo (int index, RefIdData& target) const std::string id = source->getId (localIndex.first); - target.insertRecord (source->getRecord (localIndex.first), localIndex.second, id); + std::auto_ptr newRecord (source->getRecord (localIndex.first).modifiedCopy()); + + target.insertRecord (*newRecord, localIndex.second, id); } diff --git a/apps/opencs/model/world/refiddata.hpp b/apps/opencs/model/world/refiddata.hpp index 4507f6028..8909ae4fb 100644 --- a/apps/opencs/model/world/refiddata.hpp +++ b/apps/opencs/model/world/refiddata.hpp @@ -210,7 +210,8 @@ namespace CSMWorld void erase (int index, int count); - void insertRecord(CSMWorld::RecordBase& record, CSMWorld::UniversalId::Type type, const std::string& id); + void insertRecord (CSMWorld::RecordBase& record, CSMWorld::UniversalId::Type type, + const std::string& id); const RecordBase& getRecord (const LocalIndex& index) const; From a97a632aa76c3b7499ae170b689676d2f32b8550 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 26 Aug 2015 17:21:24 +0200 Subject: [PATCH 2102/3725] merge references tables --- apps/opencs/model/tools/mergeoperation.cpp | 3 +- apps/opencs/model/tools/mergestages.cpp | 34 ++++++++++++++++++++++ apps/opencs/model/tools/mergestages.hpp | 18 +++++++++++- 3 files changed, 53 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/tools/mergeoperation.cpp b/apps/opencs/model/tools/mergeoperation.cpp index 0f128e86e..f9a89aaa1 100644 --- a/apps/opencs/model/tools/mergeoperation.cpp +++ b/apps/opencs/model/tools/mergeoperation.cpp @@ -35,8 +35,9 @@ CSMTools::MergeOperation::MergeOperation (CSMDoc::Document& document, ToUTF8::Fr appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getTopicInfos)); appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getJournalInfos)); appendStage (new MergeRefIdsStage (mState)); + appendStage (new MergeReferencesStage (mState)); - /// \todo References, Land, LandTextures + /// \todo Land, LandTextures } void CSMTools::MergeOperation::setTarget (std::auto_ptr document) diff --git a/apps/opencs/model/tools/mergestages.cpp b/apps/opencs/model/tools/mergestages.cpp index d8bd93824..80f16ec14 100644 --- a/apps/opencs/model/tools/mergestages.cpp +++ b/apps/opencs/model/tools/mergestages.cpp @@ -1,6 +1,8 @@ #include "mergestages.hpp" +#include + #include "mergestate.hpp" #include "../doc/document.hpp" @@ -53,3 +55,35 @@ void CSMTools::MergeRefIdsStage::perform (int stage, CSMDoc::Messages& messages) mState.mSource.getData().getReferenceables().copyTo ( stage, mState.mTarget->getData().getReferenceables()); } + + +CSMTools::MergeReferencesStage::MergeReferencesStage (MergeState& state) +: mState (state) +{} + +int CSMTools::MergeReferencesStage::setup() +{ + mIndex.clear(); + return mState.mSource.getData().getReferences().getSize(); +} + +void CSMTools::MergeReferencesStage::perform (int stage, CSMDoc::Messages& messages) +{ + const CSMWorld::Record& record = + mState.mSource.getData().getReferences().getRecord (stage); + + if (!record.isDeleted()) + { + CSMWorld::CellRef ref = record.get(); + + ref.mOriginalCell = ref.mCell; + + ref.mRefNum.mIndex = mIndex[Misc::StringUtils::lowerCase (ref.mCell)]++; + ref.mRefNum.mContentFile = 0; + + CSMWorld::Record newRecord ( + CSMWorld::RecordBase::State_ModifiedOnly, 0, &ref); + + mState.mTarget->getData().getReferences().appendRecord (newRecord); + } +} diff --git a/apps/opencs/model/tools/mergestages.hpp b/apps/opencs/model/tools/mergestages.hpp index 5c2243d43..e1cc17a3e 100644 --- a/apps/opencs/model/tools/mergestages.hpp +++ b/apps/opencs/model/tools/mergestages.hpp @@ -2,6 +2,7 @@ #define CSM_TOOLS_MERGESTAGES_H #include +#include #include @@ -69,7 +70,6 @@ namespace CSMTools target.appendRecord (CSMWorld::Record (CSMWorld::RecordBase::State_ModifiedOnly, 0, &record.get())); } - class MergeRefIdsStage : public CSMDoc::Stage { MergeState& mState; @@ -84,6 +84,22 @@ namespace CSMTools virtual void perform (int stage, CSMDoc::Messages& messages); ///< Messages resulting from this stage will be appended to \a messages. }; + + class MergeReferencesStage : public CSMDoc::Stage + { + MergeState& mState; + std::map mIndex; + + public: + + MergeReferencesStage (MergeState& state); + + virtual int setup(); + ///< \return number of steps + + virtual void perform (int stage, CSMDoc::Messages& messages); + ///< Messages resulting from this stage will be appended to \a messages. + }; } #endif From 54fa5273dc2d95f79368a82f815519b1c6d53fde Mon Sep 17 00:00:00 2001 From: slothlife Date: Wed, 26 Aug 2015 22:59:21 -0500 Subject: [PATCH 2103/3725] Refactor weather transitions to act more like MW Fixed several issues: * Waiting/jail time/training all now properly skip remaining transitions * ChangeWeather no longer permanently sets the region's weather * ChangeWeather being called during a transition now correctly queues up another transition * Corrected transition delta and factor calculations * ModRegion settings are now saved --- apps/essimporter/converter.hpp | 64 +- apps/openmw/engine.cpp | 3 +- apps/openmw/mwbase/world.hpp | 3 + apps/openmw/mwworld/weather.cpp | 1036 +++++++++++++++++------------- apps/openmw/mwworld/weather.hpp | 151 +++-- apps/openmw/mwworld/worldimp.cpp | 39 +- apps/openmw/mwworld/worldimp.hpp | 3 + components/esm/weatherstate.cpp | 131 ++-- components/esm/weatherstate.hpp | 63 +- 9 files changed, 832 insertions(+), 661 deletions(-) diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index fb8fb8c9f..4bad5e23b 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -507,60 +507,40 @@ class ConvertGAME : public Converter public: ConvertGAME() : mHasGame(false) {} - std::string toString(int weatherId) - { - switch (weatherId) - { - case 0: - return "clear"; - case 1: - return "cloudy"; - case 2: - return "foggy"; - case 3: - return "overcast"; - case 4: - return "rain"; - case 5: - return "thunderstorm"; - case 6: - return "ashstorm"; - case 7: - return "blight"; - case 8: - return "snow"; - case 9: - return "blizzard"; - case -1: - return ""; - default: - { - std::stringstream error; - error << "unknown weather id: " << weatherId; - throw std::runtime_error(error.str()); - } - } - } - virtual void read(ESM::ESMReader &esm) { mGame.load(esm); mHasGame = true; } + int validateWeatherID(int weatherID) + { + if(weatherID >= -1 && weatherID < 10) + { + return weatherID; + } + else + { + std::stringstream error; + error << "Invalid weather ID:" << weatherID << std::endl; + throw std::runtime_error(error.str()); + } + } + virtual void write(ESM::ESMWriter &esm) { if (!mHasGame) return; esm.startRecord(ESM::REC_WTHR); ESM::WeatherState weather; - weather.mCurrentWeather = toString(mGame.mGMDT.mCurrentWeather); - weather.mNextWeather = toString(mGame.mGMDT.mNextWeather); - weather.mRemainingTransitionTime = mGame.mGMDT.mWeatherTransition/100.f*(0.015f*24*3600); - weather.mHour = mContext->mHour; - weather.mWindSpeed = 0.f; - weather.mTimePassed = 0.0; - weather.mFirstUpdate = false; + weather.mTimePassed = 0.0f; + weather.mFastForward = false; + weather.mWeatherUpdateTime = mGame.mGMDT.mTimeOfNextTransition - mContext->mHour; + weather.mTransitionFactor = 1 - (mGame.mGMDT.mWeatherTransition / 100.0f); + weather.mCurrentWeather = validateWeatherID(mGame.mGMDT.mCurrentWeather); + weather.mNextWeather = validateWeatherID(mGame.mGMDT.mNextWeather); + weather.mQueuedWeather = -1; + // TODO: Determine how ModRegion modifiers are saved in Morrowind. weather.save(esm); esm.endRecord(ESM::REC_WTHR); } diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index e183107ec..6c95700b3 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -128,8 +128,7 @@ void OMW::Engine::frame(float frametime) } if (!guiActive) - mEnvironment.getWorld()->advanceTime( - frametime*mEnvironment.getWorld()->getTimeScaleFactor()/3600); + mEnvironment.getWorld()->advanceTimeByFrame(frametime); } osg::Timer_t afterScriptTick = osg::Timer::instance()->tick(); diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index d345cdf7e..636370342 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -188,6 +188,9 @@ namespace MWBase virtual void advanceTime (double hours) = 0; ///< Advance in-game time. + virtual void advanceTimeByFrame (double frametime) = 0; + ///< Advance in-game time by the duration of a frame. + virtual void setHour (double hour) = 0; ///< Set in-game time hour. diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index cc5b726af..8799ae57c 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -28,6 +28,8 @@ using namespace MWWorld; namespace { + static const int invalidWeatherID = -1; + float lerp (float x, float y, float factor) { return x * (1-factor) + y * factor; @@ -87,12 +89,11 @@ Max Raindrops=650 ? */ } -float Weather::transitionSeconds() const +float Weather::transitionDelta() const { - // This formula is reversed from Morrowind by observing different Transition Delta values with Clouds - // Maximum Percent set to 1.0, and watching for when the light from the sun was no longer visible. - static const float deltasPerHour = 0.00835; - return (deltasPerHour / mTransitionDelta) * 60.0f * 60.0f; + // Transition Delta describes how quickly transitioning to the weather in question will take, in Hz. Note that the + // measurement is in real time, not in-game time. + return mTransitionDelta; } float Weather::cloudBlendFactor(float transitionRatio) const @@ -101,6 +102,89 @@ float Weather::cloudBlendFactor(float transitionRatio) const return transitionRatio / mCloudsMaximumPercent; } +RegionWeather::RegionWeather(const ESM::Region& region) + : mWeather(invalidWeatherID) + , mChances() +{ + mChances.reserve(10); + mChances.push_back(region.mData.mClear); + mChances.push_back(region.mData.mCloudy); + mChances.push_back(region.mData.mFoggy); + mChances.push_back(region.mData.mOvercast); + mChances.push_back(region.mData.mRain); + mChances.push_back(region.mData.mThunder); + mChances.push_back(region.mData.mAsh); + mChances.push_back(region.mData.mBlight); + mChances.push_back(region.mData.mA); + mChances.push_back(region.mData.mB); +} + +RegionWeather::RegionWeather(const ESM::RegionWeatherState& state) + : mWeather(state.mWeather) + , mChances(state.mChances) +{ +} + +RegionWeather::operator ESM::RegionWeatherState() const +{ + return ESM::RegionWeatherState { mWeather, mChances }; +} + +void RegionWeather::setChances(const std::vector& chances) +{ + if(mChances.size() < chances.size()) + { + mChances.reserve(chances.size()); + } + + std::vector::const_iterator it = chances.begin(); + for(size_t i = 0; it != chances.end(); ++it, ++i) + { + mChances[i] = *it; + } + + // Regional weather no longer supports the current type, select a new weather pattern. + if((static_cast(mWeather) >= mChances.size()) || (mChances[mWeather] == 0)) + { + chooseNewWeather(); + } +} + +void RegionWeather::setWeather(int weatherID) +{ + mWeather = weatherID; +} + +int RegionWeather::getWeather() +{ + // If the region weather was already set (by ChangeWeather, or by a previous call) then just return that value. + // Note that the region weather will be expired periodically when the weather update timer expires. + if(mWeather == invalidWeatherID) + { + chooseNewWeather(); + } + + return mWeather; +} + +void RegionWeather::chooseNewWeather() +{ + // All probabilities must add to 100 (responsibility of the user). + // If chances A and B has values 30 and 70 then by generating 100 numbers 1..100, 30% will be lesser or equal 30 + // and 70% will be greater than 30 (in theory). + int chance = Misc::Rng::rollDice(100) + 1; // 1..100 + int sum = 0; + int i = 0; + for(; static_cast(i) < mChances.size(); ++i) + { + sum += mChances[i]; + if(chance <= sum) + break; + } + + mWeather = i; +} + MoonModel::MoonModel(const std::string& name, const MWWorld::Fallback& fallback) : mFadeInStart(fallback.getFallbackFloat("Moons_" + name + "_Fade_In_Start")) , mFadeInFinish(fallback.getFallbackFloat("Moons_" + name + "_Fade_In_Finish")) @@ -118,22 +202,22 @@ MoonModel::MoonModel(const std::string& name, const MWWorld::Fallback& fallback) mSpeed = std::min(mSpeed, 180.0f / 23.0f); } -MWRender::MoonState MoonModel::calculateState(unsigned int daysPassed, float gameHour) const +MWRender::MoonState MoonModel::calculateState(const TimeStamp& gameTime) const { - float rotationFromHorizon = angle(daysPassed, gameHour); + float rotationFromHorizon = angle(gameTime); MWRender::MoonState state = - { - rotationFromHorizon, - mAxisOffset, // Reverse engineered from Morrowind's scene graph rotation matrices. - static_cast(phase(daysPassed, gameHour)), - shadowBlend(rotationFromHorizon), - earlyMoonShadowAlpha(rotationFromHorizon) * hourlyAlpha(gameHour) - }; + { + rotationFromHorizon, + mAxisOffset, // Reverse engineered from Morrowind's scene graph rotation matrices. + static_cast(phase(gameTime)), + shadowBlend(rotationFromHorizon), + earlyMoonShadowAlpha(rotationFromHorizon) * hourlyAlpha(gameTime.getHour()) + }; return state; } -inline float MoonModel::angle(unsigned int daysPassed, float gameHour) const +inline float MoonModel::angle(const TimeStamp& gameTime) const { // Morrowind's moons start travel on one side of the horizon (let's call it H-rise) and travel 180 degrees to the // opposite horizon (let's call it H-set). Upon reaching H-set, they reset to H-rise until the next moon rise. @@ -142,25 +226,25 @@ inline float MoonModel::angle(unsigned int daysPassed, float gameHour) const // 1. Moon rises and then sets in one day. // 2. Moon sets and doesn't rise in one day (occurs when the moon rise hour is >= 24). // 3. Moon sets and then rises in one day. - float moonRiseHourToday = moonRiseHour(daysPassed); + float moonRiseHourToday = moonRiseHour(gameTime.getDay()); float moonRiseAngleToday = 0; - if(gameHour < moonRiseHourToday) + if(gameTime.getHour() < moonRiseHourToday) { - float moonRiseHourYesterday = moonRiseHour(daysPassed - 1); + float moonRiseHourYesterday = moonRiseHour(gameTime.getDay() - 1); if(moonRiseHourYesterday < 24) { float moonRiseAngleYesterday = rotation(24 - moonRiseHourYesterday); if(moonRiseAngleYesterday < 180) { // The moon rose but did not set yesterday, so accumulate yesterday's angle with how much we've travelled today. - moonRiseAngleToday = rotation(gameHour) + moonRiseAngleYesterday; + moonRiseAngleToday = rotation(gameTime.getHour()) + moonRiseAngleYesterday; } } } else { - moonRiseAngleToday = rotation(gameHour - moonRiseHourToday); + moonRiseAngleToday = rotation(gameTime.getHour() - moonRiseHourToday); } if(moonRiseAngleToday >= 180) @@ -194,17 +278,17 @@ inline float MoonModel::rotation(float hours) const return 15.0f * mSpeed * hours; } -inline unsigned int MoonModel::phase(unsigned int daysPassed, float gameHour) const +inline unsigned int MoonModel::phase(const TimeStamp& gameTime) const { // Morrowind starts with a full moon on 16 Last Seed and then begins to wane 17 Last Seed, working on 3 day phase cycle. // Note: this is an internal helper, and as such we don't want to return MWRender::MoonState::Phase since we can't // forward declare it (C++11 strongly typed enums solve this). // If the moon didn't rise yet today, use yesterday's moon phase. - if(gameHour < moonRiseHour(daysPassed)) - return (daysPassed / 3) % 8; + if(gameTime.getHour() < moonRiseHour(gameTime.getDay())) + return (gameTime.getDay() / 3) % 8; else - return ((daysPassed + 1) / 3) % 8; + return ((gameTime.getDay() + 1) / 3) % 8; } inline float MoonModel::shadowBlend(float angle) const @@ -270,51 +354,68 @@ inline float MoonModel::earlyMoonShadowAlpha(float angle) const return 0.0f; } -WeatherManager::WeatherManager(MWRender::RenderingManager* rendering, MWWorld::Fallback* fallback, MWWorld::ESMStore* store) : - mHour(14), mWindSpeed(0.f), mIsStorm(false), mStormDirection(0,1,0), mStore(store), - mRendering(rendering), mCurrentWeather("clear"), mNextWeather(""), mFirstUpdate(true), - mRemainingTransitionTime(0), mThunderFlash(0), mThunderChance(0), mThunderChanceNeeded(50), - mTimePassed(0), mWeatherUpdateTime(0), mThunderSoundDelay(0), - mMasser("Masser", *fallback), mSecunda("Secunda", *fallback) -{ - //Globals - mThunderSoundID0 = fallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_0"); - mThunderSoundID1 = fallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_1"); - mThunderSoundID2 = fallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_2"); - mThunderSoundID3 = fallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_3"); - mSunriseTime = fallback->getFallbackFloat("Weather_Sunrise_Time"); - mSunsetTime = fallback->getFallbackFloat("Weather_Sunset_Time"); - mSunriseDuration = fallback->getFallbackFloat("Weather_Sunrise_Duration"); - mSunsetDuration = fallback->getFallbackFloat("Weather_Sunset_Duration"); - mHoursBetweenWeatherChanges = fallback->getFallbackFloat("Weather_Hours_Between_Weather_Changes"); - mWeatherUpdateTime = mHoursBetweenWeatherChanges * 3600; - mThunderFrequency = fallback->getFallbackFloat("Weather_Thunderstorm_Thunder_Frequency"); - mThunderThreshold = fallback->getFallbackFloat("Weather_Thunderstorm_Thunder_Threshold"); - mThunderSoundDelay = 0.25; - - mRainSpeed = fallback->getFallbackFloat("Weather_Precip_Gravity"); - - //Some useful values - /* TODO: Use pre-sunrise_time, pre-sunset_time, - * post-sunrise_time, and post-sunset_time to better - * describe sunrise/sunset time. - * These values are fallbacks attached to weather. - */ - mNightStart = mSunsetTime + mSunsetDuration; - mNightEnd = mSunriseTime - 0.5f; - mDayStart = mSunriseTime + mSunriseDuration; - mDayEnd = mSunsetTime; - - addWeather("Clear", *fallback); - addWeather("Cloudy", *fallback); - addWeather("Foggy", *fallback); - addWeather("Overcast", *fallback); - addWeather("Rain", *fallback, "rain"); - addWeather("Thunderstorm", *fallback, "rain heavy"); - addWeather("Ashstorm", *fallback, "ashstorm", "meshes\\ashcloud.nif"); - addWeather("Blight", *fallback, "blight", "meshes\\blightcloud.nif"); - addWeather("Snow", *fallback, "", "meshes\\snow.nif"); - addWeather("Blizzard", *fallback, "BM Blizzard", "meshes\\blizzard.nif"); +WeatherManager::WeatherManager(MWRender::RenderingManager& rendering, const MWWorld::Fallback& fallback, MWWorld::ESMStore& store) + : mStore(store) + , mRendering(rendering) + , mSunriseTime(fallback.getFallbackFloat("Weather_Sunrise_Time")) + , mSunsetTime(fallback.getFallbackFloat("Weather_Sunset_Time")) + , mSunriseDuration(fallback.getFallbackFloat("Weather_Sunrise_Duration")) + , mSunsetDuration(fallback.getFallbackFloat("Weather_Sunset_Duration")) + , mNightStart(mSunsetTime + mSunsetDuration) + , mNightEnd(mSunriseTime - 0.5f) + , mDayStart(mSunriseTime + mSunriseDuration) + , mDayEnd(mSunsetTime) + , mHoursBetweenWeatherChanges(fallback.getFallbackFloat("Weather_Hours_Between_Weather_Changes")) + , mRainSpeed(fallback.getFallbackFloat("Weather_Precip_Gravity")) + , mWeatherSettings() + , mMasser("Masser", fallback) + , mSecunda("Secunda", fallback) + , mThunderSoundID0(fallback.getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_0")) + , mThunderSoundID1(fallback.getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_1")) + , mThunderSoundID2(fallback.getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_2")) + , mThunderSoundID3(fallback.getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_3")) + , mThunderFrequency(fallback.getFallbackFloat("Weather_Thunderstorm_Thunder_Frequency")) + , mThunderThreshold(fallback.getFallbackFloat("Weather_Thunderstorm_Thunder_Threshold")) + , mWindSpeed(0.f) + , mIsStorm(false) + , mStormDirection(0,1,0) + , mThunderSoundDelay(0.25) + , mThunderFlash(0) + , mThunderChance(0) + , mThunderChanceNeeded(50) + , mCurrentRegion() + , mTimePassed(0) + , mFastForward(false) + , mWeatherUpdateTime(mHoursBetweenWeatherChanges) + , mTransitionFactor(0) + , mCurrentWeather(0) + , mNextWeather(0) + , mQueuedWeather(0) + , mRegions() + , mResult() + , mAmbientSound() + , mPlayingSoundID() +{ + mWeatherSettings.reserve(10); + addWeather("Clear", fallback); + addWeather("Cloudy", fallback); + addWeather("Foggy", fallback); + addWeather("Overcast", fallback); + addWeather("Rain", fallback, "rain"); + addWeather("Thunderstorm", fallback, "rain heavy"); + addWeather("Ashstorm", fallback, "ashstorm", "meshes\\ashcloud.nif"); + addWeather("Blight", fallback, "blight", "meshes\\blightcloud.nif"); + addWeather("Snow", fallback, "", "meshes\\snow.nif"); + addWeather("Blizzard", fallback, "BM Blizzard", "meshes\\blizzard.nif"); + + Store::iterator it = store.get().begin(); + for(; it != store.get().end(); ++it) + { + std::string regionID = Misc::StringUtils::lowerCase(it->mId); + mRegions.insert(std::make_pair(regionID, RegionWeather(*it))); + } + + forceWeather(0); } WeatherManager::~WeatherManager() @@ -322,250 +423,127 @@ WeatherManager::~WeatherManager() stopSounds(); } -void WeatherManager::setWeather(const std::string& weather, bool instant) +void WeatherManager::changeWeather(const std::string& regionID, const unsigned int weatherID) { - if (weather == mCurrentWeather && mNextWeather == "") - { - mFirstUpdate = false; - return; - } - - if (instant || mFirstUpdate) + // In Morrowind, this seems to have the following behavior, when applied to the current region: + // - When there is no transition in progress, start transitioning to the new weather. + // - If there is a transition in progress, queue up the transition and process it when the current one completes. + // - If there is a transition in progress, and a queued transition, overwrite the queued transition. + // - If multiple calls to ChangeWeather are made while paused (console up), only the last call will be used, + // meaning that if there was no transition in progress, only the last ChangeWeather will be processed. + // If the region isn't current, Morrowind will store the new weather for the region in question. + + if(weatherID < mWeatherSettings.size()) { - mNextWeather = ""; - mCurrentWeather = weather; - } - else - { - if (mNextWeather != "") + std::string lowerCaseRegionID = Misc::StringUtils::lowerCase(regionID); + std::map::iterator it = mRegions.find(lowerCaseRegionID); + if(it != mRegions.end()) { - // transition more than 50% finished? - if (mRemainingTransitionTime / (findWeather(mCurrentWeather).transitionSeconds()) <= 0.5) - mCurrentWeather = mNextWeather; + it->second.setWeather(weatherID); + regionalWeatherChanged(it->first, it->second); } - - mNextWeather = weather; - mRemainingTransitionTime = findWeather(mCurrentWeather).transitionSeconds(); } - mFirstUpdate = false; } -void WeatherManager::setResult(const std::string& weatherType) +void WeatherManager::modRegion(const std::string& regionID, const std::vector& chances) { - const Weather& current = findWeather(weatherType); - - mResult.mCloudTexture = current.mCloudTexture; - mResult.mCloudBlendFactor = 0; - mResult.mWindSpeed = current.mWindSpeed; - mResult.mCloudSpeed = current.mCloudSpeed; - mResult.mGlareView = current.mGlareView; - mResult.mAmbientLoopSoundID = current.mAmbientLoopSoundID; - mResult.mAmbientSoundVolume = 1.f; - mResult.mEffectFade = 1.f; - mResult.mSunColor = current.mSunDiscSunsetColor; - - mResult.mIsStorm = current.mIsStorm; - - mResult.mRainSpeed = current.mRainSpeed; - mResult.mRainFrequency = current.mRainFrequency; - - mResult.mParticleEffect = current.mParticleEffect; - mResult.mRainEffect = current.mRainEffect; - - mResult.mNight = (mHour < mSunriseTime || mHour > mNightStart - 1); - - mResult.mFogDepth = mResult.mNight ? current.mLandFogNightDepth : current.mLandFogDayDepth; - - // night - if (mHour <= mNightEnd || mHour >= mNightStart + 1) + // Sets the region's probability for various weather patterns. Note that this appears to be saved permanently. + // In Morrowind, this seems to have the following behavior when applied to the current region: + // - If the region supports the current weather, no change in current weather occurs. + // - If the region no longer supports the current weather, and there is no transition in progress, begin to + // transition to a new supported weather type. + // - If the region no longer supports the current weather, and there is a transition in progress, queue a + // transition to a new supported weather type. + + std::string lowerCaseRegionID = Misc::StringUtils::lowerCase(regionID); + std::map::iterator it = mRegions.find(lowerCaseRegionID); + if(it != mRegions.end()) { - mResult.mFogColor = current.mFogNightColor; - mResult.mAmbientColor = current.mAmbientNightColor; - mResult.mSunColor = current.mSunNightColor; - mResult.mSkyColor = current.mSkyNightColor; - mResult.mNightFade = 1.f; + it->second.setChances(chances); + regionalWeatherChanged(it->first, it->second); } +} - // sunrise - else if (mHour >= mNightEnd && mHour <= mDayStart + 1) +void WeatherManager::playerTeleported() +{ + // If the player teleports to an outdoors cell in a new region (for instance, by travelling), the weather needs to + // be changed immediately, and any transitions for the previous region discarded. + MWBase::World* world = MWBase::Environment::get().getWorld(); + if(world->isCellExterior() || world->isCellQuasiExterior()) { - if (mHour <= mSunriseTime) + std::string playerRegion = Misc::StringUtils::lowerCase(world->getPlayerPtr().getCell()->getCell()->mRegion); + std::map::iterator it = mRegions.find(playerRegion); + if(it != mRegions.end() && playerRegion != mCurrentRegion) { - // fade in - float advance = mSunriseTime - mHour; - float factor = advance / 0.5f; - mResult.mFogColor = lerp(current.mFogSunriseColor, current.mFogNightColor, factor); - mResult.mAmbientColor = lerp(current.mAmbientSunriseColor, current.mAmbientNightColor, factor); - mResult.mSunColor = lerp(current.mSunSunriseColor, current.mSunNightColor, factor); - mResult.mSkyColor = lerp(current.mSkySunriseColor, current.mSkyNightColor, factor); - mResult.mNightFade = factor; - } - else //if (mHour >= 6) - { - // fade out - float advance = mHour - mSunriseTime; - float factor = advance / 3.f; - mResult.mFogColor = lerp(current.mFogSunriseColor, current.mFogDayColor, factor); - mResult.mAmbientColor = lerp(current.mAmbientSunriseColor, current.mAmbientDayColor, factor); - mResult.mSunColor = lerp(current.mSunSunriseColor, current.mSunDayColor, factor); - mResult.mSkyColor = lerp(current.mSkySunriseColor, current.mSkyDayColor, factor); + mCurrentRegion = playerRegion; + forceWeather(it->second.getWeather()); } } +} - // day - else if (mHour >= mDayStart + 1 && mHour <= mDayEnd - 1) - { - mResult.mFogColor = current.mFogDayColor; - mResult.mAmbientColor = current.mAmbientDayColor; - mResult.mSunColor = current.mSunDayColor; - mResult.mSkyColor = current.mSkyDayColor; - } +void WeatherManager::update(float duration, bool paused) +{ + MWWorld::Ptr player = MWMechanics::getPlayer(); + MWBase::World& world = *MWBase::Environment::get().getWorld(); + TimeStamp time = world.getTimeStamp(); - // sunset - else if (mHour >= mDayEnd - 1 && mHour <= mNightStart + 1) + if(!paused) { - if (mHour <= mDayEnd + 1) - { - // fade in - float advance = (mDayEnd + 1) - mHour; - float factor = (advance / 2); - mResult.mFogColor = lerp(current.mFogSunsetColor, current.mFogDayColor, factor); - mResult.mAmbientColor = lerp(current.mAmbientSunsetColor, current.mAmbientDayColor, factor); - mResult.mSunColor = lerp(current.mSunSunsetColor, current.mSunDayColor, factor); - mResult.mSkyColor = lerp(current.mSkySunsetColor, current.mSkyDayColor, factor); - } - else //if (mHour >= 19) + // Add new transitions when either the player's current external region changes. + std::string playerRegion = Misc::StringUtils::lowerCase(player.getCell()->getCell()->mRegion); + if(updateWeatherTime() || updateWeatherRegion(playerRegion)) { - // fade out - float advance = mHour - (mDayEnd + 1); - float factor = advance / 2.f; - mResult.mFogColor = lerp(current.mFogSunsetColor, current.mFogNightColor, factor); - mResult.mAmbientColor = lerp(current.mAmbientSunsetColor, current.mAmbientNightColor, factor); - mResult.mSunColor = lerp(current.mSunSunsetColor, current.mSunNightColor, factor); - mResult.mSkyColor = lerp(current.mSkySunsetColor, current.mSkyNightColor, factor); - mResult.mNightFade = factor; + std::map::iterator it = mRegions.find(mCurrentRegion); + if(it != mRegions.end()) + { + addWeatherTransition(it->second.getWeather()); + } } - } -} -void WeatherManager::transition(float factor) -{ - setResult(mCurrentWeather); - const MWRender::WeatherResult current = mResult; - setResult(mNextWeather); - const MWRender::WeatherResult other = mResult; - - const Weather& nextWeather = findWeather(mNextWeather); - - mResult.mCloudTexture = current.mCloudTexture; - mResult.mNextCloudTexture = other.mCloudTexture; - mResult.mCloudBlendFactor = nextWeather.cloudBlendFactor(factor); - - mResult.mFogColor = lerp(current.mFogColor, other.mFogColor, factor); - mResult.mSunColor = lerp(current.mSunColor, other.mSunColor, factor); - mResult.mSkyColor = lerp(current.mSkyColor, other.mSkyColor, factor); - - mResult.mAmbientColor = lerp(current.mAmbientColor, other.mAmbientColor, factor); - mResult.mSunDiscColor = lerp(current.mSunDiscColor, other.mSunDiscColor, factor); - mResult.mFogDepth = lerp(current.mFogDepth, other.mFogDepth, factor); - mResult.mWindSpeed = lerp(current.mWindSpeed, other.mWindSpeed, factor); - mResult.mCloudSpeed = lerp(current.mCloudSpeed, other.mCloudSpeed, factor); - mResult.mGlareView = lerp(current.mGlareView, other.mGlareView, factor); - mResult.mNightFade = lerp(current.mNightFade, other.mNightFade, factor); - - mResult.mNight = current.mNight; - - if (factor < 0.5) - { - mResult.mIsStorm = current.mIsStorm; - mResult.mParticleEffect = current.mParticleEffect; - mResult.mRainEffect = current.mRainEffect; - mResult.mParticleEffect = current.mParticleEffect; - mResult.mRainSpeed = current.mRainSpeed; - mResult.mRainFrequency = current.mRainFrequency; - mResult.mAmbientSoundVolume = 1-(factor*2); - mResult.mEffectFade = mResult.mAmbientSoundVolume; - mResult.mAmbientLoopSoundID = current.mAmbientLoopSoundID; - } - else - { - mResult.mIsStorm = other.mIsStorm; - mResult.mParticleEffect = other.mParticleEffect; - mResult.mRainEffect = other.mRainEffect; - mResult.mParticleEffect = other.mParticleEffect; - mResult.mRainSpeed = other.mRainSpeed; - mResult.mRainFrequency = other.mRainFrequency; - mResult.mAmbientSoundVolume = 2*(factor-0.5f); - mResult.mEffectFade = mResult.mAmbientSoundVolume; - mResult.mAmbientLoopSoundID = other.mAmbientLoopSoundID; + updateWeatherTransitions(duration); } -} - -void WeatherManager::update(float duration, bool paused) -{ - float timePassed = static_cast(mTimePassed); - mTimePassed = 0; - mWeatherUpdateTime -= timePassed; - - MWBase::World* world = MWBase::Environment::get().getWorld(); - const bool exterior = (world->isCellExterior() || world->isCellQuasiExterior()); - if (!exterior) + const bool exterior = (world.isCellExterior() || world.isCellQuasiExterior()); + if(!exterior) { - mRendering->setSkyEnabled(false); + mRendering.setSkyEnabled(false); //mRendering->getSkyManager()->setLightningStrength(0.f); stopSounds(); return; } - switchToNextWeather(false); - - if (mNextWeather != "") - { - mRemainingTransitionTime -= timePassed; - if (mRemainingTransitionTime < 0) - { - mCurrentWeather = mNextWeather; - mNextWeather = ""; - } - } - - if (mNextWeather != "") - transition(1 - (mRemainingTransitionTime / (findWeather(mCurrentWeather).transitionSeconds()))); - else - setResult(mCurrentWeather); + calculateWeatherResult(time.getHour()); mWindSpeed = mResult.mWindSpeed; mIsStorm = mResult.mIsStorm; if (mIsStorm) { - MWWorld::Ptr player = world->getPlayerPtr(); osg::Vec3f playerPos (player.getRefData().getPosition().asVec3()); osg::Vec3f redMountainPos (19950, 72032, 27831); mStormDirection = (playerPos - redMountainPos); mStormDirection.z() = 0; mStormDirection.normalize(); - mRendering->getSkyManager()->setStormDirection(mStormDirection); + mRendering.getSkyManager()->setStormDirection(mStormDirection); } - mRendering->configureFog(mResult.mFogDepth, mResult.mFogColor); + mRendering.configureFog(mResult.mFogDepth, mResult.mFogColor); // disable sun during night - if (mHour >= mNightStart || mHour <= mSunriseTime) - mRendering->getSkyManager()->sunDisable(); + if (time.getHour() >= mNightStart || time.getHour() <= mSunriseTime) + mRendering.getSkyManager()->sunDisable(); else - mRendering->getSkyManager()->sunEnable(); + mRendering.getSkyManager()->sunEnable(); // Update the sun direction. Run it east to west at a fixed angle from overhead. // The sun's speed at day and night may differ, since mSunriseTime and mNightStart // mark when the sun is level with the horizon. { // Shift times into a 24-hour window beginning at mSunriseTime... - float adjustedHour = mHour; + float adjustedHour = time.getHour(); float adjustedNightStart = mNightStart; - if ( mHour < mSunriseTime ) + if ( time.getHour() < mSunriseTime ) adjustedHour += 24.f; if ( mNightStart < mSunriseTime ) adjustedNightStart += 24.f; @@ -585,16 +563,15 @@ void WeatherManager::update(float duration, bool paused) static_cast(cos(theta)), -0.268f, // approx tan( -15 degrees ) static_cast(sin(theta))); - mRendering->setSunDirection( final * -1 ); + mRendering.setSunDirection( final * -1 ); } - TimeStamp time = MWBase::Environment::get().getWorld()->getTimeStamp(); - mRendering->getSkyManager()->setMasserState(mMasser.calculateState(time.getDay(), time.getHour())); - mRendering->getSkyManager()->setSecundaState(mSecunda.calculateState(time.getDay(), time.getHour())); + mRendering.getSkyManager()->setMasserState(mMasser.calculateState(time)); + mRendering.getSkyManager()->setSecundaState(mSecunda.calculateState(time)); if (!paused) { - if (mCurrentWeather == "thunderstorm" && mNextWeather == "") + if(mCurrentWeather == 5 && !inTransition()) { if (mThunderFlash > 0) { @@ -641,12 +618,11 @@ void WeatherManager::update(float duration, bool paused) //else //mRendering->getSkyManager()->setLightningStrength(0.f); } - - mRendering->setAmbientColour(mResult.mAmbientColor); - mRendering->setSunColour(mResult.mSunColor); + mRendering.setAmbientColour(mResult.mAmbientColor); + mRendering.setSunColour(mResult.mSunColor); - mRendering->getSkyManager()->setWeather(mResult); + mRendering.getSkyManager()->setWeather(mResult); // Play sounds if (mPlayingSoundID != mResult.mAmbientLoopSoundID) @@ -671,176 +647,66 @@ void WeatherManager::stopSounds() } } -std::string WeatherManager::nextWeather(const ESM::Region* region) const +float WeatherManager::getWindSpeed() const { - std::vector probability; - - RegionModMap::const_iterator iter = mRegionMods.find(Misc::StringUtils::lowerCase(region->mId)); - if(iter != mRegionMods.end()) - probability = iter->second; - else - { - probability.reserve(10); - probability.push_back(region->mData.mClear); - probability.push_back(region->mData.mCloudy); - probability.push_back(region->mData.mFoggy); - probability.push_back(region->mData.mOvercast); - probability.push_back(region->mData.mRain); - probability.push_back(region->mData.mThunder); - probability.push_back(region->mData.mAsh); - probability.push_back(region->mData.mBlight); - probability.push_back(region->mData.mA); - probability.push_back(region->mData.mB); - } - - /* - * All probabilities must add to 100 (responsibility of the user). - * If chances A and B has values 30 and 70 then by generating - * 100 numbers 1..100, 30% will be lesser or equal 30 and - * 70% will be greater than 30 (in theory). - */ - - int chance = Misc::Rng::rollDice(100) + 1; // 1..100 - int sum = 0; - unsigned int i = 0; - for (; i < probability.size(); ++i) - { - sum += probability[i]; - if (chance < sum) - break; - } - - switch (i) - { - case 1: - return "cloudy"; - case 2: - return "foggy"; - case 3: - return "overcast"; - case 4: - return "rain"; - case 5: - return "thunderstorm"; - case 6: - return "ashstorm"; - case 7: - return "blight"; - case 8: - return "snow"; - case 9: - return "blizzard"; - default: // case 0 - return "clear"; - } + return mWindSpeed; } -void WeatherManager::setHour(const float hour) +bool WeatherManager::isInStorm() const { - mHour = hour; + return mIsStorm; } -unsigned int WeatherManager::getWeatherID() const +osg::Vec3f WeatherManager::getStormDirection() const { - // Source: http://www.uesp.net/wiki/Tes3Mod:GetCurrentWeather - - if (mCurrentWeather == "clear") - return 0; - else if (mCurrentWeather == "cloudy") - return 1; - else if (mCurrentWeather == "foggy") - return 2; - else if (mCurrentWeather == "overcast") - return 3; - else if (mCurrentWeather == "rain") - return 4; - else if (mCurrentWeather == "thunderstorm") - return 5; - else if (mCurrentWeather == "ashstorm") - return 6; - else if (mCurrentWeather == "blight") - return 7; - else if (mCurrentWeather == "snow") - return 8; - else if (mCurrentWeather == "blizzard") - return 9; - - else - return 0; -} - -void WeatherManager::changeWeather(const std::string& region, const unsigned int id) -{ - // make sure this region exists - MWBase::Environment::get().getWorld()->getStore().get().find(region); - - std::string weather; - if (id==0) - weather = "clear"; - else if (id==1) - weather = "cloudy"; - else if (id==2) - weather = "foggy"; - else if (id==3) - weather = "overcast"; - else if (id==4) - weather = "rain"; - else if (id==5) - weather = "thunderstorm"; - else if (id==6) - weather = "ashstorm"; - else if (id==7) - weather = "blight"; - else if (id==8) - weather = "snow"; - else if (id==9) - weather = "blizzard"; - else - weather = "clear"; - - mRegionOverrides[Misc::StringUtils::lowerCase(region)] = weather; + return mStormDirection; +} - MWWorld::Ptr player = MWMechanics::getPlayer(); - if (player.isInCell()) - { - std::string playerRegion = player.getCell()->getCell()->mRegion; - if (Misc::StringUtils::ciEqual(region, playerRegion)) - setWeather(weather); - } +void WeatherManager::advanceTime(double hours) +{ + // This is called when the player sleeps/waits, serves jail time, travels, or trains. + // In Morrowind, when any of those events occur, all weather transitions are immediately applied, regardless of + // whatever transition time might have been remaining. + mTimePassed += hours; + mFastForward = true; } -void WeatherManager::modRegion(const std::string ®ionid, const std::vector &chances) +void WeatherManager::advanceTimeByFrame(double hours) { - mRegionMods[Misc::StringUtils::lowerCase(regionid)] = chances; - // Start transitioning right away if the region no longer supports the current weather type - unsigned int current = getWeatherID(); - if(current >= chances.size() || chances[current] == 0) - mWeatherUpdateTime = 0.0f; + // Called when time is advanced by an incremental update for each frame. + mTimePassed += hours; } -float WeatherManager::getWindSpeed() const +unsigned int WeatherManager::getWeatherID() const { - return mWindSpeed; + return mCurrentWeather; } bool WeatherManager::isDark() const { + TimeStamp time = MWBase::Environment::get().getWorld()->getTimeStamp(); bool exterior = (MWBase::Environment::get().getWorld()->isCellExterior() || MWBase::Environment::get().getWorld()->isCellQuasiExterior()); - return exterior && (mHour < mSunriseTime || mHour > mNightStart - 1); + return exterior && (time.getHour() < mSunriseTime || time.getHour() > mNightStart - 1); } void WeatherManager::write(ESM::ESMWriter& writer, Loading::Listener& progress) { ESM::WeatherState state; - state.mHour = mHour; - state.mWindSpeed = mWindSpeed; - state.mCurrentWeather = mCurrentWeather; - state.mNextWeather = mNextWeather; state.mCurrentRegion = mCurrentRegion; - state.mFirstUpdate = mFirstUpdate; - state.mRemainingTransitionTime = mRemainingTransitionTime; state.mTimePassed = mTimePassed; + state.mFastForward = mFastForward; + state.mWeatherUpdateTime = mWeatherUpdateTime; + state.mTransitionFactor = mTransitionFactor; + state.mCurrentWeather = mCurrentWeather; + state.mNextWeather = mNextWeather; + state.mQueuedWeather = mQueuedWeather; + + std::map::iterator it = mRegions.begin(); + for(; it != mRegions.end(); ++it) + { + state.mRegions.insert(std::make_pair(it->first, ESM::RegionWeatherState(it->second))); + } writer.startRecord(ESM::REC_WTHR); state.save(writer); @@ -851,19 +717,32 @@ bool WeatherManager::readRecord(ESM::ESMReader& reader, uint32_t type) { if(ESM::REC_WTHR == type) { - // load first so that if it fails, we haven't accidentally reset the state below ESM::WeatherState state; state.load(reader); - // swap in the loaded values now that we can't fail - mHour = state.mHour; - mWindSpeed = state.mWindSpeed; - mCurrentWeather.swap(state.mCurrentWeather); - mNextWeather.swap(state.mNextWeather); mCurrentRegion.swap(state.mCurrentRegion); - mFirstUpdate = state.mFirstUpdate; - mRemainingTransitionTime = state.mRemainingTransitionTime; mTimePassed = state.mTimePassed; + mFastForward = state.mFastForward; + mWeatherUpdateTime = state.mWeatherUpdateTime; + mTransitionFactor = state.mTransitionFactor; + mCurrentWeather = state.mCurrentWeather; + mNextWeather = state.mCurrentWeather; + mQueuedWeather = state.mQueuedWeather; + + mRegions.clear(); + std::map::iterator it = state.mRegions.begin(); + if(it == state.mRegions.end()) + { + // When loading an imported save, the region modifiers aren't currently being set, so just reset them. + importRegions(); + } + else + { + for(; it != state.mRegions.end(); ++it) + { + mRegions.insert(std::make_pair(it->first, RegionWeather(it->second))); + } + } return true; } @@ -874,78 +753,319 @@ bool WeatherManager::readRecord(ESM::ESMReader& reader, uint32_t type) void WeatherManager::clear() { stopSounds(); - mRegionOverrides.clear(); - mRegionMods.clear(); + mThunderFlash = 0.0; mThunderChance = 0.0; mThunderChanceNeeded = 50.0; + + mCurrentRegion = ""; + mTimePassed = 0.0f; + mWeatherUpdateTime = 0.0f; + forceWeather(0); + mRegions.clear(); + importRegions(); } -void WeatherManager::switchToNextWeather(bool instantly) +inline void WeatherManager::addWeather(const std::string& name, + const MWWorld::Fallback& fallback, + const std::string& ambientLoopSoundID, + const std::string& particleEffect) { - MWBase::World* world = MWBase::Environment::get().getWorld(); - if (world->isCellExterior() || world->isCellQuasiExterior()) + static const float fStromWindSpeed = mStore.get().find("fStromWindSpeed")->getFloat(); + + Weather weather(name, fallback, fStromWindSpeed, mRainSpeed, ambientLoopSoundID, particleEffect); + + mWeatherSettings.push_back(weather); +} + +inline void WeatherManager::importRegions() +{ + Store::iterator it = mStore.get().begin(); + for(; it != mStore.get().end(); ++it) + { + std::string regionID = Misc::StringUtils::lowerCase(it->mId); + mRegions.insert(std::make_pair(regionID, RegionWeather(*it))); + } +} + +inline void WeatherManager::regionalWeatherChanged(const std::string& regionID, RegionWeather& region) +{ + // If the region is current, then add a weather transition for it. + MWWorld::Ptr player = MWMechanics::getPlayer(); + if(player.isInCell()) { - std::string regionstr = Misc::StringUtils::lowerCase(world->getPlayerPtr().getCell()->getCell()->mRegion); + std::string playerRegion = Misc::StringUtils::lowerCase(player.getCell()->getCell()->mRegion); + if(!playerRegion.empty() && (playerRegion == regionID)) + { + addWeatherTransition(region.getWeather()); + } + } +} - if (mWeatherUpdateTime <= 0 || regionstr != mCurrentRegion) +inline bool WeatherManager::updateWeatherTime() +{ + mWeatherUpdateTime -= mTimePassed; + mTimePassed = 0.0f; + if(mWeatherUpdateTime <= 0.0f) + { + // Expire all regional weather, so that any call to getWeather() will return a new weather ID. + std::map::iterator it = mRegions.begin(); + for(; it != mRegions.end(); ++it) { - mCurrentRegion = regionstr; - mWeatherUpdateTime = mHoursBetweenWeatherChanges * 3600; + it->second.setWeather(invalidWeatherID); + } + + mWeatherUpdateTime += mHoursBetweenWeatherChanges; + + return true; + } + + return false; +} + +inline bool WeatherManager::updateWeatherRegion(const std::string& playerRegion) +{ + if(!playerRegion.empty() && playerRegion != mCurrentRegion) + { + mCurrentRegion = playerRegion; + + return true; + } - std::string weatherType = "clear"; + return false; +} + +inline void WeatherManager::updateWeatherTransitions(const float elapsedRealSeconds) +{ + // When a player chooses to train, wait, or serves jail time, any transitions will be fast forwarded to the last + // weather type set, regardless of the remaining transition time. + if(!mFastForward && inTransition()) + { + const float delta = mWeatherSettings[mNextWeather].transitionDelta(); + mTransitionFactor -= elapsedRealSeconds * delta; + if(mTransitionFactor <= 0.0f) + { + mCurrentWeather = mNextWeather; + mNextWeather = mQueuedWeather; + mQueuedWeather = invalidWeatherID; - if (mRegionOverrides.find(regionstr) != mRegionOverrides.end()) + // We may have begun processing the queued transition, so we need to apply the remaining time towards it. + if(inTransition()) { - weatherType = mRegionOverrides[regionstr]; + const float newDelta = mWeatherSettings[mNextWeather].transitionDelta(); + const float remainingSeconds = -(mTransitionFactor / delta); + mTransitionFactor = 1.0f - (remainingSeconds * newDelta); } else { - // get weather probabilities for the current region - const ESM::Region *region = world->getStore().get().search (regionstr); - - if (region != 0) - { - weatherType = nextWeather(region); - } + mTransitionFactor = 0.0f; } - - setWeather(weatherType, instantly); } } + else + { + if(mQueuedWeather != invalidWeatherID) + { + mCurrentWeather = mQueuedWeather; + } + else if(mNextWeather != invalidWeatherID) + { + mCurrentWeather = mNextWeather; + } + + mFastForward = false; + } } -bool WeatherManager::isInStorm() const +inline void WeatherManager::forceWeather(const int weatherID) { - return mIsStorm; + mTransitionFactor = 0.0f; + mCurrentWeather = weatherID; + mNextWeather = invalidWeatherID; + mQueuedWeather = invalidWeatherID; } -osg::Vec3f WeatherManager::getStormDirection() const +inline bool WeatherManager::inTransition() { - return mStormDirection; + return mNextWeather != invalidWeatherID; } -void WeatherManager::advanceTime(double hours) +inline void WeatherManager::addWeatherTransition(const int weatherID) { - mTimePassed += hours*3600; + // In order to work like ChangeWeather expects, this method begins transitioning to the new weather immediately if + // no transition is in progress, otherwise it queues it to be transitioned. + + assert(weatherID >= 0 && static_cast(weatherID) < mWeatherSettings.size()); + + if(!inTransition() && (weatherID != mCurrentWeather)) + { + mNextWeather = weatherID; + mTransitionFactor = 1.0f; + } + else if(inTransition() && (weatherID != mNextWeather)) + { + mQueuedWeather = weatherID; + } } -inline void WeatherManager::addWeather(const std::string& name, - const MWWorld::Fallback& fallback, - const std::string& ambientLoopSoundID, - const std::string& particleEffect) +inline void WeatherManager::calculateWeatherResult(const float gameHour) { - static const float fStromWindSpeed = mStore->get().find("fStromWindSpeed")->getFloat(); + if(!inTransition()) + { + calculateResult(mCurrentWeather, gameHour); + } + else + { + calculateTransitionResult(1 - mTransitionFactor, gameHour); + } +} - Weather weather(name, fallback, fStromWindSpeed, mRainSpeed, ambientLoopSoundID, particleEffect); +inline void WeatherManager::calculateResult(const int weatherID, const float gameHour) +{ + const Weather& current = mWeatherSettings[weatherID]; + + mResult.mCloudTexture = current.mCloudTexture; + mResult.mCloudBlendFactor = 0; + mResult.mWindSpeed = current.mWindSpeed; + mResult.mCloudSpeed = current.mCloudSpeed; + mResult.mGlareView = current.mGlareView; + mResult.mAmbientLoopSoundID = current.mAmbientLoopSoundID; + mResult.mAmbientSoundVolume = 1.f; + mResult.mEffectFade = 1.f; + mResult.mSunColor = current.mSunDiscSunsetColor; + + mResult.mIsStorm = current.mIsStorm; - std::string lower = name; - lower[0] = tolower(lower[0]); - mWeatherSettings.insert(std::make_pair(lower, weather)); + mResult.mRainSpeed = current.mRainSpeed; + mResult.mRainFrequency = current.mRainFrequency; + + mResult.mParticleEffect = current.mParticleEffect; + mResult.mRainEffect = current.mRainEffect; + + mResult.mNight = (gameHour < mSunriseTime || gameHour > mNightStart - 1); + + mResult.mFogDepth = mResult.mNight ? current.mLandFogNightDepth : current.mLandFogDayDepth; + + // night + if (gameHour <= mNightEnd || gameHour >= mNightStart + 1) + { + mResult.mFogColor = current.mFogNightColor; + mResult.mAmbientColor = current.mAmbientNightColor; + mResult.mSunColor = current.mSunNightColor; + mResult.mSkyColor = current.mSkyNightColor; + mResult.mNightFade = 1.f; + } + + // sunrise + else if (gameHour >= mNightEnd && gameHour <= mDayStart + 1) + { + if (gameHour <= mSunriseTime) + { + // fade in + float advance = mSunriseTime - gameHour; + float factor = advance / 0.5f; + mResult.mFogColor = lerp(current.mFogSunriseColor, current.mFogNightColor, factor); + mResult.mAmbientColor = lerp(current.mAmbientSunriseColor, current.mAmbientNightColor, factor); + mResult.mSunColor = lerp(current.mSunSunriseColor, current.mSunNightColor, factor); + mResult.mSkyColor = lerp(current.mSkySunriseColor, current.mSkyNightColor, factor); + mResult.mNightFade = factor; + } + else //if (gameHour >= 6) + { + // fade out + float advance = gameHour - mSunriseTime; + float factor = advance / 3.f; + mResult.mFogColor = lerp(current.mFogSunriseColor, current.mFogDayColor, factor); + mResult.mAmbientColor = lerp(current.mAmbientSunriseColor, current.mAmbientDayColor, factor); + mResult.mSunColor = lerp(current.mSunSunriseColor, current.mSunDayColor, factor); + mResult.mSkyColor = lerp(current.mSkySunriseColor, current.mSkyDayColor, factor); + } + } + + // day + else if (gameHour >= mDayStart + 1 && gameHour <= mDayEnd - 1) + { + mResult.mFogColor = current.mFogDayColor; + mResult.mAmbientColor = current.mAmbientDayColor; + mResult.mSunColor = current.mSunDayColor; + mResult.mSkyColor = current.mSkyDayColor; + } + + // sunset + else if (gameHour >= mDayEnd - 1 && gameHour <= mNightStart + 1) + { + if (gameHour <= mDayEnd + 1) + { + // fade in + float advance = (mDayEnd + 1) - gameHour; + float factor = (advance / 2); + mResult.mFogColor = lerp(current.mFogSunsetColor, current.mFogDayColor, factor); + mResult.mAmbientColor = lerp(current.mAmbientSunsetColor, current.mAmbientDayColor, factor); + mResult.mSunColor = lerp(current.mSunSunsetColor, current.mSunDayColor, factor); + mResult.mSkyColor = lerp(current.mSkySunsetColor, current.mSkyDayColor, factor); + } + else //if (gameHour >= 19) + { + // fade out + float advance = gameHour - (mDayEnd + 1); + float factor = advance / 2.f; + mResult.mFogColor = lerp(current.mFogSunsetColor, current.mFogNightColor, factor); + mResult.mAmbientColor = lerp(current.mAmbientSunsetColor, current.mAmbientNightColor, factor); + mResult.mSunColor = lerp(current.mSunSunsetColor, current.mSunNightColor, factor); + mResult.mSkyColor = lerp(current.mSkySunsetColor, current.mSkyNightColor, factor); + mResult.mNightFade = factor; + } + } } -inline Weather& WeatherManager::findWeather(const std::string& name) +inline void WeatherManager::calculateTransitionResult(const float factor, const float gameHour) { - return mWeatherSettings.at(name); + calculateResult(mCurrentWeather, gameHour); + const MWRender::WeatherResult current = mResult; + calculateResult(mNextWeather, gameHour); + const MWRender::WeatherResult other = mResult; + + mResult.mCloudTexture = current.mCloudTexture; + mResult.mNextCloudTexture = other.mCloudTexture; + mResult.mCloudBlendFactor = mWeatherSettings[mNextWeather].cloudBlendFactor(factor); + + mResult.mFogColor = lerp(current.mFogColor, other.mFogColor, factor); + mResult.mSunColor = lerp(current.mSunColor, other.mSunColor, factor); + mResult.mSkyColor = lerp(current.mSkyColor, other.mSkyColor, factor); + + mResult.mAmbientColor = lerp(current.mAmbientColor, other.mAmbientColor, factor); + mResult.mSunDiscColor = lerp(current.mSunDiscColor, other.mSunDiscColor, factor); + mResult.mFogDepth = lerp(current.mFogDepth, other.mFogDepth, factor); + mResult.mWindSpeed = lerp(current.mWindSpeed, other.mWindSpeed, factor); + mResult.mCloudSpeed = lerp(current.mCloudSpeed, other.mCloudSpeed, factor); + mResult.mGlareView = lerp(current.mGlareView, other.mGlareView, factor); + mResult.mNightFade = lerp(current.mNightFade, other.mNightFade, factor); + + mResult.mNight = current.mNight; + + if(factor < 0.5) + { + mResult.mIsStorm = current.mIsStorm; + mResult.mParticleEffect = current.mParticleEffect; + mResult.mRainEffect = current.mRainEffect; + mResult.mParticleEffect = current.mParticleEffect; + mResult.mRainSpeed = current.mRainSpeed; + mResult.mRainFrequency = current.mRainFrequency; + mResult.mAmbientSoundVolume = 1-(factor*2); + mResult.mEffectFade = mResult.mAmbientSoundVolume; + mResult.mAmbientLoopSoundID = current.mAmbientLoopSoundID; + } + else + { + mResult.mIsStorm = other.mIsStorm; + mResult.mParticleEffect = other.mParticleEffect; + mResult.mRainEffect = other.mRainEffect; + mResult.mParticleEffect = other.mParticleEffect; + mResult.mRainSpeed = other.mRainSpeed; + mResult.mRainFrequency = other.mRainFrequency; + mResult.mAmbientSoundVolume = 2*(factor-0.5f); + mResult.mEffectFade = mResult.mAmbientSoundVolume; + mResult.mAmbientLoopSoundID = other.mAmbientLoopSoundID; + } } diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index 710e45d9b..d07e7e1e4 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -14,6 +14,7 @@ namespace ESM { struct Region; + struct RegionWeatherState; class ESMWriter; class ESMReader; } @@ -31,6 +32,7 @@ namespace Loading namespace MWWorld { class Fallback; + class TimeStamp; /// Defines a single weather setting (according to INI) class Weather @@ -110,7 +112,7 @@ namespace MWWorld // Note: For Weather Blight, there is a "Disease Chance" (=0.1) setting. But according to MWSFD this feature // is broken in the vanilla game and was disabled. - float transitionSeconds() const; + float transitionDelta() const; float cloudBlendFactor(float transitionRatio) const; private: @@ -118,12 +120,35 @@ namespace MWWorld float mCloudsMaximumPercent; }; + /// A class for storing a region's weather. + class RegionWeather + { + public: + explicit RegionWeather(const ESM::Region& region); + explicit RegionWeather(const ESM::RegionWeatherState& state); + + explicit operator ESM::RegionWeatherState() const; + + void setChances(const std::vector& chances); + + void setWeather(int weatherID); + + int getWeather(); + + private: + int mWeather; + std::vector mChances; + + void chooseNewWeather(); + }; + + /// A class that acts as a model for the moons. class MoonModel { public: MoonModel(const std::string& name, const MWWorld::Fallback& fallback); - MWRender::MoonState calculateState(unsigned int daysPassed, float gameHour) const; + MWRender::MoonState calculateState(const TimeStamp& gameTime) const; private: float mFadeInStart; @@ -137,23 +162,23 @@ namespace MWWorld float mFadeEndAngle; float mMoonShadowEarlyFadeAngle; - float angle(unsigned int daysPassed, float gameHour) const; + float angle(const TimeStamp& gameTime) const; float moonRiseHour(unsigned int daysPassed) const; float rotation(float hours) const; - unsigned int phase(unsigned int daysPassed, float gameHour) const; + unsigned int phase(const TimeStamp& gameTime) const; float shadowBlend(float angle) const; float hourlyAlpha(float gameHour) const; float earlyMoonShadowAlpha(float angle) const; }; - /// /// Interface for weather settings - /// class WeatherManager { public: // Have to pass fallback and Store, can't use singleton since World isn't fully constructed yet at the time - WeatherManager(MWRender::RenderingManager*, MWWorld::Fallback* fallback, MWWorld::ESMStore* store); + WeatherManager(MWRender::RenderingManager& rendering, + const MWWorld::Fallback& fallback, + MWWorld::ESMStore& store); ~WeatherManager(); /** @@ -161,8 +186,9 @@ namespace MWWorld * @param region that should be changed * @param ID of the weather setting to shift to */ - void changeWeather(const std::string& region, const unsigned int id); - void switchToNextWeather(bool instantly = true); + void changeWeather(const std::string& regionID, const unsigned int weatherID); + void modRegion(const std::string& regionID, const std::vector& chances); + void playerTeleported(); /** * Per-frame update @@ -173,8 +199,6 @@ namespace MWWorld void stopSounds(); - void setHour(const float hour); - float getWindSpeed() const; /// Are we in an ash or blight storm? @@ -183,11 +207,10 @@ namespace MWWorld osg::Vec3f getStormDirection() const; void advanceTime(double hours); + void advanceTimeByFrame(double hours); unsigned int getWeatherID() const; - void modRegion(const std::string ®ionid, const std::vector &chances); - /// @see World::isDark bool isDark() const; @@ -198,73 +221,77 @@ namespace MWWorld void clear(); private: - float mHour; - float mWindSpeed; - bool mIsStorm; - osg::Vec3f mStormDirection; - - MWBase::SoundPtr mAmbientSound; - std::string mPlayingSoundID; - - MWWorld::ESMStore* mStore; - MWRender::RenderingManager* mRendering; - - std::map mWeatherSettings; - - std::map mRegionOverrides; - - std::string mCurrentWeather; - std::string mNextWeather; - - std::string mCurrentRegion; - - bool mFirstUpdate; - - float mRemainingTransitionTime; - - float mThunderFlash; - float mThunderChance; - float mThunderChanceNeeded; - - double mTimePassed; // time passed since last update - - void transition(const float factor); - void setResult(const std::string& weatherType); - - void setWeather(const std::string& weatherType, bool instant=false); - std::string nextWeather(const ESM::Region* region) const; - MWRender::WeatherResult mResult; - - typedef std::map > RegionModMap; - RegionModMap mRegionMods; - - float mRainSpeed; + MWWorld::ESMStore& mStore; + MWRender::RenderingManager& mRendering; float mSunriseTime; float mSunsetTime; float mSunriseDuration; float mSunsetDuration; - float mWeatherUpdateTime; - float mHoursBetweenWeatherChanges; - float mThunderFrequency; - float mThunderThreshold; - float mThunderSoundDelay; + // Some useful values + /* TODO: Use pre-sunrise_time, pre-sunset_time, + * post-sunrise_time, and post-sunset_time to better + * describe sunrise/sunset time. + * These values are fallbacks attached to weather. + */ float mNightStart; float mNightEnd; float mDayStart; float mDayEnd; + float mHoursBetweenWeatherChanges; + float mRainSpeed; + std::vector mWeatherSettings; + MoonModel mMasser; + MoonModel mSecunda; + + float mThunderFrequency; + float mThunderThreshold; std::string mThunderSoundID0; std::string mThunderSoundID1; std::string mThunderSoundID2; std::string mThunderSoundID3; - MoonModel mMasser; - MoonModel mSecunda; + + float mWindSpeed; + bool mIsStorm; + osg::Vec3f mStormDirection; + + float mThunderSoundDelay; + float mThunderFlash; + float mThunderChance; + float mThunderChanceNeeded; + + std::string mCurrentRegion; + float mTimePassed; + bool mFastForward; + float mWeatherUpdateTime; + float mTransitionFactor; + int mCurrentWeather; + int mNextWeather; + int mQueuedWeather; + std::map mRegions; + MWRender::WeatherResult mResult; + + MWBase::SoundPtr mAmbientSound; + std::string mPlayingSoundID; void addWeather(const std::string& name, const MWWorld::Fallback& fallback, const std::string& ambientLoopSoundID = "", const std::string& particleEffect = ""); - Weather& findWeather(const std::string& name); + void importRegions(); + + void regionalWeatherChanged(const std::string& regionID, RegionWeather& region); + bool updateWeatherTime(); + bool updateWeatherRegion(const std::string& playerRegion); + void updateWeatherTransitions(const float elapsedRealSeconds); + void forceWeather(const int weatherID); + + bool inTransition(); + void addWeatherTransition(const int weatherID); + + void calculateWeatherResult(const float gameHour); + void calculateResult(const int weatherID, const float gameHour); + void calculateTransitionResult(const float factor, const float gameHour); }; } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 40a929cda..56c7415a2 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -193,7 +193,7 @@ namespace MWWorld mGlobalVariables.fill (mStore); - mWeatherManager = new MWWorld::WeatherManager(mRendering,&mFallback,&mStore); + mWeatherManager = new MWWorld::WeatherManager(*mRendering, mFallback, mStore); mWorldScene = new Scene(*mRendering, mPhysics); } @@ -212,6 +212,11 @@ namespace MWWorld MWBase::Environment::get().getWindowManager()->updatePlayer(); + // we don't want old weather to persist on a new game + // Note that if reset later, the initial ChangeWeather that the chargen script calls will be lost. + delete mWeatherManager; + mWeatherManager = new MWWorld::WeatherManager(*mRendering, mFallback, mStore); + if (!bypass) { // set new game mark @@ -265,11 +270,6 @@ namespace MWWorld if (!mPhysics->toggleCollisionMode()) mPhysics->toggleCollisionMode(); - // we don't want old weather to persist on a new game - delete mWeatherManager; - mWeatherManager = 0; - mWeatherManager = new MWWorld::WeatherManager(mRendering,&mFallback,&mStore); - if (!mStartupScript.empty()) MWBase::Environment::get().getWindowManager()->executeInConsole(mStartupScript); } @@ -804,6 +804,25 @@ namespace MWWorld days + mGlobalVariables["dayspassed"].getInteger()); } + void World::advanceTimeByFrame (double frametime) + { + double hours = (frametime * getTimeScaleFactor()) / 3600.0; + + MWBase::Environment::get().getMechanicsManager()->advanceTime(static_cast(hours * 3600)); + + mWeatherManager->advanceTimeByFrame (hours); + + hours += mGlobalVariables["gamehour"].getFloat(); + + setHour (hours); + + int days = static_cast(hours / 24); + + if (days>0) + mGlobalVariables["dayspassed"].setInteger ( + days + mGlobalVariables["dayspassed"].getInteger()); + } + void World::setHour (double hour) { if (hour<0) @@ -815,8 +834,6 @@ namespace MWWorld mGlobalVariables["gamehour"].setFloat(static_cast(hour)); - mWeatherManager->setHour(static_cast(hour)); - if (days>0) setDay (days + mGlobalVariables["day"].getInteger()); } @@ -2888,15 +2905,15 @@ namespace MWWorld MWWorld::ActionTeleport action(cellName, closestMarker.getRefData().getPosition(), false); action.execute(ptr); } - + void World::updateWeather(float duration, bool paused) { if (mPlayer->wasTeleported()) { mPlayer->setTeleported(false); - mWeatherManager->switchToNextWeather(true); + mWeatherManager->playerTeleported(); } - + mWeatherManager->update(duration, paused); } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 35e433549..80fe6d850 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -277,6 +277,9 @@ namespace MWWorld virtual void advanceTime (double hours); ///< Advance in-game time. + virtual void advanceTimeByFrame (double frametime); + ///< Advance in-game time by the duration of a frame. + virtual void setHour (double hour); ///< Set in-game time hour. diff --git a/components/esm/weatherstate.cpp b/components/esm/weatherstate.cpp index 48cf55a60..ff2528e58 100644 --- a/components/esm/weatherstate.cpp +++ b/components/esm/weatherstate.cpp @@ -1,59 +1,72 @@ -#include "weatherstate.hpp" - -#include "esmreader.hpp" -#include "esmwriter.hpp" - -namespace -{ - const char* hourRecord = "HOUR"; - const char* windSpeedRecord = "WNSP"; - const char* currentWeatherRecord = "CWTH"; - const char* nextWeatherRecord = "NWTH"; - const char* currentRegionRecord = "CREG"; - const char* firstUpdateRecord = "FUPD"; - const char* remainingTransitionTimeRecord = "RTTM"; - const char* timePassedRecord = "TMPS"; -} - -namespace ESM -{ - void WeatherState::load(ESMReader& esm) - { - // store values locally so that a failed load can't leave the state half set - float newHour = 0.0; - esm.getHNT(newHour, hourRecord); - float newWindSpeed = 0.0; - esm.getHNT(newWindSpeed, windSpeedRecord); - std::string newCurrentWeather = esm.getHNString(currentWeatherRecord); - std::string newNextWeather = esm.getHNString(nextWeatherRecord); - std::string newCurrentRegion = esm.getHNString(currentRegionRecord); - bool newFirstUpdate = false; - esm.getHNT(newFirstUpdate, firstUpdateRecord); - float newRemainingTransitionTime = 0.0; - esm.getHNT(newRemainingTransitionTime, remainingTransitionTimeRecord); - double newTimePassed = 0.0; - esm.getHNT(newTimePassed, timePassedRecord); - - // swap values now that it is safe to do so - mHour = newHour; - mWindSpeed = newWindSpeed; - mCurrentWeather.swap(newCurrentWeather); - mNextWeather.swap(newNextWeather); - mCurrentRegion.swap(newCurrentRegion); - mFirstUpdate = newFirstUpdate; - mRemainingTransitionTime = newRemainingTransitionTime; - mTimePassed = newTimePassed; - } - - void WeatherState::save(ESMWriter& esm) const - { - esm.writeHNT(hourRecord, mHour); - esm.writeHNT(windSpeedRecord, mWindSpeed); - esm.writeHNCString(currentWeatherRecord, mCurrentWeather.c_str()); - esm.writeHNCString(nextWeatherRecord, mNextWeather.c_str()); - esm.writeHNCString(currentRegionRecord, mCurrentRegion.c_str()); - esm.writeHNT(firstUpdateRecord, mFirstUpdate); - esm.writeHNT(remainingTransitionTimeRecord, mRemainingTransitionTime); - esm.writeHNT(timePassedRecord, mTimePassed); - } -} +#include "weatherstate.hpp" + +#include "esmreader.hpp" +#include "esmwriter.hpp" + +namespace +{ + const char* currentRegionRecord = "CREG"; + const char* timePassedRecord = "TMPS"; + const char* fastForwardRecord = "FAST"; + const char* weatherUpdateTimeRecord = "WUPD"; + const char* transitionFactorRecord = "TRFC"; + const char* currentWeatherRecord = "CWTH"; + const char* nextWeatherRecord = "NWTH"; + const char* queuedWeatherRecord = "QWTH"; + const char* regionNameRecord = "RGNN"; + const char* regionWeatherRecord = "RGNW"; + const char* regionChanceRecord = "RGNC"; +} + +namespace ESM +{ + void WeatherState::load(ESMReader& esm) + { + mCurrentRegion = esm.getHNString(currentRegionRecord); + esm.getHNT(mTimePassed, timePassedRecord); + esm.getHNT(mFastForward, fastForwardRecord); + esm.getHNT(mWeatherUpdateTime, weatherUpdateTimeRecord); + esm.getHNT(mTransitionFactor, transitionFactorRecord); + esm.getHNT(mCurrentWeather, currentWeatherRecord); + esm.getHNT(mNextWeather, nextWeatherRecord); + esm.getHNT(mQueuedWeather, queuedWeatherRecord); + + while(esm.peekNextSub(regionNameRecord)) + { + std::string regionID = esm.getHNString(regionNameRecord); + RegionWeatherState region; + esm.getHNT(region.mWeather, regionWeatherRecord); + while(esm.peekNextSub(regionChanceRecord)) + { + char chance; + esm.getHNT(chance, regionChanceRecord); + region.mChances.push_back(chance); + } + + mRegions.insert(std::make_pair(regionID, region)); + } + } + + void WeatherState::save(ESMWriter& esm) const + { + esm.writeHNCString(currentRegionRecord, mCurrentRegion.c_str()); + esm.writeHNT(timePassedRecord, mTimePassed); + esm.writeHNT(fastForwardRecord, mFastForward); + esm.writeHNT(weatherUpdateTimeRecord, mWeatherUpdateTime); + esm.writeHNT(transitionFactorRecord, mTransitionFactor); + esm.writeHNT(currentWeatherRecord, mCurrentWeather); + esm.writeHNT(nextWeatherRecord, mNextWeather); + esm.writeHNT(queuedWeatherRecord, mQueuedWeather); + + std::map::const_iterator it = mRegions.begin(); + for(; it != mRegions.end(); ++it) + { + esm.writeHNCString(regionNameRecord, it->first.c_str()); + esm.writeHNT(regionWeatherRecord, it->second.mWeather); + for(size_t i = 0; i < it->second.mChances.size(); ++i) + { + esm.writeHNT(regionChanceRecord, it->second.mChances[i]); + } + } + } +} diff --git a/components/esm/weatherstate.hpp b/components/esm/weatherstate.hpp index d0cd59c16..532a056ac 100644 --- a/components/esm/weatherstate.hpp +++ b/components/esm/weatherstate.hpp @@ -1,27 +1,36 @@ -#ifndef OPENMW_ESM_WEATHERSTATE_H -#define OPENMW_ESM_WEATHERSTATE_H - -#include - -namespace ESM -{ - class ESMReader; - class ESMWriter; - - struct WeatherState - { - float mHour; - float mWindSpeed; - std::string mCurrentWeather; - std::string mNextWeather; - std::string mCurrentRegion; - bool mFirstUpdate; - float mRemainingTransitionTime; - double mTimePassed; - - void load(ESMReader& esm); - void save(ESMWriter& esm) const; - }; -} - -#endif +#ifndef OPENMW_ESM_WEATHERSTATE_H +#define OPENMW_ESM_WEATHERSTATE_H + +#include +#include +#include + +namespace ESM +{ + class ESMReader; + class ESMWriter; + + struct RegionWeatherState + { + int mWeather; + std::vector mChances; + }; + + struct WeatherState + { + std::string mCurrentRegion; + float mTimePassed; + bool mFastForward; + float mWeatherUpdateTime; + float mTransitionFactor; + int mCurrentWeather; + int mNextWeather; + int mQueuedWeather; + std::map mRegions; + + void load(ESMReader& esm); + void save(ESMWriter& esm) const; + }; +} + +#endif From c907ed517d05861db942b4555f0d3883e6c8814a Mon Sep 17 00:00:00 2001 From: slothlife Date: Wed, 26 Aug 2015 23:34:15 -0500 Subject: [PATCH 2104/3725] Remove C++11 explicit on conversion operator --- apps/openmw/mwworld/weather.cpp | 14 ++++++++++---- apps/openmw/mwworld/weather.hpp | 2 +- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 8799ae57c..744cae28b 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -127,7 +127,13 @@ RegionWeather::RegionWeather(const ESM::RegionWeatherState& state) RegionWeather::operator ESM::RegionWeatherState() const { - return ESM::RegionWeatherState { mWeather, mChances }; + ESM::RegionWeatherState state = + { + mWeather, + mChances + }; + + return state; } void RegionWeather::setChances(const std::vector& chances) @@ -370,12 +376,12 @@ WeatherManager::WeatherManager(MWRender::RenderingManager& rendering, const MWWo , mWeatherSettings() , mMasser("Masser", fallback) , mSecunda("Secunda", fallback) + , mThunderFrequency(fallback.getFallbackFloat("Weather_Thunderstorm_Thunder_Frequency")) + , mThunderThreshold(fallback.getFallbackFloat("Weather_Thunderstorm_Thunder_Threshold")) , mThunderSoundID0(fallback.getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_0")) , mThunderSoundID1(fallback.getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_1")) , mThunderSoundID2(fallback.getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_2")) , mThunderSoundID3(fallback.getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_3")) - , mThunderFrequency(fallback.getFallbackFloat("Weather_Thunderstorm_Thunder_Frequency")) - , mThunderThreshold(fallback.getFallbackFloat("Weather_Thunderstorm_Thunder_Threshold")) , mWindSpeed(0.f) , mIsStorm(false) , mStormDirection(0,1,0) @@ -705,7 +711,7 @@ void WeatherManager::write(ESM::ESMWriter& writer, Loading::Listener& progress) std::map::iterator it = mRegions.begin(); for(; it != mRegions.end(); ++it) { - state.mRegions.insert(std::make_pair(it->first, ESM::RegionWeatherState(it->second))); + state.mRegions.insert(std::make_pair(it->first, it->second)); } writer.startRecord(ESM::REC_WTHR); diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index d07e7e1e4..cdbe14dfa 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -127,7 +127,7 @@ namespace MWWorld explicit RegionWeather(const ESM::Region& region); explicit RegionWeather(const ESM::RegionWeatherState& state); - explicit operator ESM::RegionWeatherState() const; + operator ESM::RegionWeatherState() const; void setChances(const std::vector& chances); From 95d2d82abf75c533fe9fbec2446d7038696094e7 Mon Sep 17 00:00:00 2001 From: dteviot Date: Thu, 27 Aug 2015 18:36:46 +1200 Subject: [PATCH 2105/3725] extracted isFlagBitSet() --- apps/openmw/mwclass/creature.cpp | 60 ++++++++++++-------------------- apps/openmw/mwclass/creature.hpp | 7 ++++ 2 files changed, 29 insertions(+), 38 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index e14d9f8ba..80934f885 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -129,7 +129,8 @@ namespace MWClass } // inventory - if (ref->mBase->mFlags & ESM::Creature::Weapon) + bool hasInventory = hasInventoryStore(ptr); + if (hasInventory) data->mContainerStore = new MWWorld::InventoryStore(); else data->mContainerStore = new MWWorld::ContainerStore(); @@ -143,7 +144,7 @@ namespace MWClass getContainerStore(ptr).fill(ref->mBase->mInventory, getId(ptr)); - if (ref->mBase->mFlags & ESM::Creature::Weapon) + if (hasInventory) getInventoryStore(ptr).autoEquip(ptr); } } @@ -158,10 +159,8 @@ namespace MWClass void Creature::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { - MWWorld::LiveCellRef *ref = ptr.get(); - MWRender::Objects& objects = renderingInterface.getObjects(); - objects.insertCreature(ptr, model, (ref->mBase->mFlags & ESM::Creature::Weapon) != 0); + objects.insertCreature(ptr, model, hasInventoryStore(ptr)); } std::string Creature::getModel(const MWWorld::Ptr &ptr) const @@ -422,9 +421,7 @@ namespace MWClass MWWorld::InventoryStore& Creature::getInventoryStore(const MWWorld::Ptr &ptr) const { - MWWorld::LiveCellRef *ref = ptr.get(); - - if (ref->mBase->mFlags & ESM::Creature::Weapon) + if (hasInventoryStore(ptr)) return dynamic_cast(getContainerStore(ptr)); else throw std::runtime_error("this creature has no inventory store"); @@ -432,9 +429,7 @@ namespace MWClass bool Creature::hasInventoryStore(const MWWorld::Ptr &ptr) const { - MWWorld::LiveCellRef *ref = ptr.get(); - - return (ref->mBase->mFlags & ESM::Creature::Weapon) != 0; + return isFlagBitSet(ptr, ESM::Creature::Weapon); } std::string Creature::getScript (const MWWorld::Ptr& ptr) const @@ -446,10 +441,7 @@ namespace MWClass bool Creature::isEssential (const MWWorld::Ptr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); - - return (ref->mBase->mFlags & ESM::Creature::Essential) != 0; + return isFlagBitSet(ptr, ESM::Creature::Essential); } void Creature::registerSelf() @@ -601,34 +593,22 @@ namespace MWClass bool Creature::isBipedal(const MWWorld::Ptr &ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); - - return ref->mBase->mFlags & ESM::Creature::Bipedal; + return isFlagBitSet(ptr, ESM::Creature::Bipedal); } bool Creature::canFly(const MWWorld::Ptr &ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); - - return (ref->mBase->mFlags & ESM::Creature::Flies) != 0; + return isFlagBitSet(ptr, ESM::Creature::Flies); } bool Creature::canSwim(const MWWorld::Ptr &ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); - - return ref->mBase->mFlags & ESM::Creature::Swims || ref->mBase->mFlags & ESM::Creature::Bipedal; + return isFlagBitSet(ptr, static_cast(ESM::Creature::Swims | ESM::Creature::Bipedal)); } bool Creature::canWalk(const MWWorld::Ptr &ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); - - return ref->mBase->mFlags & ESM::Creature::Walks || ref->mBase->mFlags & ESM::Creature::Bipedal; + return isFlagBitSet(ptr, static_cast(ESM::Creature::Walks | ESM::Creature::Bipedal)); } int Creature::getSndGenTypeFromName(const MWWorld::Ptr &ptr, const std::string &name) @@ -691,11 +671,11 @@ namespace MWClass int Creature::getBloodTexture(const MWWorld::Ptr &ptr) const { - MWWorld::LiveCellRef *ref = ptr.get(); + int flags = ptr.get()->mBase->mFlags; - if (ref->mBase->mFlags & ESM::Creature::Skeleton) + if (flags & ESM::Creature::Skeleton) return 1; - if (ref->mBase->mFlags & ESM::Creature::Metal) + if (flags & ESM::Creature::Metal) return 2; return 0; } @@ -715,9 +695,7 @@ namespace MWClass // Create a CustomData, but don't fill it from ESM records (not needed) std::auto_ptr data (new CreatureCustomData); - MWWorld::LiveCellRef *ref = ptr.get(); - - if (ref->mBase->mFlags & ESM::Creature::Weapon) + if (hasInventoryStore(ptr)) data->mContainerStore = new MWWorld::InventoryStore(); else data->mContainerStore = new MWWorld::ContainerStore(); @@ -760,7 +738,7 @@ namespace MWClass void Creature::respawn(const MWWorld::Ptr &ptr) const { - if (ptr.get()->mBase->mFlags & ESM::Creature::Respawn) + if (isFlagBitSet(ptr, ESM::Creature::Respawn)) { // Note we do not respawn moved references in the cell they were moved to. Instead they are respawned in the original cell. // This also means we cannot respawn dynamically placed references with no content file connection. @@ -796,4 +774,10 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); scale *= ref->mBase->mScale; } + + bool Creature::isFlagBitSet(const MWWorld::Ptr &ptr, ESM::Creature::Flags bitMask) const + { + MWWorld::LiveCellRef *ref = ptr.get(); + return (ref->mBase->mFlags & bitMask) != 0; + } } diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index c4ea09255..1a29d0318 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -1,6 +1,8 @@ #ifndef GAME_MWCLASS_CREATURE_H #define GAME_MWCLASS_CREATURE_H +#include + #include "actor.hpp" namespace ESM @@ -134,6 +136,11 @@ namespace MWClass virtual int getBaseFightRating(const MWWorld::Ptr &ptr) const; virtual void adjustScale(const MWWorld::Ptr& ptr, osg::Vec3f& scale) const; + + private: + + /// \return true if any of the indicated bits in Creature's mFlags is set + bool isFlagBitSet(const MWWorld::Ptr &ptr, ESM::Creature::Flags bitMask) const; }; } From 7817c52cbb6e7f67d4cc49a8b07a89f3d26d5407 Mon Sep 17 00:00:00 2001 From: slothlife Date: Thu, 27 Aug 2015 09:57:32 -0500 Subject: [PATCH 2106/3725] Discard old save game weather records --- apps/openmw/mwworld/weather.cpp | 49 ++++++++++++++++++++------------- components/esm/savedgame.cpp | 2 +- 2 files changed, 31 insertions(+), 20 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 744cae28b..43b2a0dff 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -5,7 +5,9 @@ #include +#include #include +#include #include #include "../mwbase/environment.hpp" @@ -723,30 +725,39 @@ bool WeatherManager::readRecord(ESM::ESMReader& reader, uint32_t type) { if(ESM::REC_WTHR == type) { - ESM::WeatherState state; - state.load(reader); - - mCurrentRegion.swap(state.mCurrentRegion); - mTimePassed = state.mTimePassed; - mFastForward = state.mFastForward; - mWeatherUpdateTime = state.mWeatherUpdateTime; - mTransitionFactor = state.mTransitionFactor; - mCurrentWeather = state.mCurrentWeather; - mNextWeather = state.mCurrentWeather; - mQueuedWeather = state.mQueuedWeather; - - mRegions.clear(); - std::map::iterator it = state.mRegions.begin(); - if(it == state.mRegions.end()) + if(reader.getFormat() < ESM::SavedGame::sCurrentFormat) { - // When loading an imported save, the region modifiers aren't currently being set, so just reset them. - importRegions(); + // Weather state isn't really all that important, so to preserve older save games, we'll just discard the + // older weather records, rather than fail to handle the record. + reader.skipRecord(); } else { - for(; it != state.mRegions.end(); ++it) + ESM::WeatherState state; + state.load(reader); + + mCurrentRegion.swap(state.mCurrentRegion); + mTimePassed = state.mTimePassed; + mFastForward = state.mFastForward; + mWeatherUpdateTime = state.mWeatherUpdateTime; + mTransitionFactor = state.mTransitionFactor; + mCurrentWeather = state.mCurrentWeather; + mNextWeather = state.mCurrentWeather; + mQueuedWeather = state.mQueuedWeather; + + mRegions.clear(); + std::map::iterator it = state.mRegions.begin(); + if(it == state.mRegions.end()) { - mRegions.insert(std::make_pair(it->first, RegionWeather(it->second))); + // When loading an imported save, the region modifiers aren't currently being set, so just reset them. + importRegions(); + } + else + { + for(; it != state.mRegions.end(); ++it) + { + mRegions.insert(std::make_pair(it->first, RegionWeather(it->second))); + } } } diff --git a/components/esm/savedgame.cpp b/components/esm/savedgame.cpp index 2e5509b7a..cf9f68c9a 100644 --- a/components/esm/savedgame.cpp +++ b/components/esm/savedgame.cpp @@ -5,7 +5,7 @@ #include "defs.hpp" unsigned int ESM::SavedGame::sRecordId = ESM::REC_SAVE; -int ESM::SavedGame::sCurrentFormat = 1; +int ESM::SavedGame::sCurrentFormat = 2; void ESM::SavedGame::load (ESMReader &esm) { From cd8ec5c11e48def47b69373a1f5f779da84a3e43 Mon Sep 17 00:00:00 2001 From: slothlife Date: Thu, 27 Aug 2015 10:34:35 -0500 Subject: [PATCH 2107/3725] Improve checking for older weather records --- apps/openmw/mwworld/weather.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 43b2a0dff..5c2a81c09 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -725,7 +725,8 @@ bool WeatherManager::readRecord(ESM::ESMReader& reader, uint32_t type) { if(ESM::REC_WTHR == type) { - if(reader.getFormat() < ESM::SavedGame::sCurrentFormat) + static const int oldestCompatibleSaveFormat = 2; + if(reader.getFormat() < oldestCompatibleSaveFormat) { // Weather state isn't really all that important, so to preserve older save games, we'll just discard the // older weather records, rather than fail to handle the record. From 4fd00a75d5814a495f150b302570e7779bb48132 Mon Sep 17 00:00:00 2001 From: slothlife Date: Thu, 27 Aug 2015 14:20:45 -0500 Subject: [PATCH 2108/3725] Merge advanceTime and advanceTimeByFrame --- apps/openmw/engine.cpp | 5 ++++- apps/openmw/mwbase/world.hpp | 5 +---- apps/openmw/mwworld/weather.cpp | 15 ++++----------- apps/openmw/mwworld/weather.hpp | 3 +-- apps/openmw/mwworld/worldimp.cpp | 23 ++--------------------- apps/openmw/mwworld/worldimp.hpp | 5 +---- 6 files changed, 13 insertions(+), 43 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 6c95700b3..32ff20ba7 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -128,7 +128,10 @@ void OMW::Engine::frame(float frametime) } if (!guiActive) - mEnvironment.getWorld()->advanceTimeByFrame(frametime); + { + double hours = (frametime * mEnvironment.getWorld()->getTimeScaleFactor()) / 3600.0; + mEnvironment.getWorld()->advanceTime(hours, true); + } } osg::Timer_t afterScriptTick = osg::Timer::instance()->tick(); diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 636370342..a3d293d95 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -185,12 +185,9 @@ namespace MWBase virtual void disable (const MWWorld::Ptr& ptr) = 0; - virtual void advanceTime (double hours) = 0; + virtual void advanceTime (double hours, bool incremental = false) = 0; ///< Advance in-game time. - virtual void advanceTimeByFrame (double frametime) = 0; - ///< Advance in-game time by the duration of a frame. - virtual void setHour (double hour) = 0; ///< Set in-game time hour. diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 5c2a81c09..52609f21a 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -670,19 +670,12 @@ osg::Vec3f WeatherManager::getStormDirection() const return mStormDirection; } -void WeatherManager::advanceTime(double hours) +void WeatherManager::advanceTime(double hours, bool incremental) { - // This is called when the player sleeps/waits, serves jail time, travels, or trains. - // In Morrowind, when any of those events occur, all weather transitions are immediately applied, regardless of - // whatever transition time might have been remaining. - mTimePassed += hours; - mFastForward = true; -} - -void WeatherManager::advanceTimeByFrame(double hours) -{ - // Called when time is advanced by an incremental update for each frame. + // In Morrowind, when the player sleeps/waits, serves jail time, travels, or trains, all weather transitions are + // immediately applied, regardless of whatever transition time might have been remaining. mTimePassed += hours; + mFastForward = (!mFastForward && !incremental) ? true : mFastForward; } unsigned int WeatherManager::getWeatherID() const diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index cdbe14dfa..c808b029b 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -206,8 +206,7 @@ namespace MWWorld osg::Vec3f getStormDirection() const; - void advanceTime(double hours); - void advanceTimeByFrame(double hours); + void advanceTime(double hours, bool incremental); unsigned int getWeatherID() const; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 56c7415a2..5f9c8f8d3 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -787,30 +787,11 @@ namespace MWWorld } } - void World::advanceTime (double hours) + void World::advanceTime (double hours, bool incremental) { MWBase::Environment::get().getMechanicsManager()->advanceTime(static_cast(hours * 3600)); - mWeatherManager->advanceTime (hours); - - hours += mGlobalVariables["gamehour"].getFloat(); - - setHour (hours); - - int days = static_cast(hours / 24); - - if (days>0) - mGlobalVariables["dayspassed"].setInteger ( - days + mGlobalVariables["dayspassed"].getInteger()); - } - - void World::advanceTimeByFrame (double frametime) - { - double hours = (frametime * getTimeScaleFactor()) / 3600.0; - - MWBase::Environment::get().getMechanicsManager()->advanceTime(static_cast(hours * 3600)); - - mWeatherManager->advanceTimeByFrame (hours); + mWeatherManager->advanceTime (hours, incremental); hours += mGlobalVariables["gamehour"].getFloat(); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 80fe6d850..241dacc8a 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -274,12 +274,9 @@ namespace MWWorld virtual void disable (const Ptr& ptr); - virtual void advanceTime (double hours); + virtual void advanceTime (double hours, bool incremental = false); ///< Advance in-game time. - virtual void advanceTimeByFrame (double frametime); - ///< Advance in-game time by the duration of a frame. - virtual void setHour (double hour); ///< Set in-game time hour. From 300c48329d447ec6a43b67a597005a4ce2fcd7fb Mon Sep 17 00:00:00 2001 From: dteviot Date: Fri, 28 Aug 2015 18:38:05 +1200 Subject: [PATCH 2109/3725] Creature::isFlagBitSet() changed to free function. --- apps/openmw/mwclass/creature.cpp | 11 +++++------ apps/openmw/mwclass/creature.hpp | 7 ------- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 80934f885..450889eb2 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -58,6 +58,11 @@ namespace cloned->mContainerStore = mContainerStore->clone(); return cloned; } + + bool isFlagBitSet(const MWWorld::Ptr &ptr, ESM::Creature::Flags bitMask) + { + return (ptr.get()->mBase->mFlags & bitMask) != 0; + } } namespace MWClass @@ -774,10 +779,4 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); scale *= ref->mBase->mScale; } - - bool Creature::isFlagBitSet(const MWWorld::Ptr &ptr, ESM::Creature::Flags bitMask) const - { - MWWorld::LiveCellRef *ref = ptr.get(); - return (ref->mBase->mFlags & bitMask) != 0; - } } diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index 1a29d0318..c4ea09255 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -1,8 +1,6 @@ #ifndef GAME_MWCLASS_CREATURE_H #define GAME_MWCLASS_CREATURE_H -#include - #include "actor.hpp" namespace ESM @@ -136,11 +134,6 @@ namespace MWClass virtual int getBaseFightRating(const MWWorld::Ptr &ptr) const; virtual void adjustScale(const MWWorld::Ptr& ptr, osg::Vec3f& scale) const; - - private: - - /// \return true if any of the indicated bits in Creature's mFlags is set - bool isFlagBitSet(const MWWorld::Ptr &ptr, ESM::Creature::Flags bitMask) const; }; } From d9a7986b3a654847be77826626d68bc5ba1b22c2 Mon Sep 17 00:00:00 2001 From: slothlife Date: Fri, 28 Aug 2015 18:04:22 -0500 Subject: [PATCH 2110/3725] Remove redundant fast forward check --- apps/openmw/mwworld/weather.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 52609f21a..da1f2f7e6 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -675,7 +675,7 @@ void WeatherManager::advanceTime(double hours, bool incremental) // In Morrowind, when the player sleeps/waits, serves jail time, travels, or trains, all weather transitions are // immediately applied, regardless of whatever transition time might have been remaining. mTimePassed += hours; - mFastForward = (!mFastForward && !incremental) ? true : mFastForward; + mFastForward = !incremental ? true : mFastForward; } unsigned int WeatherManager::getWeatherID() const From 2b48a20b76ef0ca85311bfce201477ea799b30d6 Mon Sep 17 00:00:00 2001 From: slothlife Date: Fri, 28 Aug 2015 23:12:39 -0500 Subject: [PATCH 2111/3725] Fix weather transition bugs --- apps/openmw/mwworld/weather.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index da1f2f7e6..e7c67d2e1 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -736,7 +736,7 @@ bool WeatherManager::readRecord(ESM::ESMReader& reader, uint32_t type) mWeatherUpdateTime = state.mWeatherUpdateTime; mTransitionFactor = state.mTransitionFactor; mCurrentWeather = state.mCurrentWeather; - mNextWeather = state.mCurrentWeather; + mNextWeather = state.mNextWeather; mQueuedWeather = state.mQueuedWeather; mRegions.clear(); @@ -884,6 +884,8 @@ inline void WeatherManager::updateWeatherTransitions(const float elapsedRealSeco mCurrentWeather = mNextWeather; } + mNextWeather = invalidWeatherID; + mQueuedWeather = invalidWeatherID; mFastForward = false; } } From 067779983986e91b226e9a3c8932094b2330d377 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sat, 29 Aug 2015 17:21:18 +1200 Subject: [PATCH 2112/3725] movement logic in AiPackage uses ObstacleCheck. --- apps/openmw/mwmechanics/aipackage.cpp | 27 ++++++++++----------------- apps/openmw/mwmechanics/aipackage.hpp | 2 -- 2 files changed, 10 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index 2c8c57c56..c18ee5ceb 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -19,7 +19,7 @@ MWMechanics::AiPackage::~AiPackage() {} -MWMechanics::AiPackage::AiPackage() : mTimer(0.26f), mStuckTimer(0) { //mTimer starts at .26 to force initial pathbuild +MWMechanics::AiPackage::AiPackage() : mTimer(0.26f) { //mTimer starts at .26 to force initial pathbuild } @@ -28,7 +28,6 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, ESM::Pathgrid::Po { //Update various Timers mTimer += duration; //Update timer - mStuckTimer += duration; //Update stuck timer ESM::Position pos = actor.getRefData().getPosition(); //position of the actor @@ -91,11 +90,13 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, ESM::Pathgrid::Po //************************ if(mPathFinder.checkPathCompleted(pos.pos[0],pos.pos[1])) //Path finished? return true; - else if(mStuckTimer>0.5) //Every half second see if we need to take action to avoid something + else { -/// TODO (tluppi#1#): Use ObstacleCheck here. Not working for some reason - //if(mObstacleCheck.check(actor, duration)) { - if(distance(start, mStuckPos.pos[0], mStuckPos.pos[1], mStuckPos.pos[2]) < actor.getClass().getSpeed(actor)*0.05 && distance(dest, start) > 20) { //Actually stuck, and far enough away from destination to care + zTurn(actor, mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1])); + + MWMechanics::Movement& movement = actor.getClass().getMovementSettings(actor); + if(mObstacleCheck.check(actor, duration)) + { // first check if we're walking into a door MWWorld::Ptr door = getNearbyDoor(actor); if(door != MWWorld::Ptr()) // NOTE: checks interior cells only @@ -106,24 +107,16 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, ESM::Pathgrid::Po } else // probably walking into another NPC { - actor.getClass().getMovementSettings(actor).mPosition[0] = 1; - actor.getClass().getMovementSettings(actor).mPosition[1] = 1; + movement.mPosition[0] = 1; + movement.mPosition[1] = 1; // change the angle a bit, too zTurn(actor, mPathFinder.getZAngleToNext(pos.pos[0] + 1, pos.pos[1])); } } else { //Not stuck, so reset things - mStuckTimer = 0; - mStuckPos = pos; - actor.getClass().getMovementSettings(actor).mPosition[1] = 1; //Just run forward + movement.mPosition[1] = 1; //Just run forward } } - else { - actor.getClass().getMovementSettings(actor).mPosition[1] = 1; //Just run forward the rest of the time - } - - zTurn(actor, mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1])); - return false; } diff --git a/apps/openmw/mwmechanics/aipackage.hpp b/apps/openmw/mwmechanics/aipackage.hpp index d73833b94..00cab2d08 100644 --- a/apps/openmw/mwmechanics/aipackage.hpp +++ b/apps/openmw/mwmechanics/aipackage.hpp @@ -83,9 +83,7 @@ namespace MWMechanics ObstacleCheck mObstacleCheck; float mTimer; - float mStuckTimer; - ESM::Position mStuckPos; ESM::Pathgrid::Point mPrevDest; }; } From f59e918a3b697e119a224b86c7ac2edd591e978f Mon Sep 17 00:00:00 2001 From: dteviot Date: Sat, 29 Aug 2015 17:34:33 +1200 Subject: [PATCH 2113/3725] removed useless code. zTurn ignores turns < 0.0087 radians. --- apps/openmw/mwmechanics/aipackage.cpp | 2 -- apps/openmw/mwmechanics/aiwander.cpp | 3 --- 2 files changed, 5 deletions(-) diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index c18ee5ceb..36843663e 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -109,8 +109,6 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, ESM::Pathgrid::Po { movement.mPosition[0] = 1; movement.mPosition[1] = 1; - // change the angle a bit, too - zTurn(actor, mPathFinder.getZAngleToNext(pos.pos[0] + 1, pos.pos[1])); } } else { //Not stuck, so reset things diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 8f27a2048..01d8125b3 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -437,9 +437,6 @@ namespace MWMechanics // but doesn't seem to do that? actor.getClass().getMovementSettings(actor).mPosition[0] = 1; actor.getClass().getMovementSettings(actor).mPosition[1] = 0.1f; - // change the angle a bit, too - const ESM::Position& pos = actor.getRefData().getPosition(); - zTurn(actor, storage.mPathFinder.getZAngleToNext(pos.pos[0] + 1, pos.pos[1])); } mStuckCount++; // TODO: maybe no longer needed } From 31d82b6b0c09a9e1cf2296fc46a2c40bdaf10627 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 30 Aug 2015 08:32:47 +1200 Subject: [PATCH 2114/3725] Unifiy evadeObstacles() logic between AiWander and AiPackage Can't use same code, but logic is now same. --- apps/openmw/mwmechanics/aipackage.cpp | 41 +++++++++++++++------------ apps/openmw/mwmechanics/aipackage.hpp | 4 +++ apps/openmw/mwmechanics/aiwander.cpp | 20 +++++++------ apps/openmw/mwmechanics/aiwander.hpp | 2 +- 4 files changed, 40 insertions(+), 27 deletions(-) diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index 36843663e..097cc4042 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -92,30 +92,35 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, ESM::Pathgrid::Po return true; else { - zTurn(actor, mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1])); + evadeObstacles(actor, duration, pos); + } + return false; +} - MWMechanics::Movement& movement = actor.getClass().getMovementSettings(actor); - if(mObstacleCheck.check(actor, duration)) +void MWMechanics::AiPackage::evadeObstacles(const MWWorld::Ptr& actor, float duration, ESM::Position& pos) +{ + zTurn(actor, mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1])); + + MWMechanics::Movement& movement = actor.getClass().getMovementSettings(actor); + if (mObstacleCheck.check(actor, duration)) + { + // first check if we're walking into a door + MWWorld::Ptr door = getNearbyDoor(actor); + if (door != MWWorld::Ptr()) // NOTE: checks interior cells only { - // first check if we're walking into a door - MWWorld::Ptr door = getNearbyDoor(actor); - if(door != MWWorld::Ptr()) // NOTE: checks interior cells only - { - if(!door.getCellRef().getTeleport() && door.getCellRef().getTrap().empty() && door.getClass().getDoorState(door) == 0) { //Open the door if untrapped - MWBase::Environment::get().getWorld()->activateDoor(door, 1); - } - } - else // probably walking into another NPC - { - movement.mPosition[0] = 1; - movement.mPosition[1] = 1; + if (!door.getCellRef().getTeleport() && door.getCellRef().getTrap().empty() && door.getClass().getDoorState(door) == 0) { //Open the door if untrapped + MWBase::Environment::get().getWorld()->activateDoor(door, 1); } } - else { //Not stuck, so reset things - movement.mPosition[1] = 1; //Just run forward + else // probably walking into another NPC + { + movement.mPosition[0] = 1; + movement.mPosition[1] = 1; } } - return false; + else { //Not stuck, so reset things + movement.mPosition[1] = 1; //Just run forward + } } bool MWMechanics::AiPackage::doesPathNeedRecalc(ESM::Pathgrid::Point dest, const ESM::Cell *cell) diff --git a/apps/openmw/mwmechanics/aipackage.hpp b/apps/openmw/mwmechanics/aipackage.hpp index 00cab2d08..4f919edbc 100644 --- a/apps/openmw/mwmechanics/aipackage.hpp +++ b/apps/openmw/mwmechanics/aipackage.hpp @@ -85,6 +85,10 @@ namespace MWMechanics float mTimer; ESM::Pathgrid::Point mPrevDest; + + private: + void evadeObstacles(const MWWorld::Ptr& actor, float duration, ESM::Position& pos); + }; } diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 01d8125b3..ce70fee77 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -381,11 +381,7 @@ namespace MWMechanics else { // have not yet reached the destination - //... turn towards the next point in mPath - zTurn(actor, storage.mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1])); - actor.getClass().getMovementSettings(actor).mPosition[1] = 1; - - evadeObstacles(actor, storage, duration); + evadeObstacles(actor, storage, duration, pos); } } @@ -417,8 +413,12 @@ namespace MWMechanics storage.mState = Wander_IdleNow; } - void AiWander::evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration) + void AiWander::evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration, ESM::Position& pos) { + // turn towards the next point in mPath + zTurn(actor, storage.mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1])); + + MWMechanics::Movement& movement = actor.getClass().getMovementSettings(actor); if (mObstacleCheck.check(actor, duration)) { // first check if we're walking into a door @@ -435,11 +435,15 @@ namespace MWMechanics { // TODO: diagonal should have same animation as walk forward // but doesn't seem to do that? - actor.getClass().getMovementSettings(actor).mPosition[0] = 1; - actor.getClass().getMovementSettings(actor).mPosition[1] = 0.1f; + movement.mPosition[0] = 1; + movement.mPosition[1] = 0.1f; } mStuckCount++; // TODO: maybe no longer needed } + else + { + movement.mPosition[1] = 1; + } //#if 0 // TODO: maybe no longer needed if (mStuckCount >= COUNT_BEFORE_RESET) // something has gone wrong, reset diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 27e6fe9fb..b0fabfce3 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -83,7 +83,7 @@ namespace MWMechanics short unsigned getRandomIdle(); void setPathToAnAllowedNode(const MWWorld::Ptr& actor, AiWanderStorage& storage, const ESM::Position& actorPos); void playGreetingIfPlayerGetsTooClose(const MWWorld::Ptr& actor, AiWanderStorage& storage); - void evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration); + void evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration, ESM::Position& pos); void playIdleDialogueRandomly(const MWWorld::Ptr& actor); void turnActorToFacePlayer(const osg::Vec3f& actorPosition, const osg::Vec3f& playerPosition, AiWanderStorage& storage); void doPerFrameActionsForState(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage, ESM::Position& pos); From f2c9b9351f702d18e8ca3e2fcb97d640780fa8bf Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 30 Aug 2015 10:06:09 +1200 Subject: [PATCH 2115/3725] Try going right and left to "unstick" actor. --- apps/openmw/mwmechanics/aipackage.cpp | 3 +-- apps/openmw/mwmechanics/aiwander.cpp | 3 +-- apps/openmw/mwmechanics/obstacle.cpp | 20 ++++++++++++++++++++ apps/openmw/mwmechanics/obstacle.hpp | 8 ++++++++ 4 files changed, 30 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index 097cc4042..b6b240833 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -114,8 +114,7 @@ void MWMechanics::AiPackage::evadeObstacles(const MWWorld::Ptr& actor, float dur } else // probably walking into another NPC { - movement.mPosition[0] = 1; - movement.mPosition[1] = 1; + mObstacleCheck.takeEvasiveAction(movement); } } else { //Not stuck, so reset things diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index ce70fee77..67a9f766c 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -435,8 +435,7 @@ namespace MWMechanics { // TODO: diagonal should have same animation as walk forward // but doesn't seem to do that? - movement.mPosition[0] = 1; - movement.mPosition[1] = 0.1f; + mObstacleCheck.takeEvasiveAction(movement); } mStuckCount++; // TODO: maybe no longer needed } diff --git a/apps/openmw/mwmechanics/obstacle.cpp b/apps/openmw/mwmechanics/obstacle.cpp index 25bd06301..fe3d68a58 100644 --- a/apps/openmw/mwmechanics/obstacle.cpp +++ b/apps/openmw/mwmechanics/obstacle.cpp @@ -6,6 +6,8 @@ #include "../mwworld/class.hpp" #include "../mwworld/cellstore.hpp" +#include "movement.hpp" + namespace MWMechanics { // NOTE: determined empirically but probably need further tweaking @@ -67,6 +69,7 @@ namespace MWMechanics , mStuckDuration(0) , mEvadeDuration(0) , mDistSameSpot(-1) // avoid calculating it each time + , mEvadeDirection(1.0f) { } @@ -155,6 +158,7 @@ namespace MWMechanics /* FALL THROUGH */ case State_Evade: { + chooseEvasionDirection(samePosition); mEvadeDuration += duration; if(mEvadeDuration < DURATION_TO_EVADE) return true; @@ -169,4 +173,20 @@ namespace MWMechanics } return false; // no obstacles to evade (yet) } + + void ObstacleCheck::takeEvasiveAction(MWMechanics::Movement& actorMovement) + { + actorMovement.mPosition[0] = mEvadeDirection; + actorMovement.mPosition[1] = 0; + } + + void ObstacleCheck::chooseEvasionDirection(bool samePosition) + { + // change direction if attempt didn't work + if (samePosition && (0 < mEvadeDuration)) + { + mEvadeDirection = mEvadeDirection == 1.0f ? -1.0f : 1.0f; + } + } + } diff --git a/apps/openmw/mwmechanics/obstacle.hpp b/apps/openmw/mwmechanics/obstacle.hpp index e0ae9203d..ef3e29e8b 100644 --- a/apps/openmw/mwmechanics/obstacle.hpp +++ b/apps/openmw/mwmechanics/obstacle.hpp @@ -8,6 +8,8 @@ namespace MWWorld namespace MWMechanics { + struct Movement; + /// NOTE: determined empirically based on in-game behaviour static const float MIN_DIST_TO_DOOR_SQUARED = 128*128; @@ -36,6 +38,9 @@ namespace MWMechanics // should be taken bool check(const MWWorld::Ptr& actor, float duration); + // change direction to try to fix "stuck" actor + void takeEvasiveAction(MWMechanics::Movement& actorMovement); + private: // for checking if we're stuck (ignoring Z axis) @@ -53,6 +58,9 @@ namespace MWMechanics float mStuckDuration; // accumulate time here while in same spot float mEvadeDuration; float mDistSameSpot; // take account of actor's speed + float mEvadeDirection; + + void chooseEvasionDirection(bool samePosition); }; } From 39c2ba8efe98aa4d9f29f06450a62f2081d372c9 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 30 Aug 2015 16:12:51 +1200 Subject: [PATCH 2116/3725] Pathfinding bugfix. Observed at Ebonheart (coe 1, -13). Especially at the western tower. Guards try to walk though tower door. Cause: buildPath() adds destination (even when unreachable) when only using single node from pathgrid. --- apps/openmw/mwmechanics/pathfinding.cpp | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index f53badbf4..daab32136 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -225,19 +225,16 @@ namespace MWMechanics ESM::Pathgrid::Point temp(mPathgrid->mPoints[startNode]); converter.ToWorld(temp); mPath.push_back(temp); - - mPath.push_back(endPoint); - return; } - - mPath = mCell->aStarSearch(startNode, endNode.first); - if (mPath.empty()) - return; - - // convert supplied path to world co-ordinates - for (std::list::iterator iter(mPath.begin()); iter != mPath.end(); ++iter) + else { - converter.ToWorld(*iter); + mPath = mCell->aStarSearch(startNode, endNode.first); + + // convert supplied path to world co-ordinates + for (std::list::iterator iter(mPath.begin()); iter != mPath.end(); ++iter) + { + converter.ToWorld(*iter); + } } // If endNode found is NOT the closest PathGrid point to the endPoint, @@ -254,8 +251,6 @@ namespace MWMechanics // The AI routines will have to deal with such situations. if(endNode.second) mPath.push_back(endPoint); - - return; } float PathFinder::getZAngleToNext(float x, float y) const From 1dfe438a5d37401b75bd2de491a2524cc92ffd21 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 30 Aug 2015 16:43:35 +1200 Subject: [PATCH 2117/3725] reduce "reset if stuck" AiWander timeout. Now is about 14 seconds, instead of 300. --- apps/openmw/mwmechanics/aiwander.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 67a9f766c..b789c4428 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -27,7 +27,7 @@ namespace MWMechanics { - static const int COUNT_BEFORE_RESET = 200; // TODO: maybe no longer needed + static const int COUNT_BEFORE_RESET = 10; static const float DOOR_CHECK_INTERVAL = 1.5f; static const float REACTION_INTERVAL = 0.25f; static const int GREETING_SHOULD_START = 4; //how many reaction intervals should pass before NPC can greet player @@ -443,8 +443,8 @@ namespace MWMechanics { movement.mPosition[1] = 1; } -//#if 0 - // TODO: maybe no longer needed + + // if stuck for sufficiently long, act like current location was the destination if (mStuckCount >= COUNT_BEFORE_RESET) // something has gone wrong, reset { //std::cout << "Reset \""<< cls.getName(actor) << "\"" << std::endl; @@ -454,7 +454,6 @@ namespace MWMechanics storage.mState = Wander_ChooseAction; mStuckCount = 0; } -//#endif } void AiWander::playIdleDialogueRandomly(const MWWorld::Ptr& actor) From b7983d08ba3f238f0cddad467049c87b17a3745f Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 30 Aug 2015 11:08:56 +0200 Subject: [PATCH 2118/3725] fixed merge stage order; added proper initialisation --- apps/opencs/model/tools/mergeoperation.cpp | 5 ++++- apps/opencs/model/tools/mergestages.cpp | 17 +++++++++++++++++ apps/opencs/model/tools/mergestages.hpp | 15 +++++++++++++++ apps/opencs/model/tools/mergestate.hpp | 2 ++ 4 files changed, 38 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/tools/mergeoperation.cpp b/apps/opencs/model/tools/mergeoperation.cpp index f9a89aaa1..89f22ef1a 100644 --- a/apps/opencs/model/tools/mergeoperation.cpp +++ b/apps/opencs/model/tools/mergeoperation.cpp @@ -9,7 +9,8 @@ CSMTools::MergeOperation::MergeOperation (CSMDoc::Document& document, ToUTF8::FromType encoding) : CSMDoc::Operation (CSMDoc::State_Merging, true), mState (document) { - appendStage (new FinishMergedDocumentStage (mState, encoding)); + appendStage (new StartMergeStage (mState)); + appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getGlobals)); appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getGmsts)); appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getSkills)); @@ -37,6 +38,8 @@ CSMTools::MergeOperation::MergeOperation (CSMDoc::Document& document, ToUTF8::Fr appendStage (new MergeRefIdsStage (mState)); appendStage (new MergeReferencesStage (mState)); + appendStage (new FinishMergedDocumentStage (mState, encoding)); + /// \todo Land, LandTextures } diff --git a/apps/opencs/model/tools/mergestages.cpp b/apps/opencs/model/tools/mergestages.cpp index 80f16ec14..349cc2925 100644 --- a/apps/opencs/model/tools/mergestages.cpp +++ b/apps/opencs/model/tools/mergestages.cpp @@ -8,6 +8,23 @@ #include "../doc/document.hpp" #include "../world/data.hpp" + +CSMTools::StartMergeStage::StartMergeStage (MergeState& state) +: mState (state) +{} + +int CSMTools::StartMergeStage::setup() +{ + return 1; +} + +void CSMTools::StartMergeStage::perform (int stage, CSMDoc::Messages& messages) +{ + mState.mCompleted = false; + mState.mTextureIndices.clear(); +} + + CSMTools::FinishMergedDocumentStage::FinishMergedDocumentStage (MergeState& state, ToUTF8::FromType encoding) : mState (state), mEncoder (encoding) {} diff --git a/apps/opencs/model/tools/mergestages.hpp b/apps/opencs/model/tools/mergestages.hpp index e1cc17a3e..7d62058f0 100644 --- a/apps/opencs/model/tools/mergestages.hpp +++ b/apps/opencs/model/tools/mergestages.hpp @@ -14,6 +14,21 @@ namespace CSMTools { + class StartMergeStage : public CSMDoc::Stage + { + MergeState& mState; + + public: + + StartMergeStage (MergeState& state); + + virtual int setup(); + ///< \return number of steps + + virtual void perform (int stage, CSMDoc::Messages& messages); + ///< Messages resulting from this stage will be appended to \a messages. + }; + class FinishMergedDocumentStage : public CSMDoc::Stage { MergeState& mState; diff --git a/apps/opencs/model/tools/mergestate.hpp b/apps/opencs/model/tools/mergestate.hpp index 4482ba6f4..077edc9d9 100644 --- a/apps/opencs/model/tools/mergestate.hpp +++ b/apps/opencs/model/tools/mergestate.hpp @@ -2,6 +2,7 @@ #define CSM_TOOLS_MERGESTATE_H #include +#include #include "../doc/document.hpp" @@ -12,6 +13,7 @@ namespace CSMTools std::auto_ptr mTarget; CSMDoc::Document& mSource; bool mCompleted; + std::map, int> mTextureIndices; // (texture, content file) -> new texture MergeState (CSMDoc::Document& source) : mSource (source), mCompleted (false) {} }; From 890bbb6b119bab1b9a7b5724ab3e6a769ede761a Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 30 Aug 2015 14:27:22 +0200 Subject: [PATCH 2119/3725] merge land texture tables --- apps/opencs/model/tools/mergeoperation.cpp | 5 +- apps/opencs/model/tools/mergestages.cpp | 79 ++++++++++++++++++++++ apps/opencs/model/tools/mergestages.hpp | 31 +++++++++ apps/opencs/model/tools/mergestate.hpp | 4 +- apps/opencs/model/world/data.cpp | 5 ++ apps/opencs/model/world/data.hpp | 2 + 6 files changed, 124 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/tools/mergeoperation.cpp b/apps/opencs/model/tools/mergeoperation.cpp index 89f22ef1a..9e791683c 100644 --- a/apps/opencs/model/tools/mergeoperation.cpp +++ b/apps/opencs/model/tools/mergeoperation.cpp @@ -37,10 +37,13 @@ CSMTools::MergeOperation::MergeOperation (CSMDoc::Document& document, ToUTF8::Fr appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getJournalInfos)); appendStage (new MergeRefIdsStage (mState)); appendStage (new MergeReferencesStage (mState)); + appendStage (new MergeReferencesStage (mState)); + appendStage (new ListLandTexturesMergeStage (mState)); + appendStage (new MergeLandTexturesStage (mState)); appendStage (new FinishMergedDocumentStage (mState, encoding)); - /// \todo Land, LandTextures + /// \todo Land } void CSMTools::MergeOperation::setTarget (std::auto_ptr document) diff --git a/apps/opencs/model/tools/mergestages.cpp b/apps/opencs/model/tools/mergestages.cpp index 349cc2925..f34ba8eb4 100644 --- a/apps/opencs/model/tools/mergestages.cpp +++ b/apps/opencs/model/tools/mergestages.cpp @@ -1,6 +1,8 @@ #include "mergestages.hpp" +#include + #include #include "mergestate.hpp" @@ -104,3 +106,80 @@ void CSMTools::MergeReferencesStage::perform (int stage, CSMDoc::Messages& messa mState.mTarget->getData().getReferences().appendRecord (newRecord); } } + + +CSMTools::ListLandTexturesMergeStage::ListLandTexturesMergeStage (MergeState& state) +: mState (state) +{} + +int CSMTools::ListLandTexturesMergeStage::setup() +{ + return mState.mSource.getData().getLand().getSize(); +} + +void CSMTools::ListLandTexturesMergeStage::perform (int stage, CSMDoc::Messages& messages) +{ + const CSMWorld::Record& record = + mState.mSource.getData().getLand().getRecord (stage); + + if (!record.isDeleted()) + { + ESM::Land& land = *record.get().mLand; + + // make sure record is loaded + land.loadData (ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML | + ESM::Land::DATA_VCLR | ESM::Land::DATA_VTEX | ESM::Land::DATA_WNAM); + + if (land.mLandData) + { + // list texture indices + std::pair key; + key.second = land.mPlugin; + + for (int i=0; imTextures[i]; + + mState.mTextureIndices[key] = -1; + } + } + } +} + + +CSMTools::MergeLandTexturesStage::MergeLandTexturesStage (MergeState& state) +: mState (state), mNext (mState.mTextureIndices.end()) +{} + +int CSMTools::MergeLandTexturesStage::setup() +{ + mNext = mState.mTextureIndices.begin(); + return mState.mTextureIndices.size(); +} + +void CSMTools::MergeLandTexturesStage::perform (int stage, CSMDoc::Messages& messages) +{ + mNext->second = stage; + + std::ostringstream stream; + stream << mNext->first.first << "_" << mNext->first.second; + + int index = mState.mSource.getData().getLandTextures().searchId (stream.str()); + + if (index!=-1) + { + CSMWorld::LandTexture texture = + mState.mSource.getData().getLandTextures().getRecord (index).get(); + + texture.mIndex = mNext->second; + texture.mId = stream.str(); + + CSMWorld::Record newRecord ( + CSMWorld::RecordBase::State_ModifiedOnly, 0, &texture); + + mState.mTarget->getData().getLandTextures().appendRecord (newRecord); + } + /// \todo deal with missing textures (either abort merge or report and make sure OpenMW can deal with missing textures) + + ++mNext; +} diff --git a/apps/opencs/model/tools/mergestages.hpp b/apps/opencs/model/tools/mergestages.hpp index 7d62058f0..f0ae99842 100644 --- a/apps/opencs/model/tools/mergestages.hpp +++ b/apps/opencs/model/tools/mergestages.hpp @@ -115,6 +115,37 @@ namespace CSMTools virtual void perform (int stage, CSMDoc::Messages& messages); ///< Messages resulting from this stage will be appended to \a messages. }; + + class ListLandTexturesMergeStage : public CSMDoc::Stage + { + MergeState& mState; + + public: + + ListLandTexturesMergeStage (MergeState& state); + + virtual int setup(); + ///< \return number of steps + + virtual void perform (int stage, CSMDoc::Messages& messages); + ///< Messages resulting from this stage will be appended to \a messages. + }; + + class MergeLandTexturesStage : public CSMDoc::Stage + { + MergeState& mState; + std::map, int>::iterator mNext; + + public: + + MergeLandTexturesStage (MergeState& state); + + virtual int setup(); + ///< \return number of steps + + virtual void perform (int stage, CSMDoc::Messages& messages); + ///< Messages resulting from this stage will be appended to \a messages. + }; } #endif diff --git a/apps/opencs/model/tools/mergestate.hpp b/apps/opencs/model/tools/mergestate.hpp index 077edc9d9..29e1bbda7 100644 --- a/apps/opencs/model/tools/mergestate.hpp +++ b/apps/opencs/model/tools/mergestate.hpp @@ -1,6 +1,8 @@ #ifndef CSM_TOOLS_MERGESTATE_H #define CSM_TOOLS_MERGESTATE_H +#include + #include #include @@ -13,7 +15,7 @@ namespace CSMTools std::auto_ptr mTarget; CSMDoc::Document& mSource; bool mCompleted; - std::map, int> mTextureIndices; // (texture, content file) -> new texture + std::map, int> mTextureIndices; // (texture, content file) -> new texture MergeState (CSMDoc::Document& source) : mSource (source), mCompleted (false) {} }; diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index d8999d950..c12827b53 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -778,6 +778,11 @@ const CSMWorld::IdCollection& CSMWorld::Data::getLandText return mLandTextures; } +CSMWorld::IdCollection& CSMWorld::Data::getLandTextures() +{ + return mLandTextures; +} + const CSMWorld::IdCollection& CSMWorld::Data::getSoundGens() const { return mSoundGens; diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 5706b005b..9a41ead42 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -234,6 +234,8 @@ namespace CSMWorld const IdCollection& getLandTextures() const; + IdCollection& getLandTextures(); + const IdCollection& getSoundGens() const; IdCollection& getSoundGens(); From 8aaba0af6fac116f09092bbc1f88241988b7706e Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 30 Aug 2015 17:38:21 +0200 Subject: [PATCH 2120/3725] Fix journal page navigation bug introduced by 7dd09dd637c317d3d94 (Fixes #2899) --- apps/openmw/mwgui/journalwindow.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index 8238f6585..b6f72a04c 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -356,6 +356,8 @@ namespace setVisible (OptionsOverlay, false); setVisible (OptionsBTN, true); setVisible (JournalBTN, true); + + mOptionsMode = false; } void notifyTopicSelected (const std::string& topic, int id) @@ -383,6 +385,8 @@ namespace setVisible (OptionsOverlay, false); setVisible (OptionsBTN, true); setVisible (JournalBTN, true); + + mOptionsMode = false; } void notifyOptions(MyGUI::Widget* _sender) From cda8a88f0d9a9fb5f12e3a39f683b2a874e4e9e2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 30 Aug 2015 20:00:37 +0200 Subject: [PATCH 2121/3725] Use DEEP_COPY_PRIMITIVES to work around problem in osg::Geometry copy constructor (Bug #2754) --- components/sceneutil/clone.cpp | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/components/sceneutil/clone.cpp b/components/sceneutil/clone.cpp index 36c5c02a1..74eae0b6b 100644 --- a/components/sceneutil/clone.cpp +++ b/components/sceneutil/clone.cpp @@ -52,6 +52,32 @@ namespace SceneUtil { osg::CopyOp copyop = *this; copyop.setCopyFlags(copyop.getCopyFlags()|osg::CopyOp::DEEP_COPY_ARRAYS); + + /* + + Deep copy of primitives required to work around the following (bad?) code in osg::Geometry copy constructor: + + if ((copyop.getCopyFlags() & osg::CopyOp::DEEP_COPY_ARRAYS)) + { + if (_useVertexBufferObjects) + { + // copying of arrays doesn't set up buffer objects so we'll need to force + // Geometry to assign these, we'll do this by switching off VBO's then renabling them. + setUseVertexBufferObjects(false); + setUseVertexBufferObjects(true); + } + } + + In case of DEEP_COPY_PRIMITIVES=Off, DEEP_COPY_ARRAYS=On, the above code makes a modification to the original const Geometry& we copied from, + causing problems if we relied on the original Geometry to remain static such as when it was added to an osgUtil::IncrementalCompileOperation. + + TODO: report/fix in upstream OSG + + */ + + copyop.setCopyFlags(copyop.getCopyFlags()|osg::CopyOp::DEEP_COPY_PRIMITIVES); + + osg::Drawable* cloned = osg::clone(drawable, copyop); if (cloned->getUpdateCallback()) cloned->setUpdateCallback(osg::clone(cloned->getUpdateCallback(), *this)); From e9acd135a6a405f88f2f3ab896cdac7eade31f04 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 30 Aug 2015 20:43:39 +0200 Subject: [PATCH 2122/3725] Update todo comment --- components/sceneutil/clone.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/sceneutil/clone.cpp b/components/sceneutil/clone.cpp index 74eae0b6b..e4b4f63bb 100644 --- a/components/sceneutil/clone.cpp +++ b/components/sceneutil/clone.cpp @@ -71,7 +71,7 @@ namespace SceneUtil In case of DEEP_COPY_PRIMITIVES=Off, DEEP_COPY_ARRAYS=On, the above code makes a modification to the original const Geometry& we copied from, causing problems if we relied on the original Geometry to remain static such as when it was added to an osgUtil::IncrementalCompileOperation. - TODO: report/fix in upstream OSG + Possible fix submitted to osg-submissions ( http://forum.openscenegraph.org/viewtopic.php?t=15217 ). */ From b0641934d4a34b4e462932aa715cc0ca9d854cae Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 31 Aug 2015 11:06:32 +0200 Subject: [PATCH 2123/3725] added copy constructor and assignment operator for Land record struct --- components/esm/loadland.cpp | 27 +++++++++++++++++++++++++++ components/esm/loadland.hpp | 8 ++++++-- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/components/esm/loadland.cpp b/components/esm/loadland.cpp index b0897ec67..baeca34de 100644 --- a/components/esm/loadland.cpp +++ b/components/esm/loadland.cpp @@ -1,5 +1,7 @@ #include "loadland.hpp" +#include + #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" @@ -215,4 +217,29 @@ bool Land::isDataLoaded(int flags) const return (mDataLoaded & flags) == (flags & mDataTypes); } + Land::Land (const Land& land) + : mFlags (land.mFlags), mX (land.mX), mY (land.mY), mPlugin (land.mPlugin), + mEsm (land.mEsm), mContext (land.mContext), mDataTypes (land.mDataTypes), + mDataLoaded (land.mDataLoaded), + mLandData (land.mLandData ? new LandData (*land.mLandData) : 0) + {} + + Land& Land::operator= (Land land) + { + swap (land); + return *this; + } + + void Land::swap (Land& land) + { + std::swap (mFlags, land.mFlags); + std::swap (mX, land.mX); + std::swap (mY, land.mY); + std::swap (mPlugin, land.mPlugin); + std::swap (mEsm, land.mEsm); + std::swap (mContext, land.mContext); + std::swap (mDataTypes, land.mDataTypes); + std::swap (mDataLoaded, land.mDataLoaded); + std::swap (mLandData, land.mLandData); + } } diff --git a/components/esm/loadland.hpp b/components/esm/loadland.hpp index 61ce4855e..e010b170c 100644 --- a/components/esm/loadland.hpp +++ b/components/esm/loadland.hpp @@ -116,9 +116,13 @@ struct Land /// @note We only check data types that *can* be loaded (present in mDataTypes) bool isDataLoaded(int flags) const; + Land (const Land& land); + + Land& operator= (Land land); + + void swap (Land& land); + private: - Land(const Land& land); - Land& operator=(const Land& land); /// Loads data and marks it as loaded /// \return true if data is actually loaded from file, false otherwise From 69045d7ec9d293f2bb5626b2ac4a8517a0cf67e4 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 31 Aug 2015 11:10:58 +0200 Subject: [PATCH 2124/3725] additional safety check for land texture listing merge stage --- apps/opencs/model/tools/mergestages.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/tools/mergestages.cpp b/apps/opencs/model/tools/mergestages.cpp index f34ba8eb4..a4072e4bc 100644 --- a/apps/opencs/model/tools/mergestages.cpp +++ b/apps/opencs/model/tools/mergestages.cpp @@ -130,7 +130,7 @@ void CSMTools::ListLandTexturesMergeStage::perform (int stage, CSMDoc::Messages& land.loadData (ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML | ESM::Land::DATA_VCLR | ESM::Land::DATA_VTEX | ESM::Land::DATA_WNAM); - if (land.mLandData) + if (land.mLandData && land.mDataLoaded & ESM::Land::DATA_VTEX) { // list texture indices std::pair key; From febf611c827a257a4d4000b601f9ef413f2f8012 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 31 Aug 2015 14:17:11 +0200 Subject: [PATCH 2125/3725] made return type of ESMTerrain::Storage::getLand const --- apps/opencs/view/render/terrainstorage.cpp | 2 +- apps/opencs/view/render/terrainstorage.hpp | 2 +- apps/openmw/mwrender/terrainstorage.cpp | 2 +- apps/openmw/mwrender/terrainstorage.hpp | 2 +- components/esmterrain/storage.cpp | 10 +++++----- components/esmterrain/storage.hpp | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/apps/opencs/view/render/terrainstorage.cpp b/apps/opencs/view/render/terrainstorage.cpp index fe302cef1..a60678f88 100644 --- a/apps/opencs/view/render/terrainstorage.cpp +++ b/apps/opencs/view/render/terrainstorage.cpp @@ -9,7 +9,7 @@ namespace CSVRender { } - ESM::Land* TerrainStorage::getLand(int cellX, int cellY) + const ESM::Land* TerrainStorage::getLand(int cellX, int cellY) { std::ostringstream stream; stream << "#" << cellX << " " << cellY; diff --git a/apps/opencs/view/render/terrainstorage.hpp b/apps/opencs/view/render/terrainstorage.hpp index 97782ad17..16b0f3ec7 100644 --- a/apps/opencs/view/render/terrainstorage.hpp +++ b/apps/opencs/view/render/terrainstorage.hpp @@ -18,7 +18,7 @@ namespace CSVRender private: const CSMWorld::Data& mData; - virtual ESM::Land* getLand (int cellX, int cellY); + virtual const ESM::Land* getLand (int cellX, int cellY); virtual const ESM::LandTexture* getLandTexture(int index, short plugin); virtual void getBounds(float& minX, float& maxX, float& minY, float& maxY); diff --git a/apps/openmw/mwrender/terrainstorage.cpp b/apps/openmw/mwrender/terrainstorage.cpp index 269e7f99f..f9a9083f0 100644 --- a/apps/openmw/mwrender/terrainstorage.cpp +++ b/apps/openmw/mwrender/terrainstorage.cpp @@ -51,7 +51,7 @@ namespace MWRender maxY += 1; } - ESM::Land* TerrainStorage::getLand(int cellX, int cellY) + const ESM::Land* TerrainStorage::getLand(int cellX, int cellY) { const MWWorld::ESMStore &esmStore = MWBase::Environment::get().getWorld()->getStore(); diff --git a/apps/openmw/mwrender/terrainstorage.hpp b/apps/openmw/mwrender/terrainstorage.hpp index 93531a552..a12ffd540 100644 --- a/apps/openmw/mwrender/terrainstorage.hpp +++ b/apps/openmw/mwrender/terrainstorage.hpp @@ -10,7 +10,7 @@ namespace MWRender class TerrainStorage : public ESMTerrain::Storage { private: - virtual ESM::Land* getLand (int cellX, int cellY); + virtual const ESM::Land* getLand (int cellX, int cellY); virtual const ESM::LandTexture* getLandTexture(int index, short plugin); public: diff --git a/components/esmterrain/storage.cpp b/components/esmterrain/storage.cpp index 10b75bb74..5bc56a430 100644 --- a/components/esmterrain/storage.cpp +++ b/components/esmterrain/storage.cpp @@ -74,7 +74,7 @@ namespace ESMTerrain --cellX; row += ESM::Land::LAND_SIZE-1; } - ESM::Land* land = getLand(cellX, cellY); + const ESM::Land* land = getLand(cellX, cellY); if (land && land->mDataTypes&ESM::Land::DATA_VNML) { normal.x() = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3]; @@ -109,7 +109,7 @@ namespace ESMTerrain ++cellX; row = 0; } - ESM::Land* land = getLand(cellX, cellY); + const ESM::Land* land = getLand(cellX, cellY); if (land && land->mDataTypes&ESM::Land::DATA_VCLR) { color.r() = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3] / 255.f; @@ -158,7 +158,7 @@ namespace ESMTerrain float vertX_ = 0; // of current cell corner for (int cellX = startX; cellX < startX + std::ceil(size); ++cellX) { - ESM::Land* land = getLand(cellX, cellY); + const ESM::Land* land = getLand(cellX, cellY); if (land && !(land->mDataTypes&ESM::Land::DATA_VHGT)) land = NULL; @@ -262,7 +262,7 @@ namespace ESMTerrain assert(xmDataTypes&ESM::Land::DATA_VTEX)) { int tex = land->mLandData->mTextures[y * ESM::Land::LAND_TEXTURE_SIZE + x]; @@ -368,7 +368,7 @@ namespace ESMTerrain int cellX = static_cast(std::floor(worldPos.x() / 8192.f)); int cellY = static_cast(std::floor(worldPos.y() / 8192.f)); - ESM::Land* land = getLand(cellX, cellY); + const ESM::Land* land = getLand(cellX, cellY); if (!land || !(land->mDataTypes&ESM::Land::DATA_VHGT)) return -2048; diff --git a/components/esmterrain/storage.hpp b/components/esmterrain/storage.hpp index 8f4a3aa92..debbc59b9 100644 --- a/components/esmterrain/storage.hpp +++ b/components/esmterrain/storage.hpp @@ -21,7 +21,7 @@ namespace ESMTerrain private: // Not implemented in this class, because we need different Store implementations for game and editor - virtual ESM::Land* getLand (int cellX, int cellY) = 0; + virtual const ESM::Land* getLand (int cellX, int cellY) = 0; virtual const ESM::LandTexture* getLandTexture(int index, short plugin) = 0; public: From b3fdf92d2b1b37a8c118ee5bdc1a2f6d6437a667 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 31 Aug 2015 16:08:19 +0200 Subject: [PATCH 2126/3725] more const-ness fixes --- apps/openmw/mwphysics/physicssystem.cpp | 4 ++-- apps/openmw/mwphysics/physicssystem.hpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 2cb261851..23b3f051c 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -460,7 +460,7 @@ namespace MWPhysics class HeightField { public: - HeightField(float* heights, int x, int y, float triSize, float sqrtVerts) + HeightField(const float* heights, int x, int y, float triSize, float sqrtVerts) { // find the minimum and maximum heights (needed for bullet) float minh = heights[0]; @@ -927,7 +927,7 @@ namespace MWPhysics return MovementSolver::traceDown(ptr, found->second, mCollisionWorld, maxHeight); } - void PhysicsSystem::addHeightField (float* heights, int x, int y, float triSize, float sqrtVerts) + void PhysicsSystem::addHeightField (const float* heights, int x, int y, float triSize, float sqrtVerts) { HeightField *heightfield = new HeightField(heights, x, y, triSize, sqrtVerts); mHeightFields[std::make_pair(x,y)] = heightfield; diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index c3b22c385..ee9378ea4 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -71,7 +71,7 @@ namespace MWPhysics void updatePosition (const MWWorld::Ptr& ptr); - void addHeightField (float* heights, int x, int y, float triSize, float sqrtVerts); + void addHeightField (const float* heights, int x, int y, float triSize, float sqrtVerts); void removeHeightField (int x, int y); From 69b9eadb52cf24398d64b6399341d9e6b5d40bdf Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 31 Aug 2015 16:13:26 +0200 Subject: [PATCH 2127/3725] refactored loading of land data --- apps/esmtool/record.cpp | 16 ++--- apps/opencs/model/doc/savingstages.cpp | 5 +- apps/opencs/model/tools/mergestages.cpp | 4 +- apps/openmw/mwrender/globalmap.cpp | 8 ++- apps/openmw/mwworld/scene.cpp | 6 +- components/esm/loadland.cpp | 22 ++++-- components/esm/loadland.hpp | 23 ++++-- components/esmterrain/storage.cpp | 93 ++++++++++++++----------- components/esmterrain/storage.hpp | 7 +- 9 files changed, 109 insertions(+), 75 deletions(-) diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index 2ee6c54bb..76c14e728 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -841,19 +841,13 @@ void Record::print() std::cout << " Flags: " << landFlags(mData.mFlags) << std::endl; std::cout << " DataTypes: " << mData.mDataTypes << std::endl; - // Seems like this should done with reference counting in the - // loader to me. But I'm not really knowledgable about this - // record type yet. --Cory - bool wasLoaded = (mData.mDataLoaded != 0); - if (mData.mDataTypes) mData.loadData(mData.mDataTypes); - if (mData.mDataLoaded) - { - std::cout << " Height Offset: " << mData.mLandData->mHeightOffset << std::endl; + if (const ESM::Land::LandData *data = mData.getLandData (mData.mDataTypes)) + { + std::cout << " Height Offset: " << data->mHeightOffset << std::endl; // Lots of missing members. - std::cout << " Unknown1: " << mData.mLandData->mUnk1 << std::endl; - std::cout << " Unknown2: " << mData.mLandData->mUnk2 << std::endl; + std::cout << " Unknown1: " << data->mUnk1 << std::endl; + std::cout << " Unknown2: " << data->mUnk2 << std::endl; } - if (!wasLoaded) mData.unloadData(); } template<> diff --git a/apps/opencs/model/doc/savingstages.cpp b/apps/opencs/model/doc/savingstages.cpp index f78c57ecd..a21a28c99 100644 --- a/apps/opencs/model/doc/savingstages.cpp +++ b/apps/opencs/model/doc/savingstages.cpp @@ -421,8 +421,9 @@ void CSMDoc::WriteLandCollectionStage::perform (int stage, Messages& messages) mState.getWriter().startRecord (record.mLand->sRecordId); record.mLand->save (mState.getWriter()); - if(record.mLand->mLandData) - record.mLand->mLandData->save (mState.getWriter()); + + if (const ESM::Land::LandData *data = record.mLand->getLandData (record.mLand->mDataTypes)) + data->save (mState.getWriter()); mState.getWriter().endRecord (record.mLand->sRecordId); } diff --git a/apps/opencs/model/tools/mergestages.cpp b/apps/opencs/model/tools/mergestages.cpp index a4072e4bc..5bf0241ac 100644 --- a/apps/opencs/model/tools/mergestages.cpp +++ b/apps/opencs/model/tools/mergestages.cpp @@ -130,7 +130,7 @@ void CSMTools::ListLandTexturesMergeStage::perform (int stage, CSMDoc::Messages& land.loadData (ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML | ESM::Land::DATA_VCLR | ESM::Land::DATA_VTEX | ESM::Land::DATA_WNAM); - if (land.mLandData && land.mDataLoaded & ESM::Land::DATA_VTEX) + if (const ESM::Land::LandData *data = land.getLandData (ESM::Land::DATA_VTEX)) { // list texture indices std::pair key; @@ -138,7 +138,7 @@ void CSMTools::ListLandTexturesMergeStage::perform (int stage, CSMDoc::Messages& for (int i=0; imTextures[i]; + key.first = data->mTextures[i]; mState.mTextureIndices[key] = -1; } diff --git a/apps/openmw/mwrender/globalmap.cpp b/apps/openmw/mwrender/globalmap.cpp index 890c8444a..97a27ebbc 100644 --- a/apps/openmw/mwrender/globalmap.cpp +++ b/apps/openmw/mwrender/globalmap.cpp @@ -156,6 +156,9 @@ namespace MWRender land->loadData(mask); } + const ESM::Land::LandData *landData = + land ? land->getLandData (ESM::Land::DATA_WNAM) : 0; + for (int cellY=0; cellY(float(cellX)/float(mCellSize) * 9); int vertexY = static_cast(float(cellY) / float(mCellSize) * 9); - int texelX = (x-mMinX) * mCellSize + cellX; int texelY = (mHeight-1) - ((y-mMinY) * mCellSize + cellY); unsigned char r,g,b; float y = 0; - if (land && land->mDataTypes & ESM::Land::DATA_WNAM) - y = (land->mLandData->mWnam[vertexY * 9 + vertexX] << 4) / 2048.f; + if (landData) + y = (landData->mWnam[vertexY * 9 + vertexX] << 4) / 2048.f; else y = (SCHAR_MIN << 4) / 2048.f; if (y < 0) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 48e346c14..459b3b6ca 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -250,9 +250,9 @@ namespace MWWorld // Actually only VHGT is needed here, but we'll need the rest for rendering anyway. // Load everything now to reduce IO overhead. const int flags = ESM::Land::DATA_VCLR|ESM::Land::DATA_VHGT|ESM::Land::DATA_VNML|ESM::Land::DATA_VTEX; - if (!land->isDataLoaded(flags)) - land->loadData(flags); - mPhysics->addHeightField (land->mLandData->mHeights, cell->getCell()->getGridX(), cell->getCell()->getGridY(), + + const ESM::Land::LandData *data = land->getLandData (flags); + mPhysics->addHeightField (data->mHeights, cell->getCell()->getGridX(), cell->getCell()->getGridY(), worldsize / (verts-1), verts); } } diff --git a/components/esm/loadland.cpp b/components/esm/loadland.cpp index baeca34de..770830fdd 100644 --- a/components/esm/loadland.cpp +++ b/components/esm/loadland.cpp @@ -10,7 +10,7 @@ namespace ESM { unsigned int Land::sRecordId = REC_LAND; -void Land::LandData::save(ESMWriter &esm) +void Land::LandData::save(ESMWriter &esm) const { if (mDataTypes & Land::DATA_VNML) { esm.writeHNT("VNML", mNormals, sizeof(mNormals)); @@ -55,7 +55,7 @@ void Land::LandData::save(ESMWriter &esm) } } -void Land::LandData::transposeTextureData(uint16_t *in, uint16_t *out) +void Land::LandData::transposeTextureData(const uint16_t *in, uint16_t *out) { int readPos = 0; //bit ugly, but it works for ( int y1 = 0; y1 < 4; y1++ ) @@ -139,7 +139,7 @@ void Land::save(ESMWriter &esm) const esm.writeHNT("DATA", mFlags); } -void Land::loadData(int flags) +void Land::loadData(int flags) const { // Try to load only available data flags = flags & mDataTypes; @@ -201,7 +201,7 @@ void Land::unloadData() } } -bool Land::condLoad(int flags, int dataFlag, void *ptr, unsigned int size) +bool Land::condLoad(int flags, int dataFlag, void *ptr, unsigned int size) const { if ((mDataLoaded & dataFlag) == 0 && (flags & dataFlag) != 0) { mEsm->getHExact(ptr, size); @@ -242,4 +242,18 @@ bool Land::isDataLoaded(int flags) const std::swap (mDataLoaded, land.mDataLoaded); std::swap (mLandData, land.mLandData); } + + const Land::LandData *Land::getLandData (int flags) const + { + if (!(flags & mDataTypes)) + return 0; + + loadData (flags); + return mLandData; + } + + const Land::LandData *Land::getLandData() const + { + return mLandData; + } } diff --git a/components/esm/loadland.hpp b/components/esm/loadland.hpp index e010b170c..64d131ecb 100644 --- a/components/esm/loadland.hpp +++ b/components/esm/loadland.hpp @@ -35,7 +35,6 @@ struct Land ESM_Context mContext; int mDataTypes; - int mDataLoaded; enum { @@ -91,12 +90,10 @@ struct Land short mUnk1; uint8_t mUnk2; - void save(ESMWriter &esm); - static void transposeTextureData(uint16_t *in, uint16_t *out); + void save(ESMWriter &esm) const; + static void transposeTextureData(const uint16_t *in, uint16_t *out); }; - LandData *mLandData; - void load(ESMReader &esm); void save(ESMWriter &esm) const; @@ -105,7 +102,7 @@ struct Land /** * Actually loads data */ - void loadData(int flags); + void loadData(int flags) const; /** * Frees memory allocated for land data @@ -122,12 +119,24 @@ struct Land void swap (Land& land); + /// Return land data with at least the data types specified in \a flags loaded (if they + /// are available). Will return a 0-pointer if there is no data for any of the + /// specified types. + const LandData *getLandData (int flags) const; + + /// Return land data without loading first anything. Can return a 0-pointer. + const LandData *getLandData() const; + private: /// Loads data and marks it as loaded /// \return true if data is actually loaded from file, false otherwise /// including the case when data is already loaded - bool condLoad(int flags, int dataFlag, void *ptr, unsigned int size); + bool condLoad(int flags, int dataFlag, void *ptr, unsigned int size) const; + + mutable int mDataLoaded; + + mutable LandData *mLandData; }; } diff --git a/components/esmterrain/storage.cpp b/components/esmterrain/storage.cpp index 5bc56a430..ccfe6d9ee 100644 --- a/components/esmterrain/storage.cpp +++ b/components/esmterrain/storage.cpp @@ -18,6 +18,14 @@ namespace ESMTerrain { } + const ESM::Land::LandData *Storage::getLandData (int cellX, int cellY, int flags) + { + if (const ESM::Land *land = getLand (cellX, cellY)) + return land->getLandData (flags); + + return 0; + } + bool Storage::getMinMaxHeights(float size, const osg::Vec2f ¢er, float &min, float &max) { assert (size <= 1 && "Storage::getMinMaxHeights, chunk size should be <= 1 cell"); @@ -32,24 +40,25 @@ namespace ESMTerrain int cellX = static_cast(origin.x()); int cellY = static_cast(origin.y()); - const ESM::Land* land = getLand(cellX, cellY); - if (!land || !(land->mDataTypes&ESM::Land::DATA_VHGT)) - return false; - - min = std::numeric_limits::max(); - max = -std::numeric_limits::max(); - for (int row=0; row::max(); + max = -std::numeric_limits::max(); + for (int row=0; rowmLandData->mHeights[col*ESM::Land::LAND_SIZE+row]; - if (h > max) - max = h; - if (h < min) - min = h; + for (int col=0; colmHeights[col*ESM::Land::LAND_SIZE+row]; + if (h > max) + max = h; + if (h < min) + min = h; + } } + return true; } - return true; + + return false; } void Storage::fixNormal (osg::Vec3f& normal, int cellX, int cellY, int col, int row) @@ -74,12 +83,12 @@ namespace ESMTerrain --cellX; row += ESM::Land::LAND_SIZE-1; } - const ESM::Land* land = getLand(cellX, cellY); - if (land && land->mDataTypes&ESM::Land::DATA_VNML) + + if (const ESM::Land::LandData *data = getLandData (cellX, cellY, ESM::Land::DATA_VNML)) { - normal.x() = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3]; - normal.y() = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3+1]; - normal.z() = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3+2]; + normal.x() = data->mNormals[col*ESM::Land::LAND_SIZE*3+row*3]; + normal.y() = data->mNormals[col*ESM::Land::LAND_SIZE*3+row*3+1]; + normal.z() = data->mNormals[col*ESM::Land::LAND_SIZE*3+row*3+2]; normal.normalize(); } else @@ -109,12 +118,12 @@ namespace ESMTerrain ++cellX; row = 0; } - const ESM::Land* land = getLand(cellX, cellY); - if (land && land->mDataTypes&ESM::Land::DATA_VCLR) + + if (const ESM::Land::LandData *data = getLandData (cellX, cellY, ESM::Land::DATA_VCLR)) { - color.r() = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3] / 255.f; - color.g() = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3+1] / 255.f; - color.b() = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3+2] / 255.f; + color.r() = data->mColours[col*ESM::Land::LAND_SIZE*3+row*3] / 255.f; + color.g() = data->mColours[col*ESM::Land::LAND_SIZE*3+row*3+1] / 255.f; + color.b() = data->mColours[col*ESM::Land::LAND_SIZE*3+row*3+2] / 255.f; } else { @@ -158,9 +167,9 @@ namespace ESMTerrain float vertX_ = 0; // of current cell corner for (int cellX = startX; cellX < startX + std::ceil(size); ++cellX) { - const ESM::Land* land = getLand(cellX, cellY); - if (land && !(land->mDataTypes&ESM::Land::DATA_VHGT)) - land = NULL; + const ESM::Land::LandData *heightData = getLandData (cellX, cellY, ESM::Land::DATA_VHGT); + const ESM::Land::LandData *normalData = getLandData (cellX, cellY, ESM::Land::DATA_VNML); + const ESM::Land::LandData *colourData = getLandData (cellX, cellY, ESM::Land::DATA_VCLR); int rowStart = 0; int colStart = 0; @@ -177,20 +186,22 @@ namespace ESMTerrain vertX = vertX_; for (int row=rowStart; rowmLandData->mHeights[col*ESM::Land::LAND_SIZE + row]; + if (heightData) + height = heightData->mHeights[col*ESM::Land::LAND_SIZE + row]; (*positions)[static_cast(vertX*numVerts + vertY)] = osg::Vec3f((vertX / float(numVerts - 1) - 0.5f) * size * 8192, (vertY / float(numVerts - 1) - 0.5f) * size * 8192, height); - if (land && land->mDataTypes&ESM::Land::DATA_VNML) + if (normalData) { - normal.x() = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3]; - normal.y() = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3+1]; - normal.z() = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3+2]; + for (int i=0; i<3; ++i) + normal[i] = normalData->mNormals[arrayIndex+i]; + normal.normalize(); } else @@ -208,11 +219,10 @@ namespace ESMTerrain (*normals)[static_cast(vertX*numVerts + vertY)] = normal; - if (land && land->mDataTypes&ESM::Land::DATA_VCLR) + if (colourData) { - color.r() = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3] / 255.f; - color.g() = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3+1] / 255.f; - color.b() = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3+2] / 255.f; + for (int i=0; i<3; ++i) + color[i] = colourData->mColours[arrayIndex+i] / 255.f; } else { @@ -262,13 +272,12 @@ namespace ESMTerrain assert(xmDataTypes&ESM::Land::DATA_VTEX)) + if (const ESM::Land::LandData *data = getLandData (cellX, cellY, ESM::Land::DATA_VTEX)) { - int tex = land->mLandData->mTextures[y * ESM::Land::LAND_TEXTURE_SIZE + x]; + int tex = data->mTextures[y * ESM::Land::LAND_TEXTURE_SIZE + x]; if (tex == 0) return std::make_pair(0,0); // vtex 0 is always the base texture, regardless of plugin - return std::make_pair(tex, land->mPlugin); + return std::make_pair(tex, getLand (cellX, cellY)->mPlugin); } else return std::make_pair(0,0); @@ -447,7 +456,7 @@ namespace ESMTerrain { assert(x < ESM::Land::LAND_SIZE); assert(y < ESM::Land::LAND_SIZE); - return land->mLandData->mHeights[y * ESM::Land::LAND_SIZE + x]; + return land->getLandData()->mHeights[y * ESM::Land::LAND_SIZE + x]; } Terrain::LayerInfo Storage::getLayerInfo(const std::string& texture) diff --git a/components/esmterrain/storage.hpp b/components/esmterrain/storage.hpp index debbc59b9..5b8ca953d 100644 --- a/components/esmterrain/storage.hpp +++ b/components/esmterrain/storage.hpp @@ -21,12 +21,17 @@ namespace ESMTerrain private: // Not implemented in this class, because we need different Store implementations for game and editor - virtual const ESM::Land* getLand (int cellX, int cellY) = 0; + virtual const ESM::Land* getLand (int cellX, int cellY)= 0; virtual const ESM::LandTexture* getLandTexture(int index, short plugin) = 0; public: Storage(const VFS::Manager* vfs); + /// Data is loaded first, if necessary. Will return a 0-pointer if there is no data for + /// any of the data types specified via \a flags. Will also return a 0-pointer if there + /// is no land record for the coordinates \a cellX / \a cellY. + const ESM::Land::LandData *getLandData (int cellX, int cellY, int flags); + // Not implemented in this class, because we need different Store implementations for game and editor /// Get bounds of the whole terrain in cell units virtual void getBounds(float& minX, float& maxX, float& minY, float& maxY) = 0; From 85f6bb892b7f61b95d297efcf67cfccaee134e54 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 31 Aug 2015 18:13:27 +0200 Subject: [PATCH 2128/3725] removed indirection in OpenMW-CS land record --- apps/opencs/model/doc/savingstages.cpp | 10 +++++----- apps/opencs/model/tools/mergestages.cpp | 2 +- apps/opencs/model/world/data.cpp | 7 ++++++- apps/opencs/model/world/data.hpp | 2 ++ apps/opencs/model/world/land.cpp | 16 ++-------------- apps/opencs/model/world/land.hpp | 10 ++-------- apps/opencs/view/render/cell.cpp | 15 ++++++++------- apps/opencs/view/render/terrainstorage.cpp | 7 +++---- 8 files changed, 29 insertions(+), 40 deletions(-) diff --git a/apps/opencs/model/doc/savingstages.cpp b/apps/opencs/model/doc/savingstages.cpp index a21a28c99..894c479a4 100644 --- a/apps/opencs/model/doc/savingstages.cpp +++ b/apps/opencs/model/doc/savingstages.cpp @@ -416,16 +416,16 @@ void CSMDoc::WriteLandCollectionStage::perform (int stage, Messages& messages) if (land.mState==CSMWorld::RecordBase::State_Modified || land.mState==CSMWorld::RecordBase::State_ModifiedOnly) { - CSMWorld::Land record = land.get(); + const CSMWorld::Land& record = land.get(); - mState.getWriter().startRecord (record.mLand->sRecordId); + mState.getWriter().startRecord (record.sRecordId); - record.mLand->save (mState.getWriter()); + record.save (mState.getWriter()); - if (const ESM::Land::LandData *data = record.mLand->getLandData (record.mLand->mDataTypes)) + if (const ESM::Land::LandData *data = record.getLandData (record.mDataTypes)) data->save (mState.getWriter()); - mState.getWriter().endRecord (record.mLand->sRecordId); + mState.getWriter().endRecord (record.sRecordId); } else if (land.mState==CSMWorld::RecordBase::State_Deleted) { diff --git a/apps/opencs/model/tools/mergestages.cpp b/apps/opencs/model/tools/mergestages.cpp index 5bf0241ac..c624ff548 100644 --- a/apps/opencs/model/tools/mergestages.cpp +++ b/apps/opencs/model/tools/mergestages.cpp @@ -124,7 +124,7 @@ void CSMTools::ListLandTexturesMergeStage::perform (int stage, CSMDoc::Messages& if (!record.isDeleted()) { - ESM::Land& land = *record.get().mLand; + const ESM::Land& land = record.get(); // make sure record is loaded land.loadData (ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML | diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index c12827b53..fe6d6ccbb 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -773,6 +773,11 @@ const CSMWorld::IdCollection& CSMWorld::Data::getLand() const return mLand; } +CSMWorld::IdCollection& CSMWorld::Data::getLand() +{ + return mLand; +} + const CSMWorld::IdCollection& CSMWorld::Data::getLandTextures() const { return mLandTextures; @@ -951,7 +956,7 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Messages& messages) int index = mLand.load(*mReader, mBase); if (index!=-1 && !mBase) - mLand.getRecord (index).mModified.mLand->loadData ( + mLand.getRecord (index).mModified.loadData ( ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML | ESM::Land::DATA_VCLR | ESM::Land::DATA_VTEX | ESM::Land::DATA_WNAM); diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 9a41ead42..c6623279a 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -232,6 +232,8 @@ namespace CSMWorld const IdCollection& getLand() const; + IdCollection& getLand(); + const IdCollection& getLandTextures() const; IdCollection& getLandTextures(); diff --git a/apps/opencs/model/world/land.cpp b/apps/opencs/model/world/land.cpp index 119e18761..222f9bc02 100644 --- a/apps/opencs/model/world/land.cpp +++ b/apps/opencs/model/world/land.cpp @@ -4,25 +4,13 @@ namespace CSMWorld { - - Land::Land() - { - mLand.reset(new ESM::Land()); - } - void Land::load(ESM::ESMReader &esm) { - mLand->load(esm); + ESM::Land::load(esm); std::ostringstream stream; - stream << "#" << mLand->mX << " " << mLand->mY; + stream << "#" << mX << " " << mY; mId = stream.str(); } - - void Land::blank() - { - /// \todo - } - } diff --git a/apps/opencs/model/world/land.hpp b/apps/opencs/model/world/land.hpp index e97a2d7dd..22cedb56d 100644 --- a/apps/opencs/model/world/land.hpp +++ b/apps/opencs/model/world/land.hpp @@ -2,7 +2,7 @@ #define CSM_WORLD_LAND_H #include -#include + #include namespace CSMWorld @@ -11,18 +11,12 @@ namespace CSMWorld /// /// \todo Add worldspace support to the Land record. /// \todo Add a proper copy constructor (currently worked around using shared_ptr) - struct Land + struct Land : public ESM::Land { - Land(); - - boost::shared_ptr mLand; - std::string mId; /// Loads the metadata and ID void load (ESM::ESMReader &esm); - - void blank(); }; } diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index fe2eab066..4425c193f 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -32,7 +32,7 @@ bool CSVRender::Cell::addObjects (int start, int end) bool modified = false; const CSMWorld::RefCollection& collection = mData.getReferences(); - + for (int i=start; i<=end; ++i) { std::string cell = Misc::StringUtils::lowerCase (collection.getRecord (i).get().mCell); @@ -68,15 +68,16 @@ CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::st int landIndex = land.searchId(mId); if (landIndex != -1) { - const ESM::Land* esmLand = land.getRecord(mId).get().mLand.get(); - if(esmLand && esmLand->mDataTypes&ESM::Land::DATA_VHGT) + const ESM::Land& esmLand = land.getRecord(mId).get(); + + if (esmLand.getLandData (ESM::Land::DATA_VHGT)) { mTerrain.reset(new Terrain::TerrainGrid(mCellNode, data.getResourceSystem().get(), NULL, new TerrainStorage(mData), Element_Terrain<<1)); - mTerrain->loadCell(esmLand->mX, - esmLand->mY); + mTerrain->loadCell(esmLand.mX, + esmLand.mY); - mX = esmLand->mX; - mY = esmLand->mY; + mX = esmLand.mX; + mY = esmLand.mY; } } } diff --git a/apps/opencs/view/render/terrainstorage.cpp b/apps/opencs/view/render/terrainstorage.cpp index a60678f88..b5b144fe4 100644 --- a/apps/opencs/view/render/terrainstorage.cpp +++ b/apps/opencs/view/render/terrainstorage.cpp @@ -20,11 +20,10 @@ namespace CSVRender if (index == -1) return NULL; - ESM::Land* land = mData.getLand().getRecord(index).get().mLand.get(); + const ESM::Land& land = mData.getLand().getRecord(index).get(); int mask = ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML | ESM::Land::DATA_VCLR | ESM::Land::DATA_VTEX; - if (!land->isDataLoaded(mask)) - land->loadData(mask); - return land; + land.loadData (mask); + return &land; } const ESM::LandTexture* TerrainStorage::getLandTexture(int index, short plugin) From a8dc1c119859abd0ad4cf16765abbf1f70fe6013 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 3 Sep 2015 16:15:00 +0200 Subject: [PATCH 2129/3725] merge land tables --- apps/opencs/model/tools/mergeoperation.cpp | 3 +- apps/opencs/model/tools/mergestages.cpp | 64 +++++++++++++++++++++- apps/opencs/model/tools/mergestages.hpp | 15 +++++ components/esm/loadland.cpp | 26 +++++++++ components/esm/loadland.hpp | 11 ++++ 5 files changed, 115 insertions(+), 4 deletions(-) diff --git a/apps/opencs/model/tools/mergeoperation.cpp b/apps/opencs/model/tools/mergeoperation.cpp index 9e791683c..907d742ed 100644 --- a/apps/opencs/model/tools/mergeoperation.cpp +++ b/apps/opencs/model/tools/mergeoperation.cpp @@ -40,10 +40,9 @@ CSMTools::MergeOperation::MergeOperation (CSMDoc::Document& document, ToUTF8::Fr appendStage (new MergeReferencesStage (mState)); appendStage (new ListLandTexturesMergeStage (mState)); appendStage (new MergeLandTexturesStage (mState)); + appendStage (new MergeLandStage (mState)); appendStage (new FinishMergedDocumentStage (mState, encoding)); - - /// \todo Land } void CSMTools::MergeOperation::setTarget (std::auto_ptr document) diff --git a/apps/opencs/model/tools/mergestages.cpp b/apps/opencs/model/tools/mergestages.cpp index c624ff548..f4cb42aa4 100644 --- a/apps/opencs/model/tools/mergestages.cpp +++ b/apps/opencs/model/tools/mergestages.cpp @@ -153,12 +153,20 @@ CSMTools::MergeLandTexturesStage::MergeLandTexturesStage (MergeState& state) int CSMTools::MergeLandTexturesStage::setup() { - mNext = mState.mTextureIndices.begin(); - return mState.mTextureIndices.size(); + // Should use the size of mState.mTextureIndices instead, but that is not available at this + // point. Unless there are any errors in the land and land texture records this will not + // make a difference. + return mState.mSource.getData().getLandTextures().getSize(); } void CSMTools::MergeLandTexturesStage::perform (int stage, CSMDoc::Messages& messages) { + if (stage==0) + mNext = mState.mTextureIndices.begin(); + + if (mNext==mState.mTextureIndices.end()) + return; + mNext->second = stage; std::ostringstream stream; @@ -183,3 +191,55 @@ void CSMTools::MergeLandTexturesStage::perform (int stage, CSMDoc::Messages& mes ++mNext; } + + +CSMTools::MergeLandStage::MergeLandStage (MergeState& state) : mState (state) {} + +int CSMTools::MergeLandStage::setup() +{ + return mState.mSource.getData().getLand().getSize(); +} + +void CSMTools::MergeLandStage::perform (int stage, CSMDoc::Messages& messages) +{ + const CSMWorld::Record& record = + mState.mSource.getData().getLand().getRecord (stage); + + if (!record.isDeleted()) + { + const CSMWorld::Land& land = record.get(); + + land.loadData (ESM::Land::DATA_VCLR | ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML | + ESM::Land::DATA_VTEX | ESM::Land::DATA_WNAM); + + CSMWorld::Land newLand (land); + + newLand.mEsm = 0; // avoid potential dangling pointer (ESMReader isn't needed anyway, + // because record is already fully loaded) + newLand.mPlugin = 0; + + // adjust land texture references + if (ESM::Land::LandData *data = newLand.getLandData()) + { + std::pair key; + key.second = land.mPlugin; + + for (int i=0; imTextures[i]; + std::map, int>::const_iterator iter = + mState.mTextureIndices.find (key); + + if (iter!=mState.mTextureIndices.end()) + data->mTextures[i] = iter->second; + else + data->mTextures[i] = 0; + } + } + + CSMWorld::Record newRecord ( + CSMWorld::RecordBase::State_ModifiedOnly, 0, &newLand); + + mState.mTarget->getData().getLand().appendRecord (newRecord); + } +} diff --git a/apps/opencs/model/tools/mergestages.hpp b/apps/opencs/model/tools/mergestages.hpp index f0ae99842..f88f5be9f 100644 --- a/apps/opencs/model/tools/mergestages.hpp +++ b/apps/opencs/model/tools/mergestages.hpp @@ -146,6 +146,21 @@ namespace CSMTools virtual void perform (int stage, CSMDoc::Messages& messages); ///< Messages resulting from this stage will be appended to \a messages. }; + + class MergeLandStage : public CSMDoc::Stage + { + MergeState& mState; + + public: + + MergeLandStage (MergeState& state); + + virtual int setup(); + ///< \return number of steps + + virtual void perform (int stage, CSMDoc::Messages& messages); + ///< Messages resulting from this stage will be appended to \a messages. + }; } #endif diff --git a/components/esm/loadland.cpp b/components/esm/loadland.cpp index 770830fdd..784cfd407 100644 --- a/components/esm/loadland.cpp +++ b/components/esm/loadland.cpp @@ -256,4 +256,30 @@ bool Land::isDataLoaded(int flags) const { return mLandData; } + + Land::LandData *Land::getLandData() + { + return mLandData; + } + + void Land::add (int flags) + { + if (!mLandData) + mLandData = new LandData; + + mDataTypes |= flags; + mDataLoaded |= flags; + } + + void Land::remove (int flags) + { + mDataTypes &= ~flags; + mDataLoaded &= ~flags; + + if (!mDataLoaded) + { + delete mLandData; + mLandData = 0; + } + } } diff --git a/components/esm/loadland.hpp b/components/esm/loadland.hpp index 64d131ecb..56267a28c 100644 --- a/components/esm/loadland.hpp +++ b/components/esm/loadland.hpp @@ -127,6 +127,17 @@ struct Land /// Return land data without loading first anything. Can return a 0-pointer. const LandData *getLandData() const; + /// Return land data without loading first anything. Can return a 0-pointer. + LandData *getLandData(); + + /// \attention Must not be called on objects that aren't fully loaded. + /// + /// \note Added data fields will be uninitialised + void add (int flags); + + /// \attention Must not be called on objects that aren't fully loaded. + void remove (int flags); + private: /// Loads data and marks it as loaded From d11952c48a7f2055b1bba79bd06c5180d15411d8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 4 Sep 2015 03:44:14 +0200 Subject: [PATCH 2130/3725] Stop rendering when the window is minimized --- apps/openmw/engine.cpp | 22 +++++++++++++++------- apps/openmw/mwbase/inputmanager.hpp | 2 ++ apps/openmw/mwinput/inputmanagerimp.cpp | 8 +++++++- apps/openmw/mwinput/inputmanagerimp.hpp | 3 +++ 4 files changed, 27 insertions(+), 8 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 32ff20ba7..6801363b1 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -92,10 +92,11 @@ void OMW::Engine::frame(float frametime) // update input mEnvironment.getInputManager()->update(frametime, false); - // When the window is minimized, pause everything. Currently this *has* to be here to work around a MyGUI bug. - // If we are not currently rendering, then RenderItems will not be reused resulting in a memory leak upon changing widget textures. - //if (!mOgre->getWindow()->isActive() || !mOgre->getWindow()->isVisible()) - // return true; + // When the window is minimized, pause the game. Currently this *has* to be here to work around a MyGUI bug. + // If we are not currently rendering, then RenderItems will not be reused resulting in a memory leak upon changing widget textures (fixed in MyGUI 3.3.2), + // and destroyed widgets will not be deleted (not fixed yet, https://github.com/MyGUI/mygui/issues/21) + if (!mEnvironment.getInputManager()->isWindowVisible()) + return; // sound if (mUseSound) @@ -689,9 +690,16 @@ void OMW::Engine::go() frame(dt); - mViewer->eventTraversal(); - mViewer->updateTraversal(); - mViewer->renderingTraversals(); + if (!mEnvironment.getInputManager()->isWindowVisible()) + { + OpenThreads::Thread::microSleep(5000); + } + else + { + mViewer->eventTraversal(); + mViewer->updateTraversal(); + mViewer->renderingTraversals(); + } } // Save user settings diff --git a/apps/openmw/mwbase/inputmanager.hpp b/apps/openmw/mwbase/inputmanager.hpp index 79477d883..75c55e028 100644 --- a/apps/openmw/mwbase/inputmanager.hpp +++ b/apps/openmw/mwbase/inputmanager.hpp @@ -25,6 +25,8 @@ namespace MWBase virtual ~InputManager() {} + virtual bool isWindowVisible() = 0; + virtual void update(float dt, bool disableControls, bool disableEvents=false) = 0; virtual void changeInputMode(bool guiMode) = 0; diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 74842e3e3..bd94d60c6 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -41,6 +41,7 @@ namespace MWInput const std::string& userFile, bool userFileExists, const std::string& controllerBindingsFile, bool grab) : mWindow(window) + , mWindowVisible(true) , mViewer(viewer) , mJoystickLastUsed(false) , mPlayer(NULL) @@ -156,6 +157,11 @@ namespace MWInput delete mVideoWrapper; } + bool InputManager::isWindowVisible() + { + return mWindowVisible; + } + void InputManager::setPlayerControlsEnabled(bool enabled) { int nPlayerChannels = 17; @@ -850,7 +856,7 @@ namespace MWInput void InputManager::windowVisibilityChange(bool visible) { - //TODO: Pause game? + mWindowVisible = visible; } void InputManager::windowResized(int x, int y) diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index aec640736..62d0f413b 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -83,6 +83,8 @@ namespace MWInput virtual ~InputManager(); + virtual bool isWindowVisible(); + /// Clear all savegame-specific data virtual void clear(); @@ -153,6 +155,7 @@ namespace MWInput private: SDL_Window* mWindow; + bool mWindowVisible; osg::ref_ptr mViewer; bool mJoystickLastUsed; From acbea2461b0eb6596a86154f584759d0dc18a842 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 4 Sep 2015 23:27:33 +0200 Subject: [PATCH 2131/3725] Fix a typo --- apps/openmw/mwworld/worldimp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 788aaca62..f50991e24 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -3156,7 +3156,7 @@ namespace MWWorld // Spawn the explosion orb effect const ESM::Static* areaStatic; - if (!effect->mCasting.empty()) + if (!effect->mArea.empty()) areaStatic = getStore().get().find (effect->mArea); else areaStatic = getStore().get().find ("VFX_DefaultArea"); From 96e3933ee9cdfbd17492ed2f2559b22e02b26909 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 6 Sep 2015 17:39:48 +1200 Subject: [PATCH 2132/3725] Fixed bug in smoothTurn() Now correctly handles changing direction from 178 to -178 degrees. --- apps/openmw/mwmechanics/steering.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwmechanics/steering.cpp b/apps/openmw/mwmechanics/steering.cpp index 219a23655..1ef46e1ae 100644 --- a/apps/openmw/mwmechanics/steering.cpp +++ b/apps/openmw/mwmechanics/steering.cpp @@ -14,14 +14,16 @@ bool smoothTurn(const MWWorld::Ptr& actor, float targetAngleRadians, int axis, f { float currentAngle (actor.getRefData().getPosition().rot[axis]); float diff (targetAngleRadians - currentAngle); - if (diff >= osg::DegreesToRadians(180.f)) + if (std::abs(diff) >= osg::DegreesToRadians(180.f)) { - // Turning the other way would be a better idea - diff = diff-osg::DegreesToRadians(360.f); - } - else if (diff <= osg::DegreesToRadians(-180.f)) - { - diff = osg::DegreesToRadians(360.f)-diff; + if (diff >= 0) + { + diff = diff - osg::DegreesToRadians(360.f); + } + else + { + diff = osg::DegreesToRadians(360.f) + diff; + } } float absDiff = std::abs(diff); From b68f64ed97aff7c48d6878241ecd64d6acaba2f5 Mon Sep 17 00:00:00 2001 From: Sebastian Wick Date: Sun, 6 Sep 2015 21:46:05 +0200 Subject: [PATCH 2133/3725] adjust FindMyGUI.cmake to correctly handle REQUIRED and QUIETLY --- cmake/FindMyGUI.cmake | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/cmake/FindMyGUI.cmake b/cmake/FindMyGUI.cmake index f85b6ba52..6e93a92ce 100644 --- a/cmake/FindMyGUI.cmake +++ b/cmake/FindMyGUI.cmake @@ -146,11 +146,12 @@ IF (MYGUI_FOUND) IF (NOT MYGUI_FIND_QUIETLY) MESSAGE(STATUS "MyGUI version: ${MYGUI_VERSION}") ENDIF (NOT MYGUI_FIND_QUIETLY) - -ELSE (MYGUI_FOUND) - IF (MYGUI_FIND_REQUIRED) - MESSAGE(FATAL_ERROR "Could not find MYGUI") - ENDIF (MYGUI_FIND_REQUIRED) ENDIF (MYGUI_FOUND) +include(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(MyGUI DEFAULT_MSG + MYGUI_INCLUDE_DIRS + FREETYPE_LIBRARIES + MYGUI_LIBRARIES) + CMAKE_POLICY(POP) From 481f23d955a8802b36cf7cc13ecb35c6c574b551 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 7 Sep 2015 16:05:51 +0200 Subject: [PATCH 2134/3725] Implement framerate limit setting The framerate limit can be used to reduce strain on the CPU and GPU, in a way similar to VSync, but without the increased input lag that is typical with VSync. --- apps/openmw/engine.cpp | 12 ++++++++++++ files/settings-default.cfg | 3 +++ 2 files changed, 15 insertions(+) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 6801363b1..79c8c4cc9 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -676,6 +676,7 @@ void OMW::Engine::go() // Start the main rendering loop osg::Timer frameTimer; double simulationTime = 0.0; + float framerateLimit = Settings::Manager::getFloat("framerate limit", "Video"); while (!mViewer->done() && !mEnvironment.getStateManager()->hasQuitRequest()) { double dt = frameTimer.time_s(); @@ -693,6 +694,7 @@ void OMW::Engine::go() if (!mEnvironment.getInputManager()->isWindowVisible()) { OpenThreads::Thread::microSleep(5000); + continue; } else { @@ -700,6 +702,16 @@ void OMW::Engine::go() mViewer->updateTraversal(); mViewer->renderingTraversals(); } + + if (framerateLimit > 0.f) + { + double thisFrameTime = frameTimer.time_s(); + double minFrameTime = 1.0 / framerateLimit; + if (thisFrameTime < minFrameTime) + { + OpenThreads::Thread::microSleep(1000*1000*(minFrameTime-thisFrameTime)); + } + } } // Save user settings diff --git a/files/settings-default.cfg b/files/settings-default.cfg index f2b6aa34f..c793225c2 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -20,6 +20,9 @@ vsync = false gamma = 1.00 contrast = 1.00 +# Maximum framerate in frames per second, 0 = unlimited +framerate limit = 0 + [GUI] scaling factor = 1.0 From 76fb68a9c0fceb2f7fc047ede26214ff18c5ea56 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 7 Sep 2015 22:07:09 +0200 Subject: [PATCH 2135/3725] Handle particle systems that don't have emitters Fixes a crash in the Magic Diversity mod. --- components/nifosg/nifloader.cpp | 43 ++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index c98008394..54a02c950 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -825,30 +825,33 @@ namespace NifOsg partsys->setFreezeOnCull(true); - osg::ref_ptr emitter = handleParticleEmitter(partctrl); - emitter->setParticleSystem(partsys); - emitter->setReferenceFrame(osgParticle::ParticleProcessor::RELATIVE_RF); + if (!partctrl->emitter.empty()) + { + osg::ref_ptr emitter = handleParticleEmitter(partctrl); + emitter->setParticleSystem(partsys); + emitter->setReferenceFrame(osgParticle::ParticleProcessor::RELATIVE_RF); - // Note: we assume that the Emitter node is placed *before* the Particle node in the scene graph. - // This seems to be true for all NIF files in the game that I've checked, suggesting that NIFs work similar to OSG with regards to update order. - // If something ever violates this assumption, the worst that could happen is the culling being one frame late, which wouldn't be a disaster. + // Note: we assume that the Emitter node is placed *before* the Particle node in the scene graph. + // This seems to be true for all NIF files in the game that I've checked, suggesting that NIFs work similar to OSG with regards to update order. + // If something ever violates this assumption, the worst that could happen is the culling being one frame late, which wouldn't be a disaster. - FindRecIndexVisitor find (partctrl->emitter->recIndex); - rootNode->accept(find); - if (!find.mFound) - { - std::cerr << "can't find emitter node, wrong node order? in " << mFilename << std::endl; - return; - } - osg::Group* emitterNode = find.mFound; + FindRecIndexVisitor find (partctrl->emitter->recIndex); + rootNode->accept(find); + if (!find.mFound) + { + std::cerr << "can't find emitter node, wrong node order? in " << mFilename << std::endl; + return; + } + osg::Group* emitterNode = find.mFound; - // Emitter attached to the emitter node. Note one side effect of the emitter using the CullVisitor is that hiding its node - // actually causes the emitter to stop firing. Convenient, because MW behaves this way too! - emitterNode->addChild(emitter); + // Emitter attached to the emitter node. Note one side effect of the emitter using the CullVisitor is that hiding its node + // actually causes the emitter to stop firing. Convenient, because MW behaves this way too! + emitterNode->addChild(emitter); - osg::ref_ptr callback(new ParticleSystemController(partctrl)); - setupController(partctrl, callback, animflags); - emitter->setUpdateCallback(callback); + osg::ref_ptr callback(new ParticleSystemController(partctrl)); + setupController(partctrl, callback, animflags); + emitter->setUpdateCallback(callback); + } // affectors must be attached *after* the emitter in the scene graph for correct update order // attach to same node as the ParticleSystem, we need osgParticle Operators to get the correct From fd48c1d6f4312ca96a401f1cc6341835133a50d8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 7 Sep 2015 21:32:28 +0200 Subject: [PATCH 2136/3725] Make the Equip script function "use" items (drink potion, use alchemy, etc) --- apps/openmw/mwbase/windowmanager.hpp | 3 +++ apps/openmw/mwgui/quickkeysmenu.cpp | 6 ++---- apps/openmw/mwgui/spellwindow.cpp | 3 +-- apps/openmw/mwgui/windowmanagerimp.cpp | 6 ++++++ apps/openmw/mwgui/windowmanagerimp.hpp | 3 +++ apps/openmw/mwscript/containerextensions.cpp | 12 +++++++----- 6 files changed, 22 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index f8bf157c2..fb7eca4a3 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -148,6 +148,9 @@ namespace MWBase virtual MWGui::ConfirmationDialog* getConfirmationDialog() = 0; virtual MWGui::TradeWindow* getTradeWindow() = 0; + /// Make the player use an item, while updating GUI state accordingly + virtual void useItem(const MWWorld::Ptr& item) = 0; + virtual void updateSpellWindow() = 0; virtual void setConsoleSelectedObject(const MWWorld::Ptr& object) = 0; diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index f1e474a2f..f2ae8dd83 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -21,8 +21,6 @@ #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/actorutil.hpp" -#include "../mwgui/inventorywindow.hpp" - #include "itemselection.hpp" #include "spellview.hpp" #include "itemwidget.hpp" @@ -311,7 +309,7 @@ namespace MWGui else if (type == Type_Item) { MWWorld::Ptr item = *button->getUserData(); - MWBase::Environment::get().getWindowManager()->getInventoryWindow()->useItem(item); + MWBase::Environment::get().getWindowManager()->useItem(item); MWWorld::ContainerStoreIterator rightHand = store.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); // change draw state only if the item is in player's right hand if (rightHand != store.end() && item == *rightHand) @@ -337,7 +335,7 @@ namespace MWGui // equip, if it can be equipped if (!item.getClass().getEquipmentSlots(item).first.empty()) { - MWBase::Environment::get().getWindowManager()->getInventoryWindow()->useItem(item); + MWBase::Environment::get().getWindowManager()->useItem(item); // make sure that item was successfully equipped if (!store.isEquipped(item)) diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index 68a604256..8422bb33f 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -18,7 +18,6 @@ #include "../mwmechanics/actorutil.hpp" #include "spellicons.hpp" -#include "inventorywindow.hpp" #include "confirmationdialog.hpp" #include "spellview.hpp" @@ -104,7 +103,7 @@ namespace MWGui if (!alreadyEquipped && !item.getClass().getEquipmentSlots(item).first.empty()) { - MWBase::Environment::get().getWindowManager()->getInventoryWindow()->useItem(item); + MWBase::Environment::get().getWindowManager()->useItem(item); // make sure that item was successfully equipped if (!store.isEquipped(item)) return; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 365f2c7a1..90a5f7481 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1327,6 +1327,12 @@ namespace MWGui MWGui::ConfirmationDialog* WindowManager::getConfirmationDialog() { return mConfirmationDialog; } MWGui::TradeWindow* WindowManager::getTradeWindow() { return mTradeWindow; } + void WindowManager::useItem(const MWWorld::Ptr &item) + { + if (mInventoryWindow) + mInventoryWindow->useItem(item); + } + bool WindowManager::isAllowed (GuiWindow wnd) const { return (mAllowed & wnd) != 0; diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 336a2a19a..a1f76683e 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -173,6 +173,9 @@ namespace MWGui virtual MWGui::ConfirmationDialog* getConfirmationDialog(); virtual MWGui::TradeWindow* getTradeWindow(); + /// Make the player use an item, while updating GUI state accordingly + virtual void useItem(const MWWorld::Ptr& item); + virtual void updateSpellWindow(); virtual void setConsoleSelectedObject(const MWWorld::Ptr& object); diff --git a/apps/openmw/mwscript/containerextensions.cpp b/apps/openmw/mwscript/containerextensions.cpp index 20ca2b580..ec14add9a 100644 --- a/apps/openmw/mwscript/containerextensions.cpp +++ b/apps/openmw/mwscript/containerextensions.cpp @@ -191,11 +191,13 @@ namespace MWScript if (it == invStore.end()) throw std::runtime_error("Item to equip not found"); - MWWorld::ActionEquip action (*it); - action.execute(ptr); - - if (ptr == MWMechanics::getPlayer() && !ptr.getClass().getScript(ptr).empty()) - ptr.getRefData().getLocals().setVarByInt(ptr.getClass().getScript(ptr), "onpcequip", 1); + if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + MWBase::Environment::get().getWindowManager()->useItem(*it); + else + { + boost::shared_ptr action = it->getClass().use(*it); + action->execute(ptr); + } } }; From e5d54fb539e92ec2bf9754e4b06cceee9f90f1da Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 7 Sep 2015 22:13:20 +0200 Subject: [PATCH 2137/3725] Check for actor being the player in various actions --- apps/openmw/mwworld/actionalchemy.cpp | 3 +++ apps/openmw/mwworld/actionapply.cpp | 2 +- apps/openmw/mwworld/actioneat.cpp | 2 +- apps/openmw/mwworld/actionread.cpp | 3 +++ apps/openmw/mwworld/actionrepair.cpp | 3 +++ apps/openmw/mwworld/actionsoulgem.cpp | 3 +++ 6 files changed, 14 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/actionalchemy.cpp b/apps/openmw/mwworld/actionalchemy.cpp index bbba1081c..f413f1aed 100644 --- a/apps/openmw/mwworld/actionalchemy.cpp +++ b/apps/openmw/mwworld/actionalchemy.cpp @@ -10,6 +10,9 @@ namespace MWWorld { void ActionAlchemy::executeImp (const Ptr& actor) { + if (actor != MWBase::Environment::get().getWorld()->getPlayerPtr()) + return; + if(MWBase::Environment::get().getWorld()->getPlayer().isInCombat()) { //Ensure we're not in combat MWBase::Environment::get().getWindowManager()->messageBox("#{sInventoryMessage3}"); return; diff --git a/apps/openmw/mwworld/actionapply.cpp b/apps/openmw/mwworld/actionapply.cpp index 00c9628ce..42757a41a 100644 --- a/apps/openmw/mwworld/actionapply.cpp +++ b/apps/openmw/mwworld/actionapply.cpp @@ -32,7 +32,7 @@ namespace MWWorld { MWBase::Environment::get().getWorld()->breakInvisibility(actor); - if (actor.getClass().apply (actor, mId, actor) && mUsageType!=-1) + if (actor.getClass().apply (actor, mId, actor) && mUsageType!=-1 && actor == MWBase::Environment::get().getWorld()->getPlayerPtr()) actor.getClass().skillUsageSucceeded (actor, mSkillIndex, mUsageType); actor.getClass().getContainerStore(actor).remove(getTarget(), 1, actor); diff --git a/apps/openmw/mwworld/actioneat.cpp b/apps/openmw/mwworld/actioneat.cpp index d9ca4aaf5..5339a113e 100644 --- a/apps/openmw/mwworld/actioneat.cpp +++ b/apps/openmw/mwworld/actioneat.cpp @@ -19,7 +19,7 @@ namespace MWWorld // apply to actor std::string id = getTarget().getClass().getId (getTarget()); - if (actor.getClass().apply (actor, id, actor)) + if (actor.getClass().apply (actor, id, actor) && actor == MWBase::Environment::get().getWorld()->getPlayerPtr()) actor.getClass().skillUsageSucceeded (actor, ESM::Skill::Alchemy, 1); } diff --git a/apps/openmw/mwworld/actionread.cpp b/apps/openmw/mwworld/actionread.cpp index cd0471a0e..d77ca73fd 100644 --- a/apps/openmw/mwworld/actionread.cpp +++ b/apps/openmw/mwworld/actionread.cpp @@ -18,6 +18,9 @@ namespace MWWorld void ActionRead::executeImp (const MWWorld::Ptr& actor) { + if (actor != MWBase::Environment::get().getWorld()->getPlayerPtr()) + return; + //Ensure we're not in combat if(MWBase::Environment::get().getWorld()->getPlayer().isInCombat() // Reading in combat is still allowed if the scroll/book is not in the player inventory yet diff --git a/apps/openmw/mwworld/actionrepair.cpp b/apps/openmw/mwworld/actionrepair.cpp index 699440a01..993f32cde 100644 --- a/apps/openmw/mwworld/actionrepair.cpp +++ b/apps/openmw/mwworld/actionrepair.cpp @@ -14,6 +14,9 @@ namespace MWWorld void ActionRepair::executeImp (const Ptr& actor) { + if (actor != MWBase::Environment::get().getWorld()->getPlayerPtr()) + return; + if(MWBase::Environment::get().getWorld()->getPlayer().isInCombat()) { MWBase::Environment::get().getWindowManager()->messageBox("#{sInventoryMessage2}"); return; diff --git a/apps/openmw/mwworld/actionsoulgem.cpp b/apps/openmw/mwworld/actionsoulgem.cpp index 7237fd334..f87c16482 100644 --- a/apps/openmw/mwworld/actionsoulgem.cpp +++ b/apps/openmw/mwworld/actionsoulgem.cpp @@ -16,6 +16,9 @@ namespace MWWorld void ActionSoulgem::executeImp(const Ptr &actor) { + if (actor != MWBase::Environment::get().getWorld()->getPlayerPtr()) + return; + if(MWBase::Environment::get().getWorld()->getPlayer().isInCombat()) { //Ensure we're not in combat MWBase::Environment::get().getWindowManager()->messageBox("#{sInventoryMessage5}"); return; From 5aa33fde4300b8e165905d41534d37d85d915ac1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 7 Sep 2015 22:16:15 +0200 Subject: [PATCH 2138/3725] Include cleanup --- apps/openmw/mwscript/containerextensions.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/openmw/mwscript/containerextensions.cpp b/apps/openmw/mwscript/containerextensions.cpp index ec14add9a..e33c7580f 100644 --- a/apps/openmw/mwscript/containerextensions.cpp +++ b/apps/openmw/mwscript/containerextensions.cpp @@ -23,7 +23,6 @@ #include "../mwworld/class.hpp" #include "../mwworld/containerstore.hpp" -#include "../mwworld/actionequip.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwmechanics/actorutil.hpp" From 0442bc98f3e0a6fd52fdf9f7bd1a59cf3e87bddc Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 7 Sep 2015 22:31:11 +0200 Subject: [PATCH 2139/3725] Update sleep interruption formula according to wiki, thanks Hrnchamd --- apps/openmw/mwgui/waitdialog.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index 733fdd132..e8ac63bf6 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -158,11 +158,15 @@ namespace MWGui // figure out if player will be woken while sleeping int x = Misc::Rng::rollDice(hoursToWait); float fSleepRandMod = world->getStore().get().find("fSleepRandMod")->getFloat(); - if (x < static_cast(fSleepRandMod * hoursToWait)) + if (x < fSleepRandMod * hoursToWait) { float fSleepRestMod = world->getStore().get().find("fSleepRestMod")->getFloat(); - mInterruptAt = hoursToWait - int(fSleepRestMod * hoursToWait); - mInterruptCreatureList = region->mSleepList; + int interruptAtHoursRemaining = int(fSleepRestMod * hoursToWait); + if (interruptAtHoursRemaining != 0) + { + mInterruptAt = hoursToWait - interruptAtHoursRemaining; + mInterruptCreatureList = region->mSleepList; + } } } } From b98a0760557c712bc1987b2646890027b6f185cb Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 7 Sep 2015 23:27:14 +0200 Subject: [PATCH 2140/3725] Add documentation for ACTN ess-record (activation flags) --- apps/essimporter/importacdt.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/apps/essimporter/importacdt.cpp b/apps/essimporter/importacdt.cpp index 9d881515d..a5f9d6eb3 100644 --- a/apps/essimporter/importacdt.cpp +++ b/apps/essimporter/importacdt.cpp @@ -10,7 +10,21 @@ namespace ESSImport void ActorData::load(ESM::ESMReader &esm) { if (esm.isNextSub("ACTN")) + { + /* + Activation flags: + ActivationFlag_UseEnabled = 1 + ActivationFlag_OnActivate = 2 + ActivationFlag_OnDeath = 10h + ActivationFlag_OnKnockout = 20h + ActivationFlag_OnMurder = 40h + ActivationFlag_DoorOpening = 100h + ActivationFlag_DoorClosing = 200h + ActivationFlag_DoorJammedOpening = 400h + ActivationFlag_DoorJammedClosing = 800h + */ esm.skipHSub(); + } if (esm.isNextSub("STPR")) esm.skipHSub(); From 73f6efddcc1b6f5816f9f775418c6317cf74ee20 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 8 Sep 2015 15:33:15 +0200 Subject: [PATCH 2141/3725] fixed a texture indexing bug (only affects the editor) --- apps/opencs/model/tools/mergestages.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/opencs/model/tools/mergestages.cpp b/apps/opencs/model/tools/mergestages.cpp index f4cb42aa4..e24d1f911 100644 --- a/apps/opencs/model/tools/mergestages.cpp +++ b/apps/opencs/model/tools/mergestages.cpp @@ -179,6 +179,9 @@ void CSMTools::MergeLandTexturesStage::perform (int stage, CSMDoc::Messages& mes CSMWorld::LandTexture texture = mState.mSource.getData().getLandTextures().getRecord (index).get(); + std::ostringstream stream; + stream << mNext->second << "_0"; + texture.mIndex = mNext->second; texture.mId = stream.str(); From 09ec60fe2a7b2cce91ee5f2271db4479b97ae228 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 8 Sep 2015 16:01:34 +0200 Subject: [PATCH 2142/3725] handle missing land texture records properly during merge --- apps/opencs/model/tools/mergestages.cpp | 47 ++++++++++++++----------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/apps/opencs/model/tools/mergestages.cpp b/apps/opencs/model/tools/mergestages.cpp index e24d1f911..fab5fae71 100644 --- a/apps/opencs/model/tools/mergestages.cpp +++ b/apps/opencs/model/tools/mergestages.cpp @@ -164,35 +164,42 @@ void CSMTools::MergeLandTexturesStage::perform (int stage, CSMDoc::Messages& mes if (stage==0) mNext = mState.mTextureIndices.begin(); - if (mNext==mState.mTextureIndices.end()) - return; + bool found = false; - mNext->second = stage; + do + { + if (mNext==mState.mTextureIndices.end()) + return; - std::ostringstream stream; - stream << mNext->first.first << "_" << mNext->first.second; + mNext->second = stage; - int index = mState.mSource.getData().getLandTextures().searchId (stream.str()); + std::ostringstream stream; + stream << mNext->first.first << "_" << mNext->first.second; - if (index!=-1) - { - CSMWorld::LandTexture texture = - mState.mSource.getData().getLandTextures().getRecord (index).get(); + int index = mState.mSource.getData().getLandTextures().searchId (stream.str()); - std::ostringstream stream; - stream << mNext->second << "_0"; + if (index!=-1) + { + CSMWorld::LandTexture texture = + mState.mSource.getData().getLandTextures().getRecord (index).get(); - texture.mIndex = mNext->second; - texture.mId = stream.str(); + std::ostringstream stream; + stream << mNext->second << "_0"; - CSMWorld::Record newRecord ( - CSMWorld::RecordBase::State_ModifiedOnly, 0, &texture); + texture.mIndex = mNext->second; + texture.mId = stream.str(); - mState.mTarget->getData().getLandTextures().appendRecord (newRecord); - } - /// \todo deal with missing textures (either abort merge or report and make sure OpenMW can deal with missing textures) + CSMWorld::Record newRecord ( + CSMWorld::RecordBase::State_ModifiedOnly, 0, &texture); + + mState.mTarget->getData().getLandTextures().appendRecord (newRecord); - ++mNext; + found = true; + } + + ++mNext; + } + while (!found); } From 29d74f024910c36ad6a474dbca4ccffe7db2e073 Mon Sep 17 00:00:00 2001 From: slothlife Date: Tue, 8 Sep 2015 22:05:33 -0500 Subject: [PATCH 2143/3725] Improve thunderstorm support. Reversed settings for thunderstorms. Added thunder support to all weather types. Implemented a simple lightning flash effect similar to MW. --- apps/openmw/mwrender/sky.cpp | 14 --- apps/openmw/mwrender/sky.hpp | 2 - apps/openmw/mwworld/weather.cpp | 169 +++++++++++++++++--------------- apps/openmw/mwworld/weather.hpp | 32 +++--- 4 files changed, 109 insertions(+), 108 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 138365ae4..dba2e5b0e 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1181,20 +1181,6 @@ void SkyManager::setSecundaState(const MoonState& state) mSecunda->setState(state); } -void SkyManager::setLightningStrength(const float factor) -{ - if (!mCreated) return; - /* - if (factor > 0.f) - { - mLightning->setDiffuseColour (ColourValue(2*factor, 2*factor, 2*factor)); - mLightning->setVisible(true); - } - else - mLightning->setVisible(false); - */ -} - void SkyManager::setDate(int day, int month) { mDay = day; diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index 3855136a9..de27cf447 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -140,8 +140,6 @@ namespace MWRender void setMasserState(const MoonState& state); void setSecundaState(const MoonState& state); - void setLightningStrength(const float factor); - void setGlare(const float glare); void setGlareEnabled(bool enabled); diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index e7c67d2e1..cdd0a8d79 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -80,15 +80,24 @@ Weather::Weather(const std::string& name, , mRainEffect(fallback.getFallbackBool("Weather_" + name + "_Using_Precip") ? "meshes\\raindrop.nif" : "") , mTransitionDelta(fallback.getFallbackFloat("Weather_" + name + "_Transition_Delta")) , mCloudsMaximumPercent(fallback.getFallbackFloat("Weather_" + name + "_Clouds_Maximum_Percent")) + , mThunderFrequency(fallback.getFallbackFloat("Weather_" + name + "_Thunder_Frequency")) + , mThunderThreshold(fallback.getFallbackFloat("Weather_" + name + "_Thunder_Threshold")) + , mThunderSoundID() + , mFlashDecrement(fallback.getFallbackFloat("Weather_" + name + "_Flash_Decrement")) + , mFlashBrightness(0.0f) { -/* -Unhandled: -Rain Diameter=600 ? -Rain Height Min=200 ? -Rain Height Max=700 ? -Rain Threshold=0.6 ? -Max Raindrops=650 ? -*/ + mThunderSoundID[0] = fallback.getFallbackString("Weather_" + name + "_Thunder_Sound_ID_0"); + mThunderSoundID[1] = fallback.getFallbackString("Weather_" + name + "_Thunder_Sound_ID_1"); + mThunderSoundID[2] = fallback.getFallbackString("Weather_" + name + "_Thunder_Sound_ID_2"); + mThunderSoundID[3] = fallback.getFallbackString("Weather_" + name + "_Thunder_Sound_ID_3"); + /* + Unhandled: + Rain Diameter=600 ? + Rain Height Min=200 ? + Rain Height Max=700 ? + Rain Threshold=0.6 ? + Max Raindrops=650 ? + */ } float Weather::transitionDelta() const @@ -98,12 +107,66 @@ float Weather::transitionDelta() const return mTransitionDelta; } -float Weather::cloudBlendFactor(float transitionRatio) const +float Weather::cloudBlendFactor(const float transitionRatio) const { // Clouds Maximum Percent affects how quickly the sky transitions from one sky texture to the next. return transitionRatio / mCloudsMaximumPercent; } +float Weather::calculateThunder(const float transitionRatio, const float elapsedSeconds, const bool isPaused) +{ + // When paused, the flash brightness remains the same and no new strikes can occur. + if(!isPaused) + { + // Morrowind doesn't appear to do any calculations unless the transition ratio is higher than the Thunder Threshold. + if(transitionRatio >= mThunderThreshold && mThunderFrequency > 0.0f) + { + flashDecrement(elapsedSeconds); + + if(Misc::Rng::rollProbability() <= thunderChance(transitionRatio, elapsedSeconds)) + { + lightningAndThunder(); + } + } + else + { + mFlashBrightness = 0.0f; + } + } + + return mFlashBrightness; +} + +inline void Weather::flashDecrement(const float elapsedSeconds) +{ + // The Flash Decrement is measured in whole units per second. This means that if the flash brightness was + // currently 1.0, then it should take approximately 0.25 seconds to decay to 0.0 (the minimum). + float decrement = mFlashDecrement * elapsedSeconds; + mFlashBrightness = decrement > mFlashBrightness ? 0.0f : mFlashBrightness - decrement; +} + +inline float Weather::thunderChance(const float transitionRatio, const float elapsedSeconds) const +{ + // This formula is reversed from the observation that with Thunder Frequency set to 1, there are roughly 10 strikes + // per minute. It doesn't appear to be tied to in game time as Timescale doesn't affect it. Various values of + // Thunder Frequency seem to change the average number of strikes in a linear fashion.. During a transition, it appears to + // scaled based on how far past it is past the Thunder Threshold. + float scaleFactor = (transitionRatio - mThunderThreshold) / (1.0f - mThunderThreshold); + return ((mThunderFrequency * 10.0f) / 60.0f) * elapsedSeconds * scaleFactor; +} + +inline void Weather::lightningAndThunder(void) +{ + // Morrowind seems to vary the intensity of the brightness based on which of the four sound IDs it selects. + // They appear to go from 0 (brightest, closest) to 3 (faintest, farthest). The value of 0.25 per distance + // was derived by setting the Flash Decrement to 0.1 and measuring how long each value took to decay to 0. + // TODO: Determine the distribution of each distance to see if it's evenly weighted. + unsigned int distance = Misc::Rng::rollDice(4); + // Flash brightness appears additive, since if multiple strikes occur, it takes longer for it to decay to 0. + mFlashBrightness += 1 - (distance * 0.25f); + MWBase::Environment::get().getSoundManager()->playSound(mThunderSoundID[distance], 1.0, 1.0); +} + RegionWeather::RegionWeather(const ESM::Region& region) : mWeather(invalidWeatherID) , mChances() @@ -378,19 +441,9 @@ WeatherManager::WeatherManager(MWRender::RenderingManager& rendering, const MWWo , mWeatherSettings() , mMasser("Masser", fallback) , mSecunda("Secunda", fallback) - , mThunderFrequency(fallback.getFallbackFloat("Weather_Thunderstorm_Thunder_Frequency")) - , mThunderThreshold(fallback.getFallbackFloat("Weather_Thunderstorm_Thunder_Threshold")) - , mThunderSoundID0(fallback.getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_0")) - , mThunderSoundID1(fallback.getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_1")) - , mThunderSoundID2(fallback.getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_2")) - , mThunderSoundID3(fallback.getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_3")) , mWindSpeed(0.f) , mIsStorm(false) , mStormDirection(0,1,0) - , mThunderSoundDelay(0.25) - , mThunderFlash(0) - , mThunderChance(0) - , mThunderChanceNeeded(50) , mCurrentRegion() , mTimePassed(0) , mFastForward(false) @@ -515,12 +568,11 @@ void WeatherManager::update(float duration, bool paused) if(!exterior) { mRendering.setSkyEnabled(false); - //mRendering->getSkyManager()->setLightningStrength(0.f); stopSounds(); return; } - calculateWeatherResult(time.getHour()); + calculateWeatherResult(time.getHour(), duration, paused); mWindSpeed = mResult.mWindSpeed; mIsStorm = mResult.mIsStorm; @@ -536,8 +588,6 @@ void WeatherManager::update(float duration, bool paused) mRendering.getSkyManager()->setStormDirection(mStormDirection); } - mRendering.configureFog(mResult.mFogDepth, mResult.mFogColor); - // disable sun during night if (time.getHour() >= mNightStart || time.getHour() <= mSunriseTime) mRendering.getSkyManager()->sunDisable(); @@ -577,56 +627,7 @@ void WeatherManager::update(float duration, bool paused) mRendering.getSkyManager()->setMasserState(mMasser.calculateState(time)); mRendering.getSkyManager()->setSecundaState(mSecunda.calculateState(time)); - if (!paused) - { - if(mCurrentWeather == 5 && !inTransition()) - { - if (mThunderFlash > 0) - { - // play the sound after a delay - mThunderSoundDelay -= duration; - if (mThunderSoundDelay <= 0) - { - // pick a random sound - int sound = Misc::Rng::rollDice(4); - std::string* soundName = NULL; - if (sound == 0) soundName = &mThunderSoundID0; - else if (sound == 1) soundName = &mThunderSoundID1; - else if (sound == 2) soundName = &mThunderSoundID2; - else if (sound == 3) soundName = &mThunderSoundID3; - if (soundName) - MWBase::Environment::get().getSoundManager()->playSound(*soundName, 1.0, 1.0); - mThunderSoundDelay = 1000; - } - - mThunderFlash -= duration; - //if (mThunderFlash > 0) - //mRendering->getSkyManager()->setLightningStrength( mThunderFlash / mThunderThreshold ); - //else - { - mThunderChanceNeeded = static_cast(Misc::Rng::rollDice(100)); - mThunderChance = 0; - //mRendering->getSkyManager()->setLightningStrength( 0.f ); - } - } - else - { - // no thunder active - mThunderChance += duration*4; // chance increases by 4 percent every second - if (mThunderChance >= mThunderChanceNeeded) - { - mThunderFlash = mThunderThreshold; - - //mRendering->getSkyManager()->setLightningStrength( mThunderFlash / mThunderThreshold ); - - mThunderSoundDelay = 0.25; - } - } - } - //else - //mRendering->getSkyManager()->setLightningStrength(0.f); - } - + mRendering.configureFog(mResult.mFogDepth, mResult.mFogColor); mRendering.setAmbientColour(mResult.mAmbientColor); mRendering.setSunColour(mResult.mSunColor); @@ -765,10 +766,6 @@ void WeatherManager::clear() { stopSounds(); - mThunderFlash = 0.0; - mThunderChance = 0.0; - mThunderChanceNeeded = 50.0; - mCurrentRegion = ""; mTimePassed = 0.0f; mWeatherUpdateTime = 0.0f; @@ -921,16 +918,32 @@ inline void WeatherManager::addWeatherTransition(const int weatherID) } } -inline void WeatherManager::calculateWeatherResult(const float gameHour) +inline void WeatherManager::calculateWeatherResult(const float gameHour, + const float elapsedSeconds, + const bool isPaused) { + float flash = 0.0f; if(!inTransition()) { calculateResult(mCurrentWeather, gameHour); + flash = mWeatherSettings[mCurrentWeather].calculateThunder(1.0f, elapsedSeconds, isPaused); } else { calculateTransitionResult(1 - mTransitionFactor, gameHour); + float currentFlash = mWeatherSettings[mCurrentWeather].calculateThunder(mTransitionFactor, + elapsedSeconds, + isPaused); + float nextFlash = mWeatherSettings[mNextWeather].calculateThunder(1 - mTransitionFactor, + elapsedSeconds, + isPaused); + flash = currentFlash + nextFlash; } + osg::Vec4f flashColor(flash, flash, flash, 0.0f); + + mResult.mFogColor += flashColor; + mResult.mAmbientColor += flashColor; + mResult.mSunColor += flashColor; } inline void WeatherManager::calculateResult(const int weatherID, const float gameHour) diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index c808b029b..a0c93a460 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -113,11 +113,27 @@ namespace MWWorld // is broken in the vanilla game and was disabled. float transitionDelta() const; - float cloudBlendFactor(float transitionRatio) const; + float cloudBlendFactor(const float transitionRatio) const; + + float calculateThunder(const float transitionRatio, const float elapsedSeconds, const bool isPaused); private: float mTransitionDelta; float mCloudsMaximumPercent; + + // Note: In MW, only thunderstorms support these attributes, but in the interest of making weather more + // flexible, these settings are imported for all weather types. Only thunderstorms will normally have any + // non-zero values. + float mThunderFrequency; + float mThunderThreshold; + std::string mThunderSoundID[4]; + float mFlashDecrement; + + float mFlashBrightness; + + void flashDecrement(const float elapsedSeconds); + float thunderChance(const float transitionRatio, const float elapsedSeconds) const; + void lightningAndThunder(void); }; /// A class for storing a region's weather. @@ -242,22 +258,10 @@ namespace MWWorld MoonModel mMasser; MoonModel mSecunda; - float mThunderFrequency; - float mThunderThreshold; - std::string mThunderSoundID0; - std::string mThunderSoundID1; - std::string mThunderSoundID2; - std::string mThunderSoundID3; - float mWindSpeed; bool mIsStorm; osg::Vec3f mStormDirection; - float mThunderSoundDelay; - float mThunderFlash; - float mThunderChance; - float mThunderChanceNeeded; - std::string mCurrentRegion; float mTimePassed; bool mFastForward; @@ -288,7 +292,7 @@ namespace MWWorld bool inTransition(); void addWeatherTransition(const int weatherID); - void calculateWeatherResult(const float gameHour); + void calculateWeatherResult(const float gameHour, const float elapsedSeconds, const bool isPaused); void calculateResult(const int weatherID, const float gameHour); void calculateTransitionResult(const float factor, const float gameHour); }; From e9c796166ae6866a118b0fec8a045373e5dc4577 Mon Sep 17 00:00:00 2001 From: dteviot Date: Thu, 10 Sep 2015 18:48:34 +1200 Subject: [PATCH 2144/3725] Added MWMechanics::isPlayerInCombat() --- apps/openmw/mwmechanics/actorutil.cpp | 7 +++++++ apps/openmw/mwmechanics/actorutil.hpp | 1 + apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 2 +- apps/openmw/mwworld/actionalchemy.cpp | 5 +++-- apps/openmw/mwworld/actionapply.cpp | 4 +++- apps/openmw/mwworld/actioneat.cpp | 4 +++- apps/openmw/mwworld/actionread.cpp | 5 +++-- apps/openmw/mwworld/actionrepair.cpp | 5 +++-- apps/openmw/mwworld/actionsoulgem.cpp | 5 +++-- 9 files changed, 27 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwmechanics/actorutil.cpp b/apps/openmw/mwmechanics/actorutil.cpp index dc3770556..537f27197 100644 --- a/apps/openmw/mwmechanics/actorutil.cpp +++ b/apps/openmw/mwmechanics/actorutil.cpp @@ -3,10 +3,17 @@ #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" +#include "../mwworld/player.hpp" + namespace MWMechanics { MWWorld::Ptr getPlayer() { return MWBase::Environment::get().getWorld()->getPlayerPtr(); } + + bool isPlayerInCombat() + { + return MWBase::Environment::get().getWorld()->getPlayer().isInCombat(); + } } diff --git a/apps/openmw/mwmechanics/actorutil.hpp b/apps/openmw/mwmechanics/actorutil.hpp index 95172b9f9..3c6dc940c 100644 --- a/apps/openmw/mwmechanics/actorutil.hpp +++ b/apps/openmw/mwmechanics/actorutil.hpp @@ -9,6 +9,7 @@ namespace MWWorld namespace MWMechanics { MWWorld::Ptr getPlayer(); + bool isPlayerInCombat(); } #endif diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 711ecdbd2..12927101d 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -927,7 +927,7 @@ namespace MWMechanics return true; } - if(MWBase::Environment::get().getWorld()->getPlayer().isInCombat()) { + if(MWMechanics::isPlayerInCombat()) { MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage2}"); return true; } diff --git a/apps/openmw/mwworld/actionalchemy.cpp b/apps/openmw/mwworld/actionalchemy.cpp index f413f1aed..53ed1ad84 100644 --- a/apps/openmw/mwworld/actionalchemy.cpp +++ b/apps/openmw/mwworld/actionalchemy.cpp @@ -5,15 +5,16 @@ #include "../mwbase/world.hpp" #include "../mwworld/player.hpp" +#include "../mwmechanics/actorutil.hpp" namespace MWWorld { void ActionAlchemy::executeImp (const Ptr& actor) { - if (actor != MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (actor != MWMechanics::getPlayer()) return; - if(MWBase::Environment::get().getWorld()->getPlayer().isInCombat()) { //Ensure we're not in combat + if(MWMechanics::isPlayerInCombat()) { //Ensure we're not in combat MWBase::Environment::get().getWindowManager()->messageBox("#{sInventoryMessage3}"); return; } diff --git a/apps/openmw/mwworld/actionapply.cpp b/apps/openmw/mwworld/actionapply.cpp index 42757a41a..e3699a6ac 100644 --- a/apps/openmw/mwworld/actionapply.cpp +++ b/apps/openmw/mwworld/actionapply.cpp @@ -7,6 +7,8 @@ #include "../mwworld/containerstore.hpp" +#include "../mwmechanics/actorutil.hpp" + namespace MWWorld { ActionApply::ActionApply (const Ptr& object, const std::string& id) @@ -32,7 +34,7 @@ namespace MWWorld { MWBase::Environment::get().getWorld()->breakInvisibility(actor); - if (actor.getClass().apply (actor, mId, actor) && mUsageType!=-1 && actor == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (actor.getClass().apply (actor, mId, actor) && mUsageType!=-1 && actor == MWMechanics::getPlayer()) actor.getClass().skillUsageSucceeded (actor, mSkillIndex, mUsageType); actor.getClass().getContainerStore(actor).remove(getTarget(), 1, actor); diff --git a/apps/openmw/mwworld/actioneat.cpp b/apps/openmw/mwworld/actioneat.cpp index 5339a113e..82c7fb80e 100644 --- a/apps/openmw/mwworld/actioneat.cpp +++ b/apps/openmw/mwworld/actioneat.cpp @@ -7,6 +7,8 @@ #include "../mwworld/containerstore.hpp" +#include "../mwmechanics/actorutil.hpp" + #include "class.hpp" namespace MWWorld @@ -19,7 +21,7 @@ namespace MWWorld // apply to actor std::string id = getTarget().getClass().getId (getTarget()); - if (actor.getClass().apply (actor, id, actor) && actor == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (actor.getClass().apply (actor, id, actor) && actor == MWMechanics::getPlayer()) actor.getClass().skillUsageSucceeded (actor, ESM::Skill::Alchemy, 1); } diff --git a/apps/openmw/mwworld/actionread.cpp b/apps/openmw/mwworld/actionread.cpp index d77ca73fd..90e9a375b 100644 --- a/apps/openmw/mwworld/actionread.cpp +++ b/apps/openmw/mwworld/actionread.cpp @@ -5,6 +5,7 @@ #include "../mwbase/world.hpp" #include "../mwmechanics/npcstats.hpp" +#include "../mwmechanics/actorutil.hpp" #include "player.hpp" #include "class.hpp" @@ -18,11 +19,11 @@ namespace MWWorld void ActionRead::executeImp (const MWWorld::Ptr& actor) { - if (actor != MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (actor != MWMechanics::getPlayer()) return; //Ensure we're not in combat - if(MWBase::Environment::get().getWorld()->getPlayer().isInCombat() + if(MWMechanics::isPlayerInCombat() // Reading in combat is still allowed if the scroll/book is not in the player inventory yet // (since otherwise, there would be no way to pick it up) && getTarget().getContainerStore() == &actor.getClass().getContainerStore(actor) diff --git a/apps/openmw/mwworld/actionrepair.cpp b/apps/openmw/mwworld/actionrepair.cpp index 993f32cde..8e19927b8 100644 --- a/apps/openmw/mwworld/actionrepair.cpp +++ b/apps/openmw/mwworld/actionrepair.cpp @@ -4,6 +4,7 @@ #include "../mwbase/windowmanager.hpp" #include "../mwbase/world.hpp" #include "../mwworld/player.hpp" +#include "../mwmechanics/actorutil.hpp" namespace MWWorld { @@ -14,10 +15,10 @@ namespace MWWorld void ActionRepair::executeImp (const Ptr& actor) { - if (actor != MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (actor != MWMechanics::getPlayer()) return; - if(MWBase::Environment::get().getWorld()->getPlayer().isInCombat()) { + if(MWMechanics::isPlayerInCombat()) { MWBase::Environment::get().getWindowManager()->messageBox("#{sInventoryMessage2}"); return; } diff --git a/apps/openmw/mwworld/actionsoulgem.cpp b/apps/openmw/mwworld/actionsoulgem.cpp index f87c16482..98fe8ee34 100644 --- a/apps/openmw/mwworld/actionsoulgem.cpp +++ b/apps/openmw/mwworld/actionsoulgem.cpp @@ -4,6 +4,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwworld/player.hpp" +#include "../mwmechanics/actorutil.hpp" namespace MWWorld { @@ -16,10 +17,10 @@ namespace MWWorld void ActionSoulgem::executeImp(const Ptr &actor) { - if (actor != MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (actor != MWMechanics::getPlayer()) return; - if(MWBase::Environment::get().getWorld()->getPlayer().isInCombat()) { //Ensure we're not in combat + if(MWMechanics::isPlayerInCombat()) { //Ensure we're not in combat MWBase::Environment::get().getWindowManager()->messageBox("#{sInventoryMessage5}"); return; } From 573a14993ac1d41979c805cd6298bd9f82227a64 Mon Sep 17 00:00:00 2001 From: dteviot Date: Thu, 10 Sep 2015 21:53:31 +1200 Subject: [PATCH 2145/3725] Moved isActorNearInactiveCell() logic to own function. Also, triggers when actor is near edge of cell, not when less than 1/2 way to edge. --- apps/openmw/mwmechanics/aipackage.cpp | 62 ++++++++++++++------------- apps/openmw/mwmechanics/aipackage.hpp | 1 + 2 files changed, 34 insertions(+), 29 deletions(-) diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index b6b240833..e5da16865 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -16,6 +16,7 @@ #include "steering.hpp" #include "actorutil.hpp" +#include "coordinateconverter.hpp" MWMechanics::AiPackage::~AiPackage() {} @@ -32,45 +33,24 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, ESM::Pathgrid::Po ESM::Position pos = actor.getRefData().getPosition(); //position of the actor /// Stops the actor when it gets too close to a unloaded cell - const ESM::Cell *cell = actor.getCell()->getCell(); + //... At current time, this test is unnecessary. AI shuts down when actor is more than 7168 + //... units from player, and exterior cells are 8192 units long and wide. + //... But AI processing distance may increase in the future. + if (isActorNearInactiveCell(pos)) { - MWWorld::Ptr player = getPlayer(); - Movement &movement = actor.getClass().getMovementSettings(actor); - - //Ensure pursuer doesn't leave loaded cells - if(cell->mData.mX != player.getCell()->getCell()->mData.mX) - { - int sideX = PathFinder::sgn(cell->mData.mX - player.getCell()->getCell()->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)) - { - movement.mPosition[1] = 0; - return false; - } - } - if(cell->mData.mY != player.getCell()->getCell()->mData.mY) - { - int sideY = PathFinder::sgn(cell->mData.mY - player.getCell()->getCell()->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)) - { - movement.mPosition[1] = 0; - return false; - } - } + actor.getClass().getMovementSettings(actor).mPosition[1] = 0; + return false; } - //Start position - ESM::Pathgrid::Point start = pos.pos; - //*********************** /// Checks if you can't get to the end position at all, adds end position to end of path /// Rebuilds path every quarter of a second, in case the target has moved //*********************** if(mTimer > 0.25) { + const ESM::Cell *cell = actor.getCell()->getCell(); if (doesPathNeedRecalc(dest, cell)) { //Only rebuild path if it's moved - mPathFinder.buildSyncedPath(start, dest, actor.getCell(), true); //Rebuild path, in case the target has moved + mPathFinder.buildSyncedPath(pos.pos, dest, actor.getCell(), true); //Rebuild path, in case the target has moved mPrevDest = dest; } @@ -133,3 +113,27 @@ bool MWMechanics::AiPackage::isTargetMagicallyHidden(const MWWorld::Ptr& target) return (magicEffects.get(ESM::MagicEffect::Invisibility).getMagnitude() > 0) || (magicEffects.get(ESM::MagicEffect::Chameleon).getMagnitude() > 75); } + +bool MWMechanics::AiPackage::isActorNearInactiveCell(const ESM::Position& actorPos) +{ + const ESM::Cell* playerCell(getPlayer().getCell()->getCell()); + if (playerCell->isExterior()) + { + // get actor's distance from origin of center cell + osg::Vec3f actorOffset(actorPos.asVec3()); + CoordinateConverter(playerCell).ToLocal(actorOffset); + + // currently assumes 3 x 3 grid for exterior cells, with player at center cell. + // ToDo: (Maybe) use "exterior cell load distance" setting to get count of actual active cells + // While AI Process distance is 7168, AI shuts down actors before they reach edges of 3 x 3 grid. + const float distanceFromEdge = 200.0; + float minThreshold = (-1.0f * ESM::Land::REAL_SIZE) + distanceFromEdge; + float maxThreshold = (2.0f * ESM::Land::REAL_SIZE) - distanceFromEdge; + return (actorOffset[0] < minThreshold) || (maxThreshold < actorOffset[0]) + || (actorOffset[1] < minThreshold) || (maxThreshold < actorOffset[1]); + } + else + { + return false; + } +} \ No newline at end of file diff --git a/apps/openmw/mwmechanics/aipackage.hpp b/apps/openmw/mwmechanics/aipackage.hpp index 4f919edbc..befd159bf 100644 --- a/apps/openmw/mwmechanics/aipackage.hpp +++ b/apps/openmw/mwmechanics/aipackage.hpp @@ -88,6 +88,7 @@ namespace MWMechanics private: void evadeObstacles(const MWWorld::Ptr& actor, float duration, ESM::Position& pos); + bool isActorNearInactiveCell(const ESM::Position& actorPos); }; } From 6f97187bb6558c44978d106b1394fe2c353406c1 Mon Sep 17 00:00:00 2001 From: dteviot Date: Thu, 10 Sep 2015 22:26:33 +1200 Subject: [PATCH 2146/3725] Fix travis warning about no newline at end of file. --- apps/openmw/mwmechanics/aipackage.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index e5da16865..c4091c63e 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -136,4 +136,4 @@ bool MWMechanics::AiPackage::isActorNearInactiveCell(const ESM::Position& actorP { return false; } -} \ No newline at end of file +} From 584a7a66b97739c91c38cf8f17922ba29d5536e2 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 10 Sep 2015 12:41:31 +0200 Subject: [PATCH 2147/3725] various minor fixes --- apps/opencs/model/tools/mergestages.cpp | 33 ++++++++++++++----------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/apps/opencs/model/tools/mergestages.cpp b/apps/opencs/model/tools/mergestages.cpp index fab5fae71..f7c3b8dc0 100644 --- a/apps/opencs/model/tools/mergestages.cpp +++ b/apps/opencs/model/tools/mergestages.cpp @@ -124,7 +124,7 @@ void CSMTools::ListLandTexturesMergeStage::perform (int stage, CSMDoc::Messages& if (!record.isDeleted()) { - const ESM::Land& land = record.get(); + const CSMWorld::Land& land = record.get(); // make sure record is loaded land.loadData (ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML | @@ -228,22 +228,25 @@ void CSMTools::MergeLandStage::perform (int stage, CSMDoc::Messages& messages) // because record is already fully loaded) newLand.mPlugin = 0; - // adjust land texture references - if (ESM::Land::LandData *data = newLand.getLandData()) + if (land.mDataTypes & ESM::Land::DATA_VTEX) { - std::pair key; - key.second = land.mPlugin; - - for (int i=0; imTextures[i]; - std::map, int>::const_iterator iter = - mState.mTextureIndices.find (key); - - if (iter!=mState.mTextureIndices.end()) - data->mTextures[i] = iter->second; - else - data->mTextures[i] = 0; + std::pair key; + key.second = land.mPlugin; + + for (int i=0; imTextures[i]; + std::map, int>::const_iterator iter = + mState.mTextureIndices.find (key); + + if (iter!=mState.mTextureIndices.end()) + data->mTextures[i] = iter->second; + else + data->mTextures[i] = 0; + } } } From 10eabc9d519d27d5a02c66e7c7bb886ad55228b2 Mon Sep 17 00:00:00 2001 From: dteviot Date: Fri, 11 Sep 2015 18:43:06 +1200 Subject: [PATCH 2148/3725] actorutil.hpp includes mwworld/ptr.hpp As pointed out by Scrawl, fixes compiler error if getPlayer() is called before MWWorld::Ptr is defined, because getPlayer() returns a Ptr by value. --- apps/openmw/mwmechanics/actorutil.hpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/actorutil.hpp b/apps/openmw/mwmechanics/actorutil.hpp index 3c6dc940c..510e41db3 100644 --- a/apps/openmw/mwmechanics/actorutil.hpp +++ b/apps/openmw/mwmechanics/actorutil.hpp @@ -1,10 +1,7 @@ #ifndef OPENMW_MWMECHANICS_ACTORUTIL_H #define OPENMW_MWMECHANICS_ACTORUTIL_H -namespace MWWorld -{ - class Ptr; -} +#include "../mwworld/ptr.hpp" namespace MWMechanics { From 23fde87816644912c9896920b80348429a045003 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 11 Sep 2015 10:50:19 +0200 Subject: [PATCH 2149/3725] fixed an indexing error --- apps/opencs/model/tools/mergestages.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/opencs/model/tools/mergestages.cpp b/apps/opencs/model/tools/mergestages.cpp index f7c3b8dc0..52e1e6964 100644 --- a/apps/opencs/model/tools/mergestages.cpp +++ b/apps/opencs/model/tools/mergestages.cpp @@ -171,10 +171,10 @@ void CSMTools::MergeLandTexturesStage::perform (int stage, CSMDoc::Messages& mes if (mNext==mState.mTextureIndices.end()) return; - mNext->second = stage; + mNext->second = stage+1; std::ostringstream stream; - stream << mNext->first.first << "_" << mNext->first.second; + stream << mNext->first.first-1 << "_" << mNext->first.second; int index = mState.mSource.getData().getLandTextures().searchId (stream.str()); @@ -184,9 +184,9 @@ void CSMTools::MergeLandTexturesStage::perform (int stage, CSMDoc::Messages& mes mState.mSource.getData().getLandTextures().getRecord (index).get(); std::ostringstream stream; - stream << mNext->second << "_0"; + stream << mNext->second-1 << "_0"; - texture.mIndex = mNext->second; + texture.mIndex = mNext->second-1; texture.mId = stream.str(); CSMWorld::Record newRecord ( From 5be176ee85da349163e161f86693f836fb1b5fdc Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 11 Sep 2015 13:02:24 +0200 Subject: [PATCH 2150/3725] disable on-demand loading of land data (for now, maybe) --- apps/opencs/model/world/data.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index fe6d6ccbb..a95761929 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -955,8 +955,10 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Messages& messages) { int index = mLand.load(*mReader, mBase); - if (index!=-1 && !mBase) - mLand.getRecord (index).mModified.loadData ( + // Load all land data for now. A future optimisation may only load non-base data + // if a suitable mechanism for avoiding race conditions can be established. + if (index!=-1/* && !mBase*/) + mLand.getRecord (index).get().loadData ( ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML | ESM::Land::DATA_VCLR | ESM::Land::DATA_VTEX | ESM::Land::DATA_WNAM); From 5252dbcf1f4dc311419ca9f7d5f32a765771d1e0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 11 Sep 2015 21:09:54 +0200 Subject: [PATCH 2151/3725] Add some comments to ESM::Land --- components/esm/loadland.hpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/components/esm/loadland.hpp b/components/esm/loadland.hpp index 56267a28c..8ec4f74ea 100644 --- a/components/esm/loadland.hpp +++ b/components/esm/loadland.hpp @@ -76,17 +76,29 @@ struct Land struct LandData { + // Initial reference height for the first vertex, only needed for filling mHeights float mHeightOffset; + // Height in world space for each vertex float mHeights[LAND_NUM_VERTS]; + + // 24-bit normals, these aren't always correct though. Edge and corner normals may be garbage. VNML mNormals[LAND_NUM_VERTS * 3]; + + // 2D array of texture indices. An index can be used to look up an ESM::LandTexture, + // but to do so you must subtract 1 from the index first! + // An index of 0 indicates the default texture. uint16_t mTextures[LAND_NUM_TEXTURES]; + // 24-bit RGB color for each vertex unsigned char mColours[3 * LAND_NUM_VERTS]; + + // DataTypes available in this LandData, accessing data that is not available is an undefined operation int mDataTypes; // low-LOD heightmap (used for rendering the global map) signed char mWnam[81]; + // ??? short mUnk1; uint8_t mUnk2; From 258b2ba29abedf329db1db2c5660cf213445c999 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 12 Sep 2015 09:04:43 +1000 Subject: [PATCH 2152/3725] Ensure ColumnId names are unique. Filter parser calls Columns::getId() which implies that these should be unique. --- apps/opencs/model/world/columns.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 045438bef..e6dabc4d7 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -265,7 +265,7 @@ namespace CSMWorld { ColumnId_LevelledList,"Levelled List" }, { ColumnId_LevelledItemId,"Levelled Item" }, - { ColumnId_LevelledItemLevel,"Level" }, + { ColumnId_LevelledItemLevel,"Item Level" }, { ColumnId_LevelledItemType, "Calculate all levels <= player" }, { ColumnId_LevelledItemTypeEach, "Select a new item each instance" }, { ColumnId_LevelledItemChanceNone, "Chance None" }, @@ -281,26 +281,26 @@ namespace CSMWorld { ColumnId_InfoCondValue, "Values" }, { ColumnId_OriginalCell, "Original Cell" }, - { ColumnId_NpcAttributes, "Attributes" }, - { ColumnId_NpcSkills, "Skills" }, + { ColumnId_NpcAttributes, "NPC Attributes" }, + { ColumnId_NpcSkills, "NPC Skill" }, { ColumnId_UChar, "Value [0..255]" }, - { ColumnId_NpcMisc, "Misc" }, + { ColumnId_NpcMisc, "NPC Misc" }, { ColumnId_NpcLevel, "Level" }, { ColumnId_NpcFactionID, "Faction ID" }, - { ColumnId_NpcHealth, "Health" }, + { ColumnId_NpcHealth, "NPC Health" }, { ColumnId_NpcMana, "Mana" }, { ColumnId_NpcFatigue, "Fatigue" }, - { ColumnId_NpcDisposition, "Disposition" }, + { ColumnId_NpcDisposition, "NPC Disposition" }, { ColumnId_NpcReputation, "Reputation" }, - { ColumnId_NpcRank, "Rank" }, + { ColumnId_NpcRank, "NPC Rank" }, { ColumnId_NpcGold, "Gold" }, { ColumnId_NpcPersistence, "Persistent" }, - { ColumnId_RaceAttributes, "Attributes" }, - { ColumnId_RaceMaleValue, "Male" }, - { ColumnId_RaceFemaleValue, "Female" }, + { ColumnId_RaceAttributes, "Race Attributes" }, + { ColumnId_RaceMaleValue, "Male Attrib" }, + { ColumnId_RaceFemaleValue, "Female Attrib" }, { ColumnId_RaceSkillBonus, "Skill Bonus" }, - { ColumnId_RaceSkill, "Skills" }, + { ColumnId_RaceSkill, "Race Skill" }, { ColumnId_RaceBonus, "Bonus" }, { ColumnId_Interior, "Interior" }, From c4a900ca2c9b98267c9a507bb887829373fc9193 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 12 Sep 2015 09:33:11 +1000 Subject: [PATCH 2153/3725] Rationalise the use of ColumnIds --- apps/opencs/model/world/columns.cpp | 15 +++++---------- apps/opencs/model/world/columns.hpp | 14 +++++++------- apps/opencs/model/world/data.cpp | 4 ++-- apps/opencs/model/world/nestedcoladapterimp.cpp | 2 +- apps/opencs/model/world/refidadapterimp.cpp | 15 ++------------- apps/opencs/model/world/refidcollection.cpp | 14 +++++++------- apps/opencs/view/doc/viewmanager.cpp | 1 - 7 files changed, 24 insertions(+), 41 deletions(-) diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index e6dabc4d7..9f39be5f3 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -199,8 +199,6 @@ namespace CSMWorld { ColumnId_RotY, "Rotation Y"}, { ColumnId_RotZ, "Rotation Z"}, - { ColumnId_Skill, "Skill" }, - { ColumnId_OwnerGlobal, "Owner Global" }, { ColumnId_DefaultProfile, "Default Profile" }, { ColumnId_BypassNewGame, "Bypass New Game" }, @@ -271,7 +269,7 @@ namespace CSMWorld { ColumnId_LevelledItemChanceNone, "Chance None" }, { ColumnId_PowerList, "Powers" }, - { ColumnId_SkillImpact, "Skills" }, + { ColumnId_SkillImpact, "Skill" }, { ColumnId_InfoList, "Info List" }, { ColumnId_InfoCondition, "Info Conditions" }, @@ -285,22 +283,20 @@ namespace CSMWorld { ColumnId_NpcSkills, "NPC Skill" }, { ColumnId_UChar, "Value [0..255]" }, { ColumnId_NpcMisc, "NPC Misc" }, - { ColumnId_NpcLevel, "Level" }, + { ColumnId_Level, "Level" }, { ColumnId_NpcFactionID, "Faction ID" }, - { ColumnId_NpcHealth, "NPC Health" }, - { ColumnId_NpcMana, "Mana" }, - { ColumnId_NpcFatigue, "Fatigue" }, + { ColumnId_Mana, "Mana" }, + { ColumnId_Fatigue, "Fatigue" }, { ColumnId_NpcDisposition, "NPC Disposition" }, { ColumnId_NpcReputation, "Reputation" }, { ColumnId_NpcRank, "NPC Rank" }, - { ColumnId_NpcGold, "Gold" }, + { ColumnId_Gold, "Gold" }, { ColumnId_NpcPersistence, "Persistent" }, { ColumnId_RaceAttributes, "Race Attributes" }, { ColumnId_RaceMaleValue, "Male Attrib" }, { ColumnId_RaceFemaleValue, "Female Attrib" }, { ColumnId_RaceSkillBonus, "Skill Bonus" }, - { ColumnId_RaceSkill, "Race Skill" }, { ColumnId_RaceBonus, "Bonus" }, { ColumnId_Interior, "Interior" }, @@ -579,7 +575,6 @@ namespace // FIXME: don't have dynamic value enum delegate, use Display_String for now //case CSMWorld::Columns::ColumnId_InfoCond: return sInfoCond; case CSMWorld::Columns::ColumnId_InfoCondComp: return sInfoCondComp; - case CSMWorld::Columns::ColumnId_RaceSkill: return sSkills; default: return 0; } diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 2f66542b1..5deaf65cb 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -189,7 +189,7 @@ namespace CSMWorld ColumnId_RotX = 174, ColumnId_RotY = 175, ColumnId_RotZ = 176, - ColumnId_Skill = 177, + // unused ColumnId_OwnerGlobal = 178, ColumnId_DefaultProfile = 179, ColumnId_BypassNewGame = 180, @@ -276,22 +276,22 @@ namespace CSMWorld ColumnId_NpcSkills = 249, ColumnId_UChar = 250, ColumnId_NpcMisc = 251, - ColumnId_NpcLevel = 252, + ColumnId_Level = 252, ColumnId_NpcFactionID = 253, - ColumnId_NpcHealth = 254, - ColumnId_NpcMana = 255, - ColumnId_NpcFatigue = 256, + // unused + ColumnId_Mana = 255, + ColumnId_Fatigue = 256, ColumnId_NpcDisposition = 257, ColumnId_NpcReputation = 258, ColumnId_NpcRank = 259, - ColumnId_NpcGold = 260, + ColumnId_Gold = 260, ColumnId_NpcPersistence = 261, ColumnId_RaceAttributes = 262, ColumnId_RaceMaleValue = 263, ColumnId_RaceFemaleValue = 264, ColumnId_RaceSkillBonus = 265, - ColumnId_RaceSkill = 266, + // unused ColumnId_RaceBonus = 267, ColumnId_Interior = 268, diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index ab9c8f74e..a27ab5094 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -140,7 +140,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc index = mRaces.getColumns()-1; mRaces.addAdapter (std::make_pair(&mRaces.getColumn(index), new RaceAttributeAdapter())); mRaces.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_RaceAttributes, ColumnBase::Display_String, + new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_Attribute, ColumnBase::Flag_Dialogue, false)); mRaces.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_RaceMaleValue, ColumnBase::Display_Integer)); @@ -151,7 +151,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc index = mRaces.getColumns()-1; mRaces.addAdapter (std::make_pair(&mRaces.getColumn(index), new RaceSkillsBonusAdapter())); mRaces.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_RaceSkill, ColumnBase::Display_RaceSkill)); + new NestedChildColumn (Columns::ColumnId_SkillImpact, ColumnBase::Display_SkillImpact)); mRaces.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_RaceBonus, ColumnBase::Display_Integer)); diff --git a/apps/opencs/model/world/nestedcoladapterimp.cpp b/apps/opencs/model/world/nestedcoladapterimp.cpp index dc5cd2299..002838c67 100644 --- a/apps/opencs/model/world/nestedcoladapterimp.cpp +++ b/apps/opencs/model/world/nestedcoladapterimp.cpp @@ -922,7 +922,7 @@ namespace CSMWorld switch (subColIndex) { - case 0: return QString(ESM::Attribute::sAttributeNames[subRowIndex].c_str()); + case 0: return subRowIndex; case 1: return race.mData.mAttributeValues[subRowIndex].mMale; case 2: return race.mData.mAttributeValues[subRowIndex].mFemale; default: throw std::runtime_error("Race Attribute subcolumn index out of range"); diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index c8cca5c3d..6a881d0af 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -694,18 +694,7 @@ QVariant CSMWorld::NpcAttributesRefIdAdapter::getNestedData (const RefIdColumn * const ESM::NPC::NPDTstruct52& npcStruct = record.get().mNpdt52; if (subColIndex == 0) - switch (subRowIndex) - { - case 0: return QString("Strength"); - case 1: return QString("Intelligence"); - case 2: return QString("Willpower"); - case 3: return QString("Agility"); - case 4: return QString("Speed"); - case 5: return QString("Endurance"); - case 6: return QString("Personality"); - case 7: return QString("Luck"); - default: return QVariant(); // throw an exception here? - } + return subRowIndex; else if (subColIndex == 1) switch (subRowIndex) { @@ -815,7 +804,7 @@ QVariant CSMWorld::NpcSkillsRefIdAdapter::getNestedData (const RefIdColumn *colu throw std::runtime_error ("index out of range"); if (subColIndex == 0) - return QString(ESM::Skill::sSkillNames[subRowIndex].c_str()); + return subRowIndex; else if (subColIndex == 1) return static_cast(npcStruct.mSkills[subRowIndex]); else diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index c4d110754..b20e12fef 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -439,7 +439,7 @@ CSMWorld::RefIdCollection::RefIdCollection() attrMap.insert(std::make_pair(UniversalId::Type_Npc, new NpcAttributesRefIdAdapter())); mNestedAdapters.push_back (std::make_pair(&mColumns.back(), attrMap)); mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_NpcAttributes, CSMWorld::ColumnBase::Display_String, false, false)); + new RefIdColumn (Columns::ColumnId_Attribute, CSMWorld::ColumnBase::Display_Attribute, false, false)); mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_UChar, CSMWorld::ColumnBase::Display_Integer)); @@ -451,7 +451,7 @@ CSMWorld::RefIdCollection::RefIdCollection() skillsMap.insert(std::make_pair(UniversalId::Type_Npc, new NpcSkillsRefIdAdapter())); mNestedAdapters.push_back (std::make_pair(&mColumns.back(), skillsMap)); mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_NpcSkills, CSMWorld::ColumnBase::Display_String, false, false)); + new RefIdColumn (Columns::ColumnId_SkillImpact, CSMWorld::ColumnBase::Display_SkillImpact, false, false)); mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_UChar, CSMWorld::ColumnBase::Display_Integer)); @@ -463,15 +463,15 @@ CSMWorld::RefIdCollection::RefIdCollection() miscMap.insert(std::make_pair(UniversalId::Type_Npc, new NpcMiscRefIdAdapter())); mNestedAdapters.push_back (std::make_pair(&mColumns.back(), miscMap)); mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_NpcLevel, CSMWorld::ColumnBase::Display_Integer)); + new RefIdColumn (Columns::ColumnId_Level, CSMWorld::ColumnBase::Display_Integer)); mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_NpcFactionID, CSMWorld::ColumnBase::Display_Integer)); mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_NpcHealth, CSMWorld::ColumnBase::Display_Integer)); + new RefIdColumn (Columns::ColumnId_Health, CSMWorld::ColumnBase::Display_Integer)); mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_NpcMana, CSMWorld::ColumnBase::Display_Integer)); + new RefIdColumn (Columns::ColumnId_Mana, CSMWorld::ColumnBase::Display_Integer)); mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_NpcFatigue, CSMWorld::ColumnBase::Display_Integer)); + new RefIdColumn (Columns::ColumnId_Fatigue, CSMWorld::ColumnBase::Display_Integer)); mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_NpcDisposition, CSMWorld::ColumnBase::Display_Integer)); mColumns.back().addColumn( @@ -479,7 +479,7 @@ CSMWorld::RefIdCollection::RefIdCollection() mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_NpcRank, CSMWorld::ColumnBase::Display_Integer)); mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_NpcGold, CSMWorld::ColumnBase::Display_Integer)); + new RefIdColumn (Columns::ColumnId_Gold, CSMWorld::ColumnBase::Display_Integer)); mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_NpcPersistence, CSMWorld::ColumnBase::Display_Boolean)); diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 60219d319..ca4ad2d00 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -104,7 +104,6 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) { CSMWorld::ColumnBase::Display_AiPackageType, CSMWorld::Columns::ColumnId_AiPackageType, false }, { CSMWorld::ColumnBase::Display_InfoCondFunc, CSMWorld::Columns::ColumnId_InfoCondFunc, false }, { CSMWorld::ColumnBase::Display_InfoCondComp, CSMWorld::Columns::ColumnId_InfoCondComp, false }, - { CSMWorld::ColumnBase::Display_RaceSkill, CSMWorld::Columns::ColumnId_RaceSkill, true }, }; for (std::size_t i=0; i Date: Sat, 12 Sep 2015 10:00:23 +1000 Subject: [PATCH 2154/3725] Add missing fields for editing creatures. - Should resolve resolve bugs #2878 (level), #2901 (gold) and #2889 (health). - Moved Soul, Combat, Magic and Stealth editing to dialogue only (to be consistent with editing NPCs) --- apps/opencs/model/world/columns.cpp | 7 + apps/opencs/model/world/columns.hpp | 7 + apps/opencs/model/world/refidadapterimp.cpp | 313 ++++++++++++++++++-- apps/opencs/model/world/refidadapterimp.hpp | 98 +++++- apps/opencs/model/world/refidcollection.cpp | 64 +++- 5 files changed, 453 insertions(+), 36 deletions(-) diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 9f39be5f3..44ec9d384 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -311,6 +311,13 @@ namespace CSMWorld { ColumnId_FileDescription, "File Description" }, { ColumnId_Author, "Author" }, + { ColumnId_CreatureAttributes, "Creature Attributes" }, + { ColumnId_AttributeValue, "Attrib Value" }, + { ColumnId_CreatureAttack, "Creature Attack" }, + { ColumnId_MinAttack, "Min Attack" }, + { ColumnId_MaxAttack, "Max Attack" }, + { ColumnId_CreatureMisc, "Creature Misc" }, + { ColumnId_UseValue1, "Use value 1" }, { ColumnId_UseValue2, "Use value 2" }, { ColumnId_UseValue3, "Use value 3" }, diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 5deaf65cb..981599e53 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -309,6 +309,13 @@ namespace CSMWorld ColumnId_MinMagnitude = 278, ColumnId_MaxMagnitude = 279, + ColumnId_CreatureAttributes = 280, + ColumnId_AttributeValue = 281, + ColumnId_CreatureAttack = 282, + ColumnId_MinAttack = 283, + ColumnId_MaxAttack = 284, + ColumnId_CreatureMisc = 285, + // Allocated to a separate value range, so we don't get a collision should we ever need // to extend the number of use values. ColumnId_UseValue1 = 0x10000, diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index 6a881d0af..da0cc0760 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -296,12 +296,11 @@ void CSMWorld::ContainerRefIdAdapter::setData (const RefIdColumn *column, RefIdD CSMWorld::CreatureColumns::CreatureColumns (const ActorColumns& actorColumns) : ActorColumns (actorColumns), mType(NULL), - mSoul(NULL), mScale(NULL), mOriginal(NULL), - mCombat(NULL), - mMagic(NULL), - mStealth(NULL) + mAttributes(NULL), + mAttacks(NULL), + mMisc(NULL) {} CSMWorld::CreatureRefIdAdapter::CreatureRefIdAdapter (const CreatureColumns& columns) @@ -317,23 +316,20 @@ QVariant CSMWorld::CreatureRefIdAdapter::getData (const RefIdColumn *column, con if (column==mColumns.mType) return record.get().mData.mType; - if (column==mColumns.mSoul) - return record.get().mData.mSoul; - if (column==mColumns.mScale) return record.get().mScale; if (column==mColumns.mOriginal) return QString::fromUtf8 (record.get().mOriginal.c_str()); - if (column==mColumns.mCombat) - return static_cast (record.get().mData.mCombat); + if (column==mColumns.mAttributes) + return true; // Required to show nested tables in dialogue subview - if (column==mColumns.mMagic) - return static_cast (record.get().mData.mMagic); + if (column==mColumns.mAttacks) + return true; // Required to show nested tables in dialogue subview - if (column==mColumns.mStealth) - return static_cast (record.get().mData.mStealth); + if (column==mColumns.mMisc) + return true; // Required to show nested items in dialogue subview std::map::const_iterator iter = mColumns.mFlags.find (column); @@ -354,18 +350,10 @@ void CSMWorld::CreatureRefIdAdapter::setData (const RefIdColumn *column, RefIdDa if (column==mColumns.mType) creature.mData.mType = value.toInt(); - else if (column==mColumns.mSoul) - creature.mData.mSoul = value.toInt(); else if (column==mColumns.mScale) creature.mScale = value.toFloat(); else if (column==mColumns.mOriginal) creature.mOriginal = value.toString().toUtf8().constData(); - else if (column==mColumns.mCombat) - creature.mData.mCombat = value.toInt(); - else if (column==mColumns.mMagic) - creature.mData.mMagic = value.toInt(); - else if (column==mColumns.mStealth) - creature.mData.mStealth = value.toInt(); else { std::map::const_iterator iter = @@ -964,6 +952,289 @@ int CSMWorld::NpcMiscRefIdAdapter::getNestedRowsCount(const RefIdColumn *column, return 1; // fixed at size 1 } +CSMWorld::CreatureAttributesRefIdAdapter::CreatureAttributesRefIdAdapter() +{} + +void CSMWorld::CreatureAttributesRefIdAdapter::addNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int position) const +{ + // Do nothing, this table cannot be changed by the user +} + +void CSMWorld::CreatureAttributesRefIdAdapter::removeNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int rowToRemove) const +{ + // Do nothing, this table cannot be changed by the user +} + +void CSMWorld::CreatureAttributesRefIdAdapter::setNestedTable (const RefIdColumn* column, + RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const +{ + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Creature))); + ESM::Creature creature = record.get(); + + // store the whole struct + creature.mData = + static_cast > &>(nestedTable).mNestedTable.at(0); + + record.setModified (creature); +} + +CSMWorld::NestedTableWrapperBase* CSMWorld::CreatureAttributesRefIdAdapter::nestedTable (const RefIdColumn* column, + const RefIdData& data, int index) const +{ + const Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Creature))); + + // return the whole struct + std::vector wrap; + wrap.push_back(record.get().mData); + // deleted by dtor of NestedTableStoring + return new NestedTableWrapper >(wrap); +} + +QVariant CSMWorld::CreatureAttributesRefIdAdapter::getNestedData (const RefIdColumn *column, + const RefIdData& data, int index, int subRowIndex, int subColIndex) const +{ + const Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Creature))); + + const ESM::Creature creature = record.get(); + + if (subColIndex == 0) + return subRowIndex; + else if (subColIndex == 1) + switch (subRowIndex) + { + case 0: return creature.mData.mStrength; + case 1: return creature.mData.mIntelligence; + case 2: return creature.mData.mWillpower; + case 3: return creature.mData.mAgility; + case 4: return creature.mData.mSpeed; + case 5: return creature.mData.mEndurance; + case 6: return creature.mData.mPersonality; + case 7: return creature.mData.mLuck; + default: return QVariant(); // throw an exception here? + } + else + return QVariant(); // throw an exception here? +} + +void CSMWorld::CreatureAttributesRefIdAdapter::setNestedData (const RefIdColumn *column, + RefIdData& data, int row, const QVariant& value, int subRowIndex, int subColIndex) const +{ + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (row, UniversalId::Type_Creature))); + ESM::Creature creature = record.get(); + + if (subColIndex == 1) + switch(subRowIndex) + { + case 0: creature.mData.mStrength = value.toInt(); break; + case 1: creature.mData.mIntelligence = value.toInt(); break; + case 2: creature.mData.mWillpower = value.toInt(); break; + case 3: creature.mData.mAgility = value.toInt(); break; + case 4: creature.mData.mSpeed = value.toInt(); break; + case 5: creature.mData.mEndurance = value.toInt(); break; + case 6: creature.mData.mPersonality = value.toInt(); break; + case 7: creature.mData.mLuck = value.toInt(); break; + default: return; // throw an exception here? + } + else + return; // throw an exception here? + + record.setModified (creature); +} + +int CSMWorld::CreatureAttributesRefIdAdapter::getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const +{ + return 2; +} + +int CSMWorld::CreatureAttributesRefIdAdapter::getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const +{ + // There are 8 attributes + return 8; +} + +CSMWorld::CreatureAttackRefIdAdapter::CreatureAttackRefIdAdapter() +{} + +void CSMWorld::CreatureAttackRefIdAdapter::addNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int position) const +{ + // Do nothing, this table cannot be changed by the user +} + +void CSMWorld::CreatureAttackRefIdAdapter::removeNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int rowToRemove) const +{ + // Do nothing, this table cannot be changed by the user +} + +void CSMWorld::CreatureAttackRefIdAdapter::setNestedTable (const RefIdColumn* column, + RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const +{ + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Creature))); + ESM::Creature creature = record.get(); + + // store the whole struct + creature.mData = + static_cast > &>(nestedTable).mNestedTable.at(0); + + record.setModified (creature); +} + +CSMWorld::NestedTableWrapperBase* CSMWorld::CreatureAttackRefIdAdapter::nestedTable (const RefIdColumn* column, + const RefIdData& data, int index) const +{ + const Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Creature))); + + // return the whole struct + std::vector wrap; + wrap.push_back(record.get().mData); + // deleted by dtor of NestedTableStoring + return new NestedTableWrapper >(wrap); +} + +QVariant CSMWorld::CreatureAttackRefIdAdapter::getNestedData (const RefIdColumn *column, + const RefIdData& data, int index, int subRowIndex, int subColIndex) const +{ + const Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Creature))); + + const ESM::Creature creature = record.get(); + + if (subRowIndex < 0 || subRowIndex > 2 || subColIndex < 0 || subColIndex > 2) + throw std::runtime_error ("index out of range"); + + if (subColIndex == 0) + return subRowIndex + 1; + else if (subColIndex < 3) // 1 or 2 + return creature.mData.mAttack[(subRowIndex * 2) + (subColIndex - 1)]; + else + return QVariant(); // throw an exception here? +} + +void CSMWorld::CreatureAttackRefIdAdapter::setNestedData (const RefIdColumn *column, + RefIdData& data, int row, const QVariant& value, int subRowIndex, int subColIndex) const +{ + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (row, UniversalId::Type_Creature))); + ESM::Creature creature = record.get(); + + if (subRowIndex < 0 || subRowIndex > 2) + throw std::runtime_error ("index out of range"); + + if (subColIndex == 1 || subColIndex == 2) + creature.mData.mAttack[(subRowIndex * 2) + (subColIndex - 1)] = value.toInt(); + else + return; // throw an exception here? + + record.setModified (creature); +} + +int CSMWorld::CreatureAttackRefIdAdapter::getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const +{ + return 3; +} + +int CSMWorld::CreatureAttackRefIdAdapter::getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const +{ + // There are 3 attacks + return 3; +} + +CSMWorld::CreatureMiscRefIdAdapter::CreatureMiscRefIdAdapter() +{} + +CSMWorld::CreatureMiscRefIdAdapter::~CreatureMiscRefIdAdapter() +{} + +void CSMWorld::CreatureMiscRefIdAdapter::addNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int position) const +{ + throw std::logic_error ("cannot add a row to a fixed table"); +} + +void CSMWorld::CreatureMiscRefIdAdapter::removeNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int rowToRemove) const +{ + throw std::logic_error ("cannot remove a row to a fixed table"); +} + +void CSMWorld::CreatureMiscRefIdAdapter::setNestedTable (const RefIdColumn* column, + RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const +{ + throw std::logic_error ("table operation not supported"); +} + +CSMWorld::NestedTableWrapperBase* CSMWorld::CreatureMiscRefIdAdapter::nestedTable (const RefIdColumn* column, + const RefIdData& data, int index) const +{ + throw std::logic_error ("table operation not supported"); +} + +QVariant CSMWorld::CreatureMiscRefIdAdapter::getNestedData (const RefIdColumn *column, + const RefIdData& data, int index, int subRowIndex, int subColIndex) const +{ + const Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Creature))); + + const ESM::Creature creature = record.get(); + + switch (subColIndex) + { + case 0: return creature.mData.mLevel; + case 1: return creature.mData.mHealth; + case 2: return creature.mData.mMana; + case 3: return creature.mData.mFatigue; + case 4: return creature.mData.mSoul; + case 5: return creature.mData.mCombat; + case 6: return creature.mData.mMagic; + case 7: return creature.mData.mStealth; + case 8: return creature.mData.mGold; + default: return QVariant(); // throw an exception here? + } +} + +void CSMWorld::CreatureMiscRefIdAdapter::setNestedData (const RefIdColumn *column, + RefIdData& data, int row, const QVariant& value, int subRowIndex, int subColIndex) const +{ + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (row, UniversalId::Type_Creature))); + ESM::Creature creature = record.get(); + + switch(subColIndex) + { + case 0: creature.mData.mLevel = value.toInt(); break; + case 1: creature.mData.mHealth = value.toInt(); break; + case 2: creature.mData.mMana = value.toInt(); break; + case 3: creature.mData.mFatigue = value.toInt(); break; + case 4: creature.mData.mSoul = value.toInt(); break; + case 5: creature.mData.mCombat = value.toInt(); break; + case 6: creature.mData.mMagic = value.toInt(); break; + case 7: creature.mData.mStealth = value.toInt(); break; + case 8: creature.mData.mGold = value.toInt(); break; + default: return; // throw an exception here? + } + + record.setModified (creature); +} + +int CSMWorld::CreatureMiscRefIdAdapter::getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const +{ + return 9; // Level, Health, Mana, Fatigue, Soul, Combat, Magic, Steath, Gold +} + +int CSMWorld::CreatureMiscRefIdAdapter::getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const +{ + return 1; // fixed at size 1 +} + CSMWorld::WeaponColumns::WeaponColumns (const EnchantableColumns& columns) : EnchantableColumns (columns) {} diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index 5ceb3325a..41f254355 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -696,12 +696,11 @@ namespace CSMWorld { std::map mFlags; const RefIdColumn *mType; - const RefIdColumn *mSoul; const RefIdColumn *mScale; const RefIdColumn *mOriginal; - const RefIdColumn *mCombat; - const RefIdColumn *mMagic; - const RefIdColumn *mStealth; + const RefIdColumn *mAttributes; + const RefIdColumn *mAttack; + const RefIdColumn *mMisc; CreatureColumns (const ActorColumns& actorColumns); }; @@ -938,6 +937,97 @@ namespace CSMWorld virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const; }; + class CreatureAttributesRefIdAdapter : public NestedRefIdAdapterBase + { + public: + + CreatureAttributesRefIdAdapter (); + + virtual void addNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int position) const; + + virtual void removeNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int rowToRemove) const; + + virtual void setNestedTable (const RefIdColumn* column, + RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const; + + virtual NestedTableWrapperBase* nestedTable (const RefIdColumn* column, + const RefIdData& data, int index) const; + + virtual QVariant getNestedData (const RefIdColumn *column, + const RefIdData& data, int index, int subRowIndex, int subColIndex) const; + + virtual void setNestedData (const RefIdColumn *column, + RefIdData& data, int row, const QVariant& value, int subRowIndex, int subColIndex) const; + + virtual int getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const; + + virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const; + }; + + class CreatureAttackRefIdAdapter : public NestedRefIdAdapterBase + { + public: + + CreatureAttackRefIdAdapter (); + + virtual void addNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int position) const; + + virtual void removeNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int rowToRemove) const; + + virtual void setNestedTable (const RefIdColumn* column, + RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const; + + virtual NestedTableWrapperBase* nestedTable (const RefIdColumn* column, + const RefIdData& data, int index) const; + + virtual QVariant getNestedData (const RefIdColumn *column, + const RefIdData& data, int index, int subRowIndex, int subColIndex) const; + + virtual void setNestedData (const RefIdColumn *column, + RefIdData& data, int row, const QVariant& value, int subRowIndex, int subColIndex) const; + + virtual int getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const; + + virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const; + }; + + class CreatureMiscRefIdAdapter : public NestedRefIdAdapterBase + { + CreatureMiscRefIdAdapter (const CreatureMiscRefIdAdapter&); + CreatureMiscRefIdAdapter& operator= (const CreatureMiscRefIdAdapter&); + + public: + + CreatureMiscRefIdAdapter (); + virtual ~CreatureMiscRefIdAdapter(); + + virtual void addNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int position) const; + + virtual void removeNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int rowToRemove) const; + + virtual void setNestedTable (const RefIdColumn* column, + RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const; + + virtual NestedTableWrapperBase* nestedTable (const RefIdColumn* column, + const RefIdData& data, int index) const; + + virtual QVariant getNestedData (const RefIdColumn *column, + const RefIdData& data, int index, int subRowIndex, int subColIndex) const; + + virtual void setNestedData (const RefIdColumn *column, + RefIdData& data, int row, const QVariant& value, int subRowIndex, int subColIndex) const; + + virtual int getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const; + + virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const; + }; + template class EffectsListAdapter; diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index b20e12fef..f8c9e28fe 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -297,21 +297,10 @@ CSMWorld::RefIdCollection::RefIdCollection() mColumns.push_back (RefIdColumn (Columns::ColumnId_CreatureType, ColumnBase::Display_CreatureType)); creatureColumns.mType = &mColumns.back(); - mColumns.push_back (RefIdColumn (Columns::ColumnId_SoulPoints, ColumnBase::Display_Integer)); - creatureColumns.mSoul = &mColumns.back(); mColumns.push_back (RefIdColumn (Columns::ColumnId_Scale, ColumnBase::Display_Float)); creatureColumns.mScale = &mColumns.back(); mColumns.push_back (RefIdColumn (Columns::ColumnId_OriginalCreature, ColumnBase::Display_Creature)); creatureColumns.mOriginal = &mColumns.back(); - mColumns.push_back ( - RefIdColumn (Columns::ColumnId_CombatState, ColumnBase::Display_Integer)); - creatureColumns.mCombat = &mColumns.back(); - mColumns.push_back ( - RefIdColumn (Columns::ColumnId_MagicState, ColumnBase::Display_Integer)); - creatureColumns.mMagic = &mColumns.back(); - mColumns.push_back ( - RefIdColumn (Columns::ColumnId_StealthState, ColumnBase::Display_Integer)); - creatureColumns.mStealth = &mColumns.back(); static const struct { @@ -350,6 +339,59 @@ CSMWorld::RefIdCollection::RefIdCollection() creatureColumns.mFlags.insert (std::make_pair (respawn, ESM::Creature::Respawn)); + // Nested table + mColumns.push_back(RefIdColumn (Columns::ColumnId_CreatureAttributes, + ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue)); + creatureColumns.mAttributes = &mColumns.back(); + std::map creaAttrMap; + creaAttrMap.insert(std::make_pair(UniversalId::Type_Creature, new CreatureAttributesRefIdAdapter())); + mNestedAdapters.push_back (std::make_pair(&mColumns.back(), creaAttrMap)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_Attribute, CSMWorld::ColumnBase::Display_Attribute, false, false)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_AttributeValue, CSMWorld::ColumnBase::Display_Integer)); + + // Nested table + mColumns.push_back(RefIdColumn (Columns::ColumnId_CreatureAttack, + ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue)); + creatureColumns.mAttacks = &mColumns.back(); + std::map attackMap; + attackMap.insert(std::make_pair(UniversalId::Type_Creature, new CreatureAttackRefIdAdapter())); + mNestedAdapters.push_back (std::make_pair(&mColumns.back(), attackMap)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_CreatureAttack, CSMWorld::ColumnBase::Display_Integer, false, false)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_MinAttack, CSMWorld::ColumnBase::Display_Integer)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_MaxAttack, CSMWorld::ColumnBase::Display_Integer)); + + // Nested list + mColumns.push_back(RefIdColumn (Columns::ColumnId_CreatureMisc, + ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue | ColumnBase::Flag_Dialogue_List)); + creatureColumns.mMisc = &mColumns.back(); + std::map creaMiscMap; + creaMiscMap.insert(std::make_pair(UniversalId::Type_Creature, new CreatureMiscRefIdAdapter())); + mNestedAdapters.push_back (std::make_pair(&mColumns.back(), creaMiscMap)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_Level, CSMWorld::ColumnBase::Display_Integer, + ColumnBase::Flag_Dialogue | ColumnBase::Flag_Dialogue_Refresh)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_Health, CSMWorld::ColumnBase::Display_Integer)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_Mana, CSMWorld::ColumnBase::Display_Integer)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_Fatigue, CSMWorld::ColumnBase::Display_Integer)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_SoulPoints, CSMWorld::ColumnBase::Display_Integer)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_CombatState, CSMWorld::ColumnBase::Display_Integer)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_MagicState, CSMWorld::ColumnBase::Display_Integer)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_StealthState, CSMWorld::ColumnBase::Display_Integer)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_Gold, CSMWorld::ColumnBase::Display_Integer)); + mColumns.push_back (RefIdColumn (Columns::ColumnId_OpenSound, ColumnBase::Display_Sound)); const RefIdColumn *openSound = &mColumns.back(); From 45aee1b5088cb110e06540356670b806887f7372 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 12 Sep 2015 10:15:32 +1000 Subject: [PATCH 2155/3725] Remove AI flag from the UI and instead auto-detect whether to save AIDT records. Should resolve bug #2879. --- apps/opencs/model/world/columns.cpp | 1 - apps/opencs/model/world/columns.hpp | 2 +- apps/opencs/model/world/refidadapterimp.hpp | 8 +------- apps/opencs/model/world/refidcollection.cpp | 2 -- components/esm/loadcrea.cpp | 7 ++++++- components/esm/loadnpc.cpp | 7 ++++++- 6 files changed, 14 insertions(+), 13 deletions(-) diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 44ec9d384..2e0a697a5 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -71,7 +71,6 @@ namespace CSMWorld { ColumnId_Weight, "Weight" }, { ColumnId_EnchantmentPoints, "Enchantment Points" }, { ColumnId_Quality, "Quality" }, - { ColumnId_Ai, "AI" }, { ColumnId_AiHello, "AI Hello" }, { ColumnId_AiFlee, "AI Flee" }, { ColumnId_AiFight, "AI Fight" }, diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 981599e53..fb25004ec 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -65,7 +65,7 @@ namespace CSMWorld ColumnId_Weight = 50, ColumnId_EnchantmentPoints = 51, ColumnId_Quality = 52, - ColumnId_Ai = 53, + // unused ColumnId_AiHello = 54, ColumnId_AiFlee = 55, ColumnId_AiFight = 56, diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index 41f254355..ae446599e 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -479,7 +479,6 @@ namespace CSMWorld struct ActorColumns : public NameColumns { - const RefIdColumn *mHasAi; const RefIdColumn *mHello; const RefIdColumn *mFlee; const RefIdColumn *mFight; @@ -524,9 +523,6 @@ namespace CSMWorld const Record& record = static_cast&> ( data.getRecord (RefIdData::LocalIndex (index, BaseRefIdAdapter::getType()))); - if (column==mActors.mHasAi) - return record.get().mHasAI!=0; - if (column==mActors.mHello) return record.get().mAiData.mHello; @@ -568,9 +564,7 @@ namespace CSMWorld data.getRecord (RefIdData::LocalIndex (index, BaseRefIdAdapter::getType()))); RecordT record2 = record.get(); - if (column==mActors.mHasAi) - record2.mHasAI = value.toInt(); - else if (column==mActors.mHello) + if (column==mActors.mHello) record2.mAiData.mHello = value.toInt(); else if (column==mActors.mFlee) record2.mAiData.mFlee = value.toInt(); diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index f8c9e28fe..d7b7cedfa 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -113,8 +113,6 @@ CSMWorld::RefIdCollection::RefIdCollection() ActorColumns actorsColumns (nameColumns); - mColumns.push_back (RefIdColumn (Columns::ColumnId_Ai, ColumnBase::Display_Boolean)); - actorsColumns.mHasAi = &mColumns.back(); mColumns.push_back (RefIdColumn (Columns::ColumnId_AiHello, ColumnBase::Display_Integer)); actorsColumns.mHello = &mColumns.back(); mColumns.push_back (RefIdColumn (Columns::ColumnId_AiFlee, ColumnBase::Display_Integer)); diff --git a/components/esm/loadcrea.cpp b/components/esm/loadcrea.cpp index 50c47349c..8c4f49e45 100644 --- a/components/esm/loadcrea.cpp +++ b/components/esm/loadcrea.cpp @@ -96,7 +96,12 @@ namespace ESM { mInventory.save(esm); mSpells.save(esm); - if (mHasAI) { + if (mAiData.mHello != 0 + || mAiData.mFight != 0 + || mAiData.mFlee != 0 + || mAiData.mAlarm != 0 + || mAiData.mServices != 0) + { esm.writeHNT("AIDT", mAiData, sizeof(mAiData)); } mTransport.save(esm); diff --git a/components/esm/loadnpc.cpp b/components/esm/loadnpc.cpp index 44d298785..67a437176 100644 --- a/components/esm/loadnpc.cpp +++ b/components/esm/loadnpc.cpp @@ -121,7 +121,12 @@ namespace ESM mInventory.save(esm); mSpells.save(esm); - if (mHasAI) { + if (mAiData.mHello != 0 + || mAiData.mFight != 0 + || mAiData.mFlee != 0 + || mAiData.mAlarm != 0 + || mAiData.mServices != 0) + { esm.writeHNT("AIDT", mAiData, sizeof(mAiData)); } From 192f01e3ac5db4f0d1d9d78c2a419b274f307bb1 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 12 Sep 2015 10:17:14 +1000 Subject: [PATCH 2156/3725] Set default creature scale to 1. Partially resolves bug #2880. (no creature verifier yet) --- components/esm/loadcrea.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esm/loadcrea.cpp b/components/esm/loadcrea.cpp index 8c4f49e45..fb235e6b3 100644 --- a/components/esm/loadcrea.cpp +++ b/components/esm/loadcrea.cpp @@ -120,7 +120,7 @@ namespace ESM { for (int i=0; i<6; ++i) mData.mAttack[i] = 0; mData.mGold = 0; mFlags = 0; - mScale = 0; + mScale = 1.f; mModel.clear(); mName.clear(); mScript.clear(); From 1365b8edd1f0a20e97ccb9a30cd74a6dc97c44bd Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 12 Sep 2015 11:18:07 +1000 Subject: [PATCH 2157/3725] Fix typo. --- apps/opencs/model/world/refidadapterimp.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index ae446599e..53da63806 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -693,7 +693,7 @@ namespace CSMWorld const RefIdColumn *mScale; const RefIdColumn *mOriginal; const RefIdColumn *mAttributes; - const RefIdColumn *mAttack; + const RefIdColumn *mAttacks; const RefIdColumn *mMisc; CreatureColumns (const ActorColumns& actorColumns); From 8e2fe1985d8a794aaf70173c71e7c63cd4ac3f1a Mon Sep 17 00:00:00 2001 From: dteviot Date: Sat, 12 Sep 2015 14:17:46 +1200 Subject: [PATCH 2158/3725] Fixed errors pointed out by Zini. 1. Removed "Actor" from name of function isActorNearInactiveCell(). 2. Corrected case of CoordinateConverter member function names. --- apps/openmw/mwmechanics/aipackage.cpp | 6 +++--- apps/openmw/mwmechanics/aipackage.hpp | 2 +- apps/openmw/mwmechanics/aiwander.cpp | 4 ++-- apps/openmw/mwmechanics/coordinateconverter.cpp | 8 ++++---- apps/openmw/mwmechanics/coordinateconverter.hpp | 8 ++++---- apps/openmw/mwmechanics/pathfinding.cpp | 8 ++++---- apps/openmw/mwrender/pathgrid.cpp | 2 +- 7 files changed, 19 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index c4091c63e..1af0f1c5a 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -36,7 +36,7 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, ESM::Pathgrid::Po //... At current time, this test is unnecessary. AI shuts down when actor is more than 7168 //... units from player, and exterior cells are 8192 units long and wide. //... But AI processing distance may increase in the future. - if (isActorNearInactiveCell(pos)) + if (isNearInactiveCell(pos)) { actor.getClass().getMovementSettings(actor).mPosition[1] = 0; return false; @@ -114,14 +114,14 @@ bool MWMechanics::AiPackage::isTargetMagicallyHidden(const MWWorld::Ptr& target) || (magicEffects.get(ESM::MagicEffect::Chameleon).getMagnitude() > 75); } -bool MWMechanics::AiPackage::isActorNearInactiveCell(const ESM::Position& actorPos) +bool MWMechanics::AiPackage::isNearInactiveCell(const ESM::Position& actorPos) { const ESM::Cell* playerCell(getPlayer().getCell()->getCell()); if (playerCell->isExterior()) { // get actor's distance from origin of center cell osg::Vec3f actorOffset(actorPos.asVec3()); - CoordinateConverter(playerCell).ToLocal(actorOffset); + CoordinateConverter(playerCell).toLocal(actorOffset); // currently assumes 3 x 3 grid for exterior cells, with player at center cell. // ToDo: (Maybe) use "exterior cell load distance" setting to get count of actual active cells diff --git a/apps/openmw/mwmechanics/aipackage.hpp b/apps/openmw/mwmechanics/aipackage.hpp index befd159bf..e16d66dbe 100644 --- a/apps/openmw/mwmechanics/aipackage.hpp +++ b/apps/openmw/mwmechanics/aipackage.hpp @@ -88,7 +88,7 @@ namespace MWMechanics private: void evadeObstacles(const MWWorld::Ptr& actor, float duration, ESM::Position& pos); - bool isActorNearInactiveCell(const ESM::Position& actorPos); + bool isNearInactiveCell(const ESM::Position& actorPos); }; } diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index b789c4428..a3fdc69cc 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -588,7 +588,7 @@ namespace MWMechanics void AiWander::ToWorldCoordinates(ESM::Pathgrid::Point& point, const ESM::Cell * cell) { - CoordinateConverter(cell).ToWorld(point); + CoordinateConverter(cell).toWorld(point); } void AiWander::trimAllowedNodes(std::vector& nodes, @@ -746,7 +746,7 @@ namespace MWMechanics { // get NPC's position in local (i.e. cell) co-ordinates osg::Vec3f npcPos(mInitialActorPosition); - CoordinateConverter(cell).ToLocal(npcPos); + CoordinateConverter(cell).toLocal(npcPos); // mAllowedNodes for this actor with pathgrid point indexes based on mDistance // NOTE: mPoints and mAllowedNodes are in local co-ordinates diff --git a/apps/openmw/mwmechanics/coordinateconverter.cpp b/apps/openmw/mwmechanics/coordinateconverter.cpp index 583ac41c5..0a2d99f92 100644 --- a/apps/openmw/mwmechanics/coordinateconverter.cpp +++ b/apps/openmw/mwmechanics/coordinateconverter.cpp @@ -15,25 +15,25 @@ namespace MWMechanics } } - void CoordinateConverter::ToWorld(ESM::Pathgrid::Point& point) + void CoordinateConverter::toWorld(ESM::Pathgrid::Point& point) { point.mX += mCellX; point.mY += mCellY; } - void CoordinateConverter::ToWorld(osg::Vec3f& point) + void CoordinateConverter::toWorld(osg::Vec3f& point) { point.x() += static_cast(mCellX); point.y() += static_cast(mCellY); } - void CoordinateConverter::ToLocal(osg::Vec3f& point) + void CoordinateConverter::toLocal(osg::Vec3f& point) { point.x() -= static_cast(mCellX); point.y() -= static_cast(mCellY); } - osg::Vec3f CoordinateConverter::ToLocalVec3(const ESM::Pathgrid::Point& point) + osg::Vec3f CoordinateConverter::toLocalVec3(const ESM::Pathgrid::Point& point) { return osg::Vec3f( static_cast(point.mX - mCellX), diff --git a/apps/openmw/mwmechanics/coordinateconverter.hpp b/apps/openmw/mwmechanics/coordinateconverter.hpp index 2c4d3d3ba..cd855e84a 100644 --- a/apps/openmw/mwmechanics/coordinateconverter.hpp +++ b/apps/openmw/mwmechanics/coordinateconverter.hpp @@ -18,15 +18,15 @@ namespace MWMechanics CoordinateConverter(const ESM::Cell* cell); /// in-place conversion from local to world - void ToWorld(ESM::Pathgrid::Point& point); + void toWorld(ESM::Pathgrid::Point& point); /// in-place conversion from local to world - void ToWorld(osg::Vec3f& point); + void toWorld(osg::Vec3f& point); /// in-place conversion from world to local - void ToLocal(osg::Vec3f& point); + void toLocal(osg::Vec3f& point); - osg::Vec3f ToLocalVec3(const ESM::Pathgrid::Point& point); + osg::Vec3f toLocalVec3(const ESM::Pathgrid::Point& point); private: int mCellX; diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index daab32136..f26d3e109 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -207,10 +207,10 @@ namespace MWMechanics // outside an area enclosed by walls, but there is a pathgrid // point right behind the wall that is closer than any pathgrid // point outside the wall - osg::Vec3f startPointInLocalCoords(converter.ToLocalVec3(startPoint)); + osg::Vec3f startPointInLocalCoords(converter.toLocalVec3(startPoint)); int startNode = getClosestPoint(mPathgrid, startPointInLocalCoords); - osg::Vec3f endPointInLocalCoords(converter.ToLocalVec3(endPoint)); + osg::Vec3f endPointInLocalCoords(converter.toLocalVec3(endPoint)); std::pair endNode = getClosestReachablePoint(mPathgrid, cell, endPointInLocalCoords, startNode); @@ -223,7 +223,7 @@ namespace MWMechanics if(startNode == endNode.first) { ESM::Pathgrid::Point temp(mPathgrid->mPoints[startNode]); - converter.ToWorld(temp); + converter.toWorld(temp); mPath.push_back(temp); } else @@ -233,7 +233,7 @@ namespace MWMechanics // convert supplied path to world co-ordinates for (std::list::iterator iter(mPath.begin()); iter != mPath.end(); ++iter) { - converter.ToWorld(*iter); + converter.toWorld(*iter); } } diff --git a/apps/openmw/mwrender/pathgrid.cpp b/apps/openmw/mwrender/pathgrid.cpp index bd22446de..ae8bda1fb 100644 --- a/apps/openmw/mwrender/pathgrid.cpp +++ b/apps/openmw/mwrender/pathgrid.cpp @@ -208,7 +208,7 @@ void Pathgrid::enableCellPathgrid(const MWWorld::CellStore *store) if (!pathgrid) return; osg::Vec3f cellPathGridPos(0, 0, 0); - MWMechanics::CoordinateConverter(store->getCell()).ToWorld(cellPathGridPos); + MWMechanics::CoordinateConverter(store->getCell()).toWorld(cellPathGridPos); osg::ref_ptr cellPathGrid = new osg::PositionAttitudeTransform; cellPathGrid->setPosition(cellPathGridPos); From 0feae19140f6c869fc025772432183a00059e570 Mon Sep 17 00:00:00 2001 From: dteviot Date: Mon, 14 Sep 2015 19:57:22 +1200 Subject: [PATCH 2159/3725] AiCombat use evadeObstacles() from AiPackage. --- apps/openmw/mwmechanics/aicombat.cpp | 7 +++---- apps/openmw/mwmechanics/aicombat.hpp | 2 +- apps/openmw/mwmechanics/aipackage.cpp | 2 +- apps/openmw/mwmechanics/aipackage.hpp | 3 ++- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 5ea3ba6a3..58f74a87f 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -200,7 +200,7 @@ namespace MWMechanics //Update every frame storage.updateCombatMove(duration); - updateActorsMovement(actor, storage.mMovement); + updateActorsMovement(actor, duration, storage.mMovement); storage.updateAttack(characterController); storage.mActionCooldown -= duration; @@ -494,7 +494,7 @@ namespace MWMechanics return false; } - void AiCombat::updateActorsMovement(const MWWorld::Ptr& actor, MWMechanics::Movement& desiredMovement) + void AiCombat::updateActorsMovement(const MWWorld::Ptr& actor, float duration, MWMechanics::Movement& desiredMovement) { MWMechanics::Movement& actorMovementSettings = actor.getClass().getMovementSettings(actor); if (mPathFinder.isPathConstructed()) @@ -506,8 +506,7 @@ namespace MWMechanics } else { - zTurn(actor, mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1])); - actorMovementSettings.mPosition[1] = 1; + evadeObstacles(actor, duration, pos); } } else diff --git a/apps/openmw/mwmechanics/aicombat.hpp b/apps/openmw/mwmechanics/aicombat.hpp index 73d0254f3..93d630529 100644 --- a/apps/openmw/mwmechanics/aicombat.hpp +++ b/apps/openmw/mwmechanics/aicombat.hpp @@ -65,7 +65,7 @@ namespace MWMechanics AiCombatStorage& storage, MWWorld::Ptr target); /// Transfer desired movement (from AiCombatStorage) to Actor - void updateActorsMovement(const MWWorld::Ptr& actor, MWMechanics::Movement& movement); + void updateActorsMovement(const MWWorld::Ptr& actor, float duration, MWMechanics::Movement& movement); void rotateActorOnAxis(const MWWorld::Ptr& actor, int axis, MWMechanics::Movement& actorMovementSettings, MWMechanics::Movement& desiredMovement); }; diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index 1af0f1c5a..1cd9649f7 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -77,7 +77,7 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, ESM::Pathgrid::Po return false; } -void MWMechanics::AiPackage::evadeObstacles(const MWWorld::Ptr& actor, float duration, ESM::Position& pos) +void MWMechanics::AiPackage::evadeObstacles(const MWWorld::Ptr& actor, float duration, const ESM::Position& pos) { zTurn(actor, mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1])); diff --git a/apps/openmw/mwmechanics/aipackage.hpp b/apps/openmw/mwmechanics/aipackage.hpp index e16d66dbe..3f227a49a 100644 --- a/apps/openmw/mwmechanics/aipackage.hpp +++ b/apps/openmw/mwmechanics/aipackage.hpp @@ -78,6 +78,8 @@ namespace MWMechanics virtual bool doesPathNeedRecalc(ESM::Pathgrid::Point dest, const ESM::Cell *cell); + void evadeObstacles(const MWWorld::Ptr& actor, float duration, const ESM::Position& pos); + // TODO: all this does not belong here, move into temporary storage PathFinder mPathFinder; ObstacleCheck mObstacleCheck; @@ -87,7 +89,6 @@ namespace MWMechanics ESM::Pathgrid::Point mPrevDest; private: - void evadeObstacles(const MWWorld::Ptr& actor, float duration, ESM::Position& pos); bool isNearInactiveCell(const ESM::Position& actorPos); }; From 6c6fc662ef80b5c99fc2b3723faa410edb37868c Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 14 Sep 2015 15:14:18 +0200 Subject: [PATCH 2160/3725] Add CONTRIBUTING.md --- CONTRIBUTING.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..879113a51 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,16 @@ +Description +=========== + +Your pull request description should include: + +* Summary of the changes made +* Reasoning / motivation behind the change +* What testing you have carried out to verify the change +* If applicable, a link back to the bug report or forum discussion that prompted the change + +Other notes +=========== + +* Separate your work into multiple pull requests whenever possible. As a rule of thumb, each feature and each bugfix should go into a separate PR, unless they are closely related or dependent upon each other. Small pull requests are easier to review, and are less likely to require further changes before we can merge them. A "mega" pull request with lots of unrelated commits in it is likely to get held up in review for a long time. +* Feel free to submit incomplete pull requests. Even if the work can not be merged yet, pull requests are a great place to collect early feedback. Just make sure to mark it as *[Incomplete]* or *[Do not merge yet]* in the title. +* If you plan on contributing often, please read the [Developer Reference](https://wiki.openmw.org/index.php?title=Developer_Reference) on our wiki, especially the [Policies and Standards](https://wiki.openmw.org/index.php?title=Policies_and_Standards). From 5fde9149594f6503c192f9d949d8f0bb3f3df5ba Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 14 Sep 2015 17:17:38 +0200 Subject: [PATCH 2161/3725] CONTRIBUTING.md: clarify "if applicable" --- CONTRIBUTING.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 879113a51..a9cd6a690 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,12 +1,12 @@ Description =========== -Your pull request description should include: +Your pull request description should include (if applicable): +* A link back to the bug report or forum discussion that prompted the change * Summary of the changes made * Reasoning / motivation behind the change * What testing you have carried out to verify the change -* If applicable, a link back to the bug report or forum discussion that prompted the change Other notes =========== From 2a981a5272e4d9bc513c3555c9dbcb0de2a31879 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 15 Sep 2015 13:58:07 +0200 Subject: [PATCH 2162/3725] make sure local variables are loaded when trying to access them from outside of a script (Fixes #2659) --- apps/openmw/mwscript/globalscripts.cpp | 11 +++---- apps/openmw/mwscript/locals.cpp | 39 +++++++++++++++++++++-- apps/openmw/mwscript/locals.hpp | 26 +++++++++++++-- apps/openmw/mwscript/scriptmanagerimp.cpp | 2 +- apps/openmw/mwworld/refdata.cpp | 23 ++++--------- apps/openmw/mwworld/refdata.hpp | 6 ++-- 6 files changed, 75 insertions(+), 32 deletions(-) diff --git a/apps/openmw/mwscript/globalscripts.cpp b/apps/openmw/mwscript/globalscripts.cpp index f339fa520..6074a12d0 100644 --- a/apps/openmw/mwscript/globalscripts.cpp +++ b/apps/openmw/mwscript/globalscripts.cpp @@ -198,13 +198,12 @@ namespace MWScript if (iter==mScripts.end()) { - if (const ESM::Script *script = mStore.get().find (name)) - { - GlobalScriptDesc desc; - desc.mLocals.configure (*script); + const ESM::Script *script = mStore.get().find (name); - iter = mScripts.insert (std::make_pair (name, desc)).first; - } + GlobalScriptDesc desc; + desc.mLocals.configure (*script); + + iter = mScripts.insert (std::make_pair (name2, desc)).first; } return iter->second.mLocals; diff --git a/apps/openmw/mwscript/locals.cpp b/apps/openmw/mwscript/locals.cpp index a18d0d5ae..ee93ea2e7 100644 --- a/apps/openmw/mwscript/locals.cpp +++ b/apps/openmw/mwscript/locals.cpp @@ -9,13 +9,32 @@ #include "../mwbase/environment.hpp" #include "../mwbase/scriptmanager.hpp" +#include "../mwbase/world.hpp" + +#include "../mwworld/esmstore.hpp" #include namespace MWScript { - void Locals::configure (const ESM::Script& script) + void Locals::ensure (const std::string& scriptName) { + if (!mInitialised) + { + const ESM::Script *script = MWBase::Environment::get().getWorld()->getStore(). + get().find (scriptName); + + configure (*script); + } + } + + Locals::Locals() : mInitialised (false) {} + + bool Locals::configure (const ESM::Script& script) + { + if (mInitialised) + return false; + const Compiler::Locals& locals = MWBase::Environment::get().getScriptManager()->getLocals (script.mId); @@ -25,6 +44,9 @@ namespace MWScript mLongs.resize (locals.get ('l').size(), 0); mFloats.clear(); mFloats.resize (locals.get ('f').size(), 0); + + mInitialised = true; + return true; } bool Locals::isEmpty() const @@ -36,6 +58,8 @@ namespace MWScript { try { + ensure (script); + const Compiler::Locals& locals = MWBase::Environment::get().getScriptManager()->getLocals(script); int index = locals.getIndex(var); @@ -49,6 +73,8 @@ namespace MWScript int Locals::getIntVar(const std::string &script, const std::string &var) { + ensure (script); + const Compiler::Locals& locals = MWBase::Environment::get().getScriptManager()->getLocals(script); int index = locals.getIndex(var); char type = locals.getType(var); @@ -73,6 +99,8 @@ namespace MWScript bool Locals::setVarByInt(const std::string& script, const std::string& var, int val) { + ensure (script); + const Compiler::Locals& locals = MWBase::Environment::get().getScriptManager()->getLocals(script); int index = locals.getIndex(var); char type = locals.getType(var); @@ -94,8 +122,11 @@ namespace MWScript return false; } - void Locals::write (ESM::Locals& locals, const std::string& script) const + bool Locals::write (ESM::Locals& locals, const std::string& script) const { + if (!mInitialised) + return false; + try { const Compiler::Locals& declarations = @@ -132,10 +163,14 @@ namespace MWScript catch (const Compiler::SourceException&) { } + + return true; } void Locals::read (const ESM::Locals& locals, const std::string& script) { + ensure (script); + try { const Compiler::Locals& declarations = diff --git a/apps/openmw/mwscript/locals.hpp b/apps/openmw/mwscript/locals.hpp index a9fcf317c..bb4df42bf 100644 --- a/apps/openmw/mwscript/locals.hpp +++ b/apps/openmw/mwscript/locals.hpp @@ -15,30 +15,50 @@ namespace MWScript { class Locals { + bool mInitialised; + + void ensure (const std::string& scriptName); + public: std::vector mShorts; std::vector mLongs; std::vector mFloats; + Locals(); + /// Are there any locals? + /// + /// \note Will return false, if locals have not been configured yet. bool isEmpty() const; - void configure (const ESM::Script& script); + /// \return Did the state of *this change from uninitialised to initialised? + bool configure (const ESM::Script& script); /// @note var needs to be in lowercase + /// + /// \note Locals will be automatically configured first, if necessary bool setVarByInt(const std::string& script, const std::string& var, int val); + /// \note Locals will be automatically configured first, if necessary + // + // \note If it can not be determined if the variable exists, the error will be + // ignored and false will be returned. bool hasVar(const std::string& script, const std::string& var); /// if var does not exist, returns 0 /// @note var needs to be in lowercase + /// + /// \note Locals will be automatically configured first, if necessary int getIntVar (const std::string& script, const std::string& var); - void write (ESM::Locals& locals, const std::string& script) const; + /// \note If locals have not been configured yet, no data is written. + /// + /// \return Locals written? + bool write (ESM::Locals& locals, const std::string& script) const; + /// \note Locals will be automatically configured first, if necessary void read (const ESM::Locals& locals, const std::string& script); }; } #endif - diff --git a/apps/openmw/mwscript/scriptmanagerimp.cpp b/apps/openmw/mwscript/scriptmanagerimp.cpp index 084beb812..b73c9a642 100644 --- a/apps/openmw/mwscript/scriptmanagerimp.cpp +++ b/apps/openmw/mwscript/scriptmanagerimp.cpp @@ -170,7 +170,7 @@ namespace MWScript return iter->second; } - if (const ESM::Script *script = mStore.get().find (name2)) + if (const ESM::Script *script = mStore.get().search (name2)) { if (mVerbose) std::cout diff --git a/apps/openmw/mwworld/refdata.cpp b/apps/openmw/mwworld/refdata.cpp index 2062e78d9..88a6fa353 100644 --- a/apps/openmw/mwworld/refdata.cpp +++ b/apps/openmw/mwworld/refdata.cpp @@ -14,7 +14,6 @@ namespace MWWorld { mBaseNode = refData.mBaseNode; mLocals = refData.mLocals; - mHasLocals = refData.mHasLocals; mEnabled = refData.mEnabled; mCount = refData.mCount; mPosition = refData.mPosition; @@ -34,7 +33,7 @@ namespace MWWorld } RefData::RefData() - : mBaseNode(0), mDeleted(false), mHasLocals (false), mEnabled (true), mCount (1), mCustomData (0), mChanged(false) + : mBaseNode(0), mDeleted(false), mEnabled (true), mCount (1), mCustomData (0), mChanged(false) { for (int i=0; i<3; ++i) { @@ -45,7 +44,7 @@ namespace MWWorld } RefData::RefData (const ESM::CellRef& cellRef) - : mBaseNode(0), mDeleted(false), mHasLocals (false), mEnabled (true), + : mBaseNode(0), mDeleted(false), mEnabled (true), mCount (1), mPosition (cellRef.mPos), mCustomData (0), mChanged(false) // Loading from ESM/ESP files -> assume unchanged @@ -56,13 +55,13 @@ namespace MWWorld } RefData::RefData (const ESM::ObjectState& objectState) - : mBaseNode(0), mDeleted(false), mHasLocals (false), + : mBaseNode(0), mDeleted(false), mEnabled (objectState.mEnabled != 0), mCount (objectState.mCount), mPosition (objectState.mPosition), mCustomData (0), mChanged(true) // Loading from a savegame -> assume changed - { + { for (int i=0; i<3; ++i) mLocalRotation.rot[i] = objectState.mLocalRotation[i]; } @@ -83,10 +82,7 @@ namespace MWWorld void RefData::write (ESM::ObjectState& objectState, const std::string& scriptId) const { - objectState.mHasLocals = mHasLocals; - - if (mHasLocals) - mLocals.write (objectState.mLocals, scriptId); + objectState.mHasLocals = mLocals.write (objectState.mLocals, scriptId); objectState.mEnabled = mEnabled; objectState.mCount = mCount; @@ -139,13 +135,8 @@ namespace MWWorld void RefData::setLocals (const ESM::Script& script) { - if (!mHasLocals) - { - mLocals.configure (script); - mHasLocals = true; - if (!mLocals.isEmpty()) - mChanged = true; - } + if (mLocals.configure (script) && !mLocals.isEmpty()) + mChanged = true; } void RefData::setCount (int count) diff --git a/apps/openmw/mwworld/refdata.hpp b/apps/openmw/mwworld/refdata.hpp index 61055aa73..4075f62ce 100644 --- a/apps/openmw/mwworld/refdata.hpp +++ b/apps/openmw/mwworld/refdata.hpp @@ -31,11 +31,9 @@ namespace MWWorld { osg::PositionAttitudeTransform* mBaseNode; - MWScript::Locals mLocals; // if we find the overhead of heaving a locals - // object in the refdata of refs without a script, - // we can make this a pointer later. + MWScript::Locals mLocals; + bool mDeleted; // separate delete flag used for deletion by a content file - bool mHasLocals; bool mEnabled; int mCount; // 0: deleted From 4d94f38f4b7255fd1abbcdc8d2bd388e604bec04 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 15 Sep 2015 14:57:07 +0200 Subject: [PATCH 2163/3725] replaced context-sensitive implementation of allowing digits at the beginning of names with a more general implementation (Fixes #1730) --- components/compiler/fileparser.cpp | 2 -- components/compiler/scanner.cpp | 36 +++++++++++++++++------------- components/compiler/scanner.hpp | 3 --- 3 files changed, 21 insertions(+), 20 deletions(-) diff --git a/components/compiler/fileparser.cpp b/components/compiler/fileparser.cpp index c8a512340..8711d92fe 100644 --- a/components/compiler/fileparser.cpp +++ b/components/compiler/fileparser.cpp @@ -63,7 +63,6 @@ namespace Compiler if (mState==BeginState && keyword==Scanner::K_begin) { mState = NameState; - scanner.allowNameStartingwithDigit(); return true; } @@ -110,7 +109,6 @@ namespace Compiler scanner.scan (mScriptParser); mState = EndNameState; - scanner.allowNameStartingwithDigit(); return true; } diff --git a/components/compiler/scanner.cpp b/components/compiler/scanner.cpp index 5af396d27..f25e69e39 100644 --- a/components/compiler/scanner.cpp +++ b/components/compiler/scanner.cpp @@ -47,9 +47,6 @@ namespace Compiler bool Scanner::scanToken (Parser& parser) { - bool allowDigit = mNameStartingWithDigit; - mNameStartingWithDigit = false; - switch (mPutback) { case Putback_Special: @@ -114,7 +111,6 @@ namespace Compiler else if (isWhitespace (c)) { mLoc.mLiteral.clear(); - mNameStartingWithDigit = allowDigit; return true; } else if (c==':') @@ -123,7 +119,7 @@ namespace Compiler mLoc.mLiteral.clear(); return true; } - else if (std::isalpha (c) || c=='_' || c=='"' || (allowDigit && std::isdigit (c))) + else if (std::isalpha (c) || c=='_' || c=='"') { bool cont = false; @@ -179,10 +175,18 @@ namespace Compiler { value += c; } - else if (std::isalpha (c) || c=='_') + else if (isStringCharacter (c)) + { error = true; - else if (c=='.' && !error) + value += c; + } + else if (c=='.') { + if (error) + { + putback (c); + break; + } return scanFloat (value, parser, cont); } else @@ -193,7 +197,15 @@ namespace Compiler } if (error) - return false; + { + /// workaround that allows names to begin with digits + /// \todo disable + TokenLoc loc (mLoc); + mLoc.mLiteral.clear(); + cont = parser.parseName (value, loc, *this); + return true; +// return false; + } TokenLoc loc (mLoc); mLoc.mLiteral.clear(); @@ -555,8 +567,7 @@ namespace Compiler Scanner::Scanner (ErrorHandler& errorHandler, std::istream& inputStream, const Extensions *extensions) : mErrorHandler (errorHandler), mStream (inputStream), mExtensions (extensions), - mPutback (Putback_None), mPutbackCode(0), mPutbackInteger(0), mPutbackFloat(0), - mNameStartingWithDigit (false) + mPutback (Putback_None), mPutbackCode(0), mPutbackInteger(0), mPutbackFloat(0) { } @@ -608,9 +619,4 @@ namespace Compiler if (mExtensions) mExtensions->listKeywords (keywords); } - - void Scanner::allowNameStartingwithDigit() - { - mNameStartingWithDigit = true; - } } diff --git a/components/compiler/scanner.hpp b/components/compiler/scanner.hpp index ed01bbe44..847895978 100644 --- a/components/compiler/scanner.hpp +++ b/components/compiler/scanner.hpp @@ -124,9 +124,6 @@ namespace Compiler void listKeywords (std::vector& keywords); ///< Append all known keywords to \a kaywords. - - /// For the next token allow names to start with a digit. - void allowNameStartingwithDigit(); }; } From 84747fbdd764eb00dde424b4ac6e9201b8beb3f7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 16 Sep 2015 15:37:36 +0200 Subject: [PATCH 2164/3725] Use the actual sneak state to determine visibility of indicator (Fixes #2915) --- apps/openmw/mwmechanics/actors.cpp | 2 +- apps/openmw/mwmechanics/character.cpp | 11 ++++++++++- apps/openmw/mwmechanics/character.hpp | 1 + 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index fcda6fa08..1c26c7dd1 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1094,7 +1094,7 @@ namespace MWMechanics static float sneakTimer = 0.f; // times update of sneak icon // if player is in sneak state see if anyone detects him - if (player.getClass().getCreatureStats(player).getMovementFlag(MWMechanics::CreatureStats::Flag_Sneak)) + if (playerCharacter && playerCharacter->isSneaking()) { static float sneakSkillTimer = 0.f; // times sneak skill progress from "avoid notice" diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 3837e9a75..4a826043b 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1768,7 +1768,7 @@ void CharacterController::update(float duration) if(mAnimQueue.empty() || inwater || sneak) { - idlestate = (inwater ? CharState_IdleSwim : (sneak ? CharState_IdleSneak : CharState_Idle)); + idlestate = (inwater ? CharState_IdleSwim : (sneak && !inJump ? CharState_IdleSneak : CharState_Idle)); } else if(mAnimQueue.size() > 1) { @@ -2048,6 +2048,15 @@ bool CharacterController::isKnockedOut() const return mHitState == CharState_KnockOut; } +bool CharacterController::isSneaking() const +{ + return mIdleState == CharState_IdleSneak || + mMovementState == CharState_SneakForward || + mMovementState == CharState_SneakBack || + mMovementState == CharState_SneakLeft || + mMovementState == CharState_SneakRight; +} + void CharacterController::setAttackingOrSpell(bool attackingOrSpell) { mAttackingOrSpell = attackingOrSpell; diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 98c181749..4448467f7 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -241,6 +241,7 @@ public: bool isReadyToBlock() const; bool isKnockedOut() const; + bool isSneaking() const; void setAttackingOrSpell(bool attackingOrSpell); From 5692ef1eae83cf80b21a643782ecfe80eab087b8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 16 Sep 2015 15:43:42 +0200 Subject: [PATCH 2165/3725] Add convenience operator [] to AnimPriority --- apps/openmw/mwmechanics/character.cpp | 4 ++-- apps/openmw/mwrender/animation.cpp | 2 +- apps/openmw/mwrender/animation.hpp | 10 ++++++++++ 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 4a826043b..0d7c0ff26 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -278,7 +278,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat mHitState = CharState_Block; mCurrentHit = "shield"; MWRender::Animation::AnimPriority priorityBlock (Priority_Hit); - priorityBlock.mPriority[MWRender::Animation::BoneGroup_LeftArm] = Priority_Block; + priorityBlock[MWRender::Animation::BoneGroup_LeftArm] = Priority_Block; mAnimation->play(mCurrentHit, priorityBlock, MWRender::Animation::BlendMask_All, true, 1, "block start", "block stop", 0.0f, 0); } @@ -1063,7 +1063,7 @@ bool CharacterController::updateWeaponState() } MWRender::Animation::AnimPriority priorityWeapon(Priority_Weapon); - priorityWeapon.mPriority[MWRender::Animation::BoneGroup_LowerBody] = Priority_WeaponLowerBody; + priorityWeapon[MWRender::Animation::BoneGroup_LowerBody] = Priority_WeaponLowerBody; bool forcestateupdate = false; if(weaptype != mWeaponType && mHitState != CharState_KnockDown && mHitState != CharState_KnockOut diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index c1ae5fed5..b14e629d0 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -680,7 +680,7 @@ namespace MWRender if(!(state->second.mBlendMask&(1<second.mPriority.mPriority[blendMask] < state->second.mPriority.mPriority[blendMask]) + if(active == mStates.end() || active->second.mPriority[blendMask] < state->second.mPriority[blendMask]) active = state; } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 30b6d156a..ef572c7c3 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -105,6 +105,16 @@ public: return true; } + int& operator[] (int n) + { + return mPriority[n]; + } + + const int& operator[] (int n) const + { + return mPriority[n]; + } + bool contains(int priority) const { for (unsigned int i=0; i Date: Wed, 16 Sep 2015 16:14:17 +0200 Subject: [PATCH 2166/3725] Keep playing IdleSneak on the lower body when casting spells / using weapons --- apps/openmw/mwmechanics/character.cpp | 3 +++ apps/openmw/mwmechanics/character.hpp | 1 + apps/openmw/mwrender/animation.cpp | 2 +- apps/openmw/mwrender/animation.hpp | 4 ++-- 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 0d7c0ff26..49e40349b 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -483,7 +483,10 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat idlePriority = Priority_SwimIdle; } else if(mIdleState == CharState_IdleSneak && mAnimation->hasAnimation("idlesneak")) + { idle = "idlesneak"; + idlePriority[MWRender::Animation::BoneGroup_LowerBody] = Priority_SneakIdleLowerBody; + } else if(mIdleState != CharState_None) { idle = "idle"; diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 4448467f7..fee7b959c 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -29,6 +29,7 @@ class CreatureStats; enum Priority { Priority_Default, Priority_WeaponLowerBody, + Priority_SneakIdleLowerBody, Priority_SwimIdle, Priority_Jump, Priority_Movement, diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index b14e629d0..078d136f1 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -680,7 +680,7 @@ namespace MWRender if(!(state->second.mBlendMask&(1<second.mPriority[blendMask] < state->second.mPriority[blendMask]) + if(active == mStates.end() || active->second.mPriority[(BoneGroup)blendMask] < state->second.mPriority[(BoneGroup)blendMask]) active = state; } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index ef572c7c3..e64879a75 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -105,12 +105,12 @@ public: return true; } - int& operator[] (int n) + int& operator[] (BoneGroup n) { return mPriority[n]; } - const int& operator[] (int n) const + const int& operator[] (BoneGroup n) const { return mPriority[n]; } From f8d4bc378ff1ef08de7547877deb8b3a6f0b3d4d Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 16 Sep 2015 16:15:55 +0200 Subject: [PATCH 2167/3725] Move setAlpha from NpcAnimation to Animation (Fixes #2917) --- apps/openmw/mwrender/animation.cpp | 34 +++++++++++++++++++++++++ apps/openmw/mwrender/animation.hpp | 5 +++- apps/openmw/mwrender/npcanimation.cpp | 36 --------------------------- apps/openmw/mwrender/npcanimation.hpp | 4 --- 4 files changed, 38 insertions(+), 41 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 078d136f1..24d540e20 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -9,6 +9,8 @@ #include #include #include +#include +#include #include @@ -292,6 +294,7 @@ namespace MWRender , mTextKeyListener(NULL) , mHeadYawRadians(0.f) , mHeadPitchRadians(0.f) + , mAlpha(1.f) { for(size_t i = 0;i < sNumBlendMasks;i++) mAnimationTimePtr[i].reset(new AnimationTime); @@ -1247,6 +1250,37 @@ namespace MWRender return found->second; } + void Animation::setAlpha(float alpha) + { + if (alpha == mAlpha) + return; + mAlpha = alpha; + + if (alpha != 1.f) + { + osg::StateSet* stateset (new osg::StateSet); + + osg::BlendFunc* blendfunc (new osg::BlendFunc); + stateset->setAttributeAndModes(blendfunc, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + + // FIXME: overriding diffuse/ambient/emissive colors + osg::Material* material (new osg::Material); + material->setColorMode(osg::Material::OFF); + material->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(1,1,1,alpha)); + material->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(1,1,1,1)); + stateset->setAttributeAndModes(material, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + + stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); + stateset->setRenderBinMode(osg::StateSet::OVERRIDE_RENDERBIN_DETAILS); + stateset->setNestRenderBins(false); + mObjectRoot->setStateSet(stateset); + } + else + { + mObjectRoot->setStateSet(NULL); + } + } + void Animation::setLightEffect(float effect) { if (effect == 0) diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index e64879a75..94b792c0d 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -253,6 +253,8 @@ protected: osg::ref_ptr mGlowLight; + float mAlpha; + /* Sets the appropriate animations on the bone groups based on priority. */ void resetActiveGroups(); @@ -419,7 +421,8 @@ public: virtual void showCarriedLeft(bool show) {} virtual void setWeaponGroup(const std::string& group) {} virtual void setVampire(bool vampire) {} - virtual void setAlpha(float alpha) {} + /// A value < 1 makes the animation translucent, 1.f = fully opaque + void setAlpha(float alpha); virtual void setPitchFactor(float factor) {} virtual void attachArrow() {} virtual void releaseArrow(float attackStrength) {} diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 66a3d3ec6..99ee886e1 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -2,8 +2,6 @@ #include #include -#include -#include #include @@ -278,7 +276,6 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, osg::ref_ptr par mShowWeapons(false), mShowCarriedLeft(true), mNpcType(Type_Normal), - mAlpha(1.f), mSoundsDisabled(disableSounds) { mNpc = mPtr.get()->mBase; @@ -422,7 +419,6 @@ void NpcAnimation::updateParts() if (!mObjectRoot.get()) return; - mAlpha = 1.f; const MWWorld::Class &cls = mPtr.getClass(); NpcType curType = Type_Normal; @@ -902,7 +898,6 @@ void NpcAnimation::showWeapons(bool showWeapon) { removeIndividualPart(ESM::PRT_Weapon); } - mAlpha = 1.f; } void NpcAnimation::showCarriedLeft(bool show) @@ -988,37 +983,6 @@ void NpcAnimation::permanentEffectAdded(const ESM::MagicEffect *magicEffect, boo } } -void NpcAnimation::setAlpha(float alpha) -{ - if (alpha == mAlpha) - return; - mAlpha = alpha; - - if (alpha != 1.f) - { - osg::StateSet* stateset (new osg::StateSet); - - osg::BlendFunc* blendfunc (new osg::BlendFunc); - stateset->setAttributeAndModes(blendfunc, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); - - // FIXME: overriding diffuse/ambient/emissive colors - osg::Material* material (new osg::Material); - material->setColorMode(osg::Material::OFF); - material->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(1,1,1,alpha)); - material->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(1,1,1,1)); - stateset->setAttributeAndModes(material, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); - - stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); - stateset->setRenderBinMode(osg::StateSet::OVERRIDE_RENDERBIN_DETAILS); - stateset->setNestRenderBins(false); - mObjectRoot->setStateSet(stateset); - } - else - { - mObjectRoot->setStateSet(NULL); - } -} - void NpcAnimation::enableHeadAnimation(bool enable) { mHeadAnimationTime->setEnabled(enable); diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 6462c53c3..06f40f847 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -65,7 +65,6 @@ private: boost::shared_ptr mHeadAnimationTime; boost::shared_ptr mWeaponAnimationTime; - float mAlpha; bool mSoundsDisabled; void updateNpcBase(); @@ -134,9 +133,6 @@ public: /// Get the inventory slot that the given node path leads into, or -1 if not found. int getSlot(const osg::NodePath& path) const; - /// Make the NPC only partially visible - virtual void setAlpha(float alpha); - virtual void setVampire(bool vampire); /// Set a translation offset (in object root space) to apply to meshes when in first person mode. From 47e29480ce9c46f5787885183537ef7774742656 Mon Sep 17 00:00:00 2001 From: Emmanuel Anne Date: Wed, 16 Sep 2015 16:04:25 +0200 Subject: [PATCH 2168/3725] show duration of light sources in tooltip I had forgotten light sources disappear after a while, this way at least you know it's normal ! --- apps/openmw/mwclass/light.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index c532b5d65..cbd051fdb 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -169,6 +169,7 @@ namespace MWClass std::string text; + text += "\nDuration: " + MWGui::ToolTips::toString(ptr.getClass().getRemainingUsageTime(ptr)); if (ref->mBase->mData.mWeight != 0) { text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->mBase->mData.mWeight); From 1472711583358f633d17cc055a24edfb970e85eb Mon Sep 17 00:00:00 2001 From: Emmanuel Anne Date: Wed, 16 Sep 2015 17:32:00 +0200 Subject: [PATCH 2169/3725] add duration to spell icons too and use gmststrings instead of direct strings in tooltips durations can display minutes and hours I don't know any effect lasting an hour or more but you never know... --- apps/openmw/mwclass/light.cpp | 2 +- apps/openmw/mwgui/spellicons.cpp | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index cbd051fdb..98d86e5ae 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -169,7 +169,7 @@ namespace MWClass std::string text; - text += "\nDuration: " + MWGui::ToolTips::toString(ptr.getClass().getRemainingUsageTime(ptr)); + text += "\n#{sDuration}: " + MWGui::ToolTips::toString(ptr.getClass().getRemainingUsageTime(ptr)); if (ref->mBase->mData.mWeight != 0) { text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->mBase->mData.mWeight); diff --git a/apps/openmw/mwgui/spellicons.cpp b/apps/openmw/mwgui/spellicons.cpp index b2995af3c..f132cd73e 100644 --- a/apps/openmw/mwgui/spellicons.cpp +++ b/apps/openmw/mwgui/spellicons.cpp @@ -133,6 +133,23 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->getGameSettingString("spoints", "") : MWBase::Environment::get().getWindowManager()->getGameSettingString("spoint", "") ); } + if (effectIt->mRemainingTime > -1) { + sourcesDescription += " #{sDuration}: "; + float duration = effectIt->mRemainingTime; + if (duration > 3600) { + int hour = duration / 3600; + duration -= hour*3600; + sourcesDescription += MWGui::ToolTips::toString(hour) + "h"; + } + if (duration > 60) { + int minute = duration / 60; + duration -= minute*60; + sourcesDescription += MWGui::ToolTips::toString(minute) + "m"; + } + if (duration > 0.1) { + sourcesDescription += MWGui::ToolTips::toString(duration) + "s"; + } + } } } From b0d373f7e6ffec07b8f356dfeb2ec3805f31574c Mon Sep 17 00:00:00 2001 From: Emmanuel Anne Date: Wed, 16 Sep 2015 19:18:01 +0200 Subject: [PATCH 2170/3725] durations in tooltips : water walking effects is seen differently so move the duration info out of this block... --- apps/openmw/mwgui/spellicons.cpp | 34 ++++++++++++++++---------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwgui/spellicons.cpp b/apps/openmw/mwgui/spellicons.cpp index f132cd73e..632baeb19 100644 --- a/apps/openmw/mwgui/spellicons.cpp +++ b/apps/openmw/mwgui/spellicons.cpp @@ -133,24 +133,24 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->getGameSettingString("spoints", "") : MWBase::Environment::get().getWindowManager()->getGameSettingString("spoint", "") ); } - if (effectIt->mRemainingTime > -1) { - sourcesDescription += " #{sDuration}: "; - float duration = effectIt->mRemainingTime; - if (duration > 3600) { - int hour = duration / 3600; - duration -= hour*3600; - sourcesDescription += MWGui::ToolTips::toString(hour) + "h"; - } - if (duration > 60) { - int minute = duration / 60; - duration -= minute*60; - sourcesDescription += MWGui::ToolTips::toString(minute) + "m"; - } - if (duration > 0.1) { - sourcesDescription += MWGui::ToolTips::toString(duration) + "s"; - } - } } + if (effectIt->mRemainingTime > -1) { + sourcesDescription += " #{sDuration}: "; + float duration = effectIt->mRemainingTime; + if (duration > 3600) { + int hour = duration / 3600; + duration -= hour*3600; + sourcesDescription += MWGui::ToolTips::toString(hour) + "h"; + } + if (duration > 60) { + int minute = duration / 60; + duration -= minute*60; + sourcesDescription += MWGui::ToolTips::toString(minute) + "m"; + } + if (duration > 0.1) { + sourcesDescription += MWGui::ToolTips::toString(duration) + "s"; + } + } } if (remainingDuration > 0.f) From a47617c21f11c33e10b8a635292c3b1a4d8d5769 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 16 Sep 2015 20:45:37 +0200 Subject: [PATCH 2171/3725] Fix tab indentations in apps/ and components/ --- apps/esmtool/record.cpp | 30 +++++++++---------- apps/esmtool/record.hpp | 2 +- .../model/world/infotableproxymodel.cpp | 2 +- apps/opencs/view/widget/droplineedit.cpp | 2 +- apps/openmw/android_commandLine.cpp | 26 ++++++++-------- apps/openmw/android_main.c | 20 ++++++------- apps/openmw/crashcatcher.cpp | 4 +-- apps/openmw/mwgui/debugwindow.cpp | 8 ++--- apps/openmw/mwgui/tooltips.hpp | 2 +- apps/openmw/mwgui/widgets.cpp | 4 +-- apps/openmw/mwinput/inputmanagerimp.cpp | 14 ++++----- apps/openmw/mwmechanics/aicombat.cpp | 2 +- apps/openmw/mwphysics/physicssystem.cpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 2 +- components/compiler/extensions0.hpp | 2 +- components/esm/loadmgef.hpp | 4 +-- components/files/configurationmanager.hpp | 10 +++---- components/sdlutil/sdlinputwrapper.hpp | 4 +-- 18 files changed, 70 insertions(+), 70 deletions(-) diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index 76c14e728..5fe6471b0 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -493,14 +493,14 @@ void Record::print() std::cout << " Enchantment Points: " << mData.mData.mEnchant << std::endl; if (mPrintPlain) { - std::cout << " Text:" << std::endl; - std::cout << "START--------------------------------------" << std::endl; - std::cout << mData.mText << std::endl; - std::cout << "END----------------------------------------" << std::endl; + std::cout << " Text:" << std::endl; + std::cout << "START--------------------------------------" << std::endl; + std::cout << mData.mText << std::endl; + std::cout << "END----------------------------------------" << std::endl; } else { - std::cout << " Text: [skipped]" << std::endl; + std::cout << " Text: [skipped]" << std::endl; } } @@ -799,14 +799,14 @@ void Record::print() { if (mPrintPlain) { - std::cout << " Result Script:" << std::endl; - std::cout << "START--------------------------------------" << std::endl; - std::cout << mData.mResultScript << std::endl; - std::cout << "END----------------------------------------" << std::endl; + std::cout << " Result Script:" << std::endl; + std::cout << "START--------------------------------------" << std::endl; + std::cout << mData.mResultScript << std::endl; + std::cout << "END----------------------------------------" << std::endl; } else { - std::cout << " Result Script: [skipped]" << std::endl; + std::cout << " Result Script: [skipped]" << std::endl; } } } @@ -1201,14 +1201,14 @@ void Record::print() if (mPrintPlain) { - std::cout << " Script:" << std::endl; - std::cout << "START--------------------------------------" << std::endl; - std::cout << mData.mScriptText << std::endl; - std::cout << "END----------------------------------------" << std::endl; + std::cout << " Script:" << std::endl; + std::cout << "START--------------------------------------" << std::endl; + std::cout << mData.mScriptText << std::endl; + std::cout << "END----------------------------------------" << std::endl; } else { - std::cout << " Script: [skipped]" << std::endl; + std::cout << " Script: [skipped]" << std::endl; } } diff --git a/apps/esmtool/record.hpp b/apps/esmtool/record.hpp index c1b90ac2b..5e03c64db 100644 --- a/apps/esmtool/record.hpp +++ b/apps/esmtool/record.hpp @@ -53,7 +53,7 @@ namespace EsmTool } void setPrintPlain(bool plain) { - mPrintPlain = plain; + mPrintPlain = plain; } virtual void load(ESM::ESMReader &esm) = 0; diff --git a/apps/opencs/model/world/infotableproxymodel.cpp b/apps/opencs/model/world/infotableproxymodel.cpp index f55f775ab..4f0b2e752 100644 --- a/apps/opencs/model/world/infotableproxymodel.cpp +++ b/apps/opencs/model/world/infotableproxymodel.cpp @@ -16,7 +16,7 @@ namespace CSMWorld::InfoTableProxyModel::InfoTableProxyModel(CSMWorld::UniversalId::Type type, QObject *parent) : IdTableProxyModel(parent), mType(type), - mInfoColumnId(type == UniversalId::Type_TopicInfos ? Columns::ColumnId_Topic : + mInfoColumnId(type == UniversalId::Type_TopicInfos ? Columns::ColumnId_Topic : Columns::ColumnId_Journal), mInfoColumnIndex(-1), mLastAddedSourceRow(-1) diff --git a/apps/opencs/view/widget/droplineedit.cpp b/apps/opencs/view/widget/droplineedit.cpp index 1df598cb8..2ca306461 100644 --- a/apps/opencs/view/widget/droplineedit.cpp +++ b/apps/opencs/view/widget/droplineedit.cpp @@ -35,7 +35,7 @@ void CSVWidget::DropLineEdit::dropEvent(QDropEvent *event) if (CSVWorld::DragDropUtils::canAcceptData(*event, mDropType)) { CSMWorld::UniversalId id = CSVWorld::DragDropUtils::getAcceptedData(*event, mDropType); - setText(QString::fromUtf8(id.getId().c_str())); + setText(QString::fromUtf8(id.getId().c_str())); emit tableMimeDataDropped(id, CSVWorld::DragDropUtils::getTableMimeData(*event)->getDocumentPtr()); } } diff --git a/apps/openmw/android_commandLine.cpp b/apps/openmw/android_commandLine.cpp index ebfff28ca..7e7f368e0 100644 --- a/apps/openmw/android_commandLine.cpp +++ b/apps/openmw/android_commandLine.cpp @@ -7,21 +7,21 @@ int argcData; extern "C" void releaseArgv(); void releaseArgv() { - delete[] argvData; + delete[] argvData; } JNIEXPORT void JNICALL Java_ui_activity_GameActivity_commandLine(JNIEnv *env, - jobject obj, jint argc, jobjectArray stringArray) { - jboolean iscopy; - argcData = (int) argc; - argvData = new const char *[argcData + 1]; - argvData[0] = "openmw"; - for (int i = 1; i < argcData + 1; i++) { - jstring string = (jstring) (env)->GetObjectArrayElement(stringArray, - i - 1); - argvData[i] = (env)->GetStringUTFChars(string, &iscopy); - (env)->DeleteLocalRef(string); - } - (env)->DeleteLocalRef(stringArray); + jobject obj, jint argc, jobjectArray stringArray) { + jboolean iscopy; + argcData = (int) argc; + argvData = new const char *[argcData + 1]; + argvData[0] = "openmw"; + for (int i = 1; i < argcData + 1; i++) { + jstring string = (jstring) (env)->GetObjectArrayElement(stringArray, + i - 1); + argvData[i] = (env)->GetStringUTFChars(string, &iscopy); + (env)->DeleteLocalRef(string); + } + (env)->DeleteLocalRef(stringArray); } diff --git a/apps/openmw/android_main.c b/apps/openmw/android_main.c index 1b2839519..47b77a8b3 100644 --- a/apps/openmw/android_main.c +++ b/apps/openmw/android_main.c @@ -16,22 +16,22 @@ extern const char **argvData; void releaseArgv(); int Java_org_libsdl_app_SDLActivity_nativeInit(JNIEnv* env, jclass cls, - jobject obj) { + jobject obj) { - SDL_Android_Init(env, cls); + SDL_Android_Init(env, cls); - SDL_SetMainReady(); + SDL_SetMainReady(); - /* Run the application code! */ + /* Run the application code! */ - int status; + int status; - status = main(argcData+1, argvData); - releaseArgv(); - /* Do not issue an exit or the whole application will terminate instead of just the SDL thread */ - /* exit(status); */ + status = main(argcData+1, argvData); + releaseArgv(); + /* Do not issue an exit or the whole application will terminate instead of just the SDL thread */ + /* exit(status); */ - return status; + return status; } #endif /* __ANDROID__ */ diff --git a/apps/openmw/crashcatcher.cpp b/apps/openmw/crashcatcher.cpp index 8f25d041c..373d78746 100644 --- a/apps/openmw/crashcatcher.cpp +++ b/apps/openmw/crashcatcher.cpp @@ -37,8 +37,8 @@ static const char pipe_err[] = "!!! Failed to create pipe\n"; static const char fork_err[] = "!!! Failed to fork debug process\n"; static const char exec_err[] = "!!! Failed to exec debug process\n"; -#ifndef PATH_MAX /* Not all platforms (GNU Hurd) have this. */ -# define PATH_MAX 256 +#ifndef PATH_MAX /* Not all platforms (GNU Hurd) have this. */ +# define PATH_MAX 256 #endif static char argv0[PATH_MAX]; diff --git a/apps/openmw/mwgui/debugwindow.cpp b/apps/openmw/mwgui/debugwindow.cpp index a6dab66c1..37ea3470d 100644 --- a/apps/openmw/mwgui/debugwindow.cpp +++ b/apps/openmw/mwgui/debugwindow.cpp @@ -18,9 +18,9 @@ namespace float accumulated_time=0,parent_time = pit->Is_Root() ? CProfileManager::Get_Time_Since_Reset() : pit->Get_Current_Parent_Total_Time(); int i,j; int frames_since_reset = CProfileManager::Get_Frame_Count_Since_Reset(); - for (i=0;iGet_Current_Parent_Name())+" (total running time: "+MyGUI::utility::toString(parent_time,3)+" ms) ---\n"; os << s; @@ -35,7 +35,7 @@ namespace accumulated_time += current_total_time; float fraction = parent_time > SIMD_EPSILON ? (current_total_time / parent_time) * 100 : 0.f; - for (j=0;jGet_Current_Name()+" ("+MyGUI::utility::toString(fraction,2)+" %) :: "+MyGUI::utility::toString(ms,3)+" ms / frame ("+MyGUI::utility::toString(pit->Get_Current_Total_Calls())+" calls)\n"; os << s; @@ -47,7 +47,7 @@ namespace { os << "what's wrong\n"; } - for (i=0;i SIMD_EPSILON ? ((parent_time - accumulated_time) / parent_time) * 100 : 0.f; s = "Unaccounted: ("+MyGUI::utility::toString(unaccounted,3)+" %) :: "+MyGUI::utility::toString(parent_time - accumulated_time,3)+" ms\n"; os << s; diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp index 384bccfea..983b50fe2 100644 --- a/apps/openmw/mwgui/tooltips.hpp +++ b/apps/openmw/mwgui/tooltips.hpp @@ -109,7 +109,7 @@ namespace MWGui static std::string sSchoolNames[6]; - int mHorizontalScrollIndex; + int mHorizontalScrollIndex; float mDelay; diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index 481ffaade..695337cde 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -605,7 +605,7 @@ namespace MWGui controller->eventRepeatClick += newDelegate(this, &MWScrollBar::repeatClick); controller->setEnabled(mEnableRepeat); controller->setRepeat(mRepeatTriggerTime, mRepeatStepTime); - MyGUI::ControllerManager::getInstance().addItem(this, controller); + MyGUI::ControllerManager::getInstance().addItem(this, controller); } void MWScrollBar::onDecreaseButtonReleased(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id) @@ -621,7 +621,7 @@ namespace MWGui controller->eventRepeatClick += newDelegate(this, &MWScrollBar::repeatClick); controller->setEnabled(mEnableRepeat); controller->setRepeat(mRepeatTriggerTime, mRepeatStepTime); - MyGUI::ControllerManager::getInstance().addItem(this, controller); + MyGUI::ControllerManager::getInstance().addItem(this, controller); } void MWScrollBar::onIncreaseButtonReleased(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index bd94d60c6..ad5fe35bd 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -102,9 +102,9 @@ namespace MWInput mControlSwitch["playerviewswitch"] = true; mControlSwitch["vanitymode"] = true; - /* Joystick Init */ + /* Joystick Init */ - //Load controller mappings + // Load controller mappings #if SDL_VERSION_ATLEAST(2,0,2) if(controllerBindingsFile!="") { @@ -112,10 +112,10 @@ namespace MWInput } #endif - //Open all presently connected sticks - int numSticks = SDL_NumJoysticks(); - for(int i = 0; i < numSticks; i++) - { + // Open all presently connected sticks + int numSticks = SDL_NumJoysticks(); + for(int i = 0; i < numSticks; i++) + { if(SDL_IsGameController(i)) { SDL_ControllerDeviceEvent evt; @@ -126,7 +126,7 @@ namespace MWInput { //ICS_LOG(std::string("Unusable controller plugged in: ")+SDL_JoystickNameForIndex(i)); } - } + } float uiScale = Settings::Manager::getFloat("scaling factor", "GUI"); if (uiScale != 0.f) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 58f74a87f..45a6cce6d 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -57,7 +57,7 @@ namespace osg::Vec3f dir = to - from; dir.z() = 0; dir.normalize(); - float verticalOffset = 200; // instead of '200' here we want the height of the actor + float verticalOffset = 200; // instead of '200' here we want the height of the actor osg::Vec3f _from = from + dir*offsetXY + osg::Vec3f(0,0,1) * verticalOffset; // cast up-down ray and find height in world space of hit diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index c4fec7256..e666161da 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -747,7 +747,7 @@ namespace MWPhysics { } - virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult,bool normalInWorldSpace) + virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult,bool normalInWorldSpace) { if (rayResult.m_collisionObject == mMe) return 1.f; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index f50991e24..f812fd8fd 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -287,7 +287,7 @@ namespace MWWorld if (mPlayer) { - mPlayer->clear(); + mPlayer->clear(); mPlayer->setCell(0); mPlayer->getPlayer().getRefData() = RefData(); mPlayer->set(mStore.get().find ("player")); diff --git a/components/compiler/extensions0.hpp b/components/compiler/extensions0.hpp index 83f3a44fa..e9ce6a6d6 100644 --- a/components/compiler/extensions0.hpp +++ b/components/compiler/extensions0.hpp @@ -44,7 +44,7 @@ namespace Compiler namespace Gui { - void registerExtensions (Extensions& extensions); + void registerExtensions (Extensions& extensions); } namespace Misc diff --git a/components/esm/loadmgef.hpp b/components/esm/loadmgef.hpp index 32b8a85a6..eeb4268c2 100644 --- a/components/esm/loadmgef.hpp +++ b/components/esm/loadmgef.hpp @@ -31,9 +31,9 @@ struct MagicEffect CastTouch = 0x80, // Allows range - cast on touch. CastTarget = 0x100, // Allows range - cast on target. UncappedDamage = 0x1000, // Negates multiple cap behaviours. Allows an effect to reduce an attribute below zero; removes the normal minimum effect duration of 1 second. - NonRecastable = 0x4000, // Does not land if parent spell is already affecting target. Shows "you cannot re-cast" message for self target. + NonRecastable = 0x4000, // Does not land if parent spell is already affecting target. Shows "you cannot re-cast" message for self target. Unreflectable = 0x10000, // Cannot be reflected, the effect always lands normally. - CasterLinked = 0x20000, // Must quench if caster is dead, or not an NPC/creature. Not allowed in containter/door trap spells. + CasterLinked = 0x20000, // Must quench if caster is dead, or not an NPC/creature. Not allowed in containter/door trap spells. // Originally modifiable flags AllowSpellmaking = 0x200, // Can be used for spellmaking diff --git a/components/files/configurationmanager.hpp b/components/files/configurationmanager.hpp index 5f0062c2e..102f7c3cb 100644 --- a/components/files/configurationmanager.hpp +++ b/components/files/configurationmanager.hpp @@ -52,11 +52,11 @@ struct ConfigurationManager typedef Files::FixedPath<> FixedPathType; typedef const boost::filesystem::path& (FixedPathType::*path_type_f)() const; - #if defined HAVE_UNORDERED_MAP - typedef std::unordered_map TokensMappingContainer; - #else - typedef std::tr1::unordered_map TokensMappingContainer; - #endif + #if defined HAVE_UNORDERED_MAP + typedef std::unordered_map TokensMappingContainer; + #else + typedef std::tr1::unordered_map TokensMappingContainer; + #endif void loadConfig(const boost::filesystem::path& path, boost::program_options::variables_map& variables, diff --git a/components/sdlutil/sdlinputwrapper.hpp b/components/sdlutil/sdlinputwrapper.hpp index bdb5842ae..a821b9012 100644 --- a/components/sdlutil/sdlinputwrapper.hpp +++ b/components/sdlutil/sdlinputwrapper.hpp @@ -30,8 +30,8 @@ namespace SDLUtil void setControllerEventCallback(ControllerListener* listen) { mConListener = listen; } void capture(bool windowEventsOnly); - bool isModifierHeld(SDL_Keymod mod); - bool isKeyDown(SDL_Scancode key); + bool isModifierHeld(SDL_Keymod mod); + bool isKeyDown(SDL_Scancode key); void setMouseVisible (bool visible); void setMouseRelative(bool relative); From 29a84452ab71886d1e97d6110844ad88e2cb48f4 Mon Sep 17 00:00:00 2001 From: Emmanuel Anne Date: Wed, 16 Sep 2015 22:41:42 +0200 Subject: [PATCH 2172/3725] durations in tooltips : use "show effect duration" setting --- apps/openmw/mwclass/light.cpp | 4 +++- apps/openmw/mwgui/spellicons.cpp | 36 +++++++++++++++++--------------- files/settings-default.cfg | 2 ++ 3 files changed, 24 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 98d86e5ae..f1dd18acc 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -2,6 +2,7 @@ #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -169,7 +170,8 @@ namespace MWClass std::string text; - text += "\n#{sDuration}: " + MWGui::ToolTips::toString(ptr.getClass().getRemainingUsageTime(ptr)); + if (Settings::Manager::getBool("show effect duration","Game")) + text += "\n#{sDuration}: " + MWGui::ToolTips::toString(ptr.getClass().getRemainingUsageTime(ptr)); if (ref->mBase->mData.mWeight != 0) { text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->mBase->mData.mWeight); diff --git a/apps/openmw/mwgui/spellicons.cpp b/apps/openmw/mwgui/spellicons.cpp index 632baeb19..27896381e 100644 --- a/apps/openmw/mwgui/spellicons.cpp +++ b/apps/openmw/mwgui/spellicons.cpp @@ -6,6 +6,7 @@ #include #include +#include #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" @@ -134,23 +135,24 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->getGameSettingString("spoint", "") ); } } - if (effectIt->mRemainingTime > -1) { - sourcesDescription += " #{sDuration}: "; - float duration = effectIt->mRemainingTime; - if (duration > 3600) { - int hour = duration / 3600; - duration -= hour*3600; - sourcesDescription += MWGui::ToolTips::toString(hour) + "h"; - } - if (duration > 60) { - int minute = duration / 60; - duration -= minute*60; - sourcesDescription += MWGui::ToolTips::toString(minute) + "m"; - } - if (duration > 0.1) { - sourcesDescription += MWGui::ToolTips::toString(duration) + "s"; - } - } + if (effectIt->mRemainingTime > -1 && + Settings::Manager::getBool("show effect duration","Game")) { + sourcesDescription += " #{sDuration}: "; + float duration = effectIt->mRemainingTime; + if (duration > 3600) { + int hour = duration / 3600; + duration -= hour*3600; + sourcesDescription += MWGui::ToolTips::toString(hour) + "h"; + } + if (duration > 60) { + int minute = duration / 60; + duration -= minute*60; + sourcesDescription += MWGui::ToolTips::toString(minute) + "m"; + } + if (duration > 0.1) { + sourcesDescription += MWGui::ToolTips::toString(duration) + "s"; + } + } } if (remainingDuration > 0.f) diff --git a/files/settings-default.cfg b/files/settings-default.cfg index c793225c2..274a31315 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -175,6 +175,8 @@ difficulty = 0 #2: tint crosshair #3: both show owned = 0 +# Show the remaining duration of magic effects and lights +show effect duration = false [Saves] character = From ab97a90c760fb3a558f25bd49527bf69fbba8d64 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 16 Sep 2015 20:50:57 +0200 Subject: [PATCH 2173/3725] Add travis-ci script to detect tab characters in the code --- .travis.yml | 2 +- CI/check_tabs.sh | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) create mode 100755 CI/check_tabs.sh diff --git a/.travis.yml b/.travis.yml index 80277f8ba..69879bd78 100644 --- a/.travis.yml +++ b/.travis.yml @@ -40,8 +40,8 @@ script: - cd ./build - if [ "$COVERITY_SCAN_BRANCH" != 1 ]; then ${ANALYZE}make -j2; fi - if [ "$COVERITY_SCAN_BRANCH" != 1 ] && [ "${TRAVIS_OS_NAME}" = "osx" ]; then make package; fi -after_script: - if [ "${TRAVIS_OS_NAME}" = "linux" ]; then ./openmw_test_suite; fi + - if [ "${TRAVIS_OS_NAME}" = "linux" ]; then cd .. && ./CI/check_tabs.sh; fi notifications: recipients: - corrmage+travis-ci@gmail.com diff --git a/CI/check_tabs.sh b/CI/check_tabs.sh new file mode 100755 index 000000000..91f81e2a1 --- /dev/null +++ b/CI/check_tabs.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +OUTPUT=$(grep -nRP '\t' --include=\*.{cpp,hpp,c,h} apps components) + +if [[ $OUTPUT ]] ; then + echo "Error: Tab characters found!" + echo $OUTPUT + exit 1 +fi From c4b5a41ac396fc0e69df339513217ee0d5ba5ba9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 17 Sep 2015 01:08:16 +0200 Subject: [PATCH 2174/3725] Improve combat AI vertical aiming (Fixes #1366, Fixes #1330) --- apps/openmw/mwbase/world.hpp | 4 +++ apps/openmw/mwmechanics/aicombat.cpp | 29 ++++++++-------- apps/openmw/mwphysics/physicssystem.hpp | 1 + apps/openmw/mwworld/worldimp.cpp | 44 ++++++++++++------------- apps/openmw/mwworld/worldimp.hpp | 4 +++ 5 files changed, 45 insertions(+), 37 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index a3d293d95..1622e1537 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -541,6 +541,10 @@ namespace MWBase virtual void resetActors() = 0; virtual bool isWalkingOnWater (const MWWorld::Ptr& actor) = 0; + + /// Return a vector aiming the actor's weapon towards a target. + /// @note The length of the vector is the distance between actor and target. + virtual osg::Vec3f aimToTarget(const MWWorld::Ptr& actor, const MWWorld::Ptr& target) = 0; }; } diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 58f74a87f..93b4e0ee7 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -34,10 +34,9 @@ namespace return std::atan2(dir.x(), dir.y()); } - float getXAngleToDir(const osg::Vec3f& dir, float dirLen = 0.0f) + float getXAngleToDir(const osg::Vec3f& dir) { - float len = (dirLen > 0.0f)? dirLen : dir.length(); - return -std::asin(dir.z() / len); + return -std::asin(dir.z() / dir.length()); } const float REACTION_INTERVAL = 0.25f; @@ -346,8 +345,9 @@ namespace MWMechanics ESM::Position pos = actor.getRefData().getPosition(); osg::Vec3f vActorPos(pos.asVec3()); osg::Vec3f vTargetPos(target.getRefData().getPosition().asVec3()); - osg::Vec3f vDirToTarget = vTargetPos - vActorPos; - float distToTarget = vDirToTarget.length(); + + osg::Vec3f vAimDir = MWBase::Environment::get().getWorld()->aimToTarget(actor, target); + float distToTarget = (vTargetPos - vActorPos).length(); osg::Vec3f& lastActorPos = storage.mLastActorPos; bool& followTarget = storage.mFollowTarget; @@ -388,7 +388,7 @@ namespace MWMechanics if (distantCombat) { osg::Vec3f& lastTargetPos = storage.mLastTargetPos; - osg::Vec3f vAimDir = AimDirToMovingTarget(actor, target, lastTargetPos, REACTION_INTERVAL, weaptype, + vAimDir = AimDirToMovingTarget(actor, target, lastTargetPos, REACTION_INTERVAL, weaptype, storage.mStrength); lastTargetPos = vTargetPos; movement.mRotation[0] = getXAngleToDir(vAimDir); @@ -396,8 +396,8 @@ namespace MWMechanics } else { - movement.mRotation[0] = getXAngleToDir(vDirToTarget, distToTarget); - movement.mRotation[2] = getZAngleToDir(vDirToTarget); + movement.mRotation[0] = getXAngleToDir(vAimDir); + movement.mRotation[2] = getZAngleToDir((vTargetPos-vActorPos)); // using vAimDir results in spastic movements since the head is animated } // (not quite attack dist while following) @@ -431,19 +431,19 @@ namespace MWMechanics if(speed == 0.0f) speed = actorClass.getSpeed(actor); // maximum dist before pit/obstacle for actor to avoid them depending on his speed float maxAvoidDist = REACTION_INTERVAL * speed + speed / MAX_VEL_ANGULAR_RADIANS * 2; // *2 - for reliability - preferShortcut = checkWayIsClear(vActorPos, vTargetPos, osg::Vec3f(vDirToTarget.x(), vDirToTarget.y(), 0).length() > maxAvoidDist*1.5? maxAvoidDist : maxAvoidDist/2); + preferShortcut = checkWayIsClear(vActorPos, vTargetPos, osg::Vec3f(vAimDir.x(), vAimDir.y(), 0).length() > maxAvoidDist*1.5? maxAvoidDist : maxAvoidDist/2); } // don't use pathgrid when actor can move in 3 dimensions if (canMoveByZ) { preferShortcut = true; - movement.mRotation[0] = getXAngleToDir(vDirToTarget, distToTarget); + movement.mRotation[0] = getXAngleToDir(vAimDir); } if(preferShortcut) { - movement.mRotation[2] = getZAngleToDir(vDirToTarget); + movement.mRotation[2] = getZAngleToDir((vTargetPos-vActorPos)); forceNoShortcut = false; shortcutFailPos.pos[0] = shortcutFailPos.pos[1] = shortcutFailPos.pos[2] = 0; mPathFinder.clearPath(); @@ -478,7 +478,7 @@ namespace MWMechanics // if there is no new path, then go straight on target if (!mPathFinder.isPathConstructed()) { - movement.mRotation[2] = getZAngleToDir(vDirToTarget); + movement.mRotation[2] = getZAngleToDir((vTargetPos-vActorPos)); } } @@ -779,9 +779,8 @@ osg::Vec3f AimDirToMovingTarget(const MWWorld::Ptr& actor, const MWWorld::Ptr& t // idea: perpendicular to dir to target speed components of target move vector and projectile vector should be the same - osg::Vec3f vActorPos = actor.getRefData().getPosition().asVec3(); osg::Vec3f vTargetPos = target.getRefData().getPosition().asVec3(); - osg::Vec3f vDirToTarget = vTargetPos - vActorPos; + osg::Vec3f vDirToTarget = MWBase::Environment::get().getWorld()->aimToTarget(actor, target); float distToTarget = vDirToTarget.length(); osg::Vec3f vTargetMoveDir = vTargetPos - vLastTargetPos; @@ -812,7 +811,7 @@ osg::Vec3f AimDirToMovingTarget(const MWWorld::Ptr& actor, const MWWorld::Ptr& t t_collision = projDistDiff / (std::sqrt(projVelDirSquared) - velDir); else t_collision = 0; // speed of projectile is not enough to reach moving target - return vTargetPos + vTargetMoveDir * t_collision - vActorPos; + return vDirToTarget + vTargetMoveDir * t_collision; } } diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index ee9378ea4..db8da2886 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -107,6 +107,7 @@ namespace MWPhysics bool isOnGround (const MWWorld::Ptr& actor); + /// Get physical half extents (scaled) of the given actor. osg::Vec3f getHalfExtents(const MWWorld::Ptr& actor); /// Queues velocity movement for a Ptr. If a Ptr is already queued, its velocity will diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index f50991e24..b3e1c6ecb 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1018,14 +1018,11 @@ namespace MWWorld return facedObject; } - std::pair World::getHitContact(const MWWorld::Ptr &ptr, float distance) + osg::Vec3f getActorHeadPosition(const MWWorld::Ptr& actor, MWRender::RenderingManager* rendering) { - const ESM::Position &posdata = ptr.getRefData().getPosition(); - - osg::Quat rot = osg::Quat(posdata.rot[0], osg::Vec3f(-1,0,0)) * osg::Quat(posdata.rot[2], osg::Vec3f(0,0,-1)); - osg::Vec3f pos (posdata.asVec3()); + osg::Vec3f origin(actor.getRefData().getPosition().asVec3()); - MWRender::Animation* anim = mRendering->getAnimation(ptr); + MWRender::Animation* anim = rendering->getAnimation(actor); if (anim != NULL) { const osg::Node* node = anim->getNode("Head"); @@ -1035,9 +1032,18 @@ namespace MWWorld { osg::MatrixList mats = node->getWorldMatrices(); if (mats.size()) - pos = mats[0].getTrans(); + origin = mats[0].getTrans(); } } + return origin; + } + + std::pair World::getHitContact(const MWWorld::Ptr &ptr, float distance) + { + const ESM::Position &posdata = ptr.getRefData().getPosition(); + + osg::Quat rot = osg::Quat(posdata.rot[0], osg::Vec3f(-1,0,0)) * osg::Quat(posdata.rot[2], osg::Vec3f(0,0,-1)); + osg::Vec3f pos = getActorHeadPosition(ptr, mRendering); std::pair result = mPhysics->getHitContact(ptr, pos, rot, distance); if(result.first.isEmpty()) @@ -2608,21 +2614,7 @@ namespace MWWorld MWWorld::Ptr target; float distance = 192.f; // ?? osg::Vec3f hitPosition = actor.getRefData().getPosition().asVec3(); - osg::Vec3f origin(actor.getRefData().getPosition().asVec3()); - - MWRender::Animation* anim = mRendering->getAnimation(actor); - if (anim != NULL) - { - const osg::Node* node = anim->getNode("Head"); - if (node == NULL) - node = anim->getNode("Bip01 Head"); - if (node != NULL) - { - osg::MatrixList mats = node->getWorldMatrices(); - if (mats.size()) - origin = mats[0].getTrans(); - } - } + osg::Vec3f origin = getActorHeadPosition(actor, mRendering); osg::Quat orient = osg::Quat(actor.getRefData().getPosition().rot[0], osg::Vec3f(-1,0,0)) * osg::Quat(actor.getRefData().getPosition().rot[2], osg::Vec3f(0,0,-1)); @@ -3262,4 +3254,12 @@ namespace MWWorld return true; return false; } + + osg::Vec3f World::aimToTarget(const Ptr &actor, const MWWorld::Ptr& target) + { + osg::Vec3f weaponPos = getActorHeadPosition(actor, mRendering); + osg::Vec3f targetPos = target.getRefData().getPosition().asVec3(); + targetPos.z() += mPhysics->getHalfExtents(target).z(); + return (targetPos - weaponPos); + } } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 241dacc8a..26153086a 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -630,6 +630,10 @@ namespace MWWorld virtual void resetActors(); virtual bool isWalkingOnWater (const MWWorld::Ptr& actor); + + /// Return a vector aiming the actor's weapon towards a target. + /// @note The length of the vector is the distance between actor and target. + virtual osg::Vec3f aimToTarget(const MWWorld::Ptr& actor, const MWWorld::Ptr& target); }; } From a7f898057ba345d1c06f1f9071f1e067ab02bda4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 17 Sep 2015 04:30:55 +0200 Subject: [PATCH 2175/3725] Don't activate the initial death animation when skipAnim is set (Fixes #2513) --- apps/openmw/mwmechanics/character.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 3837e9a75..e80d6f4d0 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -701,8 +701,9 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim mIdleState = CharState_Idle; else { - int deathindex = mPtr.getClass().getCreatureStats(mPtr).getDeathAnimation(); - playDeath(1.0f, CharacterState(CharState_Death1 + deathindex)); + // Set the death state, but don't play it yet + // We will play it in the first frame, but only if no script set the skipAnim flag + mDeathState = static_cast(CharState_Death1 + mPtr.getClass().getCreatureStats(mPtr).getDeathAnimation()); } } else @@ -1835,6 +1836,13 @@ void CharacterController::update(float duration) } else if(cls.getCreatureStats(mPtr).isDead()) { + // initial start of death animation for actors that started the game as dead + // not done in constructor since we need to give scripts a chance to set the mSkipAnim flag + if (!mSkipAnim && mDeathState != CharState_None && mCurrentDeath.empty()) + { + playDeath(1.f, mDeathState); + } + world->queueMovement(mPtr, osg::Vec3f(0.f, 0.f, 0.f)); } From 56163dcb2a33fdf67bd78dc63a6134c4f408505a Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 17 Sep 2015 09:39:42 +0200 Subject: [PATCH 2176/3725] updated credits file --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index 16c888239..8e9d35cf2 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -113,6 +113,7 @@ Programmers viadanna Vincent Heuken vocollapse + zelurker Manual ------ From b3b4fb3efbaf84a31b9a62203f9767b08328b671 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 17 Sep 2015 11:27:55 +0200 Subject: [PATCH 2177/3725] removed some left-over signal slot stuff that shouldn't have been there in the first place --- apps/opencs/view/world/scenesubview.cpp | 7 ------- apps/opencs/view/world/scenesubview.hpp | 8 -------- 2 files changed, 15 deletions(-) diff --git a/apps/opencs/view/world/scenesubview.cpp b/apps/opencs/view/world/scenesubview.cpp index 2ca2548c0..b698d9034 100644 --- a/apps/opencs/view/world/scenesubview.cpp +++ b/apps/opencs/view/world/scenesubview.cpp @@ -247,8 +247,6 @@ void CSVWorld::SceneSubView::replaceToolbarAndWorldspace (CSVRender::WorldspaceW mToolbar = toolbar; connect (mScene, SIGNAL (focusToolbarRequest()), mToolbar, SLOT (setFocus())); - connect (this, SIGNAL (updateSceneUserSetting(const QString &, const QStringList &)), - mScene, SLOT (updateUserSetting(const QString &, const QStringList &))); connect (mToolbar, SIGNAL (focusSceneRequest()), mScene, SLOT (setFocus())); mLayout->addWidget (mToolbar, 0); @@ -257,8 +255,3 @@ void CSVWorld::SceneSubView::replaceToolbarAndWorldspace (CSVRender::WorldspaceW mScene->selectDefaultNavigationMode(); setFocusProxy (mScene); } - -void CSVWorld::SceneSubView::updateUserSetting (const QString &key, const QStringList &list) -{ - emit updateSceneUserSetting(key, list); -} diff --git a/apps/opencs/view/world/scenesubview.hpp b/apps/opencs/view/world/scenesubview.hpp index fc45347d0..65aaca999 100644 --- a/apps/opencs/view/world/scenesubview.hpp +++ b/apps/opencs/view/world/scenesubview.hpp @@ -83,14 +83,6 @@ namespace CSVWorld void cellSelectionChanged (const CSMWorld::UniversalId& id); void handleDrop(const std::vector& data); - - public slots: - - void updateUserSetting (const QString &, const QStringList &); - - signals: - - void updateSceneUserSetting (const QString &, const QStringList &); }; } From 659b87b25faec71089ae5f8b96b4283d58abaab7 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 17 Sep 2015 11:31:25 +0200 Subject: [PATCH 2178/3725] more cleanup --- apps/opencs/view/doc/view.hpp | 3 --- apps/opencs/view/world/scenesubview.cpp | 5 ----- apps/opencs/view/world/scenesubview.hpp | 2 -- 3 files changed, 10 deletions(-) diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index adda73526..2dd717440 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -115,9 +115,6 @@ namespace CSVDoc Operations *getOperations() const; - /// Function called by view manager when user preferences are updated - void updateEditorSetting (const QString &, const QString &); - signals: void newGameRequest(); diff --git a/apps/opencs/view/world/scenesubview.cpp b/apps/opencs/view/world/scenesubview.cpp index b698d9034..c2f3442f8 100644 --- a/apps/opencs/view/world/scenesubview.cpp +++ b/apps/opencs/view/world/scenesubview.cpp @@ -132,11 +132,6 @@ void CSVWorld::SceneSubView::setEditLock (bool locked) } -void CSVWorld::SceneSubView::updateEditorSetting(const QString &settingName, const QString &settingValue) -{ - -} - void CSVWorld::SceneSubView::setStatusBar (bool show) { mBottom->setStatusBar (show); diff --git a/apps/opencs/view/world/scenesubview.hpp b/apps/opencs/view/world/scenesubview.hpp index 65aaca999..a34d71901 100644 --- a/apps/opencs/view/world/scenesubview.hpp +++ b/apps/opencs/view/world/scenesubview.hpp @@ -52,8 +52,6 @@ namespace CSVWorld virtual void setEditLock (bool locked); - virtual void updateEditorSetting (const QString& key, const QString& value); - virtual void setStatusBar (bool show); virtual void useHint (const std::string& hint); From 1aa926c7e0e151e2744ab90174d8b62caacb9dfe Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 17 Sep 2015 12:41:56 +0200 Subject: [PATCH 2179/3725] restored T-shortcut (focus toolbar) in scene widget --- apps/opencs/view/render/scenewidget.cpp | 4 ++++ apps/opencs/view/render/scenewidget.hpp | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index d91c075e1..59cc71855 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -143,6 +143,10 @@ SceneWidget::SceneWidget(boost::shared_ptr resourceSys mView->setLightingMode(osgViewer::View::NO_LIGHT); setLighting(&mLightingDay); + + /// \todo make shortcut configurable + QShortcut *focusToolbar = new QShortcut (Qt::Key_T, this, 0, 0, Qt::WidgetWithChildrenShortcut); + connect (focusToolbar, SIGNAL (activated()), this, SIGNAL (focusToolbarRequest())); } SceneWidget::~SceneWidget() diff --git a/apps/opencs/view/render/scenewidget.hpp b/apps/opencs/view/render/scenewidget.hpp index f5c36b641..54f001c15 100644 --- a/apps/opencs/view/render/scenewidget.hpp +++ b/apps/opencs/view/render/scenewidget.hpp @@ -88,6 +88,10 @@ namespace CSVRender private slots: void selectLightingMode (const std::string& mode); + + signals: + + void focusToolbarRequest(); }; From 169fc6a61b2c2d2eed99c3e28156d53367e9312a Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Sep 2015 18:29:22 +0200 Subject: [PATCH 2180/3725] OpenCS: Remove margin around the render window --- apps/opencs/view/render/scenewidget.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index 59cc71855..0a5087998 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -52,6 +52,7 @@ RenderWidget::RenderWidget(QWidget *parent, Qt::WindowFlags f) osg::ref_ptr window = new osgQt::GraphicsWindowQt(traits.get()); QLayout* layout = new QHBoxLayout(this); + layout->setContentsMargins(0, 0, 0, 0); layout->addWidget(window->getGLWidget()); setLayout(layout); From dac3b33efba7872ab5ff1f458e3248632e4d2edf Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Sep 2015 18:29:40 +0200 Subject: [PATCH 2181/3725] OpenCS: Pass events from the QGLWidget to the RenderWidget --- apps/opencs/view/render/scenewidget.cpp | 21 +++++++++++++++++++++ apps/opencs/view/render/scenewidget.hpp | 2 ++ 2 files changed, 23 insertions(+) diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index 0a5087998..fb3bcb3c3 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -56,6 +56,9 @@ RenderWidget::RenderWidget(QWidget *parent, Qt::WindowFlags f) layout->addWidget(window->getGLWidget()); setLayout(layout); + // Pass events through this widget first + window->getGLWidget()->installEventFilter(this); + mView->getCamera()->setGraphicsContext(window); mView->getCamera()->setClearColor( osg::Vec4(0.2, 0.2, 0.6, 1.0) ); mView->getCamera()->setViewport( new osg::Viewport(0, 0, traits->width, traits->height) ); @@ -94,6 +97,24 @@ void RenderWidget::setVisibilityMask(int mask) mView->getCamera()->setCullMask(mask<<1); } +bool RenderWidget::eventFilter(QObject* obj, QEvent* event) +{ + // handle event in this widget, is there a better way to do this? + if (event->type() == QEvent::MouseButtonPress) + mousePressEvent(static_cast(event)); + if (event->type() == QEvent::MouseButtonRelease) + mouseReleaseEvent(static_cast(event)); + if (event->type() == QEvent::MouseMove) + mouseMoveEvent(static_cast(event)); + if (event->type() == QEvent::KeyPress) + keyPressEvent(static_cast(event)); + if (event->type() == QEvent::KeyRelease) + keyReleaseEvent(static_cast(event)); + + // Always pass the event on to GLWidget, i.e. to OSG event queue + return QObject::eventFilter(obj, event); +} + // -------------------------------------------------- CompositeViewer::CompositeViewer() diff --git a/apps/opencs/view/render/scenewidget.hpp b/apps/opencs/view/render/scenewidget.hpp index 54f001c15..63da01a45 100644 --- a/apps/opencs/view/render/scenewidget.hpp +++ b/apps/opencs/view/render/scenewidget.hpp @@ -45,6 +45,8 @@ namespace CSVRender void setVisibilityMask(int mask); + bool eventFilter(QObject *, QEvent *); + protected: osg::ref_ptr mView; From 41ea76fd836eb956b9a7517c2181181c7c8ea115 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Sep 2015 18:31:05 +0200 Subject: [PATCH 2182/3725] OpenCS: Add selection outline effect to CSVRender::Object --- apps/opencs/view/render/object.cpp | 26 +++++++++++++++++++++++++- apps/opencs/view/render/object.hpp | 28 ++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index 973893a71..f05e311f9 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -10,6 +10,8 @@ #include #include +#include + #include "../../model/world/data.hpp" #include "../../model/world/ref.hpp" #include "../../model/world/refidcollection.hpp" @@ -116,9 +118,14 @@ const CSMWorld::CellRef& CSVRender::Object::getReference() const CSVRender::Object::Object (CSMWorld::Data& data, osg::Group* parentNode, const std::string& id, bool referenceable, bool forceBaseToZero) -: mData (data), mBaseNode(0), mParentNode(parentNode), mResourceSystem(data.getResourceSystem().get()), mForceBaseToZero (forceBaseToZero) +: mData (data), mBaseNode(0), mSelected(false), mParentNode(parentNode), mResourceSystem(data.getResourceSystem().get()), mForceBaseToZero (forceBaseToZero) { mBaseNode = new osg::PositionAttitudeTransform; + mOutline = new osgFX::Scribe; + mOutline->addChild(mBaseNode); + + mBaseNode->setUserData(new ObjectHolder(this)); + parentNode->addChild(mBaseNode); // 0x1 reserved for separating cull and update visitors @@ -145,6 +152,23 @@ CSVRender::Object::~Object() mParentNode->removeChild(mBaseNode); } +void CSVRender::Object::setSelected(bool selected) +{ + mSelected = selected; + + mParentNode->removeChild(mOutline); + mParentNode->removeChild(mBaseNode); + if (selected) + mParentNode->addChild(mOutline); + else + mParentNode->addChild(mBaseNode); +} + +bool CSVRender::Object::getSelected() const +{ + return mSelected; +} + bool CSVRender::Object::referenceableDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) { diff --git a/apps/opencs/view/render/object.hpp b/apps/opencs/view/render/object.hpp index 9f411ffc6..9b3749069 100644 --- a/apps/opencs/view/render/object.hpp +++ b/apps/opencs/view/render/object.hpp @@ -6,6 +6,7 @@ #include #include +#include class QModelIndex; @@ -16,6 +17,11 @@ namespace osg class Group; } +namespace osgFX +{ + class Scribe; +} + namespace Resource { class ResourceSystem; @@ -29,12 +35,29 @@ namespace CSMWorld namespace CSVRender { + + class Object; + + // An object to attach as user data to the osg::Node, allows us to get an Object back from a Node when we are doing a ray query + class ObjectHolder : public osg::Referenced + { + public: + ObjectHolder(Object* obj) + : mObject(obj) + { + } + + Object* mObject; + }; + class Object { const CSMWorld::Data& mData; std::string mReferenceId; std::string mReferenceableId; osg::ref_ptr mBaseNode; + osg::ref_ptr mOutline; + bool mSelected; osg::Group* mParentNode; Resource::ResourceSystem* mResourceSystem; bool mForceBaseToZero; @@ -68,6 +91,11 @@ namespace CSVRender ~Object(); + /// Mark the object as selected, selected objects show an outline effect + void setSelected(bool selected); + + bool getSelected() const; + /// \return Did this call result in a modification of the visual representation of /// this object? bool referenceableDataChanged (const QModelIndex& topLeft, From 18d0cae801e77f9c10dc4f26124b32e5372697e1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Sep 2015 18:31:33 +0200 Subject: [PATCH 2183/3725] OpenCS: Select objects with the right mouse button --- apps/opencs/view/render/worldspacewidget.cpp | 48 ++++++++++++++++++-- 1 file changed, 45 insertions(+), 3 deletions(-) diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index d45fc45a8..a1f0f6bf2 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -1,6 +1,7 @@ #include "worldspacewidget.hpp" #include +#include #include #include @@ -12,6 +13,8 @@ #include #include +#include + #include "../../model/world/universalid.hpp" #include "../../model/world/idtable.hpp" @@ -19,6 +22,7 @@ #include "../widget/scenetooltoggle2.hpp" #include "../widget/scenetoolrun.hpp" +#include "object.hpp" #include "elements.hpp" #include "editmode.hpp" @@ -370,11 +374,49 @@ void CSVRender::WorldspaceWidget::mouseMoveEvent (QMouseEvent *event) void CSVRender::WorldspaceWidget::mousePressEvent (QMouseEvent *event) { - if(event->buttons() & Qt::RightButton) + if (event->button() != Qt::RightButton) + return; + + // (0,0) is considered the lower left corner of an OpenGL window + int x = event->x(); + int y = height() - event->y(); + + osg::ref_ptr intersector (new osgUtil::LineSegmentIntersector(osgUtil::Intersector::WINDOW, x, y)); + + intersector->setIntersectionLimit(osgUtil::LineSegmentIntersector::NO_LIMIT); + osgUtil::IntersectionVisitor visitor(intersector); + + visitor.setTraversalMask(getInteractionMask() << 1); + + mView->getCamera()->accept(visitor); + + for (osgUtil::LineSegmentIntersector::Intersections::iterator it = intersector->getIntersections().begin(); + it != intersector->getIntersections().end(); ++it) { - //mMouse->mousePressEvent(event); + osgUtil::LineSegmentIntersector::Intersection intersection = *it; + + // reject back-facing polygons + osg::Vec3f normal = intersection.getWorldIntersectNormal(); + normal = osg::Matrix::transform3x3(normal, mView->getCamera()->getViewMatrix()); + if (normal.z() < 0) + continue; + + for (std::vector::iterator it = intersection.nodePath.begin(); it != intersection.nodePath.end(); ++it) + { + osg::Node* node = *it; + if (CSVRender::ObjectHolder* holder = dynamic_cast(node->getUserData())) + { + // hit an Object, toggle its selection state + CSVRender::Object* obj = holder->mObject; + obj->setSelected(!obj->getSelected()); + return; + } + } + + // must be terrain, report coordinates + std::cout << "Terrain hit at " << intersection.getWorldIntersectPoint().x() << " " << intersection.getWorldIntersectPoint().y() << std::endl; + return; } - //SceneWidget::mousePressEvent(event); } void CSVRender::WorldspaceWidget::mouseReleaseEvent (QMouseEvent *event) From a37dee09e2f074a76ce1b2c38c1473b3a3e03334 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Sep 2015 21:29:32 +0200 Subject: [PATCH 2184/3725] Fix invisibility effect disappearing after a view mode switch --- apps/openmw/mwrender/animation.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 24d540e20..37ec4c213 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -935,8 +935,10 @@ namespace MWRender void Animation::setObjectRoot(const std::string &model, bool forceskeleton, bool baseonly, bool isCreature) { + osg::ref_ptr previousStateset; if (mObjectRoot) { + previousStateset = mObjectRoot->getStateSet(); mObjectRoot->getParent(0)->removeChild(mObjectRoot); } mObjectRoot = NULL; @@ -961,6 +963,9 @@ namespace MWRender mObjectRoot = newObjectRoot; } + if (previousStateset) + mObjectRoot->setStateSet(previousStateset); + if (baseonly) { RemoveDrawableVisitor removeDrawableVisitor; From 5369d206822def39fac0d6b7674fb8e1537cb82d Mon Sep 17 00:00:00 2001 From: dteviot Date: Sat, 19 Sep 2015 15:34:02 +1200 Subject: [PATCH 2185/3725] Moved pathfinding logic from AiCombat to Pathfinding. --- apps/openmw/mwmechanics/aicombat.cpp | 24 +++--------------------- apps/openmw/mwmechanics/pathfinding.cpp | 11 +++++++++++ 2 files changed, 14 insertions(+), 21 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index b42c3bdcc..6270779a4 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -458,28 +458,10 @@ namespace MWMechanics followTarget = false; - buildNewPath(actor, target); //may fail to build a path, check before use + buildNewPath(actor, target); - // if current actor pos is closer to target then last point of path (excluding target itself) then go straight on target - // This works on the borders between the path grid and areas with no waypoints. - if(inLOS && mPathFinder.getPath().size() > 1) - { - // get point just before target - std::list::const_iterator pntIter = --mPathFinder.getPath().end(); - --pntIter; - osg::Vec3f vBeforeTarget(PathFinder::MakeOsgVec3(*pntIter)); - - if(distToTarget <= (vTargetPos - vBeforeTarget).length()) - { - mPathFinder.clearPath(); - } - } - - // if there is no new path, then go straight on target - if (!mPathFinder.isPathConstructed()) - { - movement.mRotation[2] = getZAngleToDir((vTargetPos-vActorPos)); - } + // should always return a path (even if it's just go straight on target.) + assert(mPathFinder.isPathConstructed()); } if (readyToAttack) diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index f26d3e109..dbe20fdc0 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -215,6 +215,17 @@ namespace MWMechanics endPointInLocalCoords, startNode); + // if it's shorter for actor to travel from start to end, than to travel from either + // start or end to nearest pathgrid point, just travel from start to end. + float startToEndLength2 = (endPointInLocalCoords - startPointInLocalCoords).length2(); + float endTolastNodeLength2 = distanceSquared(mPathgrid->mPoints[endNode.first], endPointInLocalCoords); + float startTo1stNodeLength2 = distanceSquared(mPathgrid->mPoints[startNode], startPointInLocalCoords); + if ((startToEndLength2 < startTo1stNodeLength2) || (startToEndLength2 < endTolastNodeLength2)) + { + mPath.push_back(endPoint); + return; + } + // AiWander has logic that depends on whether a path was created, // deleting allowed nodes if not. Hence a path needs to be created // even if the start and the end points are the same. From 60d0ad928386e4d77aa08add8e763fcc4c9ab170 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sat, 19 Sep 2015 16:14:00 +1200 Subject: [PATCH 2186/3725] When stuck, try moving backwards as well as to side. --- apps/openmw/mwmechanics/obstacle.cpp | 20 ++++++++++++++++---- apps/openmw/mwmechanics/obstacle.hpp | 7 ++++++- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/obstacle.cpp b/apps/openmw/mwmechanics/obstacle.cpp index fe3d68a58..53f12a982 100644 --- a/apps/openmw/mwmechanics/obstacle.cpp +++ b/apps/openmw/mwmechanics/obstacle.cpp @@ -15,6 +15,14 @@ namespace MWMechanics static const float DURATION_SAME_SPOT = 1.0f; static const float DURATION_TO_EVADE = 0.4f; + const float ObstacleCheck::evadeDirections[NUM_EVADE_DIRECTIONS][2] = + { + { 1.0f, 0.0f }, // move to side + { 1.0f, -1.0f }, // move to side and backwards + { -1.0f, 0.0f }, // move to other side + { -1.0f, -1.0f } // move to side and backwards + }; + // Proximity check function for interior doors. Given that most interior cells // do not have many doors performance shouldn't be too much of an issue. // @@ -69,7 +77,7 @@ namespace MWMechanics , mStuckDuration(0) , mEvadeDuration(0) , mDistSameSpot(-1) // avoid calculating it each time - , mEvadeDirection(1.0f) + , mEvadeDirectionIndex(0) { } @@ -176,8 +184,8 @@ namespace MWMechanics void ObstacleCheck::takeEvasiveAction(MWMechanics::Movement& actorMovement) { - actorMovement.mPosition[0] = mEvadeDirection; - actorMovement.mPosition[1] = 0; + actorMovement.mPosition[0] = evadeDirections[mEvadeDirectionIndex][0]; + actorMovement.mPosition[1] = evadeDirections[mEvadeDirectionIndex][1]; } void ObstacleCheck::chooseEvasionDirection(bool samePosition) @@ -185,7 +193,11 @@ namespace MWMechanics // change direction if attempt didn't work if (samePosition && (0 < mEvadeDuration)) { - mEvadeDirection = mEvadeDirection == 1.0f ? -1.0f : 1.0f; + ++mEvadeDirectionIndex; + if (mEvadeDirectionIndex == NUM_EVADE_DIRECTIONS) + { + mEvadeDirectionIndex = 0; + } } } diff --git a/apps/openmw/mwmechanics/obstacle.hpp b/apps/openmw/mwmechanics/obstacle.hpp index ef3e29e8b..ecff00a5c 100644 --- a/apps/openmw/mwmechanics/obstacle.hpp +++ b/apps/openmw/mwmechanics/obstacle.hpp @@ -13,6 +13,8 @@ namespace MWMechanics /// NOTE: determined empirically based on in-game behaviour static const float MIN_DIST_TO_DOOR_SQUARED = 128*128; + static const int NUM_EVADE_DIRECTIONS = 4; + /// tests actor's proximity to a closed door by default bool proximityToDoor(const MWWorld::Ptr& actor, float minSqr = MIN_DIST_TO_DOOR_SQUARED, @@ -47,6 +49,9 @@ namespace MWMechanics float mPrevX; float mPrevY; + // directions to try moving in when get stuck + static const float evadeDirections[NUM_EVADE_DIRECTIONS][2]; + enum WalkState { State_Norm, @@ -58,7 +63,7 @@ namespace MWMechanics float mStuckDuration; // accumulate time here while in same spot float mEvadeDuration; float mDistSameSpot; // take account of actor's speed - float mEvadeDirection; + int mEvadeDirectionIndex; void chooseEvasionDirection(bool samePosition); }; From 8de3ce90a7e0d219137eaf61ec120c24f8419c2c Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 19 Sep 2015 18:04:24 +0200 Subject: [PATCH 2187/3725] Add comments for weather IDs --- apps/openmw/mwworld/weather.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index cdd0a8d79..b0e617f2b 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -458,16 +458,16 @@ WeatherManager::WeatherManager(MWRender::RenderingManager& rendering, const MWWo , mPlayingSoundID() { mWeatherSettings.reserve(10); - addWeather("Clear", fallback); - addWeather("Cloudy", fallback); - addWeather("Foggy", fallback); - addWeather("Overcast", fallback); - addWeather("Rain", fallback, "rain"); - addWeather("Thunderstorm", fallback, "rain heavy"); - addWeather("Ashstorm", fallback, "ashstorm", "meshes\\ashcloud.nif"); - addWeather("Blight", fallback, "blight", "meshes\\blightcloud.nif"); - addWeather("Snow", fallback, "", "meshes\\snow.nif"); - addWeather("Blizzard", fallback, "BM Blizzard", "meshes\\blizzard.nif"); + addWeather("Clear", fallback); // 0 + addWeather("Cloudy", fallback); // 1 + addWeather("Foggy", fallback); // 2 + addWeather("Overcast", fallback); // 3 + addWeather("Rain", fallback, "rain"); // 4 + addWeather("Thunderstorm", fallback, "rain heavy"); // 5 + addWeather("Ashstorm", fallback, "ashstorm", "meshes\\ashcloud.nif"); // 6 + addWeather("Blight", fallback, "blight", "meshes\\blightcloud.nif"); // 7 + addWeather("Snow", fallback, "", "meshes\\snow.nif"); // 8 + addWeather("Blizzard", fallback, "BM Blizzard", "meshes\\blizzard.nif"); // 9 Store::iterator it = store.get().begin(); for(; it != store.get().end(); ++it) From 39b73405800bd3409184a894a0d899ba28904c41 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 21 Sep 2015 15:32:18 +0200 Subject: [PATCH 2188/3725] added mouse button settings for 3D scene (not in use yet) --- apps/opencs/model/settings/usersettings.cpp | 35 +++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/apps/opencs/model/settings/usersettings.cpp b/apps/opencs/model/settings/usersettings.cpp index 24680ada3..3daf7f9ec 100644 --- a/apps/opencs/model/settings/usersettings.cpp +++ b/apps/opencs/model/settings/usersettings.cpp @@ -371,6 +371,41 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() "list go to the first/last item"); } + declareSection ("scene-input", "3D Scene Input"); + { + QString left ("Left Mouse-Button"); + QString cLeft ("Ctrl-Left Mouse-Button"); + QString right ("Right Mouse-Button"); + QString cRight ("Ctrl-Right Mouse-Button"); + QString middle ("Middle Mouse-Button"); + QString cMiddle ("Ctrl-Middle Mouse-Button"); + + QStringList values; + values << left << cLeft << right << cRight << middle << cMiddle; + + Setting *primaryNavigation = createSetting (Type_ComboBox, "p-navi", "Primary Camera Navigation Button"); + primaryNavigation->setDeclaredValues (values); + primaryNavigation->setDefaultValue (left); + + Setting *secondaryNavigation = createSetting (Type_ComboBox, "s-navi", "Secondary Camera Navigation Button"); + secondaryNavigation->setDeclaredValues (values); + secondaryNavigation->setDefaultValue (cLeft); + + Setting *primaryEditing = createSetting (Type_ComboBox, "p-edit", "Primary Editing Button"); + primaryEditing->setDeclaredValues (values); + primaryEditing->setDefaultValue (right); + + Setting *secondaryEditing = createSetting (Type_ComboBox, "s-edit", "Secondary Editing Button"); + secondaryEditing->setDeclaredValues (values); + secondaryEditing->setDefaultValue (cRight); + + values << "Context Sensitive"; + + Setting *selection = createSetting (Type_ComboBox, "select", "Selection Button"); + selection->setDeclaredValues (values); + selection->setDefaultValue (middle); + } + { /****************************************************************** * There are three types of values: From 6bafa564d4b96a7336490d6ea4be8b96438ee72b Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 19 Sep 2015 18:08:31 +0200 Subject: [PATCH 2189/3725] Move sun texture setting out of the Updater class so we can reuse the Updater for fading the flash texture --- apps/openmw/mwrender/sky.cpp | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index dba2e5b0e..67e842c8d 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -359,14 +359,20 @@ class Sun : public CelestialBody public: Sun(osg::Group* parentNode, Resource::TextureManager& textureManager) : CelestialBody(parentNode, 1.0f, 1) - , mUpdater(new Updater(textureManager)) + , mUpdater(new Updater) { - mGeode->addUpdateCallback(mUpdater); + mTransform->addUpdateCallback(mUpdater); + + osg::ref_ptr sunTex = textureManager.getTexture2D("textures/tx_sun_05.dds", + osg::Texture::CLAMP, + osg::Texture::CLAMP); + + mGeode->getOrCreateStateSet()->setTextureAttributeAndModes(0, sunTex, osg::StateAttribute::ON); } ~Sun() { - mGeode->removeUpdateCallback(mUpdater); + mTransform->removeUpdateCallback(mUpdater); } virtual void adjustTransparency(const float ratio) @@ -387,22 +393,15 @@ public: private: struct Updater : public SceneUtil::StateSetUpdater { - Resource::TextureManager& mTextureManager; osg::Vec4f mColor; - Updater(Resource::TextureManager& textureManager) - : mTextureManager(textureManager) - , mColor(0.0f, 0.0f, 0.0f, 1.0f) + Updater() + : mColor(1.f, 1.f, 1.f, 1.0f) { } virtual void setDefaults(osg::StateSet* stateset) { - osg::ref_ptr tex = mTextureManager.getTexture2D("textures/tx_sun_05.dds", - osg::Texture::CLAMP, - osg::Texture::CLAMP); - - stateset->setTextureAttributeAndModes(0, tex, osg::StateAttribute::ON); stateset->setAttributeAndModes(createUnlitMaterial(), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); } From d191a528470b990be094bf243b697694ad159dda Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 19 Sep 2015 18:10:02 +0200 Subject: [PATCH 2190/3725] Create occlusion query nodes for the sun flash --- apps/openmw/mwrender/sky.cpp | 57 ++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 67e842c8d..3d2b35c37 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -11,6 +11,9 @@ #include #include #include +#include +#include +#include #include #include @@ -368,6 +371,18 @@ public: osg::Texture::CLAMP); mGeode->getOrCreateStateSet()->setTextureAttributeAndModes(0, sunTex, osg::StateAttribute::ON); + + // Slightly downscale the query geometry since the sun quad has a transparent texture that doesn't cover the whole area + osg::ref_ptr queryTransform (new osg::PositionAttitudeTransform); + queryTransform->setScale(osg::Vec3f(0.5f, 0.5f, 0.5f)); + // Need to render after the world geometry so we can correctly test for occlusions + queryTransform->getOrCreateStateSet()->setRenderBinDetails(10, "RenderBin"); + queryTransform->getOrCreateStateSet()->setNestRenderBins(false); + + mTransform->addChild(queryTransform); + + mOcclusionQueryVisiblePixels = createOcclusionQueryNode(queryTransform, true); + mOcclusionQueryTotalPixels = createOcclusionQueryNode(queryTransform, false); } ~Sun() @@ -391,6 +406,46 @@ public: } private: + /// @param queryVisible If true, queries the amount of visible pixels. If false, queries the total amount of pixels. + osg::ref_ptr createOcclusionQueryNode(osg::Group* parent, bool queryVisible) + { + osg::ref_ptr oqn = new osg::OcclusionQueryNode; + oqn->setQueriesEnabled(true); + + // Make it fast! A DYNAMIC query geometry means we can't break frame until the flare is rendered (which is rendered after all the other geometry, + // so that would be pretty bad). STATIC should be safe, since our node's local bounds are static, thus computeBounds() which modifies the queryGeometry + // is only called once. + // Note the debug geometry setDebugDisplay(true) is always DYNAMIC and that can't be changed, not a big deal. + oqn->getQueryGeometry()->setDataVariance(osg::Object::STATIC); + + osg::ref_ptr queryGeode = osg::clone(mGeode.get(), osg::CopyOp::DEEP_COPY_ALL); + // Disable writing to the color buffer. We are using this geode for visibility tests only. + osg::ref_ptr colormask (new osg::ColorMask(0, 0, 0, 0)); + queryGeode->getOrCreateStateSet()->setAttributeAndModes(colormask, osg::StateAttribute::ON); + + oqn->addChild(queryGeode); + + if (queryVisible) + { + osg::ref_ptr depth (new osg::Depth); + depth->setFunction(osg::Depth::LESS); + // This is a trick to make fragments written by the query always use the maximum depth value, + // without having to retrieve the current far clipping distance. + // We want the sun glare to be "infinitely" far away. + depth->setZNear(1.0); + depth->setZFar(1.0); + oqn->getQueryStateSet()->setAttributeAndModes(depth, osg::StateAttribute::ON); + } + else + { + oqn->getQueryStateSet()->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF); + } + + parent->addChild(oqn); + + return oqn; + } + struct Updater : public SceneUtil::StateSetUpdater { osg::Vec4f mColor; @@ -414,6 +469,8 @@ private: }; osg::ref_ptr mUpdater; + osg::ref_ptr mOcclusionQueryVisiblePixels; + osg::ref_ptr mOcclusionQueryTotalPixels; }; class Moon : public CelestialBody From 89d9323c2b6d870d7ea5d0b3d33a84a834916ef5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 19 Sep 2015 18:19:36 +0200 Subject: [PATCH 2191/3725] Document RenderBin numbers in a common header to keep them organised --- apps/openmw/CMakeLists.txt | 1 + apps/openmw/mwrender/renderbin.hpp | 20 ++++++++++++++++++++ apps/openmw/mwrender/sky.cpp | 5 +++-- apps/openmw/mwrender/water.cpp | 3 ++- 4 files changed, 26 insertions(+), 3 deletions(-) create mode 100644 apps/openmw/mwrender/renderbin.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 2dd16a4e6..5a9b52cb2 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -23,6 +23,7 @@ add_openmw_dir (mwrender actors objects renderingmanager animation rotatecontroller sky npcanimation vismask creatureanimation effectmanager util renderinginterface pathgrid rendermode weaponanimation bulletdebugdraw globalmap characterpreview camera localmap water terrainstorage ripplesimulation + renderbin ) add_openmw_dir (mwinput diff --git a/apps/openmw/mwrender/renderbin.hpp b/apps/openmw/mwrender/renderbin.hpp new file mode 100644 index 000000000..63ccdd259 --- /dev/null +++ b/apps/openmw/mwrender/renderbin.hpp @@ -0,0 +1,20 @@ +#ifndef OPENMW_MWRENDER_RENDERBIN_H +#define OPENMW_MWRENDER_RENDERBIN_H + +namespace MWRender +{ + + /// Defines the render bin numbers used in the OpenMW scene graph. The bin with the lowest number is rendered first. + /// Beware of RenderBin nesting, in most cases you will want to use setNestRenderBins(false). + enum RenderBins + { + RenderBin_Sky = -1, + RenderBin_Default = 0, + RenderBin_Water = 9, + RenderBin_OcclusionQuery = 10, + RenderBin_SunGlare = 11 + }; + +} + +#endif diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 3d2b35c37..8588d2158 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -41,6 +41,7 @@ #include "../mwworld/fallback.hpp" #include "vismask.hpp" +#include "renderbin.hpp" namespace { @@ -376,7 +377,7 @@ public: osg::ref_ptr queryTransform (new osg::PositionAttitudeTransform); queryTransform->setScale(osg::Vec3f(0.5f, 0.5f, 0.5f)); // Need to render after the world geometry so we can correctly test for occlusions - queryTransform->getOrCreateStateSet()->setRenderBinDetails(10, "RenderBin"); + queryTransform->getOrCreateStateSet()->setRenderBinDetails(RenderBin_OcclusionQuery, "RenderBin"); queryTransform->getOrCreateStateSet()->setNestRenderBins(false); mTransform->addChild(queryTransform); @@ -680,7 +681,7 @@ SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneMana mRootNode = skyroot; // By default render before the world is rendered - mRootNode->getOrCreateStateSet()->setRenderBinDetails(-1, "RenderBin"); + mRootNode->getOrCreateStateSet()->setRenderBinDetails(RenderBin_Sky, "RenderBin"); } void SkyManager::create() diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index b5f141963..03ab58e6b 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -21,6 +21,7 @@ #include "vismask.hpp" #include "ripplesimulation.hpp" +#include "renderbin.hpp" namespace { @@ -86,7 +87,7 @@ namespace depth->setWriteMask(false); stateset->setAttributeAndModes(depth, osg::StateAttribute::ON); - stateset->setRenderBinDetails(9, "RenderBin"); + stateset->setRenderBinDetails(MWRender::RenderBin_Water, "RenderBin"); std::vector > textures; for (int i=0; i<32; ++i) From ac5d0bf40502f355a2bd46cdf57c12b3723d59b6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 19 Sep 2015 18:22:16 +0200 Subject: [PATCH 2192/3725] Render the sun flash (not adjusted based on occlusion yet) --- apps/openmw/mwrender/sky.cpp | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 8588d2158..17b4f2f6a 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -364,6 +364,7 @@ public: Sun(osg::Group* parentNode, Resource::TextureManager& textureManager) : CelestialBody(parentNode, 1.0f, 1) , mUpdater(new Updater) + , mInitialFlashScale(2.6f) { mTransform->addUpdateCallback(mUpdater); @@ -384,6 +385,8 @@ public: mOcclusionQueryVisiblePixels = createOcclusionQueryNode(queryTransform, true); mOcclusionQueryTotalPixels = createOcclusionQueryNode(queryTransform, false); + + createSunFlash(textureManager); } ~Sun() @@ -447,6 +450,34 @@ private: return oqn; } + void createSunFlash(Resource::TextureManager& textureManager) + { + osg::ref_ptr tex = textureManager.getTexture2D("textures/tx_sun_flash_grey_05.dds", + osg::Texture::CLAMP, + osg::Texture::CLAMP); + + osg::ref_ptr transform (new osg::PositionAttitudeTransform); + transform->setScale(osg::Vec3f(mInitialFlashScale, mInitialFlashScale, mInitialFlashScale)); + + mTransform->addChild(transform); + + osg::ref_ptr geode (new osg::Geode); + transform->addChild(geode); + + geode->addDrawable(createTexturedQuad()); + + osg::StateSet* stateset = geode->getOrCreateStateSet(); + + stateset->setTextureAttributeAndModes(0, tex, osg::StateAttribute::ON); + stateset->setAttributeAndModes(createUnlitMaterial(), + osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); + stateset->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF); + stateset->setRenderBinDetails(RenderBin_SunGlare, "RenderBin"); + stateset->setNestRenderBins(false); + + // TODO: change size depending on occlusion + } + struct Updater : public SceneUtil::StateSetUpdater { osg::Vec4f mColor; @@ -472,6 +503,7 @@ private: osg::ref_ptr mUpdater; osg::ref_ptr mOcclusionQueryVisiblePixels; osg::ref_ptr mOcclusionQueryTotalPixels; + float mInitialFlashScale; }; class Moon : public CelestialBody From a2a4532e71317332068e6617a29a2bfc5aa20544 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 21 Sep 2015 16:03:30 +0200 Subject: [PATCH 2193/3725] Add the full-screen sun glare effect --- apps/openmw/mwrender/sky.cpp | 260 ++++++++++++++++++++++++++++++-- apps/openmw/mwrender/sky.hpp | 3 +- apps/openmw/mwworld/weather.cpp | 8 + 3 files changed, 253 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 17b4f2f6a..69041a724 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -376,7 +377,7 @@ public: // Slightly downscale the query geometry since the sun quad has a transparent texture that doesn't cover the whole area osg::ref_ptr queryTransform (new osg::PositionAttitudeTransform); - queryTransform->setScale(osg::Vec3f(0.5f, 0.5f, 0.5f)); + queryTransform->setScale(osg::Vec3f(0.4f, 0.4f, 0.4f)); // Need to render after the world geometry so we can correctly test for occlusions queryTransform->getOrCreateStateSet()->setRenderBinDetails(RenderBin_OcclusionQuery, "RenderBin"); queryTransform->getOrCreateStateSet()->setNestRenderBins(false); @@ -386,17 +387,26 @@ public: mOcclusionQueryVisiblePixels = createOcclusionQueryNode(queryTransform, true); mOcclusionQueryTotalPixels = createOcclusionQueryNode(queryTransform, false); - createSunFlash(textureManager); + osg::PositionAttitudeTransform* sunFlashNode = createSunFlash(textureManager); + + mSunFlashCallback = new SunFlashCallback(mOcclusionQueryVisiblePixels, mOcclusionQueryTotalPixels, sunFlashNode, mTransform); + mTransform->addCullCallback(mSunFlashCallback); + + createSunGlare(); } ~Sun() { mTransform->removeUpdateCallback(mUpdater); + destroySunFlash(); + destroySunGlare(); } virtual void adjustTransparency(const float ratio) { mUpdater->mColor.a() = ratio; + if (mSunGlareCallback) + mSunGlareCallback->setGlareView(ratio); } void setDirection(const osg::Vec3f& direction) @@ -409,6 +419,12 @@ public: mTransform->setAttitude(quat); } + void setGlareTimeOfDayFade(float val) + { + if (mSunGlareCallback) + mSunGlareCallback->setTimeOfDayFade(val); + } + private: /// @param queryVisible If true, queries the amount of visible pixels. If false, queries the total amount of pixels. osg::ref_ptr createOcclusionQueryNode(osg::Group* parent, bool queryVisible) @@ -450,7 +466,7 @@ private: return oqn; } - void createSunFlash(Resource::TextureManager& textureManager) + osg::PositionAttitudeTransform* createSunFlash(Resource::TextureManager& textureManager) { osg::ref_ptr tex = textureManager.getTexture2D("textures/tx_sun_flash_grey_05.dds", osg::Texture::CLAMP, @@ -474,12 +490,58 @@ private: stateset->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF); stateset->setRenderBinDetails(RenderBin_SunGlare, "RenderBin"); stateset->setNestRenderBins(false); + return transform; + } + void destroySunFlash() + { + mTransform->removeCullCallback(mSunFlashCallback); + mSunFlashCallback = NULL; + } + + void createSunGlare() + { + osg::ref_ptr camera (new osg::Camera); + camera->setProjectionMatrix(osg::Matrix::identity()); + camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF); // add to skyRoot instead? + camera->setViewMatrix(osg::Matrix::identity()); + camera->setClearMask(0); + camera->setRenderOrder(osg::Camera::NESTED_RENDER); + camera->setAllowEventFocus(false); + + osg::ref_ptr geode (new osg::Geode); + osg::ref_ptr geom = osg::createTexturedQuadGeometry(osg::Vec3f(-1,-1,0), osg::Vec3f(2,0,0), osg::Vec3f(0,2,0)); + geode->addDrawable(geom); + + camera->addChild(geode); + + osg::StateSet* stateset = geom->getOrCreateStateSet(); - // TODO: change size depending on occlusion + stateset->setRenderBinDetails(RenderBin_SunGlare, "RenderBin"); + stateset->setNestRenderBins(false); + stateset->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF); + + // set up additive blending + osg::ref_ptr blendFunc (new osg::BlendFunc); + blendFunc->setSource(osg::BlendFunc::SRC_ALPHA); + blendFunc->setDestination(osg::BlendFunc::ONE); + stateset->setAttributeAndModes(blendFunc, osg::StateAttribute::ON); + + mSunGlareCallback = new SunGlareCallback(mOcclusionQueryVisiblePixels, mOcclusionQueryTotalPixels, mTransform); + mSunGlareNode = camera; + + mSunGlareNode->addCullCallback(mSunGlareCallback); + + mTransform->addChild(camera); + } + void destroySunGlare() + { + mSunGlareNode->removeCullCallback(mSunGlareCallback); + mSunGlareCallback = NULL; } - struct Updater : public SceneUtil::StateSetUpdater + class Updater : public SceneUtil::StateSetUpdater { + public: osg::Vec4f mColor; Updater() @@ -489,8 +551,7 @@ private: virtual void setDefaults(osg::StateSet* stateset) { - stateset->setAttributeAndModes(createUnlitMaterial(), - osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); + stateset->setAttributeAndModes(createUnlitMaterial(), osg::StateAttribute::ON); } virtual void apply(osg::StateSet* stateset, osg::NodeVisitor*) @@ -500,7 +561,181 @@ private: } }; + class OcclusionCallback : public osg::NodeCallback + { + public: + OcclusionCallback(osg::ref_ptr oqnVisible, osg::ref_ptr oqnTotal) + : mOcclusionQueryVisiblePixels(oqnVisible) + , mOcclusionQueryTotalPixels(oqnTotal) + { + } + + protected: + float getVisibleRatio (osg::Camera* camera) + { + int visible = mOcclusionQueryVisiblePixels->getQueryGeometry()->getNumPixels(camera); + int total = mOcclusionQueryTotalPixels->getQueryGeometry()->getNumPixels(camera); + + float visibleRatio = 0.f; + if (total > 0) + visibleRatio = static_cast(visible) / static_cast(total); + + float dt = MWBase::Environment::get().getFrameDuration(); + + float lastRatio = mLastRatio[osg::observer_ptr(camera)]; + + float change = dt*10; + + if (visibleRatio > lastRatio) + visibleRatio = std::min(visibleRatio, lastRatio + change); + else + visibleRatio = std::max(visibleRatio, lastRatio - change); + + mLastRatio[osg::observer_ptr(camera)] = visibleRatio; + + return visibleRatio; + } + + private: + osg::ref_ptr mOcclusionQueryVisiblePixels; + osg::ref_ptr mOcclusionQueryTotalPixels; + + std::map, float> mLastRatio; + }; + + /// SunFlashCallback handles fading/scaling of the sun flash depending on occlusion query result. Must be attached as a cull callback. + class SunFlashCallback : public OcclusionCallback + { + public: + SunFlashCallback(osg::ref_ptr oqnVisible, osg::ref_ptr oqnTotal, + osg::ref_ptr flashNode, + osg::ref_ptr sunTransform) + : OcclusionCallback(oqnVisible, oqnTotal) + , mFlashNode(flashNode) + { + mInitialScale = mFlashNode->getScale().x(); + } + + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) + { + osgUtil::CullVisitor* cv = static_cast(nv); + + float visibleRatio = getVisibleRatio(cv->getCurrentCamera()); + + handleOcclusionResult (visibleRatio, cv); + + traverse(node, nv); + } + + void handleOcclusionResult(float visibleRatio, osgUtil::CullVisitor* cv) + { + // TODO + } + + private: + float mInitialScale; + osg::ref_ptr mFlashNode; + }; + + + /// SunGlareCallback controls a full-screen glare effect depending on occlusion query result and the angle between sun and camera. + /// Must be attached as a cull callback to the node above the glare node. + class SunGlareCallback : public OcclusionCallback + { + public: + SunGlareCallback(osg::ref_ptr oqnVisible, osg::ref_ptr oqnTotal, + osg::ref_ptr sunTransform) + : OcclusionCallback(oqnVisible, oqnTotal) + , mSunTransform(sunTransform) + , mTimeOfDayFade(1.f) + , mGlareView(1.f) + { + + } + + virtual void operator ()(osg::Node* node, osg::NodeVisitor* nv) + { + osgUtil::CullVisitor* cv = static_cast(nv); + + float angleRadians = getAngleToSunInRadians(cv->getCurrentCamera()); + float visibleRatio = getVisibleRatio(cv->getCurrentCamera()); + + const float angleMaxRadians = osg::DegreesToRadians(30.f); // Sun Glare Fader Angle Max + + float value = 1.f - std::min(1.f, angleRadians / angleMaxRadians); + + const float sunGlareFaderMax = 0.5f; + float fade = value * sunGlareFaderMax; + + fade *= mTimeOfDayFade * mGlareView * visibleRatio; + + if (fade == 0.f) + { + // no traverse + return; + } + else + { + osg::ref_ptr stateset (new osg::StateSet); + + osg::ref_ptr mat (createUnlitMaterial()); + + osg::Vec4f sunGlareFaderColor (222/255.f, 95/255.f, 39/255.f, 1); + + // Replicating a design flaw in MW. The color was being set on both ambient and emissive properties, which multiplies the result by two, + // then finally gets clamped by the fixed function pipeline. With the default INI settings, only the red component gets clamped, + // so the resulting color looks more orange than red. + sunGlareFaderColor *= 2; + for (int i=0; i<3; ++i) + sunGlareFaderColor[i] = std::min(1.f, sunGlareFaderColor[i]); + + mat->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(0,0,0,1)); + mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0,0,0,fade)); + mat->setEmission(osg::Material::FRONT_AND_BACK, sunGlareFaderColor); + mat->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4f(0,0,0,0)); + + stateset->setAttributeAndModes(mat, osg::StateAttribute::ON); + + cv->pushStateSet(stateset); + traverse(node, nv); + cv->popStateSet(); + } + } + + void setTimeOfDayFade(float val) + { + mTimeOfDayFade = val; + } + + void setGlareView(float glareView) + { + mGlareView = glareView; + } + + private: + float getAngleToSunInRadians(osg::Camera* camera) const + { + osg::Vec3d eye, center, up; + camera->getViewMatrixAsLookAt(eye, center, up); + + osg::Vec3d forward = center - eye; + osg::Vec3d sun = mSunTransform->getPosition(); + + forward.normalize(); + sun.normalize(); + float angleRadians = std::acos(forward * sun); + return angleRadians; + } + + osg::ref_ptr mSunTransform; + float mTimeOfDayFade; + float mGlareView; + }; + osg::ref_ptr mUpdater; + osg::ref_ptr mSunFlashCallback; + osg::ref_ptr mSunGlareCallback; + osg::ref_ptr mSunGlareNode; osg::ref_ptr mOcclusionQueryVisiblePixels; osg::ref_ptr mOcclusionQueryTotalPixels; float mInitialFlashScale; @@ -1223,11 +1458,6 @@ void SkyManager::setWeather(const WeatherResult& weather) mParticleFader->setAlpha(weather.mEffectFade); } -void SkyManager::setGlare(const float glare) -{ - mGlare = glare; -} - void SkyManager::sunEnable() { if (!mCreated) return; @@ -1276,11 +1506,9 @@ void SkyManager::setDate(int day, int month) mMonth = month; } -void SkyManager::setGlareEnabled (bool enabled) +void SkyManager::setGlareTimeOfDayFade(float val) { - if (!mCreated || !mEnabled) - return; - //mSunGlare->setVisible (mSunEnabled && enabled); + mSun->setGlareTimeOfDayFade(val); } } diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index de27cf447..b9b27b3d0 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -140,8 +140,7 @@ namespace MWRender void setMasserState(const MoonState& state); void setSecundaState(const MoonState& state); - void setGlare(const float glare); - void setGlareEnabled(bool enabled); + void setGlareTimeOfDayFade(float val); private: void create(); diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index b0e617f2b..050b6652c 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -624,6 +624,14 @@ void WeatherManager::update(float duration, bool paused) mRendering.setSunDirection( final * -1 ); } + float peakHour = mSunriseTime + (mSunsetTime - mSunriseTime) / 2; + if (time.getHour() < mSunriseTime || time.getHour() > mSunsetTime) + mRendering.getSkyManager()->setGlareTimeOfDayFade(0); + else if (time.getHour() < peakHour) + mRendering.getSkyManager()->setGlareTimeOfDayFade(1 - (peakHour - time.getHour()) / (peakHour - mSunriseTime)); + else + mRendering.getSkyManager()->setGlareTimeOfDayFade(1 - (time.getHour() - peakHour) / (mSunsetTime - peakHour)); + mRendering.getSkyManager()->setMasserState(mMasser.calculateState(time)); mRendering.getSkyManager()->setSecundaState(mSecunda.calculateState(time)); From 96b31d3bba084e2a95ae63c3f245b427dc1f3977 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 21 Sep 2015 16:34:30 +0200 Subject: [PATCH 2194/3725] Scale the sun flash texture depending on occlusion query --- apps/openmw/mwrender/sky.cpp | 71 ++++++++++++++++++++++-------------- 1 file changed, 44 insertions(+), 27 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 69041a724..78b1aba70 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -387,11 +387,7 @@ public: mOcclusionQueryVisiblePixels = createOcclusionQueryNode(queryTransform, true); mOcclusionQueryTotalPixels = createOcclusionQueryNode(queryTransform, false); - osg::PositionAttitudeTransform* sunFlashNode = createSunFlash(textureManager); - - mSunFlashCallback = new SunFlashCallback(mOcclusionQueryVisiblePixels, mOcclusionQueryTotalPixels, sunFlashNode, mTransform); - mTransform->addCullCallback(mSunFlashCallback); - + createSunFlash(textureManager); createSunGlare(); } @@ -466,7 +462,7 @@ private: return oqn; } - osg::PositionAttitudeTransform* createSunFlash(Resource::TextureManager& textureManager) + void createSunFlash(Resource::TextureManager& textureManager) { osg::ref_ptr tex = textureManager.getTexture2D("textures/tx_sun_flash_grey_05.dds", osg::Texture::CLAMP, @@ -490,12 +486,19 @@ private: stateset->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF); stateset->setRenderBinDetails(RenderBin_SunGlare, "RenderBin"); stateset->setNestRenderBins(false); - return transform; + + mSunFlashNode = transform; + + mSunFlashCallback = new SunFlashCallback(mOcclusionQueryVisiblePixels, mOcclusionQueryTotalPixels); + mSunFlashNode->addCullCallback(mSunFlashCallback); } void destroySunFlash() { - mTransform->removeCullCallback(mSunFlashCallback); - mSunFlashCallback = NULL; + if (mSunFlashNode) + { + mSunFlashNode->removeCullCallback(mSunFlashCallback); + mSunFlashCallback = NULL; + } } void createSunGlare() @@ -535,8 +538,11 @@ private: } void destroySunGlare() { - mSunGlareNode->removeCullCallback(mSunGlareCallback); - mSunGlareCallback = NULL; + if (mSunGlareNode) + { + mSunGlareNode->removeCullCallback(mSunGlareCallback); + mSunGlareCallback = NULL; + } } class Updater : public SceneUtil::StateSetUpdater @@ -603,17 +609,13 @@ private: std::map, float> mLastRatio; }; - /// SunFlashCallback handles fading/scaling of the sun flash depending on occlusion query result. Must be attached as a cull callback. + /// SunFlashCallback handles fading/scaling of a node depending on occlusion query result. Must be attached as a cull callback. class SunFlashCallback : public OcclusionCallback { public: - SunFlashCallback(osg::ref_ptr oqnVisible, osg::ref_ptr oqnTotal, - osg::ref_ptr flashNode, - osg::ref_ptr sunTransform) + SunFlashCallback(osg::ref_ptr oqnVisible, osg::ref_ptr oqnTotal) : OcclusionCallback(oqnVisible, oqnTotal) - , mFlashNode(flashNode) { - mInitialScale = mFlashNode->getScale().x(); } virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) @@ -622,19 +624,33 @@ private: float visibleRatio = getVisibleRatio(cv->getCurrentCamera()); - handleOcclusionResult (visibleRatio, cv); + if (visibleRatio > 0.f) + { + // rescale into [0.35, 1.0] range + const float threshold = 0.35; + visibleRatio = visibleRatio * (1.f - threshold) + threshold; + } - traverse(node, nv); - } + float scale = visibleRatio; - void handleOcclusionResult(float visibleRatio, osgUtil::CullVisitor* cv) - { - // TODO - } + if (scale == 0.f) + { + // no traverse + return; + } + else + { + osg::Matrix modelView = *cv->getModelViewMatrix(); - private: - float mInitialScale; - osg::ref_ptr mFlashNode; + modelView.preMultScale(osg::Vec3f(visibleRatio, visibleRatio, visibleRatio)); + + cv->pushModelViewMatrix(new osg::RefMatrix(modelView), osg::Transform::RELATIVE_RF); + + traverse(node, nv); + + cv->popModelViewMatrix(); + } + } }; @@ -734,6 +750,7 @@ private: osg::ref_ptr mUpdater; osg::ref_ptr mSunFlashCallback; + osg::ref_ptr mSunFlashNode; osg::ref_ptr mSunGlareCallback; osg::ref_ptr mSunGlareNode; osg::ref_ptr mOcclusionQueryVisiblePixels; From 9bb6c3f288c001ba11a2c08bf260ad927410f253 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 21 Sep 2015 17:09:24 +0200 Subject: [PATCH 2195/3725] Improve accuracy of sun occlusion query (use circular shape) --- apps/openmw/mwrender/sky.cpp | 43 +++++++++++++++++++++++++++--------- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 78b1aba70..63a041579 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -375,17 +376,20 @@ public: mGeode->getOrCreateStateSet()->setTextureAttributeAndModes(0, sunTex, osg::StateAttribute::ON); - // Slightly downscale the query geometry since the sun quad has a transparent texture that doesn't cover the whole area - osg::ref_ptr queryTransform (new osg::PositionAttitudeTransform); - queryTransform->setScale(osg::Vec3f(0.4f, 0.4f, 0.4f)); + osg::ref_ptr queryNode (new osg::Group); // Need to render after the world geometry so we can correctly test for occlusions - queryTransform->getOrCreateStateSet()->setRenderBinDetails(RenderBin_OcclusionQuery, "RenderBin"); - queryTransform->getOrCreateStateSet()->setNestRenderBins(false); + queryNode->getOrCreateStateSet()->setRenderBinDetails(RenderBin_OcclusionQuery, "RenderBin"); + queryNode->getOrCreateStateSet()->setNestRenderBins(false); + // Set up alpha testing on the occlusion testing subgraph, that way we can get the occlusion tested fragments to match the circular shape of the sun + osg::ref_ptr alphaFunc (new osg::AlphaFunc); + alphaFunc->setFunction(osg::AlphaFunc::GREATER, 0.8); + queryNode->getOrCreateStateSet()->setAttributeAndModes(alphaFunc, osg::StateAttribute::ON); + queryNode->getOrCreateStateSet()->setTextureAttributeAndModes(0, sunTex, osg::StateAttribute::ON); - mTransform->addChild(queryTransform); + mTransform->addChild(queryNode); - mOcclusionQueryVisiblePixels = createOcclusionQueryNode(queryTransform, true); - mOcclusionQueryTotalPixels = createOcclusionQueryNode(queryTransform, false); + mOcclusionQueryVisiblePixels = createOcclusionQueryNode(queryNode, true); + mOcclusionQueryTotalPixels = createOcclusionQueryNode(queryNode, false); createSunFlash(textureManager); createSunGlare(); @@ -441,6 +445,26 @@ private: oqn->addChild(queryGeode); + // Remove the default OFF|PROTECTED setting for texturing. We *want* to enable texturing for alpha testing purposes + oqn->getQueryStateSet()->removeTextureMode(0, GL_TEXTURE_2D); + + // Need to add texture coordinates so that texturing works. A bit ugly, relies on the vertex ordering + // used within OcclusionQueryNode. + osg::ref_ptr texCoordArray (new osg::Vec2Array); + for (int i=0; i<8; ++i) + { + texCoordArray->push_back(osg::Vec2(0,0)); + texCoordArray->push_back(osg::Vec2(1,0)); + texCoordArray->push_back(osg::Vec2(0,0)); + texCoordArray->push_back(osg::Vec2(1,0)); + texCoordArray->push_back(osg::Vec2(1,1)); + texCoordArray->push_back(osg::Vec2(0,1)); + texCoordArray->push_back(osg::Vec2(0,1)); + texCoordArray->push_back(osg::Vec2(1,1)); + } + + oqn->getQueryGeometry()->setTexCoordArray(0, texCoordArray, osg::Array::BIND_PER_VERTEX); + if (queryVisible) { osg::ref_ptr depth (new osg::Depth); @@ -626,8 +650,7 @@ private: if (visibleRatio > 0.f) { - // rescale into [0.35, 1.0] range - const float threshold = 0.35; + const float threshold = 0.6; visibleRatio = visibleRatio * (1.f - threshold) + threshold; } From 854fd9fe051c17395ec49a4e8321497b1c9e721e Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 21 Sep 2015 17:18:27 +0200 Subject: [PATCH 2196/3725] Remove dead code --- apps/openmw/mwrender/sky.cpp | 53 ++++++------------------------------ apps/openmw/mwrender/sky.hpp | 3 -- 2 files changed, 9 insertions(+), 47 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 63a041579..86a9a1765 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -972,8 +972,6 @@ SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneMana , mCloudSpeed(0.0f) , mStarsOpacity(0.0f) , mRemainingTransitionTime(0.0f) - , mGlare(0.0f) - , mGlareFade(0.0f) , mRainEnabled(false) , mRainSpeed(0) , mRainFrequency(1) @@ -1290,32 +1288,6 @@ void SkyManager::update(float duration) mCloudUpdater->setAnimationTimer(mCloudAnimationTimer); mCloudUpdater2->setAnimationTimer(mCloudAnimationTimer); - if (mSunEnabled) - { - // take 1/10 sec for fading the glare effect from invisible to full - if (mGlareFade > mGlare) - { - mGlareFade -= duration*10; - if (mGlareFade < mGlare) mGlareFade = mGlare; - } - else if (mGlareFade < mGlare) - { - mGlareFade += duration*10; - if (mGlareFade > mGlare) mGlareFade = mGlare; - } - - // increase the strength of the sun glare effect depending - // on how directly the player is looking at the sun - /* - Vector3 sun = mSunGlare->getPosition(); - Vector3 cam = mCamera->getRealDirection(); - const Degree angle = sun.angleBetween( cam ); - float val = 1- (angle.valueDegrees() / 180.f); - val = (val*val*val*val)*6; - mSunGlare->setSize(val * mGlareFade); - */ - } - // rotate the stars by 360 degrees every 4 days mAtmosphereNightRoll += MWBase::Environment::get().getWorld()->getTimeScaleFactor()*duration*osg::DegreesToRadians(360.f) / (3600*96.f); if (mAtmosphereNightNode->getNodeMask() != 0) @@ -1466,6 +1438,15 @@ void SkyManager::setWeather(const WeatherResult& weather) mMasser->adjustTransparency(weather.mGlareView); mSecunda->adjustTransparency(weather.mGlareView); + + /* + float timeofday_angle = std::abs(mSun->getPosition().z/mSunGlare->getPosition().length()); + float strength; + if (timeofday_angle <= 0.44) + strength = timeofday_angle/0.44f; + else + strength = 1.f; + */ mSun->adjustTransparency(weather.mGlareView); float nextStarsOpacity = weather.mNightFade * weather.mGlareView; @@ -1478,20 +1459,6 @@ void SkyManager::setWeather(const WeatherResult& weather) mAtmosphereNightNode->setNodeMask(weather.mNight ? ~0 : 0); - - /* - float strength; - float timeofday_angle = std::abs(mSunGlare->getPosition().z/mSunGlare->getPosition().length()); - if (timeofday_angle <= 0.44) - strength = timeofday_angle/0.44f; - else - strength = 1.f; - - mSunGlare->setVisibility(weather.mGlareView * mGlareFade * strength); - - mSun->setVisibility(weather.mGlareView * strength); - */ - if (mRainFader) mRainFader->setAlpha(weather.mEffectFade * 0.6); // * Rain_Threshold? if (mParticleFader) @@ -1522,8 +1489,6 @@ void SkyManager::setSunDirection(const osg::Vec3f& direction) if (!mCreated) return; mSun->setDirection(direction); - - //mSunGlare->setPosition(direction); } void SkyManager::setMasserState(const MoonState& state) diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index b9b27b3d0..0cef46346 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -209,9 +209,6 @@ namespace MWRender float mRemainingTransitionTime; - float mGlare; // target - float mGlareFade; // actual - bool mRainEnabled; std::string mRainEffect; float mRainSpeed; From d812434feeb8b32aa1edada2e240994e5715cd43 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 21 Sep 2015 17:32:57 +0200 Subject: [PATCH 2197/3725] Add a subtle fading effect to the sun flash texture --- apps/openmw/mwrender/sky.cpp | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 86a9a1765..7f5666b17 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -385,6 +385,7 @@ public: alphaFunc->setFunction(osg::AlphaFunc::GREATER, 0.8); queryNode->getOrCreateStateSet()->setAttributeAndModes(alphaFunc, osg::StateAttribute::ON); queryNode->getOrCreateStateSet()->setTextureAttributeAndModes(0, sunTex, osg::StateAttribute::ON); + queryNode->getOrCreateStateSet()->setAttributeAndModes(createUnlitMaterial(), osg::StateAttribute::ON); mTransform->addChild(queryNode); @@ -407,6 +408,8 @@ public: mUpdater->mColor.a() = ratio; if (mSunGlareCallback) mSunGlareCallback->setGlareView(ratio); + if (mSunFlashCallback) + mSunFlashCallback->setGlareView(ratio); } void setDirection(const osg::Vec3f& direction) @@ -505,8 +508,6 @@ private: osg::StateSet* stateset = geode->getOrCreateStateSet(); stateset->setTextureAttributeAndModes(0, tex, osg::StateAttribute::ON); - stateset->setAttributeAndModes(createUnlitMaterial(), - osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); stateset->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF); stateset->setRenderBinDetails(RenderBin_SunGlare, "RenderBin"); stateset->setNestRenderBins(false); @@ -639,6 +640,7 @@ private: public: SunFlashCallback(osg::ref_ptr oqnVisible, osg::ref_ptr oqnTotal) : OcclusionCallback(oqnVisible, oqnTotal) + , mGlareView(1.f) { } @@ -648,8 +650,20 @@ private: float visibleRatio = getVisibleRatio(cv->getCurrentCamera()); + osg::ref_ptr stateset; + if (visibleRatio > 0.f) { + const float fadeThreshold = 0.1; + if (visibleRatio < fadeThreshold) + { + float fade = 1.f - (fadeThreshold - visibleRatio) / fadeThreshold; + osg::ref_ptr mat (createUnlitMaterial()); + mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0,0,0,fade*mGlareView)); + stateset = new osg::StateSet; + stateset->setAttributeAndModes(mat, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + } + const float threshold = 0.6; visibleRatio = visibleRatio * (1.f - threshold) + threshold; } @@ -667,13 +681,27 @@ private: modelView.preMultScale(osg::Vec3f(visibleRatio, visibleRatio, visibleRatio)); + if (stateset) + cv->pushStateSet(stateset); + cv->pushModelViewMatrix(new osg::RefMatrix(modelView), osg::Transform::RELATIVE_RF); traverse(node, nv); cv->popModelViewMatrix(); + + if (stateset) + cv->popStateSet(); } } + + void setGlareView(float value) + { + mGlareView = value; + } + + private: + float mGlareView; }; @@ -728,10 +756,8 @@ private: for (int i=0; i<3; ++i) sunGlareFaderColor[i] = std::min(1.f, sunGlareFaderColor[i]); - mat->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(0,0,0,1)); mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0,0,0,fade)); mat->setEmission(osg::Material::FRONT_AND_BACK, sunGlareFaderColor); - mat->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4f(0,0,0,0)); stateset->setAttributeAndModes(mat, osg::StateAttribute::ON); From 1a1f1fae87097885d11773f0137aed5ba0f03b51 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 21 Sep 2015 17:50:36 +0200 Subject: [PATCH 2198/3725] Minor cleanup --- apps/openmw/mwrender/sky.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 7f5666b17..754e00909 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -366,7 +366,6 @@ public: Sun(osg::Group* parentNode, Resource::TextureManager& textureManager) : CelestialBody(parentNode, 1.0f, 1) , mUpdater(new Updater) - , mInitialFlashScale(2.6f) { mTransform->addUpdateCallback(mUpdater); @@ -496,7 +495,8 @@ private: osg::Texture::CLAMP); osg::ref_ptr transform (new osg::PositionAttitudeTransform); - transform->setScale(osg::Vec3f(mInitialFlashScale, mInitialFlashScale, mInitialFlashScale)); + const float scale = 2.6f; + transform->setScale(osg::Vec3f(scale,scale,scale)); mTransform->addChild(transform); @@ -804,7 +804,6 @@ private: osg::ref_ptr mSunGlareNode; osg::ref_ptr mOcclusionQueryVisiblePixels; osg::ref_ptr mOcclusionQueryTotalPixels; - float mInitialFlashScale; }; class Moon : public CelestialBody From f7e5a40143d0db37e349ee5e3541c3e2e2ace1b7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 21 Sep 2015 17:58:57 +0200 Subject: [PATCH 2199/3725] Fix typo --- components/sceneutil/statesetupdater.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/sceneutil/statesetupdater.hpp b/components/sceneutil/statesetupdater.hpp index a4fcd7866..37d08e025 100644 --- a/components/sceneutil/statesetupdater.hpp +++ b/components/sceneutil/statesetupdater.hpp @@ -6,7 +6,7 @@ namespace SceneUtil { - /// @brief Implements efficient pre-frame updating of StateSets. + /// @brief Implements efficient per-frame updating of StateSets. /// @par With a naive update there would be race conditions when the OSG draw thread of the last frame /// queues up a StateSet that we want to modify for the next frame. To solve this we could set the StateSet to /// DYNAMIC data variance but that would undo all the benefits of the threading model - having the cull and draw From 385f4f729c967c02fbcc6fac062af9c0d27a82b6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 21 Sep 2015 19:43:48 +0200 Subject: [PATCH 2200/3725] Implement SunDiscSunsetColor, fade the sun during sunrise & sunset --- apps/openmw/mwrender/sky.cpp | 23 ++++++++++++----------- apps/openmw/mwrender/sky.hpp | 2 ++ apps/openmw/mwworld/weather.cpp | 33 ++++++++++++++++++++++++++++++++- apps/openmw/mwworld/weather.hpp | 9 ++------- 4 files changed, 48 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 754e00909..317f2229d 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -402,6 +402,13 @@ public: destroySunGlare(); } + void setColor(const osg::Vec4f& color) + { + mUpdater->mColor.r() = color.r(); + mUpdater->mColor.g() = color.g(); + mUpdater->mColor.b() = color.b(); + } + virtual void adjustTransparency(const float ratio) { mUpdater->mColor.a() = ratio; @@ -576,7 +583,7 @@ private: osg::Vec4f mColor; Updater() - : mColor(1.f, 1.f, 1.f, 1.0f) + : mColor(1.f, 1.f, 1.f, 1.f) { } @@ -588,7 +595,8 @@ private: virtual void apply(osg::StateSet* stateset, osg::NodeVisitor*) { osg::Material* mat = static_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); - mat->setDiffuse(osg::Material::FRONT_AND_BACK, mColor); + mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0,0,0,mColor.a())); + mat->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(mColor.r(), mColor.g(), mColor.b(), 1)); } }; @@ -1464,15 +1472,8 @@ void SkyManager::setWeather(const WeatherResult& weather) mMasser->adjustTransparency(weather.mGlareView); mSecunda->adjustTransparency(weather.mGlareView); - /* - float timeofday_angle = std::abs(mSun->getPosition().z/mSunGlare->getPosition().length()); - float strength; - if (timeofday_angle <= 0.44) - strength = timeofday_angle/0.44f; - else - strength = 1.f; - */ - mSun->adjustTransparency(weather.mGlareView); + mSun->setColor(weather.mSunDiscColor); + mSun->adjustTransparency(weather.mGlareView * weather.mSunDiscColor.a()); float nextStarsOpacity = weather.mNightFade * weather.mGlareView; if(weather.mNight && mStarsOpacity != nextStarsOpacity) diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index 0cef46346..072083d27 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -48,8 +48,10 @@ namespace MWRender osg::Vec4f mSkyColor; + // sun light color osg::Vec4f mSunColor; + // alpha is the sun transparency osg::Vec4f mSunDiscColor; float mFogDepth; diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 050b6652c..78ae6fa0b 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -432,6 +432,7 @@ WeatherManager::WeatherManager(MWRender::RenderingManager& rendering, const MWWo , mSunsetTime(fallback.getFallbackFloat("Weather_Sunset_Time")) , mSunriseDuration(fallback.getFallbackFloat("Weather_Sunrise_Duration")) , mSunsetDuration(fallback.getFallbackFloat("Weather_Sunset_Duration")) + , mSunPreSunsetTime(fallback.getFallbackFloat("Weather_Sun_Pre-Sunset_Time")) , mNightStart(mSunsetTime + mSunsetDuration) , mNightEnd(mSunriseTime - 0.5f) , mDayStart(mSunriseTime + mSunriseDuration) @@ -966,7 +967,6 @@ inline void WeatherManager::calculateResult(const int weatherID, const float gam mResult.mAmbientLoopSoundID = current.mAmbientLoopSoundID; mResult.mAmbientSoundVolume = 1.f; mResult.mEffectFade = 1.f; - mResult.mSunColor = current.mSunDiscSunsetColor; mResult.mIsStorm = current.mIsStorm; @@ -980,6 +980,7 @@ inline void WeatherManager::calculateResult(const int weatherID, const float gam mResult.mFogDepth = mResult.mNight ? current.mLandFogNightDepth : current.mLandFogDayDepth; + // TODO: use pre/post sunset/sunrise time values in [Weather] section // night if (gameHour <= mNightEnd || gameHour >= mNightStart + 1) { @@ -1050,6 +1051,36 @@ inline void WeatherManager::calculateResult(const int weatherID, const float gam mResult.mNightFade = factor; } } + + if (gameHour >= mSunsetTime - mSunPreSunsetTime) + { + float factor = (gameHour - (mSunsetTime - mSunPreSunsetTime)) / mSunPreSunsetTime; + factor = std::min(1.f, factor); + mResult.mSunDiscColor = lerp(osg::Vec4f(1,1,1,1), current.mSunDiscSunsetColor, factor); + // The SunDiscSunsetColor in the INI isn't exactly the resulting color on screen, most likely because + // MW applied the color to the ambient term as well. After the ambient and emissive terms are added together, the fixed pipeline + // would then clamp the total lighting to (1,1,1). A noticable change in color tone can be observed when only one of the color components gets clamped. + // Unfortunately that means we can't use the INI color as is, have to replicate the above nonsense. + mResult.mSunDiscColor = mResult.mSunDiscColor + osg::componentMultiply(mResult.mSunDiscColor, mResult.mAmbientColor); + for (int i=0; i<3; ++i) + mResult.mSunDiscColor[i] = std::min(1.f, mResult.mSunDiscColor[i]); + } + else + mResult.mSunDiscColor = osg::Vec4f(1,1,1,1); + + if (gameHour >= mSunsetTime) + { + float fade = std::min(1.f, (gameHour - mSunsetTime) / 2.f); + fade = fade*fade; + mResult.mSunDiscColor.a() = 1.f - fade; + } + else if (gameHour >= mSunriseTime && gameHour <= mSunriseTime + 1) + { + mResult.mSunDiscColor.a() = gameHour - mSunriseTime; + } + else + mResult.mSunDiscColor.a() = 1; + } inline void WeatherManager::calculateTransitionResult(const float factor, const float gameHour) diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index a0c93a460..7ce7c1bf8 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -75,7 +75,7 @@ namespace MWWorld float mLandFogDayDepth; float mLandFogNightDepth; - // Color modulation for the sun itself during sunset (not completely sure) + // Color modulation for the sun itself during sunset osg::Vec4f mSunDiscSunsetColor; // Used by scripts to animate signs, etc based on the wind (GetWindSpeed) @@ -242,12 +242,7 @@ namespace MWWorld float mSunsetTime; float mSunriseDuration; float mSunsetDuration; - // Some useful values - /* TODO: Use pre-sunrise_time, pre-sunset_time, - * post-sunrise_time, and post-sunset_time to better - * describe sunrise/sunset time. - * These values are fallbacks attached to weather. - */ + float mSunPreSunsetTime; float mNightStart; float mNightEnd; float mDayStart; From 7bef97bf3331dbdf9544c2caad17ecf68b3be96b Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 22 Sep 2015 15:36:00 +0200 Subject: [PATCH 2201/3725] fixed local variable caching issue in automatic error checking (Fixes #2927) --- apps/opencs/model/world/scriptcontext.cpp | 17 +++++++++++-- apps/opencs/model/world/scriptcontext.hpp | 3 +++ apps/opencs/view/world/scripterrortable.cpp | 5 ++++ apps/opencs/view/world/scripterrortable.hpp | 5 ++++ apps/opencs/view/world/scriptsubview.cpp | 27 ++++++++++++++++++++- apps/opencs/view/world/scriptsubview.hpp | 1 + 6 files changed, 55 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/world/scriptcontext.cpp b/apps/opencs/model/world/scriptcontext.cpp index bcbca4b28..f644ad37a 100644 --- a/apps/opencs/model/world/scriptcontext.cpp +++ b/apps/opencs/model/world/scriptcontext.cpp @@ -39,8 +39,6 @@ char CSMWorld::ScriptContext::getGlobalType (const std::string& name) const std::pair CSMWorld::ScriptContext::getMemberType (const std::string& name, const std::string& id) const { - /// \todo invalidate locals cache on change to scripts - std::string id2 = Misc::StringUtils::lowerCase (id); int index = mData.getScripts().searchId (id2); @@ -120,3 +118,18 @@ void CSMWorld::ScriptContext::clear() mIdsUpdated = false; mLocals.clear(); } + +bool CSMWorld::ScriptContext::clearLocals (const std::string& script) +{ + std::map::iterator iter = + mLocals.find (Misc::StringUtils::lowerCase (script)); + + if (iter!=mLocals.end()) + { + mLocals.erase (iter); + mIdsUpdated = false; + return true; + } + + return false; +} diff --git a/apps/opencs/model/world/scriptcontext.hpp b/apps/opencs/model/world/scriptcontext.hpp index 29ee42645..2cd59f070 100644 --- a/apps/opencs/model/world/scriptcontext.hpp +++ b/apps/opencs/model/world/scriptcontext.hpp @@ -46,6 +46,9 @@ namespace CSMWorld void clear(); ///< Remove all cached data. + + /// \return Were there any locals that needed clearing? + bool clearLocals (const std::string& script); }; } diff --git a/apps/opencs/view/world/scripterrortable.cpp b/apps/opencs/view/world/scripterrortable.cpp index b44e1c0bd..a9e315c73 100644 --- a/apps/opencs/view/world/scripterrortable.cpp +++ b/apps/opencs/view/world/scripterrortable.cpp @@ -131,6 +131,11 @@ void CSVWorld::ScriptErrorTable::clear() setRowCount (0); } +bool CSVWorld::ScriptErrorTable::clearLocals (const std::string& script) +{ + return mContext.clearLocals (script); +} + void CSVWorld::ScriptErrorTable::cellClicked (int row, int column) { if (item (row, 1)) diff --git a/apps/opencs/view/world/scripterrortable.hpp b/apps/opencs/view/world/scripterrortable.hpp index 98db425cf..33af7c864 100644 --- a/apps/opencs/view/world/scripterrortable.hpp +++ b/apps/opencs/view/world/scripterrortable.hpp @@ -44,6 +44,11 @@ namespace CSVWorld void clear(); + /// Clear local variable cache for \a script. + /// + /// \return Were there any locals that needed clearing? + bool clearLocals (const std::string& script); + private slots: void cellClicked (int row, int column); diff --git a/apps/opencs/view/world/scriptsubview.cpp b/apps/opencs/view/world/scriptsubview.cpp index d405d1765..d99f789b3 100644 --- a/apps/opencs/view/world/scriptsubview.cpp +++ b/apps/opencs/view/world/scriptsubview.cpp @@ -89,6 +89,7 @@ CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc: *document.getData().getTableModel (CSMWorld::UniversalId::Type_Scripts)); mColumn = mModel->findColumnIndex (CSMWorld::Columns::ColumnId_ScriptText); + mIdColumn = mModel->findColumnIndex (CSMWorld::Columns::ColumnId_Id); mStateColumn = mModel->findColumnIndex (CSMWorld::Columns::ColumnId_Modification); QString source = mModel->data (mModel->getModelIndex (id.getId(), mColumn)).toString(); @@ -241,6 +242,15 @@ void CSVWorld::ScriptSubView::dataChanged (const QModelIndex& topLeft, const QMo ScriptEdit::ChangeLock lock (*mEditor); + bool updateRequired = false; + + for (int i=topLeft.row(); i<=bottomRight.row(); ++i) + { + std::string id = mModel->data (mModel->index (i, mIdColumn)).toString().toUtf8().constData(); + if (mErrors->clearLocals (id)) + updateRequired = true; + } + QModelIndex index = mModel->getModelIndex (getUniversalId().getId(), mColumn); if (index.row()>=topLeft.row() && index.row()<=bottomRight.row()) @@ -256,13 +266,28 @@ void CSVWorld::ScriptSubView::dataChanged (const QModelIndex& topLeft, const QMo mEditor->setPlainText (source); mEditor->setTextCursor (cursor); - recompile(); + updateRequired = true; } } + + if (updateRequired) + recompile(); } void CSVWorld::ScriptSubView::rowsAboutToBeRemoved (const QModelIndex& parent, int start, int end) { + bool updateRequired = false; + + for (int i=start; i<=end; ++i) + { + std::string id = mModel->data (mModel->index (i, mIdColumn)).toString().toUtf8().constData(); + if (mErrors->clearLocals (id)) + updateRequired = true; + } + + if (updateRequired) + recompile(); + QModelIndex index = mModel->getModelIndex (getUniversalId().getId(), mColumn); if (!parent.isValid() && index.row()>=start && index.row()<=end) diff --git a/apps/opencs/view/world/scriptsubview.hpp b/apps/opencs/view/world/scriptsubview.hpp index 6125dd259..907dc7958 100644 --- a/apps/opencs/view/world/scriptsubview.hpp +++ b/apps/opencs/view/world/scriptsubview.hpp @@ -38,6 +38,7 @@ namespace CSVWorld CSMDoc::Document& mDocument; CSMWorld::IdTable *mModel; int mColumn; + int mIdColumn; int mStateColumn; TableBottomBox *mBottom; RecordButtonBar *mButtons; From 12b8fcf0bfb4cd5950a1f1dd7e7be460d5f3a75a Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 23 Sep 2015 23:37:09 +0200 Subject: [PATCH 2202/3725] OpenCS: Fix camera position retrieval in WorldspaceWidget --- apps/opencs/view/render/pagedworldspacewidget.cpp | 5 ++++- apps/opencs/view/render/unpagedworldspacewidget.cpp | 4 +++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index 274c77620..b0c1e74a9 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -170,7 +170,10 @@ void CSVRender::PagedWorldspaceWidget::referenceAdded (const QModelIndex& parent std::string CSVRender::PagedWorldspaceWidget::getStartupInstruction() { - osg::Vec3d position = mView->getCamera()->getViewMatrix().getTrans(); + osg::Vec3d eye, center, up; + mView->getCamera()->getViewMatrixAsLookAt(eye, center, up); + osg::Vec3d position = eye; + std::ostringstream stream; stream diff --git a/apps/opencs/view/render/unpagedworldspacewidget.cpp b/apps/opencs/view/render/unpagedworldspacewidget.cpp index a5733ad10..3e1733c81 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.cpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.cpp @@ -166,7 +166,9 @@ void CSVRender::UnpagedWorldspaceWidget::addVisibilitySelectorButtons ( std::string CSVRender::UnpagedWorldspaceWidget::getStartupInstruction() { - osg::Vec3d position = mView->getCamera()->getViewMatrix().getTrans(); + osg::Vec3d eye, center, up; + mView->getCamera()->getViewMatrixAsLookAt(eye, center, up); + osg::Vec3d position = eye; std::ostringstream stream; From 7d4125d97ff1e79ad19f9d11f43410c50de9354c Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Thu, 24 Sep 2015 15:21:42 +0200 Subject: [PATCH 2203/3725] Fixes for building with unity build --- apps/openmw/CMakeLists.txt | 3 ++- apps/openmw/mwgui/dialogue.cpp | 28 ++++++++++---------- apps/openmw/mwmechanics/steering.hpp | 1 + apps/openmw/mwrender/camera.cpp | 6 ++--- apps/openmw/mwrender/globalmap.cpp | 6 ++--- apps/openmw/mwrender/localmap.cpp | 6 ++--- apps/openmw/mwrender/sky.cpp | 1 - apps/openmw/mwscript/containerextensions.cpp | 24 ++++++++--------- apps/openmw/mwscript/statsextensions.cpp | 2 +- apps/openmw/mwworld/store.cpp | 6 ++--- apps/openmw/mwworld/weather.cpp | 5 ++-- components/CMakeLists.txt | 2 +- components/files/windowspath.cpp | 2 +- components/vfs/bsaarchive.hpp | 5 ++++ 14 files changed, 50 insertions(+), 47 deletions(-) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 5a9b52cb2..fa05576f5 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -65,7 +65,7 @@ add_openmw_dir (mwworld containerstore actiontalk actiontake manualref player cellfunctors failedaction cells localscripts customdata inventorystore ptr actionopen actionread actionequip timestamp actionalchemy cellstore actionapply actioneat - esmstore store recordcmp fallback actionrepair actionsoulgem livecellref actiondoor + store esmstore recordcmp fallback actionrepair actionsoulgem livecellref actiondoor contentloader esmloader actiontrap cellreflist cellref physicssystem weather projectilemanager ) @@ -179,4 +179,5 @@ if (MSVC) if (CMAKE_CL_64) set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /bigobj") endif (CMAKE_CL_64) + add_definitions("-D_USE_MATH_DEFINES") endif (MSVC) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index a6000a739..d32588631 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -31,7 +31,7 @@ namespace { - MyGUI::Colour getTextColour (const std::string& type) + MyGUI::Colour getDialogueTextColour (const std::string& type) { return MyGUI::Colour::parse(MyGUI::LanguageManager::getInstance().replaceTags("#{fontcolour=" + type + "}")); } @@ -115,7 +115,7 @@ namespace MWGui void Response::write(BookTypesetter::Ptr typesetter, KeywordSearchT* keywordSearch, std::map& topicLinks) const { - BookTypesetter::Style* title = typesetter->createStyle("", getTextColour("header")); + BookTypesetter::Style* title = typesetter->createStyle("", getDialogueTextColour("header")); typesetter->sectionBreak(9); if (mTitle != "") typesetter->write(title, to_utf8_span(mTitle.c_str())); @@ -159,14 +159,14 @@ namespace MWGui if (hyperLinks.size() && MWBase::Environment::get().getWindowManager()->getTranslationDataStorage().hasTranslation()) { - BookTypesetter::Style* style = typesetter->createStyle("", getTextColour("normal")); + BookTypesetter::Style* style = typesetter->createStyle("", getDialogueTextColour("normal")); size_t formatted = 0; // points to the first character that is not laid out yet for (std::map::iterator it = hyperLinks.begin(); it != hyperLinks.end(); ++it) { intptr_t topicId = it->second; - const MyGUI::Colour linkHot (getTextColour("link_over")); - const MyGUI::Colour linkNormal (getTextColour("link")); - const MyGUI::Colour linkActive (getTextColour("link_pressed")); + const MyGUI::Colour linkHot(getDialogueTextColour("link_over")); + const MyGUI::Colour linkNormal(getDialogueTextColour("link")); + const MyGUI::Colour linkActive(getDialogueTextColour("link_pressed")); BookTypesetter::Style* hotStyle = typesetter->createHotStyle (style, linkNormal, linkHot, linkActive, topicId); if (formatted < it->first.first) typesetter->write(style, formatted, it->first.first); @@ -199,11 +199,11 @@ namespace MWGui void Response::addTopicLink(BookTypesetter::Ptr typesetter, intptr_t topicId, size_t begin, size_t end) const { - BookTypesetter::Style* style = typesetter->createStyle("", getTextColour("normal")); + BookTypesetter::Style* style = typesetter->createStyle("", getDialogueTextColour("normal")); - const MyGUI::Colour linkHot (getTextColour("link_over")); - const MyGUI::Colour linkNormal (getTextColour("link")); - const MyGUI::Colour linkActive (getTextColour("link_pressed")); + const MyGUI::Colour linkHot(getDialogueTextColour("link_over")); + const MyGUI::Colour linkNormal(getDialogueTextColour("link")); + const MyGUI::Colour linkActive(getDialogueTextColour("link_pressed")); if (topicId) style = typesetter->createHotStyle (style, linkNormal, linkHot, linkActive, topicId); @@ -217,7 +217,7 @@ namespace MWGui void Message::write(BookTypesetter::Ptr typesetter, KeywordSearchT* keywordSearch, std::map& topicLinks) const { - BookTypesetter::Style* title = typesetter->createStyle("", getTextColour("notify")); + BookTypesetter::Style* title = typesetter->createStyle("", getDialogueTextColour("notify")); typesetter->sectionBreak(9); typesetter->write(title, to_utf8_span(mText.c_str())); } @@ -486,9 +486,9 @@ namespace MWGui typesetter->sectionBreak(9); // choices - const MyGUI::Colour linkHot (getTextColour("answer_over")); - const MyGUI::Colour linkNormal (getTextColour("answer")); - const MyGUI::Colour linkActive (getTextColour("answer_pressed")); + const MyGUI::Colour linkHot(getDialogueTextColour("answer_over")); + const MyGUI::Colour linkNormal(getDialogueTextColour("answer")); + const MyGUI::Colour linkActive(getDialogueTextColour("answer_pressed")); for (std::vector >::iterator it = mChoices.begin(); it != mChoices.end(); ++it) { Choice* link = new Choice(it->second); diff --git a/apps/openmw/mwmechanics/steering.hpp b/apps/openmw/mwmechanics/steering.hpp index 4b29dc1d9..632ab3611 100644 --- a/apps/openmw/mwmechanics/steering.hpp +++ b/apps/openmw/mwmechanics/steering.hpp @@ -1,4 +1,5 @@ #ifndef OPENMW_MECHANICS_STEERING_H +#define OPENMW_MECHANICS_STEERING_H #include diff --git a/apps/openmw/mwrender/camera.cpp b/apps/openmw/mwrender/camera.cpp index 316c9308b..fb6573d65 100644 --- a/apps/openmw/mwrender/camera.cpp +++ b/apps/openmw/mwrender/camera.cpp @@ -14,10 +14,10 @@ namespace { -class UpdateCameraCallback : public osg::NodeCallback +class UpdateRenderCameraCallback : public osg::NodeCallback { public: - UpdateCameraCallback(MWRender::Camera* cam) + UpdateRenderCameraCallback(MWRender::Camera* cam) : mCamera(cam) { } @@ -67,7 +67,7 @@ namespace MWRender mMainCam.yaw = 0.f; mMainCam.offset = 400.f; - mUpdateCallback = new UpdateCameraCallback(this); + mUpdateCallback = new UpdateRenderCameraCallback(this); mCamera->addUpdateCallback(mUpdateCallback); } diff --git a/apps/openmw/mwrender/globalmap.cpp b/apps/openmw/mwrender/globalmap.cpp index 7acda92a3..3445e4189 100644 --- a/apps/openmw/mwrender/globalmap.cpp +++ b/apps/openmw/mwrender/globalmap.cpp @@ -59,10 +59,10 @@ namespace } - class CameraUpdateCallback : public osg::NodeCallback + class CameraUpdateGlobalCallback : public osg::NodeCallback { public: - CameraUpdateCallback(osg::Camera* cam, MWRender::GlobalMap* parent) + CameraUpdateGlobalCallback(osg::Camera* cam, MWRender::GlobalMap* parent) : mRendered(false) , mCamera(cam) , mParent(parent) @@ -263,7 +263,7 @@ namespace MWRender else camera->setClearMask(GL_NONE); - camera->setUpdateCallback(new CameraUpdateCallback(camera, this)); + camera->setUpdateCallback(new CameraUpdateGlobalCallback(camera, this)); camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT, osg::Camera::PIXEL_BUFFER_RTT); camera->attach(osg::Camera::COLOR_BUFFER, mOverlayTexture); diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 02ca0cb4c..fe685f97c 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -27,10 +27,10 @@ namespace { - class CameraUpdateCallback : public osg::NodeCallback + class CameraLocalUpdateCallback : public osg::NodeCallback { public: - CameraUpdateCallback(osg::Camera* cam, MWRender::LocalMap* parent) + CameraLocalUpdateCallback(osg::Camera* cam, MWRender::LocalMap* parent) : mRendered(false) , mCamera(cam) , mParent(parent) @@ -205,7 +205,7 @@ osg::ref_ptr LocalMap::createOrthographicCamera(float x, float y, f camera->setStateSet(stateset); camera->setGraphicsContext(mViewer->getCamera()->getGraphicsContext()); camera->setViewport(0, 0, mMapResolution, mMapResolution); - camera->setUpdateCallback(new CameraUpdateCallback(camera, this)); + camera->setUpdateCallback(new CameraLocalUpdateCallback(camera, this)); return camera; } diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 317f2229d..6f1b26733 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1,6 +1,5 @@ #include "sky.hpp" -#define _USE_MATH_DEFINES #include #include diff --git a/apps/openmw/mwscript/containerextensions.cpp b/apps/openmw/mwscript/containerextensions.cpp index e33c7580f..4e3e010f7 100644 --- a/apps/openmw/mwscript/containerextensions.cpp +++ b/apps/openmw/mwscript/containerextensions.cpp @@ -56,10 +56,10 @@ namespace MWScript if (count == 0) return; - if(Misc::StringUtils::ciEqual(item, "gold_005") - || Misc::StringUtils::ciEqual(item, "gold_010") - || Misc::StringUtils::ciEqual(item, "gold_025") - || Misc::StringUtils::ciEqual(item, "gold_100")) + if(::Misc::StringUtils::ciEqual(item, "gold_005") + || ::Misc::StringUtils::ciEqual(item, "gold_010") + || ::Misc::StringUtils::ciEqual(item, "gold_025") + || ::Misc::StringUtils::ciEqual(item, "gold_100")) item = "gold_001"; MWWorld::Ptr itemPtr = *ptr.getClass().getContainerStore (ptr).add (item, count, ptr); @@ -97,10 +97,10 @@ namespace MWScript std::string item = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); - if(Misc::StringUtils::ciEqual(item, "gold_005") - || Misc::StringUtils::ciEqual(item, "gold_010") - || Misc::StringUtils::ciEqual(item, "gold_025") - || Misc::StringUtils::ciEqual(item, "gold_100")) + if(::Misc::StringUtils::ciEqual(item, "gold_005") + || ::Misc::StringUtils::ciEqual(item, "gold_010") + || ::Misc::StringUtils::ciEqual(item, "gold_025") + || ::Misc::StringUtils::ciEqual(item, "gold_100")) item = "gold_001"; MWWorld::ContainerStore& store = ptr.getClass().getContainerStore (ptr); @@ -131,10 +131,10 @@ namespace MWScript if (count == 0) return; - if(Misc::StringUtils::ciEqual(item, "gold_005") - || Misc::StringUtils::ciEqual(item, "gold_010") - || Misc::StringUtils::ciEqual(item, "gold_025") - || Misc::StringUtils::ciEqual(item, "gold_100")) + if(::Misc::StringUtils::ciEqual(item, "gold_005") + || ::Misc::StringUtils::ciEqual(item, "gold_010") + || ::Misc::StringUtils::ciEqual(item, "gold_025") + || ::Misc::StringUtils::ciEqual(item, "gold_100")) item = "gold_001"; MWWorld::ContainerStore& store = ptr.getClass().getContainerStore (ptr); diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index 4debb24fe..e4ad71875 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -228,7 +228,7 @@ namespace MWScript // workaround broken endgame scripts that kill dagoth ur if (!R::implicit && - Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "dagoth_ur_1")) + ::Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "dagoth_ur_1")) { runtime.push (peek); diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index 29187f950..b647a6c88 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -994,7 +994,7 @@ namespace MWWorld template<> - inline void Store::setUp() + void Store::setUp() { // DialInfos marked as deleted are kept during the loading phase, so that the linked list // structure is kept intact for inserting further INFOs. Delete them now that loading is done. @@ -1013,7 +1013,7 @@ namespace MWWorld } template <> - inline void Store::load(ESM::ESMReader &esm, const std::string &id) { + void Store::load(ESM::ESMReader &esm, const std::string &id) { std::string idLower = Misc::StringUtils::lowerCase(id); std::map::iterator it = mStatic.find(idLower); @@ -1029,7 +1029,6 @@ namespace MWWorld // Script //========================================================================= - template <> inline void Store::load(ESM::ESMReader &esm, const std::string &id) { ESM::Script scpt; scpt.load(esm); @@ -1046,7 +1045,6 @@ namespace MWWorld // StartScript //========================================================================= - template <> inline void Store::load(ESM::ESMReader &esm, const std::string &id) { ESM::StartScript s; diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 78ae6fa0b..5008d8fbf 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -1,6 +1,3 @@ -#define _USE_MATH_DEFINES -#include - #include "weather.hpp" #include @@ -26,6 +23,8 @@ #include "fallback.hpp" #include "cellstore.hpp" +#include + using namespace MWWorld; namespace diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 946c3af16..00eac6ca5 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -47,7 +47,7 @@ add_component_dir (sceneutil ) add_component_dir (nif - controlled effect niftypes record controller extra node record_ptr data niffile property nifkey data node base nifstream + controlled effect niftypes record controller extra node record_ptr data niffile property nifkey base nifstream ) add_component_dir (nifosg diff --git a/components/files/windowspath.cpp b/components/files/windowspath.cpp index ece4049a8..4b7c6c50a 100644 --- a/components/files/windowspath.cpp +++ b/components/files/windowspath.cpp @@ -4,9 +4,9 @@ #include -#include #include #include +#include #include namespace bconv = boost::locale::conv; diff --git a/components/vfs/bsaarchive.hpp b/components/vfs/bsaarchive.hpp index 961746947..25ad60e0a 100644 --- a/components/vfs/bsaarchive.hpp +++ b/components/vfs/bsaarchive.hpp @@ -1,3 +1,6 @@ +#ifndef VFS_BSAARCHIVE_HPP_ +#define VFS_BSAARCHIVE_HPP_ + #include "archive.hpp" #include @@ -30,3 +33,5 @@ namespace VFS }; } + +#endif \ No newline at end of file From fec08ef73e286e3749b67b9fa768e7e773a180b0 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Thu, 24 Sep 2015 15:29:08 +0200 Subject: [PATCH 2204/3725] Run unity build --- CI/before_script.msvc.sh | 7 +++++++ appveyor.yml | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/CI/before_script.msvc.sh b/CI/before_script.msvc.sh index cd47cbf8d..756653fe9 100644 --- a/CI/before_script.msvc.sh +++ b/CI/before_script.msvc.sh @@ -16,6 +16,9 @@ while [ $# -gt 0 ]; do -k ) KEEP=true ;; + + -u ) + UNITY_BUILD=true ;; * ) echo "Unknown arg $ARG." @@ -162,6 +165,10 @@ case $PLATFORM in ;; esac +if ! [ -z $UNITY_BUILD ]; then + add_cmake_opts "-DOPENMW_UNITY_BUILD=True" +fi + case $CONFIGURATION in debug|Debug|DEBUG ) CONFIGURATION=Debug diff --git a/appveyor.yml b/appveyor.yml index d5ad13430..e89a54e3b 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -15,7 +15,7 @@ environment: - STEP: misc # - STEP: components # misc builds this too # Build takes too long for these, ignore for now -# - STEP: openmw + - STEP: openmw # - STEP: opencs matrix: @@ -40,7 +40,7 @@ cache: clone_folder: C:\projects\openmw before_build: - - cmd: sh %APPVEYOR_BUILD_FOLDER%\CI\before_script.msvc.sh + - cmd: sh %APPVEYOR_BUILD_FOLDER%\CI\before_script.msvc.sh -u build_script: - cmd: if %PLATFORM%==Win32 set build=Build_32 From b2cb5f037447e6baa8ad6bbdeb076c388d89595a Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 24 Sep 2015 15:51:16 +0200 Subject: [PATCH 2205/3725] pass on user settings updates to potentially interested parties within a scene subview --- apps/opencs/view/render/editmode.cpp | 5 +++++ apps/opencs/view/render/editmode.hpp | 3 +++ apps/opencs/view/render/worldspacewidget.cpp | 5 +++++ apps/opencs/view/render/worldspacewidget.hpp | 2 ++ apps/opencs/view/widget/scenetoolmode.cpp | 5 +++++ apps/opencs/view/widget/scenetoolmode.hpp | 3 +++ apps/opencs/view/world/scenesubview.cpp | 15 ++++++++++++--- apps/opencs/view/world/scenesubview.hpp | 4 ++++ 8 files changed, 39 insertions(+), 3 deletions(-) diff --git a/apps/opencs/view/render/editmode.cpp b/apps/opencs/view/render/editmode.cpp index 8a99ba049..bf96fea3a 100644 --- a/apps/opencs/view/render/editmode.cpp +++ b/apps/opencs/view/render/editmode.cpp @@ -16,3 +16,8 @@ void CSVRender::EditMode::activate (CSVWidget::SceneToolbar *toolbar) { mWorldspaceWidget->setInteractionMask (mMask); } + +void CSVRender::EditMode::updateUserSetting (const QString& name, const QStringList& value) +{ + +} diff --git a/apps/opencs/view/render/editmode.hpp b/apps/opencs/view/render/editmode.hpp index c3192f8ea..381a6abcb 100644 --- a/apps/opencs/view/render/editmode.hpp +++ b/apps/opencs/view/render/editmode.hpp @@ -22,6 +22,9 @@ namespace CSVRender unsigned int getInteractionMask() const; virtual void activate (CSVWidget::SceneToolbar *toolbar); + + /// Default-implementation: Do nothing. + virtual void updateUserSetting (const QString& name, const QStringList& value); }; } diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index a1f0f6bf2..2eb84d0a2 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -254,6 +254,11 @@ unsigned int CSVRender::WorldspaceWidget::getInteractionMask() const return mInteractionMask & getVisibilityMask(); } +void CSVRender::WorldspaceWidget::updateUserSetting (const QString& name, const QStringList& value) +{ + +} + void CSVRender::WorldspaceWidget::addVisibilitySelectorButtons ( CSVWidget::SceneToolToggle2 *tool) { diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp index fe4555820..c3796af34 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -93,6 +93,8 @@ namespace CSVRender /// marked for interaction. unsigned int getInteractionMask() const; + virtual void updateUserSetting (const QString& name, const QStringList& value); + protected: virtual void addVisibilitySelectorButtons (CSVWidget::SceneToolToggle2 *tool); diff --git a/apps/opencs/view/widget/scenetoolmode.cpp b/apps/opencs/view/widget/scenetoolmode.cpp index 9f963873c..a93bb0556 100644 --- a/apps/opencs/view/widget/scenetoolmode.cpp +++ b/apps/opencs/view/widget/scenetoolmode.cpp @@ -71,6 +71,11 @@ void CSVWidget::SceneToolMode::addButton (ModeButton *button, const std::string& } } +CSVWidget::ModeButton *CSVWidget::SceneToolMode::getCurrent() +{ + return mCurrent; +} + void CSVWidget::SceneToolMode::selected() { std::map::const_iterator iter = diff --git a/apps/opencs/view/widget/scenetoolmode.hpp b/apps/opencs/view/widget/scenetoolmode.hpp index e6f462cf8..6828a2269 100644 --- a/apps/opencs/view/widget/scenetoolmode.hpp +++ b/apps/opencs/view/widget/scenetoolmode.hpp @@ -41,6 +41,9 @@ namespace CSVWidget /// The ownership of \a button is transferred to *this. void addButton (ModeButton *button, const std::string& id); + /// Will return a 0-pointer only if the mode does not have any buttons yet. + ModeButton *getCurrent(); + signals: void modeChanged (const std::string& id); diff --git a/apps/opencs/view/world/scenesubview.cpp b/apps/opencs/view/world/scenesubview.cpp index c2f3442f8..f0b18dd86 100644 --- a/apps/opencs/view/world/scenesubview.cpp +++ b/apps/opencs/view/world/scenesubview.cpp @@ -15,6 +15,7 @@ #include "../render/pagedworldspacewidget.hpp" #include "../render/unpagedworldspacewidget.hpp" +#include "../render/editmode.hpp" #include "../widget/scenetoolbar.hpp" #include "../widget/scenetoolmode.hpp" @@ -26,7 +27,8 @@ #include "creator.hpp" CSVWorld::SceneSubView::SceneSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) -: SubView (id), mScene(NULL), mLayout(new QHBoxLayout), mDocument(document), mToolbar(NULL) +: SubView (id), mScene(NULL), mLayout(new QHBoxLayout), mDocument(document), mToolbar(NULL), + mEditMode (0) { QVBoxLayout *layout = new QVBoxLayout; @@ -121,8 +123,8 @@ CSVWidget::SceneToolbar* CSVWorld::SceneSubView::makeToolbar (CSVRender::Worldsp CSVWidget::SceneToolRun *runTool = widget->makeRunTool (toolbar); toolbar->addTool (runTool); - CSVWidget::SceneToolMode *editModeTool = widget->makeEditModeSelector (toolbar); - toolbar->addTool (editModeTool); + mEditMode = widget->makeEditModeSelector (toolbar); + toolbar->addTool (mEditMode); return toolbar; } @@ -147,6 +149,13 @@ std::string CSVWorld::SceneSubView::getTitle() const return mTitle; } +void CSVWorld::SceneSubView::updateUserSetting (const QString& name, const QStringList& value) +{ + mScene->updateUserSetting (name, value); + dynamic_cast (*mEditMode->getCurrent()).updateUserSetting (name, value); + CSVDoc::SubView::updateUserSetting (name, value); +} + void CSVWorld::SceneSubView::cellSelectionChanged (const CSMWorld::UniversalId& id) { setUniversalId(id); diff --git a/apps/opencs/view/world/scenesubview.hpp b/apps/opencs/view/world/scenesubview.hpp index a34d71901..29aca5ab6 100644 --- a/apps/opencs/view/world/scenesubview.hpp +++ b/apps/opencs/view/world/scenesubview.hpp @@ -27,6 +27,7 @@ namespace CSVRender namespace CSVWidget { class SceneToolbar; + class SceneToolMode; } namespace CSVWorld @@ -45,6 +46,7 @@ namespace CSVWorld CSMDoc::Document& mDocument; CSVWidget::SceneToolbar* mToolbar; std::string mTitle; + CSVWidget::SceneToolMode *mEditMode; public: @@ -58,6 +60,8 @@ namespace CSVWorld virtual std::string getTitle() const; + virtual void updateUserSetting (const QString& name, const QStringList& value); + private: void makeConnections(CSVRender::PagedWorldspaceWidget* widget); From caa119f13c7599736b7e7466371d09c92cd696db Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Thu, 24 Sep 2015 15:55:38 +0200 Subject: [PATCH 2206/3725] Fix instantiation on non-Visual Studio --- apps/openmw/mwworld/store.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index b647a6c88..7a471eaa4 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -1029,7 +1029,8 @@ namespace MWWorld // Script //========================================================================= - inline void Store::load(ESM::ESMReader &esm, const std::string &id) { + template <> + void Store::load(ESM::ESMReader &esm, const std::string &id) { ESM::Script scpt; scpt.load(esm); Misc::StringUtils::toLower(scpt.mId); @@ -1045,7 +1046,8 @@ namespace MWWorld // StartScript //========================================================================= - inline void Store::load(ESM::ESMReader &esm, const std::string &id) + template <> + void Store::load(ESM::ESMReader &esm, const std::string &id) { ESM::StartScript s; s.load(esm); From 33175b44b827601c070776891a679eda617cf8b0 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Thu, 24 Sep 2015 16:02:03 +0200 Subject: [PATCH 2207/3725] Disable SDL main library --- CI/before_script.msvc.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CI/before_script.msvc.sh b/CI/before_script.msvc.sh index 756653fe9..bc8965066 100644 --- a/CI/before_script.msvc.sh +++ b/CI/before_script.msvc.sh @@ -520,8 +520,8 @@ printf "SDL 2.0.3... " SDL_SDK="`real_pwd`/SDL2-2.0.3" add_cmake_opts -DSDL2_INCLUDE_DIR="$SDL_SDK/include" \ - -DSDL2MAIN_LIBRARY="$SDL_SDK/lib/x$ARCHSUFFIX/SDL2main.lib" \ - -DSDL2_LIBRARY_PATH="$SDL_SDK/lib/x$ARCHSUFFIX/SDL2.lib" + -DSDL2_LIBRARY_PATH="$SDL_SDK/lib/x$ARCHSUFFIX/SDL2.lib" \ + -DSDL2_LIBRARY_ONLY="$SDL_SDK/lib/x$ARCHSUFFIX/SDL2.lib" add_runtime_dlls `pwd`/SDL2-2.0.3/lib/x$ARCHSUFFIX/SDL2.dll From 3ada08af90dab4440247ba4b3190b669e6b42b73 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 24 Sep 2015 16:07:17 +0200 Subject: [PATCH 2208/3725] store lock state and pass it on to edit mode --- apps/opencs/view/render/editmode.cpp | 5 +++++ apps/opencs/view/render/editmode.hpp | 3 +++ apps/opencs/view/world/scenesubview.cpp | 13 +++++++++++-- apps/opencs/view/world/scenesubview.hpp | 3 +++ 4 files changed, 22 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/render/editmode.cpp b/apps/opencs/view/render/editmode.cpp index bf96fea3a..c3aad3f7a 100644 --- a/apps/opencs/view/render/editmode.cpp +++ b/apps/opencs/view/render/editmode.cpp @@ -21,3 +21,8 @@ void CSVRender::EditMode::updateUserSetting (const QString& name, const QStringL { } + +void CSVRender::EditMode::setEditLock (bool locked) +{ + +} diff --git a/apps/opencs/view/render/editmode.hpp b/apps/opencs/view/render/editmode.hpp index 381a6abcb..1212cd285 100644 --- a/apps/opencs/view/render/editmode.hpp +++ b/apps/opencs/view/render/editmode.hpp @@ -25,6 +25,9 @@ namespace CSVRender /// Default-implementation: Do nothing. virtual void updateUserSetting (const QString& name, const QStringList& value); + + /// Default-implementation: Ignored. + virtual void setEditLock (bool locked); }; } diff --git a/apps/opencs/view/world/scenesubview.cpp b/apps/opencs/view/world/scenesubview.cpp index f0b18dd86..967909969 100644 --- a/apps/opencs/view/world/scenesubview.cpp +++ b/apps/opencs/view/world/scenesubview.cpp @@ -28,7 +28,7 @@ CSVWorld::SceneSubView::SceneSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) : SubView (id), mScene(NULL), mLayout(new QHBoxLayout), mDocument(document), mToolbar(NULL), - mEditMode (0) + mEditMode (0), mLocked (false) { QVBoxLayout *layout = new QVBoxLayout; @@ -131,7 +131,8 @@ CSVWidget::SceneToolbar* CSVWorld::SceneSubView::makeToolbar (CSVRender::Worldsp void CSVWorld::SceneSubView::setEditLock (bool locked) { - + mLocked = locked; + dynamic_cast (*mEditMode->getCurrent()).setEditLock (locked); } void CSVWorld::SceneSubView::setStatusBar (bool show) @@ -258,4 +259,12 @@ void CSVWorld::SceneSubView::replaceToolbarAndWorldspace (CSVRender::WorldspaceW mScene->selectDefaultNavigationMode(); setFocusProxy (mScene); + + connect (mEditMode, SIGNAL (modeChanged (const std::string&)), + this, SLOT (editModeChanged (const std::string&))); +} + +void CSVWorld::SceneSubView::editModeChanged (const std::string& id) +{ + dynamic_cast (*mEditMode->getCurrent()).setEditLock (mLocked); } diff --git a/apps/opencs/view/world/scenesubview.hpp b/apps/opencs/view/world/scenesubview.hpp index 29aca5ab6..f59fee37f 100644 --- a/apps/opencs/view/world/scenesubview.hpp +++ b/apps/opencs/view/world/scenesubview.hpp @@ -47,6 +47,7 @@ namespace CSVWorld CSVWidget::SceneToolbar* mToolbar; std::string mTitle; CSVWidget::SceneToolMode *mEditMode; + bool mLocked; public: @@ -85,6 +86,8 @@ namespace CSVWorld void cellSelectionChanged (const CSMWorld::UniversalId& id); void handleDrop(const std::vector& data); + + void editModeChanged (const std::string& id); }; } From 7df115d61bade2750fb22a1e0eaeb473d07aebbd Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Thu, 24 Sep 2015 16:21:40 +0200 Subject: [PATCH 2209/3725] Just run OpenMW builds for now --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index e89a54e3b..ea508abd6 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -12,7 +12,7 @@ configuration: Debug environment: matrix: - - STEP: misc +# - STEP: misc # - STEP: components # misc builds this too # Build takes too long for these, ignore for now - STEP: openmw From 2e174fd1b5981103fc317bcca83a06748c6b02c1 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Thu, 24 Sep 2015 19:59:17 +0200 Subject: [PATCH 2210/3725] Readd SDL2 main --- CI/before_script.msvc.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CI/before_script.msvc.sh b/CI/before_script.msvc.sh index bc8965066..756653fe9 100644 --- a/CI/before_script.msvc.sh +++ b/CI/before_script.msvc.sh @@ -520,8 +520,8 @@ printf "SDL 2.0.3... " SDL_SDK="`real_pwd`/SDL2-2.0.3" add_cmake_opts -DSDL2_INCLUDE_DIR="$SDL_SDK/include" \ - -DSDL2_LIBRARY_PATH="$SDL_SDK/lib/x$ARCHSUFFIX/SDL2.lib" \ - -DSDL2_LIBRARY_ONLY="$SDL_SDK/lib/x$ARCHSUFFIX/SDL2.lib" + -DSDL2MAIN_LIBRARY="$SDL_SDK/lib/x$ARCHSUFFIX/SDL2main.lib" \ + -DSDL2_LIBRARY_PATH="$SDL_SDK/lib/x$ARCHSUFFIX/SDL2.lib" add_runtime_dlls `pwd`/SDL2-2.0.3/lib/x$ARCHSUFFIX/SDL2.dll From d597bef2cda32eea1c12d623d0956d6e18b05976 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 25 Sep 2015 10:58:20 +0200 Subject: [PATCH 2211/3725] refined selection related user settings --- apps/opencs/model/settings/usersettings.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/settings/usersettings.cpp b/apps/opencs/model/settings/usersettings.cpp index 3daf7f9ec..5cc60c318 100644 --- a/apps/opencs/model/settings/usersettings.cpp +++ b/apps/opencs/model/settings/usersettings.cpp @@ -399,11 +399,12 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() secondaryEditing->setDeclaredValues (values); secondaryEditing->setDefaultValue (cRight); - values << "Context Sensitive"; - Setting *selection = createSetting (Type_ComboBox, "select", "Selection Button"); selection->setDeclaredValues (values); selection->setDefaultValue (middle); + + Setting *contextSensitive = createSetting (Type_CheckBox, "context-select", "Context Sensitive Selection"); + contextSensitive->setDefaultValue ("false"); } { From 5c34a0205804dd718cc4d6efe26ee3be51b37101 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 25 Sep 2015 13:11:40 +0200 Subject: [PATCH 2212/3725] store mouse bindings in WorldspaceWidget --- apps/opencs/view/render/worldspacewidget.cpp | 57 +++++++++++++++++++- apps/opencs/view/render/worldspacewidget.hpp | 6 +++ 2 files changed, 62 insertions(+), 1 deletion(-) diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 2eb84d0a2..5d866fc6c 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -18,6 +18,8 @@ #include "../../model/world/universalid.hpp" #include "../../model/world/idtable.hpp" +#include "../../model/settings/usersettings.hpp" + #include "../widget/scenetoolmode.hpp" #include "../widget/scenetooltoggle2.hpp" #include "../widget/scenetoolrun.hpp" @@ -26,6 +28,17 @@ #include "elements.hpp" #include "editmode.hpp" +namespace +{ + static const char * const sMappingSettings[] = + { + "p-navi", "s-navi", + "p-edit", "s-edit", + "select", + 0 + }; +} + CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidget* parent) : SceneWidget (document.getData().getResourceSystem(), parent), mSceneElements(0), mRun(0), mDocument(document), mInteractionMask (0) @@ -59,6 +72,13 @@ CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidg this, SLOT (debugProfileDataChanged (const QModelIndex&, const QModelIndex&))); connect (debugProfiles, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)), this, SLOT (debugProfileAboutToBeRemoved (const QModelIndex&, int, int))); + + for (int i=0; sMappingSettings[i]; ++i) + { + QString key ("scene-input/"); + key += sMappingSettings[i]; + storeMappingSetting (key, CSMSettings::UserSettings::instance().settingValue (key)); + } } CSVRender::WorldspaceWidget::~WorldspaceWidget () @@ -256,7 +276,8 @@ unsigned int CSVRender::WorldspaceWidget::getInteractionMask() const void CSVRender::WorldspaceWidget::updateUserSetting (const QString& name, const QStringList& value) { - + if (!value.isEmpty() && storeMappingSetting (name, value.first())) + return; } void CSVRender::WorldspaceWidget::addVisibilitySelectorButtons ( @@ -293,6 +314,40 @@ void CSVRender::WorldspaceWidget::dragMoveEvent(QDragMoveEvent *event) event->accept(); } + +bool CSVRender::WorldspaceWidget::storeMappingSetting (const QString& key, const QString& value) +{ + const QString prefix = "scene-input/"; + + if (key.startsWith (prefix)) + { + QString key2 (key.mid (prefix.length())); + + for (int i=0; sMappingSettings[i]; ++i) + if (key2==sMappingSettings[i]) + { + std::cout<<"button :"< (event->mimeData()); diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp index c3796af34..23f672fbd 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -1,6 +1,8 @@ #ifndef OPENCS_VIEW_WORLDSPACEWIDGET_H #define OPENCS_VIEW_WORLDSPACEWIDGET_H +#include + #include #include "scenewidget.hpp" @@ -31,6 +33,7 @@ namespace CSVRender CSVWidget::SceneToolRun *mRun; CSMDoc::Document& mDocument; unsigned int mInteractionMask; + std::map, std::string> mButtonMapping; public: @@ -120,6 +123,9 @@ namespace CSVRender void dragMoveEvent(QDragMoveEvent *event); + /// \return Is \a key a button mapping setting? (ignored otherwise) + bool storeMappingSetting (const QString& key, const QString& value); + virtual std::string getStartupInstruction() = 0; private slots: From d46eeb04cd49d3543e3800707789fde4bdf8cadf Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 25 Sep 2015 14:16:41 +0200 Subject: [PATCH 2213/3725] removed a left-over debugging statement --- apps/opencs/view/render/worldspacewidget.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 5d866fc6c..834762a67 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -326,7 +326,6 @@ bool CSVRender::WorldspaceWidget::storeMappingSetting (const QString& key, const for (int i=0; sMappingSettings[i]; ++i) if (key2==sMappingSettings[i]) { - std::cout<<"button :"< Date: Fri, 25 Sep 2015 14:18:08 +0200 Subject: [PATCH 2214/3725] scripts: recognize '+' also as a unary operator it fixes the armor sorter in "Blades safe house.esp" --- components/compiler/exprparser.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/components/compiler/exprparser.cpp b/components/compiler/exprparser.cpp index b588b6196..53b24eab6 100644 --- a/components/compiler/exprparser.cpp +++ b/components/compiler/exprparser.cpp @@ -650,8 +650,13 @@ namespace Compiler mOperators.push_back ('m'); mTokenLoc = loc; return true; + } else if (code ==Scanner::S_plus && mNextOperand) { + // Also unary, but +, just ignore it + mTokenLoc = loc; + return true; } + if (code==Scanner::S_open) { if (mNextOperand) From 2fff6b06cc604b436fe075232b2e11c5242385b0 Mon Sep 17 00:00:00 2001 From: Emmanuel Anne Date: Thu, 24 Sep 2015 16:42:10 +0200 Subject: [PATCH 2215/3725] removed items by mods do not break cell loading like fortify intelligence potions removed by sris_alchemy which break the loading of the firewatch mages guild --- apps/openmw/mwworld/containerstore.cpp | 59 ++++++++++++++------------ 1 file changed, 33 insertions(+), 26 deletions(-) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 8c6f7d259..5a26f09f5 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -411,41 +411,48 @@ void MWWorld::ContainerStore::fill (const ESM::InventoryList& items, const std:: void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std::string& owner, int count, bool topLevel, const std::string& levItem) { - ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), id, count); + try { + ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), id, count); - if (ref.getPtr().getTypeName()==typeid (ESM::ItemLevList).name()) - { - const ESM::ItemLevList* levItem = ref.getPtr().get()->mBase; - - if (topLevel && std::abs(count) > 1 && levItem->mFlags & ESM::ItemLevList::Each) + if (ref.getPtr().getTypeName()==typeid (ESM::ItemLevList).name()) { - for (int i=0; i 0 ? 1 : -1, true, levItem->mId); - return; + const ESM::ItemLevList* levItem = ref.getPtr().get()->mBase; + + if (topLevel && std::abs(count) > 1 && levItem->mFlags & ESM::ItemLevList::Each) + { + for (int i=0; i 0 ? 1 : -1, true, levItem->mId); + return; + } + else + { + std::string id = MWMechanics::getLevelledItem(ref.getPtr().get()->mBase, false); + if (id.empty()) + return; + addInitialItem(id, owner, count, false, levItem->mId); + } } else { - std::string id = MWMechanics::getLevelledItem(ref.getPtr().get()->mBase, false); - if (id.empty()) - return; - addInitialItem(id, owner, count, false, levItem->mId); + // A negative count indicates restocking items + // For a restocking levelled item, remember what we spawned so we can delete it later when the merchant restocks + if (!levItem.empty() && count < 0) + { + if (mLevelledItemMap.find(id) == mLevelledItemMap.end()) + mLevelledItemMap[id] = 0; + mLevelledItemMap[id] += std::abs(count); + } + count = std::abs(count); + + ref.getPtr().getCellRef().setOwner(owner); + addImp (ref.getPtr(), count); } } - else + catch (const std::exception& e) { - // A negative count indicates restocking items - // For a restocking levelled item, remember what we spawned so we can delete it later when the merchant restocks - if (!levItem.empty() && count < 0) - { - if (mLevelledItemMap.find(id) == mLevelledItemMap.end()) - mLevelledItemMap[id] = 0; - mLevelledItemMap[id] += std::abs(count); - } - count = std::abs(count); - - ref.getPtr().getCellRef().setOwner(owner); - addImp (ref.getPtr(), count); + std::cerr << "Error in MWWorld::ContainerStore::addInitialItem: " << e.what() << std::endl; } + } void MWWorld::ContainerStore::restock (const ESM::InventoryList& items, const MWWorld::Ptr& ptr, const std::string& owner) From 169d76b49b7b304b44170a6a042b627dd2c29e1f Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 26 Sep 2015 01:20:20 +0200 Subject: [PATCH 2216/3725] Fix scrollbar step in count dialog --- files/mygui/openmw_count_window.layout | 2 ++ 1 file changed, 2 insertions(+) diff --git a/files/mygui/openmw_count_window.layout b/files/mygui/openmw_count_window.layout index e9a1cb2c8..27b62ebf0 100644 --- a/files/mygui/openmw_count_window.layout +++ b/files/mygui/openmw_count_window.layout @@ -13,6 +13,8 @@ + + From 8e69c80bf60456687491e975c92ab39eaf314cfd Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 26 Sep 2015 01:21:33 +0200 Subject: [PATCH 2217/3725] Add framenumber checks in various cull callbacks, so we don't update more than once per frame when multiple cameras are used --- components/nifosg/nifloader.cpp | 13 ++++++++++++- components/sceneutil/riggeometry.cpp | 11 +++++++---- components/sceneutil/riggeometry.hpp | 2 +- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 54a02c950..75a427c5a 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -113,6 +113,7 @@ namespace // NodeCallback used to have a transform always oriented towards the camera. Can have translation and scale // set just like a regular MatrixTransform, but the rotation set will be overridden in order to face the camera. + // Must be set as a cull callback. class BillboardCallback : public osg::NodeCallback { public: @@ -160,24 +161,34 @@ namespace struct UpdateMorphGeometry : public osg::Drawable::CullCallback { UpdateMorphGeometry() + : mLastFrameNumber(0) { } UpdateMorphGeometry(const UpdateMorphGeometry& copy, const osg::CopyOp& copyop) : osg::Drawable::CullCallback(copy, copyop) + , mLastFrameNumber(0) { } META_Object(NifOsg, UpdateMorphGeometry) - virtual bool cull(osg::NodeVisitor *, osg::Drawable * drw, osg::State *) const + virtual bool cull(osg::NodeVisitor* nv, osg::Drawable * drw, osg::State *) const { osgAnimation::MorphGeometry* geom = static_cast(drw); if (!geom) return false; + + if (mLastFrameNumber == nv->getFrameStamp()->getFrameNumber()) + return false; + mLastFrameNumber = nv->getFrameStamp()->getFrameNumber(); + geom->transformSoftwareMethod(); return false; } + + private: + mutable unsigned int mLastFrameNumber; }; // Callback to return a static bounding box for a MorphGeometry. The idea is to not recalculate the bounding box diff --git a/components/sceneutil/riggeometry.cpp b/components/sceneutil/riggeometry.cpp index 2a67c6ce6..8eb08f546 100644 --- a/components/sceneutil/riggeometry.cpp +++ b/components/sceneutil/riggeometry.cpp @@ -60,7 +60,7 @@ public: RigGeometry::RigGeometry() : mSkeleton(NULL) - , mFirstFrame(true) + , mLastFrameNumber(0) , mBoundsFirstFrame(true) { setCullCallback(new UpdateRigGeometry); @@ -72,7 +72,7 @@ RigGeometry::RigGeometry(const RigGeometry ©, const osg::CopyOp ©op) : osg::Geometry(copy, copyop) , mSkeleton(NULL) , mInfluenceMap(copy.mInfluenceMap) - , mFirstFrame(copy.mFirstFrame) + , mLastFrameNumber(0) , mBoundsFirstFrame(copy.mBoundsFirstFrame) { setSourceGeometry(copy.mSourceGeometry); @@ -206,9 +206,12 @@ void RigGeometry::update(osg::NodeVisitor* nv) return; } - if (!mSkeleton->getActive() && !mFirstFrame) + if (!mSkeleton->getActive() && mLastFrameNumber != 0) return; - mFirstFrame = false; + + if (mLastFrameNumber == nv->getFrameStamp()->getFrameNumber()) + return; + mLastFrameNumber = nv->getFrameStamp()->getFrameNumber(); mSkeleton->updateBoneMatrices(nv); diff --git a/components/sceneutil/riggeometry.hpp b/components/sceneutil/riggeometry.hpp index bd7c586c4..e51fc0cf6 100644 --- a/components/sceneutil/riggeometry.hpp +++ b/components/sceneutil/riggeometry.hpp @@ -64,7 +64,7 @@ namespace SceneUtil BoneSphereMap mBoneSphereMap; - bool mFirstFrame; + unsigned int mLastFrameNumber; bool mBoundsFirstFrame; bool initFromParentSkeleton(osg::NodeVisitor* nv); From b9c6a6862a328cc044793a5c8547ca9e67ec9406 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 26 Sep 2015 01:49:58 +0200 Subject: [PATCH 2218/3725] Don't reset god mode, scripts enabled and sky enabled flags when loading a save game These flags aren't stored in the save file, so it makes no sense to reset them to their default each time a save game is loaded. Instead, reset on "new game". --- apps/openmw/mwworld/worldimp.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 3ff7a750a..585786136 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -204,6 +204,10 @@ namespace MWWorld mLevitationEnabled = true; mTeleportEnabled = true; + mGodMode = false; + mScriptsEnabled = true; + mSky = true; + // Rebuild player setupPlayer(); @@ -297,9 +301,6 @@ namespace MWWorld mDoorStates.clear(); - mGodMode = false; - mScriptsEnabled = true; - mSky = true; mTeleportEnabled = true; mLevitationEnabled = true; From 387624e1580d4345dcbd3a3ae3a695de94bdd377 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 26 Sep 2015 01:55:12 +0200 Subject: [PATCH 2219/3725] Add a threshold to AiFollow distance Idle animations can move the actor around slightly, which sometimes causes AiFollow to constantly toggle between "arrived" and "following" state even when the player isn't moving. Could be observed by summoning a bonelord. --- apps/openmw/mwmechanics/aifollow.cpp | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/aifollow.cpp b/apps/openmw/mwmechanics/aifollow.cpp index cd67c6058..d9356da93 100644 --- a/apps/openmw/mwmechanics/aifollow.cpp +++ b/apps/openmw/mwmechanics/aifollow.cpp @@ -20,8 +20,9 @@ namespace MWMechanics struct AiFollowStorage : AiTemporaryBase { float mTimer; + bool mMoving; - AiFollowStorage() : mTimer(0.f) {} + AiFollowStorage() : mTimer(0.f), mMoving(false) {} }; int AiFollow::mFollowIndexCounter = 0; @@ -64,10 +65,11 @@ bool AiFollow::execute (const MWWorld::Ptr& actor, CharacterController& characte actor.getClass().getCreatureStats(actor).setDrawState(DrawState_Nothing); + AiFollowStorage& storage = state.get(); + // AiFollow requires the target to be in range and within sight for the initial activation if (!mActive) { - AiFollowStorage& storage = state.get(); storage.mTimer -= duration; if (storage.mTimer < 0) @@ -126,7 +128,15 @@ bool AiFollow::execute (const MWWorld::Ptr& actor, CharacterController& characte //Set the target destination from the actor ESM::Pathgrid::Point dest = target.getRefData().getPosition().pos; - if(distance(dest, pos.pos[0], pos.pos[1], pos.pos[2]) < followDistance) //Stop when you get close + float dist = distance(dest, pos.pos[0], pos.pos[1], pos.pos[2]); + const float threshold = 10; + + if (storage.mMoving) //Stop when you get close + storage.mMoving = (dist > followDistance); + else + storage.mMoving = (dist > followDistance + threshold); + + if(!storage.mMoving) { actor.getClass().getMovementSettings(actor).mPosition[1] = 0; @@ -141,9 +151,9 @@ bool AiFollow::execute (const MWWorld::Ptr& actor, CharacterController& characte } //Check if you're far away - if(distance(dest, pos.pos[0], pos.pos[1], pos.pos[2]) > 450) + if(dist > 450) actor.getClass().getCreatureStats(actor).setMovementFlag(MWMechanics::CreatureStats::Flag_Run, true); //Make NPC run - else if(distance(dest, pos.pos[0], pos.pos[1], pos.pos[2]) < 325) //Have a bit of a dead zone, otherwise npc will constantly flip between running and not when right on the edge of the running threshhold + else if(dist < 325) //Have a bit of a dead zone, otherwise npc will constantly flip between running and not when right on the edge of the running threshhold actor.getClass().getCreatureStats(actor).setMovementFlag(MWMechanics::CreatureStats::Flag_Run, false); //make NPC walk return false; From 899e35591c24c5cd90d88f680c8a5011b32ab79c Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 26 Sep 2015 02:08:23 +0200 Subject: [PATCH 2220/3725] Escape MyGUI markup codes in console output --- apps/openmw/mwgui/console.cpp | 10 +++++----- apps/openmw/mwgui/console.hpp | 5 ++--- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwgui/console.cpp b/apps/openmw/mwgui/console.cpp index 083dd32b0..761f7d164 100644 --- a/apps/openmw/mwgui/console.cpp +++ b/apps/openmw/mwgui/console.cpp @@ -170,25 +170,25 @@ namespace MWGui mCommandLine->setFontName(fntName); } - void Console::print(const std::string &msg) + void Console::print(const std::string &msg, const std::string& color) { - mHistory->addText(msg); + mHistory->addText(color + MyGUI::TextIterator::toTagsString(msg)); } void Console::printOK(const std::string &msg) { - print("#FF00FF" + msg + "\n"); + print(msg + "\n", "#FF00FF"); } void Console::printError(const std::string &msg) { - print("#FF2222" + msg + "\n"); + print(msg + "\n", "#FF2222"); } void Console::execute (const std::string& command) { // Log the command - print("#FFFFFF> " + command + "\n"); + print("> " + command + "\n"); Compiler::Locals locals; Compiler::Output output (locals); diff --git a/apps/openmw/mwgui/console.hpp b/apps/openmw/mwgui/console.hpp index 09a05be48..98e46a559 100644 --- a/apps/openmw/mwgui/console.hpp +++ b/apps/openmw/mwgui/console.hpp @@ -48,9 +48,8 @@ namespace MWGui void onResChange(int width, int height); - // Print a message to the console. Messages may contain color - // code, eg. "#FFFFFF this is white". - void print(const std::string &msg); + // Print a message to the console, in specified color. + void print(const std::string &msg, const std::string& color = "#FFFFFF"); // These are pre-colored versions that you should use. From ae54f34f25ce08a2abc5ee9a162292940d256c84 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 26 Sep 2015 11:30:35 +0200 Subject: [PATCH 2221/3725] removed a redundant else and made unary + work also in the console --- components/compiler/exprparser.cpp | 6 ++++-- components/compiler/lineparser.cpp | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/components/compiler/exprparser.cpp b/components/compiler/exprparser.cpp index 53b24eab6..c0375b436 100644 --- a/components/compiler/exprparser.cpp +++ b/components/compiler/exprparser.cpp @@ -650,13 +650,15 @@ namespace Compiler mOperators.push_back ('m'); mTokenLoc = loc; return true; - } else if (code ==Scanner::S_plus && mNextOperand) { + } + + if (code ==Scanner::S_plus && mNextOperand) + { // Also unary, but +, just ignore it mTokenLoc = loc; return true; } - if (code==Scanner::S_open) { if (mNextOperand) diff --git a/components/compiler/lineparser.cpp b/components/compiler/lineparser.cpp index 032af7d65..c1622c3e0 100644 --- a/components/compiler/lineparser.cpp +++ b/components/compiler/lineparser.cpp @@ -555,7 +555,7 @@ namespace Compiler } if (mAllowExpression && mState==BeginState && - (code==Scanner::S_open || code==Scanner::S_minus)) + (code==Scanner::S_open || code==Scanner::S_minus || code==Scanner::S_plus)) { scanner.putbackSpecial (code, loc); parseExpression (scanner, loc); From 435e52306a0b1a7ef4cf7059bbc388b3262d2631 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 26 Sep 2015 11:34:46 +0200 Subject: [PATCH 2222/3725] adjusted a workaround for names starting with digits that interfered with some numerical expressions written without spaces --- components/compiler/scanner.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/compiler/scanner.cpp b/components/compiler/scanner.cpp index f25e69e39..3c5bb7747 100644 --- a/components/compiler/scanner.cpp +++ b/components/compiler/scanner.cpp @@ -175,7 +175,7 @@ namespace Compiler { value += c; } - else if (isStringCharacter (c)) + else if (c!='-' && isStringCharacter (c)) { error = true; value += c; From 748b13b45b5b08ac0184dd3cb8acd4ef30f5302a Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 26 Sep 2015 12:05:44 +0200 Subject: [PATCH 2223/3725] renamed ObjectHolder into ObjectTag --- apps/opencs/view/render/object.cpp | 2 +- apps/opencs/view/render/object.hpp | 4 ++-- apps/opencs/view/render/worldspacewidget.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index f05e311f9..c7485c891 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -124,7 +124,7 @@ CSVRender::Object::Object (CSMWorld::Data& data, osg::Group* parentNode, mOutline = new osgFX::Scribe; mOutline->addChild(mBaseNode); - mBaseNode->setUserData(new ObjectHolder(this)); + mBaseNode->setUserData(new ObjectTag(this)); parentNode->addChild(mBaseNode); diff --git a/apps/opencs/view/render/object.hpp b/apps/opencs/view/render/object.hpp index 9b3749069..1a1295b53 100644 --- a/apps/opencs/view/render/object.hpp +++ b/apps/opencs/view/render/object.hpp @@ -39,10 +39,10 @@ namespace CSVRender class Object; // An object to attach as user data to the osg::Node, allows us to get an Object back from a Node when we are doing a ray query - class ObjectHolder : public osg::Referenced + class ObjectTag : public osg::Referenced { public: - ObjectHolder(Object* obj) + ObjectTag (Object* obj) : mObject(obj) { } diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 834762a67..378b5bea9 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -463,7 +463,7 @@ void CSVRender::WorldspaceWidget::mousePressEvent (QMouseEvent *event) for (std::vector::iterator it = intersection.nodePath.begin(); it != intersection.nodePath.end(); ++it) { osg::Node* node = *it; - if (CSVRender::ObjectHolder* holder = dynamic_cast(node->getUserData())) + if (CSVRender::ObjectTag* holder = dynamic_cast(node->getUserData())) { // hit an Object, toggle its selection state CSVRender::Object* obj = holder->mObject; From 71247a018652cf5ac4894e1f242daccd971e41bb Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 26 Sep 2015 12:18:18 +0200 Subject: [PATCH 2224/3725] inserted TagBase between ObjectTag and osg::Referenced --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/view/render/object.cpp | 5 +++++ apps/opencs/view/render/object.hpp | 17 ++++++++--------- apps/opencs/view/render/tagbase.cpp | 9 +++++++++ apps/opencs/view/render/tagbase.hpp | 22 ++++++++++++++++++++++ 5 files changed, 45 insertions(+), 10 deletions(-) create mode 100644 apps/opencs/view/render/tagbase.cpp create mode 100644 apps/opencs/view/render/tagbase.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index f9a73a09f..cfa938473 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -90,7 +90,7 @@ opencs_units (view/render opencs_units_noqt (view/render lighting lightingday lightingnight - lightingbright object cell terrainstorage + lightingbright object cell terrainstorage tagbase ) opencs_hdrs_noqt (view/render diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index c7485c891..ac96cb283 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -38,6 +38,11 @@ namespace } +CSVRender::ObjectTag::ObjectTag (Object* object) +: TagBase (Element_Reference), mObject (object) +{} + + void CSVRender::Object::clear() { } diff --git a/apps/opencs/view/render/object.hpp b/apps/opencs/view/render/object.hpp index 1a1295b53..0858a2edb 100644 --- a/apps/opencs/view/render/object.hpp +++ b/apps/opencs/view/render/object.hpp @@ -8,8 +8,9 @@ #include #include -class QModelIndex; +#include "tagbase.hpp" +class QModelIndex; namespace osg { @@ -35,21 +36,19 @@ namespace CSMWorld namespace CSVRender { - class Object; // An object to attach as user data to the osg::Node, allows us to get an Object back from a Node when we are doing a ray query - class ObjectTag : public osg::Referenced + class ObjectTag : public TagBase { - public: - ObjectTag (Object* obj) - : mObject(obj) - { - } + public: + + ObjectTag (Object* object); - Object* mObject; + Object* mObject; }; + class Object { const CSMWorld::Data& mData; diff --git a/apps/opencs/view/render/tagbase.cpp b/apps/opencs/view/render/tagbase.cpp new file mode 100644 index 000000000..af9a37624 --- /dev/null +++ b/apps/opencs/view/render/tagbase.cpp @@ -0,0 +1,9 @@ + +#include "tagbase.hpp" + +CSVRender::TagBase::TagBase (Elements element) : mElement (element) {} + +CSVRender::Elements CSVRender::TagBase::getElement() const +{ + return mElement; +} diff --git a/apps/opencs/view/render/tagbase.hpp b/apps/opencs/view/render/tagbase.hpp new file mode 100644 index 000000000..874b856c6 --- /dev/null +++ b/apps/opencs/view/render/tagbase.hpp @@ -0,0 +1,22 @@ +#ifndef OPENCS_VIEW_TAGBASE_H +#define OPENCS_VIEW_TAGBASE_H + +#include + +#include "elements.hpp" + +namespace CSVRender +{ + class TagBase : public osg::Referenced + { + Elements mElement; + + public: + + TagBase (Elements element); + + Elements getElement() const; + }; +} + +#endif From 72bb33c2c479ef82eebe5c07450c0f4388848891 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 26 Sep 2015 12:24:41 +0200 Subject: [PATCH 2225/3725] filter mouse interaction by interaction mask --- apps/opencs/view/render/worldspacewidget.cpp | 21 ++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 378b5bea9..246f6a4bf 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -463,18 +463,27 @@ void CSVRender::WorldspaceWidget::mousePressEvent (QMouseEvent *event) for (std::vector::iterator it = intersection.nodePath.begin(); it != intersection.nodePath.end(); ++it) { osg::Node* node = *it; - if (CSVRender::ObjectTag* holder = dynamic_cast(node->getUserData())) + if (CSVRender::TagBase* tag = dynamic_cast(node->getUserData())) { - // hit an Object, toggle its selection state - CSVRender::Object* obj = holder->mObject; - obj->setSelected(!obj->getSelected()); + if (!(tag->getElement() && mInteractionMask)) + break; // not interested -> continue looking + + // hit something marked with a tag + if (CSVRender::ObjectTag *objectTag = dynamic_cast (tag)) + { + // hit an Object, toggle its selection state + CSVRender::Object* object = objectTag->mObject; + object->setSelected (!object->getSelected()); + } + return; } } +// ignoring terrain for now // must be terrain, report coordinates - std::cout << "Terrain hit at " << intersection.getWorldIntersectPoint().x() << " " << intersection.getWorldIntersectPoint().y() << std::endl; - return; +// std::cout << "Terrain hit at " << intersection.getWorldIntersectPoint().x() << " " << intersection.getWorldIntersectPoint().y() << std::endl; +// return; } } From 3844c94975d18f7b98a3cd19f7e57ec310df636c Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 26 Sep 2015 17:39:55 +0200 Subject: [PATCH 2226/3725] bit masking fix --- apps/opencs/view/render/worldspacewidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 246f6a4bf..42f81eea4 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -465,7 +465,7 @@ void CSVRender::WorldspaceWidget::mousePressEvent (QMouseEvent *event) osg::Node* node = *it; if (CSVRender::TagBase* tag = dynamic_cast(node->getUserData())) { - if (!(tag->getElement() && mInteractionMask)) + if (!(tag->getElement() & mInteractionMask)) break; // not interested -> continue looking // hit something marked with a tag From 501ae6372d60a6d6932f5ed72719da6196fcc665 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 26 Sep 2015 17:51:41 +0200 Subject: [PATCH 2227/3725] factored out mouse picking into a separate function --- apps/opencs/view/render/worldspacewidget.cpp | 97 +++++++++++--------- apps/opencs/view/render/worldspacewidget.hpp | 4 + 2 files changed, 57 insertions(+), 44 deletions(-) diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 42f81eea4..15978e0e1 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -347,6 +347,53 @@ bool CSVRender::WorldspaceWidget::storeMappingSetting (const QString& key, const return false; } +osg::ref_ptr CSVRender::WorldspaceWidget::mousePick (QMouseEvent *event) +{ + // (0,0) is considered the lower left corner of an OpenGL window + int x = event->x(); + int y = height() - event->y(); + + osg::ref_ptr intersector (new osgUtil::LineSegmentIntersector(osgUtil::Intersector::WINDOW, x, y)); + + intersector->setIntersectionLimit(osgUtil::LineSegmentIntersector::NO_LIMIT); + osgUtil::IntersectionVisitor visitor(intersector); + + visitor.setTraversalMask(getInteractionMask() << 1); + + mView->getCamera()->accept(visitor); + + for (osgUtil::LineSegmentIntersector::Intersections::iterator it = intersector->getIntersections().begin(); + it != intersector->getIntersections().end(); ++it) + { + osgUtil::LineSegmentIntersector::Intersection intersection = *it; + + // reject back-facing polygons + osg::Vec3f normal = intersection.getWorldIntersectNormal(); + normal = osg::Matrix::transform3x3(normal, mView->getCamera()->getViewMatrix()); + if (normal.z() < 0) + continue; + + for (std::vector::iterator it = intersection.nodePath.begin(); it != intersection.nodePath.end(); ++it) + { + osg::Node* node = *it; + if (osg::ref_ptr tag = dynamic_cast(node->getUserData())) + { + if (!(tag->getElement() & mInteractionMask)) + break; // not interested -> continue looking + + return tag; + } + } + +// ignoring terrain for now + // must be terrain, report coordinates +// std::cout << "Terrain hit at " << intersection.getWorldIntersectPoint().x() << " " << intersection.getWorldIntersectPoint().y() << std::endl; +// return; + } + + return osg::ref_ptr(); +} + void CSVRender::WorldspaceWidget::dropEvent (QDropEvent* event) { const CSMWorld::TableMimeData* mime = dynamic_cast (event->mimeData()); @@ -436,54 +483,16 @@ void CSVRender::WorldspaceWidget::mousePressEvent (QMouseEvent *event) if (event->button() != Qt::RightButton) return; - // (0,0) is considered the lower left corner of an OpenGL window - int x = event->x(); - int y = height() - event->y(); - - osg::ref_ptr intersector (new osgUtil::LineSegmentIntersector(osgUtil::Intersector::WINDOW, x, y)); - - intersector->setIntersectionLimit(osgUtil::LineSegmentIntersector::NO_LIMIT); - osgUtil::IntersectionVisitor visitor(intersector); - - visitor.setTraversalMask(getInteractionMask() << 1); - - mView->getCamera()->accept(visitor); + osg::ref_ptr tag = mousePick (event); - for (osgUtil::LineSegmentIntersector::Intersections::iterator it = intersector->getIntersections().begin(); - it != intersector->getIntersections().end(); ++it) + if (tag) { - osgUtil::LineSegmentIntersector::Intersection intersection = *it; - - // reject back-facing polygons - osg::Vec3f normal = intersection.getWorldIntersectNormal(); - normal = osg::Matrix::transform3x3(normal, mView->getCamera()->getViewMatrix()); - if (normal.z() < 0) - continue; - - for (std::vector::iterator it = intersection.nodePath.begin(); it != intersection.nodePath.end(); ++it) + if (CSVRender::ObjectTag *objectTag = dynamic_cast (tag.get())) { - osg::Node* node = *it; - if (CSVRender::TagBase* tag = dynamic_cast(node->getUserData())) - { - if (!(tag->getElement() & mInteractionMask)) - break; // not interested -> continue looking - - // hit something marked with a tag - if (CSVRender::ObjectTag *objectTag = dynamic_cast (tag)) - { - // hit an Object, toggle its selection state - CSVRender::Object* object = objectTag->mObject; - object->setSelected (!object->getSelected()); - } - - return; - } + // hit an Object, toggle its selection state + CSVRender::Object* object = objectTag->mObject; + object->setSelected (!object->getSelected()); } - -// ignoring terrain for now - // must be terrain, report coordinates -// std::cout << "Terrain hit at " << intersection.getWorldIntersectPoint().x() << " " << intersection.getWorldIntersectPoint().y() << std::endl; -// return; } } diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp index 23f672fbd..90a85006f 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -25,6 +25,8 @@ namespace CSVWidget namespace CSVRender { + class TagBase; + class WorldspaceWidget : public SceneWidget { Q_OBJECT @@ -126,6 +128,8 @@ namespace CSVRender /// \return Is \a key a button mapping setting? (ignored otherwise) bool storeMappingSetting (const QString& key, const QString& value); + osg::ref_ptr mousePick (QMouseEvent *event); + virtual std::string getStartupInstruction() = 0; private slots: From 7bbc475bda71ea8d87ca63933c3d8c0c21dc2841 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 26 Sep 2015 18:01:49 +0200 Subject: [PATCH 2228/3725] apply button mapping --- apps/opencs/view/render/worldspacewidget.cpp | 37 +++++++++++++++----- apps/opencs/view/render/worldspacewidget.hpp | 2 ++ 2 files changed, 31 insertions(+), 8 deletions(-) diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 15978e0e1..5b5219184 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -394,6 +395,20 @@ osg::ref_ptr CSVRender::WorldspaceWidget::mousePick (QMouseE return osg::ref_ptr(); } +std::string CSVRender::WorldspaceWidget::mapButton (QMouseEvent *event) +{ + std::pair phyiscal ( + event->button(), QApplication::keyboardModifiers() & Qt::ControlModifier); + + std::map, std::string>::const_iterator iter = + mButtonMapping.find (phyiscal); + + if (iter!=mButtonMapping.end()) + return iter->second; + + return ""; +} + void CSVRender::WorldspaceWidget::dropEvent (QDropEvent* event) { const CSMWorld::TableMimeData* mime = dynamic_cast (event->mimeData()); @@ -480,18 +495,24 @@ void CSVRender::WorldspaceWidget::mouseMoveEvent (QMouseEvent *event) void CSVRender::WorldspaceWidget::mousePressEvent (QMouseEvent *event) { - if (event->button() != Qt::RightButton) - return; + std::string button = mapButton (event); - osg::ref_ptr tag = mousePick (event); + if (button=="p-navi" || button=="s-navi") + { - if (tag) + } + else if (button=="p-edit" || button=="s-edit" || button=="select") { - if (CSVRender::ObjectTag *objectTag = dynamic_cast (tag.get())) + osg::ref_ptr tag = mousePick (event); + + if (tag) { - // hit an Object, toggle its selection state - CSVRender::Object* object = objectTag->mObject; - object->setSelected (!object->getSelected()); + if (CSVRender::ObjectTag *objectTag = dynamic_cast (tag.get())) + { + // hit an Object, toggle its selection state + CSVRender::Object* object = objectTag->mObject; + object->setSelected (!object->getSelected()); + } } } } diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp index 90a85006f..ed5c5bcc8 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -130,6 +130,8 @@ namespace CSVRender osg::ref_ptr mousePick (QMouseEvent *event); + std::string mapButton (QMouseEvent *event); + virtual std::string getStartupInstruction() = 0; private slots: From 5d9863aec12429aa086d54012da7638a4eb663bc Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 27 Sep 2015 11:34:14 +0200 Subject: [PATCH 2229/3725] removed a redundant check --- apps/opencs/view/render/worldspacewidget.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 5b5219184..70def97b9 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -378,12 +378,7 @@ osg::ref_ptr CSVRender::WorldspaceWidget::mousePick (QMouseE { osg::Node* node = *it; if (osg::ref_ptr tag = dynamic_cast(node->getUserData())) - { - if (!(tag->getElement() & mInteractionMask)) - break; // not interested -> continue looking - return tag; - } } // ignoring terrain for now From 9bf27c7e371e4b1fdf01b356210a7bb9d02d58d5 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 27 Sep 2015 14:38:12 +0200 Subject: [PATCH 2230/3725] moved edit mode handling from SceneSubView to WorldspaceWidget --- apps/opencs/view/render/worldspacewidget.cpp | 23 ++++++++++++++++---- apps/opencs/view/render/worldspacewidget.hpp | 5 +++++ apps/opencs/view/world/scenesubview.cpp | 18 +++------------ apps/opencs/view/world/scenesubview.hpp | 4 ---- 4 files changed, 27 insertions(+), 23 deletions(-) diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 70def97b9..be4d32bb5 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -42,7 +42,7 @@ namespace CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidget* parent) : SceneWidget (document.getData().getResourceSystem(), parent), mSceneElements(0), mRun(0), mDocument(document), - mInteractionMask (0) + mInteractionMask (0), mEditMode (0), mLocked (false) { setAcceptDrops(true); @@ -199,11 +199,14 @@ CSVWidget::SceneToolRun *CSVRender::WorldspaceWidget::makeRunTool ( CSVWidget::SceneToolMode *CSVRender::WorldspaceWidget::makeEditModeSelector ( CSVWidget::SceneToolbar *parent) { - CSVWidget::SceneToolMode *tool = new CSVWidget::SceneToolMode (parent, "Edit Mode"); + mEditMode = new CSVWidget::SceneToolMode (parent, "Edit Mode"); - addEditModeSelectorButtons (tool); + addEditModeSelectorButtons (mEditMode); - return tool; + connect (mEditMode, SIGNAL (modeChanged (const std::string&)), + this, SLOT (editModeChanged (const std::string&))); + + return mEditMode; } CSVRender::WorldspaceWidget::DropType CSVRender::WorldspaceWidget::getDropType ( @@ -279,6 +282,13 @@ void CSVRender::WorldspaceWidget::updateUserSetting (const QString& name, const { if (!value.isEmpty() && storeMappingSetting (name, value.first())) return; + + dynamic_cast (*mEditMode->getCurrent()).updateUserSetting (name, value); +} + +void CSVRender::WorldspaceWidget::setEditLock (bool locked) +{ + dynamic_cast (*mEditMode->getCurrent()).setEditLock (locked); } void CSVRender::WorldspaceWidget::addVisibilitySelectorButtons ( @@ -468,6 +478,11 @@ void CSVRender::WorldspaceWidget::debugProfileAboutToBeRemoved (const QModelInde } } +void CSVRender::WorldspaceWidget::editModeChanged (const std::string& id) +{ + dynamic_cast (*mEditMode->getCurrent()).setEditLock (mLocked); +} + void CSVRender::WorldspaceWidget::elementSelectionChanged() { setVisibilityMask (getVisibilityMask()); diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp index ed5c5bcc8..272987a05 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -36,6 +36,8 @@ namespace CSVRender CSMDoc::Document& mDocument; unsigned int mInteractionMask; std::map, std::string> mButtonMapping; + CSVWidget::SceneToolMode *mEditMode; + bool mLocked; public: @@ -100,6 +102,8 @@ namespace CSVRender virtual void updateUserSetting (const QString& name, const QStringList& value); + virtual void setEditLock (bool locked); + protected: virtual void addVisibilitySelectorButtons (CSVWidget::SceneToolToggle2 *tool); @@ -158,6 +162,7 @@ namespace CSVRender void debugProfileAboutToBeRemoved (const QModelIndex& parent, int start, int end); + void editModeChanged (const std::string& id); protected slots: diff --git a/apps/opencs/view/world/scenesubview.cpp b/apps/opencs/view/world/scenesubview.cpp index 967909969..753d791c0 100644 --- a/apps/opencs/view/world/scenesubview.cpp +++ b/apps/opencs/view/world/scenesubview.cpp @@ -27,8 +27,7 @@ #include "creator.hpp" CSVWorld::SceneSubView::SceneSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) -: SubView (id), mScene(NULL), mLayout(new QHBoxLayout), mDocument(document), mToolbar(NULL), - mEditMode (0), mLocked (false) +: SubView (id), mScene(NULL), mLayout(new QHBoxLayout), mDocument(document), mToolbar(NULL) { QVBoxLayout *layout = new QVBoxLayout; @@ -123,16 +122,14 @@ CSVWidget::SceneToolbar* CSVWorld::SceneSubView::makeToolbar (CSVRender::Worldsp CSVWidget::SceneToolRun *runTool = widget->makeRunTool (toolbar); toolbar->addTool (runTool); - mEditMode = widget->makeEditModeSelector (toolbar); - toolbar->addTool (mEditMode); + toolbar->addTool (widget->makeEditModeSelector (toolbar)); return toolbar; } void CSVWorld::SceneSubView::setEditLock (bool locked) { - mLocked = locked; - dynamic_cast (*mEditMode->getCurrent()).setEditLock (locked); + mScene->setEditLock (locked); } void CSVWorld::SceneSubView::setStatusBar (bool show) @@ -153,7 +150,6 @@ std::string CSVWorld::SceneSubView::getTitle() const void CSVWorld::SceneSubView::updateUserSetting (const QString& name, const QStringList& value) { mScene->updateUserSetting (name, value); - dynamic_cast (*mEditMode->getCurrent()).updateUserSetting (name, value); CSVDoc::SubView::updateUserSetting (name, value); } @@ -259,12 +255,4 @@ void CSVWorld::SceneSubView::replaceToolbarAndWorldspace (CSVRender::WorldspaceW mScene->selectDefaultNavigationMode(); setFocusProxy (mScene); - - connect (mEditMode, SIGNAL (modeChanged (const std::string&)), - this, SLOT (editModeChanged (const std::string&))); -} - -void CSVWorld::SceneSubView::editModeChanged (const std::string& id) -{ - dynamic_cast (*mEditMode->getCurrent()).setEditLock (mLocked); } diff --git a/apps/opencs/view/world/scenesubview.hpp b/apps/opencs/view/world/scenesubview.hpp index f59fee37f..2458d58f4 100644 --- a/apps/opencs/view/world/scenesubview.hpp +++ b/apps/opencs/view/world/scenesubview.hpp @@ -46,8 +46,6 @@ namespace CSVWorld CSMDoc::Document& mDocument; CSVWidget::SceneToolbar* mToolbar; std::string mTitle; - CSVWidget::SceneToolMode *mEditMode; - bool mLocked; public: @@ -86,8 +84,6 @@ namespace CSVWorld void cellSelectionChanged (const CSMWorld::UniversalId& id); void handleDrop(const std::vector& data); - - void editModeChanged (const std::string& id); }; } From 981a8a2cc2754fe5f9c9abc5e1b42b86f091dc3d Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 27 Sep 2015 16:18:22 +0200 Subject: [PATCH 2231/3725] delegated editing and selection functions to mode objects --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/view/render/editmode.cpp | 6 ++++ apps/opencs/view/render/editmode.hpp | 12 +++++++ apps/opencs/view/render/instancemode.cpp | 35 ++++++++++++++++++++ apps/opencs/view/render/instancemode.hpp | 24 ++++++++++++++ apps/opencs/view/render/worldspacewidget.cpp | 22 ++++++------ 6 files changed, 88 insertions(+), 13 deletions(-) create mode 100644 apps/opencs/view/render/instancemode.cpp create mode 100644 apps/opencs/view/render/instancemode.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index cfa938473..2ed55218a 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -85,7 +85,7 @@ opencs_units (view/widget opencs_units (view/render scenewidget worldspacewidget pagedworldspacewidget unpagedworldspacewidget - previewwidget editmode + previewwidget editmode instancemode ) opencs_units_noqt (view/render diff --git a/apps/opencs/view/render/editmode.cpp b/apps/opencs/view/render/editmode.cpp index c3aad3f7a..2240318b6 100644 --- a/apps/opencs/view/render/editmode.cpp +++ b/apps/opencs/view/render/editmode.cpp @@ -26,3 +26,9 @@ void CSVRender::EditMode::setEditLock (bool locked) { } + +void CSVRender::EditMode::primaryEditPressed (osg::ref_ptr tag) {} + +void CSVRender::EditMode::secondaryEditPressed (osg::ref_ptr tag) {} + +void CSVRender::EditMode::selectPressed (osg::ref_ptr tag) {} diff --git a/apps/opencs/view/render/editmode.hpp b/apps/opencs/view/render/editmode.hpp index 1212cd285..c00669534 100644 --- a/apps/opencs/view/render/editmode.hpp +++ b/apps/opencs/view/render/editmode.hpp @@ -1,11 +1,14 @@ #ifndef CSV_RENDER_EDITMODE_H #define CSV_RENDER_EDITMODE_H +#include + #include "../widget/modebutton.hpp" namespace CSVRender { class WorldspaceWidget; + class TagBase; class EditMode : public CSVWidget::ModeButton { @@ -28,6 +31,15 @@ namespace CSVRender /// Default-implementation: Ignored. virtual void setEditLock (bool locked); + + /// Default-implementation: Ignored. + virtual void primaryEditPressed (osg::ref_ptr tag); + + /// Default-implementation: Ignored. + virtual void secondaryEditPressed (osg::ref_ptr tag); + + /// Default-implementation: Ignored. + virtual void selectPressed (osg::ref_ptr tag); }; } diff --git a/apps/opencs/view/render/instancemode.cpp b/apps/opencs/view/render/instancemode.cpp new file mode 100644 index 000000000..ccff8c7c5 --- /dev/null +++ b/apps/opencs/view/render/instancemode.cpp @@ -0,0 +1,35 @@ + +#include "instancemode.hpp" + +#include "elements.hpp" +#include "object.hpp" + +CSVRender::InstanceMode::InstanceMode (WorldspaceWidget *worldspaceWidget, QWidget *parent) +: EditMode (worldspaceWidget, QIcon (":placeholder"), Element_Reference, "Instance editing", + parent) +{ + +} + +void CSVRender::InstanceMode::primaryEditPressed (osg::ref_ptr tag) +{ + +} + +void CSVRender::InstanceMode::secondaryEditPressed (osg::ref_ptr tag) +{ + +} + +void CSVRender::InstanceMode::selectPressed (osg::ref_ptr tag) +{ + if (tag) + { + if (CSVRender::ObjectTag *objectTag = dynamic_cast (tag.get())) + { + // hit an Object, toggle its selection state + CSVRender::Object* object = objectTag->mObject; + object->setSelected (!object->getSelected()); + } + } +} diff --git a/apps/opencs/view/render/instancemode.hpp b/apps/opencs/view/render/instancemode.hpp new file mode 100644 index 000000000..6071aedf0 --- /dev/null +++ b/apps/opencs/view/render/instancemode.hpp @@ -0,0 +1,24 @@ +#ifndef CSV_RENDER_INSTANCEMODE_H +#define CSV_RENDER_INSTANCEMODE_H + +#include "editmode.hpp" + +namespace CSVRender +{ + class InstanceMode : public EditMode + { + Q_OBJECT + + public: + + InstanceMode (WorldspaceWidget *worldspaceWidget, QWidget *parent = 0); + + virtual void primaryEditPressed (osg::ref_ptr tag); + + virtual void secondaryEditPressed (osg::ref_ptr tag); + + virtual void selectPressed (osg::ref_ptr tag); + }; +} + +#endif diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index be4d32bb5..1c1dc4d6b 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -28,6 +28,7 @@ #include "object.hpp" #include "elements.hpp" #include "editmode.hpp" +#include "instancemode.hpp" namespace { @@ -302,9 +303,7 @@ void CSVRender::WorldspaceWidget::addVisibilitySelectorButtons ( void CSVRender::WorldspaceWidget::addEditModeSelectorButtons (CSVWidget::SceneToolMode *tool) { /// \todo replace EditMode with suitable subclasses - tool->addButton ( - new EditMode (this, QIcon (":placeholder"), Element_Reference, "Instance editing"), - "object"); + tool->addButton (new InstanceMode (this, tool), "object"); tool->addButton ( new EditMode (this, QIcon (":placeholder"), Element_Pathgrid, "Pathgrid editing"), "pathgrid"); @@ -515,15 +514,14 @@ void CSVRender::WorldspaceWidget::mousePressEvent (QMouseEvent *event) { osg::ref_ptr tag = mousePick (event); - if (tag) - { - if (CSVRender::ObjectTag *objectTag = dynamic_cast (tag.get())) - { - // hit an Object, toggle its selection state - CSVRender::Object* object = objectTag->mObject; - object->setSelected (!object->getSelected()); - } - } + EditMode& editMode = dynamic_cast (*mEditMode->getCurrent()); + + if (button=="p-edit") + editMode.primaryEditPressed (tag); + else if (button=="s-edit") + editMode.secondaryEditPressed (tag); + else if (button=="select") + editMode.selectPressed (tag); } } From 319e3f24a3d23e158adbc3e46f0f80dc55e5206f Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 29 Sep 2015 13:48:04 +0200 Subject: [PATCH 2232/3725] on edit mode change clear selection of elements that are not affected by current edit mode (only support for instance for now since we do not have selection for other elements yet) --- apps/opencs/view/render/cell.cpp | 21 +++++++++++++++++++ apps/opencs/view/render/cell.hpp | 11 ++++++++++ apps/opencs/view/render/editmode.cpp | 1 + .../view/render/pagedworldspacewidget.cpp | 7 +++++++ .../view/render/pagedworldspacewidget.hpp | 3 +++ .../view/render/unpagedworldspacewidget.cpp | 5 +++++ .../view/render/unpagedworldspacewidget.hpp | 3 +++ apps/opencs/view/render/worldspacewidget.hpp | 10 ++++++--- 8 files changed, 58 insertions(+), 3 deletions(-) diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index 28a48cfbd..c4f744510 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -211,3 +211,24 @@ bool CSVRender::Cell::referenceAdded (const QModelIndex& parent, int start, int return addObjects (start, end); } + +void CSVRender::Cell::setSelection (int elementMask, Selection mode) +{ + if (elementMask & Element_Reference) + { + for (std::map::const_iterator iter (mObjects.begin()); + iter!=mObjects.end(); ++iter) + { + bool selected = false; + + switch (mode) + { + case Selection_Clear: selected = false; break; + case Selection_All: selected = true; break; + case Selection_Invert: selected = !iter->second->getSelected(); break; + } + + iter->second->setSelected (selected); + } + } +} diff --git a/apps/opencs/view/render/cell.hpp b/apps/opencs/view/render/cell.hpp index f4272b887..d26a2d9af 100644 --- a/apps/opencs/view/render/cell.hpp +++ b/apps/opencs/view/render/cell.hpp @@ -49,6 +49,15 @@ namespace CSVRender /// \return Have any objects been added? bool addObjects (int start, int end); + public: + + enum Selection + { + Selection_Clear, + Selection_All, + Selection_Invert + }; + public: Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::string& id); @@ -75,6 +84,8 @@ namespace CSVRender /// \return Did this call result in a modification of the visual representation of /// this cell? bool referenceAdded (const QModelIndex& parent, int start, int end); + + void setSelection (int elementMask, Selection mode); }; } diff --git a/apps/opencs/view/render/editmode.cpp b/apps/opencs/view/render/editmode.cpp index 2240318b6..e1f69a63d 100644 --- a/apps/opencs/view/render/editmode.cpp +++ b/apps/opencs/view/render/editmode.cpp @@ -15,6 +15,7 @@ unsigned int CSVRender::EditMode::getInteractionMask() const void CSVRender::EditMode::activate (CSVWidget::SceneToolbar *toolbar) { mWorldspaceWidget->setInteractionMask (mMask); + mWorldspaceWidget->clearSelection (~mMask); } void CSVRender::EditMode::updateUserSetting (const QString& name, const QStringList& value) diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index b0c1e74a9..543f3788a 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -314,6 +314,13 @@ unsigned int CSVRender::PagedWorldspaceWidget::getVisibilityMask() const return WorldspaceWidget::getVisibilityMask() | mControlElements->getSelection(); } +void CSVRender::PagedWorldspaceWidget::clearSelection (int elementMask) +{ + for (std::map::iterator iter = mCells.begin(); + iter!=mCells.end(); ++iter) + iter->second->setSelection (elementMask, Cell::Selection_Clear); +} + CSVWidget::SceneToolToggle *CSVRender::PagedWorldspaceWidget::makeControlVisibilitySelector ( CSVWidget::SceneToolbar *parent) { diff --git a/apps/opencs/view/render/pagedworldspacewidget.hpp b/apps/opencs/view/render/pagedworldspacewidget.hpp index 64a0bccd1..d52efd90e 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.hpp +++ b/apps/opencs/view/render/pagedworldspacewidget.hpp @@ -79,6 +79,9 @@ namespace CSVRender virtual unsigned int getVisibilityMask() const; + /// \param elementMask Elements to be affected by the clear operation + virtual void clearSelection (int elementMask); + protected: virtual void addVisibilitySelectorButtons (CSVWidget::SceneToolToggle2 *tool); diff --git a/apps/opencs/view/render/unpagedworldspacewidget.cpp b/apps/opencs/view/render/unpagedworldspacewidget.cpp index 3e1733c81..989c976ff 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.cpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.cpp @@ -102,6 +102,11 @@ bool CSVRender::UnpagedWorldspaceWidget::handleDrop (const std::vectorsetSelection (elementMask, Cell::Selection_Clear); +} + void CSVRender::UnpagedWorldspaceWidget::referenceableDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) { diff --git a/apps/opencs/view/render/unpagedworldspacewidget.hpp b/apps/opencs/view/render/unpagedworldspacewidget.hpp index d01c3e766..9e6fa97f4 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.hpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.hpp @@ -43,6 +43,9 @@ namespace CSVRender virtual bool handleDrop (const std::vector& data, DropType type); + /// \param elementMask Elements to be affected by the clear operation + virtual void clearSelection (int elementMask); + private: virtual void referenceableDataChanged (const QModelIndex& topLeft, diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp index 272987a05..ffdcf3bc3 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -5,10 +5,11 @@ #include -#include "scenewidget.hpp" +#include "../../model/doc/document.hpp" +#include "../../model/world/tablemimedata.hpp" -#include -#include +#include "scenewidget.hpp" +#include "elements.hpp" namespace CSMWorld { @@ -104,6 +105,9 @@ namespace CSVRender virtual void setEditLock (bool locked); + /// \param elementMask Elements to be affected by the clear operation + virtual void clearSelection (int elementMask) = 0; + protected: virtual void addVisibilitySelectorButtons (CSVWidget::SceneToolToggle2 *tool); From f28fa9fc16ec1477b1de18bf078a5d16af2b34aa Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 29 Sep 2015 13:53:47 +0200 Subject: [PATCH 2233/3725] clear instance selection on select click on nothing/something that isn't an instance --- apps/opencs/view/render/editmode.cpp | 5 +++++ apps/opencs/view/render/editmode.hpp | 4 ++++ apps/opencs/view/render/instancemode.cpp | 4 ++++ 3 files changed, 13 insertions(+) diff --git a/apps/opencs/view/render/editmode.cpp b/apps/opencs/view/render/editmode.cpp index e1f69a63d..816067107 100644 --- a/apps/opencs/view/render/editmode.cpp +++ b/apps/opencs/view/render/editmode.cpp @@ -2,6 +2,11 @@ #include "worldspacewidget.hpp" +CSVRender::WorldspaceWidget& CSVRender::EditMode::getWorldspaceWidget() +{ + return *mWorldspaceWidget; +} + CSVRender::EditMode::EditMode (WorldspaceWidget *worldspaceWidget, const QIcon& icon, unsigned int mask, const QString& tooltip, QWidget *parent) : ModeButton (icon, tooltip, parent), mWorldspaceWidget (worldspaceWidget), mMask (mask) diff --git a/apps/opencs/view/render/editmode.hpp b/apps/opencs/view/render/editmode.hpp index c00669534..fa2beedd8 100644 --- a/apps/opencs/view/render/editmode.hpp +++ b/apps/opencs/view/render/editmode.hpp @@ -17,6 +17,10 @@ namespace CSVRender WorldspaceWidget *mWorldspaceWidget; unsigned int mMask; + protected: + + WorldspaceWidget& getWorldspaceWidget(); + public: EditMode (WorldspaceWidget *worldspaceWidget, const QIcon& icon, unsigned int mask, diff --git a/apps/opencs/view/render/instancemode.cpp b/apps/opencs/view/render/instancemode.cpp index ccff8c7c5..2e8f8cda2 100644 --- a/apps/opencs/view/render/instancemode.cpp +++ b/apps/opencs/view/render/instancemode.cpp @@ -3,6 +3,7 @@ #include "elements.hpp" #include "object.hpp" +#include "worldspacewidget.hpp" CSVRender::InstanceMode::InstanceMode (WorldspaceWidget *worldspaceWidget, QWidget *parent) : EditMode (worldspaceWidget, QIcon (":placeholder"), Element_Reference, "Instance editing", @@ -30,6 +31,9 @@ void CSVRender::InstanceMode::selectPressed (osg::ref_ptr tag) // hit an Object, toggle its selection state CSVRender::Object* object = objectTag->mObject; object->setSelected (!object->getSelected()); + return; } } + + getWorldspaceWidget().clearSelection (Element_Reference); } From 2cb106f6adfe5f8f7f94079077de0d43f41f8a44 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 29 Sep 2015 16:06:55 +0200 Subject: [PATCH 2234/3725] added missing flagAsModified calls --- apps/opencs/view/render/pagedworldspacewidget.cpp | 2 ++ apps/opencs/view/render/unpagedworldspacewidget.cpp | 1 + 2 files changed, 3 insertions(+) diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index 543f3788a..7403113b3 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -319,6 +319,8 @@ void CSVRender::PagedWorldspaceWidget::clearSelection (int elementMask) for (std::map::iterator iter = mCells.begin(); iter!=mCells.end(); ++iter) iter->second->setSelection (elementMask, Cell::Selection_Clear); + + flagAsModified(); } CSVWidget::SceneToolToggle *CSVRender::PagedWorldspaceWidget::makeControlVisibilitySelector ( diff --git a/apps/opencs/view/render/unpagedworldspacewidget.cpp b/apps/opencs/view/render/unpagedworldspacewidget.cpp index 989c976ff..68f068dac 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.cpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.cpp @@ -105,6 +105,7 @@ bool CSVRender::UnpagedWorldspaceWidget::handleDrop (const std::vectorsetSelection (elementMask, Cell::Selection_Clear); + flagAsModified(); } void CSVRender::UnpagedWorldspaceWidget::referenceableDataChanged (const QModelIndex& topLeft, From 8e87b48866e66c1546c7d7f7914f9ab4f7fd015e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 29 Sep 2015 16:07:14 +0200 Subject: [PATCH 2235/3725] handle context-sensitive select mode in instance editing --- apps/opencs/view/render/instancemode.cpp | 23 ++++++++++++++++++++--- apps/opencs/view/render/instancemode.hpp | 6 ++++++ 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/apps/opencs/view/render/instancemode.cpp b/apps/opencs/view/render/instancemode.cpp index 2e8f8cda2..333d91656 100644 --- a/apps/opencs/view/render/instancemode.cpp +++ b/apps/opencs/view/render/instancemode.cpp @@ -1,25 +1,42 @@ #include "instancemode.hpp" +#include "../../model/settings/usersettings.hpp" + #include "elements.hpp" #include "object.hpp" #include "worldspacewidget.hpp" CSVRender::InstanceMode::InstanceMode (WorldspaceWidget *worldspaceWidget, QWidget *parent) : EditMode (worldspaceWidget, QIcon (":placeholder"), Element_Reference, "Instance editing", - parent) + parent), mContextSelect (false) { } -void CSVRender::InstanceMode::primaryEditPressed (osg::ref_ptr tag) +void CSVRender::InstanceMode::activate (CSVWidget::SceneToolbar *toolbar) { + EditMode::activate (toolbar); + mContextSelect = CSMSettings::UserSettings::instance().setting ("scene-input/context-select")=="true"; } -void CSVRender::InstanceMode::secondaryEditPressed (osg::ref_ptr tag) +void CSVRender::InstanceMode::updateUserSetting (const QString& name, const QStringList& value) +{ + if (name=="scene-input/context-select") + mContextSelect = value.at (0)=="true"; +} + +void CSVRender::InstanceMode::primaryEditPressed (osg::ref_ptr tag) { + if (mContextSelect) + selectPressed (tag); +} +void CSVRender::InstanceMode::secondaryEditPressed (osg::ref_ptr tag) +{ + if (mContextSelect) + selectPressed (tag); } void CSVRender::InstanceMode::selectPressed (osg::ref_ptr tag) diff --git a/apps/opencs/view/render/instancemode.hpp b/apps/opencs/view/render/instancemode.hpp index 6071aedf0..cc4fd5434 100644 --- a/apps/opencs/view/render/instancemode.hpp +++ b/apps/opencs/view/render/instancemode.hpp @@ -9,10 +9,16 @@ namespace CSVRender { Q_OBJECT + bool mContextSelect; + public: InstanceMode (WorldspaceWidget *worldspaceWidget, QWidget *parent = 0); + virtual void activate (CSVWidget::SceneToolbar *toolbar); + + virtual void updateUserSetting (const QString& name, const QStringList& value); + virtual void primaryEditPressed (osg::ref_ptr tag); virtual void secondaryEditPressed (osg::ref_ptr tag); From 3f27c856300671083123d3027cf7b6299bc01438 Mon Sep 17 00:00:00 2001 From: "artemutin@yandex.ru" Date: Tue, 29 Sep 2015 10:46:03 +1000 Subject: [PATCH 2236/3725] Added StartScriptCreator class with redefined getErrors method. --- apps/opencs/view/world/startscriptcreator.cpp | 26 +++++++++++++++++++ apps/opencs/view/world/startscriptcreator.hpp | 25 ++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 apps/opencs/view/world/startscriptcreator.cpp create mode 100644 apps/opencs/view/world/startscriptcreator.hpp diff --git a/apps/opencs/view/world/startscriptcreator.cpp b/apps/opencs/view/world/startscriptcreator.cpp new file mode 100644 index 000000000..5812cd931 --- /dev/null +++ b/apps/opencs/view/world/startscriptcreator.cpp @@ -0,0 +1,26 @@ +#include "startscriptcreator.hpp" + +StartScriptCreator::StartScriptCreator() +{ + +} + + +CSVWORLD::StartScriptCreator::StartScriptCreator(CSMWorld::Data &data, QUndoStack &undoStack, const CSMWorld::UniversalId &id, bool relaxedIdRules): + GenericCreator (data, undoStack, id, true) +{} + +std::string CSVWORLD::StartScriptCreator::getErrors() const +{ + std::string errors; + + errors = getIdValidatorResult(); + if (errors.length() > 0) + return errors; + else if (getData().getScripts().searchId(getId()) == -1) + errors = "Script ID not found"; + else if (getData().getStartScripts().searchId(getId()) > -1 ) + errors = "Script with this ID already registered as Start Script"; + + return errors; +} diff --git a/apps/opencs/view/world/startscriptcreator.hpp b/apps/opencs/view/world/startscriptcreator.hpp new file mode 100644 index 000000000..4c91ad96a --- /dev/null +++ b/apps/opencs/view/world/startscriptcreator.hpp @@ -0,0 +1,25 @@ +#ifndef STARTSCRIPTCREATOR_HPP +#define STARTSCRIPTCREATOR_HPP + +#include "genericcreator.hpp" + +namespace CSVWORLD { + + class StartScriptCreator : public GenericCreator + { + Q_OBJECT + + public: + StartScriptCreator(CSMWorld::Data& data, QUndoStack& undoStack, + const CSMWorld::UniversalId& id, bool relaxedIdRules = false); + + virtual std::string getErrors() const; + ///< Return formatted error descriptions for the current state of the creator. if an empty + /// string is returned, there is no error. + }; + +} + + + +#endif // STARTSCRIPTCREATOR_HPP From e672880f644066716452d363b61eff1c56010b0f Mon Sep 17 00:00:00 2001 From: "artemutin@yandex.ru" Date: Tue, 29 Sep 2015 22:43:20 +1000 Subject: [PATCH 2237/3725] Fix namespace, add file to CMakeLists.txt --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/view/world/startscriptcreator.cpp | 10 ++-------- apps/opencs/view/world/startscriptcreator.hpp | 4 ++-- 3 files changed, 5 insertions(+), 11 deletions(-) diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index f9a73a09f..c428cd27a 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -67,7 +67,7 @@ opencs_hdrs_noqt (view/doc opencs_units (view/world table tablesubview scriptsubview util regionmapsubview tablebottombox creator genericcreator - cellcreator referenceablecreator referencecreator scenesubview + cellcreator referenceablecreator startscriptcreator referencecreator scenesubview infocreator scriptedit dialoguesubview previewsubview regionmap dragrecordtable nestedtable dialoguespinbox recordbuttonbar tableeditidaction scripterrortable extendedcommandconfigurator ) diff --git a/apps/opencs/view/world/startscriptcreator.cpp b/apps/opencs/view/world/startscriptcreator.cpp index 5812cd931..69b1b3ff1 100644 --- a/apps/opencs/view/world/startscriptcreator.cpp +++ b/apps/opencs/view/world/startscriptcreator.cpp @@ -1,16 +1,10 @@ #include "startscriptcreator.hpp" -StartScriptCreator::StartScriptCreator() -{ - -} - - -CSVWORLD::StartScriptCreator::StartScriptCreator(CSMWorld::Data &data, QUndoStack &undoStack, const CSMWorld::UniversalId &id, bool relaxedIdRules): +CSVWorld::StartScriptCreator::StartScriptCreator(CSMWorld::Data &data, QUndoStack &undoStack, const CSMWorld::UniversalId &id, bool relaxedIdRules): GenericCreator (data, undoStack, id, true) {} -std::string CSVWORLD::StartScriptCreator::getErrors() const +std::string CSVWorld::StartScriptCreator::getErrors() const { std::string errors; diff --git a/apps/opencs/view/world/startscriptcreator.hpp b/apps/opencs/view/world/startscriptcreator.hpp index 4c91ad96a..07fe8ff3d 100644 --- a/apps/opencs/view/world/startscriptcreator.hpp +++ b/apps/opencs/view/world/startscriptcreator.hpp @@ -3,7 +3,7 @@ #include "genericcreator.hpp" -namespace CSVWORLD { +namespace CSVWorld { class StartScriptCreator : public GenericCreator { @@ -16,7 +16,7 @@ namespace CSVWORLD { virtual std::string getErrors() const; ///< Return formatted error descriptions for the current state of the creator. if an empty /// string is returned, there is no error. - }; + }; } From 903cd3322b2a24e4d0a757ede8e429583f34f2b4 Mon Sep 17 00:00:00 2001 From: "artemutin@yandex.ru" Date: Tue, 29 Sep 2015 22:44:25 +1000 Subject: [PATCH 2238/3725] add getIdValidatorResult method to GenericCreator, for use in subclass StartScriptCreator --- apps/opencs/view/world/genericcreator.cpp | 10 ++++++++++ apps/opencs/view/world/genericcreator.hpp | 2 ++ 2 files changed, 12 insertions(+) diff --git a/apps/opencs/view/world/genericcreator.cpp b/apps/opencs/view/world/genericcreator.cpp index 8ed52bf80..df7739941 100644 --- a/apps/opencs/view/world/genericcreator.cpp +++ b/apps/opencs/view/world/genericcreator.cpp @@ -47,6 +47,16 @@ std::string CSVWorld::GenericCreator::getId() const return mId->text().toUtf8().constData(); } +std::string CSVWorld::GenericCreator::getIdValidatorResult() const +{ + std::string errors; + + if (!mId->hasAcceptableInput()) + errors = mValidator->getError(); + + return errors; +} + void CSVWorld::GenericCreator::configureCreateCommand (CSMWorld::CreateCommand& command) const {} void CSVWorld::GenericCreator::pushCommand (std::auto_ptr command, diff --git a/apps/opencs/view/world/genericcreator.hpp b/apps/opencs/view/world/genericcreator.hpp index 471d0622e..f63c45109 100644 --- a/apps/opencs/view/world/genericcreator.hpp +++ b/apps/opencs/view/world/genericcreator.hpp @@ -60,6 +60,8 @@ namespace CSVWorld virtual std::string getId() const; + virtual std::string getIdValidatorResult() const; + /// Allow subclasses to add additional data to \a command. virtual void configureCreateCommand (CSMWorld::CreateCommand& command) const; From ecce3a197550cd8b689e7d2bf697461325a7c6b9 Mon Sep 17 00:00:00 2001 From: "artemutin@yandex.ru" Date: Tue, 29 Sep 2015 23:52:35 +1000 Subject: [PATCH 2239/3725] Add StartScriptCreator to a factory manager. --- apps/opencs/view/world/subviews.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp index 299ac6ebe..88375caaf 100644 --- a/apps/opencs/view/world/subviews.cpp +++ b/apps/opencs/view/world/subviews.cpp @@ -10,6 +10,7 @@ #include "cellcreator.hpp" #include "referenceablecreator.hpp" #include "referencecreator.hpp" +#include "startscriptcreator.hpp" #include "scenesubview.hpp" #include "dialoguecreator.hpp" #include "infocreator.hpp" @@ -42,7 +43,6 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) CSMWorld::UniversalId::Type_BodyParts, CSMWorld::UniversalId::Type_SoundGens, CSMWorld::UniversalId::Type_Pathgrids, - CSMWorld::UniversalId::Type_StartScripts, CSMWorld::UniversalId::Type_None // end marker }; @@ -51,6 +51,9 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) manager.add (sTableTypes[i], new CSVDoc::SubViewFactoryWithCreator >); + manager.add (CSMWorld::UniversalId::Type_StartScripts, + new CSVDoc::SubViewFactoryWithCreator >); + manager.add (CSMWorld::UniversalId::Type_Cells, new CSVDoc::SubViewFactoryWithCreator >); @@ -123,7 +126,6 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) CSMWorld::UniversalId::Type_BodyPart, CSMWorld::UniversalId::Type_SoundGen, CSMWorld::UniversalId::Type_Pathgrid, - CSMWorld::UniversalId::Type_StartScript, CSMWorld::UniversalId::Type_None // end marker }; @@ -133,6 +135,10 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) new CSVDoc::SubViewFactoryWithCreator > (false)); + manager.add (CSMWorld::UniversalId::Type_StartScript, + new CSVDoc::SubViewFactoryWithCreator > (false)); + manager.add (CSMWorld::UniversalId::Type_Skill, new CSVDoc::SubViewFactoryWithCreator (false)); From 64902bf22112d0b44464f7657b12db86627cdd38 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 30 Sep 2015 09:44:05 +0200 Subject: [PATCH 2240/3725] updated credits file --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index 8e9d35cf2..e968d1d01 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -19,6 +19,7 @@ Programmers Alexander Nadeau (wareya) Alexander Olofsson (Ace) Artem Kotsynyak (greye) + artemutin Arthur Moore (EmperorArthur) athile Bret Curtis (psi29a) From 0a5bfb2107ddf46465ce74902470dc7056eb279b Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 1 Oct 2015 12:46:01 +0200 Subject: [PATCH 2241/3725] added framework for drag operations --- apps/opencs/view/render/editmode.cpp | 21 ++++++ apps/opencs/view/render/editmode.hpp | 27 +++++++ apps/opencs/view/render/worldspacewidget.cpp | 75 +++++++++++++++++--- apps/opencs/view/render/worldspacewidget.hpp | 4 ++ 4 files changed, 116 insertions(+), 11 deletions(-) diff --git a/apps/opencs/view/render/editmode.cpp b/apps/opencs/view/render/editmode.cpp index 816067107..e1ab619cd 100644 --- a/apps/opencs/view/render/editmode.cpp +++ b/apps/opencs/view/render/editmode.cpp @@ -38,3 +38,24 @@ void CSVRender::EditMode::primaryEditPressed (osg::ref_ptr tag) {} void CSVRender::EditMode::secondaryEditPressed (osg::ref_ptr tag) {} void CSVRender::EditMode::selectPressed (osg::ref_ptr tag) {} + +bool CSVRender::EditMode::primaryEditStartDrag (osg::ref_ptr tag) +{ + return false; +} + +bool CSVRender::EditMode::secondaryEditStartDrag (osg::ref_ptr tag) +{ + return false; +} + +bool CSVRender::EditMode::selectStartDrag (osg::ref_ptr tag) +{ + return false; +} + +void CSVRender::EditMode::drag (int diffX, int diffY) {} + +void CSVRender::EditMode::dragCompleted() {} + +void CSVRender::EditMode::dragAborted() {} diff --git a/apps/opencs/view/render/editmode.hpp b/apps/opencs/view/render/editmode.hpp index fa2beedd8..361ffc5ed 100644 --- a/apps/opencs/view/render/editmode.hpp +++ b/apps/opencs/view/render/editmode.hpp @@ -44,6 +44,33 @@ namespace CSVRender /// Default-implementation: Ignored. virtual void selectPressed (osg::ref_ptr tag); + + /// Default-implementation: ignore and return false + /// + /// \return Drag accepted? + virtual bool primaryEditStartDrag (osg::ref_ptr tag); + + /// Default-implementation: ignore and return false + /// + /// \return Drag accepted? + virtual bool secondaryEditStartDrag (osg::ref_ptr tag); + + /// Default-implementation: ignore and return false + /// + /// \return Drag accepted? + virtual bool selectStartDrag (osg::ref_ptr tag); + + /// Default-implementation: ignored + virtual void drag (int diffX, int diffY); + + /// Default-implementation: ignored + virtual void dragCompleted(); + + /// Default-implementation: ignored + /// + /// \note dragAborted will not be called, if the drag is aborted via changing + /// editing mode + virtual void dragAborted(); }; } diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 1c1dc4d6b..25ee56a05 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -43,7 +43,7 @@ namespace CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidget* parent) : SceneWidget (document.getData().getResourceSystem(), parent), mSceneElements(0), mRun(0), mDocument(document), - mInteractionMask (0), mEditMode (0), mLocked (false) + mInteractionMask (0), mEditMode (0), mLocked (false), mDragging (false) { setAcceptDrops(true); @@ -480,6 +480,7 @@ void CSVRender::WorldspaceWidget::debugProfileAboutToBeRemoved (const QModelInde void CSVRender::WorldspaceWidget::editModeChanged (const std::string& id) { dynamic_cast (*mEditMode->getCurrent()).setEditLock (mLocked); + mDragging = false; } void CSVRender::WorldspaceWidget::elementSelectionChanged() @@ -495,10 +496,45 @@ void CSVRender::WorldspaceWidget::updateOverlay() void CSVRender::WorldspaceWidget::mouseMoveEvent (QMouseEvent *event) { - if(event->buttons() & Qt::RightButton) + if (!mDragging) { - //mMouse->mouseMoveEvent(event); + if (mDragMode=="p-navi" || mDragMode=="s-navi") + { + + } + else if (mDragMode=="p-edit" || mDragMode=="s-edit" || mDragMode=="select") + { + osg::ref_ptr tag = mousePick (event); + + EditMode& editMode = dynamic_cast (*mEditMode->getCurrent()); + + if (mDragMode=="p-edit") + mDragging = editMode.primaryEditStartDrag (tag); + else if (mDragMode=="s-edit") + mDragging = editMode.secondaryEditStartDrag (tag); + else if (mDragMode=="select") + mDragging = editMode.selectStartDrag (tag); + + if (mDragging) + { + mDragX = event->posF().x(); + mDragY = height() - event->posF().y(); + } + } + } + else + { + int diffX = event->x() - mDragX; + int diffY = (height() - event->y()) - mDragY; + + mDragX = event->x(); + mDragY = height() - event->y(); + + EditMode& editMode = dynamic_cast (*mEditMode->getCurrent()); + + editMode.drag (diffX, diffY); } + RenderWidget::mouseMoveEvent(event); } @@ -506,6 +542,9 @@ void CSVRender::WorldspaceWidget::mousePressEvent (QMouseEvent *event) { std::string button = mapButton (event); + if (!mDragging) + mDragMode = button; + if (button=="p-navi" || button=="s-navi") { @@ -527,17 +566,25 @@ void CSVRender::WorldspaceWidget::mousePressEvent (QMouseEvent *event) void CSVRender::WorldspaceWidget::mouseReleaseEvent (QMouseEvent *event) { - if(event->button() == Qt::RightButton) + if (mDragging) { - /* - if(!getViewport()) + std::string button = mapButton (event); + + if (mDragMode=="p-navi" || mDragMode=="s-navi") { - SceneWidget::mouseReleaseEvent(event); - return; + + } + else if (mDragMode=="p-edit" || mDragMode=="s-edit" || mDragMode=="select") + { + EditMode& editMode = dynamic_cast (*mEditMode->getCurrent()); + + editMode.dragCompleted(); + mDragging = false; } - */ - //mMouse->mouseReleaseEvent(event); } + + mDragMode.clear(); + RenderWidget::mouseReleaseEvent(event); } @@ -560,7 +607,13 @@ void CSVRender::WorldspaceWidget::keyPressEvent (QKeyEvent *event) { if(event->key() == Qt::Key_Escape) { - //mMouse->cancelDrag(); + if (mDragging) + { + EditMode& editMode = dynamic_cast (*mEditMode->getCurrent()); + + editMode.dragAborted(); + mDragging = false; + } } else RenderWidget::keyPressEvent(event); diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp index ffdcf3bc3..f51ce047e 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -39,6 +39,10 @@ namespace CSVRender std::map, std::string> mButtonMapping; CSVWidget::SceneToolMode *mEditMode; bool mLocked; + std::string mDragMode; + bool mDragging; + int mDragX; + int mDragY; public: From 1d4f8b2595b6f7d49d2dbc95590f5bdd2486dd68 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 1 Oct 2015 13:19:48 +0200 Subject: [PATCH 2242/3725] send mouse wheel input to active EditMode during drag operations --- apps/opencs/view/render/editmode.cpp | 2 ++ apps/opencs/view/render/editmode.hpp | 3 +++ apps/opencs/view/render/scenewidget.cpp | 2 ++ apps/opencs/view/render/worldspacewidget.cpp | 10 ++++++++-- 4 files changed, 15 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/render/editmode.cpp b/apps/opencs/view/render/editmode.cpp index e1ab619cd..cc76e3362 100644 --- a/apps/opencs/view/render/editmode.cpp +++ b/apps/opencs/view/render/editmode.cpp @@ -59,3 +59,5 @@ void CSVRender::EditMode::drag (int diffX, int diffY) {} void CSVRender::EditMode::dragCompleted() {} void CSVRender::EditMode::dragAborted() {} + +void CSVRender::EditMode::dragWheel (int diff) {} diff --git a/apps/opencs/view/render/editmode.hpp b/apps/opencs/view/render/editmode.hpp index 361ffc5ed..0a4bdf9b8 100644 --- a/apps/opencs/view/render/editmode.hpp +++ b/apps/opencs/view/render/editmode.hpp @@ -71,6 +71,9 @@ namespace CSVRender /// \note dragAborted will not be called, if the drag is aborted via changing /// editing mode virtual void dragAborted(); + + /// Default-implementation: ignored + virtual void dragWheel (int diff); }; } diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index fb3bcb3c3..76b3db348 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -110,6 +110,8 @@ bool RenderWidget::eventFilter(QObject* obj, QEvent* event) keyPressEvent(static_cast(event)); if (event->type() == QEvent::KeyRelease) keyReleaseEvent(static_cast(event)); + if (event->type() == QEvent::Wheel) + wheelEvent(static_cast(event)); // Always pass the event on to GLWidget, i.e. to OSG event queue return QObject::eventFilter(obj, event); diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 25ee56a05..3971f76fa 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -599,8 +599,14 @@ void CSVRender::WorldspaceWidget::mouseDoubleClickEvent (QMouseEvent *event) void CSVRender::WorldspaceWidget::wheelEvent (QWheelEvent *event) { - //if(!mMouse->wheelEvent(event)) - RenderWidget::wheelEvent(event); + if (mDragging) + { + EditMode& editMode = dynamic_cast (*mEditMode->getCurrent()); + + editMode.dragWheel (event->delta()); + } + + RenderWidget::wheelEvent(event); } void CSVRender::WorldspaceWidget::keyPressEvent (QKeyEvent *event) From 323f8bb29f04b7b48f0cbe4e5a04ac6a3f880e6e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 1 Oct 2015 13:42:21 +0200 Subject: [PATCH 2243/3725] sensitivity settings --- apps/opencs/model/settings/usersettings.cpp | 15 +++++++++++ apps/opencs/view/render/editmode.cpp | 4 +-- apps/opencs/view/render/editmode.hpp | 4 +-- apps/opencs/view/render/worldspacewidget.cpp | 27 +++++++++++++++++--- apps/opencs/view/render/worldspacewidget.hpp | 3 +++ 5 files changed, 46 insertions(+), 7 deletions(-) diff --git a/apps/opencs/model/settings/usersettings.cpp b/apps/opencs/model/settings/usersettings.cpp index 5cc60c318..3e5ab24d1 100644 --- a/apps/opencs/model/settings/usersettings.cpp +++ b/apps/opencs/model/settings/usersettings.cpp @@ -405,6 +405,21 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() Setting *contextSensitive = createSetting (Type_CheckBox, "context-select", "Context Sensitive Selection"); contextSensitive->setDefaultValue ("false"); + + Setting *dragMouseSensitivity = createSetting (Type_DoubleSpinBox, "drag-factor", + "Mouse sensitivity during drag operations"); + dragMouseSensitivity->setDefaultValue (1.0); + dragMouseSensitivity->setRange (0.001, 100.0); + + Setting *dragWheelSensitivity = createSetting (Type_DoubleSpinBox, "drag-wheel-factor", + "Mouse wheel sensitivity during drag operations"); + dragWheelSensitivity->setDefaultValue (1.0); + dragWheelSensitivity->setRange (0.001, 100.0); + + Setting *dragShiftFactor = createSetting (Type_DoubleSpinBox, "drag-shift-factor", + "Acceleration factor during drag operations while holding down shift"); + dragShiftFactor->setDefaultValue (4.0); + dragShiftFactor->setRange (0.001, 100.0); } { diff --git a/apps/opencs/view/render/editmode.cpp b/apps/opencs/view/render/editmode.cpp index cc76e3362..c35b4f354 100644 --- a/apps/opencs/view/render/editmode.cpp +++ b/apps/opencs/view/render/editmode.cpp @@ -54,10 +54,10 @@ bool CSVRender::EditMode::selectStartDrag (osg::ref_ptr tag) return false; } -void CSVRender::EditMode::drag (int diffX, int diffY) {} +void CSVRender::EditMode::drag (int diffX, int diffY, double speedFactor) {} void CSVRender::EditMode::dragCompleted() {} void CSVRender::EditMode::dragAborted() {} -void CSVRender::EditMode::dragWheel (int diff) {} +void CSVRender::EditMode::dragWheel (int diff, double speedFactor) {} diff --git a/apps/opencs/view/render/editmode.hpp b/apps/opencs/view/render/editmode.hpp index 0a4bdf9b8..77676d6a3 100644 --- a/apps/opencs/view/render/editmode.hpp +++ b/apps/opencs/view/render/editmode.hpp @@ -61,7 +61,7 @@ namespace CSVRender virtual bool selectStartDrag (osg::ref_ptr tag); /// Default-implementation: ignored - virtual void drag (int diffX, int diffY); + virtual void drag (int diffX, int diffY, double speedFactor); /// Default-implementation: ignored virtual void dragCompleted(); @@ -73,7 +73,7 @@ namespace CSVRender virtual void dragAborted(); /// Default-implementation: ignored - virtual void dragWheel (int diff); + virtual void dragWheel (int diff, double speedFactor); }; } diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 3971f76fa..2789cd9d5 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -81,6 +81,10 @@ CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidg key += sMappingSettings[i]; storeMappingSetting (key, CSMSettings::UserSettings::instance().settingValue (key)); } + + mDragFactor = CSMSettings::UserSettings::instance().settingValue ("scene-input/drag-factor").toDouble(); + mDragWheelFactor = CSMSettings::UserSettings::instance().settingValue ("scene-input/drag-wheel-factor").toDouble(); + mDragShiftFactor = CSMSettings::UserSettings::instance().settingValue ("scene-input/drag-shift-factor").toDouble(); } CSVRender::WorldspaceWidget::~WorldspaceWidget () @@ -284,7 +288,14 @@ void CSVRender::WorldspaceWidget::updateUserSetting (const QString& name, const if (!value.isEmpty() && storeMappingSetting (name, value.first())) return; - dynamic_cast (*mEditMode->getCurrent()).updateUserSetting (name, value); + if (name=="scene-input/drag-factor") + mDragFactor = value.at (0).toDouble(); + else if (name=="scene-input/drag-wheel-factor") + mDragWheelFactor = value.at (0).toDouble(); + else if (name=="scene-input/drag-shift-factor") + mDragShiftFactor = value.at (0).toDouble(); + else + dynamic_cast (*mEditMode->getCurrent()).updateUserSetting (name, value); } void CSVRender::WorldspaceWidget::setEditLock (bool locked) @@ -530,9 +541,14 @@ void CSVRender::WorldspaceWidget::mouseMoveEvent (QMouseEvent *event) mDragX = event->x(); mDragY = height() - event->y(); + double factor = mDragFactor; + + if (QApplication::keyboardModifiers() & Qt::ShiftModifier) + factor *= mDragShiftFactor; + EditMode& editMode = dynamic_cast (*mEditMode->getCurrent()); - editMode.drag (diffX, diffY); + editMode.drag (diffX, diffY, factor); } RenderWidget::mouseMoveEvent(event); @@ -601,9 +617,14 @@ void CSVRender::WorldspaceWidget::wheelEvent (QWheelEvent *event) { if (mDragging) { + double factor = mDragWheelFactor; + + if (QApplication::keyboardModifiers() & Qt::ShiftModifier) + factor *= mDragShiftFactor; + EditMode& editMode = dynamic_cast (*mEditMode->getCurrent()); - editMode.dragWheel (event->delta()); + editMode.dragWheel (event->delta(), factor); } RenderWidget::wheelEvent(event); diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp index f51ce047e..338ebcc97 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -43,6 +43,9 @@ namespace CSVRender bool mDragging; int mDragX; int mDragY; + double mDragFactor; + double mDragWheelFactor; + double mDragShiftFactor; public: From 4b0fa370e38f6791c5f48df9caf3d77719b62ad8 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 2 Oct 2015 15:06:42 +0200 Subject: [PATCH 2244/3725] made WorldspaceWidget::getDocument public (EditModes will need the document later) --- apps/opencs/view/render/worldspacewidget.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp index 338ebcc97..f5e7970b6 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -112,6 +112,8 @@ namespace CSVRender virtual void setEditLock (bool locked); + CSMDoc::Document& getDocument(); + /// \param elementMask Elements to be affected by the clear operation virtual void clearSelection (int elementMask) = 0; @@ -121,8 +123,6 @@ namespace CSVRender virtual void addEditModeSelectorButtons (CSVWidget::SceneToolMode *tool); - CSMDoc::Document& getDocument(); - virtual void updateOverlay(); virtual void mouseMoveEvent (QMouseEvent *event); From 0a8e2c0b215af1287f1d250a7f48fa2852e75610 Mon Sep 17 00:00:00 2001 From: Rohit Nirmal Date: Sat, 3 Oct 2015 00:07:08 -0500 Subject: [PATCH 2245/3725] Fix building OpenCS with Qt 5. --- apps/opencs/view/render/worldspacewidget.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 2789cd9d5..75dd800eb 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -528,8 +528,13 @@ void CSVRender::WorldspaceWidget::mouseMoveEvent (QMouseEvent *event) if (mDragging) { +#if QT_VERSION >= QT_VERSION_CHECK(5,0,0) + mDragX = event->localPos().x(); + mDragY = height() - event->localPos().y(); +#else mDragX = event->posF().x(); mDragY = height() - event->posF().y(); +#endif } } } From b4132faaea34d1d153735c80e84dcea715523b34 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Sun, 4 Oct 2015 16:27:05 +0200 Subject: [PATCH 2246/3725] Update editmode.cpp Fixes builds on Windows --- apps/opencs/view/render/editmode.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/opencs/view/render/editmode.cpp b/apps/opencs/view/render/editmode.cpp index c35b4f354..4235faf76 100644 --- a/apps/opencs/view/render/editmode.cpp +++ b/apps/opencs/view/render/editmode.cpp @@ -1,5 +1,6 @@ #include "editmode.hpp" +#include "tagbase.hpp" #include "worldspacewidget.hpp" CSVRender::WorldspaceWidget& CSVRender::EditMode::getWorldspaceWidget() From ec4fff588dd4c1222a1435e348a7e499482bdc92 Mon Sep 17 00:00:00 2001 From: "artemutin@yandex.ru" Date: Mon, 5 Oct 2015 23:07:13 +1000 Subject: [PATCH 2247/3725] uncomment updateActor call in buildPlayer for magicka recalc --- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 12927101d..761c5ece9 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -295,7 +295,7 @@ namespace MWMechanics creatureStats.getSpells().add(*it); // forced update and current value adjustments - //mActors.updateActor (ptr, 0); + mActors.updateActor (ptr, 0); for (int i=0; i<3; ++i) { From 77cb438714963b70cee791ec5d592cf1c5fda2fb Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 5 Oct 2015 15:41:07 +0200 Subject: [PATCH 2248/3725] Fix potential case smashing issue --- apps/openmw/mwmechanics/spells.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/spells.cpp b/apps/openmw/mwmechanics/spells.cpp index 6d7673a59..330d78a20 100644 --- a/apps/openmw/mwmechanics/spells.cpp +++ b/apps/openmw/mwmechanics/spells.cpp @@ -312,7 +312,7 @@ namespace MWMechanics bool Spells::canUsePower(const std::string &power) const { - std::map::const_iterator it = mUsedPowers.find(power); + std::map::const_iterator it = mUsedPowers.find(Misc::StringUtils::lowerCase(power)); if (it == mUsedPowers.end() || it->second + 24 <= MWBase::Environment::get().getWorld()->getTimeStamp()) return true; else @@ -321,7 +321,7 @@ namespace MWMechanics void Spells::usePower(const std::string &power) { - mUsedPowers[power] = MWBase::Environment::get().getWorld()->getTimeStamp(); + mUsedPowers[Misc::StringUtils::lowerCase(power)] = MWBase::Environment::get().getWorld()->getTimeStamp(); } void Spells::readState(const ESM::SpellState &state) From 7b6fe149f2770de7d019696b6e2f6d0bbb670c6e Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 5 Oct 2015 15:41:43 +0200 Subject: [PATCH 2249/3725] getSpellSuccessChance return 0 for used powers (Fixes #2944) --- apps/openmw/mwmechanics/spellcasting.cpp | 7 +++++++ apps/openmw/mwworld/worldimp.cpp | 4 ---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 6d6b9d950..70d097687 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -123,6 +123,9 @@ namespace MWMechanics } } + if (spell->mData.mType == ESM::Spell::ST_Power) + return stats.getSpells().canUsePower(spell->mId) ? 100 : 0; + if (spell->mData.mType != ESM::Spell::ST_Spell) return 100; @@ -817,6 +820,10 @@ namespace MWMechanics sndMgr->playSound3D(mCaster, "Spell Failure " + schools[school], 1.0f, 1.0f); return false; } + + // A power can be used once per 24h + if (spell->mData.mType == ESM::Spell::ST_Power) + stats.getSpells().usePower(spell->mId); } if (mCaster == getPlayer() && spellIncreasesSkill(spell)) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 585786136..d994a35ee 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2660,10 +2660,6 @@ namespace MWWorld { const ESM::Spell* spell = getStore().get().find(selectedSpell); - // A power can be used once per 24h - if (spell->mData.mType == ESM::Spell::ST_Power) - stats.getSpells().usePower(spell->mId); - cast.cast(spell); } else if (actor.getClass().hasInventoryStore(actor)) From e8f68973760e32e77b8488e916ff603c3edad2b1 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 6 Oct 2015 14:30:32 +0200 Subject: [PATCH 2250/3725] fixed a possible script bug regarding ID-access for instances that did not yet existed when the script was compiled --- apps/openmw/mwscript/compilercontext.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwscript/compilercontext.cpp b/apps/openmw/mwscript/compilercontext.cpp index 083f463bc..cf5eff9e7 100644 --- a/apps/openmw/mwscript/compilercontext.cpp +++ b/apps/openmw/mwscript/compilercontext.cpp @@ -12,6 +12,7 @@ #include "../mwworld/ptr.hpp" #include "../mwworld/class.hpp" +#include "../mwworld/manualref.hpp" namespace MWScript { @@ -42,9 +43,9 @@ namespace MWScript } else { - MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPtr (id, false); + MWWorld::ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), id); - script = ptr.getClass().getScript (ptr); + script = ref.getPtr().getClass().getScript (ref.getPtr()); reference = true; } From 91bf5ae237adc7016432b20b57e600e06c6cbb17 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 7 Oct 2015 02:43:21 +0200 Subject: [PATCH 2251/3725] Add new script instance when a container item is unstacked (Bug #2962) --- apps/openmw/mwworld/containerstore.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 5a26f09f5..bcaaeff94 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -140,7 +140,11 @@ void MWWorld::ContainerStore::unstack(const Ptr &ptr, const Ptr& container) { if (ptr.getRefData().getCount() <= 1) return; - addNewStack(ptr, ptr.getRefData().getCount()-1); + MWWorld::ContainerStoreIterator it = addNewStack(ptr, ptr.getRefData().getCount()-1); + const std::string script = it->getClass().getScript(*it); + if (!script.empty()) + MWBase::Environment::get().getWorld()->getLocalScripts().add(script, *it); + remove(ptr, ptr.getRefData().getCount()-1, container); } From 944dfa53727eb0f8e93a6805cad0195093efa5f9 Mon Sep 17 00:00:00 2001 From: Emmanuel Anne Date: Mon, 5 Oct 2015 11:53:12 +0200 Subject: [PATCH 2252/3725] a light without the carry flag can't be equipped ! it fixes Antares big mod teaching disciplines, it adds a light which should not be equipped to npcs which have learnt something. --- apps/openmw/mwclass/light.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index f1dd18acc..34d93da67 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -234,6 +234,11 @@ namespace MWClass std::pair Light::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const { + MWWorld::LiveCellRef *ref = + ptr.get(); + if (!(ref->mBase->mData.mFlags & ESM::Light::Carry)) + return std::make_pair(0,""); + MWWorld::InventoryStore& invStore = npc.getClass().getInventoryStore(npc); MWWorld::ContainerStoreIterator weapon = invStore.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); From b911abd7d8c1e1f14350b8155825970020957790 Mon Sep 17 00:00:00 2001 From: Emmanuel Anne Date: Wed, 7 Oct 2015 12:25:52 +0200 Subject: [PATCH 2253/3725] add a few more possible arguments to choice this fixes some travel dialogs for "Antares Big Mod" --- components/compiler/extensions0.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/compiler/extensions0.cpp b/components/compiler/extensions0.cpp index cd645f0cf..6e65c3183 100644 --- a/components/compiler/extensions0.cpp +++ b/components/compiler/extensions0.cpp @@ -179,7 +179,7 @@ namespace Compiler extensions.registerInstruction ("setjournalindex", "cl", opcodeSetJournalIndex); extensions.registerFunction ("getjournalindex", 'l', "c", opcodeGetJournalIndex); extensions.registerInstruction ("addtopic", "S" , opcodeAddTopic); - extensions.registerInstruction ("choice", "j/SlSlSlSlSlSlSlSlSlSlSlSlSlSlSlSl", opcodeChoice); + extensions.registerInstruction ("choice", "j/SlSlSlSlSlSlSlSlSlSlSlSlSlSlSlSlSlSlSlSlSlSlSlSl", opcodeChoice); extensions.registerInstruction("forcegreeting","",opcodeForceGreeting, opcodeForceGreetingExplicit); extensions.registerInstruction("goodbye", "", opcodeGoodbye); From 998348e606182eb171dd82b99b647e3dff798b26 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Thu, 8 Oct 2015 12:35:09 +1100 Subject: [PATCH 2254/3725] Further rationalise the use of ColumnIds - Address Zini's review comments as per https://github.com/OpenMW/openmw/pull/755 --- apps/opencs/model/world/columnbase.cpp | 3 +-- apps/opencs/model/world/columnbase.hpp | 3 +-- apps/opencs/model/world/columns.cpp | 7 +++---- apps/opencs/model/world/columns.hpp | 6 +++--- apps/opencs/model/world/data.cpp | 10 +++++----- apps/opencs/model/world/refidcollection.cpp | 4 ++-- apps/opencs/view/doc/viewmanager.cpp | 2 +- 7 files changed, 16 insertions(+), 19 deletions(-) diff --git a/apps/opencs/model/world/columnbase.cpp b/apps/opencs/model/world/columnbase.cpp index 2143ec730..39232d442 100644 --- a/apps/opencs/model/world/columnbase.cpp +++ b/apps/opencs/model/world/columnbase.cpp @@ -77,7 +77,7 @@ bool CSMWorld::ColumnBase::isId (Display display) Display_Video, Display_Id, - Display_SkillImpact, + Display_SkillId, Display_EffectRange, Display_EffectId, Display_PartRefType, @@ -85,7 +85,6 @@ bool CSMWorld::ColumnBase::isId (Display display) Display_InfoCondFunc, Display_InfoCondVar, Display_InfoCondComp, - Display_RaceSkill, Display_None }; diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index 400e31333..e2871d4d8 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -113,7 +113,7 @@ namespace CSMWorld Display_SoundGeneratorType, Display_School, Display_Id, - Display_SkillImpact, + Display_SkillId, Display_EffectRange, Display_EffectId, Display_PartRefType, @@ -121,7 +121,6 @@ namespace CSMWorld Display_InfoCondFunc, Display_InfoCondVar, Display_InfoCondComp, - Display_RaceSkill, Display_String32, Display_LongString256, diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 2e0a697a5..78bee2195 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -268,7 +268,7 @@ namespace CSMWorld { ColumnId_LevelledItemChanceNone, "Chance None" }, { ColumnId_PowerList, "Powers" }, - { ColumnId_SkillImpact, "Skill" }, + { ColumnId_Skill, "Skill" }, { ColumnId_InfoList, "Info List" }, { ColumnId_InfoCondition, "Info Conditions" }, @@ -293,8 +293,7 @@ namespace CSMWorld { ColumnId_NpcPersistence, "Persistent" }, { ColumnId_RaceAttributes, "Race Attributes" }, - { ColumnId_RaceMaleValue, "Male Attrib" }, - { ColumnId_RaceFemaleValue, "Female Attrib" }, + { ColumnId_Male, "Male" }, { ColumnId_RaceSkillBonus, "Skill Bonus" }, { ColumnId_RaceBonus, "Bonus" }, @@ -572,7 +571,7 @@ namespace case CSMWorld::Columns::ColumnId_MeshType: return sMeshTypes; case CSMWorld::Columns::ColumnId_SoundGeneratorType: return sSoundGeneratorType; case CSMWorld::Columns::ColumnId_School: return sSchools; - case CSMWorld::Columns::ColumnId_SkillImpact: return sSkills; + case CSMWorld::Columns::ColumnId_Skill: return sSkills; case CSMWorld::Columns::ColumnId_EffectRange: return sEffectRange; case CSMWorld::Columns::ColumnId_EffectId: return sEffectId; case CSMWorld::Columns::ColumnId_PartRefType: return sPartRefType; diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index fb25004ec..b73f5e605 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -261,7 +261,7 @@ namespace CSMWorld ColumnId_LevelledItemChanceNone = 238, ColumnId_PowerList = 239, - ColumnId_SkillImpact = 240, // impact from magic effects + ColumnId_Skill = 240, ColumnId_InfoList = 241, ColumnId_InfoCondition = 242, @@ -288,8 +288,8 @@ namespace CSMWorld ColumnId_NpcPersistence = 261, ColumnId_RaceAttributes = 262, - ColumnId_RaceMaleValue = 263, - ColumnId_RaceFemaleValue = 264, + ColumnId_Male = 263, + // unused ColumnId_RaceSkillBonus = 265, // unused ColumnId_RaceBonus = 267, diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index a27ab5094..8acdac84f 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -143,15 +143,15 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_Attribute, ColumnBase::Flag_Dialogue, false)); mRaces.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_RaceMaleValue, ColumnBase::Display_Integer)); + new NestedChildColumn (Columns::ColumnId_Male, ColumnBase::Display_Integer)); mRaces.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_RaceFemaleValue, ColumnBase::Display_Integer)); + new NestedChildColumn (Columns::ColumnId_Female, ColumnBase::Display_Integer)); // Race skill bonus mRaces.addColumn (new NestedParentColumn (Columns::ColumnId_RaceSkillBonus)); index = mRaces.getColumns()-1; mRaces.addAdapter (std::make_pair(&mRaces.getColumn(index), new RaceSkillsBonusAdapter())); mRaces.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_SkillImpact, ColumnBase::Display_SkillImpact)); + new NestedChildColumn (Columns::ColumnId_Skill, ColumnBase::Display_SkillId)); mRaces.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_RaceBonus, ColumnBase::Display_Integer)); @@ -213,7 +213,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mSpells.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_EffectId)); mSpells.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_SkillImpact, ColumnBase::Display_SkillImpact)); + new NestedChildColumn (Columns::ColumnId_Skill, ColumnBase::Display_SkillId)); mSpells.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_Attribute)); mSpells.getNestableColumn(index)->addColumn( @@ -329,7 +329,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mEnchantments.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_EffectId)); mEnchantments.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_SkillImpact, ColumnBase::Display_SkillImpact)); + new NestedChildColumn (Columns::ColumnId_Skill, ColumnBase::Display_SkillId)); mEnchantments.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_Attribute)); mEnchantments.getNestableColumn(index)->addColumn( diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index d7b7cedfa..eb4dce51e 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -83,7 +83,7 @@ CSMWorld::RefIdCollection::RefIdCollection() mColumns.back().addColumn( new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_EffectId)); mColumns.back().addColumn( - new NestedChildColumn (Columns::ColumnId_SkillImpact, ColumnBase::Display_SkillImpact)); + new NestedChildColumn (Columns::ColumnId_Skill, ColumnBase::Display_SkillId)); mColumns.back().addColumn( new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_Attribute)); mColumns.back().addColumn( @@ -491,7 +491,7 @@ CSMWorld::RefIdCollection::RefIdCollection() skillsMap.insert(std::make_pair(UniversalId::Type_Npc, new NpcSkillsRefIdAdapter())); mNestedAdapters.push_back (std::make_pair(&mColumns.back(), skillsMap)); mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_SkillImpact, CSMWorld::ColumnBase::Display_SkillImpact, false, false)); + new RefIdColumn (Columns::ColumnId_Skill, CSMWorld::ColumnBase::Display_SkillId, false, false)); mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_UChar, CSMWorld::ColumnBase::Display_Integer)); diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index ca4ad2d00..728e69a7a 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -97,7 +97,7 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) { CSMWorld::ColumnBase::Display_Gender, CSMWorld::Columns::ColumnId_Gender, true }, { CSMWorld::ColumnBase::Display_SoundGeneratorType, CSMWorld::Columns::ColumnId_SoundGeneratorType, false }, { CSMWorld::ColumnBase::Display_School, CSMWorld::Columns::ColumnId_School, false }, - { CSMWorld::ColumnBase::Display_SkillImpact, CSMWorld::Columns::ColumnId_SkillImpact, true }, + { CSMWorld::ColumnBase::Display_SkillId, CSMWorld::Columns::ColumnId_Skill, true }, { CSMWorld::ColumnBase::Display_EffectRange, CSMWorld::Columns::ColumnId_EffectRange, false }, { CSMWorld::ColumnBase::Display_EffectId, CSMWorld::Columns::ColumnId_EffectId, false }, { CSMWorld::ColumnBase::Display_PartRefType, CSMWorld::Columns::ColumnId_PartRefType, false }, From 3bbcf6a9169dc24d47c4d10e24f3818681fc34c0 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Thu, 8 Oct 2015 12:47:23 +1100 Subject: [PATCH 2255/3725] Fix AiWander sub-table editing. Should resolve bugs #2888 and #2930. --- apps/opencs/model/world/columns.cpp | 11 ++- apps/opencs/model/world/columns.hpp | 11 ++- apps/opencs/model/world/refidadapterimp.hpp | 98 +++++++++++++-------- apps/opencs/model/world/refidcollection.cpp | 18 +++- 4 files changed, 99 insertions(+), 39 deletions(-) diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 78bee2195..d0d3a1671 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -249,7 +249,7 @@ namespace CSMWorld { ColumnId_AiWanderDist, "Wander Dist" }, { ColumnId_AiDuration, "Ai Duration" }, { ColumnId_AiWanderToD, "Wander ToD" }, - { ColumnId_AiWanderIdle, "Wander Idle" }, + //{ ColumnId_AiWanderIdle, "Wander Idle" }, { ColumnId_AiWanderRepeat, "Wander Repeat" }, { ColumnId_AiActivateName, "Activate" }, { ColumnId_AiTargetId, "Target ID" }, @@ -316,6 +316,15 @@ namespace CSMWorld { ColumnId_MaxAttack, "Max Attack" }, { ColumnId_CreatureMisc, "Creature Misc" }, + { ColumnId_Idle1, "Idle 1" }, + { ColumnId_Idle2, "Idle 2" }, + { ColumnId_Idle3, "Idle 3" }, + { ColumnId_Idle4, "Idle 4" }, + { ColumnId_Idle5, "Idle 5" }, + { ColumnId_Idle6, "Idle 6" }, + { ColumnId_Idle7, "Idle 7" }, + { ColumnId_Idle8, "Idle 8" }, + { ColumnId_UseValue1, "Use value 1" }, { ColumnId_UseValue2, "Use value 2" }, { ColumnId_UseValue3, "Use value 3" }, diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index b73f5e605..a504e5f65 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -241,7 +241,7 @@ namespace CSMWorld ColumnId_AiWanderDist = 221, ColumnId_AiDuration = 222, ColumnId_AiWanderToD = 223, - ColumnId_AiWanderIdle = 224, + // unused ColumnId_AiWanderRepeat = 225, ColumnId_AiActivateName = 226, // use ColumnId_PosX, etc for AI destinations @@ -316,6 +316,15 @@ namespace CSMWorld ColumnId_MaxAttack = 284, ColumnId_CreatureMisc = 285, + ColumnId_Idle1 = 286, + ColumnId_Idle2 = 287, + ColumnId_Idle3 = 288, + ColumnId_Idle4 = 289, + ColumnId_Idle5 = 290, + ColumnId_Idle6 = 291, + ColumnId_Idle7 = 292, + ColumnId_Idle8 = 293, + // Allocated to a separate value range, so we don't get a collision should we ever need // to extend the number of use values. ColumnId_UseValue1 = 0x10000, diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index 53da63806..4ac27b6e9 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -1532,6 +1532,8 @@ namespace CSMWorld virtual ~ActorAiRefIdAdapter() {} + // FIXME: should check if the AI package type is already in the list and use a default + // that wasn't used already (in extreme case do not add anything at all? virtual void addNestedRow (const RefIdColumn *column, RefIdData& data, int index, int position) const { @@ -1615,6 +1617,7 @@ namespace CSMWorld switch (subColIndex) { case 0: + // FIXME: should more than one AI package type be allowed? Check vanilla switch (content.mType) { case ESM::AI_Wander: return 0; @@ -1642,47 +1645,52 @@ namespace CSMWorld else return QVariant(); case 4: // wander idle + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: if (content.mType == ESM::AI_Wander) - { - return static_cast(content.mWander.mIdle[0]); // FIXME: - } + return static_cast(content.mWander.mIdle[subColIndex-4]); else return QVariant(); - case 5: // wander repeat + case 12: // wander repeat if (content.mType == ESM::AI_Wander) return content.mWander.mShouldRepeat != 0; else return QVariant(); - case 6: // activate name + case 13: // activate name if (content.mType == ESM::AI_Activate) return QString(content.mActivate.mName.toString().c_str()); else return QVariant(); - case 7: // target id + case 14: // target id if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort) return QString(content.mTarget.mId.toString().c_str()); else return QVariant(); - case 8: // target cell + case 15: // target cell if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort) return QString::fromUtf8(content.mCellName.c_str()); else return QVariant(); - case 9: + case 16: if (content.mType == ESM::AI_Travel) return content.mTravel.mX; else if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort) return content.mTarget.mX; else return QVariant(); - case 10: + case 17: if (content.mType == ESM::AI_Travel) return content.mTravel.mY; else if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort) return content.mTarget.mY; else return QVariant(); - case 11: + case 18: if (content.mType == ESM::AI_Travel) return content.mTravel.mZ; else if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort) @@ -1712,11 +1720,12 @@ namespace CSMWorld case 0: // ai package type switch (value.toInt()) { - case 0: content.mType = ESM::AI_Wander; - case 1: content.mType = ESM::AI_Travel; - case 2: content.mType = ESM::AI_Follow; - case 3: content.mType = ESM::AI_Escort; - case 4: content.mType = ESM::AI_Activate; + case 0: content.mType = ESM::AI_Wander; break; + case 1: content.mType = ESM::AI_Travel; break; + case 2: content.mType = ESM::AI_Follow; break; + case 3: content.mType = ESM::AI_Escort; break; + case 4: content.mType = ESM::AI_Activate; break; + default: return; // return without saving } break; // always save @@ -1725,6 +1734,8 @@ namespace CSMWorld content.mWander.mDistance = static_cast(value.toInt()); else return; // return without saving + + break; // always save case 2: if (content.mType == ESM::AI_Wander || content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort) @@ -1736,62 +1747,77 @@ namespace CSMWorld content.mWander.mTimeOfDay = static_cast(value.toInt()); else return; // return without saving + + break; // always save case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: if (content.mType == ESM::AI_Wander) - break; // FIXME: idle + content.mWander.mIdle[subColIndex-4] = static_cast(value.toInt()); else return; // return without saving - case 5: + + break; // always save + case 12: if (content.mType == ESM::AI_Wander) - { content.mWander.mShouldRepeat = static_cast(value.toInt()); - break; - } - case 6: // NAME32 + else + return; // return without saving + + break; // always save + case 13: // NAME32 if (content.mType == ESM::AI_Activate) - { content.mActivate.mName.assign(value.toString().toUtf8().constData()); - break; - } else return; // return without saving - case 7: // NAME32 + + break; // always save + case 14: // NAME32 if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort) - { content.mTarget.mId.assign(value.toString().toUtf8().constData()); - break; - } else return; // return without saving - case 8: + + break; // always save + case 15: if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort) - { content.mCellName = std::string(value.toString().toUtf8().constData()); - break; - } else return; // return without saving - case 9: + + break; // always save + case 16: if (content.mType == ESM::AI_Travel) content.mTravel.mZ = value.toFloat(); else if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort) content.mTarget.mZ = value.toFloat(); else return; // return without saving - case 10: + + break; // always save + case 17: if (content.mType == ESM::AI_Travel) content.mTravel.mZ = value.toFloat(); else if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort) content.mTarget.mZ = value.toFloat(); else return; // return without saving - case 11: + + break; // always save + case 18: if (content.mType == ESM::AI_Travel) content.mTravel.mZ = value.toFloat(); else if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort) content.mTarget.mZ = value.toFloat(); else return; // return without saving + + break; // always save default: throw std::runtime_error("Trying to access non-existing column in the nested table!"); } @@ -1801,7 +1827,7 @@ namespace CSMWorld virtual int getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const { - return 12; + return 19; } virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index eb4dce51e..3b316bea3 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -193,8 +193,24 @@ CSMWorld::RefIdCollection::RefIdCollection() new RefIdColumn (Columns::ColumnId_AiDuration, CSMWorld::ColumnBase::Display_Integer)); mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_AiWanderToD, CSMWorld::ColumnBase::Display_Integer)); + + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_Idle1, CSMWorld::ColumnBase::Display_Integer)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_Idle2, CSMWorld::ColumnBase::Display_Integer)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_Idle3, CSMWorld::ColumnBase::Display_Integer)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_Idle4, CSMWorld::ColumnBase::Display_Integer)); mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_AiWanderIdle, CSMWorld::ColumnBase::Display_Integer)); + new RefIdColumn (Columns::ColumnId_Idle5, CSMWorld::ColumnBase::Display_Integer)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_Idle6, CSMWorld::ColumnBase::Display_Integer)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_Idle7, CSMWorld::ColumnBase::Display_Integer)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_Idle8, CSMWorld::ColumnBase::Display_Integer)); + mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_AiWanderRepeat, CSMWorld::ColumnBase::Display_Boolean)); mColumns.back().addColumn( From 2f808f957d6cb0f59e4eb40002c931bf1bbee60b Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 8 Oct 2015 14:01:29 +0200 Subject: [PATCH 2256/3725] fixed for compiler not recognising script names in some situations --- apps/openmw/mwscript/compilercontext.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwscript/compilercontext.cpp b/apps/openmw/mwscript/compilercontext.cpp index cf5eff9e7..4a7038e1c 100644 --- a/apps/openmw/mwscript/compilercontext.cpp +++ b/apps/openmw/mwscript/compilercontext.cpp @@ -83,7 +83,8 @@ namespace MWScript store.get().search (name) || store.get().search (name) || store.get().search (name) || - store.get().search (name); + store.get().search (name) || + store.get().search (name); } bool CompilerContext::isJournalId (const std::string& name) const From e7a3f059aafb643238d95de8d34554747d7e74f2 Mon Sep 17 00:00:00 2001 From: "artemutin@yandex.ru" Date: Wed, 7 Oct 2015 12:39:19 +1000 Subject: [PATCH 2257/3725] Implemented line and col calculations in scriptsubview --- apps/opencs/view/world/scriptsubview.cpp | 46 +++++++++++++++--------- 1 file changed, 29 insertions(+), 17 deletions(-) diff --git a/apps/opencs/view/world/scriptsubview.cpp b/apps/opencs/view/world/scriptsubview.cpp index d99f789b3..35b9ccf0c 100644 --- a/apps/opencs/view/world/scriptsubview.cpp +++ b/apps/opencs/view/world/scriptsubview.cpp @@ -198,26 +198,38 @@ void CSVWorld::ScriptSubView::useHint (const std::string& hint) if (hint.empty()) return; - if (hint[0]=='l') - { - std::istringstream stream (hint.c_str()+1); - - char ignore; - int line; - int column; - - if (stream >> ignore >> line >> column) + size_t line = 0, column = 0; + std::istringstream stream (hint.c_str()+2); + switch(hint[0]){ + case 'R': + case 'r': { - QTextCursor cursor = mEditor->textCursor(); - - cursor.movePosition (QTextCursor::Start); - if (cursor.movePosition (QTextCursor::Down, QTextCursor::MoveAnchor, line)) - cursor.movePosition (QTextCursor::Right, QTextCursor::MoveAnchor, column); - - mEditor->setFocus(); - mEditor->setTextCursor (cursor); + QModelIndex index = mModel->getModelIndex (getUniversalId().getId(), mColumn); + QString source = mModel->data (index).toString(); + size_t pos; + stream >> pos >> pos; + + for (size_t i = 0; i <= pos; ++i){ + if (source[(unsigned) i] == '\n'){ + ++line; + column = i; + } + } + column = pos - column - (line > 0 ? 1 : 0); + break; } + case 'l': + stream >> line >> column; } + + QTextCursor cursor = mEditor->textCursor(); + + cursor.movePosition (QTextCursor::Start); + if (cursor.movePosition (QTextCursor::Down, QTextCursor::MoveAnchor, line)) + cursor.movePosition (QTextCursor::Right, QTextCursor::MoveAnchor, column); + + mEditor->setFocus(); + mEditor->setTextCursor (cursor); } void CSVWorld::ScriptSubView::textChanged() From 64821b0785a306f90e4f2f3be9c6a8fa61d440eb Mon Sep 17 00:00:00 2001 From: cc9cii Date: Fri, 9 Oct 2015 06:29:50 +1100 Subject: [PATCH 2258/3725] Disable toolbar context menu. Should resolve bug #2953. --- apps/opencs/view/doc/view.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index ea11bb0f9..38088c6d7 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -435,6 +435,8 @@ CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int to mOperations = new Operations; addDockWidget (Qt::BottomDockWidgetArea, mOperations); + setContextMenuPolicy(Qt::NoContextMenu); + updateTitle(); setupUi(); From 8eb6d337d556dce2f64698ac30ad0df881bf84e0 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 9 Oct 2015 12:14:22 +0200 Subject: [PATCH 2259/3725] deal with script execution from within a script (Fixes #2964) --- components/interpreter/interpreter.cpp | 55 +++++++++++++++++++++----- components/interpreter/interpreter.hpp | 7 ++++ 2 files changed, 53 insertions(+), 9 deletions(-) diff --git a/components/interpreter/interpreter.cpp b/components/interpreter/interpreter.cpp index 263cea9a5..1892e4a6f 100644 --- a/components/interpreter/interpreter.cpp +++ b/components/interpreter/interpreter.cpp @@ -132,7 +132,34 @@ namespace Interpreter throw std::runtime_error (error.str()); } - Interpreter::Interpreter() + void Interpreter::begin() + { + if (mRunning) + { + mCallstack.push (mRuntime); + mRuntime.clear(); + } + else + { + mRunning = true; + } + } + + void Interpreter::end() + { + if (mCallstack.empty()) + { + mRuntime.clear(); + mRunning = false; + } + else + { + mRuntime = mCallstack.top(); + mCallstack.pop(); + } + } + + Interpreter::Interpreter() : mRunning (false) {} Interpreter::~Interpreter() @@ -202,19 +229,29 @@ namespace Interpreter { assert (codeSize>=4); - mRuntime.configure (code, codeSize, context); + begin(); - int opcodes = static_cast (code[0]); + try + { + mRuntime.configure (code, codeSize, context); - const Type_Code *codeBlock = code + 4; + int opcodes = static_cast (code[0]); - while (mRuntime.getPC()>=0 && mRuntime.getPC()=0 && mRuntime.getPC() +#include #include "runtime.hpp" #include "types.hpp" @@ -14,6 +15,8 @@ namespace Interpreter class Interpreter { + std::stack mCallstack; + bool mRunning; Runtime mRuntime; std::map mSegment0; std::map mSegment1; @@ -32,6 +35,10 @@ namespace Interpreter void abortUnknownSegment (Type_Code code); + void begin(); + + void end(); + public: Interpreter(); From 4ca7b2660932efb06535f148a643a7e814f3a72d Mon Sep 17 00:00:00 2001 From: "artemutin@yandex.ru" Date: Fri, 9 Oct 2015 21:52:12 +1000 Subject: [PATCH 2260/3725] Stream error handling, and other minor changes. --- apps/opencs/view/world/scriptsubview.cpp | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/apps/opencs/view/world/scriptsubview.cpp b/apps/opencs/view/world/scriptsubview.cpp index 35b9ccf0c..eb0c70656 100644 --- a/apps/opencs/view/world/scriptsubview.cpp +++ b/apps/opencs/view/world/scriptsubview.cpp @@ -198,28 +198,31 @@ void CSVWorld::ScriptSubView::useHint (const std::string& hint) if (hint.empty()) return; - size_t line = 0, column = 0; - std::istringstream stream (hint.c_str()+2); + unsigned line = 0, column = 0; + char c; + std::istringstream stream (hint.c_str()+1); switch(hint[0]){ case 'R': case 'r': { QModelIndex index = mModel->getModelIndex (getUniversalId().getId(), mColumn); QString source = mModel->data (index).toString(); - size_t pos; - stream >> pos >> pos; + unsigned pos, dummy; + if (!(stream >> c >> dummy >> pos) ) + return; - for (size_t i = 0; i <= pos; ++i){ - if (source[(unsigned) i] == '\n'){ + for (unsigned i = 0; i <= pos; ++i){ + if (source[i] == '\n'){ ++line; - column = i; + column = i+1; } } - column = pos - column - (line > 0 ? 1 : 0); + column = pos - column; break; } case 'l': - stream >> line >> column; + if (!(stream >> c >> line >> column)) + return; } QTextCursor cursor = mEditor->textCursor(); From 0d35938794f161a84ff66ae587e95fae8e0f2c12 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 12 Oct 2015 14:12:01 +0200 Subject: [PATCH 2261/3725] basic cell arrow rendering (shape is a placeholder) --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/view/render/cell.cpp | 24 +++++ apps/opencs/view/render/cell.hpp | 8 ++ apps/opencs/view/render/cellarrow.cpp | 93 +++++++++++++++++++ apps/opencs/view/render/cellarrow.hpp | 70 ++++++++++++++ .../view/render/pagedworldspacewidget.cpp | 32 +++++++ 6 files changed, 228 insertions(+), 1 deletion(-) create mode 100644 apps/opencs/view/render/cellarrow.cpp create mode 100644 apps/opencs/view/render/cellarrow.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 196e899b2..6af04e8fc 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -90,7 +90,7 @@ opencs_units (view/render opencs_units_noqt (view/render lighting lightingday lightingnight - lightingbright object cell terrainstorage tagbase + lightingbright object cell terrainstorage tagbase cellarrow ) opencs_hdrs_noqt (view/render diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index c4f744510..345bc79a7 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -9,6 +9,7 @@ #include "../../model/world/columns.hpp" #include "../../model/world/data.hpp" #include "../../model/world/refcollection.hpp" +#include "../../model/world/cellcoordinates.hpp" #include "elements.hpp" #include "terrainstorage.hpp" @@ -232,3 +233,26 @@ void CSVRender::Cell::setSelection (int elementMask, Selection mode) } } } + +void CSVRender::Cell::setCellArrows (int mask) +{ + for (int i=0; i<4; ++i) + { + CellArrow::Direction direction = static_cast (1< mTerrain; int mX; int mY; + std::auto_ptr mCellArrows[4]; /// Ignored if cell does not have an object with the given ID. /// @@ -86,6 +89,11 @@ namespace CSVRender bool referenceAdded (const QModelIndex& parent, int start, int end); void setSelection (int elementMask, Selection mode); + + void setCellArrows (int mask); + + /// Returns 0, 0 in case of an unpaged cell. + CSMWorld::CellCoordinates getCoordinates() const; }; } diff --git a/apps/opencs/view/render/cellarrow.cpp b/apps/opencs/view/render/cellarrow.cpp new file mode 100644 index 000000000..ee055a0b1 --- /dev/null +++ b/apps/opencs/view/render/cellarrow.cpp @@ -0,0 +1,93 @@ + +#include "cellarrow.hpp" + +#include +#include + +#include +#include +#include + + +#include "elements.hpp" + +CSVRender::CellArrowTag::CellArrowTag (CellArrow *arrow) +: TagBase (Element_CellArrow), mArrow (arrow) +{} + +CSVRender::CellArrow *CSVRender::CellArrowTag::getCellArrow() const +{ + return mArrow; +} + + +void CSVRender::CellArrow::adjustTransform() +{ + // position + const int cellSize = 8192; + const int offset = cellSize / 2 + 400; + + int x = mXIndex*cellSize + cellSize/2; + int y = mYIndex*cellSize + cellSize/2; + + switch (mDirection) + { + case Direction_North: y += offset; break; + case Direction_West: x -= offset; break; + case Direction_South: y -= offset; break; + case Direction_East: x += offset; break; + }; + + mBaseNode->setPosition (osg::Vec3f (x, y, 0)); + + // orientation + osg::Quat xr (0, osg::Vec3f (1,0,0)); + osg::Quat yr (0, osg::Vec3f (0,1,0)); + osg::Quat zr (0, osg::Vec3f (0,0,1)); + mBaseNode->setAttitude (zr*yr*xr); +} + +void CSVRender::CellArrow::buildShape() +{ + /// \todo placeholder shape -> replace + osg::ref_ptr shape(new osg::Box(osg::Vec3f(0,0,0), 200)); + osg::ref_ptr shapedrawable(new osg::ShapeDrawable); + shapedrawable->setShape(shape); + + osg::ref_ptr geode (new osg::Geode); + geode->addDrawable(shapedrawable); + + mBaseNode->addChild (geode); +} + +CSVRender::CellArrow::CellArrow (osg::Group *cellNode, Direction direction, + int xIndex, int yIndex) +: mDirection (direction), mParentNode (cellNode), mXIndex (xIndex), mYIndex (yIndex) +{ + mBaseNode = new osg::PositionAttitudeTransform; + + mBaseNode->setUserData (new CellArrowTag (this)); + + mParentNode->addChild (mBaseNode); + + // 0x1 reserved for separating cull and update visitors + mBaseNode->setNodeMask (Element_CellArrow<<1); + + adjustTransform(); + buildShape(); +} + +CSVRender::CellArrow::~CellArrow() +{ + mParentNode->removeChild (mBaseNode); +} + +int CSVRender::CellArrow::getXIndex() const +{ + return mXIndex; +} + +int CSVRender::CellArrow::getYIndex() const +{ + return mYIndex; +} diff --git a/apps/opencs/view/render/cellarrow.hpp b/apps/opencs/view/render/cellarrow.hpp new file mode 100644 index 000000000..822e63bdc --- /dev/null +++ b/apps/opencs/view/render/cellarrow.hpp @@ -0,0 +1,70 @@ +#ifndef OPENCS_VIEW_CELLARROW_H +#define OPENCS_VIEW_CELLARROW_H + +#include "tagbase.hpp" + +#include + +namespace osg +{ + class PositionAttitudeTransform; + class Group; +} + +namespace CSVRender +{ + class CellArrow; + + class CellArrowTag : public TagBase + { + CellArrow *mArrow; + + public: + + CellArrowTag (CellArrow *arrow); + + CellArrow *getCellArrow() const; + }; + + + class CellArrow + { + public: + + enum Direction + { + Direction_North = 1, + Direction_West = 2, + Direction_South = 4, + Direction_East = 8 + }; + + private: + + // not implemented + CellArrow (const CellArrow&); + CellArrow& operator= (const CellArrow&); + + Direction mDirection; + osg::Group* mParentNode; + osg::ref_ptr mBaseNode; + int mXIndex; + int mYIndex; + + void adjustTransform(); + + void buildShape(); + + public: + + CellArrow (osg::Group *cellNode, Direction direction, int xIndex, int yIndex); + + ~CellArrow(); + + int getXIndex() const; + + int getYIndex() const; + }; +} + +#endif diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index 7403113b3..070ce7d17 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -21,6 +21,7 @@ bool CSVRender::PagedWorldspaceWidget::adjustCells() { bool modified = false; + bool wasEmpty = mCells.empty(); const CSMWorld::IdCollection& cells = mDocument.getData().getCells(); @@ -32,6 +33,7 @@ bool CSVRender::PagedWorldspaceWidget::adjustCells() { int index = cells.searchId (iter->first.getId (mWorldspace)); + /// \todo handle cells that don't exist if (!mSelection.has (iter->first) || index==-1 || cells.getRecord (index).mState==CSMWorld::RecordBase::State_Deleted) { @@ -60,6 +62,7 @@ bool CSVRender::PagedWorldspaceWidget::adjustCells() { int index = cells.searchId (iter->getId (mWorldspace)); + /// \todo handle cells that don't exist if (index > 0 && cells.getRecord (index).mState!=CSMWorld::RecordBase::State_Deleted && mCells.find (*iter)==mCells.end()) { @@ -72,6 +75,35 @@ bool CSVRender::PagedWorldspaceWidget::adjustCells() } if (modified) + { + for (std::map::const_iterator iter (mCells.begin()); + iter!=mCells.end(); ++iter) + { + int mask = 0; + + for (int i=CellArrow::Direction_North; i<=CellArrow::Direction_East; i *= 2) + { + CSMWorld::CellCoordinates coordinates (iter->second->getCoordinates()); + + switch (i) + { + case CellArrow::Direction_North: coordinates = coordinates.move (0, 1); break; + case CellArrow::Direction_West: coordinates = coordinates.move (-1, 0); break; + case CellArrow::Direction_South: coordinates = coordinates.move (0, -1); break; + case CellArrow::Direction_East: coordinates = coordinates.move (1, 0); break; + } + + if (!mSelection.has (coordinates)) + mask |= i; + } + + iter->second->setCellArrows (mask); + } + } + + /// \todo do not overwrite manipulator object + /// \todo move code to useViewHint function + if (modified && wasEmpty) mView->setCameraManipulator(new osgGA::TrackballManipulator); return modified; From b81ee606c831f3a7b700165716f0df568d0a6ad3 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 12 Oct 2015 14:31:55 +0200 Subject: [PATCH 2262/3725] use CellCoordinates instead of a pair of ints for cell coordinates --- apps/opencs/view/render/cell.cpp | 9 ++++----- apps/opencs/view/render/cell.hpp | 3 +-- apps/opencs/view/render/cellarrow.cpp | 18 ++++++------------ apps/opencs/view/render/cellarrow.hpp | 12 ++++++------ 4 files changed, 17 insertions(+), 25 deletions(-) diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index 345bc79a7..e0e63c8c9 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -52,7 +52,7 @@ bool CSVRender::Cell::addObjects (int start, int end) } CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::string& id) -: mData (data), mId (Misc::StringUtils::lowerCase (id)), mX(0), mY(0) +: mData (data), mId (Misc::StringUtils::lowerCase (id)) { mCellNode = new osg::Group; rootNode->addChild(mCellNode); @@ -76,8 +76,7 @@ CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::st mTerrain->loadCell(esmLand.mX, esmLand.mY); - mX = esmLand.mX; - mY = esmLand.mY; + mCoordinates = CSMWorld::CellCoordinates (esmLand.mX, esmLand.mY); } } } @@ -245,7 +244,7 @@ void CSVRender::Cell::setCellArrows (int mask) if (enable!=(mCellArrows[i].get()!=0)) { if (enable) - mCellArrows[i].reset (new CellArrow (mCellNode, direction, mX, mY)); + mCellArrows[i].reset (new CellArrow (mCellNode, direction, mCoordinates)); else mCellArrows[i].reset (0); } @@ -254,5 +253,5 @@ void CSVRender::Cell::setCellArrows (int mask) CSMWorld::CellCoordinates CSVRender::Cell::getCoordinates() const { - return CSMWorld::CellCoordinates (mX, mY); + return mCoordinates; } diff --git a/apps/opencs/view/render/cell.hpp b/apps/opencs/view/render/cell.hpp index 5b1badcbe..7cced4fe3 100644 --- a/apps/opencs/view/render/cell.hpp +++ b/apps/opencs/view/render/cell.hpp @@ -38,8 +38,7 @@ namespace CSVRender osg::ref_ptr mCellNode; std::map mObjects; std::auto_ptr mTerrain; - int mX; - int mY; + CSMWorld::CellCoordinates mCoordinates; std::auto_ptr mCellArrows[4]; /// Ignored if cell does not have an object with the given ID. diff --git a/apps/opencs/view/render/cellarrow.cpp b/apps/opencs/view/render/cellarrow.cpp index ee055a0b1..443d398dd 100644 --- a/apps/opencs/view/render/cellarrow.cpp +++ b/apps/opencs/view/render/cellarrow.cpp @@ -8,7 +8,6 @@ #include #include - #include "elements.hpp" CSVRender::CellArrowTag::CellArrowTag (CellArrow *arrow) @@ -27,8 +26,8 @@ void CSVRender::CellArrow::adjustTransform() const int cellSize = 8192; const int offset = cellSize / 2 + 400; - int x = mXIndex*cellSize + cellSize/2; - int y = mYIndex*cellSize + cellSize/2; + int x = mCoordinates.getX()*cellSize + cellSize/2; + int y = mCoordinates.getY()*cellSize + cellSize/2; switch (mDirection) { @@ -61,8 +60,8 @@ void CSVRender::CellArrow::buildShape() } CSVRender::CellArrow::CellArrow (osg::Group *cellNode, Direction direction, - int xIndex, int yIndex) -: mDirection (direction), mParentNode (cellNode), mXIndex (xIndex), mYIndex (yIndex) + const CSMWorld::CellCoordinates& coordinates) +: mDirection (direction), mParentNode (cellNode), mCoordinates (coordinates) { mBaseNode = new osg::PositionAttitudeTransform; @@ -82,12 +81,7 @@ CSVRender::CellArrow::~CellArrow() mParentNode->removeChild (mBaseNode); } -int CSVRender::CellArrow::getXIndex() const -{ - return mXIndex; -} - -int CSVRender::CellArrow::getYIndex() const +CSMWorld::CellCoordinates CSVRender::CellArrow::getCoordinates() const { - return mYIndex; + return mCoordinates; } diff --git a/apps/opencs/view/render/cellarrow.hpp b/apps/opencs/view/render/cellarrow.hpp index 822e63bdc..4422ec890 100644 --- a/apps/opencs/view/render/cellarrow.hpp +++ b/apps/opencs/view/render/cellarrow.hpp @@ -5,6 +5,8 @@ #include +#include "../../model/world/cellcoordinates.hpp" + namespace osg { class PositionAttitudeTransform; @@ -48,8 +50,7 @@ namespace CSVRender Direction mDirection; osg::Group* mParentNode; osg::ref_ptr mBaseNode; - int mXIndex; - int mYIndex; + CSMWorld::CellCoordinates mCoordinates; void adjustTransform(); @@ -57,13 +58,12 @@ namespace CSVRender public: - CellArrow (osg::Group *cellNode, Direction direction, int xIndex, int yIndex); + CellArrow (osg::Group *cellNode, Direction direction, + const CSMWorld::CellCoordinates& coordinates); ~CellArrow(); - int getXIndex() const; - - int getYIndex() const; + CSMWorld::CellCoordinates getCoordinates() const; }; } From 3f9db7ba3cc12739a238207797c92c07b74332ab Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 12 Oct 2015 18:00:44 +0200 Subject: [PATCH 2263/3725] more reliable method of obtaining the cell coordinates in CSVRender::Cell --- apps/opencs/model/world/cellcoordinates.cpp | 17 +++++++++++++++++ apps/opencs/model/world/cellcoordinates.hpp | 6 ++++++ apps/opencs/view/render/cell.cpp | 7 +++++-- 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/world/cellcoordinates.cpp b/apps/opencs/model/world/cellcoordinates.cpp index 95e206e2d..3ef3e6c69 100644 --- a/apps/opencs/model/world/cellcoordinates.cpp +++ b/apps/opencs/model/world/cellcoordinates.cpp @@ -32,6 +32,23 @@ std::string CSMWorld::CellCoordinates::getId (const std::string& worldspace) con return stream.str(); } +std::pair CSMWorld::CellCoordinates::fromId ( + const std::string& id) +{ + // no worldspace for now, needs to be changed for 1.1 + if (!id.empty() && id[0]=='#') + { + int x, y; + char ignore; + + std::istringstream stream (id); + if (stream >> ignore >> x >> y) + return std::make_pair (CellCoordinates (x, y), true); + } + + return std::make_pair (CellCoordinates(), false); +} + bool CSMWorld::operator== (const CellCoordinates& left, const CellCoordinates& right) { return left.getX()==right.getX() && left.getY()==right.getY(); diff --git a/apps/opencs/model/world/cellcoordinates.hpp b/apps/opencs/model/world/cellcoordinates.hpp index ee395ea7e..63db60c29 100644 --- a/apps/opencs/model/world/cellcoordinates.hpp +++ b/apps/opencs/model/world/cellcoordinates.hpp @@ -28,6 +28,12 @@ namespace CSMWorld std::string getId (const std::string& worldspace) const; ///< Return the ID for the cell at these coordinates. + + /// \return first: CellCoordinates (or 0, 0 if cell does not have coordinates), + /// second: is cell paged? + /// + /// \note The worldspace part of \a id is ignored + static std::pair fromId (const std::string& id); }; bool operator== (const CellCoordinates& left, const CellCoordinates& right); diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index e0e63c8c9..5ec69a5f2 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -54,6 +54,11 @@ bool CSVRender::Cell::addObjects (int start, int end) CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::string& id) : mData (data), mId (Misc::StringUtils::lowerCase (id)) { + std::pair result = CSMWorld::CellCoordinates::fromId (id); + + if (result.second) + mCoordinates = result.first; + mCellNode = new osg::Group; rootNode->addChild(mCellNode); @@ -75,8 +80,6 @@ CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::st mTerrain.reset(new Terrain::TerrainGrid(mCellNode, data.getResourceSystem().get(), NULL, new TerrainStorage(mData), Element_Terrain<<1)); mTerrain->loadCell(esmLand.mX, esmLand.mY); - - mCoordinates = CSMWorld::CellCoordinates (esmLand.mX, esmLand.mY); } } } From 6e140c9cb1c3cb3406295a57488f32e5d6acc288 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 13 Oct 2015 11:43:33 +0200 Subject: [PATCH 2264/3725] proper shape for cell arrows (kinda) --- apps/opencs/view/render/cellarrow.cpp | 95 ++++++++++++++++++++++----- 1 file changed, 78 insertions(+), 17 deletions(-) diff --git a/apps/opencs/view/render/cellarrow.cpp b/apps/opencs/view/render/cellarrow.cpp index 443d398dd..8f03b489f 100644 --- a/apps/opencs/view/render/cellarrow.cpp +++ b/apps/opencs/view/render/cellarrow.cpp @@ -3,10 +3,9 @@ #include #include - -#include -#include #include +#include +#include #include "elements.hpp" @@ -24,37 +23,99 @@ void CSVRender::CellArrow::adjustTransform() { // position const int cellSize = 8192; - const int offset = cellSize / 2 + 400; + const int offset = cellSize / 2 + 800; int x = mCoordinates.getX()*cellSize + cellSize/2; int y = mCoordinates.getY()*cellSize + cellSize/2; + float xr = 0; + float yr = 0; + float zr = 0; + + float angle = osg::DegreesToRadians (90.0f); + switch (mDirection) { - case Direction_North: y += offset; break; - case Direction_West: x -= offset; break; - case Direction_South: y -= offset; break; - case Direction_East: x += offset; break; + case Direction_North: y += offset; xr = -angle; zr = angle; break; + case Direction_West: x -= offset; yr = -angle; break; + case Direction_South: y -= offset; xr = angle; zr = angle; break; + case Direction_East: x += offset; yr = angle; break; }; mBaseNode->setPosition (osg::Vec3f (x, y, 0)); // orientation - osg::Quat xr (0, osg::Vec3f (1,0,0)); - osg::Quat yr (0, osg::Vec3f (0,1,0)); - osg::Quat zr (0, osg::Vec3f (0,0,1)); - mBaseNode->setAttitude (zr*yr*xr); + osg::Quat xr2 (xr, osg::Vec3f (1,0,0)); + osg::Quat yr2 (yr, osg::Vec3f (0,1,0)); + osg::Quat zr2 (zr, osg::Vec3f (0,0,1)); + mBaseNode->setAttitude (zr2*yr2*xr2); } void CSVRender::CellArrow::buildShape() { - /// \todo placeholder shape -> replace - osg::ref_ptr shape(new osg::Box(osg::Vec3f(0,0,0), 200)); - osg::ref_ptr shapedrawable(new osg::ShapeDrawable); - shapedrawable->setShape(shape); + osg::ref_ptr geometry (new osg::Geometry); + + const int arrowWidth = 4000; + const int arrowLength = 1500; + const int arrowHeight = 500; + + osg::Vec3Array *vertices = new osg::Vec3Array; + for (int i2=0; i2<2; ++i2) + for (int i=0; i<2; ++i) + { + float height = i ? -arrowHeight/2 : arrowHeight/2; + vertices->push_back (osg::Vec3f (height, -arrowWidth/2, 0)); + vertices->push_back (osg::Vec3f (height, arrowWidth/2, 0)); + vertices->push_back (osg::Vec3f (height, 0, arrowLength)); + } + + geometry->setVertexArray (vertices); + + osg::DrawElementsUShort *top = new osg::DrawElementsUShort (osg::PrimitiveSet::TRIANGLES, 0); + top->push_back (0); + top->push_back (1); + top->push_back (2); + geometry->addPrimitiveSet (top); + + osg::DrawElementsUShort *bottom = new osg::DrawElementsUShort (osg::PrimitiveSet::TRIANGLES, 0); + bottom->push_back (5); + bottom->push_back (4); + bottom->push_back (3); + geometry->addPrimitiveSet (bottom); + + osg::DrawElementsUShort *back = new osg::DrawElementsUShort (osg::PrimitiveSet::QUADS, 0); + back->push_back (3+6); + back->push_back (4+6); + back->push_back (1+6); + back->push_back (0+6); + geometry->addPrimitiveSet (back); + + osg::DrawElementsUShort *side1 = new osg::DrawElementsUShort (osg::PrimitiveSet::QUADS, 0); + side1->push_back (0+6); + side1->push_back (2+6); + side1->push_back (5+6); + side1->push_back (3+6); + geometry->addPrimitiveSet (side1); + + osg::DrawElementsUShort *side2 = new osg::DrawElementsUShort (osg::PrimitiveSet::QUADS, 0); + side2->push_back (4+6); + side2->push_back (5+6); + side2->push_back (2+6); + side2->push_back (1+6); + geometry->addPrimitiveSet (side2); + + osg::Vec4Array *colours = new osg::Vec4Array; + + for (int i=0; i<6; ++i) + colours->push_back (osg::Vec4f (1.0f, 0.0f, 0.0f, 1.0f)); + for (int i=0; i<6; ++i) + colours->push_back (osg::Vec4f (1.0f, 0.0f, 0.4f, 1.0f)); + + geometry->setColorArray (colours); + geometry->setColorBinding (osg::Geometry::BIND_PER_VERTEX); osg::ref_ptr geode (new osg::Geode); - geode->addDrawable(shapedrawable); + geode->addDrawable (geometry); mBaseNode->addChild (geode); } From 0b1d6bddc8b1f2f16b61d51be7bc4fd09e618049 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 13 Oct 2015 16:11:47 +0200 Subject: [PATCH 2265/3725] merged primitives arrays --- apps/opencs/view/render/cellarrow.cpp | 71 +++++++++++++++------------ 1 file changed, 39 insertions(+), 32 deletions(-) diff --git a/apps/opencs/view/render/cellarrow.cpp b/apps/opencs/view/render/cellarrow.cpp index 8f03b489f..526c9a24c 100644 --- a/apps/opencs/view/render/cellarrow.cpp +++ b/apps/opencs/view/render/cellarrow.cpp @@ -71,38 +71,45 @@ void CSVRender::CellArrow::buildShape() geometry->setVertexArray (vertices); - osg::DrawElementsUShort *top = new osg::DrawElementsUShort (osg::PrimitiveSet::TRIANGLES, 0); - top->push_back (0); - top->push_back (1); - top->push_back (2); - geometry->addPrimitiveSet (top); - - osg::DrawElementsUShort *bottom = new osg::DrawElementsUShort (osg::PrimitiveSet::TRIANGLES, 0); - bottom->push_back (5); - bottom->push_back (4); - bottom->push_back (3); - geometry->addPrimitiveSet (bottom); - - osg::DrawElementsUShort *back = new osg::DrawElementsUShort (osg::PrimitiveSet::QUADS, 0); - back->push_back (3+6); - back->push_back (4+6); - back->push_back (1+6); - back->push_back (0+6); - geometry->addPrimitiveSet (back); - - osg::DrawElementsUShort *side1 = new osg::DrawElementsUShort (osg::PrimitiveSet::QUADS, 0); - side1->push_back (0+6); - side1->push_back (2+6); - side1->push_back (5+6); - side1->push_back (3+6); - geometry->addPrimitiveSet (side1); - - osg::DrawElementsUShort *side2 = new osg::DrawElementsUShort (osg::PrimitiveSet::QUADS, 0); - side2->push_back (4+6); - side2->push_back (5+6); - side2->push_back (2+6); - side2->push_back (1+6); - geometry->addPrimitiveSet (side2); + osg::DrawElementsUShort *primitives = new osg::DrawElementsUShort (osg::PrimitiveSet::TRIANGLES, 0); + + // top + primitives->push_back (0); + primitives->push_back (1); + primitives->push_back (2); + + // bottom + primitives->push_back (5); + primitives->push_back (4); + primitives->push_back (3); + + // back + primitives->push_back (3+6); + primitives->push_back (4+6); + primitives->push_back (1+6); + + primitives->push_back (3+6); + primitives->push_back (1+6); + primitives->push_back (0+6); + + // sides + primitives->push_back (0+6); + primitives->push_back (2+6); + primitives->push_back (5+6); + + primitives->push_back (0+6); + primitives->push_back (5+6); + primitives->push_back (3+6); + + primitives->push_back (4+6); + primitives->push_back (5+6); + primitives->push_back (2+6); + + primitives->push_back (4+6); + primitives->push_back (2+6); + primitives->push_back (1+6); + + geometry->addPrimitiveSet (primitives); osg::Vec4Array *colours = new osg::Vec4Array; From 68115c4e8aa3447e8848528b816c3fd4a8253e64 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 13 Oct 2015 16:15:53 +0200 Subject: [PATCH 2266/3725] (somewhat) improved the colour scheme --- apps/opencs/view/render/cellarrow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/view/render/cellarrow.cpp b/apps/opencs/view/render/cellarrow.cpp index 526c9a24c..59460b626 100644 --- a/apps/opencs/view/render/cellarrow.cpp +++ b/apps/opencs/view/render/cellarrow.cpp @@ -116,7 +116,7 @@ void CSVRender::CellArrow::buildShape() for (int i=0; i<6; ++i) colours->push_back (osg::Vec4f (1.0f, 0.0f, 0.0f, 1.0f)); for (int i=0; i<6; ++i) - colours->push_back (osg::Vec4f (1.0f, 0.0f, 0.4f, 1.0f)); + colours->push_back (osg::Vec4f (0.8f, (i==2 || i==5) ? 0.6f : 0.4f, 0.0f, 1.0f)); geometry->setColorArray (colours); geometry->setColorBinding (osg::Geometry::BIND_PER_VERTEX); From a88d56148b45a6ddb1c4cb95ab75f112550fac58 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 13 Oct 2015 16:35:31 +0200 Subject: [PATCH 2267/3725] Read the Sun Glare Fader ini settings --- apps/openmw/mwrender/sky.cpp | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 6f1b26733..a8aeeb930 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -724,7 +724,17 @@ private: , mTimeOfDayFade(1.f) , mGlareView(1.f) { - + const MWWorld::Fallback* fallback = MWBase::Environment::get().getWorld()->getFallback(); + mColor = fallback->getFallbackColour("Weather_Sun_Glare_Fader_Color"); + mSunGlareFaderMax = fallback->getFallbackFloat("Weather_Sun_Glare_Fader_Max"); + mSunGlareFaderAngleMax = fallback->getFallbackFloat("Weather_Sun_Glare_Fader_Angle_Max"); + + // Replicating a design flaw in MW. The color was being set on both ambient and emissive properties, which multiplies the result by two, + // then finally gets clamped by the fixed function pipeline. With the default INI settings, only the red component gets clamped, + // so the resulting color looks more orange than red. + mColor *= 2; + for (int i=0; i<3; ++i) + mColor[i] = std::min(1.f, mColor[i]); } virtual void operator ()(osg::Node* node, osg::NodeVisitor* nv) @@ -734,12 +744,10 @@ private: float angleRadians = getAngleToSunInRadians(cv->getCurrentCamera()); float visibleRatio = getVisibleRatio(cv->getCurrentCamera()); - const float angleMaxRadians = osg::DegreesToRadians(30.f); // Sun Glare Fader Angle Max + const float angleMaxRadians = osg::DegreesToRadians(mSunGlareFaderAngleMax); float value = 1.f - std::min(1.f, angleRadians / angleMaxRadians); - - const float sunGlareFaderMax = 0.5f; - float fade = value * sunGlareFaderMax; + float fade = value * mSunGlareFaderMax; fade *= mTimeOfDayFade * mGlareView * visibleRatio; @@ -754,17 +762,8 @@ private: osg::ref_ptr mat (createUnlitMaterial()); - osg::Vec4f sunGlareFaderColor (222/255.f, 95/255.f, 39/255.f, 1); - - // Replicating a design flaw in MW. The color was being set on both ambient and emissive properties, which multiplies the result by two, - // then finally gets clamped by the fixed function pipeline. With the default INI settings, only the red component gets clamped, - // so the resulting color looks more orange than red. - sunGlareFaderColor *= 2; - for (int i=0; i<3; ++i) - sunGlareFaderColor[i] = std::min(1.f, sunGlareFaderColor[i]); - mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0,0,0,fade)); - mat->setEmission(osg::Material::FRONT_AND_BACK, sunGlareFaderColor); + mat->setEmission(osg::Material::FRONT_AND_BACK, mColor); stateset->setAttributeAndModes(mat, osg::StateAttribute::ON); @@ -802,6 +801,9 @@ private: osg::ref_ptr mSunTransform; float mTimeOfDayFade; float mGlareView; + osg::Vec4f mColor; + float mSunGlareFaderMax; + float mSunGlareFaderAngleMax; }; osg::ref_ptr mUpdater; From 773df6fd22e756ec39f0ad516edd47286914eef0 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 13 Oct 2015 16:53:40 +0200 Subject: [PATCH 2268/3725] some OSG fixes --- apps/opencs/view/render/cellarrow.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/render/cellarrow.cpp b/apps/opencs/view/render/cellarrow.cpp index 59460b626..720db5327 100644 --- a/apps/opencs/view/render/cellarrow.cpp +++ b/apps/opencs/view/render/cellarrow.cpp @@ -118,8 +118,9 @@ void CSVRender::CellArrow::buildShape() for (int i=0; i<6; ++i) colours->push_back (osg::Vec4f (0.8f, (i==2 || i==5) ? 0.6f : 0.4f, 0.0f, 1.0f)); - geometry->setColorArray (colours); - geometry->setColorBinding (osg::Geometry::BIND_PER_VERTEX); + geometry->setColorArray (colours, osg::Array::BIND_PER_VERTEX); + + geometry->getOrCreateStateSet()->setMode (GL_LIGHTING, osg::StateAttribute::OFF); osg::ref_ptr geode (new osg::Geode); geode->addDrawable (geometry); From ee450471fdf4dbb276bbf6f3f7e7662237d84652 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 13 Oct 2015 17:55:57 +0200 Subject: [PATCH 2269/3725] Disable head controller for non-bipedal creatures (Fixes #2843, Fixes #2966) --- apps/openmw/mwrender/animation.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 37ec4c213..a0704a59a 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1320,13 +1320,16 @@ namespace MWRender { mHeadController = NULL; - NodeMap::iterator found = mNodeMap.find("bip01 head"); - if (found != mNodeMap.end() && dynamic_cast(found->second.get())) + if (mPtr.getClass().isBipedal(mPtr)) { - osg::Node* node = found->second; - mHeadController = new RotateController(mObjectRoot.get()); - node->addUpdateCallback(mHeadController); - mActiveControllers.insert(std::make_pair(node, mHeadController)); + NodeMap::iterator found = mNodeMap.find("bip01 head"); + if (found != mNodeMap.end() && dynamic_cast(found->second.get())) + { + osg::Node* node = found->second; + mHeadController = new RotateController(mObjectRoot.get()); + node->addUpdateCallback(mHeadController); + mActiveControllers.insert(std::make_pair(node, mHeadController)); + } } } From f36d463617b0b9f29dd9edaf19bb122882b8b7e6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 13 Oct 2015 18:13:52 +0200 Subject: [PATCH 2270/3725] Enchantment error handling fix (Fixes #2959) Catch errors about missing enchantments before they propagate up the stack and interrupt the whole frame update. --- apps/openmw/mwgui/spellmodel.cpp | 11 +++++++++-- apps/openmw/mwworld/inventorystore.cpp | 11 +++++++++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwgui/spellmodel.cpp b/apps/openmw/mwgui/spellmodel.cpp index 91512a011..58ec05794 100644 --- a/apps/openmw/mwgui/spellmodel.cpp +++ b/apps/openmw/mwgui/spellmodel.cpp @@ -1,5 +1,7 @@ #include "spellmodel.hpp" +#include + #include #include "../mwbase/environment.hpp" @@ -79,8 +81,13 @@ namespace MWGui const std::string enchantId = item.getClass().getEnchantment(item); if (enchantId.empty()) continue; - const ESM::Enchantment* enchant = - esmStore.get().find(item.getClass().getEnchantment(item)); + const ESM::Enchantment* enchant = esmStore.get().search(enchantId); + if (!enchant) + { + std::cerr << "Can't find enchantment '" << enchantId << "' on item " << item.getCellRef().getRefId() << std::endl; + continue; + } + if (enchant->mData.mType != ESM::Enchantment::WhenUsed && enchant->mData.mType != ESM::Enchantment::CastOnce) continue; diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 0755c1555..ebba4ae30 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -645,8 +645,15 @@ void MWWorld::InventoryStore::updateRechargingItems() { if (it->getClass().getEnchantment(*it) != "") { - const ESM::Enchantment* enchantment = MWBase::Environment::get().getWorld()->getStore().get().find( - it->getClass().getEnchantment(*it)); + std::string enchantmentId = it->getClass().getEnchantment(*it); + const ESM::Enchantment* enchantment = MWBase::Environment::get().getWorld()->getStore().get().search( + enchantmentId); + if (!enchantment) + { + std::cerr << "Can't find enchantment '" << enchantmentId << "' on item " << it->getCellRef().getRefId() << std::endl; + continue; + } + if (enchantment->mData.mType == ESM::Enchantment::WhenUsed || enchantment->mData.mType == ESM::Enchantment::WhenStrikes) mRechargingItems.push_back(std::make_pair(it, static_cast(enchantment->mData.mCharge))); From 8459a79a2c1da69e3f215fb3d29b4999ad0a8b6f Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 13 Oct 2015 19:05:17 +0200 Subject: [PATCH 2271/3725] Fix AI being able to open locked doors (Fixes #2948) --- apps/openmw/mwmechanics/aipackage.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index 1cd9649f7..bedff8bcd 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -88,7 +88,8 @@ void MWMechanics::AiPackage::evadeObstacles(const MWWorld::Ptr& actor, float dur MWWorld::Ptr door = getNearbyDoor(actor); if (door != MWWorld::Ptr()) // NOTE: checks interior cells only { - if (!door.getCellRef().getTeleport() && door.getCellRef().getTrap().empty() && door.getClass().getDoorState(door) == 0) { //Open the door if untrapped + if (!door.getCellRef().getTeleport() && door.getCellRef().getTrap().empty() + && door.getCellRef().getLockLevel() <= 0 && door.getClass().getDoorState(door) == 0) { MWBase::Environment::get().getWorld()->activateDoor(door, 1); } } From 33e12a99fad15ced87a9996c42ffeb84983be2a4 Mon Sep 17 00:00:00 2001 From: "artemutin@yandex.ru" Date: Sun, 11 Oct 2015 21:49:10 +1000 Subject: [PATCH 2272/3725] If table dont use any filter, filter update now dont cause a reapply of empty filter --- apps/opencs/view/filter/editwidget.cpp | 12 +++++++++++- apps/opencs/view/filter/editwidget.hpp | 1 + 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/apps/opencs/view/filter/editwidget.cpp b/apps/opencs/view/filter/editwidget.cpp index 657a47750..5fbc66464 100644 --- a/apps/opencs/view/filter/editwidget.cpp +++ b/apps/opencs/view/filter/editwidget.cpp @@ -7,7 +7,7 @@ #include "../../model/world/data.hpp" CSVFilter::EditWidget::EditWidget (CSMWorld::Data& data, QWidget *parent) -: QLineEdit (parent), mParser (data) +: QLineEdit (parent), mParser (data), mIsEmpty(true) { mPalette = palette(); connect (this, SIGNAL (textChanged (const QString&)), this, SLOT (textChanged (const QString&))); @@ -27,6 +27,16 @@ CSVFilter::EditWidget::EditWidget (CSMWorld::Data& data, QWidget *parent) void CSVFilter::EditWidget::textChanged (const QString& text) { + //no need to parse and apply filter if it was empty and now is empty too. + //e.g. - we modifiing content of filter with already opened some other (big) tables. + if (text.length() == 0){ + if (mIsEmpty) + return; + else + mIsEmpty = true; + }else + mIsEmpty = false; + if (mParser.parse (text.toUtf8().constData())) { setPalette (mPalette); diff --git a/apps/opencs/view/filter/editwidget.hpp b/apps/opencs/view/filter/editwidget.hpp index a0f9f8919..5c3f1b09e 100644 --- a/apps/opencs/view/filter/editwidget.hpp +++ b/apps/opencs/view/filter/editwidget.hpp @@ -25,6 +25,7 @@ namespace CSVFilter CSMFilter::Parser mParser; QPalette mPalette; + bool mIsEmpty; public: From 361634489ed7a1286919bef02b687fe3682cd619 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 15 Oct 2015 14:46:08 +0200 Subject: [PATCH 2273/3725] properly handle cells that don't exist --- apps/opencs/view/render/cell.cpp | 50 +++++++++++++------ apps/opencs/view/render/cell.hpp | 8 ++- .../view/render/pagedworldspacewidget.cpp | 47 +++++++++++------ 3 files changed, 72 insertions(+), 33 deletions(-) diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index 5ec69a5f2..da40f7e7c 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -51,8 +51,9 @@ bool CSVRender::Cell::addObjects (int start, int end) return modified; } -CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::string& id) -: mData (data), mId (Misc::StringUtils::lowerCase (id)) +CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::string& id, + bool deleted) +: mData (data), mId (Misc::StringUtils::lowerCase (id)), mDeleted (deleted) { std::pair result = CSMWorld::CellCoordinates::fromId (id); @@ -62,24 +63,27 @@ CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::st mCellNode = new osg::Group; rootNode->addChild(mCellNode); - CSMWorld::IdTable& references = dynamic_cast ( - *mData.getTableModel (CSMWorld::UniversalId::Type_References)); - - int rows = references.rowCount(); + if (!mDeleted) + { + CSMWorld::IdTable& references = dynamic_cast ( + *mData.getTableModel (CSMWorld::UniversalId::Type_References)); - addObjects (0, rows-1); + int rows = references.rowCount(); - const CSMWorld::IdCollection& land = mData.getLand(); - int landIndex = land.searchId(mId); - if (landIndex != -1) - { - const ESM::Land& esmLand = land.getRecord(mId).get(); + addObjects (0, rows-1); - if (esmLand.getLandData (ESM::Land::DATA_VHGT)) + const CSMWorld::IdCollection& land = mData.getLand(); + int landIndex = land.searchId(mId); + if (landIndex != -1) { - mTerrain.reset(new Terrain::TerrainGrid(mCellNode, data.getResourceSystem().get(), NULL, new TerrainStorage(mData), Element_Terrain<<1)); - mTerrain->loadCell(esmLand.mX, - esmLand.mY); + const ESM::Land& esmLand = land.getRecord(mId).get(); + + if (esmLand.getLandData (ESM::Land::DATA_VHGT)) + { + mTerrain.reset(new Terrain::TerrainGrid(mCellNode, data.getResourceSystem().get(), NULL, new TerrainStorage(mData), Element_Terrain<<1)); + mTerrain->loadCell(esmLand.mX, + esmLand.mY); + } } } } @@ -125,6 +129,9 @@ bool CSVRender::Cell::referenceableAboutToBeRemoved (const QModelIndex& parent, bool CSVRender::Cell::referenceDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) { + if (mDeleted) + return false; + CSMWorld::IdTable& references = dynamic_cast ( *mData.getTableModel (CSMWorld::UniversalId::Type_References)); @@ -192,6 +199,9 @@ bool CSVRender::Cell::referenceAboutToBeRemoved (const QModelIndex& parent, int if (parent.isValid()) return false; + if (mDeleted) + return false; + CSMWorld::IdTable& references = dynamic_cast ( *mData.getTableModel (CSMWorld::UniversalId::Type_References)); @@ -212,6 +222,9 @@ bool CSVRender::Cell::referenceAdded (const QModelIndex& parent, int start, int if (parent.isValid()) return false; + if (mDeleted) + return false; + return addObjects (start, end); } @@ -258,3 +271,8 @@ CSMWorld::CellCoordinates CSVRender::Cell::getCoordinates() const { return mCoordinates; } + +bool CSVRender::Cell::isDeleted() const +{ + return mDeleted; +} diff --git a/apps/opencs/view/render/cell.hpp b/apps/opencs/view/render/cell.hpp index 7cced4fe3..59f4cafee 100644 --- a/apps/opencs/view/render/cell.hpp +++ b/apps/opencs/view/render/cell.hpp @@ -40,6 +40,7 @@ namespace CSVRender std::auto_ptr mTerrain; CSMWorld::CellCoordinates mCoordinates; std::auto_ptr mCellArrows[4]; + bool mDeleted; /// Ignored if cell does not have an object with the given ID. /// @@ -62,7 +63,10 @@ namespace CSVRender public: - Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::string& id); + /// \note Deleted covers both cells that are deleted and cells that don't exist in + /// the first place. + Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::string& id, + bool deleted = false); ~Cell(); @@ -93,6 +97,8 @@ namespace CSVRender /// Returns 0, 0 in case of an unpaged cell. CSMWorld::CellCoordinates getCoordinates() const; + + bool isDeleted() const; }; } diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index 070ce7d17..dd740ab9a 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -1,5 +1,6 @@ #include "pagedworldspacewidget.hpp" +#include #include #include @@ -26,17 +27,14 @@ bool CSVRender::PagedWorldspaceWidget::adjustCells() const CSMWorld::IdCollection& cells = mDocument.getData().getCells(); { - // remove (or name/region modified) + // remove/update std::map::iterator iter (mCells.begin()); while (iter!=mCells.end()) { - int index = cells.searchId (iter->first.getId (mWorldspace)); - - /// \todo handle cells that don't exist - if (!mSelection.has (iter->first) || index==-1 || - cells.getRecord (index).mState==CSMWorld::RecordBase::State_Deleted) + if (!mSelection.has (iter->first)) { + // remove delete iter->second; mCells.erase (iter++); @@ -44,12 +42,33 @@ bool CSVRender::PagedWorldspaceWidget::adjustCells() } else { - // check if name or region field has changed - // FIXME: config setting - //std::string name = cells.getRecord(index).get().mName; - //std::string region = cells.getRecord(index).get().mRegion; + // update + int index = cells.searchId (iter->first.getId (mWorldspace)); + + bool deleted = index==-1 || + cells.getRecord (index).mState==CSMWorld::RecordBase::State_Deleted; + + if (deleted!=iter->second->isDeleted()) + { + modified = true; - // cell marker update goes here + std::auto_ptr cell (new Cell (mDocument.getData(), mRootNode, + iter->first.getId (mWorldspace), deleted)); + + delete iter->second; + iter->second = cell.release(); + } + else if (!deleted) + { + // delete state has not changed -> just update + + // TODO check if name or region field has changed (cell marker) + // FIXME: config setting + //std::string name = cells.getRecord(index).get().mName; + //std::string region = cells.getRecord(index).get().mRegion; + + modified = true; + } ++iter; } @@ -60,11 +79,7 @@ bool CSVRender::PagedWorldspaceWidget::adjustCells() for (CSMWorld::CellSelection::Iterator iter (mSelection.begin()); iter!=mSelection.end(); ++iter) { - int index = cells.searchId (iter->getId (mWorldspace)); - - /// \todo handle cells that don't exist - if (index > 0 && cells.getRecord (index).mState!=CSMWorld::RecordBase::State_Deleted && - mCells.find (*iter)==mCells.end()) + if (mCells.find (*iter)==mCells.end()) { Cell *cell = new Cell (mDocument.getData(), mRootNode, iter->getId (mWorldspace)); From eae36f800585a9347e778b36a1010b2a05f576c4 Mon Sep 17 00:00:00 2001 From: "artemutin@yandex.ru" Date: Tue, 13 Oct 2015 23:44:23 +1000 Subject: [PATCH 2274/3725] Fixed filter reapplication on Description column change and on State column change. Moved column index search to widget constructor, rewrite slot with respect to multiple columns data change. --- apps/opencs/view/filter/editwidget.cpp | 12 ++++++++++-- apps/opencs/view/filter/editwidget.hpp | 2 ++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/filter/editwidget.cpp b/apps/opencs/view/filter/editwidget.cpp index 5fbc66464..600fa4f3b 100644 --- a/apps/opencs/view/filter/editwidget.cpp +++ b/apps/opencs/view/filter/editwidget.cpp @@ -5,6 +5,8 @@ #include #include "../../model/world/data.hpp" +#include "../../model/world/idtablebase.hpp" +#include "../../model/world/columns.hpp" CSVFilter::EditWidget::EditWidget (CSMWorld::Data& data, QWidget *parent) : QLineEdit (parent), mParser (data), mIsEmpty(true) @@ -12,7 +14,8 @@ CSVFilter::EditWidget::EditWidget (CSMWorld::Data& data, QWidget *parent) mPalette = palette(); connect (this, SIGNAL (textChanged (const QString&)), this, SLOT (textChanged (const QString&))); - QAbstractItemModel *model = data.getTableModel (CSMWorld::UniversalId::Type_Filters); + const CSMWorld::IdTableBase *model = + static_cast (data.getTableModel (CSMWorld::UniversalId::Type_Filters)); connect (model, SIGNAL (dataChanged (const QModelIndex &, const QModelIndex&)), this, SLOT (filterDataChanged (const QModelIndex &, const QModelIndex&)), @@ -23,6 +26,9 @@ CSVFilter::EditWidget::EditWidget (CSMWorld::Data& data, QWidget *parent) connect (model, SIGNAL (rowsInserted (const QModelIndex&, int, int)), this, SLOT (filterRowsInserted (const QModelIndex&, int, int)), Qt::QueuedConnection); + + mStateColumnIndex = model->findColumnIndex(CSMWorld::Columns::ColumnId_Modification); + mDescColumnIndex = model->findColumnIndex(CSMWorld::Columns::ColumnId_Description); } void CSVFilter::EditWidget::textChanged (const QString& text) @@ -55,7 +61,9 @@ void CSVFilter::EditWidget::textChanged (const QString& text) void CSVFilter::EditWidget::filterDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) { - textChanged (text()); + for (int i = topLeft.column(); i <= bottomRight.column(); ++i) + if (i != mStateColumnIndex && i != mDescColumnIndex) + textChanged (text()); } void CSVFilter::EditWidget::filterRowsRemoved (const QModelIndex& parent, int start, int end) diff --git a/apps/opencs/view/filter/editwidget.hpp b/apps/opencs/view/filter/editwidget.hpp index 5c3f1b09e..f672877d9 100644 --- a/apps/opencs/view/filter/editwidget.hpp +++ b/apps/opencs/view/filter/editwidget.hpp @@ -26,6 +26,8 @@ namespace CSVFilter CSMFilter::Parser mParser; QPalette mPalette; bool mIsEmpty; + int mStateColumnIndex; + int mDescColumnIndex; public: From 04df656f54e9eda44cc1ff68b4f23678089d02f1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 18 Oct 2015 21:39:53 +0200 Subject: [PATCH 2275/3725] Remove some junk --- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 993dde6e4..1f06940c6 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -420,7 +420,6 @@ namespace MWDialogue { if(mDialogueMap.find(keyword) != mDialogueMap.end()) { - ESM::Dialogue ndialogue = mDialogueMap[keyword]; if (mDialogueMap[keyword].mType == ESM::Dialogue::Topic) { executeTopic (keyword); From 93565eccbff87bb3ef8beef9da7250611195a825 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 18 Oct 2015 21:40:16 +0200 Subject: [PATCH 2276/3725] Update the dialogue topic list after running greeting script --- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 1f06940c6..f8c9bb38e 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -139,9 +139,6 @@ namespace MWDialogue win->startDialogue(actor, actor.getClass().getName (actor), resetHistory); - //setup the list of topics known by the actor. Topics who are also on the knownTopics list will be added to the GUI - updateTopics(); - //greeting const MWWorld::Store &dialogs = MWBase::Environment::get().getWorld()->getStore().get(); @@ -165,12 +162,19 @@ namespace MWDialogue // TODO play sound } + // first topics update so that parseText knows the keywords to highlight + updateTopics(); + parseText (info->mResponse); MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor); win->addResponse (Interpreter::fixDefinesDialog(info->mResponse, interpreterContext)); executeScript (info->mResultScript); mLastTopic = Misc::StringUtils::lowerCase(it->mId); + + // update topics again to accomodate changes resulting from executeScript + updateTopics(); + return; } } From 2ee6b41887b8dff5231f9925c6a0205a75d67159 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 19 Oct 2015 15:46:53 +0200 Subject: [PATCH 2277/3725] Handle NiAlphaProperty on a drawable basis Removes the RenderBin nesting complication. Also results in leaner StateSets, so the cull phase should be a bit faster. --- components/nifosg/nifloader.cpp | 92 ++++++++++++++++++--------------- 1 file changed, 50 insertions(+), 42 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 75a427c5a..2b73f779f 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -57,8 +57,8 @@ namespace } } - // Collect all properties affecting the given node that should be applied to an osg::Material. - void collectMaterialProperties(const Nif::Node* nifNode, std::vector& out) + // Collect all properties affecting the given drawable that should be handled on drawable basis rather than on the node hierarchy above it. + void collectDrawableProperties(const Nif::Node* nifNode, std::vector& out) { const Nif::PropertyList& props = nifNode->props; for (size_t i = 0; i parent) - collectMaterialProperties(nifNode->parent, out); + collectDrawableProperties(nifNode->parent, out); } class FrameSwitch : public osg::Group @@ -872,9 +873,9 @@ namespace NifOsg osg::ref_ptr geode (new osg::Geode); geode->addDrawable(partsys); - std::vector materialProps; - collectMaterialProperties(nifNode, materialProps); - applyMaterialProperties(parentNode, materialProps, composite, true, animflags); + std::vector drawableProps; + collectDrawableProperties(nifNode, drawableProps); + applyDrawableProperties(parentNode, drawableProps, composite, true, animflags); // Particles don't have normals, so can't be diffuse lit. osg::Material* mat = static_cast(parentNode->getStateSet()->getAttribute(osg::StateAttribute::MATERIAL)); @@ -934,9 +935,9 @@ namespace NifOsg // - if there are no vertex colors, we need to disable colorMode. // - there are 3 "overlapping" nif properties that all affect the osg::Material, handling them // above the actual renderable would be tedious. - std::vector materialProps; - collectMaterialProperties(triShape, materialProps); - applyMaterialProperties(parentNode, materialProps, composite, !data->colors->empty(), animflags); + std::vector drawableProps; + collectDrawableProperties(triShape, drawableProps); + applyDrawableProperties(parentNode, drawableProps, composite, !data->colors->empty(), animflags); } void handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::vector& boundTextures, int animflags) @@ -1223,42 +1224,12 @@ namespace NifOsg case Nif::RC_NiVertexColorProperty: case Nif::RC_NiSpecularProperty: { - // Handled in handleTriShape so we know whether vertex colors are available + // Handled on drawable level so we know whether vertex colors are available break; } case Nif::RC_NiAlphaProperty: { - const Nif::NiAlphaProperty* alphaprop = static_cast(property); - osg::BlendFunc* blendfunc = new osg::BlendFunc; - osg::StateSet* stateset = node->getOrCreateStateSet(); - if (alphaprop->flags&1) - { - blendfunc->setFunction(getBlendMode((alphaprop->flags>>1)&0xf), - getBlendMode((alphaprop->flags>>5)&0xf)); - stateset->setAttributeAndModes(blendfunc, osg::StateAttribute::ON); - - bool noSort = (alphaprop->flags>>13)&1; - if (!noSort) - { - stateset->setNestRenderBins(false); - stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); - } - } - else - { - stateset->setAttributeAndModes(blendfunc, osg::StateAttribute::OFF); - stateset->setNestRenderBins(false); - stateset->setRenderingHint(osg::StateSet::OPAQUE_BIN); - } - - osg::AlphaFunc* alphafunc = new osg::AlphaFunc; - if((alphaprop->flags>>9)&1) - { - alphafunc->setFunction(getTestMode((alphaprop->flags>>10)&0x7), alphaprop->data.threshold/255.f); - stateset->setAttributeAndModes(alphafunc, osg::StateAttribute::ON); - } - else - stateset->setAttributeAndModes(alphafunc, osg::StateAttribute::OFF); + // Handled on drawable level to prevent RenderBin nesting issues break; } case Nif::RC_NiTexturingProperty: @@ -1388,7 +1359,7 @@ namespace NifOsg } } - void applyMaterialProperties(osg::Node* node, const std::vector& properties, SceneUtil::CompositeStateSetUpdater* composite, + void applyDrawableProperties(osg::Node* node, const std::vector& properties, SceneUtil::CompositeStateSetUpdater* composite, bool hasVertexColors, int animflags) { osg::StateSet* stateset = node->getOrCreateStateSet(); @@ -1444,6 +1415,43 @@ namespace NifOsg mat->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE); break; } + break; + } + case Nif::RC_NiAlphaProperty: + { + const Nif::NiAlphaProperty* alphaprop = static_cast(property); + osg::BlendFunc* blendfunc = new osg::BlendFunc; + if (alphaprop->flags&1) + { + blendfunc->setFunction(getBlendMode((alphaprop->flags>>1)&0xf), + getBlendMode((alphaprop->flags>>5)&0xf)); + stateset->setAttributeAndModes(blendfunc, osg::StateAttribute::ON); + + bool noSort = (alphaprop->flags>>13)&1; + if (!noSort) + stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); + else + stateset->setRenderBinToInherit(); + } + else + { + stateset->removeAttribute(osg::StateAttribute::BLENDFUNC); + stateset->removeMode(GL_BLEND); + stateset->setRenderBinToInherit(); + } + + osg::AlphaFunc* alphafunc = new osg::AlphaFunc; + if((alphaprop->flags>>9)&1) + { + alphafunc->setFunction(getTestMode((alphaprop->flags>>10)&0x7), alphaprop->data.threshold/255.f); + stateset->setAttributeAndModes(alphafunc, osg::StateAttribute::ON); + } + else + { + stateset->removeAttribute(osg::StateAttribute::ALPHAFUNC); + stateset->removeMode(GL_ALPHA_TEST); + } + break; } } } From 6ef139e1d7de6f0a952009c523ccfc4ac9d20768 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 19 Oct 2015 22:17:04 +0200 Subject: [PATCH 2278/3725] Implement a custom RenderBin for first person models (Fixes #1612) --- apps/openmw/mwrender/animation.cpp | 17 ++++++++-- apps/openmw/mwrender/animation.hpp | 3 ++ apps/openmw/mwrender/npcanimation.cpp | 48 +++++++++++++++++++++++++++ apps/openmw/mwrender/npcanimation.hpp | 2 ++ apps/openmw/mwrender/renderbin.hpp | 9 ++--- 5 files changed, 72 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index a0704a59a..b2fa87310 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1275,15 +1275,26 @@ namespace MWRender material->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(1,1,1,1)); stateset->setAttributeAndModes(material, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); - stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); - stateset->setRenderBinMode(osg::StateSet::OVERRIDE_RENDERBIN_DETAILS); - stateset->setNestRenderBins(false); mObjectRoot->setStateSet(stateset); } else { mObjectRoot->setStateSet(NULL); } + + setRenderBin(); + } + + void Animation::setRenderBin() + { + if (mAlpha != 1.f) + { + osg::StateSet* stateset = mObjectRoot->getOrCreateStateSet(); + stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); + stateset->setRenderBinMode(osg::StateSet::OVERRIDE_RENDERBIN_DETAILS); + } + else if (osg::StateSet* stateset = mObjectRoot->getStateSet()) + stateset->setRenderBinToInherit(); } void Animation::setLightEffect(float effect) diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 94b792c0d..1e46cc71a 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -307,6 +307,9 @@ protected: void addGlow(osg::ref_ptr node, osg::Vec4f glowColor); + /// Set the render bin for this animation's object root. May be customized by subclasses. + virtual void setRenderBin(); + public: Animation(const MWWorld::Ptr &ptr, osg::ref_ptr parentNode, Resource::ResourceSystem* resourceSystem); diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 99ee886e1..cba6c5696 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -2,6 +2,9 @@ #include #include +#include + +#include #include @@ -28,6 +31,7 @@ #include "camera.hpp" #include "rotatecontroller.hpp" +#include "renderbin.hpp" namespace { @@ -303,6 +307,50 @@ void NpcAnimation::setViewMode(NpcAnimation::ViewMode viewMode) mViewMode = viewMode; rebuild(); + + setRenderBin(); +} + +/// @brief A RenderBin callback to clear the depth buffer before rendering. +class DepthClearCallback : public osgUtil::RenderBin::DrawCallback +{ +public: + DepthClearCallback() + { + mDepth = new osg::Depth; + mDepth->setWriteMask(true); + } + + virtual void drawImplementation(osgUtil::RenderBin* bin, osg::RenderInfo& renderInfo, osgUtil::RenderLeaf*& previous) + { + renderInfo.getState()->applyAttribute(mDepth); + + glClear(GL_DEPTH_BUFFER_BIT); + + bin->drawImplementation(renderInfo, previous); + } + + osg::ref_ptr mDepth; +}; + +void NpcAnimation::setRenderBin() +{ + if (mViewMode == VM_FirstPerson) + { + static bool prototypeAdded = false; + if (!prototypeAdded) + { + osg::ref_ptr depthClearBin (new osgUtil::RenderBin); + depthClearBin->setDrawCallback(new DepthClearCallback); + osgUtil::RenderBin::addRenderBinPrototype("DepthClear", depthClearBin); + prototypeAdded = true; + } + + osg::StateSet* stateset = mObjectRoot->getOrCreateStateSet(); + stateset->setRenderBinDetails(RenderBin_FirstPerson, "DepthClear", osg::StateSet::OVERRIDE_RENDERBIN_DETAILS); + } + else + Animation::setRenderBin(); } void NpcAnimation::rebuild() diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 06f40f847..b4272226d 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -81,6 +81,8 @@ private: void addPartGroup(int group, int priority, const std::vector &parts, bool enchantedGlow=false, osg::Vec4f* glowColor=NULL); + virtual void setRenderBin(); + osg::ref_ptr mFirstPersonNeckController; protected: diff --git a/apps/openmw/mwrender/renderbin.hpp b/apps/openmw/mwrender/renderbin.hpp index 63ccdd259..c14f61142 100644 --- a/apps/openmw/mwrender/renderbin.hpp +++ b/apps/openmw/mwrender/renderbin.hpp @@ -5,14 +5,15 @@ namespace MWRender { /// Defines the render bin numbers used in the OpenMW scene graph. The bin with the lowest number is rendered first. - /// Beware of RenderBin nesting, in most cases you will want to use setNestRenderBins(false). enum RenderBins { RenderBin_Sky = -1, - RenderBin_Default = 0, + RenderBin_Default = 0, // osg::StateSet::OPAQUE_BIN RenderBin_Water = 9, - RenderBin_OcclusionQuery = 10, - RenderBin_SunGlare = 11 + RenderBin_DepthSorted = 10, // osg::StateSet::TRANSPARENT_BIN + RenderBin_OcclusionQuery = 11, + RenderBin_FirstPerson = 12, + RenderBin_SunGlare = 13 }; } From 8552a9d82c8e9f01e9d843745664788f9d460976 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 23 Oct 2015 01:58:22 +0200 Subject: [PATCH 2279/3725] Add multiple camera support to LightManager --- components/sceneutil/lightmanager.cpp | 56 ++++++++++++++------------- components/sceneutil/lightmanager.hpp | 16 +++++--- 2 files changed, 41 insertions(+), 31 deletions(-) diff --git a/components/sceneutil/lightmanager.cpp b/components/sceneutil/lightmanager.cpp index 07ec0aff6..77551e006 100644 --- a/components/sceneutil/lightmanager.cpp +++ b/components/sceneutil/lightmanager.cpp @@ -126,15 +126,13 @@ namespace SceneUtil }; LightManager::LightManager() - : mLightsInViewSpace(false) - , mStartLight(0) + : mStartLight(0) { setUpdateCallback(new LightManagerUpdateCallback); } LightManager::LightManager(const LightManager ©, const osg::CopyOp ©op) : osg::Group(copy, copyop) - , mLightsInViewSpace(false) , mStartLight(copy.mStartLight) { @@ -142,8 +140,8 @@ namespace SceneUtil void LightManager::update() { - mLightsInViewSpace = false; mLights.clear(); + mLightsInViewSpace.clear(); // do an occasional cleanup for orphaned lights if (mStateSetCache.size() > 5000) @@ -161,22 +159,6 @@ namespace SceneUtil mLights.push_back(l); } - void LightManager::prepareForCamera(osg::Camera *cam) - { - // later on we need to store this per camera - if (!mLightsInViewSpace) - { - for (std::vector::iterator it = mLights.begin(); it != mLights.end(); ++it) - { - LightSourceTransform& l = *it; - osg::Matrix worldViewMat = l.mWorldMatrix * cam->getViewMatrix(); - l.mViewBound = osg::BoundingSphere(osg::Vec3f(0,0,0), l.mLightSource->getRadius()); - transformBoundingSphere(worldViewMat, l.mViewBound); - } - mLightsInViewSpace = true; - } - } - osg::ref_ptr LightManager::getLightListStateSet(const LightList &lightList) { // possible optimization: return a StateSet containing all requested lights plus some extra lights (if a suitable one exists) @@ -212,6 +194,30 @@ namespace SceneUtil return mLights; } + const std::vector& LightManager::getLightsInViewSpace(osg::Camera *camera) + { + osg::observer_ptr camPtr (camera); + std::map, LightSourceViewBoundCollection>::iterator it = mLightsInViewSpace.find(camPtr); + + if (it == mLightsInViewSpace.end()) + { + it = mLightsInViewSpace.insert(std::make_pair(camPtr, LightSourceViewBoundCollection())).first; + + for (std::vector::iterator lightIt = mLights.begin(); lightIt != mLights.end(); ++lightIt) + { + osg::Matrix worldViewMat = lightIt->mWorldMatrix * camera->getViewMatrix(); + osg::BoundingSphere viewBound = osg::BoundingSphere(osg::Vec3f(0,0,0), lightIt->mLightSource->getRadius()); + transformBoundingSphere(worldViewMat, viewBound); + + LightSourceViewBound l; + l.mLightSource = lightIt->mLightSource; + l.mViewBound = viewBound; + it->second.push_back(l); + } + } + return it->second; + } + void LightManager::setStartLight(int start) { mStartLight = start; @@ -241,7 +247,7 @@ namespace SceneUtil } - bool sortLights (const LightManager::LightSourceTransform* left, const LightManager::LightSourceTransform* right) + bool sortLights (const LightManager::LightSourceViewBound* left, const LightManager::LightSourceViewBound* right) { return left->mViewBound.center().length2() - left->mViewBound.radius2()/4.f < right->mViewBound.center().length2() - right->mViewBound.radius2()/4.f; } @@ -273,13 +279,11 @@ namespace SceneUtil } } - mLightManager->prepareForCamera(cv->getCurrentCamera()); - // Possible optimizations: // - cull list of lights by the camera frustum // - organize lights in a quad tree - const std::vector& lights = mLightManager->getLights(); + const std::vector& lights = mLightManager->getLightsInViewSpace(cv->getCurrentCamera()); if (lights.size()) { @@ -288,10 +292,10 @@ namespace SceneUtil osg::Matrixf mat = *cv->getModelViewMatrix(); transformBoundingSphere(mat, nodeBound); - std::vector lightList; + LightManager::LightList lightList; for (unsigned int i=0; i& getLights() const; - typedef std::vector LightList; + struct LightSourceViewBound + { + LightSource* mLightSource; + osg::BoundingSphere mViewBound; + }; + + const std::vector& getLightsInViewSpace(osg::Camera* camera); + + typedef std::vector LightList; osg::ref_ptr getLightListStateSet(const LightList& lightList); @@ -98,7 +103,8 @@ namespace SceneUtil // Lights collected from the scene graph. Only valid during the cull traversal. std::vector mLights; - bool mLightsInViewSpace; + typedef std::vector LightSourceViewBoundCollection; + std::map, LightSourceViewBoundCollection> mLightsInViewSpace; // < Light list hash , StateSet > typedef std::map > LightStateSetMap; From 69f234d97b04f2263455a65c221c981f3482cb53 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 23 Oct 2015 16:50:08 +0200 Subject: [PATCH 2280/3725] Small delay before the loading screen shows Kinda irritating to have the loading bar pop up for a fraction of a second. --- apps/openmw/mwgui/loadingscreen.cpp | 74 +++++++++++++++++++---------- apps/openmw/mwgui/loadingscreen.hpp | 1 + 2 files changed, 50 insertions(+), 25 deletions(-) diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index 9b99ad7bf..9afce6873 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -235,40 +235,64 @@ namespace MWGui draw(); } - void LoadingScreen::draw() + bool LoadingScreen::needToDrawLoadingScreen() { - if (mTimer.time_m() > mLastRenderTime + (1.0/mTargetFrameRate) * 1000.0) + if ( mTimer.time_m() <= mLastRenderTime + (1.0/mTargetFrameRate) * 1000.0) + return false; + + // the minimal delay before a loading screen shows + const float initialDelay = 0.05; + + bool alreadyShown = (mLastRenderTime > mLoadingOnTime); + float diff = (mTimer.time_m() - mLoadingOnTime); + + if (!alreadyShown) { - bool showWallpaper = (MWBase::Environment::get().getStateManager()->getState() - == MWBase::StateManager::State_NoGame); + // bump the delay by the current progress - i.e. if during the initial delay the loading + // has almost finished, no point showing the loading screen now + diff -= mProgress / static_cast(mProgressBar->getScrollRange()) * 100.f; + } - if (showWallpaper && mTimer.time_m() > mLastWallpaperChangeTime + 5000*1) - { - mLastWallpaperChangeTime = mTimer.time_m(); - changeWallpaper(); - } + bool showWallpaper = (MWBase::Environment::get().getStateManager()->getState() + == MWBase::StateManager::State_NoGame); + if (!showWallpaper && diff < initialDelay*1000) + return false; + return true; + } - // Turn off rendering except the GUI - int oldUpdateMask = mViewer->getUpdateVisitor()->getTraversalMask(); - int oldCullMask = mViewer->getCamera()->getCullMask(); - mViewer->getUpdateVisitor()->setTraversalMask(MWRender::Mask_GUI); - mViewer->getCamera()->setCullMask(MWRender::Mask_GUI); + void LoadingScreen::draw() + { + if (!needToDrawLoadingScreen()) + return; + + bool showWallpaper = (MWBase::Environment::get().getStateManager()->getState() + == MWBase::StateManager::State_NoGame); + if (showWallpaper && mTimer.time_m() > mLastWallpaperChangeTime + 5000*1) + { + mLastWallpaperChangeTime = mTimer.time_m(); + changeWallpaper(); + } - MWBase::Environment::get().getInputManager()->update(0, true, true); + // Turn off rendering except the GUI + int oldUpdateMask = mViewer->getUpdateVisitor()->getTraversalMask(); + int oldCullMask = mViewer->getCamera()->getCullMask(); + mViewer->getUpdateVisitor()->setTraversalMask(MWRender::Mask_GUI); + mViewer->getCamera()->setCullMask(MWRender::Mask_GUI); - //osg::Timer timer; - mViewer->frame(mViewer->getFrameStamp()->getSimulationTime()); - //std::cout << "frame took " << timer.time_m() << std::endl; + MWBase::Environment::get().getInputManager()->update(0, true, true); - //if (mViewer->getIncrementalCompileOperation()) - //std::cout << "num to compile " << mViewer->getIncrementalCompileOperation()->getToCompile().size() << std::endl; + //osg::Timer timer; + mViewer->frame(mViewer->getFrameStamp()->getSimulationTime()); + //std::cout << "frame took " << timer.time_m() << std::endl; - // resume 3d rendering - mViewer->getUpdateVisitor()->setTraversalMask(oldUpdateMask); - mViewer->getCamera()->setCullMask(oldCullMask); + //if (mViewer->getIncrementalCompileOperation()) + //std::cout << "num to compile " << mViewer->getIncrementalCompileOperation()->getToCompile().size() << std::endl; - mLastRenderTime = mTimer.time_m(); - } + // resume 3d rendering + mViewer->getUpdateVisitor()->setTraversalMask(oldUpdateMask); + mViewer->getCamera()->setCullMask(oldCullMask); + + mLastRenderTime = mTimer.time_m(); } } diff --git a/apps/openmw/mwgui/loadingscreen.hpp b/apps/openmw/mwgui/loadingscreen.hpp index 194535eee..f0f354223 100644 --- a/apps/openmw/mwgui/loadingscreen.hpp +++ b/apps/openmw/mwgui/loadingscreen.hpp @@ -52,6 +52,7 @@ namespace MWGui private: void findSplashScreens(); + bool needToDrawLoadingScreen(); const VFS::Manager* mVFS; osg::ref_ptr mViewer; From 6dff11f8475c7dbc5aea5d7307e79d5e8d807e98 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 23 Oct 2015 18:16:26 +0200 Subject: [PATCH 2281/3725] Duplicate code fix --- components/sceneutil/lightmanager.cpp | 29 ++++++++++++--------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/components/sceneutil/lightmanager.cpp b/components/sceneutil/lightmanager.cpp index 77551e006..92fa83537 100644 --- a/components/sceneutil/lightmanager.cpp +++ b/components/sceneutil/lightmanager.cpp @@ -64,6 +64,16 @@ namespace SceneUtil std::vector > mLights; }; + LightManager* findLightManager(const osg::NodePath& path) + { + for (unsigned int i=0;i(path[i])) + return lightManager; + } + return NULL; + } + // Set on a LightSource. Adds the light source to its light manager for the current frame. // This allows us to keep track of the current lights in the scene graph without tying creation & destruction to the manager. class CollectLightCallback : public osg::NodeCallback @@ -82,14 +92,8 @@ namespace SceneUtil { if (!mLightManager) { - for (unsigned int i=0;igetNodePath().size(); ++i) - { - if (LightManager* lightManager = dynamic_cast(nv->getNodePath()[i])) - { - mLightManager = lightManager; - break; - } - } + mLightManager = findLightManager(nv->getNodePath()); + if (!mLightManager) throw std::runtime_error("can't find parent LightManager"); } @@ -264,14 +268,7 @@ namespace SceneUtil if (!mLightManager) { - for (unsigned int i=0;igetNodePath().size(); ++i) - { - if (LightManager* lightManager = dynamic_cast(nv->getNodePath()[i])) - { - mLightManager = lightManager; - break; - } - } + mLightManager = findLightManager(nv->getNodePath()); if (!mLightManager) { traverse(node, nv); From 49df6b7450cc46e6d895d58d0a7a0701a5513f52 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 23 Oct 2015 21:25:56 +0200 Subject: [PATCH 2282/3725] LightManager: fix incorrect view matrix for RELATIVE_RF cameras --- components/sceneutil/lightmanager.cpp | 9 ++++++--- components/sceneutil/lightmanager.hpp | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/components/sceneutil/lightmanager.cpp b/components/sceneutil/lightmanager.cpp index 92fa83537..18d7ddd46 100644 --- a/components/sceneutil/lightmanager.cpp +++ b/components/sceneutil/lightmanager.cpp @@ -198,7 +198,7 @@ namespace SceneUtil return mLights; } - const std::vector& LightManager::getLightsInViewSpace(osg::Camera *camera) + const std::vector& LightManager::getLightsInViewSpace(osg::Camera *camera, const osg::RefMatrix* viewMatrix) { osg::observer_ptr camPtr (camera); std::map, LightSourceViewBoundCollection>::iterator it = mLightsInViewSpace.find(camPtr); @@ -209,7 +209,7 @@ namespace SceneUtil for (std::vector::iterator lightIt = mLights.begin(); lightIt != mLights.end(); ++lightIt) { - osg::Matrix worldViewMat = lightIt->mWorldMatrix * camera->getViewMatrix(); + osg::Matrix worldViewMat = lightIt->mWorldMatrix * (*viewMatrix); osg::BoundingSphere viewBound = osg::BoundingSphere(osg::Vec3f(0,0,0), lightIt->mLightSource->getRadius()); transformBoundingSphere(worldViewMat, viewBound); @@ -280,7 +280,10 @@ namespace SceneUtil // - cull list of lights by the camera frustum // - organize lights in a quad tree - const std::vector& lights = mLightManager->getLightsInViewSpace(cv->getCurrentCamera()); + // Don't use Camera::getViewMatrix, that one might be relative to another camera! + const osg::RefMatrix* viewMatrix = cv->getCurrentRenderStage()->getInitialViewMatrix(); + + const std::vector& lights = mLightManager->getLightsInViewSpace(cv->getCurrentCamera(), viewMatrix); if (lights.size()) { diff --git a/components/sceneutil/lightmanager.hpp b/components/sceneutil/lightmanager.hpp index 454eeeefe..3e0329c8b 100644 --- a/components/sceneutil/lightmanager.hpp +++ b/components/sceneutil/lightmanager.hpp @@ -88,7 +88,7 @@ namespace SceneUtil osg::BoundingSphere mViewBound; }; - const std::vector& getLightsInViewSpace(osg::Camera* camera); + const std::vector& getLightsInViewSpace(osg::Camera* camera, const osg::RefMatrix* viewMatrix); typedef std::vector LightList; From ef5838df7eb70fb9eddeef448244171dac548caa Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 24 Oct 2015 15:46:15 +0200 Subject: [PATCH 2283/3725] SunGlareCallback: Fix incorrect view matrix for RELATIVE_RF cameras --- apps/openmw/mwrender/sky.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index a8aeeb930..8de8a61fc 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -741,7 +741,7 @@ private: { osgUtil::CullVisitor* cv = static_cast(nv); - float angleRadians = getAngleToSunInRadians(cv->getCurrentCamera()); + float angleRadians = getAngleToSunInRadians(*cv->getCurrentRenderStage()->getInitialViewMatrix()); float visibleRatio = getVisibleRatio(cv->getCurrentCamera()); const float angleMaxRadians = osg::DegreesToRadians(mSunGlareFaderAngleMax); @@ -784,10 +784,10 @@ private: } private: - float getAngleToSunInRadians(osg::Camera* camera) const + float getAngleToSunInRadians(const osg::Matrix& viewMatrix) const { osg::Vec3d eye, center, up; - camera->getViewMatrixAsLookAt(eye, center, up); + viewMatrix.getLookAt(eye, center, up); osg::Vec3d forward = center - eye; osg::Vec3d sun = mSunTransform->getPosition(); From 7b954e8cc30bbceb33bacfea42726694d40807ed Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 24 Oct 2015 16:04:08 +0200 Subject: [PATCH 2284/3725] Remove unnecessary dependency on MWScrollBar --- apps/openmw/mwgui/waitdialog.hpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/apps/openmw/mwgui/waitdialog.hpp b/apps/openmw/mwgui/waitdialog.hpp index e8f58c574..13df1f8ae 100644 --- a/apps/openmw/mwgui/waitdialog.hpp +++ b/apps/openmw/mwgui/waitdialog.hpp @@ -8,11 +8,6 @@ namespace MWGui { - namespace Widgets - { - class MWScrollBar; - } - class WaitDialogProgressBar : public WindowBase { public: @@ -51,7 +46,7 @@ namespace MWGui MyGUI::Button* mUntilHealedButton; MyGUI::Button* mWaitButton; MyGUI::Button* mCancelButton; - MWGui::Widgets::MWScrollBar* mHourSlider; + MyGUI::ScrollBar* mHourSlider; TimeAdvancer mTimeAdvancer; bool mSleeping; From e34af4c4b5fe860c033dd4f55cd7aae0279d4bbc Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 25 Oct 2015 15:16:22 +0100 Subject: [PATCH 2285/3725] handle primary and secondary edit button clicks on cell arrows --- apps/opencs/view/render/cellarrow.cpp | 5 + apps/opencs/view/render/cellarrow.hpp | 2 + .../view/render/pagedworldspacewidget.cpp | 142 +++++++++++++++++- .../view/render/pagedworldspacewidget.hpp | 16 ++ apps/opencs/view/render/worldspacewidget.cpp | 21 ++- apps/opencs/view/render/worldspacewidget.hpp | 3 + 6 files changed, 177 insertions(+), 12 deletions(-) diff --git a/apps/opencs/view/render/cellarrow.cpp b/apps/opencs/view/render/cellarrow.cpp index 720db5327..fce5ffda5 100644 --- a/apps/opencs/view/render/cellarrow.cpp +++ b/apps/opencs/view/render/cellarrow.cpp @@ -154,3 +154,8 @@ CSMWorld::CellCoordinates CSVRender::CellArrow::getCoordinates() const { return mCoordinates; } + +CSVRender::CellArrow::Direction CSVRender::CellArrow::getDirection() const +{ + return mDirection; +} diff --git a/apps/opencs/view/render/cellarrow.hpp b/apps/opencs/view/render/cellarrow.hpp index 4422ec890..cbbcc9d5e 100644 --- a/apps/opencs/view/render/cellarrow.hpp +++ b/apps/opencs/view/render/cellarrow.hpp @@ -64,6 +64,8 @@ namespace CSVRender ~CellArrow(); CSMWorld::CellCoordinates getCoordinates() const; + + Direction getDirection() const; }; } diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index dd740ab9a..6e5c2587d 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -4,6 +4,7 @@ #include #include +#include #include @@ -81,10 +82,7 @@ bool CSVRender::PagedWorldspaceWidget::adjustCells() { if (mCells.find (*iter)==mCells.end()) { - Cell *cell = new Cell (mDocument.getData(), mRootNode, - iter->getId (mWorldspace)); - mCells.insert (std::make_pair (*iter, cell)); - + addCellToScene (*iter); modified = true; } } @@ -152,6 +150,76 @@ void CSVRender::PagedWorldspaceWidget::addEditModeSelectorButtons ( "terrain-move"); } +void CSVRender::PagedWorldspaceWidget::handleMouseClick (osg::ref_ptr tag, const std::string& button) +{ + if (tag && tag->getElement()==Element_CellArrow) + { + if (button=="p-edit" || button=="s-edit") + { + if (CellArrowTag *cellArrowTag = + dynamic_cast (tag.get())) + { + CellArrow *arrow = cellArrowTag->getCellArrow(); + + CSMWorld::CellCoordinates coordinates = arrow->getCoordinates(); + + CellArrow::Direction direction = arrow->getDirection(); + + int x = 0; + int y = 0; + + switch (direction) + { + case CellArrow::Direction_North: y = 1; break; + case CellArrow::Direction_West: x = -1; break; + case CellArrow::Direction_South: y = -1; break; + case CellArrow::Direction_East: x = 1; break; + } + + bool modified = false; + + if (QApplication::keyboardModifiers() & Qt::ShiftModifier) + { + if (button=="p-edit") + addCellSelection (x, y); + else + moveCellSelection (x, y); + + modified = true; + } + else + { + CSMWorld::CellCoordinates newCoordinates = coordinates.move (x, y); + + if (mCells.find (newCoordinates)==mCells.end()) + { + addCellToScene (newCoordinates); + mSelection.add (newCoordinates); + modified = true; + } + + if (button=="s-edit") + { + if (mCells.find (coordinates)!=mCells.end()) + { + removeCellFromScene (coordinates); + mSelection.remove (coordinates); + modified = true; + } + } + } + + if (modified) + adjustCells(); + + return; + } + } + } + + WorldspaceWidget::handleMouseClick (tag, button); +} + void CSVRender::PagedWorldspaceWidget::referenceableDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) { @@ -231,6 +299,72 @@ std::string CSVRender::PagedWorldspaceWidget::getStartupInstruction() return stream.str(); } +void CSVRender::PagedWorldspaceWidget::addCellToScene ( + const CSMWorld::CellCoordinates& coordinates) +{ + const CSMWorld::IdCollection& cells = mDocument.getData().getCells(); + + int index = cells.searchId (coordinates.getId (mWorldspace)); + + bool deleted = index==-1 || + cells.getRecord (index).mState==CSMWorld::RecordBase::State_Deleted; + + Cell *cell = new Cell (mDocument.getData(), mRootNode, coordinates.getId (mWorldspace), + deleted); + + mCells.insert (std::make_pair (coordinates, cell)); +} + +void CSVRender::PagedWorldspaceWidget::removeCellFromScene ( + const CSMWorld::CellCoordinates& coordinates) +{ + std::map::iterator iter = mCells.find (coordinates); + + if (iter!=mCells.end()) + { + delete iter->second; + mCells.erase (iter); + } +} + +void CSVRender::PagedWorldspaceWidget::addCellSelection (int x, int y) +{ + CSMWorld::CellSelection newSelection = mSelection; + newSelection.move (x, y); + + for (CSMWorld::CellSelection::Iterator iter (newSelection.begin()); iter!=newSelection.end(); + ++iter) + { + if (mCells.find (*iter)==mCells.end()) + { + addCellToScene (*iter); + mSelection.add (*iter); + } + } +} + +void CSVRender::PagedWorldspaceWidget::moveCellSelection (int x, int y) +{ + CSMWorld::CellSelection newSelection = mSelection; + newSelection.move (x, y); + + for (CSMWorld::CellSelection::Iterator iter (mSelection.begin()); iter!=mSelection.end(); + ++iter) + { + if (!newSelection.has (*iter)) + removeCellFromScene (*iter); + } + + for (CSMWorld::CellSelection::Iterator iter (newSelection.begin()); iter!=newSelection.end(); + ++iter) + { + if (!mSelection.has (*iter)) + addCellToScene (*iter); + } + + mSelection = newSelection; +} + CSVRender::PagedWorldspaceWidget::PagedWorldspaceWidget (QWidget* parent, CSMDoc::Document& document) : WorldspaceWidget (document, parent), mDocument (document), mWorldspace ("std::default"), mControlElements(NULL), mDisplayCellCoord(true) diff --git a/apps/opencs/view/render/pagedworldspacewidget.hpp b/apps/opencs/view/render/pagedworldspacewidget.hpp index d52efd90e..e1a43ba7c 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.hpp +++ b/apps/opencs/view/render/pagedworldspacewidget.hpp @@ -53,6 +53,20 @@ namespace CSVRender virtual std::string getStartupInstruction(); + /// \note Does not update the view or any cell marker + void addCellToScene (const CSMWorld::CellCoordinates& coordinates); + + /// \note Does not update the view or any cell marker + /// + /// \note Calling this function for a cell that is not in the selection is a no-op. + void removeCellFromScene (const CSMWorld::CellCoordinates& coordinates); + + /// \note Does not update the view or any cell marker + void addCellSelection (int x, int y); + + /// \note Does not update the view or any cell marker + void moveCellSelection (int x, int y); + public: PagedWorldspaceWidget (QWidget *parent, CSMDoc::Document& document); @@ -88,6 +102,8 @@ namespace CSVRender virtual void addEditModeSelectorButtons (CSVWidget::SceneToolMode *tool); + virtual void handleMouseClick (osg::ref_ptr tag, const std::string& button); + signals: void cellSelectionChanged (const CSMWorld::CellSelection& selection); diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 75dd800eb..a542a3c59 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -574,14 +574,7 @@ void CSVRender::WorldspaceWidget::mousePressEvent (QMouseEvent *event) { osg::ref_ptr tag = mousePick (event); - EditMode& editMode = dynamic_cast (*mEditMode->getCurrent()); - - if (button=="p-edit") - editMode.primaryEditPressed (tag); - else if (button=="s-edit") - editMode.secondaryEditPressed (tag); - else if (button=="select") - editMode.selectPressed (tag); + handleMouseClick (tag, button); } } @@ -650,3 +643,15 @@ void CSVRender::WorldspaceWidget::keyPressEvent (QKeyEvent *event) else RenderWidget::keyPressEvent(event); } + +void CSVRender::WorldspaceWidget::handleMouseClick (osg::ref_ptr tag, const std::string& button) +{ + EditMode& editMode = dynamic_cast (*mEditMode->getCurrent()); + + if (button=="p-edit") + editMode.primaryEditPressed (tag); + else if (button=="s-edit") + editMode.secondaryEditPressed (tag); + else if (button=="select") + editMode.selectPressed (tag); +} diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp index f5e7970b6..fe766cf87 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -27,6 +27,7 @@ namespace CSVWidget namespace CSVRender { class TagBase; + class CellArrow; class WorldspaceWidget : public SceneWidget { @@ -132,6 +133,8 @@ namespace CSVRender virtual void wheelEvent (QWheelEvent *event); virtual void keyPressEvent (QKeyEvent *event); + virtual void handleMouseClick (osg::ref_ptr tag, const std::string& button); + private: void dragEnterEvent(QDragEnterEvent *event); From 515c52211e9bce049d6412e8e434ce7c907ca8ad Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 25 Oct 2015 18:28:50 +0100 Subject: [PATCH 2286/3725] Disable mipmaps for temporary screenshot texture --- apps/openmw/mwrender/renderingmanager.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index f4b8aa451..cae6541af 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -493,6 +493,8 @@ namespace MWRender texture->setInternalFormat(GL_RGB); texture->setTextureSize(w, h); texture->setResizeNonPowerOfTwoHint(false); + texture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR); + texture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); rttCamera->attach(osg::Camera::COLOR_BUFFER, texture); image->setDataType(GL_UNSIGNED_BYTE); From 944e6d0844158d67c3a6041db1b29c4685ef2797 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 26 Oct 2015 14:25:44 +0100 Subject: [PATCH 2287/3725] Fix adjustment of inventory preview size when guimode changes (Fixes #2973) --- apps/openmw/mwgui/inventorywindow.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index f5a5f023f..c1e202bc0 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -167,11 +167,12 @@ namespace MWGui MyGUI::IntSize size(static_cast(Settings::Manager::getFloat(setting + " w", "Windows") * viewSize.width), static_cast(Settings::Manager::getFloat(setting + " h", "Windows") * viewSize.height)); + mMainWidget->setPosition(pos); + mMainWidget->setSize(size); + if (size.width != mMainWidget->getWidth() || size.height != mMainWidget->getHeight()) updatePreviewSize(); - mMainWidget->setPosition(pos); - mMainWidget->setSize(size); adjustPanes(); } From f3ee3f5be1d529698177655ebc6103a8f9847cde Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 27 Oct 2015 15:25:46 +0100 Subject: [PATCH 2288/3725] Do not call base class event functions in WorldspaceWidget This avoids some event function being triggered twice. I do not fully understand why calling the base class function causes this problem, which is more than a bit disconcerting, but let's roll with it for now. --- apps/opencs/view/render/worldspacewidget.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index a542a3c59..e539c14b9 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -555,8 +555,6 @@ void CSVRender::WorldspaceWidget::mouseMoveEvent (QMouseEvent *event) editMode.drag (diffX, diffY, factor); } - - RenderWidget::mouseMoveEvent(event); } void CSVRender::WorldspaceWidget::mousePressEvent (QMouseEvent *event) @@ -598,8 +596,6 @@ void CSVRender::WorldspaceWidget::mouseReleaseEvent (QMouseEvent *event) } mDragMode.clear(); - - RenderWidget::mouseReleaseEvent(event); } void CSVRender::WorldspaceWidget::mouseDoubleClickEvent (QMouseEvent *event) @@ -608,7 +604,6 @@ void CSVRender::WorldspaceWidget::mouseDoubleClickEvent (QMouseEvent *event) { //mMouse->mouseDoubleClickEvent(event); } - //SceneWidget::mouseDoubleClickEvent(event); } void CSVRender::WorldspaceWidget::wheelEvent (QWheelEvent *event) @@ -624,8 +619,6 @@ void CSVRender::WorldspaceWidget::wheelEvent (QWheelEvent *event) editMode.dragWheel (event->delta(), factor); } - - RenderWidget::wheelEvent(event); } void CSVRender::WorldspaceWidget::keyPressEvent (QKeyEvent *event) From d2e92fd36f8bd6bb54724abf36acd918edcf6875 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 27 Oct 2015 15:30:51 +0100 Subject: [PATCH 2289/3725] trigger mouse click actions on release instead of on press (avoids problems with dragging) --- apps/opencs/view/render/worldspacewidget.cpp | 28 +++++++++++--------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index e539c14b9..3f4b77383 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -563,25 +563,14 @@ void CSVRender::WorldspaceWidget::mousePressEvent (QMouseEvent *event) if (!mDragging) mDragMode = button; - - if (button=="p-navi" || button=="s-navi") - { - - } - else if (button=="p-edit" || button=="s-edit" || button=="select") - { - osg::ref_ptr tag = mousePick (event); - - handleMouseClick (tag, button); - } } void CSVRender::WorldspaceWidget::mouseReleaseEvent (QMouseEvent *event) { + std::string button = mapButton (event); + if (mDragging) { - std::string button = mapButton (event); - if (mDragMode=="p-navi" || mDragMode=="s-navi") { @@ -594,6 +583,19 @@ void CSVRender::WorldspaceWidget::mouseReleaseEvent (QMouseEvent *event) mDragging = false; } } + else + { + if (button=="p-navi" || button=="s-navi") + { + + } + else if (button=="p-edit" || button=="s-edit" || button=="select") + { + osg::ref_ptr tag = mousePick (event); + + handleMouseClick (tag, button); + } + } mDragMode.clear(); } From 843225996cc4d8573be7d4a70b71333ab2baf319 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 27 Oct 2015 15:43:52 +0100 Subject: [PATCH 2290/3725] get modifiers from event instead of from the application --- apps/opencs/view/render/pagedworldspacewidget.cpp | 6 +++--- apps/opencs/view/render/pagedworldspacewidget.hpp | 2 +- apps/opencs/view/render/worldspacewidget.cpp | 10 +++++----- apps/opencs/view/render/worldspacewidget.hpp | 3 ++- 4 files changed, 11 insertions(+), 10 deletions(-) diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index 6e5c2587d..dae5990e6 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -150,7 +150,7 @@ void CSVRender::PagedWorldspaceWidget::addEditModeSelectorButtons ( "terrain-move"); } -void CSVRender::PagedWorldspaceWidget::handleMouseClick (osg::ref_ptr tag, const std::string& button) +void CSVRender::PagedWorldspaceWidget::handleMouseClick (osg::ref_ptr tag, const std::string& button, bool shift) { if (tag && tag->getElement()==Element_CellArrow) { @@ -178,7 +178,7 @@ void CSVRender::PagedWorldspaceWidget::handleMouseClick (osg::ref_ptr t bool modified = false; - if (QApplication::keyboardModifiers() & Qt::ShiftModifier) + if (shift) { if (button=="p-edit") addCellSelection (x, y); @@ -217,7 +217,7 @@ void CSVRender::PagedWorldspaceWidget::handleMouseClick (osg::ref_ptr t } } - WorldspaceWidget::handleMouseClick (tag, button); + WorldspaceWidget::handleMouseClick (tag, button, shift); } void CSVRender::PagedWorldspaceWidget::referenceableDataChanged (const QModelIndex& topLeft, diff --git a/apps/opencs/view/render/pagedworldspacewidget.hpp b/apps/opencs/view/render/pagedworldspacewidget.hpp index e1a43ba7c..e983fddd5 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.hpp +++ b/apps/opencs/view/render/pagedworldspacewidget.hpp @@ -102,7 +102,7 @@ namespace CSVRender virtual void addEditModeSelectorButtons (CSVWidget::SceneToolMode *tool); - virtual void handleMouseClick (osg::ref_ptr tag, const std::string& button); + virtual void handleMouseClick (osg::ref_ptr tag, const std::string& button, bool shift); signals: diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 3f4b77383..46c5867eb 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -413,7 +413,7 @@ osg::ref_ptr CSVRender::WorldspaceWidget::mousePick (QMouseE std::string CSVRender::WorldspaceWidget::mapButton (QMouseEvent *event) { std::pair phyiscal ( - event->button(), QApplication::keyboardModifiers() & Qt::ControlModifier); + event->button(), event->modifiers() & Qt::ControlModifier); std::map, std::string>::const_iterator iter = mButtonMapping.find (phyiscal); @@ -548,7 +548,7 @@ void CSVRender::WorldspaceWidget::mouseMoveEvent (QMouseEvent *event) double factor = mDragFactor; - if (QApplication::keyboardModifiers() & Qt::ShiftModifier) + if (event->modifiers() & Qt::ShiftModifier) factor *= mDragShiftFactor; EditMode& editMode = dynamic_cast (*mEditMode->getCurrent()); @@ -593,7 +593,7 @@ void CSVRender::WorldspaceWidget::mouseReleaseEvent (QMouseEvent *event) { osg::ref_ptr tag = mousePick (event); - handleMouseClick (tag, button); + handleMouseClick (tag, button, event->modifiers() & Qt::ShiftModifier); } } @@ -614,7 +614,7 @@ void CSVRender::WorldspaceWidget::wheelEvent (QWheelEvent *event) { double factor = mDragWheelFactor; - if (QApplication::keyboardModifiers() & Qt::ShiftModifier) + if (event->modifiers() & Qt::ShiftModifier) factor *= mDragShiftFactor; EditMode& editMode = dynamic_cast (*mEditMode->getCurrent()); @@ -639,7 +639,7 @@ void CSVRender::WorldspaceWidget::keyPressEvent (QKeyEvent *event) RenderWidget::keyPressEvent(event); } -void CSVRender::WorldspaceWidget::handleMouseClick (osg::ref_ptr tag, const std::string& button) +void CSVRender::WorldspaceWidget::handleMouseClick (osg::ref_ptr tag, const std::string& button, bool shift) { EditMode& editMode = dynamic_cast (*mEditMode->getCurrent()); diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp index fe766cf87..c2d61e75b 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -133,7 +133,8 @@ namespace CSVRender virtual void wheelEvent (QWheelEvent *event); virtual void keyPressEvent (QKeyEvent *event); - virtual void handleMouseClick (osg::ref_ptr tag, const std::string& button); + virtual void handleMouseClick (osg::ref_ptr tag, const std::string& button, + bool shift); private: From 9f0e059a15106eb5fa8f1174eadd91076623e7d3 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Wed, 28 Oct 2015 11:18:48 +1100 Subject: [PATCH 2291/3725] Fix editing ingredient effects sub-table. Should resolve bug #2978. --- apps/opencs/model/world/refidadapterimp.cpp | 127 ++++++++++++++++++++ apps/opencs/model/world/refidadapterimp.hpp | 60 +++++++++ apps/opencs/model/world/refidcollection.cpp | 17 ++- 3 files changed, 203 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index da0cc0760..d4fa91bd5 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -52,6 +52,133 @@ void CSMWorld::PotionRefIdAdapter::setData (const RefIdColumn *column, RefIdData } +CSMWorld::IngredientColumns::IngredientColumns (const InventoryColumns& columns) +: InventoryColumns (columns) {} + +CSMWorld::IngredientRefIdAdapter::IngredientRefIdAdapter (const IngredientColumns& columns) +: InventoryRefIdAdapter (UniversalId::Type_Ingredient, columns), + mColumns(columns) +{} + +QVariant CSMWorld::IngredientRefIdAdapter::getData (const RefIdColumn *column, const RefIdData& data, + int index) const +{ + const Record& record = static_cast&> ( + data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Ingredient))); + + if (column==mColumns.mEffects) + return true; // to show nested tables in dialogue subview, see IdTree::hasChildren() + + return InventoryRefIdAdapter::getData (column, data, index); +} + +void CSMWorld::IngredientRefIdAdapter::setData (const RefIdColumn *column, RefIdData& data, int index, + const QVariant& value) const +{ + InventoryRefIdAdapter::setData (column, data, index, value); + + return; +} + + +CSMWorld::IngredEffectRefIdAdapter::IngredEffectRefIdAdapter() +: mType(UniversalId::Type_Ingredient) +{} + +CSMWorld::IngredEffectRefIdAdapter::~IngredEffectRefIdAdapter() +{} + +void CSMWorld::IngredEffectRefIdAdapter::addNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int position) const +{ + // Do nothing, this table cannot be changed by the user +} + +void CSMWorld::IngredEffectRefIdAdapter::removeNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int rowToRemove) const +{ + // Do nothing, this table cannot be changed by the user +} + +void CSMWorld::IngredEffectRefIdAdapter::setNestedTable (const RefIdColumn* column, + RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const +{ + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + ESM::Ingredient ingredient = record.get(); + + ingredient.mData = + static_cast >&>(nestedTable).mNestedTable.at(0); + + record.setModified (ingredient); +} + +CSMWorld::NestedTableWrapperBase* CSMWorld::IngredEffectRefIdAdapter::nestedTable (const RefIdColumn* column, + const RefIdData& data, int index) const +{ + const Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + + // return the whole struct + std::vector wrap; + wrap.push_back(record.get().mData); + + // deleted by dtor of NestedTableStoring + return new NestedTableWrapper >(wrap); +} + +QVariant CSMWorld::IngredEffectRefIdAdapter::getNestedData (const RefIdColumn *column, + const RefIdData& data, int index, int subRowIndex, int subColIndex) const +{ + const Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + + if (subRowIndex < 0 || subRowIndex >= 4) + throw std::runtime_error ("index out of range"); + + switch (subColIndex) + { + case 0: return record.get().mData.mEffectID[subRowIndex]; + case 1: return record.get().mData.mSkills[subRowIndex]; + case 2: return record.get().mData.mAttributes[subRowIndex]; + default: + throw std::runtime_error("Trying to access non-existing column in the nested table!"); + } +} + +void CSMWorld::IngredEffectRefIdAdapter::setNestedData (const RefIdColumn *column, + RefIdData& data, int row, const QVariant& value, int subRowIndex, int subColIndex) const +{ + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (row, mType))); + ESM::Ingredient ingredient = record.get(); + + if (subRowIndex < 0 || subRowIndex >= 4) + throw std::runtime_error ("index out of range"); + + switch(subColIndex) + { + case 0: ingredient.mData.mEffectID[subRowIndex] = value.toInt(); break; + case 1: ingredient.mData.mSkills[subRowIndex] = value.toInt(); break; + case 2: ingredient.mData.mAttributes[subRowIndex] = value.toInt(); break; + default: + throw std::runtime_error("Trying to access non-existing column in the nested table!"); + } + + record.setModified (ingredient); +} + +int CSMWorld::IngredEffectRefIdAdapter::getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const +{ + return 3; // effect, skill, attribute +} + +int CSMWorld::IngredEffectRefIdAdapter::getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const +{ + return 4; // up to 4 effects +} + + CSMWorld::ApparatusRefIdAdapter::ApparatusRefIdAdapter (const InventoryColumns& columns, const RefIdColumn *type, const RefIdColumn *quality) : InventoryRefIdAdapter (UniversalId::Type_Apparatus, columns), diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index 4ac27b6e9..93d4ce894 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -340,6 +340,66 @@ namespace CSMWorld ///< If the data type does not match an exception is thrown. }; + struct IngredientColumns : public InventoryColumns + { + const RefIdColumn *mEffects; + + IngredientColumns (const InventoryColumns& columns); + }; + + class IngredientRefIdAdapter : public InventoryRefIdAdapter + { + IngredientColumns mColumns; + + public: + + IngredientRefIdAdapter (const IngredientColumns& columns); + + virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index) + const; + + virtual void setData (const RefIdColumn *column, RefIdData& data, int index, + const QVariant& value) const; + ///< If the data type does not match an exception is thrown. + }; + + class IngredEffectRefIdAdapter : public NestedRefIdAdapterBase + { + UniversalId::Type mType; + + // not implemented + IngredEffectRefIdAdapter (const IngredEffectRefIdAdapter&); + IngredEffectRefIdAdapter& operator= (const IngredEffectRefIdAdapter&); + + public: + + IngredEffectRefIdAdapter(); + + virtual ~IngredEffectRefIdAdapter(); + + virtual void addNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int position) const; + + virtual void removeNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int rowToRemove) const; + + virtual void setNestedTable (const RefIdColumn* column, + RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const; + + virtual NestedTableWrapperBase* nestedTable (const RefIdColumn* column, + const RefIdData& data, int index) const; + + virtual QVariant getNestedData (const RefIdColumn *column, + const RefIdData& data, int index, int subRowIndex, int subColIndex) const; + + virtual void setNestedData (const RefIdColumn *column, + RefIdData& data, int row, const QVariant& value, int subRowIndex, int subColIndex) const; + + virtual int getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const; + + virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const; + }; + struct EnchantableColumns : public InventoryColumns { const RefIdColumn *mEnchantment; diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 3b316bea3..76694027b 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -71,6 +71,21 @@ CSMWorld::RefIdCollection::RefIdCollection() mColumns.push_back (RefIdColumn (Columns::ColumnId_CoinValue, ColumnBase::Display_Integer)); inventoryColumns.mValue = &mColumns.back(); + IngredientColumns ingredientColumns (inventoryColumns); + mColumns.push_back (RefIdColumn (Columns::ColumnId_EffectList, + ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue)); + ingredientColumns.mEffects = &mColumns.back(); + std::map ingredientEffectsMap; + ingredientEffectsMap.insert(std::make_pair(UniversalId::Type_Ingredient, + new IngredEffectRefIdAdapter ())); + mNestedAdapters.push_back (std::make_pair(&mColumns.back(), ingredientEffectsMap)); + mColumns.back().addColumn( + new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_EffectId)); + mColumns.back().addColumn( + new NestedChildColumn (Columns::ColumnId_Skill, ColumnBase::Display_SkillId)); + mColumns.back().addColumn( + new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_Attribute)); + // nested table PotionColumns potionColumns (inventoryColumns); mColumns.push_back (RefIdColumn (Columns::ColumnId_EffectList, @@ -651,7 +666,7 @@ CSMWorld::RefIdCollection::RefIdCollection() mAdapters.insert (std::make_pair (UniversalId::Type_Door, new DoorRefIdAdapter (nameColumns, openSound, closeSound))); mAdapters.insert (std::make_pair (UniversalId::Type_Ingredient, - new InventoryRefIdAdapter (UniversalId::Type_Ingredient, inventoryColumns))); + new IngredientRefIdAdapter (ingredientColumns))); mAdapters.insert (std::make_pair (UniversalId::Type_CreatureLevelledList, new LevelledListRefIdAdapter ( UniversalId::Type_CreatureLevelledList, levListColumns))); From 1a64b4072570e09a75e2ac250576589244ed8a3e Mon Sep 17 00:00:00 2001 From: cc9cii Date: Wed, 28 Oct 2015 11:30:36 +1100 Subject: [PATCH 2292/3725] Fix skills and attributes being possible to add to irrelevant effects. Should resolve bug #2980. --- .../model/world/nestedcoladapterimp.hpp | 30 +++++++++++++++++-- apps/opencs/model/world/refidadapterimp.cpp | 30 +++++++++++++++++-- 2 files changed, 56 insertions(+), 4 deletions(-) diff --git a/apps/opencs/model/world/nestedcoladapterimp.hpp b/apps/opencs/model/world/nestedcoladapterimp.hpp index 81c52588b..2fd569bd0 100644 --- a/apps/opencs/model/world/nestedcoladapterimp.hpp +++ b/apps/opencs/model/world/nestedcoladapterimp.hpp @@ -317,8 +317,34 @@ namespace CSMWorld else throw std::runtime_error("Magic effects ID unexpected value"); } - case 1: return effect.mSkill; - case 2: return effect.mAttribute; + case 1: + { + switch (effect.mEffectID) + { + case ESM::MagicEffect::DrainSkill: + case ESM::MagicEffect::DamageSkill: + case ESM::MagicEffect::RestoreSkill: + case ESM::MagicEffect::FortifySkill: + case ESM::MagicEffect::AbsorbSkill: + return effect.mSkill; + default: + return QVariant(); + } + } + case 2: + { + switch (effect.mEffectID) + { + case ESM::MagicEffect::DrainAttribute: + case ESM::MagicEffect::DamageAttribute: + case ESM::MagicEffect::RestoreAttribute: + case ESM::MagicEffect::FortifyAttribute: + case ESM::MagicEffect::AbsorbAttribute: + return effect.mAttribute; + default: + return QVariant(); + } + } case 3: { if (effect.mRange >=0 && effect.mRange <=2) diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index d4fa91bd5..319c6ef5a 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -139,8 +139,34 @@ QVariant CSMWorld::IngredEffectRefIdAdapter::getNestedData (const RefIdColumn *c switch (subColIndex) { case 0: return record.get().mData.mEffectID[subRowIndex]; - case 1: return record.get().mData.mSkills[subRowIndex]; - case 2: return record.get().mData.mAttributes[subRowIndex]; + case 1: + { + switch (record.get().mData.mEffectID[subRowIndex]) + { + case ESM::MagicEffect::DrainSkill: + case ESM::MagicEffect::DamageSkill: + case ESM::MagicEffect::RestoreSkill: + case ESM::MagicEffect::FortifySkill: + case ESM::MagicEffect::AbsorbSkill: + return record.get().mData.mSkills[subRowIndex]; + default: + return QVariant(); + } + } + case 2: + { + switch (record.get().mData.mEffectID[subRowIndex]) + { + case ESM::MagicEffect::DrainAttribute: + case ESM::MagicEffect::DamageAttribute: + case ESM::MagicEffect::RestoreAttribute: + case ESM::MagicEffect::FortifyAttribute: + case ESM::MagicEffect::AbsorbAttribute: + return record.get().mData.mAttributes[subRowIndex]; + default: + return QVariant(); + } + } default: throw std::runtime_error("Trying to access non-existing column in the nested table!"); } From 972193c7ebcb597dfdd5b38e72965efa1bb4e70f Mon Sep 17 00:00:00 2001 From: cc9cii Date: Wed, 28 Oct 2015 11:49:24 +1100 Subject: [PATCH 2293/3725] Fix issue where mandatory effects field was allowed to be empty (and vice versa) --- apps/opencs/model/world/columnbase.cpp | 4 ++++ apps/opencs/model/world/columnbase.hpp | 4 ++++ apps/opencs/model/world/data.cpp | 8 ++++---- apps/opencs/model/world/refidcollection.cpp | 10 +++++----- apps/opencs/view/doc/viewmanager.cpp | 3 +++ 5 files changed, 20 insertions(+), 9 deletions(-) diff --git a/apps/opencs/model/world/columnbase.cpp b/apps/opencs/model/world/columnbase.cpp index 39232d442..1f16c9695 100644 --- a/apps/opencs/model/world/columnbase.cpp +++ b/apps/opencs/model/world/columnbase.cpp @@ -86,6 +86,10 @@ bool CSMWorld::ColumnBase::isId (Display display) Display_InfoCondVar, Display_InfoCondComp, + Display_EffectSkill, + Display_EffectAttribute, + Display_IngredEffectId, + Display_None }; diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index e2871d4d8..67d79fdbe 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -124,6 +124,10 @@ namespace CSMWorld Display_String32, Display_LongString256, + Display_EffectSkill, // must display at least one, unlike Display_Skill + Display_EffectAttribute, // must display at least one, unlike Display_Attribute + Display_IngredEffectId, // display none allowed, unlike Display_EffectId + //top level columns that nest other columns Display_NestedHeader }; diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 8acdac84f..b75bd54e1 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -213,9 +213,9 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mSpells.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_EffectId)); mSpells.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_Skill, ColumnBase::Display_SkillId)); + new NestedChildColumn (Columns::ColumnId_Skill, ColumnBase::Display_EffectSkill)); mSpells.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_Attribute)); + new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_EffectAttribute)); mSpells.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_EffectRange, ColumnBase::Display_EffectRange)); mSpells.getNestableColumn(index)->addColumn( @@ -329,9 +329,9 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mEnchantments.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_EffectId)); mEnchantments.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_Skill, ColumnBase::Display_SkillId)); + new NestedChildColumn (Columns::ColumnId_Skill, ColumnBase::Display_EffectSkill)); mEnchantments.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_Attribute)); + new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_EffectAttribute)); mEnchantments.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_EffectRange, ColumnBase::Display_EffectRange)); mEnchantments.getNestableColumn(index)->addColumn( diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 76694027b..337580fad 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -80,11 +80,11 @@ CSMWorld::RefIdCollection::RefIdCollection() new IngredEffectRefIdAdapter ())); mNestedAdapters.push_back (std::make_pair(&mColumns.back(), ingredientEffectsMap)); mColumns.back().addColumn( - new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_EffectId)); + new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_IngredEffectId)); mColumns.back().addColumn( - new NestedChildColumn (Columns::ColumnId_Skill, ColumnBase::Display_SkillId)); + new NestedChildColumn (Columns::ColumnId_Skill, ColumnBase::Display_EffectSkill)); mColumns.back().addColumn( - new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_Attribute)); + new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_EffectAttribute)); // nested table PotionColumns potionColumns (inventoryColumns); @@ -98,9 +98,9 @@ CSMWorld::RefIdCollection::RefIdCollection() mColumns.back().addColumn( new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_EffectId)); mColumns.back().addColumn( - new NestedChildColumn (Columns::ColumnId_Skill, ColumnBase::Display_SkillId)); + new NestedChildColumn (Columns::ColumnId_Skill, ColumnBase::Display_EffectSkill)); mColumns.back().addColumn( - new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_Attribute)); + new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_EffectAttribute)); mColumns.back().addColumn( new NestedChildColumn (Columns::ColumnId_EffectRange, ColumnBase::Display_EffectRange)); mColumns.back().addColumn( diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 728e69a7a..116febae4 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -104,6 +104,9 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) { CSMWorld::ColumnBase::Display_AiPackageType, CSMWorld::Columns::ColumnId_AiPackageType, false }, { CSMWorld::ColumnBase::Display_InfoCondFunc, CSMWorld::Columns::ColumnId_InfoCondFunc, false }, { CSMWorld::ColumnBase::Display_InfoCondComp, CSMWorld::Columns::ColumnId_InfoCondComp, false }, + { CSMWorld::ColumnBase::Display_IngredEffectId, CSMWorld::Columns::ColumnId_EffectId, true }, + { CSMWorld::ColumnBase::Display_EffectSkill, CSMWorld::Columns::ColumnId_Skill, false }, + { CSMWorld::ColumnBase::Display_EffectAttribute, CSMWorld::Columns::ColumnId_Attribute, false }, }; for (std::size_t i=0; i Date: Wed, 28 Oct 2015 20:30:30 +1100 Subject: [PATCH 2294/3725] Disable context menu for fixed size sub-tables. Should resolve bug #2932. --- apps/opencs/model/world/columnbase.hpp | 22 +++++++++-- apps/opencs/model/world/data.cpp | 6 ++- apps/opencs/model/world/refidadapterimp.cpp | 23 ++++++------ apps/opencs/view/world/dialoguesubview.cpp | 19 ++++++++-- apps/opencs/view/world/nestedtable.cpp | 41 +++++++++++++++------ apps/opencs/view/world/nestedtable.hpp | 4 +- 6 files changed, 82 insertions(+), 33 deletions(-) diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index 67d79fdbe..c40bd9663 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -12,6 +12,13 @@ namespace CSMWorld { + enum TableEditModes + { + TableEdit_None, // no editing + TableEdit_Full, // edit cells and add/remove rows + TableEdit_FixedRows // edit cells only + }; + struct ColumnBase { enum Roles @@ -190,8 +197,8 @@ namespace CSMWorld template struct NestedParentColumn : public Column { - NestedParentColumn (int id, int flags = ColumnBase::Flag_Dialogue) : Column (id, - ColumnBase::Display_NestedHeader, flags) + NestedParentColumn (int id, int flags = ColumnBase::Flag_Dialogue, bool fixedRows = false) + : Column (id, ColumnBase::Display_NestedHeader, flags), mFixedRows(fixedRows) {} virtual void set (Record& record, const QVariant& data) @@ -202,13 +209,20 @@ namespace CSMWorld virtual QVariant get (const Record& record) const { - return true; // required by IdTree::hasChildren() + // by default editable; also see IdTree::hasChildren() + if (mFixedRows) + return QVariant::fromValue(TableEditModes::TableEdit_FixedRows); + else + return QVariant::fromValue(TableEditModes::TableEdit_Full); } virtual bool isEditable() const { return true; } + + Private: + bool mFixedRows; }; struct NestedChildColumn : public NestableColumn @@ -223,4 +237,6 @@ namespace CSMWorld }; } +Q_DECLARE_METATYPE(CSMWorld::TableEditModes) + #endif diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index b75bd54e1..bfdab0675 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -136,7 +136,8 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mRaces.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_SpellId, ColumnBase::Display_Spell)); // Race attributes - mRaces.addColumn (new NestedParentColumn (Columns::ColumnId_RaceAttributes)); + mRaces.addColumn (new NestedParentColumn (Columns::ColumnId_RaceAttributes, + ColumnBase::Flag_Dialogue, true)); // fixed rows table index = mRaces.getColumns()-1; mRaces.addAdapter (std::make_pair(&mRaces.getColumn(index), new RaceAttributeAdapter())); mRaces.getNestableColumn(index)->addColumn( @@ -147,7 +148,8 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mRaces.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_Female, ColumnBase::Display_Integer)); // Race skill bonus - mRaces.addColumn (new NestedParentColumn (Columns::ColumnId_RaceSkillBonus)); + mRaces.addColumn (new NestedParentColumn (Columns::ColumnId_RaceSkillBonus, + ColumnBase::Flag_Dialogue, true)); // fixed rows table index = mRaces.getColumns()-1; mRaces.addAdapter (std::make_pair(&mRaces.getColumn(index), new RaceSkillsBonusAdapter())); mRaces.getNestableColumn(index)->addColumn( diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index 319c6ef5a..369a349b5 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -25,8 +25,9 @@ QVariant CSMWorld::PotionRefIdAdapter::getData (const RefIdColumn *column, const if (column==mAutoCalc) return record.get().mData.mAutoCalc!=0; + // to show nested tables in dialogue subview, see IdTree::hasChildren() if (column==mColumns.mEffects) - return true; // to show nested tables in dialogue subview, see IdTree::hasChildren() + return QVariant::fromValue(TableEditModes::TableEdit_Full); return InventoryRefIdAdapter::getData (column, data, index); } @@ -67,7 +68,7 @@ QVariant CSMWorld::IngredientRefIdAdapter::getData (const RefIdColumn *column, c data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Ingredient))); if (column==mColumns.mEffects) - return true; // to show nested tables in dialogue subview, see IdTree::hasChildren() + return QVariant::fromValue(TableEditModes::TableEdit_FixedRows); return InventoryRefIdAdapter::getData (column, data, index); } @@ -271,7 +272,7 @@ QVariant CSMWorld::ArmorRefIdAdapter::getData (const RefIdColumn *column, return record.get().mData.mArmor; if (column==mPartRef) - return true; // to show nested tables in dialogue subview, see IdTree::hasChildren() + return QVariant::fromValue(TableEditModes::TableEdit_Full); return EnchantableRefIdAdapter::getData (column, data, index); } @@ -359,7 +360,7 @@ QVariant CSMWorld::ClothingRefIdAdapter::getData (const RefIdColumn *column, return record.get().mData.mType; if (column==mPartRef) - return true; // to show nested tables in dialogue subview, see IdTree::hasChildren() + return QVariant::fromValue(TableEditModes::TableEdit_Full); return EnchantableRefIdAdapter::getData (column, data, index); } @@ -407,7 +408,7 @@ QVariant CSMWorld::ContainerRefIdAdapter::getData (const RefIdColumn *column, return (record.get().mFlags & ESM::Container::Respawn)!=0; if (column==mContent) - return true; // Required to show nested tables in dialogue subview + return QVariant::fromValue(TableEditModes::TableEdit_Full); return NameRefIdAdapter::getData (column, data, index); } @@ -476,13 +477,13 @@ QVariant CSMWorld::CreatureRefIdAdapter::getData (const RefIdColumn *column, con return QString::fromUtf8 (record.get().mOriginal.c_str()); if (column==mColumns.mAttributes) - return true; // Required to show nested tables in dialogue subview + return QVariant::fromValue(TableEditModes::TableEdit_FixedRows); if (column==mColumns.mAttacks) - return true; // Required to show nested tables in dialogue subview + return QVariant::fromValue(TableEditModes::TableEdit_FixedRows); if (column==mColumns.mMisc) - return true; // Required to show nested items in dialogue subview + return QVariant::fromValue(TableEditModes::TableEdit_Full); std::map::const_iterator iter = mColumns.mFlags.find (column); @@ -722,13 +723,13 @@ QVariant CSMWorld::NpcRefIdAdapter::getData (const RefIdColumn *column, const Re if (column==mColumns.mAttributes || column==mColumns.mSkills) { if ((record.get().mFlags & ESM::NPC::Autocalc) != 0) - return QVariant(QVariant::UserType); + return QVariant::fromValue(TableEditModes::TableEdit_None); else - return true; + return QVariant::fromValue(TableEditModes::TableEdit_FixedRows); } if (column==mColumns.mMisc) - return true; + return QVariant::fromValue(TableEditModes::TableEdit_Full); std::map::const_iterator iter = mColumns.mFlags.find (column); diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 7402f62ee..cdc50a0c6 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -564,10 +564,21 @@ void CSVWorld::EditWidget::remake(int row) static_cast (mTable->data (mTable->index (row, typeColumn)).toInt()), mTable->data (mTable->index (row, idColumn)).toString().toUtf8().constData()); - NestedTable* table = new NestedTable(mDocument, id, mNestedModels.back(), this); - table->resizeColumnsToContents(); + bool editable = true; + bool fixedRows = false; + QVariant v = mTable->index(row, i).data(); + if (v.canConvert()) + { + assert (QString(v.typeName()) == "CSMWorld::TableEditModes"); + + if (v.value() == CSMWorld::TableEditModes::TableEdit_None) + editable = false; + else if (v.value() == CSMWorld::TableEditModes::TableEdit_FixedRows) + fixedRows = true; + } - if(mTable->index(row, i).data().type() == QVariant::UserType) + NestedTable* table = new NestedTable(mDocument, id, mNestedModels.back(), this, editable, fixedRows); + if (!editable) { table->setEditTriggers(QAbstractItemView::NoEditTriggers); table->setEnabled(false); @@ -583,7 +594,7 @@ void CSVWorld::EditWidget::remake(int row) new QLabel (mTable->headerData (i, Qt::Horizontal, Qt::DisplayRole).toString(), mMainWidget); label->setSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed); - if(mTable->index(row, i).data().type() == QVariant::UserType) + if(!editable) label->setEnabled(false); tablesLayout->addWidget(label); diff --git a/apps/opencs/view/world/nestedtable.cpp b/apps/opencs/view/world/nestedtable.cpp index 0876b2ce7..23d566439 100644 --- a/apps/opencs/view/world/nestedtable.cpp +++ b/apps/opencs/view/world/nestedtable.cpp @@ -16,8 +16,13 @@ CSVWorld::NestedTable::NestedTable(CSMDoc::Document& document, CSMWorld::UniversalId id, CSMWorld::NestedTableProxyModel* model, - QWidget* parent) + QWidget* parent, + bool editable, + bool fixedRows) : DragRecordTable(document, parent), + mAddNewRowAction(NULL), + mRemoveRowAction(NULL), + mEditIdAction(NULL), mModel(model) { mDispatcher = new CSMWorld::CommandDispatcher (document, id, this); @@ -49,18 +54,24 @@ CSVWorld::NestedTable::NestedTable(CSMDoc::Document& document, setModel(model); - mAddNewRowAction = new QAction (tr ("Add new row"), this); + if (editable) + { + if (!fixedRows) + { + mAddNewRowAction = new QAction (tr ("Add new row"), this); - connect(mAddNewRowAction, SIGNAL(triggered()), - this, SLOT(addNewRowActionTriggered())); + connect(mAddNewRowAction, SIGNAL(triggered()), + this, SLOT(addNewRowActionTriggered())); - mRemoveRowAction = new QAction (tr ("Remove row"), this); + mRemoveRowAction = new QAction (tr ("Remove row"), this); - connect(mRemoveRowAction, SIGNAL(triggered()), - this, SLOT(removeRowActionTriggered())); + connect(mRemoveRowAction, SIGNAL(triggered()), + this, SLOT(removeRowActionTriggered())); + } - mEditIdAction = new TableEditIdAction(*this, this); - connect(mEditIdAction, SIGNAL(triggered()), this, SLOT(editCell())); + mEditIdAction = new TableEditIdAction(*this, this); + connect(mEditIdAction, SIGNAL(triggered()), this, SLOT(editCell())); + } } std::vector CSVWorld::NestedTable::getDraggedRecords() const @@ -71,6 +82,9 @@ std::vector CSVWorld::NestedTable::getDraggedRecords() co void CSVWorld::NestedTable::contextMenuEvent (QContextMenuEvent *event) { + if (!mEditIdAction) + return; + QModelIndexList selectedRows = selectionModel()->selectedRows(); QMenu menu(this); @@ -84,10 +98,13 @@ void CSVWorld::NestedTable::contextMenuEvent (QContextMenuEvent *event) menu.addSeparator(); } - if (selectionModel()->selectedRows().size() == 1) - menu.addAction(mRemoveRowAction); + if (mAddNewRowAction && mRemoveRowAction) + { + if (selectionModel()->selectedRows().size() == 1) + menu.addAction(mRemoveRowAction); - menu.addAction(mAddNewRowAction); + menu.addAction(mAddNewRowAction); + } menu.exec (event->globalPos()); } diff --git a/apps/opencs/view/world/nestedtable.hpp b/apps/opencs/view/world/nestedtable.hpp index ba8b6c0e3..765060ea5 100644 --- a/apps/opencs/view/world/nestedtable.hpp +++ b/apps/opencs/view/world/nestedtable.hpp @@ -38,7 +38,9 @@ namespace CSVWorld NestedTable(CSMDoc::Document& document, CSMWorld::UniversalId id, CSMWorld::NestedTableProxyModel* model, - QWidget* parent = NULL); + QWidget* parent = NULL, + bool editable = true, + bool fixedRows = false); virtual std::vector getDraggedRecords() const; From 77471d1592611fe08b65e6b34b7e656d78753944 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Wed, 28 Oct 2015 20:52:07 +1100 Subject: [PATCH 2295/3725] Re-add mistakenly removed line and fix a silly typo. --- apps/opencs/model/world/columnbase.hpp | 2 +- apps/opencs/view/world/dialoguesubview.cpp | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index c40bd9663..8a0a70644 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -221,7 +221,7 @@ namespace CSMWorld return true; } - Private: + private: bool mFixedRows; }; diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index cdc50a0c6..28a1942e0 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -577,7 +577,9 @@ void CSVWorld::EditWidget::remake(int row) fixedRows = true; } - NestedTable* table = new NestedTable(mDocument, id, mNestedModels.back(), this, editable, fixedRows); + NestedTable* table = + new NestedTable(mDocument, id, mNestedModels.back(), this, editable, fixedRows); + table->resizeColumnsToContents(); if (!editable) { table->setEditTriggers(QAbstractItemView::NoEditTriggers); From 107ccd84d4f411a825c2f095bae7f84e65f8609d Mon Sep 17 00:00:00 2001 From: cc9cii Date: Wed, 28 Oct 2015 23:33:24 +1100 Subject: [PATCH 2296/3725] Move TableEditModes enum inside a class scope. --- apps/opencs/model/world/columnbase.hpp | 20 +++++++-------- apps/opencs/model/world/refidadapterimp.cpp | 28 ++++++++++----------- apps/opencs/view/world/dialoguesubview.cpp | 8 +++--- 3 files changed, 28 insertions(+), 28 deletions(-) diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index 8a0a70644..c75a3c2a1 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -12,15 +12,15 @@ namespace CSMWorld { - enum TableEditModes - { - TableEdit_None, // no editing - TableEdit_Full, // edit cells and add/remove rows - TableEdit_FixedRows // edit cells only - }; - struct ColumnBase { + enum TableEditModes + { + TableEdit_None, // no editing + TableEdit_Full, // edit cells and add/remove rows + TableEdit_FixedRows // edit cells only + }; + enum Roles { Role_Flags = Qt::UserRole, @@ -211,9 +211,9 @@ namespace CSMWorld { // by default editable; also see IdTree::hasChildren() if (mFixedRows) - return QVariant::fromValue(TableEditModes::TableEdit_FixedRows); + return QVariant::fromValue(ColumnBase::TableEdit_FixedRows); else - return QVariant::fromValue(TableEditModes::TableEdit_Full); + return QVariant::fromValue(ColumnBase::TableEdit_Full); } virtual bool isEditable() const @@ -237,6 +237,6 @@ namespace CSMWorld }; } -Q_DECLARE_METATYPE(CSMWorld::TableEditModes) +Q_DECLARE_METATYPE(CSMWorld::ColumnBase::TableEditModes) #endif diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index 369a349b5..860fc9bdf 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -5,6 +5,9 @@ #include #include +#include + +#include "columnbase.hpp" #include "nestedtablewrapper.hpp" CSMWorld::PotionColumns::PotionColumns (const InventoryColumns& columns) @@ -27,7 +30,7 @@ QVariant CSMWorld::PotionRefIdAdapter::getData (const RefIdColumn *column, const // to show nested tables in dialogue subview, see IdTree::hasChildren() if (column==mColumns.mEffects) - return QVariant::fromValue(TableEditModes::TableEdit_Full); + return QVariant::fromValue(ColumnBase::TableEdit_Full); return InventoryRefIdAdapter::getData (column, data, index); } @@ -64,11 +67,8 @@ CSMWorld::IngredientRefIdAdapter::IngredientRefIdAdapter (const IngredientColumn QVariant CSMWorld::IngredientRefIdAdapter::getData (const RefIdColumn *column, const RefIdData& data, int index) const { - const Record& record = static_cast&> ( - data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Ingredient))); - if (column==mColumns.mEffects) - return QVariant::fromValue(TableEditModes::TableEdit_FixedRows); + return QVariant::fromValue(ColumnBase::TableEdit_FixedRows); return InventoryRefIdAdapter::getData (column, data, index); } @@ -272,7 +272,7 @@ QVariant CSMWorld::ArmorRefIdAdapter::getData (const RefIdColumn *column, return record.get().mData.mArmor; if (column==mPartRef) - return QVariant::fromValue(TableEditModes::TableEdit_Full); + return QVariant::fromValue(ColumnBase::TableEdit_Full); return EnchantableRefIdAdapter::getData (column, data, index); } @@ -360,7 +360,7 @@ QVariant CSMWorld::ClothingRefIdAdapter::getData (const RefIdColumn *column, return record.get().mData.mType; if (column==mPartRef) - return QVariant::fromValue(TableEditModes::TableEdit_Full); + return QVariant::fromValue(ColumnBase::TableEdit_Full); return EnchantableRefIdAdapter::getData (column, data, index); } @@ -408,7 +408,7 @@ QVariant CSMWorld::ContainerRefIdAdapter::getData (const RefIdColumn *column, return (record.get().mFlags & ESM::Container::Respawn)!=0; if (column==mContent) - return QVariant::fromValue(TableEditModes::TableEdit_Full); + return QVariant::fromValue(ColumnBase::TableEdit_Full); return NameRefIdAdapter::getData (column, data, index); } @@ -477,13 +477,13 @@ QVariant CSMWorld::CreatureRefIdAdapter::getData (const RefIdColumn *column, con return QString::fromUtf8 (record.get().mOriginal.c_str()); if (column==mColumns.mAttributes) - return QVariant::fromValue(TableEditModes::TableEdit_FixedRows); + return QVariant::fromValue(ColumnBase::TableEdit_FixedRows); if (column==mColumns.mAttacks) - return QVariant::fromValue(TableEditModes::TableEdit_FixedRows); + return QVariant::fromValue(ColumnBase::TableEdit_FixedRows); if (column==mColumns.mMisc) - return QVariant::fromValue(TableEditModes::TableEdit_Full); + return QVariant::fromValue(ColumnBase::TableEdit_Full); std::map::const_iterator iter = mColumns.mFlags.find (column); @@ -723,13 +723,13 @@ QVariant CSMWorld::NpcRefIdAdapter::getData (const RefIdColumn *column, const Re if (column==mColumns.mAttributes || column==mColumns.mSkills) { if ((record.get().mFlags & ESM::NPC::Autocalc) != 0) - return QVariant::fromValue(TableEditModes::TableEdit_None); + return QVariant::fromValue(ColumnBase::TableEdit_None); else - return QVariant::fromValue(TableEditModes::TableEdit_FixedRows); + return QVariant::fromValue(ColumnBase::TableEdit_FixedRows); } if (column==mColumns.mMisc) - return QVariant::fromValue(TableEditModes::TableEdit_Full); + return QVariant::fromValue(ColumnBase::TableEdit_Full); std::map::const_iterator iter = mColumns.mFlags.find (column); diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 28a1942e0..61d3fb1ca 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -567,13 +567,13 @@ void CSVWorld::EditWidget::remake(int row) bool editable = true; bool fixedRows = false; QVariant v = mTable->index(row, i).data(); - if (v.canConvert()) + if (v.canConvert()) { - assert (QString(v.typeName()) == "CSMWorld::TableEditModes"); + assert (QString(v.typeName()) == "CSMWorld::ColumnBase::TableEditModes"); - if (v.value() == CSMWorld::TableEditModes::TableEdit_None) + if (v.value() == CSMWorld::ColumnBase::TableEdit_None) editable = false; - else if (v.value() == CSMWorld::TableEditModes::TableEdit_FixedRows) + else if (v.value() == CSMWorld::ColumnBase::TableEdit_FixedRows) fixedRows = true; } From 4ddb2feebb1b9a3fb5fc813047ab110c99605ac4 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Wed, 28 Oct 2015 17:35:16 +0100 Subject: [PATCH 2297/3725] Let's try building everything, see how far we get --- CI/before_script.msvc.sh | 3 +++ appveyor.yml | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/CI/before_script.msvc.sh b/CI/before_script.msvc.sh index 756653fe9..37905fc4c 100644 --- a/CI/before_script.msvc.sh +++ b/CI/before_script.msvc.sh @@ -573,6 +573,9 @@ else add_cmake_opts -DBUILD_OPENCS=no \ -DBUILD_OPENMW=no ;; + * ) + echo " Building everything." + ;; esac fi diff --git a/appveyor.yml b/appveyor.yml index ea508abd6..651f41783 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -10,12 +10,12 @@ platform: configuration: Debug -environment: - matrix: +#environment: +# matrix: # - STEP: misc # - STEP: components # misc builds this too # Build takes too long for these, ignore for now - - STEP: openmw +# - STEP: openmw # - STEP: opencs matrix: From e13eb625d38a13b47d1b6680608c69c20de6842a Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 26 Oct 2015 21:36:19 +0100 Subject: [PATCH 2298/3725] New water WIP Changes compared to old (Ogre) water: - Uses depth-texture readback to handle the underwater fog in the water shader, instead of handling it in the object shader - Different clipping mechanism (glClipPlane instead of a skewed viewing frustum) - Fixed bug where the reflection camera would look strange when the viewer was very close to the water surface - Toned down light scattering, made the waterColor a bit darker at night - Fixed flipped water normals and strange resulting logic in the shader Still to do: see comments... --- apps/openmw/engine.cpp | 2 +- apps/openmw/mwrender/npcanimation.cpp | 6 +- apps/openmw/mwrender/renderingmanager.cpp | 39 ++- apps/openmw/mwrender/renderingmanager.hpp | 3 +- apps/openmw/mwrender/sky.cpp | 53 +++- apps/openmw/mwrender/vismask.hpp | 9 +- apps/openmw/mwrender/water.cpp | 311 +++++++++++++++++++++- apps/openmw/mwrender/water.hpp | 8 +- apps/openmw/mwworld/worldimp.cpp | 5 +- apps/openmw/mwworld/worldimp.hpp | 2 +- files/CMakeLists.txt | 1 + files/shaders/CMakeLists.txt | 11 + files/shaders/water_fragment.glsl | 189 +++++++++++++ files/shaders/water_nm.png | Bin 0 -> 24405 bytes files/shaders/water_vertex.glsl | 22 ++ 15 files changed, 642 insertions(+), 19 deletions(-) create mode 100644 files/shaders/CMakeLists.txt create mode 100644 files/shaders/water_fragment.glsl create mode 100644 files/shaders/water_nm.png create mode 100644 files/shaders/water_vertex.glsl diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 79c8c4cc9..089880fb2 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -513,7 +513,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) // Create the world mEnvironment.setWorld( new MWWorld::World (mViewer, rootNode, mResourceSystem.get(), mFileCollections, mContentFiles, mEncoder, mFallbackMap, - mActivationDistanceOverride, mCellName, mStartupScript)); + mActivationDistanceOverride, mCellName, mStartupScript, mResDir.string())); mEnvironment.getWorld()->setupPlayer(); input->setPlayer(&mEnvironment.getWorld()->getPlayer()); diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index cba6c5696..17f0ce73c 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -32,6 +32,7 @@ #include "camera.hpp" #include "rotatecontroller.hpp" #include "renderbin.hpp" +#include "vismask.hpp" namespace { @@ -323,9 +324,9 @@ public: virtual void drawImplementation(osgUtil::RenderBin* bin, osg::RenderInfo& renderInfo, osgUtil::RenderLeaf*& previous) { - renderInfo.getState()->applyAttribute(mDepth); + //renderInfo.getState()->applyAttribute(mDepth); - glClear(GL_DEPTH_BUFFER_BIT); + //glClear(GL_DEPTH_BUFFER_BIT); bin->drawImplementation(renderInfo, previous); } @@ -441,6 +442,7 @@ void NpcAnimation::updateNpcBase() } else { + mObjectRoot->setNodeMask(Mask_FirstPerson); if(isWerewolf) addAnimSource(smodel); else diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index cae6541af..2aaba3035 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -122,7 +122,8 @@ namespace MWRender bool mWireframe; }; - RenderingManager::RenderingManager(osgViewer::Viewer* viewer, osg::ref_ptr rootNode, Resource::ResourceSystem* resourceSystem, const MWWorld::Fallback* fallback) + RenderingManager::RenderingManager(osgViewer::Viewer* viewer, osg::ref_ptr rootNode, Resource::ResourceSystem* resourceSystem, + const MWWorld::Fallback* fallback, const std::string& resourcePath) : mViewer(viewer) , mRootNode(rootNode) , mResourceSystem(resourceSystem) @@ -145,7 +146,7 @@ namespace MWRender mEffectManager.reset(new EffectManager(lightRoot, mResourceSystem)); - mWater.reset(new Water(lightRoot, mResourceSystem, mViewer->getIncrementalCompileOperation(), fallback)); + mWater.reset(new Water(mRootNode, lightRoot, mResourceSystem, mViewer->getIncrementalCompileOperation(), fallback, resourcePath)); mTerrain.reset(new Terrain::TerrainGrid(lightRoot, mResourceSystem, mViewer->getIncrementalCompileOperation(), new TerrainStorage(mResourceSystem->getVFS(), false), Mask_Terrain)); @@ -197,6 +198,39 @@ namespace MWRender mFieldOfView = Settings::Manager::getFloat("field of view", "General"); updateProjectionMatrix(); mStateUpdater->setFogEnd(mViewDistance); + + /* + osg::Texture2D* texture = new osg::Texture2D; + texture->setSourceFormat(GL_DEPTH_COMPONENT); + texture->setInternalFormat(GL_DEPTH_COMPONENT24_ARB); + texture->setSourceType(GL_UNSIGNED_INT); + + mViewer->getCamera()->attach(osg::Camera::DEPTH_BUFFER, texture); + + osg::ref_ptr camera (new osg::Camera); + camera->setProjectionMatrix(osg::Matrix::identity()); + camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF); + camera->setViewMatrix(osg::Matrix::identity()); + camera->setClearMask(0); + camera->setRenderOrder(osg::Camera::NESTED_RENDER); + camera->setAllowEventFocus(false); + + osg::ref_ptr geode (new osg::Geode); + osg::ref_ptr geom = osg::createTexturedQuadGeometry(osg::Vec3f(-1,-1,0), osg::Vec3f(0.5,0,0), osg::Vec3f(0,0.5,0)); + geode->addDrawable(geom); + + camera->addChild(geode); + + osg::StateSet* stateset = geom->getOrCreateStateSet(); + + stateset->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON); + stateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF); + + stateset->setRenderBinDetails(20, "RenderBin"); + stateset->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF); + + mLightRoot->addChild(camera); + */ } RenderingManager::~RenderingManager() @@ -260,6 +294,7 @@ namespace MWRender { // need to wrap this in a StateUpdater? mSunLight->setDiffuse(colour); + mSunLight->setSpecular(colour); } void RenderingManager::setSunDirection(const osg::Vec3f &direction) diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index def3ea4bb..1ddab7338 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -57,7 +57,8 @@ namespace MWRender class RenderingManager : public MWRender::RenderingInterface { public: - RenderingManager(osgViewer::Viewer* viewer, osg::ref_ptr rootNode, Resource::ResourceSystem* resourceSystem, const MWWorld::Fallback* fallback); + RenderingManager(osgViewer::Viewer* viewer, osg::ref_ptr rootNode, Resource::ResourceSystem* resourceSystem, + const MWWorld::Fallback* fallback, const std::string& resourcePath); ~RenderingManager(); MWRender::Objects& getObjects(); diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 8de8a61fc..30dc08989 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1,6 +1,9 @@ #include "sky.hpp" #include +#include + +#include #include #include @@ -250,6 +253,8 @@ public: // That's not a problem though, children of this node can be culled just fine // Just make sure you do not place a CameraRelativeTransform deep in the scene graph setCullingActive(false); + + addCullCallback(new CullCallback); } CameraRelativeTransform(const CameraRelativeTransform& copy, const osg::CopyOp& copyop) @@ -259,7 +264,7 @@ public: META_Node(MWRender, CameraRelativeTransform) - virtual bool computeLocalToWorldMatrix(osg::Matrix& matrix, osg::NodeVisitor*) const + virtual bool computeLocalToWorldMatrix(osg::Matrix& matrix, osg::NodeVisitor* nv) const { if (_referenceFrame==RELATIVE_RF) { @@ -277,6 +282,48 @@ public: { return osg::BoundingSphere(osg::Vec3f(0,0,0), 0); } + + class CullCallback : public osg::NodeCallback + { + public: + virtual void operator() (osg::Node* node, osg::NodeVisitor* nv) + { + osgUtil::CullVisitor* cv = static_cast(nv); + + // XXX have to remove unwanted culling plane of the water reflection camera + + // Remove all planes that aren't from the standard frustum + unsigned int numPlanes = 4; + if (cv->getCullingMode() & osg::CullSettings::NEAR_PLANE_CULLING) + ++numPlanes; + if (cv->getCullingMode() & osg::CullSettings::FAR_PLANE_CULLING) + ++numPlanes; + + int mask = 0x1; + int resultMask = cv->getProjectionCullingStack().back().getFrustum().getResultMask(); + for (unsigned int i=0; igetProjectionCullingStack().back().getFrustum().getPlaneList().size(); ++i) + { + if (i >= numPlanes) + { + // turn off this culling plane + resultMask &= (~mask); + } + + mask <<= 1; + } + + cv->getProjectionCullingStack().back().getFrustum().setResultMask(resultMask); + cv->getCurrentCullingSet().getFrustum().setResultMask(resultMask); + + cv->getProjectionCullingStack().back().pushCurrentMask(); + cv->getCurrentCullingSet().pushCurrentMask(); + + traverse(node, nv); + + cv->getProjectionCullingStack().back().popCurrentMask(); + cv->getCurrentCullingSet().popCurrentMask(); + } + }; }; class ModVertexAlphaVisitor : public osg::NodeVisitor @@ -1014,6 +1061,7 @@ SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneMana , mSunEnabled(true) { osg::ref_ptr skyroot (new CameraRelativeTransform); + skyroot->setNodeMask(Mask_Sky); parentNode->addChild(skyroot); @@ -1021,6 +1069,9 @@ SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneMana // By default render before the world is rendered mRootNode->getOrCreateStateSet()->setRenderBinDetails(RenderBin_Sky, "RenderBin"); + + // Prevent unwanted clipping by water reflection camera's clipping plane + mRootNode->getOrCreateStateSet()->setMode(GL_CLIP_PLANE0, osg::StateAttribute::OFF); } void SkyManager::create() diff --git a/apps/openmw/mwrender/vismask.hpp b/apps/openmw/mwrender/vismask.hpp index 38fcfe648..fc63cddbb 100644 --- a/apps/openmw/mwrender/vismask.hpp +++ b/apps/openmw/mwrender/vismask.hpp @@ -17,16 +17,17 @@ namespace MWRender Mask_Sky = (1<<5), Mask_Water = (1<<6), Mask_Terrain = (1<<7), + Mask_FirstPerson = (1<<8), // top level masks - Mask_Scene = (1<<8), - Mask_GUI = (1<<9), + Mask_Scene = (1<<9), + Mask_GUI = (1<<10), // Set on a Geode - Mask_ParticleSystem = (1<<10), + Mask_ParticleSystem = (1<<11), // Set on cameras within the main scene graph - Mask_RenderToTexture = (1<<11) + Mask_RenderToTexture = (1<<12) // reserved: (1<<16) for SceneUtil::Mask_Lit }; diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 03ab58e6b..cf361a504 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -2,14 +2,24 @@ #include +#include + +#include #include #include #include #include #include #include +#include +#include +#include +#include + +#include // XXX remove #include +#include #include #include @@ -17,6 +27,8 @@ #include #include +#include + #include #include "vismask.hpp" @@ -69,7 +81,7 @@ namespace return waterGeom; } - void createWaterStateSet(Resource::ResourceSystem* resourceSystem, osg::ref_ptr node) + void createSimpleWaterStateSet(Resource::ResourceSystem* resourceSystem, osg::ref_ptr node) { osg::ref_ptr stateset (new osg::StateSet); @@ -111,8 +123,152 @@ namespace MWRender // -------------------------------------------------------------------------------------------------------------------------------- -Water::Water(osg::Group *parent, Resource::ResourceSystem *resourceSystem, osgUtil::IncrementalCompileOperation *ico, const MWWorld::Fallback* fallback) +/// @brief Allows to cull and clip meshes that are below a plane. Useful for reflection & refraction camera effects. +/// Also handles flipping of the plane when the eye point goes below it. +/// To use, simply create the scene as subgraph of this node, then do setPlane(const osg::Plane& plane); +class ClipCullNode : public osg::Group +{ + class PlaneCullCallback : public osg::NodeCallback + { + public: + /// @param cullPlane The culling plane (in world space). + PlaneCullCallback(const osg::Plane* cullPlane) + : osg::NodeCallback() + , mCullPlane(cullPlane) + { + } + + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) + { + osgUtil::CullVisitor* cv = static_cast(nv); + + osg::Polytope::PlaneList origPlaneList = cv->getProjectionCullingStack().back().getFrustum().getPlaneList(); + + // TODO: offset plane towards the viewer to fix bleeding at the water shore + + osg::Plane plane = *mCullPlane; + plane.transform(*cv->getCurrentRenderStage()->getInitialViewMatrix()); + + osg::Vec3d eyePoint = cv->getEyePoint(); + if (mCullPlane->intersect(osg::BoundingSphere(osg::Vec3d(0,0,eyePoint.z()), 0)) > 0) + plane.flip(); + + cv->getProjectionCullingStack().back().getFrustum().add(plane); + + traverse(node, nv); + + // undo + cv->getProjectionCullingStack().back().getFrustum().set(origPlaneList); + } + + private: + const osg::Plane* mCullPlane; + }; + + class FlipCallback : public osg::NodeCallback + { + public: + FlipCallback(const osg::Plane* cullPlane) + : mCullPlane(cullPlane) + { + } + + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) + { + osgUtil::CullVisitor* cv = static_cast(nv); + osg::Vec3d eyePoint = cv->getEyePoint(); + // flip the below graph if the eye point is above the plane + if (mCullPlane->intersect(osg::BoundingSphere(osg::Vec3d(0,0,eyePoint.z()), 0)) > 0) + { + osg::RefMatrix* modelViewMatrix = new osg::RefMatrix(*cv->getModelViewMatrix()); + modelViewMatrix->preMultScale(osg::Vec3(1,1,-1)); + + cv->pushModelViewMatrix(modelViewMatrix, osg::Transform::RELATIVE_RF); + traverse(node, nv); + cv->popModelViewMatrix(); + } + else + traverse(node, nv); + } + + private: + const osg::Plane* mCullPlane; + }; + +public: + ClipCullNode() + { + addCullCallback (new PlaneCullCallback(&mPlane)); + + mClipNodeTransform = new osg::PositionAttitudeTransform; + mClipNodeTransform->addCullCallback(new FlipCallback(&mPlane)); + addChild(mClipNodeTransform); + + mClipNode = new osg::ClipNode; + + mClipNodeTransform->addChild(mClipNode); + } + + void setPlane (const osg::Plane& plane) + { + if (plane == mPlane) + return; + mPlane = plane; + + mClipNode->getClipPlaneList().clear(); + mClipNode->addClipPlane(new osg::ClipPlane(0, mPlane)); + mClipNode->setStateSetModes(*getOrCreateStateSet(), osg::StateAttribute::ON); + } + +private: + osg::ref_ptr mClipNodeTransform; + osg::ref_ptr mClipNode; + + osg::Plane mPlane; +}; + +// Node callback to entirely skip the traversal. +class NoTraverseCallback : public osg::NodeCallback +{ +public: + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) + { + // no traverse() + } +}; + +void addDebugOverlay(osg::Texture2D* texture, int pos, osg::Group* parent) +{ + osg::ref_ptr debugCamera (new osg::Camera); + debugCamera->setProjectionMatrix(osg::Matrix::identity()); + debugCamera->setReferenceFrame(osg::Transform::ABSOLUTE_RF); + debugCamera->setViewMatrix(osg::Matrix::identity()); + debugCamera->setClearMask(0); + debugCamera->setRenderOrder(osg::Camera::NESTED_RENDER); + debugCamera->setAllowEventFocus(false); + + const float size = 0.5; + osg::ref_ptr debugGeode (new osg::Geode); + osg::ref_ptr geom = osg::createTexturedQuadGeometry(osg::Vec3f(-1 + size*pos, -1, 0), osg::Vec3f(size,0,0), osg::Vec3f(0,size,0)); + debugGeode->addDrawable(geom); + + debugCamera->addChild(debugGeode); + + osg::StateSet* debugStateset = geom->getOrCreateStateSet(); + + debugStateset->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON); + debugStateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF); + + debugStateset->setRenderBinDetails(20, "RenderBin"); + debugStateset->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF); + + parent->addChild(debugCamera); +} + +Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem *resourceSystem, osgUtil::IncrementalCompileOperation *ico, + const MWWorld::Fallback* fallback, const std::string& resourcePath) : mParent(parent) + , mSceneRoot(sceneRoot) , mResourceSystem(resourceSystem) , mEnabled(true) , mToggled(true) @@ -126,17 +282,164 @@ Water::Water(osg::Group *parent, Resource::ResourceSystem *resourceSystem, osgUt geode->addDrawable(waterGeom); geode->setNodeMask(Mask_Water); + // TODO: node mask to use simple water for local map + if (ico) ico->add(geode); - createWaterStateSet(mResourceSystem, geode); + //createSimpleWaterStateSet(mResourceSystem, geode); mWaterNode = new osg::PositionAttitudeTransform; mWaterNode->addChild(geode); - mParent->addChild(mWaterNode); + mSceneRoot->addChild(mWaterNode); setHeight(mTop); + + const float waterLevel = -1; + + // refraction + unsigned int rttSize = Settings::Manager::getInt("rtt size", "Water"); + osg::ref_ptr refractionCamera (new osg::Camera); + refractionCamera->setRenderOrder(osg::Camera::PRE_RENDER); + refractionCamera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + refractionCamera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT); + refractionCamera->setReferenceFrame(osg::Camera::RELATIVE_RF); + + refractionCamera->setCullMask(Mask_Effect|Mask_Scene|Mask_Terrain|Mask_Actor|Mask_ParticleSystem|Mask_Sky|Mask_Player|(1<<16)); + refractionCamera->setNodeMask(Mask_RenderToTexture); + refractionCamera->setViewport(0, 0, rttSize, rttSize); + + // No need for Update traversal since the mSceneRoot is already updated as part of the main scene graph + // A double update would mess with the light collection (in addition to being plain redundant) + refractionCamera->setUpdateCallback(new NoTraverseCallback); + + // No need for fog here, we are already applying fog on the water surface itself as well as underwater fog + refractionCamera->getOrCreateStateSet()->setMode(GL_FOG, osg::StateAttribute::OFF|osg::StateAttribute::OVERRIDE); + + osg::ref_ptr clipNode (new ClipCullNode); + clipNode->setPlane(osg::Plane(osg::Vec3d(0,0,-1), osg::Vec3d(0,0, waterLevel))); + + refractionCamera->addChild(clipNode); + clipNode->addChild(mSceneRoot); + + // TODO: add ingame setting for texture quality + + osg::ref_ptr refractionTexture = new osg::Texture2D; + refractionTexture->setTextureSize(rttSize, rttSize); + refractionTexture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); + refractionTexture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); + refractionTexture->setInternalFormat(GL_RGB); + refractionTexture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR); + refractionTexture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); + + refractionCamera->attach(osg::Camera::COLOR_BUFFER, refractionTexture); + + osg::ref_ptr refractionDepthTexture = new osg::Texture2D; + refractionDepthTexture->setSourceFormat(GL_DEPTH_COMPONENT); + refractionDepthTexture->setInternalFormat(GL_DEPTH_COMPONENT24_ARB); + refractionDepthTexture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); + refractionDepthTexture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); + refractionDepthTexture->setSourceType(GL_UNSIGNED_INT); + refractionDepthTexture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR); + refractionDepthTexture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); + + refractionCamera->attach(osg::Camera::DEPTH_BUFFER, refractionDepthTexture); + + mParent->addChild(refractionCamera); + + // reflection + osg::ref_ptr reflectionCamera (new osg::Camera); + reflectionCamera->setRenderOrder(osg::Camera::PRE_RENDER); + reflectionCamera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + reflectionCamera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT); + reflectionCamera->setReferenceFrame(osg::Camera::RELATIVE_RF); + + reflectionCamera->setCullMask(Mask_Effect|Mask_Scene|Mask_Terrain|Mask_Actor|Mask_ParticleSystem|Mask_Sky|Mask_Player|(1<<16)); + reflectionCamera->setNodeMask(Mask_RenderToTexture); + + reflectionCamera->setViewport(0, 0, rttSize, rttSize); + + // No need for Update traversal since the mSceneRoot is already updated as part of the main scene graph + // A double update would mess with the light collection (in addition to being plain redundant) + reflectionCamera->setUpdateCallback(new NoTraverseCallback); + + osg::ref_ptr reflectionTexture = new osg::Texture2D; + reflectionTexture->setInternalFormat(GL_RGB); + reflectionTexture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR); + reflectionTexture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); + reflectionTexture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); + reflectionTexture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); + + reflectionCamera->attach(osg::Camera::COLOR_BUFFER, reflectionTexture); + + reflectionCamera->setViewMatrix(osg::Matrix::translate(0,0,-waterLevel) * osg::Matrix::scale(1,1,-1) * osg::Matrix::translate(0,0,waterLevel)); + + osg::ref_ptr reflectNode (new osg::MatrixTransform); + + // XXX: should really flip the FrontFace on each renderable instead of forcing clockwise. + osg::ref_ptr frontFace (new osg::FrontFace); + frontFace->setMode(osg::FrontFace::CLOCKWISE); + reflectNode->getOrCreateStateSet()->setAttributeAndModes(frontFace, osg::StateAttribute::ON); + + osg::ref_ptr clipNode2 (new ClipCullNode); + clipNode2->setPlane(osg::Plane(osg::Vec3d(0,0,1), osg::Vec3d(0,0,waterLevel))); + + reflectNode->addChild(clipNode2); + clipNode2->addChild(mSceneRoot); + + reflectionCamera->addChild(reflectNode); + + // TODO: add to waterNode so cameras don't get updated when water is hidden? + + mParent->addChild(reflectionCamera); + + // debug overlay + addDebugOverlay(refractionTexture, 0, mParent); + addDebugOverlay(refractionDepthTexture, 1, mParent); + addDebugOverlay(reflectionTexture, 2, mParent); + + // shader + // FIXME: windows utf8 path handling? + + osg::ref_ptr vertexShader (osg::Shader::readShaderFile(osg::Shader::VERTEX, resourcePath + "/shaders/water_vertex.glsl")); + + osg::ref_ptr fragmentShader (osg::Shader::readShaderFile(osg::Shader::FRAGMENT, resourcePath + "/shaders/water_fragment.glsl")); + + osg::ref_ptr program (new osg::Program); + program->addShader(vertexShader); + program->addShader(fragmentShader); + + osg::ref_ptr normalMap (new osg::Texture2D(osgDB::readImageFile(resourcePath + "/shaders/water_nm.png"))); + normalMap->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT); + normalMap->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT); + normalMap->setMaxAnisotropy(16); + normalMap->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR_MIPMAP_LINEAR); + normalMap->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); + normalMap->getImage()->flipVertical(); + + osg::ref_ptr shaderStateset = new osg::StateSet; + shaderStateset->setAttributeAndModes(program, osg::StateAttribute::ON); + shaderStateset->addUniform(new osg::Uniform("reflectionMap", 0)); + shaderStateset->addUniform(new osg::Uniform("refractionMap", 1)); + shaderStateset->addUniform(new osg::Uniform("refractionDepthMap", 2)); + shaderStateset->addUniform(new osg::Uniform("normalMap", 3)); + + shaderStateset->setTextureAttributeAndModes(0, reflectionTexture, osg::StateAttribute::ON); + shaderStateset->setTextureAttributeAndModes(1, refractionTexture, osg::StateAttribute::ON); + shaderStateset->setTextureAttributeAndModes(2, refractionDepthTexture, osg::StateAttribute::ON); + shaderStateset->setTextureAttributeAndModes(3, normalMap, osg::StateAttribute::ON); + shaderStateset->setMode(GL_BLEND, osg::StateAttribute::ON); // TODO: set Off when refraction is on + shaderStateset->setMode(GL_CULL_FACE, osg::StateAttribute::OFF); + + osg::ref_ptr depth (new osg::Depth); + depth->setWriteMask(false); + shaderStateset->setAttributeAndModes(depth, osg::StateAttribute::ON); + + // TODO: render after transparent bin when refraction is on + shaderStateset->setRenderBinDetails(MWRender::RenderBin_Water, "RenderBin"); + + geode->setStateSet(shaderStateset); } Water::~Water() diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index 519cd5181..78e8a4927 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -9,6 +9,9 @@ namespace osg { class Group; class PositionAttitudeTransform; + class Texture2D; + class Image; + class Camera; } namespace osgUtil @@ -37,6 +40,7 @@ namespace MWRender static const int CELL_SIZE = 8192; osg::ref_ptr mParent; + osg::ref_ptr mSceneRoot; osg::ref_ptr mWaterNode; Resource::ResourceSystem* mResourceSystem; osg::ref_ptr mIncrementalCompileOperation; @@ -51,7 +55,9 @@ namespace MWRender void updateVisible(); public: - Water(osg::Group* parent, Resource::ResourceSystem* resourceSystem, osgUtil::IncrementalCompileOperation* ico, const MWWorld::Fallback* fallback); + Water(osg::Group* parent, osg::Group* sceneRoot, + Resource::ResourceSystem* resourceSystem, osgUtil::IncrementalCompileOperation* ico, const MWWorld::Fallback* fallback, + const std::string& resourcePath); ~Water(); void setEnabled(bool enabled); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index d994a35ee..be86987e8 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -153,7 +153,8 @@ namespace MWWorld const Files::Collections& fileCollections, const std::vector& contentFiles, ToUTF8::Utf8Encoder* encoder, const std::map& fallbackMap, - int activationDistanceOverride, const std::string& startCell, const std::string& startupScript) + int activationDistanceOverride, const std::string& startCell, const std::string& startupScript, + const std::string& resourcePath) : mResourceSystem(resourceSystem), mFallback(fallbackMap), mPlayer (0), mLocalScripts (mStore), mSky (true), mCells (mStore, mEsm), mGodMode(false), mScriptsEnabled(true), mContentFiles (contentFiles), @@ -163,7 +164,7 @@ namespace MWWorld { mPhysics = new MWPhysics::PhysicsSystem(resourceSystem, rootNode); mProjectileManager.reset(new ProjectileManager(rootNode, resourceSystem, mPhysics)); - mRendering = new MWRender::RenderingManager(viewer, rootNode, resourceSystem, &mFallback); + mRendering = new MWRender::RenderingManager(viewer, rootNode, resourceSystem, &mFallback, resourcePath); mEsm.resize(contentFiles.size()); Loading::Listener* listener = MWBase::Environment::get().getWindowManager()->getLoadingScreen(); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 26153086a..de9266cb2 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -167,7 +167,7 @@ namespace MWWorld const Files::Collections& fileCollections, const std::vector& contentFiles, ToUTF8::Utf8Encoder* encoder, const std::map& fallbackMap, - int activationDistanceOverride, const std::string& startCell, const std::string& startupScript); + int activationDistanceOverride, const std::string& startCell, const std::string& startupScript, const std::string& resourcePath); virtual ~World(); diff --git a/files/CMakeLists.txt b/files/CMakeLists.txt index 00cae86d2..75cb6a9b0 100644 --- a/files/CMakeLists.txt +++ b/files/CMakeLists.txt @@ -1 +1,2 @@ add_subdirectory(mygui) +add_subdirectory(shaders) diff --git a/files/shaders/CMakeLists.txt b/files/shaders/CMakeLists.txt new file mode 100644 index 000000000..fc4706c1f --- /dev/null +++ b/files/shaders/CMakeLists.txt @@ -0,0 +1,11 @@ +# Copy resource files into the build directory +set(SDIR ${CMAKE_CURRENT_SOURCE_DIR}) +set(DDIR ${OpenMW_BINARY_DIR}/resources/shaders) + +set(SHADER_FILES + water_vertex.glsl + water_fragment.glsl + water_nm.png +) + +copy_all_files(${CMAKE_CURRENT_SOURCE_DIR} ${DDIR} "${SHADER_FILES}") diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl new file mode 100644 index 000000000..01e0816bc --- /dev/null +++ b/files/shaders/water_fragment.glsl @@ -0,0 +1,189 @@ +#version 120 + +// Inspired by Blender GLSL Water by martinsh ( http://devlog-martinsh.blogspot.de/2012/07/waterundewater-shader-wip.html ) + +#define REFRACTION 1 + +// tweakables -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- + +const float VISIBILITY = 1200.0; // how far you can look through water + +const float BIG_WAVES_X = 0.1; // strength of big waves +const float BIG_WAVES_Y = 0.1; + +const float MID_WAVES_X = 0.1; // strength of middle sized waves +const float MID_WAVES_Y = 0.1; + +const float SMALL_WAVES_X = 0.1; // strength of small waves +const float SMALL_WAVES_Y = 0.1; + +const float WAVE_CHOPPYNESS = 0.05; // wave choppyness +const float WAVE_SCALE = 75.0; // overall wave scale + +const float BUMP = 0.5; // overall water surface bumpiness +const float REFL_BUMP = 0.15; // reflection distortion amount +const float REFR_BUMP = 0.06; // refraction distortion amount + +const float SCATTER_AMOUNT = 0.3; // amount of sunlight scattering +const vec3 SCATTER_COLOUR = vec3(0.0,1.0,0.95); // colour of sunlight scattering + +const vec3 SUN_EXT = vec3(0.45, 0.55, 0.68); //sunlight extinction + +const float SPEC_HARDNESS = 256.0; // specular highlights hardness + +const vec2 WIND_DIR = vec2(0.5f, -0.8f); +const float WIND_SPEED = 0.2f; + +// -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - + +float fresnel_dielectric(vec3 Incoming, vec3 Normal, float eta) +{ + float c = abs(dot(Incoming, Normal)); + float g = eta * eta - 1.0 + c * c; + float result; + + if(g > 0.0) { + g = sqrt(g); + float A =(g - c)/(g + c); + float B =(c *(g + c)- 1.0)/(c *(g - c)+ 1.0); + result = 0.5 * A * A *(1.0 + B * B); + } + else + result = 1.0; /* TIR (no refracted component) */ + + return result; +} + +varying vec3 screenCoordsPassthrough; +varying vec4 position; +varying float depthPassthrough; + +uniform sampler2D reflectionMap; +#if REFRACTION +uniform sampler2D refractionMap; +uniform sampler2D refractionDepthMap; +#endif + +uniform sampler2D normalMap; + +uniform float osg_SimulationTime; + +void main(void) +{ + // FIXME + vec3 worldPos = position.xyz; // ((wMat) * ( position)).xyz; + vec2 UV = worldPos.xy / (8192.0*5.0) * 3.0; + UV.y *= -1.0; + + float shadow = 1.0; + + vec2 screenCoords = screenCoordsPassthrough.xy / screenCoordsPassthrough.z; + screenCoords.y = (1.0-screenCoords.y); + + vec2 nCoord = vec2(0.0,0.0); + + #define waterTimer osg_SimulationTime + + nCoord = UV * (WAVE_SCALE * 0.05) + WIND_DIR * waterTimer * (WIND_SPEED*0.04); + vec3 normal0 = 2.0 * texture2D(normalMap, nCoord + vec2(-waterTimer*0.015,-waterTimer*0.005)).rgb - 1.0; + nCoord = UV * (WAVE_SCALE * 0.1) + WIND_DIR * waterTimer * (WIND_SPEED*0.08)-(normal0.xy/normal0.zz)*WAVE_CHOPPYNESS; + vec3 normal1 = 2.0 * texture2D(normalMap, nCoord + vec2(+waterTimer*0.020,+waterTimer*0.015)).rgb - 1.0; + + nCoord = UV * (WAVE_SCALE * 0.25) + WIND_DIR * waterTimer * (WIND_SPEED*0.07)-(normal1.xy/normal1.zz)*WAVE_CHOPPYNESS; + vec3 normal2 = 2.0 * texture2D(normalMap, nCoord + vec2(-waterTimer*0.04,-waterTimer*0.03)).rgb - 1.0; + nCoord = UV * (WAVE_SCALE * 0.5) + WIND_DIR * waterTimer * (WIND_SPEED*0.09)-(normal2.xy/normal2.z)*WAVE_CHOPPYNESS; + vec3 normal3 = 2.0 * texture2D(normalMap, nCoord + vec2(+waterTimer*0.03,+waterTimer*0.04)).rgb - 1.0; + + nCoord = UV * (WAVE_SCALE* 1.0) + WIND_DIR * waterTimer * (WIND_SPEED*0.4)-(normal3.xy/normal3.zz)*WAVE_CHOPPYNESS; + vec3 normal4 = 2.0 * texture2D(normalMap, nCoord + vec2(-waterTimer*0.02,+waterTimer*0.1)).rgb - 1.0; + nCoord = UV * (WAVE_SCALE * 2.0) + WIND_DIR * waterTimer * (WIND_SPEED*0.7)-(normal4.xy/normal4.zz)*WAVE_CHOPPYNESS; + vec3 normal5 = 2.0 * texture2D(normalMap, nCoord + vec2(+waterTimer*0.1,-waterTimer*0.06)).rgb - 1.0; + + + + vec3 normal = (normal0 * BIG_WAVES_X + normal1 * BIG_WAVES_Y + + normal2 * MID_WAVES_X + normal3 * MID_WAVES_Y + + normal4 * SMALL_WAVES_X + normal5 * SMALL_WAVES_Y); + + normal = normalize(vec3(normal.x * BUMP, normal.y * BUMP, normal.z)); + + normal = vec3(-normal.x, -normal.y, normal.z); + + // normal for sunlight scattering + vec3 lNormal = (normal0 * BIG_WAVES_X*0.5 + normal1 * BIG_WAVES_Y*0.5 + + normal2 * MID_WAVES_X*0.2 + normal3 * MID_WAVES_Y*0.2 + + normal4 * SMALL_WAVES_X*0.1 + normal5 * SMALL_WAVES_Y*0.1).xyz; + lNormal = normalize(vec3(lNormal.x * BUMP, lNormal.y * BUMP, lNormal.z)); + lNormal = vec3(-lNormal.x, -lNormal.y, lNormal.z); + + + vec3 lVec = normalize((gl_ModelViewMatrixInverse * vec4(gl_LightSource[0].position.xyz, 0.0)).xyz); + + vec3 cameraPos = (gl_ModelViewMatrixInverse * vec4(0,0,0,1)).xyz; + vec3 vVec = normalize(position.xyz - cameraPos.xyz); + + float isUnderwater = (cameraPos.z > 0.0) ? 0.0 : 1.0; + + // sunlight scattering + vec3 pNormal = vec3(0,0,1); + vec3 lR = reflect(lVec, lNormal); + vec3 llR = reflect(lVec, pNormal); + + float sunHeight = lVec.z; + float sunFade = length(gl_LightModel.ambient.xyz); + + float s = clamp(dot(lR, vVec)*2.0-1.2, 0.0, 1.0); + float lightScatter = shadow * clamp(dot(lVec,lNormal)*0.7+0.3, 0.0, 1.0) * s * SCATTER_AMOUNT * sunFade * clamp(1.0-exp(-sunHeight), 0.0, 1.0); + vec3 scatterColour = mix(vec3(SCATTER_COLOUR)*vec3(1.0,0.4,0.0), SCATTER_COLOUR, clamp(1.0-exp(-sunHeight*SUN_EXT), 0.0, 1.0)); + + // fresnel + float ior = (cameraPos.z>0.0)?(1.333/1.0):(1.0/1.333); //air to water; water to air + float fresnel = fresnel_dielectric(vVec, normal, ior); + + fresnel = clamp(fresnel, 0.0, 1.0); + + // reflection + vec3 reflection = texture2D(reflectionMap, screenCoords+(normal.xy*REFL_BUMP)).rgb; + + // refraction +#if REFRACTION + vec3 refraction = texture2D(refractionMap, screenCoords-(normal.xy*REFR_BUMP)).rgb; + + // brighten up the refraction underwater + refraction = (cameraPos.z < 0.0) ? clamp(refraction * 1.5, 0.0, 1.0) : refraction; +#endif + + // specular + vec3 R = reflect(vVec, normal); + float specular = pow(max(dot(R, lVec), 0.0),SPEC_HARDNESS) * shadow; + +#if REFRACTION + float refractionDepth = texture2D(refractionDepthMap, screenCoords-(normal.xy*REFR_BUMP)).x; + // make linear + float zNear = 5; // FIXME + float zFar = 6666; // FIXME + float z_n = 2.0 * refractionDepth - 1.0; + refractionDepth = 2.0 * zNear * zFar / (zFar + zNear - z_n * (zFar - zNear)); + + float waterDepth = refractionDepth - depthPassthrough; + + vec3 waterColor = vec3(0.090195, 0.115685, 0.12745); + waterColor = waterColor * length(gl_LightModel.ambient.xyz); + if (cameraPos.z > 0.0) + refraction = mix(refraction, waterColor, clamp(waterDepth/VISIBILITY, 0.0, 1.0)); + + gl_FragData[0].xyz = mix( mix(refraction, scatterColour, lightScatter), reflection, fresnel) + specular * gl_LightSource[0].specular.xyz; +#else + gl_FragData[0].xyz = mix(reflection, vec3(0.090195, 0.115685, 0.12745), (1.0-fresnel)*0.5) + specular * gl_LightSource[0].specular.xyz; +#endif + + // fog + float fogValue = clamp((depthPassthrough - gl_Fog.start) * gl_Fog.scale, 0.0, 1.0); + gl_FragData[0].xyz = mix(gl_FragData[0].xyz, gl_Fog.color.xyz, fogValue); + +#if REFRACTION + gl_FragData[0].w = 1.0; +#else + gl_FragData[0].w = clamp(fresnel*2.0 + specular, 0.0, 1.0); +#endif +} diff --git a/files/shaders/water_nm.png b/files/shaders/water_nm.png new file mode 100644 index 0000000000000000000000000000000000000000..361431a0efc35882b56bab8ea407d245f27c879d GIT binary patch literal 24405 zcmV(~K+nI4P)zc5 z|C-I$7<43zLB=3!a^>X8VD@AJlVs9l!-FOovbTP(O;@uvd~NvJ!LFdUpF!yNjKLWA z`N9miMi4X^n@Ihc)lh8KDqg#IEnsbW7gSTbh=z_$braF_XgVQ={@l2N$e^x(k?c&K zkxU9kH|&54x{D?$ijJTIA{#pB+%yFQbU?R0L^rV;Xfol^#Xqw7TJTpCtApx>eg5rc z_atd5psOH)AczX0;r=lV(a9Q36FfWkD}(3u%kKdV8PL7RPDVkl&3rXka1o5!1WCrG zM-Ux)G8yDZ=GD}MO+o}6LAJhUWw0A^Cxaw_ilA%gud5gV*+3NZBw{nsGijP%1yD2) zTmOEr=so;Bn+{kNJfdI#r2`sOj0U=>E}EjED4^Ly6irh!9Zik%lVC)$Q-7VQ=jyLT z7R>R4y@M#A3Mxr_{eTKR_-50EzEW4GAt*t9|kM9~@a zN3b424EQMhxkVEZR4FR4gC@ux6i_6y280guU_x)YC&?zd$WC7txM+4LBH-5+rN7FC zp24nGRG6EhnY$sNq8JoKK^GZCcG07VYC4PFO;uCbG*F?N-vQefc>uljJkM*Zg2_)9 zRrF5X<&i59(pX@kV6kAMl%Z@3H2&Jp71BokJ}x}R}~Du^zg%P ziprprJ?IfS8L`PqsyDF`B|wN*5E10|e}`URR}n+6hlDwSA3^-4G|&v1=CKDq5?+p4 zT|rcm-Na5Z6y@}=lIWlldY8f~gCa;49fRg82j9Qr5;e&?xE0@ z9X^oB=%8va*u+*oX6xlmPB>SpuWp!7pF#f)`5D9r-NIgE4?be^MoDu85nJCU(@_Uq;iAd075dnKB3O4p zGsap~a5y{-m9D|w=kDwnupo0NE5eMXuj1=RuztY) zRQ(beekQ>fsz1g@GG34ybwykC4_)j|KR=i!8D~1ugbzS|`{HrFhyG?~(-->n2h?u? zpFz&nzc+otXm;oUM8e0`OI(-!ak}^Y7?7(KzVPkOzH?z_Qyb=1*kd>Bgx>6O;@bgH ztbk&uKAFRxE6EYeRzZ1%4t$=VZym zSd4(E@PpM~4~kBh3o3;fj7RH#I~pE!_y0PG+%?G6&8}vA!Co*{v0o4!tP&8gDj)|d zHvJgv$7YQ5F;5plL2u}h^lAYiK)~(QYHKfcnzi1O27CB0ZUu;%p;l) zg3oh_KmBF-A$)4UY1f?-vJ^;&rPr2$J>YHCfMP7x#l+i&9wUQYs zeB9+Ll6TWR80~Q0O@@96_R}pN(|5=Do2WYiW$Uo^tLPQv7qFB*UQS)Bi@FAp1*w!% zos3phojcgTD22VwRuUbhbbx@AnegeuvR>yM>cxW(Ks2#ocQW%t$RaYBQDg)iPL=+Z zqg8jz)*+c2t|VqtSFt1YJ`9pY7%V%D1IhNwk5nfTrN5pXTzl|=3e=3Cvx(mpm6QG` z>gf(^G(D2pS5SkyU<#vZOh0g=ca#c>9q>$e4i!8R%0Cs!s9?m@5AIe#b&*4qk-nn3 z)mi~*P-%B@rK)AJEB70GoJCyf7~&sAJVQ70)$El@Uu-G_)I>J}fi%4YdJPxz zJDWM2M~wjPQAFz2e-7vhzP1j)c6UMvb&IVOH!1eg8_EoNZ#se+#TBP|ErsDKY6Lx1 zE7UdM(sv#$3?OcDR?qkAzPtjuyCPP>4TEap2@BuaD*@-;V@pORY(S{7s#e7xeHPM zCvJI3Az5(>lIW9LZa6vzlxu=mD%!e?A-lM%)y&v*4fWAE=!Bg*Fhr}nOX$=MjH%D~ z@ee)hU;hofc;7}^;kl9>YCEBXIUJmIozGmlRn-dZ(JY!8I;?d1K&TfHu3_BPr!ky@ zUnQ_$SCTmd9Qp7@39SS@hY^b05nBgrz)yl#!V0~Mxm~7Y=}SbMA&kL-P_JJNmC4?H z-}>H7M(T^K;T9;ASIdoiv=4z_Zu{?Z6FZ4E+SN()I+uk$pwL0nQ=wN))^Me*-y`9g zeu2@jg4zfw-D;;OrvTKxzD6=Gw_}&n*Xd}S2GjLGxWM}L->`ncF5Uj171_#p-~V5( zn=*u+jy6oLz{O9EU6fW*9n7ep5ZI)dg%7zQ_cF#?5%_ib!VVvcm#YMJU4>cLDtY^&%xY*suv)J+e-Y9ge?-f zO`2c@?B!x}(y{IXFhYl}dsEw;#~FL{@JSgySZc?5DnP7OeGpsep-V+r`G%E?wO6JF zIRgPhMhi!)_vfU;--4b2{{!`J2cXg+J0MtuQUlSRLA>h#Tr*U_ujzt(s!bzcW%6i) zUp~aRJz-Cxw0i3@FI(hpSW=qsW>nifThly43<1|D<{`I~5?ppc?|G_Gr%q zTBp8(7|wG{ClKAXO4u*Gl)X?C=zibOp)m7|$;f68)iSe#kpfJF?`zCDjHky8;vWH5 zu>J@7X;8&o4<2%jhT&OBN4XeQUGt=P7E}f-wP*bdwR{ooRa%3natG$-Xy^Hs2bIx* zP1grK6n#6CI(F>4D_N2J?Jj2xZJ1z_H14b)jlr_ zACmM7I@o?2|5wjko)-+y&IMWs#$C{Zsur*j`Z9%vMLS?m-b0=&RlnW-749m8lkbMT zb<=jkYJpa(6{0I9jM7X#6@m`{7CC&d1ni^(-bW}()Fa@(g8g^HFM%u=vd>oJ#8nZk z89)r-_J7TA3+aj6KE*Z$-?&l4?LvGzBtJckt@LNA7L4x_X>X?%lDO)g>r`r1^Xk;p zzXMld%-RPGIMbjBtLfaPV{GU_`ioozpBw&)W*fyCQ81@lk~rtxv&8rRWpTHF-ANiK zi(0TXcnaK~XXvB6jNt7vidNy*E-IsZ07{VQ*g@}NwsPJAO%R#9C|;55(e(7JGvTp- zE7^`*S?$p#PA^6wQ@G5Jkvga!Dx7(i>x9jyVmKmnZ*r)r-Y$#Q!8Y!JkOo0f=@z-% z-xpoNyGVFt@XP}$xkbm5+n3Yr3M$PL@I^YznqLJgHQ+jsbugH*4vZS#X0R$g(se<` zg5?3rZXPrr8-B5AQZ>ZhH=aODg|RzJodLhmw=S~uaKlAfm!?y9y9B&8tPa+~VOyiw zU4~sXBGCisO;))Q763&HMx7A~y(GV~HCvb}W=F%QWImgHC0Q_Hz=5&FN%GLkHKHTZ zD~mm$RxqNuqPYTQZjXjF@QPIQ`3j}5?4)uN+hEZSW{E=(E>bx!*#+bFP0Dxq1r@$T zanC9CcGlgBk~NjXo&#PDHPUko9j2+9ID80B8MrBBTB6$d&Ev$~e0Fm+yiADbWoAwL zn)D)4dASZ^dB&*i7gk$El25SOAy@kTvtJtSu}=(Sus4jMLt9{C#`dHuPFX~bre^Rc z1P(>;ielwpT_q9+1$(esbBgf{x173Bjm7zC3Xv zfR0v^r%%7XVuC|5wO!4-^`ZF@ra2vyu1@=^e_w2xezQ96vt=Z0!K|WJ6TOtIDLP7n zkEz4;icmM{pFCn1l^hynQZ5cm#%NKkpc$jtk7CSZm8#&^C>VnkYL#k>1=U-ffjR{7 z12o)Gfty{1Tuael2epf;X1|(Tdg;@Ln=FloL!i&|1L`+FhMn+LnttYHZoypxv9Zd} zORT$~66%4W_Ml%zOY%KwOyeqt?6KGTpj5-Nl~T=9AwpHa%faIiAYd}n73(YiztO_g?~NNXY1wf*O`x>@E7zF{7_pa-b{&S5r7@QQ7ri%D#o?kGZqGg4F zppm89H=7>Cy5Q@-;5D7YY4}LS*u=jFGdymNdj{&c3-l+{nYp;%*&o4p1$^oJ=N1BZ zE+L1{<-dP*+(mIr4OdQTne6h!FWwkHHJSBBWU_9OUWZz#+06&VFI)Fm+6ibNr@ zgwjcDBU*)rDWyWCe50cDp_lV&!D|VLsV(TZ{a!T08RRn4)vV%X(KYnKJeVPZ$Px(! z9J;4zZ>hq`e75$(YxS|BZ$&FiBQi#~R;d@{v-qfH@6sT(MB7qVz3l$IG7ec|Gg^gKY@>PwSwcwD-=WQ?>{1%5XnuYu_wO{&=F$6PGG{S=Gtlq^zVs0) zpngDKiejA!8Akb>zef z*t+osQN-41mdNl#Z>}A%Len|l{&)lH3a>lfWJEOZ8E)GM9fb3HVV+wxOy&C=K`r&t z!z9Tt(^cr3Zu;I^!D^UJoND)mdHj#r{MzO|B;+dQ9>l8{t?D@Tez(M~mb1z%;Zhy6 zMI;cPVBeihx$A&pXY=!dzkV3>InO*pT)b=^8RW^!*_3$_dl>A=gY&0TTtX@Wm>fl3 zDtL3kctHJ`zLJO02CiX>H=8RFeHoBZ!^bR|v;H%#Bo5|9!trpg8T1L6-AAsf-Mt`V9VK7fBi|E=2_ zB_=UUc9(`mhaEL^2!b}-!llpHx-FNLEK|i7;rVwgJ(OBxPM_7KuERKc3>Bg^R1}r_ z!r5?z63vdh`{>!td^KZ>^QU~D`sI-k~U$eyBmsZ5j}!gxx?)FH@XZjGY(cn`Ds+03V@;yXNh zv34b-XPC9NV9FSbSRz17AKK73xUOdZ2;##zsT7_fLIq8F()FAF_a9Kdihd=X%T;{o z^jWS{-LCj?3h<}PW?VkCVQ82ldU?*U$e2`Zf03lvJP?6$E`@#01hHY&sd%9~edB~! z&YDb`StrkHDk&hwWA9h+XFDiYLp;6wG*=H(&dnzJYX&d3p#s>(T>y&o?5@e|+^EfF@M4RRT+$DQDQ+F}&98`Y zOYrD494uPf2NzutV6)119(_GjHXg!TTQEAr{>i=hdT@Ptr-%f%%u_S{t8yK@byKu9Ku+=X zj;`-Ow!h*VVbfF5?jaVDYk_W)^iNpsrfR6JNvuUkA%^Fc=e(mNEAA=M(H^L)()=c> znC5U^G>q%(37K^0V2WNnYy7k2q9_)1duwk~dvC4h5R`(59tM zWRnIShWc}#mz^zM{SBLLx|A!ghnj~hwPkx-=k{7|hvGkx%dHo_OB2DpCBypb3C{@n zl0Hz%=iou`Ig;O|h?8L?`nB}Zh31RwxsUAXpTO_%cr+j5t@%@#QdD@_mLAQT5qwy? z!Qdg4jp*w)GfF9OhgxcOzDYO6FFMCP5R(kcAwJW@Q_m9G<9jn}g64B54g9@}Y)w~j zN}M}3UkP(2{Ydx>;-Mb6Gfjj{@zcu;o_>FrZ1nJ3Bi+rA&?JIofd)hT{Uh9nJXp3K zU_|?c>O-e7g#cho$VQY^fUV5|+9A*?b1+_-L(EKd;wS(n>$;da$_!00s&0_}n z!_V}uW(;`lW;y&nXS04l{lkUs@Hn>nPJ>6g(+1C<4t){hEh7_z!^0Ru#x|8*FF8#Z zxWT9r(e`jP6!G$IQOh^IjJb^1Y}$W5Z^g73#Xkc6HQ?EGi%(v_>{-f@pTU|%W-wAs z>p<1}8Q%(o7r>llh__B#SrCKFX64|ODrO3eIy=%>w@$dYb#-({H}D*mq)iuAJ3UY- zrIt2XBkDb3$a>S-5192D@IM?{cf3!$@%^h635FxpbOAS(h`Jm2ieg{EzD(rgeSpd@ zeYmp<^qszr$itO7x1d}yTiTJk$Cfb=ey-=ct5D zWSLj1W9Vcd01II5N0ArwSQ1jiP_NxXG%R!1YkRuC#k0%hm|1yP5cJed`ZaLXne-5V z5g`x*>kf}9hiEZ-4quR^XwXHBlDug;L?X6Lzupq^n?Jb)*0iNsUkU#ndRxmA#_HrU zOCgOdR0LxnU@L{kZ!?9rTi1Q$$-Kof`q|~Q;(y%DubyH(=Mae0N1i1xD(sao`bc!c zYT+|s%%iFCK`5%Gira%wo)=syN;@T!TNICoTUPJ-Q>{J4n4zNeOGHuWCVx{amJ^G* zVf0|HO^?Ae3K%VJU9?p)b=Whm!TkGc1b*5JN0Q&!=YsdlCDh;@r@%d z=!HqhsL4~!F+wH|@$waTHe>1U^BY1~L*Z_xip-;Vcp*=M;!R`A20#QCBeX5sgkjXT@f0QatW>H}!sRB%HL#1Zm zr04rp?u8L+0v zZ1+^J2!3IrY>bF#hpE=`0#e6%{{)JE&I2c4>TuQB*-7nk*mSOBvE{)`raS7{rTVXo!4N7-?H z@1$6Mq2;;&u4P8^QShGex#@P*OGMQUg?=<~#Gj?aZqxgl8lA68s;&r_4-e*^K~0$X z8N@Gr*<9bu4mucHE*4n_&@fxg@|Gu4iD-AY&}m{pgrF|HG6o47)QtJ zNN~Kx8;%HNWdfl?Jy>=csk<5aYuQ;L_h`hIB!BQNxvNt7{JFc;vXd(scXTr7&Ne{5G0@_T=w#6JCZ_J@l$> zUiP(l)R1C%CgBdFQs7b=LXB7Pv0<7XCrn|Bku!p)PkkaHOmC}^O;L$?RF`qsMKm(6_q=TRG^AJ`QG>mR{eDuDR`L-a>8N)aOHC zOaq|9E|$7irbvBT*$m6i{@E}xc!p95M%APvP}tvVuy)WNFn+?mh8;P~h~6TCR)i)0%xxY$~@8p$@={5O4odeydJ$2#465g3Mh) zy(ew|D7lOMvIk*dDs?u!)G}@wYS5SL6}8R#_!e3jhEh z07*naR3q%&y?weJ2^(9Ca%YvA%^!Jrje~@?@d1B!UyF3hl)VmaB!<<^uCm!h`{uVT z;W}>JMW&+ZfrqgZWH!v`LB`S5)vbVG7t0dsws%`!YAIAsx~%IrSAAL*n4akEGJR_6 z5ClVXaL?k;0eDMfj(k9}s=eVW;O~^VRM@vCN6=$P>z^%}c-1Y#4$s;zPw_;a2wwKk zsfK)d@>#`p+sPJjAcxyV3p|B7+8_(T;pK{}fIq)+sb>UxTM)Bayu}^24x(S`CSr-Z z(0g0dTJEii>DM0zx;C*z<6hVi7VE~XwcSI!!7&e4!?r&a^hzR*;g^`l5|9=%>mqB} z)&w4-Ji1Nww?n{5+EufVJ4Mt{zpCvUb`+hZAxRC*;a?>w*2z1kyCA}ieciRdc^LSH z)NFnNUuBTW7H~ZWwQU76Lc)s}^eD~FQHaI_&OEX!G2K|3n*-P;a?~nh&!O5R;~m+e zE&mEj+3h|Sz}JAM(Y_JF?5`H}JDktwmcTQ&iaOHtv291t*u+(a#;q|pTOs32(D*K7$(bVp7Rq9H%!TnvV#FRSz5E7#OLL+I55l zaho@FBbE!Mjt`-9(}qYp!kU2iHYeWP@IoJNoujB}p2$~Et(hJ`-#=60klwP36~thi z!Kok)N57hB-`+0I6a34av|jF3e;iW=4Tl#IcJMmUtEa~DuYmvQV4F4;6-*OLDM{yN zOJSwXs)XS$6--s7$T*w*ENVy>k%wk)lre1M6D7cC4;#mgpv~3jOLfjj!BgEy*I+cJ z%}M)lP~Grhn4^Z-F4h3_BvRVCGY3DCm#1R; z8&z%ybBV9yf_> z_r;z`hjIK!YA2CH564IJrgzsA!7}v2MmDdhp7z(PEpd9&#CN~zhPH?@rv9DpeC4u* zTJ-HBY03AH*EtRUuoN_n6d( z8mWWOXY48y=1&uQi)Qb>ef(}?%&>;;t8WaiZ2@7_%Aj&+-&$jJr3E*kpeoFAJz|gq;ff#s7sTW%0O~Ee)qh-Z^r`dXQ2#)9srjW>z z^Touo`Y`7|{qPpai;|gu35tqyliG1+TY`m44vt-^=Acy_4Bw0(_=sjj5mOZLebh(~ z;Scdc6G^6!$JiS5ToJsi--|ACrya)ZS-g+wVZW)82@iuT$=h0nHUnu(#k(p*9yzs3 zg$mXlnk?2ag_a$BdyKI*{5hmJ<^W$Qys29reHqD^1+Qf6tsMS>c=c^q!8dw*hpcyx z9nRqpjzg&%DtOmW0Z1pg_2MPpA12Knhn8pro)BNts2N% zo*lQD#BnD!t0l?<*L~yOfvWVJ!MFt6EDw?7%+btDyLOq@R1!LTgbJ-)Dn@T^JI5sY z&~f5+Rwy=e37Q_fU#1|GBzx@$nLp%$9A<$*{g;&CS**sEDd=FRsBXw~u(d*QT4k`w@2CTDgW8V6S z=scb;M>+7O0((x}xtMt#-qH2PGCO$iJiR8vbLb&5C~x<#WY`Ob`w#DJE28(joCr2>$b2hJgsewXublh%oN0)eW4qOTU?!5l= z0);diS;grh7}hVAWmepu=lp(q;JMYOikv~dlK%4i!zPzW+yK`(*PTh%V$I-RSMdCV z_&unp=%zYG1FP#;+}zV_&r|9&_9pCI2DMCb$qj4ER=-^R*ErUA&iSF2E{F0<9!ujg z$mWO}CYHpwE%^lLAES=rF|$qz_(tuj@}>#iu!QN_yU%3I7s?!VLR&jjhLEm`12o0|8d$?&E_dUJ4X4~atZnD4 zH}QvfPjOpe^#GOj2FPezo#^BqmJe-JOe$}Eb?|H45>xf_ws#$M&uL7I+}h7$+koui zH@koReTFJMiKusrc<}Fhn;^&xQu705z^8iWdJKo`W<&}uenJ0&{MlSTH5kgDhHULk z{rn96{71+RpU@P}mUVFxHp4)Sh$0&Gv=6~@Ix&`FwQokUM|qK!(8?ZIL!oH9Wa{S9 zd+NsLG~dz+qM@!p)&}wRIIv#gY%m&?w_(>*(cpXQ0mU#czRvjGEtIO(Er-w(9HYI> zBFv2s7cksUGU?0$2qOQ&2yE{2`ovwMFdm3Yo8AZ9?ewcBUb4!;rUwiye$Y)O-0oIqZia@=8-C zw3{hyN0wf3GqcO5!XSvJQu`#Z@)XU}zUm`7Sk{^Ur+TJF+~ZjuA?$s@GmZUE>|5r) zFWbEKv1^w-UDzlv&jKfcA5r4mjnf}1l+C+L*#P7T}fOn=^#4*yKqDwOWxD3d&d ze>7Z=X8xD-`ur4TksF>-EQVOWAxc}AxR}Hd`tTqAEp-eZO|UtOH%dfLZEIN~;<9Az7eNnE-YO;^a#GC~-% zj21gY(rAe^PFvHVR;OLn%XeT)g6#!KmBFu(#Iw~hz1&b&+PO$>q6`^J^w@qdKEaMW znVLzYi^}lxNOu+zPMS-9ne7{S;~GZ`)ppJh$R(GO;|MldRINwY2Vg>cLOh!_u<1H<4QKu!D?Af1mnydh~OK zQ4aN~-HQxI@02&;@X8;hd(Uhl&VRv;PVFvPm(+0zx5v+tWvn1y2_fjSH)pAOwRLTq z-L=>8`aRRb(3(0AO@h=eoE=_EqZVq0vR<1=nl?Q&^2v7LbADKy2Re@Hs7V>|&8hHa zQg|s&4=Z#eG0N5}7;Xv2IXtIH$`U8w7RVayysb9Fx9mUqhxgAj&hp+7;?JJvg-YT* z9RY6q#b(@H(g!9<)X>duL{i}xbbIaJS)w^Lbv!Ts@REk%=9v_`%I3tyF(se=2-}5N zS8#RRhK7>!$z&;a@f_mZomqbkh58sEczt7YJLoJsFxnW6PA z!>ji4fEfMF_VadEJ9@w-)2<)W%QBA%Mp>CvZ(RiziIV^65iFnKakH%AMm-N@tQL;#i$(*9LPLzJo6=%D^{|=DQ~8@2Q>8*EI{3=;%Th>=EPDuY^Zbvs z?7=#_sShLqq zChV=Kms@Ldj0gD-xYy&94V{j-R1Ze2U|J9oJy--EYf$+%mp&;c`uH=~e?|m0W7oIs zCCk%5L=HIXPF};t#y^TH<-pZX;IAdY-CuPtIV`+x<^mqcdI-a>tO5V zw=*oony>~uCah=?E8Yu)?u8Ov!XeITSMlB6j^no*#mV{Kh9Q`bxNo-z?LQDp24PI||%d^fzD{~t&FyZl}hAlE?MQBrI#$9j)dAF^2Xx068 zFkzL~vC5cYmljQ4E%8VYJn_DQsXlv-Al%NjRc%4rsZ><=yumK}7VKlSYlG}qas>C3 z^7#0_5}WkvNTvPW5A+ho1&$2t_yfo8_vW{=Rlp|N@;Fw}*S(poTUoi89h*Iiuc39M ze7sMT3JZxAv1)61tIF$fgIV`WtK(f;!N>2&?CC1|PdYnd%|Gb-Mh}PRUU7!U3T^UIr!$!+N!fc9w>7~@yudP5i=-tw8I-YvfoxPXNYu= zx&EfN3-@Qkn>VgZ=4|p)0Dn9@*LQ8yxxMP-05ti{=-^-z-@}G~IeOa2OaFKY>hGnt zvBF!k-tNLSp4hioBE1LcY~nu5;F{WsmYl*fS(oMza={PA!)@(Mt$eE>y~Zw|Z`nFe zz5K)bpSL4w*-2etZe{b8@M{F?JH_iPgQ#I642^cj&YS8kLZjW?oyuKJSaPQHDdzWP zvq_`AJvQ^#D85X@Jfq7t#2NeBM(_OQDVm5h~g-_9BBm!E|MJV3#-BO9>}Q`EE8M(HLGc9h??Z|>%@uAxu#(B^dOK?aer9~9?nzeJ)Z{xmUg^?zH>~C#FOrLc9gXEawIw5a) z=+&+}M4rWx`#5|aq0*^Kj6u|qcGtH<;004`iBfL=pKNkZ(=>}Q+H%Fx8-QNMLuo4{J%ysD-HqC ztCQD}TI+$#!@_g1w}-ceUgiN#dEv~$%c88-ZFvpI>1y93ka?Q6wwW>JFz&o_a=^pG3)FdaJ#c^{hCjx+tVOZN~(vKWN3Ma3`i>>Nm|l*}|LlQa5g3J=kyn^}3MKSe}a?sw4Z7*+elLCFT;}W|Iz)rMeSU5(VH91m$qUz0X-|Scj%4`zr6=NDVqjNDM|kfz z=w@s~@2#Cethl25j1Z`z5 zaS)&Sj|dh-t8|!`=j}sdsO#IaDAxv!Pyr*$I%5#=t=Y?&!n-E!@*n;$Q&pj{_rg$lt+Y3`;` z!3Z&O>LYmiXKQk%(r)lh2cyLn+Q;pDD!a^hTN2s*nf}m<_jo1sk|SArhhKkFtR5>Y z`a22aeZUSM@bu*!b zJ>I(t_-OVYLH{Aw)4UXs!Zn5RnG8W5c2S?7BjF*<+_0O4s9JSPlvcx+*}eK?;|A38 zNVHELv)*5{7dGjVeC7`K!3eAszCDc@DLeF@x~~>JndIpX#{{wA>2gydBGS z!ehUwho>nZT-e6(A@J~I2!rUayH*m_(d}v7o74{Dr~D$kk^9~p(%&|w#@qcnJhe=3 zNB0!7hry#1CH^-t(s{igUs{TlwW*lGKm6TC?0eo-7TrWP>$6#ZXuh%^o?(o$&~4aS zz8K}|qeLG0q?wOMW)$NiB&kAqx=@kvJou2+FW57`O^j4Av@H)mmgi;?#bFZj9!~7d zd}3xof$17%W>#ut}R-)LzqqaXKEC~ub=ama;oixZ65C|JjOK^; zX|PW5t!?Lvw0oY0Kr!u>I-34nH@zP4nsP*Hw<31^J=r?{PBA;e+&8n zb4X}WB|o4r#9UtV*rhdSVGN+%l2sR#!Dy|Znf4V3)6DZ5gXeQ=ukQUmy}q`P=Wp11 zNYTd=kR6VMnlF?ImUsPdkj@m%{jAEVkY(f;+xp1Vzy|m+;MKC5E2E%i+`n2bYk4V+ zCGqs- z+D*K?wR;^pl_=zW*2?bkL(~vNTgoB?zz@01g#Xj_BPrfZlwtrk=>-uWy3Hw(u zj)Wdnpd;dlP+GpI5}yli1_ z|N7$#Sk=S@Yc!7u^=Rs$D5gsxv&gH09~1W1i5>!cUQS~@f_@C*6Y@h*puOkeMe-GO z)5wq3vQ86pYdei*ngJaYbG*D7_8?GaHOa&NKl6w=adPI_clKv9zo4bd<6Rn zn@F2;aN4Y`MUA;tDF0=Bi+a@w#_MegukdN#fkq^_$3`yl{%gFRRyB*L z=Cjvf>BfBs&NS|o@Rz*;I=E4=Xu+j9y$WG@oeGk7XC0IZv+u+_4r7{qHP1_&f<5I3 z(#Iy%EqCpMY)UtFZC!_al~71CmB$(Da!-531b!X!sU{wlTzju!p(^`0ndWz9l{b1s zPOowoM?fQ5+0`Da7s@VQfvXu8ds>exEDglfUA@WIEY~uKm1%)zdMM1 z#IwWd>}Yp3>8)c44zS;^aF zs5jE;*ktq4A36m2Tq*86E^4t116+}5s~uYJqAYlc$lQ^e*DHy-k((cr|V? z&}P|Q;@LMZ#w_ZsUGgMTUd7F>B*%Nz%b&oX=G9lf?J?5-IYU}_Q36Vs$K~mi8|pCn z)-6Ara@hQJ!QW@M4*gy&8 zt3Z@Ox1&**rz^uH!?Ee*R?NQ1!FNY^tnz&T?uFS~Jc5mE^Y=)42yN6xv*MX@{#>K& zS^T!srM%y#oAFQuDAiTm*1WZ$zJ?ZWAHl1?S2_&VYOlA|HquK_{s;InxiVb!4#TXY z&_aflj4Gx_(rxRvK6`?Pc?+rWv6f0W^d0dha{1~}_kO?fm^q?l963ug?2z^CF~qjN z684C^H;J(=qw{Cb%KNsAO@p$9mQ~=TS6f^-9xJJ-Tiw0yZbS<>tTRX%S^dk@xU(Fq ztWVs#nYOt-!vkR!LLak_`baN+*t3Yd*OTeub<@bQvYi2lOSDP#KW)b{)!JiMWGWXil^r4&^uF@=G-h6_(O{B4>@nM8y zwMU+=+-Zf&d*%H(1a8x;Al9}L`~75450s;mcP+Gq)yGlbe52oo|GaQyNjr~hcNoi& z?KYw`1|kV~5-;<~&(1@WMzfDPTYf_u)60w7$uyT&&h;RB!A^EBTf(e6f<+{e%gZv% z!ig>7Z0O}PU{>w_udB1$lHd-Eo%qhJPu^OB=M#KFQD&PdlDx+5nmxXLqTj<;os7dL~h zQK@Sv)!K$N4eN(CikG$wMlg{FSKYLXorGI^s})-&XL%xJL(8CE)mk~HQxd&+D#us( z$eqk?zB52D2Jq0}^!9cVYtIyR@O;4*aux{S>IX&4M+;^kaZ8)KKB}R~X%uFnRCRLi z@lzW5Z17VW@@beaQ${kq_-@+zjocHbp<@=4^X$r|ZzTg2v+z?t3o~o9O_Y|ydf1ld z3oreiHkp)-4{ipzkICj+@C|EK?u*kCzYA00*xXgvRx;v8v6!r(4FYI18C=qIf5h z6)Vk~8Nr3ZFED6gg=@SjF{syeO!xl3J)Sv9C%36q$agKKG}2x+>EUr;e9*=<2hU`` zwPvoQGwFjGfPC;>Wfp>C6!rN0iyi(j%v%E^4W*`Y=+z5f_cy!^PD>_H6;FX2jErAK z_c7QBMdbDv+Jmk1)2X`{4$Kb@-OLJj(V%)QdLSAAQc6J$U+nE6>Z|mFE;I|60aD-F5(8RF*1<(N$ z#+iT{0~qSTr3of`>kXgUX_e=MsW&?mDlwBGk-Yo)Mb8Ypb5M8dL*kRv<{bL#l9f%}QIl$9OBhd1Sl0kfvepHkgUse^g}Zyj=c^_MRQ(goySz_^Uo?y00P>tnU!PaQUI z_?-9{g&zt0Q%xH`sFV`NM=K+CT{*-OAXq9}g1!?*oMY%u+@SOzbFM8MvcP!3-F(Sf9WL% zI+_5TqVnDDjWgO88v9&Bz-T4Jg{&Q9x0lkl_i)<81nQhIk| z+e;e!Hf>COMdNfVFMVV-c)XgN>a&=HK0kr+Dc;~0zW}C;1M7oG{E)@2q%&-P@YE2@ zrD7hsdQ6eI*#S{@zIbadf&QG)4?wr5lbXgke83|2atm6rSfnIh>e;nWu@7wuT{=LV zKh#q*dS@I7EHQJSurQJj#P=#hCH|=?36*W+u+-du3&?=MS8KarfO;v9m((T>X-XVZhM8$f)Q;rFEwVj(wcpHuAuq9Z2JdfINm<3abV9p(-LGY} z?OEI{HY6ZWs9eBtumR9Nt{`j?0!w(ZNizZKg30i-8Y)o7@!OdxJiJ{^b zw$Nm0z>>*nS?0hMiRF{))+TFaKM+FMY~Ou*C9zclJIKPg&aLEU)>Ulv#!I__Y9*4k zuSmimIQimL(@0(~#p&iL@-jN-fR1RE0Rl^=Xky|ixsY`nTTgh=3prgs(Ad_a(z~mp z&DkP$b`baD3`ZQHnb_8X>qAkDS(_9LrFJg1LuOPWf)Bw9td?C1qf@MeG>7A4>GtN! zPk>&j4a_R6!I?!Cvk49}Pz2Ge4M%UOdLZss5SpD*T$jk*Q`@Colg7t_BP%Z3)SmE+jewS96ScEMg3hYY66&! zuH{sF>y4hj(QJC-I(sUx8OkcGGNyj4zUq2B{I-3Qv^z7mP_;dcAr@jE+1|k%si}m1 zUze}ZYVeBGX}2-Edkop`Rw+*o)M59Drr0eP*>3p+ikBoB&w?{$lj^;D( z2Ouf2&I4*#APXo}xz^I1*`rPy+>~KZ2~?b*HQUEqcV@}sMsOatQYdpVXAgz%DEtaO zY!0J`zL((W2>3(|=B3%B^0%P0tgB!j1^WPE7E)kn!@#h@lvvfk-h1T0g}|#Ekx9+| z_SyrH6E1Zxx12^1#una$9;ml?doN^2GCuV0EOm07=$U>CQ*Gcr0o?w8U5N#5NLl<#2it_QcaYmEy8+WHqJv@Ppnjkc)77aYqAwWP!E!Gv=- zG>UJCML(IkMvU$t>mE7*bLQ_1m+7NqC`sTOfd58eiQW;tz)*C3hbfwxZl-|)F^GJ} zqkwM)yQrDx%~ZJClxc<#a;X8W!wL^Gyn?^0t;MRpTx!|w3~XcLQmgI3l_UfULd&;@vVn7(DWSLAEtKw+7*0$( ze<#YI{zBm=>Y!g#qL+dY()7m9L=GqR{hOm62ESZ_Q(fm9t1WZ+?Y%Gu@UJW^CnkQil5AHHfvSO2gh~iy zhXGPW!HBkgOG4|<4Aa_`@u}_GqmB>wD8rZ9QRLa~MNW}ZnTS?$5|tAv(`oA_qYIRg z$YZs+0XQ6iOn!br@1hHo949t9??!sSB0i03~fry*w1Iwvoi4QJLFcsb`*Gwh_kTwW-4o$#D8p@VZO*C{$ zmop~uaKj1()(UiOb|Z0-JG5~)bO3G9OEn`|s8=b8D@Xh337qWXy+R3Kve`LD#TgEp zq>wlFk=JRL5iL*&uBRnUvMMRB3m-*_`?GzC$BBvIM`YBF-(ybjAiddeoPFl3v#Ngc2>a80a45y?_VPQ3$ROfqi~IH#s{M7_ixiySwC5`I6DQ!_n3HnCAR9fU#0k8Qz4 zTjR$B9yjp2^OZCX9V4d&{6`n4zq_i}hfni2>)fy&& z4wG37=QJ^;vRz59gdD6y$ssY}Bz@FHR4P}RDt_KfAqReZ(x`XLY4NDn5=!hG_NCK9 z89O-0H8ZT@8_mT>;kLrdCt|4bpM)gE1n*#h+_ygm!Bzu5+lMKxFcFMubr3^GU|DOZ{qQW7+# z!c1Nul7$U&a-jRHii(^P9m~?T!sZ|(_jN-R>-*FZ@2EKw(S}FgCH4N2H{j_MrKV9h z+7HwWK`lPGeO&s>*0N)(T7LKgAgO$~hBd~}i;@O!DAg03fK!q+`Q*}5Ap7_*87*9~ zHEpJlNoAACq^$A6Y|)Ge>Ek64hxQI`flRV`yq}`Z5qe|$SA}vBcvJoWK> ztp6GK`et}eYU$@E7jt$M?B78BhhuN39`OvG@<<6e3lkG`<~onLSDBfvgu1Tyh!qt?fQ1#i>@>-WU728a+M&s%nXu)2M0OSVHj5>J`K!9 ze4IKF(X)->71V;**&dgY`9-I#2g;_#x&&%Iirgd{B!J+m0-*;@Ub{K;;eshC8v2Ax=d_BuJ=a{LQD$Ma8oOEjM zFaQmdU8)cgHiVG%p)Wl#f(hUw^6X00nrwQGu`F>ngp|NvMzo2AE6nlmcFa2VB{2hn zAxVN>e4^JZ*b7@yR29n0CB>tIk}OzE9#_7i5!;^^g z^L2C0m;I&3_Wwr#k%ku>&%uW!yePOta%^gIPv^Xs?d`;E9IOghJUBM)4c0X3kp86!J-`9lu}oxBJsr%~|XVmYa{ z7-C7L;6%R`kKrhhZo|dFRh~}rEw!G2i9BUmGSFPwop=2|4L1RWHk6B7hL=+a62TxS zU(NoNwmt!~slBxn%H8ja24P;h4rovT3iaY0zc-sHF0j+DNE;SsFTWQxdALai=iY!q zR3>rZq;l_8PF;lwa%pG4)U`{wK8wo`51_u$I?vI8tmo>W=QPAmL;ma)gBDF*%x}7U z>pEtEox^H3wUCoa2J2;B@A5rLO6@kZ%C%^r+$3PGFuVfzH5kjb_tNs8`Qnm;h%vQ% z-9r`c(I!><=GnbvvZ&|*M0+p8x*%n+iDYq{G(0ii5Ufi1gvH706TQodBy1bDvkbio z_9{j;mn`e1902`uP2fLi_!{IHAv$>44y_yZ=MYA2C{*a@TSs4y-gv6JK+$+Q0DRKv z^yv9Wz1iI-AB_6Wadth`LYnFV6|7viVJztv6kusu76HK(e}EcIot#Wf zZ8Z}xR{%fFu<}jMpS|bT@+Ucs>kk83J2ISDJMiB9zC#Es2sj>RO-Yj|!OYS2DY0z^ z6eeAMOdUIo#9`Jud*$F1yA>~k4~9ASkO$_d`$lAKA0v$OhPzmM++Hv(B%D3~x_+^O zBkhQ7!0a#VX@!>!Dv=}z9o6DYrHA%-8#Kf6B&v=n(E#k+y{Qa@-!gdK^X&Ouq(`=s zn)FN7?T!t)s0UED6vA4IH&~U>DOxe`5&XH zfkp#6nYL(SA(g08frJ^N*_6qWrF6jNqUNAm*UXpsinqHe1$M~HO`UUi6$mzk=EeZ`i0I@N~)Z~RGUb? z-Z8b5%%3fJp{8v_cFwHibU$^ zurH;WH%zGotj4>NQ>#!H(uTS|tChEtK!KP$cPf{|3r{b+^ue7Eu$*Z|`hQ*d# z)e!ZpIM_}v#7v$nJswCqsV8Yj8)~t)yjo%p+o@tEzrbi3i1Dgy@3?7xZ9UtM{3A57 z-3j~#6=nNQz?L07g|qo`VAdr|lAS8p;kpHd6xzM@?8})!-+O6`k{B`H`enm1 zM`GbN!>fgl$32NhI%|0`=1H+a5ve;q2# zldWZCO*A?C6u@@N#=Q{-WEr{D)o7*fM&dUQsSYJvMewlP1vqooF3F`^gRe2|bgF5_ z`ryMQZm_q4g%h|c+ONsQ@wezx zJ09q&?Pe}h%zS4VcmD5=uxX^gVz4t3pKiFl6xqW4yRYP1j|sUTs6|i>l3Ve{nSwiG zcI}bKt6xOlOMs1?SAb;Y`SMxHxNK#UQ@Xe0(X7H_*EI~2j^zOTRSi?yTYY5XB0LAJ(U$e@vv^KqsETb=Ua!2irqUV7`dnm;lbU%e?qI7O8WI0|{xXf`&!sg#N z*okk%CR(Rz>ie8Elu*a3G*@>vl8$9-`cDDJsqBzq_|LKKbYkSQWdqVPc(!aFTjW~e zG?GBJ5G&zRISfsYZsQP$)W3#fjxKWQ;8BKdWyhAh?qLavDV630`(7AV;{KViUx{3a zmz1h&4y=((-9{km675@gx{66-a+vMS8c%vTfcpe!9B-bM(yUO!u&i(o(y|MK>|S*T zHK>bE?K_58{Pv<1Y^=n8dEuV{+^GbU4qfVnaQl3IHLDp6}nWvsYdp<57k>K;48DIWw!hAY4L&JFh--9Z#oyebfKCB{gsmAZa3 zCQw^0U>qK0m_EiIY9DWLxfv}{c9vlK=t$aUj60hHh42BYxrSAP(J^l@> z$z_LY$Ye`u5B;+M$5LYUI$W5|hmrDEmbg`p=QQ@UT?CaOG}sBTg0ee`nDC{115Gv` zMkmd`XQIk+4?ciP5iIx{@J|xQhRJ-Q`T8uDhhwYxcXPTidywI_kVwU?Ib=Syfly~~ zZH~)PTlC!FLm7YNg*B8eTA{q?5WSSge+I>#v5HjEbwHNg5vJP~j?Tuz_!d8mJxH*| zjVojs*fR%i?L^6(pz3CP(C8O3MWj}%s6eg@RyWx{FtXZf9`D;8A$K3%!Hn2>JrGc_ z3Ru(eWkI-tOqu-uh?q?b%q6kuqWjqwr+in4B&x;Ne|h0I3~O?#c8@}Sr_~HYZ;qR+ ziPTK!w$PD{%|oD_D{*Ob@Cxh{mY%lIa_)Kvq_U9QY_IZok)Q)yuQaZ*SEFh*s8UD= zSJw5p|L>29!2tMt%$Jp1gFM}evB%oTbL#}kV=MoxvVl_LY&*y_sF zvowsG3#?HC(^4s*2ckR&@Hv4mXM4LooUZCYEl4`8RS)e3P?ENz6TPVe^J42bx5tMc z>x!;{0;oxZz7-u;Vh_aN&c0x0Dky@uSK-5x^7qNi<8qF>8|zt?JBt}8+}g^v8!dxV gMoYrLm+F-N1M82l_OpCl^Z)<=07*qoM6N<$g1e6Q^Z)<= literal 0 HcmV?d00001 diff --git a/files/shaders/water_vertex.glsl b/files/shaders/water_vertex.glsl new file mode 100644 index 000000000..7d7b7b18a --- /dev/null +++ b/files/shaders/water_vertex.glsl @@ -0,0 +1,22 @@ +#version 120 + +varying vec3 screenCoordsPassthrough; +varying vec4 position; +varying float depthPassthrough; + +void main(void) +{ + gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; + + mat4 scalemat = mat4(0.5, 0.0, 0.0, 0.0, + 0.0, -0.5, 0.0, 0.0, + 0.0, 0.0, 0.5, 0.0, + 0.5, 0.5, 0.5, 1.0); + + vec4 texcoordProj = ((scalemat) * ( gl_Position)); + screenCoordsPassthrough = vec3(texcoordProj.x, texcoordProj.y, texcoordProj.w); + + position = gl_Vertex; + + depthPassthrough = gl_Position.z; +} From 700a0099c3737f9cb1c976459a6cfa2073667908 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 28 Oct 2015 16:13:40 +0100 Subject: [PATCH 2299/3725] Remove debug code --- apps/openmw/mwrender/npcanimation.cpp | 4 +-- apps/openmw/mwrender/renderingmanager.cpp | 33 ----------------------- apps/openmw/mwrender/sky.cpp | 5 +--- apps/openmw/mwrender/water.cpp | 2 -- apps/openmw/mwrender/water.hpp | 3 --- 5 files changed, 3 insertions(+), 44 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 17f0ce73c..0b3838a33 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -324,9 +324,9 @@ public: virtual void drawImplementation(osgUtil::RenderBin* bin, osg::RenderInfo& renderInfo, osgUtil::RenderLeaf*& previous) { - //renderInfo.getState()->applyAttribute(mDepth); + renderInfo.getState()->applyAttribute(mDepth); - //glClear(GL_DEPTH_BUFFER_BIT); + glClear(GL_DEPTH_BUFFER_BIT); bin->drawImplementation(renderInfo, previous); } diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 2aaba3035..b9132dc8c 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -198,39 +198,6 @@ namespace MWRender mFieldOfView = Settings::Manager::getFloat("field of view", "General"); updateProjectionMatrix(); mStateUpdater->setFogEnd(mViewDistance); - - /* - osg::Texture2D* texture = new osg::Texture2D; - texture->setSourceFormat(GL_DEPTH_COMPONENT); - texture->setInternalFormat(GL_DEPTH_COMPONENT24_ARB); - texture->setSourceType(GL_UNSIGNED_INT); - - mViewer->getCamera()->attach(osg::Camera::DEPTH_BUFFER, texture); - - osg::ref_ptr camera (new osg::Camera); - camera->setProjectionMatrix(osg::Matrix::identity()); - camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF); - camera->setViewMatrix(osg::Matrix::identity()); - camera->setClearMask(0); - camera->setRenderOrder(osg::Camera::NESTED_RENDER); - camera->setAllowEventFocus(false); - - osg::ref_ptr geode (new osg::Geode); - osg::ref_ptr geom = osg::createTexturedQuadGeometry(osg::Vec3f(-1,-1,0), osg::Vec3f(0.5,0,0), osg::Vec3f(0,0.5,0)); - geode->addDrawable(geom); - - camera->addChild(geode); - - osg::StateSet* stateset = geom->getOrCreateStateSet(); - - stateset->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON); - stateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF); - - stateset->setRenderBinDetails(20, "RenderBin"); - stateset->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF); - - mLightRoot->addChild(camera); - */ } RenderingManager::~RenderingManager() diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 30dc08989..5938fb13c 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1,9 +1,6 @@ #include "sky.hpp" #include -#include - -#include #include #include @@ -264,7 +261,7 @@ public: META_Node(MWRender, CameraRelativeTransform) - virtual bool computeLocalToWorldMatrix(osg::Matrix& matrix, osg::NodeVisitor* nv) const + virtual bool computeLocalToWorldMatrix(osg::Matrix& matrix, osg::NodeVisitor*) const { if (_referenceFrame==RELATIVE_RF) { diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index cf361a504..b2354924a 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -2,8 +2,6 @@ #include -#include - #include #include #include diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index 78e8a4927..a75464612 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -9,9 +9,6 @@ namespace osg { class Group; class PositionAttitudeTransform; - class Texture2D; - class Image; - class Camera; } namespace osgUtil From 37c9c12962f74fd26543b7cdf8b0063928c78e1b Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 28 Oct 2015 18:54:49 +0100 Subject: [PATCH 2300/3725] Water: clipping plane offset --- apps/openmw/mwrender/water.cpp | 19 ++++++++++--------- files/shaders/water_fragment.glsl | 4 ++-- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index b2354924a..97e0df1b6 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -142,8 +142,6 @@ class ClipCullNode : public osg::Group osg::Polytope::PlaneList origPlaneList = cv->getProjectionCullingStack().back().getFrustum().getPlaneList(); - // TODO: offset plane towards the viewer to fix bleeding at the water shore - osg::Plane plane = *mCullPlane; plane.transform(*cv->getCurrentRenderStage()->getInitialViewMatrix()); @@ -175,18 +173,21 @@ class ClipCullNode : public osg::Group { osgUtil::CullVisitor* cv = static_cast(nv); osg::Vec3d eyePoint = cv->getEyePoint(); + + osg::RefMatrix* modelViewMatrix = new osg::RefMatrix(*cv->getModelViewMatrix()); + // flip the below graph if the eye point is above the plane if (mCullPlane->intersect(osg::BoundingSphere(osg::Vec3d(0,0,eyePoint.z()), 0)) > 0) { - osg::RefMatrix* modelViewMatrix = new osg::RefMatrix(*cv->getModelViewMatrix()); modelViewMatrix->preMultScale(osg::Vec3(1,1,-1)); - - cv->pushModelViewMatrix(modelViewMatrix, osg::Transform::RELATIVE_RF); - traverse(node, nv); - cv->popModelViewMatrix(); } - else - traverse(node, nv); + // move the plane back along its normal a little bit to prevent bleeding at the water shore + const float clipFudge = 5; + modelViewMatrix->preMultTranslate(mCullPlane->getNormal() * (-clipFudge)); + + cv->pushModelViewMatrix(modelViewMatrix, osg::Transform::RELATIVE_RF); + traverse(node, nv); + cv->popModelViewMatrix(); } private: diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index 01e0816bc..5860120ab 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -21,8 +21,8 @@ const float WAVE_CHOPPYNESS = 0.05; // wave choppyness const float WAVE_SCALE = 75.0; // overall wave scale const float BUMP = 0.5; // overall water surface bumpiness -const float REFL_BUMP = 0.15; // reflection distortion amount -const float REFR_BUMP = 0.06; // refraction distortion amount +const float REFL_BUMP = 0.10; // reflection distortion amount +const float REFR_BUMP = 0.07; // refraction distortion amount const float SCATTER_AMOUNT = 0.3; // amount of sunlight scattering const vec3 SCATTER_COLOUR = vec3(0.0,1.0,0.95); // colour of sunlight scattering From 9f2f503d3747533b6ea223829b998b1f0bd93c51 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 28 Oct 2015 18:59:35 +0100 Subject: [PATCH 2301/3725] Water: pass the near and far planes --- apps/openmw/mwrender/renderingmanager.cpp | 3 +++ files/shaders/water_fragment.glsl | 7 ++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index b9132dc8c..dcf4406bb 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -198,6 +198,9 @@ namespace MWRender mFieldOfView = Settings::Manager::getFloat("field of view", "General"); updateProjectionMatrix(); mStateUpdater->setFogEnd(mViewDistance); + + mRootNode->getOrCreateStateSet()->addUniform(new osg::Uniform("near", mNearClip)); + mRootNode->getOrCreateStateSet()->addUniform(new osg::Uniform("far", mViewDistance)); } RenderingManager::~RenderingManager() diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index 5860120ab..994d74964 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -68,6 +68,9 @@ uniform sampler2D normalMap; uniform float osg_SimulationTime; +uniform float near; +uniform float far; + void main(void) { // FIXME @@ -160,10 +163,8 @@ void main(void) #if REFRACTION float refractionDepth = texture2D(refractionDepthMap, screenCoords-(normal.xy*REFR_BUMP)).x; // make linear - float zNear = 5; // FIXME - float zFar = 6666; // FIXME float z_n = 2.0 * refractionDepth - 1.0; - refractionDepth = 2.0 * zNear * zFar / (zFar + zNear - z_n * (zFar - zNear)); + refractionDepth = 2.0 * near * far / (far + near - z_n * (far - near)); float waterDepth = refractionDepth - depthPassthrough; From d485dd0782d95bca5f16a8841ca37c5677ea4efd Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 28 Oct 2015 19:11:32 +0100 Subject: [PATCH 2302/3725] Water: fix world UV coords --- apps/openmw/mwrender/water.cpp | 5 +++++ files/shaders/water_fragment.glsl | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 97e0df1b6..b56f21754 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -458,6 +458,11 @@ void Water::changeCell(const MWWorld::CellStore* store) mWaterNode->setPosition(getSceneNodeCoordinates(store->getCell()->mData.mX, store->getCell()->mData.mY)); else mWaterNode->setPosition(osg::Vec3f(0,0,mTop)); + + // create a new StateSet to prevent threading issues + osg::ref_ptr nodeStateSet (new osg::StateSet); + nodeStateSet->addUniform(new osg::Uniform("nodePosition", osg::Vec3f(mWaterNode->getPosition()))); + mWaterNode->setStateSet(nodeStateSet); } void Water::setHeight(const float height) diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index 994d74964..d7c0e1e6b 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -70,11 +70,11 @@ uniform float osg_SimulationTime; uniform float near; uniform float far; +uniform vec3 nodePosition; void main(void) { - // FIXME - vec3 worldPos = position.xyz; // ((wMat) * ( position)).xyz; + vec3 worldPos = position.xyz + nodePosition.xyz; vec2 UV = worldPos.xy / (8192.0*5.0) * 3.0; UV.y *= -1.0; From 51e40cf1b853e7aa6653750715eae9082b63c48d Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 28 Oct 2015 19:13:55 +0100 Subject: [PATCH 2303/3725] Water: minor shader cleanup --- files/shaders/water_fragment.glsl | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index d7c0e1e6b..8dcd73fab 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -34,6 +34,8 @@ const float SPEC_HARDNESS = 256.0; // specular highlights hardne const vec2 WIND_DIR = vec2(0.5f, -0.8f); const float WIND_SPEED = 0.2f; +const vec3 WATER_COLOR = vec3(0.090195, 0.115685, 0.12745); + // -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - float fresnel_dielectric(vec3 Incoming, vec3 Normal, float eta) @@ -160,6 +162,8 @@ void main(void) vec3 R = reflect(vVec, normal); float specular = pow(max(dot(R, lVec), 0.0),SPEC_HARDNESS) * shadow; + vec3 waterColor = WATER_COLOR; + waterColor = waterColor * length(gl_LightModel.ambient.xyz); #if REFRACTION float refractionDepth = texture2D(refractionDepthMap, screenCoords-(normal.xy*REFR_BUMP)).x; // make linear @@ -168,14 +172,12 @@ void main(void) float waterDepth = refractionDepth - depthPassthrough; - vec3 waterColor = vec3(0.090195, 0.115685, 0.12745); - waterColor = waterColor * length(gl_LightModel.ambient.xyz); if (cameraPos.z > 0.0) refraction = mix(refraction, waterColor, clamp(waterDepth/VISIBILITY, 0.0, 1.0)); gl_FragData[0].xyz = mix( mix(refraction, scatterColour, lightScatter), reflection, fresnel) + specular * gl_LightSource[0].specular.xyz; #else - gl_FragData[0].xyz = mix(reflection, vec3(0.090195, 0.115685, 0.12745), (1.0-fresnel)*0.5) + specular * gl_LightSource[0].specular.xyz; + gl_FragData[0].xyz = mix(reflection, waterColor, (1.0-fresnel)*0.5) + specular * gl_LightSource[0].specular.xyz; #endif // fog From 09631385c37f76821461d37e54623434fb9830f6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 28 Oct 2015 19:25:46 +0100 Subject: [PATCH 2304/3725] Use boost ifstream for water resources --- apps/openmw/mwrender/water.cpp | 45 ++++++++++++++++++++++++++++--- files/shaders/water_fragment.glsl | 1 - 2 files changed, 41 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index b56f21754..af9fae04a 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -16,6 +16,9 @@ #include // XXX remove +#include +#include + #include #include @@ -264,6 +267,41 @@ void addDebugOverlay(osg::Texture2D* texture, int pos, osg::Group* parent) parent->addChild(debugCamera); } +osg::ref_ptr readShader (osg::Shader::Type type, const std::string& file) +{ + osg::ref_ptr shader (new osg::Shader(type)); + + // use boost in favor of osg::Shader::readShaderFile, to handle utf-8 path issues on Windows + boost::filesystem::ifstream inStream; + inStream.open(boost::filesystem::path(file)); + std::stringstream strstream; + strstream << inStream.rdbuf(); + shader->setShaderSource(strstream.str()); + return shader; +} + +osg::ref_ptr readPngImage (const std::string& file) +{ + // use boost in favor of osgDB::readImage, to handle utf-8 path issues on Windows + boost::filesystem::ifstream inStream; + inStream.open(file, std::ios_base::in | std::ios_base::binary); + if (inStream.fail()) + std::cerr << "Failed to open " << file << std::endl; + osgDB::ReaderWriter* reader = osgDB::Registry::instance()->getReaderWriterForExtension("png"); + if (!reader) + { + std::cerr << "Failed to read " << file << ", no png readerwriter found" << std::endl; + return osg::ref_ptr(); + } + osgDB::ReaderWriter::ReadResult result = reader->readImage(inStream); + if (!result.success()) + std::cerr << "Failed to read " << file << ": " << result.message() << " code " << result.status() << std::endl; + + return result.getImage(); +} + + + Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem *resourceSystem, osgUtil::IncrementalCompileOperation *ico, const MWWorld::Fallback* fallback, const std::string& resourcePath) : mParent(parent) @@ -399,17 +437,16 @@ Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem addDebugOverlay(reflectionTexture, 2, mParent); // shader - // FIXME: windows utf8 path handling? - osg::ref_ptr vertexShader (osg::Shader::readShaderFile(osg::Shader::VERTEX, resourcePath + "/shaders/water_vertex.glsl")); + osg::ref_ptr vertexShader (readShader(osg::Shader::VERTEX, resourcePath + "/shaders/water_vertex.glsl")); - osg::ref_ptr fragmentShader (osg::Shader::readShaderFile(osg::Shader::FRAGMENT, resourcePath + "/shaders/water_fragment.glsl")); + osg::ref_ptr fragmentShader (readShader(osg::Shader::FRAGMENT, resourcePath + "/shaders/water_fragment.glsl")); osg::ref_ptr program (new osg::Program); program->addShader(vertexShader); program->addShader(fragmentShader); - osg::ref_ptr normalMap (new osg::Texture2D(osgDB::readImageFile(resourcePath + "/shaders/water_nm.png"))); + osg::ref_ptr normalMap (new osg::Texture2D(readPngImage(resourcePath + "/shaders/water_nm.png"))); normalMap->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT); normalMap->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT); normalMap->setMaxAnisotropy(16); diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index 8dcd73fab..c11c18a2d 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -166,7 +166,6 @@ void main(void) waterColor = waterColor * length(gl_LightModel.ambient.xyz); #if REFRACTION float refractionDepth = texture2D(refractionDepthMap, screenCoords-(normal.xy*REFR_BUMP)).x; - // make linear float z_n = 2.0 * refractionDepth - 1.0; refractionDepth = 2.0 * near * far / (far + near - z_n * (far - near)); From 6ba9f561ea9656034912075654b78c93605b59aa Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 28 Oct 2015 19:39:22 +0100 Subject: [PATCH 2305/3725] Use simple water for the local map --- apps/openmw/mwrender/localmap.cpp | 2 +- apps/openmw/mwrender/renderingmanager.cpp | 2 +- apps/openmw/mwrender/vismask.hpp | 13 +++++++------ apps/openmw/mwrender/water.cpp | 11 ++++++----- 4 files changed, 15 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index fe685f97c..e479119ee 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -173,7 +173,7 @@ osg::ref_ptr LocalMap::createOrthographicCamera(float x, float y, f camera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); camera->setRenderOrder(osg::Camera::PRE_RENDER); - camera->setCullMask(Mask_Scene|Mask_Water|Mask_Terrain); + camera->setCullMask(Mask_Scene|Mask_SimpleWater|Mask_Terrain); camera->setNodeMask(Mask_RenderToTexture); osg::ref_ptr stateset = new osg::StateSet; diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index dcf4406bb..b0fe98565 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -191,7 +191,7 @@ namespace MWRender mViewer->getCamera()->setComputeNearFarMode(osg::Camera::DO_NOT_COMPUTE_NEAR_FAR); mViewer->getCamera()->setCullingMode(cullingMode); - mViewer->getCamera()->setCullMask(~(Mask_UpdateVisitor)); + mViewer->getCamera()->setCullMask(~(Mask_UpdateVisitor|Mask_SimpleWater)); mNearClip = Settings::Manager::getFloat("near clip", "Camera"); mViewDistance = Settings::Manager::getFloat("viewing distance", "Camera"); diff --git a/apps/openmw/mwrender/vismask.hpp b/apps/openmw/mwrender/vismask.hpp index fc63cddbb..7faae4602 100644 --- a/apps/openmw/mwrender/vismask.hpp +++ b/apps/openmw/mwrender/vismask.hpp @@ -16,18 +16,19 @@ namespace MWRender Mask_Player = (1<<4), Mask_Sky = (1<<5), Mask_Water = (1<<6), - Mask_Terrain = (1<<7), - Mask_FirstPerson = (1<<8), + Mask_SimpleWater = (1<<7), + Mask_Terrain = (1<<8), + Mask_FirstPerson = (1<<9), // top level masks - Mask_Scene = (1<<9), - Mask_GUI = (1<<10), + Mask_Scene = (1<<10), + Mask_GUI = (1<<11), // Set on a Geode - Mask_ParticleSystem = (1<<11), + Mask_ParticleSystem = (1<<12), // Set on cameras within the main scene graph - Mask_RenderToTexture = (1<<12) + Mask_RenderToTexture = (1<<13) // reserved: (1<<16) for SceneUtil::Mask_Lit }; diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index af9fae04a..c090dfbfe 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -301,7 +301,6 @@ osg::ref_ptr readPngImage (const std::string& file) } - Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem *resourceSystem, osgUtil::IncrementalCompileOperation *ico, const MWWorld::Fallback* fallback, const std::string& resourcePath) : mParent(parent) @@ -319,16 +318,18 @@ Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem geode->addDrawable(waterGeom); geode->setNodeMask(Mask_Water); - // TODO: node mask to use simple water for local map - if (ico) ico->add(geode); - //createSimpleWaterStateSet(mResourceSystem, geode); - mWaterNode = new osg::PositionAttitudeTransform; mWaterNode->addChild(geode); + // simple water fallback for the local map + osg::ref_ptr geode2 (osg::clone(geode.get(), osg::CopyOp::DEEP_COPY_NODES)); + createSimpleWaterStateSet(mResourceSystem, geode2); + geode2->setNodeMask(Mask_SimpleWater); + mWaterNode->addChild(geode2); + mSceneRoot->addChild(mWaterNode); setHeight(mTop); From 7bbdb131383f566ba63f93f8533aad5af1931c32 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 28 Oct 2015 19:57:20 +0100 Subject: [PATCH 2306/3725] Remove debug code --- apps/openmw/mwrender/water.cpp | 35 +--------------------------------- 1 file changed, 1 insertion(+), 34 deletions(-) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index c090dfbfe..58e80a271 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -14,7 +14,7 @@ #include #include -#include // XXX remove +#include #include #include @@ -239,34 +239,6 @@ public: } }; -void addDebugOverlay(osg::Texture2D* texture, int pos, osg::Group* parent) -{ - osg::ref_ptr debugCamera (new osg::Camera); - debugCamera->setProjectionMatrix(osg::Matrix::identity()); - debugCamera->setReferenceFrame(osg::Transform::ABSOLUTE_RF); - debugCamera->setViewMatrix(osg::Matrix::identity()); - debugCamera->setClearMask(0); - debugCamera->setRenderOrder(osg::Camera::NESTED_RENDER); - debugCamera->setAllowEventFocus(false); - - const float size = 0.5; - osg::ref_ptr debugGeode (new osg::Geode); - osg::ref_ptr geom = osg::createTexturedQuadGeometry(osg::Vec3f(-1 + size*pos, -1, 0), osg::Vec3f(size,0,0), osg::Vec3f(0,size,0)); - debugGeode->addDrawable(geom); - - debugCamera->addChild(debugGeode); - - osg::StateSet* debugStateset = geom->getOrCreateStateSet(); - - debugStateset->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON); - debugStateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF); - - debugStateset->setRenderBinDetails(20, "RenderBin"); - debugStateset->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF); - - parent->addChild(debugCamera); -} - osg::ref_ptr readShader (osg::Shader::Type type, const std::string& file) { osg::ref_ptr shader (new osg::Shader(type)); @@ -432,11 +404,6 @@ Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem mParent->addChild(reflectionCamera); - // debug overlay - addDebugOverlay(refractionTexture, 0, mParent); - addDebugOverlay(refractionDepthTexture, 1, mParent); - addDebugOverlay(reflectionTexture, 2, mParent); - // shader osg::ref_ptr vertexShader (readShader(osg::Shader::VERTEX, resourcePath + "/shaders/water_vertex.glsl")); From ebdf25ccb942b0128facd18a06d36fb120d98ecf Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 28 Oct 2015 19:57:58 +0100 Subject: [PATCH 2307/3725] Water: move refraction code to a new class --- apps/openmw/mwrender/water.cpp | 136 +++++++++++++++++++++------------ apps/openmw/mwrender/water.hpp | 5 ++ 2 files changed, 94 insertions(+), 47 deletions(-) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 58e80a271..17e804052 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -273,6 +273,88 @@ osg::ref_ptr readPngImage (const std::string& file) } +class Refraction : public osg::Camera +{ +public: + Refraction() + { + unsigned int rttSize = Settings::Manager::getInt("rtt size", "Water"); + setRenderOrder(osg::Camera::PRE_RENDER); + setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT); + setReferenceFrame(osg::Camera::RELATIVE_RF); + + setCullMask(Mask_Effect|Mask_Scene|Mask_Terrain|Mask_Actor|Mask_ParticleSystem|Mask_Sky|Mask_Player|(1<<16)); + setNodeMask(Mask_RenderToTexture); + setViewport(0, 0, rttSize, rttSize); + + // No need for Update traversal since the scene is already updated as part of the main scene graph + // A double update would mess with the light collection (in addition to being plain redundant) + setUpdateCallback(new NoTraverseCallback); + + // No need for fog here, we are already applying fog on the water surface itself as well as underwater fog + getOrCreateStateSet()->setMode(GL_FOG, osg::StateAttribute::OFF|osg::StateAttribute::OVERRIDE); + + mClipCullNode = new ClipCullNode; + addChild(mClipCullNode); + + mRefractionTexture = new osg::Texture2D; + mRefractionTexture->setTextureSize(rttSize, rttSize); + mRefractionTexture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); + mRefractionTexture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); + mRefractionTexture->setInternalFormat(GL_RGB); + mRefractionTexture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR); + mRefractionTexture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); + + attach(osg::Camera::COLOR_BUFFER, mRefractionTexture); + + mRefractionDepthTexture = new osg::Texture2D; + mRefractionDepthTexture->setSourceFormat(GL_DEPTH_COMPONENT); + mRefractionDepthTexture->setInternalFormat(GL_DEPTH_COMPONENT24_ARB); + mRefractionDepthTexture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); + mRefractionDepthTexture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); + mRefractionDepthTexture->setSourceType(GL_UNSIGNED_INT); + mRefractionDepthTexture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR); + mRefractionDepthTexture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); + + attach(osg::Camera::DEPTH_BUFFER, mRefractionDepthTexture); + } + + void setScene(osg::Node* scene) + { + if (mScene) + mClipCullNode->removeChild(mScene); + mScene = scene; + mClipCullNode->addChild(scene); + } + + void setWaterLevel(float waterLevel) + { + mClipCullNode->setPlane(osg::Plane(osg::Vec3d(0,0,-1), osg::Vec3d(0,0, waterLevel))); + } + + osg::Texture2D* getRefractionTexture() const + { + return mRefractionTexture.get(); + } + + osg::Texture2D* getRefractionDepthTexture() const + { + return mRefractionDepthTexture.get(); + } + +private: + osg::ref_ptr mClipCullNode; + osg::ref_ptr mRefractionTexture; + osg::ref_ptr mRefractionDepthTexture; + osg::ref_ptr mScene; +}; + +class Reflection : public osg::Camera +{ + +}; + Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem *resourceSystem, osgUtil::IncrementalCompileOperation *ico, const MWWorld::Fallback* fallback, const std::string& resourcePath) : mParent(parent) @@ -309,54 +391,13 @@ Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem const float waterLevel = -1; // refraction - unsigned int rttSize = Settings::Manager::getInt("rtt size", "Water"); - osg::ref_ptr refractionCamera (new osg::Camera); - refractionCamera->setRenderOrder(osg::Camera::PRE_RENDER); - refractionCamera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - refractionCamera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT); - refractionCamera->setReferenceFrame(osg::Camera::RELATIVE_RF); - - refractionCamera->setCullMask(Mask_Effect|Mask_Scene|Mask_Terrain|Mask_Actor|Mask_ParticleSystem|Mask_Sky|Mask_Player|(1<<16)); - refractionCamera->setNodeMask(Mask_RenderToTexture); - refractionCamera->setViewport(0, 0, rttSize, rttSize); - - // No need for Update traversal since the mSceneRoot is already updated as part of the main scene graph - // A double update would mess with the light collection (in addition to being plain redundant) - refractionCamera->setUpdateCallback(new NoTraverseCallback); - - // No need for fog here, we are already applying fog on the water surface itself as well as underwater fog - refractionCamera->getOrCreateStateSet()->setMode(GL_FOG, osg::StateAttribute::OFF|osg::StateAttribute::OVERRIDE); - - osg::ref_ptr clipNode (new ClipCullNode); - clipNode->setPlane(osg::Plane(osg::Vec3d(0,0,-1), osg::Vec3d(0,0, waterLevel))); - - refractionCamera->addChild(clipNode); - clipNode->addChild(mSceneRoot); + mRefraction = new Refraction(); + mRefraction->setWaterLevel(waterLevel); + mRefraction->setScene(mSceneRoot); // TODO: add ingame setting for texture quality - osg::ref_ptr refractionTexture = new osg::Texture2D; - refractionTexture->setTextureSize(rttSize, rttSize); - refractionTexture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); - refractionTexture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); - refractionTexture->setInternalFormat(GL_RGB); - refractionTexture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR); - refractionTexture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); - - refractionCamera->attach(osg::Camera::COLOR_BUFFER, refractionTexture); - - osg::ref_ptr refractionDepthTexture = new osg::Texture2D; - refractionDepthTexture->setSourceFormat(GL_DEPTH_COMPONENT); - refractionDepthTexture->setInternalFormat(GL_DEPTH_COMPONENT24_ARB); - refractionDepthTexture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); - refractionDepthTexture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); - refractionDepthTexture->setSourceType(GL_UNSIGNED_INT); - refractionDepthTexture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR); - refractionDepthTexture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); - - refractionCamera->attach(osg::Camera::DEPTH_BUFFER, refractionDepthTexture); - - mParent->addChild(refractionCamera); + mParent->addChild(mRefraction); // reflection osg::ref_ptr reflectionCamera (new osg::Camera); @@ -368,6 +409,7 @@ Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem reflectionCamera->setCullMask(Mask_Effect|Mask_Scene|Mask_Terrain|Mask_Actor|Mask_ParticleSystem|Mask_Sky|Mask_Player|(1<<16)); reflectionCamera->setNodeMask(Mask_RenderToTexture); + unsigned int rttSize = Settings::Manager::getInt("rtt size", "Water"); reflectionCamera->setViewport(0, 0, rttSize, rttSize); // No need for Update traversal since the mSceneRoot is already updated as part of the main scene graph @@ -430,8 +472,8 @@ Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem shaderStateset->addUniform(new osg::Uniform("normalMap", 3)); shaderStateset->setTextureAttributeAndModes(0, reflectionTexture, osg::StateAttribute::ON); - shaderStateset->setTextureAttributeAndModes(1, refractionTexture, osg::StateAttribute::ON); - shaderStateset->setTextureAttributeAndModes(2, refractionDepthTexture, osg::StateAttribute::ON); + shaderStateset->setTextureAttributeAndModes(1, mRefraction->getRefractionTexture(), osg::StateAttribute::ON); + shaderStateset->setTextureAttributeAndModes(2, mRefraction->getRefractionDepthTexture(), osg::StateAttribute::ON); shaderStateset->setTextureAttributeAndModes(3, normalMap, osg::StateAttribute::ON); shaderStateset->setMode(GL_BLEND, osg::StateAttribute::ON); // TODO: set Off when refraction is on shaderStateset->setMode(GL_CULL_FACE, osg::StateAttribute::OFF); diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index a75464612..46b6382e7 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -29,6 +29,8 @@ namespace MWWorld namespace MWRender { + class Refraction; + class Reflection; class RippleSimulation; /// Water rendering @@ -44,6 +46,9 @@ namespace MWRender std::auto_ptr mSimulation; + osg::ref_ptr mRefraction; + osg::ref_ptr mReflection; + bool mEnabled; bool mToggled; float mTop; From 11c997d09d59ef846c566bf65e862e5aff36946b Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 28 Oct 2015 20:09:44 +0100 Subject: [PATCH 2308/3725] Water: move reflection code to a new class --- apps/openmw/mwrender/water.cpp | 107 ++++++++++++++++++++------------- 1 file changed, 64 insertions(+), 43 deletions(-) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 17e804052..f8a39f40b 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -352,7 +352,66 @@ private: class Reflection : public osg::Camera { +public: + Reflection() + { + setRenderOrder(osg::Camera::PRE_RENDER); + setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT); + setReferenceFrame(osg::Camera::RELATIVE_RF); + + setCullMask(Mask_Effect|Mask_Scene|Mask_Terrain|Mask_Actor|Mask_ParticleSystem|Mask_Sky|Mask_Player|(1<<16)); + setNodeMask(Mask_RenderToTexture); + + unsigned int rttSize = Settings::Manager::getInt("rtt size", "Water"); + setViewport(0, 0, rttSize, rttSize); + + // No need for Update traversal since the mSceneRoot is already updated as part of the main scene graph + // A double update would mess with the light collection (in addition to being plain redundant) + setUpdateCallback(new NoTraverseCallback); + + mReflectionTexture = new osg::Texture2D; + mReflectionTexture->setInternalFormat(GL_RGB); + mReflectionTexture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR); + mReflectionTexture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); + mReflectionTexture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); + mReflectionTexture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); + + attach(osg::Camera::COLOR_BUFFER, mReflectionTexture); + + // XXX: should really flip the FrontFace on each renderable instead of forcing clockwise. + osg::ref_ptr frontFace (new osg::FrontFace); + frontFace->setMode(osg::FrontFace::CLOCKWISE); + getOrCreateStateSet()->setAttributeAndModes(frontFace, osg::StateAttribute::ON); + + mClipCullNode = new ClipCullNode; + addChild(mClipCullNode); + } + + void setWaterLevel(float waterLevel) + { + setViewMatrix(osg::Matrix::translate(0,0,-waterLevel) * osg::Matrix::scale(1,1,-1) * osg::Matrix::translate(0,0,waterLevel)); + + mClipCullNode->setPlane(osg::Plane(osg::Vec3d(0,0,1), osg::Vec3d(0,0,waterLevel))); + } + void setScene(osg::Node* scene) + { + if (mScene) + mClipCullNode->removeChild(mScene); + mScene = scene; + mClipCullNode->addChild(scene); + } + + osg::Texture2D* getReflectionTexture() const + { + return mReflectionTexture.get(); + } + +private: + osg::ref_ptr mReflectionTexture; + osg::ref_ptr mClipCullNode; + osg::ref_ptr mScene; }; Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem *resourceSystem, osgUtil::IncrementalCompileOperation *ico, @@ -400,51 +459,13 @@ Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem mParent->addChild(mRefraction); // reflection - osg::ref_ptr reflectionCamera (new osg::Camera); - reflectionCamera->setRenderOrder(osg::Camera::PRE_RENDER); - reflectionCamera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - reflectionCamera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT); - reflectionCamera->setReferenceFrame(osg::Camera::RELATIVE_RF); - - reflectionCamera->setCullMask(Mask_Effect|Mask_Scene|Mask_Terrain|Mask_Actor|Mask_ParticleSystem|Mask_Sky|Mask_Player|(1<<16)); - reflectionCamera->setNodeMask(Mask_RenderToTexture); - - unsigned int rttSize = Settings::Manager::getInt("rtt size", "Water"); - reflectionCamera->setViewport(0, 0, rttSize, rttSize); - - // No need for Update traversal since the mSceneRoot is already updated as part of the main scene graph - // A double update would mess with the light collection (in addition to being plain redundant) - reflectionCamera->setUpdateCallback(new NoTraverseCallback); - - osg::ref_ptr reflectionTexture = new osg::Texture2D; - reflectionTexture->setInternalFormat(GL_RGB); - reflectionTexture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR); - reflectionTexture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); - reflectionTexture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); - reflectionTexture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); - - reflectionCamera->attach(osg::Camera::COLOR_BUFFER, reflectionTexture); - - reflectionCamera->setViewMatrix(osg::Matrix::translate(0,0,-waterLevel) * osg::Matrix::scale(1,1,-1) * osg::Matrix::translate(0,0,waterLevel)); - - osg::ref_ptr reflectNode (new osg::MatrixTransform); - - // XXX: should really flip the FrontFace on each renderable instead of forcing clockwise. - osg::ref_ptr frontFace (new osg::FrontFace); - frontFace->setMode(osg::FrontFace::CLOCKWISE); - reflectNode->getOrCreateStateSet()->setAttributeAndModes(frontFace, osg::StateAttribute::ON); - - osg::ref_ptr clipNode2 (new ClipCullNode); - clipNode2->setPlane(osg::Plane(osg::Vec3d(0,0,1), osg::Vec3d(0,0,waterLevel))); - - reflectNode->addChild(clipNode2); - clipNode2->addChild(mSceneRoot); - - reflectionCamera->addChild(reflectNode); + mReflection = new Reflection(); + mReflection->setWaterLevel(waterLevel); + mReflection->setScene(mSceneRoot); // TODO: add to waterNode so cameras don't get updated when water is hidden? - mParent->addChild(reflectionCamera); + mParent->addChild(mReflection); // shader @@ -471,7 +492,7 @@ Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem shaderStateset->addUniform(new osg::Uniform("refractionDepthMap", 2)); shaderStateset->addUniform(new osg::Uniform("normalMap", 3)); - shaderStateset->setTextureAttributeAndModes(0, reflectionTexture, osg::StateAttribute::ON); + shaderStateset->setTextureAttributeAndModes(0, mReflection->getReflectionTexture(), osg::StateAttribute::ON); shaderStateset->setTextureAttributeAndModes(1, mRefraction->getRefractionTexture(), osg::StateAttribute::ON); shaderStateset->setTextureAttributeAndModes(2, mRefraction->getRefractionDepthTexture(), osg::StateAttribute::ON); shaderStateset->setTextureAttributeAndModes(3, normalMap, osg::StateAttribute::ON); From 9f8d36b57332c039f1850942aa435958cd5049d2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 28 Oct 2015 20:24:52 +0100 Subject: [PATCH 2309/3725] Water code cleanup --- apps/openmw/mwrender/water.cpp | 150 ++++++++++++++++-------------- apps/openmw/mwrender/water.hpp | 11 +++ files/shaders/water_fragment.glsl | 4 +- 3 files changed, 94 insertions(+), 71 deletions(-) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index f8a39f40b..121b07654 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -82,41 +82,6 @@ namespace return waterGeom; } - void createSimpleWaterStateSet(Resource::ResourceSystem* resourceSystem, osg::ref_ptr node) - { - osg::ref_ptr stateset (new osg::StateSet); - - osg::ref_ptr material (new osg::Material); - material->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(1.f, 1.f, 1.f, 1.f)); - material->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 0.7f)); - material->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 1.f)); - material->setColorMode(osg::Material::OFF); - stateset->setAttributeAndModes(material, osg::StateAttribute::ON); - - stateset->setMode(GL_BLEND, osg::StateAttribute::ON); - stateset->setMode(GL_CULL_FACE, osg::StateAttribute::OFF); - - osg::ref_ptr depth (new osg::Depth); - depth->setWriteMask(false); - stateset->setAttributeAndModes(depth, osg::StateAttribute::ON); - - stateset->setRenderBinDetails(MWRender::RenderBin_Water, "RenderBin"); - - std::vector > textures; - for (int i=0; i<32; ++i) - { - std::ostringstream texname; - texname << "textures/water/water" << std::setw(2) << std::setfill('0') << i << ".dds"; - textures.push_back(resourceSystem->getTextureManager()->getTexture2D(texname.str(), osg::Texture::REPEAT, osg::Texture::REPEAT)); - } - - osg::ref_ptr controller (new NifOsg::FlipController(0, 2/32.f, textures)); - controller->setSource(boost::shared_ptr(new SceneUtil::FrameTimeSource)); - node->addUpdateCallback(controller); - node->setStateSet(stateset); - stateset->setTextureAttributeAndModes(0, textures[0], osg::StateAttribute::ON); - } - } namespace MWRender @@ -419,6 +384,7 @@ Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem : mParent(parent) , mSceneRoot(sceneRoot) , mResourceSystem(resourceSystem) + , mResourcePath(resourcePath) , mEnabled(true) , mToggled(true) , mTop(0) @@ -427,19 +393,19 @@ Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem osg::ref_ptr waterGeom = createWaterGeometry(CELL_SIZE*150, 40, 900); - osg::ref_ptr geode (new osg::Geode); - geode->addDrawable(waterGeom); - geode->setNodeMask(Mask_Water); + mWaterGeode = new osg::Geode; + mWaterGeode->addDrawable(waterGeom); + mWaterGeode->setNodeMask(Mask_Water); if (ico) - ico->add(geode); + ico->add(mWaterGeode); mWaterNode = new osg::PositionAttitudeTransform; - mWaterNode->addChild(geode); + mWaterNode->addChild(mWaterGeode); // simple water fallback for the local map - osg::ref_ptr geode2 (osg::clone(geode.get(), osg::CopyOp::DEEP_COPY_NODES)); - createSimpleWaterStateSet(mResourceSystem, geode2); + osg::ref_ptr geode2 (osg::clone(mWaterGeode.get(), osg::CopyOp::DEEP_COPY_NODES)); + createSimpleWaterStateSet(geode2); geode2->setNodeMask(Mask_SimpleWater); mWaterNode->addChild(geode2); @@ -453,31 +419,65 @@ Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem mRefraction = new Refraction(); mRefraction->setWaterLevel(waterLevel); mRefraction->setScene(mSceneRoot); - - // TODO: add ingame setting for texture quality - mParent->addChild(mRefraction); // reflection mReflection = new Reflection(); mReflection->setWaterLevel(waterLevel); mReflection->setScene(mSceneRoot); + mParent->addChild(mReflection); - // TODO: add to waterNode so cameras don't get updated when water is hidden? + createShaderWaterStateSet(mWaterGeode, mReflection, mRefraction); - mParent->addChild(mReflection); + // TODO: add ingame setting for texture quality +} - // shader +void Water::createSimpleWaterStateSet(osg::Node* node) +{ + osg::ref_ptr stateset (new osg::StateSet); - osg::ref_ptr vertexShader (readShader(osg::Shader::VERTEX, resourcePath + "/shaders/water_vertex.glsl")); + osg::ref_ptr material (new osg::Material); + material->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(1.f, 1.f, 1.f, 1.f)); + material->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 0.7f)); + material->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 1.f)); + material->setColorMode(osg::Material::OFF); + stateset->setAttributeAndModes(material, osg::StateAttribute::ON); - osg::ref_ptr fragmentShader (readShader(osg::Shader::FRAGMENT, resourcePath + "/shaders/water_fragment.glsl")); + stateset->setMode(GL_BLEND, osg::StateAttribute::ON); + stateset->setMode(GL_CULL_FACE, osg::StateAttribute::OFF); + + osg::ref_ptr depth (new osg::Depth); + depth->setWriteMask(false); + stateset->setAttributeAndModes(depth, osg::StateAttribute::ON); + + stateset->setRenderBinDetails(MWRender::RenderBin_Water, "RenderBin"); + + std::vector > textures; + for (int i=0; i<32; ++i) + { + std::ostringstream texname; + texname << "textures/water/water" << std::setw(2) << std::setfill('0') << i << ".dds"; + textures.push_back(mResourceSystem->getTextureManager()->getTexture2D(texname.str(), osg::Texture::REPEAT, osg::Texture::REPEAT)); + } + + osg::ref_ptr controller (new NifOsg::FlipController(0, 2/32.f, textures)); + controller->setSource(boost::shared_ptr(new SceneUtil::FrameTimeSource)); + node->addUpdateCallback(controller); + node->setStateSet(stateset); + stateset->setTextureAttributeAndModes(0, textures[0], osg::StateAttribute::ON); +} + +void Water::createShaderWaterStateSet(osg::Node* node, Reflection* reflection, Refraction* refraction) +{ + osg::ref_ptr vertexShader (readShader(osg::Shader::VERTEX, mResourcePath + "/shaders/water_vertex.glsl")); + + osg::ref_ptr fragmentShader (readShader(osg::Shader::FRAGMENT, mResourcePath + "/shaders/water_fragment.glsl")); osg::ref_ptr program (new osg::Program); program->addShader(vertexShader); program->addShader(fragmentShader); - osg::ref_ptr normalMap (new osg::Texture2D(readPngImage(resourcePath + "/shaders/water_nm.png"))); + osg::ref_ptr normalMap (new osg::Texture2D(readPngImage(mResourcePath + "/shaders/water_nm.png"))); normalMap->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT); normalMap->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT); normalMap->setMaxAnisotropy(16); @@ -487,26 +487,33 @@ Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem osg::ref_ptr shaderStateset = new osg::StateSet; shaderStateset->setAttributeAndModes(program, osg::StateAttribute::ON); - shaderStateset->addUniform(new osg::Uniform("reflectionMap", 0)); - shaderStateset->addUniform(new osg::Uniform("refractionMap", 1)); - shaderStateset->addUniform(new osg::Uniform("refractionDepthMap", 2)); - shaderStateset->addUniform(new osg::Uniform("normalMap", 3)); - - shaderStateset->setTextureAttributeAndModes(0, mReflection->getReflectionTexture(), osg::StateAttribute::ON); - shaderStateset->setTextureAttributeAndModes(1, mRefraction->getRefractionTexture(), osg::StateAttribute::ON); - shaderStateset->setTextureAttributeAndModes(2, mRefraction->getRefractionDepthTexture(), osg::StateAttribute::ON); - shaderStateset->setTextureAttributeAndModes(3, normalMap, osg::StateAttribute::ON); - shaderStateset->setMode(GL_BLEND, osg::StateAttribute::ON); // TODO: set Off when refraction is on - shaderStateset->setMode(GL_CULL_FACE, osg::StateAttribute::OFF); + shaderStateset->addUniform(new osg::Uniform("normalMap", 0)); + shaderStateset->addUniform(new osg::Uniform("reflectionMap", 1)); + shaderStateset->addUniform(new osg::Uniform("refractionMap", 2)); + shaderStateset->addUniform(new osg::Uniform("refractionDepthMap", 3)); + + shaderStateset->setTextureAttributeAndModes(0, normalMap, osg::StateAttribute::ON); + shaderStateset->setTextureAttributeAndModes(1, reflection->getReflectionTexture(), osg::StateAttribute::ON); + if (refraction) + { + shaderStateset->setTextureAttributeAndModes(2, refraction->getRefractionTexture(), osg::StateAttribute::ON); + shaderStateset->setTextureAttributeAndModes(3, refraction->getRefractionDepthTexture(), osg::StateAttribute::ON); + shaderStateset->setRenderBinDetails(MWRender::RenderBin_Default, "RenderBin"); + } + else + { + shaderStateset->setMode(GL_BLEND, osg::StateAttribute::ON); - osg::ref_ptr depth (new osg::Depth); - depth->setWriteMask(false); - shaderStateset->setAttributeAndModes(depth, osg::StateAttribute::ON); + shaderStateset->setRenderBinDetails(MWRender::RenderBin_Water, "RenderBin"); - // TODO: render after transparent bin when refraction is on - shaderStateset->setRenderBinDetails(MWRender::RenderBin_Water, "RenderBin"); + osg::ref_ptr depth (new osg::Depth); + depth->setWriteMask(false); + shaderStateset->setAttributeAndModes(depth, osg::StateAttribute::ON); + } + + shaderStateset->setMode(GL_CULL_FACE, osg::StateAttribute::OFF); - geode->setStateSet(shaderStateset); + node->setStateSet(shaderStateset); } Water::~Water() @@ -551,7 +558,12 @@ void Water::update(float dt) void Water::updateVisible() { - mWaterNode->setNodeMask(mEnabled && mToggled ? ~0 : 0); + unsigned int mask = mEnabled && mToggled ? ~0 : 0; + mWaterNode->setNodeMask(mask); + if (mRefraction) + mRefraction->setNodeMask(mask); + if (mReflection) + mReflection->setNodeMask(mask); } bool Water::toggle() diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index 46b6382e7..857f7fbb0 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -9,6 +9,8 @@ namespace osg { class Group; class PositionAttitudeTransform; + class Geode; + class Node; } namespace osgUtil @@ -41,6 +43,7 @@ namespace MWRender osg::ref_ptr mParent; osg::ref_ptr mSceneRoot; osg::ref_ptr mWaterNode; + osg::ref_ptr mWaterGeode; Resource::ResourceSystem* mResourceSystem; osg::ref_ptr mIncrementalCompileOperation; @@ -49,6 +52,8 @@ namespace MWRender osg::ref_ptr mRefraction; osg::ref_ptr mReflection; + const std::string mResourcePath; + bool mEnabled; bool mToggled; float mTop; @@ -56,6 +61,12 @@ namespace MWRender osg::Vec3f getSceneNodeCoordinates(int gridX, int gridY); void updateVisible(); + void createSimpleWaterStateSet(osg::Node* node); + + /// @param reflection the reflection camera (required) + /// @param refraction the refraction camera (optional) + void createShaderWaterStateSet(osg::Node* node, Reflection* reflection, Refraction* refraction); + public: Water(osg::Group* parent, osg::Group* sceneRoot, Resource::ResourceSystem* resourceSystem, osgUtil::IncrementalCompileOperation* ico, const MWWorld::Fallback* fallback, diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index c11c18a2d..6f7b173bf 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -60,13 +60,13 @@ varying vec3 screenCoordsPassthrough; varying vec4 position; varying float depthPassthrough; +uniform sampler2D normalMap; + uniform sampler2D reflectionMap; #if REFRACTION uniform sampler2D refractionMap; uniform sampler2D refractionDepthMap; #endif - -uniform sampler2D normalMap; uniform float osg_SimulationTime; From 8433e0679f0b0c8bbb2fb8625d83196b9586eee1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 28 Oct 2015 21:22:14 +0100 Subject: [PATCH 2310/3725] Water: connect to settings window --- apps/openmw/mwrender/renderingmanager.cpp | 2 + apps/openmw/mwrender/water.cpp | 80 +++++++++++++++++++---- apps/openmw/mwrender/water.hpp | 5 ++ files/shaders/water_fragment.glsl | 4 +- 4 files changed, 77 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index b0fe98565..1370631bc 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -785,6 +785,8 @@ namespace MWRender } else if (it->first == "General" && (it->second == "texture filtering" || it->second == "anisotropy")) updateTextureFiltering(); + else if (it->first == "Water") + mWater->processChangedSettings(changed); } } diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 121b07654..4b936ba30 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -204,7 +204,7 @@ public: } }; -osg::ref_ptr readShader (osg::Shader::Type type, const std::string& file) +osg::ref_ptr readShader (osg::Shader::Type type, const std::string& file, const std::map& defineMap = std::map()) { osg::ref_ptr shader (new osg::Shader(type)); @@ -213,7 +213,17 @@ osg::ref_ptr readShader (osg::Shader::Type type, const std::string& inStream.open(boost::filesystem::path(file)); std::stringstream strstream; strstream << inStream.rdbuf(); - shader->setShaderSource(strstream.str()); + + std::string shaderSource = strstream.str(); + + for (std::map::const_iterator it = defineMap.begin(); it != defineMap.end(); ++it) + { + size_t pos = shaderSource.find(it->first); + if (pos != std::string::npos) + shaderSource.replace(pos, it->first.length(), it->second); + } + + shader->setShaderSource(shaderSource); return shader; } @@ -429,7 +439,44 @@ Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem createShaderWaterStateSet(mWaterGeode, mReflection, mRefraction); + updateWaterMaterial(); +} + +void Water::updateWaterMaterial() +{ // TODO: add ingame setting for texture quality + if (mReflection) + { + mParent->removeChild(mReflection); + mReflection = NULL; + } + if (mRefraction) + { + mParent->removeChild(mRefraction); + mRefraction = NULL; + } + + if (Settings::Manager::getBool("shader", "Water")) + { + mReflection = new Reflection; + mReflection->setWaterLevel(mTop); + mReflection->setScene(mSceneRoot); + mParent->addChild(mReflection); + + if (Settings::Manager::getBool("refraction", "Water")) + { + mRefraction = new Refraction; + mRefraction->setWaterLevel(mTop); + mRefraction->setScene(mSceneRoot); + mParent->addChild(mRefraction); + } + + createShaderWaterStateSet(mWaterGeode, mReflection, mRefraction); + } + else + createSimpleWaterStateSet(mWaterGeode); + + updateVisible(); } void Water::createSimpleWaterStateSet(osg::Node* node) @@ -462,20 +509,19 @@ void Water::createSimpleWaterStateSet(osg::Node* node) osg::ref_ptr controller (new NifOsg::FlipController(0, 2/32.f, textures)); controller->setSource(boost::shared_ptr(new SceneUtil::FrameTimeSource)); - node->addUpdateCallback(controller); + node->setUpdateCallback(controller); node->setStateSet(stateset); stateset->setTextureAttributeAndModes(0, textures[0], osg::StateAttribute::ON); } void Water::createShaderWaterStateSet(osg::Node* node, Reflection* reflection, Refraction* refraction) { - osg::ref_ptr vertexShader (readShader(osg::Shader::VERTEX, mResourcePath + "/shaders/water_vertex.glsl")); + // use a define map to conditionally compile the shader + std::map defineMap; + defineMap.insert(std::make_pair(std::string("@refraction_enabled"), std::string(refraction ? "1" : "0"))); - osg::ref_ptr fragmentShader (readShader(osg::Shader::FRAGMENT, mResourcePath + "/shaders/water_fragment.glsl")); - - osg::ref_ptr program (new osg::Program); - program->addShader(vertexShader); - program->addShader(fragmentShader); + osg::ref_ptr vertexShader (readShader(osg::Shader::VERTEX, mResourcePath + "/shaders/water_vertex.glsl", defineMap)); + osg::ref_ptr fragmentShader (readShader(osg::Shader::FRAGMENT, mResourcePath + "/shaders/water_fragment.glsl", defineMap)); osg::ref_ptr normalMap (new osg::Texture2D(readPngImage(mResourcePath + "/shaders/water_nm.png"))); normalMap->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT); @@ -486,11 +532,8 @@ void Water::createShaderWaterStateSet(osg::Node* node, Reflection* reflection, R normalMap->getImage()->flipVertical(); osg::ref_ptr shaderStateset = new osg::StateSet; - shaderStateset->setAttributeAndModes(program, osg::StateAttribute::ON); shaderStateset->addUniform(new osg::Uniform("normalMap", 0)); shaderStateset->addUniform(new osg::Uniform("reflectionMap", 1)); - shaderStateset->addUniform(new osg::Uniform("refractionMap", 2)); - shaderStateset->addUniform(new osg::Uniform("refractionDepthMap", 3)); shaderStateset->setTextureAttributeAndModes(0, normalMap, osg::StateAttribute::ON); shaderStateset->setTextureAttributeAndModes(1, reflection->getReflectionTexture(), osg::StateAttribute::ON); @@ -498,6 +541,8 @@ void Water::createShaderWaterStateSet(osg::Node* node, Reflection* reflection, R { shaderStateset->setTextureAttributeAndModes(2, refraction->getRefractionTexture(), osg::StateAttribute::ON); shaderStateset->setTextureAttributeAndModes(3, refraction->getRefractionDepthTexture(), osg::StateAttribute::ON); + shaderStateset->addUniform(new osg::Uniform("refractionMap", 2)); + shaderStateset->addUniform(new osg::Uniform("refractionDepthMap", 3)); shaderStateset->setRenderBinDetails(MWRender::RenderBin_Default, "RenderBin"); } else @@ -513,7 +558,18 @@ void Water::createShaderWaterStateSet(osg::Node* node, Reflection* reflection, R shaderStateset->setMode(GL_CULL_FACE, osg::StateAttribute::OFF); + osg::ref_ptr program (new osg::Program); + program->addShader(vertexShader); + program->addShader(fragmentShader); + shaderStateset->setAttributeAndModes(program, osg::StateAttribute::ON); + node->setStateSet(shaderStateset); + node->setUpdateCallback(NULL); +} + +void Water::processChangedSettings(const Settings::CategorySettingVector& settings) +{ + updateWaterMaterial(); } Water::~Water() diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index 857f7fbb0..f77afbfee 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -3,6 +3,8 @@ #include +#include + #include "../mwworld/cellstore.hpp" namespace osg @@ -67,6 +69,8 @@ namespace MWRender /// @param refraction the refraction camera (optional) void createShaderWaterStateSet(osg::Node* node, Reflection* reflection, Refraction* refraction); + void updateWaterMaterial(); + public: Water(osg::Group* parent, osg::Group* sceneRoot, Resource::ResourceSystem* resourceSystem, osgUtil::IncrementalCompileOperation* ico, const MWWorld::Fallback* fallback, @@ -92,6 +96,7 @@ namespace MWRender void update(float dt); + void processChangedSettings(const Settings::CategorySettingVector& settings); }; } diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index 6f7b173bf..c04233fcf 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -1,8 +1,8 @@ #version 120 -// Inspired by Blender GLSL Water by martinsh ( http://devlog-martinsh.blogspot.de/2012/07/waterundewater-shader-wip.html ) +#define REFRACTION @refraction_enabled -#define REFRACTION 1 +// Inspired by Blender GLSL Water by martinsh ( http://devlog-martinsh.blogspot.de/2012/07/waterundewater-shader-wip.html ) // tweakables -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- From 8cb2c7a9fbb55b7748867b2a48598c891821a12a Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 28 Oct 2015 21:25:16 +0100 Subject: [PATCH 2311/3725] Water: remove defunct "reflect " settings Not really useful --- files/mygui/openmw_settings_window.layout | 30 ----------------------- files/settings-default.cfg | 3 --- 2 files changed, 33 deletions(-) diff --git a/files/mygui/openmw_settings_window.layout b/files/mygui/openmw_settings_window.layout index 19e3bcf88..4b2e1cc27 100644 --- a/files/mygui/openmw_settings_window.layout +++ b/files/mygui/openmw_settings_window.layout @@ -369,36 +369,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 274a31315..7c809b926 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -129,9 +129,6 @@ shader = false refraction = false rtt size = 512 -reflect terrain = true -reflect statics = false -reflect actors = false [Sound] # Device name. Blank means default From 60bc7dbabcc9f1819419f1356837f6278ce295cd Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 28 Oct 2015 21:38:34 +0100 Subject: [PATCH 2312/3725] Improve MW_ComboBox skin --- files/mygui/openmw_resources.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/mygui/openmw_resources.xml b/files/mygui/openmw_resources.xml index 305cb0c0d..ab6899341 100644 --- a/files/mygui/openmw_resources.xml +++ b/files/mygui/openmw_resources.xml @@ -101,7 +101,7 @@ - + From c9d7078b4b0e648e5aa4c544f4d2390563a0b2d0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 28 Oct 2015 21:49:01 +0100 Subject: [PATCH 2313/3725] Water: add texture quality setting to the settings window --- apps/openmw/mwgui/settingswindow.cpp | 35 ++++++++++++++++------- apps/openmw/mwgui/settingswindow.hpp | 5 +++- apps/openmw/mwrender/water.cpp | 2 +- files/mygui/openmw_settings_window.layout | 29 +++++++++++++------ 4 files changed, 49 insertions(+), 22 deletions(-) diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 3ab2a6ce3..667dc0c28 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -177,10 +177,10 @@ namespace MWGui getWidget(mShadowsTextureSize, "ShadowsTextureSize"); getWidget(mControlsBox, "ControlsBox"); getWidget(mResetControlsButton, "ResetControlsButton"); - getWidget(mRefractionButton, "RefractionButton"); getWidget(mDifficultySlider, "DifficultySlider"); getWidget(mKeyboardSwitch, "KeyboardButton"); getWidget(mControllerSwitch, "ControllerButton"); + getWidget(mWaterTextureSize, "WaterTextureSize"); #ifndef WIN32 // hide gamma controls since it currently does not work under Linux @@ -204,6 +204,8 @@ namespace MWGui mFPSButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onFpsToggled); mResolutionList->eventListChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onResolutionSelected); + mWaterTextureSize->eventComboChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onWaterTextureSizeChanged); + mShadowsTextureSize->eventComboChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onShadowTextureSizeChanged); mKeyboardSwitch->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onKeyboardSwitchClicked); @@ -239,11 +241,18 @@ namespace MWGui mTextureFilteringButton->setCaption(textureFilteringToStr(tf)); mAnisotropyLabel->setCaption("Anisotropy (" + MyGUI::utility::toString(Settings::Manager::getInt("anisotropy", "General")) + ")"); + int waterTextureSize = Settings::Manager::getInt ("rtt size", "Water"); + if (waterTextureSize >= 512) + mWaterTextureSize->setIndexSelected(0); + if (waterTextureSize >= 1024) + mWaterTextureSize->setIndexSelected(1); + if (waterTextureSize >= 2048) + mWaterTextureSize->setIndexSelected(2); + mShadowsTextureSize->setCaption (Settings::Manager::getString ("texture size", "Shadows")); if (!Settings::Manager::getBool("shaders", "Objects")) { - mRefractionButton->setEnabled(false); mShadowsEnabledButton->setEnabled(false); } @@ -324,6 +333,19 @@ namespace MWGui } } + void SettingsWindow::onWaterTextureSizeChanged(MyGUI::ComboBox* _sender, size_t pos) + { + int size = 0; + if (pos == 0) + size = 512; + else if (pos == 1) + size = 1024; + else if (pos == 2) + size = 2048; + Settings::Manager::setInt("rtt size", "Water", size); + apply(); + } + void SettingsWindow::onShadowTextureSizeChanged(MyGUI::ComboBox *_sender, size_t pos) { Settings::Manager::setString("texture size", "Shadows", _sender->getItemNameAt(pos)); @@ -350,12 +372,6 @@ namespace MWGui { if (newState == false) { - // refraction needs shaders to display underwater fog - mRefractionButton->setCaptionWithReplacing("#{sOff}"); - mRefractionButton->setEnabled(false); - - Settings::Manager::setBool("refraction", "Water", false); - // shadows not supported mShadowsEnabledButton->setEnabled(false); mShadowsEnabledButton->setCaptionWithReplacing("#{sOff}"); @@ -363,9 +379,6 @@ namespace MWGui } else { - // re-enable - mRefractionButton->setEnabled(true); - mShadowsEnabledButton->setEnabled(true); } } diff --git a/apps/openmw/mwgui/settingswindow.hpp b/apps/openmw/mwgui/settingswindow.hpp index 79487c54b..0369eb40e 100644 --- a/apps/openmw/mwgui/settingswindow.hpp +++ b/apps/openmw/mwgui/settingswindow.hpp @@ -38,7 +38,8 @@ namespace MWGui MyGUI::TextBox* mAnisotropyLabel; MyGUI::Widget* mAnisotropyBox; MyGUI::Button* mShadersButton; - MyGUI::Button* mRefractionButton; + + MyGUI::ComboBox* mWaterTextureSize; MyGUI::Button* mShadowsEnabledButton; MyGUI::ComboBox* mShadowsTextureSize; @@ -61,6 +62,8 @@ namespace MWGui void onResolutionCancel(); void highlightCurrentResolution(); + void onWaterTextureSizeChanged(MyGUI::ComboBox* _sender, size_t pos); + void onShadowTextureSizeChanged(MyGUI::ComboBox* _sender, size_t pos); void onRebindAction(MyGUI::Widget* _sender); diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 4b936ba30..8ab29c3a7 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -444,7 +444,6 @@ Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem void Water::updateWaterMaterial() { - // TODO: add ingame setting for texture quality if (mReflection) { mParent->removeChild(mReflection); @@ -543,6 +542,7 @@ void Water::createShaderWaterStateSet(osg::Node* node, Reflection* reflection, R shaderStateset->setTextureAttributeAndModes(3, refraction->getRefractionDepthTexture(), osg::StateAttribute::ON); shaderStateset->addUniform(new osg::Uniform("refractionMap", 2)); shaderStateset->addUniform(new osg::Uniform("refractionDepthMap", 3)); + // FIXME: zfighting with ripples shaderStateset->setRenderBinDetails(MWRender::RenderBin_Default, "RenderBin"); } else diff --git a/files/mygui/openmw_settings_window.layout b/files/mygui/openmw_settings_window.layout index 4b2e1cc27..e76c3a7db 100644 --- a/files/mygui/openmw_settings_window.layout +++ b/files/mygui/openmw_settings_window.layout @@ -365,21 +365,32 @@ - + - - - - - - + + + + + + + + + - - + + + + + + + + + + From d394b0793f8b9918d2b5f0a74533877229f3b7fb Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 28 Oct 2015 23:31:59 +0100 Subject: [PATCH 2314/3725] waterLevel fix --- apps/openmw/mwrender/water.cpp | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 8ab29c3a7..f1ec66f4b 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -423,22 +423,6 @@ Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem setHeight(mTop); - const float waterLevel = -1; - - // refraction - mRefraction = new Refraction(); - mRefraction->setWaterLevel(waterLevel); - mRefraction->setScene(mSceneRoot); - mParent->addChild(mRefraction); - - // reflection - mReflection = new Reflection(); - mReflection->setWaterLevel(waterLevel); - mReflection->setScene(mSceneRoot); - mParent->addChild(mReflection); - - createShaderWaterStateSet(mWaterGeode, mReflection, mRefraction); - updateWaterMaterial(); } @@ -605,6 +589,11 @@ void Water::setHeight(const float height) osg::Vec3f pos = mWaterNode->getPosition(); pos.z() = height; mWaterNode->setPosition(pos); + + if (mReflection) + mReflection->setWaterLevel(mTop); + if (mRefraction) + mRefraction->setWaterLevel(mTop); } void Water::update(float dt) From 9b8e45fc01405e15e1d7d61764f0af762f87aff7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 28 Oct 2015 23:34:37 +0100 Subject: [PATCH 2315/3725] Fix ripple particles z-fighting with the water surface --- apps/openmw/mwrender/ripplesimulation.cpp | 6 ++++++ apps/openmw/mwrender/water.cpp | 1 - 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/ripplesimulation.cpp b/apps/openmw/mwrender/ripplesimulation.cpp index a7637f2e1..5caee8046 100644 --- a/apps/openmw/mwrender/ripplesimulation.cpp +++ b/apps/openmw/mwrender/ripplesimulation.cpp @@ -2,6 +2,7 @@ #include +#include #include #include #include @@ -55,6 +56,11 @@ namespace depth->setWriteMask(false); stateset->setAttributeAndModes(depth, osg::StateAttribute::ON); + osg::ref_ptr polygonOffset (new osg::PolygonOffset); + polygonOffset->setUnits(-1); + polygonOffset->setFactor(-1); + stateset->setAttributeAndModes(polygonOffset, osg::StateAttribute::ON); + stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); osg::ref_ptr mat (new osg::Material); diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index f1ec66f4b..81f7c4e11 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -526,7 +526,6 @@ void Water::createShaderWaterStateSet(osg::Node* node, Reflection* reflection, R shaderStateset->setTextureAttributeAndModes(3, refraction->getRefractionDepthTexture(), osg::StateAttribute::ON); shaderStateset->addUniform(new osg::Uniform("refractionMap", 2)); shaderStateset->addUniform(new osg::Uniform("refractionDepthMap", 3)); - // FIXME: zfighting with ripples shaderStateset->setRenderBinDetails(MWRender::RenderBin_Default, "RenderBin"); } else From f336c6db87be04903c0a92ab0c749bfe290bb5f0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 29 Oct 2015 00:51:35 +0100 Subject: [PATCH 2316/3725] Fix LightSource crash --- components/sceneutil/lightmanager.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/sceneutil/lightmanager.hpp b/components/sceneutil/lightmanager.hpp index 3e0329c8b..c2a1779ed 100644 --- a/components/sceneutil/lightmanager.hpp +++ b/components/sceneutil/lightmanager.hpp @@ -76,7 +76,7 @@ namespace SceneUtil struct LightSourceTransform { - LightSource* mLightSource; + osg::ref_ptr mLightSource; osg::Matrix mWorldMatrix; }; @@ -84,7 +84,7 @@ namespace SceneUtil struct LightSourceViewBound { - LightSource* mLightSource; + osg::ref_ptr mLightSource; osg::BoundingSphere mViewBound; }; From 7692ae175a45b0d6f3b1db5ca4b94696cf7eb174 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 29 Oct 2015 01:17:23 +0100 Subject: [PATCH 2317/3725] Disable sun rendering on the reflection camera Not needed, we have specular highlights. --- apps/openmw/mwrender/sky.cpp | 1 + apps/openmw/mwrender/vismask.hpp | 17 +++++++++-------- apps/openmw/mwrender/water.cpp | 2 +- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 5938fb13c..b0af85c0b 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -411,6 +411,7 @@ public: , mUpdater(new Updater) { mTransform->addUpdateCallback(mUpdater); + mTransform->setNodeMask(Mask_Sun); osg::ref_ptr sunTex = textureManager.getTexture2D("textures/tx_sun_05.dds", osg::Texture::CLAMP, diff --git a/apps/openmw/mwrender/vismask.hpp b/apps/openmw/mwrender/vismask.hpp index 7faae4602..b1329e958 100644 --- a/apps/openmw/mwrender/vismask.hpp +++ b/apps/openmw/mwrender/vismask.hpp @@ -15,20 +15,21 @@ namespace MWRender Mask_Actor = (1<<3), Mask_Player = (1<<4), Mask_Sky = (1<<5), - Mask_Water = (1<<6), - Mask_SimpleWater = (1<<7), - Mask_Terrain = (1<<8), - Mask_FirstPerson = (1<<9), + Mask_Sun = (1<<6), + Mask_Water = (1<<7), + Mask_SimpleWater = (1<<8), + Mask_Terrain = (1<<9), + Mask_FirstPerson = (1<<10), // top level masks - Mask_Scene = (1<<10), - Mask_GUI = (1<<11), + Mask_Scene = (1<<11), + Mask_GUI = (1<<12), // Set on a Geode - Mask_ParticleSystem = (1<<12), + Mask_ParticleSystem = (1<<13), // Set on cameras within the main scene graph - Mask_RenderToTexture = (1<<13) + Mask_RenderToTexture = (1<<14) // reserved: (1<<16) for SceneUtil::Mask_Lit }; diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 81f7c4e11..09143a3bd 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -259,7 +259,7 @@ public: setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT); setReferenceFrame(osg::Camera::RELATIVE_RF); - setCullMask(Mask_Effect|Mask_Scene|Mask_Terrain|Mask_Actor|Mask_ParticleSystem|Mask_Sky|Mask_Player|(1<<16)); + setCullMask(Mask_Effect|Mask_Scene|Mask_Terrain|Mask_Actor|Mask_ParticleSystem|Mask_Sky|Mask_Sun|Mask_Player|(1<<16)); setNodeMask(Mask_RenderToTexture); setViewport(0, 0, rttSize, rttSize); From ad4e0e3b971d4eb0203fe11b0adc7b1fea0ed6cc Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 29 Oct 2015 11:20:06 +0100 Subject: [PATCH 2318/3725] split virtual select button into two buttons (primary select and seconadry select) --- apps/opencs/model/settings/usersettings.cpp | 10 ++++++--- apps/opencs/view/render/editmode.cpp | 11 ++++++++-- apps/opencs/view/render/editmode.hpp | 12 +++++++++-- apps/opencs/view/render/instancemode.cpp | 22 +++++++++++++++++--- apps/opencs/view/render/instancemode.hpp | 4 +++- apps/opencs/view/render/worldspacewidget.cpp | 22 +++++++++++++------- 6 files changed, 62 insertions(+), 19 deletions(-) diff --git a/apps/opencs/model/settings/usersettings.cpp b/apps/opencs/model/settings/usersettings.cpp index 3e5ab24d1..e8568cac1 100644 --- a/apps/opencs/model/settings/usersettings.cpp +++ b/apps/opencs/model/settings/usersettings.cpp @@ -399,9 +399,13 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() secondaryEditing->setDeclaredValues (values); secondaryEditing->setDefaultValue (cRight); - Setting *selection = createSetting (Type_ComboBox, "select", "Selection Button"); - selection->setDeclaredValues (values); - selection->setDefaultValue (middle); + Setting *primarySelection = createSetting (Type_ComboBox, "p-select", "Selection Button"); + primarySelection->setDeclaredValues (values); + primarySelection->setDefaultValue (middle); + + Setting *secondarySelection = createSetting (Type_ComboBox, "s-select", "Selection Button"); + secondarySelection->setDeclaredValues (values); + secondarySelection->setDefaultValue (cMiddle); Setting *contextSensitive = createSetting (Type_CheckBox, "context-select", "Context Sensitive Selection"); contextSensitive->setDefaultValue ("false"); diff --git a/apps/opencs/view/render/editmode.cpp b/apps/opencs/view/render/editmode.cpp index 4235faf76..4c6f2bd43 100644 --- a/apps/opencs/view/render/editmode.cpp +++ b/apps/opencs/view/render/editmode.cpp @@ -38,7 +38,9 @@ void CSVRender::EditMode::primaryEditPressed (osg::ref_ptr tag) {} void CSVRender::EditMode::secondaryEditPressed (osg::ref_ptr tag) {} -void CSVRender::EditMode::selectPressed (osg::ref_ptr tag) {} +void CSVRender::EditMode::primarySelectPressed (osg::ref_ptr tag) {} + +void CSVRender::EditMode::secondarySelectPressed (osg::ref_ptr tag) {} bool CSVRender::EditMode::primaryEditStartDrag (osg::ref_ptr tag) { @@ -50,7 +52,12 @@ bool CSVRender::EditMode::secondaryEditStartDrag (osg::ref_ptr tag) return false; } -bool CSVRender::EditMode::selectStartDrag (osg::ref_ptr tag) +bool CSVRender::EditMode::primarySelectStartDrag (osg::ref_ptr tag) +{ + return false; +} + +bool CSVRender::EditMode::secondarySelectStartDrag (osg::ref_ptr tag) { return false; } diff --git a/apps/opencs/view/render/editmode.hpp b/apps/opencs/view/render/editmode.hpp index 77676d6a3..c17616b56 100644 --- a/apps/opencs/view/render/editmode.hpp +++ b/apps/opencs/view/render/editmode.hpp @@ -43,7 +43,10 @@ namespace CSVRender virtual void secondaryEditPressed (osg::ref_ptr tag); /// Default-implementation: Ignored. - virtual void selectPressed (osg::ref_ptr tag); + virtual void primarySelectPressed (osg::ref_ptr tag); + + /// Default-implementation: Ignored. + virtual void secondarySelectPressed (osg::ref_ptr tag); /// Default-implementation: ignore and return false /// @@ -58,7 +61,12 @@ namespace CSVRender /// Default-implementation: ignore and return false /// /// \return Drag accepted? - virtual bool selectStartDrag (osg::ref_ptr tag); + virtual bool primarySelectStartDrag (osg::ref_ptr tag); + + /// Default-implementation: ignore and return false + /// + /// \return Drag accepted? + virtual bool secondarySelectStartDrag (osg::ref_ptr tag); /// Default-implementation: ignored virtual void drag (int diffX, int diffY, double speedFactor); diff --git a/apps/opencs/view/render/instancemode.cpp b/apps/opencs/view/render/instancemode.cpp index 333d91656..fdd031ad4 100644 --- a/apps/opencs/view/render/instancemode.cpp +++ b/apps/opencs/view/render/instancemode.cpp @@ -30,16 +30,32 @@ void CSVRender::InstanceMode::updateUserSetting (const QString& name, const QStr void CSVRender::InstanceMode::primaryEditPressed (osg::ref_ptr tag) { if (mContextSelect) - selectPressed (tag); + primarySelectPressed (tag); } void CSVRender::InstanceMode::secondaryEditPressed (osg::ref_ptr tag) { if (mContextSelect) - selectPressed (tag); + secondarySelectPressed (tag); } -void CSVRender::InstanceMode::selectPressed (osg::ref_ptr tag) +void CSVRender::InstanceMode::primarySelectPressed (osg::ref_ptr tag) +{ + if (tag) + { + if (CSVRender::ObjectTag *objectTag = dynamic_cast (tag.get())) + { + // hit an Object, toggle its selection state + CSVRender::Object* object = objectTag->mObject; + object->setSelected (!object->getSelected()); + return; + } + } + + getWorldspaceWidget().clearSelection (Element_Reference); +} + +void CSVRender::InstanceMode::secondarySelectPressed (osg::ref_ptr tag) { if (tag) { diff --git a/apps/opencs/view/render/instancemode.hpp b/apps/opencs/view/render/instancemode.hpp index cc4fd5434..50bd8243d 100644 --- a/apps/opencs/view/render/instancemode.hpp +++ b/apps/opencs/view/render/instancemode.hpp @@ -23,7 +23,9 @@ namespace CSVRender virtual void secondaryEditPressed (osg::ref_ptr tag); - virtual void selectPressed (osg::ref_ptr tag); + virtual void primarySelectPressed (osg::ref_ptr tag); + + virtual void secondarySelectPressed (osg::ref_ptr tag); }; } diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 46c5867eb..e76582b94 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -36,7 +36,7 @@ namespace { "p-navi", "s-navi", "p-edit", "s-edit", - "select", + "p-select", "s-select", 0 }; } @@ -513,7 +513,7 @@ void CSVRender::WorldspaceWidget::mouseMoveEvent (QMouseEvent *event) { } - else if (mDragMode=="p-edit" || mDragMode=="s-edit" || mDragMode=="select") + else if (mDragMode=="p-edit" || mDragMode=="s-edit" || mDragMode=="p-select" || mDragMode=="s-select") { osg::ref_ptr tag = mousePick (event); @@ -523,8 +523,10 @@ void CSVRender::WorldspaceWidget::mouseMoveEvent (QMouseEvent *event) mDragging = editMode.primaryEditStartDrag (tag); else if (mDragMode=="s-edit") mDragging = editMode.secondaryEditStartDrag (tag); - else if (mDragMode=="select") - mDragging = editMode.selectStartDrag (tag); + else if (mDragMode=="p-select") + mDragging = editMode.primarySelectStartDrag (tag); + else if (mDragMode=="s-select") + mDragging = editMode.secondarySelectStartDrag (tag); if (mDragging) { @@ -575,7 +577,8 @@ void CSVRender::WorldspaceWidget::mouseReleaseEvent (QMouseEvent *event) { } - else if (mDragMode=="p-edit" || mDragMode=="s-edit" || mDragMode=="select") + else if (mDragMode=="p-edit" || mDragMode=="s-edit" || + mDragMode=="p-select" || mDragMode=="s-select") { EditMode& editMode = dynamic_cast (*mEditMode->getCurrent()); @@ -589,7 +592,8 @@ void CSVRender::WorldspaceWidget::mouseReleaseEvent (QMouseEvent *event) { } - else if (button=="p-edit" || button=="s-edit" || button=="select") + else if (button=="p-edit" || button=="s-edit" || + button=="p-select" || button=="s-select") { osg::ref_ptr tag = mousePick (event); @@ -647,6 +651,8 @@ void CSVRender::WorldspaceWidget::handleMouseClick (osg::ref_ptr tag, c editMode.primaryEditPressed (tag); else if (button=="s-edit") editMode.secondaryEditPressed (tag); - else if (button=="select") - editMode.selectPressed (tag); + else if (button=="p-select") + editMode.primarySelectPressed (tag); + else if (button=="s-select") + editMode.secondarySelectPressed (tag); } From 655b40267b9aa24587620694866e244a2a44023d Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 29 Oct 2015 11:27:01 +0100 Subject: [PATCH 2319/3725] changed instance selection model (primary selects, secondary toggles selection) --- apps/opencs/view/render/instancemode.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/apps/opencs/view/render/instancemode.cpp b/apps/opencs/view/render/instancemode.cpp index fdd031ad4..8f0526443 100644 --- a/apps/opencs/view/render/instancemode.cpp +++ b/apps/opencs/view/render/instancemode.cpp @@ -41,18 +41,18 @@ void CSVRender::InstanceMode::secondaryEditPressed (osg::ref_ptr tag) void CSVRender::InstanceMode::primarySelectPressed (osg::ref_ptr tag) { + getWorldspaceWidget().clearSelection (Element_Reference); + if (tag) { if (CSVRender::ObjectTag *objectTag = dynamic_cast (tag.get())) { - // hit an Object, toggle its selection state + // hit an Object, select it CSVRender::Object* object = objectTag->mObject; - object->setSelected (!object->getSelected()); + object->setSelected (true); return; } } - - getWorldspaceWidget().clearSelection (Element_Reference); } void CSVRender::InstanceMode::secondarySelectPressed (osg::ref_ptr tag) @@ -67,6 +67,4 @@ void CSVRender::InstanceMode::secondarySelectPressed (osg::ref_ptr tag) return; } } - - getWorldspaceWidget().clearSelection (Element_Reference); } From d90fa977e8ac58656d123113970dc7121a371c85 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 29 Oct 2015 13:52:48 +0100 Subject: [PATCH 2320/3725] GL_DEPTH_COMPONEN24 fix --- apps/openmw/mwrender/water.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 09143a3bd..8c50fbde1 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -285,7 +285,7 @@ public: mRefractionDepthTexture = new osg::Texture2D; mRefractionDepthTexture->setSourceFormat(GL_DEPTH_COMPONENT); - mRefractionDepthTexture->setInternalFormat(GL_DEPTH_COMPONENT24_ARB); + mRefractionDepthTexture->setInternalFormat(GL_DEPTH_COMPONENT24); mRefractionDepthTexture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); mRefractionDepthTexture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); mRefractionDepthTexture->setSourceType(GL_UNSIGNED_INT); From b9b154a01598e62f01e474e5c295501d8aa0f8d0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 31 Oct 2015 00:01:12 +0100 Subject: [PATCH 2321/3725] Minor cleanup --- apps/openmw/mwrender/renderingmanager.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 1370631bc..03a44a4e6 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -487,12 +487,9 @@ namespace MWRender rttCamera->setRenderOrder(osg::Camera::PRE_RENDER); rttCamera->setReferenceFrame(osg::Camera::ABSOLUTE_RF); rttCamera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT, osg::Camera::PIXEL_BUFFER_RTT); - rttCamera->setClearColor(mViewer->getCamera()->getClearColor()); - rttCamera->setClearMask(mViewer->getCamera()->getClearMask()); rttCamera->setProjectionMatrixAsPerspective(mFieldOfView, w/float(h), mNearClip, mViewDistance); rttCamera->setViewMatrix(mViewer->getCamera()->getViewMatrix()); rttCamera->setViewport(0, 0, w, h); - rttCamera->setGraphicsContext(mViewer->getCamera()->getGraphicsContext()); osg::ref_ptr texture (new osg::Texture2D); texture->setInternalFormat(GL_RGB); From 93f4d31cf94047bf9f0c72e52c072816b20975db Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 31 Oct 2015 01:30:02 +0100 Subject: [PATCH 2322/3725] Raytest mask fix (Fixes #2984) --- apps/openmw/mwrender/renderingmanager.cpp | 36 ++++++++++------------- 1 file changed, 15 insertions(+), 21 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 03a44a4e6..da81b23b1 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -588,23 +588,27 @@ namespace MWRender } - RenderingManager::RayResult RenderingManager::castRay(const osg::Vec3f& origin, const osg::Vec3f& dest, bool ignorePlayer, bool ignoreActors) + osg::ref_ptr createIntersectionVisitor(osgUtil::Intersector* intersector, bool ignorePlayer, bool ignoreActors) { - osg::ref_ptr intersector (new osgUtil::LineSegmentIntersector(osgUtil::LineSegmentIntersector::MODEL, - origin, dest)); - intersector->setIntersectionLimit(osgUtil::LineSegmentIntersector::LIMIT_NEAREST); - - osgUtil::IntersectionVisitor intersectionVisitor(intersector); - int mask = intersectionVisitor.getTraversalMask(); - mask &= ~(Mask_RenderToTexture|Mask_Sky|Mask_Debug|Mask_Effect|Mask_Water); + osg::ref_ptr intersectionVisitor( new osgUtil::IntersectionVisitor(intersector)); + int mask = intersectionVisitor->getTraversalMask(); + mask &= ~(Mask_RenderToTexture|Mask_Sky|Mask_Debug|Mask_Effect|Mask_Water|Mask_SimpleWater); if (ignorePlayer) mask &= ~(Mask_Player); if (ignoreActors) mask &= ~(Mask_Actor|Mask_Player); - intersectionVisitor.setTraversalMask(mask); + intersectionVisitor->setTraversalMask(mask); + return intersectionVisitor; + } + + RenderingManager::RayResult RenderingManager::castRay(const osg::Vec3f& origin, const osg::Vec3f& dest, bool ignorePlayer, bool ignoreActors) + { + osg::ref_ptr intersector (new osgUtil::LineSegmentIntersector(osgUtil::LineSegmentIntersector::MODEL, + origin, dest)); + intersector->setIntersectionLimit(osgUtil::LineSegmentIntersector::LIMIT_NEAREST); - mRootNode->accept(intersectionVisitor); + mRootNode->accept(*createIntersectionVisitor(intersector, ignorePlayer, ignoreActors)); return getIntersectionResult(intersector); } @@ -623,17 +627,7 @@ namespace MWRender intersector->setEnd(end); intersector->setIntersectionLimit(osgUtil::LineSegmentIntersector::LIMIT_NEAREST); - osgUtil::IntersectionVisitor intersectionVisitor(intersector); - int mask = intersectionVisitor.getTraversalMask(); - mask &= ~(Mask_RenderToTexture|Mask_Sky|Mask_Debug|Mask_Effect|Mask_Water); - if (ignorePlayer) - mask &= ~(Mask_Player); - if (ignoreActors) - mask &= ~(Mask_Actor|Mask_Player); - - intersectionVisitor.setTraversalMask(mask); - - mViewer->getCamera()->accept(intersectionVisitor); + mViewer->getCamera()->accept(*createIntersectionVisitor(intersector, ignorePlayer, ignoreActors)); return getIntersectionResult(intersector); } From 7b817ba010c9b643e81d0060be71b85e8170c81e Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 31 Oct 2015 03:14:05 +0100 Subject: [PATCH 2323/3725] Fix the node masks of water cameras being reset (Bug #2984) Node mask needs to remain Mask_RenderToTexture so the raytesting visitor won't go through the reflection graph. --- apps/openmw/mwrender/water.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 8c50fbde1..251a1232c 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -602,12 +602,12 @@ void Water::update(float dt) void Water::updateVisible() { - unsigned int mask = mEnabled && mToggled ? ~0 : 0; - mWaterNode->setNodeMask(mask); + bool visible = mEnabled && mToggled; + mWaterNode->setNodeMask(visible ? ~0 : 0); if (mRefraction) - mRefraction->setNodeMask(mask); + mRefraction->setNodeMask(visible ? Mask_RenderToTexture : 0); if (mReflection) - mReflection->setNodeMask(mask); + mReflection->setNodeMask(visible ? Mask_RenderToTexture : 0); } bool Water::toggle() From 78c735adc609dda06954746b31cea4289a7060ad Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 31 Oct 2015 20:42:42 +1100 Subject: [PATCH 2324/3725] Fix saving when only topic info was modified (topic itself unchanged) --- apps/opencs/model/doc/savingstages.cpp | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/apps/opencs/model/doc/savingstages.cpp b/apps/opencs/model/doc/savingstages.cpp index c6d8a8cb3..138e84b9a 100644 --- a/apps/opencs/model/doc/savingstages.cpp +++ b/apps/opencs/model/doc/savingstages.cpp @@ -134,10 +134,21 @@ void CSMDoc::WriteDialogueCollectionStage::perform (int stage, Messages& message state==CSMWorld::RecordBase::State_ModifiedOnly || infoModified) { - mState.getWriter().startRecord (topic.mModified.sRecordId); - mState.getWriter().writeHNCString ("NAME", topic.mModified.mId); - topic.mModified.save (mState.getWriter()); - mState.getWriter().endRecord (topic.mModified.sRecordId); + if (infoModified && state != CSMWorld::RecordBase::State_Modified + && state != CSMWorld::RecordBase::State_ModifiedOnly) + { + mState.getWriter().startRecord (topic.mBase.sRecordId); + mState.getWriter().writeHNCString ("NAME", topic.mBase.mId); + topic.mBase.save (mState.getWriter()); + mState.getWriter().endRecord (topic.mBase.sRecordId); + } + else + { + mState.getWriter().startRecord (topic.mModified.sRecordId); + mState.getWriter().writeHNCString ("NAME", topic.mModified.mId); + topic.mModified.save (mState.getWriter()); + mState.getWriter().endRecord (topic.mModified.sRecordId); + } // write modified selected info records for (CSMWorld::InfoCollection::RecordConstIterator iter (range.first); iter!=range.second; From 7c007d9c6d530126075165766a8c497bd3de7d62 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 31 Oct 2015 20:45:16 +1100 Subject: [PATCH 2325/3725] Rename a variable to make it less confusing. --- apps/opencs/model/doc/savingstages.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/opencs/model/doc/savingstages.cpp b/apps/opencs/model/doc/savingstages.cpp index 138e84b9a..3fba2cd85 100644 --- a/apps/opencs/model/doc/savingstages.cpp +++ b/apps/opencs/model/doc/savingstages.cpp @@ -154,14 +154,14 @@ void CSMDoc::WriteDialogueCollectionStage::perform (int stage, Messages& message for (CSMWorld::InfoCollection::RecordConstIterator iter (range.first); iter!=range.second; ++iter) { - CSMWorld::RecordBase::State state = iter->mState; + CSMWorld::RecordBase::State infoState = iter->mState; - if (state==CSMWorld::RecordBase::State_Deleted) + if (infoState==CSMWorld::RecordBase::State_Deleted) { /// \todo wrote record with delete flag } - else if (state==CSMWorld::RecordBase::State_Modified || - state==CSMWorld::RecordBase::State_ModifiedOnly) + else if (infoState==CSMWorld::RecordBase::State_Modified || + infoState==CSMWorld::RecordBase::State_ModifiedOnly) { ESM::DialInfo info = iter->get(); info.mId = info.mId.substr (info.mId.find_last_of ('#')+1); From 819fecd08ec163e3f6b94ca40330f68214d54579 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 1 Nov 2015 11:23:28 +1100 Subject: [PATCH 2326/3725] Add a check for scale value of 0. Should resolve bug #2880. --- apps/opencs/model/tools/referenceablecheck.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/opencs/model/tools/referenceablecheck.cpp b/apps/opencs/model/tools/referenceablecheck.cpp index 6b323547f..336a5e713 100644 --- a/apps/opencs/model/tools/referenceablecheck.cpp +++ b/apps/opencs/model/tools/referenceablecheck.cpp @@ -468,6 +468,9 @@ void CSMTools::ReferenceableCheckStage::creatureCheck ( if (creature.mData.mGold < 0) //It seems that this is for gold in merchant creatures messages.push_back (std::make_pair (id, creature.mId + " has negative gold ")); + if (creature.mScale == 0) + messages.push_back (std::make_pair (id, creature.mId + " has zero scale value")); + // Check that mentioned scripts exist scriptCheck(creature, messages, id.toString()); } From 4af469511da373c48d7b3eaa0b4e1eb37971558c Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 2 Nov 2015 06:43:20 +1100 Subject: [PATCH 2327/3725] Fix some sub-tables becoming uneditable since commit 80869d --- apps/opencs/model/world/refidadapterimp.hpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index 93d4ce894..b1004da98 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -596,16 +596,16 @@ namespace CSMWorld return record.get().mAiData.mAlarm; if (column==mActors.mInventory) - return true; // to show nested tables in dialogue subview, see IdTree::hasChildren() + return QVariant::fromValue(ColumnBase::TableEdit_Full); if (column==mActors.mSpells) - return true; // to show nested tables in dialogue subview, see IdTree::hasChildren() + return QVariant::fromValue(ColumnBase::TableEdit_Full); if (column==mActors.mDestinations) - return true; // to show nested tables in dialogue subview, see IdTree::hasChildren() + return QVariant::fromValue(ColumnBase::TableEdit_Full); if (column==mActors.mAiPackages) - return true; // to show nested tables in dialogue subview, see IdTree::hasChildren() + return QVariant::fromValue(ColumnBase::TableEdit_Full); std::map::const_iterator iter = mActors.mServices.find (column); @@ -2080,7 +2080,7 @@ namespace CSMWorld int index) const { if (column==mLevList.mLevList || column == mLevList.mNestedListLevList) - return true; // to show nested tables in dialogue subview, see IdTree::hasChildren() + return QVariant::fromValue(ColumnBase::TableEdit_Full); return BaseRefIdAdapter::getData (column, data, index); } From 7f477e2fae47bdfe78ac17b2622ed2fdd844fd98 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 2 Nov 2015 06:57:24 +1100 Subject: [PATCH 2328/3725] Fix include file issue. --- apps/opencs/model/world/refidadapterimp.cpp | 1 - apps/opencs/model/world/refidadapterimp.hpp | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index 860fc9bdf..90a710fc8 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -7,7 +7,6 @@ #include #include -#include "columnbase.hpp" #include "nestedtablewrapper.hpp" CSMWorld::PotionColumns::PotionColumns (const InventoryColumns& columns) diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index b1004da98..eff7167de 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -11,6 +11,7 @@ #include #include +#include "columnbase.hpp" #include "record.hpp" #include "refiddata.hpp" #include "universalid.hpp" From bd9dc5856030763aa49a412fc5942288d2e5a2af Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 1 Nov 2015 21:45:58 +0100 Subject: [PATCH 2329/3725] Use the correct scale for actor swim height (Fixes #2833) --- apps/openmw/mwclass/creature.cpp | 2 +- apps/openmw/mwclass/creature.hpp | 3 ++- apps/openmw/mwclass/npc.cpp | 6 +++++- apps/openmw/mwclass/npc.hpp | 3 ++- apps/openmw/mwphysics/actor.cpp | 13 ++++++++++--- apps/openmw/mwphysics/actor.hpp | 10 +++++++++- apps/openmw/mwphysics/physicssystem.cpp | 11 ++++++++++- apps/openmw/mwphysics/physicssystem.hpp | 3 +++ apps/openmw/mwrender/characterpreview.cpp | 2 +- apps/openmw/mwworld/class.cpp | 2 +- apps/openmw/mwworld/class.hpp | 3 ++- apps/openmw/mwworld/scene.cpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 2 +- 13 files changed, 48 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 450889eb2..95bc429e3 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -774,7 +774,7 @@ namespace MWClass return ref->mBase->mAiData.mFight; } - void Creature::adjustScale(const MWWorld::Ptr &ptr, osg::Vec3f &scale) const + void Creature::adjustScale(const MWWorld::Ptr &ptr, osg::Vec3f &scale, bool /* rendering */) const { MWWorld::LiveCellRef *ref = ptr.get(); scale *= ref->mBase->mScale; diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index c4ea09255..55127eefc 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -133,7 +133,8 @@ namespace MWClass virtual int getBaseFightRating(const MWWorld::Ptr &ptr) const; - virtual void adjustScale(const MWWorld::Ptr& ptr, osg::Vec3f& scale) const; + virtual void adjustScale(const MWWorld::Ptr& ptr, osg::Vec3f& scale, bool rendering) const; + /// @param rendering Indicates if the scale to adjust is for the rendering mesh, or for the collision mesh }; } diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 9fa2cc603..5679dc3e9 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -1012,8 +1012,12 @@ namespace MWClass + shield; } - void Npc::adjustScale(const MWWorld::Ptr &ptr, osg::Vec3f&scale) const + void Npc::adjustScale(const MWWorld::Ptr &ptr, osg::Vec3f&scale, bool rendering) const { + if (!rendering) + return; // collision meshes are not scaled based on race height + // having the same collision extents for all races makes the environments easier to test + MWWorld::LiveCellRef *ref = ptr.get(); diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index d919131db..c2d2ca8fa 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -109,7 +109,8 @@ namespace MWClass /// \param actor Actor that is resposible for the ID being applied to \a ptr. /// \return Any effect? - virtual void adjustScale (const MWWorld::Ptr &ptr, osg::Vec3f &scale) const; + virtual void adjustScale (const MWWorld::Ptr &ptr, osg::Vec3f &scale, bool rendering) const; + /// @param rendering Indicates if the scale to adjust is for the rendering mesh, or for the collision mesh virtual void skillUsageSucceeded (const MWWorld::Ptr& ptr, int skill, int usageType, float extraFactor=1.f) const; ///< Inform actor \a ptr that a skill use has succeeded. diff --git a/apps/openmw/mwphysics/actor.cpp b/apps/openmw/mwphysics/actor.cpp index 94d93e7d7..a681c7945 100644 --- a/apps/openmw/mwphysics/actor.cpp +++ b/apps/openmw/mwphysics/actor.cpp @@ -110,12 +110,14 @@ void Actor::updateScale() float scale = mPtr.getCellRef().getScale(); osg::Vec3f scaleVec(scale,scale,scale); - if (!mPtr.getClass().isNpc()) - mPtr.getClass().adjustScale(mPtr, scaleVec); - + mPtr.getClass().adjustScale(mPtr, scaleVec, false); mScale = scaleVec; mShape->setLocalScaling(toBullet(mScale)); + scaleVec = osg::Vec3f(scale,scale,scale); + mPtr.getClass().adjustScale(mPtr, scaleVec, true); + mRenderingScale = scaleVec; + updatePosition(); } @@ -124,6 +126,11 @@ osg::Vec3f Actor::getHalfExtents() const return osg::componentMultiply(mHalfExtents, mScale); } +osg::Vec3f Actor::getRenderingHalfExtents() const +{ + return osg::componentMultiply(mHalfExtents, mRenderingScale); +} + void Actor::setInertialForce(const osg::Vec3f &force) { mForce = force; diff --git a/apps/openmw/mwphysics/actor.hpp b/apps/openmw/mwphysics/actor.hpp index 7a12f549d..a4afa48a1 100644 --- a/apps/openmw/mwphysics/actor.hpp +++ b/apps/openmw/mwphysics/actor.hpp @@ -66,10 +66,17 @@ namespace MWPhysics void updatePosition(); /** - * Returns the (scaled) half extents + * Returns the half extents of the collision body (scaled according to collision scale) */ osg::Vec3f getHalfExtents() const; + /** + * Returns the half extents of the collision body (scaled according to rendering scale) + * @note The reason we need this extra method is because of an inconsistency in MW - NPC race scales aren't applied to the collision shape, + * most likely to make environment collision testing easier. However in some cases (swimming level) we want the actual scale. + */ + osg::Vec3f getRenderingHalfExtents() const; + /** * Sets the current amount of inertial force (incl. gravity) affecting this physic actor */ @@ -118,6 +125,7 @@ namespace MWPhysics osg::Quat mRotation; osg::Vec3f mScale; + osg::Vec3f mRenderingScale; osg::Vec3f mPosition; osg::Vec3f mForce; diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index e666161da..80a63bf1b 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -261,7 +261,7 @@ namespace MWPhysics static const float fSwimHeightScale = MWBase::Environment::get().getWorld()->getStore().get() .find("fSwimHeightScale")->getFloat(); - float swimlevel = waterlevel + halfExtents.z() - (halfExtents.z() * 2 * fSwimHeightScale); + float swimlevel = waterlevel + halfExtents.z() - (physicActor->getRenderingHalfExtents().z() * 2 * fSwimHeightScale); ActorTracer tracer; osg::Vec3f inertia = physicActor->getInertialForce(); @@ -878,6 +878,15 @@ namespace MWPhysics return osg::Vec3f(); } + osg::Vec3f PhysicsSystem::getRenderingHalfExtents(const MWWorld::Ptr &actor) + { + Actor* physactor = getActor(actor); + if (physactor) + return physactor->getRenderingHalfExtents(); + else + return osg::Vec3f(); + } + class ContactTestResultCallback : public btCollisionWorld::ContactResultCallback { public: diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index db8da2886..6f38653c8 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -110,6 +110,9 @@ namespace MWPhysics /// Get physical half extents (scaled) of the given actor. osg::Vec3f getHalfExtents(const MWWorld::Ptr& actor); + /// @see MWPhysics::Actor::getRenderingHalfExtents + osg::Vec3f getRenderingHalfExtents(const MWWorld::Ptr& actor); + /// Queues velocity movement for a Ptr. If a Ptr is already queued, its velocity will /// be overwritten. Valid until the next call to applyQueuedMovement. void queueObjectMovement(const MWWorld::Ptr &ptr, const osg::Vec3f &velocity); diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 93afeda25..eb950ea79 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -287,7 +287,7 @@ namespace MWRender void InventoryPreview::onSetup() { osg::Vec3f scale (1.f, 1.f, 1.f); - mCharacter.getClass().adjustScale(mCharacter, scale); + mCharacter.getClass().adjustScale(mCharacter, scale, true); mNode->setScale(scale); diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 4c73c603b..30fd42527 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -287,7 +287,7 @@ namespace MWWorld return ""; } - void Class::adjustScale(const MWWorld::Ptr& ptr, osg::Vec3f& scale) const + void Class::adjustScale(const MWWorld::Ptr& ptr, osg::Vec3f& scale, bool rendering) const { } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 1157db670..b2d3453af 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -258,7 +258,8 @@ namespace MWWorld virtual int getEnchantmentPoints (const MWWorld::Ptr& ptr) const; ///< @return the number of enchantment points available for possible enchanting - virtual void adjustScale(const MWWorld::Ptr& ptr, osg::Vec3f& scale) const; + virtual void adjustScale(const MWWorld::Ptr& ptr, osg::Vec3f& scale, bool rendering) const; + /// @param rendering Indicates if the scale to adjust is for the rendering mesh, or for the collision mesh virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; ///< Determine whether or not \a item can be sold to an npc with the given \a npcServices diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 459b3b6ca..33e2ba17c 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -72,7 +72,7 @@ namespace { float scale = ptr.getCellRef().getScale(); osg::Vec3f scaleVec (scale, scale, scale); - ptr.getClass().adjustScale(ptr, scaleVec); + ptr.getClass().adjustScale(ptr, scaleVec, true); rendering.scaleObject(ptr, scaleVec); } } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index be86987e8..17118e169 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1969,7 +1969,7 @@ namespace MWWorld { osg::Vec3f pos (object.getRefData().getPosition().asVec3()); - pos.z() += heightRatio*2*mPhysics->getHalfExtents(object).z(); + pos.z() += heightRatio*2*mPhysics->getRenderingHalfExtents(object).z(); return isUnderwater(object.getCell(), pos); } From 8da4530957f1e64b031c513486cceeba311a8044 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 1 Nov 2015 22:09:02 +0100 Subject: [PATCH 2330/3725] Use INI-imported underwater fog settings (Fixes #2907, Fixes #1511) --- apps/openmw/mwrender/renderingmanager.cpp | 17 +++++--- apps/openmw/mwrender/renderingmanager.hpp | 6 ++- apps/openmw/mwworld/weather.cpp | 53 ++++++++++++++++++++++- apps/openmw/mwworld/weather.hpp | 7 +++ 4 files changed, 76 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index da81b23b1..e1c0ea666 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -31,6 +31,8 @@ #include +#include "../mwworld/fallback.hpp" + #include "sky.hpp" #include "effectmanager.hpp" #include "npcanimation.hpp" @@ -199,6 +201,10 @@ namespace MWRender updateProjectionMatrix(); mStateUpdater->setFogEnd(mViewDistance); + mUnderwaterColor = fallback->getFallbackColour("Water_UnderwaterColor"); + mUnderwaterWeight = fallback->getFallbackFloat("Water_UnderwaterColorWeight"); + mUnderwaterIndoorFog = fallback->getFallbackFloat("Water_UnderwaterIndoorFog"); + mRootNode->getOrCreateStateSet()->addUniform(new osg::Uniform("near", mNearClip)); mRootNode->getOrCreateStateSet()->addUniform(new osg::Uniform("far", mViewDistance)); } @@ -349,13 +355,14 @@ namespace MWRender { osg::Vec4f color = SceneUtil::colourFromRGB(cell->mAmbi.mFog); - configureFog (cell->mAmbi.mFogDensity, color); + configureFog (cell->mAmbi.mFogDensity, mUnderwaterIndoorFog, color); } - void RenderingManager::configureFog(float fogDepth, const osg::Vec4f &color) + void RenderingManager::configureFog(float fogDepth, float underwaterFog, const osg::Vec4f &color) { mFogDepth = fogDepth; mFogColor = color; + mUnderwaterFog = underwaterFog; } SkyManager* RenderingManager::getSkyManager() @@ -378,9 +385,9 @@ namespace MWRender mCamera->getPosition(focal, cameraPos); if (mWater->isUnderwater(cameraPos)) { - setFogColor(osg::Vec4f(0.090195f, 0.115685f, 0.12745f, 1.f)); - mStateUpdater->setFogStart(0.f); - mStateUpdater->setFogEnd(1000); + setFogColor(mUnderwaterColor * mUnderwaterWeight + mFogColor * (1.f-mUnderwaterWeight)); + mStateUpdater->setFogStart(mViewDistance * (1 - mUnderwaterFog)); + mStateUpdater->setFogEnd(mViewDistance); } else { diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 1ddab7338..3e17ef413 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -79,7 +79,7 @@ namespace MWRender void configureAmbient(const ESM::Cell* cell); void configureFog(const ESM::Cell* cell); - void configureFog(float fogDepth, const osg::Vec4f& colour); + void configureFog(float fogDepth, float underwaterFog, const osg::Vec4f& colour); void addCell(const MWWorld::CellStore* store); void removeCell(const MWWorld::CellStore* store); @@ -192,6 +192,10 @@ namespace MWRender osg::ref_ptr mStateUpdater; float mFogDepth; + osg::Vec4f mUnderwaterColor; + float mUnderwaterWeight; + float mUnderwaterFog; + float mUnderwaterIndoorFog; osg::Vec4f mFogColor; osg::Vec4f mAmbientColor; diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 5008d8fbf..8920c17b4 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -438,6 +438,10 @@ WeatherManager::WeatherManager(MWRender::RenderingManager& rendering, const MWWo , mDayEnd(mSunsetTime) , mHoursBetweenWeatherChanges(fallback.getFallbackFloat("Weather_Hours_Between_Weather_Changes")) , mRainSpeed(fallback.getFallbackFloat("Weather_Precip_Gravity")) + , mUnderwaterSunriseFog(fallback.getFallbackFloat("Water_UnderwaterSunriseFog")) + , mUnderwaterDayFog(fallback.getFallbackFloat("Water_UnderwaterDayFog")) + , mUnderwaterSunsetFog(fallback.getFallbackFloat("Water_UnderwaterSunsetFog")) + , mUnderwaterNightFog(fallback.getFallbackFloat("Water_UnderwaterNightFog")) , mWeatherSettings() , mMasser("Masser", fallback) , mSecunda("Secunda", fallback) @@ -624,6 +628,53 @@ void WeatherManager::update(float duration, bool paused) mRendering.setSunDirection( final * -1 ); } + // TODO: use pre/post sunset/sunrise time values in [Weather] section + // TODO: factor out the time of day interpolation code to reuse for calculateWeatherResult() + float gameHour = time.getHour(); + float underwaterFog; + // night + if (gameHour <= mNightEnd || gameHour >= mNightStart + 1) + underwaterFog = mUnderwaterNightFog; + // sunrise + else if (gameHour >= mNightEnd && gameHour <= mDayStart + 1) + { + if (gameHour <= mSunriseTime) + { + // fade in + float advance = mSunriseTime - gameHour; + float factor = advance / 0.5f; + underwaterFog = lerp(mUnderwaterSunriseFog, mUnderwaterNightFog, factor); + } + else //if (gameHour >= 6) + { + // fade out + float advance = gameHour - mSunriseTime; + float factor = advance / 3.f; + underwaterFog = lerp(mUnderwaterSunriseFog, mUnderwaterDayFog, factor); + } + } + // day + else if (gameHour >= mDayStart + 1 && gameHour <= mDayEnd - 1) + underwaterFog = mUnderwaterDayFog; + // sunset + else if (gameHour >= mDayEnd - 1 && gameHour <= mNightStart + 1) + { + if (gameHour <= mDayEnd + 1) + { + // fade in + float advance = (mDayEnd + 1) - gameHour; + float factor = (advance / 2); + underwaterFog = lerp(mUnderwaterSunsetFog, mUnderwaterDayFog, factor); + } + else //if (gameHour >= 19) + { + // fade out + float advance = gameHour - (mDayEnd + 1); + float factor = advance / 2.f; + underwaterFog = lerp(mUnderwaterSunsetFog, mUnderwaterNightFog, factor); + } + } + float peakHour = mSunriseTime + (mSunsetTime - mSunriseTime) / 2; if (time.getHour() < mSunriseTime || time.getHour() > mSunsetTime) mRendering.getSkyManager()->setGlareTimeOfDayFade(0); @@ -635,7 +686,7 @@ void WeatherManager::update(float duration, bool paused) mRendering.getSkyManager()->setMasserState(mMasser.calculateState(time)); mRendering.getSkyManager()->setSecundaState(mSecunda.calculateState(time)); - mRendering.configureFog(mResult.mFogDepth, mResult.mFogColor); + mRendering.configureFog(mResult.mFogDepth, underwaterFog, mResult.mFogColor); mRendering.setAmbientColour(mResult.mAmbientColor); mRendering.setSunColour(mResult.mSunColor); diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index 7ce7c1bf8..a1a7d3077 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -249,6 +249,13 @@ namespace MWWorld float mDayEnd; float mHoursBetweenWeatherChanges; float mRainSpeed; + + // underwater fog not really related to weather, but we handle it here because it's convenient + float mUnderwaterSunriseFog; + float mUnderwaterDayFog; + float mUnderwaterSunsetFog; + float mUnderwaterNightFog; + std::vector mWeatherSettings; MoonModel mMasser; MoonModel mSecunda; From 45bf3e6788a8d6649c0bb5e7771bcbe8abc6f8d0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 1 Nov 2015 22:47:40 +0100 Subject: [PATCH 2331/3725] Create TimeOfDayInterpolator class to refactor time handling in WeatherManager --- apps/openmw/mwworld/weather.cpp | 243 +++++++++++++------------------- apps/openmw/mwworld/weather.hpp | 73 ++++++---- 2 files changed, 138 insertions(+), 178 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 8920c17b4..ed43059f4 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -31,17 +31,74 @@ namespace { static const int invalidWeatherID = -1; + // linear interpolate between x and y based on factor. float lerp (float x, float y, float factor) { return x * (1-factor) + y * factor; } - + // linear interpolate between x and y based on factor. osg::Vec4f lerp (const osg::Vec4f& x, const osg::Vec4f& y, float factor) { return x * (1-factor) + y * factor; } } +template +T TimeOfDayInterpolator::getValue(const float gameHour, const TimeOfDaySettings& timeSettings) const +{ + // TODO: use pre/post sunset/sunrise time values in [Weather] section + + // night + if (gameHour <= timeSettings.mNightEnd || gameHour >= timeSettings.mNightStart + 1) + return mNightValue; + // sunrise + else if (gameHour >= timeSettings.mNightEnd && gameHour <= timeSettings.mDayStart + 1) + { + if (gameHour <= timeSettings.mSunriseTime) + { + // fade in + float advance = timeSettings.mSunriseTime - gameHour; + float factor = advance / 0.5f; + return lerp(mSunriseValue, mNightValue, factor); + } + else + { + // fade out + float advance = gameHour - timeSettings.mSunriseTime; + float factor = advance / 3.f; + return lerp(mSunriseValue, mDayValue, factor); + } + } + // day + else if (gameHour >= timeSettings.mDayStart + 1 && gameHour <= timeSettings.mDayEnd - 1) + return mDayValue; + // sunset + else if (gameHour >= timeSettings.mDayEnd - 1 && gameHour <= timeSettings.mNightStart + 1) + { + if (gameHour <= timeSettings.mDayEnd + 1) + { + // fade in + float advance = (timeSettings.mDayEnd + 1) - gameHour; + float factor = (advance / 2); + return lerp(mSunsetValue, mDayValue, factor); + } + else + { + // fade out + float advance = gameHour - (timeSettings.mDayEnd + 1); + float factor = advance / 2.f; + return lerp(mSunsetValue, mNightValue, factor); + } + } + // shut up compiler + return T(); +} + + + +template class TimeOfDayInterpolator; +template class TimeOfDayInterpolator; + Weather::Weather(const std::string& name, const MWWorld::Fallback& fallback, float stormWindSpeed, @@ -49,22 +106,22 @@ Weather::Weather(const std::string& name, const std::string& ambientLoopSoundID, const std::string& particleEffect) : mCloudTexture(fallback.getFallbackString("Weather_" + name + "_Cloud_Texture")) - , mSkySunriseColor(fallback.getFallbackColour("Weather_" + name +"_Sky_Sunrise_Color")) - , mSkyDayColor(fallback.getFallbackColour("Weather_" + name + "_Sky_Day_Color")) - , mSkySunsetColor(fallback.getFallbackColour("Weather_" + name + "_Sky_Sunset_Color")) - , mSkyNightColor(fallback.getFallbackColour("Weather_" + name + "_Sky_Night_Color")) - , mFogSunriseColor(fallback.getFallbackColour("Weather_" + name + "_Fog_Sunrise_Color")) - , mFogDayColor(fallback.getFallbackColour("Weather_" + name + "_Fog_Day_Color")) - , mFogSunsetColor(fallback.getFallbackColour("Weather_" + name + "_Fog_Sunset_Color")) - , mFogNightColor(fallback.getFallbackColour("Weather_" + name + "_Fog_Night_Color")) - , mAmbientSunriseColor(fallback.getFallbackColour("Weather_" + name + "_Ambient_Sunrise_Color")) - , mAmbientDayColor(fallback.getFallbackColour("Weather_" + name + "_Ambient_Day_Color")) - , mAmbientSunsetColor(fallback.getFallbackColour("Weather_" + name + "_Ambient_Sunset_Color")) - , mAmbientNightColor(fallback.getFallbackColour("Weather_" + name + "_Ambient_Night_Color")) - , mSunSunriseColor(fallback.getFallbackColour("Weather_" + name + "_Sun_Sunrise_Color")) - , mSunDayColor(fallback.getFallbackColour("Weather_" + name + "_Sun_Day_Color")) - , mSunSunsetColor(fallback.getFallbackColour("Weather_" + name + "_Sun_Sunset_Color")) - , mSunNightColor(fallback.getFallbackColour("Weather_" + name + "_Sun_Night_Color")) + , mSkyColor(fallback.getFallbackColour("Weather_" + name +"_Sky_Sunrise_Color"), + fallback.getFallbackColour("Weather_" + name + "_Sky_Day_Color"), + fallback.getFallbackColour("Weather_" + name + "_Sky_Sunset_Color"), + fallback.getFallbackColour("Weather_" + name + "_Sky_Night_Color")) + , mFogColor(fallback.getFallbackColour("Weather_" + name + "_Fog_Sunrise_Color"), + fallback.getFallbackColour("Weather_" + name + "_Fog_Day_Color"), + fallback.getFallbackColour("Weather_" + name + "_Fog_Sunset_Color"), + fallback.getFallbackColour("Weather_" + name + "_Fog_Night_Color")) + , mAmbientColor(fallback.getFallbackColour("Weather_" + name + "_Ambient_Sunrise_Color"), + fallback.getFallbackColour("Weather_" + name + "_Ambient_Day_Color"), + fallback.getFallbackColour("Weather_" + name + "_Ambient_Sunset_Color"), + fallback.getFallbackColour("Weather_" + name + "_Ambient_Night_Color")) + , mSunColor(fallback.getFallbackColour("Weather_" + name + "_Sun_Sunrise_Color"), + fallback.getFallbackColour("Weather_" + name + "_Sun_Day_Color"), + fallback.getFallbackColour("Weather_" + name + "_Sun_Sunset_Color"), + fallback.getFallbackColour("Weather_" + name + "_Sun_Night_Color")) , mLandFogDayDepth(fallback.getFallbackFloat("Weather_" + name + "_Land_Fog_Day_Depth")) , mLandFogNightDepth(fallback.getFallbackFloat("Weather_" + name + "_Land_Fog_Night_Depth")) , mSunDiscSunsetColor(fallback.getFallbackColour("Weather_" + name + "_Sun_Disc_Sunset_Color")) @@ -432,16 +489,13 @@ WeatherManager::WeatherManager(MWRender::RenderingManager& rendering, const MWWo , mSunriseDuration(fallback.getFallbackFloat("Weather_Sunrise_Duration")) , mSunsetDuration(fallback.getFallbackFloat("Weather_Sunset_Duration")) , mSunPreSunsetTime(fallback.getFallbackFloat("Weather_Sun_Pre-Sunset_Time")) - , mNightStart(mSunsetTime + mSunsetDuration) - , mNightEnd(mSunriseTime - 0.5f) - , mDayStart(mSunriseTime + mSunriseDuration) - , mDayEnd(mSunsetTime) + , mNightFade(0, 0, 0, 1) , mHoursBetweenWeatherChanges(fallback.getFallbackFloat("Weather_Hours_Between_Weather_Changes")) , mRainSpeed(fallback.getFallbackFloat("Weather_Precip_Gravity")) - , mUnderwaterSunriseFog(fallback.getFallbackFloat("Water_UnderwaterSunriseFog")) - , mUnderwaterDayFog(fallback.getFallbackFloat("Water_UnderwaterDayFog")) - , mUnderwaterSunsetFog(fallback.getFallbackFloat("Water_UnderwaterSunsetFog")) - , mUnderwaterNightFog(fallback.getFallbackFloat("Water_UnderwaterNightFog")) + , mUnderwaterFog(fallback.getFallbackFloat("Water_UnderwaterSunriseFog"), + fallback.getFallbackFloat("Water_UnderwaterDayFog"), + fallback.getFallbackFloat("Water_UnderwaterSunsetFog"), + fallback.getFallbackFloat("Water_UnderwaterNightFog")) , mWeatherSettings() , mMasser("Masser", fallback) , mSecunda("Secunda", fallback) @@ -461,6 +515,12 @@ WeatherManager::WeatherManager(MWRender::RenderingManager& rendering, const MWWo , mAmbientSound() , mPlayingSoundID() { + mTimeSettings.mNightStart = mSunsetTime + mSunsetDuration; + mTimeSettings.mNightEnd = mSunriseTime - 0.5f; + mTimeSettings.mDayStart = mSunriseTime + mSunriseDuration; + mTimeSettings.mDayEnd = mSunsetTime; + mTimeSettings.mSunriseTime = mSunriseTime; + mWeatherSettings.reserve(10); addWeather("Clear", fallback); // 0 addWeather("Cloudy", fallback); // 1 @@ -593,7 +653,7 @@ void WeatherManager::update(float duration, bool paused) } // disable sun during night - if (time.getHour() >= mNightStart || time.getHour() <= mSunriseTime) + if (time.getHour() >= mTimeSettings.mNightStart || time.getHour() <= mSunriseTime) mRendering.getSkyManager()->sunDisable(); else mRendering.getSkyManager()->sunEnable(); @@ -604,10 +664,10 @@ void WeatherManager::update(float duration, bool paused) { // Shift times into a 24-hour window beginning at mSunriseTime... float adjustedHour = time.getHour(); - float adjustedNightStart = mNightStart; + float adjustedNightStart = mTimeSettings.mNightStart; if ( time.getHour() < mSunriseTime ) adjustedHour += 24.f; - if ( mNightStart < mSunriseTime ) + if ( mTimeSettings.mNightStart < mSunriseTime ) adjustedNightStart += 24.f; const bool is_night = adjustedHour >= adjustedNightStart; @@ -628,52 +688,7 @@ void WeatherManager::update(float duration, bool paused) mRendering.setSunDirection( final * -1 ); } - // TODO: use pre/post sunset/sunrise time values in [Weather] section - // TODO: factor out the time of day interpolation code to reuse for calculateWeatherResult() - float gameHour = time.getHour(); - float underwaterFog; - // night - if (gameHour <= mNightEnd || gameHour >= mNightStart + 1) - underwaterFog = mUnderwaterNightFog; - // sunrise - else if (gameHour >= mNightEnd && gameHour <= mDayStart + 1) - { - if (gameHour <= mSunriseTime) - { - // fade in - float advance = mSunriseTime - gameHour; - float factor = advance / 0.5f; - underwaterFog = lerp(mUnderwaterSunriseFog, mUnderwaterNightFog, factor); - } - else //if (gameHour >= 6) - { - // fade out - float advance = gameHour - mSunriseTime; - float factor = advance / 3.f; - underwaterFog = lerp(mUnderwaterSunriseFog, mUnderwaterDayFog, factor); - } - } - // day - else if (gameHour >= mDayStart + 1 && gameHour <= mDayEnd - 1) - underwaterFog = mUnderwaterDayFog; - // sunset - else if (gameHour >= mDayEnd - 1 && gameHour <= mNightStart + 1) - { - if (gameHour <= mDayEnd + 1) - { - // fade in - float advance = (mDayEnd + 1) - gameHour; - float factor = (advance / 2); - underwaterFog = lerp(mUnderwaterSunsetFog, mUnderwaterDayFog, factor); - } - else //if (gameHour >= 19) - { - // fade out - float advance = gameHour - (mDayEnd + 1); - float factor = advance / 2.f; - underwaterFog = lerp(mUnderwaterSunsetFog, mUnderwaterNightFog, factor); - } - } + float underwaterFog = mUnderwaterFog.getValue(time.getHour(), mTimeSettings); float peakHour = mSunriseTime + (mSunsetTime - mSunriseTime) / 2; if (time.getHour() < mSunriseTime || time.getHour() > mSunsetTime) @@ -748,7 +763,7 @@ bool WeatherManager::isDark() const TimeStamp time = MWBase::Environment::get().getWorld()->getTimeStamp(); bool exterior = (MWBase::Environment::get().getWorld()->isCellExterior() || MWBase::Environment::get().getWorld()->isCellQuasiExterior()); - return exterior && (time.getHour() < mSunriseTime || time.getHour() > mNightStart - 1); + return exterior && (time.getHour() < mSunriseTime || time.getHour() > mTimeSettings.mNightStart - 1); } void WeatherManager::write(ESM::ESMWriter& writer, Loading::Listener& progress) @@ -1026,81 +1041,15 @@ inline void WeatherManager::calculateResult(const int weatherID, const float gam mResult.mParticleEffect = current.mParticleEffect; mResult.mRainEffect = current.mRainEffect; - mResult.mNight = (gameHour < mSunriseTime || gameHour > mNightStart - 1); + mResult.mNight = (gameHour < mSunriseTime || gameHour > mTimeSettings.mNightStart - 1); mResult.mFogDepth = mResult.mNight ? current.mLandFogNightDepth : current.mLandFogDayDepth; - // TODO: use pre/post sunset/sunrise time values in [Weather] section - // night - if (gameHour <= mNightEnd || gameHour >= mNightStart + 1) - { - mResult.mFogColor = current.mFogNightColor; - mResult.mAmbientColor = current.mAmbientNightColor; - mResult.mSunColor = current.mSunNightColor; - mResult.mSkyColor = current.mSkyNightColor; - mResult.mNightFade = 1.f; - } - - // sunrise - else if (gameHour >= mNightEnd && gameHour <= mDayStart + 1) - { - if (gameHour <= mSunriseTime) - { - // fade in - float advance = mSunriseTime - gameHour; - float factor = advance / 0.5f; - mResult.mFogColor = lerp(current.mFogSunriseColor, current.mFogNightColor, factor); - mResult.mAmbientColor = lerp(current.mAmbientSunriseColor, current.mAmbientNightColor, factor); - mResult.mSunColor = lerp(current.mSunSunriseColor, current.mSunNightColor, factor); - mResult.mSkyColor = lerp(current.mSkySunriseColor, current.mSkyNightColor, factor); - mResult.mNightFade = factor; - } - else //if (gameHour >= 6) - { - // fade out - float advance = gameHour - mSunriseTime; - float factor = advance / 3.f; - mResult.mFogColor = lerp(current.mFogSunriseColor, current.mFogDayColor, factor); - mResult.mAmbientColor = lerp(current.mAmbientSunriseColor, current.mAmbientDayColor, factor); - mResult.mSunColor = lerp(current.mSunSunriseColor, current.mSunDayColor, factor); - mResult.mSkyColor = lerp(current.mSkySunriseColor, current.mSkyDayColor, factor); - } - } - - // day - else if (gameHour >= mDayStart + 1 && gameHour <= mDayEnd - 1) - { - mResult.mFogColor = current.mFogDayColor; - mResult.mAmbientColor = current.mAmbientDayColor; - mResult.mSunColor = current.mSunDayColor; - mResult.mSkyColor = current.mSkyDayColor; - } - - // sunset - else if (gameHour >= mDayEnd - 1 && gameHour <= mNightStart + 1) - { - if (gameHour <= mDayEnd + 1) - { - // fade in - float advance = (mDayEnd + 1) - gameHour; - float factor = (advance / 2); - mResult.mFogColor = lerp(current.mFogSunsetColor, current.mFogDayColor, factor); - mResult.mAmbientColor = lerp(current.mAmbientSunsetColor, current.mAmbientDayColor, factor); - mResult.mSunColor = lerp(current.mSunSunsetColor, current.mSunDayColor, factor); - mResult.mSkyColor = lerp(current.mSkySunsetColor, current.mSkyDayColor, factor); - } - else //if (gameHour >= 19) - { - // fade out - float advance = gameHour - (mDayEnd + 1); - float factor = advance / 2.f; - mResult.mFogColor = lerp(current.mFogSunsetColor, current.mFogNightColor, factor); - mResult.mAmbientColor = lerp(current.mAmbientSunsetColor, current.mAmbientNightColor, factor); - mResult.mSunColor = lerp(current.mSunSunsetColor, current.mSunNightColor, factor); - mResult.mSkyColor = lerp(current.mSkySunsetColor, current.mSkyNightColor, factor); - mResult.mNightFade = factor; - } - } + mResult.mFogColor = current.mFogColor.getValue(gameHour, mTimeSettings); + mResult.mAmbientColor = current.mAmbientColor.getValue(gameHour, mTimeSettings); + mResult.mSunColor = current.mSunColor.getValue(gameHour, mTimeSettings); + mResult.mSkyColor = current.mSkyColor.getValue(gameHour, mTimeSettings); + mResult.mNightFade = mNightFade.getValue(gameHour, mTimeSettings); if (gameHour >= mSunsetTime - mSunPreSunsetTime) { diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index a1a7d3077..86d1898fa 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -34,6 +34,33 @@ namespace MWWorld class Fallback; class TimeStamp; + + struct TimeOfDaySettings + { + float mNightStart; + float mNightEnd; + float mDayStart; + float mDayEnd; + float mSunriseTime; + }; + + /// Interpolates between 4 data points (sunrise, day, sunset, night) based on the time of day. + /// The template value could be a floating point number, or a color. + template + class TimeOfDayInterpolator + { + public: + TimeOfDayInterpolator(const T& sunrise, const T& day, const T& sunset, const T& night) + : mSunriseValue(sunrise), mDayValue(day), mSunsetValue(sunset), mNightValue(night) + { + } + + T getValue (const float gameHour, const TimeOfDaySettings& timeSettings) const; + + private: + T mSunriseValue, mDayValue, mSunsetValue, mNightValue; + }; + /// Defines a single weather setting (according to INI) class Weather { @@ -47,29 +74,14 @@ namespace MWWorld std::string mCloudTexture; - // Sky (atmosphere) colors - osg::Vec4f mSkySunriseColor; - osg::Vec4f mSkyDayColor; - osg::Vec4f mSkySunsetColor; - osg::Vec4f mSkyNightColor; - - // Fog colors - osg::Vec4f mFogSunriseColor; - osg::Vec4f mFogDayColor; - osg::Vec4f mFogSunsetColor; - osg::Vec4f mFogNightColor; - - // Ambient lighting colors - osg::Vec4f mAmbientSunriseColor; - osg::Vec4f mAmbientDayColor; - osg::Vec4f mAmbientSunsetColor; - osg::Vec4f mAmbientNightColor; - - // Sun (directional) lighting colors - osg::Vec4f mSunSunriseColor; - osg::Vec4f mSunDayColor; - osg::Vec4f mSunSunsetColor; - osg::Vec4f mSunNightColor; + // Sky (atmosphere) color + TimeOfDayInterpolator mSkyColor; + // Fog color + TimeOfDayInterpolator mFogColor; + // Ambient lighting color + TimeOfDayInterpolator mAmbientColor; + // Sun (directional) lighting color + TimeOfDayInterpolator mSunColor; // Fog depth/density float mLandFogDayDepth; @@ -243,18 +255,17 @@ namespace MWWorld float mSunriseDuration; float mSunsetDuration; float mSunPreSunsetTime; - float mNightStart; - float mNightEnd; - float mDayStart; - float mDayEnd; + + TimeOfDaySettings mTimeSettings; + + // fading of night skydome + TimeOfDayInterpolator mNightFade; + float mHoursBetweenWeatherChanges; float mRainSpeed; // underwater fog not really related to weather, but we handle it here because it's convenient - float mUnderwaterSunriseFog; - float mUnderwaterDayFog; - float mUnderwaterSunsetFog; - float mUnderwaterNightFog; + TimeOfDayInterpolator mUnderwaterFog; std::vector mWeatherSettings; MoonModel mMasser; From 802620a86b08850f07a88b1eea1120d0b5ac1ea0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 1 Nov 2015 23:03:16 +0100 Subject: [PATCH 2332/3725] Use TimeOfDayInterpolator for Land Fog Depth Fixes the sudden fog jump at nightfall. --- apps/openmw/mwworld/weather.cpp | 9 +++++---- apps/openmw/mwworld/weather.hpp | 3 +-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index ed43059f4..24b45fcea 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -122,8 +122,10 @@ Weather::Weather(const std::string& name, fallback.getFallbackColour("Weather_" + name + "_Sun_Day_Color"), fallback.getFallbackColour("Weather_" + name + "_Sun_Sunset_Color"), fallback.getFallbackColour("Weather_" + name + "_Sun_Night_Color")) - , mLandFogDayDepth(fallback.getFallbackFloat("Weather_" + name + "_Land_Fog_Day_Depth")) - , mLandFogNightDepth(fallback.getFallbackFloat("Weather_" + name + "_Land_Fog_Night_Depth")) + , mLandFogDepth(fallback.getFallbackFloat("Weather_" + name + "_Land_Fog_Day_Depth"), + fallback.getFallbackFloat("Weather_" + name + "_Land_Fog_Day_Depth"), + fallback.getFallbackFloat("Weather_" + name + "_Land_Fog_Day_Depth"), + fallback.getFallbackFloat("Weather_" + name + "_Land_Fog_Night_Depth")) , mSunDiscSunsetColor(fallback.getFallbackColour("Weather_" + name + "_Sun_Disc_Sunset_Color")) , mWindSpeed(fallback.getFallbackFloat("Weather_" + name + "_Wind_Speed")) , mCloudSpeed(fallback.getFallbackFloat("Weather_" + name + "_Cloud_Speed")) @@ -1043,8 +1045,7 @@ inline void WeatherManager::calculateResult(const int weatherID, const float gam mResult.mNight = (gameHour < mSunriseTime || gameHour > mTimeSettings.mNightStart - 1); - mResult.mFogDepth = mResult.mNight ? current.mLandFogNightDepth : current.mLandFogDayDepth; - + mResult.mFogDepth = current.mLandFogDepth.getValue(gameHour, mTimeSettings); mResult.mFogColor = current.mFogColor.getValue(gameHour, mTimeSettings); mResult.mAmbientColor = current.mAmbientColor.getValue(gameHour, mTimeSettings); mResult.mSunColor = current.mSunColor.getValue(gameHour, mTimeSettings); diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index 86d1898fa..4a78350fe 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -84,8 +84,7 @@ namespace MWWorld TimeOfDayInterpolator mSunColor; // Fog depth/density - float mLandFogDayDepth; - float mLandFogNightDepth; + TimeOfDayInterpolator mLandFogDepth; // Color modulation for the sun itself during sunset osg::Vec4f mSunDiscSunsetColor; From 4690ec12cc80cada2d026caa6b1c6c560d8a7689 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 2 Nov 2015 00:29:09 +0100 Subject: [PATCH 2333/3725] Render the water plane with GL_DEPTH_CLAMP if supported (Fixes #996) --- apps/openmw/mwrender/water.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 251a1232c..20710ab7e 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include @@ -389,6 +390,24 @@ private: osg::ref_ptr mScene; }; +/// DepthClampCallback enables GL_DEPTH_CLAMP for the current draw, if supported. +class DepthClampCallback : public osg::Drawable::DrawCallback +{ +public: + virtual void drawImplementation(osg::RenderInfo& renderInfo,const osg::Drawable* drawable) const + { + if (!osg::isGLExtensionOrVersionSupported(renderInfo.getState()->getContextID(), "GL_ARB_depth_clamp", 3.3)) + drawable->drawImplementation(renderInfo); + + glEnable(GL_DEPTH_CLAMP); + + drawable->drawImplementation(renderInfo); + + // restore default + glDisable(GL_DEPTH_CLAMP); + } +}; + Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem *resourceSystem, osgUtil::IncrementalCompileOperation *ico, const MWWorld::Fallback* fallback, const std::string& resourcePath) : mParent(parent) @@ -402,6 +421,7 @@ Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem mSimulation.reset(new RippleSimulation(parent, resourceSystem, fallback)); osg::ref_ptr waterGeom = createWaterGeometry(CELL_SIZE*150, 40, 900); + waterGeom->setDrawCallback(new DepthClampCallback); mWaterGeode = new osg::Geode; mWaterGeode->addDrawable(waterGeom); From c60388afb68afa22d433f7d9dfaa4ea3e0a95a0f Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 2 Nov 2015 00:30:18 +0100 Subject: [PATCH 2334/3725] Add fudge factor to move the water mesh away from camera when the camera gets too close --- apps/openmw/mwrender/water.cpp | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 20710ab7e..c44f480f8 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -205,6 +205,36 @@ public: } }; +/// Moves water mesh away from the camera slightly if the camera gets to close on the Z axis. +/// The offset works around graphics artifacts that occured with the GL_DEPTH_CLAMP when the camera gets extremely close to the mesh (seen on NVIDIA at least). +/// Must be added as a Cull callback. +class FudgeCallback : public osg::NodeCallback +{ +public: + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) + { + osgUtil::CullVisitor* cv = static_cast(nv); + + const float fudge = 0.1; + if (std::abs(cv->getEyeLocal().z()) < fudge) + { + float diff = fudge - cv->getEyeLocal().z(); + osg::RefMatrix* modelViewMatrix = new osg::RefMatrix(*cv->getModelViewMatrix()); + + if (cv->getEyeLocal().z() > 0) + modelViewMatrix->preMultTranslate(osg::Vec3f(0,0,-diff)); + else + modelViewMatrix->preMultTranslate(osg::Vec3f(0,0,diff)); + + cv->pushModelViewMatrix(modelViewMatrix, osg::Transform::RELATIVE_RF); + traverse(node, nv); + cv->popModelViewMatrix(); + } + else + traverse(node, nv); + } +}; + osg::ref_ptr readShader (osg::Shader::Type type, const std::string& file, const std::map& defineMap = std::map()) { osg::ref_ptr shader (new osg::Shader(type)); @@ -432,6 +462,7 @@ Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem mWaterNode = new osg::PositionAttitudeTransform; mWaterNode->addChild(mWaterGeode); + mWaterNode->addCullCallback(new FudgeCallback); // simple water fallback for the local map osg::ref_ptr geode2 (osg::clone(mWaterGeode.get(), osg::CopyOp::DEEP_COPY_NODES)); From 913bbe347b0b0704800d61b3470d11fc69e36ab7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 2 Nov 2015 00:52:20 +0100 Subject: [PATCH 2335/3725] Don't check the extension string every frame --- apps/openmw/mwrender/water.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index c44f480f8..c6061b40a 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -426,8 +426,12 @@ class DepthClampCallback : public osg::Drawable::DrawCallback public: virtual void drawImplementation(osg::RenderInfo& renderInfo,const osg::Drawable* drawable) const { - if (!osg::isGLExtensionOrVersionSupported(renderInfo.getState()->getContextID(), "GL_ARB_depth_clamp", 3.3)) + static bool supported = osg::isGLExtensionOrVersionSupported(renderInfo.getState()->getContextID(), "GL_ARB_depth_clamp", 3.3); + if (!supported) + { drawable->drawImplementation(renderInfo); + return; + } glEnable(GL_DEPTH_CLAMP); From 3f988327c7178d3c6a106c1366e9a23bd0084104 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 2 Nov 2015 00:57:59 +0100 Subject: [PATCH 2336/3725] Destructor fix --- apps/openmw/mwrender/water.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index c6061b40a..046164698 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -613,6 +613,17 @@ void Water::processChangedSettings(const Settings::CategorySettingVector& settin Water::~Water() { mParent->removeChild(mWaterNode); + + if (mReflection) + { + mParent->removeChild(mReflection); + mReflection = NULL; + } + if (mRefraction) + { + mParent->removeChild(mRefraction); + mRefraction = NULL; + } } void Water::setEnabled(bool enabled) From 0348b8df1c25b5134ee28c0f6c25d1682fd03000 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 2 Nov 2015 01:23:21 +0100 Subject: [PATCH 2337/3725] Fix applying of plane height in ClipCullNode (Fixes #2985) --- apps/openmw/mwrender/water.cpp | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 046164698..bb6d549e0 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -145,14 +145,18 @@ class ClipCullNode : public osg::Group osg::RefMatrix* modelViewMatrix = new osg::RefMatrix(*cv->getModelViewMatrix()); + // move the plane back along its normal a little bit to prevent bleeding at the water shore + const float clipFudge = -5; + // now apply the height of the plane + // we can't apply this height in the addClipPlane() since the "flip the below graph" function would otherwise flip the height as well + float translate = clipFudge + ((*mCullPlane)[3] * -1); + modelViewMatrix->preMultTranslate(mCullPlane->getNormal() * translate); + // flip the below graph if the eye point is above the plane if (mCullPlane->intersect(osg::BoundingSphere(osg::Vec3d(0,0,eyePoint.z()), 0)) > 0) { modelViewMatrix->preMultScale(osg::Vec3(1,1,-1)); } - // move the plane back along its normal a little bit to prevent bleeding at the water shore - const float clipFudge = 5; - modelViewMatrix->preMultTranslate(mCullPlane->getNormal() * (-clipFudge)); cv->pushModelViewMatrix(modelViewMatrix, osg::Transform::RELATIVE_RF); traverse(node, nv); @@ -168,7 +172,7 @@ public: { addCullCallback (new PlaneCullCallback(&mPlane)); - mClipNodeTransform = new osg::PositionAttitudeTransform; + mClipNodeTransform = new osg::Group; mClipNodeTransform->addCullCallback(new FlipCallback(&mPlane)); addChild(mClipNodeTransform); @@ -184,12 +188,12 @@ public: mPlane = plane; mClipNode->getClipPlaneList().clear(); - mClipNode->addClipPlane(new osg::ClipPlane(0, mPlane)); + mClipNode->addClipPlane(new osg::ClipPlane(0, osg::Plane(mPlane.getNormal(), 0))); // mPlane.d() applied in FlipCallback mClipNode->setStateSetModes(*getOrCreateStateSet(), osg::StateAttribute::ON); } private: - osg::ref_ptr mClipNodeTransform; + osg::ref_ptr mClipNodeTransform; osg::ref_ptr mClipNode; osg::Plane mPlane; @@ -205,7 +209,7 @@ public: } }; -/// Moves water mesh away from the camera slightly if the camera gets to close on the Z axis. +/// Moves water mesh away from the camera slightly if the camera gets too close on the Z axis. /// The offset works around graphics artifacts that occured with the GL_DEPTH_CLAMP when the camera gets extremely close to the mesh (seen on NVIDIA at least). /// Must be added as a Cull callback. class FudgeCallback : public osg::NodeCallback @@ -215,7 +219,7 @@ public: { osgUtil::CullVisitor* cv = static_cast(nv); - const float fudge = 0.1; + const float fudge = 0.2; if (std::abs(cv->getEyeLocal().z()) < fudge) { float diff = fudge - cv->getEyeLocal().z(); From bd1f3493d76cf2ab3b2b5ca2dc1e90c062e6ca38 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 2 Nov 2015 21:35:03 +0100 Subject: [PATCH 2338/3725] Fix weather particles not being cleared when changing from one particle effect to another --- apps/openmw/mwrender/sky.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index b0af85c0b..240dff7fd 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1432,6 +1432,14 @@ void SkyManager::setWeather(const WeatherResult& weather) { mCurrentParticleEffect = weather.mParticleEffect; + // cleanup old particles + if (mParticleEffect) + { + mParticleNode->removeChild(mParticleEffect); + mParticleEffect = NULL; + mParticleFader = NULL; + } + if (mCurrentParticleEffect.empty()) { if (mParticleNode) @@ -1439,8 +1447,6 @@ void SkyManager::setWeather(const WeatherResult& weather) mRootNode->removeChild(mParticleNode); mParticleNode = NULL; } - mParticleEffect = NULL; - mParticleFader = NULL; } else { From d6f45c33906072aad42f29a59d835a031ebb14bc Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 2 Nov 2015 21:51:01 +0100 Subject: [PATCH 2339/3725] Fix the renderbin for weather particles Regression from commit 2ee6b41887b8dff5231f9925c6a0205a75d67159 --- apps/openmw/mwrender/sky.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 240dff7fd..7d67d38f0 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1453,6 +1453,8 @@ void SkyManager::setWeather(const WeatherResult& weather) if (!mParticleNode) { mParticleNode = new osg::PositionAttitudeTransform; + mParticleNode->getOrCreateStateSet()->setRenderBinDetails(RenderBin_Default, "RenderBin"); + mParticleNode->getOrCreateStateSet()->setNestRenderBins(false); mRootNode->addChild(mParticleNode); } mParticleEffect = mSceneManager->createInstance(mCurrentParticleEffect, mParticleNode); From 5ca0ae52321380e7b5850b9b1ee37dd378fa7ab6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 2 Nov 2015 23:38:34 +0100 Subject: [PATCH 2340/3725] Don't add the same AlphaFader to multiple nodes --- apps/openmw/mwrender/sky.cpp | 25 +++++++++++++----------- apps/openmw/mwrender/sky.hpp | 2 +- components/sceneutil/statesetupdater.hpp | 1 + 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 7d67d38f0..a4f357322 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1196,14 +1196,13 @@ public: mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0,0,0,mAlpha)); } - // Helper for adding AlphaFader to a subgraph + // Helper for adding AlphaFaders to a subgraph class SetupVisitor : public osg::NodeVisitor { public: SetupVisitor() : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) { - mAlphaFader = new AlphaFader; } virtual void apply(osg::Node &node) @@ -1225,22 +1224,26 @@ public: callback = callback->getNestedCallback(); } + osg::ref_ptr alphaFader (new AlphaFader); + if (composite) - composite->addController(mAlphaFader); + composite->addController(alphaFader); else - node.addUpdateCallback(mAlphaFader); + node.addUpdateCallback(alphaFader); + + mAlphaFaders.push_back(alphaFader); } } traverse(node); } - osg::ref_ptr getAlphaFader() + std::vector > getAlphaFaders() { - return mAlphaFader; + return mAlphaFaders; } private: - osg::ref_ptr mAlphaFader; + std::vector > mAlphaFaders; }; private: @@ -1437,7 +1440,7 @@ void SkyManager::setWeather(const WeatherResult& weather) { mParticleNode->removeChild(mParticleEffect); mParticleEffect = NULL; - mParticleFader = NULL; + mParticleFaders.clear(); } if (mCurrentParticleEffect.empty()) @@ -1464,7 +1467,7 @@ void SkyManager::setWeather(const WeatherResult& weather) AlphaFader::SetupVisitor alphaFaderSetupVisitor; mParticleEffect->accept(alphaFaderSetupVisitor); - mParticleFader = alphaFaderSetupVisitor.getAlphaFader(); + mParticleFaders = alphaFaderSetupVisitor.getAlphaFaders(); } } @@ -1545,8 +1548,8 @@ void SkyManager::setWeather(const WeatherResult& weather) if (mRainFader) mRainFader->setAlpha(weather.mEffectFade * 0.6); // * Rain_Threshold? - if (mParticleFader) - mParticleFader->setAlpha(weather.mEffectFade); + for (std::vector >::const_iterator it = mParticleFaders.begin(); it != mParticleFaders.end(); ++it) + (*it)->setAlpha(weather.mEffectFade); } void SkyManager::sunEnable() diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index 072083d27..a4eeb861c 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -158,7 +158,7 @@ namespace MWRender osg::ref_ptr mParticleNode; osg::ref_ptr mParticleEffect; - osg::ref_ptr mParticleFader; + std::vector > mParticleFaders; osg::ref_ptr mCloudNode; diff --git a/components/sceneutil/statesetupdater.hpp b/components/sceneutil/statesetupdater.hpp index 37d08e025..34b8da848 100644 --- a/components/sceneutil/statesetupdater.hpp +++ b/components/sceneutil/statesetupdater.hpp @@ -15,6 +15,7 @@ namespace SceneUtil /// the first StateSet is the one we can write to, the second is the one currently in use by the draw traversal of the last frame. /// After a frame is completed the places are swapped. /// @par Must be set as UpdateCallback on a Node. + /// @note Do not add the same StateSetUpdater to multiple nodes. /// @note Do not add multiple StateSetControllers on the same Node as they will conflict - instead use the CompositeStateSetUpdater. class StateSetUpdater : public osg::NodeCallback { From fd1ccd21ff587c96cbd5e1cc83a09cb66e871e5a Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 2 Nov 2015 23:49:22 +0100 Subject: [PATCH 2341/3725] Disable freezeOnCull for weather particles --- apps/openmw/mwrender/animation.cpp | 21 +------------------- apps/openmw/mwrender/sky.cpp | 4 ++++ components/sceneutil/visitor.cpp | 32 ++++++++++++++++++++++++++++++ components/sceneutil/visitor.hpp | 26 ++++++++++++++---------- 4 files changed, 52 insertions(+), 31 deletions(-) create mode 100644 components/sceneutil/visitor.cpp diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index b2fa87310..06065c566 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1111,25 +1111,6 @@ namespace MWRender attachTo->addChild(lightSource); } - class DisableFreezeOnCullVisitor : public osg::NodeVisitor - { - public: - DisableFreezeOnCullVisitor() - : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) - { - } - - virtual void apply(osg::Geode &geode) - { - for (unsigned int i=0; i(drw)) - partsys->setFreezeOnCull(false); - } - } - }; - void Animation::addEffect (const std::string& model, int effectId, bool loop, const std::string& bonename, std::string texture) { if (!mObjectRoot.get()) @@ -1163,7 +1144,7 @@ namespace MWRender node->accept(findMaxLengthVisitor); // FreezeOnCull doesn't work so well with effect particles, that tend to have moving emitters - DisableFreezeOnCullVisitor disableFreezeOnCullVisitor; + SceneUtil::DisableFreezeOnCullVisitor disableFreezeOnCullVisitor; node->accept(disableFreezeOnCullVisitor); params.mMaxControllerLength = findMaxLengthVisitor.getMaxLength(); diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index a4f357322..0f00b5a4c 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -1468,6 +1469,9 @@ void SkyManager::setWeather(const WeatherResult& weather) AlphaFader::SetupVisitor alphaFaderSetupVisitor; mParticleEffect->accept(alphaFaderSetupVisitor); mParticleFaders = alphaFaderSetupVisitor.getAlphaFaders(); + + SceneUtil::DisableFreezeOnCullVisitor disableFreezeOnCullVisitor; + mParticleEffect->accept(disableFreezeOnCullVisitor); } } diff --git a/components/sceneutil/visitor.cpp b/components/sceneutil/visitor.cpp new file mode 100644 index 000000000..3738be08d --- /dev/null +++ b/components/sceneutil/visitor.cpp @@ -0,0 +1,32 @@ +#include "visitor.hpp" + +#include + +#include + +#include + +namespace SceneUtil +{ + + void FindByNameVisitor::apply(osg::Group &group) + { + if (Misc::StringUtils::ciEqual(group.getName(), mNameToFind)) + { + mFoundNode = &group; + return; + } + traverse(group); + } + + void DisableFreezeOnCullVisitor::apply(osg::Geode &geode) + { + for (unsigned int i=0; i(drw)) + partsys->setFreezeOnCull(false); + } + } + +} diff --git a/components/sceneutil/visitor.hpp b/components/sceneutil/visitor.hpp index b9342b884..656084940 100644 --- a/components/sceneutil/visitor.hpp +++ b/components/sceneutil/visitor.hpp @@ -3,12 +3,12 @@ #include -#include - // Commonly used scene graph visitors namespace SceneUtil { + // Find a Group by name, case-insensitive + // If not found, mFoundNode will be NULL class FindByNameVisitor : public osg::NodeVisitor { public: @@ -19,20 +19,24 @@ namespace SceneUtil { } - virtual void apply(osg::Group& group) - { - if (Misc::StringUtils::ciEqual(group.getName(), mNameToFind)) - { - mFoundNode = &group; - return; - } - traverse(group); - } + virtual void apply(osg::Group& group); std::string mNameToFind; osg::Group* mFoundNode; }; + // Disable freezeOnCull for all visited particlesystems + class DisableFreezeOnCullVisitor : public osg::NodeVisitor + { + public: + DisableFreezeOnCullVisitor() + : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) + { + } + + virtual void apply(osg::Geode &geode); + }; + } #endif From ad016da31d1c36b674262631d406843563a88a83 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Nov 2015 01:42:37 +0100 Subject: [PATCH 2342/3725] Enable fog on weather particles --- apps/openmw/mwrender/sky.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 0f00b5a4c..3adc565ea 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1457,8 +1457,10 @@ void SkyManager::setWeather(const WeatherResult& weather) if (!mParticleNode) { mParticleNode = new osg::PositionAttitudeTransform; - mParticleNode->getOrCreateStateSet()->setRenderBinDetails(RenderBin_Default, "RenderBin"); - mParticleNode->getOrCreateStateSet()->setNestRenderBins(false); + osg::StateSet* particleStateSet = mParticleNode->getOrCreateStateSet(); + particleStateSet->setRenderBinDetails(RenderBin_Default, "RenderBin"); + particleStateSet->setNestRenderBins(false); + particleStateSet->setMode(GL_FOG, osg::StateAttribute::ON); mRootNode->addChild(mParticleNode); } mParticleEffect = mSceneManager->createInstance(mCurrentParticleEffect, mParticleNode); From 9902dfc9ef4be89288c824335629723782a58462 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Nov 2015 01:53:22 +0100 Subject: [PATCH 2343/3725] Comment --- apps/openmw/mwrender/water.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index bb6d549e0..84fe4fcc9 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -474,7 +474,7 @@ Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem // simple water fallback for the local map osg::ref_ptr geode2 (osg::clone(mWaterGeode.get(), osg::CopyOp::DEEP_COPY_NODES)); - createSimpleWaterStateSet(geode2); + createSimpleWaterStateSet(geode2); // Water_Map_Alpha geode2->setNodeMask(Mask_SimpleWater); mWaterNode->addChild(geode2); @@ -527,7 +527,7 @@ void Water::createSimpleWaterStateSet(osg::Node* node) osg::ref_ptr material (new osg::Material); material->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(1.f, 1.f, 1.f, 1.f)); - material->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 0.7f)); + material->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 0.7f)); // Water_World_Alpha material->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 1.f)); material->setColorMode(osg::Material::OFF); stateset->setAttributeAndModes(material, osg::StateAttribute::ON); From 380256977b2d737c33a725141dcb53b7337b21bb Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Nov 2015 01:53:38 +0100 Subject: [PATCH 2344/3725] Fix another renderBin issue with the weather particles Depth sorting w.r.t. the rest of the scene was broken --- apps/openmw/mwrender/sky.cpp | 32 +++++++++++++++----------------- apps/openmw/mwrender/sky.hpp | 1 + 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 3adc565ea..a1e5dbba8 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1066,18 +1066,19 @@ SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneMana mRootNode = skyroot; - // By default render before the world is rendered - mRootNode->getOrCreateStateSet()->setRenderBinDetails(RenderBin_Sky, "RenderBin"); - + mEarlyRenderBinRoot = new osg::Group; + // render before the world is rendered + mEarlyRenderBinRoot->getOrCreateStateSet()->setRenderBinDetails(RenderBin_Sky, "RenderBin"); // Prevent unwanted clipping by water reflection camera's clipping plane - mRootNode->getOrCreateStateSet()->setMode(GL_CLIP_PLANE0, osg::StateAttribute::OFF); + mEarlyRenderBinRoot->getOrCreateStateSet()->setMode(GL_CLIP_PLANE0, osg::StateAttribute::OFF); + mRootNode->addChild(mEarlyRenderBinRoot); } void SkyManager::create() { assert(!mCreated); - mAtmosphereDay = mSceneManager->createInstance("meshes/sky_atmosphere.nif", mRootNode); + mAtmosphereDay = mSceneManager->createInstance("meshes/sky_atmosphere.nif", mEarlyRenderBinRoot); ModVertexAlphaVisitor modAtmosphere(0); mAtmosphereDay->accept(modAtmosphere); @@ -1086,7 +1087,7 @@ void SkyManager::create() mAtmosphereNightNode = new osg::PositionAttitudeTransform; mAtmosphereNightNode->setNodeMask(0); - mRootNode->addChild(mAtmosphereNightNode); + mEarlyRenderBinRoot->addChild(mAtmosphereNightNode); osg::ref_ptr atmosphereNight; if (mSceneManager->getVFS()->exists("meshes/sky_night_02.nif")) @@ -1099,14 +1100,14 @@ void SkyManager::create() mAtmosphereNightUpdater = new AtmosphereNightUpdater(mSceneManager->getTextureManager()); atmosphereNight->addUpdateCallback(mAtmosphereNightUpdater); - mSun.reset(new Sun(mRootNode, *mSceneManager->getTextureManager())); + mSun.reset(new Sun(mEarlyRenderBinRoot, *mSceneManager->getTextureManager())); const MWWorld::Fallback* fallback=MWBase::Environment::get().getWorld()->getFallback(); - mMasser.reset(new Moon(mRootNode, *mSceneManager->getTextureManager(), fallback->getFallbackFloat("Moons_Masser_Size")/125, Moon::Type_Masser)); - mSecunda.reset(new Moon(mRootNode, *mSceneManager->getTextureManager(), fallback->getFallbackFloat("Moons_Secunda_Size")/125, Moon::Type_Secunda)); + mMasser.reset(new Moon(mEarlyRenderBinRoot, *mSceneManager->getTextureManager(), fallback->getFallbackFloat("Moons_Masser_Size")/125, Moon::Type_Masser)); + mSecunda.reset(new Moon(mEarlyRenderBinRoot, *mSceneManager->getTextureManager(), fallback->getFallbackFloat("Moons_Secunda_Size")/125, Moon::Type_Secunda)); mCloudNode = new osg::PositionAttitudeTransform; - mRootNode->addChild(mCloudNode); + mEarlyRenderBinRoot->addChild(mCloudNode); mCloudMesh = mSceneManager->createInstance("meshes/sky_clouds_01.nif", mCloudNode); ModVertexAlphaVisitor modClouds(1); mCloudMesh->accept(modClouds); @@ -1123,9 +1124,9 @@ void SkyManager::create() osg::ref_ptr depth = new osg::Depth; depth->setWriteMask(false); - mRootNode->getOrCreateStateSet()->setAttributeAndModes(depth, osg::StateAttribute::ON); - mRootNode->getOrCreateStateSet()->setMode(GL_BLEND, osg::StateAttribute::ON); - mRootNode->getOrCreateStateSet()->setMode(GL_FOG, osg::StateAttribute::OFF); + mEarlyRenderBinRoot->getOrCreateStateSet()->setAttributeAndModes(depth, osg::StateAttribute::ON); + mEarlyRenderBinRoot->getOrCreateStateSet()->setMode(GL_BLEND, osg::StateAttribute::ON); + mEarlyRenderBinRoot->getOrCreateStateSet()->setMode(GL_FOG, osg::StateAttribute::OFF); mMoonScriptColor = fallback->getFallbackColour("Moons_Script_Color"); @@ -1282,6 +1283,7 @@ void SkyManager::createRain() stateset->setNestRenderBins(false); stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); stateset->setMode(GL_CULL_FACE, osg::StateAttribute::OFF); + stateset->setMode(GL_BLEND, osg::StateAttribute::ON); osgParticle::Particle& particleTemplate = mRainParticleSystem->getDefaultParticleTemplate(); particleTemplate.setSizeRange(osgParticle::rangef(5.f, 15.f)); @@ -1457,10 +1459,6 @@ void SkyManager::setWeather(const WeatherResult& weather) if (!mParticleNode) { mParticleNode = new osg::PositionAttitudeTransform; - osg::StateSet* particleStateSet = mParticleNode->getOrCreateStateSet(); - particleStateSet->setRenderBinDetails(RenderBin_Default, "RenderBin"); - particleStateSet->setNestRenderBins(false); - particleStateSet->setMode(GL_FOG, osg::StateAttribute::ON); mRootNode->addChild(mParticleNode); } mParticleEffect = mSceneManager->createInstance(mCurrentParticleEffect, mParticleNode); diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index a4eeb861c..573c0ceb6 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -155,6 +155,7 @@ namespace MWRender Resource::SceneManager* mSceneManager; osg::ref_ptr mRootNode; + osg::ref_ptr mEarlyRenderBinRoot; osg::ref_ptr mParticleNode; osg::ref_ptr mParticleEffect; From 8e8f72408d45720891401dc5d021bec52d1fa795 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Nov 2015 02:12:00 +0100 Subject: [PATCH 2345/3725] Use diffuse/ambient lighting for the simple water --- apps/openmw/mwrender/water.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 84fe4fcc9..e72fc050c 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -79,6 +79,10 @@ namespace waterGeom->setVertexArray(verts); waterGeom->setTexCoordArray(0, texcoords); + osg::ref_ptr normal (new osg::Vec3Array); + normal->push_back(osg::Vec3f(0,0,1)); + waterGeom->setNormalArray(normal, osg::Array::BIND_OVERALL); + waterGeom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,verts->size())); return waterGeom; } @@ -526,9 +530,9 @@ void Water::createSimpleWaterStateSet(osg::Node* node) osg::ref_ptr stateset (new osg::StateSet); osg::ref_ptr material (new osg::Material); - material->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(1.f, 1.f, 1.f, 1.f)); - material->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 0.7f)); // Water_World_Alpha - material->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 1.f)); + material->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 1.f)); + material->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(1.f, 1.f, 1.f, 0.7f)); // Water_World_Alpha + material->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(1.f, 1.f, 1.f, 1.f)); material->setColorMode(osg::Material::OFF); stateset->setAttributeAndModes(material, osg::StateAttribute::ON); From 30c828dff0642f3e3a3f2181c7473a3931856959 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Nov 2015 02:17:42 +0100 Subject: [PATCH 2346/3725] Include cleanup --- apps/openmw/mwrender/renderingmanager.cpp | 1 + apps/openmw/mwrender/water.cpp | 2 ++ apps/openmw/mwrender/water.hpp | 7 +++++-- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index e1c0ea666..4dbfb3072 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -32,6 +32,7 @@ #include #include "../mwworld/fallback.hpp" +#include "../mwworld/cellstore.hpp" #include "sky.hpp" #include "effectmanager.hpp" diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index e72fc050c..cb03c489d 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -33,6 +33,8 @@ #include +#include "../mwworld/cellstore.hpp" + #include "vismask.hpp" #include "ripplesimulation.hpp" #include "renderbin.hpp" diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index f77afbfee..b5eca3f25 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -1,12 +1,13 @@ #ifndef OPENMW_MWRENDER_WATER_H #define OPENMW_MWRENDER_WATER_H +#include + #include +#include #include -#include "../mwworld/cellstore.hpp" - namespace osg { class Group; @@ -28,6 +29,8 @@ namespace Resource namespace MWWorld { class Fallback; + class CellStore; + class Ptr; } namespace MWRender From c0a81030bba44e92e54dcb255c8aed48dadcb763 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Nov 2015 02:24:50 +0100 Subject: [PATCH 2347/3725] Make use of INI settings for the simple water --- apps/openmw/mwrender/water.cpp | 20 +++++++++++++------- apps/openmw/mwrender/water.hpp | 3 ++- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index cb03c489d..101d9c822 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -34,6 +34,7 @@ #include #include "../mwworld/cellstore.hpp" +#include "../mwworld/fallback.hpp" #include "vismask.hpp" #include "ripplesimulation.hpp" @@ -457,6 +458,7 @@ Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem : mParent(parent) , mSceneRoot(sceneRoot) , mResourceSystem(resourceSystem) + , mFallback(fallback) , mResourcePath(resourcePath) , mEnabled(true) , mToggled(true) @@ -480,7 +482,7 @@ Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem // simple water fallback for the local map osg::ref_ptr geode2 (osg::clone(mWaterGeode.get(), osg::CopyOp::DEEP_COPY_NODES)); - createSimpleWaterStateSet(geode2); // Water_Map_Alpha + createSimpleWaterStateSet(geode2, mFallback->getFallbackFloat("Water_Map_Alpha")); geode2->setNodeMask(Mask_SimpleWater); mWaterNode->addChild(geode2); @@ -522,18 +524,18 @@ void Water::updateWaterMaterial() createShaderWaterStateSet(mWaterGeode, mReflection, mRefraction); } else - createSimpleWaterStateSet(mWaterGeode); + createSimpleWaterStateSet(mWaterGeode, mFallback->getFallbackFloat("Water_World_Alpha")); updateVisible(); } -void Water::createSimpleWaterStateSet(osg::Node* node) +void Water::createSimpleWaterStateSet(osg::Node* node, float alpha) { osg::ref_ptr stateset (new osg::StateSet); osg::ref_ptr material (new osg::Material); material->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 1.f)); - material->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(1.f, 1.f, 1.f, 0.7f)); // Water_World_Alpha + material->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(1.f, 1.f, 1.f, alpha)); material->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(1.f, 1.f, 1.f, 1.f)); material->setColorMode(osg::Material::OFF); stateset->setAttributeAndModes(material, osg::StateAttribute::ON); @@ -548,14 +550,18 @@ void Water::createSimpleWaterStateSet(osg::Node* node) stateset->setRenderBinDetails(MWRender::RenderBin_Water, "RenderBin"); std::vector > textures; - for (int i=0; i<32; ++i) + int frameCount = mFallback->getFallbackInt("Water_SurfaceFrameCount"); + std::string texture = mFallback->getFallbackString("Water_SurfaceTexture"); + for (int i=0; igetTextureManager()->getTexture2D(texname.str(), osg::Texture::REPEAT, osg::Texture::REPEAT)); } - osg::ref_ptr controller (new NifOsg::FlipController(0, 2/32.f, textures)); + float fps = mFallback->getFallbackFloat("Water_SurfaceFPS"); + + osg::ref_ptr controller (new NifOsg::FlipController(0, 1.f/fps, textures)); controller->setSource(boost::shared_ptr(new SceneUtil::FrameTimeSource)); node->setUpdateCallback(controller); node->setStateSet(stateset); diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index b5eca3f25..551184c11 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -50,6 +50,7 @@ namespace MWRender osg::ref_ptr mWaterNode; osg::ref_ptr mWaterGeode; Resource::ResourceSystem* mResourceSystem; + const MWWorld::Fallback* mFallback; osg::ref_ptr mIncrementalCompileOperation; std::auto_ptr mSimulation; @@ -66,7 +67,7 @@ namespace MWRender osg::Vec3f getSceneNodeCoordinates(int gridX, int gridY); void updateVisible(); - void createSimpleWaterStateSet(osg::Node* node); + void createSimpleWaterStateSet(osg::Node* node, float alpha); /// @param reflection the reflection camera (required) /// @param refraction the refraction camera (optional) From b72d5c5190a9e1ef8756d3c8734a0d011748cb75 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Nov 2015 17:48:35 +0100 Subject: [PATCH 2348/3725] Don't play idlestorm animation when swimming --- apps/openmw/mwmechanics/character.cpp | 7 +++---- apps/openmw/mwmechanics/character.hpp | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 36c251053..de4b44986 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -504,8 +504,6 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat mAnimation->play(mCurrentIdle, idlePriority, MWRender::Animation::BlendMask_All, false, 1.0f, "start", "stop", 0.0f, ~0ul, true); } - - updateIdleStormState(); } @@ -867,7 +865,7 @@ void CharacterController::updatePtr(const MWWorld::Ptr &ptr) mPtr = ptr; } -void CharacterController::updateIdleStormState() +void CharacterController::updateIdleStormState(bool inwater) { bool inStormDirection = false; if (MWBase::Environment::get().getWorld()->isInStorm()) @@ -877,7 +875,7 @@ void CharacterController::updateIdleStormState() inStormDirection = std::acos(stormDirection * characterDirection / (stormDirection.length() * characterDirection.length())) > osg::DegreesToRadians(120.f); } - if (inStormDirection && mUpperBodyState == UpperCharState_Nothing && mAnimation->hasAnimation("idlestorm")) + if (inStormDirection && !inwater && mUpperBodyState == UpperCharState_Nothing && mAnimation->hasAnimation("idlestorm")) { float complete = 0; mAnimation->getInfo("idlestorm", &complete); @@ -1796,6 +1794,7 @@ void CharacterController::update(float duration) forcestateupdate = updateCreatureState() || forcestateupdate; refreshCurrentAnims(idlestate, movestate, jumpstate, forcestateupdate); + updateIdleStormState(inwater); } if (inJump) diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index fee7b959c..90e285b52 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -196,7 +196,7 @@ class CharacterController : public MWRender::Animation::TextKeyListener bool updateWeaponState(); bool updateCreatureState(); - void updateIdleStormState(); + void updateIdleStormState(bool inwater); void updateHeadTracking(float duration); From de97a8a3dad74b49a72917bb32df80c3be49983b Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Nov 2015 17:53:57 +0100 Subject: [PATCH 2349/3725] Do not allow disabling the player object --- apps/openmw/mwworld/worldimp.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 17118e169..45aa31065 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -781,6 +781,9 @@ namespace MWWorld if (reference.getRefData().isEnabled()) { + if (reference == getPlayerPtr()) + throw std::runtime_error("can not disable player object"); + reference.getRefData().disable(); if(mWorldScene->getActiveCells().find (reference.getCell())!=mWorldScene->getActiveCells().end() && reference.getRefData().getCount()) From a5f8ffb83dbbae8cde9dde83e16f98c03ae6fc30 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Nov 2015 18:15:47 +0100 Subject: [PATCH 2350/3725] aimToTarget: Fix the collision box translation not being taken into account --- apps/openmw/mwphysics/actor.cpp | 5 +++++ apps/openmw/mwphysics/actor.hpp | 6 ++++++ apps/openmw/mwphysics/physicssystem.cpp | 25 +++++++++++++++++++++---- apps/openmw/mwphysics/physicssystem.hpp | 9 +++++++-- apps/openmw/mwworld/worldimp.cpp | 3 +-- 5 files changed, 40 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwphysics/actor.cpp b/apps/openmw/mwphysics/actor.cpp index a681c7945..98ccefe71 100644 --- a/apps/openmw/mwphysics/actor.cpp +++ b/apps/openmw/mwphysics/actor.cpp @@ -95,6 +95,11 @@ void Actor::updatePosition() mCollisionObject->setWorldTransform(tr); } +osg::Vec3f Actor::getPosition() const +{ + return toOsg(mCollisionObject->getWorldTransform().getOrigin()); +} + void Actor::updateRotation () { btTransform tr = mCollisionObject->getWorldTransform(); diff --git a/apps/openmw/mwphysics/actor.hpp b/apps/openmw/mwphysics/actor.hpp index a4afa48a1..bcbc256d0 100644 --- a/apps/openmw/mwphysics/actor.hpp +++ b/apps/openmw/mwphysics/actor.hpp @@ -70,6 +70,12 @@ namespace MWPhysics */ osg::Vec3f getHalfExtents() const; + /** + * Returns the position of the collision body + * @note The collision shape's origin is in its center, so the position returned can be described as center of the actor collision box in world space. + */ + osg::Vec3f getPosition() const; + /** * Returns the half extents of the collision body (scaled according to rendering scale) * @note The reason we need this extra method is because of an inconsistency in MW - NPC race scales aren't applied to the collision shape, diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 80a63bf1b..f4bf7a364 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -869,24 +869,33 @@ namespace MWPhysics } } - osg::Vec3f PhysicsSystem::getHalfExtents(const MWWorld::Ptr &actor) + osg::Vec3f PhysicsSystem::getHalfExtents(const MWWorld::Ptr &actor) const { - Actor* physactor = getActor(actor); + const Actor* physactor = getActor(actor); if (physactor) return physactor->getHalfExtents(); else return osg::Vec3f(); } - osg::Vec3f PhysicsSystem::getRenderingHalfExtents(const MWWorld::Ptr &actor) + osg::Vec3f PhysicsSystem::getRenderingHalfExtents(const MWWorld::Ptr &actor) const { - Actor* physactor = getActor(actor); + const Actor* physactor = getActor(actor); if (physactor) return physactor->getRenderingHalfExtents(); else return osg::Vec3f(); } + osg::Vec3f PhysicsSystem::getPosition(const MWWorld::Ptr &actor) const + { + const Actor* physactor = getActor(actor); + if (physactor) + return physactor->getPosition(); + else + return osg::Vec3f(); + } + class ContactTestResultCallback : public btCollisionWorld::ContactResultCallback { public: @@ -1036,6 +1045,14 @@ namespace MWPhysics return NULL; } + const Actor *PhysicsSystem::getActor(const MWWorld::Ptr &ptr) const + { + ActorMap::const_iterator found = mActors.find(ptr); + if (found != mActors.end()) + return found->second; + return NULL; + } + void PhysicsSystem::updateScale(const MWWorld::Ptr &ptr) { ObjectMap::iterator found = mObjects.find(ptr); diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index 6f38653c8..7c5be0b6e 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -62,6 +62,7 @@ namespace MWPhysics void updatePtr (const MWWorld::Ptr& old, const MWWorld::Ptr& updated); Actor* getActor(const MWWorld::Ptr& ptr); + const Actor* getActor(const MWWorld::Ptr& ptr) const; // Object or Actor void remove (const MWWorld::Ptr& ptr); @@ -108,10 +109,14 @@ namespace MWPhysics bool isOnGround (const MWWorld::Ptr& actor); /// Get physical half extents (scaled) of the given actor. - osg::Vec3f getHalfExtents(const MWWorld::Ptr& actor); + osg::Vec3f getHalfExtents(const MWWorld::Ptr& actor) const; /// @see MWPhysics::Actor::getRenderingHalfExtents - osg::Vec3f getRenderingHalfExtents(const MWWorld::Ptr& actor); + osg::Vec3f getRenderingHalfExtents(const MWWorld::Ptr& actor) const; + + /// Get the position of the collision shape for the actor. Use together with getHalfExtents() to get the collision bounds in world space. + /// @note The collision shape's origin is in its center, so the position returned can be described as center of the actor collision box in world space. + osg::Vec3f getPosition(const MWWorld::Ptr& actor) const; /// Queues velocity movement for a Ptr. If a Ptr is already queued, its velocity will /// be overwritten. Valid until the next call to applyQueuedMovement. diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 45aa31065..0f8c5aa32 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -3259,8 +3259,7 @@ namespace MWWorld osg::Vec3f World::aimToTarget(const Ptr &actor, const MWWorld::Ptr& target) { osg::Vec3f weaponPos = getActorHeadPosition(actor, mRendering); - osg::Vec3f targetPos = target.getRefData().getPosition().asVec3(); - targetPos.z() += mPhysics->getHalfExtents(target).z(); + osg::Vec3f targetPos = mPhysics->getPosition(target); return (targetPos - weaponPos); } } From 46e07e4b19e5db9a8860dfbf844ccfa71a407a52 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Nov 2015 18:27:15 +0100 Subject: [PATCH 2351/3725] Head tracking: fall back to target collision box center if the target has no head node --- apps/openmw/mwmechanics/character.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index de4b44986..f1c3da5ad 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -2121,7 +2121,7 @@ void CharacterController::updateHeadTracking(float duration) osg::Matrixf mat = mats[0]; osg::Vec3f headPos = mat.getTrans(); - osg::Vec3f targetPos (mHeadTrackTarget.getRefData().getPosition().asVec3()); + osg::Vec3f direction; if (MWRender::Animation* anim = MWBase::Environment::get().getWorld()->getAnimation(mHeadTrackTarget)) { const osg::Node* node = anim->getNode("Head"); @@ -2131,11 +2131,12 @@ void CharacterController::updateHeadTracking(float duration) { osg::MatrixList mats = node->getWorldMatrices(); if (mats.size()) - targetPos = mats[0].getTrans(); + direction = mats[0].getTrans() - headPos; } + else + // no head node to look at, fall back to look at center of collision box + direction = MWBase::Environment::get().getWorld()->aimToTarget(mPtr, mHeadTrackTarget); } - - osg::Vec3f direction = targetPos - headPos; direction.normalize(); if (!mPtr.getRefData().getBaseNode()) From 682f30ef9c7e8edad3e825be6920670ffac3bdce Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Nov 2015 19:05:36 +0100 Subject: [PATCH 2352/3725] Fix incorrect uses of PhysicsSystem::getHalfExtents Did not account for translation of collision box (mMeshTranslation in actor.cpp) --- apps/openmw/mwphysics/physicssystem.cpp | 19 ++++++++----------- apps/openmw/mwworld/projectilemanager.cpp | 7 +------ 2 files changed, 9 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index f4bf7a364..92994d557 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -240,6 +240,8 @@ namespace MWPhysics const ESM::Position& refpos = ptr.getRefData().getPosition(); osg::Vec3f position(refpos.asVec3()); + float collisionShapeOffset = physicActor->getPosition().z() - position.z(); + // Early-out for totally static creatures // (Not sure if gravity should still apply?) if (!ptr.getClass().isMobile(ptr)) @@ -256,12 +258,11 @@ namespace MWPhysics } btCollisionObject *colobj = physicActor->getCollisionObject(); - osg::Vec3f halfExtents = physicActor->getHalfExtents(); - position.z() += halfExtents.z(); + position.z() += collisionShapeOffset; static const float fSwimHeightScale = MWBase::Environment::get().getWorld()->getStore().get() .find("fSwimHeightScale")->getFloat(); - float swimlevel = waterlevel + halfExtents.z() - (physicActor->getRenderingHalfExtents().z() * 2 * fSwimHeightScale); + float swimlevel = waterlevel + collisionShapeOffset - (physicActor->getRenderingHalfExtents().z() * 2 * fSwimHeightScale); ActorTracer tracer; osg::Vec3f inertia = physicActor->getInertialForce(); @@ -369,7 +370,7 @@ namespace MWPhysics { // don't let pure water creatures move out of water after stepMove if (ptr.getClass().isPureWaterCreature(ptr) - && newPosition.z() + halfExtents.z() > waterlevel) + && newPosition.z() + physicActor->getHalfExtents().z() > waterlevel) newPosition = oldPosition; } else @@ -450,7 +451,7 @@ namespace MWPhysics } physicActor->setOnGround(isOnGround); - newPosition.z() -= halfExtents.z(); // remove what was added at the beginning + newPosition.z() -= collisionShapeOffset; // remove what was added at the beginning return newPosition; } }; @@ -820,12 +821,8 @@ namespace MWPhysics if (!physactor1 || !physactor2) return false; - osg::Vec3f halfExt1 = physactor1->getHalfExtents(); - osg::Vec3f pos1 (actor1.getRefData().getPosition().asVec3()); - pos1.z() += halfExt1.z()*2*0.9f; // eye level - osg::Vec3f halfExt2 = physactor2->getHalfExtents(); - osg::Vec3f pos2 (actor2.getRefData().getPosition().asVec3()); - pos2.z() += halfExt2.z()*2*0.9f; + osg::Vec3f pos1 (physactor1->getPosition() + osg::Vec3f(0,0,physactor1->getHalfExtents().z() * 0.8)); // eye level + osg::Vec3f pos2 (physactor2->getPosition() + osg::Vec3f(0,0,physactor2->getHalfExtents().z() * 0.8)); RayResult result = castRay(pos1, pos2, MWWorld::Ptr(), CollisionType_World|CollisionType_HeightMap); diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 3e9f17278..d5aca17a6 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -68,12 +68,7 @@ namespace MWWorld const ESM::EffectList &effects, const Ptr &caster, const std::string &sourceName, const osg::Vec3f& fallbackDirection) { - float height = 0; - - height += mPhysics->getHalfExtents(caster).z() * 2.f * 0.75f; // Spawn at 0.75 * ActorHeight - - osg::Vec3f pos(caster.getRefData().getPosition().asVec3()); - pos.z() += height; + osg::Vec3f pos = mPhysics->getPosition(caster) + osg::Vec3f(0,0,mPhysics->getHalfExtents(caster).z() * 0.5); // Spawn at 0.75 * ActorHeight if (MWBase::Environment::get().getWorld()->isUnderwater(caster.getCell(), pos)) // Underwater casting not possible return; From e3b30baff9733396fbad1fa7f3ff0e51782fd9b8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Nov 2015 23:10:52 +0100 Subject: [PATCH 2353/3725] clipFudge fix --- apps/openmw/mwrender/water.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 101d9c822..80023ecda 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -152,12 +152,9 @@ class ClipCullNode : public osg::Group osg::RefMatrix* modelViewMatrix = new osg::RefMatrix(*cv->getModelViewMatrix()); - // move the plane back along its normal a little bit to prevent bleeding at the water shore - const float clipFudge = -5; - // now apply the height of the plane + // apply the height of the plane // we can't apply this height in the addClipPlane() since the "flip the below graph" function would otherwise flip the height as well - float translate = clipFudge + ((*mCullPlane)[3] * -1); - modelViewMatrix->preMultTranslate(mCullPlane->getNormal() * translate); + modelViewMatrix->preMultTranslate(mCullPlane->getNormal() * ((*mCullPlane)[3] * -1)); // flip the below graph if the eye point is above the plane if (mCullPlane->intersect(osg::BoundingSphere(osg::Vec3d(0,0,eyePoint.z()), 0)) > 0) @@ -165,6 +162,10 @@ class ClipCullNode : public osg::Group modelViewMatrix->preMultScale(osg::Vec3(1,1,-1)); } + // move the plane back along its normal a little bit to prevent bleeding at the water shore + const float clipFudge = -5; + modelViewMatrix->preMultTranslate(mCullPlane->getNormal() * clipFudge); + cv->pushModelViewMatrix(modelViewMatrix, osg::Transform::RELATIVE_RF); traverse(node, nv); cv->popModelViewMatrix(); From 209fa52883aa824baac579074e4568e9993c66a3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Nov 2015 23:15:43 +0100 Subject: [PATCH 2354/3725] Hide weather particles underwater (Fixes #2701) --- apps/openmw/mwrender/renderingmanager.cpp | 2 + apps/openmw/mwrender/sky.cpp | 68 ++++++++++++++++++++++- apps/openmw/mwrender/sky.hpp | 10 ++++ 3 files changed, 79 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 4dbfb3072..5b2aac9e5 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -450,11 +450,13 @@ namespace MWRender void RenderingManager::setWaterEnabled(bool enabled) { mWater->setEnabled(enabled); + mSky->setWaterEnabled(enabled); } void RenderingManager::setWaterHeight(float height) { mWater->setHeight(height); + mSky->setWaterHeight(height); } class NotifyDrawCompletedCallback : public osg::Camera::DrawCallback diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index a1e5dbba8..4ff7256ca 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -262,8 +262,18 @@ public: META_Node(MWRender, CameraRelativeTransform) - virtual bool computeLocalToWorldMatrix(osg::Matrix& matrix, osg::NodeVisitor*) const + const osg::Vec3f& getLastEyePoint() const { + return mEyePoint; + } + + virtual bool computeLocalToWorldMatrix(osg::Matrix& matrix, osg::NodeVisitor* nv) const + { + if (nv->getVisitorType() == osg::NodeVisitor::CULL_VISITOR) + { + mEyePoint = static_cast(nv)->getEyePoint(); + } + if (_referenceFrame==RELATIVE_RF) { matrix.setTrans(osg::Vec3f(0.f,0.f,0.f)); @@ -322,6 +332,9 @@ public: cv->getCurrentCullingSet().popCurrentMask(); } }; +private: + // eyePoint for the current frame + mutable osg::Vec3f mEyePoint; }; class ModVertexAlphaVisitor : public osg::NodeVisitor @@ -371,6 +384,45 @@ private: int mMeshType; }; +/// @brief Hides the node subgraph if the eye point is below water. +/// @note Must be added as cull callback. +/// @note Meant to be used on a node that is child of a CameraRelativeTransform. +/// The current eye point must be retrieved by the CameraRelativeTransform since we can't get it anymore once we are in camera-relative space. +class UnderwaterSwitchCallback : public osg::NodeCallback +{ +public: + UnderwaterSwitchCallback(CameraRelativeTransform* cameraRelativeTransform) + : mCameraRelativeTransform(cameraRelativeTransform) + , mEnabled(true) + , mWaterLevel(0.f) + { + } + + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) + { + osg::Vec3f eyePoint = mCameraRelativeTransform->getLastEyePoint(); + + if (mEnabled && eyePoint.z() < mWaterLevel) + return; + + traverse(node, nv); + } + + void setEnabled(bool enabled) + { + mEnabled = enabled; + } + void setWaterLevel(float waterLevel) + { + mWaterLevel = waterLevel; + } + +private: + osg::ref_ptr mCameraRelativeTransform; + bool mEnabled; + float mWaterLevel; +}; + /// A base class for the sun and moons. class CelestialBody { @@ -1072,6 +1124,8 @@ SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneMana // Prevent unwanted clipping by water reflection camera's clipping plane mEarlyRenderBinRoot->getOrCreateStateSet()->setMode(GL_CLIP_PLANE0, osg::StateAttribute::OFF); mRootNode->addChild(mEarlyRenderBinRoot); + + mUnderwaterSwitch = new UnderwaterSwitchCallback(skyroot); } void SkyManager::create() @@ -1319,6 +1373,7 @@ void SkyManager::createRain() mRainFader = new RainFader; mRainNode->addUpdateCallback(mRainFader); + mRainNode->addCullCallback(mUnderwaterSwitch); mRootNode->addChild(mRainNode); } @@ -1459,6 +1514,7 @@ void SkyManager::setWeather(const WeatherResult& weather) if (!mParticleNode) { mParticleNode = new osg::PositionAttitudeTransform; + mParticleNode->addCullCallback(mUnderwaterSwitch); mRootNode->addChild(mParticleNode); } mParticleEffect = mSceneManager->createInstance(mCurrentParticleEffect, mParticleNode); @@ -1607,4 +1663,14 @@ void SkyManager::setGlareTimeOfDayFade(float val) mSun->setGlareTimeOfDayFade(val); } +void SkyManager::setWaterHeight(float height) +{ + mUnderwaterSwitch->setWaterLevel(height); +} + +void SkyManager::setWaterEnabled(bool enabled) +{ + mUnderwaterSwitch->setEnabled(enabled); +} + } diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index 573c0ceb6..0caadaa07 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -35,6 +35,7 @@ namespace MWRender class RainShooter; class RainFader; class AlphaFader; + class UnderwaterSwitchCallback; struct WeatherResult { @@ -100,6 +101,8 @@ namespace MWRender float mMoonAlpha; }; + ///@brief The SkyManager handles rendering of the sky domes, celestial bodies as well as other objects that need to be rendered + /// relative to the camera (e.g. weather particle effects) class SkyManager { public: @@ -144,6 +147,12 @@ namespace MWRender void setGlareTimeOfDayFade(float val); + /// Enable or disable the water plane (used to remove underwater weather particles) + void setWaterEnabled(bool enabled); + + /// Set height of water plane (used to remove underwater weather particles) + void setWaterHeight(float height); + private: void create(); ///< no need to call this, automatically done on first enable() @@ -160,6 +169,7 @@ namespace MWRender osg::ref_ptr mParticleNode; osg::ref_ptr mParticleEffect; std::vector > mParticleFaders; + osg::ref_ptr mUnderwaterSwitch; osg::ref_ptr mCloudNode; From 1cf1c944b79d3bbd64bbb909614816b08e663cfa Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Nov 2015 23:20:17 +0100 Subject: [PATCH 2355/3725] Don't attempt to render weather particles on the refraction and reflection textures --- apps/openmw/mwrender/sky.cpp | 2 ++ apps/openmw/mwrender/vismask.hpp | 23 ++++++++++++++--------- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 4ff7256ca..12708ba48 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1374,6 +1374,7 @@ void SkyManager::createRain() mRainFader = new RainFader; mRainNode->addUpdateCallback(mRainFader); mRainNode->addCullCallback(mUnderwaterSwitch); + mRainNode->setNodeMask(Mask_WeatherParticles); mRootNode->addChild(mRainNode); } @@ -1515,6 +1516,7 @@ void SkyManager::setWeather(const WeatherResult& weather) { mParticleNode = new osg::PositionAttitudeTransform; mParticleNode->addCullCallback(mUnderwaterSwitch); + mParticleNode->setNodeMask(Mask_WeatherParticles); mRootNode->addChild(mParticleNode); } mParticleEffect = mSceneManager->createInstance(mCurrentParticleEffect, mParticleNode); diff --git a/apps/openmw/mwrender/vismask.hpp b/apps/openmw/mwrender/vismask.hpp index b1329e958..a26bde1d1 100644 --- a/apps/openmw/mwrender/vismask.hpp +++ b/apps/openmw/mwrender/vismask.hpp @@ -15,21 +15,26 @@ namespace MWRender Mask_Actor = (1<<3), Mask_Player = (1<<4), Mask_Sky = (1<<5), - Mask_Sun = (1<<6), - Mask_Water = (1<<7), - Mask_SimpleWater = (1<<8), - Mask_Terrain = (1<<9), - Mask_FirstPerson = (1<<10), + Mask_Water = (1<<6), + Mask_Terrain = (1<<7), + Mask_FirstPerson = (1<<8), + + // child of Sky + Mask_Sun = (1<<9), + Mask_WeatherParticles = (1<<10), + + // child of Water + Mask_SimpleWater = (1<<11), // top level masks - Mask_Scene = (1<<11), - Mask_GUI = (1<<12), + Mask_Scene = (1<<12), + Mask_GUI = (1<<13), // Set on a Geode - Mask_ParticleSystem = (1<<13), + Mask_ParticleSystem = (1<<14), // Set on cameras within the main scene graph - Mask_RenderToTexture = (1<<14) + Mask_RenderToTexture = (1<<15) // reserved: (1<<16) for SceneUtil::Mask_Lit }; From c23609e22b1d931274b93c3ce031c682cf6176ff Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 4 Nov 2015 00:19:15 +0100 Subject: [PATCH 2356/3725] Cache the light list in LightListCallback When multiple cameras are rendering, the later cameras can reuse the light lists from the first camera. --- components/sceneutil/lightmanager.cpp | 37 +++++++++++++++------------ components/sceneutil/lightmanager.hpp | 4 +++ 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/components/sceneutil/lightmanager.cpp b/components/sceneutil/lightmanager.cpp index 18d7ddd46..1e1d04cf5 100644 --- a/components/sceneutil/lightmanager.cpp +++ b/components/sceneutil/lightmanager.cpp @@ -280,37 +280,40 @@ namespace SceneUtil // - cull list of lights by the camera frustum // - organize lights in a quad tree - // Don't use Camera::getViewMatrix, that one might be relative to another camera! - const osg::RefMatrix* viewMatrix = cv->getCurrentRenderStage()->getInitialViewMatrix(); - const std::vector& lights = mLightManager->getLightsInViewSpace(cv->getCurrentCamera(), viewMatrix); - - if (lights.size()) + // update light list if necessary + // makes sure we don't update it more than once per frame when rendering with multiple cameras + if (mLastFrameNumber != nv->getFrameStamp()->getFrameNumber()) { + mLastFrameNumber = nv->getFrameStamp()->getFrameNumber(); + + // Don't use Camera::getViewMatrix, that one might be relative to another camera! + const osg::RefMatrix* viewMatrix = cv->getCurrentRenderStage()->getInitialViewMatrix(); + const std::vector& lights = mLightManager->getLightsInViewSpace(cv->getCurrentCamera(), viewMatrix); + // we do the intersections in view space osg::BoundingSphere nodeBound = node->getBound(); osg::Matrixf mat = *cv->getModelViewMatrix(); transformBoundingSphere(mat, nodeBound); - LightManager::LightList lightList; + mLightList.clear(); for (unsigned int i=0; i (8 - mLightManager->getStartLight()); - if (lightList.size() > maxLights) + osg::StateSet* stateset = NULL; + + if (mLightList.size() > maxLights) { // remove lights culled by this camera + LightManager::LightList lightList = mLightList; for (LightManager::LightList::iterator it = lightList.begin(); it != lightList.end() && lightList.size() > maxLights; ) { osg::CullStack::CullingStack& stack = cv->getModelViewCullingStack(); @@ -334,9 +337,11 @@ namespace SceneUtil while (lightList.size() > maxLights) lightList.pop_back(); } + stateset = mLightManager->getLightListStateSet(lightList); } + else + stateset = mLightManager->getLightListStateSet(mLightList); - osg::StateSet* stateset = mLightManager->getLightListStateSet(lightList); cv->pushStateSet(stateset); diff --git a/components/sceneutil/lightmanager.hpp b/components/sceneutil/lightmanager.hpp index c2a1779ed..0783e595d 100644 --- a/components/sceneutil/lightmanager.hpp +++ b/components/sceneutil/lightmanager.hpp @@ -113,11 +113,13 @@ namespace SceneUtil int mStartLight; }; + /// @note Not thread safe for CullThreadPerCamera threading mode. class LightListCallback : public osg::NodeCallback { public: LightListCallback() : mLightManager(NULL) + , mLastFrameNumber(0) {} LightListCallback(const LightListCallback& copy, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY) : osg::Object(copy, copyop), osg::NodeCallback(copy, copyop), mLightManager(copy.mLightManager) @@ -129,6 +131,8 @@ namespace SceneUtil private: LightManager* mLightManager; + unsigned int mLastFrameNumber; + LightManager::LightList mLightList; }; /// @brief Configures a light's attenuation according to vanilla Morrowind attenuation settings. From 6bf393227922926be06e520e46f9c656b4d08b21 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 4 Nov 2015 20:25:03 +0100 Subject: [PATCH 2357/3725] Fix the check_tabs.sh script choking on QT generated UI files when doing an in-source build --- CI/check_tabs.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CI/check_tabs.sh b/CI/check_tabs.sh index 91f81e2a1..1e88b57fd 100755 --- a/CI/check_tabs.sh +++ b/CI/check_tabs.sh @@ -1,6 +1,6 @@ #!/bin/bash -OUTPUT=$(grep -nRP '\t' --include=\*.{cpp,hpp,c,h} apps components) +OUTPUT=$(grep -nRP '\t' --include=\*.{cpp,hpp,c,h} --exclude=ui_\* apps components) if [[ $OUTPUT ]] ; then echo "Error: Tab characters found!" From f7d0d06134c8b82c5142451d9ff256c1effcce74 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 4 Nov 2015 20:31:23 +0100 Subject: [PATCH 2358/3725] Compiler: remove unused mNameStartingWithDigit --- components/compiler/scanner.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/components/compiler/scanner.hpp b/components/compiler/scanner.hpp index 847895978..fe867feba 100644 --- a/components/compiler/scanner.hpp +++ b/components/compiler/scanner.hpp @@ -37,7 +37,6 @@ namespace Compiler float mPutbackFloat; std::string mPutbackName; TokenLoc mPutbackLoc; - bool mNameStartingWithDigit; public: From c996702b56e9525299f90969aecaf84f68badb8d Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 4 Nov 2015 20:34:50 +0100 Subject: [PATCH 2359/3725] Fix some uninitialised variables found by static analysis --- apps/openmw/mwmechanics/character.cpp | 1 + apps/openmw/mwrender/renderingmanager.cpp | 8 ++++---- components/sceneutil/lightmanager.hpp | 4 +++- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index f1c3da5ad..c9b248984 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -654,6 +654,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim , mAnimation(anim) , mIdleState(CharState_None) , mMovementState(CharState_None) + , mAdjustMovementAnimSpeed(false) , mHasMovedInXY(false) , mMovementAnimationControlled(true) , mDeathState(CharState_None) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 5b2aac9e5..7b11c9d85 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -131,6 +131,10 @@ namespace MWRender , mRootNode(rootNode) , mResourceSystem(resourceSystem) , mFogDepth(0.f) + , mUnderwaterColor(fallback->getFallbackColour("Water_UnderwaterColor")) + , mUnderwaterWeight(fallback->getFallbackFloat("Water_UnderwaterColorWeight")) + , mUnderwaterFog(0.f) + , mUnderwaterIndoorFog(fallback->getFallbackFloat("Water_UnderwaterIndoorFog")) , mNightEyeFactor(0.f) { osg::ref_ptr lightRoot = new SceneUtil::LightManager; @@ -202,10 +206,6 @@ namespace MWRender updateProjectionMatrix(); mStateUpdater->setFogEnd(mViewDistance); - mUnderwaterColor = fallback->getFallbackColour("Water_UnderwaterColor"); - mUnderwaterWeight = fallback->getFallbackFloat("Water_UnderwaterColorWeight"); - mUnderwaterIndoorFog = fallback->getFallbackFloat("Water_UnderwaterIndoorFog"); - mRootNode->getOrCreateStateSet()->addUniform(new osg::Uniform("near", mNearClip)); mRootNode->getOrCreateStateSet()->addUniform(new osg::Uniform("far", mViewDistance)); } diff --git a/components/sceneutil/lightmanager.hpp b/components/sceneutil/lightmanager.hpp index 0783e595d..b652562aa 100644 --- a/components/sceneutil/lightmanager.hpp +++ b/components/sceneutil/lightmanager.hpp @@ -122,7 +122,9 @@ namespace SceneUtil , mLastFrameNumber(0) {} LightListCallback(const LightListCallback& copy, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY) - : osg::Object(copy, copyop), osg::NodeCallback(copy, copyop), mLightManager(copy.mLightManager) + : osg::Object(copy, copyop), osg::NodeCallback(copy, copyop) + , mLightManager(copy.mLightManager) + , mLastFrameNumber(0) {} META_Object(NifOsg, LightListCallback) From 489addf772568d0d67c4387a21b5dc4788ce72d3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 4 Nov 2015 22:24:25 +0100 Subject: [PATCH 2360/3725] Don't attempt to run openmw_test_suite on coverity scan branch, since it is not being built --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 69879bd78..22f6164c2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -40,8 +40,8 @@ script: - cd ./build - if [ "$COVERITY_SCAN_BRANCH" != 1 ]; then ${ANALYZE}make -j2; fi - if [ "$COVERITY_SCAN_BRANCH" != 1 ] && [ "${TRAVIS_OS_NAME}" = "osx" ]; then make package; fi - - if [ "${TRAVIS_OS_NAME}" = "linux" ]; then ./openmw_test_suite; fi - - if [ "${TRAVIS_OS_NAME}" = "linux" ]; then cd .. && ./CI/check_tabs.sh; fi + - if [ "$COVERITY_SCAN_BRANCH" != 1 ] && ["${TRAVIS_OS_NAME}" = "linux" ]; then ./openmw_test_suite; fi + - if [ "$COVERITY_SCAN_BRANCH" != 1 ] && ["${TRAVIS_OS_NAME}" = "linux" ]; then cd .. && ./CI/check_tabs.sh; fi notifications: recipients: - corrmage+travis-ci@gmail.com From 8e4e4e5e38f53974fef9bc3373cd8b9d72c89c8f Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 5 Nov 2015 01:18:01 +0100 Subject: [PATCH 2361/3725] Fix infinite loop in addToLevList --- apps/openmw/mwscript/miscextensions.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 32d86f55a..5aebbc3a9 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -37,7 +37,7 @@ namespace void addToLevList(ESM::LevelledListBase* list, const std::string& itemId, int level) { - for (std::vector::iterator it = list->mList.begin(); it != list->mList.end();) + for (std::vector::iterator it = list->mList.begin(); it != list->mList.end(); ++it) { if (it->mLevel == level && itemId == it->mId) return; From 95cf13e3f2995e573c8c275256106dc1d4449d81 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 6 Nov 2015 15:23:37 +0100 Subject: [PATCH 2362/3725] Terrain: make the blendmapSize and layerTileSize in FixedFunctionTechnique configurable --- components/terrain/material.cpp | 14 ++++++++------ components/terrain/material.hpp | 6 ++++-- components/terrain/terraingrid.cpp | 4 +++- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/components/terrain/material.cpp b/components/terrain/material.cpp index df45b6ec2..d467a9e16 100644 --- a/components/terrain/material.cpp +++ b/components/terrain/material.cpp @@ -11,7 +11,7 @@ namespace Terrain { FixedFunctionTechnique::FixedFunctionTechnique(const std::vector >& layers, - const std::vector >& blendmaps) + const std::vector >& blendmaps, int blendmapSize, float layerTileSize) { bool firstLayer = true; int i=0; @@ -36,7 +36,7 @@ namespace Terrain // This is to map corner vertices directly to the center of a blendmap texel. osg::Matrixf texMat; - float scale = (16/(16.f+1.f)); + float scale = (blendmapSize/(static_cast(blendmapSize)+1.f)); texMat.preMultTranslate(osg::Vec3f(0.5f, 0.5f, 0.f)); texMat.preMultScale(osg::Vec3f(scale, scale, 1.f)); texMat.preMultTranslate(osg::Vec3f(-0.5f, -0.5f, 0.f)); @@ -57,8 +57,7 @@ namespace Terrain stateset->setTextureAttributeAndModes(texunit, tex.get()); osg::ref_ptr texMat (new osg::TexMat); - float scale = 16.f; - texMat->setMatrix(osg::Matrix::scale(osg::Vec3f(scale,scale,1.f))); + texMat->setMatrix(osg::Matrix::scale(osg::Vec3f(layerTileSize,layerTileSize,1.f))); stateset->setTextureAttributeAndModes(texunit, texMat, osg::StateAttribute::ON); firstLayer = false; @@ -67,9 +66,12 @@ namespace Terrain } } - Effect::Effect(const std::vector > &layers, const std::vector > &blendmaps) + Effect::Effect(const std::vector > &layers, const std::vector > &blendmaps, + int blendmapSize, float layerTileSize) : mLayers(layers) , mBlendmaps(blendmaps) + , mBlendmapSize(blendmapSize) + , mLayerTileSize(layerTileSize) { osg::ref_ptr material (new osg::Material); material->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE); @@ -80,7 +82,7 @@ namespace Terrain bool Effect::define_techniques() { - addTechnique(new FixedFunctionTechnique(mLayers, mBlendmaps)); + addTechnique(new FixedFunctionTechnique(mLayers, mBlendmaps, mBlendmapSize, mLayerTileSize)); return true; } diff --git a/components/terrain/material.hpp b/components/terrain/material.hpp index b423aa8b0..1be227b0d 100644 --- a/components/terrain/material.hpp +++ b/components/terrain/material.hpp @@ -19,7 +19,7 @@ namespace Terrain public: FixedFunctionTechnique( const std::vector >& layers, - const std::vector >& blendmaps); + const std::vector >& blendmaps, int blendmapSize, float layerTileSize); protected: virtual void define_passes() {} @@ -30,7 +30,7 @@ namespace Terrain public: Effect( const std::vector >& layers, - const std::vector >& blendmaps); + const std::vector >& blendmaps, int blendmapSize, float layerTileSize); virtual bool define_techniques(); @@ -50,6 +50,8 @@ namespace Terrain private: std::vector > mLayers; std::vector > mBlendmaps; + int mBlendmapSize; + float mLayerTileSize; }; } diff --git a/components/terrain/terraingrid.cpp b/components/terrain/terraingrid.cpp index 5afb99176..7c2395566 100644 --- a/components/terrain/terraingrid.cpp +++ b/components/terrain/terraingrid.cpp @@ -7,6 +7,8 @@ #include +#include + #include #include #include @@ -150,7 +152,7 @@ void TerrainGrid::loadCell(int x, int y) for (unsigned int i=0; i<2; ++i) geometry->setTexCoordArray(i, mCache.getUVBuffer()); - osg::ref_ptr effect (new Terrain::Effect(layerTextures, blendmapTextures)); + osg::ref_ptr effect (new Terrain::Effect(layerTextures, blendmapTextures, ESM::Land::LAND_TEXTURE_SIZE, ESM::Land::LAND_TEXTURE_SIZE)); effect->addCullCallback(new SceneUtil::LightListCallback); From ef18f4217f1aca7830f39f241d355b353a4602ea Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 6 Nov 2015 20:14:57 +0100 Subject: [PATCH 2363/3725] Terrain: create 4x4 terrain chunks per ESM::Cell to improve performance Improves performance because the number of splatting layers per chunk is reduced, and finer grained frustum culling can be done. --- components/esmterrain/storage.cpp | 80 ++++++++---- components/terrain/buffercache.cpp | 3 + components/terrain/material.cpp | 10 +- components/terrain/material.hpp | 6 +- components/terrain/terraingrid.cpp | 191 ++++++++++++++++++----------- components/terrain/terraingrid.hpp | 7 ++ 6 files changed, 193 insertions(+), 104 deletions(-) diff --git a/components/esmterrain/storage.cpp b/components/esmterrain/storage.cpp index ccfe6d9ee..e954bfec8 100644 --- a/components/esmterrain/storage.cpp +++ b/components/esmterrain/storage.cpp @@ -1,6 +1,7 @@ #include "storage.hpp" #include +#include #include #include @@ -34,19 +35,22 @@ namespace ESMTerrain osg::Vec2f origin = center - osg::Vec2f(size/2.f, size/2.f); - assert(origin.x() == (int) origin.x()); - assert(origin.y() == (int) origin.y()); + int cellX = static_cast(std::floor(origin.x())); + int cellY = static_cast(std::floor(origin.y())); - int cellX = static_cast(origin.x()); - int cellY = static_cast(origin.y()); + int startRow = (origin.x() - cellX) * ESM::Land::LAND_SIZE; + int startColumn = (origin.y() - cellY) * ESM::Land::LAND_SIZE; + + int endRow = startRow + size * (ESM::Land::LAND_SIZE-1) + 1; + int endColumn = startColumn + size * (ESM::Land::LAND_SIZE-1) + 1; if (const ESM::Land::LandData *data = getLandData (cellX, cellY, ESM::Land::DATA_VHGT)) { min = std::numeric_limits::max(); max = -std::numeric_limits::max(); - for (int row=0; rowmHeights[col*ESM::Land::LAND_SIZE+row]; if (h > max) @@ -143,11 +147,9 @@ namespace ESMTerrain size_t increment = 1 << lodLevel; osg::Vec2f origin = center - osg::Vec2f(size/2.f, size/2.f); - assert(origin.x() == (int) origin.x()); - assert(origin.y() == (int) origin.y()); - int startX = static_cast(origin.x()); - int startY = static_cast(origin.y()); + int startCellX = static_cast(std::floor(origin.x())); + int startCellY = static_cast(std::floor(origin.y())); size_t numVerts = static_cast(size*(ESM::Land::LAND_SIZE - 1) / increment + 1); @@ -162,10 +164,10 @@ namespace ESMTerrain float vertX = 0; float vertY_ = 0; // of current cell corner - for (int cellY = startY; cellY < startY + std::ceil(size); ++cellY) + for (int cellY = startCellY; cellY < startCellY + std::ceil(size); ++cellY) { float vertX_ = 0; // of current cell corner - for (int cellX = startX; cellX < startX + std::ceil(size); ++cellX) + for (int cellX = startCellX; cellX < startCellX + std::ceil(size); ++cellX) { const ESM::Land::LandData *heightData = getLandData (cellX, cellY, ESM::Land::DATA_VHGT); const ESM::Land::LandData *normalData = getLandData (cellX, cellY, ESM::Land::DATA_VNML); @@ -175,18 +177,31 @@ namespace ESMTerrain int colStart = 0; // Skip the first row / column unless we're at a chunk edge, // since this row / column is already contained in a previous cell + // This is only relevant if we're creating a chunk spanning multiple cells if (colStart == 0 && vertY_ != 0) colStart += increment; if (rowStart == 0 && vertX_ != 0) rowStart += increment; + // Only relevant for chunks smaller than (contained in) one cell + rowStart += (origin.x() - startCellX) * ESM::Land::LAND_SIZE; + colStart += (origin.y() - startCellY) * ESM::Land::LAND_SIZE; + int rowEnd = rowStart + std::min(1.f, size) * (ESM::Land::LAND_SIZE-1) + 1; + int colEnd = colStart + std::min(1.f, size) * (ESM::Land::LAND_SIZE-1) + 1; + vertY = vertY_; - for (int col=colStart; col= 0 && row < ESM::Land::LAND_SIZE); + assert(col >= 0 && col < ESM::Land::LAND_SIZE); + + assert (vertX < numVerts); + assert (vertY < numVerts); float height = -2048; if (heightData) @@ -200,7 +215,7 @@ namespace ESMTerrain if (normalData) { for (int i=0; i<3; ++i) - normal[i] = normalData->mNormals[arrayIndex+i]; + normal[i] = normalData->mNormals[srcArrayIndex+i]; normal.normalize(); } @@ -222,7 +237,7 @@ namespace ESMTerrain if (colourData) { for (int i=0; i<3; ++i) - color[i] = colourData->mColours[arrayIndex+i] / 255.f; + color[i] = colourData->mColours[srcArrayIndex+i] / 255.f; } else { @@ -305,8 +320,19 @@ namespace ESMTerrain // and interpolate the rest of the cell by hand? :/ osg::Vec2f origin = chunkCenter - osg::Vec2f(chunkSize/2.f, chunkSize/2.f); - int cellX = static_cast(origin.x()); - int cellY = static_cast(origin.y()); + int cellX = static_cast(std::floor(origin.x())); + int cellY = static_cast(std::floor(origin.y())); + + int realTextureSize = ESM::Land::LAND_TEXTURE_SIZE+1; // add 1 to wrap around next cell + + int rowStart = (origin.x() - cellX) * realTextureSize; + int colStart = (origin.y() - cellY) * realTextureSize; + int rowEnd = rowStart + chunkSize * (realTextureSize-1) + 1; + int colEnd = colStart + chunkSize * (realTextureSize-1) + 1; + + assert (rowStart >= 0 && colStart >= 0); + assert (rowEnd <= realTextureSize); + assert (colEnd <= realTextureSize); // Save the used texture indices so we know the total number of textures // and number of required blend maps @@ -317,8 +343,15 @@ namespace ESMTerrain // So we're always adding _land_default.dds as the base layer here, even if it's not referenced in this cell. textureIndices.insert(std::make_pair(0,0)); - for (int y=0; ysecond; int blendIndex = (pack ? static_cast(std::floor((layerIndex - 1) / 4.f)) : layerIndex - 1); int channel = pack ? std::max(0, (layerIndex-1) % 4) : 0; diff --git a/components/terrain/buffercache.cpp b/components/terrain/buffercache.cpp index a64f8ffd1..c6cf0fe33 100644 --- a/components/terrain/buffercache.cpp +++ b/components/terrain/buffercache.cpp @@ -1,6 +1,7 @@ #include "buffercache.hpp" #include +#include #include @@ -208,6 +209,8 @@ namespace Terrain { unsigned int verts = mNumVerts; + std::cout << "getting index buffer for " << verts << std::endl; + if (mIndexBufferMap.find(flags) != mIndexBufferMap.end()) { return mIndexBufferMap[flags]; diff --git a/components/terrain/material.cpp b/components/terrain/material.cpp index d467a9e16..59d06f254 100644 --- a/components/terrain/material.cpp +++ b/components/terrain/material.cpp @@ -11,7 +11,7 @@ namespace Terrain { FixedFunctionTechnique::FixedFunctionTechnique(const std::vector >& layers, - const std::vector >& blendmaps, int blendmapSize, float layerTileSize) + const std::vector >& blendmaps, int blendmapScale, float layerTileSize) { bool firstLayer = true; int i=0; @@ -36,7 +36,7 @@ namespace Terrain // This is to map corner vertices directly to the center of a blendmap texel. osg::Matrixf texMat; - float scale = (blendmapSize/(static_cast(blendmapSize)+1.f)); + float scale = (blendmapScale/(static_cast(blendmapScale)+1.f)); texMat.preMultTranslate(osg::Vec3f(0.5f, 0.5f, 0.f)); texMat.preMultScale(osg::Vec3f(scale, scale, 1.f)); texMat.preMultTranslate(osg::Vec3f(-0.5f, -0.5f, 0.f)); @@ -67,10 +67,10 @@ namespace Terrain } Effect::Effect(const std::vector > &layers, const std::vector > &blendmaps, - int blendmapSize, float layerTileSize) + int blendmapScale, float layerTileSize) : mLayers(layers) , mBlendmaps(blendmaps) - , mBlendmapSize(blendmapSize) + , mBlendmapScale(blendmapScale) , mLayerTileSize(layerTileSize) { osg::ref_ptr material (new osg::Material); @@ -82,7 +82,7 @@ namespace Terrain bool Effect::define_techniques() { - addTechnique(new FixedFunctionTechnique(mLayers, mBlendmaps, mBlendmapSize, mLayerTileSize)); + addTechnique(new FixedFunctionTechnique(mLayers, mBlendmaps, mBlendmapScale, mLayerTileSize)); return true; } diff --git a/components/terrain/material.hpp b/components/terrain/material.hpp index 1be227b0d..dd00e41ed 100644 --- a/components/terrain/material.hpp +++ b/components/terrain/material.hpp @@ -19,7 +19,7 @@ namespace Terrain public: FixedFunctionTechnique( const std::vector >& layers, - const std::vector >& blendmaps, int blendmapSize, float layerTileSize); + const std::vector >& blendmaps, int blendmapScale, float layerTileSize); protected: virtual void define_passes() {} @@ -30,7 +30,7 @@ namespace Terrain public: Effect( const std::vector >& layers, - const std::vector >& blendmaps, int blendmapSize, float layerTileSize); + const std::vector >& blendmaps, int blendmapScale, float layerTileSize); virtual bool define_techniques(); @@ -50,7 +50,7 @@ namespace Terrain private: std::vector > mLayers; std::vector > mBlendmaps; - int mBlendmapSize; + int mBlendmapScale; float mLayerTileSize; }; diff --git a/components/terrain/terraingrid.cpp b/components/terrain/terraingrid.cpp index 7c2395566..6414fa951 100644 --- a/components/terrain/terraingrid.cpp +++ b/components/terrain/terraingrid.cpp @@ -1,6 +1,8 @@ #include "terraingrid.hpp" #include +#include +#include #include #include @@ -47,8 +49,10 @@ namespace Terrain TerrainGrid::TerrainGrid(osg::Group* parent, Resource::ResourceSystem* resourceSystem, osgUtil::IncrementalCompileOperation* ico, Storage* storage, int nodeMask) : Terrain::World(parent, resourceSystem, ico, storage, nodeMask) + , mNumSplits(4) , mKdTreeBuilder(new osg::KdTreeBuilder) { + mCache = BufferCache((storage->getCellVertices()-1)/static_cast(mNumSplits) + 1); } TerrainGrid::~TerrainGrid() @@ -62,108 +66,149 @@ TerrainGrid::~TerrainGrid() class GridElement { public: - osg::ref_ptr mNode; + osg::ref_ptr mNode; }; -void TerrainGrid::loadCell(int x, int y) +osg::ref_ptr TerrainGrid::buildTerrain (osg::Group* parent, float chunkSize, const osg::Vec2f& chunkCenter) { - if (mGrid.find(std::make_pair(x, y)) != mGrid.end()) - return; // already loaded + if (chunkSize * mNumSplits > 1.f) + { + // keep splitting + osg::ref_ptr group (new osg::Group); + if (parent) + parent->addChild(group); + std::cout << "splitting " << chunkSize << " " << std::endl; + float newChunkSize = chunkSize/2.f; + buildTerrain(group, newChunkSize, chunkCenter + osg::Vec2f(newChunkSize/2.f, newChunkSize/2.f)); + buildTerrain(group, newChunkSize, chunkCenter + osg::Vec2f(newChunkSize/2.f, -newChunkSize/2.f)); + buildTerrain(group, newChunkSize, chunkCenter + osg::Vec2f(-newChunkSize/2.f, newChunkSize/2.f)); + buildTerrain(group, newChunkSize, chunkCenter + osg::Vec2f(-newChunkSize/2.f, -newChunkSize/2.f)); + return group; + } + else + { + float minH, maxH; + if (!mStorage->getMinMaxHeights(chunkSize, chunkCenter, minH, maxH)) + return NULL; // no terrain defined - osg::Vec2f center(x+0.5f, y+0.5f); - float minH, maxH; - if (!mStorage->getMinMaxHeights(1, center, minH, maxH)) - return; // no terrain defined + std::cout << "creating " << chunkSize << " " << chunkCenter << std::endl; - std::auto_ptr element (new GridElement); + osg::Vec2f worldCenter = chunkCenter*mStorage->getCellWorldSize(); + osg::ref_ptr transform (new osg::PositionAttitudeTransform); + transform->setPosition(osg::Vec3f(worldCenter.x(), worldCenter.y(), 0.f)); - osg::Vec2f worldCenter = center*mStorage->getCellWorldSize(); - element->mNode = new osg::PositionAttitudeTransform; - element->mNode->setPosition(osg::Vec3f(worldCenter.x(), worldCenter.y(), 0.f)); - mTerrainRoot->addChild(element->mNode); + if (parent) + parent->addChild(transform); - osg::ref_ptr positions (new osg::Vec3Array); - osg::ref_ptr normals (new osg::Vec3Array); - osg::ref_ptr colors (new osg::Vec4Array); + osg::ref_ptr positions (new osg::Vec3Array); + osg::ref_ptr normals (new osg::Vec3Array); + osg::ref_ptr colors (new osg::Vec4Array); - osg::ref_ptr vbo (new osg::VertexBufferObject); - positions->setVertexBufferObject(vbo); - normals->setVertexBufferObject(vbo); - colors->setVertexBufferObject(vbo); + osg::ref_ptr vbo (new osg::VertexBufferObject); + positions->setVertexBufferObject(vbo); + normals->setVertexBufferObject(vbo); + colors->setVertexBufferObject(vbo); - mStorage->fillVertexBuffers(0, 1, center, positions, normals, colors); + mStorage->fillVertexBuffers(0, chunkSize, chunkCenter, positions, normals, colors); - osg::ref_ptr geometry (new osg::Geometry); - geometry->setVertexArray(positions); - geometry->setNormalArray(normals, osg::Array::BIND_PER_VERTEX); - geometry->setColorArray(colors, osg::Array::BIND_PER_VERTEX); - geometry->setUseDisplayList(false); - geometry->setUseVertexBufferObjects(true); + osg::ref_ptr geometry (new osg::Geometry); + geometry->setVertexArray(positions); + geometry->setNormalArray(normals, osg::Array::BIND_PER_VERTEX); + geometry->setColorArray(colors, osg::Array::BIND_PER_VERTEX); + geometry->setUseDisplayList(false); + geometry->setUseVertexBufferObjects(true); - geometry->addPrimitiveSet(mCache.getIndexBuffer(0)); + geometry->addPrimitiveSet(mCache.getIndexBuffer(0)); - // we already know the bounding box, so no need to let OSG compute it. - osg::Vec3f min(-0.5f*mStorage->getCellWorldSize(), - -0.5f*mStorage->getCellWorldSize(), - minH); - osg::Vec3f max (0.5f*mStorage->getCellWorldSize(), - 0.5f*mStorage->getCellWorldSize(), - maxH); - osg::BoundingBox bounds(min, max); - geometry->setComputeBoundingBoxCallback(new StaticBoundingBoxCallback(bounds)); + // we already know the bounding box, so no need to let OSG compute it. + osg::Vec3f min(-0.5f*mStorage->getCellWorldSize()*chunkSize, + -0.5f*mStorage->getCellWorldSize()*chunkSize, + minH); + osg::Vec3f max (0.5f*mStorage->getCellWorldSize()*chunkSize, + 0.5f*mStorage->getCellWorldSize()*chunkSize, + maxH); + osg::BoundingBox bounds(min, max); + geometry->setComputeBoundingBoxCallback(new StaticBoundingBoxCallback(bounds)); - osg::ref_ptr geode (new osg::Geode); - geode->addDrawable(geometry); + osg::ref_ptr geode (new osg::Geode); + geode->addDrawable(geometry); - // build a kdtree to speed up intersection tests with the terrain - // Note, the build could be optimized using a custom kdtree builder, since we know that the terrain can be represented by a quadtree - geode->accept(*mKdTreeBuilder); - std::vector layerList; - std::vector > blendmaps; - mStorage->getBlendmaps(1.f, center, false, blendmaps, layerList); + std::vector layerList; + std::vector > blendmaps; + mStorage->getBlendmaps(chunkSize, chunkCenter, false, blendmaps, layerList); - // For compiling textures, I don't think the osgFX::Effect does it correctly - osg::ref_ptr textureCompileDummy (new osg::Node); + // For compiling textures, I don't think the osgFX::Effect does it correctly + osg::ref_ptr textureCompileDummy (new osg::Node); - std::vector > layerTextures; - for (std::vector::const_iterator it = layerList.begin(); it != layerList.end(); ++it) - { - layerTextures.push_back(mResourceSystem->getTextureManager()->getTexture2D(it->mDiffuseMap, osg::Texture::REPEAT, osg::Texture::REPEAT)); - textureCompileDummy->getOrCreateStateSet()->setTextureAttributeAndModes(0, layerTextures.back()); - } + std::vector > layerTextures; + for (std::vector::const_iterator it = layerList.begin(); it != layerList.end(); ++it) + { + layerTextures.push_back(mResourceSystem->getTextureManager()->getTexture2D(it->mDiffuseMap, osg::Texture::REPEAT, osg::Texture::REPEAT)); + textureCompileDummy->getOrCreateStateSet()->setTextureAttributeAndModes(0, layerTextures.back()); + } - std::vector > blendmapTextures; - for (std::vector >::const_iterator it = blendmaps.begin(); it != blendmaps.end(); ++it) - { - osg::ref_ptr texture (new osg::Texture2D); - texture->setImage(*it); - texture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); - texture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); - texture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR); - texture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); - texture->setResizeNonPowerOfTwoHint(false); - blendmapTextures.push_back(texture); - - textureCompileDummy->getOrCreateStateSet()->setTextureAttributeAndModes(0, layerTextures.back()); + std::vector > blendmapTextures; + for (std::vector >::const_iterator it = blendmaps.begin(); it != blendmaps.end(); ++it) + { + osg::ref_ptr texture (new osg::Texture2D); + texture->setImage(*it); + texture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); + texture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); + texture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR); + texture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); + texture->setResizeNonPowerOfTwoHint(false); + blendmapTextures.push_back(texture); + + textureCompileDummy->getOrCreateStateSet()->setTextureAttributeAndModes(0, layerTextures.back()); + } + + // use texture coordinates for both texture units, the layer texture and blend texture + for (unsigned int i=0; i<2; ++i) + geometry->setTexCoordArray(i, mCache.getUVBuffer()); + + float blendmapScale = ESM::Land::LAND_TEXTURE_SIZE*chunkSize; + osg::ref_ptr effect (new Terrain::Effect(layerTextures, blendmapTextures, blendmapScale, blendmapScale)); + + effect->addCullCallback(new SceneUtil::LightListCallback); + + transform->addChild(effect); + effect->addChild(geode); + + return transform; } +} + +void TerrainGrid::loadCell(int x, int y) +{ + if (mGrid.find(std::make_pair(x, y)) != mGrid.end()) + return; // already loaded - // use texture coordinates for both texture units, the layer texture and blend texture - for (unsigned int i=0; i<2; ++i) - geometry->setTexCoordArray(i, mCache.getUVBuffer()); + osg::Vec2f center(x+0.5f, y+0.5f); - osg::ref_ptr effect (new Terrain::Effect(layerTextures, blendmapTextures, ESM::Land::LAND_TEXTURE_SIZE, ESM::Land::LAND_TEXTURE_SIZE)); + osg::ref_ptr terrainNode = buildTerrain(NULL, 1.f, center); + if (!terrainNode) + return; // no terrain defined + + std::auto_ptr element (new GridElement); + element->mNode = terrainNode; + mTerrainRoot->addChild(element->mNode); - effect->addCullCallback(new SceneUtil::LightListCallback); + /* + // build a kdtree to speed up intersection tests with the terrain + // Note, the build could be optimized using a custom kdtree builder, since we know that the terrain can be represented by a quadtree + geode->accept(*mKdTreeBuilder); + */ - effect->addChild(geode); - element->mNode->addChild(effect); + /* if (mIncrementalCompileOperation) { mIncrementalCompileOperation->add(geode); mIncrementalCompileOperation->add(textureCompileDummy); } + */ + mGrid[std::make_pair(x,y)] = element.release(); } diff --git a/components/terrain/terraingrid.hpp b/components/terrain/terraingrid.hpp index 832b952e8..169a9a622 100644 --- a/components/terrain/terraingrid.hpp +++ b/components/terrain/terraingrid.hpp @@ -1,6 +1,8 @@ #ifndef COMPONENTS_TERRAIN_TERRAINGRID_H #define COMPONENTS_TERRAIN_TERRAINGRID_H +#include + #include "world.hpp" #include "material.hpp" @@ -26,6 +28,11 @@ namespace Terrain virtual void unloadCell(int x, int y); private: + osg::ref_ptr buildTerrain (osg::Group* parent, float chunkSize, const osg::Vec2f& chunkCenter); + + // split each ESM::Cell into mNumSplits*mNumSplits terrain chunks + unsigned int mNumSplits; + typedef std::map, GridElement*> Grid; Grid mGrid; From 7ca8e45d5ddbb2cfbf28716aa297e928cde08889 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 6 Nov 2015 20:21:39 +0100 Subject: [PATCH 2364/3725] Terrain: remove debug code --- components/esmterrain/storage.cpp | 8 -------- components/terrain/buffercache.cpp | 3 --- components/terrain/terraingrid.cpp | 7 ++----- 3 files changed, 2 insertions(+), 16 deletions(-) diff --git a/components/esmterrain/storage.cpp b/components/esmterrain/storage.cpp index e954bfec8..c36e3efe0 100644 --- a/components/esmterrain/storage.cpp +++ b/components/esmterrain/storage.cpp @@ -1,7 +1,6 @@ #include "storage.hpp" #include -#include #include #include @@ -343,13 +342,6 @@ namespace ESMTerrain // So we're always adding _land_default.dds as the base layer here, even if it's not referenced in this cell. textureIndices.insert(std::make_pair(0,0)); - /* - _________ - | | | | - | | | | - - | | | | - | | | | - - - */ - for (int y=colStart; y -#include #include @@ -209,8 +208,6 @@ namespace Terrain { unsigned int verts = mNumVerts; - std::cout << "getting index buffer for " << verts << std::endl; - if (mIndexBufferMap.find(flags) != mIndexBufferMap.end()) { return mIndexBufferMap[flags]; diff --git a/components/terrain/terraingrid.cpp b/components/terrain/terraingrid.cpp index 6414fa951..99525d0f4 100644 --- a/components/terrain/terraingrid.cpp +++ b/components/terrain/terraingrid.cpp @@ -1,8 +1,6 @@ #include "terraingrid.hpp" #include -#include -#include #include #include @@ -77,7 +75,7 @@ osg::ref_ptr TerrainGrid::buildTerrain (osg::Group* parent, float chu osg::ref_ptr group (new osg::Group); if (parent) parent->addChild(group); - std::cout << "splitting " << chunkSize << " " << std::endl; + float newChunkSize = chunkSize/2.f; buildTerrain(group, newChunkSize, chunkCenter + osg::Vec2f(newChunkSize/2.f, newChunkSize/2.f)); buildTerrain(group, newChunkSize, chunkCenter + osg::Vec2f(newChunkSize/2.f, -newChunkSize/2.f)); @@ -91,8 +89,6 @@ osg::ref_ptr TerrainGrid::buildTerrain (osg::Group* parent, float chu if (!mStorage->getMinMaxHeights(chunkSize, chunkCenter, minH, maxH)) return NULL; // no terrain defined - std::cout << "creating " << chunkSize << " " << chunkCenter << std::endl; - osg::Vec2f worldCenter = chunkCenter*mStorage->getCellWorldSize(); osg::ref_ptr transform (new osg::PositionAttitudeTransform); transform->setPosition(osg::Vec3f(worldCenter.x(), worldCenter.y(), 0.f)); @@ -194,6 +190,7 @@ void TerrainGrid::loadCell(int x, int y) element->mNode = terrainNode; mTerrainRoot->addChild(element->mNode); + // kdtree probably not needed with mNumSplits=4 /* // build a kdtree to speed up intersection tests with the terrain // Note, the build could be optimized using a custom kdtree builder, since we know that the terrain can be represented by a quadtree From 72252d4f32e200f21c076688322854b477ca9bb8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 6 Nov 2015 20:22:07 +0100 Subject: [PATCH 2365/3725] Terrain: restore IncrementalCompileOperation --- components/terrain/terraingrid.cpp | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/components/terrain/terraingrid.cpp b/components/terrain/terraingrid.cpp index 99525d0f4..732936aa9 100644 --- a/components/terrain/terraingrid.cpp +++ b/components/terrain/terraingrid.cpp @@ -171,6 +171,12 @@ osg::ref_ptr TerrainGrid::buildTerrain (osg::Group* parent, float chu transform->addChild(effect); effect->addChild(geode); + if (mIncrementalCompileOperation) + { + mIncrementalCompileOperation->add(geode); + mIncrementalCompileOperation->add(textureCompileDummy); + } + return transform; } } @@ -197,16 +203,6 @@ void TerrainGrid::loadCell(int x, int y) geode->accept(*mKdTreeBuilder); */ - - /* - if (mIncrementalCompileOperation) - { - mIncrementalCompileOperation->add(geode); - mIncrementalCompileOperation->add(textureCompileDummy); - } - */ - - mGrid[std::make_pair(x,y)] = element.release(); } From 0210b87ffc0fc33bddaf2449ad1d1c042cc51553 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 6 Nov 2015 22:35:12 +0100 Subject: [PATCH 2366/3725] Revert "Fix LightSource crash" This reverts commit f336c6db87be04903c0a92ab0c749bfe290bb5f0. Root cause should be fixed in next commit. --- components/sceneutil/lightmanager.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/sceneutil/lightmanager.hpp b/components/sceneutil/lightmanager.hpp index b652562aa..e62dc00e5 100644 --- a/components/sceneutil/lightmanager.hpp +++ b/components/sceneutil/lightmanager.hpp @@ -76,7 +76,7 @@ namespace SceneUtil struct LightSourceTransform { - osg::ref_ptr mLightSource; + LightSource* mLightSource; osg::Matrix mWorldMatrix; }; @@ -84,7 +84,7 @@ namespace SceneUtil struct LightSourceViewBound { - osg::ref_ptr mLightSource; + LightSource* mLightSource; osg::BoundingSphere mViewBound; }; From 6e698081294377acab61a29be0056d8ac491e2c3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 6 Nov 2015 22:41:32 +0100 Subject: [PATCH 2367/3725] Fix the frameNumber not being incremented in certain frames --- apps/openmw/mwgui/loadingscreen.cpp | 8 +++++++- apps/openmw/mwgui/windowmanagerimp.cpp | 16 ++++++++++++++-- apps/openmw/mwrender/renderingmanager.cpp | 10 +++++++++- 3 files changed, 30 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index 9afce6873..321d5e664 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -282,7 +282,13 @@ namespace MWGui MWBase::Environment::get().getInputManager()->update(0, true, true); //osg::Timer timer; - mViewer->frame(mViewer->getFrameStamp()->getSimulationTime()); + // at the time this function is called we are in the middle of a frame, + // so out of order calls are necessary to get a correct frameNumber for the next frame. + // refer to the advance() and frame() order in Engine::go() + mViewer->eventTraversal(); + mViewer->updateTraversal(); + mViewer->renderingTraversals(); + mViewer->advance(mViewer->getFrameStamp()->getSimulationTime()); //std::cout << "frame took " << timer.time_m() << std::endl; //if (mViewer->getIncrementalCompileOperation()) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 90a5f7481..e1e838cdf 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -859,7 +859,13 @@ namespace MWGui mMessageBoxManager->onFrame(0.f); MWBase::Environment::get().getInputManager()->update(0, true, false); - mViewer->frame(mViewer->getFrameStamp()->getSimulationTime()); + // at the time this function is called we are in the middle of a frame, + // so out of order calls are necessary to get a correct frameNumber for the next frame. + // refer to the advance() and frame() order in Engine::go() + mViewer->eventTraversal(); + mViewer->updateTraversal(); + mViewer->renderingTraversals(); + mViewer->advance(mViewer->getFrameStamp()->getSimulationTime()); } } } @@ -1756,7 +1762,13 @@ namespace MWGui { MWBase::Environment::get().getInputManager()->update(0, true, false); - mViewer->frame(mViewer->getFrameStamp()->getSimulationTime()); + // at the time this function is called we are in the middle of a frame, + // so out of order calls are necessary to get a correct frameNumber for the next frame. + // refer to the advance() and frame() order in Engine::go() + mViewer->eventTraversal(); + mViewer->updateTraversal(); + mViewer->renderingTraversals(); + mViewer->advance(mViewer->getFrameStamp()->getSimulationTime()); } mVideoWidget->stop(); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 7b11c9d85..7848cdd3c 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -521,10 +521,18 @@ namespace MWRender osg::ref_ptr callback (new NotifyDrawCompletedCallback); rttCamera->setFinalDrawCallback(callback); - mViewer->frame(mViewer->getFrameStamp()->getSimulationTime()); + // at the time this function is called we are in the middle of a frame, + // so out of order calls are necessary to get a correct frameNumber for the next frame. + // refer to the advance() and frame() order in Engine::go() + mViewer->eventTraversal(); + mViewer->updateTraversal(); + mViewer->renderingTraversals(); callback->waitTillDone(); + // now that we've "used up" the current frame, get a fresh framenumber for the next frame() following after the screenshot is completed + mViewer->advance(mViewer->getFrameStamp()->getSimulationTime()); + rttCamera->removeChildren(0, rttCamera->getNumChildren()); rttCamera->setGraphicsContext(NULL); mRootNode->removeChild(rttCamera); From 2407f393cee9a3a7634337777c8ce902a9186923 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 6 Nov 2015 23:13:57 +0100 Subject: [PATCH 2368/3725] Fix double update traversal in screenshot function --- apps/openmw/mwrender/renderingmanager.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 7848cdd3c..45c04ceec 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -489,6 +489,15 @@ namespace MWRender mutable bool mDone; }; + + class NoTraverseCallback : public osg::NodeCallback + { + public: + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) + { + } + }; + void RenderingManager::screenshot(osg::Image *image, int w, int h) { osg::ref_ptr rttCamera (new osg::Camera); @@ -512,6 +521,7 @@ namespace MWRender image->setDataType(GL_UNSIGNED_BYTE); image->setPixelFormat(texture->getInternalFormat()); + rttCamera->setUpdateCallback(new NoTraverseCallback); rttCamera->addChild(mLightRoot); rttCamera->setCullMask(mViewer->getCamera()->getCullMask() & (~Mask_GUI)); From 4cc200680c071541f484d36897eab61171d57182 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 6 Nov 2015 23:59:06 +0100 Subject: [PATCH 2369/3725] Comment out shadows tab in settings menu --- files/mygui/openmw_settings_window.layout | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/files/mygui/openmw_settings_window.layout b/files/mygui/openmw_settings_window.layout index e76c3a7db..5f2a6e5a0 100644 --- a/files/mygui/openmw_settings_window.layout +++ b/files/mygui/openmw_settings_window.layout @@ -392,7 +392,11 @@ + + + From a41ebd6695096f71b2c5a54983e222d2aec8eb16 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 7 Nov 2015 00:02:15 +0100 Subject: [PATCH 2370/3725] Comment out object shaders in the settings menu --- files/mygui/openmw_settings_window.layout | 2 ++ 1 file changed, 2 insertions(+) diff --git a/files/mygui/openmw_settings_window.layout b/files/mygui/openmw_settings_window.layout index 5f2a6e5a0..cb7463656 100644 --- a/files/mygui/openmw_settings_window.layout +++ b/files/mygui/openmw_settings_window.layout @@ -262,6 +262,8 @@ + + From 47664e13707c5ed2a4f0b3282dc4cb67dfc7392a Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 7 Nov 2015 00:10:49 +0100 Subject: [PATCH 2371/3725] Hide the defunct FPS checkbox in settings menu, added hint text for f3 binding --- files/mygui/openmw_settings_window.layout | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/files/mygui/openmw_settings_window.layout b/files/mygui/openmw_settings_window.layout index cb7463656..1d02ea19a 100644 --- a/files/mygui/openmw_settings_window.layout +++ b/files/mygui/openmw_settings_window.layout @@ -256,6 +256,8 @@ + + @@ -273,6 +275,12 @@ + + + + + + From 13c7235b6b49b8ec76a1034e2876992adbccdffc Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 7 Nov 2015 00:13:13 +0100 Subject: [PATCH 2372/3725] Remove old FPS setting code --- apps/mwiniimporter/importer.cpp | 1 - apps/openmw/engine.cpp | 3 --- apps/openmw/mwbase/windowmanager.hpp | 2 -- apps/openmw/mwgui/hud.cpp | 28 +---------------------- apps/openmw/mwgui/hud.hpp | 8 +------ apps/openmw/mwgui/settingswindow.cpp | 12 ---------- apps/openmw/mwgui/settingswindow.hpp | 2 -- apps/openmw/mwgui/windowmanagerimp.cpp | 11 +-------- apps/openmw/mwgui/windowmanagerimp.hpp | 4 ---- files/mygui/openmw_hud.layout | 6 ----- files/mygui/openmw_settings_window.layout | 8 ------- files/mygui/openmw_text.skin.xml | 9 -------- files/settings-default.cfg | 5 ---- 13 files changed, 3 insertions(+), 96 deletions(-) diff --git a/apps/mwiniimporter/importer.cpp b/apps/mwiniimporter/importer.cpp index 479f8cba2..251889e28 100644 --- a/apps/mwiniimporter/importer.cpp +++ b/apps/mwiniimporter/importer.cpp @@ -20,7 +20,6 @@ MwIniImporter::MwIniImporter() { const char *map[][2] = { - { "fps", "General:Show FPS" }, { "no-sound", "General:Disable Audio" }, { 0, 0 } }; diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 089880fb2..5d2d588ed 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -168,9 +168,6 @@ void OMW::Engine::frame(float frametime) if (mEnvironment.getStateManager()->getState()!= MWBase::StateManager::State_NoGame) { -#if 0 - mEnvironment.getWindowManager()->wmUpdateFps(fps); -#endif mEnvironment.getWindowManager()->update(); } diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index fb7eca4a3..f364ada7a 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -155,8 +155,6 @@ namespace MWBase virtual void setConsoleSelectedObject(const MWWorld::Ptr& object) = 0; - virtual void wmUpdateFps(float fps) = 0; - /// Set value for the given ID. virtual void setValue (const std::string& id, const MWMechanics::AttributeValue& value) = 0; virtual void setValue (int parSkill, const MWMechanics::SkillValue& value) = 0; diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index a93bb47e9..3922b1997 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -67,7 +67,7 @@ namespace MWGui }; - HUD::HUD(CustomMarkerCollection &customMarkers, bool showFps, DragAndDrop* dragAndDrop, MWRender::LocalMap* localMapRender) + HUD::HUD(CustomMarkerCollection &customMarkers, DragAndDrop* dragAndDrop, MWRender::LocalMap* localMapRender) : Layout("openmw_hud.layout") , LocalMapBase(customMarkers, localMapRender) , mHealth(NULL) @@ -85,8 +85,6 @@ namespace MWGui , mCellNameBox(NULL) , mDrowningFrame(NULL) , mDrowningFlash(NULL) - , mFpsBox(NULL) - , mFpsCounter(NULL) , mHealthManaStaminaBaseLeft(0) , mWeapBoxBaseLeft(0) , mSpellBoxBaseLeft(0) @@ -161,8 +159,6 @@ namespace MWGui getWidget(mCrosshair, "Crosshair"); - setFpsVisible(showFps); - LocalMapBase::init(mMinimap, mCompass, Settings::Manager::getInt("local map hud widget size", "Map")); mMainWidget->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onWorldClicked); @@ -181,28 +177,6 @@ namespace MWGui delete mSpellIcons; } - void HUD::setFpsVisible(const bool visible) - { - mFpsCounter = 0; - - MyGUI::Widget* fps; - getWidget(fps, "FPSBox"); - fps->setVisible(false); - - if (visible) - { - getWidget(mFpsBox, "FPSBox"); - //mFpsBox->setVisible(true); - getWidget(mFpsCounter, "FPSCounter"); - } - } - - void HUD::setFPS(float fps) - { - if (mFpsCounter) - mFpsCounter->setCaption(MyGUI::utility::toString((int)fps)); - } - void HUD::setValue(const std::string& id, const MWMechanics::DynamicStat& value) { int current = std::max(0, static_cast(value.getCurrent())); diff --git a/apps/openmw/mwgui/hud.hpp b/apps/openmw/mwgui/hud.hpp index 629613c98..c5ae45789 100644 --- a/apps/openmw/mwgui/hud.hpp +++ b/apps/openmw/mwgui/hud.hpp @@ -19,10 +19,9 @@ namespace MWGui class HUD : public Layout, public LocalMapBase { public: - HUD(CustomMarkerCollection& customMarkers, bool fpsVisible, DragAndDrop* dragAndDrop, MWRender::LocalMap* localMapRender); + HUD(CustomMarkerCollection& customMarkers, DragAndDrop* dragAndDrop, MWRender::LocalMap* localMapRender); virtual ~HUD(); void setValue (const std::string& id, const MWMechanics::DynamicStat& value); - void setFPS(float fps); /// Set time left for the player to start drowning /// @param time time left to start drowning @@ -38,8 +37,6 @@ namespace MWGui void setEffectVisible(bool visible); void setMinimapVisible(bool visible); - void setFpsVisible(const bool visible); - void setSelectedSpell(const std::string& spellId, int successChancePercent); void setSelectedEnchantItem(const MWWorld::Ptr& item, int chargePercent); void setSelectedWeapon(const MWWorld::Ptr& item, int durabilityPercent); @@ -77,9 +74,6 @@ namespace MWGui MyGUI::TextBox* mWeaponSpellBox; MyGUI::Widget *mDrowningFrame, *mDrowningFlash; - MyGUI::Widget* mFpsBox; - MyGUI::TextBox* mFpsCounter; - // bottom left elements int mHealthManaStaminaBaseLeft, mWeapBoxBaseLeft, mSpellBoxBaseLeft, mSneakBoxBaseLeft; // bottom right elements diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 667dc0c28..eb2f23529 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -166,7 +166,6 @@ namespace MWGui getWidget(mFullscreenButton, "FullscreenButton"); getWidget(mVSyncButton, "VSyncButton"); getWidget(mWindowBorderButton, "WindowBorderButton"); - getWidget(mFPSButton, "FPSButton"); getWidget(mFOVSlider, "FOVSlider"); getWidget(mAnisotropySlider, "AnisotropySlider"); getWidget(mTextureFilteringButton, "TextureFilteringButton"); @@ -201,7 +200,6 @@ namespace MWGui mSettingsTab->eventTabChangeSelect += MyGUI::newDelegate(this, &SettingsWindow::onTabChanged); mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onOkButtonClicked); mTextureFilteringButton->eventComboChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onTextureFilteringChanged); - mFPSButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onFpsToggled); mResolutionList->eventListChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onResolutionSelected); mWaterTextureSize->eventComboChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onWaterTextureSizeChanged); @@ -256,8 +254,6 @@ namespace MWGui mShadowsEnabledButton->setEnabled(false); } - mFPSButton->setCaptionWithReplacing(fpsLevelToStr(Settings::Manager::getInt("fps", "HUD"))); - MyGUI::TextBox* fovText; getWidget(fovText, "FovText"); fovText->setCaption("Field of View (" + MyGUI::utility::toString(int(Settings::Manager::getInt("field of view", "General"))) + ")"); @@ -427,14 +423,6 @@ namespace MWGui } } - void SettingsWindow::onFpsToggled(MyGUI::Widget* _sender) - { - int newLevel = (Settings::Manager::getInt("fps", "HUD") + 1) % 2; - Settings::Manager::setInt("fps", "HUD", newLevel); - mFPSButton->setCaptionWithReplacing(fpsLevelToStr(newLevel)); - apply(); - } - void SettingsWindow::onTextureFilteringChanged(MyGUI::ComboBox* _sender, size_t pos) { Settings::Manager::setString("texture filtering", "General", Misc::StringUtils::lowerCase(_sender->getItemNameAt(pos))); diff --git a/apps/openmw/mwgui/settingswindow.hpp b/apps/openmw/mwgui/settingswindow.hpp index 0369eb40e..99553808b 100644 --- a/apps/openmw/mwgui/settingswindow.hpp +++ b/apps/openmw/mwgui/settingswindow.hpp @@ -30,7 +30,6 @@ namespace MWGui MyGUI::Button* mFullscreenButton; MyGUI::Button* mVSyncButton; MyGUI::Button* mWindowBorderButton; - MyGUI::Button* mFPSButton; MyGUI::ScrollBar* mFOVSlider; MyGUI::ScrollBar* mDifficultySlider; MyGUI::ScrollBar* mAnisotropySlider; @@ -53,7 +52,6 @@ namespace MWGui void onTabChanged(MyGUI::TabControl* _sender, size_t index); void onOkButtonClicked(MyGUI::Widget* _sender); - void onFpsToggled(MyGUI::Widget* _sender); void onTextureFilteringChanged(MyGUI::ComboBox* _sender, size_t pos); void onSliderChangePosition(MyGUI::ScrollBar* scroller, size_t pos); void onButtonToggled(MyGUI::Widget* _sender); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index e1e838cdf..e2404c58a 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -185,7 +185,6 @@ namespace MWGui , mForceHidden(GW_None) , mAllowed(GW_ALL) , mRestAllowed(true) - , mFPS(0.0f) , mFallbackMap(fallbackMap) , mShowOwned(0) , mVersionDescription(versionDescription) @@ -296,7 +295,7 @@ namespace MWGui trackWindow(mDialogueWindow, "dialogue"); mContainerWindow = new ContainerWindow(mDragAndDrop); trackWindow(mContainerWindow, "container"); - mHud = new HUD(mCustomMarkers, Settings::Manager::getInt("fps", "HUD"), mDragAndDrop, mLocalMapRender); + mHud = new HUD(mCustomMarkers, mDragAndDrop, mLocalMapRender); mToolTips = new ToolTips(); mScrollWindow = new ScrollWindow(); mBookWindow = new BookWindow(); @@ -464,8 +463,6 @@ namespace MWGui { cleanupGarbage(); - mHud->setFPS(mFPS); - mHud->update(); } @@ -1138,7 +1135,6 @@ namespace MWGui void WindowManager::processChangedSettings(const Settings::CategorySettingVector& changed) { - mHud->setFpsVisible(static_cast(Settings::Manager::getInt("fps", "HUD"))); mToolTips->setDelay(Settings::Manager::getFloat("tooltip delay", "GUI")); for (Settings::CategorySettingVector::const_iterator it = changed.begin(); @@ -1322,11 +1318,6 @@ namespace MWGui mConsole->executeFile (path); } - void WindowManager::wmUpdateFps(float fps) - { - mFPS = fps; - } - MWGui::DialogueWindow* WindowManager::getDialogueWindow() { return mDialogueWindow; } MWGui::InventoryWindow* WindowManager::getInventoryWindow() { return mInventoryWindow; } MWGui::CountDialog* WindowManager::getCountDialog() { return mCountDialog; } diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index a1f76683e..7df5508a1 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -180,8 +180,6 @@ namespace MWGui virtual void setConsoleSelectedObject(const MWWorld::Ptr& object); - virtual void wmUpdateFps(float fps); - ///< Set value for the given ID. virtual void setValue (const std::string& id, const MWMechanics::AttributeValue& value); virtual void setValue (int parSkill, const MWMechanics::SkillValue& value); @@ -486,8 +484,6 @@ namespace MWGui void updateMap(); - float mFPS; - std::map mFallbackMap; int mShowOwned; diff --git a/files/mygui/openmw_hud.layout b/files/mygui/openmw_hud.layout index 97b018469..03c05260f 100644 --- a/files/mygui/openmw_hud.layout +++ b/files/mygui/openmw_hud.layout @@ -125,11 +125,5 @@ - - - - - - diff --git a/files/mygui/openmw_settings_window.layout b/files/mygui/openmw_settings_window.layout index 1d02ea19a..22d36de2b 100644 --- a/files/mygui/openmw_settings_window.layout +++ b/files/mygui/openmw_settings_window.layout @@ -255,14 +255,6 @@ - - - - - - - - diff --git a/files/mygui/openmw_text.skin.xml b/files/mygui/openmw_text.skin.xml index e459f22fa..b7a893580 100644 --- a/files/mygui/openmw_text.skin.xml +++ b/files/mygui/openmw_text.skin.xml @@ -18,15 +18,6 @@ color_misc=0,205,205 # ???? - - - - - - - - - diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 7c809b926..d68bc2fef 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -84,11 +84,6 @@ fade start = 0.8 debug = false [HUD] -# FPS counter -# 0: not visible -# 1: FPS display -fps = 0 - crosshair = true [Objects] From 7ff168b787f33169456db82c3127b2c6f832cdbe Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 7 Nov 2015 17:21:03 +0100 Subject: [PATCH 2373/3725] osgMyGUI: add support for layers to insert custom rendering state --- .../myguiplatform/myguirendermanager.cpp | 46 ++++++++++++++++--- .../myguiplatform/myguirendermanager.hpp | 6 +++ 2 files changed, 46 insertions(+), 6 deletions(-) diff --git a/components/myguiplatform/myguirendermanager.cpp b/components/myguiplatform/myguirendermanager.cpp index 160d659bd..5bd56dc8f 100644 --- a/components/myguiplatform/myguirendermanager.cpp +++ b/components/myguiplatform/myguirendermanager.cpp @@ -45,6 +45,9 @@ namespace osgMyGUI class Drawable : public osg::Drawable { osgMyGUI::RenderManager *mParent; + osg::ref_ptr mStateSet; + +public: // Stage 0: update widget animations and controllers. Run during the Update traversal. class FrameUpdate : public osg::Drawable::UpdateCallback @@ -101,6 +104,10 @@ class Drawable : public osg::Drawable { virtual void drawImplementation(osg::RenderInfo &renderInfo) const { osg::State *state = renderInfo.getState(); + + state->pushStateSet(mStateSet); + state->apply(); + state->disableAllVertexArrays(); state->setClientActiveTextureUnit(0); glEnableClientState(GL_VERTEX_ARRAY); @@ -113,6 +120,13 @@ class Drawable : public osg::Drawable { { const Batch& batch = *it; osg::VertexBufferObject *vbo = batch.mVertexBuffer; + + if (batch.mStateSet) + { + state->pushStateSet(batch.mStateSet); + state->apply(); + } + osg::Texture2D* texture = batch.mTexture; if(texture) state->applyTextureAttribute(0, texture); @@ -135,12 +149,20 @@ class Drawable : public osg::Drawable { } glDrawArrays(GL_TRIANGLES, 0, batch.mVertexCount); + + if (batch.mStateSet) + { + state->popStateSet(); + state->apply(); + } } glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisableClientState(GL_COLOR_ARRAY); + state->popStateSet(); + state->unbindVertexBufferObject(); state->dirtyAllVertexArrays(); state->disableAllVertexArrays(); @@ -161,10 +183,17 @@ public: osg::ref_ptr frameUpdate = new FrameUpdate; frameUpdate->setRenderManager(mParent); setUpdateCallback(frameUpdate); + + mStateSet = new osg::StateSet; + mStateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF); + mStateSet->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::ON); + mStateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF); + mStateSet->setMode(GL_BLEND, osg::StateAttribute::ON); } Drawable(const Drawable ©, const osg::CopyOp ©op=osg::CopyOp::SHALLOW_COPY) : osg::Drawable(copy, copyop) , mParent(copy.mParent) + , mStateSet(copy.mStateSet) , mWriteTo(0) , mReadFrom(0) { @@ -180,6 +209,9 @@ public: // need to hold on to this too as the mVertexBuffer does not hold a ref to its own array osg::ref_ptr mArray; + // optional + osg::ref_ptr mStateSet; + size_t mVertexCount; }; @@ -321,6 +353,7 @@ RenderManager::RenderManager(osgViewer::Viewer *viewer, osg::Group *sceneroot, R , mUpdate(false) , mIsInitialise(false) , mInvScalingFactor(1.f) + , mInjectState(NULL) { if (scalingFactor != 0.f) mInvScalingFactor = 1.f / scalingFactor; @@ -364,12 +397,6 @@ void RenderManager::initialise() camera->setViewMatrix(osg::Matrix::identity()); camera->setRenderOrder(osg::Camera::POST_RENDER); camera->setClearMask(GL_NONE); - osg::StateSet *state = new osg::StateSet; - state->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::ON); - state->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF); - state->setMode(GL_BLEND, osg::StateAttribute::ON); - state->setAttribute(new osg::BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); - geode->setStateSet(state); geode->setCullingActive(false); camera->addChild(geode.get()); @@ -418,10 +445,17 @@ void RenderManager::doRender(MyGUI::IVertexBuffer *buffer, MyGUI::ITexture *text if (batch.mTexture->getDataVariance() == osg::Object::DYNAMIC) mDrawable->setDataVariance(osg::Object::DYNAMIC); // only for this frame, reset in begin() } + if (mInjectState) + batch.mStateSet = mInjectState; mDrawable->addBatch(batch); } +void RenderManager::setInjectState(osg::StateSet* stateSet) +{ + mInjectState = stateSet; +} + void RenderManager::end() { } diff --git a/components/myguiplatform/myguirendermanager.hpp b/components/myguiplatform/myguirendermanager.hpp index d9fdc1834..f2251cdb0 100644 --- a/components/myguiplatform/myguirendermanager.hpp +++ b/components/myguiplatform/myguirendermanager.hpp @@ -20,6 +20,7 @@ namespace osg class Group; class Camera; class RenderInfo; + class StateSet; } namespace osgMyGUI @@ -48,6 +49,8 @@ class RenderManager : public MyGUI::RenderManager, public MyGUI::IRenderTarget float mInvScalingFactor; + osg::StateSet* mInjectState; + void destroyAllResources(); public: @@ -95,6 +98,9 @@ public: /** @see IRenderTarget::doRender */ virtual void doRender(MyGUI::IVertexBuffer *buffer, MyGUI::ITexture *texture, size_t count); + /** specify a StateSet to inject for rendering. The StateSet will be used by future doRender calls until you reset it to NULL again. */ + void setInjectState(osg::StateSet* stateSet); + /** @see IRenderTarget::getInfo */ virtual const MyGUI::RenderTargetInfo& getInfo() { return mInfo; } From 51f3a8fec66ce990d6cef41ed5b8490355a9791c Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 7 Nov 2015 17:39:31 +0100 Subject: [PATCH 2374/3725] osgMyGUI: move Platform methods to the .cpp file --- apps/openmw/mwgui/windowmanagerimp.cpp | 1 + components/CMakeLists.txt | 2 +- components/myguiplatform/myguiplatform.cpp | 62 +++++++++++++++++ components/myguiplatform/myguiplatform.hpp | 79 ++++++++-------------- 4 files changed, 91 insertions(+), 53 deletions(-) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index e2404c58a..6f2e7755d 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -33,6 +33,7 @@ #include #include +#include #include diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 00eac6ca5..1460dee7b 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -115,7 +115,7 @@ add_component_dir (loadinglistener ) add_component_dir (myguiplatform - myguirendermanager myguidatamanager myguiplatform myguitexture myguiloglistener + myguirendermanager myguidatamanager myguiplatform myguitexture myguiloglistener additivelayer ) add_component_dir (widgets diff --git a/components/myguiplatform/myguiplatform.cpp b/components/myguiplatform/myguiplatform.cpp index 01d6ca567..22b88438f 100644 --- a/components/myguiplatform/myguiplatform.cpp +++ b/components/myguiplatform/myguiplatform.cpp @@ -1,2 +1,64 @@ #include "myguiplatform.hpp" +#include "myguirendermanager.hpp" +#include "myguidatamanager.hpp" +#include "myguiloglistener.hpp" + +namespace osgMyGUI +{ + +Platform::Platform(osgViewer::Viewer *viewer, osg::Group *guiRoot, Resource::TextureManager *textureManager, float uiScalingFactor) + : mRenderManager(nullptr) + , mDataManager(nullptr) + , mLogManager(nullptr) + , mLogFacility(nullptr) +{ + mLogManager = new MyGUI::LogManager(); + mRenderManager = new RenderManager(viewer, guiRoot, textureManager, uiScalingFactor); + mDataManager = new DataManager(); +} + +Platform::~Platform() +{ + delete mRenderManager; + mRenderManager = nullptr; + delete mDataManager; + mDataManager = nullptr; + delete mLogManager; + mLogManager = nullptr; + delete mLogFacility; + mLogFacility = nullptr; +} + +void Platform::initialise(const std::string &resourcePath, const std::string &_logName) +{ + if (!_logName.empty() && !mLogFacility) + { + mLogFacility = new LogFacility(_logName, false); + mLogManager->addLogSource(mLogFacility->getSource()); + } + + mDataManager->setResourcePath(resourcePath); + + mRenderManager->initialise(); + mDataManager->initialise(); +} + +void Platform::shutdown() +{ + mRenderManager->shutdown(); + mDataManager->shutdown(); +} + +RenderManager *Platform::getRenderManagerPtr() +{ + return mRenderManager; +} + +DataManager *Platform::getDataManagerPtr() +{ + return mDataManager; +} + + +} diff --git a/components/myguiplatform/myguiplatform.hpp b/components/myguiplatform/myguiplatform.hpp index 513267c99..56562e12a 100644 --- a/components/myguiplatform/myguiplatform.hpp +++ b/components/myguiplatform/myguiplatform.hpp @@ -1,71 +1,46 @@ #ifndef OPENMW_COMPONENTS_MYGUIPLATFORM_MYGUIPLATFORM_H #define OPENMW_COMPONENTS_MYGUIPLATFORM_MYGUIPLATFORM_H -#include "MyGUI_Prerequest.h" -#include "MyGUI_LogManager.h" +#include -#include "myguirendermanager.hpp" -#include "myguidatamanager.hpp" -#include "myguiloglistener.hpp" +namespace osgViewer +{ + class Viewer; +} +namespace osg +{ + class Group; +} +namespace Resource +{ + class TextureManager; +} +namespace MyGUI +{ + class LogManager; +} namespace osgMyGUI { + class RenderManager; + class DataManager; + class LogFacility; + class Platform { public: - Platform(osgViewer::Viewer* viewer, osg::Group* guiRoot, Resource::TextureManager* textureManager, float uiScalingFactor) - : mRenderManager(nullptr) - , mDataManager(nullptr) - , mLogManager(nullptr) - , mLogFacility(nullptr) - { - mLogManager = new MyGUI::LogManager(); - mRenderManager = new RenderManager(viewer, guiRoot, textureManager, uiScalingFactor); - mDataManager = new DataManager(); - } - - ~Platform() - { - delete mRenderManager; - mRenderManager = nullptr; - delete mDataManager; - mDataManager = nullptr; - delete mLogManager; - mLogManager = nullptr; - delete mLogFacility; - mLogFacility = nullptr; - } - - void initialise(const std::string& resourcePath, const std::string& _logName = "MyGUI.log") - { - if (!_logName.empty() && !mLogFacility) - { - mLogFacility = new LogFacility(_logName, false); - mLogManager->addLogSource(mLogFacility->getSource()); - } + Platform(osgViewer::Viewer* viewer, osg::Group* guiRoot, Resource::TextureManager* textureManager, float uiScalingFactor); - mDataManager->setResourcePath(resourcePath); + ~Platform(); - mRenderManager->initialise(); - mDataManager->initialise(); - } + void initialise(const std::string& resourcePath, const std::string& _logName = "MyGUI.log"); - void shutdown() - { - mRenderManager->shutdown(); - mDataManager->shutdown(); - } + void shutdown(); - RenderManager* getRenderManagerPtr() - { - return mRenderManager; - } + RenderManager* getRenderManagerPtr(); - DataManager* getDataManagerPtr() - { - return mDataManager; - } + DataManager* getDataManagerPtr(); private: RenderManager* mRenderManager; From 57b9eafa0fd2d4d073a3fee9176f24b4cd98de52 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 7 Nov 2015 17:45:22 +0100 Subject: [PATCH 2375/3725] osgMyGUI: implement AdditiveLayer --- apps/openmw/mwgui/windowmanagerimp.cpp | 2 ++ components/myguiplatform/additivelayer.cpp | 33 ++++++++++++++++++++++ components/myguiplatform/additivelayer.hpp | 33 ++++++++++++++++++++++ 3 files changed, 68 insertions(+) create mode 100644 components/myguiplatform/additivelayer.cpp create mode 100644 components/myguiplatform/additivelayer.hpp diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 6f2e7755d..fdf26d949 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -34,6 +34,7 @@ #include #include +#include #include @@ -216,6 +217,7 @@ namespace MWGui MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); + MyGUI::FactoryManager::getInstance().registerFactory("Layer"); BookPage::registerMyGUIComponents (); ItemView::registerComponents(); ItemWidget::registerComponents(); diff --git a/components/myguiplatform/additivelayer.cpp b/components/myguiplatform/additivelayer.cpp new file mode 100644 index 000000000..aa2ef08b3 --- /dev/null +++ b/components/myguiplatform/additivelayer.cpp @@ -0,0 +1,33 @@ +#include "additivelayer.hpp" + +#include +#include + +#include "myguirendermanager.hpp" + +namespace osgMyGUI +{ + + AdditiveLayer::AdditiveLayer() + { + mStateSet = new osg::StateSet; + mStateSet->setAttributeAndModes(new osg::BlendFunc(osg::BlendFunc::SRC_ALPHA, osg::BlendFunc::ONE)); + } + + AdditiveLayer::~AdditiveLayer() + { + // defined in .cpp file since we can't delete incomplete types + } + + void AdditiveLayer::renderToTarget(MyGUI::IRenderTarget *_target, bool _update) + { + RenderManager& renderManager = static_cast(MyGUI::RenderManager::getInstance()); + + renderManager.setInjectState(mStateSet.get()); + + MyGUI::OverlappedLayer::renderToTarget(_target, _update); + + renderManager.setInjectState(NULL); + } + +} diff --git a/components/myguiplatform/additivelayer.hpp b/components/myguiplatform/additivelayer.hpp new file mode 100644 index 000000000..f3d47bc82 --- /dev/null +++ b/components/myguiplatform/additivelayer.hpp @@ -0,0 +1,33 @@ +#ifndef OPENMW_COMPONENTS_MYGUIPLATFORM_ADDITIVELAYER +#define OPENMW_COMPONENTS_MYGUIPLATFORM_ADDITIVELAYER + +#include + +#include + +namespace osg +{ + class StateSet; +} + +namespace osgMyGUI +{ + + /// @brief A Layer rendering with additive blend mode. + class AdditiveLayer : public MyGUI::OverlappedLayer + { + public: + MYGUI_RTTI_DERIVED( AdditiveLayer ) + + AdditiveLayer(); + ~AdditiveLayer(); + + virtual void renderToTarget(MyGUI::IRenderTarget* _target, bool _update); + + private: + osg::ref_ptr mStateSet; + }; + +} + +#endif From a90ef8afd0aacf576467513cc9ec4e64732e2b40 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 7 Nov 2015 17:48:36 +0100 Subject: [PATCH 2376/3725] layer renaming --- apps/openmw/mwgui/windowmanagerimp.cpp | 2 +- files/mygui/openmw_layers.xml | 4 ++-- files/mygui/openmw_screen_fader.layout | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index fdf26d949..3fe786ab2 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -334,7 +334,7 @@ namespace MWGui mDebugWindow = new DebugWindow(); - mInputBlocker = MyGUI::Gui::getInstance().createWidget("",0,0,w,h,MyGUI::Align::Stretch,"Overlay"); + mInputBlocker = MyGUI::Gui::getInstance().createWidget("",0,0,w,h,MyGUI::Align::Stretch,"InputBlocker"); mHud->setVisible(mHudEnabled); diff --git a/files/mygui/openmw_layers.xml b/files/mygui/openmw_layers.xml index cf577aec5..7b2955bbd 100644 --- a/files/mygui/openmw_layers.xml +++ b/files/mygui/openmw_layers.xml @@ -1,7 +1,7 @@ - + @@ -12,6 +12,6 @@ - + diff --git a/files/mygui/openmw_screen_fader.layout b/files/mygui/openmw_screen_fader.layout index 13234792f..e9009d32a 100644 --- a/files/mygui/openmw_screen_fader.layout +++ b/files/mygui/openmw_screen_fader.layout @@ -1,7 +1,7 @@ - + From d85d74e615818ba2abf71dd668b0581c077a1575 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 7 Nov 2015 18:04:03 +0100 Subject: [PATCH 2377/3725] Use AdditiveLayer for the hit fader --- apps/openmw/mwgui/screenfader.cpp | 4 ++-- apps/openmw/mwgui/screenfader.hpp | 2 +- apps/openmw/mwgui/windowmanagerimp.cpp | 2 +- files/mygui/CMakeLists.txt | 1 + files/mygui/openmw_layers.xml | 1 + files/mygui/openmw_screen_fader_hit.layout | 7 +++++++ 6 files changed, 13 insertions(+), 4 deletions(-) create mode 100644 files/mygui/openmw_screen_fader_hit.layout diff --git a/apps/openmw/mwgui/screenfader.cpp b/apps/openmw/mwgui/screenfader.cpp index 473776a82..c44bcc3f1 100644 --- a/apps/openmw/mwgui/screenfader.cpp +++ b/apps/openmw/mwgui/screenfader.cpp @@ -66,8 +66,8 @@ namespace MWGui mFader->notifyOperationFinished(); } - ScreenFader::ScreenFader(const std::string & texturePath) - : WindowBase("openmw_screen_fader.layout") + ScreenFader::ScreenFader(const std::string & texturePath, const std::string& layout) + : WindowBase(layout) , mCurrentAlpha(0.f) , mFactor(1.f) , mRepeat(false) diff --git a/apps/openmw/mwgui/screenfader.hpp b/apps/openmw/mwgui/screenfader.hpp index 402554555..d25f5fdc4 100644 --- a/apps/openmw/mwgui/screenfader.hpp +++ b/apps/openmw/mwgui/screenfader.hpp @@ -36,7 +36,7 @@ namespace MWGui class ScreenFader : public WindowBase { public: - ScreenFader(const std::string & texturePath); + ScreenFader(const std::string & texturePath, const std::string& layout = "openmw_screen_fader.layout"); void setTexture(const std::string & texturePath); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 3fe786ab2..bf65377f6 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -329,7 +329,7 @@ namespace MWGui // TODO: check if non-BM versions actually use player_hit_01.dds if(!mResourceSystem->getVFS()->exists(hitFaderTexture)) hitFaderTexture = "textures\\player_hit_01.dds"; - mHitFader = new ScreenFader(hitFaderTexture); + mHitFader = new ScreenFader(hitFaderTexture, "openmw_screen_fader_hit.layout"); mScreenFader = new ScreenFader("black"); mDebugWindow = new DebugWindow(); diff --git a/files/mygui/CMakeLists.txt b/files/mygui/CMakeLists.txt index dc9e8ea84..7494d3ba2 100644 --- a/files/mygui/CMakeLists.txt +++ b/files/mygui/CMakeLists.txt @@ -80,6 +80,7 @@ set(MYGUI_FILES openmw_savegame_dialog.layout openmw_recharge_dialog.layout openmw_screen_fader.layout + openmw_screen_fader_hit.layout openmw_edit_note.layout openmw_debug_window.layout openmw_debug_window.skin.xml diff --git a/files/mygui/openmw_layers.xml b/files/mygui/openmw_layers.xml index 7b2955bbd..c8684c858 100644 --- a/files/mygui/openmw_layers.xml +++ b/files/mygui/openmw_layers.xml @@ -2,6 +2,7 @@ + diff --git a/files/mygui/openmw_screen_fader_hit.layout b/files/mygui/openmw_screen_fader_hit.layout new file mode 100644 index 000000000..7e60f0ff5 --- /dev/null +++ b/files/mygui/openmw_screen_fader_hit.layout @@ -0,0 +1,7 @@ + + + + + + + From 6c12c9a467cfeb0b4e640e9f48b95bfaec1bf3b2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 7 Nov 2015 19:45:30 +0100 Subject: [PATCH 2378/3725] Layer renaming fix --- apps/openmw/mwgui/windowmanagerimp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index bf65377f6..58e33623d 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -248,7 +248,7 @@ namespace MWGui MyGUI::PointerManager::getInstance().setVisible(false); mVideoBackground = MyGUI::Gui::getInstance().createWidgetReal("ImageBox", 0,0,1,1, - MyGUI::Align::Default, "Overlay"); + MyGUI::Align::Default, "InputBlocker"); mVideoBackground->setImageTexture("black"); mVideoBackground->setVisible(false); mVideoBackground->setNeedMouseFocus(true); From 231570f0916386c56fe7134106e56baf25d7cd9a Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 8 Nov 2015 01:21:59 +0100 Subject: [PATCH 2379/3725] travis.yml fix --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 22f6164c2..0910ac546 100644 --- a/.travis.yml +++ b/.travis.yml @@ -40,8 +40,8 @@ script: - cd ./build - if [ "$COVERITY_SCAN_BRANCH" != 1 ]; then ${ANALYZE}make -j2; fi - if [ "$COVERITY_SCAN_BRANCH" != 1 ] && [ "${TRAVIS_OS_NAME}" = "osx" ]; then make package; fi - - if [ "$COVERITY_SCAN_BRANCH" != 1 ] && ["${TRAVIS_OS_NAME}" = "linux" ]; then ./openmw_test_suite; fi - - if [ "$COVERITY_SCAN_BRANCH" != 1 ] && ["${TRAVIS_OS_NAME}" = "linux" ]; then cd .. && ./CI/check_tabs.sh; fi + - if [ "$COVERITY_SCAN_BRANCH" != 1 ] && [ "${TRAVIS_OS_NAME}" = "linux" ]; then ./openmw_test_suite; fi + - if [ "$COVERITY_SCAN_BRANCH" != 1 ] && [ "${TRAVIS_OS_NAME}" = "linux" ]; then cd .. && ./CI/check_tabs.sh; fi notifications: recipients: - corrmage+travis-ci@gmail.com From 08a55febc874abb44216303110ea4dcc1db6525c Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 8 Nov 2015 17:52:39 +0100 Subject: [PATCH 2380/3725] Adjust Scroll window layout to better match MW --- files/mygui/openmw_scroll.layout | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/files/mygui/openmw_scroll.layout b/files/mygui/openmw_scroll.layout index 194700f36..e4ad23bba 100644 --- a/files/mygui/openmw_scroll.layout +++ b/files/mygui/openmw_scroll.layout @@ -2,24 +2,24 @@ - + - + - + - + From 59aee04ddb33b50e4a02a6f4a296126a7bdf1d4f Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 8 Nov 2015 18:21:25 +0100 Subject: [PATCH 2381/3725] Implement ScalingLayer, for layouting of widgets in screen-relative coordinates --- components/CMakeLists.txt | 2 +- components/myguiplatform/scalinglayer.cpp | 138 ++++++++++++++++++++++ components/myguiplatform/scalinglayer.hpp | 31 +++++ 3 files changed, 170 insertions(+), 1 deletion(-) create mode 100644 components/myguiplatform/scalinglayer.cpp create mode 100644 components/myguiplatform/scalinglayer.hpp diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 1460dee7b..f8f4c64ab 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -115,7 +115,7 @@ add_component_dir (loadinglistener ) add_component_dir (myguiplatform - myguirendermanager myguidatamanager myguiplatform myguitexture myguiloglistener additivelayer + myguirendermanager myguidatamanager myguiplatform myguitexture myguiloglistener additivelayer scalinglayer ) add_component_dir (widgets diff --git a/components/myguiplatform/scalinglayer.cpp b/components/myguiplatform/scalinglayer.cpp new file mode 100644 index 000000000..7f7cac69b --- /dev/null +++ b/components/myguiplatform/scalinglayer.cpp @@ -0,0 +1,138 @@ +#include "scalinglayer.hpp" + +#include + +namespace osgMyGUI +{ + + /// @brief the ProxyRenderTarget allows to adjust the pixel scale and offset for a "source" render target. + class ProxyRenderTarget : public MyGUI::IRenderTarget + { + public: + /// @param target The target to render to. + /// @param viewSize The size of the underlying layer node to render. + /// @param hoffset The horizontal rendering offset, specified as an offset from the left screen edge in range 0-1. + /// @param voffset The vertical rendering offset, specified as an offset from the top screen edge in range 0-1. + ProxyRenderTarget(MyGUI::IRenderTarget* target, MyGUI::IntSize viewSize, float hoffset, float voffset) + : mTarget(target) + , mViewSize(viewSize) + , mHOffset(hoffset) + , mVOffset(voffset) + { + } + + virtual void begin() + { + mTarget->begin(); + } + + virtual void end() + { + mTarget->end(); + } + + virtual void doRender(MyGUI::IVertexBuffer* _buffer, MyGUI::ITexture* _texture, size_t _count) + { + mTarget->doRender(_buffer, _texture, _count); + } + + virtual const MyGUI::RenderTargetInfo& getInfo() + { + mInfo = mTarget->getInfo(); + mInfo.hOffset = mHOffset; + mInfo.vOffset = mVOffset; + mInfo.pixScaleX = 1.f / mViewSize.width; + mInfo.pixScaleY = 1.f / mViewSize.height; + return mInfo; + } + + private: + MyGUI::IRenderTarget* mTarget; + MyGUI::IntSize mViewSize; + float mHOffset, mVOffset; + MyGUI::RenderTargetInfo mInfo; + }; + + MyGUI::ILayerItem *ScalingLayer::getLayerItemByPoint(int _left, int _top) const + { + screenToLayerCoords(_left, _top); + + return OverlappedLayer::getLayerItemByPoint(_left, _top); + } + + void ScalingLayer::screenToLayerCoords(int& _left, int& _top) const + { + float scale = getScaleFactor(); + if (scale <= 0.f) + return; + + MyGUI::IntSize globalViewSize = MyGUI::RenderManager::getInstance().getViewSize(); + + _left -= globalViewSize.width/2; + _top -= globalViewSize.height/2; + + _left /= scale; + _top /= scale; + + _left += mViewSize.width/2; + _top += mViewSize.height/2; + } + + float ScalingLayer::getScaleFactor() const + { + MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize(); + float w = viewSize.width; + float h = viewSize.height; + + float heightScale = (h / mViewSize.height); + float widthScale = (w / mViewSize.width); + return std::min(widthScale, heightScale); + } + + MyGUI::IntPoint ScalingLayer::getPosition(int _left, int _top) const + { + screenToLayerCoords(_left, _top); + return MyGUI::IntPoint(_left, _top); + } + + void ScalingLayer::renderToTarget(MyGUI::IRenderTarget *_target, bool _update) + { + MyGUI::IntSize globalViewSize = MyGUI::RenderManager::getInstance().getViewSize(); + MyGUI::IntSize viewSize = globalViewSize; + viewSize.width /= getScaleFactor(); + viewSize.height /= getScaleFactor(); + + float hoffset = (globalViewSize.width - mViewSize.width*getScaleFactor())/2.f / static_cast(globalViewSize.width); + float voffset = (globalViewSize.height - mViewSize.height*getScaleFactor())/2.f / static_cast(globalViewSize.height); + + ProxyRenderTarget proxy(_target, viewSize, hoffset, voffset); + + MyGUI::OverlappedLayer::renderToTarget(&proxy, _update); + } + + void ScalingLayer::resizeView(const MyGUI::IntSize &_viewSize) + { + // do nothing + } + + void ScalingLayer::deserialization(MyGUI::xml::ElementPtr _node, MyGUI::Version _version) + { + MyGUI::OverlappedLayer::deserialization(_node, _version); + + MyGUI::xml::ElementEnumerator info = _node->getElementEnumerator(); + while (info.next()) + { + if (info->getName() == "Property") + { + const std::string& key = info->findAttribute("key"); + const std::string& value = info->findAttribute("value"); + + if (key == "Size") + { + mViewSize = MyGUI::IntSize::parse(value); + } + } + } + } + +} diff --git a/components/myguiplatform/scalinglayer.hpp b/components/myguiplatform/scalinglayer.hpp new file mode 100644 index 000000000..3ee1489f1 --- /dev/null +++ b/components/myguiplatform/scalinglayer.hpp @@ -0,0 +1,31 @@ +#ifndef OPENMW_COMPONENTS_MYGUIPLATFORM_SCALINGLAYER +#define OPENMW_COMPONENTS_MYGUIPLATFORM_SCALINGLAYER + +#include + +namespace osgMyGUI +{ + + ///@brief A Layer that lays out and renders widgets in screen-relative coordinates. The "Size" property determines the size of the virtual screen, + /// which is then upscaled to the real screen size during rendering. The aspect ratio is kept intact, adding blanks to the sides when necessary. + class ScalingLayer : public MyGUI::OverlappedLayer + { + public: + MYGUI_RTTI_DERIVED(ScalingLayer) + + virtual void deserialization(MyGUI::xml::ElementPtr _node, MyGUI::Version _version); + + virtual MyGUI::ILayerItem* getLayerItemByPoint(int _left, int _top) const; + virtual MyGUI::IntPoint getPosition(int _left, int _top) const; + virtual void renderToTarget(MyGUI::IRenderTarget* _target, bool _update); + + virtual void resizeView(const MyGUI::IntSize& _viewSize); + + private: + void screenToLayerCoords(int& _left, int& _top) const; + float getScaleFactor() const; + }; + +} + +#endif From f9932130dabc201067d32cca69b8b5b4e49b2c95 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 8 Nov 2015 18:23:02 +0100 Subject: [PATCH 2382/3725] Work around MyGUI bug with mouse event coordinates (fixed in git) --- apps/openmw/mwgui/bookpage.cpp | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwgui/bookpage.cpp b/apps/openmw/mwgui/bookpage.cpp index cfb49ebff..9878051f7 100644 --- a/apps/openmw/mwgui/bookpage.cpp +++ b/apps/openmw/mwgui/bookpage.cpp @@ -949,12 +949,18 @@ public: if (!mBook) return; - left -= mCroppedParent->getAbsoluteLeft (); - top -= mCroppedParent->getAbsoluteTop (); + // work around inconsistency in MyGUI where the mouse press coordinates aren't + // transformed by the current Layer (even though mouse *move* events are). + MyGUI::IntPoint pos (left, top); +#if MYGUI_VERSION < MYGUI_DEFINE_VERSION(3,2,3) + pos = mNode->getLayer()->getPosition(left, top); +#endif + pos.left -= mCroppedParent->getAbsoluteLeft (); + pos.top -= mCroppedParent->getAbsoluteTop (); if (mLastDown == MyGUI::MouseButton::None) { - mFocusItem = mBook->hitTest (left, mViewTop + top); + mFocusItem = mBook->hitTest (pos.left, mViewTop + pos.top); mItemActive = true; dirtyFocusItem (); @@ -968,12 +974,19 @@ public: if (!mBook) return; - left -= mCroppedParent->getAbsoluteLeft (); - top -= mCroppedParent->getAbsoluteTop (); + // work around inconsistency in MyGUI where the mouse release coordinates aren't + // transformed by the current Layer (even though mouse *move* events are). + MyGUI::IntPoint pos (left, top); +#if MYGUI_VERSION < MYGUI_DEFINE_VERSION(3,2,3) + pos = mNode->getLayer()->getPosition(left, top); +#endif + + pos.left -= mCroppedParent->getAbsoluteLeft (); + pos.top -= mCroppedParent->getAbsoluteTop (); if (mLastDown == id) { - Style * mItem = mBook->hitTest (left, mViewTop + top); + Style * mItem = mBook->hitTest (pos.left, mViewTop + pos.top); bool clicked = mFocusItem == mItem; From a7ad45e73e32131716bbdf871231fe43aa8abe0b Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 8 Nov 2015 18:23:47 +0100 Subject: [PATCH 2383/3725] WindowBase::center use the layer size instead of render window size --- apps/openmw/mwgui/windowbase.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwgui/windowbase.cpp b/apps/openmw/mwgui/windowbase.cpp index 191e8223d..c9d1b0617 100644 --- a/apps/openmw/mwgui/windowbase.cpp +++ b/apps/openmw/mwgui/windowbase.cpp @@ -49,11 +49,13 @@ void WindowBase::center() { // Centre dialog - MyGUI::IntSize gameWindowSize = MyGUI::RenderManager::getInstance().getViewSize(); + MyGUI::IntSize layerSize = MyGUI::RenderManager::getInstance().getViewSize(); + if (mMainWidget->getLayer()) + layerSize = mMainWidget->getLayer()->getSize(); MyGUI::IntCoord coord = mMainWidget->getCoord(); - coord.left = (gameWindowSize.width - coord.width)/2; - coord.top = (gameWindowSize.height - coord.height)/2; + coord.left = (layerSize.width - coord.width)/2; + coord.top = (layerSize.height - coord.height)/2; mMainWidget->setCoord(coord); } From 516f2765a15c7c80fcc8784f953c1d5e2842bbd6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 8 Nov 2015 18:24:28 +0100 Subject: [PATCH 2384/3725] Use the ScalingLayer for journal, books and scrolls --- apps/openmw/mwgui/windowmanagerimp.cpp | 2 ++ files/mygui/openmw_book.layout | 2 +- files/mygui/openmw_journal.layout | 2 +- files/mygui/openmw_layers.xml | 3 +++ 4 files changed, 7 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 58e33623d..a7c3a1957 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include @@ -218,6 +219,7 @@ namespace MWGui MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Layer"); + MyGUI::FactoryManager::getInstance().registerFactory("Layer"); BookPage::registerMyGUIComponents (); ItemView::registerComponents(); ItemWidget::registerComponents(); diff --git a/files/mygui/openmw_book.layout b/files/mygui/openmw_book.layout index 2336d5b2c..7c158af8d 100644 --- a/files/mygui/openmw_book.layout +++ b/files/mygui/openmw_book.layout @@ -2,7 +2,7 @@ - + diff --git a/files/mygui/openmw_journal.layout b/files/mygui/openmw_journal.layout index 5524f5520..9c40bd562 100644 --- a/files/mygui/openmw_journal.layout +++ b/files/mygui/openmw_journal.layout @@ -2,7 +2,7 @@ - + diff --git a/files/mygui/openmw_layers.xml b/files/mygui/openmw_layers.xml index c8684c858..c6d3df521 100644 --- a/files/mygui/openmw_layers.xml +++ b/files/mygui/openmw_layers.xml @@ -6,6 +6,9 @@ + + + From 79b3f1e6a823ff5fbf9784adb4db9f991d477ec5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 8 Nov 2015 18:27:01 +0100 Subject: [PATCH 2385/3725] Small cleanup --- components/myguiplatform/scalinglayer.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/components/myguiplatform/scalinglayer.cpp b/components/myguiplatform/scalinglayer.cpp index 7f7cac69b..19ae10841 100644 --- a/components/myguiplatform/scalinglayer.cpp +++ b/components/myguiplatform/scalinglayer.cpp @@ -99,8 +99,9 @@ namespace osgMyGUI { MyGUI::IntSize globalViewSize = MyGUI::RenderManager::getInstance().getViewSize(); MyGUI::IntSize viewSize = globalViewSize; - viewSize.width /= getScaleFactor(); - viewSize.height /= getScaleFactor(); + float scale = getScaleFactor(); + viewSize.width /= scale; + viewSize.height /= scale; float hoffset = (globalViewSize.width - mViewSize.width*getScaleFactor())/2.f / static_cast(globalViewSize.width); float voffset = (globalViewSize.height - mViewSize.height*getScaleFactor())/2.f / static_cast(globalViewSize.height); From 75f11f781c85acc3d6efa077403e1fb12db710d3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 8 Nov 2015 18:32:41 +0100 Subject: [PATCH 2386/3725] Use the ScalingLayer for Scroll window --- files/mygui/openmw_scroll.layout | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/mygui/openmw_scroll.layout b/files/mygui/openmw_scroll.layout index e4ad23bba..b2e62f28d 100644 --- a/files/mygui/openmw_scroll.layout +++ b/files/mygui/openmw_scroll.layout @@ -2,7 +2,7 @@ - + From 66925be44073dbd45d1c107823eb6c2c1633edea Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 8 Nov 2015 19:59:33 +0100 Subject: [PATCH 2387/3725] Partially revert 682f30ef9c7e8edad3e825be6920670ffac3bdce This change made dead netch fall through the floor, because the animation moves the creature *below* its external collision box. --- apps/openmw/mwphysics/physicssystem.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 92994d557..739b0013b 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -240,8 +240,6 @@ namespace MWPhysics const ESM::Position& refpos = ptr.getRefData().getPosition(); osg::Vec3f position(refpos.asVec3()); - float collisionShapeOffset = physicActor->getPosition().z() - position.z(); - // Early-out for totally static creatures // (Not sure if gravity should still apply?) if (!ptr.getClass().isMobile(ptr)) @@ -258,11 +256,17 @@ namespace MWPhysics } btCollisionObject *colobj = physicActor->getCollisionObject(); - position.z() += collisionShapeOffset; + osg::Vec3f halfExtents = physicActor->getHalfExtents(); + + // NOTE: here we don't account for the collision box translation (i.e. physicActor->getPosition() - refpos.pos). + // That means the collision shape used for moving this actor is in a different spot than the collision shape + // other actors are using to collide against this actor. + // While this is strictly speaking wrong, it's needed for MW compatibility. + position.z() += halfExtents.z(); static const float fSwimHeightScale = MWBase::Environment::get().getWorld()->getStore().get() .find("fSwimHeightScale")->getFloat(); - float swimlevel = waterlevel + collisionShapeOffset - (physicActor->getRenderingHalfExtents().z() * 2 * fSwimHeightScale); + float swimlevel = waterlevel + halfExtents.z() - (physicActor->getRenderingHalfExtents().z() * 2 * fSwimHeightScale); ActorTracer tracer; osg::Vec3f inertia = physicActor->getInertialForce(); @@ -370,7 +374,7 @@ namespace MWPhysics { // don't let pure water creatures move out of water after stepMove if (ptr.getClass().isPureWaterCreature(ptr) - && newPosition.z() + physicActor->getHalfExtents().z() > waterlevel) + && newPosition.z() + halfExtents.z() > waterlevel) newPosition = oldPosition; } else @@ -451,7 +455,7 @@ namespace MWPhysics } physicActor->setOnGround(isOnGround); - newPosition.z() -= collisionShapeOffset; // remove what was added at the beginning + newPosition.z() -= halfExtents.z(); // remove what was added at the beginning return newPosition; } }; From f0a1434578506727f86c935f72c0be2d3f986044 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 8 Nov 2015 20:58:00 +0100 Subject: [PATCH 2388/3725] Dead actors underwater will float to the surface --- apps/openmw/mwphysics/physicssystem.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 739b0013b..55144afe7 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -288,6 +288,11 @@ namespace MWPhysics velocity = velocity + physicActor->getInertialForce(); } } + + // dead actors underwater will float to the surface + if (ptr.getClass().getCreatureStats(ptr).isDead() && position.z() < swimlevel) + velocity = osg::Vec3f(0,0,1) * 25; + ptr.getClass().getMovementSettings(ptr).mPosition[2] = 0; // Now that we have the effective movement vector, apply wind forces to it From 055841e721734b043f1f80be6f3653547332239a Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 9 Nov 2015 02:22:40 +0100 Subject: [PATCH 2389/3725] Improve cloud lighting --- apps/openmw/mwrender/sky.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 12708ba48..5c38d79d4 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1563,17 +1563,15 @@ void SkyManager::setWeather(const WeatherResult& weather) mCloudMesh2->setNodeMask(mCloudBlendFactor > 0.f ? ~0 : 0); } - if (mCloudColour != weather.mSunColor) + if (mCloudColour != weather.mFogColor) { - // FIXME: this doesn't look correct - osg::Vec4f clr( weather.mSunColor.r()*0.7f + weather.mAmbientColor.r()*0.7f, - weather.mSunColor.g()*0.7f + weather.mAmbientColor.g()*0.7f, - weather.mSunColor.b()*0.7f + weather.mAmbientColor.b()*0.7f, 1.f); + osg::Vec4f clr (weather.mFogColor); + clr += osg::Vec4f(0.13f, 0.13f, 0.13f, 0.f); mCloudUpdater->setEmissionColor(clr); mCloudUpdater2->setEmissionColor(clr); - mCloudColour = weather.mSunColor; + mCloudColour = weather.mFogColor; } if (mSkyColour != weather.mSkyColor) From b89945804c829443beac2de8c80730c2a2dbb7a6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 9 Nov 2015 02:57:49 +0100 Subject: [PATCH 2390/3725] BookPage: implement hit test with margin for error --- apps/openmw/mwgui/bookpage.cpp | 46 +++++++++++++++++++++++++++------- 1 file changed, 37 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwgui/bookpage.cpp b/apps/openmw/mwgui/bookpage.cpp index 9878051f7..b728b748f 100644 --- a/apps/openmw/mwgui/bookpage.cpp +++ b/apps/openmw/mwgui/bookpage.cpp @@ -153,6 +153,34 @@ struct TypesetBookImpl : TypesetBook visitRuns (top, bottom, NULL, visitor); } + /// hit test with a margin for error. only hits on interactive text fragments are reported. + StyleImpl * hitTestWithMargin (int left, int top) + { + StyleImpl * hit = hitTest(left, top); + if (hit && hit->mInteractiveId > 0) + return hit; + + const int maxMargin = 10; + for (int margin=1; margin < maxMargin; ++margin) + { + for (int i=0; i<4; ++i) + { + if (i==0) + hit = hitTest(left, top-margin); + else if (i==1) + hit = hitTest(left, top+margin); + else if (i==2) + hit = hitTest(left-margin, top); + else + hit = hitTest(left+margin, top); + + if (hit && hit->mInteractiveId > 0) + return hit; + } + } + return NULL; + } + StyleImpl * hitTest (int left, int top) const { for (Sections::const_iterator i = mSections.begin (); i != mSections.end (); ++i) @@ -916,15 +944,15 @@ public: left -= mCroppedParent->getAbsoluteLeft (); top -= mCroppedParent->getAbsoluteTop (); - Style * Hit = mBook->hitTest (left, mViewTop + top); + Style * hit = mBook->hitTestWithMargin (left, mViewTop + top); if (mLastDown == MyGUI::MouseButton::None) { - if (Hit != mFocusItem) + if (hit != mFocusItem) { dirtyFocusItem (); - mFocusItem = Hit; + mFocusItem = hit; mItemActive = false; dirtyFocusItem (); @@ -933,7 +961,7 @@ public: else if (mFocusItem != 0) { - bool newItemActive = Hit == mFocusItem; + bool newItemActive = hit == mFocusItem; if (newItemActive != mItemActive) { @@ -960,7 +988,7 @@ public: if (mLastDown == MyGUI::MouseButton::None) { - mFocusItem = mBook->hitTest (pos.left, mViewTop + pos.top); + mFocusItem = mBook->hitTestWithMargin (pos.left, mViewTop + pos.top); mItemActive = true; dirtyFocusItem (); @@ -986,9 +1014,9 @@ public: if (mLastDown == id) { - Style * mItem = mBook->hitTest (pos.left, mViewTop + pos.top); + Style * item = mBook->hitTestWithMargin (pos.left, mViewTop + pos.top); - bool clicked = mFocusItem == mItem; + bool clicked = mFocusItem == item; mItemActive = false; @@ -996,8 +1024,8 @@ public: mLastDown = MyGUI::MouseButton::None; - if (clicked && mLinkClicked && mItem && mItem->mInteractiveId != 0) - mLinkClicked (mItem->mInteractiveId); + if (clicked && mLinkClicked && item && item->mInteractiveId != 0) + mLinkClicked (item->mInteractiveId); } } From b61b732207e9ec5e48023987e368156375916b57 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 9 Nov 2015 09:07:18 +0100 Subject: [PATCH 2391/3725] fixed an interference with script warning mode and error downgrading (Fixes #2990) --- components/compiler/errorhandler.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/components/compiler/errorhandler.cpp b/components/compiler/errorhandler.cpp index a987a86da..7f02255db 100644 --- a/components/compiler/errorhandler.cpp +++ b/components/compiler/errorhandler.cpp @@ -32,7 +32,10 @@ namespace Compiler void ErrorHandler::warning (const std::string& message, const TokenLoc& loc) { - if (mWarningsMode==1) + if (mWarningsMode==1 || + // temporarily change from mode 2 to mode 1 if error downgrading is enabled to + // avoid infinite recursion + (mWarningsMode==2 && mDowngradeErrors)) { ++mWarnings; report (message, loc, WarningMessage); From cdf17f415e5357723aae6d49fb32419d55154f70 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 9 Nov 2015 12:03:27 +0100 Subject: [PATCH 2392/3725] updated version number --- CMakeLists.txt | 4 ++-- README.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1e966a163..d33521e8b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,8 +19,8 @@ set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/) message(STATUS "Configuring OpenMW...") set(OPENMW_VERSION_MAJOR 0) -set(OPENMW_VERSION_MINOR 36) -set(OPENMW_VERSION_RELEASE 1) +set(OPENMW_VERSION_MINOR 37) +set(OPENMW_VERSION_RELEASE 0) set(OPENMW_VERSION_COMMITHASH "") set(OPENMW_VERSION_TAGHASH "") diff --git a/README.md b/README.md index 362d2eef4..f353cd76e 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ OpenMW is a recreation of the engine for the popular role-playing game Morrowind OpenMW also comes with OpenMW-CS, a replacement for Morrowind's TES Construction Set. -* Version: 0.36.1 +* Version: 0.37.0 * License: GPL (see docs/license/GPL3.txt for more information) * Website: http://www.openmw.org * IRC: #openmw on irc.freenode.net From 93b0008a18da08760ac93b149c6c282594fa51c9 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 9 Nov 2015 12:14:36 +0100 Subject: [PATCH 2393/3725] updated changelog --- CHANGELOG.md | 225 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 225 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b2e7dc25c..3a3cdfd25 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,228 @@ +0.37.0 +------ + + Bug #385: Light emitting objects have a too short distance of activation + Bug #455: Animation doesn't resize creature's bounding box + Bug #602: Only collision model is updated when modifying objects trough console + Bug #639: Sky horizon at nighttime + Bug #672: incorrect trajectory of the moons + Bug #814: incorrect NPC width + Bug #827: Inaccurate raycasting for dead actors + Bug #996: Can see underwater clearly when at right height/angle + Bug #1317: Erene Llenim in Seyda Neen does not walk around + Bug #1330: Cliff racers fail to hit the player + Bug #1366: Combat AI can't aim down (in order to hit small creatures) + Bug #1511: View distance while under water is much too short + Bug #1563: Terrain positioned incorrectly and appears to vibrate in far-out cells + Bug #1612: First person models clip through walls + Bug #1647: Crash switching from full screen to windows mode - D3D9 + Bug #1650: No textures with directx on windows + Bug #1730: Scripts names starting with digit(s) fail to compile + Bug #1738: Socucius Ergalla's greetings are doubled during the tutorial + Bug #1813: Underwater flora lighting up entire area. + Bug #1871: Handle controller extrapolation flags + Bug #1921: Footstep frequency and velocity do not immediately update when speed attribute changes + Bug #2001: OpenMW crashes on start with OpenGL 1.4 drivers + Bug #2014: Antialiasing setting does nothing on Linux + Bug #2037: Some enemies attack the air when spotting the player + Bug #2052: NIF rotation matrices including scales are not supported + Bug #2111: Raindrops in front of fire look wrong + Bug #2140: [OpenGL] Water effects, flames and parts of creatures solid black when observed through brazier flame + Bug #2147: Trueflame and Hopesfire flame effects not properly aligned with blade + Bug #2148: Verminous fabricants have little coloured box beneath their feet + Bug #2149: Sparks in Clockwork City should bounce off the floor + Bug #2151: Clockwork City dicer trap doesn't activate when you're too close + Bug #2186: Mini map contains scrambled pixels that cause the mini map to flicker + Bug #2187: NIF file with more than 255 NiBillboardNodes does not load + Bug #2191: Editor: Crash when trying to view cell in render view in OpenCS + Bug #2270: Objects flicker transparently + Bug #2280: Latest 32bit windows build of openmw runns out of vram + Bug #2281: NPCs don't scream when they die + Bug #2286: Jumping animation restarts when equipping mid-air + Bug #2287: Weapon idle animation stops when turning + Bug #2355: Light spell doesn't work in 1st person view + Bug #2362: Lantern glas opaque to flame effect from certain viewing angles + Bug #2364: Light spells are not as bright as in Morrowind + Bug #2383: Remove the alpha testing override list + Bug #2436: Crash on entering cell "Tower of Tel Fyr, Hall of Fyr" + Bug #2457: Player followers should not report crimes + Bug #2458: crash in some fighting situations + Bug #2464: Hiding an emitter node should make that emitter stop firing particles + Bug #2466: Can't load a save created with OpenMW-0.35.0-win64 + Bug #2468: music from title screen continues after loading savegame + Bug #2494: Map not consistent between saves + Bug #2504: Dialog scroll should always start at the top + Bug #2506: Editor: Undo/Redo shortcuts do not work in script editor + Bug #2513: Mannequins in mods appear as dead bodies + Bug #2524: Editor: TopicInfo "custom" condition section is missing + Bug #2540: Editor: search and verification result table can not be sorted by clicking on the column names + Bug #2543: Editor: there is a problem with spell effects + Bug #2544: Editor fails to save NPC information correctly. + Bug #2545: Editor: delete record in Objects (referenceables) table messes up data + Bug #2546: Editor: race base attributes and skill boni are not displayed, thus not editable + Bug #2547: Editor: some NPC data is not displayed, thus not editable + Bug #2551: Editor: missing data in cell definition + Bug #2553: Editor: value filter does not work for float values + Bug #2555: Editor: undo leaves the record status as Modified + Bug #2559: Make Detect Enchantment marks appear on top of the player arrow + Bug #2563: position consoling npc doesn't work without cell reload + Bug #2564: Editor: Closing a subview from code does not clean up properly and will lead to crash on opening the next subview + Bug #2568: Editor: Setting default window size is ignored + Bug #2569: Editor: saving from an esp to omwaddon file results in data loss for TopicInfo + Bug #2575: Editor: Deleted record (with Added (ModifiedOnly) status) remains in the Dialog SubView + Bug #2576: Editor: Editor doesn't scroll to a newly opened subview, when ScrollBar Only mode is active + Bug #2578: Editor: changing Level or Reputation of an NPC crashes the editor + Bug #2579: Editor: filters not updated when adding or cloning records + Bug #2580: Editor: omwaddon makes OpenMW crash + Bug #2581: Editor: focus problems in edit subviews single- and multiline input fields + Bug #2582: Editor: object verifier should check for non-existing scripts being referenced + Bug #2583: Editor: applying filter to TopicInfo on mods that have added dialouge makes the Editor crash + Bug #2586: Editor: some dialogue only editable items do not refresh after undo + Bug #2588: Editor: Cancel button exits program + Bug #2589: Editor: Regions table - mapcolor does not change correctly + Bug #2591: Placeatme - spurious 5th parameter raises error + Bug #2593: COC command prints multiple times when GUI is hidden + Bug #2598: Editor: scene view of instances has to be zoomed out to displaying something - center camera instance please + Bug #2607: water behind an invisible NPC becomes invisible as well + Bug #2611: Editor: Sort problem in Objects table when few nested rows are added + Bug #2621: crash when a creature has no model + Bug #2624: Editor: missing columns in tables + Bug #2627: Character sheet doesn't properly update when backing out of CharGen + Bug #2642: Editor: endif without if - is not reported as error when "verify" was executed + Bug #2644: Editor: rebuild the list of available content files when opening the open/new dialogues + Bug #2656: OpenMW & OpenMW-CS: setting "Flies" flag for ghosts has no effect + Bug #2659: OpenMW & OpenMW-CS: savegame load fail due to script attached to NPCs + Bug #2668: Editor: reputation value in the input field is not stored + Bug #2696: Horkers use land idle animations under water + Bug #2705: Editor: Sort by Record Type (Objects table) is incorrect + Bug #2711: Map notes on an exterior cell that shows up with a map marker on the world map do not show up in the tooltip for that cell's marker on the world map + Bug #2714: Editor: Can't reorder rows with the same topic in different letter case + Bug #2720: Head tracking for creatures not implemented + Bug #2722: Alchemy should only include effects shared by at least 2 ingredients + Bug #2723: "ori" console command is not working + Bug #2726: Ashlanders in front of Ghostgate start wandering around + Bug #2727: ESM writer does not handle encoding when saving the TES3 header + Bug #2728: Editor: Incorrect position of an added row in Info tables + Bug #2731: Editor: Deleting a record triggers a Qt warning + Bug #2733: Editor: Undo doesn't restore the Modified status of a record when a nested data is changed + Bug #2734: Editor: The Search doesn't work + Bug #2738: Additive moon blending + Bug #2746: NIF node names should be case insensitive + Bug #2752: Fog depth/density not handled correctly + Bug #2753: Editor: line edit in dialogue subview tables shows after a single click + Bug #2755: Combat AI changes target too frequently + Bug #2761: Can't attack during block animations + Bug #2764: Player doesn't raise arm in 3rd person for weathertype 9 + Bug #2768: Current screen resolution not selected in options when starting OpenMW + Bug #2773: Editor: Deleted scripts are editable + Bug #2776: ordinators still think I'm wearing their helm even though Khajiit and argonians can't + Bug #2779: Slider bars continue to move if you don't release mouse button + Bug #2781: sleep interruption is a little off (is this an added feature?) + Bug #2782: erroneously able to ready weapon/magic (+sheathe weapon/magic) while paralyzed + Bug #2785: Editor: Incorrect GMSTs for newly created omwgame files + Bug #2786: Kwama Queen head is inverted under OpenMW + Bug #2788: additem and removeitem incorrect gold behavior + Bug #2790: --start doesn't trace down + Bug #2791: Editor: Listed attributes and skill should not be based on number of NPC objects. + Bug #2792: glitched merchantile/infinite free items + Bug #2794: Need to ignore quotes in names of script function + Bug #2797: Editor: Crash when removing the first row in a nested table + Bug #2800: Show an error message when S3TC support is missing + Bug #2811: Targetted Open spell effect persists. + Bug #2819: Editor: bodypart's race filter not displayed correctly + Bug #2820: Editor: table sorting is inverted + Bug #2821: Editor: undo/redo command labels are incorrect + Bug #2826: locking beds that have been locked via magic psuedo-freezes the game + Bug #2830: Script compiler does not accept IDs as instruction/functions arguments if the ID is also a keyword + Bug #2832: Cell names are not localized on the world map + Bug #2833: [cosmetic] Players swimming at water's surface are slightly too low. + Bug #2840: Save/load menu is not entirely localized + Bug #2853: [exploit/bug] disintegrate weapon incorrectly applying to lockpicks, probes. creates unbreakable lockpicks + Bug #2855: Mouse wheel in journal is not disabled by "Options" panel. + Bug #2856: Heart of Lorkhan doesn't visually respond to attacks + Bug #2863: Inventory highlights wrong category after load + Bug #2864: Illuminated Order 1.0c Bug – The teleport amulet is not placed in the PC inventory. + Bug #2866: Editor: use checkbox instead of combobox for boolean values + Bug #2875: special cases of fSleepRandMod not behaving properly. + Bug #2878: Editor: Verify reports "creature has non-positive level" but there is no level setting + Bug #2879: Editor: entered value of field "Buys *" is not saved for a creature + Bug #2880: OpenMW & OpenMW-CS: having a scale value of 0.000 makes the game laggy + Bug #2882: Freeze when entering cell "Guild of Fighters (Ald'ruhn)" after dropping some items inside + Bug #2884: NPC chats about wrong player race + Bug #2886: Adding custom races breaks existing numbering of PcRace + Bug #2888: Editor: value entered in "AI Wander Idle" is not kept + Bug #2889: Editor: creatures made with the CS (not cloned) are always dead + Bug #2890: Editor: can't make NPC say a specific "Hello" voice-dialouge + Bug #2893: Editor: making a creature use textual dialogue doesn't work. + Bug #2901: Editor: gold for trading can not be set for creatures + Bug #2907: looking from uderwater part of the PC that is below the surface looks like it would be above the water + Bug #2914: Magicka not recalculated on character generation + Bug #2915: When paralyzed, you can still enter and exit sneak + Bug #2917: chameleon does not work for creatures + Bug #2927: Editor: in the automatic script checker local variable caches are not invalidated/updated on modifications of other scripts + Bug #2930: Editor: AIWander Idle can not be set for a creature + Bug #2932: Editor: you can add rows to "Creature Attack" but you can not enter values + Bug #2938: Editor: Can't add a start script. + Bug #2944: Spell chance for power to show as 0 on hud when used + Bug #2953: Editor: rightclick in an empty place in the menu bar shows an unnamed checkbox + Bug #2956: Editor: freezes while editing Filter + Bug #2962: OpenMW: Assertion `it != invStore.end()' failed + Bug #2964: Recursive script execution can corrupt script runtime data + Bug #2973: Editor: placing a chest in the game world and activating it heavily blurrs the character portrait + Bug #2978: Editor: Cannot edit alchemy ingredient properties + Bug #2980: Editor: Attribute and Skill can be selected for spells that do not require these parameters, leading to non-functional spells + Bug #2990: Compiling a script with warning mode 2 and enabled error downgrading leads to infinite recursion + Bug #2992: [Mod: Great House Dagoth] Killing Dagoth Gares freezes the game + Feature #706: Editor: Script Editor enhancements + Feature #872: Editor: Colour values in tables + Feature #880: Editor: ID auto-complete + Feature #928: Editor: Partial sorting in info tables + Feature #942: Editor: Dialogue for editing/viewing content file meta information + Feature #1057: NiStencilProperty + Feature #1278: Editor: Mouse picking in worldspace widget + Feature #1280: Editor: Cell border arrows + Feature #1401: Editor: Cloning enhancements + Feature #1463: Editor: Fine grained configuration of extended revert/delete commands + Feature #1591: Editor: Make fields in creation bar drop targets where applicable + Feature #1998: Editor: Magic effect record verifier + Feature #1999: Editor Sound Gen record verifier + Feature #2000: Editor: Pathgrid record verifier + Feature #2528: Game Time Tracker + Feature #2534: Editor: global search does not auomatically focus the search input field + Feature #2535: OpenMW: allow comments in openmw.cfg + Feature #2541: Editor: provide a go to the very bottom button for TopicInfo and JournalInfo + Feature #2549: Editor: add a horizontal slider to scroll between opened tables + Feature #2558: Editor: provide a shortcut for closing the subview that has the focus + Feature #2565: Editor: add context menu for dialogue sub view fields with an item matching "Edit 'x'" from the table subview context menu + Feature #2585: Editor: Ignore mouse wheel input for numeric values unless the respective widget has the focus + Feature #2620: Editor: make the verify-view refreshable + Feature #2622: Editor: Make double click behaviour in result tables configurable (see ID tables) + Feature #2717: Editor: Add severity column to report tables + Feature #2729: Editor: Various dialogue button bar improvements + Feature #2739: Profiling overlay + Feature #2740: Resource manager optimizations + Feature #2741: Make NIF files into proper resources + Feature #2742: Use the skinning data in NIF files as-is + Feature #2743: Small feature culling + Feature #2744: Configurable near clip distance + Feature #2745: GUI scaling option + Feature #2747: Support anonymous textures + Feature #2749: Loading screen optimizations + Feature #2751: Character preview optimization + Feature #2804: Editor: Merge Tool + Feature #2818: Editor: allow copying a record ID to the clipboard + Feature #2883: game not playable if mod providing a spell is removed but the list of known spells still contains it + Feature #2946: Editor: add script line number in results of search + Feature #2959: space character in field enchantment (of an amulet) prevents rendering of surroundings + Feature #2963: Editor: Mouse button bindings in 3D scene + Feature #2983: Sun Glare fader + Feature #2999: Scaling of journal and books + Task #2665: Support building with Qt5 + Task #2725: Editor: Remove Display_YesNo + Task #2730: Replace hardcoded column numbers in SimpleDialogueSubView/DialogueSubView + Task #2750: Bullet shape instancing optimization + Task #2793: Replace grid size setting with half grid size setting + 0.36.1 ------ From 2fb4a9df6d992ca9ee14f3632c51a1fff0ca8a92 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 9 Nov 2015 15:32:16 +0100 Subject: [PATCH 2394/3725] Update CHANGELOG.md (features that should be bugs instead) --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3a3cdfd25..c5905a897 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -148,6 +148,7 @@ Bug #2879: Editor: entered value of field "Buys *" is not saved for a creature Bug #2880: OpenMW & OpenMW-CS: having a scale value of 0.000 makes the game laggy Bug #2882: Freeze when entering cell "Guild of Fighters (Ald'ruhn)" after dropping some items inside + Bug #2883: game not playable if mod providing a spell is removed but the list of known spells still contains it Bug #2884: NPC chats about wrong player race Bug #2886: Adding custom races breaks existing numbering of PcRace Bug #2888: Editor: value entered in "AI Wander Idle" is not kept @@ -166,6 +167,7 @@ Bug #2944: Spell chance for power to show as 0 on hud when used Bug #2953: Editor: rightclick in an empty place in the menu bar shows an unnamed checkbox Bug #2956: Editor: freezes while editing Filter + Bug #2959: space character in field enchantment (of an amulet) prevents rendering of surroundings Bug #2962: OpenMW: Assertion `it != invStore.end()' failed Bug #2964: Recursive script execution can corrupt script runtime data Bug #2973: Editor: placing a chest in the game world and activating it heavily blurrs the character portrait @@ -211,9 +213,7 @@ Feature #2751: Character preview optimization Feature #2804: Editor: Merge Tool Feature #2818: Editor: allow copying a record ID to the clipboard - Feature #2883: game not playable if mod providing a spell is removed but the list of known spells still contains it Feature #2946: Editor: add script line number in results of search - Feature #2959: space character in field enchantment (of an amulet) prevents rendering of surroundings Feature #2963: Editor: Mouse button bindings in 3D scene Feature #2983: Sun Glare fader Feature #2999: Scaling of journal and books From 35f5be680bb877bd4c8ad9ae48c1126fb25a6d69 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 9 Nov 2015 16:52:39 +0100 Subject: [PATCH 2395/3725] Support for NiVisController on trishape nodes --- components/nifosg/nifloader.cpp | 56 ++++++++++++++++++++++----------- 1 file changed, 37 insertions(+), 19 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 2b73f779f..a8865e7d2 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -609,15 +609,20 @@ namespace NifOsg } else if (ctrl->recType == Nif::RC_NiVisController) { - const Nif::NiVisController* visctrl = static_cast(ctrl.getPtr()); - - osg::ref_ptr callback(new VisController(visctrl->data.getPtr())); - setupController(visctrl, callback, animflags); - transformNode->addUpdateCallback(callback); + handleVisController(static_cast(ctrl.getPtr()), transformNode, animflags); } + else + std::cerr << "Unhandled controller " << ctrl->recName << " on node " << nifNode->recIndex << " in " << mFilename << std::endl; } } + void handleVisController(const Nif::NiVisController* visctrl, osg::Node* node, int animflags) + { + osg::ref_ptr callback(new VisController(visctrl->data.getPtr())); + setupController(visctrl, callback, animflags); + node->addUpdateCallback(callback); + } + void handleMaterialControllers(const Nif::Property *materialProperty, SceneUtil::CompositeStateSetUpdater* composite, int animflags) { for (Nif::ControllerPtr ctrl = materialProperty->controller; !ctrl.empty(); ctrl = ctrl->next) @@ -942,28 +947,31 @@ namespace NifOsg void handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::vector& boundTextures, int animflags) { + osg::ref_ptr geode (new osg::Geode); + osg::ref_ptr geometry; - if(!triShape->controller.empty()) + for (Nif::ControllerPtr ctrl = triShape->controller; !ctrl.empty(); ctrl = ctrl->next) { - Nif::ControllerPtr ctrl = triShape->controller; - do { - if(ctrl->recType == Nif::RC_NiGeomMorpherController && ctrl->flags & Nif::NiNode::ControllerFlag_Active) - { - geometry = handleMorphGeometry(static_cast(ctrl.getPtr())); + if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active)) + continue; + if(ctrl->recType == Nif::RC_NiGeomMorpherController) + { + geometry = handleMorphGeometry(static_cast(ctrl.getPtr())); - osg::ref_ptr morphctrl = new GeomMorpherController( - static_cast(ctrl.getPtr())->data.getPtr()); - setupController(ctrl.getPtr(), morphctrl, animflags); - geometry->setUpdateCallback(morphctrl); - break; - } - } while(!(ctrl=ctrl->next).empty()); + osg::ref_ptr morphctrl = new GeomMorpherController( + static_cast(ctrl.getPtr())->data.getPtr()); + setupController(ctrl.getPtr(), morphctrl, animflags); + geometry->setUpdateCallback(morphctrl); + } + else if (ctrl->recType == Nif::RC_NiVisController) + { + handleVisController(static_cast(ctrl.getPtr()), geode, animflags); + } } if (!geometry.get()) geometry = new osg::Geometry; - osg::ref_ptr geode (new osg::Geode); triShapeToGeometry(triShape, geometry, parentNode, composite, boundTextures, animflags); geode->addDrawable(geometry); @@ -1043,6 +1051,16 @@ namespace NifOsg { osg::ref_ptr geode (new osg::Geode); + for (Nif::ControllerPtr ctrl = triShape->controller; !ctrl.empty(); ctrl = ctrl->next) + { + if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active)) + continue; + if (ctrl->recType == Nif::RC_NiVisController) + { + handleVisController(static_cast(ctrl.getPtr()), geode, animflags); + } + } + osg::ref_ptr geometry (new osg::Geometry); triShapeToGeometry(triShape, geometry, parentNode, composite, boundTextures, animflags); From 64abdbabe3f2b169ebcc9932dc910512592dcae7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 9 Nov 2015 17:00:33 +0100 Subject: [PATCH 2396/3725] Small refactor of controllers handling, print warning messages for unhandled controllers --- components/nifosg/nifloader.cpp | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index a8865e7d2..49bc7b0fb 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -536,7 +536,7 @@ namespace NifOsg handleSkinnedTriShape(triShape, node, composite, boundTextures, animflags); if (!nifNode->controller.empty()) - handleMeshControllers(nifNode, composite, boundTextures, animflags); + handleMeshControllers(nifNode, node, composite, boundTextures, animflags); } if(nifNode->recType == Nif::RC_NiAutoNormalParticles || nifNode->recType == Nif::RC_NiRotatingParticles) @@ -570,7 +570,7 @@ namespace NifOsg return node; } - void handleMeshControllers(const Nif::Node *nifNode, SceneUtil::CompositeStateSetUpdater* composite, const std::vector &boundTextures, int animflags) + void handleMeshControllers(const Nif::Node *nifNode, osg::Node* node, SceneUtil::CompositeStateSetUpdater* composite, const std::vector &boundTextures, int animflags) { for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next) { @@ -587,6 +587,14 @@ namespace NifOsg setupController(uvctrl, ctrl, animflags); composite->addController(ctrl); } + else if (ctrl->recType == Nif::RC_NiVisController) + { + handleVisController(static_cast(ctrl.getPtr()), node, animflags); + } + else if(ctrl->recType == Nif::RC_NiGeomMorpherController) + {} // handled in handleTriShape + else + std::cerr << "Unhandled controller " << ctrl->recName << " on node " << nifNode->recIndex << " in " << mFilename << std::endl; } } @@ -815,6 +823,8 @@ namespace NifOsg continue; if(ctrl->recType == Nif::RC_NiParticleSystemController || ctrl->recType == Nif::RC_NiBSPArrayController) partctrl = static_cast(ctrl.getPtr()); + else + std::cerr << "Unhandled controller " << ctrl->recName << " on node " << nifNode->recIndex << " in " << mFilename << std::endl; } if (!partctrl) { @@ -962,10 +972,7 @@ namespace NifOsg static_cast(ctrl.getPtr())->data.getPtr()); setupController(ctrl.getPtr(), morphctrl, animflags); geometry->setUpdateCallback(morphctrl); - } - else if (ctrl->recType == Nif::RC_NiVisController) - { - handleVisController(static_cast(ctrl.getPtr()), geode, animflags); + break; } } @@ -1051,16 +1058,6 @@ namespace NifOsg { osg::ref_ptr geode (new osg::Geode); - for (Nif::ControllerPtr ctrl = triShape->controller; !ctrl.empty(); ctrl = ctrl->next) - { - if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active)) - continue; - if (ctrl->recType == Nif::RC_NiVisController) - { - handleVisController(static_cast(ctrl.getPtr()), geode, animflags); - } - } - osg::ref_ptr geometry (new osg::Geometry); triShapeToGeometry(triShape, geometry, parentNode, composite, boundTextures, animflags); From 1b52749ae1930e5322e19066a2513d8b9dccfece Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 9 Nov 2015 17:30:11 +0100 Subject: [PATCH 2397/3725] Adjust third person camera height based on character height --- apps/openmw/mwrender/camera.cpp | 13 ++++++++++--- apps/openmw/mwrender/camera.hpp | 3 +++ apps/openmw/mwrender/renderingmanager.cpp | 3 +++ 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/camera.cpp b/apps/openmw/mwrender/camera.cpp index fb6573d65..ea8c60bf3 100644 --- a/apps/openmw/mwrender/camera.cpp +++ b/apps/openmw/mwrender/camera.cpp @@ -42,7 +42,8 @@ namespace MWRender { Camera::Camera (osg::Camera* camera) - : mCamera(camera), + : mHeightScale(1.f), + mCamera(camera), mAnimation(NULL), mFirstPersonView(true), mPreviewMode(false), @@ -93,7 +94,7 @@ namespace MWRender osg::Vec3d position = worldMat.getTrans(); if (!isFirstPerson()) - position.z() += mHeight; + position.z() += mHeight * mHeightScale; return position; } @@ -372,11 +373,17 @@ namespace MWRender mTrackingNode = mAnimation->getNode("Camera"); if (!mTrackingNode) mTrackingNode = mAnimation->getNode("Head"); + mHeightScale = 1.f; } else { mAnimation->setViewMode(NpcAnimation::VM_Normal); - mTrackingNode = mTrackingPtr.getRefData().getBaseNode(); + osg::PositionAttitudeTransform* transform = mTrackingPtr.getRefData().getBaseNode(); + mTrackingNode = transform; + if (transform) + mHeightScale = mTrackingPtr.getRefData().getBaseNode()->getScale().z(); + else + mHeightScale = 1.f; } rotateCamera(getPitch(), getYaw(), false); } diff --git a/apps/openmw/mwrender/camera.hpp b/apps/openmw/mwrender/camera.hpp index a655e1c1f..899fc9447 100644 --- a/apps/openmw/mwrender/camera.hpp +++ b/apps/openmw/mwrender/camera.hpp @@ -29,6 +29,7 @@ namespace MWRender MWWorld::Ptr mTrackingPtr; osg::ref_ptr mTrackingNode; + float mHeightScale; osg::ref_ptr mCamera; @@ -97,6 +98,8 @@ namespace MWRender bool isFirstPerson() const { return !(mVanity.enabled || mPreviewMode || !mFirstPersonView); } + void updateScale(); + void processViewChange(); void update(float duration, bool paused=false); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 45c04ceec..27ea7ebed 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -439,6 +439,9 @@ namespace MWRender void RenderingManager::scaleObject(const MWWorld::Ptr &ptr, const osg::Vec3f &scale) { ptr.getRefData().getBaseNode()->setScale(scale); + + if (ptr == mCamera->getTrackingPtr()) // update height of camera + mCamera->processViewChange(); } void RenderingManager::removeObject(const MWWorld::Ptr &ptr) From 1200ff91866ae430d9e5d3e4d1ccff3d133e1ba6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 9 Nov 2015 18:31:41 +0100 Subject: [PATCH 2398/3725] RigGeometry: fix incorrect bounding box in the first frame The default computeBound() was overriding the manually set bounding box. --- components/sceneutil/riggeometry.cpp | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/components/sceneutil/riggeometry.cpp b/components/sceneutil/riggeometry.cpp index 8eb08f546..ac29ee3e8 100644 --- a/components/sceneutil/riggeometry.cpp +++ b/components/sceneutil/riggeometry.cpp @@ -2,9 +2,9 @@ #include #include - #include +#include #include #include "skeleton.hpp" @@ -58,6 +58,14 @@ public: } }; +// We can't compute the bounds without a NodeVisitor, since we need the current geomToSkelMatrix. +// So we return nothing. Bounds are updated every frame in the UpdateCallback. +class DummyComputeBoundCallback : public osg::Drawable::ComputeBoundingBoxCallback +{ +public: + virtual osg::BoundingBox computeBound(const osg::Drawable&) const { return osg::BoundingBox(); } +}; + RigGeometry::RigGeometry() : mSkeleton(NULL) , mLastFrameNumber(0) @@ -66,6 +74,7 @@ RigGeometry::RigGeometry() setCullCallback(new UpdateRigGeometry); setUpdateCallback(new UpdateRigBounds); setSupportsDisplayList(false); + setComputeBoundingBoxCallback(new DummyComputeBoundCallback); } RigGeometry::RigGeometry(const RigGeometry ©, const osg::CopyOp ©op) @@ -278,6 +287,12 @@ void RigGeometry::updateBounds(osg::NodeVisitor *nv) } _boundingBox = box; + _boundingBoxComputed = true; +#if OSG_MIN_VERSION_REQUIRED(3,3,3) + // in OSG 3.3.3 and up Drawable inherits from Node, so has a bounding sphere as well. + _boundingSphere = osg::BoundingSphere(_boundingBox); + _boundingSphereComputed = true; +#endif for (unsigned int i=0; idirtyBound(); } From bd8332d2b01ab600b6405c7d6a0b73cf7746e8a1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 9 Nov 2015 18:57:17 +0100 Subject: [PATCH 2399/3725] Remove default copyop argument for nodecallback copy constructors Works around a compiler warning with OSG 3.4: warning: base class 'class osg::Callback' should be explicitly initialized in the copy constructor [-Wextra] With no default argument for osg::CopyOp&, the compiler no longer sees the function as a real copy constructor and stops warning about the missing virtual initializations. We don't care about this warning because there is nothing interesting to initialize in the osg::NodeCallback base anyway. A proper fix for the warning would require to inserting OSG_VERSION conditional compiling all over the place, that is as long as we are still supporting OSG 3.2. --- components/nifosg/controller.hpp | 2 +- components/nifosg/particle.hpp | 2 +- components/sceneutil/lightmanager.hpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index 58870317e..d0c6d1de3 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -146,7 +146,7 @@ namespace NifOsg { public: UVController(); - UVController(const UVController&,const osg::CopyOp& = osg::CopyOp::SHALLOW_COPY); + UVController(const UVController&,const osg::CopyOp&); UVController(const Nif::NiUVData *data, std::set textureUnits); META_Object(NifOsg,UVController) diff --git a/components/nifosg/particle.hpp b/components/nifosg/particle.hpp index c7d5d585d..043489865 100644 --- a/components/nifosg/particle.hpp +++ b/components/nifosg/particle.hpp @@ -60,7 +60,7 @@ namespace NifOsg InverseWorldMatrix() { } - InverseWorldMatrix(const InverseWorldMatrix& copy, const osg::CopyOp& op = osg::CopyOp::SHALLOW_COPY) + InverseWorldMatrix(const InverseWorldMatrix& copy, const osg::CopyOp& op) : osg::Object(), osg::NodeCallback() { } diff --git a/components/sceneutil/lightmanager.hpp b/components/sceneutil/lightmanager.hpp index e62dc00e5..bcdcdf7dc 100644 --- a/components/sceneutil/lightmanager.hpp +++ b/components/sceneutil/lightmanager.hpp @@ -121,7 +121,7 @@ namespace SceneUtil : mLightManager(NULL) , mLastFrameNumber(0) {} - LightListCallback(const LightListCallback& copy, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY) + LightListCallback(const LightListCallback& copy, const osg::CopyOp& copyop) : osg::Object(copy, copyop), osg::NodeCallback(copy, copyop) , mLightManager(copy.mLightManager) , mLastFrameNumber(0) From 801dc8eee381e30c64a52d8c27513d3c284b940a Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 9 Nov 2015 20:17:21 +0100 Subject: [PATCH 2400/3725] ObstacleCheck: fix weird distance calculation --- apps/openmw/mwmechanics/obstacle.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/obstacle.cpp b/apps/openmw/mwmechanics/obstacle.cpp index 53f12a982..b5c0dedd4 100644 --- a/apps/openmw/mwmechanics/obstacle.cpp +++ b/apps/openmw/mwmechanics/obstacle.cpp @@ -126,8 +126,8 @@ namespace MWMechanics if(mDistSameSpot == -1) mDistSameSpot = DIST_SAME_SPOT * (cls.getSpeed(actor) / 150); - bool samePosition = (std::abs(pos.pos[0] - mPrevX) < mDistSameSpot) && - (std::abs(pos.pos[1] - mPrevY) < mDistSameSpot); + bool samePosition = (osg::Vec2f(pos.pos[0], pos.pos[1]) - osg::Vec2f(mPrevX, mPrevY)).length2() < mDistSameSpot * mDistSameSpot; + // update position mPrevX = pos.pos[0]; mPrevY = pos.pos[1]; From caa523a9592c80abdacc102bc6a5c9d94b15af25 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 9 Nov 2015 20:21:25 +0100 Subject: [PATCH 2401/3725] ObstacleCheck: fix the framerate not being taken into account --- apps/openmw/mwmechanics/obstacle.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwmechanics/obstacle.cpp b/apps/openmw/mwmechanics/obstacle.cpp index b5c0dedd4..078c31ac0 100644 --- a/apps/openmw/mwmechanics/obstacle.cpp +++ b/apps/openmw/mwmechanics/obstacle.cpp @@ -11,7 +11,7 @@ namespace MWMechanics { // NOTE: determined empirically but probably need further tweaking - static const float DIST_SAME_SPOT = 1.8f; + static const float DIST_SAME_SPOT = 0.72f; static const float DURATION_SAME_SPOT = 1.0f; static const float DURATION_TO_EVADE = 0.4f; @@ -114,19 +114,22 @@ namespace MWMechanics * t = how long before considered stuck * u = how long to move sideways * - * DIST_SAME_SPOT is calibrated for movement speed of around 150. - * A rat has walking speed of around 30, so we need to adjust for - * that. */ bool ObstacleCheck::check(const MWWorld::Ptr& actor, float duration) { const MWWorld::Class& cls = actor.getClass(); ESM::Position pos = actor.getRefData().getPosition(); + // actors can move at most 60 fps (the physics framerate). + // the max() can be removed if we implement physics interpolation. + float movementDuration = std::max(1/60.f, duration); + if(mDistSameSpot == -1) - mDistSameSpot = DIST_SAME_SPOT * (cls.getSpeed(actor) / 150); + mDistSameSpot = DIST_SAME_SPOT * cls.getSpeed(actor); + + float distSameSpot = mDistSameSpot * movementDuration; - bool samePosition = (osg::Vec2f(pos.pos[0], pos.pos[1]) - osg::Vec2f(mPrevX, mPrevY)).length2() < mDistSameSpot * mDistSameSpot; + bool samePosition = (osg::Vec2f(pos.pos[0], pos.pos[1]) - osg::Vec2f(mPrevX, mPrevY)).length2() < distSameSpot * distSameSpot; // update position mPrevX = pos.pos[0]; From d233bc483d195afbbacbad7b6b2c940bace024b6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 9 Nov 2015 20:26:18 +0100 Subject: [PATCH 2402/3725] ObstacleCheck: fix evasion issue The check if (samePosition... would not work as intended because actors do not move in every frame when the framerate is higher than the physics framerate. In that case the actor would change its evasion direction almost every frame. --- apps/openmw/mwmechanics/obstacle.cpp | 13 +++++-------- apps/openmw/mwmechanics/obstacle.hpp | 2 +- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwmechanics/obstacle.cpp b/apps/openmw/mwmechanics/obstacle.cpp index 078c31ac0..8c9ab3380 100644 --- a/apps/openmw/mwmechanics/obstacle.cpp +++ b/apps/openmw/mwmechanics/obstacle.cpp @@ -163,13 +163,13 @@ namespace MWMechanics { mStuckDuration = 0; mWalkState = State_Evade; + chooseEvasionDirection(); } } } /* FALL THROUGH */ case State_Evade: { - chooseEvasionDirection(samePosition); mEvadeDuration += duration; if(mEvadeDuration < DURATION_TO_EVADE) return true; @@ -191,16 +191,13 @@ namespace MWMechanics actorMovement.mPosition[1] = evadeDirections[mEvadeDirectionIndex][1]; } - void ObstacleCheck::chooseEvasionDirection(bool samePosition) + void ObstacleCheck::chooseEvasionDirection() { // change direction if attempt didn't work - if (samePosition && (0 < mEvadeDuration)) + ++mEvadeDirectionIndex; + if (mEvadeDirectionIndex == NUM_EVADE_DIRECTIONS) { - ++mEvadeDirectionIndex; - if (mEvadeDirectionIndex == NUM_EVADE_DIRECTIONS) - { - mEvadeDirectionIndex = 0; - } + mEvadeDirectionIndex = 0; } } diff --git a/apps/openmw/mwmechanics/obstacle.hpp b/apps/openmw/mwmechanics/obstacle.hpp index ecff00a5c..6b442f5a5 100644 --- a/apps/openmw/mwmechanics/obstacle.hpp +++ b/apps/openmw/mwmechanics/obstacle.hpp @@ -65,7 +65,7 @@ namespace MWMechanics float mDistSameSpot; // take account of actor's speed int mEvadeDirectionIndex; - void chooseEvasionDirection(bool samePosition); + void chooseEvasionDirection(); }; } From 3c338b9da994b0c0d2d222e3ef08ab1cf44daa6e Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 9 Nov 2015 20:31:40 +0100 Subject: [PATCH 2403/3725] ObstacleCheck: tweak the stuck detection parameters The netch_betty wander animation starts up so slowly that the creature thought it was stuck, even though it's not. --- apps/openmw/mwmechanics/obstacle.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/obstacle.cpp b/apps/openmw/mwmechanics/obstacle.cpp index 8c9ab3380..7def96bef 100644 --- a/apps/openmw/mwmechanics/obstacle.cpp +++ b/apps/openmw/mwmechanics/obstacle.cpp @@ -11,8 +11,8 @@ namespace MWMechanics { // NOTE: determined empirically but probably need further tweaking - static const float DIST_SAME_SPOT = 0.72f; - static const float DURATION_SAME_SPOT = 1.0f; + static const float DIST_SAME_SPOT = 0.5f; + static const float DURATION_SAME_SPOT = 1.5f; static const float DURATION_TO_EVADE = 0.4f; const float ObstacleCheck::evadeDirections[NUM_EVADE_DIRECTIONS][2] = From 637cd3a628e365899752a7a95e865e21fd854fa3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 10 Nov 2015 01:01:41 +0100 Subject: [PATCH 2404/3725] Adjust the FirstPersonNeckController to follow the camera with a reduced factor (Fixes #1784) --- apps/openmw/mwmechanics/character.cpp | 2 ++ apps/openmw/mwrender/animation.hpp | 1 + apps/openmw/mwrender/npcanimation.cpp | 18 ++++++++++++++++-- apps/openmw/mwrender/npcanimation.hpp | 7 +++++++ 4 files changed, 26 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index c9b248984..129206f51 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1479,6 +1479,8 @@ bool CharacterController::updateWeaponState() } } + mAnimation->setAccurateAiming(mUpperBodyState > UpperCharState_WeapEquiped); + return forcestateupdate; } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 1e46cc71a..5aaa4071b 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -439,6 +439,7 @@ public: virtual void setHeadYaw(float yawRadians); virtual float getHeadPitch() const; virtual float getHeadYaw() const; + virtual void setAccurateAiming(bool enabled) {} private: Animation(const Animation&); diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 0b3838a33..815671266 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -281,7 +281,9 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, osg::ref_ptr par mShowWeapons(false), mShowCarriedLeft(true), mNpcType(Type_Normal), - mSoundsDisabled(disableSounds) + mSoundsDisabled(disableSounds), + mAccurateAiming(false), + mAimingFactor(0.f) { mNpc = mPtr.get()->mBase; @@ -726,7 +728,14 @@ osg::Vec3f NpcAnimation::runAnimation(float timepassed) if (mFirstPersonNeckController) { - mFirstPersonNeckController->setRotate(osg::Quat(mPtr.getRefData().getPosition().rot[0], osg::Vec3f(-1,0,0))); + if (mAccurateAiming) + mAimingFactor = 1.f; + else + mAimingFactor = std::max(0.f, mAimingFactor - timepassed * 0.5f); + + float rotateFactor = 0.75f + 0.25f * mAimingFactor; + + mFirstPersonNeckController->setRotate(osg::Quat(mPtr.getRefData().getPosition().rot[0] * rotateFactor, osg::Vec3f(-1,0,0))); mFirstPersonNeckController->setOffset(mFirstPersonOffset); } @@ -1072,4 +1081,9 @@ void NpcAnimation::updatePtr(const MWWorld::Ptr &updated) mHeadAnimationTime->updatePtr(updated); } +void NpcAnimation::setAccurateAiming(bool enabled) +{ + mAccurateAiming = enabled; +} + } diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index b4272226d..2289703c8 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -67,6 +67,9 @@ private: bool mSoundsDisabled; + bool mAccurateAiming; + float mAimingFactor; + void updateNpcBase(); PartHolderPtr insertBoundedPart(const std::string &model, const std::string &bonename, @@ -104,6 +107,10 @@ public: virtual void enableHeadAnimation(bool enable); + /// 1: the first person meshes follow the camera's rotation completely + /// 0: the first person meshes follow the camera with a reduced factor, so you can look down at your own hands + virtual void setAccurateAiming(bool enabled); + virtual void setWeaponGroup(const std::string& group); virtual osg::Vec3f runAnimation(float timepassed); From 37158df339d1cc5b760e54f9e260ce565ab0915e Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Tue, 10 Nov 2015 14:59:26 +0100 Subject: [PATCH 2405/3725] Update scalinglayer.cpp MSVC Explicitly requires for std::min and/or max --- components/myguiplatform/scalinglayer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/components/myguiplatform/scalinglayer.cpp b/components/myguiplatform/scalinglayer.cpp index 19ae10841..ee9de349e 100644 --- a/components/myguiplatform/scalinglayer.cpp +++ b/components/myguiplatform/scalinglayer.cpp @@ -1,6 +1,7 @@ #include "scalinglayer.hpp" #include +#include namespace osgMyGUI { From 91583fc027024e1cb80eed63d8a0a24f6eaa8ff0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 10 Nov 2015 17:00:33 +0100 Subject: [PATCH 2406/3725] Fix MWRender::Mask_ParticleSystem --- apps/openmw/mwrender/renderingmanager.cpp | 2 ++ components/resource/scenemanager.cpp | 17 +++++++++++++---- components/resource/scenemanager.hpp | 5 +++++ 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 27ea7ebed..e0a0c75c6 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -137,6 +137,8 @@ namespace MWRender , mUnderwaterIndoorFog(fallback->getFallbackFloat("Water_UnderwaterIndoorFog")) , mNightEyeFactor(0.f) { + resourceSystem->getSceneManager()->setParticleSystemMask(MWRender::Mask_ParticleSystem); + osg::ref_ptr lightRoot = new SceneUtil::LightManager; mLightRoot = lightRoot; lightRoot->setStartLight(1); diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index 08fa7bc9b..f2840574b 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -25,8 +25,10 @@ namespace class InitWorldSpaceParticlesVisitor : public osg::NodeVisitor { public: - InitWorldSpaceParticlesVisitor() + /// @param mask The node mask to set on ParticleSystem nodes. + InitWorldSpaceParticlesVisitor(unsigned int mask) : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) + , mMask(mask) { } @@ -47,7 +49,7 @@ namespace if (geode->getNumParents() && geode->getParent(0)->getNumParents()) transformInitialParticles(partsys, geode->getParent(0)->getParent(0)); } - geode->setNodeMask((1<<10)); //MWRender::Mask_ParticleSystem + geode->setNodeMask(mMask); } } } @@ -74,8 +76,9 @@ namespace box.expandBy(sphere); partsys->setInitialBound(box); } + private: + unsigned int mMask; }; - } namespace Resource @@ -84,6 +87,7 @@ namespace Resource SceneManager::SceneManager(const VFS::Manager *vfs, Resource::TextureManager* textureManager) : mVFS(vfs) , mTextureManager(textureManager) + , mParticleSystemMask(~0u) { } @@ -183,7 +187,7 @@ namespace Resource void SceneManager::notifyAttached(osg::Node *node) const { - InitWorldSpaceParticlesVisitor visitor; + InitWorldSpaceParticlesVisitor visitor (mParticleSystemMask); node->accept(visitor); } @@ -197,4 +201,9 @@ namespace Resource return mTextureManager; } + void SceneManager::setParticleSystemMask(unsigned int mask) + { + mParticleSystemMask = mask; + } + } diff --git a/components/resource/scenemanager.hpp b/components/resource/scenemanager.hpp index 168247a15..5ecb875ac 100644 --- a/components/resource/scenemanager.hpp +++ b/components/resource/scenemanager.hpp @@ -73,12 +73,17 @@ namespace Resource Resource::TextureManager* getTextureManager(); + /// @param mask The node mask to apply to loaded particle system nodes. + void setParticleSystemMask(unsigned int mask); + private: const VFS::Manager* mVFS; Resource::TextureManager* mTextureManager; osg::ref_ptr mIncrementalCompileOperation; + unsigned int mParticleSystemMask; + // observer_ptr? typedef std::map > Index; Index mIndex; From 35459f20d54602d6c465863cb7975e183c4607fa Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 10 Nov 2015 17:19:51 +0100 Subject: [PATCH 2407/3725] Refactor lighting mask --- apps/openmw/mwrender/animation.cpp | 1 + apps/openmw/mwrender/renderingmanager.cpp | 3 ++- apps/openmw/mwrender/vismask.hpp | 17 +++++++-------- apps/openmw/mwrender/water.cpp | 4 ++-- components/sceneutil/lightmanager.cpp | 25 ++++++++++++++++------- components/sceneutil/lightmanager.hpp | 13 +++++++++--- 6 files changed, 42 insertions(+), 21 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 06065c566..c3ddbf297 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1066,6 +1066,7 @@ namespace MWRender osg::ref_ptr lightSource = new SceneUtil::LightSource; osg::Light* light = new osg::Light; lightSource->setLight(light); + lightSource->setNodeMask(Mask_Lighting); const MWWorld::Fallback* fallback = MWBase::Environment::get().getWorld()->getFallback(); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index e0a0c75c6..c55d11795 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -140,6 +140,7 @@ namespace MWRender resourceSystem->getSceneManager()->setParticleSystemMask(MWRender::Mask_ParticleSystem); osg::ref_ptr lightRoot = new SceneUtil::LightManager; + lightRoot->setLightingMask(Mask_Lighting); mLightRoot = lightRoot; lightRoot->setStartLight(1); @@ -165,7 +166,7 @@ namespace MWRender mViewer->setLightingMode(osgViewer::View::NO_LIGHT); osg::ref_ptr source = new osg::LightSource; - source->setNodeMask(SceneUtil::Mask_Lit); + source->setNodeMask(Mask_Lighting); mSunLight = new osg::Light; source->setLight(mSunLight); mSunLight->setDiffuse(osg::Vec4f(0,0,0,1)); diff --git a/apps/openmw/mwrender/vismask.hpp b/apps/openmw/mwrender/vismask.hpp index a26bde1d1..dd6e85e2c 100644 --- a/apps/openmw/mwrender/vismask.hpp +++ b/apps/openmw/mwrender/vismask.hpp @@ -15,16 +15,16 @@ namespace MWRender Mask_Actor = (1<<3), Mask_Player = (1<<4), Mask_Sky = (1<<5), - Mask_Water = (1<<6), - Mask_Terrain = (1<<7), - Mask_FirstPerson = (1<<8), + Mask_Water = (1<<6), // choose Water or SimpleWater depending on detail required + Mask_SimpleWater = (1<<7), + Mask_Terrain = (1<<8), + Mask_FirstPerson = (1<<9), // child of Sky - Mask_Sun = (1<<9), - Mask_WeatherParticles = (1<<10), + Mask_Sun = (1<<10), + Mask_WeatherParticles = (1<<11), // child of Water - Mask_SimpleWater = (1<<11), // top level masks Mask_Scene = (1<<12), @@ -34,9 +34,10 @@ namespace MWRender Mask_ParticleSystem = (1<<14), // Set on cameras within the main scene graph - Mask_RenderToTexture = (1<<15) + Mask_RenderToTexture = (1<<15), - // reserved: (1<<16) for SceneUtil::Mask_Lit + // Set on a camera's cull mask to enable the LightManager + Mask_Lighting = (1<<16) }; } diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 80023ecda..e93060f7c 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -302,7 +302,7 @@ public: setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT); setReferenceFrame(osg::Camera::RELATIVE_RF); - setCullMask(Mask_Effect|Mask_Scene|Mask_Terrain|Mask_Actor|Mask_ParticleSystem|Mask_Sky|Mask_Sun|Mask_Player|(1<<16)); + setCullMask(Mask_Effect|Mask_Scene|Mask_Terrain|Mask_Actor|Mask_ParticleSystem|Mask_Sky|Mask_Sun|Mask_Player|Mask_Lighting); setNodeMask(Mask_RenderToTexture); setViewport(0, 0, rttSize, rttSize); @@ -378,7 +378,7 @@ public: setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT); setReferenceFrame(osg::Camera::RELATIVE_RF); - setCullMask(Mask_Effect|Mask_Scene|Mask_Terrain|Mask_Actor|Mask_ParticleSystem|Mask_Sky|Mask_Player|(1<<16)); + setCullMask(Mask_Effect|Mask_Scene|Mask_Terrain|Mask_Actor|Mask_ParticleSystem|Mask_Sky|Mask_Player|Mask_Lighting); setNodeMask(Mask_RenderToTexture); unsigned int rttSize = Settings::Manager::getInt("rtt size", "Water"); diff --git a/components/sceneutil/lightmanager.cpp b/components/sceneutil/lightmanager.cpp index 1e1d04cf5..dc6da73a6 100644 --- a/components/sceneutil/lightmanager.cpp +++ b/components/sceneutil/lightmanager.cpp @@ -131,6 +131,7 @@ namespace SceneUtil LightManager::LightManager() : mStartLight(0) + , mLightingMask(~0u) { setUpdateCallback(new LightManagerUpdateCallback); } @@ -138,10 +139,21 @@ namespace SceneUtil LightManager::LightManager(const LightManager ©, const osg::CopyOp ©op) : osg::Group(copy, copyop) , mStartLight(copy.mStartLight) + , mLightingMask(copy.mLightingMask) { } + void LightManager::setLightingMask(unsigned int mask) + { + mLightingMask = mask; + } + + unsigned int LightManager::getLightingMask() const + { + return mLightingMask; + } + void LightManager::update() { mLights.clear(); @@ -237,7 +249,6 @@ namespace SceneUtil LightSource::LightSource() : mRadius(0.f) { - setNodeMask(Mask_Lit); setUpdateCallback(new CollectLightCallback); mId = sLightId++; } @@ -260,12 +271,6 @@ namespace SceneUtil { osgUtil::CullVisitor* cv = static_cast(nv); - if (!(cv->getCurrentCamera()->getCullMask()&Mask_Lit)) - { - traverse(node, nv); - return; - } - if (!mLightManager) { mLightManager = findLightManager(nv->getNodePath()); @@ -276,6 +281,12 @@ namespace SceneUtil } } + if (!(cv->getCurrentCamera()->getCullMask() & mLightManager->getLightingMask())) + { + traverse(node, nv); + return; + } + // Possible optimizations: // - cull list of lights by the camera frustum // - organize lights in a quad tree diff --git a/components/sceneutil/lightmanager.hpp b/components/sceneutil/lightmanager.hpp index bcdcdf7dc..27ee1cdaa 100644 --- a/components/sceneutil/lightmanager.hpp +++ b/components/sceneutil/lightmanager.hpp @@ -9,9 +9,6 @@ namespace SceneUtil { - // This mask should be included in the Cull and Update visitor's traversal mask if lighting is desired. - const int Mask_Lit = (1<<16); - /// LightSource managed by a LightManager. class LightSource : public osg::Node { @@ -68,6 +65,14 @@ namespace SceneUtil LightManager(const LightManager& copy, const osg::CopyOp& copyop); + /// @param mask This mask is compared with the current Camera's cull mask to determine if lighting is desired. + /// By default, it's ~0u i.e. always on. + /// If you have some views that do not require lighting, then set the Camera's cull mask to not include + /// the lightingMask for a much faster cull and rendering. + void setLightingMask (unsigned int mask); + + unsigned int getLightingMask() const; + // Called automatically by the UpdateCallback void update(); @@ -111,6 +116,8 @@ namespace SceneUtil LightStateSetMap mStateSetCache; int mStartLight; + + unsigned int mLightingMask; }; /// @note Not thread safe for CullThreadPerCamera threading mode. From f1ac408f352fed6c5520b6bae1b6c120ff4873bb Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 10 Nov 2015 18:21:56 +0100 Subject: [PATCH 2408/3725] Place Drawables directly in the scene graph when built with OSG 3.4 OSG 3.4 adds the ability to place Drawables directly in the scene graph, without a Geode decorating them. Leveraging this should give a small performance boost, because the redundant Geodes increase culling overhead. There is still an oustanding issue with the RemoveDrawableVisitor no longer working correctly, because Drawables can have multiple parents. --- apps/openmw/mwrender/animation.cpp | 22 ++++++++++++ apps/openmw/mwrender/objects.cpp | 9 +++++ apps/openmw/mwrender/sky.cpp | 47 ++++++++++++------------ components/nifosg/nifloader.cpp | 53 +++++++++++++++++++++------- components/resource/scenemanager.cpp | 48 +++++++++++++++++-------- components/sceneutil/visitor.cpp | 12 ++++--- components/sceneutil/visitor.hpp | 1 + 7 files changed, 137 insertions(+), 55 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index c3ddbf297..c2cbb4627 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include @@ -196,10 +197,18 @@ namespace traverse(node); } +#if OSG_VERSION_GREATER_OR_EQUAL(3,3,3) + virtual void apply(osg::Drawable& drw) + { + mToRemove.push_back(&drw); + } +#endif + void remove() { for (std::vector::iterator it = mToRemove.begin(); it != mToRemove.end(); ++it) { + // FIXME: a Drawable might have more than one parent osg::Node* node = *it; if (node->getNumParents()) node->getParent(0)->removeChild(node); @@ -219,6 +228,18 @@ namespace } virtual void apply(osg::Geode &node) + { + applyImpl(node); + } + +#if OSG_VERSION_GREATER_OR_EQUAL(3,3,3) + virtual void apply(osg::Drawable& drw) + { + applyImpl(drw); + } +#endif + + void applyImpl(osg::Node& node) { const std::string toFind = "tri bip"; if (Misc::StringUtils::ciCompareLen(node.getName(), toFind, toFind.size()) == 0) @@ -232,6 +253,7 @@ namespace { for (std::vector::iterator it = mToRemove.begin(); it != mToRemove.end(); ++it) { + // FIXME: a Drawable might have more than one parent osg::Node* node = *it; if (node->getNumParents()) node->getParent(0)->removeChild(node); diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index bdefdcafa..9f4fe2de2 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -54,11 +55,19 @@ namespace for (std::vector::iterator it = partsysVector.begin(); it != partsysVector.end(); ++it) geode.removeDrawable(*it); } +#if OSG_VERSION_GREATER_OR_EQUAL(3,3,3) + virtual void apply(osg::Drawable& drw) + { + if (osgParticle::ParticleSystem* partsys = dynamic_cast(&drw)) + mToRemove.push_back(partsys); + } +#endif void remove() { for (std::vector >::iterator it = mToRemove.begin(); it != mToRemove.end(); ++it) { + // FIXME: a Drawable might have more than one parent osg::Node* node = *it; if (node->getNumParents()) node->getParent(0)->removeChild(node); diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 5c38d79d4..7d38308b1 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -351,33 +351,36 @@ public: for (unsigned int i=0; iasGeometry(); - if (!geom) - continue; - - osg::ref_ptr colors = new osg::Vec4Array(geom->getVertexArray()->getNumElements()); - for (unsigned int i=0; isize(); ++i) + osg::ref_ptr colors = new osg::Vec4Array(geom->getVertexArray()->getNumElements()); + for (unsigned int i=0; isize(); ++i) + { + float alpha = 1.f; + if (mMeshType == 0) alpha = i%2 ? 0.f : 1.f; // this is a cylinder, so every second vertex belongs to the bottom-most row + else if (mMeshType == 1) { - float alpha = 1.f; - if (mMeshType == 0) alpha = i%2 ? 0.f : 1.f; // this is a cylinder, so every second vertex belongs to the bottom-most row - else if (mMeshType == 1) - { - if (i>= 49 && i <= 64) alpha = 0.f; // bottom-most row - else if (i>= 33 && i <= 48) alpha = 0.25098; // second row - else alpha = 1.f; - } - else if (mMeshType == 2) - { - osg::Vec4Array* origColors = static_cast(geom->getColorArray()); - alpha = ((*origColors)[i].x() == 1.f) ? 1.f : 0.f; - } - - (*colors)[i] = osg::Vec4f(0.f, 0.f, 0.f, alpha); + if (i>= 49 && i <= 64) alpha = 0.f; // bottom-most row + else if (i>= 33 && i <= 48) alpha = 0.25098; // second row + else alpha = 1.f; + } + else if (mMeshType == 2) + { + osg::Vec4Array* origColors = static_cast(geom->getColorArray()); + alpha = ((*origColors)[i].x() == 1.f) ? 1.f : 0.f; } - geom->setColorArray(colors, osg::Array::BIND_PER_VERTEX); + (*colors)[i] = osg::Vec4f(0.f, 0.f, 0.f, alpha); } + + geom->setColorArray(colors, osg::Array::BIND_PER_VERTEX); } private: diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 49bc7b0fb..b926d7eea 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -5,6 +5,7 @@ #include #include #include +#include // resource #include @@ -885,9 +886,6 @@ namespace NifOsg // localToWorldMatrix for transforming to particle space handleParticlePrograms(partctrl->affectors, partctrl->colliders, parentNode, partsys.get(), rf); - osg::ref_ptr geode (new osg::Geode); - geode->addDrawable(partsys); - std::vector drawableProps; collectDrawableProperties(nifNode, drawableProps); applyDrawableProperties(parentNode, drawableProps, composite, true, animflags); @@ -907,13 +905,21 @@ namespace NifOsg updater->addParticleSystem(partsys); parentNode->addChild(updater); +#if not(OSG_MIN_VERSION_REQUIRED(3,3,3)) + osg::ref_ptr geode (new osg::Geode); + geode->addDrawable(partsys); + osg::Node* toAttach = geode.get(); +#else + osg::Node* toAttach = partsys.get(); +#endif + if (rf == osgParticle::ParticleProcessor::RELATIVE_RF) - parentNode->addChild(geode); + parentNode->addChild(toAttach); else { osg::MatrixTransform* trans = new osg::MatrixTransform; trans->setUpdateCallback(new InverseWorldMatrix); - trans->addChild(geode); + trans->addChild(toAttach); parentNode->addChild(trans); } } @@ -957,8 +963,6 @@ namespace NifOsg void handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::vector& boundTextures, int animflags) { - osg::ref_ptr geode (new osg::Geode); - osg::ref_ptr geometry; for (Nif::ControllerPtr ctrl = triShape->controller; !ctrl.empty(); ctrl = ctrl->next) { @@ -981,21 +985,36 @@ namespace NifOsg triShapeToGeometry(triShape, geometry, parentNode, composite, boundTextures, animflags); +#if not(OSG_MIN_VERSION_REQUIRED(3,3,3)) + osg::ref_ptr geode (new osg::Geode); geode->addDrawable(geometry); +#endif if (geometry->getDataVariance() == osg::Object::DYNAMIC) { // Add a copy, we will alternate between the two copies every other frame using the FrameSwitch // This is so we can set the DataVariance as STATIC, giving a huge performance boost geometry->setDataVariance(osg::Object::STATIC); - osg::ref_ptr geode2 = static_cast(osg::clone(geode.get(), osg::CopyOp::DEEP_COPY_NODES|osg::CopyOp::DEEP_COPY_DRAWABLES)); osg::ref_ptr frameswitch = new FrameSwitch; + +#if not(OSG_MIN_VERSION_REQUIRED(3,3,3)) + osg::ref_ptr geode2 = static_cast(osg::clone(geode.get(), osg::CopyOp::DEEP_COPY_NODES|osg::CopyOp::DEEP_COPY_DRAWABLES)); frameswitch->addChild(geode); frameswitch->addChild(geode2); +#else + osg::ref_ptr geom2 = static_cast(osg::clone(geometry.get(), osg::CopyOp::DEEP_COPY_NODES|osg::CopyOp::DEEP_COPY_DRAWABLES)); + frameswitch->addChild(geometry); + frameswitch->addChild(geom2); +#endif + parentNode->addChild(frameswitch); } else +#if not(OSG_MIN_VERSION_REQUIRED(3,3,3)) parentNode->addChild(geode); +#else + parentNode->addChild(geometry); +#endif } osg::ref_ptr handleMorphGeometry(const Nif::NiGeomMorpherController* morpher) @@ -1056,8 +1075,6 @@ namespace NifOsg void handleSkinnedTriShape(const Nif::NiTriShape *triShape, osg::Group *parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::vector& boundTextures, int animflags) { - osg::ref_ptr geode (new osg::Geode); - osg::ref_ptr geometry (new osg::Geometry); triShapeToGeometry(triShape, geometry, parentNode, composite, boundTextures, animflags); @@ -1090,17 +1107,27 @@ namespace NifOsg } rig->setInfluenceMap(map); - geode->addDrawable(rig); - // Add a copy, we will alternate between the two copies every other frame using the FrameSwitch // This is so we can set the DataVariance as STATIC, giving a huge performance boost rig->setDataVariance(osg::Object::STATIC); + + osg::ref_ptr frameswitch = new FrameSwitch; + +#if not(OSG_MIN_VERSION_REQUIRED(3,3,3)) + osg::ref_ptr geode (new osg::Geode); + geode->addDrawable(rig); + osg::Geode* geode2 = static_cast(osg::clone(geode.get(), osg::CopyOp::DEEP_COPY_NODES| osg::CopyOp::DEEP_COPY_DRAWABLES)); - osg::ref_ptr frameswitch = new FrameSwitch; frameswitch->addChild(geode); frameswitch->addChild(geode2); +#else + SceneUtil::RigGeometry* rig2 = static_cast(osg::clone(rig.get(), osg::CopyOp::DEEP_COPY_NODES| + osg::CopyOp::DEEP_COPY_DRAWABLES)); + frameswitch->addChild(rig); + frameswitch->addChild(rig2); +#endif parentNode->addChild(frameswitch); } diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index f2840574b..20bee13d1 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include @@ -32,30 +33,47 @@ namespace { } - void apply(osg::Node& node) + bool isWorldSpaceParticleSystem(osgParticle::ParticleSystem* partsys) { - if (osg::Geode* geode = node.asGeode()) + // HACK: ParticleSystem has no getReferenceFrame() + return (partsys->getUserDataContainer() + && partsys->getUserDataContainer()->getNumDescriptions() > 0 + && partsys->getUserDataContainer()->getDescriptions()[0] == "worldspace"); + } + + void apply(osg::Geode& geode) + { + for (unsigned int i=0;igetNumDrawables();++i) + if (osgParticle::ParticleSystem* partsys = dynamic_cast(geode.getDrawable(i))) { - if (osgParticle::ParticleSystem* partsys = dynamic_cast(geode->getDrawable(i))) + if (isWorldSpaceParticleSystem(partsys)) { - // HACK: ParticleSystem has no getReferenceFrame() - if (partsys->getUserDataContainer() - && partsys->getUserDataContainer()->getNumDescriptions() > 0 - && partsys->getUserDataContainer()->getDescriptions()[0] == "worldspace") - { - // HACK: Ignore the InverseWorldMatrix transform the geode is attached to - if (geode->getNumParents() && geode->getParent(0)->getNumParents()) - transformInitialParticles(partsys, geode->getParent(0)->getParent(0)); - } - geode->setNodeMask(mMask); + // HACK: Ignore the InverseWorldMatrix transform the geode is attached to + if (geode.getNumParents() && geode.getParent(0)->getNumParents()) + transformInitialParticles(partsys, geode.getParent(0)->getParent(0)); } + geode.setNodeMask(mMask); } } + } - traverse(node); +#if OSG_MIN_VERSION_REQUIRED(3,3,3) + // in OSG 3.3 and up Drawables can be directly in the scene graph without a Geode decorating them. + void apply(osg::Drawable& drw) + { + if (osgParticle::ParticleSystem* partsys = dynamic_cast(&drw)) + { + if (isWorldSpaceParticleSystem(partsys)) + { + // HACK: Ignore the InverseWorldMatrix transform the particle system is attached to + if (partsys->getNumParents() && partsys->getParent(0)->getNumParents()) + transformInitialParticles(partsys, partsys->getParent(0)->getParent(0)); + } + partsys->setNodeMask(mMask); + } } +#endif void transformInitialParticles(osgParticle::ParticleSystem* partsys, osg::Node* node) { diff --git a/components/sceneutil/visitor.cpp b/components/sceneutil/visitor.cpp index 3738be08d..0a5ad2d00 100644 --- a/components/sceneutil/visitor.cpp +++ b/components/sceneutil/visitor.cpp @@ -22,11 +22,13 @@ namespace SceneUtil void DisableFreezeOnCullVisitor::apply(osg::Geode &geode) { for (unsigned int i=0; i(drw)) - partsys->setFreezeOnCull(false); - } + apply(*geode.getDrawable(i)); + } + + void DisableFreezeOnCullVisitor::apply(osg::Drawable& drw) + { + if (osgParticle::ParticleSystem* partsys = dynamic_cast(&drw)) + partsys->setFreezeOnCull(false); } } diff --git a/components/sceneutil/visitor.hpp b/components/sceneutil/visitor.hpp index 656084940..dcfefe9cd 100644 --- a/components/sceneutil/visitor.hpp +++ b/components/sceneutil/visitor.hpp @@ -35,6 +35,7 @@ namespace SceneUtil } virtual void apply(osg::Geode &geode); + virtual void apply(osg::Drawable& drw); }; } From 0409e5a043d1d2db1c07aded5f73e5a8b2a9b25b Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 10 Nov 2015 18:28:58 +0100 Subject: [PATCH 2409/3725] Use OSG_VERSION_GREATER_EQUAL / LESS_THAN rather than MIN_VERSION_REQUIRED (cosmetic change) --- apps/openmw/mwrender/sky.cpp | 2 +- components/nifosg/nifloader.cpp | 10 +++++----- components/resource/scenemanager.cpp | 2 +- components/resource/texturemanager.cpp | 2 +- components/sceneutil/controller.cpp | 4 ++-- components/sceneutil/riggeometry.cpp | 2 +- components/sdlutil/sdlgraphicswindow.cpp | 4 ++-- 7 files changed, 13 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 7d38308b1..66253f70d 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1271,7 +1271,7 @@ public: if (stateset->getAttribute(osg::StateAttribute::MATERIAL)) { SceneUtil::CompositeStateSetUpdater* composite = NULL; -#if OSG_MIN_VERSION_REQUIRED(3,3,3) +#if OSG_VERSION_GREATER_OR_EQUAL(3,3,3) osg::Callback* callback = node.getUpdateCallback(); #else osg::NodeCallback* callback = node.getUpdateCallback(); diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index b926d7eea..ccf840dfe 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -905,7 +905,7 @@ namespace NifOsg updater->addParticleSystem(partsys); parentNode->addChild(updater); -#if not(OSG_MIN_VERSION_REQUIRED(3,3,3)) +#if OSG_VERSION_LESS_THAN(3,3,3) osg::ref_ptr geode (new osg::Geode); geode->addDrawable(partsys); osg::Node* toAttach = geode.get(); @@ -985,7 +985,7 @@ namespace NifOsg triShapeToGeometry(triShape, geometry, parentNode, composite, boundTextures, animflags); -#if not(OSG_MIN_VERSION_REQUIRED(3,3,3)) +#if OSG_VERSION_LESS_THAN(3,3,3) osg::ref_ptr geode (new osg::Geode); geode->addDrawable(geometry); #endif @@ -997,7 +997,7 @@ namespace NifOsg geometry->setDataVariance(osg::Object::STATIC); osg::ref_ptr frameswitch = new FrameSwitch; -#if not(OSG_MIN_VERSION_REQUIRED(3,3,3)) +#if OSG_VERSION_LESS_THAN(3,3,3) osg::ref_ptr geode2 = static_cast(osg::clone(geode.get(), osg::CopyOp::DEEP_COPY_NODES|osg::CopyOp::DEEP_COPY_DRAWABLES)); frameswitch->addChild(geode); frameswitch->addChild(geode2); @@ -1010,7 +1010,7 @@ namespace NifOsg parentNode->addChild(frameswitch); } else -#if not(OSG_MIN_VERSION_REQUIRED(3,3,3)) +#if OSG_VERSION_LESS_THAN(3,3,3) parentNode->addChild(geode); #else parentNode->addChild(geometry); @@ -1113,7 +1113,7 @@ namespace NifOsg osg::ref_ptr frameswitch = new FrameSwitch; -#if not(OSG_MIN_VERSION_REQUIRED(3,3,3)) +#if OSG_VERSION_LESS_THAN(3,3,3) osg::ref_ptr geode (new osg::Geode); geode->addDrawable(rig); diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index 20bee13d1..eb4a4992d 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -58,7 +58,7 @@ namespace } } -#if OSG_MIN_VERSION_REQUIRED(3,3,3) +#if OSG_VERSION_GREATER_OR_EQUAL(3,3,3) // in OSG 3.3 and up Drawables can be directly in the scene graph without a Geode decorating them. void apply(osg::Drawable& drw) { diff --git a/components/resource/texturemanager.cpp b/components/resource/texturemanager.cpp index c2f76a527..8b80efcdc 100644 --- a/components/resource/texturemanager.cpp +++ b/components/resource/texturemanager.cpp @@ -119,7 +119,7 @@ namespace Resource case(GL_COMPRESSED_RGBA_S3TC_DXT3_EXT): case(GL_COMPRESSED_RGBA_S3TC_DXT5_EXT): { -#if OSG_MIN_VERSION_REQUIRED(3,3,3) +#if OSG_VERSION_GREATER_OR_EQUAL(3,3,3) osg::GLExtensions* exts = osg::GLExtensions::Get(0, false); if (exts && !exts->isTextureCompressionS3TCSupported // This one works too. Should it be included in isTextureCompressionS3TCSupported()? Submitted as a patch to OSG. diff --git a/components/sceneutil/controller.cpp b/components/sceneutil/controller.cpp index a2c1cdcd3..7762b48d0 100644 --- a/components/sceneutil/controller.cpp +++ b/components/sceneutil/controller.cpp @@ -65,7 +65,7 @@ namespace SceneUtil void ControllerVisitor::apply(osg::Node &node) { -#if OSG_MIN_VERSION_REQUIRED(3,3,3) +#if OSG_VERSION_GREATER_OR_EQUAL(3,3,3) osg::Callback* callback = node.getUpdateCallback(); #else osg::NodeCallback* callback = node.getUpdateCallback(); @@ -96,7 +96,7 @@ namespace SceneUtil { osg::Drawable* drw = geode.getDrawable(i); -#if OSG_MIN_VERSION_REQUIRED(3,3,3) +#if OSG_VERSION_GREATER_OR_EQUAL(3,3,3) osg::Callback* callback = drw->getUpdateCallback(); #else osg::Drawable::UpdateCallback* callback = drw->getUpdateCallback(); diff --git a/components/sceneutil/riggeometry.cpp b/components/sceneutil/riggeometry.cpp index ac29ee3e8..bd3d613a3 100644 --- a/components/sceneutil/riggeometry.cpp +++ b/components/sceneutil/riggeometry.cpp @@ -288,7 +288,7 @@ void RigGeometry::updateBounds(osg::NodeVisitor *nv) _boundingBox = box; _boundingBoxComputed = true; -#if OSG_MIN_VERSION_REQUIRED(3,3,3) +#if OSG_VERSION_GREATER_OR_EQUAL(3,3,3) // in OSG 3.3.3 and up Drawable inherits from Node, so has a bounding sphere as well. _boundingSphere = osg::BoundingSphere(_boundingBox); _boundingSphereComputed = true; diff --git a/components/sdlutil/sdlgraphicswindow.cpp b/components/sdlutil/sdlgraphicswindow.cpp index 84aafa100..da4b666ec 100644 --- a/components/sdlutil/sdlgraphicswindow.cpp +++ b/components/sdlutil/sdlgraphicswindow.cpp @@ -109,7 +109,7 @@ void GraphicsWindowSDL2::init() mValid = true; -#if OSG_MIN_VERSION_REQUIRED(3,3,4) +#if OSG_VERSION_GREATER_OR_EQUAL(3,3,4) getEventQueue()->syncWindowRectangleWithGraphicsContext(); #else getEventQueue()->syncWindowRectangleWithGraphcisContext(); @@ -130,7 +130,7 @@ bool GraphicsWindowSDL2::realizeImplementation() SDL_ShowWindow(mWindow); -#if OSG_MIN_VERSION_REQUIRED(3,3,4) +#if OSG_VERSION_GREATER_OR_EQUAL(3,3,4) getEventQueue()->syncWindowRectangleWithGraphicsContext(); #else getEventQueue()->syncWindowRectangleWithGraphcisContext(); From 7776c49fc15a921d2e81bf24c46be88de80f8157 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 10 Nov 2015 18:42:59 +0100 Subject: [PATCH 2410/3725] GraphicsWindowSDL2: adjust the log levels --- components/sdlutil/sdlgraphicswindow.cpp | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/components/sdlutil/sdlgraphicswindow.cpp b/components/sdlutil/sdlgraphicswindow.cpp index da4b666ec..49afe32a8 100644 --- a/components/sdlutil/sdlgraphicswindow.cpp +++ b/components/sdlutil/sdlgraphicswindow.cpp @@ -2,7 +2,6 @@ #include -#include #include namespace SDLUtil @@ -79,15 +78,13 @@ void GraphicsWindowSDL2::init() if(!_traits.valid()) return; - // getEventQueue()->setCurrentEventState(osgGA::GUIEventAdapter::getAccumulatedEventState().get()); - WindowData *inheritedWindowData = dynamic_cast(_traits->inheritedWindowData.get()); mWindow = inheritedWindowData ? inheritedWindowData->mWindow : NULL; mOwnsWindow = (mWindow == 0); if(mOwnsWindow) { - OSG_NOTICE<<"Error: No SDL window provided."< Date: Tue, 10 Nov 2015 19:18:02 +0100 Subject: [PATCH 2411/3725] Fixing bug for merchant --- apps/openmw/mwworld/containerstore.cpp | 52 ++++++++++++++++++++------ apps/openmw/mwworld/containerstore.hpp | 7 ++-- components/esm/inventorystate.cpp | 9 ++++- components/esm/inventorystate.hpp | 2 +- 4 files changed, 52 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index bcaaeff94..78a50b4e7 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -442,9 +442,11 @@ void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std:: // For a restocking levelled item, remember what we spawned so we can delete it later when the merchant restocks if (!levItem.empty() && count < 0) { - if (mLevelledItemMap.find(id) == mLevelledItemMap.end()) - mLevelledItemMap[id] = 0; - mLevelledItemMap[id] += std::abs(count); + //If there is no item in map, insert it + std::map >::iterator itemInMap = + mLevelledItemMap.insert(std::make_pair(id, std::make_pair(0, levItem))).first; + //Update spawned count + itemInMap->second.first += std::abs(count); } count = std::abs(count); @@ -461,30 +463,56 @@ void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std:: void MWWorld::ContainerStore::restock (const ESM::InventoryList& items, const MWWorld::Ptr& ptr, const std::string& owner) { - // Remove the items already spawned by levelled items that will restock - for (std::map::iterator it = mLevelledItemMap.begin(); it != mLevelledItemMap.end(); ++it) + //allowedForReplace - Holds information about how many items from the list were sold; + // Hence, tells us how many items we need to restock. + //allowedForReplace[list] <- How many items we should generate(how many of these were sold) + std::map allowedForReplace; + + //Check which lists need restocking: + for (std::map >::iterator it = mLevelledItemMap.begin(); it != mLevelledItemMap.end(); ++it) { - if (count(it->first) >= it->second) - remove(it->first, it->second, ptr); + int spawnedCount = it->second.first; //How many items should be in shop originally + int itemCount = count(it->first); //How many items are there in shop now + //If anything was sold + if(itemCount < spawnedCount) + { + //Create entry if it does not exist yet + std::map::iterator listInMap = allowedForReplace.insert( + std::make_pair(it->second.second, 0)).first; + //And signal that we need to restock item from this list + listInMap->second += std::abs(spawnedCount - itemCount); + //Also, remove the record if item no longer figures in the shop + if(!itemCount) + mLevelledItemMap.erase(it->first); + //If there's still item in the shop, change its spawnedCount to current count. + else + it->second.first -= itemCount; + } } - mLevelledItemMap.clear(); + //Restock: + //For every item that NPC could have for (std::vector::const_iterator it = items.mList.begin(); it != items.mList.end(); ++it) { + //If he shouldn't have it restocked, don't restock it. if (it->mCount >= 0) continue; - std::string item = Misc::StringUtils::lowerCase(it->mItem.toString()); + std::string itemOrList = Misc::StringUtils::lowerCase(it->mItem.toString()); + //If it's levelled list, restock if there's need to do so. if (MWBase::Environment::get().getWorld()->getStore().get().search(it->mItem.toString())) { - addInitialItem(item, owner, it->mCount, true); + std::map::iterator listInMap = allowedForReplace.find(itemOrList); + if(listInMap != allowedForReplace.end()) + addInitialItem(itemOrList, owner, listInMap->second, true); } else { - int currentCount = count(item); + //Restocking static item - just restock to the max count + int currentCount = count(itemOrList); if (currentCount < std::abs(it->mCount)) - addInitialItem(item, owner, std::abs(it->mCount) - currentCount, true); + addInitialItem(itemOrList, owner, std::abs(it->mCount) - currentCount, true); } } flagAsModified(); diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index e9750a622..aaf83755a 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -68,9 +69,9 @@ namespace MWWorld MWWorld::CellRefList repairs; MWWorld::CellRefList weapons; - std::map mLevelledItemMap; - ///< Stores result of levelled item spawns. - /// This is used to remove the spawned item(s) if the levelled item is restocked. + std::map > mLevelledItemMap; + ///< Stores result of levelled item spawns. + /// This is used to restock levelled items(s) if the old item was sold. mutable float mCachedWeight; mutable bool mWeightUpToDate; diff --git a/components/esm/inventorystate.cpp b/components/esm/inventorystate.cpp index e7257ae53..1864b6e8d 100644 --- a/components/esm/inventorystate.cpp +++ b/components/esm/inventorystate.cpp @@ -36,6 +36,10 @@ void ESM::InventoryState::load (ESMReader &esm) { std::string id = esm.getHString(); int count; + std::string parentList; + //TODO: How should I handle old saves? + if(esm.isNextSub("LLST")) + std::string parentList = esm.getHString(); esm.getHNT (count, "COUN"); mLevelledItemMap[id] = count; } @@ -79,10 +83,11 @@ void ESM::InventoryState::save (ESMWriter &esm) const iter->save (esm, true); } - for (std::map::const_iterator it = mLevelledItemMap.begin(); it != mLevelledItemMap.end(); ++it) + for (std::map >::const_iterator it = mLevelledItemMap.begin(); it != mLevelledItemMap.end(); ++it) { esm.writeHNString ("LEVM", it->first); - esm.writeHNT ("COUN", it->second); + esm.writeHNT ("COUN", it->second.first); + esm.writeHNString("LLST", it->second.second) } for (TEffectMagnitudes::const_iterator it = mPermanentMagicEffectMagnitudes.begin(); it != mPermanentMagicEffectMagnitudes.end(); ++it) diff --git a/components/esm/inventorystate.hpp b/components/esm/inventorystate.hpp index d5c317beb..a12be321f 100644 --- a/components/esm/inventorystate.hpp +++ b/components/esm/inventorystate.hpp @@ -20,7 +20,7 @@ namespace ESM // std::map mEquipmentSlots; - std::map mLevelledItemMap; + std::map > mLevelledItemMap; typedef std::map > > TEffectMagnitudes; TEffectMagnitudes mPermanentMagicEffectMagnitudes; From 8e3bc981a218b669bdc567ca27d856595977475e Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 10 Nov 2015 21:45:53 +0100 Subject: [PATCH 2412/3725] Fix self-referencing camera --- apps/openmw/mwrender/globalmap.cpp | 10 ++++------ apps/openmw/mwrender/localmap.cpp | 12 +++++------- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwrender/globalmap.cpp b/apps/openmw/mwrender/globalmap.cpp index 3445e4189..1e0a9112f 100644 --- a/apps/openmw/mwrender/globalmap.cpp +++ b/apps/openmw/mwrender/globalmap.cpp @@ -62,9 +62,8 @@ namespace class CameraUpdateGlobalCallback : public osg::NodeCallback { public: - CameraUpdateGlobalCallback(osg::Camera* cam, MWRender::GlobalMap* parent) + CameraUpdateGlobalCallback(MWRender::GlobalMap* parent) : mRendered(false) - , mCamera(cam) , mParent(parent) { } @@ -73,7 +72,7 @@ namespace { if (mRendered) { - mCamera->setNodeMask(0); + node->setNodeMask(0); return; } @@ -82,13 +81,12 @@ namespace if (!mRendered) { mRendered = true; - mParent->markForRemoval(mCamera); + mParent->markForRemoval(static_cast(node)); } } private: bool mRendered; - osg::ref_ptr mCamera; MWRender::GlobalMap* mParent; }; @@ -263,7 +261,7 @@ namespace MWRender else camera->setClearMask(GL_NONE); - camera->setUpdateCallback(new CameraUpdateGlobalCallback(camera, this)); + camera->setUpdateCallback(new CameraUpdateGlobalCallback(this)); camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT, osg::Camera::PIXEL_BUFFER_RTT); camera->attach(osg::Camera::COLOR_BUFFER, mOverlayTexture); diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index e479119ee..14ec770e8 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -30,22 +30,21 @@ namespace class CameraLocalUpdateCallback : public osg::NodeCallback { public: - CameraLocalUpdateCallback(osg::Camera* cam, MWRender::LocalMap* parent) + CameraLocalUpdateCallback(MWRender::LocalMap* parent) : mRendered(false) - , mCamera(cam) , mParent(parent) { } - virtual void operator()(osg::Node*, osg::NodeVisitor*) + virtual void operator()(osg::Node* node, osg::NodeVisitor*) { if (mRendered) - mCamera->setNodeMask(0); + node->setNodeMask(0); if (!mRendered) { mRendered = true; - mParent->markForRemoval(mCamera); + mParent->markForRemoval(static_cast(node)); } // Note, we intentionally do not traverse children here. The map camera's scene data is the same as the master camera's, @@ -55,7 +54,6 @@ namespace private: bool mRendered; - osg::ref_ptr mCamera; MWRender::LocalMap* mParent; }; @@ -205,7 +203,7 @@ osg::ref_ptr LocalMap::createOrthographicCamera(float x, float y, f camera->setStateSet(stateset); camera->setGraphicsContext(mViewer->getCamera()->getGraphicsContext()); camera->setViewport(0, 0, mMapResolution, mMapResolution); - camera->setUpdateCallback(new CameraLocalUpdateCallback(camera, this)); + camera->setUpdateCallback(new CameraLocalUpdateCallback(this)); return camera; } From b840c68f0c5ad860a074be71e851d6298d8cc717 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 10 Nov 2015 21:46:40 +0100 Subject: [PATCH 2413/3725] Do not create a depth buffer for the global map 2d rendering --- apps/openmw/mwrender/globalmap.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwrender/globalmap.cpp b/apps/openmw/mwrender/globalmap.cpp index 1e0a9112f..f91f7674f 100644 --- a/apps/openmw/mwrender/globalmap.cpp +++ b/apps/openmw/mwrender/globalmap.cpp @@ -266,6 +266,9 @@ namespace MWRender camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT, osg::Camera::PIXEL_BUFFER_RTT); camera->attach(osg::Camera::COLOR_BUFFER, mOverlayTexture); + // no need for a depth buffer + camera->setImplicitBufferAttachmentMask(osg::DisplaySettings::IMPLICIT_COLOR_BUFFER_ATTACHMENT); + if (cpuCopy) { // Attach an image to copy the render back to the CPU when finished @@ -286,10 +289,12 @@ namespace MWRender { osg::ref_ptr geom = createTexturedQuad(srcLeft, srcTop, srcRight, srcBottom); osg::ref_ptr depth = new osg::Depth; - depth->setFunction(osg::Depth::ALWAYS); - geom->getOrCreateStateSet()->setAttributeAndModes(depth, osg::StateAttribute::ON); - geom->getOrCreateStateSet()->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON); - geom->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF); + depth->setWriteMask(0); + osg::StateSet* stateset = geom->getOrCreateStateSet(); + stateset->setAttribute(depth); + stateset->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON); + stateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF); + stateset->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF); osg::ref_ptr geode = new osg::Geode; geode->addDrawable(geom); camera->addChild(geode); From 2e9805fa0ee57fa5d724c04f8c2230cc0ba5a927 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 11 Nov 2015 00:50:57 +0100 Subject: [PATCH 2414/3725] Leak fix --- apps/openmw/mwrender/characterpreview.cpp | 9 ++++----- apps/openmw/mwrender/characterpreview.hpp | 3 ++- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index eb950ea79..f7296b1bd 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -157,11 +157,10 @@ namespace MWRender void CharacterPreview::rebuild() { - delete mAnimation; - mAnimation = NULL; + mAnimation.reset(NULL); - mAnimation = new NpcAnimation(mCharacter, mNode, mResourceSystem, true, true, - (renderHeadOnly() ? NpcAnimation::VM_HeadOnly : NpcAnimation::VM_Normal)); + mAnimation.reset(new NpcAnimation(mCharacter, mNode, mResourceSystem, true, true, + (renderHeadOnly() ? NpcAnimation::VM_HeadOnly : NpcAnimation::VM_Normal))); onSetup(); @@ -194,7 +193,7 @@ namespace MWRender void InventoryPreview::update() { - if (!mAnimation) + if (!mAnimation.get()) return; mAnimation->showWeapons(true); diff --git a/apps/openmw/mwrender/characterpreview.hpp b/apps/openmw/mwrender/characterpreview.hpp index 0f85cc3bf..32c1850c6 100644 --- a/apps/openmw/mwrender/characterpreview.hpp +++ b/apps/openmw/mwrender/characterpreview.hpp @@ -2,6 +2,7 @@ #define MWRENDER_CHARACTERPREVIEW_H #include +#include #include @@ -61,7 +62,7 @@ namespace MWRender MWWorld::Ptr mCharacter; - MWRender::NpcAnimation* mAnimation; + std::auto_ptr mAnimation; osg::ref_ptr mNode; std::string mCurrentAnimGroup; From fc93dc619578eff74c647ee35a3875b4c79332ca Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 11 Nov 2015 01:32:31 +0100 Subject: [PATCH 2415/3725] Remove a stray method declaration --- components/nifosg/particle.hpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/components/nifosg/particle.hpp b/components/nifosg/particle.hpp index 043489865..bfb127218 100644 --- a/components/nifosg/particle.hpp +++ b/components/nifosg/particle.hpp @@ -139,9 +139,6 @@ namespace NifOsg META_Object(NifOsg, ParticleColorAffector) - // TODO: very similar to vec3 version, refactor to a template - osg::Vec4f interpolate(const float time, const Nif::Vector4KeyMap::MapType& keys); - virtual void operate(osgParticle::Particle* particle, double dt); private: From c62c1693e9dd3741b44d84faabf119ef20c08d3d Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 11 Nov 2015 01:47:11 +0100 Subject: [PATCH 2416/3725] Disable copy constructor and operator= in PartHolder --- apps/openmw/mwrender/animation.hpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 5aaa4071b..b1c34576b 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -61,6 +61,9 @@ public: private: osg::ref_ptr mNode; + + void operator= (const PartHolder&); + PartHolder(const PartHolder&); }; typedef boost::shared_ptr PartHolderPtr; From afa590bddb5a991cd35aeabd17f43e3ae2fb0e1f Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 11 Nov 2015 16:04:17 +0100 Subject: [PATCH 2417/3725] Leak fix --- apps/openmw/mwrender/rotatecontroller.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/rotatecontroller.hpp b/apps/openmw/mwrender/rotatecontroller.hpp index 8c3758cb0..456a6dd20 100644 --- a/apps/openmw/mwrender/rotatecontroller.hpp +++ b/apps/openmw/mwrender/rotatecontroller.hpp @@ -27,7 +27,7 @@ protected: bool mEnabled; osg::Quat mRotate; - osg::ref_ptr mRelativeTo; + osg::Node* mRelativeTo; }; From 1edcb219a70f757221810e8c5861dc58972bd691 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 11 Nov 2015 16:27:17 +0100 Subject: [PATCH 2418/3725] Leak fix --- components/nifosg/nifloader.cpp | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index ccf840dfe..3e7f47b6f 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -1407,7 +1407,7 @@ namespace NifOsg osg::StateSet* stateset = node->getOrCreateStateSet(); int specFlags = 0; // Specular is disabled by default, even if there's a specular color in the NiMaterialProperty - osg::Material* mat = new osg::Material; + osg::ref_ptr mat (new osg::Material); mat->setColorMode(hasVertexColors ? osg::Material::AMBIENT_AND_DIFFUSE : osg::Material::OFF); // NIF material defaults don't match OpenGL defaults @@ -1462,12 +1462,11 @@ namespace NifOsg case Nif::RC_NiAlphaProperty: { const Nif::NiAlphaProperty* alphaprop = static_cast(property); - osg::BlendFunc* blendfunc = new osg::BlendFunc; if (alphaprop->flags&1) { - blendfunc->setFunction(getBlendMode((alphaprop->flags>>1)&0xf), - getBlendMode((alphaprop->flags>>5)&0xf)); - stateset->setAttributeAndModes(blendfunc, osg::StateAttribute::ON); + stateset->setAttributeAndModes(new osg::BlendFunc(getBlendMode((alphaprop->flags>>1)&0xf), + getBlendMode((alphaprop->flags>>5)&0xf)), + osg::StateAttribute::ON); bool noSort = (alphaprop->flags>>13)&1; if (!noSort) @@ -1482,11 +1481,10 @@ namespace NifOsg stateset->setRenderBinToInherit(); } - osg::AlphaFunc* alphafunc = new osg::AlphaFunc; if((alphaprop->flags>>9)&1) { - alphafunc->setFunction(getTestMode((alphaprop->flags>>10)&0x7), alphaprop->data.threshold/255.f); - stateset->setAttributeAndModes(alphafunc, osg::StateAttribute::ON); + stateset->setAttributeAndModes(new osg::AlphaFunc(getTestMode((alphaprop->flags>>10)&0x7), + alphaprop->data.threshold/255.f), osg::StateAttribute::ON); } else { From 0a52ee17c31851a3c9ad4ea576d0782a1f8feb2c Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 11 Nov 2015 17:04:06 +0100 Subject: [PATCH 2419/3725] Fix Drawable removal issues --- apps/openmw/mwrender/animation.cpp | 88 +++++++++++++++--------------- 1 file changed, 44 insertions(+), 44 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index c2cbb4627..b5f0a2036 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -175,58 +175,71 @@ namespace return 0.0f; } - - // Removes all drawables from a graph. - class RemoveDrawableVisitor : public osg::NodeVisitor + /// @brief Base class for visitors that remove nodes from a scene graph. + /// Subclasses need to fill the mToRemove vector. + /// To use, node->accept(removeVisitor); removeVisitor.remove(); + class RemoveVisitor : public osg::NodeVisitor { public: - RemoveDrawableVisitor() + RemoveVisitor() : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) { } - virtual void apply(osg::Geode &node) + void remove() { - // Not safe to remove in apply(), since the visitor is still iterating the child list - osg::Group* parent = node.getParent(0); - // prune nodes that would be empty after the removal - if (parent->getNumChildren() == 1 && parent->getDataVariance() == osg::Object::STATIC) - mToRemove.push_back(parent); - else - mToRemove.push_back(&node); - traverse(node); + for (RemoveVec::iterator it = mToRemove.begin(); it != mToRemove.end(); ++it) + it->second->removeChild(it->first); + } + + protected: + // + typedef std::vector > RemoveVec; + std::vector > mToRemove; + }; + + // Removes all drawables from a graph. + class RemoveDrawableVisitor : public RemoveVisitor + { + public: + virtual void apply(osg::Geode &geode) + { + applyImpl(geode); } #if OSG_VERSION_GREATER_OR_EQUAL(3,3,3) virtual void apply(osg::Drawable& drw) { - mToRemove.push_back(&drw); + applyImpl(drw); } #endif - void remove() + void applyImpl(osg::Node& node) { - for (std::vector::iterator it = mToRemove.begin(); it != mToRemove.end(); ++it) + osg::NodePath::iterator parent = getNodePath().end()-2; + // We know that the parent is a Group because only Groups can have children. + osg::Group* parentGroup = static_cast(*parent); + + // Try to prune nodes that would be empty after the removal + if (parent != getNodePath().begin()) { - // FIXME: a Drawable might have more than one parent - osg::Node* node = *it; - if (node->getNumParents()) - node->getParent(0)->removeChild(node); + // This could be extended to remove the parent's parent, and so on if they are empty as well. + // But for NIF files, there won't be a benefit since only TriShapes can be set to STATIC dataVariance. + osg::Group* parentParent = static_cast(*(parent - 1)); + if (parentGroup->getNumChildren() == 1 && parentGroup->getDataVariance() == osg::Object::STATIC) + { + mToRemove.push_back(std::make_pair(parentGroup, parentParent)); + return; + } } - } - private: - std::vector mToRemove; + mToRemove.push_back(std::make_pair(&node, parentGroup)); + } }; - class RemoveTriBipVisitor : public osg::NodeVisitor + class RemoveTriBipVisitor : public RemoveVisitor { public: - RemoveTriBipVisitor() - : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) - { - } - virtual void apply(osg::Geode &node) { applyImpl(node); @@ -244,24 +257,11 @@ namespace const std::string toFind = "tri bip"; if (Misc::StringUtils::ciCompareLen(node.getName(), toFind, toFind.size()) == 0) { + osg::Group* parent = static_cast(*(getNodePath().end()-2)); // Not safe to remove in apply(), since the visitor is still iterating the child list - mToRemove.push_back(&node); + mToRemove.push_back(std::make_pair(&node, parent)); } } - - void remove() - { - for (std::vector::iterator it = mToRemove.begin(); it != mToRemove.end(); ++it) - { - // FIXME: a Drawable might have more than one parent - osg::Node* node = *it; - if (node->getNumParents()) - node->getParent(0)->removeChild(node); - } - } - - private: - std::vector mToRemove; }; } From 9c503cbd8c0b9f4235e3f7ca0be18c43931684d7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 11 Nov 2015 17:07:31 +0100 Subject: [PATCH 2420/3725] Add build* to the gitignore Allows one to have multiple build folders, e.g. a separate build for a different OSG versions, or for different OpenMW versions, or when you often switch between branches. --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 88f591aae..e1abcaa63 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,7 @@ CMakeCache.txt cmake_install.cmake Makefile makefile -build +build* prebuilt ## doxygen From 02148a43f5da34d3d4be31adf9c148e9de8951d0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 11 Nov 2015 17:22:31 +0100 Subject: [PATCH 2421/3725] Node mask fix --- apps/openmw/mwrender/animation.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index b5f0a2036..55a47d4b6 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1317,6 +1317,7 @@ namespace MWRender { mGlowLight = new SceneUtil::LightSource; mGlowLight->setLight(new osg::Light); + mGlowLight->setNodeMask(Mask_Lighting); osg::Light* light = mGlowLight->getLight(); light->setDiffuse(osg::Vec4f(0,0,0,0)); light->setSpecular(osg::Vec4f(0,0,0,0)); From 79c44d0bfe33deb2ccacda73ac631cdb31931133 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 11 Nov 2015 17:23:47 +0100 Subject: [PATCH 2422/3725] Style fix --- apps/openmw/mwrender/camera.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/camera.cpp b/apps/openmw/mwrender/camera.cpp index ea8c60bf3..1d43cde43 100644 --- a/apps/openmw/mwrender/camera.cpp +++ b/apps/openmw/mwrender/camera.cpp @@ -381,7 +381,7 @@ namespace MWRender osg::PositionAttitudeTransform* transform = mTrackingPtr.getRefData().getBaseNode(); mTrackingNode = transform; if (transform) - mHeightScale = mTrackingPtr.getRefData().getBaseNode()->getScale().z(); + mHeightScale = transform->getScale().z(); else mHeightScale = 1.f; } From a68fd791c849d0820d3286921cc6ffa46b54258f Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 11 Nov 2015 17:24:27 +0100 Subject: [PATCH 2423/3725] Remove a stray method declaration --- apps/openmw/mwrender/camera.hpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/openmw/mwrender/camera.hpp b/apps/openmw/mwrender/camera.hpp index 899fc9447..fab63cd3f 100644 --- a/apps/openmw/mwrender/camera.hpp +++ b/apps/openmw/mwrender/camera.hpp @@ -98,8 +98,6 @@ namespace MWRender bool isFirstPerson() const { return !(mVanity.enabled || mPreviewMode || !mFirstPersonView); } - void updateScale(); - void processViewChange(); void update(float duration, bool paused=false); From fef0a40bee1809658079f52d2d2a64c742a6a948 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 11 Nov 2015 19:55:14 +0100 Subject: [PATCH 2424/3725] updated changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3a3cdfd25..cb88ca5d5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -338,6 +338,7 @@ Bug #1730: Scripts names starting with digit(s) fail to compile Bug #1743: Moons are transparent Bug #1745: Shadows crash: Assertion `mEffects.empty()' failed. + Bug #1784: First person weapons always in the same position Bug #1785: Can't equip two-handed weapon and shield Bug #1809: Player falls too easily Bug #1825: Sword of Perithia can´t run in OpenMW From a07c6b4364b6696abca0f4559275cc4f321b4930 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 11 Nov 2015 19:57:38 +0100 Subject: [PATCH 2425/3725] Modified the changelog for the wrong version. Oops. --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e51023422..378348ff8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ Bug #1650: No textures with directx on windows Bug #1730: Scripts names starting with digit(s) fail to compile Bug #1738: Socucius Ergalla's greetings are doubled during the tutorial + Bug #1784: First person weapons always in the same position Bug #1813: Underwater flora lighting up entire area. Bug #1871: Handle controller extrapolation flags Bug #1921: Footstep frequency and velocity do not immediately update when speed attribute changes @@ -338,7 +339,6 @@ Bug #1730: Scripts names starting with digit(s) fail to compile Bug #1743: Moons are transparent Bug #1745: Shadows crash: Assertion `mEffects.empty()' failed. - Bug #1784: First person weapons always in the same position Bug #1785: Can't equip two-handed weapon and shield Bug #1809: Player falls too easily Bug #1825: Sword of Perithia can´t run in OpenMW From 8aacbc398f629ecec0abe79317b6a6f5724fb8d4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 12 Nov 2015 00:52:36 +0100 Subject: [PATCH 2426/3725] Rotations: don't wrap the angle values for non-actors It's not really necessary, and just complicates logic elsewhere. Neither does vanilla MW do it. As well, the question is if wrapping to [-PI, PI] or [0, 2*PI] would be the desired range. --- apps/openmw/mwworld/worldimp.cpp | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 0f8c5aa32..ef594ddeb 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1247,14 +1247,10 @@ namespace MWWorld if(objRot[0] < -half_pi) objRot[0] = -half_pi; else if(objRot[0] > half_pi) objRot[0] = half_pi; - } - else - { - wrap(objRot[0]); - } - wrap(objRot[1]); - wrap(objRot[2]); + wrap(objRot[1]); + wrap(objRot[2]); + } ptr.getRefData().setPosition(pos); @@ -1269,10 +1265,6 @@ namespace MWWorld rot.rot[1]=osg::DegreesToRadians(y); rot.rot[2]=osg::DegreesToRadians(z); - wrap(rot.rot[0]); - wrap(rot.rot[1]); - wrap(rot.rot[2]); - ptr.getRefData().setLocalRotation(rot); if (ptr.getRefData().getBaseNode() != 0) From 6405049add6c506ea5ca22eec3d0928f1b174e4a Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 12 Nov 2015 00:58:29 +0100 Subject: [PATCH 2427/3725] Rotations: move doors via Rotation rather than LocalRotation Now LocalRotation is unneeded, will remove in next commit. --- apps/openmw/mwclass/door.cpp | 7 ++++--- apps/openmw/mwmechanics/obstacle.cpp | 17 ++++++++--------- apps/openmw/mwmechanics/obstacle.hpp | 6 ++---- apps/openmw/mwworld/worldimp.cpp | 17 +++++++++++------ 4 files changed, 25 insertions(+), 22 deletions(-) diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 18c381e13..b469dc9e2 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -159,16 +159,17 @@ namespace MWClass boost::shared_ptr action(new MWWorld::ActionDoor(ptr)); int doorstate = getDoorState(ptr); bool opening = true; + float doorRot = ptr.getRefData().getPosition().rot[2] - ptr.getCellRef().getPosition().rot[2]; if (doorstate == 1) opening = false; - if (doorstate == 0 && ptr.getRefData().getLocalRotation().rot[2] != 0) + if (doorstate == 0 && doorRot != 0) opening = false; if (opening) { MWBase::Environment::get().getSoundManager()->fadeOutSound3D(ptr, closeSound, 0.5f); - float offset = ptr.getRefData().getLocalRotation().rot[2]/ 3.14159265f * 2.0f; + float offset = doorRot/ 3.14159265f * 2.0f; action->setSoundOffset(offset); action->setSound(openSound); } @@ -176,7 +177,7 @@ namespace MWClass { MWBase::Environment::get().getSoundManager()->fadeOutSound3D(ptr, openSound, 0.5f); - float offset = 1.0f - ptr.getRefData().getLocalRotation().rot[2]/ 3.14159265f * 2.0f; + float offset = 1.0f - doorRot/ 3.14159265f * 2.0f; //most if not all door have closing bang somewhere in the middle of the sound, //so we divide offset by two action->setSoundOffset(offset * 0.5f); diff --git a/apps/openmw/mwmechanics/obstacle.cpp b/apps/openmw/mwmechanics/obstacle.cpp index 7def96bef..dae5f8496 100644 --- a/apps/openmw/mwmechanics/obstacle.cpp +++ b/apps/openmw/mwmechanics/obstacle.cpp @@ -28,15 +28,15 @@ namespace MWMechanics // // Limitation: there can be false detections, and does not test whether the // actor is facing the door. - bool proximityToDoor(const MWWorld::Ptr& actor, float minSqr, bool closed) + bool proximityToDoor(const MWWorld::Ptr& actor, float minSqr) { - if(getNearbyDoor(actor, minSqr, closed)!=MWWorld::Ptr()) + if(getNearbyDoor(actor, minSqr)!=MWWorld::Ptr()) return true; else return false; } - MWWorld::Ptr getNearbyDoor(const MWWorld::Ptr& actor, float minSqr, bool closed) + MWWorld::Ptr getNearbyDoor(const MWWorld::Ptr& actor, float minSqr) { MWWorld::CellStore *cell = actor.getCell(); @@ -60,12 +60,11 @@ namespace MWMechanics for (; it != refList.end(); ++it) { MWWorld::LiveCellRef& ref = *it; - if((pos - ref.mData.getPosition().asVec3()).length2() < minSqr) - if((closed && ref.mData.getLocalRotation().rot[2] == 0) || - (!closed && ref.mData.getLocalRotation().rot[2] >= 1)) - { - return MWWorld::Ptr(&ref, actor.getCell()); // found, stop searching - } + if((pos - ref.mData.getPosition().asVec3()).length2() < minSqr + && ref.mData.getPosition().rot[2] == ref.mRef.getPosition().rot[2]) + { + return MWWorld::Ptr(&ref, actor.getCell()); // found, stop searching + } } return MWWorld::Ptr(); // none found } diff --git a/apps/openmw/mwmechanics/obstacle.hpp b/apps/openmw/mwmechanics/obstacle.hpp index 6b442f5a5..98cc4e7a0 100644 --- a/apps/openmw/mwmechanics/obstacle.hpp +++ b/apps/openmw/mwmechanics/obstacle.hpp @@ -17,14 +17,12 @@ namespace MWMechanics /// tests actor's proximity to a closed door by default bool proximityToDoor(const MWWorld::Ptr& actor, - float minSqr = MIN_DIST_TO_DOOR_SQUARED, - bool closed = true); + float minSqr = MIN_DIST_TO_DOOR_SQUARED); /// Returns door pointer within range. No guarentee is given as too which one /** \return Pointer to the door, or NULL if none exists **/ MWWorld::Ptr getNearbyDoor(const MWWorld::Ptr& actor, - float minSqr = MIN_DIST_TO_DOOR_SQUARED, - bool closed = true); + float minSqr = MIN_DIST_TO_DOOR_SQUARED); class ObstacleCheck { diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index ef594ddeb..af3470cac 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1402,12 +1402,17 @@ namespace MWWorld } else { - float oldRot = osg::RadiansToDegrees(it->first.getRefData().getLocalRotation().rot[2]); + const ESM::Position& objPos = it->first.getRefData().getPosition(); + float oldRot = osg::RadiansToDegrees(objPos.rot[2]); + + float minRot = osg::RadiansToDegrees(it->first.getCellRef().getPosition().rot[2]); + float maxRot = minRot + 90.f; + float diff = duration * 90.f; - float targetRot = std::min(std::max(0.f, oldRot + diff * (it->second == 1 ? 1 : -1)), 90.f); - localRotateObject(it->first, 0, 0, targetRot); + float targetRot = std::min(std::max(minRot, oldRot + diff * (it->second == 1 ? 1 : -1)), maxRot); + rotateObject(it->first, objPos.rot[0], objPos.rot[1], targetRot); - bool reached = (targetRot == 90.f && it->second) || targetRot == 0.f; + bool reached = (targetRot == maxRot && it->second) || targetRot == minRot; /// \todo should use convexSweepTest here std::vector collisions = mPhysics->getCollisions(it->first, MWPhysics::CollisionType_Actor, MWPhysics::CollisionType_Actor); @@ -1424,7 +1429,7 @@ namespace MWWorld } // we need to undo the rotation - localRotateObject(it->first, 0, 0, oldRot); + rotateObject(it->first, objPos.rot[0], objPos.rot[1], oldRot); reached = false; } } @@ -2103,7 +2108,7 @@ namespace MWWorld switch (state) { case 0: - if (door.getRefData().getLocalRotation().rot[2] == 0) + if (door.getRefData().getPosition().rot[2] == door.getCellRef().getPosition().rot[2]) state = 1; // if closed, then open else state = 2; // if open, then close From 666fbba1e044e2a18c9195112636b193734dce6b Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 12 Nov 2015 01:08:31 +0100 Subject: [PATCH 2428/3725] Rotations: World::rotateObject takes radians instead of degrees Cuts down on the amount of redundant degree<->radians conversions in the codebase. --- apps/openmw/mwmechanics/character.cpp | 1 - .../mwscript/transformationextensions.cpp | 18 +++++++++--------- apps/openmw/mwworld/scene.cpp | 12 ++++++------ apps/openmw/mwworld/worldimp.cpp | 13 +++++-------- apps/openmw/mwworld/worldimp.hpp | 2 +- 5 files changed, 21 insertions(+), 25 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 129206f51..b5b4721c0 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1816,7 +1816,6 @@ void CharacterController::update(float duration) if (!mSkipAnim) { - rot *= osg::RadiansToDegrees(1.0f); if(mHitState != CharState_KnockDown && mHitState != CharState_KnockOut) { world->rotateObject(mPtr, rot.x(), rot.y(), rot.z(), true); diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 679a8d2de..1f47741c3 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -85,12 +85,12 @@ namespace MWScript std::string axis = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); - Interpreter::Type_Float angle = runtime[0].mFloat; + Interpreter::Type_Float angle = osg::DegreesToRadians(runtime[0].mFloat); runtime.pop(); - float ax = osg::RadiansToDegrees(ptr.getRefData().getPosition().rot[0]); - float ay = osg::RadiansToDegrees(ptr.getRefData().getPosition().rot[1]); - float az = osg::RadiansToDegrees(ptr.getRefData().getPosition().rot[2]); + float ax = ptr.getRefData().getPosition().rot[0]; + float ay = ptr.getRefData().getPosition().rot[1]; + float az = ptr.getRefData().getPosition().rot[2]; MWWorld::LocalRotation localRot = ptr.getRefData().getLocalRotation(); @@ -337,7 +337,7 @@ namespace MWScript // See "Morrowind Scripting for Dummies (9th Edition)" pages 50 and 54 for reference. if(ptr != MWMechanics::getPlayer()) zRot = zRot/60.0f; - MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay,zRot); + MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay,osg::DegreesToRadians(zRot)); ptr.getClass().adjustPosition(ptr, false); } @@ -603,14 +603,14 @@ namespace MWScript std::string axis = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); - Interpreter::Type_Float rotation = (runtime[0].mFloat*MWBase::Environment::get().getFrameDuration()); + Interpreter::Type_Float rotation = osg::DegreesToRadians(runtime[0].mFloat*MWBase::Environment::get().getFrameDuration()); runtime.pop(); const float *objRot = ptr.getRefData().getPosition().rot; - float ax = osg::RadiansToDegrees(objRot[0]); - float ay = osg::RadiansToDegrees(objRot[1]); - float az = osg::RadiansToDegrees(objRot[2]); + float ax = objRot[0]; + float ay = objRot[1]; + float az = objRot[2]; if (axis == "x") { diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 33e2ba17c..83a7a9f2c 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -419,9 +419,9 @@ namespace MWWorld if (adjustPlayerPos) { world->moveObject(player, pos.pos[0], pos.pos[1], pos.pos[2]); - float x = osg::RadiansToDegrees(pos.rot[0]); - float y = osg::RadiansToDegrees(pos.rot[1]); - float z = osg::RadiansToDegrees(pos.rot[2]); + float x = pos.rot[0]; + float y = pos.rot[1]; + float z = pos.rot[2]; world->rotateObject(player, x, y, z); player.getClass().adjustPosition(player, true); @@ -476,9 +476,9 @@ namespace MWWorld MWBase::World *world = MWBase::Environment::get().getWorld(); world->moveObject(world->getPlayerPtr(), position.pos[0], position.pos[1], position.pos[2]); - float x = osg::RadiansToDegrees(position.rot[0]); - float y = osg::RadiansToDegrees(position.rot[1]); - float z = osg::RadiansToDegrees(position.rot[2]); + float x = position.rot[0]; + float y = position.rot[1]; + float z = position.rot[2]; world->rotateObject(world->getPlayerPtr(), x, y, z); world->getPlayerPtr().getClass().adjustPosition(world->getPlayerPtr(), true); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index af3470cac..20a84d6b1 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1317,10 +1317,7 @@ namespace MWWorld void World::rotateObject (const Ptr& ptr,float x,float y,float z, bool adjust) { - rotateObjectImp(ptr, osg::Vec3f(osg::DegreesToRadians(x), - osg::DegreesToRadians(y), - osg::DegreesToRadians(z)), - adjust); + rotateObjectImp(ptr, osg::Vec3f(x, y, z), adjust); } MWWorld::Ptr World::safePlaceObject(const MWWorld::Ptr& ptr, MWWorld::CellStore* cell, ESM::Position pos) @@ -1403,12 +1400,12 @@ namespace MWWorld else { const ESM::Position& objPos = it->first.getRefData().getPosition(); - float oldRot = osg::RadiansToDegrees(objPos.rot[2]); + float oldRot = objPos.rot[2]; - float minRot = osg::RadiansToDegrees(it->first.getCellRef().getPosition().rot[2]); - float maxRot = minRot + 90.f; + float minRot = it->first.getCellRef().getPosition().rot[2]; + float maxRot = minRot + osg::DegreesToRadians(90.f); - float diff = duration * 90.f; + float diff = duration * osg::DegreesToRadians(90.f); float targetRot = std::min(std::max(minRot, oldRot + diff * (it->second == 1 ? 1 : -1)), maxRot); rotateObject(it->first, objPos.rot[0], objPos.rot[1], targetRot); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index de9266cb2..4b3cc5eb7 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -349,7 +349,7 @@ namespace MWWorld virtual void scaleObject (const Ptr& ptr, float scale); - /// World rotates object, uses degrees + /// World rotates object, uses radians /// \param adjust indicates rotation should be set or adjusted virtual void rotateObject (const Ptr& ptr,float x,float y,float z, bool adjust = false); From b4ce73f179f7c2d9465935e7f8efcf3ed614e420 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 12 Nov 2015 01:16:37 +0100 Subject: [PATCH 2429/3725] Rotations: remove LocalRotation This never existed in vanilla MW in the first place. The reason we got confused was because of a strange behaviour where the order of applying rotations changes as soon as a script touches the object's rotation. --- apps/openmw/mwbase/world.hpp | 2 - apps/openmw/mwscript/miscextensions.cpp | 7 ++- .../mwscript/transformationextensions.cpp | 44 +++++-------------- apps/openmw/mwworld/refdata.cpp | 21 --------- apps/openmw/mwworld/refdata.hpp | 8 ---- apps/openmw/mwworld/scene.cpp | 10 +---- apps/openmw/mwworld/worldimp.cpp | 20 --------- apps/openmw/mwworld/worldimp.hpp | 3 -- components/esm/objectstate.cpp | 7 +-- components/esm/objectstate.hpp | 1 - 10 files changed, 20 insertions(+), 103 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 1622e1537..7332a26be 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -270,8 +270,6 @@ namespace MWBase virtual void rotateObject(const MWWorld::Ptr& ptr,float x,float y,float z, bool adjust = false) = 0; - virtual void localRotateObject (const MWWorld::Ptr& ptr, float x, float y, float z) = 0; - virtual MWWorld::Ptr safePlaceObject(const MWWorld::Ptr& ptr, MWWorld::CellStore* cell, ESM::Position pos) = 0; ///< place an object in a "safe" location (ie not in the void, etc). diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 5aebbc3a9..63f3ea190 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -188,7 +188,12 @@ namespace MWScript if (ptr.getTypeName() == typeid(ESM::Door).name() && !ptr.getCellRef().getTeleport()) { MWBase::Environment::get().getWorld()->activateDoor(ptr, 0); - MWBase::Environment::get().getWorld()->localRotateObject(ptr, 0, 0, 0); + + float xr = ptr.getCellRef().getPosition().rot[0]; + float yr = ptr.getCellRef().getPosition().rot[1]; + float zr = ptr.getCellRef().getPosition().rot[2]; + + MWBase::Environment::get().getWorld()->rotateObject(ptr, xr, yr, zr); } } }; diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 1f47741c3..f41bb8842 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -92,26 +92,12 @@ namespace MWScript float ay = ptr.getRefData().getPosition().rot[1]; float az = ptr.getRefData().getPosition().rot[2]; - MWWorld::LocalRotation localRot = ptr.getRefData().getLocalRotation(); - if (axis == "x") - { - localRot.rot[0] = 0; - ptr.getRefData().setLocalRotation(localRot); MWBase::Environment::get().getWorld()->rotateObject(ptr,angle,ay,az); - } else if (axis == "y") - { - localRot.rot[1] = 0; - ptr.getRefData().setLocalRotation(localRot); MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,angle,az); - } else if (axis == "z") - { - localRot.rot[2] = 0; - ptr.getRefData().setLocalRotation(localRot); MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay,angle); - } else throw std::runtime_error ("invalid rotation axis: " + axis); } @@ -568,25 +554,19 @@ namespace MWScript std::string axis = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); - Interpreter::Type_Float rotation = (runtime[0].mFloat*MWBase::Environment::get().getFrameDuration()); + Interpreter::Type_Float rotation = osg::DegreesToRadians(runtime[0].mFloat*MWBase::Environment::get().getFrameDuration()); runtime.pop(); - float ax = osg::RadiansToDegrees(ptr.getRefData().getLocalRotation().rot[0]); - float ay = osg::RadiansToDegrees(ptr.getRefData().getLocalRotation().rot[1]); - float az = osg::RadiansToDegrees(ptr.getRefData().getLocalRotation().rot[2]); + float ax = ptr.getRefData().getPosition().rot[0]; + float ay = ptr.getRefData().getPosition().rot[1]; + float az = ptr.getRefData().getPosition().rot[2]; if (axis == "x") - { - MWBase::Environment::get().getWorld()->localRotateObject(ptr,ax+rotation,ay,az); - } + MWBase::Environment::get().getWorld()->rotateObject(ptr,ax+rotation,ay,az); else if (axis == "y") - { - MWBase::Environment::get().getWorld()->localRotateObject(ptr,ax,ay+rotation,az); - } + MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay+rotation,az); else if (axis == "z") - { - MWBase::Environment::get().getWorld()->localRotateObject(ptr,ax,ay,az+rotation); - } + MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay,az+rotation); else throw std::runtime_error ("invalid rotation axis: " + axis); } @@ -641,13 +621,11 @@ namespace MWScript if (!ptr.isInCell()) return; - MWWorld::LocalRotation rot; - rot.rot[0] = 0; - rot.rot[1] = 0; - rot.rot[2] = 0; - ptr.getRefData().setLocalRotation(rot); + float xr = ptr.getCellRef().getPosition().rot[0]; + float yr = ptr.getCellRef().getPosition().rot[1]; + float zr = ptr.getCellRef().getPosition().rot[2]; - MWBase::Environment::get().getWorld()->rotateObject(ptr, 0,0,0,true); + MWBase::Environment::get().getWorld()->rotateObject(ptr, xr, yr, zr); dynamic_cast(runtime.getContext()).updatePtr( MWBase::Environment::get().getWorld()->moveObject(ptr, ptr.getCellRef().getPosition().pos[0], diff --git a/apps/openmw/mwworld/refdata.cpp b/apps/openmw/mwworld/refdata.cpp index 88a6fa353..87cbc586f 100644 --- a/apps/openmw/mwworld/refdata.cpp +++ b/apps/openmw/mwworld/refdata.cpp @@ -17,7 +17,6 @@ namespace MWWorld mEnabled = refData.mEnabled; mCount = refData.mCount; mPosition = refData.mPosition; - mLocalRotation = refData.mLocalRotation; mChanged = refData.mChanged; mDeleted = refData.mDeleted; @@ -37,7 +36,6 @@ namespace MWWorld { for (int i=0; i<3; ++i) { - mLocalRotation.rot[i] = 0; mPosition.pos[i] = 0; mPosition.rot[i] = 0; } @@ -49,9 +47,6 @@ namespace MWWorld mCustomData (0), mChanged(false) // Loading from ESM/ESP files -> assume unchanged { - mLocalRotation.rot[0]=0; - mLocalRotation.rot[1]=0; - mLocalRotation.rot[2]=0; } RefData::RefData (const ESM::ObjectState& objectState) @@ -62,8 +57,6 @@ namespace MWWorld mCustomData (0), mChanged(true) // Loading from a savegame -> assume changed { - for (int i=0; i<3; ++i) - mLocalRotation.rot[i] = objectState.mLocalRotation[i]; } RefData::RefData (const RefData& refData) @@ -87,9 +80,6 @@ namespace MWWorld objectState.mEnabled = mEnabled; objectState.mCount = mCount; objectState.mPosition = mPosition; - - for (int i=0; i<3; ++i) - objectState.mLocalRotation[i] = mLocalRotation.rot[i]; } RefData& RefData::operator= (const RefData& refData) @@ -197,17 +187,6 @@ namespace MWWorld return mPosition; } - void RefData::setLocalRotation(const LocalRotation& rot) - { - mChanged = true; - mLocalRotation = rot; - } - - const LocalRotation& RefData::getLocalRotation() - { - return mLocalRotation; - } - void RefData::setCustomData (CustomData *data) { mChanged = true; // We do not currently track CustomData, so assume anything with a CustomData is changed diff --git a/apps/openmw/mwworld/refdata.hpp b/apps/openmw/mwworld/refdata.hpp index 4075f62ce..13a71ec33 100644 --- a/apps/openmw/mwworld/refdata.hpp +++ b/apps/openmw/mwworld/refdata.hpp @@ -21,9 +21,6 @@ namespace ESM namespace MWWorld { - struct LocalRotation{ - float rot[3]; - }; class CustomData; @@ -40,8 +37,6 @@ namespace MWWorld ESM::Position mPosition; - LocalRotation mLocalRotation; - CustomData *mCustomData; void copy (const RefData& refData); @@ -110,9 +105,6 @@ namespace MWWorld void setPosition (const ESM::Position& pos); const ESM::Position& getPosition(); - void setLocalRotation (const LocalRotation& rotation); - const LocalRotation& getLocalRotation(); - void setCustomData (CustomData *data); ///< Set custom data (potentially replacing old custom data). The ownership of \a data is /// transferred to this. diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 83a7a9f2c..919eeb18f 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -52,15 +52,7 @@ namespace worldRotQuat = worldRotQuat * osg::Quat(ptr.getRefData().getPosition().rot[1], osg::Vec3(0,-1,0)) * osg::Quat(ptr.getRefData().getPosition().rot[0], osg::Vec3(-1,0,0)); - float x = ptr.getRefData().getLocalRotation().rot[0]; - float y = ptr.getRefData().getLocalRotation().rot[1]; - float z = ptr.getRefData().getLocalRotation().rot[2]; - - osg::Quat rot(z, osg::Vec3(0,0,-1)); - if (!ptr.getClass().isActor()) - rot = rot * osg::Quat(y, osg::Vec3(0,-1,0)) * osg::Quat(x, osg::Vec3(-1,0,0)); - - rendering.rotateObject(ptr, rot * worldRotQuat); + rendering.rotateObject(ptr, worldRotQuat); physics.updateRotation(ptr); } } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 20a84d6b1..03f2c1ab8 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1258,21 +1258,6 @@ namespace MWWorld mWorldScene->updateObjectLocalRotation(ptr); } - void World::localRotateObject (const Ptr& ptr, float x, float y, float z) - { - LocalRotation rot = ptr.getRefData().getLocalRotation(); - rot.rot[0]=osg::DegreesToRadians(x); - rot.rot[1]=osg::DegreesToRadians(y); - rot.rot[2]=osg::DegreesToRadians(z); - - ptr.getRefData().setLocalRotation(rot); - - if (ptr.getRefData().getBaseNode() != 0) - { - mWorldScene->updateObjectLocalRotation(ptr); - } - } - void World::adjustPosition(const Ptr &ptr, bool force) { ESM::Position pos (ptr.getRefData().getPosition()); @@ -1829,11 +1814,6 @@ namespace MWWorld object.getClass().copyToCell(object, *cell, pos); // Reset some position values that could be uninitialized if this item came from a container - LocalRotation localRotation; - localRotation.rot[0] = 0; - localRotation.rot[1] = 0; - localRotation.rot[2] = 0; - dropped.getRefData().setLocalRotation(localRotation); dropped.getCellRef().setPosition(pos); dropped.getCellRef().unsetRefNum(); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 4b3cc5eb7..9ff3e7d1f 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -353,9 +353,6 @@ namespace MWWorld /// \param adjust indicates rotation should be set or adjusted virtual void rotateObject (const Ptr& ptr,float x,float y,float z, bool adjust = false); - /// Local rotates object, uses degrees - virtual void localRotateObject (const Ptr& ptr, float x, float y, float z); - virtual MWWorld::Ptr safePlaceObject(const MWWorld::Ptr& ptr, MWWorld::CellStore* cell, ESM::Position pos); ///< place an object in a "safe" location (ie not in the void, etc). Makes a copy of the Ptr. diff --git a/components/esm/objectstate.cpp b/components/esm/objectstate.cpp index 62aa0452a..4fd4245c7 100644 --- a/components/esm/objectstate.cpp +++ b/components/esm/objectstate.cpp @@ -23,7 +23,8 @@ void ESM::ObjectState::load (ESMReader &esm) esm.getHNOT (mPosition, "POS_", 24); - esm.getHNOT (mLocalRotation, "LROT", 12); + if (esm.isNextSub("LROT")) + esm.skipHSub(); // local rotation, no longer used // obsolete int unused; @@ -51,10 +52,7 @@ void ESM::ObjectState::save (ESMWriter &esm, bool inInventory) const esm.writeHNT ("COUN", mCount); if (!inInventory) - { esm.writeHNT ("POS_", mPosition, 24); - esm.writeHNT ("LROT", mLocalRotation, 12); - } if (!mHasCustomState) esm.writeHNT ("HCUS", false); @@ -70,7 +68,6 @@ void ESM::ObjectState::blank() { mPosition.pos[i] = 0; mPosition.rot[i] = 0; - mLocalRotation[i] = 0; } mHasCustomState = true; } diff --git a/components/esm/objectstate.hpp b/components/esm/objectstate.hpp index 674bcb8fc..215cb74ba 100644 --- a/components/esm/objectstate.hpp +++ b/components/esm/objectstate.hpp @@ -24,7 +24,6 @@ namespace ESM unsigned char mEnabled; int mCount; ESM::Position mPosition; - float mLocalRotation[3]; // Is there any class-specific state following the ObjectState bool mHasCustomState; From 3647af8d731fc15c4197ed5528b6c2fa180bd13d Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 12 Nov 2015 01:44:00 +0100 Subject: [PATCH 2430/3725] Rotations: use different rotation order when object is rotated via script (Fixes #2062) --- apps/openmw/mwworld/scene.cpp | 23 +++++++++++++++-------- apps/openmw/mwworld/scene.hpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 2 +- apps/openmw/mwworld/worldimp.hpp | 2 ++ 4 files changed, 19 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 919eeb18f..1ba17a967 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -42,15 +42,22 @@ namespace rendering.addWaterRippleEmitter(ptr); } - void updateObjectLocalRotation (const MWWorld::Ptr& ptr, MWPhysics::PhysicsSystem& physics, - MWRender::RenderingManager& rendering) + void updateObjectRotation (const MWWorld::Ptr& ptr, MWPhysics::PhysicsSystem& physics, + MWRender::RenderingManager& rendering, bool inverseRotationOrder) { if (ptr.getRefData().getBaseNode() != NULL) { osg::Quat worldRotQuat(ptr.getRefData().getPosition().rot[2], osg::Vec3(0,0,-1)); if (!ptr.getClass().isActor()) - worldRotQuat = worldRotQuat * osg::Quat(ptr.getRefData().getPosition().rot[1], osg::Vec3(0,-1,0)) * - osg::Quat(ptr.getRefData().getPosition().rot[0], osg::Vec3(-1,0,0)); + { + float xr = ptr.getRefData().getPosition().rot[0]; + float yr = ptr.getRefData().getPosition().rot[1]; + if (!inverseRotationOrder) + worldRotQuat = worldRotQuat * osg::Quat(yr, osg::Vec3(0,-1,0)) * + osg::Quat(xr, osg::Vec3(-1,0,0)); + else + worldRotQuat = osg::Quat(xr, osg::Vec3(-1,0,0)) * osg::Quat(yr, osg::Vec3(0,-1,0)) * worldRotQuat; + } rendering.rotateObject(ptr, worldRotQuat); physics.updateRotation(ptr); @@ -106,7 +113,7 @@ namespace try { addObject(ptr, mPhysics, mRendering); - updateObjectLocalRotation(ptr, mPhysics, mRendering); + updateObjectRotation(ptr, mPhysics, mRendering, false); updateObjectScale(ptr, mPhysics, mRendering); ptr.getClass().adjustPosition (ptr, false); } @@ -127,9 +134,9 @@ namespace namespace MWWorld { - void Scene::updateObjectLocalRotation (const Ptr& ptr) + void Scene::updateObjectRotation (const Ptr& ptr, bool inverseRotationOrder) { - ::updateObjectLocalRotation(ptr, *mPhysics, mRendering); + ::updateObjectRotation(ptr, *mPhysics, mRendering, inverseRotationOrder); } void Scene::updateObjectScale(const Ptr &ptr) @@ -548,7 +555,7 @@ namespace MWWorld try { addObject(ptr, *mPhysics, mRendering); - MWBase::Environment::get().getWorld()->rotateObject(ptr, 0, 0, 0, true); + updateObjectRotation(ptr, false); MWBase::Environment::get().getWorld()->scaleObject(ptr, ptr.getCellRef().getScale()); } catch (std::exception& e) diff --git a/apps/openmw/mwworld/scene.hpp b/apps/openmw/mwworld/scene.hpp index ca6ed83b9..439c8d72c 100644 --- a/apps/openmw/mwworld/scene.hpp +++ b/apps/openmw/mwworld/scene.hpp @@ -107,7 +107,7 @@ namespace MWWorld void removeObjectFromScene (const Ptr& ptr); ///< Remove an object from the scene, but not from the world model. - void updateObjectLocalRotation (const Ptr& ptr); + void updateObjectRotation (const Ptr& ptr, bool inverseRotationOrder); void updateObjectScale(const Ptr& ptr); bool isCellActive(const CellStore &cell); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 03f2c1ab8..b800db4a2 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1255,7 +1255,7 @@ namespace MWWorld ptr.getRefData().setPosition(pos); if(ptr.getRefData().getBaseNode() != 0) - mWorldScene->updateObjectLocalRotation(ptr); + mWorldScene->updateObjectRotation(ptr, true); } void World::adjustPosition(const Ptr &ptr, bool force) diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 9ff3e7d1f..9f4928120 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -350,6 +350,8 @@ namespace MWWorld virtual void scaleObject (const Ptr& ptr, float scale); /// World rotates object, uses radians + /// @note Rotations via this method use a different rotation order than the initial rotations in the CS. This + /// could be considered a bug, but is needed for MW compatibility. /// \param adjust indicates rotation should be set or adjusted virtual void rotateObject (const Ptr& ptr,float x,float y,float z, bool adjust = false); From 90b6fa5ef1f16b5a5744216115268ae3b5a2a955 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 11 Nov 2015 21:19:50 +0100 Subject: [PATCH 2431/3725] PlaceItem, PlaceItemCell angle should be treated as degrees (Fixes #3007) --- apps/openmw/mwscript/transformationextensions.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index f41bb8842..b2b21a532 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -402,7 +402,7 @@ namespace MWScript runtime.pop(); Interpreter::Type_Float z = runtime[0].mFloat; runtime.pop(); - Interpreter::Type_Float zRot = runtime[0].mFloat; + Interpreter::Type_Float zRotDegrees = runtime[0].mFloat; runtime.pop(); MWWorld::CellStore* store = 0; @@ -429,7 +429,7 @@ namespace MWScript pos.pos[1] = y; pos.pos[2] = z; pos.rot[0] = pos.rot[1] = 0; - pos.rot[2] = zRot; + pos.rot[2] = osg::DegreesToRadians(zRotDegrees); MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(),itemID); ref.getPtr().getCellRef().setPosition(pos); MWWorld::Ptr placed = MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),store,pos); @@ -454,7 +454,7 @@ namespace MWScript runtime.pop(); Interpreter::Type_Float z = runtime[0].mFloat; runtime.pop(); - Interpreter::Type_Float zRot = runtime[0].mFloat; + Interpreter::Type_Float zRotDegrees = runtime[0].mFloat; runtime.pop(); MWWorld::Ptr player = MWMechanics::getPlayer(); @@ -473,7 +473,7 @@ namespace MWScript pos.pos[1] = y; pos.pos[2] = z; pos.rot[0] = pos.rot[1] = 0; - pos.rot[2] = zRot; + pos.rot[2] = osg::DegreesToRadians(zRotDegrees); MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(),itemID); ref.getPtr().getCellRef().setPosition(pos); MWWorld::Ptr placed = MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),store,pos); From 9e3eb8291fe5bf0e380f057809794d589ee5be5b Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 12 Nov 2015 02:09:00 +0100 Subject: [PATCH 2432/3725] Rotations: fix the rotation order for doors --- apps/openmw/mwworld/worldimp.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index b800db4a2..f82392662 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1393,6 +1393,8 @@ namespace MWWorld float diff = duration * osg::DegreesToRadians(90.f); float targetRot = std::min(std::max(minRot, oldRot + diff * (it->second == 1 ? 1 : -1)), maxRot); rotateObject(it->first, objPos.rot[0], objPos.rot[1], targetRot); + // the rotation order we want to use + mWorldScene->updateObjectRotation(it->first, false); bool reached = (targetRot == maxRot && it->second) || targetRot == minRot; From 19cd987208a18ae098327699d3828404b0f52e13 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 12 Nov 2015 14:32:39 +0100 Subject: [PATCH 2433/3725] Fix Ptr updates in PositionCell This was not the proper way to get the updated Ptr, it will only work for the player which isn't owned by any cell. For other objects, moving between cells makes the object owned by that cell and thus the getBase() pointer will change. --- apps/openmw/mwscript/transformationextensions.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index b2b21a532..35e61ab56 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -312,8 +312,8 @@ namespace MWScript } if(store) { - MWBase::Environment::get().getWorld()->moveObject(ptr,store,x,y,z); - ptr = MWWorld::Ptr(ptr.getBase(), store); + ptr = MWBase::Environment::get().getWorld()->moveObject(ptr,store,x,y,z); + dynamic_cast(runtime.getContext()).updatePtr(ptr); float ax = osg::RadiansToDegrees(ptr.getRefData().getPosition().rot[0]); @@ -363,8 +363,7 @@ namespace MWScript if (ptr == MWMechanics::getPlayer()) { MWWorld::CellStore* cell = MWBase::Environment::get().getWorld()->getExterior(cx,cy); - MWBase::Environment::get().getWorld()->moveObject(ptr,cell,x,y,z); - ptr = MWWorld::Ptr(ptr.getBase(), cell); + ptr = MWBase::Environment::get().getWorld()->moveObject(ptr,cell,x,y,z); } else { From 01f4b8a182a1722df661b933cd39001b7e10b837 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 12 Nov 2015 15:05:17 +0100 Subject: [PATCH 2434/3725] added scene tooltips system (tag based) --- apps/opencs/model/settings/usersettings.cpp | 14 ++++++ apps/opencs/view/render/tagbase.cpp | 5 ++ apps/opencs/view/render/tagbase.hpp | 5 ++ apps/opencs/view/render/worldspacewidget.cpp | 51 +++++++++++++++++--- apps/opencs/view/render/worldspacewidget.hpp | 10 +++- 5 files changed, 77 insertions(+), 8 deletions(-) diff --git a/apps/opencs/model/settings/usersettings.cpp b/apps/opencs/model/settings/usersettings.cpp index e8568cac1..8bf24ae34 100644 --- a/apps/opencs/model/settings/usersettings.cpp +++ b/apps/opencs/model/settings/usersettings.cpp @@ -426,6 +426,20 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() dragShiftFactor->setRange (0.001, 100.0); } + declareSection ("tooltips", "Tooltips"); + { + Setting *scene = createSetting (Type_CheckBox, "scene", "Show Tooltips in 3D scenes"); + scene->setDefaultValue ("true"); + + Setting *sceneHideBasic = createSetting (Type_CheckBox, "scene-hide-basic", "Hide basic 3D scenes tooltips"); + sceneHideBasic->setDefaultValue ("false"); + + Setting *sceneDelay = createSetting (Type_SpinBox, "scene-delay", + "Tooltip delay in milliseconds"); + sceneDelay->setDefaultValue (500); + sceneDelay->setRange (1, 10000); + } + { /****************************************************************** * There are three types of values: diff --git a/apps/opencs/view/render/tagbase.cpp b/apps/opencs/view/render/tagbase.cpp index af9a37624..79412c132 100644 --- a/apps/opencs/view/render/tagbase.cpp +++ b/apps/opencs/view/render/tagbase.cpp @@ -7,3 +7,8 @@ CSVRender::Elements CSVRender::TagBase::getElement() const { return mElement; } + +QString CSVRender::TagBase::getToolTip (bool hideBasics) const +{ + return ""; +} diff --git a/apps/opencs/view/render/tagbase.hpp b/apps/opencs/view/render/tagbase.hpp index 874b856c6..9f169c3b1 100644 --- a/apps/opencs/view/render/tagbase.hpp +++ b/apps/opencs/view/render/tagbase.hpp @@ -3,6 +3,8 @@ #include +#include + #include "elements.hpp" namespace CSVRender @@ -16,6 +18,9 @@ namespace CSVRender TagBase (Elements element); Elements getElement() const; + + virtual QString getToolTip (bool hideBasics) const; + }; } diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index e76582b94..0deb49840 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -43,7 +44,8 @@ namespace CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidget* parent) : SceneWidget (document.getData().getResourceSystem(), parent), mSceneElements(0), mRun(0), mDocument(document), - mInteractionMask (0), mEditMode (0), mLocked (false), mDragging (false) + mInteractionMask (0), mEditMode (0), mLocked (false), mDragging (false), + mToolTipPos (-1, -1) { setAcceptDrops(true); @@ -85,6 +87,12 @@ CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidg mDragFactor = CSMSettings::UserSettings::instance().settingValue ("scene-input/drag-factor").toDouble(); mDragWheelFactor = CSMSettings::UserSettings::instance().settingValue ("scene-input/drag-wheel-factor").toDouble(); mDragShiftFactor = CSMSettings::UserSettings::instance().settingValue ("scene-input/drag-shift-factor").toDouble(); + + mShowToolTips = CSMSettings::UserSettings::instance().settingValue ("tooltips/scene") == "true"; + mToolTipDelay = CSMSettings::UserSettings::instance().settingValue ("tooltips/scene-delay").toInt(); + + mToolTipDelayTimer.setSingleShot (true); + connect (&mToolTipDelayTimer, SIGNAL (timeout()), this, SLOT (showToolTip())); } CSVRender::WorldspaceWidget::~WorldspaceWidget () @@ -294,6 +302,10 @@ void CSVRender::WorldspaceWidget::updateUserSetting (const QString& name, const mDragWheelFactor = value.at (0).toDouble(); else if (name=="scene-input/drag-shift-factor") mDragShiftFactor = value.at (0).toDouble(); + else if (name=="tooltips/scene-delay") + mToolTipDelay = value.at (0).toInt(); + else if (name=="tooltips/scene") + mShowToolTips = value.at (0)=="true"; else dynamic_cast (*mEditMode->getCurrent()).updateUserSetting (name, value); } @@ -368,11 +380,11 @@ bool CSVRender::WorldspaceWidget::storeMappingSetting (const QString& key, const return false; } -osg::ref_ptr CSVRender::WorldspaceWidget::mousePick (QMouseEvent *event) +osg::ref_ptr CSVRender::WorldspaceWidget::mousePick (const QPoint& localPos) { // (0,0) is considered the lower left corner of an OpenGL window - int x = event->x(); - int y = height() - event->y(); + int x = localPos.x(); + int y = height() - localPos.y(); osg::ref_ptr intersector (new osgUtil::LineSegmentIntersector(osgUtil::Intersector::WINDOW, x, y)); @@ -494,6 +506,21 @@ void CSVRender::WorldspaceWidget::editModeChanged (const std::string& id) mDragging = false; } +void CSVRender::WorldspaceWidget::showToolTip() +{ + if (mShowToolTips) + { + QPoint pos = QCursor::pos(); + + if (osg::ref_ptr tag = mousePick (mapFromGlobal (pos))) + { + bool hideBasics = + CSMSettings::UserSettings::instance().settingValue ("tooltips/scene-hide-basic")=="true"; + QToolTip::showText (pos, tag->getToolTip (hideBasics), this); + } + } +} + void CSVRender::WorldspaceWidget::elementSelectionChanged() { setVisibilityMask (getVisibilityMask()); @@ -509,13 +536,23 @@ void CSVRender::WorldspaceWidget::mouseMoveEvent (QMouseEvent *event) { if (!mDragging) { - if (mDragMode=="p-navi" || mDragMode=="s-navi") + if (mDragMode.empty()) + { + if (event->globalPos()!=mToolTipPos) + { + mToolTipPos = event->globalPos(); + + if (mShowToolTips) + mToolTipDelayTimer.start (mToolTipDelay); + } + } + else if (mDragMode=="p-navi" || mDragMode=="s-navi") { } else if (mDragMode=="p-edit" || mDragMode=="s-edit" || mDragMode=="p-select" || mDragMode=="s-select") { - osg::ref_ptr tag = mousePick (event); + osg::ref_ptr tag = mousePick (event->pos()); EditMode& editMode = dynamic_cast (*mEditMode->getCurrent()); @@ -595,7 +632,7 @@ void CSVRender::WorldspaceWidget::mouseReleaseEvent (QMouseEvent *event) else if (button=="p-edit" || button=="s-edit" || button=="p-select" || button=="s-select") { - osg::ref_ptr tag = mousePick (event); + osg::ref_ptr tag = mousePick (event->pos()); handleMouseClick (tag, button, event->modifiers() & Qt::ShiftModifier); } diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp index c2d61e75b..0b5ae2523 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -5,6 +5,8 @@ #include +#include + #include "../../model/doc/document.hpp" #include "../../model/world/tablemimedata.hpp" @@ -47,6 +49,10 @@ namespace CSVRender double mDragFactor; double mDragWheelFactor; double mDragShiftFactor; + QTimer mToolTipDelayTimer; + QPoint mToolTipPos; + bool mShowToolTips; + int mToolTipDelay; public: @@ -147,7 +153,7 @@ namespace CSVRender /// \return Is \a key a button mapping setting? (ignored otherwise) bool storeMappingSetting (const QString& key, const QString& value); - osg::ref_ptr mousePick (QMouseEvent *event); + osg::ref_ptr mousePick (const QPoint& localPos); std::string mapButton (QMouseEvent *event); @@ -179,6 +185,8 @@ namespace CSVRender void editModeChanged (const std::string& id); + void showToolTip(); + protected slots: void elementSelectionChanged(); From 8b01f1f6fbcfcc4aaffe4667fa6aa98b49a9eba0 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 12 Nov 2015 15:09:43 +0100 Subject: [PATCH 2435/3725] added instance tooltips --- apps/opencs/view/render/object.cpp | 5 +++++ apps/opencs/view/render/object.hpp | 2 ++ 2 files changed, 7 insertions(+) diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index ac96cb283..c295a023a 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -42,6 +42,11 @@ CSVRender::ObjectTag::ObjectTag (Object* object) : TagBase (Element_Reference), mObject (object) {} +QString CSVRender::ObjectTag::getToolTip (bool hideBasics) const +{ + return QString::fromUtf8 (mObject->getReferenceableId().c_str()); +} + void CSVRender::Object::clear() { diff --git a/apps/opencs/view/render/object.hpp b/apps/opencs/view/render/object.hpp index 0858a2edb..e7638e7a9 100644 --- a/apps/opencs/view/render/object.hpp +++ b/apps/opencs/view/render/object.hpp @@ -46,6 +46,8 @@ namespace CSVRender ObjectTag (Object* object); Object* mObject; + + virtual QString getToolTip (bool hideBasics) const; }; From 8d2990cc03d55a8768904a56403af63f13785714 Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Wed, 11 Nov 2015 08:45:34 +0100 Subject: [PATCH 2436/3725] add support for ffmpeg29 thanks to Andreas Cadhalpun; https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=803848 --- extern/osg-ffmpeg-videoplayer/videostate.cpp | 33 ++++++++------------ 1 file changed, 13 insertions(+), 20 deletions(-) diff --git a/extern/osg-ffmpeg-videoplayer/videostate.cpp b/extern/osg-ffmpeg-videoplayer/videostate.cpp index f143088e8..fb392bb4d 100644 --- a/extern/osg-ffmpeg-videoplayer/videostate.cpp +++ b/extern/osg-ffmpeg-videoplayer/videostate.cpp @@ -90,16 +90,6 @@ void PacketQueue::put(AVPacket *pkt) pkt1->pkt = *pkt; pkt1->next = NULL; - if(pkt->data != flush_pkt.data && pkt1->pkt.destruct == NULL) - { - if(av_dup_packet(&pkt1->pkt) < 0) - { - av_free(pkt1); - throw std::runtime_error("Failed to duplicate packet"); - } - av_free_packet(pkt); - } - this->mutex.lock (); if(!last_pkt) @@ -313,7 +303,7 @@ int VideoState::queue_picture(AVFrame *pFrame, double pts) int w = (*this->video_st)->codec->width; int h = (*this->video_st)->codec->height; this->sws_context = sws_getContext(w, h, (*this->video_st)->codec->pix_fmt, - w, h, PIX_FMT_RGBA, SWS_BICUBIC, + w, h, AV_PIX_FMT_RGBA, SWS_BICUBIC, NULL, NULL, NULL); if(this->sws_context == NULL) throw std::runtime_error("Cannot initialize the conversion context!\n"); @@ -354,24 +344,28 @@ double VideoState::synchronize_video(AVFrame *src_frame, double pts) return pts; } - +static void our_free_buffer(void *opaque, uint8_t *data); /* These are called whenever we allocate a frame * buffer. We use this to store the global_pts in * a frame at the time it is allocated. */ static int64_t global_video_pkt_pts = AV_NOPTS_VALUE; -static int our_get_buffer(struct AVCodecContext *c, AVFrame *pic) +static int our_get_buffer(struct AVCodecContext *c, AVFrame *pic, int flags) { - int ret = avcodec_default_get_buffer(c, pic); + AVBufferRef *ref; + int ret = avcodec_default_get_buffer2(c, pic, flags); int64_t *pts = (int64_t*)av_malloc(sizeof(int64_t)); *pts = global_video_pkt_pts; pic->opaque = pts; + ref = av_buffer_create((uint8_t *)pic->opaque, sizeof(int64_t), our_free_buffer, pic->buf[0], flags); + pic->buf[0] = ref; return ret; } -static void our_release_buffer(struct AVCodecContext *c, AVFrame *pic) +static void our_free_buffer(void *opaque, uint8_t *data) { - if(pic) av_freep(&pic->opaque); - avcodec_default_release_buffer(c, pic); + AVBufferRef *ref = (AVBufferRef *)opaque; + av_buffer_unref(&ref); + av_free(data); } @@ -384,7 +378,7 @@ void VideoState::video_thread_loop(VideoState *self) pFrame = av_frame_alloc(); self->rgbaFrame = av_frame_alloc(); - avpicture_alloc((AVPicture*)self->rgbaFrame, PIX_FMT_RGBA, (*self->video_st)->codec->width, (*self->video_st)->codec->height); + avpicture_alloc((AVPicture*)self->rgbaFrame, AV_PIX_FMT_RGBA, (*self->video_st)->codec->width, (*self->video_st)->codec->height); while(self->videoq.get(packet, self) >= 0) { @@ -589,8 +583,7 @@ int VideoState::stream_open(int stream_index, AVFormatContext *pFormatCtx) case AVMEDIA_TYPE_VIDEO: this->video_st = pFormatCtx->streams + stream_index; - codecCtx->get_buffer = our_get_buffer; - codecCtx->release_buffer = our_release_buffer; + codecCtx->get_buffer2 = our_get_buffer; this->video_thread = boost::thread(video_thread_loop, this); break; From bdfd1c217b926a4f89dac064fe449d7939ef5a29 Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Wed, 11 Nov 2015 09:37:27 +0100 Subject: [PATCH 2437/3725] try using precise ffmpeg library instead of libav --- CI/before_install.linux.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CI/before_install.linux.sh b/CI/before_install.linux.sh index 2efb6e2bb..37f98c141 100755 --- a/CI/before_install.linux.sh +++ b/CI/before_install.linux.sh @@ -14,7 +14,7 @@ echo "yes" | sudo apt-add-repository ppa:boost-latest/ppa sudo apt-get update -qq sudo apt-get install -qq libgtest-dev google-mock sudo apt-get install -qq libboost-filesystem1.55-dev libboost-program-options1.55-dev libboost-system1.55-dev libboost-thread1.55-dev -sudo apt-get install -qq libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libavresample-dev +sudo apt-get install -qq libavcodec-ffmpeg-opti-dev libavformat-ffmpeg-opti-dev libavutil-ffmpeg-opti-dev libswscale-ffmpeg-opti-dev libswresample-ffmpeg-opti-dev sudo apt-get install -qq libbullet-dev libopenscenegraph-dev libmygui-dev libsdl2-dev libunshield-dev libtinyxml-dev libopenal-dev libqt4-dev sudo apt-get install -qq cmake-data #workaround for broken osgqt cmake script in ubuntu 12.04 if [ "${ANALYZE}" ]; then sudo apt-get install -qq clang-3.6; fi From 1e8eddc5b47deb32752871bbbaffa06cf6cc547e Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Wed, 11 Nov 2015 09:45:01 +0100 Subject: [PATCH 2438/3725] another try --- CI/before_install.linux.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CI/before_install.linux.sh b/CI/before_install.linux.sh index 37f98c141..9edcf55cc 100755 --- a/CI/before_install.linux.sh +++ b/CI/before_install.linux.sh @@ -14,7 +14,7 @@ echo "yes" | sudo apt-add-repository ppa:boost-latest/ppa sudo apt-get update -qq sudo apt-get install -qq libgtest-dev google-mock sudo apt-get install -qq libboost-filesystem1.55-dev libboost-program-options1.55-dev libboost-system1.55-dev libboost-thread1.55-dev -sudo apt-get install -qq libavcodec-ffmpeg-opti-dev libavformat-ffmpeg-opti-dev libavutil-ffmpeg-opti-dev libswscale-ffmpeg-opti-dev libswresample-ffmpeg-opti-dev +sudo apt-get install -qq ffmpeg-real ffmpeg-opti libavcodec-ffmpeg-opti-dev libavformat-ffmpeg-opti-dev libavutil-ffmpeg-opti-dev libswscale-ffmpeg-opti-dev libswresample-ffmpeg-opti-dev sudo apt-get install -qq libbullet-dev libopenscenegraph-dev libmygui-dev libsdl2-dev libunshield-dev libtinyxml-dev libopenal-dev libqt4-dev sudo apt-get install -qq cmake-data #workaround for broken osgqt cmake script in ubuntu 12.04 if [ "${ANALYZE}" ]; then sudo apt-get install -qq clang-3.6; fi From 9d5e7b34c6e1f934bbf0851c6005a0c749f0645e Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Wed, 11 Nov 2015 23:18:51 +0100 Subject: [PATCH 2439/3725] use ffmpeg from our repo --- CI/before_install.linux.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CI/before_install.linux.sh b/CI/before_install.linux.sh index 9edcf55cc..6e288aa14 100755 --- a/CI/before_install.linux.sh +++ b/CI/before_install.linux.sh @@ -14,7 +14,7 @@ echo "yes" | sudo apt-add-repository ppa:boost-latest/ppa sudo apt-get update -qq sudo apt-get install -qq libgtest-dev google-mock sudo apt-get install -qq libboost-filesystem1.55-dev libboost-program-options1.55-dev libboost-system1.55-dev libboost-thread1.55-dev -sudo apt-get install -qq ffmpeg-real ffmpeg-opti libavcodec-ffmpeg-opti-dev libavformat-ffmpeg-opti-dev libavutil-ffmpeg-opti-dev libswscale-ffmpeg-opti-dev libswresample-ffmpeg-opti-dev +sudo apt-get install -qq ffmpeg libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libswresample-dev sudo apt-get install -qq libbullet-dev libopenscenegraph-dev libmygui-dev libsdl2-dev libunshield-dev libtinyxml-dev libopenal-dev libqt4-dev sudo apt-get install -qq cmake-data #workaround for broken osgqt cmake script in ubuntu 12.04 if [ "${ANALYZE}" ]; then sudo apt-get install -qq clang-3.6; fi From 39f89f967b16d4368130a95a2b33aa2a04cbe4b7 Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Thu, 12 Nov 2015 12:44:40 +0100 Subject: [PATCH 2440/3725] from kcat: We can't simply get rid of this, otherwise it may break for certain kinds of packets. --- extern/osg-ffmpeg-videoplayer/videostate.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/extern/osg-ffmpeg-videoplayer/videostate.cpp b/extern/osg-ffmpeg-videoplayer/videostate.cpp index fb392bb4d..3c9279ea2 100644 --- a/extern/osg-ffmpeg-videoplayer/videostate.cpp +++ b/extern/osg-ffmpeg-videoplayer/videostate.cpp @@ -85,6 +85,9 @@ void VideoState::setAudioFactory(MovieAudioFactory *factory) void PacketQueue::put(AVPacket *pkt) { AVPacketList *pkt1; + if(pkt != &flush_pkt && !pkt->buf && av_dup_packet(pkt) < 0) + throw std::runtime_error("Failed to duplicate packet"); + pkt1 = (AVPacketList*)av_malloc(sizeof(AVPacketList)); if(!pkt1) throw std::bad_alloc(); pkt1->pkt = *pkt; From 3ea3d07d4416ebc3f1f4400bc54e89a5f05d2349 Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Thu, 12 Nov 2015 16:38:54 +0100 Subject: [PATCH 2441/3725] really purge libav --- CMakeLists.txt | 15 +-- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwsound/ffmpeg_decoder.cpp | 10 -- apps/openmw/mwsound/ffmpeg_decoder.hpp | 6 - apps/openmw/mwsound/libavwrapper.cpp | 108 ----------------- extern/osg-ffmpeg-videoplayer/CMakeLists.txt | 1 - .../osg-ffmpeg-videoplayer/audiodecoder.cpp | 12 -- .../osg-ffmpeg-videoplayer/libavwrapper.cpp | 110 ------------------ 8 files changed, 3 insertions(+), 261 deletions(-) delete mode 100644 apps/openmw/mwsound/libavwrapper.cpp delete mode 100644 extern/osg-ffmpeg-videoplayer/libavwrapper.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index d33521e8b..58b88f621 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -107,22 +107,11 @@ unset(FFMPEG_LIBRARIES CACHE) find_package(FFmpeg REQUIRED) -set (FFMPEG_LIBRARIES ${FFMPEG_LIBRARIES} ${SWSCALE_LIBRARY}) +set (FFMPEG_LIBRARIES ${FFMPEG_LIBRARIES} ${SWSCALE_LIBRARY} ${SWRESAMPLE_LIBRARIES}) -if ( NOT AVCODEC_FOUND OR NOT AVFORMAT_FOUND OR NOT AVUTIL_FOUND OR NOT SWSCALE_FOUND ) +if ( NOT AVCODEC_FOUND OR NOT AVFORMAT_FOUND OR NOT AVUTIL_FOUND OR NOT SWSCALE_FOUND OR NOT SWRESAMPLE_FOUND) message(FATAL_ERROR "FFmpeg component required, but not found!") endif() -set(SOUND_INPUT_INCLUDES ${FFMPEG_INCLUDE_DIRS}) -if( SWRESAMPLE_FOUND ) - add_definitions(-DHAVE_LIBSWRESAMPLE) - set (FFMPEG_LIBRARIES ${FFMPEG_LIBRARIES} ${SWRESAMPLE_LIBRARIES}) -else() - if( AVRESAMPLE_FOUND ) - set (FFMPEG_LIBRARIES ${FFMPEG_LIBRARIES} ${AVRESAMPLE_LIBRARIES}) - else() - message(FATAL_ERROR "Install either libswresample (FFmpeg) or libavresample (Libav).") - endif() -endif() # Required for building the FFmpeg headers add_definitions(-D__STDC_CONSTANT_MACROS) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index fa05576f5..887eedebb 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -57,7 +57,7 @@ add_openmw_dir (mwscript ) add_openmw_dir (mwsound - soundmanagerimp openal_output ffmpeg_decoder sound sound_decoder sound_output loudness libavwrapper movieaudiofactory + soundmanagerimp openal_output ffmpeg_decoder sound sound_decoder sound_output loudness movieaudiofactory ) add_openmw_dir (mwworld diff --git a/apps/openmw/mwsound/ffmpeg_decoder.cpp b/apps/openmw/mwsound/ffmpeg_decoder.cpp index 6a586e81d..66b7e09e3 100644 --- a/apps/openmw/mwsound/ffmpeg_decoder.cpp +++ b/apps/openmw/mwsound/ffmpeg_decoder.cpp @@ -6,16 +6,6 @@ #include #include -extern "C" { -#ifndef HAVE_LIBSWRESAMPLE -// FIXME: remove this section once libswresample is packaged for Debian -int swr_init(AVAudioResampleContext *avr); -void swr_free(AVAudioResampleContext **avr); -int swr_convert( AVAudioResampleContext *avr, uint8_t** output, int out_samples, const uint8_t** input, int in_samples); -AVAudioResampleContext * swr_alloc_set_opts( AVAudioResampleContext *avr, int64_t out_ch_layout, AVSampleFormat out_fmt, int out_rate, int64_t in_ch_layout, AVSampleFormat in_fmt, int in_rate, int o, void* l); -#endif -} - #include namespace MWSound diff --git a/apps/openmw/mwsound/ffmpeg_decoder.hpp b/apps/openmw/mwsound/ffmpeg_decoder.hpp index da8e58964..b27e60c9f 100644 --- a/apps/openmw/mwsound/ffmpeg_decoder.hpp +++ b/apps/openmw/mwsound/ffmpeg_decoder.hpp @@ -22,13 +22,7 @@ extern "C" // From version 54.56 binkaudio encoding format changed from S16 to FLTP. See: // https://gitorious.org/ffmpeg/ffmpeg/commit/7bfd1766d1c18f07b0a2dd042418a874d49ea60d // http://ffmpeg.zeranoe.com/forum/viewtopic.php?f=15&t=872 -#ifdef HAVE_LIBSWRESAMPLE #include -#else -#include -#include -#define SwrContext AVAudioResampleContext -#endif } #include diff --git a/apps/openmw/mwsound/libavwrapper.cpp b/apps/openmw/mwsound/libavwrapper.cpp deleted file mode 100644 index 40be67176..000000000 --- a/apps/openmw/mwsound/libavwrapper.cpp +++ /dev/null @@ -1,108 +0,0 @@ -#ifndef HAVE_LIBSWRESAMPLE -extern "C" -{ -#include - -#include -#include -// From libavutil version 52.2.0 and onward the declaration of -// AV_CH_LAYOUT_* is removed from libavcodec/avcodec.h and moved to -// libavutil/channel_layout.h -#if AV_VERSION_INT(52, 2, 0) <= AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \ - LIBAVUTIL_VERSION_MINOR, LIBAVUTIL_VERSION_MICRO) - #include -#endif -#include -#include - -/* FIXME: delete this file once libswresample is packaged for Debian */ - -int swr_init(AVAudioResampleContext *avr) { return 1; } - -void swr_free(AVAudioResampleContext **avr) { avresample_free(avr); } - -int swr_convert( - AVAudioResampleContext *avr, - uint8_t** output, - int out_samples, - const uint8_t** input, - int in_samples) -{ - // FIXME: potential performance hit - int out_plane_size = 0; - int in_plane_size = 0; - return avresample_convert(avr, output, out_plane_size, out_samples, - (uint8_t **)input, in_plane_size, in_samples); -} - -AVAudioResampleContext * swr_alloc_set_opts( - AVAudioResampleContext *avr, - int64_t out_ch_layout, - AVSampleFormat out_fmt, - int out_rate, - int64_t in_ch_layout, - AVSampleFormat in_fmt, - int in_rate, - int o, - void* l) -{ - avr = avresample_alloc_context(); - if(!avr) - return 0; - - int res; - res = av_opt_set_int(avr, "out_channel_layout", out_ch_layout, 0); - if(res < 0) - { - av_log(avr, AV_LOG_ERROR, "av_opt_set_int: out_ch_layout = %d\n", res); - return 0; - } - res = av_opt_set_int(avr, "out_sample_fmt", out_fmt, 0); - if(res < 0) - { - av_log(avr, AV_LOG_ERROR, "av_opt_set_int: out_fmt = %d\n", res); - return 0; - } - res = av_opt_set_int(avr, "out_sample_rate", out_rate, 0); - if(res < 0) - { - av_log(avr, AV_LOG_ERROR, "av_opt_set_int: out_rate = %d\n", res); - return 0; - } - res = av_opt_set_int(avr, "in_channel_layout", in_ch_layout, 0); - if(res < 0) - { - av_log(avr, AV_LOG_ERROR, "av_opt_set_int: in_ch_layout = %d\n", res); - return 0; - } - res = av_opt_set_int(avr, "in_sample_fmt", in_fmt, 0); - if(res < 0) - { - av_log(avr, AV_LOG_ERROR, "av_opt_set_int: in_fmt = %d\n", res); - return 0; - } - res = av_opt_set_int(avr, "in_sample_rate", in_rate, 0); - if(res < 0) - { - av_log(avr, AV_LOG_ERROR, "av_opt_set_int: in_rate = %d\n", res); - return 0; - } - res = av_opt_set_int(avr, "internal_sample_fmt", AV_SAMPLE_FMT_FLTP, 0); - if(res < 0) - { - av_log(avr, AV_LOG_ERROR, "av_opt_set_int: internal_sample_fmt\n"); - return 0; - } - - - if(avresample_open(avr) < 0) - { - av_log(avr, AV_LOG_ERROR, "Error opening context\n"); - return 0; - } - else - return avr; -} - -} -#endif diff --git a/extern/osg-ffmpeg-videoplayer/CMakeLists.txt b/extern/osg-ffmpeg-videoplayer/CMakeLists.txt index 614a0804c..6009f69de 100644 --- a/extern/osg-ffmpeg-videoplayer/CMakeLists.txt +++ b/extern/osg-ffmpeg-videoplayer/CMakeLists.txt @@ -6,7 +6,6 @@ set(OSG_FFMPEG_VIDEOPLAYER_SOURCE_FILES videoplayer.cpp videostate.cpp videodefs.hpp - libavwrapper.cpp audiodecoder.cpp audiofactory.hpp ) diff --git a/extern/osg-ffmpeg-videoplayer/audiodecoder.cpp b/extern/osg-ffmpeg-videoplayer/audiodecoder.cpp index 77e6b4b6c..f095d1617 100644 --- a/extern/osg-ffmpeg-videoplayer/audiodecoder.cpp +++ b/extern/osg-ffmpeg-videoplayer/audiodecoder.cpp @@ -6,24 +6,12 @@ extern "C" #include - #ifdef HAVE_LIBSWRESAMPLE #include - #else - // FIXME: remove this section once libswresample is packaged for Debian - #include - #include - #define SwrContext AVAudioResampleContext - int swr_init(AVAudioResampleContext *avr); - void swr_free(AVAudioResampleContext **avr); - int swr_convert( AVAudioResampleContext *avr, uint8_t** output, int out_samples, const uint8_t** input, int in_samples); - AVAudioResampleContext * swr_alloc_set_opts( AVAudioResampleContext *avr, int64_t out_ch_layout, AVSampleFormat out_fmt, int out_rate, int64_t in_ch_layout, AVSampleFormat in_fmt, int in_rate, int o, void* l); - #endif #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(55,28,1) #define av_frame_alloc avcodec_alloc_frame #endif - } #include "videostate.hpp" diff --git a/extern/osg-ffmpeg-videoplayer/libavwrapper.cpp b/extern/osg-ffmpeg-videoplayer/libavwrapper.cpp deleted file mode 100644 index 26a7b6370..000000000 --- a/extern/osg-ffmpeg-videoplayer/libavwrapper.cpp +++ /dev/null @@ -1,110 +0,0 @@ -// This file is a wrapper around the libavresample library (the API-incompatible swresample replacement in the libav fork of ffmpeg), to make it look like swresample to the user. - -#ifndef HAVE_LIBSWRESAMPLE -extern "C" -{ -#include - -#include -#include -// From libavutil version 52.2.0 and onward the declaration of -// AV_CH_LAYOUT_* is removed from libavcodec/avcodec.h and moved to -// libavutil/channel_layout.h -#if AV_VERSION_INT(52, 2, 0) <= AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \ - LIBAVUTIL_VERSION_MINOR, LIBAVUTIL_VERSION_MICRO) - #include -#endif -#include -#include - -/* FIXME: delete this file once libswresample is packaged for Debian */ - -int swr_init(AVAudioResampleContext *avr) { return 1; } - -void swr_free(AVAudioResampleContext **avr) { avresample_free(avr); } - -int swr_convert( - AVAudioResampleContext *avr, - uint8_t** output, - int out_samples, - const uint8_t** input, - int in_samples) -{ - // FIXME: potential performance hit - int out_plane_size = 0; - int in_plane_size = 0; - return avresample_convert(avr, output, out_plane_size, out_samples, - (uint8_t **)input, in_plane_size, in_samples); -} - -AVAudioResampleContext * swr_alloc_set_opts( - AVAudioResampleContext *avr, - int64_t out_ch_layout, - AVSampleFormat out_fmt, - int out_rate, - int64_t in_ch_layout, - AVSampleFormat in_fmt, - int in_rate, - int o, - void* l) -{ - avr = avresample_alloc_context(); - if(!avr) - return 0; - - int res; - res = av_opt_set_int(avr, "out_channel_layout", out_ch_layout, 0); - if(res < 0) - { - av_log(avr, AV_LOG_ERROR, "av_opt_set_int: out_ch_layout = %d\n", res); - return 0; - } - res = av_opt_set_int(avr, "out_sample_fmt", out_fmt, 0); - if(res < 0) - { - av_log(avr, AV_LOG_ERROR, "av_opt_set_int: out_fmt = %d\n", res); - return 0; - } - res = av_opt_set_int(avr, "out_sample_rate", out_rate, 0); - if(res < 0) - { - av_log(avr, AV_LOG_ERROR, "av_opt_set_int: out_rate = %d\n", res); - return 0; - } - res = av_opt_set_int(avr, "in_channel_layout", in_ch_layout, 0); - if(res < 0) - { - av_log(avr, AV_LOG_ERROR, "av_opt_set_int: in_ch_layout = %d\n", res); - return 0; - } - res = av_opt_set_int(avr, "in_sample_fmt", in_fmt, 0); - if(res < 0) - { - av_log(avr, AV_LOG_ERROR, "av_opt_set_int: in_fmt = %d\n", res); - return 0; - } - res = av_opt_set_int(avr, "in_sample_rate", in_rate, 0); - if(res < 0) - { - av_log(avr, AV_LOG_ERROR, "av_opt_set_int: in_rate = %d\n", res); - return 0; - } - res = av_opt_set_int(avr, "internal_sample_fmt", AV_SAMPLE_FMT_FLTP, 0); - if(res < 0) - { - av_log(avr, AV_LOG_ERROR, "av_opt_set_int: internal_sample_fmt\n"); - return 0; - } - - - if(avresample_open(avr) < 0) - { - av_log(avr, AV_LOG_ERROR, "Error opening context\n"); - return 0; - } - else - return avr; -} - -} -#endif From af7b5e636e173a12c9b5799cc59d8f4b17fdb678 Mon Sep 17 00:00:00 2001 From: Emmanuel Anne Date: Wed, 30 Sep 2015 10:30:50 +0200 Subject: [PATCH 2442/3725] improves InterpreterContext::updatePtr This checks the update is really on the right pointer. It fixes the boat disappearing in "fishing academy", and it allows scripts linked to objects not to loose their default reference when using the object-> notation on another object. --- apps/openmw/mwscript/interpretercontext.cpp | 4 ++-- apps/openmw/mwscript/interpretercontext.hpp | 2 +- .../mwscript/transformationextensions.cpp | 19 ++++++++++--------- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index b0d4d3f2d..c70eb6cf8 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -601,9 +601,9 @@ namespace MWScript return mTargetId; } - void InterpreterContext::updatePtr(const MWWorld::Ptr& updated) + void InterpreterContext::updatePtr(const MWWorld::Ptr& base, const MWWorld::Ptr& updated) { - if (!mReference.isEmpty()) + if (!mReference.isEmpty() && base == mReference) mReference = updated; } } diff --git a/apps/openmw/mwscript/interpretercontext.hpp b/apps/openmw/mwscript/interpretercontext.hpp index d3841befd..3c43444cc 100644 --- a/apps/openmw/mwscript/interpretercontext.hpp +++ b/apps/openmw/mwscript/interpretercontext.hpp @@ -167,7 +167,7 @@ namespace MWScript MWWorld::Ptr getReference(bool required=true); ///< Reference, that the script is running from (can be empty) - void updatePtr(const MWWorld::Ptr& updated); + void updatePtr(const MWWorld::Ptr& base, const MWWorld::Ptr& updated); ///< Update the Ptr stored in mReference, if there is one stored there. Should be called after the reference has been moved to a new cell. virtual std::string getTargetId() const; diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 35e61ab56..f65035226 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -186,7 +186,7 @@ namespace MWScript runtime.push(ptr.getRefData().getPosition().pos[2]); } else - throw std::runtime_error ("invalid axis: " + axis); + throw std::runtime_error ("invalid axis: " + axis); } }; @@ -232,7 +232,7 @@ namespace MWScript else throw std::runtime_error ("invalid axis: " + axis); - dynamic_cast(runtime.getContext()).updatePtr(updated); + dynamic_cast(runtime.getContext()).updatePtr(ptr,updated); } }; @@ -300,7 +300,7 @@ namespace MWScript } catch(std::exception&) { - const ESM::Cell* cell = MWBase::Environment::get().getWorld()->getExterior(cellID); + const ESM::Cell* cell = MWBase::Environment::get().getWorld()->getExterior(cellID); int cx,cy; MWBase::Environment::get().getWorld()->positionToIndex(x,y,cx,cy); store = MWBase::Environment::get().getWorld()->getExterior(cx,cy); @@ -312,9 +312,9 @@ namespace MWScript } if(store) { + MWWorld::Ptr base = ptr; ptr = MWBase::Environment::get().getWorld()->moveObject(ptr,store,x,y,z); - - dynamic_cast(runtime.getContext()).updatePtr(ptr); + dynamic_cast(runtime.getContext()).updatePtr(base,ptr); float ax = osg::RadiansToDegrees(ptr.getRefData().getPosition().rot[0]); float ay = osg::RadiansToDegrees(ptr.getRefData().getPosition().rot[1]); @@ -360,6 +360,7 @@ namespace MWScript // another morrowind oddity: player will be moved to the exterior cell at this location, // non-player actors will move within the cell they are in. + MWWorld::Ptr base = ptr; if (ptr == MWMechanics::getPlayer()) { MWWorld::CellStore* cell = MWBase::Environment::get().getWorld()->getExterior(cx,cy); @@ -369,7 +370,7 @@ namespace MWScript { ptr = MWBase::Environment::get().getWorld()->moveObject(ptr, x, y, z); } - dynamic_cast(runtime.getContext()).updatePtr(ptr); + dynamic_cast(runtime.getContext()).updatePtr(base,ptr); float ax = osg::RadiansToDegrees(ptr.getRefData().getPosition().rot[0]); float ay = osg::RadiansToDegrees(ptr.getRefData().getPosition().rot[1]); @@ -626,7 +627,7 @@ namespace MWScript MWBase::Environment::get().getWorld()->rotateObject(ptr, xr, yr, zr); - dynamic_cast(runtime.getContext()).updatePtr( + dynamic_cast(runtime.getContext()).updatePtr(ptr, MWBase::Environment::get().getWorld()->moveObject(ptr, ptr.getCellRef().getPosition().pos[0], ptr.getCellRef().getPosition().pos[1], ptr.getCellRef().getPosition().pos[2])); @@ -744,8 +745,8 @@ namespace MWScript interpreter.installSegment5(Compiler::Transformation::opcodePositionExplicit,new OpPosition); interpreter.installSegment5(Compiler::Transformation::opcodePositionCell,new OpPositionCell); interpreter.installSegment5(Compiler::Transformation::opcodePositionCellExplicit,new OpPositionCell); - interpreter.installSegment5(Compiler::Transformation::opcodePlaceItemCell,new OpPlaceItemCell); - interpreter.installSegment5(Compiler::Transformation::opcodePlaceItem,new OpPlaceItem); + interpreter.installSegment5(Compiler::Transformation::opcodePlaceItemCell,new OpPlaceItemCell); + interpreter.installSegment5(Compiler::Transformation::opcodePlaceItem,new OpPlaceItem); interpreter.installSegment5(Compiler::Transformation::opcodePlaceAtPc,new OpPlaceAt); interpreter.installSegment5(Compiler::Transformation::opcodePlaceAtMe,new OpPlaceAt); interpreter.installSegment5(Compiler::Transformation::opcodePlaceAtMeExplicit,new OpPlaceAt); From 9897400d9702117183319b52959d354e459ef598 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 12 Nov 2015 19:03:24 +0100 Subject: [PATCH 2443/3725] Restore the previous key focus widget after playing video --- apps/openmw/mwgui/windowmanagerimp.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index a7c3a1957..114b8223d 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1743,6 +1743,7 @@ namespace MWGui MyGUI::IntSize screenSize = MyGUI::RenderManager::getInstance().getViewSize(); sizeVideo(screenSize.width, screenSize.height); + MyGUI::Widget* oldKeyFocus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); setKeyFocusWidget(mVideoWidget); mVideoBackground->setVisible(true); @@ -1770,6 +1771,8 @@ namespace MWGui MWBase::Environment::get().getSoundManager()->resumeSounds(); + setKeyFocusWidget(oldKeyFocus); + setCursorVisible(cursorWasVisible); // Restore normal rendering From 626281977eb2d0bc5c3549ce0409b0b5e4ed1cca Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 12 Nov 2015 19:40:31 +0100 Subject: [PATCH 2444/3725] Read NiLODNode (Bug #3008) --- components/nif/niffile.cpp | 2 ++ components/nif/node.hpp | 36 ++++++++++++++++++++++++++++++++++++ components/nif/record.hpp | 2 ++ 3 files changed, 40 insertions(+) diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index 1db9c8ccf..1387a97b0 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -48,6 +48,8 @@ static std::map makeFactory() { std::map newFactory; newFactory.insert(makeEntry("NiNode", &construct , RC_NiNode )); + newFactory.insert(makeEntry("NiSwitchNode", &construct , RC_NiSwitchNode )); + newFactory.insert(makeEntry("NiLODNode", &construct , RC_NiLODNode )); newFactory.insert(makeEntry("AvoidNode", &construct , RC_AvoidNode )); newFactory.insert(makeEntry("NiBSParticleNode", &construct , RC_NiBSParticleNode )); newFactory.insert(makeEntry("NiBSAnimationNode", &construct , RC_NiBSAnimationNode )); diff --git a/components/nif/node.hpp b/components/nif/node.hpp index 943ddcc66..326e9802f 100644 --- a/components/nif/node.hpp +++ b/components/nif/node.hpp @@ -250,5 +250,41 @@ struct NiRotatingParticles : Node } }; +// A node used as the base to switch between child nodes, such as for LOD levels. +struct NiSwitchNode : public NiNode +{ + void read(NIFStream *nif) + { + NiNode::read(nif); + nif->getInt(); // unknown + } +}; + +struct NiLODNode : public NiSwitchNode +{ + osg::Vec3f lodCenter; + + struct LODRange + { + float minRange; + float maxRange; + }; + std::vector lodLevels; + + void read(NIFStream *nif) + { + NiSwitchNode::read(nif); + lodCenter = nif->getVector3(); + unsigned int numLodLevels = nif->getUInt(); + for (unsigned int i=0; igetFloat(); + r.maxRange = nif->getFloat(); + lodLevels.push_back(r); + } + } +}; + } // Namespace #endif diff --git a/components/nif/record.hpp b/components/nif/record.hpp index 1022802cc..bcbdba115 100644 --- a/components/nif/record.hpp +++ b/components/nif/record.hpp @@ -36,6 +36,8 @@ enum RecordType { RC_MISSING = 0, RC_NiNode, + RC_NiSwitchNode, + RC_NiLODNode, RC_NiBillboardNode, RC_AvoidNode, RC_NiTriShape, From 0965a9059d76bac29af26a091e7c7ac0012ec39c Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 12 Nov 2015 19:52:36 +0100 Subject: [PATCH 2445/3725] Handle NiLODNode using osg::LOD (Fixes #3008) --- components/nifosg/nifloader.cpp | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 3e7f47b6f..73b72811a 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -6,6 +6,7 @@ #include #include #include +#include // resource #include @@ -424,6 +425,20 @@ namespace NifOsg // Need to make sure that won't break transparency sorting. Check what the original engine is doing? } + osg::ref_ptr handleLodNode(const Nif::NiLODNode* niLodNode) + { + osg::ref_ptr lod (new osg::LOD); + lod->setCenterMode(osg::LOD::USER_DEFINED_CENTER); + lod->setCenter(niLodNode->lodCenter); + for (unsigned int i=0; ilodLevels.size(); ++i) + { + const Nif::NiLODNode::LODRange& range = niLodNode->lodLevels[i]; + lod->setRange(i, range.minRange, range.maxRange); + } + lod->setRangeMode(osg::LOD::DISTANCE_FROM_EYE_POINT); + return lod; + } + osg::ref_ptr handleNode(const Nif::Node* nifNode, osg::Group* parentNode, Resource::TextureManager* textureManager, std::vector boundTextures, int animflags, int particleflags, bool skipMeshes, TextKeyMap* textKeys, osg::Node* rootNode=NULL) { @@ -555,6 +570,15 @@ namespace NifOsg // Optimization pass optimize(nifNode, node, skipMeshes); + + if (nifNode->recType == Nif::RC_NiLODNode) + { + const Nif::NiLODNode* niLodNode = static_cast(nifNode); + osg::ref_ptr lod = handleLodNode(niLodNode); + node->addChild(lod); // unsure if LOD should be above or below this node's transform + node = lod; + } + const Nif::NiNode *ninode = dynamic_cast(nifNode); if(ninode) { From 8cd41f0ed4809e960e36733eee481b180be25a2a Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 12 Nov 2015 23:05:44 +0100 Subject: [PATCH 2446/3725] Increase the ray distance for dropObjectOnGround (Fixes #3010) --- apps/openmw/mwworld/worldimp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index f82392662..7e78bef8c 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1870,7 +1870,7 @@ namespace MWWorld orig.z() += 20; osg::Vec3f dir (0, 0, -1); - float len = 100.0; + float len = 1000000.0; MWRender::RenderingManager::RayResult result = mRendering->castRay(orig, orig+dir*len, true, true); if (result.mHit) From ba211ad9ad43e69f1bb19b00bb0de5ae446750af Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 12 Nov 2015 23:27:34 +0100 Subject: [PATCH 2447/3725] Read NiPointLight (Fixes #3011) --- components/nif/effect.cpp | 27 ++++++++++++-------------- components/nif/effect.hpp | 39 ++++++++++++++++++++++++-------------- components/nif/niffile.cpp | 1 + 3 files changed, 38 insertions(+), 29 deletions(-) diff --git a/components/nif/effect.cpp b/components/nif/effect.cpp index 41dcb09de..78feeea94 100644 --- a/components/nif/effect.cpp +++ b/components/nif/effect.cpp @@ -5,29 +5,19 @@ namespace Nif { -void NiLight::SLight::read(NIFStream *nif) +void NiLight::read(NIFStream *nif) { + NiDynamicEffect::read(nif); + dimmer = nif->getFloat(); ambient = nif->getVector3(); diffuse = nif->getVector3(); specular = nif->getVector3(); } -void NiLight::read(NIFStream *nif) -{ - Effect::read(nif); - - nif->getInt(); // 1 - nif->getInt(); // 1? - light.read(nif); -} - void NiTextureEffect::read(NIFStream *nif) { - Effect::read(nif); - - int tmp = nif->getInt(); - if(tmp) nif->getInt(); // always 1? + NiDynamicEffect::read(nif); /* 3 x Vector4 = [1,0,0,0] @@ -52,10 +42,17 @@ void NiTextureEffect::read(NIFStream *nif) void NiTextureEffect::post(NIFFile *nif) { - Effect::post(nif); + NiDynamicEffect::post(nif); texture.post(nif); } +void NiPointLight::read(NIFStream *nif) +{ + NiLight::read(nif); + constantAttenuation = nif->getFloat(); + linearAttenuation = nif->getFloat(); + quadraticAttenuation = nif->getFloat(); +} } diff --git a/components/nif/effect.hpp b/components/nif/effect.hpp index fae1cd7f5..75de0a9ab 100644 --- a/components/nif/effect.hpp +++ b/components/nif/effect.hpp @@ -29,27 +29,38 @@ namespace Nif { -typedef Node Effect; - -// Used for NiAmbientLight and NiDirectionalLight. Might also work for -// NiPointLight and NiSpotLight? -struct NiLight : Effect +struct NiDynamicEffect : public Node { - struct SLight + void read(NIFStream *nif) { - float dimmer; - osg::Vec3f ambient; - osg::Vec3f diffuse; - osg::Vec3f specular; + Node::read(nif); + unsigned int numAffectedNodes = nif->getUInt(); + for (unsigned int i=0; igetUInt(); // ref to another Node + } +}; + +// Used as base for NiAmbientLight, NiDirectionalLight, NiPointLight and NiSpotLight. +struct NiLight : NiDynamicEffect +{ + float dimmer; + osg::Vec3f ambient; + osg::Vec3f diffuse; + osg::Vec3f specular; - void read(NIFStream *nif); - }; - SLight light; + void read(NIFStream *nif); +}; + +struct NiPointLight : public NiLight +{ + float constantAttenuation; + float linearAttenuation; + float quadraticAttenuation; void read(NIFStream *nif); }; -struct NiTextureEffect : Effect +struct NiTextureEffect : NiDynamicEffect { NiSourceTexturePtr texture; diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index 1387a97b0..ab0af8f99 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -82,6 +82,7 @@ static std::map makeFactory() newFactory.insert(makeEntry("NiFlipController", &construct , RC_NiFlipController )); newFactory.insert(makeEntry("NiAmbientLight", &construct , RC_NiLight )); newFactory.insert(makeEntry("NiDirectionalLight", &construct , RC_NiLight )); + newFactory.insert(makeEntry("NiPointLight", &construct , RC_NiLight )); newFactory.insert(makeEntry("NiTextureEffect", &construct , RC_NiTextureEffect )); newFactory.insert(makeEntry("NiVertWeightsExtraData", &construct , RC_NiVertWeightsExtraData )); newFactory.insert(makeEntry("NiTextKeyExtraData", &construct , RC_NiTextKeyExtraData )); From a29d1ace2b2beeeda58cc523793f73e401ec1afd Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 12 Nov 2015 23:45:12 +0100 Subject: [PATCH 2448/3725] Read NiSpotLight --- components/nif/effect.cpp | 8 ++++++++ components/nif/effect.hpp | 7 +++++++ components/nif/niffile.cpp | 1 + 3 files changed, 16 insertions(+) diff --git a/components/nif/effect.cpp b/components/nif/effect.cpp index 78feeea94..79cd10431 100644 --- a/components/nif/effect.cpp +++ b/components/nif/effect.cpp @@ -55,4 +55,12 @@ void NiPointLight::read(NIFStream *nif) quadraticAttenuation = nif->getFloat(); } +void NiSpotLight::read(NIFStream *nif) +{ + NiPointLight::read(nif); + + cutoff = nif->getFloat(); + exponent = nif->getFloat(); +} + } diff --git a/components/nif/effect.hpp b/components/nif/effect.hpp index 75de0a9ab..02647e444 100644 --- a/components/nif/effect.hpp +++ b/components/nif/effect.hpp @@ -60,6 +60,13 @@ struct NiPointLight : public NiLight void read(NIFStream *nif); }; +struct NiSpotLight : public NiPointLight +{ + float cutoff; + float exponent; + void read(NIFStream *nif); +}; + struct NiTextureEffect : NiDynamicEffect { NiSourceTexturePtr texture; diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index ab0af8f99..ccfcdfc73 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -83,6 +83,7 @@ static std::map makeFactory() newFactory.insert(makeEntry("NiAmbientLight", &construct , RC_NiLight )); newFactory.insert(makeEntry("NiDirectionalLight", &construct , RC_NiLight )); newFactory.insert(makeEntry("NiPointLight", &construct , RC_NiLight )); + newFactory.insert(makeEntry("NiSpotLight", &construct , RC_NiLight )); newFactory.insert(makeEntry("NiTextureEffect", &construct , RC_NiTextureEffect )); newFactory.insert(makeEntry("NiVertWeightsExtraData", &construct , RC_NiVertWeightsExtraData )); newFactory.insert(makeEntry("NiTextKeyExtraData", &construct , RC_NiTextKeyExtraData )); From 7c16630874230d886aa1d94f620c8b332676d93a Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 13 Nov 2015 00:21:30 +0100 Subject: [PATCH 2449/3725] NifOsg::Emitter: ignore psToWorld scale Seems wrong to me, but MW appears to do it that way. Without this fix, the light_de_candle_08_64 from http://www.nexusmods.com/morrowind/mods/41654/ has flame particles in the wrong spot. --- components/nifosg/particle.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/components/nifosg/particle.cpp b/components/nifosg/particle.cpp index 68f3de8aa..44d062d8b 100644 --- a/components/nifosg/particle.cpp +++ b/components/nifosg/particle.cpp @@ -264,7 +264,9 @@ void Emitter::emitParticles(double dt) osg::MatrixList worldMats = getParticleSystem()->getWorldMatrices(); if (!worldMats.empty()) { - const osg::Matrix psToWorld = worldMats[0]; + osg::Matrix psToWorld = worldMats[0]; + // ignore scales in particlesystem world matrix. this seems wrong, but have to do so for MW compatibility. + psToWorld.orthoNormalize(psToWorld); worldToPs = osg::Matrix::inverse(psToWorld); } From 63ee37d91462282267eddbe97336e8e255dc2919 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 13 Nov 2015 11:39:57 +0100 Subject: [PATCH 2450/3725] added 3D scene tooltips --- apps/opencs/view/render/cellarrow.cpp | 27 +++++++++++++++++++++++++++ apps/opencs/view/render/cellarrow.hpp | 2 ++ 2 files changed, 29 insertions(+) diff --git a/apps/opencs/view/render/cellarrow.cpp b/apps/opencs/view/render/cellarrow.cpp index fce5ffda5..1356aa0fb 100644 --- a/apps/opencs/view/render/cellarrow.cpp +++ b/apps/opencs/view/render/cellarrow.cpp @@ -18,6 +18,33 @@ CSVRender::CellArrow *CSVRender::CellArrowTag::getCellArrow() const return mArrow; } +QString CSVRender::CellArrowTag::getToolTip (bool hideBasics) const +{ + QString text ("Direction: "); + + switch (mArrow->getDirection()) + { + case CellArrow::Direction_North: text += "North"; break; + case CellArrow::Direction_West: text += "West"; break; + case CellArrow::Direction_South: text += "South"; break; + case CellArrow::Direction_East: text += "East"; break; + } + + if (!hideBasics) + { + text += + "

    " + "Modify which cells are shown" + "

    • Primary-Edit: Add cell in given direction
    • " + "
    • Secondary-Edit: Add cell and remove old cell
    • " + "
    • Shift Primary-Edit: Add cells in given direction
    • " + "
    • Shift Secondary-Edit: Add cells and remove old cells
    • " + "
    "; + } + + return text; +} + void CSVRender::CellArrow::adjustTransform() { diff --git a/apps/opencs/view/render/cellarrow.hpp b/apps/opencs/view/render/cellarrow.hpp index cbbcc9d5e..452356194 100644 --- a/apps/opencs/view/render/cellarrow.hpp +++ b/apps/opencs/view/render/cellarrow.hpp @@ -26,6 +26,8 @@ namespace CSVRender CellArrowTag (CellArrow *arrow); CellArrow *getCellArrow() const; + + virtual QString getToolTip (bool hideBasics) const; }; From 692a15a3dfdfafe58595314a5358b5416995bb19 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 13 Nov 2015 14:20:55 +0100 Subject: [PATCH 2451/3725] updated changelog again --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 378348ff8..36700904e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -223,6 +223,7 @@ Task #2730: Replace hardcoded column numbers in SimpleDialogueSubView/DialogueSubView Task #2750: Bullet shape instancing optimization Task #2793: Replace grid size setting with half grid size setting + Task #3003: Support FFMPEG 2.9 (Debian request) 0.36.1 ------ From fc8e40889df58bc18a54082799699c6151d41343 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 13 Nov 2015 18:07:18 +0100 Subject: [PATCH 2452/3725] Move common subrecord definitions (NAME, DELE) to defs.hpp --- components/esm/cellref.cpp | 2 +- components/esm/debugprofile.cpp | 4 ++-- components/esm/defs.hpp | 7 +++++++ components/esm/filter.cpp | 4 ++-- components/esm/loadacti.cpp | 4 ++-- components/esm/loadalch.cpp | 4 ++-- components/esm/loadappa.cpp | 4 ++-- components/esm/loadarmo.cpp | 4 ++-- components/esm/loadbody.cpp | 4 ++-- components/esm/loadbook.cpp | 4 ++-- components/esm/loadbsgn.cpp | 4 ++-- components/esm/loadcell.cpp | 4 ++-- components/esm/loadclas.cpp | 4 ++-- components/esm/loadclot.cpp | 4 ++-- components/esm/loadcont.cpp | 4 ++-- components/esm/loadcrea.cpp | 4 ++-- components/esm/loaddial.cpp | 2 +- components/esm/loaddoor.cpp | 4 ++-- components/esm/loadench.cpp | 4 ++-- components/esm/loadfact.cpp | 4 ++-- components/esm/loadinfo.cpp | 4 ++-- components/esm/loadingr.cpp | 4 ++-- components/esm/loadland.cpp | 2 +- components/esm/loadlevlist.cpp | 4 ++-- components/esm/loadligh.cpp | 4 ++-- components/esm/loadlock.cpp | 4 ++-- components/esm/loadltex.cpp | 4 ++-- components/esm/loadmisc.cpp | 4 ++-- components/esm/loadnpc.cpp | 4 ++-- components/esm/loadpgrd.cpp | 4 ++-- components/esm/loadprob.cpp | 4 ++-- components/esm/loadrace.cpp | 4 ++-- components/esm/loadregn.cpp | 4 ++-- components/esm/loadrepa.cpp | 4 ++-- components/esm/loadscpt.cpp | 2 +- components/esm/loadsndg.cpp | 4 ++-- components/esm/loadsoun.cpp | 4 ++-- components/esm/loadspel.cpp | 4 ++-- components/esm/loadsscr.cpp | 4 ++-- components/esm/loadstat.cpp | 4 ++-- components/esm/loadweap.cpp | 4 ++-- 41 files changed, 83 insertions(+), 76 deletions(-) diff --git a/components/esm/cellref.cpp b/components/esm/cellref.cpp index d4ef29e04..76a82fe23 100644 --- a/components/esm/cellref.cpp +++ b/components/esm/cellref.cpp @@ -108,7 +108,7 @@ void ESM::CellRef::loadData(ESMReader &esm, bool &isDeleted) case ESM::FourCC<'N','A','M','0'>::value: esm.skipHSub(); break; - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; diff --git a/components/esm/debugprofile.cpp b/components/esm/debugprofile.cpp index 56be91e71..66e338d0c 100644 --- a/components/esm/debugprofile.cpp +++ b/components/esm/debugprofile.cpp @@ -15,7 +15,7 @@ void ESM::DebugProfile::load (ESMReader& esm, bool &isDeleted) esm.getSubName(); switch (esm.retSubName().val) { - case ESM::FourCC<'N','A','M','E'>::value: + case ESM::SREC_NAME: mId = esm.getHString(); break; case ESM::FourCC<'D','E','S','C'>::value: @@ -27,7 +27,7 @@ void ESM::DebugProfile::load (ESMReader& esm, bool &isDeleted) case ESM::FourCC<'F','L','A','G'>::value: esm.getHT(mFlags); break; - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; diff --git a/components/esm/defs.hpp b/components/esm/defs.hpp index 9f1a935ae..8066b622a 100644 --- a/components/esm/defs.hpp +++ b/components/esm/defs.hpp @@ -133,5 +133,12 @@ enum RecNameInts REC_DBGP = FourCC<'D','B','G','P'>::value ///< only used in project files }; +/// Common subrecords +enum SubRecNameInts +{ + SREC_DELE = ESM::FourCC<'D','E','L','E'>::value, + SREC_NAME = ESM::FourCC<'N','A','M','E'>::value +}; + } #endif diff --git a/components/esm/filter.cpp b/components/esm/filter.cpp index 5b33c6683..c3658f152 100644 --- a/components/esm/filter.cpp +++ b/components/esm/filter.cpp @@ -16,7 +16,7 @@ void ESM::Filter::load (ESMReader& esm, bool &isDeleted) uint32_t name = esm.retSubName().val; switch (name) { - case ESM::FourCC<'N','A','M','E'>::value: + case ESM::SREC_NAME: mId = esm.getHString(); break; case ESM::FourCC<'F','I','L','T'>::value: @@ -25,7 +25,7 @@ void ESM::Filter::load (ESMReader& esm, bool &isDeleted) case ESM::FourCC<'D','E','S','C'>::value: mDescription = esm.getHString(); break; - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; diff --git a/components/esm/loadacti.cpp b/components/esm/loadacti.cpp index 14db45c34..b9934d3d3 100644 --- a/components/esm/loadacti.cpp +++ b/components/esm/loadacti.cpp @@ -18,7 +18,7 @@ namespace ESM esm.getSubName(); switch (esm.retSubName().val) { - case ESM::FourCC<'N','A','M','E'>::value: + case ESM::SREC_NAME: mId = esm.getHString(); hasName = true; break; @@ -31,7 +31,7 @@ namespace ESM case ESM::FourCC<'S','C','R','I'>::value: mScript = esm.getHString(); break; - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; diff --git a/components/esm/loadalch.cpp b/components/esm/loadalch.cpp index ceff4ba7d..204904502 100644 --- a/components/esm/loadalch.cpp +++ b/components/esm/loadalch.cpp @@ -21,7 +21,7 @@ namespace ESM esm.getSubName(); switch (esm.retSubName().val) { - case ESM::FourCC<'N','A','M','E'>::value: + case ESM::SREC_NAME: mId = esm.getHString(); hasName = true; break; @@ -44,7 +44,7 @@ namespace ESM case ESM::FourCC<'E','N','A','M'>::value: mEffects.add(esm); break; - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; diff --git a/components/esm/loadappa.cpp b/components/esm/loadappa.cpp index 7a77ba421..490881fae 100644 --- a/components/esm/loadappa.cpp +++ b/components/esm/loadappa.cpp @@ -19,7 +19,7 @@ namespace ESM esm.getSubName(); switch (esm.retSubName().val) { - case ESM::FourCC<'N','A','M','E'>::value: + case ESM::SREC_NAME: mId = esm.getHString(); hasName = true; break; @@ -39,7 +39,7 @@ namespace ESM case ESM::FourCC<'I','T','E','X'>::value: mIcon = esm.getHString(); break; - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; diff --git a/components/esm/loadarmo.cpp b/components/esm/loadarmo.cpp index 600c417be..f2526554a 100644 --- a/components/esm/loadarmo.cpp +++ b/components/esm/loadarmo.cpp @@ -51,7 +51,7 @@ namespace ESM esm.getSubName(); switch (esm.retSubName().val) { - case ESM::FourCC<'N','A','M','E'>::value: + case ESM::SREC_NAME: mId = esm.getHString(); hasName = true; break; @@ -77,7 +77,7 @@ namespace ESM case ESM::FourCC<'I','N','D','X'>::value: mParts.add(esm); break; - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; diff --git a/components/esm/loadbody.cpp b/components/esm/loadbody.cpp index 20d6b35cf..09113e8d1 100644 --- a/components/esm/loadbody.cpp +++ b/components/esm/loadbody.cpp @@ -19,7 +19,7 @@ namespace ESM esm.getSubName(); switch (esm.retSubName().val) { - case ESM::FourCC<'N','A','M','E'>::value: + case ESM::SREC_NAME: mId = esm.getHString(); hasName = true; break; @@ -33,7 +33,7 @@ namespace ESM esm.getHT(mData, 4); hasData = true; break; - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; diff --git a/components/esm/loadbook.cpp b/components/esm/loadbook.cpp index b08b12f50..617040be4 100644 --- a/components/esm/loadbook.cpp +++ b/components/esm/loadbook.cpp @@ -19,7 +19,7 @@ namespace ESM esm.getSubName(); switch (esm.retSubName().val) { - case ESM::FourCC<'N','A','M','E'>::value: + case ESM::SREC_NAME: mId = esm.getHString(); hasName = true; break; @@ -45,7 +45,7 @@ namespace ESM case ESM::FourCC<'T','E','X','T'>::value: mText = esm.getHString(); break; - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; diff --git a/components/esm/loadbsgn.cpp b/components/esm/loadbsgn.cpp index 0413a8610..9a4d98bb7 100644 --- a/components/esm/loadbsgn.cpp +++ b/components/esm/loadbsgn.cpp @@ -20,7 +20,7 @@ namespace ESM esm.getSubName(); switch (esm.retSubName().val) { - case ESM::FourCC<'N','A','M','E'>::value: + case ESM::SREC_NAME: mId = esm.getHString(); hasName = true; break; @@ -36,7 +36,7 @@ namespace ESM case ESM::FourCC<'N','P','C','S'>::value: mPowers.add(esm); break; - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index 703a4f4cb..8455daeac 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -71,14 +71,14 @@ namespace ESM esm.getSubName(); switch (esm.retSubName().val) { - case ESM::FourCC<'N','A','M','E'>::value: + case ESM::SREC_NAME: mName = esm.getHString(); break; case ESM::FourCC<'D','A','T','A'>::value: esm.getHT(mData, 12); hasData = true; break; - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; diff --git a/components/esm/loadclas.cpp b/components/esm/loadclas.cpp index 2ad14b9f2..61960b87d 100644 --- a/components/esm/loadclas.cpp +++ b/components/esm/loadclas.cpp @@ -49,7 +49,7 @@ namespace ESM esm.getSubName(); switch (esm.retSubName().val) { - case ESM::FourCC<'N','A','M','E'>::value: + case ESM::SREC_NAME: mId = esm.getHString(); hasName = true; break; @@ -65,7 +65,7 @@ namespace ESM case ESM::FourCC<'D','E','S','C'>::value: mDescription = esm.getHString(); break; - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; diff --git a/components/esm/loadclot.cpp b/components/esm/loadclot.cpp index 8a88e6d7a..2ef69e5e9 100644 --- a/components/esm/loadclot.cpp +++ b/components/esm/loadclot.cpp @@ -21,7 +21,7 @@ namespace ESM esm.getSubName(); switch (esm.retSubName().val) { - case ESM::FourCC<'N','A','M','E'>::value: + case ESM::SREC_NAME: mId = esm.getHString(); hasName = true; break; @@ -47,7 +47,7 @@ namespace ESM case ESM::FourCC<'I','N','D','X'>::value: mParts.add(esm); break; - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; diff --git a/components/esm/loadcont.cpp b/components/esm/loadcont.cpp index 372683750..739b0d7db 100644 --- a/components/esm/loadcont.cpp +++ b/components/esm/loadcont.cpp @@ -38,7 +38,7 @@ namespace ESM esm.getSubName(); switch (esm.retSubName().val) { - case ESM::FourCC<'N','A','M','E'>::value: + case ESM::SREC_NAME: mId = esm.getHString(); hasName = true; break; @@ -66,7 +66,7 @@ namespace ESM case ESM::FourCC<'N','P','C','O'>::value: mInventory.add(esm); break; - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; diff --git a/components/esm/loadcrea.cpp b/components/esm/loadcrea.cpp index e593ff540..0b53e5737 100644 --- a/components/esm/loadcrea.cpp +++ b/components/esm/loadcrea.cpp @@ -30,7 +30,7 @@ namespace ESM { esm.getSubName(); switch (esm.retSubName().val) { - case ESM::FourCC<'N','A','M','E'>::value: + case ESM::SREC_NAME: mId = esm.getHString(); hasName = true; break; @@ -79,7 +79,7 @@ namespace ESM { case AI_CNDT: mAiPackage.add(esm); break; - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; diff --git a/components/esm/loaddial.cpp b/components/esm/loaddial.cpp index 30fa3cfef..bc87c4f57 100644 --- a/components/esm/loaddial.cpp +++ b/components/esm/loaddial.cpp @@ -44,7 +44,7 @@ namespace ESM } break; } - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); mType = Unknown; isDeleted = true; diff --git a/components/esm/loaddoor.cpp b/components/esm/loaddoor.cpp index 706e938e8..6d8c0978c 100644 --- a/components/esm/loaddoor.cpp +++ b/components/esm/loaddoor.cpp @@ -18,7 +18,7 @@ namespace ESM esm.getSubName(); switch (esm.retSubName().val) { - case ESM::FourCC<'N','A','M','E'>::value: + case ESM::SREC_NAME: mId = esm.getHString(); hasName = true; break; @@ -37,7 +37,7 @@ namespace ESM case ESM::FourCC<'A','N','A','M'>::value: mCloseSound = esm.getHString(); break; - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; diff --git a/components/esm/loadench.cpp b/components/esm/loadench.cpp index 5580ef222..ae83c63f7 100644 --- a/components/esm/loadench.cpp +++ b/components/esm/loadench.cpp @@ -20,7 +20,7 @@ namespace ESM esm.getSubName(); switch (esm.retSubName().val) { - case ESM::FourCC<'N','A','M','E'>::value: + case ESM::SREC_NAME: mId = esm.getHString(); hasName = true; break; @@ -31,7 +31,7 @@ namespace ESM case ESM::FourCC<'E','N','A','M'>::value: mEffects.add(esm); break; - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; diff --git a/components/esm/loadfact.cpp b/components/esm/loadfact.cpp index f550a5538..75c482d20 100644 --- a/components/esm/loadfact.cpp +++ b/components/esm/loadfact.cpp @@ -42,7 +42,7 @@ namespace ESM esm.getSubName(); switch (esm.retSubName().val) { - case ESM::FourCC<'N','A','M','E'>::value: + case ESM::SREC_NAME: mId = esm.getHString(); hasName = true; break; @@ -68,7 +68,7 @@ namespace ESM mReactions[faction] = reaction; break; } - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; diff --git a/components/esm/loadinfo.cpp b/components/esm/loadinfo.cpp index d1f20a3d4..246baf026 100644 --- a/components/esm/loadinfo.cpp +++ b/components/esm/loadinfo.cpp @@ -67,7 +67,7 @@ namespace ESM case ESM::FourCC<'S','N','A','M'>::value: mSound = esm.getHString(); break; - case ESM::FourCC<'N','A','M','E'>::value: + case ESM::SREC_NAME: mResponse = esm.getHString(); break; case ESM::FourCC<'S','C','V','R'>::value: @@ -93,7 +93,7 @@ namespace ESM mQuestStatus = QS_Restart; esm.skipRecord(); break; - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; diff --git a/components/esm/loadingr.cpp b/components/esm/loadingr.cpp index a481d5b79..e00e73ab0 100644 --- a/components/esm/loadingr.cpp +++ b/components/esm/loadingr.cpp @@ -19,7 +19,7 @@ namespace ESM esm.getSubName(); switch (esm.retSubName().val) { - case ESM::FourCC<'N','A','M','E'>::value: + case ESM::SREC_NAME: mId = esm.getHString(); hasName = true; break; @@ -39,7 +39,7 @@ namespace ESM case ESM::FourCC<'I','T','E','X'>::value: mIcon = esm.getHString(); break; - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; diff --git a/components/esm/loadland.cpp b/components/esm/loadland.cpp index 9db58fc5b..e7be03321 100644 --- a/components/esm/loadland.cpp +++ b/components/esm/loadland.cpp @@ -105,7 +105,7 @@ namespace ESM case ESM::FourCC<'D','A','T','A'>::value: esm.getHT(mFlags); break; - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; diff --git a/components/esm/loadlevlist.cpp b/components/esm/loadlevlist.cpp index 6245ec856..8c0d50324 100644 --- a/components/esm/loadlevlist.cpp +++ b/components/esm/loadlevlist.cpp @@ -17,7 +17,7 @@ namespace ESM esm.getSubName(); switch (esm.retSubName().val) { - case ESM::FourCC<'N','A','M','E'>::value: + case ESM::SREC_NAME: mId = esm.getHString(); hasName = true; break; @@ -49,7 +49,7 @@ namespace ESM hasList = true; break; } - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; diff --git a/components/esm/loadligh.cpp b/components/esm/loadligh.cpp index a0fedc3ad..20c700b23 100644 --- a/components/esm/loadligh.cpp +++ b/components/esm/loadligh.cpp @@ -19,7 +19,7 @@ namespace ESM esm.getSubName(); switch (esm.retSubName().val) { - case ESM::FourCC<'N','A','M','E'>::value: + case ESM::SREC_NAME: mId = esm.getHString(); hasName = true; break; @@ -42,7 +42,7 @@ namespace ESM case ESM::FourCC<'S','N','A','M'>::value: mSound = esm.getHString(); break; - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; diff --git a/components/esm/loadlock.cpp b/components/esm/loadlock.cpp index be93eaa0e..fc6af8699 100644 --- a/components/esm/loadlock.cpp +++ b/components/esm/loadlock.cpp @@ -19,7 +19,7 @@ namespace ESM esm.getSubName(); switch (esm.retSubName().val) { - case ESM::FourCC<'N','A','M','E'>::value: + case ESM::SREC_NAME: mId = esm.getHString(); hasName = true; break; @@ -39,7 +39,7 @@ namespace ESM case ESM::FourCC<'I','T','E','X'>::value: mIcon = esm.getHString(); break; - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; diff --git a/components/esm/loadltex.cpp b/components/esm/loadltex.cpp index e9cd4578d..a42ae7c5b 100644 --- a/components/esm/loadltex.cpp +++ b/components/esm/loadltex.cpp @@ -19,7 +19,7 @@ namespace ESM esm.getSubName(); switch (esm.retSubName().val) { - case ESM::FourCC<'N','A','M','E'>::value: + case ESM::SREC_NAME: mId = esm.getHString(); hasName = true; break; @@ -30,7 +30,7 @@ namespace ESM case ESM::FourCC<'D','A','T','A'>::value: mTexture = esm.getHString(); break; - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; diff --git a/components/esm/loadmisc.cpp b/components/esm/loadmisc.cpp index f03cb9a85..199b4e3b2 100644 --- a/components/esm/loadmisc.cpp +++ b/components/esm/loadmisc.cpp @@ -19,7 +19,7 @@ namespace ESM esm.getSubName(); switch (esm.retSubName().val) { - case ESM::FourCC<'N','A','M','E'>::value: + case ESM::SREC_NAME: mId = esm.getHString(); hasName = true; break; @@ -39,7 +39,7 @@ namespace ESM case ESM::FourCC<'I','T','E','X'>::value: mIcon = esm.getHString(); break; - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; diff --git a/components/esm/loadnpc.cpp b/components/esm/loadnpc.cpp index 72333add3..e524e6a7c 100644 --- a/components/esm/loadnpc.cpp +++ b/components/esm/loadnpc.cpp @@ -28,7 +28,7 @@ namespace ESM esm.getSubName(); switch (esm.retSubName().val) { - case ESM::FourCC<'N','A','M','E'>::value: + case ESM::SREC_NAME: mId = esm.getHString(); hasName = true; break; @@ -98,7 +98,7 @@ namespace ESM case AI_CNDT: mAiPackage.add(esm); break; - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; diff --git a/components/esm/loadpgrd.cpp b/components/esm/loadpgrd.cpp index 95e6a906f..69ee60eeb 100644 --- a/components/esm/loadpgrd.cpp +++ b/components/esm/loadpgrd.cpp @@ -48,7 +48,7 @@ namespace ESM esm.getSubName(); switch (esm.retSubName().val) { - case ESM::FourCC<'N','A','M','E'>::value: + case ESM::SREC_NAME: mCell = esm.getHString(); break; case ESM::FourCC<'D','A','T','A'>::value: @@ -111,7 +111,7 @@ namespace ESM } break; } - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; diff --git a/components/esm/loadprob.cpp b/components/esm/loadprob.cpp index 31caeff41..baf466490 100644 --- a/components/esm/loadprob.cpp +++ b/components/esm/loadprob.cpp @@ -19,7 +19,7 @@ namespace ESM esm.getSubName(); switch (esm.retSubName().val) { - case ESM::FourCC<'N','A','M','E'>::value: + case ESM::SREC_NAME: mId = esm.getHString(); hasName = true; break; @@ -39,7 +39,7 @@ namespace ESM case ESM::FourCC<'I','T','E','X'>::value: mIcon = esm.getHString(); break; - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; diff --git a/components/esm/loadrace.cpp b/components/esm/loadrace.cpp index d5172a133..a37175144 100644 --- a/components/esm/loadrace.cpp +++ b/components/esm/loadrace.cpp @@ -31,7 +31,7 @@ namespace ESM esm.getSubName(); switch (esm.retSubName().val) { - case ESM::FourCC<'N','A','M','E'>::value: + case ESM::SREC_NAME: mId = esm.getHString(); hasName = true; break; @@ -48,7 +48,7 @@ namespace ESM case ESM::FourCC<'N','P','C','S'>::value: mPowers.add(esm); break; - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; diff --git a/components/esm/loadregn.cpp b/components/esm/loadregn.cpp index 9f3089763..e5382f50b 100644 --- a/components/esm/loadregn.cpp +++ b/components/esm/loadregn.cpp @@ -18,7 +18,7 @@ namespace ESM esm.getSubName(); switch (esm.retSubName().val) { - case ESM::FourCC<'N','A','M','E'>::value: + case ESM::SREC_NAME: mId = esm.getHString(); hasName = true; break; @@ -65,7 +65,7 @@ namespace ESM esm.getHT(sr, 33); mSoundList.push_back(sr); break; - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; diff --git a/components/esm/loadrepa.cpp b/components/esm/loadrepa.cpp index 00d2ebf08..e4af3d937 100644 --- a/components/esm/loadrepa.cpp +++ b/components/esm/loadrepa.cpp @@ -19,7 +19,7 @@ namespace ESM esm.getSubName(); switch (esm.retSubName().val) { - case ESM::FourCC<'N','A','M','E'>::value: + case ESM::SREC_NAME: mId = esm.getHString(); hasName = true; break; @@ -39,7 +39,7 @@ namespace ESM case ESM::FourCC<'I','T','E','X'>::value: mIcon = esm.getHString(); break; - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; diff --git a/components/esm/loadscpt.cpp b/components/esm/loadscpt.cpp index 2a0542138..b46d5b658 100644 --- a/components/esm/loadscpt.cpp +++ b/components/esm/loadscpt.cpp @@ -88,7 +88,7 @@ namespace ESM case ESM::FourCC<'S','C','T','X'>::value: mScriptText = esm.getHString(); break; - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; diff --git a/components/esm/loadsndg.cpp b/components/esm/loadsndg.cpp index 189cc97df..d84fe624d 100644 --- a/components/esm/loadsndg.cpp +++ b/components/esm/loadsndg.cpp @@ -19,7 +19,7 @@ namespace ESM esm.getSubName(); switch (esm.retSubName().val) { - case ESM::FourCC<'N','A','M','E'>::value: + case ESM::SREC_NAME: mId = esm.getHString(); hasName = true; break; @@ -33,7 +33,7 @@ namespace ESM case ESM::FourCC<'S','N','A','M'>::value: mSound = esm.getHString(); break; - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; diff --git a/components/esm/loadsoun.cpp b/components/esm/loadsoun.cpp index d3a82e198..82f169e54 100644 --- a/components/esm/loadsoun.cpp +++ b/components/esm/loadsoun.cpp @@ -19,7 +19,7 @@ namespace ESM esm.getSubName(); switch (esm.retSubName().val) { - case ESM::FourCC<'N','A','M','E'>::value: + case ESM::SREC_NAME: mId = esm.getHString(); hasName = true; break; @@ -30,7 +30,7 @@ namespace ESM esm.getHT(mData, 3); hasData = true; break; - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; diff --git a/components/esm/loadspel.cpp b/components/esm/loadspel.cpp index 16ffb63ff..728b7bc2a 100644 --- a/components/esm/loadspel.cpp +++ b/components/esm/loadspel.cpp @@ -21,7 +21,7 @@ namespace ESM esm.getSubName(); switch (esm.retSubName().val) { - case ESM::FourCC<'N','A','M','E'>::value: + case ESM::SREC_NAME: mId = esm.getHString(); hasName = true; break; @@ -37,7 +37,7 @@ namespace ESM esm.getHT(s, 24); mEffects.mList.push_back(s); break; - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; diff --git a/components/esm/loadsscr.cpp b/components/esm/loadsscr.cpp index a211a99bf..ab4c09750 100644 --- a/components/esm/loadsscr.cpp +++ b/components/esm/loadsscr.cpp @@ -19,7 +19,7 @@ namespace ESM esm.getSubName(); switch (esm.retSubName().val) { - case ESM::FourCC<'N','A','M','E'>::value: + case ESM::SREC_NAME: mId = esm.getHString(); hasName = true; break; @@ -27,7 +27,7 @@ namespace ESM mData = esm.getHString(); hasData = true; break; - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; diff --git a/components/esm/loadstat.cpp b/components/esm/loadstat.cpp index eee7a50f5..62d495ee3 100644 --- a/components/esm/loadstat.cpp +++ b/components/esm/loadstat.cpp @@ -18,14 +18,14 @@ namespace ESM esm.getSubName(); switch (esm.retSubName().val) { - case ESM::FourCC<'N','A','M','E'>::value: + case ESM::SREC_NAME: mId = esm.getHString(); hasName = true; break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; diff --git a/components/esm/loadweap.cpp b/components/esm/loadweap.cpp index b0bc1dad6..880a26bcb 100644 --- a/components/esm/loadweap.cpp +++ b/components/esm/loadweap.cpp @@ -19,7 +19,7 @@ namespace ESM esm.getSubName(); switch (esm.retSubName().val) { - case ESM::FourCC<'N','A','M','E'>::value: + case ESM::SREC_NAME: mId = esm.getHString(); hasName = true; break; @@ -42,7 +42,7 @@ namespace ESM case ESM::FourCC<'E','N','A','M'>::value: mEnchant = esm.getHString(); break; - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; From 054c3eb24e0160b8a903dfe0de5c9081b8ddb937 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 13 Nov 2015 20:39:44 +0100 Subject: [PATCH 2453/3725] Do not deep copy PrimitiveSets when build with OSG 3.5 --- components/sceneutil/clone.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/components/sceneutil/clone.cpp b/components/sceneutil/clone.cpp index e4b4f63bb..a372b1ebd 100644 --- a/components/sceneutil/clone.cpp +++ b/components/sceneutil/clone.cpp @@ -1,6 +1,7 @@ #include "clone.hpp" #include +#include #include #include @@ -53,6 +54,7 @@ namespace SceneUtil osg::CopyOp copyop = *this; copyop.setCopyFlags(copyop.getCopyFlags()|osg::CopyOp::DEEP_COPY_ARRAYS); +#if OSG_VERSION_LESS_THAN(3,5,0) /* Deep copy of primitives required to work around the following (bad?) code in osg::Geometry copy constructor: @@ -71,12 +73,12 @@ namespace SceneUtil In case of DEEP_COPY_PRIMITIVES=Off, DEEP_COPY_ARRAYS=On, the above code makes a modification to the original const Geometry& we copied from, causing problems if we relied on the original Geometry to remain static such as when it was added to an osgUtil::IncrementalCompileOperation. - Possible fix submitted to osg-submissions ( http://forum.openscenegraph.org/viewtopic.php?t=15217 ). + Fixed in OSG 3.5 ( http://forum.openscenegraph.org/viewtopic.php?t=15217 ). */ copyop.setCopyFlags(copyop.getCopyFlags()|osg::CopyOp::DEEP_COPY_PRIMITIVES); - +#endif osg::Drawable* cloned = osg::clone(drawable, copyop); if (cloned->getUpdateCallback()) From 1402a16702112b628225e0274019c9998dcd28d1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 13 Nov 2015 20:59:39 +0100 Subject: [PATCH 2454/3725] SceneWidget: change the threading model to DrawThreadPerContext Performs much better because we can break frame early, running cull in parallel with last frame's draw. --- apps/opencs/view/render/scenewidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index 76b3db348..426e10ecb 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -126,7 +126,7 @@ CompositeViewer::CompositeViewer() // Qt5 is currently crashing and reporting "Cannot make QOpenGLContext current in a different thread" when the viewer is run multi-threaded, this is regression from Qt4 osgViewer::ViewerBase::ThreadingModel threadingModel = osgViewer::ViewerBase::SingleThreaded; #else - osgViewer::ViewerBase::ThreadingModel threadingModel = osgViewer::ViewerBase::CullDrawThreadPerContext; + osgViewer::ViewerBase::ThreadingModel threadingModel = osgViewer::ViewerBase::DrawThreadPerContext; #endif setThreadingModel(threadingModel); From 9116c701d518f791252fe2c991d24938bf03e3ea Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 13 Nov 2015 20:50:57 +0100 Subject: [PATCH 2455/3725] esmtool fix --- apps/esmtool/record.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index 0e7769f37..d7cbea73b 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -867,7 +867,7 @@ void Record::print() std::cout << " Unknown1: " << data->mUnk1 << std::endl; std::cout << " Unknown2: " << data->mUnk2 << std::endl; } - if (!wasLoaded) mData.unloadData(); + mData.unloadData(); std::cout << " Deleted: " << mIsDeleted << std::endl; } From d0d8c2ededfcb45d8c5aebaac23bf076f719b4e3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 13 Nov 2015 20:27:06 +0100 Subject: [PATCH 2456/3725] Delete empty test --- apps/openmw_test_suite/CMakeLists.txt | 3 +-- .../components/misc/test_stringops.cpp | 14 -------------- 2 files changed, 1 insertion(+), 16 deletions(-) delete mode 100644 apps/openmw_test_suite/components/misc/test_stringops.cpp diff --git a/apps/openmw_test_suite/CMakeLists.txt b/apps/openmw_test_suite/CMakeLists.txt index 2ffb7ffa0..a27c8f1a4 100644 --- a/apps/openmw_test_suite/CMakeLists.txt +++ b/apps/openmw_test_suite/CMakeLists.txt @@ -4,8 +4,7 @@ if (GTEST_FOUND) include_directories(${GTEST_INCLUDE_DIRS}) file(GLOB UNITTEST_SRC_FILES - components/misc/test_*.cpp - mwdialogue/test_*.cpp + mwdialogue/test_keywordsearch.cpp ) source_group(apps\\openmw_test_suite FILES openmw_test_suite.cpp ${UNITTEST_SRC_FILES}) diff --git a/apps/openmw_test_suite/components/misc/test_stringops.cpp b/apps/openmw_test_suite/components/misc/test_stringops.cpp deleted file mode 100644 index 55fe0e0c2..000000000 --- a/apps/openmw_test_suite/components/misc/test_stringops.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include -#include "components/misc/stringops.hpp" - -struct StringOpsTest : public ::testing::Test -{ - protected: - virtual void SetUp() - { - } - - virtual void TearDown() - { - } -}; From 38c155c579342f8748e3c93f531be1f1da91784a Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 13 Nov 2015 23:12:07 +0100 Subject: [PATCH 2457/3725] Tests: add dialogue_merging_test (requires some data files) --- apps/openmw_test_suite/CMakeLists.txt | 4 + apps/openmw_test_suite/mwworld/test_store.cpp | 172 ++++++++++++++++++ .../loadinglistener/loadinglistener.hpp | 14 +- 3 files changed, 183 insertions(+), 7 deletions(-) create mode 100644 apps/openmw_test_suite/mwworld/test_store.cpp diff --git a/apps/openmw_test_suite/CMakeLists.txt b/apps/openmw_test_suite/CMakeLists.txt index a27c8f1a4..2300f97a3 100644 --- a/apps/openmw_test_suite/CMakeLists.txt +++ b/apps/openmw_test_suite/CMakeLists.txt @@ -4,6 +4,10 @@ if (GTEST_FOUND) include_directories(${GTEST_INCLUDE_DIRS}) file(GLOB UNITTEST_SRC_FILES + ../openmw/mwworld/store.cpp + ../openmw/mwworld/esmstore.cpp + mwworld/test_store.cpp + mwdialogue/test_keywordsearch.cpp ) diff --git a/apps/openmw_test_suite/mwworld/test_store.cpp b/apps/openmw_test_suite/mwworld/test_store.cpp new file mode 100644 index 000000000..64e064865 --- /dev/null +++ b/apps/openmw_test_suite/mwworld/test_store.cpp @@ -0,0 +1,172 @@ +#include + +#include + +#include +#include +#include + +#include "apps/openmw/mwworld/esmstore.hpp" + +/// Base class for tests of ESMStore that rely on external content files to produce the test data +struct ContentFileTest : public ::testing::Test +{ + protected: + + virtual void SetUp() + { + readContentFiles(); + + // load the content files + std::vector readerList; + readerList.resize(mContentFiles.size()); + + int index=0; + for (std::vector::const_iterator it = mContentFiles.begin(); it != mContentFiles.end(); ++it) + { + ESM::ESMReader lEsm; + lEsm.setEncoder(NULL); + lEsm.setIndex(index); + lEsm.setGlobalReaderList(&readerList); + lEsm.open(it->string()); + readerList[index] = lEsm; + std::auto_ptr listener; + listener.reset(new Loading::Listener); + mEsmStore.load(readerList[index], listener.get()); + + ++index; + } + + mEsmStore.setUp(); + } + + virtual void TearDown() + { + } + + // read absolute path to content files from openmw.cfg + void readContentFiles() + { + boost::program_options::variables_map variables; + + boost::program_options::options_description desc("Allowed options"); + desc.add_options() + ("data", boost::program_options::value()->default_value(Files::PathContainer(), "data")->multitoken()->composing()) + ("content", boost::program_options::value >()->default_value(std::vector(), "") + ->multitoken(), "content file(s): esm/esp, or omwgame/omwaddon") + ("data-local", boost::program_options::value()->default_value("")); + + boost::program_options::notify(variables); + + mConfigurationManager.readConfiguration(variables, desc, true); + + Files::PathContainer dataDirs, dataLocal; + if (!variables["data"].empty()) { + dataDirs = Files::PathContainer(variables["data"].as()); + } + + std::string local = variables["data-local"].as(); + if (!local.empty()) { + dataLocal.push_back(Files::PathContainer::value_type(local)); + } + + mConfigurationManager.processPaths (dataDirs); + mConfigurationManager.processPaths (dataLocal, true); + + if (!dataLocal.empty()) + dataDirs.insert (dataDirs.end(), dataLocal.begin(), dataLocal.end()); + + Files::Collections collections (dataDirs, true); + + std::vector contentFiles = variables["content"].as >(); + for (std::vector::iterator it = contentFiles.begin(); it != contentFiles.end(); ++it) + mContentFiles.push_back(collections.getPath(*it)); + } + +protected: + Files::ConfigurationManager mConfigurationManager; + MWWorld::ESMStore mEsmStore; + std::vector mContentFiles; +}; + +/// Print results of the dialogue merging process, i.e. the resulting linked list. +TEST_F(ContentFileTest, dialogue_merging_test) +{ + if (mContentFiles.empty()) + { + std::cout << "No content files found, skipping test" << std::endl; + return; + } + + const std::string file = "test_dialogue_merging.txt"; + + boost::filesystem::ofstream stream; + stream.open(file); + + const MWWorld::Store& dialStore = mEsmStore.get(); + for (MWWorld::Store::iterator it = dialStore.begin(); it != dialStore.end(); ++it) + { + const ESM::Dialogue& dial = *it; + stream << "Dialogue: " << dial.mId << std::endl; + + for (ESM::Dialogue::InfoContainer::const_iterator infoIt = dial.mInfo.begin(); infoIt != dial.mInfo.end(); ++infoIt) + { + const ESM::DialInfo& info = *infoIt; + stream << info.mId << std::endl; + } + stream << std::endl; + } + + std::cout << "dialogue_merging_test successful, results printed to " << file << std::endl; +} + +/* +TEST_F(ContentFileTest, diagnostics) +{ + if (mContentFiles.empty()) + { + std::cout << "No content files found, skipping test" << std::endl; + return; + } + + +} +*/ + +// TODO: +/// Print results of autocalculated NPC spell lists. Also serves as test for attribute/skill autocalculation which the spell autocalculation heavily relies on +/// - even rounding errors can completely change the resulting spell lists. +/* +TEST_F(ContentFileTest, autocalc_test) +{ + if (mContentFiles.empty()) + { + std::cout << "No content files found, skipping test" << std::endl; + return; + } + + +} +*/ + +/* +/// Base class for tests of ESMStore that do not rely on external content files +struct StoreTest : public ::testing::Test +{ +protected: + MWWorld::ESMStore mEsmStore; +}; + +/// Tests deletion of records. +TEST_F(StoreTest, delete_test) +{ + + +} + +/// Tests overwriting of records. +TEST_F(StoreTest, overwrite_test) +{ + +} +*/ diff --git a/components/loadinglistener/loadinglistener.hpp b/components/loadinglistener/loadinglistener.hpp index 47962015c..558111b34 100644 --- a/components/loadinglistener/loadinglistener.hpp +++ b/components/loadinglistener/loadinglistener.hpp @@ -6,18 +6,18 @@ namespace Loading class Listener { public: - virtual void setLabel (const std::string& label) = 0; + virtual void setLabel (const std::string& label) {} // Use ScopedLoad instead of using these directly - virtual void loadingOn() = 0; - virtual void loadingOff() = 0; + virtual void loadingOn() {} + virtual void loadingOff() {} /// Indicate that some progress has been made, without specifying how much - virtual void indicateProgress () = 0; + virtual void indicateProgress () {} - virtual void setProgressRange (size_t range) = 0; - virtual void setProgress (size_t value) = 0; - virtual void increaseProgress (size_t increase = 1) = 0; + virtual void setProgressRange (size_t range) {} + virtual void setProgress (size_t value) {} + virtual void increaseProgress (size_t increase = 1) {} }; // Used for stopping a loading sequence when the object goes out of scope From 771193bae8d00e0cee089544973deeffafdaccc8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 13 Nov 2015 23:38:38 +0100 Subject: [PATCH 2458/3725] Tests: add content_diagnostics_test (requires some data files) --- apps/openmw_test_suite/mwworld/test_store.cpp | 65 ++++++++++++++++++- 1 file changed, 62 insertions(+), 3 deletions(-) diff --git a/apps/openmw_test_suite/mwworld/test_store.cpp b/apps/openmw_test_suite/mwworld/test_store.cpp index 64e064865..bb8bcc37c 100644 --- a/apps/openmw_test_suite/mwworld/test_store.cpp +++ b/apps/openmw_test_suite/mwworld/test_store.cpp @@ -120,8 +120,61 @@ TEST_F(ContentFileTest, dialogue_merging_test) std::cout << "dialogue_merging_test successful, results printed to " << file << std::endl; } -/* -TEST_F(ContentFileTest, diagnostics) +// Note: here we don't test records that don't use string names (e.g. Land, Pathgrid, Cell) +#define RUN_TEST_FOR_TYPES(func, arg1, arg2) \ + func(arg1, arg2); \ + func(arg1, arg2); \ + func(arg1, arg2); \ + func(arg1, arg2); \ + func(arg1, arg2); \ + func(arg1, arg2); \ + func(arg1, arg2); \ + func(arg1, arg2); \ + func(arg1, arg2); \ + func(arg1, arg2); \ + func(arg1, arg2); \ + func(arg1, arg2); \ + func(arg1, arg2); \ + func(arg1, arg2); \ + func(arg1, arg2); \ + func(arg1, arg2); \ + func(arg1, arg2); \ + func(arg1, arg2); \ + func(arg1, arg2); \ + func(arg1, arg2); \ + func(arg1, arg2); \ + func(arg1, arg2); \ + func(arg1, arg2); \ + func(arg1, arg2); \ + func(arg1, arg2); \ + func(arg1, arg2); \ + func(arg1, arg2); \ + func(arg1, arg2); \ + func(arg1, arg2); \ + func(arg1, arg2); \ + func(arg1, arg2); \ + func(arg1, arg2); \ + func(arg1, arg2); \ + func(arg1, arg2); + +template +void printRecords(MWWorld::ESMStore& esmStore, std::ostream& outStream) +{ + const MWWorld::Store& store = esmStore.get(); + outStream << store.getSize() << " " << T::getRecordType() << " records" << std::endl; + + for (typename MWWorld::Store::iterator it = store.begin(); it != store.end(); ++it) + { + const T& record = *it; + outStream << record.mId << std::endl; + } + + outStream << std::endl; +} + +/// Print some basic diagnostics about the loaded content files, e.g. number of records and names of those records +/// Also used to test the iteration order of records +TEST_F(ContentFileTest, content_diagnostics_test) { if (mContentFiles.empty()) { @@ -129,9 +182,15 @@ TEST_F(ContentFileTest, diagnostics) return; } + const std::string file = "test_content_diagnostics.txt"; + + boost::filesystem::ofstream stream; + stream.open(file); + + RUN_TEST_FOR_TYPES(printRecords, mEsmStore, stream); + std::cout << "diagnostics_test successful, results printed to " << file << std::endl; } -*/ // TODO: /// Print results of autocalculated NPC spell lists. Also serves as test for attribute/skill autocalculation which the spell autocalculation heavily relies on From 1e817a976fb836600c74cd4dbfe94742639f1179 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 14 Nov 2015 00:12:59 +0100 Subject: [PATCH 2459/3725] Tests: add record deletion test --- apps/openmw_test_suite/mwworld/test_store.cpp | 65 +++++++++++++++++-- 1 file changed, 60 insertions(+), 5 deletions(-) diff --git a/apps/openmw_test_suite/mwworld/test_store.cpp b/apps/openmw_test_suite/mwworld/test_store.cpp index bb8bcc37c..dfa1c0b25 100644 --- a/apps/openmw_test_suite/mwworld/test_store.cpp +++ b/apps/openmw_test_suite/mwworld/test_store.cpp @@ -4,10 +4,14 @@ #include #include +#include +#include #include #include "apps/openmw/mwworld/esmstore.hpp" +static Loading::Listener dummyListener; + /// Base class for tests of ESMStore that rely on external content files to produce the test data struct ContentFileTest : public ::testing::Test { @@ -30,9 +34,7 @@ struct ContentFileTest : public ::testing::Test lEsm.setGlobalReaderList(&readerList); lEsm.open(it->string()); readerList[index] = lEsm; - std::auto_ptr listener; - listener.reset(new Loading::Listener); - mEsmStore.load(readerList[index], listener.get()); + mEsmStore.load(readerList[index], &dummyListener); ++index; } @@ -208,7 +210,6 @@ TEST_F(ContentFileTest, autocalc_test) } */ -/* /// Base class for tests of ESMStore that do not rely on external content files struct StoreTest : public ::testing::Test { @@ -216,11 +217,66 @@ protected: MWWorld::ESMStore mEsmStore; }; + +/// Create an ESM file in-memory containing the specified record. +/// @param deleted Write record with deleted flag? +template +Files::IStreamPtr getEsmFile(T record, bool deleted) +{ + ESM::ESMWriter writer; + std::stringstream* stream = new std::stringstream; + writer.setFormat(0); + writer.save(*stream); + writer.startRecord(T::sRecordId); + writer.writeHNString("NAME", record.mId); + if (deleted) + writer.writeHNT("DELE", (int)1); + record.save(writer); + writer.endRecord(T::sRecordId); + + return Files::IStreamPtr(stream); +} + /// Tests deletion of records. TEST_F(StoreTest, delete_test) { + const std::string recordId = "foobar"; + + typedef ESM::Apparatus RecordType; + RecordType record; + record.blank(); + record.mId = recordId; + ESM::ESMReader reader; + std::vector readerList; + readerList.push_back(reader); + reader.setGlobalReaderList(&readerList); + + // master file inserts a record + Files::IStreamPtr file = getEsmFile(record, false); + reader.open(file, "filename"); + mEsmStore.load(reader, &dummyListener); + mEsmStore.setUp(); + + ASSERT_TRUE (mEsmStore.get().getSize() == 1); + + // now a plugin deletes it + file = getEsmFile(record, true); + reader.open(file, "filename"); + mEsmStore.load(reader, &dummyListener); + mEsmStore.setUp(); + + ASSERT_TRUE (mEsmStore.get().getSize() == 0); + + // now another plugin inserts it again + // expected behaviour is the record to reappear rather than staying deleted + file = getEsmFile(record, false); + reader.open(file, "filename"); + mEsmStore.load(reader, &dummyListener); + mEsmStore.setUp(); + + ASSERT_TRUE (mEsmStore.get().getSize() == 1); } /// Tests overwriting of records. @@ -228,4 +284,3 @@ TEST_F(StoreTest, overwrite_test) { } -*/ From f91aae2350a1c6ce188b4f53b5714eb7a288306d Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 14 Nov 2015 00:17:13 +0100 Subject: [PATCH 2460/3725] Tests: add record overwrite test --- apps/openmw_test_suite/mwworld/test_store.cpp | 35 ++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/apps/openmw_test_suite/mwworld/test_store.cpp b/apps/openmw_test_suite/mwworld/test_store.cpp index dfa1c0b25..993386207 100644 --- a/apps/openmw_test_suite/mwworld/test_store.cpp +++ b/apps/openmw_test_suite/mwworld/test_store.cpp @@ -196,7 +196,7 @@ TEST_F(ContentFileTest, content_diagnostics_test) // TODO: /// Print results of autocalculated NPC spell lists. Also serves as test for attribute/skill autocalculation which the spell autocalculation heavily relies on -/// - even rounding errors can completely change the resulting spell lists. +/// - even incorrect rounding modes can completely change the resulting spell lists. /* TEST_F(ContentFileTest, autocalc_test) { @@ -282,5 +282,38 @@ TEST_F(StoreTest, delete_test) /// Tests overwriting of records. TEST_F(StoreTest, overwrite_test) { + const std::string recordId = "foobar"; + const std::string recordIdUpper = "Foobar"; + + typedef ESM::Apparatus RecordType; + + RecordType record; + record.blank(); + record.mId = recordId; + + ESM::ESMReader reader; + std::vector readerList; + readerList.push_back(reader); + reader.setGlobalReaderList(&readerList); + + // master file inserts a record + Files::IStreamPtr file = getEsmFile(record, false); + reader.open(file, "filename"); + mEsmStore.load(reader, &dummyListener); + mEsmStore.setUp(); + + // now a plugin overwrites it with changed data + record.mId = recordIdUpper; // change id to uppercase, to test case smashing while we're at it + record.mModel = "the_new_model"; + file = getEsmFile(record, false); + reader.open(file, "filename"); + mEsmStore.load(reader, &dummyListener); + mEsmStore.setUp(); + + // verify that changes were actually applied + const RecordType* overwrittenRec = mEsmStore.get().search(recordId); + + ASSERT_TRUE (overwrittenRec != NULL); + ASSERT_TRUE (overwrittenRec && overwrittenRec->mModel == "the_new_model"); } From aae1aa3708bf7a48e768f6b323372f5a61aa93ca Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 14 Nov 2015 00:23:35 +0100 Subject: [PATCH 2461/3725] Adjust tests to work with esm_rewrite branch. --- apps/openmw_test_suite/mwworld/test_store.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/apps/openmw_test_suite/mwworld/test_store.cpp b/apps/openmw_test_suite/mwworld/test_store.cpp index 993386207..ac21470de 100644 --- a/apps/openmw_test_suite/mwworld/test_store.cpp +++ b/apps/openmw_test_suite/mwworld/test_store.cpp @@ -5,14 +5,13 @@ #include #include #include -#include #include #include "apps/openmw/mwworld/esmstore.hpp" static Loading::Listener dummyListener; -/// Base class for tests of ESMStore that rely on external content files to produce the test data +/// Base class for tests of ESMStore that rely on external content files to produce the test results struct ContentFileTest : public ::testing::Test { protected: @@ -228,10 +227,7 @@ Files::IStreamPtr getEsmFile(T record, bool deleted) writer.setFormat(0); writer.save(*stream); writer.startRecord(T::sRecordId); - writer.writeHNString("NAME", record.mId); - if (deleted) - writer.writeHNT("DELE", (int)1); - record.save(writer); + record.save(writer, deleted); writer.endRecord(T::sRecordId); return Files::IStreamPtr(stream); From 05498ad5920e29aead9e0b431c884f84d98043b0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 14 Nov 2015 02:43:24 +0100 Subject: [PATCH 2462/3725] Refactor: InputManager no longer depends on Engine --- apps/openmw/engine.cpp | 38 +------------------------ apps/openmw/engine.hpp | 6 ---- apps/openmw/mwinput/inputmanagerimp.cpp | 14 +++++---- apps/openmw/mwinput/inputmanagerimp.hpp | 10 ++----- apps/openmw/mwworld/player.cpp | 29 +++++++++++++++++++ apps/openmw/mwworld/player.hpp | 3 ++ 6 files changed, 44 insertions(+), 56 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 5d2d588ed..031eac800 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -483,8 +483,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) else gameControllerdb = ""; //if it doesn't exist, pass in an empty string - // FIXME: shouldn't depend on Engine - MWInput::InputManager* input = new MWInput::InputManager (mWindow, mViewer, *this, keybinderUser, keybinderUserExists, gameControllerdb, mGrab); + MWInput::InputManager* input = new MWInput::InputManager (mWindow, mViewer, mScreenCaptureHandler, keybinderUser, keybinderUserExists, gameControllerdb, mGrab); mEnvironment.setInputManager (input); std::string myguiResources = (mResDir / "mygui").string(); @@ -717,41 +716,6 @@ void OMW::Engine::go() std::cout << "Quitting peacefully." << std::endl; } -void OMW::Engine::activate() -{ - if (mEnvironment.getWindowManager()->isGuiMode()) - return; - - MWWorld::Ptr player = mEnvironment.getWorld()->getPlayerPtr(); - const MWMechanics::NpcStats &playerStats = player.getClass().getNpcStats(player); - if (playerStats.isParalyzed() || playerStats.getKnockedDown()) - return; - - MWWorld::Ptr ptr = mEnvironment.getWorld()->getFacedObject(); - - if (ptr.isEmpty()) - return; - - if (ptr.getClass().getName(ptr) == "") // objects without name presented to user can never be activated - return; - - if (ptr.getClass().isActor()) - { - MWMechanics::CreatureStats &stats = ptr.getClass().getCreatureStats(ptr); - - if (stats.getAiSequence().isInCombat() && !stats.isDead()) - return; - } - - mEnvironment.getWorld()->activate(ptr, mEnvironment.getWorld()->getPlayerPtr()); -} - -void OMW::Engine::screenshot() -{ - mScreenCaptureHandler->setFramesToCapture(1); - mScreenCaptureHandler->captureNextFrame(*mViewer); -} - void OMW::Engine::setCompileAll (bool all) { mCompileAll = all; diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index 73de57dc4..a03752b86 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -169,12 +169,6 @@ namespace OMW /// Initialise and enter main loop. void go(); - /// Activate the focussed object. - void activate(); - - /// Write screenshot to file. - void screenshot(); - /// Compile all scripts (excludign dialogue scripts) at startup? void setCompileAll (bool all); diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index ad5fe35bd..688685e74 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -4,6 +4,8 @@ #include +#include + #include #include #include @@ -15,12 +17,11 @@ #include #include -#include "../engine.hpp" - #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwbase/statemanager.hpp" +#include "../mwbase/environment.hpp" #include "../mwworld/player.hpp" #include "../mwworld/class.hpp" @@ -37,15 +38,15 @@ namespace MWInput InputManager::InputManager( SDL_Window* window, osg::ref_ptr viewer, - OMW::Engine& engine, + osg::ref_ptr screenCaptureHandler, const std::string& userFile, bool userFileExists, const std::string& controllerBindingsFile, bool grab) : mWindow(window) , mWindowVisible(true) , mViewer(viewer) + , mScreenCaptureHandler(screenCaptureHandler) , mJoystickLastUsed(false) , mPlayer(NULL) - , mEngine(engine) , mInputManager(NULL) , mVideoWrapper(NULL) , mUserFile(userFile) @@ -952,7 +953,8 @@ namespace MWInput void InputManager::screenshot() { - mEngine.screenshot(); + mScreenCaptureHandler->setFramesToCapture(1); + mScreenCaptureHandler->captureNextFrame(*mViewer); MWBase::Environment::get().getWindowManager()->messageBox ("Screenshot saved"); } @@ -1058,7 +1060,7 @@ namespace MWInput void InputManager::activate() { if (mControlSwitch["playercontrols"]) - mEngine.activate(); + mPlayer->activate(); } void InputManager::toggleAutoMove() diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 62d0f413b..fc539f522 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -25,11 +25,6 @@ namespace MWBase class WindowManager; } -namespace OMW -{ - class Engine; -} - namespace ICS { class InputControlSystem; @@ -54,6 +49,7 @@ namespace SDLUtil namespace osgViewer { class Viewer; + class ScreenCaptureHandler; } struct SDL_Window; @@ -77,7 +73,7 @@ namespace MWInput InputManager( SDL_Window* window, osg::ref_ptr viewer, - OMW::Engine& engine, + osg::ref_ptr screenCaptureHandler, const std::string& userFile, bool userFileExists, const std::string& controllerBindingsFile, bool grab); @@ -157,10 +153,10 @@ namespace MWInput SDL_Window* mWindow; bool mWindowVisible; osg::ref_ptr mViewer; + osg::ref_ptr mScreenCaptureHandler; bool mJoystickLastUsed; MWWorld::Player* mPlayer; - OMW::Engine& mEngine; ICS::InputControlSystem* mInputBinder; diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index 6bfdd2986..19b66c3c9 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -205,6 +205,35 @@ namespace MWWorld return ptr.getClass().getNpcStats(ptr).getDrawState(); } + void Player::activate() + { + if (MWBase::Environment::get().getWindowManager()->isGuiMode()) + return; + + MWWorld::Ptr player = getPlayer(); + const MWMechanics::NpcStats &playerStats = player.getClass().getNpcStats(player); + if (playerStats.isParalyzed() || playerStats.getKnockedDown()) + return; + + MWWorld::Ptr toActivate = MWBase::Environment::get().getWorld()->getFacedObject(); + + if (toActivate.isEmpty()) + return; + + if (toActivate.getClass().getName(toActivate) == "") // objects without name presented to user can never be activated + return; + + if (toActivate.getClass().isActor()) + { + MWMechanics::CreatureStats &stats = toActivate.getClass().getCreatureStats(toActivate); + + if (stats.getAiSequence().isInCombat() && !stats.isDead()) + return; + } + + MWBase::Environment::get().getWorld()->activate(toActivate, player); + } + bool Player::wasTeleported() const { return mTeleported; diff --git a/apps/openmw/mwworld/player.hpp b/apps/openmw/mwworld/player.hpp index f0ae13daa..595dd89fc 100644 --- a/apps/openmw/mwworld/player.hpp +++ b/apps/openmw/mwworld/player.hpp @@ -82,6 +82,9 @@ namespace MWWorld void setDrawState (MWMechanics::DrawState_ state); MWMechanics::DrawState_ getDrawState(); /// \todo constness + /// Activate the object under the crosshair, if any + void activate(); + bool getAutoMove() const; void setAutoMove (bool enable); From 0ec56d321ac39888831ddb3c80a0f494773e13c3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 14 Nov 2015 03:01:40 +0100 Subject: [PATCH 2463/3725] Remove unneeded using namespace --- apps/openmw/mwinput/inputmanagerimp.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 688685e74..0c306da68 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -31,8 +31,6 @@ #include "../mwmechanics/npcstats.hpp" #include "../mwmechanics/actorutil.hpp" -using namespace ICS; - namespace MWInput { InputManager::InputManager( From 4e3bbe01b6bfc77e3565bdaf98c1eba7aa22a83e Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Thu, 12 Nov 2015 21:40:59 +0100 Subject: [PATCH 2464/3725] OS X: disable `glTexStorage2D` because of OSG/driver issue See http://forum.openscenegraph.org/viewtopic.php?p=65276#65276 for the details. --- apps/opencs/main.cpp | 4 ++++ apps/openmw/main.cpp | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/apps/opencs/main.cpp b/apps/opencs/main.cpp index de2e6e83e..0b7a34cdb 100644 --- a/apps/opencs/main.cpp +++ b/apps/opencs/main.cpp @@ -43,6 +43,10 @@ class Application : public QApplication int main(int argc, char *argv[]) { + #ifdef Q_OS_MAC + setenv("OSG_GL_TEXTURE_STORAGE", "OFF", 0); + #endif + try { // To allow background thread drawing in OSG diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 3d631c743..609452a9f 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -321,6 +321,10 @@ private: int main(int argc, char**argv) { +#if defined(__APPLE__) + setenv("OSG_GL_TEXTURE_STORAGE", "OFF", 0); +#endif + // Some objects used to redirect cout and cerr // Scope must be here, so this still works inside the catch block for logging exceptions std::streambuf* cout_rdbuf = std::cout.rdbuf (); From 3ba546628df2babb0b6198c4374a7b2062cdde24 Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Thu, 12 Nov 2015 22:33:22 +0100 Subject: [PATCH 2465/3725] OS X: always copy Cocoa platform plugin into OpenMW bundle --- CMakeLists.txt | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 58b88f621..d7c5efa5f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -710,6 +710,18 @@ endif() # Apple bundling if (APPLE) + get_property(QT_COCOA_PLUGIN_PATH TARGET Qt5::QCocoaIntegrationPlugin PROPERTY LOCATION_RELEASE) + get_filename_component(QT_COCOA_PLUGIN_DIR "${QT_COCOA_PLUGIN_PATH}" DIRECTORY) + get_filename_component(QT_COCOA_PLUGIN_GROUP "${QT_COCOA_PLUGIN_DIR}" NAME) + get_filename_component(QT_COCOA_PLUGIN_NAME "${QT_COCOA_PLUGIN_PATH}" NAME) + configure_file("${QT_COCOA_PLUGIN_PATH}" "${APP_BUNDLE_DIR}/Contents/MacOS/${QT_COCOA_PLUGIN_GROUP}/${QT_COCOA_PLUGIN_NAME}" COPYONLY) + + if (BUILD_OPENCS) + get_property(OPENCS_BUNDLE_NAME_TMP TARGET openmw-cs PROPERTY OUTPUT_NAME) + set(OPENCS_BUNDLE_NAME "${OPENCS_BUNDLE_NAME_TMP}.app") + configure_file("${QT_COCOA_PLUGIN_PATH}" "${OPENCS_BUNDLE_NAME}/Contents/MacOS/${QT_COCOA_PLUGIN_GROUP}/${QT_COCOA_PLUGIN_NAME}" COPYONLY) + endif () + set(INSTALL_SUBDIR OpenMW) install(DIRECTORY "${APP_BUNDLE_DIR}" USE_SOURCE_PERMISSIONS DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) @@ -726,8 +738,6 @@ if (APPLE) set(CPACK_PACKAGE_VERSION_PATCH ${OPENMW_VERSION_RELEASE}) set(OPENMW_APP "\${CMAKE_INSTALL_PREFIX}/${INSTALL_SUBDIR}/${APP_BUNDLE_NAME}") - - set(OPENCS_BUNDLE_NAME "OpenMW-CS.app") set(OPENCS_APP "\${CMAKE_INSTALL_PREFIX}/${INSTALL_SUBDIR}/${OPENCS_BUNDLE_NAME}") install(CODE " From 4dcb1a1b1785426a2a7766b3fb22f0c21c7ca4ac Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Thu, 12 Nov 2015 22:34:00 +0100 Subject: [PATCH 2466/3725] OS X: remove QPlastiqueStyle usage --- apps/launcher/playpage.cpp | 9 --------- 1 file changed, 9 deletions(-) diff --git a/apps/launcher/playpage.cpp b/apps/launcher/playpage.cpp index 6cfb9686f..99b74fdd3 100644 --- a/apps/launcher/playpage.cpp +++ b/apps/launcher/playpage.cpp @@ -2,20 +2,11 @@ #include -#ifdef Q_OS_MAC -#include -#endif - Launcher::PlayPage::PlayPage(QWidget *parent) : QWidget(parent) { setObjectName ("PlayPage"); setupUi(this); - // Hacks to get the stylesheet look properly -#ifdef Q_OS_MAC - QPlastiqueStyle *style = new QPlastiqueStyle; - profilesComboBox->setStyle(style); -#endif profilesComboBox->setView(new QListView()); connect(profilesComboBox, SIGNAL(activated(int)), this, SIGNAL (signalProfileChanged(int))); From 014a2fc0e924b9229e8da812eddf85b883cd8a8e Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Thu, 12 Nov 2015 22:34:20 +0100 Subject: [PATCH 2467/3725] OS X: do not override Qt plugin path --- apps/launcher/main.cpp | 9 --------- apps/opencs/main.cpp | 9 --------- 2 files changed, 18 deletions(-) diff --git a/apps/launcher/main.cpp b/apps/launcher/main.cpp index 32fe8c93a..282b3fb89 100644 --- a/apps/launcher/main.cpp +++ b/apps/launcher/main.cpp @@ -41,15 +41,6 @@ int main(int argc, char *argv[]) dir.cdUp(); dir.cdUp(); } - - // force Qt to load only LOCAL plugins, don't touch system Qt installation - QDir pluginsPath(QCoreApplication::applicationDirPath()); - pluginsPath.cdUp(); - pluginsPath.cd("Plugins"); - - QStringList libraryPaths; - libraryPaths << pluginsPath.path() << QCoreApplication::applicationDirPath(); - app.setLibraryPaths(libraryPaths); #endif QDir::setCurrent(dir.absolutePath()); diff --git a/apps/opencs/main.cpp b/apps/opencs/main.cpp index 0b7a34cdb..c6fe34835 100644 --- a/apps/opencs/main.cpp +++ b/apps/opencs/main.cpp @@ -68,15 +68,6 @@ int main(int argc, char *argv[]) dir.cdUp(); } QDir::setCurrent(dir.absolutePath()); - - // force Qt to load only LOCAL plugins, don't touch system Qt installation - QDir pluginsPath(QCoreApplication::applicationDirPath()); - pluginsPath.cdUp(); - pluginsPath.cd("Plugins"); - - QStringList libraryPaths; - libraryPaths << pluginsPath.path() << QCoreApplication::applicationDirPath(); - application.setLibraryPaths(libraryPaths); #endif application.setWindowIcon (QIcon (":./openmw-cs.png")); From 5c4899580f1cb6dccc5d06995811b30079ff6ea6 Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Thu, 12 Nov 2015 23:37:03 +0100 Subject: [PATCH 2468/3725] OS X: use less ambiguous variable names in packaging code --- CMakeLists.txt | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d7c5efa5f..3d66d8ebe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -737,8 +737,8 @@ if (APPLE) set(CPACK_PACKAGE_VERSION_MINOR ${OPENMW_VERSION_MINOR}) set(CPACK_PACKAGE_VERSION_PATCH ${OPENMW_VERSION_RELEASE}) - set(OPENMW_APP "\${CMAKE_INSTALL_PREFIX}/${INSTALL_SUBDIR}/${APP_BUNDLE_NAME}") - set(OPENCS_APP "\${CMAKE_INSTALL_PREFIX}/${INSTALL_SUBDIR}/${OPENCS_BUNDLE_NAME}") + set(INSTALLED_OPENMW_APP "\${CMAKE_INSTALL_PREFIX}/${INSTALL_SUBDIR}/${APP_BUNDLE_NAME}") + set(INSTALLED_OPENCS_APP "\${CMAKE_INSTALL_PREFIX}/${INSTALL_SUBDIR}/${OPENCS_BUNDLE_NAME}") install(CODE " set(BU_CHMOD_BUNDLE_ITEMS ON) @@ -758,12 +758,12 @@ if (APPLE) set(ABSOLUTE_PLUGINS ${PLUGIN_ABS} ${ABSOLUTE_PLUGINS}) endforeach () - get_filename_component(PLUGIN_PREFIX_DIR "${OSG_PLUGIN_LIB_SEARCH_PATH}" NAME) + get_filename_component(OSG_PLUGIN_PREFIX_DIR "${OSG_PLUGIN_LIB_SEARCH_PATH}" NAME) # installs used plugins in bundle at given path (bundle_path must be relative to ${CMAKE_INSTALL_PREFIX}) # and returns list of install paths for all installed plugins function (install_plugins_for_bundle bundle_path plugins_var) - set(RELATIVE_PLUGIN_INSTALL_BASE "${bundle_path}/Contents/PlugIns/${PLUGIN_PREFIX_DIR}") + set(RELATIVE_PLUGIN_INSTALL_BASE "${bundle_path}/Contents/PlugIns/${OSG_PLUGIN_PREFIX_DIR}") set(PLUGINS "") set(PLUGIN_INSTALL_BASE "\${CMAKE_INSTALL_PREFIX}/${RELATIVE_PLUGIN_INSTALL_BASE}") @@ -790,15 +790,15 @@ if (APPLE) install(CODE " function(gp_item_default_embedded_path_override item default_embedded_path_var) - if (\${item} MATCHES ${PLUGIN_PREFIX_DIR}) - set(path \"@executable_path/../PlugIns/${PLUGIN_PREFIX_DIR}\") + if (\${item} MATCHES ${OSG_PLUGIN_PREFIX_DIR}) + set(path \"@executable_path/../PlugIns/${OSG_PLUGIN_PREFIX_DIR}\") set(\${default_embedded_path_var} \"\${path}\" PARENT_SCOPE) endif() endfunction() cmake_policy(SET CMP0009 OLD) - fixup_bundle(\"${OPENMW_APP}\" \"${PLUGINS}\" \"${DIRS}\") - fixup_bundle(\"${OPENCS_APP}\" \"${OPENCS_PLUGINS}\" \"${DIRS}\") + fixup_bundle(\"${INSTALLED_OPENMW_APP}\" \"${PLUGINS}\" \"${DIRS}\") + fixup_bundle(\"${INSTALLED_OPENCS_APP}\" \"${OPENCS_PLUGINS}\" \"${DIRS}\") " COMPONENT Runtime) include(CPack) endif (APPLE) From fff6b5fde1014714ebde324b81a1a0a9bab42156 Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Fri, 13 Nov 2015 00:53:54 +0100 Subject: [PATCH 2469/3725] OS X: remove custom bundle utilities, ones from CMake versions >= 3.1.0 are good enough --- CMakeLists.txt | 3 +- cmake/BundleUtilitiesWithRPath.cmake | 961 ------------------------- cmake/COPYING-CMAKE-SCRIPTS | 266 ------- cmake/GetPrerequisitesWithRPath.cmake | 990 -------------------------- 4 files changed, 2 insertions(+), 2218 deletions(-) delete mode 100644 cmake/BundleUtilitiesWithRPath.cmake delete mode 100644 cmake/GetPrerequisitesWithRPath.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 3d66d8ebe..e218923bf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -743,7 +743,8 @@ if (APPLE) install(CODE " set(BU_CHMOD_BUNDLE_ITEMS ON) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH}) - include(BundleUtilitiesWithRPath) + include(BundleUtilities) + cmake_minimum_required(VERSION 3.1) " COMPONENT Runtime) set(ABSOLUTE_PLUGINS "") diff --git a/cmake/BundleUtilitiesWithRPath.cmake b/cmake/BundleUtilitiesWithRPath.cmake deleted file mode 100644 index 5254e1a52..000000000 --- a/cmake/BundleUtilitiesWithRPath.cmake +++ /dev/null @@ -1,961 +0,0 @@ -#.rst: -# BundleUtilities -# --------------- -# -# Functions to help assemble a standalone bundle application. -# -# A collection of CMake utility functions useful for dealing with .app -# bundles on the Mac and bundle-like directories on any OS. -# -# The following functions are provided by this module: -# -# :: -# -# fixup_bundle -# copy_and_fixup_bundle -# verify_app -# get_bundle_main_executable -# get_dotapp_dir -# get_bundle_and_executable -# get_bundle_all_executables -# get_item_key -# clear_bundle_keys -# set_bundle_key_values -# get_bundle_keys -# copy_resolved_item_into_bundle -# copy_resolved_framework_into_bundle -# fixup_bundle_item -# verify_bundle_prerequisites -# verify_bundle_symlinks -# -# Requires CMake 2.6 or greater because it uses function, break and -# PARENT_SCOPE. Also depends on GetPrerequisites.cmake. -# -# :: -# -# FIXUP_BUNDLE( ) -# -# Fix up a bundle in-place and make it standalone, such that it can be -# drag-n-drop copied to another machine and run on that machine as long -# as all of the system libraries are compatible. -# -# If you pass plugins to fixup_bundle as the libs parameter, you should -# install them or copy them into the bundle before calling fixup_bundle. -# The "libs" parameter is a list of libraries that must be fixed up, but -# that cannot be determined by otool output analysis. (i.e., plugins) -# -# Gather all the keys for all the executables and libraries in a bundle, -# and then, for each key, copy each prerequisite into the bundle. Then -# fix each one up according to its own list of prerequisites. -# -# Then clear all the keys and call verify_app on the final bundle to -# ensure that it is truly standalone. -# -# :: -# -# COPY_AND_FIXUP_BUNDLE( ) -# -# Makes a copy of the bundle at location and then fixes up -# the new copied bundle in-place at ... -# -# :: -# -# VERIFY_APP() -# -# Verifies that an application appears valid based on running -# analysis tools on it. Calls "message(FATAL_ERROR" if the application -# is not verified. -# -# :: -# -# GET_BUNDLE_MAIN_EXECUTABLE( ) -# -# The result will be the full path name of the bundle's main executable -# file or an "error:" prefixed string if it could not be determined. -# -# :: -# -# GET_DOTAPP_DIR( ) -# -# Returns the nearest parent dir whose name ends with ".app" given the -# full path to an executable. If there is no such parent dir, then -# simply return the dir containing the executable. -# -# The returned directory may or may not exist. -# -# :: -# -# GET_BUNDLE_AND_EXECUTABLE( ) -# -# Takes either a ".app" directory name or the name of an executable -# nested inside a ".app" directory and returns the path to the ".app" -# directory in and the path to its main executable in -# -# -# :: -# -# GET_BUNDLE_ALL_EXECUTABLES( ) -# -# Scans the given bundle recursively for all executable files and -# accumulates them into a variable. -# -# :: -# -# GET_ITEM_KEY( ) -# -# Given a file (item) name, generate a key that should be unique -# considering the set of libraries that need copying or fixing up to -# make a bundle standalone. This is essentially the file name including -# extension with "." replaced by "_" -# -# This key is used as a prefix for CMake variables so that we can -# associate a set of variables with a given item based on its key. -# -# :: -# -# CLEAR_BUNDLE_KEYS() -# -# Loop over the list of keys, clearing all the variables associated with -# each key. After the loop, clear the list of keys itself. -# -# Caller of get_bundle_keys should call clear_bundle_keys when done with -# list of keys. -# -# :: -# -# SET_BUNDLE_KEY_VALUES( -# ) -# -# Add a key to the list (if necessary) for the given item. If added, -# also set all the variables associated with that key. -# -# :: -# -# GET_BUNDLE_KEYS( ) -# -# Loop over all the executable and library files within the bundle (and -# given as extra ) and accumulate a list of keys representing -# them. Set values associated with each key such that we can loop over -# all of them and copy prerequisite libs into the bundle and then do -# appropriate install_name_tool fixups. -# -# :: -# -# COPY_RESOLVED_ITEM_INTO_BUNDLE( ) -# -# Copy a resolved item into the bundle if necessary. Copy is not -# necessary if the resolved_item is "the same as" the -# resolved_embedded_item. -# -# :: -# -# COPY_RESOLVED_FRAMEWORK_INTO_BUNDLE( ) -# -# Copy a resolved framework into the bundle if necessary. Copy is not -# necessary if the resolved_item is "the same as" the -# resolved_embedded_item. -# -# By default, BU_COPY_FULL_FRAMEWORK_CONTENTS is not set. If you want -# full frameworks embedded in your bundles, set -# BU_COPY_FULL_FRAMEWORK_CONTENTS to ON before calling fixup_bundle. By -# default, COPY_RESOLVED_FRAMEWORK_INTO_BUNDLE copies the framework -# dylib itself plus the framework Resources directory. -# -# :: -# -# IS_RESOLVED_ITEM_EMBEDDED( ) -# -# Set variable to True if the resolved item is -# embedded into the bundle. The function does NOT check for the existence of the -# item, instead if checks if the provided path would correspond to an embeddable -# item. If is True, extra information will be displayed in case the item -# is not embedded. -# -# :: -# -# FIXUP_BUNDLE_ITEM( ) -# -# Get the direct/non-system prerequisites of the resolved embedded item. -# For each prerequisite, change the way it is referenced to the value of -# the _EMBEDDED_ITEM keyed variable for that prerequisite. (Most likely -# changing to an "@executable_path" style reference.) -# -# This function requires that the resolved_embedded_item be "inside" the -# bundle already. In other words, if you pass plugins to fixup_bundle -# as the libs parameter, you should install them or copy them into the -# bundle before calling fixup_bundle. The "libs" parameter is a list of -# libraries that must be fixed up, but that cannot be determined by -# otool output analysis. (i.e., plugins) -# -# Also, change the id of the item being fixed up to its own -# _EMBEDDED_ITEM value. -# -# Accumulate changes in a local variable and make *one* call to -# install_name_tool at the end of the function with all the changes at -# once. -# -# If the BU_CHMOD_BUNDLE_ITEMS variable is set then bundle items will be -# marked writable before install_name_tool tries to change them. -# -# :: -# -# VERIFY_BUNDLE_PREREQUISITES( ) -# -# Verifies that the sum of all prerequisites of all files inside the -# bundle are contained within the bundle or are "system" libraries, -# presumed to exist everywhere. -# -# :: -# -# VERIFY_BUNDLE_SYMLINKS( ) -# -# Verifies that any symlinks found in the bundle point to other files -# that are already also in the bundle... Anything that points to an -# external file causes this function to fail the verification. - -#============================================================================= -# Copyright 2008-2009 Kitware, Inc. -# -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. -#============================================================================= -# (To distribute this file outside of CMake, substitute the full -# License text for the above reference.) - -# Copyright (c) 2015 BWH and 3D Slicer contributors, http://slicer.org -# -# Redistribution AND use is allowed according to the terms of the -# BSD-style license. -# For details see the accompanying COPYING-CMAKE-SCRIPTS file. - -# The functions defined in this file depend on the get_prerequisites function -# (and possibly others) found in: -# -get_filename_component(BundleUtilities_cmake_dir "${CMAKE_CURRENT_LIST_FILE}" PATH) -include("${BundleUtilities_cmake_dir}/GetPrerequisitesWithRPath.cmake") - - -function(get_bundle_main_executable bundle result_var) - set(result "error: '${bundle}/Contents/Info.plist' file does not exist") - - if(EXISTS "${bundle}/Contents/Info.plist") - set(result "error: no CFBundleExecutable in '${bundle}/Contents/Info.plist' file") - set(line_is_main_executable 0) - set(bundle_executable "") - - # Read Info.plist as a list of lines: - # - set(eol_char "E") - file(READ "${bundle}/Contents/Info.plist" info_plist) - string(REPLACE ";" "\\;" info_plist "${info_plist}") - string(REPLACE "\n" "${eol_char};" info_plist "${info_plist}") - string(REPLACE "\r" "${eol_char};" info_plist "${info_plist}") - - # Scan the lines for "CFBundleExecutable" - the line after that - # is the name of the main executable. - # - foreach(line ${info_plist}) - if(line_is_main_executable) - string(REGEX REPLACE "^.*(.*).*$" "\\1" bundle_executable "${line}") - break() - endif() - - if(line MATCHES "CFBundleExecutable") - set(line_is_main_executable 1) - endif() - endforeach() - - if(NOT "${bundle_executable}" STREQUAL "") - if(EXISTS "${bundle}/Contents/MacOS/${bundle_executable}") - set(result "${bundle}/Contents/MacOS/${bundle_executable}") - else() - - # Ultimate goal: - # If not in "Contents/MacOS" then scan the bundle for matching files. If - # there is only one executable file that matches, then use it, otherwise - # it's an error... - # - #file(GLOB_RECURSE file_list "${bundle}/${bundle_executable}") - - # But for now, pragmatically, it's an error. Expect the main executable - # for the bundle to be in Contents/MacOS, it's an error if it's not: - # - set(result "error: '${bundle}/Contents/MacOS/${bundle_executable}' does not exist") - endif() - endif() - else() - # - # More inclusive technique... (This one would work on Windows and Linux - # too, if a developer followed the typical Mac bundle naming convention...) - # - # If there is no Info.plist file, try to find an executable with the same - # base name as the .app directory: - # - endif() - - set(${result_var} "${result}" PARENT_SCOPE) -endfunction() - - -function(get_dotapp_dir exe dotapp_dir_var) - set(s "${exe}") - - if(s MATCHES "/.*\\.app/") - # If there is a ".app" parent directory, - # ascend until we hit it: - # (typical of a Mac bundle executable) - # - set(done 0) - while(NOT ${done}) - get_filename_component(snamewe "${s}" NAME_WE) - get_filename_component(sname "${s}" NAME) - get_filename_component(sdir "${s}" PATH) - set(s "${sdir}") - if(sname MATCHES "\\.app$") - set(done 1) - set(dotapp_dir "${sdir}/${sname}") - endif() - endwhile() - else() - # Otherwise use a directory containing the exe - # (typical of a non-bundle executable on Mac, Windows or Linux) - # - is_file_executable("${s}" is_executable) - if(is_executable) - get_filename_component(sdir "${s}" PATH) - set(dotapp_dir "${sdir}") - else() - set(dotapp_dir "${s}") - endif() - endif() - - - set(${dotapp_dir_var} "${dotapp_dir}" PARENT_SCOPE) -endfunction() - - -function(get_bundle_and_executable app bundle_var executable_var valid_var) - set(valid 0) - - if(EXISTS "${app}") - # Is it a directory ending in .app? - if(IS_DIRECTORY "${app}") - if(app MATCHES "\\.app$") - get_bundle_main_executable("${app}" executable) - if(EXISTS "${app}" AND EXISTS "${executable}") - set(${bundle_var} "${app}" PARENT_SCOPE) - set(${executable_var} "${executable}" PARENT_SCOPE) - set(valid 1) - #message(STATUS "info: handled .app directory case...") - else() - message(STATUS "warning: *NOT* handled - .app directory case...") - endif() - else() - message(STATUS "warning: *NOT* handled - directory but not .app case...") - endif() - else() - # Is it an executable file? - is_file_executable("${app}" is_executable) - if(is_executable) - get_dotapp_dir("${app}" dotapp_dir) - if(EXISTS "${dotapp_dir}") - set(${bundle_var} "${dotapp_dir}" PARENT_SCOPE) - set(${executable_var} "${app}" PARENT_SCOPE) - set(valid 1) - #message(STATUS "info: handled executable file in .app dir case...") - else() - get_filename_component(app_dir "${app}" PATH) - set(${bundle_var} "${app_dir}" PARENT_SCOPE) - set(${executable_var} "${app}" PARENT_SCOPE) - set(valid 1) - #message(STATUS "info: handled executable file in any dir case...") - endif() - else() - message(STATUS "warning: *NOT* handled - not .app dir, not executable file...") - endif() - endif() - else() - message(STATUS "warning: *NOT* handled - directory/file does not exist...") - endif() - - if(NOT valid) - set(${bundle_var} "error: not a bundle" PARENT_SCOPE) - set(${executable_var} "error: not a bundle" PARENT_SCOPE) - endif() - - set(${valid_var} ${valid} PARENT_SCOPE) -endfunction() - - -function(get_bundle_all_executables bundle exes_var) - set(exes "") - - file(GLOB_RECURSE file_list "${bundle}/*") - if(UNIX) - find_program(find_cmd "find") - mark_as_advanced(find_cmd) - endif() - - # find command is much quicker than checking every file one by one on Unix - # which can take long time for large bundles, and since anyway we expect - # executable to have execute flag set we can narrow the list much quicker. - if(find_cmd) - execute_process(COMMAND "${find_cmd}" "${bundle}" - -type f \( -perm -0100 -o -perm -0010 -o -perm -0001 \) - OUTPUT_VARIABLE file_list - OUTPUT_STRIP_TRAILING_WHITESPACE - ) - string(REPLACE "\n" ";" file_list "${file_list}") - else() - file(GLOB_RECURSE file_list "${bundle}/*") - endif() - - foreach(f ${file_list}) - is_file_executable("${f}" is_executable) - if(is_executable) - set(exes ${exes} "${f}") - endif() - endforeach() - - set(${exes_var} "${exes}" PARENT_SCOPE) -endfunction() - - -function(get_item_key item key_var) - get_filename_component(item_name "${item}" NAME) - if(WIN32) - string(TOLOWER "${item_name}" item_name) - endif() - string(REPLACE "." "_" ${key_var} "${item_name}") - set(${key_var} ${${key_var}} PARENT_SCOPE) -endfunction() - - -function(clear_bundle_keys keys_var) - foreach(key ${${keys_var}}) - set(${key}_ITEM PARENT_SCOPE) - set(${key}_RESOLVED_ITEM PARENT_SCOPE) - set(${key}_DEFAULT_EMBEDDED_PATH PARENT_SCOPE) - set(${key}_EMBEDDED_ITEM PARENT_SCOPE) - set(${key}_RESOLVED_EMBEDDED_ITEM PARENT_SCOPE) - set(${key}_COPYFLAG PARENT_SCOPE) - endforeach() - set(${keys_var} PARENT_SCOPE) -endfunction() - - -function(set_bundle_key_values keys_var context item exepath dirs copyflag) - get_filename_component(item_name "${item}" NAME) - - get_item_key("${item}" key) - - list(LENGTH ${keys_var} length_before) - gp_append_unique(${keys_var} "${key}") - list(LENGTH ${keys_var} length_after) - - if(NOT length_before EQUAL length_after) - gp_resolve_item("${context}" "${item}" "${exepath}" "${dirs}" resolved_item) - - gp_item_default_embedded_path("${item}" default_embedded_path) - - if(item MATCHES "[^/]+\\.framework/") - # For frameworks, construct the name under the embedded path from the - # opening "${item_name}.framework/" to the closing "/${item_name}": - # - string(REGEX REPLACE "^.*(${item_name}.framework/.*/?${item_name}).*$" "${default_embedded_path}/\\1" embedded_item "${item}") - else() - # For other items, just use the same name as the original, but in the - # embedded path: - # - set(embedded_item "${default_embedded_path}/${item_name}") - - if(APPLE) - # For executables inside the bundle, extract the expected path. - # This remove the hack introduced in commit 6f8bdd27 consisting in - # reseting the value of 'resolved_embedded_item' with 'resolved_item'. - get_dotapp_dir("${exepath}" exe_dotapp_dir) - if(NOT DEFINED gp_bundle_executables) - get_bundle_all_executables("${exe_dotapp_dir}" gp_bundle_executables) - endif() - foreach(exe ${gp_bundle_executables}) - get_item_key("${exe}" exe_key) - list(APPEND exe_keys ${exe_key}) - endforeach() - list(FIND exe_keys ${key} is_executable) - if(NOT is_executable EQUAL "-1") - get_filename_component(resolved_item_path ${resolved_item} PATH) - file(RELATIVE_PATH exe_relative_path_from_dir ${exe_dotapp_dir} ${resolved_item_path}) - # For example, if input variables are: - # resolved_item: /path/to/MyApp.app/Contents/bin/myapp - # exe_dotapp_dir: /path/to/MyApp.app - # Computed variables will be: - # resolved_item_path: /path/to/MyApp.app/Contents/bin - # exe_relative_path_from_dir: Contents/bin - set(embedded_item "@executable_path/../../${exe_relative_path_from_dir}/${item_name}") - set(show_status 0) - if(show_status) - message(STATUS "resolved_item='${resolved_item}'") - message(STATUS "exe_dotapp_dir='${exe_dotapp_dir}'") - message(STATUS "exe_relative_path_from_dir='${exe_relative_path_from_dir}'") - message(STATUS "item_name='${item_name}'") - message(STATUS "embedded_item='${embedded_item}'") - message(STATUS "") - endif() - endif() - endif() - endif() - - gp_resolve_embedded_item("${context}" "${embedded_item}" "${exepath}" resolved_embedded_item) - get_filename_component(resolved_embedded_item "${resolved_embedded_item}" ABSOLUTE) - - # Do not copy already embedded item - set(verbose 0) - is_resolved_item_embedded("${resolved_embedded_item}" "${exepath}" "${verbose}" is_embedded) - if(EXISTS "${resolved_embedded_item}" AND is_embedded) - set(copyflag 0) - set(resolved_item "${resolved_embedded_item}") - endif() - - set(${keys_var} ${${keys_var}} PARENT_SCOPE) - set(${key}_ITEM "${item}" PARENT_SCOPE) - set(${key}_RESOLVED_ITEM "${resolved_item}" PARENT_SCOPE) - set(${key}_DEFAULT_EMBEDDED_PATH "${default_embedded_path}" PARENT_SCOPE) - set(${key}_EMBEDDED_ITEM "${embedded_item}" PARENT_SCOPE) - set(${key}_RESOLVED_EMBEDDED_ITEM "${resolved_embedded_item}" PARENT_SCOPE) - set(${key}_COPYFLAG "${copyflag}" PARENT_SCOPE) - else() - #message("warning: item key '${key}' already in the list, subsequent references assumed identical to first") - endif() -endfunction() - - -function(get_bundle_keys app libs dirs keys_var) - set(${keys_var} PARENT_SCOPE) - - get_bundle_and_executable("${app}" bundle executable valid) - if(valid) - # Always use the exepath of the main bundle executable for @executable_path - # replacements: - # - get_filename_component(exepath "${executable}" PATH) - - # But do fixups on all executables in the bundle: - # - get_bundle_all_executables("${bundle}" gp_bundle_executables) - - # For each extra lib, accumulate a key as well and then also accumulate - # any of its prerequisites. (Extra libs are typically dynamically loaded - # plugins: libraries that are prerequisites for full runtime functionality - # but that do not show up in otool -L output...) - # - foreach(lib ${libs}) - set_bundle_key_values(${keys_var} "${lib}" "${lib}" "${exepath}" "${dirs}" 0) - - set(prereqs "") - get_prerequisites("${lib}" prereqs 1 1 "${exepath}" "${dirs}") - foreach(pr ${prereqs}) - set_bundle_key_values(${keys_var} "${lib}" "${pr}" "${exepath}" "${dirs}" 1) - endforeach() - endforeach() - - # For each executable found in the bundle, accumulate keys as we go. - # The list of keys should be complete when all prerequisites of all - # binaries in the bundle have been analyzed. - # - foreach(exe ${gp_bundle_executables}) - # Add the exe itself to the keys: - # - set_bundle_key_values(${keys_var} "${exe}" "${exe}" "${exepath}" "${dirs}" 0) - - # Add each prerequisite to the keys: - # - set(prereqs "") - get_prerequisites("${exe}" prereqs 1 1 "${exepath}" "${dirs}") - foreach(pr ${prereqs}) - set_bundle_key_values(${keys_var} "${exe}" "${pr}" "${exepath}" "${dirs}" 1) - endforeach() - endforeach() - - # Propagate values to caller's scope: - # - set(${keys_var} ${${keys_var}} PARENT_SCOPE) - foreach(key ${${keys_var}}) - set(${key}_ITEM "${${key}_ITEM}" PARENT_SCOPE) - set(${key}_RESOLVED_ITEM "${${key}_RESOLVED_ITEM}" PARENT_SCOPE) - set(${key}_DEFAULT_EMBEDDED_PATH "${${key}_DEFAULT_EMBEDDED_PATH}" PARENT_SCOPE) - set(${key}_EMBEDDED_ITEM "${${key}_EMBEDDED_ITEM}" PARENT_SCOPE) - set(${key}_RESOLVED_EMBEDDED_ITEM "${${key}_RESOLVED_EMBEDDED_ITEM}" PARENT_SCOPE) - set(${key}_COPYFLAG "${${key}_COPYFLAG}" PARENT_SCOPE) - endforeach() - endif() -endfunction() - - -function(copy_resolved_item_into_bundle resolved_item resolved_embedded_item) - if(WIN32) - # ignore case on Windows - string(TOLOWER "${resolved_item}" resolved_item_compare) - string(TOLOWER "${resolved_embedded_item}" resolved_embedded_item_compare) - else() - set(resolved_item_compare "${resolved_item}") - set(resolved_embedded_item_compare "${resolved_embedded_item}") - endif() - - if("${resolved_item_compare}" STREQUAL "${resolved_embedded_item_compare}") - message(STATUS "warning: resolved_item == resolved_embedded_item - not copying...") - else() - #message(STATUS "copying COMMAND ${CMAKE_COMMAND} -E copy ${resolved_item} ${resolved_embedded_item}") - execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${resolved_item}" "${resolved_embedded_item}") - if(UNIX AND NOT APPLE) - file(RPATH_REMOVE FILE "${resolved_embedded_item}") - endif() - endif() - -endfunction() - - -function(copy_resolved_framework_into_bundle resolved_item resolved_embedded_item) - if(WIN32) - # ignore case on Windows - string(TOLOWER "${resolved_item}" resolved_item_compare) - string(TOLOWER "${resolved_embedded_item}" resolved_embedded_item_compare) - else() - set(resolved_item_compare "${resolved_item}") - set(resolved_embedded_item_compare "${resolved_embedded_item}") - endif() - - if("${resolved_item_compare}" STREQUAL "${resolved_embedded_item_compare}") - message(STATUS "warning: resolved_item == resolved_embedded_item - not copying...") - else() - if(BU_COPY_FULL_FRAMEWORK_CONTENTS) - # Full Framework (everything): - get_filename_component(resolved_dir "${resolved_item}" PATH) - get_filename_component(resolved_dir "${resolved_dir}/../.." ABSOLUTE) - get_filename_component(resolved_embedded_dir "${resolved_embedded_item}" PATH) - get_filename_component(resolved_embedded_dir "${resolved_embedded_dir}/../.." ABSOLUTE) - #message(STATUS "copying COMMAND ${CMAKE_COMMAND} -E copy_directory '${resolved_dir}' '${resolved_embedded_dir}'") - execute_process(COMMAND ${CMAKE_COMMAND} -E copy_directory "${resolved_dir}" "${resolved_embedded_dir}") - else() - # Framework lib itself: - #message(STATUS "copying COMMAND ${CMAKE_COMMAND} -E copy ${resolved_item} ${resolved_embedded_item}") - execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${resolved_item}" "${resolved_embedded_item}") - - # Plus Resources, if they exist: - string(REGEX REPLACE "^(.*)/[^/]+$" "\\1/Resources" resolved_resources "${resolved_item}") - string(REGEX REPLACE "^(.*)/[^/]+$" "\\1/Resources" resolved_embedded_resources "${resolved_embedded_item}") - if(EXISTS "${resolved_resources}") - #message(STATUS "copying COMMAND ${CMAKE_COMMAND} -E copy_directory '${resolved_resources}' '${resolved_embedded_resources}'") - execute_process(COMMAND ${CMAKE_COMMAND} -E copy_directory "${resolved_resources}" "${resolved_embedded_resources}") - endif() - - # Some frameworks e.g. Qt put Info.plist in wrong place, so when it is - # missing in resources, copy it from other well known incorrect locations: - if(NOT EXISTS "${resolved_resources}/Info.plist") - # Check for Contents/Info.plist in framework root (older Qt SDK): - string(REGEX REPLACE "^(.*)/[^/]+/[^/]+/[^/]+$" "\\1/Contents/Info.plist" resolved_info_plist "${resolved_item}") - string(REGEX REPLACE "^(.*)/[^/]+$" "\\1/Resources/Info.plist" resolved_embedded_info_plist "${resolved_embedded_item}") - if(EXISTS "${resolved_info_plist}") - #message(STATUS "copying COMMAND ${CMAKE_COMMAND} -E copy_directory '${resolved_info_plist}' '${resolved_embedded_info_plist}'") - execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${resolved_info_plist}" "${resolved_embedded_info_plist}") - endif() - endif() - - # Check if framework is versioned and fix it layout - string(REGEX REPLACE "^.*/([^/]+)/[^/]+$" "\\1" resolved_embedded_version "${resolved_embedded_item}") - string(REGEX REPLACE "^(.*)/[^/]+/[^/]+$" "\\1" resolved_embedded_versions "${resolved_embedded_item}") - string(REGEX REPLACE "^.*/([^/]+)/[^/]+/[^/]+$" "\\1" resolved_embedded_versions_basename "${resolved_embedded_item}") - if(resolved_embedded_versions_basename STREQUAL "Versions") - # Ensure Current symlink points to the framework version - if(NOT EXISTS "${resolved_embedded_versions}/Current") - execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink "${resolved_embedded_version}" "${resolved_embedded_versions}/Current") - endif() - # Restore symlinks in framework root pointing to current framework - # binary and resources: - string(REGEX REPLACE "^(.*)/[^/]+/[^/]+/[^/]+$" "\\1" resolved_embedded_root "${resolved_embedded_item}") - string(REGEX REPLACE "^.*/([^/]+)$" "\\1" resolved_embedded_item_basename "${resolved_embedded_item}") - if(NOT EXISTS "${resolved_embedded_root}/${resolved_embedded_item_basename}") - execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink "Versions/Current/${resolved_embedded_item_basename}" "${resolved_embedded_root}/${resolved_embedded_item_basename}") - endif() - if(NOT EXISTS "${resolved_embedded_root}/Resources") - execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink "Versions/Current/Resources" "${resolved_embedded_root}/Resources") - endif() - endif() - endif() - if(UNIX AND NOT APPLE) - file(RPATH_REMOVE FILE "${resolved_embedded_item}") - endif() - endif() - -endfunction() - -function(is_resolved_item_embedded resolved_item exepath verbose is_embedded_var) - get_dotapp_dir("${exepath}" exe_dotapp_dir) - string(LENGTH "${exe_dotapp_dir}/" exe_dotapp_dir_length) - string(LENGTH "${resolved_item}" resolved_item_length) - set(path_too_short 0) - set(is_embedded 0) - if(${resolved_item_length} LESS ${exe_dotapp_dir_length}) - set(path_too_short 1) - endif() - if(NOT path_too_short) - string(SUBSTRING "${resolved_item}" 0 ${exe_dotapp_dir_length} item_substring) - if("${exe_dotapp_dir}/" STREQUAL "${item_substring}") - set(is_embedded 1) - endif() - endif() - if(verbose AND NOT is_embedded) - message(" exe_dotapp_dir/='${exe_dotapp_dir}/'") - message(" item_substring='${item_substring}'") - message(" resolved_item='${resolved_item}'") - message("") - endif() - set(${is_embedded_var} ${is_embedded} PARENT_SCOPE) -endfunction() - -function(fixup_bundle_item resolved_embedded_item exepath dirs) - # This item's key is "ikey": - # - get_item_key("${resolved_embedded_item}" ikey) - - # Ensure the item is "inside the .app bundle" -- it should not be fixed up if - # it is not in the .app bundle... Otherwise, we'll modify files in the build - # tree, or in other varied locations around the file system, with our call to - # install_name_tool. Make sure that doesn't happen here: - # - set(verbose 1) - is_resolved_item_embedded("${resolved_embedded_item}" "${exepath}" "${verbose}" is_embedded) - if(NOT is_embedded) - message("Install or copy the item into the bundle before calling fixup_bundle.") - message("Or maybe there's a typo or incorrect path in one of the args to fixup_bundle?") - message("") - message(FATAL_ERROR "cannot fixup an item that is not in the bundle...") - endif() - - set(prereqs "") - get_prerequisites("${resolved_embedded_item}" prereqs 1 0 "${exepath}" "${dirs}") - - set(changes "") - - foreach(pr ${prereqs}) - # Each referenced item's key is "rkey" in the loop: - # - get_item_key("${pr}" rkey) - - if(NOT "${${rkey}_EMBEDDED_ITEM}" STREQUAL "") - set(changes ${changes} "-change" "${pr}" "${${rkey}_EMBEDDED_ITEM}") - else() - message("warning: unexpected reference to '${pr}'") - endif() - endforeach() - - if(BU_CHMOD_BUNDLE_ITEMS) - execute_process(COMMAND chmod u+w "${resolved_embedded_item}") - endif() - - # Change this item's id and all of its references in one call - # to install_name_tool: - # - execute_process(COMMAND install_name_tool - ${changes} -id "${${ikey}_EMBEDDED_ITEM}" "${resolved_embedded_item}" - ) -endfunction() - - -function(fixup_bundle app libs dirs) - message(STATUS "fixup_bundle") - message(STATUS " app='${app}'") - message(STATUS " libs='${libs}'") - message(STATUS " dirs='${dirs}'") - - get_bundle_and_executable("${app}" bundle executable valid) - message(STATUS " bundle='${bundle}'") - message(STATUS " executable='${executable}'") - if(valid) - get_filename_component(exepath "${executable}" PATH) - - # TODO: Extract list of rpath dirs automatically. On MacOSX, the following could be - # done: otool -l path/to/executable | grep -A 3 LC_RPATH | grep path - # See http://www.mikeash.com/pyblog/friday-qa-2009-11-06-linking-and-install-names.html#comment-87ea054b4839586412727dcfc94c79d2 - set(GP_RPATH_DIR ${bundle}/Contents) - message(STATUS " GP_RPATH_DIR='${GP_RPATH_DIR}'") - - message(STATUS "fixup_bundle: preparing...") - get_bundle_keys("${app}" "${libs}" "${dirs}" keys) - - message(STATUS "fixup_bundle: copying...") - list(LENGTH keys n) - math(EXPR n ${n}*2) - - set(i 0) - foreach(key ${keys}) - math(EXPR i ${i}+1) - if(${${key}_COPYFLAG}) - message(STATUS "${i}/${n}: copying '${${key}_RESOLVED_ITEM}'") - else() - message(STATUS "${i}/${n}: *NOT* copying '${${key}_RESOLVED_ITEM}'") - endif() - - set(show_status 0) - if(show_status) - message(STATUS "key='${key}'") - message(STATUS "item='${${key}_ITEM}'") - message(STATUS "resolved_item='${${key}_RESOLVED_ITEM}'") - message(STATUS "default_embedded_path='${${key}_DEFAULT_EMBEDDED_PATH}'") - message(STATUS "embedded_item='${${key}_EMBEDDED_ITEM}'") - message(STATUS "resolved_embedded_item='${${key}_RESOLVED_EMBEDDED_ITEM}'") - message(STATUS "copyflag='${${key}_COPYFLAG}'") - message(STATUS "") - endif() - - if(${${key}_COPYFLAG}) - set(item "${${key}_ITEM}") - if(item MATCHES "[^/]+\\.framework/") - copy_resolved_framework_into_bundle("${${key}_RESOLVED_ITEM}" - "${${key}_RESOLVED_EMBEDDED_ITEM}") - else() - copy_resolved_item_into_bundle("${${key}_RESOLVED_ITEM}" - "${${key}_RESOLVED_EMBEDDED_ITEM}") - endif() - endif() - endforeach() - - message(STATUS "fixup_bundle: fixing...") - foreach(key ${keys}) - math(EXPR i ${i}+1) - if(APPLE) - message(STATUS "${i}/${n}: fixing up '${${key}_RESOLVED_EMBEDDED_ITEM}'") - fixup_bundle_item("${${key}_RESOLVED_EMBEDDED_ITEM}" "${exepath}" "${dirs}") - else() - message(STATUS "${i}/${n}: fix-up not required on this platform '${${key}_RESOLVED_EMBEDDED_ITEM}'") - endif() - endforeach() - - message(STATUS "fixup_bundle: cleaning up...") - clear_bundle_keys(keys) - - message(STATUS "fixup_bundle: verifying...") - verify_app("${app}") - else() - message(SEND_ERROR "error: fixup_bundle: not a valid bundle") - endif() - - message(STATUS "fixup_bundle: done") -endfunction() - - -function(copy_and_fixup_bundle src dst libs dirs) - execute_process(COMMAND ${CMAKE_COMMAND} -E copy_directory "${src}" "${dst}") - fixup_bundle("${dst}" "${libs}" "${dirs}") -endfunction() - - -function(verify_bundle_prerequisites bundle result_var info_var) - set(result 1) - set(info "") - set(count 0) - - get_bundle_main_executable("${bundle}" main_bundle_exe) - - file(GLOB_RECURSE file_list "${bundle}/*") - foreach(f ${file_list}) - is_file_executable("${f}" is_executable) - if(is_executable) - get_filename_component(exepath "${f}" PATH) - math(EXPR count "${count} + 1") - - message(STATUS "executable file ${count}: ${f}") - - set(prereqs "") - get_prerequisites("${f}" prereqs 1 1 "${exepath}" "") - - # On the Mac, - # "embedded" and "system" prerequisites are fine... anything else means - # the bundle's prerequisites are not verified (i.e., the bundle is not - # really "standalone") - # - # On Windows (and others? Linux/Unix/...?) - # "local" and "system" prereqs are fine... - # - set(external_prereqs "") - - foreach(p ${prereqs}) - set(p_type "") - gp_file_type("${f}" "${p}" p_type) - - if(APPLE) - if(NOT "${p_type}" STREQUAL "embedded" AND NOT "${p_type}" STREQUAL "system") - set(external_prereqs ${external_prereqs} "${p}") - endif() - else() - if(NOT "${p_type}" STREQUAL "local" AND NOT "${p_type}" STREQUAL "system") - set(external_prereqs ${external_prereqs} "${p}") - endif() - endif() - endforeach() - - if(external_prereqs) - # Found non-system/somehow-unacceptable prerequisites: - set(result 0) - set(info ${info} "external prerequisites found:\nf='${f}'\nexternal_prereqs='${external_prereqs}'\n") - endif() - endif() - endforeach() - - if(result) - set(info "Verified ${count} executable files in '${bundle}'") - endif() - - set(${result_var} "${result}" PARENT_SCOPE) - set(${info_var} "${info}" PARENT_SCOPE) -endfunction() - - -function(verify_bundle_symlinks bundle result_var info_var) - set(result 1) - set(info "") - set(count 0) - - # TODO: implement this function for real... - # Right now, it is just a stub that verifies unconditionally... - - set(${result_var} "${result}" PARENT_SCOPE) - set(${info_var} "${info}" PARENT_SCOPE) -endfunction() - - -function(verify_app app) - set(verified 0) - set(info "") - - get_bundle_and_executable("${app}" bundle executable valid) - - message(STATUS "===========================================================================") - message(STATUS "Analyzing app='${app}'") - message(STATUS "bundle='${bundle}'") - message(STATUS "executable='${executable}'") - message(STATUS "valid='${valid}'") - - # Verify that the bundle does not have any "external" prerequisites: - # - verify_bundle_prerequisites("${bundle}" verified info) - message(STATUS "verified='${verified}'") - message(STATUS "info='${info}'") - message(STATUS "") - - if(verified) - # Verify that the bundle does not have any symlinks to external files: - # - verify_bundle_symlinks("${bundle}" verified info) - message(STATUS "verified='${verified}'") - message(STATUS "info='${info}'") - message(STATUS "") - endif() - - if(NOT verified) - message(FATAL_ERROR "error: verify_app failed") - endif() -endfunction() diff --git a/cmake/COPYING-CMAKE-SCRIPTS b/cmake/COPYING-CMAKE-SCRIPTS index 21f1dbf7d..d33c6f33b 100644 --- a/cmake/COPYING-CMAKE-SCRIPTS +++ b/cmake/COPYING-CMAKE-SCRIPTS @@ -25,269 +25,3 @@ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -The following files are derived from the Slicer project -(https://github.com/Slicer/Slicer), which in turn derived from CMake project (http://cmake.org) and are covered under the licenses below. - -BundleUtilitiesWithRPath.cmake, GetPrerequisitesWithRPath.cmake - -# Slicer - -For more information, please see: - - http://www.slicer.org - -The 3D Slicer license below is a BSD style license, with extensions -to cover contributions and other issues specific to 3D Slicer. - - -3D Slicer Contribution and Software License Agreement ("Agreement") -Version 1.0 (December 20, 2005) - -This Agreement covers contributions to and downloads from the 3D -Slicer project ("Slicer") maintained by The Brigham and Women's -Hospital, Inc. ("Brigham"). Part A of this Agreement applies to -contributions of software and/or data to Slicer (including making -revisions of or additions to code and/or data already in Slicer). Part -B of this Agreement applies to downloads of software and/or data from -Slicer. Part C of this Agreement applies to all transactions with -Slicer. If you distribute Software (as defined below) downloaded from -Slicer, all of the paragraphs of Part B of this Agreement must be -included with and apply to such Software. - -Your contribution of software and/or data to Slicer (including prior -to the date of the first publication of this Agreement, each a -"Contribution") and/or downloading, copying, modifying, displaying, -distributing or use of any software and/or data from Slicer -(collectively, the "Software") constitutes acceptance of all of the -terms and conditions of this Agreement. If you do not agree to such -terms and conditions, you have no right to contribute your -Contribution, or to download, copy, modify, display, distribute or use -the Software. - -PART A. CONTRIBUTION AGREEMENT - License to Brigham with Right to -Sublicense ("Contribution Agreement"). - -1. As used in this Contribution Agreement, "you" means the individual - contributing the Contribution to Slicer and the institution or - entity which employs or is otherwise affiliated with such - individual in connection with such Contribution. - -2. This Contribution Agreement applies to all Contributions made to - Slicer, including without limitation Contributions made prior to - the date of first publication of this Agreement. If at any time you - make a Contribution to Slicer, you represent that (i) you are - legally authorized and entitled to make such Contribution and to - grant all licenses granted in this Contribution Agreement with - respect to such Contribution; (ii) if your Contribution includes - any patient data, all such data is de-identified in accordance with - U.S. confidentiality and security laws and requirements, including - but not limited to the Health Insurance Portability and - Accountability Act (HIPAA) and its regulations, and your disclosure - of such data for the purposes contemplated by this Agreement is - properly authorized and in compliance with all applicable laws and - regulations; and (iii) you have preserved in the Contribution all - applicable attributions, copyright notices and licenses for any - third party software or data included in the Contribution. - -3. Except for the licenses granted in this Agreement, you reserve all - right, title and interest in your Contribution. - -4. You hereby grant to Brigham, with the right to sublicense, a - perpetual, worldwide, non-exclusive, no charge, royalty-free, - irrevocable license to use, reproduce, make derivative works of, - display and distribute the Contribution. If your Contribution is - protected by patent, you hereby grant to Brigham, with the right to - sublicense, a perpetual, worldwide, non-exclusive, no-charge, - royalty-free, irrevocable license under your interest in patent - rights covering the Contribution, to make, have made, use, sell and - otherwise transfer your Contribution, alone or in combination with - any other code. - -5. You acknowledge and agree that Brigham may incorporate your - Contribution into Slicer and may make Slicer available to members - of the public on an open source basis under terms substantially in - accordance with the Software License set forth in Part B of this - Agreement. You further acknowledge and agree that Brigham shall - have no liability arising in connection with claims resulting from - your breach of any of the terms of this Agreement. - -6. YOU WARRANT THAT TO THE BEST OF YOUR KNOWLEDGE YOUR CONTRIBUTION - DOES NOT CONTAIN ANY CODE THAT REQURES OR PRESCRIBES AN "OPEN - SOURCE LICENSE" FOR DERIVATIVE WORKS (by way of non-limiting - example, the GNU General Public License or other so-called - "reciprocal" license that requires any derived work to be licensed - under the GNU General Public License or other "open source - license"). - -PART B. DOWNLOADING AGREEMENT - License from Brigham with Right to -Sublicense ("Software License"). - -1. As used in this Software License, "you" means the individual - downloading and/or using, reproducing, modifying, displaying and/or - distributing the Software and the institution or entity which - employs or is otherwise affiliated with such individual in - connection therewith. The Brigham and Women?s Hospital, - Inc. ("Brigham") hereby grants you, with right to sublicense, with - respect to Brigham's rights in the software, and data, if any, - which is the subject of this Software License (collectively, the - "Software"), a royalty-free, non-exclusive license to use, - reproduce, make derivative works of, display and distribute the - Software, provided that: - -(a) you accept and adhere to all of the terms and conditions of this -Software License; - -(b) in connection with any copy of or sublicense of all or any portion -of the Software, all of the terms and conditions in this Software -License shall appear in and shall apply to such copy and such -sublicense, including without limitation all source and executable -forms and on any user documentation, prefaced with the following -words: "All or portions of this licensed product (such portions are -the "Software") have been obtained under license from The Brigham and -Women's Hospital, Inc. and are subject to the following terms and -conditions:" - -(c) you preserve and maintain all applicable attributions, copyright -notices and licenses included in or applicable to the Software; - -(d) modified versions of the Software must be clearly identified and -marked as such, and must not be misrepresented as being the original -Software; and - -(e) you consider making, but are under no obligation to make, the -source code of any of your modifications to the Software freely -available to others on an open source basis. - -2. The license granted in this Software License includes without - limitation the right to (i) incorporate the Software into - proprietary programs (subject to any restrictions applicable to - such programs), (ii) add your own copyright statement to your - modifications of the Software, and (iii) provide additional or - different license terms and conditions in your sublicenses of - modifications of the Software; provided that in each case your use, - reproduction or distribution of such modifications otherwise - complies with the conditions stated in this Software License. - -3. This Software License does not grant any rights with respect to - third party software, except those rights that Brigham has been - authorized by a third party to grant to you, and accordingly you - are solely responsible for (i) obtaining any permissions from third - parties that you need to use, reproduce, make derivative works of, - display and distribute the Software, and (ii) informing your - sublicensees, including without limitation your end-users, of their - obligations to secure any such required permissions. - -4. The Software has been designed for research purposes only and has - not been reviewed or approved by the Food and Drug Administration - or by any other agency. YOU ACKNOWLEDGE AND AGREE THAT CLINICAL - APPLICATIONS ARE NEITHER RECOMMENDED NOR ADVISED. Any - commercialization of the Software is at the sole risk of the party - or parties engaged in such commercialization. You further agree to - use, reproduce, make derivative works of, display and distribute - the Software in compliance with all applicable governmental laws, - regulations and orders, including without limitation those relating - to export and import control. - -5. The Software is provided "AS IS" and neither Brigham nor any - contributor to the software (each a "Contributor") shall have any - obligation to provide maintenance, support, updates, enhancements - or modifications thereto. BRIGHAM AND ALL CONTRIBUTORS SPECIFICALLY - DISCLAIM ALL EXPRESS AND IMPLIED WARRANTIES OF ANY KIND INCLUDING, - BUT NOT LIMITED TO, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR - A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL - BRIGHAM OR ANY CONTRIBUTOR BE LIABLE TO ANY PARTY FOR DIRECT, - INDIRECT, SPECIAL, INCIDENTAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES - HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY ARISING IN ANY WAY - RELATED TO THE SOFTWARE, EVEN IF BRIGHAM OR ANY CONTRIBUTOR HAS - BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. TO THE MAXIMUM - EXTENT NOT PROHIBITED BY LAW OR REGULATION, YOU FURTHER ASSUME ALL - LIABILITY FOR YOUR USE, REPRODUCTION, MAKING OF DERIVATIVE WORKS, - DISPLAY, LICENSE OR DISTRIBUTION OF THE SOFTWARE AND AGREE TO - INDEMNIFY AND HOLD HARMLESS BRIGHAM AND ALL CONTRIBUTORS FROM AND - AGAINST ANY AND ALL CLAIMS, SUITS, ACTIONS, DEMANDS AND JUDGMENTS - ARISING THEREFROM. - -6. None of the names, logos or trademarks of Brigham or any of - Brigham's affiliates or any of the Contributors, or any funding - agency, may be used to endorse or promote products produced in - whole or in part by operation of the Software or derived from or - based on the Software without specific prior written permission - from the applicable party. - -7. Any use, reproduction or distribution of the Software which is not - in accordance with this Software License shall automatically revoke - all rights granted to you under this Software License and render - Paragraphs 1 and 2 of this Software License null and void. - -8. This Software License does not grant any rights in or to any - intellectual property owned by Brigham or any Contributor except - those rights expressly granted hereunder. - -PART C. MISCELLANEOUS - -This Agreement shall be governed by and construed in accordance with -the laws of The Commonwealth of Massachusetts without regard to -principles of conflicts of law. This Agreement shall supercede and -replace any license terms that you may have agreed to previously with -respect to Slicer. - -# CMake - -CMake - Cross Platform Makefile Generator -Copyright 2000-2015 Kitware, Inc. -Copyright 2000-2011 Insight Software Consortium -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - -* Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -* Neither the names of Kitware, Inc., the Insight Software Consortium, - nor the names of their contributors may be used to endorse or promote - products derived from this software without specific prior written - permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ------------------------------------------------------------------------------- - -The above copyright and license notice applies to distributions of -CMake in source and binary form. Some source files contain additional -notices of original copyright by their contributors; see each source -for details. Third-party software packages supplied with CMake under -compatible licenses provide their own copyright notices documented in -corresponding subdirectories. - ------------------------------------------------------------------------------- - -CMake was initially developed by Kitware with the following sponsorship: - - * National Library of Medicine at the National Institutes of Health - as part of the Insight Segmentation and Registration Toolkit (ITK). - - * US National Labs (Los Alamos, Livermore, Sandia) ASC Parallel - Visualization Initiative. - - * National Alliance for Medical Image Computing (NAMIC) is funded by the - National Institutes of Health through the NIH Roadmap for Medical Research, - Grant U54 EB005149. - - * Kitware, Inc. diff --git a/cmake/GetPrerequisitesWithRPath.cmake b/cmake/GetPrerequisitesWithRPath.cmake deleted file mode 100644 index 5b5751ead..000000000 --- a/cmake/GetPrerequisitesWithRPath.cmake +++ /dev/null @@ -1,990 +0,0 @@ -# - Functions to analyze and list executable file prerequisites. -# This module provides functions to list the .dll, .dylib or .so -# files that an executable or shared library file depends on. (Its -# prerequisites.) -# -# It uses various tools to obtain the list of required shared library files: -# dumpbin (Windows) -# objdump (MinGW on Windows) -# ldd (Linux/Unix) -# otool (Mac OSX) -# The following functions are provided by this module: -# get_prerequisites -# list_prerequisites -# list_prerequisites_by_glob -# gp_append_unique -# is_file_executable -# gp_item_default_embedded_path -# (projects can override with gp_item_default_embedded_path_override) -# gp_resolve_item -# (projects can override with gp_resolve_item_override) -# gp_resolve_embedded_item -# (projects can override with gp_resolve_embedded_item_override) -# gp_resolved_file_type -# (projects can override with gp_resolved_file_type_override) -# gp_file_type -# Requires CMake 2.6 or greater because it uses function, break, return and -# PARENT_SCOPE. -# -# GET_PREREQUISITES( -# ) -# Get the list of shared library files required by . The list in -# the variable named should be empty on first entry to -# this function. On exit, will contain the list of -# required shared library files. -# -# is the full path to an executable file. is the -# name of a CMake variable to contain the results. must be 0 -# or 1 indicating whether to include or exclude "system" prerequisites. If -# is set to 1 all prerequisites will be found recursively, if set to -# 0 only direct prerequisites are listed. is the path to the top -# level executable used for @executable_path replacment on the Mac. is -# a list of paths where libraries might be found: these paths are searched -# first when a target without any path info is given. Then standard system -# locations are also searched: PATH, Framework locations, /usr/lib... -# -# LIST_PREREQUISITES( [ [ []]]) -# Print a message listing the prerequisites of . -# -# is the name of a shared library or executable target or the full -# path to a shared library or executable file. If is set to 1 all -# prerequisites will be found recursively, if set to 0 only direct -# prerequisites are listed. must be 0 or 1 indicating whether -# to include or exclude "system" prerequisites. With set to 0 only -# the full path names of the prerequisites are printed, set to 1 extra -# informatin will be displayed. -# -# LIST_PREREQUISITES_BY_GLOB( ) -# Print the prerequisites of shared library and executable files matching a -# globbing pattern. is GLOB or GLOB_RECURSE and is a -# globbing expression used with "file(GLOB" or "file(GLOB_RECURSE" to retrieve -# a list of matching files. If a matching file is executable, its prerequisites -# are listed. -# -# Any additional (optional) arguments provided are passed along as the -# optional arguments to the list_prerequisites calls. -# -# GP_APPEND_UNIQUE( ) -# Append to the list variable only if the value is not -# already in the list. -# -# IS_FILE_EXECUTABLE( ) -# Return 1 in if is a binary executable, 0 otherwise. -# -# GP_IS_FILE_EXECUTABLE_EXCLUDE_REGEX can be set to a regular expression used -# to give a hint to identify more quickly if a given file is an executable or not. -# This is particularly useful on unix platform where it can avoid a lot of -# time-consuming call to "file" external process. For packages bundling hundreds -# of libraries, executables, resources and data, it largely speeds up the function -# "get_bundle_all_executables". -# On unix, a convenient command line allowing to collect recursively all file extensions -# useful to generate a regular expression like "\\.(dylib|py|pyc|so)$" is: -# find . -type f -name '*.*' | sed 's@.*/.*\.@@' | sort | uniq | tr "\\n" "|" -# -# GP_ITEM_DEFAULT_EMBEDDED_PATH( ) -# Return the path that others should refer to the item by when the item -# is embedded inside a bundle. -# -# Override on a per-project basis by providing a project-specific -# gp_item_default_embedded_path_override function. -# -# GP_RESOLVE_ITEM( ) -# Resolve an item into an existing full path file. -# -# Override on a per-project basis by providing a project-specific -# gp_resolve_item_override function. -# -# GP_RESOLVE_EMBEDDED_ITEM( ) -# Resolve an embedded item into the full path within the full path. Since the item can be -# copied later, it doesn't have to exist when calling this function. -# -# Override on a per-project basis by providing a project-specific -# gp_resolve_embedded_item_override function. -# -# If GP_RPATH_DIR variable is set then item matching '@rpath' are -# resolved using the provided directory. Currently setting this variable -# has an effect only on MacOSX when fixing up application bundle. The directory -# are also assumed to be located within the application bundle. It is -# usually the directory passed to the 'rpath' linker option. -# -# GP_RESOLVED_FILE_TYPE( ) -# Return the type of with respect to . String -# describing type of prerequisite is returned in variable named . -# -# Use and if necessary to resolve non-absolute -# values -- but only for non-embedded items. -# -# Possible types are: -# system -# local -# embedded -# other -# Override on a per-project basis by providing a project-specific -# gp_resolved_file_type_override function. -# -# GP_FILE_TYPE( ) -# Return the type of with respect to . String -# describing type of prerequisite is returned in variable named . -# -# Possible types are: -# system -# local -# embedded -# other - -#============================================================================= -# Copyright 2008-2009 Kitware, Inc. -# -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. -#============================================================================= -# (To distribute this file outside of CMake, substitute the full -# License text for the above reference.) - -# Copyright (c) 2015 BWH and 3D Slicer contributors, http://slicer.org -# -# Redistribution AND use is allowed according to the terms of the -# BSD-style license. -# For details see the accompanying COPYING-CMAKE-SCRIPTS file. - -function(gp_append_unique list_var value) - set(contains 0) - - foreach(item ${${list_var}}) - if("${item}" STREQUAL "${value}") - set(contains 1) - break() - endif() - endforeach() - - if(NOT contains) - set(${list_var} ${${list_var}} "${value}" PARENT_SCOPE) - endif() -endfunction() - - -function(is_file_executable file result_var) - # - # A file is not executable until proven otherwise: - # - set(${result_var} 0 PARENT_SCOPE) - - get_filename_component(file_full "${file}" ABSOLUTE) - string(TOLOWER "${file_full}" file_full_lower) - - # If file name ends in .exe on Windows, *assume* executable: - # - if(WIN32 AND NOT UNIX) - if("${file_full_lower}" MATCHES "\\.exe$") - set(${result_var} 1 PARENT_SCOPE) - return() - endif() - - # A clause could be added here that uses output or return value of dumpbin - # to determine ${result_var}. In 99%+? practical cases, the exe name - # match will be sufficient... - # - endif() - - # Use the information returned from the Unix shell command "file" to - # determine if ${file_full} should be considered an executable file... - # - # If the file command's output contains "executable" and does *not* contain - # "text" then it is likely an executable suitable for prerequisite analysis - # via the get_prerequisites macro. - # - if(UNIX) - - if(NOT "${GP_IS_FILE_EXECUTABLE_EXCLUDE_REGEX}" STREQUAL "") - if(${file_full} MATCHES "${GP_IS_FILE_EXECUTABLE_EXCLUDE_REGEX}") - set(${result_var} 0 PARENT_SCOPE) - return() - endif() - endif() - - if(NOT file_cmd) - find_program(file_cmd "file") - mark_as_advanced(file_cmd) - endif() - - if(file_cmd) - execute_process(COMMAND "${file_cmd}" "${file_full}" - OUTPUT_VARIABLE file_ov - OUTPUT_STRIP_TRAILING_WHITESPACE - ) - - # Replace the name of the file in the output with a placeholder token - # (the string " _file_full_ ") so that just in case the path name of - # the file contains the word "text" or "executable" we are not fooled - # into thinking "the wrong thing" because the file name matches the - # other 'file' command output we are looking for... - # - string(REPLACE "${file_full}" " _file_full_ " file_ov "${file_ov}") - string(TOLOWER "${file_ov}" file_ov) - - #message(STATUS "file_ov='${file_ov}'") - if("${file_ov}" MATCHES "executable") - #message(STATUS "executable!") - if("${file_ov}" MATCHES "text") - #message(STATUS "but text, so *not* a binary executable!") - else() - set(${result_var} 1 PARENT_SCOPE) - return() - endif() - endif() - - # Also detect position independent executables on Linux, - # where "file" gives "shared object ... (uses shared libraries)" - if("${file_ov}" MATCHES "shared object.*\(uses shared libs\)") - set(${result_var} 1 PARENT_SCOPE) - return() - endif() - - else() - message(STATUS "warning: No 'file' command, skipping execute_process...") - endif() - endif() -endfunction() - - -function(gp_item_default_embedded_path item default_embedded_path_var) - - # On Windows and Linux, "embed" prerequisites in the same directory - # as the executable by default: - # - set(path "@executable_path") - set(overridden 0) - - # On the Mac, relative to the executable depending on the type - # of the thing we are embedding: - # - if(APPLE) - # - # The assumption here is that all executables in the bundle will be - # in same-level-directories inside the bundle. The parent directory - # of an executable inside the bundle should be MacOS or a sibling of - # MacOS and all embedded paths returned from here will begin with - # "@executable_path/../" and will work from all executables in all - # such same-level-directories inside the bundle. - # - - # By default, embed things right next to the main bundle executable: - # - set(path "@executable_path/../../Contents/MacOS") - - # Embed .dylibs right next to the main bundle executable: - # - if(item MATCHES "\\.dylib$") - set(path "@executable_path/../MacOS") - set(overridden 1) - endif() - - # Embed frameworks in the embedded "Frameworks" directory (sibling of MacOS): - # - if(NOT overridden) - if(item MATCHES "[^/]+\\.framework/") - set(path "@executable_path/../Frameworks") - set(overridden 1) - endif() - endif() - endif() - - # Provide a hook so that projects can override the default embedded location - # of any given library by whatever logic they choose: - # - if(COMMAND gp_item_default_embedded_path_override) - gp_item_default_embedded_path_override("${item}" path) - endif() - - set(${default_embedded_path_var} "${path}" PARENT_SCOPE) -endfunction() - - -function(gp_resolve_item context item exepath dirs resolved_item_var) - set(resolved 0) - set(resolved_item "${item}") - - # Is it already resolved? - # - if(IS_ABSOLUTE "${resolved_item}" AND EXISTS "${resolved_item}") - set(resolved 1) - endif() - - if(NOT resolved) - if(item MATCHES "@executable_path") - # - # @executable_path references are assumed relative to exepath - # - string(REPLACE "@executable_path" "${exepath}" ri "${item}") - get_filename_component(ri "${ri}" ABSOLUTE) - - if(EXISTS "${ri}") - #message(STATUS "info: embedded item exists (${ri})") - set(resolved 1) - set(resolved_item "${ri}") - else() - message(STATUS "warning: embedded item does not exist '${ri}'") - endif() - endif() - endif() - - if(NOT resolved) - if(item MATCHES "@loader_path") - # - # @loader_path references are assumed relative to the - # PATH of the given "context" (presumably another library) - # - get_filename_component(contextpath "${context}" PATH) - string(REPLACE "@loader_path" "${contextpath}" ri "${item}") - get_filename_component(ri "${ri}" ABSOLUTE) - - if(EXISTS "${ri}") - #message(STATUS "info: embedded item exists (${ri})") - set(resolved 1) - set(resolved_item "${ri}") - else() - message(STATUS "warning: embedded item does not exist '${ri}'") - endif() - endif() - endif() - - if(NOT resolved) - if(item MATCHES "@rpath") - # - # @rpath references are relative to the paths built into the binaries with -rpath - # We handle this case like we do for other Unixes. - # - # Two cases of item resolution are considered: - # - # (1) item has been copied into the bundle - # - # (2) item has NOT been copied into the bundle: Since the item can exist in a build or - # install tree outside of the bundle, the item is resolved using its name and the - # passed list of directories. - # - string(REPLACE "@rpath/" "" norpath_item "${item}") - - set(ri "ri-NOTFOUND") - if(EXISTS ${GP_RPATH_DIR}/${norpath_item}) - set(ri ${GP_RPATH_DIR}/${norpath_item}) - set(_msg "'find_file' in GP_RPATH_DIR (${ri})") - else() - get_filename_component(norpath_item_name ${norpath_item} NAME) - find_file(ri "${norpath_item_name}" ${exepath} ${dirs} NO_DEFAULT_PATH) - set(_msg "'find_file' in exepath/dirs (${ri})") - endif() - if(ri) - #message(STATUS "info: ${_msg}") - set(resolved 1) - set(resolved_item "${ri}") - set(ri "ri-NOTFOUND") - endif() - - endif() - endif() - - if(NOT resolved) - set(ri "ri-NOTFOUND") - find_file(ri "${item}" ${exepath} ${dirs} NO_DEFAULT_PATH) - find_file(ri "${item}" ${exepath} ${dirs} /usr/lib) - if(ri) - #message(STATUS "info: 'find_file' in exepath/dirs (${ri})") - set(resolved 1) - set(resolved_item "${ri}") - set(ri "ri-NOTFOUND") - endif() - endif() - - if(NOT resolved) - if(item MATCHES "[^/]+\\.framework/") - set(fw "fw-NOTFOUND") - find_file(fw "${item}" - "~/Library/Frameworks" - "/Library/Frameworks" - "/System/Library/Frameworks" - ) - if(fw) - #message(STATUS "info: 'find_file' found framework (${fw})") - set(resolved 1) - set(resolved_item "${fw}") - set(fw "fw-NOTFOUND") - endif() - endif() - endif() - - # Using find_program on Windows will find dll files that are in the PATH. - # (Converting simple file names into full path names if found.) - # - if(WIN32 AND NOT UNIX) - if(NOT resolved) - set(ri "ri-NOTFOUND") - find_program(ri "${item}" PATHS "${exepath};${dirs}" NO_DEFAULT_PATH) - find_program(ri "${item}" PATHS "${exepath};${dirs}") - if(ri) - #message(STATUS "info: 'find_program' in exepath/dirs (${ri})") - set(resolved 1) - set(resolved_item "${ri}") - set(ri "ri-NOTFOUND") - endif() - endif() - endif() - - # Provide a hook so that projects can override item resolution - # by whatever logic they choose: - # - if(COMMAND gp_resolve_item_override) - gp_resolve_item_override("${context}" "${item}" "${exepath}" "${dirs}" resolved_item resolved) - endif() - - if(NOT resolved) - message(STATUS " -warning: cannot resolve item '${item}' - - possible problems: - need more directories? - need to use InstallRequiredSystemLibraries? - run in install tree instead of build tree? -") -# message(STATUS " -#****************************************************************************** -#warning: cannot resolve item '${item}' -# -# possible problems: -# need more directories? -# need to use InstallRequiredSystemLibraries? -# run in install tree instead of build tree? -# -# context='${context}' -# item='${item}' -# exepath='${exepath}' -# dirs='${dirs}' -# resolved_item_var='${resolved_item_var}' -#****************************************************************************** -#") - endif() - - set(${resolved_item_var} "${resolved_item}" PARENT_SCOPE) -endfunction() - -function(gp_resolve_embedded_item context embedded_item exepath resolved_embedded_item_var) - #message(STATUS "**") - set(resolved 0) - set(resolved_embedded_item "${embedded_item}") - - if(embedded_item MATCHES "@executable_path") - string(REPLACE "@executable_path" "${exepath}" resolved_embedded_item "${embedded_item}") - set(resolved 1) - endif() - if(EXISTS "${GP_RPATH_DIR}" AND embedded_item MATCHES "@rpath") - string(REPLACE "@rpath" "${GP_RPATH_DIR}" resolved_embedded_item "${embedded_item}") - set(resolved 1) - endif() - - # Provide a hook so that projects can override embedded item resolution - # by whatever logic they choose: - # - if(COMMAND gp_resolve_embedded_item_override) - gp_resolve_embedded_item_override( - "${context}" "${embedded_item}" "${exepath}" resolved_embedded_item resolved) - endif() - - if(NOT resolved) - message(STATUS " -warning: cannot resolve embedded item '${embedded_item}' - possible problems: - need more directories? - need to use InstallRequiredSystemLibraries? - run in install tree instead of build tree? - - context='${context}' - embedded_item='${embedded_item}' - GP_RPATH_DIR='${GP_RPATH_DIR}' - exepath='${exepath}' - resolved_embedded_item_var='${resolved_embedded_item_var}' -") - endif() - - set(${resolved_embedded_item_var} "${resolved_embedded_item}" PARENT_SCOPE) -endfunction() - -function(gp_resolved_file_type original_file file exepath dirs type_var) - #message(STATUS "**") - - if(NOT IS_ABSOLUTE "${original_file}") - message(STATUS "warning: gp_resolved_file_type expects absolute full path for first arg original_file") - endif() - - set(is_embedded 0) - set(is_local 0) - set(is_system 0) - - set(resolved_file "${file}") - - if("${file}" MATCHES "^@(executable_|loader_|r)path") - set(is_embedded 1) - endif() - - if(NOT is_embedded) - if(NOT IS_ABSOLUTE "${file}") - gp_resolve_item("${original_file}" "${file}" "${exepath}" "${dirs}" resolved_file) - endif() - - string(TOLOWER "${original_file}" original_lower) - string(TOLOWER "${resolved_file}" lower) - - if(UNIX) - if(resolved_file MATCHES "^(/lib/|/lib32/|/lib64/|/usr/lib/|/usr/lib32/|/usr/lib64/|/usr/X11/|/usr/X11R6/|/usr/bin/)") - set(is_system 1) - endif() - endif() - - if(APPLE) - if(resolved_file MATCHES "^(/System/Library/|/usr/lib/|/opt/X11/)") - set(is_system 1) - endif() - endif() - - if(WIN32) - string(TOLOWER "$ENV{SystemRoot}" sysroot) - string(REGEX REPLACE "\\\\" "/" sysroot "${sysroot}") - - string(TOLOWER "$ENV{windir}" windir) - string(REGEX REPLACE "\\\\" "/" windir "${windir}") - - if(lower MATCHES "^(${sysroot}/sys(tem|wow)|${windir}/sys(tem|wow)|(.*/)*msvc[^/]+dll)") - set(is_system 1) - endif() - - if(UNIX) - # if cygwin, we can get the properly formed windows paths from cygpath - find_program(CYGPATH_EXECUTABLE cygpath) - - if(CYGPATH_EXECUTABLE) - execute_process(COMMAND ${CYGPATH_EXECUTABLE} -W - OUTPUT_VARIABLE env_windir - OUTPUT_STRIP_TRAILING_WHITESPACE) - execute_process(COMMAND ${CYGPATH_EXECUTABLE} -S - OUTPUT_VARIABLE env_sysdir - OUTPUT_STRIP_TRAILING_WHITESPACE) - string(TOLOWER "${env_windir}" windir) - string(TOLOWER "${env_sysdir}" sysroot) - - if(lower MATCHES "^(${sysroot}/sys(tem|wow)|${windir}/sys(tem|wow)|(.*/)*msvc[^/]+dll)") - set(is_system 1) - endif() - endif() - endif() - endif() - - if(NOT is_system) - get_filename_component(original_path "${original_lower}" PATH) - get_filename_component(path "${lower}" PATH) - if("${original_path}" STREQUAL "${path}") - set(is_local 1) - else() - string(LENGTH "${original_path}/" original_length) - string(LENGTH "${lower}" path_length) - if(${path_length} GREATER ${original_length}) - string(SUBSTRING "${lower}" 0 ${original_length} path) - if("${original_path}/" STREQUAL "${path}") - set(is_embedded 1) - endif() - endif() - endif() - endif() - endif() - - # Return type string based on computed booleans: - # - set(type "other") - - if(is_system) - set(type "system") - elseif(is_embedded) - set(type "embedded") - elseif(is_local) - set(type "local") - endif() - - #message(STATUS "gp_resolved_file_type: '${file}' '${resolved_file}'") - #message(STATUS " type: '${type}'") - - if(NOT is_embedded) - if(NOT IS_ABSOLUTE "${resolved_file}") - if(lower MATCHES "^msvc[^/]+dll" AND is_system) - message(STATUS "info: non-absolute msvc file '${file}' returning type '${type}'") - else() - message(STATUS "warning: gp_resolved_file_type non-absolute file '${file}' returning type '${type}' -- possibly incorrect") - endif() - endif() - endif() - - # Provide a hook so that projects can override the decision on whether a - # library belongs to the system or not by whatever logic they choose: - # - if(COMMAND gp_resolved_file_type_override) - gp_resolved_file_type_override("${resolved_file}" type) - endif() - - set(${type_var} "${type}" PARENT_SCOPE) - - #message(STATUS "**") -endfunction() - - -function(gp_file_type original_file file type_var) - if(NOT IS_ABSOLUTE "${original_file}") - message(STATUS "warning: gp_file_type expects absolute full path for first arg original_file") - endif() - - get_filename_component(exepath "${original_file}" PATH) - - set(type "") - gp_resolved_file_type("${original_file}" "${file}" "${exepath}" "" type) - - set(${type_var} "${type}" PARENT_SCOPE) -endfunction() - - -function(get_prerequisites target prerequisites_var exclude_system recurse exepath dirs) - set(verbose 0) - set(eol_char "E") - - if(NOT IS_ABSOLUTE "${target}") - message("warning: target '${target}' is not absolute...") - endif() - - if(NOT EXISTS "${target}") - message("warning: target '${target}' does not exist...") - endif() - - set(gp_cmd_paths ${gp_cmd_paths} - "C:/Program Files/Microsoft Visual Studio 9.0/VC/bin" - "C:/Program Files (x86)/Microsoft Visual Studio 9.0/VC/bin" - "C:/Program Files/Microsoft Visual Studio 8/VC/BIN" - "C:/Program Files (x86)/Microsoft Visual Studio 8/VC/BIN" - "C:/Program Files/Microsoft Visual Studio .NET 2003/VC7/BIN" - "C:/Program Files (x86)/Microsoft Visual Studio .NET 2003/VC7/BIN" - "/usr/local/bin" - "/usr/bin" - ) - - # - # - # Try to choose the right tool by default. Caller can set gp_tool prior to - # calling this function to force using a different tool. - # - if("${gp_tool}" STREQUAL "") - set(gp_tool "ldd") - - if(APPLE) - set(gp_tool "otool") - endif() - - if(WIN32 AND NOT UNIX) # This is how to check for cygwin, har! - find_program(gp_dumpbin "dumpbin" PATHS ${gp_cmd_paths}) - if(gp_dumpbin) - set(gp_tool "dumpbin") - else() # Try harder. Maybe we're on MinGW - set(gp_tool "objdump") - endif() - endif() - endif() - - find_program(gp_cmd ${gp_tool} PATHS ${gp_cmd_paths}) - - if(NOT gp_cmd) - message(STATUS "warning: could not find '${gp_tool}' - cannot analyze prerequisites...") - return() - endif() - - set(gp_tool_known 0) - - if("${gp_tool}" STREQUAL "ldd") - set(gp_cmd_args "") - set(gp_regex "^[\t ]*[^\t ]+ => ([^\t\(]+) .*${eol_char}$") - set(gp_regex_error "not found${eol_char}$") - set(gp_regex_fallback "^[\t ]*([^\t ]+) => ([^\t ]+).*${eol_char}$") - set(gp_regex_cmp_count 1) - set(gp_tool_known 1) - endif() - - if("${gp_tool}" STREQUAL "otool") - set(gp_cmd_args "-L") - set(gp_regex "^\t([^\t]+) \\(compatibility version ([0-9]+.[0-9]+.[0-9]+), current version ([0-9]+.[0-9]+.[0-9]+)\\)${eol_char}$") - set(gp_regex_error "") - set(gp_regex_fallback "") - set(gp_regex_cmp_count 3) - set(gp_tool_known 1) - endif() - - if("${gp_tool}" STREQUAL "dumpbin") - set(gp_cmd_args "/dependents") - set(gp_regex "^ ([^ ].*[Dd][Ll][Ll])${eol_char}$") - set(gp_regex_error "") - set(gp_regex_fallback "") - set(gp_regex_cmp_count 1) - set(gp_tool_known 1) - set(ENV{VS_UNICODE_OUTPUT} "") # Block extra output from inside VS IDE. - endif() - - if("${gp_tool}" STREQUAL "objdump") - set(gp_cmd_args "-p") - set(gp_regex "^\t*DLL Name: (.*\\.[Dd][Ll][Ll])${eol_char}$") - set(gp_regex_error "") - set(gp_regex_fallback "") - set(gp_regex_cmp_count 1) - set(gp_tool_known 1) - endif() - - if(NOT gp_tool_known) - message(STATUS "warning: gp_tool='${gp_tool}' is an unknown tool...") - message(STATUS "CMake function get_prerequisites needs more code to handle '${gp_tool}'") - message(STATUS "Valid gp_tool values are dumpbin, ldd, objdump and otool.") - return() - endif() - - - if("${gp_tool}" STREQUAL "dumpbin") - # When running dumpbin, it also needs the "Common7/IDE" directory in the - # PATH. It will already be in the PATH if being run from a Visual Studio - # command prompt. Add it to the PATH here in case we are running from a - # different command prompt. - # - get_filename_component(gp_cmd_dir "${gp_cmd}" PATH) - get_filename_component(gp_cmd_dlls_dir "${gp_cmd_dir}/../../Common7/IDE" ABSOLUTE) - # Use cmake paths as a user may have a PATH element ending with a backslash. - # This will escape the list delimiter and create havoc! - if(EXISTS "${gp_cmd_dlls_dir}") - # only add to the path if it is not already in the path - set(gp_found_cmd_dlls_dir 0) - file(TO_CMAKE_PATH "$ENV{PATH}" env_path) - foreach(gp_env_path_element ${env_path}) - if("${gp_env_path_element}" STREQUAL "${gp_cmd_dlls_dir}") - set(gp_found_cmd_dlls_dir 1) - endif() - endforeach() - - if(NOT gp_found_cmd_dlls_dir) - file(TO_NATIVE_PATH "${gp_cmd_dlls_dir}" gp_cmd_dlls_dir) - set(ENV{PATH} "$ENV{PATH};${gp_cmd_dlls_dir}") - endif() - endif() - endif() - # - # - - if("${gp_tool}" STREQUAL "ldd") - set(old_ld_env "$ENV{LD_LIBRARY_PATH}") - foreach(dir ${exepath} ${dirs}) - set(ENV{LD_LIBRARY_PATH} "${dir}:$ENV{LD_LIBRARY_PATH}") - endforeach() - endif() - - - # Track new prerequisites at each new level of recursion. Start with an - # empty list at each level: - # - set(unseen_prereqs) - - # Run gp_cmd on the target: - # - execute_process( - COMMAND ${gp_cmd} ${gp_cmd_args} ${target} - OUTPUT_VARIABLE gp_cmd_ov - ) - - if("${gp_tool}" STREQUAL "ldd") - set(ENV{LD_LIBRARY_PATH} "${old_ld_env}") - endif() - - if(verbose) - message(STATUS "") - message(STATUS "gp_cmd_ov='${gp_cmd_ov}'") - message(STATUS "") - endif() - - get_filename_component(target_dir "${target}" PATH) - - # Convert to a list of lines: - # - string(REGEX REPLACE ";" "\\\\;" candidates "${gp_cmd_ov}") - string(REGEX REPLACE "\n" "${eol_char};" candidates "${candidates}") - - # check for install id and remove it from list, since otool -L can include a - # reference to itself - set(gp_install_id) - if("${gp_tool}" STREQUAL "otool") - execute_process( - COMMAND otool -D ${target} - OUTPUT_VARIABLE gp_install_id_ov - ) - # second line is install name - string(REGEX REPLACE ".*:\n" "" gp_install_id "${gp_install_id_ov}") - if(gp_install_id) - # trim - string(REGEX MATCH "[^\n ].*[^\n ]" gp_install_id "${gp_install_id}") - #message("INSTALL ID is \"${gp_install_id}\"") - endif() - endif() - - # Analyze each line for file names that match the regular expression: - # - foreach(candidate ${candidates}) - if("${candidate}" MATCHES "${gp_regex}") - - # Extract information from each candidate: - if(gp_regex_error AND "${candidate}" MATCHES "${gp_regex_error}") - string(REGEX REPLACE "${gp_regex_fallback}" "\\1" raw_item "${candidate}") - else() - string(REGEX REPLACE "${gp_regex}" "\\1" raw_item "${candidate}") - endif() - - if(gp_regex_cmp_count GREATER 1) - string(REGEX REPLACE "${gp_regex}" "\\2" raw_compat_version "${candidate}") - string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\1" compat_major_version "${raw_compat_version}") - string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\2" compat_minor_version "${raw_compat_version}") - string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\3" compat_patch_version "${raw_compat_version}") - endif() - - if(gp_regex_cmp_count GREATER 2) - string(REGEX REPLACE "${gp_regex}" "\\3" raw_current_version "${candidate}") - string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\1" current_major_version "${raw_current_version}") - string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\2" current_minor_version "${raw_current_version}") - string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\3" current_patch_version "${raw_current_version}") - endif() - - # Use the raw_item as the list entries returned by this function. Use the - # gp_resolve_item function to resolve it to an actual full path file if - # necessary. - # - set(item "${raw_item}") - - # Add each item unless it is excluded: - # - set(add_item 1) - - if("${item}" STREQUAL "${gp_install_id}") - set(add_item 0) - endif() - - if(add_item AND ${exclude_system}) - set(type "") - gp_resolved_file_type("${target}" "${item}" "${exepath}" "${dirs}" type) - - if("${type}" STREQUAL "system") - set(add_item 0) - endif() - endif() - - if(add_item) - list(LENGTH ${prerequisites_var} list_length_before_append) - gp_append_unique(${prerequisites_var} "${item}") - list(LENGTH ${prerequisites_var} list_length_after_append) - - if(${recurse}) - # If item was really added, this is the first time we have seen it. - # Add it to unseen_prereqs so that we can recursively add *its* - # prerequisites... - # - # But first: resolve its name to an absolute full path name such - # that the analysis tools can simply accept it as input. - # - if(NOT list_length_before_append EQUAL list_length_after_append) - gp_resolve_item("${target}" "${item}" "${exepath}" "${dirs}" resolved_item) - set(unseen_prereqs ${unseen_prereqs} "${resolved_item}") - endif() - endif() - endif() - else() - if(verbose) - message(STATUS "ignoring non-matching line: '${candidate}'") - endif() - endif() - endforeach() - - list(LENGTH ${prerequisites_var} prerequisites_var_length) - if(prerequisites_var_length GREATER 0) - list(SORT ${prerequisites_var}) - endif() - if(${recurse}) - set(more_inputs ${unseen_prereqs}) - foreach(input ${more_inputs}) - get_prerequisites("${input}" ${prerequisites_var} ${exclude_system} ${recurse} "${exepath}" "${dirs}") - endforeach() - endif() - - set(${prerequisites_var} ${${prerequisites_var}} PARENT_SCOPE) -endfunction() - - -function(list_prerequisites target) - if("${ARGV1}" STREQUAL "") - set(all 1) - else() - set(all "${ARGV1}") - endif() - - if("${ARGV2}" STREQUAL "") - set(exclude_system 0) - else() - set(exclude_system "${ARGV2}") - endif() - - if("${ARGV3}" STREQUAL "") - set(verbose 0) - else() - set(verbose "${ARGV3}") - endif() - - set(count 0) - set(count_str "") - set(print_count "${verbose}") - set(print_prerequisite_type "${verbose}") - set(print_target "${verbose}") - set(type_str "") - - get_filename_component(exepath "${target}" PATH) - - set(prereqs "") - get_prerequisites("${target}" prereqs ${exclude_system} ${all} "${exepath}" "") - - if(print_target) - message(STATUS "File '${target}' depends on:") - endif() - - foreach(d ${prereqs}) - math(EXPR count "${count} + 1") - - if(print_count) - set(count_str "${count}. ") - endif() - - if(print_prerequisite_type) - gp_file_type("${target}" "${d}" type) - set(type_str " (${type})") - endif() - - message(STATUS "${count_str}${d}${type_str}") - endforeach() -endfunction() - - -function(list_prerequisites_by_glob glob_arg glob_exp) - message(STATUS "=============================================================================") - message(STATUS "List prerequisites of executables matching ${glob_arg} '${glob_exp}'") - message(STATUS "") - file(${glob_arg} file_list ${glob_exp}) - foreach(f ${file_list}) - is_file_executable("${f}" is_f_executable) - if(is_f_executable) - message(STATUS "=============================================================================") - list_prerequisites("${f}" ${ARGN}) - message(STATUS "") - endif() - endforeach() -endfunction() From d5aeb354495b9bfc834ebbc463e5ed0a14ec04f9 Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Fri, 13 Nov 2015 01:19:56 +0100 Subject: [PATCH 2470/3725] OS X: use link path for packaging to allow CMake infer library search dirs for @rpath resolving --- CMakeLists.txt | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e218923bf..5c996e3b4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -297,8 +297,7 @@ if (APPLE) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${APP_BUNDLE_DIR}/Contents/MacOS") if (OPENMW_OSX_DEPLOYMENT) - SET(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) - SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH FALSE) + SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) endif() else (APPLE) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${OpenMW_BINARY_DIR}") @@ -787,8 +786,6 @@ if (APPLE) install_plugins_for_bundle("${INSTALL_SUBDIR}/${APP_BUNDLE_NAME}" PLUGINS) install_plugins_for_bundle("${INSTALL_SUBDIR}/${OPENCS_BUNDLE_NAME}" OPENCS_PLUGINS) - set(DIRS "${CMAKE_PREFIX_PATH}/lib") - install(CODE " function(gp_item_default_embedded_path_override item default_embedded_path_var) if (\${item} MATCHES ${OSG_PLUGIN_PREFIX_DIR}) @@ -798,8 +795,8 @@ if (APPLE) endfunction() cmake_policy(SET CMP0009 OLD) - fixup_bundle(\"${INSTALLED_OPENMW_APP}\" \"${PLUGINS}\" \"${DIRS}\") - fixup_bundle(\"${INSTALLED_OPENCS_APP}\" \"${OPENCS_PLUGINS}\" \"${DIRS}\") + fixup_bundle(\"${INSTALLED_OPENMW_APP}\" \"${PLUGINS}\" \"\") + fixup_bundle(\"${INSTALLED_OPENCS_APP}\" \"${OPENCS_PLUGINS}\" \"\") " COMPONENT Runtime) include(CPack) endif (APPLE) From 63c47a78d6edc8d7519b740271cceaf90ec6e5ab Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Fri, 13 Nov 2015 20:20:34 +0100 Subject: [PATCH 2471/3725] OS X: fixup Qt plugin during packaging --- CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5c996e3b4..0f168be16 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -786,6 +786,9 @@ if (APPLE) install_plugins_for_bundle("${INSTALL_SUBDIR}/${APP_BUNDLE_NAME}" PLUGINS) install_plugins_for_bundle("${INSTALL_SUBDIR}/${OPENCS_BUNDLE_NAME}" OPENCS_PLUGINS) + set(PLUGINS ${PLUGINS} "${INSTALLED_OPENMW_APP}/Contents/MacOS/${QT_COCOA_PLUGIN_GROUP}/${QT_COCOA_PLUGIN_NAME}") + set(OPENCS_PLUGINS ${OPENCS_PLUGINS} "${INSTALLED_OPENCS_APP}/Contents/MacOS/${QT_COCOA_PLUGIN_GROUP}/${QT_COCOA_PLUGIN_NAME}") + install(CODE " function(gp_item_default_embedded_path_override item default_embedded_path_var) if (\${item} MATCHES ${OSG_PLUGIN_PREFIX_DIR}) From d2a417580446deec3c465875ae9f85a2d455be1d Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Sat, 14 Nov 2015 16:02:42 +0100 Subject: [PATCH 2472/3725] Add FFMPEG to include path for OpenMW I'm a bit confused; `mwsound/ffmpeg_decoder.hpp/cpp` requires FFMPEG headers to compile, how did this work in the first place? --- apps/openmw/CMakeLists.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 887eedebb..bf21805d0 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -113,7 +113,10 @@ endif () # Sound stuff - here so CMake doesn't stupidly recompile EVERYTHING # when we change the backend. -include_directories(${SOUND_INPUT_INCLUDES}) +include_directories( + ${SOUND_INPUT_INCLUDES} + ${FFMPEG_INCLUDE_DIRS} +) target_link_libraries(openmw ${OPENSCENEGRAPH_LIBRARIES} From 0220e82259bd799e93eb6ae5f2288ba4c71fcd3e Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 14 Nov 2015 17:17:22 +0100 Subject: [PATCH 2473/3725] Remove unused SOUND_INPUT_INCLUDES cmake variable. --- CMakeLists.txt | 2 -- apps/openmw/CMakeLists.txt | 3 +-- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 58b88f621..08608972b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -115,8 +115,6 @@ endif() # Required for building the FFmpeg headers add_definitions(-D__STDC_CONSTANT_MACROS) -set(SOUND_INPUT_LIBRARY ${FFMPEG_LIBRARIES}) - # TinyXML option(USE_SYSTEM_TINYXML "Use system TinyXML library instead of internal." OFF) if(USE_SYSTEM_TINYXML) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index bf21805d0..59a523023 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -114,7 +114,6 @@ endif () # Sound stuff - here so CMake doesn't stupidly recompile EVERYTHING # when we change the backend. include_directories( - ${SOUND_INPUT_INCLUDES} ${FFMPEG_INCLUDE_DIRS} ) @@ -125,7 +124,7 @@ target_link_libraries(openmw ${Boost_FILESYSTEM_LIBRARY} ${Boost_PROGRAM_OPTIONS_LIBRARY} ${OPENAL_LIBRARY} - ${SOUND_INPUT_LIBRARY} + ${FFMPEG_LIBRARIES} ${BULLET_LIBRARIES} ${MYGUI_LIBRARIES} ${SDL2_LIBRARY} From af4923577b4f97ef4f5c6e89c58bf4badf3228ec Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 15 Nov 2015 16:04:52 +0100 Subject: [PATCH 2474/3725] Fix double writing of Dialogue NAME in OpenCS --- apps/opencs/model/doc/savingstages.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/opencs/model/doc/savingstages.cpp b/apps/opencs/model/doc/savingstages.cpp index 16a91c865..db38c4779 100644 --- a/apps/opencs/model/doc/savingstages.cpp +++ b/apps/opencs/model/doc/savingstages.cpp @@ -131,14 +131,12 @@ void CSMDoc::WriteDialogueCollectionStage::perform (int stage, Messages& message && topic.mState != CSMWorld::RecordBase::State_ModifiedOnly) { mState.getWriter().startRecord (topic.mBase.sRecordId); - mState.getWriter().writeHNCString ("NAME", topic.mBase.mId); topic.mBase.save (mState.getWriter(), topic.mState == CSMWorld::RecordBase::State_Deleted); mState.getWriter().endRecord (topic.mBase.sRecordId); } else { mState.getWriter().startRecord (topic.mModified.sRecordId); - mState.getWriter().writeHNCString ("NAME", topic.mModified.mId); topic.mModified.save (mState.getWriter(), topic.mState == CSMWorld::RecordBase::State_Deleted); mState.getWriter().endRecord (topic.mModified.sRecordId); } From 8b7bdcd127ad696a8e64070ffcc864fdf32ae75d Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 15 Nov 2015 21:32:34 +0100 Subject: [PATCH 2475/3725] Fix the global map overlay viewport (Bug #3018) --- apps/openmw/mwrender/globalmap.cpp | 5 +++-- apps/openmw/mwrender/globalmap.hpp | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/globalmap.cpp b/apps/openmw/mwrender/globalmap.cpp index f91f7674f..b4015b709 100644 --- a/apps/openmw/mwrender/globalmap.cpp +++ b/apps/openmw/mwrender/globalmap.cpp @@ -251,6 +251,7 @@ namespace MWRender camera->setProjectionMatrix(osg::Matrix::identity()); camera->setProjectionResizePolicy(osg::Camera::FIXED); camera->setRenderOrder(osg::Camera::PRE_RENDER); + y = mHeight - y - height; // convert top-left origin to bottom-left camera->setViewport(x, y, width, height); if (clear) @@ -311,12 +312,12 @@ namespace MWRender return; int originX = (cellX - mMinX) * mCellSize; - int originY = (cellY - mMinY) * mCellSize; + int originY = (cellY - mMinY + 1) * mCellSize; // +1 because we want the top left corner of the cell, not the bottom left if (cellX > mMaxX || cellX < mMinX || cellY > mMaxY || cellY < mMinY) return; - requestOverlayTextureUpdate(originX, originY, mCellSize, mCellSize, localMapTexture, false, true); + requestOverlayTextureUpdate(originX, mHeight - originY, mCellSize, mCellSize, localMapTexture, false, true); } void GlobalMap::clear() diff --git a/apps/openmw/mwrender/globalmap.hpp b/apps/openmw/mwrender/globalmap.hpp index 91c17c06f..07ae7cdae 100644 --- a/apps/openmw/mwrender/globalmap.hpp +++ b/apps/openmw/mwrender/globalmap.hpp @@ -70,7 +70,7 @@ namespace MWRender private: /** * Request rendering a 2d quad onto mOverlayTexture. - * x, y, width and height are the destination coordinates. + * x, y, width and height are the destination coordinates (top-left coordinate origin) * @param cpuCopy copy the resulting render onto mOverlayImage as well? */ void requestOverlayTextureUpdate(int x, int y, int width, int height, osg::ref_ptr texture, bool clear, bool cpuCopy, From 0f347eccbf43197dbdd404dbbef061ca854281b3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 15 Nov 2015 21:36:41 +0100 Subject: [PATCH 2476/3725] Flip the origin of global map texture Now it's consistent with the overlay texture. --- apps/openmw/mwgui/mapwindow.cpp | 2 +- apps/openmw/mwrender/globalmap.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 2df1c8f3c..0ebb595dd 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -746,7 +746,7 @@ namespace MWGui mGlobalMapTexture.reset(new osgMyGUI::OSGTexture(mGlobalMapRender->getBaseTexture())); mGlobalMapImage->setRenderItemTexture(mGlobalMapTexture.get()); - mGlobalMapImage->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 0.f, 1.f, 1.f)); + mGlobalMapImage->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 1.f, 1.f, 0.f)); mGlobalMapOverlayTexture.reset(new osgMyGUI::OSGTexture(mGlobalMapRender->getOverlayTexture())); mGlobalMapOverlay->setRenderItemTexture(mGlobalMapOverlayTexture.get()); diff --git a/apps/openmw/mwrender/globalmap.cpp b/apps/openmw/mwrender/globalmap.cpp index b4015b709..9e8a545f8 100644 --- a/apps/openmw/mwrender/globalmap.cpp +++ b/apps/openmw/mwrender/globalmap.cpp @@ -165,7 +165,7 @@ namespace MWRender int vertexY = static_cast(float(cellY) / float(mCellSize) * 9); int texelX = (x-mMinX) * mCellSize + cellX; - int texelY = (mHeight-1) - ((y-mMinY) * mCellSize + cellY); + int texelY = (y-mMinY) * mCellSize + cellY; unsigned char r,g,b; From 71d9e7dc523aadfda49993db619c3060b4504e84 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 12 Nov 2015 16:29:59 +0100 Subject: [PATCH 2477/3725] Read Ambient Loop Sound ID and Rain Loop Sound ID from the INI file --- apps/openmw/mwworld/weather.cpp | 29 +++++++++++++++++++---------- apps/openmw/mwworld/weather.hpp | 2 -- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 24b45fcea..37f5e094d 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -103,7 +103,6 @@ Weather::Weather(const std::string& name, const MWWorld::Fallback& fallback, float stormWindSpeed, float rainSpeed, - const std::string& ambientLoopSoundID, const std::string& particleEffect) : mCloudTexture(fallback.getFallbackString("Weather_" + name + "_Cloud_Texture")) , mSkyColor(fallback.getFallbackColour("Weather_" + name +"_Sky_Sunrise_Color"), @@ -130,7 +129,6 @@ Weather::Weather(const std::string& name, , mWindSpeed(fallback.getFallbackFloat("Weather_" + name + "_Wind_Speed")) , mCloudSpeed(fallback.getFallbackFloat("Weather_" + name + "_Cloud_Speed")) , mGlareView(fallback.getFallbackFloat("Weather_" + name + "_Glare_View")) - , mAmbientLoopSoundID(ambientLoopSoundID) , mIsStorm(mWindSpeed > stormWindSpeed) , mRainSpeed(rainSpeed) , mRainFrequency(fallback.getFallbackFloat("Weather_" + name + "_Rain_Entrance_Speed")) @@ -148,6 +146,18 @@ Weather::Weather(const std::string& name, mThunderSoundID[1] = fallback.getFallbackString("Weather_" + name + "_Thunder_Sound_ID_1"); mThunderSoundID[2] = fallback.getFallbackString("Weather_" + name + "_Thunder_Sound_ID_2"); mThunderSoundID[3] = fallback.getFallbackString("Weather_" + name + "_Thunder_Sound_ID_3"); + + // TODO: support weathers that have both "Ambient Loop Sound ID" and "Rain Loop Sound ID", need to play both sounds at the same time. + + if (!mRainEffect.empty()) // NOTE: in vanilla, the weathers with rain seem to be hardcoded; changing Using_Precip has no effect + { + mAmbientLoopSoundID = fallback.getFallbackString("Weather_" + name + "_Rain_Loop_Sound_ID"); + if (mAmbientLoopSoundID.empty()) // default to "rain" if not set + mAmbientLoopSoundID = "rain"; + } + else + mAmbientLoopSoundID = fallback.getFallbackString("Weather_" + name + "_Ambient_Loop_Sound_ID"); + /* Unhandled: Rain Diameter=600 ? @@ -528,12 +538,12 @@ WeatherManager::WeatherManager(MWRender::RenderingManager& rendering, const MWWo addWeather("Cloudy", fallback); // 1 addWeather("Foggy", fallback); // 2 addWeather("Overcast", fallback); // 3 - addWeather("Rain", fallback, "rain"); // 4 - addWeather("Thunderstorm", fallback, "rain heavy"); // 5 - addWeather("Ashstorm", fallback, "ashstorm", "meshes\\ashcloud.nif"); // 6 - addWeather("Blight", fallback, "blight", "meshes\\blightcloud.nif"); // 7 - addWeather("Snow", fallback, "", "meshes\\snow.nif"); // 8 - addWeather("Blizzard", fallback, "BM Blizzard", "meshes\\blizzard.nif"); // 9 + addWeather("Rain", fallback); // 4 + addWeather("Thunderstorm", fallback); // 5 + addWeather("Ashstorm", fallback, "meshes\\ashcloud.nif"); // 6 + addWeather("Blight", fallback, "meshes\\blightcloud.nif"); // 7 + addWeather("Snow", fallback, "meshes\\snow.nif"); // 8 + addWeather("Blizzard", fallback, "meshes\\blizzard.nif"); // 9 Store::iterator it = store.get().begin(); for(; it != store.get().end(); ++it) @@ -852,12 +862,11 @@ void WeatherManager::clear() inline void WeatherManager::addWeather(const std::string& name, const MWWorld::Fallback& fallback, - const std::string& ambientLoopSoundID, const std::string& particleEffect) { static const float fStromWindSpeed = mStore.get().find("fStromWindSpeed")->getFloat(); - Weather weather(name, fallback, fStromWindSpeed, mRainSpeed, ambientLoopSoundID, particleEffect); + Weather weather(name, fallback, fStromWindSpeed, mRainSpeed, particleEffect); mWeatherSettings.push_back(weather); } diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index 4a78350fe..a5627a507 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -69,7 +69,6 @@ namespace MWWorld const MWWorld::Fallback& fallback, float stormWindSpeed, float rainSpeed, - const std::string& ambientLoopSoundID, const std::string& particleEffect); std::string mCloudTexture; @@ -290,7 +289,6 @@ namespace MWWorld void addWeather(const std::string& name, const MWWorld::Fallback& fallback, - const std::string& ambientLoopSoundID = "", const std::string& particleEffect = ""); void importRegions(); From 52901ec10cd0d15731de93be3e46d49eec8fcd05 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 16 Nov 2015 15:11:20 +0100 Subject: [PATCH 2478/3725] Do not create terrain geodes when built with OSG 3.4 --- components/terrain/terraingrid.cpp | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/components/terrain/terraingrid.cpp b/components/terrain/terraingrid.cpp index 732936aa9..ceb39a24b 100644 --- a/components/terrain/terraingrid.cpp +++ b/components/terrain/terraingrid.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include @@ -126,10 +127,6 @@ osg::ref_ptr TerrainGrid::buildTerrain (osg::Group* parent, float chu osg::BoundingBox bounds(min, max); geometry->setComputeBoundingBoxCallback(new StaticBoundingBoxCallback(bounds)); - osg::ref_ptr geode (new osg::Geode); - geode->addDrawable(geometry); - - std::vector layerList; std::vector > blendmaps; mStorage->getBlendmaps(chunkSize, chunkCenter, false, blendmaps, layerList); @@ -169,11 +166,20 @@ osg::ref_ptr TerrainGrid::buildTerrain (osg::Group* parent, float chu effect->addCullCallback(new SceneUtil::LightListCallback); transform->addChild(effect); - effect->addChild(geode); + +#if OSG_VERSION_GREATER_OR_EQUAL(3,3,3) + osg::Node* toAttach = geometry.get(); +#else + osg::ref_ptr geode (new osg::Geode); + geode->addDrawable(geometry); + osg::Node* toAttach = geode.get(); +#endif + + effect->addChild(toAttach); if (mIncrementalCompileOperation) { - mIncrementalCompileOperation->add(geode); + mIncrementalCompileOperation->add(toAttach); mIncrementalCompileOperation->add(textureCompileDummy); } From 21e25f4756df2bb1ddbf24fc7d8747ae76defe9d Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 16 Nov 2015 20:03:45 +0100 Subject: [PATCH 2479/3725] Use the traversalNumber as frame number --- components/nifosg/nifloader.cpp | 9 ++++----- components/sceneutil/lightmanager.cpp | 4 ++-- components/sceneutil/riggeometry.cpp | 4 ++-- components/sceneutil/skeleton.cpp | 4 ++-- 4 files changed, 10 insertions(+), 11 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 73b72811a..21bf8a096 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -100,14 +100,13 @@ namespace virtual void traverse(osg::NodeVisitor& nv) { - const osg::FrameStamp* stamp = nv.getFrameStamp(); - if (!stamp || nv.getTraversalMode() != osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN) + if (nv.getTraversalMode() != osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN) osg::Group::traverse(nv); else { for (unsigned int i=0; igetFrameNumber()%2) + if (i%2 == nv.getTraversalNumber()%2) getChild(i)->accept(nv); } } @@ -182,9 +181,9 @@ namespace if (!geom) return false; - if (mLastFrameNumber == nv->getFrameStamp()->getFrameNumber()) + if (mLastFrameNumber == nv->getTraversalNumber()) return false; - mLastFrameNumber = nv->getFrameStamp()->getFrameNumber(); + mLastFrameNumber = nv->getTraversalNumber(); geom->transformSoftwareMethod(); return false; diff --git a/components/sceneutil/lightmanager.cpp b/components/sceneutil/lightmanager.cpp index dc6da73a6..d3e11050d 100644 --- a/components/sceneutil/lightmanager.cpp +++ b/components/sceneutil/lightmanager.cpp @@ -294,9 +294,9 @@ namespace SceneUtil // update light list if necessary // makes sure we don't update it more than once per frame when rendering with multiple cameras - if (mLastFrameNumber != nv->getFrameStamp()->getFrameNumber()) + if (mLastFrameNumber != nv->getTraversalNumber()) { - mLastFrameNumber = nv->getFrameStamp()->getFrameNumber(); + mLastFrameNumber = nv->getTraversalNumber(); // Don't use Camera::getViewMatrix, that one might be relative to another camera! const osg::RefMatrix* viewMatrix = cv->getCurrentRenderStage()->getInitialViewMatrix(); diff --git a/components/sceneutil/riggeometry.cpp b/components/sceneutil/riggeometry.cpp index bd3d613a3..023ac12d5 100644 --- a/components/sceneutil/riggeometry.cpp +++ b/components/sceneutil/riggeometry.cpp @@ -218,9 +218,9 @@ void RigGeometry::update(osg::NodeVisitor* nv) if (!mSkeleton->getActive() && mLastFrameNumber != 0) return; - if (mLastFrameNumber == nv->getFrameStamp()->getFrameNumber()) + if (mLastFrameNumber == nv->getTraversalNumber()) return; - mLastFrameNumber = nv->getFrameStamp()->getFrameNumber(); + mLastFrameNumber = nv->getTraversalNumber(); mSkeleton->updateBoneMatrices(nv); diff --git a/components/sceneutil/skeleton.cpp b/components/sceneutil/skeleton.cpp index 5c2af4397..d66131b4e 100644 --- a/components/sceneutil/skeleton.cpp +++ b/components/sceneutil/skeleton.cpp @@ -104,10 +104,10 @@ Bone* Skeleton::getBone(const std::string &name) void Skeleton::updateBoneMatrices(osg::NodeVisitor* nv) { - if (nv->getFrameStamp()->getFrameNumber() != mLastFrameNumber) + if (nv->getTraversalNumber() != mLastFrameNumber) mNeedToUpdateBoneMatrices = true; - mLastFrameNumber = nv->getFrameStamp()->getFrameNumber(); + mLastFrameNumber = nv->getTraversalNumber(); if (mNeedToUpdateBoneMatrices) { From eb2f16d682b692ade3ef97307ab534ab07ea9b52 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 16 Nov 2015 23:26:43 +0100 Subject: [PATCH 2480/3725] Support for loading .osg mesh format --- apps/opencs/model/world/resourcesmanager.cpp | 4 +- apps/openmw/mwphysics/physicssystem.cpp | 7 +- apps/openmw/mwrender/animation.cpp | 2 +- components/nifbullet/bulletshapemanager.cpp | 7 ++ components/resource/scenemanager.cpp | 80 +++++++++++++++++++- components/resource/texturemanager.cpp | 51 +++++++++++++ components/resource/texturemanager.hpp | 4 +- 7 files changed, 145 insertions(+), 10 deletions(-) diff --git a/apps/opencs/model/world/resourcesmanager.cpp b/apps/opencs/model/world/resourcesmanager.cpp index 2ec661cb1..016799be3 100644 --- a/apps/opencs/model/world/resourcesmanager.cpp +++ b/apps/opencs/model/world/resourcesmanager.cpp @@ -19,7 +19,9 @@ void CSMWorld::ResourcesManager::setVFS(const VFS::Manager *vfs) mVFS = vfs; mResources.clear(); - static const char * const sMeshTypes[] = { "nif", 0 }; + // maybe we could go over the osgDB::Registry to list all supported node formats + + static const char * const sMeshTypes[] = { "nif", "osg", "osgt", "osgb", "osgx", "osg2", 0 }; addResources (Resources (vfs, "meshes", UniversalId::Type_Mesh, sMeshTypes)); addResources (Resources (vfs, "icons", UniversalId::Type_Icon)); diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 55144afe7..f5e9ce2fa 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -975,7 +975,7 @@ namespace MWPhysics void PhysicsSystem::addObject (const MWWorld::Ptr& ptr, const std::string& mesh) { osg::ref_ptr shapeInstance = mShapeManager->createInstance(mesh); - if (!shapeInstance->getCollisionShape()) + if (!shapeInstance || !shapeInstance->getCollisionShape()) return; Object *obj = new Object(ptr, shapeInstance); @@ -1114,9 +1114,10 @@ namespace MWPhysics } } - void PhysicsSystem::addActor (const MWWorld::Ptr& ptr, const std::string& mesh) - { + void PhysicsSystem::addActor (const MWWorld::Ptr& ptr, const std::string& mesh) { osg::ref_ptr shapeInstance = mShapeManager->createInstance(mesh); + if (!shapeInstance) + return; Actor* actor = new Actor(ptr, shapeInstance, mCollisionWorld); mActors.insert(std::make_pair(ptr, actor)); diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 55a47d4b6..6ef6fab23 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -402,7 +402,7 @@ namespace MWRender animsrc.reset(new AnimSource); animsrc->mKeyframes = mResourceSystem->getSceneManager()->getKeyframes(kfname); - if (animsrc->mKeyframes->mTextKeys.empty() || animsrc->mKeyframes->mKeyframeControllers.empty()) + if (!animsrc->mKeyframes || animsrc->mKeyframes->mTextKeys.empty() || animsrc->mKeyframes->mKeyframeControllers.empty()) return; for (NifOsg::KeyframeHolder::KeyframeControllerMap::const_iterator it = animsrc->mKeyframes->mKeyframeControllers.begin(); diff --git a/components/nifbullet/bulletshapemanager.cpp b/components/nifbullet/bulletshapemanager.cpp index 6acfdd408..23b461953 100644 --- a/components/nifbullet/bulletshapemanager.cpp +++ b/components/nifbullet/bulletshapemanager.cpp @@ -30,6 +30,13 @@ osg::ref_ptr BulletShapeManager::createInstance(const std:: Files::IStreamPtr file = mVFS->get(normalized); // TODO: add support for non-NIF formats + size_t extPos = normalized.find_last_of('.'); + std::string ext; + if (extPos != std::string::npos && extPos+1 < normalized.size()) + ext = normalized.substr(extPos+1); + + if (ext != "nif") + return NULL; BulletNifLoader loader; // might be worth sharing NIFFiles with SceneManager in some way diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index eb4a4992d..3717ecb16 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -20,6 +20,8 @@ #include #include +#include "texturemanager.hpp" + namespace { @@ -112,6 +114,73 @@ namespace Resource SceneManager::~SceneManager() { // this has to be defined in the .cpp file as we can't delete incomplete types + + } + + /// @brief Callback to read image files from the VFS. + class ImageReadCallback : public osgDB::ReadFileCallback + { + public: + ImageReadCallback(Resource::TextureManager* textureMgr) + : mTextureManager(textureMgr) + { + } + + virtual osgDB::ReaderWriter::ReadResult readImage(const std::string& filename, const osgDB::Options* options) + { + try + { + mTextureManager->getTexture2D(filename, osg::Texture::CLAMP_TO_EDGE, osg::Texture::CLAMP_TO_EDGE); + return osgDB::ReaderWriter::ReadResult(mTextureManager->getImage(filename), osgDB::ReaderWriter::ReadResult::FILE_LOADED); + } + catch (std::exception& e) + { + return osgDB::ReaderWriter::ReadResult(e.what()); + } + } + + private: + Resource::TextureManager* mTextureManager; + }; + + std::string getFileExtension(const std::string& file) + { + size_t extPos = file.find_last_of('.'); + if (extPos != std::string::npos && extPos+1 < file.size()) + return file.substr(extPos+1); + return std::string(); + } + + osg::ref_ptr load (Files::IStreamPtr file, const std::string& normalizedFilename, Resource::TextureManager* textureMgr) + { + std::string ext = getFileExtension(normalizedFilename); + if (ext == "nif") + return NifOsg::Loader::load(Nif::NIFFilePtr(new Nif::NIFFile(file, normalizedFilename)), textureMgr); + else + { + osgDB::ReaderWriter* reader = osgDB::Registry::instance()->getReaderWriterForExtension(ext); + if (!reader) + { + std::stringstream errormsg; + errormsg << "Error loading " << normalizedFilename << ": no readerwriter for '" << ext << "' found" << std::endl; + throw std::runtime_error(errormsg.str()); + } + + osg::ref_ptr options (new osgDB::Options); + // Set a ReadFileCallback so that image files referenced in the model are read from our virtual file system instead of the osgDB. + // Note, for some formats (.obj/.mtl) that reference other (non-image) files a findFileCallback would be necessary. + // but findFileCallback does not support virtual files, so we can't implement it. + options->setReadFileCallback(new ImageReadCallback(textureMgr)); + + osgDB::ReaderWriter::ReadResult result = reader->readNode(*file, options); + if (!result.success()) + { + std::stringstream errormsg; + errormsg << "Error loading " << normalizedFilename << ": " << result.message() << " code " << result.status() << std::endl; + throw std::runtime_error(errormsg.str()); + } + return result.getNode(); + } } osg::ref_ptr SceneManager::getTemplate(const std::string &name) @@ -122,19 +191,19 @@ namespace Resource Index::iterator it = mIndex.find(normalized); if (it == mIndex.end()) { - // TODO: add support for non-NIF formats osg::ref_ptr loaded; try { Files::IStreamPtr file = mVFS->get(normalized); - loaded = NifOsg::Loader::load(Nif::NIFFilePtr(new Nif::NIFFile(file, normalized)), mTextureManager); + loaded = load(file, normalized, mTextureManager); } catch (std::exception& e) { std::cerr << "Failed to load '" << name << "': " << e.what() << ", using marker_error.nif instead" << std::endl; Files::IStreamPtr file = mVFS->get("meshes/marker_error.nif"); - loaded = NifOsg::Loader::load(Nif::NIFFilePtr(new Nif::NIFFile(file, normalized)), mTextureManager); + normalized = "meshes/marker_error.nif"; + loaded = load(file, normalized, mTextureManager); } osgDB::Registry::instance()->getOrCreateSharedStateManager()->share(loaded.get()); @@ -174,6 +243,11 @@ namespace Resource { Files::IStreamPtr file = mVFS->get(normalized); + std::string ext = getFileExtension(normalized); + + if (ext != "nif" && ext != "kf") + return NULL; + osg::ref_ptr loaded (new NifOsg::KeyframeHolder); NifOsg::Loader::loadKf(Nif::NIFFilePtr(new Nif::NIFFile(file, normalized)), *loaded.get()); diff --git a/components/resource/texturemanager.cpp b/components/resource/texturemanager.cpp index 8b80efcdc..15ac37514 100644 --- a/components/resource/texturemanager.cpp +++ b/components/resource/texturemanager.cpp @@ -143,6 +143,57 @@ namespace Resource return true; } + osg::ref_ptr TextureManager::getImage(const std::string &filename) + { + std::string normalized = filename; + mVFS->normalizeFilename(normalized); + std::map >::iterator found = mImages.find(normalized); + if (found != mImages.end()) + return found->second; + else + { + Files::IStreamPtr stream; + try + { + stream = mVFS->get(normalized.c_str()); + } + catch (std::exception& e) + { + std::cerr << "Failed to open image: " << e.what() << std::endl; + return NULL; + } + + osg::ref_ptr opts (new osgDB::Options); + opts->setOptionString("dds_dxt1_detect_rgba"); // tx_creature_werewolf.dds isn't loading in the correct format without this option + size_t extPos = normalized.find_last_of('.'); + std::string ext; + if (extPos != std::string::npos && extPos+1 < normalized.size()) + ext = normalized.substr(extPos+1); + osgDB::ReaderWriter* reader = osgDB::Registry::instance()->getReaderWriterForExtension(ext); + if (!reader) + { + std::cerr << "Error loading " << filename << ": no readerwriter for '" << ext << "' found" << std::endl; + return NULL; + } + + osgDB::ReaderWriter::ReadResult result = reader->readImage(*stream, opts); + if (!result.success()) + { + std::cerr << "Error loading " << filename << ": " << result.message() << " code " << result.status() << std::endl; + return NULL; + } + + osg::Image* image = result.getImage(); + if (!checkSupported(image, filename)) + { + return NULL; + } + + mImages.insert(std::make_pair(normalized, image)); + return image; + } + } + osg::ref_ptr TextureManager::getTexture2D(const std::string &filename, osg::Texture::WrapMode wrapS, osg::Texture::WrapMode wrapT) { std::string normalized = filename; diff --git a/components/resource/texturemanager.hpp b/components/resource/texturemanager.hpp index 2ee3baa77..1a7d41a7b 100644 --- a/components/resource/texturemanager.hpp +++ b/components/resource/texturemanager.hpp @@ -34,7 +34,7 @@ namespace Resource osg::ref_ptr getTexture2D(const std::string& filename, osg::Texture::WrapMode wrapS, osg::Texture::WrapMode wrapT); /// Create or retrieve an Image - //osg::ref_ptr getImage(const std::string& filename); + osg::ref_ptr getImage(const std::string& filename); const VFS::Manager* getVFS() { return mVFS; } @@ -49,7 +49,7 @@ namespace Resource typedef std::pair, std::string> MapKey; - std::map > mImages; + std::map > mImages; std::map > mTextures; From 8cf57ef6ac1eaf4a0ba51c230f3ad4d222ba4fc0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 16 Nov 2015 23:30:10 +0100 Subject: [PATCH 2481/3725] Move BulletShapeManager and BulletShape to resource/ --- apps/openmw/mwphysics/actor.cpp | 4 +- apps/openmw/mwphysics/actor.hpp | 4 +- apps/openmw/mwphysics/physicssystem.cpp | 12 +- apps/openmw/mwphysics/physicssystem.hpp | 4 +- components/CMakeLists.txt | 4 +- components/nifbullet/bulletnifloader.cpp | 114 +----------------- components/nifbullet/bulletnifloader.hpp | 47 +------- components/resource/bulletshape.cpp | 102 ++++++++++++++++ components/resource/bulletshape.hpp | 78 ++++++++++++ .../bulletshapemanager.cpp | 6 +- .../bulletshapemanager.hpp | 6 +- 11 files changed, 208 insertions(+), 173 deletions(-) create mode 100644 components/resource/bulletshape.cpp create mode 100644 components/resource/bulletshape.hpp rename components/{nifbullet => resource}/bulletshapemanager.cpp (93%) rename components/{nifbullet => resource}/bulletshapemanager.hpp (96%) diff --git a/apps/openmw/mwphysics/actor.cpp b/apps/openmw/mwphysics/actor.cpp index 98ccefe71..8cd0dfeb9 100644 --- a/apps/openmw/mwphysics/actor.cpp +++ b/apps/openmw/mwphysics/actor.cpp @@ -6,7 +6,7 @@ #include #include -#include +#include #include "../mwworld/class.hpp" @@ -17,7 +17,7 @@ namespace MWPhysics { -Actor::Actor(const MWWorld::Ptr& ptr, osg::ref_ptr shape, btCollisionWorld* world) +Actor::Actor(const MWWorld::Ptr& ptr, osg::ref_ptr shape, btCollisionWorld* world) : mCanWaterWalk(false), mWalkingOnWater(false) , mCollisionObject(0), mForce(0.f, 0.f, 0.f), mOnGround(false) , mInternalCollisionMode(true) diff --git a/apps/openmw/mwphysics/actor.hpp b/apps/openmw/mwphysics/actor.hpp index bcbc256d0..3ea64840e 100644 --- a/apps/openmw/mwphysics/actor.hpp +++ b/apps/openmw/mwphysics/actor.hpp @@ -13,7 +13,7 @@ class btCollisionWorld; class btCollisionShape; class btCollisionObject; -namespace NifBullet +namespace Resource { class BulletShapeInstance; } @@ -43,7 +43,7 @@ namespace MWPhysics class Actor : public PtrHolder { public: - Actor(const MWWorld::Ptr& ptr, osg::ref_ptr shape, btCollisionWorld* world); + Actor(const MWWorld::Ptr& ptr, osg::ref_ptr shape, btCollisionWorld* world); ~Actor(); /** diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index f5e9ce2fa..6960d2801 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -17,9 +17,9 @@ #include #include -#include #include #include +#include #include @@ -520,7 +520,7 @@ namespace MWPhysics class Object : public PtrHolder { public: - Object(const MWWorld::Ptr& ptr, osg::ref_ptr shapeInstance) + Object(const MWWorld::Ptr& ptr, osg::ref_ptr shapeInstance) : mShapeInstance(shapeInstance) { mPtr = ptr; @@ -599,13 +599,13 @@ namespace MWPhysics private: std::auto_ptr mCollisionObject; - osg::ref_ptr mShapeInstance; + osg::ref_ptr mShapeInstance; }; // --------------------------------------------------------------- PhysicsSystem::PhysicsSystem(Resource::ResourceSystem* resourceSystem, osg::ref_ptr parentNode) - : mShapeManager(new NifBullet::BulletShapeManager(resourceSystem->getVFS())) + : mShapeManager(new Resource::BulletShapeManager(resourceSystem->getVFS())) , mDebugDrawEnabled(false) , mTimeAccum(0.0f) , mWaterHeight(0) @@ -974,7 +974,7 @@ namespace MWPhysics void PhysicsSystem::addObject (const MWWorld::Ptr& ptr, const std::string& mesh) { - osg::ref_ptr shapeInstance = mShapeManager->createInstance(mesh); + osg::ref_ptr shapeInstance = mShapeManager->createInstance(mesh); if (!shapeInstance || !shapeInstance->getCollisionShape()) return; @@ -1115,7 +1115,7 @@ namespace MWPhysics } void PhysicsSystem::addActor (const MWWorld::Ptr& ptr, const std::string& mesh) { - osg::ref_ptr shapeInstance = mShapeManager->createInstance(mesh); + osg::ref_ptr shapeInstance = mShapeManager->createInstance(mesh); if (!shapeInstance) return; diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index 7c5be0b6e..283c85725 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -21,7 +21,7 @@ namespace MWRender class DebugDrawer; } -namespace NifBullet +namespace Resource { class BulletShapeManager; } @@ -154,7 +154,7 @@ namespace MWPhysics btCollisionDispatcher* mDispatcher; btCollisionWorld* mCollisionWorld; - std::auto_ptr mShapeManager; + std::auto_ptr mShapeManager; typedef std::map ObjectMap; ObjectMap mObjects; diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index f8f4c64ab..b7865cb8a 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -37,7 +37,7 @@ add_component_dir (vfs ) add_component_dir (resource - scenemanager texturemanager resourcesystem + scenemanager texturemanager resourcesystem bulletshapemanager bulletshape ) add_component_dir (sceneutil @@ -55,7 +55,7 @@ add_component_dir (nifosg ) add_component_dir (nifbullet - bulletnifloader bulletshapemanager + bulletnifloader ) add_component_dir (to_utf8 diff --git a/components/nifbullet/bulletnifloader.cpp b/components/nifbullet/bulletnifloader.cpp index 2496c68cd..5de6d51ca 100644 --- a/components/nifbullet/bulletnifloader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -40,21 +40,6 @@ btVector3 getbtVector(const osg::Vec3f &v) namespace NifBullet { -// Subclass btBhvTriangleMeshShape to auto-delete the meshInterface -struct TriangleMeshShape : public btBvhTriangleMeshShape -{ - TriangleMeshShape(btStridingMeshInterface* meshInterface, bool useQuantizedAabbCompression) - : btBvhTriangleMeshShape(meshInterface, useQuantizedAabbCompression) - { - } - - virtual ~TriangleMeshShape() - { - delete getTriangleInfoMap(); - delete m_meshInterface; - } -}; - BulletNifLoader::BulletNifLoader() : mCompoundShape(NULL) , mStaticMesh(NULL) @@ -65,9 +50,9 @@ BulletNifLoader::~BulletNifLoader() { } -osg::ref_ptr BulletNifLoader::load(const Nif::NIFFilePtr nif) +osg::ref_ptr BulletNifLoader::load(const Nif::NIFFilePtr nif) { - mShape = new BulletShape; + mShape = new Resource::BulletShape; mCompoundShape = NULL; mStaticMesh = NULL; @@ -126,11 +111,11 @@ osg::ref_ptr BulletNifLoader::load(const Nif::NIFFilePtr nif) { btTransform trans; trans.setIdentity(); - mCompoundShape->addChildShape(trans, new TriangleMeshShape(mStaticMesh,true)); + mCompoundShape->addChildShape(trans, new Resource::TriangleMeshShape(mStaticMesh,true)); } } else if (mStaticMesh) - mShape->mCollisionShape = new TriangleMeshShape(mStaticMesh,true); + mShape->mCollisionShape = new Resource::TriangleMeshShape(mStaticMesh,true); return mShape; } @@ -306,7 +291,7 @@ void BulletNifLoader::handleNiTriShape(const Nif::NiTriShape *shape, int flags, childMesh->addTriangle(getbtVector(b1), getbtVector(b2), getbtVector(b3)); } - TriangleMeshShape* childShape = new TriangleMeshShape(childMesh,true); + Resource::TriangleMeshShape* childShape = new Resource::TriangleMeshShape(childMesh,true); float scale = shape->trafo.scale; const Nif::Node* parent = shape; @@ -346,93 +331,4 @@ void BulletNifLoader::handleNiTriShape(const Nif::NiTriShape *shape, int flags, } } -BulletShape::BulletShape() - : mCollisionShape(NULL) -{ - -} - -BulletShape::~BulletShape() -{ - deleteShape(mCollisionShape); -} - -void BulletShape::deleteShape(btCollisionShape* shape) -{ - if(shape!=NULL) - { - if(shape->isCompound()) - { - btCompoundShape* ms = static_cast(shape); - int a = ms->getNumChildShapes(); - for(int i=0; i getChildShape(i)); - } - delete shape; - } -} - -btCollisionShape* BulletShape::duplicateCollisionShape(btCollisionShape *shape) const -{ - if(shape->isCompound()) - { - btCompoundShape *comp = static_cast(shape); - btCompoundShape *newShape = new btCompoundShape; - - int numShapes = comp->getNumChildShapes(); - for(int i = 0;i < numShapes;++i) - { - btCollisionShape *child = duplicateCollisionShape(comp->getChildShape(i)); - btTransform trans = comp->getChildTransform(i); - newShape->addChildShape(trans, child); - } - - return newShape; - } - - if(btBvhTriangleMeshShape* trishape = dynamic_cast(shape)) - { -#if BT_BULLET_VERSION >= 283 - btScaledBvhTriangleMeshShape* newShape = new btScaledBvhTriangleMeshShape(trishape, btVector3(1.f, 1.f, 1.f)); -#else - // work around btScaledBvhTriangleMeshShape bug ( https://code.google.com/p/bullet/issues/detail?id=371 ) in older bullet versions - btTriangleMesh* oldMesh = static_cast(trishape->getMeshInterface()); - btTriangleMesh* newMesh = new btTriangleMesh(*oldMesh); - NifBullet::TriangleMeshShape* newShape = new NifBullet::TriangleMeshShape(newMesh, true); -#endif - return newShape; - } - - if (btBoxShape* boxshape = dynamic_cast(shape)) - { - return new btBoxShape(*boxshape); - } - - throw std::logic_error(std::string("Unhandled Bullet shape duplication: ")+shape->getName()); -} - -btCollisionShape *BulletShape::getCollisionShape() -{ - return mCollisionShape; -} - -osg::ref_ptr BulletShape::makeInstance() -{ - osg::ref_ptr instance (new BulletShapeInstance(this)); - return instance; -} - -BulletShapeInstance::BulletShapeInstance(osg::ref_ptr source) - : BulletShape() - , mSource(source) -{ - mCollisionBoxHalfExtents = source->mCollisionBoxHalfExtents; - mCollisionBoxTranslate = source->mCollisionBoxTranslate; - - mAnimatedShapes = source->mAnimatedShapes; - - if (source->mCollisionShape) - mCollisionShape = duplicateCollisionShape(source->mCollisionShape); -} - } // namespace NifBullet diff --git a/components/nifbullet/bulletnifloader.hpp b/components/nifbullet/bulletnifloader.hpp index 52428cc74..a30bf8fdf 100644 --- a/components/nifbullet/bulletnifloader.hpp +++ b/components/nifbullet/bulletnifloader.hpp @@ -13,6 +13,7 @@ #include #include +#include class btTriangleMesh; class btCompoundShape; @@ -28,48 +29,6 @@ namespace Nif namespace NifBullet { -class BulletShapeInstance; -class BulletShape : public osg::Referenced -{ -public: - BulletShape(); - virtual ~BulletShape(); - - btCollisionShape* mCollisionShape; - - // Used for actors. Note, ideally actors would use a separate loader - as it is - // we have to keep a redundant copy of the actor model around in mCollisionShape, which isn't used. - // For now, use one file <-> one resource for simplicity. - osg::Vec3f mCollisionBoxHalfExtents; - osg::Vec3f mCollisionBoxTranslate; - - // Stores animated collision shapes. If any collision nodes in the NIF are animated, then mCollisionShape - // will be a btCompoundShape (which consists of one or more child shapes). - // In this map, for each animated collision shape, - // we store the node's record index mapped to the child index of the shape in the btCompoundShape. - std::map mAnimatedShapes; - - osg::ref_ptr makeInstance(); - - btCollisionShape* duplicateCollisionShape(btCollisionShape* shape) const; - - btCollisionShape* getCollisionShape(); - -private: - void deleteShape(btCollisionShape* shape); -}; - -// An instance of a BulletShape that may have its own unique scaling set on the mCollisionShape. -// Vertex data is shallow-copied where possible. A ref_ptr to the original shape needs to be held to keep vertex pointers intact. -class BulletShapeInstance : public BulletShape -{ -public: - BulletShapeInstance(osg::ref_ptr source); - -private: - osg::ref_ptr mSource; -}; - /** *Load bulletShape from NIF files. */ @@ -91,7 +50,7 @@ public: abort(); } - osg::ref_ptr load(const Nif::NIFFilePtr file); + osg::ref_ptr load(const Nif::NIFFilePtr file); private: bool findBoundingBox(const Nif::Node* node, int flags = 0); @@ -106,7 +65,7 @@ private: btTriangleMesh* mStaticMesh; - osg::ref_ptr mShape; + osg::ref_ptr mShape; }; } diff --git a/components/resource/bulletshape.cpp b/components/resource/bulletshape.cpp new file mode 100644 index 000000000..00bcb9e04 --- /dev/null +++ b/components/resource/bulletshape.cpp @@ -0,0 +1,102 @@ +#include "bulletshape.hpp" + +#include + +#include +#include +#include +#include + +namespace Resource +{ + +BulletShape::BulletShape() + : mCollisionShape(NULL) +{ + +} + +BulletShape::~BulletShape() +{ + deleteShape(mCollisionShape); +} + +void BulletShape::deleteShape(btCollisionShape* shape) +{ + if(shape!=NULL) + { + if(shape->isCompound()) + { + btCompoundShape* ms = static_cast(shape); + int a = ms->getNumChildShapes(); + for(int i=0; i getChildShape(i)); + } + delete shape; + } +} + +btCollisionShape* BulletShape::duplicateCollisionShape(btCollisionShape *shape) const +{ + if(shape->isCompound()) + { + btCompoundShape *comp = static_cast(shape); + btCompoundShape *newShape = new btCompoundShape; + + int numShapes = comp->getNumChildShapes(); + for(int i = 0;i < numShapes;++i) + { + btCollisionShape *child = duplicateCollisionShape(comp->getChildShape(i)); + btTransform trans = comp->getChildTransform(i); + newShape->addChildShape(trans, child); + } + + return newShape; + } + + if(btBvhTriangleMeshShape* trishape = dynamic_cast(shape)) + { +#if BT_BULLET_VERSION >= 283 + btScaledBvhTriangleMeshShape* newShape = new btScaledBvhTriangleMeshShape(trishape, btVector3(1.f, 1.f, 1.f)); +#else + // work around btScaledBvhTriangleMeshShape bug ( https://code.google.com/p/bullet/issues/detail?id=371 ) in older bullet versions + btTriangleMesh* oldMesh = static_cast(trishape->getMeshInterface()); + btTriangleMesh* newMesh = new btTriangleMesh(*oldMesh); + TriangleMeshShape* newShape = new TriangleMeshShape(newMesh, true); +#endif + return newShape; + } + + if (btBoxShape* boxshape = dynamic_cast(shape)) + { + return new btBoxShape(*boxshape); + } + + throw std::logic_error(std::string("Unhandled Bullet shape duplication: ")+shape->getName()); +} + +btCollisionShape *BulletShape::getCollisionShape() +{ + return mCollisionShape; +} + +osg::ref_ptr BulletShape::makeInstance() +{ + osg::ref_ptr instance (new BulletShapeInstance(this)); + return instance; +} + +BulletShapeInstance::BulletShapeInstance(osg::ref_ptr source) + : BulletShape() + , mSource(source) +{ + mCollisionBoxHalfExtents = source->mCollisionBoxHalfExtents; + mCollisionBoxTranslate = source->mCollisionBoxTranslate; + + mAnimatedShapes = source->mAnimatedShapes; + + if (source->mCollisionShape) + mCollisionShape = duplicateCollisionShape(source->mCollisionShape); +} + +} diff --git a/components/resource/bulletshape.hpp b/components/resource/bulletshape.hpp new file mode 100644 index 000000000..78e509db7 --- /dev/null +++ b/components/resource/bulletshape.hpp @@ -0,0 +1,78 @@ +#ifndef OPENMW_COMPONENTS_RESOURCE_BULLETSHAPE_H +#define OPENMW_COMPONENTS_RESOURCE_BULLETSHAPE_H + +#include + +#include +#include +#include + +#include + +class btCollisionShape; + +namespace Resource +{ + + class BulletShapeInstance; + class BulletShape : public osg::Referenced + { + public: + BulletShape(); + virtual ~BulletShape(); + + btCollisionShape* mCollisionShape; + + // Used for actors. Note, ideally actors would use a separate loader - as it is + // we have to keep a redundant copy of the actor model around in mCollisionShape, which isn't used. + // For now, use one file <-> one resource for simplicity. + osg::Vec3f mCollisionBoxHalfExtents; + osg::Vec3f mCollisionBoxTranslate; + + // Stores animated collision shapes. If any collision nodes in the NIF are animated, then mCollisionShape + // will be a btCompoundShape (which consists of one or more child shapes). + // In this map, for each animated collision shape, + // we store the node's record index mapped to the child index of the shape in the btCompoundShape. + std::map mAnimatedShapes; + + osg::ref_ptr makeInstance(); + + btCollisionShape* duplicateCollisionShape(btCollisionShape* shape) const; + + btCollisionShape* getCollisionShape(); + + private: + void deleteShape(btCollisionShape* shape); + }; + + + // An instance of a BulletShape that may have its own unique scaling set on the mCollisionShape. + // Vertex data is shallow-copied where possible. A ref_ptr to the original shape is held to keep vertex pointers intact. + class BulletShapeInstance : public BulletShape + { + public: + BulletShapeInstance(osg::ref_ptr source); + + private: + osg::ref_ptr mSource; + }; + + // Subclass btBhvTriangleMeshShape to auto-delete the meshInterface + struct TriangleMeshShape : public btBvhTriangleMeshShape + { + TriangleMeshShape(btStridingMeshInterface* meshInterface, bool useQuantizedAabbCompression) + : btBvhTriangleMeshShape(meshInterface, useQuantizedAabbCompression) + { + } + + virtual ~TriangleMeshShape() + { + delete getTriangleInfoMap(); + delete m_meshInterface; + } + }; + + +} + +#endif diff --git a/components/nifbullet/bulletshapemanager.cpp b/components/resource/bulletshapemanager.cpp similarity index 93% rename from components/nifbullet/bulletshapemanager.cpp rename to components/resource/bulletshapemanager.cpp index 23b461953..3254a5c97 100644 --- a/components/nifbullet/bulletshapemanager.cpp +++ b/components/resource/bulletshapemanager.cpp @@ -4,7 +4,9 @@ #include -namespace NifBullet +#include "bulletshape.hpp" + +namespace Resource { BulletShapeManager::BulletShapeManager(const VFS::Manager* vfs) @@ -38,7 +40,7 @@ osg::ref_ptr BulletShapeManager::createInstance(const std:: if (ext != "nif") return NULL; - BulletNifLoader loader; + NifBullet::BulletNifLoader loader; // might be worth sharing NIFFiles with SceneManager in some way shape = loader.load(Nif::NIFFilePtr(new Nif::NIFFile(file, normalized))); diff --git a/components/nifbullet/bulletshapemanager.hpp b/components/resource/bulletshapemanager.hpp similarity index 96% rename from components/nifbullet/bulletshapemanager.hpp rename to components/resource/bulletshapemanager.hpp index 6b9ec60de..3e1f05ce5 100644 --- a/components/nifbullet/bulletshapemanager.hpp +++ b/components/resource/bulletshapemanager.hpp @@ -6,6 +6,8 @@ #include +#include "bulletshape.hpp" + namespace VFS { class Manager; @@ -14,10 +16,6 @@ namespace VFS namespace Resource { class SceneManager; -} - -namespace NifBullet -{ class BulletShape; class BulletShapeInstance; From e62470d67411c665231162959c764c27f4f19e2e Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 17 Nov 2015 00:18:27 +0100 Subject: [PATCH 2482/3725] Auto-generate the collision shape for native mesh formats --- apps/openmw/mwphysics/physicssystem.cpp | 2 +- components/resource/bulletshapemanager.cpp | 107 +++++++++++++++++++-- components/resource/bulletshapemanager.hpp | 3 +- 3 files changed, 103 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 6960d2801..1898a3de1 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -605,7 +605,7 @@ namespace MWPhysics // --------------------------------------------------------------- PhysicsSystem::PhysicsSystem(Resource::ResourceSystem* resourceSystem, osg::ref_ptr parentNode) - : mShapeManager(new Resource::BulletShapeManager(resourceSystem->getVFS())) + : mShapeManager(new Resource::BulletShapeManager(resourceSystem->getVFS(), resourceSystem->getSceneManager())) , mDebugDrawEnabled(false) , mTimeAccum(0.0f) , mWaterHeight(0) diff --git a/components/resource/bulletshapemanager.cpp b/components/resource/bulletshapemanager.cpp index 3254a5c97..d573b455d 100644 --- a/components/resource/bulletshapemanager.cpp +++ b/components/resource/bulletshapemanager.cpp @@ -1,16 +1,99 @@ #include "bulletshapemanager.hpp" +#include +#include +#include + +#include + #include #include #include "bulletshape.hpp" +#include "scenemanager.hpp" + namespace Resource { -BulletShapeManager::BulletShapeManager(const VFS::Manager* vfs) +struct GetTriangleFunctor +{ + GetTriangleFunctor() + : mTriMesh(NULL) + { + } + + void setTriMesh(btTriangleMesh* triMesh) + { + mTriMesh = triMesh; + } + + void setMatrix(const osg::Matrixf& matrix) + { + mMatrix = matrix; + } + + inline btVector3 toBullet(const osg::Vec3f& vec) + { + return btVector3(vec.x(), vec.y(), vec.z()); + } + + void inline operator()( const osg::Vec3 v1, const osg::Vec3 v2, const osg::Vec3 v3, bool _temp ) + { + if (mTriMesh) + mTriMesh->addTriangle( toBullet(mMatrix.preMult(v1)), toBullet(mMatrix.preMult(v2)), toBullet(mMatrix.preMult(v3))); + } + + btTriangleMesh* mTriMesh; + osg::Matrixf mMatrix; +}; + +/// Creates a BulletShape out of a Node hierarchy. +class NodeToShapeVisitor : public osg::NodeVisitor +{ +public: + NodeToShapeVisitor() + : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) + , mTriangleMesh(NULL) + { + + } + + virtual void apply(osg::Geode& geode) + { + for (unsigned int i=0; i functor; + functor.setTriMesh(mTriangleMesh); + functor.setMatrix(worldMat); + drawable.accept(functor); + } + + osg::ref_ptr getShape() + { + osg::ref_ptr shape (new BulletShape); + TriangleMeshShape* meshShape = new TriangleMeshShape(mTriangleMesh, true); + shape->mCollisionShape = meshShape; + mTriangleMesh = NULL; + return shape; + } + +private: + btTriangleMesh* mTriangleMesh; +}; + +BulletShapeManager::BulletShapeManager(const VFS::Manager* vfs, SceneManager* sceneMgr) : mVFS(vfs) + , mSceneManager(sceneMgr) { } @@ -37,12 +120,22 @@ osg::ref_ptr BulletShapeManager::createInstance(const std:: if (extPos != std::string::npos && extPos+1 < normalized.size()) ext = normalized.substr(extPos+1); - if (ext != "nif") - return NULL; - - NifBullet::BulletNifLoader loader; - // might be worth sharing NIFFiles with SceneManager in some way - shape = loader.load(Nif::NIFFilePtr(new Nif::NIFFile(file, normalized))); + if (ext == "nif") + { + NifBullet::BulletNifLoader loader; + // might be worth sharing NIFFiles with SceneManager in some way + shape = loader.load(Nif::NIFFilePtr(new Nif::NIFFile(file, normalized))); + } + else + { + // TODO: support .bullet shape files + + osg::ref_ptr constNode (mSceneManager->getTemplate(normalized)); + osg::ref_ptr node (const_cast(constNode.get())); // const-trickery required because there is no const version of NodeVisitor + NodeToShapeVisitor visitor; + node->accept(visitor); + shape = visitor.getShape(); + } mIndex[normalized] = shape; } diff --git a/components/resource/bulletshapemanager.hpp b/components/resource/bulletshapemanager.hpp index 3e1f05ce5..6b8e64c21 100644 --- a/components/resource/bulletshapemanager.hpp +++ b/components/resource/bulletshapemanager.hpp @@ -23,13 +23,14 @@ namespace Resource class BulletShapeManager { public: - BulletShapeManager(const VFS::Manager* vfs); + BulletShapeManager(const VFS::Manager* vfs, SceneManager* sceneMgr); ~BulletShapeManager(); osg::ref_ptr createInstance(const std::string& name); private: const VFS::Manager* mVFS; + SceneManager* mSceneManager; typedef std::map > Index; Index mIndex; From 83e9a649e5910c186331d99e861ec9244d16df67 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 17 Nov 2015 01:43:19 +0100 Subject: [PATCH 2483/3725] Cleanup --- components/resource/bulletshapemanager.cpp | 1 - components/resource/scenemanager.cpp | 1 - 2 files changed, 2 deletions(-) diff --git a/components/resource/bulletshapemanager.cpp b/components/resource/bulletshapemanager.cpp index d573b455d..c4e46321f 100644 --- a/components/resource/bulletshapemanager.cpp +++ b/components/resource/bulletshapemanager.cpp @@ -114,7 +114,6 @@ osg::ref_ptr BulletShapeManager::createInstance(const std:: { Files::IStreamPtr file = mVFS->get(normalized); - // TODO: add support for non-NIF formats size_t extPos = normalized.find_last_of('.'); std::string ext; if (extPos != std::string::npos && extPos+1 < normalized.size()) diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index 3717ecb16..d5b0088d3 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -130,7 +130,6 @@ namespace Resource { try { - mTextureManager->getTexture2D(filename, osg::Texture::CLAMP_TO_EDGE, osg::Texture::CLAMP_TO_EDGE); return osgDB::ReaderWriter::ReadResult(mTextureManager->getImage(filename), osgDB::ReaderWriter::ReadResult::FILE_LOADED); } catch (std::exception& e) From d68ea994d56fc03d009eccbab079a7f51883d8ba Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 17 Nov 2015 01:51:21 +0100 Subject: [PATCH 2484/3725] Deal with empty meshes --- components/resource/bulletshapemanager.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/components/resource/bulletshapemanager.cpp b/components/resource/bulletshapemanager.cpp index c4e46321f..9aae1cad4 100644 --- a/components/resource/bulletshapemanager.cpp +++ b/components/resource/bulletshapemanager.cpp @@ -80,6 +80,9 @@ public: osg::ref_ptr getShape() { + if (!mTriangleMesh) + return osg::ref_ptr(); + osg::ref_ptr shape (new BulletShape); TriangleMeshShape* meshShape = new TriangleMeshShape(mTriangleMesh, true); shape->mCollisionShape = meshShape; @@ -134,6 +137,8 @@ osg::ref_ptr BulletShapeManager::createInstance(const std:: NodeToShapeVisitor visitor; node->accept(visitor); shape = visitor.getShape(); + if (!shape) + return osg::ref_ptr(); } mIndex[normalized] = shape; From 0bdfd1b0d7c625eb8cd82bb402f3c6c9a528515b Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 18 Nov 2015 16:47:03 +0100 Subject: [PATCH 2485/3725] Ignore Creature INDX subrecords Found in some .ess files, not sure what they mean. --- components/esm/loadcrea.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/components/esm/loadcrea.cpp b/components/esm/loadcrea.cpp index 0b53e5737..b51782089 100644 --- a/components/esm/loadcrea.cpp +++ b/components/esm/loadcrea.cpp @@ -1,5 +1,7 @@ #include "loadcrea.hpp" +#include + #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" @@ -83,6 +85,12 @@ namespace ESM { esm.skipHSub(); isDeleted = true; break; + case ESM::FourCC<'I','N','D','X'>::value: + // seems to occur only in .ESS files, unsure of purpose + int index; + esm.getHT(index); + std::cerr << "Creature::load: Unhandled INDX " << index << std::endl; + break; default: esm.fail("Unknown subrecord"); break; From 345335309193b865a3c01b27a1e42b219a099dc3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 18 Nov 2015 19:00:43 +0100 Subject: [PATCH 2486/3725] AiCombat distance check takes into account collision box (Fixes #1699) --- apps/openmw/mwbase/world.hpp | 3 +++ apps/openmw/mwmechanics/aicombat.cpp | 2 +- apps/openmw/mwphysics/physicssystem.cpp | 31 +++++++++++++++++++++++++ apps/openmw/mwphysics/physicssystem.hpp | 7 ++++++ apps/openmw/mwworld/worldimp.cpp | 7 ++++++ apps/openmw/mwworld/worldimp.hpp | 3 +++ 6 files changed, 52 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 7332a26be..39c1910df 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -543,6 +543,9 @@ namespace MWBase /// Return a vector aiming the actor's weapon towards a target. /// @note The length of the vector is the distance between actor and target. virtual osg::Vec3f aimToTarget(const MWWorld::Ptr& actor, const MWWorld::Ptr& target) = 0; + + /// Return the distance between actor's weapon and target's collision box. + virtual float getHitDistance(const MWWorld::Ptr& actor, const MWWorld::Ptr& target) = 0; }; } diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 6270779a4..3cea00e45 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -347,7 +347,7 @@ namespace MWMechanics osg::Vec3f vTargetPos(target.getRefData().getPosition().asVec3()); osg::Vec3f vAimDir = MWBase::Environment::get().getWorld()->aimToTarget(actor, target); - float distToTarget = (vTargetPos - vActorPos).length(); + float distToTarget = MWBase::Environment::get().getWorld()->getHitDistance(actor, target); osg::Vec3f& lastActorPos = storage.mLastActorPos; bool& followTarget = storage.mFollowTarget; diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 1898a3de1..1393832bb 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -218,6 +218,7 @@ namespace MWPhysics resultCallback1.m_collisionFilterMask = CollisionType_World|CollisionType_HeightMap; collisionWorld->rayTest(from, to, resultCallback1); + if (resultCallback1.hasHit() && ( (toOsg(resultCallback1.m_hitPointWorld) - tracer.mEndPos).length() > 30 || getSlope(tracer.mPlaneNormal) > sMaxSlope)) @@ -748,6 +749,36 @@ namespace MWPhysics return std::make_pair(MWWorld::Ptr(), osg::Vec3f()); } + float PhysicsSystem::getHitDistance(const osg::Vec3f &point, const MWWorld::Ptr &target) const + { + btCollisionObject* targetCollisionObj = NULL; + const Actor* actor = getActor(target); + if (actor) + targetCollisionObj = actor->getCollisionObject(); + if (!targetCollisionObj) + return 0.f; + + btTransform rayFrom; + rayFrom.setIdentity(); + rayFrom.setOrigin(toBullet(point)); + + // target the collision object's world origin, this should be the center of the collision object + btTransform rayTo; + rayTo.setIdentity(); + rayTo.setOrigin(targetCollisionObj->getWorldTransform().getOrigin()); + + btCollisionWorld::ClosestRayResultCallback cb(rayFrom.getOrigin(), rayTo.getOrigin()); + + btCollisionWorld::rayTestSingle(rayFrom, rayTo, targetCollisionObj, targetCollisionObj->getCollisionShape(), targetCollisionObj->getWorldTransform(), cb); + if (!cb.hasHit()) + { + // didn't hit the target. this could happen if point is already inside the collision box + return 0.f; + } + else + return (point - toOsg(cb.m_hitPointWorld)).length(); + } + class ClosestNotMeRayResultCallback : public btCollisionWorld::ClosestRayResultCallback { public: diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index 283c85725..a045638ef 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -89,6 +89,13 @@ namespace MWPhysics const osg::Quat &orientation, float queryDistance); + + /// Get distance from \a point to the collision shape of \a target. Uses a raycast to find where the + /// target vector hits the collision shape and then calculates distance from the intersection point. + /// This can be used to find out how much nearer we need to move to the target for a "getHitContact" to be successful. + /// \note Only Actor targets are supported at the moment. + float getHitDistance(const osg::Vec3f& point, const MWWorld::Ptr& target) const; + struct RayResult { bool mHit; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 7e78bef8c..57a20a993 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -3238,4 +3238,11 @@ namespace MWWorld osg::Vec3f targetPos = mPhysics->getPosition(target); return (targetPos - weaponPos); } + + float World::getHitDistance(const Ptr &actor, const Ptr &target) + { + osg::Vec3f weaponPos = getActorHeadPosition(actor, mRendering); + return mPhysics->getHitDistance(weaponPos, target); + } + } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 9f4928120..72093d281 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -633,6 +633,9 @@ namespace MWWorld /// Return a vector aiming the actor's weapon towards a target. /// @note The length of the vector is the distance between actor and target. virtual osg::Vec3f aimToTarget(const MWWorld::Ptr& actor, const MWWorld::Ptr& target); + + /// Return the distance between actor's weapon and target's collision box. + virtual float getHitDistance(const MWWorld::Ptr& actor, const MWWorld::Ptr& target); }; } From 9fce428929cce5b0f1be761683ec3d937f0ef00b Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 18 Nov 2015 20:41:49 +0100 Subject: [PATCH 2487/3725] ContactTestResultCallback: do not rely on col1 being the object tested against Unsure why, but in some cases col0 and col1 are swapped. --- apps/openmw/mwphysics/physicssystem.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 1393832bb..5d8fa2da2 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -936,6 +936,13 @@ namespace MWPhysics class ContactTestResultCallback : public btCollisionWorld::ContactResultCallback { public: + ContactTestResultCallback(const btCollisionObject* testedAgainst) + : mTestedAgainst(testedAgainst) + { + } + + const btCollisionObject* mTestedAgainst; + std::vector mResult; #if BT_BULLET_VERSION >= 281 @@ -944,11 +951,15 @@ namespace MWPhysics const btCollisionObjectWrapper* col1Wrap,int partId1,int index1) { const btCollisionObject* collisionObject = col0Wrap->m_collisionObject; + if (collisionObject == mTestedAgainst) + collisionObject = col1Wrap->m_collisionObject; #else virtual btScalar addSingleResult(btManifoldPoint& cp, const btCollisionObject* col0, int partId0, int index0, const btCollisionObject* col1, int partId1, int index1) { const btCollisionObject* collisionObject = col0; + if (collisionObject == mTestedAgainst) + collisionObject = col1; #endif const PtrHolder* holder = static_cast(collisionObject->getUserPointer()); if (holder) @@ -967,7 +978,7 @@ namespace MWPhysics else return std::vector(); - ContactTestResultCallback resultCallback; + ContactTestResultCallback resultCallback (me); resultCallback.m_collisionFilterGroup = collisionGroup; resultCallback.m_collisionFilterMask = collisionMask; mCollisionWorld->contactTest(me, resultCallback); From a49058721e4c6dedb2e19c89f508f38c290a6422 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 18 Nov 2015 21:20:12 +0100 Subject: [PATCH 2488/3725] Use a contactTest for collision script functions The previous method didn't work for stationary actors. This change fixes the grinder in "Sotha Sil, Dome of Kasia" not registering collisions if the player stands still. (Fixes #1934) --- apps/openmw/mwphysics/physicssystem.cpp | 36 +++++++------------------ apps/openmw/mwphysics/physicssystem.hpp | 8 +++--- 2 files changed, 12 insertions(+), 32 deletions(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 5d8fa2da2..5734f4827 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -234,9 +234,8 @@ namespace MWPhysics } static osg::Vec3f move(const MWWorld::Ptr &ptr, Actor* physicActor, const osg::Vec3f &movement, float time, - bool isFlying, float waterlevel, float slowFall, btCollisionWorld* collisionWorld - , std::map& collisionTracker - , std::map& standingCollisionTracker) + bool isFlying, float waterlevel, float slowFall, btCollisionWorld* collisionWorld, + std::map& standingCollisionTracker) { const ESM::Position& refpos = ptr.getRefData().getPosition(); osg::Vec3f position(refpos.asVec3()); @@ -345,13 +344,6 @@ namespace MWPhysics newPosition = tracer.mEndPos; // ok to move, so set newPosition break; } - else - { - const btCollisionObject* standingOn = tracer.mHitObject; - const PtrHolder* ptrHolder = static_cast(standingOn->getUserPointer()); - if (ptrHolder) - collisionTracker[ptr] = ptrHolder->getPtr(); - } } else { @@ -968,11 +960,11 @@ namespace MWPhysics } }; - std::vector PhysicsSystem::getCollisions(const MWWorld::Ptr &ptr, int collisionGroup, int collisionMask) + std::vector PhysicsSystem::getCollisions(const MWWorld::Ptr &ptr, int collisionGroup, int collisionMask) const { btCollisionObject* me = NULL; - ObjectMap::iterator found = mObjects.find(ptr); + ObjectMap::const_iterator found = mObjects.find(ptr); if (found != mObjects.end()) me = found->second->getCollisionObject(); else @@ -1081,7 +1073,6 @@ namespace MWPhysics mActors.insert(std::make_pair(updated, actor)); } - updateCollisionMapPtr(mCollisions, old, updated); updateCollisionMapPtr(mStandingCollisions, old, updated); } @@ -1197,7 +1188,6 @@ namespace MWPhysics void PhysicsSystem::clearQueuedMovement() { mMovementQueue.clear(); - mCollisions.clear(); mStandingCollisions.clear(); } @@ -1209,7 +1199,6 @@ namespace MWPhysics if(mTimeAccum >= 1.0f/60.0f) { // Collision events should be available on every frame - mCollisions.clear(); mStandingCollisions.clear(); const MWBase::World *world = MWBase::Environment::get().getWorld(); @@ -1243,7 +1232,7 @@ namespace MWPhysics osg::Vec3f newpos = MovementSolver::move(iter->first, physicActor, iter->second, mTimeAccum, world->isFlying(iter->first), - waterlevel, slowFall, mCollisionWorld, mCollisions, mStandingCollisions); + waterlevel, slowFall, mCollisionWorld, mStandingCollisions); float heightDiff = newpos.z() - oldHeight; @@ -1296,21 +1285,14 @@ namespace MWPhysics bool PhysicsSystem::isActorCollidingWith(const MWWorld::Ptr &actor, const MWWorld::Ptr &object) const { - for (CollisionMap::const_iterator it = mCollisions.begin(); it != mCollisions.end(); ++it) - { - if (it->first == actor && it->second == object) - return true; - } - return false; + std::vector collisions = getCollisions(object, CollisionType_World, CollisionType_Actor); + return (std::find(collisions.begin(), collisions.end(), actor) != collisions.end()); } void PhysicsSystem::getActorsCollidingWith(const MWWorld::Ptr &object, std::vector &out) const { - for (CollisionMap::const_iterator it = mCollisions.begin(); it != mCollisions.end(); ++it) - { - if (it->second == object) - out.push_back(it->first); - } + std::vector collisions = getCollisions(object, CollisionType_World, CollisionType_Actor); + out.insert(out.end(), collisions.begin(), collisions.end()); } void PhysicsSystem::disableWater() diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index a045638ef..1ccfb21cd 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -81,7 +81,7 @@ namespace MWPhysics void stepSimulation(float dt); void debugDraw(); - std::vector getCollisions(const MWWorld::Ptr &ptr, int collisionGroup, int collisionMask); ///< get handles this object collides with + std::vector getCollisions(const MWWorld::Ptr &ptr, int collisionGroup, int collisionMask) const; ///< get handles this object collides with osg::Vec3f traceDown(const MWWorld::Ptr &ptr, float maxHeight); std::pair getHitContact(const MWWorld::Ptr& actor, @@ -174,11 +174,9 @@ namespace MWPhysics bool mDebugDrawEnabled; - // Tracks all movement collisions happening during a single frame. - // This will detect e.g. running against a vertical wall. It will not detect climbing up stairs, - // stepping up small objects, etc. + // Tracks standing collisions happening during a single frame. + // This will detect standing on an object, but won't detect running e.g. against a wall. typedef std::map CollisionMap; - CollisionMap mCollisions; CollisionMap mStandingCollisions; // replaces all occurences of 'old' in the map by 'updated', no matter if its a key or value From 3bd2aaddea168f4e27fdd2e3244b64bc6daf4af7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 18 Nov 2015 23:14:01 +0100 Subject: [PATCH 2489/3725] Adjust PulseSlow light controller (Fixes #1963) --- components/sceneutil/lightcontroller.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/sceneutil/lightcontroller.cpp b/components/sceneutil/lightcontroller.cpp index d31e3d107..ccfd836f7 100644 --- a/components/sceneutil/lightcontroller.cpp +++ b/components/sceneutil/lightcontroller.cpp @@ -76,7 +76,7 @@ namespace SceneUtil if(mType == LT_Pulse || mType == LT_PulseSlow) { cycle_time = 2.0f * pi; - time_distortion = 20.0f; + time_distortion = mType == LT_Pulse ? 20.0f : 4.f; } else { @@ -114,9 +114,9 @@ namespace SceneUtil else if(mType == LT_FlickerSlow) brightness = 0.75f + flickerAmplitude(mDeltaCount*slow)*0.25f; else if(mType == LT_Pulse) - brightness = 1.0f + pulseAmplitude(mDeltaCount*fast)*0.25f; + brightness = 0.7f + pulseAmplitude(mDeltaCount*fast)*0.3f; else if(mType == LT_PulseSlow) - brightness = 1.0f + pulseAmplitude(mDeltaCount*slow)*0.25f; + brightness = 0.7f + pulseAmplitude(mDeltaCount*slow)*0.3f; static_cast(node)->getLight()->setDiffuse(mDiffuseColor * brightness); } From f08cfa19ea15f43816dedeb3f49d69c75f54f0b1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 19 Nov 2015 01:06:51 +0100 Subject: [PATCH 2490/3725] Fix SoundManager::isPlaying to consider multiple entries with the same Ptr/id Now it returns true if *any* sounds matching the given Ptr and id are playing. The previous behaviour was causing problems with "zombie" sounds (sounds that have finished playing, but weren't removed from the map yet) making the isPlaying method return false even though there's another legitimately playing sound in the map. --- apps/openmw/mwsound/soundmanagerimp.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index bc97f1601..6e309e28e 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -168,8 +168,8 @@ namespace MWSound SoundMap::const_iterator snditer = mActiveSounds.begin(); while(snditer != mActiveSounds.end()) { - if(snditer->second.first == ptr && snditer->second.second == id) - return snditer->first->isPlaying(); + if(snditer->second.first == ptr && snditer->second.second == id && snditer->first->isPlaying()) + return true; ++snditer; } return false; From ccc721ba3fb39d8f6e348ec0a9ab1f1b1c0b1613 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 19 Nov 2015 02:56:26 +0100 Subject: [PATCH 2491/3725] Print the OpenMW version to the logfile --- apps/openmw/main.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 609452a9f..17ef46246 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -210,6 +210,9 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat cfgMgr.readConfiguration(variables, desc); + Version::Version v = Version::getOpenmwVersion(variables["resources"].as()); + std::cout << v.describe() << std::endl; + engine.setGrabMouse(!variables.count("no-grab")); // Font encoding settings From 9b96fcc224ce65a0fde625ad2850787810ae7128 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 19 Nov 2015 15:49:42 +0100 Subject: [PATCH 2492/3725] Set the particle scaleReferenceFrame to local space --- components/nifosg/nifloader.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 21bf8a096..45e7c16df 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -866,6 +866,8 @@ namespace NifOsg partsys->getOrCreateUserDataContainer()->addDescription("worldspace"); } + partsys->setParticleScaleReferenceFrame(osgParticle::ParticleSystem::LOCAL_COORDINATES); + handleParticleInitialState(nifNode, partsys, partctrl); partsys->setQuota(partctrl->numParticles); From 8c268f239e1b5019cd804bcb82975db514a63a75 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 19 Nov 2015 15:57:12 +0100 Subject: [PATCH 2493/3725] Set the object node scale before inserting model This fixes initWorldSpaceParticles not taking object scale into account. Still not taking into account object rotation or node animations. Ideally the initWorldSpaceParticles needs to run in an updateCallback. --- apps/openmw/mwrender/objects.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 9f4fe2de2..40cbb6511 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -125,6 +125,11 @@ void Objects::insertBegin(const MWWorld::Ptr& ptr) insert->setPosition(osg::Vec3(f[0], f[1], f[2])); + const float scale = ptr.getCellRef().getScale(); + osg::Vec3f scaleVec(scale, scale, scale); + ptr.getClass().adjustScale(ptr, scaleVec, true); + insert->setScale(scaleVec); + ptr.getRefData().setBaseNode(insert); } From 36e91617c900a0887c5d1decbd6bf83d56bf9437 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 19 Nov 2015 22:09:32 +0100 Subject: [PATCH 2494/3725] Revert "NifOsg::Emitter: ignore psToWorld scale" This reverts commit 7c16630874230d886aa1d94f620c8b332676d93a. Fixes #3022 --- components/nifosg/particle.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/components/nifosg/particle.cpp b/components/nifosg/particle.cpp index 44d062d8b..68f3de8aa 100644 --- a/components/nifosg/particle.cpp +++ b/components/nifosg/particle.cpp @@ -264,9 +264,7 @@ void Emitter::emitParticles(double dt) osg::MatrixList worldMats = getParticleSystem()->getWorldMatrices(); if (!worldMats.empty()) { - osg::Matrix psToWorld = worldMats[0]; - // ignore scales in particlesystem world matrix. this seems wrong, but have to do so for MW compatibility. - psToWorld.orthoNormalize(psToWorld); + const osg::Matrix psToWorld = worldMats[0]; worldToPs = osg::Matrix::inverse(psToWorld); } From 894477849a4fdd48509b3c0337136776c020bf9c Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 19 Nov 2015 23:33:08 +0100 Subject: [PATCH 2495/3725] Store animated collision objects in a separate container --- apps/openmw/mwphysics/physicssystem.cpp | 15 +++++++++++++-- apps/openmw/mwphysics/physicssystem.hpp | 3 +++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 5734f4827..71a155392 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -549,6 +549,11 @@ namespace MWPhysics return mCollisionObject.get(); } + bool isAnimated() const + { + return !mShapeInstance->mAnimatedShapes.empty(); + } + void animateCollisionShapes(btCollisionWorld* collisionWorld) { if (mShapeInstance->mAnimatedShapes.empty()) @@ -1015,6 +1020,9 @@ namespace MWPhysics Object *obj = new Object(ptr, shapeInstance); mObjects.insert(std::make_pair(ptr, obj)); + if (obj->isAnimated()) + mAnimatedObjects.insert(obj); + mCollisionWorld->addCollisionObject(obj->getCollisionObject(), CollisionType_World, CollisionType_Actor|CollisionType_HeightMap|CollisionType_Projectile); } @@ -1025,6 +1033,9 @@ namespace MWPhysics if (found != mObjects.end()) { mCollisionWorld->removeCollisionObject(found->second->getCollisionObject()); + + mAnimatedObjects.erase(found->second); + delete found->second; mObjects.erase(found); } @@ -1251,8 +1262,8 @@ namespace MWPhysics void PhysicsSystem::stepSimulation(float dt) { - for (ObjectMap::iterator it = mObjects.begin(); it != mObjects.end(); ++it) - it->second->animateCollisionShapes(mCollisionWorld); + for (std::set::iterator it = mAnimatedObjects.begin(); it != mAnimatedObjects.end(); ++it) + (*it)->animateCollisionShapes(mCollisionWorld); CProfileManager::Reset(); CProfileManager::Increment_Frame_Counter(); diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index 1ccfb21cd..83729d7ae 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -166,6 +167,8 @@ namespace MWPhysics typedef std::map ObjectMap; ObjectMap mObjects; + std::set mAnimatedObjects; // stores pointers to elements in mObjects + typedef std::map ActorMap; ActorMap mActors; From cbf344663fc0914098d2c0d0b1679baa81ea1019 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 20 Nov 2015 00:17:07 +0100 Subject: [PATCH 2496/3725] animateCollisionShape checks if the shape is really animated --- apps/openmw/mwphysics/physicssystem.cpp | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 71a155392..b7d02ce36 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -563,7 +563,7 @@ namespace MWPhysics btCompoundShape* compound = dynamic_cast(mShapeInstance->getCollisionShape()); - for (std::map::const_iterator it = mShapeInstance->mAnimatedShapes.begin(); it != mShapeInstance->mAnimatedShapes.end(); ++it) + for (std::map::iterator it = mShapeInstance->mAnimatedShapes.begin(); it != mShapeInstance->mAnimatedShapes.end();) { int recIndex = it->first; int shapeIndex = it->second; @@ -578,6 +578,24 @@ namespace MWPhysics osg::NodePath path = visitor.mFoundPath; path.erase(path.begin()); + + // Attempt to remove "animated" shapes that are not actually animated + // We may get these because the BulletNifLoader does not know if a .kf file with additional controllers will be attached later on. + // On the first animateCollisionShapes call, we'll consider the graph completely loaded (with extra controllers and what not), + // so now we can better decide if the shape is really animated. + bool animated = false; + for (osg::NodePath::iterator nodePathIt = path.begin(); nodePathIt != path.end(); ++nodePathIt) + { + osg::Node* node = *nodePathIt; + if (node->getUpdateCallback()) + animated = true; + } + if (!animated) + { + mShapeInstance->mAnimatedShapes.erase(it++); + break; + } + osg::Matrixf matrix = osg::computeLocalToWorld(path); osg::Vec3f scale = matrix.getScale(); matrix.orthoNormalize(matrix); @@ -590,6 +608,8 @@ namespace MWPhysics compound->getChildShape(shapeIndex)->setLocalScaling(compound->getLocalScaling() * toBullet(scale)); compound->updateChildTransform(shapeIndex, transform); + + ++it; } collisionWorld->updateSingleAabb(mCollisionObject.get()); From 706b1d4c28c131e55b33f46e7ada805acdeed242 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 20 Nov 2015 02:22:37 +0100 Subject: [PATCH 2497/3725] Disable culling of ClipNode --- apps/openmw/mwrender/water.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index e93060f7c..ca099991e 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -198,6 +198,7 @@ public: mClipNode->getClipPlaneList().clear(); mClipNode->addClipPlane(new osg::ClipPlane(0, osg::Plane(mPlane.getNormal(), 0))); // mPlane.d() applied in FlipCallback mClipNode->setStateSetModes(*getOrCreateStateSet(), osg::StateAttribute::ON); + mClipNode->setCullingActive(false); } private: From 61314e1db16ed09d186b871b0a55d671d5a0a0a2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 20 Nov 2015 03:04:03 +0100 Subject: [PATCH 2498/3725] Fix bounding box of bullet debug drawer --- apps/openmw/mwrender/bulletdebugdraw.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwrender/bulletdebugdraw.cpp b/apps/openmw/mwrender/bulletdebugdraw.cpp index c6d7935c5..eaf36cf85 100644 --- a/apps/openmw/mwrender/bulletdebugdraw.cpp +++ b/apps/openmw/mwrender/bulletdebugdraw.cpp @@ -78,6 +78,7 @@ void DebugDrawer::step() mWorld->debugDrawWorld(); mDrawArrays->setCount(mVertices->size()); mVertices->dirty(); + mGeometry->dirtyBound(); } } From 5f143dee2d84323ddcbfd95231338913ce275621 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 20 Nov 2015 03:22:35 +0100 Subject: [PATCH 2499/3725] Fix lighting incontinuity at nightfall and sunrise --- apps/openmw/mwworld/weather.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 37f5e094d..49d421a20 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -690,7 +690,7 @@ void WeatherManager::update(float duration, bool paused) if ( !is_night ) { theta = M_PI * (adjustedHour - mSunriseTime) / dayDuration; } else { - theta = M_PI * (adjustedHour - adjustedNightStart) / nightDuration; + theta = M_PI * (1.f - (adjustedHour - adjustedNightStart) / nightDuration); } osg::Vec3f final( From 27617468c8db06953ba32b7807b46d560a22f0e7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 20 Nov 2015 03:29:58 +0100 Subject: [PATCH 2500/3725] Fix the collision shape not updating when scaling an object via script --- apps/openmw/mwphysics/physicssystem.cpp | 2 +- apps/openmw/mwworld/scene.cpp | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index b7d02ce36..9eda6cb06 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -1126,9 +1126,9 @@ namespace MWPhysics void PhysicsSystem::updateScale(const MWWorld::Ptr &ptr) { ObjectMap::iterator found = mObjects.find(ptr); - float scale = ptr.getCellRef().getScale(); if (found != mObjects.end()) { + float scale = ptr.getCellRef().getScale(); found->second->setScale(scale); mCollisionWorld->updateSingleAabb(found->second->getCollisionObject()); return; diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 1ba17a967..5598598d0 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -73,6 +73,8 @@ namespace osg::Vec3f scaleVec (scale, scale, scale); ptr.getClass().adjustScale(ptr, scaleVec, true); rendering.scaleObject(ptr, scaleVec); + + physics.updateScale(ptr); } } @@ -114,7 +116,6 @@ namespace { addObject(ptr, mPhysics, mRendering); updateObjectRotation(ptr, mPhysics, mRendering, false); - updateObjectScale(ptr, mPhysics, mRendering); ptr.getClass().adjustPosition (ptr, false); } catch (const std::exception& e) From 038f682510e0dc12ddbf5d15a75d6c68774cb78b Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 19 Nov 2015 01:06:51 +0100 Subject: [PATCH 2501/3725] Fix SoundManager::isPlaying to consider multiple entries with the same Ptr/id Now it returns true if *any* sounds matching the given Ptr and id are playing. The previous behaviour was causing problems with "zombie" sounds (sounds that have finished playing, but weren't removed from the map yet) making the isPlaying method return false even though there's another legitimately playing sound in the map. --- apps/openmw/mwsound/soundmanagerimp.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index bc97f1601..6e309e28e 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -168,8 +168,8 @@ namespace MWSound SoundMap::const_iterator snditer = mActiveSounds.begin(); while(snditer != mActiveSounds.end()) { - if(snditer->second.first == ptr && snditer->second.second == id) - return snditer->first->isPlaying(); + if(snditer->second.first == ptr && snditer->second.second == id && snditer->first->isPlaying()) + return true; ++snditer; } return false; From 966737f891d013d3ece6a6de35900399baf322fa Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 19 Nov 2015 15:49:42 +0100 Subject: [PATCH 2502/3725] Set the particle scaleReferenceFrame to local space --- components/nifosg/nifloader.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 3e7f47b6f..6a536d7af 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -843,6 +843,8 @@ namespace NifOsg partsys->getOrCreateUserDataContainer()->addDescription("worldspace"); } + partsys->setParticleScaleReferenceFrame(osgParticle::ParticleSystem::LOCAL_COORDINATES); + handleParticleInitialState(nifNode, partsys, partctrl); partsys->setQuota(partctrl->numParticles); From 622573f494af36af9c923e26acae7ca56226754f Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 19 Nov 2015 15:57:12 +0100 Subject: [PATCH 2503/3725] Set the object node scale before inserting model This fixes initWorldSpaceParticles not taking object scale into account. Still not taking into account object rotation or node animations. Ideally the initWorldSpaceParticles needs to run in an updateCallback. --- apps/openmw/mwrender/objects.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 9f4fe2de2..40cbb6511 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -125,6 +125,11 @@ void Objects::insertBegin(const MWWorld::Ptr& ptr) insert->setPosition(osg::Vec3(f[0], f[1], f[2])); + const float scale = ptr.getCellRef().getScale(); + osg::Vec3f scaleVec(scale, scale, scale); + ptr.getClass().adjustScale(ptr, scaleVec, true); + insert->setScale(scaleVec); + ptr.getRefData().setBaseNode(insert); } From e5ce3f62b7db6e46ed8a4648fa0b04ca07410309 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 20 Nov 2015 03:22:35 +0100 Subject: [PATCH 2504/3725] Fix lighting incontinuity at nightfall and sunrise --- apps/openmw/mwworld/weather.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 24b45fcea..e4fdd62de 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -680,7 +680,7 @@ void WeatherManager::update(float duration, bool paused) if ( !is_night ) { theta = M_PI * (adjustedHour - mSunriseTime) / dayDuration; } else { - theta = M_PI * (adjustedHour - adjustedNightStart) / nightDuration; + theta = M_PI * (1.f - (adjustedHour - adjustedNightStart) / nightDuration); } osg::Vec3f final( From b2746c8c01794c3241bddcbb16d24efdf996e495 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 20 Nov 2015 03:29:58 +0100 Subject: [PATCH 2505/3725] Fix the collision shape not updating when scaling an object via script --- apps/openmw/mwphysics/physicssystem.cpp | 2 +- apps/openmw/mwworld/scene.cpp | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 55144afe7..0a687d93f 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -1062,9 +1062,9 @@ namespace MWPhysics void PhysicsSystem::updateScale(const MWWorld::Ptr &ptr) { ObjectMap::iterator found = mObjects.find(ptr); - float scale = ptr.getCellRef().getScale(); if (found != mObjects.end()) { + float scale = ptr.getCellRef().getScale(); found->second->setScale(scale); mCollisionWorld->updateSingleAabb(found->second->getCollisionObject()); return; diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 1ba17a967..5598598d0 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -73,6 +73,8 @@ namespace osg::Vec3f scaleVec (scale, scale, scale); ptr.getClass().adjustScale(ptr, scaleVec, true); rendering.scaleObject(ptr, scaleVec); + + physics.updateScale(ptr); } } @@ -114,7 +116,6 @@ namespace { addObject(ptr, mPhysics, mRendering); updateObjectRotation(ptr, mPhysics, mRendering, false); - updateObjectScale(ptr, mPhysics, mRendering); ptr.getClass().adjustPosition (ptr, false); } catch (const std::exception& e) From 2d302aef99f804423fc0b837317f47742bc8c1d5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 20 Nov 2015 05:05:43 +0100 Subject: [PATCH 2506/3725] Implement stayOutside script variable --- apps/openmw/mwworld/actionteleport.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/apps/openmw/mwworld/actionteleport.cpp b/apps/openmw/mwworld/actionteleport.cpp index cd6698c98..031f07258 100644 --- a/apps/openmw/mwworld/actionteleport.cpp +++ b/apps/openmw/mwworld/actionteleport.cpp @@ -3,6 +3,9 @@ #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/mechanicsmanager.hpp" + +#include "../mwworld/class.hpp" + #include "player.hpp" namespace @@ -40,6 +43,11 @@ namespace MWWorld for(std::set::iterator it = followers.begin();it != followers.end();++it) { MWWorld::Ptr follower = *it; + + std::string script = follower.getClass().getScript(follower); + if (!script.empty() && follower.getRefData().getLocals().getIntVar(script, "stayoutside") == 1) + continue; + if ((follower.getRefData().getPosition().asVec3() - actor.getRefData().getPosition().asVec3()).length2() <= 800*800) teleport(*it); From 43de13fa993a36edfd37c7c4d3aa4389713a9835 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 20 Nov 2015 19:22:31 +0100 Subject: [PATCH 2507/3725] Do not allow resting on lava --- apps/openmw/mwphysics/physicssystem.cpp | 42 +++++++++++++++++++++++++ apps/openmw/mwphysics/physicssystem.hpp | 6 ++++ apps/openmw/mwworld/worldimp.cpp | 9 ++++-- 3 files changed, 54 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 9eda6cb06..17014e162 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -515,6 +515,7 @@ namespace MWPhysics public: Object(const MWWorld::Ptr& ptr, osg::ref_ptr shapeInstance) : mShapeInstance(shapeInstance) + , mSolid(true) { mPtr = ptr; @@ -549,6 +550,17 @@ namespace MWPhysics return mCollisionObject.get(); } + /// Return solid flag. Not used by the object itself, true by default. + bool isSolid() const + { + return mSolid; + } + + void setSolid(bool solid) + { + mSolid = solid; + } + bool isAnimated() const { return !mShapeInstance->mAnimatedShapes.empty(); @@ -618,6 +630,7 @@ namespace MWPhysics private: std::auto_ptr mCollisionObject; osg::ref_ptr mShapeInstance; + bool mSolid; }; // --------------------------------------------------------------- @@ -684,6 +697,35 @@ namespace MWPhysics return mDebugDrawEnabled; } + void PhysicsSystem::markAsNonSolid(const MWWorld::Ptr &ptr) + { + ObjectMap::iterator found = mObjects.find(ptr); + if (found == mObjects.end()) + return; + + found->second->setSolid(false); + } + + bool PhysicsSystem::isOnSolidGround (const MWWorld::Ptr& actor) const + { + const Actor* physactor = getActor(actor); + if (!physactor->getOnGround()) + return false; + + CollisionMap::const_iterator found = mStandingCollisions.find(actor); + if (found == mStandingCollisions.end()) + return true; // assume standing on terrain (which is a non-object, so not collision tracked) + + ObjectMap::const_iterator foundObj = mObjects.find(found->second); + if (foundObj == mObjects.end()) + return false; + + if (!foundObj->second->isSolid()) + return false; + + return true; + } + class DeepestNotMeContactTestResultCallback : public btCollisionWorld::ContactResultCallback { const btCollisionObject* mMe; diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index 83729d7ae..de644e0f3 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -153,6 +153,12 @@ namespace MWPhysics bool toggleDebugRendering(); + /// Mark the given object as a 'non-solid' object. A non-solid object means that + /// \a isOnSolidGround will return false for actors standing on that object. + void markAsNonSolid (const MWWorld::Ptr& ptr); + + bool isOnSolidGround (const MWWorld::Ptr& actor) const; + private: void updateWater(); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 57a20a993..b1234c8a4 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2059,11 +2059,10 @@ namespace MWWorld if (!actor) throw std::runtime_error("can't find player"); - if((!actor->getOnGround()&&actor->getCollisionMode()) || isUnderwater(currentCell, playerPos) || isWalkingOnWater(player)) + if ((actor->getCollisionMode() && !mPhysics->isOnSolidGround(player)) || isUnderwater(currentCell, playerPos)) return 2; - if((currentCell->getCell()->mData.mFlags&ESM::Cell::NoSleep) || - player.getClass().getNpcStats(player).isWerewolf()) + if((currentCell->getCell()->mData.mFlags&ESM::Cell::NoSleep) || player.getClass().getNpcStats(player).isWerewolf()) return 1; return 0; @@ -2155,6 +2154,8 @@ namespace MWWorld health.setCurrent(health.getCurrent()-healthPerSecond*MWBase::Environment::get().getFrameDuration()); stats.setHealth(health); + mPhysics->markAsNonSolid (object); + if (healthPerSecond > 0.0f) { if (actor == getPlayerPtr()) @@ -2183,6 +2184,8 @@ namespace MWWorld health.setCurrent(health.getCurrent()-healthPerSecond*MWBase::Environment::get().getFrameDuration()); stats.setHealth(health); + mPhysics->markAsNonSolid (object); + if (healthPerSecond > 0.0f) { if (actor == getPlayerPtr()) From cf4f3d9ebcf7ba264d9c688be56b21dcc6e1e768 Mon Sep 17 00:00:00 2001 From: cfcohen Date: Fri, 20 Nov 2015 14:57:42 -0500 Subject: [PATCH 2508/3725] Correct tooltip for Magicka in stats window. --- apps/openmw/mwgui/statswindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/statswindow.cpp b/apps/openmw/mwgui/statswindow.cpp index efbbeb29a..e66e01238 100644 --- a/apps/openmw/mwgui/statswindow.cpp +++ b/apps/openmw/mwgui/statswindow.cpp @@ -159,7 +159,7 @@ namespace MWGui else if (id == "MBar") { getWidget(w, "Magicka"); - w->setUserString("Caption_HealthDescription", "#{sIntDesc}\n" + valStr); + w->setUserString("Caption_HealthDescription", "#{sMagDesc}\n" + valStr); } else if (id == "FBar") { From 1b1d9a7a9c3d89bbde1c8510961c2c3cac684926 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 21 Nov 2015 02:05:27 +0100 Subject: [PATCH 2509/3725] Fixed another tooltip --- apps/openmw/mwgui/hud.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 3922b1997..cf0fa3414 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -196,7 +196,7 @@ namespace MWGui mMagicka->setProgressRange (modified); mMagicka->setProgressPosition (current); getWidget(w, "MagickaFrame"); - w->setUserString("Caption_HealthDescription", "#{sIntDesc}\n" + valStr); + w->setUserString("Caption_HealthDescription", "#{sMagDesc}\n" + valStr); } else if (id == "FBar") { From 9d8a1479eb3d0f7a645a6913b38ebec8a68d6514 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 21 Nov 2015 09:31:30 +0100 Subject: [PATCH 2510/3725] updated change log once more --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 36700904e..43e598566 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,7 @@ Bug #2014: Antialiasing setting does nothing on Linux Bug #2037: Some enemies attack the air when spotting the player Bug #2052: NIF rotation matrices including scales are not supported + Bug #2062: Crank in Old Mournhold: Forgotten Sewer turns about the wrong axis Bug #2111: Raindrops in front of fire look wrong Bug #2140: [OpenGL] Water effects, flames and parts of creatures solid black when observed through brazier flame Bug #2147: Trueflame and Hopesfire flame effects not properly aligned with blade @@ -176,6 +177,7 @@ Bug #2980: Editor: Attribute and Skill can be selected for spells that do not require these parameters, leading to non-functional spells Bug #2990: Compiling a script with warning mode 2 and enabled error downgrading leads to infinite recursion Bug #2992: [Mod: Great House Dagoth] Killing Dagoth Gares freezes the game + Bug #3007: PlaceItem takes radians instead of degrees + angle reliability Feature #706: Editor: Script Editor enhancements Feature #872: Editor: Colour values in tables Feature #880: Editor: ID auto-complete From e0e9e7f8c2e2e666f125c2c3a8b1c098ec4ea43a Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 21 Nov 2015 11:56:24 +0100 Subject: [PATCH 2511/3725] adjusted startup warning message for recent improvements regarding loading/saving --- apps/opencs/view/doc/startup.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/doc/startup.cpp b/apps/opencs/view/doc/startup.cpp index a9d697f1c..67ff50dab 100644 --- a/apps/opencs/view/doc/startup.cpp +++ b/apps/opencs/view/doc/startup.cpp @@ -104,14 +104,16 @@ CSVDoc::StartupDialogue::StartupDialogue() : mWidth (0), mColumn (2) layout->addWidget (createButtons()); layout->addWidget (createTools()); - /// \todo remove this label once loading and saving are fully implemented - QLabel *warning = new QLabel ("WARNING:

    OpenCS is in alpha stage.
    The code for loading and saving is incomplete.
    This version of OpenCS is only a preview.
    Do NOT use it for real editing!
    You will lose records both on loading and on saving.

    Please note:
    If you lose data and come to the OpenMW forum to complain,
    we will mock you.
    "); + /// \todo remove this label once we are feature complete and convinced that this thing is + /// working properly. + QLabel *warning = new QLabel ("WARNING: OpenMW-CS is in alpha stage.

    The editor is not feature complete and not sufficiently tested.
    In theory your data should be safe. But we strongly advice to make backups regularly if you are working with live data.
    "); QFont font; font.setPointSize (12); font.setBold (true); warning->setFont (font); + warning->setWordWrap (true); layout->addWidget (warning, 1); From b74b274ac0e88ad7c833b908bb301dee3986264f Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 21 Nov 2015 12:14:57 +0100 Subject: [PATCH 2512/3725] Removed validator for filenames in OpenMW-CS (Fixes #2918) --- apps/opencs/view/doc/filewidget.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/opencs/view/doc/filewidget.cpp b/apps/opencs/view/doc/filewidget.cpp index 110d561c1..9e9acdfbe 100644 --- a/apps/opencs/view/doc/filewidget.cpp +++ b/apps/opencs/view/doc/filewidget.cpp @@ -16,7 +16,6 @@ CSVDoc::FileWidget::FileWidget (QWidget *parent) : QWidget (parent), mAddon (fal QHBoxLayout *layout = new QHBoxLayout (this); mInput = new QLineEdit (this); - mInput->setValidator (new QRegExpValidator(QRegExp("^[a-zA-Z0-9_-\\s]*$"))); layout->addWidget (mInput, 1); From 1093a53cf9f2a85374e145d96bb21bfb46eb13ad Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 21 Nov 2015 12:45:11 +0100 Subject: [PATCH 2513/3725] hide script error list when there are no errors (Fixes #2867) --- apps/opencs/view/world/scriptsubview.cpp | 19 +++++++++++++++++++ apps/opencs/view/world/scriptsubview.hpp | 2 ++ 2 files changed, 21 insertions(+) diff --git a/apps/opencs/view/world/scriptsubview.cpp b/apps/opencs/view/world/scriptsubview.cpp index eb0c70656..7907dca03 100644 --- a/apps/opencs/view/world/scriptsubview.cpp +++ b/apps/opencs/view/world/scriptsubview.cpp @@ -54,6 +54,7 @@ void CSVWorld::ScriptSubView::updateDeletedState() if (isDeleted()) { mErrors->clear(); + adjustSplitter(); mEditor->setEnabled (false); } else @@ -63,6 +64,22 @@ void CSVWorld::ScriptSubView::updateDeletedState() } } +void CSVWorld::ScriptSubView::adjustSplitter() +{ + QList sizes; + + if (mErrors->rowCount()) + { + sizes << 1 << 1; + } + else + { + sizes << 1 << 0; + } + + mMain->setSizes (sizes); +} + CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) : SubView (id), mDocument (document), mColumn (-1), mBottom(0), mButtons (0), mCommandDispatcher (document, CSMWorld::UniversalId::getParentType (id.getType())) @@ -347,4 +364,6 @@ void CSVWorld::ScriptSubView::updateRequest() QString source = mModel->data (index).toString(); mErrors->update (source.toUtf8().constData()); + + adjustSplitter(); } diff --git a/apps/opencs/view/world/scriptsubview.hpp b/apps/opencs/view/world/scriptsubview.hpp index 907dc7958..c04a7df7c 100644 --- a/apps/opencs/view/world/scriptsubview.hpp +++ b/apps/opencs/view/world/scriptsubview.hpp @@ -58,6 +58,8 @@ namespace CSVWorld void updateDeletedState(); + void adjustSplitter(); + public: ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document); From 26640d17eb053176b45482e801236415a42ddf1f Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 21 Nov 2015 12:52:32 +0100 Subject: [PATCH 2514/3725] do not adjust error panel height if panal was already open --- apps/opencs/view/world/scriptsubview.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/opencs/view/world/scriptsubview.cpp b/apps/opencs/view/world/scriptsubview.cpp index 7907dca03..0faf61f9b 100644 --- a/apps/opencs/view/world/scriptsubview.cpp +++ b/apps/opencs/view/world/scriptsubview.cpp @@ -70,6 +70,9 @@ void CSVWorld::ScriptSubView::adjustSplitter() if (mErrors->rowCount()) { + if (mErrors->height()) + return; // keep old height if the error panel was already open + sizes << 1 << 1; } else From f5c61ee616bfaed911a574c6d43aa6842c224773 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 21 Nov 2015 14:19:14 +0100 Subject: [PATCH 2515/3725] remember script error panel height per scriptsubview --- apps/opencs/view/world/scriptsubview.cpp | 12 ++++++++++-- apps/opencs/view/world/scriptsubview.hpp | 1 + 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/world/scriptsubview.cpp b/apps/opencs/view/world/scriptsubview.cpp index 0faf61f9b..c45e45f56 100644 --- a/apps/opencs/view/world/scriptsubview.cpp +++ b/apps/opencs/view/world/scriptsubview.cpp @@ -73,10 +73,13 @@ void CSVWorld::ScriptSubView::adjustSplitter() if (mErrors->height()) return; // keep old height if the error panel was already open - sizes << 1 << 1; + sizes << (mMain->height()-mErrorHeight-mMain->handleWidth()) << mErrorHeight; } else { + if (mErrors->height()) + mErrorHeight = mErrors->height(); + sizes << 1 << 0; } @@ -85,7 +88,8 @@ void CSVWorld::ScriptSubView::adjustSplitter() CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) : SubView (id), mDocument (document), mColumn (-1), mBottom(0), mButtons (0), - mCommandDispatcher (document, CSMWorld::UniversalId::getParentType (id.getType())) + mCommandDispatcher (document, CSMWorld::UniversalId::getParentType (id.getType())), + mErrorHeight (100) { std::vector selection (1, id.getId()); mCommandDispatcher.setSelection (selection); @@ -101,6 +105,10 @@ CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc: mErrors = new ScriptErrorTable (document, this); mMain->addWidget (mErrors); + QList sizes; + sizes << 1 << 0; + mMain->setSizes (sizes); + QWidget *widget = new QWidget (this);; widget->setLayout (&mLayout); setWidget (widget); diff --git a/apps/opencs/view/world/scriptsubview.hpp b/apps/opencs/view/world/scriptsubview.hpp index c04a7df7c..179430ef9 100644 --- a/apps/opencs/view/world/scriptsubview.hpp +++ b/apps/opencs/view/world/scriptsubview.hpp @@ -47,6 +47,7 @@ namespace CSVWorld QSplitter *mMain; ScriptErrorTable *mErrors; QTimer *mCompileDelay; + int mErrorHeight; private: From 99500f40212c7b37a536c2692d5b066c26c79bbf Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 21 Nov 2015 14:28:40 +0100 Subject: [PATCH 2516/3725] make initial size of script error panel configurable (Fixes #2996) --- apps/opencs/model/settings/usersettings.cpp | 5 +++++ apps/opencs/view/world/scriptsubview.cpp | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/settings/usersettings.cpp b/apps/opencs/model/settings/usersettings.cpp index 8bf24ae34..8e5ab3d87 100644 --- a/apps/opencs/model/settings/usersettings.cpp +++ b/apps/opencs/model/settings/usersettings.cpp @@ -334,6 +334,11 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() delay->setRange (0, 10000); delay->setToolTip ("Delay in milliseconds"); + Setting *errorHeight = createSetting (Type_SpinBox, "error-height", + "Initial height of the error panel"); + errorHeight->setDefaultValue (100); + errorHeight->setRange (100, 10000); + Setting *formatInt = createSetting (Type_LineEdit, "colour-int", "Highlight Colour: Int"); formatInt->setDefaultValues (QStringList() << "Dark magenta"); formatInt->setToolTip ("(Default: Green) Use one of the following formats:" + tooltip); diff --git a/apps/opencs/view/world/scriptsubview.cpp b/apps/opencs/view/world/scriptsubview.cpp index c45e45f56..bd66f2bf6 100644 --- a/apps/opencs/view/world/scriptsubview.cpp +++ b/apps/opencs/view/world/scriptsubview.cpp @@ -89,7 +89,7 @@ void CSVWorld::ScriptSubView::adjustSplitter() CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) : SubView (id), mDocument (document), mColumn (-1), mBottom(0), mButtons (0), mCommandDispatcher (document, CSMWorld::UniversalId::getParentType (id.getType())), - mErrorHeight (100) + mErrorHeight (CSMSettings::UserSettings::instance().setting ("script-editor/error-height").toInt()) { std::vector selection (1, id.getId()); mCommandDispatcher.setSelection (selection); From b507d5da5dd81b9f2a29a2e1acd3bc1f20a9997a Mon Sep 17 00:00:00 2001 From: cfcohen Date: Sun, 22 Nov 2015 00:50:36 -0500 Subject: [PATCH 2517/3725] One more tooltip fix. This one in the review dialog with Socucius Ergalla. --- apps/openmw/mwgui/review.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/review.cpp b/apps/openmw/mwgui/review.cpp index fa07f1020..d7d6c3cdb 100644 --- a/apps/openmw/mwgui/review.cpp +++ b/apps/openmw/mwgui/review.cpp @@ -154,7 +154,7 @@ namespace MWGui { mMagicka->setValue(static_cast(value.getCurrent()), static_cast(value.getModified())); std::string valStr = MyGUI::utility::toString(value.getCurrent()) + "/" + MyGUI::utility::toString(value.getModified()); - mMagicka->setUserString("Caption_HealthDescription", "#{sIntDesc}\n" + valStr); + mMagicka->setUserString("Caption_HealthDescription", "#{sMagDesc}\n" + valStr); } void ReviewDialog::setFatigue(const MWMechanics::DynamicStat& value) From 34350ddeb1a9f86627fe8f52605cc1fb8b8bd15f Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 22 Nov 2015 15:46:04 +0100 Subject: [PATCH 2518/3725] Fix bug #3028 --- files/mygui/openmw_layers.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/mygui/openmw_layers.xml b/files/mygui/openmw_layers.xml index c6d3df521..cd8a9f760 100644 --- a/files/mygui/openmw_layers.xml +++ b/files/mygui/openmw_layers.xml @@ -4,7 +4,7 @@ - + From 2108e96c159b5834e667699ec0e86e4a372c28e4 Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Sun, 22 Nov 2015 19:32:13 +0100 Subject: [PATCH 2519/3725] OS X: use TGA, PNG & JPEG plugins instead of ImageIO Using ImageIO is troublesome when one needs to read an image from memory, see for the details: https://forum.openmw.org/viewtopic.php?f=20&t=2949&start=220#p35531 --- CMakeLists.txt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0f168be16..6716e0e23 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -748,9 +748,10 @@ if (APPLE) set(ABSOLUTE_PLUGINS "") set(USED_OSG_PLUGINS - osgdb_tga osgdb_dds - osgdb_imageio + osgdb_jpeg + osgdb_png + osgdb_tga ) foreach (PLUGIN_NAME ${USED_OSG_PLUGINS}) From 62169a70392ebef85aeb2b7cf3d0e1d41573a578 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 20 Nov 2015 21:57:04 +0100 Subject: [PATCH 2520/3725] Use a single-precision PositionAttitudeTransform in speed critical places --- apps/openmw/mwmechanics/actors.cpp | 3 +- apps/openmw/mwmechanics/character.cpp | 3 +- apps/openmw/mwmechanics/combat.cpp | 4 +- .../mwmechanics/mechanicsmanagerimp.cpp | 4 +- apps/openmw/mwphysics/actor.cpp | 3 +- apps/openmw/mwphysics/physicssystem.cpp | 2 +- apps/openmw/mwrender/animation.cpp | 1 + apps/openmw/mwrender/camera.cpp | 5 +- apps/openmw/mwrender/characterpreview.hpp | 2 + apps/openmw/mwrender/creatureanimation.cpp | 3 +- apps/openmw/mwrender/objects.cpp | 4 +- apps/openmw/mwrender/renderingmanager.cpp | 4 +- apps/openmw/mwrender/renderingmanager.hpp | 2 +- apps/openmw/mwrender/ripplesimulation.hpp | 1 + .../mwscript/transformationextensions.cpp | 2 +- apps/openmw/mwworld/projectilemanager.hpp | 1 + apps/openmw/mwworld/refdata.cpp | 4 +- apps/openmw/mwworld/refdata.hpp | 8 +-- apps/openmw/mwworld/worldimp.cpp | 3 +- components/CMakeLists.txt | 2 +- .../sceneutil/positionattitudetransform.cpp | 51 ++++++++++++++++++ .../sceneutil/positionattitudetransform.hpp | 53 +++++++++++++++++++ components/terrain/terraingrid.cpp | 4 +- 23 files changed, 139 insertions(+), 30 deletions(-) create mode 100644 components/sceneutil/positionattitudetransform.cpp create mode 100644 components/sceneutil/positionattitudetransform.hpp diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 1c26c7dd1..284e237a0 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -3,11 +3,10 @@ #include #include -#include - #include #include #include +#include #include "../mwworld/esmstore.hpp" #include "../mwworld/class.hpp" diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index b5b4721c0..ff23844dd 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -21,7 +21,6 @@ #include -#include #include "movement.hpp" #include "npcstats.hpp" @@ -33,6 +32,8 @@ #include +#include + #include "../mwrender/animation.hpp" #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwmechanics/combat.cpp b/apps/openmw/mwmechanics/combat.cpp index f11e6bcfd..a01dc7079 100644 --- a/apps/openmw/mwmechanics/combat.cpp +++ b/apps/openmw/mwmechanics/combat.cpp @@ -1,9 +1,9 @@ #include "combat.hpp" -#include - #include +#include + #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/mechanicsmanager.hpp" diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 761c5ece9..e392b309b 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -2,13 +2,13 @@ #include -#include - #include #include #include +#include + #include "../mwworld/esmstore.hpp" #include "../mwworld/inventorystore.hpp" diff --git a/apps/openmw/mwphysics/actor.cpp b/apps/openmw/mwphysics/actor.cpp index 8cd0dfeb9..8438f26a3 100644 --- a/apps/openmw/mwphysics/actor.cpp +++ b/apps/openmw/mwphysics/actor.cpp @@ -1,11 +1,10 @@ #include "actor.hpp" -#include - #include #include #include +#include #include #include "../mwworld/class.hpp" diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 17014e162..1f59c5c99 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -3,7 +3,6 @@ #include #include -#include #include #include @@ -22,6 +21,7 @@ #include #include +#include #include // FindRecIndexVisitor diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 6ef6fab23..d530c2c92 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" diff --git a/apps/openmw/mwrender/camera.cpp b/apps/openmw/mwrender/camera.cpp index 1d43cde43..88934414f 100644 --- a/apps/openmw/mwrender/camera.cpp +++ b/apps/openmw/mwrender/camera.cpp @@ -1,8 +1,9 @@ #include "camera.hpp" -#include #include +#include + #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" @@ -378,7 +379,7 @@ namespace MWRender else { mAnimation->setViewMode(NpcAnimation::VM_Normal); - osg::PositionAttitudeTransform* transform = mTrackingPtr.getRefData().getBaseNode(); + SceneUtil::PositionAttitudeTransform* transform = mTrackingPtr.getRefData().getBaseNode(); mTrackingNode = transform; if (transform) mHeightScale = transform->getScale().z(); diff --git a/apps/openmw/mwrender/characterpreview.hpp b/apps/openmw/mwrender/characterpreview.hpp index 32c1850c6..2b7984b00 100644 --- a/apps/openmw/mwrender/characterpreview.hpp +++ b/apps/openmw/mwrender/characterpreview.hpp @@ -4,6 +4,8 @@ #include #include +#include + #include #include diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index f46736a39..7c447182f 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -2,12 +2,11 @@ #include -#include - #include #include #include #include +#include #include "../mwbase/world.hpp" diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 40cbb6511..d612824e2 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -4,7 +4,6 @@ #include #include -#include #include #include @@ -14,6 +13,7 @@ #include #include +#include #include "../mwworld/ptr.hpp" #include "../mwworld/class.hpp" @@ -116,7 +116,7 @@ void Objects::insertBegin(const MWWorld::Ptr& ptr) else cellnode = found->second; - osg::ref_ptr insert (new osg::PositionAttitudeTransform); + osg::ref_ptr insert (new SceneUtil::PositionAttitudeTransform); cellnode->addChild(insert); insert->getOrCreateUserDataContainer()->addUserObject(new PtrHolder(ptr)); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index c55d11795..f6403a925 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -8,7 +8,6 @@ #include #include #include -#include #include #include @@ -26,6 +25,7 @@ #include #include #include +#include #include @@ -706,7 +706,7 @@ namespace MWRender { if (!mPlayerNode) { - mPlayerNode = new osg::PositionAttitudeTransform; + mPlayerNode = new SceneUtil::PositionAttitudeTransform; mPlayerNode->setNodeMask(Mask_Player); mLightRoot->addChild(mPlayerNode); } diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 3e17ef413..203df2269 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -186,7 +186,7 @@ namespace MWRender std::auto_ptr mSky; std::auto_ptr mEffectManager; std::auto_ptr mPlayerAnimation; - osg::ref_ptr mPlayerNode; + osg::ref_ptr mPlayerNode; std::auto_ptr mCamera; osg::ref_ptr mStateUpdater; diff --git a/apps/openmw/mwrender/ripplesimulation.hpp b/apps/openmw/mwrender/ripplesimulation.hpp index 1717cca57..17d5fea15 100644 --- a/apps/openmw/mwrender/ripplesimulation.hpp +++ b/apps/openmw/mwrender/ripplesimulation.hpp @@ -8,6 +8,7 @@ namespace osg { class Group; + class PositionAttitudeTransform; } namespace osgParticle diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index f65035226..592168687 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -1,6 +1,6 @@ #include -#include +#include #include diff --git a/apps/openmw/mwworld/projectilemanager.hpp b/apps/openmw/mwworld/projectilemanager.hpp index 0aa2efded..22fc4784c 100644 --- a/apps/openmw/mwworld/projectilemanager.hpp +++ b/apps/openmw/mwworld/projectilemanager.hpp @@ -4,6 +4,7 @@ #include #include +#include #include diff --git a/apps/openmw/mwworld/refdata.cpp b/apps/openmw/mwworld/refdata.cpp index 87cbc586f..8acba43df 100644 --- a/apps/openmw/mwworld/refdata.cpp +++ b/apps/openmw/mwworld/refdata.cpp @@ -108,12 +108,12 @@ namespace MWWorld {} } - void RefData::setBaseNode(osg::PositionAttitudeTransform *base) + void RefData::setBaseNode(SceneUtil::PositionAttitudeTransform *base) { mBaseNode = base; } - osg::PositionAttitudeTransform* RefData::getBaseNode() + SceneUtil::PositionAttitudeTransform* RefData::getBaseNode() { return mBaseNode; } diff --git a/apps/openmw/mwworld/refdata.hpp b/apps/openmw/mwworld/refdata.hpp index 13a71ec33..6713334d7 100644 --- a/apps/openmw/mwworld/refdata.hpp +++ b/apps/openmw/mwworld/refdata.hpp @@ -7,7 +7,7 @@ #include -namespace osg +namespace SceneUtil { class PositionAttitudeTransform; } @@ -26,7 +26,7 @@ namespace MWWorld class RefData { - osg::PositionAttitudeTransform* mBaseNode; + SceneUtil::PositionAttitudeTransform* mBaseNode; MWScript::Locals mLocals; @@ -69,10 +69,10 @@ namespace MWWorld RefData& operator= (const RefData& refData); /// Return base node (can be a null pointer). - osg::PositionAttitudeTransform* getBaseNode(); + SceneUtil::PositionAttitudeTransform* getBaseNode(); /// Set base node (can be a null pointer). - void setBaseNode (osg::PositionAttitudeTransform* base); + void setBaseNode (SceneUtil::PositionAttitudeTransform* base); int getCount() const; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index b1234c8a4..d6480b146 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -10,7 +10,6 @@ #include #include -#include #include #include @@ -22,6 +21,8 @@ #include #include +#include + #include "../mwbase/environment.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index b7865cb8a..c80e27e4d 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -41,7 +41,7 @@ add_component_dir (resource ) add_component_dir (sceneutil - clone attach lightmanager visitor util statesetupdater controller skeleton riggeometry lightcontroller + clone attach lightmanager visitor util statesetupdater controller skeleton riggeometry lightcontroller positionattitudetransform # not used yet #workqueue ) diff --git a/components/sceneutil/positionattitudetransform.cpp b/components/sceneutil/positionattitudetransform.cpp new file mode 100644 index 000000000..5f6b57e97 --- /dev/null +++ b/components/sceneutil/positionattitudetransform.cpp @@ -0,0 +1,51 @@ +#include "positionattitudetransform.hpp" + +#include + +namespace SceneUtil +{ + +PositionAttitudeTransform::PositionAttitudeTransform(): + _scale(1.0,1.0,1.0) +{ +} + +bool PositionAttitudeTransform::computeLocalToWorldMatrix(osg::Matrix& matrix, osg::NodeVisitor*) const +{ + if (_referenceFrame==RELATIVE_RF) + { + matrix.preMultTranslate(_position); + matrix.preMultRotate(_attitude); + matrix.preMultScale(_scale); + } + else // absolute + { + matrix.makeRotate(_attitude); + matrix.postMultTranslate(_position); + matrix.preMultScale(_scale); + } + return true; +} + + +bool PositionAttitudeTransform::computeWorldToLocalMatrix(osg::Matrix& matrix, osg::NodeVisitor*) const +{ + if (_scale.x() == 0.0 || _scale.y() == 0.0 || _scale.z() == 0.0) + return false; + + if (_referenceFrame==RELATIVE_RF) + { + matrix.postMultTranslate(-_position); + matrix.postMultRotate(_attitude.inverse()); + matrix.postMultScale(osg::Vec3f(1.0/_scale.x(), 1.0/_scale.y(), 1.0/_scale.z())); + } + else // absolute + { + matrix.makeRotate(_attitude.inverse()); + matrix.preMultTranslate(-_position); + matrix.postMultScale(osg::Vec3f(1.0/_scale.x(), 1.0/_scale.y(), 1.0/_scale.z())); + } + return true; +} + +} diff --git a/components/sceneutil/positionattitudetransform.hpp b/components/sceneutil/positionattitudetransform.hpp new file mode 100644 index 000000000..b6f92ee84 --- /dev/null +++ b/components/sceneutil/positionattitudetransform.hpp @@ -0,0 +1,53 @@ +#ifndef OPENMW_COMPONENTS_POSITIONATTITUDE_TRANSFORM_H +#define OPENMW_COMPONENTS_POSITIONATTITUDE_TRANSFORM_H + +#include + +namespace SceneUtil +{ + +/// @brief A customized version of osg::PositionAttitudeTransform optimized for speed. +/// Uses single precision values. Also removed _pivotPoint which we don't need. +class PositionAttitudeTransform : public osg::Transform +{ + public : + PositionAttitudeTransform(); + + PositionAttitudeTransform(const PositionAttitudeTransform& pat,const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY): + Transform(pat,copyop), + _position(pat._position), + _attitude(pat._attitude), + _scale(pat._scale){} + + + META_Node(SceneUtil, PositionAttitudeTransform) + + inline void setPosition(const osg::Vec3f& pos) { _position = pos; dirtyBound(); } + inline const osg::Vec3f& getPosition() const { return _position; } + + + inline void setAttitude(const osg::Quat& quat) { _attitude = quat; dirtyBound(); } + inline const osg::Quat& getAttitude() const { return _attitude; } + + + inline void setScale(const osg::Vec3f& scale) { _scale = scale; dirtyBound(); } + inline const osg::Vec3f& getScale() const { return _scale; } + + + + virtual bool computeLocalToWorldMatrix(osg::Matrix& matrix,osg::NodeVisitor* nv) const; + virtual bool computeWorldToLocalMatrix(osg::Matrix& matrix,osg::NodeVisitor* nv) const; + + + protected : + + virtual ~PositionAttitudeTransform() {} + + osg::Vec3f _position; + osg::Quat _attitude; + osg::Vec3f _scale; +}; + +} + +#endif diff --git a/components/terrain/terraingrid.cpp b/components/terrain/terraingrid.cpp index ceb39a24b..aa82e0bd6 100644 --- a/components/terrain/terraingrid.cpp +++ b/components/terrain/terraingrid.cpp @@ -6,10 +6,10 @@ #include #include +#include #include -#include #include #include #include @@ -91,7 +91,7 @@ osg::ref_ptr TerrainGrid::buildTerrain (osg::Group* parent, float chu return NULL; // no terrain defined osg::Vec2f worldCenter = chunkCenter*mStorage->getCellWorldSize(); - osg::ref_ptr transform (new osg::PositionAttitudeTransform); + osg::ref_ptr transform (new SceneUtil::PositionAttitudeTransform); transform->setPosition(osg::Vec3f(worldCenter.x(), worldCenter.y(), 0.f)); if (parent) From ffea9ec2c43441de73a0b07c98c7d5330c580f62 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 21 Nov 2015 04:13:25 +0100 Subject: [PATCH 2521/3725] Remove comment SharedStateManager::prune is run automatically during the update traversal. --- components/resource/scenemanager.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index d5b0088d3..cd3aeb3d6 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -206,7 +206,6 @@ namespace Resource } osgDB::Registry::instance()->getOrCreateSharedStateManager()->share(loaded.get()); - // TODO: run SharedStateManager::prune on unload if (mIncrementalCompileOperation) mIncrementalCompileOperation->add(loaded); From fc7456e0a10e31c03057d2b46974c1b05efe218f Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 21 Nov 2015 23:35:56 +0100 Subject: [PATCH 2522/3725] Explicitely opt for float matrices in performance critical places --- components/nifosg/particle.cpp | 2 +- components/resource/scenemanager.cpp | 2 +- components/sceneutil/lightmanager.cpp | 4 ++-- components/sceneutil/lightmanager.hpp | 4 ++-- components/sceneutil/util.cpp | 2 +- components/sceneutil/util.hpp | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/components/nifosg/particle.cpp b/components/nifosg/particle.cpp index 68f3de8aa..e30837d39 100644 --- a/components/nifosg/particle.cpp +++ b/components/nifosg/particle.cpp @@ -49,7 +49,7 @@ void InverseWorldMatrix::operator()(osg::Node *node, osg::NodeVisitor *nv) osg::Matrix mat = osg::computeLocalToWorld( path ); mat.orthoNormalize(mat); // don't undo the scale - mat = osg::Matrix::inverse(mat); + mat.invert(mat); trans->setMatrix(mat); } traverse(node,nv); diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index cd3aeb3d6..b2ba5c4cf 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -82,7 +82,7 @@ namespace osg::MatrixList mats = node->getWorldMatrices(); if (mats.empty()) return; - osg::Matrix worldMat = mats[0]; + osg::Matrixf worldMat = mats[0]; worldMat.orthoNormalize(worldMat); // scale is already applied on the particle node for (int i=0; inumParticles(); ++i) { diff --git a/components/sceneutil/lightmanager.cpp b/components/sceneutil/lightmanager.cpp index d3e11050d..43f11cf00 100644 --- a/components/sceneutil/lightmanager.cpp +++ b/components/sceneutil/lightmanager.cpp @@ -164,7 +164,7 @@ namespace SceneUtil mStateSetCache.clear(); } - void LightManager::addLight(LightSource* lightSource, osg::Matrix worldMat) + void LightManager::addLight(LightSource* lightSource, osg::Matrixf worldMat) { LightSourceTransform l; l.mLightSource = lightSource; @@ -221,7 +221,7 @@ namespace SceneUtil for (std::vector::iterator lightIt = mLights.begin(); lightIt != mLights.end(); ++lightIt) { - osg::Matrix worldViewMat = lightIt->mWorldMatrix * (*viewMatrix); + osg::Matrixf worldViewMat = lightIt->mWorldMatrix * (*viewMatrix); osg::BoundingSphere viewBound = osg::BoundingSphere(osg::Vec3f(0,0,0), lightIt->mLightSource->getRadius()); transformBoundingSphere(worldViewMat, viewBound); diff --git a/components/sceneutil/lightmanager.hpp b/components/sceneutil/lightmanager.hpp index 27ee1cdaa..ecee873e8 100644 --- a/components/sceneutil/lightmanager.hpp +++ b/components/sceneutil/lightmanager.hpp @@ -77,12 +77,12 @@ namespace SceneUtil void update(); // Called automatically by the LightSource's UpdateCallback - void addLight(LightSource* lightSource, osg::Matrix worldMat); + void addLight(LightSource* lightSource, osg::Matrixf worldMat); struct LightSourceTransform { LightSource* mLightSource; - osg::Matrix mWorldMatrix; + osg::Matrixf mWorldMatrix; }; const std::vector& getLights() const; diff --git a/components/sceneutil/util.cpp b/components/sceneutil/util.cpp index 52f9c9e54..3add3bb23 100644 --- a/components/sceneutil/util.cpp +++ b/components/sceneutil/util.cpp @@ -3,7 +3,7 @@ namespace SceneUtil { -void transformBoundingSphere (const osg::Matrix& matrix, osg::BoundingSphere& bsphere) +void transformBoundingSphere (const osg::Matrixf& matrix, osg::BoundingSphere& bsphere) { osg::BoundingSphere::vec_type xdash = bsphere._center; xdash.x() += bsphere._radius; diff --git a/components/sceneutil/util.hpp b/components/sceneutil/util.hpp index c99771c5e..d8fefdb29 100644 --- a/components/sceneutil/util.hpp +++ b/components/sceneutil/util.hpp @@ -11,7 +11,7 @@ namespace SceneUtil // Transform a bounding sphere by a matrix // based off private code in osg::Transform // TODO: patch osg to make public - void transformBoundingSphere (const osg::Matrix& matrix, osg::BoundingSphere& bsphere); + void transformBoundingSphere (const osg::Matrixf& matrix, osg::BoundingSphere& bsphere); osg::Vec4f colourFromRGB (unsigned int clr); From 75a464f7ec1abad4957c07ad014f3035d1429180 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 22 Nov 2015 18:43:13 +0100 Subject: [PATCH 2523/3725] Fix a typo --- components/sceneutil/riggeometry.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/sceneutil/riggeometry.cpp b/components/sceneutil/riggeometry.cpp index 023ac12d5..bd24ba785 100644 --- a/components/sceneutil/riggeometry.cpp +++ b/components/sceneutil/riggeometry.cpp @@ -185,7 +185,7 @@ bool RigGeometry::initFromParentSkeleton(osg::NodeVisitor* nv) return true; } -void accummulateMatrix(const osg::Matrixf& invBindMatrix, const osg::Matrixf& matrix, float weight, osg::Matrixf& result) +void accumulateMatrix(const osg::Matrixf& invBindMatrix, const osg::Matrixf& matrix, float weight, osg::Matrixf& result) { osg::Matrixf m = invBindMatrix * matrix; float* ptr = m.ptr(); @@ -246,7 +246,7 @@ void RigGeometry::update(osg::NodeVisitor* nv) const osg::Matrix& invBindMatrix = weightIt->first.second; float weight = weightIt->second; const osg::Matrixf& boneMatrix = bone->mMatrixInSkeletonSpace; - accummulateMatrix(invBindMatrix, boneMatrix, weight, resultMat); + accumulateMatrix(invBindMatrix, boneMatrix, weight, resultMat); } resultMat = resultMat * geomToSkel; From 6d5aa272fc50e0410cbcabdf7109daf9bd739b91 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 22 Nov 2015 19:49:11 +0100 Subject: [PATCH 2524/3725] RigGeometry: do not update the geomToSkelMatrix more than once per frame --- components/sceneutil/riggeometry.cpp | 14 ++++++-------- components/sceneutil/riggeometry.hpp | 4 +++- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/components/sceneutil/riggeometry.cpp b/components/sceneutil/riggeometry.cpp index bd24ba785..2de6bc1ad 100644 --- a/components/sceneutil/riggeometry.cpp +++ b/components/sceneutil/riggeometry.cpp @@ -224,8 +224,6 @@ void RigGeometry::update(osg::NodeVisitor* nv) mSkeleton->updateBoneMatrices(nv); - osg::Matrixf geomToSkel = getGeomToSkelMatrix(nv); - // skinning osg::Vec3Array* positionSrc = static_cast(mSourceGeometry->getVertexArray()); osg::Vec3Array* normalSrc = static_cast(mSourceGeometry->getNormalArray()); @@ -248,7 +246,7 @@ void RigGeometry::update(osg::NodeVisitor* nv) const osg::Matrixf& boneMatrix = bone->mMatrixInSkeletonSpace; accumulateMatrix(invBindMatrix, boneMatrix, weight, resultMat); } - resultMat = resultMat * geomToSkel; + resultMat = resultMat * mGeomToSkelMatrix; for (std::vector::const_iterator vertexIt = it->second.begin(); vertexIt != it->second.end(); ++vertexIt) { @@ -276,13 +274,14 @@ void RigGeometry::updateBounds(osg::NodeVisitor *nv) mSkeleton->updateBoneMatrices(nv); - osg::Matrixf geomToSkel = getGeomToSkelMatrix(nv); + updateGeomToSkelMatrix(nv); + osg::BoundingBox box; for (BoneSphereMap::const_iterator it = mBoneSphereMap.begin(); it != mBoneSphereMap.end(); ++it) { Bone* bone = it->first; osg::BoundingSpheref bs = it->second; - transformBoundingSphere(bone->mMatrixInSkeletonSpace * geomToSkel, bs); + transformBoundingSphere(bone->mMatrixInSkeletonSpace * mGeomToSkelMatrix, bs); box.expandBy(bs); } @@ -297,7 +296,7 @@ void RigGeometry::updateBounds(osg::NodeVisitor *nv) getParent(i)->dirtyBound(); } -osg::Matrixf RigGeometry::getGeomToSkelMatrix(osg::NodeVisitor *nv) +void RigGeometry::updateGeomToSkelMatrix(osg::NodeVisitor *nv) { osg::NodePath path; bool foundSkel = false; @@ -311,8 +310,7 @@ osg::Matrixf RigGeometry::getGeomToSkelMatrix(osg::NodeVisitor *nv) else path.push_back(*it); } - return osg::computeWorldToLocal(path); - + mGeomToSkelMatrix = osg::computeWorldToLocal(path); } void RigGeometry::setInfluenceMap(osg::ref_ptr influenceMap) diff --git a/components/sceneutil/riggeometry.hpp b/components/sceneutil/riggeometry.hpp index e51fc0cf6..0a39fcde2 100644 --- a/components/sceneutil/riggeometry.hpp +++ b/components/sceneutil/riggeometry.hpp @@ -48,6 +48,8 @@ namespace SceneUtil osg::ref_ptr mSourceGeometry; Skeleton* mSkeleton; + osg::Matrixf mGeomToSkelMatrix; + osg::ref_ptr mInfluenceMap; typedef std::pair BoneBindMatrixPair; @@ -69,7 +71,7 @@ namespace SceneUtil bool initFromParentSkeleton(osg::NodeVisitor* nv); - osg::Matrixf getGeomToSkelMatrix(osg::NodeVisitor* nv); + void updateGeomToSkelMatrix(osg::NodeVisitor* nv); }; } From 94e8560bf811a9fdab641da9a1741161a854dd71 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 22 Nov 2015 19:58:21 +0100 Subject: [PATCH 2525/3725] RigGeometry: do not allocate new NodePath every frame --- components/sceneutil/riggeometry.cpp | 6 +++--- components/sceneutil/riggeometry.hpp | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/components/sceneutil/riggeometry.cpp b/components/sceneutil/riggeometry.cpp index 2de6bc1ad..0006c947e 100644 --- a/components/sceneutil/riggeometry.cpp +++ b/components/sceneutil/riggeometry.cpp @@ -298,7 +298,7 @@ void RigGeometry::updateBounds(osg::NodeVisitor *nv) void RigGeometry::updateGeomToSkelMatrix(osg::NodeVisitor *nv) { - osg::NodePath path; + mSkelToGeomPath.clear(); bool foundSkel = false; for (osg::NodePath::const_iterator it = nv->getNodePath().begin(); it != nv->getNodePath().end(); ++it) { @@ -308,9 +308,9 @@ void RigGeometry::updateGeomToSkelMatrix(osg::NodeVisitor *nv) foundSkel = true; } else - path.push_back(*it); + mSkelToGeomPath.push_back(*it); } - mGeomToSkelMatrix = osg::computeWorldToLocal(path); + mGeomToSkelMatrix = osg::computeWorldToLocal(mSkelToGeomPath); } void RigGeometry::setInfluenceMap(osg::ref_ptr influenceMap) diff --git a/components/sceneutil/riggeometry.hpp b/components/sceneutil/riggeometry.hpp index 0a39fcde2..f61fe62e7 100644 --- a/components/sceneutil/riggeometry.hpp +++ b/components/sceneutil/riggeometry.hpp @@ -48,6 +48,7 @@ namespace SceneUtil osg::ref_ptr mSourceGeometry; Skeleton* mSkeleton; + osg::NodePath mSkelToGeomPath; osg::Matrixf mGeomToSkelMatrix; osg::ref_ptr mInfluenceMap; From 28b20428b9ab8d185067dd9e14844f102f9ce795 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 22 Nov 2015 20:33:22 +0100 Subject: [PATCH 2526/3725] Remove dynamic_cast in GeomMorpherController --- components/nifosg/controller.cpp | 33 +++++++++++++++----------------- components/nifosg/controller.hpp | 1 + 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index bb698ed63..8f8b5003c 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -221,28 +221,25 @@ GeomMorpherController::GeomMorpherController(const Nif::NiMorphData *data) void GeomMorpherController::update(osg::NodeVisitor *nv, osg::Drawable *drawable) { - osgAnimation::MorphGeometry* morphGeom = dynamic_cast(drawable); - if (morphGeom) + osgAnimation::MorphGeometry* morphGeom = static_cast(drawable); + if (hasInput()) { - if (hasInput()) + if (mKeyFrames.size() <= 1) + return; + float input = getInputValue(nv); + int i = 0; + for (std::vector::iterator it = mKeyFrames.begin()+1; it != mKeyFrames.end(); ++it,++i) { - if (mKeyFrames.size() <= 1) - return; - float input = getInputValue(nv); - int i = 0; - for (std::vector::iterator it = mKeyFrames.begin()+1; it != mKeyFrames.end(); ++it,++i) - { - float val = 0; - if (!(*it)->mKeys.empty()) - val = interpKey((*it)->mKeys, input); - val = std::max(0.f, std::min(1.f, val)); - - morphGeom->setWeight(i, val); - } - } + float val = 0; + if (!(*it)->mKeys.empty()) + val = interpKey((*it)->mKeys, input); + val = std::max(0.f, std::min(1.f, val)); - morphGeom->transformSoftwareMethod(); + morphGeom->setWeight(i, val); + } } + + morphGeom->transformSoftwareMethod(); } UVController::UVController() diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index d0c6d1de3..803ce77a2 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -97,6 +97,7 @@ namespace NifOsg virtual float getMaximum() const; }; + /// Must be set on an osgAnimation::MorphGeometry. class GeomMorpherController : public osg::Drawable::UpdateCallback, public SceneUtil::Controller, public ValueInterpolator { public: From 0d49c7fa517bad02387112c916a2a8c648742903 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 22 Nov 2015 21:19:02 +0100 Subject: [PATCH 2527/3725] GeomMorpherController: fix double update of MorphGeometry --- components/nifosg/controller.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index 8f8b5003c..4dfa4b304 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -239,7 +239,7 @@ void GeomMorpherController::update(osg::NodeVisitor *nv, osg::Drawable *drawable } } - morphGeom->transformSoftwareMethod(); + // morphGeometry::transformSoftwareMethod() done in cull callback i.e. only for visible morph geometries } UVController::UVController() From 38510a56c206520472e505c7fca24f6f3b6275e5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 22 Nov 2015 21:19:55 +0100 Subject: [PATCH 2528/3725] GeomMorpherController: do not dirty the MorphGeometry unless necessary --- components/nifosg/controller.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index 4dfa4b304..93c1de89a 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -235,7 +235,12 @@ void GeomMorpherController::update(osg::NodeVisitor *nv, osg::Drawable *drawable val = interpKey((*it)->mKeys, input); val = std::max(0.f, std::min(1.f, val)); - morphGeom->setWeight(i, val); + osgAnimation::MorphGeometry::MorphTarget& target = morphGeom->getMorphTarget(i); + if (target.getWeight() != val) + { + target.setWeight(val); + morphGeom->dirty(); + } } } From 71cd57a3b54b34b1fa7aa606e5f05aba5e9726e0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 22 Nov 2015 22:13:21 +0100 Subject: [PATCH 2529/3725] Optimize World::getTimeStamp World::getTimeStamp was searching through the globals store on every call. Not a big issue, but slow enough to show up in the profiler. --- apps/openmw/mwworld/worldimp.cpp | 60 +++++++++++++++++++------------- apps/openmw/mwworld/worldimp.hpp | 9 +++++ 2 files changed, 44 insertions(+), 25 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index d6480b146..6f63605c7 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -138,8 +138,7 @@ namespace MWWorld { if (mSky && (isCellExterior() || isCellQuasiExterior())) { - mRendering->skySetDate (mGlobalVariables["day"].getInteger(), - mGlobalVariables["month"].getInteger()); + mRendering->skySetDate (mDay->getInteger(), mMonth->getInteger()); mRendering->setSkyEnabled(true); } @@ -188,18 +187,30 @@ namespace MWWorld if (mEsm[0].getFormat() == 0) ensureNeededRecords(); + fillGlobalVariables(); + mStore.setUp(); mStore.movePlayerRecord(); mSwimHeightScale = mStore.get().find("fSwimHeightScale")->getFloat(); - mGlobalVariables.fill (mStore); - mWeatherManager = new MWWorld::WeatherManager(*mRendering, mFallback, mStore); mWorldScene = new Scene(*mRendering, mPhysics); } + void World::fillGlobalVariables() + { + mGlobalVariables.fill (mStore); + + mGameHour = &mGlobalVariables["gamehour"]; + mDaysPassed = &mGlobalVariables["dayspassed"]; + mDay = &mGlobalVariables["day"]; + mMonth = &mGlobalVariables["month"]; + mYear = &mGlobalVariables["year"]; + mTimeScale = &mGlobalVariables["timescale"]; + } + void World::startNewGame (bool bypass) { mGoToJail = false; @@ -306,7 +317,7 @@ namespace MWWorld mTeleportEnabled = true; mLevitationEnabled = true; - mGlobalVariables.fill (mStore); + fillGlobalVariables(); } int World::countSavedGameRecords() const @@ -798,15 +809,15 @@ namespace MWWorld mWeatherManager->advanceTime (hours, incremental); - hours += mGlobalVariables["gamehour"].getFloat(); + hours += mGameHour->getFloat(); setHour (hours); int days = static_cast(hours / 24); if (days>0) - mGlobalVariables["dayspassed"].setInteger ( - days + mGlobalVariables["dayspassed"].getInteger()); + mDaysPassed->setInteger ( + days + mDaysPassed->getInteger()); } void World::setHour (double hour) @@ -818,10 +829,10 @@ namespace MWWorld hour = std::fmod (hour, 24); - mGlobalVariables["gamehour"].setFloat(static_cast(hour)); + mGameHour->setFloat(static_cast(hour)); if (days>0) - setDay (days + mGlobalVariables["day"].getInteger()); + setDay (days + mDay->getInteger()); } void World::setDay (int day) @@ -829,7 +840,7 @@ namespace MWWorld if (day<1) day = 1; - int month = mGlobalVariables["month"].getInteger(); + int month = mMonth->getInteger(); while (true) { @@ -844,14 +855,14 @@ namespace MWWorld else { month = 0; - mGlobalVariables["year"].setInteger (mGlobalVariables["year"].getInteger()+1); + mYear->setInteger(mYear->getInteger()+1); } day -= days; } - mGlobalVariables["day"].setInteger (day); - mGlobalVariables["month"].setInteger (month); + mDay->setInteger(day); + mMonth->setInteger(month); mRendering->skySetDate(day, month); } @@ -866,30 +877,30 @@ namespace MWWorld int days = getDaysPerMonth (month); - if (mGlobalVariables["day"].getInteger()>days) - mGlobalVariables["day"].setInteger (days); + if (mDay->getInteger()>days) + mDay->setInteger (days); - mGlobalVariables["month"].setInteger (month); + mMonth->setInteger (month); if (years>0) - mGlobalVariables["year"].setInteger (years+mGlobalVariables["year"].getInteger()); + mYear->setInteger (years+mYear->getInteger()); - mRendering->skySetDate (mGlobalVariables["day"].getInteger(), month); + mRendering->skySetDate (mDay->getInteger(), month); } int World::getDay() const { - return mGlobalVariables["day"].getInteger(); + return mDay->getInteger(); } int World::getMonth() const { - return mGlobalVariables["month"].getInteger(); + return mMonth->getInteger(); } int World::getYear() const { - return mGlobalVariables["year"].getInteger(); + return mYear->getInteger(); } std::string World::getMonthName (int month) const @@ -914,8 +925,7 @@ namespace MWWorld TimeStamp World::getTimeStamp() const { - return TimeStamp (mGlobalVariables["gamehour"].getFloat(), - mGlobalVariables["dayspassed"].getInteger()); + return TimeStamp (mGameHour->getFloat(), mDaysPassed->getInteger()); } bool World::toggleSky() @@ -942,7 +952,7 @@ namespace MWWorld float World::getTimeScaleFactor() const { - return mGlobalVariables["timescale"].getFloat(); + return mTimeScale->getFloat(); } void World::changeToInteriorCell (const std::string& cellName, const ESM::Position& position) diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 72093d281..92027868e 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -85,6 +85,13 @@ namespace MWWorld MWPhysics::PhysicsSystem *mPhysics; bool mSky; + ESM::Variant* mGameHour; + ESM::Variant* mDaysPassed; + ESM::Variant* mDay; + ESM::Variant* mMonth; + ESM::Variant* mYear; + ESM::Variant* mTimeScale; + Cells mCells; std::string mCurrentWorldSpace; @@ -135,6 +142,8 @@ namespace MWWorld void ensureNeededRecords(); + void fillGlobalVariables(); + /** * @brief loadContentFiles - Loads content files (esm,esp,omwgame,omwaddon) * @param fileCollections- Container which holds content file names and their paths From 7b64b35eb3eea82911763a7eff67761fcd37c377 Mon Sep 17 00:00:00 2001 From: cfcohen Date: Sun, 22 Nov 2015 19:28:09 -0500 Subject: [PATCH 2530/3725] Added comments (and commentary) to the settings-default.cfg file. --- files/settings-default.cfg | 779 +++++++++++++++++++++++++++++-------- 1 file changed, 622 insertions(+), 157 deletions(-) diff --git a/files/settings-default.cfg b/files/settings-default.cfg index d68bc2fef..2c71f483a 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -1,244 +1,709 @@ -# WARNING: Editing this file might have no effect, as these -# settings are overwritten by your user settings file. +# WARNING: Editing this file might have no effect, as these settings +# are overwritten by your user settings file. Your user settings file +# varies with your operating system: +# +# Linux: $HOME/.config/openmw +# Mac: $HOME/Library/Preferences/openmw +# Windows: C:\Users\Username\Documents\my games\openmw +# This path may vary depending on your installation hard drive, your +# Windows username, and your default language. +# +# Additionally, the user settings file is often written to disk when +# exiting OpenMW, so comments and changes to that file may also be +# discarded after running OpenMW. While most changes to the file will +# reflect setting changes made in game, some settings can have a wider +# range of values in the settings file than the GUI settings widgets +# allow. You may want to exercise some caution and backup this file +# when editing it by hand. -[Video] -resolution x = 800 -resolution y = 600 - -fullscreen = false -window border = true -screen = 0 - -# Minimize the window if it loses key focus? -minimize on focus loss = true +[Camera] -# Valid values: 0 for no antialiasing, or any power of two -antialiasing = 0 +# This floating point setting controls the distance to the near +# clipping plane. The value must be greater than zero. Values +# greater than approximately 18.0 will occasionally clip objects in +# the world in front of the character. Values greater than +# approximately 8.0 will clip the character's hands in first person +# view and/or the back of their head in third person view. +near clip = 5.0 + +# This boolean setting determines whether objects that render to one +# pixel or smaller will be culled. It generally improves performance +# to enable this feature. +small feature culling = true -vsync = false +# Set the maximum visible distance. Larger values significantly +# improve rendering in exterior spaces, but also increase the amount +# rendered geometry and significantly reduce the frame rate. This +# value is a floating point value that defaults to 6666.0. This value +# interacts with the "exterior cell load distance" setting in that +# it's probably undesired for this value to provide visibility into +# cells that have not yet been loaded. When cells are visible before +# loading, the geometry will "pop-in" suddenly, creating a jarring +# visual effect. To prevent this effect, this value must be less +# than: +# +# 8192 * exterior cell load distance - 1024 +# +# The constant 8192 is the size of a cell, and 1024 is the threshold +# distance for loading a new cell. Additionally, the "field of view" +# setting also interacts with this setting because the view frustrum +# end is a plane, so you can see further at the edges of the screen +# than you should be able to. This can be observed in game by looking +# at distant objects and rotating the camera so the object are near +# the edge of the screen. As a result, the "viewing distance" setting +# should further be reduced by a factor that depends on the "field of +# view" setting. In the default configuration this reduction is 7%. +# Using this factor, approximate values recommended for other +# "exterior cell load distance" settings are: 14285 for 2 cells, 21903 +# for 3 cells, 29522 for 4 cells, and 35924 for 5 cells. +# +# Reductions of up 25% or more can be required to completely eliminate +# pop-in for wide fields of view and long viewing distances near the +# edges of the screen, but such situations are unusual and probably +# not worth the performance penalty introduced by loading geometry +# obscured by fog in the center of the screen. +# +# This setting can be adjusted in game from the ridiculously low value +# of 2000 to a maximum of 6666, using the "View Distance" slider in +# the Detail tab of the Video panel of the Options menu. See +# RenderingManager::configureFog for the relevant source code. +viewing distance = 6666.0 -gamma = 1.00 -contrast = 1.00 +[Cells] -# Maximum framerate in frames per second, 0 = unlimited -framerate limit = 0 +# This integer setting determines the number of exterior cells +# adjacent to the character that will be loaded for rendering. It +# interacts with "viewing distance" and "field of view" as described +# previously, and it is generally very wasteful for this value to load +# geometry than will almost never be visible due to viewing distance +# and fog. For low frame rate screenshots of scenic vistas, this +# setting should be set high, and viewing distances adjusted +# accordingly. This value must be greater than or equal to 1. +exterior cell load distance = 1 [GUI] -scaling factor = 1.0 -# 1 is fully opaque +# These two settings determine the background color of the tool tip +# and the crosshair when hovering over an item owned by an NPC. The +# color definitions are composed of four floating point values between +# 0.0 and 1.0 inclusive, representing the red, green, blue and alpha +# channels. The alpha value is currently ignored. The crosshair +# color will have no effect if the "crosshair" setting in the HUD +# section is disabled. These colors are used only if the "show owned" +# setting is enabled in the Game section. +color background owned = 0.15 0.0 0.0 1.0 +color crosshair owned = 1.0 0.15 0.15 1.0 + +# This boolean setting enables or disables the "red flash" overlay +# that provides a visual clue when the character has taken damage. +hit fader = true + +# This floating point setting controls the transparency of the GUI +# windows. The value should be between 0.0 (transparent) and 1.0 +# (opaque). The setting can be adjusted in game with the "Menu +# Transparency" slider in the Prefs panel of the Options menu. menu transparency = 0.84 -# 0 - instantly, 1 - max. delay -tooltip delay = 0 +# This floating point setting scales the GUI interface windows. The +# value must be greater than 0.0. A value of 1.0 results in the +# default scale. Values much larger than 2.0 may result in user +# interface components being inaccessible. +scaling factor = 1.0 + +# Stretch or shrink the introductory movie, new game screen, and +# loading screens to fill the specified video resolution. The default +# assets have a 4:3 aspect ratio, but other assets may have other +# resolutions. If this setting is false, the assets will be centered +# in their correct aspect ratio. +stretch menu background = false +# Enable or disable subtitles for NPC spoken dialog (and some sound +# effects). Subtitles will appear in a tool tip box in the lower +# center of the screen. The setting can be toggled in game with the +# "Subtitles" button in the Prefs panel of Options menu. subtitles = false -hit fader = true +# Set the delay between when you begin hovering over an item and when +# it's tooltip appears. This setting is a floating point value +# between 0.0, which displays the tool tip instantly and 1.0 which +# results in the maximum delay (approximately 1.5 seconds). This +# setting does not affect the tooltip delay for object under the +# crosshair in the "look mode", only widgets in the GUI windows. This +# setting can be adjusted in game with the "Menu Help Delay" slider in +# the Prefs panel of the Options menu. +tooltip delay = 0.0 + +# Enable or disable the werewolf overlay. Unable to evaluate fully +# due to issues with becoming a werewolf. werewolf overlay = true -stretch menu background = false +[Game] -# colour definitions (red green blue alpha) -color background owned = 0.15 0 0 1 -color crosshair owned = 1 0.15 0.15 1 +# If this boolean setting is true, the character will always use the +# most powerful attack when striking with a weapon (chop, slash or +# thrust). If this setting is false, the type of attack is determined +# by the direction that the character is moving at the time the attack +# begins. The setting can be toggled with the "Always Use Best +# Attack" button in the Prefs panel of the Options menu. +best attack = false -[General] -# Camera field of view -field of view = 55 +# This integer setting adjusts the difficulty of the game and is +# intended to be in the range -100 to 100 inclusive. Given the +# default game setting for fDifficultyMult of 5.0, a value of -100 +# results in the player taking 80% of the usual damage, doing 6 times +# the normal damage. A value of 100 results in the player taking 6 +# times as much damage, but inflicting only 80% of the usual damage. +# Values less than -500 will result in the player receiving no damage, +# and values greater than 500 will result in the player inflicting no +# damage. The setting can be controlled in game with the Difficulty +# slider in the Prefs panel of the Options menu. +difficulty = 0 + +# Show the remaining duration of magic effects and lights if this +# boolean setting is true. The remaining duration is displayed in the +# tooltip by hovering over the magical effect. +show effect duration = false -# Texture filtering mode. valid values: -# bilinear -# trilinear -texture filtering = +# Enable visual clues for items owned by NPCs when the crosshair is on +# the object. If the setting is 0, no clues are provided which is the +# default Morrowind behavior. If the setting is 1, the background of +# the tool tip for the object is highlight in the color specified by +# the "color background owned" setting in the "GUI" section. If the +# setting is 2, the crosshair is the color of the "color crosshair +# owned" setting in the "GUI" section. If the setting is 3, both the +# tool tip background and the crosshair are colored. Settings 2 and 3 +# only color the crosshair if it's enabled in the "HUD" section. +show owned = 0 +[General] + +# Set the maximum anisotropic filtering on textures. Anisotropic +# filtering is a method of enhancing the image quality of textures on +# surfaces that are at oblique viewing angles with respect to the +# camera. Valid values range from 0 to 16. Modern video cards can +# often perform 8 or 16 anisotropic filtering with a minimal +# performance impact. This effect of this setting can be seen in the +# Video panel of the Options menu by finding a location with straight +# lines (striped rugs and Balmora cobblestones work well) radiating +# into the distance, and adjusting the anisotropy slider. This +# setting can be changed in game using the "Anisotropy" slider in the +# Detail tab of the Video panel of the Options menu. anisotropy = 4 +# Sets the camera field of view in degrees. Recommended values range +# from 30 degrees to 110 degrees. Small values provide a very narrow +# field of view that creates a "zoomed in" effect, while large values +# cause distortion at the edges of the screen. The "field of view" +# setting interacts with aspect ratio of your video resolution in that +# more square aspect ratios (e.g. 4:3) need a wider field of view to +# more resemble the same field of view on a widescreen (e.g. 16:9) +# monitor. This setting can be adjusted in game from the Video tab of +# the Video panel of the Options menu using the "Field of View" +# slider. +field of view = 55.0 + +# Specify the format for screenshots taken by pressing F12. This +# setting should be the file extension commonly associated with the +# desired format. The formats supported will be determined at +# compilation, but "jpg", "png", and "tga" should be allowed. screenshot format = png -[Shadows] -# Shadows are only supported when object shaders are on! -enabled = false +# Set the isotropic texture filtering mode to bilinear or trilinear. +# Bilinear filtering is a texture filtering method used to smooth +# textures when displayed larger or smaller than they actually are. +# Bilinear filtering is reasonably accurate until the scaling of the +# texture gets below half or above double the original size of the +# texture. Trilinear filtering is an extension of the bilinear +# texture filtering method, which also performs linear interpolation +# between mipmaps. Both methods use mipmaps in OpenMW, and the +# corresponding OpenGL modes are LINEAR_MIPMAP_NEAREST and +# LINEAR_MIPMAP_LINEAR. Trilinear filtering produces better texturing +# at a minimal cost on modern video cards. This setting can be +# changed in game using the "Texture filtering" pull down in the +# Detail tab of the Video panel of the Options menu. +texture filtering = trilinear -# Split the shadow maps, allows for a larger shadow distance -split = false +[HUD] -# Increasing shadow distance will lower the shadow quality. -# Uses "shadow distance" or "split shadow distance" depending on "split" setting. -shadow distance = 1300 -# This one shouldn't be too low, otherwise you'll see artifacts. Use at least 2x max viewing distance. -split shadow distance = 14000 +# This boolean setting determines whether the crosshair or reticle is +# displayed. If this setting is disabled it will override "show +# owned" and "color crosshair owned". This setting can be toggled +# with the "Crosshair" button in the Prefs panel of the Options menu. +crosshair = true -# Size of the shadow textures, higher means higher quality -texture size = 1024 +[Input] -# Turn on/off various shadow casters -actor shadows = true -misc shadows = true -statics shadows = true -terrain shadows = true +# Allow zooming in and out using the middle mouse wheel in third +# person view. +allow third person zoom = false -# Fraction of the total shadow distance after which the shadow starts to fade out -fade start = 0.8 +# If this boolean setting is true, the character is running by +# default, otherwise the character is walking by default. The shift +# key will temporarily invert this setting, and the caps lock key will +# invert this setting while it's "locked". Confusingly, this setting +# is updated every time you exit the game, based on whether the caps +# lock key was on or off at the time you exited. +always run = false -debug = false +# This floating point setting controls the camera/mouse sensitivity +# when in "look mode". The default sensitivity is 1.0, with smaller +# values requiring more mouse movement, and larger values requiring +# less. This setting is multiplicative in magnitude. This setting +# does not affect mouse speed in GUI mode. +camera sensitivity = 1.0 -[HUD] -crosshair = true +# This floating point setting controls the vertical camera/mouse +# sensitivity relative to the horizontal sensitivity (see "camera +# sensitivity") above. It is multiplicative with the previous +# setting, meaning that it should remain set at 1.0 unless the player +# desires to have different sensitivities in the two axes. +camera y multiplier = 1.0 -[Objects] -shaders = true +# OpenMW will capture control of the cursor if this boolean setting is +# true. In "look mode", OpenMW will capture the cursor regardless of +# the value of this setting (since the cursor/crosshair is always +# centered in the OpenMW window). However, in GUI mode, this setting +# determines the behavior when the cursor is moved outside the OpenMW +# window. If true, the cursor movement stops at the edge of the +# window preventing access to other applications. If false, the +# cursor is allowed to move freely on the desktop. +# +# This setting does not apply to the screen where escape has been +# pressed, where the cursor is never captured. Regardless of this +# setting "Alt-Tab" or some other operating system dependent key +# sequence can be used to allow the operating system to regain control +# of the mouse cursor. This setting interacts with the "minimize on +# focus loss" setting by affecting what counts as a focus loss. +# Specifically on a two-screen configuration it may be more convenient +# to access the second screen with setting disabled. +grab cursor = true + +# Invert the vertical axis while in "look mode". If this setting is +# true, moving the mouse away from the player will look down, while +# moving it towards the player will look up. This setting does not +# affect cursor movement in GUI mode. +invert y axis = false + +# This boolean setting causes the behavior of the sneak key (Ctrl by +# default) to toggle sneaking on and off rather than requiring the key +# to be held while sneaking. Players that spend significant time +# sneaking may find the character easier to control with this option +# enabled. +toggle sneak = false + +# This setting continues to be loaded and saved, but has no known +# effect. Presumably it and a related but also removed option named +# "ui y sensitivity" used to control mouse sensitivity while in GUI +# mode. The default value is 1.0. +ui sensitivity = 1.0 [Map] -# Adjusts the scale of the global map + +# It is not currently possible to control how many adjacent cells are +# displayed in the map. It appears that this is hardcoded to one +# adjacent cell (3x3) in the code. These settings control the canvas +# and resolution sizes, and therefore the amount of panning required +# to see the entire map, and the level of detail visible. + +# This integer setting adjusts the scale of the world map in the GUI +# mode map display. The value is the width in pixels of each cell in +# the map, so larger values result in larger more detailed world maps, +# while smaller values result in smaller less detailed world maps. +# However, the native resolution of the map source material appears to +# be 9 pixels per unexplored cell and approximately 18 pixels per +# explored cell, so values larger than 36 don't produce much +# additional detail. Similarly, the size of place markers is +# currently fixed at 12 pixels, so values smaller than this result in +# overlapping place markers. Values from 12 to 36 are recommended. +# For reference, Vvardenfell is approximately 41x36 cells. global map cell size = 18 +# This integer setting controls the zoom level for the HUD map display +# (the map in the lower right corner while not in GUI mode). A value +# of 64 results in the HUD map displaying one exterior cell. Since +# the GUI mode map displays 3x3 cells, a value of approximately 21 +# displays the same area as the GUI mode map. Larger values increase +# the level of zoom, while smaller values are wasteful. +# +# Note that the actual size of the widget is always the same on the +# screen unless the "scaling factor" setting in the "GUI" section is +# changed. Increasing both the scaling factor of the GUI and this +# setting does result in a higher resolution HUD map, but +# unfortunately with a scaled direction pointer on top of it. +local map hud widget size = 256 + +# This integer setting controls the resolution of the GUI mode local +# map widget. Larger values generally increase the visible detail in +# map. If this setting is half the "local map widget size" or +# smaller, the map will generally be be fairly blurry. Setting the +# both options to the same value results in a map with good detail. +# Values that exceed the "local map widget size" setting by more than +# a factor of two are unlikely to provide much of an improvement in +# detail since they're subsequently scaled back to the approximately +# the map widget size before display. The video resolution setting +# interacts with this setting in that regard. local map resolution = 256 +# This integer setting controls the canvas size of the GUI mode local +# map widget. Larger values result in a larger physical map size on +# screen, and typically require more panning to see all available +# portions of the map. This larger size also enables an overall +# greater level of detail if the "local map resolution" setting is +# also increased. local map widget size = 512 -local map hud widget size = 256 -[Cells] -exterior cell load distance = 1 +[Objects] -[Camera] -near clip = 5 +# This boolean setting currently has no known impact, but is +# presumably intended to enable shaders for objects other than water. +# Whenever the setting file is written by the game, this option is +# currently reset to false. +shaders = true -# The maximum distance with no pop-in will be: (see RenderingManager::configureFog) -# viewing distance * view frustum factor <= cell size (8192) - loading threshold (1024) -# view frustum factor takes into account that the view frustum end is a plane, so at the edges of the screen you can see further than you should be able to. -# exact factor would depend on FOV -viewing distance = 6666 +[Saves] -# Culling of objects smaller than a pixel -small feature culling = true +# This string setting contains the default character name for loading +# saved games. This setting is automatically updated from the Load +# game menu option when a different character is selected. +character = -[Terrain] -distant land = false +# This boolean setting determines whether the game will be +# automatically saved when the character rests. This setting can be +# toggled in game with the "Auto-Save when Rest" button in the Prefs +# panel of the Options menu. +autosave = true -shader = true +# This boolean setting determines whether the amount of the time the +# player has spent playing will displayed for each saved game in the +# menu for saving and loading games. This setting can not currently +# be adjusted in game. This setting is disabled by default for players +# who would prefer not to know how many hours they've spent +# playing. :-) +timeplayed = false -[Water] -shader = false +[Shadows] -refraction = false +# Shadows in general are dependent on the "shaders" setting be enabled +# in the Objects section. Additionally, the "enabled" setting in this +# section must be true for any other options in this section to have +# effect. Both that setting and the Shadows section options are +# temporarily disabled following the conversion to the OpenSceneGraph +# engine. None of these option can be adjusted in game at the present +# time. -rtt size = 512 +# This boolean setting enables actors to cast shadows. +actor shadows = true + +# Enable debugging of shadows? +debug = false + +# Are shadows enabled in general? +enabled = false + +# This floating point setting determines the fraction of the total +# shadow distance after which the shadow starts to fade out. +fade start = 0.8 + +# Allows miscellaneous object to cast shadows. +misc shadows = true + +# This setting will only have effect if the "split" setting in the +# Shadows section is false. Increasing shadow distance will lower the +# shadow quality. +shadow distance = 1300 + +# Split the shadow maps, allowing for a larger shadow distance? +split = false + +# This setting will only have effect if the "split" setting in the +# Shadows section is true. # This one shouldn't be too low, otherwise +# you'll see artifacts. Use at least 2x max viewing distance. +split shadow distance = 14000 + +# Allow static objects to cast shadows. +statics shadows = true + +# Allow terrain to cast shadows. +terrain shadows = true + +# Size of the shadow textures. Higher resolution texture produce more +# detailed shadows and a better visual effect. +texture size = 1024 [Sound] -# Device name. Blank means default + +# This string setting determines which audio device to use. A blank or +# missing setting means to use the default device, which should +# usually be sufficient, but if you need to explicitly specify a +# device name try doing so here. device = -# Volumes. master volume affects all other volumes. -master volume = 1.0 -sfx volume = 1.0 -music volume = 0.5 +# The settings in the Sound section are generally floating point +# settings in the range from 0.0 (silent) to 1.0 (maximum volume). +# All sound settings are multiplied by the "master volume" setting, and +# will thus have no effect if the master volume is set to 0.0. These +# settings can be adjusted in game from the Audio panel of the Options +# menu under the appropriately labeled slider. + +# The volume of footsteps from the character and other actors. footsteps volume = 0.2 -voice volume = 0.8 +# The master volume is multiplied with all other volume settings to +# determine the final volume +master volume = 1.0 -[Input] +# The volume for music tracks. +music volume = 0.5 -grab cursor = true +# The volume for special effect sounds such as combat noises, etc. +sfx volume = 1.0 -invert y axis = false +# The volume for spoken dialog from NPCs. +voice volume = 0.8 -camera sensitivity = 1.0 +[Terrain] -ui sensitivity = 1.0 +# Not currently used, presumably due to the OpenSceneGraph upgrade. +distant land = false -camera y multiplier = 1.0 +# Not currently used, presumably due to the OpenSceneGraph upgrade. +shader = true -always run = false +[Video] -allow third person zoom = false +# This integer setting controls anti-aliasing. Anti-aliasing is +# technique designed to reduce distortions called aliasing caused by +# displaying high resolution textures at a lower resolution. +# Anti-aliasing can correct these distortions at the cost of a minor +# reduction in the frame rate. A value of 0 disables anti-aliasing. +# Other powers of two (e.g. 2, 4, 8, 16) are supported according to +# the capabilities of your graphics hardware. Higher values do a +# better job of correcting the distortion and have a greater impact on +# frame rate. This setting can be configured from a list of valid +# choices in the Graphics panel of the OpenMW Launcher. +antialiasing = 0 -toggle sneak = false +# This floating point setting controls the contrast correction for all +# video in the game. This setting does not currently work under +# Linux, and the in-game setting in the Options menu has been +# disabled. +contrast = 1.00 -[Game] -# Always use the most powerful attack when striking with a weapon (chop, slash or thrust) -best attack = false +# This floating point setting determines the maximum frame rate in +# frames per second. If this setting is 0.0, the frame rate is +# unlimited. There are several reasons to consider capping your frame +# rate, especially if you're already experiencing a relatively high +# frame rate (greater than 60 frames per second). Lower frame rates +# will consume less power and generate less heat and noise. Frame +# rates above 60 frames per second rarely produce perceptible +# improvements in visual quality. Capping the frame rate may in some +# situations reduce the perception of choppiness (highly variable +# frame rates during game play) by lowering the peak frame rates. +# This setting interacts with the "vsync" setting in the Video section +# in the sense that enabling vertical sync limits the frame rate to +# the refresh rate of your monitor (often 60 frames per second). +framerate limit = 0.0 + +# This boolean setting determines whether the entire screen is used +# for the specified resolution. This setting can be toggled in game +# using the "Fullscreen" button in the Video tab of the Video panel in +# the Options menu. It can also be toggled with the "Full Screen" +# check box in the Graphic tab of the OpenMW Launcher. +fullscreen = false -difficulty = 0 +# Theses two setting determine the horizontal and vertical resolution +# of the OpenMW game window. Larger values produce more detailed +# images within the constraints of your graphics hardware but also +# significantly reduce the frame rate. The window resolution can be +# selected from a menu of common screen sizes in the Video tab of the +# Video Panel of the Options menu. The resolution can also be set to +# a custom value in the Graphics tab of the OpenMW Launcher. +resolution x = 800 +resolution y = 600 -# Change crosshair/toolTip color when pointing on owned object -#0: nothing changed -#1: tint toolTip -#2: tint crosshair -#3: both -show owned = 0 -# Show the remaining duration of magic effects and lights -show effect duration = false +# This boolean setting determines whether there's an operating system +# border drawn around the OpenMW window. If this setting is true, the +# window can be moved and resized with the operating system window +# controls. If this setting is false, the window has no operating +# system border. This setting has no effect if the "fullscreen" +# setting in the Video section is true. This setting can be toggled +# in game using the "Window Border" button in the Video tab of the +# Video panel in the Options menu. It can also be toggled with the +# "Window Border" check box in the OpenMW Launcher. +window border = true -[Saves] -character = -# Save when resting -autosave = true -# display time played -timeplayed = false +# This integer setting determines which screen the game will open on +# in multi-monitor configurations. This setting is particularly +# important when "fullscreen" setting in the Video section is true, +# since this is the only way to control which screen is used, but it +# can also be used to control which screen a normal window or a +# borderless window opens on as well. This setting can be selected +# from a pull down menu in the Graphics tab of the OpenMW Launcher, +# but not adjusted during game play. +screen = 0 -[Windows] -inventory x = 0 -inventory y = 0.4275 -inventory w = 0.6225 -inventory h = 0.5725 +# Minimize the OpenMW window if it loses cursor focus. This setting +# has no effect if the "fullscreen" setting is false. This setting is +# primarily useful for single screen configurations, so that the +# OpenMW screen in full screen mode can be minimized when the +# operating system regains control of the mouse and keyboard. On +# multiple screen configurations, disabling this option make make it +# easier to switch between screens while playing OpenMW. +minimize on focus loss = true -inventory container x = 0 -inventory container y = 0.4275 -inventory container w = 0.6225 -inventory container h = 0.5725 +# This boolean setting determines whether frame draws are synchronized +# with the vertical refresh rate of your monitor. Enabling this +# setting can reduce "tearing", a visual defect caused by updating the +# image buffer in the middle of a screen draw. Enabling this option +# typically implies limiting the framerate to 60 frames per second, +# but may also introduce additional delays caused by having to wait +# until the appropriate time (the vertical blanking interval) to draw +# a frame. + +# This setting can be adjusted in game using the "VSync" button in the +# Video tab of the Video panel in the Options menu. It can also be +# changed by toggling the "Vertical Sync" check box in the Graphics +# tab of the OpenMW Launcher. +vsync = false -inventory barter x = 0 -inventory barter y = 0.4275 -inventory barter w = 0.6225 -inventory barter h = 0.5725 +# This floating point setting controls the gamma correction for all +# video in the game. This setting does not currently work under +# Linux, and the in-game setting in the Options menu has been +# disabled. +gamma = 1.00 -inventory companion x = 0 -inventory companion y = 0.4275 -inventory companion w = 0.6225 -inventory companion h = 0.5725 +[Water] -container x = 0.25 -container y = 0 -container w = 0.75 -container h = 0.375 +# The water settings can be tested experimentally in the Water tab of +# the Video panel in the Options menu. Changes there will be saved to +# these settings. + +# This boolean setting enables the refraction rendering feature of the +# water shader. Refraction causes deep water to be more opaque and +# objects seen through the plane of the water to have a wavy +# appearance. Enabling this feature results in better visuals, and a +# marginally lower framerate depending on your graphics hardware. The +# "shader" setting in the Water section must be enabled for this +# setting to have any effect. +refraction = false -companion x = 0.25 -companion y = 0 -companion w = 0.75 -companion h = 0.375 +# Refracted texture size. In the Video panel of the options menu, the +# choices are Low (512), Medium (1024) and High (2048). This setting +# determines the resolution of the textures used for rendering objects +# on the other wide of the plane of water (which have a wavy +# appearance caused the by the refraction). Higher values produces +# better visuals and result in a marginally lower framerate depending +# on your graphics hardware. The "refraction" setting in the "Water" +# section must be enabled for this setting to have any effect. +rtt size = 512 -map x = 0.625 -map y = 0 -map w = 0.375 -map h = 0.5725 +# This boolean setting enables or disables the water shader, which +# results in much more realistic looking water surfaces, including +# shadows of reflected objects. +shader = false -barter x = 0.25 -barter y = 0 -barter w = 0.75 -barter h = 0.375 +[Windows] + +# Each window in the GUI mode remembers it's previous location. Each +# setting is a floating point number representing a fraction of the +# "resolution x" or "resolution y" setting in the Video section. The +# X and Y values locate the top left corner, while the W value +# determines the width of the window and the H value determines the +# height of the window. +# The alchemy window, for crafting potions. Activated by dragging an +# alchemy tool on to the rag doll. Unlike most other windows, this +# window hides all other windows when opened. +alchemy h = 0.5 +alchemy w = 0.5 alchemy x = 0.25 alchemy y = 0.25 -alchemy w = 0.5 -alchemy h = 0.5 -stats x = 0 -stats y = 0 -stats w = 0.375 -stats h = 0.4275 +# The NPC bartering window, displaying goods owned by the shopkeeper +# while bartering. Activated by clicking on the "Barter" choice in +# the dialog window for an NPC. +barter h = 0.375 +barter w = 0.75 +barter x = 0.25 +barter y = 0 -spells x = 0.625 -spells y = 0.5725 -spells w = 0.375 -spells h = 0.4275 +# Unused? +companion h = 0.375 +companion w = 0.75 +companion x = 0.25 +companion y = 0 +# The console command window. Activated by pressing the tilde (~) key. +console h = 0.5 +console w = 1 console x = 0 console y = 0 -console w = 1 -console h = 0.5 +# The container window, showing the contents of the container. +# Activated by clicking on a container. The same window is used for +# searching dead bodies, and pickpocketing people. +container h = 0.375 +container w = 0.75 +container x = 0.25 +container y = 0 + +# The dialog window, for talking with NPCs. Activated by clicking on a +# NPC. dialogue h = 0.810 dialogue w = 0.810 dialogue x = 0.095 dialogue y = 0.095 + +# The character inventory window while bartering. It displays goods +# owned by the character while bartering. Activated by clicking on the +# "Barter" choice in the dialog window for an NPC. +inventory barter h = 0.5725 +inventory barter w = 0.6225 +inventory barter x = 0 +inventory barter y = 0.4275 + +# Unused? +inventory companion h = 0.5725 +inventory companion w = 0.6225 +inventory companion x = 0 +inventory companion y = 0.4275 + +# The character inventory window while searching a container, showing +# the contents of the character's inventory. Activated by clicking on +# a container. The same window is used for searching dead bodies, and +# pickpocketing people. +inventory container h = 0.5725 +inventory container w = 0.6225 +inventory container x = 0 +inventory container y = 0.4275 + +# The inventory window, displaying the paper doll and possessions. +# Activated by clicking on the inventory widget (second from left) in +# the bottom left corner of the HUD. +inventory h = 0.5725 +inventory w = 0.6225 +inventory x = 0 +inventory y = 0.4275 + +# The local and world map window. Activated by clicking on the map +# widget in the bottom right corner of the HUD. +map h = 0.5725 +map w = 0.375 +map x = 0.625 +map y = 0 + +# The spells window, displaying powers, spells, and magical items. +# Activated by clicking on the spells widget (third from left) in the +# bottom left corner of the HUD. +spells h = 0.4275 +spells w = 0.375 +spells x = 0.625 +spells y = 0.5725 + +# The stats window, displaying level, race, class, skills and stats. +# Activated by clicking on any of the three bars in the lower left +# corner of the HUD. +stats h = 0.4275 +stats w = 0.375 +stats x = 0 +stats y = 0 From 3fe38e3556d31194d8c293426b7b7e2c5dc4bd3b Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 23 Nov 2015 03:26:21 +0100 Subject: [PATCH 2531/3725] Remove unused setting --- apps/openmw/mwinput/inputmanagerimp.cpp | 4 ---- apps/openmw/mwinput/inputmanagerimp.hpp | 1 - files/settings-default.cfg | 2 -- 3 files changed, 7 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 0c306da68..0d1dc0e62 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -53,7 +53,6 @@ namespace MWInput , mInvertY (Settings::Manager::getBool("invert y axis", "Input")) , mControlsDisabled(false) , mCameraSensitivity (Settings::Manager::getFloat("camera sensitivity", "Input")) - , mUISensitivity (Settings::Manager::getFloat("ui sensitivity", "Input")) , mCameraYMultiplier (Settings::Manager::getFloat("camera y multiplier", "Input")) , mPreviewPOVDelay(0.f) , mTimeIdle(0.f) @@ -586,9 +585,6 @@ namespace MWInput if (it->first == "Input" && it->second == "camera sensitivity") mCameraSensitivity = Settings::Manager::getFloat("camera sensitivity", "Input"); - if (it->first == "Input" && it->second == "ui sensitivity") - mUISensitivity = Settings::Manager::getFloat("ui sensitivity", "Input"); - if (it->first == "Input" && it->second == "grab cursor") mGrabCursor = Settings::Manager::getBool("grab cursor", "Input"); diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index fc539f522..3b11e04c0 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -174,7 +174,6 @@ namespace MWInput bool mControlsDisabled; float mCameraSensitivity; - float mUISensitivity; float mCameraYMultiplier; float mPreviewPOVDelay; float mTimeIdle; diff --git a/files/settings-default.cfg b/files/settings-default.cfg index d68bc2fef..85434ff32 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -145,8 +145,6 @@ invert y axis = false camera sensitivity = 1.0 -ui sensitivity = 1.0 - camera y multiplier = 1.0 always run = false From 69acacefff5237a851d813e51c67c7b7116a7a57 Mon Sep 17 00:00:00 2001 From: sandstranger Date: Mon, 23 Nov 2015 20:28:35 +0300 Subject: [PATCH 2532/3725] openmw building on Android with Opengl es --- CMakeLists.txt | 44 +++-- apps/openmw/CMakeLists.txt | 34 +++- apps/openmw/android_main.c | 1 - apps/openmw/main.cpp | 2 +- apps/openmw/mwrender/localmap.cpp | 5 + apps/openmw/mwrender/sky.cpp | 5 + apps/openmw/mwrender/water.cpp | 11 +- cmake/FindOpenGLES.cmake | 94 +++++++++++ cmake/FindOpenGLES2.cmake | 170 +++++++++++++++++++ components/CMakeLists.txt | 105 +++++++----- components/sdlutil/sdlcursormanager.cpp | 3 + files/shaders/CMakeLists.txt | 20 ++- files/shaders/watergles_fragment.glsl | 209 ++++++++++++++++++++++++ files/shaders/watergles_vertex.glsl | 24 +++ 14 files changed, 656 insertions(+), 71 deletions(-) create mode 100644 cmake/FindOpenGLES.cmake create mode 100644 cmake/FindOpenGLES2.cmake create mode 100644 files/shaders/watergles_fragment.glsl create mode 100644 files/shaders/watergles_vertex.glsl diff --git a/CMakeLists.txt b/CMakeLists.txt index 8fac1b77f..4b46542e7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -47,8 +47,20 @@ include(OpenMWMacros) if (ANDROID) set(CMAKE_FIND_ROOT_PATH ${OPENMW_DEPENDENCIES_DIR} "${CMAKE_FIND_ROOT_PATH}") + set(OSG_PLUGINS_DIR ${OSG_PLUGINS_DIR}) + add_definitions (-DOSG_PLUGINS_DIR) + set(OPENGLES TRUE CACHE BOOL "enable opengl es support for android" FORCE) endif (ANDROID) +option(OPENGLES "enable opengl es support" FALSE ) + +if (OPENGLES) + INCLUDE(cmake/FindOpenGLES.cmake) + INCLUDE(cmake/FindOpenGLES2.cmake) + add_definitions (-DOPENGLES) + INCLUDE_DIRECTORIES(${OPENGLES_INCLUDE_DIR}) +endif (OPENGLES) + # doxygen main page configure_file ("${OpenMW_SOURCE_DIR}/docs/mainpage.hpp.cmake" "${OpenMW_BINARY_DIR}/docs/mainpage.hpp") @@ -145,21 +157,21 @@ if (WIN32) endif() # Dependencies +if (NOT ANDROID) + set(DESIRED_QT_VERSION 4 CACHE STRING "The QT version OpenMW should use (4 or 5)") + message(STATUS "Using Qt${DESIRED_QT_VERSION}") -set(DESIRED_QT_VERSION 4 CACHE STRING "The QT version OpenMW should use (4 or 5)") -message(STATUS "Using Qt${DESIRED_QT_VERSION}") - -if (DESIRED_QT_VERSION MATCHES 4) - find_package(Qt4 REQUIRED COMPONENTS QtCore QtGui QtNetwork QtOpenGL) -else() - find_package(Qt5Widgets REQUIRED) - find_package(Qt5Core REQUIRED) - find_package(Qt5Network REQUIRED) - find_package(Qt5OpenGL REQUIRED) - # Instruct CMake to run moc automatically when needed. - #set(CMAKE_AUTOMOC ON) + if (DESIRED_QT_VERSION MATCHES 4) + find_package(Qt4 REQUIRED COMPONENTS QtCore QtGui QtNetwork QtOpenGL) + else() + find_package(Qt5Widgets REQUIRED) + find_package(Qt5Core REQUIRED) + find_package(Qt5Network REQUIRED) + find_package(Qt5OpenGL REQUIRED) + # Instruct CMake to run moc automatically when needed. + #set(CMAKE_AUTOMOC ON) + endif() endif() - # Fix for not visible pthreads functions for linker with glibc 2.15 if (UNIX AND NOT APPLE) find_package (Threads) @@ -189,7 +201,11 @@ IF(BOOST_STATIC) set(Boost_USE_STATIC_LIBS ON) endif() -find_package(OpenSceneGraph 3.2.0 REQUIRED osgDB osgViewer osgText osgGA osgAnimation osgParticle osgQt osgUtil osgFX) +if (NOT ANDROID) + find_package(OpenSceneGraph 3.2.0 REQUIRED osgDB osgViewer osgText osgGA osgAnimation osgParticle osgQt osgUtil osgFX) +else() + find_package(OpenSceneGraph 3.2.0 REQUIRED osgDB osgViewer osgText osgGA osgAnimation osgParticle osgUtil osgFX) +endif() include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS}) if(OSG_STATIC) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 59a523023..1f0fe71ab 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -134,18 +134,50 @@ target_link_libraries(openmw ) if (ANDROID) + set (OSG_PLUGINS + -Wl,--whole-archive + ${OSG_PLUGINS_DIR}/libosgdb_dds.a + ${OSG_PLUGINS_DIR}/libosgdb_bmp.a + ${OSG_PLUGINS_DIR}/libosgdb_tga.a + ${OSG_PLUGINS_DIR}/libosgdb_gif.a + ${OSG_PLUGINS_DIR}/libosgdb_jpeg.a + ${OSG_PLUGINS_DIR}/libosgdb_png.a + -Wl,--no-whole-archive + ) target_link_libraries(openmw EGL android log dl MyGUIEngineStatic - cpufeatures BulletCollision LinearMath + z + osg + osgDB + osgAnimation + osgText + osgUtil + osgShadow + ${OPENSCENEGRAPH_LIBRARIES} + ${OSG_PLUGINS} + ${Boost_SYSTEM_LIBRARY} + ${Boost_THREAD_LIBRARY} + ${Boost_FILESYSTEM_LIBRARY} + ${Boost_PROGRAM_OPTIONS_LIBRARY} + jpeg + gif + png ) endif (ANDROID) +if (OPENGLES) + target_link_libraries(openmw + ${OPENGLES_gl_LIBRARY} + ${OPENGLES2_gl_LIBRARY} + ) +endif (OPENGLES) + if (USE_SYSTEM_TINYXML) target_link_libraries(openmw ${TINYXML_LIBRARIES}) endif() diff --git a/apps/openmw/android_main.c b/apps/openmw/android_main.c index 47b77a8b3..8cd69e8f0 100644 --- a/apps/openmw/android_main.c +++ b/apps/openmw/android_main.c @@ -1,4 +1,3 @@ -#include "../../SDL_internal.h" #ifdef __ANDROID__ #include "SDL_main.h" diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 17ef46246..c3f0f8688 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -23,7 +23,7 @@ #endif -#if (defined(__APPLE__) || defined(__linux) || defined(__unix) || defined(__posix)) +#if (defined(__APPLE__) || (defined(__linux) && !defined(ANDROID)) || (defined(__unix) && !defined(ANDROID)) || defined(__posix)) #define USE_CRASH_CATCHER 1 #else #define USE_CRASH_CATCHER 0 diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 14ec770e8..077d21512 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -24,6 +24,11 @@ #include "vismask.hpp" +#ifdef OPENGLES + #include +#endif + + namespace { diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 66253f70d..7572d7e92 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -45,6 +45,11 @@ #include "vismask.hpp" #include "renderbin.hpp" +#ifdef OPENGLES + #include +#endif + + namespace { diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index ca099991e..5a9bc664a 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -40,6 +40,10 @@ #include "ripplesimulation.hpp" #include "renderbin.hpp" +#ifdef OPENGLES +#include +#endif + namespace { @@ -575,10 +579,13 @@ void Water::createShaderWaterStateSet(osg::Node* node, Reflection* reflection, R // use a define map to conditionally compile the shader std::map defineMap; defineMap.insert(std::make_pair(std::string("@refraction_enabled"), std::string(refraction ? "1" : "0"))); - +#ifdef OPENGLES + osg::ref_ptr vertexShader (readShader(osg::Shader::VERTEX, mResourcePath + "/shaders/watergles_vertex.glsl", defineMap)); + osg::ref_ptr fragmentShader (readShader(osg::Shader::FRAGMENT, mResourcePath + "/shaders/watergles_fragment.glsl", defineMap)); +#else osg::ref_ptr vertexShader (readShader(osg::Shader::VERTEX, mResourcePath + "/shaders/water_vertex.glsl", defineMap)); osg::ref_ptr fragmentShader (readShader(osg::Shader::FRAGMENT, mResourcePath + "/shaders/water_fragment.glsl", defineMap)); - +#endif osg::ref_ptr normalMap (new osg::Texture2D(readPngImage(mResourcePath + "/shaders/water_nm.png"))); normalMap->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT); normalMap->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT); diff --git a/cmake/FindOpenGLES.cmake b/cmake/FindOpenGLES.cmake new file mode 100644 index 000000000..7ee2c07f1 --- /dev/null +++ b/cmake/FindOpenGLES.cmake @@ -0,0 +1,94 @@ +#------------------------------------------------------------------- +# This file is part of the CMake build system for OGRE +# (Object-oriented Graphics Rendering Engine) +# For the latest info, see http://www.ogre3d.org/ +# +# The contents of this file are placed in the public domain. Feel +# free to make use of it in any way you like. +#------------------------------------------------------------------- + +# - Try to find OpenGLES +# Once done this will define +# +# OPENGLES_FOUND - system has OpenGLES +# OPENGLES_INCLUDE_DIR - the GL include directory +# OPENGLES_LIBRARIES - Link these to use OpenGLES + +IF (WIN32) + IF (CYGWIN) + + FIND_PATH(OPENGLES_INCLUDE_DIR GLES/gl.h ) + + FIND_LIBRARY(OPENGLES_gl_LIBRARY libgles_cm ) + + ELSE (CYGWIN) + + IF(BORLAND) + SET (OPENGLES_gl_LIBRARY import32 CACHE STRING "OpenGL ES 1.x library for win32") + ELSE(BORLAND) + #MS compiler - todo - fix the following line: + SET (OPENGLES_gl_LIBRARY ${OGRE_SOURCE_DIR}/Dependencies/lib/release/libgles_cm.lib CACHE STRING "OpenGL ES 1.x library for win32") + ENDIF(BORLAND) + + ENDIF (CYGWIN) + +ELSE (WIN32) + + IF (APPLE) + + #create_search_paths(/Developer/Platforms) + #findpkg_framework(OpenGLES) + #set(OPENGLES_gl_LIBRARY "-framework OpenGLES") + + ELSE(APPLE) + + FIND_PATH(OPENGLES_INCLUDE_DIR GLES/gl.h + /opt/vc/include + /opt/graphics/OpenGL/include + /usr/openwin/share/include + /usr/X11R6/include + /usr/include + ) + + FIND_LIBRARY(OPENGLES_gl_LIBRARY + NAMES GLES_CM GLESv1_CM + PATHS /opt/vc/lib + /opt/graphics/OpenGL/lib + /usr/openwin/lib + /usr/shlib /usr/X11R6/lib + /usr/lib + ) + + # On Unix OpenGL most certainly always requires X11. + # Feel free to tighten up these conditions if you don't + # think this is always true. + + #IF (OPENGLES_gl_LIBRARY) + # IF(NOT X11_FOUND) + # INCLUDE(FindX11) + # ENDIF(NOT X11_FOUND) + # IF (X11_FOUND) + # SET (OPENGLES_LIBRARIES ${X11_LIBRARIES}) + # ENDIF (X11_FOUND) + #ENDIF (OPENGLES_gl_LIBRARY) + + ENDIF(APPLE) +ENDIF (WIN32) + +SET( OPENGLES_FOUND "NO" ) +IF(OPENGLES_gl_LIBRARY) + + SET( OPENGLES_LIBRARIES ${OPENGLES_gl_LIBRARY} ${OPENGLES_LIBRARIES}) + + SET( OPENGLES_FOUND "YES" ) + +ENDIF(OPENGLES_gl_LIBRARY) + +MARK_AS_ADVANCED( + OPENGLES_INCLUDE_DIR + OPENGLES_gl_LIBRARY +) + +INCLUDE(FindPackageHandleStandardArgs) + +FIND_PACKAGE_HANDLE_STANDARD_ARGS(OPENGLES REQUIRED_VARS OPENGLES_LIBRARIES OPENGLES_INCLUDE_DIR) diff --git a/cmake/FindOpenGLES2.cmake b/cmake/FindOpenGLES2.cmake new file mode 100644 index 000000000..136e7618b --- /dev/null +++ b/cmake/FindOpenGLES2.cmake @@ -0,0 +1,170 @@ +#------------------------------------------------------------------- +# This file is part of the CMake build system for OGRE +# (Object-oriented Graphics Rendering Engine) +# For the latest info, see http://www.ogre3d.org/ +# +# The contents of this file are placed in the public domain. Feel +# free to make use of it in any way you like. +#------------------------------------------------------------------- + +# - Try to find OpenGLES and EGL +# If using ARM Mali emulation you can specify the parent directory that contains the bin and include directories by +# setting the MALI_SDK_ROOT variable in the environment. +# +# For AMD emulation use the AMD_SDK_ROOT variable +# +# Once done this will define +# +# OPENGLES2_FOUND - system has OpenGLES +# OPENGLES2_INCLUDE_DIR - the GL include directory +# OPENGLES2_LIBRARIES - Link these to use OpenGLES +# +# EGL_FOUND - system has EGL +# EGL_INCLUDE_DIR - the EGL include directory +# EGL_LIBRARIES - Link these to use EGL + +#include(FindPkgMacros) + +IF (WIN32) + IF (CYGWIN) + + FIND_PATH(OPENGLES2_INCLUDE_DIR GLES2/gl2.h ) + + FIND_LIBRARY(OPENGLES2_gl_LIBRARY libGLESv2 ) + + ELSE (CYGWIN) + + IF(BORLAND) + SET (OPENGLES2_gl_LIBRARY import32 CACHE STRING "OpenGL ES 2.x library for win32") + ELSE(BORLAND) + #getenv_path(AMD_SDK_ROOT) + #getenv_path(MALI_SDK_ROOT) + + SET(POWERVR_SDK_PATH "C:/Imagination/PowerVR/GraphicsSDK/SDK_3.1/Builds") + FIND_PATH(OPENGLES2_INCLUDE_DIR GLES2/gl2.h + ${ENV_AMD_SDK_ROOT}/include + ${ENV_MALI_SDK_ROOT}/include + ${POWERVR_SDK_PATH}/Include + "C:/Imagination Technologies/PowerVR Insider SDK/OGLES2_WINDOWS_X86EMULATION_2.10/Builds/OGLES2/Include" + ) + + FIND_PATH(EGL_INCLUDE_DIR EGL/egl.h + ${ENV_AMD_SDK_ROOT}/include + ${ENV_MALI_SDK_ROOT}/include + ${POWERVR_SDK_PATH}/Include + "C:/Imagination Technologies/PowerVR Insider SDK/OGLES2_WINDOWS_X86EMULATION_2.10/Builds/OGLES2/Include" + ) + + FIND_LIBRARY(OPENGLES2_gl_LIBRARY + NAMES libGLESv2 + PATHS ${ENV_AMD_SDK_ROOT}/x86 + ${ENV_MALI_SDK_ROOT}/bin + ${POWERVR_SDK_PATH}/Windows/x86_32/Lib + "C:/Imagination Technologies/PowerVR Insider SDK/OGLES2_WINDOWS_X86EMULATION_2.10/Builds/OGLES2/WindowsX86/Lib" + ) + + FIND_LIBRARY(EGL_egl_LIBRARY + NAMES libEGL + PATHS ${ENV_AMD_SDK_ROOT}/x86 + ${ENV_MALI_SDK_ROOT}/bin + ${POWERVR_SDK_PATH}/Windows/x86_32/Lib + "C:/Imagination Technologies/PowerVR Insider SDK/OGLES2_WINDOWS_X86EMULATION_2.10/Builds/OGLES2/WindowsX86/Lib" + ) + ENDIF(BORLAND) + + ENDIF (CYGWIN) + +ELSE (WIN32) + + IF (APPLE) + + #create_search_paths(/Developer/Platforms) + #findpkg_framework(OpenGLES2) + #set(OPENGLES2_gl_LIBRARY "-framework OpenGLES") + + ELSE(APPLE) + #getenv_path(AMD_SDK_ROOT) + #getenv_path(MALI_SDK_ROOT) + + FIND_PATH(OPENGLES2_INCLUDE_DIR GLES2/gl2.h + ${ENV_AMD_SDK_ROOT}/include + ${ENV_MALI_SDK_ROOT}/include + /opt/Imagination/PowerVR/GraphicsSDK/SDK_3.1/Builds/Include + /opt/vc/include + /usr/openwin/share/include + /opt/graphics/OpenGL/include /usr/X11R6/include + /usr/include + ) + + FIND_LIBRARY(OPENGLES2_gl_LIBRARY + NAMES GLESv2 + PATHS ${ENV_AMD_SDK_ROOT}/x86 + ${ENV_MALI_SDK_ROOT}/bin + /opt/Imagination/PowerVR/GraphicsSDK/SDK_3.1/Builds/Linux/x86_32/Lib + /opt/vc/lib + /opt/graphics/OpenGL/lib + /usr/openwin/lib + /usr/shlib /usr/X11R6/lib + /usr/lib + ) + + FIND_PATH(EGL_INCLUDE_DIR EGL/egl.h + ${ENV_AMD_SDK_ROOT}/include + ${ENV_MALI_SDK_ROOT}/include + /opt/Imagination/PowerVR/GraphicsSDK/SDK_3.1/Builds/Include + /opt/vc/include + /usr/openwin/share/include + /opt/graphics/OpenGL/include /usr/X11R6/include + /usr/include + ) + + FIND_LIBRARY(EGL_egl_LIBRARY + NAMES EGL + PATHS ${ENV_AMD_SDK_ROOT}/x86 + ${ENV_MALI_SDK_ROOT}/bin + /opt/Imagination/PowerVR/GraphicsSDK/SDK_3.1/Builds/Linux/x86_32/Lib + /opt/vc/lib + /opt/graphics/OpenGL/lib + /usr/openwin/lib + /usr/shlib /usr/X11R6/lib + /usr/lib + ) + + # On Unix OpenGL most certainly always requires X11. + # Feel free to tighten up these conditions if you don't + # think this is always true. + # It's not true on OSX. + + #IF (OPENGLES2_gl_LIBRARY) + # IF(NOT X11_FOUND) + # INCLUDE(FindX11) + # ENDIF(NOT X11_FOUND) + # IF (X11_FOUND) + # IF (NOT APPLE) + # SET (OPENGLES2_LIBRARIES ${X11_LIBRARIES}) + # ENDIF (NOT APPLE) + # ENDIF (X11_FOUND) + #ENDIF (OPENGLES2_gl_LIBRARY) + + ENDIF(APPLE) +ENDIF (WIN32) + +SET( OPENGLES2_FOUND "YES" ) +IF(OPENGLES2_gl_LIBRARY AND EGL_egl_LIBRARY) + + SET( OPENGLES2_LIBRARIES ${OPENGLES2_gl_LIBRARY} ${OPENGLES2_LIBRARIES}) + SET( EGL_LIBRARIES ${EGL_egl_LIBRARY} ${EGL_LIBRARIES}) + SET( OPENGLES2_FOUND "YES" ) + +ENDIF(OPENGLES2_gl_LIBRARY AND EGL_egl_LIBRARY) + +MARK_AS_ADVANCED( + OPENGLES2_INCLUDE_DIR + OPENGLES2_gl_LIBRARY + EGL_INCLUDE_DIR + EGL_egl_LIBRARY +) + +INCLUDE(FindPackageHandleStandardArgs) + +FIND_PACKAGE_HANDLE_STANDARD_ARGS(OPENGLES2 REQUIRED_VARS OPENGLES2_LIBRARIES OPENGLES2_INCLUDE_DIR) diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index c80e27e4d..7bfbf6d93 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -20,8 +20,9 @@ else (GIT_CHECKOUT) configure_file(${VERSION_IN_FILE} ${VERSION_FILE}) endif (GIT_CHECKOUT) -find_package(OpenGL REQUIRED) - +if (NOT ANDROID) + find_package(OpenGL REQUIRED) +endif() # source files add_component_dir (settings @@ -137,31 +138,31 @@ add_component_dir (version set (ESM_UI ${CMAKE_SOURCE_DIR}/files/ui/contentselector.ui ) -add_component_qt_dir (contentselector - model/modelitem model/esmfile - model/naturalsort model/contentmodel - model/loadordererror - view/combobox view/contentselector - ) -add_component_qt_dir (config - gamesettings - launchersettings - settingsbase - ) - -add_component_qt_dir (process - processinvoker -) - -if (DESIRED_QT_VERSION MATCHES 4) - include(${QT_USE_FILE}) - QT4_WRAP_UI(ESM_UI_HDR ${ESM_UI}) - QT4_WRAP_CPP(MOC_SRCS ${COMPONENT_MOC_FILES}) -else() - QT5_WRAP_UI(ESM_UI_HDR ${ESM_UI}) - QT5_WRAP_CPP(MOC_SRCS ${COMPONENT_MOC_FILES}) +if (NOT ANDROID) + add_component_qt_dir (contentselector + model/modelitem model/esmfile + model/naturalsort model/contentmodel + model/loadordererror + view/combobox view/contentselector + ) + add_component_qt_dir (config + gamesettings + launchersettings + settingsbase + ) + + add_component_qt_dir (process + processinvoker + ) + if (DESIRED_QT_VERSION MATCHES 4) + include(${QT_USE_FILE}) + QT4_WRAP_UI(ESM_UI_HDR ${ESM_UI}) + QT4_WRAP_CPP(MOC_SRCS ${COMPONENT_MOC_FILES}) + else() + QT5_WRAP_UI(ESM_UI_HDR ${ESM_UI}) + QT5_WRAP_CPP(MOC_SRCS ${COMPONENT_MOC_FILES}) + endif() endif() - if (CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") if("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "x86_64" AND NOT APPLE) add_definitions(-fPIC) @@ -172,32 +173,46 @@ include_directories(${BULLET_INCLUDE_DIRS} ${CMAKE_CURRENT_BINARY_DIR}) add_library(components STATIC ${COMPONENT_FILES} ${MOC_SRCS} ${ESM_UI_HDR}) -target_link_libraries(components - ${Boost_SYSTEM_LIBRARY} - ${Boost_FILESYSTEM_LIBRARY} - ${Boost_THREAD_LIBRARY} - ${Boost_PROGRAM_OPTIONS_LIBRARY} - ${OPENSCENEGRAPH_LIBRARIES} - ${BULLET_LIBRARIES} - ${SDL2_LIBRARY} - # For MyGUI platform - ${OPENGL_gl_LIBRARY} - ${MYGUI_LIBRARIES} -) +if (NOT ANDROID) + target_link_libraries(components + ${Boost_SYSTEM_LIBRARY} + ${Boost_FILESYSTEM_LIBRARY} + ${Boost_THREAD_LIBRARY} + ${Boost_PROGRAM_OPTIONS_LIBRARY} + ${OPENSCENEGRAPH_LIBRARIES} + ${BULLET_LIBRARIES} + ${SDL2_LIBRARY} + # For MyGUI platform + ${OPENGL_gl_LIBRARY} + ${MYGUI_LIBRARIES} + ) +else() + target_link_libraries(components + ${Boost_SYSTEM_LIBRARY} + ${Boost_FILESYSTEM_LIBRARY} + ${Boost_THREAD_LIBRARY} + ${Boost_PROGRAM_OPTIONS_LIBRARY} + ${OPENSCENEGRAPH_LIBRARIES} + ${BULLET_LIBRARIES} + ${SDL2_LIBRARY} + ${MYGUI_LIBRARIES} + ) +endif() if (WIN32) target_link_libraries(components ${Boost_LOCALE_LIBRARY}) endif() -if (DESIRED_QT_VERSION MATCHES 4) - target_link_libraries(components - ${QT_QTCORE_LIBRARY} - ${QT_QTGUI_LIBRARY}) -else() - qt5_use_modules(components Widgets Core) +if (NOT ANDROID) + if (DESIRED_QT_VERSION MATCHES 4) + target_link_libraries(components + ${QT_QTCORE_LIBRARY} + ${QT_QTGUI_LIBRARY}) + else() + qt5_use_modules(components Widgets Core) + endif() endif() - if (GIT_CHECKOUT) add_dependencies (components git-version) endif (GIT_CHECKOUT) diff --git a/components/sdlutil/sdlcursormanager.cpp b/components/sdlutil/sdlcursormanager.cpp index e1a67aff8..23f01f3a7 100644 --- a/components/sdlutil/sdlcursormanager.cpp +++ b/components/sdlutil/sdlcursormanager.cpp @@ -217,6 +217,9 @@ namespace SDLUtil void SDLCursorManager::_createCursorFromResource(const std::string& name, int rotDegrees, osg::Image* image, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y) { + #ifdef ANDROID + return; + #endif if (mCursorMap.find(name) != mCursorMap.end()) return; diff --git a/files/shaders/CMakeLists.txt b/files/shaders/CMakeLists.txt index fc4706c1f..da2550275 100644 --- a/files/shaders/CMakeLists.txt +++ b/files/shaders/CMakeLists.txt @@ -1,11 +1,17 @@ # Copy resource files into the build directory set(SDIR ${CMAKE_CURRENT_SOURCE_DIR}) set(DDIR ${OpenMW_BINARY_DIR}/resources/shaders) - -set(SHADER_FILES - water_vertex.glsl - water_fragment.glsl - water_nm.png -) - +if (OPENGLES) + set(SHADER_FILES + watergles_vertex.glsl + watergles_fragment.glsl + water_nm.png + ) +else() + set(SHADER_FILES + water_vertex.glsl + water_fragment.glsl + water_nm.png + ) +endif() copy_all_files(${CMAKE_CURRENT_SOURCE_DIR} ${DDIR} "${SHADER_FILES}") diff --git a/files/shaders/watergles_fragment.glsl b/files/shaders/watergles_fragment.glsl new file mode 100644 index 000000000..e3f756087 --- /dev/null +++ b/files/shaders/watergles_fragment.glsl @@ -0,0 +1,209 @@ +#version 100 +precision mediump float; +precision mediump int; + +struct osg_LightSourceParameters { + mediump vec4 ambient; + mediump vec4 diffuse; + mediump vec4 specular; + mediump vec4 position; + mediump vec4 halfVector; + mediump vec3 spotDirection; + mediump float spotExponent; + mediump float spotCutoff; + mediump float spotCosCutoff; + mediump float constantAttenuation; + mediump float linearAttenuation; + mediump float quadraticAttenuation; + }; +uniform osg_LightSourceParameters osg_LightSource[1]; + +#define REFRACTION @refraction_enabled + +// Inspired by Blender GLSL Water by martinsh ( http://devlog-martinsh.blogspot.de/2012/07/waterundewater-shader-wip.html ) + +// tweakables -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- + +const float VISIBILITY = 1200.0; // how far you can look through water + +const float BIG_WAVES_X = 0.1; // strength of big waves +const float BIG_WAVES_Y = 0.1; + +const float MID_WAVES_X = 0.1; // strength of middle sized waves +const float MID_WAVES_Y = 0.1; + +const float SMALL_WAVES_X = 0.1; // strength of small waves +const float SMALL_WAVES_Y = 0.1; + +const float WAVE_CHOPPYNESS = 0.05; // wave choppyness +const float WAVE_SCALE = 75.0; // overall wave scale + +const float BUMP = 0.5; // overall water surface bumpiness +const float REFL_BUMP = 0.10; // reflection distortion amount +const float REFR_BUMP = 0.07; // refraction distortion amount + +const float SCATTER_AMOUNT = 0.3; // amount of sunlight scattering +const vec3 SCATTER_COLOUR = vec3(0.0,1.0,0.95); // colour of sunlight scattering + +const vec3 SUN_EXT = vec3(0.45, 0.55, 0.68); //sunlight extinction + +const float SPEC_HARDNESS = 256.0; // specular highlights hardness + +const vec2 WIND_DIR = vec2(0.5, -0.8); +const float WIND_SPEED = 0.2; + +const vec3 WATER_COLOR = vec3(0.090195, 0.115685, 0.12745); + +// -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - + +float fresnel_dielectric(vec3 Incoming, vec3 Normal, float eta) +{ + float c = abs(dot(Incoming, Normal)); + float g = eta * eta - 1.0 + c * c; + float result; + + if(g > 0.0) { + g = sqrt(g); + float A =(g - c)/(g + c); + float B =(c *(g + c)- 1.0)/(c *(g - c)+ 1.0); + result = 0.5 * A * A *(1.0 + B * B); + } + else + result = 1.0; + + return result; +} + +varying vec3 screenCoordsPassthrough; +varying vec4 position; +varying float depthPassthrough; + +uniform sampler2D normalMap; + +uniform sampler2D reflectionMap; +#if REFRACTION +uniform sampler2D refractionMap; +uniform sampler2D refractionDepthMap; +#endif + +uniform float osg_SimulationTime; + +uniform float near; +uniform float far; +uniform vec3 nodePosition; + +void main(void) +{ + vec3 worldPos = position.xyz + nodePosition.xyz; + vec2 UV = worldPos.xy / (8192.0*5.0) * 3.0; + UV.y *= -1.0; + + float shadow = 1.0; + + vec2 screenCoords = screenCoordsPassthrough.xy / screenCoordsPassthrough.z; + screenCoords.y = (1.0-screenCoords.y); + + vec2 nCoord = vec2(0.0,0.0); + + #define waterTimer osg_SimulationTime + + nCoord = UV * (WAVE_SCALE * 0.05) + WIND_DIR * waterTimer * (WIND_SPEED*0.04); + vec3 normal0 = 2.0 * texture2D(normalMap, nCoord + vec2(-waterTimer*0.015,-waterTimer*0.005)).rgb - 1.0; + nCoord = UV * (WAVE_SCALE * 0.1) + WIND_DIR * waterTimer * (WIND_SPEED*0.08)-(normal0.xy/normal0.zz)*WAVE_CHOPPYNESS; + vec3 normal1 = 2.0 * texture2D(normalMap, nCoord + vec2(+waterTimer*0.020,+waterTimer*0.015)).rgb - 1.0; + + nCoord = UV * (WAVE_SCALE * 0.25) + WIND_DIR * waterTimer * (WIND_SPEED*0.07)-(normal1.xy/normal1.zz)*WAVE_CHOPPYNESS; + vec3 normal2 = 2.0 * texture2D(normalMap, nCoord + vec2(-waterTimer*0.04,-waterTimer*0.03)).rgb - 1.0; + nCoord = UV * (WAVE_SCALE * 0.5) + WIND_DIR * waterTimer * (WIND_SPEED*0.09)-(normal2.xy/normal2.z)*WAVE_CHOPPYNESS; + vec3 normal3 = 2.0 * texture2D(normalMap, nCoord + vec2(+waterTimer*0.03,+waterTimer*0.04)).rgb - 1.0; + + nCoord = UV * (WAVE_SCALE* 1.0) + WIND_DIR * waterTimer * (WIND_SPEED*0.4)-(normal3.xy/normal3.zz)*WAVE_CHOPPYNESS; + vec3 normal4 = 2.0 * texture2D(normalMap, nCoord + vec2(-waterTimer*0.02,+waterTimer*0.1)).rgb - 1.0; + nCoord = UV * (WAVE_SCALE * 2.0) + WIND_DIR * waterTimer * (WIND_SPEED*0.7)-(normal4.xy/normal4.zz)*WAVE_CHOPPYNESS; + vec3 normal5 = 2.0 * texture2D(normalMap, nCoord + vec2(+waterTimer*0.1,-waterTimer*0.06)).rgb - 1.0; + + + + vec3 normal = (normal0 * BIG_WAVES_X + normal1 * BIG_WAVES_Y + + normal2 * MID_WAVES_X + normal3 * MID_WAVES_Y + + normal4 * SMALL_WAVES_X + normal5 * SMALL_WAVES_Y); + + normal = normalize(vec3(normal.x * BUMP, normal.y * BUMP, normal.z)); + + normal = vec3(-normal.x, -normal.y, normal.z); + + // normal for sunlight scattering + vec3 lNormal = (normal0 * BIG_WAVES_X*0.5 + normal1 * BIG_WAVES_Y*0.5 + + normal2 * MID_WAVES_X*0.2 + normal3 * MID_WAVES_Y*0.2 + + normal4 * SMALL_WAVES_X*0.1 + normal5 * SMALL_WAVES_Y*0.1).xyz; + lNormal = normalize(vec3(lNormal.x * BUMP, lNormal.y * BUMP, lNormal.z)); + lNormal = vec3(-lNormal.x, -lNormal.y, lNormal.z); + + + vec3 lVec = normalize((gl_ModelViewMatrixInverse * vec4(osg_LightSource[0].position.xyz, 0.0)).xyz); + + vec3 cameraPos = (gl_ModelViewMatrixInverse * vec4(0.0,0.0,0.0,1.0)).xyz; + vec3 vVec = normalize(position.xyz - cameraPos.xyz); + + float isUnderwater = (cameraPos.z > 0.0) ? 0.0 : 1.0; + + // sunlight scattering + vec3 pNormal = vec3(0.0,0.0,1.0); + vec3 lR = reflect(lVec, lNormal); + vec3 llR = reflect(lVec, pNormal); + + float sunHeight = lVec.z; + float sunFade = length(gl_LightModel.ambient.xyz); + + float s = clamp(dot(lR, vVec)*2.0-1.2, 0.0, 1.0); + float lightScatter = shadow * clamp(dot(lVec,lNormal)*0.7+0.3, 0.0, 1.0) * s * SCATTER_AMOUNT * sunFade * clamp(1.0-exp(-sunHeight), 0.0, 1.0); + vec3 scatterColour = mix(vec3(SCATTER_COLOUR)*vec3(1.0,0.4,0.0), SCATTER_COLOUR, clamp(1.0-exp(-sunHeight*SUN_EXT), 0.0, 1.0)); + + // fresnel + float ior = (cameraPos.z>0.0)?(1.333/1.0):(1.0/1.333); //air to water; water to air + float fresnel = fresnel_dielectric(vVec, normal, ior); + + fresnel = clamp(fresnel, 0.0, 1.0); + + // reflection + vec3 reflection = texture2D(reflectionMap, screenCoords+(normal.xy*REFL_BUMP)).rgb; + + // refraction +#if REFRACTION + vec3 refraction = texture2D(refractionMap, screenCoords-(normal.xy*REFR_BUMP)).rgb; + + // brighten up the refraction underwater + refraction = (cameraPos.z < 0.0) ? clamp(refraction * 1.5, 0.0, 1.0) : refraction; +#endif + + // specular + vec3 R = reflect(vVec, normal); + float specular = pow(max(dot(R, lVec), 0.0),SPEC_HARDNESS) * shadow; + + vec3 waterColor = WATER_COLOR; + waterColor = waterColor * length(gl_LightModel.ambient.xyz); +#if REFRACTION + float refractionDepth = texture2D(refractionDepthMap, screenCoords-(normal.xy*REFR_BUMP)).x; + float z_n = 2.0 * refractionDepth - 1.0; + refractionDepth = 2.0 * near * far / (far + near - z_n * (far - near)); + + float waterDepth = refractionDepth - depthPassthrough; + + if (cameraPos.z > 0.0) + refraction = mix(refraction, waterColor, clamp(waterDepth/VISIBILITY, 0.0, 1.0)); + + gl_FragData[0].xyz = mix( mix(refraction, scatterColour, lightScatter), reflection, fresnel) + specular * osg_LightSource[0].specular.xyz; +#else + gl_FragData[0].xyz = mix(reflection, waterColor, (1.0-fresnel)*0.5) + specular * osg_LightSource[0].specular.xyz; +#endif + + // fog + float fogValue = clamp((depthPassthrough - gl_Fog.start) * gl_Fog.scale, 0.0, 1.0); + gl_FragData[0].xyz = mix(gl_FragData[0].xyz, gl_Fog.color.xyz, fogValue); + +#if REFRACTION + gl_FragData[0].w = 1.0; +#else + gl_FragData[0].w = clamp(fresnel*2.0 + specular, 0.0, 1.0); +#endif +} diff --git a/files/shaders/watergles_vertex.glsl b/files/shaders/watergles_vertex.glsl new file mode 100644 index 000000000..71cc9718b --- /dev/null +++ b/files/shaders/watergles_vertex.glsl @@ -0,0 +1,24 @@ +#version 100 +precision mediump float; +precision mediump int; + +varying vec3 screenCoordsPassthrough; +varying vec4 position; +varying float depthPassthrough; + +void main(void) +{ + gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; + + mat4 scalemat = mat4(0.5, 0.0, 0.0, 0.0, + 0.0, -0.5, 0.0, 0.0, + 0.0, 0.0, 0.5, 0.0, + 0.5, 0.5, 0.5, 1.0); + + vec4 texcoordProj = ((scalemat) * ( gl_Position)); + screenCoordsPassthrough = vec3(texcoordProj.x, texcoordProj.y, texcoordProj.w); + + position = gl_Vertex; + + depthPassthrough = gl_Position.z; +} From 16c6816a6fd9c6c94db15b97681b72d6150531e7 Mon Sep 17 00:00:00 2001 From: sandstranger Date: Mon, 23 Nov 2015 20:42:30 +0300 Subject: [PATCH 2533/3725] add forgotten file for building on opengles --- components/myguiplatform/myguirendermanager.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/components/myguiplatform/myguirendermanager.cpp b/components/myguiplatform/myguirendermanager.cpp index 5bd56dc8f..5fb3054a6 100644 --- a/components/myguiplatform/myguirendermanager.cpp +++ b/components/myguiplatform/myguirendermanager.cpp @@ -17,6 +17,10 @@ #include #include "myguitexture.hpp" + +#ifdef OPENGLES + #include +#endif #define MYGUI_PLATFORM_LOG_SECTION "Platform" #define MYGUI_PLATFORM_LOG(level, text) MYGUI_LOGGING(MYGUI_PLATFORM_LOG_SECTION, level, text) From d7e27fa9f443bcc1aa6394314456ad457ef7cf70 Mon Sep 17 00:00:00 2001 From: cfcohen Date: Mon, 23 Nov 2015 16:36:59 -0500 Subject: [PATCH 2534/3725] New brief comments version of settings.cfg. --- files/settings-default.cfg | 614 ++++++++----------------------------- 1 file changed, 121 insertions(+), 493 deletions(-) diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 9a8d8c67e..6ad4ccff9 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -1,713 +1,341 @@ -# WARNING: Editing this file might have no effect, as these settings -# are overwritten by your user settings file. Your user settings file -# varies with your operating system: -# -# Linux: $HOME/.config/openmw -# Mac: $HOME/Library/Preferences/openmw -# Windows: C:\Users\Username\Documents\my games\openmw -# This path may vary depending on your installation hard drive, your -# Windows username, and your default language. +# This file provides minimal documentation for each setting, and +# ranges of recommended values. For detailed explanations of the +# significance of each setting, interaction with other settings, hard +# limits on value ranges and more information in general, please read +# the detailed documentation at the OpenMW Wiki page: +# +# https://wiki.openmw.org/index.php?title=Settings # -# Additionally, the user settings file is often written to disk when -# exiting OpenMW, so comments and changes to that file may also be -# discarded after running OpenMW. While most changes to the file will -# reflect setting changes made in game, some settings can have a wider -# range of values in the settings file than the GUI settings widgets -# allow. You may want to exercise some caution and backup this file -# when editing it by hand. +# The version of this file that actually controls the behavior of +# OpenMW is user specific, and it's location can be found in the +# documentation above. This file is probably NOT that file. [Camera] -# This floating point setting controls the distance to the near -# clipping plane. The value must be greater than zero. Values -# greater than approximately 18.0 will occasionally clip objects in -# the world in front of the character. Values greater than -# approximately 8.0 will clip the character's hands in first person -# view and/or the back of their head in third person view. +# Near clipping plane (0.01 to 18.0). near clip = 5.0 -# This boolean setting determines whether objects that render to one -# pixel or smaller will be culled. It generally improves performance -# to enable this feature. +# Cull objects smaller than one pixel. small feature culling = true -# Set the maximum visible distance. Larger values significantly -# improve rendering in exterior spaces, but also increase the amount -# rendered geometry and significantly reduce the frame rate. This -# value is a floating point value that defaults to 6666.0. This value -# interacts with the "exterior cell load distance" setting in that -# it's probably undesired for this value to provide visibility into -# cells that have not yet been loaded. When cells are visible before -# loading, the geometry will "pop-in" suddenly, creating a jarring -# visual effect. To prevent this effect, this value must be less -# than: -# -# 8192 * exterior cell load distance - 1024 -# -# The constant 8192 is the size of a cell, and 1024 is the threshold -# distance for loading a new cell. Additionally, the "field of view" -# setting also interacts with this setting because the view frustrum -# end is a plane, so you can see further at the edges of the screen -# than you should be able to. This can be observed in game by looking -# at distant objects and rotating the camera so the object are near -# the edge of the screen. As a result, the "viewing distance" setting -# should further be reduced by a factor that depends on the "field of -# view" setting. In the default configuration this reduction is 7%. -# Using this factor, approximate values recommended for other -# "exterior cell load distance" settings are: 14285 for 2 cells, 21903 -# for 3 cells, 29522 for 4 cells, and 35924 for 5 cells. -# -# Reductions of up 25% or more can be required to completely eliminate -# pop-in for wide fields of view and long viewing distances near the -# edges of the screen, but such situations are unusual and probably -# not worth the performance penalty introduced by loading geometry -# obscured by fog in the center of the screen. -# -# This setting can be adjusted in game from the ridiculously low value -# of 2000 to a maximum of 6666, using the "View Distance" slider in -# the Detail tab of the Video panel of the Options menu. See -# RenderingManager::configureFog for the relevant source code. +# Maximum visible distance (2000.0 to 6666.0+). Caution: this setting +# can dramatically affect performance, see documentation for details. viewing distance = 6666.0 [Cells] -# This integer setting determines the number of exterior cells -# adjacent to the character that will be loaded for rendering. It -# interacts with "viewing distance" and "field of view" as described -# previously, and it is generally very wasteful for this value to load -# geometry than will almost never be visible due to viewing distance -# and fog. For low frame rate screenshots of scenic vistas, this -# setting should be set high, and viewing distances adjusted -# accordingly. This value must be greater than or equal to 1. +# Adjacent exterior cells loaded (>0). Caution: this setting can +# dramatically affect performance, see documentation for details. exterior cell load distance = 1 [GUI] -# These two settings determine the background color of the tool tip -# and the crosshair when hovering over an item owned by an NPC. The -# color definitions are composed of four floating point values between -# 0.0 and 1.0 inclusive, representing the red, green, blue and alpha -# channels. The alpha value is currently ignored. The crosshair -# color will have no effect if the "crosshair" setting in the HUD -# section is disabled. These colors are used only if the "show owned" -# setting is enabled in the Game section. +# Color for tool tips and crosshair when owned by an NPC (R G B A). color background owned = 0.15 0.0 0.0 1.0 color crosshair owned = 1.0 0.15 0.15 1.0 -# This boolean setting enables or disables the "red flash" overlay -# that provides a visual clue when the character has taken damage. +# Red flash visually showing player damage. hit fader = true -# This floating point setting controls the transparency of the GUI -# windows. The value should be between 0.0 (transparent) and 1.0 -# (opaque). The setting can be adjusted in game with the "Menu -# Transparency" slider in the Prefs panel of the Options menu. +# Transparency of GUI windows (0.0 to 1.0, transparent to opaque). menu transparency = 0.84 -# This floating point setting scales the GUI interface windows. The -# value must be greater than 0.0. A value of 1.0 results in the -# default scale. Values much larger than 2.0 may result in user -# interface components being inaccessible. +# Scales GUI window and widget size. (<1 is smaller, >1 is larger). scaling factor = 1.0 -# Stretch or shrink the introductory movie, new game screen, and -# loading screens to fill the specified video resolution. The default -# assets have a 4:3 aspect ratio, but other assets may have other -# resolutions. If this setting is false, the assets will be centered -# in their correct aspect ratio. +# Stretch menus, load screens, etc. to the window aspect ratio. stretch menu background = false -# Enable or disable subtitles for NPC spoken dialog (and some sound -# effects). Subtitles will appear in a tool tip box in the lower -# center of the screen. The setting can be toggled in game with the -# "Subtitles" button in the Prefs panel of Options menu. +# Subtitles for NPC spoken dialog and some sound effects. subtitles = false -# Set the delay between when you begin hovering over an item and when -# it's tooltip appears. This setting is a floating point value -# between 0.0, which displays the tool tip instantly and 1.0 which -# results in the maximum delay (approximately 1.5 seconds). This -# setting does not affect the tooltip delay for object under the -# crosshair in the "look mode", only widgets in the GUI windows. This -# setting can be adjusted in game with the "Menu Help Delay" slider in -# the Prefs panel of the Options menu. +# Time until tool tip appears when hovering over an object (0.0 is +# instantly, 1.0 is the maximum delay of about 1.5 seconds). tooltip delay = 0.0 -# Enable or disable the werewolf overlay. Unable to evaluate fully -# due to issues with becoming a werewolf. +# Werewolf overlay border around screen or window. werewolf overlay = true [Game] -# If this boolean setting is true, the character will always use the -# most powerful attack when striking with a weapon (chop, slash or -# thrust). If this setting is false, the type of attack is determined -# by the direction that the character is moving at the time the attack -# begins. The setting can be toggled with the "Always Use Best -# Attack" button in the Prefs panel of the Options menu. +# Always use the best mode of attack: e.g. chop, slash or thrust. best attack = false -# This integer setting adjusts the difficulty of the game and is -# intended to be in the range -100 to 100 inclusive. Given the -# default game setting for fDifficultyMult of 5.0, a value of -100 -# results in the player taking 80% of the usual damage, doing 6 times -# the normal damage. A value of 100 results in the player taking 6 -# times as much damage, but inflicting only 80% of the usual damage. -# Values less than -500 will result in the player receiving no damage, -# and values greater than 500 will result in the player inflicting no -# damage. The setting can be controlled in game with the Difficulty -# slider in the Prefs panel of the Options menu. +# Difficulty. Expressed as damage dealt and received. (-100 to 100). difficulty = 0 -# Show the remaining duration of magic effects and lights if this -# boolean setting is true. The remaining duration is displayed in the -# tooltip by hovering over the magical effect. +# Show duration of magic effect and lights in the spells window. show effect duration = false -# Enable visual clues for items owned by NPCs when the crosshair is on -# the object. If the setting is 0, no clues are provided which is the -# default Morrowind behavior. If the setting is 1, the background of -# the tool tip for the object is highlight in the color specified by -# the "color background owned" setting in the "GUI" section. If the -# setting is 2, the crosshair is the color of the "color crosshair -# owned" setting in the "GUI" section. If the setting is 3, both the -# tool tip background and the crosshair are colored. Settings 2 and 3 -# only color the crosshair if it's enabled in the "HUD" section. +# Color crosshair and tool tip when object is owned by an NPC. (O is +# no color, 1 is tool tip only, 2 is crosshair only, and 3 is both). show owned = 0 [General] -# Set the maximum anisotropic filtering on textures. Anisotropic -# filtering is a method of enhancing the image quality of textures on -# surfaces that are at oblique viewing angles with respect to the -# camera. Valid values range from 0 to 16. Modern video cards can -# often perform 8 or 16 anisotropic filtering with a minimal -# performance impact. This effect of this setting can be seen in the -# Video panel of the Options menu by finding a location with straight -# lines (striped rugs and Balmora cobblestones work well) radiating -# into the distance, and adjusting the anisotropy slider. This -# setting can be changed in game using the "Anisotropy" slider in the -# Detail tab of the Video panel of the Options menu. +# Anisotropy reduces distortion in textures at low angles (0 to 16). anisotropy = 4 -# Sets the camera field of view in degrees. Recommended values range -# from 30 degrees to 110 degrees. Small values provide a very narrow -# field of view that creates a "zoomed in" effect, while large values -# cause distortion at the edges of the screen. The "field of view" -# setting interacts with aspect ratio of your video resolution in that -# more square aspect ratios (e.g. 4:3) need a wider field of view to -# more resemble the same field of view on a widescreen (e.g. 16:9) -# monitor. This setting can be adjusted in game from the Video tab of -# the Video panel of the Options menu using the "Field of View" -# slider. +# Camera field of view in degrees (30.0 to 110.0). field of view = 55.0 -# Specify the format for screenshots taken by pressing F12. This -# setting should be the file extension commonly associated with the -# desired format. The formats supported will be determined at -# compilation, but "jpg", "png", and "tga" should be allowed. +# File format for screenshots. (jpg, png, tga, and possibly more). screenshot format = png -# Set the isotropic texture filtering mode to bilinear or trilinear. -# Bilinear filtering is a texture filtering method used to smooth -# textures when displayed larger or smaller than they actually are. -# Bilinear filtering is reasonably accurate until the scaling of the -# texture gets below half or above double the original size of the -# texture. Trilinear filtering is an extension of the bilinear -# texture filtering method, which also performs linear interpolation -# between mipmaps. Both methods use mipmaps in OpenMW, and the -# corresponding OpenGL modes are LINEAR_MIPMAP_NEAREST and -# LINEAR_MIPMAP_LINEAR. Trilinear filtering produces better texturing -# at a minimal cost on modern video cards. This setting can be -# changed in game using the "Texture filtering" pull down in the -# Detail tab of the Video panel of the Options menu. +# Isotropic texture filtering. (bilinear or trilinear). texture filtering = trilinear [HUD] -# This boolean setting determines whether the crosshair or reticle is -# displayed. If this setting is disabled it will override "show -# owned" and "color crosshair owned". This setting can be toggled -# with the "Crosshair" button in the Prefs panel of the Options menu. +# Displays the crosshair or reticle when not in GUI mode. crosshair = true [Input] -# Allow zooming in and out using the middle mouse wheel in third -# person view. +# Zoom in and out from player in third person view with mouse wheel. allow third person zoom = false -# If this boolean setting is true, the character is running by -# default, otherwise the character is walking by default. The shift -# key will temporarily invert this setting, and the caps lock key will -# invert this setting while it's "locked". Confusingly, this setting -# is updated every time you exit the game, based on whether the caps -# lock key was on or off at the time you exited. +# Player is running by default. always run = false -# This floating point setting controls the camera/mouse sensitivity -# when in "look mode". The default sensitivity is 1.0, with smaller -# values requiring more mouse movement, and larger values requiring -# less. This setting is multiplicative in magnitude. This setting -# does not affect mouse speed in GUI mode. +# Camera sensitivity when not in GUI mode. (0.1 to 5.0). camera sensitivity = 1.0 -# This floating point setting controls the vertical camera/mouse -# sensitivity relative to the horizontal sensitivity (see "camera -# sensitivity") above. It is multiplicative with the previous -# setting, meaning that it should remain set at 1.0 unless the player -# desires to have different sensitivities in the two axes. +# Vertical camera sensitivity multiplier when not in GUI mode. +# Because it's a multiplier values should be near one (0.5 to 1.5). camera y multiplier = 1.0 -# OpenMW will capture control of the cursor if this boolean setting is -# true. In "look mode", OpenMW will capture the cursor regardless of -# the value of this setting (since the cursor/crosshair is always -# centered in the OpenMW window). However, in GUI mode, this setting -# determines the behavior when the cursor is moved outside the OpenMW -# window. If true, the cursor movement stops at the edge of the -# window preventing access to other applications. If false, the -# cursor is allowed to move freely on the desktop. -# -# This setting does not apply to the screen where escape has been -# pressed, where the cursor is never captured. Regardless of this -# setting "Alt-Tab" or some other operating system dependent key -# sequence can be used to allow the operating system to regain control -# of the mouse cursor. This setting interacts with the "minimize on -# focus loss" setting by affecting what counts as a focus loss. -# Specifically on a two-screen configuration it may be more convenient -# to access the second screen with setting disabled. +# Capture control of the cursor prevent movement outside the window. grab cursor = true -# Invert the vertical axis while in "look mode". If this setting is -# true, moving the mouse away from the player will look down, while -# moving it towards the player will look up. This setting does not -# affect cursor movement in GUI mode. +# Invert the vertical axis while not in GUI mode. invert y axis = false -# This boolean setting causes the behavior of the sneak key (Ctrl by -# default) to toggle sneaking on and off rather than requiring the key -# to be held while sneaking. Players that spend significant time -# sneaking may find the character easier to control with this option -# enabled. +# Key controlling sneak toggles setting instead of being held down. toggle sneak = false -# This setting continues to be loaded and saved, but has no known -# effect. Presumably it and a related but also removed option named -# "ui y sensitivity" used to control mouse sensitivity while in GUI -# mode. The default value is 1.0. -ui sensitivity = 1.0 - [Map] -# It is not currently possible to control how many adjacent cells are -# displayed in the map. It appears that this is hardcoded to one -# adjacent cell (3x3) in the code. These settings control the canvas -# and resolution sizes, and therefore the amount of panning required -# to see the entire map, and the level of detail visible. - -# This integer setting adjusts the scale of the world map in the GUI -# mode map display. The value is the width in pixels of each cell in -# the map, so larger values result in larger more detailed world maps, -# while smaller values result in smaller less detailed world maps. -# However, the native resolution of the map source material appears to -# be 9 pixels per unexplored cell and approximately 18 pixels per -# explored cell, so values larger than 36 don't produce much -# additional detail. Similarly, the size of place markers is -# currently fixed at 12 pixels, so values smaller than this result in -# overlapping place markers. Values from 12 to 36 are recommended. -# For reference, Vvardenfell is approximately 41x36 cells. +# Size of each exterior cell in pixels in the world map. (12 to 24). +# Warning: affects explored areas in save files, see documentation. global map cell size = 18 -# This integer setting controls the zoom level for the HUD map display -# (the map in the lower right corner while not in GUI mode). A value -# of 64 results in the HUD map displaying one exterior cell. Since -# the GUI mode map displays 3x3 cells, a value of approximately 21 -# displays the same area as the GUI mode map. Larger values increase -# the level of zoom, while smaller values are wasteful. -# -# Note that the actual size of the widget is always the same on the -# screen unless the "scaling factor" setting in the "GUI" section is -# changed. Increasing both the scaling factor of the GUI and this -# setting does result in a higher resolution HUD map, but -# unfortunately with a scaled direction pointer on top of it. +# Zoom level in pixels for HUD map widget. 64 is one cell, 128 is 1/4 +# cell, 256 is 1/8 cell. See documentation for details. (64 to 256). local map hud widget size = 256 -# This integer setting controls the resolution of the GUI mode local -# map widget. Larger values generally increase the visible detail in -# map. If this setting is half the "local map widget size" or -# smaller, the map will generally be be fairly blurry. Setting the -# both options to the same value results in a map with good detail. -# Values that exceed the "local map widget size" setting by more than -# a factor of two are unlikely to provide much of an improvement in -# detail since they're subsequently scaled back to the approximately -# the map widget size before display. The video resolution setting -# interacts with this setting in that regard. +# Resolution of local map in GUI window in pixels. See documentation +# for details which may affect cell load performance. (128 to 1024). local map resolution = 256 -# This integer setting controls the canvas size of the GUI mode local -# map widget. Larger values result in a larger physical map size on -# screen, and typically require more panning to see all available -# portions of the map. This larger size also enables an overall -# greater level of detail if the "local map resolution" setting is -# also increased. +# Size of local map in GUI window in pixels. See documentation for +# details which may affect cell load performance. (256 to 1024). local map widget size = 512 [Objects] -# This boolean setting currently has no known impact, but is -# presumably intended to enable shaders for objects other than water. -# Whenever the setting file is written by the game, this option is -# currently reset to false. +# Enable shaders for objects other than water. Unused. shaders = true [Saves] -# This string setting contains the default character name for loading -# saved games. This setting is automatically updated from the Load -# game menu option when a different character is selected. -character = - -# This boolean setting determines whether the game will be -# automatically saved when the character rests. This setting can be -# toggled in game with the "Auto-Save when Rest" button in the Prefs -# panel of the Options menu. +# Automatically save the game whenever the player rests. autosave = true -# This boolean setting determines whether the amount of the time the -# player has spent playing will displayed for each saved game in the -# menu for saving and loading games. This setting can not currently -# be adjusted in game. This setting is disabled by default for players -# who would prefer not to know how many hours they've spent -# playing. :-) +# Name of last character played, and default for loading save files. +character = + +# Display the time played on each save file in the load menu. timeplayed = false [Shadows] -# Shadows in general are dependent on the "shaders" setting be enabled -# in the Objects section. Additionally, the "enabled" setting in this -# section must be true for any other options in this section to have -# effect. Both that setting and the Shadows section options are -# temporarily disabled following the conversion to the OpenSceneGraph -# engine. None of these option can be adjusted in game at the present -# time. - -# This boolean setting enables actors to cast shadows. +# Actors cast shadows. Unused. actor shadows = true -# Enable debugging of shadows? +# Debugging of shadows. Unused. debug = false -# Are shadows enabled in general? +# Enable shadows. Other shadow settings disabled if false. Unused. enabled = false -# This floating point setting determines the fraction of the total -# shadow distance after which the shadow starts to fade out. +# Fraction of distance after which shadow starts to fade out. Unused. fade start = 0.8 -# Allows miscellaneous object to cast shadows. +# Miscellaneous object cast shadows. misc shadows = true -# This setting will only have effect if the "split" setting in the -# Shadows section is false. Increasing shadow distance will lower the -# shadow quality. +# Distance for shadows if not split. Smaller is poorer. Unused. shadow distance = 1300 -# Split the shadow maps, allowing for a larger shadow distance? +# Split shadow maps, allowing for a larger shadow distance. Unused. split = false -# This setting will only have effect if the "split" setting in the -# Shadows section is true. # This one shouldn't be too low, otherwise -# you'll see artifacts. Use at least 2x max viewing distance. +# Distance for shadows if split. Unused. split shadow distance = 14000 -# Allow static objects to cast shadows. +# Static objects cast shadows. Unused. statics shadows = true -# Allow terrain to cast shadows. +# Terrain cast shadows. Unused. terrain shadows = true -# Size of the shadow textures. Higher resolution texture produce more -# detailed shadows and a better visual effect. +# Size of the shadow textures in pixels. Unused. (256 to 2048). texture size = 1024 [Sound] -# This string setting determines which audio device to use. A blank or -# missing setting means to use the default device, which should -# usually be sufficient, but if you need to explicitly specify a -# device name try doing so here. +# Name of audio device file. Blank means use the default device. device = -# The settings in the Sound section are generally floating point -# settings in the range from 0.0 (silent) to 1.0 (maximum volume). -# All sound settings are multiplied by the "master volume" setting, and -# will thus have no effect if the master volume is set to 0.0. These -# settings can be adjusted in game from the Audio panel of the Options -# menu under the appropriately labeled slider. +# Volumes are 0.0 for silent and 1.0 for the maximum volume. -# The volume of footsteps from the character and other actors. +# Footsteps volume. footsteps volume = 0.2 -# The master volume is multiplied with all other volume settings to -# determine the final volume +# Master volume. Controls all other volumes. master volume = 1.0 -# The volume for music tracks. +# Music tracks volume. music volume = 0.5 -# The volume for special effect sounds such as combat noises, etc. +# Sound effects volume. sfx volume = 1.0 -# The volume for spoken dialog from NPCs. +# Voice dialog volume. voice volume = 0.8 [Terrain] -<<<<<<< HEAD -# Not currently used, presumably due to the OpenSceneGraph upgrade. +# Distant land is rendered? Unused. distant land = false -# Not currently used, presumably due to the OpenSceneGraph upgrade. +# Use shaders for terrain? Unused. shader = true -======= -camera y multiplier = 1.0 ->>>>>>> upstream/master [Video] -# This integer setting controls anti-aliasing. Anti-aliasing is -# technique designed to reduce distortions called aliasing caused by -# displaying high resolution textures at a lower resolution. -# Anti-aliasing can correct these distortions at the cost of a minor -# reduction in the frame rate. A value of 0 disables anti-aliasing. -# Other powers of two (e.g. 2, 4, 8, 16) are supported according to -# the capabilities of your graphics hardware. Higher values do a -# better job of correcting the distortion and have a greater impact on -# frame rate. This setting can be configured from a list of valid -# choices in the Graphics panel of the OpenMW Launcher. +# Anti-aliasing reduces texture distortion. (0, 2, 4, 8, 16). antialiasing = 0 -# This floating point setting controls the contrast correction for all -# video in the game. This setting does not currently work under -# Linux, and the in-game setting in the Options menu has been -# disabled. -contrast = 1.00 - -# This floating point setting determines the maximum frame rate in -# frames per second. If this setting is 0.0, the frame rate is -# unlimited. There are several reasons to consider capping your frame -# rate, especially if you're already experiencing a relatively high -# frame rate (greater than 60 frames per second). Lower frame rates -# will consume less power and generate less heat and noise. Frame -# rates above 60 frames per second rarely produce perceptible -# improvements in visual quality. Capping the frame rate may in some -# situations reduce the perception of choppiness (highly variable -# frame rates during game play) by lowering the peak frame rates. -# This setting interacts with the "vsync" setting in the Video section -# in the sense that enabling vertical sync limits the frame rate to -# the refresh rate of your monitor (often 60 frames per second). +# Game video contrast. (0.0 to 1.0). No effect in Linux. +contrast = 1.0 + +# Maximum frames per second. (1.0 to 200.0). framerate limit = 0.0 -# This boolean setting determines whether the entire screen is used -# for the specified resolution. This setting can be toggled in game -# using the "Fullscreen" button in the Video tab of the Video panel in -# the Options menu. It can also be toggled with the "Full Screen" -# check box in the Graphic tab of the OpenMW Launcher. +# OpenMW takes complete control of the screen. fullscreen = false -# Theses two setting determine the horizontal and vertical resolution -# of the OpenMW game window. Larger values produce more detailed -# images within the constraints of your graphics hardware but also -# significantly reduce the frame rate. The window resolution can be -# selected from a menu of common screen sizes in the Video tab of the -# Video Panel of the Options menu. The resolution can also be set to -# a custom value in the Graphics tab of the OpenMW Launcher. +# Resolution of the Open window or screen. (600 to 2560). resolution x = 800 resolution y = 600 -# This boolean setting determines whether there's an operating system -# border drawn around the OpenMW window. If this setting is true, the -# window can be moved and resized with the operating system window -# controls. If this setting is false, the window has no operating -# system border. This setting has no effect if the "fullscreen" -# setting in the Video section is true. This setting can be toggled -# in game using the "Window Border" button in the Video tab of the -# Video panel in the Options menu. It can also be toggled with the -# "Window Border" check box in the OpenMW Launcher. +# An operating system border is drawn around the OpenMW window. window border = true -# This integer setting determines which screen the game will open on -# in multi-monitor configurations. This setting is particularly -# important when "fullscreen" setting in the Video section is true, -# since this is the only way to control which screen is used, but it -# can also be used to control which screen a normal window or a -# borderless window opens on as well. This setting can be selected -# from a pull down menu in the Graphics tab of the OpenMW Launcher, -# but not adjusted during game play. +# Determines which screen OpenMW is on. (0 or 1). screen = 0 -# Minimize the OpenMW window if it loses cursor focus. This setting -# has no effect if the "fullscreen" setting is false. This setting is -# primarily useful for single screen configurations, so that the -# OpenMW screen in full screen mode can be minimized when the -# operating system regains control of the mouse and keyboard. On -# multiple screen configurations, disabling this option make make it -# easier to switch between screens while playing OpenMW. +# Minimize OpenMW if it loses cursor or keyboard focus. minimize on focus loss = true -# This boolean setting determines whether frame draws are synchronized -# with the vertical refresh rate of your monitor. Enabling this -# setting can reduce "tearing", a visual defect caused by updating the -# image buffer in the middle of a screen draw. Enabling this option -# typically implies limiting the framerate to 60 frames per second, -# but may also introduce additional delays caused by having to wait -# until the appropriate time (the vertical blanking interval) to draw -# a frame. - -# This setting can be adjusted in game using the "VSync" button in the -# Video tab of the Video panel in the Options menu. It can also be -# changed by toggling the "Vertical Sync" check box in the Graphics -# tab of the OpenMW Launcher. +# Enable vertical syncing to reduce tearing defects. vsync = false -# This floating point setting controls the gamma correction for all -# video in the game. This setting does not currently work under -# Linux, and the in-game setting in the Options menu has been -# disabled. -gamma = 1.00 +# Video gamma setting. (0.0 to 1.0). No effect in Linux. +gamma = 1.0 [Water] -# The water settings can be tested experimentally in the Water tab of -# the Video panel in the Options menu. Changes there will be saved to -# these settings. - -# This boolean setting enables the refraction rendering feature of the -# water shader. Refraction causes deep water to be more opaque and -# objects seen through the plane of the water to have a wavy -# appearance. Enabling this feature results in better visuals, and a -# marginally lower framerate depending on your graphics hardware. The -# "shader" setting in the Water section must be enabled for this -# setting to have any effect. +# Enable refraction which affects visibility through water plane. refraction = false -# Refracted texture size. In the Video panel of the options menu, the -# choices are Low (512), Medium (1024) and High (2048). This setting -# determines the resolution of the textures used for rendering objects -# on the other wide of the plane of water (which have a wavy -# appearance caused the by the refraction). Higher values produces -# better visuals and result in a marginally lower framerate depending -# on your graphics hardware. The "refraction" setting in the "Water" -# section must be enabled for this setting to have any effect. +# Reflection and refraction texture size in pixels. (512, 1024, 2048). rtt size = 512 -# This boolean setting enables or disables the water shader, which -# results in much more realistic looking water surfaces, including -# shadows of reflected objects. +# Enable water shader with reflections and optionally refraction. shader = false [Windows] -# Each window in the GUI mode remembers it's previous location. Each -# setting is a floating point number representing a fraction of the -# "resolution x" or "resolution y" setting in the Video section. The -# X and Y values locate the top left corner, while the W value -# determines the width of the window and the H value determines the -# height of the window. +# Location and sizes of windows as a fraction of the OpenMW window or +# screen size. (0.0 to 1.0). X & Y, Height & Width. -# The alchemy window, for crafting potions. Activated by dragging an -# alchemy tool on to the rag doll. Unlike most other windows, this -# window hides all other windows when opened. +# Alchemy window for crafting potions. alchemy h = 0.5 alchemy w = 0.5 alchemy x = 0.25 alchemy y = 0.25 -# The NPC bartering window, displaying goods owned by the shopkeeper -# while bartering. Activated by clicking on the "Barter" choice in -# the dialog window for an NPC. +# NPC inventory window when bartering with a shopkeeper. barter h = 0.375 barter w = 0.75 barter x = 0.25 -barter y = 0 +barter y = 0.0 -# Unused? +# NPC inventory window when trading with a companion. companion h = 0.375 companion w = 0.75 companion x = 0.25 -companion y = 0 +companion y = 0.0 -# The console command window. Activated by pressing the tilde (~) key. +# Console command window for debugging commands. console h = 0.5 -console w = 1 -console x = 0 -console y = 0 +console w = 1.0 +console x = 0.0 +console y = 0.0 -# The container window, showing the contents of the container. -# Activated by clicking on a container. The same window is used for -# searching dead bodies, and pickpocketing people. +# Container inventory when searching a container. container h = 0.375 container w = 0.75 container x = 0.25 -container y = 0 +container y = 0.0 -# The dialog window, for talking with NPCs. Activated by clicking on a -# NPC. +# Dialog window for talking with NPCs. dialogue h = 0.810 dialogue w = 0.810 dialogue x = 0.095 dialogue y = 0.095 -# The character inventory window while bartering. It displays goods -# owned by the character while bartering. Activated by clicking on the -# "Barter" choice in the dialog window for an NPC. +# Player inventory window when bartering with a shopkeeper. inventory barter h = 0.5725 inventory barter w = 0.6225 -inventory barter x = 0 +inventory barter x = 0.0 inventory barter y = 0.4275 -# Unused? +# Player inventory window when trading with a companion. inventory companion h = 0.5725 inventory companion w = 0.6225 -inventory companion x = 0 +inventory companion x = 0.0 inventory companion y = 0.4275 -# The character inventory window while searching a container, showing -# the contents of the character's inventory. Activated by clicking on -# a container. The same window is used for searching dead bodies, and -# pickpocketing people. +# Player inventory window when searching a container. inventory container h = 0.5725 inventory container w = 0.6225 -inventory container x = 0 +inventory container x = 0.0 inventory container y = 0.4275 -# The inventory window, displaying the paper doll and possessions. -# Activated by clicking on the inventory widget (second from left) in -# the bottom left corner of the HUD. +# Player inventory window when explicitly opened. inventory h = 0.5725 inventory w = 0.6225 -inventory x = 0 +inventory x = 0.0 inventory y = 0.4275 -# The local and world map window. Activated by clicking on the map -# widget in the bottom right corner of the HUD. +# Local and world map window. map h = 0.5725 map w = 0.375 map x = 0.625 -map y = 0 +map y = 0.0 -# The spells window, displaying powers, spells, and magical items. -# Activated by clicking on the spells widget (third from left) in the -# bottom left corner of the HUD. +# Spells window displaying powers, spells, and magical items. spells h = 0.4275 spells w = 0.375 spells x = 0.625 spells y = 0.5725 -# The stats window, displaying level, race, class, skills and stats. -# Activated by clicking on any of the three bars in the lower left -# corner of the HUD. +# Stats window displaying level, race, class, skills and stats. stats h = 0.4275 stats w = 0.375 -stats x = 0 -stats y = 0 +stats x = 0.0 +stats y = 0.0 From 89100088f35a66834e83ce88979226898f55c450 Mon Sep 17 00:00:00 2001 From: cfcohen Date: Mon, 23 Nov 2015 20:07:48 -0500 Subject: [PATCH 2535/3725] The latest version of the settings.cfg without any code changes. --- files/settings-default.cfg | 354 ++++++++++++++++++------------------- 1 file changed, 177 insertions(+), 177 deletions(-) diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 6ad4ccff9..3b91e7f0a 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -8,7 +8,7 @@ # # The version of this file that actually controls the behavior of # OpenMW is user specific, and it's location can be found in the -# documentation above. This file is probably NOT that file. +# documentation above. This file is probably NOT that file... [Camera] @@ -28,36 +28,63 @@ viewing distance = 6666.0 # dramatically affect performance, see documentation for details. exterior cell load distance = 1 -[GUI] +[Map] -# Color for tool tips and crosshair when owned by an NPC (R G B A). -color background owned = 0.15 0.0 0.0 1.0 -color crosshair owned = 1.0 0.15 0.15 1.0 +# Size of each exterior cell in pixels in the world map. (12 to 24). +# Warning: affects explored areas in save files, see documentation. +global map cell size = 18 -# Red flash visually showing player damage. -hit fader = true +# Zoom level in pixels for HUD map widget. 64 is one cell, 128 is 1/4 +# cell, 256 is 1/8 cell. See documentation for details. (64 to 256). +local map hud widget size = 256 -# Transparency of GUI windows (0.0 to 1.0, transparent to opaque). -menu transparency = 0.84 +# Resolution of local map in GUI window in pixels. See documentation +# for details which may affect cell load performance. (128 to 1024). +local map resolution = 256 + +# Size of local map in GUI window in pixels. See documentation for +# details which may affect cell load performance. (256 to 1024). +local map widget size = 512 + +[GUI] # Scales GUI window and widget size. (<1 is smaller, >1 is larger). scaling factor = 1.0 +# Transparency of GUI windows (0.0 to 1.0, transparent to opaque). +menu transparency = 0.84 + +# Time until tool tip appears when hovering over an object (0.0 is +# instantly, 1.0 is the maximum delay of about 1.5 seconds). +tooltip delay = 0.0 + # Stretch menus, load screens, etc. to the window aspect ratio. stretch menu background = false # Subtitles for NPC spoken dialog and some sound effects. subtitles = false -# Time until tool tip appears when hovering over an object (0.0 is -# instantly, 1.0 is the maximum delay of about 1.5 seconds). -tooltip delay = 0.0 +# Red flash visually showing player damage. +hit fader = true # Werewolf overlay border around screen or window. werewolf overlay = true +# Color for tool tips and crosshair when owned by an NPC (R G B A). +color background owned = 0.15 0.0 0.0 1.0 +color crosshair owned = 1.0 0.15 0.15 1.0 + +[HUD] + +# Displays the crosshair or reticle when not in GUI mode. +crosshair = true + [Game] +# Color crosshair and tool tip when object is owned by an NPC. (O is +# no color, 1 is tool tip only, 2 is crosshair only, and 3 is both). +show owned = 0 + # Always use the best mode of attack: e.g. chop, slash or thrust. best attack = false @@ -67,10 +94,6 @@ difficulty = 0 # Show duration of magic effect and lights in the spells window. show effect duration = false -# Color crosshair and tool tip when object is owned by an NPC. (O is -# no color, 1 is tool tip only, 2 is crosshair only, and 3 is both). -show owned = 0 - [General] # Anisotropy reduces distortion in textures at low angles (0 to 16). @@ -85,19 +108,20 @@ screenshot format = png # Isotropic texture filtering. (bilinear or trilinear). texture filtering = trilinear -[HUD] - -# Displays the crosshair or reticle when not in GUI mode. -crosshair = true - [Input] -# Zoom in and out from player in third person view with mouse wheel. -allow third person zoom = false +# Capture control of the cursor prevent movement outside the window. +grab cursor = true + +# Key controlling sneak toggles setting instead of being held down. +toggle sneak = false # Player is running by default. always run = false +# Zoom in and out from player in third person view with mouse wheel. +allow third person zoom = false + # Camera sensitivity when not in GUI mode. (0.1 to 5.0). camera sensitivity = 1.0 @@ -105,84 +129,20 @@ camera sensitivity = 1.0 # Because it's a multiplier values should be near one (0.5 to 1.5). camera y multiplier = 1.0 -# Capture control of the cursor prevent movement outside the window. -grab cursor = true - # Invert the vertical axis while not in GUI mode. invert y axis = false -# Key controlling sneak toggles setting instead of being held down. -toggle sneak = false - -[Map] - -# Size of each exterior cell in pixels in the world map. (12 to 24). -# Warning: affects explored areas in save files, see documentation. -global map cell size = 18 - -# Zoom level in pixels for HUD map widget. 64 is one cell, 128 is 1/4 -# cell, 256 is 1/8 cell. See documentation for details. (64 to 256). -local map hud widget size = 256 - -# Resolution of local map in GUI window in pixels. See documentation -# for details which may affect cell load performance. (128 to 1024). -local map resolution = 256 - -# Size of local map in GUI window in pixels. See documentation for -# details which may affect cell load performance. (256 to 1024). -local map widget size = 512 - -[Objects] - -# Enable shaders for objects other than water. Unused. -shaders = true - [Saves] -# Automatically save the game whenever the player rests. -autosave = true - # Name of last character played, and default for loading save files. character = +# Automatically save the game whenever the player rests. +autosave = true + # Display the time played on each save file in the load menu. timeplayed = false -[Shadows] - -# Actors cast shadows. Unused. -actor shadows = true - -# Debugging of shadows. Unused. -debug = false - -# Enable shadows. Other shadow settings disabled if false. Unused. -enabled = false - -# Fraction of distance after which shadow starts to fade out. Unused. -fade start = 0.8 - -# Miscellaneous object cast shadows. -misc shadows = true - -# Distance for shadows if not split. Smaller is poorer. Unused. -shadow distance = 1300 - -# Split shadow maps, allowing for a larger shadow distance. Unused. -split = false - -# Distance for shadows if split. Unused. -split shadow distance = 14000 - -# Static objects cast shadows. Unused. -statics shadows = true - -# Terrain cast shadows. Unused. -terrain shadows = true - -# Size of the shadow textures in pixels. Unused. (256 to 2048). -texture size = 1024 - [Sound] # Name of audio device file. Blank means use the default device. @@ -190,12 +150,12 @@ device = # Volumes are 0.0 for silent and 1.0 for the maximum volume. -# Footsteps volume. -footsteps volume = 0.2 - # Master volume. Controls all other volumes. master volume = 1.0 +# Footsteps volume. +footsteps volume = 0.2 + # Music tracks volume. music volume = 0.5 @@ -205,34 +165,14 @@ sfx volume = 1.0 # Voice dialog volume. voice volume = 0.8 -[Terrain] - -# Distant land is rendered? Unused. -distant land = false - -# Use shaders for terrain? Unused. -shader = true - [Video] -# Anti-aliasing reduces texture distortion. (0, 2, 4, 8, 16). -antialiasing = 0 - -# Game video contrast. (0.0 to 1.0). No effect in Linux. -contrast = 1.0 - -# Maximum frames per second. (1.0 to 200.0). -framerate limit = 0.0 - -# OpenMW takes complete control of the screen. -fullscreen = false - # Resolution of the Open window or screen. (600 to 2560). resolution x = 800 resolution y = 600 -# An operating system border is drawn around the OpenMW window. -window border = true +# OpenMW takes complete control of the screen. +fullscreen = false # Determines which screen OpenMW is on. (0 or 1). screen = 0 @@ -240,102 +180,162 @@ screen = 0 # Minimize OpenMW if it loses cursor or keyboard focus. minimize on focus loss = true +# An operating system border is drawn around the OpenMW window. +window border = true + +# Anti-aliasing reduces texture distortion. (0, 2, 4, 8, 16). +antialiasing = 0 + # Enable vertical syncing to reduce tearing defects. vsync = false +# Maximum frames per second. (1.0 to 200.0). +framerate limit = 0.0 + +# Game video contrast. (0.0 to 1.0). No effect in Linux. +contrast = 1.0 + # Video gamma setting. (0.0 to 1.0). No effect in Linux. gamma = 1.0 [Water] -# Enable refraction which affects visibility through water plane. -refraction = false +# Enable water shader with reflections and optionally refraction. +shader = false # Reflection and refraction texture size in pixels. (512, 1024, 2048). rtt size = 512 -# Enable water shader with reflections and optionally refraction. -shader = false +# Enable refraction which affects visibility through water plane. +refraction = false + +[Objects] + +# Enable shaders for objects other than water. Unused. +shaders = true + +[Terrain] + +# Use shaders for terrain? Unused. +shader = true + +# Distant land is rendered? Unused. +distant land = false + +[Shadows] + +# Enable shadows. Other shadow settings disabled if false. Unused. +enabled = false + +# Size of the shadow textures in pixels. Unused. (256 to 2048). +texture size = 1024 + +# Actors cast shadows. Unused. +actor shadows = true + +# Static objects cast shadows. Unused. +statics shadows = true + +# Terrain cast shadows. Unused. +terrain shadows = true + +# Miscellaneous objects cast shadows. Unused. +misc shadows = true + +# Debugging of shadows. Unused. +debug = false + +# Fraction of distance after which shadow starts to fade out. Unused. +fade start = 0.8 + +# Split shadow maps, allowing for a larger shadow distance. Unused. +split = false + +# Distance for shadows if not split. Smaller is poorer. Unused. +shadow distance = 1300 + +# Distance for shadows if split. Unused. +split shadow distance = 14000 [Windows] # Location and sizes of windows as a fraction of the OpenMW window or -# screen size. (0.0 to 1.0). X & Y, Height & Width. +# screen size. (0.0 to 1.0). X & Y, Width & Height. + +# Stats window displaying level, race, class, skills and stats. +stats x = 0.0 +stats y = 0.0 +stats w = 0.375 +stats h = 0.4275 + +# Spells window displaying powers, spells, and magical items. +spells x = 0.625 +spells y = 0.5725 +spells w = 0.375 +spells h = 0.4275 + +# Local and world map window. +map x = 0.625 +map y = 0.0 +map w = 0.375 +map h = 0.5725 + +# Dialog window for talking with NPCs. +dialogue x = 0.095 +dialogue y = 0.095 +dialogue w = 0.810 +dialogue h = 0.810 # Alchemy window for crafting potions. -alchemy h = 0.5 -alchemy w = 0.5 alchemy x = 0.25 alchemy y = 0.25 - -# NPC inventory window when bartering with a shopkeeper. -barter h = 0.375 -barter w = 0.75 -barter x = 0.25 -barter y = 0.0 - -# NPC inventory window when trading with a companion. -companion h = 0.375 -companion w = 0.75 -companion x = 0.25 -companion y = 0.0 +alchemy w = 0.5 +alchemy h = 0.5 # Console command window for debugging commands. -console h = 0.5 -console w = 1.0 console x = 0.0 console y = 0.0 +console w = 1.0 +console h = 0.5 -# Container inventory when searching a container. -container h = 0.375 -container w = 0.75 -container x = 0.25 -container y = 0.0 +# Player inventory window when explicitly opened. +inventory x = 0.0 +inventory y = 0.4275 +inventory w = 0.6225 +inventory h = 0.5725 -# Dialog window for talking with NPCs. -dialogue h = 0.810 -dialogue w = 0.810 -dialogue x = 0.095 -dialogue y = 0.095 +# Player inventory window when searching a container. +inventory container x = 0.0 +inventory container y = 0.4275 +inventory container w = 0.6225 +inventory container h = 0.5725 # Player inventory window when bartering with a shopkeeper. -inventory barter h = 0.5725 -inventory barter w = 0.6225 inventory barter x = 0.0 inventory barter y = 0.4275 +inventory barter w = 0.6225 +inventory barter h = 0.5725 # Player inventory window when trading with a companion. -inventory companion h = 0.5725 -inventory companion w = 0.6225 inventory companion x = 0.0 inventory companion y = 0.4275 +inventory companion w = 0.6225 +inventory companion h = 0.5725 -# Player inventory window when searching a container. -inventory container h = 0.5725 -inventory container w = 0.6225 -inventory container x = 0.0 -inventory container y = 0.4275 - -# Player inventory window when explicitly opened. -inventory h = 0.5725 -inventory w = 0.6225 -inventory x = 0.0 -inventory y = 0.4275 - -# Local and world map window. -map h = 0.5725 -map w = 0.375 -map x = 0.625 -map y = 0.0 +# Container inventory when searching a container. +container x = 0.25 +container y = 0.0 +container w = 0.75 +container h = 0.375 -# Spells window displaying powers, spells, and magical items. -spells h = 0.4275 -spells w = 0.375 -spells x = 0.625 -spells y = 0.5725 +# NPC inventory window when bartering with a shopkeeper. +barter x = 0.25 +barter y = 0.0 +barter w = 0.75 +barter h = 0.375 -# Stats window displaying level, race, class, skills and stats. -stats h = 0.4275 -stats w = 0.375 -stats x = 0.0 -stats y = 0.0 +# NPC inventory window when trading with a companion. +companion x = 0.25 +companion y = 0.0 +companion w = 0.75 +companion h = 0.375 From 9a975a2e684e030650d064c70e05dcdfcd956df9 Mon Sep 17 00:00:00 2001 From: cfcohen Date: Mon, 23 Nov 2015 18:10:33 -0500 Subject: [PATCH 2536/3725] Substantial rewrite of code to save settings.cfg file, allowing comments to persist, ordering of settings to be retained, additional reporting of changed settings, preservation of the settings.cfg timestamp when no changes are made, and foundational changes for possible future features. Due to poor interaction with the openmw-launcher settings code, the launcher will still discard all of these benefits. --- components/settings/settings.cpp | 241 +++++++++++++++++++++++++++++-- 1 file changed, 229 insertions(+), 12 deletions(-) diff --git a/components/settings/settings.cpp b/components/settings/settings.cpp index 90fd300ec..7abfaff2c 100644 --- a/components/settings/settings.cpp +++ b/components/settings/settings.cpp @@ -2,6 +2,7 @@ #include #include +#include #include @@ -58,6 +59,7 @@ CategorySettingValueMap Manager::mDefaultSettings = CategorySettingValueMap(); CategorySettingValueMap Manager::mUserSettings = CategorySettingValueMap(); CategorySettingVector Manager::mChangedSettings = CategorySettingVector(); +typedef std::map< CategorySetting, bool > CategorySettingStatusMap; class SettingsFileParser { @@ -69,6 +71,7 @@ public: mFile = file; boost::filesystem::ifstream stream; stream.open(boost::filesystem::path(file)); + std::cout << "Loading settings file: " << file << std::endl; std::string currentCategory; mLine = 0; while (!stream.eof() && !stream.fail()) @@ -117,6 +120,230 @@ public: } } + void saveSettingsFile (const std::string& file, CategorySettingValueMap& settings) + { + // No options have been written to the file yet. + CategorySettingStatusMap written; + for (CategorySettingValueMap::iterator it = settings.begin(); it != settings.end(); ++it) { + written[it->first] = false; + } + + // Have we substantively changed the settings file? + bool changed = false; + + // Was there anything in the existing file? This is intended to permit the deletion of + // the settings.cfg file and it's automatic recreation -- a feature not currently + // supported elsewhere in the code. + bool existing = false; + + // The category/section we're currently in. + std::string currentCategory; + + // Open the existing settings.cfg file to copy comments. This might not be the same file + // as the output file if we're copying the setting from the default settings.cfg for the + // first time. A minor change in API to pass the source file might be in order here. + boost::filesystem::ifstream istream; + boost::filesystem::path ipath(file); + istream.open(ipath); + //std::cout << "Reading previous settings file: " << ipath << std::endl; + + // Create a new string stream to write the current settings to. It's likely that the + // input file and the output file are the same, so this stream serves as a temporary file + // of sorts. The setting files aren't very large so there's no performance issue. + std::stringstream ostream; + + // For every line in the input file... + while (!istream.eof() && !istream.fail()) { + std::string line; + std::getline(istream, line); + + // The current character position in the line. + size_t i = 0; + + // Don't add additional newlines at the end of the file. + if (istream.eof()) continue; + + // Copy entirely blank lines. + if (!skipWhiteSpace(i, line)) { + ostream << line << std::endl; + continue; + } + + // There were at least some comments in the input file. + existing = true; + + // Copy comments. + if (line[i] == '#') { + ostream << line << std::endl; + continue; + } + + // Category heading. + if (line[i] == '[') { + size_t end = line.find(']', i); + // This should never happen unless the player edited the file while playing. + if (end == std::string::npos) { + ostream << "# unterminated category: " << line << std::endl; + changed = true; + continue; + } + + // Ensure that all options in the current category have been written. + for (CategorySettingStatusMap::iterator mit = written.begin(); mit != written.end(); ++mit) { + bool missed = false; + if (mit->second == false && mit->first.first == currentCategory) { + std::cout << "Added new setting: [" << currentCategory << "] " + << mit->first.second << " = " << settings[mit->first] << std::endl; + // With some further code changes, this comment could be more descriptive. + ostream << "# Automatically added setting." << std::endl; + ostream << mit->first.second << " = " << settings[mit->first] << std::endl; + mit->second = true; + missed = true; + changed = true; + } + // Ensure that there's a newline before the next section if we added settings. + if (missed) ostream << std::endl; + } + + // Update the current category. + currentCategory = line.substr(i+1, end - (i+1)); + boost::algorithm::trim(currentCategory); + + // Write the (new) current category to the file. + ostream << "[" << currentCategory << "]" << std::endl; + //std::cout << "Wrote category: " << currentCategory << std::endl; + + // A setting can apparently follow the category on an input line. That's rather + // inconvenient, since it makes it more likely to have duplicative sections, + // which our algorithm doesn't like. Do the best we can. + i = end+1; + } + + // Truncate trailing whitespace, since we're changing the file anayway. + if (!skipWhiteSpace(i, line)) + continue; + + // If we'cve found settings befor ethe first category, something's wrong. This + // should never happen unless the player edited the file while playing, since + // the loadSettingsFile() logic rejects it. + if (currentCategory.empty()) { + ostream << "# empty category name: " << line << std::endl; + changed = true; + continue; + } + + // Which setting was at this location in the input file? + size_t settingEnd = line.find('=', i); + // This should never happen unless the player edited the file while playing. + if (settingEnd == std::string::npos) { + ostream << "# unterminated setting name: " << line << std::endl; + changed = true; + continue; + } + std::string setting = line.substr(i, (settingEnd-i)); + boost::algorithm::trim(setting); + + // Get the existing value so we can see if we've changed it. + size_t valueBegin = settingEnd+1; + std::string value = line.substr(valueBegin); + boost::algorithm::trim(value); + + // Construct the setting map key to determine whether the setting has already been + // written to the file. + CategorySetting key = std::make_pair(currentCategory, setting); + CategorySettingStatusMap::iterator finder = written.find(key); + + // Settings not in the written map are definitely invalid. Currently, this can only + // happen if the player edited the file while playing, because loadSettingsFile() + // will accept anything and pass it along in the map, but in the future, we might + // want to handle invalid settings more gracefully here. + if (finder == written.end()) { + ostream << "# invalid setting: " << line << std::endl; + changed = true; + continue; + } + + // Write the current value of the setting to the file. The key must exist in the + // settings map because of how written was initialized and finder != end(). + ostream << setting << " = " << settings[key] << std::endl; + // Mark that setting as written. + finder->second = true; + // Did we really change it? + if (value != settings[key]) { + std::cout << "Changed setting: [" << currentCategory << "] " + << setting << " = " << settings[key] << std::endl; + changed = true; + } + // No need to write the current line, because we just emitted a replacement. + + // Curiously, it appears that comments at the ends of lines with settings are not + // allowed, and the comment becomes part of the value. Was that intended? + } + + // We're done with the input stream file. + istream.close(); + + // Ensure that all options in the current category have been written. We must complete + // the current category at the end of the file before moving on to any new categories. + for (CategorySettingStatusMap::iterator mit = written.begin(); mit != written.end(); ++mit) { + bool missed = false; + if (mit->second == false && mit->first.first == currentCategory) { + std::cout << "Added new setting: [" << mit->first.first << "] " + << mit->first.second << " = " << settings[mit->first] << std::endl; + // With some further code changes, this comment could be more descriptive. + ostream << std::endl << "# Automatically added setting." << std::endl; + ostream << mit->first.second << " = " << settings[mit->first] << std::endl; + mit->second = true; + missed = true; + changed = true; + } + // Ensure that there's a newline before the next section if we added settings. + if (missed) ostream << std::endl; + } + + // This logic triggers when the input file was effectively empty. It could be extended + // to doing something more intelligent instead, like make a copy of the default settings + // file (complete with comments) before continuing. Other code prevents OpenMW from + // executing to this point with a missing config file. + if (!existing) { + ostream << "# This file was automatically generated." << std::endl << std::endl; + } + + // We still have one more thing to do before we're completely done writing the file. + // It's possible that there are entirely new categories, or that the input file had + // disappeared completely, so we need ensure that all settings are written to the file + // regardless of those issues. + for (CategorySettingStatusMap::iterator mit = written.begin(); mit != written.end(); ++mit) { + // If the setting hasn't been written yet. + if (mit->second == false) { + // If the catgory has changed, write a new category header. + if (mit->first.first != currentCategory) { + currentCategory = mit->first.first; + std::cout << "Created new setting section: " << mit->first.first << std::endl; + ostream << std::endl; + // Add new category comments only if we're amending an existing file. + if (existing) ostream << "# Automatically added category." << std::endl; + ostream << "[" << currentCategory << "]" << std::endl; + } + std::cout << "Added new setting: [" << mit->first.first << "] " + << mit->first.second << " = " << settings[mit->first] << std::endl; + // Then write the setting. No need to mark it as written because we're done. + ostream << std::endl; + ostream << mit->first.second << " = " << settings[mit->first] << std::endl; + changed = true; + } + } + + // Now install the newly written file in the requested place. + if (changed) { + std::cout << "Updating settings file: " << ipath << std::endl; + boost::filesystem::ofstream ofstream; + ofstream.open(ipath); + ofstream << ostream.rdbuf(); + ofstream.close(); + } + } + private: /// Increment i until it longer points to a whitespace character /// in the string or has reached the end of the string. @@ -155,18 +382,8 @@ void Manager::loadUser(const std::string &file) void Manager::saveUser(const std::string &file) { - boost::filesystem::ofstream stream; - stream.open(boost::filesystem::path(file)); - std::string currentCategory; - for (CategorySettingValueMap::iterator it = mUserSettings.begin(); it != mUserSettings.end(); ++it) - { - if (it->first.first != currentCategory) - { - currentCategory = it->first.first; - stream << "\n[" << currentCategory << "]\n"; - } - stream << it->first.second << " = " << it->second << "\n"; - } + SettingsFileParser parser; + parser.saveSettingsFile(file, mUserSettings); } std::string Manager::getString(const std::string &setting, const std::string &category) From 6882e6451ab027b565c03de5e8da233d72fd937a Mon Sep 17 00:00:00 2001 From: cfcohen Date: Mon, 23 Nov 2015 18:55:48 -0500 Subject: [PATCH 2537/3725] Remove tabs. :-[ --- components/settings/settings.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/components/settings/settings.cpp b/components/settings/settings.cpp index 7abfaff2c..c72e1ace4 100644 --- a/components/settings/settings.cpp +++ b/components/settings/settings.cpp @@ -194,7 +194,7 @@ public: if (mit->second == false && mit->first.first == currentCategory) { std::cout << "Added new setting: [" << currentCategory << "] " << mit->first.second << " = " << settings[mit->first] << std::endl; - // With some further code changes, this comment could be more descriptive. + // With some further code changes, this comment could be more descriptive. ostream << "# Automatically added setting." << std::endl; ostream << mit->first.second << " = " << settings[mit->first] << std::endl; mit->second = true; @@ -223,9 +223,9 @@ public: if (!skipWhiteSpace(i, line)) continue; - // If we'cve found settings befor ethe first category, something's wrong. This + // If we'cve found settings befor ethe first category, something's wrong. This // should never happen unless the player edited the file while playing, since - // the loadSettingsFile() logic rejects it. + // the loadSettingsFile() logic rejects it. if (currentCategory.empty()) { ostream << "# empty category name: " << line << std::endl; changed = true; @@ -276,7 +276,7 @@ public: } // No need to write the current line, because we just emitted a replacement. - // Curiously, it appears that comments at the ends of lines with settings are not + // Curiously, it appears that comments at the ends of lines with settings are not // allowed, and the comment becomes part of the value. Was that intended? } @@ -290,7 +290,7 @@ public: if (mit->second == false && mit->first.first == currentCategory) { std::cout << "Added new setting: [" << mit->first.first << "] " << mit->first.second << " = " << settings[mit->first] << std::endl; - // With some further code changes, this comment could be more descriptive. + // With some further code changes, this comment could be more descriptive. ostream << std::endl << "# Automatically added setting." << std::endl; ostream << mit->first.second << " = " << settings[mit->first] << std::endl; mit->second = true; @@ -301,10 +301,10 @@ public: if (missed) ostream << std::endl; } - // This logic triggers when the input file was effectively empty. It could be extended - // to doing something more intelligent instead, like make a copy of the default settings - // file (complete with comments) before continuing. Other code prevents OpenMW from - // executing to this point with a missing config file. + // This logic triggers when the input file was effectively empty. It could be extended + // to doing something more intelligent instead, like make a copy of the default settings + // file (complete with comments) before continuing. Other code prevents OpenMW from + // executing to this point with a missing config file. if (!existing) { ostream << "# This file was automatically generated." << std::endl << std::endl; } From 1b77428c59d230883194820f35c1e26c2186658f Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 24 Nov 2015 03:42:35 +0100 Subject: [PATCH 2538/3725] Use const reference, thanks ace13 --- components/sceneutil/lightmanager.cpp | 2 +- components/sceneutil/lightmanager.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/components/sceneutil/lightmanager.cpp b/components/sceneutil/lightmanager.cpp index 43f11cf00..ba2f8c510 100644 --- a/components/sceneutil/lightmanager.cpp +++ b/components/sceneutil/lightmanager.cpp @@ -164,7 +164,7 @@ namespace SceneUtil mStateSetCache.clear(); } - void LightManager::addLight(LightSource* lightSource, osg::Matrixf worldMat) + void LightManager::addLight(LightSource* lightSource, const osg::Matrixf& worldMat) { LightSourceTransform l; l.mLightSource = lightSource; diff --git a/components/sceneutil/lightmanager.hpp b/components/sceneutil/lightmanager.hpp index ecee873e8..89ffc1305 100644 --- a/components/sceneutil/lightmanager.hpp +++ b/components/sceneutil/lightmanager.hpp @@ -77,7 +77,7 @@ namespace SceneUtil void update(); // Called automatically by the LightSource's UpdateCallback - void addLight(LightSource* lightSource, osg::Matrixf worldMat); + void addLight(LightSource* lightSource, const osg::Matrixf& worldMat); struct LightSourceTransform { From e0752ccdd058e3ef6daff73d661b6f24e99c5be8 Mon Sep 17 00:00:00 2001 From: cfcohen Date: Tue, 24 Nov 2015 00:10:23 -0500 Subject: [PATCH 2539/3725] Prioritize warning about user settings. Make recommendations for screen number more generic. Remove resolution recommendation. --- files/settings-default.cfg | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 3b91e7f0a..f16ef9124 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -1,3 +1,6 @@ +# WARNING: Editing this file might have no effect, as these settings +# are overwritten by your user settings file. +# # This file provides minimal documentation for each setting, and # ranges of recommended values. For detailed explanations of the # significance of each setting, interaction with other settings, hard @@ -6,9 +9,6 @@ # # https://wiki.openmw.org/index.php?title=Settings # -# The version of this file that actually controls the behavior of -# OpenMW is user specific, and it's location can be found in the -# documentation above. This file is probably NOT that file... [Camera] @@ -167,14 +167,14 @@ voice volume = 0.8 [Video] -# Resolution of the Open window or screen. (600 to 2560). +# Resolution of the Open window or screen. resolution x = 800 resolution y = 600 # OpenMW takes complete control of the screen. fullscreen = false -# Determines which screen OpenMW is on. (0 or 1). +# Determines which screen OpenMW is on. (>=0). screen = 0 # Minimize OpenMW if it loses cursor or keyboard focus. From edfcb45ad7b9d535c984ccb22e3cc8879ce3a7a6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 24 Nov 2015 22:50:54 +0100 Subject: [PATCH 2540/3725] Fix crash when onPcEquip script removes the equipped item (Fixes #3016) --- apps/openmw/mwgui/inventorywindow.cpp | 16 +++++++++------- apps/openmw/mwworld/actionequip.cpp | 7 ++++++- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index c1e202bc0..e5bf1f4b4 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -471,16 +471,18 @@ namespace MWGui MWBase::Environment::get().getScriptManager()->run (script, interpreterContext); } - if (script.empty() || ptr.getRefData().getLocals().getIntVar(script, "pcskipequip") == 0) + mSkippedToEquip = MWWorld::Ptr(); + if (ptr.getRefData().getCount()) // make sure the item is still there, the script might have removed it { - boost::shared_ptr action = ptr.getClass().use(ptr); - - action->execute (player); + if (script.empty() || ptr.getRefData().getLocals().getIntVar(script, "pcskipequip") == 0) + { + boost::shared_ptr action = ptr.getClass().use(ptr); - mSkippedToEquip = MWWorld::Ptr(); + action->execute (player); + } + else + mSkippedToEquip = ptr; } - else - mSkippedToEquip = ptr; if (isVisible()) { diff --git a/apps/openmw/mwworld/actionequip.cpp b/apps/openmw/mwworld/actionequip.cpp index 147f22963..a6d6eef2b 100644 --- a/apps/openmw/mwworld/actionequip.cpp +++ b/apps/openmw/mwworld/actionequip.cpp @@ -52,7 +52,12 @@ namespace MWWorld } } - assert(it != invStore.end()); + if (it == invStore.end()) + { + std::stringstream error; + error << "ActionEquip can't find item " << object.getCellRef().getRefId(); + throw std::runtime_error(error.str()); + } // equip the item in the first free slot std::vector::const_iterator slot=slots_.first.begin(); From e2beefd8b59a358544cfb0eede9524459a12f214 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 22 Nov 2015 04:53:24 -0800 Subject: [PATCH 2541/3725] Store info calculated from the ESM::Sound record --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwsound/sound_buffer.hpp | 26 +++++++ apps/openmw/mwsound/soundmanagerimp.cpp | 92 ++++++++++++++----------- apps/openmw/mwsound/soundmanagerimp.hpp | 8 ++- 4 files changed, 85 insertions(+), 43 deletions(-) create mode 100644 apps/openmw/mwsound/sound_buffer.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 59a523023..48d10e202 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -57,7 +57,7 @@ add_openmw_dir (mwscript ) add_openmw_dir (mwsound - soundmanagerimp openal_output ffmpeg_decoder sound sound_decoder sound_output loudness movieaudiofactory + soundmanagerimp openal_output ffmpeg_decoder sound sound_buffer sound_decoder sound_output loudness movieaudiofactory ) add_openmw_dir (mwworld diff --git a/apps/openmw/mwsound/sound_buffer.hpp b/apps/openmw/mwsound/sound_buffer.hpp new file mode 100644 index 000000000..fcef7963a --- /dev/null +++ b/apps/openmw/mwsound/sound_buffer.hpp @@ -0,0 +1,26 @@ +#ifndef GAME_SOUND_SOUND_BUFFER_H +#define GAME_SOUND_SOUND_BUFFER_H + +#include + +#include "soundmanagerimp.hpp" + +#include "../mwworld/ptr.hpp" + +namespace MWSound +{ + class Sound_Buffer + { + public: + std::string mResourceName; + + float mVolume; + float mMinDist, mMaxDist; + + Sound_Buffer(std::string resname, float volume, float mindist, float maxdist) + : mResourceName(resname), mVolume(volume), mMinDist(mindist), mMaxDist(maxdist) + { } + }; +} + +#endif /* GAME_SOUND_SOUND_BUFFER_H */ diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 6e309e28e..084524074 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -18,6 +18,7 @@ #include "../mwmechanics/actorutil.hpp" #include "sound_output.hpp" +#include "sound_buffer.hpp" #include "sound_decoder.hpp" #include "sound.hpp" @@ -103,38 +104,48 @@ namespace MWSound return DecoderPtr(new DEFAULT_DECODER (mVFS)); } - // Convert a soundId to file name, and modify the volume - // according to the sounds local volume setting, minRange and - // maxRange. - std::string SoundManager::lookup(const std::string &soundId, - float &volume, float &min, float &max) + // Lookup a soundid for its sound data (resource name, local volume, + // minRange and maxRange. The returned pointer is only valid temporarily. + const Sound_Buffer *SoundManager::lookup(const std::string &soundId) { - MWBase::World* world = MWBase::Environment::get().getWorld(); - const ESM::Sound *snd = world->getStore().get().find(soundId); + NameBufferMap::iterator sfxiter = mSoundBuffers.find(soundId); + if(sfxiter == mSoundBuffers.end()) + { + // TODO: We could process all available ESM::Sound records on init + // to pre-fill a non-resizing list, which would allow subsystems to + // reference sounds by index instead of string. + MWBase::World* world = MWBase::Environment::get().getWorld(); + const ESM::Sound *snd = world->getStore().get().find(soundId); - volume *= static_cast(pow(10.0, (snd->mData.mVolume / 255.0*3348.0 - 3348.0) / 2000.0)); + float volume, min, max; + volume = static_cast(pow(10.0, (snd->mData.mVolume / 255.0*3348.0 - 3348.0) / 2000.0)); - if(snd->mData.mMinRange == 0 && snd->mData.mMaxRange == 0) - { - static const float fAudioDefaultMinDistance = world->getStore().get().find("fAudioDefaultMinDistance")->getFloat(); - static const float fAudioDefaultMaxDistance = world->getStore().get().find("fAudioDefaultMaxDistance")->getFloat(); - min = fAudioDefaultMinDistance; - max = fAudioDefaultMaxDistance; - } - else - { - min = snd->mData.mMinRange; - max = snd->mData.mMaxRange; - } + if(snd->mData.mMinRange == 0 && snd->mData.mMaxRange == 0) + { + static const float fAudioDefaultMinDistance = world->getStore().get().find("fAudioDefaultMinDistance")->getFloat(); + static const float fAudioDefaultMaxDistance = world->getStore().get().find("fAudioDefaultMaxDistance")->getFloat(); + min = fAudioDefaultMinDistance; + max = fAudioDefaultMaxDistance; + } + else + { + min = snd->mData.mMinRange; + max = snd->mData.mMaxRange; + } - static const float fAudioMinDistanceMult = world->getStore().get().find("fAudioMinDistanceMult")->getFloat(); - static const float fAudioMaxDistanceMult = world->getStore().get().find("fAudioMaxDistanceMult")->getFloat(); - min *= fAudioMinDistanceMult; - max *= fAudioMaxDistanceMult; - min = std::max(min, 1.0f); - max = std::max(min, max); + static const float fAudioMinDistanceMult = world->getStore().get().find("fAudioMinDistanceMult")->getFloat(); + static const float fAudioMaxDistanceMult = world->getStore().get().find("fAudioMaxDistanceMult")->getFloat(); + min *= fAudioMinDistanceMult; + max *= fAudioMaxDistanceMult; + min = std::max(min, 1.0f); + max = std::max(min, max); - return "Sound/"+snd->mSound; + sfxiter = mSoundBuffers.insert(std::make_pair( + soundId, Sound_Buffer("Sound/"+snd->mSound, volume, min, max) + )).first; + mVFS->normalizeFilename(sfxiter->second.mResourceName); + } + return &sfxiter->second; } // Gets the combined volume settings for the given sound type @@ -268,7 +279,7 @@ namespace MWSound try { float basevol = volumeFromType(Play_TypeVoice); - std::string filePath = "Sound/"+filename; + std::string filePath = "sound/"+filename; const ESM::Position &pos = ptr.getRefData().getPosition(); const osg::Vec3f objpos(pos.asVec3()); @@ -371,11 +382,12 @@ namespace MWSound return sound; try { + const Sound_Buffer *sfx = lookup(Misc::StringUtils::lowerCase(soundId)); float basevol = volumeFromType(type); - float min, max; - std::string file = lookup(soundId, volume, min, max); - sound = mOutput->playSound(file, volume, basevol, pitch, mode|type, offset); + sound = mOutput->playSound(sfx->mResourceName, + volume * sfx->mVolume, basevol, pitch, mode|type, offset + ); mActiveSounds[sound] = std::make_pair(MWWorld::Ptr(), soundId); } catch(std::exception&) @@ -394,18 +406,17 @@ namespace MWSound try { // Look up the sound in the ESM data + const Sound_Buffer *sfx = lookup(Misc::StringUtils::lowerCase(soundId)); float basevol = volumeFromType(type); - float min, max; - std::string file = lookup(soundId, volume, min, max); const ESM::Position &pos = ptr.getRefData().getPosition(); const osg::Vec3f objpos(pos.asVec3()); - if ((mode & Play_RemoveAtDistance) && (mListenerPos-objpos).length2() > 2000*2000) - { + if((mode&Play_RemoveAtDistance) && (mListenerPos-objpos).length2() > 2000*2000) return MWBase::SoundPtr(); - } - sound = mOutput->playSound3D(file, objpos, volume, basevol, pitch, min, max, mode|type, offset); + sound = mOutput->playSound3D(sfx->mResourceName, + objpos, volume * sfx->mVolume, basevol, pitch, sfx->mMinDist, sfx->mMaxDist, mode|type, offset + ); if((mode&Play_NoTrack)) mActiveSounds[sound] = std::make_pair(MWWorld::Ptr(), soundId); else @@ -427,11 +438,12 @@ namespace MWSound try { // Look up the sound in the ESM data + const Sound_Buffer *sfx = lookup(Misc::StringUtils::lowerCase(soundId)); float basevol = volumeFromType(type); - float min, max; - std::string file = lookup(soundId, volume, min, max); - sound = mOutput->playSound3D(file, initialPos, volume, basevol, pitch, min, max, mode|type, offset); + sound = mOutput->playSound3D(sfx->mResourceName, + initialPos, volume * sfx->mVolume, basevol, pitch, sfx->mMinDist, sfx->mMaxDist, mode|type, offset + ); mActiveSounds[sound] = std::make_pair(MWWorld::Ptr(), soundId); } catch(std::exception &) diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index f79bfce15..d9eb7ff3d 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -21,6 +21,7 @@ namespace MWSound class Sound_Output; struct Sound_Decoder; class Sound; + class Sound_Buffer; enum Environment { Env_Normal, @@ -43,6 +44,9 @@ namespace MWSound float mVoiceVolume; float mFootstepsVolume; + typedef std::map NameBufferMap; + NameBufferMap mSoundBuffers; + boost::shared_ptr mMusic; std::string mCurrentPlaylist; @@ -59,8 +63,8 @@ namespace MWSound int mPausedSoundTypes; - std::string lookup(const std::string &soundId, - float &volume, float &min, float &max); + const Sound_Buffer *lookup(const std::string &soundId); + void streamMusicFull(const std::string& filename); bool isPlaying(const MWWorld::Ptr &ptr, const std::string &id) const; void updateSounds(float duration); From 4571218827802651a8b9b6bd734558e1a2a3a463 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 23 Nov 2015 01:01:20 -0800 Subject: [PATCH 2542/3725] Load the sound as needed and pass it directly to the play methods This breaks say sounds, loudness handling, and the cache limit. Fixes are forthcoming. --- apps/openmw/mwsound/openal_output.cpp | 155 ++++++++---------------- apps/openmw/mwsound/openal_output.hpp | 27 +---- apps/openmw/mwsound/sound_buffer.hpp | 5 +- apps/openmw/mwsound/sound_output.hpp | 12 +- apps/openmw/mwsound/soundmanagerimp.cpp | 28 ++++- 5 files changed, 95 insertions(+), 132 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index a984fffa9..b71fe4d80 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -19,6 +19,9 @@ #define ALC_ALL_DEVICES_SPECIFIER 0x1013 #endif +#define MAKE_PTRID(id) ((void*)(uintptr_t)id) +#define GET_PTRID(ptr) ((ALuint)(uintptr_t)ptr) + namespace { const int loudnessFPS = 20; // loudness values per second of audio @@ -545,7 +548,6 @@ OpenAL_Sound::~OpenAL_Sound() alSourcei(mSource, AL_BUFFER, 0); mOutput.mFreeSources.push_back(mSource); - mOutput.bufferFinished(mBuffer); mOutput.mActiveSounds.erase(std::find(mOutput.mActiveSounds.begin(), mOutput.mActiveSounds.end(), this)); @@ -737,14 +739,6 @@ void OpenAL_Output::deinit() alDeleteSources(1, &mFreeSources[i]); mFreeSources.clear(); - mBufferRefs.clear(); - mUnusedBuffers.clear(); - while(!mBufferCache.empty()) - { - alDeleteBuffers(1, &mBufferCache.begin()->second.mALBuffer); - mBufferCache.erase(mBufferCache.begin()); - } - alcMakeContextCurrent(0); if(mContext) alcDestroyContext(mContext); @@ -757,32 +751,10 @@ void OpenAL_Output::deinit() } -const CachedSound& OpenAL_Output::getBuffer(const std::string &fname) +Sound_Handle OpenAL_Output::loadSound(const std::string &fname) { - ALuint buf = 0; - - NameMap::iterator iditer = mBufferCache.find(fname); - if(iditer != mBufferCache.end()) - { - buf = iditer->second.mALBuffer; - if(mBufferRefs[buf]++ == 0) - { - IDDq::iterator iter = std::find(mUnusedBuffers.begin(), - mUnusedBuffers.end(), buf); - if(iter != mUnusedBuffers.end()) - mUnusedBuffers.erase(iter); - } - - return iditer->second; - } throwALerror(); - std::vector data; - ChannelConfig chans; - SampleType type; - ALenum format; - int srate; - DecoderPtr decoder = mManager.getDecoder(); // Workaround: Bethesda at some point converted some of the files to mp3, but the references were kept as .wav. std::string file = fname; @@ -794,87 +766,70 @@ const CachedSound& OpenAL_Output::getBuffer(const std::string &fname) } decoder->open(file); + std::vector data; + ChannelConfig chans; + SampleType type; + ALenum format; + int srate; + decoder->getInfo(&srate, &chans, &type); format = getALFormat(chans, type); decoder->readAll(data); decoder->close(); - CachedSound cached; - analyzeLoudness(data, srate, chans, type, cached.mLoudnessVector, static_cast(loudnessFPS)); - - alGenBuffers(1, &buf); - throwALerror(); - - alBufferData(buf, format, &data[0], data.size(), srate); - mBufferRefs[buf] = 1; - cached.mALBuffer = buf; - mBufferCache[fname] = cached; + //analyzeLoudness(data, srate, chans, type, cached.mLoudnessVector, static_cast(loudnessFPS)); - ALint bufsize = 0; - alGetBufferi(buf, AL_SIZE, &bufsize); - mBufferCacheMemSize += bufsize; - - // NOTE: Max buffer cache: 15MB - while(mBufferCacheMemSize > 15*1024*1024) - { - if(mUnusedBuffers.empty()) - { - std::cout <<"No more unused buffers to clear!"<< std::endl; - break; - } - - ALuint oldbuf = mUnusedBuffers.front(); - mUnusedBuffers.pop_front(); - - NameMap::iterator nameiter = mBufferCache.begin(); - while(nameiter != mBufferCache.end()) - { - if(nameiter->second.mALBuffer == oldbuf) - mBufferCache.erase(nameiter++); - else - ++nameiter; - } - - bufsize = 0; - alGetBufferi(oldbuf, AL_SIZE, &bufsize); - alDeleteBuffers(1, &oldbuf); - mBufferCacheMemSize -= bufsize; + ALuint buf = 0; + try { + alGenBuffers(1, &buf); + alBufferData(buf, format, &data[0], data.size(), srate); + throwALerror(); } - - return mBufferCache[fname]; + catch(...) { + if(buf && alIsBuffer(buf)) + alDeleteBuffers(1, &buf); + throw; + } + return MAKE_PTRID(buf); } -void OpenAL_Output::bufferFinished(ALuint buf) +void OpenAL_Output::unloadSound(Sound_Handle data) { - if(mBufferRefs.at(buf)-- == 1) + ALuint buffer = GET_PTRID(data); + // Make sure no sources are playing this buffer before unloading it. + SoundVec::const_iterator iter = mActiveSounds.begin(); + for(;iter != mActiveSounds.end();++iter) { - mBufferRefs.erase(mBufferRefs.find(buf)); - mUnusedBuffers.push_back(buf); + OpenAL_Sound *sound = dynamic_cast(*iter); + if(sound && sound->mSource && sound->mBuffer == buffer) + { + alSourceStop(sound->mSource); + alSourcei(sound->mSource, AL_BUFFER, 0); + sound->mBuffer = 0; + } } + alDeleteBuffers(1, &buffer); } -MWBase::SoundPtr OpenAL_Output::playSound(const std::string &fname, float vol, float basevol, float pitch, int flags,float offset) + +MWBase::SoundPtr OpenAL_Output::playSound(Sound_Handle data, float vol, float basevol, float pitch, int flags,float offset) { boost::shared_ptr sound; - ALuint src=0, buf=0; + ALuint src=0; if(mFreeSources.empty()) fail("No free sources"); src = mFreeSources.front(); mFreeSources.pop_front(); - try - { - buf = getBuffer(fname).mALBuffer; - sound.reset(new OpenAL_Sound(*this, src, buf, osg::Vec3f(0.f, 0.f, 0.f), vol, basevol, pitch, 1.0f, 1000.0f, flags)); + ALuint buffer = GET_PTRID(data); + try { + sound.reset(new OpenAL_Sound(*this, src, buffer, osg::Vec3f(0.f, 0.f, 0.f), vol, basevol, pitch, 1.0f, 1000.0f, flags)); } catch(std::exception&) { mFreeSources.push_back(src); - if(buf && alIsBuffer(buf)) - bufferFinished(buf); - alGetError(); throw; } @@ -884,7 +839,7 @@ MWBase::SoundPtr OpenAL_Output::playSound(const std::string &fname, float vol, f if(offset>1) offset=1; - alSourcei(src, AL_BUFFER, buf); + alSourcei(src, AL_BUFFER, buffer); alSourcef(src, AL_SEC_OFFSET, static_cast(sound->getLength()*offset / pitch)); alSourcePlay(src); throwALerror(); @@ -892,32 +847,24 @@ MWBase::SoundPtr OpenAL_Output::playSound(const std::string &fname, float vol, f return sound; } -MWBase::SoundPtr OpenAL_Output::playSound3D(const std::string &fname, const osg::Vec3f &pos, float vol, float basevol, float pitch, - float min, float max, int flags, float offset, bool extractLoudness) +MWBase::SoundPtr OpenAL_Output::playSound3D(Sound_Handle data, const osg::Vec3f &pos, float vol, float basevol, float pitch, + float min, float max, int flags, float offset) { boost::shared_ptr sound; - ALuint src=0, buf=0; + ALuint src=0; if(mFreeSources.empty()) fail("No free sources"); src = mFreeSources.front(); mFreeSources.pop_front(); - try - { - const CachedSound& cached = getBuffer(fname); - buf = cached.mALBuffer; - - sound.reset(new OpenAL_Sound3D(*this, src, buf, pos, vol, basevol, pitch, min, max, flags)); - if (extractLoudness) - sound->setLoudnessVector(cached.mLoudnessVector, static_cast(loudnessFPS)); + ALuint buffer = GET_PTRID(data); + try { + sound.reset(new OpenAL_Sound3D(*this, src, buffer, pos, vol, basevol, pitch, min, max, flags)); } catch(std::exception&) { mFreeSources.push_back(src); - if(buf && alIsBuffer(buf)) - bufferFinished(buf); - alGetError(); throw; } @@ -928,7 +875,7 @@ MWBase::SoundPtr OpenAL_Output::playSound3D(const std::string &fname, const osg: if(offset>1) offset=1; - alSourcei(src, AL_BUFFER, buf); + alSourcei(src, AL_BUFFER, buffer); alSourcef(src, AL_SEC_OFFSET, static_cast(sound->getLength()*offset / pitch)); alSourcePlay(src); @@ -1041,8 +988,8 @@ void OpenAL_Output::resumeSounds(int types) OpenAL_Output::OpenAL_Output(SoundManager &mgr) - : Sound_Output(mgr), mDevice(0), mContext(0), mBufferCacheMemSize(0), - mLastEnvironment(Env_Normal), mStreamThread(new StreamThread) + : Sound_Output(mgr), mDevice(0), mContext(0), mLastEnvironment(Env_Normal), + mStreamThread(new StreamThread) { } diff --git a/apps/openmw/mwsound/openal_output.hpp b/apps/openmw/mwsound/openal_output.hpp index 755a0e5b6..8af46a478 100644 --- a/apps/openmw/mwsound/openal_output.hpp +++ b/apps/openmw/mwsound/openal_output.hpp @@ -16,12 +16,6 @@ namespace MWSound class SoundManager; class Sound; - struct CachedSound - { - ALuint mALBuffer; - std::vector mLoudnessVector; - }; - class OpenAL_Output : public Sound_Output { ALCdevice *mDevice; @@ -29,33 +23,24 @@ namespace MWSound typedef std::deque IDDq; IDDq mFreeSources; - IDDq mUnusedBuffers; - - typedef std::map NameMap; - NameMap mBufferCache; - - typedef std::map IDRefMap; - IDRefMap mBufferRefs; - - uint64_t mBufferCacheMemSize; typedef std::vector SoundVec; SoundVec mActiveSounds; - const CachedSound& getBuffer(const std::string &fname); - void bufferFinished(ALuint buffer); - Environment mLastEnvironment; virtual std::vector enumerate(); virtual void init(const std::string &devname=""); virtual void deinit(); + virtual Sound_Handle loadSound(const std::string &fname); + virtual void unloadSound(Sound_Handle data); + /// @param offset Value from [0,1] meaning from which fraction the sound the playback starts. - virtual MWBase::SoundPtr playSound(const std::string &fname, float vol, float basevol, float pitch, int flags, float offset); + virtual MWBase::SoundPtr playSound(Sound_Handle data, float vol, float basevol, float pitch, int flags, float offset); /// @param offset Value from [0,1] meaning from which fraction the sound the playback starts. - virtual MWBase::SoundPtr playSound3D(const std::string &fname, const osg::Vec3f &pos, - float vol, float basevol, float pitch, float min, float max, int flags, float offset, bool extractLoudness=false); + virtual MWBase::SoundPtr playSound3D(Sound_Handle data, const osg::Vec3f &pos, + float vol, float basevol, float pitch, float min, float max, int flags, float offset); virtual MWBase::SoundPtr streamSound(DecoderPtr decoder, float volume, float pitch, int flags); virtual void updateListener(const osg::Vec3f &pos, const osg::Vec3f &atdir, const osg::Vec3f &updir, Environment env); diff --git a/apps/openmw/mwsound/sound_buffer.hpp b/apps/openmw/mwsound/sound_buffer.hpp index fcef7963a..37f49e518 100644 --- a/apps/openmw/mwsound/sound_buffer.hpp +++ b/apps/openmw/mwsound/sound_buffer.hpp @@ -4,6 +4,7 @@ #include #include "soundmanagerimp.hpp" +#include "sound_output.hpp" #include "../mwworld/ptr.hpp" @@ -17,8 +18,10 @@ namespace MWSound float mVolume; float mMinDist, mMaxDist; + Sound_Handle mHandle; + Sound_Buffer(std::string resname, float volume, float mindist, float maxdist) - : mResourceName(resname), mVolume(volume), mMinDist(mindist), mMaxDist(maxdist) + : mResourceName(resname), mVolume(volume), mMinDist(mindist), mMaxDist(maxdist), mHandle(0) { } }; } diff --git a/apps/openmw/mwsound/sound_output.hpp b/apps/openmw/mwsound/sound_output.hpp index a0c6fb17b..cbda19d59 100644 --- a/apps/openmw/mwsound/sound_output.hpp +++ b/apps/openmw/mwsound/sound_output.hpp @@ -14,6 +14,9 @@ namespace MWSound struct Sound_Decoder; class Sound; + // An opaque handle for the implementation's sound buffers. + typedef void *Sound_Handle; + class Sound_Output { SoundManager &mManager; @@ -22,11 +25,14 @@ namespace MWSound virtual void init(const std::string &devname="") = 0; virtual void deinit() = 0; + virtual Sound_Handle loadSound(const std::string &fname) = 0; + virtual void unloadSound(Sound_Handle data) = 0; + /// @param offset Value from [0,1] meaning from which fraction the sound the playback starts. - virtual MWBase::SoundPtr playSound(const std::string &fname, float vol, float basevol, float pitch, int flags, float offset) = 0; + virtual MWBase::SoundPtr playSound(Sound_Handle data, float vol, float basevol, float pitch, int flags, float offset) = 0; /// @param offset Value from [0,1] meaning from which fraction the sound the playback starts. - virtual MWBase::SoundPtr playSound3D(const std::string &fname, const osg::Vec3f &pos, - float vol, float basevol, float pitch, float min, float max, int flags, float offset, bool extractLoudness=false) = 0; + virtual MWBase::SoundPtr playSound3D(Sound_Handle data, const osg::Vec3f &pos, + float vol, float basevol, float pitch, float min, float max, int flags, float offset) = 0; virtual MWBase::SoundPtr streamSound(DecoderPtr decoder, float volume, float pitch, int flags) = 0; virtual void updateListener(const osg::Vec3f &pos, const osg::Vec3f &atdir, const osg::Vec3f &updir, Environment env) = 0; diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 084524074..820a9841d 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -92,6 +92,16 @@ namespace MWSound SoundManager::~SoundManager() { + if(mOutput->isInitialized()) + { + NameBufferMap::iterator sfxiter = mSoundBuffers.begin(); + for(;sfxiter != mSoundBuffers.end();++sfxiter) + { + if(sfxiter->second.mHandle) + mOutput->unloadSound(sfxiter->second.mHandle); + sfxiter->second.mHandle = 0; + } + } mUnderwaterSound.reset(); mActiveSounds.clear(); mMusic.reset(); @@ -144,7 +154,11 @@ namespace MWSound soundId, Sound_Buffer("Sound/"+snd->mSound, volume, min, max) )).first; mVFS->normalizeFilename(sfxiter->second.mResourceName); + sfxiter->second.mHandle = mOutput->loadSound(sfxiter->second.mResourceName); } + else if(!sfxiter->second.mHandle) + sfxiter->second.mHandle = mOutput->loadSound(sfxiter->second.mResourceName); + return &sfxiter->second; } @@ -278,6 +292,7 @@ namespace MWSound return; try { +#if 0 float basevol = volumeFromType(Play_TypeVoice); std::string filePath = "sound/"+filename; const ESM::Position &pos = ptr.getRefData().getPosition(); @@ -297,6 +312,9 @@ namespace MWSound MWBase::SoundPtr sound = mOutput->playSound3D(filePath, objpos, 1.0f, basevol, 1.0f, minDistance, maxDistance, Play_Normal|Play_TypeVoice, 0, true); mActiveSounds[sound] = std::make_pair(ptr, std::string("_say_sound")); +#else + throw std::runtime_error("say disabled"); +#endif } catch(std::exception &e) { @@ -325,11 +343,15 @@ namespace MWSound return; try { +#if 0 float basevol = volumeFromType(Play_TypeVoice); std::string filePath = "Sound/"+filename; MWBase::SoundPtr sound = mOutput->playSound(filePath, 1.0f, basevol, 1.0f, Play_Normal|Play_TypeVoice, 0); mActiveSounds[sound] = std::make_pair(MWWorld::Ptr(), std::string("_say_sound")); +#else + throw std::runtime_error("say disabled"); +#endif } catch(std::exception &e) { @@ -385,7 +407,7 @@ namespace MWSound const Sound_Buffer *sfx = lookup(Misc::StringUtils::lowerCase(soundId)); float basevol = volumeFromType(type); - sound = mOutput->playSound(sfx->mResourceName, + sound = mOutput->playSound(sfx->mHandle, volume * sfx->mVolume, basevol, pitch, mode|type, offset ); mActiveSounds[sound] = std::make_pair(MWWorld::Ptr(), soundId); @@ -414,7 +436,7 @@ namespace MWSound if((mode&Play_RemoveAtDistance) && (mListenerPos-objpos).length2() > 2000*2000) return MWBase::SoundPtr(); - sound = mOutput->playSound3D(sfx->mResourceName, + sound = mOutput->playSound3D(sfx->mHandle, objpos, volume * sfx->mVolume, basevol, pitch, sfx->mMinDist, sfx->mMaxDist, mode|type, offset ); if((mode&Play_NoTrack)) @@ -441,7 +463,7 @@ namespace MWSound const Sound_Buffer *sfx = lookup(Misc::StringUtils::lowerCase(soundId)); float basevol = volumeFromType(type); - sound = mOutput->playSound3D(sfx->mResourceName, + sound = mOutput->playSound3D(sfx->mHandle, initialPos, volume * sfx->mVolume, basevol, pitch, sfx->mMinDist, sfx->mMaxDist, mode|type, offset ); mActiveSounds[sound] = std::make_pair(MWWorld::Ptr(), soundId); From f4c22ec49e14dd348446e8574c4f50be4db8692e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 23 Nov 2015 01:33:59 -0800 Subject: [PATCH 2543/3725] Hold a separate list for voice sound buffers This fixes say. Ideally voices would be streamed, but the loudness/"lip" buffer extraction should be separated from the buffer loading code. --- apps/openmw/mwsound/openal_output.cpp | 4 +- apps/openmw/mwsound/soundmanagerimp.cpp | 70 ++++++++++++++++--------- apps/openmw/mwsound/soundmanagerimp.hpp | 4 ++ 3 files changed, 51 insertions(+), 27 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index b71fe4d80..381c5ba18 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -816,7 +816,7 @@ void OpenAL_Output::unloadSound(Sound_Handle data) MWBase::SoundPtr OpenAL_Output::playSound(Sound_Handle data, float vol, float basevol, float pitch, int flags,float offset) { boost::shared_ptr sound; - ALuint src=0; + ALuint src; if(mFreeSources.empty()) fail("No free sources"); @@ -851,7 +851,7 @@ MWBase::SoundPtr OpenAL_Output::playSound3D(Sound_Handle data, const osg::Vec3f float min, float max, int flags, float offset) { boost::shared_ptr sound; - ALuint src=0; + ALuint src; if(mFreeSources.empty()) fail("No free sources"); diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 820a9841d..6e95c1116 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -101,6 +101,13 @@ namespace MWSound mOutput->unloadSound(sfxiter->second.mHandle); sfxiter->second.mHandle = 0; } + sfxiter = mVoiceSoundBuffers.begin(); + for(;sfxiter != mVoiceSoundBuffers.end();++sfxiter) + { + if(sfxiter->second.mHandle) + mOutput->unloadSound(sfxiter->second.mHandle); + sfxiter->second.mHandle = 0; + } } mUnderwaterSound.reset(); mActiveSounds.clear(); @@ -162,6 +169,35 @@ namespace MWSound return &sfxiter->second; } + const Sound_Buffer *SoundManager::lookupVoice(const std::string &voicefile) + { + NameBufferMap::iterator sfxiter = mVoiceSoundBuffers.find(voicefile); + if(sfxiter == mVoiceSoundBuffers.end()) + { + MWBase::World* world = MWBase::Environment::get().getWorld(); + static const float fAudioMinDistanceMult = world->getStore().get().find("fAudioMinDistanceMult")->getFloat(); + static const float fAudioMaxDistanceMult = world->getStore().get().find("fAudioMaxDistanceMult")->getFloat(); + static const float fAudioVoiceDefaultMinDistance = world->getStore().get().find("fAudioVoiceDefaultMinDistance")->getFloat(); + static const float fAudioVoiceDefaultMaxDistance = world->getStore().get().find("fAudioVoiceDefaultMaxDistance")->getFloat(); + + float minDistance = fAudioVoiceDefaultMinDistance * fAudioMinDistanceMult; + float maxDistance = fAudioVoiceDefaultMaxDistance * fAudioMaxDistanceMult; + minDistance = std::max(minDistance, 1.f); + maxDistance = std::max(minDistance, maxDistance); + + sfxiter = mVoiceSoundBuffers.insert(std::make_pair( + voicefile, Sound_Buffer("sound/"+voicefile, 1.0f, minDistance, maxDistance) + )).first; + mVFS->normalizeFilename(sfxiter->second.mResourceName); + sfxiter->second.mHandle = mOutput->loadSound(sfxiter->second.mResourceName); + } + else if(!sfxiter->second.mHandle) + sfxiter->second.mHandle = mOutput->loadSound(sfxiter->second.mResourceName); + + return &sfxiter->second; + } + + // Gets the combined volume settings for the given sound type float SoundManager::volumeFromType(PlayType type) const { @@ -286,35 +322,21 @@ namespace MWSound startRandomTitle(); } - void SoundManager::say(const MWWorld::Ptr &ptr, const std::string& filename) + void SoundManager::say(const MWWorld::Ptr &ptr, const std::string &filename) { if(!mOutput->isInitialized()) return; try { -#if 0 + const Sound_Buffer *sfx = lookupVoice(Misc::StringUtils::lowerCase(filename)); float basevol = volumeFromType(Play_TypeVoice); - std::string filePath = "sound/"+filename; const ESM::Position &pos = ptr.getRefData().getPosition(); const osg::Vec3f objpos(pos.asVec3()); - MWBase::World* world = MWBase::Environment::get().getWorld(); - static const float fAudioMinDistanceMult = world->getStore().get().find("fAudioMinDistanceMult")->getFloat(); - static const float fAudioMaxDistanceMult = world->getStore().get().find("fAudioMaxDistanceMult")->getFloat(); - static const float fAudioVoiceDefaultMinDistance = world->getStore().get().find("fAudioVoiceDefaultMinDistance")->getFloat(); - static const float fAudioVoiceDefaultMaxDistance = world->getStore().get().find("fAudioVoiceDefaultMaxDistance")->getFloat(); - - float minDistance = fAudioVoiceDefaultMinDistance * fAudioMinDistanceMult; - float maxDistance = fAudioVoiceDefaultMaxDistance * fAudioMaxDistanceMult; - minDistance = std::max(minDistance, 1.f); - maxDistance = std::max(minDistance, maxDistance); - - MWBase::SoundPtr sound = mOutput->playSound3D(filePath, objpos, 1.0f, basevol, 1.0f, - minDistance, maxDistance, Play_Normal|Play_TypeVoice, 0, true); + MWBase::SoundPtr sound = mOutput->playSound3D(sfx->mHandle, + objpos, sfx->mVolume, basevol, 1.0f, sfx->mMinDist, sfx->mMaxDist, Play_Normal|Play_TypeVoice, 0 + ); mActiveSounds[sound] = std::make_pair(ptr, std::string("_say_sound")); -#else - throw std::runtime_error("say disabled"); -#endif } catch(std::exception &e) { @@ -343,15 +365,13 @@ namespace MWSound return; try { -#if 0 + const Sound_Buffer *sfx = lookupVoice(Misc::StringUtils::lowerCase(filename)); float basevol = volumeFromType(Play_TypeVoice); - std::string filePath = "Sound/"+filename; - MWBase::SoundPtr sound = mOutput->playSound(filePath, 1.0f, basevol, 1.0f, Play_Normal|Play_TypeVoice, 0); + MWBase::SoundPtr sound = mOutput->playSound(sfx->mHandle, + sfx->mVolume, basevol, 1.0f, Play_Normal|Play_TypeVoice, 0 + ); mActiveSounds[sound] = std::make_pair(MWWorld::Ptr(), std::string("_say_sound")); -#else - throw std::runtime_error("say disabled"); -#endif } catch(std::exception &e) { diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index d9eb7ff3d..5d605a90f 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -46,6 +46,9 @@ namespace MWSound typedef std::map NameBufferMap; NameBufferMap mSoundBuffers; + // Should stream voices, but that requires handling the "lip" data + // separately from buffer loading. + NameBufferMap mVoiceSoundBuffers; boost::shared_ptr mMusic; std::string mCurrentPlaylist; @@ -64,6 +67,7 @@ namespace MWSound int mPausedSoundTypes; const Sound_Buffer *lookup(const std::string &soundId); + const Sound_Buffer *lookupVoice(const std::string &voicefile); void streamMusicFull(const std::string& filename); bool isPlaying(const MWWorld::Ptr &ptr, const std::string &id) const; From 495e13890793d69452336313761eb77774bbd6de Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 23 Nov 2015 02:08:27 -0800 Subject: [PATCH 2544/3725] Load sound loudness and store it with the Sound_Buffer Still not used for say yet, though --- apps/openmw/mwsound/loudness.cpp | 84 ++++++++++++++----------- apps/openmw/mwsound/loudness.hpp | 44 +++++++++---- apps/openmw/mwsound/openal_output.cpp | 5 +- apps/openmw/mwsound/openal_output.hpp | 2 +- apps/openmw/mwsound/sound.cpp | 23 ------- apps/openmw/mwsound/sound.hpp | 9 --- apps/openmw/mwsound/sound_buffer.hpp | 2 + apps/openmw/mwsound/sound_output.hpp | 3 +- apps/openmw/mwsound/soundmanagerimp.cpp | 6 +- 9 files changed, 90 insertions(+), 88 deletions(-) delete mode 100644 apps/openmw/mwsound/sound.cpp diff --git a/apps/openmw/mwsound/loudness.cpp b/apps/openmw/mwsound/loudness.cpp index 12fe8ae4d..21f399ddc 100644 --- a/apps/openmw/mwsound/loudness.cpp +++ b/apps/openmw/mwsound/loudness.cpp @@ -8,49 +8,61 @@ namespace MWSound { - void analyzeLoudness(const std::vector &data, int sampleRate, ChannelConfig chans, - SampleType type, std::vector &out, float valuesPerSecond) - { - int samplesPerSegment = static_cast(sampleRate / valuesPerSecond); - int numSamples = bytesToFrames(data.size(), chans, type); - int advance = framesToBytes(1, chans, type); +void Sound_Loudness::analyzeLoudness(const std::vector< char >& data, int sampleRate, ChannelConfig chans, SampleType type, float valuesPerSecond) +{ + int samplesPerSegment = static_cast(sampleRate / valuesPerSecond); + int numSamples = bytesToFrames(data.size(), chans, type); + int advance = framesToBytes(1, chans, type); - out.reserve(numSamples/samplesPerSegment); + mSamplesPerSec = valuesPerSecond; + mSamples.clear(); + mSamples.reserve(numSamples/samplesPerSegment); - int segment=0; - int sample=0; - while (segment < numSamples/samplesPerSegment) + int segment=0; + int sample=0; + while (segment < numSamples/samplesPerSegment) + { + float sum=0; + int samplesAdded = 0; + while (sample < numSamples && sample < (segment+1)*samplesPerSegment) { - float sum=0; - int samplesAdded = 0; - while (sample < numSamples && sample < (segment+1)*samplesPerSegment) + // get sample on a scale from -1 to 1 + float value = 0; + if (type == SampleType_UInt8) + value = ((char)(data[sample*advance]^0x80))/128.f; + else if (type == SampleType_Int16) { - // get sample on a scale from -1 to 1 - float value = 0; - if (type == SampleType_UInt8) - value = ((char)(data[sample*advance]^0x80))/128.f; - else if (type == SampleType_Int16) - { - value = *reinterpret_cast(&data[sample*advance]); - value /= float(std::numeric_limits::max()); - } - else if (type == SampleType_Float32) - { - value = *reinterpret_cast(&data[sample*advance]); - value = std::max(-1.f, std::min(1.f, value)); // Float samples *should* be scaled to [-1,1] already. - } - - sum += value*value; - ++samplesAdded; - ++sample; + value = *reinterpret_cast(&data[sample*advance]); + value /= float(std::numeric_limits::max()); + } + else if (type == SampleType_Float32) + { + value = *reinterpret_cast(&data[sample*advance]); + value = std::max(-1.f, std::min(1.f, value)); // Float samples *should* be scaled to [-1,1] already. } - float rms = 0; // root mean square - if (samplesAdded > 0) - rms = std::sqrt(sum / samplesAdded); - out.push_back(rms); - ++segment; + sum += value*value; + ++samplesAdded; + ++sample; } + + float rms = 0; // root mean square + if (samplesAdded > 0) + rms = std::sqrt(sum / samplesAdded); + mSamples.push_back(rms); + ++segment; } +} + + +float Sound_Loudness::getLoudnessAtTime(float sec) const +{ + if(mSamplesPerSec <= 0.0f || mSamples.empty() || sec < 0.0f) + return 0.0f; + + size_t index = static_cast(sec * mSamplesPerSec); + index = std::max(0, std::min(index, mSamples.size()-1)); + return mSamples[index]; +} } diff --git a/apps/openmw/mwsound/loudness.hpp b/apps/openmw/mwsound/loudness.hpp index df727bd0b..a0af2b558 100644 --- a/apps/openmw/mwsound/loudness.hpp +++ b/apps/openmw/mwsound/loudness.hpp @@ -1,20 +1,38 @@ +#ifndef GAME_SOUND_LOUDNESS_H +#define GAME_SOUND_LOUDNESS_H + +#include + #include "sound_decoder.hpp" namespace MWSound { -/** - * Analyzes the energy (closely related to loudness) of a sound buffer. - * The buffer will be divided into segments according to \a valuesPerSecond, - * and for each segment a loudness value in the range of [0,1] will be computed. - * @param data the sound buffer to analyze, containing raw samples - * @param sampleRate the sample rate of the sound buffer - * @param chans channel layout of the buffer - * @param type sample type of the buffer - * @param out Will contain the output loudness values. - * @param valuesPerSecond How many loudness values per second of audio to compute. - */ -void analyzeLoudness (const std::vector& data, int sampleRate, ChannelConfig chans, SampleType type, - std::vector& out, float valuesPerSecond); +class Sound_Loudness { + // Loudness sample info + float mSamplesPerSec; + std::vector mSamples; + +public: + Sound_Loudness() : mSamplesPerSec(0.0f) { } + + /** + * Analyzes the energy (closely related to loudness) of a sound buffer. + * The buffer will be divided into segments according to \a valuesPerSecond, + * and for each segment a loudness value in the range of [0,1] will be computed. + * @param data the sound buffer to analyze, containing raw samples + * @param sampleRate the sample rate of the sound buffer + * @param chans channel layout of the buffer + * @param type sample type of the buffer + * @param valuesPerSecond How many loudness values per second of audio to compute. + */ + void analyzeLoudness(const std::vector& data, int sampleRate, + ChannelConfig chans, SampleType type, + float valuesPerSecond); + + float getLoudnessAtTime(float sec) const; +}; } + +#endif /* GAME_SOUND_LOUDNESS_H */ diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 381c5ba18..82d56ffa0 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -751,7 +751,7 @@ void OpenAL_Output::deinit() } -Sound_Handle OpenAL_Output::loadSound(const std::string &fname) +Sound_Handle OpenAL_Output::loadSound(const std::string &fname, Sound_Loudness *loudness) { throwALerror(); @@ -778,7 +778,8 @@ Sound_Handle OpenAL_Output::loadSound(const std::string &fname) decoder->readAll(data); decoder->close(); - //analyzeLoudness(data, srate, chans, type, cached.mLoudnessVector, static_cast(loudnessFPS)); + if(loudness != 0) + loudness->analyzeLoudness(data, srate, chans, type, static_cast(loudnessFPS)); ALuint buf = 0; try { diff --git a/apps/openmw/mwsound/openal_output.hpp b/apps/openmw/mwsound/openal_output.hpp index 8af46a478..b4c788faa 100644 --- a/apps/openmw/mwsound/openal_output.hpp +++ b/apps/openmw/mwsound/openal_output.hpp @@ -33,7 +33,7 @@ namespace MWSound virtual void init(const std::string &devname=""); virtual void deinit(); - virtual Sound_Handle loadSound(const std::string &fname); + virtual Sound_Handle loadSound(const std::string &fname, Sound_Loudness *loudness); virtual void unloadSound(Sound_Handle data); /// @param offset Value from [0,1] meaning from which fraction the sound the playback starts. diff --git a/apps/openmw/mwsound/sound.cpp b/apps/openmw/mwsound/sound.cpp deleted file mode 100644 index 8b6bfda82..000000000 --- a/apps/openmw/mwsound/sound.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include "sound.hpp" - -namespace MWSound -{ - - float Sound::getCurrentLoudness() - { - if (mLoudnessVector.empty()) - return 0.f; - int index = static_cast(getTimeOffset() * mLoudnessFPS); - - index = std::max(0, std::min(index, int(mLoudnessVector.size()-1))); - - return mLoudnessVector[index]; - } - - void Sound::setLoudnessVector(const std::vector &loudnessVector, float loudnessFPS) - { - mLoudnessVector = loudnessVector; - mLoudnessFPS = loudnessFPS; - } - -} diff --git a/apps/openmw/mwsound/sound.hpp b/apps/openmw/mwsound/sound.hpp index 96f59cea0..53b258a6a 100644 --- a/apps/openmw/mwsound/sound.hpp +++ b/apps/openmw/mwsound/sound.hpp @@ -22,9 +22,6 @@ namespace MWSound int mFlags; float mFadeOutTime; - std::vector mLoudnessVector; - float mLoudnessFPS; - public: virtual void stop() = 0; virtual bool isPlaying() = 0; @@ -32,11 +29,6 @@ namespace MWSound void setPosition(const osg::Vec3f &pos) { mPos = pos; } void setVolume(float volume) { mVolume = volume; } void setFadeout(float duration) { mFadeOutTime=duration; } - void setLoudnessVector(const std::vector& loudnessVector, float loudnessFPS); - - /// Get loudness at the current time position on a [0,1] scale. - /// Requires that loudnessVector was filled in by the user. - float getCurrentLoudness(); MWBase::SoundManager::PlayType getPlayType() const { return (MWBase::SoundManager::PlayType)(mFlags&MWBase::SoundManager::Play_TypeMask); } @@ -51,7 +43,6 @@ namespace MWSound , mMaxDistance(maxdist) , mFlags(flags) , mFadeOutTime(0) - , mLoudnessFPS(20) { } virtual ~Sound() { } diff --git a/apps/openmw/mwsound/sound_buffer.hpp b/apps/openmw/mwsound/sound_buffer.hpp index 37f49e518..8ee7ae342 100644 --- a/apps/openmw/mwsound/sound_buffer.hpp +++ b/apps/openmw/mwsound/sound_buffer.hpp @@ -5,6 +5,7 @@ #include "soundmanagerimp.hpp" #include "sound_output.hpp" +#include "loudness.hpp" #include "../mwworld/ptr.hpp" @@ -19,6 +20,7 @@ namespace MWSound float mMinDist, mMaxDist; Sound_Handle mHandle; + Sound_Loudness mLoudness; Sound_Buffer(std::string resname, float volume, float mindist, float maxdist) : mResourceName(resname), mVolume(volume), mMinDist(mindist), mMaxDist(maxdist), mHandle(0) diff --git a/apps/openmw/mwsound/sound_output.hpp b/apps/openmw/mwsound/sound_output.hpp index cbda19d59..5c437a699 100644 --- a/apps/openmw/mwsound/sound_output.hpp +++ b/apps/openmw/mwsound/sound_output.hpp @@ -13,6 +13,7 @@ namespace MWSound class SoundManager; struct Sound_Decoder; class Sound; + class Sound_Loudness; // An opaque handle for the implementation's sound buffers. typedef void *Sound_Handle; @@ -25,7 +26,7 @@ namespace MWSound virtual void init(const std::string &devname="") = 0; virtual void deinit() = 0; - virtual Sound_Handle loadSound(const std::string &fname) = 0; + virtual Sound_Handle loadSound(const std::string &fname, Sound_Loudness *loudness=0) = 0; virtual void unloadSound(Sound_Handle data) = 0; /// @param offset Value from [0,1] meaning from which fraction the sound the playback starts. diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 6e95c1116..d48c614dd 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -189,10 +189,10 @@ namespace MWSound voicefile, Sound_Buffer("sound/"+voicefile, 1.0f, minDistance, maxDistance) )).first; mVFS->normalizeFilename(sfxiter->second.mResourceName); - sfxiter->second.mHandle = mOutput->loadSound(sfxiter->second.mResourceName); + sfxiter->second.mHandle = mOutput->loadSound(sfxiter->second.mResourceName, &sfxiter->second.mLoudness); } else if(!sfxiter->second.mHandle) - sfxiter->second.mHandle = mOutput->loadSound(sfxiter->second.mResourceName); + sfxiter->second.mHandle = mOutput->loadSound(sfxiter->second.mResourceName, &sfxiter->second.mLoudness); return &sfxiter->second; } @@ -356,7 +356,7 @@ namespace MWSound if (snditer == mActiveSounds.end()) return 0.f; - return snditer->first->getCurrentLoudness(); + return 0.0f; } void SoundManager::say(const std::string& filename) From 9d0018e1bc0ad40dec7b1ab0dca880642e4c7ae7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 23 Nov 2015 03:07:04 -0800 Subject: [PATCH 2545/3725] Reorder active sound data to make lookup by Ptr better --- apps/openmw/mwsound/soundmanagerimp.cpp | 223 ++++++++++++++---------- apps/openmw/mwsound/soundmanagerimp.hpp | 5 +- 2 files changed, 135 insertions(+), 93 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index d48c614dd..4eecf9a14 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -226,12 +226,15 @@ namespace MWSound bool SoundManager::isPlaying(const MWWorld::Ptr &ptr, const std::string &id) const { - SoundMap::const_iterator snditer = mActiveSounds.begin(); - while(snditer != mActiveSounds.end()) + SoundMap::const_iterator snditer = mActiveSounds.find(ptr); + if(snditer != mActiveSounds.end()) { - if(snditer->second.first == ptr && snditer->second.second == id && snditer->first->isPlaying()) - return true; - ++snditer; + SoundNamePairList::const_iterator sndname = snditer->second.begin(); + for(;sndname != snditer->second.end();++sndname) + { + if(sndname->second == id && sndname->first->isPlaying()) + return true; + } } return false; } @@ -336,7 +339,7 @@ namespace MWSound MWBase::SoundPtr sound = mOutput->playSound3D(sfx->mHandle, objpos, sfx->mVolume, basevol, 1.0f, sfx->mMinDist, sfx->mMaxDist, Play_Normal|Play_TypeVoice, 0 ); - mActiveSounds[sound] = std::make_pair(ptr, std::string("_say_sound")); + mActiveSounds[ptr].push_back(std::make_pair(sound, std::string("_say_sound"))); } catch(std::exception &e) { @@ -346,15 +349,16 @@ namespace MWSound float SoundManager::getSaySoundLoudness(const MWWorld::Ptr &ptr) const { - SoundMap::const_iterator snditer = mActiveSounds.begin(); - while(snditer != mActiveSounds.end()) + SoundMap::const_iterator snditer = mActiveSounds.find(ptr); + if(snditer != mActiveSounds.end()) { - if(snditer->second.first == ptr && snditer->second.second == "_say_sound") - break; - ++snditer; + SoundNamePairList::const_iterator sndname = snditer->second.begin(); + for(;sndname != snditer->second.end();++sndname) + { + if(sndname->second == "_say_sound") + return 0.0f; + } } - if (snditer == mActiveSounds.end()) - return 0.f; return 0.0f; } @@ -371,7 +375,7 @@ namespace MWSound MWBase::SoundPtr sound = mOutput->playSound(sfx->mHandle, sfx->mVolume, basevol, 1.0f, Play_Normal|Play_TypeVoice, 0 ); - mActiveSounds[sound] = std::make_pair(MWWorld::Ptr(), std::string("_say_sound")); + mActiveSounds[MWWorld::Ptr()].push_back(std::make_pair(sound, std::string("_say_sound"))); } catch(std::exception &e) { @@ -386,16 +390,21 @@ namespace MWSound void SoundManager::stopSay(const MWWorld::Ptr &ptr) { - SoundMap::iterator snditer = mActiveSounds.begin(); - while(snditer != mActiveSounds.end()) + SoundMap::iterator snditer = mActiveSounds.find(ptr); + if(snditer != mActiveSounds.end()) { - if(snditer->second.first == ptr && snditer->second.second == "_say_sound") + SoundNamePairList::iterator sndname = snditer->second.begin(); + for(;sndname != snditer->second.end();++sndname) { - snditer->first->stop(); - mActiveSounds.erase(snditer++); + if(sndname->second != "_say_sound") + continue; + + sndname->first->stop(); + snditer->second.erase(sndname); + if(snditer->second.empty()) + mActiveSounds.erase(snditer); + return; } - else - ++snditer; } } @@ -430,7 +439,7 @@ namespace MWSound sound = mOutput->playSound(sfx->mHandle, volume * sfx->mVolume, basevol, pitch, mode|type, offset ); - mActiveSounds[sound] = std::make_pair(MWWorld::Ptr(), soundId); + mActiveSounds[MWWorld::Ptr()].push_back(std::make_pair(sound, soundId)); } catch(std::exception&) { @@ -460,9 +469,9 @@ namespace MWSound objpos, volume * sfx->mVolume, basevol, pitch, sfx->mMinDist, sfx->mMaxDist, mode|type, offset ); if((mode&Play_NoTrack)) - mActiveSounds[sound] = std::make_pair(MWWorld::Ptr(), soundId); + mActiveSounds[MWWorld::Ptr()].push_back(std::make_pair(sound, soundId)); else - mActiveSounds[sound] = std::make_pair(ptr, soundId); + mActiveSounds[ptr].push_back(std::make_pair(sound, soundId)); } catch(std::exception&) { @@ -486,7 +495,7 @@ namespace MWSound sound = mOutput->playSound3D(sfx->mHandle, initialPos, volume * sfx->mVolume, basevol, pitch, sfx->mMinDist, sfx->mMaxDist, mode|type, offset ); - mActiveSounds[sound] = std::make_pair(MWWorld::Ptr(), soundId); + mActiveSounds[MWWorld::Ptr()].push_back(std::make_pair(sound, soundId)); } catch(std::exception &) { @@ -500,43 +509,50 @@ namespace MWSound SoundMap::iterator snditer = mActiveSounds.begin(); while(snditer != mActiveSounds.end()) { - if(snditer->first == sound) + SoundNamePairList::iterator sndname = snditer->second.begin(); + for(;sndname != snditer->second.end();++sndname) { - snditer->first->stop(); - mActiveSounds.erase(snditer++); + if(sndname->first != sound) + continue; + + sndname->first->stop(); + snditer->second.erase(sndname); + if(snditer->second.empty()) + mActiveSounds.erase(snditer); + return; } - else - ++snditer; } } void SoundManager::stopSound3D(const MWWorld::Ptr &ptr, const std::string& soundId) { - SoundMap::iterator snditer = mActiveSounds.begin(); - while(snditer != mActiveSounds.end()) + SoundMap::iterator snditer = mActiveSounds.find(ptr); + if(snditer != mActiveSounds.end()) { - if(snditer->second.first == ptr && snditer->second.second == soundId) + SoundNamePairList::iterator sndname = snditer->second.begin(); + for(;sndname != snditer->second.end();++sndname) { - snditer->first->stop(); - mActiveSounds.erase(snditer++); + if(sndname->second != soundId) + continue; + + sndname->first->stop(); + snditer->second.erase(sndname); + if(snditer->second.empty()) + mActiveSounds.erase(snditer); + return; } - else - ++snditer; } } void SoundManager::stopSound3D(const MWWorld::Ptr &ptr) { - SoundMap::iterator snditer = mActiveSounds.begin(); - while(snditer != mActiveSounds.end()) + SoundMap::iterator snditer = mActiveSounds.find(ptr); + if(snditer != mActiveSounds.end()) { - if(snditer->second.first == ptr) - { - snditer->first->stop(); - mActiveSounds.erase(snditer++); - } - else - ++snditer; + SoundNamePairList::iterator sndname = snditer->second.begin(); + for(;sndname != snditer->second.end();++sndname) + sndname->first->stop(); + mActiveSounds.erase(snditer); } } @@ -545,11 +561,13 @@ namespace MWSound SoundMap::iterator snditer = mActiveSounds.begin(); while(snditer != mActiveSounds.end()) { - if(snditer->second.first != MWWorld::Ptr() && - snditer->second.first != MWMechanics::getPlayer() && - snditer->second.first.getCell() == cell) + if(snditer->first != MWWorld::Ptr() && + snditer->first != MWMechanics::getPlayer() && + snditer->first.getCell() == cell) { - snditer->first->stop(); + SoundNamePairList::iterator sndname = snditer->second.begin(); + for(;sndname != snditer->second.end();++sndname) + sndname->first->stop(); mActiveSounds.erase(snditer++); } else @@ -559,31 +577,36 @@ namespace MWSound void SoundManager::stopSound(const std::string& soundId) { - SoundMap::iterator snditer = mActiveSounds.begin(); - while(snditer != mActiveSounds.end()) + SoundMap::iterator snditer = mActiveSounds.find(MWWorld::Ptr()); + if(snditer != mActiveSounds.end()) { - if(snditer->second.first == MWWorld::Ptr() && - snditer->second.second == soundId) + SoundNamePairList::iterator sndname = snditer->second.begin(); + for(;sndname != snditer->second.end();++sndname) { - snditer->first->stop(); - mActiveSounds.erase(snditer++); + if(sndname->second != soundId) + continue; + + sndname->first->stop(); + snditer->second.erase(sndname); + if(snditer->second.empty()) + mActiveSounds.erase(snditer); + return; } - else - ++snditer; } } void SoundManager::fadeOutSound3D(const MWWorld::Ptr &ptr, const std::string& soundId, float duration) { - SoundMap::iterator snditer = mActiveSounds.begin(); - while(snditer != mActiveSounds.end()) + SoundMap::iterator snditer = mActiveSounds.find(ptr); + if(snditer != mActiveSounds.end()) { - if(snditer->second.first == ptr && snditer->second.second == soundId) + SoundNamePairList::iterator sndname = snditer->second.begin(); + for(;sndname != snditer->second.end();++sndname) { - snditer->first->setFadeout(duration); + if(sndname->second == soundId) + sndname->first->setFadeout(duration); } - ++snditer; } } @@ -714,37 +737,47 @@ namespace MWSound SoundMap::iterator snditer = mActiveSounds.begin(); while(snditer != mActiveSounds.end()) { - if(!snditer->first->isPlaying()) - mActiveSounds.erase(snditer++); - else + SoundNamePairList::iterator sndname = snditer->second.begin(); + while(sndname != snditer->second.end()) { - const MWWorld::Ptr &ptr = snditer->second.first; + if(!sndname->first->isPlaying()) + { + sndname = snditer->second.erase(sndname); + continue; + } + + const MWWorld::Ptr &ptr = snditer->first; if(!ptr.isEmpty()) { const ESM::Position &pos = ptr.getRefData().getPosition(); const osg::Vec3f objpos(pos.asVec3()); - snditer->first->setPosition(objpos); + sndname->first->setPosition(objpos); - if ((snditer->first->mFlags & Play_RemoveAtDistance) + if ((sndname->first->mFlags & Play_RemoveAtDistance) && (mListenerPos - ptr.getRefData().getPosition().asVec3()).length2() > 2000*2000) { - mActiveSounds.erase(snditer++); + sndname = snditer->second.erase(sndname); continue; } } + //update fade out - if(snditer->first->mFadeOutTime>0) + if(sndname->first->mFadeOutTime > 0.0f) { - float soundDuration=duration; - if(soundDuration>snditer->first->mFadeOutTime) - soundDuration=snditer->first->mFadeOutTime; - snditer->first->setVolume(snditer->first->mVolume - - soundDuration / snditer->first->mFadeOutTime * snditer->first->mVolume); - snditer->first->mFadeOutTime -= soundDuration; + float soundDuration = duration; + if(soundDuration > sndname->first->mFadeOutTime) + soundDuration = sndname->first->mFadeOutTime; + sndname->first->setVolume(sndname->first->mVolume + - soundDuration / sndname->first->mFadeOutTime * sndname->first->mVolume); + sndname->first->mFadeOutTime -= soundDuration; } - snditer->first->update(); - ++snditer; + sndname->first->update(); + ++sndname; } + if(snditer->second.empty()) + mActiveSounds.erase(snditer++); + else + ++snditer; } } @@ -771,11 +804,14 @@ namespace MWSound mVoiceVolume = Settings::Manager::getFloat("voice volume", "Sound"); SoundMap::iterator snditer = mActiveSounds.begin(); - while(snditer != mActiveSounds.end()) + for(;snditer != mActiveSounds.end();++snditer) { - snditer->first->mBaseVolume = volumeFromType(snditer->first->getPlayType()); - snditer->first->update(); - ++snditer; + SoundNamePairList::iterator sndname = snditer->second.begin(); + for(;sndname != snditer->second.end();++sndname) + { + sndname->first->mBaseVolume = volumeFromType(sndname->first->getPlayType()); + sndname->first->update(); + } } if(mMusic) { @@ -790,8 +826,7 @@ namespace MWSound mListenerDir = dir; mListenerUp = up; - MWWorld::Ptr player = - MWMechanics::getPlayer(); + MWWorld::Ptr player = MWMechanics::getPlayer(); const MWWorld::CellStore *cell = player.getCell(); mListenerUnderwater = ((cell->getCell()->mData.mFlags&ESM::Cell::HasWater) && mListenerPos.z() < cell->getWaterLevel()); @@ -799,10 +834,12 @@ namespace MWSound void SoundManager::updatePtr(const MWWorld::Ptr &old, const MWWorld::Ptr &updated) { - for (SoundMap::iterator snditer = mActiveSounds.begin(); snditer != mActiveSounds.end(); ++snditer) + SoundMap::iterator snditer = mActiveSounds.find(old); + if(snditer != mActiveSounds.end()) { - if (snditer->second.first == old) - snditer->second.first = updated; + SoundNamePairList sndlist = snditer->second; + mActiveSounds.erase(snditer); + mActiveSounds[updated] = sndlist; } } @@ -873,9 +910,13 @@ namespace MWSound void SoundManager::clear() { - for (SoundMap::iterator iter (mActiveSounds.begin()); iter!=mActiveSounds.end(); ++iter) - iter->first->stop(); - + SoundMap::iterator snditer = mActiveSounds.begin(); + for(;snditer != mActiveSounds.end();++snditer) + { + SoundNamePairList::iterator sndname = snditer->second.begin(); + for(;sndname != snditer->second.end();++sndname) + sndname->first->stop(); + } mActiveSounds.clear(); stopMusic(); } diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index 5d605a90f..999a49f8c 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -53,8 +53,9 @@ namespace MWSound boost::shared_ptr mMusic; std::string mCurrentPlaylist; - typedef std::pair PtrIDPair; - typedef std::map SoundMap; + typedef std::pair SoundNamePair; + typedef std::vector SoundNamePairList; + typedef std::map SoundMap; SoundMap mActiveSounds; MWBase::SoundPtr mUnderwaterSound; From 3fdc3c4ea948dd5e108eabbaaa986e6ab2560d09 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 23 Nov 2015 04:00:10 -0800 Subject: [PATCH 2546/3725] Use a separate map for say sounds Also restores lip movement --- apps/openmw/mwsound/soundmanagerimp.cpp | 171 ++++++++++++++++-------- apps/openmw/mwsound/soundmanagerimp.hpp | 3 + 2 files changed, 121 insertions(+), 53 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 4eecf9a14..262bc0644 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -92,6 +92,10 @@ namespace MWSound SoundManager::~SoundManager() { + mUnderwaterSound.reset(); + mActiveSounds.clear(); + mActiveSaySounds.clear(); + mMusic.reset(); if(mOutput->isInitialized()) { NameBufferMap::iterator sfxiter = mSoundBuffers.begin(); @@ -109,9 +113,6 @@ namespace MWSound sfxiter->second.mHandle = 0; } } - mUnderwaterSound.reset(); - mActiveSounds.clear(); - mMusic.reset(); mOutput.reset(); } @@ -224,21 +225,6 @@ namespace MWSound return volume; } - bool SoundManager::isPlaying(const MWWorld::Ptr &ptr, const std::string &id) const - { - SoundMap::const_iterator snditer = mActiveSounds.find(ptr); - if(snditer != mActiveSounds.end()) - { - SoundNamePairList::const_iterator sndname = snditer->second.begin(); - for(;sndname != snditer->second.end();++sndname) - { - if(sndname->second == id && sndname->first->isPlaying()) - return true; - } - } - return false; - } - void SoundManager::stopMusic() { @@ -325,13 +311,15 @@ namespace MWSound startRandomTitle(); } + void SoundManager::say(const MWWorld::Ptr &ptr, const std::string &filename) { if(!mOutput->isInitialized()) return; try { - const Sound_Buffer *sfx = lookupVoice(Misc::StringUtils::lowerCase(filename)); + std::string voicefile = Misc::StringUtils::lowerCase(filename); + const Sound_Buffer *sfx = lookupVoice(voicefile); float basevol = volumeFromType(Play_TypeVoice); const ESM::Position &pos = ptr.getRefData().getPosition(); const osg::Vec3f objpos(pos.asVec3()); @@ -339,7 +327,7 @@ namespace MWSound MWBase::SoundPtr sound = mOutput->playSound3D(sfx->mHandle, objpos, sfx->mVolume, basevol, 1.0f, sfx->mMinDist, sfx->mMaxDist, Play_Normal|Play_TypeVoice, 0 ); - mActiveSounds[ptr].push_back(std::make_pair(sound, std::string("_say_sound"))); + mActiveSaySounds[ptr] = std::make_pair(sound, voicefile); } catch(std::exception &e) { @@ -349,14 +337,15 @@ namespace MWSound float SoundManager::getSaySoundLoudness(const MWWorld::Ptr &ptr) const { - SoundMap::const_iterator snditer = mActiveSounds.find(ptr); - if(snditer != mActiveSounds.end()) + SaySoundMap::const_iterator snditer = mActiveSaySounds.find(ptr); + if(snditer != mActiveSaySounds.end()) { - SoundNamePairList::const_iterator sndname = snditer->second.begin(); - for(;sndname != snditer->second.end();++sndname) + NameBufferMap::const_iterator sfxiter = mVoiceSoundBuffers.find(snditer->second.second); + if(sfxiter != mVoiceSoundBuffers.end()) { - if(sndname->second == "_say_sound") - return 0.0f; + float sec = snditer->second.first->getTimeOffset(); + if(snditer->second.first->isPlaying()) + return sfxiter->second.mLoudness.getLoudnessAtTime(sec); } } @@ -369,13 +358,14 @@ namespace MWSound return; try { - const Sound_Buffer *sfx = lookupVoice(Misc::StringUtils::lowerCase(filename)); + std::string voicefile = Misc::StringUtils::lowerCase(filename); + const Sound_Buffer *sfx = lookupVoice(voicefile); float basevol = volumeFromType(Play_TypeVoice); MWBase::SoundPtr sound = mOutput->playSound(sfx->mHandle, sfx->mVolume, basevol, 1.0f, Play_Normal|Play_TypeVoice, 0 ); - mActiveSounds[MWWorld::Ptr()].push_back(std::make_pair(sound, std::string("_say_sound"))); + mActiveSaySounds[MWWorld::Ptr()] = std::make_pair(sound, voicefile); } catch(std::exception &e) { @@ -385,26 +375,22 @@ namespace MWSound bool SoundManager::sayDone(const MWWorld::Ptr &ptr) const { - return !isPlaying(ptr, "_say_sound"); + SaySoundMap::const_iterator snditer = mActiveSaySounds.find(ptr); + if(snditer != mActiveSaySounds.end()) + { + if(snditer->second.first->isPlaying()) + return false; + } + return true; } void SoundManager::stopSay(const MWWorld::Ptr &ptr) { - SoundMap::iterator snditer = mActiveSounds.find(ptr); - if(snditer != mActiveSounds.end()) + SaySoundMap::iterator snditer = mActiveSaySounds.find(ptr); + if(snditer != mActiveSaySounds.end()) { - SoundNamePairList::iterator sndname = snditer->second.begin(); - for(;sndname != snditer->second.end();++sndname) - { - if(sndname->second != "_say_sound") - continue; - - sndname->first->stop(); - snditer->second.erase(sndname); - if(snditer->second.empty()) - mActiveSounds.erase(snditer); - return; - } + snditer->second.first->stop(); + mActiveSaySounds.erase(snditer); } } @@ -426,6 +412,21 @@ namespace MWSound } + bool SoundManager::isPlaying(const MWWorld::Ptr &ptr, const std::string &id) const + { + SoundMap::const_iterator snditer = mActiveSounds.find(ptr); + if(snditer != mActiveSounds.end()) + { + SoundNamePairList::const_iterator sndname = snditer->second.begin(); + for(;sndname != snditer->second.end();++sndname) + { + if(sndname->second == id && sndname->first->isPlaying()) + return true; + } + } + return false; + } + MWBase::SoundPtr SoundManager::playSound(const std::string& soundId, float volume, float pitch, PlayType type, PlayMode mode, float offset) { MWBase::SoundPtr sound; @@ -573,6 +574,19 @@ namespace MWSound else ++snditer; } + SaySoundMap::iterator sayiter = mActiveSaySounds.begin(); + while(sayiter != mActiveSaySounds.end()) + { + if(sayiter->first != MWWorld::Ptr() && + sayiter->first != MWMechanics::getPlayer() && + sayiter->first.getCell() == cell) + { + sayiter->second.first->stop(); + mActiveSaySounds.erase(sayiter++); + } + else + ++sayiter; + } } void SoundManager::stopSound(const std::string& soundId) @@ -740,7 +754,8 @@ namespace MWSound SoundNamePairList::iterator sndname = snditer->second.begin(); while(sndname != snditer->second.end()) { - if(!sndname->first->isPlaying()) + MWBase::SoundPtr sound = sndname->first; + if(!sound->isPlaying()) { sndname = snditer->second.erase(sndname); continue; @@ -751,9 +766,9 @@ namespace MWSound { const ESM::Position &pos = ptr.getRefData().getPosition(); const osg::Vec3f objpos(pos.asVec3()); - sndname->first->setPosition(objpos); + sound->setPosition(objpos); - if ((sndname->first->mFlags & Play_RemoveAtDistance) + if ((sound->mFlags & Play_RemoveAtDistance) && (mListenerPos - ptr.getRefData().getPosition().asVec3()).length2() > 2000*2000) { sndname = snditer->second.erase(sndname); @@ -762,16 +777,16 @@ namespace MWSound } //update fade out - if(sndname->first->mFadeOutTime > 0.0f) + if(sound->mFadeOutTime > 0.0f) { float soundDuration = duration; - if(soundDuration > sndname->first->mFadeOutTime) - soundDuration = sndname->first->mFadeOutTime; - sndname->first->setVolume(sndname->first->mVolume - - soundDuration / sndname->first->mFadeOutTime * sndname->first->mVolume); - sndname->first->mFadeOutTime -= soundDuration; + if(soundDuration > sound->mFadeOutTime) + soundDuration = sound->mFadeOutTime; + sound->setVolume(sound->mVolume - soundDuration/sound->mFadeOutTime*sound->mVolume); + sound->mFadeOutTime -= soundDuration; } - sndname->first->update(); + sound->update(); + ++sndname; } if(snditer->second.empty()) @@ -779,6 +794,45 @@ namespace MWSound else ++snditer; } + + SaySoundMap::iterator sayiter = mActiveSaySounds.begin(); + while(sayiter != mActiveSaySounds.end()) + { + MWBase::SoundPtr sound = sayiter->second.first; + if(!sound->isPlaying()) + { + mActiveSaySounds.erase(sayiter++); + continue; + } + + const MWWorld::Ptr &ptr = sayiter->first; + if(!ptr.isEmpty()) + { + const ESM::Position &pos = ptr.getRefData().getPosition(); + const osg::Vec3f objpos(pos.asVec3()); + sound->setPosition(objpos); + + if ((sound->mFlags & Play_RemoveAtDistance) + && (mListenerPos - ptr.getRefData().getPosition().asVec3()).length2() > 2000*2000) + { + mActiveSaySounds.erase(sayiter++); + continue; + } + } + + //update fade out + if(sound->mFadeOutTime > 0.0f) + { + float soundDuration = duration; + if(soundDuration > sound->mFadeOutTime) + soundDuration = sound->mFadeOutTime; + sound->setVolume(sound->mVolume - soundDuration/sound->mFadeOutTime*sound->mVolume); + sound->mFadeOutTime -= soundDuration; + } + sound->update(); + + ++sayiter; + } } void SoundManager::update(float duration) @@ -841,6 +895,13 @@ namespace MWSound mActiveSounds.erase(snditer); mActiveSounds[updated] = sndlist; } + SaySoundMap::iterator sayiter = mActiveSaySounds.find(old); + if(sayiter != mActiveSaySounds.end()) + { + SoundNamePair sndlist = sayiter->second; + mActiveSaySounds.erase(sayiter); + mActiveSaySounds[updated] = sndlist; + } } // Default readAll implementation, for decoders that can't do anything @@ -918,6 +979,10 @@ namespace MWSound sndname->first->stop(); } mActiveSounds.clear(); + SaySoundMap::iterator sayiter = mActiveSaySounds.begin(); + for(;sayiter != mActiveSaySounds.end();++sayiter) + sayiter->second.first->stop(); + mActiveSaySounds.clear(); stopMusic(); } } diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index 999a49f8c..acd04fc07 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -58,6 +58,9 @@ namespace MWSound typedef std::map SoundMap; SoundMap mActiveSounds; + typedef std::map SaySoundMap; + SaySoundMap mActiveSaySounds; + MWBase::SoundPtr mUnderwaterSound; bool mListenerUnderwater; From febc7b510a0718620c12f7d6695c45b818654c0e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 23 Nov 2015 04:10:56 -0800 Subject: [PATCH 2547/3725] Remove an unneeded method --- apps/openmw/mwsound/soundmanagerimp.cpp | 27 ++++++++++--------------- apps/openmw/mwsound/soundmanagerimp.hpp | 1 - 2 files changed, 11 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 262bc0644..73c9060bd 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -412,21 +412,6 @@ namespace MWSound } - bool SoundManager::isPlaying(const MWWorld::Ptr &ptr, const std::string &id) const - { - SoundMap::const_iterator snditer = mActiveSounds.find(ptr); - if(snditer != mActiveSounds.end()) - { - SoundNamePairList::const_iterator sndname = snditer->second.begin(); - for(;sndname != snditer->second.end();++sndname) - { - if(sndname->second == id && sndname->first->isPlaying()) - return true; - } - } - return false; - } - MWBase::SoundPtr SoundManager::playSound(const std::string& soundId, float volume, float pitch, PlayType type, PlayMode mode, float offset) { MWBase::SoundPtr sound; @@ -626,7 +611,17 @@ namespace MWSound bool SoundManager::getSoundPlaying(const MWWorld::Ptr &ptr, const std::string& soundId) const { - return isPlaying(ptr, soundId); + SoundMap::const_iterator snditer = mActiveSounds.find(ptr); + if(snditer != mActiveSounds.end()) + { + SoundNamePairList::const_iterator sndname = snditer->second.begin(); + for(;sndname != snditer->second.end();++sndname) + { + if(sndname->second == soundId && sndname->first->isPlaying()) + return true; + } + } + return false; } diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index acd04fc07..896cf48a7 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -74,7 +74,6 @@ namespace MWSound const Sound_Buffer *lookupVoice(const std::string &voicefile); void streamMusicFull(const std::string& filename); - bool isPlaying(const MWWorld::Ptr &ptr, const std::string &id) const; void updateSounds(float duration); void updateRegionSound(float duration); From e36289681776bdbe4556a98816029fe71596e511 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 23 Nov 2015 04:31:15 -0800 Subject: [PATCH 2548/3725] Combine some duplicate code --- apps/openmw/mwsound/soundmanagerimp.cpp | 108 +++++++++--------------- apps/openmw/mwsound/soundmanagerimp.hpp | 1 + 2 files changed, 42 insertions(+), 67 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 73c9060bd..e00e5eecd 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -722,12 +722,7 @@ namespace MWSound Environment env = Env_Normal; if (mListenerUnderwater) - { env = Env_Underwater; - //play underwater sound - if(!(mUnderwaterSound && mUnderwaterSound->isPlaying())) - mUnderwaterSound = playSound("Underwater", 1.0f, 1.0f, Play_TypeSfx, Play_LoopNoEnv); - } else if(mUnderwaterSound) { mUnderwaterSound->stop(); @@ -741,48 +736,24 @@ namespace MWSound env ); + if(mListenerUnderwater) + { + // Play underwater sound (after updating listener) + if(!(mUnderwaterSound && mUnderwaterSound->isPlaying())) + mUnderwaterSound = playSound("Underwater", 1.0f, 1.0f, Play_TypeSfx, Play_LoopNoEnv); + } + // Check if any sounds are finished playing, and trash them - // Lower volume on fading out sounds SoundMap::iterator snditer = mActiveSounds.begin(); while(snditer != mActiveSounds.end()) { SoundNamePairList::iterator sndname = snditer->second.begin(); while(sndname != snditer->second.end()) { - MWBase::SoundPtr sound = sndname->first; - if(!sound->isPlaying()) - { + if(!updateSound(sndname->first, snditer->first, duration)) sndname = snditer->second.erase(sndname); - continue; - } - - const MWWorld::Ptr &ptr = snditer->first; - if(!ptr.isEmpty()) - { - const ESM::Position &pos = ptr.getRefData().getPosition(); - const osg::Vec3f objpos(pos.asVec3()); - sound->setPosition(objpos); - - if ((sound->mFlags & Play_RemoveAtDistance) - && (mListenerPos - ptr.getRefData().getPosition().asVec3()).length2() > 2000*2000) - { - sndname = snditer->second.erase(sndname); - continue; - } - } - - //update fade out - if(sound->mFadeOutTime > 0.0f) - { - float soundDuration = duration; - if(soundDuration > sound->mFadeOutTime) - soundDuration = sound->mFadeOutTime; - sound->setVolume(sound->mVolume - soundDuration/sound->mFadeOutTime*sound->mVolume); - sound->mFadeOutTime -= soundDuration; - } - sound->update(); - - ++sndname; + else + ++sndname; } if(snditer->second.empty()) mActiveSounds.erase(snditer++); @@ -793,43 +764,46 @@ namespace MWSound SaySoundMap::iterator sayiter = mActiveSaySounds.begin(); while(sayiter != mActiveSaySounds.end()) { - MWBase::SoundPtr sound = sayiter->second.first; - if(!sound->isPlaying()) - { + if(!updateSound(sayiter->second.first, sayiter->first, duration)) mActiveSaySounds.erase(sayiter++); - continue; - } + else + ++sayiter; + } + } - const MWWorld::Ptr &ptr = sayiter->first; - if(!ptr.isEmpty()) - { - const ESM::Position &pos = ptr.getRefData().getPosition(); - const osg::Vec3f objpos(pos.asVec3()); - sound->setPosition(objpos); - - if ((sound->mFlags & Play_RemoveAtDistance) - && (mListenerPos - ptr.getRefData().getPosition().asVec3()).length2() > 2000*2000) - { - mActiveSaySounds.erase(sayiter++); - continue; - } - } + bool SoundManager::updateSound(MWBase::SoundPtr sound, const MWWorld::Ptr& ptr, float duration) + { + if(!ptr.isEmpty()) + { + const ESM::Position &pos = ptr.getRefData().getPosition(); + const osg::Vec3f objpos(pos.asVec3()); + sound->setPosition(objpos); - //update fade out - if(sound->mFadeOutTime > 0.0f) + if((sound->mFlags&Play_RemoveAtDistance)) { - float soundDuration = duration; - if(soundDuration > sound->mFadeOutTime) - soundDuration = sound->mFadeOutTime; - sound->setVolume(sound->mVolume - soundDuration/sound->mFadeOutTime*sound->mVolume); - sound->mFadeOutTime -= soundDuration; + osg::Vec3f diff = mListenerPos - ptr.getRefData().getPosition().asVec3(); + if(diff.length2() > 2000*2000) + sound->stop(); } - sound->update(); + } + + if(!sound->isPlaying()) + return false; - ++sayiter; + // Update fade out + if(sound->mFadeOutTime > 0.0f) + { + float soundDuration = duration; + if(soundDuration > sound->mFadeOutTime) + soundDuration = sound->mFadeOutTime; + sound->setVolume(sound->mVolume - soundDuration/sound->mFadeOutTime*sound->mVolume); + sound->mFadeOutTime -= soundDuration; } + sound->update(); + return true; } + void SoundManager::update(float duration) { if(!mOutput->isInitialized()) diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index 896cf48a7..db60df044 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -74,6 +74,7 @@ namespace MWSound const Sound_Buffer *lookupVoice(const std::string &voicefile); void streamMusicFull(const std::string& filename); + bool updateSound(MWBase::SoundPtr sound, const MWWorld::Ptr &ptr, float duration); void updateSounds(float duration); void updateRegionSound(float duration); From 407349507071f674fbb59e6566a0851c08b0f46b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 23 Nov 2015 04:48:18 -0800 Subject: [PATCH 2549/3725] Add some missing sound handling --- apps/openmw/mwsound/soundmanagerimp.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index e00e5eecd..f984bd96f 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -95,6 +95,7 @@ namespace MWSound mUnderwaterSound.reset(); mActiveSounds.clear(); mActiveSaySounds.clear(); + mUnderwaterSound.reset(); mMusic.reset(); if(mOutput->isInitialized()) { @@ -832,10 +833,18 @@ namespace MWSound SoundNamePairList::iterator sndname = snditer->second.begin(); for(;sndname != snditer->second.end();++sndname) { - sndname->first->mBaseVolume = volumeFromType(sndname->first->getPlayType()); - sndname->first->update(); + MWBase::SoundPtr sound = sndname->first; + sound->mBaseVolume = volumeFromType(sound->getPlayType()); + sound->update(); } } + SaySoundMap::iterator sayiter = mActiveSaySounds.begin(); + for(;sayiter != mActiveSaySounds.end();++sayiter) + { + MWBase::SoundPtr sound = sayiter->second.first; + sound->mBaseVolume = volumeFromType(sound->getPlayType()); + sound->update(); + } if(mMusic) { mMusic->mBaseVolume = volumeFromType(mMusic->getPlayType()); @@ -952,6 +961,7 @@ namespace MWSound for(;sayiter != mActiveSaySounds.end();++sayiter) sayiter->second.first->stop(); mActiveSaySounds.clear(); + mUnderwaterSound.reset(); stopMusic(); } } From 0b2747098c0293fbf09b54b6f785d51bb2566a95 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 23 Nov 2015 06:35:01 -0800 Subject: [PATCH 2550/3725] Keep track of unused sound buffers --- apps/openmw/mwsound/sound_output.hpp | 3 - apps/openmw/mwsound/soundmanagerimp.cpp | 94 ++++++++++++------------- apps/openmw/mwsound/soundmanagerimp.hpp | 8 +++ 3 files changed, 52 insertions(+), 53 deletions(-) diff --git a/apps/openmw/mwsound/sound_output.hpp b/apps/openmw/mwsound/sound_output.hpp index 5c437a699..4c1691ed1 100644 --- a/apps/openmw/mwsound/sound_output.hpp +++ b/apps/openmw/mwsound/sound_output.hpp @@ -15,9 +15,6 @@ namespace MWSound class Sound; class Sound_Loudness; - // An opaque handle for the implementation's sound buffers. - typedef void *Sound_Handle; - class Sound_Output { SoundManager &mManager; diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index f984bd96f..7f0a11817 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -92,11 +92,7 @@ namespace MWSound SoundManager::~SoundManager() { - mUnderwaterSound.reset(); - mActiveSounds.clear(); - mActiveSaySounds.clear(); - mUnderwaterSound.reset(); - mMusic.reset(); + clear(); if(mOutput->isInitialized()) { NameBufferMap::iterator sfxiter = mSoundBuffers.begin(); @@ -128,6 +124,9 @@ namespace MWSound const Sound_Buffer *SoundManager::lookup(const std::string &soundId) { NameBufferMap::iterator sfxiter = mSoundBuffers.find(soundId); + if(sfxiter != mSoundBuffers.end() && sfxiter->second.mHandle) + return &sfxiter->second; + if(sfxiter == mSoundBuffers.end()) { // TODO: We could process all available ESM::Sound records on init @@ -163,10 +162,10 @@ namespace MWSound soundId, Sound_Buffer("Sound/"+snd->mSound, volume, min, max) )).first; mVFS->normalizeFilename(sfxiter->second.mResourceName); - sfxiter->second.mHandle = mOutput->loadSound(sfxiter->second.mResourceName); } - else if(!sfxiter->second.mHandle) - sfxiter->second.mHandle = mOutput->loadSound(sfxiter->second.mResourceName); + + sfxiter->second.mHandle = mOutput->loadSound(sfxiter->second.mResourceName); + mUnusedBuffers.insert(sfxiter->second.mHandle); return &sfxiter->second; } @@ -420,13 +419,16 @@ namespace MWSound return sound; try { - const Sound_Buffer *sfx = lookup(Misc::StringUtils::lowerCase(soundId)); + std::string soundid = Misc::StringUtils::lowerCase(soundId); + const Sound_Buffer *sfx = lookup(soundid); float basevol = volumeFromType(type); sound = mOutput->playSound(sfx->mHandle, volume * sfx->mVolume, basevol, pitch, mode|type, offset ); - mActiveSounds[MWWorld::Ptr()].push_back(std::make_pair(sound, soundId)); + if(mBufferRefs[sfx->mHandle]++ == 0) + mUnusedBuffers.erase(sfx->mHandle); + mActiveSounds[MWWorld::Ptr()].push_back(std::make_pair(sound, soundid)); } catch(std::exception&) { @@ -444,7 +446,8 @@ namespace MWSound try { // Look up the sound in the ESM data - const Sound_Buffer *sfx = lookup(Misc::StringUtils::lowerCase(soundId)); + std::string soundid = Misc::StringUtils::lowerCase(soundId); + const Sound_Buffer *sfx = lookup(soundid); float basevol = volumeFromType(type); const ESM::Position &pos = ptr.getRefData().getPosition(); const osg::Vec3f objpos(pos.asVec3()); @@ -455,10 +458,12 @@ namespace MWSound sound = mOutput->playSound3D(sfx->mHandle, objpos, volume * sfx->mVolume, basevol, pitch, sfx->mMinDist, sfx->mMaxDist, mode|type, offset ); + if(mBufferRefs[sfx->mHandle]++ == 0) + mUnusedBuffers.erase(sfx->mHandle); if((mode&Play_NoTrack)) - mActiveSounds[MWWorld::Ptr()].push_back(std::make_pair(sound, soundId)); + mActiveSounds[MWWorld::Ptr()].push_back(std::make_pair(sound, soundid)); else - mActiveSounds[ptr].push_back(std::make_pair(sound, soundId)); + mActiveSounds[ptr].push_back(std::make_pair(sound, soundid)); } catch(std::exception&) { @@ -476,13 +481,16 @@ namespace MWSound try { // Look up the sound in the ESM data - const Sound_Buffer *sfx = lookup(Misc::StringUtils::lowerCase(soundId)); + std::string soundid = Misc::StringUtils::lowerCase(soundId); + const Sound_Buffer *sfx = lookup(soundid); float basevol = volumeFromType(type); sound = mOutput->playSound3D(sfx->mHandle, initialPos, volume * sfx->mVolume, basevol, pitch, sfx->mMinDist, sfx->mMaxDist, mode|type, offset ); - mActiveSounds[MWWorld::Ptr()].push_back(std::make_pair(sound, soundId)); + if(mBufferRefs[sfx->mHandle]++ == 0) + mUnusedBuffers.erase(sfx->mHandle); + mActiveSounds[MWWorld::Ptr()].push_back(std::make_pair(sound, soundid)); } catch(std::exception &) { @@ -493,22 +501,7 @@ namespace MWSound void SoundManager::stopSound (MWBase::SoundPtr sound) { - SoundMap::iterator snditer = mActiveSounds.begin(); - while(snditer != mActiveSounds.end()) - { - SoundNamePairList::iterator sndname = snditer->second.begin(); - for(;sndname != snditer->second.end();++sndname) - { - if(sndname->first != sound) - continue; - - sndname->first->stop(); - snditer->second.erase(sndname); - if(snditer->second.empty()) - mActiveSounds.erase(snditer); - return; - } - } + sound->stop(); } void SoundManager::stopSound3D(const MWWorld::Ptr &ptr, const std::string& soundId) @@ -516,16 +509,13 @@ namespace MWSound SoundMap::iterator snditer = mActiveSounds.find(ptr); if(snditer != mActiveSounds.end()) { + std::string soundid = Misc::StringUtils::lowerCase(soundId); SoundNamePairList::iterator sndname = snditer->second.begin(); for(;sndname != snditer->second.end();++sndname) { - if(sndname->second != soundId) + if(sndname->second != soundid) continue; - sndname->first->stop(); - snditer->second.erase(sndname); - if(snditer->second.empty()) - mActiveSounds.erase(snditer); return; } } @@ -539,7 +529,6 @@ namespace MWSound SoundNamePairList::iterator sndname = snditer->second.begin(); for(;sndname != snditer->second.end();++sndname) sndname->first->stop(); - mActiveSounds.erase(snditer); } } @@ -555,10 +544,8 @@ namespace MWSound SoundNamePairList::iterator sndname = snditer->second.begin(); for(;sndname != snditer->second.end();++sndname) sndname->first->stop(); - mActiveSounds.erase(snditer++); } - else - ++snditer; + ++snditer; } SaySoundMap::iterator sayiter = mActiveSaySounds.begin(); while(sayiter != mActiveSaySounds.end()) @@ -568,10 +555,8 @@ namespace MWSound sayiter->first.getCell() == cell) { sayiter->second.first->stop(); - mActiveSaySounds.erase(sayiter++); } - else - ++sayiter; + ++sayiter; } } @@ -580,16 +565,13 @@ namespace MWSound SoundMap::iterator snditer = mActiveSounds.find(MWWorld::Ptr()); if(snditer != mActiveSounds.end()) { + std::string soundid = Misc::StringUtils::lowerCase(soundId); SoundNamePairList::iterator sndname = snditer->second.begin(); for(;sndname != snditer->second.end();++sndname) { - if(sndname->second != soundId) + if(sndname->second != soundid) continue; - sndname->first->stop(); - snditer->second.erase(sndname); - if(snditer->second.empty()) - mActiveSounds.erase(snditer); return; } } @@ -601,10 +583,11 @@ namespace MWSound SoundMap::iterator snditer = mActiveSounds.find(ptr); if(snditer != mActiveSounds.end()) { + std::string soundid = Misc::StringUtils::lowerCase(soundId); SoundNamePairList::iterator sndname = snditer->second.begin(); for(;sndname != snditer->second.end();++sndname) { - if(sndname->second == soundId) + if(sndname->second == soundid) sndname->first->setFadeout(duration); } } @@ -615,10 +598,11 @@ namespace MWSound SoundMap::const_iterator snditer = mActiveSounds.find(ptr); if(snditer != mActiveSounds.end()) { + std::string soundid = Misc::StringUtils::lowerCase(soundId); SoundNamePairList::const_iterator sndname = snditer->second.begin(); for(;sndname != snditer->second.end();++sndname) { - if(sndname->second == soundId && sndname->first->isPlaying()) + if(sndname->second == soundid && sndname->first->isPlaying()) return true; } } @@ -752,7 +736,12 @@ namespace MWSound while(sndname != snditer->second.end()) { if(!updateSound(sndname->first, snditer->first, duration)) + { + NameBufferMap::iterator sfxiter = mSoundBuffers.find(sndname->second); + if(mBufferRefs[sfxiter->second.mHandle]-- == 1) + mUnusedBuffers.insert(sfxiter->second.mHandle); sndname = snditer->second.erase(sndname); + } else ++sndname; } @@ -954,7 +943,12 @@ namespace MWSound { SoundNamePairList::iterator sndname = snditer->second.begin(); for(;sndname != snditer->second.end();++sndname) + { sndname->first->stop(); + NameBufferMap::iterator sfxiter = mSoundBuffers.find(sndname->second); + if(mBufferRefs[sfxiter->second.mHandle]-- <= 1) + mUnusedBuffers.insert(sfxiter->second.mHandle); + } } mActiveSounds.clear(); SaySoundMap::iterator sayiter = mActiveSaySounds.begin(); diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index db60df044..cb6c93044 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -23,6 +23,9 @@ namespace MWSound class Sound; class Sound_Buffer; + // An opaque handle for the implementation's sound buffers. + typedef void *Sound_Handle; + enum Environment { Env_Normal, Env_Underwater @@ -50,6 +53,11 @@ namespace MWSound // separately from buffer loading. NameBufferMap mVoiceSoundBuffers; + typedef std::map SoundRefMap; + SoundRefMap mBufferRefs; + typedef std::set SoundSet; + SoundSet mUnusedBuffers; + boost::shared_ptr mMusic; std::string mCurrentPlaylist; From 22a681142599f266986b6f89e8f5d0e743fec0f3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 23 Nov 2015 06:52:37 -0800 Subject: [PATCH 2551/3725] Limit the sound buffer cache to 15MB --- apps/openmw/mwsound/openal_output.cpp | 11 +++++++++++ apps/openmw/mwsound/openal_output.hpp | 1 + apps/openmw/mwsound/sound_output.hpp | 1 + apps/openmw/mwsound/soundmanagerimp.cpp | 14 ++++++++++++++ apps/openmw/mwsound/soundmanagerimp.hpp | 1 + 5 files changed, 28 insertions(+) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 82d56ffa0..47acb414e 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -813,6 +813,17 @@ void OpenAL_Output::unloadSound(Sound_Handle data) alDeleteBuffers(1, &buffer); } +size_t OpenAL_Output::getSoundDataSize(Sound_Handle data) const +{ + ALuint buffer = GET_PTRID(data); + ALint size = 0; + + alGetBufferi(buffer, AL_SIZE, &size); + throwALerror(); + + return (ALuint)size; +} + MWBase::SoundPtr OpenAL_Output::playSound(Sound_Handle data, float vol, float basevol, float pitch, int flags,float offset) { diff --git a/apps/openmw/mwsound/openal_output.hpp b/apps/openmw/mwsound/openal_output.hpp index b4c788faa..3186706a3 100644 --- a/apps/openmw/mwsound/openal_output.hpp +++ b/apps/openmw/mwsound/openal_output.hpp @@ -35,6 +35,7 @@ namespace MWSound virtual Sound_Handle loadSound(const std::string &fname, Sound_Loudness *loudness); virtual void unloadSound(Sound_Handle data); + virtual size_t getSoundDataSize(Sound_Handle data) const; /// @param offset Value from [0,1] meaning from which fraction the sound the playback starts. virtual MWBase::SoundPtr playSound(Sound_Handle data, float vol, float basevol, float pitch, int flags, float offset); diff --git a/apps/openmw/mwsound/sound_output.hpp b/apps/openmw/mwsound/sound_output.hpp index 4c1691ed1..f0b3fc465 100644 --- a/apps/openmw/mwsound/sound_output.hpp +++ b/apps/openmw/mwsound/sound_output.hpp @@ -25,6 +25,7 @@ namespace MWSound virtual Sound_Handle loadSound(const std::string &fname, Sound_Loudness *loudness=0) = 0; virtual void unloadSound(Sound_Handle data) = 0; + virtual size_t getSoundDataSize(Sound_Handle data) const = 0; /// @param offset Value from [0,1] meaning from which fraction the sound the playback starts. virtual MWBase::SoundPtr playSound(Sound_Handle data, float vol, float basevol, float pitch, int flags, float offset) = 0; diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 7f0a11817..b758ef7d6 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -40,6 +40,7 @@ namespace MWSound , mMusicVolume(1.0f) , mVoiceVolume(1.0f) , mFootstepsVolume(1.0f) + , mBufferCacheSize(0) , mListenerUnderwater(false) , mListenerPos(0,0,0) , mListenerDir(1,0,0) @@ -165,6 +166,19 @@ namespace MWSound } sfxiter->second.mHandle = mOutput->loadSound(sfxiter->second.mResourceName); + mBufferCacheSize += mOutput->getSoundDataSize(sfxiter->second.mHandle); + // NOTE: Max sound buffer cache size is 15MB. Make configurable? + while(mBufferCacheSize > 15*1024*1024) + { + if(mUnusedBuffers.empty()) + { + std::cerr<< "No unused sound buffers to free, using "<getSoundDataSize(*iter); + mUnusedBuffers.erase(iter); + } mUnusedBuffers.insert(sfxiter->second.mHandle); return &sfxiter->second; diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index cb6c93044..ff0ff28b4 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -49,6 +49,7 @@ namespace MWSound typedef std::map NameBufferMap; NameBufferMap mSoundBuffers; + size_t mBufferCacheSize; // Should stream voices, but that requires handling the "lip" data // separately from buffer loading. NameBufferMap mVoiceSoundBuffers; From 0f33f41d8d4d6a111cc9f646112690bb4f13f722 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 23 Nov 2015 07:50:46 -0800 Subject: [PATCH 2552/3725] Actually unload sounds when running over --- apps/openmw/mwsound/sound_buffer.hpp | 4 ++- apps/openmw/mwsound/sound_output.hpp | 3 ++ apps/openmw/mwsound/soundmanagerimp.cpp | 42 ++++++++++++++----------- apps/openmw/mwsound/soundmanagerimp.hpp | 9 ++---- 4 files changed, 31 insertions(+), 27 deletions(-) diff --git a/apps/openmw/mwsound/sound_buffer.hpp b/apps/openmw/mwsound/sound_buffer.hpp index 8ee7ae342..8818ac23c 100644 --- a/apps/openmw/mwsound/sound_buffer.hpp +++ b/apps/openmw/mwsound/sound_buffer.hpp @@ -22,8 +22,10 @@ namespace MWSound Sound_Handle mHandle; Sound_Loudness mLoudness; + size_t mReferences; + Sound_Buffer(std::string resname, float volume, float mindist, float maxdist) - : mResourceName(resname), mVolume(volume), mMinDist(mindist), mMaxDist(maxdist), mHandle(0) + : mResourceName(resname), mVolume(volume), mMinDist(mindist), mMaxDist(maxdist), mHandle(0), mReferences(0) { } }; } diff --git a/apps/openmw/mwsound/sound_output.hpp b/apps/openmw/mwsound/sound_output.hpp index f0b3fc465..6e1f20110 100644 --- a/apps/openmw/mwsound/sound_output.hpp +++ b/apps/openmw/mwsound/sound_output.hpp @@ -15,6 +15,9 @@ namespace MWSound class Sound; class Sound_Loudness; + // An opaque handle for the implementation's sound buffers. + typedef void *Sound_Handle; + class Sound_Output { SoundManager &mManager; diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index b758ef7d6..b63e20395 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -122,7 +122,7 @@ namespace MWSound // Lookup a soundid for its sound data (resource name, local volume, // minRange and maxRange. The returned pointer is only valid temporarily. - const Sound_Buffer *SoundManager::lookup(const std::string &soundId) + Sound_Buffer *SoundManager::lookup(const std::string &soundId) { NameBufferMap::iterator sfxiter = mSoundBuffers.find(soundId); if(sfxiter != mSoundBuffers.end() && sfxiter->second.mHandle) @@ -165,8 +165,10 @@ namespace MWSound mVFS->normalizeFilename(sfxiter->second.mResourceName); } - sfxiter->second.mHandle = mOutput->loadSound(sfxiter->second.mResourceName); - mBufferCacheSize += mOutput->getSoundDataSize(sfxiter->second.mHandle); + Sound_Buffer *sfx = &sfxiter->second; + sfx->mHandle = mOutput->loadSound(sfx->mResourceName); + mBufferCacheSize += mOutput->getSoundDataSize(sfx->mHandle); + // NOTE: Max sound buffer cache size is 15MB. Make configurable? while(mBufferCacheSize > 15*1024*1024) { @@ -176,12 +178,14 @@ namespace MWSound break; } SoundSet::iterator iter = mUnusedBuffers.begin(); - mBufferCacheSize -= mOutput->getSoundDataSize(*iter); + sfxiter = mSoundBuffers.find(*iter); + mBufferCacheSize -= mOutput->getSoundDataSize(sfxiter->second.mHandle); + mOutput->unloadSound(sfxiter->second.mHandle); mUnusedBuffers.erase(iter); } - mUnusedBuffers.insert(sfxiter->second.mHandle); + mUnusedBuffers.insert(soundId); - return &sfxiter->second; + return sfx; } const Sound_Buffer *SoundManager::lookupVoice(const std::string &voicefile) @@ -434,14 +438,14 @@ namespace MWSound try { std::string soundid = Misc::StringUtils::lowerCase(soundId); - const Sound_Buffer *sfx = lookup(soundid); + Sound_Buffer *sfx = lookup(soundid); float basevol = volumeFromType(type); sound = mOutput->playSound(sfx->mHandle, volume * sfx->mVolume, basevol, pitch, mode|type, offset ); - if(mBufferRefs[sfx->mHandle]++ == 0) - mUnusedBuffers.erase(sfx->mHandle); + if(sfx->mReferences++ == 0) + mUnusedBuffers.erase(soundid); mActiveSounds[MWWorld::Ptr()].push_back(std::make_pair(sound, soundid)); } catch(std::exception&) @@ -461,7 +465,7 @@ namespace MWSound { // Look up the sound in the ESM data std::string soundid = Misc::StringUtils::lowerCase(soundId); - const Sound_Buffer *sfx = lookup(soundid); + Sound_Buffer *sfx = lookup(soundid); float basevol = volumeFromType(type); const ESM::Position &pos = ptr.getRefData().getPosition(); const osg::Vec3f objpos(pos.asVec3()); @@ -472,8 +476,8 @@ namespace MWSound sound = mOutput->playSound3D(sfx->mHandle, objpos, volume * sfx->mVolume, basevol, pitch, sfx->mMinDist, sfx->mMaxDist, mode|type, offset ); - if(mBufferRefs[sfx->mHandle]++ == 0) - mUnusedBuffers.erase(sfx->mHandle); + if(sfx->mReferences++ == 0) + mUnusedBuffers.erase(soundid); if((mode&Play_NoTrack)) mActiveSounds[MWWorld::Ptr()].push_back(std::make_pair(sound, soundid)); else @@ -496,14 +500,14 @@ namespace MWSound { // Look up the sound in the ESM data std::string soundid = Misc::StringUtils::lowerCase(soundId); - const Sound_Buffer *sfx = lookup(soundid); + Sound_Buffer *sfx = lookup(soundid); float basevol = volumeFromType(type); sound = mOutput->playSound3D(sfx->mHandle, initialPos, volume * sfx->mVolume, basevol, pitch, sfx->mMinDist, sfx->mMaxDist, mode|type, offset ); - if(mBufferRefs[sfx->mHandle]++ == 0) - mUnusedBuffers.erase(sfx->mHandle); + if(sfx->mReferences++ == 0) + mUnusedBuffers.erase(soundid); mActiveSounds[MWWorld::Ptr()].push_back(std::make_pair(sound, soundid)); } catch(std::exception &) @@ -752,8 +756,8 @@ namespace MWSound if(!updateSound(sndname->first, snditer->first, duration)) { NameBufferMap::iterator sfxiter = mSoundBuffers.find(sndname->second); - if(mBufferRefs[sfxiter->second.mHandle]-- == 1) - mUnusedBuffers.insert(sfxiter->second.mHandle); + if(sfxiter->second.mReferences-- == 1) + mUnusedBuffers.insert(sndname->second); sndname = snditer->second.erase(sndname); } else @@ -960,8 +964,8 @@ namespace MWSound { sndname->first->stop(); NameBufferMap::iterator sfxiter = mSoundBuffers.find(sndname->second); - if(mBufferRefs[sfxiter->second.mHandle]-- <= 1) - mUnusedBuffers.insert(sfxiter->second.mHandle); + if(sfxiter->second.mReferences-- == 1) + mUnusedBuffers.insert(sndname->second); } } mActiveSounds.clear(); diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index ff0ff28b4..db5ced5c3 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -23,9 +23,6 @@ namespace MWSound class Sound; class Sound_Buffer; - // An opaque handle for the implementation's sound buffers. - typedef void *Sound_Handle; - enum Environment { Env_Normal, Env_Underwater @@ -54,9 +51,7 @@ namespace MWSound // separately from buffer loading. NameBufferMap mVoiceSoundBuffers; - typedef std::map SoundRefMap; - SoundRefMap mBufferRefs; - typedef std::set SoundSet; + typedef std::set SoundSet; SoundSet mUnusedBuffers; boost::shared_ptr mMusic; @@ -79,7 +74,7 @@ namespace MWSound int mPausedSoundTypes; - const Sound_Buffer *lookup(const std::string &soundId); + Sound_Buffer *lookup(const std::string &soundId); const Sound_Buffer *lookupVoice(const std::string &voicefile); void streamMusicFull(const std::string& filename); From 16f72886e93c9b5233d4d9ae025a5ce15265c376 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 23 Nov 2015 07:51:52 -0800 Subject: [PATCH 2553/3725] Use separate lists for openal sounds and streams --- apps/openmw/mwsound/openal_output.cpp | 65 +++++++++++---------------- apps/openmw/mwsound/openal_output.hpp | 7 ++- 2 files changed, 33 insertions(+), 39 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 47acb414e..0d8a994ae 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -296,7 +296,7 @@ OpenAL_SoundStream::OpenAL_SoundStream(OpenAL_Output &output, ALuint src, Decode mBufferSize = static_cast(sBufferLength*srate); mBufferSize = framesToBytes(mBufferSize, chans, type); - mOutput.mActiveSounds.push_back(this); + mOutput.mActiveStreams.push_back(this); } catch(std::exception&) { @@ -318,8 +318,8 @@ OpenAL_SoundStream::~OpenAL_SoundStream() mDecoder->close(); - mOutput.mActiveSounds.erase(std::find(mOutput.mActiveSounds.begin(), - mOutput.mActiveSounds.end(), this)); + mOutput.mActiveStreams.erase(std::find(mOutput.mActiveStreams.begin(), + mOutput.mActiveStreams.end(), this)); } void OpenAL_SoundStream::play() @@ -802,12 +802,11 @@ void OpenAL_Output::unloadSound(Sound_Handle data) SoundVec::const_iterator iter = mActiveSounds.begin(); for(;iter != mActiveSounds.end();++iter) { - OpenAL_Sound *sound = dynamic_cast(*iter); - if(sound && sound->mSource && sound->mBuffer == buffer) + if((*iter)->mSource && (*iter)->mBuffer == buffer) { - alSourceStop(sound->mSource); - alSourcei(sound->mSource, AL_BUFFER, 0); - sound->mBuffer = 0; + alSourceStop((*iter)->mSource); + alSourcei((*iter)->mSource, AL_BUFFER, 0); + (*iter)->mBuffer = 0; } } alDeleteBuffers(1, &buffer); @@ -947,22 +946,17 @@ void OpenAL_Output::updateListener(const osg::Vec3f &pos, const osg::Vec3f &atdi void OpenAL_Output::pauseSounds(int types) { std::vector sources; - SoundVec::const_iterator iter = mActiveSounds.begin(); - while(iter != mActiveSounds.end()) + SoundVec::const_iterator sound = mActiveSounds.begin(); + for(;sound != mActiveSounds.end();++sound) { - const OpenAL_SoundStream *stream = dynamic_cast(*iter); - if(stream) - { - if(stream->mSource && (stream->getPlayType()&types)) - sources.push_back(stream->mSource); - } - else - { - const OpenAL_Sound *sound = dynamic_cast(*iter); - if(sound && sound->mSource && (sound->getPlayType()&types)) - sources.push_back(sound->mSource); - } - ++iter; + if(*sound && (*sound)->mSource && ((*sound)->getPlayType()&types)) + sources.push_back((*sound)->mSource); + } + StreamVec::const_iterator stream = mActiveStreams.begin(); + for(;stream != mActiveStreams.end();++stream) + { + if(*stream && (*stream)->mSource && ((*stream)->getPlayType()&types)) + sources.push_back((*stream)->mSource); } if(!sources.empty()) { @@ -974,22 +968,17 @@ void OpenAL_Output::pauseSounds(int types) void OpenAL_Output::resumeSounds(int types) { std::vector sources; - SoundVec::const_iterator iter = mActiveSounds.begin(); - while(iter != mActiveSounds.end()) + SoundVec::const_iterator sound = mActiveSounds.begin(); + for(;sound != mActiveSounds.end();++sound) { - const OpenAL_SoundStream *stream = dynamic_cast(*iter); - if(stream) - { - if(stream->mSource && (stream->getPlayType()&types)) - sources.push_back(stream->mSource); - } - else - { - const OpenAL_Sound *sound = dynamic_cast(*iter); - if(sound && sound->mSource && (sound->getPlayType()&types)) - sources.push_back(sound->mSource); - } - ++iter; + if(*sound && (*sound)->mSource && ((*sound)->getPlayType()&types)) + sources.push_back((*sound)->mSource); + } + StreamVec::const_iterator stream = mActiveStreams.begin(); + for(;stream != mActiveStreams.end();++stream) + { + if(*stream && (*stream)->mSource && ((*stream)->getPlayType()&types)) + sources.push_back((*stream)->mSource); } if(!sources.empty()) { diff --git a/apps/openmw/mwsound/openal_output.hpp b/apps/openmw/mwsound/openal_output.hpp index 3186706a3..9a9d188d9 100644 --- a/apps/openmw/mwsound/openal_output.hpp +++ b/apps/openmw/mwsound/openal_output.hpp @@ -16,6 +16,9 @@ namespace MWSound class SoundManager; class Sound; + class OpenAL_Sound; + class OpenAL_SoundStream; + class OpenAL_Output : public Sound_Output { ALCdevice *mDevice; @@ -24,8 +27,10 @@ namespace MWSound typedef std::deque IDDq; IDDq mFreeSources; - typedef std::vector SoundVec; + typedef std::vector SoundVec; SoundVec mActiveSounds; + typedef std::vector StreamVec; + StreamVec mActiveStreams; Environment mLastEnvironment; From 83721092f2c6c11243587a54833ee35cd97dc235 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 23 Nov 2015 19:10:49 -0800 Subject: [PATCH 2554/3725] Refactor the audio streaming code to be a bit saner --- apps/openmw/mwsound/openal_output.cpp | 164 ++++++++++++-------------- 1 file changed, 78 insertions(+), 86 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 0d8a994ae..bee58bbe8 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -150,18 +150,6 @@ static ALenum getALFormat(ChannelConfig chans, SampleType type) return AL_NONE; } -static ALint getBufferSampleCount(ALuint buf) -{ - ALint size, bits, channels; - - alGetBufferi(buf, AL_SIZE, &size); - alGetBufferi(buf, AL_BITS, &bits); - alGetBufferi(buf, AL_CHANNELS, &channels); - throwALerror(); - - return size / channels * 8 / bits; -} - // // A streaming OpenAL sound. // @@ -174,17 +162,17 @@ class OpenAL_SoundStream : public Sound ALuint mSource; ALuint mBuffers[sNumBuffers]; + ALint mCurrentBufIdx; ALenum mFormat; ALsizei mSampleRate; ALuint mBufferSize; - - ALuint mSamplesQueued; + ALuint mFrameSize; + ALint mSilence; DecoderPtr mDecoder; volatile bool mIsFinished; - volatile bool mIsInitialBatchEnqueued; void updateAll(bool local); @@ -204,6 +192,7 @@ public: void play(); bool process(); + ALint refillQueue(); }; const ALfloat OpenAL_SoundStream::sBufferLength = 0.125f; @@ -277,7 +266,8 @@ private: OpenAL_SoundStream::OpenAL_SoundStream(OpenAL_Output &output, ALuint src, DecoderPtr decoder, float basevol, float pitch, int flags) : Sound(osg::Vec3f(0.f, 0.f, 0.f), 1.0f, basevol, pitch, 1.0f, 1000.0f, flags) - , mOutput(output), mSource(src), mSamplesQueued(0), mDecoder(decoder), mIsFinished(true), mIsInitialBatchEnqueued(false) + , mOutput(output), mSource(src), mCurrentBufIdx(0), mFrameSize(0), mSilence(0) + , mDecoder(decoder), mIsFinished(true) { throwALerror(); @@ -293,8 +283,16 @@ OpenAL_SoundStream::OpenAL_SoundStream(OpenAL_Output &output, ALuint src, Decode mFormat = getALFormat(chans, type); mSampleRate = srate; + switch(type) + { + case SampleType_UInt8: mSilence = 0x80; + case SampleType_Int16: mSilence = 0x00; + case SampleType_Float32: mSilence = 0x00; + } + + mFrameSize = framesToBytes(1, chans, type); mBufferSize = static_cast(sBufferLength*srate); - mBufferSize = framesToBytes(mBufferSize, chans, type); + mBufferSize *= mFrameSize; mOutput.mActiveStreams.push_back(this); } @@ -327,9 +325,8 @@ void OpenAL_SoundStream::play() alSourceStop(mSource); alSourcei(mSource, AL_BUFFER, 0); throwALerror(); - mSamplesQueued = 0; + mIsFinished = false; - mIsInitialBatchEnqueued = false; mOutput.mStreamThread->add(this); } @@ -337,12 +334,10 @@ void OpenAL_SoundStream::stop() { mOutput.mStreamThread->remove(this); mIsFinished = true; - mIsInitialBatchEnqueued = false; alSourceStop(mSource); alSourcei(mSource, AL_BUFFER, 0); throwALerror(); - mSamplesQueued = 0; mDecoder->rewind(); } @@ -351,6 +346,7 @@ bool OpenAL_SoundStream::isPlaying() { ALint state; + boost::lock_guard lock(mOutput.mStreamThread->mMutex); alGetSourcei(mSource, AL_SOURCE_STATE, &state); throwALerror(); @@ -362,17 +358,26 @@ bool OpenAL_SoundStream::isPlaying() double OpenAL_SoundStream::getTimeOffset() { ALint state = AL_STOPPED; - ALfloat offset = 0.0f; + ALint offset; double t; - mOutput.mStreamThread->mMutex.lock(); - alGetSourcef(mSource, AL_SEC_OFFSET, &offset); + boost::unique_lock lock(mOutput.mStreamThread->mMutex); + alGetSourcei(mSource, AL_SAMPLE_OFFSET, &offset); alGetSourcei(mSource, AL_SOURCE_STATE, &state); if(state == AL_PLAYING || state == AL_PAUSED) - t = (double)(mDecoder->getSampleOffset() - mSamplesQueued)/(double)mSampleRate + offset; + { + ALint queued; + alGetSourcei(mSource, AL_BUFFERS_QUEUED, &queued); + ALint inqueue = mBufferSize/mFrameSize*queued + offset; + t = (double)(mDecoder->getSampleOffset() - inqueue) / (double)mSampleRate; + } else + { + /* Underrun, or not started yet. The decoder offset is where we'll play + * next. */ t = (double)mDecoder->getSampleOffset() / (double)mSampleRate; - mOutput.mStreamThread->mMutex.unlock(); + } + lock.unlock(); throwALerror(); return t; @@ -418,78 +423,65 @@ void OpenAL_SoundStream::update() bool OpenAL_SoundStream::process() { try { - bool finished = mIsFinished; - ALint processed, state; - - alGetSourcei(mSource, AL_SOURCE_STATE, &state); - alGetSourcei(mSource, AL_BUFFERS_PROCESSED, &processed); - throwALerror(); - - if(processed > 0) + if(refillQueue() > 0) { - std::vector data(mBufferSize); - do { - ALuint bufid = 0; - size_t got; - - alSourceUnqueueBuffers(mSource, 1, &bufid); - mSamplesQueued -= getBufferSampleCount(bufid); - processed--; - - if(finished) - continue; - - got = mDecoder->read(&data[0], data.size()); - finished = (got < data.size()); - if(got > 0) - { - alBufferData(bufid, mFormat, &data[0], got, mSampleRate); - alSourceQueueBuffers(mSource, 1, &bufid); - mSamplesQueued += getBufferSampleCount(bufid); - } - } while(processed > 0); - throwALerror(); - } - else if (!mIsInitialBatchEnqueued) { // nothing enqueued yet - std::vector data(mBufferSize); - - for(ALuint i = 0;i < sNumBuffers && !finished;i++) + ALint state; + alGetSourcei(mSource, AL_SOURCE_STATE, &state); + if(state != AL_PLAYING && state != AL_PAUSED) { - size_t got = mDecoder->read(&data[0], data.size()); - finished = (got < data.size()); - if(got > 0) - { - ALuint bufid = mBuffers[i]; - alBufferData(bufid, mFormat, &data[0], got, mSampleRate); - alSourceQueueBuffers(mSource, 1, &bufid); - throwALerror(); - mSamplesQueued += getBufferSampleCount(bufid); - } + if(refillQueue() > 0) + alSourcePlay(mSource); + throwALerror(); } - mIsInitialBatchEnqueued = true; - } - - if(state != AL_PLAYING && state != AL_PAUSED) - { - ALint queued = 0; - - alGetSourcei(mSource, AL_BUFFERS_QUEUED, &queued); - if(queued > 0) - alSourcePlay(mSource); - throwALerror(); } - - mIsFinished = finished; } catch(std::exception&) { std::cout<< "Error updating stream \""<getName()<<"\"" < 0) + { + ALuint buf; + alSourceUnqueueBuffers(mSource, 1, &buf); + --processed; + } + throwALerror(); + + ALint queued; + alGetSourcei(mSource, AL_BUFFERS_QUEUED, &queued); + if(!mIsFinished && (ALuint)queued < sNumBuffers) + { + std::vector data(mBufferSize); + for(;!mIsFinished && (ALuint)queued < sNumBuffers;++queued) + { + size_t got = mDecoder->read(&data[0], data.size()); + if(got < data.size()) + { + mIsFinished = true; + memset(&data[got], mSilence, data.size()-got); + } + if(got > 0) + { + ALuint bufid = mBuffers[mCurrentBufIdx]; + alBufferData(bufid, mFormat, &data[0], data.size(), mSampleRate); + alSourceQueueBuffers(mSource, 1, &bufid); + throwALerror(); + mCurrentBufIdx = (mCurrentBufIdx+1) % sNumBuffers; + } + } + } + + return queued; +} + + // // A regular 2D OpenAL sound // From f1a1dc8408f4bbf6538c7965637cd800754110c3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 23 Nov 2015 19:27:35 -0800 Subject: [PATCH 2555/3725] Pass relevant sound parameters to the OpenAL_SoundStream constructor --- apps/openmw/mwsound/openal_output.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index bee58bbe8..1a33d1cb0 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -182,7 +182,7 @@ class OpenAL_SoundStream : public Sound friend class OpenAL_Output; public: - OpenAL_SoundStream(OpenAL_Output &output, ALuint src, DecoderPtr decoder, float basevol, float pitch, int flags); + OpenAL_SoundStream(OpenAL_Output &output, ALuint src, DecoderPtr decoder, const osg::Vec3f& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags); virtual ~OpenAL_SoundStream(); virtual void stop(); @@ -264,8 +264,8 @@ private: }; -OpenAL_SoundStream::OpenAL_SoundStream(OpenAL_Output &output, ALuint src, DecoderPtr decoder, float basevol, float pitch, int flags) - : Sound(osg::Vec3f(0.f, 0.f, 0.f), 1.0f, basevol, pitch, 1.0f, 1000.0f, flags) +OpenAL_SoundStream::OpenAL_SoundStream(OpenAL_Output &output, ALuint src, DecoderPtr decoder, const osg::Vec3f& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags) + : Sound(pos, vol, basevol, pitch, mindist, maxdist, flags) , mOutput(output), mSource(src), mCurrentBufIdx(0), mFrameSize(0), mSilence(0) , mDecoder(decoder), mIsFinished(true) { @@ -888,7 +888,7 @@ MWBase::SoundPtr OpenAL_Output::playSound3D(Sound_Handle data, const osg::Vec3f } -MWBase::SoundPtr OpenAL_Output::streamSound(DecoderPtr decoder, float volume, float pitch, int flags) +MWBase::SoundPtr OpenAL_Output::streamSound(DecoderPtr decoder, float basevol, float pitch, int flags) { boost::shared_ptr sound; ALuint src; @@ -902,7 +902,7 @@ MWBase::SoundPtr OpenAL_Output::streamSound(DecoderPtr decoder, float volume, fl std::cout <<"Warning: cannot loop stream \""<getName()<<"\""<< std::endl; try { - sound.reset(new OpenAL_SoundStream(*this, src, decoder, volume, pitch, flags)); + sound.reset(new OpenAL_SoundStream(*this, src, decoder, osg::Vec3f(0.0f, 0.0f, 0.0f), 1.0f, basevol, pitch, 1.0f, 1000.0f, flags)); } catch(std::exception&) { From eee6a19e312b6cb50b765358212d7dfcb80f4a65 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 23 Nov 2015 19:41:57 -0800 Subject: [PATCH 2556/3725] Add a method to stream sounds in 3D --- apps/openmw/mwsound/openal_output.cpp | 67 ++++++++++++++++++++++++++- apps/openmw/mwsound/openal_output.hpp | 5 +- apps/openmw/mwsound/sound_output.hpp | 4 +- 3 files changed, 73 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 1a33d1cb0..0c0f63475 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -158,9 +158,12 @@ class OpenAL_SoundStream : public Sound static const ALuint sNumBuffers = 6; static const ALfloat sBufferLength; +protected: OpenAL_Output &mOutput; ALuint mSource; + +private: ALuint mBuffers[sNumBuffers]; ALint mCurrentBufIdx; @@ -194,9 +197,22 @@ public: bool process(); ALint refillQueue(); }; - const ALfloat OpenAL_SoundStream::sBufferLength = 0.125f; +class OpenAL_SoundStream3D : public OpenAL_SoundStream +{ + OpenAL_SoundStream3D(const OpenAL_SoundStream3D &rhs); + OpenAL_SoundStream3D& operator=(const OpenAL_SoundStream3D &rhs); + +public: + OpenAL_SoundStream3D(OpenAL_Output &output, ALuint src, DecoderPtr decoder, const osg::Vec3f& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags) + : OpenAL_SoundStream(output, src, decoder, pos, vol, basevol, pitch, mindist, maxdist, flags) + { } + + virtual void update(); +}; + + // // A background streaming thread (keeps active streams processed) // @@ -481,6 +497,26 @@ ALint OpenAL_SoundStream::refillQueue() return queued; } +void OpenAL_SoundStream3D::update() +{ + ALfloat gain = mVolume*mBaseVolume; + ALfloat pitch = mPitch; + if((mPos - mOutput.mPos).length2() > mMaxDistance*mMaxDistance) + gain = 0.0f; + else if(!(mFlags&MWBase::SoundManager::Play_NoEnv) && mOutput.mLastEnvironment == Env_Underwater) + { + gain *= 0.9f; + pitch *= 0.7f; + } + + alSourcef(mSource, AL_GAIN, gain); + alSourcef(mSource, AL_PITCH, pitch); + alSource3f(mSource, AL_POSITION, mPos[0], mPos[1], mPos[2]); + alSource3f(mSource, AL_DIRECTION, 0.0f, 0.0f, 0.0f); + alSource3f(mSource, AL_VELOCITY, 0.0f, 0.0f, 0.0f); + throwALerror(); +} + // // A regular 2D OpenAL sound @@ -917,6 +953,35 @@ MWBase::SoundPtr OpenAL_Output::streamSound(DecoderPtr decoder, float basevol, f } +MWBase::SoundPtr OpenAL_Output::streamSound3D(DecoderPtr decoder, const osg::Vec3f &pos, float volume, float basevol, float pitch, float min, float max, int flags) +{ + boost::shared_ptr sound; + ALuint src; + + if(mFreeSources.empty()) + fail("No free sources"); + src = mFreeSources.front(); + mFreeSources.pop_front(); + + if((flags&MWBase::SoundManager::Play_Loop)) + std::cout <<"Warning: cannot loop stream \""<getName()<<"\""<< std::endl; + try + { + sound.reset(new OpenAL_SoundStream3D(*this, src, decoder, pos, volume, basevol, pitch, min, max, flags)); + } + catch(std::exception&) + { + mFreeSources.push_back(src); + throw; + } + + sound->updateAll(true); + + sound->play(); + return sound; +} + + void OpenAL_Output::updateListener(const osg::Vec3f &pos, const osg::Vec3f &atdir, const osg::Vec3f &updir, Environment env) { mPos = pos; diff --git a/apps/openmw/mwsound/openal_output.hpp b/apps/openmw/mwsound/openal_output.hpp index 9a9d188d9..e6f438ad8 100644 --- a/apps/openmw/mwsound/openal_output.hpp +++ b/apps/openmw/mwsound/openal_output.hpp @@ -47,7 +47,9 @@ namespace MWSound /// @param offset Value from [0,1] meaning from which fraction the sound the playback starts. virtual MWBase::SoundPtr playSound3D(Sound_Handle data, const osg::Vec3f &pos, float vol, float basevol, float pitch, float min, float max, int flags, float offset); - virtual MWBase::SoundPtr streamSound(DecoderPtr decoder, float volume, float pitch, int flags); + virtual MWBase::SoundPtr streamSound(DecoderPtr decoder, float basevol, float pitch, int flags); + virtual MWBase::SoundPtr streamSound3D(DecoderPtr decoder, const osg::Vec3f &pos, + float vol, float basevol, float pitch, float min, float max, int flags); virtual void updateListener(const osg::Vec3f &pos, const osg::Vec3f &atdir, const osg::Vec3f &updir, Environment env); @@ -66,6 +68,7 @@ namespace MWSound friend class OpenAL_Sound; friend class OpenAL_Sound3D; friend class OpenAL_SoundStream; + friend class OpenAL_SoundStream3D; friend class SoundManager; }; #ifndef DEFAULT_OUTPUT diff --git a/apps/openmw/mwsound/sound_output.hpp b/apps/openmw/mwsound/sound_output.hpp index 6e1f20110..2326c64ba 100644 --- a/apps/openmw/mwsound/sound_output.hpp +++ b/apps/openmw/mwsound/sound_output.hpp @@ -35,7 +35,9 @@ namespace MWSound /// @param offset Value from [0,1] meaning from which fraction the sound the playback starts. virtual MWBase::SoundPtr playSound3D(Sound_Handle data, const osg::Vec3f &pos, float vol, float basevol, float pitch, float min, float max, int flags, float offset) = 0; - virtual MWBase::SoundPtr streamSound(DecoderPtr decoder, float volume, float pitch, int flags) = 0; + virtual MWBase::SoundPtr streamSound(DecoderPtr decoder, float basevol, float pitch, int flags) = 0; + virtual MWBase::SoundPtr streamSound3D(DecoderPtr decoder, const osg::Vec3f &pos, + float vol, float basevol, float pitch, float min, float max, int flags) = 0; virtual void updateListener(const osg::Vec3f &pos, const osg::Vec3f &atdir, const osg::Vec3f &updir, Environment env) = 0; From fbfcc4050f059e21cc737b008bef2702137afe3d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 23 Nov 2015 20:13:24 -0800 Subject: [PATCH 2557/3725] Stream voice clips Voices tend to be a bit long, and not individually replayed often. So it's better to stream them instead of loading theminto a sound buffer. The loudness data is very small, though, so that can be kept buffered indefinitely. --- apps/openmw/mwsound/openal_output.cpp | 13 +-- apps/openmw/mwsound/openal_output.hpp | 2 +- apps/openmw/mwsound/sound_buffer.hpp | 1 - apps/openmw/mwsound/sound_output.hpp | 2 +- apps/openmw/mwsound/soundmanagerimp.cpp | 100 ++++++++++++++---------- apps/openmw/mwsound/soundmanagerimp.hpp | 10 ++- 6 files changed, 70 insertions(+), 58 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 0c0f63475..ccdbff3af 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -19,14 +19,10 @@ #define ALC_ALL_DEVICES_SPECIFIER 0x1013 #endif + #define MAKE_PTRID(id) ((void*)(uintptr_t)id) #define GET_PTRID(ptr) ((ALuint)(uintptr_t)ptr) -namespace -{ - const int loudnessFPS = 20; // loudness values per second of audio -} - namespace MWSound { @@ -779,7 +775,7 @@ void OpenAL_Output::deinit() } -Sound_Handle OpenAL_Output::loadSound(const std::string &fname, Sound_Loudness *loudness) +Sound_Handle OpenAL_Output::loadSound(const std::string &fname) { throwALerror(); @@ -806,9 +802,6 @@ Sound_Handle OpenAL_Output::loadSound(const std::string &fname, Sound_Loudness * decoder->readAll(data); decoder->close(); - if(loudness != 0) - loudness->analyzeLoudness(data, srate, chans, type, static_cast(loudnessFPS)); - ALuint buf = 0; try { alGenBuffers(1, &buf); @@ -975,7 +968,7 @@ MWBase::SoundPtr OpenAL_Output::streamSound3D(DecoderPtr decoder, const osg::Vec throw; } - sound->updateAll(true); + sound->updateAll(false); sound->play(); return sound; diff --git a/apps/openmw/mwsound/openal_output.hpp b/apps/openmw/mwsound/openal_output.hpp index e6f438ad8..912bebb56 100644 --- a/apps/openmw/mwsound/openal_output.hpp +++ b/apps/openmw/mwsound/openal_output.hpp @@ -38,7 +38,7 @@ namespace MWSound virtual void init(const std::string &devname=""); virtual void deinit(); - virtual Sound_Handle loadSound(const std::string &fname, Sound_Loudness *loudness); + virtual Sound_Handle loadSound(const std::string &fname); virtual void unloadSound(Sound_Handle data); virtual size_t getSoundDataSize(Sound_Handle data) const; diff --git a/apps/openmw/mwsound/sound_buffer.hpp b/apps/openmw/mwsound/sound_buffer.hpp index 8818ac23c..eb67908a2 100644 --- a/apps/openmw/mwsound/sound_buffer.hpp +++ b/apps/openmw/mwsound/sound_buffer.hpp @@ -20,7 +20,6 @@ namespace MWSound float mMinDist, mMaxDist; Sound_Handle mHandle; - Sound_Loudness mLoudness; size_t mReferences; diff --git a/apps/openmw/mwsound/sound_output.hpp b/apps/openmw/mwsound/sound_output.hpp index 2326c64ba..86be94d33 100644 --- a/apps/openmw/mwsound/sound_output.hpp +++ b/apps/openmw/mwsound/sound_output.hpp @@ -26,7 +26,7 @@ namespace MWSound virtual void init(const std::string &devname="") = 0; virtual void deinit() = 0; - virtual Sound_Handle loadSound(const std::string &fname, Sound_Loudness *loudness=0) = 0; + virtual Sound_Handle loadSound(const std::string &fname) = 0; virtual void unloadSound(Sound_Handle data) = 0; virtual size_t getSoundDataSize(Sound_Handle data) const = 0; diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index b63e20395..bafd3aa1e 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -30,6 +30,11 @@ #endif +namespace +{ + const int sLoudnessFPS = 20; // loudness values per second of audio +} + namespace MWSound { SoundManager::SoundManager(const VFS::Manager* vfs, bool useSound) @@ -103,13 +108,6 @@ namespace MWSound mOutput->unloadSound(sfxiter->second.mHandle); sfxiter->second.mHandle = 0; } - sfxiter = mVoiceSoundBuffers.begin(); - for(;sfxiter != mVoiceSoundBuffers.end();++sfxiter) - { - if(sfxiter->second.mHandle) - mOutput->unloadSound(sfxiter->second.mHandle); - sfxiter->second.mHandle = 0; - } } mOutput.reset(); } @@ -188,32 +186,37 @@ namespace MWSound return sfx; } - const Sound_Buffer *SoundManager::lookupVoice(const std::string &voicefile) + void SoundManager::loadVoice(const std::string &voicefile) { - NameBufferMap::iterator sfxiter = mVoiceSoundBuffers.find(voicefile); - if(sfxiter == mVoiceSoundBuffers.end()) + NameLoudnessMap::iterator lipiter = mVoiceLipBuffers.find(voicefile); + if(lipiter != mVoiceLipBuffers.end()) return; + + DecoderPtr decoder = getDecoder(); + // Workaround: Bethesda at some point converted some of the files to mp3, but the references were kept as .wav. + if(decoder->mResourceMgr->exists(voicefile)) + decoder->open(voicefile); + else { - MWBase::World* world = MWBase::Environment::get().getWorld(); - static const float fAudioMinDistanceMult = world->getStore().get().find("fAudioMinDistanceMult")->getFloat(); - static const float fAudioMaxDistanceMult = world->getStore().get().find("fAudioMaxDistanceMult")->getFloat(); - static const float fAudioVoiceDefaultMinDistance = world->getStore().get().find("fAudioVoiceDefaultMinDistance")->getFloat(); - static const float fAudioVoiceDefaultMaxDistance = world->getStore().get().find("fAudioVoiceDefaultMaxDistance")->getFloat(); + std::string file = voicefile; + std::string::size_type pos = file.rfind('.'); + if(pos != std::string::npos) + file = file.substr(0, pos)+".mp3"; + decoder->open(file); + } - float minDistance = fAudioVoiceDefaultMinDistance * fAudioMinDistanceMult; - float maxDistance = fAudioVoiceDefaultMaxDistance * fAudioMaxDistanceMult; - minDistance = std::max(minDistance, 1.f); - maxDistance = std::max(minDistance, maxDistance); + ChannelConfig chans; + SampleType type; + int srate; + decoder->getInfo(&srate, &chans, &type); - sfxiter = mVoiceSoundBuffers.insert(std::make_pair( - voicefile, Sound_Buffer("sound/"+voicefile, 1.0f, minDistance, maxDistance) - )).first; - mVFS->normalizeFilename(sfxiter->second.mResourceName); - sfxiter->second.mHandle = mOutput->loadSound(sfxiter->second.mResourceName, &sfxiter->second.mLoudness); - } - else if(!sfxiter->second.mHandle) - sfxiter->second.mHandle = mOutput->loadSound(sfxiter->second.mResourceName, &sfxiter->second.mLoudness); + std::vector data; + decoder->readAll(data); + decoder->close(); - return &sfxiter->second; + Sound_Loudness loudness; + loudness.analyzeLoudness(data, srate, chans, type, static_cast(sLoudnessFPS)); + + mVoiceLipBuffers.insert(std::make_pair(voicefile, loudness)); } @@ -336,14 +339,25 @@ namespace MWSound return; try { - std::string voicefile = Misc::StringUtils::lowerCase(filename); - const Sound_Buffer *sfx = lookupVoice(voicefile); + MWBase::World* world = MWBase::Environment::get().getWorld(); + static const float fAudioMinDistanceMult = world->getStore().get().find("fAudioMinDistanceMult")->getFloat(); + static const float fAudioMaxDistanceMult = world->getStore().get().find("fAudioMaxDistanceMult")->getFloat(); + static const float fAudioVoiceDefaultMinDistance = world->getStore().get().find("fAudioVoiceDefaultMinDistance")->getFloat(); + static const float fAudioVoiceDefaultMaxDistance = world->getStore().get().find("fAudioVoiceDefaultMaxDistance")->getFloat(); + static float minDistance = std::max(fAudioVoiceDefaultMinDistance * fAudioMinDistanceMult, 1.0f); + static float maxDistance = std::max(fAudioVoiceDefaultMaxDistance * fAudioMaxDistanceMult, minDistance); + + std::string voicefile = "sound/"+Misc::StringUtils::lowerCase(filename); float basevol = volumeFromType(Play_TypeVoice); const ESM::Position &pos = ptr.getRefData().getPosition(); const osg::Vec3f objpos(pos.asVec3()); - MWBase::SoundPtr sound = mOutput->playSound3D(sfx->mHandle, - objpos, sfx->mVolume, basevol, 1.0f, sfx->mMinDist, sfx->mMaxDist, Play_Normal|Play_TypeVoice, 0 + loadVoice(voicefile); + DecoderPtr decoder = getDecoder(); + decoder->open(voicefile); + + MWBase::SoundPtr sound = mOutput->streamSound3D(decoder, + objpos, 1.0f, basevol, 1.0f, minDistance, maxDistance, Play_Normal|Play_TypeVoice ); mActiveSaySounds[ptr] = std::make_pair(sound, voicefile); } @@ -358,12 +372,13 @@ namespace MWSound SaySoundMap::const_iterator snditer = mActiveSaySounds.find(ptr); if(snditer != mActiveSaySounds.end()) { - NameBufferMap::const_iterator sfxiter = mVoiceSoundBuffers.find(snditer->second.second); - if(sfxiter != mVoiceSoundBuffers.end()) + MWBase::SoundPtr sound = snditer->second.first; + NameLoudnessMap::const_iterator lipiter = mVoiceLipBuffers.find(snditer->second.second); + if(lipiter != mVoiceLipBuffers.end()) { - float sec = snditer->second.first->getTimeOffset(); - if(snditer->second.first->isPlaying()) - return sfxiter->second.mLoudness.getLoudnessAtTime(sec); + float sec = sound->getTimeOffset(); + if(sound->isPlaying()) + return lipiter->second.getLoudnessAtTime(sec); } } @@ -376,12 +391,15 @@ namespace MWSound return; try { - std::string voicefile = Misc::StringUtils::lowerCase(filename); - const Sound_Buffer *sfx = lookupVoice(voicefile); + std::string voicefile = "sound/"+Misc::StringUtils::lowerCase(filename); float basevol = volumeFromType(Play_TypeVoice); - MWBase::SoundPtr sound = mOutput->playSound(sfx->mHandle, - sfx->mVolume, basevol, 1.0f, Play_Normal|Play_TypeVoice, 0 + loadVoice(voicefile); + DecoderPtr decoder = getDecoder(); + decoder->open(voicefile); + + MWBase::SoundPtr sound = mOutput->streamSound(decoder, + basevol, 1.0f, Play_Normal|Play_TypeVoice ); mActiveSaySounds[MWWorld::Ptr()] = std::make_pair(sound, voicefile); } diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index db5ced5c3..00c0af7b2 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -9,6 +9,7 @@ #include +#include "loudness.hpp" #include "../mwbase/soundmanager.hpp" namespace VFS @@ -47,9 +48,9 @@ namespace MWSound typedef std::map NameBufferMap; NameBufferMap mSoundBuffers; size_t mBufferCacheSize; - // Should stream voices, but that requires handling the "lip" data - // separately from buffer loading. - NameBufferMap mVoiceSoundBuffers; + + typedef std::map NameLoudnessMap; + NameLoudnessMap mVoiceLipBuffers; typedef std::set SoundSet; SoundSet mUnusedBuffers; @@ -75,7 +76,8 @@ namespace MWSound int mPausedSoundTypes; Sound_Buffer *lookup(const std::string &soundId); - const Sound_Buffer *lookupVoice(const std::string &voicefile); + // Ensure the loudness/"lip" data is loaded + void loadVoice(const std::string &voicefile); void streamMusicFull(const std::string& filename); bool updateSound(MWBase::SoundPtr sound, const MWWorld::Ptr &ptr, float duration); From 6c3953766e97a5d8be561d76cb119c05b668a791 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 24 Nov 2015 00:03:54 -0800 Subject: [PATCH 2558/3725] Use separate lists for the sound name and its buffer This should make sound lookup a bit more efficient, especially when an integer ID can be used. --- apps/openmw/mwsound/soundmanagerimp.cpp | 82 +++++++++++++++---------- apps/openmw/mwsound/soundmanagerimp.hpp | 9 ++- 2 files changed, 57 insertions(+), 34 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index bafd3aa1e..d74b0bc6d 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -101,12 +101,12 @@ namespace MWSound clear(); if(mOutput->isInitialized()) { - NameBufferMap::iterator sfxiter = mSoundBuffers.begin(); + SoundBufferList::iterator sfxiter = mSoundBuffers.begin(); for(;sfxiter != mSoundBuffers.end();++sfxiter) { - if(sfxiter->second.mHandle) - mOutput->unloadSound(sfxiter->second.mHandle); - sfxiter->second.mHandle = 0; + if(sfxiter->mHandle) + mOutput->unloadSound(sfxiter->mHandle); + sfxiter->mHandle = 0; } } mOutput.reset(); @@ -122,11 +122,11 @@ namespace MWSound // minRange and maxRange. The returned pointer is only valid temporarily. Sound_Buffer *SoundManager::lookup(const std::string &soundId) { - NameBufferMap::iterator sfxiter = mSoundBuffers.find(soundId); - if(sfxiter != mSoundBuffers.end() && sfxiter->second.mHandle) - return &sfxiter->second; - - if(sfxiter == mSoundBuffers.end()) + Sound_Buffer *sfx; + BufferKeyList::iterator bufkey = std::lower_bound(mBufferKeys.begin(), mBufferKeys.end(), soundId); + if(bufkey != mBufferKeys.end() && *bufkey == soundId) + sfx = &mSoundBuffers[std::distance(mBufferKeys.begin(), bufkey)]; + else { // TODO: We could process all available ESM::Sound records on init // to pre-fill a non-resizing list, which would allow subsystems to @@ -157,31 +157,45 @@ namespace MWSound min = std::max(min, 1.0f); max = std::max(min, max); - sfxiter = mSoundBuffers.insert(std::make_pair( - soundId, Sound_Buffer("Sound/"+snd->mSound, volume, min, max) - )).first; - mVFS->normalizeFilename(sfxiter->second.mResourceName); - } + bufkey = mBufferKeys.insert(bufkey, soundId); + try { + BufferKeyList::difference_type id; + id = std::distance(mBufferKeys.begin(), bufkey); + mSoundBuffers.insert(mSoundBuffers.begin()+id, + Sound_Buffer("Sound/"+snd->mSound, volume, min, max) + ); + sfx = &mSoundBuffers[id]; + } + catch(...) { + mBufferKeys.erase(bufkey); + throw; + } - Sound_Buffer *sfx = &sfxiter->second; - sfx->mHandle = mOutput->loadSound(sfx->mResourceName); - mBufferCacheSize += mOutput->getSoundDataSize(sfx->mHandle); + mVFS->normalizeFilename(sfx->mResourceName); + } - // NOTE: Max sound buffer cache size is 15MB. Make configurable? - while(mBufferCacheSize > 15*1024*1024) + if(!sfx->mHandle) { - if(mUnusedBuffers.empty()) + sfx->mHandle = mOutput->loadSound(sfx->mResourceName); + mBufferCacheSize += mOutput->getSoundDataSize(sfx->mHandle); + + // NOTE: Max sound buffer cache size is 15MB. Make configurable? + while(mBufferCacheSize > 15*1024*1024) { - std::cerr<< "No unused sound buffers to free, using "<getSoundDataSize(unused->mHandle); + mOutput->unloadSound(unused->mHandle); + mUnusedBuffers.erase(iter); } - SoundSet::iterator iter = mUnusedBuffers.begin(); - sfxiter = mSoundBuffers.find(*iter); - mBufferCacheSize -= mOutput->getSoundDataSize(sfxiter->second.mHandle); - mOutput->unloadSound(sfxiter->second.mHandle); - mUnusedBuffers.erase(iter); + mUnusedBuffers.insert(soundId); } - mUnusedBuffers.insert(soundId); return sfx; } @@ -773,8 +787,10 @@ namespace MWSound { if(!updateSound(sndname->first, snditer->first, duration)) { - NameBufferMap::iterator sfxiter = mSoundBuffers.find(sndname->second); - if(sfxiter->second.mReferences-- == 1) + BufferKeyList::iterator bufkey = std::lower_bound(mBufferKeys.begin(), mBufferKeys.end(), + sndname->second); + Sound_Buffer *sfx = &mSoundBuffers[std::distance(mBufferKeys.begin(), bufkey)]; + if(sfx->mReferences-- == 1) mUnusedBuffers.insert(sndname->second); sndname = snditer->second.erase(sndname); } @@ -981,8 +997,10 @@ namespace MWSound for(;sndname != snditer->second.end();++sndname) { sndname->first->stop(); - NameBufferMap::iterator sfxiter = mSoundBuffers.find(sndname->second); - if(sfxiter->second.mReferences-- == 1) + BufferKeyList::iterator bufkey = std::lower_bound(mBufferKeys.begin(), mBufferKeys.end(), + sndname->second); + Sound_Buffer *sfx = &mSoundBuffers[std::distance(mBufferKeys.begin(), bufkey)]; + if(sfx->mReferences-- == 1) mUnusedBuffers.insert(sndname->second); } } diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index 00c0af7b2..082e04678 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -45,8 +45,13 @@ namespace MWSound float mVoiceVolume; float mFootstepsVolume; - typedef std::map NameBufferMap; - NameBufferMap mSoundBuffers; + typedef std::vector BufferKeyList; + typedef std::vector SoundBufferList; + // Each mBufferKeys index has a corresponding entry in mSoundBuffers. + // That is, if string "foo" is at index 10 in mBufferKeys, index 10 in + // mSoundBuffers contains the Sound_Buffer for "foo". + BufferKeyList mBufferKeys; + SoundBufferList mSoundBuffers; size_t mBufferCacheSize; typedef std::map NameLoudnessMap; From f9e18cd966bf7431b186a80e4d558350cd31a7f8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 24 Nov 2015 01:40:14 -0800 Subject: [PATCH 2559/3725] Prepare all Sound_Buffer objects when one is needed This simply sets up the Sound record data to be used by the sound output. The actual audio buffers, stored in the Sound_Handle, are still loaded on-demand. --- apps/openmw/mwsound/soundmanagerimp.cpp | 112 ++++++++++++++---------- apps/openmw/mwsound/soundmanagerimp.hpp | 7 ++ 2 files changed, 74 insertions(+), 45 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index d74b0bc6d..2c33cb2b7 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -118,62 +118,84 @@ namespace MWSound return DecoderPtr(new DEFAULT_DECODER (mVFS)); } - // Lookup a soundid for its sound data (resource name, local volume, - // minRange and maxRange. The returned pointer is only valid temporarily. - Sound_Buffer *SoundManager::lookup(const std::string &soundId) + void SoundManager::insertSound(const std::string &soundId, const ESM::Sound *sound) { - Sound_Buffer *sfx; BufferKeyList::iterator bufkey = std::lower_bound(mBufferKeys.begin(), mBufferKeys.end(), soundId); if(bufkey != mBufferKeys.end() && *bufkey == soundId) - sfx = &mSoundBuffers[std::distance(mBufferKeys.begin(), bufkey)]; + { + std::cerr<< "Duplicate sound record \""<getStore().get().find("fAudioDefaultMinDistance")->getFloat(); + static const float fAudioDefaultMaxDistance = world->getStore().get().find("fAudioDefaultMaxDistance")->getFloat(); + static const float fAudioMinDistanceMult = world->getStore().get().find("fAudioMinDistanceMult")->getFloat(); + static const float fAudioMaxDistanceMult = world->getStore().get().find("fAudioMaxDistanceMult")->getFloat(); + float volume, min, max; + + volume = static_cast(pow(10.0, (sound->mData.mVolume / 255.0*3348.0 - 3348.0) / 2000.0)); + if(sound->mData.mMinRange == 0 && sound->mData.mMaxRange == 0) + { + min = fAudioDefaultMinDistance; + max = fAudioDefaultMaxDistance; + } else { - // TODO: We could process all available ESM::Sound records on init - // to pre-fill a non-resizing list, which would allow subsystems to - // reference sounds by index instead of string. - MWBase::World* world = MWBase::Environment::get().getWorld(); - const ESM::Sound *snd = world->getStore().get().find(soundId); + min = sound->mData.mMinRange; + max = sound->mData.mMaxRange; + } - float volume, min, max; - volume = static_cast(pow(10.0, (snd->mData.mVolume / 255.0*3348.0 - 3348.0) / 2000.0)); + min *= fAudioMinDistanceMult; + max *= fAudioMaxDistanceMult; + min = std::max(min, 1.0f); + max = std::max(min, max); - if(snd->mData.mMinRange == 0 && snd->mData.mMaxRange == 0) - { - static const float fAudioDefaultMinDistance = world->getStore().get().find("fAudioDefaultMinDistance")->getFloat(); - static const float fAudioDefaultMaxDistance = world->getStore().get().find("fAudioDefaultMaxDistance")->getFloat(); - min = fAudioDefaultMinDistance; - max = fAudioDefaultMaxDistance; - } - else - { - min = snd->mData.mMinRange; - max = snd->mData.mMaxRange; - } + Sound_Buffer *sfx; + bufkey = mBufferKeys.insert(bufkey, soundId); + try { + BufferKeyList::difference_type id; + id = std::distance(mBufferKeys.begin(), bufkey); + mSoundBuffers.insert(mSoundBuffers.begin()+id, + Sound_Buffer("Sound/"+sound->mSound, volume, min, max) + ); + sfx = &mSoundBuffers[id]; + } + catch(...) { + mBufferKeys.erase(bufkey); + throw; + } - static const float fAudioMinDistanceMult = world->getStore().get().find("fAudioMinDistanceMult")->getFloat(); - static const float fAudioMaxDistanceMult = world->getStore().get().find("fAudioMaxDistanceMult")->getFloat(); - min *= fAudioMinDistanceMult; - max *= fAudioMaxDistanceMult; - min = std::max(min, 1.0f); - max = std::max(min, max); - - bufkey = mBufferKeys.insert(bufkey, soundId); - try { - BufferKeyList::difference_type id; - id = std::distance(mBufferKeys.begin(), bufkey); - mSoundBuffers.insert(mSoundBuffers.begin()+id, - Sound_Buffer("Sound/"+snd->mSound, volume, min, max) - ); - sfx = &mSoundBuffers[id]; - } - catch(...) { - mBufferKeys.erase(bufkey); - throw; - } + mVFS->normalizeFilename(sfx->mResourceName); + } - mVFS->normalizeFilename(sfx->mResourceName); + // Lookup a soundid for its sound data (resource name, local volume, + // minRange and maxRange). + Sound_Buffer *SoundManager::lookup(const std::string &soundId) + { + Sound_Buffer *sfx; + BufferKeyList::iterator bufkey = std::lower_bound(mBufferKeys.begin(), mBufferKeys.end(), soundId); + if(bufkey == mBufferKeys.end() || *bufkey != soundId) + { + if(mBufferKeys.empty()) + { + MWBase::World *world = MWBase::Environment::get().getWorld(); + MWWorld::Store::iterator iter = world->getStore().get().begin(); + MWWorld::Store::iterator end = world->getStore().get().end(); + size_t storesize = world->getStore().get().getSize(); + mBufferKeys.reserve(storesize); + mSoundBuffers.reserve(storesize); + for(;iter != end;++iter) + insertSound(Misc::StringUtils::lowerCase(iter->mId), &*iter); + + bufkey = std::lower_bound(mBufferKeys.begin(), mBufferKeys.end(), soundId); + } + if(bufkey == mBufferKeys.end() || *bufkey != soundId) + throw std::runtime_error("Sound "+soundId+" not found"); } + sfx = &mSoundBuffers[std::distance(mBufferKeys.begin(), bufkey)]; + if(!sfx->mHandle) { sfx->mHandle = mOutput->loadSound(sfx->mResourceName); diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index 082e04678..5e8d0d8f8 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -17,6 +17,11 @@ namespace VFS class Manager; } +namespace ESM +{ + struct Sound; +} + namespace MWSound { class Sound_Output; @@ -80,6 +85,8 @@ namespace MWSound int mPausedSoundTypes; + void insertSound(const std::string &soundId, const ESM::Sound *sound); + Sound_Buffer *lookup(const std::string &soundId); // Ensure the loudness/"lip" data is loaded void loadVoice(const std::string &voicefile); From f7218f5a2586efcfc8a1bc3b7dff89a6bb881d90 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 24 Nov 2015 02:57:43 -0800 Subject: [PATCH 2560/3725] Use proper mutex mechanisms and don't check al errors in the stream thread --- apps/openmw/mwsound/openal_output.cpp | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index ccdbff3af..e3d3ca8da 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -232,7 +232,7 @@ struct OpenAL_Output::StreamThread { { while(1) { - mMutex.lock(); + boost::unique_lock lock(mMutex); StreamVec::iterator iter = mStreams.begin(); while(iter != mStreams.end()) { @@ -241,33 +241,29 @@ struct OpenAL_Output::StreamThread { else ++iter; } - mMutex.unlock(); + lock.unlock(); boost::this_thread::sleep(boost::posix_time::milliseconds(50)); } } void add(OpenAL_SoundStream *stream) { - mMutex.lock(); + boost::lock_guard lock(mMutex); if(std::find(mStreams.begin(), mStreams.end(), stream) == mStreams.end()) mStreams.push_back(stream); - mMutex.unlock(); } void remove(OpenAL_SoundStream *stream) { - mMutex.lock(); + boost::lock_guard lock(mMutex); StreamVec::iterator iter = std::find(mStreams.begin(), mStreams.end(), stream); - if(iter != mStreams.end()) - mStreams.erase(iter); - mMutex.unlock(); + if(iter != mStreams.end()) mStreams.erase(iter); } void removeAll() { - mMutex.lock(); + boost::lock_guard lock(mMutex); mStreams.clear(); - mMutex.unlock(); } private: @@ -373,7 +369,7 @@ double OpenAL_SoundStream::getTimeOffset() ALint offset; double t; - boost::unique_lock lock(mOutput.mStreamThread->mMutex); + boost::lock_guard lock(mOutput.mStreamThread->mMutex); alGetSourcei(mSource, AL_SAMPLE_OFFSET, &offset); alGetSourcei(mSource, AL_SOURCE_STATE, &state); if(state == AL_PLAYING || state == AL_PAUSED) @@ -389,7 +385,6 @@ double OpenAL_SoundStream::getTimeOffset() * next. */ t = (double)mDecoder->getSampleOffset() / (double)mSampleRate; } - lock.unlock(); throwALerror(); return t; @@ -443,7 +438,6 @@ bool OpenAL_SoundStream::process() { if(refillQueue() > 0) alSourcePlay(mSource); - throwALerror(); } } } @@ -464,7 +458,6 @@ ALint OpenAL_SoundStream::refillQueue() alSourceUnqueueBuffers(mSource, 1, &buf); --processed; } - throwALerror(); ALint queued; alGetSourcei(mSource, AL_BUFFERS_QUEUED, &queued); @@ -484,7 +477,6 @@ ALint OpenAL_SoundStream::refillQueue() ALuint bufid = mBuffers[mCurrentBufIdx]; alBufferData(bufid, mFormat, &data[0], data.size(), mSampleRate); alSourceQueueBuffers(mSource, 1, &bufid); - throwALerror(); mCurrentBufIdx = (mCurrentBufIdx+1) % sNumBuffers; } } From 24f8c78fcaf4b470f6e9c6ca158f765a3938cb88 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 24 Nov 2015 03:18:23 -0800 Subject: [PATCH 2561/3725] Store sound buffer references by index instead of string --- apps/openmw/mwsound/soundmanagerimp.cpp | 181 +++++++++++++----------- apps/openmw/mwsound/soundmanagerimp.hpp | 13 +- 2 files changed, 106 insertions(+), 88 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 2c33cb2b7..bb767cf41 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -169,32 +169,45 @@ namespace MWSound mVFS->normalizeFilename(sfx->mResourceName); } - // Lookup a soundid for its sound data (resource name, local volume, - // minRange and maxRange). - Sound_Buffer *SoundManager::lookup(const std::string &soundId) + size_t SoundManager::lookupId(const std::string &soundId) { - Sound_Buffer *sfx; BufferKeyList::iterator bufkey = std::lower_bound(mBufferKeys.begin(), mBufferKeys.end(), soundId); - if(bufkey == mBufferKeys.end() || *bufkey != soundId) + if(bufkey != mBufferKeys.end() && *bufkey == soundId) + return std::distance(mBufferKeys.begin(), bufkey); + + if(mBufferKeys.empty()) { - if(mBufferKeys.empty()) - { - MWBase::World *world = MWBase::Environment::get().getWorld(); - MWWorld::Store::iterator iter = world->getStore().get().begin(); - MWWorld::Store::iterator end = world->getStore().get().end(); - size_t storesize = world->getStore().get().getSize(); - mBufferKeys.reserve(storesize); - mSoundBuffers.reserve(storesize); - for(;iter != end;++iter) - insertSound(Misc::StringUtils::lowerCase(iter->mId), &*iter); - - bufkey = std::lower_bound(mBufferKeys.begin(), mBufferKeys.end(), soundId); - } - if(bufkey == mBufferKeys.end() || *bufkey != soundId) - throw std::runtime_error("Sound "+soundId+" not found"); + MWBase::World *world = MWBase::Environment::get().getWorld(); + MWWorld::Store::iterator iter = world->getStore().get().begin(); + MWWorld::Store::iterator end = world->getStore().get().end(); + size_t storesize = world->getStore().get().getSize(); + mBufferKeys.reserve(storesize); + mSoundBuffers.reserve(storesize); + for(;iter != end;++iter) + insertSound(Misc::StringUtils::lowerCase(iter->mId), &*iter); + + bufkey = std::lower_bound(mBufferKeys.begin(), mBufferKeys.end(), soundId); + if(bufkey != mBufferKeys.end() && *bufkey == soundId) + return std::distance(mBufferKeys.begin(), bufkey); } - sfx = &mSoundBuffers[std::distance(mBufferKeys.begin(), bufkey)]; + throw std::runtime_error("Sound "+soundId+" not found"); + } + + size_t SoundManager::lookupId(const std::string& soundId) const + { + BufferKeyList::const_iterator bufkey = std::lower_bound(mBufferKeys.begin(), mBufferKeys.end(), soundId); + if(bufkey != mBufferKeys.end() && *bufkey == soundId) + return std::distance(mBufferKeys.begin(), bufkey); + + throw std::runtime_error("Sound "+soundId+" not found"); + } + + // Lookup a sfxid for its sound data (resource name, local volume, + // minRange, and maxRange). + Sound_Buffer *SoundManager::lookup(size_t sfxid) + { + Sound_Buffer *sfx = &mSoundBuffers[sfxid]; if(!sfx->mHandle) { @@ -210,18 +223,24 @@ namespace MWSound break; } SoundSet::iterator iter = mUnusedBuffers.begin(); - bufkey = std::lower_bound(mBufferKeys.begin(), mBufferKeys.end(), *iter); - Sound_Buffer *unused = &mSoundBuffers[std::distance(mBufferKeys.begin(), bufkey)]; + Sound_Buffer *unused = &mSoundBuffers[*iter]; mBufferCacheSize -= mOutput->getSoundDataSize(unused->mHandle); mOutput->unloadSound(unused->mHandle); mUnusedBuffers.erase(iter); } - mUnusedBuffers.insert(soundId); + mUnusedBuffers.insert(sfxid); } return sfx; } + // Lookup a soundid for its sound data (resource name, local volume, + // minRange, and maxRange). + Sound_Buffer *SoundManager::lookup(const std::string &soundId) + { + return lookup(lookupId(soundId)); + } + void SoundManager::loadVoice(const std::string &voicefile) { NameLoudnessMap::iterator lipiter = mVoiceLipBuffers.find(voicefile); @@ -491,16 +510,16 @@ namespace MWSound return sound; try { - std::string soundid = Misc::StringUtils::lowerCase(soundId); - Sound_Buffer *sfx = lookup(soundid); + size_t sfxid = lookupId(Misc::StringUtils::lowerCase(soundId)); + Sound_Buffer *sfx = lookup(sfxid); float basevol = volumeFromType(type); sound = mOutput->playSound(sfx->mHandle, volume * sfx->mVolume, basevol, pitch, mode|type, offset ); if(sfx->mReferences++ == 0) - mUnusedBuffers.erase(soundid); - mActiveSounds[MWWorld::Ptr()].push_back(std::make_pair(sound, soundid)); + mUnusedBuffers.erase(sfxid); + mActiveSounds[MWWorld::Ptr()].push_back(std::make_pair(sound, sfxid)); } catch(std::exception&) { @@ -518,8 +537,8 @@ namespace MWSound try { // Look up the sound in the ESM data - std::string soundid = Misc::StringUtils::lowerCase(soundId); - Sound_Buffer *sfx = lookup(soundid); + size_t sfxid = lookupId(Misc::StringUtils::lowerCase(soundId)); + Sound_Buffer *sfx = lookup(sfxid); float basevol = volumeFromType(type); const ESM::Position &pos = ptr.getRefData().getPosition(); const osg::Vec3f objpos(pos.asVec3()); @@ -531,11 +550,11 @@ namespace MWSound objpos, volume * sfx->mVolume, basevol, pitch, sfx->mMinDist, sfx->mMaxDist, mode|type, offset ); if(sfx->mReferences++ == 0) - mUnusedBuffers.erase(soundid); + mUnusedBuffers.erase(sfxid); if((mode&Play_NoTrack)) - mActiveSounds[MWWorld::Ptr()].push_back(std::make_pair(sound, soundid)); + mActiveSounds[MWWorld::Ptr()].push_back(std::make_pair(sound, sfxid)); else - mActiveSounds[ptr].push_back(std::make_pair(sound, soundid)); + mActiveSounds[ptr].push_back(std::make_pair(sound, sfxid)); } catch(std::exception&) { @@ -553,16 +572,16 @@ namespace MWSound try { // Look up the sound in the ESM data - std::string soundid = Misc::StringUtils::lowerCase(soundId); - Sound_Buffer *sfx = lookup(soundid); + size_t sfxid = lookupId(Misc::StringUtils::lowerCase(soundId)); + Sound_Buffer *sfx = lookup(sfxid); float basevol = volumeFromType(type); sound = mOutput->playSound3D(sfx->mHandle, initialPos, volume * sfx->mVolume, basevol, pitch, sfx->mMinDist, sfx->mMaxDist, mode|type, offset ); if(sfx->mReferences++ == 0) - mUnusedBuffers.erase(soundid); - mActiveSounds[MWWorld::Ptr()].push_back(std::make_pair(sound, soundid)); + mUnusedBuffers.erase(sfxid); + mActiveSounds[MWWorld::Ptr()].push_back(std::make_pair(sound, sfxid)); } catch(std::exception &) { @@ -581,13 +600,13 @@ namespace MWSound SoundMap::iterator snditer = mActiveSounds.find(ptr); if(snditer != mActiveSounds.end()) { - std::string soundid = Misc::StringUtils::lowerCase(soundId); - SoundNamePairList::iterator sndname = snditer->second.begin(); - for(;sndname != snditer->second.end();++sndname) + size_t sfxid = lookupId(Misc::StringUtils::lowerCase(soundId)); + SoundIndexPairList::iterator sndidx = snditer->second.begin(); + for(;sndidx != snditer->second.end();++sndidx) { - if(sndname->second != soundid) + if(sndidx->second != sfxid) continue; - sndname->first->stop(); + sndidx->first->stop(); return; } } @@ -598,9 +617,9 @@ namespace MWSound SoundMap::iterator snditer = mActiveSounds.find(ptr); if(snditer != mActiveSounds.end()) { - SoundNamePairList::iterator sndname = snditer->second.begin(); - for(;sndname != snditer->second.end();++sndname) - sndname->first->stop(); + SoundIndexPairList::iterator sndidx = snditer->second.begin(); + for(;sndidx != snditer->second.end();++sndidx) + sndidx->first->stop(); } } @@ -613,9 +632,9 @@ namespace MWSound snditer->first != MWMechanics::getPlayer() && snditer->first.getCell() == cell) { - SoundNamePairList::iterator sndname = snditer->second.begin(); - for(;sndname != snditer->second.end();++sndname) - sndname->first->stop(); + SoundIndexPairList::iterator sndidx = snditer->second.begin(); + for(;sndidx != snditer->second.end();++sndidx) + sndidx->first->stop(); } ++snditer; } @@ -637,14 +656,12 @@ namespace MWSound SoundMap::iterator snditer = mActiveSounds.find(MWWorld::Ptr()); if(snditer != mActiveSounds.end()) { - std::string soundid = Misc::StringUtils::lowerCase(soundId); - SoundNamePairList::iterator sndname = snditer->second.begin(); - for(;sndname != snditer->second.end();++sndname) + size_t sfxid = lookupId(Misc::StringUtils::lowerCase(soundId)); + SoundIndexPairList::iterator sndidx = snditer->second.begin(); + for(;sndidx != snditer->second.end();++sndidx) { - if(sndname->second != soundid) - continue; - sndname->first->stop(); - return; + if(sndidx->second == sfxid) + sndidx->first->stop(); } } } @@ -655,12 +672,12 @@ namespace MWSound SoundMap::iterator snditer = mActiveSounds.find(ptr); if(snditer != mActiveSounds.end()) { - std::string soundid = Misc::StringUtils::lowerCase(soundId); - SoundNamePairList::iterator sndname = snditer->second.begin(); - for(;sndname != snditer->second.end();++sndname) + size_t sfxid = lookupId(Misc::StringUtils::lowerCase(soundId)); + SoundIndexPairList::iterator sndidx = snditer->second.begin(); + for(;sndidx != snditer->second.end();++sndidx) { - if(sndname->second == soundid) - sndname->first->setFadeout(duration); + if(sndidx->second == sfxid) + sndidx->first->setFadeout(duration); } } } @@ -670,11 +687,11 @@ namespace MWSound SoundMap::const_iterator snditer = mActiveSounds.find(ptr); if(snditer != mActiveSounds.end()) { - std::string soundid = Misc::StringUtils::lowerCase(soundId); - SoundNamePairList::const_iterator sndname = snditer->second.begin(); - for(;sndname != snditer->second.end();++sndname) + size_t sfxid = lookupId(Misc::StringUtils::lowerCase(soundId)); + SoundIndexPairList::const_iterator sndidx = snditer->second.begin(); + for(;sndidx != snditer->second.end();++sndidx) { - if(sndname->second == soundid && sndname->first->isPlaying()) + if(sndidx->second == sfxid && sndidx->first->isPlaying()) return true; } } @@ -804,20 +821,18 @@ namespace MWSound SoundMap::iterator snditer = mActiveSounds.begin(); while(snditer != mActiveSounds.end()) { - SoundNamePairList::iterator sndname = snditer->second.begin(); - while(sndname != snditer->second.end()) + SoundIndexPairList::iterator sndidx = snditer->second.begin(); + while(sndidx != snditer->second.end()) { - if(!updateSound(sndname->first, snditer->first, duration)) + if(!updateSound(sndidx->first, snditer->first, duration)) { - BufferKeyList::iterator bufkey = std::lower_bound(mBufferKeys.begin(), mBufferKeys.end(), - sndname->second); - Sound_Buffer *sfx = &mSoundBuffers[std::distance(mBufferKeys.begin(), bufkey)]; + Sound_Buffer *sfx = &mSoundBuffers[sndidx->second]; if(sfx->mReferences-- == 1) - mUnusedBuffers.insert(sndname->second); - sndname = snditer->second.erase(sndname); + mUnusedBuffers.insert(sndidx->second); + sndidx = snditer->second.erase(sndidx); } else - ++sndname; + ++sndidx; } if(snditer->second.empty()) mActiveSounds.erase(snditer++); @@ -893,10 +908,10 @@ namespace MWSound SoundMap::iterator snditer = mActiveSounds.begin(); for(;snditer != mActiveSounds.end();++snditer) { - SoundNamePairList::iterator sndname = snditer->second.begin(); - for(;sndname != snditer->second.end();++sndname) + SoundIndexPairList::iterator sndidx = snditer->second.begin(); + for(;sndidx != snditer->second.end();++sndidx) { - MWBase::SoundPtr sound = sndname->first; + MWBase::SoundPtr sound = sndidx->first; sound->mBaseVolume = volumeFromType(sound->getPlayType()); sound->update(); } @@ -932,7 +947,7 @@ namespace MWSound SoundMap::iterator snditer = mActiveSounds.find(old); if(snditer != mActiveSounds.end()) { - SoundNamePairList sndlist = snditer->second; + SoundIndexPairList sndlist = snditer->second; mActiveSounds.erase(snditer); mActiveSounds[updated] = sndlist; } @@ -1015,15 +1030,13 @@ namespace MWSound SoundMap::iterator snditer = mActiveSounds.begin(); for(;snditer != mActiveSounds.end();++snditer) { - SoundNamePairList::iterator sndname = snditer->second.begin(); - for(;sndname != snditer->second.end();++sndname) + SoundIndexPairList::iterator sndidx = snditer->second.begin(); + for(;sndidx != snditer->second.end();++sndidx) { - sndname->first->stop(); - BufferKeyList::iterator bufkey = std::lower_bound(mBufferKeys.begin(), mBufferKeys.end(), - sndname->second); - Sound_Buffer *sfx = &mSoundBuffers[std::distance(mBufferKeys.begin(), bufkey)]; + sndidx->first->stop(); + Sound_Buffer *sfx = &mSoundBuffers[sndidx->second]; if(sfx->mReferences-- == 1) - mUnusedBuffers.insert(sndname->second); + mUnusedBuffers.insert(sndidx->second); } } mActiveSounds.clear(); diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index 5e8d0d8f8..25ba9ce05 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -62,17 +62,18 @@ namespace MWSound typedef std::map NameLoudnessMap; NameLoudnessMap mVoiceLipBuffers; - typedef std::set SoundSet; + typedef std::set SoundSet; SoundSet mUnusedBuffers; boost::shared_ptr mMusic; std::string mCurrentPlaylist; - typedef std::pair SoundNamePair; - typedef std::vector SoundNamePairList; - typedef std::map SoundMap; + typedef std::pair SoundIndexPair; + typedef std::vector SoundIndexPairList; + typedef std::map SoundMap; SoundMap mActiveSounds; + typedef std::pair SoundNamePair; typedef std::map SaySoundMap; SaySoundMap mActiveSaySounds; @@ -87,7 +88,11 @@ namespace MWSound void insertSound(const std::string &soundId, const ESM::Sound *sound); + size_t lookupId(const std::string &soundId); + size_t lookupId(const std::string &soundId) const; + Sound_Buffer *lookup(size_t sfxid); Sound_Buffer *lookup(const std::string &soundId); + // Ensure the loudness/"lip" data is loaded void loadVoice(const std::string &voicefile); From 3ce6aee98babc135b95c77b749f509549855e81f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 24 Nov 2015 04:00:17 -0800 Subject: [PATCH 2562/3725] Return a decoder from the loadVoice function --- apps/openmw/mwsound/soundmanagerimp.cpp | 31 ++++++++++++++++++------- apps/openmw/mwsound/soundmanagerimp.hpp | 5 ++-- 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index bb767cf41..fca879e8f 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -241,10 +241,25 @@ namespace MWSound return lookup(lookupId(soundId)); } - void SoundManager::loadVoice(const std::string &voicefile) + DecoderPtr SoundManager::loadVoice(const std::string &voicefile) { NameLoudnessMap::iterator lipiter = mVoiceLipBuffers.find(voicefile); - if(lipiter != mVoiceLipBuffers.end()) return; + if(lipiter != mVoiceLipBuffers.end()) + { + DecoderPtr decoder = getDecoder(); + // Workaround: Bethesda at some point converted some of the files to mp3, but the references were kept as .wav. + if(decoder->mResourceMgr->exists(voicefile)) + decoder->open(voicefile); + else + { + std::string file = voicefile; + std::string::size_type pos = file.rfind('.'); + if(pos != std::string::npos) + file = file.substr(0, pos)+".mp3"; + decoder->open(file); + } + return decoder; + } DecoderPtr decoder = getDecoder(); // Workaround: Bethesda at some point converted some of the files to mp3, but the references were kept as .wav. @@ -266,12 +281,14 @@ namespace MWSound std::vector data; decoder->readAll(data); - decoder->close(); Sound_Loudness loudness; loudness.analyzeLoudness(data, srate, chans, type, static_cast(sLoudnessFPS)); mVoiceLipBuffers.insert(std::make_pair(voicefile, loudness)); + + decoder->rewind(); + return decoder; } @@ -407,9 +424,7 @@ namespace MWSound const ESM::Position &pos = ptr.getRefData().getPosition(); const osg::Vec3f objpos(pos.asVec3()); - loadVoice(voicefile); - DecoderPtr decoder = getDecoder(); - decoder->open(voicefile); + DecoderPtr decoder = loadVoice(voicefile); MWBase::SoundPtr sound = mOutput->streamSound3D(decoder, objpos, 1.0f, basevol, 1.0f, minDistance, maxDistance, Play_Normal|Play_TypeVoice @@ -449,9 +464,7 @@ namespace MWSound std::string voicefile = "sound/"+Misc::StringUtils::lowerCase(filename); float basevol = volumeFromType(Play_TypeVoice); - loadVoice(voicefile); - DecoderPtr decoder = getDecoder(); - decoder->open(voicefile); + DecoderPtr decoder = loadVoice(voicefile); MWBase::SoundPtr sound = mOutput->streamSound(decoder, basevol, 1.0f, Play_Normal|Play_TypeVoice diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index 25ba9ce05..9fc9084ee 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -93,8 +93,9 @@ namespace MWSound Sound_Buffer *lookup(size_t sfxid); Sound_Buffer *lookup(const std::string &soundId); - // Ensure the loudness/"lip" data is loaded - void loadVoice(const std::string &voicefile); + // Ensures the loudness/"lip" data is loaded, and returns a decoder to + // start streaming + DecoderPtr loadVoice(const std::string &voicefile); void streamMusicFull(const std::string& filename); bool updateSound(MWBase::SoundPtr sound, const MWWorld::Ptr &ptr, float duration); From 5ad772c3b3b84012346e8baa18f171e0c610a8cd Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 24 Nov 2015 04:54:14 -0800 Subject: [PATCH 2563/3725] Fix streaming sound time --- apps/openmw/mwsound/openal_output.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index e3d3ca8da..b851b931d 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -376,7 +376,7 @@ double OpenAL_SoundStream::getTimeOffset() { ALint queued; alGetSourcei(mSource, AL_BUFFERS_QUEUED, &queued); - ALint inqueue = mBufferSize/mFrameSize*queued + offset; + ALint inqueue = mBufferSize/mFrameSize*queued - offset; t = (double)(mDecoder->getSampleOffset() - inqueue) / (double)mSampleRate; } else From 574c1923fe7ad463c8c556f93086dd08575c81d3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 24 Nov 2015 04:54:54 -0800 Subject: [PATCH 2564/3725] Clear unused buffers after unloading them all --- apps/openmw/mwsound/soundmanagerimp.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index fca879e8f..d7199c0fe 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -108,6 +108,7 @@ namespace MWSound mOutput->unloadSound(sfxiter->mHandle); sfxiter->mHandle = 0; } + mUnusedBuffers.clear(); } mOutput.reset(); } From 45628316f869ee85f54f0f9f33f4315655bffa9a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 24 Nov 2015 05:03:08 -0800 Subject: [PATCH 2565/3725] Remove an unnecessary check --- apps/openmw/mwsound/openal_output.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index b851b931d..867a29044 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -436,8 +436,8 @@ bool OpenAL_SoundStream::process() alGetSourcei(mSource, AL_SOURCE_STATE, &state); if(state != AL_PLAYING && state != AL_PAUSED) { - if(refillQueue() > 0) - alSourcePlay(mSource); + refillQueue(); + alSourcePlay(mSource); } } } From 8a69f676ec182af006674bfe229d9e3d71ff9f79 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 24 Nov 2015 05:56:05 -0800 Subject: [PATCH 2566/3725] Remove some duplicate code --- apps/openmw/mwsound/soundmanagerimp.cpp | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index d7199c0fe..d02776136 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -244,24 +244,6 @@ namespace MWSound DecoderPtr SoundManager::loadVoice(const std::string &voicefile) { - NameLoudnessMap::iterator lipiter = mVoiceLipBuffers.find(voicefile); - if(lipiter != mVoiceLipBuffers.end()) - { - DecoderPtr decoder = getDecoder(); - // Workaround: Bethesda at some point converted some of the files to mp3, but the references were kept as .wav. - if(decoder->mResourceMgr->exists(voicefile)) - decoder->open(voicefile); - else - { - std::string file = voicefile; - std::string::size_type pos = file.rfind('.'); - if(pos != std::string::npos) - file = file.substr(0, pos)+".mp3"; - decoder->open(file); - } - return decoder; - } - DecoderPtr decoder = getDecoder(); // Workaround: Bethesda at some point converted some of the files to mp3, but the references were kept as .wav. if(decoder->mResourceMgr->exists(voicefile)) @@ -275,6 +257,9 @@ namespace MWSound decoder->open(file); } + NameLoudnessMap::iterator lipiter = mVoiceLipBuffers.find(voicefile); + if(lipiter != mVoiceLipBuffers.end()) return decoder; + ChannelConfig chans; SampleType type; int srate; From 4801661b34e1e50be065f02b8221c122161a3603 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 24 Nov 2015 08:08:38 -0800 Subject: [PATCH 2567/3725] Stop all sounds of the given id --- apps/openmw/mwsound/soundmanagerimp.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index d02776136..1b88bb3f2 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -603,10 +603,8 @@ namespace MWSound SoundIndexPairList::iterator sndidx = snditer->second.begin(); for(;sndidx != snditer->second.end();++sndidx) { - if(sndidx->second != sfxid) - continue; - sndidx->first->stop(); - return; + if(sndidx->second == sfxid) + sndidx->first->stop(); } } } From fd7d58fe7e130a885bcbd74faa1665266164f0f1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 24 Nov 2015 18:48:25 -0800 Subject: [PATCH 2568/3725] Reset the sound handle back to null after unloading --- apps/openmw/mwsound/soundmanagerimp.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 1b88bb3f2..ebc3aab7e 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -225,8 +225,11 @@ namespace MWSound } SoundSet::iterator iter = mUnusedBuffers.begin(); Sound_Buffer *unused = &mSoundBuffers[*iter]; + mBufferCacheSize -= mOutput->getSoundDataSize(unused->mHandle); mOutput->unloadSound(unused->mHandle); + unused->mHandle = 0; + mUnusedBuffers.erase(iter); } mUnusedBuffers.insert(sfxid); From ea70b0baee524387b05c0ff7595c67662d2e8aa7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 24 Nov 2015 20:03:15 -0800 Subject: [PATCH 2569/3725] Don't store the buffer in the sound struct --- apps/openmw/mwsound/openal_output.cpp | 73 ++++++++++++++------------- 1 file changed, 38 insertions(+), 35 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 867a29044..61a5cc3a3 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -146,6 +146,19 @@ static ALenum getALFormat(ChannelConfig chans, SampleType type) return AL_NONE; } +static double getBufferLength(ALuint buffer) +{ + ALint bufferSize, frequency, channels, bitsPerSample; + alGetBufferi(buffer, AL_SIZE, &bufferSize); + alGetBufferi(buffer, AL_FREQUENCY, &frequency); + alGetBufferi(buffer, AL_CHANNELS, &channels); + alGetBufferi(buffer, AL_BITS, &bitsPerSample); + throwALerror(); + + return (8.0*bufferSize)/(frequency*channels*bitsPerSample); +} + + // // A streaming OpenAL sound. // @@ -515,7 +528,6 @@ protected: OpenAL_Output &mOutput; ALuint mSource; - ALuint mBuffer; friend class OpenAL_Output; @@ -526,13 +538,12 @@ private: OpenAL_Sound& operator=(const OpenAL_Sound &rhs); public: - OpenAL_Sound(OpenAL_Output &output, ALuint src, ALuint buf, const osg::Vec3f& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags); + OpenAL_Sound(OpenAL_Output &output, ALuint src, const osg::Vec3f& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags); virtual ~OpenAL_Sound(); virtual void stop(); virtual bool isPlaying(); virtual double getTimeOffset(); - virtual double getLength(); virtual void update(); }; @@ -545,16 +556,16 @@ class OpenAL_Sound3D : public OpenAL_Sound OpenAL_Sound3D& operator=(const OpenAL_Sound &rhs); public: - OpenAL_Sound3D(OpenAL_Output &output, ALuint src, ALuint buf, const osg::Vec3f& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags) - : OpenAL_Sound(output, src, buf, pos, vol, basevol, pitch, mindist, maxdist, flags) + OpenAL_Sound3D(OpenAL_Output &output, ALuint src, const osg::Vec3f& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags) + : OpenAL_Sound(output, src, pos, vol, basevol, pitch, mindist, maxdist, flags) { } virtual void update(); }; -OpenAL_Sound::OpenAL_Sound(OpenAL_Output &output, ALuint src, ALuint buf, const osg::Vec3f& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags) +OpenAL_Sound::OpenAL_Sound(OpenAL_Output &output, ALuint src, const osg::Vec3f& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags) : Sound(pos, vol, basevol, pitch, mindist, maxdist, flags) - , mOutput(output), mSource(src), mBuffer(buf) + , mOutput(output), mSource(src) { mOutput.mActiveSounds.push_back(this); } @@ -595,17 +606,6 @@ double OpenAL_Sound::getTimeOffset() return t; } -double OpenAL_Sound::getLength() -{ - ALint bufferSize, frequency, channels, bitsPerSample; - alGetBufferi(mBuffer, AL_SIZE, &bufferSize); - alGetBufferi(mBuffer, AL_FREQUENCY, &frequency); - alGetBufferi(mBuffer, AL_CHANNELS, &channels); - alGetBufferi(mBuffer, AL_BITS, &bitsPerSample); - - return (8.0*bufferSize)/(frequency*channels*bitsPerSample); -} - void OpenAL_Sound::updateAll(bool local) { alSourcef(mSource, AL_REFERENCE_DISTANCE, mMinDistance); @@ -815,11 +815,15 @@ void OpenAL_Output::unloadSound(Sound_Handle data) SoundVec::const_iterator iter = mActiveSounds.begin(); for(;iter != mActiveSounds.end();++iter) { - if((*iter)->mSource && (*iter)->mBuffer == buffer) + if(!(*iter)->mSource) + continue; + + ALint srcbuf; + alGetSourcei((*iter)->mSource, AL_BUFFER, &srcbuf); + if((ALuint)srcbuf == buffer) { alSourceStop((*iter)->mSource); alSourcei((*iter)->mSource, AL_BUFFER, 0); - (*iter)->mBuffer = 0; } } alDeleteBuffers(1, &buffer); @@ -847,9 +851,8 @@ MWBase::SoundPtr OpenAL_Output::playSound(Sound_Handle data, float vol, float ba src = mFreeSources.front(); mFreeSources.pop_front(); - ALuint buffer = GET_PTRID(data); try { - sound.reset(new OpenAL_Sound(*this, src, buffer, osg::Vec3f(0.f, 0.f, 0.f), vol, basevol, pitch, 1.0f, 1000.0f, flags)); + sound.reset(new OpenAL_Sound(*this, src, osg::Vec3f(0.f, 0.f, 0.f), vol, basevol, pitch, 1.0f, 1000.0f, flags)); } catch(std::exception&) { @@ -858,13 +861,14 @@ MWBase::SoundPtr OpenAL_Output::playSound(Sound_Handle data, float vol, float ba } sound->updateAll(true); - if(offset<0) - offset=0; - if(offset>1) - offset=1; + if(offset < 0.0f) + offset = 0.0f; + if(offset > 1.0f) + offset = 1.0f; + ALuint buffer = GET_PTRID(data); alSourcei(src, AL_BUFFER, buffer); - alSourcef(src, AL_SEC_OFFSET, static_cast(sound->getLength()*offset / pitch)); + alSourcef(src, AL_SEC_OFFSET, static_cast(getBufferLength(buffer)*offset / pitch)); alSourcePlay(src); throwALerror(); @@ -882,9 +886,8 @@ MWBase::SoundPtr OpenAL_Output::playSound3D(Sound_Handle data, const osg::Vec3f src = mFreeSources.front(); mFreeSources.pop_front(); - ALuint buffer = GET_PTRID(data); try { - sound.reset(new OpenAL_Sound3D(*this, src, buffer, pos, vol, basevol, pitch, min, max, flags)); + sound.reset(new OpenAL_Sound3D(*this, src, pos, vol, basevol, pitch, min, max, flags)); } catch(std::exception&) { @@ -893,14 +896,14 @@ MWBase::SoundPtr OpenAL_Output::playSound3D(Sound_Handle data, const osg::Vec3f } sound->updateAll(false); + if(offset < 0.0f) + offset = 0.0f; + if(offset > 1.0f) + offset = 1.0f; - if(offset<0) - offset=0; - if(offset>1) - offset=1; - + ALuint buffer = GET_PTRID(data); alSourcei(src, AL_BUFFER, buffer); - alSourcef(src, AL_SEC_OFFSET, static_cast(sound->getLength()*offset / pitch)); + alSourcef(src, AL_SEC_OFFSET, static_cast(getBufferLength(buffer)*offset / pitch)); alSourcePlay(src); throwALerror(); From 669b7a22953689a5b8593a0131b400f1ff812769 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 24 Nov 2015 20:37:38 -0800 Subject: [PATCH 2570/3725] Batch update changes together, when possible Certain OpenAL implementations, including Rapture3D, Creative's hardware drivers, and more recent versions of OpenAL Soft, can batch together changes so that they all occur at once, avoiding potential discontinuities with one sound being changed before another, or the listeenr being changed before sounds are. On other implementaitons, this is a no-op and maintains existing behavior. --- apps/openmw/mwsound/openal_output.cpp | 11 +++++++++++ apps/openmw/mwsound/openal_output.hpp | 3 +++ apps/openmw/mwsound/sound_output.hpp | 3 +++ apps/openmw/mwsound/soundmanagerimp.cpp | 6 ++++++ 4 files changed, 23 insertions(+) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 61a5cc3a3..33202ba74 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -970,6 +970,17 @@ MWBase::SoundPtr OpenAL_Output::streamSound3D(DecoderPtr decoder, const osg::Vec } +void OpenAL_Output::startUpdate() +{ + alcSuspendContext(alcGetCurrentContext()); +} + +void OpenAL_Output::finishUpdate() +{ + alcProcessContext(alcGetCurrentContext()); +} + + void OpenAL_Output::updateListener(const osg::Vec3f &pos, const osg::Vec3f &atdir, const osg::Vec3f &updir, Environment env) { mPos = pos; diff --git a/apps/openmw/mwsound/openal_output.hpp b/apps/openmw/mwsound/openal_output.hpp index 912bebb56..0f54da9b5 100644 --- a/apps/openmw/mwsound/openal_output.hpp +++ b/apps/openmw/mwsound/openal_output.hpp @@ -51,6 +51,9 @@ namespace MWSound virtual MWBase::SoundPtr streamSound3D(DecoderPtr decoder, const osg::Vec3f &pos, float vol, float basevol, float pitch, float min, float max, int flags); + virtual void startUpdate(); + virtual void finishUpdate(); + virtual void updateListener(const osg::Vec3f &pos, const osg::Vec3f &atdir, const osg::Vec3f &updir, Environment env); virtual void pauseSounds(int types); diff --git a/apps/openmw/mwsound/sound_output.hpp b/apps/openmw/mwsound/sound_output.hpp index 86be94d33..c91431f69 100644 --- a/apps/openmw/mwsound/sound_output.hpp +++ b/apps/openmw/mwsound/sound_output.hpp @@ -39,6 +39,9 @@ namespace MWSound virtual MWBase::SoundPtr streamSound3D(DecoderPtr decoder, const osg::Vec3f &pos, float vol, float basevol, float pitch, float min, float max, int flags) = 0; + virtual void startUpdate() = 0; + virtual void finishUpdate() = 0; + virtual void updateListener(const osg::Vec3f &pos, const osg::Vec3f &atdir, const osg::Vec3f &updir, Environment env) = 0; virtual void pauseSounds(int types) = 0; diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index ebc3aab7e..3ccc1c715 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -803,6 +803,7 @@ namespace MWSound mUnderwaterSound.reset(); } + mOutput->startUpdate(); mOutput->updateListener( mListenerPos, mListenerDir, @@ -848,6 +849,7 @@ namespace MWSound else ++sayiter; } + mOutput->finishUpdate(); } bool SoundManager::updateSound(MWBase::SoundPtr sound, const MWWorld::Ptr& ptr, float duration) @@ -905,6 +907,9 @@ namespace MWSound mFootstepsVolume = Settings::Manager::getFloat("footsteps volume", "Sound"); mVoiceVolume = Settings::Manager::getFloat("voice volume", "Sound"); + if(!mOutput->isInitialized()) + return; + mOutput->startUpdate(); SoundMap::iterator snditer = mActiveSounds.begin(); for(;snditer != mActiveSounds.end();++snditer) { @@ -928,6 +933,7 @@ namespace MWSound mMusic->mBaseVolume = volumeFromType(mMusic->getPlayType()); mMusic->update(); } + mOutput->finishUpdate(); } void SoundManager::setListenerPosDir(const osg::Vec3f &pos, const osg::Vec3f &dir, const osg::Vec3f &up) From caae305dddde434ca79f89a20d40416da43b4462 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 24 Nov 2015 21:40:15 -0800 Subject: [PATCH 2571/3725] Use a sorted list for unused buffers Helps ensure the buffers being unloaded due to cache limits are not likely to be needed anytime soon. --- apps/openmw/mwsound/soundmanagerimp.cpp | 29 +++++++++++++++++-------- apps/openmw/mwsound/soundmanagerimp.hpp | 6 +++-- 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 3ccc1c715..9183378f7 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -223,16 +223,15 @@ namespace MWSound std::cerr<< "No unused sound buffers to free, using "<getSoundDataSize(unused->mHandle); mOutput->unloadSound(unused->mHandle); unused->mHandle = 0; - mUnusedBuffers.erase(iter); + mUnusedBuffers.pop_back(); } - mUnusedBuffers.insert(sfxid); + mUnusedBuffers.push_front(sfxid); } return sfx; @@ -520,7 +519,11 @@ namespace MWSound volume * sfx->mVolume, basevol, pitch, mode|type, offset ); if(sfx->mReferences++ == 0) - mUnusedBuffers.erase(sfxid); + { + SoundList::iterator iter = std::find(mUnusedBuffers.begin(), mUnusedBuffers.end(), sfxid); + if(iter != mUnusedBuffers.end()) + mUnusedBuffers.erase(iter); + } mActiveSounds[MWWorld::Ptr()].push_back(std::make_pair(sound, sfxid)); } catch(std::exception&) @@ -552,7 +555,11 @@ namespace MWSound objpos, volume * sfx->mVolume, basevol, pitch, sfx->mMinDist, sfx->mMaxDist, mode|type, offset ); if(sfx->mReferences++ == 0) - mUnusedBuffers.erase(sfxid); + { + SoundList::iterator iter = std::find(mUnusedBuffers.begin(), mUnusedBuffers.end(), sfxid); + if(iter != mUnusedBuffers.end()) + mUnusedBuffers.erase(iter); + } if((mode&Play_NoTrack)) mActiveSounds[MWWorld::Ptr()].push_back(std::make_pair(sound, sfxid)); else @@ -582,7 +589,11 @@ namespace MWSound initialPos, volume * sfx->mVolume, basevol, pitch, sfx->mMinDist, sfx->mMaxDist, mode|type, offset ); if(sfx->mReferences++ == 0) - mUnusedBuffers.erase(sfxid); + { + SoundList::iterator iter = std::find(mUnusedBuffers.begin(), mUnusedBuffers.end(), sfxid); + if(iter != mUnusedBuffers.end()) + mUnusedBuffers.erase(iter); + } mActiveSounds[MWWorld::Ptr()].push_back(std::make_pair(sound, sfxid)); } catch(std::exception &) @@ -829,7 +840,7 @@ namespace MWSound { Sound_Buffer *sfx = &mSoundBuffers[sndidx->second]; if(sfx->mReferences-- == 1) - mUnusedBuffers.insert(sndidx->second); + mUnusedBuffers.push_front(sndidx->second); sndidx = snditer->second.erase(sndidx); } else @@ -1042,7 +1053,7 @@ namespace MWSound sndidx->first->stop(); Sound_Buffer *sfx = &mSoundBuffers[sndidx->second]; if(sfx->mReferences-- == 1) - mUnusedBuffers.insert(sndidx->second); + mUnusedBuffers.push_front(sndidx->second); } } mActiveSounds.clear(); diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index 9fc9084ee..d5c9a881e 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -62,8 +63,9 @@ namespace MWSound typedef std::map NameLoudnessMap; NameLoudnessMap mVoiceLipBuffers; - typedef std::set SoundSet; - SoundSet mUnusedBuffers; + // NOTE: unused buffers are stored in front-newest order. + typedef std::deque SoundList; + SoundList mUnusedBuffers; boost::shared_ptr mMusic; std::string mCurrentPlaylist; From 73448c72f63583e6e881ee6a6f5c3c42c9d7945c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 24 Nov 2015 23:24:42 -0800 Subject: [PATCH 2572/3725] Replace Play_NoTrack with playManualSound3D, and rename the latter --- apps/openmw/mwbase/soundmanager.hpp | 23 ++++++++++------------- apps/openmw/mwmechanics/actors.cpp | 5 +++-- apps/openmw/mwsound/soundmanagerimp.cpp | 9 +++------ apps/openmw/mwsound/soundmanagerimp.hpp | 6 +++--- apps/openmw/mwworld/action.cpp | 23 +++++++++++++++-------- apps/openmw/mwworld/projectilemanager.cpp | 6 +++--- apps/openmw/mwworld/worldimp.cpp | 4 ++-- 7 files changed, 39 insertions(+), 37 deletions(-) diff --git a/apps/openmw/mwbase/soundmanager.hpp b/apps/openmw/mwbase/soundmanager.hpp index 4fccec40b..91bdef967 100644 --- a/apps/openmw/mwbase/soundmanager.hpp +++ b/apps/openmw/mwbase/soundmanager.hpp @@ -29,13 +29,10 @@ namespace MWBase public: /* These must all fit together */ enum PlayMode { - Play_Normal = 0, /* tracked, non-looping, multi-instance, environment */ + Play_Normal = 0, /* non-looping, affected by 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 - * but do not keep it updated (the sound will not move with - * the object and will not stop when the object is deleted. */ - Play_RemoveAtDistance = 1<<3, /* (3D only) If the listener gets further than 2000 units away + Play_RemoveAtDistance = 1<<2, /* (3D only) If the listener gets further than 2000 units away from the sound source, the sound is removed. This is weird stuff but apparently how vanilla works for sounds played by the PlayLoopSound family of script functions. Perhaps we @@ -45,11 +42,11 @@ namespace MWBase Play_LoopRemoveAtDistance = Play_Loop | Play_RemoveAtDistance }; enum PlayType { - Play_TypeSfx = 1<<4, /* Normal SFX sound */ - Play_TypeVoice = 1<<5, /* Voice sound */ - Play_TypeFoot = 1<<6, /* Footstep sound */ - Play_TypeMusic = 1<<7, /* Music track */ - Play_TypeMovie = 1<<8, /* Movie audio track */ + Play_TypeSfx = 1<<3, /* Normal SFX sound */ + Play_TypeVoice = 1<<4, /* Voice sound */ + Play_TypeFoot = 1<<5, /* Footstep sound */ + Play_TypeMusic = 1<<6, /* Music track */ + Play_TypeMovie = 1<<7, /* Movie audio track */ Play_TypeMask = Play_TypeSfx|Play_TypeVoice|Play_TypeFoot|Play_TypeMusic|Play_TypeMovie }; @@ -120,9 +117,9 @@ namespace MWBase ///< Play a 3D sound attached to an MWWorld::Ptr. Will be updated automatically with the Ptr's position, unless Play_NoTrack is specified. ///< @param offset Value from [0,1] meaning from which fraction the sound the playback starts. - virtual MWBase::SoundPtr playManualSound3D(const osg::Vec3f& initialPos, const std::string& soundId, - float volume, float pitch, PlayType type, PlayMode mode, float offset=0) = 0; - ///< Play a 3D sound at \a initialPos. If the sound should be moving, it must be updated manually using Sound::setPosition. + virtual MWBase::SoundPtr playSound3D(const osg::Vec3f& initialPos, const std::string& soundId, + float volume, float pitch, PlayType type=Play_TypeSfx, PlayMode mode=Play_Normal, float offset=0) = 0; + ///< Play a 3D sound at \a initialPos. If the sound should be moving, it must be updated using Sound::setPosition. virtual void stopSound3D(const MWWorld::Ptr &reference, const std::string& soundId) = 0; ///< Stop the given object from playing the given sound, diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 284e237a0..59f8ecbc0 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -212,8 +212,9 @@ namespace MWMechanics MWBase::Environment::get().getWorld()->spawnEffect("meshes\\" + fx->mModel, "", mCreature.getRefData().getPosition().asVec3()); - MWBase::Environment::get().getSoundManager()->playSound3D(mCreature, "conjuration hit", 1.f, 1.f, - MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_NoTrack); + MWBase::Environment::get().getSoundManager()->playSound3D( + mCreature.getRefData().getPosition().asVec3(), "conjuration hit", 1.f, 1.f + ); } }; diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 9183378f7..781910283 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -560,10 +560,7 @@ namespace MWSound if(iter != mUnusedBuffers.end()) mUnusedBuffers.erase(iter); } - if((mode&Play_NoTrack)) - mActiveSounds[MWWorld::Ptr()].push_back(std::make_pair(sound, sfxid)); - else - mActiveSounds[ptr].push_back(std::make_pair(sound, sfxid)); + mActiveSounds[ptr].push_back(std::make_pair(sound, sfxid)); } catch(std::exception&) { @@ -572,8 +569,8 @@ namespace MWSound return sound; } - MWBase::SoundPtr SoundManager::playManualSound3D(const osg::Vec3f& initialPos, const std::string& soundId, - float volume, float pitch, PlayType type, PlayMode mode, float offset) + MWBase::SoundPtr SoundManager::playSound3D(const osg::Vec3f& initialPos, const std::string& soundId, + float volume, float pitch, PlayType type, PlayMode mode, float offset) { MWBase::SoundPtr sound; if(!mOutput->isInitialized()) diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index d5c9a881e..3b2ed873e 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -168,9 +168,9 @@ namespace MWSound ///< Play a 3D sound attached to an MWWorld::Ptr. Will be updated automatically with the Ptr's position, unless Play_NoTrack is specified. ///< @param offset Value from [0,1] meaning from which fraction the sound the playback starts. - virtual MWBase::SoundPtr playManualSound3D(const osg::Vec3f& initialPos, const std::string& soundId, - float volume, float pitch, PlayType type, PlayMode mode, float offset=0); - ///< Play a 3D sound at \a initialPos. If the sound should be moving, it must be updated manually using Sound::setPosition. + virtual MWBase::SoundPtr playSound3D(const osg::Vec3f& initialPos, const std::string& soundId, + float volume, float pitch, PlayType type, PlayMode mode, float offset=0); + ///< Play a 3D sound at \a initialPos. If the sound should be moving, it must be updated using Sound::setPosition. ///< Play a sound from an object ///< @param offset value from [0,1], when to start playback. 0 is beginning, 1 is end. diff --git a/apps/openmw/mwworld/action.cpp b/apps/openmw/mwworld/action.cpp index 6361b3404..c29377ecb 100644 --- a/apps/openmw/mwworld/action.cpp +++ b/apps/openmw/mwworld/action.cpp @@ -19,19 +19,26 @@ MWWorld::Action::~Action() {} void MWWorld::Action::execute (const Ptr& actor) { - if (!mSoundId.empty()) + if(!mSoundId.empty()) { - if (mKeepSound && actor == MWMechanics::getPlayer()) + if(mKeepSound && actor == MWMechanics::getPlayer()) MWBase::Environment::get().getSoundManager()->playSound(mSoundId, 1.0, 1.0, - MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_Normal,mSoundOffset); + MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_Normal, mSoundOffset + ); else { bool local = mTarget.isEmpty() || !mTarget.isInCell(); // no usable target - - MWBase::Environment::get().getSoundManager()->playSound3D(local ? actor : mTarget, - mSoundId, 1.0, 1.0, MWBase::SoundManager::Play_TypeSfx, - mKeepSound ? MWBase::SoundManager::Play_NoTrack : MWBase::SoundManager::Play_Normal, - mSoundOffset); + if(mKeepSound) + MWBase::Environment::get().getSoundManager()->playSound3D( + (local ? actor : mTarget).getRefData().getPosition().asVec3(), + mSoundId, 1.0, 1.0, MWBase::SoundManager::Play_TypeSfx, + MWBase::SoundManager::Play_Normal, mSoundOffset + ); + else + MWBase::Environment::get().getSoundManager()->playSound3D(local ? actor : mTarget, + mSoundId, 1.0, 1.0, MWBase::SoundManager::Play_TypeSfx, + MWBase::SoundManager::Play_Normal, mSoundOffset + ); } } diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index d5aca17a6..0aeaabf12 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -107,7 +107,7 @@ namespace MWWorld createModel(state, ptr.getClass().getModel(ptr), pos, orient); MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); - state.mSound = sndMgr->playManualSound3D(pos, sound, 1.0f, 1.0f, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_Loop); + state.mSound = sndMgr->playSound3D(pos, sound, 1.0f, 1.0f, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_Loop); mMagicBolts.push_back(state); } @@ -374,8 +374,8 @@ namespace MWWorld createModel(state, model, osg::Vec3f(esm.mPosition), osg::Quat(esm.mOrientation)); MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); - state.mSound = sndMgr->playManualSound3D(esm.mPosition, esm.mSound, 1.0f, 1.0f, - MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_Loop); + state.mSound = sndMgr->playSound3D(esm.mPosition, esm.mSound, 1.0f, 1.0f, + MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_Loop); state.mSoundId = esm.mSound; mMagicBolts.push_back(state); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 6f63605c7..df2e577d1 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -3153,9 +3153,9 @@ namespace MWWorld { MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); if(!effect->mAreaSound.empty()) - sndMgr->playManualSound3D(origin, effect->mAreaSound, 1.0f, 1.0f, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_NoTrack); + sndMgr->playSound3D(origin, effect->mAreaSound, 1.0f, 1.0f); else - sndMgr->playManualSound3D(origin, schools[effect->mData.mSchool]+" area", 1.0f, 1.0f, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_NoTrack); + sndMgr->playSound3D(origin, schools[effect->mData.mSchool]+" area", 1.0f, 1.0f); } // Get the actors in range of the effect std::vector objects; From aac903484c661e6bcecfb2c7d67b182822bd3735 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 25 Nov 2015 00:09:40 -0800 Subject: [PATCH 2573/3725] Remove a really unnecessary method --- apps/openmw/mwbase/soundmanager.hpp | 3 --- apps/openmw/mwsound/soundmanagerimp.cpp | 5 ----- apps/openmw/mwsound/soundmanagerimp.hpp | 3 --- apps/openmw/mwworld/projectilemanager.cpp | 5 ++--- apps/openmw/mwworld/weather.cpp | 8 +++----- 5 files changed, 5 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwbase/soundmanager.hpp b/apps/openmw/mwbase/soundmanager.hpp index 91bdef967..9366875e3 100644 --- a/apps/openmw/mwbase/soundmanager.hpp +++ b/apps/openmw/mwbase/soundmanager.hpp @@ -127,9 +127,6 @@ namespace MWBase virtual void stopSound3D(const MWWorld::Ptr &reference) = 0; ///< Stop the given object from playing all sounds. - virtual void stopSound(MWBase::SoundPtr sound) = 0; - ///< Stop the given sound handle - virtual void stopSound(const MWWorld::CellStore *cell) = 0; ///< Stop all sounds for the given cell. diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 781910283..26ba1e210 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -600,11 +600,6 @@ namespace MWSound return sound; } - void SoundManager::stopSound (MWBase::SoundPtr sound) - { - sound->stop(); - } - void SoundManager::stopSound3D(const MWWorld::Ptr &ptr, const std::string& soundId) { SoundMap::iterator snditer = mActiveSounds.find(ptr); diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index 3b2ed873e..15fdd86cf 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -181,9 +181,6 @@ namespace MWSound virtual void stopSound3D(const MWWorld::Ptr &reference); ///< Stop the given object from playing all sounds. - virtual void stopSound(MWBase::SoundPtr sound); - ///< Stop the given sound handle - virtual void stopSound(const MWWorld::CellStore *cell); ///< Stop all sounds for the given cell. diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 0aeaabf12..4ec4d1432 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -190,8 +190,7 @@ namespace MWWorld { MWBase::Environment::get().getWorld()->explodeSpell(pos, it->mEffects, caster, ESM::RT_Target, it->mSpellId, it->mSourceName); - MWBase::Environment::get().getSoundManager()->stopSound(it->mSound); - + it->mSound->stop(); mParent->removeChild(it->mNode); it = mMagicBolts.erase(it); @@ -265,7 +264,7 @@ namespace MWWorld for (std::vector::iterator it = mMagicBolts.begin(); it != mMagicBolts.end(); ++it) { mParent->removeChild(it->mNode); - MWBase::Environment::get().getSoundManager()->stopSound(it->mSound); + it->mSound->stop(); } mMagicBolts.clear(); } diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 49d421a20..6d9a85ada 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -735,11 +735,9 @@ void WeatherManager::update(float duration, bool paused) void WeatherManager::stopSounds() { if (mAmbientSound.get()) - { - MWBase::Environment::get().getSoundManager()->stopSound(mAmbientSound); - mAmbientSound.reset(); - mPlayingSoundID.clear(); - } + mAmbientSound->stop(); + mAmbientSound.reset(); + mPlayingSoundID.clear(); } float WeatherManager::getWindSpeed() const From a1bdb544dbaa6520f265be73a2710a5c5b82668d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 25 Nov 2015 01:05:55 -0800 Subject: [PATCH 2574/3725] Avoid an unnecessary string copy --- apps/openmw/mwsound/openal_output.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 33202ba74..bafd272af 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -773,14 +773,16 @@ Sound_Handle OpenAL_Output::loadSound(const std::string &fname) DecoderPtr decoder = mManager.getDecoder(); // Workaround: Bethesda at some point converted some of the files to mp3, but the references were kept as .wav. - std::string file = fname; - if (!decoder->mResourceMgr->exists(file)) + if(decoder->mResourceMgr->exists(fname)) + decoder->open(fname); + else { + std::string file = fname; std::string::size_type pos = file.rfind('.'); if(pos != std::string::npos) file = file.substr(0, pos)+".mp3"; + decoder->open(file); } - decoder->open(file); std::vector data; ChannelConfig chans; From 0d4fea896c549edb109587d42f9630af1f7816f9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 25 Nov 2015 02:04:10 -0800 Subject: [PATCH 2575/3725] Avoid unsafe sizeof(x)/sizeof(x[0]) constructs for array counting --- apps/openmw/mwsound/openal_output.cpp | 98 ++++++++++++--------------- 1 file changed, 44 insertions(+), 54 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index bafd272af..419bb76b7 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -23,13 +23,17 @@ #define MAKE_PTRID(id) ((void*)(uintptr_t)id) #define GET_PTRID(ptr) ((ALuint)(uintptr_t)ptr) -namespace MWSound +namespace { -static void fail(const std::string &msg) +template +inline size_t countof(const T(&)[N]) +{ return N; } + +void fail(const std::string &msg) { throw std::runtime_error("OpenAL exception: " + msg); } -static void throwALCerror(ALCdevice *device) +void throwALCerror(ALCdevice *device) { ALCenum err = alcGetError(device); if(err != ALC_NO_ERROR) @@ -39,7 +43,7 @@ static void throwALCerror(ALCdevice *device) } } -static void throwALerror() +void throwALerror() { ALenum err = alGetError(); if(err != AL_NO_ERROR) @@ -50,21 +54,39 @@ static void throwALerror() } -static ALenum getALFormat(ChannelConfig chans, SampleType type) +ALenum getALFormat(MWSound::ChannelConfig chans, MWSound::SampleType type) { static const struct { ALenum format; - ChannelConfig chans; - SampleType type; + MWSound::ChannelConfig chans; + MWSound::SampleType type; } fmtlist[] = { - { AL_FORMAT_MONO16, ChannelConfig_Mono, SampleType_Int16 }, - { AL_FORMAT_MONO8, ChannelConfig_Mono, SampleType_UInt8 }, - { AL_FORMAT_STEREO16, ChannelConfig_Stereo, SampleType_Int16 }, - { AL_FORMAT_STEREO8, ChannelConfig_Stereo, SampleType_UInt8 }, + { AL_FORMAT_MONO16, MWSound::ChannelConfig_Mono, MWSound::SampleType_Int16 }, + { AL_FORMAT_MONO8, MWSound::ChannelConfig_Mono, MWSound::SampleType_UInt8 }, + { AL_FORMAT_STEREO16, MWSound::ChannelConfig_Stereo, MWSound::SampleType_Int16 }, + { AL_FORMAT_STEREO8, MWSound::ChannelConfig_Stereo, MWSound::SampleType_UInt8 }, + }; + static const struct { + char name[32]; + MWSound::ChannelConfig chans; + MWSound::SampleType type; + } mcfmtlist[] = { + { "AL_FORMAT_QUAD16", MWSound::ChannelConfig_Quad, MWSound::SampleType_Int16 }, + { "AL_FORMAT_QUAD8", MWSound::ChannelConfig_Quad, MWSound::SampleType_UInt8 }, + { "AL_FORMAT_51CHN16", MWSound::ChannelConfig_5point1, MWSound::SampleType_Int16 }, + { "AL_FORMAT_51CHN8", MWSound::ChannelConfig_5point1, MWSound::SampleType_UInt8 }, + { "AL_FORMAT_71CHN16", MWSound::ChannelConfig_7point1, MWSound::SampleType_Int16 }, + { "AL_FORMAT_71CHN8", MWSound::ChannelConfig_7point1, MWSound::SampleType_UInt8 }, + }, fltfmtlist[] = { + { "AL_FORMAT_MONO_FLOAT32", MWSound::ChannelConfig_Mono, MWSound::SampleType_Float32 }, + { "AL_FORMAT_STEREO_FLOAT32", MWSound::ChannelConfig_Stereo, MWSound::SampleType_Float32 }, + }, fltmcfmtlist[] = { + { "AL_FORMAT_QUAD32", MWSound::ChannelConfig_Quad, MWSound::SampleType_Float32 }, + { "AL_FORMAT_51CHN32", MWSound::ChannelConfig_5point1, MWSound::SampleType_Float32 }, + { "AL_FORMAT_71CHN32", MWSound::ChannelConfig_7point1, MWSound::SampleType_Float32 }, }; - static const size_t fmtlistsize = sizeof(fmtlist)/sizeof(fmtlist[0]); - for(size_t i = 0;i < fmtlistsize;i++) + for(size_t i = 0;i < countof(fmtlist);i++) { if(fmtlist[i].chans == chans && fmtlist[i].type == type) return fmtlist[i].format; @@ -72,21 +94,7 @@ static ALenum getALFormat(ChannelConfig chans, SampleType type) if(alIsExtensionPresent("AL_EXT_MCFORMATS")) { - static const struct { - char name[32]; - ChannelConfig chans; - SampleType type; - } mcfmtlist[] = { - { "AL_FORMAT_QUAD16", ChannelConfig_Quad, SampleType_Int16 }, - { "AL_FORMAT_QUAD8", ChannelConfig_Quad, SampleType_UInt8 }, - { "AL_FORMAT_51CHN16", ChannelConfig_5point1, SampleType_Int16 }, - { "AL_FORMAT_51CHN8", ChannelConfig_5point1, SampleType_UInt8 }, - { "AL_FORMAT_71CHN16", ChannelConfig_7point1, SampleType_Int16 }, - { "AL_FORMAT_71CHN8", ChannelConfig_7point1, SampleType_UInt8 }, - }; - static const size_t mcfmtlistsize = sizeof(mcfmtlist)/sizeof(mcfmtlist[0]); - - for(size_t i = 0;i < mcfmtlistsize;i++) + for(size_t i = 0;i < countof(mcfmtlist);i++) { if(mcfmtlist[i].chans == chans && mcfmtlist[i].type == type) { @@ -98,17 +106,7 @@ static ALenum getALFormat(ChannelConfig chans, SampleType type) } if(alIsExtensionPresent("AL_EXT_FLOAT32")) { - static const struct { - char name[32]; - ChannelConfig chans; - SampleType type; - } fltfmtlist[] = { - { "AL_FORMAT_MONO_FLOAT32", ChannelConfig_Mono, SampleType_Float32 }, - { "AL_FORMAT_STEREO_FLOAT32", ChannelConfig_Stereo, SampleType_Float32 }, - }; - static const size_t fltfmtlistsize = sizeof(fltfmtlist)/sizeof(fltfmtlist[0]); - - for(size_t i = 0;i < fltfmtlistsize;i++) + for(size_t i = 0;i < countof(fltfmtlist);i++) { if(fltfmtlist[i].chans == chans && fltfmtlist[i].type == type) { @@ -119,18 +117,7 @@ static ALenum getALFormat(ChannelConfig chans, SampleType type) } if(alIsExtensionPresent("AL_EXT_MCFORMATS")) { - static const struct { - char name[32]; - ChannelConfig chans; - SampleType type; - } fltmcfmtlist[] = { - { "AL_FORMAT_QUAD32", ChannelConfig_Quad, SampleType_Float32 }, - { "AL_FORMAT_51CHN32", ChannelConfig_5point1, SampleType_Float32 }, - { "AL_FORMAT_71CHN32", ChannelConfig_7point1, SampleType_Float32 }, - }; - static const size_t fltmcfmtlistsize = sizeof(fltmcfmtlist)/sizeof(fltmcfmtlist[0]); - - for(size_t i = 0;i < fltmcfmtlistsize;i++) + for(size_t i = 0;i < countof(fltmcfmtlist);i++) { if(fltmcfmtlist[i].chans == chans && fltmcfmtlist[i].type == type) { @@ -142,11 +129,10 @@ static ALenum getALFormat(ChannelConfig chans, SampleType type) } } - fail(std::string("Unsupported sound format (")+getChannelConfigName(chans)+", "+getSampleTypeName(type)+")"); - return AL_NONE; + throw std::runtime_error(std::string("Unsupported sound format (")+MWSound::getChannelConfigName(chans)+", "+MWSound::getSampleTypeName(type)+")"); } -static double getBufferLength(ALuint buffer) +double getBufferLength(ALuint buffer) { ALint bufferSize, frequency, channels, bitsPerSample; alGetBufferi(buffer, AL_SIZE, &bufferSize); @@ -158,6 +144,10 @@ static double getBufferLength(ALuint buffer) return (8.0*bufferSize)/(frequency*channels*bitsPerSample); } +} + +namespace MWSound +{ // // A streaming OpenAL sound. From 04f885d8cc72a36deccbdd5f7c3fe9fa12942a58 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 25 Nov 2015 03:34:44 -0800 Subject: [PATCH 2576/3725] Rename mReferences to mUses --- apps/openmw/mwsound/sound_buffer.hpp | 4 ++-- apps/openmw/mwsound/soundmanagerimp.cpp | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwsound/sound_buffer.hpp b/apps/openmw/mwsound/sound_buffer.hpp index eb67908a2..8f8e43da4 100644 --- a/apps/openmw/mwsound/sound_buffer.hpp +++ b/apps/openmw/mwsound/sound_buffer.hpp @@ -21,10 +21,10 @@ namespace MWSound Sound_Handle mHandle; - size_t mReferences; + size_t mUses; Sound_Buffer(std::string resname, float volume, float mindist, float maxdist) - : mResourceName(resname), mVolume(volume), mMinDist(mindist), mMaxDist(maxdist), mHandle(0), mReferences(0) + : mResourceName(resname), mVolume(volume), mMinDist(mindist), mMaxDist(maxdist), mHandle(0), mUses(0) { } }; } diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 26ba1e210..c7e504770 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -518,7 +518,7 @@ namespace MWSound sound = mOutput->playSound(sfx->mHandle, volume * sfx->mVolume, basevol, pitch, mode|type, offset ); - if(sfx->mReferences++ == 0) + if(sfx->mUses++ == 0) { SoundList::iterator iter = std::find(mUnusedBuffers.begin(), mUnusedBuffers.end(), sfxid); if(iter != mUnusedBuffers.end()) @@ -554,7 +554,7 @@ namespace MWSound sound = mOutput->playSound3D(sfx->mHandle, objpos, volume * sfx->mVolume, basevol, pitch, sfx->mMinDist, sfx->mMaxDist, mode|type, offset ); - if(sfx->mReferences++ == 0) + if(sfx->mUses++ == 0) { SoundList::iterator iter = std::find(mUnusedBuffers.begin(), mUnusedBuffers.end(), sfxid); if(iter != mUnusedBuffers.end()) @@ -585,7 +585,7 @@ namespace MWSound sound = mOutput->playSound3D(sfx->mHandle, initialPos, volume * sfx->mVolume, basevol, pitch, sfx->mMinDist, sfx->mMaxDist, mode|type, offset ); - if(sfx->mReferences++ == 0) + if(sfx->mUses++ == 0) { SoundList::iterator iter = std::find(mUnusedBuffers.begin(), mUnusedBuffers.end(), sfxid); if(iter != mUnusedBuffers.end()) @@ -831,7 +831,7 @@ namespace MWSound if(!updateSound(sndidx->first, snditer->first, duration)) { Sound_Buffer *sfx = &mSoundBuffers[sndidx->second]; - if(sfx->mReferences-- == 1) + if(sfx->mUses-- == 1) mUnusedBuffers.push_front(sndidx->second); sndidx = snditer->second.erase(sndidx); } @@ -1044,7 +1044,7 @@ namespace MWSound { sndidx->first->stop(); Sound_Buffer *sfx = &mSoundBuffers[sndidx->second]; - if(sfx->mReferences-- == 1) + if(sfx->mUses-- == 1) mUnusedBuffers.push_front(sndidx->second); } } From 8f08ca9cbafcce05879e8a254e6888edf3eead12 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 25 Nov 2015 06:06:27 -0800 Subject: [PATCH 2577/3725] Revert "Avoid unsafe sizeof(x)/sizeof(x[0]) constructs for array counting" This reverts commit 0d4fea896c549edb109587d42f9630af1f7816f9. --- apps/openmw/mwsound/openal_output.cpp | 98 +++++++++++++++------------ 1 file changed, 54 insertions(+), 44 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 419bb76b7..bafd272af 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -23,17 +23,13 @@ #define MAKE_PTRID(id) ((void*)(uintptr_t)id) #define GET_PTRID(ptr) ((ALuint)(uintptr_t)ptr) -namespace +namespace MWSound { -template -inline size_t countof(const T(&)[N]) -{ return N; } - -void fail(const std::string &msg) +static void fail(const std::string &msg) { throw std::runtime_error("OpenAL exception: " + msg); } -void throwALCerror(ALCdevice *device) +static void throwALCerror(ALCdevice *device) { ALCenum err = alcGetError(device); if(err != ALC_NO_ERROR) @@ -43,7 +39,7 @@ void throwALCerror(ALCdevice *device) } } -void throwALerror() +static void throwALerror() { ALenum err = alGetError(); if(err != AL_NO_ERROR) @@ -54,39 +50,21 @@ void throwALerror() } -ALenum getALFormat(MWSound::ChannelConfig chans, MWSound::SampleType type) +static ALenum getALFormat(ChannelConfig chans, SampleType type) { static const struct { ALenum format; - MWSound::ChannelConfig chans; - MWSound::SampleType type; + ChannelConfig chans; + SampleType type; } fmtlist[] = { - { AL_FORMAT_MONO16, MWSound::ChannelConfig_Mono, MWSound::SampleType_Int16 }, - { AL_FORMAT_MONO8, MWSound::ChannelConfig_Mono, MWSound::SampleType_UInt8 }, - { AL_FORMAT_STEREO16, MWSound::ChannelConfig_Stereo, MWSound::SampleType_Int16 }, - { AL_FORMAT_STEREO8, MWSound::ChannelConfig_Stereo, MWSound::SampleType_UInt8 }, - }; - static const struct { - char name[32]; - MWSound::ChannelConfig chans; - MWSound::SampleType type; - } mcfmtlist[] = { - { "AL_FORMAT_QUAD16", MWSound::ChannelConfig_Quad, MWSound::SampleType_Int16 }, - { "AL_FORMAT_QUAD8", MWSound::ChannelConfig_Quad, MWSound::SampleType_UInt8 }, - { "AL_FORMAT_51CHN16", MWSound::ChannelConfig_5point1, MWSound::SampleType_Int16 }, - { "AL_FORMAT_51CHN8", MWSound::ChannelConfig_5point1, MWSound::SampleType_UInt8 }, - { "AL_FORMAT_71CHN16", MWSound::ChannelConfig_7point1, MWSound::SampleType_Int16 }, - { "AL_FORMAT_71CHN8", MWSound::ChannelConfig_7point1, MWSound::SampleType_UInt8 }, - }, fltfmtlist[] = { - { "AL_FORMAT_MONO_FLOAT32", MWSound::ChannelConfig_Mono, MWSound::SampleType_Float32 }, - { "AL_FORMAT_STEREO_FLOAT32", MWSound::ChannelConfig_Stereo, MWSound::SampleType_Float32 }, - }, fltmcfmtlist[] = { - { "AL_FORMAT_QUAD32", MWSound::ChannelConfig_Quad, MWSound::SampleType_Float32 }, - { "AL_FORMAT_51CHN32", MWSound::ChannelConfig_5point1, MWSound::SampleType_Float32 }, - { "AL_FORMAT_71CHN32", MWSound::ChannelConfig_7point1, MWSound::SampleType_Float32 }, + { AL_FORMAT_MONO16, ChannelConfig_Mono, SampleType_Int16 }, + { AL_FORMAT_MONO8, ChannelConfig_Mono, SampleType_UInt8 }, + { AL_FORMAT_STEREO16, ChannelConfig_Stereo, SampleType_Int16 }, + { AL_FORMAT_STEREO8, ChannelConfig_Stereo, SampleType_UInt8 }, }; + static const size_t fmtlistsize = sizeof(fmtlist)/sizeof(fmtlist[0]); - for(size_t i = 0;i < countof(fmtlist);i++) + for(size_t i = 0;i < fmtlistsize;i++) { if(fmtlist[i].chans == chans && fmtlist[i].type == type) return fmtlist[i].format; @@ -94,7 +72,21 @@ ALenum getALFormat(MWSound::ChannelConfig chans, MWSound::SampleType type) if(alIsExtensionPresent("AL_EXT_MCFORMATS")) { - for(size_t i = 0;i < countof(mcfmtlist);i++) + static const struct { + char name[32]; + ChannelConfig chans; + SampleType type; + } mcfmtlist[] = { + { "AL_FORMAT_QUAD16", ChannelConfig_Quad, SampleType_Int16 }, + { "AL_FORMAT_QUAD8", ChannelConfig_Quad, SampleType_UInt8 }, + { "AL_FORMAT_51CHN16", ChannelConfig_5point1, SampleType_Int16 }, + { "AL_FORMAT_51CHN8", ChannelConfig_5point1, SampleType_UInt8 }, + { "AL_FORMAT_71CHN16", ChannelConfig_7point1, SampleType_Int16 }, + { "AL_FORMAT_71CHN8", ChannelConfig_7point1, SampleType_UInt8 }, + }; + static const size_t mcfmtlistsize = sizeof(mcfmtlist)/sizeof(mcfmtlist[0]); + + for(size_t i = 0;i < mcfmtlistsize;i++) { if(mcfmtlist[i].chans == chans && mcfmtlist[i].type == type) { @@ -106,7 +98,17 @@ ALenum getALFormat(MWSound::ChannelConfig chans, MWSound::SampleType type) } if(alIsExtensionPresent("AL_EXT_FLOAT32")) { - for(size_t i = 0;i < countof(fltfmtlist);i++) + static const struct { + char name[32]; + ChannelConfig chans; + SampleType type; + } fltfmtlist[] = { + { "AL_FORMAT_MONO_FLOAT32", ChannelConfig_Mono, SampleType_Float32 }, + { "AL_FORMAT_STEREO_FLOAT32", ChannelConfig_Stereo, SampleType_Float32 }, + }; + static const size_t fltfmtlistsize = sizeof(fltfmtlist)/sizeof(fltfmtlist[0]); + + for(size_t i = 0;i < fltfmtlistsize;i++) { if(fltfmtlist[i].chans == chans && fltfmtlist[i].type == type) { @@ -117,7 +119,18 @@ ALenum getALFormat(MWSound::ChannelConfig chans, MWSound::SampleType type) } if(alIsExtensionPresent("AL_EXT_MCFORMATS")) { - for(size_t i = 0;i < countof(fltmcfmtlist);i++) + static const struct { + char name[32]; + ChannelConfig chans; + SampleType type; + } fltmcfmtlist[] = { + { "AL_FORMAT_QUAD32", ChannelConfig_Quad, SampleType_Float32 }, + { "AL_FORMAT_51CHN32", ChannelConfig_5point1, SampleType_Float32 }, + { "AL_FORMAT_71CHN32", ChannelConfig_7point1, SampleType_Float32 }, + }; + static const size_t fltmcfmtlistsize = sizeof(fltmcfmtlist)/sizeof(fltmcfmtlist[0]); + + for(size_t i = 0;i < fltmcfmtlistsize;i++) { if(fltmcfmtlist[i].chans == chans && fltmcfmtlist[i].type == type) { @@ -129,10 +142,11 @@ ALenum getALFormat(MWSound::ChannelConfig chans, MWSound::SampleType type) } } - throw std::runtime_error(std::string("Unsupported sound format (")+MWSound::getChannelConfigName(chans)+", "+MWSound::getSampleTypeName(type)+")"); + fail(std::string("Unsupported sound format (")+getChannelConfigName(chans)+", "+getSampleTypeName(type)+")"); + return AL_NONE; } -double getBufferLength(ALuint buffer) +static double getBufferLength(ALuint buffer) { ALint bufferSize, frequency, channels, bitsPerSample; alGetBufferi(buffer, AL_SIZE, &bufferSize); @@ -144,10 +158,6 @@ double getBufferLength(ALuint buffer) return (8.0*bufferSize)/(frequency*channels*bitsPerSample); } -} - -namespace MWSound -{ // // A streaming OpenAL sound. From ac2eedcb7d944240bb8f35ef179ade8811f3b544 Mon Sep 17 00:00:00 2001 From: cfcohen Date: Wed, 25 Nov 2015 09:24:38 -0500 Subject: [PATCH 2578/3725] Change wording in warning to be clearer. Correct ranges on contrast and gamma. --- files/settings-default.cfg | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/files/settings-default.cfg b/files/settings-default.cfg index f16ef9124..5ed2d688d 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -1,5 +1,6 @@ -# WARNING: Editing this file might have no effect, as these settings -# are overwritten by your user settings file. +# WARNING: If this file is named settings-default.cfg, then editing +# this file might have no effect, as these settings may be overwritten +# by your user settings.cfg file (see docmentation for its location). # # This file provides minimal documentation for each setting, and # ranges of recommended values. For detailed explanations of the @@ -192,10 +193,10 @@ vsync = false # Maximum frames per second. (1.0 to 200.0). framerate limit = 0.0 -# Game video contrast. (0.0 to 1.0). No effect in Linux. +# Game video contrast. (>0.0). No effect in Linux. contrast = 1.0 -# Video gamma setting. (0.0 to 1.0). No effect in Linux. +# Video gamma setting. (>0.0). No effect in Linux. gamma = 1.0 [Water] From 18da95e4f8dd82fb7058b0cb5e17c06259e0961f Mon Sep 17 00:00:00 2001 From: cfcohen Date: Wed, 25 Nov 2015 13:08:53 -0500 Subject: [PATCH 2579/3725] Make openmw-launcher pass comments through settings.cfg, and reuse the Settings::Manager code to do most of the work. Stop loading both the global settings-default.cfg and the one in the current directory, while continuing to prefer the latter one. Cleanup paths slightly and remove what appears to have been debugging in the launcher settings. --- apps/launcher/settings/graphicssettings.cpp | 44 --------------------- apps/launcher/settings/graphicssettings.hpp | 18 --------- 2 files changed, 62 deletions(-) delete mode 100644 apps/launcher/settings/graphicssettings.cpp delete mode 100644 apps/launcher/settings/graphicssettings.hpp diff --git a/apps/launcher/settings/graphicssettings.cpp b/apps/launcher/settings/graphicssettings.cpp deleted file mode 100644 index 9dad3dee6..000000000 --- a/apps/launcher/settings/graphicssettings.cpp +++ /dev/null @@ -1,44 +0,0 @@ -#include "graphicssettings.hpp" - -#include -#include -#include -#include - -Launcher::GraphicsSettings::GraphicsSettings() -{ -} - -Launcher::GraphicsSettings::~GraphicsSettings() -{ -} - -bool Launcher::GraphicsSettings::writeFile(QTextStream &stream) -{ - QString sectionPrefix; - QRegExp sectionRe("([^/]+)/(.+)$"); - QMap settings = SettingsBase::getSettings(); - - QMapIterator i(settings); - while (i.hasNext()) { - i.next(); - - QString prefix; - QString key; - - if (sectionRe.exactMatch(i.key())) { - prefix = sectionRe.cap(1); - key = sectionRe.cap(2); - } - - if (sectionPrefix != prefix) { - sectionPrefix = prefix; - stream << "\n[" << prefix << "]\n"; - } - - stream << key << " = " << i.value() << "\n"; - } - - return true; - -} diff --git a/apps/launcher/settings/graphicssettings.hpp b/apps/launcher/settings/graphicssettings.hpp deleted file mode 100644 index a52e0aa84..000000000 --- a/apps/launcher/settings/graphicssettings.hpp +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef GRAPHICSSETTINGS_HPP -#define GRAPHICSSETTINGS_HPP - -#include - -namespace Launcher -{ - class GraphicsSettings : public Config::SettingsBase > - { - public: - GraphicsSettings(); - ~GraphicsSettings(); - - bool writeFile(QTextStream &stream); - - }; -} -#endif // GRAPHICSSETTINGS_HPP From 67c4b17581850ced0439b2f107dd7b0e0971203a Mon Sep 17 00:00:00 2001 From: cfcohen Date: Wed, 25 Nov 2015 13:17:03 -0500 Subject: [PATCH 2580/3725] Commit files that I thought wre in the previous commit. :-[ I'm accustomed to the hg behavior of commiting all modified files by default. --- apps/launcher/CMakeLists.txt | 4 - apps/launcher/datafilespage.cpp | 2 +- apps/launcher/graphicspage.cpp | 62 ++++++------ apps/launcher/graphicspage.hpp | 6 +- apps/launcher/maindialog.cpp | 125 ++++++++++++------------- apps/launcher/maindialog.hpp | 4 +- apps/openmw/engine.cpp | 6 +- components/config/launchersettings.cpp | 2 - 8 files changed, 102 insertions(+), 109 deletions(-) diff --git a/apps/launcher/CMakeLists.txt b/apps/launcher/CMakeLists.txt index 274239fb0..75f76a532 100644 --- a/apps/launcher/CMakeLists.txt +++ b/apps/launcher/CMakeLists.txt @@ -7,8 +7,6 @@ set(LAUNCHER textslotmsgbox.cpp settingspage.cpp - settings/graphicssettings.cpp - utils/profilescombobox.cpp utils/textinputdialog.cpp utils/lineedit.cpp @@ -24,8 +22,6 @@ set(LAUNCHER_HEADER textslotmsgbox.hpp settingspage.hpp - settings/graphicssettings.hpp - utils/profilescombobox.hpp utils/textinputdialog.hpp utils/lineedit.hpp diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index ec2e1246e..0b0f8c75e 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -75,7 +75,7 @@ bool Launcher::DataFilesPage::loadSettings() QStringList profiles = mLauncherSettings.getContentLists(); QString currentProfile = mLauncherSettings.getCurrentContentListName(); - qDebug() << "current profile is: " << currentProfile; + qDebug() << "The current profile is: " << currentProfile; foreach (const QString &item, profiles) addProfile (item, false); diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index 2128c08f7..a3bfbe5db 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -18,7 +18,7 @@ #include -#include "settings/graphicssettings.hpp" +#include QString getAspect(int x, int y) { @@ -32,10 +32,10 @@ QString getAspect(int x, int y) return QString(QString::number(xaspect) + ":" + QString::number(yaspect)); } -Launcher::GraphicsPage::GraphicsPage(Files::ConfigurationManager &cfg, GraphicsSettings &graphicsSetting, QWidget *parent) +Launcher::GraphicsPage::GraphicsPage(Files::ConfigurationManager &cfg, Settings::Manager &engineSettings, QWidget *parent) : QWidget(parent) , mCfgMgr(cfg) - , mGraphicsSettings(graphicsSetting) + , mEngineSettings(engineSettings) { setObjectName ("GraphicsPage"); setupUi(this); @@ -80,25 +80,26 @@ bool Launcher::GraphicsPage::loadSettings() if (!setupSDL()) return false; - if (mGraphicsSettings.value(QString("Video/vsync")) == QLatin1String("true")) + if (mEngineSettings.getBool("vsync", "Video")) vSyncCheckBox->setCheckState(Qt::Checked); - if (mGraphicsSettings.value(QString("Video/fullscreen")) == QLatin1String("true")) + if (mEngineSettings.getBool("fullscreen", "Video")) fullScreenCheckBox->setCheckState(Qt::Checked); - if (mGraphicsSettings.value(QString("Video/window border")) == QLatin1String("true")) + if (mEngineSettings.getBool("window border", "Video")) windowBorderCheckBox->setCheckState(Qt::Checked); - int aaIndex = antiAliasingComboBox->findText(mGraphicsSettings.value(QString("Video/antialiasing"))); + // aaValue is the actual value (0, 1, 2, 4, 8, 16) + int aaValue = mEngineSettings.getInt("antialiasing", "Video"); + // aaIndex is the index into the allowed values in the pull down. + int aaIndex = antiAliasingComboBox->findText(QString::number(aaValue)); if (aaIndex != -1) antiAliasingComboBox->setCurrentIndex(aaIndex); - QString width = mGraphicsSettings.value(QString("Video/resolution x")); - QString height = mGraphicsSettings.value(QString("Video/resolution y")); - QString resolution = width + QString(" x ") + height; - QString screen = mGraphicsSettings.value(QString("Video/screen")); - - screenComboBox->setCurrentIndex(screen.toInt()); + int width = mEngineSettings.getInt("resolution x", "Video"); + int height = mEngineSettings.getInt("resolution y", "Video"); + QString resolution = QString::number(width) + QString(" x ") + QString::number(height); + screenComboBox->setCurrentIndex(mEngineSettings.getInt("screen", "Video")); int resIndex = resolutionComboBox->findText(resolution, Qt::MatchStartsWith); @@ -107,9 +108,8 @@ bool Launcher::GraphicsPage::loadSettings() resolutionComboBox->setCurrentIndex(resIndex); } else { customRadioButton->toggle(); - customWidthSpinBox->setValue(width.toInt()); - customHeightSpinBox->setValue(height.toInt()); - + customWidthSpinBox->setValue(width); + customHeightSpinBox->setValue(height); } return true; @@ -117,31 +117,29 @@ bool Launcher::GraphicsPage::loadSettings() void Launcher::GraphicsPage::saveSettings() { - vSyncCheckBox->checkState() ? mGraphicsSettings.setValue(QString("Video/vsync"), QString("true")) - : mGraphicsSettings.setValue(QString("Video/vsync"), QString("false")); - - fullScreenCheckBox->checkState() ? mGraphicsSettings.setValue(QString("Video/fullscreen"), QString("true")) - : mGraphicsSettings.setValue(QString("Video/fullscreen"), QString("false")); - - windowBorderCheckBox->checkState() ? mGraphicsSettings.setValue(QString("Video/window border"), QString("true")) - : mGraphicsSettings.setValue(QString("Video/window border"), QString("false")); - - mGraphicsSettings.setValue(QString("Video/antialiasing"), antiAliasingComboBox->currentText()); + mEngineSettings.setBool("vsync", "Video", vSyncCheckBox->checkState()); + mEngineSettings.setBool("fullscreen", "Video", fullScreenCheckBox->checkState()); + mEngineSettings.setBool("window border", "Video", windowBorderCheckBox->checkState()); + // The atoi() call is safe because the pull down constrains the string values. + int aaValue = atoi(antiAliasingComboBox->currentText().toLatin1().data()); + mEngineSettings.setInt("antialiasing", "Video", aaValue); if (standardRadioButton->isChecked()) { QRegExp resolutionRe(QString("(\\d+) x (\\d+).*")); - if (resolutionRe.exactMatch(resolutionComboBox->currentText().simplified())) { - mGraphicsSettings.setValue(QString("Video/resolution x"), resolutionRe.cap(1)); - mGraphicsSettings.setValue(QString("Video/resolution y"), resolutionRe.cap(2)); + // The atoi() call is safe because the pull down constrains the string values. + int width = atoi(resolutionRe.cap(1).toLatin1().data()); + int height = atoi(resolutionRe.cap(2).toLatin1().data()); + mEngineSettings.setInt("resolution x", "Video", width); + mEngineSettings.setInt("resolution y", "Video", height); } } else { - mGraphicsSettings.setValue(QString("Video/resolution x"), QString::number(customWidthSpinBox->value())); - mGraphicsSettings.setValue(QString("Video/resolution y"), QString::number(customHeightSpinBox->value())); + mEngineSettings.setInt("resolution x", "Video", customWidthSpinBox->value()); + mEngineSettings.setInt("resolution y", "Video", customHeightSpinBox->value()); } - mGraphicsSettings.setValue(QString("Video/screen"), QString::number(screenComboBox->currentIndex())); + mEngineSettings.setInt("screen", "Video", screenComboBox->currentIndex()); } QStringList Launcher::GraphicsPage::getAvailableResolutions(int screen) diff --git a/apps/launcher/graphicspage.hpp b/apps/launcher/graphicspage.hpp index fb96c39d7..e6eb53a3b 100644 --- a/apps/launcher/graphicspage.hpp +++ b/apps/launcher/graphicspage.hpp @@ -5,6 +5,8 @@ #include "ui_graphicspage.h" +#include + namespace Files { struct ConfigurationManager; } namespace Launcher @@ -16,7 +18,7 @@ namespace Launcher Q_OBJECT public: - GraphicsPage(Files::ConfigurationManager &cfg, GraphicsSettings &graphicsSettings, QWidget *parent = 0); + GraphicsPage(Files::ConfigurationManager &cfg, Settings::Manager &engineSettings, QWidget *parent = 0); void saveSettings(); bool loadSettings(); @@ -30,7 +32,7 @@ namespace Launcher private: Files::ConfigurationManager &mCfgMgr; - GraphicsSettings &mGraphicsSettings; + Settings::Manager &mEngineSettings; QStringList getAvailableResolutions(int screen); QRect getMaximumResolution(); diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index 9a6f91a0f..1c56a9efd 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -105,7 +105,7 @@ void Launcher::MainDialog::createPages() { mPlayPage = new PlayPage(this); mDataFilesPage = new DataFilesPage(mCfgMgr, mGameSettings, mLauncherSettings, this); - mGraphicsPage = new GraphicsPage(mCfgMgr, mGraphicsSettings, this); + mGraphicsPage = new GraphicsPage(mCfgMgr, mEngineSettings, this); mSettingsPage = new SettingsPage(mCfgMgr, mGameSettings, mLauncherSettings, this); // Set the combobox of the play page to imitate the combobox on the datafilespage @@ -381,55 +381,64 @@ bool Launcher::MainDialog::setupGameSettings() return true; } +void cfgError(const QString& title, const QString& msg) { + QMessageBox msgBox; + msgBox.setWindowTitle(title); + msgBox.setIcon(QMessageBox::Critical); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setText(msg); + msgBox.exec(); +} + bool Launcher::MainDialog::setupGraphicsSettings() { - mGraphicsSettings.setMultiValueEnabled(false); - - QString userPath = QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str()); - QString globalPath = QString::fromUtf8(mCfgMgr.getGlobalPath().string().c_str()); - - QFile localDefault(QString("settings-default.cfg")); - QFile globalDefault(globalPath + QString("settings-default.cfg")); - - if (!localDefault.exists() && !globalDefault.exists()) { - QMessageBox msgBox; - msgBox.setWindowTitle(tr("Error reading OpenMW configuration file")); - msgBox.setIcon(QMessageBox::Critical); - msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(tr("
    Could not find settings-default.cfg

    \ - The problem may be due to an incomplete installation of OpenMW.
    \ - Reinstalling OpenMW may resolve the problem.")); - msgBox.exec(); + // This method is almost a copy of OMW::Engine::loadSettings(). They should definitely + // remain consistent, and possibly be merged into a shared component. At the very least + // the filenames should be in the CfgMgr component. + + // Create the settings manager and load default settings file + const std::string localDefault = mCfgMgr.getLocalPath().string() + "settings-default.cfg"; + const std::string globalDefault = mCfgMgr.getGlobalPath().string() + "settings-default.cfg"; + std::string defaultPath; + + // Prefer the settings-default.cfg in the current directory. + if (boost::filesystem::exists(localDefault)) + defaultPath = localDefault; + else if (boost::filesystem::exists(globalDefault)) + defaultPath = globalDefault; + // Something's very wrong if we can't find the file at all. + else { + cfgError(tr("Error reading OpenMW configuration file"), + tr("
    Could not find settings-default.cfg

    \ + The problem may be due to an incomplete installation of OpenMW.
    \ + Reinstalling OpenMW may resolve the problem.")); return false; } + // Load the default settings, report any parsing errors. + try { + mEngineSettings.loadDefault(defaultPath); + } + catch (std::exception& e) { + std::string msg = "
    Error reading settings-default.cfg

    " + + defaultPath + "

    " + e.what(); + cfgError(tr("Error reading OpenMW configuration file"), tr(msg.c_str())); + return false; + } - QStringList paths; - paths.append(globalPath + QString("settings-default.cfg")); - paths.append(QString("settings-default.cfg")); - paths.append(userPath + QString("settings.cfg")); + // Load user settings if they exist + const std::string userPath = mCfgMgr.getUserConfigPath().string() + "settings.cfg"; + // User settings are not required to exist, so if they don't we're done. + if (!boost::filesystem::exists(userPath)) return true; - foreach (const QString &path, paths) { - qDebug() << "Loading config file:" << qPrintable(path); - QFile file(path); - if (file.exists()) { - if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { - QMessageBox msgBox; - msgBox.setWindowTitle(tr("Error opening OpenMW configuration file")); - msgBox.setIcon(QMessageBox::Critical); - msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(tr("
    Could not open %0 for reading

    \ - Please make sure you have the right permissions \ - and try again.
    ").arg(file.fileName())); - msgBox.exec(); - return false; - } - QTextStream stream(&file); - stream.setCodec(QTextCodec::codecForName("UTF-8")); - - mGraphicsSettings.readFile(stream); - } - file.close(); + try { + mEngineSettings.loadUser(userPath); + } + catch (std::exception& e) { + std::string msg = "
    Error reading settings-default.cfg

    " + + defaultPath + "

    " + e.what(); + cfgError(tr("Error reading OpenMW configuration file"), tr(msg.c_str())); + return false; } return true; @@ -511,27 +520,16 @@ bool Launcher::MainDialog::writeSettings() file.close(); // Graphics settings - file.setFileName(userPath + QString("settings.cfg")); - - if (!file.open(QIODevice::ReadWrite | QIODevice::Text | QIODevice::Truncate)) { - // File cannot be opened or created - QMessageBox msgBox; - msgBox.setWindowTitle(tr("Error writing OpenMW configuration file")); - msgBox.setIcon(QMessageBox::Critical); - msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(tr("
    Could not open or create %0 for writing

    \ - Please make sure you have the right permissions \ - and try again.
    ").arg(file.fileName())); - msgBox.exec(); - return false; + const std::string settingsPath = mCfgMgr.getUserConfigPath().string() + "settings.cfg"; + try { + mEngineSettings.saveUser(settingsPath); + } + catch (std::exception& e) { + std::string msg = "
    Error writing settings.cfg

    " + + settingsPath + "

    " + e.what(); + cfgError(tr("Error reading OpenMW configuration file"), tr(msg.c_str())); + return false; } - - QTextStream stream(&file); - stream.setDevice(&file); - stream.setCodec(QTextCodec::codecForName("UTF-8")); - - mGraphicsSettings.writeFile(stream); - file.close(); // Launcher settings file.setFileName(userPath + QString(Config::LauncherSettings::sLauncherConfigFileName)); @@ -549,6 +547,7 @@ bool Launcher::MainDialog::writeSettings() return false; } + QTextStream stream(&file); stream.setDevice(&file); stream.setCodec(QTextCodec::codecForName("UTF-8")); diff --git a/apps/launcher/maindialog.hpp b/apps/launcher/maindialog.hpp index 298682d20..0dfea4865 100644 --- a/apps/launcher/maindialog.hpp +++ b/apps/launcher/maindialog.hpp @@ -13,7 +13,7 @@ #include #include -#include "settings/graphicssettings.hpp" +#include #include "ui_mainwindow.h" @@ -93,7 +93,7 @@ namespace Launcher Files::ConfigurationManager mCfgMgr; Config::GameSettings mGameSettings; - GraphicsSettings mGraphicsSettings; + Settings::Manager mEngineSettings; Config::LauncherSettings mLauncherSettings; }; diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 031eac800..a4f5f9440 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -298,8 +298,8 @@ void OMW::Engine::setSkipMenu (bool skipMenu, bool newGame) std::string OMW::Engine::loadSettings (Settings::Manager & settings) { // Create the settings manager and load default settings file - const std::string localdefault = mCfgMgr.getLocalPath().string() + "/settings-default.cfg"; - const std::string globaldefault = mCfgMgr.getGlobalPath().string() + "/settings-default.cfg"; + const std::string localdefault = mCfgMgr.getLocalPath().string() + "settings-default.cfg"; + const std::string globaldefault = mCfgMgr.getGlobalPath().string() + "settings-default.cfg"; // prefer local if (boost::filesystem::exists(localdefault)) @@ -310,7 +310,7 @@ std::string OMW::Engine::loadSettings (Settings::Manager & settings) throw std::runtime_error ("No default settings file found! Make sure the file \"settings-default.cfg\" was properly installed."); // load user settings if they exist - const std::string settingspath = mCfgMgr.getUserConfigPath().string() + "/settings.cfg"; + const std::string settingspath = mCfgMgr.getUserConfigPath().string() + "settings.cfg"; if (boost::filesystem::exists(settingspath)) settings.loadUser(settingspath); diff --git a/components/config/launchersettings.cpp b/components/config/launchersettings.cpp index 1d4b428c9..8f3498826 100644 --- a/components/config/launchersettings.cpp +++ b/components/config/launchersettings.cpp @@ -25,8 +25,6 @@ QStringList Config::LauncherSettings::subKeys(const QString &key) QMap settings = SettingsBase::getSettings(); QStringList keys = settings.uniqueKeys(); - qDebug() << keys; - QRegExp keyRe("(.+)/"); QStringList result; From 8a3ec14bc616e897f3bbf22c2e6992ae752c6460 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 25 Nov 2015 19:22:48 +0100 Subject: [PATCH 2581/3725] Revert "Merge remote-tracking branch 'sandstranger/opengles'" This reverts commit cc9cab6fd1531a8df6e44ea34c5843c7e9070ad5, reversing changes made to da856eed9512aa202f93b955552f6f7d8ca7ecd2. --- CMakeLists.txt | 44 ++-- apps/openmw/CMakeLists.txt | 34 +-- apps/openmw/android_main.c | 1 + apps/openmw/main.cpp | 2 +- apps/openmw/mwrender/localmap.cpp | 5 - apps/openmw/mwrender/sky.cpp | 5 - apps/openmw/mwrender/water.cpp | 11 +- cmake/FindOpenGLES.cmake | 94 -------- cmake/FindOpenGLES2.cmake | 170 -------------- components/CMakeLists.txt | 105 ++++----- .../myguiplatform/myguirendermanager.cpp | 4 - components/sdlutil/sdlcursormanager.cpp | 3 - files/shaders/CMakeLists.txt | 20 +- files/shaders/watergles_fragment.glsl | 209 ------------------ files/shaders/watergles_vertex.glsl | 24 -- 15 files changed, 71 insertions(+), 660 deletions(-) delete mode 100644 cmake/FindOpenGLES.cmake delete mode 100644 cmake/FindOpenGLES2.cmake delete mode 100644 files/shaders/watergles_fragment.glsl delete mode 100644 files/shaders/watergles_vertex.glsl diff --git a/CMakeLists.txt b/CMakeLists.txt index ec14d5916..d038936d3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -47,20 +47,8 @@ include(OpenMWMacros) if (ANDROID) set(CMAKE_FIND_ROOT_PATH ${OPENMW_DEPENDENCIES_DIR} "${CMAKE_FIND_ROOT_PATH}") - set(OSG_PLUGINS_DIR ${OSG_PLUGINS_DIR}) - add_definitions (-DOSG_PLUGINS_DIR) - set(OPENGLES TRUE CACHE BOOL "enable opengl es support for android" FORCE) endif (ANDROID) -option(OPENGLES "enable opengl es support" FALSE ) - -if (OPENGLES) - INCLUDE(cmake/FindOpenGLES.cmake) - INCLUDE(cmake/FindOpenGLES2.cmake) - add_definitions (-DOPENGLES) - INCLUDE_DIRECTORIES(${OPENGLES_INCLUDE_DIR}) -endif (OPENGLES) - # doxygen main page configure_file ("${OpenMW_SOURCE_DIR}/docs/mainpage.hpp.cmake" "${OpenMW_BINARY_DIR}/docs/mainpage.hpp") @@ -157,21 +145,21 @@ if (WIN32) endif() # Dependencies -if (NOT ANDROID) - set(DESIRED_QT_VERSION 4 CACHE STRING "The QT version OpenMW should use (4 or 5)") - message(STATUS "Using Qt${DESIRED_QT_VERSION}") - if (DESIRED_QT_VERSION MATCHES 4) - find_package(Qt4 REQUIRED COMPONENTS QtCore QtGui QtNetwork QtOpenGL) - else() - find_package(Qt5Widgets REQUIRED) - find_package(Qt5Core REQUIRED) - find_package(Qt5Network REQUIRED) - find_package(Qt5OpenGL REQUIRED) - # Instruct CMake to run moc automatically when needed. - #set(CMAKE_AUTOMOC ON) - endif() +set(DESIRED_QT_VERSION 4 CACHE STRING "The QT version OpenMW should use (4 or 5)") +message(STATUS "Using Qt${DESIRED_QT_VERSION}") + +if (DESIRED_QT_VERSION MATCHES 4) + find_package(Qt4 REQUIRED COMPONENTS QtCore QtGui QtNetwork QtOpenGL) +else() + find_package(Qt5Widgets REQUIRED) + find_package(Qt5Core REQUIRED) + find_package(Qt5Network REQUIRED) + find_package(Qt5OpenGL REQUIRED) + # Instruct CMake to run moc automatically when needed. + #set(CMAKE_AUTOMOC ON) endif() + # Fix for not visible pthreads functions for linker with glibc 2.15 if (UNIX AND NOT APPLE) find_package (Threads) @@ -201,11 +189,7 @@ IF(BOOST_STATIC) set(Boost_USE_STATIC_LIBS ON) endif() -if (NOT ANDROID) - find_package(OpenSceneGraph 3.2.0 REQUIRED osgDB osgViewer osgText osgGA osgAnimation osgParticle osgQt osgUtil osgFX) -else() - find_package(OpenSceneGraph 3.2.0 REQUIRED osgDB osgViewer osgText osgGA osgAnimation osgParticle osgUtil osgFX) -endif() +find_package(OpenSceneGraph 3.2.0 REQUIRED osgDB osgViewer osgText osgGA osgAnimation osgParticle osgQt osgUtil osgFX) include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS}) if(OSG_STATIC) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 1f0fe71ab..59a523023 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -134,50 +134,18 @@ target_link_libraries(openmw ) if (ANDROID) - set (OSG_PLUGINS - -Wl,--whole-archive - ${OSG_PLUGINS_DIR}/libosgdb_dds.a - ${OSG_PLUGINS_DIR}/libosgdb_bmp.a - ${OSG_PLUGINS_DIR}/libosgdb_tga.a - ${OSG_PLUGINS_DIR}/libosgdb_gif.a - ${OSG_PLUGINS_DIR}/libosgdb_jpeg.a - ${OSG_PLUGINS_DIR}/libosgdb_png.a - -Wl,--no-whole-archive - ) target_link_libraries(openmw EGL android log dl MyGUIEngineStatic + cpufeatures BulletCollision LinearMath - z - osg - osgDB - osgAnimation - osgText - osgUtil - osgShadow - ${OPENSCENEGRAPH_LIBRARIES} - ${OSG_PLUGINS} - ${Boost_SYSTEM_LIBRARY} - ${Boost_THREAD_LIBRARY} - ${Boost_FILESYSTEM_LIBRARY} - ${Boost_PROGRAM_OPTIONS_LIBRARY} - jpeg - gif - png ) endif (ANDROID) -if (OPENGLES) - target_link_libraries(openmw - ${OPENGLES_gl_LIBRARY} - ${OPENGLES2_gl_LIBRARY} - ) -endif (OPENGLES) - if (USE_SYSTEM_TINYXML) target_link_libraries(openmw ${TINYXML_LIBRARIES}) endif() diff --git a/apps/openmw/android_main.c b/apps/openmw/android_main.c index 8cd69e8f0..47b77a8b3 100644 --- a/apps/openmw/android_main.c +++ b/apps/openmw/android_main.c @@ -1,3 +1,4 @@ +#include "../../SDL_internal.h" #ifdef __ANDROID__ #include "SDL_main.h" diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index c3f0f8688..17ef46246 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -23,7 +23,7 @@ #endif -#if (defined(__APPLE__) || (defined(__linux) && !defined(ANDROID)) || (defined(__unix) && !defined(ANDROID)) || defined(__posix)) +#if (defined(__APPLE__) || defined(__linux) || defined(__unix) || defined(__posix)) #define USE_CRASH_CATCHER 1 #else #define USE_CRASH_CATCHER 0 diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 077d21512..14ec770e8 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -24,11 +24,6 @@ #include "vismask.hpp" -#ifdef OPENGLES - #include -#endif - - namespace { diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 7572d7e92..66253f70d 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -45,11 +45,6 @@ #include "vismask.hpp" #include "renderbin.hpp" -#ifdef OPENGLES - #include -#endif - - namespace { diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 5a9bc664a..ca099991e 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -40,10 +40,6 @@ #include "ripplesimulation.hpp" #include "renderbin.hpp" -#ifdef OPENGLES -#include -#endif - namespace { @@ -579,13 +575,10 @@ void Water::createShaderWaterStateSet(osg::Node* node, Reflection* reflection, R // use a define map to conditionally compile the shader std::map defineMap; defineMap.insert(std::make_pair(std::string("@refraction_enabled"), std::string(refraction ? "1" : "0"))); -#ifdef OPENGLES - osg::ref_ptr vertexShader (readShader(osg::Shader::VERTEX, mResourcePath + "/shaders/watergles_vertex.glsl", defineMap)); - osg::ref_ptr fragmentShader (readShader(osg::Shader::FRAGMENT, mResourcePath + "/shaders/watergles_fragment.glsl", defineMap)); -#else + osg::ref_ptr vertexShader (readShader(osg::Shader::VERTEX, mResourcePath + "/shaders/water_vertex.glsl", defineMap)); osg::ref_ptr fragmentShader (readShader(osg::Shader::FRAGMENT, mResourcePath + "/shaders/water_fragment.glsl", defineMap)); -#endif + osg::ref_ptr normalMap (new osg::Texture2D(readPngImage(mResourcePath + "/shaders/water_nm.png"))); normalMap->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT); normalMap->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT); diff --git a/cmake/FindOpenGLES.cmake b/cmake/FindOpenGLES.cmake deleted file mode 100644 index 7ee2c07f1..000000000 --- a/cmake/FindOpenGLES.cmake +++ /dev/null @@ -1,94 +0,0 @@ -#------------------------------------------------------------------- -# This file is part of the CMake build system for OGRE -# (Object-oriented Graphics Rendering Engine) -# For the latest info, see http://www.ogre3d.org/ -# -# The contents of this file are placed in the public domain. Feel -# free to make use of it in any way you like. -#------------------------------------------------------------------- - -# - Try to find OpenGLES -# Once done this will define -# -# OPENGLES_FOUND - system has OpenGLES -# OPENGLES_INCLUDE_DIR - the GL include directory -# OPENGLES_LIBRARIES - Link these to use OpenGLES - -IF (WIN32) - IF (CYGWIN) - - FIND_PATH(OPENGLES_INCLUDE_DIR GLES/gl.h ) - - FIND_LIBRARY(OPENGLES_gl_LIBRARY libgles_cm ) - - ELSE (CYGWIN) - - IF(BORLAND) - SET (OPENGLES_gl_LIBRARY import32 CACHE STRING "OpenGL ES 1.x library for win32") - ELSE(BORLAND) - #MS compiler - todo - fix the following line: - SET (OPENGLES_gl_LIBRARY ${OGRE_SOURCE_DIR}/Dependencies/lib/release/libgles_cm.lib CACHE STRING "OpenGL ES 1.x library for win32") - ENDIF(BORLAND) - - ENDIF (CYGWIN) - -ELSE (WIN32) - - IF (APPLE) - - #create_search_paths(/Developer/Platforms) - #findpkg_framework(OpenGLES) - #set(OPENGLES_gl_LIBRARY "-framework OpenGLES") - - ELSE(APPLE) - - FIND_PATH(OPENGLES_INCLUDE_DIR GLES/gl.h - /opt/vc/include - /opt/graphics/OpenGL/include - /usr/openwin/share/include - /usr/X11R6/include - /usr/include - ) - - FIND_LIBRARY(OPENGLES_gl_LIBRARY - NAMES GLES_CM GLESv1_CM - PATHS /opt/vc/lib - /opt/graphics/OpenGL/lib - /usr/openwin/lib - /usr/shlib /usr/X11R6/lib - /usr/lib - ) - - # On Unix OpenGL most certainly always requires X11. - # Feel free to tighten up these conditions if you don't - # think this is always true. - - #IF (OPENGLES_gl_LIBRARY) - # IF(NOT X11_FOUND) - # INCLUDE(FindX11) - # ENDIF(NOT X11_FOUND) - # IF (X11_FOUND) - # SET (OPENGLES_LIBRARIES ${X11_LIBRARIES}) - # ENDIF (X11_FOUND) - #ENDIF (OPENGLES_gl_LIBRARY) - - ENDIF(APPLE) -ENDIF (WIN32) - -SET( OPENGLES_FOUND "NO" ) -IF(OPENGLES_gl_LIBRARY) - - SET( OPENGLES_LIBRARIES ${OPENGLES_gl_LIBRARY} ${OPENGLES_LIBRARIES}) - - SET( OPENGLES_FOUND "YES" ) - -ENDIF(OPENGLES_gl_LIBRARY) - -MARK_AS_ADVANCED( - OPENGLES_INCLUDE_DIR - OPENGLES_gl_LIBRARY -) - -INCLUDE(FindPackageHandleStandardArgs) - -FIND_PACKAGE_HANDLE_STANDARD_ARGS(OPENGLES REQUIRED_VARS OPENGLES_LIBRARIES OPENGLES_INCLUDE_DIR) diff --git a/cmake/FindOpenGLES2.cmake b/cmake/FindOpenGLES2.cmake deleted file mode 100644 index 136e7618b..000000000 --- a/cmake/FindOpenGLES2.cmake +++ /dev/null @@ -1,170 +0,0 @@ -#------------------------------------------------------------------- -# This file is part of the CMake build system for OGRE -# (Object-oriented Graphics Rendering Engine) -# For the latest info, see http://www.ogre3d.org/ -# -# The contents of this file are placed in the public domain. Feel -# free to make use of it in any way you like. -#------------------------------------------------------------------- - -# - Try to find OpenGLES and EGL -# If using ARM Mali emulation you can specify the parent directory that contains the bin and include directories by -# setting the MALI_SDK_ROOT variable in the environment. -# -# For AMD emulation use the AMD_SDK_ROOT variable -# -# Once done this will define -# -# OPENGLES2_FOUND - system has OpenGLES -# OPENGLES2_INCLUDE_DIR - the GL include directory -# OPENGLES2_LIBRARIES - Link these to use OpenGLES -# -# EGL_FOUND - system has EGL -# EGL_INCLUDE_DIR - the EGL include directory -# EGL_LIBRARIES - Link these to use EGL - -#include(FindPkgMacros) - -IF (WIN32) - IF (CYGWIN) - - FIND_PATH(OPENGLES2_INCLUDE_DIR GLES2/gl2.h ) - - FIND_LIBRARY(OPENGLES2_gl_LIBRARY libGLESv2 ) - - ELSE (CYGWIN) - - IF(BORLAND) - SET (OPENGLES2_gl_LIBRARY import32 CACHE STRING "OpenGL ES 2.x library for win32") - ELSE(BORLAND) - #getenv_path(AMD_SDK_ROOT) - #getenv_path(MALI_SDK_ROOT) - - SET(POWERVR_SDK_PATH "C:/Imagination/PowerVR/GraphicsSDK/SDK_3.1/Builds") - FIND_PATH(OPENGLES2_INCLUDE_DIR GLES2/gl2.h - ${ENV_AMD_SDK_ROOT}/include - ${ENV_MALI_SDK_ROOT}/include - ${POWERVR_SDK_PATH}/Include - "C:/Imagination Technologies/PowerVR Insider SDK/OGLES2_WINDOWS_X86EMULATION_2.10/Builds/OGLES2/Include" - ) - - FIND_PATH(EGL_INCLUDE_DIR EGL/egl.h - ${ENV_AMD_SDK_ROOT}/include - ${ENV_MALI_SDK_ROOT}/include - ${POWERVR_SDK_PATH}/Include - "C:/Imagination Technologies/PowerVR Insider SDK/OGLES2_WINDOWS_X86EMULATION_2.10/Builds/OGLES2/Include" - ) - - FIND_LIBRARY(OPENGLES2_gl_LIBRARY - NAMES libGLESv2 - PATHS ${ENV_AMD_SDK_ROOT}/x86 - ${ENV_MALI_SDK_ROOT}/bin - ${POWERVR_SDK_PATH}/Windows/x86_32/Lib - "C:/Imagination Technologies/PowerVR Insider SDK/OGLES2_WINDOWS_X86EMULATION_2.10/Builds/OGLES2/WindowsX86/Lib" - ) - - FIND_LIBRARY(EGL_egl_LIBRARY - NAMES libEGL - PATHS ${ENV_AMD_SDK_ROOT}/x86 - ${ENV_MALI_SDK_ROOT}/bin - ${POWERVR_SDK_PATH}/Windows/x86_32/Lib - "C:/Imagination Technologies/PowerVR Insider SDK/OGLES2_WINDOWS_X86EMULATION_2.10/Builds/OGLES2/WindowsX86/Lib" - ) - ENDIF(BORLAND) - - ENDIF (CYGWIN) - -ELSE (WIN32) - - IF (APPLE) - - #create_search_paths(/Developer/Platforms) - #findpkg_framework(OpenGLES2) - #set(OPENGLES2_gl_LIBRARY "-framework OpenGLES") - - ELSE(APPLE) - #getenv_path(AMD_SDK_ROOT) - #getenv_path(MALI_SDK_ROOT) - - FIND_PATH(OPENGLES2_INCLUDE_DIR GLES2/gl2.h - ${ENV_AMD_SDK_ROOT}/include - ${ENV_MALI_SDK_ROOT}/include - /opt/Imagination/PowerVR/GraphicsSDK/SDK_3.1/Builds/Include - /opt/vc/include - /usr/openwin/share/include - /opt/graphics/OpenGL/include /usr/X11R6/include - /usr/include - ) - - FIND_LIBRARY(OPENGLES2_gl_LIBRARY - NAMES GLESv2 - PATHS ${ENV_AMD_SDK_ROOT}/x86 - ${ENV_MALI_SDK_ROOT}/bin - /opt/Imagination/PowerVR/GraphicsSDK/SDK_3.1/Builds/Linux/x86_32/Lib - /opt/vc/lib - /opt/graphics/OpenGL/lib - /usr/openwin/lib - /usr/shlib /usr/X11R6/lib - /usr/lib - ) - - FIND_PATH(EGL_INCLUDE_DIR EGL/egl.h - ${ENV_AMD_SDK_ROOT}/include - ${ENV_MALI_SDK_ROOT}/include - /opt/Imagination/PowerVR/GraphicsSDK/SDK_3.1/Builds/Include - /opt/vc/include - /usr/openwin/share/include - /opt/graphics/OpenGL/include /usr/X11R6/include - /usr/include - ) - - FIND_LIBRARY(EGL_egl_LIBRARY - NAMES EGL - PATHS ${ENV_AMD_SDK_ROOT}/x86 - ${ENV_MALI_SDK_ROOT}/bin - /opt/Imagination/PowerVR/GraphicsSDK/SDK_3.1/Builds/Linux/x86_32/Lib - /opt/vc/lib - /opt/graphics/OpenGL/lib - /usr/openwin/lib - /usr/shlib /usr/X11R6/lib - /usr/lib - ) - - # On Unix OpenGL most certainly always requires X11. - # Feel free to tighten up these conditions if you don't - # think this is always true. - # It's not true on OSX. - - #IF (OPENGLES2_gl_LIBRARY) - # IF(NOT X11_FOUND) - # INCLUDE(FindX11) - # ENDIF(NOT X11_FOUND) - # IF (X11_FOUND) - # IF (NOT APPLE) - # SET (OPENGLES2_LIBRARIES ${X11_LIBRARIES}) - # ENDIF (NOT APPLE) - # ENDIF (X11_FOUND) - #ENDIF (OPENGLES2_gl_LIBRARY) - - ENDIF(APPLE) -ENDIF (WIN32) - -SET( OPENGLES2_FOUND "YES" ) -IF(OPENGLES2_gl_LIBRARY AND EGL_egl_LIBRARY) - - SET( OPENGLES2_LIBRARIES ${OPENGLES2_gl_LIBRARY} ${OPENGLES2_LIBRARIES}) - SET( EGL_LIBRARIES ${EGL_egl_LIBRARY} ${EGL_LIBRARIES}) - SET( OPENGLES2_FOUND "YES" ) - -ENDIF(OPENGLES2_gl_LIBRARY AND EGL_egl_LIBRARY) - -MARK_AS_ADVANCED( - OPENGLES2_INCLUDE_DIR - OPENGLES2_gl_LIBRARY - EGL_INCLUDE_DIR - EGL_egl_LIBRARY -) - -INCLUDE(FindPackageHandleStandardArgs) - -FIND_PACKAGE_HANDLE_STANDARD_ARGS(OPENGLES2 REQUIRED_VARS OPENGLES2_LIBRARIES OPENGLES2_INCLUDE_DIR) diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 7bfbf6d93..c80e27e4d 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -20,9 +20,8 @@ else (GIT_CHECKOUT) configure_file(${VERSION_IN_FILE} ${VERSION_FILE}) endif (GIT_CHECKOUT) -if (NOT ANDROID) - find_package(OpenGL REQUIRED) -endif() +find_package(OpenGL REQUIRED) + # source files add_component_dir (settings @@ -138,31 +137,31 @@ add_component_dir (version set (ESM_UI ${CMAKE_SOURCE_DIR}/files/ui/contentselector.ui ) -if (NOT ANDROID) - add_component_qt_dir (contentselector - model/modelitem model/esmfile - model/naturalsort model/contentmodel - model/loadordererror - view/combobox view/contentselector - ) - add_component_qt_dir (config - gamesettings - launchersettings - settingsbase - ) - - add_component_qt_dir (process - processinvoker - ) - if (DESIRED_QT_VERSION MATCHES 4) - include(${QT_USE_FILE}) - QT4_WRAP_UI(ESM_UI_HDR ${ESM_UI}) - QT4_WRAP_CPP(MOC_SRCS ${COMPONENT_MOC_FILES}) - else() - QT5_WRAP_UI(ESM_UI_HDR ${ESM_UI}) - QT5_WRAP_CPP(MOC_SRCS ${COMPONENT_MOC_FILES}) - endif() +add_component_qt_dir (contentselector + model/modelitem model/esmfile + model/naturalsort model/contentmodel + model/loadordererror + view/combobox view/contentselector + ) +add_component_qt_dir (config + gamesettings + launchersettings + settingsbase + ) + +add_component_qt_dir (process + processinvoker +) + +if (DESIRED_QT_VERSION MATCHES 4) + include(${QT_USE_FILE}) + QT4_WRAP_UI(ESM_UI_HDR ${ESM_UI}) + QT4_WRAP_CPP(MOC_SRCS ${COMPONENT_MOC_FILES}) +else() + QT5_WRAP_UI(ESM_UI_HDR ${ESM_UI}) + QT5_WRAP_CPP(MOC_SRCS ${COMPONENT_MOC_FILES}) endif() + if (CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") if("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "x86_64" AND NOT APPLE) add_definitions(-fPIC) @@ -173,46 +172,32 @@ include_directories(${BULLET_INCLUDE_DIRS} ${CMAKE_CURRENT_BINARY_DIR}) add_library(components STATIC ${COMPONENT_FILES} ${MOC_SRCS} ${ESM_UI_HDR}) -if (NOT ANDROID) - target_link_libraries(components - ${Boost_SYSTEM_LIBRARY} - ${Boost_FILESYSTEM_LIBRARY} - ${Boost_THREAD_LIBRARY} - ${Boost_PROGRAM_OPTIONS_LIBRARY} - ${OPENSCENEGRAPH_LIBRARIES} - ${BULLET_LIBRARIES} - ${SDL2_LIBRARY} - # For MyGUI platform - ${OPENGL_gl_LIBRARY} - ${MYGUI_LIBRARIES} - ) -else() - target_link_libraries(components - ${Boost_SYSTEM_LIBRARY} - ${Boost_FILESYSTEM_LIBRARY} - ${Boost_THREAD_LIBRARY} - ${Boost_PROGRAM_OPTIONS_LIBRARY} - ${OPENSCENEGRAPH_LIBRARIES} - ${BULLET_LIBRARIES} - ${SDL2_LIBRARY} - ${MYGUI_LIBRARIES} - ) -endif() +target_link_libraries(components + ${Boost_SYSTEM_LIBRARY} + ${Boost_FILESYSTEM_LIBRARY} + ${Boost_THREAD_LIBRARY} + ${Boost_PROGRAM_OPTIONS_LIBRARY} + ${OPENSCENEGRAPH_LIBRARIES} + ${BULLET_LIBRARIES} + ${SDL2_LIBRARY} + # For MyGUI platform + ${OPENGL_gl_LIBRARY} + ${MYGUI_LIBRARIES} +) if (WIN32) target_link_libraries(components ${Boost_LOCALE_LIBRARY}) endif() -if (NOT ANDROID) - if (DESIRED_QT_VERSION MATCHES 4) - target_link_libraries(components - ${QT_QTCORE_LIBRARY} - ${QT_QTGUI_LIBRARY}) - else() - qt5_use_modules(components Widgets Core) - endif() +if (DESIRED_QT_VERSION MATCHES 4) + target_link_libraries(components + ${QT_QTCORE_LIBRARY} + ${QT_QTGUI_LIBRARY}) +else() + qt5_use_modules(components Widgets Core) endif() + if (GIT_CHECKOUT) add_dependencies (components git-version) endif (GIT_CHECKOUT) diff --git a/components/myguiplatform/myguirendermanager.cpp b/components/myguiplatform/myguirendermanager.cpp index 5fb3054a6..5bd56dc8f 100644 --- a/components/myguiplatform/myguirendermanager.cpp +++ b/components/myguiplatform/myguirendermanager.cpp @@ -17,10 +17,6 @@ #include #include "myguitexture.hpp" - -#ifdef OPENGLES - #include -#endif #define MYGUI_PLATFORM_LOG_SECTION "Platform" #define MYGUI_PLATFORM_LOG(level, text) MYGUI_LOGGING(MYGUI_PLATFORM_LOG_SECTION, level, text) diff --git a/components/sdlutil/sdlcursormanager.cpp b/components/sdlutil/sdlcursormanager.cpp index 23f01f3a7..e1a67aff8 100644 --- a/components/sdlutil/sdlcursormanager.cpp +++ b/components/sdlutil/sdlcursormanager.cpp @@ -217,9 +217,6 @@ namespace SDLUtil void SDLCursorManager::_createCursorFromResource(const std::string& name, int rotDegrees, osg::Image* image, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y) { - #ifdef ANDROID - return; - #endif if (mCursorMap.find(name) != mCursorMap.end()) return; diff --git a/files/shaders/CMakeLists.txt b/files/shaders/CMakeLists.txt index da2550275..fc4706c1f 100644 --- a/files/shaders/CMakeLists.txt +++ b/files/shaders/CMakeLists.txt @@ -1,17 +1,11 @@ # Copy resource files into the build directory set(SDIR ${CMAKE_CURRENT_SOURCE_DIR}) set(DDIR ${OpenMW_BINARY_DIR}/resources/shaders) -if (OPENGLES) - set(SHADER_FILES - watergles_vertex.glsl - watergles_fragment.glsl - water_nm.png - ) -else() - set(SHADER_FILES - water_vertex.glsl - water_fragment.glsl - water_nm.png - ) -endif() + +set(SHADER_FILES + water_vertex.glsl + water_fragment.glsl + water_nm.png +) + copy_all_files(${CMAKE_CURRENT_SOURCE_DIR} ${DDIR} "${SHADER_FILES}") diff --git a/files/shaders/watergles_fragment.glsl b/files/shaders/watergles_fragment.glsl deleted file mode 100644 index e3f756087..000000000 --- a/files/shaders/watergles_fragment.glsl +++ /dev/null @@ -1,209 +0,0 @@ -#version 100 -precision mediump float; -precision mediump int; - -struct osg_LightSourceParameters { - mediump vec4 ambient; - mediump vec4 diffuse; - mediump vec4 specular; - mediump vec4 position; - mediump vec4 halfVector; - mediump vec3 spotDirection; - mediump float spotExponent; - mediump float spotCutoff; - mediump float spotCosCutoff; - mediump float constantAttenuation; - mediump float linearAttenuation; - mediump float quadraticAttenuation; - }; -uniform osg_LightSourceParameters osg_LightSource[1]; - -#define REFRACTION @refraction_enabled - -// Inspired by Blender GLSL Water by martinsh ( http://devlog-martinsh.blogspot.de/2012/07/waterundewater-shader-wip.html ) - -// tweakables -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - -const float VISIBILITY = 1200.0; // how far you can look through water - -const float BIG_WAVES_X = 0.1; // strength of big waves -const float BIG_WAVES_Y = 0.1; - -const float MID_WAVES_X = 0.1; // strength of middle sized waves -const float MID_WAVES_Y = 0.1; - -const float SMALL_WAVES_X = 0.1; // strength of small waves -const float SMALL_WAVES_Y = 0.1; - -const float WAVE_CHOPPYNESS = 0.05; // wave choppyness -const float WAVE_SCALE = 75.0; // overall wave scale - -const float BUMP = 0.5; // overall water surface bumpiness -const float REFL_BUMP = 0.10; // reflection distortion amount -const float REFR_BUMP = 0.07; // refraction distortion amount - -const float SCATTER_AMOUNT = 0.3; // amount of sunlight scattering -const vec3 SCATTER_COLOUR = vec3(0.0,1.0,0.95); // colour of sunlight scattering - -const vec3 SUN_EXT = vec3(0.45, 0.55, 0.68); //sunlight extinction - -const float SPEC_HARDNESS = 256.0; // specular highlights hardness - -const vec2 WIND_DIR = vec2(0.5, -0.8); -const float WIND_SPEED = 0.2; - -const vec3 WATER_COLOR = vec3(0.090195, 0.115685, 0.12745); - -// -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - - -float fresnel_dielectric(vec3 Incoming, vec3 Normal, float eta) -{ - float c = abs(dot(Incoming, Normal)); - float g = eta * eta - 1.0 + c * c; - float result; - - if(g > 0.0) { - g = sqrt(g); - float A =(g - c)/(g + c); - float B =(c *(g + c)- 1.0)/(c *(g - c)+ 1.0); - result = 0.5 * A * A *(1.0 + B * B); - } - else - result = 1.0; - - return result; -} - -varying vec3 screenCoordsPassthrough; -varying vec4 position; -varying float depthPassthrough; - -uniform sampler2D normalMap; - -uniform sampler2D reflectionMap; -#if REFRACTION -uniform sampler2D refractionMap; -uniform sampler2D refractionDepthMap; -#endif - -uniform float osg_SimulationTime; - -uniform float near; -uniform float far; -uniform vec3 nodePosition; - -void main(void) -{ - vec3 worldPos = position.xyz + nodePosition.xyz; - vec2 UV = worldPos.xy / (8192.0*5.0) * 3.0; - UV.y *= -1.0; - - float shadow = 1.0; - - vec2 screenCoords = screenCoordsPassthrough.xy / screenCoordsPassthrough.z; - screenCoords.y = (1.0-screenCoords.y); - - vec2 nCoord = vec2(0.0,0.0); - - #define waterTimer osg_SimulationTime - - nCoord = UV * (WAVE_SCALE * 0.05) + WIND_DIR * waterTimer * (WIND_SPEED*0.04); - vec3 normal0 = 2.0 * texture2D(normalMap, nCoord + vec2(-waterTimer*0.015,-waterTimer*0.005)).rgb - 1.0; - nCoord = UV * (WAVE_SCALE * 0.1) + WIND_DIR * waterTimer * (WIND_SPEED*0.08)-(normal0.xy/normal0.zz)*WAVE_CHOPPYNESS; - vec3 normal1 = 2.0 * texture2D(normalMap, nCoord + vec2(+waterTimer*0.020,+waterTimer*0.015)).rgb - 1.0; - - nCoord = UV * (WAVE_SCALE * 0.25) + WIND_DIR * waterTimer * (WIND_SPEED*0.07)-(normal1.xy/normal1.zz)*WAVE_CHOPPYNESS; - vec3 normal2 = 2.0 * texture2D(normalMap, nCoord + vec2(-waterTimer*0.04,-waterTimer*0.03)).rgb - 1.0; - nCoord = UV * (WAVE_SCALE * 0.5) + WIND_DIR * waterTimer * (WIND_SPEED*0.09)-(normal2.xy/normal2.z)*WAVE_CHOPPYNESS; - vec3 normal3 = 2.0 * texture2D(normalMap, nCoord + vec2(+waterTimer*0.03,+waterTimer*0.04)).rgb - 1.0; - - nCoord = UV * (WAVE_SCALE* 1.0) + WIND_DIR * waterTimer * (WIND_SPEED*0.4)-(normal3.xy/normal3.zz)*WAVE_CHOPPYNESS; - vec3 normal4 = 2.0 * texture2D(normalMap, nCoord + vec2(-waterTimer*0.02,+waterTimer*0.1)).rgb - 1.0; - nCoord = UV * (WAVE_SCALE * 2.0) + WIND_DIR * waterTimer * (WIND_SPEED*0.7)-(normal4.xy/normal4.zz)*WAVE_CHOPPYNESS; - vec3 normal5 = 2.0 * texture2D(normalMap, nCoord + vec2(+waterTimer*0.1,-waterTimer*0.06)).rgb - 1.0; - - - - vec3 normal = (normal0 * BIG_WAVES_X + normal1 * BIG_WAVES_Y + - normal2 * MID_WAVES_X + normal3 * MID_WAVES_Y + - normal4 * SMALL_WAVES_X + normal5 * SMALL_WAVES_Y); - - normal = normalize(vec3(normal.x * BUMP, normal.y * BUMP, normal.z)); - - normal = vec3(-normal.x, -normal.y, normal.z); - - // normal for sunlight scattering - vec3 lNormal = (normal0 * BIG_WAVES_X*0.5 + normal1 * BIG_WAVES_Y*0.5 + - normal2 * MID_WAVES_X*0.2 + normal3 * MID_WAVES_Y*0.2 + - normal4 * SMALL_WAVES_X*0.1 + normal5 * SMALL_WAVES_Y*0.1).xyz; - lNormal = normalize(vec3(lNormal.x * BUMP, lNormal.y * BUMP, lNormal.z)); - lNormal = vec3(-lNormal.x, -lNormal.y, lNormal.z); - - - vec3 lVec = normalize((gl_ModelViewMatrixInverse * vec4(osg_LightSource[0].position.xyz, 0.0)).xyz); - - vec3 cameraPos = (gl_ModelViewMatrixInverse * vec4(0.0,0.0,0.0,1.0)).xyz; - vec3 vVec = normalize(position.xyz - cameraPos.xyz); - - float isUnderwater = (cameraPos.z > 0.0) ? 0.0 : 1.0; - - // sunlight scattering - vec3 pNormal = vec3(0.0,0.0,1.0); - vec3 lR = reflect(lVec, lNormal); - vec3 llR = reflect(lVec, pNormal); - - float sunHeight = lVec.z; - float sunFade = length(gl_LightModel.ambient.xyz); - - float s = clamp(dot(lR, vVec)*2.0-1.2, 0.0, 1.0); - float lightScatter = shadow * clamp(dot(lVec,lNormal)*0.7+0.3, 0.0, 1.0) * s * SCATTER_AMOUNT * sunFade * clamp(1.0-exp(-sunHeight), 0.0, 1.0); - vec3 scatterColour = mix(vec3(SCATTER_COLOUR)*vec3(1.0,0.4,0.0), SCATTER_COLOUR, clamp(1.0-exp(-sunHeight*SUN_EXT), 0.0, 1.0)); - - // fresnel - float ior = (cameraPos.z>0.0)?(1.333/1.0):(1.0/1.333); //air to water; water to air - float fresnel = fresnel_dielectric(vVec, normal, ior); - - fresnel = clamp(fresnel, 0.0, 1.0); - - // reflection - vec3 reflection = texture2D(reflectionMap, screenCoords+(normal.xy*REFL_BUMP)).rgb; - - // refraction -#if REFRACTION - vec3 refraction = texture2D(refractionMap, screenCoords-(normal.xy*REFR_BUMP)).rgb; - - // brighten up the refraction underwater - refraction = (cameraPos.z < 0.0) ? clamp(refraction * 1.5, 0.0, 1.0) : refraction; -#endif - - // specular - vec3 R = reflect(vVec, normal); - float specular = pow(max(dot(R, lVec), 0.0),SPEC_HARDNESS) * shadow; - - vec3 waterColor = WATER_COLOR; - waterColor = waterColor * length(gl_LightModel.ambient.xyz); -#if REFRACTION - float refractionDepth = texture2D(refractionDepthMap, screenCoords-(normal.xy*REFR_BUMP)).x; - float z_n = 2.0 * refractionDepth - 1.0; - refractionDepth = 2.0 * near * far / (far + near - z_n * (far - near)); - - float waterDepth = refractionDepth - depthPassthrough; - - if (cameraPos.z > 0.0) - refraction = mix(refraction, waterColor, clamp(waterDepth/VISIBILITY, 0.0, 1.0)); - - gl_FragData[0].xyz = mix( mix(refraction, scatterColour, lightScatter), reflection, fresnel) + specular * osg_LightSource[0].specular.xyz; -#else - gl_FragData[0].xyz = mix(reflection, waterColor, (1.0-fresnel)*0.5) + specular * osg_LightSource[0].specular.xyz; -#endif - - // fog - float fogValue = clamp((depthPassthrough - gl_Fog.start) * gl_Fog.scale, 0.0, 1.0); - gl_FragData[0].xyz = mix(gl_FragData[0].xyz, gl_Fog.color.xyz, fogValue); - -#if REFRACTION - gl_FragData[0].w = 1.0; -#else - gl_FragData[0].w = clamp(fresnel*2.0 + specular, 0.0, 1.0); -#endif -} diff --git a/files/shaders/watergles_vertex.glsl b/files/shaders/watergles_vertex.glsl deleted file mode 100644 index 71cc9718b..000000000 --- a/files/shaders/watergles_vertex.glsl +++ /dev/null @@ -1,24 +0,0 @@ -#version 100 -precision mediump float; -precision mediump int; - -varying vec3 screenCoordsPassthrough; -varying vec4 position; -varying float depthPassthrough; - -void main(void) -{ - gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; - - mat4 scalemat = mat4(0.5, 0.0, 0.0, 0.0, - 0.0, -0.5, 0.0, 0.0, - 0.0, 0.0, 0.5, 0.0, - 0.5, 0.5, 0.5, 1.0); - - vec4 texcoordProj = ((scalemat) * ( gl_Position)); - screenCoordsPassthrough = vec3(texcoordProj.x, texcoordProj.y, texcoordProj.w); - - position = gl_Vertex; - - depthPassthrough = gl_Position.z; -} From fa610c447c7325963b537be1cec7ce02d3c6fb47 Mon Sep 17 00:00:00 2001 From: cfcohen Date: Wed, 25 Nov 2015 17:42:10 -0500 Subject: [PATCH 2582/3725] Fix typos. Add "e.g." in places where ranges are only recommmendations. Add more factual limits where that's easy. --- files/settings-default.cfg | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 5ed2d688d..cab6e7c4a 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -1,6 +1,6 @@ # WARNING: If this file is named settings-default.cfg, then editing # this file might have no effect, as these settings may be overwritten -# by your user settings.cfg file (see docmentation for its location). +# by your user settings.cfg file (see documentation for its location). # # This file provides minimal documentation for each setting, and # ranges of recommended values. For detailed explanations of the @@ -13,13 +13,13 @@ [Camera] -# Near clipping plane (0.01 to 18.0). +# Near clipping plane (>0.0, e.g. 0.01 to 18.0). near clip = 5.0 # Cull objects smaller than one pixel. small feature culling = true -# Maximum visible distance (2000.0 to 6666.0+). Caution: this setting +# Maximum visible distance (e.g. 2000.0 to 6666.0). Caution: this setting # can dramatically affect performance, see documentation for details. viewing distance = 6666.0 @@ -31,25 +31,24 @@ exterior cell load distance = 1 [Map] -# Size of each exterior cell in pixels in the world map. (12 to 24). +# Size of each exterior cell in pixels in the world map. (e.g. 12 to 24). # Warning: affects explored areas in save files, see documentation. global map cell size = 18 # Zoom level in pixels for HUD map widget. 64 is one cell, 128 is 1/4 -# cell, 256 is 1/8 cell. See documentation for details. (64 to 256). +# cell, 256 is 1/8 cell. See documentation for details. (e.g. 64 to 256). local map hud widget size = 256 # Resolution of local map in GUI window in pixels. See documentation -# for details which may affect cell load performance. (128 to 1024). +# for details which may affect cell load performance. (e.g. 128 to 1024). local map resolution = 256 -# Size of local map in GUI window in pixels. See documentation for -# details which may affect cell load performance. (256 to 1024). +# Size of local map in GUI window in pixels. (e.g. 256 to 1024). local map widget size = 512 [GUI] -# Scales GUI window and widget size. (<1 is smaller, >1 is larger). +# Scales GUI window and widget size. (<1.0 is smaller, >1.0 is larger). scaling factor = 1.0 # Transparency of GUI windows (0.0 to 1.0, transparent to opaque). @@ -89,7 +88,7 @@ show owned = 0 # Always use the best mode of attack: e.g. chop, slash or thrust. best attack = false -# Difficulty. Expressed as damage dealt and received. (-100 to 100). +# Difficulty. Expressed as damage dealt and received. (e.g. -100 to 100). difficulty = 0 # Show duration of magic effect and lights in the spells window. @@ -97,10 +96,10 @@ show effect duration = false [General] -# Anisotropy reduces distortion in textures at low angles (0 to 16). +# Anisotropy reduces distortion in textures at low angles (e.g. 0 to 16). anisotropy = 4 -# Camera field of view in degrees (30.0 to 110.0). +# Camera field of view in degrees (e.g. 30.0 to 110.0). field of view = 55.0 # File format for screenshots. (jpg, png, tga, and possibly more). @@ -123,11 +122,11 @@ always run = false # Zoom in and out from player in third person view with mouse wheel. allow third person zoom = false -# Camera sensitivity when not in GUI mode. (0.1 to 5.0). +# Camera sensitivity when not in GUI mode. (>0.0, e.g. 0.1 to 5.0). camera sensitivity = 1.0 # Vertical camera sensitivity multiplier when not in GUI mode. -# Because it's a multiplier values should be near one (0.5 to 1.5). +# (>0.0, Because it's a multiplier values should be near 1.0) camera y multiplier = 1.0 # Invert the vertical axis while not in GUI mode. @@ -168,7 +167,7 @@ voice volume = 0.8 [Video] -# Resolution of the Open window or screen. +# Resolution of the OpenMW window or screen. resolution x = 800 resolution y = 600 @@ -190,13 +189,13 @@ antialiasing = 0 # Enable vertical syncing to reduce tearing defects. vsync = false -# Maximum frames per second. (1.0 to 200.0). +# Maximum frames per second. 0.0 is unlimited, or >0.0 to limit. framerate limit = 0.0 # Game video contrast. (>0.0). No effect in Linux. contrast = 1.0 -# Video gamma setting. (>0.0). No effect in Linux. +# Video gamma setting. (>0.0). No effect in Linux. gamma = 1.0 [Water] @@ -228,7 +227,7 @@ distant land = false # Enable shadows. Other shadow settings disabled if false. Unused. enabled = false -# Size of the shadow textures in pixels. Unused. (256 to 2048). +# Size of the shadow textures in pixels. Unused. (e.g. 256 to 2048). texture size = 1024 # Actors cast shadows. Unused. From ad5eaaa705dcb1fe6ffe29e7be5fcf71c16c5889 Mon Sep 17 00:00:00 2001 From: cfcohen Date: Wed, 25 Nov 2015 21:30:04 -0500 Subject: [PATCH 2583/3725] Update the OpenMW Launcher so that it only writes changed values to the user settings.cfg file. Add a helpful header to the top of new settings.cfg files. Remove old code involve whitespace management that didn't work correctly anayway, and doesn't matter since we're not adding comments to the file. Remove "automatically generated" comments. --- apps/launcher/graphicspage.cpp | 52 ++++++++++++++++++++++++-------- apps/launcher/graphicspage.hpp | 1 + components/settings/settings.cpp | 35 ++++++--------------- 3 files changed, 50 insertions(+), 38 deletions(-) diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index a3bfbe5db..d7f045f80 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -80,6 +80,8 @@ bool Launcher::GraphicsPage::loadSettings() if (!setupSDL()) return false; + mInitialSettings = mEngineSettings; + if (mEngineSettings.getBool("vsync", "Video")) vSyncCheckBox->setCheckState(Qt::Checked); @@ -117,29 +119,53 @@ bool Launcher::GraphicsPage::loadSettings() void Launcher::GraphicsPage::saveSettings() { - mEngineSettings.setBool("vsync", "Video", vSyncCheckBox->checkState()); - mEngineSettings.setBool("fullscreen", "Video", fullScreenCheckBox->checkState()); - mEngineSettings.setBool("window border", "Video", windowBorderCheckBox->checkState()); - + bool iVSync = mInitialSettings.getBool("vsync", "Video"); + bool cVSync = vSyncCheckBox->checkState(); + if (iVSync != cVSync) + mEngineSettings.setBool("vsync", "Video", cVSync); + + bool iFullScreen = mInitialSettings.getBool("fullscreen", "Video"); + bool cFullScreen = fullScreenCheckBox->checkState(); + if (iFullScreen != cFullScreen) + mEngineSettings.setBool("fullscreen", "Video", cFullScreen); + + bool iWindowBorder = mInitialSettings.getBool("window border", "Video"); + bool cWindowBorder = windowBorderCheckBox->checkState(); + if (iWindowBorder != cWindowBorder) + mEngineSettings.setBool("window border", "Video", cWindowBorder); + + int iAAValue = mInitialSettings.getInt("antialiasing", "Video"); // The atoi() call is safe because the pull down constrains the string values. - int aaValue = atoi(antiAliasingComboBox->currentText().toLatin1().data()); - mEngineSettings.setInt("antialiasing", "Video", aaValue); + int cAAValue = atoi(antiAliasingComboBox->currentText().toLatin1().data()); + if (iAAValue != cAAValue) + mEngineSettings.setInt("antialiasing", "Video", cAAValue); + int cWidth = 0; + int cHeight = 0; if (standardRadioButton->isChecked()) { QRegExp resolutionRe(QString("(\\d+) x (\\d+).*")); if (resolutionRe.exactMatch(resolutionComboBox->currentText().simplified())) { // The atoi() call is safe because the pull down constrains the string values. - int width = atoi(resolutionRe.cap(1).toLatin1().data()); - int height = atoi(resolutionRe.cap(2).toLatin1().data()); - mEngineSettings.setInt("resolution x", "Video", width); - mEngineSettings.setInt("resolution y", "Video", height); + cWidth = atoi(resolutionRe.cap(1).toLatin1().data()); + cHeight = atoi(resolutionRe.cap(2).toLatin1().data()); } } else { - mEngineSettings.setInt("resolution x", "Video", customWidthSpinBox->value()); - mEngineSettings.setInt("resolution y", "Video", customHeightSpinBox->value()); + cWidth = customWidthSpinBox->value(); + cHeight = customHeightSpinBox->value(); } - mEngineSettings.setInt("screen", "Video", screenComboBox->currentIndex()); + int iWidth = mInitialSettings.getInt("resolution x", "Video"); + if (iWidth != cWidth) + mEngineSettings.setInt("resolution x", "Video", cWidth); + + int iHeight = mInitialSettings.getInt("resolution y", "Video"); + if (iHeight != cHeight) + mEngineSettings.setInt("resolution y", "Video", cHeight); + + int iScreen = mInitialSettings.getInt("screen", "Video"); + int cScreen = screenComboBox->currentIndex(); + if (iScreen != cScreen) + mEngineSettings.setInt("screen", "Video", cScreen); } QStringList Launcher::GraphicsPage::getAvailableResolutions(int screen) diff --git a/apps/launcher/graphicspage.hpp b/apps/launcher/graphicspage.hpp index e6eb53a3b..0958f07da 100644 --- a/apps/launcher/graphicspage.hpp +++ b/apps/launcher/graphicspage.hpp @@ -33,6 +33,7 @@ namespace Launcher private: Files::ConfigurationManager &mCfgMgr; Settings::Manager &mEngineSettings; + Settings::Manager mInitialSettings; QStringList getAvailableResolutions(int screen); QRect getMaximumResolution(); diff --git a/components/settings/settings.cpp b/components/settings/settings.cpp index c72e1ace4..acad1a98e 100644 --- a/components/settings/settings.cpp +++ b/components/settings/settings.cpp @@ -131,9 +131,7 @@ public: // Have we substantively changed the settings file? bool changed = false; - // Was there anything in the existing file? This is intended to permit the deletion of - // the settings.cfg file and it's automatic recreation -- a feature not currently - // supported elsewhere in the code. + // Were there any lines at all in the file? bool existing = false; // The category/section we're currently in. @@ -145,7 +143,6 @@ public: boost::filesystem::ifstream istream; boost::filesystem::path ipath(file); istream.open(ipath); - //std::cout << "Reading previous settings file: " << ipath << std::endl; // Create a new string stream to write the current settings to. It's likely that the // input file and the output file are the same, so this stream serves as a temporary file @@ -190,19 +187,13 @@ public: // Ensure that all options in the current category have been written. for (CategorySettingStatusMap::iterator mit = written.begin(); mit != written.end(); ++mit) { - bool missed = false; if (mit->second == false && mit->first.first == currentCategory) { std::cout << "Added new setting: [" << currentCategory << "] " << mit->first.second << " = " << settings[mit->first] << std::endl; - // With some further code changes, this comment could be more descriptive. - ostream << "# Automatically added setting." << std::endl; ostream << mit->first.second << " = " << settings[mit->first] << std::endl; mit->second = true; - missed = true; changed = true; } - // Ensure that there's a newline before the next section if we added settings. - if (missed) ostream << std::endl; } // Update the current category. @@ -223,7 +214,7 @@ public: if (!skipWhiteSpace(i, line)) continue; - // If we'cve found settings befor ethe first category, something's wrong. This + // If we've found settings before the first category, something's wrong. This // should never happen unless the player edited the file while playing, since // the loadSettingsFile() logic rejects it. if (currentCategory.empty()) { @@ -286,27 +277,24 @@ public: // Ensure that all options in the current category have been written. We must complete // the current category at the end of the file before moving on to any new categories. for (CategorySettingStatusMap::iterator mit = written.begin(); mit != written.end(); ++mit) { - bool missed = false; if (mit->second == false && mit->first.first == currentCategory) { std::cout << "Added new setting: [" << mit->first.first << "] " << mit->first.second << " = " << settings[mit->first] << std::endl; - // With some further code changes, this comment could be more descriptive. - ostream << std::endl << "# Automatically added setting." << std::endl; ostream << mit->first.second << " = " << settings[mit->first] << std::endl; mit->second = true; - missed = true; changed = true; } - // Ensure that there's a newline before the next section if we added settings. - if (missed) ostream << std::endl; } - // This logic triggers when the input file was effectively empty. It could be extended - // to doing something more intelligent instead, like make a copy of the default settings - // file (complete with comments) before continuing. Other code prevents OpenMW from - // executing to this point with a missing config file. + // If there was absolutely nothing in the file (or more likely the file didn't + // exist), start the newly created file with a helpful comment. if (!existing) { - ostream << "# This file was automatically generated." << std::endl << std::endl; + ostream << "# This is the OpenMW user 'settings.cfg' file. This file only contains" << std::endl; + ostream << "# explicitly changed settings. If you would like to revert a setting" << std::endl; + ostream << "# to its default, simply remove it from this file. For available" << std::endl; + ostream << "# settings, see the file 'settings-default.cfg' or the documentation at:" << std::endl; + ostream << "#" << std::endl; + ostream << "# https://wiki.openmw.org/index.php?title=Settings" << std::endl; } // We still have one more thing to do before we're completely done writing the file. @@ -321,14 +309,11 @@ public: currentCategory = mit->first.first; std::cout << "Created new setting section: " << mit->first.first << std::endl; ostream << std::endl; - // Add new category comments only if we're amending an existing file. - if (existing) ostream << "# Automatically added category." << std::endl; ostream << "[" << currentCategory << "]" << std::endl; } std::cout << "Added new setting: [" << mit->first.first << "] " << mit->first.second << " = " << settings[mit->first] << std::endl; // Then write the setting. No need to mark it as written because we're done. - ostream << std::endl; ostream << mit->first.second << " = " << settings[mit->first] << std::endl; changed = true; } From 046538984c580c2dcf93920b67c9761b96ee987a Mon Sep 17 00:00:00 2001 From: cfcohen Date: Thu, 26 Nov 2015 01:49:14 -0500 Subject: [PATCH 2584/3725] Fix duplicate filename in what() message. Use newly create cfgError utility function consistently throughout code. --- apps/launcher/maindialog.cpp | 102 +++++++++++++---------------------- 1 file changed, 38 insertions(+), 64 deletions(-) diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index 1c56a9efd..6453beacc 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -24,6 +24,15 @@ using namespace Process; +void cfgError(const QString& title, const QString& msg) { + QMessageBox msgBox; + msgBox.setWindowTitle(title); + msgBox.setIcon(QMessageBox::Critical); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setText(msg); + msgBox.exec(); +} + Launcher::MainDialog::MainDialog(QWidget *parent) : QMainWindow(parent), mGameSettings (mCfgMgr) { @@ -261,14 +270,10 @@ bool Launcher::MainDialog::setupLauncherSettings() QFile file(path); if (file.exists()) { if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { - QMessageBox msgBox; - msgBox.setWindowTitle(tr("Error opening OpenMW configuration file")); - msgBox.setIcon(QMessageBox::Critical); - msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(tr("
    Could not open %0 for reading

    \ - Please make sure you have the right permissions \ - and try again.
    ").arg(file.fileName())); - msgBox.exec(); + cfgError(tr("Error opening OpenMW configuration file"), + tr("
    Could not open %0 for reading

    \ + Please make sure you have the right permissions \ + and try again.
    ").arg(file.fileName())); return false; } QTextStream stream(&file); @@ -296,14 +301,10 @@ bool Launcher::MainDialog::setupGameSettings() if (file.exists()) { if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { - QMessageBox msgBox; - msgBox.setWindowTitle(tr("Error opening OpenMW configuration file")); - msgBox.setIcon(QMessageBox::Critical); - msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(tr("
    Could not open %0 for reading

    \ - Please make sure you have the right permissions \ - and try again.
    ").arg(file.fileName())); - msgBox.exec(); + cfgError(tr("Error opening OpenMW configuration file"), + tr("
    Could not open %0 for reading

    \ + Please make sure you have the right permissions \ + and try again.
    ").arg(file.fileName())); return false; } QTextStream stream(&file); @@ -324,14 +325,10 @@ bool Launcher::MainDialog::setupGameSettings() QFile file(path); if (file.exists()) { if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { - QMessageBox msgBox; - msgBox.setWindowTitle(tr("Error opening OpenMW configuration file")); - msgBox.setIcon(QMessageBox::Critical); - msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(tr("
    Could not open %0 for reading

    \ - Please make sure you have the right permissions \ - and try again.
    ").arg(file.fileName())); - msgBox.exec(); + cfgError(tr("Error opening OpenMW configuration file"), + tr("
    Could not open %0 for reading

    \ + Please make sure you have the right permissions \ + and try again.
    ").arg(file.fileName())); return false; } QTextStream stream(&file); @@ -381,15 +378,6 @@ bool Launcher::MainDialog::setupGameSettings() return true; } -void cfgError(const QString& title, const QString& msg) { - QMessageBox msgBox; - msgBox.setWindowTitle(title); - msgBox.setIcon(QMessageBox::Critical); - msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(msg); - msgBox.exec(); -} - bool Launcher::MainDialog::setupGraphicsSettings() { // This method is almost a copy of OMW::Engine::loadSettings(). They should definitely @@ -420,8 +408,7 @@ bool Launcher::MainDialog::setupGraphicsSettings() mEngineSettings.loadDefault(defaultPath); } catch (std::exception& e) { - std::string msg = "
    Error reading settings-default.cfg

    " + - defaultPath + "

    " + e.what(); + std::string msg = std::string("
    Error reading settings-default.cfg

    ") + e.what(); cfgError(tr("Error reading OpenMW configuration file"), tr(msg.c_str())); return false; } @@ -435,8 +422,7 @@ bool Launcher::MainDialog::setupGraphicsSettings() mEngineSettings.loadUser(userPath); } catch (std::exception& e) { - std::string msg = "
    Error reading settings-default.cfg

    " + - defaultPath + "

    " + e.what(); + std::string msg = std::string("
    Error reading settings.cfg

    ") + e.what(); cfgError(tr("Error reading OpenMW configuration file"), tr(msg.c_str())); return false; } @@ -487,15 +473,11 @@ bool Launcher::MainDialog::writeSettings() if (!dir.exists()) { if (!dir.mkpath(userPath)) { - QMessageBox msgBox; - msgBox.setWindowTitle(tr("Error creating OpenMW configuration directory")); - msgBox.setIcon(QMessageBox::Critical); - msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(tr("
    Could not create %0

    \ - Please make sure you have the right permissions \ - and try again.
    ").arg(userPath)); - msgBox.exec(); - return false; + cfgError(tr("Error creating OpenMW configuration directory"), + tr("
    Could not create %0

    \ + Please make sure you have the right permissions \ + and try again.
    ").arg(userPath)); + return false; } } @@ -504,15 +486,11 @@ bool Launcher::MainDialog::writeSettings() if (!file.open(QIODevice::ReadWrite | QIODevice::Text)) { // File cannot be opened or created - QMessageBox msgBox; - msgBox.setWindowTitle(tr("Error writing OpenMW configuration file")); - msgBox.setIcon(QMessageBox::Critical); - msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(tr("
    Could not open or create %0 for writing

    \ - Please make sure you have the right permissions \ - and try again.
    ").arg(file.fileName())); - msgBox.exec(); - return false; + cfgError(tr("Error writing OpenMW configuration file"), + tr("
    Could not open or create %0 for writing

    \ + Please make sure you have the right permissions \ + and try again.
    ").arg(file.fileName())); + return false; } @@ -536,15 +514,11 @@ bool Launcher::MainDialog::writeSettings() if (!file.open(QIODevice::ReadWrite | QIODevice::Text | QIODevice::Truncate)) { // File cannot be opened or created - QMessageBox msgBox; - msgBox.setWindowTitle(tr("Error writing Launcher configuration file")); - msgBox.setIcon(QMessageBox::Critical); - msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(tr("
    Could not open or create %0 for writing

    \ - Please make sure you have the right permissions \ - and try again.
    ").arg(file.fileName())); - msgBox.exec(); - return false; + cfgError(tr("Error writing Launcher configuration file"), + tr("
    Could not open or create %0 for writing

    \ + Please make sure you have the right permissions \ + and try again.
    ").arg(file.fileName())); + return false; } QTextStream stream(&file); From 8715add72fdff41b1d5d574f15545f747f707f29 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 26 Nov 2015 01:26:33 -0800 Subject: [PATCH 2585/3725] Store sound buffers in a deque that's filled in as needed A deque allows existing Sound_Buffer references to remain valid as long as new ones are back-inserted. These references can be used instead of indices. --- apps/openmw/mwsound/soundmanagerimp.cpp | 157 +++++++++--------------- apps/openmw/mwsound/soundmanagerimp.hpp | 29 +++-- 2 files changed, 72 insertions(+), 114 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index c7e504770..f19f298e1 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -119,15 +119,8 @@ namespace MWSound return DecoderPtr(new DEFAULT_DECODER (mVFS)); } - void SoundManager::insertSound(const std::string &soundId, const ESM::Sound *sound) + Sound_Buffer *SoundManager::insertSound(const std::string &soundId, const ESM::Sound *sound) { - BufferKeyList::iterator bufkey = std::lower_bound(mBufferKeys.begin(), mBufferKeys.end(), soundId); - if(bufkey != mBufferKeys.end() && *bufkey == soundId) - { - std::cerr<< "Duplicate sound record \""<getStore().get().find("fAudioDefaultMinDistance")->getFloat(); static const float fAudioDefaultMaxDistance = world->getStore().get().find("fAudioDefaultMaxDistance")->getFloat(); @@ -152,63 +145,39 @@ namespace MWSound min = std::max(min, 1.0f); max = std::max(min, max); - Sound_Buffer *sfx; - bufkey = mBufferKeys.insert(bufkey, soundId); - try { - BufferKeyList::difference_type id; - id = std::distance(mBufferKeys.begin(), bufkey); - mSoundBuffers.insert(mSoundBuffers.begin()+id, - Sound_Buffer("Sound/"+sound->mSound, volume, min, max) - ); - sfx = &mSoundBuffers[id]; - } - catch(...) { - mBufferKeys.erase(bufkey); - throw; - } - + Sound_Buffer *sfx = &*mSoundBuffers.insert(mSoundBuffers.end(), + Sound_Buffer("Sound/"+sound->mSound, volume, min, max) + ); mVFS->normalizeFilename(sfx->mResourceName); - } - - size_t SoundManager::lookupId(const std::string &soundId) - { - BufferKeyList::iterator bufkey = std::lower_bound(mBufferKeys.begin(), mBufferKeys.end(), soundId); - if(bufkey != mBufferKeys.end() && *bufkey == soundId) - return std::distance(mBufferKeys.begin(), bufkey); - if(mBufferKeys.empty()) - { - MWBase::World *world = MWBase::Environment::get().getWorld(); - MWWorld::Store::iterator iter = world->getStore().get().begin(); - MWWorld::Store::iterator end = world->getStore().get().end(); - size_t storesize = world->getStore().get().getSize(); - mBufferKeys.reserve(storesize); - mSoundBuffers.reserve(storesize); - for(;iter != end;++iter) - insertSound(Misc::StringUtils::lowerCase(iter->mId), &*iter); - - bufkey = std::lower_bound(mBufferKeys.begin(), mBufferKeys.end(), soundId); - if(bufkey != mBufferKeys.end() && *bufkey == soundId) - return std::distance(mBufferKeys.begin(), bufkey); - } + mBufferNameMap.insert(std::make_pair(soundId, sfx)); - throw std::runtime_error("Sound "+soundId+" not found"); + return sfx; } - size_t SoundManager::lookupId(const std::string& soundId) const + // Lookup a soundId for its sound data (resource name, local volume, + // minRange, and maxRange) + Sound_Buffer *SoundManager::lookupSound(const std::string &soundId) const { - BufferKeyList::const_iterator bufkey = std::lower_bound(mBufferKeys.begin(), mBufferKeys.end(), soundId); - if(bufkey != mBufferKeys.end() && *bufkey == soundId) - return std::distance(mBufferKeys.begin(), bufkey); - - throw std::runtime_error("Sound "+soundId+" not found"); + NameBufferMap::const_iterator snd = mBufferNameMap.find(soundId); + if(snd != mBufferNameMap.end()) return snd->second; + return 0; } - // Lookup a sfxid for its sound data (resource name, local volume, - // minRange, and maxRange). - Sound_Buffer *SoundManager::lookup(size_t sfxid) + // Lookup a soundId for its sound data (resource name, local volume, + // minRange, and maxRange), and ensure it's ready for use. + Sound_Buffer *SoundManager::loadSound(const std::string &soundId) { - Sound_Buffer *sfx = &mSoundBuffers[sfxid]; + Sound_Buffer *sfx; + NameBufferMap::const_iterator snd = mBufferNameMap.find(soundId); + if(snd != mBufferNameMap.end()) + sfx = snd->second; + else + { + MWBase::World *world = MWBase::Environment::get().getWorld(); + const ESM::Sound *sound = world->getStore().get().find(soundId); + sfx = insertSound(soundId, sound); + } if(!sfx->mHandle) { @@ -223,7 +192,7 @@ namespace MWSound std::cerr<< "No unused sound buffers to free, using "<getSoundDataSize(unused->mHandle); mOutput->unloadSound(unused->mHandle); @@ -231,19 +200,12 @@ namespace MWSound mUnusedBuffers.pop_back(); } - mUnusedBuffers.push_front(sfxid); + mUnusedBuffers.push_front(sfx); } return sfx; } - // Lookup a soundid for its sound data (resource name, local volume, - // minRange, and maxRange). - Sound_Buffer *SoundManager::lookup(const std::string &soundId) - { - return lookup(lookupId(soundId)); - } - DecoderPtr SoundManager::loadVoice(const std::string &voicefile) { DecoderPtr decoder = getDecoder(); @@ -511,8 +473,7 @@ namespace MWSound return sound; try { - size_t sfxid = lookupId(Misc::StringUtils::lowerCase(soundId)); - Sound_Buffer *sfx = lookup(sfxid); + Sound_Buffer *sfx = loadSound(Misc::StringUtils::lowerCase(soundId)); float basevol = volumeFromType(type); sound = mOutput->playSound(sfx->mHandle, @@ -520,11 +481,11 @@ namespace MWSound ); if(sfx->mUses++ == 0) { - SoundList::iterator iter = std::find(mUnusedBuffers.begin(), mUnusedBuffers.end(), sfxid); + SoundList::iterator iter = std::find(mUnusedBuffers.begin(), mUnusedBuffers.end(), sfx); if(iter != mUnusedBuffers.end()) mUnusedBuffers.erase(iter); } - mActiveSounds[MWWorld::Ptr()].push_back(std::make_pair(sound, sfxid)); + mActiveSounds[MWWorld::Ptr()].push_back(std::make_pair(sound, sfx)); } catch(std::exception&) { @@ -542,8 +503,7 @@ namespace MWSound try { // Look up the sound in the ESM data - size_t sfxid = lookupId(Misc::StringUtils::lowerCase(soundId)); - Sound_Buffer *sfx = lookup(sfxid); + Sound_Buffer *sfx = loadSound(Misc::StringUtils::lowerCase(soundId)); float basevol = volumeFromType(type); const ESM::Position &pos = ptr.getRefData().getPosition(); const osg::Vec3f objpos(pos.asVec3()); @@ -556,11 +516,11 @@ namespace MWSound ); if(sfx->mUses++ == 0) { - SoundList::iterator iter = std::find(mUnusedBuffers.begin(), mUnusedBuffers.end(), sfxid); + SoundList::iterator iter = std::find(mUnusedBuffers.begin(), mUnusedBuffers.end(), sfx); if(iter != mUnusedBuffers.end()) mUnusedBuffers.erase(iter); } - mActiveSounds[ptr].push_back(std::make_pair(sound, sfxid)); + mActiveSounds[ptr].push_back(std::make_pair(sound, sfx)); } catch(std::exception&) { @@ -578,8 +538,7 @@ namespace MWSound try { // Look up the sound in the ESM data - size_t sfxid = lookupId(Misc::StringUtils::lowerCase(soundId)); - Sound_Buffer *sfx = lookup(sfxid); + Sound_Buffer *sfx = loadSound(Misc::StringUtils::lowerCase(soundId)); float basevol = volumeFromType(type); sound = mOutput->playSound3D(sfx->mHandle, @@ -587,11 +546,11 @@ namespace MWSound ); if(sfx->mUses++ == 0) { - SoundList::iterator iter = std::find(mUnusedBuffers.begin(), mUnusedBuffers.end(), sfxid); + SoundList::iterator iter = std::find(mUnusedBuffers.begin(), mUnusedBuffers.end(), sfx); if(iter != mUnusedBuffers.end()) mUnusedBuffers.erase(iter); } - mActiveSounds[MWWorld::Ptr()].push_back(std::make_pair(sound, sfxid)); + mActiveSounds[MWWorld::Ptr()].push_back(std::make_pair(sound, sfx)); } catch(std::exception &) { @@ -605,11 +564,11 @@ namespace MWSound SoundMap::iterator snditer = mActiveSounds.find(ptr); if(snditer != mActiveSounds.end()) { - size_t sfxid = lookupId(Misc::StringUtils::lowerCase(soundId)); - SoundIndexPairList::iterator sndidx = snditer->second.begin(); + Sound_Buffer *sfx = loadSound(Misc::StringUtils::lowerCase(soundId)); + SoundBufferRefPairList::iterator sndidx = snditer->second.begin(); for(;sndidx != snditer->second.end();++sndidx) { - if(sndidx->second == sfxid) + if(sndidx->second == sfx) sndidx->first->stop(); } } @@ -620,7 +579,7 @@ namespace MWSound SoundMap::iterator snditer = mActiveSounds.find(ptr); if(snditer != mActiveSounds.end()) { - SoundIndexPairList::iterator sndidx = snditer->second.begin(); + SoundBufferRefPairList::iterator sndidx = snditer->second.begin(); for(;sndidx != snditer->second.end();++sndidx) sndidx->first->stop(); } @@ -635,7 +594,7 @@ namespace MWSound snditer->first != MWMechanics::getPlayer() && snditer->first.getCell() == cell) { - SoundIndexPairList::iterator sndidx = snditer->second.begin(); + SoundBufferRefPairList::iterator sndidx = snditer->second.begin(); for(;sndidx != snditer->second.end();++sndidx) sndidx->first->stop(); } @@ -659,11 +618,11 @@ namespace MWSound SoundMap::iterator snditer = mActiveSounds.find(MWWorld::Ptr()); if(snditer != mActiveSounds.end()) { - size_t sfxid = lookupId(Misc::StringUtils::lowerCase(soundId)); - SoundIndexPairList::iterator sndidx = snditer->second.begin(); + Sound_Buffer *sfx = loadSound(Misc::StringUtils::lowerCase(soundId)); + SoundBufferRefPairList::iterator sndidx = snditer->second.begin(); for(;sndidx != snditer->second.end();++sndidx) { - if(sndidx->second == sfxid) + if(sndidx->second == sfx) sndidx->first->stop(); } } @@ -675,11 +634,11 @@ namespace MWSound SoundMap::iterator snditer = mActiveSounds.find(ptr); if(snditer != mActiveSounds.end()) { - size_t sfxid = lookupId(Misc::StringUtils::lowerCase(soundId)); - SoundIndexPairList::iterator sndidx = snditer->second.begin(); + Sound_Buffer *sfx = loadSound(Misc::StringUtils::lowerCase(soundId)); + SoundBufferRefPairList::iterator sndidx = snditer->second.begin(); for(;sndidx != snditer->second.end();++sndidx) { - if(sndidx->second == sfxid) + if(sndidx->second == sfx) sndidx->first->setFadeout(duration); } } @@ -690,11 +649,11 @@ namespace MWSound SoundMap::const_iterator snditer = mActiveSounds.find(ptr); if(snditer != mActiveSounds.end()) { - size_t sfxid = lookupId(Misc::StringUtils::lowerCase(soundId)); - SoundIndexPairList::const_iterator sndidx = snditer->second.begin(); + Sound_Buffer *sfx = lookupSound(Misc::StringUtils::lowerCase(soundId)); + SoundBufferRefPairList::const_iterator sndidx = snditer->second.begin(); for(;sndidx != snditer->second.end();++sndidx) { - if(sndidx->second == sfxid && sndidx->first->isPlaying()) + if(sndidx->second == sfx && sndidx->first->isPlaying()) return true; } } @@ -825,14 +784,14 @@ namespace MWSound SoundMap::iterator snditer = mActiveSounds.begin(); while(snditer != mActiveSounds.end()) { - SoundIndexPairList::iterator sndidx = snditer->second.begin(); + SoundBufferRefPairList::iterator sndidx = snditer->second.begin(); while(sndidx != snditer->second.end()) { if(!updateSound(sndidx->first, snditer->first, duration)) { - Sound_Buffer *sfx = &mSoundBuffers[sndidx->second]; + Sound_Buffer *sfx = sndidx->second; if(sfx->mUses-- == 1) - mUnusedBuffers.push_front(sndidx->second); + mUnusedBuffers.push_front(sfx); sndidx = snditer->second.erase(sndidx); } else @@ -916,7 +875,7 @@ namespace MWSound SoundMap::iterator snditer = mActiveSounds.begin(); for(;snditer != mActiveSounds.end();++snditer) { - SoundIndexPairList::iterator sndidx = snditer->second.begin(); + SoundBufferRefPairList::iterator sndidx = snditer->second.begin(); for(;sndidx != snditer->second.end();++sndidx) { MWBase::SoundPtr sound = sndidx->first; @@ -956,7 +915,7 @@ namespace MWSound SoundMap::iterator snditer = mActiveSounds.find(old); if(snditer != mActiveSounds.end()) { - SoundIndexPairList sndlist = snditer->second; + SoundBufferRefPairList sndlist = snditer->second; mActiveSounds.erase(snditer); mActiveSounds[updated] = sndlist; } @@ -1039,13 +998,13 @@ namespace MWSound SoundMap::iterator snditer = mActiveSounds.begin(); for(;snditer != mActiveSounds.end();++snditer) { - SoundIndexPairList::iterator sndidx = snditer->second.begin(); + SoundBufferRefPairList::iterator sndidx = snditer->second.begin(); for(;sndidx != snditer->second.end();++sndidx) { sndidx->first->stop(); - Sound_Buffer *sfx = &mSoundBuffers[sndidx->second]; + Sound_Buffer *sfx = sndidx->second; if(sfx->mUses-- == 1) - mUnusedBuffers.push_front(sndidx->second); + mUnusedBuffers.push_front(sfx); } } mActiveSounds.clear(); diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index 15fdd86cf..cdf35189f 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -51,28 +51,29 @@ namespace MWSound float mVoiceVolume; float mFootstepsVolume; - typedef std::vector BufferKeyList; - typedef std::vector SoundBufferList; - // Each mBufferKeys index has a corresponding entry in mSoundBuffers. - // That is, if string "foo" is at index 10 in mBufferKeys, index 10 in - // mSoundBuffers contains the Sound_Buffer for "foo". - BufferKeyList mBufferKeys; + typedef std::deque SoundBufferList; + // List of sound buffers, grown as needed. New enties are added to the + // back, allowing existing Sound_Buffer references/pointers to remain + // valid. SoundBufferList mSoundBuffers; size_t mBufferCacheSize; + typedef std::map NameBufferMap; + NameBufferMap mBufferNameMap; + typedef std::map NameLoudnessMap; NameLoudnessMap mVoiceLipBuffers; // NOTE: unused buffers are stored in front-newest order. - typedef std::deque SoundList; + typedef std::deque SoundList; SoundList mUnusedBuffers; boost::shared_ptr mMusic; std::string mCurrentPlaylist; - typedef std::pair SoundIndexPair; - typedef std::vector SoundIndexPairList; - typedef std::map SoundMap; + typedef std::pair SoundBufferRefPair; + typedef std::vector SoundBufferRefPairList; + typedef std::map SoundMap; SoundMap mActiveSounds; typedef std::pair SoundNamePair; @@ -88,12 +89,10 @@ namespace MWSound int mPausedSoundTypes; - void insertSound(const std::string &soundId, const ESM::Sound *sound); + Sound_Buffer *insertSound(const std::string &soundId, const ESM::Sound *sound); - size_t lookupId(const std::string &soundId); - size_t lookupId(const std::string &soundId) const; - Sound_Buffer *lookup(size_t sfxid); - Sound_Buffer *lookup(const std::string &soundId); + Sound_Buffer *lookupSound(const std::string &soundId) const; + Sound_Buffer *loadSound(const std::string &soundId); // Ensures the loudness/"lip" data is loaded, and returns a decoder to // start streaming From d4238a6d91e9c804e298be8a5b304c0708e0fa03 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 26 Nov 2015 02:13:37 -0800 Subject: [PATCH 2586/3725] Add config options for the sound buffer cache size The cache size is specified with a min/max range, intended to avoid constant unloading once the limit is reached. This way, buffers can be unloaded down to a reasonable mimimum, allowing some more buffers to be subsequently loaded without causing more unloading. --- apps/openmw/mwsound/soundmanagerimp.cpp | 34 +++++++++++++++---------- apps/openmw/mwsound/soundmanagerimp.hpp | 2 ++ files/settings-default.cfg | 9 +++++++ 3 files changed, 31 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index f19f298e1..4d0c7912c 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -66,6 +66,11 @@ namespace MWSound mFootstepsVolume = Settings::Manager::getFloat("footsteps volume", "Sound"); mFootstepsVolume = std::min(std::max(mFootstepsVolume, 0.0f), 1.0f); + mBufferCacheMin = std::max(Settings::Manager::getInt("buffer cache min", "Sound"), 1); + mBufferCacheMax = std::max(Settings::Manager::getInt("buffer cache max", "Sound"), 1); + mBufferCacheMax *= 1024*1024; + mBufferCacheMin = std::min(mBufferCacheMin*1024*1024, mBufferCacheMax); + std::cout << "Sound output: " << SOUND_OUT << std::endl; std::cout << "Sound decoder: " << SOUND_IN << std::endl; @@ -184,21 +189,22 @@ namespace MWSound sfx->mHandle = mOutput->loadSound(sfx->mResourceName); mBufferCacheSize += mOutput->getSoundDataSize(sfx->mHandle); - // NOTE: Max sound buffer cache size is 15MB. Make configurable? - while(mBufferCacheSize > 15*1024*1024) + if(mBufferCacheSize > mBufferCacheMax) { - if(mUnusedBuffers.empty()) - { - std::cerr<< "No unused sound buffers to free, using "<getSoundDataSize(unused->mHandle); - mOutput->unloadSound(unused->mHandle); - unused->mHandle = 0; - - mUnusedBuffers.pop_back(); + do { + if(mUnusedBuffers.empty()) + { + std::cerr<< "No unused sound buffers to free, using "<getSoundDataSize(unused->mHandle); + mOutput->unloadSound(unused->mHandle); + unused->mHandle = 0; + + mUnusedBuffers.pop_back(); + } while(mBufferCacheSize > mBufferCacheMin); } mUnusedBuffers.push_front(sfx); } diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index cdf35189f..38bad2194 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -56,6 +56,8 @@ namespace MWSound // back, allowing existing Sound_Buffer references/pointers to remain // valid. SoundBufferList mSoundBuffers; + size_t mBufferCacheMin; + size_t mBufferCacheMax; size_t mBufferCacheSize; typedef std::map NameBufferMap; diff --git a/files/settings-default.cfg b/files/settings-default.cfg index cab6e7c4a..7d0292c5b 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -165,6 +165,15 @@ sfx volume = 1.0 # Voice dialog volume. voice volume = 0.8 +# Minimum size to use for the sound buffer cache, in MB. When the cache is +# filled, old buffers will be unloaded until it's using no more than this much +# memory. Must be less than or equal to 'buffer cache max'. +buffer cache min = 14 + +# Maximum size to use for the sound buffer cache, in MB. The cache can use up +# to this much memory until old buffers get purged. +buffer cache max = 16 + [Video] # Resolution of the OpenMW window or screen. From a9c9cc5508f49dc095fd5e518dab93239646620a Mon Sep 17 00:00:00 2001 From: cfcohen Date: Thu, 26 Nov 2015 10:42:43 -0500 Subject: [PATCH 2587/3725] Remove unnecessary copy of mEngineSettings in mInitialSettings. --- apps/launcher/graphicspage.cpp | 16 +++++++--------- apps/launcher/graphicspage.hpp | 1 - 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index d7f045f80..f56c97888 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -80,8 +80,6 @@ bool Launcher::GraphicsPage::loadSettings() if (!setupSDL()) return false; - mInitialSettings = mEngineSettings; - if (mEngineSettings.getBool("vsync", "Video")) vSyncCheckBox->setCheckState(Qt::Checked); @@ -119,22 +117,22 @@ bool Launcher::GraphicsPage::loadSettings() void Launcher::GraphicsPage::saveSettings() { - bool iVSync = mInitialSettings.getBool("vsync", "Video"); + bool iVSync = mEngineSettings.getBool("vsync", "Video"); bool cVSync = vSyncCheckBox->checkState(); if (iVSync != cVSync) mEngineSettings.setBool("vsync", "Video", cVSync); - bool iFullScreen = mInitialSettings.getBool("fullscreen", "Video"); + bool iFullScreen = mEngineSettings.getBool("fullscreen", "Video"); bool cFullScreen = fullScreenCheckBox->checkState(); if (iFullScreen != cFullScreen) mEngineSettings.setBool("fullscreen", "Video", cFullScreen); - bool iWindowBorder = mInitialSettings.getBool("window border", "Video"); + bool iWindowBorder = mEngineSettings.getBool("window border", "Video"); bool cWindowBorder = windowBorderCheckBox->checkState(); if (iWindowBorder != cWindowBorder) mEngineSettings.setBool("window border", "Video", cWindowBorder); - int iAAValue = mInitialSettings.getInt("antialiasing", "Video"); + int iAAValue = mEngineSettings.getInt("antialiasing", "Video"); // The atoi() call is safe because the pull down constrains the string values. int cAAValue = atoi(antiAliasingComboBox->currentText().toLatin1().data()); if (iAAValue != cAAValue) @@ -154,15 +152,15 @@ void Launcher::GraphicsPage::saveSettings() cHeight = customHeightSpinBox->value(); } - int iWidth = mInitialSettings.getInt("resolution x", "Video"); + int iWidth = mEngineSettings.getInt("resolution x", "Video"); if (iWidth != cWidth) mEngineSettings.setInt("resolution x", "Video", cWidth); - int iHeight = mInitialSettings.getInt("resolution y", "Video"); + int iHeight = mEngineSettings.getInt("resolution y", "Video"); if (iHeight != cHeight) mEngineSettings.setInt("resolution y", "Video", cHeight); - int iScreen = mInitialSettings.getInt("screen", "Video"); + int iScreen = mEngineSettings.getInt("screen", "Video"); int cScreen = screenComboBox->currentIndex(); if (iScreen != cScreen) mEngineSettings.setInt("screen", "Video", cScreen); diff --git a/apps/launcher/graphicspage.hpp b/apps/launcher/graphicspage.hpp index 0958f07da..e6eb53a3b 100644 --- a/apps/launcher/graphicspage.hpp +++ b/apps/launcher/graphicspage.hpp @@ -33,7 +33,6 @@ namespace Launcher private: Files::ConfigurationManager &mCfgMgr; Settings::Manager &mEngineSettings; - Settings::Manager mInitialSettings; QStringList getAvailableResolutions(int screen); QRect getMaximumResolution(); From c26463fd91b90bba390085228712fa7396c997f5 Mon Sep 17 00:00:00 2001 From: cfcohen Date: Thu, 26 Nov 2015 10:52:20 -0500 Subject: [PATCH 2588/3725] Should have coded it the way scrawl said, since it's cleaner. --- apps/launcher/graphicspage.cpp | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index f56c97888..bc797574b 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -117,25 +117,21 @@ bool Launcher::GraphicsPage::loadSettings() void Launcher::GraphicsPage::saveSettings() { - bool iVSync = mEngineSettings.getBool("vsync", "Video"); bool cVSync = vSyncCheckBox->checkState(); - if (iVSync != cVSync) + if (cVSync != mEngineSettings.getBool("vsync", "Video")) mEngineSettings.setBool("vsync", "Video", cVSync); - bool iFullScreen = mEngineSettings.getBool("fullscreen", "Video"); bool cFullScreen = fullScreenCheckBox->checkState(); - if (iFullScreen != cFullScreen) + if (cFullScreen != mEngineSettings.getBool("fullscreen", "Video")) mEngineSettings.setBool("fullscreen", "Video", cFullScreen); - bool iWindowBorder = mEngineSettings.getBool("window border", "Video"); bool cWindowBorder = windowBorderCheckBox->checkState(); - if (iWindowBorder != cWindowBorder) + if (cWindowBorder != mEngineSettings.getBool("window border", "Video")) mEngineSettings.setBool("window border", "Video", cWindowBorder); - int iAAValue = mEngineSettings.getInt("antialiasing", "Video"); // The atoi() call is safe because the pull down constrains the string values. int cAAValue = atoi(antiAliasingComboBox->currentText().toLatin1().data()); - if (iAAValue != cAAValue) + if (cAAValue != mEngineSettings.getInt("antialiasing", "Video")) mEngineSettings.setInt("antialiasing", "Video", cAAValue); int cWidth = 0; @@ -152,17 +148,14 @@ void Launcher::GraphicsPage::saveSettings() cHeight = customHeightSpinBox->value(); } - int iWidth = mEngineSettings.getInt("resolution x", "Video"); - if (iWidth != cWidth) + if (cWidth != mEngineSettings.getInt("resolution x", "Video")) mEngineSettings.setInt("resolution x", "Video", cWidth); - int iHeight = mEngineSettings.getInt("resolution y", "Video"); - if (iHeight != cHeight) + if (cHeight != mEngineSettings.getInt("resolution y", "Video")) mEngineSettings.setInt("resolution y", "Video", cHeight); - int iScreen = mEngineSettings.getInt("screen", "Video"); int cScreen = screenComboBox->currentIndex(); - if (iScreen != cScreen) + if (cScreen != mEngineSettings.getInt("screen", "Video")) mEngineSettings.setInt("screen", "Video", cScreen); } From 3747843c921a20159bc7ab048064c72ceab61480 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 26 Nov 2015 17:07:20 +0100 Subject: [PATCH 2589/3725] Use QString::toInt instead of atoi --- apps/launcher/graphicspage.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index bc797574b..523d0bb04 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -129,8 +129,7 @@ void Launcher::GraphicsPage::saveSettings() if (cWindowBorder != mEngineSettings.getBool("window border", "Video")) mEngineSettings.setBool("window border", "Video", cWindowBorder); - // The atoi() call is safe because the pull down constrains the string values. - int cAAValue = atoi(antiAliasingComboBox->currentText().toLatin1().data()); + int cAAValue = antiAliasingComboBox->currentText().toInt(); if (cAAValue != mEngineSettings.getInt("antialiasing", "Video")) mEngineSettings.setInt("antialiasing", "Video", cAAValue); @@ -139,9 +138,8 @@ void Launcher::GraphicsPage::saveSettings() if (standardRadioButton->isChecked()) { QRegExp resolutionRe(QString("(\\d+) x (\\d+).*")); if (resolutionRe.exactMatch(resolutionComboBox->currentText().simplified())) { - // The atoi() call is safe because the pull down constrains the string values. - cWidth = atoi(resolutionRe.cap(1).toLatin1().data()); - cHeight = atoi(resolutionRe.cap(2).toLatin1().data()); + cWidth = resolutionRe.cap(1).toInt(); + cHeight = resolutionRe.cap(2).toInt(); } } else { cWidth = customWidthSpinBox->value(); From 325d208b4a74ce9f1bd976ba76c07f69b9c61525 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 26 Nov 2015 17:13:13 +0100 Subject: [PATCH 2590/3725] Fix incorrect error message --- apps/launcher/maindialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index 6453beacc..9bf135e7e 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -505,7 +505,7 @@ bool Launcher::MainDialog::writeSettings() catch (std::exception& e) { std::string msg = "
    Error writing settings.cfg

    " + settingsPath + "

    " + e.what(); - cfgError(tr("Error reading OpenMW configuration file"), tr(msg.c_str())); + cfgError(tr("Error writing user settings file"), tr(msg.c_str())); return false; } From 84aceedfa26352fd85d2364555e51d744258d287 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 26 Nov 2015 17:15:12 +0100 Subject: [PATCH 2591/3725] Add comment --- apps/launcher/graphicspage.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index 523d0bb04..622db4da4 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -117,6 +117,8 @@ bool Launcher::GraphicsPage::loadSettings() void Launcher::GraphicsPage::saveSettings() { + // Ensure we only set the new settings if they changed. This is to avoid cluttering the + // user settings file (which by definition should only contain settings the user has touched) bool cVSync = vSyncCheckBox->checkState(); if (cVSync != mEngineSettings.getBool("vsync", "Video")) mEngineSettings.setBool("vsync", "Video", cVSync); From d894d54e41e7577dc7b54e06613712780a07bd65 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 26 Nov 2015 17:15:28 +0100 Subject: [PATCH 2592/3725] Improve path conversions --- apps/launcher/maindialog.cpp | 8 ++++---- apps/openmw/engine.cpp | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index 9bf135e7e..8738dae2c 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -385,8 +385,8 @@ bool Launcher::MainDialog::setupGraphicsSettings() // the filenames should be in the CfgMgr component. // Create the settings manager and load default settings file - const std::string localDefault = mCfgMgr.getLocalPath().string() + "settings-default.cfg"; - const std::string globalDefault = mCfgMgr.getGlobalPath().string() + "settings-default.cfg"; + const std::string localDefault = (mCfgMgr.getLocalPath() / "settings-default.cfg").string(); + const std::string globalDefault = (mCfgMgr.getGlobalPath() / "settings-default.cfg").string(); std::string defaultPath; // Prefer the settings-default.cfg in the current directory. @@ -414,7 +414,7 @@ bool Launcher::MainDialog::setupGraphicsSettings() } // Load user settings if they exist - const std::string userPath = mCfgMgr.getUserConfigPath().string() + "settings.cfg"; + const std::string userPath = (mCfgMgr.getUserConfigPath() / "settings.cfg").string(); // User settings are not required to exist, so if they don't we're done. if (!boost::filesystem::exists(userPath)) return true; @@ -498,7 +498,7 @@ bool Launcher::MainDialog::writeSettings() file.close(); // Graphics settings - const std::string settingsPath = mCfgMgr.getUserConfigPath().string() + "settings.cfg"; + const std::string settingsPath = (mCfgMgr.getUserConfigPath() / "settings.cfg").string(); try { mEngineSettings.saveUser(settingsPath); } diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index a4f5f9440..66231dd98 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -298,8 +298,8 @@ void OMW::Engine::setSkipMenu (bool skipMenu, bool newGame) std::string OMW::Engine::loadSettings (Settings::Manager & settings) { // Create the settings manager and load default settings file - const std::string localdefault = mCfgMgr.getLocalPath().string() + "settings-default.cfg"; - const std::string globaldefault = mCfgMgr.getGlobalPath().string() + "settings-default.cfg"; + const std::string localdefault = (mCfgMgr.getLocalPath() / "settings-default.cfg").string(); + const std::string globaldefault = (mCfgMgr.getGlobalPath() / "settings-default.cfg").string(); // prefer local if (boost::filesystem::exists(localdefault)) @@ -310,7 +310,7 @@ std::string OMW::Engine::loadSettings (Settings::Manager & settings) throw std::runtime_error ("No default settings file found! Make sure the file \"settings-default.cfg\" was properly installed."); // load user settings if they exist - const std::string settingspath = mCfgMgr.getUserConfigPath().string() + "settings.cfg"; + const std::string settingspath = (mCfgMgr.getUserConfigPath() / "settings.cfg").string(); if (boost::filesystem::exists(settingspath)) settings.loadUser(settingspath); From 2ffcc2a2b4fdd49304c5a7ffc7c6421872413e5c Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 26 Nov 2015 17:34:22 +0100 Subject: [PATCH 2593/3725] Fix incorrect path encoding handling in debug message --- apps/launcher/maindialog.cpp | 6 +++--- apps/wizard/mainwizard.cpp | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index 8738dae2c..fb1b73c3e 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -266,7 +266,7 @@ bool Launcher::MainDialog::setupLauncherSettings() paths.append(userPath + QString(Config::LauncherSettings::sLauncherConfigFileName)); foreach (const QString &path, paths) { - qDebug() << "Loading config file:" << qPrintable(path); + qDebug() << "Loading config file:" << path.toUtf8().constData(); QFile file(path); if (file.exists()) { if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { @@ -297,7 +297,7 @@ bool Launcher::MainDialog::setupGameSettings() QString path = userPath + QLatin1String("openmw.cfg"); QFile file(path); - qDebug() << "Loading config file:" << qPrintable(path); + qDebug() << "Loading config file:" << path.toUtf8().constData(); if (file.exists()) { if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { @@ -320,7 +320,7 @@ bool Launcher::MainDialog::setupGameSettings() paths.append(userPath + QString("openmw.cfg")); foreach (const QString &path, paths) { - qDebug() << "Loading config file:" << qPrintable(path); + qDebug() << "Loading config file:" << path.toUtf8().constData(); QFile file(path); if (file.exists()) { diff --git a/apps/wizard/mainwizard.cpp b/apps/wizard/mainwizard.cpp index 7538511fe..19cdf9535 100644 --- a/apps/wizard/mainwizard.cpp +++ b/apps/wizard/mainwizard.cpp @@ -138,7 +138,7 @@ void Wizard::MainWizard::setupGameSettings() QString path(userPath + QLatin1String("openmw.cfg")); QFile file(path); - qDebug() << "Loading config file:" << qPrintable(path); + qDebug() << "Loading config file:" << path.toUtf8().constData(); if (file.exists()) { if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { @@ -163,7 +163,7 @@ void Wizard::MainWizard::setupGameSettings() paths.append(globalPath + QLatin1String("openmw.cfg")); foreach (const QString &path, paths) { - qDebug() << "Loading config file:" << qPrintable(path); + qDebug() << "Loading config file:" << path.toUtf8().constData(); QFile file(path); if (file.exists()) { @@ -197,7 +197,7 @@ void Wizard::MainWizard::setupLauncherSettings() QFile file(path); - qDebug() << "Loading config file:" << qPrintable(path); + qDebug() << "Loading config file:" << path.toUtf8().constData(); if (file.exists()) { if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { From 984c4550279907c432791fdeb07161339f3d1e57 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 26 Nov 2015 18:22:01 +0100 Subject: [PATCH 2594/3725] Fix Show Owned option affecting tooltips that are not objects (Fixes #3036) --- apps/openmw/mwgui/tooltips.cpp | 18 +++++++++--------- apps/openmw/mwgui/tooltips.hpp | 3 ++- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 7c7f951af..3356698df 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -87,9 +87,9 @@ namespace MWGui return; } - bool gameMode = MWBase::Environment::get().getWindowManager()->isGuiMode(); + bool guiMode = MWBase::Environment::get().getWindowManager()->isGuiMode(); - if (gameMode) + if (guiMode) { const MyGUI::IntPoint& mousePos = MyGUI::InputManager::getInstance().getMousePosition(); @@ -112,7 +112,7 @@ namespace MWGui if (info.caption.empty()) info.caption=mFocusObject.getCellRef().getRefId(); info.icon=""; - tooltipSize = createToolTip(info); + tooltipSize = createToolTip(info, true); } else tooltipSize = getToolTipViaPtr(true); @@ -178,7 +178,7 @@ namespace MWGui ToolTipInfo info; info.text = data.caption; info.notes = data.notes; - tooltipSize = createToolTip(info); + tooltipSize = createToolTip(info, false); } else if (type == "ItemPtr") { @@ -197,7 +197,7 @@ namespace MWGui } else if (type == "ToolTipInfo") { - tooltipSize = createToolTip(*focus->getUserData()); + tooltipSize = createToolTip(*focus->getUserData(), false); } else if (type == "AvatarItemSelection") { @@ -240,7 +240,7 @@ namespace MWGui info.text = "#{sSchool}: " + sSchoolNames[school]; } info.effects = effects; - tooltipSize = createToolTip(info); + tooltipSize = createToolTip(info, false); } else if (type == "Layout") { @@ -345,7 +345,7 @@ namespace MWGui ToolTipInfo info = object.getToolTipInfo(mFocusObject); if (!image) info.icon = ""; - tooltipSize = createToolTip(info); + tooltipSize = createToolTip(info, true); } return tooltipSize; @@ -370,13 +370,13 @@ namespace MWGui } } - MyGUI::IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info) + MyGUI::IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info, bool isFocusObject) { mDynamicToolTipBox->setVisible(true); if(mShowOwned == 1 || mShowOwned == 3) { - if(checkOwned()) + if(isFocusObject && checkOwned()) { mDynamicToolTipBox->changeWidgetSkin("HUD_Box_NoTransp_Owned"); } diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp index 983b50fe2..fa1ae4f88 100644 --- a/apps/openmw/mwgui/tooltips.hpp +++ b/apps/openmw/mwgui/tooltips.hpp @@ -98,8 +98,9 @@ namespace MWGui MyGUI::IntSize getToolTipViaPtr (bool image=true); ///< @return requested tooltip size - MyGUI::IntSize createToolTip(const ToolTipInfo& info); + MyGUI::IntSize createToolTip(const ToolTipInfo& info, bool isFocusObject); ///< @return requested tooltip size + /// @param isFocusObject Is the object this tooltips originates from mFocusObject? float mFocusToolTipX; float mFocusToolTipY; From fbee32729acb8af7e397b927031ac09e605ca84a Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 26 Nov 2015 23:46:41 +0100 Subject: [PATCH 2595/3725] Cache CellId ESM::Cell::getCellId() was allocating a string on every call. This caused functions dealing with cellIds to be unnecessarily expensive. For example, World::moveObject spent almost as much time comparing CellIds as it did updating Bullet's AABB after the move. OpGetDistance was by far the most expensive script instruction because it has to compare cellIds. The total cost of getCellId() relative to the frame loop was about 0.3%. --- apps/openmw/mwstate/statemanagerimp.cpp | 2 +- components/esm/loadcell.cpp | 36 ++++++++++++------------- components/esm/loadcell.hpp | 6 +++-- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 6a780f2ca..b76d9eae5 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -475,7 +475,7 @@ void MWState::StateManager::loadGame (const Character *character, const std::str MWWorld::Ptr ptr = MWMechanics::getPlayer(); - ESM::CellId cellId = ptr.getCell()->getCell()->getCellId(); + const ESM::CellId& cellId = ptr.getCell()->getCell()->getCellId(); // Use detectWorldSpaceChange=false, otherwise some of the data we just loaded would be cleared again MWBase::Environment::get().getWorld()->changeToCell (cellId, ptr.getRefData().getPosition(), false); diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index 8455daeac..eb9d6b8d8 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -91,6 +91,21 @@ namespace ESM if (!hasData) esm.fail("Missing DATA subrecord"); + + mCellId.mPaged = !(mData.mFlags & Interior); + + if (mCellId.mPaged) + { + mCellId.mWorldspace = "sys::default"; + mCellId.mIndex.mX = mData.mX; + mCellId.mIndex.mY = mData.mY; + } + else + { + mCellId.mWorldspace = Misc::StringUtils::lowerCase (mName); + mCellId.mIndex.mX = 0; + mCellId.mIndex.mY = 0; + } } void Cell::loadCell(ESMReader &esm, bool saveContext) @@ -266,25 +281,8 @@ namespace ESM mAmbi.mFogDensity = 0; } - CellId Cell::getCellId() const + const CellId& Cell::getCellId() const { - CellId id; - - id.mPaged = !(mData.mFlags & Interior); - - if (id.mPaged) - { - id.mWorldspace = "sys::default"; - id.mIndex.mX = mData.mX; - id.mIndex.mY = mData.mY; - } - else - { - id.mWorldspace = Misc::StringUtils::lowerCase (mName); - id.mIndex.mX = 0; - id.mIndex.mY = 0; - } - - return id; + return mCellId; } } diff --git a/components/esm/loadcell.hpp b/components/esm/loadcell.hpp index 2a7a78a54..f92e0b5b7 100644 --- a/components/esm/loadcell.hpp +++ b/components/esm/loadcell.hpp @@ -8,6 +8,7 @@ #include "esmcommon.hpp" #include "defs.hpp" #include "cellref.hpp" +#include "cellid.hpp" namespace MWWorld { @@ -18,7 +19,6 @@ namespace ESM { class ESMReader; class ESMWriter; -struct CellId; /* Moved cell reference tracking object. This mainly stores the target cell of the reference, so we can easily know where it has been moved when another @@ -97,6 +97,8 @@ struct Cell std::vector mContextList; // File position; multiple positions for multiple plugin support DATAstruct mData; + CellId mCellId; + AMBIstruct mAmbi; float mWater; // Water level @@ -173,7 +175,7 @@ struct Cell void blank(); ///< Set record to default state (does not touch the ID/index). - CellId getCellId() const; + const CellId& getCellId() const; }; } #endif From 783594033ad9c7be1461163d4f37b7d03aa423b0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 27 Nov 2015 01:02:29 +0100 Subject: [PATCH 2596/3725] Optimize MWMechanics::Spells Use pointers as map keys instead of string IDs. Resolves a nasty performance bottleneck on functions like hasCommonDisease() that previously had to look up all contained spells from the ESM store on every call. hasCommonDisease() is called hundreds of times per frame by the AI target update since it's used to calculate target disposition. The total cost of hasCommonDisease() was 2.7% of the frame loop, now it's negligible. --- apps/openmw/mwgui/spellbuyingwindow.cpp | 7 +- apps/openmw/mwgui/spellcreationdialog.cpp | 3 +- apps/openmw/mwgui/spellmodel.cpp | 6 +- apps/openmw/mwmechanics/aicombataction.cpp | 2 +- apps/openmw/mwmechanics/disease.hpp | 3 +- apps/openmw/mwmechanics/spellcasting.cpp | 4 +- apps/openmw/mwmechanics/spells.cpp | 144 +++++++++++---------- apps/openmw/mwmechanics/spells.hpp | 24 ++-- apps/openmw/mwworld/worldimp.cpp | 2 +- 9 files changed, 102 insertions(+), 93 deletions(-) diff --git a/apps/openmw/mwgui/spellbuyingwindow.cpp b/apps/openmw/mwgui/spellbuyingwindow.cpp index 8c4520662..843731cff 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.cpp +++ b/apps/openmw/mwgui/spellbuyingwindow.cpp @@ -95,8 +95,7 @@ namespace MWGui for (MWMechanics::Spells::TIterator iter = merchantSpells.begin(); iter!=merchantSpells.end(); ++iter) { - const ESM::Spell* spell = - MWBase::Environment::get().getWorld()->getStore().get().find (iter->first); + const ESM::Spell* spell = iter->first; if (spell->mData.mType!=ESM::Spell::ST_Spell) continue; // don't try to sell diseases, curses or powers @@ -110,10 +109,10 @@ namespace MWGui continue; } - if (playerHasSpell(iter->first)) + if (playerHasSpell(iter->first->mId)) continue; - addSpell (iter->first); + addSpell (iter->first->mId); } updateLabels(); diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index ff5a27abe..64d4d86c6 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -516,8 +516,7 @@ namespace MWGui for (MWMechanics::Spells::TIterator it = spells.begin(); it != spells.end(); ++it) { - const ESM::Spell* spell = - MWBase::Environment::get().getWorld()->getStore().get().find (it->first); + const ESM::Spell* spell = it->first; // only normal spells count if (spell->mData.mType != ESM::Spell::ST_Spell) diff --git a/apps/openmw/mwgui/spellmodel.cpp b/apps/openmw/mwgui/spellmodel.cpp index 58ec05794..0d3b64f78 100644 --- a/apps/openmw/mwgui/spellmodel.cpp +++ b/apps/openmw/mwgui/spellmodel.cpp @@ -52,7 +52,7 @@ namespace MWGui for (MWMechanics::Spells::TIterator it = spells.begin(); it != spells.end(); ++it) { - const ESM::Spell* spell = esmStore.get().find(it->first); + const ESM::Spell* spell = it->first; if (spell->mData.mType != ESM::Spell::ST_Power && spell->mData.mType != ESM::Spell::ST_Spell) continue; @@ -67,9 +67,9 @@ namespace MWGui } else newSpell.mType = Spell::Type_Power; - newSpell.mId = it->first; + newSpell.mId = spell->mId; - newSpell.mSelected = (MWBase::Environment::get().getWindowManager()->getSelectedSpell() == it->first); + newSpell.mSelected = (MWBase::Environment::get().getWindowManager()->getSelectedSpell() == spell->mId); newSpell.mActive = true; mSpells.push_back(newSpell); } diff --git a/apps/openmw/mwmechanics/aicombataction.cpp b/apps/openmw/mwmechanics/aicombataction.cpp index 33e3c3d67..60446e524 100644 --- a/apps/openmw/mwmechanics/aicombataction.cpp +++ b/apps/openmw/mwmechanics/aicombataction.cpp @@ -541,7 +541,7 @@ namespace MWMechanics for (Spells::TIterator it = spells.begin(); it != spells.end(); ++it) { - const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get().find(it->first); + const ESM::Spell* spell = it->first; float rating = rateSpell(spell, actor, target); if (rating > bestActionRating) diff --git a/apps/openmw/mwmechanics/disease.hpp b/apps/openmw/mwmechanics/disease.hpp index 27c19364f..25bde56ab 100644 --- a/apps/openmw/mwmechanics/disease.hpp +++ b/apps/openmw/mwmechanics/disease.hpp @@ -34,8 +34,7 @@ namespace MWMechanics Spells& spells = carrier.getClass().getCreatureStats(carrier).getSpells(); for (Spells::TIterator it = spells.begin(); it != spells.end(); ++it) { - const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get().find(it->first); - + const ESM::Spell* spell = it->first; if (actor.getClass().getCreatureStats(actor).getSpells().hasSpell(spell->mId)) continue; diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 70d097687..2485091ea 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -124,7 +124,7 @@ namespace MWMechanics } if (spell->mData.mType == ESM::Spell::ST_Power) - return stats.getSpells().canUsePower(spell->mId) ? 100 : 0; + return stats.getSpells().canUsePower(spell) ? 100 : 0; if (spell->mData.mType != ESM::Spell::ST_Spell) return 100; @@ -823,7 +823,7 @@ namespace MWMechanics // A power can be used once per 24h if (spell->mData.mType == ESM::Spell::ST_Power) - stats.getSpells().usePower(spell->mId); + stats.getSpells().usePower(spell); } if (mCaster == getPlayer() && spellIncreasesSkill(spell)) diff --git a/apps/openmw/mwmechanics/spells.cpp b/apps/openmw/mwmechanics/spells.cpp index 330d78a20..a88b6b263 100644 --- a/apps/openmw/mwmechanics/spells.cpp +++ b/apps/openmw/mwmechanics/spells.cpp @@ -25,9 +25,24 @@ namespace MWMechanics return mSpells.end(); } + const ESM::Spell* Spells::getSpell(const std::string& id) const + { + return MWBase::Environment::get().getWorld()->getStore().get().find(id); + } + + bool Spells::hasSpell(const std::string &spell) const + { + return hasSpell(getSpell(spell)); + } + + bool Spells::hasSpell(const ESM::Spell *spell) const + { + return mSpells.find(spell) != mSpells.end(); + } + void Spells::add (const ESM::Spell* spell) { - if (mSpells.find (spell->mId)==mSpells.end()) + if (mSpells.find (spell)==mSpells.end()) { std::map random; @@ -48,32 +63,32 @@ namespace MWMechanics corprus.mWorsenings = 0; corprus.mNextWorsening = MWBase::Environment::get().getWorld()->getTimeStamp() + CorprusStats::sWorseningPeriod; - mCorprusSpells[spell->mId] = corprus; + mCorprusSpells[spell] = corprus; } - mSpells.insert (std::make_pair (spell->mId, random)); + mSpells.insert (std::make_pair (spell, random)); } } void Spells::add (const std::string& spellId) { - const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get().find(spellId); - add(spell); + add(getSpell(spellId)); } void Spells::remove (const std::string& spellId) { - std::string lower = Misc::StringUtils::lowerCase(spellId); - TContainer::iterator iter = mSpells.find (lower); - std::map::iterator corprusIt = mCorprusSpells.find(lower); + const ESM::Spell* spell = getSpell(spellId); + TContainer::iterator iter = mSpells.find (spell); + + std::map::iterator corprusIt = mCorprusSpells.find(spell); // if it's corprus, remove negative and keep positive effects if (corprusIt != mCorprusSpells.end()) { - worsenCorprus(lower); - if (mPermanentSpellEffects.find(lower) != mPermanentSpellEffects.end()) + worsenCorprus(spell); + if (mPermanentSpellEffects.find(spell) != mPermanentSpellEffects.end()) { - MagicEffects & effects = mPermanentSpellEffects[lower]; + MagicEffects & effects = mPermanentSpellEffects[spell]; for (MagicEffects::Collection::const_iterator effectIt = effects.begin(); effectIt != effects.end();) { const ESM::MagicEffect * magicEffect = MWBase::Environment::get().getWorld()->getStore().get().find(effectIt->first.mId); @@ -101,8 +116,7 @@ namespace MWMechanics for (TIterator iter = mSpells.begin(); iter!=mSpells.end(); ++iter) { - const ESM::Spell *spell = - MWBase::Environment::get().getWorld()->getStore().get().find (iter->first); + const ESM::Spell *spell = iter->first; if (spell->mData.mType==ESM::Spell::ST_Ability || spell->mData.mType==ESM::Spell::ST_Blight || spell->mData.mType==ESM::Spell::ST_Disease || spell->mData.mType==ESM::Spell::ST_Curse) @@ -120,7 +134,7 @@ namespace MWMechanics } } - for (std::map::const_iterator it = mPermanentSpellEffects.begin(); it != mPermanentSpellEffects.end(); ++it) + for (std::map::const_iterator it = mPermanentSpellEffects.begin(); it != mPermanentSpellEffects.end(); ++it) { effects += it->second; } @@ -145,11 +159,10 @@ namespace MWMechanics bool Spells::isSpellActive(const std::string &id) const { - TContainer::const_iterator found = mSpells.find(id); + TContainer::const_iterator found = mSpells.find(getSpell(id)); if (found != mSpells.end()) { - const ESM::Spell *spell = - MWBase::Environment::get().getWorld()->getStore().get().find (id); + const ESM::Spell *spell = found->first; return (spell->mData.mType==ESM::Spell::ST_Ability || spell->mData.mType==ESM::Spell::ST_Blight || spell->mData.mType==ESM::Spell::ST_Disease || spell->mData.mType==ESM::Spell::ST_Curse); @@ -161,9 +174,7 @@ namespace MWMechanics { for (TIterator iter = mSpells.begin(); iter!=mSpells.end(); ++iter) { - const ESM::Spell *spell = - MWBase::Environment::get().getWorld()->getStore().get().find (iter->first); - + const ESM::Spell *spell = iter->first; if (spell->mData.mType == ESM::Spell::ST_Disease) return true; } @@ -175,9 +186,7 @@ namespace MWMechanics { for (TIterator iter = mSpells.begin(); iter!=mSpells.end(); ++iter) { - const ESM::Spell *spell = - MWBase::Environment::get().getWorld()->getStore().get().find (iter->first); - + const ESM::Spell *spell = iter->first; if (spell->mData.mType == ESM::Spell::ST_Blight) return true; } @@ -189,9 +198,7 @@ namespace MWMechanics { for (TContainer::iterator iter = mSpells.begin(); iter!=mSpells.end();) { - const ESM::Spell *spell = - MWBase::Environment::get().getWorld()->getStore().get().find (iter->first); - + const ESM::Spell *spell = iter->first; if (spell->mData.mType == ESM::Spell::ST_Disease) mSpells.erase(iter++); else @@ -203,9 +210,7 @@ namespace MWMechanics { for (TContainer::iterator iter = mSpells.begin(); iter!=mSpells.end();) { - const ESM::Spell *spell = - MWBase::Environment::get().getWorld()->getStore().get().find (iter->first); - + const ESM::Spell *spell = iter->first; if (spell->mData.mType == ESM::Spell::ST_Blight && !hasCorprusEffect(spell)) mSpells.erase(iter++); else @@ -217,9 +222,7 @@ namespace MWMechanics { for (TContainer::iterator iter = mSpells.begin(); iter!=mSpells.end();) { - const ESM::Spell *spell = - MWBase::Environment::get().getWorld()->getStore().get().find (iter->first); - + const ESM::Spell *spell = iter->first; if (hasCorprusEffect(spell)) mSpells.erase(iter++); else @@ -231,9 +234,7 @@ namespace MWMechanics { for (TContainer::iterator iter = mSpells.begin(); iter!=mSpells.end();) { - const ESM::Spell *spell = - MWBase::Environment::get().getWorld()->getStore().get().find (iter->first); - + const ESM::Spell *spell = iter->first; if (spell->mData.mType == ESM::Spell::ST_Curse) mSpells.erase(iter++); else @@ -245,7 +246,7 @@ namespace MWMechanics { for (TIterator it = begin(); it != end(); ++it) { - const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get().find(it->first); + const ESM::Spell* spell = it->first; // these are the spell types that are permanently in effect if (!(spell->mData.mType == ESM::Spell::ST_Ability) @@ -268,14 +269,13 @@ namespace MWMechanics } } - void Spells::worsenCorprus(const std::string &corpSpellId) + void Spells::worsenCorprus(const ESM::Spell* spell) { - mCorprusSpells[corpSpellId].mNextWorsening = MWBase::Environment::get().getWorld()->getTimeStamp() + CorprusStats::sWorseningPeriod; - mCorprusSpells[corpSpellId].mWorsenings++; + mCorprusSpells[spell].mNextWorsening = MWBase::Environment::get().getWorld()->getTimeStamp() + CorprusStats::sWorseningPeriod; + mCorprusSpells[spell].mWorsenings++; // update worsened effects - mPermanentSpellEffects[corpSpellId] = MagicEffects(); - const ESM::Spell * spell = MWBase::Environment::get().getWorld()->getStore().get().find(corpSpellId); + mPermanentSpellEffects[spell] = MagicEffects(); int i=0; for (std::vector::const_iterator effectIt = spell->mEffects.mList.begin(); effectIt != spell->mEffects.mList.end(); ++effectIt, ++i) { @@ -283,12 +283,12 @@ namespace MWMechanics if ((effectIt->mEffectID != ESM::MagicEffect::Corprus) && (magicEffect->mData.mFlags & ESM::MagicEffect::UncappedDamage)) // APPLIED_ONCE { float random = 1.f; - if (mSpells[corpSpellId].find(i) != mSpells[corpSpellId].end()) - random = mSpells[corpSpellId].at(i); + if (mSpells[spell].find(i) != mSpells[spell].end()) + random = mSpells[spell].at(i); float magnitude = effectIt->mMagnMin + (effectIt->mMagnMax - effectIt->mMagnMin) * random; - magnitude *= std::max(1, mCorprusSpells[corpSpellId].mWorsenings); - mPermanentSpellEffects[corpSpellId].add(MWMechanics::EffectKey(*effectIt), MWMechanics::EffectParam(magnitude)); + magnitude *= std::max(1, mCorprusSpells[spell].mWorsenings); + mPermanentSpellEffects[spell].add(MWMechanics::EffectKey(*effectIt), MWMechanics::EffectParam(magnitude)); } } } @@ -305,43 +305,47 @@ namespace MWMechanics return false; } - const std::map &Spells::getCorprusSpells() const + const std::map &Spells::getCorprusSpells() const { return mCorprusSpells; } - bool Spells::canUsePower(const std::string &power) const + bool Spells::canUsePower(const ESM::Spell* spell) const { - std::map::const_iterator it = mUsedPowers.find(Misc::StringUtils::lowerCase(power)); + std::map::const_iterator it = mUsedPowers.find(spell); if (it == mUsedPowers.end() || it->second + 24 <= MWBase::Environment::get().getWorld()->getTimeStamp()) return true; else return false; } - void Spells::usePower(const std::string &power) + void Spells::usePower(const ESM::Spell* spell) { - mUsedPowers[Misc::StringUtils::lowerCase(power)] = MWBase::Environment::get().getWorld()->getTimeStamp(); + mUsedPowers[spell] = MWBase::Environment::get().getWorld()->getTimeStamp(); } void Spells::readState(const ESM::SpellState &state) { - for (TContainer::const_iterator it = state.mSpells.begin(); it != state.mSpells.end(); ++it) + for (ESM::SpellState::TContainer::const_iterator it = state.mSpells.begin(); it != state.mSpells.end(); ++it) { // Discard spells that are no longer available due to changed content files const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get().search(it->first); if (spell) { - mSpells[it->first] = it->second; + mSpells[spell] = it->second; if (it->first == state.mSelectedSpell) mSelectedSpell = it->first; } } - // No need to discard spells here (doesn't really matter if non existent ids are kept) for (std::map::const_iterator it = state.mUsedPowers.begin(); it != state.mUsedPowers.end(); ++it) - mUsedPowers[it->first] = MWWorld::TimeStamp(it->second); + { + const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get().search(it->first); + if (!spell) + continue; + mUsedPowers[spell] = MWWorld::TimeStamp(it->second); + } for (std::map >::const_iterator it = state.mPermanentSpellEffects.begin(); it != state.mPermanentSpellEffects.end(); ++it) @@ -350,33 +354,35 @@ namespace MWMechanics if (!spell) continue; - mPermanentSpellEffects[it->first] = MagicEffects(); + mPermanentSpellEffects[spell] = MagicEffects(); for (std::vector::const_iterator effectIt = it->second.begin(); effectIt != it->second.end(); ++effectIt) { - mPermanentSpellEffects[it->first].add(EffectKey(effectIt->mId, effectIt->mArg), effectIt->mMagnitude); + mPermanentSpellEffects[spell].add(EffectKey(effectIt->mId, effectIt->mArg), effectIt->mMagnitude); } } mCorprusSpells.clear(); for (std::map::const_iterator it = state.mCorprusSpells.begin(); it != state.mCorprusSpells.end(); ++it) { - if (mSpells.find(it->first) != mSpells.end()) // Discard unavailable corprus spells - { - mCorprusSpells[it->first].mWorsenings = state.mCorprusSpells.at(it->first).mWorsenings; - mCorprusSpells[it->first].mNextWorsening = MWWorld::TimeStamp(state.mCorprusSpells.at(it->first).mNextWorsening); - } + const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get().search(it->first); + if (!spell) // Discard unavailable corprus spells + continue; + mCorprusSpells[spell].mWorsenings = state.mCorprusSpells.at(it->first).mWorsenings; + mCorprusSpells[spell].mNextWorsening = MWWorld::TimeStamp(state.mCorprusSpells.at(it->first).mNextWorsening); } } void Spells::writeState(ESM::SpellState &state) const { - state.mSpells = mSpells; + for (TContainer::const_iterator it = mSpells.begin(); it != mSpells.end(); ++it) + state.mSpells.insert(std::make_pair(it->first->mId, it->second)); + state.mSelectedSpell = mSelectedSpell; - for (std::map::const_iterator it = mUsedPowers.begin(); it != mUsedPowers.end(); ++it) - state.mUsedPowers[it->first] = it->second.toEsm(); + for (std::map::const_iterator it = mUsedPowers.begin(); it != mUsedPowers.end(); ++it) + state.mUsedPowers[it->first->mId] = it->second.toEsm(); - for (std::map::const_iterator it = mPermanentSpellEffects.begin(); it != mPermanentSpellEffects.end(); ++it) + for (std::map::const_iterator it = mPermanentSpellEffects.begin(); it != mPermanentSpellEffects.end(); ++it) { std::vector effectList; for (MagicEffects::Collection::const_iterator effectIt = it->second.begin(); effectIt != it->second.end(); ++effectIt) @@ -388,13 +394,13 @@ namespace MWMechanics effectList.push_back(info); } - state.mPermanentSpellEffects[it->first] = effectList; + state.mPermanentSpellEffects[it->first->mId] = effectList; } - for (std::map::const_iterator it = mCorprusSpells.begin(); it != mCorprusSpells.end(); ++it) + for (std::map::const_iterator it = mCorprusSpells.begin(); it != mCorprusSpells.end(); ++it) { - state.mCorprusSpells[it->first].mWorsenings = mCorprusSpells.at(it->first).mWorsenings; - state.mCorprusSpells[it->first].mNextWorsening = mCorprusSpells.at(it->first).mNextWorsening.toEsm(); + state.mCorprusSpells[it->first->mId].mWorsenings = mCorprusSpells.at(it->first).mWorsenings; + state.mCorprusSpells[it->first->mId].mNextWorsening = mCorprusSpells.at(it->first).mNextWorsening.toEsm(); } } } diff --git a/apps/openmw/mwmechanics/spells.hpp b/apps/openmw/mwmechanics/spells.hpp index 6b4149939..1b1993d5e 100644 --- a/apps/openmw/mwmechanics/spells.hpp +++ b/apps/openmw/mwmechanics/spells.hpp @@ -31,7 +31,9 @@ namespace MWMechanics { public: - typedef std::map > TContainer; // ID, + typedef const ESM::Spell* SpellKey; + + typedef std::map > TContainer; // ID, typedef TContainer::const_iterator TIterator; struct CorprusStats @@ -47,23 +49,26 @@ namespace MWMechanics TContainer mSpells; // spell-tied effects that will be applied even after removing the spell (currently used to keep positive effects when corprus is removed) - std::map mPermanentSpellEffects; + std::map mPermanentSpellEffects; // Note: this is the spell that's about to be cast, *not* the spell selected in the GUI (which may be different) std::string mSelectedSpell; - std::map mUsedPowers; + std::map mUsedPowers; + + std::map mCorprusSpells; - std::map mCorprusSpells; + /// Get spell from ID, throws exception if not found + const ESM::Spell* getSpell(const std::string& id) const; public: - void worsenCorprus(const std::string &corpSpellId); + void worsenCorprus(const ESM::Spell* spell); static bool hasCorprusEffect(const ESM::Spell *spell); - const std::map & getCorprusSpells() const; + const std::map & getCorprusSpells() const; - bool canUsePower (const std::string& power) const; - void usePower (const std::string& power); + bool canUsePower (const ESM::Spell* spell) const; + void usePower (const ESM::Spell* spell); void purgeCommonDisease(); void purgeBlightDisease(); @@ -74,7 +79,8 @@ namespace MWMechanics TIterator end() const; - bool hasSpell(const std::string& spell) const { return mSpells.find(Misc::StringUtils::lowerCase(spell)) != mSpells.end(); } + bool hasSpell(const std::string& spell) const; + bool hasSpell(const ESM::Spell* spell) const; void add (const std::string& spell); ///< Adding a spell that is already listed in *this is a no-op. diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index df2e577d1..03a64bce8 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2581,7 +2581,7 @@ namespace MWWorld } // If this is a power, check if it was already used in the last 24h - if (!fail && spell->mData.mType == ESM::Spell::ST_Power && !stats.getSpells().canUsePower(spell->mId)) + if (!fail && spell->mData.mType == ESM::Spell::ST_Power && !stats.getSpells().canUsePower(spell)) { message = "#{sPowerAlreadyUsed}"; fail = true; From 44dd62067e31ab32745e148aa4a353146c7a356c Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 27 Nov 2015 02:10:10 +0100 Subject: [PATCH 2597/3725] Remove some unnecessary per-frame store searches --- apps/openmw/mwmechanics/actors.cpp | 4 ++-- apps/openmw/mwmechanics/creaturestats.cpp | 6 ++++-- apps/openmw/mwworld/worldimp.cpp | 3 ++- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 59f8ecbc0..02b73bff7 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -838,7 +838,7 @@ namespace MWMechanics if (ptr.getClass().isClass(ptr, "Guard") && creatureStats.getAiSequence().getTypeId() != AiPackage::TypeIdPursue && !creatureStats.getAiSequence().isInCombat()) { const MWWorld::ESMStore& esmStore = MWBase::Environment::get().getWorld()->getStore(); - int cutoff = esmStore.get().find("iCrimeThreshold")->getInt(); + static const int cutoff = esmStore.get().find("iCrimeThreshold")->getInt(); // Force dialogue on sight if bounty is greater than the cutoff // In vanilla morrowind, the greeting dialogue is scripted to either arrest the player (< 5000 bounty) or attack (>= 5000 bounty) if ( player.getClass().getNpcStats(player).getBounty() >= cutoff @@ -846,7 +846,7 @@ namespace MWMechanics && MWBase::Environment::get().getWorld()->getLOS(ptr, player) && MWBase::Environment::get().getMechanicsManager()->awarenessCheck(player, ptr)) { - static int iCrimeThresholdMultiplier = esmStore.get().find("iCrimeThresholdMultiplier")->getInt(); + static const int iCrimeThresholdMultiplier = esmStore.get().find("iCrimeThresholdMultiplier")->getInt(); if (player.getClass().getNpcStats(player).getBounty() >= cutoff * iCrimeThresholdMultiplier) MWBase::Environment::get().getMechanicsManager()->startCombat(ptr, player); else diff --git a/apps/openmw/mwmechanics/creaturestats.cpp b/apps/openmw/mwmechanics/creaturestats.cpp index 0638637fa..602e54a09 100644 --- a/apps/openmw/mwmechanics/creaturestats.cpp +++ b/apps/openmw/mwmechanics/creaturestats.cpp @@ -48,8 +48,10 @@ namespace MWMechanics const MWWorld::Store &gmst = MWBase::Environment::get().getWorld()->getStore().get(); - return gmst.find ("fFatigueBase")->getFloat() - - gmst.find ("fFatigueMult")->getFloat() * (1-normalised); + static const float fFatigueBase = gmst.find("fFatigueBase")->getFloat(); + static const float fFatigueMult = gmst.find("fFatigueMult")->getFloat(); + + return fFatigueBase - fFatigueMult * (1-normalised); } const AttributeValue &CreatureStats::getAttribute(int index) const diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index df2e577d1..896e95ec6 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1009,7 +1009,8 @@ namespace MWWorld if (mActivationDistanceOverride >= 0) return static_cast(mActivationDistanceOverride); - return getStore().get().find("iMaxActivateDist")->getFloat() * 5 / 4; + static const int iMaxActivateDist = getStore().get().find("iMaxActivateDist")->getInt(); + return iMaxActivateDist * 5.f / 4.f; } MWWorld::Ptr World::getFacedObject() From 27e669296e54621472ed5578103ad4306f8a94a9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 27 Nov 2015 03:22:52 +0100 Subject: [PATCH 2598/3725] StringUtils: use the locale-unaware tolower function There is no change in behaviour since we were using the C locale. The locale-aware tolower is much slower than the locale-unaware one. At least on Linux/GCC it calls dynamic_cast's, and is overall slower by an order of magnitude. --- components/misc/stringops.cpp | 8 -------- components/misc/stringops.hpp | 11 ++++------- 2 files changed, 4 insertions(+), 15 deletions(-) delete mode 100644 components/misc/stringops.cpp diff --git a/components/misc/stringops.cpp b/components/misc/stringops.cpp deleted file mode 100644 index 723c1c1e0..000000000 --- a/components/misc/stringops.cpp +++ /dev/null @@ -1,8 +0,0 @@ -#include "stringops.hpp" - -namespace Misc -{ - -std::locale StringUtils::mLocale = std::locale::classic(); - -} diff --git a/components/misc/stringops.hpp b/components/misc/stringops.hpp index 04dedb072..d6bc19069 100644 --- a/components/misc/stringops.hpp +++ b/components/misc/stringops.hpp @@ -4,18 +4,15 @@ #include #include #include -#include namespace Misc { class StringUtils { - - static std::locale mLocale; struct ci { bool operator()(char x, char y) const { - return std::tolower(x, StringUtils::mLocale) < std::tolower(y, StringUtils::mLocale); + return tolower(x) < tolower(y); } }; @@ -31,7 +28,7 @@ public: std::string::const_iterator xit = x.begin(); std::string::const_iterator yit = y.begin(); for (; xit != x.end(); ++xit, ++yit) { - if (std::tolower(*xit, mLocale) != std::tolower(*yit, mLocale)) { + if (tolower(*xit) != tolower(*yit)) { return false; } } @@ -45,7 +42,7 @@ public: for(;xit != x.end() && yit != y.end() && len > 0;++xit,++yit,--len) { int res = *xit - *yit; - if(res != 0 && std::tolower(*xit, mLocale) != std::tolower(*yit, mLocale)) + if(res != 0 && tolower(*xit) != tolower(*yit)) return (res > 0) ? 1 : -1; } if(len > 0) @@ -61,7 +58,7 @@ public: /// Transforms input string to lower case w/o copy static std::string &toLower(std::string &inout) { for (unsigned int i=0; i Date: Thu, 26 Nov 2015 09:11:52 -0800 Subject: [PATCH 2599/3725] Avoid unnecessarily friending classes --- apps/openmw/mwsound/sound.hpp | 23 +++++++++++++++-------- apps/openmw/mwsound/soundmanagerimp.cpp | 22 +++++++--------------- 2 files changed, 22 insertions(+), 23 deletions(-) diff --git a/apps/openmw/mwsound/sound.hpp b/apps/openmw/mwsound/sound.hpp index 53b258a6a..dd1685367 100644 --- a/apps/openmw/mwsound/sound.hpp +++ b/apps/openmw/mwsound/sound.hpp @@ -7,8 +7,6 @@ namespace MWSound { class Sound { - virtual void update() = 0; - Sound& operator=(const Sound &rhs); Sound(const Sound &rhs); @@ -20,19 +18,31 @@ namespace MWSound float mMinDistance; float mMaxDistance; int mFlags; + float mFadeOutTime; public: virtual void stop() = 0; virtual bool isPlaying() = 0; virtual double getTimeOffset() = 0; + virtual void update() = 0; void setPosition(const osg::Vec3f &pos) { mPos = pos; } void setVolume(float volume) { mVolume = volume; } - void setFadeout(float duration) { mFadeOutTime=duration; } + void setBaseVolume(float volume) { mBaseVolume = volume; } + void setFadeout(float duration) { mFadeOutTime = duration; } + void updateFade(float duration) + { + if(mFadeOutTime > 0.0f) + { + float soundDuration = std::min(duration, mFadeOutTime); + mVolume *= (mFadeOutTime-soundDuration) / mFadeOutTime; + mFadeOutTime -= soundDuration; + } + } MWBase::SoundManager::PlayType getPlayType() const { return (MWBase::SoundManager::PlayType)(mFlags&MWBase::SoundManager::Play_TypeMask); } - + bool getDistanceCull() const { return mFlags&MWBase::SoundManager::Play_RemoveAtDistance; } Sound(const osg::Vec3f& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags) : mPos(pos) @@ -42,12 +52,9 @@ namespace MWSound , mMinDistance(mindist) , mMaxDistance(maxdist) , mFlags(flags) - , mFadeOutTime(0) + , mFadeOutTime(0.0f) { } virtual ~Sound() { } - - friend class OpenAL_Output; - friend class SoundManager; }; } diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 4d0c7912c..a125494ad 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -828,10 +828,9 @@ namespace MWSound const osg::Vec3f objpos(pos.asVec3()); sound->setPosition(objpos); - if((sound->mFlags&Play_RemoveAtDistance)) + if(sound->getDistanceCull()) { - osg::Vec3f diff = mListenerPos - ptr.getRefData().getPosition().asVec3(); - if(diff.length2() > 2000*2000) + if((mListenerPos - objpos).length2() > 2000*2000) sound->stop(); } } @@ -839,15 +838,8 @@ namespace MWSound if(!sound->isPlaying()) return false; - // Update fade out - if(sound->mFadeOutTime > 0.0f) - { - float soundDuration = duration; - if(soundDuration > sound->mFadeOutTime) - soundDuration = sound->mFadeOutTime; - sound->setVolume(sound->mVolume - soundDuration/sound->mFadeOutTime*sound->mVolume); - sound->mFadeOutTime -= soundDuration; - } + sound->updateFade(duration); + sound->update(); return true; } @@ -885,7 +877,7 @@ namespace MWSound for(;sndidx != snditer->second.end();++sndidx) { MWBase::SoundPtr sound = sndidx->first; - sound->mBaseVolume = volumeFromType(sound->getPlayType()); + sound->setBaseVolume(volumeFromType(sound->getPlayType())); sound->update(); } } @@ -893,12 +885,12 @@ namespace MWSound for(;sayiter != mActiveSaySounds.end();++sayiter) { MWBase::SoundPtr sound = sayiter->second.first; - sound->mBaseVolume = volumeFromType(sound->getPlayType()); + sound->setBaseVolume(volumeFromType(sound->getPlayType())); sound->update(); } if(mMusic) { - mMusic->mBaseVolume = volumeFromType(mMusic->getPlayType()); + mMusic->setBaseVolume(volumeFromType(mMusic->getPlayType())); mMusic->update(); } mOutput->finishUpdate(); From 8b7587f9a699a7da1fffa2e76e30aca7d0f2f485 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 26 Nov 2015 09:33:16 -0800 Subject: [PATCH 2600/3725] Track whether a sound is 3D --- apps/openmw/mwsound/sound.hpp | 1 + apps/openmw/mwsound/soundmanagerimp.cpp | 10 ++++++---- apps/openmw/mwsound/soundmanagerimp.hpp | 5 +++++ 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwsound/sound.hpp b/apps/openmw/mwsound/sound.hpp index dd1685367..8ef1d25db 100644 --- a/apps/openmw/mwsound/sound.hpp +++ b/apps/openmw/mwsound/sound.hpp @@ -43,6 +43,7 @@ namespace MWSound MWBase::SoundManager::PlayType getPlayType() const { return (MWBase::SoundManager::PlayType)(mFlags&MWBase::SoundManager::Play_TypeMask); } bool getDistanceCull() const { return mFlags&MWBase::SoundManager::Play_RemoveAtDistance; } + bool getIs3D() const { return mFlags&Play_3D; } Sound(const osg::Vec3f& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags) : mPos(pos) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index a125494ad..aa51977cc 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -483,7 +483,7 @@ namespace MWSound float basevol = volumeFromType(type); sound = mOutput->playSound(sfx->mHandle, - volume * sfx->mVolume, basevol, pitch, mode|type, offset + volume * sfx->mVolume, basevol, pitch, mode|type|Play_2D, offset ); if(sfx->mUses++ == 0) { @@ -518,7 +518,8 @@ namespace MWSound return MWBase::SoundPtr(); sound = mOutput->playSound3D(sfx->mHandle, - objpos, volume * sfx->mVolume, basevol, pitch, sfx->mMinDist, sfx->mMaxDist, mode|type, offset + objpos, volume * sfx->mVolume, basevol, pitch, sfx->mMinDist, sfx->mMaxDist, + mode|type|Play_3D, offset ); if(sfx->mUses++ == 0) { @@ -548,7 +549,8 @@ namespace MWSound float basevol = volumeFromType(type); sound = mOutput->playSound3D(sfx->mHandle, - initialPos, volume * sfx->mVolume, basevol, pitch, sfx->mMinDist, sfx->mMaxDist, mode|type, offset + initialPos, volume * sfx->mVolume, basevol, pitch, sfx->mMinDist, sfx->mMaxDist, + mode|type|Play_3D, offset ); if(sfx->mUses++ == 0) { @@ -822,7 +824,7 @@ namespace MWSound bool SoundManager::updateSound(MWBase::SoundPtr sound, const MWWorld::Ptr& ptr, float duration) { - if(!ptr.isEmpty()) + if(!ptr.isEmpty() && sound->getIs3D()) { const ESM::Position &pos = ptr.getRefData().getPosition(); const osg::Vec3f objpos(pos.asVec3()); diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index 38bad2194..db0b06dc0 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -34,6 +34,11 @@ namespace MWSound Env_Normal, Env_Underwater }; + // Extra play flags, not intended for caller use + enum PlayModeEx { + Play_2D = 0, + Play_3D = 1<<31 + }; class SoundManager : public MWBase::SoundManager { From 82f3651f8130c4ad71cf4a5c4971accfe2619a36 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 26 Nov 2015 23:40:02 -0800 Subject: [PATCH 2601/3725] Treat the sound offset as the offset in seconds --- apps/openmw/mwbase/soundmanager.hpp | 4 ++-- apps/openmw/mwclass/door.cpp | 10 ++++---- apps/openmw/mwsound/openal_output.cpp | 31 ++++--------------------- apps/openmw/mwsound/openal_output.hpp | 2 -- apps/openmw/mwsound/sound_output.hpp | 4 ++-- apps/openmw/mwsound/soundmanagerimp.hpp | 8 +++---- 6 files changed, 16 insertions(+), 43 deletions(-) diff --git a/apps/openmw/mwbase/soundmanager.hpp b/apps/openmw/mwbase/soundmanager.hpp index 9366875e3..67203d0a4 100644 --- a/apps/openmw/mwbase/soundmanager.hpp +++ b/apps/openmw/mwbase/soundmanager.hpp @@ -109,13 +109,13 @@ namespace MWBase PlayType type=Play_TypeSfx, PlayMode mode=Play_Normal, float offset=0) = 0; ///< Play a sound, independently of 3D-position - ///< @param offset Value from [0,1] meaning from which fraction the sound the playback starts. + ///< @param offset Number of seconds into the sound to start playback. virtual MWBase::SoundPtr playSound3D(const MWWorld::Ptr &reference, const std::string& soundId, float volume, float pitch, PlayType type=Play_TypeSfx, PlayMode mode=Play_Normal, float offset=0) = 0; ///< Play a 3D sound attached to an MWWorld::Ptr. Will be updated automatically with the Ptr's position, unless Play_NoTrack is specified. - ///< @param offset Value from [0,1] meaning from which fraction the sound the playback starts. + ///< @param offset Number of seconds into the sound to start playback. virtual MWBase::SoundPtr playSound3D(const osg::Vec3f& initialPos, const std::string& soundId, float volume, float pitch, PlayType type=Play_TypeSfx, PlayMode mode=Play_Normal, float offset=0) = 0; diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index b469dc9e2..47219deb7 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -169,7 +169,9 @@ namespace MWClass { MWBase::Environment::get().getSoundManager()->fadeOutSound3D(ptr, closeSound, 0.5f); - float offset = doorRot/ 3.14159265f * 2.0f; + // Doors rotate at 90 degrees per second, so start the sound at + // where it would be at the current rotation. + float offset = doorRot/(3.14159265f * 0.5f); action->setSoundOffset(offset); action->setSound(openSound); } @@ -177,10 +179,8 @@ namespace MWClass { MWBase::Environment::get().getSoundManager()->fadeOutSound3D(ptr, openSound, 0.5f); - float offset = 1.0f - doorRot/ 3.14159265f * 2.0f; - //most if not all door have closing bang somewhere in the middle of the sound, - //so we divide offset by two - action->setSoundOffset(offset * 0.5f); + float offset = 1.0f - doorRot/(3.14159265f * 0.5f); + action->setSoundOffset(std::max(offset, 0.0f)); action->setSound(closeSound); } diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index bafd272af..a5246bde9 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -146,18 +146,6 @@ static ALenum getALFormat(ChannelConfig chans, SampleType type) return AL_NONE; } -static double getBufferLength(ALuint buffer) -{ - ALint bufferSize, frequency, channels, bitsPerSample; - alGetBufferi(buffer, AL_SIZE, &bufferSize); - alGetBufferi(buffer, AL_FREQUENCY, &frequency); - alGetBufferi(buffer, AL_CHANNELS, &channels); - alGetBufferi(buffer, AL_BITS, &bitsPerSample); - throwALerror(); - - return (8.0*bufferSize)/(frequency*channels*bitsPerSample); -} - // // A streaming OpenAL sound. @@ -863,14 +851,9 @@ MWBase::SoundPtr OpenAL_Output::playSound(Sound_Handle data, float vol, float ba } sound->updateAll(true); - if(offset < 0.0f) - offset = 0.0f; - if(offset > 1.0f) - offset = 1.0f; + alSourcei(src, AL_BUFFER, GET_PTRID(data)); + alSourcef(src, AL_SEC_OFFSET, offset/pitch); - ALuint buffer = GET_PTRID(data); - alSourcei(src, AL_BUFFER, buffer); - alSourcef(src, AL_SEC_OFFSET, static_cast(getBufferLength(buffer)*offset / pitch)); alSourcePlay(src); throwALerror(); @@ -898,14 +881,8 @@ MWBase::SoundPtr OpenAL_Output::playSound3D(Sound_Handle data, const osg::Vec3f } sound->updateAll(false); - if(offset < 0.0f) - offset = 0.0f; - if(offset > 1.0f) - offset = 1.0f; - - ALuint buffer = GET_PTRID(data); - alSourcei(src, AL_BUFFER, buffer); - alSourcef(src, AL_SEC_OFFSET, static_cast(getBufferLength(buffer)*offset / pitch)); + alSourcei(src, AL_BUFFER, GET_PTRID(data)); + alSourcef(src, AL_SEC_OFFSET, offset/pitch); alSourcePlay(src); throwALerror(); diff --git a/apps/openmw/mwsound/openal_output.hpp b/apps/openmw/mwsound/openal_output.hpp index 0f54da9b5..fdce32c8a 100644 --- a/apps/openmw/mwsound/openal_output.hpp +++ b/apps/openmw/mwsound/openal_output.hpp @@ -42,9 +42,7 @@ namespace MWSound virtual void unloadSound(Sound_Handle data); virtual size_t getSoundDataSize(Sound_Handle data) const; - /// @param offset Value from [0,1] meaning from which fraction the sound the playback starts. virtual MWBase::SoundPtr playSound(Sound_Handle data, float vol, float basevol, float pitch, int flags, float offset); - /// @param offset Value from [0,1] meaning from which fraction the sound the playback starts. virtual MWBase::SoundPtr playSound3D(Sound_Handle data, const osg::Vec3f &pos, float vol, float basevol, float pitch, float min, float max, int flags, float offset); virtual MWBase::SoundPtr streamSound(DecoderPtr decoder, float basevol, float pitch, int flags); diff --git a/apps/openmw/mwsound/sound_output.hpp b/apps/openmw/mwsound/sound_output.hpp index c91431f69..e358ba344 100644 --- a/apps/openmw/mwsound/sound_output.hpp +++ b/apps/openmw/mwsound/sound_output.hpp @@ -30,9 +30,9 @@ namespace MWSound virtual void unloadSound(Sound_Handle data) = 0; virtual size_t getSoundDataSize(Sound_Handle data) const = 0; - /// @param offset Value from [0,1] meaning from which fraction the sound the playback starts. + /// @param offset Number of seconds into the sound to start playback. virtual MWBase::SoundPtr playSound(Sound_Handle data, float vol, float basevol, float pitch, int flags, float offset) = 0; - /// @param offset Value from [0,1] meaning from which fraction the sound the playback starts. + /// @param offset Number of seconds into the sound to start playback. virtual MWBase::SoundPtr playSound3D(Sound_Handle data, const osg::Vec3f &pos, float vol, float basevol, float pitch, float min, float max, int flags, float offset) = 0; virtual MWBase::SoundPtr streamSound(DecoderPtr decoder, float basevol, float pitch, int flags) = 0; diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index db0b06dc0..fa855646d 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -166,20 +166,18 @@ namespace MWSound virtual MWBase::SoundPtr playSound(const std::string& soundId, float volume, float pitch, PlayType type=Play_TypeSfx, PlayMode mode=Play_Normal, float offset=0); ///< Play a sound, independently of 3D-position - ///< @param offset value from [0,1], when to start playback. 0 is beginning, 1 is end. + ///< @param offset Number of seconds into the sound to start playback. virtual MWBase::SoundPtr playSound3D(const MWWorld::Ptr &reference, const std::string& soundId, float volume, float pitch, PlayType type=Play_TypeSfx, PlayMode mode=Play_Normal, float offset=0); ///< Play a 3D sound attached to an MWWorld::Ptr. Will be updated automatically with the Ptr's position, unless Play_NoTrack is specified. - ///< @param offset Value from [0,1] meaning from which fraction the sound the playback starts. + ///< @param offset Number of seconds into the sound to start playback. virtual MWBase::SoundPtr playSound3D(const osg::Vec3f& initialPos, const std::string& soundId, float volume, float pitch, PlayType type, PlayMode mode, float offset=0); ///< Play a 3D sound at \a initialPos. If the sound should be moving, it must be updated using Sound::setPosition. - - ///< Play a sound from an object - ///< @param offset value from [0,1], when to start playback. 0 is beginning, 1 is end. + ///< @param offset Number of seconds into the sound to start playback. virtual void stopSound3D(const MWWorld::Ptr &reference, const std::string& soundId); ///< Stop the given object from playing the given sound, From 5f8a09df9728d3dbdd017857f46f5b8af973de8a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 27 Nov 2015 01:02:53 -0800 Subject: [PATCH 2602/3725] Play player sounds (except footsteps) local to the listener --- apps/openmw/mwbase/soundmanager.hpp | 12 +++++++----- apps/openmw/mwmechanics/character.cpp | 11 ++++++++--- apps/openmw/mwsound/soundmanagerimp.cpp | 13 +++++++++---- 3 files changed, 24 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwbase/soundmanager.hpp b/apps/openmw/mwbase/soundmanager.hpp index 67203d0a4..a91149777 100644 --- a/apps/openmw/mwbase/soundmanager.hpp +++ b/apps/openmw/mwbase/soundmanager.hpp @@ -38,15 +38,17 @@ namespace MWBase played by the PlayLoopSound family of script functions. Perhaps we can make this cut off a more subtle fade later, but have to be careful to not change the overall volume of areas by too much. */ + Play_NoPlayerLocal = 1<<3, /* (3D only) Don't play the sound local to the listener even if the + player is making it. */ Play_LoopNoEnv = Play_Loop | Play_NoEnv, Play_LoopRemoveAtDistance = Play_Loop | Play_RemoveAtDistance }; enum PlayType { - Play_TypeSfx = 1<<3, /* Normal SFX sound */ - Play_TypeVoice = 1<<4, /* Voice sound */ - Play_TypeFoot = 1<<5, /* Footstep sound */ - Play_TypeMusic = 1<<6, /* Music track */ - Play_TypeMovie = 1<<7, /* Movie audio track */ + Play_TypeSfx = 1<<4, /* Normal SFX sound */ + Play_TypeVoice = 1<<5, /* Voice sound */ + Play_TypeFoot = 1<<6, /* Footstep sound */ + Play_TypeMusic = 1<<7, /* Music track */ + Play_TypeMovie = 1<<8, /* Movie audio track */ Play_TypeMask = Play_TypeSfx|Play_TypeVoice|Play_TypeFoot|Play_TypeMusic|Play_TypeMovie }; diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index ff23844dd..f7f355a38 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -777,10 +777,15 @@ void CharacterController::handleTextKey(const std::string &groupname, const std: if(!sound.empty()) { MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); - MWBase::SoundManager::PlayType type = MWBase::SoundManager::Play_TypeSfx; if(evt.compare(10, evt.size()-10, "left") == 0 || evt.compare(10, evt.size()-10, "right") == 0 || evt.compare(10, evt.size()-10, "land") == 0) - type = MWBase::SoundManager::Play_TypeFoot; - sndMgr->playSound3D(mPtr, sound, volume, pitch, type); + { + // Don't make foot sounds local for the player, it makes sense to keep them + // positioned on the ground. + sndMgr->playSound3D(mPtr, sound, volume, pitch, MWBase::SoundManager::Play_TypeFoot, + MWBase::SoundManager::Play_NoPlayerLocal); + } + else + sndMgr->playSound3D(mPtr, sound, volume, pitch); } return; } diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index aa51977cc..5ae824393 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -517,10 +517,15 @@ namespace MWSound if((mode&Play_RemoveAtDistance) && (mListenerPos-objpos).length2() > 2000*2000) return MWBase::SoundPtr(); - sound = mOutput->playSound3D(sfx->mHandle, - objpos, volume * sfx->mVolume, basevol, pitch, sfx->mMinDist, sfx->mMaxDist, - mode|type|Play_3D, offset - ); + if(!(mode&Play_NoPlayerLocal) && ptr == MWMechanics::getPlayer()) + sound = mOutput->playSound(sfx->mHandle, + volume * sfx->mVolume, basevol, pitch, mode|type|Play_2D, offset + ); + else + sound = mOutput->playSound3D(sfx->mHandle, + objpos, volume * sfx->mVolume, basevol, pitch, sfx->mMinDist, sfx->mMaxDist, + mode|type|Play_3D, offset + ); if(sfx->mUses++ == 0) { SoundList::iterator iter = std::find(mUnusedBuffers.begin(), mUnusedBuffers.end(), sfx); From 21bb2e9314c68f49ca4fae9ec51c29957540252b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 27 Nov 2015 01:58:13 -0800 Subject: [PATCH 2603/3725] Use a deque for loudness buffers with a map lookup Similar to Sound_Buffer, this allows individual Sound_Loudness objects to retain a constant pointer when new ones are inserted on to the end. --- apps/openmw/mwsound/soundmanagerimp.cpp | 45 +++++++++++++++---------- apps/openmw/mwsound/soundmanagerimp.hpp | 13 ++++--- 2 files changed, 35 insertions(+), 23 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 5ae824393..0cdaddfd2 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -212,7 +212,7 @@ namespace MWSound return sfx; } - DecoderPtr SoundManager::loadVoice(const std::string &voicefile) + DecoderPtr SoundManager::loadVoice(const std::string &voicefile, Sound_Loudness **lipdata) { DecoderPtr decoder = getDecoder(); // Workaround: Bethesda at some point converted some of the files to mp3, but the references were kept as .wav. @@ -227,8 +227,12 @@ namespace MWSound decoder->open(file); } - NameLoudnessMap::iterator lipiter = mVoiceLipBuffers.find(voicefile); - if(lipiter != mVoiceLipBuffers.end()) return decoder; + NameLoudnessRefMap::iterator lipiter = mVoiceLipNameMap.find(voicefile); + if(lipiter != mVoiceLipNameMap.end()) + { + *lipdata = lipiter->second; + return decoder; + } ChannelConfig chans; SampleType type; @@ -241,9 +245,13 @@ namespace MWSound Sound_Loudness loudness; loudness.analyzeLoudness(data, srate, chans, type, static_cast(sLoudnessFPS)); - mVoiceLipBuffers.insert(std::make_pair(voicefile, loudness)); + mVoiceLipBuffers.insert(mVoiceLipBuffers.end(), loudness); + lipiter = mVoiceLipNameMap.insert( + std::make_pair(voicefile, &mVoiceLipBuffers.back()) + ).first; decoder->rewind(); + *lipdata = lipiter->second; return decoder; } @@ -375,17 +383,19 @@ namespace MWSound static float minDistance = std::max(fAudioVoiceDefaultMinDistance * fAudioMinDistanceMult, 1.0f); static float maxDistance = std::max(fAudioVoiceDefaultMaxDistance * fAudioMaxDistanceMult, minDistance); - std::string voicefile = "sound/"+Misc::StringUtils::lowerCase(filename); + std::string voicefile = "Sound/"+filename; float basevol = volumeFromType(Play_TypeVoice); const ESM::Position &pos = ptr.getRefData().getPosition(); const osg::Vec3f objpos(pos.asVec3()); - DecoderPtr decoder = loadVoice(voicefile); + Sound_Loudness *loudness; + mVFS->normalizeFilename(voicefile); + DecoderPtr decoder = loadVoice(voicefile, &loudness); MWBase::SoundPtr sound = mOutput->streamSound3D(decoder, objpos, 1.0f, basevol, 1.0f, minDistance, maxDistance, Play_Normal|Play_TypeVoice ); - mActiveSaySounds[ptr] = std::make_pair(sound, voicefile); + mActiveSaySounds[ptr] = std::make_pair(sound, loudness); } catch(std::exception &e) { @@ -399,13 +409,10 @@ namespace MWSound if(snditer != mActiveSaySounds.end()) { MWBase::SoundPtr sound = snditer->second.first; - NameLoudnessMap::const_iterator lipiter = mVoiceLipBuffers.find(snditer->second.second); - if(lipiter != mVoiceLipBuffers.end()) - { - float sec = sound->getTimeOffset(); - if(sound->isPlaying()) - return lipiter->second.getLoudnessAtTime(sec); - } + Sound_Loudness *loudness = snditer->second.second; + float sec = sound->getTimeOffset(); + if(sound->isPlaying()) + return loudness->getLoudnessAtTime(sec); } return 0.0f; @@ -417,15 +424,17 @@ namespace MWSound return; try { - std::string voicefile = "sound/"+Misc::StringUtils::lowerCase(filename); + std::string voicefile = "Sound/"+filename; float basevol = volumeFromType(Play_TypeVoice); - DecoderPtr decoder = loadVoice(voicefile); + Sound_Loudness *loudness; + mVFS->normalizeFilename(voicefile); + DecoderPtr decoder = loadVoice(voicefile, &loudness); MWBase::SoundPtr sound = mOutput->streamSound(decoder, basevol, 1.0f, Play_Normal|Play_TypeVoice ); - mActiveSaySounds[MWWorld::Ptr()] = std::make_pair(sound, voicefile); + mActiveSaySounds[MWWorld::Ptr()] = std::make_pair(sound, loudness); } catch(std::exception &e) { @@ -927,7 +936,7 @@ namespace MWSound SaySoundMap::iterator sayiter = mActiveSaySounds.find(old); if(sayiter != mActiveSaySounds.end()) { - SoundNamePair sndlist = sayiter->second; + SoundLoudnessPair sndlist = sayiter->second; mActiveSaySounds.erase(sayiter); mActiveSaySounds[updated] = sndlist; } diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index fa855646d..e12fe16fc 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -68,8 +68,11 @@ namespace MWSound typedef std::map NameBufferMap; NameBufferMap mBufferNameMap; - typedef std::map NameLoudnessMap; - NameLoudnessMap mVoiceLipBuffers; + typedef std::deque LoudnessList; + LoudnessList mVoiceLipBuffers; + + typedef std::map NameLoudnessRefMap; + NameLoudnessRefMap mVoiceLipNameMap; // NOTE: unused buffers are stored in front-newest order. typedef std::deque SoundList; @@ -83,8 +86,8 @@ namespace MWSound typedef std::map SoundMap; SoundMap mActiveSounds; - typedef std::pair SoundNamePair; - typedef std::map SaySoundMap; + typedef std::pair SoundLoudnessPair; + typedef std::map SaySoundMap; SaySoundMap mActiveSaySounds; MWBase::SoundPtr mUnderwaterSound; @@ -103,7 +106,7 @@ namespace MWSound // Ensures the loudness/"lip" data is loaded, and returns a decoder to // start streaming - DecoderPtr loadVoice(const std::string &voicefile); + DecoderPtr loadVoice(const std::string &voicefile, Sound_Loudness **lipdata); void streamMusicFull(const std::string& filename); bool updateSound(MWBase::SoundPtr sound, const MWWorld::Ptr &ptr, float duration); From 449eca4fb4913b0c377e525da022426990f96266 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 27 Nov 2015 02:36:33 -0800 Subject: [PATCH 2604/3725] Properly mark streams as 2D or 3D --- apps/openmw/mwsound/soundmanagerimp.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 0cdaddfd2..7e1244feb 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -304,7 +304,7 @@ namespace MWSound decoder->open(filename); mMusic = mOutput->streamSound(decoder, volumeFromType(Play_TypeMusic), - 1.0f, Play_NoEnv|Play_TypeMusic); + 1.0f, Play_NoEnv|Play_TypeMusic|Play_2D); } catch(std::exception &e) { @@ -393,7 +393,8 @@ namespace MWSound DecoderPtr decoder = loadVoice(voicefile, &loudness); MWBase::SoundPtr sound = mOutput->streamSound3D(decoder, - objpos, 1.0f, basevol, 1.0f, minDistance, maxDistance, Play_Normal|Play_TypeVoice + objpos, 1.0f, basevol, 1.0f, minDistance, maxDistance, + Play_Normal|Play_TypeVoice|Play_3D ); mActiveSaySounds[ptr] = std::make_pair(sound, loudness); } @@ -432,7 +433,7 @@ namespace MWSound DecoderPtr decoder = loadVoice(voicefile, &loudness); MWBase::SoundPtr sound = mOutput->streamSound(decoder, - basevol, 1.0f, Play_Normal|Play_TypeVoice + basevol, 1.0f, Play_Normal|Play_TypeVoice|Play_2D ); mActiveSaySounds[MWWorld::Ptr()] = std::make_pair(sound, loudness); } From 4a078725d4a669bfa1863e50547ed9025f3c532d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 27 Nov 2015 02:57:44 -0800 Subject: [PATCH 2605/3725] Play player voices locally --- apps/openmw/mwsound/soundmanagerimp.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 7e1244feb..d08aa4ca0 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -392,10 +392,16 @@ namespace MWSound mVFS->normalizeFilename(voicefile); DecoderPtr decoder = loadVoice(voicefile, &loudness); - MWBase::SoundPtr sound = mOutput->streamSound3D(decoder, - objpos, 1.0f, basevol, 1.0f, minDistance, maxDistance, - Play_Normal|Play_TypeVoice|Play_3D - ); + MWBase::SoundPtr sound; + if(ptr == MWMechanics::getPlayer()) + sound = mOutput->streamSound(decoder, + basevol, 1.0f, Play_Normal|Play_TypeVoice|Play_2D + ); + else + sound = mOutput->streamSound3D(decoder, + objpos, 1.0f, basevol, 1.0f, minDistance, maxDistance, + Play_Normal|Play_TypeVoice|Play_3D + ); mActiveSaySounds[ptr] = std::make_pair(sound, loudness); } catch(std::exception &e) From 9568aa6a84af76e9f33db7dde600eee9b7fbb386 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 27 Nov 2015 04:30:09 -0800 Subject: [PATCH 2606/3725] Use a condition variable to wake up the audio stream thread This should make starting streams a bit more responsive, and allows us to do more in it that really shouldn't wait for its next wake up. --- apps/openmw/mwsound/openal_output.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index a5246bde9..685979bcf 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -217,6 +217,7 @@ struct OpenAL_Output::StreamThread { typedef std::vector StreamVec; StreamVec mStreams; boost::recursive_mutex mMutex; + boost::condition_variable_any mCondVar; boost::thread mThread; StreamThread() @@ -231,9 +232,9 @@ struct OpenAL_Output::StreamThread { // boost::thread entry point void operator()() { + boost::unique_lock lock(mMutex); while(1) { - boost::unique_lock lock(mMutex); StreamVec::iterator iter = mStreams.begin(); while(iter != mStreams.end()) { @@ -242,16 +243,19 @@ struct OpenAL_Output::StreamThread { else ++iter; } - lock.unlock(); - boost::this_thread::sleep(boost::posix_time::milliseconds(50)); + mCondVar.timed_wait(lock, boost::posix_time::milliseconds(50)); } } void add(OpenAL_SoundStream *stream) { - boost::lock_guard lock(mMutex); + boost::unique_lock lock(mMutex); if(std::find(mStreams.begin(), mStreams.end(), stream) == mStreams.end()) + { mStreams.push_back(stream); + lock.unlock(); + mCondVar.notify_all(); + } } void remove(OpenAL_SoundStream *stream) From f3c035907c9daa4706e2ca29936c53de154c1d73 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 27 Nov 2015 04:55:17 -0800 Subject: [PATCH 2607/3725] Rename Sound::update to Sound::applyUpdates --- apps/openmw/mwsound/openal_output.cpp | 20 ++++++++++---------- apps/openmw/mwsound/sound.hpp | 2 +- apps/openmw/mwsound/soundmanagerimp.cpp | 8 ++++---- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 685979bcf..87667019e 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -188,7 +188,7 @@ public: virtual void stop(); virtual bool isPlaying(); virtual double getTimeOffset(); - virtual void update(); + virtual void applyUpdates(); void play(); bool process(); @@ -206,7 +206,7 @@ public: : OpenAL_SoundStream(output, src, decoder, pos, vol, basevol, pitch, mindist, maxdist, flags) { } - virtual void update(); + virtual void applyUpdates(); }; @@ -411,10 +411,10 @@ void OpenAL_SoundStream::updateAll(bool local) } alSourcei(mSource, AL_LOOPING, AL_FALSE); - update(); + applyUpdates(); } -void OpenAL_SoundStream::update() +void OpenAL_SoundStream::applyUpdates() { ALfloat gain = mVolume*mBaseVolume; ALfloat pitch = mPitch; @@ -490,7 +490,7 @@ ALint OpenAL_SoundStream::refillQueue() return queued; } -void OpenAL_SoundStream3D::update() +void OpenAL_SoundStream3D::applyUpdates() { ALfloat gain = mVolume*mBaseVolume; ALfloat pitch = mPitch; @@ -536,7 +536,7 @@ public: virtual void stop(); virtual bool isPlaying(); virtual double getTimeOffset(); - virtual void update(); + virtual void applyUpdates(); }; // @@ -552,7 +552,7 @@ public: : OpenAL_Sound(output, src, pos, vol, basevol, pitch, mindist, maxdist, flags) { } - virtual void update(); + virtual void applyUpdates(); }; OpenAL_Sound::OpenAL_Sound(OpenAL_Output &output, ALuint src, const osg::Vec3f& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags) @@ -614,10 +614,10 @@ void OpenAL_Sound::updateAll(bool local) } alSourcei(mSource, AL_LOOPING, (mFlags&MWBase::SoundManager::Play_Loop) ? AL_TRUE : AL_FALSE); - update(); + applyUpdates(); } -void OpenAL_Sound::update() +void OpenAL_Sound::applyUpdates() { ALfloat gain = mVolume*mBaseVolume; ALfloat pitch = mPitch; @@ -636,7 +636,7 @@ void OpenAL_Sound::update() throwALerror(); } -void OpenAL_Sound3D::update() +void OpenAL_Sound3D::applyUpdates() { ALfloat gain = mVolume*mBaseVolume; ALfloat pitch = mPitch; diff --git a/apps/openmw/mwsound/sound.hpp b/apps/openmw/mwsound/sound.hpp index 8ef1d25db..944fbc032 100644 --- a/apps/openmw/mwsound/sound.hpp +++ b/apps/openmw/mwsound/sound.hpp @@ -25,7 +25,7 @@ namespace MWSound virtual void stop() = 0; virtual bool isPlaying() = 0; virtual double getTimeOffset() = 0; - virtual void update() = 0; + virtual void applyUpdates() = 0; void setPosition(const osg::Vec3f &pos) { mPos = pos; } void setVolume(float volume) { mVolume = volume; } void setBaseVolume(float volume) { mBaseVolume = volume; } diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index d08aa4ca0..b31ae9019 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -863,7 +863,7 @@ namespace MWSound sound->updateFade(duration); - sound->update(); + sound->applyUpdates(); return true; } @@ -901,7 +901,7 @@ namespace MWSound { MWBase::SoundPtr sound = sndidx->first; sound->setBaseVolume(volumeFromType(sound->getPlayType())); - sound->update(); + sound->applyUpdates(); } } SaySoundMap::iterator sayiter = mActiveSaySounds.begin(); @@ -909,12 +909,12 @@ namespace MWSound { MWBase::SoundPtr sound = sayiter->second.first; sound->setBaseVolume(volumeFromType(sound->getPlayType())); - sound->update(); + sound->applyUpdates(); } if(mMusic) { mMusic->setBaseVolume(volumeFromType(mMusic->getPlayType())); - mMusic->update(); + mMusic->applyUpdates(); } mOutput->finishUpdate(); } From b5ed2e65f8f5572f8a0f1a39f691e37f699bbe12 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 27 Nov 2015 06:01:50 -0800 Subject: [PATCH 2608/3725] Add a method to get the sound stream delay This helps avoid a lock during the movie player's read method, since it needs to sync with the current playback position which would otherwise need to get the movie decoder's current position. --- apps/openmw/mwsound/movieaudiofactory.cpp | 3 ++- apps/openmw/mwsound/openal_output.cpp | 21 +++++++++++++++++++++ apps/openmw/mwsound/sound.hpp | 1 + 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwsound/movieaudiofactory.cpp b/apps/openmw/mwsound/movieaudiofactory.cpp index 47889051a..925c966da 100644 --- a/apps/openmw/mwsound/movieaudiofactory.cpp +++ b/apps/openmw/mwsound/movieaudiofactory.cpp @@ -60,7 +60,8 @@ namespace MWSound virtual double getAudioClock() { - return mAudioTrack->getTimeOffset(); + return (double)getSampleOffset()/(double)mAVStream->codec->sample_rate - + mAudioTrack->getStreamDelay(); } virtual void adjustAudioSettings(AVSampleFormat& sampleFormat, uint64_t& channelLayout, int& sampleRate) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 87667019e..dd440674f 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -188,6 +188,7 @@ public: virtual void stop(); virtual bool isPlaying(); virtual double getTimeOffset(); + virtual double getStreamDelay() const; virtual void applyUpdates(); void play(); @@ -395,6 +396,26 @@ double OpenAL_SoundStream::getTimeOffset() return t; } +double OpenAL_SoundStream::getStreamDelay() const +{ + ALint state = AL_STOPPED; + double d = 0.0; + ALint offset; + + alGetSourcei(mSource, AL_SAMPLE_OFFSET, &offset); + alGetSourcei(mSource, AL_SOURCE_STATE, &state); + if(state == AL_PLAYING || state == AL_PAUSED) + { + ALint queued; + alGetSourcei(mSource, AL_BUFFERS_QUEUED, &queued); + ALint inqueue = mBufferSize/mFrameSize*queued - offset; + d = (double)inqueue / (double)mSampleRate; + } + + throwALerror(); + return d; +} + void OpenAL_SoundStream::updateAll(bool local) { alSourcef(mSource, AL_REFERENCE_DISTANCE, mMinDistance); diff --git a/apps/openmw/mwsound/sound.hpp b/apps/openmw/mwsound/sound.hpp index 944fbc032..f95ff169d 100644 --- a/apps/openmw/mwsound/sound.hpp +++ b/apps/openmw/mwsound/sound.hpp @@ -25,6 +25,7 @@ namespace MWSound virtual void stop() = 0; virtual bool isPlaying() = 0; virtual double getTimeOffset() = 0; + virtual double getStreamDelay() const { return 0.0; } virtual void applyUpdates() = 0; void setPosition(const osg::Vec3f &pos) { mPos = pos; } void setVolume(float volume) { mVolume = volume; } From 0f05ccf72a20b0a2a927509c58b30dabdb0520a0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 27 Nov 2015 08:13:23 -0800 Subject: [PATCH 2609/3725] Use a non-recursive mutex and properly end the streaming thrread --- apps/openmw/mwsound/openal_output.cpp | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index dd440674f..533e7e657 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -217,24 +217,28 @@ public: struct OpenAL_Output::StreamThread { typedef std::vector StreamVec; StreamVec mStreams; - boost::recursive_mutex mMutex; - boost::condition_variable_any mCondVar; + volatile bool mQuitNow; + boost::mutex mMutex; + boost::condition_variable mCondVar; boost::thread mThread; StreamThread() - : mThread(boost::ref(*this)) + : mQuitNow(false), mThread(boost::ref(*this)) { } ~StreamThread() { - mThread.interrupt(); + mQuitNow = true; + mMutex.lock(); mMutex.unlock(); + mCondVar.notify_all(); + mThread.join(); } // boost::thread entry point void operator()() { - boost::unique_lock lock(mMutex); - while(1) + boost::unique_lock lock(mMutex); + while(!mQuitNow) { StreamVec::iterator iter = mStreams.begin(); while(iter != mStreams.end()) @@ -250,7 +254,7 @@ struct OpenAL_Output::StreamThread { void add(OpenAL_SoundStream *stream) { - boost::unique_lock lock(mMutex); + boost::unique_lock lock(mMutex); if(std::find(mStreams.begin(), mStreams.end(), stream) == mStreams.end()) { mStreams.push_back(stream); @@ -261,14 +265,14 @@ struct OpenAL_Output::StreamThread { void remove(OpenAL_SoundStream *stream) { - boost::lock_guard lock(mMutex); + boost::lock_guard lock(mMutex); StreamVec::iterator iter = std::find(mStreams.begin(), mStreams.end(), stream); if(iter != mStreams.end()) mStreams.erase(iter); } void removeAll() { - boost::lock_guard lock(mMutex); + boost::lock_guard lock(mMutex); mStreams.clear(); } @@ -360,7 +364,7 @@ bool OpenAL_SoundStream::isPlaying() { ALint state; - boost::lock_guard lock(mOutput.mStreamThread->mMutex); + boost::lock_guard lock(mOutput.mStreamThread->mMutex); alGetSourcei(mSource, AL_SOURCE_STATE, &state); throwALerror(); @@ -375,7 +379,7 @@ double OpenAL_SoundStream::getTimeOffset() ALint offset; double t; - boost::lock_guard lock(mOutput.mStreamThread->mMutex); + boost::lock_guard lock(mOutput.mStreamThread->mMutex); alGetSourcei(mSource, AL_SAMPLE_OFFSET, &offset); alGetSourcei(mSource, AL_SOURCE_STATE, &state); if(state == AL_PLAYING || state == AL_PAUSED) From 4ee409af84ff9dac4083cd0a0e6af0266136d311 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 27 Nov 2015 09:47:14 -0800 Subject: [PATCH 2610/3725] Load loudness data asynchronously Currently abuses the output audio streams' background processing thread to do the work, since there's no generalized threaded processing mechanism. --- apps/openmw/mwsound/loudness.cpp | 2 + apps/openmw/mwsound/loudness.hpp | 4 +- apps/openmw/mwsound/openal_output.cpp | 53 +++++++++++ apps/openmw/mwsound/openal_output.hpp | 2 + apps/openmw/mwsound/sound_output.hpp | 5 + apps/openmw/mwsound/soundmanagerimp.cpp | 120 +++++++++++++++--------- apps/openmw/mwsound/soundmanagerimp.hpp | 10 +- 7 files changed, 150 insertions(+), 46 deletions(-) diff --git a/apps/openmw/mwsound/loudness.cpp b/apps/openmw/mwsound/loudness.cpp index 21f399ddc..326c59c07 100644 --- a/apps/openmw/mwsound/loudness.cpp +++ b/apps/openmw/mwsound/loudness.cpp @@ -52,6 +52,8 @@ void Sound_Loudness::analyzeLoudness(const std::vector< char >& data, int sample mSamples.push_back(rms); ++segment; } + + mReady = true; } diff --git a/apps/openmw/mwsound/loudness.hpp b/apps/openmw/mwsound/loudness.hpp index a0af2b558..366d29de5 100644 --- a/apps/openmw/mwsound/loudness.hpp +++ b/apps/openmw/mwsound/loudness.hpp @@ -12,9 +12,10 @@ class Sound_Loudness { // Loudness sample info float mSamplesPerSec; std::vector mSamples; + volatile bool mReady; public: - Sound_Loudness() : mSamplesPerSec(0.0f) { } + Sound_Loudness() : mSamplesPerSec(0.0f), mReady(false) { } /** * Analyzes the energy (closely related to loudness) of a sound buffer. @@ -30,6 +31,7 @@ public: ChannelConfig chans, SampleType type, float valuesPerSecond); + bool isReady() { return mReady; } float getLoudnessAtTime(float sec) const; }; diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 533e7e657..d4c890cee 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -23,6 +23,13 @@ #define MAKE_PTRID(id) ((void*)(uintptr_t)id) #define GET_PTRID(ptr) ((ALuint)(uintptr_t)ptr) +namespace +{ + +const int sLoudnessFPS = 20; // loudness values per second of audio + +} + namespace MWSound { @@ -217,6 +224,10 @@ public: struct OpenAL_Output::StreamThread { typedef std::vector StreamVec; StreamVec mStreams; + + typedef std::vector > DecoderLoudnessVec; + DecoderLoudnessVec mDecoderLoudness; + volatile bool mQuitNow; boost::mutex mMutex; boost::condition_variable mCondVar; @@ -248,6 +259,33 @@ struct OpenAL_Output::StreamThread { else ++iter; } + + // Only do one loudness decode at a time, in case it takes particularly long we don't + // want to block up anything. + DecoderLoudnessVec::iterator dliter = mDecoderLoudness.begin(); + if(dliter != mDecoderLoudness.end()) + { + DecoderPtr decoder = dliter->first; + Sound_Loudness *loudness = dliter->second; + mDecoderLoudness.erase(dliter); + lock.unlock(); + + std::vector data; + ChannelConfig chans = ChannelConfig_Mono; + SampleType type = SampleType_Int16; + int srate = 48000; + try { + decoder->getInfo(&srate, &chans, &type); + decoder->readAll(data); + } + catch(std::exception &e) { + std::cerr<< "Failed to decode audio: "<analyzeLoudness(data, srate, chans, type, static_cast(sLoudnessFPS)); + lock.lock(); + continue; + } mCondVar.timed_wait(lock, boost::posix_time::milliseconds(50)); } } @@ -274,6 +312,15 @@ struct OpenAL_Output::StreamThread { { boost::lock_guard lock(mMutex); mStreams.clear(); + mDecoderLoudness.clear(); + } + + void add(DecoderPtr decoder, Sound_Loudness *loudness) + { + boost::unique_lock lock(mMutex); + mDecoderLoudness.push_back(std::make_pair(decoder, loudness)); + lock.unlock(); + mCondVar.notify_all(); } private: @@ -1052,6 +1099,12 @@ void OpenAL_Output::resumeSounds(int types) } +void OpenAL_Output::loadLoudnessAsync(DecoderPtr decoder, Sound_Loudness *loudness) +{ + mStreamThread->add(decoder, loudness); +} + + OpenAL_Output::OpenAL_Output(SoundManager &mgr) : Sound_Output(mgr), mDevice(0), mContext(0), mLastEnvironment(Env_Normal), mStreamThread(new StreamThread) diff --git a/apps/openmw/mwsound/openal_output.hpp b/apps/openmw/mwsound/openal_output.hpp index fdce32c8a..751ec4fd2 100644 --- a/apps/openmw/mwsound/openal_output.hpp +++ b/apps/openmw/mwsound/openal_output.hpp @@ -57,6 +57,8 @@ namespace MWSound virtual void pauseSounds(int types); virtual void resumeSounds(int types); + virtual void loadLoudnessAsync(DecoderPtr decoder, Sound_Loudness *loudness); + OpenAL_Output& operator=(const OpenAL_Output &rhs); OpenAL_Output(const OpenAL_Output &rhs); diff --git a/apps/openmw/mwsound/sound_output.hpp b/apps/openmw/mwsound/sound_output.hpp index e358ba344..0f69498aa 100644 --- a/apps/openmw/mwsound/sound_output.hpp +++ b/apps/openmw/mwsound/sound_output.hpp @@ -47,6 +47,11 @@ namespace MWSound virtual void pauseSounds(int types) = 0; virtual void resumeSounds(int types) = 0; + // HACK: The sound output implementation really shouldn't be handling + // asynchronous loudness data loading, but it's currently where we have + // a background processing thread. + virtual void loadLoudnessAsync(DecoderPtr decoder, Sound_Loudness *loudness) = 0; + Sound_Output& operator=(const Sound_Output &rhs); Sound_Output(const Sound_Output &rhs); diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index b31ae9019..0f5cee737 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -30,11 +30,6 @@ #endif -namespace -{ - const int sLoudnessFPS = 20; // loudness values per second of audio -} - namespace MWSound { SoundManager::SoundManager(const VFS::Manager* vfs, bool useSound) @@ -234,27 +229,38 @@ namespace MWSound return decoder; } - ChannelConfig chans; - SampleType type; - int srate; - decoder->getInfo(&srate, &chans, &type); - - std::vector data; - decoder->readAll(data); - - Sound_Loudness loudness; - loudness.analyzeLoudness(data, srate, chans, type, static_cast(sLoudnessFPS)); - - mVoiceLipBuffers.insert(mVoiceLipBuffers.end(), loudness); + mVoiceLipBuffers.insert(mVoiceLipBuffers.end(), Sound_Loudness()); lipiter = mVoiceLipNameMap.insert( std::make_pair(voicefile, &mVoiceLipBuffers.back()) ).first; - decoder->rewind(); + mOutput->loadLoudnessAsync(decoder, lipiter->second); + *lipdata = lipiter->second; return decoder; } + MWBase::SoundPtr SoundManager::playVoice(DecoderPtr decoder, const osg::Vec3f &pos, bool playlocal) + { + MWBase::World* world = MWBase::Environment::get().getWorld(); + static const float fAudioMinDistanceMult = world->getStore().get().find("fAudioMinDistanceMult")->getFloat(); + static const float fAudioMaxDistanceMult = world->getStore().get().find("fAudioMaxDistanceMult")->getFloat(); + static const float fAudioVoiceDefaultMinDistance = world->getStore().get().find("fAudioVoiceDefaultMinDistance")->getFloat(); + static const float fAudioVoiceDefaultMaxDistance = world->getStore().get().find("fAudioVoiceDefaultMaxDistance")->getFloat(); + static float minDistance = std::max(fAudioVoiceDefaultMinDistance * fAudioMinDistanceMult, 1.0f); + static float maxDistance = std::max(fAudioVoiceDefaultMaxDistance * fAudioMaxDistanceMult, minDistance); + + float basevol = volumeFromType(Play_TypeVoice); + if(playlocal) + return mOutput->streamSound(decoder, + basevol, 1.0f, Play_Normal|Play_TypeVoice|Play_2D + ); + return mOutput->streamSound3D(decoder, + pos, 1.0f, basevol, 1.0f, minDistance, maxDistance, + Play_Normal|Play_TypeVoice|Play_3D + ); + } + // Gets the combined volume settings for the given sound type float SoundManager::volumeFromType(PlayType type) const @@ -375,16 +381,7 @@ namespace MWSound return; try { - MWBase::World* world = MWBase::Environment::get().getWorld(); - static const float fAudioMinDistanceMult = world->getStore().get().find("fAudioMinDistanceMult")->getFloat(); - static const float fAudioMaxDistanceMult = world->getStore().get().find("fAudioMaxDistanceMult")->getFloat(); - static const float fAudioVoiceDefaultMinDistance = world->getStore().get().find("fAudioVoiceDefaultMinDistance")->getFloat(); - static const float fAudioVoiceDefaultMaxDistance = world->getStore().get().find("fAudioVoiceDefaultMaxDistance")->getFloat(); - static float minDistance = std::max(fAudioVoiceDefaultMinDistance * fAudioMinDistanceMult, 1.0f); - static float maxDistance = std::max(fAudioVoiceDefaultMaxDistance * fAudioMaxDistanceMult, minDistance); - std::string voicefile = "Sound/"+filename; - float basevol = volumeFromType(Play_TypeVoice); const ESM::Position &pos = ptr.getRefData().getPosition(); const osg::Vec3f objpos(pos.asVec3()); @@ -392,17 +389,13 @@ namespace MWSound mVFS->normalizeFilename(voicefile); DecoderPtr decoder = loadVoice(voicefile, &loudness); - MWBase::SoundPtr sound; - if(ptr == MWMechanics::getPlayer()) - sound = mOutput->streamSound(decoder, - basevol, 1.0f, Play_Normal|Play_TypeVoice|Play_2D - ); + if(!loudness->isReady()) + mPendingSaySounds[ptr] = std::make_pair(decoder, loudness); else - sound = mOutput->streamSound3D(decoder, - objpos, 1.0f, basevol, 1.0f, minDistance, maxDistance, - Play_Normal|Play_TypeVoice|Play_3D - ); - mActiveSaySounds[ptr] = std::make_pair(sound, loudness); + { + MWBase::SoundPtr sound = playVoice(decoder, objpos, (ptr == MWMechanics::getPlayer())); + mActiveSaySounds[ptr] = std::make_pair(sound, loudness); + } } catch(std::exception &e) { @@ -432,16 +425,18 @@ namespace MWSound try { std::string voicefile = "Sound/"+filename; - float basevol = volumeFromType(Play_TypeVoice); Sound_Loudness *loudness; mVFS->normalizeFilename(voicefile); DecoderPtr decoder = loadVoice(voicefile, &loudness); - MWBase::SoundPtr sound = mOutput->streamSound(decoder, - basevol, 1.0f, Play_Normal|Play_TypeVoice|Play_2D - ); - mActiveSaySounds[MWWorld::Ptr()] = std::make_pair(sound, loudness); + if(!loudness->isReady()) + mPendingSaySounds[MWWorld::Ptr()] = std::make_pair(decoder, loudness); + else + { + MWBase::SoundPtr sound = playVoice(decoder, osg::Vec3f(), true); + mActiveSaySounds[MWWorld::Ptr()] = std::make_pair(sound, loudness); + } } catch(std::exception &e) { @@ -456,8 +451,9 @@ namespace MWSound { if(snditer->second.first->isPlaying()) return false; + return true; } - return true; + return mPendingSaySounds.find(ptr) == mPendingSaySounds.end(); } void SoundManager::stopSay(const MWWorld::Ptr &ptr) @@ -468,6 +464,7 @@ namespace MWSound snditer->second.first->stop(); mActiveSaySounds.erase(snditer); } + mPendingSaySounds.erase(ptr); } @@ -832,6 +829,35 @@ namespace MWSound ++snditer; } + SayDecoderMap::iterator penditer = mPendingSaySounds.begin(); + while(penditer != mPendingSaySounds.end()) + { + Sound_Loudness *loudness = penditer->second.second; + if(loudness->isReady()) + { + try { + DecoderPtr decoder = penditer->second.first; + decoder->rewind(); + + MWWorld::Ptr ptr = penditer->first; + const ESM::Position &pos = ptr.getRefData().getPosition(); + const osg::Vec3f objpos(pos.asVec3()); + + MWBase::SoundPtr sound = playVoice(decoder, + objpos, (ptr == MWMechanics::getPlayer()) + ); + mActiveSaySounds[ptr] = std::make_pair(sound, loudness); + } + catch(std::exception &e) { + std::cerr<< "Sound Error: "<second; + mPendingSaySounds.erase(penditer); + mPendingSaySounds[updated] = dl; + } } // Default readAll implementation, for decoders that can't do anything @@ -1033,6 +1066,7 @@ namespace MWSound for(;sayiter != mActiveSaySounds.end();++sayiter) sayiter->second.first->stop(); mActiveSaySounds.clear(); + mPendingSaySounds.clear(); mUnderwaterSound.reset(); stopMusic(); } diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index e12fe16fc..8e2df9f1a 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -90,6 +90,10 @@ namespace MWSound typedef std::map SaySoundMap; SaySoundMap mActiveSaySounds; + typedef std::pair DecoderLoudnessPair; + typedef std::map SayDecoderMap; + SayDecoderMap mPendingSaySounds; + MWBase::SoundPtr mUnderwaterSound; bool mListenerUnderwater; @@ -104,10 +108,12 @@ namespace MWSound Sound_Buffer *lookupSound(const std::string &soundId) const; Sound_Buffer *loadSound(const std::string &soundId); - // Ensures the loudness/"lip" data is loaded, and returns a decoder to - // start streaming + // Ensures the loudness/"lip" data gets loaded, and returns a decoder + // to start streaming DecoderPtr loadVoice(const std::string &voicefile, Sound_Loudness **lipdata); + MWBase::SoundPtr playVoice(DecoderPtr decoder, const osg::Vec3f &pos, bool playlocal); + void streamMusicFull(const std::string& filename); bool updateSound(MWBase::SoundPtr sound, const MWWorld::Ptr &ptr, float duration); void updateSounds(float duration); From 89783e047b6a373b4be276638d4de9794469ae9b Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 27 Nov 2015 19:40:31 +0100 Subject: [PATCH 2611/3725] Fix typo --- apps/openmw/mwworld/worldimp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 7fd73b482..6bced30c4 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2281,7 +2281,7 @@ namespace MWWorld { if (!targetActor.getRefData().isEnabled() || !actor.getRefData().isEnabled()) return false; // cannot get LOS unless both NPC's are enabled - if (!targetActor.getRefData().getBaseNode() || !targetActor.getRefData().getBaseNode()) + if (!targetActor.getRefData().getBaseNode() || !actor.getRefData().getBaseNode()) return false; // not in active cell return mPhysics->getLineOfSight(actor, targetActor); From ace4cfc0a850dc62f6b6a0069a894b1634fe9ed3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 27 Nov 2015 20:32:45 +0100 Subject: [PATCH 2612/3725] Fix 'duplicate setting' errors when running installation wizard --- apps/launcher/maindialog.cpp | 3 +++ components/settings/settings.cpp | 7 +++++++ components/settings/settings.hpp | 3 +++ 3 files changed, 13 insertions(+) diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index fb1b73c3e..a979a2125 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -384,6 +384,9 @@ bool Launcher::MainDialog::setupGraphicsSettings() // remain consistent, and possibly be merged into a shared component. At the very least // the filenames should be in the CfgMgr component. + // Ensure to clear previous settings in case we had already loaded settings. + mEngineSettings.clear(); + // Create the settings manager and load default settings file const std::string localDefault = (mCfgMgr.getLocalPath() / "settings-default.cfg").string(); const std::string globalDefault = (mCfgMgr.getGlobalPath() / "settings-default.cfg").string(); diff --git a/components/settings/settings.cpp b/components/settings/settings.cpp index acad1a98e..0e5324bd9 100644 --- a/components/settings/settings.cpp +++ b/components/settings/settings.cpp @@ -353,6 +353,13 @@ private: int mLine; }; +void Manager::clear() +{ + mDefaultSettings.clear(); + mUserSettings.clear(); + mChangedSettings.clear(); +} + void Manager::loadDefault(const std::string &file) { SettingsFileParser parser; diff --git a/components/settings/settings.hpp b/components/settings/settings.hpp index c16ff5a1e..7adcb9b39 100644 --- a/components/settings/settings.hpp +++ b/components/settings/settings.hpp @@ -23,6 +23,9 @@ namespace Settings static CategorySettingVector mChangedSettings; ///< tracks all the settings that were changed since the last apply() call + void clear(); + ///< clears all settings and default settings + void loadDefault (const std::string& file); ///< load file as the default settings (can be overridden by user settings) From 177a6f4a683bdefa0707e426c746f1c5deaf8d20 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 27 Nov 2015 20:52:29 +0100 Subject: [PATCH 2613/3725] Launcher: ensure to clear previous settings when reloading settings --- apps/launcher/maindialog.cpp | 4 ++++ components/config/gamesettings.cpp | 8 ++++++++ components/config/gamesettings.hpp | 2 ++ components/config/settingsbase.hpp | 5 +++++ 4 files changed, 19 insertions(+) diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index a979a2125..60ae5b3a0 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -257,6 +257,8 @@ void Launcher::MainDialog::changePage(QListWidgetItem *current, QListWidgetItem bool Launcher::MainDialog::setupLauncherSettings() { + mLauncherSettings.clear(); + mLauncherSettings.setMultiValueEnabled(true); QString userPath = QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str()); @@ -289,6 +291,8 @@ bool Launcher::MainDialog::setupLauncherSettings() bool Launcher::MainDialog::setupGameSettings() { + mGameSettings.clear(); + QString userPath = QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str()); QString globalPath = QString::fromUtf8(mCfgMgr.getGlobalPath().string().c_str()); diff --git a/components/config/gamesettings.cpp b/components/config/gamesettings.cpp index ca6bfd80d..a897806c2 100644 --- a/components/config/gamesettings.cpp +++ b/components/config/gamesettings.cpp @@ -454,3 +454,11 @@ QStringList Config::GameSettings::getContentList() const return Config::LauncherSettings::reverse(values(sContentKey)); } +void Config::GameSettings::clear() +{ + mSettings.clear(); + mUserSettings.clear(); + mDataDirs.clear(); + mDataLocal.clear(); +} + diff --git a/components/config/gamesettings.hpp b/components/config/gamesettings.hpp index 992a3e565..eeac893c2 100644 --- a/components/config/gamesettings.hpp +++ b/components/config/gamesettings.hpp @@ -72,6 +72,8 @@ namespace Config void setContentList(const QStringList& fileNames); QStringList getContentList() const; + void clear(); + private: Files::ConfigurationManager &mCfgMgr; diff --git a/components/config/settingsbase.hpp b/components/config/settingsbase.hpp index c798d2893..08cd0bfc6 100644 --- a/components/config/settingsbase.hpp +++ b/components/config/settingsbase.hpp @@ -101,6 +101,11 @@ namespace Config return true; } + void clear() + { + mSettings.clear(); + } + private: Map mSettings; From 5b8fd79b4bdc6871e3dbd7e32adcde1dc930b2bf Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 27 Nov 2015 21:38:57 +0100 Subject: [PATCH 2614/3725] Fix crash when exception is thrown in startNewGame() --- apps/openmw/mwmechanics/actors.cpp | 2 +- apps/openmw/mwrender/ripplesimulation.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 02b73bff7..2d794b3e0 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -926,7 +926,7 @@ namespace MWMechanics PtrActorMap::iterator iter = mActors.begin(); while(iter != mActors.end()) { - if(iter->first.getCell()==cellStore && iter->first != ignore) + if((iter->first.isInCell() && iter->first.getCell()==cellStore) && iter->first != ignore) { delete iter->second; mActors.erase(iter++); diff --git a/apps/openmw/mwrender/ripplesimulation.cpp b/apps/openmw/mwrender/ripplesimulation.cpp index 5caee8046..55b732613 100644 --- a/apps/openmw/mwrender/ripplesimulation.cpp +++ b/apps/openmw/mwrender/ripplesimulation.cpp @@ -185,7 +185,7 @@ void RippleSimulation::removeCell(const MWWorld::CellStore *store) { for (std::vector::iterator it = mEmitters.begin(); it != mEmitters.end();) { - if (it->mPtr.getCell() == store && it->mPtr != MWMechanics::getPlayer()) + if ((it->mPtr.isInCell() && it->mPtr.getCell() == store) && it->mPtr != MWMechanics::getPlayer()) { it = mEmitters.erase(it); } From 4687c4baad4397d55d42ab37b225dbbf25cf8781 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 27 Nov 2015 21:40:36 +0100 Subject: [PATCH 2615/3725] Do not assert() for invalid land data in plugins (Bug #3037) The resizing of LTEX store to the correct number of plugins was done in the load() method, but the load method won't be called if a plugin contains LAND records but doesn't contain LTEX records. For such plugins the Store::search() function would then fail an assertion. --- apps/openmw/mwworld/esmstore.cpp | 6 ++++++ apps/openmw/mwworld/store.cpp | 16 ++++++++++------ apps/openmw/mwworld/store.hpp | 3 +++ 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index 50324f3e8..9cf8de6bb 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -32,6 +32,12 @@ void ESMStore::load(ESM::ESMReader &esm, Loading::Listener* listener) ESM::Dialogue *dialogue = 0; + // Land texture loading needs to use a separate internal store for each plugin. + // We set the number of plugins here to avoid continual resizes during loading, + // and so we can properly verify if valid plugin indices are being passed to the + // LandTexture Store retrieval methods. + mLandTextures.resize(esm.getGlobalReaderList()->size()); + /// \todo Move this to somewhere else. ESMReader? // Cache parent esX files by tracking their indices in the global list of // all files/readers used by the engine. This will greaty accelerate diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index 644c3d0cf..3d23f3da4 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -351,8 +351,9 @@ namespace MWWorld assert(plugin < mStatic.size()); const LandTextureList <exl = mStatic[plugin]; - assert(index < ltexl.size()); - return <exl.at(index); + if (index >= ltexl.size()) + return NULL; + return <exl[index]; } const ESM::LandTexture *Store::find(size_t index, size_t plugin) const { @@ -380,10 +381,8 @@ namespace MWWorld lt.load(esm, isDeleted); - // Make sure we have room for the structure - if (plugin >= mStatic.size()) { - mStatic.resize(plugin+1); - } + assert(plugin < mStatic.size()); + LandTextureList <exl = mStatic[plugin]; if(lt.mIndex + 1 > (int)ltexl.size()) ltexl.resize(lt.mIndex+1); @@ -407,6 +406,11 @@ namespace MWWorld assert(plugin < mStatic.size()); return mStatic[plugin].end(); } + void Store::resize(size_t num) + { + if (mStatic.size() < num) + mStatic.resize(num); + } // Land //========================================================================= diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index ef551e205..443dd4175 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -210,6 +210,9 @@ namespace MWWorld const ESM::LandTexture *search(size_t index, size_t plugin) const; const ESM::LandTexture *find(size_t index, size_t plugin) const; + /// Resize the internal store to hold at least \a num plugins. + void resize(size_t num); + size_t getSize() const; size_t getSize(size_t plugin) const; From 35fa1f5865bcb8370505f0a2b641c8363024c8a7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 27 Nov 2015 21:45:37 +0100 Subject: [PATCH 2616/3725] Not found Land Textures are no longer a fatal error (Bug #3037) Log warning message and show the default texture when encountering invalid ESM::LandTexture references. --- apps/opencs/view/render/terrainstorage.cpp | 4 +--- apps/openmw/mwrender/terrainstorage.cpp | 2 +- components/esmterrain/storage.cpp | 8 +++++++- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/apps/opencs/view/render/terrainstorage.cpp b/apps/opencs/view/render/terrainstorage.cpp index 860ed0080..2be4efd73 100644 --- a/apps/opencs/view/render/terrainstorage.cpp +++ b/apps/opencs/view/render/terrainstorage.cpp @@ -37,9 +37,7 @@ namespace CSVRender return ltex; } - std::stringstream error; - error << "Can't find LandTexture " << index << " from plugin " << plugin; - throw std::runtime_error(error.str()); + return NULL; } void TerrainStorage::getBounds(float &minX, float &maxX, float &minY, float &maxY) diff --git a/apps/openmw/mwrender/terrainstorage.cpp b/apps/openmw/mwrender/terrainstorage.cpp index f9a9083f0..a98084709 100644 --- a/apps/openmw/mwrender/terrainstorage.cpp +++ b/apps/openmw/mwrender/terrainstorage.cpp @@ -69,7 +69,7 @@ namespace MWRender { const MWWorld::ESMStore &esmStore = MWBase::Environment::get().getWorld()->getStore(); - return esmStore.get().find(index, plugin); + return esmStore.get().search(index, plugin); } } diff --git a/components/esmterrain/storage.cpp b/components/esmterrain/storage.cpp index c36e3efe0..fc56b883c 100644 --- a/components/esmterrain/storage.cpp +++ b/components/esmterrain/storage.cpp @@ -299,11 +299,17 @@ namespace ESMTerrain std::string Storage::getTextureName(UniqueTextureId id) { + static const std::string defaultTexture = "textures\\_land_default.dds"; if (id.first == 0) - return "textures\\_land_default.dds"; // Not sure if the default texture really is hardcoded? + return defaultTexture; // Not sure if the default texture really is hardcoded? // NB: All vtex ids are +1 compared to the ltex ids const ESM::LandTexture* ltex = getLandTexture(id.first-1, id.second); + if (!ltex) + { + std::cerr << "Unable to find land texture index " << id.first-1 << " in plugin " << id.second << ", using default texture instead" << std::endl; + return defaultTexture; + } // this is needed due to MWs messed up texture handling std::string texture = Misc::ResourceHelpers::correctTexturePath(ltex->mTexture, mVFS); From 30cc633f2c485452b817a500889ded1790fcf3d4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 27 Nov 2015 22:21:01 +0100 Subject: [PATCH 2617/3725] Missing include fix --- components/esmterrain/storage.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/components/esmterrain/storage.cpp b/components/esmterrain/storage.cpp index fc56b883c..f0865a0a9 100644 --- a/components/esmterrain/storage.cpp +++ b/components/esmterrain/storage.cpp @@ -1,6 +1,7 @@ #include "storage.hpp" #include +#include #include #include From 4c0c20b1a0510d6d224f74a07a7f24aeda654854 Mon Sep 17 00:00:00 2001 From: Arthur Moore Date: Fri, 27 Nov 2015 21:01:28 -0500 Subject: [PATCH 2618/3725] Changed relative includes to library header format --- components/bsa/bsa_file.cpp | 2 -- components/contentselector/view/contentselector.cpp | 2 +- components/contentselector/view/contentselector.hpp | 2 +- components/nifbullet/bulletnifloader.cpp | 11 +++++------ 4 files changed, 7 insertions(+), 10 deletions(-) diff --git a/components/bsa/bsa_file.cpp b/components/bsa/bsa_file.cpp index 401d043d9..2b9a3f632 100644 --- a/components/bsa/bsa_file.cpp +++ b/components/bsa/bsa_file.cpp @@ -28,8 +28,6 @@ #include #include -#include "../files/constrainedfilestream.hpp" - using namespace std; using namespace Bsa; diff --git a/components/contentselector/view/contentselector.cpp b/components/contentselector/view/contentselector.cpp index 78aa20cd2..87c9cea08 100644 --- a/components/contentselector/view/contentselector.cpp +++ b/components/contentselector/view/contentselector.cpp @@ -1,6 +1,6 @@ #include "contentselector.hpp" -#include "../model/esmfile.hpp" +#include #include diff --git a/components/contentselector/view/contentselector.hpp b/components/contentselector/view/contentselector.hpp index 4e9fcfb3c..9f775d597 100644 --- a/components/contentselector/view/contentselector.hpp +++ b/components/contentselector/view/contentselector.hpp @@ -4,7 +4,7 @@ #include #include "ui_contentselector.h" -#include "../model/contentmodel.hpp" +#include class QSortFilterProxyModel; diff --git a/components/nifbullet/bulletnifloader.cpp b/components/nifbullet/bulletnifloader.cpp index 5de6d51ca..0b8e9c163 100644 --- a/components/nifbullet/bulletnifloader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -12,12 +12,11 @@ #include -#include "../nif/niffile.hpp" -#include "../nif/node.hpp" -#include "../nif/data.hpp" -#include "../nif/property.hpp" -#include "../nif/controller.hpp" -#include "../nif/extra.hpp" +#include +#include +#include +#include +#include namespace From c66fd69c47336cb610a2880800fc450d941a3e49 Mon Sep 17 00:00:00 2001 From: Arthur Moore Date: Fri, 27 Nov 2015 21:20:54 -0500 Subject: [PATCH 2619/3725] Fix #include error --- components/contentselector/model/contentmodel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/contentselector/model/contentmodel.cpp b/components/contentselector/model/contentmodel.cpp index 769afee37..8dc4351f6 100644 --- a/components/contentselector/model/contentmodel.cpp +++ b/components/contentselector/model/contentmodel.cpp @@ -7,7 +7,7 @@ #include #include -#include "components/esm/esmreader.hpp" +#include ContentSelectorModel::ContentModel::ContentModel(QObject *parent, QIcon warningIcon) : QAbstractTableModel(parent), From debce0fb8090b704bb08523cca99507960409390 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 28 Nov 2015 05:12:15 +0100 Subject: [PATCH 2620/3725] crashcatcher: show the message box before killing crashed process This change fixes a random X server lock-up that I get about 1 in 10 times when a crash is caught. I'm presuming it's an X server bug since faulty applications shouldn't be able to crash or freeze the X server under any circumstances. --- apps/openmw/crashcatcher.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/openmw/crashcatcher.cpp b/apps/openmw/crashcatcher.cpp index 373d78746..8d812efd3 100644 --- a/apps/openmw/crashcatcher.cpp +++ b/apps/openmw/crashcatcher.cpp @@ -382,16 +382,17 @@ static void crash_handler(const char *logfile) fflush(stdout); if(crash_info.pid > 0) - { gdb_info(crash_info.pid); - kill(crash_info.pid, SIGKILL); - } if(logfile) { std::string message = "OpenMW has encountered a fatal error.\nCrash log saved to '" + std::string(logfile) + "'.\n Please report this to https://bugs.openmw.org !"; SDL_ShowSimpleMessageBox(0, "Fatal Error", message.c_str(), NULL); } + + if (crash_info.pid > 0) + kill(crash_info.pid, SIGKILL); + exit(0); } From 93a76e2f56b18fc5abff5e92dc338d208441a906 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 28 Nov 2015 05:36:57 +0100 Subject: [PATCH 2621/3725] Revert debce0fb80, use a sleep() to work around the X11 bug Problem with debce0fb80 is the crashed process won't be killed until the user accepts the message box, and it's harder to get to the message box when the window is in full screen or the cursor is locked. --- apps/openmw/crashcatcher.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/apps/openmw/crashcatcher.cpp b/apps/openmw/crashcatcher.cpp index 8d812efd3..0b4ff6304 100644 --- a/apps/openmw/crashcatcher.cpp +++ b/apps/openmw/crashcatcher.cpp @@ -382,7 +382,15 @@ static void crash_handler(const char *logfile) fflush(stdout); if(crash_info.pid > 0) + { gdb_info(crash_info.pid); + kill(crash_info.pid, SIGKILL); + } + + // delay between killing of the crashed process and showing the message box to + // work around occasional X server lock-up. this can only be a bug in X11 since + // even faulty applications shouldn't be able to freeze the X server. + usleep(100000); if(logfile) { @@ -390,9 +398,6 @@ static void crash_handler(const char *logfile) SDL_ShowSimpleMessageBox(0, "Fatal Error", message.c_str(), NULL); } - if (crash_info.pid > 0) - kill(crash_info.pid, SIGKILL); - exit(0); } From d97dda05c9533b751caa0e33b2509d50a6c35290 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 28 Nov 2015 05:55:36 +0100 Subject: [PATCH 2622/3725] Don't attempt to play unset weather sounds --- apps/openmw/mwworld/weather.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 6d9a85ada..a5e4db547 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -158,6 +158,9 @@ Weather::Weather(const std::string& name, else mAmbientLoopSoundID = fallback.getFallbackString("Weather_" + name + "_Ambient_Loop_Sound_ID"); + if (Misc::StringUtils::ciEqual(mAmbientLoopSoundID, "None")) + mAmbientLoopSoundID.clear(); + /* Unhandled: Rain Diameter=600 ? From a1fa1b2b2ec5f8d5366b4c7f72115eee84d0dbab Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 28 Nov 2015 06:00:18 +0100 Subject: [PATCH 2623/3725] Don't attempt to open an empty texture --- apps/openmw/mwrender/sky.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 66253f70d..68ee17e6b 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1550,11 +1550,13 @@ void SkyManager::setWeather(const WeatherResult& weather) { mNextClouds = weather.mNextCloudTexture; - std::string texture = Misc::ResourceHelpers::correctTexturePath(mNextClouds, mSceneManager->getVFS()); + if (!mNextClouds.empty()) + { + std::string texture = Misc::ResourceHelpers::correctTexturePath(mNextClouds, mSceneManager->getVFS()); - if (!texture.empty()) mCloudUpdater2->setTexture(mSceneManager->getTextureManager()->getTexture2D(texture, osg::Texture::REPEAT, osg::Texture::REPEAT)); + } } if (mCloudBlendFactor != weather.mCloudBlendFactor) From c9bfe0112084708fb27b47d35af4e133582881a3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 28 Nov 2015 17:57:35 +0100 Subject: [PATCH 2624/3725] Fix applying of weather changes after serving a jail sentence --- apps/openmw/mwworld/weather.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index a5e4db547..afa819121 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -627,7 +627,7 @@ void WeatherManager::update(float duration, bool paused) MWBase::World& world = *MWBase::Environment::get().getWorld(); TimeStamp time = world.getTimeStamp(); - if(!paused) + if(!paused || mFastForward) { // Add new transitions when either the player's current external region changes. std::string playerRegion = Misc::StringUtils::lowerCase(player.getCell()->getCell()->mRegion); From db71634a2d66dd6a41a706410463364e90b91c9b Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 28 Nov 2015 19:14:47 +0100 Subject: [PATCH 2625/3725] Allow replacing of interactive message boxes (Fixes #3040) --- apps/openmw/mwgui/messagebox.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index c647ecaf5..f8ddeba3e 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -117,8 +117,11 @@ namespace MWGui bool MessageBoxManager::createInteractiveMessageBox (const std::string& message, const std::vector& buttons) { - if(mInterMessageBoxe != NULL) { - throw std::runtime_error("There is a message box already"); + if (mInterMessageBoxe != NULL) + { + std::cerr << "Warning: replacing an interactive message box that was not answered yet" << std::endl; + delete mInterMessageBoxe; + mInterMessageBoxe = NULL; } mInterMessageBoxe = new InteractiveMessageBox(*this, message, buttons); From cd4a1ffd164a4f98878e440b3c33a1e6a0236d16 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 29 Nov 2015 14:13:14 +0100 Subject: [PATCH 2626/3725] Fast version of dynamic_cast for MWClass --- apps/openmw/mwclass/container.cpp | 15 ++++---- apps/openmw/mwclass/creature.cpp | 35 ++++++++++-------- apps/openmw/mwclass/creaturelevlist.cpp | 21 ++++++----- apps/openmw/mwclass/door.cpp | 23 ++++++------ apps/openmw/mwclass/npc.cpp | 48 ++++++++++++++----------- apps/openmw/mwworld/customdata.cpp | 46 ++++++++++++++++++++++++ apps/openmw/mwworld/customdata.hpp | 21 +++++++++++ 7 files changed, 150 insertions(+), 59 deletions(-) create mode 100644 apps/openmw/mwworld/customdata.cpp diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index f785797c1..6c44c97e2 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -27,23 +27,26 @@ #include "../mwmechanics/npcstats.hpp" -namespace +namespace MWClass { - struct ContainerCustomData : public MWWorld::CustomData + class ContainerCustomData : public MWWorld::CustomData { + public: MWWorld::ContainerStore mContainerStore; virtual MWWorld::CustomData *clone() const; + + virtual ContainerCustomData& asContainerCustomData() + { + return *this; + } }; MWWorld::CustomData *ContainerCustomData::clone() const { return new ContainerCustomData (*this); } -} -namespace MWClass -{ std::string Container::getId (const MWWorld::Ptr& ptr) const { return ptr.get()->mBase->mId; @@ -202,7 +205,7 @@ namespace MWClass { ensureCustomData (ptr); - return dynamic_cast (*ptr.getRefData().getCustomData()).mContainerStore; + return ptr.getRefData().getCustomData()->asContainerCustomData().mContainerStore; } std::string Container::getScript (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 95bc429e3..2cd11d113 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -40,14 +40,29 @@ namespace { - struct CreatureCustomData : public MWWorld::CustomData + bool isFlagBitSet(const MWWorld::Ptr &ptr, ESM::Creature::Flags bitMask) + { + return (ptr.get()->mBase->mFlags & bitMask) != 0; + } +} + +namespace MWClass +{ + + class CreatureCustomData : public MWWorld::CustomData { + public: MWMechanics::CreatureStats mCreatureStats; MWWorld::ContainerStore* mContainerStore; // may be InventoryStore for some creatures MWMechanics::Movement mMovement; virtual MWWorld::CustomData *clone() const; + virtual CreatureCustomData& asCreatureCustomData() + { + return *this; + } + CreatureCustomData() : mContainerStore(0) {} virtual ~CreatureCustomData() { delete mContainerStore; } }; @@ -59,14 +74,6 @@ namespace return cloned; } - bool isFlagBitSet(const MWWorld::Ptr &ptr, ESM::Creature::Flags bitMask) - { - return (ptr.get()->mBase->mFlags & bitMask) != 0; - } -} - -namespace MWClass -{ const Creature::GMST& Creature::getGmst() { static GMST gmst; @@ -193,7 +200,7 @@ namespace MWClass { ensureCustomData (ptr); - return dynamic_cast (*ptr.getRefData().getCustomData()).mCreatureStats; + return ptr.getRefData().getCustomData()->asCreatureCustomData().mCreatureStats; } @@ -421,7 +428,7 @@ namespace MWClass { ensureCustomData (ptr); - return *dynamic_cast (*ptr.getRefData().getCustomData()).mContainerStore; + return *ptr.getRefData().getCustomData()->asCreatureCustomData().mContainerStore; } MWWorld::InventoryStore& Creature::getInventoryStore(const MWWorld::Ptr &ptr) const @@ -511,7 +518,7 @@ namespace MWClass { ensureCustomData (ptr); - return dynamic_cast (*ptr.getRefData().getCustomData()).mMovement; + return ptr.getRefData().getCustomData()->asCreatureCustomData().mMovement; } MWGui::ToolTipInfo Creature::getToolTipInfo (const MWWorld::Ptr& ptr) const @@ -711,7 +718,7 @@ namespace MWClass else ensureCustomData(ptr); // in openmw 0.30 savegames not all state was saved yet, so need to load it regardless. - CreatureCustomData& customData = dynamic_cast (*ptr.getRefData().getCustomData()); + CreatureCustomData& customData = ptr.getRefData().getCustomData()->asCreatureCustomData(); customData.mContainerStore->readState (state2.mInventory); customData.mCreatureStats.readState (state2.mCreatureStats); @@ -730,7 +737,7 @@ namespace MWClass ensureCustomData (ptr); - CreatureCustomData& customData = dynamic_cast (*ptr.getRefData().getCustomData()); + CreatureCustomData& customData = ptr.getRefData().getCustomData()->asCreatureCustomData(); customData.mContainerStore->writeState (state2.mInventory); customData.mCreatureStats.writeState (state2.mCreatureStats); diff --git a/apps/openmw/mwclass/creaturelevlist.cpp b/apps/openmw/mwclass/creaturelevlist.cpp index 433e5fcea..c015d53d6 100644 --- a/apps/openmw/mwclass/creaturelevlist.cpp +++ b/apps/openmw/mwclass/creaturelevlist.cpp @@ -7,25 +7,28 @@ #include "../mwworld/customdata.hpp" -namespace +namespace MWClass { - struct CreatureLevListCustomData : public MWWorld::CustomData + class CreatureLevListCustomData : public MWWorld::CustomData { + public: // actorId of the creature we spawned int mSpawnActorId; bool mSpawn; // Should a new creature be spawned? virtual MWWorld::CustomData *clone() const; + + virtual CreatureLevListCustomData& asCreatureLevListCustomData() + { + return *this; + } }; MWWorld::CustomData *CreatureLevListCustomData::clone() const { return new CreatureLevListCustomData (*this); } -} -namespace MWClass -{ std::string CreatureLevList::getId (const MWWorld::Ptr& ptr) const { return ptr.get()->mBase->mId; @@ -40,7 +43,7 @@ namespace MWClass { ensureCustomData(ptr); - CreatureLevListCustomData& customData = dynamic_cast (*ptr.getRefData().getCustomData()); + CreatureLevListCustomData& customData = ptr.getRefData().getCustomData()->asCreatureLevListCustomData(); customData.mSpawn = true; } @@ -55,7 +58,7 @@ namespace MWClass { ensureCustomData(ptr); - CreatureLevListCustomData& customData = dynamic_cast (*ptr.getRefData().getCustomData()); + CreatureLevListCustomData& customData = ptr.getRefData().getCustomData()->asCreatureLevListCustomData(); if (!customData.mSpawn) return; @@ -104,7 +107,7 @@ namespace MWClass const ESM::CreatureLevListState& state2 = dynamic_cast (state); ensureCustomData(ptr); - CreatureLevListCustomData& customData = dynamic_cast (*ptr.getRefData().getCustomData()); + CreatureLevListCustomData& customData = ptr.getRefData().getCustomData()->asCreatureLevListCustomData(); customData.mSpawnActorId = state2.mSpawnActorId; customData.mSpawn = state2.mSpawn; } @@ -115,7 +118,7 @@ namespace MWClass ESM::CreatureLevListState& state2 = dynamic_cast (state); ensureCustomData(ptr); - CreatureLevListCustomData& customData = dynamic_cast (*ptr.getRefData().getCustomData()); + CreatureLevListCustomData& customData = ptr.getRefData().getCustomData()->asCreatureLevListCustomData(); state2.mSpawnActorId = customData.mSpawnActorId; state2.mSpawn = customData.mSpawn; } diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 47219deb7..6fee79ddf 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -28,23 +28,26 @@ #include "../mwmechanics/actorutil.hpp" -namespace +namespace MWClass { - struct DoorCustomData : public MWWorld::CustomData + class DoorCustomData : public MWWorld::CustomData { + public: int mDoorState; // 0 = nothing, 1 = opening, 2 = closing virtual MWWorld::CustomData *clone() const; + + virtual DoorCustomData& asDoorCustomData() + { + return *this; + } }; MWWorld::CustomData *DoorCustomData::clone() const { return new DoorCustomData (*this); } -} -namespace MWClass -{ std::string Door::getId (const MWWorld::Ptr& ptr) const { return ptr.get()->mBase->mId; @@ -65,7 +68,7 @@ namespace MWClass // Resume the door's opening/closing animation if it wasn't finished if (ptr.getRefData().getCustomData()) { - const DoorCustomData& customData = dynamic_cast(*ptr.getRefData().getCustomData()); + const DoorCustomData& customData = ptr.getRefData().getCustomData()->asDoorCustomData(); if (customData.mDoorState > 0) { MWBase::Environment::get().getWorld()->activateDoor(ptr, customData.mDoorState); @@ -324,7 +327,7 @@ namespace MWClass int Door::getDoorState (const MWWorld::Ptr &ptr) const { ensureCustomData(ptr); - const DoorCustomData& customData = dynamic_cast(*ptr.getRefData().getCustomData()); + const DoorCustomData& customData = ptr.getRefData().getCustomData()->asDoorCustomData(); return customData.mDoorState; } @@ -334,14 +337,14 @@ namespace MWClass throw std::runtime_error("load doors can't be moved"); ensureCustomData(ptr); - DoorCustomData& customData = dynamic_cast(*ptr.getRefData().getCustomData()); + DoorCustomData& customData = ptr.getRefData().getCustomData()->asDoorCustomData(); customData.mDoorState = state; } void Door::readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state) const { ensureCustomData(ptr); - DoorCustomData& customData = dynamic_cast(*ptr.getRefData().getCustomData()); + DoorCustomData& customData = ptr.getRefData().getCustomData()->asDoorCustomData(); const ESM::DoorState& state2 = dynamic_cast(state); customData.mDoorState = state2.mDoorState; @@ -350,7 +353,7 @@ namespace MWClass void Door::writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state) const { ensureCustomData(ptr); - const DoorCustomData& customData = dynamic_cast(*ptr.getRefData().getCustomData()); + const DoorCustomData& customData = ptr.getRefData().getCustomData()->asDoorCustomData(); ESM::DoorState& state2 = dynamic_cast(state); state2.mDoorState = customData.mDoorState; diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 5679dc3e9..6633b3490 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -42,19 +42,6 @@ namespace { - struct NpcCustomData : public MWWorld::CustomData - { - MWMechanics::NpcStats mNpcStats; - MWMechanics::Movement mMovement; - MWWorld::InventoryStore mInventoryStore; - - virtual MWWorld::CustomData *clone() const; - }; - - MWWorld::CustomData *NpcCustomData::clone() const - { - return new NpcCustomData (*this); - } int is_even(double d) { double int_part; @@ -251,6 +238,27 @@ namespace namespace MWClass { + + class NpcCustomData : public MWWorld::CustomData + { + public: + MWMechanics::NpcStats mNpcStats; + MWMechanics::Movement mMovement; + MWWorld::InventoryStore mInventoryStore; + + virtual MWWorld::CustomData *clone() const; + + virtual NpcCustomData& asNpcCustomData() + { + return *this; + } + }; + + MWWorld::CustomData *NpcCustomData::clone() const + { + return new NpcCustomData (*this); + } + const Npc::GMST& Npc::getGmst() { static GMST gmst; @@ -446,14 +454,14 @@ namespace MWClass { ensureCustomData (ptr); - return dynamic_cast (*ptr.getRefData().getCustomData()).mNpcStats; + return ptr.getRefData().getCustomData()->asNpcCustomData().mNpcStats; } MWMechanics::NpcStats& Npc::getNpcStats (const MWWorld::Ptr& ptr) const { ensureCustomData (ptr); - return dynamic_cast (*ptr.getRefData().getCustomData()).mNpcStats; + return ptr.getRefData().getCustomData()->asNpcCustomData().mNpcStats; } @@ -780,7 +788,7 @@ namespace MWClass { ensureCustomData (ptr); - return dynamic_cast (*ptr.getRefData().getCustomData()).mInventoryStore; + return ptr.getRefData().getCustomData()->asNpcCustomData().mInventoryStore; } MWWorld::InventoryStore& Npc::getInventoryStore (const MWWorld::Ptr& ptr) @@ -788,7 +796,7 @@ namespace MWClass { ensureCustomData (ptr); - return dynamic_cast (*ptr.getRefData().getCustomData()).mInventoryStore; + return ptr.getRefData().getCustomData()->asNpcCustomData().mInventoryStore; } std::string Npc::getScript (const MWWorld::Ptr& ptr) const @@ -897,7 +905,7 @@ namespace MWClass { ensureCustomData (ptr); - return dynamic_cast (*ptr.getRefData().getCustomData()).mMovement; + return ptr.getRefData().getCustomData()->asNpcCustomData().mMovement; } bool Npc::isEssential (const MWWorld::Ptr& ptr) const @@ -1161,7 +1169,7 @@ namespace MWClass else ensureCustomData(ptr); // in openmw 0.30 savegames not all state was saved yet, so need to load it regardless. - NpcCustomData& customData = dynamic_cast (*ptr.getRefData().getCustomData()); + NpcCustomData& customData = ptr.getRefData().getCustomData()->asNpcCustomData(); customData.mInventoryStore.readState (state2.mInventory); customData.mNpcStats.readState (state2.mNpcStats); @@ -1181,7 +1189,7 @@ namespace MWClass ensureCustomData (ptr); - NpcCustomData& customData = dynamic_cast (*ptr.getRefData().getCustomData()); + NpcCustomData& customData = ptr.getRefData().getCustomData()->asNpcCustomData(); customData.mInventoryStore.writeState (state2.mInventory); customData.mNpcStats.writeState (state2.mNpcStats); diff --git a/apps/openmw/mwworld/customdata.cpp b/apps/openmw/mwworld/customdata.cpp new file mode 100644 index 000000000..8edbb345f --- /dev/null +++ b/apps/openmw/mwworld/customdata.cpp @@ -0,0 +1,46 @@ +#include "customdata.hpp" + +#include +#include +#include + +namespace MWWorld +{ + +MWClass::CreatureCustomData &CustomData::asCreatureCustomData() +{ + std::stringstream error; + error << "bad cast " << typeid(this).name() << " to CreatureCustomData"; + throw std::logic_error(error.str()); +} + +MWClass::NpcCustomData &CustomData::asNpcCustomData() +{ + std::stringstream error; + error << "bad cast " << typeid(this).name() << " to NpcCustomData"; + throw std::logic_error(error.str()); +} + +MWClass::ContainerCustomData &CustomData::asContainerCustomData() +{ + std::stringstream error; + error << "bad cast " << typeid(this).name() << " to ContainerCustomData"; + throw std::logic_error(error.str()); +} + +MWClass::DoorCustomData &CustomData::asDoorCustomData() +{ + std::stringstream error; + error << "bad cast " << typeid(this).name() << " to DoorCustomData"; + throw std::logic_error(error.str()); +} + +MWClass::CreatureLevListCustomData &CustomData::asCreatureLevListCustomData() +{ + std::stringstream error; + error << "bad cast " << typeid(this).name() << " to CreatureLevListCustomData"; + throw std::logic_error(error.str()); +} + + +} diff --git a/apps/openmw/mwworld/customdata.hpp b/apps/openmw/mwworld/customdata.hpp index 588991fe4..8c3890580 100644 --- a/apps/openmw/mwworld/customdata.hpp +++ b/apps/openmw/mwworld/customdata.hpp @@ -1,6 +1,15 @@ #ifndef GAME_MWWORLD_CUSTOMDATA_H #define GAME_MWWORLD_CUSTOMDATA_H +namespace MWClass +{ + class CreatureCustomData; + class NpcCustomData; + class ContainerCustomData; + class DoorCustomData; + class CreatureLevListCustomData; +} + namespace MWWorld { /// \brief Base class for the MW-class-specific part of RefData @@ -11,6 +20,18 @@ namespace MWWorld virtual ~CustomData() {} virtual CustomData *clone() const = 0; + + // Fast version of dynamic_cast. Needs to be overridden in the respective class. + + virtual MWClass::CreatureCustomData& asCreatureCustomData(); + + virtual MWClass::NpcCustomData& asNpcCustomData(); + + virtual MWClass::ContainerCustomData& asContainerCustomData(); + + virtual MWClass::DoorCustomData& asDoorCustomData(); + + virtual MWClass::CreatureLevListCustomData& asCreatureLevListCustomData(); }; } From f962ce0bbe6848b572cd83582a36cae458b2b7d7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 29 Nov 2015 19:56:43 +0100 Subject: [PATCH 2627/3725] Don't link against unnecessary OSG libraries --- apps/opencs/CMakeLists.txt | 8 +++++++- apps/openmw/CMakeLists.txt | 8 +++++++- components/CMakeLists.txt | 10 +++++++++- 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 6af04e8fc..dc90072fa 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -205,7 +205,13 @@ if(APPLE) endif(APPLE) target_link_libraries(openmw-cs - ${OPENSCENEGRAPH_LIBRARIES} + ${OSG_LIBRARIES} + ${OPENTHREADS_LIBRARIES} + ${OSGUTIL_LIBRARIES} + ${OSGVIEWER_LIBRARIES} + ${OSGGA_LIBRARIES} + ${OSGFX_LIBRARIES} + ${OSGQT_LIBRARIES} ${Boost_SYSTEM_LIBRARY} ${Boost_FILESYSTEM_LIBRARY} ${Boost_PROGRAM_OPTIONS_LIBRARY} diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 48d10e202..e2d333e56 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -118,7 +118,13 @@ include_directories( ) target_link_libraries(openmw - ${OPENSCENEGRAPH_LIBRARIES} + ${OSG_LIBRARIES} + ${OPENTHREADS_LIBRARIES} + ${OSGPARTICLE_LIBRARIES} + ${OSGUTIL_LIBRARIES} + ${OSGDB_LIBRARIES} + ${OSGVIEWER_LIBRARIES} + ${OSGGA_LIBRARIES} ${Boost_SYSTEM_LIBRARY} ${Boost_THREAD_LIBRARY} ${Boost_FILESYSTEM_LIBRARY} diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index c80e27e4d..0f2906ce5 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -177,7 +177,15 @@ target_link_libraries(components ${Boost_FILESYSTEM_LIBRARY} ${Boost_THREAD_LIBRARY} ${Boost_PROGRAM_OPTIONS_LIBRARY} - ${OPENSCENEGRAPH_LIBRARIES} + ${OSG_LIBRARIES} + ${OPENTHREADS_LIBRARIES} + ${OSGPARTICLE_LIBRARIES} + ${OSGUTIL_LIBRARIES} + ${OSGDB_LIBRARIES} + ${OSGVIEWER_LIBRARIES} + ${OSGGA_LIBRARIES} + ${OSGFX_LIBRARIES} + ${OSGANIMATION_LIBRARIES} ${BULLET_LIBRARIES} ${SDL2_LIBRARY} # For MyGUI platform From d5a738bd392b0b28a3a65cb1128ce3fd35731046 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 30 Nov 2015 00:38:52 +0100 Subject: [PATCH 2628/3725] Apply 27e669296e5 (locale-unaware tolower) to more code In particular, the one in VFS::normalizeFilename was affecting cell loading performance. --- apps/openmw/mwdialogue/keywordsearch.hpp | 15 +++++++-------- apps/openmw/mwgui/journalviewmodel.cpp | 6 ++---- components/files/multidircollection.cpp | 4 ++-- components/files/multidircollection.hpp | 6 ++---- components/vfs/manager.cpp | 4 ++-- 5 files changed, 15 insertions(+), 20 deletions(-) diff --git a/apps/openmw/mwdialogue/keywordsearch.hpp b/apps/openmw/mwdialogue/keywordsearch.hpp index c4e1d7553..3b68d3d6b 100644 --- a/apps/openmw/mwdialogue/keywordsearch.hpp +++ b/apps/openmw/mwdialogue/keywordsearch.hpp @@ -2,7 +2,7 @@ #define GAME_MWDIALOGUE_KEYWORDSEARCH_H #include -#include +#include #include #include #include // std::reverse @@ -44,7 +44,7 @@ public: typename Entry::childen_t::iterator current; typename Entry::childen_t::iterator next; - current = mRoot.mChildren.find (std::tolower (*keyword.begin(), mLocale)); + current = mRoot.mChildren.find (tolower (*keyword.begin())); if (current == mRoot.mChildren.end()) return false; else if (current->second.mKeyword.size() && Misc::StringUtils::ciEqual(current->second.mKeyword, keyword)) @@ -55,7 +55,7 @@ public: for (Point i = ++keyword.begin(); i != keyword.end(); ++i) { - next = current->second.mChildren.find(std::tolower (*i, mLocale)); + next = current->second.mChildren.find(tolower (*i)); if (next == current->second.mChildren.end()) return false; if (Misc::StringUtils::ciEqual(next->second.mKeyword, keyword)) @@ -89,7 +89,7 @@ public: // check first character - typename Entry::childen_t::iterator candidate = mRoot.mChildren.find (std::tolower (*i, mLocale)); + typename Entry::childen_t::iterator candidate = mRoot.mChildren.find (tolower (*i)); // no match, on to next character if (candidate == mRoot.mChildren.end ()) @@ -104,7 +104,7 @@ public: while ((j + 1) != end) { - typename Entry::childen_t::iterator next = candidate->second.mChildren.find (std::tolower (*++j, mLocale)); + typename Entry::childen_t::iterator next = candidate->second.mChildren.find (tolower (*++j)); if (next == candidate->second.mChildren.end ()) { @@ -136,7 +136,7 @@ public: while (k != end && t != candidate->second.mKeyword.end ()) { - if (std::tolower (*k, mLocale) != std::tolower (*t, mLocale)) + if (tolower (*k) != tolower (*t)) break; ++k, ++t; @@ -212,7 +212,7 @@ private: void seed_impl (string_t keyword, value_t value, size_t depth, Entry & entry) { - int ch = tolower (keyword.at (depth), mLocale); + int ch = tolower (keyword.at (depth)); typename Entry::childen_t::iterator j = entry.mChildren.find (ch); @@ -249,7 +249,6 @@ private: } Entry mRoot; - std::locale mLocale; }; } diff --git a/apps/openmw/mwgui/journalviewmodel.cpp b/apps/openmw/mwgui/journalviewmodel.cpp index d05257e46..03e4813b3 100644 --- a/apps/openmw/mwgui/journalviewmodel.cpp +++ b/apps/openmw/mwgui/journalviewmodel.cpp @@ -29,8 +29,6 @@ struct JournalViewModelImpl : JournalViewModel mutable bool mKeywordSearchLoaded; mutable KeywordSearchT mKeywordSearch; - std::locale mLocale; - JournalViewModelImpl () { mKeywordSearchLoaded = false; @@ -74,7 +72,7 @@ struct JournalViewModelImpl : JournalViewModel } } - wchar_t tolower (wchar_t ch) const { return std::tolower (ch, mLocale); } + wchar_t tolower (wchar_t ch) const { return tolower (ch); } bool isEmpty () const { @@ -319,7 +317,7 @@ struct JournalViewModelImpl : JournalViewModel for (MWBase::Journal::TTopicIter i = journal->topicBegin (); i != journal->topicEnd (); ++i) { - if (i->first [0] != std::tolower (character, mLocale)) + if (i->first [0] != tolower (character)) continue; visitor (i->second.getName()); diff --git a/components/files/multidircollection.cpp b/components/files/multidircollection.cpp index 7b3b0c440..9b4a542f5 100644 --- a/components/files/multidircollection.cpp +++ b/components/files/multidircollection.cpp @@ -28,8 +28,8 @@ namespace Files for (std::size_t i=0; i #include #include -#include #include #include @@ -25,12 +24,11 @@ namespace Files return left #include -#include #include "archive.hpp" @@ -15,7 +15,7 @@ namespace char nonstrict_normalize_char(char ch) { - return ch == '\\' ? '/' : std::tolower(ch,std::locale::classic()); + return ch == '\\' ? '/' : tolower(ch); } void normalize_path(std::string& path, bool strict) From d2290a81837e404c4f1b22965c67e282f647bc44 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 30 Nov 2015 00:41:26 +0100 Subject: [PATCH 2629/3725] Don't crash when Water_SurfaceFrameCount is 0 --- apps/openmw/mwrender/water.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index ca099991e..1afb74bd7 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -551,6 +551,8 @@ void Water::createSimpleWaterStateSet(osg::Node* node, float alpha) stateset->setRenderBinDetails(MWRender::RenderBin_Water, "RenderBin"); + node->setStateSet(stateset); + std::vector > textures; int frameCount = mFallback->getFallbackInt("Water_SurfaceFrameCount"); std::string texture = mFallback->getFallbackString("Water_SurfaceTexture"); @@ -561,12 +563,15 @@ void Water::createSimpleWaterStateSet(osg::Node* node, float alpha) textures.push_back(mResourceSystem->getTextureManager()->getTexture2D(texname.str(), osg::Texture::REPEAT, osg::Texture::REPEAT)); } + if (!textures.size()) + return; + float fps = mFallback->getFallbackFloat("Water_SurfaceFPS"); osg::ref_ptr controller (new NifOsg::FlipController(0, 1.f/fps, textures)); controller->setSource(boost::shared_ptr(new SceneUtil::FrameTimeSource)); node->setUpdateCallback(controller); - node->setStateSet(stateset); + stateset->setTextureAttributeAndModes(0, textures[0], osg::StateAttribute::ON); } From e49bce7b401c1a3fa31823dcc4e3688eaf365f68 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 30 Nov 2015 01:39:41 +0100 Subject: [PATCH 2630/3725] Share the bvh of btBvhTriangleMeshShape's when possible Results in decent cell-loading speed up. (only affects bullet versions < 2.83, since we use btScaledBvhTriangleMeshShape for >=2.83) --- components/resource/bulletshape.cpp | 11 ++++++++++- components/resource/bulletshape.hpp | 4 ++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/components/resource/bulletshape.cpp b/components/resource/bulletshape.cpp index 00bcb9e04..968dbe6c6 100644 --- a/components/resource/bulletshape.cpp +++ b/components/resource/bulletshape.cpp @@ -62,7 +62,16 @@ btCollisionShape* BulletShape::duplicateCollisionShape(btCollisionShape *shape) // work around btScaledBvhTriangleMeshShape bug ( https://code.google.com/p/bullet/issues/detail?id=371 ) in older bullet versions btTriangleMesh* oldMesh = static_cast(trishape->getMeshInterface()); btTriangleMesh* newMesh = new btTriangleMesh(*oldMesh); - TriangleMeshShape* newShape = new TriangleMeshShape(newMesh, true); + + // Do not build a new bvh (not needed, since it's the same as the original shape's bvh) + bool buildBvh = true; + if (trishape->getOptimizedBvh()) + buildBvh = false; + TriangleMeshShape* newShape = new TriangleMeshShape(newMesh, true, buildBvh); + // Set original shape's bvh via pointer + // The pointer is safe because the BulletShapeInstance keeps a ref_ptr to the original BulletShape + if (!buildBvh) + newShape->setOptimizedBvh(trishape->getOptimizedBvh()); #endif return newShape; } diff --git a/components/resource/bulletshape.hpp b/components/resource/bulletshape.hpp index 78e509db7..cfae27eac 100644 --- a/components/resource/bulletshape.hpp +++ b/components/resource/bulletshape.hpp @@ -60,8 +60,8 @@ namespace Resource // Subclass btBhvTriangleMeshShape to auto-delete the meshInterface struct TriangleMeshShape : public btBvhTriangleMeshShape { - TriangleMeshShape(btStridingMeshInterface* meshInterface, bool useQuantizedAabbCompression) - : btBvhTriangleMeshShape(meshInterface, useQuantizedAabbCompression) + TriangleMeshShape(btStridingMeshInterface* meshInterface, bool useQuantizedAabbCompression, bool buildBvh = true) + : btBvhTriangleMeshShape(meshInterface, useQuantizedAabbCompression, buildBvh) { } From ac366f1603213f7ad12b25d35f9b4a97d5053057 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 30 Nov 2015 04:28:20 +0100 Subject: [PATCH 2631/3725] Fix the rig bounds being updated twice per frame Unlike what I expected, the osgUtil::UpdateVisitor is set to traverse all children (not only active children). The FrameSwitch was thus traversing both RigGeometries part of the double-buffering scheme, rather than only the one active in the current frame. --- components/nifosg/nifloader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 45e7c16df..18ece5101 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -100,7 +100,7 @@ namespace virtual void traverse(osg::NodeVisitor& nv) { - if (nv.getTraversalMode() != osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN) + if (nv.getTraversalMode() != osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN && nv.getVisitorType() != osg::NodeVisitor::UPDATE_VISITOR) osg::Group::traverse(nv); else { From 8fb328ef4f306cfe1048943aedb3186701b4eca6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 30 Nov 2015 05:19:14 +0100 Subject: [PATCH 2632/3725] Fix updating of character preview size in InventoryWindow::setGuiMode --- apps/openmw/mwgui/inventorywindow.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index e5bf1f4b4..7678cb006 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -167,13 +167,15 @@ namespace MWGui MyGUI::IntSize size(static_cast(Settings::Manager::getFloat(setting + " w", "Windows") * viewSize.width), static_cast(Settings::Manager::getFloat(setting + " h", "Windows") * viewSize.height)); + bool needUpdate = (size.width != mMainWidget->getWidth() || size.height != mMainWidget->getHeight()); + mMainWidget->setPosition(pos); mMainWidget->setSize(size); - if (size.width != mMainWidget->getWidth() || size.height != mMainWidget->getHeight()) - updatePreviewSize(); - adjustPanes(); + + if (needUpdate) + updatePreviewSize(); } SortFilterItemModel* InventoryWindow::getSortFilterModel() From 0655abcd8b40e41f650def00f7151bba3186194d Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 30 Nov 2015 05:39:51 +0100 Subject: [PATCH 2633/3725] Fix some character preview raycasting issues (Bug #2769) --- apps/openmw/mwrender/characterpreview.cpp | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index f7296b1bd..7ba8369df 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -30,6 +30,7 @@ namespace MWRender public: DrawOnceCallback () : mRendered(false) + , mLastRenderedFrame(0) { } @@ -38,13 +39,14 @@ namespace MWRender if (!mRendered) { mRendered = true; + + mLastRenderedFrame = nv->getTraversalNumber(); + traverse(node, nv); } else { node->setNodeMask(0); } - - traverse(node, nv); } void redrawNextFrame() @@ -52,8 +54,14 @@ namespace MWRender mRendered = false; } + unsigned int getLastRenderedFrame() const + { + return mLastRenderedFrame; + } + private: bool mRendered; + unsigned int mLastRenderedFrame; }; CharacterPreview::CharacterPreview(osgViewer::Viewer* viewer, Resource::ResourceSystem* resourceSystem, @@ -262,8 +270,11 @@ namespace MWRender int InventoryPreview::getSlotSelected (int posX, int posY) { osg::ref_ptr intersector (new osgUtil::LineSegmentIntersector(osgUtil::Intersector::WINDOW, posX, posY)); - intersector->setIntersectionLimit(osgUtil::LineSegmentIntersector::LIMIT_ONE); + intersector->setIntersectionLimit(osgUtil::LineSegmentIntersector::LIMIT_NEAREST); osgUtil::IntersectionVisitor visitor(intersector); + visitor.setTraversalMode(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN); + // Set the traversal number from the last draw, so that the frame switch used for RigGeometry double buffering works correctly + visitor.setTraversalNumber(mDrawOnceCallback->getLastRenderedFrame()); osg::Node::NodeMask nodeMask = mCamera->getNodeMask(); mCamera->setNodeMask(~0); From b085c09f86f9256c898fc0c629dab3f930ee9624 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Mon, 30 Nov 2015 13:36:15 +0100 Subject: [PATCH 2634/3725] Fix windows builds Can't instantiate a container (at least with MSVC) without knowing the exact size of the object being stored, forward-declares only work with pointers. I couldn't see a simple way to remove the forward declare, so pointers and memory management it is. --- apps/openmw/mwsound/soundmanagerimp.cpp | 11 ++++++----- apps/openmw/mwsound/soundmanagerimp.hpp | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 0f5cee737..71e1c97a8 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -104,9 +104,10 @@ namespace MWSound SoundBufferList::iterator sfxiter = mSoundBuffers.begin(); for(;sfxiter != mSoundBuffers.end();++sfxiter) { - if(sfxiter->mHandle) - mOutput->unloadSound(sfxiter->mHandle); - sfxiter->mHandle = 0; + if((*sfxiter)->mHandle) + mOutput->unloadSound((*sfxiter)->mHandle); + (*sfxiter)->mHandle = 0; + delete (*sfxiter); } mUnusedBuffers.clear(); } @@ -145,8 +146,8 @@ namespace MWSound min = std::max(min, 1.0f); max = std::max(min, max); - Sound_Buffer *sfx = &*mSoundBuffers.insert(mSoundBuffers.end(), - Sound_Buffer("Sound/"+sound->mSound, volume, min, max) + Sound_Buffer *sfx = *mSoundBuffers.insert(mSoundBuffers.end(), + new Sound_Buffer("Sound/"+sound->mSound, volume, min, max) ); mVFS->normalizeFilename(sfx->mResourceName); diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index 8e2df9f1a..196fb28f2 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -56,7 +56,7 @@ namespace MWSound float mVoiceVolume; float mFootstepsVolume; - typedef std::deque SoundBufferList; + typedef std::deque SoundBufferList; // List of sound buffers, grown as needed. New enties are added to the // back, allowing existing Sound_Buffer references/pointers to remain // valid. From 14b143231c2c11ee90b46e02f17d965ce747523e Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 30 Nov 2015 15:26:43 +0100 Subject: [PATCH 2635/3725] Don't crash OpGetTarget when the target disappeared (Fixes #3048) --- apps/openmw/mwmechanics/aisequence.cpp | 2 +- apps/openmw/mwscript/aiextensions.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/aisequence.cpp b/apps/openmw/mwmechanics/aisequence.cpp index a1c5ab14f..d55dc240e 100644 --- a/apps/openmw/mwmechanics/aisequence.cpp +++ b/apps/openmw/mwmechanics/aisequence.cpp @@ -72,7 +72,7 @@ bool AiSequence::getCombatTarget(MWWorld::Ptr &targetActor) const targetActor = combat->getTarget(); - return true; + return !targetActor.isEmpty(); } std::list::const_iterator AiSequence::begin() const diff --git a/apps/openmw/mwscript/aiextensions.cpp b/apps/openmw/mwscript/aiextensions.cpp index 78c84141a..22b6ac8d1 100644 --- a/apps/openmw/mwscript/aiextensions.cpp +++ b/apps/openmw/mwscript/aiextensions.cpp @@ -424,7 +424,7 @@ namespace MWScript MWWorld::Ptr targetPtr; if (creatureStats.getAiSequence().getCombatTarget (targetPtr)) { - if (targetPtr.getCellRef().getRefId() == testedTargetId) + if (!targetPtr.isEmpty() && targetPtr.getCellRef().getRefId() == testedTargetId) targetsAreEqual = true; } runtime.push(int(targetsAreEqual)); From 576d5111a5747d1773c13439033754541b5d22d5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 30 Nov 2015 17:04:45 +0100 Subject: [PATCH 2636/3725] Prefer Intersector::PROJECTION over Intersector::WINDOW --- apps/openmw/mwrender/characterpreview.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 7ba8369df..e2ff08b6b 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -269,7 +269,11 @@ namespace MWRender int InventoryPreview::getSlotSelected (int posX, int posY) { - osg::ref_ptr intersector (new osgUtil::LineSegmentIntersector(osgUtil::Intersector::WINDOW, posX, posY)); + float projX = (posX / mCamera->getViewport()->width()) * 2 - 1.f; + float projY = (posY / mCamera->getViewport()->height()) * 2 - 1.f; + // With Intersector::WINDOW, the intersection ratios are slightly inaccurate. TODO: investigate + osg::ref_ptr intersector (new osgUtil::LineSegmentIntersector(osgUtil::Intersector::PROJECTION, projX, projY)); + intersector->setIntersectionLimit(osgUtil::LineSegmentIntersector::LIMIT_NEAREST); osgUtil::IntersectionVisitor visitor(intersector); visitor.setTraversalMode(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN); From f5f3d18b8e7e4842cd4be02729ffd51eb24b73a8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 30 Nov 2015 17:19:27 +0100 Subject: [PATCH 2637/3725] Add comment --- apps/openmw/mwrender/characterpreview.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index e2ff08b6b..a6f68b5d4 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -271,7 +271,10 @@ namespace MWRender { float projX = (posX / mCamera->getViewport()->width()) * 2 - 1.f; float projY = (posY / mCamera->getViewport()->height()) * 2 - 1.f; - // With Intersector::WINDOW, the intersection ratios are slightly inaccurate. TODO: investigate + // With Intersector::WINDOW, the intersection ratios are slightly inaccurate. Seems to be a + // precision issue - compiling with OSG_USE_FLOAT_MATRIX=0, Intersector::WINDOW works ok. + // Using Intersector::PROJECTION results in better precision because the start/end points and the model matrices + // don't go through as many transformations. osg::ref_ptr intersector (new osgUtil::LineSegmentIntersector(osgUtil::Intersector::PROJECTION, projX, projY)); intersector->setIntersectionLimit(osgUtil::LineSegmentIntersector::LIMIT_NEAREST); From a69e751089d5d7c9189b64687560033cf14cda0c Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Mon, 30 Nov 2015 17:38:46 +0100 Subject: [PATCH 2638/3725] Revert "Fix windows builds" This reverts commit b085c09f86f9256c898fc0c629dab3f930ee9624. --- apps/openmw/mwsound/soundmanagerimp.cpp | 11 +++++------ apps/openmw/mwsound/soundmanagerimp.hpp | 2 +- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 71e1c97a8..0f5cee737 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -104,10 +104,9 @@ namespace MWSound SoundBufferList::iterator sfxiter = mSoundBuffers.begin(); for(;sfxiter != mSoundBuffers.end();++sfxiter) { - if((*sfxiter)->mHandle) - mOutput->unloadSound((*sfxiter)->mHandle); - (*sfxiter)->mHandle = 0; - delete (*sfxiter); + if(sfxiter->mHandle) + mOutput->unloadSound(sfxiter->mHandle); + sfxiter->mHandle = 0; } mUnusedBuffers.clear(); } @@ -146,8 +145,8 @@ namespace MWSound min = std::max(min, 1.0f); max = std::max(min, max); - Sound_Buffer *sfx = *mSoundBuffers.insert(mSoundBuffers.end(), - new Sound_Buffer("Sound/"+sound->mSound, volume, min, max) + Sound_Buffer *sfx = &*mSoundBuffers.insert(mSoundBuffers.end(), + Sound_Buffer("Sound/"+sound->mSound, volume, min, max) ); mVFS->normalizeFilename(sfx->mResourceName); diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index 196fb28f2..8e2df9f1a 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -56,7 +56,7 @@ namespace MWSound float mVoiceVolume; float mFootstepsVolume; - typedef std::deque SoundBufferList; + typedef std::deque SoundBufferList; // List of sound buffers, grown as needed. New enties are added to the // back, allowing existing Sound_Buffer references/pointers to remain // valid. From 682329851633b6cb956ca01514a4b0cf26c9844b Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Mon, 30 Nov 2015 17:42:25 +0100 Subject: [PATCH 2639/3725] Different way to solve the type deduction issue --- apps/openmw/mwsound/soundmanagerimp.cpp | 7 ++++--- apps/openmw/mwsound/soundmanagerimp.hpp | 3 ++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 0f5cee737..ceff1a619 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -40,6 +40,7 @@ namespace MWSound , mMusicVolume(1.0f) , mVoiceVolume(1.0f) , mFootstepsVolume(1.0f) + , mSoundBuffers(new SoundBufferList::element_type()) , mBufferCacheSize(0) , mListenerUnderwater(false) , mListenerPos(0,0,0) @@ -101,8 +102,8 @@ namespace MWSound clear(); if(mOutput->isInitialized()) { - SoundBufferList::iterator sfxiter = mSoundBuffers.begin(); - for(;sfxiter != mSoundBuffers.end();++sfxiter) + SoundBufferList::element_type::iterator sfxiter = mSoundBuffers->begin(); + for(;sfxiter != mSoundBuffers->end();++sfxiter) { if(sfxiter->mHandle) mOutput->unloadSound(sfxiter->mHandle); @@ -145,7 +146,7 @@ namespace MWSound min = std::max(min, 1.0f); max = std::max(min, max); - Sound_Buffer *sfx = &*mSoundBuffers.insert(mSoundBuffers.end(), + Sound_Buffer *sfx = &*mSoundBuffers->insert(mSoundBuffers->end(), Sound_Buffer("Sound/"+sound->mSound, volume, min, max) ); mVFS->normalizeFilename(sfx->mResourceName); diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index 8e2df9f1a..424fa712c 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -1,6 +1,7 @@ #ifndef GAME_SOUND_SOUNDMANAGER_H #define GAME_SOUND_SOUNDMANAGER_H +#include #include #include #include @@ -56,7 +57,7 @@ namespace MWSound float mVoiceVolume; float mFootstepsVolume; - typedef std::deque SoundBufferList; + typedef std::auto_ptr> SoundBufferList; // List of sound buffers, grown as needed. New enties are added to the // back, allowing existing Sound_Buffer references/pointers to remain // valid. From 24340bff959fef20cc4277afd2666caa07dcd4de Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Mon, 30 Nov 2015 17:47:36 +0100 Subject: [PATCH 2640/3725] Add a space --- apps/openmw/mwsound/soundmanagerimp.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index 424fa712c..9c090585b 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -57,7 +57,7 @@ namespace MWSound float mVoiceVolume; float mFootstepsVolume; - typedef std::auto_ptr> SoundBufferList; + typedef std::auto_ptr > SoundBufferList; // List of sound buffers, grown as needed. New enties are added to the // back, allowing existing Sound_Buffer references/pointers to remain // valid. From 695fcf41c436ab67e00094772db736964a3eddba Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 30 Nov 2015 20:45:32 +0100 Subject: [PATCH 2641/3725] Optimize ValueInterpolator / KeyframeController Cache the current position in the animation track and attempt to reuse it in the next frame. Decent speed up for the Update phase, about 0.3 ms faster in Balmora. --- components/nif/nifkey.hpp | 3 + components/nifosg/controller.cpp | 107 +++++++++--------------- components/nifosg/controller.hpp | 138 ++++++++++++++++++++++++------- components/nifosg/particle.cpp | 4 +- components/nifosg/particle.hpp | 5 +- 5 files changed, 151 insertions(+), 106 deletions(-) diff --git a/components/nif/nifkey.hpp b/components/nif/nifkey.hpp index d702d0292..682baed05 100644 --- a/components/nif/nifkey.hpp +++ b/components/nif/nifkey.hpp @@ -37,6 +37,9 @@ template struct KeyMapT { typedef std::map< float, KeyT > MapType; + typedef T ValueType; + typedef KeyT KeyType; + static const unsigned int sLinearInterpolation = 1; static const unsigned int sQuadraticInterpolation = 2; static const unsigned int sTBCInterpolation = 3; diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index 93c1de89a..b8a38cf0f 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -86,56 +86,23 @@ KeyframeController::KeyframeController(const KeyframeController ©, const osg KeyframeController::KeyframeController(const Nif::NiKeyframeData *data) : mRotations(data->mRotations) - , mXRotations(data->mXRotations) - , mYRotations(data->mYRotations) - , mZRotations(data->mZRotations) - , mTranslations(data->mTranslations) - , mScales(data->mScales) + , mXRotations(data->mXRotations, 0.f) + , mYRotations(data->mYRotations, 0.f) + , mZRotations(data->mZRotations, 0.f) + , mTranslations(data->mTranslations, osg::Vec3f()) + , mScales(data->mScales, 1.f) { } -osg::Quat KeyframeController::interpKey(const Nif::QuaternionKeyMap::MapType &keys, float time) -{ - if(time <= keys.begin()->first) - return keys.begin()->second.mValue; - - Nif::QuaternionKeyMap::MapType::const_iterator it = keys.lower_bound(time); - if (it != keys.end()) - { - float aTime = it->first; - const Nif::QuaternionKey* aKey = &it->second; - - assert (it != keys.begin()); // Shouldn't happen, was checked at beginning of this function - - Nif::QuaternionKeyMap::MapType::const_iterator last = --it; - float aLastTime = last->first; - const Nif::QuaternionKey* aLastKey = &last->second; - - float a = (time - aLastTime) / (aTime - aLastTime); - - osg::Quat v1 = aLastKey->mValue; - osg::Quat v2 = aKey->mValue; - // don't take the long path - if (v1.x()*v2.x() + v1.y()*v2.y() + v1.z()*v2.z() + v1.w()*v2.w() < 0) // dotProduct(v1,v2) - v1 = -v1; - - osg::Quat result; - result.slerp(a, v1, v2); - return result; - } - else - return keys.rbegin()->second.mValue; -} - osg::Quat KeyframeController::getXYZRotation(float time) const { float xrot = 0, yrot = 0, zrot = 0; - if (mXRotations.get()) - xrot = interpKey(mXRotations->mKeys, time); - if (mYRotations.get()) - yrot = interpKey(mYRotations->mKeys, time); - if (mZRotations.get()) - zrot = interpKey(mZRotations->mKeys, time); + if (!mXRotations.empty()) + xrot = mXRotations.interpKey(time); + if (!mYRotations.empty()) + yrot = mYRotations.interpKey(time); + if (!mZRotations.empty()) + zrot = mZRotations.interpKey(time); osg::Quat xr(xrot, osg::Vec3f(1,0,0)); osg::Quat yr(yrot, osg::Vec3f(0,1,0)); osg::Quat zr(zrot, osg::Vec3f(0,0,1)); @@ -144,8 +111,8 @@ osg::Quat KeyframeController::getXYZRotation(float time) const osg::Vec3f KeyframeController::getTranslation(float time) const { - if(mTranslations.get() && mTranslations->mKeys.size() > 0) - return interpKey(mTranslations->mKeys, time); + if(!mTranslations.empty()) + return mTranslations.interpKey(time); return osg::Vec3f(); } @@ -162,12 +129,12 @@ void KeyframeController::operator() (osg::Node* node, osg::NodeVisitor* nv) Nif::Matrix3& rot = userdata->mRotationScale; bool setRot = false; - if(mRotations.get() && !mRotations->mKeys.empty()) + if(!mRotations.empty()) { - mat.setRotate(interpKey(mRotations->mKeys, time)); + mat.setRotate(mRotations.interpKey(time)); setRot = true; } - else if (mXRotations.get() || mYRotations.get() || mZRotations.get()) + else if (!mXRotations.empty() || !mYRotations.empty() || !mZRotations.empty()) { mat.setRotate(getXYZRotation(time)); setRot = true; @@ -186,15 +153,15 @@ void KeyframeController::operator() (osg::Node* node, osg::NodeVisitor* nv) rot.mValues[i][j] = mat(j,i); // NB column/row major difference float& scale = userdata->mScale; - if(mScales.get() && !mScales->mKeys.empty()) - scale = interpKey(mScales->mKeys, time); + if(!mScales.empty()) + scale = mScales.interpKey(time); for (int i=0;i<3;++i) for (int j=0;j<3;++j) mat(i,j) *= scale; - if(mTranslations.get() && !mTranslations->mKeys.empty()) - mat.setTrans(interpKey(mTranslations->mKeys, time)); + if(!mTranslations.empty()) + mat.setTrans(mTranslations.interpKey(time)); trans->setMatrix(mat); } @@ -216,7 +183,7 @@ GeomMorpherController::GeomMorpherController(const GeomMorpherController ©, GeomMorpherController::GeomMorpherController(const Nif::NiMorphData *data) { for (unsigned int i=0; imMorphs.size(); ++i) - mKeyFrames.push_back(data->mMorphs[i].mKeyFrames); + mKeyFrames.push_back(FloatInterpolator(data->mMorphs[i].mKeyFrames)); } void GeomMorpherController::update(osg::NodeVisitor *nv, osg::Drawable *drawable) @@ -228,11 +195,11 @@ void GeomMorpherController::update(osg::NodeVisitor *nv, osg::Drawable *drawable return; float input = getInputValue(nv); int i = 0; - for (std::vector::iterator it = mKeyFrames.begin()+1; it != mKeyFrames.end(); ++it,++i) + for (std::vector::iterator it = mKeyFrames.begin()+1; it != mKeyFrames.end(); ++it,++i) { float val = 0; - if (!(*it)->mKeys.empty()) - val = interpKey((*it)->mKeys, input); + if (!(*it).empty()) + val = it->interpKey(input); val = std::max(0.f, std::min(1.f, val)); osgAnimation::MorphGeometry::MorphTarget& target = morphGeom->getMorphTarget(i); @@ -252,10 +219,10 @@ UVController::UVController() } UVController::UVController(const Nif::NiUVData *data, std::set textureUnits) - : mUTrans(data->mKeyList[0]) - , mVTrans(data->mKeyList[1]) - , mUScale(data->mKeyList[2]) - , mVScale(data->mKeyList[3]) + : mUTrans(data->mKeyList[0], 0.f) + , mVTrans(data->mKeyList[1], 0.f) + , mUScale(data->mKeyList[2], 1.f) + , mVScale(data->mKeyList[3], 1.f) , mTextureUnits(textureUnits) { } @@ -282,10 +249,10 @@ void UVController::apply(osg::StateSet* stateset, osg::NodeVisitor* nv) if (hasInput()) { float value = getInputValue(nv); - float uTrans = interpKey(mUTrans->mKeys, value, 0.0f); - float vTrans = interpKey(mVTrans->mKeys, value, 0.0f); - float uScale = interpKey(mUScale->mKeys, value, 1.0f); - float vScale = interpKey(mVScale->mKeys, value, 1.0f); + float uTrans = mUTrans.interpKey(value); + float vTrans = mVTrans.interpKey(value); + float uScale = mUScale.interpKey(value); + float vScale = mVScale.interpKey(value); osg::Matrixf mat = osg::Matrixf::scale(uScale, vScale, 1); mat.setTrans(uTrans, vTrans, 0); @@ -340,7 +307,7 @@ void VisController::operator() (osg::Node* node, osg::NodeVisitor* nv) } AlphaController::AlphaController(const Nif::NiFloatData *data) - : mData(data->mKeyList) + : mData(data->mKeyList, 1.f) { } @@ -350,7 +317,7 @@ AlphaController::AlphaController() } AlphaController::AlphaController(const AlphaController ©, const osg::CopyOp ©op) - : StateSetUpdater(copy, copyop), Controller(copy), ValueInterpolator() + : StateSetUpdater(copy, copyop), Controller(copy) , mData(copy.mData) { } @@ -366,7 +333,7 @@ void AlphaController::apply(osg::StateSet *stateset, osg::NodeVisitor *nv) { if (hasInput()) { - float value = interpKey(mData->mKeys, getInputValue(nv)); + float value = mData.interpKey(getInputValue(nv)); osg::Material* mat = static_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); osg::Vec4f diffuse = mat->getDiffuse(osg::Material::FRONT_AND_BACK); diffuse.a() = value; @@ -375,7 +342,7 @@ void AlphaController::apply(osg::StateSet *stateset, osg::NodeVisitor *nv) } MaterialColorController::MaterialColorController(const Nif::NiPosData *data) - : mData(data->mKeyList) + : mData(data->mKeyList, osg::Vec3f(1,1,1)) { } @@ -400,7 +367,7 @@ void MaterialColorController::apply(osg::StateSet *stateset, osg::NodeVisitor *n { if (hasInput()) { - osg::Vec3f value = interpKey(mData->mKeys, getInputValue(nv)); + osg::Vec3f value = mData.interpKey(getInputValue(nv)); osg::Material* mat = static_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); osg::Vec4f diffuse = mat->getDiffuse(osg::Material::FRONT_AND_BACK); diffuse.set(value.x(), value.y(), value.z(), diffuse.a()); diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index 803ce77a2..eabf80f13 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -42,38 +42,116 @@ namespace osgAnimation namespace NifOsg { + // interpolation of keyframes + template class ValueInterpolator { - protected: - template - T interpKey (const std::map< float, Nif::KeyT >& keys, float time, T defaultValue = T()) const + public: + ValueInterpolator() + : mDefaultVal(typename MapT::ValueType()) + { + } + + ValueInterpolator(boost::shared_ptr keys, typename MapT::ValueType defaultVal = typename MapT::ValueType()) + : mKeys(keys) + , mDefaultVal(defaultVal) + { + if (keys) + { + mLastLowKey = mKeys->mKeys.end(); + mLastHighKey = mKeys->mKeys.end(); + } + } + + typename MapT::ValueType interpKey(float time) const { - if (keys.size() == 0) - return defaultValue; + if (empty()) + return mDefaultVal; + + const typename MapT::MapType & keys = mKeys->mKeys; if(time <= keys.begin()->first) return keys.begin()->second.mValue; - typename std::map< float, Nif::KeyT >::const_iterator it = keys.lower_bound(time); + // retrieve the current position in the map, optimized for the most common case + // where time moves linearly along the keyframe track + typename MapT::MapType::const_iterator it = mLastHighKey; + if (mLastHighKey != keys.end()) + { + if (time > mLastHighKey->first) + { + // try if we're there by incrementing one + ++mLastLowKey; + ++mLastHighKey; + it = mLastHighKey; + } + if (mLastHighKey == keys.end() || (time < mLastLowKey->first || time > mLastHighKey->first)) + it = keys.lower_bound(time); // still not there, reorient by performing lower_bound check on the whole map + } + else + it = keys.lower_bound(time); + + // now do the actual interpolation if (it != keys.end()) { float aTime = it->first; - const Nif::KeyT* aKey = &it->second; + const typename MapT::KeyType* aKey = &it->second; + + // cache for next time + mLastHighKey = it; assert (it != keys.begin()); // Shouldn't happen, was checked at beginning of this function - typename std::map< float, Nif::KeyT >::const_iterator last = --it; + typename MapT::MapType::const_iterator last = --it; + mLastLowKey = last; float aLastTime = last->first; - const Nif::KeyT* aLastKey = &last->second; + const typename MapT::KeyType* aLastKey = &last->second; float a = (time - aLastTime) / (aTime - aLastTime); - return aLastKey->mValue + ((aKey->mValue - aLastKey->mValue) * a); + + return InterpolationFunc()(aLastKey->mValue, aKey->mValue, a); } else return keys.rbegin()->second.mValue; } + + bool empty() const + { + return !mKeys || mKeys->mKeys.empty(); + } + + private: + mutable typename MapT::MapType::const_iterator mLastLowKey; + mutable typename MapT::MapType::const_iterator mLastHighKey; + + boost::shared_ptr mKeys; + + typename MapT::ValueType mDefaultVal; + }; + + struct LerpFunc + { + template + inline ValueType operator()(const ValueType& a, const ValueType& b, float fraction) + { + return a + ((b - a) * fraction); + } }; + struct QuaternionSlerpFunc + { + inline osg::Quat operator()(const osg::Quat& a, const osg::Quat& b, float fraction) + { + osg::Quat result; + result.slerp(fraction, a, b); + return result; + } + }; + + typedef ValueInterpolator QuaternionInterpolator; + typedef ValueInterpolator FloatInterpolator; + typedef ValueInterpolator Vec3Interpolator; + class ControllerFunction : public SceneUtil::ControllerFunction { private: @@ -98,7 +176,7 @@ namespace NifOsg }; /// Must be set on an osgAnimation::MorphGeometry. - class GeomMorpherController : public osg::Drawable::UpdateCallback, public SceneUtil::Controller, public ValueInterpolator + class GeomMorpherController : public osg::Drawable::UpdateCallback, public SceneUtil::Controller { public: GeomMorpherController(const Nif::NiMorphData* data); @@ -110,10 +188,10 @@ namespace NifOsg virtual void update(osg::NodeVisitor* nv, osg::Drawable* drawable); private: - std::vector mKeyFrames; + std::vector mKeyFrames; }; - class KeyframeController : public osg::NodeCallback, public SceneUtil::Controller, public ValueInterpolator + class KeyframeController : public osg::NodeCallback, public SceneUtil::Controller { public: KeyframeController(const Nif::NiKeyframeData *data); @@ -127,23 +205,19 @@ namespace NifOsg virtual void operator() (osg::Node*, osg::NodeVisitor*); private: - Nif::QuaternionKeyMapPtr mRotations; - - Nif::FloatKeyMapPtr mXRotations; - Nif::FloatKeyMapPtr mYRotations; - Nif::FloatKeyMapPtr mZRotations; - - Nif::Vector3KeyMapPtr mTranslations; - Nif::FloatKeyMapPtr mScales; + QuaternionInterpolator mRotations; - using ValueInterpolator::interpKey; + FloatInterpolator mXRotations; + FloatInterpolator mYRotations; + FloatInterpolator mZRotations; - osg::Quat interpKey(const Nif::QuaternionKeyMap::MapType &keys, float time); + Vec3Interpolator mTranslations; + FloatInterpolator mScales; osg::Quat getXYZRotation(float time) const; }; - class UVController : public SceneUtil::StateSetUpdater, public SceneUtil::Controller, public ValueInterpolator + class UVController : public SceneUtil::StateSetUpdater, public SceneUtil::Controller { public: UVController(); @@ -156,10 +230,10 @@ namespace NifOsg virtual void apply(osg::StateSet *stateset, osg::NodeVisitor *nv); private: - Nif::FloatKeyMapPtr mUTrans; - Nif::FloatKeyMapPtr mVTrans; - Nif::FloatKeyMapPtr mUScale; - Nif::FloatKeyMapPtr mVScale; + FloatInterpolator mUTrans; + FloatInterpolator mVTrans; + FloatInterpolator mUScale; + FloatInterpolator mVScale; std::set mTextureUnits; }; @@ -180,10 +254,10 @@ namespace NifOsg virtual void operator() (osg::Node* node, osg::NodeVisitor* nv); }; - class AlphaController : public SceneUtil::StateSetUpdater, public SceneUtil::Controller, public ValueInterpolator + class AlphaController : public SceneUtil::StateSetUpdater, public SceneUtil::Controller { private: - Nif::FloatKeyMapPtr mData; + FloatInterpolator mData; public: AlphaController(const Nif::NiFloatData *data); @@ -197,10 +271,10 @@ namespace NifOsg META_Object(NifOsg, AlphaController) }; - class MaterialColorController : public SceneUtil::StateSetUpdater, public SceneUtil::Controller, public ValueInterpolator + class MaterialColorController : public SceneUtil::StateSetUpdater, public SceneUtil::Controller { private: - Nif::Vector3KeyMapPtr mData; + Vec3Interpolator mData; public: MaterialColorController(const Nif::NiPosData *data); diff --git a/components/nifosg/particle.cpp b/components/nifosg/particle.cpp index e30837d39..08b62901b 100644 --- a/components/nifosg/particle.cpp +++ b/components/nifosg/particle.cpp @@ -127,7 +127,7 @@ void GrowFadeAffector::operate(osgParticle::Particle* particle, double /* dt */) } ParticleColorAffector::ParticleColorAffector(const Nif::NiColorData *clrdata) - : mData(*clrdata) + : mData(clrdata->mKeyMap, osg::Vec4f(1,1,1,1)) { } @@ -145,7 +145,7 @@ ParticleColorAffector::ParticleColorAffector(const ParticleColorAffector ©, void ParticleColorAffector::operate(osgParticle::Particle* particle, double /* dt */) { float time = static_cast(particle->getAge()/particle->getLifeTime()); - osg::Vec4f color = interpKey(mData.mKeyMap->mKeys, time, osg::Vec4f(1,1,1,1)); + osg::Vec4f color = mData.interpKey(time); particle->setColorRange(osgParticle::rangev4(color, color)); } diff --git a/components/nifosg/particle.hpp b/components/nifosg/particle.hpp index bfb127218..ff4c66758 100644 --- a/components/nifosg/particle.hpp +++ b/components/nifosg/particle.hpp @@ -130,7 +130,8 @@ namespace NifOsg float mCachedDefaultSize; }; - class ParticleColorAffector : public osgParticle::Operator, public ValueInterpolator + typedef ValueInterpolator Vec4Interpolator; + class ParticleColorAffector : public osgParticle::Operator { public: ParticleColorAffector(const Nif::NiColorData* clrdata); @@ -142,7 +143,7 @@ namespace NifOsg virtual void operate(osgParticle::Particle* particle, double dt); private: - Nif::NiColorData mData; + Vec4Interpolator mData; }; class GravityAffector : public osgParticle::Operator From e5ec4fe042f34a163c441b9de7ab04be1e8377c6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 30 Nov 2015 21:02:16 +0100 Subject: [PATCH 2642/3725] Add const specifier --- components/nifosg/controller.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index eabf80f13..ba353e247 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -52,7 +52,7 @@ namespace NifOsg { } - ValueInterpolator(boost::shared_ptr keys, typename MapT::ValueType defaultVal = typename MapT::ValueType()) + ValueInterpolator(boost::shared_ptr keys, typename MapT::ValueType defaultVal = typename MapT::ValueType()) : mKeys(keys) , mDefaultVal(defaultVal) { @@ -124,7 +124,7 @@ namespace NifOsg mutable typename MapT::MapType::const_iterator mLastLowKey; mutable typename MapT::MapType::const_iterator mLastHighKey; - boost::shared_ptr mKeys; + boost::shared_ptr mKeys; typename MapT::ValueType mDefaultVal; }; From e42f4999bdf6e49e2a1eefbc4e058a4723e17244 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Tue, 1 Dec 2015 04:06:34 +0100 Subject: [PATCH 2643/3725] Quick fix for building on MSVC --- components/nifosg/controller.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index ba353e247..7dae7f88a 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -52,7 +52,7 @@ namespace NifOsg { } - ValueInterpolator(boost::shared_ptr keys, typename MapT::ValueType defaultVal = typename MapT::ValueType()) + ValueInterpolator(boost::shared_ptr keys, typename MapT::ValueType defaultVal = MapT::ValueType()) : mKeys(keys) , mDefaultVal(defaultVal) { From cfcbd20d996132697cfaaa0ad3d6fd8829b02579 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Tue, 1 Dec 2015 04:19:30 +0100 Subject: [PATCH 2644/3725] Let's put it as a MSVC-only fix for now --- components/nifosg/controller.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index 7dae7f88a..a8f52b443 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -52,7 +52,11 @@ namespace NifOsg { } +#ifdef _MSC_VER ValueInterpolator(boost::shared_ptr keys, typename MapT::ValueType defaultVal = MapT::ValueType()) +#else + ValueInterpolator(boost::shared_ptr keys, typename MapT::ValueType defaultVal = typename MapT::ValueType()) +#endif : mKeys(keys) , mDefaultVal(defaultVal) { From 2327a418262880877ae51169ec19ac7e91de5bff Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 1 Dec 2015 16:09:05 +0100 Subject: [PATCH 2645/3725] Fix journal freeze --- apps/openmw/mwgui/journalviewmodel.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/openmw/mwgui/journalviewmodel.cpp b/apps/openmw/mwgui/journalviewmodel.cpp index 03e4813b3..f566e7769 100644 --- a/apps/openmw/mwgui/journalviewmodel.cpp +++ b/apps/openmw/mwgui/journalviewmodel.cpp @@ -72,8 +72,6 @@ struct JournalViewModelImpl : JournalViewModel } } - wchar_t tolower (wchar_t ch) const { return tolower (ch); } - bool isEmpty () const { MWBase::Journal * journal = MWBase::Environment::get().getJournal(); From c912310c52816aa0ff657253ad1fe3fe1643a4b8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 1 Dec 2015 16:16:21 +0100 Subject: [PATCH 2646/3725] Don't add persuasion results to the journal --- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index f8c9bb38e..c5e271b7a 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -298,15 +298,18 @@ namespace MWDialogue MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor); win->addResponse (Interpreter::fixDefinesDialog(info->mResponse, interpreterContext), title); - // Make sure the returned DialInfo is from the Dialogue we supplied. If could also be from the Info refusal group, - // in which case it should not be added to the journal. - for (ESM::Dialogue::InfoContainer::const_iterator iter = dialogue.mInfo.begin(); - iter!=dialogue.mInfo.end(); ++iter) + if (dialogue.mType == ESM::Dialogue::Topic) { - if (iter->mId == info->mId) + // Make sure the returned DialInfo is from the Dialogue we supplied. If could also be from the Info refusal group, + // in which case it should not be added to the journal. + for (ESM::Dialogue::InfoContainer::const_iterator iter = dialogue.mInfo.begin(); + iter!=dialogue.mInfo.end(); ++iter) { - MWBase::Environment::get().getJournal()->addTopic (topic, info->mId, mActor); - break; + if (iter->mId == info->mId) + { + MWBase::Environment::get().getJournal()->addTopic (topic, info->mId, mActor); + break; + } } } From c9d710f3340e19e3fb7260f6076ff33a53a3299a Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 1 Dec 2015 16:18:19 +0100 Subject: [PATCH 2647/3725] Use a typedef to avoid conditional compiling --- components/nifosg/controller.hpp | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index a8f52b443..e1e969d06 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -47,16 +47,14 @@ namespace NifOsg class ValueInterpolator { public: + typedef typename MapT::ValueType ValueT; + ValueInterpolator() - : mDefaultVal(typename MapT::ValueType()) + : mDefaultVal(ValueT()) { } -#ifdef _MSC_VER - ValueInterpolator(boost::shared_ptr keys, typename MapT::ValueType defaultVal = MapT::ValueType()) -#else - ValueInterpolator(boost::shared_ptr keys, typename MapT::ValueType defaultVal = typename MapT::ValueType()) -#endif + ValueInterpolator(boost::shared_ptr keys, ValueT defaultVal = ValueT()) : mKeys(keys) , mDefaultVal(defaultVal) { @@ -67,7 +65,7 @@ namespace NifOsg } } - typename MapT::ValueType interpKey(float time) const + ValueT interpKey(float time) const { if (empty()) return mDefaultVal; @@ -130,7 +128,7 @@ namespace NifOsg boost::shared_ptr mKeys; - typename MapT::ValueType mDefaultVal; + ValueT mDefaultVal; }; struct LerpFunc From 84305a1297f6749a8ec82df2ec95e4a4a6d7d91c Mon Sep 17 00:00:00 2001 From: Dmitry Marakasov Date: Wed, 2 Dec 2015 04:17:54 +0300 Subject: [PATCH 2648/3725] Reuse DATADIR in data paths --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d038936d3..5106db666 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -88,8 +88,8 @@ if (APPLE) set(MORROWIND_DATA_FILES "./data" CACHE PATH "location of Morrowind data files") set(OPENMW_RESOURCE_FILES "./resources" CACHE PATH "location of OpenMW resources files") elseif(UNIX) - set(MORROWIND_DATA_FILES "${CMAKE_INSTALL_PREFIX}/share/games/openmw/data/" CACHE PATH "location of Morrowind data files") - set(OPENMW_RESOURCE_FILES "${CMAKE_INSTALL_PREFIX}/share/games/openmw/resources/" CACHE PATH "location of OpenMW resources files") + set(MORROWIND_DATA_FILES "${DATADIR}/data" CACHE PATH "location of Morrowind data files") + set(OPENMW_RESOURCE_FILES "${DATADIR}/resources" CACHE PATH "location of OpenMW resources files") else() set(MORROWIND_DATA_FILES "data" CACHE PATH "location of Morrowind data files") set(OPENMW_RESOURCE_FILES "resources" CACHE PATH "location of OpenMW resources files") From 3d12b2ca9d242fdc55d8dfb0895d23e76b17b3df Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 1 Dec 2015 23:04:02 +0100 Subject: [PATCH 2649/3725] Add NifFileManager to avoid duplicate parsing of the NIFFile in SceneManager and BulletShapeManager. --- apps/openmw/mwphysics/physicssystem.cpp | 2 +- apps/openmw/mwworld/scene.cpp | 4 ++ components/CMakeLists.txt | 2 +- components/resource/bulletshapemanager.cpp | 8 +-- components/resource/bulletshapemanager.hpp | 4 +- components/resource/niffilemanager.cpp | 64 ++++++++++++++++++++++ components/resource/niffilemanager.hpp | 45 +++++++++++++++ components/resource/resourcesystem.cpp | 14 ++++- components/resource/resourcesystem.hpp | 8 ++- components/resource/scenemanager.cpp | 12 ++-- components/resource/scenemanager.hpp | 6 +- 11 files changed, 153 insertions(+), 16 deletions(-) create mode 100644 components/resource/niffilemanager.cpp create mode 100644 components/resource/niffilemanager.hpp diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 1f59c5c99..db010d0fb 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -636,7 +636,7 @@ namespace MWPhysics // --------------------------------------------------------------- PhysicsSystem::PhysicsSystem(Resource::ResourceSystem* resourceSystem, osg::ref_ptr parentNode) - : mShapeManager(new Resource::BulletShapeManager(resourceSystem->getVFS(), resourceSystem->getSceneManager())) + : mShapeManager(new Resource::BulletShapeManager(resourceSystem->getVFS(), resourceSystem->getSceneManager(), resourceSystem->getNifFileManager())) , mDebugDrawEnabled(false) , mTimeAccum(0.0f) , mWaterHeight(0) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 5598598d0..c6b50aae3 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -403,6 +403,8 @@ namespace MWWorld // Delay the map update until scripts have been given a chance to run. // If we don't do this, objects that should be disabled will still appear on the map. mNeedMapUpdate = true; + + mRendering.getResourceSystem()->clearCache(); } void Scene::changePlayerCell(CellStore *cell, const ESM::Position &pos, bool adjustPlayerPos) @@ -518,6 +520,8 @@ namespace MWWorld // Delay the map update until scripts have been given a chance to run. // If we don't do this, objects that should be disabled will still appear on the map. mNeedMapUpdate = true; + + mRendering.getResourceSystem()->clearCache(); } void Scene::changeToExteriorCell (const ESM::Position& position, bool adjustPlayerPos) diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 0f2906ce5..3e4225d7c 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -37,7 +37,7 @@ add_component_dir (vfs ) add_component_dir (resource - scenemanager texturemanager resourcesystem bulletshapemanager bulletshape + scenemanager texturemanager resourcesystem bulletshapemanager bulletshape niffilemanager ) add_component_dir (sceneutil diff --git a/components/resource/bulletshapemanager.cpp b/components/resource/bulletshapemanager.cpp index 9aae1cad4..593322190 100644 --- a/components/resource/bulletshapemanager.cpp +++ b/components/resource/bulletshapemanager.cpp @@ -12,6 +12,7 @@ #include "bulletshape.hpp" #include "scenemanager.hpp" +#include "niffilemanager.hpp" namespace Resource @@ -94,9 +95,10 @@ private: btTriangleMesh* mTriangleMesh; }; -BulletShapeManager::BulletShapeManager(const VFS::Manager* vfs, SceneManager* sceneMgr) +BulletShapeManager::BulletShapeManager(const VFS::Manager* vfs, SceneManager* sceneMgr, NifFileManager* nifFileManager) : mVFS(vfs) , mSceneManager(sceneMgr) + , mNifFileManager(nifFileManager) { } @@ -115,8 +117,6 @@ osg::ref_ptr BulletShapeManager::createInstance(const std:: Index::iterator it = mIndex.find(normalized); if (it == mIndex.end()) { - Files::IStreamPtr file = mVFS->get(normalized); - size_t extPos = normalized.find_last_of('.'); std::string ext; if (extPos != std::string::npos && extPos+1 < normalized.size()) @@ -126,7 +126,7 @@ osg::ref_ptr BulletShapeManager::createInstance(const std:: { NifBullet::BulletNifLoader loader; // might be worth sharing NIFFiles with SceneManager in some way - shape = loader.load(Nif::NIFFilePtr(new Nif::NIFFile(file, normalized))); + shape = loader.load(mNifFileManager->get(normalized)); } else { diff --git a/components/resource/bulletshapemanager.hpp b/components/resource/bulletshapemanager.hpp index 6b8e64c21..ac1523495 100644 --- a/components/resource/bulletshapemanager.hpp +++ b/components/resource/bulletshapemanager.hpp @@ -16,6 +16,7 @@ namespace VFS namespace Resource { class SceneManager; + class NifFileManager; class BulletShape; class BulletShapeInstance; @@ -23,7 +24,7 @@ namespace Resource class BulletShapeManager { public: - BulletShapeManager(const VFS::Manager* vfs, SceneManager* sceneMgr); + BulletShapeManager(const VFS::Manager* vfs, SceneManager* sceneMgr, NifFileManager* nifFileManager); ~BulletShapeManager(); osg::ref_ptr createInstance(const std::string& name); @@ -31,6 +32,7 @@ namespace Resource private: const VFS::Manager* mVFS; SceneManager* mSceneManager; + NifFileManager* mNifFileManager; typedef std::map > Index; Index mIndex; diff --git a/components/resource/niffilemanager.cpp b/components/resource/niffilemanager.cpp new file mode 100644 index 000000000..9e426bf60 --- /dev/null +++ b/components/resource/niffilemanager.cpp @@ -0,0 +1,64 @@ +#include "niffilemanager.hpp" + +#include +#include + +#include + +namespace Resource +{ + + class NifFileHolder : public osg::Object + { + public: + NifFileHolder(const Nif::NIFFilePtr& file) + : mNifFile(file) + { + } + NifFileHolder(const NifFileHolder& copy, const osg::CopyOp& copyop) + : mNifFile(copy.mNifFile) + { + } + + NifFileHolder() + { + } + + META_Object(Resource, NifFileHolder) + + Nif::NIFFilePtr mNifFile; + }; + + NifFileManager::NifFileManager(const VFS::Manager *vfs) + : mVFS(vfs) + { + mCache = new osgDB::ObjectCache; + } + + NifFileManager::~NifFileManager() + { + + } + + void NifFileManager::clearCache() + { + // NIF files aren't needed any more when the converted objects are cached in SceneManager / BulletShapeManager, + // so we'll simply drop all nif files here, unlikely to need them again + mCache->clear(); + } + + Nif::NIFFilePtr NifFileManager::get(const std::string &name) + { + osg::ref_ptr obj = mCache->getRefFromObjectCache(name); + if (obj) + return static_cast(obj.get())->mNifFile; + else + { + Nif::NIFFilePtr file (new Nif::NIFFile(mVFS->get(name), name)); + obj = new NifFileHolder(file); + mCache->addEntryToObjectCache(name, obj); + return file; + } + } + +} diff --git a/components/resource/niffilemanager.hpp b/components/resource/niffilemanager.hpp new file mode 100644 index 000000000..90ad9fc29 --- /dev/null +++ b/components/resource/niffilemanager.hpp @@ -0,0 +1,45 @@ +#ifndef OPENMW_COMPONENTS_RESOURCE_NIFFILEMANAGER_H +#define OPENMW_COMPONENTS_RESOURCE_NIFFILEMANAGER_H + +#include + +#include + +namespace VFS +{ + class Manager; +} + +namespace osgDB +{ + class ObjectCache; +} + +namespace Resource +{ + + /// @brief Handles caching of NIFFiles. + /// @note The NifFileManager is completely thread safe. + class NifFileManager + { + public: + NifFileManager(const VFS::Manager* vfs); + ~NifFileManager(); + + void clearCache(); + + /// Retrieve a NIF file from the cache, or load it from the VFS if not cached yet. + /// @note For performance reasons the NifFileManager does not handle case folding, needs + /// to be done in advance by other managers accessing the NifFileManager. + Nif::NIFFilePtr get(const std::string& name); + + private: + // Use the osgDB::ObjectCache so objects are retrieved in thread safe way + osg::ref_ptr mCache; + + const VFS::Manager* mVFS; + }; + +} + +#endif diff --git a/components/resource/resourcesystem.cpp b/components/resource/resourcesystem.cpp index bd6824079..2dfd30314 100644 --- a/components/resource/resourcesystem.cpp +++ b/components/resource/resourcesystem.cpp @@ -2,6 +2,7 @@ #include "scenemanager.hpp" #include "texturemanager.hpp" +#include "niffilemanager.hpp" namespace Resource { @@ -9,8 +10,9 @@ namespace Resource ResourceSystem::ResourceSystem(const VFS::Manager *vfs) : mVFS(vfs) { + mNifFileManager.reset(new NifFileManager(vfs)); mTextureManager.reset(new TextureManager(vfs)); - mSceneManager.reset(new SceneManager(vfs, mTextureManager.get())); + mSceneManager.reset(new SceneManager(vfs, mTextureManager.get(), mNifFileManager.get())); } ResourceSystem::~ResourceSystem() @@ -28,6 +30,16 @@ namespace Resource return mTextureManager.get(); } + NifFileManager *ResourceSystem::getNifFileManager() + { + return mNifFileManager.get(); + } + + void ResourceSystem::clearCache() + { + mNifFileManager->clearCache(); + } + const VFS::Manager* ResourceSystem::getVFS() const { return mVFS; diff --git a/components/resource/resourcesystem.hpp b/components/resource/resourcesystem.hpp index 7c00a11ee..7f90bff27 100644 --- a/components/resource/resourcesystem.hpp +++ b/components/resource/resourcesystem.hpp @@ -13,8 +13,9 @@ namespace Resource class SceneManager; class TextureManager; + class NifFileManager; - /// @brief Wrapper class that constructs and provides access to the various resource subsystems. + /// @brief Wrapper class that constructs and provides access to the most commonly used resource subsystems. /// @par Resource subsystems can be used with multiple OpenGL contexts, just like the OSG equivalents, but /// are built around the use of a single virtual file system. class ResourceSystem @@ -25,12 +26,17 @@ namespace Resource SceneManager* getSceneManager(); TextureManager* getTextureManager(); + NifFileManager* getNifFileManager(); + + /// Indicates to each resource manager to clear the cache, i.e. to drop cached objects that are no longer referenced. + void clearCache(); const VFS::Manager* getVFS() const; private: std::auto_ptr mSceneManager; std::auto_ptr mTextureManager; + std::auto_ptr mNifFileManager; const VFS::Manager* mVFS; diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index b2ba5c4cf..3ee7a8c00 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -21,6 +21,7 @@ #include #include "texturemanager.hpp" +#include "niffilemanager.hpp" namespace { @@ -104,9 +105,10 @@ namespace namespace Resource { - SceneManager::SceneManager(const VFS::Manager *vfs, Resource::TextureManager* textureManager) + SceneManager::SceneManager(const VFS::Manager *vfs, Resource::TextureManager* textureManager, Resource::NifFileManager* nifFileManager) : mVFS(vfs) , mTextureManager(textureManager) + , mNifFileManager(nifFileManager) , mParticleSystemMask(~0u) { } @@ -150,11 +152,11 @@ namespace Resource return std::string(); } - osg::ref_ptr load (Files::IStreamPtr file, const std::string& normalizedFilename, Resource::TextureManager* textureMgr) + osg::ref_ptr load (Files::IStreamPtr file, const std::string& normalizedFilename, Resource::TextureManager* textureMgr, Resource::NifFileManager* nifFileManager) { std::string ext = getFileExtension(normalizedFilename); if (ext == "nif") - return NifOsg::Loader::load(Nif::NIFFilePtr(new Nif::NIFFile(file, normalizedFilename)), textureMgr); + return NifOsg::Loader::load(nifFileManager->get(normalizedFilename), textureMgr); else { osgDB::ReaderWriter* reader = osgDB::Registry::instance()->getReaderWriterForExtension(ext); @@ -195,14 +197,14 @@ namespace Resource { Files::IStreamPtr file = mVFS->get(normalized); - loaded = load(file, normalized, mTextureManager); + loaded = load(file, normalized, mTextureManager, mNifFileManager); } catch (std::exception& e) { std::cerr << "Failed to load '" << name << "': " << e.what() << ", using marker_error.nif instead" << std::endl; Files::IStreamPtr file = mVFS->get("meshes/marker_error.nif"); normalized = "meshes/marker_error.nif"; - loaded = load(file, normalized, mTextureManager); + loaded = load(file, normalized, mTextureManager, mNifFileManager); } osgDB::Registry::instance()->getOrCreateSharedStateManager()->share(loaded.get()); diff --git a/components/resource/scenemanager.hpp b/components/resource/scenemanager.hpp index 5ecb875ac..3c1984fd9 100644 --- a/components/resource/scenemanager.hpp +++ b/components/resource/scenemanager.hpp @@ -10,6 +10,7 @@ namespace Resource { class TextureManager; + class NifFileManager; } namespace VFS @@ -34,7 +35,7 @@ namespace Resource class SceneManager { public: - SceneManager(const VFS::Manager* vfs, Resource::TextureManager* textureManager); + SceneManager(const VFS::Manager* vfs, Resource::TextureManager* textureManager, Resource::NifFileManager* nifFileManager); ~SceneManager(); /// Get a read-only copy of this scene "template" @@ -66,7 +67,7 @@ namespace Resource /// Set up an IncrementalCompileOperation for background compiling of loaded scenes. void setIncrementalCompileOperation(osgUtil::IncrementalCompileOperation* ico); - /// @note If you used SceneManager::attachTo, this was called automatically. + /// @note SceneManager::attachTo calls this method automatically, only needs to be called by users if manually attaching void notifyAttached(osg::Node* node) const; const VFS::Manager* getVFS() const; @@ -79,6 +80,7 @@ namespace Resource private: const VFS::Manager* mVFS; Resource::TextureManager* mTextureManager; + Resource::NifFileManager* mNifFileManager; osg::ref_ptr mIncrementalCompileOperation; From 6cf2c352351e4ea9071cdfd99e39ccdf794e9eae Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 2 Dec 2015 13:57:42 +0100 Subject: [PATCH 2650/3725] Don't rely on the _particles vector implementation details This will allow compiling OpenMW with an osgParticle optimization to be pushed to OpenMW/osg. --- components/nifosg/particle.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/nifosg/particle.cpp b/components/nifosg/particle.cpp index 08b62901b..e3162bcd9 100644 --- a/components/nifosg/particle.cpp +++ b/components/nifosg/particle.cpp @@ -23,7 +23,7 @@ ParticleSystem::ParticleSystem(const ParticleSystem ©, const osg::CopyOp &co { // For some reason the osgParticle constructor doesn't copy the particles for (int i=0;i Date: Wed, 2 Dec 2015 14:24:48 +0100 Subject: [PATCH 2651/3725] Eliminate a dynamic_cast in ParticleSystemController --- components/nifosg/controller.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index b8a38cf0f..28f61e4b6 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -435,10 +435,9 @@ void ParticleSystemController::operator() (osg::Node* node, osg::NodeVisitor* nv { if (hasInput()) { - osgParticle::ParticleProcessor* emitter = dynamic_cast(node); + osgParticle::ParticleProcessor* emitter = static_cast(node); float time = getInputValue(nv); - if (emitter) - emitter->setEnabled(time >= mEmitStart && time < mEmitStop); + emitter->setEnabled(time >= mEmitStart && time < mEmitStop); } traverse(node, nv); } From d3fa8a8602de45f06a995302e426e03dfaa61580 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 2 Dec 2015 15:14:39 +0100 Subject: [PATCH 2652/3725] Add osgDB::ObjectCache to the repository to work around it not being available in OSG 3.2 --- components/CMakeLists.txt | 2 +- components/resource/niffilemanager.cpp | 3 +- components/resource/objectcache.cpp | 141 +++++++++++++++++++++++++ components/resource/objectcache.hpp | 92 ++++++++++++++++ 4 files changed, 236 insertions(+), 2 deletions(-) create mode 100644 components/resource/objectcache.cpp create mode 100644 components/resource/objectcache.hpp diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 3e4225d7c..a6e9d8f13 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -37,7 +37,7 @@ add_component_dir (vfs ) add_component_dir (resource - scenemanager texturemanager resourcesystem bulletshapemanager bulletshape niffilemanager + scenemanager texturemanager resourcesystem bulletshapemanager bulletshape niffilemanager objectcache ) add_component_dir (sceneutil diff --git a/components/resource/niffilemanager.cpp b/components/resource/niffilemanager.cpp index 9e426bf60..fd25c1c40 100644 --- a/components/resource/niffilemanager.cpp +++ b/components/resource/niffilemanager.cpp @@ -1,8 +1,9 @@ #include "niffilemanager.hpp" -#include #include +#include "objectcache.hpp" + #include namespace Resource diff --git a/components/resource/objectcache.cpp b/components/resource/objectcache.cpp new file mode 100644 index 000000000..c369e5c24 --- /dev/null +++ b/components/resource/objectcache.cpp @@ -0,0 +1,141 @@ +/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * OpenSceneGraph Public License for more details. +*/ + +#include "objectcache.hpp" + +#if OSG_VERSION_LESS_THAN(3,4,0) + +#include + +using namespace osgDB; + +//////////////////////////////////////////////////////////////////////////////////////////// +// +// ObjectCache +// +ObjectCache::ObjectCache(): + osg::Referenced(true) +{ +// OSG_NOTICE<<"Constructed ObjectCache"< lock1(_objectCacheMutex); + OpenThreads::ScopedLock lock2(objectCache->_objectCacheMutex); + + // OSG_NOTICE<<"Inserting objects to main ObjectCache "<_objectCache.size()<_objectCache.begin(), objectCache->_objectCache.end()); +} + + +void ObjectCache::addEntryToObjectCache(const std::string& filename, osg::Object* object, double timestamp) +{ + OpenThreads::ScopedLock lock(_objectCacheMutex); + _objectCache[filename]=ObjectTimeStampPair(object,timestamp); +} + +osg::Object* ObjectCache::getFromObjectCache(const std::string& fileName) +{ + OpenThreads::ScopedLock lock(_objectCacheMutex); + ObjectCacheMap::iterator itr = _objectCache.find(fileName); + if (itr!=_objectCache.end()) return itr->second.first.get(); + else return 0; +} + +osg::ref_ptr ObjectCache::getRefFromObjectCache(const std::string& fileName) +{ + OpenThreads::ScopedLock lock(_objectCacheMutex); + ObjectCacheMap::iterator itr = _objectCache.find(fileName); + if (itr!=_objectCache.end()) + { + // OSG_NOTICE<<"Found "<second.first; + } + else return 0; +} + +void ObjectCache::updateTimeStampOfObjectsInCacheWithExternalReferences(double referenceTime) +{ + OpenThreads::ScopedLock lock(_objectCacheMutex); + + // look for objects with external references and update their time stamp. + for(ObjectCacheMap::iterator itr=_objectCache.begin(); + itr!=_objectCache.end(); + ++itr) + { + // if ref count is greater the 1 the object has an external reference. + if (itr->second.first->referenceCount()>1) + { + // so update it time stamp. + itr->second.second = referenceTime; + } + } +} + +void ObjectCache::removeExpiredObjectsInCache(double expiryTime) +{ + OpenThreads::ScopedLock lock(_objectCacheMutex); + + // Remove expired entries from object cache + ObjectCacheMap::iterator oitr = _objectCache.begin(); + while(oitr != _objectCache.end()) + { + if (oitr->second.second<=expiryTime) + { + _objectCache.erase(oitr++); + } + else + { + ++oitr; + } + } +} + +void ObjectCache::removeFromObjectCache(const std::string& fileName) +{ + OpenThreads::ScopedLock lock(_objectCacheMutex); + ObjectCacheMap::iterator itr = _objectCache.find(fileName); + if (itr!=_objectCache.end()) _objectCache.erase(itr); +} + +void ObjectCache::clear() +{ + OpenThreads::ScopedLock lock(_objectCacheMutex); + _objectCache.clear(); +} + +void ObjectCache::releaseGLObjects(osg::State* state) +{ + OpenThreads::ScopedLock lock(_objectCacheMutex); + + for(ObjectCacheMap::iterator itr = _objectCache.begin(); + itr != _objectCache.end(); + ++itr) + { + osg::Object* object = itr->second.first.get(); + object->releaseGLObjects(state); + } +} + +#endif diff --git a/components/resource/objectcache.hpp b/components/resource/objectcache.hpp new file mode 100644 index 000000000..0a342f27f --- /dev/null +++ b/components/resource/objectcache.hpp @@ -0,0 +1,92 @@ +/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * OpenSceneGraph Public License for more details. +*/ + +// Wrapper for osgDB/ObjectCache. Works around ObjectCache not being available in old OSG 3.2. +// Use "#include objectcache.hpp" in place of "#include + +#if OSG_VERSION_GREATER_OR_EQUAL(3,4,0) +#include +#else + +#include + +#include +#include + +#include + +namespace osgDB { + +class /*OSGDB_EXPORT*/ ObjectCache : public osg::Referenced +{ + public: + + ObjectCache(); + + /** For each object in the cache which has an reference count greater than 1 + * (and therefore referenced by elsewhere in the application) set the time stamp + * for that object in the cache to specified time. + * This would typically be called once per frame by applications which are doing database paging, + * and need to prune objects that are no longer required. + * The time used should be taken from the FrameStamp::getReferenceTime().*/ + void updateTimeStampOfObjectsInCacheWithExternalReferences(double referenceTime); + + /** Removed object in the cache which have a time stamp at or before the specified expiry time. + * This would typically be called once per frame by applications which are doing database paging, + * and need to prune objects that are no longer required, and called after the a called + * after the call to updateTimeStampOfObjectsInCacheWithExternalReferences(expirtyTime).*/ + void removeExpiredObjectsInCache(double expiryTime); + + /** Remove all objects in the cache regardless of having external references or expiry times.*/ + void clear(); + + /** Add contents of specified ObjectCache to this object cache.*/ + void addObjectCache(ObjectCache* object); + + /** Add a filename,object,timestamp triple to the Registry::ObjectCache.*/ + void addEntryToObjectCache(const std::string& filename, osg::Object* object, double timestamp = 0.0); + + /** Remove Object from cache.*/ + void removeFromObjectCache(const std::string& fileName); + + /** Get an Object from the object cache*/ + osg::Object* getFromObjectCache(const std::string& fileName); + + /** Get an ref_ptr from the object cache*/ + osg::ref_ptr getRefFromObjectCache(const std::string& fileName); + + /** call rleaseGLObjects on all objects attached to the object cache.*/ + void releaseGLObjects(osg::State* state); + + protected: + + virtual ~ObjectCache(); + + typedef std::pair, double > ObjectTimeStampPair; + typedef std::map ObjectCacheMap; + + ObjectCacheMap _objectCache; + OpenThreads::Mutex _objectCacheMutex; + +}; + +} + +#endif + +#endif From 87e44bf627e726dd3ea6c5a834de25ae4c8b31b0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 2 Dec 2015 15:21:13 +0100 Subject: [PATCH 2653/3725] Small fix --- components/resource/objectcache.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/resource/objectcache.cpp b/components/resource/objectcache.cpp index c369e5c24..8c2c52416 100644 --- a/components/resource/objectcache.cpp +++ b/components/resource/objectcache.cpp @@ -11,11 +11,11 @@ * OpenSceneGraph Public License for more details. */ -#include "objectcache.hpp" +#include #if OSG_VERSION_LESS_THAN(3,4,0) -#include +#include "objectcache.hpp" using namespace osgDB; From 7d6fa1b65a828f700170fbaa4f25af090f4cd3bc Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 2 Dec 2015 16:14:04 +0100 Subject: [PATCH 2654/3725] CMakeLists.txt: Don't use DATADIR before it's defined --- CMakeLists.txt | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5106db666..498b43961 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -83,18 +83,6 @@ if (MSVC) option(OPENMW_LTO_BUILD "Build OpenMW with Link-Time Optimization (Needs ~2GB of RAM)" OFF) endif() -# Location of morrowind data files -if (APPLE) - set(MORROWIND_DATA_FILES "./data" CACHE PATH "location of Morrowind data files") - set(OPENMW_RESOURCE_FILES "./resources" CACHE PATH "location of OpenMW resources files") -elseif(UNIX) - set(MORROWIND_DATA_FILES "${DATADIR}/data" CACHE PATH "location of Morrowind data files") - set(OPENMW_RESOURCE_FILES "${DATADIR}/resources" CACHE PATH "location of OpenMW resources files") -else() - set(MORROWIND_DATA_FILES "data" CACHE PATH "location of Morrowind data files") - set(OPENMW_RESOURCE_FILES "resources" CACHE PATH "location of OpenMW resources files") -endif(APPLE) - if (WIN32) option(USE_DEBUG_CONSOLE "whether a debug console should be enabled for debug builds, if false debug output is redirected to Visual Studio output" ON) endif() @@ -436,6 +424,18 @@ IF(NOT WIN32 AND NOT APPLE) INSTALL(DIRECTORY DESTINATION "${DATADIR}/data" COMPONENT "Resources") ENDIF(NOT WIN32 AND NOT APPLE) +# Location of morrowind data files +if (APPLE) + set(MORROWIND_DATA_FILES "./data" CACHE PATH "location of Morrowind data files") + set(OPENMW_RESOURCE_FILES "./resources" CACHE PATH "location of OpenMW resources files") +elseif(UNIX) + set(MORROWIND_DATA_FILES "${DATADIR}/data" CACHE PATH "location of Morrowind data files") + set(OPENMW_RESOURCE_FILES "${DATADIR}/resources" CACHE PATH "location of OpenMW resources files") +else() + set(MORROWIND_DATA_FILES "data" CACHE PATH "location of Morrowind data files") + set(OPENMW_RESOURCE_FILES "resources" CACHE PATH "location of OpenMW resources files") +endif(APPLE) + if(WIN32) FILE(GLOB dll_files "${OpenMW_BINARY_DIR}/Release/*.dll") INSTALL(FILES ${dll_files} DESTINATION ".") From 77965501d4011aece811b3efecdfd89a3af260c3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 2 Dec 2015 17:33:55 +0100 Subject: [PATCH 2655/3725] CMakeLists.txt: set the OPENMW_RESOURCE_FILES before configuring openmw.cfg --- CMakeLists.txt | 55 +++++++++++++++++++++++++------------------------- 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 498b43961..f403b99e0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -83,6 +83,33 @@ if (MSVC) option(OPENMW_LTO_BUILD "Build OpenMW with Link-Time Optimization (Needs ~2GB of RAM)" OFF) endif() +# Set up common paths +if (APPLE) + set(MORROWIND_DATA_FILES "./data" CACHE PATH "location of Morrowind data files") + set(OPENMW_RESOURCE_FILES "./resources" CACHE PATH "location of OpenMW resources files") +elseif(UNIX) + # Paths + SET(BINDIR "${CMAKE_INSTALL_PREFIX}/bin" CACHE PATH "Where to install binaries") + SET(LIBDIR "${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}" CACHE PATH "Where to install libraries") + SET(DATAROOTDIR "${CMAKE_INSTALL_PREFIX}/share" CACHE PATH "Sets the root of data directories to a non-default location") + SET(GLOBAL_DATA_PATH "${DATAROOTDIR}/games/" CACHE PATH "Set data path prefix") + SET(DATADIR "${GLOBAL_DATA_PATH}/openmw" CACHE PATH "Sets the openmw data directories to a non-default location") + SET(ICONDIR "${DATAROOTDIR}/pixmaps" CACHE PATH "Set icon dir") + SET(LICDIR "${DATAROOTDIR}/licenses/openmw" CACHE PATH "Sets the openmw license directory to a non-default location.") + IF("${CMAKE_INSTALL_PREFIX}" STREQUAL "/usr") + SET(GLOBAL_CONFIG_PATH "/etc/" CACHE PATH "Set config dir prefix") + ELSE() + SET(GLOBAL_CONFIG_PATH "${CMAKE_INSTALL_PREFIX}/etc/" CACHE PATH "Set config dir prefix") + ENDIF() + SET(SYSCONFDIR "${GLOBAL_CONFIG_PATH}/openmw" CACHE PATH "Set config dir") + + set(MORROWIND_DATA_FILES "${DATADIR}/data" CACHE PATH "location of Morrowind data files") + set(OPENMW_RESOURCE_FILES "${DATADIR}/resources" CACHE PATH "location of OpenMW resources files") +else() + set(MORROWIND_DATA_FILES "data" CACHE PATH "location of Morrowind data files") + set(OPENMW_RESOURCE_FILES "resources" CACHE PATH "location of OpenMW resources files") +endif(APPLE) + if (WIN32) option(USE_DEBUG_CONSOLE "whether a debug console should be enabled for debug builds, if false debug output is redirected to Visual Studio output" ON) endif() @@ -349,21 +376,7 @@ elseif (MSVC) endif (CMAKE_CXX_COMPILER_ID STREQUAL GNU OR CMAKE_CXX_COMPILER_ID STREQUAL Clang) IF(NOT WIN32 AND NOT APPLE) - # Linux building - # Paths - SET(BINDIR "${CMAKE_INSTALL_PREFIX}/bin" CACHE PATH "Where to install binaries") - SET(LIBDIR "${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}" CACHE PATH "Where to install libraries") - SET(DATAROOTDIR "${CMAKE_INSTALL_PREFIX}/share" CACHE PATH "Sets the root of data directories to a non-default location") - SET(GLOBAL_DATA_PATH "${DATAROOTDIR}/games/" CACHE PATH "Set data path prefix") - SET(DATADIR "${GLOBAL_DATA_PATH}/openmw" CACHE PATH "Sets the openmw data directories to a non-default location") - SET(ICONDIR "${DATAROOTDIR}/pixmaps" CACHE PATH "Set icon dir") - SET(LICDIR "${DATAROOTDIR}/licenses/openmw" CACHE PATH "Sets the openmw license directory to a non-default location.") - IF("${CMAKE_INSTALL_PREFIX}" STREQUAL "/usr") - SET(GLOBAL_CONFIG_PATH "/etc/" CACHE PATH "Set config dir prefix") - ELSE() - SET(GLOBAL_CONFIG_PATH "${CMAKE_INSTALL_PREFIX}/etc/" CACHE PATH "Set config dir prefix") - ENDIF() - SET(SYSCONFDIR "${GLOBAL_CONFIG_PATH}/openmw" CACHE PATH "Set config dir") + # Linux installation # Install binaries IF(BUILD_OPENMW) @@ -424,18 +437,6 @@ IF(NOT WIN32 AND NOT APPLE) INSTALL(DIRECTORY DESTINATION "${DATADIR}/data" COMPONENT "Resources") ENDIF(NOT WIN32 AND NOT APPLE) -# Location of morrowind data files -if (APPLE) - set(MORROWIND_DATA_FILES "./data" CACHE PATH "location of Morrowind data files") - set(OPENMW_RESOURCE_FILES "./resources" CACHE PATH "location of OpenMW resources files") -elseif(UNIX) - set(MORROWIND_DATA_FILES "${DATADIR}/data" CACHE PATH "location of Morrowind data files") - set(OPENMW_RESOURCE_FILES "${DATADIR}/resources" CACHE PATH "location of OpenMW resources files") -else() - set(MORROWIND_DATA_FILES "data" CACHE PATH "location of Morrowind data files") - set(OPENMW_RESOURCE_FILES "resources" CACHE PATH "location of OpenMW resources files") -endif(APPLE) - if(WIN32) FILE(GLOB dll_files "${OpenMW_BINARY_DIR}/Release/*.dll") INSTALL(FILES ${dll_files} DESTINATION ".") From 647bed7f40c06d2e805952ebf55c69606a3e2a62 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 2 Dec 2015 19:21:10 +0100 Subject: [PATCH 2656/3725] Do not read openmw.cfg from global path if one was found in the local path --- components/files/configurationmanager.cpp | 15 +++++++++++---- components/files/configurationmanager.hpp | 2 +- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/components/files/configurationmanager.cpp b/components/files/configurationmanager.cpp index dc6f02b60..9c9cebe96 100644 --- a/components/files/configurationmanager.cpp +++ b/components/files/configurationmanager.cpp @@ -60,10 +60,14 @@ void ConfigurationManager::readConfiguration(boost::program_options::variables_m loadConfig(mFixedPath.getUserConfigPath(), variables, description); boost::program_options::notify(variables); - loadConfig(mFixedPath.getLocalPath(), variables, description); - boost::program_options::notify(variables); - loadConfig(mFixedPath.getGlobalConfigPath(), variables, description); + // read either local or global config depending on type of installation + bool loaded = loadConfig(mFixedPath.getLocalPath(), variables, description); boost::program_options::notify(variables); + if (!loaded) + { + loadConfig(mFixedPath.getGlobalConfigPath(), variables, description); + boost::program_options::notify(variables); + } mSilent = silent; } @@ -126,7 +130,7 @@ void ConfigurationManager::processPaths(Files::PathContainer& dataDirs, bool cre boost::bind(&boost::filesystem::path::empty, _1)), dataDirs.end()); } -void ConfigurationManager::loadConfig(const boost::filesystem::path& path, +bool ConfigurationManager::loadConfig(const boost::filesystem::path& path, boost::program_options::variables_map& variables, boost::program_options::options_description& description) { @@ -145,13 +149,16 @@ void ConfigurationManager::loadConfig(const boost::filesystem::path& path, if (!mSilent) std::cout << "done." << std::endl; + return true; } else { if (!mSilent) std::cout << "failed." << std::endl; + return false; } } + return false; } const boost::filesystem::path& ConfigurationManager::getGlobalPath() const diff --git a/components/files/configurationmanager.hpp b/components/files/configurationmanager.hpp index 102f7c3cb..58ee5c1ae 100644 --- a/components/files/configurationmanager.hpp +++ b/components/files/configurationmanager.hpp @@ -58,7 +58,7 @@ struct ConfigurationManager typedef std::tr1::unordered_map TokensMappingContainer; #endif - void loadConfig(const boost::filesystem::path& path, + bool loadConfig(const boost::filesystem::path& path, boost::program_options::variables_map& variables, boost::program_options::options_description& description); From bd5057aa3cf7f15c3cab799f13311922389f45c5 Mon Sep 17 00:00:00 2001 From: sandstranger Date: Wed, 2 Dec 2015 22:40:04 +0300 Subject: [PATCH 2657/3725] enable opengl es1 --- CMakeLists.txt | 42 ++++++-- apps/openmw/CMakeLists.txt | 35 ++++++- apps/openmw/android_main.c | 1 - apps/openmw/main.cpp | 2 +- cmake/FindOpenGLES.cmake | 94 +++++++++++++++++ components/CMakeLists.txt | 128 ++++++++++++++--------- components/sdlutil/sdlcursormanager.cpp | 7 ++ components/sdlutil/sdlgraphicswindow.cpp | 8 +- 8 files changed, 252 insertions(+), 65 deletions(-) create mode 100644 cmake/FindOpenGLES.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index f403b99e0..61a44b758 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -159,20 +159,36 @@ if (WIN32) add_definitions(-DNOMINMAX -DWIN32_LEAN_AND_MEAN) endif() -# Dependencies +if (ANDROID) + set(CMAKE_FIND_ROOT_PATH ${OPENMW_DEPENDENCIES_DIR} "${CMAKE_FIND_ROOT_PATH}") + set(OSG_PLUGINS_DIR ${OSG_PLUGINS_DIR}) + add_definitions (-DOSG_PLUGINS_DIR) + set(OPENGL_ES TRUE CACHE BOOL "enable opengl es support for android" FORCE) +endif (ANDROID) -set(DESIRED_QT_VERSION 4 CACHE STRING "The QT version OpenMW should use (4 or 5)") -message(STATUS "Using Qt${DESIRED_QT_VERSION}") +option(OPENGL_ES "enable opengl es support" FALSE ) -if (DESIRED_QT_VERSION MATCHES 4) - find_package(Qt4 REQUIRED COMPONENTS QtCore QtGui QtNetwork QtOpenGL) -else() - find_package(Qt5Widgets REQUIRED) - find_package(Qt5Core REQUIRED) - find_package(Qt5Network REQUIRED) - find_package(Qt5OpenGL REQUIRED) +if (OPENGL_ES) + INCLUDE(cmake/FindOpenGLES.cmake) + add_definitions (-DOPENGL_ES) + INCLUDE_DIRECTORIES(${OPENGLES_INCLUDE_DIR}) +endif (OPENGLES) + +# Dependencies +if (NOT ANDROID) + set(DESIRED_QT_VERSION 4 CACHE STRING "The QT version OpenMW should use (4 or 5)") + message(STATUS "Using Qt${DESIRED_QT_VERSION}") + + if (DESIRED_QT_VERSION MATCHES 4) + find_package(Qt4 REQUIRED COMPONENTS QtCore QtGui QtNetwork QtOpenGL) + else() + find_package(Qt5Widgets REQUIRED) + find_package(Qt5Core REQUIRED) + find_package(Qt5Network REQUIRED) + find_package(Qt5OpenGL REQUIRED) # Instruct CMake to run moc automatically when needed. #set(CMAKE_AUTOMOC ON) + endif() endif() # Fix for not visible pthreads functions for linker with glibc 2.15 @@ -204,7 +220,11 @@ IF(BOOST_STATIC) set(Boost_USE_STATIC_LIBS ON) endif() -find_package(OpenSceneGraph 3.2.0 REQUIRED osgDB osgViewer osgText osgGA osgAnimation osgParticle osgQt osgUtil osgFX) +if (NOT ANDROID) + find_package(OpenSceneGraph 3.2.0 REQUIRED osgDB osgViewer osgText osgGA osgAnimation osgParticle osgQt osgUtil osgFX) +else() + find_package(OpenSceneGraph 3.2.0 REQUIRED osgDB osgViewer osgText osgGA osgAnimation osgParticle osgUtil osgFX) +endif() include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS}) if(OSG_STATIC) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index e2d333e56..5883d9a26 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -140,18 +140,51 @@ target_link_libraries(openmw ) if (ANDROID) + set (OSG_PLUGINS + -Wl,--whole-archive + ${OSG_PLUGINS_DIR}/libosgdb_dds.a + ${OSG_PLUGINS_DIR}/libosgdb_bmp.a + ${OSG_PLUGINS_DIR}/libosgdb_tga.a + ${OSG_PLUGINS_DIR}/libosgdb_gif.a + ${OSG_PLUGINS_DIR}/libosgdb_jpeg.a + ${OSG_PLUGINS_DIR}/libosgdb_png.a + -Wl,--no-whole-archive + ) target_link_libraries(openmw EGL android log dl MyGUIEngineStatic - cpufeatures BulletCollision LinearMath + z + osg + osgDB + osgAnimation + osgText + osgUtil + osgShadow + ${OPENSCENEGRAPH_LIBRARIES} + ${OSG_PLUGINS} + ${Boost_SYSTEM_LIBRARY} + ${Boost_THREAD_LIBRARY} + ${Boost_FILESYSTEM_LIBRARY} + ${Boost_PROGRAM_OPTIONS_LIBRARY} + jpeg + gif + png ) endif (ANDROID) + +if (OPENGL_ES) + target_link_libraries(openmw + ${OPENGLES_gl_LIBRARY} + ${OPENGLES2_gl_LIBRARY} + ) +endif (OPENGL_ES) + if (USE_SYSTEM_TINYXML) target_link_libraries(openmw ${TINYXML_LIBRARIES}) endif() diff --git a/apps/openmw/android_main.c b/apps/openmw/android_main.c index 47b77a8b3..8cd69e8f0 100644 --- a/apps/openmw/android_main.c +++ b/apps/openmw/android_main.c @@ -1,4 +1,3 @@ -#include "../../SDL_internal.h" #ifdef __ANDROID__ #include "SDL_main.h" diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 17ef46246..c3f0f8688 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -23,7 +23,7 @@ #endif -#if (defined(__APPLE__) || defined(__linux) || defined(__unix) || defined(__posix)) +#if (defined(__APPLE__) || (defined(__linux) && !defined(ANDROID)) || (defined(__unix) && !defined(ANDROID)) || defined(__posix)) #define USE_CRASH_CATCHER 1 #else #define USE_CRASH_CATCHER 0 diff --git a/cmake/FindOpenGLES.cmake b/cmake/FindOpenGLES.cmake new file mode 100644 index 000000000..7ee2c07f1 --- /dev/null +++ b/cmake/FindOpenGLES.cmake @@ -0,0 +1,94 @@ +#------------------------------------------------------------------- +# This file is part of the CMake build system for OGRE +# (Object-oriented Graphics Rendering Engine) +# For the latest info, see http://www.ogre3d.org/ +# +# The contents of this file are placed in the public domain. Feel +# free to make use of it in any way you like. +#------------------------------------------------------------------- + +# - Try to find OpenGLES +# Once done this will define +# +# OPENGLES_FOUND - system has OpenGLES +# OPENGLES_INCLUDE_DIR - the GL include directory +# OPENGLES_LIBRARIES - Link these to use OpenGLES + +IF (WIN32) + IF (CYGWIN) + + FIND_PATH(OPENGLES_INCLUDE_DIR GLES/gl.h ) + + FIND_LIBRARY(OPENGLES_gl_LIBRARY libgles_cm ) + + ELSE (CYGWIN) + + IF(BORLAND) + SET (OPENGLES_gl_LIBRARY import32 CACHE STRING "OpenGL ES 1.x library for win32") + ELSE(BORLAND) + #MS compiler - todo - fix the following line: + SET (OPENGLES_gl_LIBRARY ${OGRE_SOURCE_DIR}/Dependencies/lib/release/libgles_cm.lib CACHE STRING "OpenGL ES 1.x library for win32") + ENDIF(BORLAND) + + ENDIF (CYGWIN) + +ELSE (WIN32) + + IF (APPLE) + + #create_search_paths(/Developer/Platforms) + #findpkg_framework(OpenGLES) + #set(OPENGLES_gl_LIBRARY "-framework OpenGLES") + + ELSE(APPLE) + + FIND_PATH(OPENGLES_INCLUDE_DIR GLES/gl.h + /opt/vc/include + /opt/graphics/OpenGL/include + /usr/openwin/share/include + /usr/X11R6/include + /usr/include + ) + + FIND_LIBRARY(OPENGLES_gl_LIBRARY + NAMES GLES_CM GLESv1_CM + PATHS /opt/vc/lib + /opt/graphics/OpenGL/lib + /usr/openwin/lib + /usr/shlib /usr/X11R6/lib + /usr/lib + ) + + # On Unix OpenGL most certainly always requires X11. + # Feel free to tighten up these conditions if you don't + # think this is always true. + + #IF (OPENGLES_gl_LIBRARY) + # IF(NOT X11_FOUND) + # INCLUDE(FindX11) + # ENDIF(NOT X11_FOUND) + # IF (X11_FOUND) + # SET (OPENGLES_LIBRARIES ${X11_LIBRARIES}) + # ENDIF (X11_FOUND) + #ENDIF (OPENGLES_gl_LIBRARY) + + ENDIF(APPLE) +ENDIF (WIN32) + +SET( OPENGLES_FOUND "NO" ) +IF(OPENGLES_gl_LIBRARY) + + SET( OPENGLES_LIBRARIES ${OPENGLES_gl_LIBRARY} ${OPENGLES_LIBRARIES}) + + SET( OPENGLES_FOUND "YES" ) + +ENDIF(OPENGLES_gl_LIBRARY) + +MARK_AS_ADVANCED( + OPENGLES_INCLUDE_DIR + OPENGLES_gl_LIBRARY +) + +INCLUDE(FindPackageHandleStandardArgs) + +FIND_PACKAGE_HANDLE_STANDARD_ARGS(OPENGLES REQUIRED_VARS OPENGLES_LIBRARIES OPENGLES_INCLUDE_DIR) diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index a6e9d8f13..92e11c51c 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -20,7 +20,9 @@ else (GIT_CHECKOUT) configure_file(${VERSION_IN_FILE} ${VERSION_FILE}) endif (GIT_CHECKOUT) -find_package(OpenGL REQUIRED) +if (NOT OPENGL_ES) + find_package(OpenGL REQUIRED) +endif() # source files @@ -137,29 +139,31 @@ add_component_dir (version set (ESM_UI ${CMAKE_SOURCE_DIR}/files/ui/contentselector.ui ) -add_component_qt_dir (contentselector - model/modelitem model/esmfile - model/naturalsort model/contentmodel - model/loadordererror - view/combobox view/contentselector - ) -add_component_qt_dir (config - gamesettings - launchersettings - settingsbase - ) - -add_component_qt_dir (process - processinvoker -) - -if (DESIRED_QT_VERSION MATCHES 4) - include(${QT_USE_FILE}) - QT4_WRAP_UI(ESM_UI_HDR ${ESM_UI}) - QT4_WRAP_CPP(MOC_SRCS ${COMPONENT_MOC_FILES}) -else() - QT5_WRAP_UI(ESM_UI_HDR ${ESM_UI}) - QT5_WRAP_CPP(MOC_SRCS ${COMPONENT_MOC_FILES}) +if (NOT ANDROID) + add_component_qt_dir (contentselector + model/modelitem model/esmfile + model/naturalsort model/contentmodel + model/loadordererror + view/combobox view/contentselector + ) + add_component_qt_dir (config + gamesettings + launchersettings + settingsbase + ) + + add_component_qt_dir (process + processinvoker + ) + + if (DESIRED_QT_VERSION MATCHES 4) + include(${QT_USE_FILE}) + QT4_WRAP_UI(ESM_UI_HDR ${ESM_UI}) + QT4_WRAP_CPP(MOC_SRCS ${COMPONENT_MOC_FILES}) + else() + QT5_WRAP_UI(ESM_UI_HDR ${ESM_UI}) + QT5_WRAP_CPP(MOC_SRCS ${COMPONENT_MOC_FILES}) + endif() endif() if (CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") @@ -172,38 +176,62 @@ include_directories(${BULLET_INCLUDE_DIRS} ${CMAKE_CURRENT_BINARY_DIR}) add_library(components STATIC ${COMPONENT_FILES} ${MOC_SRCS} ${ESM_UI_HDR}) -target_link_libraries(components - ${Boost_SYSTEM_LIBRARY} - ${Boost_FILESYSTEM_LIBRARY} - ${Boost_THREAD_LIBRARY} - ${Boost_PROGRAM_OPTIONS_LIBRARY} - ${OSG_LIBRARIES} - ${OPENTHREADS_LIBRARIES} - ${OSGPARTICLE_LIBRARIES} - ${OSGUTIL_LIBRARIES} - ${OSGDB_LIBRARIES} - ${OSGVIEWER_LIBRARIES} - ${OSGGA_LIBRARIES} - ${OSGFX_LIBRARIES} - ${OSGANIMATION_LIBRARIES} - ${BULLET_LIBRARIES} - ${SDL2_LIBRARY} - # For MyGUI platform - ${OPENGL_gl_LIBRARY} - ${MYGUI_LIBRARIES} -) +if (NOT ANDROID) + target_link_libraries(components + ${Boost_SYSTEM_LIBRARY} + ${Boost_FILESYSTEM_LIBRARY} + ${Boost_THREAD_LIBRARY} + ${Boost_PROGRAM_OPTIONS_LIBRARY} + ${OSG_LIBRARIES} + ${OPENTHREADS_LIBRARIES} + ${OSGPARTICLE_LIBRARIES} + ${OSGUTIL_LIBRARIES} + ${OSGDB_LIBRARIES} + ${OSGVIEWER_LIBRARIES} + ${OSGGA_LIBRARIES} + ${OSGFX_LIBRARIES} + ${OSGANIMATION_LIBRARIES} + ${BULLET_LIBRARIES} + ${SDL2_LIBRARY} + # For MyGUI platform + ${OPENGL_gl_LIBRARY} + ${MYGUI_LIBRARIES} + ) +else() + target_link_libraries(components + ${Boost_SYSTEM_LIBRARY} + ${Boost_FILESYSTEM_LIBRARY} + ${Boost_THREAD_LIBRARY} + ${Boost_PROGRAM_OPTIONS_LIBRARY} + ${OSG_LIBRARIES} + ${OPENTHREADS_LIBRARIES} + ${OSGPARTICLE_LIBRARIES} + ${OSGUTIL_LIBRARIES} + ${OSGDB_LIBRARIES} + ${OSGVIEWER_LIBRARIES} + ${OSGGA_LIBRARIES} + ${OSGFX_LIBRARIES} + ${OSGANIMATION_LIBRARIES} + ${BULLET_LIBRARIES} + ${SDL2_LIBRARY} + # For MyGUI platform + ${MYGUI_LIBRARIES} + ) +endif() if (WIN32) target_link_libraries(components ${Boost_LOCALE_LIBRARY}) endif() -if (DESIRED_QT_VERSION MATCHES 4) - target_link_libraries(components - ${QT_QTCORE_LIBRARY} - ${QT_QTGUI_LIBRARY}) -else() - qt5_use_modules(components Widgets Core) +if (NOT ANDROID) + if (DESIRED_QT_VERSION MATCHES 4) + target_link_libraries(components + ${QT_QTCORE_LIBRARY} + ${QT_QTGUI_LIBRARY}) + else() + qt5_use_modules(components Widgets Core) + endif() endif() if (GIT_CHECKOUT) diff --git a/components/sdlutil/sdlcursormanager.cpp b/components/sdlutil/sdlcursormanager.cpp index e1a67aff8..c131621a8 100644 --- a/components/sdlutil/sdlcursormanager.cpp +++ b/components/sdlutil/sdlcursormanager.cpp @@ -217,6 +217,13 @@ namespace SDLUtil void SDLCursorManager::_createCursorFromResource(const std::string& name, int rotDegrees, osg::Image* image, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y) { + #ifdef ANDROID + return; + #endif + + if (mCursorMap.find(name) != mCursorMap.end()) + return; + if (mCursorMap.find(name) != mCursorMap.end()) return; diff --git a/components/sdlutil/sdlgraphicswindow.cpp b/components/sdlutil/sdlgraphicswindow.cpp index 49afe32a8..a0483e84d 100644 --- a/components/sdlutil/sdlgraphicswindow.cpp +++ b/components/sdlutil/sdlgraphicswindow.cpp @@ -92,7 +92,13 @@ void GraphicsWindowSDL2::init() // have to get the current one to be able to restore it afterward. SDL_Window *oldWin = SDL_GL_GetCurrentWindow(); SDL_GLContext oldCtx = SDL_GL_GetCurrentContext(); - + +#ifdef OPENGL_ES + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 1); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1); +#endif + mContext = SDL_GL_CreateContext(mWindow); if(!mContext) { From b0b3192520aef8b5ab5f932282dc42816303a978 Mon Sep 17 00:00:00 2001 From: sandstranger Date: Wed, 2 Dec 2015 22:50:54 +0300 Subject: [PATCH 2658/3725] delete bad symbol --- apps/openmw/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 5883d9a26..4512e004d 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -181,7 +181,6 @@ endif (ANDROID) if (OPENGL_ES) target_link_libraries(openmw ${OPENGLES_gl_LIBRARY} - ${OPENGLES2_gl_LIBRARY} ) endif (OPENGL_ES) From 816015d6e668f57bf2c4fac32d7d74fee8c0e3c4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 30 Nov 2015 05:42:51 -0800 Subject: [PATCH 2659/3725] Avoid inheriting from Sound for sound types --- apps/openmw/mwbase/soundmanager.hpp | 11 + apps/openmw/mwsound/movieaudiofactory.cpp | 4 +- apps/openmw/mwsound/openal_output.cpp | 599 +++++++++------------- apps/openmw/mwsound/openal_output.hpp | 14 +- apps/openmw/mwsound/sound.hpp | 25 +- apps/openmw/mwsound/sound_output.hpp | 7 + apps/openmw/mwsound/soundmanagerimp.cpp | 127 +++-- apps/openmw/mwsound/soundmanagerimp.hpp | 12 +- apps/openmw/mwworld/projectilemanager.cpp | 4 +- apps/openmw/mwworld/weather.cpp | 2 +- 10 files changed, 383 insertions(+), 422 deletions(-) diff --git a/apps/openmw/mwbase/soundmanager.hpp b/apps/openmw/mwbase/soundmanager.hpp index a91149777..e75949a5b 100644 --- a/apps/openmw/mwbase/soundmanager.hpp +++ b/apps/openmw/mwbase/soundmanager.hpp @@ -107,6 +107,14 @@ namespace MWBase virtual SoundPtr playTrack(const MWSound::DecoderPtr& decoder, PlayType type) = 0; ///< Play a 2D audio track, using a custom decoder + virtual void stopTrack(SoundPtr sound) = 0; + ///< Stop the given audio track from playing + + virtual double getTrackTimeDelay(SoundPtr sound) = 0; + ///< Retives the time delay, in seconds, of the audio track (must be a sound + /// returned by \ref playTrack). Only intended to be called by the track + /// decoder's read method. + virtual SoundPtr playSound(const std::string& soundId, float volume, float pitch, PlayType type=Play_TypeSfx, PlayMode mode=Play_Normal, float offset=0) = 0; @@ -123,6 +131,9 @@ namespace MWBase float volume, float pitch, PlayType type=Play_TypeSfx, PlayMode mode=Play_Normal, float offset=0) = 0; ///< Play a 3D sound at \a initialPos. If the sound should be moving, it must be updated using Sound::setPosition. + virtual void stopSound(SoundPtr sound) = 0; + ///< Stop the given sound from playing + virtual void stopSound3D(const MWWorld::Ptr &reference, const std::string& soundId) = 0; ///< Stop the given object from playing the given sound, diff --git a/apps/openmw/mwsound/movieaudiofactory.cpp b/apps/openmw/mwsound/movieaudiofactory.cpp index 925c966da..1f7b8a515 100644 --- a/apps/openmw/mwsound/movieaudiofactory.cpp +++ b/apps/openmw/mwsound/movieaudiofactory.cpp @@ -61,7 +61,7 @@ namespace MWSound virtual double getAudioClock() { return (double)getSampleOffset()/(double)mAVStream->codec->sample_rate - - mAudioTrack->getStreamDelay(); + MWBase::Environment::get().getSoundManager()->getTrackTimeDelay(mAudioTrack); } virtual void adjustAudioSettings(AVSampleFormat& sampleFormat, uint64_t& channelLayout, int& sampleRate) @@ -86,6 +86,8 @@ namespace MWSound public: ~MovieAudioDecoder() { + if(mAudioTrack.get()) + MWBase::Environment::get().getSoundManager()->stopTrack(mAudioTrack); mAudioTrack.reset(); mDecoderBridge.reset(); } diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index d4c890cee..3607f71a4 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -157,17 +157,14 @@ static ALenum getALFormat(ChannelConfig chans, SampleType type) // // A streaming OpenAL sound. // -class OpenAL_SoundStream : public Sound +class OpenAL_SoundStream { static const ALuint sNumBuffers = 6; static const ALfloat sBufferLength; -protected: - OpenAL_Output &mOutput; - +private: ALuint mSource; -private: ALuint mBuffers[sNumBuffers]; ALint mCurrentBufIdx; @@ -189,34 +186,18 @@ private: friend class OpenAL_Output; public: - OpenAL_SoundStream(OpenAL_Output &output, ALuint src, DecoderPtr decoder, const osg::Vec3f& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags); - virtual ~OpenAL_SoundStream(); + OpenAL_SoundStream(ALuint src, DecoderPtr decoder); + ~OpenAL_SoundStream(); - virtual void stop(); - virtual bool isPlaying(); - virtual double getTimeOffset(); - virtual double getStreamDelay() const; - virtual void applyUpdates(); + bool isPlaying(); + double getStreamDelay() const; + double getStreamOffset() const; - void play(); bool process(); ALint refillQueue(); }; const ALfloat OpenAL_SoundStream::sBufferLength = 0.125f; -class OpenAL_SoundStream3D : public OpenAL_SoundStream -{ - OpenAL_SoundStream3D(const OpenAL_SoundStream3D &rhs); - OpenAL_SoundStream3D& operator=(const OpenAL_SoundStream3D &rhs); - -public: - OpenAL_SoundStream3D(OpenAL_Output &output, ALuint src, DecoderPtr decoder, const osg::Vec3f& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags) - : OpenAL_SoundStream(output, src, decoder, pos, vol, basevol, pitch, mindist, maxdist, flags) - { } - - virtual void applyUpdates(); -}; - // // A background streaming thread (keeps active streams processed) @@ -329,13 +310,9 @@ private: }; -OpenAL_SoundStream::OpenAL_SoundStream(OpenAL_Output &output, ALuint src, DecoderPtr decoder, const osg::Vec3f& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags) - : Sound(pos, vol, basevol, pitch, mindist, maxdist, flags) - , mOutput(output), mSource(src), mCurrentBufIdx(0), mFrameSize(0), mSilence(0) - , mDecoder(decoder), mIsFinished(true) +OpenAL_SoundStream::OpenAL_SoundStream(ALuint src, DecoderPtr decoder) + : mSource(src), mCurrentBufIdx(0), mFrameSize(0), mSilence(0), mDecoder(decoder), mIsFinished(false) { - throwALerror(); - alGenBuffers(sNumBuffers, mBuffers); throwALerror(); try @@ -358,8 +335,6 @@ OpenAL_SoundStream::OpenAL_SoundStream(OpenAL_Output &output, ALuint src, Decode mFrameSize = framesToBytes(1, chans, type); mBufferSize = static_cast(sBufferLength*srate); mBufferSize *= mFrameSize; - - mOutput.mActiveStreams.push_back(this); } catch(std::exception&) { @@ -367,51 +342,20 @@ OpenAL_SoundStream::OpenAL_SoundStream(OpenAL_Output &output, ALuint src, Decode alGetError(); throw; } + mIsFinished = false; } OpenAL_SoundStream::~OpenAL_SoundStream() { - mOutput.mStreamThread->remove(this); - - alSourceStop(mSource); - alSourcei(mSource, AL_BUFFER, 0); - - mOutput.mFreeSources.push_back(mSource); alDeleteBuffers(sNumBuffers, mBuffers); alGetError(); mDecoder->close(); - - mOutput.mActiveStreams.erase(std::find(mOutput.mActiveStreams.begin(), - mOutput.mActiveStreams.end(), this)); -} - -void OpenAL_SoundStream::play() -{ - alSourceStop(mSource); - alSourcei(mSource, AL_BUFFER, 0); - throwALerror(); - - mIsFinished = false; - mOutput.mStreamThread->add(this); -} - -void OpenAL_SoundStream::stop() -{ - mOutput.mStreamThread->remove(this); - mIsFinished = true; - - alSourceStop(mSource); - alSourcei(mSource, AL_BUFFER, 0); - throwALerror(); - - mDecoder->rewind(); } bool OpenAL_SoundStream::isPlaying() { ALint state; - boost::lock_guard lock(mOutput.mStreamThread->mMutex); alGetSourcei(mSource, AL_SOURCE_STATE, &state); throwALerror(); @@ -420,13 +364,12 @@ bool OpenAL_SoundStream::isPlaying() return !mIsFinished; } -double OpenAL_SoundStream::getTimeOffset() +double OpenAL_SoundStream::getStreamDelay() const { ALint state = AL_STOPPED; + double d = 0.0; ALint offset; - double t; - boost::lock_guard lock(mOutput.mStreamThread->mMutex); alGetSourcei(mSource, AL_SAMPLE_OFFSET, &offset); alGetSourcei(mSource, AL_SOURCE_STATE, &state); if(state == AL_PLAYING || state == AL_PAUSED) @@ -434,24 +377,18 @@ double OpenAL_SoundStream::getTimeOffset() ALint queued; alGetSourcei(mSource, AL_BUFFERS_QUEUED, &queued); ALint inqueue = mBufferSize/mFrameSize*queued - offset; - t = (double)(mDecoder->getSampleOffset() - inqueue) / (double)mSampleRate; - } - else - { - /* Underrun, or not started yet. The decoder offset is where we'll play - * next. */ - t = (double)mDecoder->getSampleOffset() / (double)mSampleRate; + d = (double)inqueue / (double)mSampleRate; } throwALerror(); - return t; + return d; } -double OpenAL_SoundStream::getStreamDelay() const +double OpenAL_SoundStream::getStreamOffset() const { ALint state = AL_STOPPED; - double d = 0.0; ALint offset; + double t; alGetSourcei(mSource, AL_SAMPLE_OFFSET, &offset); alGetSourcei(mSource, AL_SOURCE_STATE, &state); @@ -460,48 +397,17 @@ double OpenAL_SoundStream::getStreamDelay() const ALint queued; alGetSourcei(mSource, AL_BUFFERS_QUEUED, &queued); ALint inqueue = mBufferSize/mFrameSize*queued - offset; - d = (double)inqueue / (double)mSampleRate; - } - - throwALerror(); - return d; -} - -void OpenAL_SoundStream::updateAll(bool local) -{ - alSourcef(mSource, AL_REFERENCE_DISTANCE, mMinDistance); - alSourcef(mSource, AL_MAX_DISTANCE, mMaxDistance); - if(local) - { - alSourcef(mSource, AL_ROLLOFF_FACTOR, 0.0f); - alSourcei(mSource, AL_SOURCE_RELATIVE, AL_TRUE); + t = (double)(mDecoder->getSampleOffset() - inqueue) / (double)mSampleRate; } else { - alSourcef(mSource, AL_ROLLOFF_FACTOR, 1.0f); - alSourcei(mSource, AL_SOURCE_RELATIVE, AL_FALSE); - } - alSourcei(mSource, AL_LOOPING, AL_FALSE); - - applyUpdates(); -} - -void OpenAL_SoundStream::applyUpdates() -{ - ALfloat gain = mVolume*mBaseVolume; - ALfloat pitch = mPitch; - if(!(mFlags&MWBase::SoundManager::Play_NoEnv) && mOutput.mLastEnvironment == Env_Underwater) - { - gain *= 0.9f; - pitch *= 0.7f; + /* Underrun, or not started yet. The decoder offset is where we'll play + * next. */ + t = (double)mDecoder->getSampleOffset() / (double)mSampleRate; } - alSourcef(mSource, AL_GAIN, gain); - alSourcef(mSource, AL_PITCH, pitch); - alSource3f(mSource, AL_POSITION, mPos[0], mPos[1], mPos[2]); - alSource3f(mSource, AL_DIRECTION, 0.0f, 0.0f, 0.0f); - alSource3f(mSource, AL_VELOCITY, 0.0f, 0.0f, 0.0f); throwALerror(); + return t; } bool OpenAL_SoundStream::process() @@ -562,172 +468,6 @@ ALint OpenAL_SoundStream::refillQueue() return queued; } -void OpenAL_SoundStream3D::applyUpdates() -{ - ALfloat gain = mVolume*mBaseVolume; - ALfloat pitch = mPitch; - if((mPos - mOutput.mPos).length2() > mMaxDistance*mMaxDistance) - gain = 0.0f; - else if(!(mFlags&MWBase::SoundManager::Play_NoEnv) && mOutput.mLastEnvironment == Env_Underwater) - { - gain *= 0.9f; - pitch *= 0.7f; - } - - alSourcef(mSource, AL_GAIN, gain); - alSourcef(mSource, AL_PITCH, pitch); - alSource3f(mSource, AL_POSITION, mPos[0], mPos[1], mPos[2]); - alSource3f(mSource, AL_DIRECTION, 0.0f, 0.0f, 0.0f); - alSource3f(mSource, AL_VELOCITY, 0.0f, 0.0f, 0.0f); - throwALerror(); -} - - -// -// A regular 2D OpenAL sound -// -class OpenAL_Sound : public Sound -{ -protected: - OpenAL_Output &mOutput; - - ALuint mSource; - - friend class OpenAL_Output; - - void updateAll(bool local); - -private: - OpenAL_Sound(const OpenAL_Sound &rhs); - OpenAL_Sound& operator=(const OpenAL_Sound &rhs); - -public: - OpenAL_Sound(OpenAL_Output &output, ALuint src, const osg::Vec3f& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags); - virtual ~OpenAL_Sound(); - - virtual void stop(); - virtual bool isPlaying(); - virtual double getTimeOffset(); - virtual void applyUpdates(); -}; - -// -// A regular 3D OpenAL sound -// -class OpenAL_Sound3D : public OpenAL_Sound -{ - OpenAL_Sound3D(const OpenAL_Sound &rhs); - OpenAL_Sound3D& operator=(const OpenAL_Sound &rhs); - -public: - OpenAL_Sound3D(OpenAL_Output &output, ALuint src, const osg::Vec3f& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags) - : OpenAL_Sound(output, src, pos, vol, basevol, pitch, mindist, maxdist, flags) - { } - - virtual void applyUpdates(); -}; - -OpenAL_Sound::OpenAL_Sound(OpenAL_Output &output, ALuint src, const osg::Vec3f& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags) - : Sound(pos, vol, basevol, pitch, mindist, maxdist, flags) - , mOutput(output), mSource(src) -{ - mOutput.mActiveSounds.push_back(this); -} -OpenAL_Sound::~OpenAL_Sound() -{ - alSourceStop(mSource); - alSourcei(mSource, AL_BUFFER, 0); - - mOutput.mFreeSources.push_back(mSource); - - mOutput.mActiveSounds.erase(std::find(mOutput.mActiveSounds.begin(), - mOutput.mActiveSounds.end(), this)); -} - -void OpenAL_Sound::stop() -{ - alSourceStop(mSource); - throwALerror(); -} - -bool OpenAL_Sound::isPlaying() -{ - ALint state; - - alGetSourcei(mSource, AL_SOURCE_STATE, &state); - throwALerror(); - - return state==AL_PLAYING || state==AL_PAUSED; -} - -double OpenAL_Sound::getTimeOffset() -{ - ALfloat t; - - alGetSourcef(mSource, AL_SEC_OFFSET, &t); - throwALerror(); - - return t; -} - -void OpenAL_Sound::updateAll(bool local) -{ - alSourcef(mSource, AL_REFERENCE_DISTANCE, mMinDistance); - alSourcef(mSource, AL_MAX_DISTANCE, mMaxDistance); - if(local) - { - alSourcef(mSource, AL_ROLLOFF_FACTOR, 0.0f); - alSourcei(mSource, AL_SOURCE_RELATIVE, AL_TRUE); - } - else - { - alSourcef(mSource, AL_ROLLOFF_FACTOR, 1.0f); - alSourcei(mSource, AL_SOURCE_RELATIVE, AL_FALSE); - } - alSourcei(mSource, AL_LOOPING, (mFlags&MWBase::SoundManager::Play_Loop) ? AL_TRUE : AL_FALSE); - - applyUpdates(); -} - -void OpenAL_Sound::applyUpdates() -{ - ALfloat gain = mVolume*mBaseVolume; - ALfloat pitch = mPitch; - - if(!(mFlags&MWBase::SoundManager::Play_NoEnv) && mOutput.mLastEnvironment == Env_Underwater) - { - gain *= 0.9f; - pitch *= 0.7f; - } - - alSourcef(mSource, AL_GAIN, gain); - alSourcef(mSource, AL_PITCH, pitch); - alSource3f(mSource, AL_POSITION, mPos[0], mPos[1], mPos[2]); - alSource3f(mSource, AL_DIRECTION, 0.0f, 0.0f, 0.0f); - alSource3f(mSource, AL_VELOCITY, 0.0f, 0.0f, 0.0f); - throwALerror(); -} - -void OpenAL_Sound3D::applyUpdates() -{ - ALfloat gain = mVolume*mBaseVolume; - ALfloat pitch = mPitch; - if((mPos - mOutput.mPos).length2() > mMaxDistance*mMaxDistance) - gain = 0.0f; - else if(!(mFlags&MWBase::SoundManager::Play_NoEnv) && mOutput.mLastEnvironment == Env_Underwater) - { - gain *= 0.9f; - pitch *= 0.7f; - } - - alSourcef(mSource, AL_GAIN, gain); - alSourcef(mSource, AL_PITCH, pitch); - alSource3f(mSource, AL_POSITION, mPos[0], mPos[1], mPos[2]); - alSource3f(mSource, AL_DIRECTION, 0.0f, 0.0f, 0.0f); - alSource3f(mSource, AL_VELOCITY, 0.0f, 0.0f, 0.0f); - throwALerror(); -} - // // An OpenAL output device @@ -881,15 +621,16 @@ void OpenAL_Output::unloadSound(Sound_Handle data) SoundVec::const_iterator iter = mActiveSounds.begin(); for(;iter != mActiveSounds.end();++iter) { - if(!(*iter)->mSource) + if(!(*iter)->mHandle) continue; + ALuint source = GET_PTRID((*iter)->mHandle); ALint srcbuf; - alGetSourcei((*iter)->mSource, AL_BUFFER, &srcbuf); + alGetSourcei(source, AL_BUFFER, &srcbuf); if((ALuint)srcbuf == buffer) { - alSourceStop((*iter)->mSource); - alSourcei((*iter)->mSource, AL_BUFFER, 0); + alSourceStop(source); + alSourcei(source, AL_BUFFER, 0); } } alDeleteBuffers(1, &buffer); @@ -907,123 +648,281 @@ size_t OpenAL_Output::getSoundDataSize(Sound_Handle data) const } -MWBase::SoundPtr OpenAL_Output::playSound(Sound_Handle data, float vol, float basevol, float pitch, int flags,float offset) +MWBase::SoundPtr OpenAL_Output::playSound(Sound_Handle data, float vol, float basevol, float pitch, int flags, float offset) { - boost::shared_ptr sound; - ALuint src; + boost::shared_ptr sound; + ALuint source; if(mFreeSources.empty()) fail("No free sources"); - src = mFreeSources.front(); + source = mFreeSources.front(); mFreeSources.pop_front(); try { - sound.reset(new OpenAL_Sound(*this, src, osg::Vec3f(0.f, 0.f, 0.f), vol, basevol, pitch, 1.0f, 1000.0f, flags)); + alSourcef(source, AL_REFERENCE_DISTANCE, 1.0f); + alSourcef(source, AL_MAX_DISTANCE, 1000.0f); + alSourcef(source, AL_ROLLOFF_FACTOR, 0.0f); + alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE); + alSourcei(source, AL_LOOPING, (flags&MWBase::SoundManager::Play_Loop) ? AL_TRUE : AL_FALSE); + + ALfloat gain = vol*basevol; + if(!(flags&MWBase::SoundManager::Play_NoEnv) && mLastEnvironment == Env_Underwater) + { + gain *= 0.9f; + pitch *= 0.7f; + } + + alSourcef(source, AL_GAIN, gain); + alSourcef(source, AL_PITCH, pitch); + alSource3f(source, AL_POSITION, 0.0f, 0.0f, 0.0f); + alSource3f(source, AL_DIRECTION, 0.0f, 0.0f, 0.0f); + alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f); + + alSourcef(source, AL_SEC_OFFSET, offset/pitch); + alSourcei(source, AL_BUFFER, GET_PTRID(data)); + + alSourcePlay(source); + throwALerror(); + + sound.reset(new Sound(osg::Vec3f(0.f, 0.f, 0.f), vol, basevol, pitch, 1.0f, 1000.0f, flags)); + sound->mHandle = MAKE_PTRID(source); + mActiveSounds.push_back(sound); } - catch(std::exception&) - { - mFreeSources.push_back(src); + catch(std::exception&) { + mFreeSources.push_back(source); throw; } - sound->updateAll(true); - alSourcei(src, AL_BUFFER, GET_PTRID(data)); - alSourcef(src, AL_SEC_OFFSET, offset/pitch); - - alSourcePlay(src); - throwALerror(); - return sound; } MWBase::SoundPtr OpenAL_Output::playSound3D(Sound_Handle data, const osg::Vec3f &pos, float vol, float basevol, float pitch, - float min, float max, int flags, float offset) + float mindist, float maxdist, int flags, float offset) { - boost::shared_ptr sound; - ALuint src; + boost::shared_ptr sound; + ALuint source; if(mFreeSources.empty()) fail("No free sources"); - src = mFreeSources.front(); + source = mFreeSources.front(); mFreeSources.pop_front(); try { - sound.reset(new OpenAL_Sound3D(*this, src, pos, vol, basevol, pitch, min, max, flags)); + alSourcef(source, AL_REFERENCE_DISTANCE, mindist); + alSourcef(source, AL_MAX_DISTANCE, maxdist); + alSourcef(source, AL_ROLLOFF_FACTOR, 1.0f); + alSourcei(source, AL_SOURCE_RELATIVE, AL_FALSE); + alSourcei(source, AL_LOOPING, (flags&MWBase::SoundManager::Play_Loop) ? AL_TRUE : AL_FALSE); + + ALfloat gain = vol*basevol; + if((pos - mPos).length2() > maxdist*maxdist) + gain = 0.0f; + if(!(flags&MWBase::SoundManager::Play_NoEnv) && mLastEnvironment == Env_Underwater) + { + gain *= 0.9f; + pitch *= 0.7f; + } + + alSourcef(source, AL_GAIN, gain); + alSourcef(source, AL_PITCH, pitch); + alSourcefv(source, AL_POSITION, pos.ptr()); + alSource3f(source, AL_DIRECTION, 0.0f, 0.0f, 0.0f); + alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f); + + alSourcef(source, AL_SEC_OFFSET, offset/pitch); + alSourcei(source, AL_BUFFER, GET_PTRID(data)); + + alSourcePlay(source); + throwALerror(); + + sound.reset(new Sound(pos, vol, basevol, pitch, mindist, maxdist, flags)); + sound->mHandle = MAKE_PTRID(source); + mActiveSounds.push_back(sound); } - catch(std::exception&) - { - mFreeSources.push_back(src); + catch(std::exception&) { + mFreeSources.push_back(source); throw; } - sound->updateAll(false); - alSourcei(src, AL_BUFFER, GET_PTRID(data)); - alSourcef(src, AL_SEC_OFFSET, offset/pitch); + return sound; +} + +void OpenAL_Output::stopSound(MWBase::SoundPtr sound) +{ + if(!sound->mHandle) + return; + + ALuint source = GET_PTRID(sound->mHandle); + sound->mHandle = 0; + + alSourceStop(source); + alSourcei(source, AL_BUFFER, 0); + + mFreeSources.push_back(source); + mActiveSounds.erase(std::find(mActiveSounds.begin(), mActiveSounds.end(), sound)); +} - alSourcePlay(src); +bool OpenAL_Output::isSoundPlaying(MWBase::SoundPtr sound) +{ + if(!sound->mHandle) + return false; + ALuint source = GET_PTRID(sound->mHandle); + ALint state; + + alGetSourcei(source, AL_SOURCE_STATE, &state); throwALerror(); - return sound; + return state == AL_PLAYING || state == AL_PAUSED; } MWBase::SoundPtr OpenAL_Output::streamSound(DecoderPtr decoder, float basevol, float pitch, int flags) { - boost::shared_ptr sound; - ALuint src; + boost::shared_ptr sound; + OpenAL_SoundStream *stream = 0; + ALuint source; if(mFreeSources.empty()) fail("No free sources"); - src = mFreeSources.front(); + source = mFreeSources.front(); mFreeSources.pop_front(); if((flags&MWBase::SoundManager::Play_Loop)) std::cout <<"Warning: cannot loop stream \""<getName()<<"\""<< std::endl; - try - { - sound.reset(new OpenAL_SoundStream(*this, src, decoder, osg::Vec3f(0.0f, 0.0f, 0.0f), 1.0f, basevol, pitch, 1.0f, 1000.0f, flags)); + try { + alSourcef(source, AL_REFERENCE_DISTANCE, 1.0f); + alSourcef(source, AL_MAX_DISTANCE, 1000.0f); + alSourcef(source, AL_ROLLOFF_FACTOR, 0.0f); + alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE); + alSourcei(source, AL_LOOPING, AL_FALSE); + + ALfloat gain = basevol; + if(!(flags&MWBase::SoundManager::Play_NoEnv) && mLastEnvironment == Env_Underwater) + { + gain *= 0.9f; + pitch *= 0.7f; + } + + alSourcef(source, AL_GAIN, gain); + alSourcef(source, AL_PITCH, pitch); + alSource3f(source, AL_POSITION, 0.0f, 0.0f, 0.0f); + alSource3f(source, AL_DIRECTION, 0.0f, 0.0f, 0.0f); + alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f); + throwALerror(); + + sound.reset(new Sound(osg::Vec3f(0.0f, 0.0f, 0.0f), 1.0f, basevol, pitch, 1.0f, 1000.0f, flags)); + stream = new OpenAL_SoundStream(source, decoder); + mStreamThread->add(stream); + sound->mHandle = stream; + mActiveStreams.push_back(sound); } - catch(std::exception&) - { - mFreeSources.push_back(src); + catch(std::exception&) { + mStreamThread->remove(stream); + delete stream; + mFreeSources.push_back(source); throw; } - sound->updateAll(true); - - sound->play(); return sound; } - -MWBase::SoundPtr OpenAL_Output::streamSound3D(DecoderPtr decoder, const osg::Vec3f &pos, float volume, float basevol, float pitch, float min, float max, int flags) +MWBase::SoundPtr OpenAL_Output::streamSound3D(DecoderPtr decoder, const osg::Vec3f &pos, float volume, float basevol, float pitch, float mindist, float maxdist, int flags) { - boost::shared_ptr sound; - ALuint src; + boost::shared_ptr sound; + OpenAL_SoundStream *stream = 0; + ALuint source; if(mFreeSources.empty()) fail("No free sources"); - src = mFreeSources.front(); + source = mFreeSources.front(); mFreeSources.pop_front(); if((flags&MWBase::SoundManager::Play_Loop)) std::cout <<"Warning: cannot loop stream \""<getName()<<"\""<< std::endl; - try - { - sound.reset(new OpenAL_SoundStream3D(*this, src, decoder, pos, volume, basevol, pitch, min, max, flags)); + try { + alSourcef(source, AL_REFERENCE_DISTANCE, mindist); + alSourcef(source, AL_MAX_DISTANCE, maxdist); + alSourcef(source, AL_ROLLOFF_FACTOR, 1.0f); + alSourcei(source, AL_SOURCE_RELATIVE, AL_FALSE); + alSourcei(source, AL_LOOPING, AL_FALSE); + + ALfloat gain = volume*basevol; + if((pos - mPos).length2() > maxdist*maxdist) + gain = 0.0f; + if(!(flags&MWBase::SoundManager::Play_NoEnv) && mLastEnvironment == Env_Underwater) + { + gain *= 0.9f; + pitch *= 0.7f; + } + + alSourcef(source, AL_GAIN, gain); + alSourcef(source, AL_PITCH, pitch); + alSourcefv(source, AL_POSITION, pos.ptr()); + alSource3f(source, AL_DIRECTION, 0.0f, 0.0f, 0.0f); + alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f); + throwALerror(); + + sound.reset(new Sound(pos, volume, basevol, pitch, mindist, maxdist, flags)); + stream = new OpenAL_SoundStream(source, decoder); + mStreamThread->add(stream); + sound->mHandle = stream; + mActiveStreams.push_back(sound); } - catch(std::exception&) - { - mFreeSources.push_back(src); + catch(std::exception&) { + mStreamThread->remove(stream); + delete stream; + mFreeSources.push_back(source); throw; } - sound->updateAll(false); - - sound->play(); return sound; } +void OpenAL_Output::stopStream(MWBase::SoundPtr sound) +{ + if(!sound->mHandle) + return; + OpenAL_SoundStream *stream = reinterpret_cast(sound->mHandle); + ALuint source = stream->mSource; + + sound->mHandle = 0; + mStreamThread->remove(stream); + + alSourceStop(source); + alSourcei(source, AL_BUFFER, 0); + + mFreeSources.push_back(source); + mActiveStreams.erase(std::find(mActiveStreams.begin(), mActiveStreams.end(), sound)); + + delete stream; +} + +double OpenAL_Output::getStreamDelay(MWBase::SoundPtr sound) +{ + if(!sound->mHandle) + return 0.0; + OpenAL_SoundStream *stream = reinterpret_cast(sound->mHandle); + return stream->getStreamDelay(); +} + +double OpenAL_Output::getStreamOffset(MWBase::SoundPtr sound) +{ + if(!sound->mHandle) + return 0.0; + OpenAL_SoundStream *stream = reinterpret_cast(sound->mHandle); + boost::lock_guard lock(mStreamThread->mMutex); + return stream->getStreamOffset(); +} + +bool OpenAL_Output::isStreamPlaying(MWBase::SoundPtr sound) +{ + if(!sound->mHandle) + return false; + OpenAL_SoundStream *stream = reinterpret_cast(sound->mHandle); + boost::lock_guard lock(mStreamThread->mMutex); + return stream->isPlaying(); +} + void OpenAL_Output::startUpdate() { @@ -1060,14 +959,17 @@ void OpenAL_Output::pauseSounds(int types) SoundVec::const_iterator sound = mActiveSounds.begin(); for(;sound != mActiveSounds.end();++sound) { - if(*sound && (*sound)->mSource && ((*sound)->getPlayType()&types)) - sources.push_back((*sound)->mSource); + if(*sound && (*sound)->mHandle && ((*sound)->getPlayType()&types)) + sources.push_back(GET_PTRID((*sound)->mHandle)); } StreamVec::const_iterator stream = mActiveStreams.begin(); for(;stream != mActiveStreams.end();++stream) { - if(*stream && (*stream)->mSource && ((*stream)->getPlayType()&types)) - sources.push_back((*stream)->mSource); + if(*stream && (*stream)->mHandle && ((*stream)->getPlayType()&types)) + { + OpenAL_SoundStream *strm = reinterpret_cast((*stream)->mHandle); + sources.push_back(strm->mSource); + } } if(!sources.empty()) { @@ -1082,14 +984,17 @@ void OpenAL_Output::resumeSounds(int types) SoundVec::const_iterator sound = mActiveSounds.begin(); for(;sound != mActiveSounds.end();++sound) { - if(*sound && (*sound)->mSource && ((*sound)->getPlayType()&types)) - sources.push_back((*sound)->mSource); + if(*sound && (*sound)->mHandle && ((*sound)->getPlayType()&types)) + sources.push_back(GET_PTRID((*sound)->mHandle)); } StreamVec::const_iterator stream = mActiveStreams.begin(); for(;stream != mActiveStreams.end();++stream) { - if(*stream && (*stream)->mSource && ((*stream)->getPlayType()&types)) - sources.push_back((*stream)->mSource); + if(*stream && (*stream)->mHandle && ((*stream)->getPlayType()&types)) + { + OpenAL_SoundStream *strm = reinterpret_cast((*stream)->mHandle); + sources.push_back(strm->mSource); + } } if(!sources.empty()) { diff --git a/apps/openmw/mwsound/openal_output.hpp b/apps/openmw/mwsound/openal_output.hpp index 751ec4fd2..b7c3603c6 100644 --- a/apps/openmw/mwsound/openal_output.hpp +++ b/apps/openmw/mwsound/openal_output.hpp @@ -16,9 +16,6 @@ namespace MWSound class SoundManager; class Sound; - class OpenAL_Sound; - class OpenAL_SoundStream; - class OpenAL_Output : public Sound_Output { ALCdevice *mDevice; @@ -27,9 +24,9 @@ namespace MWSound typedef std::deque IDDq; IDDq mFreeSources; - typedef std::vector SoundVec; + typedef std::vector SoundVec; SoundVec mActiveSounds; - typedef std::vector StreamVec; + typedef std::vector StreamVec; StreamVec mActiveStreams; Environment mLastEnvironment; @@ -45,9 +42,16 @@ namespace MWSound virtual MWBase::SoundPtr playSound(Sound_Handle data, float vol, float basevol, float pitch, int flags, float offset); virtual MWBase::SoundPtr playSound3D(Sound_Handle data, const osg::Vec3f &pos, float vol, float basevol, float pitch, float min, float max, int flags, float offset); + virtual void stopSound(MWBase::SoundPtr sound); + virtual bool isSoundPlaying(MWBase::SoundPtr sound); + virtual MWBase::SoundPtr streamSound(DecoderPtr decoder, float basevol, float pitch, int flags); virtual MWBase::SoundPtr streamSound3D(DecoderPtr decoder, const osg::Vec3f &pos, float vol, float basevol, float pitch, float min, float max, int flags); + virtual void stopStream(MWBase::SoundPtr sound); + virtual double getStreamDelay(MWBase::SoundPtr sound); + virtual double getStreamOffset(MWBase::SoundPtr sound); + virtual bool isStreamPlaying(MWBase::SoundPtr sound); virtual void startUpdate(); virtual void finishUpdate(); diff --git a/apps/openmw/mwsound/sound.hpp b/apps/openmw/mwsound/sound.hpp index f95ff169d..f467ba121 100644 --- a/apps/openmw/mwsound/sound.hpp +++ b/apps/openmw/mwsound/sound.hpp @@ -10,7 +10,6 @@ namespace MWSound Sound& operator=(const Sound &rhs); Sound(const Sound &rhs); - protected: osg::Vec3f mPos; float mVolume; /* NOTE: Real volume = mVolume*mBaseVolume */ float mBaseVolume; @@ -21,12 +20,13 @@ namespace MWSound float mFadeOutTime; + protected: + void *mHandle; + + friend class Sound_Output; + friend class OpenAL_Output; + public: - virtual void stop() = 0; - virtual bool isPlaying() = 0; - virtual double getTimeOffset() = 0; - virtual double getStreamDelay() const { return 0.0; } - virtual void applyUpdates() = 0; void setPosition(const osg::Vec3f &pos) { mPos = pos; } void setVolume(float volume) { mVolume = volume; } void setBaseVolume(float volume) { mBaseVolume = volume; } @@ -47,16 +47,11 @@ namespace MWSound bool getIs3D() const { return mFlags&Play_3D; } Sound(const osg::Vec3f& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags) - : mPos(pos) - , mVolume(vol) - , mBaseVolume(basevol) - , mPitch(pitch) - , mMinDistance(mindist) - , mMaxDistance(maxdist) - , mFlags(flags) - , mFadeOutTime(0.0f) + : mPos(pos), mVolume(vol), mBaseVolume(basevol), mPitch(pitch) + , mMinDistance(mindist), mMaxDistance(maxdist), mFlags(flags) + , mFadeOutTime(0.0f), mHandle(0) { } - virtual ~Sound() { } + ~Sound() { } }; } diff --git a/apps/openmw/mwsound/sound_output.hpp b/apps/openmw/mwsound/sound_output.hpp index 0f69498aa..bdf40bf44 100644 --- a/apps/openmw/mwsound/sound_output.hpp +++ b/apps/openmw/mwsound/sound_output.hpp @@ -35,9 +35,16 @@ namespace MWSound /// @param offset Number of seconds into the sound to start playback. virtual MWBase::SoundPtr playSound3D(Sound_Handle data, const osg::Vec3f &pos, float vol, float basevol, float pitch, float min, float max, int flags, float offset) = 0; + virtual void stopSound(MWBase::SoundPtr sound) = 0; + virtual bool isSoundPlaying(MWBase::SoundPtr sound) = 0; + virtual MWBase::SoundPtr streamSound(DecoderPtr decoder, float basevol, float pitch, int flags) = 0; virtual MWBase::SoundPtr streamSound3D(DecoderPtr decoder, const osg::Vec3f &pos, float vol, float basevol, float pitch, float min, float max, int flags) = 0; + virtual void stopStream(MWBase::SoundPtr sound) = 0; + virtual double getStreamDelay(MWBase::SoundPtr sound) = 0; + virtual double getStreamOffset(MWBase::SoundPtr sound) = 0; + virtual bool isStreamPlaying(MWBase::SoundPtr sound) = 0; virtual void startUpdate() = 0; virtual void finishUpdate() = 0; diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index ceff1a619..82dd49f32 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -293,7 +293,7 @@ namespace MWSound void SoundManager::stopMusic() { if(mMusic) - mMusic->stop(); + mOutput->stopStream(mMusic); mMusic.reset(); } @@ -303,8 +303,7 @@ namespace MWSound return; std::cout <<"Playing "<streamSound(decoder, volumeFromType(Play_TypeMusic), 1.0f, Play_NoEnv|Play_TypeMusic|Play_2D); } - catch(std::exception &e) - { + catch(std::exception &e) { std::cout << "Music Error: " << e.what() << "\n"; } } @@ -366,7 +364,7 @@ namespace MWSound bool SoundManager::isMusicPlaying() { - return mMusic && mMusic->isPlaying(); + return mMusic && mOutput->isStreamPlaying(mMusic); } void SoundManager::playPlaylist(const std::string &playlist) @@ -411,9 +409,8 @@ namespace MWSound { MWBase::SoundPtr sound = snditer->second.first; Sound_Loudness *loudness = snditer->second.second; - float sec = sound->getTimeOffset(); - if(sound->isPlaying()) - return loudness->getLoudnessAtTime(sec); + float sec = mOutput->getStreamOffset(sound); + return loudness->getLoudnessAtTime(sec); } return 0.0f; @@ -450,7 +447,7 @@ namespace MWSound SaySoundMap::const_iterator snditer = mActiveSaySounds.find(ptr); if(snditer != mActiveSaySounds.end()) { - if(snditer->second.first->isPlaying()) + if(mOutput->isStreamPlaying(snditer->second.first)) return false; return true; } @@ -462,7 +459,7 @@ namespace MWSound SaySoundMap::iterator snditer = mActiveSaySounds.find(ptr); if(snditer != mActiveSaySounds.end()) { - snditer->second.first->stop(); + mOutput->stopStream(snditer->second.first); mActiveSaySounds.erase(snditer); } mPendingSaySounds.erase(ptr); @@ -485,6 +482,16 @@ namespace MWSound return track; } + void SoundManager::stopTrack(MWBase::SoundPtr sound) + { + mOutput->stopStream(sound); + } + + double SoundManager::getTrackTimeDelay(MWBase::SoundPtr sound) + { + return mOutput->getStreamDelay(sound); + } + MWBase::SoundPtr SoundManager::playSound(const std::string& soundId, float volume, float pitch, PlayType type, PlayMode mode, float offset) { @@ -586,6 +593,11 @@ namespace MWSound return sound; } + void SoundManager::stopSound(MWBase::SoundPtr sound) + { + mOutput->stopSound(sound); + } + void SoundManager::stopSound3D(const MWWorld::Ptr &ptr, const std::string& soundId) { SoundMap::iterator snditer = mActiveSounds.find(ptr); @@ -596,7 +608,7 @@ namespace MWSound for(;sndidx != snditer->second.end();++sndidx) { if(sndidx->second == sfx) - sndidx->first->stop(); + mOutput->stopSound(sndidx->first); } } } @@ -608,7 +620,7 @@ namespace MWSound { SoundBufferRefPairList::iterator sndidx = snditer->second.begin(); for(;sndidx != snditer->second.end();++sndidx) - sndidx->first->stop(); + mOutput->stopSound(sndidx->first); } } @@ -623,7 +635,7 @@ namespace MWSound { SoundBufferRefPairList::iterator sndidx = snditer->second.begin(); for(;sndidx != snditer->second.end();++sndidx) - sndidx->first->stop(); + mOutput->stopSound(sndidx->first); } ++snditer; } @@ -634,7 +646,7 @@ namespace MWSound sayiter->first != MWMechanics::getPlayer() && sayiter->first.getCell() == cell) { - sayiter->second.first->stop(); + mOutput->stopStream(sayiter->second.first); } ++sayiter; } @@ -650,7 +662,7 @@ namespace MWSound for(;sndidx != snditer->second.end();++sndidx) { if(sndidx->second == sfx) - sndidx->first->stop(); + mOutput->stopSound(sndidx->first); } } } @@ -680,7 +692,7 @@ namespace MWSound SoundBufferRefPairList::const_iterator sndidx = snditer->second.begin(); for(;sndidx != snditer->second.end();++sndidx) { - if(sndidx->second == sfx && sndidx->first->isPlaying()) + if(sndidx->second == sfx && mOutput->isSoundPlaying(sndidx->first)) return true; } } @@ -788,7 +800,7 @@ namespace MWSound env = Env_Underwater; else if(mUnderwaterSound) { - mUnderwaterSound->stop(); + mOutput->stopSound(mUnderwaterSound); mUnderwaterSound.reset(); } @@ -803,7 +815,7 @@ namespace MWSound if(mListenerUnderwater) { // Play underwater sound (after updating listener) - if(!(mUnderwaterSound && mUnderwaterSound->isPlaying())) + if(!(mUnderwaterSound && mOutput->isSoundPlaying(mUnderwaterSound))) mUnderwaterSound = playSound("Underwater", 1.0f, 1.0f, Play_TypeSfx, Play_LoopNoEnv); } @@ -814,15 +826,35 @@ namespace MWSound SoundBufferRefPairList::iterator sndidx = snditer->second.begin(); while(sndidx != snditer->second.end()) { - if(!updateSound(sndidx->first, snditer->first, duration)) + MWWorld::Ptr ptr = snditer->first; + MWBase::SoundPtr sound = sndidx->first; + if(!ptr.isEmpty() && sound->getIs3D()) + { + const ESM::Position &pos = ptr.getRefData().getPosition(); + const osg::Vec3f objpos(pos.asVec3()); + sound->setPosition(objpos); + + if(sound->getDistanceCull()) + { + if((mListenerPos - objpos).length2() > 2000*2000) + mOutput->stopSound(sound); + } + } + + if(!mOutput->isSoundPlaying(sound)) { + mOutput->stopSound(sound); Sound_Buffer *sfx = sndidx->second; if(sfx->mUses-- == 1) mUnusedBuffers.push_front(sfx); sndidx = snditer->second.erase(sndidx); } else + { + sound->updateFade(duration); + ++sndidx; + } } if(snditer->second.empty()) mActiveSounds.erase(snditer++); @@ -862,36 +894,34 @@ namespace MWSound SaySoundMap::iterator sayiter = mActiveSaySounds.begin(); while(sayiter != mActiveSaySounds.end()) { - if(!updateSound(sayiter->second.first, sayiter->first, duration)) - mActiveSaySounds.erase(sayiter++); - else - ++sayiter; - } - mOutput->finishUpdate(); - } + MWWorld::Ptr ptr = sayiter->first; + MWBase::SoundPtr sound = sayiter->second.first; + if(!ptr.isEmpty() && sound->getIs3D()) + { + const ESM::Position &pos = ptr.getRefData().getPosition(); + const osg::Vec3f objpos(pos.asVec3()); + sound->setPosition(objpos); - bool SoundManager::updateSound(MWBase::SoundPtr sound, const MWWorld::Ptr& ptr, float duration) - { - if(!ptr.isEmpty() && sound->getIs3D()) - { - const ESM::Position &pos = ptr.getRefData().getPosition(); - const osg::Vec3f objpos(pos.asVec3()); - sound->setPosition(objpos); + if(sound->getDistanceCull()) + { + if((mListenerPos - objpos).length2() > 2000*2000) + mOutput->stopStream(sound); + } + } - if(sound->getDistanceCull()) + if(!mOutput->isStreamPlaying(sound)) { - if((mListenerPos - objpos).length2() > 2000*2000) - sound->stop(); + mOutput->stopStream(sound); + mActiveSaySounds.erase(sayiter++); } - } - - if(!sound->isPlaying()) - return false; - - sound->updateFade(duration); + else + { + sound->updateFade(duration); - sound->applyUpdates(); - return true; + ++sayiter; + } + } + mOutput->finishUpdate(); } @@ -928,7 +958,6 @@ namespace MWSound { MWBase::SoundPtr sound = sndidx->first; sound->setBaseVolume(volumeFromType(sound->getPlayType())); - sound->applyUpdates(); } } SaySoundMap::iterator sayiter = mActiveSaySounds.begin(); @@ -936,12 +965,10 @@ namespace MWSound { MWBase::SoundPtr sound = sayiter->second.first; sound->setBaseVolume(volumeFromType(sound->getPlayType())); - sound->applyUpdates(); } if(mMusic) { mMusic->setBaseVolume(volumeFromType(mMusic->getPlayType())); - mMusic->applyUpdates(); } mOutput->finishUpdate(); } @@ -1056,7 +1083,7 @@ namespace MWSound SoundBufferRefPairList::iterator sndidx = snditer->second.begin(); for(;sndidx != snditer->second.end();++sndidx) { - sndidx->first->stop(); + mOutput->stopSound(sndidx->first); Sound_Buffer *sfx = sndidx->second; if(sfx->mUses-- == 1) mUnusedBuffers.push_front(sfx); @@ -1065,7 +1092,7 @@ namespace MWSound mActiveSounds.clear(); SaySoundMap::iterator sayiter = mActiveSaySounds.begin(); for(;sayiter != mActiveSaySounds.end();++sayiter) - sayiter->second.first->stop(); + mOutput->stopStream(sayiter->second.first); mActiveSaySounds.clear(); mPendingSaySounds.clear(); mUnderwaterSound.reset(); diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index 9c090585b..5f4cf6ebc 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -116,7 +116,6 @@ namespace MWSound MWBase::SoundPtr playVoice(DecoderPtr decoder, const osg::Vec3f &pos, bool playlocal); void streamMusicFull(const std::string& filename); - bool updateSound(MWBase::SoundPtr sound, const MWWorld::Ptr &ptr, float duration); void updateSounds(float duration); void updateRegionSound(float duration); @@ -174,6 +173,14 @@ namespace MWSound virtual MWBase::SoundPtr playTrack(const DecoderPtr& decoder, PlayType type); ///< Play a 2D audio track, using a custom decoder + virtual void stopTrack(MWBase::SoundPtr sound); + ///< Stop the given audio track from playing + + virtual double getTrackTimeDelay(MWBase::SoundPtr sound); + ///< Retives the time delay, in seconds, of the audio track (must be a sound + /// returned by \ref playTrack). Only intended to be called by the track + /// decoder's read method. + virtual MWBase::SoundPtr playSound(const std::string& soundId, float volume, float pitch, PlayType type=Play_TypeSfx, PlayMode mode=Play_Normal, float offset=0); ///< Play a sound, independently of 3D-position ///< @param offset Number of seconds into the sound to start playback. @@ -189,6 +196,9 @@ namespace MWSound ///< Play a 3D sound at \a initialPos. If the sound should be moving, it must be updated using Sound::setPosition. ///< @param offset Number of seconds into the sound to start playback. + virtual void stopSound(MWBase::SoundPtr sound); + ///< Stop the given sound from playing + virtual void stopSound3D(const MWWorld::Ptr &reference, const std::string& soundId); ///< Stop the given object from playing the given sound, diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 4ec4d1432..08ae6f2b0 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -190,7 +190,7 @@ namespace MWWorld { MWBase::Environment::get().getWorld()->explodeSpell(pos, it->mEffects, caster, ESM::RT_Target, it->mSpellId, it->mSourceName); - it->mSound->stop(); + MWBase::Environment::get().getSoundManager()->stopSound(it->mSound); mParent->removeChild(it->mNode); it = mMagicBolts.erase(it); @@ -264,7 +264,7 @@ namespace MWWorld for (std::vector::iterator it = mMagicBolts.begin(); it != mMagicBolts.end(); ++it) { mParent->removeChild(it->mNode); - it->mSound->stop(); + MWBase::Environment::get().getSoundManager()->stopSound(it->mSound); } mMagicBolts.clear(); } diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index afa819121..9a93f3827 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -738,7 +738,7 @@ void WeatherManager::update(float duration, bool paused) void WeatherManager::stopSounds() { if (mAmbientSound.get()) - mAmbientSound->stop(); + MWBase::Environment::get().getSoundManager()->stopSound(mAmbientSound); mAmbientSound.reset(); mPlayingSoundID.clear(); } From 1ce3e7f5b999e95829205c4c2f93b7df00716194 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 30 Nov 2015 07:32:42 -0800 Subject: [PATCH 2660/3725] Use a separate type for streams They're basically the same, but it's to help avoid accidents with passing non- streaming sounds to the stream functions, or vice-versa. --- apps/openmw/mwbase/soundmanager.hpp | 10 +++++---- apps/openmw/mwsound/movieaudiofactory.cpp | 5 +++-- apps/openmw/mwsound/openal_output.cpp | 20 ++++++++--------- apps/openmw/mwsound/openal_output.hpp | 16 +++++++------- apps/openmw/mwsound/sound.hpp | 15 ++++++++++--- apps/openmw/mwsound/sound_output.hpp | 14 ++++++------ apps/openmw/mwsound/soundmanagerimp.cpp | 26 +++++++++++------------ apps/openmw/mwsound/soundmanagerimp.hpp | 12 +++++------ 8 files changed, 65 insertions(+), 53 deletions(-) diff --git a/apps/openmw/mwbase/soundmanager.hpp b/apps/openmw/mwbase/soundmanager.hpp index e75949a5b..46f245c46 100644 --- a/apps/openmw/mwbase/soundmanager.hpp +++ b/apps/openmw/mwbase/soundmanager.hpp @@ -15,6 +15,7 @@ namespace MWWorld namespace MWSound { class Sound; + class Stream; struct Sound_Decoder; typedef boost::shared_ptr DecoderPtr; } @@ -22,6 +23,7 @@ namespace MWSound namespace MWBase { typedef boost::shared_ptr SoundPtr; + typedef boost::shared_ptr SoundStreamPtr; /// \brief Interface for sound manager (implemented in MWSound) class SoundManager @@ -104,13 +106,13 @@ namespace MWBase /// and get an average loudness value (scale [0,1]) at the current time position. /// If the actor is not saying anything, returns 0. - virtual SoundPtr playTrack(const MWSound::DecoderPtr& decoder, PlayType type) = 0; + virtual SoundStreamPtr playTrack(const MWSound::DecoderPtr& decoder, PlayType type) = 0; ///< Play a 2D audio track, using a custom decoder - virtual void stopTrack(SoundPtr sound) = 0; + virtual void stopTrack(SoundStreamPtr stream) = 0; ///< Stop the given audio track from playing - virtual double getTrackTimeDelay(SoundPtr sound) = 0; + virtual double getTrackTimeDelay(SoundStreamPtr stream) = 0; ///< Retives the time delay, in seconds, of the audio track (must be a sound /// returned by \ref playTrack). Only intended to be called by the track /// decoder's read method. @@ -166,7 +168,7 @@ namespace MWBase virtual void setListenerPosDir(const osg::Vec3f &pos, const osg::Vec3f &dir, const osg::Vec3f &up) = 0; - virtual void updatePtr (const MWWorld::Ptr& old, const MWWorld::Ptr& updated) = 0; + virtual void updatePtr(const MWWorld::Ptr& old, const MWWorld::Ptr& updated) = 0; virtual void clear() = 0; }; diff --git a/apps/openmw/mwsound/movieaudiofactory.cpp b/apps/openmw/mwsound/movieaudiofactory.cpp index 1f7b8a515..554b62d26 100644 --- a/apps/openmw/mwsound/movieaudiofactory.cpp +++ b/apps/openmw/mwsound/movieaudiofactory.cpp @@ -92,7 +92,7 @@ namespace MWSound mDecoderBridge.reset(); } - MWBase::SoundPtr mAudioTrack; + MWBase::SoundStreamPtr mAudioTrack; boost::shared_ptr mDecoderBridge; }; @@ -163,7 +163,8 @@ namespace MWSound boost::shared_ptr decoder(new MWSound::MovieAudioDecoder(videoState)); decoder->setupFormat(); - MWBase::SoundPtr sound = MWBase::Environment::get().getSoundManager()->playTrack(decoder->mDecoderBridge, MWBase::SoundManager::Play_TypeMovie); + MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); + MWBase::SoundStreamPtr sound = sndMgr->playTrack(decoder->mDecoderBridge, MWBase::SoundManager::Play_TypeMovie); if (!sound.get()) { decoder.reset(); diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 3607f71a4..5757e92cf 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -776,9 +776,9 @@ bool OpenAL_Output::isSoundPlaying(MWBase::SoundPtr sound) } -MWBase::SoundPtr OpenAL_Output::streamSound(DecoderPtr decoder, float basevol, float pitch, int flags) +MWBase::SoundStreamPtr OpenAL_Output::streamSound(DecoderPtr decoder, float basevol, float pitch, int flags) { - boost::shared_ptr sound; + MWBase::SoundStreamPtr sound; OpenAL_SoundStream *stream = 0; ALuint source; @@ -810,7 +810,7 @@ MWBase::SoundPtr OpenAL_Output::streamSound(DecoderPtr decoder, float basevol, f alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f); throwALerror(); - sound.reset(new Sound(osg::Vec3f(0.0f, 0.0f, 0.0f), 1.0f, basevol, pitch, 1.0f, 1000.0f, flags)); + sound.reset(new Stream(osg::Vec3f(0.0f, 0.0f, 0.0f), 1.0f, basevol, pitch, 1.0f, 1000.0f, flags)); stream = new OpenAL_SoundStream(source, decoder); mStreamThread->add(stream); sound->mHandle = stream; @@ -826,9 +826,9 @@ MWBase::SoundPtr OpenAL_Output::streamSound(DecoderPtr decoder, float basevol, f return sound; } -MWBase::SoundPtr OpenAL_Output::streamSound3D(DecoderPtr decoder, const osg::Vec3f &pos, float volume, float basevol, float pitch, float mindist, float maxdist, int flags) +MWBase::SoundStreamPtr OpenAL_Output::streamSound3D(DecoderPtr decoder, const osg::Vec3f &pos, float volume, float basevol, float pitch, float mindist, float maxdist, int flags) { - boost::shared_ptr sound; + MWBase::SoundStreamPtr sound; OpenAL_SoundStream *stream = 0; ALuint source; @@ -862,7 +862,7 @@ MWBase::SoundPtr OpenAL_Output::streamSound3D(DecoderPtr decoder, const osg::Vec alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f); throwALerror(); - sound.reset(new Sound(pos, volume, basevol, pitch, mindist, maxdist, flags)); + sound.reset(new Stream(pos, volume, basevol, pitch, mindist, maxdist, flags)); stream = new OpenAL_SoundStream(source, decoder); mStreamThread->add(stream); sound->mHandle = stream; @@ -878,7 +878,7 @@ MWBase::SoundPtr OpenAL_Output::streamSound3D(DecoderPtr decoder, const osg::Vec return sound; } -void OpenAL_Output::stopStream(MWBase::SoundPtr sound) +void OpenAL_Output::stopStream(MWBase::SoundStreamPtr sound) { if(!sound->mHandle) return; @@ -897,7 +897,7 @@ void OpenAL_Output::stopStream(MWBase::SoundPtr sound) delete stream; } -double OpenAL_Output::getStreamDelay(MWBase::SoundPtr sound) +double OpenAL_Output::getStreamDelay(MWBase::SoundStreamPtr sound) { if(!sound->mHandle) return 0.0; @@ -905,7 +905,7 @@ double OpenAL_Output::getStreamDelay(MWBase::SoundPtr sound) return stream->getStreamDelay(); } -double OpenAL_Output::getStreamOffset(MWBase::SoundPtr sound) +double OpenAL_Output::getStreamOffset(MWBase::SoundStreamPtr sound) { if(!sound->mHandle) return 0.0; @@ -914,7 +914,7 @@ double OpenAL_Output::getStreamOffset(MWBase::SoundPtr sound) return stream->getStreamOffset(); } -bool OpenAL_Output::isStreamPlaying(MWBase::SoundPtr sound) +bool OpenAL_Output::isStreamPlaying(MWBase::SoundStreamPtr sound) { if(!sound->mHandle) return false; diff --git a/apps/openmw/mwsound/openal_output.hpp b/apps/openmw/mwsound/openal_output.hpp index b7c3603c6..0c074b126 100644 --- a/apps/openmw/mwsound/openal_output.hpp +++ b/apps/openmw/mwsound/openal_output.hpp @@ -26,7 +26,7 @@ namespace MWSound typedef std::vector SoundVec; SoundVec mActiveSounds; - typedef std::vector StreamVec; + typedef std::vector StreamVec; StreamVec mActiveStreams; Environment mLastEnvironment; @@ -45,13 +45,13 @@ namespace MWSound virtual void stopSound(MWBase::SoundPtr sound); virtual bool isSoundPlaying(MWBase::SoundPtr sound); - virtual MWBase::SoundPtr streamSound(DecoderPtr decoder, float basevol, float pitch, int flags); - virtual MWBase::SoundPtr streamSound3D(DecoderPtr decoder, const osg::Vec3f &pos, - float vol, float basevol, float pitch, float min, float max, int flags); - virtual void stopStream(MWBase::SoundPtr sound); - virtual double getStreamDelay(MWBase::SoundPtr sound); - virtual double getStreamOffset(MWBase::SoundPtr sound); - virtual bool isStreamPlaying(MWBase::SoundPtr sound); + virtual MWBase::SoundStreamPtr streamSound(DecoderPtr decoder, float basevol, float pitch, int flags); + virtual MWBase::SoundStreamPtr streamSound3D(DecoderPtr decoder, const osg::Vec3f &pos, + float vol, float basevol, float pitch, float min, float max, int flags); + virtual void stopStream(MWBase::SoundStreamPtr sound); + virtual double getStreamDelay(MWBase::SoundStreamPtr sound); + virtual double getStreamOffset(MWBase::SoundStreamPtr sound); + virtual bool isStreamPlaying(MWBase::SoundStreamPtr sound); virtual void startUpdate(); virtual void finishUpdate(); diff --git a/apps/openmw/mwsound/sound.hpp b/apps/openmw/mwsound/sound.hpp index f467ba121..b76e4d6eb 100644 --- a/apps/openmw/mwsound/sound.hpp +++ b/apps/openmw/mwsound/sound.hpp @@ -5,8 +5,7 @@ namespace MWSound { - class Sound - { + class Sound { Sound& operator=(const Sound &rhs); Sound(const Sound &rhs); @@ -51,7 +50,17 @@ namespace MWSound , mMinDistance(mindist), mMaxDistance(maxdist), mFlags(flags) , mFadeOutTime(0.0f), mHandle(0) { } - ~Sound() { } + }; + + // Same as above, but it's a different type since the output handles them differently + class Stream : public Sound { + Stream& operator=(const Stream &rhs); + Stream(const Stream &rhs); + + public: + Stream(const osg::Vec3f& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags) + : Sound(pos, vol, basevol, pitch, mindist, maxdist, flags) + { } }; } diff --git a/apps/openmw/mwsound/sound_output.hpp b/apps/openmw/mwsound/sound_output.hpp index bdf40bf44..061fcdf07 100644 --- a/apps/openmw/mwsound/sound_output.hpp +++ b/apps/openmw/mwsound/sound_output.hpp @@ -38,13 +38,13 @@ namespace MWSound virtual void stopSound(MWBase::SoundPtr sound) = 0; virtual bool isSoundPlaying(MWBase::SoundPtr sound) = 0; - virtual MWBase::SoundPtr streamSound(DecoderPtr decoder, float basevol, float pitch, int flags) = 0; - virtual MWBase::SoundPtr streamSound3D(DecoderPtr decoder, const osg::Vec3f &pos, - float vol, float basevol, float pitch, float min, float max, int flags) = 0; - virtual void stopStream(MWBase::SoundPtr sound) = 0; - virtual double getStreamDelay(MWBase::SoundPtr sound) = 0; - virtual double getStreamOffset(MWBase::SoundPtr sound) = 0; - virtual bool isStreamPlaying(MWBase::SoundPtr sound) = 0; + virtual MWBase::SoundStreamPtr streamSound(DecoderPtr decoder, float basevol, float pitch, int flags) = 0; + virtual MWBase::SoundStreamPtr streamSound3D(DecoderPtr decoder, const osg::Vec3f &pos, + float vol, float basevol, float pitch, float min, float max, int flags) = 0; + virtual void stopStream(MWBase::SoundStreamPtr sound) = 0; + virtual double getStreamDelay(MWBase::SoundStreamPtr sound) = 0; + virtual double getStreamOffset(MWBase::SoundStreamPtr sound) = 0; + virtual bool isStreamPlaying(MWBase::SoundStreamPtr sound) = 0; virtual void startUpdate() = 0; virtual void finishUpdate() = 0; diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 82dd49f32..c40d2cd3e 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -241,7 +241,7 @@ namespace MWSound return decoder; } - MWBase::SoundPtr SoundManager::playVoice(DecoderPtr decoder, const osg::Vec3f &pos, bool playlocal) + MWBase::SoundStreamPtr SoundManager::playVoice(DecoderPtr decoder, const osg::Vec3f &pos, bool playlocal) { MWBase::World* world = MWBase::Environment::get().getWorld(); static const float fAudioMinDistanceMult = world->getStore().get().find("fAudioMinDistanceMult")->getFloat(); @@ -392,7 +392,7 @@ namespace MWSound mPendingSaySounds[ptr] = std::make_pair(decoder, loudness); else { - MWBase::SoundPtr sound = playVoice(decoder, objpos, (ptr == MWMechanics::getPlayer())); + MWBase::SoundStreamPtr sound = playVoice(decoder, objpos, (ptr == MWMechanics::getPlayer())); mActiveSaySounds[ptr] = std::make_pair(sound, loudness); } } @@ -407,7 +407,7 @@ namespace MWSound SaySoundMap::const_iterator snditer = mActiveSaySounds.find(ptr); if(snditer != mActiveSaySounds.end()) { - MWBase::SoundPtr sound = snditer->second.first; + MWBase::SoundStreamPtr sound = snditer->second.first; Sound_Loudness *loudness = snditer->second.second; float sec = mOutput->getStreamOffset(sound); return loudness->getLoudnessAtTime(sec); @@ -432,7 +432,7 @@ namespace MWSound mPendingSaySounds[MWWorld::Ptr()] = std::make_pair(decoder, loudness); else { - MWBase::SoundPtr sound = playVoice(decoder, osg::Vec3f(), true); + MWBase::SoundStreamPtr sound = playVoice(decoder, osg::Vec3f(), true); mActiveSaySounds[MWWorld::Ptr()] = std::make_pair(sound, loudness); } } @@ -466,9 +466,9 @@ namespace MWSound } - MWBase::SoundPtr SoundManager::playTrack(const DecoderPtr& decoder, PlayType type) + MWBase::SoundStreamPtr SoundManager::playTrack(const DecoderPtr& decoder, PlayType type) { - MWBase::SoundPtr track; + MWBase::SoundStreamPtr track; if(!mOutput->isInitialized()) return track; try @@ -482,14 +482,14 @@ namespace MWSound return track; } - void SoundManager::stopTrack(MWBase::SoundPtr sound) + void SoundManager::stopTrack(MWBase::SoundStreamPtr stream) { - mOutput->stopStream(sound); + mOutput->stopStream(stream); } - double SoundManager::getTrackTimeDelay(MWBase::SoundPtr sound) + double SoundManager::getTrackTimeDelay(MWBase::SoundStreamPtr stream) { - return mOutput->getStreamDelay(sound); + return mOutput->getStreamDelay(stream); } @@ -876,7 +876,7 @@ namespace MWSound const ESM::Position &pos = ptr.getRefData().getPosition(); const osg::Vec3f objpos(pos.asVec3()); - MWBase::SoundPtr sound = playVoice(decoder, + MWBase::SoundStreamPtr sound = playVoice(decoder, objpos, (ptr == MWMechanics::getPlayer()) ); mActiveSaySounds[ptr] = std::make_pair(sound, loudness); @@ -895,7 +895,7 @@ namespace MWSound while(sayiter != mActiveSaySounds.end()) { MWWorld::Ptr ptr = sayiter->first; - MWBase::SoundPtr sound = sayiter->second.first; + MWBase::SoundStreamPtr sound = sayiter->second.first; if(!ptr.isEmpty() && sound->getIs3D()) { const ESM::Position &pos = ptr.getRefData().getPosition(); @@ -963,7 +963,7 @@ namespace MWSound SaySoundMap::iterator sayiter = mActiveSaySounds.begin(); for(;sayiter != mActiveSaySounds.end();++sayiter) { - MWBase::SoundPtr sound = sayiter->second.first; + MWBase::SoundStreamPtr sound = sayiter->second.first; sound->setBaseVolume(volumeFromType(sound->getPlayType())); } if(mMusic) diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index 5f4cf6ebc..e0214e091 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -79,7 +79,7 @@ namespace MWSound typedef std::deque SoundList; SoundList mUnusedBuffers; - boost::shared_ptr mMusic; + MWBase::SoundStreamPtr mMusic; std::string mCurrentPlaylist; typedef std::pair SoundBufferRefPair; @@ -87,7 +87,7 @@ namespace MWSound typedef std::map SoundMap; SoundMap mActiveSounds; - typedef std::pair SoundLoudnessPair; + typedef std::pair SoundLoudnessPair; typedef std::map SaySoundMap; SaySoundMap mActiveSaySounds; @@ -113,7 +113,7 @@ namespace MWSound // to start streaming DecoderPtr loadVoice(const std::string &voicefile, Sound_Loudness **lipdata); - MWBase::SoundPtr playVoice(DecoderPtr decoder, const osg::Vec3f &pos, bool playlocal); + MWBase::SoundStreamPtr playVoice(DecoderPtr decoder, const osg::Vec3f &pos, bool playlocal); void streamMusicFull(const std::string& filename); void updateSounds(float duration); @@ -170,13 +170,13 @@ namespace MWSound /// and get an average loudness value (scale [0,1]) at the current time position. /// If the actor is not saying anything, returns 0. - virtual MWBase::SoundPtr playTrack(const DecoderPtr& decoder, PlayType type); + virtual MWBase::SoundStreamPtr playTrack(const DecoderPtr& decoder, PlayType type); ///< Play a 2D audio track, using a custom decoder - virtual void stopTrack(MWBase::SoundPtr sound); + virtual void stopTrack(MWBase::SoundStreamPtr stream); ///< Stop the given audio track from playing - virtual double getTrackTimeDelay(MWBase::SoundPtr sound); + virtual double getTrackTimeDelay(MWBase::SoundStreamPtr stream); ///< Retives the time delay, in seconds, of the audio track (must be a sound /// returned by \ref playTrack). Only intended to be called by the track /// decoder's read method. From 4bd235284b20c7dd7728ee31cb258391ddcc14e2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 30 Nov 2015 08:00:02 -0800 Subject: [PATCH 2661/3725] Rename a couple members to avoid confusion --- apps/openmw/mwsound/openal_output.cpp | 25 +++++++++++++------------ apps/openmw/mwsound/openal_output.hpp | 22 +++++++++------------- apps/openmw/mwsound/sound_output.hpp | 5 +---- 3 files changed, 23 insertions(+), 29 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 5757e92cf..3d5a97095 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -666,7 +666,7 @@ MWBase::SoundPtr OpenAL_Output::playSound(Sound_Handle data, float vol, float ba alSourcei(source, AL_LOOPING, (flags&MWBase::SoundManager::Play_Loop) ? AL_TRUE : AL_FALSE); ALfloat gain = vol*basevol; - if(!(flags&MWBase::SoundManager::Play_NoEnv) && mLastEnvironment == Env_Underwater) + if(!(flags&MWBase::SoundManager::Play_NoEnv) && mListenerEnv == Env_Underwater) { gain *= 0.9f; pitch *= 0.7f; @@ -715,9 +715,9 @@ MWBase::SoundPtr OpenAL_Output::playSound3D(Sound_Handle data, const osg::Vec3f alSourcei(source, AL_LOOPING, (flags&MWBase::SoundManager::Play_Loop) ? AL_TRUE : AL_FALSE); ALfloat gain = vol*basevol; - if((pos - mPos).length2() > maxdist*maxdist) + if((pos - mListenerPos).length2() > maxdist*maxdist) gain = 0.0f; - if(!(flags&MWBase::SoundManager::Play_NoEnv) && mLastEnvironment == Env_Underwater) + if(!(flags&MWBase::SoundManager::Play_NoEnv) && mListenerEnv == Env_Underwater) { gain *= 0.9f; pitch *= 0.7f; @@ -797,7 +797,7 @@ MWBase::SoundStreamPtr OpenAL_Output::streamSound(DecoderPtr decoder, float base alSourcei(source, AL_LOOPING, AL_FALSE); ALfloat gain = basevol; - if(!(flags&MWBase::SoundManager::Play_NoEnv) && mLastEnvironment == Env_Underwater) + if(!(flags&MWBase::SoundManager::Play_NoEnv) && mListenerEnv == Env_Underwater) { gain *= 0.9f; pitch *= 0.7f; @@ -847,9 +847,9 @@ MWBase::SoundStreamPtr OpenAL_Output::streamSound3D(DecoderPtr decoder, const os alSourcei(source, AL_LOOPING, AL_FALSE); ALfloat gain = volume*basevol; - if((pos - mPos).length2() > maxdist*maxdist) + if((pos - mListenerPos).length2() > maxdist*maxdist) gain = 0.0f; - if(!(flags&MWBase::SoundManager::Play_NoEnv) && mLastEnvironment == Env_Underwater) + if(!(flags&MWBase::SoundManager::Play_NoEnv) && mListenerEnv == Env_Underwater) { gain *= 0.9f; pitch *= 0.7f; @@ -937,19 +937,19 @@ void OpenAL_Output::finishUpdate() void OpenAL_Output::updateListener(const osg::Vec3f &pos, const osg::Vec3f &atdir, const osg::Vec3f &updir, Environment env) { - mPos = pos; - mLastEnvironment = env; - if(mContext) { ALfloat orient[6] = { atdir.x(), atdir.y(), atdir.z(), updir.x(), updir.y(), updir.z() }; - alListener3f(AL_POSITION, mPos.x(), mPos.y(), mPos.z()); + alListenerfv(AL_POSITION, pos.ptr()); alListenerfv(AL_ORIENTATION, orient); throwALerror(); } + + mListenerPos = pos; + mListenerEnv = env; } @@ -1011,8 +1011,9 @@ void OpenAL_Output::loadLoudnessAsync(DecoderPtr decoder, Sound_Loudness *loudne OpenAL_Output::OpenAL_Output(SoundManager &mgr) - : Sound_Output(mgr), mDevice(0), mContext(0), mLastEnvironment(Env_Normal), - mStreamThread(new StreamThread) + : Sound_Output(mgr), mDevice(0), mContext(0) + , mListenerPos(0.0f, 0.0f, 0.0f), mListenerEnv(Env_Normal) + , mStreamThread(new StreamThread) { } diff --git a/apps/openmw/mwsound/openal_output.hpp b/apps/openmw/mwsound/openal_output.hpp index 0c074b126..c49bd3dbb 100644 --- a/apps/openmw/mwsound/openal_output.hpp +++ b/apps/openmw/mwsound/openal_output.hpp @@ -29,8 +29,16 @@ namespace MWSound typedef std::vector StreamVec; StreamVec mActiveStreams; - Environment mLastEnvironment; + osg::Vec3f mListenerPos; + Environment mListenerEnv; + struct StreamThread; + std::auto_ptr mStreamThread; + + OpenAL_Output& operator=(const OpenAL_Output &rhs); + OpenAL_Output(const OpenAL_Output &rhs); + + public: virtual std::vector enumerate(); virtual void init(const std::string &devname=""); virtual void deinit(); @@ -63,20 +71,8 @@ namespace MWSound virtual void loadLoudnessAsync(DecoderPtr decoder, Sound_Loudness *loudness); - OpenAL_Output& operator=(const OpenAL_Output &rhs); - OpenAL_Output(const OpenAL_Output &rhs); - OpenAL_Output(SoundManager &mgr); virtual ~OpenAL_Output(); - - struct StreamThread; - std::auto_ptr mStreamThread; - - friend class OpenAL_Sound; - friend class OpenAL_Sound3D; - friend class OpenAL_SoundStream; - friend class OpenAL_SoundStream3D; - friend class SoundManager; }; #ifndef DEFAULT_OUTPUT #define DEFAULT_OUTPUT(x) ::MWSound::OpenAL_Output((x)) diff --git a/apps/openmw/mwsound/sound_output.hpp b/apps/openmw/mwsound/sound_output.hpp index 061fcdf07..fcb992f58 100644 --- a/apps/openmw/mwsound/sound_output.hpp +++ b/apps/openmw/mwsound/sound_output.hpp @@ -64,12 +64,9 @@ namespace MWSound protected: bool mInitialized; - osg::Vec3f mPos; Sound_Output(SoundManager &mgr) - : mManager(mgr) - , mInitialized(false) - , mPos(0.0f, 0.0f, 0.0f) + : mManager(mgr), mInitialized(false) { } public: virtual ~Sound_Output() { } From a6db96b2d8defa2bd8c683438663625cd28058c2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 30 Nov 2015 14:34:14 -0800 Subject: [PATCH 2662/3725] Update sound and stream parameters --- apps/openmw/mwsound/openal_output.cpp | 55 +++++++++++++++++++++++++ apps/openmw/mwsound/openal_output.hpp | 2 + apps/openmw/mwsound/sound.hpp | 6 +++ apps/openmw/mwsound/sound_output.hpp | 2 + apps/openmw/mwsound/soundmanagerimp.cpp | 5 +++ 5 files changed, 70 insertions(+) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 3d5a97095..f93829ae5 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -775,6 +775,33 @@ bool OpenAL_Output::isSoundPlaying(MWBase::SoundPtr sound) return state == AL_PLAYING || state == AL_PAUSED; } +void OpenAL_Output::updateSound(MWBase::SoundPtr sound) +{ + if(!sound->mHandle) return; + ALuint source = GET_PTRID(sound->mHandle); + + const osg::Vec3f &pos = sound->getPosition(); + ALfloat gain = sound->getRealVolume(); + ALfloat pitch = sound->getPitch(); + if(sound->getIs3D()) + { + ALfloat maxdist = sound->getMaxDistance(); + if((pos - mListenerPos).length2() > maxdist*maxdist) + gain = 0.0f; + } + if(sound->getUseEnv() && mListenerEnv == Env_Underwater) + { + gain *= 0.9f; + pitch *= 0.7f; + } + + alSourcef(source, AL_GAIN, gain); + alSourcef(source, AL_PITCH, pitch); + alSourcefv(source, AL_POSITION, pos.ptr()); + alSource3f(source, AL_DIRECTION, 0.0f, 0.0f, 0.0f); + alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f); +} + MWBase::SoundStreamPtr OpenAL_Output::streamSound(DecoderPtr decoder, float basevol, float pitch, int flags) { @@ -923,6 +950,34 @@ bool OpenAL_Output::isStreamPlaying(MWBase::SoundStreamPtr sound) return stream->isPlaying(); } +void OpenAL_Output::updateStream(MWBase::SoundStreamPtr sound) +{ + if(!sound->mHandle) return; + OpenAL_SoundStream *stream = reinterpret_cast(sound->mHandle); + ALuint source = stream->mSource; + + const osg::Vec3f &pos = sound->getPosition(); + ALfloat gain = sound->getRealVolume(); + ALfloat pitch = sound->getPitch(); + if(sound->getIs3D()) + { + ALfloat maxdist = sound->getMaxDistance(); + if((pos - mListenerPos).length2() > maxdist*maxdist) + gain = 0.0f; + } + if(sound->getUseEnv() && mListenerEnv == Env_Underwater) + { + gain *= 0.9f; + pitch *= 0.7f; + } + + alSourcef(source, AL_GAIN, gain); + alSourcef(source, AL_PITCH, pitch); + alSourcefv(source, AL_POSITION, pos.ptr()); + alSource3f(source, AL_DIRECTION, 0.0f, 0.0f, 0.0f); + alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f); +} + void OpenAL_Output::startUpdate() { diff --git a/apps/openmw/mwsound/openal_output.hpp b/apps/openmw/mwsound/openal_output.hpp index c49bd3dbb..24b9c855f 100644 --- a/apps/openmw/mwsound/openal_output.hpp +++ b/apps/openmw/mwsound/openal_output.hpp @@ -52,6 +52,7 @@ namespace MWSound float vol, float basevol, float pitch, float min, float max, int flags, float offset); virtual void stopSound(MWBase::SoundPtr sound); virtual bool isSoundPlaying(MWBase::SoundPtr sound); + virtual void updateSound(MWBase::SoundPtr sound); virtual MWBase::SoundStreamPtr streamSound(DecoderPtr decoder, float basevol, float pitch, int flags); virtual MWBase::SoundStreamPtr streamSound3D(DecoderPtr decoder, const osg::Vec3f &pos, @@ -60,6 +61,7 @@ namespace MWSound virtual double getStreamDelay(MWBase::SoundStreamPtr sound); virtual double getStreamOffset(MWBase::SoundStreamPtr sound); virtual bool isStreamPlaying(MWBase::SoundStreamPtr sound); + virtual void updateStream(MWBase::SoundStreamPtr sound); virtual void startUpdate(); virtual void finishUpdate(); diff --git a/apps/openmw/mwsound/sound.hpp b/apps/openmw/mwsound/sound.hpp index b76e4d6eb..ec55db580 100644 --- a/apps/openmw/mwsound/sound.hpp +++ b/apps/openmw/mwsound/sound.hpp @@ -40,8 +40,14 @@ namespace MWSound } } + const osg::Vec3f &getPosition() const { return mPos; } + float getRealVolume() const { return mVolume * mBaseVolume; } + float getPitch() const { return mPitch; } + float getMaxDistance() const { return mMaxDistance; } + MWBase::SoundManager::PlayType getPlayType() const { return (MWBase::SoundManager::PlayType)(mFlags&MWBase::SoundManager::Play_TypeMask); } + bool getUseEnv() const { return !(mFlags&MWBase::SoundManager::Play_NoEnv); } bool getDistanceCull() const { return mFlags&MWBase::SoundManager::Play_RemoveAtDistance; } bool getIs3D() const { return mFlags&Play_3D; } diff --git a/apps/openmw/mwsound/sound_output.hpp b/apps/openmw/mwsound/sound_output.hpp index fcb992f58..9cc02160b 100644 --- a/apps/openmw/mwsound/sound_output.hpp +++ b/apps/openmw/mwsound/sound_output.hpp @@ -37,6 +37,7 @@ namespace MWSound float vol, float basevol, float pitch, float min, float max, int flags, float offset) = 0; virtual void stopSound(MWBase::SoundPtr sound) = 0; virtual bool isSoundPlaying(MWBase::SoundPtr sound) = 0; + virtual void updateSound(MWBase::SoundPtr sound) = 0; virtual MWBase::SoundStreamPtr streamSound(DecoderPtr decoder, float basevol, float pitch, int flags) = 0; virtual MWBase::SoundStreamPtr streamSound3D(DecoderPtr decoder, const osg::Vec3f &pos, @@ -45,6 +46,7 @@ namespace MWSound virtual double getStreamDelay(MWBase::SoundStreamPtr sound) = 0; virtual double getStreamOffset(MWBase::SoundStreamPtr sound) = 0; virtual bool isStreamPlaying(MWBase::SoundStreamPtr sound) = 0; + virtual void updateStream(MWBase::SoundStreamPtr sound) = 0; virtual void startUpdate() = 0; virtual void finishUpdate() = 0; diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index c40d2cd3e..0263c5751 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -853,6 +853,7 @@ namespace MWSound { sound->updateFade(duration); + mOutput->updateSound(sound); ++sndidx; } } @@ -918,6 +919,7 @@ namespace MWSound { sound->updateFade(duration); + mOutput->updateStream(sound); ++sayiter; } } @@ -958,6 +960,7 @@ namespace MWSound { MWBase::SoundPtr sound = sndidx->first; sound->setBaseVolume(volumeFromType(sound->getPlayType())); + mOutput->updateSound(sound); } } SaySoundMap::iterator sayiter = mActiveSaySounds.begin(); @@ -965,10 +968,12 @@ namespace MWSound { MWBase::SoundStreamPtr sound = sayiter->second.first; sound->setBaseVolume(volumeFromType(sound->getPlayType())); + mOutput->updateStream(sound); } if(mMusic) { mMusic->setBaseVolume(volumeFromType(mMusic->getPlayType())); + mOutput->updateStream(mMusic); } mOutput->finishUpdate(); } From 2883cdba5c6b3b55e35ec0b127ce5098108ce591 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 30 Nov 2015 14:51:41 -0800 Subject: [PATCH 2663/3725] Initialize the Sound object before modifying the pitch variable --- apps/openmw/mwsound/openal_output.cpp | 12 ++++++++---- apps/openmw/mwsound/sound.hpp | 8 ++++++++ 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index f93829ae5..552e5bc28 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -659,6 +659,8 @@ MWBase::SoundPtr OpenAL_Output::playSound(Sound_Handle data, float vol, float ba mFreeSources.pop_front(); try { + sound.reset(new Sound(vol, basevol, pitch, flags)); + alSourcef(source, AL_REFERENCE_DISTANCE, 1.0f); alSourcef(source, AL_MAX_DISTANCE, 1000.0f); alSourcef(source, AL_ROLLOFF_FACTOR, 0.0f); @@ -684,7 +686,6 @@ MWBase::SoundPtr OpenAL_Output::playSound(Sound_Handle data, float vol, float ba alSourcePlay(source); throwALerror(); - sound.reset(new Sound(osg::Vec3f(0.f, 0.f, 0.f), vol, basevol, pitch, 1.0f, 1000.0f, flags)); sound->mHandle = MAKE_PTRID(source); mActiveSounds.push_back(sound); } @@ -708,6 +709,8 @@ MWBase::SoundPtr OpenAL_Output::playSound3D(Sound_Handle data, const osg::Vec3f mFreeSources.pop_front(); try { + sound.reset(new Sound(pos, vol, basevol, pitch, mindist, maxdist, flags)); + alSourcef(source, AL_REFERENCE_DISTANCE, mindist); alSourcef(source, AL_MAX_DISTANCE, maxdist); alSourcef(source, AL_ROLLOFF_FACTOR, 1.0f); @@ -735,7 +738,6 @@ MWBase::SoundPtr OpenAL_Output::playSound3D(Sound_Handle data, const osg::Vec3f alSourcePlay(source); throwALerror(); - sound.reset(new Sound(pos, vol, basevol, pitch, mindist, maxdist, flags)); sound->mHandle = MAKE_PTRID(source); mActiveSounds.push_back(sound); } @@ -817,6 +819,8 @@ MWBase::SoundStreamPtr OpenAL_Output::streamSound(DecoderPtr decoder, float base if((flags&MWBase::SoundManager::Play_Loop)) std::cout <<"Warning: cannot loop stream \""<getName()<<"\""<< std::endl; try { + sound.reset(new Stream(1.0f, basevol, pitch, flags)); + alSourcef(source, AL_REFERENCE_DISTANCE, 1.0f); alSourcef(source, AL_MAX_DISTANCE, 1000.0f); alSourcef(source, AL_ROLLOFF_FACTOR, 0.0f); @@ -837,7 +841,6 @@ MWBase::SoundStreamPtr OpenAL_Output::streamSound(DecoderPtr decoder, float base alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f); throwALerror(); - sound.reset(new Stream(osg::Vec3f(0.0f, 0.0f, 0.0f), 1.0f, basevol, pitch, 1.0f, 1000.0f, flags)); stream = new OpenAL_SoundStream(source, decoder); mStreamThread->add(stream); sound->mHandle = stream; @@ -867,6 +870,8 @@ MWBase::SoundStreamPtr OpenAL_Output::streamSound3D(DecoderPtr decoder, const os if((flags&MWBase::SoundManager::Play_Loop)) std::cout <<"Warning: cannot loop stream \""<getName()<<"\""<< std::endl; try { + sound.reset(new Stream(pos, volume, basevol, pitch, mindist, maxdist, flags)); + alSourcef(source, AL_REFERENCE_DISTANCE, mindist); alSourcef(source, AL_MAX_DISTANCE, maxdist); alSourcef(source, AL_ROLLOFF_FACTOR, 1.0f); @@ -889,7 +894,6 @@ MWBase::SoundStreamPtr OpenAL_Output::streamSound3D(DecoderPtr decoder, const os alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f); throwALerror(); - sound.reset(new Stream(pos, volume, basevol, pitch, mindist, maxdist, flags)); stream = new OpenAL_SoundStream(source, decoder); mStreamThread->add(stream); sound->mHandle = stream; diff --git a/apps/openmw/mwsound/sound.hpp b/apps/openmw/mwsound/sound.hpp index ec55db580..0ae465cfb 100644 --- a/apps/openmw/mwsound/sound.hpp +++ b/apps/openmw/mwsound/sound.hpp @@ -56,6 +56,11 @@ namespace MWSound , mMinDistance(mindist), mMaxDistance(maxdist), mFlags(flags) , mFadeOutTime(0.0f), mHandle(0) { } + Sound(float vol, float basevol, float pitch, int flags) + : mPos(0.0f, 0.0f, 0.0f), mVolume(vol), mBaseVolume(basevol), mPitch(pitch) + , mMinDistance(1.0f), mMaxDistance(1000.0f), mFlags(flags) + , mFadeOutTime(0.0f), mHandle(0) + { } }; // Same as above, but it's a different type since the output handles them differently @@ -67,6 +72,9 @@ namespace MWSound Stream(const osg::Vec3f& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags) : Sound(pos, vol, basevol, pitch, mindist, maxdist, flags) { } + Stream(float vol, float basevol, float pitch, int flags) + : Sound(vol, basevol, pitch, flags) + { } }; } From 3a39a92b93e2ab3989d6e835c581f05b5fc7c4f1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 1 Dec 2015 11:28:37 -0800 Subject: [PATCH 2664/3725] Keep track of audio tracks --- apps/openmw/mwsound/soundmanagerimp.cpp | 34 +++++++++++++++++++++++++ apps/openmw/mwsound/soundmanagerimp.hpp | 11 +++++--- 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 0263c5751..157426564 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -474,6 +474,8 @@ namespace MWSound try { track = mOutput->streamSound(decoder, volumeFromType(type), 1.0f, Play_NoEnv|type); + TrackList::iterator iter = std::lower_bound(mActiveTracks.begin(), mActiveTracks.end(), track); + mActiveTracks.insert(iter, track); } catch(std::exception &e) { @@ -485,6 +487,9 @@ namespace MWSound void SoundManager::stopTrack(MWBase::SoundStreamPtr stream) { mOutput->stopStream(stream); + TrackList::iterator iter = std::lower_bound(mActiveTracks.begin(), mActiveTracks.end(), stream); + if(iter != mActiveTracks.end() && *iter == stream) + mActiveTracks.erase(iter); } double SoundManager::getTrackTimeDelay(MWBase::SoundStreamPtr stream) @@ -923,6 +928,24 @@ namespace MWSound ++sayiter; } } + + TrackList::iterator trkiter = mActiveTracks.begin(); + for(;trkiter != mActiveTracks.end();++trkiter) + { + MWBase::SoundStreamPtr sound = *trkiter; + if(!mOutput->isStreamPlaying(sound)) + { + mOutput->stopStream(sound); + trkiter = mActiveTracks.erase(trkiter); + } + else + { + sound->updateFade(duration); + + mOutput->updateStream(sound); + ++trkiter; + } + } mOutput->finishUpdate(); } @@ -970,6 +993,13 @@ namespace MWSound sound->setBaseVolume(volumeFromType(sound->getPlayType())); mOutput->updateStream(sound); } + TrackList::iterator trkiter = mActiveTracks.begin(); + for(;trkiter != mActiveTracks.end();++trkiter) + { + MWBase::SoundStreamPtr sound = *trkiter; + sound->setBaseVolume(volumeFromType(sound->getPlayType())); + mOutput->updateStream(sound); + } if(mMusic) { mMusic->setBaseVolume(volumeFromType(mMusic->getPlayType())); @@ -1099,6 +1129,10 @@ namespace MWSound for(;sayiter != mActiveSaySounds.end();++sayiter) mOutput->stopStream(sayiter->second.first); mActiveSaySounds.clear(); + TrackList::iterator trkiter = mActiveTracks.begin(); + for(;trkiter != mActiveTracks.end();++trkiter) + mOutput->stopStream(*trkiter); + mActiveTracks.clear(); mPendingSaySounds.clear(); mUnderwaterSound.reset(); stopMusic(); diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index e0214e091..8ec46bd73 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -79,9 +79,6 @@ namespace MWSound typedef std::deque SoundList; SoundList mUnusedBuffers; - MWBase::SoundStreamPtr mMusic; - std::string mCurrentPlaylist; - typedef std::pair SoundBufferRefPair; typedef std::vector SoundBufferRefPairList; typedef std::map SoundMap; @@ -95,7 +92,11 @@ namespace MWSound typedef std::map SayDecoderMap; SayDecoderMap mPendingSaySounds; - MWBase::SoundPtr mUnderwaterSound; + typedef std::vector TrackList; + TrackList mActiveTracks; + + MWBase::SoundStreamPtr mMusic; + std::string mCurrentPlaylist; bool mListenerUnderwater; osg::Vec3f mListenerPos; @@ -104,6 +105,8 @@ namespace MWSound int mPausedSoundTypes; + MWBase::SoundPtr mUnderwaterSound; + Sound_Buffer *insertSound(const std::string &soundId, const ESM::Sound *sound); Sound_Buffer *lookupSound(const std::string &soundId) const; From 53718a5ca00f95150f1c0700efa949d19d83410a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 2 Dec 2015 05:18:43 -0800 Subject: [PATCH 2665/3725] Use a typedef for the sound instance handle --- apps/openmw/mwsound/sound.hpp | 4 ++-- apps/openmw/mwsound/sound_output.hpp | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwsound/sound.hpp b/apps/openmw/mwsound/sound.hpp index 0ae465cfb..878384b43 100644 --- a/apps/openmw/mwsound/sound.hpp +++ b/apps/openmw/mwsound/sound.hpp @@ -1,7 +1,7 @@ #ifndef GAME_SOUND_SOUND_H #define GAME_SOUND_SOUND_H -#include "soundmanagerimp.hpp" +#include "sound_output.hpp" namespace MWSound { @@ -20,7 +20,7 @@ namespace MWSound float mFadeOutTime; protected: - void *mHandle; + Sound_Instance mHandle; friend class Sound_Output; friend class OpenAL_Output; diff --git a/apps/openmw/mwsound/sound_output.hpp b/apps/openmw/mwsound/sound_output.hpp index 9cc02160b..d879dbf44 100644 --- a/apps/openmw/mwsound/sound_output.hpp +++ b/apps/openmw/mwsound/sound_output.hpp @@ -3,11 +3,10 @@ #include #include +#include #include "soundmanagerimp.hpp" -#include "../mwworld/ptr.hpp" - namespace MWSound { class SoundManager; @@ -17,6 +16,8 @@ namespace MWSound // An opaque handle for the implementation's sound buffers. typedef void *Sound_Handle; + // An opaque handle for the implementation's sound instances. + typedef void *Sound_Instance; class Sound_Output { From 2ee3265b66466786d81d6c7c124dc1cc2421d359 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 2 Dec 2015 06:35:35 -0800 Subject: [PATCH 2666/3725] Use a premade Sound object for the output's playSound functions --- apps/openmw/mwsound/openal_output.cpp | 62 +++++++++++-------------- apps/openmw/mwsound/openal_output.hpp | 5 +- apps/openmw/mwsound/sound.hpp | 3 +- apps/openmw/mwsound/sound_output.hpp | 7 +-- apps/openmw/mwsound/soundmanagerimp.cpp | 31 +++++++------ 5 files changed, 49 insertions(+), 59 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 552e5bc28..8932c1b55 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -648,9 +648,8 @@ size_t OpenAL_Output::getSoundDataSize(Sound_Handle data) const } -MWBase::SoundPtr OpenAL_Output::playSound(Sound_Handle data, float vol, float basevol, float pitch, int flags, float offset) +void OpenAL_Output::playSound(MWBase::SoundPtr sound, Sound_Handle data, float offset) { - boost::shared_ptr sound; ALuint source; if(mFreeSources.empty()) @@ -659,16 +658,15 @@ MWBase::SoundPtr OpenAL_Output::playSound(Sound_Handle data, float vol, float ba mFreeSources.pop_front(); try { - sound.reset(new Sound(vol, basevol, pitch, flags)); - alSourcef(source, AL_REFERENCE_DISTANCE, 1.0f); alSourcef(source, AL_MAX_DISTANCE, 1000.0f); alSourcef(source, AL_ROLLOFF_FACTOR, 0.0f); alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE); - alSourcei(source, AL_LOOPING, (flags&MWBase::SoundManager::Play_Loop) ? AL_TRUE : AL_FALSE); + alSourcei(source, AL_LOOPING, sound->getIsLooping() ? AL_TRUE : AL_FALSE); - ALfloat gain = vol*basevol; - if(!(flags&MWBase::SoundManager::Play_NoEnv) && mListenerEnv == Env_Underwater) + ALfloat gain = sound->getRealVolume(); + ALfloat pitch = sound->getPitch(); + if(sound->getUseEnv() && mListenerEnv == Env_Underwater) { gain *= 0.9f; pitch *= 0.7f; @@ -681,12 +679,12 @@ MWBase::SoundPtr OpenAL_Output::playSound(Sound_Handle data, float vol, float ba alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f); alSourcef(source, AL_SEC_OFFSET, offset/pitch); - alSourcei(source, AL_BUFFER, GET_PTRID(data)); + throwALerror(); + alSourcei(source, AL_BUFFER, GET_PTRID(data)); alSourcePlay(source); throwALerror(); - sound->mHandle = MAKE_PTRID(source); mActiveSounds.push_back(sound); } catch(std::exception&) { @@ -694,13 +692,11 @@ MWBase::SoundPtr OpenAL_Output::playSound(Sound_Handle data, float vol, float ba throw; } - return sound; + sound->mHandle = MAKE_PTRID(source); } -MWBase::SoundPtr OpenAL_Output::playSound3D(Sound_Handle data, const osg::Vec3f &pos, float vol, float basevol, float pitch, - float mindist, float maxdist, int flags, float offset) +void OpenAL_Output::playSound3D(MWBase::SoundPtr sound, Sound_Handle data, float offset) { - boost::shared_ptr sound; ALuint source; if(mFreeSources.empty()) @@ -709,18 +705,19 @@ MWBase::SoundPtr OpenAL_Output::playSound3D(Sound_Handle data, const osg::Vec3f mFreeSources.pop_front(); try { - sound.reset(new Sound(pos, vol, basevol, pitch, mindist, maxdist, flags)); - - alSourcef(source, AL_REFERENCE_DISTANCE, mindist); - alSourcef(source, AL_MAX_DISTANCE, maxdist); + alSourcef(source, AL_REFERENCE_DISTANCE, sound->getMinDistance()); + alSourcef(source, AL_MAX_DISTANCE, sound->getMaxDistance()); alSourcef(source, AL_ROLLOFF_FACTOR, 1.0f); alSourcei(source, AL_SOURCE_RELATIVE, AL_FALSE); - alSourcei(source, AL_LOOPING, (flags&MWBase::SoundManager::Play_Loop) ? AL_TRUE : AL_FALSE); + alSourcei(source, AL_LOOPING, sound->getIsLooping() ? AL_TRUE : AL_FALSE); - ALfloat gain = vol*basevol; + const osg::Vec3f &pos = sound->getPosition(); + ALfloat maxdist = sound->getMaxDistance(); + ALfloat gain = sound->getRealVolume(); + ALfloat pitch = sound->getPitch(); if((pos - mListenerPos).length2() > maxdist*maxdist) gain = 0.0f; - if(!(flags&MWBase::SoundManager::Play_NoEnv) && mListenerEnv == Env_Underwater) + if(sound->getUseEnv() && mListenerEnv == Env_Underwater) { gain *= 0.9f; pitch *= 0.7f; @@ -733,12 +730,12 @@ MWBase::SoundPtr OpenAL_Output::playSound3D(Sound_Handle data, const osg::Vec3f alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f); alSourcef(source, AL_SEC_OFFSET, offset/pitch); - alSourcei(source, AL_BUFFER, GET_PTRID(data)); + throwALerror(); + alSourcei(source, AL_BUFFER, GET_PTRID(data)); alSourcePlay(source); throwALerror(); - sound->mHandle = MAKE_PTRID(source); mActiveSounds.push_back(sound); } catch(std::exception&) { @@ -746,14 +743,12 @@ MWBase::SoundPtr OpenAL_Output::playSound3D(Sound_Handle data, const osg::Vec3f throw; } - return sound; + sound->mHandle = MAKE_PTRID(source); } void OpenAL_Output::stopSound(MWBase::SoundPtr sound) { - if(!sound->mHandle) - return; - + if(!sound->mHandle) return; ALuint source = GET_PTRID(sound->mHandle); sound->mHandle = 0; @@ -766,8 +761,7 @@ void OpenAL_Output::stopSound(MWBase::SoundPtr sound) bool OpenAL_Output::isSoundPlaying(MWBase::SoundPtr sound) { - if(!sound->mHandle) - return false; + if(!sound->mHandle) return false; ALuint source = GET_PTRID(sound->mHandle); ALint state; @@ -911,8 +905,7 @@ MWBase::SoundStreamPtr OpenAL_Output::streamSound3D(DecoderPtr decoder, const os void OpenAL_Output::stopStream(MWBase::SoundStreamPtr sound) { - if(!sound->mHandle) - return; + if(!sound->mHandle) return; OpenAL_SoundStream *stream = reinterpret_cast(sound->mHandle); ALuint source = stream->mSource; @@ -930,16 +923,14 @@ void OpenAL_Output::stopStream(MWBase::SoundStreamPtr sound) double OpenAL_Output::getStreamDelay(MWBase::SoundStreamPtr sound) { - if(!sound->mHandle) - return 0.0; + if(!sound->mHandle) return 0.0; OpenAL_SoundStream *stream = reinterpret_cast(sound->mHandle); return stream->getStreamDelay(); } double OpenAL_Output::getStreamOffset(MWBase::SoundStreamPtr sound) { - if(!sound->mHandle) - return 0.0; + if(!sound->mHandle) return 0.0; OpenAL_SoundStream *stream = reinterpret_cast(sound->mHandle); boost::lock_guard lock(mStreamThread->mMutex); return stream->getStreamOffset(); @@ -947,8 +938,7 @@ double OpenAL_Output::getStreamOffset(MWBase::SoundStreamPtr sound) bool OpenAL_Output::isStreamPlaying(MWBase::SoundStreamPtr sound) { - if(!sound->mHandle) - return false; + if(!sound->mHandle) return false; OpenAL_SoundStream *stream = reinterpret_cast(sound->mHandle); boost::lock_guard lock(mStreamThread->mMutex); return stream->isPlaying(); diff --git a/apps/openmw/mwsound/openal_output.hpp b/apps/openmw/mwsound/openal_output.hpp index 24b9c855f..934cb2d9d 100644 --- a/apps/openmw/mwsound/openal_output.hpp +++ b/apps/openmw/mwsound/openal_output.hpp @@ -47,9 +47,8 @@ namespace MWSound virtual void unloadSound(Sound_Handle data); virtual size_t getSoundDataSize(Sound_Handle data) const; - virtual MWBase::SoundPtr playSound(Sound_Handle data, float vol, float basevol, float pitch, int flags, float offset); - virtual MWBase::SoundPtr playSound3D(Sound_Handle data, const osg::Vec3f &pos, - float vol, float basevol, float pitch, float min, float max, int flags, float offset); + virtual void playSound(MWBase::SoundPtr sound, Sound_Handle data, float offset); + virtual void playSound3D(MWBase::SoundPtr sound, Sound_Handle data, float offset); virtual void stopSound(MWBase::SoundPtr sound); virtual bool isSoundPlaying(MWBase::SoundPtr sound); virtual void updateSound(MWBase::SoundPtr sound); diff --git a/apps/openmw/mwsound/sound.hpp b/apps/openmw/mwsound/sound.hpp index 878384b43..a59027fc1 100644 --- a/apps/openmw/mwsound/sound.hpp +++ b/apps/openmw/mwsound/sound.hpp @@ -22,7 +22,6 @@ namespace MWSound protected: Sound_Instance mHandle; - friend class Sound_Output; friend class OpenAL_Output; public: @@ -43,11 +42,13 @@ namespace MWSound const osg::Vec3f &getPosition() const { return mPos; } float getRealVolume() const { return mVolume * mBaseVolume; } float getPitch() const { return mPitch; } + float getMinDistance() const { return mMinDistance; } float getMaxDistance() const { return mMaxDistance; } MWBase::SoundManager::PlayType getPlayType() const { return (MWBase::SoundManager::PlayType)(mFlags&MWBase::SoundManager::Play_TypeMask); } bool getUseEnv() const { return !(mFlags&MWBase::SoundManager::Play_NoEnv); } + bool getIsLooping() const { return mFlags&MWBase::SoundManager::Play_Loop; } bool getDistanceCull() const { return mFlags&MWBase::SoundManager::Play_RemoveAtDistance; } bool getIs3D() const { return mFlags&Play_3D; } diff --git a/apps/openmw/mwsound/sound_output.hpp b/apps/openmw/mwsound/sound_output.hpp index d879dbf44..01009c5a3 100644 --- a/apps/openmw/mwsound/sound_output.hpp +++ b/apps/openmw/mwsound/sound_output.hpp @@ -31,11 +31,8 @@ namespace MWSound virtual void unloadSound(Sound_Handle data) = 0; virtual size_t getSoundDataSize(Sound_Handle data) const = 0; - /// @param offset Number of seconds into the sound to start playback. - virtual MWBase::SoundPtr playSound(Sound_Handle data, float vol, float basevol, float pitch, int flags, float offset) = 0; - /// @param offset Number of seconds into the sound to start playback. - virtual MWBase::SoundPtr playSound3D(Sound_Handle data, const osg::Vec3f &pos, - float vol, float basevol, float pitch, float min, float max, int flags, float offset) = 0; + virtual void playSound(MWBase::SoundPtr sound, Sound_Handle data, float offset) = 0; + virtual void playSound3D(MWBase::SoundPtr sound, Sound_Handle data, float offset) = 0; virtual void stopSound(MWBase::SoundPtr sound) = 0; virtual bool isSoundPlaying(MWBase::SoundPtr sound) = 0; virtual void updateSound(MWBase::SoundPtr sound) = 0; diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 157426564..9ab86ef57 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -508,9 +508,8 @@ namespace MWSound Sound_Buffer *sfx = loadSound(Misc::StringUtils::lowerCase(soundId)); float basevol = volumeFromType(type); - sound = mOutput->playSound(sfx->mHandle, - volume * sfx->mVolume, basevol, pitch, mode|type|Play_2D, offset - ); + sound.reset(new Sound(volume * sfx->mVolume, basevol, pitch, mode|type|Play_2D)); + mOutput->playSound(sound, sfx->mHandle, offset); if(sfx->mUses++ == 0) { SoundList::iterator iter = std::find(mUnusedBuffers.begin(), mUnusedBuffers.end(), sfx); @@ -522,6 +521,7 @@ namespace MWSound catch(std::exception&) { //std::cout <<"Sound Error: "<playSound(sfx->mHandle, - volume * sfx->mVolume, basevol, pitch, mode|type|Play_2D, offset - ); + { + sound.reset(new Sound(volume * sfx->mVolume, basevol, pitch, mode|type|Play_2D)); + mOutput->playSound(sound, sfx->mHandle, offset); + } else - sound = mOutput->playSound3D(sfx->mHandle, - objpos, volume * sfx->mVolume, basevol, pitch, sfx->mMinDist, sfx->mMaxDist, - mode|type|Play_3D, offset - ); + { + sound.reset(new Sound(objpos, volume * sfx->mVolume, basevol, pitch, + sfx->mMinDist, sfx->mMaxDist, mode|type|Play_3D)); + mOutput->playSound3D(sound, sfx->mHandle, offset); + } if(sfx->mUses++ == 0) { SoundList::iterator iter = std::find(mUnusedBuffers.begin(), mUnusedBuffers.end(), sfx); @@ -563,6 +565,7 @@ namespace MWSound catch(std::exception&) { //std::cout <<"Sound Error: "<playSound3D(sfx->mHandle, - initialPos, volume * sfx->mVolume, basevol, pitch, sfx->mMinDist, sfx->mMaxDist, - mode|type|Play_3D, offset - ); + sound.reset(new Sound(initialPos, volume * sfx->mVolume, basevol, pitch, + sfx->mMinDist, sfx->mMaxDist, mode|type|Play_3D)); + mOutput->playSound3D(sound, sfx->mHandle, offset); if(sfx->mUses++ == 0) { SoundList::iterator iter = std::find(mUnusedBuffers.begin(), mUnusedBuffers.end(), sfx); @@ -594,6 +596,7 @@ namespace MWSound catch(std::exception &) { //std::cout <<"Sound Error: "< Date: Wed, 2 Dec 2015 08:04:30 -0800 Subject: [PATCH 2667/3725] Use a premade SoundStream object for the output's streamSound functions --- apps/openmw/mwsound/openal_output.cpp | 36 +++++++++++-------------- apps/openmw/mwsound/openal_output.hpp | 5 ++-- apps/openmw/mwsound/sound_output.hpp | 5 ++-- apps/openmw/mwsound/soundmanagerimp.cpp | 29 +++++++++++++------- 4 files changed, 39 insertions(+), 36 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 8932c1b55..839ae45ad 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -799,9 +799,8 @@ void OpenAL_Output::updateSound(MWBase::SoundPtr sound) } -MWBase::SoundStreamPtr OpenAL_Output::streamSound(DecoderPtr decoder, float basevol, float pitch, int flags) +void OpenAL_Output::streamSound(DecoderPtr decoder, MWBase::SoundStreamPtr sound) { - MWBase::SoundStreamPtr sound; OpenAL_SoundStream *stream = 0; ALuint source; @@ -810,19 +809,18 @@ MWBase::SoundStreamPtr OpenAL_Output::streamSound(DecoderPtr decoder, float base source = mFreeSources.front(); mFreeSources.pop_front(); - if((flags&MWBase::SoundManager::Play_Loop)) + if(sound->getIsLooping()) std::cout <<"Warning: cannot loop stream \""<getName()<<"\""<< std::endl; try { - sound.reset(new Stream(1.0f, basevol, pitch, flags)); - alSourcef(source, AL_REFERENCE_DISTANCE, 1.0f); alSourcef(source, AL_MAX_DISTANCE, 1000.0f); alSourcef(source, AL_ROLLOFF_FACTOR, 0.0f); alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE); alSourcei(source, AL_LOOPING, AL_FALSE); - ALfloat gain = basevol; - if(!(flags&MWBase::SoundManager::Play_NoEnv) && mListenerEnv == Env_Underwater) + ALfloat gain = sound->getRealVolume(); + ALfloat pitch = sound->getPitch(); + if(sound->getUseEnv() && mListenerEnv == Env_Underwater) { gain *= 0.9f; pitch *= 0.7f; @@ -837,7 +835,6 @@ MWBase::SoundStreamPtr OpenAL_Output::streamSound(DecoderPtr decoder, float base stream = new OpenAL_SoundStream(source, decoder); mStreamThread->add(stream); - sound->mHandle = stream; mActiveStreams.push_back(sound); } catch(std::exception&) { @@ -847,12 +844,11 @@ MWBase::SoundStreamPtr OpenAL_Output::streamSound(DecoderPtr decoder, float base throw; } - return sound; + sound->mHandle = stream; } -MWBase::SoundStreamPtr OpenAL_Output::streamSound3D(DecoderPtr decoder, const osg::Vec3f &pos, float volume, float basevol, float pitch, float mindist, float maxdist, int flags) +void OpenAL_Output::streamSound3D(DecoderPtr decoder, MWBase::SoundStreamPtr sound) { - MWBase::SoundStreamPtr sound; OpenAL_SoundStream *stream = 0; ALuint source; @@ -861,21 +857,22 @@ MWBase::SoundStreamPtr OpenAL_Output::streamSound3D(DecoderPtr decoder, const os source = mFreeSources.front(); mFreeSources.pop_front(); - if((flags&MWBase::SoundManager::Play_Loop)) + if(sound->getIsLooping()) std::cout <<"Warning: cannot loop stream \""<getName()<<"\""<< std::endl; try { - sound.reset(new Stream(pos, volume, basevol, pitch, mindist, maxdist, flags)); - - alSourcef(source, AL_REFERENCE_DISTANCE, mindist); - alSourcef(source, AL_MAX_DISTANCE, maxdist); + alSourcef(source, AL_REFERENCE_DISTANCE, sound->getMinDistance()); + alSourcef(source, AL_MAX_DISTANCE, sound->getMaxDistance()); alSourcef(source, AL_ROLLOFF_FACTOR, 1.0f); alSourcei(source, AL_SOURCE_RELATIVE, AL_FALSE); alSourcei(source, AL_LOOPING, AL_FALSE); - ALfloat gain = volume*basevol; + const osg::Vec3f &pos = sound->getPosition(); + ALfloat maxdist = sound->getMaxDistance(); + ALfloat gain = sound->getRealVolume(); + ALfloat pitch = sound->getPitch(); if((pos - mListenerPos).length2() > maxdist*maxdist) gain = 0.0f; - if(!(flags&MWBase::SoundManager::Play_NoEnv) && mListenerEnv == Env_Underwater) + if(sound->getUseEnv() && mListenerEnv == Env_Underwater) { gain *= 0.9f; pitch *= 0.7f; @@ -890,7 +887,6 @@ MWBase::SoundStreamPtr OpenAL_Output::streamSound3D(DecoderPtr decoder, const os stream = new OpenAL_SoundStream(source, decoder); mStreamThread->add(stream); - sound->mHandle = stream; mActiveStreams.push_back(sound); } catch(std::exception&) { @@ -900,7 +896,7 @@ MWBase::SoundStreamPtr OpenAL_Output::streamSound3D(DecoderPtr decoder, const os throw; } - return sound; + sound->mHandle = stream; } void OpenAL_Output::stopStream(MWBase::SoundStreamPtr sound) diff --git a/apps/openmw/mwsound/openal_output.hpp b/apps/openmw/mwsound/openal_output.hpp index 934cb2d9d..1c2a991cf 100644 --- a/apps/openmw/mwsound/openal_output.hpp +++ b/apps/openmw/mwsound/openal_output.hpp @@ -53,9 +53,8 @@ namespace MWSound virtual bool isSoundPlaying(MWBase::SoundPtr sound); virtual void updateSound(MWBase::SoundPtr sound); - virtual MWBase::SoundStreamPtr streamSound(DecoderPtr decoder, float basevol, float pitch, int flags); - virtual MWBase::SoundStreamPtr streamSound3D(DecoderPtr decoder, const osg::Vec3f &pos, - float vol, float basevol, float pitch, float min, float max, int flags); + virtual void streamSound(DecoderPtr decoder, MWBase::SoundStreamPtr sound); + virtual void streamSound3D(DecoderPtr decoder, MWBase::SoundStreamPtr sound); virtual void stopStream(MWBase::SoundStreamPtr sound); virtual double getStreamDelay(MWBase::SoundStreamPtr sound); virtual double getStreamOffset(MWBase::SoundStreamPtr sound); diff --git a/apps/openmw/mwsound/sound_output.hpp b/apps/openmw/mwsound/sound_output.hpp index 01009c5a3..2f459d09b 100644 --- a/apps/openmw/mwsound/sound_output.hpp +++ b/apps/openmw/mwsound/sound_output.hpp @@ -37,9 +37,8 @@ namespace MWSound virtual bool isSoundPlaying(MWBase::SoundPtr sound) = 0; virtual void updateSound(MWBase::SoundPtr sound) = 0; - virtual MWBase::SoundStreamPtr streamSound(DecoderPtr decoder, float basevol, float pitch, int flags) = 0; - virtual MWBase::SoundStreamPtr streamSound3D(DecoderPtr decoder, const osg::Vec3f &pos, - float vol, float basevol, float pitch, float min, float max, int flags) = 0; + virtual void streamSound(DecoderPtr decoder, MWBase::SoundStreamPtr sound) = 0; + virtual void streamSound3D(DecoderPtr decoder, MWBase::SoundStreamPtr sound) = 0; virtual void stopStream(MWBase::SoundStreamPtr sound) = 0; virtual double getStreamDelay(MWBase::SoundStreamPtr sound) = 0; virtual double getStreamOffset(MWBase::SoundStreamPtr sound) = 0; diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 9ab86ef57..f814e4d19 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -251,15 +251,20 @@ namespace MWSound static float minDistance = std::max(fAudioVoiceDefaultMinDistance * fAudioMinDistanceMult, 1.0f); static float maxDistance = std::max(fAudioVoiceDefaultMaxDistance * fAudioMaxDistanceMult, minDistance); + MWBase::SoundStreamPtr sound; float basevol = volumeFromType(Play_TypeVoice); if(playlocal) - return mOutput->streamSound(decoder, - basevol, 1.0f, Play_Normal|Play_TypeVoice|Play_2D - ); - return mOutput->streamSound3D(decoder, - pos, 1.0f, basevol, 1.0f, minDistance, maxDistance, - Play_Normal|Play_TypeVoice|Play_3D - ); + { + sound.reset(new Stream(1.0f, basevol, 1.0f, Play_Normal|Play_TypeVoice|Play_2D)); + mOutput->streamSound(decoder, sound); + } + else + { + sound.reset(new Stream(pos, 1.0f, basevol, 1.0f, minDistance, maxDistance, + Play_Normal|Play_TypeVoice|Play_3D)); + mOutput->streamSound3D(decoder, sound); + } + return sound; } @@ -309,11 +314,13 @@ namespace MWSound DecoderPtr decoder = getDecoder(); decoder->open(filename); - mMusic = mOutput->streamSound(decoder, volumeFromType(Play_TypeMusic), - 1.0f, Play_NoEnv|Play_TypeMusic|Play_2D); + mMusic.reset(new Stream(1.0f, volumeFromType(Play_TypeMusic), 1.0f, + Play_NoEnv|Play_TypeMusic|Play_2D)); + mOutput->streamSound(decoder, mMusic); } catch(std::exception &e) { std::cout << "Music Error: " << e.what() << "\n"; + mMusic.reset(); } } @@ -473,7 +480,9 @@ namespace MWSound return track; try { - track = mOutput->streamSound(decoder, volumeFromType(type), 1.0f, Play_NoEnv|type); + track.reset(new Stream(1.0f, volumeFromType(type), 1.0f, Play_NoEnv|type|Play_2D)); + mOutput->streamSound(decoder, track); + TrackList::iterator iter = std::lower_bound(mActiveTracks.begin(), mActiveTracks.end(), track); mActiveTracks.insert(iter, track); } From 2face3d0a9ca6d9a81ec62936820aff6a5bc2408 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 2 Dec 2015 09:55:51 -0800 Subject: [PATCH 2668/3725] Combine duplicate code --- apps/openmw/mwsound/openal_output.cpp | 206 ++++++++++---------------- apps/openmw/mwsound/openal_output.hpp | 5 + 2 files changed, 85 insertions(+), 126 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 839ae45ad..54a5efb68 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -648,6 +648,71 @@ size_t OpenAL_Output::getSoundDataSize(Sound_Handle data) const } +void OpenAL_Output::initCommon2D(ALuint source, const osg::Vec3f &pos, ALfloat gain, ALfloat pitch, bool loop, bool useenv) +{ + alSourcef(source, AL_REFERENCE_DISTANCE, 1.0f); + alSourcef(source, AL_MAX_DISTANCE, 1000.0f); + alSourcef(source, AL_ROLLOFF_FACTOR, 0.0f); + alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE); + alSourcei(source, AL_LOOPING, loop ? AL_TRUE : AL_FALSE); + + if(useenv && mListenerEnv == Env_Underwater) + { + gain *= 0.9f; + pitch *= 0.7f; + } + + alSourcef(source, AL_GAIN, gain); + alSourcef(source, AL_PITCH, pitch); + alSourcefv(source, AL_POSITION, pos.ptr()); + alSource3f(source, AL_DIRECTION, 0.0f, 0.0f, 0.0f); + alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f); +} + +void OpenAL_Output::initCommon3D(ALuint source, const osg::Vec3f &pos, ALfloat mindist, ALfloat maxdist, ALfloat gain, ALfloat pitch, bool loop, bool useenv) +{ + alSourcef(source, AL_REFERENCE_DISTANCE, mindist); + alSourcef(source, AL_MAX_DISTANCE, maxdist); + alSourcef(source, AL_ROLLOFF_FACTOR, 1.0f); + alSourcei(source, AL_SOURCE_RELATIVE, AL_FALSE); + alSourcei(source, AL_LOOPING, loop ? AL_TRUE : AL_FALSE); + + if((pos - mListenerPos).length2() > maxdist*maxdist) + gain = 0.0f; + if(useenv && mListenerEnv == Env_Underwater) + { + gain *= 0.9f; + pitch *= 0.7f; + } + + alSourcef(source, AL_GAIN, gain); + alSourcef(source, AL_PITCH, pitch); + alSourcefv(source, AL_POSITION, pos.ptr()); + alSource3f(source, AL_DIRECTION, 0.0f, 0.0f, 0.0f); + alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f); +} + +void OpenAL_Output::updateCommon(ALuint source, const osg::Vec3f& pos, ALfloat maxdist, ALfloat gain, ALfloat pitch, bool useenv, bool is3d) +{ + if(is3d) + { + if((pos - mListenerPos).length2() > maxdist*maxdist) + gain = 0.0f; + } + if(useenv && mListenerEnv == Env_Underwater) + { + gain *= 0.9f; + pitch *= 0.7f; + } + + alSourcef(source, AL_GAIN, gain); + alSourcef(source, AL_PITCH, pitch); + alSourcefv(source, AL_POSITION, pos.ptr()); + alSource3f(source, AL_DIRECTION, 0.0f, 0.0f, 0.0f); + alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f); +} + + void OpenAL_Output::playSound(MWBase::SoundPtr sound, Sound_Handle data, float offset) { ALuint source; @@ -658,27 +723,10 @@ void OpenAL_Output::playSound(MWBase::SoundPtr sound, Sound_Handle data, float o mFreeSources.pop_front(); try { - alSourcef(source, AL_REFERENCE_DISTANCE, 1.0f); - alSourcef(source, AL_MAX_DISTANCE, 1000.0f); - alSourcef(source, AL_ROLLOFF_FACTOR, 0.0f); - alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE); - alSourcei(source, AL_LOOPING, sound->getIsLooping() ? AL_TRUE : AL_FALSE); - - ALfloat gain = sound->getRealVolume(); - ALfloat pitch = sound->getPitch(); - if(sound->getUseEnv() && mListenerEnv == Env_Underwater) - { - gain *= 0.9f; - pitch *= 0.7f; - } - - alSourcef(source, AL_GAIN, gain); - alSourcef(source, AL_PITCH, pitch); - alSource3f(source, AL_POSITION, 0.0f, 0.0f, 0.0f); - alSource3f(source, AL_DIRECTION, 0.0f, 0.0f, 0.0f); - alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f); + initCommon2D(source, sound->getPosition(), sound->getRealVolume(), sound->getPitch(), + sound->getIsLooping(), sound->getUseEnv()); - alSourcef(source, AL_SEC_OFFSET, offset/pitch); + alSourcef(source, AL_SEC_OFFSET, offset); throwALerror(); alSourcei(source, AL_BUFFER, GET_PTRID(data)); @@ -705,31 +753,11 @@ void OpenAL_Output::playSound3D(MWBase::SoundPtr sound, Sound_Handle data, float mFreeSources.pop_front(); try { - alSourcef(source, AL_REFERENCE_DISTANCE, sound->getMinDistance()); - alSourcef(source, AL_MAX_DISTANCE, sound->getMaxDistance()); - alSourcef(source, AL_ROLLOFF_FACTOR, 1.0f); - alSourcei(source, AL_SOURCE_RELATIVE, AL_FALSE); - alSourcei(source, AL_LOOPING, sound->getIsLooping() ? AL_TRUE : AL_FALSE); - - const osg::Vec3f &pos = sound->getPosition(); - ALfloat maxdist = sound->getMaxDistance(); - ALfloat gain = sound->getRealVolume(); - ALfloat pitch = sound->getPitch(); - if((pos - mListenerPos).length2() > maxdist*maxdist) - gain = 0.0f; - if(sound->getUseEnv() && mListenerEnv == Env_Underwater) - { - gain *= 0.9f; - pitch *= 0.7f; - } - - alSourcef(source, AL_GAIN, gain); - alSourcef(source, AL_PITCH, pitch); - alSourcefv(source, AL_POSITION, pos.ptr()); - alSource3f(source, AL_DIRECTION, 0.0f, 0.0f, 0.0f); - alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f); + initCommon3D(source, sound->getPosition(), sound->getMinDistance(), sound->getMaxDistance(), + sound->getRealVolume(), sound->getPitch(), sound->getIsLooping(), + sound->getUseEnv()); - alSourcef(source, AL_SEC_OFFSET, offset/pitch); + alSourcef(source, AL_SEC_OFFSET, offset); throwALerror(); alSourcei(source, AL_BUFFER, GET_PTRID(data)); @@ -776,26 +804,8 @@ void OpenAL_Output::updateSound(MWBase::SoundPtr sound) if(!sound->mHandle) return; ALuint source = GET_PTRID(sound->mHandle); - const osg::Vec3f &pos = sound->getPosition(); - ALfloat gain = sound->getRealVolume(); - ALfloat pitch = sound->getPitch(); - if(sound->getIs3D()) - { - ALfloat maxdist = sound->getMaxDistance(); - if((pos - mListenerPos).length2() > maxdist*maxdist) - gain = 0.0f; - } - if(sound->getUseEnv() && mListenerEnv == Env_Underwater) - { - gain *= 0.9f; - pitch *= 0.7f; - } - - alSourcef(source, AL_GAIN, gain); - alSourcef(source, AL_PITCH, pitch); - alSourcefv(source, AL_POSITION, pos.ptr()); - alSource3f(source, AL_DIRECTION, 0.0f, 0.0f, 0.0f); - alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f); + updateCommon(source, sound->getPosition(), sound->getMaxDistance(), sound->getRealVolume(), + sound->getPitch(), sound->getUseEnv(), sound->getIs3D()); } @@ -812,25 +822,8 @@ void OpenAL_Output::streamSound(DecoderPtr decoder, MWBase::SoundStreamPtr sound if(sound->getIsLooping()) std::cout <<"Warning: cannot loop stream \""<getName()<<"\""<< std::endl; try { - alSourcef(source, AL_REFERENCE_DISTANCE, 1.0f); - alSourcef(source, AL_MAX_DISTANCE, 1000.0f); - alSourcef(source, AL_ROLLOFF_FACTOR, 0.0f); - alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE); - alSourcei(source, AL_LOOPING, AL_FALSE); - - ALfloat gain = sound->getRealVolume(); - ALfloat pitch = sound->getPitch(); - if(sound->getUseEnv() && mListenerEnv == Env_Underwater) - { - gain *= 0.9f; - pitch *= 0.7f; - } - - alSourcef(source, AL_GAIN, gain); - alSourcef(source, AL_PITCH, pitch); - alSource3f(source, AL_POSITION, 0.0f, 0.0f, 0.0f); - alSource3f(source, AL_DIRECTION, 0.0f, 0.0f, 0.0f); - alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f); + initCommon2D(source, sound->getPosition(), sound->getRealVolume(), sound->getPitch(), + false, sound->getUseEnv()); throwALerror(); stream = new OpenAL_SoundStream(source, decoder); @@ -860,29 +853,8 @@ void OpenAL_Output::streamSound3D(DecoderPtr decoder, MWBase::SoundStreamPtr sou if(sound->getIsLooping()) std::cout <<"Warning: cannot loop stream \""<getName()<<"\""<< std::endl; try { - alSourcef(source, AL_REFERENCE_DISTANCE, sound->getMinDistance()); - alSourcef(source, AL_MAX_DISTANCE, sound->getMaxDistance()); - alSourcef(source, AL_ROLLOFF_FACTOR, 1.0f); - alSourcei(source, AL_SOURCE_RELATIVE, AL_FALSE); - alSourcei(source, AL_LOOPING, AL_FALSE); - - const osg::Vec3f &pos = sound->getPosition(); - ALfloat maxdist = sound->getMaxDistance(); - ALfloat gain = sound->getRealVolume(); - ALfloat pitch = sound->getPitch(); - if((pos - mListenerPos).length2() > maxdist*maxdist) - gain = 0.0f; - if(sound->getUseEnv() && mListenerEnv == Env_Underwater) - { - gain *= 0.9f; - pitch *= 0.7f; - } - - alSourcef(source, AL_GAIN, gain); - alSourcef(source, AL_PITCH, pitch); - alSourcefv(source, AL_POSITION, pos.ptr()); - alSource3f(source, AL_DIRECTION, 0.0f, 0.0f, 0.0f); - alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f); + initCommon3D(source, sound->getPosition(), sound->getMinDistance(), sound->getMaxDistance(), + sound->getRealVolume(), sound->getPitch(), false, sound->getUseEnv()); throwALerror(); stream = new OpenAL_SoundStream(source, decoder); @@ -946,26 +918,8 @@ void OpenAL_Output::updateStream(MWBase::SoundStreamPtr sound) OpenAL_SoundStream *stream = reinterpret_cast(sound->mHandle); ALuint source = stream->mSource; - const osg::Vec3f &pos = sound->getPosition(); - ALfloat gain = sound->getRealVolume(); - ALfloat pitch = sound->getPitch(); - if(sound->getIs3D()) - { - ALfloat maxdist = sound->getMaxDistance(); - if((pos - mListenerPos).length2() > maxdist*maxdist) - gain = 0.0f; - } - if(sound->getUseEnv() && mListenerEnv == Env_Underwater) - { - gain *= 0.9f; - pitch *= 0.7f; - } - - alSourcef(source, AL_GAIN, gain); - alSourcef(source, AL_PITCH, pitch); - alSourcefv(source, AL_POSITION, pos.ptr()); - alSource3f(source, AL_DIRECTION, 0.0f, 0.0f, 0.0f); - alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f); + updateCommon(source, sound->getPosition(), sound->getMaxDistance(), sound->getRealVolume(), + sound->getPitch(), sound->getUseEnv(), sound->getIs3D()); } diff --git a/apps/openmw/mwsound/openal_output.hpp b/apps/openmw/mwsound/openal_output.hpp index 1c2a991cf..d00e8cd67 100644 --- a/apps/openmw/mwsound/openal_output.hpp +++ b/apps/openmw/mwsound/openal_output.hpp @@ -35,6 +35,11 @@ namespace MWSound struct StreamThread; std::auto_ptr mStreamThread; + void initCommon2D(ALuint source, const osg::Vec3f &pos, ALfloat gain, ALfloat pitch, bool loop, bool useenv); + void initCommon3D(ALuint source, const osg::Vec3f &pos, ALfloat mindist, ALfloat maxdist, ALfloat gain, ALfloat pitch, bool loop, bool useenv); + + void updateCommon(ALuint source, const osg::Vec3f &pos, ALfloat maxdist, ALfloat gain, ALfloat pitch, bool useenv, bool is3d); + OpenAL_Output& operator=(const OpenAL_Output &rhs); OpenAL_Output(const OpenAL_Output &rhs); From f19f1c47c8f0895e6d56234fd3551cb0f3cc321d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 2 Dec 2015 16:07:19 -0800 Subject: [PATCH 2669/3725] Fix playing pending voices without a Ptr --- apps/openmw/mwsound/soundmanagerimp.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index f814e4d19..044a8ba48 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -890,13 +890,17 @@ namespace MWSound DecoderPtr decoder = penditer->second.first; decoder->rewind(); + MWBase::SoundStreamPtr sound; MWWorld::Ptr ptr = penditer->first; - const ESM::Position &pos = ptr.getRefData().getPosition(); - const osg::Vec3f objpos(pos.asVec3()); + if(ptr == MWWorld::Ptr()) + sound = playVoice(decoder, osg::Vec3f(), true); + else + { + const ESM::Position &pos = ptr.getRefData().getPosition(); + const osg::Vec3f objpos(pos.asVec3()); - MWBase::SoundStreamPtr sound = playVoice(decoder, - objpos, (ptr == MWMechanics::getPlayer()) - ); + sound = playVoice(decoder, objpos, (ptr == MWMechanics::getPlayer())); + } mActiveSaySounds[ptr] = std::make_pair(sound, loudness); } catch(std::exception &e) { From 238a5824be1d1dd65d7118f4c09a5fe407766589 Mon Sep 17 00:00:00 2001 From: sandstranger Date: Thu, 3 Dec 2015 08:54:14 +0300 Subject: [PATCH 2670/3725] add custom new variable fot Qt --- CMakeLists.txt | 17 +++++-- apps/openmw/CMakeLists.txt | 22 +------- components/CMakeLists.txt | 68 ++++++++++--------------- components/sdlutil/sdlcursormanager.cpp | 3 -- 4 files changed, 40 insertions(+), 70 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 61a44b758..b41f0773f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -168,14 +168,23 @@ endif (ANDROID) option(OPENGL_ES "enable opengl es support" FALSE ) +option(USE_QT "Use Qt in building" TRUE ) + +if (NOT BUILD_LAUNCHER AND NOT BUILD_OPENCS) + set(USE_QT FALSE CACHE BOOL "disable Qt" FORCE ) +else() + set(USE_QT TRUE CACHE BOOL "enable Qt" FORCE ) +endif() + +add_definitions (-DUSE_QT) + if (OPENGL_ES) - INCLUDE(cmake/FindOpenGLES.cmake) + find_package(OpenGLES) add_definitions (-DOPENGL_ES) - INCLUDE_DIRECTORIES(${OPENGLES_INCLUDE_DIR}) endif (OPENGLES) # Dependencies -if (NOT ANDROID) +if (USE_QT) set(DESIRED_QT_VERSION 4 CACHE STRING "The QT version OpenMW should use (4 or 5)") message(STATUS "Using Qt${DESIRED_QT_VERSION}") @@ -220,7 +229,7 @@ IF(BOOST_STATIC) set(Boost_USE_STATIC_LIBS ON) endif() -if (NOT ANDROID) +if (USE_QT) find_package(OpenSceneGraph 3.2.0 REQUIRED osgDB osgViewer osgText osgGA osgAnimation osgParticle osgQt osgUtil osgFX) else() find_package(OpenSceneGraph 3.2.0 REQUIRED osgDB osgViewer osgText osgGA osgAnimation osgParticle osgUtil osgFX) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 4512e004d..03ce71f5c 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -155,35 +155,15 @@ if (ANDROID) android log dl - MyGUIEngineStatic - BulletCollision - LinearMath z - osg - osgDB - osgAnimation - osgText - osgUtil - osgShadow ${OPENSCENEGRAPH_LIBRARIES} ${OSG_PLUGINS} - ${Boost_SYSTEM_LIBRARY} - ${Boost_THREAD_LIBRARY} - ${Boost_FILESYSTEM_LIBRARY} - ${Boost_PROGRAM_OPTIONS_LIBRARY} jpeg gif - png + png ) endif (ANDROID) - -if (OPENGL_ES) - target_link_libraries(openmw - ${OPENGLES_gl_LIBRARY} - ) -endif (OPENGL_ES) - if (USE_SYSTEM_TINYXML) target_link_libraries(openmw ${TINYXML_LIBRARIES}) endif() diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 92e11c51c..edc7b7c25 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -139,7 +139,7 @@ add_component_dir (version set (ESM_UI ${CMAKE_SOURCE_DIR}/files/ui/contentselector.ui ) -if (NOT ANDROID) +if (USE_QT) add_component_qt_dir (contentselector model/modelitem model/esmfile model/naturalsort model/contentmodel @@ -176,55 +176,39 @@ include_directories(${BULLET_INCLUDE_DIRS} ${CMAKE_CURRENT_BINARY_DIR}) add_library(components STATIC ${COMPONENT_FILES} ${MOC_SRCS} ${ESM_UI_HDR}) -if (NOT ANDROID) - target_link_libraries(components - ${Boost_SYSTEM_LIBRARY} - ${Boost_FILESYSTEM_LIBRARY} - ${Boost_THREAD_LIBRARY} - ${Boost_PROGRAM_OPTIONS_LIBRARY} - ${OSG_LIBRARIES} - ${OPENTHREADS_LIBRARIES} - ${OSGPARTICLE_LIBRARIES} - ${OSGUTIL_LIBRARIES} - ${OSGDB_LIBRARIES} - ${OSGVIEWER_LIBRARIES} - ${OSGGA_LIBRARIES} - ${OSGFX_LIBRARIES} - ${OSGANIMATION_LIBRARIES} - ${BULLET_LIBRARIES} - ${SDL2_LIBRARY} - # For MyGUI platform - ${OPENGL_gl_LIBRARY} - ${MYGUI_LIBRARIES} - ) +if (OPENGL_ES) + set(GL_LIB ${OPENGLES_gl_LIBRARY}) else() - target_link_libraries(components - ${Boost_SYSTEM_LIBRARY} - ${Boost_FILESYSTEM_LIBRARY} - ${Boost_THREAD_LIBRARY} - ${Boost_PROGRAM_OPTIONS_LIBRARY} - ${OSG_LIBRARIES} - ${OPENTHREADS_LIBRARIES} - ${OSGPARTICLE_LIBRARIES} - ${OSGUTIL_LIBRARIES} - ${OSGDB_LIBRARIES} - ${OSGVIEWER_LIBRARIES} - ${OSGGA_LIBRARIES} - ${OSGFX_LIBRARIES} - ${OSGANIMATION_LIBRARIES} - ${BULLET_LIBRARIES} - ${SDL2_LIBRARY} - # For MyGUI platform - ${MYGUI_LIBRARIES} - ) + set(GL_LIB ${OPENGL_gl_LIBRARY}) endif() +target_link_libraries(components + ${Boost_SYSTEM_LIBRARY} + ${Boost_FILESYSTEM_LIBRARY} + ${Boost_THREAD_LIBRARY} + ${Boost_PROGRAM_OPTIONS_LIBRARY} + ${OSG_LIBRARIES} + ${OPENTHREADS_LIBRARIES} + ${OSGPARTICLE_LIBRARIES} + ${OSGUTIL_LIBRARIES} + ${OSGDB_LIBRARIES} + ${OSGVIEWER_LIBRARIES} + ${OSGGA_LIBRARIES} + ${OSGFX_LIBRARIES} + ${OSGANIMATION_LIBRARIES} + ${BULLET_LIBRARIES} + ${SDL2_LIBRARY} + # For MyGUI platform + ${GL_LIB} + ${MYGUI_LIBRARIES} + ) + if (WIN32) target_link_libraries(components ${Boost_LOCALE_LIBRARY}) endif() -if (NOT ANDROID) +if (USE_QT) if (DESIRED_QT_VERSION MATCHES 4) target_link_libraries(components ${QT_QTCORE_LIBRARY} diff --git a/components/sdlutil/sdlcursormanager.cpp b/components/sdlutil/sdlcursormanager.cpp index c131621a8..0eb161a64 100644 --- a/components/sdlutil/sdlcursormanager.cpp +++ b/components/sdlutil/sdlcursormanager.cpp @@ -221,9 +221,6 @@ namespace SDLUtil return; #endif - if (mCursorMap.find(name) != mCursorMap.end()) - return; - if (mCursorMap.find(name) != mCursorMap.end()) return; From 06efd72a89117658351870c3d01b5b32b6f62f73 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 3 Dec 2015 11:14:58 +0100 Subject: [PATCH 2671/3725] allow keywords as strings in messagebox instruction (Fixes #2991) --- components/compiler/lineparser.cpp | 7 ++++++- components/compiler/scanner.cpp | 16 +++++++++++++--- components/compiler/scanner.hpp | 10 ++++++++-- 3 files changed, 27 insertions(+), 6 deletions(-) diff --git a/components/compiler/lineparser.cpp b/components/compiler/lineparser.cpp index c1622c3e0..ce1e1e463 100644 --- a/components/compiler/lineparser.cpp +++ b/components/compiler/lineparser.cpp @@ -411,7 +411,12 @@ namespace Compiler } case Scanner::K_set: mState = SetState; return true; - case Scanner::K_messagebox: mState = MessageState; return true; + + case Scanner::K_messagebox: + + mState = MessageState; + scanner.enableStrictKeywords(); + return true; case Scanner::K_return: diff --git a/components/compiler/scanner.cpp b/components/compiler/scanner.cpp index 3c5bb7747..b370f74a1 100644 --- a/components/compiler/scanner.cpp +++ b/components/compiler/scanner.cpp @@ -26,6 +26,7 @@ namespace Compiler if (c=='\n') { + mStrictKeywords = false; mLoc.mColumn = 0; ++mLoc.mLine; mLoc.mLiteral.clear(); @@ -294,8 +295,11 @@ namespace Compiler name = name.substr (1, name.size()-2); // allow keywords enclosed in "" /// \todo optionally disable -// cont = parser.parseName (name, loc, *this); -// return true; + if (mStrictKeywords) + { + cont = parser.parseName (name, loc, *this); + return true; + } } int i = 0; @@ -567,7 +571,8 @@ namespace Compiler Scanner::Scanner (ErrorHandler& errorHandler, std::istream& inputStream, const Extensions *extensions) : mErrorHandler (errorHandler), mStream (inputStream), mExtensions (extensions), - mPutback (Putback_None), mPutbackCode(0), mPutbackInteger(0), mPutbackFloat(0) + mPutback (Putback_None), mPutbackCode(0), mPutbackInteger(0), mPutbackFloat(0), + mStrictKeywords (false) { } @@ -619,4 +624,9 @@ namespace Compiler if (mExtensions) mExtensions->listKeywords (keywords); } + + void Scanner::enableStrictKeywords() + { + mStrictKeywords = true; + } } diff --git a/components/compiler/scanner.hpp b/components/compiler/scanner.hpp index fe867feba..270782c74 100644 --- a/components/compiler/scanner.hpp +++ b/components/compiler/scanner.hpp @@ -37,6 +37,7 @@ namespace Compiler float mPutbackFloat; std::string mPutbackName; TokenLoc mPutbackLoc; + bool mStrictKeywords; public: @@ -116,13 +117,18 @@ namespace Compiler ///< put back a float token void putbackName (const std::string& name, const TokenLoc& loc); - ///< put back a name toekn + ///< put back a name token void putbackKeyword (int keyword, const TokenLoc& loc); ///< put back a keyword token void listKeywords (std::vector& keywords); - ///< Append all known keywords to \a kaywords. + ///< Append all known keywords to \a keywords. + + /// Do not accept keywords in quotation marks anymore. + /// + /// \attention This mode lasts only until the next newline is reached. + void enableStrictKeywords(); }; } From 86881bcf398d004f1b7e9437acf07bdfd73b6c1d Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 3 Dec 2015 15:16:20 +0100 Subject: [PATCH 2672/3725] In first person mode, attach sound listener to the camera --- apps/openmw/mwbase/soundmanager.hpp | 2 +- apps/openmw/mwrender/renderingmanager.cpp | 6 ++++++ apps/openmw/mwrender/renderingmanager.hpp | 2 ++ apps/openmw/mwsound/soundmanagerimp.cpp | 7 ++----- apps/openmw/mwsound/soundmanagerimp.hpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 17 +++++++++++------ 6 files changed, 23 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwbase/soundmanager.hpp b/apps/openmw/mwbase/soundmanager.hpp index a91149777..b31383936 100644 --- a/apps/openmw/mwbase/soundmanager.hpp +++ b/apps/openmw/mwbase/soundmanager.hpp @@ -153,7 +153,7 @@ namespace MWBase virtual void update(float duration) = 0; - virtual void setListenerPosDir(const osg::Vec3f &pos, const osg::Vec3f &dir, const osg::Vec3f &up) = 0; + virtual void setListenerPosDir(const osg::Vec3f &pos, const osg::Vec3f &dir, const osg::Vec3f &up, bool underwater) = 0; virtual void updatePtr (const MWWorld::Ptr& old, const MWWorld::Ptr& updated) = 0; diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index f6403a925..c0a907f70 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -387,6 +387,7 @@ namespace MWRender osg::Vec3f focal, cameraPos; mCamera->getPosition(focal, cameraPos); + mCurrentCameraPos = cameraPos; if (mWater->isUnderwater(cameraPos)) { setFogColor(mUnderwaterColor * mUnderwaterWeight + mFogColor * (1.f-mUnderwaterWeight)); @@ -865,6 +866,11 @@ namespace MWRender return mCamera.get(); } + const osg::Vec3f &RenderingManager::getCameraPosition() const + { + return mCurrentCameraPos; + } + void RenderingManager::togglePOV() { mCamera->toggleViewMode(); diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 203df2269..a0ea14cb4 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -159,6 +159,7 @@ namespace MWRender void resetCamera(); float getCameraDistance() const; Camera* getCamera(); + const osg::Vec3f& getCameraPosition() const; void togglePOV(); void togglePreviewMode(bool enable); bool toggleVanityMode(bool enable); @@ -188,6 +189,7 @@ namespace MWRender std::auto_ptr mPlayerAnimation; osg::ref_ptr mPlayerNode; std::auto_ptr mCamera; + osg::Vec3f mCurrentCameraPos; osg::ref_ptr mStateUpdater; diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index ceff1a619..3b24e26ab 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -946,16 +946,13 @@ namespace MWSound mOutput->finishUpdate(); } - void SoundManager::setListenerPosDir(const osg::Vec3f &pos, const osg::Vec3f &dir, const osg::Vec3f &up) + void SoundManager::setListenerPosDir(const osg::Vec3f &pos, const osg::Vec3f &dir, const osg::Vec3f &up, bool underwater) { mListenerPos = pos; mListenerDir = dir; mListenerUp = up; - MWWorld::Ptr player = MWMechanics::getPlayer(); - const MWWorld::CellStore *cell = player.getCell(); - - mListenerUnderwater = ((cell->getCell()->mData.mFlags&ESM::Cell::HasWater) && mListenerPos.z() < cell->getWaterLevel()); + mListenerUnderwater = underwater; } void SoundManager::updatePtr(const MWWorld::Ptr &old, const MWWorld::Ptr &updated) diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index 9c090585b..1f1a5cd6b 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -218,7 +218,7 @@ namespace MWSound virtual void update(float duration); - virtual void setListenerPosDir(const osg::Vec3f &pos, const osg::Vec3f &dir, const osg::Vec3f &up); + virtual void setListenerPosDir(const osg::Vec3f &pos, const osg::Vec3f &dir, const osg::Vec3f &up, bool underwater); virtual void updatePtr (const MWWorld::Ptr& old, const MWWorld::Ptr& updated); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 6bced30c4..22485ed92 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1601,18 +1601,23 @@ namespace MWWorld void World::updateSoundListener() { const ESM::Position& refpos = getPlayerPtr().getRefData().getPosition(); - osg::Vec3f playerPos = refpos.asVec3(); + osg::Vec3f listenerPos; - playerPos.z() += 1.85f * mPhysics->getHalfExtents(getPlayerPtr()).z(); + if (isFirstPerson()) + listenerPos = mRendering->getCameraPosition(); + else + listenerPos = refpos.asVec3() + osg::Vec3f(0, 0, 1.85f * mPhysics->getHalfExtents(getPlayerPtr()).z()); - osg::Quat playerOrient = osg::Quat(refpos.rot[1], osg::Vec3f(0,-1,0)) * + osg::Quat listenerOrient = osg::Quat(refpos.rot[1], osg::Vec3f(0,-1,0)) * osg::Quat(refpos.rot[0], osg::Vec3f(-1,0,0)) * osg::Quat(refpos.rot[2], osg::Vec3f(0,0,-1)); - osg::Vec3f forward = playerOrient * osg::Vec3f(0,1,0); - osg::Vec3f up = playerOrient * osg::Vec3f(0,0,1); + osg::Vec3f forward = listenerOrient * osg::Vec3f(0,1,0); + osg::Vec3f up = listenerOrient * osg::Vec3f(0,0,1); + + bool underwater = isUnderwater(getPlayerPtr().getCell(), listenerPos); - MWBase::Environment::get().getSoundManager()->setListenerPosDir(playerPos, forward, up); + MWBase::Environment::get().getSoundManager()->setListenerPosDir(listenerPos, forward, up, underwater); } void World::updateWindowManager () From d0c6b407b47daaee8ded5fc7bf56a7b41c526d63 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 3 Dec 2015 15:16:50 +0100 Subject: [PATCH 2673/3725] Fix isUnderwater checks being off by one for exterior cells --- apps/openmw/mwworld/cellstore.cpp | 2 ++ apps/openmw/mwworld/scene.cpp | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index e9f9c5cd1..5832a6727 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -296,6 +296,8 @@ namespace MWWorld float CellStore::getWaterLevel() const { + if (isExterior()) + return -1; return mWaterLevel; } diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index c6b50aae3..45c94b6d9 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -265,7 +265,7 @@ namespace MWWorld mRendering.addCell(cell); bool waterEnabled = cell->getCell()->hasWater() || cell->isExterior(); - float waterLevel = cell->isExterior() ? -1.f : cell->getWaterLevel(); + float waterLevel = cell->getWaterLevel(); mRendering.setWaterEnabled(waterEnabled); if (waterEnabled) { From 389b168d5fac7719d5f8781792743232ad247714 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 3 Dec 2015 15:48:27 +0100 Subject: [PATCH 2674/3725] Restore OpGetWaterLevel to vanilla behaviour --- apps/openmw/mwscript/cellextensions.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwscript/cellextensions.cpp b/apps/openmw/mwscript/cellextensions.cpp index 5dd3cf411..b6f7229e0 100644 --- a/apps/openmw/mwscript/cellextensions.cpp +++ b/apps/openmw/mwscript/cellextensions.cpp @@ -144,7 +144,9 @@ namespace MWScript return; } MWWorld::CellStore *cell = MWMechanics::getPlayer().getCell(); - if (cell->getCell()->hasWater()) + if (cell->isExterior()) + runtime.push(0.f); // vanilla oddity, return 0 even though water is actually at -1 + else if (cell->getCell()->hasWater()) runtime.push (cell->getWaterLevel()); else runtime.push (-std::numeric_limits::max()); From d9b1b7c516c1cd49c276985b3404cb9778f42ae5 Mon Sep 17 00:00:00 2001 From: sandstranger Date: Thu, 3 Dec 2015 19:56:38 +0300 Subject: [PATCH 2675/3725] addd forgotten line --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b41f0773f..58aac20ae 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -170,7 +170,7 @@ option(OPENGL_ES "enable opengl es support" FALSE ) option(USE_QT "Use Qt in building" TRUE ) -if (NOT BUILD_LAUNCHER AND NOT BUILD_OPENCS) +if (NOT BUILD_LAUNCHER AND NOT BUILD_OPENCS AND NOT BUILD_WIZARD) set(USE_QT FALSE CACHE BOOL "disable Qt" FORCE ) else() set(USE_QT TRUE CACHE BOOL "enable Qt" FORCE ) From 7d374b36fdbe9411f7dfb6373db30bbf4a5a46b4 Mon Sep 17 00:00:00 2001 From: sandstranger Date: Thu, 3 Dec 2015 21:29:50 +0300 Subject: [PATCH 2676/3725] change cmake variables --- CMakeLists.txt | 29 +++++++++++------------------ components/CMakeLists.txt | 4 +++- 2 files changed, 14 insertions(+), 19 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 58aac20ae..02a05cb3a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -45,10 +45,6 @@ endif(EXISTS ${PROJECT_SOURCE_DIR}/.git) # Macros include(OpenMWMacros) -if (ANDROID) - set(CMAKE_FIND_ROOT_PATH ${OPENMW_DEPENDENCIES_DIR} "${CMAKE_FIND_ROOT_PATH}") -endif (ANDROID) - # doxygen main page configure_file ("${OpenMW_SOURCE_DIR}/docs/mainpage.hpp.cmake" "${OpenMW_BINARY_DIR}/docs/mainpage.hpp") @@ -161,28 +157,24 @@ endif() if (ANDROID) set(CMAKE_FIND_ROOT_PATH ${OPENMW_DEPENDENCIES_DIR} "${CMAKE_FIND_ROOT_PATH}") - set(OSG_PLUGINS_DIR ${OSG_PLUGINS_DIR}) - add_definitions (-DOSG_PLUGINS_DIR) + add_definitions (-DOSG_PLUGINS_DIR=${OSG_PLUGINS_DIR}) set(OPENGL_ES TRUE CACHE BOOL "enable opengl es support for android" FORCE) endif (ANDROID) option(OPENGL_ES "enable opengl es support" FALSE ) -option(USE_QT "Use Qt in building" TRUE ) +if (OPENGL_ES) + add_definitions(-DOPENGL_ES) +endif(OPENGL_ES) if (NOT BUILD_LAUNCHER AND NOT BUILD_OPENCS AND NOT BUILD_WIZARD) - set(USE_QT FALSE CACHE BOOL "disable Qt" FORCE ) + set(USE_QT FALSE) else() - set(USE_QT TRUE CACHE BOOL "enable Qt" FORCE ) + set(USE_QT TRUE) endif() -add_definitions (-DUSE_QT) +add_definitions(-DUSE_QT) -if (OPENGL_ES) - find_package(OpenGLES) - add_definitions (-DOPENGL_ES) -endif (OPENGLES) - # Dependencies if (USE_QT) set(DESIRED_QT_VERSION 4 CACHE STRING "The QT version OpenMW should use (4 or 5)") @@ -230,10 +222,11 @@ IF(BOOST_STATIC) endif() if (USE_QT) - find_package(OpenSceneGraph 3.2.0 REQUIRED osgDB osgViewer osgText osgGA osgAnimation osgParticle osgQt osgUtil osgFX) -else() - find_package(OpenSceneGraph 3.2.0 REQUIRED osgDB osgViewer osgText osgGA osgAnimation osgParticle osgUtil osgFX) + set (OSG_QT osgQt) endif() + +find_package(OpenSceneGraph 3.2.0 REQUIRED osgDB osgViewer osgText osgGA osgAnimation osgParticle ${OSG_QT} osgUtil osgFX) + include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS}) if(OSG_STATIC) diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index edc7b7c25..a1ac53d1b 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -20,7 +20,9 @@ else (GIT_CHECKOUT) configure_file(${VERSION_IN_FILE} ${VERSION_FILE}) endif (GIT_CHECKOUT) -if (NOT OPENGL_ES) +if (OPENGL_ES) + find_package(OpenGLES REQUIRED) +else() find_package(OpenGL REQUIRED) endif() From eb458bf9c884813c4e0da7c302390bea5e67b6c4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 3 Dec 2015 19:49:45 +0100 Subject: [PATCH 2677/3725] Fix inactive RigGeometry not rendering correctly --- components/sceneutil/riggeometry.cpp | 4 +++- components/sceneutil/skeleton.cpp | 5 ++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/components/sceneutil/riggeometry.cpp b/components/sceneutil/riggeometry.cpp index 0006c947e..88b907faf 100644 --- a/components/sceneutil/riggeometry.cpp +++ b/components/sceneutil/riggeometry.cpp @@ -82,7 +82,7 @@ RigGeometry::RigGeometry(const RigGeometry ©, const osg::CopyOp ©op) , mSkeleton(NULL) , mInfluenceMap(copy.mInfluenceMap) , mLastFrameNumber(0) - , mBoundsFirstFrame(copy.mBoundsFirstFrame) + , mBoundsFirstFrame(true) { setSourceGeometry(copy.mSourceGeometry); } @@ -211,6 +211,8 @@ void RigGeometry::update(osg::NodeVisitor* nv) { if (!mSkeleton) { + std::cerr << "RigGeometry rendering with no skeleton, should have been initialized by UpdateVisitor" << std::endl; + // try to recover anyway, though rendering is likely to be incorrect. if (!initFromParentSkeleton(nv)) return; } diff --git a/components/sceneutil/skeleton.cpp b/components/sceneutil/skeleton.cpp index d66131b4e..83f7d6537 100644 --- a/components/sceneutil/skeleton.cpp +++ b/components/sceneutil/skeleton.cpp @@ -135,7 +135,10 @@ bool Skeleton::getActive() const void Skeleton::traverse(osg::NodeVisitor& nv) { - if (!mActive && nv.getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR && mLastFrameNumber != 0) + if (!getActive() && nv.getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR + // need to process at least 2 frames before shutting off update, since we need to have both frame-alternating RigGeometries initialized + // this would be more naturally handled if the double-buffering was implemented in RigGeometry itself rather than in a FrameSwitch decorator node + && mLastFrameNumber != 0 && mLastFrameNumber+2 <= nv.getTraversalNumber()) return; osg::Group::traverse(nv); } From 795f6d77f2a2ebf510955468a8fca7ee7903c425 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 3 Dec 2015 20:06:00 +0100 Subject: [PATCH 2678/3725] Cache the Animation's Skeleton --- apps/openmw/mwrender/animation.cpp | 12 +++++++----- apps/openmw/mwrender/animation.hpp | 2 ++ 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index d530c2c92..bc417dae2 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -311,6 +311,7 @@ namespace MWRender Animation::Animation(const MWWorld::Ptr &ptr, osg::ref_ptr parentNode, Resource::ResourceSystem* resourceSystem) : mInsert(parentNode) + , mSkeleton(NULL) , mPtr(ptr) , mResourceSystem(resourceSystem) , mAccumulate(1.f, 1.f, 0.f) @@ -338,10 +339,8 @@ namespace MWRender void Animation::setActive(bool active) { - if (SceneUtil::Skeleton* skel = dynamic_cast(mObjectRoot.get())) - { - skel->setActive(active); - } + if (mSkeleton) + mSkeleton->setActive(active); } void Animation::updatePtr(const MWWorld::Ptr &ptr) @@ -965,6 +964,7 @@ namespace MWRender mObjectRoot->getParent(0)->removeChild(mObjectRoot); } mObjectRoot = NULL; + mSkeleton = NULL; mNodeMap.clear(); mActiveControllers.clear(); @@ -976,9 +976,11 @@ namespace MWRender else { osg::ref_ptr newObjectRoot = mResourceSystem->getSceneManager()->createInstance(model); - if (!dynamic_cast(newObjectRoot.get())) + mSkeleton = dynamic_cast(newObjectRoot.get()); + if (!mSkeleton) { osg::ref_ptr skel = new SceneUtil::Skeleton; + mSkeleton = skel.get(); skel->addChild(newObjectRoot); newObjectRoot = skel; } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index b1c34576b..04df10a38 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -24,6 +24,7 @@ namespace NifOsg namespace SceneUtil { class LightSource; + class Skeleton; } namespace MWRender @@ -208,6 +209,7 @@ protected: osg::ref_ptr mInsert; osg::ref_ptr mObjectRoot; + SceneUtil::Skeleton* mSkeleton; // The node expected to accumulate movement during movement animations. osg::ref_ptr mAccumRoot; From 1ec338f19d86bcf316d9199e7483057426358008 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 3 Dec 2015 20:11:28 +0100 Subject: [PATCH 2679/3725] Don't attempt to load external keyframes for non-NIF files --- apps/openmw/mwrender/animation.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index bc417dae2..7a2cce7c9 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -394,6 +394,8 @@ namespace MWRender if(kfname.size() > 4 && kfname.compare(kfname.size()-4, 4, ".nif") == 0) kfname.replace(kfname.size()-4, 4, ".kf"); + else + return; if(!mResourceSystem->getVFS()->exists(kfname)) return; From 7db307e028e95418f7642ab02813c9d105250002 Mon Sep 17 00:00:00 2001 From: sandstranger Date: Thu, 3 Dec 2015 22:37:42 +0300 Subject: [PATCH 2680/3725] delete unused variables --- CMakeLists.txt | 3 --- 1 file changed, 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 02a05cb3a..db8bcc4f7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -157,7 +157,6 @@ endif() if (ANDROID) set(CMAKE_FIND_ROOT_PATH ${OPENMW_DEPENDENCIES_DIR} "${CMAKE_FIND_ROOT_PATH}") - add_definitions (-DOSG_PLUGINS_DIR=${OSG_PLUGINS_DIR}) set(OPENGL_ES TRUE CACHE BOOL "enable opengl es support for android" FORCE) endif (ANDROID) @@ -172,8 +171,6 @@ if (NOT BUILD_LAUNCHER AND NOT BUILD_OPENCS AND NOT BUILD_WIZARD) else() set(USE_QT TRUE) endif() - -add_definitions(-DUSE_QT) # Dependencies if (USE_QT) From 5f349b9a6ebe355e14d389d6f2e5a94a13731fc5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 3 Dec 2015 21:12:58 +0100 Subject: [PATCH 2681/3725] Support effects with attribute/skill argument in OpGetEffect --- apps/openmw/mwscript/miscextensions.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 63f3ea190..68a30de4a 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -422,9 +422,17 @@ namespace MWScript if(key < 0 || key > 32767 || *end != '\0') key = ESM::MagicEffect::effectStringToId(effect); - runtime.push(ptr.getClass().getCreatureStats(ptr).getMagicEffects().get( - MWMechanics::EffectKey(key)).getMagnitude() > 0); - } + const MWMechanics::MagicEffects& effects = ptr.getClass().getCreatureStats(ptr).getMagicEffects(); + for (MWMechanics::MagicEffects::Collection::const_iterator it = effects.begin(); it != effects.end(); ++it) + { + if (it->first.mId == key) + { + runtime.push(1); + return; + } + } + runtime.push(0); + } }; template From 1f8ee9b8d1e86faed9172e61143e339b732790aa Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 3 Dec 2015 23:44:15 +0100 Subject: [PATCH 2682/3725] StateSetUpdater: use the frameNumber More robust in case a node is updated twice in the same frame (e.g. because it has multiple parents). --- components/sceneutil/statesetupdater.cpp | 7 +++---- components/sceneutil/statesetupdater.hpp | 3 +-- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/components/sceneutil/statesetupdater.cpp b/components/sceneutil/statesetupdater.cpp index 36aa683db..0e325082e 100644 --- a/components/sceneutil/statesetupdater.cpp +++ b/components/sceneutil/statesetupdater.cpp @@ -20,11 +20,10 @@ namespace SceneUtil } } - // Swap to make the StateSet in [0] writable, [1] is now the StateSet that was queued by the last frame - std::swap(mStateSets[0], mStateSets[1]); - node->setStateSet(mStateSets[0]); + osg::StateSet* stateset = mStateSets[nv->getTraversalNumber()%2]; + node->setStateSet(stateset); - apply(mStateSets[0], nv); + apply(stateset, nv); traverse(node, nv); } diff --git a/components/sceneutil/statesetupdater.hpp b/components/sceneutil/statesetupdater.hpp index 34b8da848..51398844c 100644 --- a/components/sceneutil/statesetupdater.hpp +++ b/components/sceneutil/statesetupdater.hpp @@ -12,8 +12,7 @@ namespace SceneUtil /// DYNAMIC data variance but that would undo all the benefits of the threading model - having the cull and draw /// traversals run in parallel can yield up to 200% framerates. /// @par Race conditions are prevented using a "double buffering" scheme - we have two StateSets that take turns, - /// the first StateSet is the one we can write to, the second is the one currently in use by the draw traversal of the last frame. - /// After a frame is completed the places are swapped. + /// one StateSet we can write to, the second one is currently in use by the draw traversal of the last frame. /// @par Must be set as UpdateCallback on a Node. /// @note Do not add the same StateSetUpdater to multiple nodes. /// @note Do not add multiple StateSetControllers on the same Node as they will conflict - instead use the CompositeStateSetUpdater. From 8e9571d155893a20b09adea1dae1e0d684fe65b5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 4 Dec 2015 00:06:22 +0100 Subject: [PATCH 2683/3725] Double buffer the light StateAttributes and StateSets Fixes a race condition where the position of a light could jump a frame ahead. --- apps/openmw/mwrender/animation.cpp | 32 ++++++++++++++++-------- components/sceneutil/lightcontroller.cpp | 2 +- components/sceneutil/lightmanager.cpp | 29 ++++++++++++--------- components/sceneutil/lightmanager.hpp | 23 +++++++++++------ 4 files changed, 54 insertions(+), 32 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 7a2cce7c9..ecfb2df14 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1091,8 +1091,7 @@ namespace MWRender } osg::ref_ptr lightSource = new SceneUtil::LightSource; - osg::Light* light = new osg::Light; - lightSource->setLight(light); + osg::ref_ptr light (new osg::Light); lightSource->setNodeMask(Mask_Lighting); const MWWorld::Fallback* fallback = MWBase::Environment::get().getWorld()->getFallback(); @@ -1123,6 +1122,8 @@ namespace MWRender light->setAmbient(osg::Vec4f(0,0,0,1)); light->setSpecular(osg::Vec4f(0,0,0,0)); + lightSource->setLight(light); + osg::ref_ptr ctrl (new SceneUtil::LightController); ctrl->setDiffuse(light->getDiffuse()); if (esmLight->mData.mFlags & ESM::Light::Flicker) @@ -1318,22 +1319,31 @@ namespace MWRender } else { - if (!mGlowLight) + effect += 3; + float radius = effect * 66.f; + float linearAttenuation = 0.5f / effect; + + if (!mGlowLight || linearAttenuation != mGlowLight->getLight(0)->getLinearAttenuation()) { - mGlowLight = new SceneUtil::LightSource; - mGlowLight->setLight(new osg::Light); - mGlowLight->setNodeMask(Mask_Lighting); - osg::Light* light = mGlowLight->getLight(); + if (mGlowLight) + { + mInsert->removeChild(mGlowLight); + mGlowLight = NULL; + } + + osg::ref_ptr light (new osg::Light); light->setDiffuse(osg::Vec4f(0,0,0,0)); light->setSpecular(osg::Vec4f(0,0,0,0)); light->setAmbient(osg::Vec4f(1.5f,1.5f,1.5f,1.f)); + light->setLinearAttenuation(linearAttenuation); + + mGlowLight = new SceneUtil::LightSource; + mGlowLight->setNodeMask(Mask_Lighting); mInsert->addChild(mGlowLight); + mGlowLight->setLight(light); } - effect += 3; - osg::Light* light = mGlowLight->getLight(); - mGlowLight->setRadius(effect * 66.f); - light->setLinearAttenuation(0.5f/effect); + mGlowLight->setRadius(radius); } } diff --git a/components/sceneutil/lightcontroller.cpp b/components/sceneutil/lightcontroller.cpp index ccfd836f7..d44a1a94a 100644 --- a/components/sceneutil/lightcontroller.cpp +++ b/components/sceneutil/lightcontroller.cpp @@ -118,7 +118,7 @@ namespace SceneUtil else if(mType == LT_PulseSlow) brightness = 0.7f + pulseAmplitude(mDeltaCount*slow)*0.3f; - static_cast(node)->getLight()->setDiffuse(mDiffuseColor * brightness); + static_cast(node)->getLight(nv->getTraversalNumber())->setDiffuse(mDiffuseColor * brightness); } void LightController::setDiffuse(osg::Vec4f color) diff --git a/components/sceneutil/lightmanager.cpp b/components/sceneutil/lightmanager.cpp index ba2f8c510..6a992c503 100644 --- a/components/sceneutil/lightmanager.cpp +++ b/components/sceneutil/lightmanager.cpp @@ -98,7 +98,7 @@ namespace SceneUtil throw std::runtime_error("can't find parent LightManager"); } - mLightManager->addLight(static_cast(node), osg::computeLocalToWorld(nv->getNodePath())); + mLightManager->addLight(static_cast(node), osg::computeLocalToWorld(nv->getNodePath()), nv->getTraversalNumber()); traverse(node, nv); } @@ -160,37 +160,42 @@ namespace SceneUtil mLightsInViewSpace.clear(); // do an occasional cleanup for orphaned lights - if (mStateSetCache.size() > 5000) - mStateSetCache.clear(); + for (int i=0; i<2; ++i) + { + if (mStateSetCache[i].size() > 5000) + mStateSetCache[i].clear(); + } } - void LightManager::addLight(LightSource* lightSource, const osg::Matrixf& worldMat) + void LightManager::addLight(LightSource* lightSource, const osg::Matrixf& worldMat, unsigned int frameNum) { LightSourceTransform l; l.mLightSource = lightSource; l.mWorldMatrix = worldMat; - lightSource->getLight()->setPosition(osg::Vec4f(worldMat.getTrans().x(), + lightSource->getLight(frameNum)->setPosition(osg::Vec4f(worldMat.getTrans().x(), worldMat.getTrans().y(), worldMat.getTrans().z(), 1.f)); mLights.push_back(l); } - osg::ref_ptr LightManager::getLightListStateSet(const LightList &lightList) + osg::ref_ptr LightManager::getLightListStateSet(const LightList &lightList, unsigned int frameNum) { // possible optimization: return a StateSet containing all requested lights plus some extra lights (if a suitable one exists) size_t hash = 0; for (unsigned int i=0; imLightSource->getId()); - LightStateSetMap::iterator found = mStateSetCache.find(hash); - if (found != mStateSetCache.end()) + LightStateSetMap& stateSetCache = mStateSetCache[frameNum%2]; + + LightStateSetMap::iterator found = stateSetCache.find(hash); + if (found != stateSetCache.end()) return found->second; else { std::vector > lights; for (unsigned int i=0; imLightSource->getLight()); + lights.push_back(lightList[i]->mLightSource->getLight(frameNum)); osg::ref_ptr attr = new LightStateAttribute(mStartLight, lights); @@ -200,7 +205,7 @@ namespace SceneUtil stateset->setAttribute(attr, osg::StateAttribute::ON); stateset->setAssociatedModes(attr, osg::StateAttribute::ON); - mStateSetCache.insert(std::make_pair(hash, stateset)); + stateSetCache.insert(std::make_pair(hash, stateset)); return stateset; } } @@ -348,10 +353,10 @@ namespace SceneUtil while (lightList.size() > maxLights) lightList.pop_back(); } - stateset = mLightManager->getLightListStateSet(lightList); + stateset = mLightManager->getLightListStateSet(lightList, nv->getTraversalNumber()); } else - stateset = mLightManager->getLightListStateSet(mLightList); + stateset = mLightManager->getLightListStateSet(mLightList, nv->getTraversalNumber()); cv->pushStateSet(stateset); diff --git a/components/sceneutil/lightmanager.hpp b/components/sceneutil/lightmanager.hpp index 89ffc1305..78703dfca 100644 --- a/components/sceneutil/lightmanager.hpp +++ b/components/sceneutil/lightmanager.hpp @@ -12,7 +12,7 @@ namespace SceneUtil /// LightSource managed by a LightManager. class LightSource : public osg::Node { - osg::ref_ptr mLight; + osg::ref_ptr mLight[2]; // The activation radius float mRadius; @@ -37,17 +37,24 @@ namespace SceneUtil mRadius = radius; } - osg::Light* getLight() + /// Get the osg::Light safe for modification in the given frame. + osg::Light* getLight(unsigned int frame) { - return mLight; + return mLight[frame % 2]; } + /// @warning It is recommended not to replace an existing osg::Light, because there might still be + /// references to it in the light StateSet cache that are associated with this LightSource's ID. + /// These references will stay valid due to ref_ptr but will point to the old object. + /// @warning Do not modify the \a light after you've called this function. void setLight(osg::Light* light) { - mLight = light; + mLight[0] = light; + mLight[1] = osg::clone(light); } - int getId() + /// Get the unique ID for this light source. + int getId() const { return mId; } @@ -77,7 +84,7 @@ namespace SceneUtil void update(); // Called automatically by the LightSource's UpdateCallback - void addLight(LightSource* lightSource, const osg::Matrixf& worldMat); + void addLight(LightSource* lightSource, const osg::Matrixf& worldMat, unsigned int frameNum); struct LightSourceTransform { @@ -97,7 +104,7 @@ namespace SceneUtil typedef std::vector LightList; - osg::ref_ptr getLightListStateSet(const LightList& lightList); + osg::ref_ptr getLightListStateSet(const LightList& lightList, unsigned int frameNum); /// Set the first light index that should be used by this manager, typically the number of directional lights in the scene. void setStartLight(int start); @@ -113,7 +120,7 @@ namespace SceneUtil // < Light list hash , StateSet > typedef std::map > LightStateSetMap; - LightStateSetMap mStateSetCache; + LightStateSetMap mStateSetCache[2]; int mStartLight; From 462ef617ce2b6ced2924773abdc225881f84a23d Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 4 Dec 2015 00:18:54 +0100 Subject: [PATCH 2684/3725] Don't read forward/backward values for Quaternion key lists https://forum.openmw.org/viewtopic.php?f=8&t=3201&p=35867#p35867 --- components/nif/nifkey.hpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/components/nif/nifkey.hpp b/components/nif/nifkey.hpp index 682baed05..75353044d 100644 --- a/components/nif/nifkey.hpp +++ b/components/nif/nifkey.hpp @@ -138,6 +138,11 @@ private: /*key.mBackwardValue = */(nif.*getValue)(); } + static void readQuadratic(NIFStream &nif, KeyT &key) + { + readValue(nif, key); + } + static void readTBC(NIFStream &nif, KeyT &key) { readValue(nif, key); From c442af09c5b040222e365748c5640e5b0e6357b4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 4 Dec 2015 00:55:32 +0100 Subject: [PATCH 2685/3725] Write more documentation for the lighting system --- components/sceneutil/lightmanager.hpp | 37 +++++++++++++++++++-------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/components/sceneutil/lightmanager.hpp b/components/sceneutil/lightmanager.hpp index 78703dfca..522455390 100644 --- a/components/sceneutil/lightmanager.hpp +++ b/components/sceneutil/lightmanager.hpp @@ -10,11 +10,19 @@ namespace SceneUtil { /// LightSource managed by a LightManager. + /// @par Typically used for point lights. Spot lights are not supported yet. Directional lights affect the whole scene + /// so do not need to be managed by a LightManager - so for directional lights use a plain osg::LightSource instead. + /// @note LightSources must be decorated by a LightManager node in order to have an effect. Typical use would + /// be one LightManager as the root of the scene graph. + /// @note One needs to attach LightListCallback's to the scene to have objects receive lighting from LightSources. + /// See the documentation of LightListCallback for more information. + /// @note The position of the contained osg::Light is automatically updated based on the LightSource's world position. class LightSource : public osg::Node { + // double buffered osg::Light's, since one of them may be in use by the draw thread at any given time osg::ref_ptr mLight[2]; - // The activation radius + // LightSource will affect objects within this radius float mRadius; int mId; @@ -32,12 +40,15 @@ namespace SceneUtil return mRadius; } + /// The LightSource will affect objects within this radius. void setRadius(float radius) { mRadius = radius; } /// Get the osg::Light safe for modification in the given frame. + /// @par May be used externally to animate the light's color/attenuation properties, + /// and is used internally to synchronize the light's position with the position of the LightSource. osg::Light* getLight(unsigned int frame) { return mLight[frame % 2]; @@ -60,8 +71,7 @@ namespace SceneUtil } }; - /// All light sources must be a child of the LightManager node. The LightManager can be anywhere in the scene graph, - /// but would be typically somewhere near the top. + /// @brief Decorator node implementing the rendering of any number of LightSources that can be anywhere in the subgraph. class LightManager : public osg::Group { public: @@ -80,10 +90,15 @@ namespace SceneUtil unsigned int getLightingMask() const; - // Called automatically by the UpdateCallback + /// Set the first light index that should be used by this manager, typically the number of directional lights in the scene. + void setStartLight(int start); + + int getStartLight() const; + + /// Internal use only, called automatically by the LightManager's UpdateCallback void update(); - // Called automatically by the LightSource's UpdateCallback + /// Internal use only, called automatically by the LightSource's UpdateCallback void addLight(LightSource* lightSource, const osg::Matrixf& worldMat, unsigned int frameNum); struct LightSourceTransform @@ -106,11 +121,6 @@ namespace SceneUtil osg::ref_ptr getLightListStateSet(const LightList& lightList, unsigned int frameNum); - /// Set the first light index that should be used by this manager, typically the number of directional lights in the scene. - void setStartLight(int start); - - int getStartLight() const; - private: // Lights collected from the scene graph. Only valid during the cull traversal. std::vector mLights; @@ -127,6 +137,13 @@ namespace SceneUtil unsigned int mLightingMask; }; + /// To receive lighting, objects must be decorated by a LightListCallback. Light list callbacks must be added via + /// node->addCullCallback(new LightListCallback). Once a light list callback is added to a node, that node and all + /// its child nodes can receive lighting. + /// @par The placement of these LightListCallbacks affects the granularity of light lists. Having too fine grained + /// light lists can result in degraded performance. Too coarse grained light lists can result in lights no longer + /// rendering when the size of a light list exceeds the OpenGL limit on the number of concurrent lights (8). A good + /// starting point is to attach a LightListCallback to each game object's base node. /// @note Not thread safe for CullThreadPerCamera threading mode. class LightListCallback : public osg::NodeCallback { From 4a9b37aa53a896726618f689edca8055ac5c208a Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 4 Dec 2015 18:08:14 +0100 Subject: [PATCH 2686/3725] Fix copy constructor issue --- components/sceneutil/lightmanager.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/components/sceneutil/lightmanager.cpp b/components/sceneutil/lightmanager.cpp index 6a992c503..1706bb2b1 100644 --- a/components/sceneutil/lightmanager.cpp +++ b/components/sceneutil/lightmanager.cpp @@ -260,10 +260,12 @@ namespace SceneUtil LightSource::LightSource(const LightSource ©, const osg::CopyOp ©op) : osg::Node(copy, copyop) - , mLight(copy.mLight) , mRadius(copy.mRadius) { mId = sLightId++; + + for (int i=0; i<2; ++i) + mLight[i] = osg::clone(copy.mLight[i].get(), copyop); } From 0975f60d594e8bfa906875bd2952d1493d784cd4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 14 Nov 2015 16:59:25 +0100 Subject: [PATCH 2687/3725] Stub out CellStore::get accessors in preparation of reference movement between cells --- apps/openmw/mwclass/activator.cpp | 3 +- apps/openmw/mwclass/apparatus.cpp | 3 +- apps/openmw/mwclass/armor.cpp | 3 +- apps/openmw/mwclass/book.cpp | 3 +- apps/openmw/mwclass/clothing.cpp | 3 +- apps/openmw/mwclass/container.cpp | 3 +- apps/openmw/mwclass/creature.cpp | 3 +- apps/openmw/mwclass/door.cpp | 3 +- apps/openmw/mwclass/ingredient.cpp | 3 +- apps/openmw/mwclass/light.cpp | 3 +- apps/openmw/mwclass/lockpick.cpp | 3 +- apps/openmw/mwclass/misc.cpp | 2 + apps/openmw/mwclass/npc.cpp | 3 +- apps/openmw/mwclass/potion.cpp | 3 +- apps/openmw/mwclass/probe.cpp | 3 +- apps/openmw/mwclass/repair.cpp | 3 +- apps/openmw/mwclass/static.cpp | 3 +- apps/openmw/mwclass/weapon.cpp | 3 +- apps/openmw/mwmechanics/obstacle.cpp | 2 + apps/openmw/mwworld/cellstore.hpp | 159 +-------------------------- apps/openmw/mwworld/localscripts.cpp | 2 + apps/openmw/mwworld/worldimp.cpp | 20 +++- 22 files changed, 60 insertions(+), 176 deletions(-) diff --git a/apps/openmw/mwclass/activator.cpp b/apps/openmw/mwclass/activator.cpp index 3a0f1b951..fdbff026f 100644 --- a/apps/openmw/mwclass/activator.cpp +++ b/apps/openmw/mwclass/activator.cpp @@ -130,6 +130,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return MWWorld::Ptr(&cell.get().insert(*ref), &cell); + return MWWorld::Ptr(); + //return MWWorld::Ptr(&cell.get().insert(*ref), &cell); } } diff --git a/apps/openmw/mwclass/apparatus.cpp b/apps/openmw/mwclass/apparatus.cpp index f93556ef9..06eea2c24 100644 --- a/apps/openmw/mwclass/apparatus.cpp +++ b/apps/openmw/mwclass/apparatus.cpp @@ -147,8 +147,9 @@ namespace MWClass { MWWorld::LiveCellRef *ref = ptr.get(); + return MWWorld::Ptr(); - return MWWorld::Ptr(&cell.get().insert(*ref), &cell); + //return MWWorld::Ptr(&cell.get().insert(*ref), &cell); } bool Apparatus::canSell (const MWWorld::Ptr& item, int npcServices) const diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index 324dd32ee..9ad28a537 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -381,8 +381,9 @@ namespace MWClass { MWWorld::LiveCellRef *ref = ptr.get(); + return MWWorld::Ptr(); - return MWWorld::Ptr(&cell.get().insert(*ref), &cell); + //return MWWorld::Ptr(&cell.get().insert(*ref), &cell); } int Armor::getEnchantmentPoints (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index 2c20435b2..cfa2508c4 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -186,8 +186,9 @@ namespace MWClass { MWWorld::LiveCellRef *ref = ptr.get(); + return MWWorld::Ptr(); - return MWWorld::Ptr(&cell.get().insert(*ref), &cell); + //return MWWorld::Ptr(&cell.get().insert(*ref), &cell); } int Book::getEnchantmentPoints (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index cea30d561..8bd3fd2e6 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -275,8 +275,9 @@ namespace MWClass { MWWorld::LiveCellRef *ref = ptr.get(); + return MWWorld::Ptr(); - return MWWorld::Ptr(&cell.get().insert(*ref), &cell); + //return MWWorld::Ptr(&cell.get().insert(*ref), &cell); } int Clothing::getEnchantmentPoints (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index 6c44c97e2..b82dff706 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -292,8 +292,9 @@ namespace MWClass { MWWorld::LiveCellRef *ref = ptr.get(); + return MWWorld::Ptr(); - return MWWorld::Ptr(&cell.get().insert(*ref), &cell); + //return MWWorld::Ptr(&cell.get().insert(*ref), &cell); } void Container::readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state) const diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 2cd11d113..7f43f8677 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -599,8 +599,9 @@ namespace MWClass { MWWorld::LiveCellRef *ref = ptr.get(); + return MWWorld::Ptr(); - return MWWorld::Ptr(&cell.get().insert(*ref), &cell); + //return MWWorld::Ptr(&cell.get().insert(*ref), &cell); } bool Creature::isBipedal(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 6fee79ddf..cb9f59e96 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -309,8 +309,9 @@ namespace MWClass { MWWorld::LiveCellRef *ref = ptr.get(); + return MWWorld::Ptr(); - return MWWorld::Ptr(&cell.get().insert(*ref), &cell); + //return MWWorld::Ptr(&cell.get().insert(*ref), &cell); } void Door::ensureCustomData(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/ingredient.cpp b/apps/openmw/mwclass/ingredient.cpp index c9e6e70f2..0b6724c6c 100644 --- a/apps/openmw/mwclass/ingredient.cpp +++ b/apps/openmw/mwclass/ingredient.cpp @@ -184,8 +184,9 @@ namespace MWClass { MWWorld::LiveCellRef *ref = ptr.get(); + return MWWorld::Ptr(); - return MWWorld::Ptr(&cell.get().insert(*ref), &cell); + //return MWWorld::Ptr(&cell.get().insert(*ref), &cell); } bool Ingredient::canSell (const MWWorld::Ptr& item, int npcServices) const diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 34d93da67..0442fd2e0 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -216,8 +216,9 @@ namespace MWClass { MWWorld::LiveCellRef *ref = ptr.get(); + return MWWorld::Ptr(); - return MWWorld::Ptr(&cell.get().insert(*ref), &cell); + //return MWWorld::Ptr(&cell.get().insert(*ref), &cell); } bool Light::canSell (const MWWorld::Ptr& item, int npcServices) const diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index 5cffdf13a..bd17a527b 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -165,8 +165,9 @@ namespace MWClass { MWWorld::LiveCellRef *ref = ptr.get(); + return MWWorld::Ptr(); - return MWWorld::Ptr(&cell.get().insert(*ref), &cell); + //return MWWorld::Ptr(&cell.get().insert(*ref), &cell); } bool Lockpick::canSell (const MWWorld::Ptr& item, int npcServices) const diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index 98b4faab9..16d926f5e 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -194,6 +194,7 @@ namespace MWClass { MWWorld::Ptr newPtr; + /* const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); @@ -223,6 +224,7 @@ namespace MWClass ptr.get(); newPtr = MWWorld::Ptr(&cell.get().insert(*ref), &cell); } + */ return newPtr; } diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 6633b3490..b5f2b52f3 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -1129,8 +1129,9 @@ namespace MWClass { MWWorld::LiveCellRef *ref = ptr.get(); + return MWWorld::Ptr(); - return MWWorld::Ptr(&cell.get().insert(*ref), &cell); + //return MWWorld::Ptr(&cell.get().insert(*ref), &cell); } int Npc::getSkill(const MWWorld::Ptr& ptr, int skill) const diff --git a/apps/openmw/mwclass/potion.cpp b/apps/openmw/mwclass/potion.cpp index cf6b0919b..0f449fa92 100644 --- a/apps/openmw/mwclass/potion.cpp +++ b/apps/openmw/mwclass/potion.cpp @@ -177,8 +177,9 @@ namespace MWClass { MWWorld::LiveCellRef *ref = ptr.get(); + return MWWorld::Ptr(); - return MWWorld::Ptr(&cell.get().insert(*ref), &cell); + //return MWWorld::Ptr(&cell.get().insert(*ref), &cell); } bool Potion::canSell (const MWWorld::Ptr& item, int npcServices) const diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index ff717c506..80825466a 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -164,8 +164,9 @@ namespace MWClass { MWWorld::LiveCellRef *ref = ptr.get(); + return MWWorld::Ptr(); - return MWWorld::Ptr(&cell.get().insert(*ref), &cell); + //return MWWorld::Ptr(&cell.get().insert(*ref), &cell); } bool Probe::canSell (const MWWorld::Ptr& item, int npcServices) const diff --git a/apps/openmw/mwclass/repair.cpp b/apps/openmw/mwclass/repair.cpp index e6baea2e0..993c39aa2 100644 --- a/apps/openmw/mwclass/repair.cpp +++ b/apps/openmw/mwclass/repair.cpp @@ -159,8 +159,9 @@ namespace MWClass { MWWorld::LiveCellRef *ref = ptr.get(); + return MWWorld::Ptr(); - return MWWorld::Ptr(&cell.get().insert(*ref), &cell); + //return MWWorld::Ptr(&cell.get().insert(*ref), &cell); } boost::shared_ptr Repair::use (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/static.cpp b/apps/openmw/mwclass/static.cpp index 9755df28e..ae0b5d3dd 100644 --- a/apps/openmw/mwclass/static.cpp +++ b/apps/openmw/mwclass/static.cpp @@ -59,7 +59,8 @@ namespace MWClass { MWWorld::LiveCellRef *ref = ptr.get(); + return MWWorld::Ptr(); - return MWWorld::Ptr(&cell.get().insert(*ref), &cell); + //return MWWorld::Ptr(&cell.get().insert(*ref), &cell); } } diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index da4c7deb2..15c0039a4 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -417,7 +417,8 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return MWWorld::Ptr(&cell.get().insert(*ref), &cell); + return MWWorld::Ptr(); + //return MWWorld::Ptr(&cell.get().insert(*ref), &cell); } int Weapon::getEnchantmentPoints (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwmechanics/obstacle.cpp b/apps/openmw/mwmechanics/obstacle.cpp index dae5f8496..a2cbae2a0 100644 --- a/apps/openmw/mwmechanics/obstacle.cpp +++ b/apps/openmw/mwmechanics/obstacle.cpp @@ -44,6 +44,7 @@ namespace MWMechanics return MWWorld::Ptr(); // check interior cells only // Check all the doors in this cell + /* MWWorld::CellRefList& doors = cell->get(); MWWorld::CellRefList::List& refList = doors.mList; MWWorld::CellRefList::List::iterator it = refList.begin(); @@ -66,6 +67,7 @@ namespace MWMechanics return MWWorld::Ptr(&ref, actor.getCell()); // found, stop searching } } + */ return MWWorld::Ptr(); // none found } diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index f88bf0958..89b200262 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -73,6 +73,7 @@ namespace MWWorld MWWorld::TimeStamp mLastRespawn; + // List of refs owned by this cell CellRefList mActivators; CellRefList mPotions; CellRefList mAppas; @@ -179,6 +180,8 @@ namespace MWWorld forEachImp (functor, mNpcs); } + /// \todo add const version of forEach + bool isExterior() const; Ptr searchInContainer (const std::string& id); @@ -198,16 +201,6 @@ namespace MWWorld void respawn (); ///< Check mLastRespawn and respawn references if necessary. This is a no-op if the cell is not loaded. - template - CellRefList& get() { - throw std::runtime_error ("Storage for type " + std::string(typeid(T).name())+ " does not exist in cells"); - } - - template - const CellRefList& getReadOnly() { - throw std::runtime_error ("Read Only CellRefList access not available for type " + std::string(typeid(T).name()) ); - } - bool isPointConnected(const int start, const int end) const; std::list aStarSearch(const int start, const int end) const; @@ -241,152 +234,6 @@ namespace MWWorld MWMechanics::PathgridGraph mPathgridGraph; }; - template<> - inline CellRefList& CellStore::get() - { - mHasState = true; - return mActivators; - } - - template<> - inline CellRefList& CellStore::get() - { - mHasState = true; - return mPotions; - } - - template<> - inline CellRefList& CellStore::get() - { - mHasState = true; - return mAppas; - } - - template<> - inline CellRefList& CellStore::get() - { - mHasState = true; - return mArmors; - } - - template<> - inline CellRefList& CellStore::get() - { - mHasState = true; - return mBooks; - } - - template<> - inline CellRefList& CellStore::get() - { - mHasState = true; - return mClothes; - } - - template<> - inline CellRefList& CellStore::get() - { - mHasState = true; - return mContainers; - } - - template<> - inline CellRefList& CellStore::get() - { - mHasState = true; - return mCreatures; - } - - template<> - inline CellRefList& CellStore::get() - { - mHasState = true; - return mDoors; - } - - template<> - inline CellRefList& CellStore::get() - { - mHasState = true; - return mIngreds; - } - - template<> - inline CellRefList& CellStore::get() - { - mHasState = true; - return mCreatureLists; - } - - template<> - inline CellRefList& CellStore::get() - { - mHasState = true; - return mItemLists; - } - - template<> - inline CellRefList& CellStore::get() - { - mHasState = true; - return mLights; - } - - template<> - inline CellRefList& CellStore::get() - { - mHasState = true; - return mLockpicks; - } - - template<> - inline CellRefList& CellStore::get() - { - mHasState = true; - return mMiscItems; - } - - template<> - inline CellRefList& CellStore::get() - { - mHasState = true; - return mNpcs; - } - - template<> - inline CellRefList& CellStore::get() - { - mHasState = true; - return mProbes; - } - - template<> - inline CellRefList& CellStore::get() - { - mHasState = true; - return mRepairs; - } - - template<> - inline CellRefList& CellStore::get() - { - mHasState = true; - return mStatics; - } - - template<> - inline CellRefList& CellStore::get() - { - mHasState = true; - return mWeapons; - } - - template<> - inline const CellRefList& CellStore::getReadOnly() - { - return mDoors; - } - bool operator== (const CellStore& left, const CellStore& right); bool operator!= (const CellStore& left, const CellStore& right); } diff --git a/apps/openmw/mwworld/localscripts.cpp b/apps/openmw/mwworld/localscripts.cpp index e30246f7c..aa5abc076 100644 --- a/apps/openmw/mwworld/localscripts.cpp +++ b/apps/openmw/mwworld/localscripts.cpp @@ -116,6 +116,7 @@ void MWWorld::LocalScripts::add (const std::string& scriptName, const Ptr& ptr) void MWWorld::LocalScripts::addCell (CellStore *cell) { + /* listCellScripts (*this, cell->get(), cell); listCellScripts (*this, cell->get(), cell); listCellScripts (*this, cell->get(), cell); @@ -136,6 +137,7 @@ void MWWorld::LocalScripts::addCell (CellStore *cell) listCellScripts (*this, cell->get(), cell); listCellScripts (*this, cell->get(), cell); listCellScripts (*this, cell->get(), cell); + */ } void MWWorld::LocalScripts::clear() diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 22485ed92..950c38e76 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1693,6 +1693,7 @@ namespace MWWorld osg::Vec2f World::getNorthVector (CellStore* cell) { + /* MWWorld::CellRefList& statics = cell->get(); MWWorld::LiveCellRef* ref = statics.find("northmarker"); if (!ref) @@ -1702,10 +1703,13 @@ namespace MWWorld osg::Vec3f dir = orient * osg::Vec3f(0,1,0); osg::Vec2f d (dir.x(), dir.y()); return d; + */ + return osg::Vec2f(); } void World::getDoorMarkers (CellStore* cell, std::vector& out) { + /* MWWorld::CellRefList& doors = cell->get(); CellRefList::List& refList = doors.mList; for (CellRefList::List::iterator it = refList.begin(); it != refList.end(); ++it) @@ -1744,6 +1748,7 @@ namespace MWWorld out.push_back(newMarker); } } + */ } void World::setWaterHeight(const float height) @@ -2240,6 +2245,7 @@ namespace MWWorld void World::getContainersOwnedBy (const MWWorld::Ptr& npc, std::vector& out) { + /* const Scene::CellStoreCollection& collection = mWorldScene->getActiveCells(); for (Scene::CellStoreCollection::const_iterator cellIt = collection.begin(); cellIt != collection.end(); ++cellIt) { @@ -2254,6 +2260,7 @@ namespace MWWorld out.push_back(ptr); } } + */ } struct ListObjectsFunctor @@ -2316,6 +2323,8 @@ namespace MWWorld bool World::findInteriorPosition(const std::string &name, ESM::Position &pos) { + return false; + /* typedef MWWorld::CellRefList::List DoorList; typedef MWWorld::CellRefList::List StaticList; @@ -2368,6 +2377,7 @@ namespace MWWorld pos = statics.begin()->mRef.getPosition(); return true; } + */ return false; } @@ -2715,6 +2725,8 @@ namespace MWWorld bool World::findInteriorPositionInWorldSpace(MWWorld::CellStore* cell, osg::Vec3f& result) { + return false; + /* if (cell->isExterior()) return false; @@ -2732,7 +2744,7 @@ namespace MWWorld MWWorld::CellStore *next = getInterior( *i ); if ( !next ) continue; - const MWWorld::CellRefList& doors = next->getReadOnly(); + const MWWorld::CellRefList& doors = next->getReadOnlyDoors(); const CellRefList::List& refList = doors.mList; // Check if any door in the cell leads to an exterior directly @@ -2761,10 +2773,12 @@ namespace MWWorld // No luck :( return false; + */ } MWWorld::Ptr World::getClosestMarker( const MWWorld::Ptr &ptr, const std::string &id ) { + /* if ( ptr.getCell()->isExterior() ) { return getClosestMarkerFromExteriorPosition(mPlayer->getLastKnownExteriorPosition(), id); } @@ -2792,7 +2806,7 @@ namespace MWWorld return closestMarker; } - const MWWorld::CellRefList& doors = next->getReadOnly(); + const MWWorld::CellRefList& doors = next->getReadOnlyDoors(); const CellRefList::List& doorList = doors.mList; // Check if any door in the cell leads to an exterior directly @@ -2816,7 +2830,7 @@ namespace MWWorld } } } - + */ return MWWorld::Ptr(); } From fc449233bebb6c6864ca284a6c8cd0d307d8a3c2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 14 Nov 2015 17:12:05 +0100 Subject: [PATCH 2688/3725] Restore support for inserting objects into a cell --- apps/openmw/mwclass/activator.cpp | 3 +- apps/openmw/mwclass/apparatus.cpp | 3 +- apps/openmw/mwclass/armor.cpp | 3 +- apps/openmw/mwclass/book.cpp | 3 +- apps/openmw/mwclass/clothing.cpp | 3 +- apps/openmw/mwclass/container.cpp | 3 +- apps/openmw/mwclass/creature.cpp | 3 +- apps/openmw/mwclass/door.cpp | 3 +- apps/openmw/mwclass/ingredient.cpp | 3 +- apps/openmw/mwclass/light.cpp | 3 +- apps/openmw/mwclass/lockpick.cpp | 3 +- apps/openmw/mwclass/misc.cpp | 7 +- apps/openmw/mwclass/npc.cpp | 3 +- apps/openmw/mwclass/potion.cpp | 3 +- apps/openmw/mwclass/probe.cpp | 3 +- apps/openmw/mwclass/repair.cpp | 3 +- apps/openmw/mwclass/static.cpp | 3 +- apps/openmw/mwclass/weapon.cpp | 3 +- apps/openmw/mwworld/cellstore.hpp | 125 +++++++++++++++++++++++++++++ 19 files changed, 145 insertions(+), 38 deletions(-) diff --git a/apps/openmw/mwclass/activator.cpp b/apps/openmw/mwclass/activator.cpp index fdbff026f..17757cb6b 100644 --- a/apps/openmw/mwclass/activator.cpp +++ b/apps/openmw/mwclass/activator.cpp @@ -130,7 +130,6 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return MWWorld::Ptr(); - //return MWWorld::Ptr(&cell.get().insert(*ref), &cell); + return MWWorld::Ptr(cell.insert(ref), &cell); } } diff --git a/apps/openmw/mwclass/apparatus.cpp b/apps/openmw/mwclass/apparatus.cpp index 06eea2c24..07bf25086 100644 --- a/apps/openmw/mwclass/apparatus.cpp +++ b/apps/openmw/mwclass/apparatus.cpp @@ -147,9 +147,8 @@ namespace MWClass { MWWorld::LiveCellRef *ref = ptr.get(); - return MWWorld::Ptr(); - //return MWWorld::Ptr(&cell.get().insert(*ref), &cell); + return MWWorld::Ptr(cell.insert(ref), &cell); } bool Apparatus::canSell (const MWWorld::Ptr& item, int npcServices) const diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index 9ad28a537..631ddd912 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -381,9 +381,8 @@ namespace MWClass { MWWorld::LiveCellRef *ref = ptr.get(); - return MWWorld::Ptr(); - //return MWWorld::Ptr(&cell.get().insert(*ref), &cell); + return MWWorld::Ptr(cell.insert(ref), &cell); } int Armor::getEnchantmentPoints (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index cfa2508c4..9ea9e659b 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -186,9 +186,8 @@ namespace MWClass { MWWorld::LiveCellRef *ref = ptr.get(); - return MWWorld::Ptr(); - //return MWWorld::Ptr(&cell.get().insert(*ref), &cell); + return MWWorld::Ptr(cell.insert(ref), &cell); } int Book::getEnchantmentPoints (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index 8bd3fd2e6..7250e1837 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -275,9 +275,8 @@ namespace MWClass { MWWorld::LiveCellRef *ref = ptr.get(); - return MWWorld::Ptr(); - //return MWWorld::Ptr(&cell.get().insert(*ref), &cell); + return MWWorld::Ptr(cell.insert(ref), &cell); } int Clothing::getEnchantmentPoints (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index b82dff706..9e8c018cd 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -292,9 +292,8 @@ namespace MWClass { MWWorld::LiveCellRef *ref = ptr.get(); - return MWWorld::Ptr(); - //return MWWorld::Ptr(&cell.get().insert(*ref), &cell); + return MWWorld::Ptr(cell.insert(ref), &cell); } void Container::readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state) const diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 7f43f8677..e5a98c889 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -599,9 +599,8 @@ namespace MWClass { MWWorld::LiveCellRef *ref = ptr.get(); - return MWWorld::Ptr(); - //return MWWorld::Ptr(&cell.get().insert(*ref), &cell); + return MWWorld::Ptr(cell.insert(ref), &cell); } bool Creature::isBipedal(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index cb9f59e96..d0448f7ec 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -309,9 +309,8 @@ namespace MWClass { MWWorld::LiveCellRef *ref = ptr.get(); - return MWWorld::Ptr(); - //return MWWorld::Ptr(&cell.get().insert(*ref), &cell); + return MWWorld::Ptr(cell.insert(ref), &cell); } void Door::ensureCustomData(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/ingredient.cpp b/apps/openmw/mwclass/ingredient.cpp index 0b6724c6c..db2f2410b 100644 --- a/apps/openmw/mwclass/ingredient.cpp +++ b/apps/openmw/mwclass/ingredient.cpp @@ -184,9 +184,8 @@ namespace MWClass { MWWorld::LiveCellRef *ref = ptr.get(); - return MWWorld::Ptr(); - //return MWWorld::Ptr(&cell.get().insert(*ref), &cell); + return MWWorld::Ptr(cell.insert(ref), &cell); } bool Ingredient::canSell (const MWWorld::Ptr& item, int npcServices) const diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 0442fd2e0..fe5149077 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -216,9 +216,8 @@ namespace MWClass { MWWorld::LiveCellRef *ref = ptr.get(); - return MWWorld::Ptr(); - //return MWWorld::Ptr(&cell.get().insert(*ref), &cell); + return MWWorld::Ptr(cell.insert(ref), &cell); } bool Light::canSell (const MWWorld::Ptr& item, int npcServices) const diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index bd17a527b..63f75a845 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -165,9 +165,8 @@ namespace MWClass { MWWorld::LiveCellRef *ref = ptr.get(); - return MWWorld::Ptr(); - //return MWWorld::Ptr(&cell.get().insert(*ref), &cell); + return MWWorld::Ptr(cell.insert(ref), &cell); } bool Lockpick::canSell (const MWWorld::Ptr& item, int npcServices) const diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index 16d926f5e..a14ab3330 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -194,7 +194,6 @@ namespace MWClass { MWWorld::Ptr newPtr; - /* const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); @@ -216,15 +215,15 @@ namespace MWClass MWWorld::ManualRef newRef(store, base); MWWorld::LiveCellRef *ref = newRef.getPtr().get(); - newPtr = MWWorld::Ptr(&cell.get().insert(*ref), &cell); + + newPtr = MWWorld::Ptr(cell.insert(ref), &cell); newPtr.getCellRef().setGoldValue(goldAmount); newPtr.getRefData().setCount(1); } else { MWWorld::LiveCellRef *ref = ptr.get(); - newPtr = MWWorld::Ptr(&cell.get().insert(*ref), &cell); + newPtr = MWWorld::Ptr(cell.insert(ref), &cell); } - */ return newPtr; } diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index b5f2b52f3..7ab95bffa 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -1129,9 +1129,8 @@ namespace MWClass { MWWorld::LiveCellRef *ref = ptr.get(); - return MWWorld::Ptr(); - //return MWWorld::Ptr(&cell.get().insert(*ref), &cell); + return MWWorld::Ptr(cell.insert(ref), &cell); } int Npc::getSkill(const MWWorld::Ptr& ptr, int skill) const diff --git a/apps/openmw/mwclass/potion.cpp b/apps/openmw/mwclass/potion.cpp index 0f449fa92..20a849019 100644 --- a/apps/openmw/mwclass/potion.cpp +++ b/apps/openmw/mwclass/potion.cpp @@ -177,9 +177,8 @@ namespace MWClass { MWWorld::LiveCellRef *ref = ptr.get(); - return MWWorld::Ptr(); - //return MWWorld::Ptr(&cell.get().insert(*ref), &cell); + return MWWorld::Ptr(cell.insert(ref), &cell); } bool Potion::canSell (const MWWorld::Ptr& item, int npcServices) const diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index 80825466a..79f423b30 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -164,9 +164,8 @@ namespace MWClass { MWWorld::LiveCellRef *ref = ptr.get(); - return MWWorld::Ptr(); - //return MWWorld::Ptr(&cell.get().insert(*ref), &cell); + return MWWorld::Ptr(cell.insert(ref), &cell); } bool Probe::canSell (const MWWorld::Ptr& item, int npcServices) const diff --git a/apps/openmw/mwclass/repair.cpp b/apps/openmw/mwclass/repair.cpp index 993c39aa2..78ec2adcc 100644 --- a/apps/openmw/mwclass/repair.cpp +++ b/apps/openmw/mwclass/repair.cpp @@ -159,9 +159,8 @@ namespace MWClass { MWWorld::LiveCellRef *ref = ptr.get(); - return MWWorld::Ptr(); - //return MWWorld::Ptr(&cell.get().insert(*ref), &cell); + return MWWorld::Ptr(cell.insert(ref), &cell); } boost::shared_ptr Repair::use (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/static.cpp b/apps/openmw/mwclass/static.cpp index ae0b5d3dd..86019a5ad 100644 --- a/apps/openmw/mwclass/static.cpp +++ b/apps/openmw/mwclass/static.cpp @@ -59,8 +59,7 @@ namespace MWClass { MWWorld::LiveCellRef *ref = ptr.get(); - return MWWorld::Ptr(); - //return MWWorld::Ptr(&cell.get().insert(*ref), &cell); + return MWWorld::Ptr(cell.insert(ref), &cell); } } diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index 15c0039a4..5665bf1c4 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -417,8 +417,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return MWWorld::Ptr(); - //return MWWorld::Ptr(&cell.get().insert(*ref), &cell); + return MWWorld::Ptr(cell.insert(ref), &cell); } int Weapon::getEnchantmentPoints (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index 89b200262..8bf4d0ae9 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -97,6 +97,9 @@ namespace MWWorld public: + template + LiveCellRefBase* insert(const LiveCellRef* ref); + CellStore (const ESM::Cell *cell_); const ESM::Cell *getCell() const; @@ -234,6 +237,128 @@ namespace MWWorld MWMechanics::PathgridGraph mPathgridGraph; }; + + template<> + inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + { + mHasState = true; + return &mActivators.insert(*ref); + } + template<> + inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + { + mHasState = true; + return &mPotions.insert(*ref); + } + template<> + inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + { + mHasState = true; + return &mAppas.insert(*ref); + } + template<> + inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + { + mHasState = true; + return &mArmors.insert(*ref); + } + template<> + inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + { + mHasState = true; + return &mBooks.insert(*ref); + } + template<> + inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + { + mHasState = true; + return &mClothes.insert(*ref); + } + template<> + inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + { + mHasState = true; + return &mContainers.insert(*ref); + } + template<> + inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + { + mHasState = true; + return &mCreatures.insert(*ref); + } + template<> + inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + { + mHasState = true; + return &mDoors.insert(*ref); + } + template<> + inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + { + mHasState = true; + return &mIngreds.insert(*ref); + } + template<> + inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + { + mHasState = true; + return &mCreatureLists.insert(*ref); + } + template<> + inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + { + mHasState = true; + return &mItemLists.insert(*ref); + } + template<> + inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + { + mHasState = true; + return &mLights.insert(*ref); + } + template<> + inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + { + mHasState = true; + return &mLockpicks.insert(*ref); + } + template<> + inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + { + mHasState = true; + return &mMiscItems.insert(*ref); + } + template<> + inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + { + mHasState = true; + return &mNpcs.insert(*ref); + } + template<> + inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + { + mHasState = true; + return &mProbes.insert(*ref); + } + template<> + inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + { + mHasState = true; + return &mRepairs.insert(*ref); + } + template<> + inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + { + mHasState = true; + return &mStatics.insert(*ref); + } + template<> + inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + { + mHasState = true; + return &mWeapons.insert(*ref); + } + bool operator== (const CellStore& left, const CellStore& right); bool operator!= (const CellStore& left, const CellStore& right); } From 7a983340bfd3502e500c6fe76e4b1005adc480cf Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 14 Nov 2015 17:25:00 +0100 Subject: [PATCH 2689/3725] Add comment --- apps/openmw/mwworld/cellstore.hpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index 8bf4d0ae9..979316efc 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -97,6 +97,9 @@ namespace MWWorld public: + /// Make a copy of the given object and insert it into this cell. + /// @note If you get a linker error here, this means the given type can not be inserted into a cell. + /// The supported types are defined at the bottom of this file. template LiveCellRefBase* insert(const LiveCellRef* ref); From 64b4926127a7b7780213fa0feaac7b1c47a69487 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 14 Nov 2015 17:44:16 +0100 Subject: [PATCH 2690/3725] Add reference moving logic - untested --- apps/openmw/mwworld/cellstore.cpp | 48 ++++++++++++++++++++++++++++++- apps/openmw/mwworld/cellstore.hpp | 21 ++++++++++++++ 2 files changed, 68 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 5832a6727..e3ee7d249 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -179,8 +179,54 @@ namespace MWWorld return (ref.mRef.mRefnum == pRefnum); } + void CellStore::moveFrom(const Ptr &object, CellStore *from) + { + MovedRefTracker::iterator found = mMovedToAnotherCell.find(object.getBase()); + if (found != mMovedToAnotherCell.end()) + { + // A cell we had previously moved an object to is returning it to us. + assert (found->second == from); + mMovedToAnotherCell.erase(found); + } + else + { + mMovedHere.insert(std::make_pair(object.getBase(), from)); + } + } + + void CellStore::moveTo(const Ptr &object, CellStore *cellToMoveTo) + { + MovedRefTracker::iterator found = mMovedHere.find(object.getBase()); + if (found != mMovedHere.end()) + { + // Special case - object didn't originate in this cell + // Move it back to its original cell first + CellStore* originalCell = found->second; + assert (originalCell != this); + originalCell->moveFrom(object, this); + + mMovedHere.erase(found); + + // Now that object is back to its rightful owner, we can move it + originalCell->moveTo(object, cellToMoveTo); + + updateMergedRefs(); + return; + } + + cellToMoveTo->moveFrom(object, this); + mMovedToAnotherCell.insert(std::make_pair(object.getBase(), cellToMoveTo)); + + updateMergedRefs(); + } + + void CellStore::updateMergedRefs() + { + + } + CellStore::CellStore (const ESM::Cell *cell) - : mCell (cell), mState (State_Unloaded), mHasState (false), mLastRespawn(0,0) + : mCell (cell), mState (State_Unloaded), mHasState (false), mLastRespawn(0,0) { mWaterLevel = cell->mWater; } diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index 979316efc..ef1192277 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -95,8 +95,29 @@ namespace MWWorld CellRefList mStatics; CellRefList mWeapons; + typedef std::map MovedRefTracker; + // References owned by a different cell that have been moved here. + // + MovedRefTracker mMovedHere; + // References owned by this cell that have been moved to another cell. + // + MovedRefTracker mMovedToAnotherCell; + + // Merged list of ref's currently in this cell - i.e. with added refs from mMovedHere, removed refs from mMovedToAnotherCell + std::vector mMergedRefs; + + /// Moves object from the given cell to this cell. + void moveFrom(const MWWorld::Ptr& object, MWWorld::CellStore* from); + + /// Repopulate mMergedRefs. + void updateMergedRefs(); + public: + /// Moves object from this cell to the given cell. + /// @note automatically updates given cell by calling cellToMoveTo->moveFrom(...) + void moveTo(const MWWorld::Ptr& object, MWWorld::CellStore* cellToMoveTo); + /// Make a copy of the given object and insert it into this cell. /// @note If you get a linker error here, this means the given type can not be inserted into a cell. /// The supported types are defined at the bottom of this file. From 3aa53f3cb4cacbe9f88fe71dec800b6177c84ed3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 4 Dec 2015 19:46:02 +0100 Subject: [PATCH 2691/3725] Object cell movement tracker works. Savegame handling is still missing and some game functionality is still stubbed out. --- apps/openmw/mwworld/cellstore.cpp | 178 ++++++++++++++++++------------ apps/openmw/mwworld/cellstore.hpp | 175 +++++++++++++++-------------- apps/openmw/mwworld/scene.cpp | 16 ++- apps/openmw/mwworld/worldimp.cpp | 11 +- 4 files changed, 214 insertions(+), 166 deletions(-) diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index e3ee7d249..d56baf231 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -47,13 +47,16 @@ namespace template MWWorld::Ptr searchViaActorId (MWWorld::CellRefList& actorList, int actorId, - MWWorld::CellStore *cell) + MWWorld::CellStore *cell, const std::map& toIgnore) { for (typename MWWorld::CellRefList::List::iterator iter (actorList.mList.begin()); iter!=actorList.mList.end(); ++iter) { MWWorld::Ptr actor (&*iter, cell); + if (toIgnore.find(&*iter) != toIgnore.end()) + continue; + if (actor.getClass().getCreatureStats (actor).matchesActorId (actorId) && actor.getRefData().getCount() > 0) return actor; } @@ -181,6 +184,7 @@ namespace MWWorld void CellStore::moveFrom(const Ptr &object, CellStore *from) { + mHasState = true; MovedRefTracker::iterator found = mMovedToAnotherCell.find(object.getBase()); if (found != mMovedToAnotherCell.end()) { @@ -192,10 +196,27 @@ namespace MWWorld { mMovedHere.insert(std::make_pair(object.getBase(), from)); } + + if (mState == State_Loaded) + updateMergedRefs(); + else if (mState == State_Preloaded) + { + mIds.push_back(object.getCellRef().getRefId()); + std::sort(mIds.begin(), mIds.end()); + } } - void CellStore::moveTo(const Ptr &object, CellStore *cellToMoveTo) + MWWorld::Ptr CellStore::moveTo(const Ptr &object, CellStore *cellToMoveTo) { + if (cellToMoveTo == this) + throw std::runtime_error("object is already in this cell"); + + // We assume that *this is in State_Loaded since we could hardly have reference to a live object otherwise. + if (mState != State_Loaded) + throw std::runtime_error("can't move object from a non-loaded cell (how did you get this object anyway?)"); + + // TODO: ensure that the object actually exists in the cell + MovedRefTracker::iterator found = mMovedHere.find(object.getBase()); if (found != mMovedHere.end()) { @@ -208,21 +229,59 @@ namespace MWWorld mMovedHere.erase(found); // Now that object is back to its rightful owner, we can move it - originalCell->moveTo(object, cellToMoveTo); + if (cellToMoveTo != originalCell) + { + originalCell->moveTo(object, cellToMoveTo); + } updateMergedRefs(); - return; + return MWWorld::Ptr(object.getBase(), cellToMoveTo); } cellToMoveTo->moveFrom(object, this); mMovedToAnotherCell.insert(std::make_pair(object.getBase(), cellToMoveTo)); updateMergedRefs(); + return MWWorld::Ptr(object.getBase(), cellToMoveTo); } - void CellStore::updateMergedRefs() + struct MergeFunctor { + MergeFunctor(std::vector& mergeTo, const std::map& movedHere, + const std::map& movedToAnotherCell) + : mMergeTo(mergeTo) + , mMovedHere(movedHere) + , mMovedToAnotherCell(movedToAnotherCell) + { + } + bool operator() (const MWWorld::Ptr& ptr) + { + if (mMovedToAnotherCell.find(ptr.getBase()) != mMovedToAnotherCell.end()) + return true; + mMergeTo.push_back(ptr.getBase()); + return true; + } + + void merge() + { + for (std::map::const_iterator it = mMovedHere.begin(); it != mMovedHere.end(); ++it) + mMergeTo.push_back(it->first); + } + + private: + std::vector& mMergeTo; + + const std::map& mMovedHere; + const std::map& mMovedToAnotherCell; + }; + + void CellStore::updateMergedRefs() + { + mMergedRefs.clear(); + MergeFunctor functor(mMergedRefs, mMovedHere, mMovedToAnotherCell); + forEachInternal(functor); + functor.merge(); } CellStore::CellStore (const ESM::Cell *cell) @@ -258,85 +317,50 @@ namespace MWWorld return const_cast (this)->search (id).isEmpty(); } + struct SearchFunctor + { + MWWorld::Ptr mFound; + std::string mIdToFind; + bool operator()(const MWWorld::Ptr& ptr) + { + if (ptr.getCellRef().getRefId() == mIdToFind) + { + mFound = ptr; + return false; + } + return true; + } + }; + Ptr CellStore::search (const std::string& id) { bool oldState = mHasState; - mHasState = true; - - if (LiveCellRef *ref = mActivators.find (id)) - return Ptr (ref, this); - - if (LiveCellRef *ref = mPotions.find (id)) - return Ptr (ref, this); - - if (LiveCellRef *ref = mAppas.find (id)) - return Ptr (ref, this); - - if (LiveCellRef *ref = mArmors.find (id)) - return Ptr (ref, this); - - if (LiveCellRef *ref = mBooks.find (id)) - return Ptr (ref, this); - - if (LiveCellRef *ref = mClothes.find (id)) - return Ptr (ref, this); - - if (LiveCellRef *ref = mContainers.find (id)) - return Ptr (ref, this); - - if (LiveCellRef *ref = mCreatures.find (id)) - return Ptr (ref, this); - - if (LiveCellRef *ref = mDoors.find (id)) - return Ptr (ref, this); - - if (LiveCellRef *ref = mIngreds.find (id)) - return Ptr (ref, this); - - if (LiveCellRef *ref = mCreatureLists.find (id)) - return Ptr (ref, this); - - if (LiveCellRef *ref = mItemLists.find (id)) - return Ptr (ref, this); - - if (LiveCellRef *ref = mLights.find (id)) - return Ptr (ref, this); - - if (LiveCellRef *ref = mLockpicks.find (id)) - return Ptr (ref, this); - - if (LiveCellRef *ref = mMiscItems.find (id)) - return Ptr (ref, this); - - if (LiveCellRef *ref = mNpcs.find (id)) - return Ptr (ref, this); - - if (LiveCellRef *ref = mProbes.find (id)) - return Ptr (ref, this); - - if (LiveCellRef *ref = mRepairs.find (id)) - return Ptr (ref, this); - - if (LiveCellRef *ref = mStatics.find (id)) - return Ptr (ref, this); - - if (LiveCellRef *ref = mWeapons.find (id)) - return Ptr (ref, this); + SearchFunctor searchFunctor; + searchFunctor.mIdToFind = id; + forEach(searchFunctor); mHasState = oldState; - - return Ptr(); + return searchFunctor.mFound; } Ptr CellStore::searchViaActorId (int id) { - if (Ptr ptr = ::searchViaActorId (mNpcs, id, this)) + if (Ptr ptr = ::searchViaActorId (mNpcs, id, this, mMovedToAnotherCell)) return ptr; - if (Ptr ptr = ::searchViaActorId (mCreatures, id, this)) + if (Ptr ptr = ::searchViaActorId (mCreatures, id, this, mMovedToAnotherCell)) return ptr; + for (MovedRefTracker::const_iterator it = mMovedHere.begin(); it != mMovedHere.end(); ++it) + { + MWWorld::Ptr actor (it->first, this); + if (!actor.getClass().isActor()) + continue; + if (actor.getClass().getCreatureStats (actor).matchesActorId (id) && actor.getRefData().getCount() > 0) + return actor; + } + return Ptr(); } @@ -435,6 +459,8 @@ namespace MWWorld continue; } + // We don't need to check mMovedToAnotherCell because listRefs isn't used for loaded cells. + mIds.push_back (Misc::StringUtils::lowerCase (ref.mRefID)); } } @@ -447,6 +473,12 @@ namespace MWWorld mIds.push_back(Misc::StringUtils::lowerCase(ref.mRefID)); } + // List runtime moved references + for (MovedRefTracker::const_iterator it = mMovedHere.begin(); it != mMovedHere.end(); ++it) + { + mIds.push_back(Misc::StringUtils::lowerCase(it->first->mRef.getRefId())); + } + std::sort (mIds.begin(), mIds.end()); } @@ -489,6 +521,8 @@ namespace MWWorld loadRef (ref, false, store); } + + updateMergedRefs(); } bool CellStore::isExterior() const @@ -610,11 +644,15 @@ namespace MWWorld writeReferenceCollection (writer, mRepairs); writeReferenceCollection (writer, mStatics); writeReferenceCollection (writer, mWeapons); + + // TODO: write moved references } void CellStore::readReferences (ESM::ESMReader& reader, const std::map& contentFileMap) { + // TODO: read moved references + mHasState = true; while (reader.isNextSub ("OBJE")) diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index ef1192277..2ef03e2c4 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -112,11 +112,64 @@ namespace MWWorld /// Repopulate mMergedRefs. void updateMergedRefs(); + template + LiveCellRefBase* insertBase(CellRefList& list, const LiveCellRef* ref) + { + mHasState = true; + LiveCellRefBase* ret = &list.insert(*ref); + updateMergedRefs(); + return ret; + } + + // helper function for forEachInternal + template + bool forEachImp (Functor& functor, List& list) + { + for (typename List::List::iterator iter (list.mList.begin()); iter!=list.mList.end(); + ++iter) + { + if (iter->mData.isDeletedByContentFile()) + continue; + if (!functor (MWWorld::Ptr(&*iter, this))) + return false; + } + return true; + } + + // listing only objects owned by this cell. Internal use only, you probably want to use forEach() so that moved objects are accounted for. + template + bool forEachInternal (Functor& functor) + { + return + forEachImp (functor, mActivators) && + forEachImp (functor, mPotions) && + forEachImp (functor, mAppas) && + forEachImp (functor, mArmors) && + forEachImp (functor, mBooks) && + forEachImp (functor, mClothes) && + forEachImp (functor, mContainers) && + forEachImp (functor, mDoors) && + forEachImp (functor, mIngreds) && + forEachImp (functor, mItemLists) && + forEachImp (functor, mLights) && + forEachImp (functor, mLockpicks) && + forEachImp (functor, mMiscItems) && + forEachImp (functor, mProbes) && + forEachImp (functor, mRepairs) && + forEachImp (functor, mStatics) && + forEachImp (functor, mWeapons) && + forEachImp (functor, mCreatures) && + forEachImp (functor, mNpcs) && + forEachImp (functor, mCreatureLists); + } + public: /// Moves object from this cell to the given cell. /// @note automatically updates given cell by calling cellToMoveTo->moveFrom(...) - void moveTo(const MWWorld::Ptr& object, MWWorld::CellStore* cellToMoveTo); + /// @note throws exception if cellToMoveTo == this + /// @return updated MWWorld::Ptr with the new CellStore pointer set. + MWWorld::Ptr moveTo(const MWWorld::Ptr& object, MWWorld::CellStore* cellToMoveTo); /// Make a copy of the given object and insert it into this cell. /// @note If you get a linker error here, this means the given type can not be inserted into a cell. @@ -136,6 +189,7 @@ namespace MWWorld bool hasId (const std::string& id) const; ///< May return true for deleted IDs when in preload state. Will return false, if cell is /// unloaded. + /// @note Will not account for moved references which may exist in Loaded state. Use search() instead if the cell is loaded. Ptr search (const std::string& id); ///< Will return an empty Ptr if cell is not loaded. Does not check references in @@ -166,45 +220,23 @@ namespace MWWorld /// false will abort the iteration. /// \attention This function also lists deleted (count 0) objects! /// \return Iteration completed? - /// - /// \note Creatures and NPCs are handled last. template bool forEach (Functor& functor) { - mHasState = true; - - return - forEachImp (functor, mActivators) && - forEachImp (functor, mPotions) && - forEachImp (functor, mAppas) && - forEachImp (functor, mArmors) && - forEachImp (functor, mBooks) && - forEachImp (functor, mClothes) && - forEachImp (functor, mContainers) && - forEachImp (functor, mDoors) && - forEachImp (functor, mIngreds) && - forEachImp (functor, mItemLists) && - forEachImp (functor, mLights) && - forEachImp (functor, mLockpicks) && - forEachImp (functor, mMiscItems) && - forEachImp (functor, mProbes) && - forEachImp (functor, mRepairs) && - forEachImp (functor, mStatics) && - forEachImp (functor, mWeapons) && - forEachImp (functor, mCreatures) && - forEachImp (functor, mNpcs) && - forEachImp (functor, mCreatureLists); - } + if (mState != State_Loaded) + return false; - template - bool forEachContainer (Functor& functor) - { mHasState = true; - return - forEachImp (functor, mContainers) && - forEachImp (functor, mCreatures) && - forEachImp (functor, mNpcs); + for (unsigned int i=0; imData.isDeletedByContentFile()) + continue; + + if (!functor(MWWorld::Ptr(mMergedRefs[i], this))) + return false; + } + return true; } /// \todo add const version of forEach @@ -234,20 +266,6 @@ namespace MWWorld private: - template - bool forEachImp (Functor& functor, List& list) - { - for (typename List::List::iterator iter (list.mList.begin()); iter!=list.mList.end(); - ++iter) - { - if (iter->mData.isDeletedByContentFile()) - continue; - if (!functor (MWWorld::Ptr(&*iter, this))) - return false; - } - return true; - } - /// Run through references and store IDs void listRefs(const MWWorld::ESMStore &store, std::vector &esm); @@ -261,126 +279,105 @@ namespace MWWorld MWMechanics::PathgridGraph mPathgridGraph; }; - template<> inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) { - mHasState = true; - return &mActivators.insert(*ref); + return insertBase(mActivators, ref); } template<> inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) { - mHasState = true; - return &mPotions.insert(*ref); + return insertBase(mPotions, ref); } template<> inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) { - mHasState = true; - return &mAppas.insert(*ref); + return insertBase(mAppas, ref); } template<> inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) { - mHasState = true; - return &mArmors.insert(*ref); + return insertBase(mArmors, ref); } template<> inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) { - mHasState = true; - return &mBooks.insert(*ref); + return insertBase(mBooks, ref); } template<> inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) { - mHasState = true; - return &mClothes.insert(*ref); + return insertBase(mClothes, ref); } template<> inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) { - mHasState = true; - return &mContainers.insert(*ref); + return insertBase(mContainers, ref); } template<> inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) { - mHasState = true; - return &mCreatures.insert(*ref); + return insertBase(mCreatures, ref); } template<> inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) { - mHasState = true; - return &mDoors.insert(*ref); + return insertBase(mDoors, ref); } template<> inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) { - mHasState = true; - return &mIngreds.insert(*ref); + return insertBase(mIngreds, ref); } template<> inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) { - mHasState = true; - return &mCreatureLists.insert(*ref); + return insertBase(mCreatureLists, ref); } template<> inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) { - mHasState = true; - return &mItemLists.insert(*ref); + return insertBase(mItemLists, ref); } template<> inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) { - mHasState = true; - return &mLights.insert(*ref); + return insertBase(mLights, ref); } template<> inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) { - mHasState = true; - return &mLockpicks.insert(*ref); + return insertBase(mLockpicks, ref); } template<> inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) { - mHasState = true; - return &mMiscItems.insert(*ref); + return insertBase(mMiscItems, ref); } template<> inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) { - mHasState = true; - return &mNpcs.insert(*ref); + return insertBase(mNpcs, ref); } template<> inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) { - mHasState = true; - return &mProbes.insert(*ref); + return insertBase(mProbes, ref); } template<> inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) { - mHasState = true; - return &mRepairs.insert(*ref); + return insertBase(mRepairs, ref); } template<> inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) { - mHasState = true; - return &mStatics.insert(*ref); + return insertBase(mStatics, ref); } template<> inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) { - mHasState = true; - return &mWeapons.insert(*ref); + return insertBase(mWeapons, ref); } bool operator== (const CellStore& left, const CellStore& right); diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 45c94b6d9..896d5f8eb 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -116,7 +116,6 @@ namespace { addObject(ptr, mPhysics, mRendering); updateObjectRotation(ptr, mPhysics, mRendering, false); - ptr.getClass().adjustPosition (ptr, false); } catch (const std::exception& e) { @@ -129,6 +128,17 @@ namespace return true; } + + struct AdjustPositionFunctor + { + bool operator() (const MWWorld::Ptr& ptr) + { + if (!ptr.getRefData().isDeleted() && ptr.getRefData().isEnabled()) + ptr.getClass().adjustPosition (ptr, false); + return true; + } + }; + } @@ -553,6 +563,10 @@ namespace MWWorld { InsertFunctor functor (cell, rescale, *loadingListener, *mPhysics, mRendering); cell.forEach (functor); + + // do adjustPosition (snapping actors to ground) after objects are loaded, so we don't depend on the loading order + AdjustPositionFunctor adjustPosFunctor; + cell.forEach (adjustPosFunctor); } void Scene::addObjectToScene (const Ptr& ptr) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 950c38e76..bb2ca2aae 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -722,7 +722,7 @@ namespace MWWorld for (Scene::CellStoreCollection::const_iterator cellIt = collection.begin(); cellIt != collection.end(); ++cellIt) { FindContainerFunctor functor(ptr); - (*cellIt)->forEachContainer(functor); + //(*cellIt)->forEachContainer(functor); if (!functor.mResult.isEmpty()) return functor.mResult; @@ -1146,7 +1146,7 @@ namespace MWWorld bool newCellActive = mWorldScene->isCellActive(*newCell); if (!currCellActive && newCellActive) { - newPtr = ptr.getClass().copyToCell(ptr, *newCell, pos); + newPtr = currCell->moveTo(ptr, newCell); mWorldScene->addObjectToScene(newPtr); std::string script = newPtr.getClass().getScript(newPtr); @@ -1162,14 +1162,14 @@ namespace MWWorld removeContainerScripts (ptr); haveToMove = false; - newPtr = ptr.getClass().copyToCell(ptr, *newCell); + newPtr = currCell->moveTo(ptr, newCell); newPtr.getRefData().setBaseNode(0); } else if (!currCellActive && !newCellActive) - newPtr = ptr.getClass().copyToCell(ptr, *newCell); + newPtr = currCell->moveTo(ptr, newCell); else // both cells active { - newPtr = ptr.getClass().copyToCell(ptr, *newCell, pos); + newPtr = currCell->moveTo(ptr, newCell); mRendering->updatePtr(ptr, newPtr); ptr.getRefData().setBaseNode(NULL); @@ -1189,7 +1189,6 @@ namespace MWWorld addContainerScripts (newPtr, newCell); } } - ptr.getRefData().setCount(0); } } if (haveToMove && newPtr.getRefData().getBaseNode()) From 3dcefd17fc94bc970a8d8b6b3eb90245f78d781f Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 4 Dec 2015 20:03:14 +0100 Subject: [PATCH 2692/3725] Fix CellStore::count() --- apps/openmw/mwworld/cellstore.cpp | 22 +--------------------- 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index d56baf231..1a1802a05 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -379,27 +379,7 @@ namespace MWWorld int CellStore::count() const { - return - mActivators.mList.size() - + mPotions.mList.size() - + mAppas.mList.size() - + mArmors.mList.size() - + mBooks.mList.size() - + mClothes.mList.size() - + mContainers.mList.size() - + mDoors.mList.size() - + mIngreds.mList.size() - + mCreatureLists.mList.size() - + mItemLists.mList.size() - + mLights.mList.size() - + mLockpicks.mList.size() - + mMiscItems.mList.size() - + mProbes.mList.size() - + mRepairs.mList.size() - + mStatics.mList.size() - + mWeapons.mList.size() - + mCreatures.mList.size() - + mNpcs.mList.size(); + return mMergedRefs.size(); } void CellStore::load (const MWWorld::ESMStore &store, std::vector &esm) From 3f93af4181914cbf0691e38e25e68888c7cf374b Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 4 Dec 2015 23:28:11 +0100 Subject: [PATCH 2693/3725] Projectiles interact with the water surface (Fixes #2986) --- apps/openmw/mwrender/renderingmanager.cpp | 5 +++ apps/openmw/mwrender/renderingmanager.hpp | 1 + apps/openmw/mwrender/ripplesimulation.cpp | 14 +++++-- apps/openmw/mwrender/ripplesimulation.hpp | 2 + apps/openmw/mwrender/water.cpp | 5 +++ apps/openmw/mwrender/water.hpp | 2 + apps/openmw/mwworld/projectilemanager.cpp | 45 ++++++++++++++--------- apps/openmw/mwworld/projectilemanager.hpp | 7 +++- apps/openmw/mwworld/worldimp.cpp | 2 +- 9 files changed, 60 insertions(+), 23 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index c0a907f70..6e97905b8 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -756,6 +756,11 @@ namespace MWRender mWater->removeEmitter(ptr); } + void RenderingManager::emitWaterRipple(const osg::Vec3f &pos) + { + mWater->emitRipple(pos); + } + void RenderingManager::updateProjectionMatrix() { double aspect = mViewer->getCamera()->getViewport()->aspectRatio(); diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index a0ea14cb4..4d223aeb8 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -138,6 +138,7 @@ namespace MWRender void addWaterRippleEmitter(const MWWorld::Ptr& ptr); void removeWaterRippleEmitter(const MWWorld::Ptr& ptr); + void emitWaterRipple(const osg::Vec3f& pos); void updatePlayerPtr(const MWWorld::Ptr &ptr); diff --git a/apps/openmw/mwrender/ripplesimulation.cpp b/apps/openmw/mwrender/ripplesimulation.cpp index 55b732613..766e20fc4 100644 --- a/apps/openmw/mwrender/ripplesimulation.cpp +++ b/apps/openmw/mwrender/ripplesimulation.cpp @@ -139,9 +139,7 @@ void RippleSimulation::update(float dt) if (mParticleSystem->numParticles()-mParticleSystem->numDeadParticles() > 500) continue; // TODO: remove the oldest particle to make room? - osgParticle::Particle* p = mParticleSystem->createParticle(NULL); - p->setPosition(currentPos); - p->setAngle(osg::Vec3f(0,0, Misc::Rng::rollProbability() * osg::PI * 2 - osg::PI)); + emitRipple(currentPos); } } } @@ -194,6 +192,16 @@ void RippleSimulation::removeCell(const MWWorld::CellStore *store) } } +void RippleSimulation::emitRipple(const osg::Vec3f &pos) +{ + if (std::abs(pos.z() - mParticleNode->getPosition().z()) < 20) + { + osgParticle::Particle* p = mParticleSystem->createParticle(NULL); + p->setPosition(osg::Vec3f(pos.x(), pos.y(), 0.f)); + p->setAngle(osg::Vec3f(0,0, Misc::Rng::rollProbability() * osg::PI * 2 - osg::PI)); + } +} + void RippleSimulation::setWaterHeight(float height) { mParticleNode->setPosition(osg::Vec3f(0,0,height)); diff --git a/apps/openmw/mwrender/ripplesimulation.hpp b/apps/openmw/mwrender/ripplesimulation.hpp index 17d5fea15..7d412f454 100644 --- a/apps/openmw/mwrender/ripplesimulation.hpp +++ b/apps/openmw/mwrender/ripplesimulation.hpp @@ -52,6 +52,8 @@ namespace MWRender void updateEmitterPtr (const MWWorld::Ptr& old, const MWWorld::Ptr& ptr); void removeCell(const MWWorld::CellStore* store); + void emitRipple(const osg::Vec3f& pos); + /// Change the height of the water surface, thus moving all ripples with it void setWaterHeight(float height); diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 1afb74bd7..9823d79df 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -731,6 +731,11 @@ void Water::updateEmitterPtr (const MWWorld::Ptr& old, const MWWorld::Ptr& ptr) mSimulation->updateEmitterPtr(old, ptr); } +void Water::emitRipple(const osg::Vec3f &pos) +{ + mSimulation->emitRipple(pos); +} + void Water::removeCell(const MWWorld::CellStore *store) { mSimulation->removeCell(store); diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index 551184c11..b26782873 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -91,6 +91,8 @@ namespace MWRender void addEmitter (const MWWorld::Ptr& ptr, float scale = 1.f, float force = 1.f); void removeEmitter (const MWWorld::Ptr& ptr); void updateEmitterPtr (const MWWorld::Ptr& old, const MWWorld::Ptr& ptr); + void emitRipple(const osg::Vec3f& pos); + void removeCell(const MWWorld::CellStore* store); ///< remove all emitters in this cell void clearRipples(); diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 08ae6f2b0..e188afc5d 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -25,6 +25,7 @@ #include "../mwrender/effectmanager.hpp" #include "../mwrender/animation.hpp" #include "../mwrender/vismask.hpp" +#include "../mwrender/renderingmanager.hpp" #include "../mwsound/sound.hpp" @@ -34,9 +35,11 @@ namespace MWWorld { - ProjectileManager::ProjectileManager(osg::Group* parent, Resource::ResourceSystem* resourceSystem, MWPhysics::PhysicsSystem* physics) + ProjectileManager::ProjectileManager(osg::Group* parent, Resource::ResourceSystem* resourceSystem, + MWRender::RenderingManager* rendering, MWPhysics::PhysicsSystem* physics) : mParent(parent) , mResourceSystem(resourceSystem) + , mRendering(rendering) , mPhysics(physics) { @@ -225,32 +228,38 @@ namespace MWWorld // TODO: use a proper btRigidBody / btGhostObject? MWPhysics::PhysicsSystem::RayResult result = mPhysics->castRay(pos, newPos, caster, 0xff, MWPhysics::CollisionType_Projectile); - if (result.mHit) + bool underwater = MWBase::Environment::get().getWorld()->isUnderwater(MWMechanics::getPlayer().getCell(), newPos); + if (result.mHit || underwater) { - MWWorld::ManualRef projectileRef(MWBase::Environment::get().getWorld()->getStore(), it->mId); - - // Try to get a Ptr to the bow that was used. It might no longer exist. - MWWorld::Ptr bow = projectileRef.getPtr(); - if (!caster.isEmpty()) + if (result.mHit) { - MWWorld::InventoryStore& inv = caster.getClass().getInventoryStore(caster); - MWWorld::ContainerStoreIterator invIt = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); - if (invIt != inv.end() && Misc::StringUtils::ciEqual(invIt->getCellRef().getRefId(), it->mBowId)) - bow = *invIt; + MWWorld::ManualRef projectileRef(MWBase::Environment::get().getWorld()->getStore(), it->mId); + + // Try to get a Ptr to the bow that was used. It might no longer exist. + MWWorld::Ptr bow = projectileRef.getPtr(); + if (!caster.isEmpty()) + { + MWWorld::InventoryStore& inv = caster.getClass().getInventoryStore(caster); + MWWorld::ContainerStoreIterator invIt = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); + if (invIt != inv.end() && Misc::StringUtils::ciEqual(invIt->getCellRef().getRefId(), it->mBowId)) + bow = *invIt; + } + + if (caster.isEmpty()) + caster = result.mHitObject; + + MWMechanics::projectileHit(caster, result.mHitObject, bow, projectileRef.getPtr(), result.mHitPos, it->mAttackStrength); } - if (caster.isEmpty()) - caster = result.mHitObject; - - MWMechanics::projectileHit(caster, result.mHitObject, bow, projectileRef.getPtr(), result.mHitPos, it->mAttackStrength); + if (underwater) + mRendering->emitWaterRipple(newPos); mParent->removeChild(it->mNode); - it = mProjectiles.erase(it); continue; } - else - ++it; + + ++it; } } diff --git a/apps/openmw/mwworld/projectilemanager.hpp b/apps/openmw/mwworld/projectilemanager.hpp index 22fc4784c..87878ef2a 100644 --- a/apps/openmw/mwworld/projectilemanager.hpp +++ b/apps/openmw/mwworld/projectilemanager.hpp @@ -36,6 +36,7 @@ namespace Resource namespace MWRender { class EffectAnimationTime; + class RenderingManager; } namespace MWWorld @@ -45,7 +46,7 @@ namespace MWWorld { public: ProjectileManager (osg::Group* parent, Resource::ResourceSystem* resourceSystem, - MWPhysics::PhysicsSystem* physics); + MWRender::RenderingManager* rendering, MWPhysics::PhysicsSystem* physics); /// If caster is an actor, the actor's facing orientation is used. Otherwise fallbackDirection is used. void launchMagicBolt (const std::string& model, const std::string &sound, const std::string &spellId, @@ -67,6 +68,7 @@ namespace MWWorld private: osg::ref_ptr mParent; Resource::ResourceSystem* mResourceSystem; + MWRender::RenderingManager* mRendering; MWPhysics::PhysicsSystem* mPhysics; struct State @@ -120,6 +122,9 @@ namespace MWWorld void createModel (State& state, const std::string& model, const osg::Vec3f& pos, const osg::Quat& orient); void update (State& state, float duration); + + void operator=(const ProjectileManager&); + ProjectileManager(const ProjectileManager&); }; } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 22485ed92..a2c8b6bd9 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -163,8 +163,8 @@ namespace MWWorld mLevitationEnabled(true), mGoToJail(false), mDaysInPrison(0) { mPhysics = new MWPhysics::PhysicsSystem(resourceSystem, rootNode); - mProjectileManager.reset(new ProjectileManager(rootNode, resourceSystem, mPhysics)); mRendering = new MWRender::RenderingManager(viewer, rootNode, resourceSystem, &mFallback, resourcePath); + mProjectileManager.reset(new ProjectileManager(rootNode, resourceSystem, mRendering, mPhysics)); mEsm.resize(contentFiles.size()); Loading::Listener* listener = MWBase::Environment::get().getWindowManager()->getLoadingScreen(); From a8938589f6520cc5d62f587878f3316524db38bd Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 5 Dec 2015 00:03:25 +0100 Subject: [PATCH 2694/3725] Magic projectiles rotate during flight --- apps/openmw/mwworld/projectilemanager.cpp | 53 ++++++++++++++++++++--- apps/openmw/mwworld/projectilemanager.hpp | 2 +- 2 files changed, 47 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index e188afc5d..80eab27cd 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -45,15 +45,54 @@ namespace MWWorld } - void ProjectileManager::createModel(State &state, const std::string &model, const osg::Vec3f& pos, const osg::Quat& orient) + /// Rotates an osg::PositionAttitudeTransform over time. + class RotateCallback : public osg::NodeCallback + { + public: + RotateCallback(const osg::Vec3f& axis = osg::Vec3f(0,-1,0), float rotateSpeed = osg::PI*2) + : mAxis(axis) + , mRotateSpeed(rotateSpeed) + { + } + + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) + { + osg::PositionAttitudeTransform* transform = static_cast(node); + + double time = nv->getFrameStamp()->getSimulationTime(); + + osg::Quat orient = osg::Quat(time * mRotateSpeed, mAxis); + transform->setAttitude(orient); + + traverse(node, nv); + } + + private: + osg::Vec3f mAxis; + float mRotateSpeed; + }; + + + void ProjectileManager::createModel(State &state, const std::string &model, const osg::Vec3f& pos, const osg::Quat& orient, bool rotate) { state.mNode = new osg::PositionAttitudeTransform; state.mNode->setNodeMask(MWRender::Mask_Effect); state.mNode->setPosition(pos); state.mNode->setAttitude(orient); - mParent->addChild(state.mNode); - mResourceSystem->getSceneManager()->createInstance(model, state.mNode); + osg::Group* attachTo = state.mNode; + + if (rotate) + { + osg::ref_ptr rotateNode (new osg::PositionAttitudeTransform); + rotateNode->addUpdateCallback(new RotateCallback()); + state.mNode->addChild(rotateNode); + attachTo = rotateNode; + } + + mResourceSystem->getSceneManager()->createInstance(model, attachTo); + + mParent->addChild(state.mNode); state.mEffectAnimationTime.reset(new MWRender::EffectAnimationTime); @@ -107,7 +146,7 @@ namespace MWWorld MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), model); MWWorld::Ptr ptr = ref.getPtr(); - createModel(state, ptr.getClass().getModel(ptr), pos, orient); + createModel(state, ptr.getClass().getModel(ptr), pos, orient, true); MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); state.mSound = sndMgr->playSound3D(pos, sound, 1.0f, 1.0f, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_Loop); @@ -128,7 +167,7 @@ namespace MWWorld MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), projectile.getCellRef().getRefId()); MWWorld::Ptr ptr = ref.getPtr(); - createModel(state, ptr.getClass().getModel(ptr), pos, orient); + createModel(state, ptr.getClass().getModel(ptr), pos, orient, false); mProjectiles.push_back(state); } @@ -348,7 +387,7 @@ namespace MWWorld return true; } - createModel(state, model, osg::Vec3f(esm.mPosition), osg::Quat(esm.mOrientation)); + createModel(state, model, osg::Vec3f(esm.mPosition), osg::Quat(esm.mOrientation), false); mProjectiles.push_back(state); return true; @@ -379,7 +418,7 @@ namespace MWWorld return true; } - createModel(state, model, osg::Vec3f(esm.mPosition), osg::Quat(esm.mOrientation)); + createModel(state, model, osg::Vec3f(esm.mPosition), osg::Quat(esm.mOrientation), true); MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); state.mSound = sndMgr->playSound3D(esm.mPosition, esm.mSound, 1.0f, 1.0f, diff --git a/apps/openmw/mwworld/projectilemanager.hpp b/apps/openmw/mwworld/projectilemanager.hpp index 87878ef2a..f58e266b3 100644 --- a/apps/openmw/mwworld/projectilemanager.hpp +++ b/apps/openmw/mwworld/projectilemanager.hpp @@ -120,7 +120,7 @@ namespace MWWorld void moveProjectiles(float dt); void moveMagicBolts(float dt); - void createModel (State& state, const std::string& model, const osg::Vec3f& pos, const osg::Quat& orient); + void createModel (State& state, const std::string& model, const osg::Vec3f& pos, const osg::Quat& orient, bool rotate); void update (State& state, float duration); void operator=(const ProjectileManager&); From 618159425170dd0e19b75a401733796e039f813e Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 5 Dec 2015 00:04:23 +0100 Subject: [PATCH 2695/3725] Disable freezeOnCull for magic projectile particles --- apps/openmw/mwworld/projectilemanager.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 80eab27cd..e087478b3 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include "../mwworld/manualref.hpp" #include "../mwworld/class.hpp" @@ -92,6 +93,9 @@ namespace MWWorld mResourceSystem->getSceneManager()->createInstance(model, attachTo); + SceneUtil::DisableFreezeOnCullVisitor disableFreezeOnCullVisitor; + state.mNode->accept(disableFreezeOnCullVisitor); + mParent->addChild(state.mNode); state.mEffectAnimationTime.reset(new MWRender::EffectAnimationTime); From 258f7a2b42c6b2083aabe196eaa43e7c5d9854d5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 5 Dec 2015 00:38:06 +0100 Subject: [PATCH 2696/3725] LightController fixes --- components/sceneutil/lightcontroller.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/components/sceneutil/lightcontroller.cpp b/components/sceneutil/lightcontroller.cpp index d44a1a94a..511937a28 100644 --- a/components/sceneutil/lightcontroller.cpp +++ b/components/sceneutil/lightcontroller.cpp @@ -61,8 +61,10 @@ namespace SceneUtil void LightController::operator ()(osg::Node* node, osg::NodeVisitor* nv) { double time = nv->getFrameStamp()->getSimulationTime(); - if (time == mLastTime) - return; + + // disabled early out, light state needs to be set every frame regardless of change, due to the double buffering + //if (time == mLastTime) + // return; float dt = static_cast(time - mLastTime); mLastTime = time; @@ -119,6 +121,8 @@ namespace SceneUtil brightness = 0.7f + pulseAmplitude(mDeltaCount*slow)*0.3f; static_cast(node)->getLight(nv->getTraversalNumber())->setDiffuse(mDiffuseColor * brightness); + + traverse(node, nv); } void LightController::setDiffuse(osg::Vec4f color) From 67a6a8f5d437e24bd58d59f6cd82dd3a717eac7c Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 5 Dec 2015 00:44:04 +0100 Subject: [PATCH 2697/3725] Make projectiles receive lighting --- apps/openmw/mwrender/renderingmanager.cpp | 5 +++++ apps/openmw/mwrender/renderingmanager.hpp | 2 ++ apps/openmw/mwworld/projectilemanager.cpp | 3 +++ apps/openmw/mwworld/worldimp.cpp | 2 +- 4 files changed, 11 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 6e97905b8..f4e7ca684 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -227,6 +227,11 @@ namespace MWRender return mResourceSystem; } + osg::Group* RenderingManager::getLightRoot() + { + return mLightRoot.get(); + } + void RenderingManager::setNightEyeFactor(float factor) { if (factor != mNightEyeFactor) diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 4d223aeb8..936f7cb99 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -65,6 +65,8 @@ namespace MWRender Resource::ResourceSystem* getResourceSystem(); + osg::Group* getLightRoot(); + void setNightEyeFactor(float factor); void setAmbientColour(const osg::Vec4f& colour); diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index e087478b3..5728fe1d7 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include "../mwworld/manualref.hpp" #include "../mwworld/class.hpp" @@ -96,6 +97,8 @@ namespace MWWorld SceneUtil::DisableFreezeOnCullVisitor disableFreezeOnCullVisitor; state.mNode->accept(disableFreezeOnCullVisitor); + state.mNode->addCullCallback(new SceneUtil::LightListCallback); + mParent->addChild(state.mNode); state.mEffectAnimationTime.reset(new MWRender::EffectAnimationTime); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index a2c8b6bd9..0cb2e980d 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -164,7 +164,7 @@ namespace MWWorld { mPhysics = new MWPhysics::PhysicsSystem(resourceSystem, rootNode); mRendering = new MWRender::RenderingManager(viewer, rootNode, resourceSystem, &mFallback, resourcePath); - mProjectileManager.reset(new ProjectileManager(rootNode, resourceSystem, mRendering, mPhysics)); + mProjectileManager.reset(new ProjectileManager(mRendering->getLightRoot(), resourceSystem, mRendering, mPhysics)); mEsm.resize(contentFiles.size()); Loading::Listener* listener = MWBase::Environment::get().getWindowManager()->getLoadingScreen(); From 66bcd2fd685b0421dd4884755c260703b64e9049 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 5 Dec 2015 01:05:24 +0100 Subject: [PATCH 2698/3725] Write save games to a memory stream first Two motivations for doing this: - If the user chooses to overwrite existing save file, and there is an exception during the save process, the existing file will not be lost. - Many small writes to a file are slow. Very slow. Writing to memory first then writing the completed file to disk appears to be ~500% faster. --- apps/openmw/mwstate/statemanagerimp.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index b76d9eae5..b5426bc77 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -207,7 +207,9 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot else slot = getCurrentCharacter()->updateSlot (slot, profile); - boost::filesystem::ofstream stream (slot->mPath, std::ios::binary); + // Write to a memory stream first. If there is an exception during the save process, we don't want to trash the + // existing save file we are overwriting. + std::stringstream stream; ESM::ESMWriter writer; @@ -262,7 +264,14 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot writer.close(); if (stream.fail()) - throw std::runtime_error("Write operation failed"); + throw std::runtime_error("Write operation failed (memory stream)"); + + // All good, write to file + boost::filesystem::ofstream filestream (slot->mPath, std::ios::binary); + filestream << stream.rdbuf(); + + if (filestream.fail()) + throw std::runtime_error("Write operation failed (file stream)"); Settings::Manager::setString ("character", "Saves", slot->mPath.parent_path().filename().string()); From 53158d29b17a96ff3a3c9474d636221b383039d7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 5 Dec 2015 01:54:16 +0100 Subject: [PATCH 2699/3725] stopSound crash fix --- apps/openmw/mwsound/soundmanagerimp.cpp | 3 ++- apps/openmw/mwsound/soundmanagerimp.hpp | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index fd38a0ce5..1b7e91285 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -612,7 +612,8 @@ namespace MWSound void SoundManager::stopSound(MWBase::SoundPtr sound) { - mOutput->stopSound(sound); + if (sound.get()) + mOutput->stopSound(sound); } void SoundManager::stopSound3D(const MWWorld::Ptr &ptr, const std::string& soundId) diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index c1d8eeb21..7058c55b6 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -201,6 +201,7 @@ namespace MWSound virtual void stopSound(MWBase::SoundPtr sound); ///< Stop the given sound from playing + /// @note no-op if \a sound is null virtual void stopSound3D(const MWWorld::Ptr &reference, const std::string& soundId); ///< Stop the given object from playing the given sound, From c60f4ba7bdd948b58842e82a4b31d29984359b74 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 5 Dec 2015 15:02:35 +0100 Subject: [PATCH 2700/3725] Make RigGeometry bone references case-insensitive (Fixes #3058) --- components/sceneutil/skeleton.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/components/sceneutil/skeleton.cpp b/components/sceneutil/skeleton.cpp index 83f7d6537..332dc3b07 100644 --- a/components/sceneutil/skeleton.cpp +++ b/components/sceneutil/skeleton.cpp @@ -3,6 +3,8 @@ #include #include +#include + #include namespace SceneUtil @@ -23,7 +25,7 @@ public: if (!bone) return; - mCache[bone->getName()] = std::make_pair(getNodePath(), bone); + mCache[Misc::StringUtils::lowerCase(bone->getName())] = std::make_pair(getNodePath(), bone); traverse(node); } @@ -59,7 +61,7 @@ Bone* Skeleton::getBone(const std::string &name) mBoneCacheInit = true; } - BoneCache::iterator found = mBoneCache.find(name); + BoneCache::iterator found = mBoneCache.find(Misc::StringUtils::lowerCase(name)); if (found == mBoneCache.end()) return NULL; From c75303b652ee705ba4748afe6a2fd92014da72bc Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 4 Dec 2015 12:54:41 -0800 Subject: [PATCH 2701/3725] Add an option to select and enable HRTF --- apps/openmw/mwsound/openal_output.cpp | 129 ++++++++++++++++++++++++ apps/openmw/mwsound/openal_output.hpp | 6 +- apps/openmw/mwsound/sound_output.hpp | 6 +- apps/openmw/mwsound/soundmanagerimp.cpp | 43 ++++---- files/settings-default.cfg | 7 ++ 5 files changed, 172 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 54a5efb68..407a24ce1 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -19,6 +19,28 @@ #define ALC_ALL_DEVICES_SPECIFIER 0x1013 #endif +#ifndef ALC_SOFT_HRTF +#define ALC_SOFT_HRTF 1 +#define ALC_HRTF_SOFT 0x1992 +#define ALC_DONT_CARE_SOFT 0x0002 +#define ALC_HRTF_STATUS_SOFT 0x1993 +#define ALC_HRTF_DISABLED_SOFT 0x0000 +#define ALC_HRTF_ENABLED_SOFT 0x0001 +#define ALC_HRTF_DENIED_SOFT 0x0002 +#define ALC_HRTF_REQUIRED_SOFT 0x0003 +#define ALC_HRTF_HEADPHONES_DETECTED_SOFT 0x0004 +#define ALC_HRTF_UNSUPPORTED_FORMAT_SOFT 0x0005 +#define ALC_NUM_HRTF_SPECIFIERS_SOFT 0x1994 +#define ALC_HRTF_SPECIFIER_SOFT 0x1995 +#define ALC_HRTF_ID_SOFT 0x1996 +typedef const ALCchar* (ALC_APIENTRY*LPALCGETSTRINGISOFT)(ALCdevice *device, ALCenum paramName, ALCsizei index); +typedef ALCboolean (ALC_APIENTRY*LPALCRESETDEVICESOFT)(ALCdevice *device, const ALCint *attribs); +#ifdef AL_ALEXT_PROTOTYPES +ALC_API const ALCchar* ALC_APIENTRY alcGetStringiSOFT(ALCdevice *device, ALCenum paramName, ALCsizei index); +ALC_API ALCboolean ALC_APIENTRY alcResetDeviceSOFT(ALCdevice *device, const ALCint *attribs); +#endif +#endif + #define MAKE_PTRID(id) ((void*)(uintptr_t)id) #define GET_PTRID(ptr) ((ALuint)(uintptr_t)ptr) @@ -571,6 +593,113 @@ void OpenAL_Output::deinit() } +std::vector OpenAL_Output::enumerateHrtf() +{ + if(!mDevice) + fail("Device not initialized"); + + std::vector ret; + if(!alcIsExtensionPresent(mDevice, "ALC_SOFT_HRTF")) + return ret; + + LPALCGETSTRINGISOFT alcGetStringiSOFT = reinterpret_cast( + alcGetProcAddress(mDevice, "alcGetStringiSOFT") + ); + + ALCint num_hrtf; + alcGetIntegerv(mDevice, ALC_NUM_HRTF_SPECIFIERS_SOFT, 1, &num_hrtf); + ret.reserve(num_hrtf); + for(ALCint i = 0;i < num_hrtf;++i) + { + const ALCchar *entry = alcGetStringiSOFT(mDevice, ALC_HRTF_SPECIFIER_SOFT, i); + ret.push_back(entry); + } + + return ret; +} + +void OpenAL_Output::enableHrtf(const std::string &hrtfname, bool auto_enable) +{ + if(!alcIsExtensionPresent(mDevice, "ALC_SOFT_HRTF")) + { + std::cerr<< "HRTF extension not present" <( + alcGetProcAddress(mDevice, "alcGetStringiSOFT") + ); + LPALCRESETDEVICESOFT alcResetDeviceSOFT = reinterpret_cast( + alcGetProcAddress(mDevice, "alcResetDeviceSOFT") + ); + + std::vector attrs; + attrs.push_back(ALC_HRTF_SOFT); + attrs.push_back(auto_enable ? ALC_DONT_CARE_SOFT : ALC_TRUE); + if(!hrtfname.empty()) + { + ALCint index = -1; + ALCint num_hrtf; + alcGetIntegerv(mDevice, ALC_NUM_HRTF_SPECIFIERS_SOFT, 1, &num_hrtf); + for(ALCint i = 0;i < num_hrtf;++i) + { + const ALCchar *entry = alcGetStringiSOFT(mDevice, ALC_HRTF_SPECIFIER_SOFT, i); + if(hrtfname == entry) + { + index = i; + break; + } + } + + if(index < 0) + std::cerr<< "Failed to find HRTF name \""<( + alcGetProcAddress(mDevice, "alcResetDeviceSOFT") + ); + + std::vector attrs; + attrs.push_back(ALC_HRTF_SOFT); + attrs.push_back(ALC_FALSE); + attrs.push_back(0); + alcResetDeviceSOFT(mDevice, &attrs[0]); + + ALCint hrtf_state; + alcGetIntegerv(mDevice, ALC_HRTF_SOFT, 1, &hrtf_state); + if(hrtf_state) + std::cerr<< "Failed to disable HRTF" < enumerate(); - virtual void init(const std::string &devname=""); + virtual void init(const std::string &devname=std::string()); virtual void deinit(); + virtual std::vector enumerateHrtf(); + virtual void enableHrtf(const std::string &hrtfname, bool auto_enable); + virtual void disableHrtf(); + virtual Sound_Handle loadSound(const std::string &fname); virtual void unloadSound(Sound_Handle data); virtual size_t getSoundDataSize(Sound_Handle data) const; diff --git a/apps/openmw/mwsound/sound_output.hpp b/apps/openmw/mwsound/sound_output.hpp index 2f459d09b..79025abb0 100644 --- a/apps/openmw/mwsound/sound_output.hpp +++ b/apps/openmw/mwsound/sound_output.hpp @@ -24,9 +24,13 @@ namespace MWSound SoundManager &mManager; virtual std::vector enumerate() = 0; - virtual void init(const std::string &devname="") = 0; + virtual void init(const std::string &devname=std::string()) = 0; virtual void deinit() = 0; + virtual std::vector enumerateHrtf() = 0; + virtual void enableHrtf(const std::string &hrtfname, bool auto_enable) = 0; + virtual void disableHrtf() = 0; + virtual Sound_Handle loadSound(const std::string &fname) = 0; virtual void unloadSound(Sound_Handle data) = 0; virtual size_t getSoundDataSize(Sound_Handle data) const = 0; diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 1b7e91285..a13acf3e2 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -67,32 +67,44 @@ namespace MWSound mBufferCacheMax *= 1024*1024; mBufferCacheMin = std::min(mBufferCacheMin*1024*1024, mBufferCacheMax); + std::string hrtfname = Settings::Manager::getString("hrtf", "Sound"); + int hrtfstate = Settings::Manager::getInt("hrtf enable", "Sound"); + std::cout << "Sound output: " << SOUND_OUT << std::endl; std::cout << "Sound decoder: " << SOUND_IN << std::endl; - try - { + try { std::vector names = mOutput->enumerate(); std::cout <<"Enumerated output devices:"<< std::endl; for(size_t i = 0;i < names.size();i++) std::cout <<" "<init(devname); } - catch(std::exception &e) - { + catch(std::exception &e) { if(devname.empty()) throw; std::cerr <<"Failed to open device \""<init(); Settings::Manager::setString("device", "Sound", ""); } + + names = mOutput->enumerateHrtf(); + if(!names.empty()) + { + std::cout <<"Enumerated HRTF names:"<< std::endl; + for(size_t i = 0;i < names.size();i++) + std::cout <<" "<disableHrtf(); + else if(!hrtfname.empty()) + mOutput->enableHrtf(hrtfname, hrtfstate<0); } - catch(std::exception &e) - { + catch(std::exception &e) { std::cout <<"Sound init failed: "<isInitialized()) + SoundBufferList::element_type::iterator sfxiter = mSoundBuffers->begin(); + for(;sfxiter != mSoundBuffers->end();++sfxiter) { - SoundBufferList::element_type::iterator sfxiter = mSoundBuffers->begin(); - for(;sfxiter != mSoundBuffers->end();++sfxiter) - { - if(sfxiter->mHandle) - mOutput->unloadSound(sfxiter->mHandle); - sfxiter->mHandle = 0; - } - mUnusedBuffers.clear(); + if(sfxiter->mHandle) + mOutput->unloadSound(sfxiter->mHandle); + sfxiter->mHandle = 0; } + mUnusedBuffers.clear(); mOutput.reset(); } diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 7d0292c5b..47c389810 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -174,6 +174,13 @@ buffer cache min = 14 # to this much memory until old buffers get purged. buffer cache max = 16 +# Specifies whether to enable HRTF processing. Valid values are: -1 = auto, +# 0 = off, 1 = on. +hrtf enable = -1 + +# Specifies which HRTF to use when HRTF is used. Blank means use the default. +hrtf = + [Video] # Resolution of the OpenMW window or screen. From 91cd6be11b4e23d4e9c9e6a97a33adafcee9999f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 5 Dec 2015 18:00:28 -0800 Subject: [PATCH 2702/3725] Use the correct SoundId for NPC "land" sounds --- apps/openmw/mwclass/npc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 6633b3490..ec37588d9 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -1103,7 +1103,7 @@ namespace MWClass if(world->isUnderwater(ptr.getCell(), pos) || world->isWalkingOnWater(ptr)) return "DefaultLandWater"; if(world->isOnGround(ptr)) - return "Body Fall Medium"; + return "DefaultLand"; return ""; } if(name == "swimleft") From 36ce8f97d7dbbda073576439673e2cee1160ae87 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 6 Dec 2015 11:18:31 +0100 Subject: [PATCH 2703/3725] basic framework for new user settings system --- apps/opencs/CMakeLists.txt | 8 ++++ apps/opencs/editor.cpp | 4 +- apps/opencs/editor.hpp | 7 ++- apps/opencs/model/prefs/state.cpp | 68 +++++++++++++++++++++++++++ apps/opencs/model/prefs/state.hpp | 49 ++++++++++++++++++++ apps/opencs/view/prefs/dialogue.cpp | 72 +++++++++++++++++++++++++++++ apps/opencs/view/prefs/dialogue.hpp | 39 ++++++++++++++++ 7 files changed, 244 insertions(+), 3 deletions(-) create mode 100644 apps/opencs/model/prefs/state.cpp create mode 100644 apps/opencs/model/prefs/state.hpp create mode 100644 apps/opencs/view/prefs/dialogue.cpp create mode 100644 apps/opencs/view/prefs/dialogue.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index dc90072fa..628b97433 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -123,6 +123,10 @@ opencs_units_noqt (view/settings frame ) +opencs_units (view/prefs + dialogue + ) + opencs_units (model/settings usersettings setting @@ -133,6 +137,10 @@ opencs_hdrs_noqt (model/settings support ) +opencs_units (model/prefs + state + ) + opencs_units_noqt (model/filter node unarynode narynode leafnode booleannode parser andnode ornode notnode textnode valuenode ) diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index e3ecdce05..78959fe09 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -18,7 +18,7 @@ #endif CS::Editor::Editor () -: mUserSettings (mCfgMgr), mDocumentManager (mCfgMgr), +: mSettingsState (mCfgMgr), mUserSettings (mCfgMgr), mDocumentManager (mCfgMgr), mViewManager (mDocumentManager), mPid(""), mLock(), mMerge (mDocumentManager), mIpcServerName ("org.openmw.OpenCS"), mServer(NULL), mClientSocket(NULL) @@ -28,7 +28,7 @@ CS::Editor::Editor () setupDataFiles (config.first); CSMSettings::UserSettings::instance().loadSettings ("opencs.ini"); - mSettings.setModel (CSMSettings::UserSettings::instance()); +// mSettings.setModel (CSMSettings::UserSettings::instance()); NifOsg::Loader::setShowMarkers(true); diff --git a/apps/opencs/editor.hpp b/apps/opencs/editor.hpp index ac403b1ee..d7fc0b715 100644 --- a/apps/opencs/editor.hpp +++ b/apps/opencs/editor.hpp @@ -20,6 +20,8 @@ #include "model/settings/usersettings.hpp" #include "model/doc/documentmanager.hpp" +#include "model/prefs/state.hpp" + #include "view/doc/viewmanager.hpp" #include "view/doc/startup.hpp" #include "view/doc/filedialog.hpp" @@ -27,6 +29,8 @@ #include "view/settings/dialog.hpp" +#include "view/prefs/dialogue.hpp" + #include "view/tools/merge.hpp" namespace VFS @@ -49,12 +53,13 @@ namespace CS std::auto_ptr mVFS; Files::ConfigurationManager mCfgMgr; + CSMPrefs::State mSettingsState; CSMSettings::UserSettings mUserSettings; CSMDoc::DocumentManager mDocumentManager; CSVDoc::ViewManager mViewManager; CSVDoc::StartupDialogue mStartup; CSVDoc::NewGameDialogue mNewGame; - CSVSettings::Dialog mSettings; + CSVPrefs::Dialogue mSettings; CSVDoc::FileDialog mFileDialog; boost::filesystem::path mLocal; boost::filesystem::path mResources; diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp new file mode 100644 index 000000000..9b183f66a --- /dev/null +++ b/apps/opencs/model/prefs/state.cpp @@ -0,0 +1,68 @@ + +#include "state.hpp" + +#include + +CSMPrefs::State *CSMPrefs::State::sThis = 0; + +void CSMPrefs::State::load() +{ + // default settings file + boost::filesystem::path local = mConfigurationManager.getLocalPath() / mConfigFile; + boost::filesystem::path global = mConfigurationManager.getGlobalPath() / mConfigFile; + + if (boost::filesystem::exists (local)) + mSettings.loadDefault (local.string()); + else if (boost::filesystem::exists (global)) + mSettings.loadDefault (global.string()); + else + throw std::runtime_error ("No default settings file found! Make sure the file \"opencs.ini\" was properly installed."); + + // user settings file + boost::filesystem::path user = mConfigurationManager.getUserConfigPath() / mConfigFile; + + if (boost::filesystem::exists (user)) + mSettings.loadUser (user.string()); +} + +void CSMPrefs::State::declare() +{ + +} + +CSMPrefs::State::State (const Files::ConfigurationManager& configurationManager) +: mConfigFile ("opencs.ini"), mConfigurationManager (configurationManager) +{ + if (sThis) + throw std::logic_error ("An instance of CSMPRefs::State already exists"); + + load(); + declare(); + + sThis = this; +} + +CSMPrefs::State::~State() +{ + sThis = 0; +} + +void CSMPrefs::State::save() +{ + boost::filesystem::path user = mConfigurationManager.getUserConfigPath() / mConfigFile; + mSettings.saveUser (user.string()); +} + +CSMPrefs::State& CSMPrefs::State::get() +{ + if (!sThis) + throw std::logic_error ("No instance of CSMPrefs::State"); + + return *sThis; +} + + +CSMPrefs::State& CSMPrefs::get() +{ + return State::get(); +} diff --git a/apps/opencs/model/prefs/state.hpp b/apps/opencs/model/prefs/state.hpp new file mode 100644 index 000000000..d2ed8061e --- /dev/null +++ b/apps/opencs/model/prefs/state.hpp @@ -0,0 +1,49 @@ +#ifndef CSV_PREFS_STATE_H +#define CSM_PREFS_STATE_H + +#include + +#ifndef Q_MOC_RUN +#include +#endif + +#include + +namespace CSMPrefs +{ + class State : public QObject + { + Q_OBJECT + + static State *sThis; + + const std::string mConfigFile; + const Files::ConfigurationManager& mConfigurationManager; + Settings::Manager mSettings; + + // not implemented + State (const State&); + State& operator= (const State&); + + private: + + void load(); + + void declare(); + + public: + + State (const Files::ConfigurationManager& configurationManager); + + ~State(); + + void save(); + + static State& get(); + }; + + // convenience function + State& get(); +} + +#endif diff --git a/apps/opencs/view/prefs/dialogue.cpp b/apps/opencs/view/prefs/dialogue.cpp new file mode 100644 index 000000000..5f5ceaada --- /dev/null +++ b/apps/opencs/view/prefs/dialogue.cpp @@ -0,0 +1,72 @@ + +#include "dialogue.hpp" + +#include +#include +#include +#include +#include + +#include "../../model/prefs/state.hpp" + +void CSVPrefs::Dialogue::buildCategorySelector (QSplitter *main) +{ + mList = new QListWidget (main); + mList->setMinimumWidth (50); + mList->setSizePolicy (QSizePolicy::Expanding, QSizePolicy::Expanding); + + mList->setSelectionBehavior (QAbstractItemView::SelectItems); + + main->addWidget (mList); + + /// \todo connect to selection signal +} + +void CSVPrefs::Dialogue::buildContentArea (QSplitter *main) +{ + mContent = new QStackedWidget (main); + mContent->setSizePolicy (QSizePolicy::Preferred, QSizePolicy::Expanding); + + main->addWidget (mContent); +} + +CSVPrefs::Dialogue::Dialogue() +{ + setWindowTitle ("User Settings"); + + setSizePolicy (QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); + + setMinimumSize (600, 400); + + QSplitter *main = new QSplitter (this); + + setCentralWidget (main); + buildCategorySelector (main); + buildContentArea (main); +} + +void CSVPrefs::Dialogue::closeEvent (QCloseEvent *event) +{ + QMainWindow::closeEvent (event); + + CSMPrefs::State::get().save(); +} + +void CSVPrefs::Dialogue::show() +{ + if (QWidget *active = QApplication::activeWindow()) + { + // place at the centre of the window with focus + QSize size = active->size(); + move (active->geometry().x()+(size.width() - frameGeometry().width())/2, + active->geometry().y()+(size.height() - frameGeometry().height())/2); + } + else + { + // otherwise place at the centre of the screen + QPoint screenCenter = QApplication::desktop()->screenGeometry().center(); + move (screenCenter - QPoint(frameGeometry().width()/2, frameGeometry().height()/2)); + } + + QWidget::show(); +} diff --git a/apps/opencs/view/prefs/dialogue.hpp b/apps/opencs/view/prefs/dialogue.hpp new file mode 100644 index 000000000..78c832c9f --- /dev/null +++ b/apps/opencs/view/prefs/dialogue.hpp @@ -0,0 +1,39 @@ +#ifndef CSV_PREFS_DIALOGUE_H +#define CSV_PREFS_DIALOGUE_H + +#include + +class QSplitter; +class QListWidget; +class QStackedWidget; + +namespace CSVPrefs +{ + class Dialogue : public QMainWindow + { + Q_OBJECT + + QListWidget *mList; + QStackedWidget *mContent; + + private: + + void buildCategorySelector (QSplitter *main); + + void buildContentArea (QSplitter *main); + + public: + + Dialogue(); + + protected: + + void closeEvent (QCloseEvent *event); + + public slots: + + void show(); + }; +} + +#endif From b37a2ac09c6f3047514d87c23bf2aed42e0221bd Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 6 Dec 2015 12:06:28 +0100 Subject: [PATCH 2704/3725] user settings categories --- apps/opencs/CMakeLists.txt | 4 +++ apps/opencs/model/prefs/category.cpp | 16 +++++++++ apps/opencs/model/prefs/category.hpp | 26 +++++++++++++++ apps/opencs/model/prefs/state.cpp | 50 +++++++++++++++++++++++++++- apps/opencs/model/prefs/state.hpp | 12 +++++++ apps/opencs/view/prefs/dialogue.cpp | 18 +++++++++- apps/opencs/view/prefs/dialogue.hpp | 1 + 7 files changed, 125 insertions(+), 2 deletions(-) create mode 100644 apps/opencs/model/prefs/category.cpp create mode 100644 apps/opencs/model/prefs/category.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 628b97433..b58000b56 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -141,6 +141,10 @@ opencs_units (model/prefs state ) +opencs_units_noqt (model/prefs + category + ) + opencs_units_noqt (model/filter node unarynode narynode leafnode booleannode parser andnode ornode notnode textnode valuenode ) diff --git a/apps/opencs/model/prefs/category.cpp b/apps/opencs/model/prefs/category.cpp new file mode 100644 index 000000000..2f94c729b --- /dev/null +++ b/apps/opencs/model/prefs/category.cpp @@ -0,0 +1,16 @@ + +#include "category.hpp" + +CSMPrefs::Category::Category (State *parent, const std::string& key, const std::string& name) +: mParent (parent), mKey (key), mName (name) +{} + +const std::string& CSMPrefs::Category::getKey() const +{ + return mKey; +} + +const std::string& CSMPrefs::Category::getName() const +{ + return mName; +} diff --git a/apps/opencs/model/prefs/category.hpp b/apps/opencs/model/prefs/category.hpp new file mode 100644 index 000000000..d80d5416f --- /dev/null +++ b/apps/opencs/model/prefs/category.hpp @@ -0,0 +1,26 @@ +#ifndef CSV_PREFS_CATEGORY_H +#define CSM_PREFS_CATEGORY_H + +#include + +namespace CSMPrefs +{ + class State; + + class Category + { + State *mParent; + std::string mKey; + std::string mName; + + public: + + Category (State *parent, const std::string& key, const std::string& name); + + const std::string& getKey() const; + + const std::string& getName() const; + }; +} + +#endif diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index 9b183f66a..70e4c86c5 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -2,6 +2,7 @@ #include "state.hpp" #include +#include CSMPrefs::State *CSMPrefs::State::sThis = 0; @@ -27,11 +28,45 @@ void CSMPrefs::State::load() void CSMPrefs::State::declare() { + declareCategory ("window", "Windows"); + declareCategory ("records", "Records"); + + declareCategory ("table-input", "ID Tables"); + + declareCategory ("dialogues", "ID Dialogues"); + + declareCategory ("report-input", "Reports"); + + declareCategory ("search", "Search & Replace"); + + declareCategory ("script-editor", "Scripts"); + + declareCategory ("general-input", "General Input"); + + declareCategory ("scene-input", "3D Scene Input"); + + declareCategory ("tooltips", "Tooltips"); +} + +void CSMPrefs::State::declareCategory (const std::string& key, const std::string& name) +{ + std::map::iterator iter = mCategories.find (key); + + if (iter!=mCategories.end()) + { + mCurrentCategory = iter; + } + else + { + mCurrentCategory = + mCategories.insert (std::make_pair (key, Category (this, key, name))).first; + } } CSMPrefs::State::State (const Files::ConfigurationManager& configurationManager) -: mConfigFile ("opencs.ini"), mConfigurationManager (configurationManager) +: mConfigFile ("opencs.ini"), mConfigurationManager (configurationManager), + mCurrentCategory (mCategories.end()) { if (sThis) throw std::logic_error ("An instance of CSMPRefs::State already exists"); @@ -53,6 +88,19 @@ void CSMPrefs::State::save() mSettings.saveUser (user.string()); } +std::vector > CSMPrefs::State::listCategories() const +{ + std::vector > list; + + for (std::map::const_iterator iter (mCategories.begin()); + iter!=mCategories.end(); ++iter) + list.push_back (std::make_pair (iter->second.getName(), iter->first)); + + std::sort (list.begin(), list.end()); + + return list; +} + CSMPrefs::State& CSMPrefs::State::get() { if (!sThis) diff --git a/apps/opencs/model/prefs/state.hpp b/apps/opencs/model/prefs/state.hpp index d2ed8061e..fd49db3ef 100644 --- a/apps/opencs/model/prefs/state.hpp +++ b/apps/opencs/model/prefs/state.hpp @@ -1,6 +1,9 @@ #ifndef CSV_PREFS_STATE_H #define CSM_PREFS_STATE_H +#include +#include + #include #ifndef Q_MOC_RUN @@ -9,6 +12,8 @@ #include +#include "category.hpp" + namespace CSMPrefs { class State : public QObject @@ -20,6 +25,8 @@ namespace CSMPrefs const std::string mConfigFile; const Files::ConfigurationManager& mConfigurationManager; Settings::Manager mSettings; + std::map mCategories; + std::map::iterator mCurrentCategory; // not implemented State (const State&); @@ -31,6 +38,8 @@ namespace CSMPrefs void declare(); + void declareCategory (const std::string& key, const std::string& name); + public: State (const Files::ConfigurationManager& configurationManager); @@ -39,6 +48,9 @@ namespace CSMPrefs void save(); + /// \return collection of name, key pairs (sorted) + std::vector > listCategories() const; + static State& get(); }; diff --git a/apps/opencs/view/prefs/dialogue.cpp b/apps/opencs/view/prefs/dialogue.cpp index 5f5ceaada..cc794c286 100644 --- a/apps/opencs/view/prefs/dialogue.cpp +++ b/apps/opencs/view/prefs/dialogue.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "../../model/prefs/state.hpp" @@ -19,6 +20,21 @@ void CSVPrefs::Dialogue::buildCategorySelector (QSplitter *main) main->addWidget (mList); + QFontMetrics metrics (QApplication::font()); + + int maxWidth = 1; + + for (std::vector >::const_iterator iter (mCategories.begin()); + iter!=mCategories.end(); ++iter) + { + QString label = QString::fromUtf8 (iter->first.c_str()); + maxWidth = std::max (maxWidth, metrics.width (label)); + + mList->addItem (label); + } + + mList->setMaximumWidth (maxWidth + 10); + /// \todo connect to selection signal } @@ -30,7 +46,7 @@ void CSVPrefs::Dialogue::buildContentArea (QSplitter *main) main->addWidget (mContent); } -CSVPrefs::Dialogue::Dialogue() +CSVPrefs::Dialogue::Dialogue() : mCategories (CSMPrefs::get().listCategories()) { setWindowTitle ("User Settings"); diff --git a/apps/opencs/view/prefs/dialogue.hpp b/apps/opencs/view/prefs/dialogue.hpp index 78c832c9f..2773bcccc 100644 --- a/apps/opencs/view/prefs/dialogue.hpp +++ b/apps/opencs/view/prefs/dialogue.hpp @@ -15,6 +15,7 @@ namespace CSVPrefs QListWidget *mList; QStackedWidget *mContent; + std::vector > mCategories; private: From e39f49a88f1e8408a3b035739a8210f514b7037e Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 6 Dec 2015 15:27:43 +0100 Subject: [PATCH 2705/3725] OSG extensions namespace fixes --- components/nifosg/particle.hpp | 4 ++-- components/sceneutil/lightmanager.hpp | 2 +- components/sceneutil/riggeometry.hpp | 2 +- components/sceneutil/skeleton.hpp | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/components/nifosg/particle.hpp b/components/nifosg/particle.hpp index ff4c66758..d86408254 100644 --- a/components/nifosg/particle.hpp +++ b/components/nifosg/particle.hpp @@ -30,7 +30,7 @@ namespace NifOsg ParticleSystem(); ParticleSystem(const ParticleSystem& copy, const osg::CopyOp& copyop); - META_Object(NifOsg, NifOsg::ParticleSystem) + META_Object(NifOsg, ParticleSystem) virtual osgParticle::Particle* createParticle(const osgParticle::Particle *ptemplate); @@ -194,7 +194,7 @@ namespace NifOsg Emitter(); Emitter(const Emitter& copy, const osg::CopyOp& copyop); - META_Object(NifOsg, NifOsg::Emitter) + META_Object(NifOsg, Emitter) virtual void emitParticles(double dt); diff --git a/components/sceneutil/lightmanager.hpp b/components/sceneutil/lightmanager.hpp index 522455390..3e6d3251b 100644 --- a/components/sceneutil/lightmanager.hpp +++ b/components/sceneutil/lightmanager.hpp @@ -158,7 +158,7 @@ namespace SceneUtil , mLastFrameNumber(0) {} - META_Object(NifOsg, LightListCallback) + META_Object(SceneUtil, LightListCallback) void operator()(osg::Node* node, osg::NodeVisitor* nv); diff --git a/components/sceneutil/riggeometry.hpp b/components/sceneutil/riggeometry.hpp index f61fe62e7..03c287b81 100644 --- a/components/sceneutil/riggeometry.hpp +++ b/components/sceneutil/riggeometry.hpp @@ -19,7 +19,7 @@ namespace SceneUtil RigGeometry(); RigGeometry(const RigGeometry& copy, const osg::CopyOp& copyop); - META_Object(NifOsg, RigGeometry) + META_Object(SceneUtil, RigGeometry) struct BoneInfluence { diff --git a/components/sceneutil/skeleton.hpp b/components/sceneutil/skeleton.hpp index d4418fa27..d98d36751 100644 --- a/components/sceneutil/skeleton.hpp +++ b/components/sceneutil/skeleton.hpp @@ -39,7 +39,7 @@ namespace SceneUtil Skeleton(); Skeleton(const Skeleton& copy, const osg::CopyOp& copyop); - META_Node(NifOsg, Skeleton) + META_Node(SceneUtil, Skeleton) /// Retrieve a bone by name. Bone* getBone(const std::string& name); From 1d5af3c9c8415ad376a792bd4deae3d9a7e43b82 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 6 Dec 2015 15:44:27 +0100 Subject: [PATCH 2706/3725] Remove unneeded cast --- components/nifosg/nifloader.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 18ece5101..c2629194d 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -113,7 +113,7 @@ namespace } }; - // NodeCallback used to have a transform always oriented towards the camera. Can have translation and scale + // NodeCallback used to have a node always oriented towards the camera. The node can have translation and scale // set just like a regular MatrixTransform, but the rotation set will be overridden in order to face the camera. // Must be set as a cull callback. class BillboardCallback : public osg::NodeCallback @@ -132,8 +132,7 @@ namespace virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) { osgUtil::CullVisitor* cv = dynamic_cast(nv); - osg::MatrixTransform* billboardNode = dynamic_cast(node); - if (billboardNode && cv) + if (node && cv) { osg::Matrix modelView = *cv->getModelViewMatrix(); From 46f45773ca9655817fe1312bb6cd01bda41facba Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Wed, 19 Aug 2015 11:09:38 +0200 Subject: [PATCH 2707/3725] CMake: Add the list of possible values for some config options Signed-off-by: Paul Cercueil --- CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index db8bcc4f7..43b1e496d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,8 +3,9 @@ project(OpenMW) # If the user doesn't supply a CMAKE_BUILD_TYPE via command line, choose one for them. IF(NOT CMAKE_BUILD_TYPE) SET(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING - "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." + "Choose the type of build, options are: None(CMAKE_CXX_FLAGS or CMAKE_C_FLAGS used) Debug Release RelWithDebInfo MinSizeRel." FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS None Debug Release RelWithDebInfo MinSizeRel) ENDIF() if (APPLE) @@ -175,6 +176,7 @@ endif() # Dependencies if (USE_QT) set(DESIRED_QT_VERSION 4 CACHE STRING "The QT version OpenMW should use (4 or 5)") + set_property(CACHE DESIRED_QT_VERSION PROPERTY STRINGS 4 5) message(STATUS "Using Qt${DESIRED_QT_VERSION}") if (DESIRED_QT_VERSION MATCHES 4) From 0765ff3ba23d625f772b6cc703e68a8270efb00e Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Sun, 6 Dec 2015 15:56:30 +0100 Subject: [PATCH 2708/3725] mwrender: Add missing includes Those missing includes were causing the build to fail when compiled with USE_GLES set. Signed-off-by: Paul Cercueil --- apps/openmw/mwrender/localmap.cpp | 1 + apps/openmw/mwrender/sky.cpp | 2 ++ apps/openmw/mwrender/water.cpp | 1 + 3 files changed, 4 insertions(+) diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 14ec770e8..9d5950a90 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -3,6 +3,7 @@ #include #include +#include #include #include #include diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 68ee17e6b..20e3dc07c 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -2,6 +2,8 @@ #include +#include +#include #include #include #include diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 9823d79df..cd1f4c511 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -2,6 +2,7 @@ #include +#include #include #include #include From b320a01cee8847b9fa19c4e6e68f9fe8cc3cd345 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 6 Dec 2015 17:46:28 +0100 Subject: [PATCH 2709/3725] Update AUTHORS.md --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index e968d1d01..0672c1466 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -88,6 +88,7 @@ Programmers Nikolay Kasyanov (corristo) nobrakal Nolan Poe (nopoe) + Paul Cercueil (pcercuei) Paul McElroy (Greendogo) Pieter van der Kloet (pvdk) pkubik From 811df1e97ba2011b517c8fb16a60b7f920d174a2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 6 Dec 2015 18:03:55 +0100 Subject: [PATCH 2710/3725] Pass the ESM reader list to CellStore constructor --- apps/openmw/mwworld/cells.cpp | 20 ++++++++++---------- apps/openmw/mwworld/cellstore.cpp | 28 +++++++++++++++++----------- apps/openmw/mwworld/cellstore.hpp | 18 ++++++++++++------ 3 files changed, 39 insertions(+), 27 deletions(-) diff --git a/apps/openmw/mwworld/cells.cpp b/apps/openmw/mwworld/cells.cpp index b096301fd..127e43fc0 100644 --- a/apps/openmw/mwworld/cells.cpp +++ b/apps/openmw/mwworld/cells.cpp @@ -23,7 +23,7 @@ MWWorld::CellStore *MWWorld::Cells::getCellStore (const ESM::Cell *cell) if (result==mInteriors.end()) { - result = mInteriors.insert (std::make_pair (lowerName, CellStore (cell))).first; + result = mInteriors.insert (std::make_pair (lowerName, CellStore (cell, mStore, mReader))).first; } return &result->second; @@ -36,7 +36,7 @@ MWWorld::CellStore *MWWorld::Cells::getCellStore (const ESM::Cell *cell) if (result==mExteriors.end()) { result = mExteriors.insert (std::make_pair ( - std::make_pair (cell->getGridX(), cell->getGridY()), CellStore (cell))).first; + std::make_pair (cell->getGridX(), cell->getGridY()), CellStore (cell, mStore, mReader))).first; } @@ -70,7 +70,7 @@ MWWorld::Ptr MWWorld::Cells::getPtrAndCache (const std::string& name, CellStore& void MWWorld::Cells::writeCell (ESM::ESMWriter& writer, CellStore& cell) const { if (cell.getState()!=CellStore::State_Loaded) - cell.load (mStore, mReader); + cell.load (); ESM::CellState cellState; @@ -114,13 +114,13 @@ MWWorld::CellStore *MWWorld::Cells::getExterior (int x, int y) } result = mExteriors.insert (std::make_pair ( - std::make_pair (x, y), CellStore (cell))).first; + std::make_pair (x, y), CellStore (cell, mStore, mReader))).first; } if (result->second.getState()!=CellStore::State_Loaded) { // Multiple plugin support for landscape data is much easier than for references. The last plugin wins. - result->second.load (mStore, mReader); + result->second.load (); } return &result->second; @@ -135,12 +135,12 @@ MWWorld::CellStore *MWWorld::Cells::getInterior (const std::string& name) { const ESM::Cell *cell = mStore.get().find(lowerName); - result = mInteriors.insert (std::make_pair (lowerName, CellStore (cell))).first; + result = mInteriors.insert (std::make_pair (lowerName, CellStore (cell, mStore, mReader))).first; } if (result->second.getState()!=CellStore::State_Loaded) { - result->second.load (mStore, mReader); + result->second.load (); } return &result->second; @@ -158,13 +158,13 @@ MWWorld::Ptr MWWorld::Cells::getPtr (const std::string& name, CellStore& cell, bool searchInContainers) { if (cell.getState()==CellStore::State_Unloaded) - cell.preload (mStore, mReader); + cell.preload (); if (cell.getState()==CellStore::State_Preloaded) { if (cell.hasId (name)) { - cell.load (mStore, mReader); + cell.load (); } else return Ptr(); @@ -333,7 +333,7 @@ bool MWWorld::Cells::readRecord (ESM::ESMReader& reader, uint32_t type, cellStore->readFog(reader); if (cellStore->getState()!=CellStore::State_Loaded) - cellStore->load (mStore, mReader); + cellStore->load (); cellStore->readReferences (reader, contentFileMap); diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 1a1802a05..c435b0478 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -284,8 +284,8 @@ namespace MWWorld functor.merge(); } - CellStore::CellStore (const ESM::Cell *cell) - : mCell (cell), mState (State_Unloaded), mHasState (false), mLastRespawn(0,0) + CellStore::CellStore (const ESM::Cell *cell, const MWWorld::ESMStore& esmStore, std::vector& readerList) + : mStore(esmStore), mReader(readerList), mCell (cell), mState (State_Unloaded), mHasState (false), mLastRespawn(0,0) { mWaterLevel = cell->mWater; } @@ -382,14 +382,14 @@ namespace MWWorld return mMergedRefs.size(); } - void CellStore::load (const MWWorld::ESMStore &store, std::vector &esm) + void CellStore::load () { if (mState!=State_Loaded) { if (mState==State_Preloaded) mIds.clear(); - loadRefs (store, esm); + loadRefs (); mState = State_Loaded; @@ -399,18 +399,20 @@ namespace MWWorld } } - void CellStore::preload (const MWWorld::ESMStore &store, std::vector &esm) + void CellStore::preload () { if (mState==State_Unloaded) { - listRefs (store, esm); + listRefs (); mState = State_Preloaded; } } - void CellStore::listRefs(const MWWorld::ESMStore &store, std::vector &esm) + void CellStore::listRefs() { + std::vector& esm = mReader; + assert (mCell); if (mCell->mContextList.empty()) @@ -462,8 +464,10 @@ namespace MWWorld std::sort (mIds.begin(), mIds.end()); } - void CellStore::loadRefs(const MWWorld::ESMStore &store, std::vector &esm) + void CellStore::loadRefs() { + std::vector& esm = mReader; + assert (mCell); if (mCell->mContextList.empty()) @@ -490,7 +494,7 @@ namespace MWWorld continue; } - loadRef (ref, deleted, store); + loadRef (ref, deleted); } } @@ -499,7 +503,7 @@ namespace MWWorld { ESM::CellRef &ref = const_cast(*it); - loadRef (ref, false, store); + loadRef (ref, false); } updateMergedRefs(); @@ -530,10 +534,12 @@ namespace MWWorld return Ptr(); } - void CellStore::loadRef (ESM::CellRef& ref, bool deleted, const ESMStore& store) + void CellStore::loadRef (ESM::CellRef& ref, bool deleted) { Misc::StringUtils::toLower (ref.mRefID); + const MWWorld::ESMStore& store = mStore; + switch (store.find (ref.mRefID)) { case ESM::REC_ACTI: mActivators.load(ref, deleted, store); break; diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index 2ef03e2c4..80fcaf48a 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -60,6 +60,9 @@ namespace MWWorld private: + const MWWorld::ESMStore& mStore; + std::vector& mReader; + // Even though fog actually belongs to the player and not cells, // it makes sense to store it here since we need it once for each cell. // Note this is NULL until the cell is explored to save some memory @@ -177,7 +180,10 @@ namespace MWWorld template LiveCellRefBase* insert(const LiveCellRef* ref); - CellStore (const ESM::Cell *cell_); + /// @param readerList The readers to use for loading of the cell on-demand. + CellStore (const ESM::Cell *cell_, + const MWWorld::ESMStore& store, + std::vector& readerList); const ESM::Cell *getCell() const; @@ -210,10 +216,10 @@ namespace MWWorld int count() const; ///< Return total number of references, including deleted ones. - void load (const MWWorld::ESMStore &store, std::vector &esm); + void load (); ///< Load references from content file. - void preload (const MWWorld::ESMStore &store, std::vector &esm); + void preload (); ///< Build ID list from content file. /// Call functor (ref) for each reference. functor must return a bool. Returning @@ -267,11 +273,11 @@ namespace MWWorld private: /// Run through references and store IDs - void listRefs(const MWWorld::ESMStore &store, std::vector &esm); + void listRefs(); - void loadRefs(const MWWorld::ESMStore &store, std::vector &esm); + void loadRefs(); - void loadRef (ESM::CellRef& ref, bool deleted, const ESMStore& store); + void loadRef (ESM::CellRef& ref, bool deleted); ///< Make case-adjustments to \a ref and insert it into the respective container. /// /// Invalid \a ref objects are silently dropped. From 2301080c63dee1947ffe04bbb447077087da8dde Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 6 Dec 2015 18:04:48 +0100 Subject: [PATCH 2711/3725] Load CellStore when an object is moved there --- apps/openmw/mwworld/cellstore.cpp | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index c435b0478..10315b126 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -184,6 +184,9 @@ namespace MWWorld void CellStore::moveFrom(const Ptr &object, CellStore *from) { + if (mState != State_Loaded) + load(); + mHasState = true; MovedRefTracker::iterator found = mMovedToAnotherCell.find(object.getBase()); if (found != mMovedToAnotherCell.end()) @@ -196,14 +199,7 @@ namespace MWWorld { mMovedHere.insert(std::make_pair(object.getBase(), from)); } - - if (mState == State_Loaded) - updateMergedRefs(); - else if (mState == State_Preloaded) - { - mIds.push_back(object.getCellRef().getRefId()); - std::sort(mIds.begin(), mIds.end()); - } + updateMergedRefs(); } MWWorld::Ptr CellStore::moveTo(const Ptr &object, CellStore *cellToMoveTo) From 5e99a3eda6400aa4be945acef3473152375e600c Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 6 Dec 2015 18:13:04 +0100 Subject: [PATCH 2712/3725] Rename CellStore Functor to Visitor --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwworld/cellstore.cpp | 20 +++---- apps/openmw/mwworld/cellstore.hpp | 58 +++++++++---------- .../{cellfunctors.hpp => cellvisitors.hpp} | 6 +- apps/openmw/mwworld/scene.cpp | 28 ++++----- apps/openmw/mwworld/worldimp.cpp | 35 ++++++----- 6 files changed, 74 insertions(+), 75 deletions(-) rename apps/openmw/mwworld/{cellfunctors.hpp => cellvisitors.hpp} (78%) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 03ce71f5c..0113fed02 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -62,7 +62,7 @@ add_openmw_dir (mwsound add_openmw_dir (mwworld refdata worldimp scene globals class action nullaction actionteleport - containerstore actiontalk actiontake manualref player cellfunctors failedaction + containerstore actiontalk actiontake manualref player cellvisitors failedaction cells localscripts customdata inventorystore ptr actionopen actionread actionequip timestamp actionalchemy cellstore actionapply actioneat store esmstore recordcmp fallback actionrepair actionsoulgem livecellref actiondoor diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 10315b126..507e3fd7f 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -241,9 +241,9 @@ namespace MWWorld return MWWorld::Ptr(object.getBase(), cellToMoveTo); } - struct MergeFunctor + struct MergeVisitor { - MergeFunctor(std::vector& mergeTo, const std::map& movedHere, + MergeVisitor(std::vector& mergeTo, const std::map& movedHere, const std::map& movedToAnotherCell) : mMergeTo(mergeTo) , mMovedHere(movedHere) @@ -275,9 +275,9 @@ namespace MWWorld void CellStore::updateMergedRefs() { mMergedRefs.clear(); - MergeFunctor functor(mMergedRefs, mMovedHere, mMovedToAnotherCell); - forEachInternal(functor); - functor.merge(); + MergeVisitor visitor(mMergedRefs, mMovedHere, mMovedToAnotherCell); + forEachInternal(visitor); + visitor.merge(); } CellStore::CellStore (const ESM::Cell *cell, const MWWorld::ESMStore& esmStore, std::vector& readerList) @@ -313,7 +313,7 @@ namespace MWWorld return const_cast (this)->search (id).isEmpty(); } - struct SearchFunctor + struct SearchVisitor { MWWorld::Ptr mFound; std::string mIdToFind; @@ -332,12 +332,12 @@ namespace MWWorld { bool oldState = mHasState; - SearchFunctor searchFunctor; - searchFunctor.mIdToFind = id; - forEach(searchFunctor); + SearchVisitor searchVisitor; + searchVisitor.mIdToFind = id; + forEach(searchVisitor); mHasState = oldState; - return searchFunctor.mFound; + return searchVisitor.mFound; } Ptr CellStore::searchViaActorId (int id) diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index 80fcaf48a..cedf2eeb0 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -125,45 +125,45 @@ namespace MWWorld } // helper function for forEachInternal - template - bool forEachImp (Functor& functor, List& list) + template + bool forEachImp (Visitor& visitor, List& list) { for (typename List::List::iterator iter (list.mList.begin()); iter!=list.mList.end(); ++iter) { if (iter->mData.isDeletedByContentFile()) continue; - if (!functor (MWWorld::Ptr(&*iter, this))) + if (!visitor (MWWorld::Ptr(&*iter, this))) return false; } return true; } // listing only objects owned by this cell. Internal use only, you probably want to use forEach() so that moved objects are accounted for. - template - bool forEachInternal (Functor& functor) + template + bool forEachInternal (Visitor& visitor) { return - forEachImp (functor, mActivators) && - forEachImp (functor, mPotions) && - forEachImp (functor, mAppas) && - forEachImp (functor, mArmors) && - forEachImp (functor, mBooks) && - forEachImp (functor, mClothes) && - forEachImp (functor, mContainers) && - forEachImp (functor, mDoors) && - forEachImp (functor, mIngreds) && - forEachImp (functor, mItemLists) && - forEachImp (functor, mLights) && - forEachImp (functor, mLockpicks) && - forEachImp (functor, mMiscItems) && - forEachImp (functor, mProbes) && - forEachImp (functor, mRepairs) && - forEachImp (functor, mStatics) && - forEachImp (functor, mWeapons) && - forEachImp (functor, mCreatures) && - forEachImp (functor, mNpcs) && - forEachImp (functor, mCreatureLists); + forEachImp (visitor, mActivators) && + forEachImp (visitor, mPotions) && + forEachImp (visitor, mAppas) && + forEachImp (visitor, mArmors) && + forEachImp (visitor, mBooks) && + forEachImp (visitor, mClothes) && + forEachImp (visitor, mContainers) && + forEachImp (visitor, mDoors) && + forEachImp (visitor, mIngreds) && + forEachImp (visitor, mItemLists) && + forEachImp (visitor, mLights) && + forEachImp (visitor, mLockpicks) && + forEachImp (visitor, mMiscItems) && + forEachImp (visitor, mProbes) && + forEachImp (visitor, mRepairs) && + forEachImp (visitor, mStatics) && + forEachImp (visitor, mWeapons) && + forEachImp (visitor, mCreatures) && + forEachImp (visitor, mNpcs) && + forEachImp (visitor, mCreatureLists); } public: @@ -222,12 +222,12 @@ namespace MWWorld void preload (); ///< Build ID list from content file. - /// Call functor (ref) for each reference. functor must return a bool. Returning + /// Call visitor (ref) for each reference. visitor must return a bool. Returning /// false will abort the iteration. /// \attention This function also lists deleted (count 0) objects! /// \return Iteration completed? - template - bool forEach (Functor& functor) + template + bool forEach (Visitor& visitor) { if (mState != State_Loaded) return false; @@ -239,7 +239,7 @@ namespace MWWorld if (mMergedRefs[i]->mData.isDeletedByContentFile()) continue; - if (!functor(MWWorld::Ptr(mMergedRefs[i], this))) + if (!visitor(MWWorld::Ptr(mMergedRefs[i], this))) return false; } return true; diff --git a/apps/openmw/mwworld/cellfunctors.hpp b/apps/openmw/mwworld/cellvisitors.hpp similarity index 78% rename from apps/openmw/mwworld/cellfunctors.hpp rename to apps/openmw/mwworld/cellvisitors.hpp index c7fdc793c..cfb07f749 100644 --- a/apps/openmw/mwworld/cellfunctors.hpp +++ b/apps/openmw/mwworld/cellvisitors.hpp @@ -1,5 +1,5 @@ -#ifndef GAME_MWWORLD_CELLFUNCTORS_H -#define GAME_MWWORLD_CELLFUNCTORS_H +#ifndef GAME_MWWORLD_CELLVISITORS_H +#define GAME_MWWORLD_CELLVISITORS_H #include #include @@ -9,7 +9,7 @@ namespace MWWorld { - struct ListAndResetObjects + struct ListAndResetObjectsVisitor { std::vector mObjects; diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 896d5f8eb..00cb8a810 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -22,7 +22,7 @@ #include "localscripts.hpp" #include "esmstore.hpp" #include "class.hpp" -#include "cellfunctors.hpp" +#include "cellvisitors.hpp" #include "cellstore.hpp" namespace @@ -78,7 +78,7 @@ namespace } } - struct InsertFunctor + struct InsertVisitor { MWWorld::CellStore& mCell; bool mRescale; @@ -86,13 +86,13 @@ namespace MWPhysics::PhysicsSystem& mPhysics; MWRender::RenderingManager& mRendering; - InsertFunctor (MWWorld::CellStore& cell, bool rescale, Loading::Listener& loadingListener, + InsertVisitor (MWWorld::CellStore& cell, bool rescale, Loading::Listener& loadingListener, MWPhysics::PhysicsSystem& physics, MWRender::RenderingManager& rendering); bool operator() (const MWWorld::Ptr& ptr); }; - InsertFunctor::InsertFunctor (MWWorld::CellStore& cell, bool rescale, + InsertVisitor::InsertVisitor (MWWorld::CellStore& cell, bool rescale, Loading::Listener& loadingListener, MWPhysics::PhysicsSystem& physics, MWRender::RenderingManager& rendering) : mCell (cell), mRescale (rescale), mLoadingListener (loadingListener), @@ -100,7 +100,7 @@ namespace mRendering (rendering) {} - bool InsertFunctor::operator() (const MWWorld::Ptr& ptr) + bool InsertVisitor::operator() (const MWWorld::Ptr& ptr) { if (mRescale) { @@ -129,7 +129,7 @@ namespace return true; } - struct AdjustPositionFunctor + struct AdjustPositionVisitor { bool operator() (const MWWorld::Ptr& ptr) { @@ -206,11 +206,11 @@ namespace MWWorld void Scene::unloadCell (CellStoreCollection::iterator iter) { std::cout << "Unloading cell\n"; - ListAndResetObjects functor; + ListAndResetObjectsVisitor visitor; - (*iter)->forEach(functor); - for (std::vector::const_iterator iter2 (functor.mObjects.begin()); - iter2!=functor.mObjects.end(); ++iter2) + (*iter)->forEach(visitor); + for (std::vector::const_iterator iter2 (visitor.mObjects.begin()); + iter2!=visitor.mObjects.end(); ++iter2) { mPhysics->remove(*iter2); } @@ -561,12 +561,12 @@ namespace MWWorld void Scene::insertCell (CellStore &cell, bool rescale, Loading::Listener* loadingListener) { - InsertFunctor functor (cell, rescale, *loadingListener, *mPhysics, mRendering); - cell.forEach (functor); + InsertVisitor insertVisitor (cell, rescale, *loadingListener, *mPhysics, mRendering); + cell.forEach (insertVisitor); // do adjustPosition (snapping actors to ground) after objects are loaded, so we don't depend on the loading order - AdjustPositionFunctor adjustPosFunctor; - cell.forEach (adjustPosFunctor); + AdjustPositionVisitor adjustPosVisitor; + cell.forEach (adjustPosVisitor); } void Scene::addObjectToScene (const Ptr& ptr) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index bb2ca2aae..3efce5c9e 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -54,7 +54,6 @@ #include "player.hpp" #include "manualref.hpp" #include "cellstore.hpp" -#include "cellfunctors.hpp" #include "containerstore.hpp" #include "inventorystore.hpp" #include "actionteleport.hpp" @@ -690,12 +689,12 @@ namespace MWWorld return mWorldScene->searchPtrViaActorId (actorId); } - struct FindContainerFunctor + struct FindContainerVisitor { Ptr mContainedPtr; Ptr mResult; - FindContainerFunctor(const Ptr& containedPtr) : mContainedPtr(containedPtr) {} + FindContainerVisitor(const Ptr& containedPtr) : mContainedPtr(containedPtr) {} bool operator() (Ptr ptr) { @@ -721,11 +720,11 @@ namespace MWWorld const Scene::CellStoreCollection& collection = mWorldScene->getActiveCells(); for (Scene::CellStoreCollection::const_iterator cellIt = collection.begin(); cellIt != collection.end(); ++cellIt) { - FindContainerFunctor functor(ptr); - //(*cellIt)->forEachContainer(functor); + FindContainerVisitor visitor(ptr); + //(*cellIt)->forEachContainer(visitor); - if (!functor.mResult.isEmpty()) - return functor.mResult; + if (!visitor.mResult.isEmpty()) + return visitor.mResult; } return Ptr(); @@ -2262,7 +2261,7 @@ namespace MWWorld */ } - struct ListObjectsFunctor + struct ListObjectsVisitor { std::vector mObjects; @@ -2279,10 +2278,10 @@ namespace MWWorld const Scene::CellStoreCollection& collection = mWorldScene->getActiveCells(); for (Scene::CellStoreCollection::const_iterator cellIt = collection.begin(); cellIt != collection.end(); ++cellIt) { - ListObjectsFunctor functor; - (*cellIt)->forEach(functor); + ListObjectsVisitor visitor; + (*cellIt)->forEach(visitor); - for (std::vector::iterator it = functor.mObjects.begin(); it != functor.mObjects.end(); ++it) + for (std::vector::iterator it = visitor.mObjects.begin(); it != visitor.mObjects.end(); ++it) if (Misc::StringUtils::ciEqual(it->getCellRef().getOwner(), npc.getCellRef().getRefId())) out.push_back(*it); } @@ -2886,9 +2885,9 @@ namespace MWWorld mWeatherManager->update(duration, paused); } - struct AddDetectedReference + struct AddDetectedReferenceVisitor { - AddDetectedReference(std::vector& out, Ptr detector, World::DetectionType type, float squaredDist) + AddDetectedReferenceVisitor(std::vector& out, Ptr detector, World::DetectionType type, float squaredDist) : mOut(out), mDetector(detector), mSquaredDist(squaredDist), mType(type) { } @@ -2968,13 +2967,13 @@ namespace MWWorld dist = feetToGameUnits(dist); - AddDetectedReference functor (out, ptr, type, dist*dist); + AddDetectedReferenceVisitor visitor (out, ptr, type, dist*dist); const Scene::CellStoreCollection& active = mWorldScene->getActiveCells(); for (Scene::CellStoreCollection::const_iterator it = active.begin(); it != active.end(); ++it) { MWWorld::CellStore* cellStore = *it; - cellStore->forEach(functor); + cellStore->forEach(visitor); } } @@ -3230,7 +3229,7 @@ namespace MWWorld interpreterContext.executeActivation(object, actor); } - struct ResetActorsFunctor + struct ResetActorsVisitor { bool operator() (Ptr ptr) { @@ -3252,8 +3251,8 @@ namespace MWWorld iter!=mWorldScene->getActiveCells().end(); ++iter) { CellStore* cellstore = *iter; - ResetActorsFunctor functor; - cellstore->forEach(functor); + ResetActorsVisitor visitor; + cellstore->forEach(visitor); } } From 138957c49aaa892e199c58371c7b3961b252945c Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 6 Dec 2015 18:43:52 +0100 Subject: [PATCH 2713/3725] Special case objects with no refnum --- apps/openmw/mwworld/cellstore.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 507e3fd7f..edeb4f08d 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -213,6 +213,15 @@ namespace MWWorld // TODO: ensure that the object actually exists in the cell + // Objects with no refnum can't be handled correctly in the merging process that happens + // on a save/load, so do a simple copy & delete for these objects. + if (!object.getCellRef().getRefNum().hasContentFile()) + { + MWWorld::Ptr copied = object.getClass().copyToCell(object, *cellToMoveTo); + object.getRefData().setCount(0); + return copied; + } + MovedRefTracker::iterator found = mMovedHere.find(object.getBase()); if (found != mMovedHere.end()) { From 2219231230b31c2024300d11cbd48293794c678d Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 6 Dec 2015 18:46:49 +0100 Subject: [PATCH 2714/3725] Missing updateMergedRefs() --- apps/openmw/mwworld/cellstore.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index edeb4f08d..47677064e 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -770,6 +770,7 @@ namespace MWWorld throw std::runtime_error ("unknown type in cell reference section"); } } + updateMergedRefs(); } bool operator== (const CellStore& left, const CellStore& right) From 671561ea37dc8e3c172030ca150cbe1527a448a7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 6 Dec 2015 19:11:25 +0100 Subject: [PATCH 2715/3725] Write moved references to the save game file (not resolved on loading yet) --- apps/openmw/mwworld/cells.cpp | 1 - apps/openmw/mwworld/cellstore.cpp | 22 +++++++++++++++++++++- apps/openmw/mwworld/cellstore.hpp | 2 ++ components/esm/cellref.cpp | 6 +++--- components/esm/cellref.hpp | 2 +- 5 files changed, 27 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwworld/cells.cpp b/apps/openmw/mwworld/cells.cpp index 127e43fc0..b410e6488 100644 --- a/apps/openmw/mwworld/cells.cpp +++ b/apps/openmw/mwworld/cells.cpp @@ -119,7 +119,6 @@ MWWorld::CellStore *MWWorld::Cells::getExterior (int x, int y) if (result->second.getState()!=CellStore::State_Loaded) { - // Multiple plugin support for landscape data is much easier than for references. The last plugin wins. result->second.load (); } diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 47677064e..578e5ed55 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -636,7 +636,15 @@ namespace MWWorld writeReferenceCollection (writer, mStatics); writeReferenceCollection (writer, mWeapons); - // TODO: write moved references + for (MovedRefTracker::const_iterator it = mMovedToAnotherCell.begin(); it != mMovedToAnotherCell.end(); ++it) + { + LiveCellRefBase* base = it->first; + ESM::RefNum refNum = base->mRef.getRefNum(); + ESM::CellId movedTo = it->second->getCell()->getCellId(); + + refNum.save(writer, true, "MVRF"); + movedTo.save(writer); + } } void CellStore::readReferences (ESM::ESMReader& reader, @@ -770,6 +778,18 @@ namespace MWWorld throw std::runtime_error ("unknown type in cell reference section"); } } + + while (reader.isNextSub("MVRF")) + { + reader.cacheSubName(); + ESM::RefNum refnum; + ESM::CellId movedTo; + refnum.load(reader, true, "MVRF"); + movedTo.load(reader); + + std::cout << "moved to " << movedTo.mWorldspace << " " << movedTo.mIndex.mX << " " << movedTo.mIndex.mY << std::endl; + } + updateMergedRefs(); } diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index cedf2eeb0..892a5c06b 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -12,6 +12,8 @@ #include "livecellref.hpp" #include "cellreflist.hpp" +#include + #include #include #include diff --git a/components/esm/cellref.cpp b/components/esm/cellref.cpp index 76a82fe23..7acaed86d 100644 --- a/components/esm/cellref.cpp +++ b/components/esm/cellref.cpp @@ -3,12 +3,12 @@ #include "esmreader.hpp" #include "esmwriter.hpp" -void ESM::RefNum::load (ESMReader& esm, bool wide) +void ESM::RefNum::load (ESMReader& esm, bool wide, const std::string& tag) { if (wide) - esm.getHNT (*this, "FRMR", 8); + esm.getHNT (*this, tag.c_str(), 8); else - esm.getHNT (mIndex, "FRMR"); + esm.getHNT (mIndex, tag.c_str()); } void ESM::RefNum::save (ESMWriter &esm, bool wide, const std::string& tag) const diff --git a/components/esm/cellref.hpp b/components/esm/cellref.hpp index c371a4f01..3c646cc61 100644 --- a/components/esm/cellref.hpp +++ b/components/esm/cellref.hpp @@ -16,7 +16,7 @@ namespace ESM unsigned int mIndex; int mContentFile; - void load (ESMReader& esm, bool wide = false); + void load (ESMReader& esm, bool wide = false, const std::string& tag = "FRMR"); void save (ESMWriter &esm, bool wide = false, const std::string& tag = "FRMR") const; From 176a3c16f4d595c28b3b5f0fab8192bfa0bcdf33 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 6 Dec 2015 19:53:06 +0100 Subject: [PATCH 2716/3725] Resolve moved references loaded from a save game --- apps/openmw/mwworld/cells.cpp | 31 +++++++++++++++-- apps/openmw/mwworld/cellstore.cpp | 57 ++++++++++++++++++++++++++++--- apps/openmw/mwworld/cellstore.hpp | 13 +++++-- 3 files changed, 91 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwworld/cells.cpp b/apps/openmw/mwworld/cells.cpp index b410e6488..109447959 100644 --- a/apps/openmw/mwworld/cells.cpp +++ b/apps/openmw/mwworld/cells.cpp @@ -1,5 +1,7 @@ #include "cells.hpp" +#include + #include #include #include @@ -303,6 +305,29 @@ void MWWorld::Cells::write (ESM::ESMWriter& writer, Loading::Listener& progress) } } +struct GetCellStoreCallback : public MWWorld::CellStore::GetCellStoreCallback +{ +public: + GetCellStoreCallback(MWWorld::Cells& cells) + : mCells(cells) + { + } + + MWWorld::Cells& mCells; + + virtual MWWorld::CellStore* getCellStore(const ESM::CellId& cellId) + { + try + { + return mCells.getCell(cellId); + } + catch (...) + { + return NULL; + } + } +}; + bool MWWorld::Cells::readRecord (ESM::ESMReader& reader, uint32_t type, const std::map& contentFileMap) { @@ -320,9 +345,9 @@ bool MWWorld::Cells::readRecord (ESM::ESMReader& reader, uint32_t type, catch (...) { // silently drop cells that don't exist anymore + std::cerr << "Dropping state for cell " << state.mId.mWorldspace << " (cell no longer exists)" << std::endl; reader.skipRecord(); return true; - /// \todo log } state.load (reader); @@ -334,7 +359,9 @@ bool MWWorld::Cells::readRecord (ESM::ESMReader& reader, uint32_t type, if (cellStore->getState()!=CellStore::State_Loaded) cellStore->load (); - cellStore->readReferences (reader, contentFileMap); + GetCellStoreCallback callback(*this); + + cellStore->readReferences (reader, contentFileMap, &callback); return true; } diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 578e5ed55..cf9c4d830 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -613,6 +613,28 @@ namespace MWWorld mFogState->load(reader); } + struct SearchByRefNumVisitor + { + LiveCellRefBase* mFound; + ESM::RefNum mRefNumToFind; + + SearchByRefNumVisitor(const ESM::RefNum& toFind) + : mFound(NULL) + , mRefNumToFind(toFind) + { + } + + bool operator()(const MWWorld::Ptr& ptr) + { + if (ptr.getCellRef().getRefNum() == mRefNumToFind) + { + mFound = ptr.getBase(); + return false; + } + return true; + } + }; + void CellStore::writeReferences (ESM::ESMWriter& writer) const { writeReferenceCollection (writer, mActivators); @@ -647,11 +669,8 @@ namespace MWWorld } } - void CellStore::readReferences (ESM::ESMReader& reader, - const std::map& contentFileMap) + void CellStore::readReferences (ESM::ESMReader& reader, const std::map& contentFileMap, GetCellStoreCallback* callback) { - // TODO: read moved references - mHasState = true; while (reader.isNextSub ("OBJE")) @@ -787,7 +806,35 @@ namespace MWWorld refnum.load(reader, true, "MVRF"); movedTo.load(reader); - std::cout << "moved to " << movedTo.mWorldspace << " " << movedTo.mIndex.mX << " " << movedTo.mIndex.mY << std::endl; + // Search for the reference. It might no longer exist if its content file was removed. + SearchByRefNumVisitor visitor(refnum); + forEachInternal(visitor); + + if (!visitor.mFound) + { + std::cout << "Dropping moved ref tag for " << visitor.mFound->mRef.getRefId() << " (moved object no longer exists)" << std::endl; + continue; + } + + CellStore* otherCell = callback->getCellStore(movedTo); + + if (otherCell == NULL) + { + std::cerr << "Dropping moved ref tag for " << visitor.mFound->mRef.getRefId() + << " (target cell " << movedTo.mWorldspace << " no longer exists). Reference moved back to its original location." << std::endl; + // Note by dropping tag the object will automatically re-appear in its original cell, though potentially at inapproriate coordinates. + // Restore original coordinates: + visitor.mFound->mData.setPosition(visitor.mFound->mRef.getPosition()); + continue; + } + + if (otherCell == this) + { + std::cerr << "Found invalid moved ref, ignoring" << std::endl; + continue; + } + + moveTo(MWWorld::Ptr(visitor.mFound, this), otherCell); } updateMergedRefs(); diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index 892a5c06b..542d4700e 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -12,8 +12,6 @@ #include "livecellref.hpp" #include "cellreflist.hpp" -#include - #include #include #include @@ -42,6 +40,7 @@ namespace ESM { struct CellState; struct FogState; + struct CellId; } namespace MWWorld @@ -263,7 +262,15 @@ namespace MWWorld void writeReferences (ESM::ESMWriter& writer) const; - void readReferences (ESM::ESMReader& reader, const std::map& contentFileMap); + struct GetCellStoreCallback + { + public: + ///@note must return NULL if the cell is not found + virtual CellStore* getCellStore(const ESM::CellId& cellId) = 0; + }; + + /// @param callback to use for retrieving of additional CellStore objects by ID (required for resolving moved references) + void readReferences (ESM::ESMReader& reader, const std::map& contentFileMap, GetCellStoreCallback* callback); void respawn (); ///< Check mLastRespawn and respawn references if necessary. This is a no-op if the cell is not loaded. From 0af33b5abd71878d7c7e1b78e247375634fcf9ba Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 6 Dec 2015 20:05:13 +0100 Subject: [PATCH 2717/3725] Throw exception if moveTo() is passed an object not part of *this --- apps/openmw/mwworld/cellstore.cpp | 56 +++++++++++++++++-------------- 1 file changed, 31 insertions(+), 25 deletions(-) diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index cf9c4d830..4f28fcfdf 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -144,6 +144,28 @@ namespace ref.load (state); collection.mList.push_back (ref); } + + struct SearchByRefNumVisitor + { + MWWorld::LiveCellRefBase* mFound; + ESM::RefNum mRefNumToFind; + + SearchByRefNumVisitor(const ESM::RefNum& toFind) + : mFound(NULL) + , mRefNumToFind(toFind) + { + } + + bool operator()(const MWWorld::Ptr& ptr) + { + if (ptr.getCellRef().getRefNum() == mRefNumToFind) + { + mFound = ptr.getBase(); + return false; + } + return true; + } + }; } namespace MWWorld @@ -205,13 +227,18 @@ namespace MWWorld MWWorld::Ptr CellStore::moveTo(const Ptr &object, CellStore *cellToMoveTo) { if (cellToMoveTo == this) - throw std::runtime_error("object is already in this cell"); + throw std::runtime_error("moveTo: object is already in this cell"); // We assume that *this is in State_Loaded since we could hardly have reference to a live object otherwise. if (mState != State_Loaded) - throw std::runtime_error("can't move object from a non-loaded cell (how did you get this object anyway?)"); + throw std::runtime_error("moveTo: can't move object from a non-loaded cell (how did you get this object anyway?)"); + + // Ensure that the object actually exists in the cell + SearchByRefNumVisitor searchVisitor(object.getCellRef().getRefNum()); + forEach(searchVisitor); + if (!searchVisitor.mFound) + throw std::runtime_error("moveTo: object is not in this cell"); - // TODO: ensure that the object actually exists in the cell // Objects with no refnum can't be handled correctly in the merging process that happens // on a save/load, so do a simple copy & delete for these objects. @@ -613,28 +640,6 @@ namespace MWWorld mFogState->load(reader); } - struct SearchByRefNumVisitor - { - LiveCellRefBase* mFound; - ESM::RefNum mRefNumToFind; - - SearchByRefNumVisitor(const ESM::RefNum& toFind) - : mFound(NULL) - , mRefNumToFind(toFind) - { - } - - bool operator()(const MWWorld::Ptr& ptr) - { - if (ptr.getCellRef().getRefNum() == mRefNumToFind) - { - mFound = ptr.getBase(); - return false; - } - return true; - } - }; - void CellStore::writeReferences (ESM::ESMWriter& writer) const { writeReferenceCollection (writer, mActivators); @@ -830,6 +835,7 @@ namespace MWWorld if (otherCell == this) { + // Should never happen unless someone's tampering with files. std::cerr << "Found invalid moved ref, ignoring" << std::endl; continue; } From a517f4f9bad647489c654429285aef2770d08b9e Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 6 Dec 2015 20:19:07 +0100 Subject: [PATCH 2718/3725] Add CellStore::forEachType to help with porting over game logic to the new interfaces --- apps/openmw/mwworld/cellstore.hpp | 177 +++++++++++++++++++++--------- 1 file changed, 127 insertions(+), 50 deletions(-) diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index 542d4700e..ae8ac8ae5 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -116,15 +116,6 @@ namespace MWWorld /// Repopulate mMergedRefs. void updateMergedRefs(); - template - LiveCellRefBase* insertBase(CellRefList& list, const LiveCellRef* ref) - { - mHasState = true; - LiveCellRefBase* ret = &list.insert(*ref); - updateMergedRefs(); - return ret; - } - // helper function for forEachInternal template bool forEachImp (Visitor& visitor, List& list) @@ -167,6 +158,11 @@ namespace MWWorld forEachImp (visitor, mCreatureLists); } + /// @note If you get a linker error here, this means the given type can not be stored in a cell. The supported types are + /// defined at the bottom of this file. + template + CellRefList& get(); + public: /// Moves object from this cell to the given cell. @@ -179,7 +175,14 @@ namespace MWWorld /// @note If you get a linker error here, this means the given type can not be inserted into a cell. /// The supported types are defined at the bottom of this file. template - LiveCellRefBase* insert(const LiveCellRef* ref); + LiveCellRefBase* insert(const LiveCellRef* ref) + { + mHasState = true; + CellRefList& list = get(); + LiveCellRefBase* ret = &list.insert(*ref); + updateMergedRefs(); + return ret; + } /// @param readerList The readers to use for loading of the cell on-demand. CellStore (const ESM::Cell *cell_, @@ -246,6 +249,41 @@ namespace MWWorld return true; } + /// Call visitor (ref) for each reference of given type. visitor must return a bool. Returning + /// false will abort the iteration. + /// \attention This function also lists deleted (count 0) objects! + /// \return Iteration completed? + template + bool forEachType(Visitor& visitor) + { + if (mState != State_Loaded) + return false; + + mHasState = true; + + CellRefList& list = get(); + + for (typename CellRefList::List::iterator it (list.mList.begin()); it!=list.mList.end(); ++it) + { + LiveCellRefBase* base = &*it; + if (mMovedToAnotherCell.find(base) != mMovedToAnotherCell.end()) + continue; + if (base->mData.isDeletedByContentFile()) + continue; + if (!visitor(MWWorld::Ptr(base, this))) + return false; + } + + for (MovedRefTracker::const_iterator it = mMovedHere.begin(); it != mMovedHere.end(); ++it) + { + LiveCellRefBase* base = it->first; + if (dynamic_cast*>(base)) + if (!visitor(MWWorld::Ptr(base, this))) + return false; + } + return true; + } + /// \todo add const version of forEach bool isExterior() const; @@ -295,104 +333,143 @@ namespace MWWorld }; template<> - inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + inline CellRefList& CellStore::get() { - return insertBase(mActivators, ref); + mHasState = true; + return mActivators; } + template<> - inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + inline CellRefList& CellStore::get() { - return insertBase(mPotions, ref); + mHasState = true; + return mPotions; } + template<> - inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + inline CellRefList& CellStore::get() { - return insertBase(mAppas, ref); + mHasState = true; + return mAppas; } + template<> - inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + inline CellRefList& CellStore::get() { - return insertBase(mArmors, ref); + mHasState = true; + return mArmors; } + template<> - inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + inline CellRefList& CellStore::get() { - return insertBase(mBooks, ref); + mHasState = true; + return mBooks; } + template<> - inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + inline CellRefList& CellStore::get() { - return insertBase(mClothes, ref); + mHasState = true; + return mClothes; } + template<> - inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + inline CellRefList& CellStore::get() { - return insertBase(mContainers, ref); + mHasState = true; + return mContainers; } + template<> - inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + inline CellRefList& CellStore::get() { - return insertBase(mCreatures, ref); + mHasState = true; + return mCreatures; } + template<> - inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + inline CellRefList& CellStore::get() { - return insertBase(mDoors, ref); + mHasState = true; + return mDoors; } + template<> - inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + inline CellRefList& CellStore::get() { - return insertBase(mIngreds, ref); + mHasState = true; + return mIngreds; } + template<> - inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + inline CellRefList& CellStore::get() { - return insertBase(mCreatureLists, ref); + mHasState = true; + return mCreatureLists; } + template<> - inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + inline CellRefList& CellStore::get() { - return insertBase(mItemLists, ref); + mHasState = true; + return mItemLists; } + template<> - inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + inline CellRefList& CellStore::get() { - return insertBase(mLights, ref); + mHasState = true; + return mLights; } + template<> - inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + inline CellRefList& CellStore::get() { - return insertBase(mLockpicks, ref); + mHasState = true; + return mLockpicks; } + template<> - inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + inline CellRefList& CellStore::get() { - return insertBase(mMiscItems, ref); + mHasState = true; + return mMiscItems; } + template<> - inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + inline CellRefList& CellStore::get() { - return insertBase(mNpcs, ref); + mHasState = true; + return mNpcs; } + template<> - inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + inline CellRefList& CellStore::get() { - return insertBase(mProbes, ref); + mHasState = true; + return mProbes; } + template<> - inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + inline CellRefList& CellStore::get() { - return insertBase(mRepairs, ref); + mHasState = true; + return mRepairs; } + template<> - inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + inline CellRefList& CellStore::get() { - return insertBase(mStatics, ref); + mHasState = true; + return mStatics; } + template<> - inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + inline CellRefList& CellStore::get() { - return insertBase(mWeapons, ref); + mHasState = true; + return mWeapons; } bool operator== (const CellStore& left, const CellStore& right); From 9ea475d00cd85f179e4eec10dd788a78e8435bd5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 6 Dec 2015 20:30:52 +0100 Subject: [PATCH 2719/3725] Port LocalScripts::addCell to new CellStore interfaces --- apps/openmw/mwworld/localscripts.cpp | 89 +++++++++++++--------------- 1 file changed, 41 insertions(+), 48 deletions(-) diff --git a/apps/openmw/mwworld/localscripts.cpp b/apps/openmw/mwworld/localscripts.cpp index aa5abc076..030a41891 100644 --- a/apps/openmw/mwworld/localscripts.cpp +++ b/apps/openmw/mwworld/localscripts.cpp @@ -11,46 +11,54 @@ namespace { - template - void listCellScripts (MWWorld::LocalScripts& localScripts, - MWWorld::CellRefList& cellRefList, MWWorld::CellStore *cell) + + struct AddScriptsVisitor { - for (typename MWWorld::CellRefList::List::iterator iter ( - cellRefList.mList.begin()); - iter!=cellRefList.mList.end(); ++iter) + AddScriptsVisitor(MWWorld::LocalScripts& scripts) + : mScripts(scripts) { - if (!iter->mBase->mScript.empty() && !iter->mData.isDeleted()) - { - localScripts.add (iter->mBase->mScript, MWWorld::Ptr (&*iter, cell)); - } } - } + MWWorld::LocalScripts& mScripts; - // Adds scripts for items in containers (containers/npcs/creatures) - template - void listCellScriptsCont (MWWorld::LocalScripts& localScripts, - MWWorld::CellRefList& cellRefList, MWWorld::CellStore *cell) - { - for (typename MWWorld::CellRefList::List::iterator iter ( - cellRefList.mList.begin()); - iter!=cellRefList.mList.end(); ++iter) + bool operator()(const MWWorld::Ptr& ptr) { + if (ptr.getRefData().isDeleted()) + return true; + + std::string script = ptr.getClass().getScript(ptr); + + if (!script.empty()) + mScripts.add(script, ptr); + + return true; + } + }; - MWWorld::Ptr containerPtr (&*iter, cell); + struct AddContainerItemScriptsVisitor + { + AddContainerItemScriptsVisitor(MWWorld::LocalScripts& scripts) + : mScripts(scripts) + { + } + MWWorld::LocalScripts& mScripts; + bool operator()(const MWWorld::Ptr& containerPtr) + { MWWorld::ContainerStore& container = containerPtr.getClass().getContainerStore(containerPtr); - for(MWWorld::ContainerStoreIterator it3 = container.begin(); it3 != container.end(); ++it3) + for(MWWorld::ContainerStoreIterator it = container.begin(); it != container.end(); ++it) { - std::string script = it3->getClass().getScript(*it3); + std::string script = it->getClass().getScript(*it); if(script != "") { - MWWorld::Ptr item = *it3; - item.mCell = cell; - localScripts.add (script, item); + MWWorld::Ptr item = *it; + item.mCell = containerPtr.getCell(); + mScripts.add (script, item); } } + return true; } - } + }; + } MWWorld::LocalScripts::LocalScripts (const MWWorld::ESMStore& store) : mStore (store) {} @@ -116,28 +124,13 @@ void MWWorld::LocalScripts::add (const std::string& scriptName, const Ptr& ptr) void MWWorld::LocalScripts::addCell (CellStore *cell) { - /* - listCellScripts (*this, cell->get(), cell); - listCellScripts (*this, cell->get(), cell); - listCellScripts (*this, cell->get(), cell); - listCellScripts (*this, cell->get(), cell); - listCellScripts (*this, cell->get(), cell); - listCellScripts (*this, cell->get(), cell); - listCellScripts (*this, cell->get(), cell); - listCellScriptsCont (*this, cell->get(), cell); - listCellScripts (*this, cell->get(), cell); - listCellScriptsCont (*this, cell->get(), cell); - listCellScripts (*this, cell->get(), cell); - listCellScripts (*this, cell->get(), cell); - listCellScripts (*this, cell->get(), cell); - listCellScripts (*this, cell->get(), cell); - listCellScripts (*this, cell->get(), cell); - listCellScripts (*this, cell->get(), cell); - listCellScriptsCont (*this, cell->get(), cell); - listCellScripts (*this, cell->get(), cell); - listCellScripts (*this, cell->get(), cell); - listCellScripts (*this, cell->get(), cell); - */ + AddScriptsVisitor addScriptsVisitor(*this); + cell->forEach(addScriptsVisitor); + + AddContainerItemScriptsVisitor addContainerItemScriptsVisitor(*this); + cell->forEachType(addContainerItemScriptsVisitor); + cell->forEachType(addContainerItemScriptsVisitor); + cell->forEachType(addContainerItemScriptsVisitor); } void MWWorld::LocalScripts::clear() From abcf91be5b0312a60dfbaa3b4c31f006d4b1fec3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 6 Dec 2015 20:43:50 +0100 Subject: [PATCH 2720/3725] Port over more game logic to the visitor pattern --- apps/openmw/mwworld/worldimp.cpp | 84 ++++++++++++++++++++------------ 1 file changed, 52 insertions(+), 32 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 3efce5c9e..cfb7b5c82 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1691,31 +1691,32 @@ namespace MWWorld osg::Vec2f World::getNorthVector (CellStore* cell) { - /* - MWWorld::CellRefList& statics = cell->get(); - MWWorld::LiveCellRef* ref = statics.find("northmarker"); - if (!ref) + MWWorld::Ptr northmarker = cell->search("northmarker"); + + if (northmarker.isEmpty()) return osg::Vec2f(0, 1); - osg::Quat orient (-ref->mData.getPosition().rot[2], osg::Vec3f(0,0,1)); + osg::Quat orient (-northmarker.getRefData().getPosition().rot[2], osg::Vec3f(0,0,1)); osg::Vec3f dir = orient * osg::Vec3f(0,1,0); osg::Vec2f d (dir.x(), dir.y()); return d; - */ - return osg::Vec2f(); } - void World::getDoorMarkers (CellStore* cell, std::vector& out) + struct GetDoorMarkerVisitor { - /* - MWWorld::CellRefList& doors = cell->get(); - CellRefList::List& refList = doors.mList; - for (CellRefList::List::iterator it = refList.begin(); it != refList.end(); ++it) + GetDoorMarkerVisitor(std::vector& out) + : mOut(out) { - MWWorld::LiveCellRef& ref = *it; + } - if (!ref.mData.isEnabled()) - continue; + std::vector& mOut; + + bool operator()(const MWWorld::Ptr& ptr) + { + MWWorld::LiveCellRef& ref = *static_cast* >(ptr.getBase()); + + if (!ref.mData.isEnabled() || ref.mData.isDeleted()) + return true; if (ref.mRef.getTeleport()) { @@ -1731,7 +1732,7 @@ namespace MWWorld else { cellid.mPaged = true; - positionToIndex( + MWBase::Environment::get().getWorld()->positionToIndex( ref.mRef.getDoorDest().pos[0], ref.mRef.getDoorDest().pos[1], cellid.mIndex.mX, @@ -1743,10 +1744,16 @@ namespace MWWorld newMarker.x = pos.pos[0]; newMarker.y = pos.pos[1]; - out.push_back(newMarker); + mOut.push_back(newMarker); } + return true; } - */ + }; + + void World::getDoorMarkers (CellStore* cell, std::vector& out) + { + GetDoorMarkerVisitor visitor(out); + cell->forEachType(visitor); } void World::setWaterHeight(const float height) @@ -2241,24 +2248,37 @@ namespace MWWorld return osg::Vec3f(0,1,0); } - void World::getContainersOwnedBy (const MWWorld::Ptr& npc, std::vector& out) + struct GetContainersOwnedByVisitor + { + GetContainersOwnedByVisitor(const MWWorld::Ptr& owner, std::vector& out) + : mOwner(owner) + , mOut(out) + { + } + + MWWorld::Ptr mOwner; + std::vector& mOut; + + bool operator()(const MWWorld::Ptr& ptr) + { + if (ptr.getRefData().isDeleted()) + return true; + + if (Misc::StringUtils::ciEqual(ptr.getCellRef().getOwner(), mOwner.getCellRef().getRefId())) + mOut.push_back(ptr); + + return true; + } + }; + + void World::getContainersOwnedBy (const MWWorld::Ptr& owner, std::vector& out) { - /* const Scene::CellStoreCollection& collection = mWorldScene->getActiveCells(); for (Scene::CellStoreCollection::const_iterator cellIt = collection.begin(); cellIt != collection.end(); ++cellIt) { - MWWorld::CellRefList& containers = (*cellIt)->get(); - CellRefList::List& refList = containers.mList; - for (CellRefList::List::iterator container = refList.begin(); container != refList.end(); ++container) - { - MWWorld::Ptr ptr (&*container, *cellIt); - if (ptr.getRefData().isDeleted()) - continue; - if (Misc::StringUtils::ciEqual(ptr.getCellRef().getOwner(), npc.getCellRef().getRefId())) - out.push_back(ptr); - } + GetContainersOwnedByVisitor visitor (owner, out); + (*cellIt)->forEachType(visitor); } - */ } struct ListObjectsVisitor @@ -2776,11 +2796,11 @@ namespace MWWorld MWWorld::Ptr World::getClosestMarker( const MWWorld::Ptr &ptr, const std::string &id ) { - /* if ( ptr.getCell()->isExterior() ) { return getClosestMarkerFromExteriorPosition(mPlayer->getLastKnownExteriorPosition(), id); } + /* // Search for a 'nearest' marker, counting each cell between the starting // cell and the exterior as a distance of 1. If an exterior is found, jump // to the nearest exterior marker, without further interior searching. From 51b892195b329b2e7a1ce5604f904bf53fa24c0a Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 6 Dec 2015 21:58:25 +0100 Subject: [PATCH 2721/3725] Restore getReadOnlyDoors() --- apps/openmw/mwworld/cellstore.hpp | 12 ++++++++++++ apps/openmw/mwworld/worldimp.cpp | 19 ++++++------------- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index ae8ac8ae5..b08349293 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -286,6 +286,18 @@ namespace MWWorld /// \todo add const version of forEach + + // NOTE: does not account for moved references + // Should be phased out when we have const version of forEach + inline const CellRefList& getReadOnlyDoors() const + { + return mDoors; + } + inline const CellRefList& getReadOnlyStatics() const + { + return mStatics; + } + bool isExterior() const; Ptr searchInContainer (const std::string& id); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index cfb7b5c82..c64d90811 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2341,8 +2341,6 @@ namespace MWWorld bool World::findInteriorPosition(const std::string &name, ESM::Position &pos) { - return false; - /* typedef MWWorld::CellRefList::List DoorList; typedef MWWorld::CellRefList::List StaticList; @@ -2354,7 +2352,8 @@ namespace MWWorld if (0 == cellStore) { return false; } - const DoorList &doors = cellStore->get().mList; + + const DoorList &doors = cellStore->getReadOnlyDoors().mList; for (DoorList::const_iterator it = doors.begin(); it != doors.end(); ++it) { if (!it->mRef.getTeleport()) { continue; @@ -2376,7 +2375,7 @@ namespace MWWorld if (0 != source) { // Find door leading to our current teleport door // and use it destination to position inside cell. - const DoorList &doors = source->get().mList; + const DoorList &doors = source->getReadOnlyDoors().mList; for (DoorList::const_iterator jt = doors.begin(); jt != doors.end(); ++jt) { if (it->mRef.getTeleport() && Misc::StringUtils::ciEqual(name, jt->mRef.getDestCell())) @@ -2390,12 +2389,11 @@ namespace MWWorld } } // Fall back to the first static location. - const StaticList &statics = cellStore->get().mList; + const StaticList &statics = cellStore->getReadOnlyStatics().mList; if ( statics.begin() != statics.end() ) { pos = statics.begin()->mRef.getPosition(); return true; } - */ return false; } @@ -2743,8 +2741,6 @@ namespace MWWorld bool World::findInteriorPositionInWorldSpace(MWWorld::CellStore* cell, osg::Vec3f& result) { - return false; - /* if (cell->isExterior()) return false; @@ -2791,7 +2787,6 @@ namespace MWWorld // No luck :( return false; - */ } MWWorld::Ptr World::getClosestMarker( const MWWorld::Ptr &ptr, const std::string &id ) @@ -2800,7 +2795,6 @@ namespace MWWorld return getClosestMarkerFromExteriorPosition(mPlayer->getLastKnownExteriorPosition(), id); } - /* // Search for a 'nearest' marker, counting each cell between the starting // cell and the exterior as a distance of 1. If an exterior is found, jump // to the nearest exterior marker, without further interior searching. @@ -2848,7 +2842,6 @@ namespace MWWorld } } } - */ return MWWorld::Ptr(); } @@ -2916,7 +2909,7 @@ namespace MWWorld Ptr mDetector; float mSquaredDist; World::DetectionType mType; - bool operator() (MWWorld::Ptr ptr) + bool operator() (const MWWorld::Ptr& ptr) { if ((ptr.getRefData().getPosition().asVec3() - mDetector.getRefData().getPosition().asVec3()).length2() >= mSquaredDist) return true; @@ -2947,7 +2940,7 @@ namespace MWWorld return true; } - bool needToAdd (MWWorld::Ptr ptr, MWWorld::Ptr detector) + bool needToAdd (const MWWorld::Ptr& ptr, const MWWorld::Ptr& detector) { if (mType == World::Detect_Creature) { From 4b0ecaa0a0afdc35b33d8b789130443be580433a Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 6 Dec 2015 22:10:01 +0100 Subject: [PATCH 2722/3725] Fix physics bug --- apps/openmw/mwworld/cellstore.cpp | 1 + apps/openmw/mwworld/worldimp.cpp | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 4f28fcfdf..68ea2de00 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -246,6 +246,7 @@ namespace MWWorld { MWWorld::Ptr copied = object.getClass().copyToCell(object, *cellToMoveTo); object.getRefData().setCount(0); + object.getRefData().setBaseNode(NULL); return copied; } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index c64d90811..930fddd3e 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1171,7 +1171,6 @@ namespace MWWorld newPtr = currCell->moveTo(ptr, newCell); mRendering->updatePtr(ptr, newPtr); - ptr.getRefData().setBaseNode(NULL); MWBase::Environment::get().getSoundManager()->updatePtr (ptr, newPtr); mPhysics->updatePtr(ptr, newPtr); From 45a609bc54682f5afa0a897a1f073f84caf64fac Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 6 Dec 2015 22:37:04 +0100 Subject: [PATCH 2723/3725] Improve PositionCell warning message --- apps/openmw/mwscript/transformationextensions.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 592168687..61fafc40f 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -300,14 +300,16 @@ namespace MWScript } catch(std::exception&) { + // cell not found, move to exterior instead (vanilla PositionCell compatibility) const ESM::Cell* cell = MWBase::Environment::get().getWorld()->getExterior(cellID); int cx,cy; MWBase::Environment::get().getWorld()->positionToIndex(x,y,cx,cy); store = MWBase::Environment::get().getWorld()->getExterior(cx,cy); if(!cell) { - runtime.getContext().report ("unknown cell (" + cellID + ")"); - std::cerr << "unknown cell (" << cellID << ")\n"; + std::string error = "PositionCell: unknown interior cell (" + cellID + "), moving to exterior instead"; + runtime.getContext().report (error); + std::cerr << error << std::endl; } } if(store) From 4e678ce6b30328ab343a91d41e59a775672ac3fa Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 6 Dec 2015 23:32:20 +0100 Subject: [PATCH 2724/3725] Handle mCellId in AiEscort --- apps/openmw/mwmechanics/aiescort.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/openmw/mwmechanics/aiescort.cpp b/apps/openmw/mwmechanics/aiescort.cpp index f75fc22ad..484eab6fe 100644 --- a/apps/openmw/mwmechanics/aiescort.cpp +++ b/apps/openmw/mwmechanics/aiescort.cpp @@ -1,12 +1,14 @@ #include "aiescort.hpp" #include +#include #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/mechanicsmanager.hpp" #include "../mwworld/class.hpp" +#include "../mwworld/cellstore.hpp" #include "../mwmechanics/creaturestats.hpp" @@ -73,6 +75,9 @@ namespace MWMechanics return true; } + if (!mCellId.empty() && mCellId != actor.getCell()->getCell()->getCellId().mWorldspace) + return false; // Not in the correct cell, pause and rely on the player to go back through a teleport door + actor.getClass().getCreatureStats(actor).setDrawState(DrawState_Nothing); actor.getClass().getCreatureStats(actor).setMovementFlag(CreatureStats::Flag_Run, false); From 965bea45c00d15aabc27982ff7179055b8ca5a06 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 6 Dec 2015 23:32:49 +0100 Subject: [PATCH 2725/3725] AiEscort makes the actor side with target in fights (Bug #2697) Also will follow the player through teleport doors. --- apps/openmw/mwbase/mechanicsmanager.hpp | 6 +-- apps/openmw/mwmechanics/actors.cpp | 45 ++++++++----------- apps/openmw/mwmechanics/actors.hpp | 6 +-- apps/openmw/mwmechanics/aiescort.cpp | 5 +++ apps/openmw/mwmechanics/aiescort.hpp | 3 ++ apps/openmw/mwmechanics/aifollow.hpp | 1 + apps/openmw/mwmechanics/aipackage.cpp | 10 +++++ apps/openmw/mwmechanics/aipackage.hpp | 6 +++ .../mwmechanics/mechanicsmanagerimp.cpp | 8 ++-- .../mwmechanics/mechanicsmanagerimp.hpp | 2 +- apps/openmw/mwworld/actionteleport.cpp | 2 +- 11 files changed, 56 insertions(+), 38 deletions(-) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index 63ad1d32f..7cfc0861c 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -184,9 +184,9 @@ namespace MWBase virtual void getObjectsInRange (const osg::Vec3f& position, float radius, std::vector& objects) = 0; virtual void getActorsInRange(const osg::Vec3f &position, float radius, std::vector &objects) = 0; - ///return the list of actors which are following the given actor - /**ie AiFollow is active and the target is the actor**/ - virtual std::list getActorsFollowing(const MWWorld::Ptr& actor) = 0; + ///Returns the list of actors which are siding with the given actor in fights + /**ie AiFollow or AiEscort is active and the target is the actor **/ + virtual std::list getActorsSidingWith(const MWWorld::Ptr& actor) = 0; virtual std::list getActorsFollowingIndices(const MWWorld::Ptr& actor) = 0; ///Returns a list of actors who are fighting the given actor within the fAlarmDistance diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 2d794b3e0..eb837613b 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -303,7 +303,7 @@ namespace MWMechanics if (againstPlayer) { // followers with high fight should not engage in combat with the player (e.g. bm_bear_black_summon) - const std::list& followers = getActorsFollowing(actor2); + const std::list& followers = getActorsSidingWith(actor2); if (std::find(followers.begin(), followers.end(), actor1) != followers.end()) return; @@ -322,7 +322,7 @@ namespace MWMechanics } // start combat if target actor is in combat with one of our followers - const std::list& followers = getActorsFollowing(actor1); + const std::list& followers = getActorsSidingWith(actor1); const CreatureStats& creatureStats2 = actor2.getClass().getCreatureStats(actor2); for (std::list::const_iterator it = followers.begin(); it != followers.end(); ++it) { @@ -336,20 +336,21 @@ namespace MWMechanics // start combat if target actor is in combat with someone we are following for (std::list::const_iterator it = creatureStats.getAiSequence().begin(); it != creatureStats.getAiSequence().end(); ++it) { - if ((*it)->getTypeId() == MWMechanics::AiPackage::TypeIdFollow) - { - MWWorld::Ptr followTarget = static_cast(*it)->getTarget(); - if (followTarget.isEmpty()) - continue; + if (!(*it)->sideWithTarget()) + continue; - if (creatureStats.getAiSequence().isInCombat(followTarget)) - continue; + MWWorld::Ptr followTarget = (*it)->getTarget(); - // need to check both ways since player doesn't use AI packages - if (creatureStats2.getAiSequence().isInCombat(followTarget) - || followTarget.getClass().getCreatureStats(followTarget).getAiSequence().isInCombat(actor2)) - aggressive = true; - } + if (followTarget.isEmpty()) + continue; + + if (creatureStats.getAiSequence().isInCombat(followTarget)) + continue; + + // need to check both ways since player doesn't use AI packages + if (creatureStats2.getAiSequence().isInCombat(followTarget) + || followTarget.getClass().getCreatureStats(followTarget).getAiSequence().isInCombat(actor2)) + aggressive = true; } if(aggressive) @@ -1290,7 +1291,7 @@ namespace MWMechanics } } - std::list Actors::getActorsFollowing(const MWWorld::Ptr& actor) + std::list Actors::getActorsSidingWith(const MWWorld::Ptr& actor) { std::list list; for(PtrActorMap::iterator iter(mActors.begin());iter != mActors.end();++iter) @@ -1300,19 +1301,11 @@ namespace MWMechanics if (stats.isDead()) continue; - // An actor counts as following if AiFollow is the current AiPackage, or there are only Combat packages before the AiFollow package + // An actor counts as following if AiFollow or AiEscort is the current AiPackage, or there are only Combat packages before the AiFollow/AiEscort package for (std::list::const_iterator it = stats.getAiSequence().begin(); it != stats.getAiSequence().end(); ++it) { - if ((*it)->getTypeId() == MWMechanics::AiPackage::TypeIdFollow) - { - MWWorld::Ptr followTarget = static_cast(*it)->getTarget(); - if (followTarget.isEmpty()) - continue; - if (followTarget == actor) - list.push_back(iter->first); - else - break; - } + if ((*it)->sideWithTarget() && (*it)->getTarget() == actor) + list.push_back(iter->first); else if ((*it)->getTypeId() != MWMechanics::AiPackage::TypeIdCombat) break; } diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index a16b80884..494216ba8 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -111,9 +111,9 @@ namespace MWMechanics void getObjectsInRange(const osg::Vec3f& position, float radius, std::vector& out); - ///Returns the list of actors which are following the given actor - /**ie AiFollow is active and the target is the actor **/ - std::list getActorsFollowing(const MWWorld::Ptr& actor); + ///Returns the list of actors which are siding with the given actor in fights + /**ie AiFollow or AiEscort is active and the target is the actor **/ + std::list getActorsSidingWith(const MWWorld::Ptr& actor); /// Get the list of AiFollow::mFollowIndex for all actors following this target std::list getActorsFollowingIndices(const MWWorld::Ptr& actor); diff --git a/apps/openmw/mwmechanics/aiescort.cpp b/apps/openmw/mwmechanics/aiescort.cpp index 484eab6fe..fffab8d77 100644 --- a/apps/openmw/mwmechanics/aiescort.cpp +++ b/apps/openmw/mwmechanics/aiescort.cpp @@ -119,6 +119,11 @@ namespace MWMechanics return TypeIdEscort; } + MWWorld::Ptr AiEscort::getTarget() + { + return MWBase::Environment::get().getWorld()->getPtr(mActorId, false); + } + void AiEscort::writeState(ESM::AiSequence::AiSequence &sequence) const { std::auto_ptr escort(new ESM::AiSequence::AiEscort()); diff --git a/apps/openmw/mwmechanics/aiescort.hpp b/apps/openmw/mwmechanics/aiescort.hpp index 9f6335b93..cdb0f7936 100644 --- a/apps/openmw/mwmechanics/aiescort.hpp +++ b/apps/openmw/mwmechanics/aiescort.hpp @@ -37,6 +37,9 @@ namespace MWMechanics virtual int getTypeId() const; + MWWorld::Ptr getTarget(); + virtual bool sideWithTarget() const { return true; } + void writeState(ESM::AiSequence::AiSequence &sequence) const; private: diff --git a/apps/openmw/mwmechanics/aifollow.hpp b/apps/openmw/mwmechanics/aifollow.hpp index 8555f9bc4..97140a63a 100644 --- a/apps/openmw/mwmechanics/aifollow.hpp +++ b/apps/openmw/mwmechanics/aifollow.hpp @@ -32,6 +32,7 @@ namespace MWMechanics AiFollow(const ESM::AiSequence::AiFollow* follow); MWWorld::Ptr getTarget(); + virtual bool sideWithTarget() const { return true; } virtual AiFollow *clone() const; diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index bedff8bcd..fef10b730 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -20,6 +20,16 @@ MWMechanics::AiPackage::~AiPackage() {} +MWWorld::Ptr MWMechanics::AiPackage::getTarget() +{ + return MWWorld::Ptr(); +} + +bool MWMechanics::AiPackage::sideWithTarget() const +{ + return false; +} + MWMechanics::AiPackage::AiPackage() : mTimer(0.26f) { //mTimer starts at .26 to force initial pathbuild } diff --git a/apps/openmw/mwmechanics/aipackage.hpp b/apps/openmw/mwmechanics/aipackage.hpp index 3f227a49a..f9460e264 100644 --- a/apps/openmw/mwmechanics/aipackage.hpp +++ b/apps/openmw/mwmechanics/aipackage.hpp @@ -69,6 +69,12 @@ namespace MWMechanics /// Simulates the passing of time virtual void fastForward(const MWWorld::Ptr& actor, AiState& state) {} + /// Get the target actor the AI is targeted at (not applicable to all AI packages, default return empty Ptr) + virtual MWWorld::Ptr getTarget(); + + /// Return true if having this AiPackage makes the actor side with the target in fights (default false) + virtual bool sideWithTarget() const; + bool isTargetMagicallyHidden(const MWWorld::Ptr& target); protected: diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index e392b309b..68bea02b0 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1053,7 +1053,7 @@ namespace MWMechanics void getFollowers (const MWWorld::Ptr& actor, std::set& out) { - std::list followers = MWBase::Environment::get().getMechanicsManager()->getActorsFollowing(actor); + std::list followers = MWBase::Environment::get().getMechanicsManager()->getActorsSidingWith(actor); for(std::list::iterator it = followers.begin();it != followers.end();++it) { if (out.insert(*it).second) @@ -1310,7 +1310,7 @@ namespace MWMechanics if (ptr == getPlayer()) return false; - std::list followers = getActorsFollowing(attacker); + std::list followers = getActorsSidingWith(attacker); MWMechanics::CreatureStats& targetStats = ptr.getClass().getCreatureStats(ptr); if (std::find(followers.begin(), followers.end(), ptr) != followers.end()) { @@ -1487,9 +1487,9 @@ namespace MWMechanics mActors.getObjectsInRange(position, radius, objects); } - std::list MechanicsManager::getActorsFollowing(const MWWorld::Ptr& actor) + std::list MechanicsManager::getActorsSidingWith(const MWWorld::Ptr& actor) { - return mActors.getActorsFollowing(actor); + return mActors.getActorsSidingWith(actor); } std::list MechanicsManager::getActorsFollowingIndices(const MWWorld::Ptr& actor) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index f0d1cc2a0..279adeeed 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -150,7 +150,7 @@ namespace MWMechanics virtual void getObjectsInRange (const osg::Vec3f& position, float radius, std::vector& objects); virtual void getActorsInRange(const osg::Vec3f &position, float radius, std::vector &objects); - virtual std::list getActorsFollowing(const MWWorld::Ptr& actor); + virtual std::list getActorsSidingWith(const MWWorld::Ptr& actor); virtual std::list getActorsFollowingIndices(const MWWorld::Ptr& actor); virtual std::list getActorsFighting(const MWWorld::Ptr& actor); diff --git a/apps/openmw/mwworld/actionteleport.cpp b/apps/openmw/mwworld/actionteleport.cpp index 031f07258..bcb1fc6d4 100644 --- a/apps/openmw/mwworld/actionteleport.cpp +++ b/apps/openmw/mwworld/actionteleport.cpp @@ -13,7 +13,7 @@ namespace void getFollowers (const MWWorld::Ptr& actor, std::set& out) { - std::list followers = MWBase::Environment::get().getMechanicsManager()->getActorsFollowing(actor); + std::list followers = MWBase::Environment::get().getMechanicsManager()->getActorsSidingWith(actor); for(std::list::iterator it = followers.begin();it != followers.end();++it) { if (out.insert(*it).second) From 65b5cbe3f7f56b682ecfc731b04f71d6b6676b38 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 6 Dec 2015 23:40:03 +0100 Subject: [PATCH 2726/3725] AiEscortCell complains if no cell was given or cell does not exist --- apps/openmw/mwscript/aiextensions.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwscript/aiextensions.cpp b/apps/openmw/mwscript/aiextensions.cpp index 22b6ac8d1..db60d14d1 100644 --- a/apps/openmw/mwscript/aiextensions.cpp +++ b/apps/openmw/mwscript/aiextensions.cpp @@ -1,5 +1,8 @@ #include "aiextensions.hpp" +#include +#include + #include #include @@ -8,6 +11,7 @@ #include #include "../mwworld/class.hpp" +#include "../mwworld/esmstore.hpp" #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/aiactivate.hpp" @@ -18,13 +22,11 @@ #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" +#include "../mwbase/mechanicsmanager.hpp" #include "interpretercontext.hpp" #include "ref.hpp" -#include - -#include "../mwbase/mechanicsmanager.hpp" namespace MWScript { @@ -144,6 +146,11 @@ namespace MWScript // discard additional arguments (reset), because we have no idea what they mean. for (unsigned int i=0; igetStore().get().find(cellID); + MWMechanics::AiEscort escortPackage(actorID, cellID, static_cast(duration), x, y, z); ptr.getClass().getCreatureStats (ptr).getAiSequence().stack(escortPackage, ptr); From 1f543b4d79744886aa9a03ad7fcff6d97dc5f70c Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 7 Dec 2015 00:25:03 +0100 Subject: [PATCH 2727/3725] Apply the AiTravel maxRange to AiEscort as well (Fixes #2697) --- apps/openmw/mwmechanics/aiescort.cpp | 3 +++ apps/openmw/mwmechanics/aipackage.hpp | 9 +++++++++ apps/openmw/mwmechanics/aitravel.cpp | 12 ------------ 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwmechanics/aiescort.cpp b/apps/openmw/mwmechanics/aiescort.cpp index fffab8d77..baf4f1be7 100644 --- a/apps/openmw/mwmechanics/aiescort.cpp +++ b/apps/openmw/mwmechanics/aiescort.cpp @@ -75,6 +75,9 @@ namespace MWMechanics return true; } + if (!isWithinMaxRange(osg::Vec3f(mX, mY, mZ), actor.getRefData().getPosition().asVec3())) + return false; + if (!mCellId.empty() && mCellId != actor.getCell()->getCell()->getCellId().mWorldspace) return false; // Not in the correct cell, pause and rely on the player to go back through a teleport door diff --git a/apps/openmw/mwmechanics/aipackage.hpp b/apps/openmw/mwmechanics/aipackage.hpp index f9460e264..4b760e4c9 100644 --- a/apps/openmw/mwmechanics/aipackage.hpp +++ b/apps/openmw/mwmechanics/aipackage.hpp @@ -94,10 +94,19 @@ namespace MWMechanics ESM::Pathgrid::Point mPrevDest; + bool isWithinMaxRange(const osg::Vec3f& pos1, const osg::Vec3f& pos2) const + { + // Maximum travel distance for vanilla compatibility. + // Was likely meant to prevent NPCs walking into non-loaded exterior cells, but for some reason is used in interior cells as well. + // We can make this configurable at some point, but the default *must* be the below value. Anything else will break shoddily-written content (*cough* MW *cough*) in bizarre ways. + return (pos1 - pos2).length2() <= 7168*7168; + } + private: bool isNearInactiveCell(const ESM::Position& actorPos); }; + } #endif diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index 1585a3007..c29861f4e 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -13,18 +13,6 @@ #include "movement.hpp" #include "creaturestats.hpp" -namespace -{ - -bool isWithinMaxRange(const osg::Vec3f& pos1, const osg::Vec3f& pos2) -{ - // Maximum travel distance for vanilla compatibility. - // Was likely meant to prevent NPCs walking into non-loaded exterior cells, but for some reason is used in interior cells as well. - // We can make this configurable at some point, but the default *must* be the below value. Anything else will break shoddily-written content (*cough* MW *cough*) in bizarre ways. - return (pos1 - pos2).length2() <= 7168*7168; -} - -} namespace MWMechanics { From f9dd549bffaf16bd4ffb6c6504625e0479196c27 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 7 Dec 2015 03:47:40 +0100 Subject: [PATCH 2728/3725] Restore FindContainerVisitor --- apps/openmw/mwworld/worldimp.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 930fddd3e..36b3be01d 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -721,7 +721,11 @@ namespace MWWorld for (Scene::CellStoreCollection::const_iterator cellIt = collection.begin(); cellIt != collection.end(); ++cellIt) { FindContainerVisitor visitor(ptr); - //(*cellIt)->forEachContainer(visitor); + (*cellIt)->forEachType(visitor); + if (visitor.mResult.isEmpty()) + (*cellIt)->forEachType(visitor); + if (visitor.mResult.isEmpty()) + (*cellIt)->forEachType(visitor); if (!visitor.mResult.isEmpty()) return visitor.mResult; From 1875aa4a18704ee6aeb9feb84aedb64baa74165c Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 7 Dec 2015 03:51:03 +0100 Subject: [PATCH 2729/3725] Restore getNearbyDoor --- apps/openmw/mwmechanics/obstacle.cpp | 13 ++++++------- apps/openmw/mwworld/refdata.cpp | 2 +- apps/openmw/mwworld/refdata.hpp | 2 +- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwmechanics/obstacle.cpp b/apps/openmw/mwmechanics/obstacle.cpp index a2cbae2a0..5815d8cbe 100644 --- a/apps/openmw/mwmechanics/obstacle.cpp +++ b/apps/openmw/mwmechanics/obstacle.cpp @@ -44,10 +44,9 @@ namespace MWMechanics return MWWorld::Ptr(); // check interior cells only // Check all the doors in this cell - /* - MWWorld::CellRefList& doors = cell->get(); - MWWorld::CellRefList::List& refList = doors.mList; - MWWorld::CellRefList::List::iterator it = refList.begin(); + const MWWorld::CellRefList& doors = cell->getReadOnlyDoors(); + const MWWorld::CellRefList::List& refList = doors.mList; + MWWorld::CellRefList::List::const_iterator it = refList.begin(); osg::Vec3f pos(actor.getRefData().getPosition().asVec3()); /// TODO: How to check whether the actor is facing a door? Below code is for @@ -60,14 +59,14 @@ namespace MWMechanics /// opposite of the code in World::activateDoor() ::confused:: for (; it != refList.end(); ++it) { - MWWorld::LiveCellRef& ref = *it; + const MWWorld::LiveCellRef& ref = *it; if((pos - ref.mData.getPosition().asVec3()).length2() < minSqr && ref.mData.getPosition().rot[2] == ref.mRef.getPosition().rot[2]) { - return MWWorld::Ptr(&ref, actor.getCell()); // found, stop searching + // FIXME cast + return MWWorld::Ptr(&const_cast &>(ref), actor.getCell()); // found, stop searching } } - */ return MWWorld::Ptr(); // none found } diff --git a/apps/openmw/mwworld/refdata.cpp b/apps/openmw/mwworld/refdata.cpp index 8acba43df..997b3fc94 100644 --- a/apps/openmw/mwworld/refdata.cpp +++ b/apps/openmw/mwworld/refdata.cpp @@ -182,7 +182,7 @@ namespace MWWorld mPosition = pos; } - const ESM::Position& RefData::getPosition() + const ESM::Position& RefData::getPosition() const { return mPosition; } diff --git a/apps/openmw/mwworld/refdata.hpp b/apps/openmw/mwworld/refdata.hpp index 6713334d7..19c31a14b 100644 --- a/apps/openmw/mwworld/refdata.hpp +++ b/apps/openmw/mwworld/refdata.hpp @@ -103,7 +103,7 @@ namespace MWWorld void disable(); void setPosition (const ESM::Position& pos); - const ESM::Position& getPosition(); + const ESM::Position& getPosition() const; void setCustomData (CustomData *data); ///< Set custom data (potentially replacing old custom data). The ownership of \a data is From 621347b20fb7a8d778b3219dd3cd23a2232cf1a0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 7 Dec 2015 03:55:26 +0100 Subject: [PATCH 2730/3725] Remove moved ref handling from listRefs() Not needed since we now load cells when a reference is moved there. --- apps/openmw/mwworld/cellstore.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 68ea2de00..b5db42b00 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -474,8 +474,6 @@ namespace MWWorld continue; } - // We don't need to check mMovedToAnotherCell because listRefs isn't used for loaded cells. - mIds.push_back (Misc::StringUtils::lowerCase (ref.mRefID)); } } @@ -488,12 +486,6 @@ namespace MWWorld mIds.push_back(Misc::StringUtils::lowerCase(ref.mRefID)); } - // List runtime moved references - for (MovedRefTracker::const_iterator it = mMovedHere.begin(); it != mMovedHere.end(); ++it) - { - mIds.push_back(Misc::StringUtils::lowerCase(it->first->mRef.getRefId())); - } - std::sort (mIds.begin(), mIds.end()); } From 5981e1cbb3c18641cc09e4fc6da5f667c897770f Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 7 Dec 2015 14:41:33 +0100 Subject: [PATCH 2731/3725] Don't create the werewolf overlay if its texture is not available Avoiding a warning in the log when Bloodmoon is not installed --- apps/openmw/mwgui/windowmanagerimp.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 114b8223d..9d99c490b 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -324,7 +324,9 @@ namespace MWGui trackWindow(mCompanionWindow, "companion"); mJailScreen = new JailScreen(); - mWerewolfFader = new ScreenFader("textures\\werewolfoverlay.dds"); + std::string werewolfFaderTex = "textures\\werewolfoverlay.dds"; + if (mResourceSystem->getVFS()->exists(werewolfFaderTex)) + mWerewolfFader = new ScreenFader(werewolfFaderTex); mBlindnessFader = new ScreenFader("black"); std::string hitFaderTexture = "textures\\bm_player_hit_01.dds"; // fall back to player_hit_01.dds if bm_player_hit_01.dds is not available @@ -984,7 +986,8 @@ namespace MWGui mCompanionWindow->onFrame(); mJailScreen->onFrame(frameDuration); - mWerewolfFader->update(frameDuration); + if (mWerewolfFader) + mWerewolfFader->update(frameDuration); mBlindnessFader->update(frameDuration); mHitFader->update(frameDuration); mScreenFader->update(frameDuration); @@ -1878,7 +1881,8 @@ namespace MWGui if (!mWerewolfOverlayEnabled) return; - mWerewolfFader->notifyAlphaChanged(set ? 1.0f : 0.0f); + if (mWerewolfFader) + mWerewolfFader->notifyAlphaChanged(set ? 1.0f : 0.0f); } void WindowManager::onClipboardChanged(const std::string &_type, const std::string &_data) From 9d4af598605473c69167b5bfd18ae2b6561e0bb2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 7 Dec 2015 15:32:00 +0100 Subject: [PATCH 2732/3725] Don't attempt to create quest log buttons if textures are unavailable (Fixes #3063) --- apps/openmw/mwgui/journalwindow.cpp | 38 ++++++++++++++++++-------- apps/openmw/mwgui/journalwindow.hpp | 2 +- apps/openmw/mwgui/windowmanagerimp.cpp | 4 ++- components/resource/texturemanager.hpp | 1 + components/widgets/imagebutton.cpp | 19 +++++++++++-- components/widgets/imagebutton.hpp | 5 +++- files/mygui/openmw_journal.layout | 16 +++-------- 7 files changed, 56 insertions(+), 29 deletions(-) diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index b6f72a04c..9af87c7ae 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -96,7 +96,7 @@ namespace return getWidget (name); } - JournalWindowImpl (MWGui::JournalViewModel::Ptr Model) + JournalWindowImpl (MWGui::JournalViewModel::Ptr Model, bool questList) : WindowBase("openmw_journal.layout"), JournalBooks (Model) { mMainWidget->setVisible(false); @@ -142,17 +142,17 @@ namespace getPage (RightTopicIndex)->adviseLinkClicked (callback); } - adjustButton(OptionsBTN, true); adjustButton(PrevPageBTN); adjustButton(NextPageBTN); adjustButton(CloseBTN); adjustButton(CancelBTN); - adjustButton(ShowAllBTN, true); - adjustButton(ShowActiveBTN, true); adjustButton(JournalBTN); Gui::ImageButton* optionsButton = getWidget(OptionsBTN); - if (optionsButton->getWidth() == 0) + Gui::ImageButton* showActiveButton = getWidget(ShowActiveBTN); + Gui::ImageButton* showAllButton = getWidget(ShowAllBTN); + Gui::ImageButton* questsButton = getWidget(QuestsBTN); + if (!questList) { // If tribunal is not installed (-> no options button), we still want the Topics button available, // so place it where the options button would have been @@ -162,6 +162,23 @@ namespace topicsButton->setPosition(optionsButton->getPosition()); topicsButton->eventMouseButtonClick.clear(); topicsButton->eventMouseButtonClick += MyGUI::newDelegate(this, &JournalWindowImpl::notifyOptions); + + optionsButton->setVisible(false); + showActiveButton->setVisible(false); + showAllButton->setVisible(false); + questsButton->setVisible(false); + } + else + { + optionsButton->setImage("textures/tx_menubook_options.dds"); + showActiveButton->setImage("textures/tx_menubook_quests_active.dds"); + showAllButton->setImage("textures/tx_menubook_quests_all.dds"); + questsButton->setImage("textures/tx_menubook_quests.dds"); + + adjustButton(ShowAllBTN); + adjustButton(ShowActiveBTN); + adjustButton(OptionsBTN); + adjustButton(QuestsBTN); } Gui::ImageButton* nextButton = getWidget(NextPageBTN); @@ -173,7 +190,6 @@ namespace } adjustButton(TopicsBTN); - adjustButton(QuestsBTN, true); int width = getWidget(TopicsBTN)->getSize().width + getWidget(QuestsBTN)->getSize().width; int topicsWidth = getWidget(TopicsBTN)->getSize().width; int pageWidth = getWidget(RightBookPage)->getSize().width; @@ -186,12 +202,12 @@ namespace mOptionsMode = false; } - void adjustButton (char const * name, bool optional = false) + void adjustButton (char const * name) { Gui::ImageButton* button = getWidget(name); - MyGUI::IntSize diff = button->getSize() - button->getRequestedSize(!optional); - button->setSize(button->getRequestedSize(!optional)); + MyGUI::IntSize diff = button->getSize() - button->getRequestedSize(); + button->setSize(button->getRequestedSize()); if (button->getAlign().isRight()) button->setPosition(button->getPosition() + MyGUI::IntPoint(diff.width,0)); @@ -551,7 +567,7 @@ namespace } // glue the implementation to the interface -MWGui::JournalWindow * MWGui::JournalWindow::create (JournalViewModel::Ptr Model) +MWGui::JournalWindow * MWGui::JournalWindow::create (JournalViewModel::Ptr Model, bool questList) { - return new JournalWindowImpl (Model); + return new JournalWindowImpl (Model, questList); } diff --git a/apps/openmw/mwgui/journalwindow.hpp b/apps/openmw/mwgui/journalwindow.hpp index 5d2a5318a..740284e20 100644 --- a/apps/openmw/mwgui/journalwindow.hpp +++ b/apps/openmw/mwgui/journalwindow.hpp @@ -12,7 +12,7 @@ namespace MWGui struct JournalWindow { /// construct a new instance of the one JournalWindow implementation - static JournalWindow * create (boost::shared_ptr Model); + static JournalWindow * create (boost::shared_ptr Model, bool questList); /// destroy this instance of the JournalWindow implementation virtual ~JournalWindow () {}; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 9d99c490b..ccbae3ef3 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -288,7 +288,9 @@ namespace MWGui trackWindow(mStatsWindow, "stats"); mConsole = new Console(w,h, mConsoleOnlyScripts); trackWindow(mConsole, "console"); - mJournal = JournalWindow::create(JournalViewModel::create ()); + + bool questList = mResourceSystem->getVFS()->exists("textures/tx_menubook_options_over.dds"); + mJournal = JournalWindow::create(JournalViewModel::create (), questList); mMessageBoxManager = new MessageBoxManager( MWBase::Environment::get().getWorld()->getStore().get().find("fMessageTimePerChar")->getFloat()); mInventoryWindow = new InventoryWindow(mDragAndDrop, mViewer, mResourceSystem); diff --git a/components/resource/texturemanager.hpp b/components/resource/texturemanager.hpp index 1a7d41a7b..0f40d7dfe 100644 --- a/components/resource/texturemanager.hpp +++ b/components/resource/texturemanager.hpp @@ -31,6 +31,7 @@ namespace Resource void setUnRefImageDataAfterApply(bool unref); /// Create or retrieve a Texture2D using the specified image filename, and wrap parameters. + /// Returns the dummy texture if the given texture is not found. osg::ref_ptr getTexture2D(const std::string& filename, osg::Texture::WrapMode wrapS, osg::Texture::WrapMode wrapT); /// Create or retrieve an Image diff --git a/components/widgets/imagebutton.cpp b/components/widgets/imagebutton.cpp index 1cd882975..8e3f8ed69 100644 --- a/components/widgets/imagebutton.cpp +++ b/components/widgets/imagebutton.cpp @@ -42,18 +42,31 @@ namespace Gui ImageBox::onMouseButtonPressed(_left, _top, _id); } - MyGUI::IntSize ImageButton::getRequestedSize(bool logError) + MyGUI::IntSize ImageButton::getRequestedSize() { MyGUI::ITexture* texture = MyGUI::RenderManager::getInstance().getTexture(mImageNormal); if (!texture) { - if (logError) - std::cerr << "ImageButton: can't find " << mImageNormal << std::endl; + std::cerr << "ImageButton: can't find " << mImageNormal << std::endl; return MyGUI::IntSize(0,0); } return MyGUI::IntSize (texture->getWidth(), texture->getHeight()); } + void ImageButton::setImage(const std::string &image) + { + size_t extpos = image.find_last_of("."); + std::string imageNoExt = image.substr(0, extpos); + + std::string ext = image.substr(extpos); + + mImageNormal = imageNoExt + "_idle" + ext; + mImageHighlighted = imageNoExt + "_over" + ext; + mImagePushed = imageNoExt + "_pressed" + ext; + + setImageTexture(mImageNormal); + } + void ImageButton::onMouseButtonReleased(int _left, int _top, MyGUI::MouseButton _id) { if (_id == MyGUI::MouseButton::Left) diff --git a/components/widgets/imagebutton.hpp b/components/widgets/imagebutton.hpp index 10150c6b1..a539f15c9 100644 --- a/components/widgets/imagebutton.hpp +++ b/components/widgets/imagebutton.hpp @@ -14,7 +14,10 @@ namespace Gui MYGUI_RTTI_DERIVED(ImageButton) public: - MyGUI::IntSize getRequestedSize(bool logError = true); + MyGUI::IntSize getRequestedSize(); + + /// Set mImageNormal, mImageHighlighted and mImagePushed based on file convention (image_idle.ext, image_over.ext and image_pressed.ext) + void setImage(const std::string& image); protected: virtual void setPropertyOverride(const std::string& _key, const std::string& _value); diff --git a/files/mygui/openmw_journal.layout b/files/mygui/openmw_journal.layout index 9c40bd562..9b530b379 100644 --- a/files/mygui/openmw_journal.layout +++ b/files/mygui/openmw_journal.layout @@ -26,9 +26,7 @@ - - - + @@ -66,15 +64,11 @@ - - - + - - - + @@ -90,9 +84,7 @@ - - - + From 136a425cecec7925415bcdfb8981e2392c71c465 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 7 Dec 2015 16:11:47 +0100 Subject: [PATCH 2733/3725] Use the Werewolf field of view override (Fixes #3064) Need to re-run the settings importer for the feature to work. --- apps/mwiniimporter/importer.cpp | 3 +++ apps/openmw/mwrender/renderingmanager.cpp | 26 ++++++++++++++++++++++- apps/openmw/mwrender/renderingmanager.hpp | 7 ++++++ apps/openmw/mwworld/worldimp.cpp | 16 ++++++++++++-- 4 files changed, 49 insertions(+), 3 deletions(-) diff --git a/apps/mwiniimporter/importer.cpp b/apps/mwiniimporter/importer.cpp index 251889e28..7d1fd56a5 100644 --- a/apps/mwiniimporter/importer.cpp +++ b/apps/mwiniimporter/importer.cpp @@ -638,6 +638,9 @@ MwIniImporter::MwIniImporter() "Blood:Texture Name 1", "Blood:Texture Name 2", + // werewolf (Bloodmoon) + "General:Werewolf FOV", + 0 }; diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index f4e7ca684..e8da27dce 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -136,6 +136,8 @@ namespace MWRender , mUnderwaterFog(0.f) , mUnderwaterIndoorFog(fallback->getFallbackFloat("Water_UnderwaterIndoorFog")) , mNightEyeFactor(0.f) + , mFieldOfViewOverride(0.f) + , mFieldOfViewOverridden(false) { resourceSystem->getSceneManager()->setParticleSystemMask(MWRender::Mask_ParticleSystem); @@ -769,7 +771,10 @@ namespace MWRender void RenderingManager::updateProjectionMatrix() { double aspect = mViewer->getCamera()->getViewport()->aspectRatio(); - mViewer->getCamera()->setProjectionMatrixAsPerspective(mFieldOfView, aspect, mNearClip, mViewDistance); + float fov = mFieldOfView; + if (mFieldOfViewOverridden) + fov = mFieldOfViewOverride; + mViewer->getCamera()->setProjectionMatrixAsPerspective(fov, aspect, mNearClip, mViewDistance); } void RenderingManager::updateTextureFiltering() @@ -912,4 +917,23 @@ namespace MWRender mCamera->setCameraDistance(-factor/120.f*10, true, true); } + void RenderingManager::overrideFieldOfView(float val) + { + if (mFieldOfViewOverridden != true || mFieldOfViewOverride != val) + { + mFieldOfViewOverridden = true; + mFieldOfViewOverride = val; + updateProjectionMatrix(); + } + } + + void RenderingManager::resetFieldOfView() + { + if (mFieldOfViewOverridden == true) + { + mFieldOfViewOverridden = false; + updateProjectionMatrix(); + } + } + } diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 936f7cb99..d510f52b5 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -170,6 +170,11 @@ namespace MWRender void togglePlayerLooking(bool enable); void changeVanityModeScale(float factor); + /// temporarily override the field of view with given value. + void overrideFieldOfView(float val); + /// reset a previous overrideFieldOfView() call, i.e. revert to field of view specified in the settings file. + void resetFieldOfView(); + private: void updateProjectionMatrix(); void updateTextureFiltering(); @@ -208,6 +213,8 @@ namespace MWRender float mNearClip; float mViewDistance; + float mFieldOfViewOverride; + bool mFieldOfViewOverridden; float mFieldOfView; void operator = (const RenderingManager&); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 0cb2e980d..2436225b4 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1565,8 +1565,20 @@ namespace MWWorld mPlayer->setLastKnownExteriorPosition(pos.asVec3()); } - if (player.getClass().getNpcStats(player).isWerewolf()) - MWBase::Environment::get().getWindowManager()->setWerewolfOverlay(mRendering->getCamera()->isFirstPerson()); + bool isWerewolf = player.getClass().getNpcStats(player).isWerewolf(); + bool isFirstPerson = mRendering->getCamera()->isFirstPerson(); + if (isWerewolf && isFirstPerson) + { + float werewolfFov = mFallback.getFallbackFloat("General_Werewolf_FOV"); + if (werewolfFov != 0) + mRendering->overrideFieldOfView(werewolfFov); + MWBase::Environment::get().getWindowManager()->setWerewolfOverlay(true); + } + else + { + mRendering->resetFieldOfView(); + MWBase::Environment::get().getWindowManager()->setWerewolfOverlay(false); + } // Sink the camera while sneaking bool sneaking = player.getClass().getCreatureStats(getPlayerPtr()).getStance(MWMechanics::CreatureStats::Stance_Sneak); From 9621b66b786a546dd7d0f148904a6c789467f6c3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 7 Dec 2015 16:23:06 +0100 Subject: [PATCH 2734/3725] Move field of view setting to Camera section --- apps/openmw/mwrender/renderingmanager.cpp | 6 +++--- files/mygui/openmw_settings_window.layout | 2 +- files/settings-default.cfg | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index e8da27dce..e12f2b0cb 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -207,7 +207,7 @@ namespace MWRender mNearClip = Settings::Manager::getFloat("near clip", "Camera"); mViewDistance = Settings::Manager::getFloat("viewing distance", "Camera"); - mFieldOfView = Settings::Manager::getFloat("field of view", "General"); + mFieldOfView = Settings::Manager::getFloat("field of view", "Camera"); updateProjectionMatrix(); mStateUpdater->setFogEnd(mViewDistance); @@ -813,9 +813,9 @@ namespace MWRender { for (Settings::CategorySettingVector::const_iterator it = changed.begin(); it != changed.end(); ++it) { - if (it->first == "General" && it->second == "field of view") + if (it->first == "Camera" && it->second == "field of view") { - mFieldOfView = Settings::Manager::getFloat("field of view", "General"); + mFieldOfView = Settings::Manager::getFloat("field of view", "Camera"); updateProjectionMatrix(); } else if (it->first == "Camera" && it->second == "viewing distance") diff --git a/files/mygui/openmw_settings_window.layout b/files/mygui/openmw_settings_window.layout index 22d36de2b..6d2424aa5 100644 --- a/files/mygui/openmw_settings_window.layout +++ b/files/mygui/openmw_settings_window.layout @@ -280,7 +280,7 @@ - + diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 7d0292c5b..7ad2e7c1d 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -23,6 +23,9 @@ small feature culling = true # can dramatically affect performance, see documentation for details. viewing distance = 6666.0 +# Camera field of view in degrees (e.g. 30.0 to 110.0). +field of view = 55.0 + [Cells] # Adjacent exterior cells loaded (>0). Caution: this setting can @@ -99,9 +102,6 @@ show effect duration = false # Anisotropy reduces distortion in textures at low angles (e.g. 0 to 16). anisotropy = 4 -# Camera field of view in degrees (e.g. 30.0 to 110.0). -field of view = 55.0 - # File format for screenshots. (jpg, png, tga, and possibly more). screenshot format = png From e520d37c8715fc0da2c227254a2e3769b7501831 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 7 Dec 2015 16:29:30 +0100 Subject: [PATCH 2735/3725] Override the field of view for first person meshes (Fixes #858, Fixes #3051) --- apps/openmw/mwrender/npcanimation.cpp | 37 ++++++++++++++++++++++- apps/openmw/mwrender/npcanimation.hpp | 4 ++- apps/openmw/mwrender/renderingmanager.cpp | 4 ++- apps/openmw/mwrender/renderingmanager.hpp | 1 + files/settings-default.cfg | 5 +++ 5 files changed, 48 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 815671266..4e367b3b1 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -5,6 +5,7 @@ #include #include +#include #include @@ -274,13 +275,15 @@ NpcAnimation::~NpcAnimation() mPtr.getClass().getInventoryStore(mPtr).setListener(NULL, mPtr); } -NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, osg::ref_ptr parentNode, Resource::ResourceSystem* resourceSystem, bool disableListener, bool disableSounds, ViewMode viewMode) +NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, osg::ref_ptr parentNode, Resource::ResourceSystem* resourceSystem, + bool disableListener, bool disableSounds, ViewMode viewMode, float firstPersonFieldOfView) : Animation(ptr, parentNode, resourceSystem), mListenerDisabled(disableListener), mViewMode(viewMode), mShowWeapons(false), mShowCarriedLeft(true), mNpcType(Type_Normal), + mFirstPersonFieldOfView(firstPersonFieldOfView), mSoundsDisabled(disableSounds), mAccurateAiming(false), mAimingFactor(0.f) @@ -336,6 +339,37 @@ public: osg::ref_ptr mDepth; }; +/// Overrides Field of View to given value for rendering the subgraph. +/// Must be added as cull callback. +class OverrideFieldOfViewCallback : public osg::NodeCallback +{ +public: + OverrideFieldOfViewCallback(float fov) + : mFov(fov) + { + } + + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) + { + osgUtil::CullVisitor* cv = static_cast(nv); + osg::RefMatrix* projectionMatrix = new osg::RefMatrix(*cv->getProjectionMatrix()); + float fov, aspect, zNear, zFar; + if (projectionMatrix->getPerspective(fov, aspect, zNear, zFar)) + { + fov = mFov; + projectionMatrix->makePerspective(fov, aspect, zNear, zFar); + cv->pushProjectionMatrix(projectionMatrix); + traverse(node, nv); + cv->popProjectionMatrix(); + } + else + traverse(node, nv); + } + +private: + float mFov; +}; + void NpcAnimation::setRenderBin() { if (mViewMode == VM_FirstPerson) @@ -445,6 +479,7 @@ void NpcAnimation::updateNpcBase() else { mObjectRoot->setNodeMask(Mask_FirstPerson); + mObjectRoot->addCullCallback(new OverrideFieldOfViewCallback(mFirstPersonFieldOfView)); if(isWerewolf) addAnimSource(smodel); else diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 2289703c8..c5fc62f9c 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -61,6 +61,8 @@ private: int mPartPriorities[ESM::PRT_Count]; osg::Vec3f mFirstPersonOffset; + // Field of view to use when rendering first person meshes + float mFirstPersonFieldOfView; boost::shared_ptr mHeadAnimationTime; boost::shared_ptr mWeaponAnimationTime; @@ -102,7 +104,7 @@ public: * @param viewMode */ NpcAnimation(const MWWorld::Ptr& ptr, osg::ref_ptr parentNode, Resource::ResourceSystem* resourceSystem, bool disableListener = false, - bool disableSounds = false, ViewMode viewMode=VM_Normal); + bool disableSounds = false, ViewMode viewMode=VM_Normal, float firstPersonFieldOfView=55.f); virtual ~NpcAnimation(); virtual void enableHeadAnimation(bool enable); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index e12f2b0cb..4b208fa94 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -208,6 +208,7 @@ namespace MWRender mNearClip = Settings::Manager::getFloat("near clip", "Camera"); mViewDistance = Settings::Manager::getFloat("viewing distance", "Camera"); mFieldOfView = Settings::Manager::getFloat("field of view", "Camera"); + mFirstPersonFieldOfView = Settings::Manager::getFloat("first person field of view", "Camera"); updateProjectionMatrix(); mStateUpdater->setFogEnd(mViewDistance); @@ -729,7 +730,8 @@ namespace MWRender void RenderingManager::renderPlayer(const MWWorld::Ptr &player) { - mPlayerAnimation.reset(new NpcAnimation(player, player.getRefData().getBaseNode(), mResourceSystem, 0)); + mPlayerAnimation.reset(new NpcAnimation(player, player.getRefData().getBaseNode(), mResourceSystem, 0, false, NpcAnimation::VM_Normal, + mFirstPersonFieldOfView)); mCamera->setAnimation(mPlayerAnimation.get()); mCamera->attachTo(player); diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index d510f52b5..7b1c8529f 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -216,6 +216,7 @@ namespace MWRender float mFieldOfViewOverride; bool mFieldOfViewOverridden; float mFieldOfView; + float mFirstPersonFieldOfView; void operator = (const RenderingManager&); RenderingManager(const RenderingManager&); diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 7ad2e7c1d..6de42fd4e 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -24,8 +24,13 @@ small feature culling = true viewing distance = 6666.0 # Camera field of view in degrees (e.g. 30.0 to 110.0). +# Does not affect the player's hands in the first person camera. field of view = 55.0 +# Field of view for first person meshes (i.e. the player's hands) +# Best to leave this at the default since vanilla assets are not complete enough to adapt to high FoV's. Too low FoV would clip the hands off screen. +first person field of view = 55.0 + [Cells] # Adjacent exterior cells loaded (>0). Caution: this setting can From 998ef36837c143af90c29a495a6d0828571dc6e0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 7 Dec 2015 18:04:23 +0100 Subject: [PATCH 2736/3725] Setting fix --- apps/openmw/mwgui/settingswindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index eb2f23529..78ff96532 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -256,7 +256,7 @@ namespace MWGui MyGUI::TextBox* fovText; getWidget(fovText, "FovText"); - fovText->setCaption("Field of View (" + MyGUI::utility::toString(int(Settings::Manager::getInt("field of view", "General"))) + ")"); + fovText->setCaption("Field of View (" + MyGUI::utility::toString(int(Settings::Manager::getInt("field of view", "Camera"))) + ")"); MyGUI::TextBox* diffText; getWidget(diffText, "DifficultyText"); From 152f415b9a94fae1a24798125047ba5309cc9050 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 7 Dec 2015 18:32:58 +0100 Subject: [PATCH 2737/3725] Change texture coordinates when falling back to player_hit_01 --- apps/openmw/mwgui/screenfader.cpp | 18 ++++++++++++------ apps/openmw/mwgui/screenfader.hpp | 4 +--- apps/openmw/mwgui/windowmanagerimp.cpp | 12 +++++++++--- 3 files changed, 22 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwgui/screenfader.cpp b/apps/openmw/mwgui/screenfader.cpp index c44bcc3f1..be0346e88 100644 --- a/apps/openmw/mwgui/screenfader.cpp +++ b/apps/openmw/mwgui/screenfader.cpp @@ -1,6 +1,7 @@ #include "screenfader.hpp" #include +#include namespace MWGui { @@ -66,20 +67,25 @@ namespace MWGui mFader->notifyOperationFinished(); } - ScreenFader::ScreenFader(const std::string & texturePath, const std::string& layout) + ScreenFader::ScreenFader(const std::string & texturePath, const std::string& layout, const MyGUI::FloatCoord& texCoordOverride) : WindowBase(layout) , mCurrentAlpha(0.f) , mFactor(1.f) , mRepeat(false) { mMainWidget->setSize(MyGUI::RenderManager::getInstance().getViewSize()); - setTexture(texturePath); setVisible(false); - } - void ScreenFader::setTexture(const std::string & texturePath) - { - mMainWidget->setProperty("ImageTexture", texturePath); + MyGUI::ImageBox* imageBox = mMainWidget->castType(false); + if (imageBox) + { + imageBox->setImageTexture(texturePath); + const MyGUI::IntSize imageSize = imageBox->getImageSize(); + imageBox->setImageCoord(MyGUI::IntCoord(texCoordOverride.left * imageSize.width, + texCoordOverride.top * imageSize.height, + texCoordOverride.width * imageSize.width, + texCoordOverride.height * imageSize.height)); + } } void ScreenFader::update(float dt) diff --git a/apps/openmw/mwgui/screenfader.hpp b/apps/openmw/mwgui/screenfader.hpp index d25f5fdc4..f87fd8443 100644 --- a/apps/openmw/mwgui/screenfader.hpp +++ b/apps/openmw/mwgui/screenfader.hpp @@ -36,9 +36,7 @@ namespace MWGui class ScreenFader : public WindowBase { public: - ScreenFader(const std::string & texturePath, const std::string& layout = "openmw_screen_fader.layout"); - - void setTexture(const std::string & texturePath); + ScreenFader(const std::string & texturePath, const std::string& layout = "openmw_screen_fader.layout", const MyGUI::FloatCoord& texCoordOverride = MyGUI::FloatCoord(0,0,1,1)); void update(float dt); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index ccbae3ef3..31522913e 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -330,12 +330,18 @@ namespace MWGui if (mResourceSystem->getVFS()->exists(werewolfFaderTex)) mWerewolfFader = new ScreenFader(werewolfFaderTex); mBlindnessFader = new ScreenFader("black"); - std::string hitFaderTexture = "textures\\bm_player_hit_01.dds"; + // fall back to player_hit_01.dds if bm_player_hit_01.dds is not available - // TODO: check if non-BM versions actually use player_hit_01.dds + std::string hitFaderTexture = "textures\\bm_player_hit_01.dds"; + const std::string hitFaderLayout = "openmw_screen_fader_hit.layout"; + MyGUI::FloatCoord hitFaderCoord (0,0,1,1); if(!mResourceSystem->getVFS()->exists(hitFaderTexture)) + { hitFaderTexture = "textures\\player_hit_01.dds"; - mHitFader = new ScreenFader(hitFaderTexture, "openmw_screen_fader_hit.layout"); + hitFaderCoord = MyGUI::FloatCoord(0.2, 0.25, 0.6, 0.5); + } + mHitFader = new ScreenFader(hitFaderTexture, hitFaderLayout, hitFaderCoord); + mScreenFader = new ScreenFader("black"); mDebugWindow = new DebugWindow(); From 1a654fa4515f98c1b44dfd13448f88c21e5fde32 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 7 Dec 2015 21:24:30 +0100 Subject: [PATCH 2738/3725] Reset locale after strftime() call --- apps/openmw/mwgui/savegamedialog.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index 816fc0fa8..53c280737 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -360,12 +360,17 @@ namespace MWGui timeinfo = localtime(&time); // Use system/environment locale settings for datetime formatting + char* oldLctime = setlocale(LC_TIME, NULL); setlocale(LC_TIME, ""); const int size=1024; char buffer[size]; if (std::strftime(buffer, size, "%x %X", timeinfo) > 0) text << buffer << "\n"; + + // reset + setlocale(LC_TIME, oldLctime); + text << "#{sLevel} " << mCurrentSlot->mProfile.mPlayerLevel << "\n"; text << "#{sCell=" << mCurrentSlot->mProfile.mPlayerCell << "}\n"; From f875597be5f2432536631ebe016d7f1b81dfbe57 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 7 Dec 2015 21:58:30 +0100 Subject: [PATCH 2739/3725] Don't use tolower() See https://forum.openmw.org/viewtopic.php?f=8&t=3231&p=35968 --- apps/openmw/mwdialogue/keywordsearch.hpp | 12 +++---- apps/openmw/mwgui/console.cpp | 4 +-- apps/openmw/mwgui/journalviewmodel.cpp | 2 +- components/files/linuxpath.cpp | 4 ++- components/files/macospath.cpp | 4 ++- components/files/multidircollection.cpp | 6 ++-- components/files/multidircollection.hpp | 6 ++-- components/interpreter/defines.cpp | 5 +-- components/misc/stringops.hpp | 46 +++++++++++++++++++++--- components/vfs/manager.cpp | 4 ++- 10 files changed, 71 insertions(+), 22 deletions(-) diff --git a/apps/openmw/mwdialogue/keywordsearch.hpp b/apps/openmw/mwdialogue/keywordsearch.hpp index 3b68d3d6b..3532dc22b 100644 --- a/apps/openmw/mwdialogue/keywordsearch.hpp +++ b/apps/openmw/mwdialogue/keywordsearch.hpp @@ -44,7 +44,7 @@ public: typename Entry::childen_t::iterator current; typename Entry::childen_t::iterator next; - current = mRoot.mChildren.find (tolower (*keyword.begin())); + current = mRoot.mChildren.find (Misc::StringUtils::toLower (*keyword.begin())); if (current == mRoot.mChildren.end()) return false; else if (current->second.mKeyword.size() && Misc::StringUtils::ciEqual(current->second.mKeyword, keyword)) @@ -55,7 +55,7 @@ public: for (Point i = ++keyword.begin(); i != keyword.end(); ++i) { - next = current->second.mChildren.find(tolower (*i)); + next = current->second.mChildren.find(Misc::StringUtils::toLower (*i)); if (next == current->second.mChildren.end()) return false; if (Misc::StringUtils::ciEqual(next->second.mKeyword, keyword)) @@ -89,7 +89,7 @@ public: // check first character - typename Entry::childen_t::iterator candidate = mRoot.mChildren.find (tolower (*i)); + typename Entry::childen_t::iterator candidate = mRoot.mChildren.find (Misc::StringUtils::toLower (*i)); // no match, on to next character if (candidate == mRoot.mChildren.end ()) @@ -104,7 +104,7 @@ public: while ((j + 1) != end) { - typename Entry::childen_t::iterator next = candidate->second.mChildren.find (tolower (*++j)); + typename Entry::childen_t::iterator next = candidate->second.mChildren.find (Misc::StringUtils::toLower (*++j)); if (next == candidate->second.mChildren.end ()) { @@ -136,7 +136,7 @@ public: while (k != end && t != candidate->second.mKeyword.end ()) { - if (tolower (*k) != tolower (*t)) + if (Misc::StringUtils::toLower (*k) != Misc::StringUtils::toLower (*t)) break; ++k, ++t; @@ -212,7 +212,7 @@ private: void seed_impl (string_t keyword, value_t value, size_t depth, Entry & entry) { - int ch = tolower (keyword.at (depth)); + int ch = Misc::StringUtils::toLower (keyword.at (depth)); typename Entry::childen_t::iterator j = entry.mChildren.find (ch); diff --git a/apps/openmw/mwgui/console.cpp b/apps/openmw/mwgui/console.cpp index 761f7d164..1777d86ad 100644 --- a/apps/openmw/mwgui/console.cpp +++ b/apps/openmw/mwgui/console.cpp @@ -365,7 +365,7 @@ namespace MWGui /* Is the beginning of the string different from the input string? If yes skip it. */ for( std::string::iterator iter=tmp.begin(), iter2=(*it).begin(); iter < tmp.end();++iter, ++iter2) { - if( tolower(*iter) != tolower(*iter2) ) { + if( Misc::StringUtils::toLower(*iter) != Misc::StringUtils::toLower(*iter2) ) { string_different=true; break; } @@ -405,7 +405,7 @@ namespace MWGui for(std::string::iterator iter=matches.front().begin()+tmp.length(); iter < matches.front().end(); ++iter, ++i) { for(std::vector::iterator it=matches.begin(); it < matches.end();++it) { - if( tolower((*it)[i]) != tolower(*iter) ) { + if( Misc::StringUtils::toLower((*it)[i]) != Misc::StringUtils::toLower(*iter) ) { /* Append the longest match to the end of the output string*/ output.append(matches.front().substr( 0, i)); return output; diff --git a/apps/openmw/mwgui/journalviewmodel.cpp b/apps/openmw/mwgui/journalviewmodel.cpp index f566e7769..70f1305e0 100644 --- a/apps/openmw/mwgui/journalviewmodel.cpp +++ b/apps/openmw/mwgui/journalviewmodel.cpp @@ -315,7 +315,7 @@ struct JournalViewModelImpl : JournalViewModel for (MWBase::Journal::TTopicIter i = journal->topicBegin (); i != journal->topicEnd (); ++i) { - if (i->first [0] != tolower (character)) + if (i->first [0] != Misc::StringUtils::toLower(character)) continue; visitor (i->second.getName()); diff --git a/components/files/linuxpath.cpp b/components/files/linuxpath.cpp index a105bb928..212db562c 100644 --- a/components/files/linuxpath.cpp +++ b/components/files/linuxpath.cpp @@ -8,6 +8,8 @@ #include #include +#include + namespace { @@ -139,7 +141,7 @@ boost::filesystem::path LinuxPath::getInstallPath() const { // Change drive letter to lowercase, so we could use // ~/.wine/dosdevices symlinks - mwpath[0] = tolower(mwpath[0]); + mwpath[0] = Misc::StringUtils::toLower(mwpath[0]); installPath /= homePath; installPath /= ".wine/dosdevices/"; installPath /= mwpath; diff --git a/components/files/macospath.cpp b/components/files/macospath.cpp index 6e794796f..237141960 100644 --- a/components/files/macospath.cpp +++ b/components/files/macospath.cpp @@ -7,6 +7,8 @@ #include #include +#include + namespace { boost::filesystem::path getUserHome() @@ -129,7 +131,7 @@ boost::filesystem::path MacOsPath::getInstallPath() const if (!mwpath.empty()) { // Change drive letter to lowercase, so we could use ~/.wine/dosdevice symlinks - mwpath[0] = tolower(mwpath[0]); + mwpath[0] = Misc::StringUtils::toLower(mwpath[0]); installPath /= homePath; installPath /= ".wine/dosdevices/"; installPath /= mwpath; diff --git a/components/files/multidircollection.cpp b/components/files/multidircollection.cpp index 9b4a542f5..b37a95b2f 100644 --- a/components/files/multidircollection.cpp +++ b/components/files/multidircollection.cpp @@ -8,6 +8,8 @@ #include +#include + namespace Files { struct NameEqual @@ -28,8 +30,8 @@ namespace Files for (std::size_t i=0; i +#include + namespace Files { typedef std::vector PathContainer; @@ -27,8 +29,8 @@ namespace Files for (std::size_t i=0; i #include #include #include #include +#include + namespace Interpreter{ bool check(const std::string& str, const std::string& escword, unsigned int* i, unsigned int* start) @@ -35,7 +36,7 @@ namespace Interpreter{ { retval << text.substr(start, i - start); std::string temp = text.substr(i+1, 100); - transform(temp.begin(), temp.end(), temp.begin(), ::tolower); + Misc::StringUtils::lowerCase(temp); bool found = false; try diff --git a/components/misc/stringops.hpp b/components/misc/stringops.hpp index d6bc19069..72c027530 100644 --- a/components/misc/stringops.hpp +++ b/components/misc/stringops.hpp @@ -12,11 +12,49 @@ class StringUtils struct ci { bool operator()(char x, char y) const { - return tolower(x) < tolower(y); + return toLower(x) < toLower(y); } }; public: + + /// Plain and simple locale-unaware toLower. Anything from A to Z is lower-cased, multibyte characters are unchanged. + /// Don't use std::tolower(char, locale&) because that is abysmally slow. + /// Don't use tolower(int) because that depends on global locale. + static char toLower(char c) + { + switch(c) + { + case 'A':return 'a'; + case 'B':return 'b'; + case 'C':return 'c'; + case 'D':return 'd'; + case 'E':return 'e'; + case 'F':return 'f'; + case 'G':return 'g'; + case 'H':return 'h'; + case 'I':return 'i'; + case 'J':return 'j'; + case 'K':return 'k'; + case 'L':return 'l'; + case 'M':return 'm'; + case 'N':return 'n'; + case 'O':return 'o'; + case 'P':return 'p'; + case 'Q':return 'q'; + case 'R':return 'r'; + case 'S':return 's'; + case 'T':return 't'; + case 'U':return 'u'; + case 'V':return 'v'; + case 'W':return 'w'; + case 'X':return 'x'; + case 'Y':return 'y'; + case 'Z':return 'z'; + default:return c; + }; + } + static bool ciLess(const std::string &x, const std::string &y) { return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end(), ci()); } @@ -28,7 +66,7 @@ public: std::string::const_iterator xit = x.begin(); std::string::const_iterator yit = y.begin(); for (; xit != x.end(); ++xit, ++yit) { - if (tolower(*xit) != tolower(*yit)) { + if (toLower(*xit) != toLower(*yit)) { return false; } } @@ -42,7 +80,7 @@ public: for(;xit != x.end() && yit != y.end() && len > 0;++xit,++yit,--len) { int res = *xit - *yit; - if(res != 0 && tolower(*xit) != tolower(*yit)) + if(res != 0 && toLower(*xit) != toLower(*yit)) return (res > 0) ? 1 : -1; } if(len > 0) @@ -58,7 +96,7 @@ public: /// Transforms input string to lower case w/o copy static std::string &toLower(std::string &inout) { for (unsigned int i=0; i #include +#include + #include "archive.hpp" namespace @@ -15,7 +17,7 @@ namespace char nonstrict_normalize_char(char ch) { - return ch == '\\' ? '/' : tolower(ch); + return ch == '\\' ? '/' : Misc::StringUtils::toLower(ch); } void normalize_path(std::string& path, bool strict) From 42d68eb7fb9b4d1773f5000138cd3d3c6fbe6996 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 7 Dec 2015 22:29:57 +0100 Subject: [PATCH 2740/3725] Build fix --- apps/opencs/model/world/commanddispatcher.cpp | 2 +- apps/opencs/model/world/scriptcontext.cpp | 2 +- components/misc/stringops.hpp | 5 +++++ 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/world/commanddispatcher.cpp b/apps/opencs/model/world/commanddispatcher.cpp index 0b1af0e84..0bef1bb4e 100644 --- a/apps/opencs/model/world/commanddispatcher.cpp +++ b/apps/opencs/model/world/commanddispatcher.cpp @@ -93,7 +93,7 @@ void CSMWorld::CommandDispatcher::setEditLock (bool locked) void CSMWorld::CommandDispatcher::setSelection (const std::vector& selection) { mSelection = selection; - std::for_each (mSelection.begin(), mSelection.end(), Misc::StringUtils::toLower); + std::for_each (mSelection.begin(), mSelection.end(), Misc::StringUtils::toLowerStr); std::sort (mSelection.begin(), mSelection.end()); } diff --git a/apps/opencs/model/world/scriptcontext.cpp b/apps/opencs/model/world/scriptcontext.cpp index f644ad37a..33025bd1c 100644 --- a/apps/opencs/model/world/scriptcontext.cpp +++ b/apps/opencs/model/world/scriptcontext.cpp @@ -93,7 +93,7 @@ bool CSMWorld::ScriptContext::isId (const std::string& name) const { mIds = mData.getIds(); - std::for_each (mIds.begin(), mIds.end(), &Misc::StringUtils::toLower); + std::for_each (mIds.begin(), mIds.end(), &Misc::StringUtils::toLowerStr); std::sort (mIds.begin(), mIds.end()); mIdsUpdated = true; diff --git a/components/misc/stringops.hpp b/components/misc/stringops.hpp index 72c027530..ce27d5fb2 100644 --- a/components/misc/stringops.hpp +++ b/components/misc/stringops.hpp @@ -100,6 +100,11 @@ public: return inout; } + static std::string &toLowerStr(std::string &inout) + { + return toLower(inout); + } + /// Returns lower case copy of input string static std::string lowerCase(const std::string &in) { From e4751c68e948295a1fa36fee9a8904a6949d3953 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 7 Dec 2015 22:30:02 +0100 Subject: [PATCH 2741/3725] Typo fix --- components/esm/loadregn.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esm/loadregn.hpp b/components/esm/loadregn.hpp index 3d914bd17..a946e488e 100644 --- a/components/esm/loadregn.hpp +++ b/components/esm/loadregn.hpp @@ -45,7 +45,7 @@ struct Region WEATstruct mData; int mMapColor; // RGBA - // sleepList refers to a eveled list of creatures you can meet if + // sleepList refers to a leveled list of creatures you can meet if // you sleep outside in this region. std::string mId, mName, mSleepList; From 4dd4c5394bc97ce6d9cc87eedf8f4f35c5162df3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 7 Dec 2015 22:30:37 +0100 Subject: [PATCH 2742/3725] Broken lower-casing fix --- apps/opencs/model/world/regionmap.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/world/regionmap.cpp b/apps/opencs/model/world/regionmap.cpp index 10c67c909..17831c2ac 100644 --- a/apps/opencs/model/world/regionmap.cpp +++ b/apps/opencs/model/world/regionmap.cpp @@ -168,7 +168,7 @@ void CSMWorld::RegionMap::updateRegions (const std::vector& regions { std::vector regions2 (regions); - std::for_each (regions2.begin(), regions2.end(), &Misc::StringUtils::lowerCase); + std::for_each (regions2.begin(), regions2.end(), Misc::StringUtils::toLowerStr); std::sort (regions2.begin(), regions2.end()); for (std::map::const_iterator iter (mMap.begin()); From e3d3380c8ce1612f579f175972ffe79e00060df1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 7 Dec 2015 22:41:55 +0100 Subject: [PATCH 2743/3725] Remove return value for in-place toLowerStr --- apps/essimporter/converter.hpp | 2 +- components/misc/stringops.hpp | 10 +++++----- components/nifosg/nifloader.cpp | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index 8194f2b43..550b7c0ae 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -381,7 +381,7 @@ public: bool isDeleted = false; faction.load(esm, isDeleted); - std::string id = Misc::StringUtils::toLower(faction.mId); + std::string id = Misc::StringUtils::lowerCase(faction.mId); for (std::map::const_iterator it = faction.mReactions.begin(); it != faction.mReactions.end(); ++it) { diff --git a/components/misc/stringops.hpp b/components/misc/stringops.hpp index ce27d5fb2..2fd997285 100644 --- a/components/misc/stringops.hpp +++ b/components/misc/stringops.hpp @@ -94,22 +94,22 @@ public: } /// Transforms input string to lower case w/o copy - static std::string &toLower(std::string &inout) { + static void toLower(std::string &inout) { for (unsigned int i=0; ilist[i].time, Misc::StringUtils::toLower(result))); + textkeys.insert(std::make_pair(tk->list[i].time, Misc::StringUtils::lowerCase(result))); pos = nextpos; } From 07b064f61682096aef2f5f7838cd064847f5d24e Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 7 Dec 2015 22:49:15 +0100 Subject: [PATCH 2744/3725] Rename to lowerCaseInPlace --- apps/essimporter/converter.hpp | 2 +- apps/mwiniimporter/importer.cpp | 2 +- apps/opencs/model/world/commanddispatcher.cpp | 2 +- apps/opencs/model/world/regionmap.cpp | 2 +- apps/opencs/model/world/scriptcontext.cpp | 2 +- apps/openmw/mwclass/container.cpp | 4 ++-- apps/openmw/mwclass/door.cpp | 4 ++-- apps/openmw/mwgui/formatting.cpp | 4 ++-- apps/openmw/mwgui/itemmodel.cpp | 6 +++--- apps/openmw/mwmechanics/activespells.cpp | 8 ++------ apps/openmw/mwmechanics/activespells.hpp | 2 +- .../mwmechanics/mechanicsmanagerimp.cpp | 4 ++-- apps/openmw/mwrender/animation.cpp | 2 +- apps/openmw/mwscript/cellextensions.cpp | 2 +- apps/openmw/mwscript/guiextensions.cpp | 4 ++-- apps/openmw/mwscript/statsextensions.cpp | 20 +++++++++---------- apps/openmw/mwworld/cellstore.cpp | 2 +- apps/openmw/mwworld/globals.cpp | 2 +- apps/openmw/mwworld/store.cpp | 2 +- components/misc/resourcehelpers.cpp | 2 +- components/misc/stringops.hpp | 9 ++------- 21 files changed, 39 insertions(+), 48 deletions(-) diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index 550b7c0ae..f364e166c 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -398,7 +398,7 @@ public: virtual void read(ESM::ESMReader &esm) { std::string itemid = esm.getHNString("NAME"); - Misc::StringUtils::toLower(itemid); + Misc::StringUtils::lowerCaseInPlace(itemid); while (esm.isNextSub("FNAM") || esm.isNextSub("ONAM")) { diff --git a/apps/mwiniimporter/importer.cpp b/apps/mwiniimporter/importer.cpp index 251889e28..5fdc3cbf5 100644 --- a/apps/mwiniimporter/importer.cpp +++ b/apps/mwiniimporter/importer.cpp @@ -846,7 +846,7 @@ void MwIniImporter::importGameFiles(multistrmap &cfg, const multistrmap &ini, co for(std::vector::const_iterator entry = it->second.begin(); entry!=it->second.end(); ++entry) { std::string filetype(entry->substr(entry->length()-3)); - Misc::StringUtils::toLower(filetype); + Misc::StringUtils::lowerCaseInPlace(filetype); if(filetype.compare("esm") == 0 || filetype.compare("esp") == 0) { boost::filesystem::path filepath(gameFilesDir); diff --git a/apps/opencs/model/world/commanddispatcher.cpp b/apps/opencs/model/world/commanddispatcher.cpp index 0bef1bb4e..a1fc980eb 100644 --- a/apps/opencs/model/world/commanddispatcher.cpp +++ b/apps/opencs/model/world/commanddispatcher.cpp @@ -93,7 +93,7 @@ void CSMWorld::CommandDispatcher::setEditLock (bool locked) void CSMWorld::CommandDispatcher::setSelection (const std::vector& selection) { mSelection = selection; - std::for_each (mSelection.begin(), mSelection.end(), Misc::StringUtils::toLowerStr); + std::for_each (mSelection.begin(), mSelection.end(), Misc::StringUtils::lowerCaseInPlace); std::sort (mSelection.begin(), mSelection.end()); } diff --git a/apps/opencs/model/world/regionmap.cpp b/apps/opencs/model/world/regionmap.cpp index 17831c2ac..6dbbac97f 100644 --- a/apps/opencs/model/world/regionmap.cpp +++ b/apps/opencs/model/world/regionmap.cpp @@ -168,7 +168,7 @@ void CSMWorld::RegionMap::updateRegions (const std::vector& regions { std::vector regions2 (regions); - std::for_each (regions2.begin(), regions2.end(), Misc::StringUtils::toLowerStr); + std::for_each (regions2.begin(), regions2.end(), Misc::StringUtils::lowerCaseInPlace); std::sort (regions2.begin(), regions2.end()); for (std::map::const_iterator iter (mMap.begin()); diff --git a/apps/opencs/model/world/scriptcontext.cpp b/apps/opencs/model/world/scriptcontext.cpp index 33025bd1c..344ae322e 100644 --- a/apps/opencs/model/world/scriptcontext.cpp +++ b/apps/opencs/model/world/scriptcontext.cpp @@ -93,7 +93,7 @@ bool CSMWorld::ScriptContext::isId (const std::string& name) const { mIds = mData.getIds(); - std::for_each (mIds.begin(), mIds.end(), &Misc::StringUtils::toLowerStr); + std::for_each (mIds.begin(), mIds.end(), &Misc::StringUtils::lowerCaseInPlace); std::sort (mIds.begin(), mIds.end()); mIdsUpdated = true; diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index 6c44c97e2..bfdcc23c1 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -148,11 +148,11 @@ namespace MWClass // make key id lowercase std::string keyId = ptr.getCellRef().getKey(); - Misc::StringUtils::toLower(keyId); + Misc::StringUtils::lowerCaseInPlace(keyId); for (MWWorld::ContainerStoreIterator it = invStore.begin(); it != invStore.end(); ++it) { std::string refId = it->getCellRef().getRefId(); - Misc::StringUtils::toLower(refId); + Misc::StringUtils::lowerCaseInPlace(refId); if (refId == keyId) { hasKey = true; diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 6fee79ddf..56c5e655f 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -117,11 +117,11 @@ namespace MWClass // make key id lowercase std::string keyId = ptr.getCellRef().getKey(); - Misc::StringUtils::toLower(keyId); + Misc::StringUtils::lowerCaseInPlace(keyId); for (MWWorld::ContainerStoreIterator it = invStore.begin(); it != invStore.end(); ++it) { std::string refId = it->getCellRef().getRefId(); - Misc::StringUtils::toLower(refId); + Misc::StringUtils::lowerCaseInPlace(refId); if (refId == keyId) { hasKey = true; diff --git a/apps/openmw/mwgui/formatting.cpp b/apps/openmw/mwgui/formatting.cpp index 6adef5eeb..6a8145e97 100644 --- a/apps/openmw/mwgui/formatting.cpp +++ b/apps/openmw/mwgui/formatting.cpp @@ -129,7 +129,7 @@ namespace MWGui size_t tagNameEndPos = tag.find(' '); mAttributes.clear(); mTag = tag.substr(0, tagNameEndPos); - Misc::StringUtils::toLower(mTag); + Misc::StringUtils::lowerCaseInPlace(mTag); if (mTag.empty()) return; @@ -151,7 +151,7 @@ namespace MWGui return; std::string key = tag.substr(0, sepPos); - Misc::StringUtils::toLower(key); + Misc::StringUtils::lowerCaseInPlace(key); tag.erase(0, sepPos+1); std::string value; diff --git a/apps/openmw/mwgui/itemmodel.cpp b/apps/openmw/mwgui/itemmodel.cpp index a1e36bce6..2c382f3cf 100644 --- a/apps/openmw/mwgui/itemmodel.cpp +++ b/apps/openmw/mwgui/itemmodel.cpp @@ -35,7 +35,7 @@ namespace MWGui { const ESM::GameSetting ¤tSetting = *currentIteration; std::string currentGMSTID = currentSetting.mId; - Misc::StringUtils::toLower(currentGMSTID); + Misc::StringUtils::lowerCaseInPlace(currentGMSTID); // Don't bother checking this GMST if it's not a sMagicBound* one. const std::string& toFind = "smagicbound"; @@ -44,7 +44,7 @@ namespace MWGui // All sMagicBound* GMST's should be of type string std::string currentGMSTValue = currentSetting.getString(); - Misc::StringUtils::toLower(currentGMSTValue); + Misc::StringUtils::lowerCaseInPlace(currentGMSTValue); boundItemIDCache.insert(currentGMSTValue); } @@ -52,7 +52,7 @@ namespace MWGui // Perform bound item check and assign the Flag_Bound bit if it passes std::string tempItemID = base.getCellRef().getRefId(); - Misc::StringUtils::toLower(tempItemID); + Misc::StringUtils::lowerCaseInPlace(tempItemID); if (boundItemIDCache.count(tempItemID) != 0) mFlags |= Flag_Bound; diff --git a/apps/openmw/mwmechanics/activespells.cpp b/apps/openmw/mwmechanics/activespells.cpp index 7068310a0..6a247622c 100644 --- a/apps/openmw/mwmechanics/activespells.cpp +++ b/apps/openmw/mwmechanics/activespells.cpp @@ -132,15 +132,11 @@ namespace MWMechanics return scaledDuration-usedUp; } - bool ActiveSpells::isSpellActive(std::string id) const + bool ActiveSpells::isSpellActive(const std::string& id) const { - Misc::StringUtils::toLower(id); for (TContainer::iterator iter = mSpells.begin(); iter != mSpells.end(); ++iter) { - std::string left = iter->first; - Misc::StringUtils::toLower(left); - - if (iter->first == id) + if (Misc::StringUtils::ciEqual(iter->first, id)) return true; } return false; diff --git a/apps/openmw/mwmechanics/activespells.hpp b/apps/openmw/mwmechanics/activespells.hpp index 2a4d75d40..3842ee61c 100644 --- a/apps/openmw/mwmechanics/activespells.hpp +++ b/apps/openmw/mwmechanics/activespells.hpp @@ -97,7 +97,7 @@ namespace MWMechanics /// Remove all spells void clear(); - bool isSpellActive (std::string id) const; + bool isSpellActive (const std::string& id) const; ///< case insensitive const MagicEffects& getMagicEffects() const; diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 68bea02b0..ba958df10 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -604,7 +604,7 @@ namespace MWMechanics int rank = 0; std::string npcFaction = ptr.getClass().getPrimaryFaction(ptr); - Misc::StringUtils::toLower(npcFaction); + Misc::StringUtils::lowerCaseInPlace(npcFaction); if (playerStats.getFactionRanks().find(npcFaction) != playerStats.getFactionRanks().end()) { @@ -1042,7 +1042,7 @@ namespace MWMechanics owner.first = ownerCellRef->getFaction(); owner.second = true; } - Misc::StringUtils::toLower(owner.first); + Misc::StringUtils::lowerCaseInPlace(owner.first); if (!Misc::StringUtils::ciEqual(item.getCellRef().getRefId(), MWWorld::ContainerStore::sGoldId)) mStolenItems[Misc::StringUtils::lowerCase(item.getClass().getId(item))][owner] += count; diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index ecfb2df14..214e7f221 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -390,7 +390,7 @@ namespace MWRender void Animation::addAnimSource(const std::string &model) { std::string kfname = model; - Misc::StringUtils::toLower(kfname); + Misc::StringUtils::lowerCaseInPlace(kfname); if(kfname.size() > 4 && kfname.compare(kfname.size()-4, 4, ".nif") == 0) kfname.replace(kfname.size()-4, 4, ".kf"); diff --git a/apps/openmw/mwscript/cellextensions.cpp b/apps/openmw/mwscript/cellextensions.cpp index b6f7229e0..513c1cc42 100644 --- a/apps/openmw/mwscript/cellextensions.cpp +++ b/apps/openmw/mwscript/cellextensions.cpp @@ -123,7 +123,7 @@ namespace MWScript const MWWorld::CellStore *cell = MWMechanics::getPlayer().getCell(); std::string current = MWBase::Environment::get().getWorld()->getCellName(cell); - Misc::StringUtils::toLower(current); + Misc::StringUtils::lowerCaseInPlace(current); bool match = current.length()>=name.length() && current.substr (0, name.length())==name; diff --git a/apps/openmw/mwscript/guiextensions.cpp b/apps/openmw/mwscript/guiextensions.cpp index 397e0cac5..254da56d6 100644 --- a/apps/openmw/mwscript/guiextensions.cpp +++ b/apps/openmw/mwscript/guiextensions.cpp @@ -116,7 +116,7 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { std::string cell = (runtime.getStringLiteral (runtime[0].mInteger)); - ::Misc::StringUtils::toLower(cell); + ::Misc::StringUtils::lowerCaseInPlace(cell); runtime.pop(); // "Will match complete or partial cells, so ShowMap, "Vivec" will show cells Vivec and Vivec, Fred's House as well." @@ -129,7 +129,7 @@ namespace MWScript for (; it != cells.extEnd(); ++it) { std::string name = it->mName; - ::Misc::StringUtils::toLower(name); + ::Misc::StringUtils::lowerCaseInPlace(name); if (name.find(cell) != std::string::npos) MWBase::Environment::get().getWindowManager()->addVisitedLocation ( it->mName, diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index e4ad71875..3996dd80b 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -543,7 +543,7 @@ namespace MWScript factionID = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); } - ::Misc::StringUtils::toLower(factionID); + ::Misc::StringUtils::lowerCaseInPlace(factionID); // Make sure this faction exists MWBase::Environment::get().getWorld()->getStore().get().find(factionID); @@ -575,7 +575,7 @@ namespace MWScript factionID = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); } - ::Misc::StringUtils::toLower(factionID); + ::Misc::StringUtils::lowerCaseInPlace(factionID); // Make sure this faction exists MWBase::Environment::get().getWorld()->getStore().get().find(factionID); @@ -614,7 +614,7 @@ namespace MWScript factionID = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); } - ::Misc::StringUtils::toLower(factionID); + ::Misc::StringUtils::lowerCaseInPlace(factionID); // Make sure this faction exists MWBase::Environment::get().getWorld()->getStore().get().find(factionID); @@ -645,7 +645,7 @@ namespace MWScript { factionID = ptr.getClass().getPrimaryFaction(ptr); } - ::Misc::StringUtils::toLower(factionID); + ::Misc::StringUtils::lowerCaseInPlace(factionID); // Make sure this faction exists MWBase::Environment::get().getWorld()->getStore().get().find(factionID); @@ -756,7 +756,7 @@ namespace MWScript if (factionId.empty()) throw std::runtime_error ("failed to determine faction"); - ::Misc::StringUtils::toLower (factionId); + ::Misc::StringUtils::lowerCaseInPlace (factionId); MWWorld::Ptr player = MWMechanics::getPlayer(); runtime.push ( @@ -791,7 +791,7 @@ namespace MWScript if (factionId.empty()) throw std::runtime_error ("failed to determine faction"); - ::Misc::StringUtils::toLower (factionId); + ::Misc::StringUtils::lowerCaseInPlace (factionId); MWWorld::Ptr player = MWMechanics::getPlayer(); player.getClass().getNpcStats (player).setFactionReputation (factionId, value); @@ -825,7 +825,7 @@ namespace MWScript if (factionId.empty()) throw std::runtime_error ("failed to determine faction"); - ::Misc::StringUtils::toLower (factionId); + ::Misc::StringUtils::lowerCaseInPlace (factionId); MWWorld::Ptr player = MWMechanics::getPlayer(); player.getClass().getNpcStats (player).setFactionReputation (factionId, @@ -870,11 +870,11 @@ namespace MWScript MWWorld::Ptr ptr = R()(runtime); std::string race = runtime.getStringLiteral(runtime[0].mInteger); - ::Misc::StringUtils::toLower(race); + ::Misc::StringUtils::lowerCaseInPlace(race); runtime.pop(); std::string npcRace = ptr.get()->mBase->mRace; - ::Misc::StringUtils::toLower(npcRace); + ::Misc::StringUtils::lowerCaseInPlace(npcRace); runtime.push (npcRace == race); } @@ -911,7 +911,7 @@ namespace MWScript { factionID = ptr.getClass().getPrimaryFaction(ptr); } - ::Misc::StringUtils::toLower(factionID); + ::Misc::StringUtils::lowerCaseInPlace(factionID); MWWorld::Ptr player = MWMechanics::getPlayer(); if(factionID!="") { diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 5832a6727..029dac22d 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -472,7 +472,7 @@ namespace MWWorld void CellStore::loadRef (ESM::CellRef& ref, bool deleted, const ESMStore& store) { - Misc::StringUtils::toLower (ref.mRefID); + Misc::StringUtils::lowerCaseInPlace (ref.mRefID); switch (store.find (ref.mRefID)) { diff --git a/apps/openmw/mwworld/globals.cpp b/apps/openmw/mwworld/globals.cpp index 4a406613d..acc06b28a 100644 --- a/apps/openmw/mwworld/globals.cpp +++ b/apps/openmw/mwworld/globals.cpp @@ -96,7 +96,7 @@ namespace MWWorld // This readRecord() method is used when reading a saved game. // Deleted globals can't appear there, so isDeleted will be ignored here. global.load(reader, isDeleted); - Misc::StringUtils::toLower(global.mId); + Misc::StringUtils::lowerCaseInPlace(global.mId); Collection::iterator iter = mVariables.find (global.mId); if (iter!=mVariables.end()) diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index 3d23f3da4..d1ba0ef0b 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -190,7 +190,7 @@ namespace MWWorld bool isDeleted = false; record.load(esm, isDeleted); - Misc::StringUtils::toLower(record.mId); + Misc::StringUtils::lowerCaseInPlace(record.mId); std::pair inserted = mStatic.insert(std::make_pair(record.mId, record)); if (inserted.second) diff --git a/components/misc/resourcehelpers.cpp b/components/misc/resourcehelpers.cpp index 0c2635752..6fe13abf3 100644 --- a/components/misc/resourcehelpers.cpp +++ b/components/misc/resourcehelpers.cpp @@ -51,7 +51,7 @@ std::string Misc::ResourceHelpers::correctResourcePath(const std::string &topLev std::string prefix2 = topLevelDirectory + '/'; std::string correctedPath = resPath; - Misc::StringUtils::toLower(correctedPath); + Misc::StringUtils::lowerCaseInPlace(correctedPath); // Apparently, leading separators are allowed while (correctedPath.size() && (correctedPath[0] == '/' || correctedPath[0] == '\\')) diff --git a/components/misc/stringops.hpp b/components/misc/stringops.hpp index 2fd997285..2723527f1 100644 --- a/components/misc/stringops.hpp +++ b/components/misc/stringops.hpp @@ -94,21 +94,16 @@ public: } /// Transforms input string to lower case w/o copy - static void toLower(std::string &inout) { + static void lowerCaseInPlace(std::string &inout) { for (unsigned int i=0; i Date: Tue, 8 Dec 2015 09:56:42 +0100 Subject: [PATCH 2745/3725] some simplification --- apps/opencs/model/prefs/category.cpp | 9 ++----- apps/opencs/model/prefs/category.hpp | 4 +-- apps/opencs/model/prefs/state.cpp | 39 +++++++++++++--------------- apps/opencs/model/prefs/state.hpp | 18 +++++++++---- apps/opencs/view/prefs/dialogue.cpp | 8 +++--- apps/opencs/view/prefs/dialogue.hpp | 1 - 6 files changed, 38 insertions(+), 41 deletions(-) diff --git a/apps/opencs/model/prefs/category.cpp b/apps/opencs/model/prefs/category.cpp index 2f94c729b..8143a19e5 100644 --- a/apps/opencs/model/prefs/category.cpp +++ b/apps/opencs/model/prefs/category.cpp @@ -1,16 +1,11 @@ #include "category.hpp" -CSMPrefs::Category::Category (State *parent, const std::string& key, const std::string& name) -: mParent (parent), mKey (key), mName (name) +CSMPrefs::Category::Category (State *parent, const std::string& key) +: mParent (parent), mKey (key) {} const std::string& CSMPrefs::Category::getKey() const { return mKey; } - -const std::string& CSMPrefs::Category::getName() const -{ - return mName; -} diff --git a/apps/opencs/model/prefs/category.hpp b/apps/opencs/model/prefs/category.hpp index d80d5416f..43a6325ee 100644 --- a/apps/opencs/model/prefs/category.hpp +++ b/apps/opencs/model/prefs/category.hpp @@ -11,15 +11,13 @@ namespace CSMPrefs { State *mParent; std::string mKey; - std::string mName; public: - Category (State *parent, const std::string& key, const std::string& name); + Category (State *parent, const std::string& key); const std::string& getKey() const; - const std::string& getName() const; }; } diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index 70e4c86c5..d8a0a5614 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -28,28 +28,28 @@ void CSMPrefs::State::load() void CSMPrefs::State::declare() { - declareCategory ("window", "Windows"); + declareCategory ("Windows"); - declareCategory ("records", "Records"); + declareCategory ("Records"); - declareCategory ("table-input", "ID Tables"); + declareCategory ("ID Tables"); - declareCategory ("dialogues", "ID Dialogues"); + declareCategory ("ID Dialogues"); - declareCategory ("report-input", "Reports"); + declareCategory ("Reports"); - declareCategory ("search", "Search & Replace"); + declareCategory ("Search & Replace"); - declareCategory ("script-editor", "Scripts"); + declareCategory ("Scripts"); - declareCategory ("general-input", "General Input"); + declareCategory ("General Input"); - declareCategory ("scene-input", "3D Scene Input"); + declareCategory ("3D Scene Input"); - declareCategory ("tooltips", "Tooltips"); + declareCategory ("Tooltips"); } -void CSMPrefs::State::declareCategory (const std::string& key, const std::string& name) +void CSMPrefs::State::declareCategory (const std::string& key) { std::map::iterator iter = mCategories.find (key); @@ -60,7 +60,7 @@ void CSMPrefs::State::declareCategory (const std::string& key, const std::string else { mCurrentCategory = - mCategories.insert (std::make_pair (key, Category (this, key, name))).first; + mCategories.insert (std::make_pair (key, Category (this, key))).first; } } @@ -88,17 +88,14 @@ void CSMPrefs::State::save() mSettings.saveUser (user.string()); } -std::vector > CSMPrefs::State::listCategories() const +CSMPrefs::State::Iterator CSMPrefs::State::begin() { - std::vector > list; - - for (std::map::const_iterator iter (mCategories.begin()); - iter!=mCategories.end(); ++iter) - list.push_back (std::make_pair (iter->second.getName(), iter->first)); - - std::sort (list.begin(), list.end()); + return mCategories.begin(); +} - return list; +CSMPrefs::State::Iterator CSMPrefs::State::end() +{ + return mCategories.end(); } CSMPrefs::State& CSMPrefs::State::get() diff --git a/apps/opencs/model/prefs/state.hpp b/apps/opencs/model/prefs/state.hpp index fd49db3ef..d643dfa4a 100644 --- a/apps/opencs/model/prefs/state.hpp +++ b/apps/opencs/model/prefs/state.hpp @@ -22,11 +22,18 @@ namespace CSMPrefs static State *sThis; + public: + + typedef std::map Collection; + typedef Collection::iterator Iterator; + + private: + const std::string mConfigFile; const Files::ConfigurationManager& mConfigurationManager; Settings::Manager mSettings; - std::map mCategories; - std::map::iterator mCurrentCategory; + Collection mCategories; + Iterator mCurrentCategory; // not implemented State (const State&); @@ -38,7 +45,7 @@ namespace CSMPrefs void declare(); - void declareCategory (const std::string& key, const std::string& name); + void declareCategory (const std::string& key); public: @@ -48,8 +55,9 @@ namespace CSMPrefs void save(); - /// \return collection of name, key pairs (sorted) - std::vector > listCategories() const; + Iterator begin(); + + Iterator end(); static State& get(); }; diff --git a/apps/opencs/view/prefs/dialogue.cpp b/apps/opencs/view/prefs/dialogue.cpp index cc794c286..ec43d853d 100644 --- a/apps/opencs/view/prefs/dialogue.cpp +++ b/apps/opencs/view/prefs/dialogue.cpp @@ -24,10 +24,10 @@ void CSVPrefs::Dialogue::buildCategorySelector (QSplitter *main) int maxWidth = 1; - for (std::vector >::const_iterator iter (mCategories.begin()); - iter!=mCategories.end(); ++iter) + for (CSMPrefs::State::Iterator iter = CSMPrefs::get().begin(); iter!=CSMPrefs::get().end(); + ++iter) { - QString label = QString::fromUtf8 (iter->first.c_str()); + QString label = QString::fromUtf8 (iter->second.getKey().c_str()); maxWidth = std::max (maxWidth, metrics.width (label)); mList->addItem (label); @@ -46,7 +46,7 @@ void CSVPrefs::Dialogue::buildContentArea (QSplitter *main) main->addWidget (mContent); } -CSVPrefs::Dialogue::Dialogue() : mCategories (CSMPrefs::get().listCategories()) +CSVPrefs::Dialogue::Dialogue() { setWindowTitle ("User Settings"); diff --git a/apps/opencs/view/prefs/dialogue.hpp b/apps/opencs/view/prefs/dialogue.hpp index 2773bcccc..78c832c9f 100644 --- a/apps/opencs/view/prefs/dialogue.hpp +++ b/apps/opencs/view/prefs/dialogue.hpp @@ -15,7 +15,6 @@ namespace CSVPrefs QListWidget *mList; QStackedWidget *mContent; - std::vector > mCategories; private: From 5e40b4d2e83128721863e5c56c7f3b65aea0459e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 8 Dec 2015 12:04:45 +0100 Subject: [PATCH 2746/3725] page switching mechanism --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/prefs/state.cpp | 10 ++++++++++ apps/opencs/model/prefs/state.hpp | 2 ++ apps/opencs/view/prefs/dialogue.cpp | 27 ++++++++++++++++++++++++++- apps/opencs/view/prefs/dialogue.hpp | 5 +++++ apps/opencs/view/prefs/pagebase.cpp | 19 +++++++++++++++++++ apps/opencs/view/prefs/pagebase.hpp | 27 +++++++++++++++++++++++++++ 7 files changed, 90 insertions(+), 2 deletions(-) create mode 100644 apps/opencs/view/prefs/pagebase.cpp create mode 100644 apps/opencs/view/prefs/pagebase.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index b58000b56..1e666c77d 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -124,7 +124,7 @@ opencs_units_noqt (view/settings ) opencs_units (view/prefs - dialogue + dialogue pagebase ) opencs_units (model/settings diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index d8a0a5614..c484a98d6 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -98,6 +98,16 @@ CSMPrefs::State::Iterator CSMPrefs::State::end() return mCategories.end(); } +CSMPrefs::Category& CSMPrefs::State::getCategory (const std::string& key) +{ + Iterator iter = mCategories.find (key); + + if (iter==mCategories.end()) + throw std::logic_error ("Invalid user settings category: " + key); + + return iter->second; +} + CSMPrefs::State& CSMPrefs::State::get() { if (!sThis) diff --git a/apps/opencs/model/prefs/state.hpp b/apps/opencs/model/prefs/state.hpp index d643dfa4a..a2e7aa038 100644 --- a/apps/opencs/model/prefs/state.hpp +++ b/apps/opencs/model/prefs/state.hpp @@ -59,6 +59,8 @@ namespace CSMPrefs Iterator end(); + Category& getCategory (const std::string& key); + static State& get(); }; diff --git a/apps/opencs/view/prefs/dialogue.cpp b/apps/opencs/view/prefs/dialogue.cpp index ec43d853d..c4480fec4 100644 --- a/apps/opencs/view/prefs/dialogue.cpp +++ b/apps/opencs/view/prefs/dialogue.cpp @@ -10,6 +10,8 @@ #include "../../model/prefs/state.hpp" +#include "pagebase.hpp" + void CSVPrefs::Dialogue::buildCategorySelector (QSplitter *main) { mList = new QListWidget (main); @@ -35,7 +37,8 @@ void CSVPrefs::Dialogue::buildCategorySelector (QSplitter *main) mList->setMaximumWidth (maxWidth + 10); - /// \todo connect to selection signal + connect (mList, SIGNAL (currentItemChanged (QListWidgetItem *, QListWidgetItem *)), + this, SLOT (selectionChanged (QListWidgetItem *, QListWidgetItem *))); } void CSVPrefs::Dialogue::buildContentArea (QSplitter *main) @@ -86,3 +89,25 @@ void CSVPrefs::Dialogue::show() QWidget::show(); } + +void CSVPrefs::Dialogue::selectionChanged (QListWidgetItem *current, QListWidgetItem *previous) +{ + if (current) + { + std::string key = current->text().toUtf8().data(); + + for (int i=0; icount(); ++i) + { + PageBase& page = dynamic_cast (*mContent->widget (i)); + + if (page.getCategory().getKey()==key) + { + mContent->setCurrentIndex (i); + return; + } + } + + PageBase *page = new PageBase (CSMPrefs::get().getCategory (key), mContent); + mContent->setCurrentIndex (mContent->addWidget (page)); + } +} diff --git a/apps/opencs/view/prefs/dialogue.hpp b/apps/opencs/view/prefs/dialogue.hpp index 78c832c9f..6bee54eb8 100644 --- a/apps/opencs/view/prefs/dialogue.hpp +++ b/apps/opencs/view/prefs/dialogue.hpp @@ -6,6 +6,7 @@ class QSplitter; class QListWidget; class QStackedWidget; +class QListWidgetItem; namespace CSVPrefs { @@ -33,6 +34,10 @@ namespace CSVPrefs public slots: void show(); + + private slots: + + void selectionChanged (QListWidgetItem *current, QListWidgetItem *previous); }; } diff --git a/apps/opencs/view/prefs/pagebase.cpp b/apps/opencs/view/prefs/pagebase.cpp new file mode 100644 index 000000000..28c33a94a --- /dev/null +++ b/apps/opencs/view/prefs/pagebase.cpp @@ -0,0 +1,19 @@ + +#include "pagebase.hpp" + +#include + +#include "../../model/prefs/category.hpp" + +CSVPrefs::PageBase::PageBase (CSMPrefs::Category& category, QWidget *parent) +: QScrollArea (parent), mCategory (category) +{ +QLabel *temp = new QLabel (category.getKey().c_str(), this); +setWidget (temp); + +} + +CSMPrefs::Category& CSVPrefs::PageBase::getCategory() +{ + return mCategory; +} diff --git a/apps/opencs/view/prefs/pagebase.hpp b/apps/opencs/view/prefs/pagebase.hpp new file mode 100644 index 000000000..affe49f4a --- /dev/null +++ b/apps/opencs/view/prefs/pagebase.hpp @@ -0,0 +1,27 @@ +#ifndef CSV_PREFS_PAGEBASE_H +#define CSV_PREFS_PAGEBASE_H + +#include + +namespace CSMPrefs +{ + class Category; +} + +namespace CSVPrefs +{ + class PageBase : public QScrollArea + { + Q_OBJECT + + CSMPrefs::Category& mCategory; + + public: + + PageBase (CSMPrefs::Category& category, QWidget *parent); + + CSMPrefs::Category& getCategory(); + }; +} + +#endif From c15822431424627b7d3708c5d9688bae511d1bfc Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 8 Dec 2015 12:09:53 +0100 Subject: [PATCH 2747/3725] fixed a faulty include --- apps/opencs/model/prefs/category.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/prefs/category.hpp b/apps/opencs/model/prefs/category.hpp index 43a6325ee..23caba5e4 100644 --- a/apps/opencs/model/prefs/category.hpp +++ b/apps/opencs/model/prefs/category.hpp @@ -1,7 +1,7 @@ #ifndef CSV_PREFS_CATEGORY_H #define CSM_PREFS_CATEGORY_H -#include +#include namespace CSMPrefs { From bd68ebac626de076b546e0c3174dca438a5fb25c Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 8 Dec 2015 15:24:02 +0100 Subject: [PATCH 2748/3725] GetEffect fix --- apps/openmw/mwscript/miscextensions.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 68a30de4a..8375cf8ae 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -425,7 +425,7 @@ namespace MWScript const MWMechanics::MagicEffects& effects = ptr.getClass().getCreatureStats(ptr).getMagicEffects(); for (MWMechanics::MagicEffects::Collection::const_iterator it = effects.begin(); it != effects.end(); ++it) { - if (it->first.mId == key) + if (it->first.mId == key && it->second.getModifier() > 0) { runtime.push(1); return; From 624809c8dc770336888d412c348071b99d1c70f5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 8 Dec 2015 16:48:01 +0100 Subject: [PATCH 2749/3725] Minor fix for error handling in skeleton.cpp --- components/sceneutil/skeleton.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/components/sceneutil/skeleton.cpp b/components/sceneutil/skeleton.cpp index 332dc3b07..d1299c058 100644 --- a/components/sceneutil/skeleton.cpp +++ b/components/sceneutil/skeleton.cpp @@ -162,6 +162,7 @@ void Bone::update(const osg::Matrixf* parentMatrixInSkeletonSpace) if (!mNode) { std::cerr << "Bone without node " << std::endl; + return; } if (parentMatrixInSkeletonSpace) mMatrixInSkeletonSpace = mNode->getMatrix() * (*parentMatrixInSkeletonSpace); From e69750905a1a50479c0d13313ee6e0dd95657028 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 8 Dec 2015 16:48:25 +0100 Subject: [PATCH 2750/3725] Fix gcc warning about function casts --- apps/openmw/mwsound/openal_output.cpp | 36 ++++++++++++++++++--------- 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 407a24ce1..c2e808dee 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -50,6 +50,20 @@ namespace const int sLoudnessFPS = 20; // loudness values per second of audio +// Helper to get an OpenAL extension function +template +void convertPointer(T& dest, R src) +{ + memcpy(&dest, &src, sizeof(src)); +} + +template +void getFunc(T& func, ALCdevice *device, const char *name) +{ + void* funcPtr = alcGetProcAddress(device, name); + convertPointer(func, funcPtr); +} + } namespace MWSound @@ -602,9 +616,8 @@ std::vector OpenAL_Output::enumerateHrtf() if(!alcIsExtensionPresent(mDevice, "ALC_SOFT_HRTF")) return ret; - LPALCGETSTRINGISOFT alcGetStringiSOFT = reinterpret_cast( - alcGetProcAddress(mDevice, "alcGetStringiSOFT") - ); + LPALCGETSTRINGISOFT alcGetStringiSOFT = 0; + getFunc(alcGetStringiSOFT, mDevice, "alcGetStringiSOFT"); ALCint num_hrtf; alcGetIntegerv(mDevice, ALC_NUM_HRTF_SPECIFIERS_SOFT, 1, &num_hrtf); @@ -626,12 +639,12 @@ void OpenAL_Output::enableHrtf(const std::string &hrtfname, bool auto_enable) return; } - LPALCGETSTRINGISOFT alcGetStringiSOFT = reinterpret_cast( - alcGetProcAddress(mDevice, "alcGetStringiSOFT") - ); - LPALCRESETDEVICESOFT alcResetDeviceSOFT = reinterpret_cast( - alcGetProcAddress(mDevice, "alcResetDeviceSOFT") - ); + + LPALCGETSTRINGISOFT alcGetStringiSOFT = 0; + getFunc(alcGetStringiSOFT, mDevice, "alcGetStringiSOFT"); + + LPALCRESETDEVICESOFT alcResetDeviceSOFT = 0; + getFunc(alcResetDeviceSOFT, mDevice, "alcResetDeviceSOFT"); std::vector attrs; attrs.push_back(ALC_HRTF_SOFT); @@ -681,9 +694,8 @@ void OpenAL_Output::disableHrtf() return; } - LPALCRESETDEVICESOFT alcResetDeviceSOFT = reinterpret_cast( - alcGetProcAddress(mDevice, "alcResetDeviceSOFT") - ); + LPALCRESETDEVICESOFT alcResetDeviceSOFT = 0; + getFunc(alcResetDeviceSOFT, mDevice, "alcResetDeviceSOFT"); std::vector attrs; attrs.push_back(ALC_HRTF_SOFT); From c61d717e41836c11f5c8881fb9dbb1d65b9f541b Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 8 Dec 2015 17:21:58 +0100 Subject: [PATCH 2751/3725] added integer settings --- apps/opencs/CMakeLists.txt | 4 +- apps/opencs/model/prefs/category.cpp | 20 +++++++ apps/opencs/model/prefs/category.hpp | 19 ++++++- apps/opencs/model/prefs/intsetting.cpp | 69 +++++++++++++++++++++++ apps/opencs/model/prefs/intsetting.hpp | 39 +++++++++++++ apps/opencs/model/prefs/setting.cpp | 32 +++++++++++ apps/opencs/model/prefs/setting.hpp | 53 ++++++++++++++++++ apps/opencs/model/prefs/state.cpp | 76 ++++++++++++++++++++++++++ apps/opencs/model/prefs/state.hpp | 13 +++++ apps/opencs/view/prefs/dialogue.cpp | 11 +++- apps/opencs/view/prefs/dialogue.hpp | 4 ++ apps/opencs/view/prefs/page.cpp | 40 ++++++++++++++ apps/opencs/view/prefs/page.hpp | 29 ++++++++++ apps/opencs/view/prefs/pagebase.cpp | 8 +-- 14 files changed, 405 insertions(+), 12 deletions(-) create mode 100644 apps/opencs/model/prefs/intsetting.cpp create mode 100644 apps/opencs/model/prefs/intsetting.hpp create mode 100644 apps/opencs/model/prefs/setting.cpp create mode 100644 apps/opencs/model/prefs/setting.hpp create mode 100644 apps/opencs/view/prefs/page.cpp create mode 100644 apps/opencs/view/prefs/page.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 1e666c77d..003fd657b 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -124,7 +124,7 @@ opencs_units_noqt (view/settings ) opencs_units (view/prefs - dialogue pagebase + dialogue pagebase page ) opencs_units (model/settings @@ -138,7 +138,7 @@ opencs_hdrs_noqt (model/settings ) opencs_units (model/prefs - state + state setting intsetting ) opencs_units_noqt (model/prefs diff --git a/apps/opencs/model/prefs/category.cpp b/apps/opencs/model/prefs/category.cpp index 8143a19e5..b001586b5 100644 --- a/apps/opencs/model/prefs/category.cpp +++ b/apps/opencs/model/prefs/category.cpp @@ -9,3 +9,23 @@ const std::string& CSMPrefs::Category::getKey() const { return mKey; } + +CSMPrefs::State *CSMPrefs::Category::getState() const +{ + return mParent; +} + +void CSMPrefs::Category::addSetting (Setting *setting) +{ + mSettings.push_back (setting); +} + +CSMPrefs::Category::Iterator CSMPrefs::Category::begin() +{ + return mSettings.begin(); +} + +CSMPrefs::Category::Iterator CSMPrefs::Category::end() +{ + return mSettings.end(); +} diff --git a/apps/opencs/model/prefs/category.hpp b/apps/opencs/model/prefs/category.hpp index 23caba5e4..0b8e45d56 100644 --- a/apps/opencs/model/prefs/category.hpp +++ b/apps/opencs/model/prefs/category.hpp @@ -1,16 +1,26 @@ -#ifndef CSV_PREFS_CATEGORY_H +#ifndef CSM_PREFS_CATEGORY_H #define CSM_PREFS_CATEGORY_H #include +#include namespace CSMPrefs { class State; + class Setting; class Category { + public: + + typedef std::vector Container; + typedef Container::iterator Iterator; + + private: + State *mParent; std::string mKey; + Container mSettings; public: @@ -18,6 +28,13 @@ namespace CSMPrefs const std::string& getKey() const; + State *getState() const; + + void addSetting (Setting *setting); + + Iterator begin(); + + Iterator end(); }; } diff --git a/apps/opencs/model/prefs/intsetting.cpp b/apps/opencs/model/prefs/intsetting.cpp new file mode 100644 index 000000000..83fb495c5 --- /dev/null +++ b/apps/opencs/model/prefs/intsetting.cpp @@ -0,0 +1,69 @@ + +#include "intsetting.hpp" + +#include + +#include +#include + +#include + +#include "category.hpp" +#include "state.hpp" + +CSMPrefs::IntSetting::IntSetting (Category *parent, Settings::Manager *values, + const std::string& key, const std::string& label, int default_) +: Setting (parent, values, key, label), mMin (0), mMax (std::numeric_limits::max()), + mDefault (default_) +{} + +CSMPrefs::IntSetting& CSMPrefs::IntSetting::setRange (int min, int max) +{ + mMin = min; + mMax = max; + return *this; +} + +CSMPrefs::IntSetting& CSMPrefs::IntSetting::setMin (int min) +{ + mMin = min; + return *this; +} + +CSMPrefs::IntSetting& CSMPrefs::IntSetting::setMax (int max) +{ + mMax = max; + return *this; +} + +CSMPrefs::IntSetting& CSMPrefs::IntSetting::setTooltip (const std::string& tooltip) +{ + mTooltip = tooltip; + return *this; +} + +std::pair CSMPrefs::IntSetting::makeWidgets (QWidget *parent) +{ + QLabel *label = new QLabel (QString::fromUtf8 (getLabel().c_str()), parent); + + QSpinBox *widget = new QSpinBox (parent); + widget->setRange (mMin, mMax); + widget->setValue (mDefault); + + if (!mTooltip.empty()) + { + QString tooltip = QString::fromUtf8 (mTooltip.c_str()); + label->setToolTip (tooltip); + widget->setToolTip (tooltip); + } + + connect (widget, SIGNAL (valueChanged (int)), this, SLOT (valueChanged (int))); + + return std::make_pair (label, widget); +} + +void CSMPrefs::IntSetting::valueChanged (int value) +{ + getValues().setInt (getKey(), getParent()->getKey(), value); + getParent()->getState()->update (*this); +} diff --git a/apps/opencs/model/prefs/intsetting.hpp b/apps/opencs/model/prefs/intsetting.hpp new file mode 100644 index 000000000..314e68b37 --- /dev/null +++ b/apps/opencs/model/prefs/intsetting.hpp @@ -0,0 +1,39 @@ +#ifndef CSM_PREFS_INTSETTING_H +#define CSM_PREFS_INTSETTING_H + +#include "setting.hpp" + +namespace CSMPrefs +{ + class IntSetting : public Setting + { + Q_OBJECT + + int mMin; + int mMax; + std::string mTooltip; + int mDefault; + + public: + + IntSetting (Category *parent, Settings::Manager *values, + const std::string& key, const std::string& label, int default_); + + IntSetting& setRange (int min, int max); + + IntSetting& setMin (int min); + + IntSetting& setMax (int max); + + IntSetting& setTooltip (const std::string& tooltip); + + /// Return label, input widget. + virtual std::pair makeWidgets (QWidget *parent); + + private slots: + + void valueChanged (int value); + }; +} + +#endif diff --git a/apps/opencs/model/prefs/setting.cpp b/apps/opencs/model/prefs/setting.cpp new file mode 100644 index 000000000..70dbbc745 --- /dev/null +++ b/apps/opencs/model/prefs/setting.cpp @@ -0,0 +1,32 @@ + +#include "setting.hpp" + +#include "category.hpp" +#include "state.hpp" + +Settings::Manager& CSMPrefs::Setting::getValues() +{ + return *mValues; +} + +CSMPrefs::Setting::Setting (Category *parent, Settings::Manager *values, + const std::string& key, const std::string& label) +: QObject (parent->getState()), mParent (parent), mValues (values), mKey (key), mLabel (label) +{} + +CSMPrefs::Setting:: ~Setting() {} + +const CSMPrefs::Category *CSMPrefs::Setting::getParent() const +{ + return mParent; +} + +const std::string& CSMPrefs::Setting::getKey() const +{ + return mKey; +} + +const std::string& CSMPrefs::Setting::getLabel() const +{ + return mLabel; +} diff --git a/apps/opencs/model/prefs/setting.hpp b/apps/opencs/model/prefs/setting.hpp new file mode 100644 index 000000000..148c64292 --- /dev/null +++ b/apps/opencs/model/prefs/setting.hpp @@ -0,0 +1,53 @@ +#ifndef CSM_PREFS_SETTING_H +#define CSM_PREFS_SETTING_H + +#include +#include + +#include + +class QWidget; + +namespace Settings +{ + class Manager; +} + +namespace CSMPrefs +{ + class Category; + + class Setting : public QObject + { + Q_OBJECT + + Category *mParent; + Settings::Manager *mValues; + std::string mKey; + std::string mLabel; + + protected: + + Settings::Manager& getValues(); + + public: + + Setting (Category *parent, Settings::Manager *values, const std::string& key, const std::string& label); + + virtual ~Setting(); + + /// Return label, input widget. + /// + /// \note first can be a 0-pointer, which means that the label is part of the input + /// widget. + virtual std::pair makeWidgets (QWidget *parent) = 0; + + const Category *getParent() const; + + const std::string& getKey() const; + + const std::string& getLabel() const; + }; +} + +#endif diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index c484a98d6..dfc460528 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -3,6 +3,9 @@ #include #include +#include + +#include "intsetting.hpp" CSMPrefs::State *CSMPrefs::State::sThis = 0; @@ -29,6 +32,24 @@ void CSMPrefs::State::load() void CSMPrefs::State::declare() { declareCategory ("Windows"); + declareInt ("default-width", "Default window width", 800). + setTooltip ("Newly opened top-level windows will open with this width."). + setMin (80); + declareInt ("default-height", "Default window height", 600). + setTooltip ("Newly opened top-level windows will open with this height."). + setMin (80); + // reuse + // show-statusbar + declareInt ("max-subviews", "Maximum number of subviews per top-level window", 256). + setTooltip ("If the maximum number is reached and a new subview is opened " + "it will be placed into a new top-level window."). + setRange (1, 256); + // hide-subview + declareInt ("minimum-width", "Minimum subview width", 325). + setTooltip ("Minimum width of subviews."). + setRange (50, 10000); + // mainwindow-scrollbar + // grow-limit declareCategory ("Records"); @@ -39,14 +60,33 @@ void CSMPrefs::State::declare() declareCategory ("Reports"); declareCategory ("Search & Replace"); + declareInt ("char-before", "Characters before search string", 10). + setTooltip ("Maximum number of character to display in search result before the searched text"); + declareInt ("char-after", "Characters after search string", 10). + setTooltip ("Maximum number of character to display in search result after the searched text"); + // auto-delete declareCategory ("Scripts"); + // show-linenum + // mono-font + // warnings + // toolbar + declareInt ("compile-delay", "Delay between updating of source errors", 100). + setTooltip ("Delay in milliseconds"). + setRange (0, 10000); + declareInt ("error-height", "Initial height of the error panel", 100). + setRange (100, 10000); + // syntax-colouring declareCategory ("General Input"); declareCategory ("3D Scene Input"); declareCategory ("Tooltips"); + // scene + // scene-hide-basic + declareInt ("scene-delay", "Tooltip delay in milliseconds", 500). + setMin (1); } void CSMPrefs::State::declareCategory (const std::string& key) @@ -64,6 +104,37 @@ void CSMPrefs::State::declareCategory (const std::string& key) } } +CSMPrefs::IntSetting& CSMPrefs::State::declareInt (const std::string& key, + const std::string& label, int default_) +{ + if (mCurrentCategory==mCategories.end()) + throw std::logic_error ("no category for setting"); + + std::ostringstream stream; + stream << default_; + setDefault (key, stream.str()); + + default_ = mSettings.getInt (key, mCurrentCategory->second.getKey()); + + CSMPrefs::IntSetting *setting = + new CSMPrefs::IntSetting (&mCurrentCategory->second, &mSettings, key, label, default_); + + mCurrentCategory->second.addSetting (setting); + + return *setting; +} + +void CSMPrefs::State::setDefault (const std::string& key, const std::string& default_) +{ + Settings::CategorySetting fullKey (mCurrentCategory->second.getKey(), key); + + Settings::CategorySettingValueMap::iterator iter = + mSettings.mDefaultSettings.find (fullKey); + + if (iter==mSettings.mDefaultSettings.end()) + mSettings.mDefaultSettings.insert (std::make_pair (fullKey, default_)); +} + CSMPrefs::State::State (const Files::ConfigurationManager& configurationManager) : mConfigFile ("opencs.ini"), mConfigurationManager (configurationManager), mCurrentCategory (mCategories.end()) @@ -108,6 +179,11 @@ CSMPrefs::Category& CSMPrefs::State::getCategory (const std::string& key) return iter->second; } +void CSMPrefs::State::update (const Setting& setting) +{ + emit (settingChanged (setting)); +} + CSMPrefs::State& CSMPrefs::State::get() { if (!sThis) diff --git a/apps/opencs/model/prefs/state.hpp b/apps/opencs/model/prefs/state.hpp index a2e7aa038..c38f42049 100644 --- a/apps/opencs/model/prefs/state.hpp +++ b/apps/opencs/model/prefs/state.hpp @@ -13,9 +13,12 @@ #include #include "category.hpp" +#include "setting.hpp" namespace CSMPrefs { + class IntSetting; + class State : public QObject { Q_OBJECT @@ -47,6 +50,10 @@ namespace CSMPrefs void declareCategory (const std::string& key); + IntSetting& declareInt (const std::string& key, const std::string& label, int default_); + + void setDefault (const std::string& key, const std::string& default_); + public: State (const Files::ConfigurationManager& configurationManager); @@ -61,7 +68,13 @@ namespace CSMPrefs Category& getCategory (const std::string& key); + void update (const Setting& setting); + static State& get(); + + signals: + + void settingChanged (const Setting& setting); }; // convenience function diff --git a/apps/opencs/view/prefs/dialogue.cpp b/apps/opencs/view/prefs/dialogue.cpp index c4480fec4..6135afde7 100644 --- a/apps/opencs/view/prefs/dialogue.cpp +++ b/apps/opencs/view/prefs/dialogue.cpp @@ -10,7 +10,7 @@ #include "../../model/prefs/state.hpp" -#include "pagebase.hpp" +#include "page.hpp" void CSVPrefs::Dialogue::buildCategorySelector (QSplitter *main) { @@ -49,6 +49,13 @@ void CSVPrefs::Dialogue::buildContentArea (QSplitter *main) main->addWidget (mContent); } +CSVPrefs::PageBase *CSVPrefs::Dialogue::makePage (const std::string& key) +{ + // special case page code goes here + + return new Page (CSMPrefs::get().getCategory (key), mContent); +} + CSVPrefs::Dialogue::Dialogue() { setWindowTitle ("User Settings"); @@ -107,7 +114,7 @@ void CSVPrefs::Dialogue::selectionChanged (QListWidgetItem *current, QListWidget } } - PageBase *page = new PageBase (CSMPrefs::get().getCategory (key), mContent); + PageBase *page = makePage (key); mContent->setCurrentIndex (mContent->addWidget (page)); } } diff --git a/apps/opencs/view/prefs/dialogue.hpp b/apps/opencs/view/prefs/dialogue.hpp index 6bee54eb8..3965800db 100644 --- a/apps/opencs/view/prefs/dialogue.hpp +++ b/apps/opencs/view/prefs/dialogue.hpp @@ -10,6 +10,8 @@ class QListWidgetItem; namespace CSVPrefs { + class PageBase; + class Dialogue : public QMainWindow { Q_OBJECT @@ -23,6 +25,8 @@ namespace CSVPrefs void buildContentArea (QSplitter *main); + PageBase *makePage (const std::string& key); + public: Dialogue(); diff --git a/apps/opencs/view/prefs/page.cpp b/apps/opencs/view/prefs/page.cpp new file mode 100644 index 000000000..181ae40fa --- /dev/null +++ b/apps/opencs/view/prefs/page.cpp @@ -0,0 +1,40 @@ + +#include "page.hpp" + +#include + +#include "../../model/prefs/setting.hpp" +#include "../../model/prefs/category.hpp" + +CSVPrefs::Page::Page (CSMPrefs::Category& category, QWidget *parent) +: PageBase (category, parent) +{ + QWidget *widget = new QWidget (parent); + mGrid = new QGridLayout (widget); + + for (CSMPrefs::Category::Iterator iter = category.begin(); iter!=category.end(); ++iter) + addSetting (*iter); + + setWidget (widget); +} + +void CSVPrefs::Page::addSetting (CSMPrefs::Setting *setting) +{ + std::pair widgets = setting->makeWidgets (this); + + int next = mGrid->rowCount(); + + if (widgets.first) + { + mGrid->addWidget (widgets.first, next, 0); + mGrid->addWidget (widgets.second, next, 1); + } + else if (widgets.second) + { + mGrid->addWidget (widgets.second, next, 0, next, 1); + } + else + { + mGrid->addWidget (new QWidget (this), next, 0); + } +} diff --git a/apps/opencs/view/prefs/page.hpp b/apps/opencs/view/prefs/page.hpp new file mode 100644 index 000000000..ce13e5d9b --- /dev/null +++ b/apps/opencs/view/prefs/page.hpp @@ -0,0 +1,29 @@ +#ifndef CSV_PREFS_PAGE_H +#define CSV_PREFS_PAGE_H + +#include "pagebase.hpp" + +class QGridLayout; + +namespace CSMPrefs +{ + class Setting; +} + +namespace CSVPrefs +{ + class Page : public PageBase + { + Q_OBJECT + + QGridLayout *mGrid; + + public: + + Page (CSMPrefs::Category& category, QWidget *parent); + + void addSetting (CSMPrefs::Setting *setting); + }; +} + +#endif diff --git a/apps/opencs/view/prefs/pagebase.cpp b/apps/opencs/view/prefs/pagebase.cpp index 28c33a94a..16684a69d 100644 --- a/apps/opencs/view/prefs/pagebase.cpp +++ b/apps/opencs/view/prefs/pagebase.cpp @@ -1,17 +1,11 @@ #include "pagebase.hpp" -#include - #include "../../model/prefs/category.hpp" CSVPrefs::PageBase::PageBase (CSMPrefs::Category& category, QWidget *parent) : QScrollArea (parent), mCategory (category) -{ -QLabel *temp = new QLabel (category.getKey().c_str(), this); -setWidget (temp); - -} +{} CSMPrefs::Category& CSVPrefs::PageBase::getCategory() { From 1264651af73474a2da72a00c7e9e9553110efdd4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 8 Dec 2015 21:12:05 +0100 Subject: [PATCH 2752/3725] Fix coverity defects --- apps/openmw/mwphysics/physicssystem.cpp | 2 +- apps/openmw/mwsound/openal_output.cpp | 6 +++--- apps/openmw/mwsound/soundmanagerimp.cpp | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index db010d0fb..eebfddaab 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -709,7 +709,7 @@ namespace MWPhysics bool PhysicsSystem::isOnSolidGround (const MWWorld::Ptr& actor) const { const Actor* physactor = getActor(actor); - if (!physactor->getOnGround()) + if (!physactor || !physactor->getOnGround()) return false; CollisionMap::const_iterator found = mStandingCollisions.find(actor); diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index c2e808dee..02a9f33f9 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -363,9 +363,9 @@ OpenAL_SoundStream::OpenAL_SoundStream(ALuint src, DecoderPtr decoder) switch(type) { - case SampleType_UInt8: mSilence = 0x80; - case SampleType_Int16: mSilence = 0x00; - case SampleType_Float32: mSilence = 0x00; + case SampleType_UInt8: mSilence = 0x80; break; + case SampleType_Int16: mSilence = 0x00; break; + case SampleType_Float32: mSilence = 0x00; break; } mFrameSize = framesToBytes(1, chans, type); diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index a13acf3e2..d12174e20 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -48,9 +48,6 @@ namespace MWSound , mListenerUp(0,0,1) , mPausedSoundTypes(0) { - if(!useSound) - return; - mMasterVolume = Settings::Manager::getFloat("master volume", "Sound"); mMasterVolume = std::min(std::max(mMasterVolume, 0.0f), 1.0f); mSFXVolume = Settings::Manager::getFloat("sfx volume", "Sound"); @@ -67,6 +64,9 @@ namespace MWSound mBufferCacheMax *= 1024*1024; mBufferCacheMin = std::min(mBufferCacheMin*1024*1024, mBufferCacheMax); + if(!useSound) + return; + std::string hrtfname = Settings::Manager::getString("hrtf", "Sound"); int hrtfstate = Settings::Manager::getInt("hrtf enable", "Sound"); From 2f9b404094243c94465232e3932ac4b129953f21 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 8 Dec 2015 21:41:35 +0100 Subject: [PATCH 2753/3725] InstallationPage: properly exit the QThread (Fixes #2210) --- apps/wizard/installationpage.cpp | 7 +------ apps/wizard/unshield/unshieldworker.cpp | 2 -- apps/wizard/unshield/unshieldworker.hpp | 1 - 3 files changed, 1 insertion(+), 9 deletions(-) diff --git a/apps/wizard/installationpage.cpp b/apps/wizard/installationpage.cpp index dc2674680..2f0af88c9 100644 --- a/apps/wizard/installationpage.cpp +++ b/apps/wizard/installationpage.cpp @@ -28,12 +28,6 @@ Wizard::InstallationPage::InstallationPage(QWidget *parent) : connect(mUnshield, SIGNAL(finished()), mThread, SLOT(quit())); - connect(mUnshield, SIGNAL(finished()), - mUnshield, SLOT(deleteLater())); - - connect(mUnshield, SIGNAL(finished()), - mThread, SLOT(deleteLater()));; - connect(mUnshield, SIGNAL(finished()), this, SLOT(installationFinished()), Qt::QueuedConnection); @@ -60,6 +54,7 @@ Wizard::InstallationPage::~InstallationPage() { if (mThread->isRunning()) { mUnshield->stopWorker(); + mThread->quit(); mThread->wait(); } diff --git a/apps/wizard/unshield/unshieldworker.cpp b/apps/wizard/unshield/unshieldworker.cpp index 9daea2b71..c8f7ca677 100644 --- a/apps/wizard/unshield/unshieldworker.cpp +++ b/apps/wizard/unshield/unshieldworker.cpp @@ -45,9 +45,7 @@ Wizard::UnshieldWorker::~UnshieldWorker() void Wizard::UnshieldWorker::stopWorker() { - mMutex.lock(); mStopped = true; - mMutex.unlock(); } void Wizard::UnshieldWorker::setInstallComponent(Wizard::Component component, bool install) diff --git a/apps/wizard/unshield/unshieldworker.hpp b/apps/wizard/unshield/unshieldworker.hpp index c1d3cfff1..3f922ad78 100644 --- a/apps/wizard/unshield/unshieldworker.hpp +++ b/apps/wizard/unshield/unshieldworker.hpp @@ -104,7 +104,6 @@ namespace Wizard QTextCodec *mIniCodec; QWaitCondition mWait; - QMutex mMutex; QReadWriteLock mLock; From aa721fe1f662e9e9781b9522c26f2f4dd2994303 Mon Sep 17 00:00:00 2001 From: MatthewRock Date: Tue, 8 Dec 2015 22:38:26 +0100 Subject: [PATCH 2754/3725] Fix bug 2952 with merchant and levelled items --- AUTHORS.md | 1 + apps/openmw/mwworld/containerstore.cpp | 55 ++++++++++++++++++++------ components/esm/inventorystate.cpp | 17 ++++---- 3 files changed, 53 insertions(+), 20 deletions(-) diff --git a/AUTHORS.md b/AUTHORS.md index e968d1d01..077878ea2 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -74,6 +74,7 @@ Programmers Marco Melletti (mellotanica) Marco Schulze Mateusz Kołaczek (PL_kolek) + Mateusz Malisz (malice) megaton Michael Hogan (Xethik) Michael Mc Donnell diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 78a50b4e7..1130ec604 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -415,6 +415,7 @@ void MWWorld::ContainerStore::fill (const ESM::InventoryList& items, const std:: void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std::string& owner, int count, bool topLevel, const std::string& levItem) { + if (count == 0) return; //Don't restock with nothing. try { ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), id, count); @@ -463,8 +464,8 @@ void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std:: void MWWorld::ContainerStore::restock (const ESM::InventoryList& items, const MWWorld::Ptr& ptr, const std::string& owner) { - //allowedForReplace - Holds information about how many items from the list were sold; - // Hence, tells us how many items we need to restock. + //allowedForReplace - Holds information about how many items from the list were not sold; + // Hence, tells us how many items we don't need to restock. //allowedForReplace[list] <- How many items we should generate(how many of these were sold) std::map allowedForReplace; @@ -473,20 +474,42 @@ void MWWorld::ContainerStore::restock (const ESM::InventoryList& items, const MW { int spawnedCount = it->second.first; //How many items should be in shop originally int itemCount = count(it->first); //How many items are there in shop now - //If anything was sold - if(itemCount < spawnedCount) + //If something was not sold + if(itemCount >= spawnedCount) + { + const std::string& ancestor = it->second.second; + // Security check for old saves: + //If item is imported from old save(doesn't have an ancestor) and wasn't sold + if(ancestor == "") + { + //Remove it, from shop, + remove(it->first, itemCount, ptr);//ptr is the NPC + //And remove it from map, so that when we restock, the new item will have proper ancestor. + mLevelledItemMap.erase(it); + continue; + + } + //Create the entry if it does not exist yet + std::map::iterator listInMap = allowedForReplace.insert( + std::make_pair(it->second.second, 0)).first; + //And signal that we don't need to restock item from this list + listInMap->second += std::abs(itemCount); + } + //If every of the item was sold + else if (itemCount == 0) + { + mLevelledItemMap.erase(it); + } + //If some was sold, but some remain + else { //Create entry if it does not exist yet std::map::iterator listInMap = allowedForReplace.insert( std::make_pair(it->second.second, 0)).first; - //And signal that we need to restock item from this list - listInMap->second += std::abs(spawnedCount - itemCount); - //Also, remove the record if item no longer figures in the shop - if(!itemCount) - mLevelledItemMap.erase(it->first); - //If there's still item in the shop, change its spawnedCount to current count. - else - it->second.first -= itemCount; + //And signal that we don't need to restock all items from this list + listInMap->second += std::abs(itemCount); + //And update itemCount so we don't mistake it next time. + it->second.first = itemCount; } } @@ -504,8 +527,14 @@ void MWWorld::ContainerStore::restock (const ESM::InventoryList& items, const MW if (MWBase::Environment::get().getWorld()->getStore().get().search(it->mItem.toString())) { std::map::iterator listInMap = allowedForReplace.find(itemOrList); + + int restockNum = it-> mCount; + //If we know we must restock less, take it into account if(listInMap != allowedForReplace.end()) - addInitialItem(itemOrList, owner, listInMap->second, true); + restockNum += listInMap->second;//We add, because list items have negative count + //restock + addInitialItem(itemOrList, owner, restockNum, true); + } else { diff --git a/components/esm/inventorystate.cpp b/components/esm/inventorystate.cpp index 1864b6e8d..ad9e70af1 100644 --- a/components/esm/inventorystate.cpp +++ b/components/esm/inventorystate.cpp @@ -31,17 +31,20 @@ void ESM::InventoryState::load (ESMReader &esm) ++index; } - + //Next item is Levelled item while (esm.isNextSub("LEVM")) { + //Get its name std::string id = esm.getHString(); int count; - std::string parentList; - //TODO: How should I handle old saves? - if(esm.isNextSub("LLST")) - std::string parentList = esm.getHString(); + std::string parentGroup = ""; + //Then get its count esm.getHNT (count, "COUN"); - mLevelledItemMap[id] = count; + //Old save formats don't have information about parent group; check for that + if(esm.isNextSub("LGRP")) + //Newest saves contain parent group + parentGroup = esm.getHString(); + mLevelledItemMap[id] = std::make_pair(count, parentGroup); } while (esm.isNextSub("MAGI")) @@ -87,7 +90,7 @@ void ESM::InventoryState::save (ESMWriter &esm) const { esm.writeHNString ("LEVM", it->first); esm.writeHNT ("COUN", it->second.first); - esm.writeHNString("LLST", it->second.second) + esm.writeHNString("LGRP", it->second.second); } for (TEffectMagnitudes::const_iterator it = mPermanentMagicEffectMagnitudes.begin(); it != mPermanentMagicEffectMagnitudes.end(); ++it) From b0e6a525956cbac9420624b619f4446528392c66 Mon Sep 17 00:00:00 2001 From: MatthewRock Date: Tue, 8 Dec 2015 22:45:16 +0100 Subject: [PATCH 2755/3725] Replace ancestor with parent --- apps/openmw/mwworld/containerstore.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 1130ec604..99e051ea7 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -477,14 +477,14 @@ void MWWorld::ContainerStore::restock (const ESM::InventoryList& items, const MW //If something was not sold if(itemCount >= spawnedCount) { - const std::string& ancestor = it->second.second; + const std::string& parent = it->second.second; // Security check for old saves: - //If item is imported from old save(doesn't have an ancestor) and wasn't sold - if(ancestor == "") + //If item is imported from old save(doesn't have an parent) and wasn't sold + if(parent == "") { //Remove it, from shop, remove(it->first, itemCount, ptr);//ptr is the NPC - //And remove it from map, so that when we restock, the new item will have proper ancestor. + //And remove it from map, so that when we restock, the new item will have proper parent. mLevelledItemMap.erase(it); continue; From 39feb547a0892e27c256be1d7e20d67f14a6d266 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 8 Dec 2015 23:12:40 +0100 Subject: [PATCH 2756/3725] Broken lower casing fix (Fixes #3068) --- components/interpreter/defines.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/components/interpreter/defines.cpp b/components/interpreter/defines.cpp index 3812e63c5..2ceb857c4 100644 --- a/components/interpreter/defines.cpp +++ b/components/interpreter/defines.cpp @@ -35,8 +35,7 @@ namespace Interpreter{ if(text[i] == eschar) { retval << text.substr(start, i - start); - std::string temp = text.substr(i+1, 100); - Misc::StringUtils::lowerCase(temp); + std::string temp = Misc::StringUtils::lowerCase(text.substr(i+1, 100)); bool found = false; try From bc1f7499aba5d3793e5c09884a2572fd5aac604d Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 9 Dec 2015 00:26:39 +0100 Subject: [PATCH 2757/3725] Do not allow deleting the player object (Fixes #2982) --- apps/openmw/mwworld/worldimp.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 2436225b4..e8855fa5c 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1073,6 +1073,9 @@ namespace MWWorld { if (!ptr.getRefData().isDeleted() && ptr.getContainerStore() == NULL) { + if (ptr == getPlayerPtr()) + throw std::runtime_error("can not delete player object"); + ptr.getRefData().setCount(0); if (ptr.isInCell() From 34f48d63f388a52443d1ba0d02bb485a216c0481 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 9 Dec 2015 00:35:54 +0100 Subject: [PATCH 2758/3725] Apply spell absorption once per effect (Fixes #2942) --- apps/openmw/mwmechanics/spellcasting.cpp | 40 ++++++++++++------------ 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 2485091ea..a2d32b324 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -365,26 +365,6 @@ namespace MWMechanics bool castByPlayer = (!caster.isEmpty() && caster == getPlayer()); - // Try absorbing if it's a spell - // NOTE: Vanilla does this once per effect source instead of adding the % from all sources together, not sure - // if that is worth replicating. - bool absorbed = false; - if (spell && caster != target && target.getClass().isActor()) - { - float absorb = target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::SpellAbsorption).getMagnitude(); - absorbed = (Misc::Rng::roll0to99() < absorb); - if (absorbed) - { - const ESM::Static* absorbStatic = MWBase::Environment::get().getWorld()->getStore().get().find ("VFX_Absorb"); - MWBase::Environment::get().getWorld()->getAnimation(target)->addEffect( - "meshes\\" + absorbStatic->mModel, ESM::MagicEffect::SpellAbsorption, false, ""); - // Magicka is increased by cost of spell - DynamicStat magicka = target.getClass().getCreatureStats(target).getMagicka(); - magicka.setCurrent(magicka.getCurrent() + spell->mData.mCost); - target.getClass().getCreatureStats(target).setMagicka(magicka); - } - } - for (std::vector::const_iterator effectIt (effects.mList.begin()); effectIt!=effects.mList.end(); ++effectIt) { @@ -404,6 +384,26 @@ namespace MWMechanics && target.getClass().isActor()) MWBase::Environment::get().getWindowManager()->setEnemy(target); + // Try absorbing if it's a spell + // NOTE: Vanilla does this once per spell absorption effect source instead of adding the % from all sources together, not sure + // if that is worth replicating. + bool absorbed = false; + if (spell && caster != target && target.getClass().isActor()) + { + float absorb = target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::SpellAbsorption).getMagnitude(); + absorbed = (Misc::Rng::roll0to99() < absorb); + if (absorbed) + { + const ESM::Static* absorbStatic = MWBase::Environment::get().getWorld()->getStore().get().find ("VFX_Absorb"); + MWBase::Environment::get().getWorld()->getAnimation(target)->addEffect( + "meshes\\" + absorbStatic->mModel, ESM::MagicEffect::SpellAbsorption, false, ""); + // Magicka is increased by cost of spell + DynamicStat magicka = target.getClass().getCreatureStats(target).getMagicka(); + magicka.setCurrent(magicka.getCurrent() + spell->mData.mCost); + target.getClass().getCreatureStats(target).setMagicka(magicka); + } + } + float magnitudeMult = 1; if (magicEffect->mData.mFlags & ESM::MagicEffect::Harmful && target.getClass().isActor()) { From a699b4128aaaa54a72f43875b451b273c59788d5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 9 Dec 2015 00:48:51 +0100 Subject: [PATCH 2759/3725] Add isInCell checks to PlaceAt and PlaceItem (Fixes #2873) Avoids the game crashing when a script calls these functions before the player has been moved to the starting location. --- apps/openmw/mwscript/transformationextensions.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 592168687..474f2a392 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -458,6 +458,10 @@ namespace MWScript runtime.pop(); MWWorld::Ptr player = MWMechanics::getPlayer(); + + if (!player.isInCell()) + throw std::runtime_error("player not in a cell"); + MWWorld::CellStore* store = NULL; if (player.getCell()->isExterior()) { @@ -505,6 +509,9 @@ namespace MWScript if (count<0) throw std::runtime_error ("count must be non-negative"); + if (!actor.isInCell()) + throw std::runtime_error ("actor is not in a cell"); + for (int i=0; i Date: Wed, 9 Dec 2015 01:06:53 +0100 Subject: [PATCH 2760/3725] WindowManager: explicitely pass the ESMStore Fixes potential crash when the loading screen layout tries to retrieve a GMST value via #{GMST} syntax before the World has been created. Possibly related to Bug #2854. --- apps/openmw/engine.cpp | 1 + apps/openmw/mwgui/windowmanagerimp.cpp | 29 ++++++++++++++++---------- apps/openmw/mwgui/windowmanagerimp.hpp | 9 ++++++++ 3 files changed, 28 insertions(+), 11 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 66231dd98..6c360acf6 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -513,6 +513,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) mEnvironment.getWorld()->setupPlayer(); input->setPlayer(&mEnvironment.getWorld()->getPlayer()); + window->setStore(mEnvironment.getWorld()->getStore()); window->initUI(); window->renderWorldMap(); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 31522913e..f151bee80 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -117,7 +117,8 @@ namespace MWGui osgViewer::Viewer* viewer, osg::Group* guiRoot, Resource::ResourceSystem* resourceSystem , const std::string& logpath, const std::string& resourcePath, bool consoleOnlyScripts, Translation::Storage& translationDataStorage, ToUTF8::FromType encoding, bool exportFonts, const std::map& fallbackMap, const std::string& versionDescription) - : mResourceSystem(resourceSystem) + : mStore(NULL) + , mResourceSystem(resourceSystem) , mViewer(viewer) , mConsoleOnlyScripts(consoleOnlyScripts) , mCurrentModals() @@ -291,8 +292,7 @@ namespace MWGui bool questList = mResourceSystem->getVFS()->exists("textures/tx_menubook_options_over.dds"); mJournal = JournalWindow::create(JournalViewModel::create (), questList); - mMessageBoxManager = new MessageBoxManager( - MWBase::Environment::get().getWorld()->getStore().get().find("fMessageTimePerChar")->getFloat()); + mMessageBoxManager = new MessageBoxManager(mStore->get().find("fMessageTimePerChar")->getFloat()); mInventoryWindow = new InventoryWindow(mDragAndDrop, mViewer, mResourceSystem); mTradeWindow = new TradeWindow(); trackWindow(mTradeWindow, "barter"); @@ -461,6 +461,11 @@ namespace MWGui delete mGuiPlatform; } + void WindowManager::setStore(const MWWorld::ESMStore &store) + { + mStore = &store; + } + void WindowManager::cleanupGarbage() { // Delete any dialogs which are no longer in use @@ -908,8 +913,7 @@ namespace MWGui std::string WindowManager::getGameSettingString(const std::string &id, const std::string &default_) { - const ESM::GameSetting *setting = - MWBase::Environment::get().getWorld()->getStore().get().search(id); + const ESM::GameSetting *setting = mStore->get().search(id); if (setting && setting->mValue.getType()==ESM::VT_String) return setting->mValue.getString(); @@ -1139,8 +1143,12 @@ namespace MWGui } else { - const ESM::GameSetting *setting = - MWBase::Environment::get().getWorld()->getStore().get().find(tag); + if (!mStore) + { + std::cerr << "WindowManager::onRetrieveTag: no Store set up yet, can not replace '" << tag << "'" << std::endl; + return; + } + const ESM::GameSetting *setting = mStore->get().find(tag); if (setting && setting->mValue.getType()==ESM::VT_String) _result = setting->mValue.getString(); @@ -1263,8 +1271,7 @@ namespace MWGui mSelectedSpell = spellId; mHud->setSelectedSpell(spellId, successChancePercent); - const ESM::Spell* spell = - MWBase::Environment::get().getWorld()->getStore().get().find(spellId); + const ESM::Spell* spell = mStore->get().find(spellId); mSpellWindow->setTitle(spell->mName); } @@ -1272,7 +1279,7 @@ namespace MWGui void WindowManager::setSelectedEnchantItem(const MWWorld::Ptr& item) { mSelectedSpell = ""; - const ESM::Enchantment* ench = MWBase::Environment::get().getWorld()->getStore().get() + const ESM::Enchantment* ench = mStore->get() .find(item.getClass().getEnchantment(item)); int chargePercent = (item.getCellRef().getEnchantmentCharge() == -1) ? 100 @@ -1707,7 +1714,7 @@ namespace MWGui { reader.getSubNameIs("ID__"); std::string spell = reader.getHString(); - if (MWBase::Environment::get().getWorld()->getStore().get().search(spell)) + if (mStore->get().search(spell)) mSelectedSpell = spell; } else if (type == ESM::REC_MARK) diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 7df5508a1..6edb4660c 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -28,6 +28,11 @@ namespace MyGUI class ImageBox; } +namespace MWWorld +{ + class ESMStore; +} + namespace Compiler { class Extensions; @@ -119,6 +124,9 @@ namespace MWGui Translation::Storage& translationDataStorage, ToUTF8::FromType encoding, bool exportFonts, const std::map& fallbackMap, const std::string& versionDescription); virtual ~WindowManager(); + /// Set the ESMStore to use for retrieving of GUI-related strings. + void setStore (const MWWorld::ESMStore& store); + void initUI(); void renderWorldMap(); @@ -372,6 +380,7 @@ namespace MWGui void writeFog(MWWorld::CellStore* cell); private: + const MWWorld::ESMStore* mStore; Resource::ResourceSystem* mResourceSystem; osgMyGUI::Platform* mGuiPlatform; From 6f98982bc2365631682cbafcdedf2c28c1e17779 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 9 Dec 2015 01:52:20 +0100 Subject: [PATCH 2761/3725] Make sure that health is >= 1 when resurrecting the player (Fixes #2972) --- apps/openmw/mwmechanics/creaturestats.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/creaturestats.cpp b/apps/openmw/mwmechanics/creaturestats.cpp index 602e54a09..6933c40a3 100644 --- a/apps/openmw/mwmechanics/creaturestats.cpp +++ b/apps/openmw/mwmechanics/creaturestats.cpp @@ -267,9 +267,11 @@ namespace MWMechanics { if (mDead) { + if (mDynamic[0].getModified() < 1) + mDynamic[0].setModified(1, 0); + mDynamic[0].setCurrent(mDynamic[0].getModified()); - if (mDynamic[0].getCurrent()>=1) - mDead = false; + mDead = false; } } From de84452e5a2f1a51d5e08f9af65edcec80a9c995 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 9 Dec 2015 04:50:59 +0100 Subject: [PATCH 2762/3725] NifFile: close the stream after reading (Fixes #3070) --- components/nif/niffile.cpp | 8 +++----- components/nif/niffile.hpp | 4 +--- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index ccfcdfc73..f6e489527 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -12,9 +12,8 @@ NIFFile::NIFFile(Files::IStreamPtr stream, const std::string &name) : ver(0) , filename(name) , mUseSkinning(false) - , mStream(stream) { - parse(); + parse(stream); } NIFFile::~NIFFile() @@ -115,7 +114,6 @@ static std::map makeFactory() ///Make the factory map used for parsing the file static const std::map factories = makeFactory(); -/// Get the file's version in a human readable form std::string NIFFile::printVersion(unsigned int version) { union ver_quad @@ -134,9 +132,9 @@ std::string NIFFile::printVersion(unsigned int version) return stream.str(); } -void NIFFile::parse() +void NIFFile::parse(Files::IStreamPtr stream) { - NIFStream nif (this, mStream); + NIFStream nif (this, stream); // Check the header string std::string head = nif.getVersionString(); diff --git a/components/nif/niffile.hpp b/components/nif/niffile.hpp index 6fbef31ca..900c360bb 100644 --- a/components/nif/niffile.hpp +++ b/components/nif/niffile.hpp @@ -35,7 +35,7 @@ class NIFFile bool mUseSkinning; /// Parse the file - void parse(); + void parse(Files::IStreamPtr stream); /// Get the file's version in a human readable form ///\returns A string containing a human readable NIF version number @@ -46,8 +46,6 @@ class NIFFile ///\overload void operator = (NIFFile const &); - Files::IStreamPtr mStream; - public: /// Used if file parsing fails void fail(const std::string &msg) From d00d487c3d66ab96f5944112a3d1f882071e8f41 Mon Sep 17 00:00:00 2001 From: cfcohen Date: Mon, 7 Dec 2015 20:03:11 -0500 Subject: [PATCH 2763/3725] Improved error reporting under POSIX using errno and strerror(). --- components/files/lowlevelfile.cpp | 40 +++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/components/files/lowlevelfile.cpp b/components/files/lowlevelfile.cpp index 8456c7a26..169a6f813 100644 --- a/components/files/lowlevelfile.cpp +++ b/components/files/lowlevelfile.cpp @@ -8,6 +8,8 @@ #include #include #include +#include +#include #endif #if FILE_API == FILE_API_STDIO @@ -139,7 +141,7 @@ void LowLevelFile::open (char const * filename) if (mHandle == -1) { std::ostringstream os; - os << "Failed to open '" << filename << "' for reading."; + os << "Failed to open '" << filename << "' for reading: " << strerror(errno); throw std::runtime_error (os.str ()); } } @@ -160,15 +162,27 @@ size_t LowLevelFile::size () size_t oldPosition = ::lseek (mHandle, 0, SEEK_CUR); if (oldPosition == size_t (-1)) - throw std::runtime_error ("A query operation on a file failed."); + { + std::ostringstream os; + os << "An lseek() call failed:" << strerror(errno); + throw std::runtime_error (os.str ()); + } size_t Size = ::lseek (mHandle, 0, SEEK_END); if (Size == size_t (-1)) - throw std::runtime_error ("A query operation on a file failed."); + { + std::ostringstream os; + os << "An lseek() call failed:" << strerror(errno); + throw std::runtime_error (os.str ()); + } if (lseek (mHandle, oldPosition, SEEK_SET) == -1) - throw std::runtime_error ("A query operation on a file failed."); + { + std::ostringstream os; + os << "An lseek() call failed:" << strerror(errno); + throw std::runtime_error (os.str ()); + } return Size; } @@ -178,7 +192,11 @@ void LowLevelFile::seek (size_t Position) assert (mHandle != -1); if (::lseek (mHandle, Position, SEEK_SET) == -1) - throw std::runtime_error ("A seek operation on a file failed."); + { + std::ostringstream os; + os << "An lseek() call failed:" << strerror(errno); + throw std::runtime_error (os.str ()); + } } size_t LowLevelFile::tell () @@ -188,7 +206,11 @@ size_t LowLevelFile::tell () size_t Position = ::lseek (mHandle, 0, SEEK_CUR); if (Position == size_t (-1)) - throw std::runtime_error ("A query operation on a file failed."); + { + std::ostringstream os; + os << "An lseek() call failed:" << strerror(errno); + throw std::runtime_error (os.str ()); + } return Position; } @@ -200,7 +222,11 @@ size_t LowLevelFile::read (void * data, size_t size) int amount = ::read (mHandle, data, size); if (amount == -1) - throw std::runtime_error ("A read operation on a file failed."); + { + std::ostringstream os; + os << "An attempt to read " << size << "bytes failed:" << strerror(errno); + throw std::runtime_error (os.str ()); + } return amount; } From a8c287c8314e79b5628066dd975d22dae9095f07 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 9 Dec 2015 14:33:02 +0100 Subject: [PATCH 2764/3725] Print detected game controllers to the log file --- apps/openmw/mwinput/inputmanagerimp.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 0d1dc0e62..71938dfb0 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -119,10 +119,11 @@ namespace MWInput SDL_ControllerDeviceEvent evt; evt.which = i; controllerAdded(mFakeDeviceID, evt); + std::cout << "Detected game controller: " << SDL_GameControllerNameForIndex(i) << std::endl; } else { - //ICS_LOG(std::string("Unusable controller plugged in: ")+SDL_JoystickNameForIndex(i)); + std::cout << "Detected unusable controller: " << SDL_JoystickNameForIndex(i) << std::endl; } } From 3b254ad6319a6687dcbf3b7e4f10679a7cceb259 Mon Sep 17 00:00:00 2001 From: MatthewRock Date: Wed, 9 Dec 2015 18:24:35 +0100 Subject: [PATCH 2765/3725] Allows the same item to have multiple ancestors --- apps/openmw/mwworld/containerstore.cpp | 34 +++++++++++++------------- apps/openmw/mwworld/containerstore.hpp | 4 +-- components/esm/inventorystate.cpp | 10 ++++---- components/esm/inventorystate.hpp | 2 +- 4 files changed, 25 insertions(+), 25 deletions(-) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 99e051ea7..5844cfa9a 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -444,12 +444,12 @@ void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std:: if (!levItem.empty() && count < 0) { //If there is no item in map, insert it - std::map >::iterator itemInMap = - mLevelledItemMap.insert(std::make_pair(id, std::make_pair(0, levItem))).first; + std::map, int>::iterator itemInMap = + mLevelledItemMap.insert(std::make_pair(std::make_pair(id, levItem), 0)).first; //Update spawned count - itemInMap->second.first += std::abs(count); + itemInMap->second += std::abs(count); } - count = std::abs(count); + count = std::abs(count); ref.getPtr().getCellRef().setOwner(owner); addImp (ref.getPtr(), count); @@ -470,47 +470,48 @@ void MWWorld::ContainerStore::restock (const ESM::InventoryList& items, const MW std::map allowedForReplace; //Check which lists need restocking: - for (std::map >::iterator it = mLevelledItemMap.begin(); it != mLevelledItemMap.end(); ++it) + for (std::map, int>::iterator it = mLevelledItemMap.begin(); it != mLevelledItemMap.end();) { - int spawnedCount = it->second.first; //How many items should be in shop originally - int itemCount = count(it->first); //How many items are there in shop now + int spawnedCount = it->second; //How many items should be in shop originally + int itemCount = count(it->first.first); //How many items are there in shop now //If something was not sold if(itemCount >= spawnedCount) { - const std::string& parent = it->second.second; + const std::string& parent = it->first.second; // Security check for old saves: //If item is imported from old save(doesn't have an parent) and wasn't sold if(parent == "") { //Remove it, from shop, - remove(it->first, itemCount, ptr);//ptr is the NPC + remove(it->first.first, itemCount, ptr);//ptr is the NPC //And remove it from map, so that when we restock, the new item will have proper parent. - mLevelledItemMap.erase(it); + mLevelledItemMap.erase(it++); continue; - } //Create the entry if it does not exist yet std::map::iterator listInMap = allowedForReplace.insert( - std::make_pair(it->second.second, 0)).first; + std::make_pair(it->first.second, 0)).first; //And signal that we don't need to restock item from this list listInMap->second += std::abs(itemCount); } //If every of the item was sold else if (itemCount == 0) { - mLevelledItemMap.erase(it); + mLevelledItemMap.erase(it++); + continue; } //If some was sold, but some remain else { //Create entry if it does not exist yet std::map::iterator listInMap = allowedForReplace.insert( - std::make_pair(it->second.second, 0)).first; + std::make_pair(it->first.second, 0)).first; //And signal that we don't need to restock all items from this list listInMap->second += std::abs(itemCount); //And update itemCount so we don't mistake it next time. - it->second.first = itemCount; + it->second = itemCount; } + ++it; } //Restock: @@ -528,13 +529,12 @@ void MWWorld::ContainerStore::restock (const ESM::InventoryList& items, const MW { std::map::iterator listInMap = allowedForReplace.find(itemOrList); - int restockNum = it-> mCount; + int restockNum = it->mCount; //If we know we must restock less, take it into account if(listInMap != allowedForReplace.end()) restockNum += listInMap->second;//We add, because list items have negative count //restock addInitialItem(itemOrList, owner, restockNum, true); - } else { diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index aaf83755a..876821f94 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -69,8 +69,8 @@ namespace MWWorld MWWorld::CellRefList repairs; MWWorld::CellRefList weapons; - std::map > mLevelledItemMap; - ///< Stores result of levelled item spawns. + std::map, int> mLevelledItemMap; + ///< Stores result of levelled item spawns. <(refId, spawningGroup), count> /// This is used to restock levelled items(s) if the old item was sold. mutable float mCachedWeight; diff --git a/components/esm/inventorystate.cpp b/components/esm/inventorystate.cpp index ad9e70af1..b24128ec3 100644 --- a/components/esm/inventorystate.cpp +++ b/components/esm/inventorystate.cpp @@ -44,7 +44,7 @@ void ESM::InventoryState::load (ESMReader &esm) if(esm.isNextSub("LGRP")) //Newest saves contain parent group parentGroup = esm.getHString(); - mLevelledItemMap[id] = std::make_pair(count, parentGroup); + mLevelledItemMap[std::make_pair(id, parentGroup)] = count; } while (esm.isNextSub("MAGI")) @@ -86,11 +86,11 @@ void ESM::InventoryState::save (ESMWriter &esm) const iter->save (esm, true); } - for (std::map >::const_iterator it = mLevelledItemMap.begin(); it != mLevelledItemMap.end(); ++it) + for (std::map, int>::const_iterator it = mLevelledItemMap.begin(); it != mLevelledItemMap.end(); ++it) { - esm.writeHNString ("LEVM", it->first); - esm.writeHNT ("COUN", it->second.first); - esm.writeHNString("LGRP", it->second.second); + esm.writeHNString ("LEVM", it->first.first); + esm.writeHNT ("COUN", it->second); + esm.writeHNString("LGRP", it->first.second); } for (TEffectMagnitudes::const_iterator it = mPermanentMagicEffectMagnitudes.begin(); it != mPermanentMagicEffectMagnitudes.end(); ++it) diff --git a/components/esm/inventorystate.hpp b/components/esm/inventorystate.hpp index a12be321f..f4bb0ab48 100644 --- a/components/esm/inventorystate.hpp +++ b/components/esm/inventorystate.hpp @@ -20,7 +20,7 @@ namespace ESM // std::map mEquipmentSlots; - std::map > mLevelledItemMap; + std::map, int> mLevelledItemMap; typedef std::map > > TEffectMagnitudes; TEffectMagnitudes mPermanentMagicEffectMagnitudes; From ddd4004c959252871aa5b0e8487322c2c25406ff Mon Sep 17 00:00:00 2001 From: MatthewRock Date: Wed, 9 Dec 2015 18:26:33 +0100 Subject: [PATCH 2766/3725] Fix: remove space --- apps/openmw/mwworld/containerstore.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 5844cfa9a..b45e7ef83 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -449,7 +449,7 @@ void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std:: //Update spawned count itemInMap->second += std::abs(count); } - count = std::abs(count); + count = std::abs(count); ref.getPtr().getCellRef().setOwner(owner); addImp (ref.getPtr(), count); From 9bc6f2d5f65866095e690332dacc8b7e56baf345 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 9 Dec 2015 20:35:51 +0100 Subject: [PATCH 2767/3725] Fix water ripples --- apps/openmw/mwrender/ripplesimulation.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/ripplesimulation.cpp b/apps/openmw/mwrender/ripplesimulation.cpp index 766e20fc4..7439bfc70 100644 --- a/apps/openmw/mwrender/ripplesimulation.cpp +++ b/apps/openmw/mwrender/ripplesimulation.cpp @@ -127,7 +127,6 @@ void RippleSimulation::update(float dt) } osg::Vec3f currentPos (it->mPtr.getRefData().getPosition().asVec3()); - currentPos.z() = 0; // Z is set by the Scene Node if ( (currentPos - it->mLastEmitPosition).length() > 10 // Only emit when close to the water surface, not above it and not too deep in the water @@ -136,6 +135,8 @@ void RippleSimulation::update(float dt) { it->mLastEmitPosition = currentPos; + currentPos.z() = mParticleNode->getPosition().z(); + if (mParticleSystem->numParticles()-mParticleSystem->numDeadParticles() > 500) continue; // TODO: remove the oldest particle to make room? From 293f3f30b55fd0fae690887c05e9d577a869e628 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 9 Dec 2015 23:30:24 +0100 Subject: [PATCH 2768/3725] Indentation fix --- components/sdlutil/sdlcursormanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/sdlutil/sdlcursormanager.cpp b/components/sdlutil/sdlcursormanager.cpp index 0eb161a64..26b0510dc 100644 --- a/components/sdlutil/sdlcursormanager.cpp +++ b/components/sdlutil/sdlcursormanager.cpp @@ -218,7 +218,7 @@ namespace SDLUtil void SDLCursorManager::_createCursorFromResource(const std::string& name, int rotDegrees, osg::Image* image, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y) { #ifdef ANDROID - return; + return; #endif if (mCursorMap.find(name) != mCursorMap.end()) From eb92b853fed11e93b4f954ce58bab793e8ade85a Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 10 Dec 2015 00:05:35 +0100 Subject: [PATCH 2769/3725] BulletNifLoader: preallocate the btTriangleMesh's vertices/indices --- components/nifbullet/bulletnifloader.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/components/nifbullet/bulletnifloader.cpp b/components/nifbullet/bulletnifloader.cpp index 0b8e9c163..19afe49d6 100644 --- a/components/nifbullet/bulletnifloader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -319,6 +319,9 @@ void BulletNifLoader::handleNiTriShape(const Nif::NiTriShape *shape, int flags, const osg::Vec3Array& vertices = *data->vertices; const osg::DrawElementsUShort& triangles = *data->triangles; + mStaticMesh->preallocateVertices(data->vertices->size()); + mStaticMesh->preallocateIndices(data->triangles->size()); + size_t numtris = data->triangles->size(); for(size_t i = 0;i < numtris;i+=3) { From 0efce6cd4ccb519ae563e0f6229f7f5c07eaf4d1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 10 Dec 2015 00:15:55 +0100 Subject: [PATCH 2770/3725] Fix typo in a comment --- components/to_utf8/to_utf8.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/components/to_utf8/to_utf8.cpp b/components/to_utf8/to_utf8.cpp index d7f9c3a38..8af0bc5ed 100644 --- a/components/to_utf8/to_utf8.cpp +++ b/components/to_utf8/to_utf8.cpp @@ -85,10 +85,10 @@ std::string Utf8Encoder::getUtf8(const char* input, size_t size) assert(input[size] == 0); // Note: The rest of this function is designed for single-character - // input encodings only. It also assumes that the input the input - // encoding shares its first 128 values (0-127) with ASCII. There are - // no plans to add more encodings to this module (we are using utf8 - // for new content files), so that shouldn't be an issue. + // input encodings only. It also assumes that the input encoding + // shares its first 128 values (0-127) with ASCII. There are no plans + // to add more encodings to this module (we are using utf8 for new + // content files), so that shouldn't be an issue. // Compute output length, and check for pure ascii input at the same // time. From 9ca5a1b64735fd3395fe548610b5d45abfcd8b04 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 10 Dec 2015 10:58:38 +0100 Subject: [PATCH 2771/3725] added double settings --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/prefs/doublesetting.cpp | 69 +++++++++++++++++++++++ apps/opencs/model/prefs/doublesetting.hpp | 39 +++++++++++++ apps/opencs/model/prefs/state.cpp | 36 ++++++++++++ apps/opencs/model/prefs/state.hpp | 2 + 5 files changed, 147 insertions(+), 1 deletion(-) create mode 100644 apps/opencs/model/prefs/doublesetting.cpp create mode 100644 apps/opencs/model/prefs/doublesetting.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 003fd657b..2fce48fd5 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -138,7 +138,7 @@ opencs_hdrs_noqt (model/settings ) opencs_units (model/prefs - state setting intsetting + state setting intsetting doublesetting ) opencs_units_noqt (model/prefs diff --git a/apps/opencs/model/prefs/doublesetting.cpp b/apps/opencs/model/prefs/doublesetting.cpp new file mode 100644 index 000000000..2eabc78bf --- /dev/null +++ b/apps/opencs/model/prefs/doublesetting.cpp @@ -0,0 +1,69 @@ + +#include "doublesetting.hpp" + +#include + +#include +#include + +#include + +#include "category.hpp" +#include "state.hpp" + +CSMPrefs::DoubleSetting::DoubleSetting (Category *parent, Settings::Manager *values, + const std::string& key, const std::string& label, double default_) +: Setting (parent, values, key, label), mMin (0), mMax (std::numeric_limits::max()), + mDefault (default_) +{} + +CSMPrefs::DoubleSetting& CSMPrefs::DoubleSetting::setRange (double min, double max) +{ + mMin = min; + mMax = max; + return *this; +} + +CSMPrefs::DoubleSetting& CSMPrefs::DoubleSetting::setMin (double min) +{ + mMin = min; + return *this; +} + +CSMPrefs::DoubleSetting& CSMPrefs::DoubleSetting::setMax (double max) +{ + mMax = max; + return *this; +} + +CSMPrefs::DoubleSetting& CSMPrefs::DoubleSetting::setTooltip (const std::string& tooltip) +{ + mTooltip = tooltip; + return *this; +} + +std::pair CSMPrefs::DoubleSetting::makeWidgets (QWidget *parent) +{ + QLabel *label = new QLabel (QString::fromUtf8 (getLabel().c_str()), parent); + + QDoubleSpinBox *widget = new QDoubleSpinBox (parent); + widget->setRange (mMin, mMax); + widget->setValue (mDefault); + + if (!mTooltip.empty()) + { + QString tooltip = QString::fromUtf8 (mTooltip.c_str()); + label->setToolTip (tooltip); + widget->setToolTip (tooltip); + } + + connect (widget, SIGNAL (valueChanged (double)), this, SLOT (valueChanged (double))); + + return std::make_pair (label, widget); +} + +void CSMPrefs::DoubleSetting::valueChanged (double value) +{ + getValues().setFloat (getKey(), getParent()->getKey(), value); + getParent()->getState()->update (*this); +} diff --git a/apps/opencs/model/prefs/doublesetting.hpp b/apps/opencs/model/prefs/doublesetting.hpp new file mode 100644 index 000000000..ef432aeb7 --- /dev/null +++ b/apps/opencs/model/prefs/doublesetting.hpp @@ -0,0 +1,39 @@ +#ifndef CSM_PREFS_DOUBLESETTING_H +#define CSM_PREFS_DOUBLESETTING_H + +#include "setting.hpp" + +namespace CSMPrefs +{ + class DoubleSetting : public Setting + { + Q_OBJECT + + double mMin; + double mMax; + std::string mTooltip; + double mDefault; + + public: + + DoubleSetting (Category *parent, Settings::Manager *values, + const std::string& key, const std::string& label, double default_); + + DoubleSetting& setRange (double min, double max); + + DoubleSetting& setMin (double min); + + DoubleSetting& setMax (double max); + + DoubleSetting& setTooltip (const std::string& tooltip); + + /// Return label, input widget. + virtual std::pair makeWidgets (QWidget *parent); + + private slots: + + void valueChanged (double value); + }; +} + +#endif diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index dfc460528..6ade42546 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -6,6 +6,7 @@ #include #include "intsetting.hpp" +#include "doublesetting.hpp" CSMPrefs::State *CSMPrefs::State::sThis = 0; @@ -81,6 +82,21 @@ void CSMPrefs::State::declare() declareCategory ("General Input"); declareCategory ("3D Scene Input"); + // p-navi + // s-navi + // p-edit + // s-edit + // p-select + // s-select + // context-select + declareDouble ("drag-factor", "Mouse sensitivity during drag operations", 1.0). + setRange (0.001, 100.0); + declareDouble ("drag-wheel-factor", "Mouse wheel sensitivity during drag operations", 1.0). + setRange (0.001, 100.0); + declareDouble ("drag-shift-factor", + "Shift-acceleration factor during drag operations", 4.0). + setTooltip ("Acceleration factor during drag operations while holding down shift"). + setRange (0.001, 100.0); declareCategory ("Tooltips"); // scene @@ -124,6 +140,26 @@ CSMPrefs::IntSetting& CSMPrefs::State::declareInt (const std::string& key, return *setting; } +CSMPrefs::DoubleSetting& CSMPrefs::State::declareDouble (const std::string& key, + const std::string& label, double default_) +{ + if (mCurrentCategory==mCategories.end()) + throw std::logic_error ("no category for setting"); + + std::ostringstream stream; + stream << default_; + setDefault (key, stream.str()); + + default_ = mSettings.getFloat (key, mCurrentCategory->second.getKey()); + + CSMPrefs::DoubleSetting *setting = + new CSMPrefs::DoubleSetting (&mCurrentCategory->second, &mSettings, key, label, default_); + + mCurrentCategory->second.addSetting (setting); + + return *setting; +} + void CSMPrefs::State::setDefault (const std::string& key, const std::string& default_) { Settings::CategorySetting fullKey (mCurrentCategory->second.getKey(), key); diff --git a/apps/opencs/model/prefs/state.hpp b/apps/opencs/model/prefs/state.hpp index c38f42049..816f383ff 100644 --- a/apps/opencs/model/prefs/state.hpp +++ b/apps/opencs/model/prefs/state.hpp @@ -18,6 +18,7 @@ namespace CSMPrefs { class IntSetting; + class DoubleSetting; class State : public QObject { @@ -51,6 +52,7 @@ namespace CSMPrefs void declareCategory (const std::string& key); IntSetting& declareInt (const std::string& key, const std::string& label, int default_); + DoubleSetting& declareDouble (const std::string& key, const std::string& label, double default_); void setDefault (const std::string& key, const std::string& default_); From b0fb6d56f12981895671f28fc255f8ca9c606018 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 10 Dec 2015 13:28:48 +0100 Subject: [PATCH 2772/3725] added bool settings --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/prefs/boolsetting.cpp | 42 +++++++++++++++ apps/opencs/model/prefs/boolsetting.hpp | 31 +++++++++++ apps/opencs/model/prefs/state.cpp | 69 +++++++++++++++++++++---- apps/opencs/model/prefs/state.hpp | 3 ++ apps/opencs/view/prefs/page.cpp | 2 +- 6 files changed, 136 insertions(+), 13 deletions(-) create mode 100644 apps/opencs/model/prefs/boolsetting.cpp create mode 100644 apps/opencs/model/prefs/boolsetting.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 2fce48fd5..e2f9205ea 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -138,7 +138,7 @@ opencs_hdrs_noqt (model/settings ) opencs_units (model/prefs - state setting intsetting doublesetting + state setting intsetting doublesetting boolsetting ) opencs_units_noqt (model/prefs diff --git a/apps/opencs/model/prefs/boolsetting.cpp b/apps/opencs/model/prefs/boolsetting.cpp new file mode 100644 index 000000000..459993325 --- /dev/null +++ b/apps/opencs/model/prefs/boolsetting.cpp @@ -0,0 +1,42 @@ + +#include "boolsetting.hpp" + +#include + +#include + +#include "category.hpp" +#include "state.hpp" + +CSMPrefs::BoolSetting::BoolSetting (Category *parent, Settings::Manager *values, + const std::string& key, const std::string& label, bool default_) +: Setting (parent, values, key, label), mDefault (default_) +{} + +CSMPrefs::BoolSetting& CSMPrefs::BoolSetting::setTooltip (const std::string& tooltip) +{ + mTooltip = tooltip; + return *this; +} + +std::pair CSMPrefs::BoolSetting::makeWidgets (QWidget *parent) +{ + QCheckBox *widget = new QCheckBox (QString::fromUtf8 (getLabel().c_str()), parent); + widget->setCheckState (mDefault ? Qt::Checked : Qt::Unchecked); + + if (!mTooltip.empty()) + { + QString tooltip = QString::fromUtf8 (mTooltip.c_str()); + widget->setToolTip (tooltip); + } + + connect (widget, SIGNAL (stateChanged (int)), this, SLOT (valueChanged (int))); + + return std::make_pair (static_cast (0), widget); +} + +void CSMPrefs::BoolSetting::valueChanged (int value) +{ + getValues().setBool (getKey(), getParent()->getKey(), value); + getParent()->getState()->update (*this); +} diff --git a/apps/opencs/model/prefs/boolsetting.hpp b/apps/opencs/model/prefs/boolsetting.hpp new file mode 100644 index 000000000..dfc28c5ae --- /dev/null +++ b/apps/opencs/model/prefs/boolsetting.hpp @@ -0,0 +1,31 @@ +#ifndef CSM_PREFS_BOOLSETTING_H +#define CSM_PREFS_BOOLSETTING_H + +#include "setting.hpp" + +namespace CSMPrefs +{ + class BoolSetting : public Setting + { + Q_OBJECT + + std::string mTooltip; + bool mDefault; + + public: + + BoolSetting (Category *parent, Settings::Manager *values, + const std::string& key, const std::string& label, bool default_); + + BoolSetting& setTooltip (const std::string& tooltip); + + /// Return label, input widget. + virtual std::pair makeWidgets (QWidget *parent); + + private slots: + + void valueChanged (int value); + }; +} + +#endif diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index 6ade42546..cf58edce9 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -7,6 +7,7 @@ #include "intsetting.hpp" #include "doublesetting.hpp" +#include "boolsetting.hpp" CSMPrefs::State *CSMPrefs::State::sThis = 0; @@ -39,24 +40,47 @@ void CSMPrefs::State::declare() declareInt ("default-height", "Default window height", 600). setTooltip ("Newly opened top-level windows will open with this height."). setMin (80); - // reuse - // show-statusbar + declareBool ("reuse", "Reuse Subviews", true). + setTooltip ("When a new subview is requested and a matching subview already " + " exist, do not open a new subview and use the existing one instead."); + declareBool ("show-statusbar", "Show Status Bar", true). + setTooltip ("If a newly open top level window is showing status bars or not. " + " Note that this does not affect existing windows."); declareInt ("max-subviews", "Maximum number of subviews per top-level window", 256). setTooltip ("If the maximum number is reached and a new subview is opened " "it will be placed into a new top-level window."). setRange (1, 256); - // hide-subview + declareBool ("hide-subview", "Hide single subview", false). + setTooltip ("When a view contains only a single subview, hide the subview title " + "bar and if this subview is closed also close the view (unless it is the last " + "view for this document)"); declareInt ("minimum-width", "Minimum subview width", 325). setTooltip ("Minimum width of subviews."). setRange (50, 10000); // mainwindow-scrollbar - // grow-limit + declareBool ("grow-limit", "Grow Limit Screen", false). + setTooltip ("When \"Grow then Scroll\" option is selected, the window size grows to" + " the width of the virtual desktop. \nIf this option is selected the the window growth" + "is limited to the current screen."); declareCategory ("Records"); declareCategory ("ID Tables"); + // double + // double-s + // double-c + // double-sc + // jump-to-added + declareBool ("extended-config", + "Manually specify affected record types for an extended delete/revert", false). + setTooltip ("Delete and revert commands have an extended form that also affects " + "associated records.\n\n" + "If this option is enabled, types of affected records are selected " + "manually before a command execution.\nOtherwise, all associated " + "records are deleted/reverted immediately."); declareCategory ("ID Dialogues"); + declareBool ("toolbar", "Show toolbar", true); declareCategory ("Reports"); @@ -65,13 +89,15 @@ void CSMPrefs::State::declare() setTooltip ("Maximum number of character to display in search result before the searched text"); declareInt ("char-after", "Characters after search string", 10). setTooltip ("Maximum number of character to display in search result after the searched text"); - // auto-delete + declareBool ("auto-delete", "Delete row from result table after a successful replace", true); declareCategory ("Scripts"); - // show-linenum - // mono-font + declareBool ("show-linenum", "Show Line Numbers", true). + setTooltip ("Show line numbers to the left of the script editor window." + "The current row and column numbers of the text cursor are shown at the bottom."); + declareBool ("mono-font", "Use monospace font", true); // warnings - // toolbar + declareBool ("toolbar", "Show toolbar", true); declareInt ("compile-delay", "Delay between updating of source errors", 100). setTooltip ("Delay in milliseconds"). setRange (0, 10000); @@ -80,6 +106,9 @@ void CSMPrefs::State::declare() // syntax-colouring declareCategory ("General Input"); + declareBool ("cycle", "Cyclic next/previous", false). + setTooltip ("When using next/previous functions at the last/first item of a " + "list go to the first/last item"); declareCategory ("3D Scene Input"); // p-navi @@ -88,7 +117,7 @@ void CSMPrefs::State::declare() // s-edit // p-select // s-select - // context-select + declareBool ("context-select", "Context Sensitive Selection", false); declareDouble ("drag-factor", "Mouse sensitivity during drag operations", 1.0). setRange (0.001, 100.0); declareDouble ("drag-wheel-factor", "Mouse wheel sensitivity during drag operations", 1.0). @@ -99,8 +128,8 @@ void CSMPrefs::State::declare() setRange (0.001, 100.0); declareCategory ("Tooltips"); - // scene - // scene-hide-basic + declareBool ("scene", "Show Tooltips in 3D scenes", true); + declareBool ("scene-hide-basic", "Hide basic 3D scenes tooltips", false); declareInt ("scene-delay", "Tooltip delay in milliseconds", 500). setMin (1); } @@ -160,6 +189,24 @@ CSMPrefs::DoubleSetting& CSMPrefs::State::declareDouble (const std::string& key, return *setting; } +CSMPrefs::BoolSetting& CSMPrefs::State::declareBool (const std::string& key, + const std::string& label, bool default_) +{ + if (mCurrentCategory==mCategories.end()) + throw std::logic_error ("no category for setting"); + + setDefault (key, default_ ? "true" : "false"); + + default_ = mSettings.getBool (key, mCurrentCategory->second.getKey()); + + CSMPrefs::BoolSetting *setting = + new CSMPrefs::BoolSetting (&mCurrentCategory->second, &mSettings, key, label, default_); + + mCurrentCategory->second.addSetting (setting); + + return *setting; +} + void CSMPrefs::State::setDefault (const std::string& key, const std::string& default_) { Settings::CategorySetting fullKey (mCurrentCategory->second.getKey(), key); diff --git a/apps/opencs/model/prefs/state.hpp b/apps/opencs/model/prefs/state.hpp index 816f383ff..28bafd6a1 100644 --- a/apps/opencs/model/prefs/state.hpp +++ b/apps/opencs/model/prefs/state.hpp @@ -19,6 +19,7 @@ namespace CSMPrefs { class IntSetting; class DoubleSetting; + class BoolSetting; class State : public QObject { @@ -54,6 +55,8 @@ namespace CSMPrefs IntSetting& declareInt (const std::string& key, const std::string& label, int default_); DoubleSetting& declareDouble (const std::string& key, const std::string& label, double default_); + BoolSetting& declareBool (const std::string& key, const std::string& label, bool default_); + void setDefault (const std::string& key, const std::string& default_); public: diff --git a/apps/opencs/view/prefs/page.cpp b/apps/opencs/view/prefs/page.cpp index 181ae40fa..c23e9f64f 100644 --- a/apps/opencs/view/prefs/page.cpp +++ b/apps/opencs/view/prefs/page.cpp @@ -31,7 +31,7 @@ void CSVPrefs::Page::addSetting (CSMPrefs::Setting *setting) } else if (widgets.second) { - mGrid->addWidget (widgets.second, next, 0, next, 1); + mGrid->addWidget (widgets.second, next, 0, 1, 2); } else { From 8050eba83b3c4a549c6b5223690c8fe08ec14136 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 10 Dec 2015 13:33:44 +0100 Subject: [PATCH 2773/3725] added a few comments --- apps/opencs/model/prefs/doublesetting.hpp | 1 + apps/opencs/model/prefs/intsetting.hpp | 1 + 2 files changed, 2 insertions(+) diff --git a/apps/opencs/model/prefs/doublesetting.hpp b/apps/opencs/model/prefs/doublesetting.hpp index ef432aeb7..d0735d30a 100644 --- a/apps/opencs/model/prefs/doublesetting.hpp +++ b/apps/opencs/model/prefs/doublesetting.hpp @@ -19,6 +19,7 @@ namespace CSMPrefs DoubleSetting (Category *parent, Settings::Manager *values, const std::string& key, const std::string& label, double default_); + // defaults to [0, std::numeric_limits::max()] DoubleSetting& setRange (double min, double max); DoubleSetting& setMin (double min); diff --git a/apps/opencs/model/prefs/intsetting.hpp b/apps/opencs/model/prefs/intsetting.hpp index 314e68b37..05acb9fbc 100644 --- a/apps/opencs/model/prefs/intsetting.hpp +++ b/apps/opencs/model/prefs/intsetting.hpp @@ -19,6 +19,7 @@ namespace CSMPrefs IntSetting (Category *parent, Settings::Manager *values, const std::string& key, const std::string& label, int default_); + // defaults to [0, std::numeric_limits::max()] IntSetting& setRange (int min, int max); IntSetting& setMin (int min); From 590d6eba9b4b4e95775957f74605393daa32ab8a Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 10 Dec 2015 17:33:14 +0100 Subject: [PATCH 2774/3725] added enum settings --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/prefs/enumsetting.cpp | 107 ++++++++++++++++++++++++ apps/opencs/model/prefs/enumsetting.hpp | 61 ++++++++++++++ apps/opencs/model/prefs/state.cpp | 90 +++++++++++++++++--- apps/opencs/model/prefs/state.hpp | 3 + 5 files changed, 249 insertions(+), 14 deletions(-) create mode 100644 apps/opencs/model/prefs/enumsetting.cpp create mode 100644 apps/opencs/model/prefs/enumsetting.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index e2f9205ea..b51cfb52f 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -138,7 +138,7 @@ opencs_hdrs_noqt (model/settings ) opencs_units (model/prefs - state setting intsetting doublesetting boolsetting + state setting intsetting doublesetting boolsetting enumsetting ) opencs_units_noqt (model/prefs diff --git a/apps/opencs/model/prefs/enumsetting.cpp b/apps/opencs/model/prefs/enumsetting.cpp new file mode 100644 index 000000000..ea7d0703e --- /dev/null +++ b/apps/opencs/model/prefs/enumsetting.cpp @@ -0,0 +1,107 @@ + +#include "enumsetting.hpp" + +#include +#include + +#include + +#include "category.hpp" +#include "state.hpp" + + +CSMPrefs::EnumValue::EnumValue (const std::string& value, const std::string& tooltip) +: mValue (value), mTooltip (tooltip) +{} + +CSMPrefs::EnumValue::EnumValue (const char *value) +: mValue (value) +{} + + +CSMPrefs::EnumValues& CSMPrefs::EnumValues::add (const EnumValues& values) +{ + mValues.insert (mValues.end(), values.mValues.begin(), values.mValues.end()); + return *this; +} + +CSMPrefs::EnumValues& CSMPrefs::EnumValues::add (const EnumValue& value) +{ + mValues.push_back (value); + return *this; +} + +CSMPrefs::EnumValues& CSMPrefs::EnumValues::add (const std::string& value, const std::string& tooltip) +{ + mValues.push_back (EnumValue (value, tooltip)); + return *this; +} + + +CSMPrefs::EnumSetting::EnumSetting (Category *parent, Settings::Manager *values, + const std::string& key, const std::string& label, const EnumValue& default_) +: Setting (parent, values, key, label), mDefault (default_) +{} + +CSMPrefs::EnumSetting& CSMPrefs::EnumSetting::setTooltip (const std::string& tooltip) +{ + mTooltip = tooltip; + return *this; +} + +CSMPrefs::EnumSetting& CSMPrefs::EnumSetting::addValues (const EnumValues& values) +{ + mValues.add (values); + return *this; +} + +CSMPrefs::EnumSetting& CSMPrefs::EnumSetting::addValue (const EnumValue& value) +{ + mValues.add (value); + return *this; +} + +CSMPrefs::EnumSetting& CSMPrefs::EnumSetting::addValue (const std::string& value, const std::string& tooltip) +{ + mValues.add (value, tooltip); + return *this; +} + +std::pair CSMPrefs::EnumSetting::makeWidgets (QWidget *parent) +{ + QLabel *label = new QLabel (QString::fromUtf8 (getLabel().c_str()), parent); + + QComboBox *widget = new QComboBox (parent); + + int index = 0; + + for (int i=0; i (mValues.mValues.size()); ++i) + { + if (mDefault.mValue==mValues.mValues[i].mValue) + index = i; + + widget->addItem (QString::fromUtf8 (mValues.mValues[i].mValue.c_str())); + + if (!mValues.mValues[i].mTooltip.empty()) + widget->setItemData (i, QString::fromUtf8 (mValues.mValues[i].mTooltip.c_str()), + Qt::ToolTipRole); + } + + widget->setCurrentIndex (index); + + if (!mTooltip.empty()) + { + QString tooltip = QString::fromUtf8 (mTooltip.c_str()); + label->setToolTip (tooltip); + } + + connect (widget, SIGNAL (currentIndexChanged (int)), this, SLOT (valueChanged (int))); + + return std::make_pair (label, widget); +} + +void CSMPrefs::EnumSetting::valueChanged (int value) +{ + getValues().setString (getKey(), getParent()->getKey(), mValues.mValues.at (value).mValue); + getParent()->getState()->update (*this); +} diff --git a/apps/opencs/model/prefs/enumsetting.hpp b/apps/opencs/model/prefs/enumsetting.hpp new file mode 100644 index 000000000..e2102d20e --- /dev/null +++ b/apps/opencs/model/prefs/enumsetting.hpp @@ -0,0 +1,61 @@ +#ifndef CSM_PREFS_ENUMSETTING_H +#define CSM_PREFS_ENUMSETTING_H + +#include + +#include "setting.hpp" + +namespace CSMPrefs +{ + struct EnumValue + { + std::string mValue; + std::string mTooltip; + + EnumValue (const std::string& value, const std::string& tooltip = ""); + + EnumValue (const char *value); + }; + + struct EnumValues + { + std::vector mValues; + + EnumValues& add (const EnumValues& values); + + EnumValues& add (const EnumValue& value); + + EnumValues& add (const std::string& value, const std::string& tooltip); + }; + + class EnumSetting : public Setting + { + Q_OBJECT + + std::string mTooltip; + EnumValue mDefault; + EnumValues mValues; + + public: + + EnumSetting (Category *parent, Settings::Manager *values, + const std::string& key, const std::string& label, const EnumValue& default_); + + EnumSetting& setTooltip (const std::string& tooltip); + + EnumSetting& addValues (const EnumValues& values); + + EnumSetting& addValue (const EnumValue& value); + + EnumSetting& addValue (const std::string& value, const std::string& tooltip); + + /// Return label, input widget. + virtual std::pair makeWidgets (QWidget *parent); + + private slots: + + void valueChanged (int value); + }; +} + +#endif diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index cf58edce9..99449309c 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -57,20 +57,44 @@ void CSMPrefs::State::declare() declareInt ("minimum-width", "Minimum subview width", 325). setTooltip ("Minimum width of subviews."). setRange (50, 10000); - // mainwindow-scrollbar + EnumValue scrollbarOnly ("Scrollbar Only", "Simple addition of scrollbars, the view window " + "does not grow automatically."); + declareEnum ("mainwindow-scrollbar", "Horizontal scrollbar mode for main window.", scrollbarOnly). + addValue (scrollbarOnly). + addValue ("Grow Only", "The view window grows as subviews are added. No scrollbars."). + addValue ("Grow then Scroll", "The view window grows. The scrollbar appears once it cannot grow any further."); declareBool ("grow-limit", "Grow Limit Screen", false). setTooltip ("When \"Grow then Scroll\" option is selected, the window size grows to" " the width of the virtual desktop. \nIf this option is selected the the window growth" "is limited to the current screen."); declareCategory ("Records"); + EnumValue iconAndText ("Icon and Text"); + EnumValues recordValues; + recordValues.add (iconAndText).add ("Icon Only").add ("Text only"); + declareEnum ("status-format", "Modification status display format", iconAndText). + addValues (recordValues); + declareEnum ("type-format", "ID type display format", iconAndText). + addValues (recordValues); declareCategory ("ID Tables"); - // double - // double-s - // double-c - // double-sc - // jump-to-added + EnumValue inPlaceEdit ("Edit in Place", "Edit the clicked cell"); + EnumValue editRecord ("Edit Record", "Open a dialogue subview for the clicked record"); + EnumValue view ("View", "Open a scene subview for the clicked record (not available everywhere)"); + EnumValue editRecordAndClose ("Edit Record and Close"); + EnumValues doubleClickValues; + doubleClickValues.add (inPlaceEdit).add (editRecord).add (view).add ("Revert"). + add ("Delete").add (editRecordAndClose). + add ("View and Close", "Open a scene subview for the clicked record and close the table subview"); + declareEnum ("double", "Double Click", inPlaceEdit).addValues (doubleClickValues); + declareEnum ("double-s", "Shift Double Click", editRecord).addValues (doubleClickValues); + declareEnum ("double-c", "Control Double Click", view).addValues (doubleClickValues); + declareEnum ("double-sc", "Shift Control Double Click", editRecordAndClose).addValues (doubleClickValues); + EnumValue jumpAndSelect ("Jump and Select", "Scroll new record into view and make it the selection"); + declareEnum ("jump-to-added", "Action on adding or cloning a record", jumpAndSelect). + addValue (jumpAndSelect). + addValue ("Jump Only", "Scroll new record into view"). + addValue ("No Jump", "No special action"); declareBool ("extended-config", "Manually specify affected record types for an extended delete/revert", false). setTooltip ("Delete and revert commands have an extended form that also affects " @@ -83,6 +107,16 @@ void CSMPrefs::State::declare() declareBool ("toolbar", "Show toolbar", true); declareCategory ("Reports"); + EnumValue actionNone ("None"); + EnumValue actionEdit ("Edit", "Open a table or dialogue suitable for addressing the listed report"); + EnumValue actionRemove ("Remove", "Remove the report from the report table"); + EnumValue actionEditAndRemove ("Edit And Remove", "Open a table or dialogue suitable for addressing the listed report, then remove the report from the report table"); + EnumValues reportValues; + reportValues.add (actionNone).add (actionEdit).add (actionRemove).add (actionEditAndRemove); + declareEnum ("double", "Double Click", actionEdit).addValues (reportValues); + declareEnum ("double-s", "Shift Double Click", actionRemove).addValues (reportValues); + declareEnum ("double-c", "Control Double Click", actionEditAndRemove).addValues (reportValues); + declareEnum ("double-sc", "Shift Control Double Click", actionNone).addValues (reportValues); declareCategory ("Search & Replace"); declareInt ("char-before", "Characters before search string", 10). @@ -96,7 +130,11 @@ void CSMPrefs::State::declare() setTooltip ("Show line numbers to the left of the script editor window." "The current row and column numbers of the text cursor are shown at the bottom."); declareBool ("mono-font", "Use monospace font", true); - // warnings + EnumValue warningsNormal ("Normal", "Report warnings as warning"); + declareEnum ("warnings", "Warning Mode", warningsNormal). + addValue ("Ignore", "Do not report warning"). + addValue (warningsNormal). + addValue ("Strcit", "Promote warning to an error"); declareBool ("toolbar", "Show toolbar", true); declareInt ("compile-delay", "Delay between updating of source errors", 100). setTooltip ("Delay in milliseconds"). @@ -111,12 +149,20 @@ void CSMPrefs::State::declare() "list go to the first/last item"); declareCategory ("3D Scene Input"); - // p-navi - // s-navi - // p-edit - // s-edit - // p-select - // s-select + EnumValue left ("Left Mouse-Button"); + EnumValue cLeft ("Ctrl-Left Mouse-Button"); + EnumValue right ("Right Mouse-Button"); + EnumValue cRight ("Ctrl-Right Mouse-Button"); + EnumValue middle ("Middle Mouse-Button"); + EnumValue cMiddle ("Ctrl-Middle Mouse-Button"); + EnumValues inputButtons; + inputButtons.add (left).add (cLeft).add (right).add (cRight).add (middle).add (cMiddle); + declareEnum ("p-navi", "Primary Camera Navigation Button", left).addValues (inputButtons); + declareEnum ("s-navi", "Secondary Camera Navigation Button", cLeft).addValues (inputButtons); + declareEnum ("p-edit", "Primary Editing Button", right).addValues (inputButtons); + declareEnum ("s-edit", "Secondary Editing Button", cRight).addValues (inputButtons); + declareEnum ("p-select", "Primary Selection Button", middle).addValues (inputButtons); + declareEnum ("s-select", "Secondary Selection Button", cMiddle).addValues (inputButtons); declareBool ("context-select", "Context Sensitive Selection", false); declareDouble ("drag-factor", "Mouse sensitivity during drag operations", 1.0). setRange (0.001, 100.0); @@ -207,6 +253,24 @@ CSMPrefs::BoolSetting& CSMPrefs::State::declareBool (const std::string& key, return *setting; } +CSMPrefs::EnumSetting& CSMPrefs::State::declareEnum (const std::string& key, + const std::string& label, EnumValue default_) +{ + if (mCurrentCategory==mCategories.end()) + throw std::logic_error ("no category for setting"); + + setDefault (key, default_.mValue); + + default_.mValue = mSettings.getString (key, mCurrentCategory->second.getKey()); + + CSMPrefs::EnumSetting *setting = + new CSMPrefs::EnumSetting (&mCurrentCategory->second, &mSettings, key, label, default_); + + mCurrentCategory->second.addSetting (setting); + + return *setting; +} + void CSMPrefs::State::setDefault (const std::string& key, const std::string& default_) { Settings::CategorySetting fullKey (mCurrentCategory->second.getKey(), key); diff --git a/apps/opencs/model/prefs/state.hpp b/apps/opencs/model/prefs/state.hpp index 28bafd6a1..e4de7fcff 100644 --- a/apps/opencs/model/prefs/state.hpp +++ b/apps/opencs/model/prefs/state.hpp @@ -14,6 +14,7 @@ #include "category.hpp" #include "setting.hpp" +#include "enumsetting.hpp" namespace CSMPrefs { @@ -57,6 +58,8 @@ namespace CSMPrefs BoolSetting& declareBool (const std::string& key, const std::string& label, bool default_); + EnumSetting& declareEnum (const std::string& key, const std::string& label, EnumValue default_); + void setDefault (const std::string& key, const std::string& default_); public: From f1f82af64ee25290b0971214e9bede59dfa74f5a Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 11 Dec 2015 01:24:33 +0100 Subject: [PATCH 2775/3725] Fix improper swimming animations in first person mode --- apps/openmw/mwmechanics/character.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index f7f355a38..10c20e65d 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -397,10 +397,17 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat } else { - if (weap != sWeaponTypeListEnd) - movemask = MWRender::Animation::BlendMask_LowerBody; movementAnimName.erase(swimpos, 4); - if(!mAnimation->hasAnimation(movementAnimName)) + if (weap != sWeaponTypeListEnd) + { + std::string weapMovementAnimName = movementAnimName + weap->shortgroup; + if(mAnimation->hasAnimation(weapMovementAnimName)) + movementAnimName = weapMovementAnimName; + else + movemask = MWRender::Animation::BlendMask_LowerBody; + } + + if (!mAnimation->hasAnimation(movementAnimName)) movementAnimName.clear(); } } From a00a4bce77ebec91438e908845efa921eff55b3f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 10 Dec 2015 15:37:39 -0800 Subject: [PATCH 2776/3725] Avoid some unnecessary indirection --- apps/openmw/mwsound/soundmanagerimp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index d12174e20..c568ef778 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -221,7 +221,7 @@ namespace MWSound { DecoderPtr decoder = getDecoder(); // Workaround: Bethesda at some point converted some of the files to mp3, but the references were kept as .wav. - if(decoder->mResourceMgr->exists(voicefile)) + if(mVFS->exists(voicefile)) decoder->open(voicefile); else { From a47bdecac77d78f3b06759f853d70bac5cd6b7eb Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 10 Dec 2015 17:47:55 -0800 Subject: [PATCH 2777/3725] Add missing include Since Ptr is used directly in the header, a forward declaration isn't good enough. --- apps/openmw/mwworld/cellstore.hpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index b08349293..5d1685c28 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -35,6 +35,7 @@ #include "../mwmechanics/pathgrid.hpp" // TODO: maybe belongs in mwworld #include "timestamp.hpp" +#include "ptr.hpp" namespace ESM { @@ -45,10 +46,8 @@ namespace ESM namespace MWWorld { - class Ptr; class ESMStore; - /// \brief Mutable state of a cell class CellStore { From 808f7010138454f7b86bc059557a6aa3a11937f8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 10 Dec 2015 17:48:45 -0800 Subject: [PATCH 2778/3725] Use the actor's Head position for Say streams --- apps/openmw/mwbase/world.hpp | 3 +++ apps/openmw/mwsound/soundmanagerimp.cpp | 22 +++++++++--------- apps/openmw/mwworld/worldimp.cpp | 30 ++++++++++++------------- apps/openmw/mwworld/worldimp.hpp | 2 ++ 4 files changed, 31 insertions(+), 26 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 39c1910df..a7ff9b35b 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -14,6 +14,7 @@ namespace osg { class Vec3f; + class Matrixf; class Quat; class Image; } @@ -373,6 +374,8 @@ namespace MWBase virtual bool isUnderwater(const MWWorld::CellStore* cell, const osg::Vec3f &pos) const = 0; virtual bool isOnGround(const MWWorld::Ptr &ptr) const = 0; + virtual osg::Matrixf getActorHeadTransform(const MWWorld::Ptr& actor) const = 0; + virtual void togglePOV() = 0; virtual bool isFirstPerson() const = 0; virtual void togglePreviewMode(bool enable) = 0; diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index c568ef778..801a262d8 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -4,6 +4,8 @@ #include #include +#include + #include #include @@ -397,8 +399,6 @@ namespace MWSound try { std::string voicefile = "Sound/"+filename; - const ESM::Position &pos = ptr.getRefData().getPosition(); - const osg::Vec3f objpos(pos.asVec3()); Sound_Loudness *loudness; mVFS->normalizeFilename(voicefile); @@ -408,7 +408,9 @@ namespace MWSound mPendingSaySounds[ptr] = std::make_pair(decoder, loudness); else { - MWBase::SoundStreamPtr sound = playVoice(decoder, objpos, (ptr == MWMechanics::getPlayer())); + MWBase::World *world = MWBase::Environment::get().getWorld(); + const osg::Vec3f pos = world->getActorHeadTransform(ptr).getTrans(); + MWBase::SoundStreamPtr sound = playVoice(decoder, pos, (ptr == MWMechanics::getPlayer())); mActiveSaySounds[ptr] = std::make_pair(sound, loudness); } } @@ -906,10 +908,10 @@ namespace MWSound sound = playVoice(decoder, osg::Vec3f(), true); else { - const ESM::Position &pos = ptr.getRefData().getPosition(); - const osg::Vec3f objpos(pos.asVec3()); + MWBase::World *world = MWBase::Environment::get().getWorld(); + const osg::Vec3f pos = world->getActorHeadTransform(ptr).getTrans(); - sound = playVoice(decoder, objpos, (ptr == MWMechanics::getPlayer())); + sound = playVoice(decoder, pos, (ptr == MWMechanics::getPlayer())); } mActiveSaySounds[ptr] = std::make_pair(sound, loudness); } @@ -930,13 +932,13 @@ namespace MWSound MWBase::SoundStreamPtr sound = sayiter->second.first; if(!ptr.isEmpty() && sound->getIs3D()) { - const ESM::Position &pos = ptr.getRefData().getPosition(); - const osg::Vec3f objpos(pos.asVec3()); - sound->setPosition(objpos); + MWBase::World *world = MWBase::Environment::get().getWorld(); + const osg::Vec3f pos = world->getActorHeadTransform(ptr).getTrans(); + sound->setPosition(pos); if(sound->getDistanceCull()) { - if((mListenerPos - objpos).length2() > 2000*2000) + if((mListenerPos - pos).length2() > 2000*2000) mOutput->stopStream(sound); } } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 9a32c63a3..c9971c6f0 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1038,32 +1038,30 @@ namespace MWWorld return facedObject; } - osg::Vec3f getActorHeadPosition(const MWWorld::Ptr& actor, MWRender::RenderingManager* rendering) + osg::Matrixf World::getActorHeadTransform(const MWWorld::Ptr& actor) const { - osg::Vec3f origin(actor.getRefData().getPosition().asVec3()); - - MWRender::Animation* anim = rendering->getAnimation(actor); - if (anim != NULL) + MWRender::Animation *anim = mRendering->getAnimation(actor); + if(anim) { - const osg::Node* node = anim->getNode("Head"); - if (node == NULL) - node = anim->getNode("Bip01 Head"); - if (node != NULL) + const osg::Node *node = anim->getNode("Head"); + if(!node) node = anim->getNode("Bip01 Head"); + if(node) { osg::MatrixList mats = node->getWorldMatrices(); - if (mats.size()) - origin = mats[0].getTrans(); + if(!mats.empty()) + return mats[0]; } } - return origin; + return osg::Matrixf::translate(actor.getRefData().getPosition().asVec3()); } + std::pair World::getHitContact(const MWWorld::Ptr &ptr, float distance) { const ESM::Position &posdata = ptr.getRefData().getPosition(); osg::Quat rot = osg::Quat(posdata.rot[0], osg::Vec3f(-1,0,0)) * osg::Quat(posdata.rot[2], osg::Vec3f(0,0,-1)); - osg::Vec3f pos = getActorHeadPosition(ptr, mRendering); + osg::Vec3f pos = getActorHeadTransform(ptr).getTrans(); std::pair result = mPhysics->getHitContact(ptr, pos, rot, distance); if(result.first.isEmpty()) @@ -2659,7 +2657,7 @@ namespace MWWorld MWWorld::Ptr target; float distance = 192.f; // ?? osg::Vec3f hitPosition = actor.getRefData().getPosition().asVec3(); - osg::Vec3f origin = getActorHeadPosition(actor, mRendering); + osg::Vec3f origin = getActorHeadTransform(actor).getTrans(); osg::Quat orient = osg::Quat(actor.getRefData().getPosition().rot[0], osg::Vec3f(-1,0,0)) * osg::Quat(actor.getRefData().getPosition().rot[2], osg::Vec3f(0,0,-1)); @@ -3297,14 +3295,14 @@ namespace MWWorld osg::Vec3f World::aimToTarget(const Ptr &actor, const MWWorld::Ptr& target) { - osg::Vec3f weaponPos = getActorHeadPosition(actor, mRendering); + osg::Vec3f weaponPos = getActorHeadTransform(actor).getTrans(); osg::Vec3f targetPos = mPhysics->getPosition(target); return (targetPos - weaponPos); } float World::getHitDistance(const Ptr &actor, const Ptr &target) { - osg::Vec3f weaponPos = getActorHeadPosition(actor, mRendering); + osg::Vec3f weaponPos = getActorHeadTransform(actor).getTrans(); return mPhysics->getHitDistance(weaponPos, target); } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 92027868e..f08ede100 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -469,6 +469,8 @@ namespace MWWorld virtual bool isWading(const MWWorld::Ptr &object) const; virtual bool isOnGround(const MWWorld::Ptr &ptr) const; + virtual osg::Matrixf getActorHeadTransform(const MWWorld::Ptr& actor) const; + virtual void togglePOV(); virtual bool isFirstPerson() const; From 73ffdd5ac53676835d46f65be04436f97839c9c3 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 11 Dec 2015 11:15:14 +0100 Subject: [PATCH 2779/3725] added colour settings --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/prefs/coloursetting.cpp | 49 +++++++++++++++++++++++ apps/opencs/model/prefs/coloursetting.hpp | 33 +++++++++++++++ apps/opencs/model/prefs/state.cpp | 28 ++++++++++++- apps/opencs/model/prefs/state.hpp | 5 +++ 5 files changed, 114 insertions(+), 3 deletions(-) create mode 100644 apps/opencs/model/prefs/coloursetting.cpp create mode 100644 apps/opencs/model/prefs/coloursetting.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index b51cfb52f..e76b5ce77 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -138,7 +138,7 @@ opencs_hdrs_noqt (model/settings ) opencs_units (model/prefs - state setting intsetting doublesetting boolsetting enumsetting + state setting intsetting doublesetting boolsetting enumsetting coloursetting ) opencs_units_noqt (model/prefs diff --git a/apps/opencs/model/prefs/coloursetting.cpp b/apps/opencs/model/prefs/coloursetting.cpp new file mode 100644 index 000000000..a56485292 --- /dev/null +++ b/apps/opencs/model/prefs/coloursetting.cpp @@ -0,0 +1,49 @@ + +#include "coloursetting.hpp" + +#include + +#include + +#include + +#include "../../view/widget/coloreditor.hpp" + +#include "category.hpp" +#include "state.hpp" + +CSMPrefs::ColourSetting::ColourSetting (Category *parent, Settings::Manager *values, + const std::string& key, const std::string& label, QColor default_) +: Setting (parent, values, key, label), mDefault (default_) +{} + +CSMPrefs::ColourSetting& CSMPrefs::ColourSetting::setTooltip (const std::string& tooltip) +{ + mTooltip = tooltip; + return *this; +} + +std::pair CSMPrefs::ColourSetting::makeWidgets (QWidget *parent) +{ + QLabel *label = new QLabel (QString::fromUtf8 (getLabel().c_str()), parent); + + CSVWidget::ColorEditor *widget = new CSVWidget::ColorEditor (mDefault, parent); + + if (!mTooltip.empty()) + { + QString tooltip = QString::fromUtf8 (mTooltip.c_str()); + label->setToolTip (tooltip); + widget->setToolTip (tooltip); + } + + connect (widget, SIGNAL (pickingFinished()), this, SLOT (valueChanged())); + + return std::make_pair (label, widget); +} + +void CSMPrefs::ColourSetting::valueChanged() +{ + CSVWidget::ColorEditor& widget = dynamic_cast (*sender()); + getValues().setString (getKey(), getParent()->getKey(), widget.color().name().toUtf8().data()); + getParent()->getState()->update (*this); +} diff --git a/apps/opencs/model/prefs/coloursetting.hpp b/apps/opencs/model/prefs/coloursetting.hpp new file mode 100644 index 000000000..fed2adc0a --- /dev/null +++ b/apps/opencs/model/prefs/coloursetting.hpp @@ -0,0 +1,33 @@ +#ifndef CSM_PREFS_COLOURSETTING_H +#define CSM_PREFS_COLOURSETTING_H + +#include "setting.hpp" + +#include + +namespace CSMPrefs +{ + class ColourSetting : public Setting + { + Q_OBJECT + + std::string mTooltip; + QColor mDefault; + + public: + + ColourSetting (Category *parent, Settings::Manager *values, + const std::string& key, const std::string& label, QColor default_); + + ColourSetting& setTooltip (const std::string& tooltip); + + /// Return label, input widget. + virtual std::pair makeWidgets (QWidget *parent); + + private slots: + + void valueChanged(); + }; +} + +#endif diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index 99449309c..41956a5a9 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -8,6 +8,7 @@ #include "intsetting.hpp" #include "doublesetting.hpp" #include "boolsetting.hpp" +#include "coloursetting.hpp" CSMPrefs::State *CSMPrefs::State::sThis = 0; @@ -141,8 +142,13 @@ void CSMPrefs::State::declare() setRange (0, 10000); declareInt ("error-height", "Initial height of the error panel", 100). setRange (100, 10000); - // syntax-colouring - + declareColour ("colour-int", "Highlight Colour: Integer Literals", QColor ("darkmagenta")); + declareColour ("colour-float", "Highlight Colour: Float Literals", QColor ("magenta")); + declareColour ("colour-name", "Highlight Colour: Names", QColor ("grey")); + declareColour ("colour-keyword", "Highlight Colour: Keywords", QColor ("red")); + declareColour ("colour-special", "Highlight Colour: Special Characters", QColor ("darkorange")); + declareColour ("colour-comment", "Highlight Colour: Comments", QColor ("green")); + declareColour ("colour-id", "Highlight Colour: IDs", QColor ("blue")); declareCategory ("General Input"); declareBool ("cycle", "Cyclic next/previous", false). setTooltip ("When using next/previous functions at the last/first item of a " @@ -271,6 +277,24 @@ CSMPrefs::EnumSetting& CSMPrefs::State::declareEnum (const std::string& key, return *setting; } +CSMPrefs::ColourSetting& CSMPrefs::State::declareColour (const std::string& key, + const std::string& label, QColor default_) +{ + if (mCurrentCategory==mCategories.end()) + throw std::logic_error ("no category for setting"); + + setDefault (key, default_.name().toUtf8().data()); + + default_.setNamedColor (QString::fromUtf8 (mSettings.getString (key, mCurrentCategory->second.getKey()).c_str())); + + CSMPrefs::ColourSetting *setting = + new CSMPrefs::ColourSetting (&mCurrentCategory->second, &mSettings, key, label, default_); + + mCurrentCategory->second.addSetting (setting); + + return *setting; +} + void CSMPrefs::State::setDefault (const std::string& key, const std::string& default_) { Settings::CategorySetting fullKey (mCurrentCategory->second.getKey(), key); diff --git a/apps/opencs/model/prefs/state.hpp b/apps/opencs/model/prefs/state.hpp index e4de7fcff..1e4ada5b4 100644 --- a/apps/opencs/model/prefs/state.hpp +++ b/apps/opencs/model/prefs/state.hpp @@ -16,11 +16,14 @@ #include "setting.hpp" #include "enumsetting.hpp" +class QColor; + namespace CSMPrefs { class IntSetting; class DoubleSetting; class BoolSetting; + class ColourSetting; class State : public QObject { @@ -60,6 +63,8 @@ namespace CSMPrefs EnumSetting& declareEnum (const std::string& key, const std::string& label, EnumValue default_); + ColourSetting& declareColour (const std::string& key, const std::string& label, QColor default_); + void setDefault (const std::string& key, const std::string& default_); public: From a907b4ab152fc984766cee1a5dbc549ff22b9295 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 11 Dec 2015 11:22:15 +0100 Subject: [PATCH 2780/3725] made Setting class non-abstract --- apps/opencs/model/prefs/setting.cpp | 5 +++++ apps/opencs/model/prefs/setting.hpp | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/prefs/setting.cpp b/apps/opencs/model/prefs/setting.cpp index 70dbbc745..b23152d17 100644 --- a/apps/opencs/model/prefs/setting.cpp +++ b/apps/opencs/model/prefs/setting.cpp @@ -16,6 +16,11 @@ CSMPrefs::Setting::Setting (Category *parent, Settings::Manager *values, CSMPrefs::Setting:: ~Setting() {} +std::pair CSMPrefs::Setting::makeWidgets (QWidget *parent) +{ + return std::pair (0, 0); +} + const CSMPrefs::Category *CSMPrefs::Setting::getParent() const { return mParent; diff --git a/apps/opencs/model/prefs/setting.hpp b/apps/opencs/model/prefs/setting.hpp index 148c64292..e970352f4 100644 --- a/apps/opencs/model/prefs/setting.hpp +++ b/apps/opencs/model/prefs/setting.hpp @@ -40,7 +40,7 @@ namespace CSMPrefs /// /// \note first can be a 0-pointer, which means that the label is part of the input /// widget. - virtual std::pair makeWidgets (QWidget *parent) = 0; + virtual std::pair makeWidgets (QWidget *parent); const Category *getParent() const; From 31b105ad9eeb757ffa0fa1b8376f5dfdfdd856ca Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 11 Dec 2015 11:32:55 +0100 Subject: [PATCH 2781/3725] improved settings layout --- apps/opencs/model/prefs/state.cpp | 22 +++++++++++++++++++--- apps/opencs/model/prefs/state.hpp | 2 ++ 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index 41956a5a9..02ab1ca49 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -41,12 +41,13 @@ void CSMPrefs::State::declare() declareInt ("default-height", "Default window height", 600). setTooltip ("Newly opened top-level windows will open with this height."). setMin (80); - declareBool ("reuse", "Reuse Subviews", true). - setTooltip ("When a new subview is requested and a matching subview already " - " exist, do not open a new subview and use the existing one instead."); declareBool ("show-statusbar", "Show Status Bar", true). setTooltip ("If a newly open top level window is showing status bars or not. " " Note that this does not affect existing windows."); + declareSeparator(); + declareBool ("reuse", "Reuse Subviews", true). + setTooltip ("When a new subview is requested and a matching subview already " + " exist, do not open a new subview and use the existing one instead."); declareInt ("max-subviews", "Maximum number of subviews per top-level window", 256). setTooltip ("If the maximum number is reached and a new subview is opened " "it will be placed into a new top-level window."). @@ -58,6 +59,7 @@ void CSMPrefs::State::declare() declareInt ("minimum-width", "Minimum subview width", 325). setTooltip ("Minimum width of subviews."). setRange (50, 10000); + declareSeparator(); EnumValue scrollbarOnly ("Scrollbar Only", "Simple addition of scrollbars, the view window " "does not grow automatically."); declareEnum ("mainwindow-scrollbar", "Horizontal scrollbar mode for main window.", scrollbarOnly). @@ -91,6 +93,7 @@ void CSMPrefs::State::declare() declareEnum ("double-s", "Shift Double Click", editRecord).addValues (doubleClickValues); declareEnum ("double-c", "Control Double Click", view).addValues (doubleClickValues); declareEnum ("double-sc", "Shift Control Double Click", editRecordAndClose).addValues (doubleClickValues); + declareSeparator(); EnumValue jumpAndSelect ("Jump and Select", "Scroll new record into view and make it the selection"); declareEnum ("jump-to-added", "Action on adding or cloning a record", jumpAndSelect). addValue (jumpAndSelect). @@ -142,6 +145,7 @@ void CSMPrefs::State::declare() setRange (0, 10000); declareInt ("error-height", "Initial height of the error panel", 100). setRange (100, 10000); + declareSeparator(); declareColour ("colour-int", "Highlight Colour: Integer Literals", QColor ("darkmagenta")); declareColour ("colour-float", "Highlight Colour: Float Literals", QColor ("magenta")); declareColour ("colour-name", "Highlight Colour: Names", QColor ("grey")); @@ -169,6 +173,7 @@ void CSMPrefs::State::declare() declareEnum ("s-edit", "Secondary Editing Button", cRight).addValues (inputButtons); declareEnum ("p-select", "Primary Selection Button", middle).addValues (inputButtons); declareEnum ("s-select", "Secondary Selection Button", cMiddle).addValues (inputButtons); + declareSeparator(); declareBool ("context-select", "Context Sensitive Selection", false); declareDouble ("drag-factor", "Mouse sensitivity during drag operations", 1.0). setRange (0.001, 100.0); @@ -295,6 +300,17 @@ CSMPrefs::ColourSetting& CSMPrefs::State::declareColour (const std::string& key, return *setting; } +void CSMPrefs::State::declareSeparator() +{ + if (mCurrentCategory==mCategories.end()) + throw std::logic_error ("no category for setting"); + + CSMPrefs::Setting *setting = + new CSMPrefs::Setting (&mCurrentCategory->second, &mSettings, "", ""); + + mCurrentCategory->second.addSetting (setting); +} + void CSMPrefs::State::setDefault (const std::string& key, const std::string& default_) { Settings::CategorySetting fullKey (mCurrentCategory->second.getKey(), key); diff --git a/apps/opencs/model/prefs/state.hpp b/apps/opencs/model/prefs/state.hpp index 1e4ada5b4..f5376a7da 100644 --- a/apps/opencs/model/prefs/state.hpp +++ b/apps/opencs/model/prefs/state.hpp @@ -65,6 +65,8 @@ namespace CSMPrefs ColourSetting& declareColour (const std::string& key, const std::string& label, QColor default_); + void declareSeparator(); + void setDefault (const std::string& key, const std::string& default_); public: From 8245b9e4390309639f69545132d6c5464a482386 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 11 Dec 2015 11:50:06 +0100 Subject: [PATCH 2782/3725] added interface for querying settings --- apps/opencs/model/prefs/category.cpp | 13 ++++++++ apps/opencs/model/prefs/category.hpp | 2 ++ apps/opencs/model/prefs/setting.cpp | 48 ++++++++++++++++++++++++++++ apps/opencs/model/prefs/setting.hpp | 17 ++++++++++ apps/opencs/model/prefs/state.cpp | 2 +- apps/opencs/model/prefs/state.hpp | 2 +- apps/opencs/view/prefs/dialogue.cpp | 2 +- 7 files changed, 83 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/prefs/category.cpp b/apps/opencs/model/prefs/category.cpp index b001586b5..0de192eb5 100644 --- a/apps/opencs/model/prefs/category.cpp +++ b/apps/opencs/model/prefs/category.cpp @@ -1,6 +1,10 @@ #include "category.hpp" +#include + +#include "setting.hpp" + CSMPrefs::Category::Category (State *parent, const std::string& key) : mParent (parent), mKey (key) {} @@ -29,3 +33,12 @@ CSMPrefs::Category::Iterator CSMPrefs::Category::end() { return mSettings.end(); } + +CSMPrefs::Setting& CSMPrefs::Category::operator[] (const std::string& key) +{ + for (Iterator iter = mSettings.begin(); iter!=mSettings.end(); ++iter) + if ((*iter)->getKey()==key) + return **iter; + + throw std::logic_error ("Invalid user setting: " + key); +} diff --git a/apps/opencs/model/prefs/category.hpp b/apps/opencs/model/prefs/category.hpp index 0b8e45d56..7231fddea 100644 --- a/apps/opencs/model/prefs/category.hpp +++ b/apps/opencs/model/prefs/category.hpp @@ -35,6 +35,8 @@ namespace CSMPrefs Iterator begin(); Iterator end(); + + Setting& operator[] (const std::string& key); }; } diff --git a/apps/opencs/model/prefs/setting.cpp b/apps/opencs/model/prefs/setting.cpp index b23152d17..39d997988 100644 --- a/apps/opencs/model/prefs/setting.cpp +++ b/apps/opencs/model/prefs/setting.cpp @@ -1,6 +1,8 @@ #include "setting.hpp" +#include + #include "category.hpp" #include "state.hpp" @@ -35,3 +37,49 @@ const std::string& CSMPrefs::Setting::getLabel() const { return mLabel; } + +int CSMPrefs::Setting::toInt() const +{ + return mValues->getInt (mKey, mParent->getKey()); +} + +double CSMPrefs::Setting::toDouble() const +{ + return mValues->getFloat (mKey, mParent->getKey()); +} + +std::string CSMPrefs::Setting::toString() const +{ + return mValues->getString (mKey, mParent->getKey()); +} + +bool CSMPrefs::Setting::isTrue() const +{ + return mValues->getBool (mKey, mParent->getKey()); +} + +QColor CSMPrefs::Setting::toColor() const +{ + return QColor (QString::fromUtf8 (toString().c_str())); +} + +bool CSMPrefs::operator== (const Setting& setting, const std::string& key) +{ + std::string fullKey = setting.getParent()->getKey() + "/" + setting.getKey(); + return fullKey==key; +} + +bool CSMPrefs::operator== (const std::string& key, const Setting& setting) +{ + return setting==key; +} + +bool CSMPrefs::operator!= (const Setting& setting, const std::string& key) +{ + return !(setting==key); +} + +bool CSMPrefs::operator!= (const std::string& key, const Setting& setting) +{ + return !(key==setting); +} diff --git a/apps/opencs/model/prefs/setting.hpp b/apps/opencs/model/prefs/setting.hpp index e970352f4..65354469d 100644 --- a/apps/opencs/model/prefs/setting.hpp +++ b/apps/opencs/model/prefs/setting.hpp @@ -7,6 +7,7 @@ #include class QWidget; +class QColor; namespace Settings { @@ -47,7 +48,23 @@ namespace CSMPrefs const std::string& getKey() const; const std::string& getLabel() const; + + int toInt() const; + + double toDouble() const; + + std::string toString() const; + + bool isTrue() const; + + QColor toColor() const; }; + + // note: fullKeys have the format categoryKey/settingKey + bool operator== (const Setting& setting, const std::string& fullKey); + bool operator== (const std::string& fullKey, const Setting& setting); + bool operator!= (const Setting& setting, const std::string& fullKey); + bool operator!= (const std::string& fullKey, const Setting& setting); } #endif diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index 02ab1ca49..c31c2db5a 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -356,7 +356,7 @@ CSMPrefs::State::Iterator CSMPrefs::State::end() return mCategories.end(); } -CSMPrefs::Category& CSMPrefs::State::getCategory (const std::string& key) +CSMPrefs::Category& CSMPrefs::State::operator[] (const std::string& key) { Iterator iter = mCategories.find (key); diff --git a/apps/opencs/model/prefs/state.hpp b/apps/opencs/model/prefs/state.hpp index f5376a7da..2b99eec05 100644 --- a/apps/opencs/model/prefs/state.hpp +++ b/apps/opencs/model/prefs/state.hpp @@ -81,7 +81,7 @@ namespace CSMPrefs Iterator end(); - Category& getCategory (const std::string& key); + Category& operator[](const std::string& key); void update (const Setting& setting); diff --git a/apps/opencs/view/prefs/dialogue.cpp b/apps/opencs/view/prefs/dialogue.cpp index 6135afde7..97a36306f 100644 --- a/apps/opencs/view/prefs/dialogue.cpp +++ b/apps/opencs/view/prefs/dialogue.cpp @@ -53,7 +53,7 @@ CSVPrefs::PageBase *CSVPrefs::Dialogue::makePage (const std::string& key) { // special case page code goes here - return new Page (CSMPrefs::get().getCategory (key), mContent); + return new Page (CSMPrefs::get()[key], mContent); } CSVPrefs::Dialogue::Dialogue() From 3a5238bebc3486d6c719150974e4aabd48b90dde Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 11 Dec 2015 12:06:20 +0100 Subject: [PATCH 2783/3725] changed the settingChanged signature to accommodate queued connections --- apps/opencs/model/prefs/state.cpp | 2 +- apps/opencs/model/prefs/state.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index c31c2db5a..d6250c532 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -368,7 +368,7 @@ CSMPrefs::Category& CSMPrefs::State::operator[] (const std::string& key) void CSMPrefs::State::update (const Setting& setting) { - emit (settingChanged (setting)); + emit (settingChanged (&setting)); } CSMPrefs::State& CSMPrefs::State::get() diff --git a/apps/opencs/model/prefs/state.hpp b/apps/opencs/model/prefs/state.hpp index 2b99eec05..13427b1aa 100644 --- a/apps/opencs/model/prefs/state.hpp +++ b/apps/opencs/model/prefs/state.hpp @@ -89,7 +89,7 @@ namespace CSMPrefs signals: - void settingChanged (const Setting& setting); + void settingChanged (const Setting *setting); }; // convenience function From 06719df868aa934db7d99bed92567dd67e70c383 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Fri, 11 Dec 2015 15:59:16 +0100 Subject: [PATCH 2784/3725] Use the standard cursor if the custom cursor can't be used Signed-off-by: Paul Cercueil --- components/sdlutil/sdlcursormanager.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/components/sdlutil/sdlcursormanager.cpp b/components/sdlutil/sdlcursormanager.cpp index 26b0510dc..40b87d905 100644 --- a/components/sdlutil/sdlcursormanager.cpp +++ b/components/sdlutil/sdlcursormanager.cpp @@ -217,14 +217,17 @@ namespace SDLUtil void SDLCursorManager::_createCursorFromResource(const std::string& name, int rotDegrees, osg::Image* image, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y) { - #ifdef ANDROID - return; - #endif + osg::ref_ptr decompressed; if (mCursorMap.find(name) != mCursorMap.end()) return; - osg::ref_ptr decompressed = decompress(image, static_cast(rotDegrees)); + try { + decompressed = decompress(image, static_cast(rotDegrees)); + } catch (...) { + osg::notify(osg::NOTICE)<<"Using default cursor."< Date: Fri, 11 Dec 2015 16:18:08 +0100 Subject: [PATCH 2785/3725] Don't use osg::notify --- components/sdlutil/sdlcursormanager.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/components/sdlutil/sdlcursormanager.cpp b/components/sdlutil/sdlcursormanager.cpp index 40b87d905..9ecef0483 100644 --- a/components/sdlutil/sdlcursormanager.cpp +++ b/components/sdlutil/sdlcursormanager.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -52,7 +53,7 @@ namespace if (!_gc) { - osg::notify(osg::NOTICE)<<"Failed to create pbuffer, failing back to normal graphics window."<pbuffer = false; _gc = osg::GraphicsContext::createGraphicsContext(traits.get()); @@ -224,8 +225,9 @@ namespace SDLUtil try { decompressed = decompress(image, static_cast(rotDegrees)); - } catch (...) { - osg::notify(osg::NOTICE)<<"Using default cursor."< Date: Fri, 11 Dec 2015 15:55:45 +0100 Subject: [PATCH 2786/3725] ESMStore: fill mIds in setUp() --- apps/openmw/mwworld/esmstore.cpp | 30 ++++++++++++++++-------------- apps/openmw/mwworld/store.hpp | 2 ++ 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index 9cf8de6bb..2e6161bf5 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -114,10 +114,6 @@ void ESMStore::load(ESM::ESMReader &esm, Loading::Listener* listener) } else { dialogue = 0; } - // Insert the reference into the global lookup - if (!id.mId.empty() && isCacheableRecord(n.val)) { - mIds[Misc::StringUtils::lowerCase (id.mId)] = n.val; - } } listener->setProgress(static_cast(esm.getFileOffset() / (float)esm.getFileSize() * 1000)); } @@ -125,9 +121,20 @@ void ESMStore::load(ESM::ESMReader &esm, Loading::Listener* listener) void ESMStore::setUp() { - std::map::iterator it = mStores.begin(); - for (; it != mStores.end(); ++it) { - it->second->setUp(); + mIds.clear(); + + std::map::iterator storeIt = mStores.begin(); + for (; storeIt != mStores.end(); ++storeIt) { + if (isCacheableRecord(storeIt->first)) + { + std::vector identifiers; + storeIt->second->listIdentifier(identifiers); + + for (std::vector::const_iterator record = identifiers.begin(); record != identifiers.end(); ++record) + mIds[*record] = storeIt->first; + } + + storeIt->second->setUp(); } mSkills.setUp(); mMagicEffects.setUp(); @@ -189,18 +196,13 @@ void ESMStore::setUp() case ESM::REC_LEVC: { - RecordId id = mStores[type]->read (reader); - - // FIXME: there might be stale dynamic IDs in mIds from an earlier savegame - // that really should be cleared instead of just overwritten - - mIds[id.mId] = type; + mStores[type]->read (reader); } if (type==ESM::REC_NPC_) { // NPC record will always be last and we know that there can be only one - // dynamic NPC record (player) -> We are done here with dynamic record laoding + // dynamic NPC record (player) -> We are done here with dynamic record loading setUp(); const ESM::NPC *player = mNpcs.find ("player"); diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index 443dd4175..88457c950 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -32,6 +32,8 @@ namespace MWWorld virtual ~StoreBase() {} virtual void setUp() {} + + /// List identifiers of records contained in this Store (case-smashed). No-op for Stores that don't use string IDs. virtual void listIdentifier(std::vector &list) const {} virtual size_t getSize() const = 0; From cc2315a0de77b9c3d6e99ccb6dc657d18e136235 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 11 Dec 2015 16:59:13 +0100 Subject: [PATCH 2787/3725] Minor fix --- apps/openmw/mwworld/esmstore.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index 2e6161bf5..1882c6e1a 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -125,6 +125,8 @@ void ESMStore::setUp() std::map::iterator storeIt = mStores.begin(); for (; storeIt != mStores.end(); ++storeIt) { + storeIt->second->setUp(); + if (isCacheableRecord(storeIt->first)) { std::vector identifiers; @@ -133,8 +135,6 @@ void ESMStore::setUp() for (std::vector::const_iterator record = identifiers.begin(); record != identifiers.end(); ++record) mIds[*record] = storeIt->first; } - - storeIt->second->setUp(); } mSkills.setUp(); mMagicEffects.setUp(); From 7fc2df153a42ae5545d1129a31d610ea1b143f19 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 11 Dec 2015 15:13:14 -0800 Subject: [PATCH 2788/3725] Rename stopSound/stopStream to finishSound/finishStream Since they're also used to clean up output resources, not just stopping. --- apps/openmw/mwsound/openal_output.cpp | 4 +-- apps/openmw/mwsound/openal_output.hpp | 4 +-- apps/openmw/mwsound/sound_output.hpp | 4 +-- apps/openmw/mwsound/soundmanagerimp.cpp | 36 ++++++++++++------------- 4 files changed, 24 insertions(+), 24 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 02a9f33f9..d44020632 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -915,7 +915,7 @@ void OpenAL_Output::playSound3D(MWBase::SoundPtr sound, Sound_Handle data, float sound->mHandle = MAKE_PTRID(source); } -void OpenAL_Output::stopSound(MWBase::SoundPtr sound) +void OpenAL_Output::finishSound(MWBase::SoundPtr sound) { if(!sound->mHandle) return; ALuint source = GET_PTRID(sound->mHandle); @@ -1012,7 +1012,7 @@ void OpenAL_Output::streamSound3D(DecoderPtr decoder, MWBase::SoundStreamPtr sou sound->mHandle = stream; } -void OpenAL_Output::stopStream(MWBase::SoundStreamPtr sound) +void OpenAL_Output::finishStream(MWBase::SoundStreamPtr sound) { if(!sound->mHandle) return; OpenAL_SoundStream *stream = reinterpret_cast(sound->mHandle); diff --git a/apps/openmw/mwsound/openal_output.hpp b/apps/openmw/mwsound/openal_output.hpp index 28f30bec9..4986cd3a0 100644 --- a/apps/openmw/mwsound/openal_output.hpp +++ b/apps/openmw/mwsound/openal_output.hpp @@ -58,13 +58,13 @@ namespace MWSound virtual void playSound(MWBase::SoundPtr sound, Sound_Handle data, float offset); virtual void playSound3D(MWBase::SoundPtr sound, Sound_Handle data, float offset); - virtual void stopSound(MWBase::SoundPtr sound); + virtual void finishSound(MWBase::SoundPtr sound); virtual bool isSoundPlaying(MWBase::SoundPtr sound); virtual void updateSound(MWBase::SoundPtr sound); virtual void streamSound(DecoderPtr decoder, MWBase::SoundStreamPtr sound); virtual void streamSound3D(DecoderPtr decoder, MWBase::SoundStreamPtr sound); - virtual void stopStream(MWBase::SoundStreamPtr sound); + virtual void finishStream(MWBase::SoundStreamPtr sound); virtual double getStreamDelay(MWBase::SoundStreamPtr sound); virtual double getStreamOffset(MWBase::SoundStreamPtr sound); virtual bool isStreamPlaying(MWBase::SoundStreamPtr sound); diff --git a/apps/openmw/mwsound/sound_output.hpp b/apps/openmw/mwsound/sound_output.hpp index 79025abb0..98eba8466 100644 --- a/apps/openmw/mwsound/sound_output.hpp +++ b/apps/openmw/mwsound/sound_output.hpp @@ -37,13 +37,13 @@ namespace MWSound virtual void playSound(MWBase::SoundPtr sound, Sound_Handle data, float offset) = 0; virtual void playSound3D(MWBase::SoundPtr sound, Sound_Handle data, float offset) = 0; - virtual void stopSound(MWBase::SoundPtr sound) = 0; + virtual void finishSound(MWBase::SoundPtr sound) = 0; virtual bool isSoundPlaying(MWBase::SoundPtr sound) = 0; virtual void updateSound(MWBase::SoundPtr sound) = 0; virtual void streamSound(DecoderPtr decoder, MWBase::SoundStreamPtr sound) = 0; virtual void streamSound3D(DecoderPtr decoder, MWBase::SoundStreamPtr sound) = 0; - virtual void stopStream(MWBase::SoundStreamPtr sound) = 0; + virtual void finishStream(MWBase::SoundStreamPtr sound) = 0; virtual double getStreamDelay(MWBase::SoundStreamPtr sound) = 0; virtual double getStreamOffset(MWBase::SoundStreamPtr sound) = 0; virtual bool isStreamPlaying(MWBase::SoundStreamPtr sound) = 0; diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 801a262d8..a36c21da1 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -309,7 +309,7 @@ namespace MWSound void SoundManager::stopMusic() { if(mMusic) - mOutput->stopStream(mMusic); + mOutput->finishStream(mMusic); mMusic.reset(); } @@ -477,7 +477,7 @@ namespace MWSound SaySoundMap::iterator snditer = mActiveSaySounds.find(ptr); if(snditer != mActiveSaySounds.end()) { - mOutput->stopStream(snditer->second.first); + mOutput->finishStream(snditer->second.first); mActiveSaySounds.erase(snditer); } mPendingSaySounds.erase(ptr); @@ -506,7 +506,7 @@ namespace MWSound void SoundManager::stopTrack(MWBase::SoundStreamPtr stream) { - mOutput->stopStream(stream); + mOutput->finishStream(stream); TrackList::iterator iter = std::lower_bound(mActiveTracks.begin(), mActiveTracks.end(), stream); if(iter != mActiveTracks.end() && *iter == stream) mActiveTracks.erase(iter); @@ -624,7 +624,7 @@ namespace MWSound void SoundManager::stopSound(MWBase::SoundPtr sound) { if (sound.get()) - mOutput->stopSound(sound); + mOutput->finishSound(sound); } void SoundManager::stopSound3D(const MWWorld::Ptr &ptr, const std::string& soundId) @@ -637,7 +637,7 @@ namespace MWSound for(;sndidx != snditer->second.end();++sndidx) { if(sndidx->second == sfx) - mOutput->stopSound(sndidx->first); + mOutput->finishSound(sndidx->first); } } } @@ -649,7 +649,7 @@ namespace MWSound { SoundBufferRefPairList::iterator sndidx = snditer->second.begin(); for(;sndidx != snditer->second.end();++sndidx) - mOutput->stopSound(sndidx->first); + mOutput->finishSound(sndidx->first); } } @@ -664,7 +664,7 @@ namespace MWSound { SoundBufferRefPairList::iterator sndidx = snditer->second.begin(); for(;sndidx != snditer->second.end();++sndidx) - mOutput->stopSound(sndidx->first); + mOutput->finishSound(sndidx->first); } ++snditer; } @@ -675,7 +675,7 @@ namespace MWSound sayiter->first != MWMechanics::getPlayer() && sayiter->first.getCell() == cell) { - mOutput->stopStream(sayiter->second.first); + mOutput->finishStream(sayiter->second.first); } ++sayiter; } @@ -691,7 +691,7 @@ namespace MWSound for(;sndidx != snditer->second.end();++sndidx) { if(sndidx->second == sfx) - mOutput->stopSound(sndidx->first); + mOutput->finishSound(sndidx->first); } } } @@ -829,7 +829,7 @@ namespace MWSound env = Env_Underwater; else if(mUnderwaterSound) { - mOutput->stopSound(mUnderwaterSound); + mOutput->finishSound(mUnderwaterSound); mUnderwaterSound.reset(); } @@ -866,13 +866,13 @@ namespace MWSound if(sound->getDistanceCull()) { if((mListenerPos - objpos).length2() > 2000*2000) - mOutput->stopSound(sound); + mOutput->finishSound(sound); } } if(!mOutput->isSoundPlaying(sound)) { - mOutput->stopSound(sound); + mOutput->finishSound(sound); Sound_Buffer *sfx = sndidx->second; if(sfx->mUses-- == 1) mUnusedBuffers.push_front(sfx); @@ -939,13 +939,13 @@ namespace MWSound if(sound->getDistanceCull()) { if((mListenerPos - pos).length2() > 2000*2000) - mOutput->stopStream(sound); + mOutput->finishStream(sound); } } if(!mOutput->isStreamPlaying(sound)) { - mOutput->stopStream(sound); + mOutput->finishStream(sound); mActiveSaySounds.erase(sayiter++); } else @@ -963,7 +963,7 @@ namespace MWSound MWBase::SoundStreamPtr sound = *trkiter; if(!mOutput->isStreamPlaying(sound)) { - mOutput->stopStream(sound); + mOutput->finishStream(sound); trkiter = mActiveTracks.erase(trkiter); } else @@ -1143,7 +1143,7 @@ namespace MWSound SoundBufferRefPairList::iterator sndidx = snditer->second.begin(); for(;sndidx != snditer->second.end();++sndidx) { - mOutput->stopSound(sndidx->first); + mOutput->finishSound(sndidx->first); Sound_Buffer *sfx = sndidx->second; if(sfx->mUses-- == 1) mUnusedBuffers.push_front(sfx); @@ -1152,11 +1152,11 @@ namespace MWSound mActiveSounds.clear(); SaySoundMap::iterator sayiter = mActiveSaySounds.begin(); for(;sayiter != mActiveSaySounds.end();++sayiter) - mOutput->stopStream(sayiter->second.first); + mOutput->finishStream(sayiter->second.first); mActiveSaySounds.clear(); TrackList::iterator trkiter = mActiveTracks.begin(); for(;trkiter != mActiveTracks.end();++trkiter) - mOutput->stopStream(*trkiter); + mOutput->finishStream(*trkiter); mActiveTracks.clear(); mPendingSaySounds.clear(); mUnderwaterSound.reset(); From f47f0a996f096d7e0ce3cd4d89eb660b814b29b9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 11 Dec 2015 15:49:45 -0800 Subject: [PATCH 2789/3725] Stop the object's old say sound before playing the new one --- apps/openmw/mwsound/soundmanagerimp.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index a36c21da1..d1a90759b 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -410,8 +410,10 @@ namespace MWSound { MWBase::World *world = MWBase::Environment::get().getWorld(); const osg::Vec3f pos = world->getActorHeadTransform(ptr).getTrans(); - MWBase::SoundStreamPtr sound = playVoice(decoder, pos, (ptr == MWMechanics::getPlayer())); - mActiveSaySounds[ptr] = std::make_pair(sound, loudness); + SoundLoudnessPair &old = mActiveSaySounds[ptr]; + if(old.first.get()) mOutput->finishStream(old.first); + old = std::make_pair(playVoice(decoder, pos, (ptr == MWMechanics::getPlayer())), + loudness); } } catch(std::exception &e) @@ -450,8 +452,9 @@ namespace MWSound mPendingSaySounds[MWWorld::Ptr()] = std::make_pair(decoder, loudness); else { - MWBase::SoundStreamPtr sound = playVoice(decoder, osg::Vec3f(), true); - mActiveSaySounds[MWWorld::Ptr()] = std::make_pair(sound, loudness); + SoundLoudnessPair &old = mActiveSaySounds[MWWorld::Ptr()]; + if(old.first.get()) mOutput->finishStream(old.first); + old = std::make_pair(playVoice(decoder, osg::Vec3f(), true), loudness); } } catch(std::exception &e) @@ -904,16 +907,18 @@ namespace MWSound MWBase::SoundStreamPtr sound; MWWorld::Ptr ptr = penditer->first; + + SoundLoudnessPair &old = mActiveSaySounds[ptr]; + if(old.first.get()) mOutput->finishStream(old.first); if(ptr == MWWorld::Ptr()) sound = playVoice(decoder, osg::Vec3f(), true); else { MWBase::World *world = MWBase::Environment::get().getWorld(); const osg::Vec3f pos = world->getActorHeadTransform(ptr).getTrans(); - sound = playVoice(decoder, pos, (ptr == MWMechanics::getPlayer())); } - mActiveSaySounds[ptr] = std::make_pair(sound, loudness); + old = std::make_pair(sound, loudness); } catch(std::exception &e) { std::cerr<< "Sound Error: "< Date: Sat, 12 Dec 2015 02:01:19 +0100 Subject: [PATCH 2790/3725] Update comment in settings-default.cfg There are antialiasing techniques that address texture/shading aliasing, but the one we use (MSAA) does not. --- files/settings-default.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/settings-default.cfg b/files/settings-default.cfg index d41ebfde2..a5fd3cccd 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -204,7 +204,7 @@ minimize on focus loss = true # An operating system border is drawn around the OpenMW window. window border = true -# Anti-aliasing reduces texture distortion. (0, 2, 4, 8, 16). +# Anti-aliasing reduces jagged polygon edges. (0, 2, 4, 8, 16). antialiasing = 0 # Enable vertical syncing to reduce tearing defects. From 04a11679fb16ab4a60e51c8f7c98767020b2c09f Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 12 Dec 2015 11:58:53 +0100 Subject: [PATCH 2791/3725] added category update function --- apps/opencs/model/prefs/category.cpp | 7 +++++++ apps/opencs/model/prefs/category.hpp | 2 ++ 2 files changed, 9 insertions(+) diff --git a/apps/opencs/model/prefs/category.cpp b/apps/opencs/model/prefs/category.cpp index 0de192eb5..6af0ac645 100644 --- a/apps/opencs/model/prefs/category.cpp +++ b/apps/opencs/model/prefs/category.cpp @@ -4,6 +4,7 @@ #include #include "setting.hpp" +#include "state.hpp" CSMPrefs::Category::Category (State *parent, const std::string& key) : mParent (parent), mKey (key) @@ -42,3 +43,9 @@ CSMPrefs::Setting& CSMPrefs::Category::operator[] (const std::string& key) throw std::logic_error ("Invalid user setting: " + key); } + +void CSMPrefs::Category::update() +{ + for (Iterator iter = mSettings.begin(); iter!=mSettings.end(); ++iter) + mParent->update (**iter); +} diff --git a/apps/opencs/model/prefs/category.hpp b/apps/opencs/model/prefs/category.hpp index 7231fddea..b70716aa0 100644 --- a/apps/opencs/model/prefs/category.hpp +++ b/apps/opencs/model/prefs/category.hpp @@ -37,6 +37,8 @@ namespace CSMPrefs Iterator end(); Setting& operator[] (const std::string& key); + + void update(); }; } From 0ffe4290fb3b7654d95a445996ecb9bc4a011efc Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 12 Dec 2015 12:05:56 +0100 Subject: [PATCH 2792/3725] workaround for MOC's lack of namespace awareness --- apps/opencs/model/prefs/state.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/prefs/state.hpp b/apps/opencs/model/prefs/state.hpp index 13427b1aa..7807dac25 100644 --- a/apps/opencs/model/prefs/state.hpp +++ b/apps/opencs/model/prefs/state.hpp @@ -89,7 +89,7 @@ namespace CSMPrefs signals: - void settingChanged (const Setting *setting); + void settingChanged (const CSMPrefs::Setting *setting); }; // convenience function From cf9fa0e0e9742203303009725e79e2eafc4d70e6 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 12 Dec 2015 14:49:16 +0100 Subject: [PATCH 2793/3725] first batch of changing over user settings usage to the new system --- apps/opencs/view/doc/view.cpp | 59 +++---- apps/opencs/view/render/worldspacewidget.cpp | 117 ++++++------- apps/opencs/view/render/worldspacewidget.hpp | 11 +- apps/opencs/view/world/scenesubview.cpp | 6 - apps/opencs/view/world/scenesubview.hpp | 2 - apps/opencs/view/world/scriptedit.cpp | 34 ++-- apps/opencs/view/world/scriptedit.hpp | 6 +- apps/opencs/view/world/scripterrortable.cpp | 21 ++- apps/opencs/view/world/scripterrortable.hpp | 11 +- apps/opencs/view/world/scripthighlighter.cpp | 175 +++---------------- apps/opencs/view/world/scripthighlighter.hpp | 21 ++- apps/opencs/view/world/scriptsubview.cpp | 2 - apps/opencs/view/world/table.cpp | 76 ++++---- apps/opencs/view/world/table.hpp | 7 + 14 files changed, 198 insertions(+), 350 deletions(-) diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 38088c6d7..776839d19 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -16,6 +16,7 @@ #include "../../model/doc/document.hpp" #include "../../model/settings/usersettings.hpp" +#include "../../model/prefs/state.hpp" #include "../../model/world/idtable.hpp" @@ -121,10 +122,9 @@ void CSVDoc::View::setupViewMenu() mShowStatusBar = new QAction (tr ("Show Status Bar"), this); mShowStatusBar->setCheckable (true); connect (mShowStatusBar, SIGNAL (toggled (bool)), this, SLOT (toggleShowStatusBar (bool))); - std::string showStatusBar = - CSMSettings::UserSettings::instance().settingValue("window/show-statusbar").toStdString(); - if(showStatusBar == "true") - mShowStatusBar->setChecked(true); + + mShowStatusBar->setChecked (CSMPrefs::get()["Windows"]["show-statusbar"].isTrue()); + view->addAction (mShowStatusBar); QAction *filters = new QAction (tr ("Filters"), this); @@ -333,9 +333,9 @@ void CSVDoc::View::updateTitle() if (mViewTotal>1) stream << " [" << (mViewIndex+1) << "/" << mViewTotal << "]"; - CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); + CSMPrefs::Category& windows = CSMPrefs::State::get()["Windows"]; - bool hideTitle = userSettings.setting ("window/hide-subview", QString ("false"))=="true" && + bool hideTitle = windows["hide-subview"].isTrue() && mSubViews.size()==1 && !mSubViews.at (0)->isFloating(); if (hideTitle) @@ -346,19 +346,18 @@ void CSVDoc::View::updateTitle() void CSVDoc::View::updateSubViewIndicies(SubView *view) { + CSMPrefs::Category& windows = CSMPrefs::State::get()["Windows"]; + if(view && mSubViews.contains(view)) { mSubViews.removeOne(view); // adjust (reduce) the scroll area (even floating), except when it is "Scrollbar Only" - CSMSettings::UserSettings &settings = CSMSettings::UserSettings::instance(); - if(settings.settingValue ("window/mainwindow-scrollbar") == "Grow then Scroll") + if (windows["mainwindow-scrollbar"].toString() == "Grow then Scroll") updateScrollbar(); } - CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); - - bool hideTitle = userSettings.setting ("window/hide-subview", QString ("false"))=="true" && + bool hideTitle = windows["hide-subview"].isTrue() && mSubViews.size()==1 && !mSubViews.at (0)->isFloating(); updateTitle(); @@ -406,21 +405,16 @@ CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int to : mViewManager (viewManager), mDocument (document), mViewIndex (totalViews-1), mViewTotal (totalViews), mScroll(0), mScrollbarOnly(false) { - int width = CSMSettings::UserSettings::instance().settingValue - ("window/default-width").toInt(); - - int height = CSMSettings::UserSettings::instance().settingValue - ("window/default-height").toInt(); + CSMPrefs::Category& windows = CSMPrefs::State::get()["Windows"]; - width = std::max(width, 300); - height = std::max(height, 300); + int width = std::max (windows["default-width"].toInt(), 300); + int height = std::max (windows["default-height"].toInt(), 300); resize (width, height); mSubViewWindow.setDockOptions (QMainWindow::AllowNestedDocks); - CSMSettings::UserSettings &settings = CSMSettings::UserSettings::instance(); - if(settings.settingValue ("window/mainwindow-scrollbar") == "Grow Only") + if (windows["mainwindow-scrollbar"].toString() == "Grow Only") { setCentralWidget (&mSubViewWindow); } @@ -503,14 +497,12 @@ void CSVDoc::View::updateProgress (int current, int max, int type, int threads) void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id, const std::string& hint) { - CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); + CSMPrefs::Category& windows = CSMPrefs::State::get()["Windows"]; bool isReferenceable = id.getClass() == CSMWorld::UniversalId::Class_RefRecord; // User setting to reuse sub views (on a per top level view basis) - bool reuse = - userSettings.setting ("window/reuse", QString("true")) == "true" ? true : false; - if(reuse) + if (windows["reuse"].isTrue()) { foreach(SubView *sb, mSubViews) { @@ -538,8 +530,7 @@ void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id, const std::strin // // If the sub view limit setting is one, the sub view title bar is hidden and the // text in the main title bar is adjusted accordingly - int maxSubView = userSettings.setting("window/max-subviews", QString("256")).toInt(); - if(mSubViews.size() >= maxSubView) // create a new top level view + if(mSubViews.size() >= windows["max-subviews"].toInt()) // create a new top level view { mViewManager.addView(mDocument, id, hint); @@ -559,8 +550,8 @@ void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id, const std::strin view->setParent(this); mSubViews.append(view); // only after assert - int minWidth = userSettings.setting ("window/minimum-width", QString("325")).toInt(); - view->setMinimumWidth(minWidth); + int minWidth = windows["minimum-width"].toInt(); + view->setMinimumWidth (minWidth); view->setStatusBar (mShowStatusBar->isChecked()); @@ -575,13 +566,11 @@ void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id, const std::strin // should become visible) // - Move the scroll bar to the newly added subview // - CSMSettings::UserSettings &settings = CSMSettings::UserSettings::instance(); - QString mainwinScroll = settings.settingValue ("window/mainwindow-scrollbar"); - mScrollbarOnly = mainwinScroll.isEmpty() || mainwinScroll == "Scrollbar Only"; + mScrollbarOnly = windows["mainwindow-scrollbar"].toString() == "Scrollbar Only"; QDesktopWidget *dw = QApplication::desktop(); QRect rect; - if(settings.settingValue ("window/grow-limit") == "true") + if (windows["grow-limit"].isTrue()) rect = dw->screenGeometry(this); else rect = dw->screenGeometry(dw->screen(dw->screenNumber(this))); @@ -862,6 +851,7 @@ void CSVDoc::View::resizeViewHeight (int height) void CSVDoc::View::updateUserSetting (const QString &name, const QStringList &list) { + if (name=="window/hide-subview") updateSubViewIndicies (0); @@ -944,10 +934,9 @@ void CSVDoc::View::stop() void CSVDoc::View::closeRequest (SubView *subView) { - CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); + CSMPrefs::Category& windows = CSMPrefs::State::get()["Windows"]; - if (mSubViews.size()>1 || mViewTotal<=1 || - userSettings.setting ("window/hide-subview", QString ("false"))!="true") + if (mSubViews.size()>1 || mViewTotal<=1 || !windows["hide-subview"].isTrue()) { subView->deleteLater(); mSubViews.removeOne (subView); diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 0deb49840..46e2bc2e0 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -20,7 +20,7 @@ #include "../../model/world/universalid.hpp" #include "../../model/world/idtable.hpp" -#include "../../model/settings/usersettings.hpp" +#include "../../model/prefs/state.hpp" #include "../widget/scenetoolmode.hpp" #include "../widget/scenetooltoggle2.hpp" @@ -31,17 +31,6 @@ #include "editmode.hpp" #include "instancemode.hpp" -namespace -{ - static const char * const sMappingSettings[] = - { - "p-navi", "s-navi", - "p-edit", "s-edit", - "p-select", "s-select", - 0 - }; -} - CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidget* parent) : SceneWidget (document.getData().getResourceSystem(), parent), mSceneElements(0), mRun(0), mDocument(document), mInteractionMask (0), mEditMode (0), mLocked (false), mDragging (false), @@ -77,19 +66,10 @@ CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidg connect (debugProfiles, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)), this, SLOT (debugProfileAboutToBeRemoved (const QModelIndex&, int, int))); - for (int i=0; sMappingSettings[i]; ++i) - { - QString key ("scene-input/"); - key += sMappingSettings[i]; - storeMappingSetting (key, CSMSettings::UserSettings::instance().settingValue (key)); - } - - mDragFactor = CSMSettings::UserSettings::instance().settingValue ("scene-input/drag-factor").toDouble(); - mDragWheelFactor = CSMSettings::UserSettings::instance().settingValue ("scene-input/drag-wheel-factor").toDouble(); - mDragShiftFactor = CSMSettings::UserSettings::instance().settingValue ("scene-input/drag-shift-factor").toDouble(); - - mShowToolTips = CSMSettings::UserSettings::instance().settingValue ("tooltips/scene") == "true"; - mToolTipDelay = CSMSettings::UserSettings::instance().settingValue ("tooltips/scene-delay").toInt(); + connect (&CSMPrefs::State::get(), SIGNAL (settingChanged (const CSMPrefs::Setting *)), + this, SLOT (settingChanged (const CSMPrefs::Setting *))); + CSMPrefs::get()["3D Scene Input"].update(); + CSMPrefs::get()["Tooltips"].update(); mToolTipDelayTimer.setSingleShot (true); connect (&mToolTipDelayTimer, SIGNAL (timeout()), this, SLOT (showToolTip())); @@ -99,6 +79,23 @@ CSVRender::WorldspaceWidget::~WorldspaceWidget () { } +void CSVRender::WorldspaceWidget::settingChanged (const CSMPrefs::Setting *setting) +{ + if (storeMappingSetting (setting)) + return; + + if (*setting=="3D Scene Input/drag-factor") + mDragFactor = setting->toDouble(); + else if (*setting=="3D Scene Input/drag-wheel-factor") + mDragWheelFactor = setting->toDouble(); + else if (*setting=="3D Scene Input/drag-shift-factor") + mDragShiftFactor = setting->toDouble(); + else if (*setting=="Tooltips/scene-delay") + mToolTipDelay = setting->toInt(); + else if (*setting=="Tooltips/scene") + mShowToolTips = setting->isTrue(); +} + void CSVRender::WorldspaceWidget::selectNavigationMode (const std::string& mode) { if (mode=="1st") @@ -291,25 +288,6 @@ unsigned int CSVRender::WorldspaceWidget::getInteractionMask() const return mInteractionMask & getVisibilityMask(); } -void CSVRender::WorldspaceWidget::updateUserSetting (const QString& name, const QStringList& value) -{ - if (!value.isEmpty() && storeMappingSetting (name, value.first())) - return; - - if (name=="scene-input/drag-factor") - mDragFactor = value.at (0).toDouble(); - else if (name=="scene-input/drag-wheel-factor") - mDragWheelFactor = value.at (0).toDouble(); - else if (name=="scene-input/drag-shift-factor") - mDragShiftFactor = value.at (0).toDouble(); - else if (name=="tooltips/scene-delay") - mToolTipDelay = value.at (0).toInt(); - else if (name=="tooltips/scene") - mShowToolTips = value.at (0)=="true"; - else - dynamic_cast (*mEditMode->getCurrent()).updateUserSetting (name, value); -} - void CSVRender::WorldspaceWidget::setEditLock (bool locked) { dynamic_cast (*mEditMode->getCurrent()).setEditLock (locked); @@ -348,34 +326,40 @@ void CSVRender::WorldspaceWidget::dragMoveEvent(QDragMoveEvent *event) } -bool CSVRender::WorldspaceWidget::storeMappingSetting (const QString& key, const QString& value) +bool CSVRender::WorldspaceWidget::storeMappingSetting (const CSMPrefs::Setting *setting) { - const QString prefix = "scene-input/"; + if (setting->getParent()->getKey()!="3D Scene Input") + return false; - if (key.startsWith (prefix)) + static const char * const sMappingSettings[] = { - QString key2 (key.mid (prefix.length())); + "p-navi", "s-navi", + "p-edit", "s-edit", + "p-select", "s-select", + 0 + }; - for (int i=0; sMappingSettings[i]; ++i) - if (key2==sMappingSettings[i]) - { - Qt::MouseButton button = Qt::NoButton; + for (int i=0; sMappingSettings[i]; ++i) + if (setting->getKey()==sMappingSettings[i]) + { + QString value = QString::fromUtf8 (setting->toString().c_str()); - if (value.endsWith ("Left Mouse-Button")) - button = Qt::LeftButton; - else if (value.endsWith ("Right Mouse-Button")) - button = Qt::RightButton; - else if (value.endsWith ("Middle Mouse-Button")) - button = Qt::MiddleButton; - else - return false; + Qt::MouseButton button = Qt::NoButton; - bool ctrl = value.startsWith ("Ctrl-"); + if (value.endsWith ("Left Mouse-Button")) + button = Qt::LeftButton; + else if (value.endsWith ("Right Mouse-Button")) + button = Qt::RightButton; + else if (value.endsWith ("Middle Mouse-Button")) + button = Qt::MiddleButton; + else + return false; - mButtonMapping[std::make_pair (button, ctrl)] = sMappingSettings[i]; - return true; - } - } + bool ctrl = value.startsWith ("Ctrl-"); + + mButtonMapping[std::make_pair (button, ctrl)] = sMappingSettings[i]; + return true; + } return false; } @@ -514,8 +498,7 @@ void CSVRender::WorldspaceWidget::showToolTip() if (osg::ref_ptr tag = mousePick (mapFromGlobal (pos))) { - bool hideBasics = - CSMSettings::UserSettings::instance().settingValue ("tooltips/scene-hide-basic")=="true"; + bool hideBasics = CSMPrefs::get()["Tooltips"]["scene-hide-basic"].isTrue(); QToolTip::showText (pos, tag->getToolTip (hideBasics), this); } } diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp index 0b5ae2523..54376cee4 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -13,6 +13,11 @@ #include "scenewidget.hpp" #include "elements.hpp" +namespace CSMPrefs +{ + class Setting; +} + namespace CSMWorld { class UniversalId; @@ -115,8 +120,6 @@ namespace CSVRender /// marked for interaction. unsigned int getInteractionMask() const; - virtual void updateUserSetting (const QString& name, const QStringList& value); - virtual void setEditLock (bool locked); CSMDoc::Document& getDocument(); @@ -151,7 +154,7 @@ namespace CSVRender void dragMoveEvent(QDragMoveEvent *event); /// \return Is \a key a button mapping setting? (ignored otherwise) - bool storeMappingSetting (const QString& key, const QString& value); + bool storeMappingSetting (const CSMPrefs::Setting *setting); osg::ref_ptr mousePick (const QPoint& localPos); @@ -161,6 +164,8 @@ namespace CSVRender private slots: + void settingChanged (const CSMPrefs::Setting *setting); + void selectNavigationMode (const std::string& mode); virtual void referenceableDataChanged (const QModelIndex& topLeft, diff --git a/apps/opencs/view/world/scenesubview.cpp b/apps/opencs/view/world/scenesubview.cpp index 753d791c0..44fe94d84 100644 --- a/apps/opencs/view/world/scenesubview.cpp +++ b/apps/opencs/view/world/scenesubview.cpp @@ -147,12 +147,6 @@ std::string CSVWorld::SceneSubView::getTitle() const return mTitle; } -void CSVWorld::SceneSubView::updateUserSetting (const QString& name, const QStringList& value) -{ - mScene->updateUserSetting (name, value); - CSVDoc::SubView::updateUserSetting (name, value); -} - void CSVWorld::SceneSubView::cellSelectionChanged (const CSMWorld::UniversalId& id) { setUniversalId(id); diff --git a/apps/opencs/view/world/scenesubview.hpp b/apps/opencs/view/world/scenesubview.hpp index 2458d58f4..0f18e8c30 100644 --- a/apps/opencs/view/world/scenesubview.hpp +++ b/apps/opencs/view/world/scenesubview.hpp @@ -59,8 +59,6 @@ namespace CSVWorld virtual std::string getTitle() const; - virtual void updateUserSetting (const QString& name, const QStringList& value); - private: void makeConnections(CSVRender::PagedWorldspaceWidget* widget); diff --git a/apps/opencs/view/world/scriptedit.cpp b/apps/opencs/view/world/scriptedit.cpp index 25f4fd077..9f1abcf97 100644 --- a/apps/opencs/view/world/scriptedit.cpp +++ b/apps/opencs/view/world/scriptedit.cpp @@ -12,8 +12,7 @@ #include "../../model/world/universalid.hpp" #include "../../model/world/tablemimedata.hpp" -#include "../../model/settings/usersettings.hpp" - +#include "../../model/prefs/state.hpp" CSVWorld::ScriptEdit::ChangeLock::ChangeLock (ScriptEdit& edit) : mEdit (edit) { @@ -92,31 +91,24 @@ CSVWorld::ScriptEdit::ScriptEdit (const CSMDoc::Document& document, ScriptHighli connect (&mUpdateTimer, SIGNAL (timeout()), this, SLOT (updateHighlighting())); - CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); - connect (&userSettings, SIGNAL (userSettingUpdated(const QString &, const QStringList &)), - this, SLOT (updateUserSetting (const QString &, const QStringList &))); + connect (&CSMPrefs::State::get(), SIGNAL (settingChanged (const CSMPrefs::Setting *)), + this, SLOT (settingChanged (const CSMPrefs::Setting *))); + { + ChangeLock lock (*this); + CSMPrefs::get()["Scripts"].update(); + } mUpdateTimer.setSingleShot (true); // TODO: provide a font selector dialogue mMonoFont.setStyleHint(QFont::TypeWriter); - if (userSettings.setting("script-editor/mono-font", "true") == "true") - setFont(mMonoFont); - mLineNumberArea = new LineNumberArea(this); updateLineNumberAreaWidth(0); connect(this, SIGNAL(blockCountChanged(int)), this, SLOT(updateLineNumberAreaWidth(int))); connect(this, SIGNAL(updateRequest(QRect,int)), this, SLOT(updateLineNumberArea(QRect,int))); - - showLineNum(userSettings.settingValue("script-editor/show-linenum") == "true"); -} - -void CSVWorld::ScriptEdit::updateUserSetting (const QString &name, const QStringList &list) -{ - if (mHighlighter->updateUserSetting (name, list)) - updateHighlighting(); + updateHighlighting(); } void CSVWorld::ScriptEdit::showLineNum(bool show) @@ -202,6 +194,16 @@ bool CSVWorld::ScriptEdit::stringNeedsQuote (const std::string& id) const return !(string.contains(mWhiteListQoutes)); } +void CSVWorld::ScriptEdit::settingChanged (const CSMPrefs::Setting *setting) +{ + if (mHighlighter->settingChanged (setting)) + updateHighlighting(); + else if (*setting=="Scripts/mono-font") + setFont (setting->isTrue() ? mMonoFont : mDefaultFont); + else if (*setting=="Scripts/show-linenum") + showLineNum (setting->isTrue()); +} + void CSVWorld::ScriptEdit::idListChanged() { mHighlighter->invalidateIds(); diff --git a/apps/opencs/view/world/scriptedit.hpp b/apps/opencs/view/world/scriptedit.hpp index d17abf24e..941a6295d 100644 --- a/apps/opencs/view/world/scriptedit.hpp +++ b/apps/opencs/view/world/scriptedit.hpp @@ -91,6 +91,8 @@ namespace CSVWorld private slots: + void settingChanged (const CSMPrefs::Setting *setting); + void idListChanged(); void updateHighlighting(); @@ -98,10 +100,6 @@ namespace CSVWorld void updateLineNumberAreaWidth(int newBlockCount); void updateLineNumberArea(const QRect &, int); - - public slots: - - void updateUserSetting (const QString &name, const QStringList &list); }; class LineNumberArea : public QWidget diff --git a/apps/opencs/view/world/scripterrortable.cpp b/apps/opencs/view/world/scripterrortable.cpp index a9e315c73..b439e0df3 100644 --- a/apps/opencs/view/world/scripterrortable.cpp +++ b/apps/opencs/view/world/scripterrortable.cpp @@ -9,7 +9,8 @@ #include #include "../../model/doc/document.hpp" -#include "../../model/settings/usersettings.hpp" + +#include "../../model/prefs/state.hpp" void CSVWorld::ScriptErrorTable::report (const std::string& message, const Compiler::TokenLoc& loc, Type type) { @@ -57,7 +58,7 @@ void CSVWorld::ScriptErrorTable::addMessage (const std::string& message, setItem (row, 2, messageItem); } -void CSVWorld::ScriptErrorTable::setWarningsMode (const QString& value) +void CSVWorld::ScriptErrorTable::setWarningsMode (const std::string& value) { if (value=="Ignore") Compiler::ErrorHandler::setWarningsMode (0); @@ -91,17 +92,13 @@ CSVWorld::ScriptErrorTable::ScriptErrorTable (const CSMDoc::Document& document, Compiler::registerExtensions (mExtensions); mContext.setExtensions (&mExtensions); - setWarningsMode (CSMSettings::UserSettings::instance().settingValue ("script-editor/warnings")); + connect (&CSMPrefs::State::get(), SIGNAL (settingChanged (const CSMPrefs::Setting *)), + this, SLOT (settingChanged (const CSMPrefs::Setting *))); + CSMPrefs::get()["Scripts"].update(); connect (this, SIGNAL (cellClicked (int, int)), this, SLOT (cellClicked (int, int))); } -void CSVWorld::ScriptErrorTable::updateUserSetting (const QString& name, const QStringList& value) -{ - if (name=="script-editor/warnings" && !value.isEmpty()) - setWarningsMode (value.at (0)); -} - void CSVWorld::ScriptErrorTable::update (const std::string& source) { clear(); @@ -136,6 +133,12 @@ bool CSVWorld::ScriptErrorTable::clearLocals (const std::string& script) return mContext.clearLocals (script); } +void CSVWorld::ScriptErrorTable::settingChanged (const CSMPrefs::Setting *setting) +{ + if (*setting=="Scripst/warnings") + setWarningsMode (setting->toString()); +} + void CSVWorld::ScriptErrorTable::cellClicked (int row, int column) { if (item (row, 1)) diff --git a/apps/opencs/view/world/scripterrortable.hpp b/apps/opencs/view/world/scripterrortable.hpp index 33af7c864..4841aac5b 100644 --- a/apps/opencs/view/world/scripterrortable.hpp +++ b/apps/opencs/view/world/scripterrortable.hpp @@ -14,6 +14,11 @@ namespace CSMDoc class Document; } +namespace CSMPrefs +{ + class Setting; +} + namespace CSVWorld { class ScriptErrorTable : public QTableWidget, private Compiler::ErrorHandler @@ -32,14 +37,12 @@ namespace CSVWorld void addMessage (const std::string& message, CSMDoc::Message::Severity severity, int line = -1, int column = -1); - void setWarningsMode (const QString& value); + void setWarningsMode (const std::string& value); public: ScriptErrorTable (const CSMDoc::Document& document, QWidget *parent = 0); - void updateUserSetting (const QString& name, const QStringList& value); - void update (const std::string& source); void clear(); @@ -51,6 +54,8 @@ namespace CSVWorld private slots: + void settingChanged (const CSMPrefs::Setting *setting); + void cellClicked (int row, int column); signals: diff --git a/apps/opencs/view/world/scripthighlighter.cpp b/apps/opencs/view/world/scripthighlighter.cpp index 487b5b139..846a61b47 100644 --- a/apps/opencs/view/world/scripthighlighter.cpp +++ b/apps/opencs/view/world/scripthighlighter.cpp @@ -5,7 +5,8 @@ #include #include -#include "../../model/settings/usersettings.hpp" +#include "../../model/prefs/setting.hpp" +#include "../../model/prefs/category.hpp" bool CSVWorld::ScriptHighlighter::parseInt (int value, const Compiler::TokenLoc& loc, Compiler::Scanner& scanner) @@ -79,79 +80,12 @@ CSVWorld::ScriptHighlighter::ScriptHighlighter (const CSMWorld::Data& data, Mode : QSyntaxHighlighter (parent), Compiler::Parser (mErrorHandler, mContext), mContext (data), mMode (mode) { - CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); + QColor color ("black"); + QTextCharFormat format; + format.setForeground (color); - QColor color = QColor(); - - { - color.setNamedColor(userSettings.setting("script-editor/colour-int", "Dark magenta")); - if (!color.isValid()) - color = QColor(Qt::darkMagenta); - - QTextCharFormat format; - format.setForeground (color); - mScheme.insert (std::make_pair (Type_Int, format)); - } - - { - color.setNamedColor(userSettings.setting ("script-editor/colour-float", "Magenta")); - if (!color.isValid()) - color = QColor(Qt::magenta); - - QTextCharFormat format; - format.setForeground (color); - mScheme.insert (std::make_pair (Type_Float, format)); - } - - { - color.setNamedColor(userSettings.setting ("script-editor/colour-name", "Gray")); - if (!color.isValid()) - color = QColor(Qt::gray); - - QTextCharFormat format; - format.setForeground (color); - mScheme.insert (std::make_pair (Type_Name, format)); - } - - { - color.setNamedColor(userSettings.setting ("script-editor/colour-keyword", "Red")); - if (!color.isValid()) - color = QColor(Qt::red); - - QTextCharFormat format; - format.setForeground (color); - mScheme.insert (std::make_pair (Type_Keyword, format)); - } - - { - color.setNamedColor(userSettings.setting ("script-editor/colour-special", "Dark yellow")); - if (!color.isValid()) - color = QColor(Qt::darkYellow); - - QTextCharFormat format; - format.setForeground (color); - mScheme.insert (std::make_pair (Type_Special, format)); - } - - { - color.setNamedColor(userSettings.setting ("script-editor/colour-comment", "Green")); - if (!color.isValid()) - color = QColor(Qt::green); - - QTextCharFormat format; - format.setForeground (color); - mScheme.insert (std::make_pair (Type_Comment, format)); - } - - { - color.setNamedColor(userSettings.setting ("script-editor/colour-id", "Blue")); - if (!color.isValid()) - color = QColor(Qt::blue); - - QTextCharFormat format; - format.setForeground (color); - mScheme.insert (std::make_pair (Type_Id, format)); - } + for (int i=0; i<=Type_Id; ++i) + mScheme.insert (std::make_pair (static_cast (i), format)); // configure compiler Compiler::registerExtensions (mExtensions); @@ -176,85 +110,26 @@ void CSVWorld::ScriptHighlighter::invalidateIds() mContext.invalidateIds(); } -bool CSVWorld::ScriptHighlighter::updateUserSetting (const QString &name, const QStringList &list) +bool CSVWorld::ScriptHighlighter::settingChanged (const CSMPrefs::Setting *setting) { - if (list.empty()) - return false; - - QColor color = QColor(); - - if (name == "script-editor/colour-int") + if (setting->getParent()->getKey()=="Scripts") { - color.setNamedColor(list.at(0)); - if (!color.isValid()) - return false; - - QTextCharFormat format; - format.setForeground (color); - mScheme[Type_Int] = format; + static const char *const colours[Type_Id+2] = + { + "colour-int", "colour-float", "colour-name", "colour-keyword", + "colour-special", "colour-comment", "colour-id", + 0 + }; + + for (int i=0; colours[i]; ++i) + if (setting->getKey()==colours[i]) + { + QTextCharFormat format; + format.setForeground (setting->toColor()); + mScheme[static_cast (i)] = format; + return true; + } } - else if (name == "script-editor/colour-float") - { - color.setNamedColor(list.at(0)); - if (!color.isValid()) - return false; - - QTextCharFormat format; - format.setForeground (color); - mScheme[Type_Float] = format; - } - else if (name == "script-editor/colour-name") - { - color.setNamedColor(list.at(0)); - if (!color.isValid()) - return false; - - QTextCharFormat format; - format.setForeground (color); - mScheme[Type_Name] = format; - } - else if (name == "script-editor/colour-keyword") - { - color.setNamedColor(list.at(0)); - if (!color.isValid()) - return false; - QTextCharFormat format; - format.setForeground (color); - mScheme[Type_Keyword] = format; - } - else if (name == "script-editor/colour-special") - { - color.setNamedColor(list.at(0)); - if (!color.isValid()) - return false; - - QTextCharFormat format; - format.setForeground (color); - mScheme[Type_Special] = format; - } - else if (name == "script-editor/colour-comment") - { - color.setNamedColor(list.at(0)); - if (!color.isValid()) - return false; - - QTextCharFormat format; - format.setForeground (color); - mScheme[Type_Comment] = format; - } - else if (name == "script-editor/colour-id") - { - color.setNamedColor(list.at(0)); - if (!color.isValid()) - return false; - - QTextCharFormat format; - format.setForeground (color); - mScheme[Type_Id] = format; - } - else - return false; - - return true; + return false; } diff --git a/apps/opencs/view/world/scripthighlighter.hpp b/apps/opencs/view/world/scripthighlighter.hpp index 6f1f58e82..33824da0d 100644 --- a/apps/opencs/view/world/scripthighlighter.hpp +++ b/apps/opencs/view/world/scripthighlighter.hpp @@ -11,6 +11,11 @@ #include "../../model/world/scriptcontext.hpp" +namespace CSMPrefs +{ + class Setting; +} + namespace CSVWorld { class ScriptHighlighter : public QSyntaxHighlighter, private Compiler::Parser @@ -19,13 +24,13 @@ namespace CSVWorld enum Type { - Type_Int, - Type_Float, - Type_Name, - Type_Keyword, - Type_Special, - Type_Comment, - Type_Id + Type_Int = 0, + Type_Float = 1, + Type_Name = 2, + Type_Keyword = 3, + Type_Special = 4, + Type_Comment = 5, + Type_Id = 6 }; enum Mode @@ -88,7 +93,7 @@ namespace CSVWorld void invalidateIds(); - bool updateUserSetting (const QString &name, const QStringList &list); + bool settingChanged (const CSMPrefs::Setting *setting); }; } diff --git a/apps/opencs/view/world/scriptsubview.cpp b/apps/opencs/view/world/scriptsubview.cpp index bd66f2bf6..eb8bd2e29 100644 --- a/apps/opencs/view/world/scriptsubview.cpp +++ b/apps/opencs/view/world/scriptsubview.cpp @@ -194,8 +194,6 @@ void CSVWorld::ScriptSubView::updateUserSetting (const QString& name, const QStr if (mButtons) mButtons->updateUserSetting (name, value); - mErrors->updateUserSetting (name, value); - if (name=="script-editor/warnings") recompile(); } diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index 73bef7b26..ba8c4ae56 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -23,7 +23,7 @@ #include "../../model/world/tablemimedata.hpp" #include "../../model/world/tablemimedata.hpp" #include "../../model/world/commanddispatcher.hpp" -#include "../../model/settings/usersettings.hpp" +#include "../../model/prefs/state.hpp" #include "recordstatusdelegate.hpp" #include "tableeditidaction.hpp" @@ -232,23 +232,9 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id, : DragRecordTable(document), mCreateAction (0), mCloneAction(0),mRecordStatusDisplay (0) { - CSMSettings::UserSettings &settings = CSMSettings::UserSettings::instance(); - QString jumpSetting = settings.settingValue ("table-input/jump-to-added"); - if (jumpSetting.isEmpty() || jumpSetting == "Jump and Select") // default - { - mJumpToAddedRecord = true; - mUnselectAfterJump = false; - } - else if(jumpSetting == "Jump Only") - { - mJumpToAddedRecord = true; - mUnselectAfterJump = true; - } - else - { - mJumpToAddedRecord = false; - mUnselectAfterJump = false; - } + connect (&CSMPrefs::State::get(), SIGNAL (settingChanged (const CSMPrefs::Setting *)), + this, SLOT (settingChanged (const CSMPrefs::Setting *))); + CSMPrefs::get()["ID Tables"].update(); mModel = &dynamic_cast (*mDocument.getData().getTableModel (id)); @@ -358,7 +344,7 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id, //connect (mProxyModel, SIGNAL (rowsInserted (const QModelIndex&, int, int)), // this, SLOT (rowsInsertedEvent(const QModelIndex&, int, int))); - connect (mProxyModel, SIGNAL (rowAdded (const std::string &)), + connect (mProxyModel, SIGNAL (rowAdded (const std::string &)), this, SLOT (rowAdded (const std::string &))); /// \note This signal could instead be connected to a slot that filters out changes not affecting @@ -404,7 +390,7 @@ std::vector CSVWorld::Table::getSelectedIds() const QModelIndexList selectedRows = selectionModel()->selectedRows(); int columnIndex = mModel->findColumnIndex (CSMWorld::Columns::ColumnId_Id); - for (QModelIndexList::const_iterator iter (selectedRows.begin()); + for (QModelIndexList::const_iterator iter (selectedRows.begin()); iter != selectedRows.end(); ++iter) { @@ -548,9 +534,7 @@ void CSVWorld::Table::previewRecord() void CSVWorld::Table::executeExtendedDelete() { - CSMSettings::UserSettings &settings = CSMSettings::UserSettings::instance(); - QString configSetting = settings.settingValue ("table-input/extended-config"); - if (configSetting == "true") + if (CSMPrefs::get()["ID Tables"]["extended-config"].isTrue()) { emit extendedDeleteConfigRequest(getSelectedIds()); } @@ -562,9 +546,7 @@ void CSVWorld::Table::executeExtendedDelete() void CSVWorld::Table::executeExtendedRevert() { - CSMSettings::UserSettings &settings = CSMSettings::UserSettings::instance(); - QString configSetting = settings.settingValue ("table-input/extended-config"); - if (configSetting == "true") + if (CSMPrefs::get()["ID Tables"]["extended-config"].isTrue()) { emit extendedRevertConfigRequest(getSelectedIds()); } @@ -576,25 +558,6 @@ void CSVWorld::Table::executeExtendedRevert() void CSVWorld::Table::updateUserSetting (const QString &name, const QStringList &list) { - if (name=="table-input/jump-to-added") - { - if(list.isEmpty() || list.at(0) == "Jump and Select") // default - { - mJumpToAddedRecord = true; - mUnselectAfterJump = false; - } - else if(list.at(0) == "Jump Only") - { - mJumpToAddedRecord = true; - mUnselectAfterJump = true; - } - else // No Jump - { - mJumpToAddedRecord = false; - mUnselectAfterJump = false; - } - } - if (name=="records/type-format" || name=="records/status-format") { int columns = mModel->columnCount(); @@ -650,6 +613,29 @@ void CSVWorld::Table::updateUserSetting (const QString &name, const QStringList } } +void CSVWorld::Table::settingChanged (const CSMPrefs::Setting *setting) +{ + if (*setting=="ID Tables/jump-to-added") + { + if (setting->toString()=="Jump and Select") + { + mJumpToAddedRecord = true; + mUnselectAfterJump = false; + } + else if (setting->toString()=="Jump Only") + { + mJumpToAddedRecord = true; + mUnselectAfterJump = true; + } + else // No Jump + { + mJumpToAddedRecord = false; + mUnselectAfterJump = false; + } + } + +} + void CSVWorld::Table::tableSizeUpdate() { int size = 0; diff --git a/apps/opencs/view/world/table.hpp b/apps/opencs/view/world/table.hpp index 95a25075d..53401a192 100644 --- a/apps/opencs/view/world/table.hpp +++ b/apps/opencs/view/world/table.hpp @@ -27,6 +27,11 @@ namespace CSMWorld class CommandDispatcher; } +namespace CSMPrefs +{ + class Setting; +} + namespace CSVWorld { class CommandDelegate; @@ -140,6 +145,8 @@ namespace CSVWorld public slots: + void settingChanged (const CSMPrefs::Setting *setting); + void tableSizeUpdate(); void selectionSizeUpdate(); From 850092a5e576c278f85edd99686813f3e8629282 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 11 Dec 2015 17:22:46 +0100 Subject: [PATCH 2794/3725] Store: be consistent about struct / class usage Don't inherit a struct from a class, and vice versa. --- apps/openmw/mwworld/store.hpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index 88457c950..617c3552a 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -27,8 +27,9 @@ namespace MWWorld RecordId(const std::string &id = "", bool isDeleted = false); }; - struct StoreBase + class StoreBase { + public: virtual ~StoreBase() {} virtual void setUp() {} @@ -351,14 +352,16 @@ namespace MWWorld template <> - struct Store : public IndexedStore + class Store : public IndexedStore { + public: Store(); }; template <> - struct Store : public IndexedStore + class Store : public IndexedStore { + public: Store(); }; From 18cce3a6f912e6fa56aa0d125c687e7debefc1c7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 12 Dec 2015 22:33:14 +0100 Subject: [PATCH 2795/3725] Don't reset delete flag when loading reference from a save game (Fixes #2724) --- apps/openmw/mwworld/livecellref.cpp | 2 +- apps/openmw/mwworld/refdata.cpp | 4 ++-- apps/openmw/mwworld/refdata.hpp | 12 ++++++++---- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwworld/livecellref.cpp b/apps/openmw/mwworld/livecellref.cpp index bfc708185..dcd6da431 100644 --- a/apps/openmw/mwworld/livecellref.cpp +++ b/apps/openmw/mwworld/livecellref.cpp @@ -19,7 +19,7 @@ MWWorld::LiveCellRefBase::LiveCellRefBase(std::string type, const ESM::CellRef & void MWWorld::LiveCellRefBase::loadImp (const ESM::ObjectState& state) { mRef = state.mRef; - mData = RefData (state); + mData = RefData (state, mData.isDeletedByContentFile()); Ptr ptr (this); diff --git a/apps/openmw/mwworld/refdata.cpp b/apps/openmw/mwworld/refdata.cpp index 997b3fc94..6a127085c 100644 --- a/apps/openmw/mwworld/refdata.cpp +++ b/apps/openmw/mwworld/refdata.cpp @@ -49,8 +49,8 @@ namespace MWWorld { } - RefData::RefData (const ESM::ObjectState& objectState) - : mBaseNode(0), mDeleted(false), + RefData::RefData (const ESM::ObjectState& objectState, bool deleted) + : mBaseNode(0), mDeleted(deleted), mEnabled (objectState.mEnabled != 0), mCount (objectState.mCount), mPosition (objectState.mPosition), diff --git a/apps/openmw/mwworld/refdata.hpp b/apps/openmw/mwworld/refdata.hpp index 19c31a14b..fbb951c5a 100644 --- a/apps/openmw/mwworld/refdata.hpp +++ b/apps/openmw/mwworld/refdata.hpp @@ -30,10 +30,14 @@ namespace MWWorld MWScript::Locals mLocals; - bool mDeleted; // separate delete flag used for deletion by a content file + /// separate delete flag used for deletion by a content file + /// @note not stored in the save game file. + bool mDeleted; + bool mEnabled; - int mCount; // 0: deleted + /// 0: deleted + int mCount; ESM::Position mPosition; @@ -51,10 +55,10 @@ namespace MWWorld /// @param cellRef Used to copy constant data such as position into this class where it can /// be altered without affecting the original data. This makes it possible - /// to reset the position as the orignal data is still held in the CellRef + /// to reset the position as the original data is still held in the CellRef RefData (const ESM::CellRef& cellRef); - RefData (const ESM::ObjectState& objectState); + RefData (const ESM::ObjectState& objectState, bool deleted); ///< Ignores local variables and custom data (not enough context available here to /// perform these operations). From 359b0b377271efb985bcfda20ed3344a58e50820 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 12 Dec 2015 22:37:23 +0100 Subject: [PATCH 2796/3725] Rename for clarity --- apps/openmw/mwworld/cellstore.cpp | 2 +- apps/openmw/mwworld/refdata.cpp | 18 +++++++++--------- apps/openmw/mwworld/refdata.hpp | 6 +++--- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 2173820ad..164ce5533 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -184,7 +184,7 @@ namespace MWWorld LiveRef liveCellRef (ref, ptr); if (deleted) - liveCellRef.mData.setDeleted(true); + liveCellRef.mData.setDeletedByContentFile(true); if (iter != mList.end()) *iter = liveCellRef; diff --git a/apps/openmw/mwworld/refdata.cpp b/apps/openmw/mwworld/refdata.cpp index 6a127085c..56abba165 100644 --- a/apps/openmw/mwworld/refdata.cpp +++ b/apps/openmw/mwworld/refdata.cpp @@ -18,7 +18,7 @@ namespace MWWorld mCount = refData.mCount; mPosition = refData.mPosition; mChanged = refData.mChanged; - mDeleted = refData.mDeleted; + mDeletedByContentFile = refData.mDeletedByContentFile; mCustomData = refData.mCustomData ? refData.mCustomData->clone() : 0; } @@ -32,7 +32,7 @@ namespace MWWorld } RefData::RefData() - : mBaseNode(0), mDeleted(false), mEnabled (true), mCount (1), mCustomData (0), mChanged(false) + : mBaseNode(0), mDeletedByContentFile(false), mEnabled (true), mCount (1), mCustomData (0), mChanged(false) { for (int i=0; i<3; ++i) { @@ -42,15 +42,15 @@ namespace MWWorld } RefData::RefData (const ESM::CellRef& cellRef) - : mBaseNode(0), mDeleted(false), mEnabled (true), + : mBaseNode(0), mDeletedByContentFile(false), mEnabled (true), mCount (1), mPosition (cellRef.mPos), mCustomData (0), mChanged(false) // Loading from ESM/ESP files -> assume unchanged { } - RefData::RefData (const ESM::ObjectState& objectState, bool deleted) - : mBaseNode(0), mDeleted(deleted), + RefData::RefData (const ESM::ObjectState& objectState, bool deletedByContentFile) + : mBaseNode(0), mDeletedByContentFile(deletedByContentFile), mEnabled (objectState.mEnabled != 0), mCount (objectState.mCount), mPosition (objectState.mPosition), @@ -139,19 +139,19 @@ namespace MWWorld mCount = count; } - void RefData::setDeleted(bool deleted) + void RefData::setDeletedByContentFile(bool deleted) { - mDeleted = deleted; + mDeletedByContentFile = deleted; } bool RefData::isDeleted() const { - return mDeleted || mCount == 0; + return mDeletedByContentFile || mCount == 0; } bool RefData::isDeletedByContentFile() const { - return mDeleted; + return mDeletedByContentFile; } MWScript::Locals& RefData::getLocals() diff --git a/apps/openmw/mwworld/refdata.hpp b/apps/openmw/mwworld/refdata.hpp index fbb951c5a..5421ea963 100644 --- a/apps/openmw/mwworld/refdata.hpp +++ b/apps/openmw/mwworld/refdata.hpp @@ -32,7 +32,7 @@ namespace MWWorld /// separate delete flag used for deletion by a content file /// @note not stored in the save game file. - bool mDeleted; + bool mDeletedByContentFile; bool mEnabled; @@ -58,7 +58,7 @@ namespace MWWorld /// to reset the position as the original data is still held in the CellRef RefData (const ESM::CellRef& cellRef); - RefData (const ESM::ObjectState& objectState, bool deleted); + RefData (const ESM::ObjectState& objectState, bool deletedByContentFile); ///< Ignores local variables and custom data (not enough context available here to /// perform these operations). @@ -91,7 +91,7 @@ namespace MWWorld /// This flag is only used for content stack loading and will not be stored in the savegame. /// If the object was deleted by gameplay, then use setCount(0) instead. - void setDeleted(bool deleted); + void setDeletedByContentFile(bool deleted); /// Returns true if the object was either deleted by the content file or by gameplay. bool isDeleted() const; From 295563ba6594d991242e749f370f8b7d1f93c3f6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 12 Dec 2015 18:33:55 +0100 Subject: [PATCH 2797/3725] Minor fix --- components/resource/niffilemanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/resource/niffilemanager.cpp b/components/resource/niffilemanager.cpp index fd25c1c40..17165bcda 100644 --- a/components/resource/niffilemanager.cpp +++ b/components/resource/niffilemanager.cpp @@ -55,7 +55,7 @@ namespace Resource return static_cast(obj.get())->mNifFile; else { - Nif::NIFFilePtr file (new Nif::NIFFile(mVFS->get(name), name)); + Nif::NIFFilePtr file (new Nif::NIFFile(mVFS->getNormalized(name), name)); obj = new NifFileHolder(file); mCache->addEntryToObjectCache(name, obj); return file; From 64424e72626bff7abd1f87bd2dba530447495f58 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 12 Dec 2015 18:52:06 +0100 Subject: [PATCH 2798/3725] Move keyframe loading out of SceneManager to new KeyframeManager --- apps/openmw/mwrender/animation.cpp | 3 +- components/CMakeLists.txt | 2 +- components/nifosg/nifloader.hpp | 11 +++++- components/resource/keyframemanager.cpp | 41 +++++++++++++++++++++ components/resource/keyframemanager.hpp | 47 +++++++++++++++++++++++++ components/resource/niffilemanager.cpp | 2 -- components/resource/resourcesystem.cpp | 9 ++++- components/resource/resourcesystem.hpp | 3 ++ components/resource/scenemanager.cpp | 25 ------------- components/resource/scenemanager.hpp | 11 ------ 10 files changed, 112 insertions(+), 42 deletions(-) create mode 100644 components/resource/keyframemanager.cpp create mode 100644 components/resource/keyframemanager.hpp diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 214e7f221..c285ba434 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -19,6 +19,7 @@ #include #include +#include #include #include // KeyframeHolder @@ -402,7 +403,7 @@ namespace MWRender boost::shared_ptr animsrc; animsrc.reset(new AnimSource); - animsrc->mKeyframes = mResourceSystem->getSceneManager()->getKeyframes(kfname); + animsrc->mKeyframes = mResourceSystem->getKeyframeManager()->get(kfname); if (!animsrc->mKeyframes || animsrc->mKeyframes->mTextKeys.empty() || animsrc->mKeyframes->mKeyframeControllers.empty()) return; diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index a1ac53d1b..bbbff234c 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -41,7 +41,7 @@ add_component_dir (vfs ) add_component_dir (resource - scenemanager texturemanager resourcesystem bulletshapemanager bulletshape niffilemanager objectcache + scenemanager keyframemanager texturemanager resourcesystem bulletshapemanager bulletshape niffilemanager objectcache ) add_component_dir (sceneutil diff --git a/components/nifosg/nifloader.hpp b/components/nifosg/nifloader.hpp index 54f067e98..e15df5302 100644 --- a/components/nifosg/nifloader.hpp +++ b/components/nifosg/nifloader.hpp @@ -37,11 +37,20 @@ namespace NifOsg }; - class KeyframeHolder : public osg::Referenced + class KeyframeHolder : public osg::Object { public: + KeyframeHolder() {} + KeyframeHolder(const KeyframeHolder& copy, const osg::CopyOp& copyop) + : mTextKeys(copy.mTextKeys) + , mKeyframeControllers(copy.mKeyframeControllers) + { + } + TextKeyMap mTextKeys; + META_Object(OpenMW, KeyframeHolder) + typedef std::map > KeyframeControllerMap; KeyframeControllerMap mKeyframeControllers; }; diff --git a/components/resource/keyframemanager.cpp b/components/resource/keyframemanager.cpp new file mode 100644 index 000000000..860e9033f --- /dev/null +++ b/components/resource/keyframemanager.cpp @@ -0,0 +1,41 @@ +#include "keyframemanager.hpp" + +#include +#include + +#include "objectcache.hpp" + +namespace Resource +{ + + KeyframeManager::KeyframeManager(const VFS::Manager* vfs) + : mCache(new osgDB::ObjectCache) + , mVFS(vfs) + { + } + + KeyframeManager::~KeyframeManager() + { + } + + osg::ref_ptr KeyframeManager::get(const std::string &name) + { + std::string normalized = name; + mVFS->normalizeFilename(normalized); + + osg::ref_ptr obj = mCache->getRefFromObjectCache(normalized); + if (obj) + return osg::ref_ptr(static_cast(obj.get())); + else + { + osg::ref_ptr loaded (new NifOsg::KeyframeHolder); + NifOsg::Loader::loadKf(Nif::NIFFilePtr(new Nif::NIFFile(mVFS->getNormalized(normalized), normalized)), *loaded.get()); + + mCache->addEntryToObjectCache(name, loaded); + return loaded; + } + } + + + +} diff --git a/components/resource/keyframemanager.hpp b/components/resource/keyframemanager.hpp new file mode 100644 index 000000000..5032d0e38 --- /dev/null +++ b/components/resource/keyframemanager.hpp @@ -0,0 +1,47 @@ +#ifndef OPENMW_COMPONENTS_KEYFRAMEMANAGER_H +#define OPENMW_COMPONENTS_KEYFRAMEMANAGER_H + +#include +#include + +namespace VFS +{ + class Manager; +} + +namespace osgDB +{ + class ObjectCache; +} + +namespace NifOsg +{ + class KeyframeHolder; +} + +namespace Resource +{ + + /// @brief Managing of keyframe resources + class KeyframeManager + { + public: + KeyframeManager(const VFS::Manager* vfs); + ~KeyframeManager(); + + void clearCache(); + + /// Retrieve a read-only keyframe resource by name (case-insensitive). + /// @note This method is safe to call from any thread. + /// @note Throws an exception if the resource is not found. + osg::ref_ptr get(const std::string& name); + + private: + osg::ref_ptr mCache; + + const VFS::Manager* mVFS; + }; + +} + +#endif diff --git a/components/resource/niffilemanager.cpp b/components/resource/niffilemanager.cpp index 17165bcda..1d8019b69 100644 --- a/components/resource/niffilemanager.cpp +++ b/components/resource/niffilemanager.cpp @@ -4,8 +4,6 @@ #include "objectcache.hpp" -#include - namespace Resource { diff --git a/components/resource/resourcesystem.cpp b/components/resource/resourcesystem.cpp index 2dfd30314..2ce8d22e6 100644 --- a/components/resource/resourcesystem.cpp +++ b/components/resource/resourcesystem.cpp @@ -3,6 +3,7 @@ #include "scenemanager.hpp" #include "texturemanager.hpp" #include "niffilemanager.hpp" +#include "keyframemanager.hpp" namespace Resource { @@ -11,6 +12,7 @@ namespace Resource : mVFS(vfs) { mNifFileManager.reset(new NifFileManager(vfs)); + mKeyframeManager.reset(new KeyframeManager(vfs)); mTextureManager.reset(new TextureManager(vfs)); mSceneManager.reset(new SceneManager(vfs, mTextureManager.get(), mNifFileManager.get())); } @@ -30,11 +32,16 @@ namespace Resource return mTextureManager.get(); } - NifFileManager *ResourceSystem::getNifFileManager() + NifFileManager* ResourceSystem::getNifFileManager() { return mNifFileManager.get(); } + KeyframeManager* ResourceSystem::getKeyframeManager() + { + return mKeyframeManager.get(); + } + void ResourceSystem::clearCache() { mNifFileManager->clearCache(); diff --git a/components/resource/resourcesystem.hpp b/components/resource/resourcesystem.hpp index 7f90bff27..3e1a793ca 100644 --- a/components/resource/resourcesystem.hpp +++ b/components/resource/resourcesystem.hpp @@ -14,6 +14,7 @@ namespace Resource class SceneManager; class TextureManager; class NifFileManager; + class KeyframeManager; /// @brief Wrapper class that constructs and provides access to the most commonly used resource subsystems. /// @par Resource subsystems can be used with multiple OpenGL contexts, just like the OSG equivalents, but @@ -27,6 +28,7 @@ namespace Resource SceneManager* getSceneManager(); TextureManager* getTextureManager(); NifFileManager* getNifFileManager(); + KeyframeManager* getKeyframeManager(); /// Indicates to each resource manager to clear the cache, i.e. to drop cached objects that are no longer referenced. void clearCache(); @@ -37,6 +39,7 @@ namespace Resource std::auto_ptr mSceneManager; std::auto_ptr mTextureManager; std::auto_ptr mNifFileManager; + std::auto_ptr mKeyframeManager; const VFS::Manager* mVFS; diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index 3ee7a8c00..1d1c5a365 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -233,31 +233,6 @@ namespace Resource return cloned; } - osg::ref_ptr SceneManager::getKeyframes(const std::string &name) - { - std::string normalized = name; - mVFS->normalizeFilename(normalized); - - KeyframeIndex::iterator it = mKeyframeIndex.find(normalized); - if (it == mKeyframeIndex.end()) - { - Files::IStreamPtr file = mVFS->get(normalized); - - std::string ext = getFileExtension(normalized); - - if (ext != "nif" && ext != "kf") - return NULL; - - osg::ref_ptr loaded (new NifOsg::KeyframeHolder); - NifOsg::Loader::loadKf(Nif::NIFFilePtr(new Nif::NIFFile(file, normalized)), *loaded.get()); - - mKeyframeIndex[normalized] = loaded; - return loaded; - } - else - return it->second; - } - void SceneManager::attachTo(osg::Node *instance, osg::Group *parentNode) const { parentNode->addChild(instance); diff --git a/components/resource/scenemanager.hpp b/components/resource/scenemanager.hpp index 3c1984fd9..67fa2ab43 100644 --- a/components/resource/scenemanager.hpp +++ b/components/resource/scenemanager.hpp @@ -18,11 +18,6 @@ namespace VFS class Manager; } -namespace NifOsg -{ - class KeyframeHolder; -} - namespace osgUtil { class IncrementalCompileOperation; @@ -57,9 +52,6 @@ namespace Resource /// @note Assumes the given instance was not attached to any parents before. void attachTo(osg::Node* instance, osg::Group* parentNode) const; - /// Get a read-only copy of the given keyframe file. - osg::ref_ptr getKeyframes(const std::string& name); - /// Manually release created OpenGL objects for the given graphics context. This may be required /// in cases where multiple contexts are used over the lifetime of the application. void releaseGLObjects(osg::State* state); @@ -90,9 +82,6 @@ namespace Resource typedef std::map > Index; Index mIndex; - typedef std::map > KeyframeIndex; - KeyframeIndex mKeyframeIndex; - SceneManager(const SceneManager&); void operator = (const SceneManager&); }; From a7e0562e1c78429ec05a21cfe0412ba3b7a66d29 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 13 Dec 2015 17:42:11 +0100 Subject: [PATCH 2799/3725] Fix improper handling of multiple AiFollow packages with the same target (Fixes #3077) --- apps/openmw/mwmechanics/actors.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index eb837613b..c4cd8ee4b 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1333,8 +1333,7 @@ namespace MWMechanics continue; if (followTarget == actor) list.push_back(static_cast(*it)->getFollowIndex()); - else - break; + break; } else if ((*it)->getTypeId() != MWMechanics::AiPackage::TypeIdCombat) break; From 76bde5ee13de76d15a9a355906fa2dfe909dbcd4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 13 Dec 2015 11:24:23 -0800 Subject: [PATCH 2800/3725] Separate and expand texture filtering options --- apps/openmw/engine.cpp | 35 +++++++++++++++++++---- apps/openmw/mwgui/settingswindow.cpp | 26 +++++++++++++++-- apps/openmw/mwgui/settingswindow.hpp | 2 ++ apps/openmw/mwrender/renderingmanager.cpp | 30 ++++++++++++++++--- files/mygui/openmw_settings_window.layout | 14 +++++++-- files/settings-default.cfg | 7 +++-- 6 files changed, 96 insertions(+), 18 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 6c360acf6..86ccb7b3b 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -451,12 +451,35 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) mResourceSystem.reset(new Resource::ResourceSystem(mVFS.get())); mResourceSystem->getTextureManager()->setUnRefImageDataAfterApply(true); - osg::Texture::FilterMode min = osg::Texture::LINEAR_MIPMAP_NEAREST; - osg::Texture::FilterMode mag = osg::Texture::LINEAR; - if (Settings::Manager::getString("texture filtering", "General") == "trilinear") - min = osg::Texture::LINEAR_MIPMAP_LINEAR; - int maxAnisotropy = Settings::Manager::getInt("anisotropy", "General"); - mResourceSystem->getTextureManager()->setFilterSettings(min, mag, maxAnisotropy); + { + osg::Texture::FilterMode min = osg::Texture::LINEAR; + osg::Texture::FilterMode mag = osg::Texture::LINEAR; + + std::string filter = Settings::Manager::getString("texture filtering", "General"); + if(filter == "nearest") + { + min = osg::Texture::NEAREST; + mag = osg::Texture::NEAREST; + } + + std::string mipmap = Settings::Manager::getString("texture mipmapping", "General"); + if(mipmap == "nearest") + { + if(min == osg::Texture::NEAREST) + min = osg::Texture::NEAREST_MIPMAP_NEAREST; + else if(min == osg::Texture::LINEAR) + min = osg::Texture::LINEAR_MIPMAP_NEAREST; + } + else if(mipmap != "none") + { + if(min == osg::Texture::NEAREST) + min = osg::Texture::NEAREST_MIPMAP_LINEAR; + else if(min == osg::Texture::LINEAR) + min = osg::Texture::LINEAR_MIPMAP_LINEAR; + } + int maxAnisotropy = Settings::Manager::getInt("anisotropy", "General"); + mResourceSystem->getTextureManager()->setFilterSettings(min, mag, maxAnisotropy); + } // Create input and UI first to set up a bootstrapping environment for // showing a loading screen and keeping the window responsive while doing so diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 78ff96532..72c004271 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -37,10 +37,20 @@ namespace std::string textureFilteringToStr(const std::string& val) { - if (val == "trilinear") - return "Trilinear"; + if (val == "nearest") + return "Nearest"; else - return "Bilinear"; + return "Linear"; + } + + std::string textureMipmappingToStr(const std::string& val) + { + if (val == "linear") + return "Linear"; + else if (val == "none") + return "None"; + else + return "Nearest"; } void parseResolution (int &x, int &y, const std::string& str) @@ -169,6 +179,7 @@ namespace MWGui getWidget(mFOVSlider, "FOVSlider"); getWidget(mAnisotropySlider, "AnisotropySlider"); getWidget(mTextureFilteringButton, "TextureFilteringButton"); + getWidget(mTextureMipmappingButton, "TextureMipmappingButton"); getWidget(mAnisotropyLabel, "AnisotropyLabel"); getWidget(mAnisotropyBox, "AnisotropyBox"); getWidget(mShadersButton, "ShadersButton"); @@ -200,6 +211,7 @@ namespace MWGui mSettingsTab->eventTabChangeSelect += MyGUI::newDelegate(this, &SettingsWindow::onTabChanged); mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onOkButtonClicked); mTextureFilteringButton->eventComboChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onTextureFilteringChanged); + mTextureMipmappingButton->eventComboChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onTextureMipmappingChanged); mResolutionList->eventListChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onResolutionSelected); mWaterTextureSize->eventComboChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onWaterTextureSizeChanged); @@ -237,6 +249,8 @@ namespace MWGui std::string tf = Settings::Manager::getString("texture filtering", "General"); mTextureFilteringButton->setCaption(textureFilteringToStr(tf)); + std::string tmip = Settings::Manager::getString("texture mipmapping", "General"); + mTextureMipmappingButton->setCaption(textureMipmappingToStr(tmip)); mAnisotropyLabel->setCaption("Anisotropy (" + MyGUI::utility::toString(Settings::Manager::getInt("anisotropy", "General")) + ")"); int waterTextureSize = Settings::Manager::getInt ("rtt size", "Water"); @@ -429,6 +443,12 @@ namespace MWGui apply(); } + void SettingsWindow::onTextureMipmappingChanged(MyGUI::ComboBox* _sender, size_t pos) + { + Settings::Manager::setString("texture mipmapping", "General", Misc::StringUtils::lowerCase(_sender->getItemNameAt(pos))); + apply(); + } + void SettingsWindow::onSliderChangePosition(MyGUI::ScrollBar* scroller, size_t pos) { if (getSettingType(scroller) == "Slider") diff --git a/apps/openmw/mwgui/settingswindow.hpp b/apps/openmw/mwgui/settingswindow.hpp index 99553808b..da9c8628e 100644 --- a/apps/openmw/mwgui/settingswindow.hpp +++ b/apps/openmw/mwgui/settingswindow.hpp @@ -34,6 +34,7 @@ namespace MWGui MyGUI::ScrollBar* mDifficultySlider; MyGUI::ScrollBar* mAnisotropySlider; MyGUI::ComboBox* mTextureFilteringButton; + MyGUI::ComboBox* mTextureMipmappingButton; MyGUI::TextBox* mAnisotropyLabel; MyGUI::Widget* mAnisotropyBox; MyGUI::Button* mShadersButton; @@ -53,6 +54,7 @@ namespace MWGui void onTabChanged(MyGUI::TabControl* _sender, size_t index); void onOkButtonClicked(MyGUI::Widget* _sender); void onTextureFilteringChanged(MyGUI::ComboBox* _sender, size_t pos); + void onTextureMipmappingChanged(MyGUI::ComboBox* _sender, size_t pos); void onSliderChangePosition(MyGUI::ScrollBar* scroller, size_t pos); void onButtonToggled(MyGUI::Widget* _sender); void onResolutionSelected(MyGUI::ListBox* _sender, size_t index); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 4b208fa94..f66398d2f 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -781,11 +781,31 @@ namespace MWRender void RenderingManager::updateTextureFiltering() { - osg::Texture::FilterMode min = osg::Texture::LINEAR_MIPMAP_NEAREST; + osg::Texture::FilterMode min = osg::Texture::LINEAR; osg::Texture::FilterMode mag = osg::Texture::LINEAR; - if (Settings::Manager::getString("texture filtering", "General") == "trilinear") - min = osg::Texture::LINEAR_MIPMAP_LINEAR; + std::string filter = Settings::Manager::getString("texture filtering", "General"); + if(filter == "nearest") + { + min = osg::Texture::NEAREST; + mag = osg::Texture::NEAREST; + } + + std::string mipmap = Settings::Manager::getString("texture mipmapping", "General"); + if(mipmap == "nearest") + { + if(min == osg::Texture::NEAREST) + min = osg::Texture::NEAREST_MIPMAP_NEAREST; + else if(min == osg::Texture::LINEAR) + min = osg::Texture::LINEAR_MIPMAP_NEAREST; + } + else if(mipmap != "none") + { + if(min == osg::Texture::NEAREST) + min = osg::Texture::NEAREST_MIPMAP_LINEAR; + else if(min == osg::Texture::LINEAR) + min = osg::Texture::LINEAR_MIPMAP_LINEAR; + } int maxAnisotropy = Settings::Manager::getInt("anisotropy", "General"); @@ -826,7 +846,9 @@ namespace MWRender mStateUpdater->setFogEnd(mViewDistance); updateProjectionMatrix(); } - else if (it->first == "General" && (it->second == "texture filtering" || it->second == "anisotropy")) + else if (it->first == "General" && (it->second == "texture filtering" || + it->second == "texture mipmapping" || + it->second == "anisotropy")) updateTextureFiltering(); else if (it->first == "Water") mWater->processChangedSettings(changed); diff --git a/files/mygui/openmw_settings_window.layout b/files/mygui/openmw_settings_window.layout index 6d2424aa5..df268eec4 100644 --- a/files/mygui/openmw_settings_window.layout +++ b/files/mygui/openmw_settings_window.layout @@ -322,10 +322,18 @@ - - + + - + + + + + + + + + diff --git a/files/settings-default.cfg b/files/settings-default.cfg index a5fd3cccd..c9132dada 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -110,8 +110,11 @@ anisotropy = 4 # File format for screenshots. (jpg, png, tga, and possibly more). screenshot format = png -# Isotropic texture filtering. (bilinear or trilinear). -texture filtering = trilinear +# Texture filtering. (nearest or linear). +texture filtering = linear + +# Texture mipmapping. (none, nearest, or linear). +texture mipmapping = nearest [Input] From fb6abb53aeb8d3e65a5ddc376df2a80530b008cc Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 13 Dec 2015 15:02:36 -0800 Subject: [PATCH 2801/3725] Simplify the in-game texture options This makes it behave like it originally did, although the config options remain expanded. --- apps/openmw/mwgui/settingswindow.cpp | 38 +++++++---------------- apps/openmw/mwgui/settingswindow.hpp | 1 - files/mygui/openmw_settings_window.layout | 14 ++------- 3 files changed, 15 insertions(+), 38 deletions(-) diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 72c004271..b9aa3aa26 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -35,22 +35,13 @@ namespace return "#{sOn}"; } - std::string textureFilteringToStr(const std::string& val) - { - if (val == "nearest") - return "Nearest"; - else - return "Linear"; - } - std::string textureMipmappingToStr(const std::string& val) { - if (val == "linear") - return "Linear"; - else if (val == "none") - return "None"; - else - return "Nearest"; + if (val == "linear") return "Trilinear"; + if (val == "nearest") return "Bilinear"; + if (val != "none") + std::cerr<< "Invalid texture mipmap option: "<eventTabChangeSelect += MyGUI::newDelegate(this, &SettingsWindow::onTabChanged); mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onOkButtonClicked); mTextureFilteringButton->eventComboChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onTextureFilteringChanged); - mTextureMipmappingButton->eventComboChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onTextureMipmappingChanged); mResolutionList->eventListChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onResolutionSelected); mWaterTextureSize->eventComboChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onWaterTextureSizeChanged); @@ -247,10 +236,8 @@ namespace MWGui } highlightCurrentResolution(); - std::string tf = Settings::Manager::getString("texture filtering", "General"); - mTextureFilteringButton->setCaption(textureFilteringToStr(tf)); std::string tmip = Settings::Manager::getString("texture mipmapping", "General"); - mTextureMipmappingButton->setCaption(textureMipmappingToStr(tmip)); + mTextureFilteringButton->setCaption(textureMipmappingToStr(tmip)); mAnisotropyLabel->setCaption("Anisotropy (" + MyGUI::utility::toString(Settings::Manager::getInt("anisotropy", "General")) + ")"); int waterTextureSize = Settings::Manager::getInt ("rtt size", "Water"); @@ -439,13 +426,12 @@ namespace MWGui void SettingsWindow::onTextureFilteringChanged(MyGUI::ComboBox* _sender, size_t pos) { - Settings::Manager::setString("texture filtering", "General", Misc::StringUtils::lowerCase(_sender->getItemNameAt(pos))); - apply(); - } - - void SettingsWindow::onTextureMipmappingChanged(MyGUI::ComboBox* _sender, size_t pos) - { - Settings::Manager::setString("texture mipmapping", "General", Misc::StringUtils::lowerCase(_sender->getItemNameAt(pos))); + if(pos == 0) + Settings::Manager::setString("texture mipmapping", "General", "nearest"); + else if(pos == 1) + Settings::Manager::setString("texture mipmapping", "General", "linear"); + else + std::cerr<< "Unexpected option pos "< - - + + - - - - - - - - - + From 646092ce3ad88edeb001216c03cc31a70072d141 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 13 Dec 2015 15:20:59 -0800 Subject: [PATCH 2802/3725] Add warnings when loading unknown texture options --- apps/openmw/engine.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 86ccb7b3b..eeba6e65c 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -461,6 +461,8 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) min = osg::Texture::NEAREST; mag = osg::Texture::NEAREST; } + else if(filter != "linear") + std::cerr<< "Invalid texture filtering option: "< Date: Sun, 13 Dec 2015 16:02:09 -0800 Subject: [PATCH 2803/3725] Rename the texture filter options To avoid compatibility issues with upgrading from or downgrading to older builds. --- apps/openmw/engine.cpp | 8 ++++---- apps/openmw/mwgui/settingswindow.cpp | 6 +++--- apps/openmw/mwrender/renderingmanager.cpp | 8 ++++---- files/settings-default.cfg | 8 ++++---- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index eeba6e65c..1441f8b4f 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -455,16 +455,16 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) osg::Texture::FilterMode min = osg::Texture::LINEAR; osg::Texture::FilterMode mag = osg::Texture::LINEAR; - std::string filter = Settings::Manager::getString("texture filtering", "General"); + std::string filter = Settings::Manager::getString("texture filter", "General"); if(filter == "nearest") { min = osg::Texture::NEAREST; mag = osg::Texture::NEAREST; } else if(filter != "linear") - std::cerr<< "Invalid texture filtering option: "<setCaption(textureMipmappingToStr(tmip)); mAnisotropyLabel->setCaption("Anisotropy (" + MyGUI::utility::toString(Settings::Manager::getInt("anisotropy", "General")) + ")"); @@ -427,9 +427,9 @@ namespace MWGui void SettingsWindow::onTextureFilteringChanged(MyGUI::ComboBox* _sender, size_t pos) { if(pos == 0) - Settings::Manager::setString("texture mipmapping", "General", "nearest"); + Settings::Manager::setString("texture mipmap", "General", "nearest"); else if(pos == 1) - Settings::Manager::setString("texture mipmapping", "General", "linear"); + Settings::Manager::setString("texture mipmap", "General", "linear"); else std::cerr<< "Unexpected option pos "<setFogEnd(mViewDistance); updateProjectionMatrix(); } - else if (it->first == "General" && (it->second == "texture filtering" || - it->second == "texture mipmapping" || + else if (it->first == "General" && (it->second == "texture filter" || + it->second == "texture mipmap" || it->second == "anisotropy")) updateTextureFiltering(); else if (it->first == "Water") diff --git a/files/settings-default.cfg b/files/settings-default.cfg index c9132dada..b77b95c52 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -110,11 +110,11 @@ anisotropy = 4 # File format for screenshots. (jpg, png, tga, and possibly more). screenshot format = png -# Texture filtering. (nearest or linear). -texture filtering = linear +# Texture filter type. (nearest or linear). +texture filter = linear -# Texture mipmapping. (none, nearest, or linear). -texture mipmapping = nearest +# Texture mipmap type. (none, nearest, or linear). +texture mipmap = nearest [Input] From fb9f5f8fe865e92477b2216f8751682aefcda1eb Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 14 Dec 2015 01:36:53 +0100 Subject: [PATCH 2804/3725] Fix typo --- apps/opencs/model/world/nestedcoladapterimp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/world/nestedcoladapterimp.cpp b/apps/opencs/model/world/nestedcoladapterimp.cpp index 002838c67..bfacc15dc 100644 --- a/apps/opencs/model/world/nestedcoladapterimp.cpp +++ b/apps/opencs/model/world/nestedcoladapterimp.cpp @@ -606,7 +606,7 @@ namespace CSMWorld funcMap["09"] = "PC Fatigue"; funcMap["10"] = "PC Strength"; funcMap["11"] = "PC Block"; - funcMap["12"] = "PC Armoror"; + funcMap["12"] = "PC Armorer"; funcMap["13"] = "PC Medium Armor"; funcMap["14"] = "PC Heavy Armor"; funcMap["15"] = "PC Blunt Weapon"; From 5c0a847eafb2c3c31850870709d65b3ee8631254 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 13 Dec 2015 16:51:27 -0800 Subject: [PATCH 2805/3725] Combine some duplicate code --- apps/openmw/engine.cpp | 39 ++++------------------- apps/openmw/mwrender/renderingmanager.cpp | 37 ++++----------------- components/resource/texturemanager.cpp | 36 +++++++++++++++++++++ components/resource/texturemanager.hpp | 12 +++++-- 4 files changed, 58 insertions(+), 66 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 1441f8b4f..50f097ce7 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -451,39 +451,12 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) mResourceSystem.reset(new Resource::ResourceSystem(mVFS.get())); mResourceSystem->getTextureManager()->setUnRefImageDataAfterApply(true); - { - osg::Texture::FilterMode min = osg::Texture::LINEAR; - osg::Texture::FilterMode mag = osg::Texture::LINEAR; - - std::string filter = Settings::Manager::getString("texture filter", "General"); - if(filter == "nearest") - { - min = osg::Texture::NEAREST; - mag = osg::Texture::NEAREST; - } - else if(filter != "linear") - std::cerr<< "Invalid texture filter option: "<getTextureManager()->setFilterSettings(min, mag, maxAnisotropy); - } + mResourceSystem->getTextureManager()->setFilterSettings( + Settings::Manager::getString("texture filter", "General"), + Settings::Manager::getString("texture mipmap", "General"), + Settings::Manager::getInt("anisotropy", "General"), + NULL + ); // Create input and UI first to set up a bootstrapping environment for // showing a loading screen and keeping the window responsive while doing so diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index edc877ad4..ceea7ce97 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -781,37 +781,12 @@ namespace MWRender void RenderingManager::updateTextureFiltering() { - osg::Texture::FilterMode min = osg::Texture::LINEAR; - osg::Texture::FilterMode mag = osg::Texture::LINEAR; - - std::string filter = Settings::Manager::getString("texture filter", "General"); - if(filter == "nearest") - { - min = osg::Texture::NEAREST; - mag = osg::Texture::NEAREST; - } - - std::string mipmap = Settings::Manager::getString("texture mipmap", "General"); - if(mipmap == "nearest") - { - if(min == osg::Texture::NEAREST) - min = osg::Texture::NEAREST_MIPMAP_NEAREST; - else if(min == osg::Texture::LINEAR) - min = osg::Texture::LINEAR_MIPMAP_NEAREST; - } - else if(mipmap != "none") - { - if(min == osg::Texture::NEAREST) - min = osg::Texture::NEAREST_MIPMAP_LINEAR; - else if(min == osg::Texture::LINEAR) - min = osg::Texture::LINEAR_MIPMAP_LINEAR; - } - - int maxAnisotropy = Settings::Manager::getInt("anisotropy", "General"); - - mViewer->stopThreading(); - mResourceSystem->getTextureManager()->setFilterSettings(min, mag, maxAnisotropy); - mViewer->startThreading(); + mResourceSystem->getTextureManager()->setFilterSettings( + Settings::Manager::getString("texture filter", "General"), + Settings::Manager::getString("texture mipmap", "General"), + Settings::Manager::getInt("anisotropy", "General"), + mViewer + ); } void RenderingManager::updateAmbient() diff --git a/components/resource/texturemanager.cpp b/components/resource/texturemanager.cpp index 15ac37514..ea9e7ae5d 100644 --- a/components/resource/texturemanager.cpp +++ b/components/resource/texturemanager.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include @@ -65,6 +66,41 @@ namespace Resource mUnRefImageDataAfterApply = unref; } + void TextureManager::setFilterSettings(const std::string &filter, const std::string &mipmap, int maxAnisotropy, osgViewer::Viewer *viewer) + { + osg::Texture::FilterMode min = osg::Texture::LINEAR; + osg::Texture::FilterMode mag = osg::Texture::LINEAR; + + if(filter == "nearest") + { + min = osg::Texture::NEAREST; + mag = osg::Texture::NEAREST; + } + else if(filter != "linear") + std::cerr<< "Invalid texture filter: "<stopThreading(); + setFilterSettings(min, mag, maxAnisotropy); + if(viewer) viewer->startThreading(); + } + void TextureManager::setFilterSettings(osg::Texture::FilterMode minFilter, osg::Texture::FilterMode magFilter, int maxAnisotropy) { mMinFilter = minFilter; diff --git a/components/resource/texturemanager.hpp b/components/resource/texturemanager.hpp index 0f40d7dfe..c7b4d4f59 100644 --- a/components/resource/texturemanager.hpp +++ b/components/resource/texturemanager.hpp @@ -8,6 +8,11 @@ #include #include +namespace osgViewer +{ + class Viewer; +} + namespace VFS { class Manager; @@ -23,8 +28,8 @@ namespace Resource TextureManager(const VFS::Manager* vfs); ~TextureManager(); - /// @warning It is unsafe to call this function when a draw thread is using the textures. Call stopThreading() first! - void setFilterSettings(osg::Texture::FilterMode minFilter, osg::Texture::FilterMode maxFilter, int maxAnisotropy); + void setFilterSettings(const std::string &filter, const std::string &mipmap, int maxAnisotropy, + osgViewer::Viewer *view); /// Keep a copy of the texture data around in system memory? This is needed when using multiple graphics contexts, /// otherwise should be disabled to reduce memory usage. @@ -58,6 +63,9 @@ namespace Resource bool mUnRefImageDataAfterApply; + /// @warning It is unsafe to call this function when a draw thread is using the textures. Call stopThreading() first! + void setFilterSettings(osg::Texture::FilterMode minFilter, osg::Texture::FilterMode maxFilter, int maxAnisotropy); + TextureManager(const TextureManager&); void operator = (const TextureManager&); }; From 2737aabe93cde10ece0857ed4bbd10aac1bf90d5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 14 Dec 2015 01:52:13 +0100 Subject: [PATCH 2806/3725] Pc functions apply to creature dialogue (Fixes #3078) --- apps/openmw/mwdialogue/filter.cpp | 2 +- apps/openmw/mwdialogue/selectwrapper.cpp | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index e3a773b05..d41820b71 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -313,7 +313,7 @@ int MWDialogue::Filter::getSelectStructInteger (const SelectWrapper& select) con int value = 0; - for (int i=0; i<=15; ++i) // everything except thigns held in hands and amunition + for (int i=0; i<=15; ++i) // everything except things held in hands and ammunition { MWWorld::ContainerStoreIterator slot = store.getSlot (i); diff --git a/apps/openmw/mwdialogue/selectwrapper.cpp b/apps/openmw/mwdialogue/selectwrapper.cpp index a4eba30ae..68c88e943 100644 --- a/apps/openmw/mwdialogue/selectwrapper.cpp +++ b/apps/openmw/mwdialogue/selectwrapper.cpp @@ -263,10 +263,6 @@ bool MWDialogue::SelectWrapper::isNpcOnly() const { Function_NotFaction, Function_NotClass, Function_NotRace, Function_SameGender, Function_SameRace, Function_SameFaction, - Function_PcSkill, - Function_PcExpelled, - Function_PcVampire, - Function_PcCrimeLevel, Function_RankRequirement, Function_Reputation, Function_FactionRankDiff, Function_Werewolf, Function_WerewolfKills, From f1faeeae3a765c3967270c36239fd84f5d798205 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 13 Dec 2015 17:05:19 -0800 Subject: [PATCH 2807/3725] Use separate config options for min and mag texture filters --- apps/openmw/engine.cpp | 3 ++- apps/openmw/mwrender/renderingmanager.cpp | 3 ++- components/resource/texturemanager.cpp | 18 +++++++++++------- components/resource/texturemanager.hpp | 3 ++- files/settings-default.cfg | 7 +++++-- 5 files changed, 22 insertions(+), 12 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 50f097ce7..b43fd2f53 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -452,7 +452,8 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) mResourceSystem.reset(new Resource::ResourceSystem(mVFS.get())); mResourceSystem->getTextureManager()->setUnRefImageDataAfterApply(true); mResourceSystem->getTextureManager()->setFilterSettings( - Settings::Manager::getString("texture filter", "General"), + Settings::Manager::getString("texture mag filter", "General"), + Settings::Manager::getString("texture min filter", "General"), Settings::Manager::getString("texture mipmap", "General"), Settings::Manager::getInt("anisotropy", "General"), NULL diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index ceea7ce97..b44d77722 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -782,7 +782,8 @@ namespace MWRender void RenderingManager::updateTextureFiltering() { mResourceSystem->getTextureManager()->setFilterSettings( - Settings::Manager::getString("texture filter", "General"), + Settings::Manager::getString("texture mag filter", "General"), + Settings::Manager::getString("texture min filter", "General"), Settings::Manager::getString("texture mipmap", "General"), Settings::Manager::getInt("anisotropy", "General"), mViewer diff --git a/components/resource/texturemanager.cpp b/components/resource/texturemanager.cpp index ea9e7ae5d..d7f3fc61a 100644 --- a/components/resource/texturemanager.cpp +++ b/components/resource/texturemanager.cpp @@ -66,18 +66,22 @@ namespace Resource mUnRefImageDataAfterApply = unref; } - void TextureManager::setFilterSettings(const std::string &filter, const std::string &mipmap, int maxAnisotropy, osgViewer::Viewer *viewer) + void TextureManager::setFilterSettings(const std::string &magfilter, const std::string &minfilter, + const std::string &mipmap, int maxAnisotropy, + osgViewer::Viewer *viewer) { osg::Texture::FilterMode min = osg::Texture::LINEAR; osg::Texture::FilterMode mag = osg::Texture::LINEAR; - if(filter == "nearest") - { - min = osg::Texture::NEAREST; + if(magfilter == "nearest") mag = osg::Texture::NEAREST; - } - else if(filter != "linear") - std::cerr<< "Invalid texture filter: "< Date: Sun, 13 Dec 2015 17:13:36 -0800 Subject: [PATCH 2808/3725] Remove left over declaration --- apps/openmw/mwgui/settingswindow.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/openmw/mwgui/settingswindow.hpp b/apps/openmw/mwgui/settingswindow.hpp index 5910f07e0..99553808b 100644 --- a/apps/openmw/mwgui/settingswindow.hpp +++ b/apps/openmw/mwgui/settingswindow.hpp @@ -53,7 +53,6 @@ namespace MWGui void onTabChanged(MyGUI::TabControl* _sender, size_t index); void onOkButtonClicked(MyGUI::Widget* _sender); void onTextureFilteringChanged(MyGUI::ComboBox* _sender, size_t pos); - void onTextureMipmappingChanged(MyGUI::ComboBox* _sender, size_t pos); void onSliderChangePosition(MyGUI::ScrollBar* scroller, size_t pos); void onButtonToggled(MyGUI::Widget* _sender); void onResolutionSelected(MyGUI::ListBox* _sender, size_t index); From 271fcb80c6fd42d15fae3856e8f28269eb44ccf1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 14 Dec 2015 02:57:55 +0100 Subject: [PATCH 2809/3725] Remove container scripts before deleting container --- apps/openmw/mwbase/world.hpp | 2 ++ apps/openmw/mwclass/container.cpp | 1 + apps/openmw/mwclass/creature.cpp | 1 + apps/openmw/mwclass/npc.cpp | 1 + apps/openmw/mwscript/statsextensions.cpp | 1 + apps/openmw/mwworld/localscripts.hpp | 2 +- apps/openmw/mwworld/worldimp.hpp | 3 ++- 7 files changed, 9 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index a7ff9b35b..ba48aa910 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -549,6 +549,8 @@ namespace MWBase /// Return the distance between actor's weapon and target's collision box. virtual float getHitDistance(const MWWorld::Ptr& actor, const MWWorld::Ptr& target) = 0; + + virtual void removeContainerScripts(const MWWorld::Ptr& reference) = 0; }; } diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index b600cf353..c9f9f3740 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -77,6 +77,7 @@ namespace MWClass ptr.get(); if (ref->mBase->mFlags & ESM::Container::Respawn) { + MWBase::Environment::get().getWorld()->removeContainerScripts(ptr); ptr.getRefData().setCustomData(NULL); } } diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index e5a98c889..d6270077d 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -762,6 +762,7 @@ namespace MWClass // Reset to original position ptr.getRefData().setPosition(ptr.getCellRef().getPosition()); + MWBase::Environment::get().getWorld()->removeContainerScripts(ptr); ptr.getRefData().setCustomData(NULL); } } diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 41894c1dc..60ab73e04 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -1224,6 +1224,7 @@ namespace MWClass // Reset to original position ptr.getRefData().setPosition(ptr.getCellRef().getPosition()); + MWBase::Environment::get().getWorld()->removeContainerScripts(ptr); ptr.getRefData().setCustomData(NULL); } } diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index 3996dd80b..dcac73311 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -1127,6 +1127,7 @@ namespace MWScript { MWBase::Environment::get().getWorld()->undeleteObject(ptr); // resets runtime state such as inventory, stats and AI. does not reset position in the world + MWBase::Environment::get().getWorld()->removeContainerScripts(ptr); ptr.getRefData().setCustomData(NULL); } } diff --git a/apps/openmw/mwworld/localscripts.hpp b/apps/openmw/mwworld/localscripts.hpp index 9d612cb33..5a156a2e9 100644 --- a/apps/openmw/mwworld/localscripts.hpp +++ b/apps/openmw/mwworld/localscripts.hpp @@ -52,7 +52,7 @@ namespace MWWorld void remove (RefData *ref); void remove (const Ptr& ptr); - ///< Remove script for given reference (ignored if reference does not have a scirpt listed). + ///< Remove script for given reference (ignored if reference does not have a script listed). }; } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index f08ede100..713213287 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -129,8 +129,9 @@ namespace MWWorld void updateWindowManager (); void updatePlayer(bool paused); MWWorld::Ptr getFacedObject(float maxDistance, bool ignorePlayer=true); - + public: // FIXME void removeContainerScripts(const Ptr& reference); + private: void addContainerScripts(const Ptr& reference, CellStore* cell); void PCDropped (const Ptr& item); From 572786bff27e270b9666bc86d64990101998ceb8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 14 Dec 2015 03:27:49 +0100 Subject: [PATCH 2810/3725] Instant effects that were added by a permanent ability are applied every frame Via http://forum.openmw.org/viewtopic.php?f=2&t=3212&p=36120#p36121 --- apps/openmw/mwmechanics/actors.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index c4cd8ee4b..185364fae 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -486,11 +486,14 @@ namespace MWMechanics bool wasDead = creatureStats.isDead(); - // tickable effects (i.e. effects having a lasting impact after expiry) - // these effects can be applied as "instant" (handled in spellcasting.cpp) or with a duration, handled here for (MagicEffects::Collection::const_iterator it = effects.begin(); it != effects.end(); ++it) { + // tickable effects (i.e. effects having a lasting impact after expiry) effectTick(creatureStats, ptr, it->first, it->second.getMagnitude() * duration); + + // instant effects are already applied on spell impact in spellcasting.cpp, but may also come from permanent abilities + CastSpell cast(ptr, ptr); + cast.applyInstantEffect(ptr, ptr, it->first, it->second.getMagnitude()); } // attributes From 076dc539bc67ff1b979ac3c4ded838ade561ae49 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 14 Dec 2015 15:11:06 +0100 Subject: [PATCH 2811/3725] KeyframeManager fix --- components/resource/keyframemanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/resource/keyframemanager.cpp b/components/resource/keyframemanager.cpp index 860e9033f..7e948dcb0 100644 --- a/components/resource/keyframemanager.cpp +++ b/components/resource/keyframemanager.cpp @@ -31,7 +31,7 @@ namespace Resource osg::ref_ptr loaded (new NifOsg::KeyframeHolder); NifOsg::Loader::loadKf(Nif::NIFFilePtr(new Nif::NIFFile(mVFS->getNormalized(normalized), normalized)), *loaded.get()); - mCache->addEntryToObjectCache(name, loaded); + mCache->addEntryToObjectCache(normalized, loaded); return loaded; } } From c70790ecb7e1483e747145780813eca83d5f038f Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 14 Dec 2015 15:50:30 +0100 Subject: [PATCH 2812/3725] Remove outdated comment --- components/resource/bulletshapemanager.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/components/resource/bulletshapemanager.cpp b/components/resource/bulletshapemanager.cpp index 593322190..4cbe62f3c 100644 --- a/components/resource/bulletshapemanager.cpp +++ b/components/resource/bulletshapemanager.cpp @@ -125,7 +125,6 @@ osg::ref_ptr BulletShapeManager::createInstance(const std:: if (ext == "nif") { NifBullet::BulletNifLoader loader; - // might be worth sharing NIFFiles with SceneManager in some way shape = loader.load(mNifFileManager->get(normalized)); } else From a3a2c2f476d3a0753976dee335a200a2cbfca1c9 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 14 Dec 2015 17:38:33 +0100 Subject: [PATCH 2813/3725] second batch of changing over user settings usage to the new system --- apps/opencs/model/prefs/state.cpp | 1 + apps/opencs/view/tools/reportsubview.cpp | 7 +- apps/opencs/view/tools/reportsubview.hpp | 2 - apps/opencs/view/tools/reporttable.cpp | 78 +++++++++++-------- apps/opencs/view/tools/reporttable.hpp | 9 ++- apps/opencs/view/tools/searchsubview.cpp | 5 -- apps/opencs/view/tools/searchsubview.hpp | 4 +- .../opencs/view/world/datadisplaydelegate.cpp | 40 ++++------ .../opencs/view/world/datadisplaydelegate.hpp | 17 ++-- apps/opencs/view/world/dialoguesubview.cpp | 3 - apps/opencs/view/world/idtypedelegate.cpp | 2 +- apps/opencs/view/world/recordbuttonbar.cpp | 25 +++--- apps/opencs/view/world/recordbuttonbar.hpp | 13 +++- .../view/world/recordstatusdelegate.cpp | 2 +- apps/opencs/view/world/scripterrortable.cpp | 2 +- apps/opencs/view/world/scriptsubview.cpp | 61 ++++++--------- apps/opencs/view/world/scriptsubview.hpp | 9 ++- apps/opencs/view/world/table.cpp | 28 +++---- apps/opencs/view/world/util.cpp | 8 +- apps/opencs/view/world/util.hpp | 12 ++- 20 files changed, 157 insertions(+), 171 deletions(-) diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index d6250c532..ab9fd0a28 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -153,6 +153,7 @@ void CSMPrefs::State::declare() declareColour ("colour-special", "Highlight Colour: Special Characters", QColor ("darkorange")); declareColour ("colour-comment", "Highlight Colour: Comments", QColor ("green")); declareColour ("colour-id", "Highlight Colour: IDs", QColor ("blue")); + declareCategory ("General Input"); declareBool ("cycle", "Cyclic next/previous", false). setTooltip ("When using next/previous functions at the last/first item of a " diff --git a/apps/opencs/view/tools/reportsubview.cpp b/apps/opencs/view/tools/reportsubview.cpp index a7316359e..c7712f29c 100644 --- a/apps/opencs/view/tools/reportsubview.cpp +++ b/apps/opencs/view/tools/reportsubview.cpp @@ -27,11 +27,6 @@ void CSVTools::ReportSubView::setEditLock (bool locked) // ignored. We don't change document state anyway. } -void CSVTools::ReportSubView::updateUserSetting (const QString &name, const QStringList &list) -{ - mTable->updateUserSetting (name, list); -} - void CSVTools::ReportSubView::refreshRequest() { if (!(mDocument.getState() & mRefreshState)) @@ -39,7 +34,7 @@ void CSVTools::ReportSubView::refreshRequest() if (mRefreshState==CSMDoc::State_Verifying) { mTable->clear(); - mDocument.verify (getUniversalId()); + mDocument.verify (getUniversalId()); } } } diff --git a/apps/opencs/view/tools/reportsubview.hpp b/apps/opencs/view/tools/reportsubview.hpp index b8eb2690a..9f43efdac 100644 --- a/apps/opencs/view/tools/reportsubview.hpp +++ b/apps/opencs/view/tools/reportsubview.hpp @@ -29,8 +29,6 @@ namespace CSVTools virtual void setEditLock (bool locked); - virtual void updateUserSetting (const QString &, const QStringList &); - private slots: void refreshRequest(); diff --git a/apps/opencs/view/tools/reporttable.cpp b/apps/opencs/view/tools/reporttable.cpp index d4cecc971..bfc002933 100644 --- a/apps/opencs/view/tools/reporttable.cpp +++ b/apps/opencs/view/tools/reporttable.cpp @@ -14,6 +14,8 @@ #include "../../model/tools/reportmodel.hpp" +#include "../../model/prefs/state.hpp" + #include "../../view/world/idtypedelegate.hpp" namespace CSVTools @@ -189,6 +191,10 @@ CSVTools::ReportTable::ReportTable (CSMDoc::Document& document, mDoubleClickActions.insert (std::make_pair (Qt::NoModifier, Action_Edit)); mDoubleClickActions.insert (std::make_pair (Qt::ShiftModifier, Action_Remove)); mDoubleClickActions.insert (std::make_pair (Qt::ControlModifier, Action_EditAndRemove)); + + connect (&CSMPrefs::State::get(), SIGNAL (settingChanged (const CSMPrefs::Setting *)), + this, SLOT (settingChanged (const CSMPrefs::Setting *))); + CSMPrefs::get()["Reports"].update(); } std::vector CSVTools::ReportTable::getDraggedRecords() const @@ -206,40 +212,6 @@ std::vector CSVTools::ReportTable::getDraggedRecords() co return ids; } -void CSVTools::ReportTable::updateUserSetting (const QString& name, const QStringList& list) -{ - mIdTypeDelegate->updateUserSetting (name, list); - - QString base ("report-input/double"); - if (name.startsWith (base)) - { - QString modifierString = name.mid (base.size()); - Qt::KeyboardModifiers modifiers = 0; - - if (modifierString=="-s") - modifiers = Qt::ShiftModifier; - else if (modifierString=="-c") - modifiers = Qt::ControlModifier; - else if (modifierString=="-sc") - modifiers = Qt::ShiftModifier | Qt::ControlModifier; - - DoubleClickAction action = Action_None; - - QString value = list.at (0); - - if (value=="Edit") - action = Action_Edit; - else if (value=="Remove") - action = Action_Remove; - else if (value=="Edit And Remove") - action = Action_EditAndRemove; - - mDoubleClickActions[modifiers] = action; - - return; - } -} - std::vector CSVTools::ReportTable::getReplaceIndices (bool selection) const { std::vector indices; @@ -285,6 +257,44 @@ void CSVTools::ReportTable::flagAsReplaced (int index) mModel->flagAsReplaced (index); } +void CSVTools::ReportTable::settingChanged (const CSMPrefs::Setting *setting) +{ + if (setting->getParent()->getKey()=="Reports") + { + QString base ("double"); + QString key = setting->getKey().c_str(); + if (key.startsWith (base)) + { + QString modifierString = key.mid (base.size()); + Qt::KeyboardModifiers modifiers = 0; + + if (modifierString=="-s") + modifiers = Qt::ShiftModifier; + else if (modifierString=="-c") + modifiers = Qt::ControlModifier; + else if (modifierString=="-sc") + modifiers = Qt::ShiftModifier | Qt::ControlModifier; + + DoubleClickAction action = Action_None; + + std::string value = setting->toString(); + + if (value=="Edit") + action = Action_Edit; + else if (value=="Remove") + action = Action_Remove; + else if (value=="Edit And Remove") + action = Action_EditAndRemove; + + mDoubleClickActions[modifiers] = action; + + return; + } + } + else if (*setting=="Records/type-format") + mIdTypeDelegate->settingChanged (setting); +} + void CSVTools::ReportTable::showSelection() { QModelIndexList selectedRows = selectionModel()->selectedRows(); diff --git a/apps/opencs/view/tools/reporttable.hpp b/apps/opencs/view/tools/reporttable.hpp index c847b2d47..88936d3c3 100644 --- a/apps/opencs/view/tools/reporttable.hpp +++ b/apps/opencs/view/tools/reporttable.hpp @@ -13,6 +13,11 @@ namespace CSMTools class ReportModel; } +namespace CSMPrefs +{ + class Setting; +} + namespace CSVWorld { class CommandDelegate; @@ -61,8 +66,6 @@ namespace CSVTools virtual std::vector getDraggedRecords() const; - void updateUserSetting (const QString& name, const QStringList& list); - void clear(); /// Return indices of rows that are suitable for replacement. @@ -77,6 +80,8 @@ namespace CSVTools private slots: + void settingChanged (const CSMPrefs::Setting *setting); + void showSelection(); void removeSelection(); diff --git a/apps/opencs/view/tools/searchsubview.cpp b/apps/opencs/view/tools/searchsubview.cpp index d3fdbbf5d..c2cdd10a8 100644 --- a/apps/opencs/view/tools/searchsubview.cpp +++ b/apps/opencs/view/tools/searchsubview.cpp @@ -102,11 +102,6 @@ void CSVTools::SearchSubView::setEditLock (bool locked) mSearchBox.setEditLock (locked); } -void CSVTools::SearchSubView::updateUserSetting (const QString &name, const QStringList &list) -{ - mTable->updateUserSetting (name, list); -} - void CSVTools::SearchSubView::stateChanged (int state, CSMDoc::Document *document) { mSearchBox.setSearchMode (!(state & CSMDoc::State_Searching)); diff --git a/apps/opencs/view/tools/searchsubview.hpp b/apps/opencs/view/tools/searchsubview.hpp index 2e96b98b5..ac0a5a762 100644 --- a/apps/opencs/view/tools/searchsubview.hpp +++ b/apps/opencs/view/tools/searchsubview.hpp @@ -36,15 +36,13 @@ namespace CSVTools protected: void showEvent (QShowEvent *event); - + public: SearchSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document); virtual void setEditLock (bool locked); - virtual void updateUserSetting (const QString &, const QStringList &); - private slots: void stateChanged (int state, CSMDoc::Document *document); diff --git a/apps/opencs/view/world/datadisplaydelegate.cpp b/apps/opencs/view/world/datadisplaydelegate.cpp index 72f45a18c..51d7137ec 100644 --- a/apps/opencs/view/world/datadisplaydelegate.cpp +++ b/apps/opencs/view/world/datadisplaydelegate.cpp @@ -1,5 +1,6 @@ #include "datadisplaydelegate.hpp" -#include "../../model/settings/usersettings.hpp" + +#include "../../model/prefs/state.hpp" #include #include @@ -8,8 +9,8 @@ CSVWorld::DataDisplayDelegate::DataDisplayDelegate(const ValueList &values, const IconList &icons, CSMWorld::CommandDispatcher *dispatcher, CSMDoc::Document& document, - const QString &pageName, - const QString &settingName, + const std::string &pageName, + const std::string &settingName, QObject *parent) : EnumDelegate (values, dispatcher, document, parent), mDisplayMode (Mode_TextOnly), mIcons (icons), mIconSize (QSize(16, 16)), @@ -18,10 +19,8 @@ CSVWorld::DataDisplayDelegate::DataDisplayDelegate(const ValueList &values, { buildPixmaps(); - QString value = - CSMSettings::UserSettings::instance().settingValue (mSettingKey); - - updateDisplayMode(value); + if (!pageName.empty()) + updateDisplayMode (CSMPrefs::get()[pageName][settingName].toString()); } void CSVWorld::DataDisplayDelegate::buildPixmaps () @@ -52,7 +51,7 @@ void CSVWorld::DataDisplayDelegate::setTextLeftOffset(int offset) QSize CSVWorld::DataDisplayDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const { QSize size = EnumDelegate::sizeHint(option, index); - + int valueIndex = getValueIndex(index); if (valueIndex != -1) { @@ -105,7 +104,7 @@ void CSVWorld::DataDisplayDelegate::paintIcon (QPainter *painter, const QStyleOp textRect.setLeft(iconRect.right() + mTextLeftOffset); textRect.setRight(option.rect.right() - mHorizontalMargin); - QString text = option.fontMetrics.elidedText(mValues.at(index).second, + QString text = option.fontMetrics.elidedText(mValues.at(index).second, option.textElideMode, textRect.width()); QApplication::style()->drawItemText(painter, @@ -118,19 +117,7 @@ void CSVWorld::DataDisplayDelegate::paintIcon (QPainter *painter, const QStyleOp QApplication::style()->drawItemPixmap(painter, iconRect, Qt::AlignCenter, mPixmaps.at(index).second); } -void CSVWorld::DataDisplayDelegate::updateUserSetting (const QString &name, - const QStringList &list) -{ - if (list.isEmpty()) - return; - - QString value = list.at(0); - - if (name == mSettingKey) - updateDisplayMode (value); -} - -void CSVWorld::DataDisplayDelegate::updateDisplayMode (const QString &mode) +void CSVWorld::DataDisplayDelegate::updateDisplayMode (const std::string &mode) { if (mode == "Icon and Text") mDisplayMode = Mode_IconAndText; @@ -146,6 +133,13 @@ CSVWorld::DataDisplayDelegate::~DataDisplayDelegate() { } +void CSVWorld::DataDisplayDelegate::settingChanged (const CSMPrefs::Setting *setting) +{ + if (*setting==mSettingKey) + updateDisplayMode (setting->toString()); +} + + void CSVWorld::DataDisplayDelegateFactory::add (int enumValue, QString enumName, QString iconFilename) { mIcons.push_back (std::make_pair(enumValue, QIcon(iconFilename))); @@ -158,5 +152,3 @@ CSVWorld::CommandDelegate *CSVWorld::DataDisplayDelegateFactory::makeDelegate ( { return new DataDisplayDelegate (mValues, mIcons, dispatcher, document, "", "", parent); } - - diff --git a/apps/opencs/view/world/datadisplaydelegate.hpp b/apps/opencs/view/world/datadisplaydelegate.hpp index e565a3469..cde109fd4 100755 --- a/apps/opencs/view/world/datadisplaydelegate.hpp +++ b/apps/opencs/view/world/datadisplaydelegate.hpp @@ -4,10 +4,13 @@ #include #include "enumdelegate.hpp" -namespace CSVWorld +namespace CSMPrefs { + class Setting; +} - +namespace CSVWorld +{ class DataDisplayDelegate : public EnumDelegate { public: @@ -34,12 +37,12 @@ namespace CSVWorld int mHorizontalMargin; int mTextLeftOffset; - QString mSettingKey; + std::string mSettingKey; public: DataDisplayDelegate (const ValueList & values, const IconList & icons, CSMWorld::CommandDispatcher *dispatcher, CSMDoc::Document& document, - const QString &pageName, const QString &settingName, QObject *parent); + const std::string& pageName, const std::string& settingName, QObject *parent); ~DataDisplayDelegate(); @@ -53,13 +56,10 @@ namespace CSVWorld /// offset the horizontal position of the text from the right edge of the icon. Default is 8 pixels. void setTextLeftOffset (int offset); - ///update the display mode for the delegate - void updateUserSetting (const QString &name, const QStringList &list); - private: /// update the display mode based on a passed string - void updateDisplayMode (const QString &); + void updateDisplayMode (const std::string &); /// custom paint function for painting the icon. Mode_IconAndText and Mode_Icon only. void paintIcon (QPainter *painter, const QStyleOptionViewItem &option, int i) const; @@ -67,6 +67,7 @@ namespace CSVWorld /// rebuild the list of pixmaps from the provided icons (called when icon size is changed) void buildPixmaps(); + virtual void settingChanged (const CSMPrefs::Setting *setting); }; class DataDisplayDelegateFactory : public EnumDelegateFactory diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 61d3fb1ca..e0c167b0e 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -919,9 +919,6 @@ void CSVWorld::DialogueSubView::updateUserSetting (const QString& name, const QS } } } - - if (mButtons) - mButtons->updateUserSetting (name, value); } void CSVWorld::DialogueSubView::showPreview () diff --git a/apps/opencs/view/world/idtypedelegate.cpp b/apps/opencs/view/world/idtypedelegate.cpp index 34c8d12cd..ee35e07d4 100755 --- a/apps/opencs/view/world/idtypedelegate.cpp +++ b/apps/opencs/view/world/idtypedelegate.cpp @@ -5,7 +5,7 @@ CSVWorld::IdTypeDelegate::IdTypeDelegate (const ValueList &values, const IconList &icons, CSMWorld::CommandDispatcher *dispatcher, CSMDoc::Document& document, QObject *parent) : DataDisplayDelegate (values, icons, dispatcher, document, - "records", "type-format", + "Records", "type-format", parent) {} diff --git a/apps/opencs/view/world/recordbuttonbar.cpp b/apps/opencs/view/world/recordbuttonbar.cpp index 1a838a3b3..40a24bf65 100644 --- a/apps/opencs/view/world/recordbuttonbar.cpp +++ b/apps/opencs/view/world/recordbuttonbar.cpp @@ -6,7 +6,7 @@ #include "../../model/world/idtable.hpp" #include "../../model/world/commanddispatcher.hpp" -#include "../../model/settings/usersettings.hpp" +#include "../../model/prefs/state.hpp" #include "../world/tablebottombox.hpp" @@ -32,7 +32,7 @@ void CSVWorld::RecordButtonBar::updatePrevNextButtons() mPrevButton->setDisabled (true); mNextButton->setDisabled (true); } - else if (CSMSettings::UserSettings::instance().settingValue ("general-input/cycle")=="true") + else if (CSMPrefs::get()["General Input"]["cycle"].isTrue()) { mPrevButton->setDisabled (false); mNextButton->setDisabled (false); @@ -131,6 +131,9 @@ CSVWorld::RecordButtonBar::RecordButtonBar (const CSMWorld::UniversalId& id, connect (&mTable, SIGNAL (rowsRemoved (const QModelIndex&, int, int)), this, SLOT (rowNumberChanged (const QModelIndex&, int, int))); + connect (&CSMPrefs::State::get(), SIGNAL (settingChanged (const CSMPrefs::Setting *)), + this, SLOT (settingChanged (const CSMPrefs::Setting *))); + updateModificationButtons(); updatePrevNextButtons(); } @@ -141,18 +144,18 @@ void CSVWorld::RecordButtonBar::setEditLock (bool locked) updateModificationButtons(); } -void CSVWorld::RecordButtonBar::updateUserSetting (const QString& name, const QStringList& value) -{ - if (name=="general-input/cycle") - updatePrevNextButtons(); -} - void CSVWorld::RecordButtonBar::universalIdChanged (const CSMWorld::UniversalId& id) { mId = id; updatePrevNextButtons(); } +void CSVWorld::RecordButtonBar::settingChanged (const CSMPrefs::Setting *setting) +{ + if (*setting=="General Input/cycle") + updatePrevNextButtons(); +} + void CSVWorld::RecordButtonBar::cloneRequest() { if (mBottom) @@ -173,8 +176,7 @@ void CSVWorld::RecordButtonBar::nextId() if (newRow >= mTable.rowCount()) { - if (CSMSettings::UserSettings::instance().settingValue ("general-input/cycle") - =="true") + if (CSMPrefs::get()["General Input"]["cycle"].isTrue()) newRow = 0; else return; @@ -189,8 +191,7 @@ void CSVWorld::RecordButtonBar::prevId() if (newRow < 0) { - if (CSMSettings::UserSettings::instance().settingValue ("general-input/cycle") - =="true") + if (CSMPrefs::get()["General Input"]["cycle"].isTrue()) newRow = mTable.rowCount()-1; else return; diff --git a/apps/opencs/view/world/recordbuttonbar.hpp b/apps/opencs/view/world/recordbuttonbar.hpp index 93ca45518..fbee066ce 100644 --- a/apps/opencs/view/world/recordbuttonbar.hpp +++ b/apps/opencs/view/world/recordbuttonbar.hpp @@ -14,6 +14,11 @@ namespace CSMWorld class CommandDispatcher; } +namespace CSMPrefs +{ + class Setting; +} + namespace CSVWorld { class TableBottomBox; @@ -49,7 +54,7 @@ namespace CSVWorld void updateModificationButtons(); void updatePrevNextButtons(); - + public: RecordButtonBar (const CSMWorld::UniversalId& id, @@ -58,14 +63,14 @@ namespace CSVWorld void setEditLock (bool locked); - void updateUserSetting (const QString& name, const QStringList& value); - public slots: void universalIdChanged (const CSMWorld::UniversalId& id); private slots: + void settingChanged (const CSMPrefs::Setting *setting); + void cloneRequest(); void nextId(); @@ -73,7 +78,7 @@ namespace CSVWorld void prevId(); void rowNumberChanged (const QModelIndex& parent, int start, int end); - + signals: void showPreview(); diff --git a/apps/opencs/view/world/recordstatusdelegate.cpp b/apps/opencs/view/world/recordstatusdelegate.cpp index 58a5c0177..0aec13bcf 100644 --- a/apps/opencs/view/world/recordstatusdelegate.cpp +++ b/apps/opencs/view/world/recordstatusdelegate.cpp @@ -11,7 +11,7 @@ CSVWorld::RecordStatusDelegate::RecordStatusDelegate(const ValueList& values, const IconList & icons, CSMWorld::CommandDispatcher *dispatcher, CSMDoc::Document& document, QObject *parent) : DataDisplayDelegate (values, icons, dispatcher, document, - "records", "status-format", + "Records", "status-format", parent) {} diff --git a/apps/opencs/view/world/scripterrortable.cpp b/apps/opencs/view/world/scripterrortable.cpp index b439e0df3..c22bcf199 100644 --- a/apps/opencs/view/world/scripterrortable.cpp +++ b/apps/opencs/view/world/scripterrortable.cpp @@ -135,7 +135,7 @@ bool CSVWorld::ScriptErrorTable::clearLocals (const std::string& script) void CSVWorld::ScriptErrorTable::settingChanged (const CSMPrefs::Setting *setting) { - if (*setting=="Scripst/warnings") + if (*setting=="Scripts/warnings") setWarningsMode (setting->toString()); } diff --git a/apps/opencs/view/world/scriptsubview.cpp b/apps/opencs/view/world/scriptsubview.cpp index eb8bd2e29..ee0acb560 100644 --- a/apps/opencs/view/world/scriptsubview.cpp +++ b/apps/opencs/view/world/scriptsubview.cpp @@ -13,7 +13,7 @@ #include "../../model/world/columnbase.hpp" #include "../../model/world/commands.hpp" #include "../../model/world/idtable.hpp" -#include "../../model/settings/usersettings.hpp" +#include "../../model/prefs/state.hpp" #include "scriptedit.hpp" #include "recordbuttonbar.hpp" @@ -39,8 +39,7 @@ void CSVWorld::ScriptSubView::addButtonBar() void CSVWorld::ScriptSubView::recompile() { if (!mCompileDelay->isActive() && !isDeleted()) - mCompileDelay->start ( - CSMSettings::UserSettings::instance().setting ("script-editor/compile-delay").toInt()); + mCompileDelay->start (CSMPrefs::get()["Scripts"]["compile-delay"].toInt()); } bool CSVWorld::ScriptSubView::isDeleted() const @@ -89,7 +88,7 @@ void CSVWorld::ScriptSubView::adjustSplitter() CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) : SubView (id), mDocument (document), mColumn (-1), mBottom(0), mButtons (0), mCommandDispatcher (document, CSMWorld::UniversalId::getParentType (id.getType())), - mErrorHeight (CSMSettings::UserSettings::instance().setting ("script-editor/error-height").toInt()) + mErrorHeight (CSMPrefs::get()["Scripts"]["error-height"].toInt()) { std::vector selection (1, id.getId()); mCommandDispatcher.setSelection (selection); @@ -126,9 +125,6 @@ CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc: // bottom box and buttons mBottom = new TableBottomBox (CreatorFactory(), document, id, this); - if (CSMSettings::UserSettings::instance().setting ("script-editor/toolbar", QString("true")) == "true") - addButtonBar(); - connect (mBottom, SIGNAL (requestFocus (const std::string&)), this, SLOT (switchToId (const std::string&))); @@ -156,53 +152,40 @@ CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc: connect (mCompileDelay, SIGNAL (timeout()), this, SLOT (updateRequest())); updateDeletedState(); + + connect (&CSMPrefs::State::get(), SIGNAL (settingChanged (const CSMPrefs::Setting *)), + this, SLOT (settingChanged (const CSMPrefs::Setting *))); + CSMPrefs::get()["Scripts"].update(); } -void CSVWorld::ScriptSubView::updateUserSetting (const QString& name, const QStringList& value) +void CSVWorld::ScriptSubView::setStatusBar (bool show) { - if (name == "script-editor/show-linenum") - { - std::string showLinenum = value.at(0).toUtf8().constData(); - mEditor->showLineNum(showLinenum == "true"); - mBottom->setVisible(showLinenum == "true"); - } - else if (name == "script-editor/mono-font") - { - mEditor->setMonoFont (value.at(0)==QString ("true")); - } - else if (name=="script-editor/toolbar") + mBottom->setStatusBar (show); +} + +void CSVWorld::ScriptSubView::settingChanged (const CSMPrefs::Setting *setting) +{ + if (*setting=="Scripts/toolbar") { - if (value.at(0)==QString ("true")) + if (setting->isTrue()) { addButtonBar(); } - else + else if (mButtons) { - if (mButtons) - { - mLayout.removeWidget (mButtons); - delete mButtons; - mButtons = 0; - } + mLayout.removeWidget (mButtons); + delete mButtons; + mButtons = 0; } } - else if (name=="script-editor/compile-delay") + else if (*setting=="Scripts/compile-delay") { - mCompileDelay->setInterval (value.at (0).toInt()); + mCompileDelay->setInterval (setting->toInt()); } - - if (mButtons) - mButtons->updateUserSetting (name, value); - - if (name=="script-editor/warnings") + else if (*setting=="Scripts/warnings") recompile(); } -void CSVWorld::ScriptSubView::setStatusBar (bool show) -{ - mBottom->setStatusBar (show); -} - void CSVWorld::ScriptSubView::updateStatusBar () { mBottom->positionChanged (mEditor->textCursor().blockNumber() + 1, diff --git a/apps/opencs/view/world/scriptsubview.hpp b/apps/opencs/view/world/scriptsubview.hpp index 179430ef9..c1016babf 100644 --- a/apps/opencs/view/world/scriptsubview.hpp +++ b/apps/opencs/view/world/scriptsubview.hpp @@ -23,6 +23,11 @@ namespace CSMWorld class IdTable; } +namespace CSMPrefs +{ + class Setting; +} + namespace CSVWorld { class ScriptEdit; @@ -69,8 +74,6 @@ namespace CSVWorld virtual void useHint (const std::string& hint); - virtual void updateUserSetting (const QString& name, const QStringList& value); - virtual void setStatusBar (bool show); public slots: @@ -83,6 +86,8 @@ namespace CSVWorld private slots: + void settingChanged (const CSMPrefs::Setting *setting); + void updateStatusBar(); void switchToRow (int row); diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index ba8c4ae56..832e074c4 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -558,23 +558,6 @@ void CSVWorld::Table::executeExtendedRevert() void CSVWorld::Table::updateUserSetting (const QString &name, const QStringList &list) { - if (name=="records/type-format" || name=="records/status-format") - { - int columns = mModel->columnCount(); - - for (int i=0; i - (*delegate).updateUserSetting (name, list); - { - emit dataChanged (mModel->index (0, i), - mModel->index (mModel->rowCount()-1, i)); - } - } - return; - } - QString base ("table-input/double"); if (name.startsWith (base)) { @@ -633,7 +616,18 @@ void CSVWorld::Table::settingChanged (const CSMPrefs::Setting *setting) mUnselectAfterJump = false; } } + else if (*setting=="Records/type-format" || *setting=="Records/status-format") + { + int columns = mModel->columnCount(); + for (int i=0; i (*delegate).settingChanged (setting); + emit dataChanged (mModel->index (0, i), + mModel->index (mModel->rowCount()-1, i)); + } + } } void CSVWorld::Table::tableSizeUpdate() diff --git a/apps/opencs/view/world/util.cpp b/apps/opencs/view/world/util.cpp index b87d6b4f4..b0431f71a 100644 --- a/apps/opencs/view/world/util.cpp +++ b/apps/opencs/view/world/util.cpp @@ -166,7 +166,7 @@ QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleO const QModelIndex& index) const { CSMWorld::ColumnBase::Display display = getDisplayTypeFromIndex(index); - + // This createEditor() method is called implicitly from tables. // For boolean values in tables use the default editor (combobox). // Checkboxes is looking ugly in the table view. @@ -239,7 +239,7 @@ QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleO edit->setUndoRedoEnabled (false); return edit; } - + case CSMWorld::ColumnBase::Display_Boolean: return new QCheckBox(parent); @@ -260,7 +260,7 @@ QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleO widget->setMaxLength (32); return widget; } - + default: return QStyledItemDelegate::createEditor (parent, option, index); @@ -329,3 +329,5 @@ void CSVWorld::CommandDelegate::setEditorData (QWidget *editor, const QModelInde } } + +void CSVWorld::CommandDelegate::settingChanged (const CSMPrefs::Setting *setting) {} diff --git a/apps/opencs/view/world/util.hpp b/apps/opencs/view/world/util.hpp index d695be0d7..766d72958 100644 --- a/apps/opencs/view/world/util.hpp +++ b/apps/opencs/view/world/util.hpp @@ -18,6 +18,11 @@ namespace CSMWorld class CommandDispatcher; } +namespace CSMPrefs +{ + class Setting; +} + namespace CSVWorld { ///< \brief Getting the data out of an editor widget @@ -138,10 +143,9 @@ namespace CSVWorld virtual void setEditorData (QWidget *editor, const QModelIndex& index, bool tryDisplay) const; - public slots: - - virtual void updateUserSetting - (const QString &name, const QStringList &list) {} + /// \attention This is not a slot. For ordering reasons this function needs to be + /// called manually from the parent object's settingChanged function. + virtual void settingChanged (const CSMPrefs::Setting *setting); }; } From cddea4a99cd4af28800e017d0c4b5c789806fb56 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 14 Dec 2015 13:54:53 -0800 Subject: [PATCH 2814/3725] Start underwater sound after updating sounds In between the startUpdate/finishUpdate calls, changes are deferred so that they can happen all at once. This includes starting sounds, so when the underwater sound is started it will be immediately checked to see if it's playing. Since it's not yet playing, it'll be seen as stopped and get cleaned up before ever playing. --- apps/openmw/mwsound/soundmanagerimp.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index d1a90759b..522efe3a7 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -844,13 +844,6 @@ namespace MWSound env ); - if(mListenerUnderwater) - { - // Play underwater sound (after updating listener) - if(!(mUnderwaterSound && mOutput->isSoundPlaying(mUnderwaterSound))) - mUnderwaterSound = playSound("Underwater", 1.0f, 1.0f, Play_TypeSfx, Play_LoopNoEnv); - } - // Check if any sounds are finished playing, and trash them SoundMap::iterator snditer = mActiveSounds.begin(); while(snditer != mActiveSounds.end()) @@ -979,6 +972,13 @@ namespace MWSound ++trkiter; } } + + if(mListenerUnderwater) + { + // Play underwater sound (after updating sounds) + if(!(mUnderwaterSound && mOutput->isSoundPlaying(mUnderwaterSound))) + mUnderwaterSound = playSound("Underwater", 1.0f, 1.0f, Play_TypeSfx, Play_LoopNoEnv); + } mOutput->finishUpdate(); } From ecbd68a19bbf65ef4f2c527298e041dfde63ae73 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 15 Dec 2015 10:40:00 +0100 Subject: [PATCH 2815/3725] third batch of changing over user settings usage to the new system --- apps/opencs/view/doc/subview.cpp | 5 +- apps/opencs/view/doc/subview.hpp | 2 - apps/opencs/view/doc/view.cpp | 97 ++++++++++------------ apps/opencs/view/doc/view.hpp | 9 +- apps/opencs/view/doc/viewmanager.cpp | 14 +--- apps/opencs/view/render/editmode.cpp | 5 -- apps/opencs/view/render/editmode.hpp | 3 - apps/opencs/view/render/instancemode.cpp | 21 +---- apps/opencs/view/render/instancemode.hpp | 6 -- apps/opencs/view/tools/searchsubview.cpp | 12 +-- apps/opencs/view/world/dialoguesubview.cpp | 30 +++---- apps/opencs/view/world/dialoguesubview.hpp | 9 +- apps/opencs/view/world/table.cpp | 84 +++++++++---------- apps/opencs/view/world/table.hpp | 2 - apps/opencs/view/world/tablesubview.cpp | 6 -- apps/opencs/view/world/tablesubview.hpp | 3 - 16 files changed, 121 insertions(+), 187 deletions(-) diff --git a/apps/opencs/view/doc/subview.cpp b/apps/opencs/view/doc/subview.cpp index e0c2fbc46..67a8f8c70 100644 --- a/apps/opencs/view/doc/subview.cpp +++ b/apps/opencs/view/doc/subview.cpp @@ -16,7 +16,7 @@ bool CSVDoc::SubView::event (QEvent *event) emit closeRequest(); return true; } - + return QDockWidget::event (event); } @@ -38,9 +38,6 @@ void CSVDoc::SubView::setStatusBar (bool show) {} void CSVDoc::SubView::useHint (const std::string& hint) {} -void CSVDoc::SubView::updateUserSetting (const QString &, const QStringList &) -{} - void CSVDoc::SubView::setUniversalId (const CSMWorld::UniversalId& id) { mUniversalId = id; diff --git a/apps/opencs/view/doc/subview.hpp b/apps/opencs/view/doc/subview.hpp index 189bb40eb..1c5f8a786 100644 --- a/apps/opencs/view/doc/subview.hpp +++ b/apps/opencs/view/doc/subview.hpp @@ -52,8 +52,6 @@ namespace CSVDoc virtual std::string getTitle() const; - virtual void updateUserSetting (const QString& name, const QStringList& value); - private: void closeEvent (QCloseEvent *event); diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 776839d19..3491c9de2 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -15,7 +15,6 @@ #include #include "../../model/doc/document.hpp" -#include "../../model/settings/usersettings.hpp" #include "../../model/prefs/state.hpp" #include "../../model/world/idtable.hpp" @@ -443,6 +442,9 @@ CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int to mSubViewFactory.add (CSMWorld::UniversalId::Type_RunLog, new SubViewFactory); connect (mOperations, SIGNAL (abortOperation (int)), this, SLOT (abortOperation (int))); + + connect (&CSMPrefs::State::get(), SIGNAL (settingChanged (const CSMPrefs::Setting *)), + this, SLOT (settingChanged (const CSMPrefs::Setting *))); } CSVDoc::View::~View() @@ -626,6 +628,45 @@ void CSVDoc::View::moveScrollBarToEnd(int min, int max) } } +void CSVDoc::View::settingChanged (const CSMPrefs::Setting *setting) +{ + if (*setting=="Windows/hide-subview") + updateSubViewIndicies (0); + else if (*setting=="Windows/mainwindow-scrollbar") + { + if (setting->toString()!="Grow Only") + { + if (mScroll) + { + if (setting->toString()=="Scrollbar Only") + { + mScrollbarOnly = true; + mSubViewWindow.setMinimumWidth(0); + } + else if (mScrollbarOnly) + { + mScrollbarOnly = false; + updateScrollbar(); + } + } + else + { + mScroll = new QScrollArea(this); + mScroll->setWidgetResizable(true); + mScroll->setWidget(&mSubViewWindow); + setCentralWidget(mScroll); + } + } + else if (mScroll) + { + mScroll->takeWidget(); + setCentralWidget (&mSubViewWindow); + mScroll->deleteLater(); + mScroll = 0; + } + } +} + void CSVDoc::View::newView() { mViewManager.addView (mDocument); @@ -849,60 +890,6 @@ void CSVDoc::View::resizeViewHeight (int height) resize (geometry().width(), height); } -void CSVDoc::View::updateUserSetting (const QString &name, const QStringList &list) -{ - - if (name=="window/hide-subview") - updateSubViewIndicies (0); - - foreach (SubView *subView, mSubViews) - { - subView->updateUserSetting (name, list); - } - - if (name=="window/mainwindow-scrollbar") - { - if(list.at(0) != "Grow Only") - { - if (mScroll) - { - if (list.at(0).isEmpty() || list.at(0) == "Scrollbar Only") - { - mScrollbarOnly = true; - mSubViewWindow.setMinimumWidth(0); - } - else - { - if(!mScrollbarOnly) - return; - - mScrollbarOnly = false; - updateScrollbar(); - } - } - else - { - mScroll = new QScrollArea(this); - mScroll->setWidgetResizable(true); - mScroll->setWidget(&mSubViewWindow); - setCentralWidget(mScroll); - } - } - else - { - if (mScroll) - { - mScroll->takeWidget(); - setCentralWidget (&mSubViewWindow); - mScroll->deleteLater(); - mScroll = 0; - } - else - return; - } - } -} - void CSVDoc::View::toggleShowStatusBar (bool show) { foreach (QObject *view, mSubViewWindow.children()) diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index 2dd717440..90eeeb407 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -22,6 +22,11 @@ namespace CSMWorld class UniversalId; } +namespace CSMPrefs +{ + class Setting; +} + namespace CSVDoc { class ViewManager; @@ -137,8 +142,6 @@ namespace CSVDoc void abortOperation (int type); - void updateUserSetting (const QString &, const QStringList &); - void updateTitle(); // called when subviews are added or removed @@ -146,6 +149,8 @@ namespace CSVDoc private slots: + void settingChanged (const CSMPrefs::Setting *setting); + void newView(); void save(); diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 116febae4..024636f34 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -14,6 +14,8 @@ #include "../../model/world/universalid.hpp" #include "../../model/world/idcompletionmanager.hpp" +#include "../../model/prefs/state.hpp" + #include "../world/util.hpp" #include "../world/enumdelegate.hpp" #include "../world/vartypedelegate.hpp" @@ -22,8 +24,6 @@ #include "../world/idcompletiondelegate.hpp" #include "../world/colordelegate.hpp" -#include "../../model/settings/usersettings.hpp" - #include "view.hpp" void CSVDoc::ViewManager::updateIndices() @@ -165,10 +165,7 @@ CSVDoc::View *CSVDoc::ViewManager::addView (CSMDoc::Document *document) mViews.push_back (view); - std::string showStatusBar = - CSMSettings::UserSettings::instance().settingValue("window/show-statusbar").toStdString(); - - view->toggleStatusBar (showStatusBar == "true"); + view->toggleStatusBar (CSMPrefs::get()["Windows"]["show-statusbar"].isTrue()); view->show(); connect (view, SIGNAL (newGameRequest ()), this, SIGNAL (newGameRequest())); @@ -177,11 +174,6 @@ CSVDoc::View *CSVDoc::ViewManager::addView (CSMDoc::Document *document) connect (view, SIGNAL (editSettingsRequest()), this, SIGNAL (editSettingsRequest())); connect (view, SIGNAL (mergeDocument (CSMDoc::Document *)), this, SIGNAL (mergeDocument (CSMDoc::Document *))); - connect (&CSMSettings::UserSettings::instance(), - SIGNAL (userSettingUpdated(const QString &, const QStringList &)), - view, - SLOT (updateUserSetting (const QString &, const QStringList &))); - updateIndices(); return view; diff --git a/apps/opencs/view/render/editmode.cpp b/apps/opencs/view/render/editmode.cpp index 4c6f2bd43..a77ef21a5 100644 --- a/apps/opencs/view/render/editmode.cpp +++ b/apps/opencs/view/render/editmode.cpp @@ -24,11 +24,6 @@ void CSVRender::EditMode::activate (CSVWidget::SceneToolbar *toolbar) mWorldspaceWidget->clearSelection (~mMask); } -void CSVRender::EditMode::updateUserSetting (const QString& name, const QStringList& value) -{ - -} - void CSVRender::EditMode::setEditLock (bool locked) { diff --git a/apps/opencs/view/render/editmode.hpp b/apps/opencs/view/render/editmode.hpp index c17616b56..9a8ac9a3a 100644 --- a/apps/opencs/view/render/editmode.hpp +++ b/apps/opencs/view/render/editmode.hpp @@ -30,9 +30,6 @@ namespace CSVRender virtual void activate (CSVWidget::SceneToolbar *toolbar); - /// Default-implementation: Do nothing. - virtual void updateUserSetting (const QString& name, const QStringList& value); - /// Default-implementation: Ignored. virtual void setEditLock (bool locked); diff --git a/apps/opencs/view/render/instancemode.cpp b/apps/opencs/view/render/instancemode.cpp index 8f0526443..a4d147bb4 100644 --- a/apps/opencs/view/render/instancemode.cpp +++ b/apps/opencs/view/render/instancemode.cpp @@ -1,7 +1,7 @@ #include "instancemode.hpp" -#include "../../model/settings/usersettings.hpp" +#include "../../model/prefs/state.hpp" #include "elements.hpp" #include "object.hpp" @@ -9,33 +9,20 @@ CSVRender::InstanceMode::InstanceMode (WorldspaceWidget *worldspaceWidget, QWidget *parent) : EditMode (worldspaceWidget, QIcon (":placeholder"), Element_Reference, "Instance editing", - parent), mContextSelect (false) + parent) { } -void CSVRender::InstanceMode::activate (CSVWidget::SceneToolbar *toolbar) -{ - EditMode::activate (toolbar); - - mContextSelect = CSMSettings::UserSettings::instance().setting ("scene-input/context-select")=="true"; -} - -void CSVRender::InstanceMode::updateUserSetting (const QString& name, const QStringList& value) -{ - if (name=="scene-input/context-select") - mContextSelect = value.at (0)=="true"; -} - void CSVRender::InstanceMode::primaryEditPressed (osg::ref_ptr tag) { - if (mContextSelect) + if (CSMPrefs::get()["3D Scene Input"]["context-select"].isTrue()) primarySelectPressed (tag); } void CSVRender::InstanceMode::secondaryEditPressed (osg::ref_ptr tag) { - if (mContextSelect) + if (CSMPrefs::get()["3D Scene Input"]["context-select"].isTrue()) secondarySelectPressed (tag); } diff --git a/apps/opencs/view/render/instancemode.hpp b/apps/opencs/view/render/instancemode.hpp index 50bd8243d..66451bd99 100644 --- a/apps/opencs/view/render/instancemode.hpp +++ b/apps/opencs/view/render/instancemode.hpp @@ -9,16 +9,10 @@ namespace CSVRender { Q_OBJECT - bool mContextSelect; - public: InstanceMode (WorldspaceWidget *worldspaceWidget, QWidget *parent = 0); - virtual void activate (CSVWidget::SceneToolbar *toolbar); - - virtual void updateUserSetting (const QString& name, const QStringList& value); - virtual void primaryEditPressed (osg::ref_ptr tag); virtual void secondaryEditPressed (osg::ref_ptr tag); diff --git a/apps/opencs/view/tools/searchsubview.cpp b/apps/opencs/view/tools/searchsubview.cpp index c2cdd10a8..493defa5a 100644 --- a/apps/opencs/view/tools/searchsubview.cpp +++ b/apps/opencs/view/tools/searchsubview.cpp @@ -6,7 +6,7 @@ #include "../../model/tools/search.hpp" #include "../../model/tools/reportmodel.hpp" #include "../../model/world/idtablebase.hpp" -#include "../../model/settings/usersettings.hpp" +#include "../../model/prefs/state.hpp" #include "reporttable.hpp" #include "searchbox.hpp" @@ -23,8 +23,7 @@ void CSVTools::SearchSubView::replace (bool selection) const CSMTools::ReportModel& model = dynamic_cast (*mTable->model()); - bool autoDelete = CSMSettings::UserSettings::instance().setting ( - "search/auto-delete", QString ("true"))=="true"; + bool autoDelete = CSMPrefs::get()["Search & Replace"]["auto-delete"].isTrue(); CSMTools::Search search (mSearch); CSMWorld::IdTableBase *currentTable = 0; @@ -109,13 +108,10 @@ void CSVTools::SearchSubView::stateChanged (int state, CSMDoc::Document *documen void CSVTools::SearchSubView::startSearch (const CSMTools::Search& search) { - CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); - - int paddingBefore = userSettings.setting ("search/char-before", QString ("5")).toInt(); - int paddingAfter = userSettings.setting ("search/char-after", QString ("5")).toInt(); + CSMPrefs::Category& settings = CSMPrefs::get()["Search & Replace"]; mSearch = search; - mSearch.setPadding (paddingBefore, paddingAfter); + mSearch.setPadding (settings["char-before"].toInt(), settings["char-after"].toInt()); mTable->clear(); mDocument.runSearch (getUniversalId(), mSearch); diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index e0c167b0e..25bd8e8ee 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -31,7 +31,8 @@ #include "../../model/world/idtree.hpp" #include "../../model/world/commands.hpp" #include "../../model/doc/document.hpp" -#include "../../model/settings/usersettings.hpp" + +#include "../../model/prefs/state.hpp" #include "../widget/coloreditor.hpp" #include "../widget/droplineedit.hpp" @@ -883,12 +884,12 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, connect (mBottom, SIGNAL (requestFocus (const std::string&)), this, SLOT (requestFocus (const std::string&))); - // button bar - if (CSMSettings::UserSettings::instance().setting ("dialogues/toolbar", QString("true")) == "true") - addButtonBar(); - // layout getMainLayout().addWidget (mBottom); + + connect (&CSMPrefs::State::get(), SIGNAL (settingChanged (const CSMPrefs::Setting *)), + this, SLOT (settingChanged (const CSMPrefs::Setting *))); + CSMPrefs::get()["ID Dialogues"].update(); } void CSVWorld::DialogueSubView::setEditLock (bool locked) @@ -899,24 +900,19 @@ void CSVWorld::DialogueSubView::setEditLock (bool locked) mButtons->setEditLock (locked); } -void CSVWorld::DialogueSubView::updateUserSetting (const QString& name, const QStringList& value) +void CSVWorld::DialogueSubView::settingChanged (const CSMPrefs::Setting *setting) { - SimpleDialogueSubView::updateUserSetting (name, value); - - if (name=="dialogues/toolbar") + if (*setting=="ID Dialogues/toolbar") { - if (value.at(0)==QString ("true")) + if (setting->isTrue()) { addButtonBar(); } - else + else if (mButtons) { - if (mButtons) - { - getMainLayout().removeWidget (mButtons); - delete mButtons; - mButtons = 0; - } + getMainLayout().removeWidget (mButtons); + delete mButtons; + mButtons = 0; } } } diff --git a/apps/opencs/view/world/dialoguesubview.hpp b/apps/opencs/view/world/dialoguesubview.hpp index 2ae0f9720..bd7116ba2 100644 --- a/apps/opencs/view/world/dialoguesubview.hpp +++ b/apps/opencs/view/world/dialoguesubview.hpp @@ -27,6 +27,11 @@ namespace CSMWorld class NestedTableProxyModel; } +namespace CSMPrefs +{ + class Setting; +} + namespace CSMDoc { class Document; @@ -271,10 +276,10 @@ namespace CSVWorld virtual void setEditLock (bool locked); - virtual void updateUserSetting (const QString& name, const QStringList& value); - private slots: + void settingChanged (const CSMPrefs::Setting *setting); + void showPreview(); void viewRecord(); diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index 832e074c4..95dfa1034 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -23,6 +23,7 @@ #include "../../model/world/tablemimedata.hpp" #include "../../model/world/tablemimedata.hpp" #include "../../model/world/commanddispatcher.hpp" + #include "../../model/prefs/state.hpp" #include "recordstatusdelegate.hpp" @@ -232,10 +233,6 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id, : DragRecordTable(document), mCreateAction (0), mCloneAction(0),mRecordStatusDisplay (0) { - connect (&CSMPrefs::State::get(), SIGNAL (settingChanged (const CSMPrefs::Setting *)), - this, SLOT (settingChanged (const CSMPrefs::Setting *))); - CSMPrefs::get()["ID Tables"].update(); - mModel = &dynamic_cast (*mDocument.getData().getTableModel (id)); bool isInfoTable = id.getType() == CSMWorld::UniversalId::Type_TopicInfos || @@ -361,6 +358,10 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id, mDoubleClickActions.insert (std::make_pair (Qt::ShiftModifier, Action_EditRecord)); mDoubleClickActions.insert (std::make_pair (Qt::ControlModifier, Action_View)); mDoubleClickActions.insert (std::make_pair (Qt::ShiftModifier | Qt::ControlModifier, Action_EditRecordAndClose)); + + connect (&CSMPrefs::State::get(), SIGNAL (settingChanged (const CSMPrefs::Setting *)), + this, SLOT (settingChanged (const CSMPrefs::Setting *))); + CSMPrefs::get()["ID Tables"].update(); } void CSVWorld::Table::setEditLock (bool locked) @@ -556,46 +557,6 @@ void CSVWorld::Table::executeExtendedRevert() } } -void CSVWorld::Table::updateUserSetting (const QString &name, const QStringList &list) -{ - QString base ("table-input/double"); - if (name.startsWith (base)) - { - QString modifierString = name.mid (base.size()); - Qt::KeyboardModifiers modifiers = 0; - - if (modifierString=="-s") - modifiers = Qt::ShiftModifier; - else if (modifierString=="-c") - modifiers = Qt::ControlModifier; - else if (modifierString=="-sc") - modifiers = Qt::ShiftModifier | Qt::ControlModifier; - - DoubleClickAction action = Action_None; - - QString value = list.at (0); - - if (value=="Edit in Place") - action = Action_InPlaceEdit; - else if (value=="Edit Record") - action = Action_EditRecord; - else if (value=="View") - action = Action_View; - else if (value=="Revert") - action = Action_Revert; - else if (value=="Delete") - action = Action_Delete; - else if (value=="Edit Record and Close") - action = Action_EditRecordAndClose; - else if (value=="View and Close") - action = Action_ViewAndClose; - - mDoubleClickActions[modifiers] = action; - - return; - } -} - void CSVWorld::Table::settingChanged (const CSMPrefs::Setting *setting) { if (*setting=="ID Tables/jump-to-added") @@ -628,6 +589,41 @@ void CSVWorld::Table::settingChanged (const CSMPrefs::Setting *setting) mModel->index (mModel->rowCount()-1, i)); } } + else if (setting->getParent()->getKey()=="ID Tables" && + setting->getKey().substr (0, 6)=="double") + { + std::string modifierString = setting->getKey().substr (6); + + Qt::KeyboardModifiers modifiers = 0; + + if (modifierString=="-s") + modifiers = Qt::ShiftModifier; + else if (modifierString=="-c") + modifiers = Qt::ControlModifier; + else if (modifierString=="-sc") + modifiers = Qt::ShiftModifier | Qt::ControlModifier; + + DoubleClickAction action = Action_None; + + std::string value = setting->toString(); + + if (value=="Edit in Place") + action = Action_InPlaceEdit; + else if (value=="Edit Record") + action = Action_EditRecord; + else if (value=="View") + action = Action_View; + else if (value=="Revert") + action = Action_Revert; + else if (value=="Delete") + action = Action_Delete; + else if (value=="Edit Record and Close") + action = Action_EditRecordAndClose; + else if (value=="View and Close") + action = Action_ViewAndClose; + + mDoubleClickActions[modifiers] = action; + } } void CSVWorld::Table::tableSizeUpdate() diff --git a/apps/opencs/view/world/table.hpp b/apps/opencs/view/world/table.hpp index 53401a192..53249f66f 100644 --- a/apps/opencs/view/world/table.hpp +++ b/apps/opencs/view/world/table.hpp @@ -155,8 +155,6 @@ namespace CSVWorld void recordFilterChanged (boost::shared_ptr filter); - void updateUserSetting (const QString &name, const QStringList &list); - void rowAdded(const std::string &id); }; } diff --git a/apps/opencs/view/world/tablesubview.cpp b/apps/opencs/view/world/tablesubview.cpp index 81b269993..1b25e1c08 100644 --- a/apps/opencs/view/world/tablesubview.cpp +++ b/apps/opencs/view/world/tablesubview.cpp @@ -98,12 +98,6 @@ void CSVWorld::TableSubView::editRequest (const CSMWorld::UniversalId& id, const focusId (id, hint); } -void CSVWorld::TableSubView::updateUserSetting - (const QString &name, const QStringList &list) -{ - mTable->updateUserSetting(name, list); -} - void CSVWorld::TableSubView::setStatusBar (bool show) { mBottom->setStatusBar (show); diff --git a/apps/opencs/view/world/tablesubview.hpp b/apps/opencs/view/world/tablesubview.hpp index 9d86c32e4..7d143d927 100644 --- a/apps/opencs/view/world/tablesubview.hpp +++ b/apps/opencs/view/world/tablesubview.hpp @@ -43,9 +43,6 @@ namespace CSVWorld virtual void setEditLock (bool locked); - virtual void updateUserSetting - (const QString& name, const QStringList &list); - virtual void setStatusBar (bool show); virtual void useHint (const std::string& hint); From 591564566c91162a8225f360c9b52bf03840acc7 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 15 Dec 2015 12:19:48 +0100 Subject: [PATCH 2816/3725] made user settings access thread-safe --- apps/opencs/model/prefs/boolsetting.cpp | 11 ++++++++--- apps/opencs/model/prefs/boolsetting.hpp | 2 +- apps/opencs/model/prefs/coloursetting.cpp | 13 ++++++++----- apps/opencs/model/prefs/coloursetting.hpp | 3 ++- apps/opencs/model/prefs/doublesetting.cpp | 12 +++++++++--- apps/opencs/model/prefs/doublesetting.hpp | 3 ++- apps/opencs/model/prefs/enumsetting.cpp | 11 ++++++++--- apps/opencs/model/prefs/enumsetting.hpp | 3 ++- apps/opencs/model/prefs/intsetting.cpp | 11 ++++++++--- apps/opencs/model/prefs/intsetting.hpp | 2 +- apps/opencs/model/prefs/setting.cpp | 16 ++++++++++++++-- apps/opencs/model/prefs/setting.hpp | 6 +++++- apps/opencs/model/prefs/state.cpp | 17 +++++++++++------ apps/opencs/model/prefs/state.hpp | 6 ++++++ 14 files changed, 85 insertions(+), 31 deletions(-) diff --git a/apps/opencs/model/prefs/boolsetting.cpp b/apps/opencs/model/prefs/boolsetting.cpp index 459993325..6c0babaf7 100644 --- a/apps/opencs/model/prefs/boolsetting.cpp +++ b/apps/opencs/model/prefs/boolsetting.cpp @@ -2,6 +2,7 @@ #include "boolsetting.hpp" #include +#include #include @@ -9,8 +10,8 @@ #include "state.hpp" CSMPrefs::BoolSetting::BoolSetting (Category *parent, Settings::Manager *values, - const std::string& key, const std::string& label, bool default_) -: Setting (parent, values, key, label), mDefault (default_) + QMutex *mutex, const std::string& key, const std::string& label, bool default_) +: Setting (parent, values, mutex, key, label), mDefault (default_) {} CSMPrefs::BoolSetting& CSMPrefs::BoolSetting::setTooltip (const std::string& tooltip) @@ -37,6 +38,10 @@ std::pair CSMPrefs::BoolSetting::makeWidgets (QWidget *par void CSMPrefs::BoolSetting::valueChanged (int value) { - getValues().setBool (getKey(), getParent()->getKey(), value); + { + QMutexLocker lock (getMutex()); + getValues().setBool (getKey(), getParent()->getKey(), value); + } + getParent()->getState()->update (*this); } diff --git a/apps/opencs/model/prefs/boolsetting.hpp b/apps/opencs/model/prefs/boolsetting.hpp index dfc28c5ae..f8a321859 100644 --- a/apps/opencs/model/prefs/boolsetting.hpp +++ b/apps/opencs/model/prefs/boolsetting.hpp @@ -15,7 +15,7 @@ namespace CSMPrefs public: BoolSetting (Category *parent, Settings::Manager *values, - const std::string& key, const std::string& label, bool default_); + QMutex *mutex, const std::string& key, const std::string& label, bool default_); BoolSetting& setTooltip (const std::string& tooltip); diff --git a/apps/opencs/model/prefs/coloursetting.cpp b/apps/opencs/model/prefs/coloursetting.cpp index a56485292..d51bfad56 100644 --- a/apps/opencs/model/prefs/coloursetting.cpp +++ b/apps/opencs/model/prefs/coloursetting.cpp @@ -1,9 +1,8 @@ #include "coloursetting.hpp" -#include - #include +#include #include @@ -13,8 +12,8 @@ #include "state.hpp" CSMPrefs::ColourSetting::ColourSetting (Category *parent, Settings::Manager *values, - const std::string& key, const std::string& label, QColor default_) -: Setting (parent, values, key, label), mDefault (default_) + QMutex *mutex, const std::string& key, const std::string& label, QColor default_) +: Setting (parent, values, mutex, key, label), mDefault (default_) {} CSMPrefs::ColourSetting& CSMPrefs::ColourSetting::setTooltip (const std::string& tooltip) @@ -44,6 +43,10 @@ std::pair CSMPrefs::ColourSetting::makeWidgets (QWidget *p void CSMPrefs::ColourSetting::valueChanged() { CSVWidget::ColorEditor& widget = dynamic_cast (*sender()); - getValues().setString (getKey(), getParent()->getKey(), widget.color().name().toUtf8().data()); + { + QMutexLocker lock (getMutex()); + getValues().setString (getKey(), getParent()->getKey(), widget.color().name().toUtf8().data()); + } + getParent()->getState()->update (*this); } diff --git a/apps/opencs/model/prefs/coloursetting.hpp b/apps/opencs/model/prefs/coloursetting.hpp index fed2adc0a..be58426f2 100644 --- a/apps/opencs/model/prefs/coloursetting.hpp +++ b/apps/opencs/model/prefs/coloursetting.hpp @@ -17,7 +17,8 @@ namespace CSMPrefs public: ColourSetting (Category *parent, Settings::Manager *values, - const std::string& key, const std::string& label, QColor default_); + QMutex *mutex, const std::string& key, const std::string& label, + QColor default_); ColourSetting& setTooltip (const std::string& tooltip); diff --git a/apps/opencs/model/prefs/doublesetting.cpp b/apps/opencs/model/prefs/doublesetting.cpp index 2eabc78bf..7c247777d 100644 --- a/apps/opencs/model/prefs/doublesetting.cpp +++ b/apps/opencs/model/prefs/doublesetting.cpp @@ -5,6 +5,7 @@ #include #include +#include #include @@ -12,8 +13,9 @@ #include "state.hpp" CSMPrefs::DoubleSetting::DoubleSetting (Category *parent, Settings::Manager *values, - const std::string& key, const std::string& label, double default_) -: Setting (parent, values, key, label), mMin (0), mMax (std::numeric_limits::max()), + QMutex *mutex, const std::string& key, const std::string& label, double default_) +: Setting (parent, values, mutex, key, label), + mMin (0), mMax (std::numeric_limits::max()), mDefault (default_) {} @@ -64,6 +66,10 @@ std::pair CSMPrefs::DoubleSetting::makeWidgets (QWidget *p void CSMPrefs::DoubleSetting::valueChanged (double value) { - getValues().setFloat (getKey(), getParent()->getKey(), value); + { + QMutexLocker lock (getMutex()); + getValues().setFloat (getKey(), getParent()->getKey(), value); + } + getParent()->getState()->update (*this); } diff --git a/apps/opencs/model/prefs/doublesetting.hpp b/apps/opencs/model/prefs/doublesetting.hpp index d0735d30a..3868f014e 100644 --- a/apps/opencs/model/prefs/doublesetting.hpp +++ b/apps/opencs/model/prefs/doublesetting.hpp @@ -17,7 +17,8 @@ namespace CSMPrefs public: DoubleSetting (Category *parent, Settings::Manager *values, - const std::string& key, const std::string& label, double default_); + QMutex *mutex, const std::string& key, const std::string& label, + double default_); // defaults to [0, std::numeric_limits::max()] DoubleSetting& setRange (double min, double max); diff --git a/apps/opencs/model/prefs/enumsetting.cpp b/apps/opencs/model/prefs/enumsetting.cpp index ea7d0703e..e69f717ea 100644 --- a/apps/opencs/model/prefs/enumsetting.cpp +++ b/apps/opencs/model/prefs/enumsetting.cpp @@ -3,6 +3,7 @@ #include #include +#include #include @@ -39,8 +40,8 @@ CSMPrefs::EnumValues& CSMPrefs::EnumValues::add (const std::string& value, const CSMPrefs::EnumSetting::EnumSetting (Category *parent, Settings::Manager *values, - const std::string& key, const std::string& label, const EnumValue& default_) -: Setting (parent, values, key, label), mDefault (default_) + QMutex *mutex, const std::string& key, const std::string& label, const EnumValue& default_) +: Setting (parent, values, mutex, key, label), mDefault (default_) {} CSMPrefs::EnumSetting& CSMPrefs::EnumSetting::setTooltip (const std::string& tooltip) @@ -102,6 +103,10 @@ std::pair CSMPrefs::EnumSetting::makeWidgets (QWidget *par void CSMPrefs::EnumSetting::valueChanged (int value) { - getValues().setString (getKey(), getParent()->getKey(), mValues.mValues.at (value).mValue); + { + QMutexLocker lock (getMutex()); + getValues().setString (getKey(), getParent()->getKey(), mValues.mValues.at (value).mValue); + } + getParent()->getState()->update (*this); } diff --git a/apps/opencs/model/prefs/enumsetting.hpp b/apps/opencs/model/prefs/enumsetting.hpp index e2102d20e..728de3acd 100644 --- a/apps/opencs/model/prefs/enumsetting.hpp +++ b/apps/opencs/model/prefs/enumsetting.hpp @@ -39,7 +39,8 @@ namespace CSMPrefs public: EnumSetting (Category *parent, Settings::Manager *values, - const std::string& key, const std::string& label, const EnumValue& default_); + QMutex *mutex, const std::string& key, const std::string& label, + const EnumValue& default_); EnumSetting& setTooltip (const std::string& tooltip); diff --git a/apps/opencs/model/prefs/intsetting.cpp b/apps/opencs/model/prefs/intsetting.cpp index 83fb495c5..269a63af4 100644 --- a/apps/opencs/model/prefs/intsetting.cpp +++ b/apps/opencs/model/prefs/intsetting.cpp @@ -5,6 +5,7 @@ #include #include +#include #include @@ -12,8 +13,8 @@ #include "state.hpp" CSMPrefs::IntSetting::IntSetting (Category *parent, Settings::Manager *values, - const std::string& key, const std::string& label, int default_) -: Setting (parent, values, key, label), mMin (0), mMax (std::numeric_limits::max()), + QMutex *mutex, const std::string& key, const std::string& label, int default_) +: Setting (parent, values, mutex, key, label), mMin (0), mMax (std::numeric_limits::max()), mDefault (default_) {} @@ -64,6 +65,10 @@ std::pair CSMPrefs::IntSetting::makeWidgets (QWidget *pare void CSMPrefs::IntSetting::valueChanged (int value) { - getValues().setInt (getKey(), getParent()->getKey(), value); + { + QMutexLocker lock (getMutex()); + getValues().setInt (getKey(), getParent()->getKey(), value); + } + getParent()->getState()->update (*this); } diff --git a/apps/opencs/model/prefs/intsetting.hpp b/apps/opencs/model/prefs/intsetting.hpp index 05acb9fbc..0ee6cf9e3 100644 --- a/apps/opencs/model/prefs/intsetting.hpp +++ b/apps/opencs/model/prefs/intsetting.hpp @@ -17,7 +17,7 @@ namespace CSMPrefs public: IntSetting (Category *parent, Settings::Manager *values, - const std::string& key, const std::string& label, int default_); + QMutex *mutex, const std::string& key, const std::string& label, int default_); // defaults to [0, std::numeric_limits::max()] IntSetting& setRange (int min, int max); diff --git a/apps/opencs/model/prefs/setting.cpp b/apps/opencs/model/prefs/setting.cpp index 39d997988..89924ae29 100644 --- a/apps/opencs/model/prefs/setting.cpp +++ b/apps/opencs/model/prefs/setting.cpp @@ -2,6 +2,7 @@ #include "setting.hpp" #include +#include #include "category.hpp" #include "state.hpp" @@ -11,9 +12,15 @@ Settings::Manager& CSMPrefs::Setting::getValues() return *mValues; } -CSMPrefs::Setting::Setting (Category *parent, Settings::Manager *values, +QMutex *CSMPrefs::Setting::getMutex() +{ + return mMutex; +} + +CSMPrefs::Setting::Setting (Category *parent, Settings::Manager *values, QMutex *mutex, const std::string& key, const std::string& label) -: QObject (parent->getState()), mParent (parent), mValues (values), mKey (key), mLabel (label) +: QObject (parent->getState()), mParent (parent), mValues (values), mMutex (mutex), mKey (key), + mLabel (label) {} CSMPrefs::Setting:: ~Setting() {} @@ -40,26 +47,31 @@ const std::string& CSMPrefs::Setting::getLabel() const int CSMPrefs::Setting::toInt() const { + QMutexLocker lock (mMutex); return mValues->getInt (mKey, mParent->getKey()); } double CSMPrefs::Setting::toDouble() const { + QMutexLocker lock (mMutex); return mValues->getFloat (mKey, mParent->getKey()); } std::string CSMPrefs::Setting::toString() const { + QMutexLocker lock (mMutex); return mValues->getString (mKey, mParent->getKey()); } bool CSMPrefs::Setting::isTrue() const { + QMutexLocker lock (mMutex); return mValues->getBool (mKey, mParent->getKey()); } QColor CSMPrefs::Setting::toColor() const { + QMutexLocker lock (mMutex); return QColor (QString::fromUtf8 (toString().c_str())); } diff --git a/apps/opencs/model/prefs/setting.hpp b/apps/opencs/model/prefs/setting.hpp index 65354469d..00bcc638b 100644 --- a/apps/opencs/model/prefs/setting.hpp +++ b/apps/opencs/model/prefs/setting.hpp @@ -8,6 +8,7 @@ class QWidget; class QColor; +class QMutex; namespace Settings { @@ -24,6 +25,7 @@ namespace CSMPrefs Category *mParent; Settings::Manager *mValues; + QMutex *mMutex; std::string mKey; std::string mLabel; @@ -31,9 +33,11 @@ namespace CSMPrefs Settings::Manager& getValues(); + QMutex *getMutex(); + public: - Setting (Category *parent, Settings::Manager *values, const std::string& key, const std::string& label); + Setting (Category *parent, Settings::Manager *values, QMutex *mutex, const std::string& key, const std::string& label); virtual ~Setting(); diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index ab9fd0a28..64ce512bf 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -220,7 +220,8 @@ CSMPrefs::IntSetting& CSMPrefs::State::declareInt (const std::string& key, default_ = mSettings.getInt (key, mCurrentCategory->second.getKey()); CSMPrefs::IntSetting *setting = - new CSMPrefs::IntSetting (&mCurrentCategory->second, &mSettings, key, label, default_); + new CSMPrefs::IntSetting (&mCurrentCategory->second, &mSettings, &mMutex, key, label, + default_); mCurrentCategory->second.addSetting (setting); @@ -240,7 +241,8 @@ CSMPrefs::DoubleSetting& CSMPrefs::State::declareDouble (const std::string& key, default_ = mSettings.getFloat (key, mCurrentCategory->second.getKey()); CSMPrefs::DoubleSetting *setting = - new CSMPrefs::DoubleSetting (&mCurrentCategory->second, &mSettings, key, label, default_); + new CSMPrefs::DoubleSetting (&mCurrentCategory->second, &mSettings, &mMutex, + key, label, default_); mCurrentCategory->second.addSetting (setting); @@ -258,7 +260,8 @@ CSMPrefs::BoolSetting& CSMPrefs::State::declareBool (const std::string& key, default_ = mSettings.getBool (key, mCurrentCategory->second.getKey()); CSMPrefs::BoolSetting *setting = - new CSMPrefs::BoolSetting (&mCurrentCategory->second, &mSettings, key, label, default_); + new CSMPrefs::BoolSetting (&mCurrentCategory->second, &mSettings, &mMutex, key, label, + default_); mCurrentCategory->second.addSetting (setting); @@ -276,7 +279,8 @@ CSMPrefs::EnumSetting& CSMPrefs::State::declareEnum (const std::string& key, default_.mValue = mSettings.getString (key, mCurrentCategory->second.getKey()); CSMPrefs::EnumSetting *setting = - new CSMPrefs::EnumSetting (&mCurrentCategory->second, &mSettings, key, label, default_); + new CSMPrefs::EnumSetting (&mCurrentCategory->second, &mSettings, &mMutex, key, label, + default_); mCurrentCategory->second.addSetting (setting); @@ -294,7 +298,8 @@ CSMPrefs::ColourSetting& CSMPrefs::State::declareColour (const std::string& key, default_.setNamedColor (QString::fromUtf8 (mSettings.getString (key, mCurrentCategory->second.getKey()).c_str())); CSMPrefs::ColourSetting *setting = - new CSMPrefs::ColourSetting (&mCurrentCategory->second, &mSettings, key, label, default_); + new CSMPrefs::ColourSetting (&mCurrentCategory->second, &mSettings, &mMutex, key, label, + default_); mCurrentCategory->second.addSetting (setting); @@ -307,7 +312,7 @@ void CSMPrefs::State::declareSeparator() throw std::logic_error ("no category for setting"); CSMPrefs::Setting *setting = - new CSMPrefs::Setting (&mCurrentCategory->second, &mSettings, "", ""); + new CSMPrefs::Setting (&mCurrentCategory->second, &mSettings, &mMutex, "", ""); mCurrentCategory->second.addSetting (setting); } diff --git a/apps/opencs/model/prefs/state.hpp b/apps/opencs/model/prefs/state.hpp index 7807dac25..bcd76c671 100644 --- a/apps/opencs/model/prefs/state.hpp +++ b/apps/opencs/model/prefs/state.hpp @@ -5,6 +5,7 @@ #include #include +#include #ifndef Q_MOC_RUN #include @@ -25,6 +26,10 @@ namespace CSMPrefs class BoolSetting; class ColourSetting; + /// \brief User settings state + /// + /// \note Access to the user settings is thread-safe once all declarations and loading has + /// been completed. class State : public QObject { Q_OBJECT @@ -43,6 +48,7 @@ namespace CSMPrefs Settings::Manager mSettings; Collection mCategories; Iterator mCurrentCategory; + QMutex mMutex; // not implemented State (const State&); From 44925e9fc8c4858ee3a0f3bbe9597ee033fcaca9 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 15 Dec 2015 12:26:08 +0100 Subject: [PATCH 2817/3725] fixed records settings (Text Only wasn't updating) --- apps/opencs/model/prefs/state.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index 64ce512bf..738a50967 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -74,7 +74,7 @@ void CSMPrefs::State::declare() declareCategory ("Records"); EnumValue iconAndText ("Icon and Text"); EnumValues recordValues; - recordValues.add (iconAndText).add ("Icon Only").add ("Text only"); + recordValues.add (iconAndText).add ("Icon Only").add ("Text Only"); declareEnum ("status-format", "Modification status display format", iconAndText). addValues (recordValues); declareEnum ("type-format", "ID type display format", iconAndText). From 67cf260144845858a5c56cbc066edab9238ad17d Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 15 Dec 2015 12:44:04 +0100 Subject: [PATCH 2818/3725] final batch of changing over user settings usage to the new system --- apps/opencs/model/doc/operation.cpp | 23 ++----------------- apps/opencs/model/doc/operation.hpp | 8 ------- apps/opencs/model/doc/operationholder.cpp | 5 ---- apps/opencs/model/doc/stage.cpp | 2 -- apps/opencs/model/doc/stage.hpp | 4 ---- apps/opencs/model/tools/scriptcheck.cpp | 28 +++++++++++------------ apps/opencs/model/tools/scriptcheck.hpp | 4 +--- apps/opencs/model/tools/tools.cpp | 5 ---- apps/opencs/view/doc/view.hpp | 2 -- 9 files changed, 16 insertions(+), 65 deletions(-) diff --git a/apps/opencs/model/doc/operation.cpp b/apps/opencs/model/doc/operation.cpp index cb9b7ec29..2fd54bd3e 100644 --- a/apps/opencs/model/doc/operation.cpp +++ b/apps/opencs/model/doc/operation.cpp @@ -23,9 +23,6 @@ void CSMDoc::Operation::prepareStages() { iter->second = iter->first->setup(); mTotalSteps += iter->second; - - for (std::map::const_iterator iter2 (mSettings.begin()); iter2!=mSettings.end(); ++iter2) - iter->first->updateUserSetting (iter2->first, iter2->second); } } @@ -47,7 +44,7 @@ CSMDoc::Operation::~Operation() void CSMDoc::Operation::run() { mTimer->stop(); - + if (!mConnected) { connect (mTimer, SIGNAL (timeout()), this, SLOT (executeStage())); @@ -64,14 +61,6 @@ void CSMDoc::Operation::appendStage (Stage *stage) mStages.push_back (std::make_pair (stage, 0)); } -void CSMDoc::Operation::configureSettings (const std::vector& settings) -{ - for (std::vector::const_iterator iter (settings.begin()); iter!=settings.end(); ++iter) - { - mSettings.insert (std::make_pair (*iter, CSMSettings::UserSettings::instance().definitions (*iter))); - } -} - void CSMDoc::Operation::setDefaultSeverity (Message::Severity severity) { mDefaultSeverity = severity; @@ -101,14 +90,6 @@ void CSMDoc::Operation::abort() mCurrentStage = mStages.end(); } -void CSMDoc::Operation::updateUserSetting (const QString& name, const QStringList& value) -{ - std::map::iterator iter = mSettings.find (name); - - if (iter!=mSettings.end()) - iter->second = value; -} - void CSMDoc::Operation::executeStage() { if (!mPrepared) @@ -116,7 +97,7 @@ void CSMDoc::Operation::executeStage() prepareStages(); mPrepared = true; } - + Messages messages (mDefaultSeverity); while (mCurrentStage!=mStages.end()) diff --git a/apps/opencs/model/doc/operation.hpp b/apps/opencs/model/doc/operation.hpp index 3c86a6e23..ff396fa3c 100644 --- a/apps/opencs/model/doc/operation.hpp +++ b/apps/opencs/model/doc/operation.hpp @@ -34,7 +34,6 @@ namespace CSMDoc bool mError; bool mConnected; QTimer *mTimer; - std::map mSettings; bool mPrepared; Message::Severity mDefaultSeverity; @@ -53,11 +52,6 @@ namespace CSMDoc /// /// \attention Do no call this function while this Operation is running. - /// Specify settings to be passed on to stages. - /// - /// \attention Do no call this function while this Operation is running. - void configureSettings (const std::vector& settings); - /// \attention Do no call this function while this Operation is running. void setDefaultSeverity (Message::Severity severity); @@ -77,8 +71,6 @@ namespace CSMDoc void run(); - void updateUserSetting (const QString& name, const QStringList& value); - private slots: void executeStage(); diff --git a/apps/opencs/model/doc/operationholder.cpp b/apps/opencs/model/doc/operationholder.cpp index db0d1a9a4..5fcf24fe4 100644 --- a/apps/opencs/model/doc/operationholder.cpp +++ b/apps/opencs/model/doc/operationholder.cpp @@ -1,7 +1,5 @@ #include "operationholder.hpp" -#include "../settings/usersettings.hpp" - #include "operation.hpp" CSMDoc::OperationHolder::OperationHolder (Operation *operation) : mRunning (false) @@ -30,9 +28,6 @@ void CSMDoc::OperationHolder::setOperation (Operation *operation) connect (this, SIGNAL (abortSignal()), mOperation, SLOT (abort())); connect (&mThread, SIGNAL (started()), mOperation, SLOT (run())); - - connect (&CSMSettings::UserSettings::instance(), SIGNAL (userSettingUpdated (const QString&, const QStringList&)), - mOperation, SLOT (updateUserSetting (const QString&, const QStringList&))); } bool CSMDoc::OperationHolder::isRunning() const diff --git a/apps/opencs/model/doc/stage.cpp b/apps/opencs/model/doc/stage.cpp index c8da86069..3c8c107ba 100644 --- a/apps/opencs/model/doc/stage.cpp +++ b/apps/opencs/model/doc/stage.cpp @@ -1,5 +1,3 @@ #include "stage.hpp" CSMDoc::Stage::~Stage() {} - -void CSMDoc::Stage::updateUserSetting (const QString& name, const QStringList& value) {} diff --git a/apps/opencs/model/doc/stage.hpp b/apps/opencs/model/doc/stage.hpp index e0328a91a..1eae27a98 100644 --- a/apps/opencs/model/doc/stage.hpp +++ b/apps/opencs/model/doc/stage.hpp @@ -23,11 +23,7 @@ namespace CSMDoc virtual void perform (int stage, Messages& messages) = 0; ///< Messages resulting from this stage will be appended to \a messages. - - /// Default-implementation: ignore - virtual void updateUserSetting (const QString& name, const QStringList& value); }; } #endif - diff --git a/apps/opencs/model/tools/scriptcheck.cpp b/apps/opencs/model/tools/scriptcheck.cpp index d7c41cfcf..268aea379 100644 --- a/apps/opencs/model/tools/scriptcheck.cpp +++ b/apps/opencs/model/tools/scriptcheck.cpp @@ -10,6 +10,8 @@ #include "../world/data.hpp" +#include "../prefs/state.hpp" + CSMDoc::Message::Severity CSMTools::ScriptCheckStage::getSeverity (Type type) { switch (type) @@ -46,7 +48,7 @@ void CSMTools::ScriptCheckStage::report (const std::string& message, Type type) std::ostringstream stream; stream << "script " << mFile << ": " << message; - + mMessages->add (id, stream.str(), "", getSeverity (type)); } @@ -62,6 +64,15 @@ CSMTools::ScriptCheckStage::ScriptCheckStage (const CSMDoc::Document& document) int CSMTools::ScriptCheckStage::setup() { + std::string warnings = CSMPrefs::get()["Scripts"]["warnings"].toString(); + + if (warnings=="Ignore") + mWarningMode = Mode_Ignore; + else if (warnings=="Normal") + mWarningMode = Mode_Normal; + else if (warnings=="Strict") + mWarningMode = Mode_Strict; + mContext.clear(); mMessages = 0; mId.clear(); @@ -110,22 +121,9 @@ void CSMTools::ScriptCheckStage::perform (int stage, CSMDoc::Messages& messages) std::ostringstream stream; stream << "script " << mFile << ": " << error.what(); - + messages.add (id, stream.str(), "", CSMDoc::Message::Severity_SeriousError); } mMessages = 0; } - -void CSMTools::ScriptCheckStage::updateUserSetting (const QString& name, const QStringList& value) -{ - if (name=="script-editor/warnings" && !value.isEmpty()) - { - if (value.at (0)=="Ignore") - mWarningMode = Mode_Ignore; - else if (value.at (0)=="Normal") - mWarningMode = Mode_Normal; - else if (value.at (0)=="Strict") - mWarningMode = Mode_Strict; - } -} diff --git a/apps/opencs/model/tools/scriptcheck.hpp b/apps/opencs/model/tools/scriptcheck.hpp index 3f0276652..f58215800 100644 --- a/apps/opencs/model/tools/scriptcheck.hpp +++ b/apps/opencs/model/tools/scriptcheck.hpp @@ -34,7 +34,7 @@ namespace CSMTools WarningMode mWarningMode; CSMDoc::Message::Severity getSeverity (Type type); - + virtual void report (const std::string& message, const Compiler::TokenLoc& loc, Type type); ///< Report error to the user. @@ -50,8 +50,6 @@ namespace CSMTools virtual void perform (int stage, CSMDoc::Messages& messages); ///< Messages resulting from this tage will be appended to \a messages. - - virtual void updateUserSetting (const QString& name, const QStringList& value); }; } diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index fdbf406f1..608ed9922 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -53,11 +53,6 @@ CSMDoc::OperationHolder *CSMTools::Tools::getVerifier() { mVerifierOperation = new CSMDoc::Operation (CSMDoc::State_Verifying, false); - std::vector settings; - settings.push_back ("script-editor/warnings"); - - mVerifierOperation->configureSettings (settings); - connect (&mVerifier, SIGNAL (progress (int, int, int)), this, SIGNAL (progress (int, int, int))); connect (&mVerifier, SIGNAL (done (int, bool)), this, SIGNAL (done (int, bool))); connect (&mVerifier, SIGNAL (reportMessage (const CSMDoc::Message&, int)), diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index 90eeeb407..7d5304269 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -88,8 +88,6 @@ namespace CSVDoc void exitApplication(); - void loadUserSettings(); - /// User preference function void resizeViewWidth (int width); From c646533448aec57a6b6d204b856d6dc80f74b17b Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 15 Dec 2015 12:49:55 +0100 Subject: [PATCH 2819/3725] removed old user settings system --- apps/opencs/CMakeLists.txt | 27 - apps/opencs/editor.cpp | 5 +- apps/opencs/editor.hpp | 4 - apps/opencs/model/doc/operation.cpp | 1 - apps/opencs/model/settings/connector.cpp | 128 --- apps/opencs/model/settings/connector.hpp | 67 -- apps/opencs/model/settings/setting.cpp | 414 --------- apps/opencs/model/settings/setting.hpp | 159 ---- apps/opencs/model/settings/support.hpp | 149 ---- apps/opencs/model/settings/usersettings.cpp | 824 ------------------ apps/opencs/model/settings/usersettings.hpp | 107 --- apps/opencs/view/render/scenewidget.cpp | 1 - apps/opencs/view/settings/booleanview.cpp | 120 --- apps/opencs/view/settings/booleanview.hpp | 45 - apps/opencs/view/settings/dialog.cpp | 127 --- apps/opencs/view/settings/dialog.hpp | 50 -- apps/opencs/view/settings/frame.cpp | 108 --- apps/opencs/view/settings/frame.hpp | 60 -- apps/opencs/view/settings/listview.cpp | 106 --- apps/opencs/view/settings/listview.hpp | 63 -- apps/opencs/view/settings/page.cpp | 110 --- apps/opencs/view/settings/page.hpp | 56 -- apps/opencs/view/settings/rangeview.cpp | 208 ----- apps/opencs/view/settings/rangeview.hpp | 55 -- .../view/settings/resizeablestackedwidget.cpp | 39 - .../view/settings/resizeablestackedwidget.hpp | 25 - apps/opencs/view/settings/settingwindow.cpp | 131 --- apps/opencs/view/settings/settingwindow.hpp | 58 -- apps/opencs/view/settings/spinbox.cpp | 50 -- apps/opencs/view/settings/spinbox.hpp | 38 - apps/opencs/view/settings/textview.cpp | 63 -- apps/opencs/view/settings/textview.hpp | 51 -- apps/opencs/view/settings/view.cpp | 222 ----- apps/opencs/view/settings/view.hpp | 160 ---- .../view/world/recordstatusdelegate.cpp | 1 - 35 files changed, 1 insertion(+), 3831 deletions(-) delete mode 100644 apps/opencs/model/settings/connector.cpp delete mode 100644 apps/opencs/model/settings/connector.hpp delete mode 100644 apps/opencs/model/settings/setting.cpp delete mode 100644 apps/opencs/model/settings/setting.hpp delete mode 100644 apps/opencs/model/settings/support.hpp delete mode 100644 apps/opencs/model/settings/usersettings.cpp delete mode 100644 apps/opencs/model/settings/usersettings.hpp delete mode 100644 apps/opencs/view/settings/booleanview.cpp delete mode 100644 apps/opencs/view/settings/booleanview.hpp delete mode 100644 apps/opencs/view/settings/dialog.cpp delete mode 100644 apps/opencs/view/settings/dialog.hpp delete mode 100644 apps/opencs/view/settings/frame.cpp delete mode 100644 apps/opencs/view/settings/frame.hpp delete mode 100644 apps/opencs/view/settings/listview.cpp delete mode 100644 apps/opencs/view/settings/listview.hpp delete mode 100644 apps/opencs/view/settings/page.cpp delete mode 100644 apps/opencs/view/settings/page.hpp delete mode 100644 apps/opencs/view/settings/rangeview.cpp delete mode 100644 apps/opencs/view/settings/rangeview.hpp delete mode 100644 apps/opencs/view/settings/resizeablestackedwidget.cpp delete mode 100644 apps/opencs/view/settings/resizeablestackedwidget.hpp delete mode 100644 apps/opencs/view/settings/settingwindow.cpp delete mode 100644 apps/opencs/view/settings/settingwindow.hpp delete mode 100644 apps/opencs/view/settings/spinbox.cpp delete mode 100644 apps/opencs/view/settings/spinbox.hpp delete mode 100644 apps/opencs/view/settings/textview.cpp delete mode 100644 apps/opencs/view/settings/textview.hpp delete mode 100644 apps/opencs/view/settings/view.cpp delete mode 100644 apps/opencs/view/settings/view.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index e76b5ce77..0e9a49432 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -106,37 +106,10 @@ opencs_units_noqt (view/tools subviews ) -opencs_units (view/settings - settingwindow - dialog - page - view - booleanview - textview - listview - rangeview - resizeablestackedwidget - spinbox - ) - -opencs_units_noqt (view/settings - frame - ) - opencs_units (view/prefs dialogue pagebase page ) -opencs_units (model/settings - usersettings - setting - connector - ) - -opencs_hdrs_noqt (model/settings - support - ) - opencs_units (model/prefs state setting intsetting doublesetting boolsetting enumsetting coloursetting ) diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 78959fe09..92f1082b7 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -18,7 +18,7 @@ #endif CS::Editor::Editor () -: mSettingsState (mCfgMgr), mUserSettings (mCfgMgr), mDocumentManager (mCfgMgr), +: mSettingsState (mCfgMgr), mDocumentManager (mCfgMgr), mViewManager (mDocumentManager), mPid(""), mLock(), mMerge (mDocumentManager), mIpcServerName ("org.openmw.OpenCS"), mServer(NULL), mClientSocket(NULL) @@ -27,9 +27,6 @@ CS::Editor::Editor () setupDataFiles (config.first); - CSMSettings::UserSettings::instance().loadSettings ("opencs.ini"); -// mSettings.setModel (CSMSettings::UserSettings::instance()); - NifOsg::Loader::setShowMarkers(true); mVFS.reset(new VFS::Manager(mFsStrict)); diff --git a/apps/opencs/editor.hpp b/apps/opencs/editor.hpp index d7fc0b715..b088e9a44 100644 --- a/apps/opencs/editor.hpp +++ b/apps/opencs/editor.hpp @@ -17,7 +17,6 @@ #include -#include "model/settings/usersettings.hpp" #include "model/doc/documentmanager.hpp" #include "model/prefs/state.hpp" @@ -27,8 +26,6 @@ #include "view/doc/filedialog.hpp" #include "view/doc/newgame.hpp" -#include "view/settings/dialog.hpp" - #include "view/prefs/dialogue.hpp" #include "view/tools/merge.hpp" @@ -54,7 +51,6 @@ namespace CS Files::ConfigurationManager mCfgMgr; CSMPrefs::State mSettingsState; - CSMSettings::UserSettings mUserSettings; CSMDoc::DocumentManager mDocumentManager; CSVDoc::ViewManager mViewManager; CSVDoc::StartupDialogue mStartup; diff --git a/apps/opencs/model/doc/operation.cpp b/apps/opencs/model/doc/operation.cpp index 2fd54bd3e..a27ee9f51 100644 --- a/apps/opencs/model/doc/operation.cpp +++ b/apps/opencs/model/doc/operation.cpp @@ -6,7 +6,6 @@ #include #include "../world/universalid.hpp" -#include "../settings/usersettings.hpp" #include "state.hpp" #include "stage.hpp" diff --git a/apps/opencs/model/settings/connector.cpp b/apps/opencs/model/settings/connector.cpp deleted file mode 100644 index 3cf21123c..000000000 --- a/apps/opencs/model/settings/connector.cpp +++ /dev/null @@ -1,128 +0,0 @@ -#include "connector.hpp" -#include "../../view/settings/view.hpp" -#include "../../view/settings/page.hpp" - -CSMSettings::Connector::Connector(CSVSettings::View *master, - QObject *parent) - : QObject(parent), mMasterView (master) -{} - -void CSMSettings::Connector::addSlaveView (CSVSettings::View *view, - QList &masterProxyValues) -{ - mSlaveViews.append (view); - - mProxyListMap[view->viewKey()].append (masterProxyValues); -} - -QList CSMSettings::Connector::getSlaveViewValues() const -{ - QList list; - - foreach (const CSVSettings::View *view, mSlaveViews) - list.append (view->selectedValues()); - - return list; -} - -bool CSMSettings::Connector::proxyListsMatch ( - const QList &list1, - const QList &list2) const -{ - bool success = true; - - for (int i = 0; i < list1.size(); i++) - { - success = stringListsMatch (list1.at(i), list2.at(i)); - - if (!success) - break; - } - return success; -} - -void CSMSettings::Connector::slotUpdateMaster() const -{ - //list of the current values for each slave. - QList slaveValueList = getSlaveViewValues(); - - int masterColumn = -1; - - /* - * A row in the master view is one of the values in the - * master view's data model. This corresponds directly to the number of - * values in a proxy list contained in the ProxyListMap member. - * Thus, we iterate each "column" in the master proxy list - * (one for each vlaue in the master. Each column represents - * one master value's corresponding list of slave values. We examine - * each master value's list, comparing it to the current slave value list, - * stopping when we find a match using proxyListsMatch(). - * - * If no match is found, clear the master view's value - */ - - for (int i = 0; i < mMasterView->rowCount(); i++) - { - QList proxyValueList; - - foreach (const QString &settingKey, mProxyListMap.keys()) - { - // append the proxy value list stored in the i'th column - // for each setting key. A setting key is the id of the setting - // in page.name format. - proxyValueList.append (mProxyListMap.value(settingKey).at(i)); - } - - if (proxyListsMatch (slaveValueList, proxyValueList)) - { - masterColumn = i; - break; - } - } - - QString masterValue = mMasterView->value (masterColumn); - - mMasterView->setSelectedValue (masterValue); -} - -void CSMSettings::Connector::slotUpdateSlaves() const -{ - int row = mMasterView->currentIndex(); - - if (row == -1) - return; - - //iterate the proxy lists for the chosen master index - //and pass the list to each slave for updating - for (int i = 0; i < mSlaveViews.size(); i++) - { - QList proxyList = - mProxyListMap.value(mSlaveViews.at(i)->viewKey()); - - mSlaveViews.at(i)->setSelectedValues (proxyList.at(row)); - } -} - -bool CSMSettings::Connector::stringListsMatch ( - const QStringList &list1, - const QStringList &list2) const -{ - //returns a "sloppy" match, verifying that each list contains all the same - //items, though not necessarily in the same order. - - if (list1.size() != list2.size()) - return false; - - QStringList tempList(list2); - - //iterate each value in the list, removing one occurrence of the value in - //the other list. If no corresponding value is found, test fails - foreach (const QString &value, list1) - { - if (!tempList.contains(value)) - return false; - - tempList.removeOne(value); - } - return true; -} diff --git a/apps/opencs/model/settings/connector.hpp b/apps/opencs/model/settings/connector.hpp deleted file mode 100644 index aaf9936d5..000000000 --- a/apps/opencs/model/settings/connector.hpp +++ /dev/null @@ -1,67 +0,0 @@ -#ifndef CSMSETTINGS_CONNECTOR_HPP -#define CSMSETTINGS_CONNECTOR_HPP - -#include -#include -#include -#include - -#include "support.hpp" - -namespace CSVSettings { - class View; -} - -namespace CSMSettings { - - class Connector : public QObject - { - Q_OBJECT - - CSVSettings::View *mMasterView; - - ///map using the view pointer as a key to it's index value - QList mSlaveViews; - - ///list of proxy values for each master value. - ///value list order is indexed to the master value index. - QMap < QString, QList > mProxyListMap; - - public: - explicit Connector(CSVSettings::View *master, - QObject *parent = 0); - - ///Set the view which acts as a proxy for other setting views - void setMasterView (CSVSettings::View *view); - - ///Add a view to be updated / update to the master - void addSlaveView (CSVSettings::View *view, - QList &masterProxyValues); - - private: - - ///loosely matches lists of proxy values across registered slaves - ///against a proxy value list for a given master value - bool proxyListsMatch (const QList &list1, - const QList &list2) const; - - ///loosely matches two string lists - bool stringListsMatch (const QStringList &list1, - const QStringList &list2) const; - - ///retrieves current values of registered slave views - QList getSlaveViewValues() const; - - public slots: - - ///updates slave views with proxy values associated with current - ///master value - void slotUpdateSlaves() const; - - ///updates master value associated with the currently selected - ///slave values, if applicable. - void slotUpdateMaster() const; - }; -} - -#endif // CSMSETTINGS_CONNECTOR_HPP diff --git a/apps/opencs/model/settings/setting.cpp b/apps/opencs/model/settings/setting.cpp deleted file mode 100644 index 9e33ab916..000000000 --- a/apps/opencs/model/settings/setting.cpp +++ /dev/null @@ -1,414 +0,0 @@ -#include "setting.hpp" -#include "support.hpp" - -CSMSettings::Setting::Setting(SettingType typ, const QString &settingName, - const QString &pageName, const QString& label) -: mIsEditorSetting (true) -{ - buildDefaultSetting(); - - int settingType = static_cast (typ); - - //even-numbered setting types are multi-valued - if ((settingType % 2) == 0) - setProperty (Property_IsMultiValue, QVariant(true).toString()); - - //view type is related to setting type by an order of magnitude - setProperty (Property_SettingType, QVariant (settingType).toString()); - setProperty (Property_Page, pageName); - setProperty (Property_Name, settingName); - setProperty (Property_Label, label.isEmpty() ? settingName : label); -} - -void CSMSettings::Setting::buildDefaultSetting() -{ - int arrLen = sizeof(sPropertyDefaults) / sizeof (*sPropertyDefaults); - - for (int i = 0; i < arrLen; i++) - { - QStringList propertyList; - - if (i list; - - foreach (const QString &val, vals) - list << (QStringList() << val); - - mProxies [setting->page() + '/' + setting->name()] = list; -} - -void CSMSettings::Setting::addProxy (const Setting *setting, - const QList &list) -{ - if (serializable()) - setProperty (Property_Serializable, false); - - mProxies [setting->page() + '/' + setting->name()] = list; -} - -void CSMSettings::Setting::setColumnSpan (int value) -{ - setProperty (Property_ColumnSpan, value); -} - -int CSMSettings::Setting::columnSpan() const -{ - return property (Property_ColumnSpan).at(0).toInt(); -} - -void CSMSettings::Setting::setDeclaredValues (QStringList list) -{ - setProperty (Property_DeclaredValues, list); -} - -QStringList CSMSettings::Setting::declaredValues() const -{ - return property (Property_DeclaredValues); -} - -QStringList CSMSettings::Setting::property (SettingProperty prop) const -{ - if (prop >= mProperties.size()) - return QStringList(); - - return mProperties.at(prop); -} - -void CSMSettings::Setting::setDefaultValue (int value) -{ - setDefaultValues (QStringList() << QVariant (value).toString()); -} - -void CSMSettings::Setting::setDefaultValue (double value) -{ - setDefaultValues (QStringList() << QVariant (value).toString()); -} - -void CSMSettings::Setting::setDefaultValue (const QString &value) -{ - setDefaultValues (QStringList() << value); -} - -void CSMSettings::Setting::setDefaultValues (const QStringList &values) -{ - setProperty (Property_DefaultValues, values); -} - -QStringList CSMSettings::Setting::defaultValues() const -{ - return property (Property_DefaultValues); -} - -void CSMSettings::Setting::setDelimiter (const QString &value) -{ - setProperty (Property_Delimiter, value); -} - -QString CSMSettings::Setting::delimiter() const -{ - return property (Property_Delimiter).at(0); -} - -void CSMSettings::Setting::setEditorSetting(bool state) -{ - mIsEditorSetting = true; -} - -bool CSMSettings::Setting::isEditorSetting() const -{ - return mIsEditorSetting; -} -void CSMSettings::Setting::setIsMultiLine (bool state) -{ - setProperty (Property_IsMultiLine, state); -} - -bool CSMSettings::Setting::isMultiLine() const -{ - return (property (Property_IsMultiLine).at(0) == "true"); -} - -void CSMSettings::Setting::setIsMultiValue (bool state) -{ - setProperty (Property_IsMultiValue, state); -} - -bool CSMSettings::Setting::isMultiValue() const -{ - return (property (Property_IsMultiValue).at(0) == "true"); -} - -const CSMSettings::ProxyValueMap &CSMSettings::Setting::proxyLists() const -{ - return mProxies; -} - -void CSMSettings::Setting::setSerializable (bool state) -{ - setProperty (Property_Serializable, state); -} - -bool CSMSettings::Setting::serializable() const -{ - return (property (Property_Serializable).at(0) == "true"); -} - -void CSMSettings::Setting::setSpecialValueText(const QString &text) -{ - setProperty (Property_SpecialValueText, text); -} - -QString CSMSettings::Setting::specialValueText() const -{ - return property (Property_SpecialValueText).at(0); -} - -void CSMSettings::Setting::setName (const QString &value) -{ - setProperty (Property_Name, value); -} - -QString CSMSettings::Setting::name() const -{ - return property (Property_Name).at(0); -} - -void CSMSettings::Setting::setPage (const QString &value) -{ - setProperty (Property_Page, value); -} - -QString CSMSettings::Setting::page() const -{ - return property (Property_Page).at(0); -} - -void CSMSettings::Setting::setStyleSheet (const QString &value) -{ - setProperty (Property_StyleSheet, value); -} - -QString CSMSettings::Setting::styleSheet() const -{ - return property (Property_StyleSheet).at(0); -} - -void CSMSettings::Setting::setPrefix (const QString &value) -{ - setProperty (Property_Prefix, value); -} - -QString CSMSettings::Setting::prefix() const -{ - return property (Property_Prefix).at(0); -} - -void CSMSettings::Setting::setRowSpan (const int value) -{ - setProperty (Property_RowSpan, value); -} - -int CSMSettings::Setting::rowSpan () const -{ - return property (Property_RowSpan).at(0).toInt(); -} - -void CSMSettings::Setting::setSingleStep (int value) -{ - setProperty (Property_SingleStep, value); -} - -void CSMSettings::Setting::setSingleStep (double value) -{ - setProperty (Property_SingleStep, value); -} - -QString CSMSettings::Setting::singleStep() const -{ - return property (Property_SingleStep).at(0); -} - -void CSMSettings::Setting::setSuffix (const QString &value) -{ - setProperty (Property_Suffix, value); -} - -QString CSMSettings::Setting::suffix() const -{ - return property (Property_Suffix).at(0); -} - -void CSMSettings::Setting::setTickInterval (int value) -{ - setProperty (Property_TickInterval, value); -} - -int CSMSettings::Setting::tickInterval () const -{ - return property (Property_TickInterval).at(0).toInt(); -} - -void CSMSettings::Setting::setTicksAbove (bool state) -{ - setProperty (Property_TicksAbove, state); -} - -bool CSMSettings::Setting::ticksAbove() const -{ - return (property (Property_TicksAbove).at(0) == "true"); -} - -void CSMSettings::Setting::setTicksBelow (bool state) -{ - setProperty (Property_TicksBelow, state); -} - -bool CSMSettings::Setting::ticksBelow() const -{ - return (property (Property_TicksBelow).at(0) == "true"); -} - -void CSMSettings::Setting::setType (int settingType) -{ - setProperty (Property_SettingType, settingType); -} - -CSMSettings::SettingType CSMSettings::Setting::type() const -{ - return static_cast ( property ( - Property_SettingType).at(0).toInt()); -} - -void CSMSettings::Setting::setRange (int min, int max) -{ - setProperty (Property_Minimum, min); - setProperty (Property_Maximum, max); -} - -void CSMSettings::Setting::setRange (double min, double max) -{ - setProperty (Property_Minimum, min); - setProperty (Property_Maximum, max); -} - -QString CSMSettings::Setting::maximum() const -{ - return property (Property_Maximum).at(0); -} - -QString CSMSettings::Setting::minimum() const -{ - return property (Property_Minimum).at(0); -} - -CSVSettings::ViewType CSMSettings::Setting::viewType() const -{ - return static_cast ( property ( - Property_SettingType).at(0).toInt() / 10); -} - -void CSMSettings::Setting::setViewColumn (int value) -{ - setProperty (Property_ViewColumn, value); -} - -int CSMSettings::Setting::viewColumn() const -{ - return property (Property_ViewColumn).at(0).toInt(); -} - -void CSMSettings::Setting::setViewLocation (int row, int column) -{ - setViewRow (row); - setViewColumn (column); -} - -void CSMSettings::Setting::setViewRow (int value) -{ - setProperty (Property_ViewRow, value); -} - -int CSMSettings::Setting::viewRow() const -{ - return property (Property_ViewRow).at(0).toInt(); -} - -void CSMSettings::Setting::setWidgetWidth (int value) -{ - setProperty (Property_WidgetWidth, value); -} - -int CSMSettings::Setting::widgetWidth() const -{ - return property (Property_WidgetWidth).at(0).toInt(); -} - -void CSMSettings::Setting::setWrapping (bool state) -{ - setProperty (Property_Wrapping, state); -} - -bool CSMSettings::Setting::wrapping() const -{ - return (property (Property_Wrapping).at(0) == "true"); -} - -void CSMSettings::Setting::setLabel (const QString& label) -{ - setProperty (Property_Label, label); -} - -QString CSMSettings::Setting::getLabel() const -{ - return property (Property_Label).at (0); -} - -void CSMSettings::Setting::setToolTip (const QString& toolTip) -{ - setProperty (Property_ToolTip, toolTip); -} - -QString CSMSettings::Setting::getToolTip() const -{ - return property (Property_ToolTip).at (0); -} - -void CSMSettings::Setting::setProperty (SettingProperty prop, bool value) -{ - setProperty (prop, QStringList() << QVariant (value).toString()); -} - -void CSMSettings::Setting::setProperty (SettingProperty prop, int value) -{ - setProperty (prop, QStringList() << QVariant (value).toString()); -} - -void CSMSettings::Setting::setProperty (SettingProperty prop, double value) -{ - setProperty (prop, QStringList() << QVariant (value).toString()); -} - -void CSMSettings::Setting::setProperty (SettingProperty prop, - const QString &value) -{ - setProperty (prop, QStringList() << value); -} - -void CSMSettings::Setting::setProperty (SettingProperty prop, - const QStringList &value) -{ - if (prop < mProperties.size()) - mProperties.replace (prop, value); -} diff --git a/apps/opencs/model/settings/setting.hpp b/apps/opencs/model/settings/setting.hpp deleted file mode 100644 index be51a531a..000000000 --- a/apps/opencs/model/settings/setting.hpp +++ /dev/null @@ -1,159 +0,0 @@ -#ifndef CSMSETTINGS_SETTING_HPP -#define CSMSETTINGS_SETTING_HPP - -#include -#include -#include "support.hpp" - -namespace CSMSettings -{ - //QString is the setting id in the form of "page/name" - //QList is a list of stringlists of proxy values. - //Order is important! Proxy stringlists are matched against - //master values by their position in the QList. - typedef QMap > ProxyValueMap; - - ///Setting class is the interface for the User Settings. It contains - ///a great deal of boiler plate to provide the core API functions, as - ///well as the property() functions which use enumeration to be iterable. - ///This makes the Setting class capable of being manipulated by script. - ///See CSMSettings::support.hpp for enumerations / string values. - class Setting - { - QList mProperties; - QStringList mDefaults; - - bool mIsEditorSetting; - - ProxyValueMap mProxies; - - public: - - Setting(SettingType typ, const QString &settingName, - const QString &pageName, const QString& label = ""); - - void addProxy (const Setting *setting, const QStringList &vals); - void addProxy (const Setting *setting, const QList &list); - - const QList &properties() const { return mProperties; } - const ProxyValueMap &proxies() const { return mProxies; } - - void setColumnSpan (int value); - int columnSpan() const; - - void setDeclaredValues (QStringList list); - QStringList declaredValues() const; - - void setDefaultValue (int value); - void setDefaultValue (double value); - void setDefaultValue (const QString &value); - - void setDefaultValues (const QStringList &values); - QStringList defaultValues() const; - - void setDelimiter (const QString &value); - QString delimiter() const; - - void setEditorSetting (bool state); - bool isEditorSetting() const; - - void setIsMultiLine (bool state); - bool isMultiLine() const; - - void setIsMultiValue (bool state); - bool isMultiValue() const; - - void setMask (const QString &value); - QString mask() const; - - void setRange (int min, int max); - void setRange (double min, double max); - - QString maximum() const; - - QString minimum() const; - - void setName (const QString &value); - QString name() const; - - void setPage (const QString &value); - QString page() const; - - void setStyleSheet (const QString &value); - QString styleSheet() const; - - void setPrefix (const QString &value); - QString prefix() const; - - void setRowSpan (const int value); - int rowSpan() const; - - const ProxyValueMap &proxyLists() const; - - void setSerializable (bool state); - bool serializable() const; - - void setSpecialValueText (const QString &text); - QString specialValueText() const; - - void setSingleStep (int value); - void setSingleStep (double value); - QString singleStep() const; - - void setSuffix (const QString &value); - QString suffix() const; - - void setTickInterval (int value); - int tickInterval() const; - - void setTicksAbove (bool state); - bool ticksAbove() const; - - void setTicksBelow (bool state); - bool ticksBelow() const; - - void setViewColumn (int value); - int viewColumn() const; - - void setViewLocation (int row = -1, int column = -1); - - void setViewRow (int value); - int viewRow() const; - - void setType (int settingType); - CSMSettings::SettingType type() const; - - CSVSettings::ViewType viewType() const; - - void setWrapping (bool state); - bool wrapping() const; - - void setWidgetWidth (int value); - int widgetWidth() const; - - /// This is the text the user gets to see. - void setLabel (const QString& label); - QString getLabel() const; - - void setToolTip (const QString& toolTip); - QString getToolTip() const; - - ///returns the specified property value - QStringList property (SettingProperty prop) const; - - ///boilerplate code to convert setting values of common types - void setProperty (SettingProperty prop, bool value); - void setProperty (SettingProperty prop, int value); - void setProperty (SettingProperty prop, double value); - void setProperty (SettingProperty prop, const QString &value); - void setProperty (SettingProperty prop, const QStringList &value); - - void addProxy (Setting* setting, - QMap &proxyMap); - - protected: - void buildDefaultSetting(); - }; -} - -#endif // CSMSETTINGS_SETTING_HPP diff --git a/apps/opencs/model/settings/support.hpp b/apps/opencs/model/settings/support.hpp deleted file mode 100644 index ab0e5088c..000000000 --- a/apps/opencs/model/settings/support.hpp +++ /dev/null @@ -1,149 +0,0 @@ -#ifndef SETTING_SUPPORT_HPP -#define SETTING_SUPPORT_HPP - -#include -#include -#include -#include -#include - -//Enums -namespace CSMSettings -{ - ///Enumerated properties for scripting - enum SettingProperty - { - Property_Name = 0, - Property_Page = 1, - Property_SettingType = 2, - Property_IsMultiValue = 3, - Property_IsMultiLine = 4, - Property_WidgetWidth = 5, - Property_ViewRow = 6, - Property_ViewColumn = 7, - Property_Delimiter = 8, - Property_Serializable = 9, - Property_ColumnSpan = 10, - Property_RowSpan = 11, - Property_Minimum = 12, - Property_Maximum = 13, - Property_SpecialValueText = 14, - Property_Prefix = 15, - Property_Suffix = 16, - Property_SingleStep = 17, - Property_Wrapping = 18, - Property_TickInterval = 19, - Property_TicksAbove = 20, - Property_TicksBelow = 21, - Property_StyleSheet = 22, - Property_Label = 23, - Property_ToolTip = 24, - - //Stringlists should always be the last items - Property_DefaultValues = 25, - Property_DeclaredValues = 26, - Property_DefinedValues = 27, - Property_Proxies = 28 - }; - - ///Basic setting widget types. - enum SettingType - { - /* - * 0 - 9 - Boolean widgets - * 10-19 - List widgets - * 21-29 - Range widgets - * 31-39 - Text widgets - * - * Each range corresponds to a View_Type enum by a factor of 10. - * - * Even-numbered values are single-value widgets - * Odd-numbered values are multi-valued widgets - */ - - Type_CheckBox = 0, - Type_RadioButton = 1, - Type_ListView = 10, - Type_ComboBox = 11, - Type_SpinBox = 21, - Type_DoubleSpinBox = 23, - Type_Slider = 25, - Type_Dial = 27, - Type_TextArea = 30, - Type_LineEdit = 31, - Type_Undefined = 40 - }; - -} - -namespace CSVSettings -{ - ///Categorical view types which encompass the setting widget types - enum ViewType - { - ViewType_Boolean = 0, - ViewType_List = 1, - ViewType_Range = 2, - ViewType_Text = 3, - ViewType_Undefined = 4 - }; -} - - -namespace CSMSettings -{ - ///used to construct default settings in the Setting class - struct PropertyDefaultValues - { - int id; - QString name; - QVariant value; - }; - - ///strings which correspond to setting values. These strings represent - ///the script language keywords which would be used to declare setting - ///views for 3rd party addons - const QString sPropertyNames[] = - { - "name", "page", "setting_type", "is_multi_value", - "is_multi_line", "widget_width", "view_row", "view_column", "delimiter", - "is_serializable","column_span", "row_span", "minimum", "maximum", - "special_value_text", "prefix", "suffix", "single_step", "wrapping", - "tick_interval", "ticks_above", "ticks_below", "stylesheet", - "defaults", "declarations", "definitions", "proxies" - }; - - ///Default values for a setting. Used in setting creation. - const QString sPropertyDefaults[] = - { - "", //name - "", //page - "40", //setting type - "false", //multivalue - "false", //multiline - "7", //widget width - "-1", //view row - "-1", //view column - ",", //delimiter - "true", //serialized - "1", //column span - "1", //row span - "0", //value range - "0", //value minimum - "0", //value maximum - "", //special text - "", //prefix - "", //suffix - "false", //wrapping - "1", //tick interval - "false", //ticks above - "true", //ticks below - "", //StyleSheet - "", //default values - "", //declared values - "", //defined values - "" //proxy values - }; -} - -#endif // VIEW_SUPPORT_HPP diff --git a/apps/opencs/model/settings/usersettings.cpp b/apps/opencs/model/settings/usersettings.cpp deleted file mode 100644 index 8e5ab3d87..000000000 --- a/apps/opencs/model/settings/usersettings.cpp +++ /dev/null @@ -1,824 +0,0 @@ -#include "usersettings.hpp" - -#include -#include - -#include -#include -#include - -#include "setting.hpp" -#include "support.hpp" -#include -#include - -/** - * Workaround for problems with whitespaces in paths in older versions of Boost library - */ -#if (BOOST_VERSION <= 104600) -namespace boost -{ - - template<> - inline boost::filesystem::path lexical_cast(const std::string& arg) - { - return boost::filesystem::path(arg); - } - -} /* namespace boost */ -#endif /* (BOOST_VERSION <= 104600) */ - -CSMSettings::UserSettings *CSMSettings::UserSettings::sUserSettingsInstance = 0; - - CSMSettings::UserSettings::UserSettings (const Files::ConfigurationManager& configurationManager) - : mCfgMgr (configurationManager) - , mSettingDefinitions(NULL) -{ - assert(!sUserSettingsInstance); - sUserSettingsInstance = this; - - buildSettingModelDefaults(); -} - -void CSMSettings::UserSettings::buildSettingModelDefaults() -{ - /* - declareSection ("3d-render", "3D Rendering"); - { - Setting *farClipDist = createSetting (Type_DoubleSpinBox, "far-clip-distance", "Far clipping distance"); - farClipDist->setDefaultValue (300000); - farClipDist->setRange (0, 1000000); - farClipDist->setToolTip ("The maximum distance objects are still rendered at."); - - QString defaultValue = "None"; - Setting *antialiasing = createSetting (Type_ComboBox, "antialiasing", "Antialiasing"); - antialiasing->setDeclaredValues (QStringList() - << defaultValue << "MSAA 2" << "MSAA 4" << "MSAA 8" << "MSAA 16"); - antialiasing->setDefaultValue (defaultValue); - } - */ - - /* - declareSection ("scene-input", "Scene Input"); - { - Setting *fastFactor = createSetting (Type_SpinBox, "fast-factor", - "Fast movement factor"); - fastFactor->setDefaultValue (4); - fastFactor->setRange (1, 100); - fastFactor->setToolTip ( - "Factor by which movement is speed up while the shift key is held down."); - } - */ - - declareSection ("window", "Window"); - { - Setting *preDefined = createSetting (Type_ComboBox, "pre-defined", - "Default window size"); - preDefined->setEditorSetting (false); - preDefined->setDeclaredValues ( - QStringList() << "640 x 480" << "800 x 600" << "1024 x 768" << "1440 x 900"); - preDefined->setViewLocation (1, 1); - preDefined->setColumnSpan (2); - preDefined->setToolTip ("Newly opened top-level windows will open with this size " - "(picked from a list of pre-defined values)"); - - Setting *width = createSetting (Type_LineEdit, "default-width", - "Default window width"); - width->setDefaultValues (QStringList() << "1024"); - width->setViewLocation (2, 1); - width->setColumnSpan (1); - width->setToolTip ("Newly opened top-level windows will open with this width."); - preDefined->addProxy (width, QStringList() << "640" << "800" << "1024" << "1440"); - - Setting *height = createSetting (Type_LineEdit, "default-height", - "Default window height"); - height->setDefaultValues (QStringList() << "768"); - height->setViewLocation (2, 2); - height->setColumnSpan (1); - height->setToolTip ("Newly opened top-level windows will open with this height."); - preDefined->addProxy (height, QStringList() << "480" << "600" << "768" << "900"); - - Setting *reuse = createSetting (Type_CheckBox, "reuse", "Reuse Subviews"); - reuse->setDefaultValue ("true"); - reuse->setToolTip ("When a new subview is requested and a matching subview already " - " exist, do not open a new subview and use the existing one instead."); - - Setting *statusBar = createSetting (Type_CheckBox, "show-statusbar", "Show Status Bar"); - statusBar->setDefaultValue ("true"); - statusBar->setToolTip ("If a newly open top level window is showing status bars or not. " - " Note that this does not affect existing windows."); - - Setting *maxSubView = createSetting (Type_SpinBox, "max-subviews", - "Maximum number of subviews per top-level window"); - maxSubView->setDefaultValue (256); - maxSubView->setRange (1, 256); - maxSubView->setToolTip ("If the maximum number is reached and a new subview is opened " - "it will be placed into a new top-level window."); - - Setting *hide = createSetting (Type_CheckBox, "hide-subview", "Hide single subview"); - hide->setDefaultValue ("false"); - hide->setToolTip ("When a view contains only a single subview, hide the subview title " - "bar and if this subview is closed also close the view (unless it is the last " - "view for this document)"); - - Setting *minWidth = createSetting (Type_SpinBox, "minimum-width", - "Minimum subview width"); - minWidth->setDefaultValue (325); - minWidth->setRange (50, 10000); - minWidth->setToolTip ("Minimum width of subviews."); - - QString defaultScroll = "Scrollbar Only"; - QStringList scrollValues = QStringList() << defaultScroll << "Grow Only" << "Grow then Scroll"; - - Setting *mainwinScroll = createSetting (Type_RadioButton, "mainwindow-scrollbar", - "Add a horizontal scrollbar to the main view window."); - mainwinScroll->setDefaultValue (defaultScroll); - mainwinScroll->setDeclaredValues (scrollValues); - mainwinScroll->setToolTip ("Scrollbar Only: Simple addition of scrollbars, the view window does not grow" - " automatically.\n" - "Grow Only: Original Editor behaviour. The view window grows as subviews are added. No scrollbars.\n" - "Grow then Scroll: The view window grows. The scrollbar appears once it cannot grow any further."); - - Setting *grow = createSetting (Type_CheckBox, "grow-limit", "Grow Limit Screen"); - grow->setDefaultValue ("false"); - grow->setToolTip ("When \"Grow then Scroll\" option is selected, the window size grows to" - " the width of the virtual desktop. \nIf this option is selected the the window growth" - "is limited to the current screen."); - } - - declareSection ("records", "Records"); - { - QString defaultValue = "Icon and Text"; - QStringList values = QStringList() << defaultValue << "Icon Only" << "Text Only"; - - Setting *rsd = createSetting (Type_RadioButton, "status-format", - "Modification status display format"); - rsd->setDefaultValue (defaultValue); - rsd->setDeclaredValues (values); - - Setting *ritd = createSetting (Type_RadioButton, "type-format", - "ID type display format"); - ritd->setDefaultValue (defaultValue); - ritd->setDeclaredValues (values); - } - - declareSection ("table-input", "ID Tables"); - { - QString inPlaceEdit ("Edit in Place"); - QString editRecord ("Edit Record"); - QString view ("View"); - QString editRecordAndClose ("Edit Record and Close"); - - QStringList values; - values - << "None" << inPlaceEdit << editRecord << view << "Revert" << "Delete" - << editRecordAndClose << "View and Close"; - - QString toolTip = "
      " - "
    • None
    • " - "
    • Edit in Place: Edit the clicked cell
    • " - "
    • Edit Record: Open a dialogue subview for the clicked record
    • " - "
    • View: Open a scene subview for the clicked record (not available everywhere)
    • " - "
    • Revert: Revert record
    • " - "
    • Delete: Delete recordy
    • " - "
    • Edit Record and Close: Open a dialogue subview for the clicked record and close the table subview
    • " - "
    • View And Close: Open a scene subview for the clicked record and close the table subview
    • " - "
    "; - - Setting *doubleClick = createSetting (Type_ComboBox, "double", "Double Click"); - doubleClick->setDeclaredValues (values); - doubleClick->setDefaultValue (inPlaceEdit); - doubleClick->setToolTip ("Action on double click in table:

    " + toolTip); - - Setting *shiftDoubleClick = createSetting (Type_ComboBox, "double-s", - "Shift Double Click"); - shiftDoubleClick->setDeclaredValues (values); - shiftDoubleClick->setDefaultValue (editRecord); - shiftDoubleClick->setToolTip ("Action on shift double click in table:

    " + toolTip); - - Setting *ctrlDoubleClick = createSetting (Type_ComboBox, "double-c", - "Control Double Click"); - ctrlDoubleClick->setDeclaredValues (values); - ctrlDoubleClick->setDefaultValue (view); - ctrlDoubleClick->setToolTip ("Action on control double click in table:

    " + toolTip); - - Setting *shiftCtrlDoubleClick = createSetting (Type_ComboBox, "double-sc", - "Shift Control Double Click"); - shiftCtrlDoubleClick->setDeclaredValues (values); - shiftCtrlDoubleClick->setDefaultValue (editRecordAndClose); - shiftCtrlDoubleClick->setToolTip ("Action on shift control double click in table:

    " + toolTip); - - QString defaultValue = "Jump and Select"; - QStringList jumpValues = QStringList() << defaultValue << "Jump Only" << "No Jump"; - - Setting *jumpToAdded = createSetting (Type_RadioButton, "jump-to-added", - "Jump to the added or cloned record."); - jumpToAdded->setDefaultValue (defaultValue); - jumpToAdded->setDeclaredValues (jumpValues); - - Setting *extendedConfig = createSetting (Type_CheckBox, "extended-config", - "Manually specify affected record types for an extended delete/revert"); - extendedConfig->setDefaultValue("false"); - extendedConfig->setToolTip("Delete and revert commands have an extended form that also affects " - "associated records.\n\n" - "If this option is enabled, types of affected records are selected " - "manually before a command execution.\nOtherwise, all associated " - "records are deleted/reverted immediately."); - } - - declareSection ("dialogues", "ID Dialogues"); - { - Setting *toolbar = createSetting (Type_CheckBox, "toolbar", "Show toolbar"); - toolbar->setDefaultValue ("true"); - } - - declareSection ("report-input", "Reports"); - { - QString none ("None"); - QString edit ("Edit"); - QString remove ("Remove"); - QString editAndRemove ("Edit And Remove"); - - QStringList values; - values << none << edit << remove << editAndRemove; - - QString toolTip = "

      " - "
    • None
    • " - "
    • Edit: Open a table or dialogue suitable for addressing the listed report
    • " - "
    • Remove: Remove the report from the report table
    • " - "
    • Edit and Remove: Open a table or dialogue suitable for addressing the listed report, then remove the report from the report table
    • " - "
    "; - - Setting *doubleClick = createSetting (Type_ComboBox, "double", "Double Click"); - doubleClick->setDeclaredValues (values); - doubleClick->setDefaultValue (edit); - doubleClick->setToolTip ("Action on double click in report table:

    " + toolTip); - - Setting *shiftDoubleClick = createSetting (Type_ComboBox, "double-s", - "Shift Double Click"); - shiftDoubleClick->setDeclaredValues (values); - shiftDoubleClick->setDefaultValue (remove); - shiftDoubleClick->setToolTip ("Action on shift double click in report table:

    " + toolTip); - - Setting *ctrlDoubleClick = createSetting (Type_ComboBox, "double-c", - "Control Double Click"); - ctrlDoubleClick->setDeclaredValues (values); - ctrlDoubleClick->setDefaultValue (editAndRemove); - ctrlDoubleClick->setToolTip ("Action on control double click in report table:

    " + toolTip); - - Setting *shiftCtrlDoubleClick = createSetting (Type_ComboBox, "double-sc", - "Shift Control Double Click"); - shiftCtrlDoubleClick->setDeclaredValues (values); - shiftCtrlDoubleClick->setDefaultValue (none); - shiftCtrlDoubleClick->setToolTip ("Action on shift control double click in report table:

    " + toolTip); - } - - declareSection ("search", "Search & Replace"); - { - Setting *before = createSetting (Type_SpinBox, "char-before", - "Characters before search string"); - before->setDefaultValue (10); - before->setRange (0, 1000); - before->setToolTip ("Maximum number of character to display in search result before the searched text"); - - Setting *after = createSetting (Type_SpinBox, "char-after", - "Characters after search string"); - after->setDefaultValue (10); - after->setRange (0, 1000); - after->setToolTip ("Maximum number of character to display in search result after the searched text"); - - Setting *autoDelete = createSetting (Type_CheckBox, "auto-delete", "Delete row from result table after a successful replace"); - autoDelete->setDefaultValue ("true"); - } - - declareSection ("script-editor", "Scripts"); - { - Setting *lineNum = createSetting (Type_CheckBox, "show-linenum", "Show Line Numbers"); - lineNum->setDefaultValue ("true"); - lineNum->setToolTip ("Show line numbers to the left of the script editor window." - "The current row and column numbers of the text cursor are shown at the bottom."); - - Setting *monoFont = createSetting (Type_CheckBox, "mono-font", "Use monospace font"); - monoFont->setDefaultValue ("true"); - monoFont->setToolTip ("Whether to use monospaced fonts on script edit subview."); - - QString tooltip = - "\n#RGB (each of R, G, and B is a single hex digit)" - "\n#RRGGBB" - "\n#RRRGGGBBB" - "\n#RRRRGGGGBBBB" - "\nA name from the list of colors defined in the list of SVG color keyword names." - "\nX11 color names may also work."; - - QString modeNormal ("Normal"); - - QStringList modes; - modes << "Ignore" << modeNormal << "Strict"; - - Setting *warnings = createSetting (Type_ComboBox, "warnings", - "Warning Mode"); - warnings->setDeclaredValues (modes); - warnings->setDefaultValue (modeNormal); - warnings->setToolTip ("

      How to handle warning messages during compilation:

      " - "

    • Ignore: Do not report warning
    • " - "
    • Normal: Report warning as a warning
    • " - "
    • Strict: Promote warning to an error
    • " - "
    "); - - Setting *toolbar = createSetting (Type_CheckBox, "toolbar", "Show toolbar"); - toolbar->setDefaultValue ("true"); - - Setting *delay = createSetting (Type_SpinBox, "compile-delay", - "Delay between updating of source errors"); - delay->setDefaultValue (100); - delay->setRange (0, 10000); - delay->setToolTip ("Delay in milliseconds"); - - Setting *errorHeight = createSetting (Type_SpinBox, "error-height", - "Initial height of the error panel"); - errorHeight->setDefaultValue (100); - errorHeight->setRange (100, 10000); - - Setting *formatInt = createSetting (Type_LineEdit, "colour-int", "Highlight Colour: Int"); - formatInt->setDefaultValues (QStringList() << "Dark magenta"); - formatInt->setToolTip ("(Default: Green) Use one of the following formats:" + tooltip); - - Setting *formatFloat = createSetting (Type_LineEdit, "colour-float", "Highlight Colour: Float"); - formatFloat->setDefaultValues (QStringList() << "Magenta"); - formatFloat->setToolTip ("(Default: Magenta) Use one of the following formats:" + tooltip); - - Setting *formatName = createSetting (Type_LineEdit, "colour-name", "Highlight Colour: Name"); - formatName->setDefaultValues (QStringList() << "Gray"); - formatName->setToolTip ("(Default: Gray) Use one of the following formats:" + tooltip); - - Setting *formatKeyword = createSetting (Type_LineEdit, "colour-keyword", "Highlight Colour: Keyword"); - formatKeyword->setDefaultValues (QStringList() << "Red"); - formatKeyword->setToolTip ("(Default: Red) Use one of the following formats:" + tooltip); - - Setting *formatSpecial = createSetting (Type_LineEdit, "colour-special", "Highlight Colour: Special"); - formatSpecial->setDefaultValues (QStringList() << "Dark yellow"); - formatSpecial->setToolTip ("(Default: Dark yellow) Use one of the following formats:" + tooltip); - - Setting *formatComment = createSetting (Type_LineEdit, "colour-comment", "Highlight Colour: Comment"); - formatComment->setDefaultValues (QStringList() << "Green"); - formatComment->setToolTip ("(Default: Green) Use one of the following formats:" + tooltip); - - Setting *formatId = createSetting (Type_LineEdit, "colour-id", "Highlight Colour: Id"); - formatId->setDefaultValues (QStringList() << "Blue"); - formatId->setToolTip ("(Default: Blue) Use one of the following formats:" + tooltip); - } - - declareSection ("general-input", "General Input"); - { - Setting *cycle = createSetting (Type_CheckBox, "cycle", "Cyclic next/previous"); - cycle->setDefaultValue ("false"); - cycle->setToolTip ("When using next/previous functions at the last/first item of a " - "list go to the first/last item"); - } - - declareSection ("scene-input", "3D Scene Input"); - { - QString left ("Left Mouse-Button"); - QString cLeft ("Ctrl-Left Mouse-Button"); - QString right ("Right Mouse-Button"); - QString cRight ("Ctrl-Right Mouse-Button"); - QString middle ("Middle Mouse-Button"); - QString cMiddle ("Ctrl-Middle Mouse-Button"); - - QStringList values; - values << left << cLeft << right << cRight << middle << cMiddle; - - Setting *primaryNavigation = createSetting (Type_ComboBox, "p-navi", "Primary Camera Navigation Button"); - primaryNavigation->setDeclaredValues (values); - primaryNavigation->setDefaultValue (left); - - Setting *secondaryNavigation = createSetting (Type_ComboBox, "s-navi", "Secondary Camera Navigation Button"); - secondaryNavigation->setDeclaredValues (values); - secondaryNavigation->setDefaultValue (cLeft); - - Setting *primaryEditing = createSetting (Type_ComboBox, "p-edit", "Primary Editing Button"); - primaryEditing->setDeclaredValues (values); - primaryEditing->setDefaultValue (right); - - Setting *secondaryEditing = createSetting (Type_ComboBox, "s-edit", "Secondary Editing Button"); - secondaryEditing->setDeclaredValues (values); - secondaryEditing->setDefaultValue (cRight); - - Setting *primarySelection = createSetting (Type_ComboBox, "p-select", "Selection Button"); - primarySelection->setDeclaredValues (values); - primarySelection->setDefaultValue (middle); - - Setting *secondarySelection = createSetting (Type_ComboBox, "s-select", "Selection Button"); - secondarySelection->setDeclaredValues (values); - secondarySelection->setDefaultValue (cMiddle); - - Setting *contextSensitive = createSetting (Type_CheckBox, "context-select", "Context Sensitive Selection"); - contextSensitive->setDefaultValue ("false"); - - Setting *dragMouseSensitivity = createSetting (Type_DoubleSpinBox, "drag-factor", - "Mouse sensitivity during drag operations"); - dragMouseSensitivity->setDefaultValue (1.0); - dragMouseSensitivity->setRange (0.001, 100.0); - - Setting *dragWheelSensitivity = createSetting (Type_DoubleSpinBox, "drag-wheel-factor", - "Mouse wheel sensitivity during drag operations"); - dragWheelSensitivity->setDefaultValue (1.0); - dragWheelSensitivity->setRange (0.001, 100.0); - - Setting *dragShiftFactor = createSetting (Type_DoubleSpinBox, "drag-shift-factor", - "Acceleration factor during drag operations while holding down shift"); - dragShiftFactor->setDefaultValue (4.0); - dragShiftFactor->setRange (0.001, 100.0); - } - - declareSection ("tooltips", "Tooltips"); - { - Setting *scene = createSetting (Type_CheckBox, "scene", "Show Tooltips in 3D scenes"); - scene->setDefaultValue ("true"); - - Setting *sceneHideBasic = createSetting (Type_CheckBox, "scene-hide-basic", "Hide basic 3D scenes tooltips"); - sceneHideBasic->setDefaultValue ("false"); - - Setting *sceneDelay = createSetting (Type_SpinBox, "scene-delay", - "Tooltip delay in milliseconds"); - sceneDelay->setDefaultValue (500); - sceneDelay->setRange (1, 10000); - } - - { - /****************************************************************** - * There are three types of values: - * - * Declared values - * - * Pre-determined values, typically for - * combobox drop downs and boolean (radiobutton / checkbox) labels. - * These values represent the total possible list of values that - * may define a setting. No other values are allowed. - * - * Defined values - * - * Values which represent the actual, current value of - * a setting. For settings with declared values, this must be one - * or several declared values, as appropriate. - * - * Proxy values - * Values the proxy master updates the proxy slave when - * it's own definition is set / changed. These are definitions for - * proxy slave settings, but must match any declared values the - * proxy slave has, if any. - *******************************************************************/ -/* - //create setting objects, specifying the basic widget type, - //the page name, and the view name - - Setting *masterBoolean = createSetting (Type_RadioButton, section, - "Master Proxy"); - - Setting *slaveBoolean = createSetting (Type_CheckBox, section, - "Proxy Checkboxes"); - - Setting *slaveSingleText = createSetting (Type_LineEdit, section, - "Proxy TextBox 1"); - - Setting *slaveMultiText = createSetting (Type_LineEdit, section, - "ProxyTextBox 2"); - - Setting *slaveAlphaSpinbox = createSetting (Type_SpinBox, section, - "Alpha Spinbox"); - - Setting *slaveIntegerSpinbox = createSetting (Type_SpinBox, section, - "Int Spinbox"); - - Setting *slaveDoubleSpinbox = createSetting (Type_DoubleSpinBox, - section, "Double Spinbox"); - - Setting *slaveSlider = createSetting (Type_Slider, section, "Slider"); - - Setting *slaveDial = createSetting (Type_Dial, section, "Dial"); - - //set declared values for selected views - masterBoolean->setDeclaredValues (QStringList() - << "Profile One" << "Profile Two" - << "Profile Three" << "Profile Four"); - - slaveBoolean->setDeclaredValues (QStringList() - << "One" << "Two" << "Three" << "Four" << "Five"); - - slaveAlphaSpinbox->setDeclaredValues (QStringList() - << "One" << "Two" << "Three" << "Four"); - - - masterBoolean->addProxy (slaveBoolean, QList () - << (QStringList() << "One" << "Three") - << (QStringList() << "One" << "Three") - << (QStringList() << "One" << "Three" << "Five") - << (QStringList() << "Two" << "Four") - ); - - masterBoolean->addProxy (slaveSingleText, QList () - << (QStringList() << "Text A") - << (QStringList() << "Text B") - << (QStringList() << "Text A") - << (QStringList() << "Text C") - ); - - masterBoolean->addProxy (slaveMultiText, QList () - << (QStringList() << "One" << "Three") - << (QStringList() << "One" << "Three") - << (QStringList() << "One" << "Three" << "Five") - << (QStringList() << "Two" << "Four") - ); - - masterBoolean->addProxy (slaveAlphaSpinbox, QList () - << (QStringList() << "Four") - << (QStringList() << "Three") - << (QStringList() << "Two") - << (QStringList() << "One")); - - masterBoolean->addProxy (slaveIntegerSpinbox, QList () - << (QStringList() << "0") - << (QStringList() << "7") - << (QStringList() << "14") - << (QStringList() << "21")); - - masterBoolean->addProxy (slaveDoubleSpinbox, QList () - << (QStringList() << "0.17") - << (QStringList() << "0.34") - << (QStringList() << "0.51") - << (QStringList() << "0.68")); - - masterBoolean->addProxy (slaveSlider, QList () - << (QStringList() << "25") - << (QStringList() << "50") - << (QStringList() << "75") - << (QStringList() << "100") - ); - - masterBoolean->addProxy (slaveDial, QList () - << (QStringList() << "25") - << (QStringList() << "50") - << (QStringList() << "75") - << (QStringList() << "100") - ); - - //settings with proxies are not serialized by default - //other settings non-serialized for demo purposes - slaveBoolean->setSerializable (false); - slaveSingleText->setSerializable (false); - slaveMultiText->setSerializable (false); - slaveAlphaSpinbox->setSerializable (false); - slaveIntegerSpinbox->setSerializable (false); - slaveDoubleSpinbox->setSerializable (false); - slaveSlider->setSerializable (false); - slaveDial->setSerializable (false); - - slaveBoolean->setDefaultValues (QStringList() - << "One" << "Three" << "Five"); - - slaveSingleText->setDefaultValue ("Text A"); - - slaveMultiText->setDefaultValues (QStringList() - << "One" << "Three" << "Five"); - - slaveSingleText->setWidgetWidth (24); - slaveMultiText->setWidgetWidth (24); - - slaveAlphaSpinbox->setDefaultValue ("Two"); - slaveAlphaSpinbox->setWidgetWidth (20); - //slaveAlphaSpinbox->setPrefix ("No. "); - //slaveAlphaSpinbox->setSuffix ("!"); - slaveAlphaSpinbox->setWrapping (true); - - slaveIntegerSpinbox->setDefaultValue (14); - slaveIntegerSpinbox->setMinimum (0); - slaveIntegerSpinbox->setMaximum (58); - slaveIntegerSpinbox->setPrefix ("$"); - slaveIntegerSpinbox->setSuffix (".00"); - slaveIntegerSpinbox->setWidgetWidth (10); - slaveIntegerSpinbox->setSpecialValueText ("Nothing!"); - - slaveDoubleSpinbox->setDefaultValue (0.51); - slaveDoubleSpinbox->setSingleStep(0.17); - slaveDoubleSpinbox->setMaximum(4.0); - - slaveSlider->setMinimum (0); - slaveSlider->setMaximum (100); - slaveSlider->setDefaultValue (75); - slaveSlider->setWidgetWidth (100); - slaveSlider->setTicksAbove (true); - slaveSlider->setTickInterval (25); - - slaveDial->setMinimum (0); - slaveDial->setMaximum (100); - slaveDial->setSingleStep (5); - slaveDial->setDefaultValue (75); - slaveDial->setTickInterval (25); -*/ - } -} - -CSMSettings::UserSettings::~UserSettings() -{ - sUserSettingsInstance = 0; -} - -void CSMSettings::UserSettings::loadSettings (const QString &fileName) -{ - QString userFilePath = QString::fromUtf8 - (mCfgMgr.getUserConfigPath().string().c_str()); - - QString globalFilePath = QString::fromUtf8 - (mCfgMgr.getGlobalPath().string().c_str()); - - QString otherFilePath = globalFilePath; - - //test for local only if global fails (uninstalled copy) - if (!QFile (globalFilePath + fileName).exists()) - { - //if global is invalid, use the local path - otherFilePath = QString::fromUtf8 - (mCfgMgr.getLocalPath().string().c_str()); - } - - QSettings::setPath - (QSettings::IniFormat, QSettings::UserScope, userFilePath); - - QSettings::setPath - (QSettings::IniFormat, QSettings::SystemScope, otherFilePath); - - mSettingDefinitions = new QSettings - (QSettings::IniFormat, QSettings::UserScope, "opencs", QString(), this); -} - -// if the key is not found create one with a default value -QString CSMSettings::UserSettings::setting(const QString &viewKey, const QString &value) -{ - if(mSettingDefinitions->contains(viewKey)) - return settingValue(viewKey); - else if(value != QString()) - { - mSettingDefinitions->setValue (viewKey, QStringList() << value); - return value; - } - - return QString(); -} - -bool CSMSettings::UserSettings::hasSettingDefinitions (const QString &viewKey) const -{ - return (mSettingDefinitions->contains (viewKey)); -} - -void CSMSettings::UserSettings::setDefinitions - (const QString &key, const QStringList &list) -{ - mSettingDefinitions->setValue (key, list); -} - -void CSMSettings::UserSettings::saveDefinitions() const -{ - mSettingDefinitions->sync(); -} - -QString CSMSettings::UserSettings::settingValue (const QString &settingKey) -{ - QStringList defs; - - if (!mSettingDefinitions->contains (settingKey)) - return QString(); - - defs = mSettingDefinitions->value (settingKey).toStringList(); - - if (defs.isEmpty()) - return QString(); - - return defs.at(0); -} - -CSMSettings::UserSettings& CSMSettings::UserSettings::instance() -{ - assert(sUserSettingsInstance); - return *sUserSettingsInstance; -} - -void CSMSettings::UserSettings::updateUserSetting(const QString &settingKey, - const QStringList &list) -{ - mSettingDefinitions->setValue (settingKey ,list); - - emit userSettingUpdated (settingKey, list); -} - -CSMSettings::Setting *CSMSettings::UserSettings::findSetting - (const QString &pageName, const QString &settingName) -{ - foreach (Setting *setting, mSettings) - { - if (setting->name() == settingName) - { - if (setting->page() == pageName) - return setting; - } - } - return 0; -} - -void CSMSettings::UserSettings::removeSetting - (const QString &pageName, const QString &settingName) -{ - if (mSettings.isEmpty()) - return; - - QList ::iterator removeIterator = mSettings.begin(); - - while (removeIterator != mSettings.end()) - { - if ((*removeIterator)->name() == settingName) - { - if ((*removeIterator)->page() == pageName) - { - mSettings.erase (removeIterator); - break; - } - } - removeIterator++; - } -} - -CSMSettings::SettingPageMap CSMSettings::UserSettings::settingPageMap() const -{ - SettingPageMap pageMap; - - foreach (Setting *setting, mSettings) - { - SettingPageMap::iterator iter = pageMap.find (setting->page()); - - if (iter==pageMap.end()) - { - QPair > value; - - std::map::const_iterator iter2 = - mSectionLabels.find (setting->page()); - - value.first = iter2!=mSectionLabels.end() ? iter2->second : ""; - - iter = pageMap.insert (setting->page(), value); - } - - iter->second.append (setting); - } - - return pageMap; -} - -CSMSettings::Setting *CSMSettings::UserSettings::createSetting - (CSMSettings::SettingType type, const QString &name, const QString& label) -{ - Setting *setting = new Setting (type, name, mSection, label); - - // set useful defaults - int row = 1; - - if (!mSettings.empty()) - row = mSettings.back()->viewRow()+1; - - setting->setViewLocation (row, 1); - - setting->setColumnSpan (3); - - int width = 10; - - if (type==Type_CheckBox) - width = 40; - - setting->setWidgetWidth (width); - - if (type==Type_CheckBox) - setting->setStyleSheet ("QGroupBox { border: 0px; }"); - - if (type==Type_CheckBox) - setting->setDeclaredValues(QStringList() << "true" << "false"); - - if (type==Type_CheckBox) - setting->setSpecialValueText (setting->getLabel()); - - //add declaration to the model - mSettings.append (setting); - - return setting; -} - -void CSMSettings::UserSettings::declareSection (const QString& page, const QString& label) -{ - mSection = page; - mSectionLabels[page] = label; -} - -QStringList CSMSettings::UserSettings::definitions (const QString &viewKey) const -{ - if (mSettingDefinitions->contains (viewKey)) - return mSettingDefinitions->value (viewKey).toStringList(); - - return QStringList(); -} diff --git a/apps/opencs/model/settings/usersettings.hpp b/apps/opencs/model/settings/usersettings.hpp deleted file mode 100644 index 5188a9842..000000000 --- a/apps/opencs/model/settings/usersettings.hpp +++ /dev/null @@ -1,107 +0,0 @@ -#ifndef USERSETTINGS_HPP -#define USERSETTINGS_HPP - -#include - -#include -#include -#include -#include -#include - -#include -#include "support.hpp" - -#ifndef Q_MOC_RUN -#include -#endif - -namespace Files { typedef std::vector PathContainer; - struct ConfigurationManager;} - -class QFile; -class QSettings; - -namespace CSMSettings { - - class Setting; - typedef QMap > > SettingPageMap; - - class UserSettings: public QObject - { - - Q_OBJECT - - static UserSettings *sUserSettingsInstance; - const Files::ConfigurationManager& mCfgMgr; - - QSettings *mSettingDefinitions; - QList mSettings; - QString mSection; - std::map mSectionLabels; - - public: - - /// Singleton implementation - static UserSettings& instance(); - - UserSettings (const Files::ConfigurationManager& configurationManager); - ~UserSettings(); - - UserSettings (UserSettings const &); //not implemented - UserSettings& operator= (UserSettings const &); //not implemented - - /// Retrieves the settings file at all three levels (global, local and user). - void loadSettings (const QString &fileName); - - /// Updates QSettings and syncs with the ini file - void setDefinitions (const QString &key, const QStringList &defs); - - QString settingValue (const QString &settingKey); - - ///retrieve a setting object from a given page and setting name - Setting *findSetting - (const QString &pageName, const QString &settingName = QString()); - - ///remove a setting from the list - void removeSetting - (const QString &pageName, const QString &settingName); - - ///Retrieve a map of the settings, keyed by page name - SettingPageMap settingPageMap() const; - - ///Returns a string list of defined vlaues for the specified setting - ///in "page/name" format. - QStringList definitions (const QString &viewKey) const; - - ///Test to indicate whether or not a setting has any definitions - bool hasSettingDefinitions (const QString &viewKey) const; - - ///Save any unsaved changes in the QSettings object - void saveDefinitions() const; - - QString setting(const QString &viewKey, const QString &value = QString()); - - private: - - void buildSettingModelDefaults(); - - ///add a new setting to the model and return it - Setting *createSetting (CSMSettings::SettingType type, const QString &name, - const QString& label); - - /// Set the section for createSetting calls. - /// - /// Sections can be declared multiple times. - void declareSection (const QString& page, const QString& label); - - signals: - - void userSettingUpdated (const QString &, const QStringList &); - - public slots: - - void updateUserSetting (const QString &, const QStringList &); - }; -} -#endif // USERSETTINGS_HPP diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index 426e10ecb..b1300a991 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -16,7 +16,6 @@ #include #include "../widget/scenetoolmode.hpp" -#include "../../model/settings/usersettings.hpp" #include "lighting.hpp" diff --git a/apps/opencs/view/settings/booleanview.cpp b/apps/opencs/view/settings/booleanview.cpp deleted file mode 100644 index 8c759cabb..000000000 --- a/apps/opencs/view/settings/booleanview.cpp +++ /dev/null @@ -1,120 +0,0 @@ -#include -#include - -#include -#include -#include - -#include - -#include "booleanview.hpp" -#include "../../model/settings/setting.hpp" - -CSVSettings::BooleanView::BooleanView (CSMSettings::Setting *setting, - Page *parent) - : View (setting, parent), mType(setting->type()) -{ - foreach (const QString &value, setting->declaredValues()) - { - QAbstractButton *button = 0; - - switch (mType) - { - case CSMSettings::Type_CheckBox: { - if(mButtons.empty()) // show only one for checkboxes - { - button = new QCheckBox (value, this); - button->setChecked (setting->defaultValues().at(0) == "true" ? true : false); - - // special visual treatment option for checkboxes - if(setting->specialValueText() != "") { - Frame::setTitle(""); - button->setText(setting->specialValueText()); - } - } - } - break; - - case CSMSettings::Type_RadioButton: - button = new QRadioButton (value, this); - break; - - default: - break; - } - - if(button && (mType != CSMSettings::Type_CheckBox || mButtons.empty())) - { - connect (button, SIGNAL (clicked (bool)), - this, SLOT (slotToggled (bool))); - - button->setObjectName (value); - - addWidget (button); - - mButtons[value] = button; - } - } -} - -void CSVSettings::BooleanView::slotToggled (bool state) -{ - //test only for true to avoid multiple selection updates with radiobuttons - if (!isMultiValue() && !state) - return; - - QStringList values; - - foreach (QString key, mButtons.keys()) - { - // checkbox values are true/false unlike radio buttons - if(mType == CSMSettings::Type_CheckBox) - values.append(mButtons.value(key)->isChecked() ? "true" : "false"); - else - { - if (mButtons.value(key)->isChecked()) - values.append (key); - } - } - setSelectedValues (values, false); - - View::updateView(); -} - -void CSVSettings::BooleanView::updateView (bool signalUpdate) const -{ - - QStringList values = selectedValues(); - - foreach (const QString &buttonName, mButtons.keys()) - { - QAbstractButton *button = mButtons[buttonName]; - - //if the value is not found in the list, the widget is checked false - bool buttonValue = values.contains(buttonName); - - //skip if the butotn value will not change - if (button->isChecked() == buttonValue) - continue; - - //disable autoexclusive if it's enabled and we're setting - //the button value to false - bool switchExclusive = (!buttonValue && button->autoExclusive()); - - if (switchExclusive) - button->setAutoExclusive (false); - - button->setChecked (buttonValue); - - if (switchExclusive) - button->setAutoExclusive(true); - } - View::updateView (signalUpdate); -} - -CSVSettings::BooleanView *CSVSettings::BooleanViewFactory::createView - (CSMSettings::Setting *setting, - Page *parent) -{ - return new BooleanView (setting, parent); -} diff --git a/apps/opencs/view/settings/booleanview.hpp b/apps/opencs/view/settings/booleanview.hpp deleted file mode 100644 index 53198234a..000000000 --- a/apps/opencs/view/settings/booleanview.hpp +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef CSVSETTINGS_BOOLEANVIEW_HPP -#define CSVSETTINGS_BOOLEANVIEW_HPP - -#include -#include - -#include "view.hpp" -#include "../../model/settings/support.hpp" - -class QStringListModel; - -namespace CSVSettings -{ - class BooleanView : public View - { - Q_OBJECT - - QMap mButtons; - enum CSMSettings::SettingType mType; - - public: - explicit BooleanView (CSMSettings::Setting *setting, - Page *parent); - - protected: - void updateView (bool signalUpdate = true) const; - - private slots: - void slotToggled (bool state); - }; - - class BooleanViewFactory : public QObject, public IViewFactory - { - Q_OBJECT - - public: - explicit BooleanViewFactory (QWidget *parent = 0) - : QObject (parent) - {} - - BooleanView *createView (CSMSettings::Setting *setting, - Page *parent); - }; -} -#endif // CSVSETTINGS_BOOLEANVIEW_HPP diff --git a/apps/opencs/view/settings/dialog.cpp b/apps/opencs/view/settings/dialog.cpp deleted file mode 100644 index 38eb7bbc7..000000000 --- a/apps/opencs/view/settings/dialog.cpp +++ /dev/null @@ -1,127 +0,0 @@ -#include "dialog.hpp" - -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "../../model/settings/usersettings.hpp" - -#include "page.hpp" - - -CSVSettings::Dialog::Dialog(QMainWindow *parent) - : SettingWindow (parent), mStackedWidget (0), mDebugMode (false) -{ - setWindowTitle(QString::fromUtf8 ("User Settings")); - - setSizePolicy (QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); - - setMinimumSize (600, 400); - - setupDialog(); - - connect (mPageListWidget, - SIGNAL (currentItemChanged(QListWidgetItem*, QListWidgetItem*)), - this, - SLOT (slotChangePage (QListWidgetItem*, QListWidgetItem*))); -} - -void CSVSettings::Dialog::slotChangePage - (QListWidgetItem *cur, QListWidgetItem *prev) -{ - mStackedWidget->changePage - (mPageListWidget->row (cur), mPageListWidget->row (prev)); -} - -void CSVSettings::Dialog::setupDialog() -{ - QSplitter *centralWidget = new QSplitter (this); - centralWidget->setSizePolicy (QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); - - setCentralWidget (centralWidget); - - buildPageListWidget (centralWidget); - buildStackedWidget (centralWidget); -} - -void CSVSettings::Dialog::buildPages() -{ - SettingWindow::createPages (); - - QFontMetrics fm (QApplication::font()); - - int maxWidth = 1; - - foreach (Page *page, SettingWindow::pages()) - { - maxWidth = std::max (maxWidth, fm.width(page->getLabel())); - - new QListWidgetItem (page->getLabel(), mPageListWidget); - - mStackedWidget->addWidget (page); - } - - mPageListWidget->setMaximumWidth (maxWidth + 10); - - resize (mStackedWidget->sizeHint()); -} - -void CSVSettings::Dialog::buildPageListWidget (QSplitter *centralWidget) -{ - mPageListWidget = new QListWidget (centralWidget); - mPageListWidget->setMinimumWidth(50); - mPageListWidget->setSizePolicy (QSizePolicy::Expanding, QSizePolicy::Expanding); - - mPageListWidget->setSelectionBehavior (QAbstractItemView::SelectItems); - - centralWidget->addWidget(mPageListWidget); -} - -void CSVSettings::Dialog::buildStackedWidget (QSplitter *centralWidget) -{ - mStackedWidget = new ResizeableStackedWidget (centralWidget); - mStackedWidget->setSizePolicy (QSizePolicy::Preferred, QSizePolicy::Expanding); - - centralWidget->addWidget (mStackedWidget); -} - -void CSVSettings::Dialog::closeEvent (QCloseEvent *event) -{ - //SettingWindow::closeEvent() must be called first to ensure - //model is updated - SettingWindow::closeEvent (event); - - saveSettings(); -} - -void CSVSettings::Dialog::show() -{ - if (pages().isEmpty()) - { - buildPages(); - setViewValues(); - } - - QWidget *currView = QApplication::activeWindow(); - if(currView) - { - // place at the center of the window with focus - QSize size = currView->size(); - move(currView->geometry().x()+(size.width() - frameGeometry().width())/2, - currView->geometry().y()+(size.height() - frameGeometry().height())/2); - } - else - { - // something's gone wrong, place at the center of the screen - QPoint screenCenter = QApplication::desktop()->screenGeometry().center(); - move(screenCenter - QPoint(frameGeometry().width()/2, - frameGeometry().height()/2)); - } - QWidget::show(); -} diff --git a/apps/opencs/view/settings/dialog.hpp b/apps/opencs/view/settings/dialog.hpp deleted file mode 100644 index e3a3f575a..000000000 --- a/apps/opencs/view/settings/dialog.hpp +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef CSVSETTINGS_DIALOG_H -#define CSVSETTINGS_DIALOG_H - -#include "settingwindow.hpp" -#include "resizeablestackedwidget.hpp" - -class QStackedWidget; -class QListWidget; -class QListWidgetItem; -class QSplitter; - -namespace CSVSettings { - - class Page; - - class Dialog : public SettingWindow - { - Q_OBJECT - - QListWidget *mPageListWidget; - ResizeableStackedWidget *mStackedWidget; - bool mDebugMode; - - public: - - explicit Dialog (QMainWindow *parent = 0); - - protected: - - /// Settings are written on close - void closeEvent (QCloseEvent *event); - - void setupDialog(); - - private: - - void buildPages(); - void buildPageListWidget (QSplitter *centralWidget); - void buildStackedWidget (QSplitter *centralWidget); - - public slots: - - void show(); - - private slots: - - void slotChangePage (QListWidgetItem *, QListWidgetItem *); - }; -} -#endif // CSVSETTINGS_DIALOG_H diff --git a/apps/opencs/view/settings/frame.cpp b/apps/opencs/view/settings/frame.cpp deleted file mode 100644 index 454d3fefa..000000000 --- a/apps/opencs/view/settings/frame.cpp +++ /dev/null @@ -1,108 +0,0 @@ -#include "frame.hpp" - -#include - -const QString CSVSettings::Frame::sInvisibleBoxStyle = - QString::fromUtf8("Frame { border:2px; padding: 2px; margin: 2px;}"); - -CSVSettings::Frame::Frame (bool isVisible, const QString &title, - QWidget *parent) - : QGroupBox (title, parent), mIsHorizontal (true), - mLayout (new SettingLayout()) -{ - setFlat (true); - mVisibleBoxStyle = styleSheet(); - - if (!isVisible) - { - // must be Page, not a View - setStyleSheet (sInvisibleBoxStyle); - } - - setLayout (mLayout); -} - -void CSVSettings::Frame::hideWidgets() -{ - for (int i = 0; i < children().size(); i++) - { - QObject *obj = children().at(i); - - Frame *widgFrame = dynamic_cast (obj); - - if (widgFrame) - { - widgFrame->hideWidgets(); - continue; - } - - QWidget *widg = static_cast (obj); - if (widg->property("sizePolicy").isValid()) - widg->setSizePolicy (QSizePolicy::Expanding, QSizePolicy::Expanding); - } - - layout()->activate(); - setFixedSize(minimumSizeHint()); - -} - -void CSVSettings::Frame::showWidgets() -{ - for (int i = 0; i < children().size(); i++) - { - QObject *obj = children().at(i); - - Frame *widgFrame = dynamic_cast (obj); - - if (widgFrame) - { - widgFrame->showWidgets(); - continue; - } - - QWidget *widg = static_cast (obj); - - if (widg->property("sizePolicy").isValid()) - { - widg->setSizePolicy - (QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); - } - } - layout()->activate(); - setFixedSize(minimumSizeHint()); -} - -void CSVSettings::Frame::addWidget (QWidget *widget, int row, int column, - int rowSpan, int columnSpan) -{ - if (row == -1) - row = getNextRow(); - - if (column == -1) - column = getNextColumn(); - - mLayout->addWidget (widget, row, column, rowSpan, columnSpan); - //, Qt::AlignLeft | Qt::AlignTop); - - widget->setSizePolicy (QSizePolicy::Ignored, QSizePolicy::Ignored); -} - -int CSVSettings::Frame::getNextRow () const -{ - int row = mLayout->rowCount(); - - if (mIsHorizontal && row > 0) - row--; - - return row; -} - -int CSVSettings::Frame::getNextColumn () const -{ - int column = 0; - - if (mIsHorizontal) - column = mLayout->columnCount(); - - return column; -} diff --git a/apps/opencs/view/settings/frame.hpp b/apps/opencs/view/settings/frame.hpp deleted file mode 100644 index bbb92f34f..000000000 --- a/apps/opencs/view/settings/frame.hpp +++ /dev/null @@ -1,60 +0,0 @@ -#ifndef CSVSETTINGS_FRAME_HPP -#define CSVSETTINGS_FRAME_HPP - -#include -#include -#include -#include "../../model/settings/support.hpp" - -namespace CSVSettings -{ - class SettingLayout : public QGridLayout - { - public: - explicit SettingLayout (QWidget *parent = 0) - : QGridLayout (parent) - { - setContentsMargins(0,0,0,0); - setAlignment(Qt::AlignLeft | Qt::AlignTop); - } - }; - - /// Custom implementation of QGroupBox to act as a base for view classes - class Frame : public QGroupBox - { - static const QString sInvisibleBoxStyle; - - QString mVisibleBoxStyle; - - bool mIsHorizontal; - - SettingLayout *mLayout; - - public: - explicit Frame (bool isVisible, const QString &title = "", - QWidget *parent = 0); - - ///Adds a widget to the grid layout, setting the position - ///relative to the last added widgets, or absolutely for positive - ///row / column values - void addWidget (QWidget *widget, int row = -1, int column = -1, - int rowSpan = 1, int columnSpan = 1); - - ///Force the grid to lay out in horizontal or vertical alignments - void setHLayout() { mIsHorizontal = true; } - void setVLayout() { mIsHorizontal = false; } - - ///show / hide widgets (when stacked widget page changes) - void showWidgets(); - void hideWidgets(); - - private: - - ///functions which return the index for the next layout row / column - int getNextColumn() const; - int getNextRow() const; - - }; -} - -#endif // CSVSETTINGS_FRAME_HPP diff --git a/apps/opencs/view/settings/listview.cpp b/apps/opencs/view/settings/listview.cpp deleted file mode 100644 index 0876b3982..000000000 --- a/apps/opencs/view/settings/listview.cpp +++ /dev/null @@ -1,106 +0,0 @@ -#include "listview.hpp" -#include "../../model/settings/setting.hpp" - -#include -#include -#include - -CSVSettings::ListView::ListView(CSMSettings::Setting *setting, - Page *parent) - : View(setting, parent), mAbstractItemView (0), mComboBox (0) -{ - QWidget *widget = - buildWidget(setting->isMultiLine(), setting->widgetWidth()); - - addWidget (widget, setting->viewRow(), setting->viewColumn()); - - if (mComboBox) - buildComboBoxModel(); - - else if (mAbstractItemView) - buildAbstractItemViewModel(); -} - -void CSVSettings::ListView::buildComboBoxModel() -{ - mComboBox->setModel (dataModel()); - mComboBox->setModelColumn (0); - mComboBox->view()->setSelectionModel (selectionModel()); - - int curIdx = -1; - - if (!selectionModel()->selection().isEmpty()) - curIdx = selectionModel()->selectedIndexes().at(0).row(); - - mComboBox->setCurrentIndex (curIdx); - - connect (mComboBox, SIGNAL(currentIndexChanged(int)), - this, SLOT(emitItemViewUpdate(int))); -} - -void CSVSettings::ListView::buildAbstractItemViewModel() -{ - mAbstractItemView->setModel (dataModel()); - mAbstractItemView->setSelectionModel (selectionModel()); - - //connection needs to go here for list view update to signal to - //the outside -} - -void CSVSettings::ListView::emitItemViewUpdate (int idx) -{ - updateView(); -} - -QWidget *CSVSettings::ListView::buildWidget(bool isMultiLine, int width) -{ - QWidget *widget = 0; - - if (isMultiLine) - { - mAbstractItemView = new QListView (this); - widget = mAbstractItemView; - - if (width > 0) - widget->setFixedWidth (widgetWidth (width)); - } - else - { - mComboBox = new QComboBox (this); - widget = mComboBox; - - if (width > 0) - mComboBox->setMinimumContentsLength (width); - } - - return widget; -} - -void CSVSettings::ListView::showEvent ( QShowEvent * event ) -{ - View::showEvent (event); -} - -void CSVSettings::ListView::updateView (bool signalUpdate) const -{ - QStringList values = selectedValues(); - - if (mComboBox) - { - int idx = -1; - - if (values.size() > 0) - idx = (mComboBox->findText(values.at(0))); - - mComboBox->setCurrentIndex (idx); - } - - View::updateView (signalUpdate); -} - -CSVSettings::ListView *CSVSettings::ListViewFactory::createView - (CSMSettings::Setting *setting, - Page *parent) -{ - return new ListView(setting, parent); -} diff --git a/apps/opencs/view/settings/listview.hpp b/apps/opencs/view/settings/listview.hpp deleted file mode 100644 index c2860d769..000000000 --- a/apps/opencs/view/settings/listview.hpp +++ /dev/null @@ -1,63 +0,0 @@ -#ifndef CSVSETTINGS_LISTVIEW_HPP -#define CSVSETTINGS_LISTVIEW_HPP - -#include "view.hpp" - - -class QStringListModel; -class QComboBox; -class QAbstractItemView; - -namespace CSVSettings -{ - class ListView : public View - { - Q_OBJECT - - QAbstractItemView *mAbstractItemView; - QComboBox *mComboBox; - - public: - explicit ListView (CSMSettings::Setting *setting, - Page *parent); - - protected: - - void updateView (bool signalUpdate = true) const; - void showEvent ( QShowEvent * event ); - - ///Receives signal from widget and signals viwUpdated() - void slotTextEdited (QString value); - - private: - - ///Helper function to construct a model for an AbstractItemView - void buildAbstractItemViewModel(); - - ///Helper function to construct a model for a combobox - void buildComboBoxModel(); - - ///Helper function to build the view widget - QWidget *buildWidget (bool isMultiLine, int width); - - private slots: - - ///Receives updates from single-select widgets (like combobox) and - ///signals viewUpdated with the selected values. - void emitItemViewUpdate (int idx); - }; - - class ListViewFactory : public QObject, public IViewFactory - { - Q_OBJECT - - public: - explicit ListViewFactory (QWidget *parent = 0) - : QObject (parent) - {} - - ListView *createView (CSMSettings::Setting *setting, - Page *parent); - }; -} -#endif // CSVSETTINGS_LISTVIEW_HPP diff --git a/apps/opencs/view/settings/page.cpp b/apps/opencs/view/settings/page.cpp deleted file mode 100644 index c009cdd7a..000000000 --- a/apps/opencs/view/settings/page.cpp +++ /dev/null @@ -1,110 +0,0 @@ -#include "page.hpp" - -#include - -#include "view.hpp" -#include "booleanview.hpp" -#include "textview.hpp" -#include "listview.hpp" -#include "rangeview.hpp" - -#include "../../model/settings/usersettings.hpp" -#include "../../model/settings/connector.hpp" -#include "../../model/settings/support.hpp" - -#include "settingwindow.hpp" - -QMap - CSVSettings::Page::mViewFactories; - -CSVSettings::Page::Page (const QString &pageName, QList settingList, - SettingWindow *parent, const QString& label) -: Frame(false, "", parent), mParent(parent), mIsEditorPage (false), mLabel (label) -{ - setObjectName (pageName); - - if (mViewFactories.size() == 0) - buildFactories(); - - setVLayout(); - setupViews (settingList); -} - -void CSVSettings::Page::setupViews - (QList &settingList) -{ - foreach (CSMSettings::Setting *setting, settingList) - addView (setting); -} - -void CSVSettings::Page::addView (CSMSettings::Setting *setting) -{ - if (setting->viewType() == ViewType_Undefined) - { - if(setting->specialValueText() != "") - { - // hack to put a label - addWidget(new QLabel(setting->specialValueText()), - setting->viewRow(), setting->viewColumn(), - setting->rowSpan(), setting->columnSpan()); - return; - } - else - return; - } - - View *view = mViewFactories[setting->viewType()]->createView(setting, this); - - if (!view) - return; - - mViews.append (view); - - addWidget (view, setting->viewRow(), setting->viewColumn(), - setting->rowSpan(), setting->columnSpan() ); - - //if this page is an editor page, connect each of it's views up to the - //UserSettings singleton for signaling back to OpenCS - if (setting->isEditorSetting()) { - connect (view, SIGNAL (viewUpdated(const QString&, const QStringList&)), - &CSMSettings::UserSettings::instance(), - SLOT (updateUserSetting (const QString &, const QStringList &))); - } -} - -CSVSettings::View *CSVSettings::Page::findView (const QString &page, - const QString &setting) const -{ - - //if this is not the page we're looking for, - //appeal to the parent setting window to find the appropriate view - if (page != objectName()) - return mParent->findView (page, setting); - - //otherwise, return the matching view - for (int i = 0; i < mViews.size(); i++) - { - View *view = mViews.at(i); - - if (view->parentPage()->objectName() != page) - continue; - - if (view->objectName() == setting) - return view; - } - - return 0; -} - -void CSVSettings::Page::buildFactories() -{ - mViewFactories[ViewType_Boolean] = new BooleanViewFactory (this); - mViewFactories[ViewType_Text] = new TextViewFactory (this); - mViewFactories[ViewType_List] = new ListViewFactory (this); - mViewFactories[ViewType_Range] = new RangeViewFactory (this); -} - -QString CSVSettings::Page::getLabel() const -{ - return mLabel; -} diff --git a/apps/opencs/view/settings/page.hpp b/apps/opencs/view/settings/page.hpp deleted file mode 100644 index caf2eec3f..000000000 --- a/apps/opencs/view/settings/page.hpp +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef CSVSETTINGS_PAGE_HPP -#define CSVSETTINGS_PAGE_HPP - -#include -#include -#include - -#include "frame.hpp" - -#include "../../model/settings/support.hpp" - -namespace CSMSettings { class Setting; } - -namespace CSVSettings -{ - class View; - class IViewFactory; - class SettingWindow; - - class Page : public Frame - { - Q_OBJECT - - QList mViews; - SettingWindow *mParent; - static QMap mViewFactories; - bool mIsEditorPage; - QString mLabel; - - public: - Page (const QString &pageName, QList settingList, - SettingWindow *parent, const QString& label); - - ///Creates a new view based on the passed setting and adds it to - ///the page. - void addView (CSMSettings::Setting *setting); - - ///Iterates the views created for this page based on the passed setting - ///and returns it. - View *findView (const QString &page, const QString &setting) const; - - ///returns the list of views associated with the page - const QList &views () const { return mViews; } - - QString getLabel() const; - - private: - - ///Creates views based on the passed setting list - void setupViews (QList &settingList); - - ///Creates factory objects for view construction - void buildFactories(); - }; -} -#endif // CSVSETTINGS_PAGE_HPP diff --git a/apps/opencs/view/settings/rangeview.cpp b/apps/opencs/view/settings/rangeview.cpp deleted file mode 100644 index 5893c5d0d..000000000 --- a/apps/opencs/view/settings/rangeview.cpp +++ /dev/null @@ -1,208 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#include "rangeview.hpp" -#include "spinbox.hpp" -#include "../../model/settings/setting.hpp" -#include "../../model/settings/support.hpp" - -CSVSettings::RangeView::RangeView (CSMSettings::Setting *setting, - Page *parent) - : View (setting, parent), mRangeWidget (0), mRangeType (setting->type()) -{ - - mRangeWidget = 0; - - if (isMultiValue()) - return; - - switch (mRangeType) - { - case CSMSettings::Type_SpinBox: - case CSMSettings::Type_DoubleSpinBox: - buildSpinBox (setting); - break; - - case CSMSettings::Type_Dial: - case CSMSettings::Type_Slider: - buildSlider (setting); - break; - - default: - break; - } - - if(mRangeWidget) - { - mRangeWidget->setFixedWidth (widgetWidth (setting->widgetWidth())); - mRangeWidget->setObjectName (setting->name()); - } - - addWidget (mRangeWidget); -} - -void CSVSettings::RangeView::buildSlider (CSMSettings::Setting *setting) -{ - switch (setting->type()) - { - case CSMSettings::Type_Slider: - mRangeWidget = new QSlider (Qt::Horizontal, this); - mRangeWidget->setProperty ("tickInterval", setting->tickInterval()); - - if (setting->ticksAbove()) - { - if (setting->ticksBelow()) - mRangeWidget->setProperty ("tickPosition", QSlider::TicksBothSides); - else - mRangeWidget->setProperty ("tickPosition", QSlider::TicksAbove); - } - else if (setting->ticksBelow()) - mRangeWidget->setProperty ("tickPosition", QSlider::TicksBelow); - else - mRangeWidget->setProperty ("tickPosition", QSlider::NoTicks); - - break; - - case CSMSettings::Type_Dial: - mRangeWidget = new QDial (this); - mRangeWidget->setProperty ("wrapping", setting->wrapping()); - mRangeWidget->setProperty ("notchesVisible", - (setting->ticksAbove() || setting->ticksBelow())); - break; - - default: - break; - } - - if(mRangeWidget) - { - mRangeWidget->setProperty ("minimum", setting->minimum()); - mRangeWidget->setProperty ("maximum", setting->maximum()); - mRangeWidget->setProperty ("tracking", false); - mRangeWidget->setProperty ("singleStep", setting->singleStep()); - - connect (mRangeWidget, SIGNAL (valueChanged (int)), - this, SLOT (slotUpdateView (int))); - } -} - -void CSVSettings::RangeView::buildSpinBox (CSMSettings::Setting *setting) -{ - SpinBox *sb = 0; - - switch (setting->type()) - { - case CSMSettings::Type_SpinBox: - - sb = new SpinBox (this); - - if (!setting->declaredValues().isEmpty()) - sb->setValueList (setting->declaredValues()); - - mRangeWidget = sb; - - connect (mRangeWidget, SIGNAL (valueChanged (int)), - this, SLOT (slotUpdateView (int))); - break; - - case CSMSettings::Type_DoubleSpinBox: - mRangeWidget = new QDoubleSpinBox (this); - - connect (mRangeWidget, SIGNAL (valueChanged (double)), - this, SLOT (slotUpdateView (double))); - break; - - default: - return; - } - - //min / max values are set automatically in AlphaSpinBox - if (setting->declaredValues().isEmpty()) - { - mRangeWidget->setProperty ("minimum", setting->minimum()); - mRangeWidget->setProperty ("maximum", setting->maximum()); - mRangeWidget->setProperty ("singleStep", setting->singleStep()); - } - - mRangeWidget->setProperty ("prefix", setting->prefix()); - mRangeWidget->setProperty ("suffix", setting->suffix()); - mRangeWidget->setProperty ("wrapping", setting->wrapping()); - dynamic_cast (mRangeWidget)->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); - - if(setting->type() == CSMSettings::Type_SpinBox && setting->declaredValues().isEmpty()) - dynamic_cast (mRangeWidget)->setValue (setting->defaultValues().at(0).toInt()); -} - -void CSVSettings::RangeView::slotUpdateView (int value) -{ - QString textValue = ""; - QStringList list; - - switch (mRangeType) - { - case CSMSettings::Type_SpinBox: - list = static_cast (mRangeWidget)->valueList(); - if (!list.isEmpty()) - textValue = list.at(value); - break; - - default: - break; - } - - if (textValue.isEmpty()) - textValue = QVariant (value).toString(); - - setSelectedValue (textValue, false); - - View::updateView(); -} - -void CSVSettings::RangeView::slotUpdateView (double value) -{ - setSelectedValue (QVariant(value).toString(), false); - - View::updateView(); -} - -void CSVSettings::RangeView::updateView (bool signalUpdate) const -{ - QString value; - - if (!selectedValues().isEmpty()) - value = selectedValues().at(0); - - switch (mRangeType) - { - case CSMSettings::Type_SpinBox: - static_cast (mRangeWidget)->setValue (value); - break; - - case CSMSettings::Type_DoubleSpinBox: - static_cast (mRangeWidget)->setValue (value.toDouble()); - break; - - case CSMSettings::Type_Slider: - case CSMSettings::Type_Dial: - mRangeWidget->setProperty ("value", value.toInt()); - mRangeWidget->setProperty ("sliderPosition", value.toInt()); - break; - - default: - break; - - } - - View::updateView (signalUpdate); -} - -CSVSettings::RangeView *CSVSettings::RangeViewFactory::createView - (CSMSettings::Setting *setting, - Page *parent) -{ - return new RangeView (setting, parent); -} diff --git a/apps/opencs/view/settings/rangeview.hpp b/apps/opencs/view/settings/rangeview.hpp deleted file mode 100644 index 2ab343f1f..000000000 --- a/apps/opencs/view/settings/rangeview.hpp +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef CSVSETTINGS_RANGEVIEW_HPP -#define CSVSETTINGS_RANGEVIEW_HPP - -#include "view.hpp" -#include "../../model/settings/support.hpp" - -class QStringListModel; -class QAbstractSpinBox; - -namespace CSVSettings -{ - class RangeView : public View - { - Q_OBJECT - - QWidget *mRangeWidget; - CSMSettings::SettingType mRangeType; - - public: - explicit RangeView (CSMSettings::Setting *setting, - Page *parent); - - protected: - - ///virtual function called through View - void updateView (bool signalUpdate = true) const; - - ///construct a slider-based view - void buildSlider (CSMSettings::Setting *setting); - - ///construct a spinbox-based view - void buildSpinBox (CSMSettings::Setting *setting); - - private slots: - - ///responds to valueChanged signals - void slotUpdateView (int value); - void slotUpdateView (double value); - - }; - - class RangeViewFactory : public QObject, public IViewFactory - { - Q_OBJECT - - public: - explicit RangeViewFactory (QWidget *parent = 0) - : QObject (parent) - {} - - RangeView *createView (CSMSettings::Setting *setting, - Page *parent); - }; -} -#endif // CSVSETTINGS_RANGEVIEW_HPP diff --git a/apps/opencs/view/settings/resizeablestackedwidget.cpp b/apps/opencs/view/settings/resizeablestackedwidget.cpp deleted file mode 100644 index 0e87a2506..000000000 --- a/apps/opencs/view/settings/resizeablestackedwidget.cpp +++ /dev/null @@ -1,39 +0,0 @@ -#include "resizeablestackedwidget.hpp" -#include "page.hpp" - -#include - -CSVSettings::ResizeableStackedWidget::ResizeableStackedWidget(QWidget *parent) : - QStackedWidget(parent) -{} - -void CSVSettings::ResizeableStackedWidget::addWidget(QWidget* pWidget) -{ - QStackedWidget::addWidget(pWidget); -} - -void CSVSettings::ResizeableStackedWidget::changePage - (int current, int previous) -{ - if (current == previous) - return; - - Page *prevPage = 0; - Page *curPage = 0; - - if (previous > -1) - prevPage = static_cast (widget (previous)); - - if (current > -1) - curPage = static_cast (widget (current)); - - if (prevPage) - prevPage->hideWidgets(); - - if (curPage) - curPage->showWidgets(); - - layout()->activate(); - - setCurrentIndex (current); -} diff --git a/apps/opencs/view/settings/resizeablestackedwidget.hpp b/apps/opencs/view/settings/resizeablestackedwidget.hpp deleted file mode 100644 index 2d0c71a23..000000000 --- a/apps/opencs/view/settings/resizeablestackedwidget.hpp +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef CSVSETTINGS_RESIZEABLESTACKEDWIDGET_HPP -#define CSVSETTINGS_RESIZEABLESTACKEDWIDGET_HPP - -#include - -class QListWidgetItem; - -namespace CSVSettings -{ - class ResizeableStackedWidget : public QStackedWidget - { - Q_OBJECT - - public: - explicit ResizeableStackedWidget(QWidget *parent = 0); - - ///add a widget to the stacked widget - void addWidget(QWidget* pWidget); - - ///called whenever the stacked widget page is changed - void changePage (int, int); - }; -} - -#endif // CSVSETTINGS_RESIZEABLESTACKEDWIDGET_HPP diff --git a/apps/opencs/view/settings/settingwindow.cpp b/apps/opencs/view/settings/settingwindow.cpp deleted file mode 100644 index 76ea9dc4f..000000000 --- a/apps/opencs/view/settings/settingwindow.cpp +++ /dev/null @@ -1,131 +0,0 @@ -#include -#include - -#include "../../model/settings/setting.hpp" -#include "../../model/settings/connector.hpp" -#include "../../model/settings/usersettings.hpp" -#include "settingwindow.hpp" -#include "page.hpp" -#include "view.hpp" - -CSVSettings::SettingWindow::SettingWindow(QWidget *parent) - : QMainWindow(parent), mModel(NULL) -{} - -void CSVSettings::SettingWindow::createPages() -{ - CSMSettings::SettingPageMap pageMap = mModel->settingPageMap(); - - QList connectedSettings; - - foreach (const QString &pageName, pageMap.keys()) - { - QList pageSettings = pageMap.value (pageName).second; - - mPages.append (new Page (pageName, pageSettings, this, pageMap.value (pageName).first)); - - for (int i = 0; i < pageSettings.size(); i++) - { - CSMSettings::Setting *setting = pageSettings.at(i); - - if (!setting->proxyLists().isEmpty()) - connectedSettings.append (setting); - } - } - - if (!connectedSettings.isEmpty()) - createConnections(connectedSettings); -} - -void CSVSettings::SettingWindow::createConnections - (const QList &list) -{ - foreach (const CSMSettings::Setting *setting, list) - { - View *masterView = findView (setting->page(), setting->name()); - - CSMSettings::Connector *connector = - new CSMSettings::Connector (masterView, this); - - connect (masterView, - SIGNAL (viewUpdated(const QString &, const QStringList &)), - connector, - SLOT (slotUpdateSlaves()) - ); - - const CSMSettings::ProxyValueMap &proxyMap = setting->proxyLists(); - - foreach (const QString &key, proxyMap.keys()) - { - QStringList keyPair = key.split('/'); - - if (keyPair.size() != 2) - continue; - - View *slaveView = findView (keyPair.at(0), keyPair.at(1)); - - if (!slaveView) - { - qWarning () << "Unable to create connection for view " - << key; - continue; - } - - QList proxyList = proxyMap.value (key); - connector->addSlaveView (slaveView, proxyList); - - connect (slaveView, - SIGNAL (viewUpdated(const QString &, const QStringList &)), - connector, - SLOT (slotUpdateMaster())); - } - } -} - -void CSVSettings::SettingWindow::setViewValues() -{ - //iterate each page and view, setting their definitions - //if they exist in the model - foreach (const Page *page, mPages) - { - foreach (const View *view, page->views()) - { - //testing beforehand prevents overwriting a proxy setting - if (!mModel->hasSettingDefinitions (view->viewKey())) - continue; - - QStringList defs = mModel->definitions (view->viewKey()); - - view->setSelectedValues(defs); - } - } -} - -CSVSettings::View *CSVSettings::SettingWindow::findView - (const QString &pageName, const QString &setting) -{ - foreach (const Page *page, mPages) - { - if (page->objectName() == pageName) - return page->findView (pageName, setting); - } - return 0; -} - -void CSVSettings::SettingWindow::saveSettings() -{ - //setting the definition in the model automatically syncs with the file - foreach (const Page *page, mPages) - { - foreach (const View *view, page->views()) - { - if (!view->serializable()) - continue; - - mModel->setDefinitions (view->viewKey(), view->selectedValues()); - } - } - - mModel->saveDefinitions(); -} - diff --git a/apps/opencs/view/settings/settingwindow.hpp b/apps/opencs/view/settings/settingwindow.hpp deleted file mode 100644 index 11bceee96..000000000 --- a/apps/opencs/view/settings/settingwindow.hpp +++ /dev/null @@ -1,58 +0,0 @@ -#ifndef CSVSETTINGS_SETTINGWINDOW_HPP -#define CSVSETTINGS_SETTINGWINDOW_HPP - -#include -#include - -#include "../../model/settings/support.hpp" - -namespace CSMSettings { - class Setting; - class UserSettings; -} - -namespace CSVSettings { - - class Page; - class View; - - typedef QList PageList; - - class SettingWindow : public QMainWindow - { - Q_OBJECT - - PageList mPages; - CSMSettings::UserSettings *mModel; - - public: - explicit SettingWindow(QWidget *parent = 0); - - ///retrieve a reference to a view based on it's page and setting name - View *findView (const QString &pageName, const QString &setting); - - ///set the model the view uses (instance of UserSettings) - void setModel (CSMSettings::UserSettings &model) { mModel = &model; } - - protected: - - ///construct the pages to be displayed in the dialog - void createPages(); - - ///return the list of constructed pages - const PageList &pages() const { return mPages; } - - ///save settings from the GUI to file - void saveSettings(); - - ///sets the defined values for the views that have been created - void setViewValues(); - - private: - - ///create connections between settings (used for proxy settings) - void createConnections (const QList &list); - }; -} - -#endif // CSVSETTINGS_SETTINGWINDOW_HPP diff --git a/apps/opencs/view/settings/spinbox.cpp b/apps/opencs/view/settings/spinbox.cpp deleted file mode 100644 index 043107bb7..000000000 --- a/apps/opencs/view/settings/spinbox.cpp +++ /dev/null @@ -1,50 +0,0 @@ -#include "spinbox.hpp" - -#include - -CSVSettings::SpinBox::SpinBox(QWidget *parent) - : QSpinBox(parent), mValueList(QStringList()) -{ - setRange (0, 0); -} - -QString CSVSettings::SpinBox::textFromValue(int val) const -{ - if (mValueList.isEmpty()) - return QVariant (val).toString(); - - QString value; - - if (val < mValueList.size()) - value = mValueList.at (val); - - return value; -} - -int CSVSettings::SpinBox::valueFromText(const QString &text) const -{ - if (mValueList.isEmpty()) - return text.toInt(); // TODO: assumed integer, untested error handling for alpha types - - if (mValueList.contains (text)) - return mValueList.indexOf(text); - - return -1; -} - -void CSVSettings::SpinBox::setValue (const QString &value) -{ - if (!mValueList.isEmpty()) - { - lineEdit()->setText (value); - QSpinBox::setValue(valueFromText(value)); - } - else - QSpinBox::setValue (value.toInt()); -} - -void CSVSettings::SpinBox::setValueList (const QStringList &list) -{ - mValueList = list; - setMaximum (list.size() - 1); -} diff --git a/apps/opencs/view/settings/spinbox.hpp b/apps/opencs/view/settings/spinbox.hpp deleted file mode 100644 index e887e8c93..000000000 --- a/apps/opencs/view/settings/spinbox.hpp +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef CSVSETTINGS_SPINBOX_HPP -#define CSVSETTINGS_SPINBOX_HPP - -#include -#include -#include - -namespace CSVSettings -{ - class SpinBox : public QSpinBox - { - Q_OBJECT - - QStringList mValueList; - - public: - explicit SpinBox(QWidget *parent = 0); - - ///set the value displayed in the spin box - void setValue (const QString &value); - - ///set the stringlist that's used as a list of pre-defined values - ///to be displayed as the user scrolls - void setValueList (const QStringList &list); - - ///returns the pre-defined value list. - const QStringList &valueList() const { return mValueList; } - - protected: - - ///converts an index value to corresponding text to be displayed - QString textFromValue (int val) const; - - ///converts a text value to a corresponding index - int valueFromText (const QString &text) const; - }; -} -#endif // CSVSETTINGS_SPINBOX_HPP diff --git a/apps/opencs/view/settings/textview.cpp b/apps/opencs/view/settings/textview.cpp deleted file mode 100644 index a6ab657fe..000000000 --- a/apps/opencs/view/settings/textview.cpp +++ /dev/null @@ -1,63 +0,0 @@ -#include -#include - -#include "textview.hpp" -#include "../../model/settings/setting.hpp" - -CSVSettings::TextView::TextView(CSMSettings::Setting *setting, Page *parent) - : View (setting, parent), mDelimiter (setting->delimiter()) - -{ - if (setting->isMultiLine()) - mTextWidget = new QTextEdit ("", this); - else - mTextWidget = new QLineEdit ("", this); - - if (setting->widgetWidth() > 0) - mTextWidget->setFixedWidth (widgetWidth (setting->widgetWidth())); - - connect (mTextWidget, SIGNAL (textEdited (QString)), - this, SLOT (slotTextEdited (QString))); - - addWidget (mTextWidget, setting->viewRow(), setting->viewColumn()); -} - -bool CSVSettings::TextView::isEquivalent - (const QString &lhs, const QString &rhs) const -{ - return (lhs.trimmed() == rhs.trimmed()); -} - -void CSVSettings::TextView::slotTextEdited (QString value) -{ - QStringList values = value.split (mDelimiter, QString::SkipEmptyParts); - - QStringList returnValues; - - foreach (const QString &splitValue, values) - returnValues.append (splitValue.trimmed()); - - setSelectedValues (returnValues, false); - - View::updateView(); -} - -void CSVSettings::TextView::updateView(bool signalUpdate) const -{ - QString values = selectedValues().join (mDelimiter); - - if (isEquivalent (mTextWidget->property("text").toString(), values)) - return; - - mTextWidget->setProperty("text", values); - - View::updateView (signalUpdate); -} - -CSVSettings::TextView *CSVSettings::TextViewFactory::createView - (CSMSettings::Setting *setting, - Page *parent) -{ - return new TextView (setting, parent); -} - diff --git a/apps/opencs/view/settings/textview.hpp b/apps/opencs/view/settings/textview.hpp deleted file mode 100644 index f4cd03d2f..000000000 --- a/apps/opencs/view/settings/textview.hpp +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef CSVSETTINGS_TEXTVIEW_HPP -#define CSVSETTINGS_TEXTVIEW_HPP - -#include "view.hpp" -#include "../../model/settings/setting.hpp" - -namespace CSVSettings -{ - class TextView : public View - { - Q_OBJECT - - QWidget *mTextWidget; - - QString mDelimiter; - - public: - explicit TextView (CSMSettings::Setting *setting, - Page *parent = 0); - - protected: - - /// virtual function called through View - void updateView (bool signalUpdate = true) const; - - protected slots: - - ///Receives updates to the widget for signalling - void slotTextEdited (QString value); - - private: - - ///Comparison function that returns true if the trimmed() strings - ///are equal - bool isEquivalent (const QString &lhs, const QString &rhs) const; - }; - - class TextViewFactory : public QObject, public IViewFactory - { - Q_OBJECT - - public: - explicit TextViewFactory (QWidget *parent = 0) - : QObject (parent) - {} - - TextView *createView (CSMSettings::Setting *setting, - Page *parent); - }; -} -#endif // CSVSETTINGS_TEXTVIEW_HPP diff --git a/apps/opencs/view/settings/view.cpp b/apps/opencs/view/settings/view.cpp deleted file mode 100644 index 21cf55fdd..000000000 --- a/apps/opencs/view/settings/view.cpp +++ /dev/null @@ -1,222 +0,0 @@ -#include -#include -#include -#include -#include - -#include "view.hpp" -#include "../../model/settings/support.hpp" -#include "../../model/settings/setting.hpp" -#include "page.hpp" - -CSVSettings::View::View(CSMSettings::Setting *setting, - Page *parent) - - : Frame(true, setting->getLabel(), parent), - mParentPage (parent), mDataModel(0), - mHasFixedValues (!setting->declaredValues().isEmpty()), - mIsMultiValue (setting->isMultiValue()), - mViewKey (setting->page() + '/' + setting->name()), - mSerializable (setting->serializable()) -{ - if (!setting->getToolTip().isEmpty()) - setToolTip (setting->getToolTip()); - - setObjectName (setting->name()); - buildView(); - buildModel (setting); - // apply stylesheet to view's frame if exists - if(setting->styleSheet() != "") - Frame::setStyleSheet (setting->styleSheet()); -} - -void CSVSettings::View::buildModel (const CSMSettings::Setting *setting) -{ - QStringList values = setting->defaultValues(); - - if (mHasFixedValues) - buildFixedValueModel (setting->declaredValues()); - else - buildUpdatableValueModel (values); - - mSelectionModel = new QItemSelectionModel (mDataModel, this); - - setSelectedValues (values, false); -} - -void CSVSettings::View::buildFixedValueModel (const QStringList &values) -{ - //fixed value models are simple string list models, since they are read-only - mDataModel = new QStringListModel (values, this); -} - -void CSVSettings::View::buildUpdatableValueModel (const QStringList &values) -{ - //updateable models are standard item models because they support - //replacing entire columns - QList itemList; - - foreach (const QString &value, values) - itemList.append (new QStandardItem(value)); - - QStandardItemModel *model = new QStandardItemModel (this); - model->appendColumn (itemList); - - mDataModel = model; -} - -void CSVSettings::View::buildView() -{ - setFlat (true); - setHLayout(); -} - -int CSVSettings::View::currentIndex () const -{ - if (selectedValues().isEmpty()) - return -1; - - QString currentValue = selectedValues().at(0); - - for (int i = 0; i < mDataModel->rowCount(); i++) - if (value(i) == currentValue) - return i; - - return -1; -} - -void CSVSettings::View::refresh() const -{ - select (mSelectionModel->selection()); - updateView(); -} - -int CSVSettings::View::rowCount() const -{ - return mDataModel->rowCount(); -} - -void CSVSettings::View::select (const QItemSelection &selection) const -{ - mSelectionModel->clear(); - mSelectionModel->select(selection, QItemSelectionModel::Select); -} - -QStringList CSVSettings::View::selectedValues() const -{ - QStringList selValues; - - foreach (const QModelIndex &idx, mSelectionModel->selectedIndexes()) - selValues.append (value(idx.row())); - - return selValues; -} - -void CSVSettings::View::setSelectedValue (const QString &value, - bool doViewUpdate, bool signalUpdate) -{ - setSelectedValues (QStringList() << value, doViewUpdate, signalUpdate); -} - -void CSVSettings::View::setSelectedValues (const QStringList &list, - bool doViewUpdate, bool signalUpdate) const -{ - QItemSelection selection; - - if (stringListsMatch (list, selectedValues())) - return; - - if (!mHasFixedValues) - { - QStandardItemModel *model = - static_cast (mDataModel); - - model->clear(); - model->appendColumn (toStandardItemList (list)); - - for (int i = 0; i < model->rowCount(); i++) - { - QModelIndex idx = model->index(i, 0); - selection.append (QItemSelectionRange (idx, idx)); - } - } - else - { - for (int i = 0; i < mDataModel->rowCount(); i++) - { - if (list.contains(value(i))) - { - QModelIndex idx = mDataModel->index(i, 0); - selection.append(QItemSelectionRange (idx, idx)); - } - } - } - select (selection); - - //update the view if the selection was set from the model side, not by the - //user - if (doViewUpdate) - updateView (signalUpdate); -} - -void CSVSettings::View::showEvent ( QShowEvent * event ) -{ - refresh(); -} - -bool CSVSettings::View::stringListsMatch ( - const QStringList &list1, - const QStringList &list2) const -{ - //returns a "sloppy" match, verifying that each list contains all the same - //items, though not necessarily in the same order. - - if (list1.size() != list2.size()) - return false; - - QStringList tempList(list2); - - //iterate each value in the list, removing one occurrence of the value in - //the other list. If no corresponding value is found, test fails - foreach (const QString &value, list1) - { - if (!tempList.contains(value)) - return false; - - tempList.removeOne(value); - } - return true; -} - -QList CSVSettings::View::toStandardItemList - (const QStringList &list) const -{ - QList itemList; - - foreach (const QString &value, list) - itemList.append (new QStandardItem (value)); - - return itemList; -} - -void CSVSettings::View::updateView (bool signalUpdate) const -{ - if (signalUpdate) - emit viewUpdated(viewKey(), selectedValues()); -} - -QString CSVSettings::View::value (int row) const -{ - if (row > -1 && row < mDataModel->rowCount()) - return mDataModel->data (mDataModel->index(row, 0)).toString(); - - return QString(); -} - -int CSVSettings::View::widgetWidth(int characterCount) const -{ - QString widthToken = QString().fill ('m', characterCount); - QFontMetrics fm (QApplication::font()); - - return (fm.width (widthToken)); -} diff --git a/apps/opencs/view/settings/view.hpp b/apps/opencs/view/settings/view.hpp deleted file mode 100644 index 84ad62759..000000000 --- a/apps/opencs/view/settings/view.hpp +++ /dev/null @@ -1,160 +0,0 @@ -#ifndef CSVSETTINGS_VIEW_HPP -#define CSVSETTINGS_VIEW_HPP - -#include -#include - -#include "frame.hpp" -#include "../../model/settings/support.hpp" - -class QGroupBox; -class QStringList; -class QStandardItem; -class QItemSelection; -class QAbstractItemModel; -class QItemSelectionModel; - -namespace CSMSettings { class Setting; } - -namespace CSVSettings -{ - class Page; - - class View : public Frame - { - Q_OBJECT - - ///Pointer to the owning Page instance - Page *mParentPage; - - ///Pointer to the selection model for the view - QItemSelectionModel *mSelectionModel; - - ///Pointer to the data model for the view's selection model - QAbstractItemModel *mDataModel; - - ///State indicating whether or not the setting has a pre-defined list - ///of values, limiting possible definitions - bool mHasFixedValues; - - ///State indicating whether the view will allow multiple values - bool mIsMultiValue; - - ///'pagename.settingname' form of the view's id - QString mViewKey; - - ///indicates whether or not the setting is written to file - bool mSerializable; - - public: - - explicit View (CSMSettings::Setting *setting, Page *parent); - - ///Returns the index / row of the passed value, -1 if not found. - int currentIndex () const; - - ///Returns the number of rows in the view's data model - int rowCount() const; - - ///Returns bool indicating the data in this view should / should not - ///be serialized to a config file - bool serializable() const { return mSerializable; } - - ///Returns a pointer to the view's owning parent page - const Page *parentPage() const { return mParentPage; } - - ///Returns the selected items in the selection model as a QStringList - QStringList selectedValues() const; - - ///Sets the selected items in the selection model based on passed list. - ///Bools allow opt-out of updating the view - ///or signaling the view was updatedto avoid viscious cylcing. - void setSelectedValues (const QStringList &values, - bool updateView = true, - bool signalUpdate = true) const; - - void setSelectedValue (const QString &value, - bool updateView = true, - bool signalUpdate = true); - - - ///Returns the value of the data model at the specified row - QString value (int row) const; - - QString viewKey() const { return mViewKey; } - - protected: - - /// Returns the model which provides data for the selection model - QAbstractItemModel *dataModel() { return mDataModel; } - - ///Accessor function for subclasses - bool isMultiValue() { return mIsMultiValue; } - - ///Returns the view selection model - QItemSelectionModel *selectionModel() { return mSelectionModel;} - - ///Global callback for basic view initialization - void showEvent ( QShowEvent * event ); - - ///Virtual for updating a specific View subclass - ///bool indicates whether viewUpdated() signal is emitted - virtual void updateView (bool signalUpdate = true) const; - - ///Returns the pixel width corresponding to the specified number of - ///characters. - int widgetWidth(int characterCount) const; - - private: - - ///Constructs the view layout - void buildView(); - - ///Constructs the data and selection models - void buildModel (const CSMSettings::Setting *setting); - - ///In cases where the view has a pre-defined list of possible values, - ///a QStringListModel is created using those values. - ///View changes operate on the selection model only. - void buildFixedValueModel (const QStringList &definitions); - - ///In cases where the view does not have a pre-defined list of possible - ///values, a QStandardItemModel is created, containing the actual - ///setting definitions. View changes first update the data in the - ///model to match the data in the view. The selection model always - ///selects all values. - void buildUpdatableValueModel (const QStringList &definitions); - - ///Refreshes the view - void refresh() const; - - ///Convenince function for selection model's select() method. Also - ///clears out the model beforehand to ensure complete selection. - void select (const QItemSelection &selection) const; - - ///Compares two string lists "loosely", ensuring that all values in - ///one list are contained entirely in the other, and that neither list - ///has more values than the other. List order is not considered. - bool stringListsMatch (const QStringList &list1, - const QStringList &list2) const; - - ///Converts a string list to a list of QStandardItem pointers. - QList toStandardItemList(const QStringList &) const; - - signals: - - ///Signals that the view has been changed. - void viewUpdated(const QString &, const QStringList &) const; - - }; - - class IViewFactory - { - public: - - ///Creation interface for view factories - virtual View *createView (CSMSettings::Setting *setting, - Page *parent) = 0; - }; -} -#endif // CSVSETTINGS_VIEW_HPP diff --git a/apps/opencs/view/world/recordstatusdelegate.cpp b/apps/opencs/view/world/recordstatusdelegate.cpp index 0aec13bcf..12d545339 100644 --- a/apps/opencs/view/world/recordstatusdelegate.cpp +++ b/apps/opencs/view/world/recordstatusdelegate.cpp @@ -4,7 +4,6 @@ #include #include -#include "../../model/settings/usersettings.hpp" #include "../../model/world/columns.hpp" CSVWorld::RecordStatusDelegate::RecordStatusDelegate(const ValueList& values, From d6bd2cb1f054a19de4a23f847e30847e5a5ad3d5 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 15 Dec 2015 14:51:25 +0100 Subject: [PATCH 2820/3725] changed name of openmw-cs user settings file --- CMakeLists.txt | 10 +++++----- apps/opencs/model/prefs/state.cpp | 4 ++-- files/{opencs.ini => openmw-cs.cfg} | 0 3 files changed, 7 insertions(+), 7 deletions(-) rename files/{opencs.ini => openmw-cs.cfg} (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index db8bcc4f7..fbae0e405 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -347,8 +347,8 @@ configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg.local configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg "${OpenMW_BINARY_DIR}/openmw.cfg.install") -configure_file(${OpenMW_SOURCE_DIR}/files/opencs.ini - "${OpenMW_BINARY_DIR}/opencs.ini") +configure_file(${OpenMW_SOURCE_DIR}/files/openmw-cs.cfg + "${OpenMW_BINARY_DIR}/openmw-cs.cfg") configure_file(${OpenMW_SOURCE_DIR}/files/opencs/defaultfilters "${OpenMW_BINARY_DIR}/resources/defaultfilters" COPYONLY) @@ -448,7 +448,7 @@ IF(NOT WIN32 AND NOT APPLE) INSTALL(FILES "${OpenMW_BINARY_DIR}/gamecontrollerdb.txt" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw") IF(BUILD_OPENCS) - INSTALL(FILES "${OpenMW_BINARY_DIR}/opencs.ini" DESTINATION "${SYSCONFDIR}" COMPONENT "opencs") + INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw-cs.cfg" DESTINATION "${SYSCONFDIR}" COMPONENT "opencs") ENDIF(BUILD_OPENCS) # Install resources @@ -481,7 +481,7 @@ if(WIN32) ENDIF(BUILD_ESSIMPORTER) IF(BUILD_OPENCS) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/openmw-cs.exe" DESTINATION ".") - INSTALL(FILES "${OpenMW_BINARY_DIR}/opencs.ini" DESTINATION ".") + INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw-cs.cfg" DESTINATION ".") ENDIF(BUILD_OPENCS) IF(BUILD_WIZARD) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/openmw-wizard.exe" DESTINATION ".") @@ -746,7 +746,7 @@ if (APPLE) install(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" RENAME "openmw.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) install(FILES "${OpenMW_BINARY_DIR}/settings-default.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) install(FILES "${OpenMW_BINARY_DIR}/gamecontrollerdb.txt" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) - install(FILES "${OpenMW_BINARY_DIR}/opencs.ini" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) + install(FILES "${OpenMW_BINARY_DIR}/openmw-cs.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) set(CPACK_GENERATOR "DragNDrop") set(CPACK_PACKAGE_VERSION ${OPENMW_VERSION}) diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index 738a50967..8b827d0a2 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -23,7 +23,7 @@ void CSMPrefs::State::load() else if (boost::filesystem::exists (global)) mSettings.loadDefault (global.string()); else - throw std::runtime_error ("No default settings file found! Make sure the file \"opencs.ini\" was properly installed."); + throw std::runtime_error ("No default settings file found! Make sure the file \"openmw-cs.cfg\" was properly installed."); // user settings file boost::filesystem::path user = mConfigurationManager.getUserConfigPath() / mConfigFile; @@ -329,7 +329,7 @@ void CSMPrefs::State::setDefault (const std::string& key, const std::string& def } CSMPrefs::State::State (const Files::ConfigurationManager& configurationManager) -: mConfigFile ("opencs.ini"), mConfigurationManager (configurationManager), +: mConfigFile ("openmw-cs.cfg"), mConfigurationManager (configurationManager), mCurrentCategory (mCategories.end()) { if (sThis) diff --git a/files/opencs.ini b/files/openmw-cs.cfg similarity index 100% rename from files/opencs.ini rename to files/openmw-cs.cfg From be19da189abfff78acc85fb9551cbf9a573fad38 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 15 Dec 2015 14:56:29 +0100 Subject: [PATCH 2821/3725] fixed user settings not being saved when last document window is closed while user settings window is still open --- apps/opencs/view/prefs/dialogue.cpp | 6 ++++++ apps/opencs/view/prefs/dialogue.hpp | 2 ++ 2 files changed, 8 insertions(+) diff --git a/apps/opencs/view/prefs/dialogue.cpp b/apps/opencs/view/prefs/dialogue.cpp index 97a36306f..f04092653 100644 --- a/apps/opencs/view/prefs/dialogue.cpp +++ b/apps/opencs/view/prefs/dialogue.cpp @@ -71,6 +71,12 @@ CSVPrefs::Dialogue::Dialogue() buildContentArea (main); } +CSVPrefs::Dialogue::~Dialogue() +{ + if (isVisible()) + CSMPrefs::State::get().save(); +} + void CSVPrefs::Dialogue::closeEvent (QCloseEvent *event) { QMainWindow::closeEvent (event); diff --git a/apps/opencs/view/prefs/dialogue.hpp b/apps/opencs/view/prefs/dialogue.hpp index 3965800db..fc66892c8 100644 --- a/apps/opencs/view/prefs/dialogue.hpp +++ b/apps/opencs/view/prefs/dialogue.hpp @@ -31,6 +31,8 @@ namespace CSVPrefs Dialogue(); + virtual ~Dialogue(); + protected: void closeEvent (QCloseEvent *event); From 6a749e77f291174eddc7783bf910760358ff8eee Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 15 Dec 2015 15:12:48 +0100 Subject: [PATCH 2822/3725] Fix crash when running out of sound sources --- apps/openmw/mwsound/soundmanagerimp.cpp | 38 ++++++++++++++++++------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index d1a90759b..220c6e885 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -410,10 +410,17 @@ namespace MWSound { MWBase::World *world = MWBase::Environment::get().getWorld(); const osg::Vec3f pos = world->getActorHeadTransform(ptr).getTrans(); - SoundLoudnessPair &old = mActiveSaySounds[ptr]; - if(old.first.get()) mOutput->finishStream(old.first); - old = std::make_pair(playVoice(decoder, pos, (ptr == MWMechanics::getPlayer())), - loudness); + + SaySoundMap::iterator oldIt = mActiveSaySounds.find(ptr); + if (oldIt != mActiveSaySounds.end()) + { + mOutput->finishStream(oldIt->second.first); + mActiveSaySounds.erase(oldIt); + } + + MWBase::SoundStreamPtr sound = playVoice(decoder, pos, (ptr == MWMechanics::getPlayer())); + + mActiveSaySounds.insert(std::make_pair(ptr, std::make_pair(sound, loudness))); } } catch(std::exception &e) @@ -452,9 +459,15 @@ namespace MWSound mPendingSaySounds[MWWorld::Ptr()] = std::make_pair(decoder, loudness); else { - SoundLoudnessPair &old = mActiveSaySounds[MWWorld::Ptr()]; - if(old.first.get()) mOutput->finishStream(old.first); - old = std::make_pair(playVoice(decoder, osg::Vec3f(), true), loudness); + SaySoundMap::iterator oldIt = mActiveSaySounds.find(MWWorld::Ptr()); + if (oldIt != mActiveSaySounds.end()) + { + mOutput->finishStream(oldIt->second.first); + mActiveSaySounds.erase(oldIt); + } + + mActiveSaySounds.insert(std::make_pair(MWWorld::Ptr(), + std::make_pair(playVoice(decoder, osg::Vec3f(), true), loudness))); } } catch(std::exception &e) @@ -908,8 +921,13 @@ namespace MWSound MWBase::SoundStreamPtr sound; MWWorld::Ptr ptr = penditer->first; - SoundLoudnessPair &old = mActiveSaySounds[ptr]; - if(old.first.get()) mOutput->finishStream(old.first); + SaySoundMap::iterator old = mActiveSaySounds.find(ptr); + if (old != mActiveSaySounds.end()) + { + mOutput->finishStream(old->second.first); + mActiveSaySounds.erase(old); + } + if(ptr == MWWorld::Ptr()) sound = playVoice(decoder, osg::Vec3f(), true); else @@ -918,7 +936,7 @@ namespace MWSound const osg::Vec3f pos = world->getActorHeadTransform(ptr).getTrans(); sound = playVoice(decoder, pos, (ptr == MWMechanics::getPlayer())); } - old = std::make_pair(sound, loudness); + mActiveSaySounds.insert(std::make_pair(ptr, std::make_pair(sound, loudness))); } catch(std::exception &e) { std::cerr<< "Sound Error: "< Date: Tue, 15 Dec 2015 19:32:42 +0100 Subject: [PATCH 2823/3725] CSMPrefs: fix deadlock in toColor() --- apps/opencs/model/prefs/setting.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/prefs/setting.cpp b/apps/opencs/model/prefs/setting.cpp index 89924ae29..75b58322d 100644 --- a/apps/opencs/model/prefs/setting.cpp +++ b/apps/opencs/model/prefs/setting.cpp @@ -71,7 +71,7 @@ bool CSMPrefs::Setting::isTrue() const QColor CSMPrefs::Setting::toColor() const { - QMutexLocker lock (mMutex); + // toString() handles lock return QColor (QString::fromUtf8 (toString().c_str())); } From 78a733a12c45b91233bf2dc5f0c120d2414dccfc Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 15 Dec 2015 20:13:41 +0100 Subject: [PATCH 2824/3725] Fix initialization of InputWrapper::mWindowHasFocus --- components/sdlutil/sdlinputwrapper.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/components/sdlutil/sdlinputwrapper.cpp b/components/sdlutil/sdlinputwrapper.cpp index 200d19bd8..647a65005 100644 --- a/components/sdlutil/sdlinputwrapper.cpp +++ b/components/sdlutil/sdlinputwrapper.cpp @@ -33,6 +33,10 @@ InputWrapper::InputWrapper(SDL_Window* window, osg::ref_ptr v mMouseInWindow(true) { _setupOISKeys(); + + Uint32 flags = SDL_GetWindowFlags(mSDLWindow); + mWindowHasFocus = (flags & SDL_WINDOW_INPUT_FOCUS); + mMouseInWindow = (flags & SDL_WINDOW_MOUSE_FOCUS); } InputWrapper::~InputWrapper() From 4af376133b9b825960a5cb0fb7cdd0a9c14087c1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 15 Dec 2015 20:41:00 +0100 Subject: [PATCH 2825/3725] Don't tick effects when duration is zero --- apps/openmw/mwmechanics/actors.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 185364fae..58fedf2fd 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -486,14 +486,17 @@ namespace MWMechanics bool wasDead = creatureStats.isDead(); - for (MagicEffects::Collection::const_iterator it = effects.begin(); it != effects.end(); ++it) + if (duration > 0) { - // tickable effects (i.e. effects having a lasting impact after expiry) - effectTick(creatureStats, ptr, it->first, it->second.getMagnitude() * duration); + for (MagicEffects::Collection::const_iterator it = effects.begin(); it != effects.end(); ++it) + { + // tickable effects (i.e. effects having a lasting impact after expiry) + effectTick(creatureStats, ptr, it->first, it->second.getMagnitude() * duration); - // instant effects are already applied on spell impact in spellcasting.cpp, but may also come from permanent abilities - CastSpell cast(ptr, ptr); - cast.applyInstantEffect(ptr, ptr, it->first, it->second.getMagnitude()); + // instant effects are already applied on spell impact in spellcasting.cpp, but may also come from permanent abilities + CastSpell cast(ptr, ptr); + cast.applyInstantEffect(ptr, ptr, it->first, it->second.getMagnitude()); + } } // attributes From 375caf037d48c1b401547cee5aa9dee972dd3600 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 15 Dec 2015 20:46:05 +0100 Subject: [PATCH 2826/3725] Don't applyInstantEffect when magnitude is zero --- apps/openmw/mwmechanics/actors.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 58fedf2fd..ed6ace57d 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -494,8 +494,11 @@ namespace MWMechanics effectTick(creatureStats, ptr, it->first, it->second.getMagnitude() * duration); // instant effects are already applied on spell impact in spellcasting.cpp, but may also come from permanent abilities - CastSpell cast(ptr, ptr); - cast.applyInstantEffect(ptr, ptr, it->first, it->second.getMagnitude()); + if (it->second.getMagnitude() > 0) + { + CastSpell cast(ptr, ptr); + cast.applyInstantEffect(ptr, ptr, it->first, it->second.getMagnitude()); + } } } From ccbba5e9266488ed161c9b8a57121c4bb3537d26 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 15 Dec 2015 20:52:23 +0100 Subject: [PATCH 2827/3725] LoadingScreen: remove indicateProgress, not used --- apps/openmw/mwgui/loadingscreen.cpp | 11 ----------- apps/openmw/mwgui/loadingscreen.hpp | 3 --- components/loadinglistener/loadinglistener.hpp | 3 --- 3 files changed, 17 deletions(-) diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index 321d5e664..56b4e75d0 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -224,17 +224,6 @@ namespace MWGui draw(); } - void LoadingScreen::indicateProgress() - { - float time = (static_cast(mTimer.time_m()) % 2001) / 1000.f; - if (time > 1) - time = (time-2)*-1; - - mProgressBar->setTrackSize(50); - mProgressBar->setScrollPosition(static_cast(time * (mProgressBar->getScrollRange() - 1))); - draw(); - } - bool LoadingScreen::needToDrawLoadingScreen() { if ( mTimer.time_m() <= mLastRenderTime + (1.0/mTargetFrameRate) * 1000.0) diff --git a/apps/openmw/mwgui/loadingscreen.hpp b/apps/openmw/mwgui/loadingscreen.hpp index f0f354223..d7a822ace 100644 --- a/apps/openmw/mwgui/loadingscreen.hpp +++ b/apps/openmw/mwgui/loadingscreen.hpp @@ -35,9 +35,6 @@ namespace MWGui 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(); diff --git a/components/loadinglistener/loadinglistener.hpp b/components/loadinglistener/loadinglistener.hpp index 558111b34..e9a8cd3c7 100644 --- a/components/loadinglistener/loadinglistener.hpp +++ b/components/loadinglistener/loadinglistener.hpp @@ -12,9 +12,6 @@ namespace Loading virtual void loadingOn() {} virtual void loadingOff() {} - /// Indicate that some progress has been made, without specifying how much - virtual void indicateProgress () {} - virtual void setProgressRange (size_t range) {} virtual void setProgress (size_t value) {} virtual void increaseProgress (size_t increase = 1) {} From 152f1d625d3b55058de5dd0c8582325083247698 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 15 Dec 2015 20:54:21 +0100 Subject: [PATCH 2828/3725] LoadingScreen: remove unused declarations --- apps/openmw/mwgui/loadingscreen.hpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/apps/openmw/mwgui/loadingscreen.hpp b/apps/openmw/mwgui/loadingscreen.hpp index d7a822ace..92a3d9355 100644 --- a/apps/openmw/mwgui/loadingscreen.hpp +++ b/apps/openmw/mwgui/loadingscreen.hpp @@ -44,9 +44,6 @@ namespace MWGui virtual void setVisible(bool visible); - void setLoadingProgress (const std::string& stage, int depth, int current, int total); - void loadingDone(); - private: void findSplashScreens(); bool needToDrawLoadingScreen(); From 625644e917ceadc7d61238089f1c849cf6636cbe Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 15 Dec 2015 21:03:56 +0100 Subject: [PATCH 2829/3725] LoadingScreen: documentation updates --- apps/openmw/mwgui/loadingscreen.hpp | 3 +-- components/loadinglistener/loadinglistener.hpp | 13 +++++++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwgui/loadingscreen.hpp b/apps/openmw/mwgui/loadingscreen.hpp index 92a3d9355..ce9f0f6dc 100644 --- a/apps/openmw/mwgui/loadingscreen.hpp +++ b/apps/openmw/mwgui/loadingscreen.hpp @@ -33,11 +33,10 @@ namespace MWGui LoadingScreen(const VFS::Manager* vfs, osgViewer::Viewer* viewer); virtual ~LoadingScreen(); + /// Overridden from Loading::Listener, see the Loading::Listener documentation for usage details virtual void setLabel (const std::string& label); - virtual void loadingOn(); virtual void loadingOff(); - virtual void setProgressRange (size_t range); virtual void setProgress (size_t value); virtual void increaseProgress (size_t increase=1); diff --git a/components/loadinglistener/loadinglistener.hpp b/components/loadinglistener/loadinglistener.hpp index e9a8cd3c7..04e50dd28 100644 --- a/components/loadinglistener/loadinglistener.hpp +++ b/components/loadinglistener/loadinglistener.hpp @@ -1,23 +1,32 @@ #ifndef COMPONENTS_LOADINGLISTENER_H #define COMPONENTS_LOADINGLISTENER_H +#include + namespace Loading { class Listener { public: + /// Set a text label to show on the loading screen. virtual void setLabel (const std::string& label) {} - // Use ScopedLoad instead of using these directly + /// Start a loading sequence. Must call loadingOff() when done. + /// @note To get the loading screen to actually update, you must call setProgress / increaseProgress periodically. + /// @note It is best to use the ScopedLoad object instead of using loadingOn()/loadingOff() directly, + /// so that the loading is exception safe. virtual void loadingOn() {} virtual void loadingOff() {} + /// Set the total range of progress (e.g. the number of objects to load). virtual void setProgressRange (size_t range) {} + /// Set current progress. Valid range is [0, progressRange) virtual void setProgress (size_t value) {} + /// Increase current progress, default by 1. virtual void increaseProgress (size_t increase = 1) {} }; - // Used for stopping a loading sequence when the object goes out of scope + /// @brief Used for stopping a loading sequence when the object goes out of scope struct ScopedLoad { ScopedLoad(Listener* l) : mListener(l) { mListener->loadingOn(); } From 67883feaae6ef15c3e537ebd0e4fee5bff6231e9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 15 Dec 2015 21:05:35 +0100 Subject: [PATCH 2830/3725] LoadingScreen: ensure values are within progress range --- apps/openmw/mwgui/loadingscreen.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index 56b4e75d0..e82d78bfe 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -209,6 +209,7 @@ namespace MWGui // skip expensive update if there isn't enough visible progress if (value - mProgress < mProgressBar->getScrollRange()/200.f) return; + value = std::min(value, mProgressBar->getScrollRange()-1); mProgress = value; mProgressBar->setScrollPosition(0); mProgressBar->setTrackSize(static_cast(value / (float)(mProgressBar->getScrollRange()) * mProgressBar->getLineSize())); @@ -219,6 +220,7 @@ namespace MWGui { mProgressBar->setScrollPosition(0); size_t value = mProgress + increase; + value = std::min(value, mProgressBar->getScrollRange()-1); mProgress = value; mProgressBar->setTrackSize(static_cast(value / (float)(mProgressBar->getScrollRange()) * mProgressBar->getLineSize())); draw(); From d5a2586f38029a7848bb55e3a44d365c5666de41 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 15 Dec 2015 21:14:25 +0100 Subject: [PATCH 2831/3725] LoadingScreen: add support for important labels Used in saveGame so the player can be sure whether or not the game was saved. Fixes #3074 --- apps/openmw/mwgui/loadingscreen.cpp | 18 +++++++++++++++++- apps/openmw/mwgui/loadingscreen.hpp | 4 +++- apps/openmw/mwstate/statemanagerimp.cpp | 2 +- components/loadinglistener/loadinglistener.hpp | 7 ++++++- 4 files changed, 27 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index e82d78bfe..e32140cb3 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -36,6 +36,7 @@ namespace MWGui , mLastWallpaperChangeTime(0.0) , mLastRenderTime(0.0) , mLoadingOnTime(0.0) + , mImportantLabel(false) , mProgress(0) { mMainWidget->setSize(MyGUI::RenderManager::getInstance().getViewSize()); @@ -82,8 +83,10 @@ namespace MWGui std::cerr << "No splash screens found!" << std::endl; } - void LoadingScreen::setLabel(const std::string &label) + void LoadingScreen::setLabel(const std::string &label, bool important) { + mImportantLabel = important; + mLoadingText->setCaptionWithReplacing(label); int padding = mLoadingBox->getWidth() - mLoadingText->getWidth(); MyGUI::IntSize size(mLoadingText->getTextSize().width+padding, mLoadingBox->getHeight()); @@ -176,6 +179,19 @@ namespace MWGui void LoadingScreen::loadingOff() { + if (mLastRenderTime < mLoadingOnTime) + { + // the loading was so fast that we didn't show loading screen at all + // we may still want to show the label if the caller requested it + if (mImportantLabel) + { + MWBase::Environment::get().getWindowManager()->messageBox(mLoadingText->getCaption()); + mImportantLabel = false; + } + } + else + mImportantLabel = false; // label was already shown on loading screen + //std::cout << "loading took " << mTimer.time_m() - mLoadingOnTime << std::endl; setVisible(false); diff --git a/apps/openmw/mwgui/loadingscreen.hpp b/apps/openmw/mwgui/loadingscreen.hpp index ce9f0f6dc..a7f7d3619 100644 --- a/apps/openmw/mwgui/loadingscreen.hpp +++ b/apps/openmw/mwgui/loadingscreen.hpp @@ -34,7 +34,7 @@ namespace MWGui virtual ~LoadingScreen(); /// Overridden from Loading::Listener, see the Loading::Listener documentation for usage details - virtual void setLabel (const std::string& label); + virtual void setLabel (const std::string& label, bool important); virtual void loadingOn(); virtual void loadingOff(); virtual void setProgressRange (size_t range); @@ -57,6 +57,8 @@ namespace MWGui osg::Timer mTimer; double mLoadingOnTime; + bool mImportantLabel; + size_t mProgress; MyGUI::Widget* mLoadingBox; diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index b5426bc77..9931cf967 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -242,7 +242,7 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot Loading::Listener& listener = *MWBase::Environment::get().getWindowManager()->getLoadingScreen(); // Using only Cells for progress information, since they typically have the largest records by far listener.setProgressRange(MWBase::Environment::get().getWorld()->countSavedGameCells()); - listener.setLabel("#{sNotifyMessage4}"); + listener.setLabel("#{sNotifyMessage4}", true); Loading::ScopedLoad load(&listener); diff --git a/components/loadinglistener/loadinglistener.hpp b/components/loadinglistener/loadinglistener.hpp index 04e50dd28..1d48cce0b 100644 --- a/components/loadinglistener/loadinglistener.hpp +++ b/components/loadinglistener/loadinglistener.hpp @@ -9,7 +9,12 @@ namespace Loading { public: /// Set a text label to show on the loading screen. - virtual void setLabel (const std::string& label) {} + /// @param label The label + /// @param important Is the label considered important to show? + /// @note "non-important" labels may not show on screen if the loading process went so fast + /// that the implementation decided not to show a loading screen at all. "important" labels + /// will show in a separate message-box if the loading screen was not shown. + virtual void setLabel (const std::string& label, bool important=false) {} /// Start a loading sequence. Must call loadingOff() when done. /// @note To get the loading screen to actually update, you must call setProgress / increaseProgress periodically. From 8222c78cf2ac202970122832bc5fa4da07db8a20 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 16 Dec 2015 01:30:04 +0100 Subject: [PATCH 2832/3725] Do not filter creature dialogue by NPC-only conditions (Fixes #3086) --- apps/openmw/mwdialogue/filter.cpp | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index d41820b71..084941b46 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -41,7 +41,7 @@ bool MWDialogue::Filter::testActor (const ESM::DialInfo& info) const if (!info.mRace.empty()) { if (isCreature) - return false; + return true; MWWorld::LiveCellRef *cellRef = mActor.get(); @@ -53,7 +53,7 @@ bool MWDialogue::Filter::testActor (const ESM::DialInfo& info) const if (!info.mClass.empty()) { if (isCreature) - return false; + return true; MWWorld::LiveCellRef *cellRef = mActor.get(); @@ -65,7 +65,7 @@ bool MWDialogue::Filter::testActor (const ESM::DialInfo& info) const if (!info.mFaction.empty()) { if (isCreature) - return false; + return true; if (!Misc::StringUtils::ciEqual(mActor.getClass().getPrimaryFaction(mActor), info.mFaction)) return false; @@ -77,7 +77,7 @@ bool MWDialogue::Filter::testActor (const ESM::DialInfo& info) const else if (info.mData.mRank != -1) { if (isCreature) - return false; + return true; // Rank requirement, but no faction given. Use the actor's faction, if there is one. // check rank @@ -156,10 +156,8 @@ bool MWDialogue::Filter::testSelectStruct (const SelectWrapper& select) const { if (select.isNpcOnly() && (mActor.getTypeName() != typeid (ESM::NPC).name())) // If the actor is a creature, we do not test the conditions applicable - // only to NPCs. Such conditions can never be satisfied, apart - // inverted ones (NotClass, NotRace, NotFaction return true - // because creatures are not of any race, class or faction). - return select.getType() == SelectWrapper::Type_Inverted; + // only to NPCs. + return true; switch (select.getType()) { From 31c33247054cfacb65e0904feccfe291f1c872a2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 17 Dec 2015 03:04:36 +0100 Subject: [PATCH 2833/3725] Don't assume the emitter node is a Group (Fixes #3082) This would be a correct assumption by default, but is no longer true when the NifLoader::optimize() function optimizes the graph. --- apps/openmw/mwphysics/physicssystem.cpp | 2 +- components/nifosg/nifloader.cpp | 2 +- components/nifosg/particle.cpp | 12 ++++++++---- components/nifosg/particle.hpp | 7 ++++--- 4 files changed, 14 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index eebfddaab..7b4b93678 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -580,7 +580,7 @@ namespace MWPhysics int recIndex = it->first; int shapeIndex = it->second; - NifOsg::FindRecIndexVisitor visitor(recIndex); + NifOsg::FindGroupByRecIndex visitor(recIndex); mPtr.getRefData().getBaseNode()->accept(visitor); if (!visitor.mFound) { diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 0489e07e6..9a017a497 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -887,7 +887,7 @@ namespace NifOsg // This seems to be true for all NIF files in the game that I've checked, suggesting that NIFs work similar to OSG with regards to update order. // If something ever violates this assumption, the worst that could happen is the culling being one frame late, which wouldn't be a disaster. - FindRecIndexVisitor find (partctrl->emitter->recIndex); + FindGroupByRecIndex find (partctrl->emitter->recIndex); rootNode->accept(find); if (!find.mFound) { diff --git a/components/nifosg/particle.cpp b/components/nifosg/particle.cpp index e3162bcd9..500339722 100644 --- a/components/nifosg/particle.cpp +++ b/components/nifosg/particle.cpp @@ -276,7 +276,7 @@ void Emitter::emitParticles(double dt) int randomRecIndex = mTargets[(std::rand() / (static_cast(RAND_MAX)+1.0)) * mTargets.size()]; // we could use a map here for faster lookup - FindRecIndexVisitor visitor(randomRecIndex); + FindGroupByRecIndex visitor(randomRecIndex); getParent(0)->accept(visitor); if (!visitor.mFound) @@ -306,21 +306,25 @@ void Emitter::emitParticles(double dt) } } -FindRecIndexVisitor::FindRecIndexVisitor(int recIndex) +FindGroupByRecIndex::FindGroupByRecIndex(int recIndex) : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) , mFound(NULL) , mRecIndex(recIndex) { } -void FindRecIndexVisitor::apply(osg::Node &searchNode) +void FindGroupByRecIndex::apply(osg::Node &searchNode) { if (searchNode.getUserDataContainer() && searchNode.getUserDataContainer()->getNumUserObjects()) { NodeUserData* holder = dynamic_cast(searchNode.getUserDataContainer()->getUserObject(0)); if (holder && holder->mIndex == mRecIndex) { - mFound = static_cast(&searchNode); + osg::Group* group = searchNode.asGroup(); + if (!group) + group = searchNode.getParent(0); + + mFound = group; mFoundPath = getNodePath(); return; } diff --git a/components/nifosg/particle.hpp b/components/nifosg/particle.hpp index d86408254..a1ed3f3d0 100644 --- a/components/nifosg/particle.hpp +++ b/components/nifosg/particle.hpp @@ -172,11 +172,12 @@ namespace NifOsg osg::Vec3f mCachedWorldDirection; }; - // NodeVisitor to find a child node with the given record index, stored in the node's user data container. - class FindRecIndexVisitor : public osg::NodeVisitor + // NodeVisitor to find a Group node with the given record index, stored in the node's user data container. + // Alternatively, returns the node's parent Group if that node is not a Group (i.e. a leaf node). + class FindGroupByRecIndex : public osg::NodeVisitor { public: - FindRecIndexVisitor(int recIndex); + FindGroupByRecIndex(int recIndex); virtual void apply(osg::Node &searchNode); From 0731595c2bce8cbbf0f425f87e9697c6e436c6e9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 17 Dec 2015 03:38:38 +0100 Subject: [PATCH 2834/3725] Wrap a Texture2D in a ref_ptr --- components/nifosg/nifloader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 9a017a497..98512ca5c 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -1364,7 +1364,7 @@ namespace NifOsg int wrapT = (clamp) & 0x1; int wrapS = (clamp >> 1) & 0x1; - osg::Texture2D* texture2d = textureManager->getTexture2D(filename, + osg::ref_ptr texture2d = textureManager->getTexture2D(filename, wrapS ? osg::Texture::REPEAT : osg::Texture::CLAMP, wrapT ? osg::Texture::REPEAT : osg::Texture::CLAMP); From 0a723ab075ab79cff041d6fed5fa0aeaa9687630 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 17 Dec 2015 03:48:11 +0100 Subject: [PATCH 2835/3725] Animation: do not assume the object root is a Group --- apps/openmw/mwrender/animation.cpp | 33 ++++++++++++++++++------------ apps/openmw/mwrender/animation.hpp | 2 +- 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index c285ba434..114c1a5db 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -975,20 +975,27 @@ namespace MWRender mAccumCtrl = NULL; if (!forceskeleton) - mObjectRoot = mResourceSystem->getSceneManager()->createInstance(model, mInsert); + { + osg::ref_ptr created = mResourceSystem->getSceneManager()->createInstance(model, mInsert); + mObjectRoot = created->asGroup(); + if (!mObjectRoot) + { + mObjectRoot = new osg::Group; + mObjectRoot->addChild(created); + } + } else { - osg::ref_ptr newObjectRoot = mResourceSystem->getSceneManager()->createInstance(model); - mSkeleton = dynamic_cast(newObjectRoot.get()); - if (!mSkeleton) + osg::ref_ptr created = mResourceSystem->getSceneManager()->createInstance(model); + osg::ref_ptr skel = dynamic_cast(created.get()); + if (!skel) { - osg::ref_ptr skel = new SceneUtil::Skeleton; - mSkeleton = skel.get(); - skel->addChild(newObjectRoot); - newObjectRoot = skel; + skel = new SceneUtil::Skeleton; + skel->addChild(created); } - mInsert->addChild(newObjectRoot); - mObjectRoot = newObjectRoot; + mSkeleton = skel.get(); + mObjectRoot = skel; + mInsert->addChild(mObjectRoot); } if (previousStateset) @@ -1017,17 +1024,17 @@ namespace MWRender osg::Group* Animation::getObjectRoot() { - return static_cast(mObjectRoot.get()); + return mObjectRoot.get(); } osg::Group* Animation::getOrCreateObjectRoot() { if (mObjectRoot) - return static_cast(mObjectRoot.get()); + return mObjectRoot.get(); mObjectRoot = new osg::Group; mInsert->addChild(mObjectRoot); - return static_cast(mObjectRoot.get()); + return mObjectRoot.get(); } void Animation::addGlow(osg::ref_ptr node, osg::Vec4f glowColor) diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 04df10a38..213e33f67 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -208,7 +208,7 @@ protected: osg::ref_ptr mInsert; - osg::ref_ptr mObjectRoot; + osg::ref_ptr mObjectRoot; SceneUtil::Skeleton* mSkeleton; // The node expected to accumulate movement during movement animations. From fce43854bc7e8e1003a42d0568561ee1f5c74de3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 17 Dec 2015 03:49:18 +0100 Subject: [PATCH 2836/3725] Fix last commit --- apps/openmw/mwrender/animation.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 114c1a5db..85eefb329 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -980,8 +980,10 @@ namespace MWRender mObjectRoot = created->asGroup(); if (!mObjectRoot) { + mInsert->removeChild(created); mObjectRoot = new osg::Group; mObjectRoot->addChild(created); + mInsert->addChild(mObjectRoot); } } else From 723c392a73d918f0de7d0a5d455aa76df6eb459f Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 17 Dec 2015 04:05:39 +0100 Subject: [PATCH 2837/3725] NifLoader: fall back to the first UV set when encountering invalid UV set references --- components/nifosg/nifloader.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 98512ca5c..5c28bbc7e 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -963,7 +963,9 @@ namespace NifOsg int uvSet = *it; if (uvSet >= (int)data->uvlist.size()) { - std::cerr << "Warning: using an undefined UV set " << uvSet << " on TriShape \"" << triShape->name << "\" in " << mFilename << std::endl; + std::cerr << "Warning: out of bounds UV set " << uvSet << " on TriShape \"" << triShape->name << "\" in " << mFilename << std::endl; + if (data->uvlist.size()) + geometry->setTexCoordArray(textureStage, data->uvlist[0]); continue; } From 6b626c29545a83ffd21b5b3b1609655792dd8265 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 17 Dec 2015 13:06:37 +0100 Subject: [PATCH 2838/3725] spelling fixes --- apps/opencs/model/world/tablemimedata.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/world/tablemimedata.cpp b/apps/opencs/model/world/tablemimedata.cpp index 101bbf9ba..1268a7389 100644 --- a/apps/opencs/model/world/tablemimedata.cpp +++ b/apps/opencs/model/world/tablemimedata.cpp @@ -179,7 +179,7 @@ CSMWorld::UniversalId CSMWorld::TableMimeData::returnMatching (CSMWorld::Univers } } - throw std::runtime_error ("TableMimeData object does not hold object of the seeked type"); + throw std::runtime_error ("TableMimeData object does not hold object of the sought type"); } CSMWorld::UniversalId CSMWorld::TableMimeData::returnMatching (CSMWorld::ColumnBase::Display type) const @@ -201,7 +201,7 @@ CSMWorld::UniversalId CSMWorld::TableMimeData::returnMatching (CSMWorld::ColumnB } } - throw std::runtime_error ("TableMimeData object does not hold object of the seeked type"); + throw std::runtime_error ("TableMimeData object does not hold object of the sought type"); } bool CSMWorld::TableMimeData::fromDocument (const CSMDoc::Document& document) const From d6bcb7906de20ca78869de3c96252ecefafb33b5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 17 Dec 2015 16:10:55 +0100 Subject: [PATCH 2839/3725] Fix crash in a warning message --- apps/openmw/mwworld/cellstore.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 164ce5533..f8d53bbd9 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -810,19 +810,21 @@ namespace MWWorld if (!visitor.mFound) { - std::cout << "Dropping moved ref tag for " << visitor.mFound->mRef.getRefId() << " (moved object no longer exists)" << std::endl; + std::cerr << "Dropping moved ref tag for " << refnum.mIndex << " (moved object no longer exists)" << std::endl; continue; } + MWWorld::LiveCellRefBase* movedRef = visitor.mFound; + CellStore* otherCell = callback->getCellStore(movedTo); if (otherCell == NULL) { - std::cerr << "Dropping moved ref tag for " << visitor.mFound->mRef.getRefId() + std::cerr << "Dropping moved ref tag for " << movedRef->mRef.getRefId() << " (target cell " << movedTo.mWorldspace << " no longer exists). Reference moved back to its original location." << std::endl; // Note by dropping tag the object will automatically re-appear in its original cell, though potentially at inapproriate coordinates. // Restore original coordinates: - visitor.mFound->mData.setPosition(visitor.mFound->mRef.getPosition()); + movedRef->mData.setPosition(movedRef->mRef.getPosition()); continue; } @@ -833,7 +835,7 @@ namespace MWWorld continue; } - moveTo(MWWorld::Ptr(visitor.mFound, this), otherCell); + moveTo(MWWorld::Ptr(movedRef, this), otherCell); } updateMergedRefs(); From 689dea4cb3ab2bf34e31a437cbb7452ade929956 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 16 Dec 2015 19:33:39 +0100 Subject: [PATCH 2840/3725] Add instant spell effects to the actor's magic effect list Via http://forum.openmw.org/viewtopic.php?f=2&t=3212&start=20#p36208 --- apps/openmw/mwmechanics/actors.cpp | 7 ++- apps/openmw/mwmechanics/spellcasting.cpp | 74 +++++++++++++----------- apps/openmw/mwworld/inventorystore.cpp | 5 -- 3 files changed, 46 insertions(+), 40 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index ed6ace57d..ee114dff2 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -497,7 +497,12 @@ namespace MWMechanics if (it->second.getMagnitude() > 0) { CastSpell cast(ptr, ptr); - cast.applyInstantEffect(ptr, ptr, it->first, it->second.getMagnitude()); + if (cast.applyInstantEffect(ptr, ptr, it->first, it->second.getMagnitude())) + { + creatureStats.getActiveSpells().purgeEffect(it->first.mId); + if (ptr.getClass().hasInventoryStore(ptr)) + ptr.getClass().getInventoryStore(ptr).purgeEffect(it->first.mId); + } } } } diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index a2d32b324..ab8784beb 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -452,42 +452,18 @@ namespace MWMechanics float magnitude = effectIt->mMagnMin + (effectIt->mMagnMax - effectIt->mMagnMin) * random; magnitude *= magnitudeMult; - bool hasDuration = !(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration); - if (target.getClass().isActor() && hasDuration && effectIt->mDuration > 0) + if (!target.getClass().isActor()) { - ActiveSpells::ActiveEffect effect; - effect.mEffectId = effectIt->mEffectID; - effect.mArg = MWMechanics::EffectKey(*effectIt).mArg; - effect.mDuration = static_cast(effectIt->mDuration); - effect.mMagnitude = magnitude; - - targetEffects.add(MWMechanics::EffectKey(*effectIt), MWMechanics::EffectParam(effect.mMagnitude)); - - appliedLastingEffects.push_back(effect); - - // For absorb effects, also apply the effect to the caster - but with a negative - // magnitude, since we're transfering stats from the target to the caster - if (!caster.isEmpty() && caster.getClass().isActor()) - { - for (int i=0; i<5; ++i) - { - if (effectIt->mEffectID == ESM::MagicEffect::AbsorbAttribute+i) - { - std::vector effects; - ActiveSpells::ActiveEffect effect_ = effect; - effect_.mMagnitude *= -1; - effects.push_back(effect_); - // Also make sure to set casterActorId = target, so that the effect on the caster gets purged when the target dies - caster.getClass().getCreatureStats(caster).getActiveSpells().addSpell("", true, - effects, mSourceName, target.getClass().getCreatureStats(target).getActorId()); - } - } - } + // non-actor objects have no list of active magic effects, so have to apply instantly + if (!applyInstantEffect(target, caster, EffectKey(*effectIt), magnitude)) + continue; } - else + else // target.getClass().isActor() == true { - if (hasDuration && target.getClass().isActor()) + bool hasDuration = !(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration); + if (hasDuration && effectIt->mDuration == 0) { + // duration 0 means apply full magnitude instantly bool wasDead = target.getClass().getCreatureStats(target).isDead(); effectTick(target.getClass().getCreatureStats(target), target, EffectKey(*effectIt), magnitude); bool isDead = target.getClass().getCreatureStats(target).isDead(); @@ -495,8 +471,38 @@ namespace MWMechanics if (!wasDead && isDead) MWBase::Environment::get().getMechanicsManager()->actorKilled(target, caster); } - else if (!applyInstantEffect(target, caster, EffectKey(*effectIt), magnitude)) - continue; + else + { + // add to list of active effects, to apply in next frame + ActiveSpells::ActiveEffect effect; + effect.mEffectId = effectIt->mEffectID; + effect.mArg = MWMechanics::EffectKey(*effectIt).mArg; + effect.mDuration = static_cast(effectIt->mDuration); + effect.mMagnitude = magnitude; + + targetEffects.add(MWMechanics::EffectKey(*effectIt), MWMechanics::EffectParam(effect.mMagnitude)); + + appliedLastingEffects.push_back(effect); + + // For absorb effects, also apply the effect to the caster - but with a negative + // magnitude, since we're transfering stats from the target to the caster + if (!caster.isEmpty() && caster.getClass().isActor()) + { + for (int i=0; i<5; ++i) + { + if (effectIt->mEffectID == ESM::MagicEffect::AbsorbAttribute+i) + { + std::vector effects; + ActiveSpells::ActiveEffect effect_ = effect; + effect_.mMagnitude *= -1; + effects.push_back(effect_); + // Also make sure to set casterActorId = target, so that the effect on the caster gets purged when the target dies + caster.getClass().getCreatureStats(caster).getActiveSpells().addSpell("", true, + effects, mSourceName, target.getClass().getCreatureStats(target).getActorId()); + } + } + } + } } // Re-casting a summon effect will remove the creature from previous castings of that effect. diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index ebba4ae30..da591487e 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -410,11 +410,6 @@ void MWWorld::InventoryStore::updateMagicEffects(const Ptr& actor) // the items should appear as if they'd always been equipped. mListener->permanentEffectAdded(magicEffect, !mFirstAutoEquip, !mFirstAutoEquip && effectIt == enchantment.mEffects.mList.begin()); - - // Apply instant effects - MWMechanics::CastSpell cast(actor, actor); - if (magnitude) - cast.applyInstantEffect(actor, actor, effectIt->mEffectID, magnitude); } if (magnitude) From deb7f3caf64f2f3d3ef1b4d80b82d3d4d4ca71f0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 17 Dec 2015 20:15:44 +0100 Subject: [PATCH 2841/3725] Print deletion state in ObjectReferenceInfo --- apps/openmw/mwscript/miscextensions.cpp | 5 +++++ components/compiler/extensions0.cpp | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 8375cf8ae..9c63511b2 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -1051,6 +1051,11 @@ namespace MWScript msg << "RefNum: " << ptr.getCellRef().getRefNum().mIndex << std::endl; } + if (ptr.getRefData().isDeletedByContentFile()) + msg << "[Deleted by content file]" << std::endl; + if (!ptr.getRefData().getCount()) + msg << "[Deleted]" << std::endl; + msg << "RefID: " << ptr.getCellRef().getRefId() << std::endl; if (ptr.isInCell()) diff --git a/components/compiler/extensions0.cpp b/components/compiler/extensions0.cpp index 6e65c3183..8f7650191 100644 --- a/components/compiler/extensions0.cpp +++ b/components/compiler/extensions0.cpp @@ -310,7 +310,7 @@ namespace Compiler extensions.registerFunction ("getpctraveling", 'l', "", opcodeGetPcTraveling); extensions.registerInstruction ("betacomment", "/S", opcodeBetaComment, opcodeBetaCommentExplicit); extensions.registerInstruction ("bc", "/S", opcodeBetaComment, opcodeBetaCommentExplicit); - extensions.registerInstruction ("ori", "/S", opcodeBetaComment, opcodeBetaCommentExplicit); + extensions.registerInstruction ("ori", "/S", opcodeBetaComment, opcodeBetaCommentExplicit); // 'ori' stands for 'ObjectReferenceInfo' extensions.registerInstruction ("addtolevcreature", "ccl", opcodeAddToLevCreature); extensions.registerInstruction ("removefromlevcreature", "ccl", opcodeRemoveFromLevCreature); extensions.registerInstruction ("addtolevitem", "ccl", opcodeAddToLevItem); From e564c2631494b5f52b673cdbc18672c386b56fb4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 17 Dec 2015 20:17:53 +0100 Subject: [PATCH 2842/3725] Fix deleted objects being accessible in the Cells cache --- apps/openmw/mwworld/cells.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/cells.cpp b/apps/openmw/mwworld/cells.cpp index 109447959..11b76df4e 100644 --- a/apps/openmw/mwworld/cells.cpp +++ b/apps/openmw/mwworld/cells.cpp @@ -173,7 +173,7 @@ MWWorld::Ptr MWWorld::Cells::getPtr (const std::string& name, CellStore& cell, Ptr ptr = cell.search (name); - if (!ptr.isEmpty()) + if (!ptr.isEmpty() && ptr.getRefData().getCount()) return ptr; if (searchInContainers) From 04b6571d7dd359ee5da25b8a4fe5c17857fefd48 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 17 Dec 2015 20:34:50 +0100 Subject: [PATCH 2843/3725] Fix logic for scripting access of deleted objects --- apps/openmw/mwworld/cellreflist.hpp | 11 ----------- apps/openmw/mwworld/cells.cpp | 2 +- apps/openmw/mwworld/cellstore.hpp | 15 ++++++++++++--- 3 files changed, 13 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwworld/cellreflist.hpp b/apps/openmw/mwworld/cellreflist.hpp index 49197d167..4d503dcc8 100644 --- a/apps/openmw/mwworld/cellreflist.hpp +++ b/apps/openmw/mwworld/cellreflist.hpp @@ -24,17 +24,6 @@ namespace MWWorld /// all methods are known. void load (ESM::CellRef &ref, bool deleted, const MWWorld::ESMStore &esmStore); - LiveRef *find (const std::string& name) - { - for (typename List::iterator iter (mList.begin()); iter!=mList.end(); ++iter) - if (!iter->mData.isDeletedByContentFile() - && (iter->mRef.hasContentFile() || iter->mData.getCount() > 0) - && iter->mRef.getRefId() == name) - return &*iter; - - return 0; - } - LiveRef &insert (const LiveRef &item) { mList.push_back(item); diff --git a/apps/openmw/mwworld/cells.cpp b/apps/openmw/mwworld/cells.cpp index 11b76df4e..75d908db8 100644 --- a/apps/openmw/mwworld/cells.cpp +++ b/apps/openmw/mwworld/cells.cpp @@ -173,7 +173,7 @@ MWWorld::Ptr MWWorld::Cells::getPtr (const std::string& name, CellStore& cell, Ptr ptr = cell.search (name); - if (!ptr.isEmpty() && ptr.getRefData().getCount()) + if (!ptr.isEmpty() && MWWorld::CellStore::isAccessible(ptr.getRefData(), ptr.getCellRef())) return ptr; if (searchInContainers) diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index 5d1685c28..8f37b6681 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -122,7 +122,7 @@ namespace MWWorld for (typename List::List::iterator iter (list.mList.begin()); iter!=list.mList.end(); ++iter) { - if (iter->mData.isDeletedByContentFile()) + if (!isAccessible(iter->mData, iter->mRef)) continue; if (!visitor (MWWorld::Ptr(&*iter, this))) return false; @@ -164,6 +164,15 @@ namespace MWWorld public: + /// Should this reference be accessible to the outside world (i.e. to scripts / game logic)? + /// Determined based on the deletion flags. By default, objects deleted by content files are never accessible; + /// objects deleted by setCount(0) are still accessible *if* they came from a content file (needed for vanilla + /// scripting compatibility, and the fact that objects may be "un-deleted" in the original game). + static bool isAccessible(const MWWorld::RefData& refdata, const MWWorld::CellRef& cref) + { + return !refdata.isDeletedByContentFile() && (cref.hasContentFile() || refdata.getCount() > 0); + } + /// Moves object from this cell to the given cell. /// @note automatically updates given cell by calling cellToMoveTo->moveFrom(...) /// @note throws exception if cellToMoveTo == this @@ -239,7 +248,7 @@ namespace MWWorld for (unsigned int i=0; imData.isDeletedByContentFile()) + if (!isAccessible(mMergedRefs[i]->mData, mMergedRefs[i]->mRef)) continue; if (!visitor(MWWorld::Ptr(mMergedRefs[i], this))) @@ -267,7 +276,7 @@ namespace MWWorld LiveCellRefBase* base = &*it; if (mMovedToAnotherCell.find(base) != mMovedToAnotherCell.end()) continue; - if (base->mData.isDeletedByContentFile()) + if (!isAccessible(base->mData, base->mRef)) continue; if (!visitor(MWWorld::Ptr(base, this))) return false; From 2fe2f53b02a36f2d2aff2d510b63228ac7c29e03 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 17 Dec 2015 22:37:18 +0100 Subject: [PATCH 2844/3725] Set the changed flag in CellStore::search (Fixes #3089) --- apps/openmw/mwworld/cellstore.cpp | 15 ++++++++++----- apps/openmw/mwworld/cellstore.hpp | 6 ++++++ apps/openmw/mwworld/refdata.cpp | 14 ++++++++++---- apps/openmw/mwworld/worldimp.cpp | 2 +- 4 files changed, 27 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index f8d53bbd9..2429a83a7 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -347,7 +347,7 @@ namespace MWWorld return std::binary_search (mIds.begin(), mIds.end(), id); /// \todo address const-issues - return const_cast (this)->search (id).isEmpty(); + return searchConst (id).isEmpty(); } struct SearchVisitor @@ -367,16 +367,21 @@ namespace MWWorld Ptr CellStore::search (const std::string& id) { - bool oldState = mHasState; - SearchVisitor searchVisitor; searchVisitor.mIdToFind = id; forEach(searchVisitor); - - mHasState = oldState; return searchVisitor.mFound; } + Ptr CellStore::searchConst (const std::string& id) const + { + bool oldState = mHasState; + /// \todo address const-issues + Ptr result = const_cast(this)->search(id); + const_cast(this)->mHasState = oldState; + return result; + } + Ptr CellStore::searchViaActorId (int id) { if (Ptr ptr = ::searchViaActorId (mNpcs, id, this, mMovedToAnotherCell)) diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index 8f37b6681..7047682fa 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -212,6 +212,12 @@ namespace MWWorld Ptr search (const std::string& id); ///< Will return an empty Ptr if cell is not loaded. Does not check references in /// containers. + /// @note Triggers CellStore hasState flag. + + Ptr searchConst (const std::string& id) const; + ///< Will return an empty Ptr if cell is not loaded. Does not check references in + /// containers. + /// @note Does not trigger CellStore hasState flag. Do not modify the returned Ptr! Ptr searchViaActorId (int id); ///< Will return an empty Ptr if cell is not loaded. diff --git a/apps/openmw/mwworld/refdata.cpp b/apps/openmw/mwworld/refdata.cpp index 56abba165..f20e104e7 100644 --- a/apps/openmw/mwworld/refdata.cpp +++ b/apps/openmw/mwworld/refdata.cpp @@ -166,14 +166,20 @@ namespace MWWorld void RefData::enable() { - mChanged = !mEnabled; - mEnabled = true; + if (!mEnabled) + { + mChanged = true; + mEnabled = true; + } } void RefData::disable() { - mChanged = mEnabled; - mEnabled = false; + if (mEnabled) + { + mChanged = true; + mEnabled = false; + } } void RefData::setPosition(const ESM::Position& pos) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index c9971c6f0..0969df6ca 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2828,7 +2828,7 @@ namespace MWWorld checkedCells.insert( *i ); if ( !next ) continue; - closestMarker = next->search( id ); + closestMarker = next->searchConst( id ); if ( !closestMarker.isEmpty() ) { return closestMarker; From c9d02c67c0664eac8dfbd7d8b92b57641426506f Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 17 Dec 2015 23:33:31 +0100 Subject: [PATCH 2845/3725] Remove unneeded const_cast in TerrainStorage --- apps/openmw/mwrender/terrainstorage.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/terrainstorage.cpp b/apps/openmw/mwrender/terrainstorage.cpp index a98084709..ed1d8b677 100644 --- a/apps/openmw/mwrender/terrainstorage.cpp +++ b/apps/openmw/mwrender/terrainstorage.cpp @@ -20,7 +20,7 @@ namespace MWRender MWWorld::Store::iterator it = esmStore.get().begin(); for (; it != esmStore.get().end(); ++it) { - ESM::Land* land = const_cast(&*it); // TODO: fix store interface + const ESM::Land* land = &*it; land->loadData(ESM::Land::DATA_VCLR|ESM::Land::DATA_VHGT|ESM::Land::DATA_VNML|ESM::Land::DATA_VTEX); } } From d4eba794c387521af6919b5ddd83e2027b58f140 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 17 Dec 2015 23:34:52 +0100 Subject: [PATCH 2846/3725] Add ConstPtr --- apps/openmw/mwworld/ptr.cpp | 22 ++++++++++ apps/openmw/mwworld/ptr.hpp | 81 +++++++++++++++++++++++++++++++++++++ 2 files changed, 103 insertions(+) diff --git a/apps/openmw/mwworld/ptr.cpp b/apps/openmw/mwworld/ptr.cpp index 4d74c3c58..3f2ef80b6 100644 --- a/apps/openmw/mwworld/ptr.cpp +++ b/apps/openmw/mwworld/ptr.cpp @@ -52,3 +52,25 @@ MWWorld::Ptr::operator const void *() { return mRef; } + +// ------------------------------------------------------------------------------- + +const std::string &MWWorld::ConstPtr::getTypeName() const +{ + if(mRef != 0) + return mRef->mClass->getTypeName(); + throw std::runtime_error("Can't get type name from an empty object."); +} + +const MWWorld::LiveCellRefBase *MWWorld::ConstPtr::getBase() const +{ + if (!mRef) + throw std::runtime_error ("Can't access cell ref pointed to by null Ptr"); + + return mRef; +} + +MWWorld::ConstPtr::operator const void *() +{ + return mRef; +} diff --git a/apps/openmw/mwworld/ptr.hpp b/apps/openmw/mwworld/ptr.hpp index c97d2e6d1..9d370c4cb 100644 --- a/apps/openmw/mwworld/ptr.hpp +++ b/apps/openmw/mwworld/ptr.hpp @@ -85,6 +85,87 @@ namespace MWWorld ///< Return a 0-pointer, if Ptr is empty; return a non-0-pointer, if Ptr is not empty }; + /// \brief Pointer to a const LiveCellRef + /// @note a Ptr can be implicitely converted to a ConstPtr, but you can not convert a ConstPtr to a Ptr. + class ConstPtr + { + public: + + const MWWorld::LiveCellRefBase *mRef; + const CellStore *mCell; + const ContainerStore *mContainerStore; + + public: + ConstPtr(const MWWorld::LiveCellRefBase *liveCellRef=0, const CellStore *cell=0) + : mRef(liveCellRef), mCell(cell), mContainerStore(0) + { + } + + ConstPtr(const MWWorld::Ptr& ptr) + : mRef(ptr.mRef), mCell(ptr.mCell), mContainerStore(ptr.mContainerStore) + { + } + + bool isEmpty() const + { + return mRef == 0; + } + + const std::string& getTypeName() const; + + const Class& getClass() const + { + if(mRef != 0) + return *(mRef->mClass); + throw std::runtime_error("Cannot get class of an empty object"); + } + + template + const MWWorld::LiveCellRef *get() const + { + const MWWorld::LiveCellRef *ref = dynamic_cast*>(mRef); + if(ref) return ref; + + std::stringstream str; + str<< "Bad LiveCellRef cast to "<mRef; + } + + const RefData& getRefData() const + { + assert(mRef); + return mRef->mData; + } + + const CellStore *getCell() const + { + assert(mCell); + return mCell; + } + + bool isInCell() const + { + return (mContainerStore == 0) && (mCell != 0); + } + + const ContainerStore *getContainerStore() const; + ///< May return a 0-pointer, if reference is not in a container. + + operator const void *(); + ///< Return a 0-pointer, if Ptr is empty; return a non-0-pointer, if Ptr is not empty + }; + inline bool operator== (const Ptr& left, const Ptr& right) { return left.mRef==right.mRef; From 19d87c78f272f4f78b35d1e2e5fd2e515a835b47 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 17 Dec 2015 23:59:18 +0100 Subject: [PATCH 2847/3725] Add CellStore::forEachConst --- apps/openmw/mwworld/cellstore.cpp | 18 +++++++++--------- apps/openmw/mwworld/cellstore.hpp | 30 +++++++++++++++++++++++++----- apps/openmw/mwworld/worldimp.cpp | 14 +++++++------- apps/openmw/mwworld/worldimp.hpp | 4 ++-- 4 files changed, 43 insertions(+), 23 deletions(-) diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 2429a83a7..c4ab9f316 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -350,11 +350,12 @@ namespace MWWorld return searchConst (id).isEmpty(); } + template struct SearchVisitor { - MWWorld::Ptr mFound; + PtrType mFound; std::string mIdToFind; - bool operator()(const MWWorld::Ptr& ptr) + bool operator()(const PtrType& ptr) { if (ptr.getCellRef().getRefId() == mIdToFind) { @@ -367,19 +368,18 @@ namespace MWWorld Ptr CellStore::search (const std::string& id) { - SearchVisitor searchVisitor; + SearchVisitor searchVisitor; searchVisitor.mIdToFind = id; forEach(searchVisitor); return searchVisitor.mFound; } - Ptr CellStore::searchConst (const std::string& id) const + ConstPtr CellStore::searchConst (const std::string& id) const { - bool oldState = mHasState; - /// \todo address const-issues - Ptr result = const_cast(this)->search(id); - const_cast(this)->mHasState = oldState; - return result; + SearchVisitor searchVisitor; + searchVisitor.mIdToFind = id; + forEachConst(searchVisitor); + return searchVisitor.mFound; } Ptr CellStore::searchViaActorId (int id) diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index 7047682fa..f2cef1859 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -214,7 +214,7 @@ namespace MWWorld /// containers. /// @note Triggers CellStore hasState flag. - Ptr searchConst (const std::string& id) const; + ConstPtr searchConst (const std::string& id) const; ///< Will return an empty Ptr if cell is not loaded. Does not check references in /// containers. /// @note Does not trigger CellStore hasState flag. Do not modify the returned Ptr! @@ -240,8 +240,9 @@ namespace MWWorld void preload (); ///< Build ID list from content file. - /// Call visitor (ref) for each reference. visitor must return a bool. Returning + /// Call visitor (MWWorld::Ptr) for each reference. visitor must return a bool. Returning /// false will abort the iteration. + /// \note Prefer using forEachConst when possible. /// \attention This function also lists deleted (count 0) objects! /// \return Iteration completed? template @@ -263,6 +264,28 @@ namespace MWWorld return true; } + /// Call visitor (MWWorld::ConstPtr) for each reference. visitor must return a bool. Returning + /// false will abort the iteration. + /// \attention This function also lists deleted (count 0) objects! + /// \return Iteration completed? + template + bool forEachConst (Visitor& visitor) const + { + if (mState != State_Loaded) + return false; + + for (unsigned int i=0; imData, mMergedRefs[i]->mRef)) + continue; + + if (!visitor(MWWorld::ConstPtr(mMergedRefs[i], this))) + return false; + } + return true; + } + + /// Call visitor (ref) for each reference of given type. visitor must return a bool. Returning /// false will abort the iteration. /// \attention This function also lists deleted (count 0) objects! @@ -298,9 +321,6 @@ namespace MWWorld return true; } - /// \todo add const version of forEach - - // NOTE: does not account for moved references // Should be phased out when we have const version of forEach inline const CellRefList& getReadOnlyDoors() const diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 0969df6ca..56fe2fc3d 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2805,7 +2805,7 @@ namespace MWWorld return false; } - MWWorld::Ptr World::getClosestMarker( const MWWorld::Ptr &ptr, const std::string &id ) + MWWorld::ConstPtr World::getClosestMarker( const MWWorld::Ptr &ptr, const std::string &id ) { if ( ptr.getCell()->isExterior() ) { return getClosestMarkerFromExteriorPosition(mPlayer->getLastKnownExteriorPosition(), id); @@ -2817,7 +2817,7 @@ namespace MWWorld std::set< std::string >checkedCells; std::set< std::string >currentCells; std::set< std::string >nextCells; - MWWorld::Ptr closestMarker; + MWWorld::ConstPtr closestMarker; nextCells.insert( ptr.getCell()->getCell()->mName ); while ( !nextCells.empty() ) { @@ -2861,8 +2861,8 @@ namespace MWWorld return MWWorld::Ptr(); } - MWWorld::Ptr World::getClosestMarkerFromExteriorPosition( const osg::Vec3f& worldPos, const std::string &id ) { - MWWorld::Ptr closestMarker; + MWWorld::ConstPtr World::getClosestMarkerFromExteriorPosition( const osg::Vec3f& worldPos, const std::string &id ) { + MWWorld::ConstPtr closestMarker; float closestDistance = std::numeric_limits::max(); std::vector markers; @@ -2887,7 +2887,7 @@ namespace MWWorld void World::teleportToClosestMarker (const MWWorld::Ptr& ptr, const std::string& id) { - MWWorld::Ptr closestMarker = getClosestMarker( ptr, id ); + MWWorld::ConstPtr closestMarker = getClosestMarker( ptr, id ); if ( closestMarker.isEmpty() ) { @@ -3047,13 +3047,13 @@ namespace MWWorld void World::confiscateStolenItems(const Ptr &ptr) { - MWWorld::Ptr prisonMarker = getClosestMarker( ptr, "prisonmarker" ); + MWWorld::ConstPtr prisonMarker = getClosestMarker( ptr, "prisonmarker" ); if ( prisonMarker.isEmpty() ) { std::cerr << "Failed to confiscate items: no closest prison marker found." << std::endl; return; } - std::string prisonName = prisonMarker.mRef->mRef.getDestCell(); + std::string prisonName = prisonMarker.getCellRef().getDestCell(); if ( prisonName.empty() ) { std::cerr << "Failed to confiscate items: prison marker not linked to prison interior" << std::endl; diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 713213287..7d67395cf 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -165,8 +165,8 @@ namespace MWWorld float feetToGameUnits(float feet); - MWWorld::Ptr getClosestMarker( const MWWorld::Ptr &ptr, const std::string &id ); - MWWorld::Ptr getClosestMarkerFromExteriorPosition( const osg::Vec3f& worldPos, const std::string &id ); + MWWorld::ConstPtr getClosestMarker( const MWWorld::Ptr &ptr, const std::string &id ); + MWWorld::ConstPtr getClosestMarkerFromExteriorPosition( const osg::Vec3f& worldPos, const std::string &id ); public: From eb51e2838f03cf31d40ab25252b4e1a5386805bf Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 00:07:13 +0100 Subject: [PATCH 2848/3725] Utilize the mHasCustomData flag in writeAdditionalState --- apps/openmw/mwclass/container.cpp | 8 +++++++- apps/openmw/mwclass/creature.cpp | 2 -- apps/openmw/mwclass/creaturelevlist.cpp | 10 +++++++++- apps/openmw/mwclass/door.cpp | 8 +++++++- apps/openmw/mwclass/npc.cpp | 2 -- 5 files changed, 23 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index c9f9f3740..aa5142cbd 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -299,6 +299,8 @@ namespace MWClass void Container::readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state) const { + if (!state.mHasCustomState) + return; const ESM::ContainerState& state2 = dynamic_cast (state); if (!ptr.getRefData().getCustomData()) @@ -316,7 +318,11 @@ namespace MWClass { ESM::ContainerState& state2 = dynamic_cast (state); - ensureCustomData (ptr); + if (!ptr.getRefData().getCustomData()) + { + state.mHasCustomState = false; + return; + } dynamic_cast (*ptr.getRefData().getCustomData()).mContainerStore. writeState (state2.mInventory); diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index d6270077d..4954ac54d 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -735,8 +735,6 @@ namespace MWClass return; } - ensureCustomData (ptr); - CreatureCustomData& customData = ptr.getRefData().getCustomData()->asCreatureCustomData(); customData.mContainerStore->writeState (state2.mInventory); diff --git a/apps/openmw/mwclass/creaturelevlist.cpp b/apps/openmw/mwclass/creaturelevlist.cpp index c015d53d6..231a4ee37 100644 --- a/apps/openmw/mwclass/creaturelevlist.cpp +++ b/apps/openmw/mwclass/creaturelevlist.cpp @@ -104,6 +104,9 @@ namespace MWClass void CreatureLevList::readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state) const { + if (!state.mHasCustomState) + return; + const ESM::CreatureLevListState& state2 = dynamic_cast (state); ensureCustomData(ptr); @@ -117,7 +120,12 @@ namespace MWClass { ESM::CreatureLevListState& state2 = dynamic_cast (state); - ensureCustomData(ptr); + if (!ptr.getRefData().getCustomData()) + { + state.mHasCustomState = false; + return; + } + CreatureLevListCustomData& customData = ptr.getRefData().getCustomData()->asCreatureLevListCustomData(); state2.mSpawnActorId = customData.mSpawnActorId; state2.mSpawn = customData.mSpawn; diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index fffa8d1fd..cf11dfedb 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -343,6 +343,8 @@ namespace MWClass void Door::readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state) const { + if (!state.mHasCustomState) + return; ensureCustomData(ptr); DoorCustomData& customData = ptr.getRefData().getCustomData()->asDoorCustomData(); @@ -352,7 +354,11 @@ namespace MWClass void Door::writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state) const { - ensureCustomData(ptr); + if (!ptr.getRefData().getCustomData()) + { + state.mHasCustomState = false; + return; + } const DoorCustomData& customData = ptr.getRefData().getCustomData()->asDoorCustomData(); ESM::DoorState& state2 = dynamic_cast(state); diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 60ab73e04..08743cb4f 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -1187,8 +1187,6 @@ namespace MWClass return; } - ensureCustomData (ptr); - NpcCustomData& customData = ptr.getRefData().getCustomData()->asNpcCustomData(); customData.mInventoryStore.writeState (state2.mInventory); From b48445dea7c061042946f3b07afbeb760dbf0e20 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 00:12:03 +0100 Subject: [PATCH 2849/3725] Accept a ConstPtr in getScript --- apps/openmw/mwclass/activator.cpp | 4 ++-- apps/openmw/mwclass/activator.hpp | 2 +- apps/openmw/mwclass/apparatus.cpp | 5 ++--- apps/openmw/mwclass/apparatus.hpp | 2 +- apps/openmw/mwclass/armor.cpp | 5 ++--- apps/openmw/mwclass/armor.hpp | 2 +- apps/openmw/mwclass/book.cpp | 5 ++--- apps/openmw/mwclass/book.hpp | 2 +- apps/openmw/mwclass/clothing.cpp | 5 ++--- apps/openmw/mwclass/clothing.hpp | 2 +- apps/openmw/mwclass/container.cpp | 5 ++--- apps/openmw/mwclass/container.hpp | 2 +- apps/openmw/mwclass/creature.cpp | 4 ++-- apps/openmw/mwclass/creature.hpp | 2 +- apps/openmw/mwclass/door.cpp | 5 ++--- apps/openmw/mwclass/door.hpp | 2 +- apps/openmw/mwclass/ingredient.cpp | 5 ++--- apps/openmw/mwclass/ingredient.hpp | 2 +- apps/openmw/mwclass/light.cpp | 5 ++--- apps/openmw/mwclass/light.hpp | 2 +- apps/openmw/mwclass/lockpick.cpp | 5 ++--- apps/openmw/mwclass/lockpick.hpp | 2 +- apps/openmw/mwclass/misc.cpp | 5 ++--- apps/openmw/mwclass/misc.hpp | 2 +- apps/openmw/mwclass/npc.cpp | 5 ++--- apps/openmw/mwclass/npc.hpp | 2 +- apps/openmw/mwclass/potion.cpp | 4 ++-- apps/openmw/mwclass/potion.hpp | 2 +- apps/openmw/mwclass/probe.cpp | 4 ++-- apps/openmw/mwclass/probe.hpp | 2 +- apps/openmw/mwclass/repair.cpp | 4 ++-- apps/openmw/mwclass/repair.hpp | 2 +- apps/openmw/mwclass/weapon.cpp | 4 ++-- apps/openmw/mwclass/weapon.hpp | 2 +- apps/openmw/mwworld/class.cpp | 2 +- apps/openmw/mwworld/class.hpp | 2 +- 36 files changed, 53 insertions(+), 64 deletions(-) diff --git a/apps/openmw/mwclass/activator.cpp b/apps/openmw/mwclass/activator.cpp index 17757cb6b..8b41eec13 100644 --- a/apps/openmw/mwclass/activator.cpp +++ b/apps/openmw/mwclass/activator.cpp @@ -66,9 +66,9 @@ namespace MWClass return ref->mBase->mName; } - std::string Activator::getScript (const MWWorld::Ptr& ptr) const + std::string Activator::getScript (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mScript; diff --git a/apps/openmw/mwclass/activator.hpp b/apps/openmw/mwclass/activator.hpp index 646bb79bb..6280587b1 100644 --- a/apps/openmw/mwclass/activator.hpp +++ b/apps/openmw/mwclass/activator.hpp @@ -31,7 +31,7 @@ namespace MWClass virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. - virtual std::string getScript (const MWWorld::Ptr& ptr) const; + virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; ///< Return name of the script attached to ptr virtual boost::shared_ptr activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const; diff --git a/apps/openmw/mwclass/apparatus.cpp b/apps/openmw/mwclass/apparatus.cpp index 07bf25086..b4d293cb8 100644 --- a/apps/openmw/mwclass/apparatus.cpp +++ b/apps/openmw/mwclass/apparatus.cpp @@ -64,10 +64,9 @@ namespace MWClass return defaultItemActivate(ptr, actor); } - std::string Apparatus::getScript (const MWWorld::Ptr& ptr) const + std::string Apparatus::getScript (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mScript; } diff --git a/apps/openmw/mwclass/apparatus.hpp b/apps/openmw/mwclass/apparatus.hpp index 94e998e48..071bf83bd 100644 --- a/apps/openmw/mwclass/apparatus.hpp +++ b/apps/openmw/mwclass/apparatus.hpp @@ -31,7 +31,7 @@ namespace MWClass const MWWorld::Ptr& actor) const; ///< Generate action for activation - virtual std::string getScript (const MWWorld::Ptr& ptr) const; + virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; ///< Return name of the script attached to ptr virtual int getValue (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index 631ddd912..e51ea11e0 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -83,10 +83,9 @@ namespace MWClass return ref->mBase->mData.mHealth; } - std::string Armor::getScript (const MWWorld::Ptr& ptr) const + std::string Armor::getScript (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mScript; } diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index ec3290878..a7e63d6af 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -36,7 +36,7 @@ namespace MWClass virtual int getItemMaxHealth (const MWWorld::Ptr& ptr) const; ///< Return item max health or throw an exception, if class does not have item health - virtual std::string getScript (const MWWorld::Ptr& ptr) const; + virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; ///< Return name of the script attached to ptr virtual std::pair, bool> getEquipmentSlots (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index 9ea9e659b..1d645931d 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -78,10 +78,9 @@ namespace MWClass return boost::shared_ptr(new MWWorld::ActionRead(ptr)); } - std::string Book::getScript (const MWWorld::Ptr& ptr) const + std::string Book::getScript (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mScript; } diff --git a/apps/openmw/mwclass/book.hpp b/apps/openmw/mwclass/book.hpp index 8dcae731a..90cb4d762 100644 --- a/apps/openmw/mwclass/book.hpp +++ b/apps/openmw/mwclass/book.hpp @@ -28,7 +28,7 @@ namespace MWClass const MWWorld::Ptr& actor) const; ///< Generate action for activation - virtual std::string getScript (const MWWorld::Ptr& ptr) const; + virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; ///< Return name of the script attached to ptr virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index 7250e1837..616f9676b 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -66,10 +66,9 @@ namespace MWClass return defaultItemActivate(ptr, actor); } - std::string Clothing::getScript (const MWWorld::Ptr& ptr) const + std::string Clothing::getScript (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mScript; } diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index adb349158..0489f0b31 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -28,7 +28,7 @@ namespace MWClass const MWWorld::Ptr& actor) const; ///< Generate action for activation - virtual std::string getScript (const MWWorld::Ptr& ptr) const; + virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; ///< Return name of the script attached to ptr virtual std::pair, bool> getEquipmentSlots (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index aa5142cbd..648a232c8 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -209,10 +209,9 @@ namespace MWClass return ptr.getRefData().getCustomData()->asContainerCustomData().mContainerStore; } - std::string Container::getScript (const MWWorld::Ptr& ptr) const + std::string Container::getScript (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mScript; } diff --git a/apps/openmw/mwclass/container.hpp b/apps/openmw/mwclass/container.hpp index 3541937d1..d9c7daa07 100644 --- a/apps/openmw/mwclass/container.hpp +++ b/apps/openmw/mwclass/container.hpp @@ -40,7 +40,7 @@ namespace MWClass virtual MWWorld::ContainerStore& getContainerStore (const MWWorld::Ptr& ptr) const; ///< Return container store - virtual std::string getScript (const MWWorld::Ptr& ptr) const; + virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; ///< Return name of the script attached to ptr virtual float getCapacity (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 4954ac54d..55bb895b7 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -444,9 +444,9 @@ namespace MWClass return isFlagBitSet(ptr, ESM::Creature::Weapon); } - std::string Creature::getScript (const MWWorld::Ptr& ptr) const + std::string Creature::getScript (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mScript; } diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index 55127eefc..fc1421d24 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -74,7 +74,7 @@ namespace MWClass virtual bool hasInventoryStore (const MWWorld::Ptr &ptr) const; - virtual std::string getScript (const MWWorld::Ptr& ptr) const; + virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; ///< Return name of the script attached to ptr virtual float getCapacity (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index cf11dfedb..5d5e695b8 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -217,10 +217,9 @@ namespace MWClass return true; } - std::string Door::getScript (const MWWorld::Ptr& ptr) const + std::string Door::getScript (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mScript; } diff --git a/apps/openmw/mwclass/door.hpp b/apps/openmw/mwclass/door.hpp index db5a7f32a..b06ee12df 100644 --- a/apps/openmw/mwclass/door.hpp +++ b/apps/openmw/mwclass/door.hpp @@ -49,7 +49,7 @@ namespace MWClass virtual bool canLock(const MWWorld::Ptr &ptr) const; - virtual std::string getScript (const MWWorld::Ptr& ptr) const; + virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; ///< Return name of the script attached to ptr static void registerSelf(); diff --git a/apps/openmw/mwclass/ingredient.cpp b/apps/openmw/mwclass/ingredient.cpp index db2f2410b..b7d1cf3d9 100644 --- a/apps/openmw/mwclass/ingredient.cpp +++ b/apps/openmw/mwclass/ingredient.cpp @@ -70,10 +70,9 @@ namespace MWClass return defaultItemActivate(ptr, actor); } - std::string Ingredient::getScript (const MWWorld::Ptr& ptr) const + std::string Ingredient::getScript (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mScript; } diff --git a/apps/openmw/mwclass/ingredient.hpp b/apps/openmw/mwclass/ingredient.hpp index 69dd70743..00862a220 100644 --- a/apps/openmw/mwclass/ingredient.hpp +++ b/apps/openmw/mwclass/ingredient.hpp @@ -34,7 +34,7 @@ namespace MWClass virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. - virtual std::string getScript (const MWWorld::Ptr& ptr) const; + virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; ///< Return name of the script attached to ptr virtual int getValue (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index fe5149077..615f9fac0 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -96,10 +96,9 @@ namespace MWClass return defaultItemActivate(ptr, actor); } - std::string Light::getScript (const MWWorld::Ptr& ptr) const + std::string Light::getScript (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mScript; } diff --git a/apps/openmw/mwclass/light.hpp b/apps/openmw/mwclass/light.hpp index 6161f1899..b7ef199b0 100644 --- a/apps/openmw/mwclass/light.hpp +++ b/apps/openmw/mwclass/light.hpp @@ -34,7 +34,7 @@ namespace MWClass const MWWorld::Ptr& actor) const; ///< Generate action for activation - virtual std::string getScript (const MWWorld::Ptr& ptr) const; + virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; ///< Return name of the script attached to ptr virtual std::pair, bool> getEquipmentSlots (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index 63f75a845..3fae74be9 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -65,10 +65,9 @@ namespace MWClass return defaultItemActivate(ptr, actor); } - std::string Lockpick::getScript (const MWWorld::Ptr& ptr) const + std::string Lockpick::getScript (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mScript; } diff --git a/apps/openmw/mwclass/lockpick.hpp b/apps/openmw/mwclass/lockpick.hpp index 3f2c004f8..7e7ee78d5 100644 --- a/apps/openmw/mwclass/lockpick.hpp +++ b/apps/openmw/mwclass/lockpick.hpp @@ -34,7 +34,7 @@ namespace MWClass virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. - virtual std::string getScript (const MWWorld::Ptr& ptr) const; + virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; ///< Return name of the script attached to ptr virtual std::pair, bool> getEquipmentSlots (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index a14ab3330..e5836bd96 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -78,10 +78,9 @@ namespace MWClass return defaultItemActivate(ptr, actor); } - std::string Miscellaneous::getScript (const MWWorld::Ptr& ptr) const + std::string Miscellaneous::getScript (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mScript; } diff --git a/apps/openmw/mwclass/misc.hpp b/apps/openmw/mwclass/misc.hpp index 394c9ffc0..e3215a6ad 100644 --- a/apps/openmw/mwclass/misc.hpp +++ b/apps/openmw/mwclass/misc.hpp @@ -34,7 +34,7 @@ namespace MWClass virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. - virtual std::string getScript (const MWWorld::Ptr& ptr) const; + virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; ///< Return name of the script attached to ptr virtual int getValue (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 08743cb4f..bbcee8d27 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -799,10 +799,9 @@ namespace MWClass return ptr.getRefData().getCustomData()->asNpcCustomData().mInventoryStore; } - std::string Npc::getScript (const MWWorld::Ptr& ptr) const + std::string Npc::getScript (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mScript; } diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index c2d2ca8fa..aa8b7e78a 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -80,7 +80,7 @@ namespace MWClass const MWWorld::Ptr& actor) const; ///< Generate action for activation - virtual std::string getScript (const MWWorld::Ptr& ptr) const; + virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; ///< Return name of the script attached to ptr virtual float getSpeed (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/potion.cpp b/apps/openmw/mwclass/potion.cpp index 20a849019..9816c3cbc 100644 --- a/apps/openmw/mwclass/potion.cpp +++ b/apps/openmw/mwclass/potion.cpp @@ -68,9 +68,9 @@ namespace MWClass return defaultItemActivate(ptr, actor); } - std::string Potion::getScript (const MWWorld::Ptr& ptr) const + std::string Potion::getScript (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mScript; diff --git a/apps/openmw/mwclass/potion.hpp b/apps/openmw/mwclass/potion.hpp index 091d29195..a38205257 100644 --- a/apps/openmw/mwclass/potion.hpp +++ b/apps/openmw/mwclass/potion.hpp @@ -34,7 +34,7 @@ namespace MWClass virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. - virtual std::string getScript (const MWWorld::Ptr& ptr) const; + virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; ///< Return name of the script attached to ptr virtual int getValue (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index 79f423b30..0e3de75d4 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -64,9 +64,9 @@ namespace MWClass return defaultItemActivate(ptr, actor); } - std::string Probe::getScript (const MWWorld::Ptr& ptr) const + std::string Probe::getScript (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mScript; diff --git a/apps/openmw/mwclass/probe.hpp b/apps/openmw/mwclass/probe.hpp index e39e43c27..a6da5ab9d 100644 --- a/apps/openmw/mwclass/probe.hpp +++ b/apps/openmw/mwclass/probe.hpp @@ -34,7 +34,7 @@ namespace MWClass virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. - virtual std::string getScript (const MWWorld::Ptr& ptr) const; + virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; ///< Return name of the script attached to ptr virtual std::pair, bool> getEquipmentSlots (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/repair.cpp b/apps/openmw/mwclass/repair.cpp index 78ec2adcc..700db167a 100644 --- a/apps/openmw/mwclass/repair.cpp +++ b/apps/openmw/mwclass/repair.cpp @@ -64,9 +64,9 @@ namespace MWClass return defaultItemActivate(ptr, actor); } - std::string Repair::getScript (const MWWorld::Ptr& ptr) const + std::string Repair::getScript (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mScript; diff --git a/apps/openmw/mwclass/repair.hpp b/apps/openmw/mwclass/repair.hpp index 295b9d4f1..3ec617bd3 100644 --- a/apps/openmw/mwclass/repair.hpp +++ b/apps/openmw/mwclass/repair.hpp @@ -34,7 +34,7 @@ namespace MWClass virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. - virtual std::string getScript (const MWWorld::Ptr& ptr) const; + virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; ///< Return name of the script attached to ptr virtual int getValue (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index 5665bf1c4..cc5d8ed59 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -84,9 +84,9 @@ namespace MWClass return ref->mBase->mData.mHealth; } - std::string Weapon::getScript (const MWWorld::Ptr& ptr) const + std::string Weapon::getScript (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mScript; diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index 47c1157a0..88282f5a3 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -40,7 +40,7 @@ namespace MWClass virtual int getItemMaxHealth (const MWWorld::Ptr& ptr) const; ///< Return item max health or throw an exception, if class does not have item health - virtual std::string getScript (const MWWorld::Ptr& ptr) const; + virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; ///< Return name of the script attached to ptr virtual std::pair, bool> getEquipmentSlots (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 30fd42527..e57f8b299 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -158,7 +158,7 @@ namespace MWWorld return -1; } - std::string Class::getScript (const Ptr& ptr) const + std::string Class::getScript (const ConstPtr& ptr) const { return ""; } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index b2d3453af..2bbc45083 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -171,7 +171,7 @@ namespace MWWorld ///< Returns the remaining duration of the object, such as an equippable light /// source. (default implementation: -1, i.e. infinite) - virtual std::string getScript (const Ptr& ptr) const; + virtual std::string getScript (const ConstPtr& ptr) const; ///< Return name of the script attached to ptr (default implementation: return an empty /// string). From ed3486e81692135609c621630a9169ab3da377bd Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 00:18:06 +0100 Subject: [PATCH 2850/3725] Improve const-correctness in writeAdditionalState --- apps/openmw/mwclass/container.cpp | 4 ++-- apps/openmw/mwclass/container.hpp | 2 +- apps/openmw/mwclass/creature.cpp | 4 ++-- apps/openmw/mwclass/creature.hpp | 6 ++---- apps/openmw/mwclass/creaturelevlist.cpp | 4 ++-- apps/openmw/mwclass/creaturelevlist.hpp | 6 ++---- apps/openmw/mwclass/door.cpp | 4 ++-- apps/openmw/mwclass/door.hpp | 2 +- apps/openmw/mwclass/npc.cpp | 4 ++-- apps/openmw/mwclass/npc.hpp | 2 +- apps/openmw/mwworld/class.cpp | 2 +- apps/openmw/mwworld/class.hpp | 2 +- apps/openmw/mwworld/containerstore.cpp | 4 ++-- apps/openmw/mwworld/containerstore.hpp | 5 ++--- apps/openmw/mwworld/inventorystore.cpp | 2 +- apps/openmw/mwworld/inventorystore.hpp | 2 +- apps/openmw/mwworld/livecellref.cpp | 3 +-- apps/openmw/mwworld/refdata.cpp | 5 +++++ apps/openmw/mwworld/refdata.hpp | 2 ++ 19 files changed, 33 insertions(+), 32 deletions(-) diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index 648a232c8..79efc253e 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -313,7 +313,7 @@ namespace MWClass readState (state2.mInventory); } - void Container::writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state) const + void Container::writeAdditionalState (const MWWorld::ConstPtr& ptr, ESM::ObjectState& state) const { ESM::ContainerState& state2 = dynamic_cast (state); @@ -323,7 +323,7 @@ namespace MWClass return; } - dynamic_cast (*ptr.getRefData().getCustomData()).mContainerStore. + dynamic_cast (*ptr.getRefData().getCustomData()).mContainerStore. writeState (state2.mInventory); } } diff --git a/apps/openmw/mwclass/container.hpp b/apps/openmw/mwclass/container.hpp index d9c7daa07..0c24ae03d 100644 --- a/apps/openmw/mwclass/container.hpp +++ b/apps/openmw/mwclass/container.hpp @@ -63,7 +63,7 @@ namespace MWClass const; ///< Read additional state from \a state into \a ptr. - virtual void writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state) + virtual void writeAdditionalState (const MWWorld::ConstPtr& ptr, ESM::ObjectState& state) const; ///< Write additional state from \a ptr into \a state. diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 55bb895b7..9aa9871bb 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -724,7 +724,7 @@ namespace MWClass customData.mCreatureStats.readState (state2.mCreatureStats); } - void Creature::writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state) + void Creature::writeAdditionalState (const MWWorld::ConstPtr& ptr, ESM::ObjectState& state) const { ESM::CreatureState& state2 = dynamic_cast (state); @@ -735,7 +735,7 @@ namespace MWClass return; } - CreatureCustomData& customData = ptr.getRefData().getCustomData()->asCreatureCustomData(); + const CreatureCustomData& customData = dynamic_cast(*ptr.getRefData().getCustomData()); customData.mContainerStore->writeState (state2.mInventory); customData.mCreatureStats.writeState (state2.mCreatureStats); diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index fc1421d24..70ffb3ba6 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -117,12 +117,10 @@ namespace MWClass /// Get a blood texture suitable for \a ptr (see Blood Texture 0-2 in Morrowind.ini) virtual int getBloodTexture (const MWWorld::Ptr& ptr) const; - virtual void readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state) - const; + virtual void readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state) const; ///< Read additional state from \a state into \a ptr. - virtual void writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state) - const; + virtual void writeAdditionalState (const MWWorld::ConstPtr& ptr, ESM::ObjectState& state) const; ///< Write additional state from \a ptr into \a state. virtual int getBaseGold(const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/creaturelevlist.cpp b/apps/openmw/mwclass/creaturelevlist.cpp index 231a4ee37..2e4aef2fa 100644 --- a/apps/openmw/mwclass/creaturelevlist.cpp +++ b/apps/openmw/mwclass/creaturelevlist.cpp @@ -115,7 +115,7 @@ namespace MWClass customData.mSpawn = state2.mSpawn; } - void CreatureLevList::writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state) + void CreatureLevList::writeAdditionalState (const MWWorld::ConstPtr& ptr, ESM::ObjectState& state) const { ESM::CreatureLevListState& state2 = dynamic_cast (state); @@ -126,7 +126,7 @@ namespace MWClass return; } - CreatureLevListCustomData& customData = ptr.getRefData().getCustomData()->asCreatureLevListCustomData(); + const CreatureLevListCustomData& customData = dynamic_cast(*ptr.getRefData().getCustomData()); state2.mSpawnActorId = customData.mSpawnActorId; state2.mSpawn = customData.mSpawn; } diff --git a/apps/openmw/mwclass/creaturelevlist.hpp b/apps/openmw/mwclass/creaturelevlist.hpp index 177aa7235..7e1b7828a 100644 --- a/apps/openmw/mwclass/creaturelevlist.hpp +++ b/apps/openmw/mwclass/creaturelevlist.hpp @@ -23,12 +23,10 @@ namespace MWClass virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state) - const; + virtual void readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state) const; ///< Read additional state from \a state into \a ptr. - virtual void writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state) - const; + virtual void writeAdditionalState (const MWWorld::ConstPtr& ptr, ESM::ObjectState& state) const; ///< Write additional state from \a ptr into \a state. virtual void respawn (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 5d5e695b8..7c3176d52 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -351,14 +351,14 @@ namespace MWClass customData.mDoorState = state2.mDoorState; } - void Door::writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state) const + void Door::writeAdditionalState (const MWWorld::ConstPtr& ptr, ESM::ObjectState& state) const { if (!ptr.getRefData().getCustomData()) { state.mHasCustomState = false; return; } - const DoorCustomData& customData = ptr.getRefData().getCustomData()->asDoorCustomData(); + const DoorCustomData& customData = dynamic_cast(*ptr.getRefData().getCustomData()); ESM::DoorState& state2 = dynamic_cast(state); state2.mDoorState = customData.mDoorState; diff --git a/apps/openmw/mwclass/door.hpp b/apps/openmw/mwclass/door.hpp index b06ee12df..c67c96e3e 100644 --- a/apps/openmw/mwclass/door.hpp +++ b/apps/openmw/mwclass/door.hpp @@ -66,7 +66,7 @@ namespace MWClass const; ///< Read additional state from \a state into \a ptr. - virtual void writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state) + virtual void writeAdditionalState (const MWWorld::ConstPtr& ptr, ESM::ObjectState& state) const; ///< Write additional state from \a ptr into \a state. }; diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index bbcee8d27..bac555d1b 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -1175,7 +1175,7 @@ namespace MWClass static_cast (customData.mNpcStats).readState (state2.mCreatureStats); } - void Npc::writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state) + void Npc::writeAdditionalState (const MWWorld::ConstPtr& ptr, ESM::ObjectState& state) const { ESM::NpcState& state2 = dynamic_cast (state); @@ -1186,7 +1186,7 @@ namespace MWClass return; } - NpcCustomData& customData = ptr.getRefData().getCustomData()->asNpcCustomData(); + const NpcCustomData& customData = dynamic_cast(*ptr.getRefData().getCustomData()); customData.mInventoryStore.writeState (state2.mInventory); customData.mNpcStats.writeState (state2.mNpcStats); diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index aa8b7e78a..48277eb52 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -145,7 +145,7 @@ namespace MWClass const; ///< Read additional state from \a state into \a ptr. - virtual void writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state) + virtual void writeAdditionalState (const MWWorld::ConstPtr& ptr, ESM::ObjectState& state) const; ///< Write additional state from \a ptr into \a state. diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index e57f8b299..f8d4fbde4 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -397,7 +397,7 @@ namespace MWWorld void Class::readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state) const {} - void Class::writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state) const {} + void Class::writeAdditionalState (const MWWorld::ConstPtr& ptr, ESM::ObjectState& state) const {} int Class::getBaseGold(const MWWorld::Ptr& ptr) const { diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 2bbc45083..38ca7fcc1 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -313,7 +313,7 @@ namespace MWWorld const; ///< Read additional state from \a state into \a ptr. - virtual void writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state) + virtual void writeAdditionalState (const MWWorld::ConstPtr& ptr, ESM::ObjectState& state) const; ///< Write additional state from \a ptr into \a state. diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index b45e7ef83..4b4c51547 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -94,7 +94,7 @@ void MWWorld::ContainerStore::storeState (const LiveCellRef& ref, ESM::Object } template -void MWWorld::ContainerStore::storeStates (CellRefList& collection, +void MWWorld::ContainerStore::storeStates (const CellRefList& collection, ESM::InventoryState& inventory, int& index, bool equipable) const { for (typename CellRefList::List::const_iterator iter (collection.mList.begin()); @@ -707,7 +707,7 @@ MWWorld::Ptr MWWorld::ContainerStore::search (const std::string& id) return Ptr(); } -void MWWorld::ContainerStore::writeState (ESM::InventoryState& state) +void MWWorld::ContainerStore::writeState (ESM::InventoryState& state) const { state.mItems.clear(); diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index 876821f94..e103e16a1 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -86,7 +86,7 @@ namespace MWWorld void storeState (const LiveCellRef& ref, ESM::ObjectState& state) const; template - void storeStates (CellRefList& collection, + void storeStates (const CellRefList& collection, ESM::InventoryState& inventory, int& index, bool equipable = false) const; @@ -169,8 +169,7 @@ namespace MWWorld Ptr search (const std::string& id); - /// \todo make this method const once const-correct ContainerStoreIterators are available - virtual void writeState (ESM::InventoryState& state); + virtual void writeState (ESM::InventoryState& state) const; virtual void readState (const ESM::InventoryState& state); diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index da591487e..bfc33507a 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -752,7 +752,7 @@ bool MWWorld::InventoryStore::isEquipped(const MWWorld::Ptr &item) return false; } -void MWWorld::InventoryStore::writeState(ESM::InventoryState &state) +void MWWorld::InventoryStore::writeState(ESM::InventoryState &state) const { MWWorld::ContainerStore::writeState(state); diff --git a/apps/openmw/mwworld/inventorystore.hpp b/apps/openmw/mwworld/inventorystore.hpp index 95c16c115..2c1be9b03 100644 --- a/apps/openmw/mwworld/inventorystore.hpp +++ b/apps/openmw/mwworld/inventorystore.hpp @@ -207,7 +207,7 @@ namespace MWWorld virtual void clear(); ///< Empty container. - virtual void writeState (ESM::InventoryState& state); + virtual void writeState (ESM::InventoryState& state) const; virtual void readState (const ESM::InventoryState& state); }; diff --git a/apps/openmw/mwworld/livecellref.cpp b/apps/openmw/mwworld/livecellref.cpp index dcd6da431..0f83cd9c2 100644 --- a/apps/openmw/mwworld/livecellref.cpp +++ b/apps/openmw/mwworld/livecellref.cpp @@ -54,8 +54,7 @@ void MWWorld::LiveCellRefBase::saveImp (ESM::ObjectState& state) const { mRef.writeState(state); - /// \todo get rid of this cast once const-correct Ptr are available - Ptr ptr (const_cast (this)); + ConstPtr ptr (this); mData.write (state, mClass->getScript (ptr)); diff --git a/apps/openmw/mwworld/refdata.cpp b/apps/openmw/mwworld/refdata.cpp index f20e104e7..6c89f6d6f 100644 --- a/apps/openmw/mwworld/refdata.cpp +++ b/apps/openmw/mwworld/refdata.cpp @@ -205,6 +205,11 @@ namespace MWWorld return mCustomData; } + const CustomData *RefData::getCustomData() const + { + return mCustomData; + } + bool RefData::hasChanged() const { return mChanged; diff --git a/apps/openmw/mwworld/refdata.hpp b/apps/openmw/mwworld/refdata.hpp index 5421ea963..d02e05c98 100644 --- a/apps/openmw/mwworld/refdata.hpp +++ b/apps/openmw/mwworld/refdata.hpp @@ -116,6 +116,8 @@ namespace MWWorld CustomData *getCustomData(); ///< May return a 0-pointer. The ownership of the return data object is not transferred. + const CustomData *getCustomData() const; + bool hasChanged() const; ///< Has this RefData changed since it was originally loaded? }; From a3441832472b08c66dffc18ab9224f1da92f42fa Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 02:34:42 +0100 Subject: [PATCH 2851/3725] Comment fix --- apps/openmw/mwworld/cellstore.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index c4ab9f316..a6389ee0c 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -346,7 +346,6 @@ namespace MWWorld if (mState==State_Preloaded) return std::binary_search (mIds.begin(), mIds.end(), id); - /// \todo address const-issues return searchConst (id).isEmpty(); } From 1c8244276d91ba093c343af20350b6145e9a2f0e Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 02:36:34 +0100 Subject: [PATCH 2852/3725] Exception handling improvements (Bug #3090) --- apps/openmw/mwmechanics/summoning.cpp | 47 ++++++++++++++++----------- apps/openmw/mwrender/animation.cpp | 11 ++++++- 2 files changed, 38 insertions(+), 20 deletions(-) diff --git a/apps/openmw/mwmechanics/summoning.cpp b/apps/openmw/mwmechanics/summoning.cpp index 541026ee1..d248b34ba 100644 --- a/apps/openmw/mwmechanics/summoning.cpp +++ b/apps/openmw/mwmechanics/summoning.cpp @@ -34,7 +34,7 @@ namespace MWMechanics MWBase::Environment::get().getWorld()->spawnEffect("meshes\\" + fx->mModel, "", ptr.getRefData().getPosition().asVec3()); } - else + else if (creatureActorId != -1) { // We didn't find the creature. It's probably in an inactive cell. // Add to graveyard so we can delete it when the cell becomes active. @@ -132,25 +132,34 @@ namespace MWMechanics if (!creatureID.empty()) { MWWorld::CellStore* store = mActor.getCell(); - MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), creatureID, 1); - ref.getPtr().getCellRef().setPosition(ipos); - - MWMechanics::CreatureStats& summonedCreatureStats = ref.getPtr().getClass().getCreatureStats(ref.getPtr()); - - // Make the summoned creature follow its master and help in fights - AiFollow package(mActor.getCellRef().getRefId()); - summonedCreatureStats.getAiSequence().stack(package, ref.getPtr()); - int creatureActorId = summonedCreatureStats.getActorId(); - - MWWorld::Ptr placed = MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),store,ipos); - - MWRender::Animation* anim = MWBase::Environment::get().getWorld()->getAnimation(placed); - if (anim) + int creatureActorId = -1; + try + { + MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), creatureID, 1); + ref.getPtr().getCellRef().setPosition(ipos); + + MWMechanics::CreatureStats& summonedCreatureStats = ref.getPtr().getClass().getCreatureStats(ref.getPtr()); + + // Make the summoned creature follow its master and help in fights + AiFollow package(mActor.getCellRef().getRefId()); + summonedCreatureStats.getAiSequence().stack(package, ref.getPtr()); + creatureActorId = summonedCreatureStats.getActorId(); + + MWWorld::Ptr placed = MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),store,ipos); + + MWRender::Animation* anim = MWBase::Environment::get().getWorld()->getAnimation(placed); + if (anim) + { + const ESM::Static* fx = MWBase::Environment::get().getWorld()->getStore().get() + .search("VFX_Summon_Start"); + if (fx) + anim->addEffect("meshes\\" + fx->mModel, -1, false); + } + } + catch (std::exception& e) { - const ESM::Static* fx = MWBase::Environment::get().getWorld()->getStore().get() - .search("VFX_Summon_Start"); - if (fx) - anim->addEffect("meshes\\" + fx->mModel, -1, false); + std::cerr << "Failed to spawn summoned creature: " << e.what() << std::endl; + // still insert into creatureMap so we don't try to spawn again every frame, that would spam the warning log } creatureMap.insert(std::make_pair(*it, creatureActorId)); diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 85eefb329..68a073731 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -518,7 +518,16 @@ namespace MWRender } if (mTextKeyListener) - mTextKeyListener->handleTextKey(groupname, key, map); + { + try + { + mTextKeyListener->handleTextKey(groupname, key, map); + } + catch (std::exception& e) + { + std::cerr << "Error handling text key " << evt << ": " << e.what() << std::endl; + } + } } void Animation::play(const std::string &groupname, const AnimPriority& priority, int blendMask, bool autodisable, float speedmult, From b2add6470b19b603d4bdab4143c8494bf1d36fe1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 02:58:38 +0100 Subject: [PATCH 2853/3725] Missing include fix --- apps/openmw/mwmechanics/summoning.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwmechanics/summoning.cpp b/apps/openmw/mwmechanics/summoning.cpp index d248b34ba..636e19907 100644 --- a/apps/openmw/mwmechanics/summoning.cpp +++ b/apps/openmw/mwmechanics/summoning.cpp @@ -1,5 +1,7 @@ #include "summoning.hpp" +#include + #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" From 37a72d1ea62dd40940bc3bb9bddaced05a848611 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 18 Dec 2015 12:38:45 +0100 Subject: [PATCH 2854/3725] reject unsuitable drops to WorldspaceWidget earlier --- apps/opencs/view/render/worldspacewidget.cpp | 39 ++++++++++++++++++-- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 46e2bc2e0..2d0ef79ee 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -317,12 +317,38 @@ CSMDoc::Document& CSVRender::WorldspaceWidget::getDocument() void CSVRender::WorldspaceWidget::dragEnterEvent (QDragEnterEvent* event) { - event->accept(); + const CSMWorld::TableMimeData* mime = dynamic_cast (event->mimeData()); + if (!mime) // May happen when non-records (e.g. plain text) are dragged and dropped + return; + + if (mime->fromDocument (mDocument)) + { + if (mime->holdsType (CSMWorld::UniversalId::Type_Cell) || + mime->holdsType (CSMWorld::UniversalId::Type_Cell_Missing) || + mime->holdsType (CSMWorld::UniversalId::Type_DebugProfile)) + { + // These drops are handled through the subview object. + event->accept(); + } + } } void CSVRender::WorldspaceWidget::dragMoveEvent(QDragMoveEvent *event) { - event->accept(); + const CSMWorld::TableMimeData* mime = dynamic_cast (event->mimeData()); + if (!mime) // May happen when non-records (e.g. plain text) are dragged and dropped + return; + + if (mime->fromDocument (mDocument)) + { + if (mime->holdsType (CSMWorld::UniversalId::Type_Cell) || + mime->holdsType (CSMWorld::UniversalId::Type_Cell_Missing) || + mime->holdsType (CSMWorld::UniversalId::Type_DebugProfile)) + { + // These drops are handled through the subview object. + event->accept(); + } + } } @@ -428,8 +454,13 @@ void CSVRender::WorldspaceWidget::dropEvent (QDropEvent* event) if (mime->fromDocument (mDocument)) { - emit dataDropped(mime->getData()); - } //not handling drops from different documents at the moment + if (mime->holdsType (CSMWorld::UniversalId::Type_Cell) || + mime->holdsType (CSMWorld::UniversalId::Type_Cell_Missing) || + mime->holdsType (CSMWorld::UniversalId::Type_DebugProfile)) + { + emit dataDropped(mime->getData()); + } + } } void CSVRender::WorldspaceWidget::runRequest (const std::string& profile) From 102397067cecb5655219426eab567837c2448e92 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 18 Dec 2015 14:04:53 +0100 Subject: [PATCH 2855/3725] added interface for per edit-mode drop handling --- apps/opencs/view/render/editmode.cpp | 6 ++++++ apps/opencs/view/render/editmode.hpp | 13 +++++++++++++ apps/opencs/view/render/worldspacewidget.cpp | 7 ++++++- 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/apps/opencs/view/render/editmode.cpp b/apps/opencs/view/render/editmode.cpp index a77ef21a5..b325e31fb 100644 --- a/apps/opencs/view/render/editmode.cpp +++ b/apps/opencs/view/render/editmode.cpp @@ -64,3 +64,9 @@ void CSVRender::EditMode::dragCompleted() {} void CSVRender::EditMode::dragAborted() {} void CSVRender::EditMode::dragWheel (int diff, double speedFactor) {} + +void CSVRender::EditMode::dragEnterEvent (QDragEnterEvent *event) {} + +void CSVRender::EditMode::dropEvent (QDropEvent* event) {} + +void CSVRender::EditMode::dragMoveEvent (QDragMoveEvent *event) {} diff --git a/apps/opencs/view/render/editmode.hpp b/apps/opencs/view/render/editmode.hpp index 9a8ac9a3a..3ba97cf00 100644 --- a/apps/opencs/view/render/editmode.hpp +++ b/apps/opencs/view/render/editmode.hpp @@ -5,6 +5,10 @@ #include "../widget/modebutton.hpp" +class QDragEnterEvent; +class QDropEvent; +class QDragMoveEvent; + namespace CSVRender { class WorldspaceWidget; @@ -79,6 +83,15 @@ namespace CSVRender /// Default-implementation: ignored virtual void dragWheel (int diff, double speedFactor); + + /// Default-implementation: ignored + virtual void dragEnterEvent (QDragEnterEvent *event); + + /// Default-implementation: ignored + virtual void dropEvent (QDropEvent* event); + + /// Default-implementation: ignored + virtual void dragMoveEvent (QDragMoveEvent *event); }; } diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 2d0ef79ee..f0d398641 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -330,6 +330,8 @@ void CSVRender::WorldspaceWidget::dragEnterEvent (QDragEnterEvent* event) // These drops are handled through the subview object. event->accept(); } + else + dynamic_cast (*mEditMode->getCurrent()).dragEnterEvent (event); } } @@ -348,10 +350,11 @@ void CSVRender::WorldspaceWidget::dragMoveEvent(QDragMoveEvent *event) // These drops are handled through the subview object. event->accept(); } + else + dynamic_cast (*mEditMode->getCurrent()).dragMoveEvent (event); } } - bool CSVRender::WorldspaceWidget::storeMappingSetting (const CSMPrefs::Setting *setting) { if (setting->getParent()->getKey()!="3D Scene Input") @@ -460,6 +463,8 @@ void CSVRender::WorldspaceWidget::dropEvent (QDropEvent* event) { emit dataDropped(mime->getData()); } + else + dynamic_cast (*mEditMode->getCurrent()).dropEvent (event); } } From bc50587e71d6330df8436674b90483e795c88d6e Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 14:33:15 +0100 Subject: [PATCH 2856/3725] Remove comment --- apps/openmw/mwworld/cellstore.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index f2cef1859..27fe9ec03 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -217,7 +217,7 @@ namespace MWWorld ConstPtr searchConst (const std::string& id) const; ///< Will return an empty Ptr if cell is not loaded. Does not check references in /// containers. - /// @note Does not trigger CellStore hasState flag. Do not modify the returned Ptr! + /// @note Does not trigger CellStore hasState flag. Ptr searchViaActorId (int id); ///< Will return an empty Ptr if cell is not loaded. From d9bbd83b098ae8d49ce3be156fec027ef530f1cb Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 15:27:06 +0100 Subject: [PATCH 2857/3725] Accept a ConstPtr in getToolTipInfo Accept a ConstPtr in functions used by getToolTipInfo --- apps/openmw/mwclass/activator.cpp | 10 ++++---- apps/openmw/mwclass/activator.hpp | 4 ++-- apps/openmw/mwclass/apparatus.cpp | 15 +++++------- apps/openmw/mwclass/apparatus.hpp | 6 ++--- apps/openmw/mwclass/armor.cpp | 32 ++++++++++--------------- apps/openmw/mwclass/armor.hpp | 12 +++++----- apps/openmw/mwclass/book.cpp | 15 +++++------- apps/openmw/mwclass/book.hpp | 6 ++--- apps/openmw/mwclass/clothing.cpp | 20 +++++++--------- apps/openmw/mwclass/clothing.hpp | 8 +++---- apps/openmw/mwclass/container.cpp | 10 ++++---- apps/openmw/mwclass/container.hpp | 4 ++-- apps/openmw/mwclass/creature.cpp | 10 ++++---- apps/openmw/mwclass/creature.hpp | 4 ++-- apps/openmw/mwclass/creaturelevlist.cpp | 2 +- apps/openmw/mwclass/creaturelevlist.hpp | 2 +- apps/openmw/mwclass/door.cpp | 10 ++++---- apps/openmw/mwclass/door.hpp | 4 ++-- apps/openmw/mwclass/ingredient.cpp | 15 +++++------- apps/openmw/mwclass/ingredient.hpp | 6 ++--- apps/openmw/mwclass/itemlevlist.cpp | 2 +- apps/openmw/mwclass/itemlevlist.hpp | 2 +- apps/openmw/mwclass/light.cpp | 19 +++++++-------- apps/openmw/mwclass/light.hpp | 8 +++---- apps/openmw/mwclass/lockpick.cpp | 20 +++++++--------- apps/openmw/mwclass/lockpick.hpp | 8 +++---- apps/openmw/mwclass/misc.cpp | 22 +++++++---------- apps/openmw/mwclass/misc.hpp | 10 ++++---- apps/openmw/mwclass/npc.cpp | 16 ++++++++----- apps/openmw/mwclass/npc.hpp | 4 ++-- apps/openmw/mwclass/potion.cpp | 15 +++++------- apps/openmw/mwclass/potion.hpp | 6 ++--- apps/openmw/mwclass/probe.cpp | 20 +++++++--------- apps/openmw/mwclass/probe.hpp | 8 +++---- apps/openmw/mwclass/repair.cpp | 20 +++++++--------- apps/openmw/mwclass/repair.hpp | 8 +++---- apps/openmw/mwclass/static.cpp | 2 +- apps/openmw/mwclass/static.hpp | 2 +- apps/openmw/mwclass/weapon.cpp | 25 ++++++++----------- apps/openmw/mwclass/weapon.hpp | 12 +++++----- apps/openmw/mwworld/class.cpp | 14 +++++------ apps/openmw/mwworld/class.hpp | 20 ++++++++-------- apps/openmw/mwworld/customdata.cpp | 7 ++++++ apps/openmw/mwworld/customdata.hpp | 1 + 44 files changed, 212 insertions(+), 254 deletions(-) diff --git a/apps/openmw/mwclass/activator.cpp b/apps/openmw/mwclass/activator.cpp index 8b41eec13..1ca1150df 100644 --- a/apps/openmw/mwclass/activator.cpp +++ b/apps/openmw/mwclass/activator.cpp @@ -58,10 +58,9 @@ namespace MWClass return ""; } - std::string Activator::getName (const MWWorld::Ptr& ptr) const + std::string Activator::getName (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mName; } @@ -89,10 +88,9 @@ namespace MWClass return (ref->mBase->mName != ""); } - MWGui::ToolTipInfo Activator::getToolTipInfo (const MWWorld::Ptr& ptr) const + MWGui::ToolTipInfo Activator::getToolTipInfo (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); diff --git a/apps/openmw/mwclass/activator.hpp b/apps/openmw/mwclass/activator.hpp index 6280587b1..4e371d8dd 100644 --- a/apps/openmw/mwclass/activator.hpp +++ b/apps/openmw/mwclass/activator.hpp @@ -21,14 +21,14 @@ namespace MWClass virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; - virtual std::string getName (const MWWorld::Ptr& ptr) const; + virtual std::string getName (const MWWorld::ConstPtr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr) const; + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/apparatus.cpp b/apps/openmw/mwclass/apparatus.cpp index b4d293cb8..3caf68aae 100644 --- a/apps/openmw/mwclass/apparatus.cpp +++ b/apps/openmw/mwclass/apparatus.cpp @@ -50,10 +50,9 @@ namespace MWClass return ""; } - std::string Apparatus::getName (const MWWorld::Ptr& ptr) const + std::string Apparatus::getName (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mName; } @@ -71,10 +70,9 @@ namespace MWClass return ref->mBase->mScript; } - int Apparatus::getValue (const MWWorld::Ptr& ptr) const + int Apparatus::getValue (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mData.mValue; } @@ -112,10 +110,9 @@ namespace MWClass return (ref->mBase->mName != ""); } - MWGui::ToolTipInfo Apparatus::getToolTipInfo (const MWWorld::Ptr& ptr) const + MWGui::ToolTipInfo Apparatus::getToolTipInfo (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); diff --git a/apps/openmw/mwclass/apparatus.hpp b/apps/openmw/mwclass/apparatus.hpp index 071bf83bd..32b58af07 100644 --- a/apps/openmw/mwclass/apparatus.hpp +++ b/apps/openmw/mwclass/apparatus.hpp @@ -23,7 +23,7 @@ namespace MWClass virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; - virtual std::string getName (const MWWorld::Ptr& ptr) const; + virtual std::string getName (const MWWorld::ConstPtr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. @@ -34,13 +34,13 @@ namespace MWClass virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; ///< Return name of the script attached to ptr - virtual int getValue (const MWWorld::Ptr& ptr) const; + virtual int getValue (const MWWorld::ConstPtr& ptr) const; ///< Return trade value of the object. Throws an exception, if the object can't be traded. virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr) const; + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. static void registerSelf(); diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index e51ea11e0..c9369e1ae 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -56,10 +56,9 @@ namespace MWClass return ""; } - std::string Armor::getName (const MWWorld::Ptr& ptr) const + std::string Armor::getName (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mName; } @@ -75,10 +74,9 @@ namespace MWClass return true; } - int Armor::getItemMaxHealth (const MWWorld::Ptr& ptr) const + int Armor::getItemMaxHealth (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mData.mHealth; } @@ -92,8 +90,7 @@ namespace MWClass std::pair, bool> Armor::getEquipmentSlots (const MWWorld::Ptr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); std::vector slots_; @@ -124,10 +121,9 @@ namespace MWClass return std::make_pair (slots_, false); } - int Armor::getEquipmentSkill (const MWWorld::Ptr& ptr) const + int Armor::getEquipmentSkill (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); std::string typeGmst; @@ -169,10 +165,9 @@ namespace MWClass return ESM::Skill::HeavyArmor; } - int Armor::getValue (const MWWorld::Ptr& ptr) const + int Armor::getValue (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mData.mValue; } @@ -222,10 +217,9 @@ namespace MWClass return (ref->mBase->mName != ""); } - MWGui::ToolTipInfo Armor::getToolTipInfo (const MWWorld::Ptr& ptr) const + MWGui::ToolTipInfo Armor::getToolTipInfo (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); @@ -289,9 +283,9 @@ namespace MWClass return record->mId; } - int Armor::getEffectiveArmorRating(const MWWorld::Ptr &ptr, const MWWorld::Ptr &actor) const + int Armor::getEffectiveArmorRating(const MWWorld::ConstPtr &ptr, const MWWorld::Ptr &actor) const { - MWWorld::LiveCellRef *ref = ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); int armorSkillType = getEquipmentSkill(ptr); int armorSkill = actor.getClass().getSkill(actor, armorSkillType); diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index a7e63d6af..c989fcde0 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -22,7 +22,7 @@ namespace MWClass virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; - virtual std::string getName (const MWWorld::Ptr& ptr) const; + virtual std::string getName (const MWWorld::ConstPtr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. @@ -33,7 +33,7 @@ namespace MWClass virtual bool hasItemHealth (const MWWorld::Ptr& ptr) const; ///< \return Item health data available? - virtual int getItemMaxHealth (const MWWorld::Ptr& ptr) const; + virtual int getItemMaxHealth (const MWWorld::ConstPtr& ptr) const; ///< Return item max health or throw an exception, if class does not have item health virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; @@ -43,17 +43,17 @@ namespace MWClass ///< \return first: Return IDs of the slot this object can be equipped in; second: can object /// stay stacked when equipped? - virtual int getEquipmentSkill (const MWWorld::Ptr& ptr) const; + virtual int getEquipmentSkill (const MWWorld::ConstPtr& ptr) const; /// Return the index of the skill this item corresponds to when equiopped or -1, if there is /// no such skill. virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr) const; + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. - virtual int getValue (const MWWorld::Ptr& ptr) const; + virtual int getValue (const MWWorld::ConstPtr& ptr) const; ///< Return trade value of the object. Throws an exception, if the object can't be traded. static void registerSelf(); @@ -88,7 +88,7 @@ namespace MWClass virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; /// Get the effective armor rating, factoring in the actor's skills, for the given armor. - virtual int getEffectiveArmorRating(const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const; + virtual int getEffectiveArmorRating(const MWWorld::ConstPtr& armor, const MWWorld::Ptr& actor) const; }; } diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index 1d645931d..49b53c480 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -53,10 +53,9 @@ namespace MWClass return ""; } - std::string Book::getName (const MWWorld::Ptr& ptr) const + std::string Book::getName (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mName; } @@ -85,10 +84,9 @@ namespace MWClass return ref->mBase->mScript; } - int Book::getValue (const MWWorld::Ptr& ptr) const + int Book::getValue (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mData.mValue; } @@ -126,10 +124,9 @@ namespace MWClass return (ref->mBase->mName != ""); } - MWGui::ToolTipInfo Book::getToolTipInfo (const MWWorld::Ptr& ptr) const + MWGui::ToolTipInfo Book::getToolTipInfo (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); diff --git a/apps/openmw/mwclass/book.hpp b/apps/openmw/mwclass/book.hpp index 90cb4d762..a4f230219 100644 --- a/apps/openmw/mwclass/book.hpp +++ b/apps/openmw/mwclass/book.hpp @@ -20,7 +20,7 @@ namespace MWClass virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; - virtual std::string getName (const MWWorld::Ptr& ptr) const; + virtual std::string getName (const MWWorld::ConstPtr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. @@ -34,10 +34,10 @@ namespace MWClass virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr) const; + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. - virtual int getValue (const MWWorld::Ptr& ptr) const; + virtual int getValue (const MWWorld::ConstPtr& ptr) const; ///< Return trade value of the object. Throws an exception, if the object can't be traded. static void registerSelf(); diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index 616f9676b..faa776e3a 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -52,10 +52,9 @@ namespace MWClass return ""; } - std::string Clothing::getName (const MWWorld::Ptr& ptr) const + std::string Clothing::getName (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mName; } @@ -113,10 +112,9 @@ namespace MWClass return std::make_pair (slots_, false); } - int Clothing::getEquipmentSkill (const MWWorld::Ptr& ptr) const + int Clothing::getEquipmentSkill (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); if (ref->mBase->mData.mType==ESM::Clothing::Shoes) return ESM::Skill::Unarmored; @@ -124,10 +122,9 @@ namespace MWClass return -1; } - int Clothing::getValue (const MWWorld::Ptr& ptr) const + int Clothing::getValue (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mData.mValue; } @@ -179,10 +176,9 @@ namespace MWClass return (ref->mBase->mName != ""); } - MWGui::ToolTipInfo Clothing::getToolTipInfo (const MWWorld::Ptr& ptr) const + MWGui::ToolTipInfo Clothing::getToolTipInfo (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index 0489f0b31..30d16f0d7 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -20,7 +20,7 @@ namespace MWClass virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; - virtual std::string getName (const MWWorld::Ptr& ptr) const; + virtual std::string getName (const MWWorld::ConstPtr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. @@ -35,17 +35,17 @@ namespace MWClass ///< \return first: Return IDs of the slot this object can be equipped in; second: can object /// stay stacked when equipped? - virtual int getEquipmentSkill (const MWWorld::Ptr& ptr) const; + virtual int getEquipmentSkill (const MWWorld::ConstPtr& ptr) const; /// Return the index of the skill this item corresponds to when equiopped or -1, if there is /// no such skill. virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr) const; + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. - virtual int getValue (const MWWorld::Ptr& ptr) const; + virtual int getValue (const MWWorld::ConstPtr& ptr) const; ///< Return trade value of the object. Throws an exception, if the object can't be traded. static void registerSelf(); diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index 79efc253e..9c39c9df1 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -193,10 +193,9 @@ namespace MWClass } } - std::string Container::getName (const MWWorld::Ptr& ptr) const + std::string Container::getName (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mName; } @@ -231,10 +230,9 @@ namespace MWClass return (ref->mBase->mName != ""); } - MWGui::ToolTipInfo Container::getToolTipInfo (const MWWorld::Ptr& ptr) const + MWGui::ToolTipInfo Container::getToolTipInfo (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; info.caption = ref->mBase->mName; diff --git a/apps/openmw/mwclass/container.hpp b/apps/openmw/mwclass/container.hpp index 0c24ae03d..13593b1c0 100644 --- a/apps/openmw/mwclass/container.hpp +++ b/apps/openmw/mwclass/container.hpp @@ -23,7 +23,7 @@ namespace MWClass virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; - virtual std::string getName (const MWWorld::Ptr& ptr) const; + virtual std::string getName (const MWWorld::ConstPtr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. @@ -34,7 +34,7 @@ namespace MWClass virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr) const; + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. virtual MWWorld::ContainerStore& getContainerStore (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 9aa9871bb..fceae4060 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -188,10 +188,9 @@ namespace MWClass return ""; } - std::string Creature::getName (const MWWorld::Ptr& ptr) const + std::string Creature::getName (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mName; } @@ -521,10 +520,9 @@ namespace MWClass return ptr.getRefData().getCustomData()->asCreatureCustomData().mMovement; } - MWGui::ToolTipInfo Creature::getToolTipInfo (const MWWorld::Ptr& ptr) const + MWGui::ToolTipInfo Creature::getToolTipInfo (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; info.caption = ref->mBase->mName; diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index 70ffb3ba6..efb4715af 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -47,11 +47,11 @@ namespace MWClass virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual std::string getName (const MWWorld::Ptr& ptr) const; + virtual std::string getName (const MWWorld::ConstPtr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr) const; + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. virtual MWMechanics::CreatureStats& getCreatureStats (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/creaturelevlist.cpp b/apps/openmw/mwclass/creaturelevlist.cpp index 2e4aef2fa..9bd5f9537 100644 --- a/apps/openmw/mwclass/creaturelevlist.cpp +++ b/apps/openmw/mwclass/creaturelevlist.cpp @@ -34,7 +34,7 @@ namespace MWClass return ptr.get()->mBase->mId; } - std::string CreatureLevList::getName (const MWWorld::Ptr& ptr) const + std::string CreatureLevList::getName (const MWWorld::ConstPtr& ptr) const { return ""; } diff --git a/apps/openmw/mwclass/creaturelevlist.hpp b/apps/openmw/mwclass/creaturelevlist.hpp index 7e1b7828a..4ada3cd86 100644 --- a/apps/openmw/mwclass/creaturelevlist.hpp +++ b/apps/openmw/mwclass/creaturelevlist.hpp @@ -14,7 +14,7 @@ namespace MWClass /// Return ID of \a ptr virtual std::string getId (const MWWorld::Ptr& ptr) const; - virtual std::string getName (const MWWorld::Ptr& ptr) const; + virtual std::string getName (const MWWorld::ConstPtr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 7c3176d52..47116cd7b 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -91,10 +91,9 @@ namespace MWClass return ""; } - std::string Door::getName (const MWWorld::Ptr& ptr) const + std::string Door::getName (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mName; } @@ -239,10 +238,9 @@ namespace MWClass return (ref->mBase->mName != ""); } - MWGui::ToolTipInfo Door::getToolTipInfo (const MWWorld::Ptr& ptr) const + MWGui::ToolTipInfo Door::getToolTipInfo (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; info.caption = ref->mBase->mName; diff --git a/apps/openmw/mwclass/door.hpp b/apps/openmw/mwclass/door.hpp index c67c96e3e..384f38fa9 100644 --- a/apps/openmw/mwclass/door.hpp +++ b/apps/openmw/mwclass/door.hpp @@ -24,7 +24,7 @@ namespace MWClass virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; - virtual std::string getName (const MWWorld::Ptr& ptr) const; + virtual std::string getName (const MWWorld::ConstPtr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. @@ -35,7 +35,7 @@ namespace MWClass virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr) const; + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. static std::string getDestination (const MWWorld::LiveCellRef& door); diff --git a/apps/openmw/mwclass/ingredient.cpp b/apps/openmw/mwclass/ingredient.cpp index b7d1cf3d9..95cf00d94 100644 --- a/apps/openmw/mwclass/ingredient.cpp +++ b/apps/openmw/mwclass/ingredient.cpp @@ -56,10 +56,9 @@ namespace MWClass return ""; } - std::string Ingredient::getName (const MWWorld::Ptr& ptr) const + std::string Ingredient::getName (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mName; } @@ -77,10 +76,9 @@ namespace MWClass return ref->mBase->mScript; } - int Ingredient::getValue (const MWWorld::Ptr& ptr) const + int Ingredient::getValue (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mData.mValue; } @@ -128,10 +126,9 @@ namespace MWClass return (ref->mBase->mName != ""); } - MWGui::ToolTipInfo Ingredient::getToolTipInfo (const MWWorld::Ptr& ptr) const + MWGui::ToolTipInfo Ingredient::getToolTipInfo (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); diff --git a/apps/openmw/mwclass/ingredient.hpp b/apps/openmw/mwclass/ingredient.hpp index 00862a220..a6740a399 100644 --- a/apps/openmw/mwclass/ingredient.hpp +++ b/apps/openmw/mwclass/ingredient.hpp @@ -20,7 +20,7 @@ namespace MWClass virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; - virtual std::string getName (const MWWorld::Ptr& ptr) const; + virtual std::string getName (const MWWorld::ConstPtr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. @@ -31,13 +31,13 @@ namespace MWClass virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr) const; + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; ///< Return name of the script attached to ptr - virtual int getValue (const MWWorld::Ptr& ptr) const; + virtual int getValue (const MWWorld::ConstPtr& ptr) const; ///< Return trade value of the object. Throws an exception, if the object can't be traded. virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) diff --git a/apps/openmw/mwclass/itemlevlist.cpp b/apps/openmw/mwclass/itemlevlist.cpp index a70f31115..7690169c6 100644 --- a/apps/openmw/mwclass/itemlevlist.cpp +++ b/apps/openmw/mwclass/itemlevlist.cpp @@ -9,7 +9,7 @@ namespace MWClass return ptr.get()->mBase->mId; } - std::string ItemLevList::getName (const MWWorld::Ptr& ptr) const + std::string ItemLevList::getName (const MWWorld::ConstPtr& ptr) const { return ""; } diff --git a/apps/openmw/mwclass/itemlevlist.hpp b/apps/openmw/mwclass/itemlevlist.hpp index 2b507135f..8a95b9adb 100644 --- a/apps/openmw/mwclass/itemlevlist.hpp +++ b/apps/openmw/mwclass/itemlevlist.hpp @@ -12,7 +12,7 @@ namespace MWClass /// Return ID of \a ptr virtual std::string getId (const MWWorld::Ptr& ptr) const; - virtual std::string getName (const MWWorld::Ptr& ptr) const; + virtual std::string getName (const MWWorld::ConstPtr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 615f9fac0..eb1c3bcc2 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -72,10 +72,9 @@ namespace MWClass return ""; } - std::string Light::getName (const MWWorld::Ptr& ptr) const + std::string Light::getName (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); if (ref->mBase->mModel.empty()) return ""; @@ -116,10 +115,9 @@ namespace MWClass return std::make_pair (slots_, false); } - int Light::getValue (const MWWorld::Ptr& ptr) const + int Light::getValue (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mData.mValue; } @@ -158,10 +156,9 @@ namespace MWClass return (ref->mBase->mName != ""); } - MWGui::ToolTipInfo Light::getToolTipInfo (const MWWorld::Ptr& ptr) const + MWGui::ToolTipInfo Light::getToolTipInfo (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); @@ -201,9 +198,9 @@ namespace MWClass ptr.getCellRef().setChargeFloat(duration); } - float Light::getRemainingUsageTime (const MWWorld::Ptr& ptr) const + float Light::getRemainingUsageTime (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); if (ptr.getCellRef().getCharge() == -1) return static_cast(ref->mBase->mData.mTime); else diff --git a/apps/openmw/mwclass/light.hpp b/apps/openmw/mwclass/light.hpp index b7ef199b0..5e04fdb0b 100644 --- a/apps/openmw/mwclass/light.hpp +++ b/apps/openmw/mwclass/light.hpp @@ -20,14 +20,14 @@ namespace MWClass virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; - virtual std::string getName (const MWWorld::Ptr& ptr) const; + virtual std::string getName (const MWWorld::ConstPtr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr) const; + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. virtual boost::shared_ptr activate (const MWWorld::Ptr& ptr, @@ -41,7 +41,7 @@ namespace MWClass ///< \return first: Return IDs of the slot this object can be equipped in; second: can object /// stay stacked when equipped? - virtual int getValue (const MWWorld::Ptr& ptr) const; + virtual int getValue (const MWWorld::ConstPtr& ptr) const; ///< Return trade value of the object. Throws an exception, if the object can't be traded. static void registerSelf(); @@ -62,7 +62,7 @@ namespace MWClass virtual void setRemainingUsageTime (const MWWorld::Ptr& ptr, float duration) const; ///< Sets the remaining duration of the object. - virtual float getRemainingUsageTime (const MWWorld::Ptr& ptr) const; + virtual float getRemainingUsageTime (const MWWorld::ConstPtr& ptr) const; ///< Returns the remaining duration of the object. virtual std::string getModel(const MWWorld::Ptr &ptr) const; diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index 3fae74be9..858a01992 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -51,10 +51,9 @@ namespace MWClass return ""; } - std::string Lockpick::getName (const MWWorld::Ptr& ptr) const + std::string Lockpick::getName (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mName; } @@ -81,10 +80,9 @@ namespace MWClass return std::make_pair (slots_, false); } - int Lockpick::getValue (const MWWorld::Ptr& ptr) const + int Lockpick::getValue (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mData.mValue; } @@ -122,10 +120,9 @@ namespace MWClass return (ref->mBase->mName != ""); } - MWGui::ToolTipInfo Lockpick::getToolTipInfo (const MWWorld::Ptr& ptr) const + MWGui::ToolTipInfo Lockpick::getToolTipInfo (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); @@ -173,10 +170,9 @@ namespace MWClass return (npcServices & ESM::NPC::Picks) != 0; } - int Lockpick::getItemMaxHealth (const MWWorld::Ptr& ptr) const + int Lockpick::getItemMaxHealth (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mData.mUses; } diff --git a/apps/openmw/mwclass/lockpick.hpp b/apps/openmw/mwclass/lockpick.hpp index 7e7ee78d5..44333eb45 100644 --- a/apps/openmw/mwclass/lockpick.hpp +++ b/apps/openmw/mwclass/lockpick.hpp @@ -20,7 +20,7 @@ namespace MWClass virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; - virtual std::string getName (const MWWorld::Ptr& ptr) const; + virtual std::string getName (const MWWorld::ConstPtr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. @@ -31,7 +31,7 @@ namespace MWClass virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr) const; + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; @@ -41,7 +41,7 @@ namespace MWClass ///< \return first: Return IDs of the slot this object can be equipped in; second: can object /// stay stacked when equipped? - virtual int getValue (const MWWorld::Ptr& ptr) const; + virtual int getValue (const MWWorld::ConstPtr& ptr) const; ///< Return trade value of the object. Throws an exception, if the object can't be traded. static void registerSelf(); @@ -65,7 +65,7 @@ namespace MWClass virtual float getWeight (const MWWorld::Ptr& ptr) const; - virtual int getItemMaxHealth (const MWWorld::Ptr& ptr) const; + virtual int getItemMaxHealth (const MWWorld::ConstPtr& ptr) const; ///< Return item max health or throw an exception, if class does not have item health virtual bool hasItemHealth (const MWWorld::Ptr& ptr) const { return true; } diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index e5836bd96..57d5a1b1f 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -26,7 +26,7 @@ namespace MWClass { - bool Miscellaneous::isGold (const MWWorld::Ptr& ptr) const + bool Miscellaneous::isGold (const MWWorld::ConstPtr& ptr) const { return Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_001") || Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_005") @@ -64,10 +64,9 @@ namespace MWClass return ""; } - std::string Miscellaneous::getName (const MWWorld::Ptr& ptr) const + std::string Miscellaneous::getName (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mName; } @@ -85,10 +84,9 @@ namespace MWClass return ref->mBase->mScript; } - int Miscellaneous::getValue (const MWWorld::Ptr& ptr) const + int Miscellaneous::getValue (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); int value = ref->mBase->mData.mValue; if (ptr.getCellRef().getGoldValue() > 1 && ptr.getRefData().getCount() == 1) @@ -140,10 +138,9 @@ namespace MWClass return (ref->mBase->mName != ""); } - MWGui::ToolTipInfo Miscellaneous::getToolTipInfo (const MWWorld::Ptr& ptr) const + MWGui::ToolTipInfo Miscellaneous::getToolTipInfo (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; @@ -249,10 +246,9 @@ namespace MWClass return ref->mBase->mData.mWeight; } - bool Miscellaneous::isKey(const MWWorld::Ptr &ptr) const + bool Miscellaneous::isKey(const MWWorld::ConstPtr &ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mData.mIsKey != 0; } diff --git a/apps/openmw/mwclass/misc.hpp b/apps/openmw/mwclass/misc.hpp index e3215a6ad..a8ee52657 100644 --- a/apps/openmw/mwclass/misc.hpp +++ b/apps/openmw/mwclass/misc.hpp @@ -20,7 +20,7 @@ namespace MWClass virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; - virtual std::string getName (const MWWorld::Ptr& ptr) const; + virtual std::string getName (const MWWorld::ConstPtr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. @@ -31,13 +31,13 @@ namespace MWClass virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr) const; + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; ///< Return name of the script attached to ptr - virtual int getValue (const MWWorld::Ptr& ptr) const; + virtual int getValue (const MWWorld::ConstPtr& ptr) const; ///< Return trade value of the object. Throws an exception, if the object can't be traded. static void registerSelf(); @@ -61,9 +61,9 @@ namespace MWClass virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; - virtual bool isKey (const MWWorld::Ptr &ptr) const; + virtual bool isKey (const MWWorld::ConstPtr &ptr) const; - virtual bool isGold (const MWWorld::Ptr& ptr) const; + virtual bool isGold (const MWWorld::ConstPtr& ptr) const; }; } diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index bac555d1b..0d0978d37 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -252,6 +252,10 @@ namespace MWClass { return *this; } + virtual const NpcCustomData& asNpcCustomData() const + { + return *this; + } }; MWWorld::CustomData *NpcCustomData::clone() const @@ -436,9 +440,9 @@ namespace MWClass } - std::string Npc::getName (const MWWorld::Ptr& ptr) const + std::string Npc::getName (const MWWorld::ConstPtr& ptr) const { - if(getNpcStats(ptr).isWerewolf()) + if(ptr.getRefData().getCustomData() && ptr.getRefData().getCustomData()->asNpcCustomData().mNpcStats.isWerewolf()) { const MWBase::World *world = MWBase::Environment::get().getWorld(); const MWWorld::Store &store = world->getStore().get(); @@ -446,7 +450,7 @@ namespace MWClass return store.find("sWerewolfPopup")->getString(); } - MWWorld::LiveCellRef *ref = ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mName; } @@ -921,15 +925,15 @@ namespace MWClass registerClass (typeid (ESM::NPC).name(), instance); } - MWGui::ToolTipInfo Npc::getToolTipInfo (const MWWorld::Ptr& ptr) const + MWGui::ToolTipInfo Npc::getToolTipInfo (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); bool fullHelp = MWBase::Environment::get().getWindowManager()->getFullHelp(); MWGui::ToolTipInfo info; info.caption = getName(ptr); - if(fullHelp && getNpcStats(ptr).isWerewolf()) + if(fullHelp && ptr.getRefData().getCustomData() && ptr.getRefData().getCustomData()->asNpcCustomData().mNpcStats.isWerewolf()) { info.caption += " ("; info.caption += ref->mBase->mName; diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index 48277eb52..f5d9044a7 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -51,7 +51,7 @@ namespace MWClass virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual std::string getName (const MWWorld::Ptr& ptr) const; + virtual std::string getName (const MWWorld::ConstPtr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. @@ -64,7 +64,7 @@ namespace MWClass virtual MWWorld::ContainerStore& getContainerStore (const MWWorld::Ptr& ptr) const; ///< Return container store - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr) const; + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. virtual MWWorld::InventoryStore& getInventoryStore (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/potion.cpp b/apps/openmw/mwclass/potion.cpp index 9816c3cbc..34f9922ea 100644 --- a/apps/openmw/mwclass/potion.cpp +++ b/apps/openmw/mwclass/potion.cpp @@ -54,10 +54,9 @@ namespace MWClass return ""; } - std::string Potion::getName (const MWWorld::Ptr& ptr) const + std::string Potion::getName (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mName; } @@ -76,10 +75,9 @@ namespace MWClass return ref->mBase->mScript; } - int Potion::getValue (const MWWorld::Ptr& ptr) const + int Potion::getValue (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mData.mValue; } @@ -117,10 +115,9 @@ namespace MWClass return (ref->mBase->mName != ""); } - MWGui::ToolTipInfo Potion::getToolTipInfo (const MWWorld::Ptr& ptr) const + MWGui::ToolTipInfo Potion::getToolTipInfo (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); diff --git a/apps/openmw/mwclass/potion.hpp b/apps/openmw/mwclass/potion.hpp index a38205257..10083a7cf 100644 --- a/apps/openmw/mwclass/potion.hpp +++ b/apps/openmw/mwclass/potion.hpp @@ -20,7 +20,7 @@ namespace MWClass virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; - virtual std::string getName (const MWWorld::Ptr& ptr) const; + virtual std::string getName (const MWWorld::ConstPtr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. @@ -31,13 +31,13 @@ namespace MWClass virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr) const; + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; ///< Return name of the script attached to ptr - virtual int getValue (const MWWorld::Ptr& ptr) const; + virtual int getValue (const MWWorld::ConstPtr& ptr) const; ///< Return trade value of the object. Throws an exception, if the object can't be traded. virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index 0e3de75d4..8882af507 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -51,10 +51,9 @@ namespace MWClass return ""; } - std::string Probe::getName (const MWWorld::Ptr& ptr) const + std::string Probe::getName (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mName; } @@ -81,10 +80,9 @@ namespace MWClass return std::make_pair (slots_, false); } - int Probe::getValue (const MWWorld::Ptr& ptr) const + int Probe::getValue (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mData.mValue; } @@ -122,10 +120,9 @@ namespace MWClass return (ref->mBase->mName != ""); } - MWGui::ToolTipInfo Probe::getToolTipInfo (const MWWorld::Ptr& ptr) const + MWGui::ToolTipInfo Probe::getToolTipInfo (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); @@ -173,10 +170,9 @@ namespace MWClass return (npcServices & ESM::NPC::Probes) != 0; } - int Probe::getItemMaxHealth (const MWWorld::Ptr& ptr) const + int Probe::getItemMaxHealth (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mData.mUses; } diff --git a/apps/openmw/mwclass/probe.hpp b/apps/openmw/mwclass/probe.hpp index a6da5ab9d..69cf614fd 100644 --- a/apps/openmw/mwclass/probe.hpp +++ b/apps/openmw/mwclass/probe.hpp @@ -20,7 +20,7 @@ namespace MWClass virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; - virtual std::string getName (const MWWorld::Ptr& ptr) const; + virtual std::string getName (const MWWorld::ConstPtr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. @@ -31,7 +31,7 @@ namespace MWClass virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr) const; + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; @@ -41,7 +41,7 @@ namespace MWClass ///< \return first: Return IDs of the slot this object can be equipped in; second: can object /// stay stacked when equipped? - virtual int getValue (const MWWorld::Ptr& ptr) const; + virtual int getValue (const MWWorld::ConstPtr& ptr) const; ///< Return trade value of the object. Throws an exception, if the object can't be traded. static void registerSelf(); @@ -65,7 +65,7 @@ namespace MWClass virtual float getWeight (const MWWorld::Ptr& ptr) const; - virtual int getItemMaxHealth (const MWWorld::Ptr& ptr) const; + virtual int getItemMaxHealth (const MWWorld::ConstPtr& ptr) const; ///< Return item max health or throw an exception, if class does not have item health virtual bool hasItemHealth (const MWWorld::Ptr& ptr) const { return true; } diff --git a/apps/openmw/mwclass/repair.cpp b/apps/openmw/mwclass/repair.cpp index 700db167a..b52b06baf 100644 --- a/apps/openmw/mwclass/repair.cpp +++ b/apps/openmw/mwclass/repair.cpp @@ -50,10 +50,9 @@ namespace MWClass return ""; } - std::string Repair::getName (const MWWorld::Ptr& ptr) const + std::string Repair::getName (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mName; } @@ -72,10 +71,9 @@ namespace MWClass return ref->mBase->mScript; } - int Repair::getValue (const MWWorld::Ptr& ptr) const + int Repair::getValue (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mData.mValue; } @@ -118,18 +116,16 @@ namespace MWClass return true; } - int Repair::getItemMaxHealth (const MWWorld::Ptr& ptr) const + int Repair::getItemMaxHealth (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mData.mUses; } - MWGui::ToolTipInfo Repair::getToolTipInfo (const MWWorld::Ptr& ptr) const + MWGui::ToolTipInfo Repair::getToolTipInfo (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); diff --git a/apps/openmw/mwclass/repair.hpp b/apps/openmw/mwclass/repair.hpp index 3ec617bd3..ed17ff587 100644 --- a/apps/openmw/mwclass/repair.hpp +++ b/apps/openmw/mwclass/repair.hpp @@ -20,7 +20,7 @@ namespace MWClass virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; - virtual std::string getName (const MWWorld::Ptr& ptr) const; + virtual std::string getName (const MWWorld::ConstPtr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. @@ -31,13 +31,13 @@ namespace MWClass virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr) const; + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; ///< Return name of the script attached to ptr - virtual int getValue (const MWWorld::Ptr& ptr) const; + virtual int getValue (const MWWorld::ConstPtr& ptr) const; ///< Return trade value of the object. Throws an exception, if the object can't be traded. static void registerSelf(); @@ -61,7 +61,7 @@ namespace MWClass virtual bool hasItemHealth (const MWWorld::Ptr& ptr) const; ///< \return Item health data available? (default implementation: false) - virtual int getItemMaxHealth (const MWWorld::Ptr& ptr) const; + virtual int getItemMaxHealth (const MWWorld::ConstPtr& ptr) const; ///< Return item max health or throw an exception, if class does not have item health /// (default implementation: throw an exception) diff --git a/apps/openmw/mwclass/static.cpp b/apps/openmw/mwclass/static.cpp index 86019a5ad..f9d9f618a 100644 --- a/apps/openmw/mwclass/static.cpp +++ b/apps/openmw/mwclass/static.cpp @@ -42,7 +42,7 @@ namespace MWClass return ""; } - std::string Static::getName (const MWWorld::Ptr& ptr) const + std::string Static::getName (const MWWorld::ConstPtr& ptr) const { return ""; } diff --git a/apps/openmw/mwclass/static.hpp b/apps/openmw/mwclass/static.hpp index 3d78f949b..1748f86c6 100644 --- a/apps/openmw/mwclass/static.hpp +++ b/apps/openmw/mwclass/static.hpp @@ -20,7 +20,7 @@ namespace MWClass virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; - virtual std::string getName (const MWWorld::Ptr& ptr) const; + virtual std::string getName (const MWWorld::ConstPtr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index cc5d8ed59..e363c942e 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -54,10 +54,9 @@ namespace MWClass return ""; } - std::string Weapon::getName (const MWWorld::Ptr& ptr) const + std::string Weapon::getName (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mName; } @@ -76,10 +75,9 @@ namespace MWClass return (ref->mBase->mData.mType < 11); // thrown weapons and arrows/bolts don't have health, only quantity } - int Weapon::getItemMaxHealth (const MWWorld::Ptr& ptr) const + int Weapon::getItemMaxHealth (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mData.mHealth; } @@ -116,10 +114,9 @@ namespace MWClass return std::make_pair (slots_, stack); } - int Weapon::getEquipmentSkill (const MWWorld::Ptr& ptr) const + int Weapon::getEquipmentSkill (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); const int size = 12; @@ -146,10 +143,9 @@ namespace MWClass return -1; } - int Weapon::getValue (const MWWorld::Ptr& ptr) const + int Weapon::getValue (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mData.mValue; } @@ -267,10 +263,9 @@ namespace MWClass return (ref->mBase->mName != ""); } - MWGui::ToolTipInfo Weapon::getToolTipInfo (const MWWorld::Ptr& ptr) const + MWGui::ToolTipInfo Weapon::getToolTipInfo (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index 88282f5a3..916b61eae 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -20,7 +20,7 @@ namespace MWClass virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; - virtual std::string getName (const MWWorld::Ptr& ptr) const; + virtual std::string getName (const MWWorld::ConstPtr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. @@ -31,13 +31,13 @@ namespace MWClass virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr) const; + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. virtual bool hasItemHealth (const MWWorld::Ptr& ptr) const; ///< \return Item health data available? - virtual int getItemMaxHealth (const MWWorld::Ptr& ptr) const; + virtual int getItemMaxHealth (const MWWorld::ConstPtr& ptr) const; ///< Return item max health or throw an exception, if class does not have item health virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; @@ -47,11 +47,11 @@ namespace MWClass ///< \return first: Return IDs of the slot this object can be equipped in; second: can object /// stay stacked when equipped? - virtual int getEquipmentSkill (const MWWorld::Ptr& ptr) const; - /// Return the index of the skill this item corresponds to when equiopped or -1, if there is + virtual int getEquipmentSkill (const MWWorld::ConstPtr& ptr) const; + /// Return the index of the skill this item corresponds to when equipped or -1, if there is /// no such skill. - virtual int getValue (const MWWorld::Ptr& ptr) const; + virtual int getValue (const MWWorld::ConstPtr& ptr) const; ///< Return trade value of the object. Throws an exception, if the object can't be traded. static void registerSelf(); diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index f8d4fbde4..85a5a5720 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -80,7 +80,7 @@ namespace MWWorld return false; } - int Class::getItemHealth(const Ptr &ptr) const + int Class::getItemHealth(const ConstPtr &ptr) const { if (ptr.getCellRef().getCharge() == -1) return getItemMaxHealth(ptr); @@ -88,7 +88,7 @@ namespace MWWorld return ptr.getCellRef().getCharge(); } - int Class::getItemMaxHealth (const Ptr& ptr) const + int Class::getItemMaxHealth (const ConstPtr& ptr) const { throw std::runtime_error ("class does not have item health"); } @@ -153,7 +153,7 @@ namespace MWWorld throw std::runtime_error ("class does not support time-based uses"); } - float Class::getRemainingUsageTime (const Ptr& ptr) const + float Class::getRemainingUsageTime (const ConstPtr& ptr) const { return -1; } @@ -193,12 +193,12 @@ namespace MWWorld return std::make_pair (std::vector(), false); } - int Class::getEquipmentSkill (const Ptr& ptr) const + int Class::getEquipmentSkill (const ConstPtr& ptr) const { return -1; } - int Class::getValue (const Ptr& ptr) const + int Class::getValue (const ConstPtr& ptr) const { throw std::logic_error ("value not supported by this class"); } @@ -272,7 +272,7 @@ namespace MWWorld throw std::runtime_error ("class does not have any inventory icon"); } - MWGui::ToolTipInfo Class::getToolTipInfo (const Ptr& ptr) const + MWGui::ToolTipInfo Class::getToolTipInfo (const ConstPtr& ptr) const { throw std::runtime_error ("class does not have a tool tip"); } @@ -447,7 +447,7 @@ namespace MWWorld return -1; } - int Class::getEffectiveArmorRating(const Ptr &ptr, const Ptr &actor) const + int Class::getEffectiveArmorRating(const ConstPtr &armor, const Ptr &actor) const { throw std::runtime_error("class does not support armor ratings"); } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 38ca7fcc1..341094964 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -86,7 +86,7 @@ namespace MWWorld virtual void insertObject(const Ptr& ptr, const std::string& mesh, MWPhysics::PhysicsSystem& physics) const; ///< Add reference into a cell for rendering (default implementation: don't render anything). - virtual std::string getName (const Ptr& ptr) const = 0; + virtual std::string getName (const ConstPtr& ptr) const = 0; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. @@ -101,7 +101,7 @@ namespace MWWorld virtual bool hasToolTip (const Ptr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const Ptr& ptr) const; + virtual MWGui::ToolTipInfo getToolTipInfo (const ConstPtr& ptr) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. virtual MWMechanics::NpcStats& getNpcStats (const Ptr& ptr) const; @@ -111,10 +111,10 @@ namespace MWWorld virtual bool hasItemHealth (const Ptr& ptr) const; ///< \return Item health data available? (default implementation: false) - virtual int getItemHealth (const Ptr& ptr) const; + virtual int getItemHealth (const ConstPtr& ptr) const; ///< Return current item health or throw an exception if class does not have item health - virtual int getItemMaxHealth (const Ptr& ptr) const; + virtual int getItemMaxHealth (const ConstPtr& ptr) const; ///< Return item max health or throw an exception, if class does not have item health /// (default implementation: throw an exception) @@ -167,7 +167,7 @@ namespace MWWorld ///< Sets the remaining duration of the object, such as an equippable light /// source. (default implementation: throw an exception) - virtual float getRemainingUsageTime (const Ptr& ptr) const; + virtual float getRemainingUsageTime (const ConstPtr& ptr) const; ///< Returns the remaining duration of the object, such as an equippable light /// source. (default implementation: -1, i.e. infinite) @@ -193,13 +193,13 @@ namespace MWWorld /// /// Default implementation: return (empty vector, false). - virtual int getEquipmentSkill (const Ptr& ptr) + virtual int getEquipmentSkill (const ConstPtr& ptr) const; /// Return the index of the skill this item corresponds to when equiopped or -1, if there is /// no such skill. /// (default implementation: return -1) - virtual int getValue (const Ptr& ptr) const; + virtual int getValue (const ConstPtr& ptr) const; ///< Return trade value of the object. Throws an exception, if the object can't be traded. /// (default implementation: throws an exception) @@ -279,9 +279,9 @@ namespace MWWorld virtual bool isPersistent (const MWWorld::Ptr& ptr) const; - virtual bool isKey (const MWWorld::Ptr& ptr) const { return false; } + virtual bool isKey (const MWWorld::ConstPtr& ptr) const { return false; } - virtual bool isGold(const MWWorld::Ptr& ptr) const { return false; }; + virtual bool isGold(const MWWorld::ConstPtr& ptr) const { return false; }; /// Get a blood texture suitable for \a ptr (see Blood Texture 0-2 in Morrowind.ini) virtual int getBloodTexture (const MWWorld::Ptr& ptr) const; @@ -344,7 +344,7 @@ namespace MWWorld virtual int getPrimaryFactionRank (const MWWorld::Ptr& ptr) const; /// Get the effective armor rating, factoring in the actor's skills, for the given armor. - virtual int getEffectiveArmorRating(const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const; + virtual int getEffectiveArmorRating(const MWWorld::ConstPtr& armor, const MWWorld::Ptr& actor) const; }; } diff --git a/apps/openmw/mwworld/customdata.cpp b/apps/openmw/mwworld/customdata.cpp index 8edbb345f..dce1e9fdd 100644 --- a/apps/openmw/mwworld/customdata.cpp +++ b/apps/openmw/mwworld/customdata.cpp @@ -21,6 +21,13 @@ MWClass::NpcCustomData &CustomData::asNpcCustomData() throw std::logic_error(error.str()); } +const MWClass::NpcCustomData &CustomData::asNpcCustomData() const +{ + std::stringstream error; + error << "bad cast " << typeid(this).name() << " to NpcCustomData"; + throw std::logic_error(error.str()); +} + MWClass::ContainerCustomData &CustomData::asContainerCustomData() { std::stringstream error; diff --git a/apps/openmw/mwworld/customdata.hpp b/apps/openmw/mwworld/customdata.hpp index 8c3890580..407962ee0 100644 --- a/apps/openmw/mwworld/customdata.hpp +++ b/apps/openmw/mwworld/customdata.hpp @@ -26,6 +26,7 @@ namespace MWWorld virtual MWClass::CreatureCustomData& asCreatureCustomData(); virtual MWClass::NpcCustomData& asNpcCustomData(); + virtual const MWClass::NpcCustomData& asNpcCustomData() const; virtual MWClass::ContainerCustomData& asContainerCustomData(); From f258c5c508e1ecd3541952ccb9026913d39ce54e Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 15:51:05 +0100 Subject: [PATCH 2858/3725] Accept a ConstPtr in getModel --- apps/openmw/mwclass/activator.cpp | 6 ++---- apps/openmw/mwclass/activator.hpp | 2 +- apps/openmw/mwclass/apparatus.cpp | 6 ++---- apps/openmw/mwclass/apparatus.hpp | 2 +- apps/openmw/mwclass/armor.cpp | 6 ++---- apps/openmw/mwclass/armor.hpp | 2 +- apps/openmw/mwclass/book.cpp | 6 ++---- apps/openmw/mwclass/book.hpp | 2 +- apps/openmw/mwclass/clothing.cpp | 6 ++---- apps/openmw/mwclass/clothing.hpp | 2 +- apps/openmw/mwclass/container.cpp | 6 ++---- apps/openmw/mwclass/container.hpp | 2 +- apps/openmw/mwclass/creature.cpp | 6 ++---- apps/openmw/mwclass/creature.hpp | 2 +- apps/openmw/mwclass/door.cpp | 6 ++---- apps/openmw/mwclass/door.hpp | 2 +- apps/openmw/mwclass/ingredient.cpp | 6 ++---- apps/openmw/mwclass/ingredient.hpp | 2 +- apps/openmw/mwclass/light.cpp | 6 ++---- apps/openmw/mwclass/light.hpp | 2 +- apps/openmw/mwclass/lockpick.cpp | 6 ++---- apps/openmw/mwclass/lockpick.hpp | 2 +- apps/openmw/mwclass/misc.cpp | 6 ++---- apps/openmw/mwclass/misc.hpp | 2 +- apps/openmw/mwclass/npc.cpp | 7 ++----- apps/openmw/mwclass/npc.hpp | 2 +- apps/openmw/mwclass/potion.cpp | 6 ++---- apps/openmw/mwclass/potion.hpp | 2 +- apps/openmw/mwclass/probe.cpp | 6 ++---- apps/openmw/mwclass/probe.hpp | 2 +- apps/openmw/mwclass/repair.cpp | 6 ++---- apps/openmw/mwclass/repair.hpp | 2 +- apps/openmw/mwclass/static.cpp | 6 ++---- apps/openmw/mwclass/static.hpp | 2 +- apps/openmw/mwclass/weapon.cpp | 6 ++---- apps/openmw/mwclass/weapon.hpp | 2 +- apps/openmw/mwworld/class.cpp | 2 +- apps/openmw/mwworld/class.hpp | 2 +- 38 files changed, 56 insertions(+), 93 deletions(-) diff --git a/apps/openmw/mwclass/activator.cpp b/apps/openmw/mwclass/activator.cpp index 1ca1150df..fcf5dcfd7 100644 --- a/apps/openmw/mwclass/activator.cpp +++ b/apps/openmw/mwclass/activator.cpp @@ -45,11 +45,9 @@ namespace MWClass MWBase::Environment::get().getMechanicsManager()->add(ptr); } - std::string Activator::getModel(const MWWorld::Ptr &ptr) const + std::string Activator::getModel(const MWWorld::ConstPtr &ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); - assert(ref->mBase != NULL); + const MWWorld::LiveCellRef *ref = ptr.get(); const std::string &model = ref->mBase->mModel; if (!model.empty()) { diff --git a/apps/openmw/mwclass/activator.hpp b/apps/openmw/mwclass/activator.hpp index 4e371d8dd..7cdd9506c 100644 --- a/apps/openmw/mwclass/activator.hpp +++ b/apps/openmw/mwclass/activator.hpp @@ -39,7 +39,7 @@ namespace MWClass static void registerSelf(); - virtual std::string getModel(const MWWorld::Ptr &ptr) const; + virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; }; } diff --git a/apps/openmw/mwclass/apparatus.cpp b/apps/openmw/mwclass/apparatus.cpp index 3caf68aae..6a64b88c2 100644 --- a/apps/openmw/mwclass/apparatus.cpp +++ b/apps/openmw/mwclass/apparatus.cpp @@ -37,11 +37,9 @@ namespace MWClass // TODO: add option somewhere to enable collision for placeable objects } - std::string Apparatus::getModel(const MWWorld::Ptr &ptr) const + std::string Apparatus::getModel(const MWWorld::ConstPtr &ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); - assert(ref->mBase != NULL); + const MWWorld::LiveCellRef *ref = ptr.get(); const std::string &model = ref->mBase->mModel; if (!model.empty()) { diff --git a/apps/openmw/mwclass/apparatus.hpp b/apps/openmw/mwclass/apparatus.hpp index 32b58af07..fbbe676eb 100644 --- a/apps/openmw/mwclass/apparatus.hpp +++ b/apps/openmw/mwclass/apparatus.hpp @@ -58,7 +58,7 @@ namespace MWClass const; ///< Generate action for using via inventory menu - virtual std::string getModel(const MWWorld::Ptr &ptr) const; + virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; }; diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index c9369e1ae..a4206a0be 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -43,11 +43,9 @@ namespace MWClass // TODO: add option somewhere to enable collision for placeable objects } - std::string Armor::getModel(const MWWorld::Ptr &ptr) const + std::string Armor::getModel(const MWWorld::ConstPtr &ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); - assert(ref->mBase != NULL); + const MWWorld::LiveCellRef *ref = ptr.get(); const std::string &model = ref->mBase->mModel; if (!model.empty()) { diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index c989fcde0..a2dd0adc7 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -81,7 +81,7 @@ namespace MWClass const; ///< Generate action for using via inventory menu - virtual std::string getModel(const MWWorld::Ptr &ptr) const; + virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; virtual int getEnchantmentPoints (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index 49b53c480..f0e69eabf 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -40,11 +40,9 @@ namespace MWClass // TODO: add option somewhere to enable collision for placeable objects } - std::string Book::getModel(const MWWorld::Ptr &ptr) const + std::string Book::getModel(const MWWorld::ConstPtr &ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); - assert(ref->mBase != NULL); + const MWWorld::LiveCellRef *ref = ptr.get(); const std::string &model = ref->mBase->mModel; if (!model.empty()) { diff --git a/apps/openmw/mwclass/book.hpp b/apps/openmw/mwclass/book.hpp index a4f230219..38dc0ae7b 100644 --- a/apps/openmw/mwclass/book.hpp +++ b/apps/openmw/mwclass/book.hpp @@ -60,7 +60,7 @@ namespace MWClass virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; ///< Generate action for using via inventory menu - virtual std::string getModel(const MWWorld::Ptr &ptr) const; + virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; virtual int getEnchantmentPoints (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index faa776e3a..ee75676bd 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -39,11 +39,9 @@ namespace MWClass // TODO: add option somewhere to enable collision for placeable objects } - std::string Clothing::getModel(const MWWorld::Ptr &ptr) const + std::string Clothing::getModel(const MWWorld::ConstPtr &ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); - assert(ref->mBase != NULL); + const MWWorld::LiveCellRef *ref = ptr.get(); const std::string &model = ref->mBase->mModel; if (!model.empty()) { diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index 30d16f0d7..655a38742 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -73,7 +73,7 @@ namespace MWClass const; ///< Generate action for using via inventory menu - virtual std::string getModel(const MWWorld::Ptr &ptr) const; + virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; virtual int getEnchantmentPoints (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index 9c39c9df1..c70228bae 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -107,11 +107,9 @@ namespace MWClass MWBase::Environment::get().getMechanicsManager()->add(ptr); } - std::string Container::getModel(const MWWorld::Ptr &ptr) const + std::string Container::getModel(const MWWorld::ConstPtr &ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); - assert(ref->mBase != NULL); + const MWWorld::LiveCellRef *ref = ptr.get(); const std::string &model = ref->mBase->mModel; if (!model.empty()) { diff --git a/apps/openmw/mwclass/container.hpp b/apps/openmw/mwclass/container.hpp index 13593b1c0..c6a23df6c 100644 --- a/apps/openmw/mwclass/container.hpp +++ b/apps/openmw/mwclass/container.hpp @@ -73,7 +73,7 @@ namespace MWClass virtual void restock (const MWWorld::Ptr &ptr) const; - virtual std::string getModel(const MWWorld::Ptr &ptr) const; + virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; }; } diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index fceae4060..1072a2435 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -175,11 +175,9 @@ namespace MWClass objects.insertCreature(ptr, model, hasInventoryStore(ptr)); } - std::string Creature::getModel(const MWWorld::Ptr &ptr) const + std::string Creature::getModel(const MWWorld::ConstPtr &ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); - assert (ref->mBase != NULL); + const MWWorld::LiveCellRef *ref = ptr.get(); const std::string &model = ref->mBase->mModel; if (!model.empty()) { diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index efb4715af..47e886c01 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -100,7 +100,7 @@ namespace MWClass static void registerSelf(); - virtual std::string getModel(const MWWorld::Ptr &ptr) const; + virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; virtual bool isActor() const { diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 47116cd7b..3e6f2b956 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -78,11 +78,9 @@ namespace MWClass MWBase::Environment::get().getMechanicsManager()->add(ptr); } - std::string Door::getModel(const MWWorld::Ptr &ptr) const + std::string Door::getModel(const MWWorld::ConstPtr &ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); - assert(ref->mBase != NULL); + const MWWorld::LiveCellRef *ref = ptr.get(); const std::string &model = ref->mBase->mModel; if (!model.empty()) { diff --git a/apps/openmw/mwclass/door.hpp b/apps/openmw/mwclass/door.hpp index 384f38fa9..6cb297ca5 100644 --- a/apps/openmw/mwclass/door.hpp +++ b/apps/openmw/mwclass/door.hpp @@ -54,7 +54,7 @@ namespace MWClass static void registerSelf(); - virtual std::string getModel(const MWWorld::Ptr &ptr) const; + virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; /// 0 = nothing, 1 = opening, 2 = closing virtual int getDoorState (const MWWorld::Ptr &ptr) const; diff --git a/apps/openmw/mwclass/ingredient.cpp b/apps/openmw/mwclass/ingredient.cpp index 95cf00d94..f871095c7 100644 --- a/apps/openmw/mwclass/ingredient.cpp +++ b/apps/openmw/mwclass/ingredient.cpp @@ -43,11 +43,9 @@ namespace MWClass // TODO: add option somewhere to enable collision for placeable objects } - std::string Ingredient::getModel(const MWWorld::Ptr &ptr) const + std::string Ingredient::getModel(const MWWorld::ConstPtr &ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); - assert(ref->mBase != NULL); + const MWWorld::LiveCellRef *ref = ptr.get(); const std::string &model = ref->mBase->mModel; if (!model.empty()) { diff --git a/apps/openmw/mwclass/ingredient.hpp b/apps/openmw/mwclass/ingredient.hpp index a6740a399..7f1e53ca6 100644 --- a/apps/openmw/mwclass/ingredient.hpp +++ b/apps/openmw/mwclass/ingredient.hpp @@ -55,7 +55,7 @@ namespace MWClass virtual std::string getInventoryIcon (const MWWorld::Ptr& ptr) const; ///< Return name of inventory icon. - virtual std::string getModel(const MWWorld::Ptr &ptr) const; + virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; virtual float getWeight (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index eb1c3bcc2..8c0a05b96 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -59,11 +59,9 @@ namespace MWClass MWBase::Environment::get().getMechanicsManager()->add(ptr); } - std::string Light::getModel(const MWWorld::Ptr &ptr) const + std::string Light::getModel(const MWWorld::ConstPtr &ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); - assert (ref->mBase != NULL); + const MWWorld::LiveCellRef *ref = ptr.get(); const std::string &model = ref->mBase->mModel; if (!model.empty()) { diff --git a/apps/openmw/mwclass/light.hpp b/apps/openmw/mwclass/light.hpp index 5e04fdb0b..3cc005429 100644 --- a/apps/openmw/mwclass/light.hpp +++ b/apps/openmw/mwclass/light.hpp @@ -65,7 +65,7 @@ namespace MWClass virtual float getRemainingUsageTime (const MWWorld::ConstPtr& ptr) const; ///< Returns the remaining duration of the object. - virtual std::string getModel(const MWWorld::Ptr &ptr) const; + virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; virtual float getWeight (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index 858a01992..53bcb9707 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -38,11 +38,9 @@ namespace MWClass // TODO: add option somewhere to enable collision for placeable objects } - std::string Lockpick::getModel(const MWWorld::Ptr &ptr) const + std::string Lockpick::getModel(const MWWorld::ConstPtr &ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); - assert(ref->mBase != NULL); + const MWWorld::LiveCellRef *ref = ptr.get(); const std::string &model = ref->mBase->mModel; if (!model.empty()) { diff --git a/apps/openmw/mwclass/lockpick.hpp b/apps/openmw/mwclass/lockpick.hpp index 44333eb45..565477b8b 100644 --- a/apps/openmw/mwclass/lockpick.hpp +++ b/apps/openmw/mwclass/lockpick.hpp @@ -59,7 +59,7 @@ namespace MWClass const; ///< Generate action for using via inventory menu - virtual std::string getModel(const MWWorld::Ptr &ptr) const; + virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index 57d5a1b1f..da8f48c38 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -51,11 +51,9 @@ namespace MWClass // TODO: add option somewhere to enable collision for placeable objects } - std::string Miscellaneous::getModel(const MWWorld::Ptr &ptr) const + std::string Miscellaneous::getModel(const MWWorld::ConstPtr &ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); - assert(ref->mBase != NULL); + const MWWorld::LiveCellRef *ref = ptr.get(); const std::string &model = ref->mBase->mModel; if (!model.empty()) { diff --git a/apps/openmw/mwclass/misc.hpp b/apps/openmw/mwclass/misc.hpp index a8ee52657..b2c7b5c76 100644 --- a/apps/openmw/mwclass/misc.hpp +++ b/apps/openmw/mwclass/misc.hpp @@ -51,7 +51,7 @@ namespace MWClass virtual std::string getInventoryIcon (const MWWorld::Ptr& ptr) const; ///< Return name of inventory icon. - virtual std::string getModel(const MWWorld::Ptr &ptr) const; + virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 0d0978d37..0dc97df87 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -425,11 +425,9 @@ namespace MWClass return ref->mBase->mPersistent; } - std::string Npc::getModel(const MWWorld::Ptr &ptr) const + std::string Npc::getModel(const MWWorld::ConstPtr &ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); - assert(ref->mBase != NULL); + const MWWorld::LiveCellRef *ref = ptr.get(); std::string model = "meshes\\base_anim.nif"; const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get().find(ref->mBase->mRace); @@ -437,7 +435,6 @@ namespace MWClass model = "meshes\\base_animkna.nif"; return model; - } std::string Npc::getName (const MWWorld::ConstPtr& ptr) const diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index f5d9044a7..aac93ab6e 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -126,7 +126,7 @@ namespace MWClass static void registerSelf(); - virtual std::string getModel(const MWWorld::Ptr &ptr) const; + virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; virtual int getSkill(const MWWorld::Ptr& ptr, int skill) const; diff --git a/apps/openmw/mwclass/potion.cpp b/apps/openmw/mwclass/potion.cpp index 34f9922ea..7c499c7bc 100644 --- a/apps/openmw/mwclass/potion.cpp +++ b/apps/openmw/mwclass/potion.cpp @@ -41,11 +41,9 @@ namespace MWClass // TODO: add option somewhere to enable collision for placeable objects } - std::string Potion::getModel(const MWWorld::Ptr &ptr) const + std::string Potion::getModel(const MWWorld::ConstPtr &ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); - assert(ref->mBase != NULL); + const MWWorld::LiveCellRef *ref = ptr.get(); const std::string &model = ref->mBase->mModel; if (!model.empty()) { diff --git a/apps/openmw/mwclass/potion.hpp b/apps/openmw/mwclass/potion.hpp index 10083a7cf..d884277ce 100644 --- a/apps/openmw/mwclass/potion.hpp +++ b/apps/openmw/mwclass/potion.hpp @@ -54,7 +54,7 @@ namespace MWClass virtual std::string getInventoryIcon (const MWWorld::Ptr& ptr) const; ///< Return name of inventory icon. - virtual std::string getModel(const MWWorld::Ptr &ptr) const; + virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; virtual float getWeight (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index 8882af507..24d64c613 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -38,11 +38,9 @@ namespace MWClass // TODO: add option somewhere to enable collision for placeable objects } - std::string Probe::getModel(const MWWorld::Ptr &ptr) const + std::string Probe::getModel(const MWWorld::ConstPtr &ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); - assert(ref->mBase != NULL); + const MWWorld::LiveCellRef *ref = ptr.get(); const std::string &model = ref->mBase->mModel; if (!model.empty()) { diff --git a/apps/openmw/mwclass/probe.hpp b/apps/openmw/mwclass/probe.hpp index 69cf614fd..9a8c67789 100644 --- a/apps/openmw/mwclass/probe.hpp +++ b/apps/openmw/mwclass/probe.hpp @@ -59,7 +59,7 @@ namespace MWClass const; ///< Generate action for using via inventory menu - virtual std::string getModel(const MWWorld::Ptr &ptr) const; + virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; diff --git a/apps/openmw/mwclass/repair.cpp b/apps/openmw/mwclass/repair.cpp index b52b06baf..038162c92 100644 --- a/apps/openmw/mwclass/repair.cpp +++ b/apps/openmw/mwclass/repair.cpp @@ -37,11 +37,9 @@ namespace MWClass // TODO: add option somewhere to enable collision for placeable objects } - std::string Repair::getModel(const MWWorld::Ptr &ptr) const + std::string Repair::getModel(const MWWorld::ConstPtr &ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); - assert(ref->mBase != NULL); + const MWWorld::LiveCellRef *ref = ptr.get(); const std::string &model = ref->mBase->mModel; if (!model.empty()) { diff --git a/apps/openmw/mwclass/repair.hpp b/apps/openmw/mwclass/repair.hpp index ed17ff587..b52677d68 100644 --- a/apps/openmw/mwclass/repair.hpp +++ b/apps/openmw/mwclass/repair.hpp @@ -51,7 +51,7 @@ namespace MWClass virtual std::string getInventoryIcon (const MWWorld::Ptr& ptr) const; ///< Return name of inventory icon. - virtual std::string getModel(const MWWorld::Ptr &ptr) const; + virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/static.cpp b/apps/openmw/mwclass/static.cpp index f9d9f618a..5539f8375 100644 --- a/apps/openmw/mwclass/static.cpp +++ b/apps/openmw/mwclass/static.cpp @@ -29,11 +29,9 @@ namespace MWClass physics.addObject(ptr, model); } - std::string Static::getModel(const MWWorld::Ptr &ptr) const + std::string Static::getModel(const MWWorld::ConstPtr &ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); - assert(ref->mBase != NULL); + const MWWorld::LiveCellRef *ref = ptr.get(); const std::string &model = ref->mBase->mModel; if (!model.empty()) { diff --git a/apps/openmw/mwclass/static.hpp b/apps/openmw/mwclass/static.hpp index 1748f86c6..9c4a61410 100644 --- a/apps/openmw/mwclass/static.hpp +++ b/apps/openmw/mwclass/static.hpp @@ -26,7 +26,7 @@ namespace MWClass static void registerSelf(); - virtual std::string getModel(const MWWorld::Ptr &ptr) const; + virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; }; } diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index e363c942e..438497024 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -41,11 +41,9 @@ namespace MWClass // TODO: add option somewhere to enable collision for placeable objects } - std::string Weapon::getModel(const MWWorld::Ptr &ptr) const + std::string Weapon::getModel(const MWWorld::ConstPtr &ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); - assert(ref->mBase != NULL); + const MWWorld::LiveCellRef *ref = ptr.get(); const std::string &model = ref->mBase->mModel; if (!model.empty()) { diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index 916b61eae..877de41d3 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -79,7 +79,7 @@ namespace MWClass const; ///< Generate action for using via inventory menu - virtual std::string getModel(const MWWorld::Ptr &ptr) const; + virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 85a5a5720..2e6b74abc 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -291,7 +291,7 @@ namespace MWWorld { } - std::string Class::getModel(const MWWorld::Ptr &ptr) const + std::string Class::getModel(const MWWorld::ConstPtr &ptr) const { return ""; } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 341094964..9d1190a04 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -266,7 +266,7 @@ namespace MWWorld virtual int getServices (const MWWorld::Ptr& actor) const; - virtual std::string getModel(const MWWorld::Ptr &ptr) const; + virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; virtual std::string applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; ///< Creates a new record using \a ptr as template, with the given name and the given enchantment applied to it. From beb8805a12a0b53a972f46db9e10f30f80e89714 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 15:53:47 +0100 Subject: [PATCH 2859/3725] Accept a ConstPtr in getInventoryIcon --- apps/openmw/mwclass/apparatus.cpp | 5 ++--- apps/openmw/mwclass/apparatus.hpp | 2 +- apps/openmw/mwclass/armor.cpp | 5 ++--- apps/openmw/mwclass/armor.hpp | 2 +- apps/openmw/mwclass/book.cpp | 5 ++--- apps/openmw/mwclass/book.hpp | 2 +- apps/openmw/mwclass/clothing.cpp | 5 ++--- apps/openmw/mwclass/clothing.hpp | 2 +- apps/openmw/mwclass/ingredient.cpp | 5 ++--- apps/openmw/mwclass/ingredient.hpp | 2 +- apps/openmw/mwclass/light.cpp | 5 ++--- apps/openmw/mwclass/light.hpp | 2 +- apps/openmw/mwclass/lockpick.cpp | 5 ++--- apps/openmw/mwclass/lockpick.hpp | 2 +- apps/openmw/mwclass/misc.cpp | 5 ++--- apps/openmw/mwclass/misc.hpp | 2 +- apps/openmw/mwclass/potion.cpp | 5 ++--- apps/openmw/mwclass/potion.hpp | 2 +- apps/openmw/mwclass/probe.cpp | 5 ++--- apps/openmw/mwclass/probe.hpp | 2 +- apps/openmw/mwclass/repair.cpp | 5 ++--- apps/openmw/mwclass/repair.hpp | 2 +- apps/openmw/mwclass/weapon.cpp | 5 ++--- apps/openmw/mwclass/weapon.hpp | 2 +- apps/openmw/mwworld/class.cpp | 2 +- apps/openmw/mwworld/class.hpp | 2 +- 26 files changed, 38 insertions(+), 50 deletions(-) diff --git a/apps/openmw/mwclass/apparatus.cpp b/apps/openmw/mwclass/apparatus.cpp index 6a64b88c2..323ebfa63 100644 --- a/apps/openmw/mwclass/apparatus.cpp +++ b/apps/openmw/mwclass/apparatus.cpp @@ -92,10 +92,9 @@ namespace MWClass return std::string("Item Apparatus Down"); } - std::string Apparatus::getInventoryIcon (const MWWorld::Ptr& ptr) const + std::string Apparatus::getInventoryIcon (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mIcon; } diff --git a/apps/openmw/mwclass/apparatus.hpp b/apps/openmw/mwclass/apparatus.hpp index fbbe676eb..82dff46ff 100644 --- a/apps/openmw/mwclass/apparatus.hpp +++ b/apps/openmw/mwclass/apparatus.hpp @@ -51,7 +51,7 @@ namespace MWClass virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; ///< Return the put down sound Id - virtual std::string getInventoryIcon (const MWWorld::Ptr& ptr) const; + virtual std::string getInventoryIcon (const MWWorld::ConstPtr& ptr) const; ///< Return name of inventory icon. virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index a4206a0be..e366ed591 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -199,10 +199,9 @@ namespace MWClass return std::string("Item Armor Heavy Down"); } - std::string Armor::getInventoryIcon (const MWWorld::Ptr& ptr) const + std::string Armor::getInventoryIcon (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mIcon; } diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index a2dd0adc7..5857c01a1 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -64,7 +64,7 @@ namespace MWClass virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; ///< Return the put down sound Id - virtual std::string getInventoryIcon (const MWWorld::Ptr& ptr) const; + virtual std::string getInventoryIcon (const MWWorld::ConstPtr& ptr) const; ///< Return name of inventory icon. virtual std::string getEnchantment (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index f0e69eabf..6ce07b50d 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -106,10 +106,9 @@ namespace MWClass return std::string("Item Book Down"); } - std::string Book::getInventoryIcon (const MWWorld::Ptr& ptr) const + std::string Book::getInventoryIcon (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mIcon; } diff --git a/apps/openmw/mwclass/book.hpp b/apps/openmw/mwclass/book.hpp index 38dc0ae7b..14a41b210 100644 --- a/apps/openmw/mwclass/book.hpp +++ b/apps/openmw/mwclass/book.hpp @@ -48,7 +48,7 @@ namespace MWClass virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; ///< Return the put down sound Id - virtual std::string getInventoryIcon (const MWWorld::Ptr& ptr) const; + virtual std::string getInventoryIcon (const MWWorld::ConstPtr& ptr) const; ///< Return name of inventory icon. virtual std::string getEnchantment (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index ee75676bd..0cec71d05 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -158,10 +158,9 @@ namespace MWClass return std::string("Item Clothes Down"); } - std::string Clothing::getInventoryIcon (const MWWorld::Ptr& ptr) const + std::string Clothing::getInventoryIcon (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mIcon; } diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index 655a38742..fc2fa800b 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -56,7 +56,7 @@ namespace MWClass virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; ///< Return the put down sound Id - virtual std::string getInventoryIcon (const MWWorld::Ptr& ptr) const; + virtual std::string getInventoryIcon (const MWWorld::ConstPtr& ptr) const; ///< Return name of inventory icon. virtual std::string getEnchantment (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/ingredient.cpp b/apps/openmw/mwclass/ingredient.cpp index f871095c7..3a2cdfc15 100644 --- a/apps/openmw/mwclass/ingredient.cpp +++ b/apps/openmw/mwclass/ingredient.cpp @@ -108,10 +108,9 @@ namespace MWClass return std::string("Item Ingredient Down"); } - std::string Ingredient::getInventoryIcon (const MWWorld::Ptr& ptr) const + std::string Ingredient::getInventoryIcon (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mIcon; } diff --git a/apps/openmw/mwclass/ingredient.hpp b/apps/openmw/mwclass/ingredient.hpp index 7f1e53ca6..309917c44 100644 --- a/apps/openmw/mwclass/ingredient.hpp +++ b/apps/openmw/mwclass/ingredient.hpp @@ -52,7 +52,7 @@ namespace MWClass virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; ///< Return the put down sound Id - virtual std::string getInventoryIcon (const MWWorld::Ptr& ptr) const; + virtual std::string getInventoryIcon (const MWWorld::ConstPtr& ptr) const; ///< Return name of inventory icon. virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 8c0a05b96..fc3f4e5c5 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -138,10 +138,9 @@ namespace MWClass } - std::string Light::getInventoryIcon (const MWWorld::Ptr& ptr) const + std::string Light::getInventoryIcon (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mIcon; } diff --git a/apps/openmw/mwclass/light.hpp b/apps/openmw/mwclass/light.hpp index 3cc005429..68529e2d0 100644 --- a/apps/openmw/mwclass/light.hpp +++ b/apps/openmw/mwclass/light.hpp @@ -52,7 +52,7 @@ namespace MWClass virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; ///< Return the put down sound Id - virtual std::string getInventoryIcon (const MWWorld::Ptr& ptr) const; + virtual std::string getInventoryIcon (const MWWorld::ConstPtr& ptr) const; ///< Return name of inventory icon. virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index 53bcb9707..d26585ed3 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -102,10 +102,9 @@ namespace MWClass return std::string("Item Lockpick Down"); } - std::string Lockpick::getInventoryIcon (const MWWorld::Ptr& ptr) const + std::string Lockpick::getInventoryIcon (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mIcon; } diff --git a/apps/openmw/mwclass/lockpick.hpp b/apps/openmw/mwclass/lockpick.hpp index 565477b8b..fa24c0c00 100644 --- a/apps/openmw/mwclass/lockpick.hpp +++ b/apps/openmw/mwclass/lockpick.hpp @@ -52,7 +52,7 @@ namespace MWClass virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; ///< Return the put down sound Id - virtual std::string getInventoryIcon (const MWWorld::Ptr& ptr) const; + virtual std::string getInventoryIcon (const MWWorld::ConstPtr& ptr) const; ///< Return name of inventory icon. virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index da8f48c38..a29142f07 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -120,10 +120,9 @@ namespace MWClass return std::string("Item Misc Down"); } - std::string Miscellaneous::getInventoryIcon (const MWWorld::Ptr& ptr) const + std::string Miscellaneous::getInventoryIcon (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mIcon; } diff --git a/apps/openmw/mwclass/misc.hpp b/apps/openmw/mwclass/misc.hpp index b2c7b5c76..9583ce2da 100644 --- a/apps/openmw/mwclass/misc.hpp +++ b/apps/openmw/mwclass/misc.hpp @@ -48,7 +48,7 @@ namespace MWClass virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; ///< Return the put down sound Id - virtual std::string getInventoryIcon (const MWWorld::Ptr& ptr) const; + virtual std::string getInventoryIcon (const MWWorld::ConstPtr& ptr) const; ///< Return name of inventory icon. virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; diff --git a/apps/openmw/mwclass/potion.cpp b/apps/openmw/mwclass/potion.cpp index 7c499c7bc..cf83089d2 100644 --- a/apps/openmw/mwclass/potion.cpp +++ b/apps/openmw/mwclass/potion.cpp @@ -97,10 +97,9 @@ namespace MWClass return std::string("Item Potion Down"); } - std::string Potion::getInventoryIcon (const MWWorld::Ptr& ptr) const + std::string Potion::getInventoryIcon (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mIcon; } diff --git a/apps/openmw/mwclass/potion.hpp b/apps/openmw/mwclass/potion.hpp index d884277ce..e0cc2722b 100644 --- a/apps/openmw/mwclass/potion.hpp +++ b/apps/openmw/mwclass/potion.hpp @@ -51,7 +51,7 @@ namespace MWClass virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; ///< Return the put down sound Id - virtual std::string getInventoryIcon (const MWWorld::Ptr& ptr) const; + virtual std::string getInventoryIcon (const MWWorld::ConstPtr& ptr) const; ///< Return name of inventory icon. virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index 24d64c613..53403e10a 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -102,10 +102,9 @@ namespace MWClass return std::string("Item Probe Down"); } - std::string Probe::getInventoryIcon (const MWWorld::Ptr& ptr) const + std::string Probe::getInventoryIcon (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mIcon; } diff --git a/apps/openmw/mwclass/probe.hpp b/apps/openmw/mwclass/probe.hpp index 9a8c67789..fccb94ebb 100644 --- a/apps/openmw/mwclass/probe.hpp +++ b/apps/openmw/mwclass/probe.hpp @@ -52,7 +52,7 @@ namespace MWClass virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; ///< Return the put down sound Id - virtual std::string getInventoryIcon (const MWWorld::Ptr& ptr) const; + virtual std::string getInventoryIcon (const MWWorld::ConstPtr& ptr) const; ///< Return name of inventory icon. virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) diff --git a/apps/openmw/mwclass/repair.cpp b/apps/openmw/mwclass/repair.cpp index 038162c92..5e8cbad53 100644 --- a/apps/openmw/mwclass/repair.cpp +++ b/apps/openmw/mwclass/repair.cpp @@ -93,10 +93,9 @@ namespace MWClass return std::string("Item Repair Down"); } - std::string Repair::getInventoryIcon (const MWWorld::Ptr& ptr) const + std::string Repair::getInventoryIcon (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mIcon; } diff --git a/apps/openmw/mwclass/repair.hpp b/apps/openmw/mwclass/repair.hpp index b52677d68..06ccf8c35 100644 --- a/apps/openmw/mwclass/repair.hpp +++ b/apps/openmw/mwclass/repair.hpp @@ -48,7 +48,7 @@ namespace MWClass virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; ///< Return the put down sound Id - virtual std::string getInventoryIcon (const MWWorld::Ptr& ptr) const; + virtual std::string getInventoryIcon (const MWWorld::ConstPtr& ptr) const; ///< Return name of inventory icon. virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index 438497024..8752d0b33 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -245,10 +245,9 @@ namespace MWClass return std::string("Item Misc Down"); } - std::string Weapon::getInventoryIcon (const MWWorld::Ptr& ptr) const + std::string Weapon::getInventoryIcon (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mIcon; } diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index 877de41d3..73e4aa2de 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -62,7 +62,7 @@ namespace MWClass virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; ///< Return the put down sound Id - virtual std::string getInventoryIcon (const MWWorld::Ptr& ptr) const; + virtual std::string getInventoryIcon (const MWWorld::ConstPtr& ptr) const; ///< Return name of inventory icon. virtual std::string getEnchantment (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 2e6b74abc..e7c86f65d 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -267,7 +267,7 @@ namespace MWWorld throw std::runtime_error("class does not support soundgen look up"); } - std::string Class::getInventoryIcon (const MWWorld::Ptr& ptr) const + std::string Class::getInventoryIcon (const MWWorld::ConstPtr& ptr) const { throw std::runtime_error ("class does not have any inventory icon"); } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 9d1190a04..321f64615 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -248,7 +248,7 @@ namespace MWWorld virtual float getArmorRating (const MWWorld::Ptr& ptr) const; ///< @return combined armor rating of this actor - virtual std::string getInventoryIcon (const MWWorld::Ptr& ptr) const; + virtual std::string getInventoryIcon (const MWWorld::ConstPtr& ptr) const; ///< Return name of inventory icon. virtual std::string getEnchantment (const MWWorld::Ptr& ptr) const; From 2bc851c7d3356c77edff589f368074d6666dc3be Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 15:56:45 +0100 Subject: [PATCH 2860/3725] Accept a ConstPtr in getEnchantment --- apps/openmw/mwclass/armor.cpp | 5 ++--- apps/openmw/mwclass/armor.hpp | 2 +- apps/openmw/mwclass/book.cpp | 5 ++--- apps/openmw/mwclass/book.hpp | 2 +- apps/openmw/mwclass/clothing.cpp | 5 ++--- apps/openmw/mwclass/clothing.hpp | 2 +- apps/openmw/mwclass/weapon.cpp | 5 ++--- apps/openmw/mwclass/weapon.hpp | 2 +- apps/openmw/mwworld/class.cpp | 2 +- apps/openmw/mwworld/class.hpp | 2 +- 10 files changed, 14 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index e366ed591..f575f9955 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -258,10 +258,9 @@ namespace MWClass return info; } - std::string Armor::getEnchantment (const MWWorld::Ptr& ptr) const + std::string Armor::getEnchantment (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mEnchant; } diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index 5857c01a1..b5ec11445 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -67,7 +67,7 @@ namespace MWClass virtual std::string getInventoryIcon (const MWWorld::ConstPtr& ptr) const; ///< Return name of inventory icon. - virtual std::string getEnchantment (const MWWorld::Ptr& ptr) const; + virtual std::string getEnchantment (const MWWorld::ConstPtr& ptr) const; ///< @return the enchantment ID if the object is enchanted, otherwise an empty string virtual std::string applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index 6ce07b50d..d4e67fdbe 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -146,10 +146,9 @@ namespace MWClass return info; } - std::string Book::getEnchantment (const MWWorld::Ptr& ptr) const + std::string Book::getEnchantment (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mEnchant; } diff --git a/apps/openmw/mwclass/book.hpp b/apps/openmw/mwclass/book.hpp index 14a41b210..b70b3b5f5 100644 --- a/apps/openmw/mwclass/book.hpp +++ b/apps/openmw/mwclass/book.hpp @@ -51,7 +51,7 @@ namespace MWClass virtual std::string getInventoryIcon (const MWWorld::ConstPtr& ptr) const; ///< Return name of inventory icon. - virtual std::string getEnchantment (const MWWorld::Ptr& ptr) const; + virtual std::string getEnchantment (const MWWorld::ConstPtr& ptr) const; ///< @return the enchantment ID if the object is enchanted, otherwise an empty string virtual std::string applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index 0cec71d05..1316fabd2 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -200,10 +200,9 @@ namespace MWClass return info; } - std::string Clothing::getEnchantment (const MWWorld::Ptr& ptr) const + std::string Clothing::getEnchantment (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mEnchant; } diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index fc2fa800b..3ad0b12f9 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -59,7 +59,7 @@ namespace MWClass virtual std::string getInventoryIcon (const MWWorld::ConstPtr& ptr) const; ///< Return name of inventory icon. - virtual std::string getEnchantment (const MWWorld::Ptr& ptr) const; + virtual std::string getEnchantment (const MWWorld::ConstPtr& ptr) const; ///< @return the enchantment ID if the object is enchanted, otherwise an empty string virtual std::string applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index 8752d0b33..d8aac64e4 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -347,10 +347,9 @@ namespace MWClass return info; } - std::string Weapon::getEnchantment (const MWWorld::Ptr& ptr) const + std::string Weapon::getEnchantment (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mEnchant; } diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index 73e4aa2de..556f92e0b 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -65,7 +65,7 @@ namespace MWClass virtual std::string getInventoryIcon (const MWWorld::ConstPtr& ptr) const; ///< Return name of inventory icon. - virtual std::string getEnchantment (const MWWorld::Ptr& ptr) const; + virtual std::string getEnchantment (const MWWorld::ConstPtr& ptr) const; ///< @return the enchantment ID if the object is enchanted, otherwise an empty string virtual std::string applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index e7c86f65d..7f6006c5c 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -282,7 +282,7 @@ namespace MWWorld return false; } - std::string Class::getEnchantment (const Ptr& ptr) const + std::string Class::getEnchantment (const ConstPtr& ptr) const { return ""; } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 321f64615..f12b90eca 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -251,7 +251,7 @@ namespace MWWorld virtual std::string getInventoryIcon (const MWWorld::ConstPtr& ptr) const; ///< Return name of inventory icon. - virtual std::string getEnchantment (const MWWorld::Ptr& ptr) const; + virtual std::string getEnchantment (const MWWorld::ConstPtr& ptr) const; ///< @return the enchantment ID if the object is enchanted, otherwise an empty string /// (default implementation: return empty string) From 0047a2d3302c93da46ca87755c3fbdd773fd404d Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 15:58:23 +0100 Subject: [PATCH 2861/3725] Accept a ConstPtr in canSell --- apps/openmw/mwclass/apparatus.cpp | 2 +- apps/openmw/mwclass/apparatus.hpp | 2 +- apps/openmw/mwclass/armor.cpp | 2 +- apps/openmw/mwclass/armor.hpp | 2 +- apps/openmw/mwclass/book.cpp | 2 +- apps/openmw/mwclass/book.hpp | 2 +- apps/openmw/mwclass/clothing.cpp | 2 +- apps/openmw/mwclass/clothing.hpp | 2 +- apps/openmw/mwclass/ingredient.cpp | 2 +- apps/openmw/mwclass/ingredient.hpp | 2 +- apps/openmw/mwclass/light.cpp | 2 +- apps/openmw/mwclass/light.hpp | 2 +- apps/openmw/mwclass/lockpick.cpp | 2 +- apps/openmw/mwclass/lockpick.hpp | 2 +- apps/openmw/mwclass/misc.cpp | 5 ++--- apps/openmw/mwclass/misc.hpp | 2 +- apps/openmw/mwclass/potion.cpp | 2 +- apps/openmw/mwclass/potion.hpp | 2 +- apps/openmw/mwclass/probe.cpp | 2 +- apps/openmw/mwclass/probe.hpp | 2 +- apps/openmw/mwclass/repair.cpp | 2 +- apps/openmw/mwclass/repair.hpp | 2 +- apps/openmw/mwclass/weapon.cpp | 2 +- apps/openmw/mwclass/weapon.hpp | 2 +- apps/openmw/mwworld/class.cpp | 2 +- apps/openmw/mwworld/class.hpp | 2 +- 26 files changed, 27 insertions(+), 28 deletions(-) diff --git a/apps/openmw/mwclass/apparatus.cpp b/apps/openmw/mwclass/apparatus.cpp index 323ebfa63..878c9f59e 100644 --- a/apps/openmw/mwclass/apparatus.cpp +++ b/apps/openmw/mwclass/apparatus.cpp @@ -144,7 +144,7 @@ namespace MWClass return MWWorld::Ptr(cell.insert(ref), &cell); } - bool Apparatus::canSell (const MWWorld::Ptr& item, int npcServices) const + bool Apparatus::canSell (const MWWorld::ConstPtr& item, int npcServices) const { return (npcServices & ESM::NPC::Apparatus) != 0; } diff --git a/apps/openmw/mwclass/apparatus.hpp b/apps/openmw/mwclass/apparatus.hpp index 82dff46ff..c5066d0fc 100644 --- a/apps/openmw/mwclass/apparatus.hpp +++ b/apps/openmw/mwclass/apparatus.hpp @@ -60,7 +60,7 @@ namespace MWClass virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; - virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; + virtual bool canSell (const MWWorld::ConstPtr& item, int npcServices) const; }; } diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index f575f9955..0554c738e 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -382,7 +382,7 @@ namespace MWClass return ref->mBase->mData.mEnchant; } - bool Armor::canSell (const MWWorld::Ptr& item, int npcServices) const + bool Armor::canSell (const MWWorld::ConstPtr& item, int npcServices) const { return (npcServices & ESM::NPC::Armor) || ((npcServices & ESM::NPC::MagicItems) && !getEnchantment(item).empty()); diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index b5ec11445..4fd426da4 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -85,7 +85,7 @@ namespace MWClass virtual int getEnchantmentPoints (const MWWorld::Ptr& ptr) const; - virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; + virtual bool canSell (const MWWorld::ConstPtr& item, int npcServices) const; /// Get the effective armor rating, factoring in the actor's skills, for the given armor. virtual int getEffectiveArmorRating(const MWWorld::ConstPtr& armor, const MWWorld::Ptr& actor) const; diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index d4e67fdbe..9ef9b769e 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -190,7 +190,7 @@ namespace MWClass return ref->mBase->mData.mEnchant; } - bool Book::canSell (const MWWorld::Ptr& item, int npcServices) const + bool Book::canSell (const MWWorld::ConstPtr& item, int npcServices) const { return (npcServices & ESM::NPC::Books) || ((npcServices & ESM::NPC::MagicItems) && !getEnchantment(item).empty()); diff --git a/apps/openmw/mwclass/book.hpp b/apps/openmw/mwclass/book.hpp index b70b3b5f5..21c9a018d 100644 --- a/apps/openmw/mwclass/book.hpp +++ b/apps/openmw/mwclass/book.hpp @@ -66,7 +66,7 @@ namespace MWClass virtual float getWeight (const MWWorld::Ptr& ptr) const; - virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; + virtual bool canSell (const MWWorld::ConstPtr& item, int npcServices) const; }; } diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index 1316fabd2..f5000229b 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -278,7 +278,7 @@ namespace MWClass return ref->mBase->mData.mEnchant; } - bool Clothing::canSell (const MWWorld::Ptr& item, int npcServices) const + bool Clothing::canSell (const MWWorld::ConstPtr& item, int npcServices) const { return (npcServices & ESM::NPC::Clothing) || ((npcServices & ESM::NPC::MagicItems) && !getEnchantment(item).empty()); diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index 3ad0b12f9..4c0240e74 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -79,7 +79,7 @@ namespace MWClass virtual float getWeight (const MWWorld::Ptr& ptr) const; - virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; + virtual bool canSell (const MWWorld::ConstPtr& item, int npcServices) const; }; } diff --git a/apps/openmw/mwclass/ingredient.cpp b/apps/openmw/mwclass/ingredient.cpp index 3a2cdfc15..5c2cabd4c 100644 --- a/apps/openmw/mwclass/ingredient.cpp +++ b/apps/openmw/mwclass/ingredient.cpp @@ -181,7 +181,7 @@ namespace MWClass return MWWorld::Ptr(cell.insert(ref), &cell); } - bool Ingredient::canSell (const MWWorld::Ptr& item, int npcServices) const + bool Ingredient::canSell (const MWWorld::ConstPtr& item, int npcServices) const { return (npcServices & ESM::NPC::Ingredients) != 0; } diff --git a/apps/openmw/mwclass/ingredient.hpp b/apps/openmw/mwclass/ingredient.hpp index 309917c44..dddf538d1 100644 --- a/apps/openmw/mwclass/ingredient.hpp +++ b/apps/openmw/mwclass/ingredient.hpp @@ -59,7 +59,7 @@ namespace MWClass virtual float getWeight (const MWWorld::Ptr& ptr) const; - virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; + virtual bool canSell (const MWWorld::ConstPtr& item, int npcServices) const; }; } diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index fc3f4e5c5..46ddeeb5f 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -213,7 +213,7 @@ namespace MWClass return MWWorld::Ptr(cell.insert(ref), &cell); } - bool Light::canSell (const MWWorld::Ptr& item, int npcServices) const + bool Light::canSell (const MWWorld::ConstPtr& item, int npcServices) const { return (npcServices & ESM::NPC::Lights) != 0; } diff --git a/apps/openmw/mwclass/light.hpp b/apps/openmw/mwclass/light.hpp index 68529e2d0..f0061117b 100644 --- a/apps/openmw/mwclass/light.hpp +++ b/apps/openmw/mwclass/light.hpp @@ -69,7 +69,7 @@ namespace MWClass virtual float getWeight (const MWWorld::Ptr& ptr) const; - virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; + virtual bool canSell (const MWWorld::ConstPtr& item, int npcServices) const; std::pair canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const; diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index d26585ed3..26f7fba10 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -162,7 +162,7 @@ namespace MWClass return MWWorld::Ptr(cell.insert(ref), &cell); } - bool Lockpick::canSell (const MWWorld::Ptr& item, int npcServices) const + bool Lockpick::canSell (const MWWorld::ConstPtr& item, int npcServices) const { return (npcServices & ESM::NPC::Picks) != 0; } diff --git a/apps/openmw/mwclass/lockpick.hpp b/apps/openmw/mwclass/lockpick.hpp index fa24c0c00..e06060172 100644 --- a/apps/openmw/mwclass/lockpick.hpp +++ b/apps/openmw/mwclass/lockpick.hpp @@ -61,7 +61,7 @@ namespace MWClass virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; - virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; + virtual bool canSell (const MWWorld::ConstPtr& item, int npcServices) const; virtual float getWeight (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index a29142f07..aba92ae3d 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -228,10 +228,9 @@ namespace MWClass return boost::shared_ptr(new MWWorld::ActionSoulgem(ptr)); } - bool Miscellaneous::canSell (const MWWorld::Ptr& item, int npcServices) const + bool Miscellaneous::canSell (const MWWorld::ConstPtr& item, int npcServices) const { - MWWorld::LiveCellRef *ref = - item.get(); + const MWWorld::LiveCellRef *ref = item.get(); return !ref->mBase->mData.mIsKey && (npcServices & ESM::NPC::Misc) && !isGold(item); } diff --git a/apps/openmw/mwclass/misc.hpp b/apps/openmw/mwclass/misc.hpp index 9583ce2da..bc15f2c5f 100644 --- a/apps/openmw/mwclass/misc.hpp +++ b/apps/openmw/mwclass/misc.hpp @@ -59,7 +59,7 @@ namespace MWClass virtual float getWeight (const MWWorld::Ptr& ptr) const; - virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; + virtual bool canSell (const MWWorld::ConstPtr& item, int npcServices) const; virtual bool isKey (const MWWorld::ConstPtr &ptr) const; diff --git a/apps/openmw/mwclass/potion.cpp b/apps/openmw/mwclass/potion.cpp index cf83089d2..8ca8e5111 100644 --- a/apps/openmw/mwclass/potion.cpp +++ b/apps/openmw/mwclass/potion.cpp @@ -175,7 +175,7 @@ namespace MWClass return MWWorld::Ptr(cell.insert(ref), &cell); } - bool Potion::canSell (const MWWorld::Ptr& item, int npcServices) const + bool Potion::canSell (const MWWorld::ConstPtr& item, int npcServices) const { return (npcServices & ESM::NPC::Potions) != 0; } diff --git a/apps/openmw/mwclass/potion.hpp b/apps/openmw/mwclass/potion.hpp index e0cc2722b..c4e9dba3d 100644 --- a/apps/openmw/mwclass/potion.hpp +++ b/apps/openmw/mwclass/potion.hpp @@ -58,7 +58,7 @@ namespace MWClass virtual float getWeight (const MWWorld::Ptr& ptr) const; - virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; + virtual bool canSell (const MWWorld::ConstPtr& item, int npcServices) const; }; } diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index 53403e10a..89b7f0ab5 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -162,7 +162,7 @@ namespace MWClass return MWWorld::Ptr(cell.insert(ref), &cell); } - bool Probe::canSell (const MWWorld::Ptr& item, int npcServices) const + bool Probe::canSell (const MWWorld::ConstPtr& item, int npcServices) const { return (npcServices & ESM::NPC::Probes) != 0; } diff --git a/apps/openmw/mwclass/probe.hpp b/apps/openmw/mwclass/probe.hpp index fccb94ebb..79f1831b3 100644 --- a/apps/openmw/mwclass/probe.hpp +++ b/apps/openmw/mwclass/probe.hpp @@ -61,7 +61,7 @@ namespace MWClass virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; - virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; + virtual bool canSell (const MWWorld::ConstPtr& item, int npcServices) const; virtual float getWeight (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/repair.cpp b/apps/openmw/mwclass/repair.cpp index 5e8cbad53..3e6bcca95 100644 --- a/apps/openmw/mwclass/repair.cpp +++ b/apps/openmw/mwclass/repair.cpp @@ -161,7 +161,7 @@ namespace MWClass return boost::shared_ptr(new MWWorld::ActionRepair(ptr)); } - bool Repair::canSell (const MWWorld::Ptr& item, int npcServices) const + bool Repair::canSell (const MWWorld::ConstPtr& item, int npcServices) const { return (npcServices & ESM::NPC::RepairItem) != 0; } diff --git a/apps/openmw/mwclass/repair.hpp b/apps/openmw/mwclass/repair.hpp index 06ccf8c35..0e9c21cdb 100644 --- a/apps/openmw/mwclass/repair.hpp +++ b/apps/openmw/mwclass/repair.hpp @@ -67,7 +67,7 @@ namespace MWClass virtual float getWeight (const MWWorld::Ptr& ptr) const; - virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; + virtual bool canSell (const MWWorld::ConstPtr& item, int npcServices) const; }; } diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index d8aac64e4..3a827088c 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -419,7 +419,7 @@ namespace MWClass return ref->mBase->mData.mEnchant; } - bool Weapon::canSell (const MWWorld::Ptr& item, int npcServices) const + bool Weapon::canSell (const MWWorld::ConstPtr& item, int npcServices) const { return (npcServices & ESM::NPC::Weapon) || ((npcServices & ESM::NPC::MagicItems) && !getEnchantment(item).empty()); diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index 556f92e0b..29222bb5d 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -81,7 +81,7 @@ namespace MWClass virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; - virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; + virtual bool canSell (const MWWorld::ConstPtr& item, int npcServices) const; virtual float getWeight (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 7f6006c5c..9111215d2 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -55,7 +55,7 @@ namespace MWWorld throw std::runtime_error ("class does not represent an actor"); } - bool Class::canSell (const MWWorld::Ptr& item, int npcServices) const + bool Class::canSell (const MWWorld::ConstPtr& item, int npcServices) const { return false; } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index f12b90eca..8d64f9cbe 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -261,7 +261,7 @@ namespace MWWorld virtual void adjustScale(const MWWorld::Ptr& ptr, osg::Vec3f& scale, bool rendering) const; /// @param rendering Indicates if the scale to adjust is for the rendering mesh, or for the collision mesh - virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; + virtual bool canSell (const MWWorld::ConstPtr& item, int npcServices) const; ///< Determine whether or not \a item can be sold to an npc with the given \a npcServices virtual int getServices (const MWWorld::Ptr& actor) const; From e0bb28480484f20f0fa4ddad4357d1c0dd9c65d3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 16:00:50 +0100 Subject: [PATCH 2862/3725] Accept a ConstPtr in getWeight --- apps/openmw/mwclass/apparatus.cpp | 5 ++--- apps/openmw/mwclass/apparatus.hpp | 2 +- apps/openmw/mwclass/armor.cpp | 5 ++--- apps/openmw/mwclass/armor.hpp | 2 +- apps/openmw/mwclass/book.cpp | 5 ++--- apps/openmw/mwclass/book.hpp | 2 +- apps/openmw/mwclass/clothing.cpp | 5 ++--- apps/openmw/mwclass/clothing.hpp | 2 +- apps/openmw/mwclass/ingredient.cpp | 5 ++--- apps/openmw/mwclass/ingredient.hpp | 2 +- apps/openmw/mwclass/light.cpp | 5 ++--- apps/openmw/mwclass/light.hpp | 2 +- apps/openmw/mwclass/lockpick.cpp | 5 ++--- apps/openmw/mwclass/lockpick.hpp | 2 +- apps/openmw/mwclass/misc.cpp | 5 ++--- apps/openmw/mwclass/misc.hpp | 2 +- apps/openmw/mwclass/potion.cpp | 5 ++--- apps/openmw/mwclass/potion.hpp | 2 +- apps/openmw/mwclass/probe.cpp | 5 ++--- apps/openmw/mwclass/probe.hpp | 2 +- apps/openmw/mwclass/repair.cpp | 5 ++--- apps/openmw/mwclass/repair.hpp | 2 +- apps/openmw/mwclass/weapon.cpp | 5 ++--- apps/openmw/mwclass/weapon.hpp | 2 +- apps/openmw/mwworld/class.cpp | 2 +- apps/openmw/mwworld/class.hpp | 2 +- 26 files changed, 38 insertions(+), 50 deletions(-) diff --git a/apps/openmw/mwclass/apparatus.cpp b/apps/openmw/mwclass/apparatus.cpp index 878c9f59e..2a007d6ad 100644 --- a/apps/openmw/mwclass/apparatus.cpp +++ b/apps/openmw/mwclass/apparatus.cpp @@ -149,10 +149,9 @@ namespace MWClass return (npcServices & ESM::NPC::Apparatus) != 0; } - float Apparatus::getWeight(const MWWorld::Ptr &ptr) const + float Apparatus::getWeight(const MWWorld::ConstPtr &ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mData.mWeight; } } diff --git a/apps/openmw/mwclass/apparatus.hpp b/apps/openmw/mwclass/apparatus.hpp index c5066d0fc..240bf8dea 100644 --- a/apps/openmw/mwclass/apparatus.hpp +++ b/apps/openmw/mwclass/apparatus.hpp @@ -16,7 +16,7 @@ namespace MWClass /// Return ID of \a ptr virtual std::string getId (const MWWorld::Ptr& ptr) const; - virtual float getWeight (const MWWorld::Ptr& ptr) const; + virtual float getWeight (const MWWorld::ConstPtr& ptr) const; virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index 0554c738e..8cd4a98e6 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -388,10 +388,9 @@ namespace MWClass || ((npcServices & ESM::NPC::MagicItems) && !getEnchantment(item).empty()); } - float Armor::getWeight(const MWWorld::Ptr &ptr) const + float Armor::getWeight(const MWWorld::ConstPtr &ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mData.mWeight; } } diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index 4fd426da4..c06c1689f 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -15,7 +15,7 @@ namespace MWClass /// Return ID of \a ptr virtual std::string getId (const MWWorld::Ptr& ptr) const; - virtual float getWeight (const MWWorld::Ptr& ptr) const; + virtual float getWeight (const MWWorld::ConstPtr& ptr) const; virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index 9ef9b769e..372dc084f 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -196,10 +196,9 @@ namespace MWClass || ((npcServices & ESM::NPC::MagicItems) && !getEnchantment(item).empty()); } - float Book::getWeight(const MWWorld::Ptr &ptr) const + float Book::getWeight(const MWWorld::ConstPtr &ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mData.mWeight; } } diff --git a/apps/openmw/mwclass/book.hpp b/apps/openmw/mwclass/book.hpp index 21c9a018d..0452dd6f1 100644 --- a/apps/openmw/mwclass/book.hpp +++ b/apps/openmw/mwclass/book.hpp @@ -64,7 +64,7 @@ namespace MWClass virtual int getEnchantmentPoints (const MWWorld::Ptr& ptr) const; - virtual float getWeight (const MWWorld::Ptr& ptr) const; + virtual float getWeight (const MWWorld::ConstPtr& ptr) const; virtual bool canSell (const MWWorld::ConstPtr& item, int npcServices) const; }; diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index f5000229b..7b32377f6 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -284,10 +284,9 @@ namespace MWClass || ((npcServices & ESM::NPC::MagicItems) && !getEnchantment(item).empty()); } - float Clothing::getWeight(const MWWorld::Ptr &ptr) const + float Clothing::getWeight(const MWWorld::ConstPtr &ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mData.mWeight; } } diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index 4c0240e74..fdf7b1493 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -77,7 +77,7 @@ namespace MWClass virtual int getEnchantmentPoints (const MWWorld::Ptr& ptr) const; - virtual float getWeight (const MWWorld::Ptr& ptr) const; + virtual float getWeight (const MWWorld::ConstPtr& ptr) const; virtual bool canSell (const MWWorld::ConstPtr& item, int npcServices) const; }; diff --git a/apps/openmw/mwclass/ingredient.cpp b/apps/openmw/mwclass/ingredient.cpp index 5c2cabd4c..67d85458d 100644 --- a/apps/openmw/mwclass/ingredient.cpp +++ b/apps/openmw/mwclass/ingredient.cpp @@ -187,10 +187,9 @@ namespace MWClass } - float Ingredient::getWeight(const MWWorld::Ptr &ptr) const + float Ingredient::getWeight(const MWWorld::ConstPtr &ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mData.mWeight; } } diff --git a/apps/openmw/mwclass/ingredient.hpp b/apps/openmw/mwclass/ingredient.hpp index dddf538d1..46695e52d 100644 --- a/apps/openmw/mwclass/ingredient.hpp +++ b/apps/openmw/mwclass/ingredient.hpp @@ -57,7 +57,7 @@ namespace MWClass virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; - virtual float getWeight (const MWWorld::Ptr& ptr) const; + virtual float getWeight (const MWWorld::ConstPtr& ptr) const; virtual bool canSell (const MWWorld::ConstPtr& item, int npcServices) const; }; diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 46ddeeb5f..21277c038 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -218,10 +218,9 @@ namespace MWClass return (npcServices & ESM::NPC::Lights) != 0; } - float Light::getWeight(const MWWorld::Ptr &ptr) const + float Light::getWeight(const MWWorld::ConstPtr &ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mData.mWeight; } diff --git a/apps/openmw/mwclass/light.hpp b/apps/openmw/mwclass/light.hpp index f0061117b..669e7e1e0 100644 --- a/apps/openmw/mwclass/light.hpp +++ b/apps/openmw/mwclass/light.hpp @@ -67,7 +67,7 @@ namespace MWClass virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; - virtual float getWeight (const MWWorld::Ptr& ptr) const; + virtual float getWeight (const MWWorld::ConstPtr& ptr) const; virtual bool canSell (const MWWorld::ConstPtr& item, int npcServices) const; diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index 26f7fba10..80982c471 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -174,10 +174,9 @@ namespace MWClass return ref->mBase->mData.mUses; } - float Lockpick::getWeight(const MWWorld::Ptr &ptr) const + float Lockpick::getWeight(const MWWorld::ConstPtr &ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mData.mWeight; } } diff --git a/apps/openmw/mwclass/lockpick.hpp b/apps/openmw/mwclass/lockpick.hpp index e06060172..da6f824ec 100644 --- a/apps/openmw/mwclass/lockpick.hpp +++ b/apps/openmw/mwclass/lockpick.hpp @@ -63,7 +63,7 @@ namespace MWClass virtual bool canSell (const MWWorld::ConstPtr& item, int npcServices) const; - virtual float getWeight (const MWWorld::Ptr& ptr) const; + virtual float getWeight (const MWWorld::ConstPtr& ptr) const; virtual int getItemMaxHealth (const MWWorld::ConstPtr& ptr) const; ///< Return item max health or throw an exception, if class does not have item health diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index aba92ae3d..8dad332b6 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -235,10 +235,9 @@ namespace MWClass return !ref->mBase->mData.mIsKey && (npcServices & ESM::NPC::Misc) && !isGold(item); } - float Miscellaneous::getWeight(const MWWorld::Ptr &ptr) const + float Miscellaneous::getWeight(const MWWorld::ConstPtr &ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mData.mWeight; } diff --git a/apps/openmw/mwclass/misc.hpp b/apps/openmw/mwclass/misc.hpp index bc15f2c5f..64e7c6e6d 100644 --- a/apps/openmw/mwclass/misc.hpp +++ b/apps/openmw/mwclass/misc.hpp @@ -57,7 +57,7 @@ namespace MWClass const; ///< Generate action for using via inventory menu - virtual float getWeight (const MWWorld::Ptr& ptr) const; + virtual float getWeight (const MWWorld::ConstPtr& ptr) const; virtual bool canSell (const MWWorld::ConstPtr& item, int npcServices) const; diff --git a/apps/openmw/mwclass/potion.cpp b/apps/openmw/mwclass/potion.cpp index 8ca8e5111..24f7aae2d 100644 --- a/apps/openmw/mwclass/potion.cpp +++ b/apps/openmw/mwclass/potion.cpp @@ -180,10 +180,9 @@ namespace MWClass return (npcServices & ESM::NPC::Potions) != 0; } - float Potion::getWeight(const MWWorld::Ptr &ptr) const + float Potion::getWeight(const MWWorld::ConstPtr &ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mData.mWeight; } } diff --git a/apps/openmw/mwclass/potion.hpp b/apps/openmw/mwclass/potion.hpp index c4e9dba3d..a0c4b97df 100644 --- a/apps/openmw/mwclass/potion.hpp +++ b/apps/openmw/mwclass/potion.hpp @@ -56,7 +56,7 @@ namespace MWClass virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; - virtual float getWeight (const MWWorld::Ptr& ptr) const; + virtual float getWeight (const MWWorld::ConstPtr& ptr) const; virtual bool canSell (const MWWorld::ConstPtr& item, int npcServices) const; }; diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index 89b7f0ab5..6757c6ed2 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -174,10 +174,9 @@ namespace MWClass return ref->mBase->mData.mUses; } - float Probe::getWeight(const MWWorld::Ptr &ptr) const + float Probe::getWeight(const MWWorld::ConstPtr &ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mData.mWeight; } } diff --git a/apps/openmw/mwclass/probe.hpp b/apps/openmw/mwclass/probe.hpp index 79f1831b3..0c971c914 100644 --- a/apps/openmw/mwclass/probe.hpp +++ b/apps/openmw/mwclass/probe.hpp @@ -63,7 +63,7 @@ namespace MWClass virtual bool canSell (const MWWorld::ConstPtr& item, int npcServices) const; - virtual float getWeight (const MWWorld::Ptr& ptr) const; + virtual float getWeight (const MWWorld::ConstPtr& ptr) const; virtual int getItemMaxHealth (const MWWorld::ConstPtr& ptr) const; ///< Return item max health or throw an exception, if class does not have item health diff --git a/apps/openmw/mwclass/repair.cpp b/apps/openmw/mwclass/repair.cpp index 3e6bcca95..83162462f 100644 --- a/apps/openmw/mwclass/repair.cpp +++ b/apps/openmw/mwclass/repair.cpp @@ -166,10 +166,9 @@ namespace MWClass return (npcServices & ESM::NPC::RepairItem) != 0; } - float Repair::getWeight(const MWWorld::Ptr &ptr) const + float Repair::getWeight(const MWWorld::ConstPtr &ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mData.mWeight; } } diff --git a/apps/openmw/mwclass/repair.hpp b/apps/openmw/mwclass/repair.hpp index 0e9c21cdb..44b845d69 100644 --- a/apps/openmw/mwclass/repair.hpp +++ b/apps/openmw/mwclass/repair.hpp @@ -65,7 +65,7 @@ namespace MWClass ///< Return item max health or throw an exception, if class does not have item health /// (default implementation: throw an exception) - virtual float getWeight (const MWWorld::Ptr& ptr) const; + virtual float getWeight (const MWWorld::ConstPtr& ptr) const; virtual bool canSell (const MWWorld::ConstPtr& item, int npcServices) const; }; diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index 3a827088c..a45eaaa33 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -425,10 +425,9 @@ namespace MWClass || ((npcServices & ESM::NPC::MagicItems) && !getEnchantment(item).empty()); } - float Weapon::getWeight(const MWWorld::Ptr &ptr) const + float Weapon::getWeight(const MWWorld::ConstPtr &ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mData.mWeight; } } diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index 29222bb5d..0582d9892 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -83,7 +83,7 @@ namespace MWClass virtual bool canSell (const MWWorld::ConstPtr& item, int npcServices) const; - virtual float getWeight (const MWWorld::Ptr& ptr) const; + virtual float getWeight (const MWWorld::ConstPtr& ptr) const; virtual int getEnchantmentPoints (const MWWorld::Ptr& ptr) const; }; diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 9111215d2..f19dce5d0 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -208,7 +208,7 @@ namespace MWWorld throw std::runtime_error ("capacity not supported by this class"); } - float Class::getWeight(const Ptr &ptr) const + float Class::getWeight(const ConstPtr &ptr) const { throw std::runtime_error ("weight not supported by this class"); } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 8d64f9cbe..0a8265404 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -275,7 +275,7 @@ namespace MWWorld ///< Return 0 if player cannot equip item. 1 if can equip. 2 if it's twohanded weapon. 3 if twohanded weapon conflicts with that. /// Second item in the pair specifies the error message - virtual float getWeight (const MWWorld::Ptr& ptr) const; + virtual float getWeight (const MWWorld::ConstPtr& ptr) const; virtual bool isPersistent (const MWWorld::Ptr& ptr) const; From dc92fefd2b6b0fec54d8b31301d4c3aade9aed5b Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 16:06:31 +0100 Subject: [PATCH 2863/3725] Accept a ConstPtr in canBeEquipped, getEquipmentSlots & hasItemHealth --- apps/openmw/mwclass/armor.cpp | 6 +++--- apps/openmw/mwclass/armor.hpp | 6 +++--- apps/openmw/mwclass/clothing.cpp | 7 +++---- apps/openmw/mwclass/clothing.hpp | 4 ++-- apps/openmw/mwclass/light.cpp | 10 ++++------ apps/openmw/mwclass/light.hpp | 4 ++-- apps/openmw/mwclass/lockpick.cpp | 2 +- apps/openmw/mwclass/lockpick.hpp | 4 ++-- apps/openmw/mwclass/probe.cpp | 2 +- apps/openmw/mwclass/probe.hpp | 4 ++-- apps/openmw/mwclass/repair.cpp | 2 +- apps/openmw/mwclass/repair.hpp | 2 +- apps/openmw/mwclass/weapon.cpp | 12 +++++------- apps/openmw/mwclass/weapon.hpp | 6 +++--- apps/openmw/mwworld/class.cpp | 6 +++--- apps/openmw/mwworld/class.hpp | 6 +++--- 16 files changed, 39 insertions(+), 44 deletions(-) diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index 8cd4a98e6..a10ad8da7 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -67,7 +67,7 @@ namespace MWClass return defaultItemActivate(ptr, actor); } - bool Armor::hasItemHealth (const MWWorld::Ptr& ptr) const + bool Armor::hasItemHealth (const MWWorld::ConstPtr& ptr) const { return true; } @@ -86,7 +86,7 @@ namespace MWClass return ref->mBase->mScript; } - std::pair, bool> Armor::getEquipmentSlots (const MWWorld::Ptr& ptr) const + std::pair, bool> Armor::getEquipmentSlots (const MWWorld::ConstPtr& ptr) const { const MWWorld::LiveCellRef *ref = ptr.get(); @@ -295,7 +295,7 @@ namespace MWClass return ref->mBase->mData.mArmor * armorSkill / iBaseArmorSkill; } - std::pair Armor::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const + std::pair Armor::canBeEquipped(const MWWorld::ConstPtr &ptr, const MWWorld::Ptr &npc) const { MWWorld::InventoryStore& invStore = npc.getClass().getInventoryStore(npc); diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index c06c1689f..270a36bf4 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -30,7 +30,7 @@ namespace MWClass const MWWorld::Ptr& actor) const; ///< Generate action for activation - virtual bool hasItemHealth (const MWWorld::Ptr& ptr) const; + virtual bool hasItemHealth (const MWWorld::ConstPtr& ptr) const; ///< \return Item health data available? virtual int getItemMaxHealth (const MWWorld::ConstPtr& ptr) const; @@ -39,7 +39,7 @@ namespace MWClass virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; ///< Return name of the script attached to ptr - virtual std::pair, bool> getEquipmentSlots (const MWWorld::Ptr& ptr) const; + virtual std::pair, bool> getEquipmentSlots (const MWWorld::ConstPtr& ptr) const; ///< \return first: Return IDs of the slot this object can be equipped in; second: can object /// stay stacked when equipped? @@ -73,7 +73,7 @@ namespace MWClass virtual std::string applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; ///< Creates a new record using \a ptr as template, with the given name and the given enchantment applied to it. - virtual std::pair canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const; + virtual std::pair canBeEquipped(const MWWorld::ConstPtr &ptr, const MWWorld::Ptr &npc) const; ///< Return 0 if player cannot equip item. 1 if can equip. 2 if it's twohanded weapon. 3 if twohanded weapon conflicts with that. \n /// Second item in the pair specifies the error message diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index 7b32377f6..85c2fd1ba 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -70,10 +70,9 @@ namespace MWClass return ref->mBase->mScript; } - std::pair, bool> Clothing::getEquipmentSlots (const MWWorld::Ptr& ptr) const + std::pair, bool> Clothing::getEquipmentSlots (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); std::vector slots_; @@ -221,7 +220,7 @@ namespace MWClass return record->mId; } - std::pair Clothing::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const + std::pair Clothing::canBeEquipped(const MWWorld::ConstPtr &ptr, const MWWorld::Ptr &npc) const { // slots that this item can be equipped in std::pair, bool> slots_ = ptr.getClass().getEquipmentSlots(ptr); diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index fdf7b1493..799c7d688 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -31,7 +31,7 @@ namespace MWClass virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; ///< Return name of the script attached to ptr - virtual std::pair, bool> getEquipmentSlots (const MWWorld::Ptr& ptr) const; + virtual std::pair, bool> getEquipmentSlots (const MWWorld::ConstPtr& ptr) const; ///< \return first: Return IDs of the slot this object can be equipped in; second: can object /// stay stacked when equipped? @@ -65,7 +65,7 @@ namespace MWClass virtual std::string applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; ///< Creates a new record using \a ptr as template, with the given name and the given enchantment applied to it. - virtual std::pair canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const; + virtual std::pair canBeEquipped(const MWWorld::ConstPtr &ptr, const MWWorld::Ptr &npc) const; ///< Return 0 if player cannot equip item. 1 if can equip. 2 if it's twohanded weapon. 3 if twohanded weapon conflicts with that. /// Second item in the pair specifies the error message diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 21277c038..bc07d905b 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -100,10 +100,9 @@ namespace MWClass return ref->mBase->mScript; } - std::pair, bool> Light::getEquipmentSlots (const MWWorld::Ptr& ptr) const + std::pair, bool> Light::getEquipmentSlots (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); std::vector slots_; @@ -224,10 +223,9 @@ namespace MWClass return ref->mBase->mData.mWeight; } - std::pair Light::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const + std::pair Light::canBeEquipped(const MWWorld::ConstPtr &ptr, const MWWorld::Ptr &npc) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); if (!(ref->mBase->mData.mFlags & ESM::Light::Carry)) return std::make_pair(0,""); diff --git a/apps/openmw/mwclass/light.hpp b/apps/openmw/mwclass/light.hpp index 669e7e1e0..7ee5d1d47 100644 --- a/apps/openmw/mwclass/light.hpp +++ b/apps/openmw/mwclass/light.hpp @@ -37,7 +37,7 @@ namespace MWClass virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; ///< Return name of the script attached to ptr - virtual std::pair, bool> getEquipmentSlots (const MWWorld::Ptr& ptr) const; + virtual std::pair, bool> getEquipmentSlots (const MWWorld::ConstPtr& ptr) const; ///< \return first: Return IDs of the slot this object can be equipped in; second: can object /// stay stacked when equipped? @@ -71,7 +71,7 @@ namespace MWClass virtual bool canSell (const MWWorld::ConstPtr& item, int npcServices) const; - std::pair canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const; + std::pair canBeEquipped(const MWWorld::ConstPtr &ptr, const MWWorld::Ptr &npc) const; virtual std::string getSound(const MWWorld::Ptr& ptr) const; }; diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index 80982c471..c9410dd0b 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -69,7 +69,7 @@ namespace MWClass return ref->mBase->mScript; } - std::pair, bool> Lockpick::getEquipmentSlots (const MWWorld::Ptr& ptr) const + std::pair, bool> Lockpick::getEquipmentSlots (const MWWorld::ConstPtr& ptr) const { std::vector slots_; diff --git a/apps/openmw/mwclass/lockpick.hpp b/apps/openmw/mwclass/lockpick.hpp index da6f824ec..5a8579e35 100644 --- a/apps/openmw/mwclass/lockpick.hpp +++ b/apps/openmw/mwclass/lockpick.hpp @@ -37,7 +37,7 @@ namespace MWClass virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; ///< Return name of the script attached to ptr - virtual std::pair, bool> getEquipmentSlots (const MWWorld::Ptr& ptr) const; + virtual std::pair, bool> getEquipmentSlots (const MWWorld::ConstPtr& ptr) const; ///< \return first: Return IDs of the slot this object can be equipped in; second: can object /// stay stacked when equipped? @@ -68,7 +68,7 @@ namespace MWClass virtual int getItemMaxHealth (const MWWorld::ConstPtr& ptr) const; ///< Return item max health or throw an exception, if class does not have item health - virtual bool hasItemHealth (const MWWorld::Ptr& ptr) const { return true; } + virtual bool hasItemHealth (const MWWorld::ConstPtr& ptr) const { return true; } ///< \return Item health data available? (default implementation: false) }; } diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index 6757c6ed2..5973e407c 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -69,7 +69,7 @@ namespace MWClass return ref->mBase->mScript; } - std::pair, bool> Probe::getEquipmentSlots (const MWWorld::Ptr& ptr) const + std::pair, bool> Probe::getEquipmentSlots (const MWWorld::ConstPtr& ptr) const { std::vector slots_; diff --git a/apps/openmw/mwclass/probe.hpp b/apps/openmw/mwclass/probe.hpp index 0c971c914..b7252f61d 100644 --- a/apps/openmw/mwclass/probe.hpp +++ b/apps/openmw/mwclass/probe.hpp @@ -37,7 +37,7 @@ namespace MWClass virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; ///< Return name of the script attached to ptr - virtual std::pair, bool> getEquipmentSlots (const MWWorld::Ptr& ptr) const; + virtual std::pair, bool> getEquipmentSlots (const MWWorld::ConstPtr& ptr) const; ///< \return first: Return IDs of the slot this object can be equipped in; second: can object /// stay stacked when equipped? @@ -68,7 +68,7 @@ namespace MWClass virtual int getItemMaxHealth (const MWWorld::ConstPtr& ptr) const; ///< Return item max health or throw an exception, if class does not have item health - virtual bool hasItemHealth (const MWWorld::Ptr& ptr) const { return true; } + virtual bool hasItemHealth (const MWWorld::ConstPtr& ptr) const { return true; } ///< \return Item health data available? (default implementation: false) }; } diff --git a/apps/openmw/mwclass/repair.cpp b/apps/openmw/mwclass/repair.cpp index 83162462f..bf3ebda89 100644 --- a/apps/openmw/mwclass/repair.cpp +++ b/apps/openmw/mwclass/repair.cpp @@ -108,7 +108,7 @@ namespace MWClass return (ref->mBase->mName != ""); } - bool Repair::hasItemHealth (const MWWorld::Ptr& ptr) const + bool Repair::hasItemHealth (const MWWorld::ConstPtr& ptr) const { return true; } diff --git a/apps/openmw/mwclass/repair.hpp b/apps/openmw/mwclass/repair.hpp index 44b845d69..8264ae092 100644 --- a/apps/openmw/mwclass/repair.hpp +++ b/apps/openmw/mwclass/repair.hpp @@ -58,7 +58,7 @@ namespace MWClass ///< Generate action for using via inventory menu (default implementation: return a /// null action). - virtual bool hasItemHealth (const MWWorld::Ptr& ptr) const; + virtual bool hasItemHealth (const MWWorld::ConstPtr& ptr) const; ///< \return Item health data available? (default implementation: false) virtual int getItemMaxHealth (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index a45eaaa33..299a79781 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -65,10 +65,9 @@ namespace MWClass return defaultItemActivate(ptr, actor); } - bool Weapon::hasItemHealth (const MWWorld::Ptr& ptr) const + bool Weapon::hasItemHealth (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return (ref->mBase->mData.mType < 11); // thrown weapons and arrows/bolts don't have health, only quantity } @@ -88,10 +87,9 @@ namespace MWClass return ref->mBase->mScript; } - std::pair, bool> Weapon::getEquipmentSlots (const MWWorld::Ptr& ptr) const + std::pair, bool> Weapon::getEquipmentSlots (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); std::vector slots_; bool stack = false; @@ -369,7 +367,7 @@ namespace MWClass return record->mId; } - std::pair Weapon::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const + std::pair Weapon::canBeEquipped(const MWWorld::ConstPtr &ptr, const MWWorld::Ptr &npc) const { if (hasItemHealth(ptr) && ptr.getCellRef().getCharge() == 0) return std::make_pair(0, "#{sInventoryMessage1}"); diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index 0582d9892..273f8ba18 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -34,7 +34,7 @@ namespace MWClass virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. - virtual bool hasItemHealth (const MWWorld::Ptr& ptr) const; + virtual bool hasItemHealth (const MWWorld::ConstPtr& ptr) const; ///< \return Item health data available? virtual int getItemMaxHealth (const MWWorld::ConstPtr& ptr) const; @@ -43,7 +43,7 @@ namespace MWClass virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; ///< Return name of the script attached to ptr - virtual std::pair, bool> getEquipmentSlots (const MWWorld::Ptr& ptr) const; + virtual std::pair, bool> getEquipmentSlots (const MWWorld::ConstPtr& ptr) const; ///< \return first: Return IDs of the slot this object can be equipped in; second: can object /// stay stacked when equipped? @@ -71,7 +71,7 @@ namespace MWClass virtual std::string applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; ///< Creates a new record using \a ptr as template, with the given name and the given enchantment applied to it. - virtual std::pair canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const; + virtual std::pair canBeEquipped(const MWWorld::ConstPtr &ptr, const MWWorld::Ptr &npc) const; ///< Return 0 if player cannot equip item. 1 if can equip. 2 if it's twohanded weapon. 3 if twohanded weapon conflicts with that. /// Second item in the pair specifies the error message diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index f19dce5d0..5f88f241a 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -75,7 +75,7 @@ namespace MWWorld throw std::runtime_error ("class does not have NPC stats"); } - bool Class::hasItemHealth (const Ptr& ptr) const + bool Class::hasItemHealth (const ConstPtr& ptr) const { return false; } @@ -188,7 +188,7 @@ namespace MWWorld return osg::Vec3f (0, 0, 0); } - std::pair, bool> Class::getEquipmentSlots (const Ptr& ptr) const + std::pair, bool> Class::getEquipmentSlots (const ConstPtr& ptr) const { return std::make_pair (std::vector(), false); } @@ -301,7 +301,7 @@ namespace MWWorld throw std::runtime_error ("class can't be enchanted"); } - std::pair Class::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const + std::pair Class::canBeEquipped(const MWWorld::ConstPtr &ptr, const MWWorld::Ptr &npc) const { return std::make_pair (1, ""); } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 0a8265404..17ab13fbb 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -108,7 +108,7 @@ namespace MWWorld ///< Return NPC stats or throw an exception, if class does not have NPC stats /// (default implementation: throw an exception) - virtual bool hasItemHealth (const Ptr& ptr) const; + virtual bool hasItemHealth (const ConstPtr& ptr) const; ///< \return Item health data available? (default implementation: false) virtual int getItemHealth (const ConstPtr& ptr) const; @@ -187,7 +187,7 @@ namespace MWWorld virtual osg::Vec3f getRotationVector (const Ptr& ptr) const; ///< Return desired rotations, as euler angles. - virtual std::pair, bool> getEquipmentSlots (const Ptr& ptr) const; + virtual std::pair, bool> getEquipmentSlots (const ConstPtr& ptr) const; ///< \return first: Return IDs of the slot this object can be equipped in; second: can object /// stay stacked when equipped? /// @@ -271,7 +271,7 @@ namespace MWWorld virtual std::string applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; ///< Creates a new record using \a ptr as template, with the given name and the given enchantment applied to it. - virtual std::pair canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const; + virtual std::pair canBeEquipped(const MWWorld::ConstPtr &ptr, const MWWorld::Ptr &npc) const; ///< Return 0 if player cannot equip item. 1 if can equip. 2 if it's twohanded weapon. 3 if twohanded weapon conflicts with that. /// Second item in the pair specifies the error message From d77f785cbcfb38a1694fc78afcac99b94a1fb47e Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 16:09:08 +0100 Subject: [PATCH 2864/3725] Accept a ConstPtr in get*SoundId --- apps/openmw/mwclass/apparatus.cpp | 4 ++-- apps/openmw/mwclass/apparatus.hpp | 4 ++-- apps/openmw/mwclass/armor.cpp | 4 ++-- apps/openmw/mwclass/armor.hpp | 4 ++-- apps/openmw/mwclass/book.cpp | 4 ++-- apps/openmw/mwclass/book.hpp | 4 ++-- apps/openmw/mwclass/clothing.cpp | 10 ++++------ apps/openmw/mwclass/clothing.hpp | 4 ++-- apps/openmw/mwclass/ingredient.cpp | 4 ++-- apps/openmw/mwclass/ingredient.hpp | 4 ++-- apps/openmw/mwclass/light.cpp | 4 ++-- apps/openmw/mwclass/light.hpp | 4 ++-- apps/openmw/mwclass/lockpick.cpp | 4 ++-- apps/openmw/mwclass/lockpick.hpp | 4 ++-- apps/openmw/mwclass/misc.cpp | 4 ++-- apps/openmw/mwclass/misc.hpp | 4 ++-- apps/openmw/mwclass/potion.cpp | 4 ++-- apps/openmw/mwclass/potion.hpp | 4 ++-- apps/openmw/mwclass/probe.cpp | 4 ++-- apps/openmw/mwclass/probe.hpp | 4 ++-- apps/openmw/mwclass/repair.cpp | 4 ++-- apps/openmw/mwclass/repair.hpp | 4 ++-- apps/openmw/mwclass/weapon.cpp | 10 ++++------ apps/openmw/mwclass/weapon.hpp | 4 ++-- apps/openmw/mwworld/class.cpp | 4 ++-- apps/openmw/mwworld/class.hpp | 4 ++-- 26 files changed, 56 insertions(+), 60 deletions(-) diff --git a/apps/openmw/mwclass/apparatus.cpp b/apps/openmw/mwclass/apparatus.cpp index 2a007d6ad..a90a53adb 100644 --- a/apps/openmw/mwclass/apparatus.cpp +++ b/apps/openmw/mwclass/apparatus.cpp @@ -82,12 +82,12 @@ namespace MWClass registerClass (typeid (ESM::Apparatus).name(), instance); } - std::string Apparatus::getUpSoundId (const MWWorld::Ptr& ptr) const + std::string Apparatus::getUpSoundId (const MWWorld::ConstPtr& ptr) const { return std::string("Item Apparatus Up"); } - std::string Apparatus::getDownSoundId (const MWWorld::Ptr& ptr) const + std::string Apparatus::getDownSoundId (const MWWorld::ConstPtr& ptr) const { return std::string("Item Apparatus Down"); } diff --git a/apps/openmw/mwclass/apparatus.hpp b/apps/openmw/mwclass/apparatus.hpp index 240bf8dea..e50a57c6a 100644 --- a/apps/openmw/mwclass/apparatus.hpp +++ b/apps/openmw/mwclass/apparatus.hpp @@ -45,10 +45,10 @@ namespace MWClass static void registerSelf(); - virtual std::string getUpSoundId (const MWWorld::Ptr& ptr) const; + virtual std::string getUpSoundId (const MWWorld::ConstPtr& ptr) const; ///< Return the pick up sound Id - virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; + virtual std::string getDownSoundId (const MWWorld::ConstPtr& ptr) const; ///< Return the put down sound Id virtual std::string getInventoryIcon (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index a10ad8da7..500664b36 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -177,7 +177,7 @@ namespace MWClass registerClass (typeid (ESM::Armor).name(), instance); } - std::string Armor::getUpSoundId (const MWWorld::Ptr& ptr) const + std::string Armor::getUpSoundId (const MWWorld::ConstPtr& ptr) const { int es = getEquipmentSkill(ptr); if (es == ESM::Skill::LightArmor) @@ -188,7 +188,7 @@ namespace MWClass return std::string("Item Armor Heavy Up"); } - std::string Armor::getDownSoundId (const MWWorld::Ptr& ptr) const + std::string Armor::getDownSoundId (const MWWorld::ConstPtr& ptr) const { int es = getEquipmentSkill(ptr); if (es == ESM::Skill::LightArmor) diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index 270a36bf4..8ddd92e4d 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -58,10 +58,10 @@ namespace MWClass static void registerSelf(); - virtual std::string getUpSoundId (const MWWorld::Ptr& ptr) const; + virtual std::string getUpSoundId (const MWWorld::ConstPtr& ptr) const; ///< Return the pick up sound Id - virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; + virtual std::string getDownSoundId (const MWWorld::ConstPtr& ptr) const; ///< Return the put down sound Id virtual std::string getInventoryIcon (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index 372dc084f..25be08587 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -96,12 +96,12 @@ namespace MWClass registerClass (typeid (ESM::Book).name(), instance); } - std::string Book::getUpSoundId (const MWWorld::Ptr& ptr) const + std::string Book::getUpSoundId (const MWWorld::ConstPtr& ptr) const { return std::string("Item Book Up"); } - std::string Book::getDownSoundId (const MWWorld::Ptr& ptr) const + std::string Book::getDownSoundId (const MWWorld::ConstPtr& ptr) const { return std::string("Item Book Down"); } diff --git a/apps/openmw/mwclass/book.hpp b/apps/openmw/mwclass/book.hpp index 0452dd6f1..a0b5b434e 100644 --- a/apps/openmw/mwclass/book.hpp +++ b/apps/openmw/mwclass/book.hpp @@ -42,10 +42,10 @@ namespace MWClass static void registerSelf(); - virtual std::string getUpSoundId (const MWWorld::Ptr& ptr) const; + virtual std::string getUpSoundId (const MWWorld::ConstPtr& ptr) const; ///< Return the pick up sound Id - virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; + virtual std::string getDownSoundId (const MWWorld::ConstPtr& ptr) const; ///< Return the put down sound Id virtual std::string getInventoryIcon (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index 85c2fd1ba..bf3b90941 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -133,10 +133,9 @@ namespace MWClass registerClass (typeid (ESM::Clothing).name(), instance); } - std::string Clothing::getUpSoundId (const MWWorld::Ptr& ptr) const + std::string Clothing::getUpSoundId (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); if (ref->mBase->mData.mType == 8) { @@ -145,10 +144,9 @@ namespace MWClass return std::string("Item Clothes Up"); } - std::string Clothing::getDownSoundId (const MWWorld::Ptr& ptr) const + std::string Clothing::getDownSoundId (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); if (ref->mBase->mData.mType == 8) { diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index 799c7d688..e513613e4 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -50,10 +50,10 @@ namespace MWClass static void registerSelf(); - virtual std::string getUpSoundId (const MWWorld::Ptr& ptr) const; + virtual std::string getUpSoundId (const MWWorld::ConstPtr& ptr) const; ///< Return the pick up sound Id - virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; + virtual std::string getDownSoundId (const MWWorld::ConstPtr& ptr) const; ///< Return the put down sound Id virtual std::string getInventoryIcon (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/ingredient.cpp b/apps/openmw/mwclass/ingredient.cpp index 67d85458d..bdc67b452 100644 --- a/apps/openmw/mwclass/ingredient.cpp +++ b/apps/openmw/mwclass/ingredient.cpp @@ -98,12 +98,12 @@ namespace MWClass registerClass (typeid (ESM::Ingredient).name(), instance); } - std::string Ingredient::getUpSoundId (const MWWorld::Ptr& ptr) const + std::string Ingredient::getUpSoundId (const MWWorld::ConstPtr& ptr) const { return std::string("Item Ingredient Up"); } - std::string Ingredient::getDownSoundId (const MWWorld::Ptr& ptr) const + std::string Ingredient::getDownSoundId (const MWWorld::ConstPtr& ptr) const { return std::string("Item Ingredient Down"); } diff --git a/apps/openmw/mwclass/ingredient.hpp b/apps/openmw/mwclass/ingredient.hpp index 46695e52d..96fc7e8e4 100644 --- a/apps/openmw/mwclass/ingredient.hpp +++ b/apps/openmw/mwclass/ingredient.hpp @@ -46,10 +46,10 @@ namespace MWClass static void registerSelf(); - virtual std::string getUpSoundId (const MWWorld::Ptr& ptr) const; + virtual std::string getUpSoundId (const MWWorld::ConstPtr& ptr) const; ///< Return the pick up sound Id - virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; + virtual std::string getDownSoundId (const MWWorld::ConstPtr& ptr) const; ///< Return the put down sound Id virtual std::string getInventoryIcon (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index bc07d905b..c45b11467 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -126,12 +126,12 @@ namespace MWClass registerClass (typeid (ESM::Light).name(), instance); } - std::string Light::getUpSoundId (const MWWorld::Ptr& ptr) const + std::string Light::getUpSoundId (const MWWorld::ConstPtr& ptr) const { return std::string("Item Misc Up"); } - std::string Light::getDownSoundId (const MWWorld::Ptr& ptr) const + std::string Light::getDownSoundId (const MWWorld::ConstPtr& ptr) const { return std::string("Item Misc Down"); } diff --git a/apps/openmw/mwclass/light.hpp b/apps/openmw/mwclass/light.hpp index 7ee5d1d47..02e327587 100644 --- a/apps/openmw/mwclass/light.hpp +++ b/apps/openmw/mwclass/light.hpp @@ -46,10 +46,10 @@ namespace MWClass static void registerSelf(); - virtual std::string getUpSoundId (const MWWorld::Ptr& ptr) const; + virtual std::string getUpSoundId (const MWWorld::ConstPtr& ptr) const; ///< Return the pick up sound Id - virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; + virtual std::string getDownSoundId (const MWWorld::ConstPtr& ptr) const; ///< Return the put down sound Id virtual std::string getInventoryIcon (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index c9410dd0b..b46159cbc 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -92,12 +92,12 @@ namespace MWClass registerClass (typeid (ESM::Lockpick).name(), instance); } - std::string Lockpick::getUpSoundId (const MWWorld::Ptr& ptr) const + std::string Lockpick::getUpSoundId (const MWWorld::ConstPtr& ptr) const { return std::string("Item Lockpick Up"); } - std::string Lockpick::getDownSoundId (const MWWorld::Ptr& ptr) const + std::string Lockpick::getDownSoundId (const MWWorld::ConstPtr& ptr) const { return std::string("Item Lockpick Down"); } diff --git a/apps/openmw/mwclass/lockpick.hpp b/apps/openmw/mwclass/lockpick.hpp index 5a8579e35..b5b4844c3 100644 --- a/apps/openmw/mwclass/lockpick.hpp +++ b/apps/openmw/mwclass/lockpick.hpp @@ -46,10 +46,10 @@ namespace MWClass static void registerSelf(); - virtual std::string getUpSoundId (const MWWorld::Ptr& ptr) const; + virtual std::string getUpSoundId (const MWWorld::ConstPtr& ptr) const; ///< Return the pick up sound Id - virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; + virtual std::string getDownSoundId (const MWWorld::ConstPtr& ptr) const; ///< Return the put down sound Id virtual std::string getInventoryIcon (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index 8dad332b6..c8fdc2a8a 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -106,14 +106,14 @@ namespace MWClass registerClass (typeid (ESM::Miscellaneous).name(), instance); } - std::string Miscellaneous::getUpSoundId (const MWWorld::Ptr& ptr) const + std::string Miscellaneous::getUpSoundId (const MWWorld::ConstPtr& ptr) const { if (isGold(ptr)) return std::string("Item Gold Up"); return std::string("Item Misc Up"); } - std::string Miscellaneous::getDownSoundId (const MWWorld::Ptr& ptr) const + std::string Miscellaneous::getDownSoundId (const MWWorld::ConstPtr& ptr) const { if (isGold(ptr)) return std::string("Item Gold Down"); diff --git a/apps/openmw/mwclass/misc.hpp b/apps/openmw/mwclass/misc.hpp index 64e7c6e6d..679319e02 100644 --- a/apps/openmw/mwclass/misc.hpp +++ b/apps/openmw/mwclass/misc.hpp @@ -42,10 +42,10 @@ namespace MWClass static void registerSelf(); - virtual std::string getUpSoundId (const MWWorld::Ptr& ptr) const; + virtual std::string getUpSoundId (const MWWorld::ConstPtr& ptr) const; ///< Return the pick up sound Id - virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; + virtual std::string getDownSoundId (const MWWorld::ConstPtr& ptr) const; ///< Return the put down sound Id virtual std::string getInventoryIcon (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/potion.cpp b/apps/openmw/mwclass/potion.cpp index 24f7aae2d..e4928384d 100644 --- a/apps/openmw/mwclass/potion.cpp +++ b/apps/openmw/mwclass/potion.cpp @@ -87,12 +87,12 @@ namespace MWClass registerClass (typeid (ESM::Potion).name(), instance); } - std::string Potion::getUpSoundId (const MWWorld::Ptr& ptr) const + std::string Potion::getUpSoundId (const MWWorld::ConstPtr& ptr) const { return std::string("Item Potion Up"); } - std::string Potion::getDownSoundId (const MWWorld::Ptr& ptr) const + std::string Potion::getDownSoundId (const MWWorld::ConstPtr& ptr) const { return std::string("Item Potion Down"); } diff --git a/apps/openmw/mwclass/potion.hpp b/apps/openmw/mwclass/potion.hpp index a0c4b97df..ac6e0d180 100644 --- a/apps/openmw/mwclass/potion.hpp +++ b/apps/openmw/mwclass/potion.hpp @@ -45,10 +45,10 @@ namespace MWClass static void registerSelf(); - virtual std::string getUpSoundId (const MWWorld::Ptr& ptr) const; + virtual std::string getUpSoundId (const MWWorld::ConstPtr& ptr) const; ///< Return the pick up sound Id - virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; + virtual std::string getDownSoundId (const MWWorld::ConstPtr& ptr) const; ///< Return the put down sound Id virtual std::string getInventoryIcon (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index 5973e407c..ac9ac56e8 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -92,12 +92,12 @@ namespace MWClass registerClass (typeid (ESM::Probe).name(), instance); } - std::string Probe::getUpSoundId (const MWWorld::Ptr& ptr) const + std::string Probe::getUpSoundId (const MWWorld::ConstPtr& ptr) const { return std::string("Item Probe Up"); } - std::string Probe::getDownSoundId (const MWWorld::Ptr& ptr) const + std::string Probe::getDownSoundId (const MWWorld::ConstPtr& ptr) const { return std::string("Item Probe Down"); } diff --git a/apps/openmw/mwclass/probe.hpp b/apps/openmw/mwclass/probe.hpp index b7252f61d..d0a4b4947 100644 --- a/apps/openmw/mwclass/probe.hpp +++ b/apps/openmw/mwclass/probe.hpp @@ -46,10 +46,10 @@ namespace MWClass static void registerSelf(); - virtual std::string getUpSoundId (const MWWorld::Ptr& ptr) const; + virtual std::string getUpSoundId (const MWWorld::ConstPtr& ptr) const; ///< Return the pick up sound Id - virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; + virtual std::string getDownSoundId (const MWWorld::ConstPtr& ptr) const; ///< Return the put down sound Id virtual std::string getInventoryIcon (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/repair.cpp b/apps/openmw/mwclass/repair.cpp index bf3ebda89..1940baa67 100644 --- a/apps/openmw/mwclass/repair.cpp +++ b/apps/openmw/mwclass/repair.cpp @@ -83,12 +83,12 @@ namespace MWClass registerClass (typeid (ESM::Repair).name(), instance); } - std::string Repair::getUpSoundId (const MWWorld::Ptr& ptr) const + std::string Repair::getUpSoundId (const MWWorld::ConstPtr& ptr) const { return std::string("Item Repair Up"); } - std::string Repair::getDownSoundId (const MWWorld::Ptr& ptr) const + std::string Repair::getDownSoundId (const MWWorld::ConstPtr& ptr) const { return std::string("Item Repair Down"); } diff --git a/apps/openmw/mwclass/repair.hpp b/apps/openmw/mwclass/repair.hpp index 8264ae092..dce47167f 100644 --- a/apps/openmw/mwclass/repair.hpp +++ b/apps/openmw/mwclass/repair.hpp @@ -42,10 +42,10 @@ namespace MWClass static void registerSelf(); - virtual std::string getUpSoundId (const MWWorld::Ptr& ptr) const; + virtual std::string getUpSoundId (const MWWorld::ConstPtr& ptr) const; ///< Return the pick up sound Id - virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; + virtual std::string getDownSoundId (const MWWorld::ConstPtr& ptr) const; ///< Return the put down sound Id virtual std::string getInventoryIcon (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index 299a79781..db1448afc 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -153,10 +153,9 @@ namespace MWClass registerClass (typeid (ESM::Weapon).name(), instance); } - std::string Weapon::getUpSoundId (const MWWorld::Ptr& ptr) const + std::string Weapon::getUpSoundId (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); int type = ref->mBase->mData.mType; // Ammo @@ -198,10 +197,9 @@ namespace MWClass return std::string("Item Misc Up"); } - std::string Weapon::getDownSoundId (const MWWorld::Ptr& ptr) const + std::string Weapon::getDownSoundId (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); int type = ref->mBase->mData.mType; // Ammo diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index 273f8ba18..611e2edf0 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -56,10 +56,10 @@ namespace MWClass static void registerSelf(); - virtual std::string getUpSoundId (const MWWorld::Ptr& ptr) const; + virtual std::string getUpSoundId (const MWWorld::ConstPtr& ptr) const; ///< Return the pick up sound Id - virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; + virtual std::string getDownSoundId (const MWWorld::ConstPtr& ptr) const; ///< Return the put down sound Id virtual std::string getInventoryIcon (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 5f88f241a..653163a4c 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -252,12 +252,12 @@ namespace MWWorld sClasses.insert(std::make_pair(key, instance)); } - std::string Class::getUpSoundId (const Ptr& ptr) const + std::string Class::getUpSoundId (const ConstPtr& ptr) const { throw std::runtime_error ("class does not have an up sound"); } - std::string Class::getDownSoundId (const Ptr& ptr) const + std::string Class::getDownSoundId (const ConstPtr& ptr) const { throw std::runtime_error ("class does not have an down sound"); } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 17ab13fbb..56dc7ede5 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -234,11 +234,11 @@ namespace MWWorld /// /// (default implementation: return false) - virtual std::string getUpSoundId (const Ptr& ptr) const; + virtual std::string getUpSoundId (const ConstPtr& ptr) const; ///< Return the up sound ID of \a ptr or throw an exception, if class does not support ID retrieval /// (default implementation: throw an exception) - virtual std::string getDownSoundId (const Ptr& ptr) const; + virtual std::string getDownSoundId (const ConstPtr& ptr) const; ///< Return the down sound ID of \a ptr or throw an exception, if class does not support ID retrieval /// (default implementation: throw an exception) From d120f760312fdd1140aa6b6b92e1696e1adcb5ff Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 16:11:03 +0100 Subject: [PATCH 2865/3725] Accept a ConstPtr in getSound --- apps/openmw/mwclass/light.cpp | 2 +- apps/openmw/mwclass/light.hpp | 2 +- apps/openmw/mwworld/class.cpp | 2 +- apps/openmw/mwworld/class.hpp | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index c45b11467..626cde9ac 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -250,7 +250,7 @@ namespace MWClass return std::make_pair(1,""); } - std::string Light::getSound(const MWWorld::Ptr& ptr) const + std::string Light::getSound(const MWWorld::ConstPtr& ptr) const { return ptr.get()->mBase->mSound; } diff --git a/apps/openmw/mwclass/light.hpp b/apps/openmw/mwclass/light.hpp index 02e327587..a52c3f568 100644 --- a/apps/openmw/mwclass/light.hpp +++ b/apps/openmw/mwclass/light.hpp @@ -73,7 +73,7 @@ namespace MWClass std::pair canBeEquipped(const MWWorld::ConstPtr &ptr, const MWWorld::Ptr &npc) const; - virtual std::string getSound(const MWWorld::Ptr& ptr) const; + virtual std::string getSound(const MWWorld::ConstPtr& ptr) const; }; } diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 653163a4c..0617796f3 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -428,7 +428,7 @@ namespace MWWorld return getEncumbrance(ptr) / capacity; } - std::string Class::getSound(const MWWorld::Ptr&) const + std::string Class::getSound(const MWWorld::ConstPtr&) const { return std::string(); } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 56dc7ede5..1873b2a0c 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -336,7 +336,7 @@ namespace MWWorld virtual void restock (const MWWorld::Ptr& ptr) const {} /// Returns sound id - virtual std::string getSound(const MWWorld::Ptr& ptr) const; + virtual std::string getSound(const MWWorld::ConstPtr& ptr) const; virtual int getBaseFightRating (const MWWorld::Ptr& ptr) const; From 92a3acfa5673d2690de13dbb3a902481b5494d6c Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 16:12:35 +0100 Subject: [PATCH 2866/3725] Accept a ConstPtr in getBaseFightRating --- apps/openmw/mwclass/creature.cpp | 4 ++-- apps/openmw/mwclass/creature.hpp | 2 +- apps/openmw/mwclass/npc.cpp | 4 ++-- apps/openmw/mwclass/npc.hpp | 2 +- apps/openmw/mwworld/class.cpp | 2 +- apps/openmw/mwworld/class.hpp | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 1072a2435..80042fa52 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -770,9 +770,9 @@ namespace MWClass store.restock(list, ptr, ptr.getCellRef().getRefId()); } - int Creature::getBaseFightRating(const MWWorld::Ptr &ptr) const + int Creature::getBaseFightRating(const MWWorld::ConstPtr &ptr) const { - MWWorld::LiveCellRef *ref = ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mAiData.mFight; } diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index 47e886c01..66e9207a0 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -129,7 +129,7 @@ namespace MWClass virtual void restock (const MWWorld::Ptr &ptr) const; - virtual int getBaseFightRating(const MWWorld::Ptr &ptr) const; + virtual int getBaseFightRating(const MWWorld::ConstPtr &ptr) const; virtual void adjustScale(const MWWorld::Ptr& ptr, osg::Vec3f& scale, bool rendering) const; /// @param rendering Indicates if the scale to adjust is for the rendering mesh, or for the collision mesh diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 0dc97df87..1fa8d27a2 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -1236,9 +1236,9 @@ namespace MWClass store.restock(list, ptr, ptr.getCellRef().getRefId()); } - int Npc::getBaseFightRating (const MWWorld::Ptr& ptr) const + int Npc::getBaseFightRating (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mAiData.mFight; } diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index aac93ab6e..1d554ed3c 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -167,7 +167,7 @@ namespace MWClass virtual void restock (const MWWorld::Ptr& ptr) const; - virtual int getBaseFightRating (const MWWorld::Ptr& ptr) const; + virtual int getBaseFightRating (const MWWorld::ConstPtr& ptr) const; virtual std::string getPrimaryFaction(const MWWorld::Ptr &ptr) const; virtual int getPrimaryFactionRank(const MWWorld::Ptr &ptr) const; diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 0617796f3..a481afeb0 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -433,7 +433,7 @@ namespace MWWorld return std::string(); } - int Class::getBaseFightRating(const Ptr &ptr) const + int Class::getBaseFightRating(const ConstPtr &ptr) const { throw std::runtime_error("class does not support fight rating"); } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 1873b2a0c..6603ecf4b 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -338,7 +338,7 @@ namespace MWWorld /// Returns sound id virtual std::string getSound(const MWWorld::ConstPtr& ptr) const; - virtual int getBaseFightRating (const MWWorld::Ptr& ptr) const; + virtual int getBaseFightRating (const MWWorld::ConstPtr& ptr) const; virtual std::string getPrimaryFaction (const MWWorld::Ptr& ptr) const; virtual int getPrimaryFactionRank (const MWWorld::Ptr& ptr) const; From b09bdd6af58a44f767570b22892454c26de10a26 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 16:15:40 +0100 Subject: [PATCH 2867/3725] Accept a ConstPtr in isBipedal --- apps/openmw/mwclass/creature.cpp | 4 ++-- apps/openmw/mwclass/creature.hpp | 2 +- apps/openmw/mwclass/npc.cpp | 12 +++++++++++- apps/openmw/mwclass/npc.hpp | 10 +++------- apps/openmw/mwworld/class.cpp | 2 +- apps/openmw/mwworld/class.hpp | 2 +- 6 files changed, 19 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 80042fa52..35b3c4546 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -40,7 +40,7 @@ namespace { - bool isFlagBitSet(const MWWorld::Ptr &ptr, ESM::Creature::Flags bitMask) + bool isFlagBitSet(const MWWorld::ConstPtr &ptr, ESM::Creature::Flags bitMask) { return (ptr.get()->mBase->mFlags & bitMask) != 0; } @@ -599,7 +599,7 @@ namespace MWClass return MWWorld::Ptr(cell.insert(ref), &cell); } - bool Creature::isBipedal(const MWWorld::Ptr &ptr) const + bool Creature::isBipedal(const MWWorld::ConstPtr &ptr) const { return isFlagBitSet(ptr, ESM::Creature::Bipedal); } diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index 66e9207a0..fb303278f 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -107,7 +107,7 @@ namespace MWClass return true; } - virtual bool isBipedal (const MWWorld::Ptr &ptr) const; + virtual bool isBipedal (const MWWorld::ConstPtr &ptr) const; virtual bool canFly (const MWWorld::Ptr &ptr) const; virtual bool canSwim (const MWWorld::Ptr &ptr) const; virtual bool canWalk (const MWWorld::Ptr &ptr) const; diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 1fa8d27a2..8ef3c219a 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -1208,6 +1208,16 @@ namespace MWClass return Misc::StringUtils::ciEqual(ptr.get()->mBase->mClass, className); } + bool Npc::canSwim(const MWWorld::ConstPtr &ptr) const + { + return true; + } + + bool Npc::canWalk(const MWWorld::ConstPtr &ptr) const + { + return true; + } + void Npc::respawn(const MWWorld::Ptr &ptr) const { if (ptr.get()->mBase->mFlags & ESM::NPC::Respawn) @@ -1242,7 +1252,7 @@ namespace MWClass return ref->mBase->mAiData.mFight; } - bool Npc::isBipedal(const MWWorld::Ptr &ptr) const + bool Npc::isBipedal(const MWWorld::ConstPtr &ptr) const { return true; } diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index 1d554ed3c..acde83c5f 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -153,15 +153,11 @@ namespace MWClass virtual bool isClass(const MWWorld::Ptr& ptr, const std::string &className) const; - virtual bool canSwim (const MWWorld::Ptr &ptr) const { - return true; - } + virtual bool canSwim (const MWWorld::ConstPtr &ptr) const; - virtual bool canWalk (const MWWorld::Ptr &ptr) const { - return true; - } + virtual bool canWalk (const MWWorld::ConstPtr &ptr) const; - virtual bool isBipedal (const MWWorld::Ptr &ptr) const; + virtual bool isBipedal (const MWWorld::ConstPtr &ptr) const; virtual void respawn (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index a481afeb0..681b72c5b 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -355,7 +355,7 @@ namespace MWWorld return newPtr; } - bool Class::isBipedal(const Ptr &ptr) const + bool Class::isBipedal(const ConstPtr &ptr) const { return false; } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 6603ecf4b..cc84f9b32 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -300,7 +300,7 @@ namespace MWWorld return false; } - virtual bool isBipedal(const MWWorld::Ptr& ptr) const; + virtual bool isBipedal(const MWWorld::ConstPtr& ptr) const; virtual bool canFly(const MWWorld::Ptr& ptr) const; virtual bool canSwim(const MWWorld::Ptr& ptr) const; virtual bool canWalk(const MWWorld::Ptr& ptr) const; From 954186fe1e3b4045a08dfa0a3265b7b38b87f93f Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 16:16:45 +0100 Subject: [PATCH 2868/3725] Accept a ConstPtr in canFly, canSwim & canWalk --- apps/openmw/mwclass/creature.cpp | 6 +++--- apps/openmw/mwclass/creature.hpp | 6 +++--- apps/openmw/mwworld/class.cpp | 6 +++--- apps/openmw/mwworld/class.hpp | 6 +++--- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 35b3c4546..f903144b6 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -604,17 +604,17 @@ namespace MWClass return isFlagBitSet(ptr, ESM::Creature::Bipedal); } - bool Creature::canFly(const MWWorld::Ptr &ptr) const + bool Creature::canFly(const MWWorld::ConstPtr &ptr) const { return isFlagBitSet(ptr, ESM::Creature::Flies); } - bool Creature::canSwim(const MWWorld::Ptr &ptr) const + bool Creature::canSwim(const MWWorld::ConstPtr &ptr) const { return isFlagBitSet(ptr, static_cast(ESM::Creature::Swims | ESM::Creature::Bipedal)); } - bool Creature::canWalk(const MWWorld::Ptr &ptr) const + bool Creature::canWalk(const MWWorld::ConstPtr &ptr) const { return isFlagBitSet(ptr, static_cast(ESM::Creature::Walks | ESM::Creature::Bipedal)); } diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index fb303278f..5f110e918 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -108,9 +108,9 @@ namespace MWClass } virtual bool isBipedal (const MWWorld::ConstPtr &ptr) const; - virtual bool canFly (const MWWorld::Ptr &ptr) const; - virtual bool canSwim (const MWWorld::Ptr &ptr) const; - virtual bool canWalk (const MWWorld::Ptr &ptr) const; + virtual bool canFly (const MWWorld::ConstPtr &ptr) const; + virtual bool canSwim (const MWWorld::ConstPtr &ptr) const; + virtual bool canWalk (const MWWorld::ConstPtr &ptr) const; virtual int getSkill(const MWWorld::Ptr &ptr, int skill) const; diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 681b72c5b..8722187ab 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -360,17 +360,17 @@ namespace MWWorld return false; } - bool Class::canFly(const Ptr &ptr) const + bool Class::canFly(const ConstPtr &ptr) const { return false; } - bool Class::canSwim(const Ptr &ptr) const + bool Class::canSwim(const ConstPtr &ptr) const { return false; } - bool Class::canWalk(const Ptr &ptr) const + bool Class::canWalk(const ConstPtr &ptr) const { return false; } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index cc84f9b32..619508f74 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -301,9 +301,9 @@ namespace MWWorld } virtual bool isBipedal(const MWWorld::ConstPtr& ptr) const; - virtual bool canFly(const MWWorld::Ptr& ptr) const; - virtual bool canSwim(const MWWorld::Ptr& ptr) const; - virtual bool canWalk(const MWWorld::Ptr& ptr) const; + virtual bool canFly(const MWWorld::ConstPtr& ptr) const; + virtual bool canSwim(const MWWorld::ConstPtr& ptr) const; + virtual bool canWalk(const MWWorld::ConstPtr& ptr) const; bool isPureWaterCreature(const MWWorld::Ptr& ptr) const; bool isMobile(const MWWorld::Ptr& ptr) const; From da7ebfde9918f4c9d3bba176bea093aab69e170f Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 16:24:24 +0100 Subject: [PATCH 2869/3725] Accept a ConstPtr in copyToCell --- apps/openmw/mwclass/activator.cpp | 6 ++---- apps/openmw/mwclass/activator.hpp | 3 +-- apps/openmw/mwclass/apparatus.cpp | 6 ++---- apps/openmw/mwclass/apparatus.hpp | 3 +-- apps/openmw/mwclass/armor.cpp | 6 ++---- apps/openmw/mwclass/armor.hpp | 3 +-- apps/openmw/mwclass/book.cpp | 6 ++---- apps/openmw/mwclass/book.hpp | 3 +-- apps/openmw/mwclass/clothing.cpp | 6 ++---- apps/openmw/mwclass/clothing.hpp | 3 +-- apps/openmw/mwclass/container.cpp | 5 ++--- apps/openmw/mwclass/container.hpp | 3 +-- apps/openmw/mwclass/creature.cpp | 6 ++---- apps/openmw/mwclass/creature.hpp | 3 +-- apps/openmw/mwclass/door.cpp | 6 ++---- apps/openmw/mwclass/door.hpp | 3 +-- apps/openmw/mwclass/ingredient.cpp | 6 ++---- apps/openmw/mwclass/ingredient.hpp | 3 +-- apps/openmw/mwclass/light.cpp | 6 ++---- apps/openmw/mwclass/light.hpp | 3 +-- apps/openmw/mwclass/lockpick.cpp | 6 ++---- apps/openmw/mwclass/lockpick.hpp | 3 +-- apps/openmw/mwclass/misc.cpp | 7 +++---- apps/openmw/mwclass/misc.hpp | 3 +-- apps/openmw/mwclass/npc.cpp | 6 ++---- apps/openmw/mwclass/npc.hpp | 3 +-- apps/openmw/mwclass/potion.cpp | 6 ++---- apps/openmw/mwclass/potion.hpp | 3 +-- apps/openmw/mwclass/probe.cpp | 6 ++---- apps/openmw/mwclass/probe.hpp | 3 +-- apps/openmw/mwclass/repair.cpp | 6 ++---- apps/openmw/mwclass/repair.hpp | 3 +-- apps/openmw/mwclass/static.cpp | 6 ++---- apps/openmw/mwclass/static.hpp | 3 +-- apps/openmw/mwclass/weapon.cpp | 5 ++--- apps/openmw/mwclass/weapon.hpp | 2 +- apps/openmw/mwworld/class.cpp | 8 ++++---- apps/openmw/mwworld/class.hpp | 8 +++----- 38 files changed, 62 insertions(+), 114 deletions(-) diff --git a/apps/openmw/mwclass/activator.cpp b/apps/openmw/mwclass/activator.cpp index fcf5dcfd7..799ab5311 100644 --- a/apps/openmw/mwclass/activator.cpp +++ b/apps/openmw/mwclass/activator.cpp @@ -120,11 +120,9 @@ namespace MWClass } - MWWorld::Ptr - Activator::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const + MWWorld::Ptr Activator::copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return MWWorld::Ptr(cell.insert(ref), &cell); } diff --git a/apps/openmw/mwclass/activator.hpp b/apps/openmw/mwclass/activator.hpp index 7cdd9506c..7214b86e0 100644 --- a/apps/openmw/mwclass/activator.hpp +++ b/apps/openmw/mwclass/activator.hpp @@ -8,8 +8,7 @@ namespace MWClass class Activator : public MWWorld::Class { - virtual MWWorld::Ptr - copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const; + virtual MWWorld::Ptr copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const; public: diff --git a/apps/openmw/mwclass/apparatus.cpp b/apps/openmw/mwclass/apparatus.cpp index a90a53adb..36870997b 100644 --- a/apps/openmw/mwclass/apparatus.cpp +++ b/apps/openmw/mwclass/apparatus.cpp @@ -135,11 +135,9 @@ namespace MWClass return boost::shared_ptr(new MWWorld::ActionAlchemy()); } - MWWorld::Ptr - Apparatus::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const + MWWorld::Ptr Apparatus::copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return MWWorld::Ptr(cell.insert(ref), &cell); } diff --git a/apps/openmw/mwclass/apparatus.hpp b/apps/openmw/mwclass/apparatus.hpp index e50a57c6a..d8176d5df 100644 --- a/apps/openmw/mwclass/apparatus.hpp +++ b/apps/openmw/mwclass/apparatus.hpp @@ -8,8 +8,7 @@ namespace MWClass class Apparatus : public MWWorld::Class { - virtual MWWorld::Ptr - copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const; + virtual MWWorld::Ptr copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const; public: diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index 500664b36..d4605a195 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -365,11 +365,9 @@ namespace MWClass return action; } - MWWorld::Ptr - Armor::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const + MWWorld::Ptr Armor::copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return MWWorld::Ptr(cell.insert(ref), &cell); } diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index 8ddd92e4d..5fd431193 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -7,8 +7,7 @@ namespace MWClass { class Armor : public MWWorld::Class { - virtual MWWorld::Ptr - copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const; + virtual MWWorld::Ptr copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const; public: diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index 25be08587..591a3cc69 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -173,11 +173,9 @@ namespace MWClass return boost::shared_ptr(new MWWorld::ActionRead(ptr)); } - MWWorld::Ptr - Book::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const + MWWorld::Ptr Book::copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return MWWorld::Ptr(cell.insert(ref), &cell); } diff --git a/apps/openmw/mwclass/book.hpp b/apps/openmw/mwclass/book.hpp index a0b5b434e..84f744893 100644 --- a/apps/openmw/mwclass/book.hpp +++ b/apps/openmw/mwclass/book.hpp @@ -7,8 +7,7 @@ namespace MWClass { class Book : public MWWorld::Class { - virtual MWWorld::Ptr - copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const; + virtual MWWorld::Ptr copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const; public: diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index bf3b90941..d7a949168 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -258,11 +258,9 @@ namespace MWClass return action; } - MWWorld::Ptr - Clothing::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const + MWWorld::Ptr Clothing::copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return MWWorld::Ptr(cell.insert(ref), &cell); } diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index e513613e4..13ec2e593 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -7,8 +7,7 @@ namespace MWClass { class Clothing : public MWWorld::Class { - virtual MWWorld::Ptr - copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const; + virtual MWWorld::Ptr copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const; public: diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index c70228bae..03c676b9e 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -284,10 +284,9 @@ namespace MWClass return true; } - MWWorld::Ptr Container::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const + MWWorld::Ptr Container::copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return MWWorld::Ptr(cell.insert(ref), &cell); } diff --git a/apps/openmw/mwclass/container.hpp b/apps/openmw/mwclass/container.hpp index c6a23df6c..9b6d5d2e0 100644 --- a/apps/openmw/mwclass/container.hpp +++ b/apps/openmw/mwclass/container.hpp @@ -10,8 +10,7 @@ namespace MWClass void ensureCustomData (const MWWorld::Ptr& ptr) const; - virtual MWWorld::Ptr - copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const; + virtual MWWorld::Ptr copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const; public: diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index f903144b6..38e0a826d 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -590,11 +590,9 @@ namespace MWClass return ""; } - MWWorld::Ptr - Creature::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const + MWWorld::Ptr Creature::copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return MWWorld::Ptr(cell.insert(ref), &cell); } diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index 5f110e918..5076d36d0 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -14,8 +14,7 @@ namespace MWClass { void ensureCustomData (const MWWorld::Ptr& ptr) const; - virtual MWWorld::Ptr - copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const; + virtual MWWorld::Ptr copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const; static int getSndGenTypeFromName(const MWWorld::Ptr &ptr, const std::string &name); diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 3e6f2b956..f279ae3a0 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -299,11 +299,9 @@ namespace MWClass return "#{sCell=" + dest + "}"; } - MWWorld::Ptr - Door::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const + MWWorld::Ptr Door::copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return MWWorld::Ptr(cell.insert(ref), &cell); } diff --git a/apps/openmw/mwclass/door.hpp b/apps/openmw/mwclass/door.hpp index 6cb297ca5..f789055ff 100644 --- a/apps/openmw/mwclass/door.hpp +++ b/apps/openmw/mwclass/door.hpp @@ -11,8 +11,7 @@ namespace MWClass { void ensureCustomData (const MWWorld::Ptr& ptr) const; - virtual MWWorld::Ptr - copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const; + virtual MWWorld::Ptr copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const; public: diff --git a/apps/openmw/mwclass/ingredient.cpp b/apps/openmw/mwclass/ingredient.cpp index bdc67b452..bfe482e96 100644 --- a/apps/openmw/mwclass/ingredient.cpp +++ b/apps/openmw/mwclass/ingredient.cpp @@ -172,11 +172,9 @@ namespace MWClass return info; } - MWWorld::Ptr - Ingredient::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const + MWWorld::Ptr Ingredient::copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return MWWorld::Ptr(cell.insert(ref), &cell); } diff --git a/apps/openmw/mwclass/ingredient.hpp b/apps/openmw/mwclass/ingredient.hpp index 96fc7e8e4..dd156d314 100644 --- a/apps/openmw/mwclass/ingredient.hpp +++ b/apps/openmw/mwclass/ingredient.hpp @@ -7,8 +7,7 @@ namespace MWClass { class Ingredient : public MWWorld::Class { - virtual MWWorld::Ptr - copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const; + virtual MWWorld::Ptr copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const; public: diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 626cde9ac..86f1b1d61 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -203,11 +203,9 @@ namespace MWClass return ptr.getCellRef().getChargeFloat(); } - MWWorld::Ptr - Light::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const + MWWorld::Ptr Light::copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return MWWorld::Ptr(cell.insert(ref), &cell); } diff --git a/apps/openmw/mwclass/light.hpp b/apps/openmw/mwclass/light.hpp index a52c3f568..7fbaa833a 100644 --- a/apps/openmw/mwclass/light.hpp +++ b/apps/openmw/mwclass/light.hpp @@ -7,8 +7,7 @@ namespace MWClass { class Light : public MWWorld::Class { - virtual MWWorld::Ptr - copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const; + virtual MWWorld::Ptr copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const; public: diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index b46159cbc..abf9f9c14 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -153,11 +153,9 @@ namespace MWClass return action; } - MWWorld::Ptr - Lockpick::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const + MWWorld::Ptr Lockpick::copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return MWWorld::Ptr(cell.insert(ref), &cell); } diff --git a/apps/openmw/mwclass/lockpick.hpp b/apps/openmw/mwclass/lockpick.hpp index b5b4844c3..7225cab11 100644 --- a/apps/openmw/mwclass/lockpick.hpp +++ b/apps/openmw/mwclass/lockpick.hpp @@ -7,8 +7,7 @@ namespace MWClass { class Lockpick : public MWWorld::Class { - virtual MWWorld::Ptr - copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const; + virtual MWWorld::Ptr copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const; public: diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index c8fdc2a8a..1c8e75f1f 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -182,8 +182,7 @@ namespace MWClass return info; } - MWWorld::Ptr - Miscellaneous::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const + MWWorld::Ptr Miscellaneous::copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const { MWWorld::Ptr newPtr; @@ -206,14 +205,14 @@ namespace MWClass // Really, I have no idea why moving ref out of conditional // scope causes list::push_back throwing std::bad_alloc MWWorld::ManualRef newRef(store, base); - MWWorld::LiveCellRef *ref = + const MWWorld::LiveCellRef *ref = newRef.getPtr().get(); newPtr = MWWorld::Ptr(cell.insert(ref), &cell); newPtr.getCellRef().setGoldValue(goldAmount); newPtr.getRefData().setCount(1); } else { - MWWorld::LiveCellRef *ref = + const MWWorld::LiveCellRef *ref = ptr.get(); newPtr = MWWorld::Ptr(cell.insert(ref), &cell); } diff --git a/apps/openmw/mwclass/misc.hpp b/apps/openmw/mwclass/misc.hpp index 679319e02..d9979fa87 100644 --- a/apps/openmw/mwclass/misc.hpp +++ b/apps/openmw/mwclass/misc.hpp @@ -7,8 +7,7 @@ namespace MWClass { class Miscellaneous : public MWWorld::Class { - virtual MWWorld::Ptr - copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const; + virtual MWWorld::Ptr copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const; public: diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 8ef3c219a..42e28fc2f 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -1124,11 +1124,9 @@ namespace MWClass throw std::runtime_error(std::string("Unexpected soundgen type: ")+name); } - MWWorld::Ptr - Npc::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const + MWWorld::Ptr Npc::copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return MWWorld::Ptr(cell.insert(ref), &cell); } diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index acde83c5f..b62192367 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -14,8 +14,7 @@ namespace MWClass { void ensureCustomData (const MWWorld::Ptr& ptr) const; - virtual MWWorld::Ptr - copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const; + virtual MWWorld::Ptr copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const; struct GMST { diff --git a/apps/openmw/mwclass/potion.cpp b/apps/openmw/mwclass/potion.cpp index e4928384d..f0875d138 100644 --- a/apps/openmw/mwclass/potion.cpp +++ b/apps/openmw/mwclass/potion.cpp @@ -166,11 +166,9 @@ namespace MWClass return action; } - MWWorld::Ptr - Potion::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const + MWWorld::Ptr Potion::copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return MWWorld::Ptr(cell.insert(ref), &cell); } diff --git a/apps/openmw/mwclass/potion.hpp b/apps/openmw/mwclass/potion.hpp index ac6e0d180..92f0ebcd9 100644 --- a/apps/openmw/mwclass/potion.hpp +++ b/apps/openmw/mwclass/potion.hpp @@ -7,8 +7,7 @@ namespace MWClass { class Potion : public MWWorld::Class { - virtual MWWorld::Ptr - copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const; + virtual MWWorld::Ptr copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const; public: diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index ac9ac56e8..010a73a3c 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -153,11 +153,9 @@ namespace MWClass return action; } - MWWorld::Ptr - Probe::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const + MWWorld::Ptr Probe::copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return MWWorld::Ptr(cell.insert(ref), &cell); } diff --git a/apps/openmw/mwclass/probe.hpp b/apps/openmw/mwclass/probe.hpp index d0a4b4947..2dc63b155 100644 --- a/apps/openmw/mwclass/probe.hpp +++ b/apps/openmw/mwclass/probe.hpp @@ -7,8 +7,7 @@ namespace MWClass { class Probe : public MWWorld::Class { - virtual MWWorld::Ptr - copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const; + virtual MWWorld::Ptr copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const; public: diff --git a/apps/openmw/mwclass/repair.cpp b/apps/openmw/mwclass/repair.cpp index 1940baa67..6d681a87c 100644 --- a/apps/openmw/mwclass/repair.cpp +++ b/apps/openmw/mwclass/repair.cpp @@ -147,11 +147,9 @@ namespace MWClass return info; } - MWWorld::Ptr - Repair::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const + MWWorld::Ptr Repair::copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return MWWorld::Ptr(cell.insert(ref), &cell); } diff --git a/apps/openmw/mwclass/repair.hpp b/apps/openmw/mwclass/repair.hpp index dce47167f..2dcf03ce2 100644 --- a/apps/openmw/mwclass/repair.hpp +++ b/apps/openmw/mwclass/repair.hpp @@ -7,8 +7,7 @@ namespace MWClass { class Repair : public MWWorld::Class { - virtual MWWorld::Ptr - copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const; + virtual MWWorld::Ptr copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const; public: diff --git a/apps/openmw/mwclass/static.cpp b/apps/openmw/mwclass/static.cpp index 5539f8375..a6863f400 100644 --- a/apps/openmw/mwclass/static.cpp +++ b/apps/openmw/mwclass/static.cpp @@ -52,11 +52,9 @@ namespace MWClass registerClass (typeid (ESM::Static).name(), instance); } - MWWorld::Ptr - Static::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const + MWWorld::Ptr Static::copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return MWWorld::Ptr(cell.insert(ref), &cell); } diff --git a/apps/openmw/mwclass/static.hpp b/apps/openmw/mwclass/static.hpp index 9c4a61410..f2a5cef92 100644 --- a/apps/openmw/mwclass/static.hpp +++ b/apps/openmw/mwclass/static.hpp @@ -7,8 +7,7 @@ namespace MWClass { class Static : public MWWorld::Class { - virtual MWWorld::Ptr - copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const; + virtual MWWorld::Ptr copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const; public: diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index db1448afc..1b40787c8 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -399,10 +399,9 @@ namespace MWClass } MWWorld::Ptr - Weapon::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const + Weapon::copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return MWWorld::Ptr(cell.insert(ref), &cell); } diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index 611e2edf0..aa87afc7a 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -8,7 +8,7 @@ namespace MWClass class Weapon : public MWWorld::Class { virtual MWWorld::Ptr - copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const; + copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const; public: diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 8722187ab..7b57a2136 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -333,13 +333,13 @@ namespace MWWorld } MWWorld::Ptr - Class::copyToCellImpl(const Ptr &ptr, CellStore &cell) const + Class::copyToCellImpl(const ConstPtr &ptr, CellStore &cell) const { - throw std::runtime_error("unable to move class to cell"); + throw std::runtime_error("unable to copy class to cell"); } MWWorld::Ptr - Class::copyToCell(const Ptr &ptr, CellStore &cell) const + Class::copyToCell(const ConstPtr &ptr, CellStore &cell) const { Ptr newPtr = copyToCellImpl(ptr, cell); newPtr.getCellRef().unsetRefNum(); // This RefNum is only valid within the original cell of the reference @@ -347,7 +347,7 @@ namespace MWWorld } MWWorld::Ptr - Class::copyToCell(const Ptr &ptr, CellStore &cell, const ESM::Position &pos) const + Class::copyToCell(const ConstPtr &ptr, CellStore &cell, const ESM::Position &pos) const { Ptr newPtr = copyToCell(ptr, cell); newPtr.getRefData().setPosition(pos); diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 619508f74..26bd98aa4 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -66,7 +66,7 @@ namespace MWWorld boost::shared_ptr defaultItemActivate(const Ptr &ptr, const Ptr &actor) const; ///< Generate default action for activating inventory items - virtual Ptr copyToCellImpl(const Ptr &ptr, CellStore &cell) const; + virtual Ptr copyToCellImpl(const ConstPtr &ptr, CellStore &cell) const; public: @@ -286,11 +286,9 @@ namespace MWWorld /// Get a blood texture suitable for \a ptr (see Blood Texture 0-2 in Morrowind.ini) virtual int getBloodTexture (const MWWorld::Ptr& ptr) const; - virtual Ptr - copyToCell(const Ptr &ptr, CellStore &cell) const; + virtual Ptr copyToCell(const ConstPtr &ptr, CellStore &cell) const; - virtual Ptr - copyToCell(const Ptr &ptr, CellStore &cell, const ESM::Position &pos) const; + virtual Ptr copyToCell(const ConstPtr &ptr, CellStore &cell, const ESM::Position &pos) const; virtual bool isActor() const { return false; From 5b082be79fa70795dd54623b590fe55e57239968 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 16:28:20 +0100 Subject: [PATCH 2870/3725] Accept a ConstPtr in getBaseGold --- apps/openmw/mwclass/creature.cpp | 2 +- apps/openmw/mwclass/creature.hpp | 2 +- apps/openmw/mwclass/npc.cpp | 4 ++-- apps/openmw/mwclass/npc.hpp | 2 +- apps/openmw/mwworld/class.cpp | 2 +- apps/openmw/mwworld/class.hpp | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 38e0a826d..dc64fd3be 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -735,7 +735,7 @@ namespace MWClass customData.mCreatureStats.writeState (state2.mCreatureStats); } - int Creature::getBaseGold(const MWWorld::Ptr& ptr) const + int Creature::getBaseGold(const MWWorld::ConstPtr& ptr) const { return ptr.get()->mBase->mData.mGold; } diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index 5076d36d0..27dc197f9 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -122,7 +122,7 @@ namespace MWClass virtual void writeAdditionalState (const MWWorld::ConstPtr& ptr, ESM::ObjectState& state) const; ///< Write additional state from \a ptr into \a state. - virtual int getBaseGold(const MWWorld::Ptr& ptr) const; + virtual int getBaseGold(const MWWorld::ConstPtr& ptr) const; virtual void respawn (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 42e28fc2f..7238ad453 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -1192,9 +1192,9 @@ namespace MWClass static_cast (customData.mNpcStats).writeState (state2.mCreatureStats); } - int Npc::getBaseGold(const MWWorld::Ptr& ptr) const + int Npc::getBaseGold(const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); if(ref->mBase->mNpdtType != ESM::NPC::NPC_WITH_AUTOCALCULATED_STATS) return ref->mBase->mNpdt52.mGold; else diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index b62192367..946276876 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -148,7 +148,7 @@ namespace MWClass const; ///< Write additional state from \a ptr into \a state. - virtual int getBaseGold(const MWWorld::Ptr& ptr) const; + virtual int getBaseGold(const MWWorld::ConstPtr& ptr) const; virtual bool isClass(const MWWorld::Ptr& ptr, const std::string &className) const; diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 7b57a2136..c4cef4a8b 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -399,7 +399,7 @@ namespace MWWorld void Class::writeAdditionalState (const MWWorld::ConstPtr& ptr, ESM::ObjectState& state) const {} - int Class::getBaseGold(const MWWorld::Ptr& ptr) const + int Class::getBaseGold(const MWWorld::ConstPtr& ptr) const { throw std::runtime_error("class does not support base gold"); } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 26bd98aa4..fd2c1da8e 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -320,7 +320,7 @@ namespace MWWorld static void registerClass (const std::string& key, boost::shared_ptr instance); - virtual int getBaseGold(const MWWorld::Ptr& ptr) const; + virtual int getBaseGold(const MWWorld::ConstPtr& ptr) const; virtual bool isClass(const MWWorld::Ptr& ptr, const std::string &className) const; From 2ac92012e8e7b5b7011d3fcb89802dbf62dc9ed7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 16:29:30 +0100 Subject: [PATCH 2871/3725] Accept a ConstPtr in isClass --- apps/openmw/mwclass/npc.cpp | 2 +- apps/openmw/mwclass/npc.hpp | 2 +- apps/openmw/mwworld/class.cpp | 2 +- apps/openmw/mwworld/class.hpp | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 7238ad453..82dcf052b 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -1201,7 +1201,7 @@ namespace MWClass return ref->mBase->mNpdt12.mGold; } - bool Npc::isClass(const MWWorld::Ptr& ptr, const std::string &className) const + bool Npc::isClass(const MWWorld::ConstPtr& ptr, const std::string &className) const { return Misc::StringUtils::ciEqual(ptr.get()->mBase->mClass, className); } diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index 946276876..f86eeb8ff 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -150,7 +150,7 @@ namespace MWClass virtual int getBaseGold(const MWWorld::ConstPtr& ptr) const; - virtual bool isClass(const MWWorld::Ptr& ptr, const std::string &className) const; + virtual bool isClass(const MWWorld::ConstPtr& ptr, const std::string &className) const; virtual bool canSwim (const MWWorld::ConstPtr &ptr) const; diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index c4cef4a8b..bf5fdebb8 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -404,7 +404,7 @@ namespace MWWorld throw std::runtime_error("class does not support base gold"); } - bool Class::isClass(const MWWorld::Ptr& ptr, const std::string &className) const + bool Class::isClass(const MWWorld::ConstPtr& ptr, const std::string &className) const { return false; } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index fd2c1da8e..5a9a49d5a 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -322,7 +322,7 @@ namespace MWWorld virtual int getBaseGold(const MWWorld::ConstPtr& ptr) const; - virtual bool isClass(const MWWorld::Ptr& ptr, const std::string &className) const; + virtual bool isClass(const MWWorld::ConstPtr& ptr, const std::string &className) const; /// 0 = nothing, 1 = opening, 2 = closing virtual int getDoorState (const MWWorld::Ptr &ptr) const; From 2bd8d60e9fc0bed16fa031f08bed03b430f81e77 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 16:33:54 +0100 Subject: [PATCH 2872/3725] Accept a ConstPtr in getPrimaryFaction, getPrimaryFactionRank --- apps/openmw/mwclass/npc.cpp | 8 ++++---- apps/openmw/mwclass/npc.hpp | 4 ++-- apps/openmw/mwscript/statsextensions.cpp | 24 ++++++++++++------------ apps/openmw/mwworld/class.cpp | 4 ++-- apps/openmw/mwworld/class.hpp | 4 ++-- 5 files changed, 22 insertions(+), 22 deletions(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 82dcf052b..be5f6c6db 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -1255,15 +1255,15 @@ namespace MWClass return true; } - std::string Npc::getPrimaryFaction (const MWWorld::Ptr& ptr) const + std::string Npc::getPrimaryFaction (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mFaction; } - int Npc::getPrimaryFactionRank (const MWWorld::Ptr& ptr) const + int Npc::getPrimaryFactionRank (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->getFactionRank(); } } diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index f86eeb8ff..ba2679c08 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -164,8 +164,8 @@ namespace MWClass virtual int getBaseFightRating (const MWWorld::ConstPtr& ptr) const; - virtual std::string getPrimaryFaction(const MWWorld::Ptr &ptr) const; - virtual int getPrimaryFactionRank(const MWWorld::Ptr &ptr) const; + virtual std::string getPrimaryFaction(const MWWorld::ConstPtr &ptr) const; + virtual int getPrimaryFactionRank(const MWWorld::ConstPtr &ptr) const; }; } diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index dcac73311..2a504f2ab 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -32,7 +32,7 @@ namespace { - std::string getDialogueActorFaction(MWWorld::Ptr actor) + std::string getDialogueActorFaction(MWWorld::ConstPtr actor) { std::string factionId = actor.getClass().getPrimaryFaction(actor); if (factionId.empty()) @@ -530,7 +530,7 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0) { - MWWorld::Ptr actor = R()(runtime, false); + MWWorld::ConstPtr actor = R()(runtime, false); std::string factionID = ""; @@ -562,7 +562,7 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0) { - MWWorld::Ptr actor = R()(runtime, false); + MWWorld::ConstPtr actor = R()(runtime, false); std::string factionID = ""; @@ -601,7 +601,7 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0) { - MWWorld::Ptr actor = R()(runtime, false); + MWWorld::ConstPtr actor = R()(runtime, false); std::string factionID = ""; @@ -633,7 +633,7 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0) { - MWWorld::Ptr ptr = R()(runtime, false); + MWWorld::ConstPtr ptr = R()(runtime, false); std::string factionID = ""; if(arg0 >0) @@ -739,7 +739,7 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0) { - MWWorld::Ptr ptr = R()(runtime, false); + MWWorld::ConstPtr ptr = R()(runtime, false); std::string factionId; @@ -771,7 +771,7 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0) { - MWWorld::Ptr ptr = R()(runtime, false); + MWWorld::ConstPtr ptr = R()(runtime, false); Interpreter::Type_Integer value = runtime[0].mInteger; runtime.pop(); @@ -805,7 +805,7 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0) { - MWWorld::Ptr ptr = R()(runtime, false); + MWWorld::ConstPtr ptr = R()(runtime, false); Interpreter::Type_Integer value = runtime[0].mInteger; runtime.pop(); @@ -867,7 +867,7 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { - MWWorld::Ptr ptr = R()(runtime); + MWWorld::ConstPtr ptr = R()(runtime); std::string race = runtime.getStringLiteral(runtime[0].mInteger); ::Misc::StringUtils::lowerCaseInPlace(race); @@ -899,7 +899,7 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0) { - MWWorld::Ptr ptr = R()(runtime, false); + MWWorld::ConstPtr ptr = R()(runtime, false); std::string factionID = ""; if(arg0 >0 ) @@ -931,7 +931,7 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0) { - MWWorld::Ptr ptr = R()(runtime, false); + MWWorld::ConstPtr ptr = R()(runtime, false); std::string factionID = ""; if(arg0 >0 ) @@ -958,7 +958,7 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0) { - MWWorld::Ptr ptr = R()(runtime, false); + MWWorld::ConstPtr ptr = R()(runtime, false); std::string factionID = ""; if(arg0 >0 ) diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index bf5fdebb8..9ff6beb8e 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -438,11 +438,11 @@ namespace MWWorld throw std::runtime_error("class does not support fight rating"); } - std::string Class::getPrimaryFaction (const MWWorld::Ptr& ptr) const + std::string Class::getPrimaryFaction (const MWWorld::ConstPtr& ptr) const { return std::string(); } - int Class::getPrimaryFactionRank (const MWWorld::Ptr& ptr) const + int Class::getPrimaryFactionRank (const MWWorld::ConstPtr& ptr) const { return -1; } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 5a9a49d5a..10754de7d 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -338,8 +338,8 @@ namespace MWWorld virtual int getBaseFightRating (const MWWorld::ConstPtr& ptr) const; - virtual std::string getPrimaryFaction (const MWWorld::Ptr& ptr) const; - virtual int getPrimaryFactionRank (const MWWorld::Ptr& ptr) const; + virtual std::string getPrimaryFaction (const MWWorld::ConstPtr& ptr) const; + virtual int getPrimaryFactionRank (const MWWorld::ConstPtr& ptr) const; /// Get the effective armor rating, factoring in the actor's skills, for the given armor. virtual int getEffectiveArmorRating(const MWWorld::ConstPtr& armor, const MWWorld::Ptr& actor) const; From 4a47fc32fae0040732688fdbd1d0ebeffbff6a58 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 16:38:14 +0100 Subject: [PATCH 2873/3725] Accept a ConstPtr in getBloodTexture --- apps/openmw/mwclass/creature.cpp | 2 +- apps/openmw/mwclass/creature.hpp | 2 +- apps/openmw/mwclass/npc.cpp | 4 ++-- apps/openmw/mwclass/npc.hpp | 2 +- apps/openmw/mwworld/class.cpp | 2 +- apps/openmw/mwworld/class.hpp | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index dc64fd3be..6646a7d79 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -675,7 +675,7 @@ namespace MWClass } } - int Creature::getBloodTexture(const MWWorld::Ptr &ptr) const + int Creature::getBloodTexture(const MWWorld::ConstPtr &ptr) const { int flags = ptr.get()->mBase->mFlags; diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index 27dc197f9..720d87f17 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -114,7 +114,7 @@ namespace MWClass virtual int getSkill(const MWWorld::Ptr &ptr, int skill) const; /// Get a blood texture suitable for \a ptr (see Blood Texture 0-2 in Morrowind.ini) - virtual int getBloodTexture (const MWWorld::Ptr& ptr) const; + virtual int getBloodTexture (const MWWorld::ConstPtr& ptr) const; virtual void readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state) const; ///< Read additional state from \a state into \a ptr. diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index be5f6c6db..350b644ed 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -1136,9 +1136,9 @@ namespace MWClass return ptr.getClass().getNpcStats(ptr).getSkill(skill).getModified(); } - int Npc::getBloodTexture(const MWWorld::Ptr &ptr) const + int Npc::getBloodTexture(const MWWorld::ConstPtr &ptr) const { - MWWorld::LiveCellRef *ref = ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); if (ref->mBase->mFlags & ESM::NPC::Skeleton) return 1; diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index ba2679c08..684d891f9 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -130,7 +130,7 @@ namespace MWClass virtual int getSkill(const MWWorld::Ptr& ptr, int skill) const; /// Get a blood texture suitable for \a ptr (see Blood Texture 0-2 in Morrowind.ini) - virtual int getBloodTexture (const MWWorld::Ptr& ptr) const; + virtual int getBloodTexture (const MWWorld::ConstPtr& ptr) const; virtual bool isActor() const { return true; diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 9ff6beb8e..a0037df57 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -390,7 +390,7 @@ namespace MWWorld throw std::runtime_error("class does not support skills"); } - int Class::getBloodTexture (const MWWorld::Ptr& ptr) const + int Class::getBloodTexture (const MWWorld::ConstPtr& ptr) const { throw std::runtime_error("class does not support gore"); } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 10754de7d..04d22f91a 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -284,7 +284,7 @@ namespace MWWorld virtual bool isGold(const MWWorld::ConstPtr& ptr) const { return false; }; /// Get a blood texture suitable for \a ptr (see Blood Texture 0-2 in Morrowind.ini) - virtual int getBloodTexture (const MWWorld::Ptr& ptr) const; + virtual int getBloodTexture (const MWWorld::ConstPtr& ptr) const; virtual Ptr copyToCell(const ConstPtr &ptr, CellStore &cell) const; From 3fe3091275f3e6a1f1d7d144ee997b237672898b Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 16:39:35 +0100 Subject: [PATCH 2874/3725] Accept a ConstPtr in isEssential --- apps/openmw/mwclass/creature.cpp | 2 +- apps/openmw/mwclass/creature.hpp | 2 +- apps/openmw/mwclass/npc.cpp | 5 ++--- apps/openmw/mwclass/npc.hpp | 2 +- apps/openmw/mwworld/class.cpp | 2 +- apps/openmw/mwworld/class.hpp | 2 +- 6 files changed, 7 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 6646a7d79..2483f2a7e 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -448,7 +448,7 @@ namespace MWClass return ref->mBase->mScript; } - bool Creature::isEssential (const MWWorld::Ptr& ptr) const + bool Creature::isEssential (const MWWorld::ConstPtr& ptr) const { return isFlagBitSet(ptr, ESM::Creature::Essential); } diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index 720d87f17..72305a1d8 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -83,7 +83,7 @@ namespace MWClass virtual float getArmorRating (const MWWorld::Ptr& ptr) const; ///< @return combined armor rating of this actor - virtual bool isEssential (const MWWorld::Ptr& ptr) const; + virtual bool isEssential (const MWWorld::ConstPtr& ptr) const; ///< Is \a ptr essential? (i.e. may losing \a ptr make the game unwinnable) virtual int getServices (const MWWorld::Ptr& actor) const; diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 350b644ed..0e9618608 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -908,10 +908,9 @@ namespace MWClass return ptr.getRefData().getCustomData()->asNpcCustomData().mMovement; } - bool Npc::isEssential (const MWWorld::Ptr& ptr) const + bool Npc::isEssential (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return (ref->mBase->mFlags & ESM::NPC::Essential) != 0; } diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index 684d891f9..3dfb0b96e 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -114,7 +114,7 @@ namespace MWClass virtual void skillUsageSucceeded (const MWWorld::Ptr& ptr, int skill, int usageType, float extraFactor=1.f) const; ///< Inform actor \a ptr that a skill use has succeeded. - virtual bool isEssential (const MWWorld::Ptr& ptr) const; + virtual bool isEssential (const MWWorld::ConstPtr& ptr) const; ///< Is \a ptr essential? (i.e. may losing \a ptr make the game unwinnable) virtual int getServices (const MWWorld::Ptr& actor) const; diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index a0037df57..a07c94a0c 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -218,7 +218,7 @@ namespace MWWorld throw std::runtime_error ("encumbrance not supported by class"); } - bool Class::isEssential (const MWWorld::Ptr& ptr) const + bool Class::isEssential (const MWWorld::ConstPtr& ptr) const { return false; } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 04d22f91a..4fc0c96ec 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -229,7 +229,7 @@ namespace MWWorld /// /// (default implementations: throws an exception) - virtual bool isEssential (const MWWorld::Ptr& ptr) const; + virtual bool isEssential (const MWWorld::ConstPtr& ptr) const; ///< Is \a ptr essential? (i.e. may losing \a ptr make the game unwinnable) /// /// (default implementation: return false) From 3c98f8dde3b3a89c3fb6bf50b7e1c141aa1a6202 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 16:41:37 +0100 Subject: [PATCH 2875/3725] Accept a ConstPtr in isPersistent --- apps/openmw/mwclass/creature.cpp | 4 ++-- apps/openmw/mwclass/creature.hpp | 2 +- apps/openmw/mwclass/npc.cpp | 4 ++-- apps/openmw/mwclass/npc.hpp | 2 +- apps/openmw/mwworld/class.cpp | 2 +- apps/openmw/mwworld/class.hpp | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 2483f2a7e..26bb45ea3 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -554,9 +554,9 @@ namespace MWClass return 0; } - bool Creature::isPersistent(const MWWorld::Ptr &actor) const + bool Creature::isPersistent(const MWWorld::ConstPtr &actor) const { - MWWorld::LiveCellRef* ref = actor.get(); + const MWWorld::LiveCellRef* ref = actor.get(); return ref->mBase->mPersistent; } diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index 72305a1d8..2299e655c 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -88,7 +88,7 @@ namespace MWClass virtual int getServices (const MWWorld::Ptr& actor) const; - virtual bool isPersistent (const MWWorld::Ptr& ptr) const; + virtual bool isPersistent (const MWWorld::ConstPtr& ptr) const; virtual std::string getSoundIdFromSndGen(const MWWorld::Ptr &ptr, const std::string &name) const; diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 0e9618608..d05b0235e 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -419,9 +419,9 @@ namespace MWClass renderingInterface.getObjects().insertNPC(ptr); } - bool Npc::isPersistent(const MWWorld::Ptr &actor) const + bool Npc::isPersistent(const MWWorld::ConstPtr &actor) const { - MWWorld::LiveCellRef* ref = actor.get(); + const MWWorld::LiveCellRef* ref = actor.get(); return ref->mBase->mPersistent; } diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index 3dfb0b96e..8dd78f484 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -119,7 +119,7 @@ namespace MWClass virtual int getServices (const MWWorld::Ptr& actor) const; - virtual bool isPersistent (const MWWorld::Ptr& ptr) const; + virtual bool isPersistent (const MWWorld::ConstPtr& ptr) const; virtual std::string getSoundIdFromSndGen(const MWWorld::Ptr &ptr, const std::string &name) const; diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index a07c94a0c..b4861c85f 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -241,7 +241,7 @@ namespace MWWorld return *iter->second; } - bool Class::isPersistent(const Ptr &ptr) const + bool Class::isPersistent(const ConstPtr &ptr) const { throw std::runtime_error ("class does not support persistence"); } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 4fc0c96ec..3cf4326c8 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -277,7 +277,7 @@ namespace MWWorld virtual float getWeight (const MWWorld::ConstPtr& ptr) const; - virtual bool isPersistent (const MWWorld::Ptr& ptr) const; + virtual bool isPersistent (const MWWorld::ConstPtr& ptr) const; virtual bool isKey (const MWWorld::ConstPtr& ptr) const { return false; } From 648ee6e7fb04424b05ca405b4c229b5bf6597dbd Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 16:43:11 +0100 Subject: [PATCH 2876/3725] Accept a ConstPtr in applyEnchantment --- apps/openmw/mwclass/armor.cpp | 5 ++--- apps/openmw/mwclass/armor.hpp | 2 +- apps/openmw/mwclass/book.cpp | 5 ++--- apps/openmw/mwclass/book.hpp | 2 +- apps/openmw/mwclass/clothing.cpp | 5 ++--- apps/openmw/mwclass/clothing.hpp | 2 +- apps/openmw/mwclass/weapon.cpp | 5 ++--- apps/openmw/mwclass/weapon.hpp | 2 +- apps/openmw/mwworld/class.cpp | 2 +- apps/openmw/mwworld/class.hpp | 4 ++-- 10 files changed, 15 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index d4605a195..f11bbcda8 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -265,10 +265,9 @@ namespace MWClass return ref->mBase->mEnchant; } - std::string Armor::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const + std::string Armor::applyEnchantment(const MWWorld::ConstPtr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); ESM::Armor newItem = *ref->mBase; newItem.mId=""; diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index 5fd431193..598b77929 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -69,7 +69,7 @@ namespace MWClass virtual std::string getEnchantment (const MWWorld::ConstPtr& ptr) const; ///< @return the enchantment ID if the object is enchanted, otherwise an empty string - virtual std::string applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; + virtual std::string applyEnchantment(const MWWorld::ConstPtr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; ///< Creates a new record using \a ptr as template, with the given name and the given enchantment applied to it. virtual std::pair canBeEquipped(const MWWorld::ConstPtr &ptr, const MWWorld::Ptr &npc) const; diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index 591a3cc69..faea0d6f2 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -153,10 +153,9 @@ namespace MWClass return ref->mBase->mEnchant; } - std::string Book::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const + std::string Book::applyEnchantment(const MWWorld::ConstPtr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); ESM::Book newItem = *ref->mBase; newItem.mId=""; diff --git a/apps/openmw/mwclass/book.hpp b/apps/openmw/mwclass/book.hpp index 84f744893..6b8be41bb 100644 --- a/apps/openmw/mwclass/book.hpp +++ b/apps/openmw/mwclass/book.hpp @@ -53,7 +53,7 @@ namespace MWClass virtual std::string getEnchantment (const MWWorld::ConstPtr& ptr) const; ///< @return the enchantment ID if the object is enchanted, otherwise an empty string - virtual std::string applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; + virtual std::string applyEnchantment(const MWWorld::ConstPtr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; ///< Creates a new record using \a ptr as template, with the given name and the given enchantment applied to it. virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index d7a949168..2e2b8af84 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -204,10 +204,9 @@ namespace MWClass return ref->mBase->mEnchant; } - std::string Clothing::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const + std::string Clothing::applyEnchantment(const MWWorld::ConstPtr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); ESM::Clothing newItem = *ref->mBase; newItem.mId=""; diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index 13ec2e593..42d1a7ea4 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -61,7 +61,7 @@ namespace MWClass virtual std::string getEnchantment (const MWWorld::ConstPtr& ptr) const; ///< @return the enchantment ID if the object is enchanted, otherwise an empty string - virtual std::string applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; + virtual std::string applyEnchantment(const MWWorld::ConstPtr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; ///< Creates a new record using \a ptr as template, with the given name and the given enchantment applied to it. virtual std::pair canBeEquipped(const MWWorld::ConstPtr &ptr, const MWWorld::Ptr &npc) const; diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index 1b40787c8..085954c81 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -350,10 +350,9 @@ namespace MWClass return ref->mBase->mEnchant; } - std::string Weapon::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const + std::string Weapon::applyEnchantment(const MWWorld::ConstPtr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); ESM::Weapon newItem = *ref->mBase; newItem.mId=""; diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index aa87afc7a..9acda286b 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -68,7 +68,7 @@ namespace MWClass virtual std::string getEnchantment (const MWWorld::ConstPtr& ptr) const; ///< @return the enchantment ID if the object is enchanted, otherwise an empty string - virtual std::string applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; + virtual std::string applyEnchantment(const MWWorld::ConstPtr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; ///< Creates a new record using \a ptr as template, with the given name and the given enchantment applied to it. virtual std::pair canBeEquipped(const MWWorld::ConstPtr &ptr, const MWWorld::Ptr &npc) const; diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index b4861c85f..5426e8545 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -296,7 +296,7 @@ namespace MWWorld return ""; } - std::string Class::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const + std::string Class::applyEnchantment(const MWWorld::ConstPtr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const { throw std::runtime_error ("class can't be enchanted"); } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 3cf4326c8..5aa876228 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -268,7 +268,7 @@ namespace MWWorld virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; - virtual std::string applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; + virtual std::string applyEnchantment(const MWWorld::ConstPtr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; ///< Creates a new record using \a ptr as template, with the given name and the given enchantment applied to it. virtual std::pair canBeEquipped(const MWWorld::ConstPtr &ptr, const MWWorld::Ptr &npc) const; @@ -281,7 +281,7 @@ namespace MWWorld virtual bool isKey (const MWWorld::ConstPtr& ptr) const { return false; } - virtual bool isGold(const MWWorld::ConstPtr& ptr) const { return false; }; + virtual bool isGold(const MWWorld::ConstPtr& ptr) const { return false; } /// Get a blood texture suitable for \a ptr (see Blood Texture 0-2 in Morrowind.ini) virtual int getBloodTexture (const MWWorld::ConstPtr& ptr) const; From 09bdb0ad4bde954045119543f610ec32d6a0d2e0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 16:44:35 +0100 Subject: [PATCH 2877/3725] Accept a ConstPtr in getServices --- apps/openmw/mwclass/creature.cpp | 4 ++-- apps/openmw/mwclass/creature.hpp | 2 +- apps/openmw/mwclass/npc.cpp | 4 ++-- apps/openmw/mwclass/npc.hpp | 2 +- apps/openmw/mwworld/class.cpp | 2 +- apps/openmw/mwworld/class.hpp | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 26bb45ea3..753f3cbba 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -545,9 +545,9 @@ namespace MWClass return static_cast(stats.getAttribute(0).getModified() * 5); } - int Creature::getServices(const MWWorld::Ptr &actor) const + int Creature::getServices(const MWWorld::ConstPtr &actor) const { - MWWorld::LiveCellRef* ref = actor.get(); + const MWWorld::LiveCellRef* ref = actor.get(); if (ref->mBase->mHasAI) return ref->mBase->mAiData.mServices; else diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index 2299e655c..0ee6e6512 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -86,7 +86,7 @@ namespace MWClass virtual bool isEssential (const MWWorld::ConstPtr& ptr) const; ///< Is \a ptr essential? (i.e. may losing \a ptr make the game unwinnable) - virtual int getServices (const MWWorld::Ptr& actor) const; + virtual int getServices (const MWWorld::ConstPtr& actor) const; virtual bool isPersistent (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index d05b0235e..2ec436a99 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -1046,9 +1046,9 @@ namespace MWClass } - int Npc::getServices(const MWWorld::Ptr &actor) const + int Npc::getServices(const MWWorld::ConstPtr &actor) const { - MWWorld::LiveCellRef* ref = actor.get(); + const MWWorld::LiveCellRef* ref = actor.get(); if (ref->mBase->mHasAI) return ref->mBase->mAiData.mServices; else diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index 8dd78f484..90019e45b 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -117,7 +117,7 @@ namespace MWClass virtual bool isEssential (const MWWorld::ConstPtr& ptr) const; ///< Is \a ptr essential? (i.e. may losing \a ptr make the game unwinnable) - virtual int getServices (const MWWorld::Ptr& actor) const; + virtual int getServices (const MWWorld::ConstPtr& actor) const; virtual bool isPersistent (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 5426e8545..43bfafb6c 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -60,7 +60,7 @@ namespace MWWorld return false; } - int Class::getServices(const Ptr &actor) const + int Class::getServices(const ConstPtr &actor) const { throw std::runtime_error ("class does not have services"); } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 5aa876228..a7aacf638 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -264,7 +264,7 @@ namespace MWWorld virtual bool canSell (const MWWorld::ConstPtr& item, int npcServices) const; ///< Determine whether or not \a item can be sold to an npc with the given \a npcServices - virtual int getServices (const MWWorld::Ptr& actor) const; + virtual int getServices (const MWWorld::ConstPtr& actor) const; virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; From 303521002d2d4788912415d6bc3158b15c98a214 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 16:46:02 +0100 Subject: [PATCH 2878/3725] Accept a ConstPtr in adjustScale --- apps/openmw/mwclass/creature.cpp | 4 ++-- apps/openmw/mwclass/creature.hpp | 2 +- apps/openmw/mwclass/npc.cpp | 5 ++--- apps/openmw/mwclass/npc.hpp | 2 +- apps/openmw/mwworld/class.cpp | 2 +- apps/openmw/mwworld/class.hpp | 2 +- 6 files changed, 8 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 753f3cbba..43e45067a 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -774,9 +774,9 @@ namespace MWClass return ref->mBase->mAiData.mFight; } - void Creature::adjustScale(const MWWorld::Ptr &ptr, osg::Vec3f &scale, bool /* rendering */) const + void Creature::adjustScale(const MWWorld::ConstPtr &ptr, osg::Vec3f &scale, bool /* rendering */) const { - MWWorld::LiveCellRef *ref = ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); scale *= ref->mBase->mScale; } } diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index 0ee6e6512..8f55b9f3d 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -130,7 +130,7 @@ namespace MWClass virtual int getBaseFightRating(const MWWorld::ConstPtr &ptr) const; - virtual void adjustScale(const MWWorld::Ptr& ptr, osg::Vec3f& scale, bool rendering) const; + virtual void adjustScale(const MWWorld::ConstPtr& ptr, osg::Vec3f& scale, bool rendering) const; /// @param rendering Indicates if the scale to adjust is for the rendering mesh, or for the collision mesh }; } diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 2ec436a99..2f328b7de 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -1019,14 +1019,13 @@ namespace MWClass + shield; } - void Npc::adjustScale(const MWWorld::Ptr &ptr, osg::Vec3f&scale, bool rendering) const + void Npc::adjustScale(const MWWorld::ConstPtr &ptr, osg::Vec3f&scale, bool rendering) const { if (!rendering) return; // collision meshes are not scaled based on race height // having the same collision extents for all races makes the environments easier to test - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get().find(ref->mBase->mRace); diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index 90019e45b..50adb19e0 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -108,7 +108,7 @@ namespace MWClass /// \param actor Actor that is resposible for the ID being applied to \a ptr. /// \return Any effect? - virtual void adjustScale (const MWWorld::Ptr &ptr, osg::Vec3f &scale, bool rendering) const; + virtual void adjustScale (const MWWorld::ConstPtr &ptr, osg::Vec3f &scale, bool rendering) const; /// @param rendering Indicates if the scale to adjust is for the rendering mesh, or for the collision mesh virtual void skillUsageSucceeded (const MWWorld::Ptr& ptr, int skill, int usageType, float extraFactor=1.f) const; diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 43bfafb6c..fab74094a 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -287,7 +287,7 @@ namespace MWWorld return ""; } - void Class::adjustScale(const MWWorld::Ptr& ptr, osg::Vec3f& scale, bool rendering) const + void Class::adjustScale(const MWWorld::ConstPtr& ptr, osg::Vec3f& scale, bool rendering) const { } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index a7aacf638..207fc8a20 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -258,7 +258,7 @@ namespace MWWorld virtual int getEnchantmentPoints (const MWWorld::Ptr& ptr) const; ///< @return the number of enchantment points available for possible enchanting - virtual void adjustScale(const MWWorld::Ptr& ptr, osg::Vec3f& scale, bool rendering) const; + virtual void adjustScale(const MWWorld::ConstPtr& ptr, osg::Vec3f& scale, bool rendering) const; /// @param rendering Indicates if the scale to adjust is for the rendering mesh, or for the collision mesh virtual bool canSell (const MWWorld::ConstPtr& item, int npcServices) const; From c43f80633a87f9bb45476e7942f4dc185be4abf1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 16:48:19 +0100 Subject: [PATCH 2879/3725] Accept a ConstPtr in getEnchantmentPoints --- apps/openmw/mwclass/armor.cpp | 5 ++--- apps/openmw/mwclass/armor.hpp | 2 +- apps/openmw/mwclass/book.cpp | 5 ++--- apps/openmw/mwclass/book.hpp | 2 +- apps/openmw/mwclass/clothing.cpp | 5 ++--- apps/openmw/mwclass/clothing.hpp | 2 +- apps/openmw/mwclass/weapon.cpp | 5 ++--- apps/openmw/mwclass/weapon.hpp | 2 +- apps/openmw/mwworld/class.cpp | 2 +- apps/openmw/mwworld/class.hpp | 2 +- 10 files changed, 14 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index f11bbcda8..5a5265e17 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -371,10 +371,9 @@ namespace MWClass return MWWorld::Ptr(cell.insert(ref), &cell); } - int Armor::getEnchantmentPoints (const MWWorld::Ptr& ptr) const + int Armor::getEnchantmentPoints (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mData.mEnchant; } diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index 598b77929..5e7f1c2ed 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -82,7 +82,7 @@ namespace MWClass virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; - virtual int getEnchantmentPoints (const MWWorld::Ptr& ptr) const; + virtual int getEnchantmentPoints (const MWWorld::ConstPtr& ptr) const; virtual bool canSell (const MWWorld::ConstPtr& item, int npcServices) const; diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index faea0d6f2..56b573ee3 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -179,10 +179,9 @@ namespace MWClass return MWWorld::Ptr(cell.insert(ref), &cell); } - int Book::getEnchantmentPoints (const MWWorld::Ptr& ptr) const + int Book::getEnchantmentPoints (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mData.mEnchant; } diff --git a/apps/openmw/mwclass/book.hpp b/apps/openmw/mwclass/book.hpp index 6b8be41bb..7d2f578cc 100644 --- a/apps/openmw/mwclass/book.hpp +++ b/apps/openmw/mwclass/book.hpp @@ -61,7 +61,7 @@ namespace MWClass virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; - virtual int getEnchantmentPoints (const MWWorld::Ptr& ptr) const; + virtual int getEnchantmentPoints (const MWWorld::ConstPtr& ptr) const; virtual float getWeight (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index 2e2b8af84..73a012cdb 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -264,10 +264,9 @@ namespace MWClass return MWWorld::Ptr(cell.insert(ref), &cell); } - int Clothing::getEnchantmentPoints (const MWWorld::Ptr& ptr) const + int Clothing::getEnchantmentPoints (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mData.mEnchant; } diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index 42d1a7ea4..bb9fd3492 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -74,7 +74,7 @@ namespace MWClass virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; - virtual int getEnchantmentPoints (const MWWorld::Ptr& ptr) const; + virtual int getEnchantmentPoints (const MWWorld::ConstPtr& ptr) const; virtual float getWeight (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index 085954c81..0018ff930 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -405,10 +405,9 @@ namespace MWClass return MWWorld::Ptr(cell.insert(ref), &cell); } - int Weapon::getEnchantmentPoints (const MWWorld::Ptr& ptr) const + int Weapon::getEnchantmentPoints (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mData.mEnchant; } diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index 9acda286b..9426a1435 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -85,7 +85,7 @@ namespace MWClass virtual float getWeight (const MWWorld::ConstPtr& ptr) const; - virtual int getEnchantmentPoints (const MWWorld::Ptr& ptr) const; + virtual int getEnchantmentPoints (const MWWorld::ConstPtr& ptr) const; }; } diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index fab74094a..6e699dd97 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -173,7 +173,7 @@ namespace MWWorld return 0; } - int Class::getEnchantmentPoints (const MWWorld::Ptr& ptr) const + int Class::getEnchantmentPoints (const MWWorld::ConstPtr& ptr) const { throw std::runtime_error ("class does not support enchanting"); } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 207fc8a20..943cfc451 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -255,7 +255,7 @@ namespace MWWorld ///< @return the enchantment ID if the object is enchanted, otherwise an empty string /// (default implementation: return empty string) - virtual int getEnchantmentPoints (const MWWorld::Ptr& ptr) const; + virtual int getEnchantmentPoints (const MWWorld::ConstPtr& ptr) const; ///< @return the number of enchantment points available for possible enchanting virtual void adjustScale(const MWWorld::ConstPtr& ptr, osg::Vec3f& scale, bool rendering) const; From 266fbbef4827a12ceb1760a31f53fd48854e79c4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 16:50:32 +0100 Subject: [PATCH 2880/3725] Accept a ConstPtr in canLock --- apps/openmw/mwclass/container.cpp | 2 +- apps/openmw/mwclass/container.hpp | 2 +- apps/openmw/mwclass/door.cpp | 2 +- apps/openmw/mwclass/door.hpp | 2 +- apps/openmw/mwworld/class.cpp | 2 +- apps/openmw/mwworld/class.hpp | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index 03c676b9e..39ce594ae 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -279,7 +279,7 @@ namespace MWClass ptr.getCellRef().setLockLevel(-abs(ptr.getCellRef().getLockLevel())); //Makes lockLevel negative } - bool Container::canLock(const MWWorld::Ptr &ptr) const + bool Container::canLock(const MWWorld::ConstPtr &ptr) const { return true; } diff --git a/apps/openmw/mwclass/container.hpp b/apps/openmw/mwclass/container.hpp index 9b6d5d2e0..53795b540 100644 --- a/apps/openmw/mwclass/container.hpp +++ b/apps/openmw/mwclass/container.hpp @@ -56,7 +56,7 @@ namespace MWClass virtual void unlock (const MWWorld::Ptr& ptr) const; ///< Unlock object - virtual bool canLock(const MWWorld::Ptr &ptr) const; + virtual bool canLock(const MWWorld::ConstPtr &ptr) const; virtual void readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state) const; diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index f279ae3a0..dfd974ef6 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -209,7 +209,7 @@ namespace MWClass ptr.getCellRef().setLockLevel(-abs(ptr.getCellRef().getLockLevel())); //Makes lockLevel negative } - bool Door::canLock(const MWWorld::Ptr &ptr) const + bool Door::canLock(const MWWorld::ConstPtr &ptr) const { return true; } diff --git a/apps/openmw/mwclass/door.hpp b/apps/openmw/mwclass/door.hpp index f789055ff..7db9852db 100644 --- a/apps/openmw/mwclass/door.hpp +++ b/apps/openmw/mwclass/door.hpp @@ -46,7 +46,7 @@ namespace MWClass virtual void unlock (const MWWorld::Ptr& ptr) const; ///< Unlock object - virtual bool canLock(const MWWorld::Ptr &ptr) const; + virtual bool canLock(const MWWorld::ConstPtr &ptr) const; virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; ///< Return name of the script attached to ptr diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 6e699dd97..e4bb72283 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -143,7 +143,7 @@ namespace MWWorld throw std::runtime_error ("class does not support unlocking"); } - bool Class::canLock(const Ptr &ptr) const + bool Class::canLock(const ConstPtr &ptr) const { return false; } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 943cfc451..0129a3dcf 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -161,7 +161,7 @@ namespace MWWorld virtual void unlock (const Ptr& ptr) const; ///< Unlock object (default implementation: throw an exception) - virtual bool canLock (const Ptr& ptr) const; + virtual bool canLock (const ConstPtr& ptr) const; virtual void setRemainingUsageTime (const Ptr& ptr, float duration) const; ///< Sets the remaining duration of the object, such as an equippable light From 04f7a8f8eb239f1b080103ee28b50f4d5eabce6e Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 16:58:08 +0100 Subject: [PATCH 2881/3725] Remove redundant getId function --- apps/openmw/mwclass/activator.cpp | 4 ---- apps/openmw/mwclass/activator.hpp | 3 --- apps/openmw/mwclass/apparatus.cpp | 4 ---- apps/openmw/mwclass/apparatus.hpp | 3 --- apps/openmw/mwclass/armor.cpp | 4 ---- apps/openmw/mwclass/armor.hpp | 3 --- apps/openmw/mwclass/book.cpp | 4 ---- apps/openmw/mwclass/book.hpp | 3 --- apps/openmw/mwclass/clothing.cpp | 4 ---- apps/openmw/mwclass/clothing.hpp | 3 --- apps/openmw/mwclass/container.cpp | 5 ----- apps/openmw/mwclass/container.hpp | 3 --- apps/openmw/mwclass/creature.cpp | 16 ++++------------ apps/openmw/mwclass/creature.hpp | 3 --- apps/openmw/mwclass/creaturelevlist.cpp | 5 ----- apps/openmw/mwclass/creaturelevlist.hpp | 3 --- apps/openmw/mwclass/door.cpp | 5 ----- apps/openmw/mwclass/door.hpp | 3 --- apps/openmw/mwclass/ingredient.cpp | 7 ------- apps/openmw/mwclass/ingredient.hpp | 3 --- apps/openmw/mwclass/itemlevlist.cpp | 4 ---- apps/openmw/mwclass/itemlevlist.hpp | 3 --- apps/openmw/mwclass/light.cpp | 4 ---- apps/openmw/mwclass/light.hpp | 5 +---- apps/openmw/mwclass/lockpick.cpp | 4 ---- apps/openmw/mwclass/lockpick.hpp | 3 --- apps/openmw/mwclass/misc.cpp | 4 ---- apps/openmw/mwclass/misc.hpp | 3 --- apps/openmw/mwclass/npc.cpp | 14 +++----------- apps/openmw/mwclass/npc.hpp | 3 --- apps/openmw/mwclass/potion.cpp | 4 ---- apps/openmw/mwclass/potion.hpp | 3 --- apps/openmw/mwclass/probe.cpp | 4 ---- apps/openmw/mwclass/probe.hpp | 3 --- apps/openmw/mwclass/repair.cpp | 4 ---- apps/openmw/mwclass/repair.hpp | 3 --- apps/openmw/mwclass/static.cpp | 4 ---- apps/openmw/mwclass/static.hpp | 3 --- apps/openmw/mwclass/weapon.cpp | 6 ------ apps/openmw/mwclass/weapon.hpp | 3 --- apps/openmw/mwdialogue/filter.cpp | 4 ++-- apps/openmw/mwgui/spellmodel.cpp | 2 +- apps/openmw/mwmechanics/alchemy.cpp | 4 ++-- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 4 ++-- apps/openmw/mwscript/interpretercontext.cpp | 2 +- apps/openmw/mwworld/actioneat.cpp | 2 +- apps/openmw/mwworld/class.cpp | 5 ----- apps/openmw/mwworld/class.hpp | 6 ------ apps/openmw/mwworld/inventorystore.cpp | 2 +- apps/openmw/mwworld/scene.cpp | 2 +- 50 files changed, 19 insertions(+), 186 deletions(-) diff --git a/apps/openmw/mwclass/activator.cpp b/apps/openmw/mwclass/activator.cpp index 799ab5311..e6dc0b1fe 100644 --- a/apps/openmw/mwclass/activator.cpp +++ b/apps/openmw/mwclass/activator.cpp @@ -26,10 +26,6 @@ namespace MWClass { - std::string Activator::getId (const MWWorld::Ptr& ptr) const - { - return ptr.get()->mBase->mId; - } void Activator::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { diff --git a/apps/openmw/mwclass/activator.hpp b/apps/openmw/mwclass/activator.hpp index 7214b86e0..d1e905881 100644 --- a/apps/openmw/mwclass/activator.hpp +++ b/apps/openmw/mwclass/activator.hpp @@ -12,9 +12,6 @@ namespace MWClass public: - /// Return ID of \a ptr - virtual std::string getId (const MWWorld::Ptr& ptr) const; - virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering diff --git a/apps/openmw/mwclass/apparatus.cpp b/apps/openmw/mwclass/apparatus.cpp index 36870997b..8dbd638c0 100644 --- a/apps/openmw/mwclass/apparatus.cpp +++ b/apps/openmw/mwclass/apparatus.cpp @@ -20,10 +20,6 @@ namespace MWClass { - std::string Apparatus::getId (const MWWorld::Ptr& ptr) const - { - return ptr.get()->mBase->mId; - } void Apparatus::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { diff --git a/apps/openmw/mwclass/apparatus.hpp b/apps/openmw/mwclass/apparatus.hpp index d8176d5df..676362975 100644 --- a/apps/openmw/mwclass/apparatus.hpp +++ b/apps/openmw/mwclass/apparatus.hpp @@ -12,9 +12,6 @@ namespace MWClass public: - /// Return ID of \a ptr - virtual std::string getId (const MWWorld::Ptr& ptr) const; - virtual float getWeight (const MWWorld::ConstPtr& ptr) const; virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index 5a5265e17..07e4e2810 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -26,10 +26,6 @@ namespace MWClass { - std::string Armor::getId (const MWWorld::Ptr& ptr) const - { - return ptr.get()->mBase->mId; - } void Armor::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index 5e7f1c2ed..0fdfa566d 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -11,9 +11,6 @@ namespace MWClass public: - /// Return ID of \a ptr - virtual std::string getId (const MWWorld::Ptr& ptr) const; - virtual float getWeight (const MWWorld::ConstPtr& ptr) const; virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index 56b573ee3..8c37dadd7 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -23,10 +23,6 @@ namespace MWClass { - std::string Book::getId (const MWWorld::Ptr& ptr) const - { - return ptr.get()->mBase->mId; - } void Book::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { diff --git a/apps/openmw/mwclass/book.hpp b/apps/openmw/mwclass/book.hpp index 7d2f578cc..a419c89fe 100644 --- a/apps/openmw/mwclass/book.hpp +++ b/apps/openmw/mwclass/book.hpp @@ -11,9 +11,6 @@ namespace MWClass public: - /// Return ID of \a ptr - virtual std::string getId (const MWWorld::Ptr& ptr) const; - virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index 73a012cdb..6b64e84b0 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -22,10 +22,6 @@ namespace MWClass { - std::string Clothing::getId (const MWWorld::Ptr& ptr) const - { - return ptr.get()->mBase->mId; - } void Clothing::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index bb9fd3492..cbdc6295d 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -11,9 +11,6 @@ namespace MWClass public: - /// Return ID of \a ptr - virtual std::string getId (const MWWorld::Ptr& ptr) const; - virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index 39ce594ae..bd5f18efd 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -47,11 +47,6 @@ namespace MWClass return new ContainerCustomData (*this); } - std::string Container::getId (const MWWorld::Ptr& ptr) const - { - return ptr.get()->mBase->mId; - } - void Container::ensureCustomData (const MWWorld::Ptr& ptr) const { if (!ptr.getRefData().getCustomData()) diff --git a/apps/openmw/mwclass/container.hpp b/apps/openmw/mwclass/container.hpp index 53795b540..d8aaab327 100644 --- a/apps/openmw/mwclass/container.hpp +++ b/apps/openmw/mwclass/container.hpp @@ -14,9 +14,6 @@ namespace MWClass public: - /// Return ID of \a ptr - virtual std::string getId (const MWWorld::Ptr& ptr) const; - virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 43e45067a..bdd06b9f4 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -154,21 +154,13 @@ namespace MWClass // store ptr.getRefData().setCustomData(data.release()); - getContainerStore(ptr).fill(ref->mBase->mInventory, getId(ptr)); + getContainerStore(ptr).fill(ref->mBase->mInventory, ptr.getCellRef().getRefId()); if (hasInventory) getInventoryStore(ptr).autoEquip(ptr); } } - std::string Creature::getId (const MWWorld::Ptr& ptr) const - { - MWWorld::LiveCellRef *ref = - ptr.get(); - - return ref->mBase->mId; - } - void Creature::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { MWRender::Objects& objects = renderingInterface.getObjects(); @@ -335,7 +327,7 @@ namespace MWClass } if(!object.isEmpty()) - getCreatureStats(ptr).setLastHitAttemptObject(object.getClass().getId(object)); + getCreatureStats(ptr).setLastHitAttemptObject(object.getCellRef().getRefId()); if(setOnPcHitMe && !attacker.isEmpty() && attacker == MWMechanics::getPlayer()) { @@ -353,7 +345,7 @@ namespace MWClass } if(!object.isEmpty()) - getCreatureStats(ptr).setLastHitObject(object.getClass().getId(object)); + getCreatureStats(ptr).setLastHitObject(object.getCellRef().getRefId()); if (damage > 0.0f && !object.isEmpty()) MWMechanics::resistNormalWeapon(ptr, attacker, object, damage); @@ -571,7 +563,7 @@ namespace MWClass MWWorld::LiveCellRef* ref = ptr.get(); - const std::string& ourId = (ref->mBase->mOriginal.empty()) ? getId(ptr) : ref->mBase->mOriginal; + const std::string& ourId = (ref->mBase->mOriginal.empty()) ? ptr.getCellRef().getRefId() : ref->mBase->mOriginal; MWWorld::Store::iterator sound = store.begin(); while(sound != store.end()) diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index 8f55b9f3d..1647da01e 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -40,9 +40,6 @@ namespace MWClass public: - virtual std::string getId (const MWWorld::Ptr& ptr) const; - ///< Return ID of \a ptr - virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering diff --git a/apps/openmw/mwclass/creaturelevlist.cpp b/apps/openmw/mwclass/creaturelevlist.cpp index 9bd5f9537..1f9e9b0fc 100644 --- a/apps/openmw/mwclass/creaturelevlist.cpp +++ b/apps/openmw/mwclass/creaturelevlist.cpp @@ -29,11 +29,6 @@ namespace MWClass return new CreatureLevListCustomData (*this); } - std::string CreatureLevList::getId (const MWWorld::Ptr& ptr) const - { - return ptr.get()->mBase->mId; - } - std::string CreatureLevList::getName (const MWWorld::ConstPtr& ptr) const { return ""; diff --git a/apps/openmw/mwclass/creaturelevlist.hpp b/apps/openmw/mwclass/creaturelevlist.hpp index 4ada3cd86..67a7858d8 100644 --- a/apps/openmw/mwclass/creaturelevlist.hpp +++ b/apps/openmw/mwclass/creaturelevlist.hpp @@ -11,9 +11,6 @@ namespace MWClass public: - /// Return ID of \a ptr - virtual std::string getId (const MWWorld::Ptr& ptr) const; - virtual std::string getName (const MWWorld::ConstPtr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index dfd974ef6..e007d3448 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -48,11 +48,6 @@ namespace MWClass return new DoorCustomData (*this); } - std::string Door::getId (const MWWorld::Ptr& ptr) const - { - return ptr.get()->mBase->mId; - } - void Door::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { if (!model.empty()) { diff --git a/apps/openmw/mwclass/door.hpp b/apps/openmw/mwclass/door.hpp index 7db9852db..ff94cd613 100644 --- a/apps/openmw/mwclass/door.hpp +++ b/apps/openmw/mwclass/door.hpp @@ -15,9 +15,6 @@ namespace MWClass public: - /// Return ID of \a ptr - virtual std::string getId (const MWWorld::Ptr& ptr) const; - virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering diff --git a/apps/openmw/mwclass/ingredient.cpp b/apps/openmw/mwclass/ingredient.cpp index bfe482e96..5fbefcbe3 100644 --- a/apps/openmw/mwclass/ingredient.cpp +++ b/apps/openmw/mwclass/ingredient.cpp @@ -23,13 +23,6 @@ namespace MWClass { - std::string Ingredient::getId (const MWWorld::Ptr& ptr) const - { - MWWorld::LiveCellRef *ref = - ptr.get(); - - return ref->mBase->mId; - } void Ingredient::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { diff --git a/apps/openmw/mwclass/ingredient.hpp b/apps/openmw/mwclass/ingredient.hpp index dd156d314..42920f5fc 100644 --- a/apps/openmw/mwclass/ingredient.hpp +++ b/apps/openmw/mwclass/ingredient.hpp @@ -11,9 +11,6 @@ namespace MWClass public: - virtual std::string getId (const MWWorld::Ptr& ptr) const; - ///< Return ID of \a ptr - virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering diff --git a/apps/openmw/mwclass/itemlevlist.cpp b/apps/openmw/mwclass/itemlevlist.cpp index 7690169c6..290ac4c26 100644 --- a/apps/openmw/mwclass/itemlevlist.cpp +++ b/apps/openmw/mwclass/itemlevlist.cpp @@ -4,10 +4,6 @@ namespace MWClass { - std::string ItemLevList::getId (const MWWorld::Ptr& ptr) const - { - return ptr.get()->mBase->mId; - } std::string ItemLevList::getName (const MWWorld::ConstPtr& ptr) const { diff --git a/apps/openmw/mwclass/itemlevlist.hpp b/apps/openmw/mwclass/itemlevlist.hpp index 8a95b9adb..a8b313185 100644 --- a/apps/openmw/mwclass/itemlevlist.hpp +++ b/apps/openmw/mwclass/itemlevlist.hpp @@ -9,9 +9,6 @@ namespace MWClass { public: - /// Return ID of \a ptr - virtual std::string getId (const MWWorld::Ptr& ptr) const; - virtual std::string getName (const MWWorld::ConstPtr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 86f1b1d61..6ff846152 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -27,10 +27,6 @@ namespace MWClass { - std::string Light::getId (const MWWorld::Ptr& ptr) const - { - return ptr.get()->mBase->mId; - } void Light::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { diff --git a/apps/openmw/mwclass/light.hpp b/apps/openmw/mwclass/light.hpp index 7fbaa833a..c57a3afb9 100644 --- a/apps/openmw/mwclass/light.hpp +++ b/apps/openmw/mwclass/light.hpp @@ -11,10 +11,7 @@ namespace MWClass public: - /// Return ID of \a ptr - virtual std::string getId (const MWWorld::Ptr& ptr) const; - - virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; + virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index abf9f9c14..66edd7d81 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -21,10 +21,6 @@ namespace MWClass { - std::string Lockpick::getId (const MWWorld::Ptr& ptr) const - { - return ptr.get()->mBase->mId; - } void Lockpick::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { diff --git a/apps/openmw/mwclass/lockpick.hpp b/apps/openmw/mwclass/lockpick.hpp index 7225cab11..81d7c0c51 100644 --- a/apps/openmw/mwclass/lockpick.hpp +++ b/apps/openmw/mwclass/lockpick.hpp @@ -11,9 +11,6 @@ namespace MWClass public: - /// Return ID of \a ptr - virtual std::string getId (const MWWorld::Ptr& ptr) const; - virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index 1c8e75f1f..00505067d 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -34,10 +34,6 @@ namespace MWClass || Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_025") || Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_100"); } - std::string Miscellaneous::getId (const MWWorld::Ptr& ptr) const - { - return ptr.get()->mBase->mId; - } void Miscellaneous::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { diff --git a/apps/openmw/mwclass/misc.hpp b/apps/openmw/mwclass/misc.hpp index d9979fa87..d2681ac72 100644 --- a/apps/openmw/mwclass/misc.hpp +++ b/apps/openmw/mwclass/misc.hpp @@ -11,9 +11,6 @@ namespace MWClass public: - /// Return ID of \a ptr - virtual std::string getId (const MWWorld::Ptr& ptr) const; - virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 2f328b7de..e3e3fd3c2 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -395,7 +395,7 @@ namespace MWClass // inventory // setting ownership is used to make the NPC auto-equip his initial equipment only, and not bartered items - data->mInventoryStore.fill(ref->mBase->mInventory, getId(ptr)); + data->mInventoryStore.fill(ref->mBase->mInventory, ptr.getCellRef().getRefId()); data->mNpcStats.setGoldPool(gold); @@ -406,14 +406,6 @@ namespace MWClass } } - std::string Npc::getId (const MWWorld::Ptr& ptr) const - { - MWWorld::LiveCellRef *ref = - ptr.get(); - - return ref->mBase->mId; - } - void Npc::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { renderingInterface.getObjects().insertNPC(ptr); @@ -603,7 +595,7 @@ namespace MWClass } if(!object.isEmpty()) - getCreatureStats(ptr).setLastHitAttemptObject(object.getClass().getId(object)); + getCreatureStats(ptr).setLastHitAttemptObject(object.getCellRef().getRefId()); if(setOnPcHitMe && !attacker.isEmpty() && attacker == MWMechanics::getPlayer()) { @@ -621,7 +613,7 @@ namespace MWClass } if(!object.isEmpty()) - getCreatureStats(ptr).setLastHitObject(object.getClass().getId(object)); + getCreatureStats(ptr).setLastHitObject(object.getCellRef().getRefId()); if (damage > 0.0f && !object.isEmpty()) diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index 50adb19e0..88c4dfac9 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -44,9 +44,6 @@ namespace MWClass public: - virtual std::string getId (const MWWorld::Ptr& ptr) const; - ///< Return ID of \a ptr - virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering diff --git a/apps/openmw/mwclass/potion.cpp b/apps/openmw/mwclass/potion.cpp index f0875d138..6ef035679 100644 --- a/apps/openmw/mwclass/potion.cpp +++ b/apps/openmw/mwclass/potion.cpp @@ -24,10 +24,6 @@ namespace MWClass { - std::string Potion::getId (const MWWorld::Ptr& ptr) const - { - return ptr.get()->mBase->mId; - } void Potion::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { diff --git a/apps/openmw/mwclass/potion.hpp b/apps/openmw/mwclass/potion.hpp index 92f0ebcd9..391a5093d 100644 --- a/apps/openmw/mwclass/potion.hpp +++ b/apps/openmw/mwclass/potion.hpp @@ -11,9 +11,6 @@ namespace MWClass public: - /// Return ID of \a ptr - virtual std::string getId (const MWWorld::Ptr& ptr) const; - virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index 010a73a3c..fdbf69811 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -21,10 +21,6 @@ namespace MWClass { - std::string Probe::getId (const MWWorld::Ptr& ptr) const - { - return ptr.get()->mBase->mId; - } void Probe::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { diff --git a/apps/openmw/mwclass/probe.hpp b/apps/openmw/mwclass/probe.hpp index 2dc63b155..62eeb3016 100644 --- a/apps/openmw/mwclass/probe.hpp +++ b/apps/openmw/mwclass/probe.hpp @@ -11,9 +11,6 @@ namespace MWClass public: - /// Return ID of \a ptr - virtual std::string getId (const MWWorld::Ptr& ptr) const; - virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering diff --git a/apps/openmw/mwclass/repair.cpp b/apps/openmw/mwclass/repair.cpp index 6d681a87c..c6e90aecd 100644 --- a/apps/openmw/mwclass/repair.cpp +++ b/apps/openmw/mwclass/repair.cpp @@ -20,10 +20,6 @@ namespace MWClass { - std::string Repair::getId (const MWWorld::Ptr& ptr) const - { - return ptr.get()->mBase->mId; - } void Repair::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { diff --git a/apps/openmw/mwclass/repair.hpp b/apps/openmw/mwclass/repair.hpp index 2dcf03ce2..396727858 100644 --- a/apps/openmw/mwclass/repair.hpp +++ b/apps/openmw/mwclass/repair.hpp @@ -11,9 +11,6 @@ namespace MWClass public: - /// Return ID of \a ptr - virtual std::string getId (const MWWorld::Ptr& ptr) const; - virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering diff --git a/apps/openmw/mwclass/static.cpp b/apps/openmw/mwclass/static.cpp index a6863f400..65e69ea90 100644 --- a/apps/openmw/mwclass/static.cpp +++ b/apps/openmw/mwclass/static.cpp @@ -11,10 +11,6 @@ namespace MWClass { - std::string Static::getId (const MWWorld::Ptr& ptr) const - { - return ptr.get()->mBase->mId; - } void Static::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { diff --git a/apps/openmw/mwclass/static.hpp b/apps/openmw/mwclass/static.hpp index f2a5cef92..076c39cf1 100644 --- a/apps/openmw/mwclass/static.hpp +++ b/apps/openmw/mwclass/static.hpp @@ -11,9 +11,6 @@ namespace MWClass public: - /// Return ID of \a ptr - virtual std::string getId (const MWWorld::Ptr& ptr) const; - virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index 0018ff930..e9acf9ba2 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -22,12 +22,6 @@ namespace MWClass { - std::string Weapon::getId (const MWWorld::Ptr& ptr) const - { - MWWorld::LiveCellRef *ref = ptr.get(); - - return ref->mBase->mId; - } void Weapon::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index 9426a1435..f24409d82 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -12,9 +12,6 @@ namespace MWClass public: - virtual std::string getId (const MWWorld::Ptr& ptr) const; - ///< Return ID of \a ptr - virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index 084941b46..43d979ea2 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -28,7 +28,7 @@ bool MWDialogue::Filter::testActor (const ESM::DialInfo& info) const // actor id if (!info.mActor.empty()) { - if ( !Misc::StringUtils::ciEqual(info.mActor, mActor.getClass().getId (mActor))) + if ( !Misc::StringUtils::ciEqual(info.mActor, mActor.getCellRef().getRefId())) return false; } else if (isCreature) @@ -438,7 +438,7 @@ bool MWDialogue::Filter::getSelectStructBoolean (const SelectWrapper& select) co case SelectWrapper::Function_NotId: - return !Misc::StringUtils::ciEqual(mActor.getClass().getId (mActor), select.getName()); + return !Misc::StringUtils::ciEqual(mActor.getCellRef().getRefId(), select.getName()); case SelectWrapper::Function_NotFaction: diff --git a/apps/openmw/mwgui/spellmodel.cpp b/apps/openmw/mwgui/spellmodel.cpp index 0d3b64f78..c77533008 100644 --- a/apps/openmw/mwgui/spellmodel.cpp +++ b/apps/openmw/mwgui/spellmodel.cpp @@ -93,7 +93,7 @@ namespace MWGui Spell newSpell; newSpell.mItem = item; - newSpell.mId = item.getClass().getId(item); + newSpell.mId = item.getCellRef().getRefId(); newSpell.mName = item.getClass().getName(item); newSpell.mType = Spell::Type_EnchantedItem; newSpell.mSelected = invStore.getSelectedEnchantItem() == it; diff --git a/apps/openmw/mwmechanics/alchemy.cpp b/apps/openmw/mwmechanics/alchemy.cpp index 38d85a7cd..d39c88150 100644 --- a/apps/openmw/mwmechanics/alchemy.cpp +++ b/apps/openmw/mwmechanics/alchemy.cpp @@ -421,8 +421,8 @@ int MWMechanics::Alchemy::addIngredient (const MWWorld::Ptr& ingredient) return -1; for (TIngredientsIterator iter (mIngredients.begin()); iter!=mIngredients.end(); ++iter) - if (!iter->isEmpty() && Misc::StringUtils::ciEqual(ingredient.getClass().getId(ingredient), - iter->getClass().getId(*iter))) + if (!iter->isEmpty() && Misc::StringUtils::ciEqual(ingredient.getCellRef().getRefId(), + iter->getCellRef().getRefId())) return -1; mIngredients[slot] = ingredient; diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index ba958df10..21039cc65 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -983,7 +983,7 @@ namespace MWMechanics MWWorld::ContainerStore& store = player.getClass().getContainerStore(player); for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it) { - StolenItemsMap::iterator stolenIt = mStolenItems.find(Misc::StringUtils::lowerCase(it->getClass().getId(*it))); + StolenItemsMap::iterator stolenIt = mStolenItems.find(Misc::StringUtils::lowerCase(it->getCellRef().getRefId())); if (stolenIt == mStolenItems.end()) continue; OwnerMap& owners = stolenIt->second; @@ -1045,7 +1045,7 @@ namespace MWMechanics Misc::StringUtils::lowerCaseInPlace(owner.first); if (!Misc::StringUtils::ciEqual(item.getCellRef().getRefId(), MWWorld::ContainerStore::sGoldId)) - mStolenItems[Misc::StringUtils::lowerCase(item.getClass().getId(item))][owner] += count; + mStolenItems[Misc::StringUtils::lowerCase(item.getCellRef().getRefId())][owner] += count; commitCrime(ptr, victim, OT_Theft, item.getClass().getValue(item) * count); } diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index c70eb6cf8..7a6afe2e0 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -145,7 +145,7 @@ namespace MWScript // selected), store the ID of that reference store it so it can be inherited by // targeted scripts started from this one. if (targetId.empty() && !reference.isEmpty()) - mTargetId = reference.getClass().getId (reference); + mTargetId = reference.getCellRef().getRefId(); } int InterpreterContext::getLocalShort (int index) const diff --git a/apps/openmw/mwworld/actioneat.cpp b/apps/openmw/mwworld/actioneat.cpp index 82c7fb80e..84805c70e 100644 --- a/apps/openmw/mwworld/actioneat.cpp +++ b/apps/openmw/mwworld/actioneat.cpp @@ -19,7 +19,7 @@ namespace MWWorld getTarget().getContainerStore()->remove(getTarget(), 1, actor); // apply to actor - std::string id = getTarget().getClass().getId (getTarget()); + std::string id = getTarget().getCellRef().getRefId(); if (actor.getClass().apply (actor, id, actor) && actor == MWMechanics::getPlayer()) actor.getClass().skillUsageSucceeded (actor, ESM::Skill::Alchemy, 1); diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index e4bb72283..118bfe018 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -30,11 +30,6 @@ namespace MWWorld Class::~Class() {} - std::string Class::getId (const Ptr& ptr) const - { - throw std::runtime_error ("class does not support ID retrieval"); - } - void Class::insertObjectRendering (const Ptr& ptr, const std::string& mesh, MWRender::RenderingInterface& renderingInterface) const { diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 0129a3dcf..33d7e26c8 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -76,12 +76,6 @@ namespace MWWorld return mTypeName; } - virtual std::string getId (const Ptr& ptr) const; - ///< Return ID of \a ptr or throw an exception, if class does not support ID retrieval - /// (default implementation: throw an exception) - /// @note This function is currently redundant; the same ID can be retrieved by CellRef::getRefId. - /// Leaving it here for now in case we want to optimize later. - virtual void insertObjectRendering (const Ptr& ptr, const std::string& mesh, MWRender::RenderingInterface& renderingInterface) const; virtual void insertObject(const Ptr& ptr, const std::string& mesh, MWPhysics::PhysicsSystem& physics) const; ///< Add reference into a cell for rendering (default implementation: don't render anything). diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index bfc33507a..8041be1ea 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -700,7 +700,7 @@ void MWWorld::InventoryStore::purgeEffect(short effectId, const std::string &sou if (*iter==end()) continue; - if ((*iter)->getClass().getId(**iter) != sourceId) + if ((*iter)->getCellRef().getRefId() != sourceId) continue; std::string enchantmentId = (*iter)->getClass().getEnchantment (**iter); diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 00cb8a810..15b3c057b 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -32,7 +32,7 @@ namespace MWRender::RenderingManager& rendering) { std::string model = Misc::ResourceHelpers::correctActorModelPath(ptr.getClass().getModel(ptr), rendering.getResourceSystem()->getVFS()); - std::string id = ptr.getClass().getId(ptr); + std::string id = ptr.getCellRef().getRefId(); if (id == "prisonmarker" || id == "divinemarker" || id == "templemarker" || id == "northmarker") model = ""; // marker objects that have a hardcoded function in the game logic, should be hidden from the player ptr.getClass().insertObjectRendering(ptr, model, rendering); From edde5bd065b76eec01fe3d0a6478d6a1b18905a5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 17:00:31 +0100 Subject: [PATCH 2882/3725] Accept a ConstPtr in ContainerStore::stacks --- apps/openmw/mwworld/containerstore.cpp | 2 +- apps/openmw/mwworld/containerstore.hpp | 2 +- apps/openmw/mwworld/inventorystore.cpp | 2 +- apps/openmw/mwworld/inventorystore.hpp | 2 +- apps/openmw/mwworld/ptr.hpp | 30 ++++++++++++++++++++++++++ 5 files changed, 34 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 4b4c51547..6a0921013 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -176,7 +176,7 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::restack(const MWWorld:: return retval; } -bool MWWorld::ContainerStore::stacks(const Ptr& ptr1, const Ptr& ptr2) +bool MWWorld::ContainerStore::stacks(const ConstPtr& ptr1, const ConstPtr& ptr2) { const MWWorld::Class& cls1 = ptr1.getClass(); const MWWorld::Class& cls2 = ptr2.getClass(); diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index e103e16a1..b01a79366 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -149,7 +149,7 @@ namespace MWWorld public: - virtual bool stacks (const Ptr& ptr1, const Ptr& ptr2); + virtual bool stacks (const ConstPtr& ptr1, const ConstPtr& ptr2); ///< @return true if the two specified objects can stack with each other void fill (const ESM::InventoryList& items, const std::string& owner); diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 8041be1ea..0f9b2380c 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -450,7 +450,7 @@ void MWWorld::InventoryStore::flagAsModified() mRechargingItemsUpToDate = false; } -bool MWWorld::InventoryStore::stacks(const Ptr& ptr1, const Ptr& ptr2) +bool MWWorld::InventoryStore::stacks(const ConstPtr& ptr1, const ConstPtr& ptr2) { bool canStack = MWWorld::ContainerStore::stacks(ptr1, ptr2); if (!canStack) diff --git a/apps/openmw/mwworld/inventorystore.hpp b/apps/openmw/mwworld/inventorystore.hpp index 2c1be9b03..1e03746ff 100644 --- a/apps/openmw/mwworld/inventorystore.hpp +++ b/apps/openmw/mwworld/inventorystore.hpp @@ -167,7 +167,7 @@ namespace MWWorld ///< \attention This function is internal to the world model and should not be called from /// outside. - virtual bool stacks (const Ptr& ptr1, const Ptr& ptr2); + virtual bool stacks (const ConstPtr& ptr1, const ConstPtr& ptr2); ///< @return true if the two specified objects can stack with each other virtual int remove(const Ptr& item, int count, const Ptr& actor); diff --git a/apps/openmw/mwworld/ptr.hpp b/apps/openmw/mwworld/ptr.hpp index 9d370c4cb..d34f516a7 100644 --- a/apps/openmw/mwworld/ptr.hpp +++ b/apps/openmw/mwworld/ptr.hpp @@ -195,6 +195,36 @@ namespace MWWorld { return !(left>right); } + + inline bool operator== (const ConstPtr& left, const ConstPtr& right) + { + return left.mRef==right.mRef; + } + + inline bool operator!= (const ConstPtr& left, const ConstPtr& right) + { + return !(left==right); + } + + inline bool operator< (const ConstPtr& left, const ConstPtr& right) + { + return left.mRef= (const ConstPtr& left, const ConstPtr& right) + { + return !(left (const ConstPtr& left, const ConstPtr& right) + { + return rightright); + } } #endif From e1c6261fee10655b12a58da19037e3f6917c3df9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 17:03:49 +0100 Subject: [PATCH 2883/3725] Accept a ConstPtr in ContainerStore::getType --- apps/openmw/mwworld/containerstore.cpp | 2 +- apps/openmw/mwworld/containerstore.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 6a0921013..52b311abb 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -585,7 +585,7 @@ float MWWorld::ContainerStore::getWeight() const return mCachedWeight; } -int MWWorld::ContainerStore::getType (const Ptr& ptr) +int MWWorld::ContainerStore::getType (const ConstPtr& ptr) { if (ptr.isEmpty()) throw std::runtime_error ("can't put a non-existent object into a container"); diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index b01a79366..e1e59d70f 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -163,7 +163,7 @@ namespace MWWorld float getWeight() const; ///< Return total weight of the items contained in *this. - static int getType (const Ptr& ptr); + static int getType (const ConstPtr& ptr); ///< This function throws an exception, if ptr does not point to an object, that can be /// put into a container. From 3856f931dbade002ae58f08be4d5f7b453f45db2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 17:04:54 +0100 Subject: [PATCH 2884/3725] Accept a ConstPtr in ContainerStore::addNewStack --- apps/openmw/mwworld/containerstore.cpp | 2 +- apps/openmw/mwworld/containerstore.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 52b311abb..ab9fa4611 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -336,7 +336,7 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::addImp (const Ptr& ptr, return addNewStack(ptr, count); } -MWWorld::ContainerStoreIterator MWWorld::ContainerStore::addNewStack (const Ptr& ptr, int count) +MWWorld::ContainerStoreIterator MWWorld::ContainerStore::addNewStack (const ConstPtr& ptr, int count) { ContainerStoreIterator it = begin(); diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index e1e59d70f..b7ec4bb74 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -142,7 +142,7 @@ namespace MWWorld int count (const std::string& id); protected: - ContainerStoreIterator addNewStack (const Ptr& ptr, int count); + ContainerStoreIterator addNewStack (const ConstPtr& ptr, int count); ///< Add the item to this container (do not try to stack it onto existing items) virtual void flagAsModified(); From f35ab12979a09d67d774a27a52afe4bffff8d372 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 17:06:58 +0100 Subject: [PATCH 2885/3725] Accept a ConstPtr in InventoryStore::isEquipped --- apps/openmw/mwworld/inventorystore.cpp | 2 +- apps/openmw/mwworld/inventorystore.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 0f9b2380c..b82b798d1 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -742,7 +742,7 @@ void MWWorld::InventoryStore::clear() ContainerStore::clear(); } -bool MWWorld::InventoryStore::isEquipped(const MWWorld::Ptr &item) +bool MWWorld::InventoryStore::isEquipped(const MWWorld::ConstPtr &item) { for (int i=0; i < MWWorld::InventoryStore::Slots; ++i) { diff --git a/apps/openmw/mwworld/inventorystore.hpp b/apps/openmw/mwworld/inventorystore.hpp index 1e03746ff..28c44bcec 100644 --- a/apps/openmw/mwworld/inventorystore.hpp +++ b/apps/openmw/mwworld/inventorystore.hpp @@ -141,7 +141,7 @@ namespace MWWorld void equip (int slot, const ContainerStoreIterator& iterator, const Ptr& actor); ///< \warning \a iterator can not be an end()-iterator, use unequip function instead - bool isEquipped(const MWWorld::Ptr& item); + bool isEquipped(const MWWorld::ConstPtr& item); ///< Utility function, returns true if the given item is equipped in any slot void setSelectedEnchantItem(const ContainerStoreIterator& iterator); From 1212c072665ddb8e63f8270ef85d3bb7917361a5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 17:08:26 +0100 Subject: [PATCH 2886/3725] Pass a string by reference --- apps/openmw/mwworld/livecellref.cpp | 2 +- apps/openmw/mwworld/livecellref.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/livecellref.cpp b/apps/openmw/mwworld/livecellref.cpp index 0f83cd9c2..32830b5fb 100644 --- a/apps/openmw/mwworld/livecellref.cpp +++ b/apps/openmw/mwworld/livecellref.cpp @@ -11,7 +11,7 @@ #include "class.hpp" #include "esmstore.hpp" -MWWorld::LiveCellRefBase::LiveCellRefBase(std::string type, const ESM::CellRef &cref) +MWWorld::LiveCellRefBase::LiveCellRefBase(const std::string& type, const ESM::CellRef &cref) : mClass(&Class::get(type)), mRef(cref), mData(cref) { } diff --git a/apps/openmw/mwworld/livecellref.hpp b/apps/openmw/mwworld/livecellref.hpp index 3994d8a24..2631f513f 100644 --- a/apps/openmw/mwworld/livecellref.hpp +++ b/apps/openmw/mwworld/livecellref.hpp @@ -31,7 +31,7 @@ namespace MWWorld /** runtime-data */ RefData mData; - LiveCellRefBase(std::string type, const ESM::CellRef &cref=ESM::CellRef()); + LiveCellRefBase(const std::string& type, const ESM::CellRef &cref=ESM::CellRef()); /* Need this for the class to be recognized as polymorphic */ virtual ~LiveCellRefBase() { } From 8f9fc87565acfaa63893bd6dbddb1ccc62bd7998 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 17:09:11 +0100 Subject: [PATCH 2887/3725] Accept a ConstPtr in LocalScripts::setIgnore --- apps/openmw/mwworld/localscripts.cpp | 2 +- apps/openmw/mwworld/localscripts.hpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwworld/localscripts.cpp b/apps/openmw/mwworld/localscripts.cpp index 030a41891..46d0b3cc2 100644 --- a/apps/openmw/mwworld/localscripts.cpp +++ b/apps/openmw/mwworld/localscripts.cpp @@ -63,7 +63,7 @@ namespace MWWorld::LocalScripts::LocalScripts (const MWWorld::ESMStore& store) : mStore (store) {} -void MWWorld::LocalScripts::setIgnore (const Ptr& ptr) +void MWWorld::LocalScripts::setIgnore (const ConstPtr& ptr) { mIgnore = ptr; } diff --git a/apps/openmw/mwworld/localscripts.hpp b/apps/openmw/mwworld/localscripts.hpp index 5a156a2e9..6ef4633a1 100644 --- a/apps/openmw/mwworld/localscripts.hpp +++ b/apps/openmw/mwworld/localscripts.hpp @@ -17,14 +17,14 @@ namespace MWWorld { std::list > mScripts; std::list >::iterator mIter; - MWWorld::Ptr mIgnore; + MWWorld::ConstPtr mIgnore; const MWWorld::ESMStore& mStore; public: LocalScripts (const MWWorld::ESMStore& store); - void setIgnore (const Ptr& ptr); + void setIgnore (const ConstPtr& ptr); ///< Mark a single reference for ignoring during iteration over local scripts (will revoke /// previous ignores). From 553132cb51985f5580c19726edd7cc3cfd95da8d Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 17:13:54 +0100 Subject: [PATCH 2888/3725] Accept a ConstPtr in launchProjectile --- apps/openmw/mwbase/world.hpp | 2 +- apps/openmw/mwworld/projectilemanager.cpp | 2 +- apps/openmw/mwworld/projectilemanager.hpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 2 +- apps/openmw/mwworld/worldimp.hpp | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index ba48aa910..27b071f96 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -481,7 +481,7 @@ namespace MWBase virtual void launchMagicBolt (const std::string& model, const std::string& sound, const std::string& spellId, float speed, bool stack, const ESM::EffectList& effects, const MWWorld::Ptr& caster, const std::string& sourceName, const osg::Vec3f& fallbackDirection) = 0; - virtual void launchProjectile (MWWorld::Ptr actor, MWWorld::Ptr projectile, + virtual void launchProjectile (MWWorld::Ptr actor, MWWorld::ConstPtr projectile, const osg::Vec3f& worldPos, const osg::Quat& orient, MWWorld::Ptr bow, float speed, float attackStrength) = 0; virtual const std::vector& getContentFiles() const = 0; diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 5728fe1d7..439ac19ec 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -161,7 +161,7 @@ namespace MWWorld mMagicBolts.push_back(state); } - void ProjectileManager::launchProjectile(Ptr actor, Ptr projectile, const osg::Vec3f &pos, const osg::Quat &orient, Ptr bow, float speed, float attackStrength) + void ProjectileManager::launchProjectile(Ptr actor, ConstPtr projectile, const osg::Vec3f &pos, const osg::Quat &orient, Ptr bow, float speed, float attackStrength) { ProjectileState state; state.mActorId = actor.getClass().getCreatureStats(actor).getActorId(); diff --git a/apps/openmw/mwworld/projectilemanager.hpp b/apps/openmw/mwworld/projectilemanager.hpp index f58e266b3..74d4c1dc5 100644 --- a/apps/openmw/mwworld/projectilemanager.hpp +++ b/apps/openmw/mwworld/projectilemanager.hpp @@ -53,7 +53,7 @@ namespace MWWorld float speed, bool stack, const ESM::EffectList& effects, const MWWorld::Ptr& caster, const std::string& sourceName, const osg::Vec3f& fallbackDirection); - void launchProjectile (MWWorld::Ptr actor, MWWorld::Ptr projectile, + void launchProjectile (MWWorld::Ptr actor, MWWorld::ConstPtr projectile, const osg::Vec3f& pos, const osg::Quat& orient, MWWorld::Ptr bow, float speed, float attackStrength); void update(float dt); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 56fe2fc3d..3f13f2faf 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2712,7 +2712,7 @@ namespace MWWorld } } - void World::launchProjectile (MWWorld::Ptr actor, MWWorld::Ptr projectile, + void World::launchProjectile (MWWorld::Ptr actor, MWWorld::ConstPtr projectile, const osg::Vec3f& worldPos, const osg::Quat& orient, MWWorld::Ptr bow, float speed, float attackStrength) { mProjectileManager->launchProjectile(actor, projectile, worldPos, orient, bow, speed, attackStrength); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 7d67395cf..46f245a12 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -586,7 +586,7 @@ namespace MWWorld virtual void launchMagicBolt (const std::string& model, const std::string& sound, const std::string& spellId, float speed, bool stack, const ESM::EffectList& effects, const MWWorld::Ptr& caster, const std::string& sourceName, const osg::Vec3f& fallbackDirection); - virtual void launchProjectile (MWWorld::Ptr actor, MWWorld::Ptr projectile, + virtual void launchProjectile (MWWorld::Ptr actor, MWWorld::ConstPtr projectile, const osg::Vec3f& worldPos, const osg::Quat& orient, MWWorld::Ptr bow, float speed, float attackStrength); From 7a4aac184243e04bc5d12e966e8d1d3e0b0a1cb6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 17:20:29 +0100 Subject: [PATCH 2889/3725] Use a ConstPtr for the PtrAnimationMap --- apps/openmw/mwrender/objects.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/objects.hpp b/apps/openmw/mwrender/objects.hpp index 5c7ea32f4..3ce6266c8 100644 --- a/apps/openmw/mwrender/objects.hpp +++ b/apps/openmw/mwrender/objects.hpp @@ -57,7 +57,7 @@ public: }; class Objects{ - typedef std::map PtrAnimationMap; + typedef std::map PtrAnimationMap; typedef std::map > CellMap; CellMap mCellSceneNodes; From 7a8a7e3dd6a28bb734abcdf85b51d3f8662ac1c8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 17:21:51 +0100 Subject: [PATCH 2890/3725] Add const version of getAnimation --- apps/openmw/mwrender/objects.cpp | 9 +++++++++ apps/openmw/mwrender/objects.hpp | 1 + apps/openmw/mwrender/renderingmanager.cpp | 8 ++++++++ apps/openmw/mwrender/renderingmanager.hpp | 1 + 4 files changed, 19 insertions(+) diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index d612824e2..f58ebb917 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -263,4 +263,13 @@ Animation* Objects::getAnimation(const MWWorld::Ptr &ptr) return NULL; } +const Animation* Objects::getAnimation(const MWWorld::ConstPtr &ptr) const +{ + PtrAnimationMap::const_iterator iter = mObjects.find(ptr); + if(iter != mObjects.end()) + return iter->second; + + return NULL; +} + } diff --git a/apps/openmw/mwrender/objects.hpp b/apps/openmw/mwrender/objects.hpp index 3ce6266c8..3d0c92cb4 100644 --- a/apps/openmw/mwrender/objects.hpp +++ b/apps/openmw/mwrender/objects.hpp @@ -81,6 +81,7 @@ public: void insertCreature (const MWWorld::Ptr& ptr, const std::string& model, bool weaponsShields); Animation* getAnimation(const MWWorld::Ptr &ptr); + const Animation* getAnimation(const MWWorld::ConstPtr &ptr) const; bool removeObject (const MWWorld::Ptr& ptr); ///< \return found? diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index b44d77722..775463eaf 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -706,6 +706,14 @@ namespace MWRender return mObjects->getAnimation(ptr); } + const MWRender::Animation* RenderingManager::getAnimation(const MWWorld::ConstPtr &ptr) const + { + if (mPlayerAnimation.get() && ptr == mPlayerAnimation->getPtr()) + return mPlayerAnimation.get(); + + return mObjects->getAnimation(ptr); + } + MWRender::Animation* RenderingManager::getPlayerAnimation() { return mPlayerAnimation.get(); diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 7b1c8529f..c48864e91 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -136,6 +136,7 @@ namespace MWRender void update(float dt, bool paused); Animation* getAnimation(const MWWorld::Ptr& ptr); + const Animation* getAnimation(const MWWorld::ConstPtr& ptr) const; Animation* getPlayerAnimation(); void addWaterRippleEmitter(const MWWorld::Ptr& ptr); From 795032621c4d8dd643ccde72c7ebaaa7ec390b18 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 17:30:39 +0100 Subject: [PATCH 2891/3725] Use a ConstPtr for the ActorMap and ObjectMap --- apps/openmw/mwphysics/actor.hpp | 7 ++++++- apps/openmw/mwphysics/physicssystem.cpp | 8 ++++---- apps/openmw/mwphysics/physicssystem.hpp | 4 ++-- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwphysics/actor.hpp b/apps/openmw/mwphysics/actor.hpp index 3ea64840e..03193c675 100644 --- a/apps/openmw/mwphysics/actor.hpp +++ b/apps/openmw/mwphysics/actor.hpp @@ -31,7 +31,12 @@ namespace MWPhysics mPtr = updated; } - MWWorld::Ptr getPtr() const + MWWorld::Ptr getPtr() + { + return mPtr; + } + + MWWorld::ConstPtr getPtr() const { return mPtr; } diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 7b4b93678..99aa20853 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -409,7 +409,7 @@ namespace MWPhysics && tracer.mHitObject->getBroadphaseHandle()->m_collisionFilterGroup != CollisionType_Actor) { const btCollisionObject* standingOn = tracer.mHitObject; - const PtrHolder* ptrHolder = static_cast(standingOn->getUserPointer()); + PtrHolder* ptrHolder = static_cast(standingOn->getUserPointer()); if (ptrHolder) standingCollisionTracker[ptr] = ptrHolder->getPtr(); @@ -801,7 +801,7 @@ namespace MWPhysics if (resultCallback.mObject) { - const PtrHolder* holder = static_cast(resultCallback.mObject->getUserPointer()); + PtrHolder* holder = static_cast(resultCallback.mObject->getUserPointer()); if (holder) return std::make_pair(holder->getPtr(), toOsg(resultCallback.mContactPoint)); } @@ -1020,7 +1020,7 @@ namespace MWPhysics if (collisionObject == mTestedAgainst) collisionObject = col1; #endif - const PtrHolder* holder = static_cast(collisionObject->getUserPointer()); + PtrHolder* holder = static_cast(collisionObject->getUserPointer()); if (holder) mResult.push_back(holder->getPtr()); return 0.f; @@ -1303,7 +1303,7 @@ namespace MWPhysics // Slow fall reduces fall speed by a factor of (effect magnitude / 200) float slowFall = 1.f - std::max(0.f, std::min(1.f, effects.get(ESM::MagicEffect::SlowFall).getMagnitude() * 0.005f)); - osg::Vec3f newpos = MovementSolver::move(iter->first, physicActor, iter->second, mTimeAccum, + osg::Vec3f newpos = MovementSolver::move(physicActor->getPtr(), physicActor, iter->second, mTimeAccum, world->isFlying(iter->first), waterlevel, slowFall, mCollisionWorld, mStandingCollisions); diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index de644e0f3..311d5ef96 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -170,12 +170,12 @@ namespace MWPhysics std::auto_ptr mShapeManager; - typedef std::map ObjectMap; + typedef std::map ObjectMap; ObjectMap mObjects; std::set mAnimatedObjects; // stores pointers to elements in mObjects - typedef std::map ActorMap; + typedef std::map ActorMap; ActorMap mActors; typedef std::map, HeightField*> HeightFieldMap; From 0796f49c1765071492c294fcd26741b0ca74f0ec Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 17:36:14 +0100 Subject: [PATCH 2892/3725] Accept a ConstPtr in various physics getters --- apps/openmw/mwbase/world.hpp | 8 ++++---- apps/openmw/mwphysics/physicssystem.cpp | 10 +++++----- apps/openmw/mwphysics/physicssystem.hpp | 10 +++++----- apps/openmw/mwworld/worldimp.cpp | 12 ++++++------ apps/openmw/mwworld/worldimp.hpp | 8 ++++---- 5 files changed, 24 insertions(+), 24 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 27b071f96..54babfbcb 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -374,7 +374,7 @@ namespace MWBase virtual bool isUnderwater(const MWWorld::CellStore* cell, const osg::Vec3f &pos) const = 0; virtual bool isOnGround(const MWWorld::Ptr &ptr) const = 0; - virtual osg::Matrixf getActorHeadTransform(const MWWorld::Ptr& actor) const = 0; + virtual osg::Matrixf getActorHeadTransform(const MWWorld::ConstPtr& actor) const = 0; virtual void togglePOV() = 0; virtual bool isFirstPerson() const = 0; @@ -541,14 +541,14 @@ namespace MWBase /// Resets all actors in the current active cells to their original location within that cell. virtual void resetActors() = 0; - virtual bool isWalkingOnWater (const MWWorld::Ptr& actor) = 0; + virtual bool isWalkingOnWater (const MWWorld::ConstPtr& actor) = 0; /// Return a vector aiming the actor's weapon towards a target. /// @note The length of the vector is the distance between actor and target. - virtual osg::Vec3f aimToTarget(const MWWorld::Ptr& actor, const MWWorld::Ptr& target) = 0; + virtual osg::Vec3f aimToTarget(const MWWorld::ConstPtr& actor, const MWWorld::ConstPtr& target) = 0; /// Return the distance between actor's weapon and target's collision box. - virtual float getHitDistance(const MWWorld::Ptr& actor, const MWWorld::Ptr& target) = 0; + virtual float getHitDistance(const MWWorld::ConstPtr& actor, const MWWorld::ConstPtr& target) = 0; virtual void removeContainerScripts(const MWWorld::Ptr& reference) = 0; }; diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 99aa20853..d25099a80 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -808,7 +808,7 @@ namespace MWPhysics return std::make_pair(MWWorld::Ptr(), osg::Vec3f()); } - float PhysicsSystem::getHitDistance(const osg::Vec3f &point, const MWWorld::Ptr &target) const + float PhysicsSystem::getHitDistance(const osg::Vec3f &point, const MWWorld::ConstPtr &target) const { btCollisionObject* targetCollisionObj = NULL; const Actor* actor = getActor(target); @@ -965,7 +965,7 @@ namespace MWPhysics } } - osg::Vec3f PhysicsSystem::getHalfExtents(const MWWorld::Ptr &actor) const + osg::Vec3f PhysicsSystem::getHalfExtents(const MWWorld::ConstPtr &actor) const { const Actor* physactor = getActor(actor); if (physactor) @@ -974,7 +974,7 @@ namespace MWPhysics return osg::Vec3f(); } - osg::Vec3f PhysicsSystem::getRenderingHalfExtents(const MWWorld::Ptr &actor) const + osg::Vec3f PhysicsSystem::getRenderingHalfExtents(const MWWorld::ConstPtr &actor) const { const Actor* physactor = getActor(actor); if (physactor) @@ -983,7 +983,7 @@ namespace MWPhysics return osg::Vec3f(); } - osg::Vec3f PhysicsSystem::getPosition(const MWWorld::Ptr &actor) const + osg::Vec3f PhysicsSystem::getPosition(const MWWorld::ConstPtr &actor) const { const Actor* physactor = getActor(actor); if (physactor) @@ -1157,7 +1157,7 @@ namespace MWPhysics return NULL; } - const Actor *PhysicsSystem::getActor(const MWWorld::Ptr &ptr) const + const Actor *PhysicsSystem::getActor(const MWWorld::ConstPtr &ptr) const { ActorMap::const_iterator found = mActors.find(ptr); if (found != mActors.end()) diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index 311d5ef96..4edf462ca 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -63,7 +63,7 @@ namespace MWPhysics void updatePtr (const MWWorld::Ptr& old, const MWWorld::Ptr& updated); Actor* getActor(const MWWorld::Ptr& ptr); - const Actor* getActor(const MWWorld::Ptr& ptr) const; + const Actor* getActor(const MWWorld::ConstPtr& ptr) const; // Object or Actor void remove (const MWWorld::Ptr& ptr); @@ -95,7 +95,7 @@ namespace MWPhysics /// target vector hits the collision shape and then calculates distance from the intersection point. /// This can be used to find out how much nearer we need to move to the target for a "getHitContact" to be successful. /// \note Only Actor targets are supported at the moment. - float getHitDistance(const osg::Vec3f& point, const MWWorld::Ptr& target) const; + float getHitDistance(const osg::Vec3f& point, const MWWorld::ConstPtr& target) const; struct RayResult { @@ -117,14 +117,14 @@ namespace MWPhysics bool isOnGround (const MWWorld::Ptr& actor); /// Get physical half extents (scaled) of the given actor. - osg::Vec3f getHalfExtents(const MWWorld::Ptr& actor) const; + osg::Vec3f getHalfExtents(const MWWorld::ConstPtr& actor) const; /// @see MWPhysics::Actor::getRenderingHalfExtents - osg::Vec3f getRenderingHalfExtents(const MWWorld::Ptr& actor) const; + osg::Vec3f getRenderingHalfExtents(const MWWorld::ConstPtr& actor) const; /// Get the position of the collision shape for the actor. Use together with getHalfExtents() to get the collision bounds in world space. /// @note The collision shape's origin is in its center, so the position returned can be described as center of the actor collision box in world space. - osg::Vec3f getPosition(const MWWorld::Ptr& actor) const; + osg::Vec3f getPosition(const MWWorld::ConstPtr& actor) const; /// Queues velocity movement for a Ptr. If a Ptr is already queued, its velocity will /// be overwritten. Valid until the next call to applyQueuedMovement. diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 3f13f2faf..d0b3ff99e 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1038,9 +1038,9 @@ namespace MWWorld return facedObject; } - osg::Matrixf World::getActorHeadTransform(const MWWorld::Ptr& actor) const + osg::Matrixf World::getActorHeadTransform(const MWWorld::ConstPtr& actor) const { - MWRender::Animation *anim = mRendering->getAnimation(actor); + const MWRender::Animation *anim = mRendering->getAnimation(actor); if(anim) { const osg::Node *node = anim->getNode("Head"); @@ -3285,22 +3285,22 @@ namespace MWWorld } } - bool World::isWalkingOnWater(const Ptr &actor) + bool World::isWalkingOnWater(const ConstPtr &actor) { - MWPhysics::Actor* physicActor = mPhysics->getActor(actor); + const MWPhysics::Actor* physicActor = mPhysics->getActor(actor); if (physicActor && physicActor->isWalkingOnWater()) return true; return false; } - osg::Vec3f World::aimToTarget(const Ptr &actor, const MWWorld::Ptr& target) + osg::Vec3f World::aimToTarget(const ConstPtr &actor, const MWWorld::ConstPtr& target) { osg::Vec3f weaponPos = getActorHeadTransform(actor).getTrans(); osg::Vec3f targetPos = mPhysics->getPosition(target); return (targetPos - weaponPos); } - float World::getHitDistance(const Ptr &actor, const Ptr &target) + float World::getHitDistance(const ConstPtr &actor, const ConstPtr &target) { osg::Vec3f weaponPos = getActorHeadTransform(actor).getTrans(); return mPhysics->getHitDistance(weaponPos, target); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 46f245a12..90fc60ac7 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -470,7 +470,7 @@ namespace MWWorld virtual bool isWading(const MWWorld::Ptr &object) const; virtual bool isOnGround(const MWWorld::Ptr &ptr) const; - virtual osg::Matrixf getActorHeadTransform(const MWWorld::Ptr& actor) const; + virtual osg::Matrixf getActorHeadTransform(const MWWorld::ConstPtr& actor) const; virtual void togglePOV(); @@ -640,14 +640,14 @@ namespace MWWorld /// Resets all actors in the current active cells to their original location within that cell. virtual void resetActors(); - virtual bool isWalkingOnWater (const MWWorld::Ptr& actor); + virtual bool isWalkingOnWater (const MWWorld::ConstPtr& actor); /// Return a vector aiming the actor's weapon towards a target. /// @note The length of the vector is the distance between actor and target. - virtual osg::Vec3f aimToTarget(const MWWorld::Ptr& actor, const MWWorld::Ptr& target); + virtual osg::Vec3f aimToTarget(const MWWorld::ConstPtr& actor, const MWWorld::ConstPtr& target); /// Return the distance between actor's weapon and target's collision box. - virtual float getHitDistance(const MWWorld::Ptr& actor, const MWWorld::Ptr& target); + virtual float getHitDistance(const MWWorld::ConstPtr& actor, const MWWorld::ConstPtr& target); }; } From 6c505ca06f2176586cc244c462937f5326b41d95 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 17:38:21 +0100 Subject: [PATCH 2893/3725] Accept a ConstPtr in getHitContact --- apps/openmw/mwbase/world.hpp | 2 +- apps/openmw/mwphysics/physicssystem.cpp | 4 ++-- apps/openmw/mwphysics/physicssystem.hpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 2 +- apps/openmw/mwworld/worldimp.hpp | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 54babfbcb..25d434492 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -248,7 +248,7 @@ namespace MWBase /// Returns a pointer to the object the provided object would hit (if within the /// specified distance), and the point where the hit occurs. This will attempt to /// use the "Head" node, or alternatively the "Bip01 Head" node as a basis. - virtual std::pair getHitContact(const MWWorld::Ptr &ptr, float distance) = 0; + virtual std::pair getHitContact(const MWWorld::ConstPtr &ptr, float distance) = 0; virtual void adjustPosition (const MWWorld::Ptr& ptr, bool force) = 0; ///< Adjust position after load to be on ground. Must be called after model load. diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index d25099a80..5caffe4dd 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -770,7 +770,7 @@ namespace MWPhysics } }; - std::pair PhysicsSystem::getHitContact(const MWWorld::Ptr& actor, + std::pair PhysicsSystem::getHitContact(const MWWorld::ConstPtr& actor, const osg::Vec3f &origin, const osg::Quat &orient, float queryDistance) @@ -790,7 +790,7 @@ namespace MWPhysics object.setWorldTransform(btTransform(toBullet(orient), toBullet(center))); const btCollisionObject* me = NULL; - Actor* physactor = getActor(actor); + const Actor* physactor = getActor(actor); if (physactor) me = physactor->getCollisionObject(); diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index 4edf462ca..0271db273 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -85,7 +85,7 @@ namespace MWPhysics std::vector getCollisions(const MWWorld::Ptr &ptr, int collisionGroup, int collisionMask) const; ///< get handles this object collides with osg::Vec3f traceDown(const MWWorld::Ptr &ptr, float maxHeight); - std::pair getHitContact(const MWWorld::Ptr& actor, + std::pair getHitContact(const MWWorld::ConstPtr& actor, const osg::Vec3f &origin, const osg::Quat &orientation, float queryDistance); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index d0b3ff99e..be54f557a 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1056,7 +1056,7 @@ namespace MWWorld } - std::pair World::getHitContact(const MWWorld::Ptr &ptr, float distance) + std::pair World::getHitContact(const MWWorld::ConstPtr &ptr, float distance) { const ESM::Position &posdata = ptr.getRefData().getPosition(); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 90fc60ac7..c4d37b008 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -344,7 +344,7 @@ namespace MWWorld /// Returns a pointer to the object the provided object would hit (if within the /// specified distance), and the point where the hit occurs. This will attempt to /// use the "Head" node as a basis. - virtual std::pair getHitContact(const MWWorld::Ptr &ptr, float distance); + virtual std::pair getHitContact(const MWWorld::ConstPtr &ptr, float distance); /// @note No-op for items in containers. Use ContainerStore::removeItem instead. virtual void deleteObject (const Ptr& ptr); From c9ca5bc94658508920dbbef1f1a29101ab20ec4f Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 17:42:59 +0100 Subject: [PATCH 2894/3725] Accept a ConstPtr in placeObject --- apps/openmw/mwbase/world.hpp | 6 +++--- apps/openmw/mwworld/worldimp.cpp | 16 ++++++---------- apps/openmw/mwworld/worldimp.hpp | 8 ++++---- 3 files changed, 13 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 25d434492..3705cebaa 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -271,7 +271,7 @@ namespace MWBase virtual void rotateObject(const MWWorld::Ptr& ptr,float x,float y,float z, bool adjust = false) = 0; - virtual MWWorld::Ptr safePlaceObject(const MWWorld::Ptr& ptr, MWWorld::CellStore* cell, ESM::Position pos) = 0; + virtual MWWorld::Ptr safePlaceObject(const MWWorld::ConstPtr& ptr, MWWorld::CellStore* cell, ESM::Position pos) = 0; ///< place an object in a "safe" location (ie not in the void, etc). virtual void indexToPosition (int cellX, int cellY, float &x, float &y, bool centre = false) @@ -347,14 +347,14 @@ namespace MWBase virtual void update (float duration, bool paused) = 0; - virtual MWWorld::Ptr placeObject (const MWWorld::Ptr& object, float cursorX, float cursorY, int amount) = 0; + virtual MWWorld::Ptr placeObject (const MWWorld::ConstPtr& object, float cursorX, float cursorY, int amount) = 0; ///< copy and place an object into the gameworld at the specified cursor position /// @param object /// @param cursor X (relative 0-1) /// @param cursor Y (relative 0-1) /// @param number of objects to place - virtual MWWorld::Ptr dropObjectOnGround (const MWWorld::Ptr& actor, const MWWorld::Ptr& object, int amount) = 0; + virtual MWWorld::Ptr dropObjectOnGround (const MWWorld::Ptr& actor, const MWWorld::ConstPtr& object, int amount) = 0; ///< copy and place an object into the gameworld at the given actor's position /// @param actor giving the dropped object position /// @param object diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index be54f557a..2efe578a4 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1319,7 +1319,7 @@ namespace MWWorld rotateObjectImp(ptr, osg::Vec3f(x, y, z), adjust); } - MWWorld::Ptr World::safePlaceObject(const MWWorld::Ptr& ptr, MWWorld::CellStore* cell, ESM::Position pos) + MWWorld::Ptr World::safePlaceObject(const MWWorld::ConstPtr& ptr, MWWorld::CellStore* cell, ESM::Position pos) { return copyObjectToCell(ptr,cell,pos,false); } @@ -1797,7 +1797,7 @@ namespace MWWorld item.getRefData().getLocals().setVarByInt(script, "onpcdrop", 1); } - MWWorld::Ptr World::placeObject (const MWWorld::Ptr& object, float cursorX, float cursorY, int amount) + MWWorld::Ptr World::placeObject (const MWWorld::ConstPtr& object, float cursorX, float cursorY, int amount) { const float maxDist = 200.f; @@ -1817,10 +1817,8 @@ namespace MWWorld pos.rot[1] = 0; // copy the object and set its count - int origCount = object.getRefData().getCount(); - object.getRefData().setCount(amount); Ptr dropped = copyObjectToCell(object, cell, pos, true); - object.getRefData().setCount(origCount); + dropped.getRefData().setCount(amount); // only the player place items in the world, so no need to check actor PCDropped(dropped); @@ -1846,7 +1844,7 @@ namespace MWWorld } - Ptr World::copyObjectToCell(const Ptr &object, CellStore* cell, ESM::Position pos, bool adjustPos) + Ptr World::copyObjectToCell(const ConstPtr &object, CellStore* cell, ESM::Position pos, bool adjustPos) { if (cell->isExterior()) { @@ -1899,7 +1897,7 @@ namespace MWWorld return dropped; } - MWWorld::Ptr World::dropObjectOnGround (const Ptr& actor, const Ptr& object, int amount) + MWWorld::Ptr World::dropObjectOnGround (const Ptr& actor, const ConstPtr& object, int amount) { MWWorld::CellStore* cell = actor.getCell(); @@ -1920,10 +1918,8 @@ namespace MWWorld pos.pos[2] = result.mHitPointWorld.z(); // copy the object and set its count - int origCount = object.getRefData().getCount(); - object.getRefData().setCount(amount); Ptr dropped = copyObjectToCell(object, cell, pos); - object.getRefData().setCount(origCount); + dropped.getRefData().setCount(amount); if(actor == mPlayer->getPlayer()) // Only call if dropped by player PCDropped(dropped); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index c4d37b008..244ed9835 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -123,7 +123,7 @@ namespace MWWorld Ptr moveObjectImp (const Ptr& ptr, float x, float y, float z); ///< @return an updated Ptr in case the Ptr's cell changes - Ptr copyObjectToCell(const Ptr &ptr, CellStore* cell, ESM::Position pos, bool adjustPos=true); + Ptr copyObjectToCell(const ConstPtr &ptr, CellStore* cell, ESM::Position pos, bool adjustPos=true); void updateSoundListener(); void updateWindowManager (); @@ -365,7 +365,7 @@ namespace MWWorld /// \param adjust indicates rotation should be set or adjusted virtual void rotateObject (const Ptr& ptr,float x,float y,float z, bool adjust = false); - virtual MWWorld::Ptr safePlaceObject(const MWWorld::Ptr& ptr, MWWorld::CellStore* cell, ESM::Position pos); + virtual MWWorld::Ptr safePlaceObject(const MWWorld::ConstPtr& ptr, MWWorld::CellStore* cell, ESM::Position pos); ///< place an object in a "safe" location (ie not in the void, etc). Makes a copy of the Ptr. virtual float getMaxActivationDistance(); @@ -443,14 +443,14 @@ namespace MWWorld virtual void update (float duration, bool paused); - virtual MWWorld::Ptr placeObject (const MWWorld::Ptr& object, float cursorX, float cursorY, int amount); + virtual MWWorld::Ptr placeObject (const MWWorld::ConstPtr& object, float cursorX, float cursorY, int amount); ///< copy and place an object into the gameworld at the specified cursor position /// @param object /// @param cursor X (relative 0-1) /// @param cursor Y (relative 0-1) /// @param number of objects to place - virtual MWWorld::Ptr dropObjectOnGround (const MWWorld::Ptr& actor, const MWWorld::Ptr& object, int amount); + virtual MWWorld::Ptr dropObjectOnGround (const MWWorld::Ptr& actor, const MWWorld::ConstPtr& object, int amount); ///< copy and place an object into the gameworld at the given actor's position /// @param actor giving the dropped object position /// @param object From ed101ad35a43e57b5bcc043e76993d1030fdd184 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 17:44:57 +0100 Subject: [PATCH 2895/3725] Remove redundant getPlayerAnimation function --- apps/openmw/mwrender/renderingmanager.cpp | 5 ----- apps/openmw/mwrender/renderingmanager.hpp | 1 - apps/openmw/mwworld/worldimp.cpp | 2 -- 3 files changed, 8 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 775463eaf..ee9d93c0f 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -714,11 +714,6 @@ namespace MWRender return mObjects->getAnimation(ptr); } - MWRender::Animation* RenderingManager::getPlayerAnimation() - { - return mPlayerAnimation.get(); - } - void RenderingManager::setupPlayer(const MWWorld::Ptr &player) { if (!mPlayerNode) diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index c48864e91..58012078c 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -137,7 +137,6 @@ namespace MWRender Animation* getAnimation(const MWWorld::Ptr& ptr); const Animation* getAnimation(const MWWorld::ConstPtr& ptr) const; - Animation* getPlayerAnimation(); void addWaterRippleEmitter(const MWWorld::Ptr& ptr); void removeWaterRippleEmitter(const MWWorld::Ptr& ptr); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 2efe578a4..5da1e1a43 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2109,8 +2109,6 @@ namespace MWWorld MWRender::Animation* World::getAnimation(const MWWorld::Ptr &ptr) { - if (ptr == getPlayerPtr()) - return mRendering->getPlayerAnimation(); return mRendering->getAnimation(ptr); } From 388aed174884c2c91ac4187cafee950f93e4e219 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 17:56:48 +0100 Subject: [PATCH 2896/3725] Accept a ConstPtr in findContainer, collision script functions, getUnderwater functions --- apps/openmw/mwbase/world.hpp | 20 +++++++++---------- apps/openmw/mwphysics/physicssystem.cpp | 12 ++++++------ apps/openmw/mwphysics/physicssystem.hpp | 12 ++++++------ apps/openmw/mwworld/ptr.cpp | 5 +++++ apps/openmw/mwworld/worldimp.cpp | 26 ++++++++++++------------- apps/openmw/mwworld/worldimp.hpp | 22 ++++++++++----------- 6 files changed, 51 insertions(+), 46 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 3705cebaa..05b6454a3 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -178,7 +178,7 @@ namespace MWBase virtual MWWorld::Ptr searchPtrViaActorId (int actorId) = 0; ///< Search is limited to the active cells. - virtual MWWorld::Ptr findContainer (const MWWorld::Ptr& ptr) = 0; + virtual MWWorld::Ptr findContainer (const MWWorld::ConstPtr& ptr) = 0; ///< Return a pointer to a liveCellRef which contains \a ptr. /// \note Search is limited to the active cells. @@ -367,10 +367,10 @@ namespace MWBase virtual bool isFlying(const MWWorld::Ptr &ptr) const = 0; virtual bool isSlowFalling(const MWWorld::Ptr &ptr) const = 0; - virtual bool isSwimming(const MWWorld::Ptr &object) const = 0; - virtual bool isWading(const MWWorld::Ptr &object) const = 0; + virtual bool isSwimming(const MWWorld::ConstPtr &object) const = 0; + virtual bool isWading(const MWWorld::ConstPtr &object) const = 0; ///Is the head of the creature underwater? - virtual bool isSubmerged(const MWWorld::Ptr &object) const = 0; + virtual bool isSubmerged(const MWWorld::ConstPtr &object) const = 0; virtual bool isUnderwater(const MWWorld::CellStore* cell, const osg::Vec3f &pos) const = 0; virtual bool isOnGround(const MWWorld::Ptr &ptr) const = 0; @@ -396,14 +396,14 @@ namespace MWBase /// @note throws an exception when invoked on a teleport door virtual void activateDoor(const MWWorld::Ptr& door, int state) = 0; - virtual bool getPlayerStandingOn (const MWWorld::Ptr& object) = 0; ///< @return true if the player is standing on \a object - virtual bool getActorStandingOn (const MWWorld::Ptr& object) = 0; ///< @return true if any actor is standing on \a object - virtual bool getPlayerCollidingWith(const MWWorld::Ptr& object) = 0; ///< @return true if the player is colliding with \a object - virtual bool getActorCollidingWith (const MWWorld::Ptr& object) = 0; ///< @return true if any actor is colliding with \a object - virtual void hurtStandingActors (const MWWorld::Ptr& object, float dmgPerSecond) = 0; + virtual bool getPlayerStandingOn (const MWWorld::ConstPtr& object) = 0; ///< @return true if the player is standing on \a object + virtual bool getActorStandingOn (const MWWorld::ConstPtr& object) = 0; ///< @return true if any actor is standing on \a object + virtual bool getPlayerCollidingWith(const MWWorld::ConstPtr& object) = 0; ///< @return true if the player is colliding with \a object + virtual bool getActorCollidingWith (const MWWorld::ConstPtr& object) = 0; ///< @return true if any actor is colliding with \a object + virtual void hurtStandingActors (const MWWorld::ConstPtr& object, float dmgPerSecond) = 0; ///< Apply a health difference to any actors standing on \a object. /// To hurt actors, healthPerSecond should be a positive value. For a negative value, actors will be healed. - virtual void hurtCollidingActors (const MWWorld::Ptr& object, float dmgPerSecond) = 0; + virtual void hurtCollidingActors (const MWWorld::ConstPtr& object, float dmgPerSecond) = 0; ///< Apply a health difference to any actors colliding with \a object. /// To hurt actors, healthPerSecond should be a positive value. For a negative value, actors will be healed. diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 5caffe4dd..495880469 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -697,7 +697,7 @@ namespace MWPhysics return mDebugDrawEnabled; } - void PhysicsSystem::markAsNonSolid(const MWWorld::Ptr &ptr) + void PhysicsSystem::markAsNonSolid(const MWWorld::ConstPtr &ptr) { ObjectMap::iterator found = mObjects.find(ptr); if (found == mObjects.end()) @@ -1027,7 +1027,7 @@ namespace MWPhysics } }; - std::vector PhysicsSystem::getCollisions(const MWWorld::Ptr &ptr, int collisionGroup, int collisionMask) const + std::vector PhysicsSystem::getCollisions(const MWWorld::ConstPtr &ptr, int collisionGroup, int collisionMask) const { btCollisionObject* me = NULL; @@ -1337,7 +1337,7 @@ namespace MWPhysics mDebugDrawer->step(); } - bool PhysicsSystem::isActorStandingOn(const MWWorld::Ptr &actor, const MWWorld::Ptr &object) const + bool PhysicsSystem::isActorStandingOn(const MWWorld::Ptr &actor, const MWWorld::ConstPtr &object) const { for (CollisionMap::const_iterator it = mStandingCollisions.begin(); it != mStandingCollisions.end(); ++it) { @@ -1347,7 +1347,7 @@ namespace MWPhysics return false; } - void PhysicsSystem::getActorsStandingOn(const MWWorld::Ptr &object, std::vector &out) const + void PhysicsSystem::getActorsStandingOn(const MWWorld::ConstPtr &object, std::vector &out) const { for (CollisionMap::const_iterator it = mStandingCollisions.begin(); it != mStandingCollisions.end(); ++it) { @@ -1356,13 +1356,13 @@ namespace MWPhysics } } - bool PhysicsSystem::isActorCollidingWith(const MWWorld::Ptr &actor, const MWWorld::Ptr &object) const + bool PhysicsSystem::isActorCollidingWith(const MWWorld::Ptr &actor, const MWWorld::ConstPtr &object) const { std::vector collisions = getCollisions(object, CollisionType_World, CollisionType_Actor); return (std::find(collisions.begin(), collisions.end(), actor) != collisions.end()); } - void PhysicsSystem::getActorsCollidingWith(const MWWorld::Ptr &object, std::vector &out) const + void PhysicsSystem::getActorsCollidingWith(const MWWorld::ConstPtr &object, std::vector &out) const { std::vector collisions = getCollisions(object, CollisionType_World, CollisionType_Actor); out.insert(out.end(), collisions.begin(), collisions.end()); diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index 0271db273..ce611a4d0 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -82,7 +82,7 @@ namespace MWPhysics void stepSimulation(float dt); void debugDraw(); - std::vector getCollisions(const MWWorld::Ptr &ptr, int collisionGroup, int collisionMask) const; ///< get handles this object collides with + std::vector getCollisions(const MWWorld::ConstPtr &ptr, int collisionGroup, int collisionMask) const; ///< get handles this object collides with osg::Vec3f traceDown(const MWWorld::Ptr &ptr, float maxHeight); std::pair getHitContact(const MWWorld::ConstPtr& actor, @@ -139,23 +139,23 @@ namespace MWPhysics /// Return true if \a actor has been standing on \a object in this frame /// This will trigger whenever the object is directly below the actor. /// It doesn't matter if the actor is stationary or moving. - bool isActorStandingOn(const MWWorld::Ptr& actor, const MWWorld::Ptr& object) const; + bool isActorStandingOn(const MWWorld::Ptr& actor, const MWWorld::ConstPtr& object) const; /// Get the handle of all actors standing on \a object in this frame. - void getActorsStandingOn(const MWWorld::Ptr& object, std::vector& out) const; + void getActorsStandingOn(const MWWorld::ConstPtr& object, std::vector& out) const; /// Return true if \a actor has collided with \a object in this frame. /// This will detect running into objects, but will not detect climbing stairs, stepping up a small object, etc. - bool isActorCollidingWith(const MWWorld::Ptr& actor, const MWWorld::Ptr& object) const; + bool isActorCollidingWith(const MWWorld::Ptr& actor, const MWWorld::ConstPtr& object) const; /// Get the handle of all actors colliding with \a object in this frame. - void getActorsCollidingWith(const MWWorld::Ptr& object, std::vector& out) const; + void getActorsCollidingWith(const MWWorld::ConstPtr& object, std::vector& out) const; bool toggleDebugRendering(); /// Mark the given object as a 'non-solid' object. A non-solid object means that /// \a isOnSolidGround will return false for actors standing on that object. - void markAsNonSolid (const MWWorld::Ptr& ptr); + void markAsNonSolid (const MWWorld::ConstPtr& ptr); bool isOnSolidGround (const MWWorld::Ptr& actor) const; diff --git a/apps/openmw/mwworld/ptr.cpp b/apps/openmw/mwworld/ptr.cpp index 3f2ef80b6..01e7be1d1 100644 --- a/apps/openmw/mwworld/ptr.cpp +++ b/apps/openmw/mwworld/ptr.cpp @@ -70,6 +70,11 @@ const MWWorld::LiveCellRefBase *MWWorld::ConstPtr::getBase() const return mRef; } +const MWWorld::ContainerStore *MWWorld::ConstPtr::getContainerStore() const +{ + return mContainerStore; +} + MWWorld::ConstPtr::operator const void *() { return mRef; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 5da1e1a43..d19e311f5 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -691,10 +691,10 @@ namespace MWWorld struct FindContainerVisitor { - Ptr mContainedPtr; + ConstPtr mContainedPtr; Ptr mResult; - FindContainerVisitor(const Ptr& containedPtr) : mContainedPtr(containedPtr) {} + FindContainerVisitor(const ConstPtr& containedPtr) : mContainedPtr(containedPtr) {} bool operator() (Ptr ptr) { @@ -708,7 +708,7 @@ namespace MWWorld } }; - Ptr World::findContainer(const Ptr& ptr) + Ptr World::findContainer(const ConstPtr& ptr) { if (ptr.isInCell()) return Ptr(); @@ -1967,23 +1967,23 @@ namespace MWWorld return false; } - bool World::isSubmerged(const MWWorld::Ptr &object) const + bool World::isSubmerged(const MWWorld::ConstPtr &object) const { return isUnderwater(object, 1.0f/mSwimHeightScale); } - bool World::isSwimming(const MWWorld::Ptr &object) const + bool World::isSwimming(const MWWorld::ConstPtr &object) const { return isUnderwater(object, mSwimHeightScale); } - bool World::isWading(const MWWorld::Ptr &object) const + bool World::isWading(const MWWorld::ConstPtr &object) const { const float kneeDeep = 0.25f; return isUnderwater(object, kneeDeep); } - bool World::isUnderwater(const MWWorld::Ptr &object, const float heightRatio) const + bool World::isUnderwater(const MWWorld::ConstPtr &object, const float heightRatio) const { osg::Vec3f pos (object.getRefData().getPosition().asVec3()); @@ -2148,33 +2148,33 @@ namespace MWWorld mDoorStates.erase(door); } - bool World::getPlayerStandingOn (const MWWorld::Ptr& object) + bool World::getPlayerStandingOn (const MWWorld::ConstPtr& object) { MWWorld::Ptr player = getPlayerPtr(); return mPhysics->isActorStandingOn(player, object); } - bool World::getActorStandingOn (const MWWorld::Ptr& object) + bool World::getActorStandingOn (const MWWorld::ConstPtr& object) { std::vector actors; mPhysics->getActorsStandingOn(object, actors); return !actors.empty(); } - bool World::getPlayerCollidingWith (const MWWorld::Ptr& object) + bool World::getPlayerCollidingWith (const MWWorld::ConstPtr& object) { MWWorld::Ptr player = getPlayerPtr(); return mPhysics->isActorCollidingWith(player, object); } - bool World::getActorCollidingWith (const MWWorld::Ptr& object) + bool World::getActorCollidingWith (const MWWorld::ConstPtr& object) { std::vector actors; mPhysics->getActorsCollidingWith(object, actors); return !actors.empty(); } - void World::hurtStandingActors(const Ptr &object, float healthPerSecond) + void World::hurtStandingActors(const ConstPtr &object, float healthPerSecond) { if (MWBase::Environment::get().getWindowManager()->isGuiMode()) return; @@ -2204,7 +2204,7 @@ namespace MWWorld } } - void World::hurtCollidingActors(const Ptr &object, float healthPerSecond) + void World::hurtCollidingActors(const ConstPtr &object, float healthPerSecond) { if (MWBase::Environment::get().getWindowManager()->isGuiMode()) return; diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 244ed9835..ba3993c24 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -155,7 +155,7 @@ namespace MWWorld const std::vector& content, ContentLoader& contentLoader); float mSwimHeightScale; - bool isUnderwater(const MWWorld::Ptr &object, const float heightRatio) const; + bool isUnderwater(const MWWorld::ConstPtr &object, const float heightRatio) const; ///< helper function for implementing isSwimming(), isSubmerged(), isWading() bool mTeleportEnabled; @@ -269,7 +269,7 @@ namespace MWWorld virtual Ptr searchPtrViaActorId (int actorId); ///< Search is limited to the active cells. - virtual MWWorld::Ptr findContainer (const MWWorld::Ptr& ptr); + virtual MWWorld::Ptr findContainer (const MWWorld::ConstPtr& ptr); ///< Return a pointer to a liveCellRef which contains \a ptr. /// \note Search is limited to the active cells. @@ -464,10 +464,10 @@ namespace MWWorld virtual bool isFlying(const MWWorld::Ptr &ptr) const; virtual bool isSlowFalling(const MWWorld::Ptr &ptr) const; ///Is the head of the creature underwater? - virtual bool isSubmerged(const MWWorld::Ptr &object) const; - virtual bool isSwimming(const MWWorld::Ptr &object) const; + virtual bool isSubmerged(const MWWorld::ConstPtr &object) const; + virtual bool isSwimming(const MWWorld::ConstPtr &object) const; virtual bool isUnderwater(const MWWorld::CellStore* cell, const osg::Vec3f &pos) const; - virtual bool isWading(const MWWorld::Ptr &object) const; + virtual bool isWading(const MWWorld::ConstPtr &object) const; virtual bool isOnGround(const MWWorld::Ptr &ptr) const; virtual osg::Matrixf getActorHeadTransform(const MWWorld::ConstPtr& actor) const; @@ -500,14 +500,14 @@ namespace MWWorld /// @note throws an exception when invoked on a teleport door virtual void activateDoor(const MWWorld::Ptr& door, int state); - virtual bool getPlayerStandingOn (const MWWorld::Ptr& object); ///< @return true if the player is standing on \a object - virtual bool getActorStandingOn (const MWWorld::Ptr& object); ///< @return true if any actor is standing on \a object - virtual bool getPlayerCollidingWith(const MWWorld::Ptr& object); ///< @return true if the player is colliding with \a object - virtual bool getActorCollidingWith (const MWWorld::Ptr& object); ///< @return true if any actor is colliding with \a object - virtual void hurtStandingActors (const MWWorld::Ptr& object, float dmgPerSecond); + virtual bool getPlayerStandingOn (const MWWorld::ConstPtr& object); ///< @return true if the player is standing on \a object + virtual bool getActorStandingOn (const MWWorld::ConstPtr& object); ///< @return true if any actor is standing on \a object + virtual bool getPlayerCollidingWith(const MWWorld::ConstPtr& object); ///< @return true if the player is colliding with \a object + virtual bool getActorCollidingWith (const MWWorld::ConstPtr& object); ///< @return true if any actor is colliding with \a object + virtual void hurtStandingActors (const MWWorld::ConstPtr& object, float dmgPerSecond); ///< Apply a health difference to any actors standing on \a object. /// To hurt actors, healthPerSecond should be a positive value. For a negative value, actors will be healed. - virtual void hurtCollidingActors (const MWWorld::Ptr& object, float dmgPerSecond); + virtual void hurtCollidingActors (const MWWorld::ConstPtr& object, float dmgPerSecond); ///< Apply a health difference to any actors colliding with \a object. /// To hurt actors, healthPerSecond should be a positive value. For a negative value, actors will be healed. From 029d467ea5d4f96aebf4adc764e9c3a58f0c4d0c Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 18:00:18 +0100 Subject: [PATCH 2897/3725] Accept a ConstPtr in getItemsOwnedBy, getContainersOwnedBy --- apps/openmw/mwbase/world.hpp | 4 ++-- apps/openmw/mwworld/worldimp.cpp | 8 ++++---- apps/openmw/mwworld/worldimp.hpp | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 05b6454a3..9ee9db48c 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -409,9 +409,9 @@ namespace MWBase virtual float getWindSpeed() = 0; - virtual void getContainersOwnedBy (const MWWorld::Ptr& npc, std::vector& out) = 0; + virtual void getContainersOwnedBy (const MWWorld::ConstPtr& npc, std::vector& out) = 0; ///< get all containers in active cells owned by this Npc - virtual void getItemsOwnedBy (const MWWorld::Ptr& npc, std::vector& out) = 0; + virtual void getItemsOwnedBy (const MWWorld::ConstPtr& npc, std::vector& out) = 0; ///< get all items in active cells owned by this Npc virtual bool getLOS(const MWWorld::Ptr& actor,const MWWorld::Ptr& targetActor) = 0; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index d19e311f5..357d50845 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2260,13 +2260,13 @@ namespace MWWorld struct GetContainersOwnedByVisitor { - GetContainersOwnedByVisitor(const MWWorld::Ptr& owner, std::vector& out) + GetContainersOwnedByVisitor(const MWWorld::ConstPtr& owner, std::vector& out) : mOwner(owner) , mOut(out) { } - MWWorld::Ptr mOwner; + MWWorld::ConstPtr mOwner; std::vector& mOut; bool operator()(const MWWorld::Ptr& ptr) @@ -2281,7 +2281,7 @@ namespace MWWorld } }; - void World::getContainersOwnedBy (const MWWorld::Ptr& owner, std::vector& out) + void World::getContainersOwnedBy (const MWWorld::ConstPtr& owner, std::vector& out) { const Scene::CellStoreCollection& collection = mWorldScene->getActiveCells(); for (Scene::CellStoreCollection::const_iterator cellIt = collection.begin(); cellIt != collection.end(); ++cellIt) @@ -2303,7 +2303,7 @@ namespace MWWorld } }; - void World::getItemsOwnedBy (const MWWorld::Ptr& npc, std::vector& out) + void World::getItemsOwnedBy (const MWWorld::ConstPtr& npc, std::vector& out) { const Scene::CellStoreCollection& collection = mWorldScene->getActiveCells(); for (Scene::CellStoreCollection::const_iterator cellIt = collection.begin(); cellIt != collection.end(); ++cellIt) diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index ba3993c24..55932981e 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -513,9 +513,9 @@ namespace MWWorld virtual float getWindSpeed(); - virtual void getContainersOwnedBy (const MWWorld::Ptr& npc, std::vector& out); + virtual void getContainersOwnedBy (const MWWorld::ConstPtr& npc, std::vector& out); ///< get all containers in active cells owned by this Npc - virtual void getItemsOwnedBy (const MWWorld::Ptr& npc, std::vector& out); + virtual void getItemsOwnedBy (const MWWorld::ConstPtr& npc, std::vector& out); ///< get all items in active cells owned by this Npc virtual bool getLOS(const MWWorld::Ptr& actor,const MWWorld::Ptr& targetActor); From a0fb31e3b1f869b7b2019c303298002d16755132 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 18:02:57 +0100 Subject: [PATCH 2898/3725] Accept a ConstPtr in getLOS --- apps/openmw/mwbase/world.hpp | 2 +- apps/openmw/mwphysics/physicssystem.cpp | 10 +++++----- apps/openmw/mwphysics/physicssystem.hpp | 4 ++-- apps/openmw/mwworld/refdata.cpp | 5 +++++ apps/openmw/mwworld/refdata.hpp | 3 +++ apps/openmw/mwworld/worldimp.cpp | 2 +- apps/openmw/mwworld/worldimp.hpp | 2 +- 7 files changed, 18 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 9ee9db48c..fd8a10af8 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -414,7 +414,7 @@ namespace MWBase virtual void getItemsOwnedBy (const MWWorld::ConstPtr& npc, std::vector& out) = 0; ///< get all items in active cells owned by this Npc - virtual bool getLOS(const MWWorld::Ptr& actor,const MWWorld::Ptr& targetActor) = 0; + virtual bool getLOS(const MWWorld::ConstPtr& actor,const MWWorld::ConstPtr& targetActor) = 0; ///< get Line of Sight (morrowind stupid implementation) virtual float getDistToNearestRayHit(const osg::Vec3f& from, const osg::Vec3f& dir, float maxDist) = 0; diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 495880469..39e212c0b 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -857,7 +857,7 @@ namespace MWPhysics const btCollisionObject* mMe; }; - PhysicsSystem::RayResult PhysicsSystem::castRay(const osg::Vec3f &from, const osg::Vec3f &to, MWWorld::Ptr ignore, int mask, int group) + PhysicsSystem::RayResult PhysicsSystem::castRay(const osg::Vec3f &from, const osg::Vec3f &to, MWWorld::Ptr ignore, int mask, int group) const { btVector3 btFrom = toBullet(from); btVector3 btTo = toBullet(to); @@ -865,7 +865,7 @@ namespace MWPhysics const btCollisionObject* me = NULL; if (!ignore.isEmpty()) { - Actor* actor = getActor(ignore); + const Actor* actor = getActor(ignore); if (actor) me = actor->getCollisionObject(); } @@ -912,10 +912,10 @@ namespace MWPhysics return result; } - bool PhysicsSystem::getLineOfSight(const MWWorld::Ptr &actor1, const MWWorld::Ptr &actor2) + bool PhysicsSystem::getLineOfSight(const MWWorld::ConstPtr &actor1, const MWWorld::ConstPtr &actor2) const { - Actor* physactor1 = getActor(actor1); - Actor* physactor2 = getActor(actor2); + const Actor* physactor1 = getActor(actor1); + const Actor* physactor2 = getActor(actor2); if (!physactor1 || !physactor2) return false; diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index ce611a4d0..09a76e208 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -107,12 +107,12 @@ namespace MWPhysics /// @param me Optional, a Ptr to ignore in the list of results RayResult castRay(const osg::Vec3f &from, const osg::Vec3f &to, MWWorld::Ptr ignore = MWWorld::Ptr(), int mask = - CollisionType_World|CollisionType_HeightMap|CollisionType_Actor, int group=0xff); + CollisionType_World|CollisionType_HeightMap|CollisionType_Actor, int group=0xff) const; RayResult castSphere(const osg::Vec3f& from, const osg::Vec3f& to, float radius); /// Return true if actor1 can see actor2. - bool getLineOfSight(const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2); + bool getLineOfSight(const MWWorld::ConstPtr& actor1, const MWWorld::ConstPtr& actor2) const; bool isOnGround (const MWWorld::Ptr& actor); diff --git a/apps/openmw/mwworld/refdata.cpp b/apps/openmw/mwworld/refdata.cpp index 6c89f6d6f..1da6b53fa 100644 --- a/apps/openmw/mwworld/refdata.cpp +++ b/apps/openmw/mwworld/refdata.cpp @@ -118,6 +118,11 @@ namespace MWWorld return mBaseNode; } + const SceneUtil::PositionAttitudeTransform* RefData::getBaseNode() const + { + return mBaseNode; + } + int RefData::getCount() const { return mCount; diff --git a/apps/openmw/mwworld/refdata.hpp b/apps/openmw/mwworld/refdata.hpp index d02e05c98..28d2dad4c 100644 --- a/apps/openmw/mwworld/refdata.hpp +++ b/apps/openmw/mwworld/refdata.hpp @@ -75,6 +75,9 @@ namespace MWWorld /// Return base node (can be a null pointer). SceneUtil::PositionAttitudeTransform* getBaseNode(); + /// Return base node (can be a null pointer). + const SceneUtil::PositionAttitudeTransform* getBaseNode() const; + /// Set base node (can be a null pointer). void setBaseNode (SceneUtil::PositionAttitudeTransform* base); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 357d50845..821f950dd 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2317,7 +2317,7 @@ namespace MWWorld } } - bool World::getLOS(const MWWorld::Ptr& actor, const MWWorld::Ptr& targetActor) + bool World::getLOS(const MWWorld::ConstPtr& actor, const MWWorld::ConstPtr& targetActor) { if (!targetActor.getRefData().isEnabled() || !actor.getRefData().isEnabled()) return false; // cannot get LOS unless both NPC's are enabled diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 55932981e..51056c429 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -518,7 +518,7 @@ namespace MWWorld virtual void getItemsOwnedBy (const MWWorld::ConstPtr& npc, std::vector& out); ///< get all items in active cells owned by this Npc - virtual bool getLOS(const MWWorld::Ptr& actor,const MWWorld::Ptr& targetActor); + virtual bool getLOS(const MWWorld::ConstPtr& actor,const MWWorld::ConstPtr& targetActor); ///< get Line of Sight (morrowind stupid implementation) virtual float getDistToNearestRayHit(const osg::Vec3f& from, const osg::Vec3f& dir, float maxDist); From 604b5d24e91c3d582dccf87657497a2542674eb2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 18:11:30 +0100 Subject: [PATCH 2899/3725] Use a ConstPtr in SoundManager --- apps/openmw/mwbase/soundmanager.hpp | 20 +++++------ apps/openmw/mwsound/soundmanagerimp.cpp | 46 ++++++++++++------------- apps/openmw/mwsound/soundmanagerimp.hpp | 26 +++++++------- 3 files changed, 46 insertions(+), 46 deletions(-) diff --git a/apps/openmw/mwbase/soundmanager.hpp b/apps/openmw/mwbase/soundmanager.hpp index cc580f1c9..22582c2b1 100644 --- a/apps/openmw/mwbase/soundmanager.hpp +++ b/apps/openmw/mwbase/soundmanager.hpp @@ -87,7 +87,7 @@ namespace MWBase ///< Start playing music from the selected folder /// \param name of the folder that contains the playlist - virtual void say(const MWWorld::Ptr &reference, const std::string& filename) = 0; + virtual void say(const MWWorld::ConstPtr &reference, const std::string& filename) = 0; ///< Make an actor say some text. /// \param filename name of a sound file in "Sound/" in the data directory. @@ -95,13 +95,13 @@ namespace MWBase ///< Say some text, without an actor ref /// \param filename name of a sound file in "Sound/" in the data directory. - virtual bool sayDone(const MWWorld::Ptr &reference=MWWorld::Ptr()) const = 0; + virtual bool sayDone(const MWWorld::ConstPtr &reference=MWWorld::ConstPtr()) const = 0; ///< Is actor not speaking? - virtual void stopSay(const MWWorld::Ptr &reference=MWWorld::Ptr()) = 0; + virtual void stopSay(const MWWorld::ConstPtr &reference=MWWorld::ConstPtr()) = 0; ///< Stop an actor speaking - virtual float getSaySoundLoudness(const MWWorld::Ptr& reference) const = 0; + virtual float getSaySoundLoudness(const MWWorld::ConstPtr& reference) const = 0; ///< Check the currently playing say sound for this actor /// and get an average loudness value (scale [0,1]) at the current time position. /// If the actor is not saying anything, returns 0. @@ -123,7 +123,7 @@ namespace MWBase ///< Play a sound, independently of 3D-position ///< @param offset Number of seconds into the sound to start playback. - virtual MWBase::SoundPtr playSound3D(const MWWorld::Ptr &reference, const std::string& soundId, + virtual MWBase::SoundPtr playSound3D(const MWWorld::ConstPtr &reference, const std::string& soundId, float volume, float pitch, PlayType type=Play_TypeSfx, PlayMode mode=Play_Normal, float offset=0) = 0; ///< Play a 3D sound attached to an MWWorld::Ptr. Will be updated automatically with the Ptr's position, unless Play_NoTrack is specified. @@ -136,10 +136,10 @@ namespace MWBase virtual void stopSound(SoundPtr sound) = 0; ///< Stop the given sound from playing - virtual void stopSound3D(const MWWorld::Ptr &reference, const std::string& soundId) = 0; + virtual void stopSound3D(const MWWorld::ConstPtr &reference, const std::string& soundId) = 0; ///< Stop the given object from playing the given sound, - virtual void stopSound3D(const MWWorld::Ptr &reference) = 0; + virtual void stopSound3D(const MWWorld::ConstPtr &reference) = 0; ///< Stop the given object from playing all sounds. virtual void stopSound(const MWWorld::CellStore *cell) = 0; @@ -148,13 +148,13 @@ namespace MWBase virtual void stopSound(const std::string& soundId) = 0; ///< Stop a non-3d looping sound - virtual void fadeOutSound3D(const MWWorld::Ptr &reference, const std::string& soundId, float duration) = 0; + virtual void fadeOutSound3D(const MWWorld::ConstPtr &reference, const std::string& soundId, float duration) = 0; ///< Fade out given sound (that is already playing) of given object ///< @param reference Reference to object, whose sound is faded out ///< @param soundId ID of the sound to fade out. ///< @param duration Time until volume reaches 0. - virtual bool getSoundPlaying(const MWWorld::Ptr &reference, const std::string& soundId) const = 0; + virtual bool getSoundPlaying(const MWWorld::ConstPtr &reference, const std::string& soundId) const = 0; ///< Is the given sound currently playing on the given object? /// If you want to check if sound played with playSound is playing, use empty Ptr @@ -168,7 +168,7 @@ namespace MWBase virtual void setListenerPosDir(const osg::Vec3f &pos, const osg::Vec3f &dir, const osg::Vec3f &up, bool underwater) = 0; - virtual void updatePtr(const MWWorld::Ptr& old, const MWWorld::Ptr& updated) = 0; + virtual void updatePtr(const MWWorld::ConstPtr& old, const MWWorld::ConstPtr& updated) = 0; virtual void clear() = 0; }; diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index d235b2fb9..e8ceaa40f 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -392,7 +392,7 @@ namespace MWSound } - void SoundManager::say(const MWWorld::Ptr &ptr, const std::string &filename) + void SoundManager::say(const MWWorld::ConstPtr &ptr, const std::string &filename) { if(!mOutput->isInitialized()) return; @@ -429,7 +429,7 @@ namespace MWSound } } - float SoundManager::getSaySoundLoudness(const MWWorld::Ptr &ptr) const + float SoundManager::getSaySoundLoudness(const MWWorld::ConstPtr &ptr) const { SaySoundMap::const_iterator snditer = mActiveSaySounds.find(ptr); if(snditer != mActiveSaySounds.end()) @@ -456,17 +456,17 @@ namespace MWSound DecoderPtr decoder = loadVoice(voicefile, &loudness); if(!loudness->isReady()) - mPendingSaySounds[MWWorld::Ptr()] = std::make_pair(decoder, loudness); + mPendingSaySounds[MWWorld::ConstPtr()] = std::make_pair(decoder, loudness); else { - SaySoundMap::iterator oldIt = mActiveSaySounds.find(MWWorld::Ptr()); + SaySoundMap::iterator oldIt = mActiveSaySounds.find(MWWorld::ConstPtr()); if (oldIt != mActiveSaySounds.end()) { mOutput->finishStream(oldIt->second.first); mActiveSaySounds.erase(oldIt); } - mActiveSaySounds.insert(std::make_pair(MWWorld::Ptr(), + mActiveSaySounds.insert(std::make_pair(MWWorld::ConstPtr(), std::make_pair(playVoice(decoder, osg::Vec3f(), true), loudness))); } } @@ -476,7 +476,7 @@ namespace MWSound } } - bool SoundManager::sayDone(const MWWorld::Ptr &ptr) const + bool SoundManager::sayDone(const MWWorld::ConstPtr &ptr) const { SaySoundMap::const_iterator snditer = mActiveSaySounds.find(ptr); if(snditer != mActiveSaySounds.end()) @@ -488,7 +488,7 @@ namespace MWSound return mPendingSaySounds.find(ptr) == mPendingSaySounds.end(); } - void SoundManager::stopSay(const MWWorld::Ptr &ptr) + void SoundManager::stopSay(const MWWorld::ConstPtr &ptr) { SaySoundMap::iterator snditer = mActiveSaySounds.find(ptr); if(snditer != mActiveSaySounds.end()) @@ -552,7 +552,7 @@ namespace MWSound if(iter != mUnusedBuffers.end()) mUnusedBuffers.erase(iter); } - mActiveSounds[MWWorld::Ptr()].push_back(std::make_pair(sound, sfx)); + mActiveSounds[MWWorld::ConstPtr()].push_back(std::make_pair(sound, sfx)); } catch(std::exception&) { @@ -562,7 +562,7 @@ namespace MWSound return sound; } - MWBase::SoundPtr SoundManager::playSound3D(const MWWorld::Ptr &ptr, const std::string& soundId, + MWBase::SoundPtr SoundManager::playSound3D(const MWWorld::ConstPtr &ptr, const std::string& soundId, float volume, float pitch, PlayType type, PlayMode mode, float offset) { MWBase::SoundPtr sound; @@ -627,7 +627,7 @@ namespace MWSound if(iter != mUnusedBuffers.end()) mUnusedBuffers.erase(iter); } - mActiveSounds[MWWorld::Ptr()].push_back(std::make_pair(sound, sfx)); + mActiveSounds[MWWorld::ConstPtr()].push_back(std::make_pair(sound, sfx)); } catch(std::exception &) { @@ -643,7 +643,7 @@ namespace MWSound mOutput->finishSound(sound); } - void SoundManager::stopSound3D(const MWWorld::Ptr &ptr, const std::string& soundId) + void SoundManager::stopSound3D(const MWWorld::ConstPtr &ptr, const std::string& soundId) { SoundMap::iterator snditer = mActiveSounds.find(ptr); if(snditer != mActiveSounds.end()) @@ -658,7 +658,7 @@ namespace MWSound } } - void SoundManager::stopSound3D(const MWWorld::Ptr &ptr) + void SoundManager::stopSound3D(const MWWorld::ConstPtr &ptr) { SoundMap::iterator snditer = mActiveSounds.find(ptr); if(snditer != mActiveSounds.end()) @@ -674,7 +674,7 @@ namespace MWSound SoundMap::iterator snditer = mActiveSounds.begin(); while(snditer != mActiveSounds.end()) { - if(snditer->first != MWWorld::Ptr() && + if(snditer->first != MWWorld::ConstPtr() && snditer->first != MWMechanics::getPlayer() && snditer->first.getCell() == cell) { @@ -687,7 +687,7 @@ namespace MWSound SaySoundMap::iterator sayiter = mActiveSaySounds.begin(); while(sayiter != mActiveSaySounds.end()) { - if(sayiter->first != MWWorld::Ptr() && + if(sayiter->first != MWWorld::ConstPtr() && sayiter->first != MWMechanics::getPlayer() && sayiter->first.getCell() == cell) { @@ -699,7 +699,7 @@ namespace MWSound void SoundManager::stopSound(const std::string& soundId) { - SoundMap::iterator snditer = mActiveSounds.find(MWWorld::Ptr()); + SoundMap::iterator snditer = mActiveSounds.find(MWWorld::ConstPtr()); if(snditer != mActiveSounds.end()) { Sound_Buffer *sfx = loadSound(Misc::StringUtils::lowerCase(soundId)); @@ -712,7 +712,7 @@ namespace MWSound } } - void SoundManager::fadeOutSound3D(const MWWorld::Ptr &ptr, + void SoundManager::fadeOutSound3D(const MWWorld::ConstPtr &ptr, const std::string& soundId, float duration) { SoundMap::iterator snditer = mActiveSounds.find(ptr); @@ -728,7 +728,7 @@ namespace MWSound } } - bool SoundManager::getSoundPlaying(const MWWorld::Ptr &ptr, const std::string& soundId) const + bool SoundManager::getSoundPlaying(const MWWorld::ConstPtr &ptr, const std::string& soundId) const { SoundMap::const_iterator snditer = mActiveSounds.find(ptr); if(snditer != mActiveSounds.end()) @@ -773,7 +773,7 @@ namespace MWSound static std::string regionName = ""; static float sTimePassed = 0.0; MWBase::World *world = MWBase::Environment::get().getWorld(); - const MWWorld::Ptr player = world->getPlayerPtr(); + const MWWorld::ConstPtr player = world->getPlayerPtr(); const ESM::Cell *cell = player.getCell()->getCell(); sTimePassed += duration; @@ -864,7 +864,7 @@ namespace MWSound SoundBufferRefPairList::iterator sndidx = snditer->second.begin(); while(sndidx != snditer->second.end()) { - MWWorld::Ptr ptr = snditer->first; + MWWorld::ConstPtr ptr = snditer->first; MWBase::SoundPtr sound = sndidx->first; if(!ptr.isEmpty() && sound->getIs3D()) { @@ -912,7 +912,7 @@ namespace MWSound decoder->rewind(); MWBase::SoundStreamPtr sound; - MWWorld::Ptr ptr = penditer->first; + MWWorld::ConstPtr ptr = penditer->first; SaySoundMap::iterator old = mActiveSaySounds.find(ptr); if (old != mActiveSaySounds.end()) @@ -921,7 +921,7 @@ namespace MWSound mActiveSaySounds.erase(old); } - if(ptr == MWWorld::Ptr()) + if(ptr == MWWorld::ConstPtr()) sound = playVoice(decoder, osg::Vec3f(), true); else { @@ -944,7 +944,7 @@ namespace MWSound SaySoundMap::iterator sayiter = mActiveSaySounds.begin(); while(sayiter != mActiveSaySounds.end()) { - MWWorld::Ptr ptr = sayiter->first; + MWWorld::ConstPtr ptr = sayiter->first; MWBase::SoundStreamPtr sound = sayiter->second.first; if(!ptr.isEmpty() && sound->getIs3D()) { @@ -1068,7 +1068,7 @@ namespace MWSound mListenerUnderwater = underwater; } - void SoundManager::updatePtr(const MWWorld::Ptr &old, const MWWorld::Ptr &updated) + void SoundManager::updatePtr(const MWWorld::ConstPtr &old, const MWWorld::ConstPtr &updated) { SoundMap::iterator snditer = mActiveSounds.find(old); if(snditer != mActiveSounds.end()) diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index 7058c55b6..695ca92a2 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -81,15 +81,15 @@ namespace MWSound typedef std::pair SoundBufferRefPair; typedef std::vector SoundBufferRefPairList; - typedef std::map SoundMap; + typedef std::map SoundMap; SoundMap mActiveSounds; typedef std::pair SoundLoudnessPair; - typedef std::map SaySoundMap; + typedef std::map SaySoundMap; SaySoundMap mActiveSaySounds; typedef std::pair DecoderLoudnessPair; - typedef std::map SayDecoderMap; + typedef std::map SayDecoderMap; SayDecoderMap mPendingSaySounds; typedef std::vector TrackList; @@ -154,7 +154,7 @@ namespace MWSound ///< Start playing music from the selected folder /// \param name of the folder that contains the playlist - virtual void say(const MWWorld::Ptr &reference, const std::string& filename); + virtual void say(const MWWorld::ConstPtr &reference, const std::string& filename); ///< Make an actor say some text. /// \param filename name of a sound file in "Sound/" in the data directory. @@ -162,13 +162,13 @@ namespace MWSound ///< Say some text, without an actor ref /// \param filename name of a sound file in "Sound/" in the data directory. - virtual bool sayDone(const MWWorld::Ptr &reference=MWWorld::Ptr()) const; + virtual bool sayDone(const MWWorld::ConstPtr &reference=MWWorld::ConstPtr()) const; ///< Is actor not speaking? - virtual void stopSay(const MWWorld::Ptr &reference=MWWorld::Ptr()); + virtual void stopSay(const MWWorld::ConstPtr &reference=MWWorld::ConstPtr()); ///< Stop an actor speaking - virtual float getSaySoundLoudness(const MWWorld::Ptr& reference) const; + virtual float getSaySoundLoudness(const MWWorld::ConstPtr& reference) const; ///< Check the currently playing say sound for this actor /// and get an average loudness value (scale [0,1]) at the current time position. /// If the actor is not saying anything, returns 0. @@ -188,7 +188,7 @@ namespace MWSound ///< Play a sound, independently of 3D-position ///< @param offset Number of seconds into the sound to start playback. - virtual MWBase::SoundPtr playSound3D(const MWWorld::Ptr &reference, const std::string& soundId, + virtual MWBase::SoundPtr playSound3D(const MWWorld::ConstPtr &reference, const std::string& soundId, float volume, float pitch, PlayType type=Play_TypeSfx, PlayMode mode=Play_Normal, float offset=0); ///< Play a 3D sound attached to an MWWorld::Ptr. Will be updated automatically with the Ptr's position, unless Play_NoTrack is specified. @@ -203,10 +203,10 @@ namespace MWSound ///< Stop the given sound from playing /// @note no-op if \a sound is null - virtual void stopSound3D(const MWWorld::Ptr &reference, const std::string& soundId); + virtual void stopSound3D(const MWWorld::ConstPtr &reference, const std::string& soundId); ///< Stop the given object from playing the given sound, - virtual void stopSound3D(const MWWorld::Ptr &reference); + virtual void stopSound3D(const MWWorld::ConstPtr &reference); ///< Stop the given object from playing all sounds. virtual void stopSound(const MWWorld::CellStore *cell); @@ -215,13 +215,13 @@ namespace MWSound virtual void stopSound(const std::string& soundId); ///< Stop a non-3d looping sound - virtual void fadeOutSound3D(const MWWorld::Ptr &reference, const std::string& soundId, float duration); + virtual void fadeOutSound3D(const MWWorld::ConstPtr &reference, const std::string& soundId, float duration); ///< Fade out given sound (that is already playing) of given object ///< @param reference Reference to object, whose sound is faded out ///< @param soundId ID of the sound to fade out. ///< @param duration Time until volume reaches 0. - virtual bool getSoundPlaying(const MWWorld::Ptr &reference, const std::string& soundId) const; + virtual bool getSoundPlaying(const MWWorld::ConstPtr &reference, const std::string& soundId) const; ///< Is the given sound currently playing on the given object? virtual void pauseSounds(int types=Play_TypeMask); @@ -234,7 +234,7 @@ namespace MWSound virtual void setListenerPosDir(const osg::Vec3f &pos, const osg::Vec3f &dir, const osg::Vec3f &up, bool underwater); - virtual void updatePtr (const MWWorld::Ptr& old, const MWWorld::Ptr& updated); + virtual void updatePtr (const MWWorld::ConstPtr& old, const MWWorld::ConstPtr& updated); virtual void clear(); }; From 2c51e7345fb77f44ed72541c817cfbd72dd29936 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 18:32:42 +0100 Subject: [PATCH 2900/3725] Use a separate collision type for doors (Fixes #1962) --- apps/openmw/mwclass/door.cpp | 2 +- apps/openmw/mwphysics/actor.cpp | 2 +- apps/openmw/mwphysics/collisiontype.hpp | 5 +++-- apps/openmw/mwphysics/physicssystem.cpp | 8 ++++---- apps/openmw/mwphysics/physicssystem.hpp | 6 +++--- apps/openmw/mwworld/worldimp.cpp | 6 +++--- 6 files changed, 15 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index e007d3448..3d2719c58 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -58,7 +58,7 @@ namespace MWClass void Door::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const { if(!model.empty()) - physics.addObject(ptr, model); + physics.addObject(ptr, model, MWPhysics::CollisionType_Door); // Resume the door's opening/closing animation if it wasn't finished if (ptr.getRefData().getCustomData()) diff --git a/apps/openmw/mwphysics/actor.cpp b/apps/openmw/mwphysics/actor.cpp index 8438f26a3..cc46897d1 100644 --- a/apps/openmw/mwphysics/actor.cpp +++ b/apps/openmw/mwphysics/actor.cpp @@ -76,7 +76,7 @@ void Actor::updateCollisionMask() mCollisionWorld->removeCollisionObject(mCollisionObject.get()); int collisionMask = CollisionType_World | CollisionType_HeightMap; if (mExternalCollisionMode) - collisionMask |= CollisionType_Actor | CollisionType_Projectile; + collisionMask |= CollisionType_Actor | CollisionType_Projectile | CollisionType_Door; if (mCanWaterWalk) collisionMask |= CollisionType_Water; mCollisionWorld->addCollisionObject(mCollisionObject.get(), CollisionType_Actor, collisionMask); diff --git a/apps/openmw/mwphysics/collisiontype.hpp b/apps/openmw/mwphysics/collisiontype.hpp index 0f083ab35..0d6a32fc0 100644 --- a/apps/openmw/mwphysics/collisiontype.hpp +++ b/apps/openmw/mwphysics/collisiontype.hpp @@ -6,8 +6,9 @@ namespace MWPhysics enum CollisionType { CollisionType_World = 1<<0, - CollisionType_Actor = 1<<1, - CollisionType_HeightMap = 1<<2, + CollisionType_Door = 1<<1, + CollisionType_Actor = 1<<2, + CollisionType_HeightMap = 1<<3, CollisionType_Projectile = 1<<4, CollisionType_Water = 1<<5 }; diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 39e212c0b..8806641d3 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -857,7 +857,7 @@ namespace MWPhysics const btCollisionObject* mMe; }; - PhysicsSystem::RayResult PhysicsSystem::castRay(const osg::Vec3f &from, const osg::Vec3f &to, MWWorld::Ptr ignore, int mask, int group) const + PhysicsSystem::RayResult PhysicsSystem::castRay(const osg::Vec3f &from, const osg::Vec3f &to, MWWorld::ConstPtr ignore, int mask, int group) const { btVector3 btFrom = toBullet(from); btVector3 btTo = toBullet(to); @@ -923,7 +923,7 @@ namespace MWPhysics osg::Vec3f pos1 (physactor1->getPosition() + osg::Vec3f(0,0,physactor1->getHalfExtents().z() * 0.8)); // eye level osg::Vec3f pos2 (physactor2->getPosition() + osg::Vec3f(0,0,physactor2->getHalfExtents().z() * 0.8)); - RayResult result = castRay(pos1, pos2, MWWorld::Ptr(), CollisionType_World|CollisionType_HeightMap); + RayResult result = castRay(pos1, pos2, MWWorld::Ptr(), CollisionType_World|CollisionType_HeightMap|CollisionType_Door); return !result.mHit; } @@ -1073,7 +1073,7 @@ namespace MWPhysics } } - void PhysicsSystem::addObject (const MWWorld::Ptr& ptr, const std::string& mesh) + void PhysicsSystem::addObject (const MWWorld::Ptr& ptr, const std::string& mesh, int collisionType) { osg::ref_ptr shapeInstance = mShapeManager->createInstance(mesh); if (!shapeInstance || !shapeInstance->getCollisionShape()) @@ -1085,7 +1085,7 @@ namespace MWPhysics if (obj->isAnimated()) mAnimatedObjects.insert(obj); - mCollisionWorld->addCollisionObject(obj->getCollisionObject(), CollisionType_World, + mCollisionWorld->addCollisionObject(obj->getCollisionObject(), collisionType, CollisionType_Actor|CollisionType_HeightMap|CollisionType_Projectile); } diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index 09a76e208..f53d7e3d9 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -57,7 +57,7 @@ namespace MWPhysics void setWaterHeight(float height); void disableWater(); - void addObject (const MWWorld::Ptr& ptr, const std::string& mesh); + void addObject (const MWWorld::Ptr& ptr, const std::string& mesh, int collisionType = CollisionType_World); void addActor (const MWWorld::Ptr& ptr, const std::string& mesh); void updatePtr (const MWWorld::Ptr& old, const MWWorld::Ptr& updated); @@ -106,8 +106,8 @@ namespace MWPhysics }; /// @param me Optional, a Ptr to ignore in the list of results - RayResult castRay(const osg::Vec3f &from, const osg::Vec3f &to, MWWorld::Ptr ignore = MWWorld::Ptr(), int mask = - CollisionType_World|CollisionType_HeightMap|CollisionType_Actor, int group=0xff) const; + RayResult castRay(const osg::Vec3f &from, const osg::Vec3f &to, MWWorld::ConstPtr ignore = MWWorld::ConstPtr(), int mask = + CollisionType_World|CollisionType_HeightMap|CollisionType_Actor|CollisionType_Door, int group=0xff) const; RayResult castSphere(const osg::Vec3f& from, const osg::Vec3f& to, float radius); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 821f950dd..0449bfbda 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1380,7 +1380,7 @@ namespace MWWorld { osg::Vec3f a(x1,y1,z1); osg::Vec3f b(x2,y2,z2); - MWPhysics::PhysicsSystem::RayResult result = mPhysics->castRay(a, b, MWWorld::Ptr(), MWPhysics::CollisionType_World); + MWPhysics::PhysicsSystem::RayResult result = mPhysics->castRay(a, b, MWWorld::Ptr(), MWPhysics::CollisionType_World|MWPhysics::CollisionType_Door); return result.mHit; } @@ -1413,7 +1413,7 @@ namespace MWWorld bool reached = (targetRot == maxRot && it->second) || targetRot == minRot; /// \todo should use convexSweepTest here - std::vector collisions = mPhysics->getCollisions(it->first, MWPhysics::CollisionType_Actor, MWPhysics::CollisionType_Actor); + std::vector collisions = mPhysics->getCollisions(it->first, MWPhysics::CollisionType_Door, MWPhysics::CollisionType_Actor); for (std::vector::iterator cit = collisions.begin(); cit != collisions.end(); ++cit) { MWWorld::Ptr ptr = *cit; @@ -2334,7 +2334,7 @@ namespace MWWorld to = from + (to * maxDist); MWPhysics::PhysicsSystem::RayResult result = mPhysics->castRay(from, to, MWWorld::Ptr(), - MWPhysics::CollisionType_World|MWPhysics::CollisionType_HeightMap); + MWPhysics::CollisionType_World|MWPhysics::CollisionType_HeightMap|MWPhysics::CollisionType_Door); if (!result.mHit) return maxDist; From 53f4b92426ec8ea89175ab7be2b907c111d4b9f4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 19 Dec 2015 15:11:07 +0100 Subject: [PATCH 2901/3725] AiEscort do not follow target through doors Testing revealed a problem where the guard on the prison ship would incorrectly follow the player outside. Upon further investigation in vanilla MW, it appears that with AiEscort the actor only follows the target through doors once the AiEscort package has completed, *and* no new AI package is running yet. --- apps/openmw/mwbase/mechanicsmanager.hpp | 1 + apps/openmw/mwmechanics/actors.cpp | 22 +++++++++++++++++++ apps/openmw/mwmechanics/actors.hpp | 1 + apps/openmw/mwmechanics/aifollow.hpp | 1 + apps/openmw/mwmechanics/aipackage.cpp | 5 +++++ apps/openmw/mwmechanics/aipackage.hpp | 3 +++ .../mwmechanics/mechanicsmanagerimp.cpp | 5 +++++ .../mwmechanics/mechanicsmanagerimp.hpp | 1 + apps/openmw/mwworld/actionteleport.cpp | 2 +- 9 files changed, 40 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index 7cfc0861c..31afc126a 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -187,6 +187,7 @@ namespace MWBase ///Returns the list of actors which are siding with the given actor in fights /**ie AiFollow or AiEscort is active and the target is the actor **/ virtual std::list getActorsSidingWith(const MWWorld::Ptr& actor) = 0; + virtual std::list getActorsFollowing(const MWWorld::Ptr& actor) = 0; virtual std::list getActorsFollowingIndices(const MWWorld::Ptr& actor) = 0; ///Returns a list of actors who are fighting the given actor within the fAlarmDistance diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index ee114dff2..7f857a700 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1327,6 +1327,28 @@ namespace MWMechanics return list; } + std::list Actors::getActorsFollowing(const MWWorld::Ptr& actor) + { + std::list list; + for(PtrActorMap::iterator iter(mActors.begin());iter != mActors.end();++iter) + { + const MWWorld::Class &cls = iter->first.getClass(); + CreatureStats &stats = cls.getCreatureStats(iter->first); + if (stats.isDead()) + continue; + + // An actor counts as following if AiFollow is the current AiPackage, or there are only Combat packages before the AiFollow package + for (std::list::const_iterator it = stats.getAiSequence().begin(); it != stats.getAiSequence().end(); ++it) + { + if ((*it)->followTargetThroughDoors() && (*it)->getTarget() == actor) + list.push_back(iter->first); + else if ((*it)->getTypeId() != MWMechanics::AiPackage::TypeIdCombat) + break; + } + } + return list; + } + std::list Actors::getActorsFollowingIndices(const MWWorld::Ptr &actor) { std::list list; diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index 494216ba8..0bdf611d2 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -114,6 +114,7 @@ namespace MWMechanics ///Returns the list of actors which are siding with the given actor in fights /**ie AiFollow or AiEscort is active and the target is the actor **/ std::list getActorsSidingWith(const MWWorld::Ptr& actor); + std::list getActorsFollowing(const MWWorld::Ptr& actor); /// Get the list of AiFollow::mFollowIndex for all actors following this target std::list getActorsFollowingIndices(const MWWorld::Ptr& actor); diff --git a/apps/openmw/mwmechanics/aifollow.hpp b/apps/openmw/mwmechanics/aifollow.hpp index 97140a63a..017ea7122 100644 --- a/apps/openmw/mwmechanics/aifollow.hpp +++ b/apps/openmw/mwmechanics/aifollow.hpp @@ -33,6 +33,7 @@ namespace MWMechanics MWWorld::Ptr getTarget(); virtual bool sideWithTarget() const { return true; } + virtual bool followTargetThroughDoors() const { return true; } virtual AiFollow *clone() const; diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index fef10b730..cb2b002f6 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -30,6 +30,11 @@ bool MWMechanics::AiPackage::sideWithTarget() const return false; } +bool MWMechanics::AiPackage::followTargetThroughDoors() const +{ + return false; +} + MWMechanics::AiPackage::AiPackage() : mTimer(0.26f) { //mTimer starts at .26 to force initial pathbuild } diff --git a/apps/openmw/mwmechanics/aipackage.hpp b/apps/openmw/mwmechanics/aipackage.hpp index 4b760e4c9..76f89dff4 100644 --- a/apps/openmw/mwmechanics/aipackage.hpp +++ b/apps/openmw/mwmechanics/aipackage.hpp @@ -75,6 +75,9 @@ namespace MWMechanics /// Return true if having this AiPackage makes the actor side with the target in fights (default false) virtual bool sideWithTarget() const; + /// Return true if the actor should follow the target through teleport doors (default false) + virtual bool followTargetThroughDoors() const; + bool isTargetMagicallyHidden(const MWWorld::Ptr& target); protected: diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 21039cc65..9dafebffa 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1492,6 +1492,11 @@ namespace MWMechanics return mActors.getActorsSidingWith(actor); } + std::list MechanicsManager::getActorsFollowing(const MWWorld::Ptr& actor) + { + return mActors.getActorsFollowing(actor); + } + std::list MechanicsManager::getActorsFollowingIndices(const MWWorld::Ptr& actor) { return mActors.getActorsFollowingIndices(actor); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index 279adeeed..603888adc 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -151,6 +151,7 @@ namespace MWMechanics virtual void getActorsInRange(const osg::Vec3f &position, float radius, std::vector &objects); virtual std::list getActorsSidingWith(const MWWorld::Ptr& actor); + virtual std::list getActorsFollowing(const MWWorld::Ptr& actor); virtual std::list getActorsFollowingIndices(const MWWorld::Ptr& actor); virtual std::list getActorsFighting(const MWWorld::Ptr& actor); diff --git a/apps/openmw/mwworld/actionteleport.cpp b/apps/openmw/mwworld/actionteleport.cpp index bcb1fc6d4..031f07258 100644 --- a/apps/openmw/mwworld/actionteleport.cpp +++ b/apps/openmw/mwworld/actionteleport.cpp @@ -13,7 +13,7 @@ namespace void getFollowers (const MWWorld::Ptr& actor, std::set& out) { - std::list followers = MWBase::Environment::get().getMechanicsManager()->getActorsSidingWith(actor); + std::list followers = MWBase::Environment::get().getMechanicsManager()->getActorsFollowing(actor); for(std::list::iterator it = followers.begin();it != followers.end();++it) { if (out.insert(*it).second) From 7a2ca5580a40ef5760336652d0c664ae0084f75f Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 19 Dec 2015 15:50:13 +0100 Subject: [PATCH 2902/3725] Accept a ConstPtr in RippleSimulation --- apps/openmw/mwclass/armor.hpp | 2 +- apps/openmw/mwclass/clothing.hpp | 2 +- apps/openmw/mwrender/ripplesimulation.cpp | 6 +++--- apps/openmw/mwrender/ripplesimulation.hpp | 8 ++++---- apps/openmw/mwstate/statemanagerimp.cpp | 4 ++-- apps/openmw/mwworld/class.hpp | 2 +- apps/openmw/mwworld/weather.cpp | 4 ++-- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index 0fdfa566d..dc8f4f247 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -40,7 +40,7 @@ namespace MWClass /// stay stacked when equipped? virtual int getEquipmentSkill (const MWWorld::ConstPtr& ptr) const; - /// Return the index of the skill this item corresponds to when equiopped or -1, if there is + /// Return the index of the skill this item corresponds to when equipped or -1, if there is /// no such skill. virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index cbdc6295d..096f9e0cb 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -32,7 +32,7 @@ namespace MWClass /// stay stacked when equipped? virtual int getEquipmentSkill (const MWWorld::ConstPtr& ptr) const; - /// Return the index of the skill this item corresponds to when equiopped or -1, if there is + /// Return the index of the skill this item corresponds to when equipped or -1, if there is /// no such skill. virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwrender/ripplesimulation.cpp b/apps/openmw/mwrender/ripplesimulation.cpp index 7439bfc70..f232ea475 100644 --- a/apps/openmw/mwrender/ripplesimulation.cpp +++ b/apps/openmw/mwrender/ripplesimulation.cpp @@ -146,7 +146,7 @@ void RippleSimulation::update(float dt) } -void RippleSimulation::addEmitter(const MWWorld::Ptr& ptr, float scale, float force) +void RippleSimulation::addEmitter(const MWWorld::ConstPtr& ptr, float scale, float force) { Emitter newEmitter; newEmitter.mPtr = ptr; @@ -156,7 +156,7 @@ void RippleSimulation::addEmitter(const MWWorld::Ptr& ptr, float scale, float fo mEmitters.push_back (newEmitter); } -void RippleSimulation::removeEmitter (const MWWorld::Ptr& ptr) +void RippleSimulation::removeEmitter (const MWWorld::ConstPtr& ptr) { for (std::vector::iterator it = mEmitters.begin(); it != mEmitters.end(); ++it) { @@ -168,7 +168,7 @@ void RippleSimulation::removeEmitter (const MWWorld::Ptr& ptr) } } -void RippleSimulation::updateEmitterPtr (const MWWorld::Ptr& old, const MWWorld::Ptr& ptr) +void RippleSimulation::updateEmitterPtr (const MWWorld::ConstPtr& old, const MWWorld::ConstPtr& ptr) { for (std::vector::iterator it = mEmitters.begin(); it != mEmitters.end(); ++it) { diff --git a/apps/openmw/mwrender/ripplesimulation.hpp b/apps/openmw/mwrender/ripplesimulation.hpp index 7d412f454..a4e12f275 100644 --- a/apps/openmw/mwrender/ripplesimulation.hpp +++ b/apps/openmw/mwrender/ripplesimulation.hpp @@ -31,7 +31,7 @@ namespace MWRender struct Emitter { - MWWorld::Ptr mPtr; + MWWorld::ConstPtr mPtr; osg::Vec3f mLastEmitPosition; float mScale; float mForce; @@ -47,9 +47,9 @@ namespace MWRender void update(float dt); /// adds an emitter, position will be tracked automatically - void addEmitter (const MWWorld::Ptr& ptr, float scale = 1.f, float force = 1.f); - void removeEmitter (const MWWorld::Ptr& ptr); - void updateEmitterPtr (const MWWorld::Ptr& old, const MWWorld::Ptr& ptr); + void addEmitter (const MWWorld::ConstPtr& ptr, float scale = 1.f, float force = 1.f); + void removeEmitter (const MWWorld::ConstPtr& ptr); + void updateEmitterPtr (const MWWorld::ConstPtr& old, const MWWorld::ConstPtr& ptr); void removeCell(const MWWorld::CellStore* store); void emitRipple(const osg::Vec3f& pos); diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 9931cf967..89d31c485 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -482,7 +482,7 @@ void MWState::StateManager::loadGame (const Character *character, const std::str if (firstPersonCam != MWBase::Environment::get().getWorld()->isFirstPerson()) MWBase::Environment::get().getWorld()->togglePOV(); - MWWorld::Ptr ptr = MWMechanics::getPlayer(); + MWWorld::ConstPtr ptr = MWMechanics::getPlayer(); const ESM::CellId& cellId = ptr.getCell()->getCell()->getCellId(); @@ -529,7 +529,7 @@ void MWState::StateManager::deleteGame(const MWState::Character *character, cons MWState::Character *MWState::StateManager::getCurrentCharacter (bool create) { - MWWorld::Ptr player = MWMechanics::getPlayer(); + MWWorld::ConstPtr player = MWMechanics::getPlayer(); std::string name = player.get()->mBase->mName; return mCharacterManager.getCurrentCharacter (create, name); diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 33d7e26c8..deee0f154 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -189,7 +189,7 @@ namespace MWWorld virtual int getEquipmentSkill (const ConstPtr& ptr) const; - /// Return the index of the skill this item corresponds to when equiopped or -1, if there is + /// Return the index of the skill this item corresponds to when equipped or -1, if there is /// no such skill. /// (default implementation: return -1) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 9a93f3827..5ce3d5c2f 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -623,7 +623,7 @@ void WeatherManager::playerTeleported() void WeatherManager::update(float duration, bool paused) { - MWWorld::Ptr player = MWMechanics::getPlayer(); + MWWorld::ConstPtr player = MWMechanics::getPlayer(); MWBase::World& world = *MWBase::Environment::get().getWorld(); TimeStamp time = world.getTimeStamp(); @@ -885,7 +885,7 @@ inline void WeatherManager::importRegions() inline void WeatherManager::regionalWeatherChanged(const std::string& regionID, RegionWeather& region) { // If the region is current, then add a weather transition for it. - MWWorld::Ptr player = MWMechanics::getPlayer(); + MWWorld::ConstPtr player = MWMechanics::getPlayer(); if(player.isInCell()) { std::string playerRegion = Misc::StringUtils::lowerCase(player.getCell()->getCell()->mRegion); From 51c77c5045566af4ba9e9d8dca5426ed79ca4d00 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 19 Dec 2015 15:57:37 +0100 Subject: [PATCH 2903/3725] Accept a ConstPtr in getDoorState --- apps/openmw/mwclass/door.cpp | 9 +++++++-- apps/openmw/mwclass/door.hpp | 2 +- apps/openmw/mwmechanics/aiavoiddoor.cpp | 2 +- apps/openmw/mwmechanics/aiavoiddoor.hpp | 4 ++-- apps/openmw/mwworld/class.cpp | 2 +- apps/openmw/mwworld/class.hpp | 2 +- apps/openmw/mwworld/customdata.cpp | 7 +++++++ apps/openmw/mwworld/customdata.hpp | 1 + 8 files changed, 21 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 3d2719c58..58c33ba95 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -41,6 +41,10 @@ namespace MWClass { return *this; } + virtual const DoorCustomData& asDoorCustomData() const + { + return *this; + } }; MWWorld::CustomData *DoorCustomData::clone() const @@ -312,9 +316,10 @@ namespace MWClass } } - int Door::getDoorState (const MWWorld::Ptr &ptr) const + int Door::getDoorState (const MWWorld::ConstPtr &ptr) const { - ensureCustomData(ptr); + if (!ptr.getRefData().getCustomData()) + return 0; const DoorCustomData& customData = ptr.getRefData().getCustomData()->asDoorCustomData(); return customData.mDoorState; } diff --git a/apps/openmw/mwclass/door.hpp b/apps/openmw/mwclass/door.hpp index ff94cd613..74ab11fd9 100644 --- a/apps/openmw/mwclass/door.hpp +++ b/apps/openmw/mwclass/door.hpp @@ -53,7 +53,7 @@ namespace MWClass virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; /// 0 = nothing, 1 = opening, 2 = closing - virtual int getDoorState (const MWWorld::Ptr &ptr) const; + virtual int getDoorState (const MWWorld::ConstPtr &ptr) const; /// This does not actually cause the door to move. Use World::activateDoor instead. virtual void setDoorState (const MWWorld::Ptr &ptr, int state) const; diff --git a/apps/openmw/mwmechanics/aiavoiddoor.cpp b/apps/openmw/mwmechanics/aiavoiddoor.cpp index 409f7b9c4..100b666e8 100644 --- a/apps/openmw/mwmechanics/aiavoiddoor.cpp +++ b/apps/openmw/mwmechanics/aiavoiddoor.cpp @@ -11,7 +11,7 @@ #include "steering.hpp" -MWMechanics::AiAvoidDoor::AiAvoidDoor(const MWWorld::Ptr& doorPtr) +MWMechanics::AiAvoidDoor::AiAvoidDoor(const MWWorld::ConstPtr& doorPtr) : AiPackage(), mDuration(1), mDoorPtr(doorPtr), mAdjAngle(0) { diff --git a/apps/openmw/mwmechanics/aiavoiddoor.hpp b/apps/openmw/mwmechanics/aiavoiddoor.hpp index 1ad945bca..9d63c63e0 100644 --- a/apps/openmw/mwmechanics/aiavoiddoor.hpp +++ b/apps/openmw/mwmechanics/aiavoiddoor.hpp @@ -16,7 +16,7 @@ namespace MWMechanics { public: /// Avoid door until the door is fully open - AiAvoidDoor(const MWWorld::Ptr& doorPtr); + AiAvoidDoor(const MWWorld::ConstPtr& doorPtr); virtual AiAvoidDoor *clone() const; @@ -28,7 +28,7 @@ namespace MWMechanics private: float mDuration; - MWWorld::Ptr mDoorPtr; + MWWorld::ConstPtr mDoorPtr; ESM::Position mLastPos; float mAdjAngle; }; diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 118bfe018..397762df8 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -404,7 +404,7 @@ namespace MWWorld return false; } - int Class::getDoorState (const MWWorld::Ptr &ptr) const + int Class::getDoorState (const MWWorld::ConstPtr &ptr) const { throw std::runtime_error("this is not a door"); } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index deee0f154..2ef0ba2d4 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -319,7 +319,7 @@ namespace MWWorld virtual bool isClass(const MWWorld::ConstPtr& ptr, const std::string &className) const; /// 0 = nothing, 1 = opening, 2 = closing - virtual int getDoorState (const MWWorld::Ptr &ptr) const; + virtual int getDoorState (const MWWorld::ConstPtr &ptr) const; /// This does not actually cause the door to move. Use World::activateDoor instead. virtual void setDoorState (const MWWorld::Ptr &ptr, int state) const; diff --git a/apps/openmw/mwworld/customdata.cpp b/apps/openmw/mwworld/customdata.cpp index dce1e9fdd..6f9fb39a7 100644 --- a/apps/openmw/mwworld/customdata.cpp +++ b/apps/openmw/mwworld/customdata.cpp @@ -42,6 +42,13 @@ MWClass::DoorCustomData &CustomData::asDoorCustomData() throw std::logic_error(error.str()); } +const MWClass::DoorCustomData &CustomData::asDoorCustomData() const +{ + std::stringstream error; + error << "bad cast " << typeid(this).name() << " to DoorCustomData"; + throw std::logic_error(error.str()); +} + MWClass::CreatureLevListCustomData &CustomData::asCreatureLevListCustomData() { std::stringstream error; diff --git a/apps/openmw/mwworld/customdata.hpp b/apps/openmw/mwworld/customdata.hpp index 407962ee0..4ca16fd32 100644 --- a/apps/openmw/mwworld/customdata.hpp +++ b/apps/openmw/mwworld/customdata.hpp @@ -31,6 +31,7 @@ namespace MWWorld virtual MWClass::ContainerCustomData& asContainerCustomData(); virtual MWClass::DoorCustomData& asDoorCustomData(); + virtual const MWClass::DoorCustomData& asDoorCustomData() const; virtual MWClass::CreatureLevListCustomData& asCreatureLevListCustomData(); }; From 29d0f448b4ba8315677b72a609cf6c9b38386606 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 19 Dec 2015 16:02:47 +0100 Subject: [PATCH 2904/3725] Add const version of World::getAnimation --- apps/openmw/mwbase/world.hpp | 1 + apps/openmw/mwmechanics/character.cpp | 4 ++-- apps/openmw/mwmechanics/character.hpp | 4 ++-- apps/openmw/mwworld/worldimp.cpp | 5 +++++ apps/openmw/mwworld/worldimp.hpp | 1 + 5 files changed, 11 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index fd8a10af8..5ae21022c 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -430,6 +430,7 @@ namespace MWBase /// \todo Probably shouldn't be here virtual MWRender::Animation* getAnimation(const MWWorld::Ptr &ptr) = 0; + virtual const MWRender::Animation* getAnimation(const MWWorld::ConstPtr &ptr) const = 0; virtual void reattachPlayerCamera() = 0; /// \todo this does not belong here diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 10c20e65d..ba6a8fe4b 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -2114,7 +2114,7 @@ void CharacterController::setActive(bool active) mAnimation->setActive(active); } -void CharacterController::setHeadTrackTarget(const MWWorld::Ptr &target) +void CharacterController::setHeadTrackTarget(const MWWorld::ConstPtr &target) { mHeadTrackTarget = target; } @@ -2137,7 +2137,7 @@ void CharacterController::updateHeadTracking(float duration) osg::Vec3f headPos = mat.getTrans(); osg::Vec3f direction; - if (MWRender::Animation* anim = MWBase::Environment::get().getWorld()->getAnimation(mHeadTrackTarget)) + if (const MWRender::Animation* anim = MWBase::Environment::get().getWorld()->getAnimation(mHeadTrackTarget)) { const osg::Node* node = anim->getNode("Head"); if (node == NULL) diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 90e285b52..5e43bc2b7 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -180,7 +180,7 @@ class CharacterController : public MWRender::Animation::TextKeyListener float mSecondsOfSwimming; float mSecondsOfRunning; - MWWorld::Ptr mHeadTrackTarget; + MWWorld::ConstPtr mHeadTrackTarget; float mTurnAnimationThreshold; // how long to continue playing turning animation after actor stopped turning @@ -255,7 +255,7 @@ public: void setActive(bool active); /// Make this character turn its head towards \a target. To turn off head tracking, pass an empty Ptr. - void setHeadTrackTarget(const MWWorld::Ptr& target); + void setHeadTrackTarget(const MWWorld::ConstPtr& target); }; MWWorld::ContainerStoreIterator getActiveWeapon(CreatureStats &stats, MWWorld::InventoryStore &inv, WeaponType *weaptype); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 0449bfbda..f403a6faa 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2112,6 +2112,11 @@ namespace MWWorld return mRendering->getAnimation(ptr); } + const MWRender::Animation* World::getAnimation(const MWWorld::ConstPtr &ptr) const + { + return mRendering->getAnimation(ptr); + } + void World::screenshot(osg::Image* image, int w, int h) { mRendering->screenshot(image, w, h); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 51056c429..2af6a970f 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -534,6 +534,7 @@ namespace MWWorld /// \todo Probably shouldn't be here virtual MWRender::Animation* getAnimation(const MWWorld::Ptr &ptr); + virtual const MWRender::Animation* getAnimation(const MWWorld::ConstPtr &ptr) const; virtual void reattachPlayerCamera(); /// \todo this does not belong here From b0894ea20dc7e1fc05bd5d542df5925e356473ea Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 19 Dec 2015 16:13:00 +0100 Subject: [PATCH 2905/3725] Accept a ConstPtr in hasToolTip --- apps/openmw/mwclass/activator.cpp | 5 ++--- apps/openmw/mwclass/activator.hpp | 2 +- apps/openmw/mwclass/actor.cpp | 5 ----- apps/openmw/mwclass/actor.hpp | 3 --- apps/openmw/mwclass/apparatus.cpp | 5 ++--- apps/openmw/mwclass/apparatus.hpp | 2 +- apps/openmw/mwclass/armor.cpp | 5 ++--- apps/openmw/mwclass/armor.hpp | 2 +- apps/openmw/mwclass/book.cpp | 5 ++--- apps/openmw/mwclass/book.hpp | 2 +- apps/openmw/mwclass/clothing.cpp | 5 ++--- apps/openmw/mwclass/clothing.hpp | 2 +- apps/openmw/mwclass/container.cpp | 5 ++--- apps/openmw/mwclass/container.hpp | 2 +- apps/openmw/mwclass/creature.cpp | 13 +++++++++++++ apps/openmw/mwclass/creature.hpp | 3 +++ apps/openmw/mwclass/door.cpp | 5 ++--- apps/openmw/mwclass/door.hpp | 2 +- apps/openmw/mwclass/ingredient.cpp | 5 ++--- apps/openmw/mwclass/ingredient.hpp | 2 +- apps/openmw/mwclass/light.cpp | 5 ++--- apps/openmw/mwclass/light.hpp | 2 +- apps/openmw/mwclass/lockpick.cpp | 5 ++--- apps/openmw/mwclass/lockpick.hpp | 2 +- apps/openmw/mwclass/misc.cpp | 5 ++--- apps/openmw/mwclass/misc.hpp | 2 +- apps/openmw/mwclass/npc.cpp | 9 +++++++++ apps/openmw/mwclass/npc.hpp | 3 +++ apps/openmw/mwclass/potion.cpp | 5 ++--- apps/openmw/mwclass/potion.hpp | 2 +- apps/openmw/mwclass/probe.cpp | 5 ++--- apps/openmw/mwclass/probe.hpp | 2 +- apps/openmw/mwclass/repair.cpp | 5 ++--- apps/openmw/mwclass/repair.hpp | 2 +- apps/openmw/mwclass/weapon.cpp | 8 +++----- apps/openmw/mwclass/weapon.hpp | 2 +- apps/openmw/mwworld/class.cpp | 2 +- apps/openmw/mwworld/class.hpp | 2 +- apps/openmw/mwworld/customdata.cpp | 7 +++++++ apps/openmw/mwworld/customdata.hpp | 1 + 40 files changed, 84 insertions(+), 72 deletions(-) diff --git a/apps/openmw/mwclass/activator.cpp b/apps/openmw/mwclass/activator.cpp index e6dc0b1fe..48d0a254d 100644 --- a/apps/openmw/mwclass/activator.cpp +++ b/apps/openmw/mwclass/activator.cpp @@ -74,10 +74,9 @@ namespace MWClass registerClass (typeid (ESM::Activator).name(), instance); } - bool Activator::hasToolTip (const MWWorld::Ptr& ptr) const + bool Activator::hasToolTip (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return (ref->mBase->mName != ""); } diff --git a/apps/openmw/mwclass/activator.hpp b/apps/openmw/mwclass/activator.hpp index d1e905881..3cc4a394c 100644 --- a/apps/openmw/mwclass/activator.hpp +++ b/apps/openmw/mwclass/activator.hpp @@ -21,7 +21,7 @@ namespace MWClass ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. - virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; + virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/actor.cpp b/apps/openmw/mwclass/actor.cpp index d58047d06..4e89c7282 100644 --- a/apps/openmw/mwclass/actor.cpp +++ b/apps/openmw/mwclass/actor.cpp @@ -61,11 +61,6 @@ namespace MWClass } } - bool Actor::hasToolTip(const MWWorld::Ptr& ptr) const - { - return !ptr.getClass().getCreatureStats(ptr).getAiSequence().isInCombat() || getCreatureStats(ptr).isDead(); - } - osg::Vec3f Actor::getRotationVector(const MWWorld::Ptr& ptr) const { MWMechanics::Movement &movement = getMovementSettings(ptr); diff --git a/apps/openmw/mwclass/actor.hpp b/apps/openmw/mwclass/actor.hpp index 3f795dff9..88a3f1a32 100644 --- a/apps/openmw/mwclass/actor.hpp +++ b/apps/openmw/mwclass/actor.hpp @@ -28,9 +28,6 @@ namespace MWClass virtual void block(const MWWorld::Ptr &ptr) const; - virtual bool hasToolTip(const MWWorld::Ptr& ptr) const; - ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual osg::Vec3f getRotationVector(const MWWorld::Ptr& ptr) const; ///< Return desired rotations, as euler angles. diff --git a/apps/openmw/mwclass/apparatus.cpp b/apps/openmw/mwclass/apparatus.cpp index 8dbd638c0..0c27be469 100644 --- a/apps/openmw/mwclass/apparatus.cpp +++ b/apps/openmw/mwclass/apparatus.cpp @@ -95,10 +95,9 @@ namespace MWClass return ref->mBase->mIcon; } - bool Apparatus::hasToolTip (const MWWorld::Ptr& ptr) const + bool Apparatus::hasToolTip (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return (ref->mBase->mName != ""); } diff --git a/apps/openmw/mwclass/apparatus.hpp b/apps/openmw/mwclass/apparatus.hpp index 676362975..3405dd850 100644 --- a/apps/openmw/mwclass/apparatus.hpp +++ b/apps/openmw/mwclass/apparatus.hpp @@ -33,7 +33,7 @@ namespace MWClass virtual int getValue (const MWWorld::ConstPtr& ptr) const; ///< Return trade value of the object. Throws an exception, if the object can't be traded. - virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; + virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index 07e4e2810..c06dcbb98 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -202,10 +202,9 @@ namespace MWClass return ref->mBase->mIcon; } - bool Armor::hasToolTip (const MWWorld::Ptr& ptr) const + bool Armor::hasToolTip (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return (ref->mBase->mName != ""); } diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index dc8f4f247..239d3613b 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -43,7 +43,7 @@ namespace MWClass /// Return the index of the skill this item corresponds to when equipped or -1, if there is /// no such skill. - virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; + virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index 8c37dadd7..c5881eb3b 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -109,10 +109,9 @@ namespace MWClass return ref->mBase->mIcon; } - bool Book::hasToolTip (const MWWorld::Ptr& ptr) const + bool Book::hasToolTip (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return (ref->mBase->mName != ""); } diff --git a/apps/openmw/mwclass/book.hpp b/apps/openmw/mwclass/book.hpp index a419c89fe..7d28fe4c6 100644 --- a/apps/openmw/mwclass/book.hpp +++ b/apps/openmw/mwclass/book.hpp @@ -27,7 +27,7 @@ namespace MWClass virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; ///< Return name of the script attached to ptr - virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; + virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index 6b64e84b0..f7762f6b5 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -158,10 +158,9 @@ namespace MWClass return ref->mBase->mIcon; } - bool Clothing::hasToolTip (const MWWorld::Ptr& ptr) const + bool Clothing::hasToolTip (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return (ref->mBase->mName != ""); } diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index 096f9e0cb..08ca5aa2e 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -35,7 +35,7 @@ namespace MWClass /// Return the index of the skill this item corresponds to when equipped or -1, if there is /// no such skill. - virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; + virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index bd5f18efd..5a66c4999 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -215,10 +215,9 @@ namespace MWClass registerClass (typeid (ESM::Container).name(), instance); } - bool Container::hasToolTip (const MWWorld::Ptr& ptr) const + bool Container::hasToolTip (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return (ref->mBase->mName != ""); } diff --git a/apps/openmw/mwclass/container.hpp b/apps/openmw/mwclass/container.hpp index d8aaab327..d378bdb25 100644 --- a/apps/openmw/mwclass/container.hpp +++ b/apps/openmw/mwclass/container.hpp @@ -27,7 +27,7 @@ namespace MWClass const MWWorld::Ptr& actor) const; ///< Generate action for activation - virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; + virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index bdd06b9f4..4b513a640 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -62,6 +62,10 @@ namespace MWClass { return *this; } + virtual const CreatureCustomData& asCreatureCustomData() const + { + return *this; + } CreatureCustomData() : mContainerStore(0) {} virtual ~CreatureCustomData() { delete mContainerStore; } @@ -510,6 +514,15 @@ namespace MWClass return ptr.getRefData().getCustomData()->asCreatureCustomData().mMovement; } + bool Creature::hasToolTip(const MWWorld::ConstPtr& ptr) const + { + if (!ptr.getRefData().getCustomData()) + return true; + + const CreatureCustomData& customData = ptr.getRefData().getCustomData()->asCreatureCustomData(); + return !customData.mCreatureStats.getAiSequence().isInCombat() || customData.mCreatureStats.isDead(); + } + MWGui::ToolTipInfo Creature::getToolTipInfo (const MWWorld::ConstPtr& ptr) const { const MWWorld::LiveCellRef *ref = ptr.get(); diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index 1647da01e..8b31f2edf 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -47,6 +47,9 @@ namespace MWClass ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. + virtual bool hasToolTip(const MWWorld::ConstPtr& ptr) const; + ///< @return true if this object has a tooltip when focused (default implementation: false) + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 58c33ba95..b8013177a 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -227,10 +227,9 @@ namespace MWClass registerClass (typeid (ESM::Door).name(), instance); } - bool Door::hasToolTip (const MWWorld::Ptr& ptr) const + bool Door::hasToolTip (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return (ref->mBase->mName != ""); } diff --git a/apps/openmw/mwclass/door.hpp b/apps/openmw/mwclass/door.hpp index 74ab11fd9..d11abedcd 100644 --- a/apps/openmw/mwclass/door.hpp +++ b/apps/openmw/mwclass/door.hpp @@ -28,7 +28,7 @@ namespace MWClass const MWWorld::Ptr& actor) const; ///< Generate action for activation - virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; + virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/ingredient.cpp b/apps/openmw/mwclass/ingredient.cpp index 5fbefcbe3..53316da4c 100644 --- a/apps/openmw/mwclass/ingredient.cpp +++ b/apps/openmw/mwclass/ingredient.cpp @@ -108,10 +108,9 @@ namespace MWClass return ref->mBase->mIcon; } - bool Ingredient::hasToolTip (const MWWorld::Ptr& ptr) const + bool Ingredient::hasToolTip (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return (ref->mBase->mName != ""); } diff --git a/apps/openmw/mwclass/ingredient.hpp b/apps/openmw/mwclass/ingredient.hpp index 42920f5fc..12d2ee3f0 100644 --- a/apps/openmw/mwclass/ingredient.hpp +++ b/apps/openmw/mwclass/ingredient.hpp @@ -24,7 +24,7 @@ namespace MWClass const MWWorld::Ptr& actor) const; ///< Generate action for activation - virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; + virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 6ff846152..2fab08154 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -140,10 +140,9 @@ namespace MWClass return ref->mBase->mIcon; } - bool Light::hasToolTip (const MWWorld::Ptr& ptr) const + bool Light::hasToolTip (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return (ref->mBase->mName != ""); } diff --git a/apps/openmw/mwclass/light.hpp b/apps/openmw/mwclass/light.hpp index c57a3afb9..ff934406e 100644 --- a/apps/openmw/mwclass/light.hpp +++ b/apps/openmw/mwclass/light.hpp @@ -20,7 +20,7 @@ namespace MWClass ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. - virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; + virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index 66edd7d81..908a3b2ad 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -105,10 +105,9 @@ namespace MWClass return ref->mBase->mIcon; } - bool Lockpick::hasToolTip (const MWWorld::Ptr& ptr) const + bool Lockpick::hasToolTip (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return (ref->mBase->mName != ""); } diff --git a/apps/openmw/mwclass/lockpick.hpp b/apps/openmw/mwclass/lockpick.hpp index 81d7c0c51..16e9caaa8 100644 --- a/apps/openmw/mwclass/lockpick.hpp +++ b/apps/openmw/mwclass/lockpick.hpp @@ -24,7 +24,7 @@ namespace MWClass const MWWorld::Ptr& actor) const; ///< Generate action for activation - virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; + virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index 00505067d..72041fd53 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -123,10 +123,9 @@ namespace MWClass return ref->mBase->mIcon; } - bool Miscellaneous::hasToolTip (const MWWorld::Ptr& ptr) const + bool Miscellaneous::hasToolTip (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return (ref->mBase->mName != ""); } diff --git a/apps/openmw/mwclass/misc.hpp b/apps/openmw/mwclass/misc.hpp index d2681ac72..9954c1f48 100644 --- a/apps/openmw/mwclass/misc.hpp +++ b/apps/openmw/mwclass/misc.hpp @@ -24,7 +24,7 @@ namespace MWClass const MWWorld::Ptr& actor) const; ///< Generate action for activation - virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; + virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index e3e3fd3c2..fc82b143a 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -913,6 +913,15 @@ namespace MWClass registerClass (typeid (ESM::NPC).name(), instance); } + bool Npc::hasToolTip(const MWWorld::ConstPtr& ptr) const + { + if (!ptr.getRefData().getCustomData()) + return true; + + const NpcCustomData& customData = ptr.getRefData().getCustomData()->asNpcCustomData(); + return !customData.mNpcStats.getAiSequence().isInCombat() || customData.mNpcStats.isDead(); + } + MWGui::ToolTipInfo Npc::getToolTipInfo (const MWWorld::ConstPtr& ptr) const { const MWWorld::LiveCellRef *ref = ptr.get(); diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index 88c4dfac9..fb358c73e 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -60,6 +60,9 @@ namespace MWClass virtual MWWorld::ContainerStore& getContainerStore (const MWWorld::Ptr& ptr) const; ///< Return container store + virtual bool hasToolTip(const MWWorld::ConstPtr& ptr) const; + ///< @return true if this object has a tooltip when focused (default implementation: false) + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. diff --git a/apps/openmw/mwclass/potion.cpp b/apps/openmw/mwclass/potion.cpp index 6ef035679..e10f7a9f8 100644 --- a/apps/openmw/mwclass/potion.cpp +++ b/apps/openmw/mwclass/potion.cpp @@ -100,10 +100,9 @@ namespace MWClass return ref->mBase->mIcon; } - bool Potion::hasToolTip (const MWWorld::Ptr& ptr) const + bool Potion::hasToolTip (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return (ref->mBase->mName != ""); } diff --git a/apps/openmw/mwclass/potion.hpp b/apps/openmw/mwclass/potion.hpp index 391a5093d..e17c55563 100644 --- a/apps/openmw/mwclass/potion.hpp +++ b/apps/openmw/mwclass/potion.hpp @@ -24,7 +24,7 @@ namespace MWClass const MWWorld::Ptr& actor) const; ///< Generate action for activation - virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; + virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index fdbf69811..113f500fd 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -105,10 +105,9 @@ namespace MWClass return ref->mBase->mIcon; } - bool Probe::hasToolTip (const MWWorld::Ptr& ptr) const + bool Probe::hasToolTip (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return (ref->mBase->mName != ""); } diff --git a/apps/openmw/mwclass/probe.hpp b/apps/openmw/mwclass/probe.hpp index 62eeb3016..fec44967d 100644 --- a/apps/openmw/mwclass/probe.hpp +++ b/apps/openmw/mwclass/probe.hpp @@ -24,7 +24,7 @@ namespace MWClass const MWWorld::Ptr& actor) const; ///< Generate action for activation - virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; + virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/repair.cpp b/apps/openmw/mwclass/repair.cpp index c6e90aecd..3f3aaa8de 100644 --- a/apps/openmw/mwclass/repair.cpp +++ b/apps/openmw/mwclass/repair.cpp @@ -96,10 +96,9 @@ namespace MWClass return ref->mBase->mIcon; } - bool Repair::hasToolTip (const MWWorld::Ptr& ptr) const + bool Repair::hasToolTip (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return (ref->mBase->mName != ""); } diff --git a/apps/openmw/mwclass/repair.hpp b/apps/openmw/mwclass/repair.hpp index 396727858..9ead26f03 100644 --- a/apps/openmw/mwclass/repair.hpp +++ b/apps/openmw/mwclass/repair.hpp @@ -24,7 +24,7 @@ namespace MWClass const MWWorld::Ptr& actor) const; ///< Generate action for activation - virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; + virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index e9acf9ba2..367b74482 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -242,10 +242,9 @@ namespace MWClass return ref->mBase->mIcon; } - bool Weapon::hasToolTip (const MWWorld::Ptr& ptr) const + bool Weapon::hasToolTip (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return (ref->mBase->mName != ""); } @@ -391,8 +390,7 @@ namespace MWClass return action; } - MWWorld::Ptr - Weapon::copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const + MWWorld::Ptr Weapon::copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const { const MWWorld::LiveCellRef *ref = ptr.get(); diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index f24409d82..99fd8f5eb 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -25,7 +25,7 @@ namespace MWClass const MWWorld::Ptr& actor) const; ///< Generate action for activation - virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; + virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 397762df8..7f4431983 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -272,7 +272,7 @@ namespace MWWorld throw std::runtime_error ("class does not have a tool tip"); } - bool Class::hasToolTip (const Ptr& ptr) const + bool Class::hasToolTip (const ConstPtr& ptr) const { return false; } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 2ef0ba2d4..0ac368cca 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -92,7 +92,7 @@ namespace MWWorld ///< Return creature stats or throw an exception, if class does not have creature stats /// (default implementation: throw an exception) - virtual bool hasToolTip (const Ptr& ptr) const; + virtual bool hasToolTip (const ConstPtr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) virtual MWGui::ToolTipInfo getToolTipInfo (const ConstPtr& ptr) const; diff --git a/apps/openmw/mwworld/customdata.cpp b/apps/openmw/mwworld/customdata.cpp index 6f9fb39a7..4b3e143f2 100644 --- a/apps/openmw/mwworld/customdata.cpp +++ b/apps/openmw/mwworld/customdata.cpp @@ -14,6 +14,13 @@ MWClass::CreatureCustomData &CustomData::asCreatureCustomData() throw std::logic_error(error.str()); } +const MWClass::CreatureCustomData &CustomData::asCreatureCustomData() const +{ + std::stringstream error; + error << "bad cast " << typeid(this).name() << " to CreatureCustomData"; + throw std::logic_error(error.str()); +} + MWClass::NpcCustomData &CustomData::asNpcCustomData() { std::stringstream error; diff --git a/apps/openmw/mwworld/customdata.hpp b/apps/openmw/mwworld/customdata.hpp index 4ca16fd32..80d706e39 100644 --- a/apps/openmw/mwworld/customdata.hpp +++ b/apps/openmw/mwworld/customdata.hpp @@ -24,6 +24,7 @@ namespace MWWorld // Fast version of dynamic_cast. Needs to be overridden in the respective class. virtual MWClass::CreatureCustomData& asCreatureCustomData(); + virtual const MWClass::CreatureCustomData& asCreatureCustomData() const; virtual MWClass::NpcCustomData& asNpcCustomData(); virtual const MWClass::NpcCustomData& asNpcCustomData() const; From 16e3699739a72f1df790b3be538b6361713bb69b Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 19 Dec 2015 16:18:12 +0100 Subject: [PATCH 2906/3725] Fix collision mask in castSphere --- apps/openmw/mwphysics/physicssystem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 8806641d3..c3c171af8 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -892,7 +892,7 @@ namespace MWPhysics { btCollisionWorld::ClosestConvexResultCallback callback(toBullet(from), toBullet(to)); callback.m_collisionFilterGroup = 0xff; - callback.m_collisionFilterMask = CollisionType_World|CollisionType_HeightMap; + callback.m_collisionFilterMask = CollisionType_World|CollisionType_HeightMap|CollisionType_Door; btSphereShape shape(radius); const btQuaternion btrot = btQuaternion::getIdentity(); From 0d4729dcd5b57c0e7ed507ee64b59b6a27c25d56 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 19 Dec 2015 16:19:52 +0100 Subject: [PATCH 2907/3725] Use the const version of CustomData::as* --- apps/openmw/mwclass/creature.cpp | 2 +- apps/openmw/mwclass/creaturelevlist.cpp | 6 +++++- apps/openmw/mwclass/door.cpp | 2 +- apps/openmw/mwclass/npc.cpp | 2 +- apps/openmw/mwworld/customdata.cpp | 7 +++++++ apps/openmw/mwworld/customdata.hpp | 1 + 6 files changed, 16 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 4b513a640..a94c70719 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -734,7 +734,7 @@ namespace MWClass return; } - const CreatureCustomData& customData = dynamic_cast(*ptr.getRefData().getCustomData()); + const CreatureCustomData& customData = ptr.getRefData().getCustomData()->asCreatureCustomData(); customData.mContainerStore->writeState (state2.mInventory); customData.mCreatureStats.writeState (state2.mCreatureStats); diff --git a/apps/openmw/mwclass/creaturelevlist.cpp b/apps/openmw/mwclass/creaturelevlist.cpp index 1f9e9b0fc..db2ba45bc 100644 --- a/apps/openmw/mwclass/creaturelevlist.cpp +++ b/apps/openmw/mwclass/creaturelevlist.cpp @@ -22,6 +22,10 @@ namespace MWClass { return *this; } + virtual const CreatureLevListCustomData& asCreatureLevListCustomData() const + { + return *this; + } }; MWWorld::CustomData *CreatureLevListCustomData::clone() const @@ -121,7 +125,7 @@ namespace MWClass return; } - const CreatureLevListCustomData& customData = dynamic_cast(*ptr.getRefData().getCustomData()); + const CreatureLevListCustomData& customData = ptr.getRefData().getCustomData()->asCreatureLevListCustomData(); state2.mSpawnActorId = customData.mSpawnActorId; state2.mSpawn = customData.mSpawn; } diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index b8013177a..ce987bebf 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -351,7 +351,7 @@ namespace MWClass state.mHasCustomState = false; return; } - const DoorCustomData& customData = dynamic_cast(*ptr.getRefData().getCustomData()); + const DoorCustomData& customData = ptr.getRefData().getCustomData()->asDoorCustomData(); ESM::DoorState& state2 = dynamic_cast(state); state2.mDoorState = customData.mDoorState; diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index fc82b143a..a5f997e1c 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -1184,7 +1184,7 @@ namespace MWClass return; } - const NpcCustomData& customData = dynamic_cast(*ptr.getRefData().getCustomData()); + const NpcCustomData& customData = ptr.getRefData().getCustomData()->asNpcCustomData(); customData.mInventoryStore.writeState (state2.mInventory); customData.mNpcStats.writeState (state2.mNpcStats); diff --git a/apps/openmw/mwworld/customdata.cpp b/apps/openmw/mwworld/customdata.cpp index 4b3e143f2..a63123bcf 100644 --- a/apps/openmw/mwworld/customdata.cpp +++ b/apps/openmw/mwworld/customdata.cpp @@ -63,5 +63,12 @@ MWClass::CreatureLevListCustomData &CustomData::asCreatureLevListCustomData() throw std::logic_error(error.str()); } +const MWClass::CreatureLevListCustomData &CustomData::asCreatureLevListCustomData() const +{ + std::stringstream error; + error << "bad cast " << typeid(this).name() << " to CreatureLevListCustomData"; + throw std::logic_error(error.str()); +} + } diff --git a/apps/openmw/mwworld/customdata.hpp b/apps/openmw/mwworld/customdata.hpp index 80d706e39..11932e690 100644 --- a/apps/openmw/mwworld/customdata.hpp +++ b/apps/openmw/mwworld/customdata.hpp @@ -35,6 +35,7 @@ namespace MWWorld virtual const MWClass::DoorCustomData& asDoorCustomData() const; virtual MWClass::CreatureLevListCustomData& asCreatureLevListCustomData(); + virtual const MWClass::CreatureLevListCustomData& asCreatureLevListCustomData() const; }; } From 32d5dece58e99024f17abb798cfe0e34ab74767c Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 19 Dec 2015 16:29:07 +0100 Subject: [PATCH 2908/3725] Add count argument to getToolTipInfo --- apps/openmw/mwclass/activator.cpp | 4 ++-- apps/openmw/mwclass/activator.hpp | 2 +- apps/openmw/mwclass/apparatus.cpp | 4 ++-- apps/openmw/mwclass/apparatus.hpp | 2 +- apps/openmw/mwclass/armor.cpp | 4 ++-- apps/openmw/mwclass/armor.hpp | 2 +- apps/openmw/mwclass/book.cpp | 4 ++-- apps/openmw/mwclass/book.hpp | 2 +- apps/openmw/mwclass/clothing.cpp | 4 ++-- apps/openmw/mwclass/clothing.hpp | 2 +- apps/openmw/mwclass/container.cpp | 2 +- apps/openmw/mwclass/container.hpp | 2 +- apps/openmw/mwclass/creature.cpp | 2 +- apps/openmw/mwclass/creature.hpp | 2 +- apps/openmw/mwclass/door.cpp | 2 +- apps/openmw/mwclass/door.hpp | 2 +- apps/openmw/mwclass/ingredient.cpp | 4 ++-- apps/openmw/mwclass/ingredient.hpp | 2 +- apps/openmw/mwclass/light.cpp | 4 ++-- apps/openmw/mwclass/light.hpp | 2 +- apps/openmw/mwclass/lockpick.cpp | 4 ++-- apps/openmw/mwclass/lockpick.hpp | 2 +- apps/openmw/mwclass/misc.cpp | 4 +--- apps/openmw/mwclass/misc.hpp | 2 +- apps/openmw/mwclass/npc.cpp | 2 +- apps/openmw/mwclass/npc.hpp | 2 +- apps/openmw/mwclass/potion.cpp | 4 ++-- apps/openmw/mwclass/potion.hpp | 2 +- apps/openmw/mwclass/probe.cpp | 4 ++-- apps/openmw/mwclass/probe.hpp | 2 +- apps/openmw/mwclass/repair.cpp | 4 ++-- apps/openmw/mwclass/repair.hpp | 2 +- apps/openmw/mwclass/weapon.cpp | 4 ++-- apps/openmw/mwclass/weapon.hpp | 2 +- apps/openmw/mwgui/tooltips.cpp | 18 +++++++----------- apps/openmw/mwgui/tooltips.hpp | 2 +- apps/openmw/mwworld/class.cpp | 2 +- apps/openmw/mwworld/class.hpp | 2 +- 38 files changed, 56 insertions(+), 62 deletions(-) diff --git a/apps/openmw/mwclass/activator.cpp b/apps/openmw/mwclass/activator.cpp index 48d0a254d..9785eef1e 100644 --- a/apps/openmw/mwclass/activator.cpp +++ b/apps/openmw/mwclass/activator.cpp @@ -81,12 +81,12 @@ namespace MWClass return (ref->mBase->mName != ""); } - MWGui::ToolTipInfo Activator::getToolTipInfo (const MWWorld::ConstPtr& ptr) const + MWGui::ToolTipInfo Activator::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const { const MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; - info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); + info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(count); std::string text; if (MWBase::Environment::get().getWindowManager()->getFullHelp()) diff --git a/apps/openmw/mwclass/activator.hpp b/apps/openmw/mwclass/activator.hpp index 3cc4a394c..15dbf5767 100644 --- a/apps/openmw/mwclass/activator.hpp +++ b/apps/openmw/mwclass/activator.hpp @@ -24,7 +24,7 @@ namespace MWClass virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/apparatus.cpp b/apps/openmw/mwclass/apparatus.cpp index 0c27be469..8907a5f8d 100644 --- a/apps/openmw/mwclass/apparatus.cpp +++ b/apps/openmw/mwclass/apparatus.cpp @@ -102,12 +102,12 @@ namespace MWClass return (ref->mBase->mName != ""); } - MWGui::ToolTipInfo Apparatus::getToolTipInfo (const MWWorld::ConstPtr& ptr) const + MWGui::ToolTipInfo Apparatus::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const { const MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; - info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); + info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(count); info.icon = ref->mBase->mIcon; std::string text; diff --git a/apps/openmw/mwclass/apparatus.hpp b/apps/openmw/mwclass/apparatus.hpp index 3405dd850..d669b9c2d 100644 --- a/apps/openmw/mwclass/apparatus.hpp +++ b/apps/openmw/mwclass/apparatus.hpp @@ -36,7 +36,7 @@ namespace MWClass virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. static void registerSelf(); diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index c06dcbb98..2e4667016 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -209,12 +209,12 @@ namespace MWClass return (ref->mBase->mName != ""); } - MWGui::ToolTipInfo Armor::getToolTipInfo (const MWWorld::ConstPtr& ptr) const + MWGui::ToolTipInfo Armor::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const { const MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; - info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); + info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(count); info.icon = ref->mBase->mIcon; std::string text; diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index 239d3613b..9746d6d20 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -46,7 +46,7 @@ namespace MWClass virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. virtual int getValue (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index c5881eb3b..a7d8ed8f4 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -116,12 +116,12 @@ namespace MWClass return (ref->mBase->mName != ""); } - MWGui::ToolTipInfo Book::getToolTipInfo (const MWWorld::ConstPtr& ptr) const + MWGui::ToolTipInfo Book::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const { const MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; - info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); + info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(count); info.icon = ref->mBase->mIcon; std::string text; diff --git a/apps/openmw/mwclass/book.hpp b/apps/openmw/mwclass/book.hpp index 7d28fe4c6..73bfecacd 100644 --- a/apps/openmw/mwclass/book.hpp +++ b/apps/openmw/mwclass/book.hpp @@ -30,7 +30,7 @@ namespace MWClass virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. virtual int getValue (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index f7762f6b5..20ebab314 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -165,12 +165,12 @@ namespace MWClass return (ref->mBase->mName != ""); } - MWGui::ToolTipInfo Clothing::getToolTipInfo (const MWWorld::ConstPtr& ptr) const + MWGui::ToolTipInfo Clothing::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const { const MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; - info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); + info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(count); info.icon = ref->mBase->mIcon; std::string text; diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index 08ca5aa2e..e1c0f63f7 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -38,7 +38,7 @@ namespace MWClass virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. virtual int getValue (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index 5a66c4999..675287af9 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -222,7 +222,7 @@ namespace MWClass return (ref->mBase->mName != ""); } - MWGui::ToolTipInfo Container::getToolTipInfo (const MWWorld::ConstPtr& ptr) const + MWGui::ToolTipInfo Container::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const { const MWWorld::LiveCellRef *ref = ptr.get(); diff --git a/apps/openmw/mwclass/container.hpp b/apps/openmw/mwclass/container.hpp index d378bdb25..3add65a7e 100644 --- a/apps/openmw/mwclass/container.hpp +++ b/apps/openmw/mwclass/container.hpp @@ -30,7 +30,7 @@ namespace MWClass virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. virtual MWWorld::ContainerStore& getContainerStore (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index a94c70719..e9502d86b 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -523,7 +523,7 @@ namespace MWClass return !customData.mCreatureStats.getAiSequence().isInCombat() || customData.mCreatureStats.isDead(); } - MWGui::ToolTipInfo Creature::getToolTipInfo (const MWWorld::ConstPtr& ptr) const + MWGui::ToolTipInfo Creature::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const { const MWWorld::LiveCellRef *ref = ptr.get(); diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index 8b31f2edf..cb89a53d6 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -50,7 +50,7 @@ namespace MWClass virtual bool hasToolTip(const MWWorld::ConstPtr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. virtual MWMechanics::CreatureStats& getCreatureStats (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index ce987bebf..8d54dff5d 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -234,7 +234,7 @@ namespace MWClass return (ref->mBase->mName != ""); } - MWGui::ToolTipInfo Door::getToolTipInfo (const MWWorld::ConstPtr& ptr) const + MWGui::ToolTipInfo Door::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const { const MWWorld::LiveCellRef *ref = ptr.get(); diff --git a/apps/openmw/mwclass/door.hpp b/apps/openmw/mwclass/door.hpp index d11abedcd..42aa6d64d 100644 --- a/apps/openmw/mwclass/door.hpp +++ b/apps/openmw/mwclass/door.hpp @@ -31,7 +31,7 @@ namespace MWClass virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. static std::string getDestination (const MWWorld::LiveCellRef& door); diff --git a/apps/openmw/mwclass/ingredient.cpp b/apps/openmw/mwclass/ingredient.cpp index 53316da4c..99a50a67a 100644 --- a/apps/openmw/mwclass/ingredient.cpp +++ b/apps/openmw/mwclass/ingredient.cpp @@ -115,12 +115,12 @@ namespace MWClass return (ref->mBase->mName != ""); } - MWGui::ToolTipInfo Ingredient::getToolTipInfo (const MWWorld::ConstPtr& ptr) const + MWGui::ToolTipInfo Ingredient::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const { const MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; - info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); + info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(count); info.icon = ref->mBase->mIcon; std::string text; diff --git a/apps/openmw/mwclass/ingredient.hpp b/apps/openmw/mwclass/ingredient.hpp index 12d2ee3f0..9a8bdacfb 100644 --- a/apps/openmw/mwclass/ingredient.hpp +++ b/apps/openmw/mwclass/ingredient.hpp @@ -27,7 +27,7 @@ namespace MWClass virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 2fab08154..c7ebc184f 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -147,12 +147,12 @@ namespace MWClass return (ref->mBase->mName != ""); } - MWGui::ToolTipInfo Light::getToolTipInfo (const MWWorld::ConstPtr& ptr) const + MWGui::ToolTipInfo Light::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const { const MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; - info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); + info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(count); info.icon = ref->mBase->mIcon; std::string text; diff --git a/apps/openmw/mwclass/light.hpp b/apps/openmw/mwclass/light.hpp index ff934406e..5ec21f41f 100644 --- a/apps/openmw/mwclass/light.hpp +++ b/apps/openmw/mwclass/light.hpp @@ -23,7 +23,7 @@ namespace MWClass virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. virtual boost::shared_ptr activate (const MWWorld::Ptr& ptr, diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index 908a3b2ad..d3889d2fc 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -112,12 +112,12 @@ namespace MWClass return (ref->mBase->mName != ""); } - MWGui::ToolTipInfo Lockpick::getToolTipInfo (const MWWorld::ConstPtr& ptr) const + MWGui::ToolTipInfo Lockpick::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const { const MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; - info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); + info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(count); info.icon = ref->mBase->mIcon; std::string text; diff --git a/apps/openmw/mwclass/lockpick.hpp b/apps/openmw/mwclass/lockpick.hpp index 16e9caaa8..f04674f5c 100644 --- a/apps/openmw/mwclass/lockpick.hpp +++ b/apps/openmw/mwclass/lockpick.hpp @@ -27,7 +27,7 @@ namespace MWClass virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index 72041fd53..353b93c88 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -130,7 +130,7 @@ namespace MWClass return (ref->mBase->mName != ""); } - MWGui::ToolTipInfo Miscellaneous::getToolTipInfo (const MWWorld::ConstPtr& ptr) const + MWGui::ToolTipInfo Miscellaneous::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const { const MWWorld::LiveCellRef *ref = ptr.get(); @@ -138,8 +138,6 @@ namespace MWClass const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); - int count = ptr.getRefData().getCount(); - bool gold = isGold(ptr); if (gold) count *= getValue(ptr); diff --git a/apps/openmw/mwclass/misc.hpp b/apps/openmw/mwclass/misc.hpp index 9954c1f48..363af7e89 100644 --- a/apps/openmw/mwclass/misc.hpp +++ b/apps/openmw/mwclass/misc.hpp @@ -27,7 +27,7 @@ namespace MWClass virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index a5f997e1c..57a6d088a 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -922,7 +922,7 @@ namespace MWClass return !customData.mNpcStats.getAiSequence().isInCombat() || customData.mNpcStats.isDead(); } - MWGui::ToolTipInfo Npc::getToolTipInfo (const MWWorld::ConstPtr& ptr) const + MWGui::ToolTipInfo Npc::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const { const MWWorld::LiveCellRef *ref = ptr.get(); diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index fb358c73e..5df34380a 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -63,7 +63,7 @@ namespace MWClass virtual bool hasToolTip(const MWWorld::ConstPtr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. virtual MWWorld::InventoryStore& getInventoryStore (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/potion.cpp b/apps/openmw/mwclass/potion.cpp index e10f7a9f8..40b4d6234 100644 --- a/apps/openmw/mwclass/potion.cpp +++ b/apps/openmw/mwclass/potion.cpp @@ -107,12 +107,12 @@ namespace MWClass return (ref->mBase->mName != ""); } - MWGui::ToolTipInfo Potion::getToolTipInfo (const MWWorld::ConstPtr& ptr) const + MWGui::ToolTipInfo Potion::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const { const MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; - info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); + info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(count); info.icon = ref->mBase->mIcon; std::string text; diff --git a/apps/openmw/mwclass/potion.hpp b/apps/openmw/mwclass/potion.hpp index e17c55563..9cdd58058 100644 --- a/apps/openmw/mwclass/potion.hpp +++ b/apps/openmw/mwclass/potion.hpp @@ -27,7 +27,7 @@ namespace MWClass virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index 113f500fd..79d33ba60 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -112,12 +112,12 @@ namespace MWClass return (ref->mBase->mName != ""); } - MWGui::ToolTipInfo Probe::getToolTipInfo (const MWWorld::ConstPtr& ptr) const + MWGui::ToolTipInfo Probe::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const { const MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; - info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); + info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(count); info.icon = ref->mBase->mIcon; std::string text; diff --git a/apps/openmw/mwclass/probe.hpp b/apps/openmw/mwclass/probe.hpp index fec44967d..4fc991a5f 100644 --- a/apps/openmw/mwclass/probe.hpp +++ b/apps/openmw/mwclass/probe.hpp @@ -27,7 +27,7 @@ namespace MWClass virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/repair.cpp b/apps/openmw/mwclass/repair.cpp index 3f3aaa8de..271f52bde 100644 --- a/apps/openmw/mwclass/repair.cpp +++ b/apps/openmw/mwclass/repair.cpp @@ -115,12 +115,12 @@ namespace MWClass return ref->mBase->mData.mUses; } - MWGui::ToolTipInfo Repair::getToolTipInfo (const MWWorld::ConstPtr& ptr) const + MWGui::ToolTipInfo Repair::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const { const MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; - info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); + info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(count); info.icon = ref->mBase->mIcon; std::string text; diff --git a/apps/openmw/mwclass/repair.hpp b/apps/openmw/mwclass/repair.hpp index 9ead26f03..f0d1292f4 100644 --- a/apps/openmw/mwclass/repair.hpp +++ b/apps/openmw/mwclass/repair.hpp @@ -27,7 +27,7 @@ namespace MWClass virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index 367b74482..f3f840921 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -249,12 +249,12 @@ namespace MWClass return (ref->mBase->mName != ""); } - MWGui::ToolTipInfo Weapon::getToolTipInfo (const MWWorld::ConstPtr& ptr) const + MWGui::ToolTipInfo Weapon::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const { const MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; - info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); + info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(count); info.icon = ref->mBase->mIcon; const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index 99fd8f5eb..5fc3983f2 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -28,7 +28,7 @@ namespace MWClass virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. virtual bool hasItemHealth (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 3356698df..ffc32bd9f 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -115,7 +115,7 @@ namespace MWGui tooltipSize = createToolTip(info, true); } else - tooltipSize = getToolTipViaPtr(true); + tooltipSize = getToolTipViaPtr(mFocusObject.getRefData().getCount(), true); MyGUI::IntPoint tooltipPosition = MyGUI::InputManager::getInstance().getMousePosition(); position(tooltipPosition, tooltipSize, viewSize); @@ -183,17 +183,13 @@ namespace MWGui else if (type == "ItemPtr") { mFocusObject = *focus->getUserData(); - tooltipSize = getToolTipViaPtr(false); + tooltipSize = getToolTipViaPtr(mFocusObject.getRefData().getCount(), false); } else if (type == "ItemModelIndex") { std::pair pair = *focus->getUserData >(); mFocusObject = pair.second->getItem(pair.first).mBase; - // HACK: To get the correct count for multiple item stack sources - int oldCount = mFocusObject.getRefData().getCount(); - mFocusObject.getRefData().setCount(pair.second->getItem(pair.first).mCount); - tooltipSize = getToolTipViaPtr(false); - mFocusObject.getRefData().setCount(oldCount); + tooltipSize = getToolTipViaPtr(pair.second->getItem(pair.first).mCount, false); } else if (type == "ToolTipInfo") { @@ -207,7 +203,7 @@ namespace MWGui mFocusObject = item; if (!mFocusObject.isEmpty ()) - tooltipSize = getToolTipViaPtr(false); + tooltipSize = getToolTipViaPtr(mFocusObject.getRefData().getCount(), false); } else if (type == "Spell") { @@ -294,7 +290,7 @@ namespace MWGui { if (!mFocusObject.isEmpty()) { - MyGUI::IntSize tooltipSize = getToolTipViaPtr(); + MyGUI::IntSize tooltipSize = getToolTipViaPtr(mFocusObject.getRefData().getCount()); setCoord(viewSize.width/2 - tooltipSize.width/2, std::max(0, int(mFocusToolTipY*viewSize.height - tooltipSize.height)), @@ -326,7 +322,7 @@ namespace MWGui mFocusObject = focus; } - MyGUI::IntSize ToolTips::getToolTipViaPtr (bool image) + MyGUI::IntSize ToolTips::getToolTipViaPtr (int count, bool image) { // this the maximum width of the tooltip before it starts word-wrapping setCoord(0, 0, 300, 300); @@ -342,7 +338,7 @@ namespace MWGui { mDynamicToolTipBox->setVisible(true); - ToolTipInfo info = object.getToolTipInfo(mFocusObject); + ToolTipInfo info = object.getToolTipInfo(mFocusObject, count); if (!image) info.icon = ""; tooltipSize = createToolTip(info, true); diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp index fa1ae4f88..dd4d83e56 100644 --- a/apps/openmw/mwgui/tooltips.hpp +++ b/apps/openmw/mwgui/tooltips.hpp @@ -95,7 +95,7 @@ namespace MWGui MWWorld::Ptr mFocusObject; - MyGUI::IntSize getToolTipViaPtr (bool image=true); + MyGUI::IntSize getToolTipViaPtr (int count, bool image=true); ///< @return requested tooltip size MyGUI::IntSize createToolTip(const ToolTipInfo& info, bool isFocusObject); diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 7f4431983..4cdff6c3a 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -267,7 +267,7 @@ namespace MWWorld throw std::runtime_error ("class does not have any inventory icon"); } - MWGui::ToolTipInfo Class::getToolTipInfo (const ConstPtr& ptr) const + MWGui::ToolTipInfo Class::getToolTipInfo (const ConstPtr& ptr, int count) const { throw std::runtime_error ("class does not have a tool tip"); } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 0ac368cca..c59bd675e 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -95,7 +95,7 @@ namespace MWWorld virtual bool hasToolTip (const ConstPtr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const ConstPtr& ptr) const; + virtual MWGui::ToolTipInfo getToolTipInfo (const ConstPtr& ptr, int count) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. virtual MWMechanics::NpcStats& getNpcStats (const Ptr& ptr) const; From 5a7bbbd508638171afce00e7e969299b626bfb56 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 19 Dec 2015 16:34:26 +0100 Subject: [PATCH 2909/3725] Accept a ConstPtr in ToolTips::setFocusObject --- apps/openmw/mwgui/tooltips.cpp | 2 +- apps/openmw/mwgui/tooltips.hpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index ffc32bd9f..cb3d0d0a1 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -317,7 +317,7 @@ namespace MWGui } } - void ToolTips::setFocusObject(const MWWorld::Ptr& focus) + void ToolTips::setFocusObject(const MWWorld::ConstPtr& focus) { mFocusObject = focus; } diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp index dd4d83e56..1fc736bff 100644 --- a/apps/openmw/mwgui/tooltips.hpp +++ b/apps/openmw/mwgui/tooltips.hpp @@ -58,7 +58,7 @@ namespace MWGui void setDelay(float delay); - void setFocusObject(const MWWorld::Ptr& focus); + void setFocusObject(const MWWorld::ConstPtr& focus); void setFocusObjectScreenCoords(float min_x, float min_y, float max_x, float max_y); ///< set the screen-space position of the tooltip for focused object @@ -93,7 +93,7 @@ namespace MWGui private: MyGUI::Widget* mDynamicToolTipBox; - MWWorld::Ptr mFocusObject; + MWWorld::ConstPtr mFocusObject; MyGUI::IntSize getToolTipViaPtr (int count, bool image=true); ///< @return requested tooltip size From 41c8ec56e0e1b231e089d4cc6bc45b0b4615e499 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 19 Dec 2015 16:37:26 +0100 Subject: [PATCH 2910/3725] Accept a ConstPtr in ItemPtr tooltips --- apps/openmw/mwgui/alchemywindow.cpp | 6 +++--- apps/openmw/mwgui/enchantingdialog.cpp | 4 ++-- apps/openmw/mwgui/hud.cpp | 4 ++-- apps/openmw/mwgui/merchantrepair.cpp | 2 +- apps/openmw/mwgui/quickkeysmenu.cpp | 6 +++--- apps/openmw/mwgui/recharge.cpp | 4 ++-- apps/openmw/mwgui/repair.cpp | 4 ++-- apps/openmw/mwgui/spellview.cpp | 2 +- apps/openmw/mwgui/tooltips.cpp | 2 +- 9 files changed, 17 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index d12c22e06..97731e571 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -139,7 +139,7 @@ namespace MWGui if (!iter->isEmpty()) { mApparatus.at (index)->setUserString ("ToolTipType", "ItemPtr"); - mApparatus.at (index)->setUserData (*iter); + mApparatus.at (index)->setUserData (MWWorld::ConstPtr(*iter)); } } @@ -207,9 +207,9 @@ namespace MWGui continue; ingredient->setUserString("ToolTipType", "ItemPtr"); - ingredient->setUserData(item); + ingredient->setUserData(MWWorld::ConstPtr(item)); - ingredient->setCount(ingredient->getUserData()->getRefData().getCount()); + ingredient->setCount(ingredient->getUserData()->getRefData().getCount()); } mItemView->update(); diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index c182a0a52..ac48bf1db 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -79,7 +79,7 @@ namespace MWGui { mSoulBox->setItem(gem); mSoulBox->setUserString ("ToolTipType", "ItemPtr"); - mSoulBox->setUserData(gem); + mSoulBox->setUserData(MWWorld::ConstPtr(gem)); mEnchanting.setSoulGem(gem); } } @@ -97,7 +97,7 @@ namespace MWGui mName->setCaption(item.getClass().getName(item)); mItemBox->setItem(item); mItemBox->setUserString ("ToolTipType", "ItemPtr"); - mItemBox->setUserData(item); + mItemBox->setUserData(MWWorld::ConstPtr(item)); mEnchanting.setOldItem(item); } } diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index cf0fa3414..680783c19 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -417,7 +417,7 @@ namespace MWGui mSpellStatus->setProgressPosition(chargePercent); mSpellBox->setUserString("ToolTipType", "ItemPtr"); - mSpellBox->setUserData(item); + mSpellBox->setUserData(MWWorld::ConstPtr(item)); mSpellImage->setItem(item); } @@ -435,7 +435,7 @@ namespace MWGui mWeapBox->clearUserStrings(); mWeapBox->setUserString("ToolTipType", "ItemPtr"); - mWeapBox->setUserData(item); + mWeapBox->setUserData(MWWorld::ConstPtr(item)); mWeapStatus->setProgressRange(100); mWeapStatus->setProgressPosition(durabilityPercent); diff --git a/apps/openmw/mwgui/merchantrepair.cpp b/apps/openmw/mwgui/merchantrepair.cpp index 481e1ceb4..e22ce5f05 100644 --- a/apps/openmw/mwgui/merchantrepair.cpp +++ b/apps/openmw/mwgui/merchantrepair.cpp @@ -87,11 +87,11 @@ void MerchantRepair::startRepair(const MWWorld::Ptr &actor) currentY += 18; button->setUserString("Price", MyGUI::utility::toString(price)); - button->setUserData(*iter); button->setCaptionWithReplacing(name); button->setSize(button->getTextSize().width,18); button->eventMouseWheel += MyGUI::newDelegate(this, &MerchantRepair::onMouseWheel); button->setUserString("ToolTipType", "ItemPtr"); + button->setUserData(MWWorld::ConstPtr(*iter)); button->eventMouseButtonClick += MyGUI::newDelegate(this, &MerchantRepair::onRepairButtonClick); } } diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index f2ae8dd83..c741c06ce 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -185,7 +185,7 @@ namespace MWGui button->setItem(item, ItemWidget::Barter); button->setUserString ("ToolTipType", "ItemPtr"); - button->setUserData(item); + button->setUserData(MWWorld::ConstPtr(item)); if (mItemSelectionDialog) mItemSelectionDialog->setVisible(false); @@ -209,7 +209,7 @@ namespace MWGui button->setIcon(item); button->setUserString ("ToolTipType", "ItemPtr"); - button->setUserData(item); + button->setUserData(MWWorld::ConstPtr(item)); if (mMagicSelectionDialog) mMagicSelectionDialog->setVisible(false); @@ -278,7 +278,7 @@ namespace MWGui if (Misc::StringUtils::ciEqual(it->getCellRef().getRefId(), id)) { item = *it; - button->setUserData(item); + button->setUserData(MWWorld::ConstPtr(item)); break; } } diff --git a/apps/openmw/mwgui/recharge.cpp b/apps/openmw/mwgui/recharge.cpp index 1dac7138f..82962aa15 100644 --- a/apps/openmw/mwgui/recharge.cpp +++ b/apps/openmw/mwgui/recharge.cpp @@ -56,7 +56,7 @@ void Recharge::start (const MWWorld::Ptr &item) { mGemIcon->setItem(item); mGemIcon->setUserString("ToolTipType", "ItemPtr"); - mGemIcon->setUserData(item); + mGemIcon->setUserData(MWWorld::ConstPtr(item)); updateView(); } @@ -116,7 +116,7 @@ void Recharge::updateView() "MW_ItemIconSmall", MyGUI::IntCoord(16, currentY, 32, 32), MyGUI::Align::Default); icon->setItem(*iter); icon->setUserString("ToolTipType", "ItemPtr"); - icon->setUserData(*iter); + icon->setUserData(MWWorld::ConstPtr(*iter)); icon->eventMouseButtonClick += MyGUI::newDelegate(this, &Recharge::onItemClicked); icon->eventMouseWheel += MyGUI::newDelegate(this, &Recharge::onMouseWheel); diff --git a/apps/openmw/mwgui/repair.cpp b/apps/openmw/mwgui/repair.cpp index 49d5735a4..a625c07ab 100644 --- a/apps/openmw/mwgui/repair.cpp +++ b/apps/openmw/mwgui/repair.cpp @@ -53,7 +53,7 @@ void Repair::startRepairItem(const MWWorld::Ptr &item) mToolIcon->setItem(item); mToolIcon->setUserString("ToolTipType", "ItemPtr"); - mToolIcon->setUserData(item); + mToolIcon->setUserData(MWWorld::ConstPtr(item)); updateRepairView(); } @@ -119,7 +119,7 @@ void Repair::updateRepairView() "MW_ItemIconSmall", MyGUI::IntCoord(16, currentY, 32, 32), MyGUI::Align::Default); icon->setItem(*iter); icon->setUserString("ToolTipType", "ItemPtr"); - icon->setUserData(*iter); + icon->setUserData(MWWorld::ConstPtr(*iter)); icon->eventMouseButtonClick += MyGUI::newDelegate(this, &Repair::onRepairItem); icon->eventMouseWheel += MyGUI::newDelegate(this, &Repair::onMouseWheel); diff --git a/apps/openmw/mwgui/spellview.cpp b/apps/openmw/mwgui/spellview.cpp index 06809bb49..ca1219e91 100644 --- a/apps/openmw/mwgui/spellview.cpp +++ b/apps/openmw/mwgui/spellview.cpp @@ -278,7 +278,7 @@ namespace MWGui { if (spell.mType == Spell::Type_EnchantedItem) { - widget->setUserData(spell.mItem); + widget->setUserData(MWWorld::ConstPtr(spell.mItem)); widget->setUserString("ToolTipType", "ItemPtr"); } else diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index cb3d0d0a1..e24c33b39 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -182,7 +182,7 @@ namespace MWGui } else if (type == "ItemPtr") { - mFocusObject = *focus->getUserData(); + mFocusObject = *focus->getUserData(); tooltipSize = getToolTipViaPtr(mFocusObject.getRefData().getCount(), false); } else if (type == "ItemModelIndex") From e5d9ee30f4d15f912cf1b2b3a35c89cd57d260b9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 19 Dec 2015 16:47:55 +0100 Subject: [PATCH 2911/3725] Add count argument to copyObjectToCell Fixes the gold bug introduced in c9ca5bc94658508920dbbef1f1a29101ab20ec4f --- apps/openmw/mwclass/misc.cpp | 7 +++++-- apps/openmw/mwclass/misc.hpp | 4 ++-- apps/openmw/mwworld/cellstore.cpp | 2 +- apps/openmw/mwworld/class.cpp | 7 ++++--- apps/openmw/mwworld/class.hpp | 4 ++-- apps/openmw/mwworld/worldimp.cpp | 12 +++++------- apps/openmw/mwworld/worldimp.hpp | 2 +- 7 files changed, 20 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index 353b93c88..2f41fca30 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -175,7 +175,7 @@ namespace MWClass return info; } - MWWorld::Ptr Miscellaneous::copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const + MWWorld::Ptr Miscellaneous::copyToCell(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell, int count) const { MWWorld::Ptr newPtr; @@ -183,7 +183,7 @@ namespace MWClass MWBase::Environment::get().getWorld()->getStore(); if (isGold(ptr)) { - int goldAmount = getValue(ptr) * ptr.getRefData().getCount(); + int goldAmount = getValue(ptr) * count; std::string base = "Gold_001"; if (goldAmount >= 100) @@ -208,7 +208,10 @@ namespace MWClass const MWWorld::LiveCellRef *ref = ptr.get(); newPtr = MWWorld::Ptr(cell.insert(ref), &cell); + newPtr.getRefData().setCount(count); } + newPtr.getCellRef().unsetRefNum(); + return newPtr; } diff --git a/apps/openmw/mwclass/misc.hpp b/apps/openmw/mwclass/misc.hpp index 363af7e89..2a534f058 100644 --- a/apps/openmw/mwclass/misc.hpp +++ b/apps/openmw/mwclass/misc.hpp @@ -7,10 +7,10 @@ namespace MWClass { class Miscellaneous : public MWWorld::Class { - virtual MWWorld::Ptr copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const; - public: + virtual MWWorld::Ptr copyToCell(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell, int count) const; + virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index a6389ee0c..08f272ea2 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -244,7 +244,7 @@ namespace MWWorld // on a save/load, so do a simple copy & delete for these objects. if (!object.getCellRef().getRefNum().hasContentFile()) { - MWWorld::Ptr copied = object.getClass().copyToCell(object, *cellToMoveTo); + MWWorld::Ptr copied = object.getClass().copyToCell(object, *cellToMoveTo, object.getRefData().getCount()); object.getRefData().setCount(0); object.getRefData().setBaseNode(NULL); return copied; diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 4cdff6c3a..7f2d759b9 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -334,17 +334,18 @@ namespace MWWorld } MWWorld::Ptr - Class::copyToCell(const ConstPtr &ptr, CellStore &cell) const + Class::copyToCell(const ConstPtr &ptr, CellStore &cell, int count) const { Ptr newPtr = copyToCellImpl(ptr, cell); newPtr.getCellRef().unsetRefNum(); // This RefNum is only valid within the original cell of the reference + newPtr.getRefData().setCount(count); return newPtr; } MWWorld::Ptr - Class::copyToCell(const ConstPtr &ptr, CellStore &cell, const ESM::Position &pos) const + Class::copyToCell(const ConstPtr &ptr, CellStore &cell, const ESM::Position &pos, int count) const { - Ptr newPtr = copyToCell(ptr, cell); + Ptr newPtr = copyToCell(ptr, cell, count); newPtr.getRefData().setPosition(pos); return newPtr; diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index c59bd675e..85cd9ff7c 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -280,9 +280,9 @@ namespace MWWorld /// Get a blood texture suitable for \a ptr (see Blood Texture 0-2 in Morrowind.ini) virtual int getBloodTexture (const MWWorld::ConstPtr& ptr) const; - virtual Ptr copyToCell(const ConstPtr &ptr, CellStore &cell) const; + virtual Ptr copyToCell(const ConstPtr &ptr, CellStore &cell, int count) const; - virtual Ptr copyToCell(const ConstPtr &ptr, CellStore &cell, const ESM::Position &pos) const; + virtual Ptr copyToCell(const ConstPtr &ptr, CellStore &cell, const ESM::Position &pos, int count) const; virtual bool isActor() const { return false; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index f403a6faa..c2c8e5833 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1321,7 +1321,7 @@ namespace MWWorld MWWorld::Ptr World::safePlaceObject(const MWWorld::ConstPtr& ptr, MWWorld::CellStore* cell, ESM::Position pos) { - return copyObjectToCell(ptr,cell,pos,false); + return copyObjectToCell(ptr,cell,pos,ptr.getRefData().getCount(),false); } void World::indexToPosition (int cellX, int cellY, float &x, float &y, bool centre) const @@ -1817,8 +1817,7 @@ namespace MWWorld pos.rot[1] = 0; // copy the object and set its count - Ptr dropped = copyObjectToCell(object, cell, pos, true); - dropped.getRefData().setCount(amount); + Ptr dropped = copyObjectToCell(object, cell, pos, amount, true); // only the player place items in the world, so no need to check actor PCDropped(dropped); @@ -1844,7 +1843,7 @@ namespace MWWorld } - Ptr World::copyObjectToCell(const ConstPtr &object, CellStore* cell, ESM::Position pos, bool adjustPos) + Ptr World::copyObjectToCell(const ConstPtr &object, CellStore* cell, ESM::Position pos, int count, bool adjustPos) { if (cell->isExterior()) { @@ -1854,7 +1853,7 @@ namespace MWWorld } MWWorld::Ptr dropped = - object.getClass().copyToCell(object, *cell, pos); + object.getClass().copyToCell(object, *cell, pos, count); // Reset some position values that could be uninitialized if this item came from a container dropped.getCellRef().setPosition(pos); @@ -1918,8 +1917,7 @@ namespace MWWorld pos.pos[2] = result.mHitPointWorld.z(); // copy the object and set its count - Ptr dropped = copyObjectToCell(object, cell, pos); - dropped.getRefData().setCount(amount); + Ptr dropped = copyObjectToCell(object, cell, pos, amount, true); if(actor == mPlayer->getPlayer()) // Only call if dropped by player PCDropped(dropped); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 2af6a970f..ceda1321a 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -123,7 +123,7 @@ namespace MWWorld Ptr moveObjectImp (const Ptr& ptr, float x, float y, float z); ///< @return an updated Ptr in case the Ptr's cell changes - Ptr copyObjectToCell(const ConstPtr &ptr, CellStore* cell, ESM::Position pos, bool adjustPos=true); + Ptr copyObjectToCell(const ConstPtr &ptr, CellStore* cell, ESM::Position pos, int count, bool adjustPos); void updateSoundListener(); void updateWindowManager (); From 5ac226f519a2b05a84a63b50ca901ebea7dcdb35 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 19 Dec 2015 17:02:57 +0100 Subject: [PATCH 2912/3725] Another collision mask fix --- apps/openmw/mwphysics/physicssystem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index c3c171af8..f6883ae35 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -796,7 +796,7 @@ namespace MWPhysics DeepestNotMeContactTestResultCallback resultCallback(me, toBullet(origin)); resultCallback.m_collisionFilterGroup = CollisionType_Actor; - resultCallback.m_collisionFilterMask = CollisionType_World | CollisionType_HeightMap | CollisionType_Actor; + resultCallback.m_collisionFilterMask = CollisionType_World | CollisionType_Door | CollisionType_HeightMap | CollisionType_Actor; mCollisionWorld->contactTest(&object, resultCallback); if (resultCallback.mObject) From 2176ac592c12a1298bfbf4af87c4cab9647940d8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 19 Dec 2015 21:58:49 +0100 Subject: [PATCH 2913/3725] Call updateDialogueGlobals before dialogue starts (Fixes #3034) --- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index c5e271b7a..c99e86c2d 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -114,6 +114,8 @@ namespace MWDialogue void DialogueManager::startDialogue (const MWWorld::Ptr& actor) { + updateGlobals(); + // Dialogue with dead actor (e.g. through script) should not be allowed. if (actor.getClass().getCreatureStats(actor).isDead()) return; @@ -331,6 +333,8 @@ namespace MWDialogue void DialogueManager::updateTopics() { + updateGlobals(); + std::list keywordList; int choice = mChoice; mChoice = -1; @@ -417,8 +421,6 @@ namespace MWDialogue win->setKeywords(keywordList); mChoice = choice; - - updateGlobals(); } void DialogueManager::keywordSelected (const std::string& keyword) From db7b80b5035c23adae28b4f7f0bf6997c71dfae4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 19 Dec 2015 22:52:35 +0100 Subject: [PATCH 2914/3725] Revert "Accept a ConstPtr in ItemPtr tooltips" This reverts commit 41c8ec56e0e1b231e089d4cc6bc45b0b4615e499. Does not work due to code relying on getting the non-const Ptr from the widget. Further refactoring is needed. --- apps/openmw/mwgui/alchemywindow.cpp | 6 +++--- apps/openmw/mwgui/enchantingdialog.cpp | 4 ++-- apps/openmw/mwgui/hud.cpp | 4 ++-- apps/openmw/mwgui/merchantrepair.cpp | 2 +- apps/openmw/mwgui/quickkeysmenu.cpp | 6 +++--- apps/openmw/mwgui/recharge.cpp | 4 ++-- apps/openmw/mwgui/repair.cpp | 4 ++-- apps/openmw/mwgui/spellview.cpp | 2 +- apps/openmw/mwgui/tooltips.cpp | 2 +- 9 files changed, 17 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index 97731e571..d12c22e06 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -139,7 +139,7 @@ namespace MWGui if (!iter->isEmpty()) { mApparatus.at (index)->setUserString ("ToolTipType", "ItemPtr"); - mApparatus.at (index)->setUserData (MWWorld::ConstPtr(*iter)); + mApparatus.at (index)->setUserData (*iter); } } @@ -207,9 +207,9 @@ namespace MWGui continue; ingredient->setUserString("ToolTipType", "ItemPtr"); - ingredient->setUserData(MWWorld::ConstPtr(item)); + ingredient->setUserData(item); - ingredient->setCount(ingredient->getUserData()->getRefData().getCount()); + ingredient->setCount(ingredient->getUserData()->getRefData().getCount()); } mItemView->update(); diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index ac48bf1db..c182a0a52 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -79,7 +79,7 @@ namespace MWGui { mSoulBox->setItem(gem); mSoulBox->setUserString ("ToolTipType", "ItemPtr"); - mSoulBox->setUserData(MWWorld::ConstPtr(gem)); + mSoulBox->setUserData(gem); mEnchanting.setSoulGem(gem); } } @@ -97,7 +97,7 @@ namespace MWGui mName->setCaption(item.getClass().getName(item)); mItemBox->setItem(item); mItemBox->setUserString ("ToolTipType", "ItemPtr"); - mItemBox->setUserData(MWWorld::ConstPtr(item)); + mItemBox->setUserData(item); mEnchanting.setOldItem(item); } } diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 680783c19..cf0fa3414 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -417,7 +417,7 @@ namespace MWGui mSpellStatus->setProgressPosition(chargePercent); mSpellBox->setUserString("ToolTipType", "ItemPtr"); - mSpellBox->setUserData(MWWorld::ConstPtr(item)); + mSpellBox->setUserData(item); mSpellImage->setItem(item); } @@ -435,7 +435,7 @@ namespace MWGui mWeapBox->clearUserStrings(); mWeapBox->setUserString("ToolTipType", "ItemPtr"); - mWeapBox->setUserData(MWWorld::ConstPtr(item)); + mWeapBox->setUserData(item); mWeapStatus->setProgressRange(100); mWeapStatus->setProgressPosition(durabilityPercent); diff --git a/apps/openmw/mwgui/merchantrepair.cpp b/apps/openmw/mwgui/merchantrepair.cpp index e22ce5f05..481e1ceb4 100644 --- a/apps/openmw/mwgui/merchantrepair.cpp +++ b/apps/openmw/mwgui/merchantrepair.cpp @@ -87,11 +87,11 @@ void MerchantRepair::startRepair(const MWWorld::Ptr &actor) currentY += 18; button->setUserString("Price", MyGUI::utility::toString(price)); + button->setUserData(*iter); button->setCaptionWithReplacing(name); button->setSize(button->getTextSize().width,18); button->eventMouseWheel += MyGUI::newDelegate(this, &MerchantRepair::onMouseWheel); button->setUserString("ToolTipType", "ItemPtr"); - button->setUserData(MWWorld::ConstPtr(*iter)); button->eventMouseButtonClick += MyGUI::newDelegate(this, &MerchantRepair::onRepairButtonClick); } } diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index c741c06ce..f2ae8dd83 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -185,7 +185,7 @@ namespace MWGui button->setItem(item, ItemWidget::Barter); button->setUserString ("ToolTipType", "ItemPtr"); - button->setUserData(MWWorld::ConstPtr(item)); + button->setUserData(item); if (mItemSelectionDialog) mItemSelectionDialog->setVisible(false); @@ -209,7 +209,7 @@ namespace MWGui button->setIcon(item); button->setUserString ("ToolTipType", "ItemPtr"); - button->setUserData(MWWorld::ConstPtr(item)); + button->setUserData(item); if (mMagicSelectionDialog) mMagicSelectionDialog->setVisible(false); @@ -278,7 +278,7 @@ namespace MWGui if (Misc::StringUtils::ciEqual(it->getCellRef().getRefId(), id)) { item = *it; - button->setUserData(MWWorld::ConstPtr(item)); + button->setUserData(item); break; } } diff --git a/apps/openmw/mwgui/recharge.cpp b/apps/openmw/mwgui/recharge.cpp index 82962aa15..1dac7138f 100644 --- a/apps/openmw/mwgui/recharge.cpp +++ b/apps/openmw/mwgui/recharge.cpp @@ -56,7 +56,7 @@ void Recharge::start (const MWWorld::Ptr &item) { mGemIcon->setItem(item); mGemIcon->setUserString("ToolTipType", "ItemPtr"); - mGemIcon->setUserData(MWWorld::ConstPtr(item)); + mGemIcon->setUserData(item); updateView(); } @@ -116,7 +116,7 @@ void Recharge::updateView() "MW_ItemIconSmall", MyGUI::IntCoord(16, currentY, 32, 32), MyGUI::Align::Default); icon->setItem(*iter); icon->setUserString("ToolTipType", "ItemPtr"); - icon->setUserData(MWWorld::ConstPtr(*iter)); + icon->setUserData(*iter); icon->eventMouseButtonClick += MyGUI::newDelegate(this, &Recharge::onItemClicked); icon->eventMouseWheel += MyGUI::newDelegate(this, &Recharge::onMouseWheel); diff --git a/apps/openmw/mwgui/repair.cpp b/apps/openmw/mwgui/repair.cpp index a625c07ab..49d5735a4 100644 --- a/apps/openmw/mwgui/repair.cpp +++ b/apps/openmw/mwgui/repair.cpp @@ -53,7 +53,7 @@ void Repair::startRepairItem(const MWWorld::Ptr &item) mToolIcon->setItem(item); mToolIcon->setUserString("ToolTipType", "ItemPtr"); - mToolIcon->setUserData(MWWorld::ConstPtr(item)); + mToolIcon->setUserData(item); updateRepairView(); } @@ -119,7 +119,7 @@ void Repair::updateRepairView() "MW_ItemIconSmall", MyGUI::IntCoord(16, currentY, 32, 32), MyGUI::Align::Default); icon->setItem(*iter); icon->setUserString("ToolTipType", "ItemPtr"); - icon->setUserData(MWWorld::ConstPtr(*iter)); + icon->setUserData(*iter); icon->eventMouseButtonClick += MyGUI::newDelegate(this, &Repair::onRepairItem); icon->eventMouseWheel += MyGUI::newDelegate(this, &Repair::onMouseWheel); diff --git a/apps/openmw/mwgui/spellview.cpp b/apps/openmw/mwgui/spellview.cpp index ca1219e91..06809bb49 100644 --- a/apps/openmw/mwgui/spellview.cpp +++ b/apps/openmw/mwgui/spellview.cpp @@ -278,7 +278,7 @@ namespace MWGui { if (spell.mType == Spell::Type_EnchantedItem) { - widget->setUserData(MWWorld::ConstPtr(spell.mItem)); + widget->setUserData(spell.mItem); widget->setUserString("ToolTipType", "ItemPtr"); } else diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index e24c33b39..cb3d0d0a1 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -182,7 +182,7 @@ namespace MWGui } else if (type == "ItemPtr") { - mFocusObject = *focus->getUserData(); + mFocusObject = *focus->getUserData(); tooltipSize = getToolTipViaPtr(mFocusObject.getRefData().getCount(), false); } else if (type == "ItemModelIndex") From 4c1411776118558633ce872602d2e5733aaf4b15 Mon Sep 17 00:00:00 2001 From: Aesylwinn Date: Sat, 19 Dec 2015 20:03:00 -0500 Subject: [PATCH 2915/3725] Added checks to verifier for container inventories --- .../opencs/model/tools/referenceablecheck.cpp | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/apps/opencs/model/tools/referenceablecheck.cpp b/apps/opencs/model/tools/referenceablecheck.cpp index 336a5e713..bbff372ab 100644 --- a/apps/opencs/model/tools/referenceablecheck.cpp +++ b/apps/opencs/model/tools/referenceablecheck.cpp @@ -397,6 +397,41 @@ void CSMTools::ReferenceableCheckStage::containerCheck( //checking for name if (container.mName.empty()) messages.push_back (std::make_pair (id, container.mId + " has an empty name")); + + //checking contained items + const std::vector& itemList = container.mInventory.mList; + for (unsigned i = 0; i < itemList.size(); ++i) + { + std::string itemName = itemList[i].mItem.toString(); + CSMWorld::RefIdData::LocalIndex localIndex = mReferencables.searchId(itemName); + + if (localIndex.first == -1) + messages.push_back (std::make_pair (id, + container.mId + " contains unreferenced item " + itemName)); + else + { + switch (localIndex.second) + { + case CSMWorld::UniversalId::Type_Potion: + case CSMWorld::UniversalId::Type_Apparatus: + case CSMWorld::UniversalId::Type_Armor: + case CSMWorld::UniversalId::Type_Book: + case CSMWorld::UniversalId::Type_Clothing: + case CSMWorld::UniversalId::Type_Ingredient: + case CSMWorld::UniversalId::Type_Light: + case CSMWorld::UniversalId::Type_Lockpick: + case CSMWorld::UniversalId::Type_Miscellaneous: + case CSMWorld::UniversalId::Type_Probe: + case CSMWorld::UniversalId::Type_Repair: + case CSMWorld::UniversalId::Type_Weapon: + case CSMWorld::UniversalId::Type_ItemLevelledList: + break; + default: + messages.push_back (std::make_pair(id, + container.mId + " contains illegal item " + itemName)); + } + } + } // Check that mentioned scripts exist scriptCheck(container, messages, id.toString()); From 9bd14215d7a33995b24cfff29fe7131f96819fb2 Mon Sep 17 00:00:00 2001 From: Aesylwinn Date: Sat, 19 Dec 2015 22:02:39 -0500 Subject: [PATCH 2916/3725] Expanded inventory check to creatures and NPCs --- .../opencs/model/tools/referenceablecheck.cpp | 79 +++++++++++-------- .../opencs/model/tools/referenceablecheck.hpp | 4 +- 2 files changed, 49 insertions(+), 34 deletions(-) diff --git a/apps/opencs/model/tools/referenceablecheck.cpp b/apps/opencs/model/tools/referenceablecheck.cpp index bbff372ab..ce78e52b2 100644 --- a/apps/opencs/model/tools/referenceablecheck.cpp +++ b/apps/opencs/model/tools/referenceablecheck.cpp @@ -399,39 +399,7 @@ void CSMTools::ReferenceableCheckStage::containerCheck( messages.push_back (std::make_pair (id, container.mId + " has an empty name")); //checking contained items - const std::vector& itemList = container.mInventory.mList; - for (unsigned i = 0; i < itemList.size(); ++i) - { - std::string itemName = itemList[i].mItem.toString(); - CSMWorld::RefIdData::LocalIndex localIndex = mReferencables.searchId(itemName); - - if (localIndex.first == -1) - messages.push_back (std::make_pair (id, - container.mId + " contains unreferenced item " + itemName)); - else - { - switch (localIndex.second) - { - case CSMWorld::UniversalId::Type_Potion: - case CSMWorld::UniversalId::Type_Apparatus: - case CSMWorld::UniversalId::Type_Armor: - case CSMWorld::UniversalId::Type_Book: - case CSMWorld::UniversalId::Type_Clothing: - case CSMWorld::UniversalId::Type_Ingredient: - case CSMWorld::UniversalId::Type_Light: - case CSMWorld::UniversalId::Type_Lockpick: - case CSMWorld::UniversalId::Type_Miscellaneous: - case CSMWorld::UniversalId::Type_Probe: - case CSMWorld::UniversalId::Type_Repair: - case CSMWorld::UniversalId::Type_Weapon: - case CSMWorld::UniversalId::Type_ItemLevelledList: - break; - default: - messages.push_back (std::make_pair(id, - container.mId + " contains illegal item " + itemName)); - } - } - } + inventoryListCheck(container.mInventory.mList, messages, id.toString()); // Check that mentioned scripts exist scriptCheck(container, messages, id.toString()); @@ -506,6 +474,9 @@ void CSMTools::ReferenceableCheckStage::creatureCheck ( if (creature.mScale == 0) messages.push_back (std::make_pair (id, creature.mId + " has zero scale value")); + // Check inventory + inventoryListCheck(creature.mInventory.mList, messages, id.toString()); + // Check that mentioned scripts exist scriptCheck(creature, messages, id.toString()); } @@ -777,6 +748,9 @@ void CSMTools::ReferenceableCheckStage::npcCheck ( //TODO: reputation, Disposition, rank, everything else + // Check inventory + inventoryListCheck(npc.mInventory.mList, messages, id.toString()); + // Check that mentioned scripts exist scriptCheck(npc, messages, id.toString()); } @@ -926,6 +900,45 @@ void CSMTools::ReferenceableCheckStage::finalCheck (CSMDoc::Messages& messages) "There is no player record")); } +void CSMTools::ReferenceableCheckStage::inventoryListCheck( + const std::vector& itemList, + CSMDoc::Messages& messages, + const std::string& id) +{ + for (size_t i = 0; i < itemList.size(); ++i) + { + std::string itemName = itemList[i].mItem.toString(); + CSMWorld::RefIdData::LocalIndex localIndex = mReferencables.searchId(itemName); + + if (localIndex.first == -1) + messages.push_back (std::make_pair (id, + id + " contains non-existing item (" + itemName + ")")); + else + { + // Needs to accomodate Containers, Creatures, and NPCs + switch (localIndex.second) + { + case CSMWorld::UniversalId::Type_Potion: + case CSMWorld::UniversalId::Type_Apparatus: + case CSMWorld::UniversalId::Type_Armor: + case CSMWorld::UniversalId::Type_Book: + case CSMWorld::UniversalId::Type_Clothing: + case CSMWorld::UniversalId::Type_Ingredient: + case CSMWorld::UniversalId::Type_Light: + case CSMWorld::UniversalId::Type_Lockpick: + case CSMWorld::UniversalId::Type_Miscellaneous: + case CSMWorld::UniversalId::Type_Probe: + case CSMWorld::UniversalId::Type_Repair: + case CSMWorld::UniversalId::Type_Weapon: + case CSMWorld::UniversalId::Type_ItemLevelledList: + break; + default: + messages.push_back (std::make_pair(id, + id + " contains item of invalid type (" + itemName + ")")); + } + } + } +} //Templates begins here diff --git a/apps/opencs/model/tools/referenceablecheck.hpp b/apps/opencs/model/tools/referenceablecheck.hpp index a34f3a789..4356e50b2 100644 --- a/apps/opencs/model/tools/referenceablecheck.hpp +++ b/apps/opencs/model/tools/referenceablecheck.hpp @@ -47,7 +47,9 @@ namespace CSMTools //FINAL CHECK void finalCheck (CSMDoc::Messages& messages); - //TEMPLATE CHECKS + //Convenience functions + void inventoryListCheck(const std::vector& itemList, CSMDoc::Messages& messages, const std::string& id); + template void inventoryItemCheck(const ITEM& someItem, CSMDoc::Messages& messages, const std::string& someID, From fb2384a7d6d4098e1bcc258fd0aada987790f747 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 20 Dec 2015 09:26:39 +0100 Subject: [PATCH 2917/3725] updated credits file --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index a12aa0e70..292c1e9e3 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -13,6 +13,7 @@ Programmers Marc Zinnschlag (Zini) - Lead Programmer/Project Manager Adam Hogan (aurix) + Aesylwinn Aleksandar Jovanov Alex Haddad (rainChu) Alex McKibben (WeirdSexy) From f3187b17c83d0196b2b580b0122a938743f28770 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Wed, 23 Dec 2015 18:38:53 +0100 Subject: [PATCH 2918/3725] Update OpenAL soft link, get qtbinpatcher to run --- CI/before_script.msvc.sh | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/CI/before_script.msvc.sh b/CI/before_script.msvc.sh index 37905fc4c..50fd13e4e 100644 --- a/CI/before_script.msvc.sh +++ b/CI/before_script.msvc.sh @@ -225,7 +225,7 @@ if [ -z $SKIP_DOWNLOAD ]; then # OpenAL download "OpenAL-Soft 1.16.0" \ - http://kcat.strangesoft.net/openal-soft-1.16.0-bin.zip \ + http://kcat.strangesoft.net/openal-binaries/openal-soft-1.16.0-bin.zip \ OpenAL-Soft-1.16.0.zip # OSG @@ -472,10 +472,8 @@ fi rm -rf Qt eval 7z x -y $DEPS/qt$BITS-4.8.6.7z $STRIP mv qt-4.8.6-* Qt - ( - cd $QT_SDK - eval qtbinpatcher.exe $STRIP - ) + cd Qt + eval ./qtbinpatcher.exe $STRIP fi cd $QT_SDK From 5743c839a8bd40fa9336c7dacdaae4c59b1ef7ee Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Wed, 23 Dec 2015 18:51:04 +0100 Subject: [PATCH 2919/3725] Why is this breaking on AppVeyor? --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 651f41783..be8f2b12b 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -40,7 +40,7 @@ cache: clone_folder: C:\projects\openmw before_build: - - cmd: sh %APPVEYOR_BUILD_FOLDER%\CI\before_script.msvc.sh -u + - cmd: sh %APPVEYOR_BUILD_FOLDER%\CI\before_script.msvc.sh -u -v build_script: - cmd: if %PLATFORM%==Win32 set build=Build_32 From c226d015aca698cb8ac95f8ee6571f36c2946248 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Wed, 23 Dec 2015 18:59:41 +0100 Subject: [PATCH 2920/3725] AppVeyor doesn't pass the platform env variable? --- CI/before_script.msvc.sh | 2 +- appveyor.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CI/before_script.msvc.sh b/CI/before_script.msvc.sh index 50fd13e4e..3cb024dda 100644 --- a/CI/before_script.msvc.sh +++ b/CI/before_script.msvc.sh @@ -40,7 +40,7 @@ else cd $APPVEYOR_BUILD_FOLDER VERSION="$(cat README.md | grep Version: | awk '{ print $3; }')-$(git rev-parse --short HEAD)" - appveyor UpdateBuild -Version "$VERSION" + appveyor UpdateBuild -Version "$VERSION" > /dev/null & fi run_cmd() { diff --git a/appveyor.yml b/appveyor.yml index be8f2b12b..b137d4850 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -40,7 +40,7 @@ cache: clone_folder: C:\projects\openmw before_build: - - cmd: sh %APPVEYOR_BUILD_FOLDER%\CI\before_script.msvc.sh -u -v + - cmd: sh PLATFORM=%PLATFORM% %APPVEYOR_BUILD_FOLDER%\CI\before_script.msvc.sh -u build_script: - cmd: if %PLATFORM%==Win32 set build=Build_32 From c8145a1b917d81639577cfb7c6018d0d786b7b73 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Wed, 23 Dec 2015 19:32:43 +0100 Subject: [PATCH 2921/3725] Let's see if we can't get AppVeyor to work --- CI/before_script.msvc.sh | 8 ++++++++ appveyor.yml | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CI/before_script.msvc.sh b/CI/before_script.msvc.sh index 3cb024dda..51734ceb3 100644 --- a/CI/before_script.msvc.sh +++ b/CI/before_script.msvc.sh @@ -20,6 +20,14 @@ while [ $# -gt 0 ]; do -u ) UNITY_BUILD=true ;; + -p ) + PLATFORM=$1 + shift ;; + + -c ) + CONFIGURATION=$1 + shift ;; + * ) echo "Unknown arg $ARG." exit 1 ;; diff --git a/appveyor.yml b/appveyor.yml index b137d4850..46241bf29 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -40,7 +40,7 @@ cache: clone_folder: C:\projects\openmw before_build: - - cmd: sh PLATFORM=%PLATFORM% %APPVEYOR_BUILD_FOLDER%\CI\before_script.msvc.sh -u + - cmd: sh %APPVEYOR_BUILD_FOLDER%\CI\before_script.msvc.sh -u -p %PLATFORM% build_script: - cmd: if %PLATFORM%==Win32 set build=Build_32 From 1dbc1e67d8cd4f2807792bac7aa3e83d5fa274b3 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Thu, 24 Dec 2015 02:41:35 +0100 Subject: [PATCH 2922/3725] Possible Qt5 link fix for AppVeyor --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1e966a163..d75d044b1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -99,8 +99,8 @@ if (WIN32) option(USE_DEBUG_CONSOLE "whether a debug console should be enabled for debug builds, if false debug output is redirected to Visual Studio output" ON) endif() -# We probably support older versions than this. -cmake_minimum_required(VERSION 2.6) +# To make Qt5 happy and allow linking QtMain on Windows. +cmake_minimum_required(VERSION 2.8.11) # Sound setup unset(FFMPEG_LIBRARIES CACHE) From 2142d0d2d65c40155be00e49578eea5e60a25080 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Thu, 24 Dec 2015 02:48:00 +0100 Subject: [PATCH 2923/3725] Make Qt5 happy --- apps/launcher/CMakeLists.txt | 3 --- apps/opencs/CMakeLists.txt | 3 --- apps/wizard/CMakeLists.txt | 3 --- 3 files changed, 9 deletions(-) diff --git a/apps/launcher/CMakeLists.txt b/apps/launcher/CMakeLists.txt index 274239fb0..4d2dc6ac4 100644 --- a/apps/launcher/CMakeLists.txt +++ b/apps/launcher/CMakeLists.txt @@ -103,9 +103,6 @@ if (DESIRED_QT_VERSION MATCHES 4) endif(WIN32) else() qt5_use_modules(openmw-launcher Widgets Core) - if (WIN32) - target_link_libraries(Qt5::WinMain) - endif() endif() if (BUILD_WITH_CODE_COVERAGE) diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 6af04e8fc..a8ed68328 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -224,9 +224,6 @@ if (DESIRED_QT_VERSION MATCHES 4) endif() else() qt5_use_modules(openmw-cs Widgets Core Network OpenGL) - if (WIN32) - target_link_libraries(Qt5::WinMain) - endif() endif() if (WIN32) diff --git a/apps/wizard/CMakeLists.txt b/apps/wizard/CMakeLists.txt index 89438640c..4be5fb2b7 100644 --- a/apps/wizard/CMakeLists.txt +++ b/apps/wizard/CMakeLists.txt @@ -129,9 +129,6 @@ if (DESIRED_QT_VERSION MATCHES 4) endif() else() qt5_use_modules(openmw-wizard Widgets Core) - if (WIN32) - target_link_libraries(Qt5::WinMain) - endif() endif() if (OPENMW_USE_UNSHIELD) From 93ee8f1991beeeb8a1822164df502f2cf940001e Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Thu, 24 Dec 2015 11:33:59 +0100 Subject: [PATCH 2924/3725] Allow for earlier CMake on Qt4 --- CMakeLists.txt | 57 +++++++++++++++++++++++++++----------------------- 1 file changed, 31 insertions(+), 26 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 906c87db2..509988fef 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -111,8 +111,37 @@ if (WIN32) option(USE_DEBUG_CONSOLE "whether a debug console should be enabled for debug builds, if false debug output is redirected to Visual Studio output" ON) endif() -# To make Qt5 happy and allow linking QtMain on Windows. -cmake_minimum_required(VERSION 2.8.11) +if (NOT BUILD_LAUNCHER AND NOT BUILD_OPENCS AND NOT BUILD_WIZARD) + set(USE_QT FALSE) +else() + set(USE_QT TRUE) +endif() + +# Dependencies +if (USE_QT) + set(DESIRED_QT_VERSION 4 CACHE STRING "The QT version OpenMW should use (4 or 5)") + set_property(CACHE DESIRED_QT_VERSION PROPERTY STRINGS 4 5) + message(STATUS "Using Qt${DESIRED_QT_VERSION}") + + if (DESIRED_QT_VERSION MATCHES 4) + find_package(Qt4 REQUIRED COMPONENTS QtCore QtGui QtNetwork QtOpenGL) + else() + find_package(Qt5Widgets REQUIRED) + find_package(Qt5Core REQUIRED) + find_package(Qt5Network REQUIRED) + find_package(Qt5OpenGL REQUIRED) + # Instruct CMake to run moc automatically when needed. + #set(CMAKE_AUTOMOC ON) + endif() +endif() + +if (USE_QT AND DESIRED_QT_VERSION MATCHES 5) + # 2.8.11+ is required to make Qt5 happy and allow linking QtMain on Windows. + cmake_minimum_required(VERSION 2.8.11) +else() + # We probably support older versions than this. + cmake_minimum_required(VERSION 2.6) +endif() # Sound setup unset(FFMPEG_LIBRARIES CACHE) @@ -167,30 +196,6 @@ if (OPENGL_ES) add_definitions(-DOPENGL_ES) endif(OPENGL_ES) -if (NOT BUILD_LAUNCHER AND NOT BUILD_OPENCS AND NOT BUILD_WIZARD) - set(USE_QT FALSE) -else() - set(USE_QT TRUE) -endif() - -# Dependencies -if (USE_QT) - set(DESIRED_QT_VERSION 4 CACHE STRING "The QT version OpenMW should use (4 or 5)") - set_property(CACHE DESIRED_QT_VERSION PROPERTY STRINGS 4 5) - message(STATUS "Using Qt${DESIRED_QT_VERSION}") - - if (DESIRED_QT_VERSION MATCHES 4) - find_package(Qt4 REQUIRED COMPONENTS QtCore QtGui QtNetwork QtOpenGL) - else() - find_package(Qt5Widgets REQUIRED) - find_package(Qt5Core REQUIRED) - find_package(Qt5Network REQUIRED) - find_package(Qt5OpenGL REQUIRED) - # Instruct CMake to run moc automatically when needed. - #set(CMAKE_AUTOMOC ON) - endif() -endif() - # Fix for not visible pthreads functions for linker with glibc 2.15 if (UNIX AND NOT APPLE) find_package (Threads) From 09ec622f66d0d4e970c8a32165161d7aa4acdb94 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Thu, 24 Dec 2015 11:42:12 +0100 Subject: [PATCH 2925/3725] Remove unused environment, only do 32-bit --- appveyor.yml | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 46241bf29..631cae63a 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -6,18 +6,10 @@ branches: platform: - Win32 - - x64 +# - x64 configuration: Debug -#environment: -# matrix: -# - STEP: misc -# - STEP: components # misc builds this too -# Build takes too long for these, ignore for now -# - STEP: openmw -# - STEP: opencs - matrix: fast_finish: true From 0efb8e29493b4f26bd591e5a359414a1c1088395 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Thu, 24 Dec 2015 17:18:32 +0100 Subject: [PATCH 2926/3725] osgDB::ObjectCache was added in 3.3.3, not 3.4.0 Fixes redefinition error on builds with OSG >3.3.3 <3.4.0 --- components/resource/objectcache.cpp | 2 +- components/resource/objectcache.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/components/resource/objectcache.cpp b/components/resource/objectcache.cpp index 8c2c52416..7264d05aa 100644 --- a/components/resource/objectcache.cpp +++ b/components/resource/objectcache.cpp @@ -13,7 +13,7 @@ #include -#if OSG_VERSION_LESS_THAN(3,4,0) +#if OSG_VERSION_LESS_THAN(3,3,3) #include "objectcache.hpp" diff --git a/components/resource/objectcache.hpp b/components/resource/objectcache.hpp index 0a342f27f..cae48ca6b 100644 --- a/components/resource/objectcache.hpp +++ b/components/resource/objectcache.hpp @@ -19,7 +19,7 @@ #include -#if OSG_VERSION_GREATER_OR_EQUAL(3,4,0) +#if OSG_VERSION_GREATER_OR_EQUAL(3,3,3) #include #else From f422fe49f8b2f07bec6e4fcd9950fd15ac9bb7f3 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Thu, 24 Dec 2015 18:27:57 +0100 Subject: [PATCH 2927/3725] Slight improvement to the build setup --- CI/before_script.msvc.sh | 121 ++++++++++++++++++++++++++++----------- appveyor.yml | 3 +- 2 files changed, 91 insertions(+), 33 deletions(-) mode change 100644 => 100755 CI/before_script.msvc.sh diff --git a/CI/before_script.msvc.sh b/CI/before_script.msvc.sh old mode 100644 new mode 100755 index 51734ceb3..5aa8d3e9d --- a/CI/before_script.msvc.sh +++ b/CI/before_script.msvc.sh @@ -1,42 +1,86 @@ #!/bin/bash while [ $# -gt 0 ]; do - ARG=$1 + ARGSTR=$1 shift - case $ARG in - -v ) - VERBOSE=true ;; - - -d ) - SKIP_DOWNLOAD=true ;; - - -e ) - SKIP_EXTRACT=true ;; - - -k ) - KEEP=true ;; - - -u ) - UNITY_BUILD=true ;; - - -p ) - PLATFORM=$1 - shift ;; - - -c ) - CONFIGURATION=$1 - shift ;; + if [ ${ARGSTR:0:1} != "-" ]; then + echo "Unknown argument $ARGSTR" + echo "Try '$0 -h'" + exit 1 + fi - * ) - echo "Unknown arg $ARG." - exit 1 ;; - esac + for (( i=1; i<${#ARGSTR}; i++ )); do + ARG=${ARGSTR:$i:1} + case $ARG in + V ) + VERBOSE=true ;; + + v ) + VS_VERSION=$1 + shift ;; + + d ) + SKIP_DOWNLOAD=true ;; + + e ) + SKIP_EXTRACT=true ;; + + k ) + KEEP=true ;; + + u ) + UNITY_BUILD=true ;; + + p ) + PLATFORM=$1 + shift ;; + + c ) + CONFIGURATION=$1 + shift ;; + + h ) + cat < + Set the configuration, can also be set with environment variable CONFIGURATION. + -d + Skip checking the downloads. + -e + Skip extracting dependencies. + -h + Show this message. + -k + Keep the old build directory, default is to delete it. + -p + Set the build platform, can also be set with environment variable PLATFORM. + -u + Configure for unity builds. + -v <2013/2015> + Choose the Visual Studio version to use. + -V + Run verbosely +EOF + exit 0 + ;; + + * ) + echo "Unknown argument $ARG." + echo "Try '$0 -h'" + exit 1 ;; + esac + done done if [ -z $VERBOSE ]; then STRIP="> /dev/null 2>&1" fi +if [ -z $VS_VERSION ]; then + VS_VERSION="2013" +fi if [ -z $APPVEYOR ]; then echo "Running prebuild outside of Appveyor." @@ -148,14 +192,27 @@ if [ -z $CONFIGURATION ]; then CONFIGURATION="Debug" fi +case $VS_VERSION in + 14|2015 ) + GENERATOR="Visual Studio 14 2015" + XP_TOOLSET="v140_xp" + ;; + +# 12|2013| + * ) + GENERATOR="Visual Studio 12 2013" + XP_TOOLSET="v120_xp" + ;; +esac + case $PLATFORM in x64|x86_64|x86-64|win64|Win64 ) ARCHNAME=x86-64 ARCHSUFFIX=64 BITS=64 - BASE_OPTS="-G\"Visual Studio 12 2013 Win64\"" - add_cmake_opts "-G\"Visual Studio 12 2013 Win64\"" + BASE_OPTS="-G\"$GENERATOR Win64\"" + add_cmake_opts "-G\"$GENERATOR Win64\"" ;; x32|x86|i686|i386|win32|Win32 ) @@ -163,8 +220,8 @@ case $PLATFORM in ARCHSUFFIX=86 BITS=32 - BASE_OPTS="-G\"Visual Studio 12 2013\" -Tv120_xp" - add_cmake_opts "-G\"Visual Studio 12 2013\"" -Tv120_xp + BASE_OPTS="-G\"$GENERATOR\" -T$XP_TOOLSET" + add_cmake_opts "-G\"$GENERATOR\"" -T$XP_TOOLSET ;; * ) diff --git a/appveyor.yml b/appveyor.yml index 631cae63a..0667e0ee0 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -15,7 +15,8 @@ matrix: os: unstable -clone_depth: 1 +shallow_clone: true +#clone_depth: 1 cache: - C:\projects\openmw\deps\Bullet-2.83.5-win32.7z From d32358558e91b889cebb79873a5a4bf8b41ac63b Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Thu, 24 Dec 2015 22:39:07 +0100 Subject: [PATCH 2928/3725] We actually want the commit hash, so no zips --- appveyor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 0667e0ee0..28df364df 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -15,8 +15,8 @@ matrix: os: unstable -shallow_clone: true -#clone_depth: 1 +#shallow_clone: true +clone_depth: 1 cache: - C:\projects\openmw\deps\Bullet-2.83.5-win32.7z From a1e163ed209d436c84160ba768af60f246b3003a Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 26 Dec 2015 00:26:13 +0100 Subject: [PATCH 2929/3725] Correct an error in the timestamp subtracting logic (Fixes #3105) --- apps/openmw/mwworld/timestamp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/timestamp.cpp b/apps/openmw/mwworld/timestamp.cpp index bd07b91f3..ffb1cacb8 100644 --- a/apps/openmw/mwworld/timestamp.cpp +++ b/apps/openmw/mwworld/timestamp.cpp @@ -96,7 +96,7 @@ namespace MWWorld if (left.getHour() Date: Sat, 26 Dec 2015 18:15:57 +0100 Subject: [PATCH 2930/3725] Disable Ready Magic and Cycle Weapon/Spell hotkeys for werewolves (Fixes #3100) --- apps/openmw/mwinput/inputmanagerimp.cpp | 41 +++++++++++++++---------- apps/openmw/mwinput/inputmanagerimp.hpp | 2 ++ 2 files changed, 27 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 71938dfb0..a46f1778b 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -302,16 +302,20 @@ namespace MWInput quickLoad(); break; case A_CycleSpellLeft: - MWBase::Environment::get().getWindowManager()->cycleSpell(false); + if (checkAllowedToUseItems()) + MWBase::Environment::get().getWindowManager()->cycleSpell(false); break; case A_CycleSpellRight: - MWBase::Environment::get().getWindowManager()->cycleSpell(true); + if (checkAllowedToUseItems()) + MWBase::Environment::get().getWindowManager()->cycleSpell(true); break; case A_CycleWeaponLeft: - MWBase::Environment::get().getWindowManager()->cycleWeapon(false); + if (checkAllowedToUseItems()) + MWBase::Environment::get().getWindowManager()->cycleWeapon(false); break; case A_CycleWeaponRight: - MWBase::Environment::get().getWindowManager()->cycleWeapon(true); + if (checkAllowedToUseItems()) + MWBase::Environment::get().getWindowManager()->cycleWeapon(true); break; case A_Sneak: if (mSneakToggles) @@ -346,6 +350,18 @@ namespace MWInput } } + bool InputManager::checkAllowedToUseItems() const + { + MWWorld::Ptr player = MWMechanics::getPlayer(); + if (player.getClass().getNpcStats(player).isWerewolf()) + { + // Cannot use items or spells while in werewolf form + MWBase::Environment::get().getWindowManager()->messageBox("#{sWerewolfRefusal}"); + return false; + } + return true; + } + void InputManager::update(float dt, bool disableControls, bool disableEvents) { mControlsDisabled = disableControls; @@ -902,6 +918,9 @@ namespace MWInput if (!mControlSwitch["playermagic"] || !mControlSwitch["playercontrols"]) return; + if (!checkAllowedToUseItems()) + return; + // Not allowed if no spell selected MWWorld::InventoryStore& inventory = mPlayer->getPlayer().getClass().getInventoryStore(mPlayer->getPlayer()); if (MWBase::Environment::get().getWindowManager()->getSelectedSpell().empty() && @@ -1016,13 +1035,8 @@ namespace MWInput { if (!mControlSwitch["playercontrols"]) return; - MWWorld::Ptr player = MWMechanics::getPlayer(); - if (player.getClass().getNpcStats(player).isWerewolf()) - { - // Cannot use items or spells while in werewolf form - MWBase::Environment::get().getWindowManager()->messageBox("#{sWerewolfRefusal}"); + if (!checkAllowedToUseItems()) return; - } if (!MWBase::Environment::get().getWindowManager()->isGuiMode()) MWBase::Environment::get().getWindowManager()->activateQuickKey (index); @@ -1033,13 +1047,8 @@ namespace MWInput if (!MWBase::Environment::get().getWindowManager()->isGuiMode () && MWBase::Environment::get().getWorld()->getGlobalFloat ("chargenstate")==-1) { - MWWorld::Ptr player = MWMechanics::getPlayer(); - if (player.getClass().getNpcStats(player).isWerewolf()) - { - // Cannot use items or spells while in werewolf form - MWBase::Environment::get().getWindowManager()->messageBox("#{sWerewolfRefusal}"); + if (!checkAllowedToUseItems()) return; - } MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_QuickKeysMenu); diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 3b11e04c0..644391688 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -213,6 +213,8 @@ namespace MWInput void updateCursorMode(); + bool checkAllowedToUseItems() const; + private: void toggleMainMenu(); void toggleSpell(); From f052c05018455e938b27408115aded79151f90d0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 26 Dec 2015 18:22:21 +0100 Subject: [PATCH 2931/3725] Move werewolf functions from World to MechanicsManager --- apps/openmw/mwbase/mechanicsmanager.hpp | 7 ++ apps/openmw/mwbase/world.hpp | 7 -- .../mwmechanics/mechanicsmanagerimp.cpp | 105 ++++++++++++++++++ .../mwmechanics/mechanicsmanagerimp.hpp | 3 + apps/openmw/mwscript/statsextensions.cpp | 4 +- apps/openmw/mwworld/worldimp.cpp | 105 ------------------ apps/openmw/mwworld/worldimp.hpp | 4 - 7 files changed, 117 insertions(+), 118 deletions(-) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index 31afc126a..42da1a052 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -221,6 +221,13 @@ namespace MWBase virtual bool isItemStolenFrom(const std::string& itemid, const std::string& ownerid) = 0; virtual bool isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::CellRef& cellref, MWWorld::Ptr& victim) = 0; + + /// Turn actor into werewolf or normal form. + virtual void setWerewolf(const MWWorld::Ptr& actor, bool werewolf) = 0; + + /// Sets the NPC's Acrobatics skill to match the fWerewolfAcrobatics GMST. + /// It only applies to the current form the NPC is in. + virtual void applyWerewolfAcrobatics(const MWWorld::Ptr& actor) = 0; }; } diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 5ae21022c..ebce2e1bf 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -456,13 +456,6 @@ namespace MWBase /// Returns true if levitation spell effect is allowed. virtual bool isLevitationEnabled() const = 0; - /// Turn actor into werewolf or normal form. - virtual void setWerewolf(const MWWorld::Ptr& actor, bool werewolf) = 0; - - /// Sets the NPC's Acrobatics skill to match the fWerewolfAcrobatics GMST. - /// It only applies to the current form the NPC is in. - virtual void applyWerewolfAcrobatics(const MWWorld::Ptr& actor) = 0; - virtual bool getGodModeState() = 0; virtual bool toggleGodMode() = 0; diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 9dafebffa..f88d27fce 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1585,4 +1585,109 @@ namespace MWMechanics { return mActors.isReadyToBlock(ptr); } + + void MechanicsManager::setWerewolf(const MWWorld::Ptr& actor, bool werewolf) + { + MWMechanics::NpcStats& npcStats = actor.getClass().getNpcStats(actor); + + // The actor does not have to change state + if (npcStats.isWerewolf() == werewolf) + return; + + MWWorld::Player* player = &MWBase::Environment::get().getWorld()->getPlayer(); + + if (actor == player->getPlayer()) + { + if (werewolf) + { + player->saveSkillsAttributes(); + player->setWerewolfSkillsAttributes(); + } + else + player->restoreSkillsAttributes(); + } + + npcStats.setWerewolf(werewolf); + + // This is a bit dangerous. Equipped items other than WerewolfRobe may reference + // bones that do not even exist with the werewolf object root. + // Therefore, make sure to unequip everything at once, and only fire the change event + // (which will rebuild the animation parts) afterwards. unequipAll will do this for us. + MWWorld::InventoryStore& invStore = actor.getClass().getInventoryStore(actor); + invStore.unequipAll(actor); + + if(werewolf) + { + MWWorld::InventoryStore &inv = actor.getClass().getInventoryStore(actor); + + inv.equip(MWWorld::InventoryStore::Slot_Robe, inv.ContainerStore::add("werewolfrobe", 1, actor), actor); + } + else + { + actor.getClass().getContainerStore(actor).remove("werewolfrobe", 1, actor); + } + + if(actor == player->getPlayer()) + { + MWBase::Environment::get().getWorld()->reattachPlayerCamera(); + + // Update the GUI only when called on the player + MWBase::WindowManager* windowManager = MWBase::Environment::get().getWindowManager(); + + if (werewolf) + { + windowManager->forceHide(MWGui::GW_Inventory); + windowManager->forceHide(MWGui::GW_Magic); + } + else + { + windowManager->unsetForceHide(MWGui::GW_Inventory); + windowManager->unsetForceHide(MWGui::GW_Magic); + } + + windowManager->setWerewolfOverlay(werewolf); + + // Witnesses of the player's transformation will make them a globally known werewolf + std::vector closeActors; + const MWWorld::Store& gmst = MWBase::Environment::get().getWorld()->getStore().get(); + getActorsInRange(actor.getRefData().getPosition().asVec3(), gmst.find("fAlarmRadius")->getFloat(), closeActors); + + bool detected = false, reported = false; + for (std::vector::const_iterator it = closeActors.begin(); it != closeActors.end(); ++it) + { + if (*it == actor) + continue; + + if (!it->getClass().isNpc()) + continue; + + if (MWBase::Environment::get().getWorld()->getLOS(*it, actor) && awarenessCheck(actor, *it)) + detected = true; + if (it->getClass().getCreatureStats(*it).getAiSetting(MWMechanics::CreatureStats::AI_Alarm).getModified() > 0) + reported = true; + } + + if (detected) + { + windowManager->messageBox("#{sWerewolfAlarmMessage}"); + MWBase::Environment::get().getWorld()->setGlobalInt("pcknownwerewolf", 1); + + if (reported) + { + npcStats.setBounty(npcStats.getBounty()+ + gmst.find("iWereWolfBounty")->getInt()); + windowManager->messageBox("#{sCrimeMessage}"); + } + } + } + } + + void MechanicsManager::applyWerewolfAcrobatics(const MWWorld::Ptr &actor) + { + const MWWorld::Store& gmst = MWBase::Environment::get().getWorld()->getStore().get(); + MWMechanics::NpcStats &stats = actor.getClass().getNpcStats(actor); + + stats.getSkill(ESM::Skill::Acrobatics).setBase(gmst.find("fWerewolfAcrobatics")->getInt()); + } + } diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index 603888adc..fb29c07ea 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -187,6 +187,9 @@ namespace MWMechanics /// @return is \a ptr allowed to take/use \a cellref or is it a crime? virtual bool isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::CellRef& cellref, MWWorld::Ptr& victim); + virtual void setWerewolf(const MWWorld::Ptr& actor, bool werewolf); + virtual void applyWerewolfAcrobatics(const MWWorld::Ptr& actor); + private: void reportCrime (const MWWorld::Ptr& ptr, const MWWorld::Ptr& victim, OffenseType type, int arg=0); diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index 2a504f2ab..cdf60d329 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -1096,7 +1096,7 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { MWWorld::Ptr ptr = R()(runtime); - MWBase::Environment::get().getWorld()->setWerewolf(ptr, set); + MWBase::Environment::get().getMechanicsManager()->setWerewolf(ptr, set); } }; @@ -1108,7 +1108,7 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { MWWorld::Ptr ptr = R()(runtime); - MWBase::Environment::get().getWorld()->applyWerewolfAcrobatics(ptr); + MWBase::Environment::get().getMechanicsManager()->applyWerewolfAcrobatics(ptr); } }; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index c2c8e5833..15826009d 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2453,111 +2453,6 @@ namespace MWWorld mRendering->rebuildPtr(getPlayerPtr()); } - void World::setWerewolf(const MWWorld::Ptr& actor, bool werewolf) - { - MWMechanics::NpcStats& npcStats = actor.getClass().getNpcStats(actor); - - // The actor does not have to change state - if (npcStats.isWerewolf() == werewolf) - return; - - if (actor == getPlayerPtr()) - { - if (werewolf) - { - mPlayer->saveSkillsAttributes(); - mPlayer->setWerewolfSkillsAttributes(); - } - else - mPlayer->restoreSkillsAttributes(); - } - - npcStats.setWerewolf(werewolf); - - // This is a bit dangerous. Equipped items other than WerewolfRobe may reference - // bones that do not even exist with the werewolf object root. - // Therefore, make sure to unequip everything at once, and only fire the change event - // (which will rebuild the animation parts) afterwards. unequipAll will do this for us. - MWWorld::InventoryStore& invStore = actor.getClass().getInventoryStore(actor); - invStore.unequipAll(actor); - - if(werewolf) - { - InventoryStore &inv = actor.getClass().getInventoryStore(actor); - - inv.equip(InventoryStore::Slot_Robe, inv.ContainerStore::add("werewolfrobe", 1, actor), actor); - } - else - { - actor.getClass().getContainerStore(actor).remove("werewolfrobe", 1, actor); - } - - // NpcAnimation::updateParts will already rebuild the animation when it detects change of Npc type. - // the following is just for reattaching the camera properly. - mRendering->rebuildPtr(actor); - - if(actor == getPlayerPtr()) - { - // Update the GUI only when called on the player - MWBase::WindowManager* windowManager = MWBase::Environment::get().getWindowManager(); - - if (werewolf) - { - windowManager->forceHide(MWGui::GW_Inventory); - windowManager->forceHide(MWGui::GW_Magic); - } - else - { - windowManager->unsetForceHide(MWGui::GW_Inventory); - windowManager->unsetForceHide(MWGui::GW_Magic); - } - - windowManager->setWerewolfOverlay(werewolf); - - // Witnesses of the player's transformation will make them a globally known werewolf - std::vector closeActors; - MWBase::Environment::get().getMechanicsManager()->getActorsInRange(actor.getRefData().getPosition().asVec3(), - getStore().get().search("fAlarmRadius")->getFloat(), - closeActors); - - bool detected = false, reported = false; - for (std::vector::const_iterator it = closeActors.begin(); it != closeActors.end(); ++it) - { - if (*it == actor) - continue; - - if (!it->getClass().isNpc()) - continue; - - if (getLOS(*it, actor) && MWBase::Environment::get().getMechanicsManager()->awarenessCheck(actor, *it)) - detected = true; - if (it->getClass().getCreatureStats(*it).getAiSetting(MWMechanics::CreatureStats::AI_Alarm).getModified() > 0) - reported = true; - } - - if (detected) - { - windowManager->messageBox("#{sWerewolfAlarmMessage}"); - setGlobalInt("pcknownwerewolf", 1); - - if (reported) - { - npcStats.setBounty(npcStats.getBounty()+ - mStore.get().find("iWereWolfBounty")->getInt()); - windowManager->messageBox("#{sCrimeMessage}"); - } - } - } - } - - void World::applyWerewolfAcrobatics(const Ptr &actor) - { - const Store &gmst = getStore().get(); - MWMechanics::NpcStats &stats = actor.getClass().getNpcStats(actor); - - stats.getSkill(ESM::Skill::Acrobatics).setBase(gmst.find("fWerewolfAcrobatics")->getInt()); - } - bool World::getGodModeState() { return mGodMode; diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index ceda1321a..4ed97759e 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -560,10 +560,6 @@ namespace MWWorld /// Returns true if levitation spell effect is allowed. virtual bool isLevitationEnabled() const; - virtual void setWerewolf(const MWWorld::Ptr& actor, bool werewolf); - - virtual void applyWerewolfAcrobatics(const MWWorld::Ptr& actor); - virtual bool getGodModeState(); virtual bool toggleGodMode(); From 6b67911658f7813419cff9e1d0588f9e50a26f51 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 26 Dec 2015 18:26:55 +0100 Subject: [PATCH 2932/3725] Unset DrawState_Spell when becoming a werewolf --- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index f88d27fce..b98e5daa3 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1607,15 +1607,18 @@ namespace MWMechanics player->restoreSkillsAttributes(); } - npcStats.setWerewolf(werewolf); - - // This is a bit dangerous. Equipped items other than WerewolfRobe may reference - // bones that do not even exist with the werewolf object root. - // Therefore, make sure to unequip everything at once, and only fire the change event - // (which will rebuild the animation parts) afterwards. unequipAll will do this for us. + // Equipped items other than WerewolfRobe may reference bones that do not even + // exist with the werewolf object root, so make sure to unequip all items + // *before* we become a werewolf. MWWorld::InventoryStore& invStore = actor.getClass().getInventoryStore(actor); invStore.unequipAll(actor); + // Werewolfs can not cast spells, so we need to unset the prepared spell if there is one. + if (npcStats.getDrawState() == MWMechanics::DrawState_Spell) + npcStats.setDrawState(MWMechanics::DrawState_Nothing); + + npcStats.setWerewolf(werewolf); + if(werewolf) { MWWorld::InventoryStore &inv = actor.getClass().getInventoryStore(actor); From 0bec6e5fbefe6017c757b36e07192c8f9a7c8b19 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 26 Dec 2015 18:45:09 +0100 Subject: [PATCH 2933/3725] Fix 'failed to find animation' warnings when a spell was equipped before the werewolf transformation --- apps/openmw/mwmechanics/character.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index ba6a8fe4b..db1b82ba6 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -520,6 +520,8 @@ void getWeaponGroup(WeaponType weaptype, std::string &group) const WeaponInfo *info = std::find_if(sWeaponTypeList, sWeaponTypeListEnd, FindWeaponType(weaptype)); if(info != sWeaponTypeListEnd) group = info->longgroup; + else + group.clear(); } @@ -1092,11 +1094,14 @@ bool CharacterController::updateWeaponState() std::string weapgroup; if(weaptype == WeapType_None) { - getWeaponGroup(mWeaponType, weapgroup); - mAnimation->play(weapgroup, priorityWeapon, - MWRender::Animation::BlendMask_All, true, - 1.0f, "unequip start", "unequip stop", 0.0f, 0); - mUpperBodyState = UpperCharState_UnEquipingWeap; + if ((!isWerewolf || mWeaponType != WeapType_Spell)) + { + getWeaponGroup(mWeaponType, weapgroup); + mAnimation->play(weapgroup, priorityWeapon, + MWRender::Animation::BlendMask_All, true, + 1.0f, "unequip start", "unequip stop", 0.0f, 0); + mUpperBodyState = UpperCharState_UnEquipingWeap; + } } else { From 63b9b075aa3e4c759a3d9d27d6a69426116b1e5b Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 26 Dec 2015 18:47:03 +0100 Subject: [PATCH 2934/3725] Do not allow soul trapping the same creature more than once (Fixes #3102) --- apps/openmw/mwmechanics/actors.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 7f857a700..4046010d7 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -149,14 +149,20 @@ namespace MWMechanics { MWWorld::Ptr mCreature; MWWorld::Ptr mActor; + bool mTrapped; public: SoulTrap(MWWorld::Ptr trappedCreature) - : mCreature(trappedCreature) {} + : mCreature(trappedCreature) + , mTrapped(false) + { + } virtual void visit (MWMechanics::EffectKey key, const std::string& sourceName, const std::string& sourceId, int casterActorId, float magnitude, float remainingTime = -1, float totalTime = -1) { + if (mTrapped) + return; if (key.mId != ESM::MagicEffect::Soultrap) return; if (magnitude <= 0) @@ -203,6 +209,8 @@ namespace MWMechanics gem->getContainerStore()->unstack(*gem, caster); gem->getCellRef().setSoul(mCreature.getCellRef().getRefId()); + mTrapped = true; + if (caster == getPlayer()) MWBase::Environment::get().getWindowManager()->messageBox("#{sSoultrapSuccess}"); From 1ac091e5b5c0200356bdb50e3d23fe606f834703 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Sun, 27 Dec 2015 20:00:52 +0100 Subject: [PATCH 2935/3725] Quick appveyor.yml cleanup --- appveyor.yml | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 28df364df..1bc0d3ca6 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -2,6 +2,8 @@ version: "{build}" branches: only: + - master + - /openmw-.*$/ - appveyor platform: @@ -13,9 +15,11 @@ configuration: Debug matrix: fast_finish: true +# For the Qt, Boost, CMake, etc installs os: unstable -#shallow_clone: true +# We want the git revision for versioning, +# so shallow clones don't work. clone_depth: 1 cache: @@ -41,3 +45,10 @@ build_script: - cmd: msbuild %build%\OpenMW.sln /t:Build /p:Configuration=%configuration% /m:2 /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" test: off + +#notifications: +# - provider: Email +# to: +# - +# on_build_failure: true +# on_build_status_changed: true From d5196ac4fc3ea94646023e1ee0c59a9eeac39c55 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Sun, 27 Dec 2015 20:05:37 +0100 Subject: [PATCH 2936/3725] Let's throw in a build badge too --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f353cd76e..585805368 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ OpenMW ====== -[![Build Status](https://img.shields.io/travis/OpenMW/openmw.svg)](https://travis-ci.org/OpenMW/openmw) [![Coverity Scan Build Status](https://scan.coverity.com/projects/3740/badge.svg)](https://scan.coverity.com/projects/3740) +[![Build Status](https://img.shields.io/travis/OpenMW/openmw.svg)](https://travis-ci.org/OpenMW/openmw) [![Build status](https://ci.appveyor.com/api/projects/status/e6bqw8oouy8ufd46?svg=true)](https://ci.appveyor.com/project/ace13/openmw) [![Coverity Scan Build Status](https://scan.coverity.com/projects/3740/badge.svg)](https://scan.coverity.com/projects/3740) OpenMW is a recreation of 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. From 05335491ac82a78f1fe050f3b84478df0e61442d Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Mon, 28 Dec 2015 05:42:21 +0100 Subject: [PATCH 2937/3725] Build without unity builds, how far will we get? --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 1bc0d3ca6..3e3de6780 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -37,7 +37,7 @@ cache: clone_folder: C:\projects\openmw before_build: - - cmd: sh %APPVEYOR_BUILD_FOLDER%\CI\before_script.msvc.sh -u -p %PLATFORM% + - cmd: sh %APPVEYOR_BUILD_FOLDER%\CI\before_script.msvc.sh -p %PLATFORM% build_script: - cmd: if %PLATFORM%==Win32 set build=Build_32 From 42e3ff6f962dc68296b12ee693871d7f9201cc07 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Mon, 28 Dec 2015 09:01:08 +0100 Subject: [PATCH 2938/3725] Revert "Build without unity builds, how far will we get?" This reverts commit 05335491ac82a78f1fe050f3b84478df0e61442d. --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 3e3de6780..1bc0d3ca6 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -37,7 +37,7 @@ cache: clone_folder: C:\projects\openmw before_build: - - cmd: sh %APPVEYOR_BUILD_FOLDER%\CI\before_script.msvc.sh -p %PLATFORM% + - cmd: sh %APPVEYOR_BUILD_FOLDER%\CI\before_script.msvc.sh -u -p %PLATFORM% build_script: - cmd: if %PLATFORM%==Win32 set build=Build_32 From 7f7e8c63bf645e44930ef788b88a7f554de672ba Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 31 Dec 2015 00:37:47 +0100 Subject: [PATCH 2939/3725] Correct path to gamecontrollerdb.txt (Fixes #3112) --- apps/openmw/engine.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index b43fd2f53..3fcd46f7c 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -474,8 +474,8 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) } // find correct path to the game controller bindings - const std::string localdefault = mCfgMgr.getLocalPath().string() + "/gamecontrollerdb.cfg"; - const std::string globaldefault = mCfgMgr.getGlobalPath().string() + "/gamecontrollerdb.cfg"; + const std::string localdefault = mCfgMgr.getLocalPath().string() + "/gamecontrollerdb.txt"; + const std::string globaldefault = mCfgMgr.getGlobalPath().string() + "/gamecontrollerdb.txt"; std::string gameControllerdb; if (boost::filesystem::exists(localdefault)) gameControllerdb = localdefault; From 6fde02ea426ee583ece2c3d22a4d6717adcd9eb2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 29 Dec 2015 15:22:19 +0100 Subject: [PATCH 2940/3725] LocalScripts: initialize mIter --- apps/openmw/mwworld/localscripts.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/localscripts.cpp b/apps/openmw/mwworld/localscripts.cpp index 46d0b3cc2..2004a2ff3 100644 --- a/apps/openmw/mwworld/localscripts.cpp +++ b/apps/openmw/mwworld/localscripts.cpp @@ -61,7 +61,10 @@ namespace } -MWWorld::LocalScripts::LocalScripts (const MWWorld::ESMStore& store) : mStore (store) {} +MWWorld::LocalScripts::LocalScripts (const MWWorld::ESMStore& store) : mStore (store) +{ + mIter = mScripts.end(); +} void MWWorld::LocalScripts::setIgnore (const ConstPtr& ptr) { From 0333c4004733d3df5ed2fe81cc95b28dcbfe781b Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 1 Jan 2016 02:59:14 +0100 Subject: [PATCH 2941/3725] Fix typo in SameRace dialogue function (function was inverted, Fixes #3116) --- apps/openmw/mwdialogue/filter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index 43d979ea2..ce07593e6 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -478,7 +478,7 @@ bool MWDialogue::Filter::getSelectStructBoolean (const SelectWrapper& select) co case SelectWrapper::Function_SameRace: - return !Misc::StringUtils::ciEqual(mActor.get()->mBase->mRace, player.get()->mBase->mRace); + return Misc::StringUtils::ciEqual(mActor.get()->mBase->mRace, player.get()->mBase->mRace); case SelectWrapper::Function_SameFaction: From a9f0f30bb879a2197d9abc9f65d74673bead6e51 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 1 Jan 2016 23:55:17 +0100 Subject: [PATCH 2942/3725] Reject conditions testing agaist Choice when not currently in a choice (Fixes #3117) --- apps/openmw/mwdialogue/filter.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index ce07593e6..69df38ccf 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -155,10 +155,13 @@ bool MWDialogue::Filter::testDisposition (const ESM::DialInfo& info, bool invert bool MWDialogue::Filter::testSelectStruct (const SelectWrapper& select) const { if (select.isNpcOnly() && (mActor.getTypeName() != typeid (ESM::NPC).name())) - // If the actor is a creature, we do not test the conditions applicable - // only to NPCs. + // If the actor is a creature, we pass all conditions only applicable to NPCs. return true; + if (select.getFunction() == SelectWrapper::Function_Choice && mChoice == -1) + // If not currently in a choice, we reject all conditions that test against choices. + return false; + switch (select.getType()) { case SelectWrapper::Type_None: return true; From 1905f0bf2dd8bb9000c033f89564ff3cac14f7ed Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 2 Jan 2016 00:49:53 +0100 Subject: [PATCH 2943/3725] Add support for placing BodyParts in a cell (Bug #3118) --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwclass/bodypart.cpp | 52 +++++++++++++++++++++++++++++++ apps/openmw/mwclass/bodypart.hpp | 31 ++++++++++++++++++ apps/openmw/mwclass/classes.cpp | 2 ++ apps/openmw/mwworld/cellstore.cpp | 7 +++++ apps/openmw/mwworld/cellstore.hpp | 10 ++++++ apps/openmw/mwworld/esmstore.cpp | 3 +- apps/openmw/mwworld/manualref.cpp | 1 + 8 files changed, 106 insertions(+), 2 deletions(-) create mode 100644 apps/openmw/mwclass/bodypart.cpp create mode 100644 apps/openmw/mwclass/bodypart.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 0113fed02..02cf6c87d 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -75,7 +75,7 @@ add_openmw_dir (mwphysics add_openmw_dir (mwclass classes activator creature npc weapon armor potion apparatus book clothing container door - ingredient creaturelevlist itemlevlist light lockpick misc probe repair static actor + ingredient creaturelevlist itemlevlist light lockpick misc probe repair static actor bodypart ) add_openmw_dir (mwmechanics diff --git a/apps/openmw/mwclass/bodypart.cpp b/apps/openmw/mwclass/bodypart.cpp new file mode 100644 index 000000000..be2b927cc --- /dev/null +++ b/apps/openmw/mwclass/bodypart.cpp @@ -0,0 +1,52 @@ +#include "bodypart.hpp" + +#include "../mwrender/renderinginterface.hpp" +#include "../mwrender/objects.hpp" + +#include "../mwworld/cellstore.hpp" + +namespace MWClass +{ + + MWWorld::Ptr BodyPart::copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const + { + const MWWorld::LiveCellRef *ref = ptr.get(); + + return MWWorld::Ptr(cell.insert(ref), &cell); + } + + void BodyPart::insertObjectRendering(const MWWorld::Ptr &ptr, const std::string &model, MWRender::RenderingInterface &renderingInterface) const + { + if (!model.empty()) { + renderingInterface.getObjects().insertModel(ptr, model); + } + } + + void BodyPart::insertObject(const MWWorld::Ptr &ptr, const std::string &model, MWPhysics::PhysicsSystem &physics) const + { + } + + std::string BodyPart::getName(const MWWorld::ConstPtr &ptr) const + { + return std::string(); + } + + void BodyPart::registerSelf() + { + boost::shared_ptr instance (new BodyPart); + + registerClass (typeid (ESM::BodyPart).name(), instance); + } + + std::string BodyPart::getModel(const MWWorld::ConstPtr &ptr) const + { + const MWWorld::LiveCellRef *ref = ptr.get(); + + const std::string &model = ref->mBase->mModel; + if (!model.empty()) { + return "meshes\\" + model; + } + return ""; + } + +} diff --git a/apps/openmw/mwclass/bodypart.hpp b/apps/openmw/mwclass/bodypart.hpp new file mode 100644 index 000000000..79c7c860d --- /dev/null +++ b/apps/openmw/mwclass/bodypart.hpp @@ -0,0 +1,31 @@ +#ifndef GAME_MWCLASS_BODYPART_H +#define GAME_MWCLASS_BODYPART_H + +#include "../mwworld/class.hpp" + +namespace MWClass +{ + + class BodyPart : public MWWorld::Class + { + virtual MWWorld::Ptr copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const; + + public: + + virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; + ///< Add reference into a cell for rendering + + virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; + + virtual std::string getName (const MWWorld::ConstPtr& ptr) const; + ///< \return name (the one that is to be presented to the user; not the internal one); + /// can return an empty string. + + static void registerSelf(); + + virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; + }; + +} + +#endif diff --git a/apps/openmw/mwclass/classes.cpp b/apps/openmw/mwclass/classes.cpp index c303b23af..a552dfebf 100644 --- a/apps/openmw/mwclass/classes.cpp +++ b/apps/openmw/mwclass/classes.cpp @@ -20,6 +20,7 @@ #include "probe.hpp" #include "repair.hpp" #include "static.hpp" +#include "bodypart.hpp" namespace MWClass { @@ -45,5 +46,6 @@ namespace MWClass Probe::registerSelf(); Repair::registerSelf(); Static::registerSelf(); + BodyPart::registerSelf(); } } diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 08f272ea2..5b53643e8 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -591,6 +591,7 @@ namespace MWWorld case ESM::REC_REPA: mRepairs.load(ref, deleted, store); break; case ESM::REC_STAT: mStatics.load(ref, deleted, store); break; case ESM::REC_WEAP: mWeapons.load(ref, deleted, store); break; + case ESM::REC_BODY: mBodyParts.load(ref, deleted, store); break; case 0: std::cerr << "Cell reference " + ref.mRefID + " not found!\n"; break; @@ -659,6 +660,7 @@ namespace MWWorld writeReferenceCollection (writer, mRepairs); writeReferenceCollection (writer, mStatics); writeReferenceCollection (writer, mWeapons); + writeReferenceCollection (writer, mBodyParts); for (MovedRefTracker::const_iterator it = mMovedToAnotherCell.begin(); it != mMovedToAnotherCell.end(); ++it) { @@ -794,6 +796,11 @@ namespace MWWorld readReferenceCollection (reader, mWeapons, cref, contentFileMap); break; + case ESM::REC_BODY: + + readReferenceCollection (reader, mBodyParts, cref, contentFileMap); + break; + default: throw std::runtime_error ("unknown type in cell reference section"); diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index 27fe9ec03..faba76262 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -31,6 +31,7 @@ #include #include #include +#include #include "../mwmechanics/pathgrid.hpp" // TODO: maybe belongs in mwworld @@ -97,6 +98,7 @@ namespace MWWorld CellRefList mRepairs; CellRefList mStatics; CellRefList mWeapons; + CellRefList mBodyParts; typedef std::map MovedRefTracker; // References owned by a different cell that have been moved here. @@ -152,6 +154,7 @@ namespace MWWorld forEachImp (visitor, mRepairs) && forEachImp (visitor, mStatics) && forEachImp (visitor, mWeapons) && + forEachImp (visitor, mBodyParts) && forEachImp (visitor, mCreatures) && forEachImp (visitor, mNpcs) && forEachImp (visitor, mCreatureLists); @@ -518,6 +521,13 @@ namespace MWWorld return mWeapons; } + template<> + inline CellRefList& CellStore::get() + { + mHasState = true; + return mBodyParts; + } + bool operator== (const CellStore& left, const CellStore& right); bool operator!= (const CellStore& left, const CellStore& right); } diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index 1882c6e1a..7a1f222c7 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -19,7 +19,8 @@ static bool isCacheableRecord(int id) id == ESM::REC_BOOK || id == ESM::REC_CLOT || id == ESM::REC_CONT || id == ESM::REC_CREA || id == ESM::REC_DOOR || id == ESM::REC_INGR || id == ESM::REC_LEVC || id == ESM::REC_LEVI || id == ESM::REC_LIGH || id == ESM::REC_LOCK || id == ESM::REC_MISC || id == ESM::REC_NPC_ || - id == ESM::REC_PROB || id == ESM::REC_REPA || id == ESM::REC_STAT || id == ESM::REC_WEAP) + id == ESM::REC_PROB || id == ESM::REC_REPA || id == ESM::REC_STAT || id == ESM::REC_WEAP || + id == ESM::REC_BODY) { return true; } diff --git a/apps/openmw/mwworld/manualref.cpp b/apps/openmw/mwworld/manualref.cpp index d6e40ad09..c683f7e03 100644 --- a/apps/openmw/mwworld/manualref.cpp +++ b/apps/openmw/mwworld/manualref.cpp @@ -54,6 +54,7 @@ MWWorld::ManualRef::ManualRef(const MWWorld::ESMStore& store, const std::string& case ESM::REC_REPA: create(store.get(), lowerName, mRef, mPtr); break; case ESM::REC_STAT: create(store.get(), lowerName, mRef, mPtr); break; case ESM::REC_WEAP: create(store.get(), lowerName, mRef, mPtr); break; + case ESM::REC_BODY: create(store.get(), lowerName, mRef, mPtr); break; case 0: throw std::logic_error("failed to create manual cell ref for " + lowerName + " (unknown ID)"); From 3ebfb479830c02ba1172de99341670f314c4d443 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 2 Jan 2016 01:12:44 +0100 Subject: [PATCH 2944/3725] Do not discard root node transformations if the root node is named 'bip01' (Bug #3118) --- components/nif/node.hpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/components/nif/node.hpp b/components/nif/node.hpp index 326e9802f..17b58bd46 100644 --- a/components/nif/node.hpp +++ b/components/nif/node.hpp @@ -9,6 +9,8 @@ #include "controller.hpp" #include "base.hpp" +#include + namespace Nif { @@ -118,10 +120,10 @@ struct NiNode : Node children.read(nif); effects.read(nif); - // Discard tranformations for the root node, otherwise some meshes + // Discard transformations for the root node, otherwise some meshes // occasionally get wrong orientation. Only for NiNode-s for now, but // can be expanded if needed. - if (0 == recIndex) + if (0 == recIndex && !Misc::StringUtils::ciEqual(name, "bip01")) { static_cast(this)->trafo = Nif::Transformation::getIdentity(); } From b1020dcd42798fc024a4660e7698ea88840337b7 Mon Sep 17 00:00:00 2001 From: Poncho Date: Sat, 2 Jan 2016 12:24:39 -0600 Subject: [PATCH 2945/3725] Use correct direction multipliers during awareness check --- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index b98e5daa3..b8dc90cf7 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1435,7 +1435,7 @@ namespace MWMechanics osg::Vec3f observerDir = (observer.getRefData().getBaseNode()->getAttitude() * osg::Vec3f(0,1,0)); float angleRadians = std::acos(observerDir * vec / (observerDir.length() * vec.length())); - if (angleRadians < osg::DegreesToRadians(90.f)) + if (angleRadians > osg::DegreesToRadians(90.f)) y = obsTerm * observerStats.getFatigueTerm() * fSneakNoViewMult; else y = obsTerm * observerStats.getFatigueTerm() * fSneakViewMult; From ded0962130e14fb16a358a7ac2013601d6c59417 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 2 Jan 2016 20:52:22 +0100 Subject: [PATCH 2946/3725] Update AUTHORS.md --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index 292c1e9e3..d4927ea92 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -56,6 +56,7 @@ Programmers Jeffrey Haines (Jyby) Jengerer Jiří Kuneš (kunesj) + Joe Wilkerson (neuralroberts) Joel Graff (graffy) John Blomberg (fstp) Jordan Ayers From e695619aa5bfe5d8a80580fbd322fac653f0048b Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 3 Jan 2016 00:02:58 +0100 Subject: [PATCH 2947/3725] ExprParser: Warn about ignored arguments --- components/compiler/exprparser.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/components/compiler/exprparser.cpp b/components/compiler/exprparser.cpp index c0375b436..d35b08167 100644 --- a/components/compiler/exprparser.cpp +++ b/components/compiler/exprparser.cpp @@ -804,6 +804,8 @@ namespace Compiler if (optional) ++optionalCount; } + else + getErrorHandler().warning("Ignoring extra argument", mTokenLoc); } else if (*iter=='X') { @@ -815,6 +817,8 @@ namespace Compiler if (parser.isEmpty()) break; + else + getErrorHandler().warning("Ignoring extra argument", mTokenLoc); } else if (*iter=='z') { @@ -825,6 +829,8 @@ namespace Compiler if (discardParser.isEmpty()) break; + else + getErrorHandler().warning("Ignoring extra argument", mTokenLoc); } else if (*iter=='j') { From 23cd2056bf838a07bb67ffdb9eda5081c9ae9c47 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 3 Jan 2016 00:03:41 +0100 Subject: [PATCH 2948/3725] Ignore extra arguments in playSound and playSound3D. A common mistake in mods is to use playSound with volume/pitch arguments, which only playSoundVP supports. Previously these extra arguments raised a parser error, making the respective mod unusable. --- components/compiler/extensions0.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/compiler/extensions0.cpp b/components/compiler/extensions0.cpp index 8f7650191..8c76cdbb8 100644 --- a/components/compiler/extensions0.cpp +++ b/components/compiler/extensions0.cpp @@ -341,9 +341,9 @@ namespace Compiler extensions.registerInstruction ("say", "SS", opcodeSay, opcodeSayExplicit); extensions.registerFunction ("saydone", 'l', "", opcodeSayDone, opcodeSayDoneExplicit); extensions.registerInstruction ("streammusic", "S", opcodeStreamMusic); - extensions.registerInstruction ("playsound", "c", opcodePlaySound); + extensions.registerInstruction ("playsound", "cXX", opcodePlaySound); extensions.registerInstruction ("playsoundvp", "cff", opcodePlaySoundVP); - extensions.registerInstruction ("playsound3d", "c", opcodePlaySound3D, + extensions.registerInstruction ("playsound3d", "cXX", opcodePlaySound3D, opcodePlaySound3DExplicit); extensions.registerInstruction ("playsound3dvp", "cff", opcodePlaySound3DVP, opcodePlaySound3DVPExplicit); From ea0be6e737d29b60a987c301f1cfb66174b881ad Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 3 Jan 2016 00:08:05 +0100 Subject: [PATCH 2949/3725] Update ScriptArgs documentation --- components/compiler/extensions.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/compiler/extensions.hpp b/components/compiler/extensions.hpp index 9fb9bdb95..2adf25a57 100644 --- a/components/compiler/extensions.hpp +++ b/components/compiler/extensions.hpp @@ -20,9 +20,9 @@ namespace Compiler l - Integer
    s - Short
    S - String, case preserved
    - x - Optional, ignored string argument - X - Optional, ignored numeric expression - z - Optional, ignored string or numeric argument + x - Optional, ignored string argument. Emits a parser warning when this argument is supplied.
    + X - Optional, ignored numeric expression. Emits a parser warning when this argument is supplied.
    + z - Optional, ignored string or numeric argument. Emits a parser warning when this argument is supplied.
    j - A piece of junk (either . or a specific keyword) **/ typedef std::string ScriptArgs; From 0597c8fd9c748b0da4c6df76530e16176266d17d Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 3 Jan 2016 16:43:20 +0100 Subject: [PATCH 2950/3725] Pass a Vec4f by reference --- components/sceneutil/lightcontroller.cpp | 2 +- components/sceneutil/lightcontroller.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/components/sceneutil/lightcontroller.cpp b/components/sceneutil/lightcontroller.cpp index 511937a28..e3ea93843 100644 --- a/components/sceneutil/lightcontroller.cpp +++ b/components/sceneutil/lightcontroller.cpp @@ -125,7 +125,7 @@ namespace SceneUtil traverse(node, nv); } - void LightController::setDiffuse(osg::Vec4f color) + void LightController::setDiffuse(const osg::Vec4f& color) { mDiffuseColor = color; } diff --git a/components/sceneutil/lightcontroller.hpp b/components/sceneutil/lightcontroller.hpp index f6e2fa9fa..8f70af343 100644 --- a/components/sceneutil/lightcontroller.hpp +++ b/components/sceneutil/lightcontroller.hpp @@ -24,7 +24,7 @@ namespace SceneUtil void setType(LightType type); - void setDiffuse(osg::Vec4f color); + void setDiffuse(const osg::Vec4f& color); virtual void operator()(osg::Node* node, osg::NodeVisitor* nv); From daa94cc50e46038ffde0f93a816ccc5c0ff55af8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 3 Jan 2016 18:20:34 +0100 Subject: [PATCH 2951/3725] Fix cppcheck warnings --- apps/essimporter/importer.cpp | 2 +- apps/mwiniimporter/importer.cpp | 10 ++++++++-- apps/opencs/model/doc/loader.cpp | 3 +-- apps/opencs/model/tools/magiceffectcheck.cpp | 2 +- apps/opencs/model/tools/search.cpp | 9 +++++---- apps/opencs/model/tools/soundgencheck.cpp | 2 +- apps/opencs/model/world/nestedcoladapterimp.cpp | 6 +++--- apps/opencs/model/world/refidadapterimp.cpp | 6 +++--- apps/opencs/view/world/datadisplaydelegate.cpp | 2 +- apps/opencs/view/world/datadisplaydelegate.hpp | 2 +- apps/opencs/view/world/dialoguesubview.cpp | 2 -- apps/openmw/mwmechanics/aicombat.cpp | 1 - apps/openmw/mwmechanics/aifollow.cpp | 4 +++- apps/openmw/mwphysics/physicssystem.cpp | 3 +++ apps/openmw/mwrender/sky.cpp | 2 +- components/contentselector/model/contentmodel.cpp | 3 +-- components/contentselector/model/loadordererror.hpp | 7 ++----- components/myguiplatform/myguiplatform.hpp | 3 +++ components/nifosg/controller.cpp | 2 +- components/sceneutil/riggeometry.cpp | 2 +- components/sceneutil/workqueue.cpp | 4 ++-- 21 files changed, 42 insertions(+), 35 deletions(-) diff --git a/apps/essimporter/importer.cpp b/apps/essimporter/importer.cpp index 4fbf06217..3d94f2b90 100644 --- a/apps/essimporter/importer.cpp +++ b/apps/essimporter/importer.cpp @@ -54,7 +54,7 @@ namespace *(image->data(x,y)+2) = *it++; *(image->data(x,y)+1) = *it++; *image->data(x,y) = *it++; - it++; // skip alpha + ++it; // skip alpha } } diff --git a/apps/mwiniimporter/importer.cpp b/apps/mwiniimporter/importer.cpp index f90ba4184..f2fcdb711 100644 --- a/apps/mwiniimporter/importer.cpp +++ b/apps/mwiniimporter/importer.cpp @@ -1,5 +1,6 @@ #include "importer.hpp" +#include #include #include #include @@ -897,8 +898,13 @@ std::time_t MwIniImporter::lastWriteTime(const boost::filesystem::path& filename boost::filesystem::path resolved = filename; #endif writeTime = boost::filesystem::last_write_time(resolved); - std::cout << "content file: " << resolved << " timestamp = (" << writeTime << - ") " << asctime(localtime(&writeTime)) << std::endl; + + // print timestamp + const int size=1024; + char timeStrBuffer[size]; + if (std::strftime(timeStrBuffer, size, "%x %X", localtime(&writeTime)) > 0) + std::cout << "content file: " << resolved << " timestamp = (" << writeTime << + ") " << timeStrBuffer << std::endl; } else { diff --git a/apps/opencs/model/doc/loader.cpp b/apps/opencs/model/doc/loader.cpp index cb3ff2cd0..166e6f3db 100644 --- a/apps/opencs/model/doc/loader.cpp +++ b/apps/opencs/model/doc/loader.cpp @@ -45,13 +45,12 @@ void CSMDoc::Loader::load() bool done = false; - const int batchingSize = 50; - try { if (iter->second.mRecordsLeft) { Messages messages (Message::Severity_Error); + const int batchingSize = 50; for (int i=0; igetData().continueLoading (messages)) { diff --git a/apps/opencs/model/tools/magiceffectcheck.cpp b/apps/opencs/model/tools/magiceffectcheck.cpp index 5435881b3..ab8b3b68b 100644 --- a/apps/opencs/model/tools/magiceffectcheck.cpp +++ b/apps/opencs/model/tools/magiceffectcheck.cpp @@ -7,7 +7,7 @@ namespace { - void addMessageIfNotEmpty(CSMDoc::Messages &messages, const CSMWorld::UniversalId &id, const std::string text) + void addMessageIfNotEmpty(CSMDoc::Messages &messages, const CSMWorld::UniversalId &id, const std::string& text) { if (!text.empty()) { diff --git a/apps/opencs/model/tools/search.cpp b/apps/opencs/model/tools/search.cpp index 0409199af..0c068ba11 100644 --- a/apps/opencs/model/tools/search.cpp +++ b/apps/opencs/model/tools/search.cpp @@ -120,24 +120,25 @@ QString CSMTools::Search::flatten (const QString& text) const return flat; } -CSMTools::Search::Search() : mType (Type_None), mPaddingBefore (10), mPaddingAfter (10) {} +CSMTools::Search::Search() : mType (Type_None), mValue (0), mIdColumn (0), mTypeColumn (0), + mPaddingBefore (10), mPaddingAfter (10) {} CSMTools::Search::Search (Type type, const std::string& value) -: mType (type), mText (value), mPaddingBefore (10), mPaddingAfter (10) +: mType (type), mText (value), mValue (0), mIdColumn (0), mTypeColumn (0), mPaddingBefore (10), mPaddingAfter (10) { if (type!=Type_Text && type!=Type_Id) throw std::logic_error ("Invalid search parameter (string)"); } CSMTools::Search::Search (Type type, const QRegExp& value) -: mType (type), mRegExp (value), mPaddingBefore (10), mPaddingAfter (10) +: mType (type), mRegExp (value), mValue (0), mIdColumn (0), mTypeColumn (0), mPaddingBefore (10), mPaddingAfter (10) { if (type!=Type_TextRegEx && type!=Type_IdRegEx) throw std::logic_error ("Invalid search parameter (RegExp)"); } CSMTools::Search::Search (Type type, int value) -: mType (type), mValue (value), mPaddingBefore (10), mPaddingAfter (10) +: mType (type), mValue (value), mIdColumn (0), mTypeColumn (0), mPaddingBefore (10), mPaddingAfter (10) { if (type!=Type_RecordState) throw std::logic_error ("invalid search parameter (int)"); diff --git a/apps/opencs/model/tools/soundgencheck.cpp b/apps/opencs/model/tools/soundgencheck.cpp index bdf89f19d..a36c494a1 100644 --- a/apps/opencs/model/tools/soundgencheck.cpp +++ b/apps/opencs/model/tools/soundgencheck.cpp @@ -26,7 +26,7 @@ void CSMTools::SoundGenCheckStage::perform(int stage, CSMDoc::Messages &messages return; } - const ESM::SoundGenerator soundGen = record.get(); + const ESM::SoundGenerator& soundGen = record.get(); CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_SoundGen, soundGen.mId); if (!soundGen.mCreature.empty()) diff --git a/apps/opencs/model/world/nestedcoladapterimp.cpp b/apps/opencs/model/world/nestedcoladapterimp.cpp index bfacc15dc..92b4b9e62 100644 --- a/apps/opencs/model/world/nestedcoladapterimp.cpp +++ b/apps/opencs/model/world/nestedcoladapterimp.cpp @@ -277,7 +277,7 @@ namespace CSMWorld // WARNING: Assumed that the table view has the same order as std::map std::map::iterator iter = reactions.begin(); for(int i = 0; i < rowToRemove; ++i) - iter++; + ++iter; reactions.erase(iter); record.setModified (faction); @@ -314,7 +314,7 @@ namespace CSMWorld // WARNING: Assumed that the table view has the same order as std::map std::map::const_iterator iter = reactions.begin(); for(int i = 0; i < subRowIndex; ++i) - iter++; + ++iter; switch (subColIndex) { case 0: return QString((*iter).first.c_str()); @@ -337,7 +337,7 @@ namespace CSMWorld // WARNING: Assumed that the table view has the same order as std::map std::map::iterator iter = reactions.begin(); for(int i = 0; i < subRowIndex; ++i) - iter++; + ++iter; std::string factionId = (*iter).first; int reaction = (*iter).second; diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index 90a710fc8..039624c84 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -1153,7 +1153,7 @@ QVariant CSMWorld::CreatureAttributesRefIdAdapter::getNestedData (const RefIdCol const Record& record = static_cast&> (data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Creature))); - const ESM::Creature creature = record.get(); + const ESM::Creature& creature = record.get(); if (subColIndex == 0) return subRowIndex; @@ -1259,7 +1259,7 @@ QVariant CSMWorld::CreatureAttackRefIdAdapter::getNestedData (const RefIdColumn const Record& record = static_cast&> (data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Creature))); - const ESM::Creature creature = record.get(); + const ESM::Creature& creature = record.get(); if (subRowIndex < 0 || subRowIndex > 2 || subColIndex < 0 || subColIndex > 2) throw std::runtime_error ("index out of range"); @@ -1337,7 +1337,7 @@ QVariant CSMWorld::CreatureMiscRefIdAdapter::getNestedData (const RefIdColumn *c const Record& record = static_cast&> (data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Creature))); - const ESM::Creature creature = record.get(); + const ESM::Creature& creature = record.get(); switch (subColIndex) { diff --git a/apps/opencs/view/world/datadisplaydelegate.cpp b/apps/opencs/view/world/datadisplaydelegate.cpp index 51d7137ec..9db16d593 100644 --- a/apps/opencs/view/world/datadisplaydelegate.cpp +++ b/apps/opencs/view/world/datadisplaydelegate.cpp @@ -140,7 +140,7 @@ void CSVWorld::DataDisplayDelegate::settingChanged (const CSMPrefs::Setting *set } -void CSVWorld::DataDisplayDelegateFactory::add (int enumValue, QString enumName, QString iconFilename) +void CSVWorld::DataDisplayDelegateFactory::add (int enumValue, const QString& enumName, const QString& iconFilename) { mIcons.push_back (std::make_pair(enumValue, QIcon(iconFilename))); EnumDelegateFactory::add(enumValue, enumName); diff --git a/apps/opencs/view/world/datadisplaydelegate.hpp b/apps/opencs/view/world/datadisplaydelegate.hpp index cde109fd4..540216d78 100755 --- a/apps/opencs/view/world/datadisplaydelegate.hpp +++ b/apps/opencs/view/world/datadisplaydelegate.hpp @@ -83,7 +83,7 @@ namespace CSVWorld protected: - void add (int enumValue,const QString enumName, const QString iconFilename); + void add (int enumValue, const QString& enumName, const QString& iconFilename); }; diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 25bd8e8ee..0a79aac2b 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -674,8 +674,6 @@ void CSVWorld::EditWidget::remake(int row) { mNestedTableMapper->addMapping (editor, col); - std::string disString = tree->nestedHeaderData (i, col, - Qt::Horizontal, Qt::DisplayRole).toString().toStdString(); // Need to use Qt::DisplayRole in order to get the correct string // from CSMWorld::Columns QLabel* label = new QLabel (tree->nestedHeaderData (i, col, diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 3cea00e45..3aeeedad1 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -305,7 +305,6 @@ namespace MWMechanics else { distantCombat = (rangeAttack > 500); - weapRange = 150.f; } diff --git a/apps/openmw/mwmechanics/aifollow.cpp b/apps/openmw/mwmechanics/aifollow.cpp index d9356da93..1430d42f2 100644 --- a/apps/openmw/mwmechanics/aifollow.cpp +++ b/apps/openmw/mwmechanics/aifollow.cpp @@ -129,12 +129,14 @@ bool AiFollow::execute (const MWWorld::Ptr& actor, CharacterController& characte ESM::Pathgrid::Point dest = target.getRefData().getPosition().pos; float dist = distance(dest, pos.pos[0], pos.pos[1], pos.pos[2]); - const float threshold = 10; if (storage.mMoving) //Stop when you get close storage.mMoving = (dist > followDistance); else + { + const float threshold = 10; storage.mMoving = (dist > followDistance + threshold); + } if(!storage.mMoving) { diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index f6883ae35..57bf7919a 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -506,6 +506,9 @@ namespace MWPhysics private: btHeightfieldTerrainShape* mShape; btCollisionObject* mCollisionObject; + + void operator=(const HeightField&); + HeightField(const HeightField&); }; // -------------------------------------------------------------- diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 20e3dc07c..635116db0 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -366,7 +366,7 @@ public: for (unsigned int i=0; isize(); ++i) { float alpha = 1.f; - if (mMeshType == 0) alpha = i%2 ? 0.f : 1.f; // this is a cylinder, so every second vertex belongs to the bottom-most row + if (mMeshType == 0) alpha = (i%2) ? 0.f : 1.f; // this is a cylinder, so every second vertex belongs to the bottom-most row else if (mMeshType == 1) { if (i>= 49 && i <= 64) alpha = 0.f; // bottom-most row diff --git a/components/contentselector/model/contentmodel.cpp b/components/contentselector/model/contentmodel.cpp index 8dc4351f6..26f0a4806 100644 --- a/components/contentselector/model/contentmodel.cpp +++ b/components/contentselector/model/contentmodel.cpp @@ -110,12 +110,11 @@ Qt::ItemFlags ContentSelectorModel::ContentModel::flags(const QModelIndex &index bool gamefileChecked = (file->gameFiles().count() == 0); foreach (const QString &fileName, file->gameFiles()) { - bool depFound = false; foreach (EsmFile *dependency, mFiles) { //compare filenames only. Multiple instances //of the filename (with different paths) is not relevant here. - depFound = (dependency->fileName().compare(fileName, Qt::CaseInsensitive) == 0); + bool depFound = (dependency->fileName().compare(fileName, Qt::CaseInsensitive) == 0); if (!depFound) continue; diff --git a/components/contentselector/model/loadordererror.hpp b/components/contentselector/model/loadordererror.hpp index 2b840cf69..7067f1f22 100644 --- a/components/contentselector/model/loadordererror.hpp +++ b/components/contentselector/model/loadordererror.hpp @@ -17,12 +17,9 @@ namespace ContentSelectorModel ErrorCode_LoadOrder = 3 }; - inline LoadOrderError() : mErrorCode(ErrorCode_None) {}; + inline LoadOrderError() : mErrorCode(ErrorCode_None) {} inline LoadOrderError(ErrorCode errorCode, QString fileName) - { - mErrorCode = errorCode; - mFileName = fileName; - } + : mErrorCode(errorCode), mFileName(fileName) {} inline ErrorCode errorCode() const { return mErrorCode; } inline QString fileName() const { return mFileName; } QString toolTip() const; diff --git a/components/myguiplatform/myguiplatform.hpp b/components/myguiplatform/myguiplatform.hpp index 56562e12a..90d45ce20 100644 --- a/components/myguiplatform/myguiplatform.hpp +++ b/components/myguiplatform/myguiplatform.hpp @@ -47,6 +47,9 @@ namespace osgMyGUI DataManager* mDataManager; MyGUI::LogManager* mLogManager; LogFacility* mLogFacility; + + void operator=(const Platform&); + Platform(const Platform&); }; } diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index 28f61e4b6..d0abc9ead 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -258,7 +258,7 @@ void UVController::apply(osg::StateSet* stateset, osg::NodeVisitor* nv) mat.setTrans(uTrans, vTrans, 0); // setting once is enough because all other texture units share the same TexMat (see setDefaults). - if (mTextureUnits.size()) + if (!mTextureUnits.empty()) { osg::TexMat* texMat = static_cast(stateset->getTextureAttribute(*mTextureUnits.begin(), osg::StateAttribute::TEXMAT)); texMat->setMatrix(mat); diff --git a/components/sceneutil/riggeometry.cpp b/components/sceneutil/riggeometry.cpp index 88b907faf..be8d97a4c 100644 --- a/components/sceneutil/riggeometry.cpp +++ b/components/sceneutil/riggeometry.cpp @@ -177,7 +177,7 @@ bool RigGeometry::initFromParentSkeleton(osg::NodeVisitor* nv) } } - for (Vertex2BoneMap::iterator it = vertex2BoneMap.begin(); it != vertex2BoneMap.end(); it++) + for (Vertex2BoneMap::iterator it = vertex2BoneMap.begin(); it != vertex2BoneMap.end(); ++it) { mBone2VertexMap[it->second].push_back(it->first); } diff --git a/components/sceneutil/workqueue.cpp b/components/sceneutil/workqueue.cpp index b642687f0..26a392be4 100644 --- a/components/sceneutil/workqueue.cpp +++ b/components/sceneutil/workqueue.cpp @@ -59,7 +59,7 @@ WorkQueue::~WorkQueue() { { OpenThreads::ScopedLock lock(mMutex); - while (mQueue.size()) + while (!mQueue.empty()) { WorkItem* item = mQueue.front(); delete item; @@ -88,7 +88,7 @@ osg::ref_ptr WorkQueue::addWorkItem(WorkItem *item) WorkItem *WorkQueue::removeWorkItem() { OpenThreads::ScopedLock lock(mMutex); - while (!mQueue.size() && !mIsReleased) + while (mQueue.empty() && !mIsReleased) { mCondition.wait(&mMutex); } From 6c676c861cad886b04f1da9c129e6b27315b6ea0 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 4 Jan 2016 18:03:47 +0100 Subject: [PATCH 2952/3725] increased version number --- CMakeLists.txt | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index afe3ce4b7..f5422a167 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,7 +20,7 @@ set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/) message(STATUS "Configuring OpenMW...") set(OPENMW_VERSION_MAJOR 0) -set(OPENMW_VERSION_MINOR 37) +set(OPENMW_VERSION_MINOR 38) set(OPENMW_VERSION_RELEASE 0) set(OPENMW_VERSION_COMMITHASH "") diff --git a/README.md b/README.md index f353cd76e..9cfb0440d 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ OpenMW is a recreation of the engine for the popular role-playing game Morrowind OpenMW also comes with OpenMW-CS, a replacement for Morrowind's TES Construction Set. -* Version: 0.37.0 +* Version: 0.38.0 * License: GPL (see docs/license/GPL3.txt for more information) * Website: http://www.openmw.org * IRC: #openmw on irc.freenode.net From fde831e2e03281b1461e317318ebb1be82785e00 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 4 Jan 2016 18:21:30 +0100 Subject: [PATCH 2953/3725] updated changelog --- CHANGELOG.md | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 43e598566..de4a6fc24 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,77 @@ +0.38.0 +------ + + Bug #1699: Guard will continuously run into mudcrab + Bug #1934: Saw in Dome of Kasia doesnt harm the player + Bug #1962: Rat floats when killed near the door + Bug #1963: Kwama eggsacks pulse too fast + Bug #2198: NPC voice sound source should be placed at their head + Bug #2210: OpenMW installation wizard crashes... + Bug #2211: Editor: handle DELE subrecord at the end of a record + Bug #2413: ESM error Unknown subrecord in Grandmaster of Hlaalu + Bug #2537: Bloodmoon quest Ristaag: Sattir not consistently dying, plot fails to advance; same with Grerid + Bug #2697: "The Swimmer" moves away after leading you to underwater cave + Bug #2724: Loading previous save duplicates containers and harvestables + Bug #2769: Inventory doll - Cursor not respecting order of clothes + Bug #2865: Scripts silently fail when moving NPCs between cells. + Bug #2873: Starting a new game leads to CTD / Fatal Error + Bug #2918: Editor: it's not possible to create an omwaddon containing a dot in the file name + Bug #2933: Dialog box can't disable a npc if it is in another cell. (Rescue Madura Seran). + Bug #2942: atronach sign behavior (spell absorption) changes when trying to receive a blessing at "shrine of tribunal" + Bug #2952: Enchantment Merchant Items reshuffled EVERY time 'barter' is clicked + Bug #2961: ESM Error: Unknown subrecord if Deus Ex Machina mod is loaded + Bug #2972: Resurrecting the player via console does not work when health was 0 + Bug #2986: Projectile weapons work underwater + Bug #2988: "Expected subrecord" bugs showing up. + Bug #2991: Can't use keywords in strings for MessageBox + Bug #2993: Tribunal:The Shrine of the Dead – Urvel Dulni can't stop to follow the player. + Bug #3008: NIFFile Error while loading meshes with a NiLODNode + Bug #3010: Engine: items should sink to the ground when dropped under water + Bug #3011: NIFFile Error while loading meshes with a NiPointLight + Bug #3016: Engine: something wrong with scripting - crash / fatal error + Bug #3020: Editor: verify does not check if given "item ID" (as content) for a "container" exists + Bug #3026: [MOD: Julan Ashlander Companion] Dialogue not triggering correctly + Bug #3028: Tooltips for Health, Magicka and Fatigue show in Options menu even when bars aren't visible + Bug #3034: Item count check dialogue option doesn't work (Guards accept gold even if you don't have enough) + Bug #3036: Owned tooltip color affects spell tooltips incorrrectly + Bug #3037: Fatal error loading old ES_Landscape.esp in Store::search + Bug #3038: Player sounds come from underneath + Bug #3040: Execution of script failed: There is a message box already + Bug #3047: [MOD: Julan Ashlander Companion] Scripts KS_Bedscript or KS_JulanNight not working as intended + Bug #3048: Fatal Error + Bug #3051: High field of view results in first person rendering glitches + Bug #3053: Crash on new game at character class selection + Bug #3058: Physiched sleeves aren't rendered correctly. + Bug #3060: NPCs use wrong landing sound + Bug #3062: Mod support regression: Andromeda's fast travel. + Bug #3063: Missing Journal Textures without Tribunal and Bloodmoon installed + Bug #3077: repeated aifollow causes the distance to stack + Bug #3078: Creature Dialogues not showing when certain Function/Conditions are required. + Bug #3082: Crash when entering Holamayan Monastery with mesh replacer installed + Bug #3086: Party at Boro's House – Creature with Class don't talk under OpenMW + Bug #3089: Dreamers spawn too soon + Bug #3100: Certain controls erroneously work as a werewolf + Bug #3102: Multiple unique soultrap spell sources clone souls. + Bug #3105: Summoned creatures and objects disappear at midnight + Bug #3112: gamecontrollerdb file creation with wrong extension + Bug #3116: Dialogue Function "Same Race" is avoided + Bug #3117: Dialogue Bug: Choice conditions are tested when not in a choice + Bug #3118: Body Parts are not rendered when used in a pose. + Bug #3122: NPC direction is reversed during sneak awareness check + Feature #776: Sound effects from one direction don't necessarily affect both speakers in stereo + Feature #858: Different fov settings for hands and the game world + Feature #1176: Handle movement of objects between cells + Feature #2507: Editor: choosing colors for syntax highlighting + Feature #2867: Editor: hide script error list when there are no errors + Feature #2885: Accept a file format other than nif + Feature #2982: player->SetDelete 1 results in: PC can't move, menu can be opened + Feature #2996: Editor: make it possible to preset the height of the script check area in a script view + Feature #3014: Editor: Tooltips in 3D scene + Feature #3064: Werewolf field of view + Feature #3074: Quicksave indicator + Task #287: const version of Ptr + Task #2542: Editor: redo user settings system + 0.37.0 ------ From e6619c5306a5305a5aebb2bc5a17db5538162391 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 4 Jan 2016 20:27:38 +0100 Subject: [PATCH 2954/3725] Rebuild actor animations on resurrection (Fixes #3124) A new animation is necessary to set up the correct InventoryStore listener, to get notified of changes like the actor no longer being a werewolf, etc. --- apps/openmw/mwscript/statsextensions.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index cdf60d329..d5b64b7d7 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -1125,10 +1125,16 @@ namespace MWScript ptr.getClass().getCreatureStats(ptr).resurrect(); else if (ptr.getClass().getCreatureStats(ptr).isDead()) { + bool wasEnabled = ptr.getRefData().isEnabled(); MWBase::Environment::get().getWorld()->undeleteObject(ptr); - // resets runtime state such as inventory, stats and AI. does not reset position in the world MWBase::Environment::get().getWorld()->removeContainerScripts(ptr); + + // HACK: disable/enable object to re-add it to the scene properly (need a new Animation). + MWBase::Environment::get().getWorld()->disable(ptr); + // resets runtime state such as inventory, stats and AI. does not reset position in the world ptr.getRefData().setCustomData(NULL); + if (wasEnabled) + MWBase::Environment::get().getWorld()->enable(ptr); } } }; From 446c7147270ee69148a82d431309fdd3f8b458ce Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 4 Jan 2016 20:39:08 +0100 Subject: [PATCH 2955/3725] Fix a possible memory leak in error case --- apps/openmw/mwrender/npcanimation.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 4e367b3b1..a032896a7 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -352,13 +352,13 @@ public: virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) { osgUtil::CullVisitor* cv = static_cast(nv); - osg::RefMatrix* projectionMatrix = new osg::RefMatrix(*cv->getProjectionMatrix()); float fov, aspect, zNear, zFar; - if (projectionMatrix->getPerspective(fov, aspect, zNear, zFar)) + if (cv->getProjectionMatrix()->getPerspective(fov, aspect, zNear, zFar)) { fov = mFov; - projectionMatrix->makePerspective(fov, aspect, zNear, zFar); - cv->pushProjectionMatrix(projectionMatrix); + osg::RefMatrix* newProjectionMatrix = new osg::RefMatrix(*cv->getProjectionMatrix()); + newProjectionMatrix->makePerspective(fov, aspect, zNear, zFar); + cv->pushProjectionMatrix(newProjectionMatrix); traverse(node, nv); cv->popProjectionMatrix(); } From 48f4fc34eba0386d53f19507ed423cfeeb6c6e8f Mon Sep 17 00:00:00 2001 From: sandstranger Date: Tue, 5 Jan 2016 15:37:17 +0300 Subject: [PATCH 2956/3725] build fixes for Android --- CMakeLists.txt | 6 +++++- cmake/FindMyGUI.cmake | 11 ++++++----- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index afe3ce4b7..fd7e3d564 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,6 +16,11 @@ endif (APPLE) set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/) +if (ANDROID) + set(CMAKE_FIND_ROOT_PATH ${OPENMW_DEPENDENCIES_DIR} "${CMAKE_FIND_ROOT_PATH}") + set (OSG_PLUGINS_DIR CACHE STRING "") +endif() + # Version message(STATUS "Configuring OpenMW...") @@ -157,7 +162,6 @@ if (WIN32) endif() if (ANDROID) - set(CMAKE_FIND_ROOT_PATH ${OPENMW_DEPENDENCIES_DIR} "${CMAKE_FIND_ROOT_PATH}") set(OPENGL_ES TRUE CACHE BOOL "enable opengl es support for android" FORCE) endif (ANDROID) diff --git a/cmake/FindMyGUI.cmake b/cmake/FindMyGUI.cmake index 6e93a92ce..61a39e4d3 100644 --- a/cmake/FindMyGUI.cmake +++ b/cmake/FindMyGUI.cmake @@ -71,7 +71,7 @@ ELSE (WIN32) #Unix FIND_PACKAGE(PkgConfig) IF(MYGUI_STATIC) # don't use pkgconfig on OS X, find freetype & append it's libs to resulting MYGUI_LIBRARIES - IF (NOT APPLE) + IF (NOT APPLE AND NOT ANDROID) PKG_SEARCH_MODULE(MYGUI MYGUIStatic MyGUIStatic) IF (MYGUI_INCLUDE_DIRS) SET(MYGUI_INCLUDE_DIRS ${MYGUI_INCLUDE_DIRS}) @@ -84,15 +84,15 @@ ELSE (WIN32) #Unix STRING(REGEX REPLACE "(.*)/.*" "\\1" MYGUI_LIB_DIR "${MYGUI_LIB_DIR}") STRING(REGEX REPLACE ".*/" "" MYGUI_LIBRARIES "${MYGUI_LIBRARIES}") ENDIF (MYGUI_INCLUDE_DIRS) - ELSE (NOT APPLE) + ELSE (NOT APPLE AND NOT ANDROID) SET(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} ${MYGUI_DEPENDENCIES_DIR}) - FIND_PACKAGE(freetype) + FIND_PACKAGE(Freetype REQUIRED) FIND_PATH(MYGUI_INCLUDE_DIRS MyGUI.h PATHS /usr/local/include /usr/include PATH_SUFFIXES MyGUI MYGUI) - FIND_LIBRARY(MYGUI_LIBRARIES MyGUIEngineStatic PATHS /usr/lib /usr/local/lib) + FIND_LIBRARY(MYGUI_LIBRARIES MyGUIEngineStatic PATHS /usr/lib /usr/local/lib ${OPENMW_DEPENDENCIES_DIR}) SET(MYGUI_LIB_DIR ${MYGUI_LIBRARIES}) STRING(REGEX REPLACE "(.*)/.*" "\\1" MYGUI_LIB_DIR "${MYGUI_LIB_DIR}") STRING(REGEX REPLACE ".*/" "" MYGUI_LIBRARIES "${MYGUI_LIBRARIES}") - ENDIF (NOT APPLE) + ENDIF (NOT APPLE AND NOT ANDROID) ELSE(MYGUI_STATIC) PKG_SEARCH_MODULE(MYGUI MYGUI MyGUI) IF (MYGUI_INCLUDE_DIRS) @@ -109,6 +109,7 @@ ELSE (WIN32) #Unix ENDIF(MYGUI_STATIC) ENDIF (WIN32) + #Do some preparation IF (NOT WIN32) # This does not work on Windows for paths with spaces in them SEPARATE_ARGUMENTS(MYGUI_INCLUDE_DIRS) From 5952498e9e747dc8d7dc1a62866abbace2698cab Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 5 Jan 2016 16:53:51 +0100 Subject: [PATCH 2957/3725] Explicitely cast a size_t to int --- apps/openmw/mwgui/dialogue.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index d32588631..040cd6d65 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -547,7 +547,7 @@ namespace MWGui void DialogueWindow::onScrollbarMoved(MyGUI::ScrollBar *sender, size_t pos) { - mHistory->setPosition(0, pos * -1); + mHistory->setPosition(0, static_cast(pos) * -1); } void DialogueWindow::addResponse(const std::string &text, const std::string &title) From d9d6228c94ac961fc98b4e214efe30f0882d79db Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 5 Jan 2016 16:54:09 +0100 Subject: [PATCH 2958/3725] Implement PageDisplay::_updateView (Fixes #3125) --- apps/openmw/mwgui/bookpage.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/openmw/mwgui/bookpage.cpp b/apps/openmw/mwgui/bookpage.cpp index b728b748f..fe1e6aa0c 100644 --- a/apps/openmw/mwgui/bookpage.cpp +++ b/apps/openmw/mwgui/bookpage.cpp @@ -1222,6 +1222,11 @@ public: void _updateView () { + _checkMargin(); + + if (mNode != NULL) + for (ActiveTextFormats::iterator i = mActiveTextFormats.begin (); i != mActiveTextFormats.end (); ++i) + mNode->outOfDate (i->second->mRenderItem); } void _correctView() From 745b29a99509197b0c0842403697f366b2a8b439 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 5 Jan 2016 17:01:21 +0100 Subject: [PATCH 2959/3725] Remove a debugging leftover --- apps/openmw/mwgui/bookpage.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/openmw/mwgui/bookpage.cpp b/apps/openmw/mwgui/bookpage.cpp index fe1e6aa0c..8506f04ed 100644 --- a/apps/openmw/mwgui/bookpage.cpp +++ b/apps/openmw/mwgui/bookpage.cpp @@ -1153,8 +1153,6 @@ public: void createDrawItem(MyGUI::ITexture* texture, MyGUI::ILayerNode* node) { - //test (); - mNode = node; for (ActiveTextFormats::iterator i = mActiveTextFormats.begin (); i != mActiveTextFormats.end (); ++i) From 466f91db673b6c58864228b49ae62224a3ab3381 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 6 Jan 2016 13:10:09 +0100 Subject: [PATCH 2960/3725] Fixed wrong GMST name for newly created game files (Fixes #3132) --- apps/opencs/model/doc/document.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 0e2d4e7d1..8cafa7ae1 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -1481,7 +1481,7 @@ void CSMDoc::Document::addGmsts() "sMagicWingedTwilightID", "sMagnitude", "sMagnitudeDes", - "sMake", + "sMake Enchantment", "sMap", "sMaster", "sMastPlugMismatchMsg", From 210c77968a6542b401a8784c424b1b5935f631af Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 7 Jan 2016 15:38:23 +0100 Subject: [PATCH 2961/3725] Don't report warning about extra arguments, if there are no extra arguments (Fixes #3133) --- components/compiler/exprparser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/compiler/exprparser.cpp b/components/compiler/exprparser.cpp index d35b08167..c739048a6 100644 --- a/components/compiler/exprparser.cpp +++ b/components/compiler/exprparser.cpp @@ -791,7 +791,7 @@ namespace Compiler if (*iter=='c') stringParser.smashCase(); scanner.scan (stringParser); - if (optional && stringParser.isEmpty()) + if ((optional || *iter=='x') && stringParser.isEmpty()) break; if (*iter!='x') From f9607a47b319afcb4f02c51bf0ae3c57104b3119 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 7 Jan 2016 15:54:22 +0100 Subject: [PATCH 2962/3725] improved handling of extra arguments in StringParser --- components/compiler/exprparser.cpp | 4 +++- components/compiler/stringparser.cpp | 27 ++++++++++++++++++++++----- components/compiler/stringparser.hpp | 11 +++++++++++ 3 files changed, 36 insertions(+), 6 deletions(-) diff --git a/components/compiler/exprparser.cpp b/components/compiler/exprparser.cpp index c739048a6..37c20527e 100644 --- a/components/compiler/exprparser.cpp +++ b/components/compiler/exprparser.cpp @@ -789,6 +789,7 @@ namespace Compiler stringParser.setOptional (true); if (*iter=='c') stringParser.smashCase(); + if (*iter=='x') stringParser.discard(); scanner.scan (stringParser); if ((optional || *iter=='x') && stringParser.isEmpty()) @@ -805,7 +806,8 @@ namespace Compiler ++optionalCount; } else - getErrorHandler().warning("Ignoring extra argument", mTokenLoc); + getErrorHandler().warning ("Ignoring extra argument", + stringParser.getTokenLoc()); } else if (*iter=='X') { diff --git a/components/compiler/stringparser.cpp b/components/compiler/stringparser.cpp index f8798eccd..8041b0f02 100644 --- a/components/compiler/stringparser.cpp +++ b/components/compiler/stringparser.cpp @@ -13,7 +13,7 @@ namespace Compiler { StringParser::StringParser (ErrorHandler& errorHandler, const Context& context, Literals& literals) - : Parser (errorHandler, context), mLiterals (literals), mState (StartState), mSmashCase (false) + : Parser (errorHandler, context), mLiterals (literals), mState (StartState), mSmashCase (false), mDiscard (false) { } @@ -24,10 +24,15 @@ namespace Compiler if (mState==StartState || mState==CommaState) { start(); - if (mSmashCase) - Generator::pushString (mCode, mLiterals, Misc::StringUtils::lowerCase (name)); - else - Generator::pushString (mCode, mLiterals, name); + mTokenLoc = loc; + + if (!mDiscard) + { + if (mSmashCase) + Generator::pushString (mCode, mLiterals, Misc::StringUtils::lowerCase (name)); + else + Generator::pushString (mCode, mLiterals, name); + } return false; } @@ -75,6 +80,8 @@ namespace Compiler mState = StartState; mCode.clear(); mSmashCase = false; + mTokenLoc = TokenLoc(); + mDiscard = false; Parser::reset(); } @@ -82,4 +89,14 @@ namespace Compiler { mSmashCase = true; } + + const TokenLoc& StringParser::getTokenLoc() const + { + return mTokenLoc; + } + + void StringParser::discard() + { + mDiscard = true; + } } diff --git a/components/compiler/stringparser.hpp b/components/compiler/stringparser.hpp index 52469128f..72dab0580 100644 --- a/components/compiler/stringparser.hpp +++ b/components/compiler/stringparser.hpp @@ -6,6 +6,7 @@ #include #include "parser.hpp" +#include "tokenloc.hpp" namespace Compiler { @@ -22,6 +23,8 @@ namespace Compiler State mState; std::vector mCode; bool mSmashCase; + TokenLoc mTokenLoc; + bool mDiscard; public: @@ -48,6 +51,14 @@ namespace Compiler void reset(); ///< Reset parser to clean state (this includes the smashCase function). + + /// Returns TokenLoc object for string. If no string has been parsed, the TokenLoc + /// object will be default initialised. + const TokenLoc& getTokenLoc() const; + + /// If parsing a string, do not add it to the literal table and do not create code + /// for it. + void discard(); }; } From 46e32de3501d170887d8d91bda62030e1f89d058 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 7 Jan 2016 16:01:01 +0100 Subject: [PATCH 2963/3725] improved handling of extra arguments in DiscardParser --- components/compiler/discardparser.cpp | 25 +++++++++++++++++++++++++ components/compiler/discardparser.hpp | 7 ++++++- components/compiler/exprparser.cpp | 2 +- 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/components/compiler/discardparser.cpp b/components/compiler/discardparser.cpp index da114fb3d..0e7c4718c 100644 --- a/components/compiler/discardparser.cpp +++ b/components/compiler/discardparser.cpp @@ -14,6 +14,9 @@ namespace Compiler { if (mState==StartState || mState==CommaState || mState==MinusState) { + if (isEmpty()) + mTokenLoc = loc; + start(); return false; } @@ -25,6 +28,9 @@ namespace Compiler { if (mState==StartState || mState==CommaState || mState==MinusState) { + if (isEmpty()) + mTokenLoc = loc; + start(); return false; } @@ -37,6 +43,9 @@ namespace Compiler { if (mState==StartState || mState==CommaState) { + if (isEmpty()) + mTokenLoc = loc; + start(); return false; } @@ -48,12 +57,22 @@ namespace Compiler { if (code==Scanner::S_comma && mState==StartState) { + if (isEmpty()) + mTokenLoc = loc; + + start(); + mState = CommaState; return true; } if (code==Scanner::S_minus && (mState==StartState || mState==CommaState)) { + if (isEmpty()) + mTokenLoc = loc; + + start(); + mState = MinusState; return true; } @@ -64,6 +83,12 @@ namespace Compiler void DiscardParser::reset() { mState = StartState; + mTokenLoc = TokenLoc(); Parser::reset(); } + + const TokenLoc& DiscardParser::getTokenLoc() const + { + return mTokenLoc; + } } diff --git a/components/compiler/discardparser.hpp b/components/compiler/discardparser.hpp index bee8a87bb..2a7ed5544 100644 --- a/components/compiler/discardparser.hpp +++ b/components/compiler/discardparser.hpp @@ -2,6 +2,7 @@ #define COMPILER_DISCARDPARSER_H_INCLUDED #include "parser.hpp" +#include "tokenloc.hpp" namespace Compiler { @@ -14,6 +15,7 @@ namespace Compiler }; State mState; + TokenLoc mTokenLoc; public: @@ -38,8 +40,11 @@ namespace Compiler virtual void reset(); ///< Reset parser to clean state. + + /// Returns TokenLoc object for value. If no value has been parsed, the TokenLoc + /// object will be default initialised. + const TokenLoc& getTokenLoc() const; }; } #endif - diff --git a/components/compiler/exprparser.cpp b/components/compiler/exprparser.cpp index 37c20527e..7c61ad0ee 100644 --- a/components/compiler/exprparser.cpp +++ b/components/compiler/exprparser.cpp @@ -832,7 +832,7 @@ namespace Compiler if (discardParser.isEmpty()) break; else - getErrorHandler().warning("Ignoring extra argument", mTokenLoc); + getErrorHandler().warning("Ignoring extra argument", discardParser.getTokenLoc()); } else if (*iter=='j') { From ece40b1e96661c21a277d42349fd6b0cd28c5d86 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 7 Jan 2016 16:07:49 +0100 Subject: [PATCH 2964/3725] improved the remaining handling of extra arguments --- components/compiler/exprparser.cpp | 10 ++++++++-- components/compiler/exprparser.hpp | 2 ++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/components/compiler/exprparser.cpp b/components/compiler/exprparser.cpp index 7c61ad0ee..0c8220e97 100644 --- a/components/compiler/exprparser.cpp +++ b/components/compiler/exprparser.cpp @@ -639,7 +639,8 @@ namespace Compiler if (code==Scanner::S_newline) { // end marker - mTokenLoc = loc; + if (mTokenLoc.mLiteral.empty()) + mTokenLoc = loc; scanner.putbackSpecial (code, loc); return false; } @@ -820,7 +821,7 @@ namespace Compiler if (parser.isEmpty()) break; else - getErrorHandler().warning("Ignoring extra argument", mTokenLoc); + getErrorHandler().warning("Ignoring extra argument", parser.getTokenLoc()); } else if (*iter=='z') { @@ -878,4 +879,9 @@ namespace Compiler return optionalCount; } + + const TokenLoc& ExprParser::getTokenLoc() const + { + return mTokenLoc; + } } diff --git a/components/compiler/exprparser.hpp b/components/compiler/exprparser.hpp index 639ca65aa..dd8259ee1 100644 --- a/components/compiler/exprparser.hpp +++ b/components/compiler/exprparser.hpp @@ -103,6 +103,8 @@ namespace Compiler /// \param invert Store arguments in reverted order. /// \param ignoreKeyword A keyword that is seen as junk /// \return number of optional arguments + + const TokenLoc& getTokenLoc() const; }; } From 7dd7be7f0ec646a8691877ad0e51defd103f00a5 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 10 Jan 2016 08:56:15 +0100 Subject: [PATCH 2965/3725] make scenes drop target for referenceables --- apps/opencs/view/render/instancemode.cpp | 84 +++++++++++++++++++ apps/opencs/view/render/instancemode.hpp | 4 + .../view/render/pagedworldspacewidget.cpp | 11 +++ .../view/render/pagedworldspacewidget.hpp | 2 + .../view/render/unpagedworldspacewidget.cpp | 5 ++ .../view/render/unpagedworldspacewidget.hpp | 2 + apps/opencs/view/render/worldspacewidget.cpp | 48 +++++++++++ apps/opencs/view/render/worldspacewidget.hpp | 13 +++ 8 files changed, 169 insertions(+) diff --git a/apps/opencs/view/render/instancemode.cpp b/apps/opencs/view/render/instancemode.cpp index a4d147bb4..6c3593369 100644 --- a/apps/opencs/view/render/instancemode.cpp +++ b/apps/opencs/view/render/instancemode.cpp @@ -1,8 +1,13 @@ #include "instancemode.hpp" +#include + #include "../../model/prefs/state.hpp" +#include "../../model/world/idtable.hpp" +#include "../../model/world/commands.hpp" + #include "elements.hpp" #include "object.hpp" #include "worldspacewidget.hpp" @@ -55,3 +60,82 @@ void CSVRender::InstanceMode::secondarySelectPressed (osg::ref_ptr tag) } } } + +void CSVRender::InstanceMode::dragEnterEvent (QDragEnterEvent *event) +{ + if (const CSMWorld::TableMimeData* mime = dynamic_cast (event->mimeData())) + { + if (!mime->fromDocument (getWorldspaceWidget().getDocument())) + return; + + /// \todo document check + if (mime->holdsType (CSMWorld::UniversalId::Type_Referenceable)) + event->accept(); + } +} + +void CSVRender::InstanceMode::dropEvent (QDropEvent* event) +{ + if (const CSMWorld::TableMimeData* mime = dynamic_cast (event->mimeData())) + { + CSMDoc::Document& document = getWorldspaceWidget().getDocument(); + + if (!mime->fromDocument (document)) + return; + + osg::Vec3f insertPoint = getWorldspaceWidget().getIntersectionPoint (event->pos()); + + std::string cellId = getWorldspaceWidget().getCellId (insertPoint); + + bool dropped = false; + + std::vector ids = mime->getData(); + + CSMWorld::IdTable& referencesTable = dynamic_cast ( + *document.getData().getTableModel (CSMWorld::UniversalId::Type_References)); + + CSMWorld::IdTable& cellTable = dynamic_cast ( + *document.getData().getTableModel (CSMWorld::UniversalId::Type_Cells)); + + for (std::vector::const_iterator iter (ids.begin()); + iter!=ids.end(); ++iter) + if (mime->isReferencable (iter->getType())) + { + // create reference + std::auto_ptr createCommand ( + new CSMWorld::CreateCommand ( + referencesTable, document.getData().getReferences().getNewId())); + + createCommand->addValue (referencesTable.findColumnIndex ( + CSMWorld::Columns::ColumnId_Cell), QString::fromUtf8 (cellId.c_str())); + createCommand->addValue (referencesTable.findColumnIndex ( + CSMWorld::Columns::ColumnId_PositionXPos), insertPoint.x()); + createCommand->addValue (referencesTable.findColumnIndex ( + CSMWorld::Columns::ColumnId_PositionYPos), insertPoint.y()); + createCommand->addValue (referencesTable.findColumnIndex ( + CSMWorld::Columns::ColumnId_PositionZPos), insertPoint.z()); + createCommand->addValue (referencesTable.findColumnIndex ( + CSMWorld::Columns::ColumnId_ReferenceableId), + QString::fromUtf8 (iter->getId().c_str())); + + // increase reference count in cell + QModelIndex countIndex = cellTable.getModelIndex (cellId, + cellTable.findColumnIndex (CSMWorld::Columns::ColumnId_RefNumCounter)); + + int count = cellTable.data (countIndex).toInt(); + + std::auto_ptr incrementCommand ( + new CSMWorld::ModifyCommand (cellTable, countIndex, count+1)); + + document.getUndoStack().beginMacro (createCommand->text()); + document.getUndoStack().push (createCommand.release()); + document.getUndoStack().push (incrementCommand.release()); + document.getUndoStack().endMacro(); + + dropped = true; + } + + if (dropped) + event->accept(); + } +} diff --git a/apps/opencs/view/render/instancemode.hpp b/apps/opencs/view/render/instancemode.hpp index 66451bd99..7649c241c 100644 --- a/apps/opencs/view/render/instancemode.hpp +++ b/apps/opencs/view/render/instancemode.hpp @@ -20,6 +20,10 @@ namespace CSVRender virtual void primarySelectPressed (osg::ref_ptr tag); virtual void secondarySelectPressed (osg::ref_ptr tag); + + virtual void dragEnterEvent (QDragEnterEvent *event); + + virtual void dropEvent (QDropEvent* event); }; } diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index dae5990e6..e30f238a2 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -504,6 +504,17 @@ void CSVRender::PagedWorldspaceWidget::clearSelection (int elementMask) flagAsModified(); } +std::string CSVRender::PagedWorldspaceWidget::getCellId (const osg::Vec3f& point) const +{ + const int cellSize = 8192; + + CSMWorld::CellCoordinates cellCoordinates ( + static_cast (std::floor (point.x()/cellSize)), + static_cast (std::floor (point.y()/cellSize))); + + return cellCoordinates.getId (mWorldspace); +} + CSVWidget::SceneToolToggle *CSVRender::PagedWorldspaceWidget::makeControlVisibilitySelector ( CSVWidget::SceneToolbar *parent) { diff --git a/apps/opencs/view/render/pagedworldspacewidget.hpp b/apps/opencs/view/render/pagedworldspacewidget.hpp index e983fddd5..bc8e0da64 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.hpp +++ b/apps/opencs/view/render/pagedworldspacewidget.hpp @@ -96,6 +96,8 @@ namespace CSVRender /// \param elementMask Elements to be affected by the clear operation virtual void clearSelection (int elementMask); + virtual std::string getCellId (const osg::Vec3f& point) const; + protected: virtual void addVisibilitySelectorButtons (CSVWidget::SceneToolToggle2 *tool); diff --git a/apps/opencs/view/render/unpagedworldspacewidget.cpp b/apps/opencs/view/render/unpagedworldspacewidget.cpp index 68f068dac..701f50825 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.cpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.cpp @@ -108,6 +108,11 @@ void CSVRender::UnpagedWorldspaceWidget::clearSelection (int elementMask) flagAsModified(); } +std::string CSVRender::UnpagedWorldspaceWidget::getCellId (const osg::Vec3f& point) const +{ + return mCellId; +} + void CSVRender::UnpagedWorldspaceWidget::referenceableDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) { diff --git a/apps/opencs/view/render/unpagedworldspacewidget.hpp b/apps/opencs/view/render/unpagedworldspacewidget.hpp index 9e6fa97f4..70a20c216 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.hpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.hpp @@ -46,6 +46,8 @@ namespace CSVRender /// \param elementMask Elements to be affected by the clear operation virtual void clearSelection (int elementMask); + virtual std::string getCellId (const osg::Vec3f& point) const; + private: virtual void referenceableDataChanged (const QModelIndex& topLeft, diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index f0d398641..0383b0bcf 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -315,6 +315,54 @@ CSMDoc::Document& CSVRender::WorldspaceWidget::getDocument() return mDocument; } +osg::Vec3f CSVRender::WorldspaceWidget::getIntersectionPoint (const QPoint& localPos, + unsigned int interactionMask, bool ignoreHidden) const +{ + // (0,0) is considered the lower left corner of an OpenGL window + int x = localPos.x(); + int y = height() - localPos.y(); + + osg::ref_ptr intersector ( + new osgUtil::LineSegmentIntersector (osgUtil::Intersector::WINDOW, x, y)); + + intersector->setIntersectionLimit (osgUtil::LineSegmentIntersector::NO_LIMIT); + osgUtil::IntersectionVisitor visitor (intersector); + + unsigned int mask = interactionMask; + + if (ignoreHidden) + mask &= getVisibilityMask(); + + visitor.setTraversalMask (mask << 1); + + mView->getCamera()->accept (visitor); + + for (osgUtil::LineSegmentIntersector::Intersections::iterator iter = intersector->getIntersections().begin(); + iter!=intersector->getIntersections().end(); ++iter) + { + // reject back-facing polygons + osg::Vec3f normal = osg::Matrix::transform3x3 ( + iter->getWorldIntersectNormal(), mView->getCamera()->getViewMatrix()); + + if (normal.z()>=0) + return iter->getWorldIntersectPoint(); + } + + osg::Matrixd matrix; + matrix.preMult (mView->getCamera()->getViewport()->computeWindowMatrix()); + matrix.preMult (mView->getCamera()->getProjectionMatrix()); + matrix.preMult (mView->getCamera()->getViewMatrix()); + matrix = osg::Matrixd::inverse (matrix); + + osg::Vec3d start = matrix.preMult (intersector->getStart()); + osg::Vec3d end = matrix.preMult (intersector->getEnd()); + + osg::Vec3d direction = end-start; + direction.normalize(); + + return start+direction * 50; +} + void CSVRender::WorldspaceWidget::dragEnterEvent (QDragEnterEvent* event) { const CSMWorld::TableMimeData* mime = dynamic_cast (event->mimeData()); diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp index 54376cee4..0edf9f0b2 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -127,6 +127,19 @@ namespace CSVRender /// \param elementMask Elements to be affected by the clear operation virtual void clearSelection (int elementMask) = 0; + /// Return the next intersection point with scene elements matched by + /// \a interactionMask based on \a localPos and the camera vector. + /// If there is no such point, instead a point "in front" of \a localPos will be + /// returned. + /// + /// \param ignoreHidden ignore elements specified in interactionMask that are + /// flagged as not visible. + osg::Vec3f getIntersectionPoint (const QPoint& localPos, + unsigned int interactionMask = Element_Reference | Element_Terrain, + bool ignoreHidden = false) const; + + virtual std::string getCellId (const osg::Vec3f& point) const = 0; + protected: virtual void addVisibilitySelectorButtons (CSVWidget::SceneToolToggle2 *tool); From 5b9d6cce989720aa65828bcba8e13b78d10758af Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 11 Jan 2016 09:03:02 +0100 Subject: [PATCH 2966/3725] made drop distance configurable --- apps/opencs/model/prefs/state.cpp | 5 +++++ apps/opencs/view/render/worldspacewidget.cpp | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index 8b827d0a2..d2ad0f6ef 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -190,6 +190,11 @@ void CSMPrefs::State::declare() declareBool ("scene-hide-basic", "Hide basic 3D scenes tooltips", false); declareInt ("scene-delay", "Tooltip delay in milliseconds", 500). setMin (1); + + declareCategory ("Scene Drops"); + declareInt ("distance", "Drop Distance", 50). + setTooltip ("If an instance drop can not be placed against another object at the " + "insert point, it will be placed by this distance from the insert point instead"); } void CSMPrefs::State::declareCategory (const std::string& key) diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 0383b0bcf..536126689 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -360,7 +360,7 @@ osg::Vec3f CSVRender::WorldspaceWidget::getIntersectionPoint (const QPoint& loca osg::Vec3d direction = end-start; direction.normalize(); - return start+direction * 50; + return start + direction * CSMPrefs::get()["Scene Drops"]["distance"].toInt(); } void CSVRender::WorldspaceWidget::dragEnterEvent (QDragEnterEvent* event) From 190bf158878943f7ad358b8caed706f4f2b02fe7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 5 Jan 2016 22:37:36 +0100 Subject: [PATCH 2967/3725] SettingsWindow: support auto-updating of slider labels through the layout file --- apps/openmw/mwgui/settingswindow.cpp | 53 ++++++++++------------- apps/openmw/mwgui/settingswindow.hpp | 5 +-- files/mygui/openmw_settings_window.layout | 7 ++- 3 files changed, 29 insertions(+), 36 deletions(-) diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index fbfbd0e70..86ecd9dfb 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -130,12 +130,14 @@ namespace MWGui if (type == sliderType) { MyGUI::ScrollBar* scroll = current->castType(); + std::string valueStr; if (getSettingValueType(current) == "Float") { // TODO: ScrollBar isn't meant for this. should probably use a dedicated FloatSlider widget float min,max; getSettingMinMax(scroll, min, max); float value = Settings::Manager::getFloat(getSettingName(current), getSettingCategory(current)); + valueStr = MyGUI::utility::toString((int)value); value = std::max(min, std::min(value, max)); value = (value-min)/(max-min); @@ -144,15 +146,30 @@ namespace MWGui else { int value = Settings::Manager::getInt(getSettingName(current), getSettingCategory(current)); + valueStr = MyGUI::utility::toString(value); scroll->setScrollPosition(value); } scroll->eventScrollChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onSliderChangePosition); + updateSliderLabel(scroll, valueStr); } configureWidgets(current); } } + void SettingsWindow::updateSliderLabel(MyGUI::ScrollBar *scroller, const std::string& value) + { + std::string labelWidgetName = scroller->getUserString("SettingLabelWidget"); + if (!labelWidgetName.empty()) + { + MyGUI::TextBox* textBox; + getWidget(textBox, labelWidgetName); + std::string labelCaption = scroller->getUserString("SettingLabelCaption"); + boost::algorithm::replace_all(labelCaption, "%s", value); + textBox->setCaptionWithReplacing(labelCaption); + } + } + SettingsWindow::SettingsWindow() : WindowBase("openmw_settings_window.layout"), mKeyboardMode(true) @@ -167,17 +184,13 @@ namespace MWGui getWidget(mFullscreenButton, "FullscreenButton"); getWidget(mVSyncButton, "VSyncButton"); getWidget(mWindowBorderButton, "WindowBorderButton"); - getWidget(mFOVSlider, "FOVSlider"); - getWidget(mAnisotropySlider, "AnisotropySlider"); getWidget(mTextureFilteringButton, "TextureFilteringButton"); - getWidget(mAnisotropyLabel, "AnisotropyLabel"); getWidget(mAnisotropyBox, "AnisotropyBox"); getWidget(mShadersButton, "ShadersButton"); getWidget(mShadowsEnabledButton, "ShadowsEnabledButton"); getWidget(mShadowsTextureSize, "ShadowsTextureSize"); getWidget(mControlsBox, "ControlsBox"); getWidget(mResetControlsButton, "ResetControlsButton"); - getWidget(mDifficultySlider, "DifficultySlider"); getWidget(mKeyboardSwitch, "KeyboardButton"); getWidget(mControllerSwitch, "ControllerButton"); getWidget(mWaterTextureSize, "WaterTextureSize"); @@ -238,7 +251,6 @@ namespace MWGui std::string tmip = Settings::Manager::getString("texture mipmap", "General"); mTextureFilteringButton->setCaption(textureMipmappingToStr(tmip)); - mAnisotropyLabel->setCaption("Anisotropy (" + MyGUI::utility::toString(Settings::Manager::getInt("anisotropy", "General")) + ")"); int waterTextureSize = Settings::Manager::getInt ("rtt size", "Water"); if (waterTextureSize >= 512) @@ -255,15 +267,6 @@ namespace MWGui mShadowsEnabledButton->setEnabled(false); } - MyGUI::TextBox* fovText; - getWidget(fovText, "FovText"); - fovText->setCaption("Field of View (" + MyGUI::utility::toString(int(Settings::Manager::getInt("field of view", "Camera"))) + ")"); - - MyGUI::TextBox* diffText; - getWidget(diffText, "DifficultyText"); - - diffText->setCaptionWithReplacing("#{sDifficulty} (" + MyGUI::utility::toString(int(Settings::Manager::getInt("difficulty", "Game"))) + ")"); - mWindowBorderButton->setEnabled(!Settings::Manager::getBool("fullscreen", "Video")); mKeyboardSwitch->setStateSelected(true); @@ -439,6 +442,7 @@ namespace MWGui { if (getSettingType(scroller) == "Slider") { + std::string valueStr; if (getSettingValueType(scroller) == "Float") { float value = pos / float(scroller->getScrollRange()-1); @@ -447,28 +451,15 @@ namespace MWGui getSettingMinMax(scroller, min, max); value = min + (max-min) * value; Settings::Manager::setFloat(getSettingName(scroller), getSettingCategory(scroller), value); - - if (scroller == mFOVSlider) - { - MyGUI::TextBox* fovText; - getWidget(fovText, "FovText"); - fovText->setCaption("Field of View (" + MyGUI::utility::toString(int(value)) + ")"); - } - if (scroller == mDifficultySlider) - { - MyGUI::TextBox* diffText; - getWidget(diffText, "DifficultyText"); - diffText->setCaptionWithReplacing("#{sDifficulty} (" + MyGUI::utility::toString(int(value)) + ")"); - } + valueStr = MyGUI::utility::toString(int(value)); } else { Settings::Manager::setInt(getSettingName(scroller), getSettingCategory(scroller), pos); - if (scroller == mAnisotropySlider) - { - mAnisotropyLabel->setCaption("Anisotropy (" + MyGUI::utility::toString(pos) + ")"); - } + valueStr = MyGUI::utility::toString(pos); } + updateSliderLabel(scroller, valueStr); + apply(); } } diff --git a/apps/openmw/mwgui/settingswindow.hpp b/apps/openmw/mwgui/settingswindow.hpp index 99553808b..421465309 100644 --- a/apps/openmw/mwgui/settingswindow.hpp +++ b/apps/openmw/mwgui/settingswindow.hpp @@ -30,11 +30,7 @@ namespace MWGui MyGUI::Button* mFullscreenButton; MyGUI::Button* mVSyncButton; MyGUI::Button* mWindowBorderButton; - MyGUI::ScrollBar* mFOVSlider; - MyGUI::ScrollBar* mDifficultySlider; - MyGUI::ScrollBar* mAnisotropySlider; MyGUI::ComboBox* mTextureFilteringButton; - MyGUI::TextBox* mAnisotropyLabel; MyGUI::Widget* mAnisotropyBox; MyGUI::Button* mShadersButton; @@ -76,6 +72,7 @@ namespace MWGui void apply(); void configureWidgets(MyGUI::Widget* widget); + void updateSliderLabel(MyGUI::ScrollBar* scroller, const std::string& value); private: void resetScrollbars(); diff --git a/files/mygui/openmw_settings_window.layout b/files/mygui/openmw_settings_window.layout index 6d2424aa5..cf7fe1be7 100644 --- a/files/mygui/openmw_settings_window.layout +++ b/files/mygui/openmw_settings_window.layout @@ -61,6 +61,8 @@ + +
    @@ -274,7 +276,6 @@ - @@ -285,6 +286,8 @@ + + @@ -334,6 +337,8 @@ + +
    From 4f8f166f69e6ce2ccecc0a2ce3d8dbc9919dc0cb Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 5 Jan 2016 23:27:42 +0100 Subject: [PATCH 2968/3725] Fix GetPcInJail to work as in the original engine --- apps/openmw/mwbase/world.hpp | 2 ++ apps/openmw/mwscript/miscextensions.cpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 8 ++++++++ apps/openmw/mwworld/worldimp.hpp | 2 ++ 4 files changed, 13 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index ebce2e1bf..462d08727 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -545,6 +545,8 @@ namespace MWBase virtual float getHitDistance(const MWWorld::ConstPtr& actor, const MWWorld::ConstPtr& target) = 0; virtual void removeContainerScripts(const MWWorld::Ptr& reference) = 0; + + virtual bool isPlayerInJail() const = 0; }; } diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 9c63511b2..593fdcca5 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -1014,7 +1014,7 @@ namespace MWScript virtual void execute (Interpreter::Runtime &runtime) { - runtime.push (MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_Jail)); + runtime.push (MWBase::Environment::get().getWorld()->isPlayerInJail()); } }; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 15826009d..19d90e209 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2996,6 +2996,14 @@ namespace MWWorld } } + bool World::isPlayerInJail() const + { + if (mGoToJail) + return true; + + return MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_Jail); + } + void World::spawnRandomCreature(const std::string &creatureList) { const ESM::CreatureLevList* list = getStore().get().find(creatureList); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 4ed97759e..5f0507ace 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -645,6 +645,8 @@ namespace MWWorld /// Return the distance between actor's weapon and target's collision box. virtual float getHitDistance(const MWWorld::ConstPtr& actor, const MWWorld::ConstPtr& target); + + virtual bool isPlayerInJail() const; }; } From 0da6d249fe5748496d605ad19bc1243d96ad6549 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 7 Jan 2016 00:26:09 +0100 Subject: [PATCH 2969/3725] Fix the window pinning button's borders not accepting mouse clicks --- files/mygui/openmw_windows.skin.xml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/files/mygui/openmw_windows.skin.xml b/files/mygui/openmw_windows.skin.xml index 682d89ebc..22270bb9f 100644 --- a/files/mygui/openmw_windows.skin.xml +++ b/files/mygui/openmw_windows.skin.xml @@ -11,41 +11,49 @@ + + + + + + + + @@ -53,41 +61,49 @@ + + + + + + + + From 4690fd3f222b3363944df53ab15887a7cc2632c6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 7 Jan 2016 00:43:15 +0100 Subject: [PATCH 2970/3725] Change the local map exploration radius to better match the original engine --- apps/openmw/mwrender/localmap.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 9d5950a90..b3d19090f 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -526,7 +526,7 @@ void LocalMap::updatePlayer (const osg::Vec3f& position, const osg::Quat& orient } // explore radius (squared) - const float exploreRadius = (mInterior ? 0.1f : 0.3f) * (sFogOfWarResolution-1); // explore radius from 0 to sFogOfWarResolution-1 + const float exploreRadius = 0.17f * (sFogOfWarResolution-1); // explore radius from 0 to sFogOfWarResolution-1 const float sqrExploreRadius = square(exploreRadius); const float exploreRadiusUV = exploreRadius / sFogOfWarResolution; // explore radius from 0 to 1 (UV space) From ca4e859f613c4521cae17aa4ef19190391e5242c Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 7 Jan 2016 00:45:12 +0100 Subject: [PATCH 2971/3725] Remove unused argument --- apps/openmw/mwgui/mapwindow.cpp | 4 +--- apps/openmw/mwgui/mapwindow.hpp | 2 -- apps/openmw/mwrender/localmap.cpp | 2 +- apps/openmw/mwrender/localmap.hpp | 2 +- 4 files changed, 3 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 0ebb595dd..bc8f41599 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -269,8 +269,6 @@ namespace MWGui // normalized cell coordinates float nX,nY; - markerPos.interior = mInterior; - if (!mInterior) { int cellX, cellY; @@ -1078,7 +1076,7 @@ namespace MWGui { if (!mLocalMapRender) return true; - return mLocalMapRender->isPositionExplored(nX, nY, cellX, cellY, interior); + return mLocalMapRender->isPositionExplored(nX, nY, cellX, cellY); } } diff --git a/apps/openmw/mwgui/mapwindow.hpp b/apps/openmw/mwgui/mapwindow.hpp index a41d5d527..0ab38f1e3 100644 --- a/apps/openmw/mwgui/mapwindow.hpp +++ b/apps/openmw/mwgui/mapwindow.hpp @@ -78,7 +78,6 @@ namespace MWGui { MarkerUserData(MWRender::LocalMap* map) : mLocalMapRender(map) - , interior(false) , cellX(0) , cellY(0) , nX(0.f) @@ -89,7 +88,6 @@ namespace MWGui bool isPositionExplored() const; MWRender::LocalMap* mLocalMapRender; - bool interior; int cellX; int cellY; float nX; diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index b3d19090f..200f484b5 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -478,7 +478,7 @@ osg::Vec2f LocalMap::interiorMapToWorldPosition (float nX, float nY, int x, int return pos; } -bool LocalMap::isPositionExplored (float nX, float nY, int x, int y, bool interior) +bool LocalMap::isPositionExplored (float nX, float nY, int x, int y) { const MapSegment& segment = mSegments[std::make_pair(x, y)]; if (!segment.mFogOfWarImage) diff --git a/apps/openmw/mwrender/localmap.hpp b/apps/openmw/mwrender/localmap.hpp index 72ee0354e..59165013d 100644 --- a/apps/openmw/mwrender/localmap.hpp +++ b/apps/openmw/mwrender/localmap.hpp @@ -99,7 +99,7 @@ namespace MWRender /** * Check if a given position is explored by the player (i.e. not obscured by fog of war) */ - bool isPositionExplored (float nX, float nY, int x, int y, bool interior); + bool isPositionExplored (float nX, float nY, int x, int y); osg::Group* getRoot(); From ef20962fc5f9d2ba19faa679cac1c4c02bbc87a4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 7 Jan 2016 01:08:30 +0100 Subject: [PATCH 2972/3725] Disable fog of war rendering on the HUD map by default --- apps/openmw/mwgui/hud.cpp | 2 +- apps/openmw/mwgui/mapwindow.cpp | 11 ++++++----- apps/openmw/mwgui/mapwindow.hpp | 5 +++-- files/settings-default.cfg | 4 ++++ 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index cf0fa3414..8d6ce6beb 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -69,7 +69,7 @@ namespace MWGui HUD::HUD(CustomMarkerCollection &customMarkers, DragAndDrop* dragAndDrop, MWRender::LocalMap* localMapRender) : Layout("openmw_hud.layout") - , LocalMapBase(customMarkers, localMapRender) + , LocalMapBase(customMarkers, localMapRender, Settings::Manager::getBool("local map hud fog of war", "Map")) , mHealth(NULL) , mMagicka(NULL) , mStamina(NULL) diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index bc8f41599..89f4d8cf3 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -156,7 +156,7 @@ namespace MWGui // ------------------------------------------------------ - LocalMapBase::LocalMapBase(CustomMarkerCollection &markers, MWRender::LocalMap* localMapRender) + LocalMapBase::LocalMapBase(CustomMarkerCollection &markers, MWRender::LocalMap* localMapRender, bool fogOfWarEnabled) : mLocalMapRender(localMapRender) , mCurX(0) , mCurY(0) @@ -165,7 +165,8 @@ namespace MWGui , mCompass(NULL) , mPrefix() , mChanged(true) - , mFogOfWar(true) + , mFogOfWarToggled(true) + , mFogOfWarEnabled(fogOfWarEnabled) , mMapWidgetSize(0) , mCustomMarkers(markers) , mMarkerUpdateTimer(0.0f) @@ -222,9 +223,9 @@ namespace MWGui bool LocalMapBase::toggleFogOfWar() { - mFogOfWar = !mFogOfWar; + mFogOfWarToggled = !mFogOfWarToggled; applyFogOfWar(); - return mFogOfWar; + return mFogOfWarToggled; } void LocalMapBase::applyFogOfWar() @@ -238,7 +239,7 @@ namespace MWGui int y = mCurY + (-1*(my-1)); MyGUI::ImageBox* fog = mFogWidgets[my + 3*mx]; - if (!mFogOfWar) + if (!mFogOfWarToggled || !mFogOfWarEnabled) { fog->setImageTexture(""); continue; diff --git a/apps/openmw/mwgui/mapwindow.hpp b/apps/openmw/mwgui/mapwindow.hpp index 0ab38f1e3..227a9e3f9 100644 --- a/apps/openmw/mwgui/mapwindow.hpp +++ b/apps/openmw/mwgui/mapwindow.hpp @@ -61,7 +61,7 @@ namespace MWGui class LocalMapBase { public: - LocalMapBase(CustomMarkerCollection& markers, MWRender::LocalMap* localMapRender); + LocalMapBase(CustomMarkerCollection& markers, MWRender::LocalMap* localMapRender, bool fogOfWarEnabled = true); virtual ~LocalMapBase(); void init(MyGUI::ScrollView* widget, MyGUI::ImageBox* compass, int mapWidgetSize); @@ -105,7 +105,8 @@ namespace MWGui MyGUI::ImageBox* mCompass; std::string mPrefix; bool mChanged; - bool mFogOfWar; + bool mFogOfWarToggled; + bool mFogOfWarEnabled; int mMapWidgetSize; diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 49c9c5419..6a2495e26 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -47,6 +47,10 @@ global map cell size = 18 # cell, 256 is 1/8 cell. See documentation for details. (e.g. 64 to 256). local map hud widget size = 256 +# Enables Fog of War rendering on the HUD map. Default is Off since with default settings +# the map is so small that the fog would not obscure anything, just darken the edges slightly. +local map hud fog of war = false + # Resolution of local map in GUI window in pixels. See documentation # for details which may affect cell load performance. (e.g. 128 to 1024). local map resolution = 256 From f315a4386fabeb6d96648e58a1c239c557d9257a Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 11 Jan 2016 23:07:01 +0100 Subject: [PATCH 2973/3725] Accept an implicit reference in Journal (Fixes #3135) --- apps/openmw/mwbase/journal.hpp | 3 ++- apps/openmw/mwdialogue/journalentry.cpp | 8 ++++---- apps/openmw/mwdialogue/journalentry.hpp | 4 ++-- apps/openmw/mwdialogue/journalimp.cpp | 4 ++-- apps/openmw/mwdialogue/journalimp.hpp | 3 ++- apps/openmw/mwscript/dialogueextensions.cpp | 9 +++++++-- 6 files changed, 19 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwbase/journal.hpp b/apps/openmw/mwbase/journal.hpp index 738014ba6..cd8792890 100644 --- a/apps/openmw/mwbase/journal.hpp +++ b/apps/openmw/mwbase/journal.hpp @@ -50,8 +50,9 @@ namespace MWBase virtual ~Journal() {} - virtual void addEntry (const std::string& id, int index) = 0; + virtual void addEntry (const std::string& id, int index, const MWWorld::Ptr& actor) = 0; ///< Add a journal entry. + /// @param actor Used as context for replacing of escape sequences (%name, etc). virtual void setJournalIndex (const std::string& id, int index) = 0; ///< Set the journal index without adding an entry. diff --git a/apps/openmw/mwdialogue/journalentry.cpp b/apps/openmw/mwdialogue/journalentry.cpp index 2f5f02b01..9f74d0733 100644 --- a/apps/openmw/mwdialogue/journalentry.cpp +++ b/apps/openmw/mwdialogue/journalentry.cpp @@ -102,8 +102,8 @@ namespace MWDialogue {} StampedJournalEntry::StampedJournalEntry (const std::string& topic, const std::string& infoId, - int day, int month, int dayOfMonth) - : JournalEntry (topic, infoId, MWWorld::Ptr()), mDay (day), mMonth (month), mDayOfMonth (dayOfMonth) + int day, int month, int dayOfMonth, const MWWorld::Ptr& actor) + : JournalEntry (topic, infoId, actor), mDay (day), mMonth (month), mDayOfMonth (dayOfMonth) {} StampedJournalEntry::StampedJournalEntry (const ESM::JournalEntry& record) @@ -119,12 +119,12 @@ namespace MWDialogue entry.mDayOfMonth = mDayOfMonth; } - StampedJournalEntry StampedJournalEntry::makeFromQuest (const std::string& topic, int index) + StampedJournalEntry StampedJournalEntry::makeFromQuest (const std::string& topic, int index, const MWWorld::Ptr& actor) { int day = MWBase::Environment::get().getWorld()->getGlobalInt ("dayspassed"); int month = MWBase::Environment::get().getWorld()->getGlobalInt ("month"); int dayOfMonth = MWBase::Environment::get().getWorld()->getGlobalInt ("day"); - return StampedJournalEntry (topic, idFromIndex (topic, index), day, month, dayOfMonth); + return StampedJournalEntry (topic, idFromIndex (topic, index), day, month, dayOfMonth, actor); } } diff --git a/apps/openmw/mwdialogue/journalentry.hpp b/apps/openmw/mwdialogue/journalentry.hpp index 3ae3efcc8..8711ab53a 100644 --- a/apps/openmw/mwdialogue/journalentry.hpp +++ b/apps/openmw/mwdialogue/journalentry.hpp @@ -64,13 +64,13 @@ namespace MWDialogue StampedJournalEntry(); StampedJournalEntry (const std::string& topic, const std::string& infoId, - int day, int month, int dayOfMonth); + int day, int month, int dayOfMonth, const MWWorld::Ptr& actor); StampedJournalEntry (const ESM::JournalEntry& record); void write (ESM::JournalEntry& entry) const; - static StampedJournalEntry makeFromQuest (const std::string& topic, int index); + static StampedJournalEntry makeFromQuest (const std::string& topic, int index, const MWWorld::Ptr& actor); }; } diff --git a/apps/openmw/mwdialogue/journalimp.cpp b/apps/openmw/mwdialogue/journalimp.cpp index e6ffe22ab..8ea72e3ba 100644 --- a/apps/openmw/mwdialogue/journalimp.cpp +++ b/apps/openmw/mwdialogue/journalimp.cpp @@ -75,7 +75,7 @@ namespace MWDialogue mTopics.clear(); } - void Journal::addEntry (const std::string& id, int index) + void Journal::addEntry (const std::string& id, int index, const MWWorld::Ptr& actor) { // bail out of we already have heard this... std::string infoId = JournalEntry::idFromIndex (id, index); @@ -83,7 +83,7 @@ namespace MWDialogue if (i->mTopic == id && i->mInfoId == infoId) return; - StampedJournalEntry entry = StampedJournalEntry::makeFromQuest (id, index); + StampedJournalEntry entry = StampedJournalEntry::makeFromQuest (id, index, actor); mJournal.push_back (entry); diff --git a/apps/openmw/mwdialogue/journalimp.hpp b/apps/openmw/mwdialogue/journalimp.hpp index 7f26a5bb9..c3e940629 100644 --- a/apps/openmw/mwdialogue/journalimp.hpp +++ b/apps/openmw/mwdialogue/journalimp.hpp @@ -29,8 +29,9 @@ namespace MWDialogue virtual void clear(); - virtual void addEntry (const std::string& id, int index); + virtual void addEntry (const std::string& id, int index, const MWWorld::Ptr& actor); ///< Add a journal entry. + /// @param actor Used as context for replacing of escape sequences (%name, etc). virtual void setJournalIndex (const std::string& id, int index); ///< Set the journal index without adding an entry. diff --git a/apps/openmw/mwscript/dialogueextensions.cpp b/apps/openmw/mwscript/dialogueextensions.cpp index c305fb81f..fcb7e8f3b 100644 --- a/apps/openmw/mwscript/dialogueextensions.cpp +++ b/apps/openmw/mwscript/dialogueextensions.cpp @@ -22,12 +22,17 @@ namespace MWScript { namespace Dialogue { + template class OpJournal : public Interpreter::Opcode0 { public: virtual void execute (Interpreter::Runtime& runtime) { + MWWorld::Ptr ptr = R()(runtime, false); // required=false + if (ptr.isEmpty()) + ptr = MWBase::Environment::get().getWorld()->getPlayerPtr(); + std::string quest = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); @@ -37,7 +42,7 @@ namespace MWScript // Invoking Journal with a non-existing index is allowed, and triggers no errors. Seriously? :( try { - MWBase::Environment::get().getJournal()->addEntry (quest, index); + MWBase::Environment::get().getJournal()->addEntry (quest, index, ptr); } catch (...) { @@ -270,7 +275,7 @@ namespace MWScript void installOpcodes (Interpreter::Interpreter& interpreter) { - interpreter.installSegment5 (Compiler::Dialogue::opcodeJournal, new OpJournal); + interpreter.installSegment5 (Compiler::Dialogue::opcodeJournal, new OpJournal); interpreter.installSegment5 (Compiler::Dialogue::opcodeSetJournalIndex, new OpSetJournalIndex); interpreter.installSegment5 (Compiler::Dialogue::opcodeGetJournalIndex, new OpGetJournalIndex); interpreter.installSegment5 (Compiler::Dialogue::opcodeAddTopic, new OpAddTopic); From 6546c05428bb4820a337b079aa728b62adaaab5e Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 6 Jan 2016 12:46:06 +0100 Subject: [PATCH 2974/3725] Move Fallback map to components/ --- apps/openmw/main.cpp | 34 +------------ apps/openmw/mwbase/world.hpp | 8 +++- apps/openmw/mwgui/charactercreation.cpp | 5 +- apps/openmw/mwgui/levelupdialog.cpp | 3 +- apps/openmw/mwrender/animation.cpp | 5 +- apps/openmw/mwrender/renderingmanager.cpp | 4 +- apps/openmw/mwrender/renderingmanager.hpp | 6 +-- apps/openmw/mwrender/ripplesimulation.cpp | 7 ++- apps/openmw/mwrender/ripplesimulation.hpp | 6 +-- apps/openmw/mwrender/sky.cpp | 7 ++- apps/openmw/mwrender/water.cpp | 5 +- apps/openmw/mwrender/water.hpp | 10 ++-- apps/openmw/mwworld/weather.cpp | 10 ++-- apps/openmw/mwworld/weather.hpp | 14 ++++-- apps/openmw/mwworld/worldimp.cpp | 2 +- apps/openmw/mwworld/worldimp.hpp | 15 +++--- components/CMakeLists.txt | 4 ++ .../fallback}/fallback.cpp | 14 +++--- .../fallback}/fallback.hpp | 11 +++-- components/fallback/validate.hpp | 48 +++++++++++++++++++ 20 files changed, 127 insertions(+), 91 deletions(-) rename {apps/openmw/mwworld => components/fallback}/fallback.cpp (75%) rename {apps/openmw/mwworld => components/fallback}/fallback.hpp (67%) create mode 100644 components/fallback/validate.hpp diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index c3f0f8688..a4bf1fe5b 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -52,39 +53,8 @@ inline boost::filesystem::path lexical_cast mMap; -}; - -void validate(boost::any &v, std::vector const &tokens, FallbackMap*, int) -{ - if(v.empty()) - { - v = boost::any(FallbackMap()); - } - - FallbackMap *map = boost::any_cast(&v); - - for(std::vector::const_iterator it=tokens.begin(); it != tokens.end(); ++it) - { - int sep = it->find(","); - if(sep < 1 || sep == (int)it->length()-1) -#if (BOOST_VERSION < 104200) - throw boost::program_options::validation_error("invalid value"); -#else - throw boost::program_options::validation_error(boost::program_options::validation_error::invalid_option_value); -#endif - - std::string key(it->substr(0,sep)); - std::string value(it->substr(sep+1)); - - if(map->mMap.find(key) == map->mMap.end()) - { - map->mMap.insert(std::make_pair (key,value)); - } - } -} +using namespace Fallback; /** * \brief Parses application command line and calls \ref Cfg::ConfigurationManager diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index ebce2e1bf..801016e06 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -56,7 +56,6 @@ namespace MWMechanics namespace MWWorld { - class Fallback; class CellStore; class Player; class LocalScripts; @@ -67,6 +66,11 @@ namespace MWWorld typedef std::vector > PtrMovementList; } +namespace Fallback +{ + class Map; +} + namespace MWBase { /// \brief Interface for the World (implemented in MWWorld) @@ -119,7 +123,7 @@ namespace MWBase virtual void adjustSky() = 0; - virtual const MWWorld::Fallback *getFallback () const = 0; + virtual const Fallback::Map *getFallback () const = 0; virtual MWWorld::Player& getPlayer() = 0; virtual MWWorld::Ptr getPlayerPtr() = 0; diff --git a/apps/openmw/mwgui/charactercreation.cpp b/apps/openmw/mwgui/charactercreation.cpp index d2ce35509..8c2ec6881 100644 --- a/apps/openmw/mwgui/charactercreation.cpp +++ b/apps/openmw/mwgui/charactercreation.cpp @@ -1,5 +1,7 @@ #include "charactercreation.hpp" +#include + #include "../mwbase/environment.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" @@ -10,7 +12,6 @@ #include "../mwmechanics/actorutil.hpp" #include "../mwworld/class.hpp" -#include "../mwworld/fallback.hpp" #include "../mwworld/esmstore.hpp" #include "textinput.hpp" @@ -32,7 +33,7 @@ namespace const ESM::Class::Specialization mSpecializations[3]={ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth}; // The specialization for each answer Step sGenerateClassSteps(int number) { number++; - const MWWorld::Fallback* fallback=MWBase::Environment::get().getWorld()->getFallback(); + const Fallback::Map* fallback=MWBase::Environment::get().getWorld()->getFallback(); Step step = {fallback->getFallbackString("Question_"+MyGUI::utility::toString(number)+"_Question"), {fallback->getFallbackString("Question_"+MyGUI::utility::toString(number)+"_AnswerOne"), fallback->getFallbackString("Question_"+MyGUI::utility::toString(number)+"_AnswerTwo"), diff --git a/apps/openmw/mwgui/levelupdialog.cpp b/apps/openmw/mwgui/levelupdialog.cpp index c832a7879..4e8d0a02c 100644 --- a/apps/openmw/mwgui/levelupdialog.cpp +++ b/apps/openmw/mwgui/levelupdialog.cpp @@ -4,13 +4,14 @@ #include #include +#include + #include "../mwbase/windowmanager.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwworld/class.hpp" -#include "../mwworld/fallback.hpp" #include "../mwworld/esmstore.hpp" #include "../mwworld/cellstore.hpp" diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 68a073731..c2fc82881 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -35,11 +35,12 @@ #include #include +#include + #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwworld/esmstore.hpp" #include "../mwworld/class.hpp" -#include "../mwworld/fallback.hpp" #include "../mwworld/cellstore.hpp" #include "../mwmechanics/character.hpp" // FIXME: for MWMechanics::Priority @@ -1113,7 +1114,7 @@ namespace MWRender osg::ref_ptr light (new osg::Light); lightSource->setNodeMask(Mask_Lighting); - const MWWorld::Fallback* fallback = MWBase::Environment::get().getWorld()->getFallback(); + const Fallback::Map* fallback = MWBase::Environment::get().getWorld()->getFallback(); float radius = esmLight->mData.mRadius; lightSource->setRadius(radius); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index ee9d93c0f..61ce626fd 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -30,8 +30,8 @@ #include #include +#include -#include "../mwworld/fallback.hpp" #include "../mwworld/cellstore.hpp" #include "sky.hpp" @@ -126,7 +126,7 @@ namespace MWRender }; RenderingManager::RenderingManager(osgViewer::Viewer* viewer, osg::ref_ptr rootNode, Resource::ResourceSystem* resourceSystem, - const MWWorld::Fallback* fallback, const std::string& resourcePath) + const Fallback::Map* fallback, const std::string& resourcePath) : mViewer(viewer) , mRootNode(rootNode) , mResourceSystem(resourceSystem) diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 58012078c..3b583af89 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -37,9 +37,9 @@ namespace Terrain class World; } -namespace MWWorld +namespace Fallback { - class Fallback; + class Map; } namespace MWRender @@ -58,7 +58,7 @@ namespace MWRender { public: RenderingManager(osgViewer::Viewer* viewer, osg::ref_ptr rootNode, Resource::ResourceSystem* resourceSystem, - const MWWorld::Fallback* fallback, const std::string& resourcePath); + const Fallback::Map* fallback, const std::string& resourcePath); ~RenderingManager(); MWRender::Objects& getObjects(); diff --git a/apps/openmw/mwrender/ripplesimulation.cpp b/apps/openmw/mwrender/ripplesimulation.cpp index f232ea475..f74631c4a 100644 --- a/apps/openmw/mwrender/ripplesimulation.cpp +++ b/apps/openmw/mwrender/ripplesimulation.cpp @@ -15,19 +15,18 @@ #include #include #include +#include #include "vismask.hpp" #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" -#include "../mwworld/fallback.hpp" - #include "../mwmechanics/actorutil.hpp" namespace { - void createWaterRippleStateSet(Resource::ResourceSystem* resourceSystem, const MWWorld::Fallback* fallback, osg::Node* node) + void createWaterRippleStateSet(Resource::ResourceSystem* resourceSystem, const Fallback::Map* fallback, osg::Node* node) { int rippleFrameCount = fallback->getFallbackInt("Water_RippleFrameCount"); if (rippleFrameCount <= 0) @@ -78,7 +77,7 @@ namespace namespace MWRender { -RippleSimulation::RippleSimulation(osg::Group *parent, Resource::ResourceSystem* resourceSystem, const MWWorld::Fallback* fallback) +RippleSimulation::RippleSimulation(osg::Group *parent, Resource::ResourceSystem* resourceSystem, const Fallback::Map* fallback) : mParent(parent) { osg::ref_ptr geode (new osg::Geode); diff --git a/apps/openmw/mwrender/ripplesimulation.hpp b/apps/openmw/mwrender/ripplesimulation.hpp index a4e12f275..bca81c59b 100644 --- a/apps/openmw/mwrender/ripplesimulation.hpp +++ b/apps/openmw/mwrender/ripplesimulation.hpp @@ -21,9 +21,9 @@ namespace Resource class ResourceSystem; } -namespace MWWorld +namespace Fallback { - class Fallback; + class Map; } namespace MWRender @@ -40,7 +40,7 @@ namespace MWRender class RippleSimulation { public: - RippleSimulation(osg::Group* parent, Resource::ResourceSystem* resourceSystem, const MWWorld::Fallback* fallback); + RippleSimulation(osg::Group* parent, Resource::ResourceSystem* resourceSystem, const Fallback::Map* fallback); ~RippleSimulation(); /// @param dt Time since the last frame diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 635116db0..efe797336 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -33,6 +33,7 @@ #include #include +#include #include #include @@ -42,8 +43,6 @@ #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" -#include "../mwworld/fallback.hpp" - #include "vismask.hpp" #include "renderbin.hpp" @@ -827,7 +826,7 @@ private: , mTimeOfDayFade(1.f) , mGlareView(1.f) { - const MWWorld::Fallback* fallback = MWBase::Environment::get().getWorld()->getFallback(); + const Fallback::Map* fallback = MWBase::Environment::get().getWorld()->getFallback(); mColor = fallback->getFallbackColour("Weather_Sun_Glare_Fader_Color"); mSunGlareFaderMax = fallback->getFallbackFloat("Weather_Sun_Glare_Fader_Max"); mSunGlareFaderAngleMax = fallback->getFallbackFloat("Weather_Sun_Glare_Fader_Angle_Max"); @@ -1161,7 +1160,7 @@ void SkyManager::create() mSun.reset(new Sun(mEarlyRenderBinRoot, *mSceneManager->getTextureManager())); - const MWWorld::Fallback* fallback=MWBase::Environment::get().getWorld()->getFallback(); + const Fallback::Map* fallback=MWBase::Environment::get().getWorld()->getFallback(); mMasser.reset(new Moon(mEarlyRenderBinRoot, *mSceneManager->getTextureManager(), fallback->getFallbackFloat("Moons_Masser_Size")/125, Moon::Type_Masser)); mSecunda.reset(new Moon(mEarlyRenderBinRoot, *mSceneManager->getTextureManager(), fallback->getFallbackFloat("Moons_Secunda_Size")/125, Moon::Type_Secunda)); diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index cd1f4c511..1b19246f5 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -34,8 +34,9 @@ #include +#include + #include "../mwworld/cellstore.hpp" -#include "../mwworld/fallback.hpp" #include "vismask.hpp" #include "ripplesimulation.hpp" @@ -457,7 +458,7 @@ public: }; Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem *resourceSystem, osgUtil::IncrementalCompileOperation *ico, - const MWWorld::Fallback* fallback, const std::string& resourcePath) + const Fallback::Map* fallback, const std::string& resourcePath) : mParent(parent) , mSceneRoot(sceneRoot) , mResourceSystem(resourceSystem) diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index b26782873..b02ee392c 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -28,11 +28,15 @@ namespace Resource namespace MWWorld { - class Fallback; class CellStore; class Ptr; } +namespace Fallback +{ + class Map; +} + namespace MWRender { @@ -50,7 +54,7 @@ namespace MWRender osg::ref_ptr mWaterNode; osg::ref_ptr mWaterGeode; Resource::ResourceSystem* mResourceSystem; - const MWWorld::Fallback* mFallback; + const Fallback::Map* mFallback; osg::ref_ptr mIncrementalCompileOperation; std::auto_ptr mSimulation; @@ -77,7 +81,7 @@ namespace MWRender public: Water(osg::Group* parent, osg::Group* sceneRoot, - Resource::ResourceSystem* resourceSystem, osgUtil::IncrementalCompileOperation* ico, const MWWorld::Fallback* fallback, + Resource::ResourceSystem* resourceSystem, osgUtil::IncrementalCompileOperation* ico, const Fallback::Map* fallback, const std::string& resourcePath); ~Water(); diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 5ce3d5c2f..c40913ff1 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -20,7 +21,6 @@ #include "player.hpp" #include "esmstore.hpp" -#include "fallback.hpp" #include "cellstore.hpp" #include @@ -100,7 +100,7 @@ template class TimeOfDayInterpolator; template class TimeOfDayInterpolator; Weather::Weather(const std::string& name, - const MWWorld::Fallback& fallback, + const Fallback::Map& fallback, float stormWindSpeed, float rainSpeed, const std::string& particleEffect) @@ -327,7 +327,7 @@ void RegionWeather::chooseNewWeather() mWeather = i; } -MoonModel::MoonModel(const std::string& name, const MWWorld::Fallback& fallback) +MoonModel::MoonModel(const std::string& name, const Fallback::Map& fallback) : mFadeInStart(fallback.getFallbackFloat("Moons_" + name + "_Fade_In_Start")) , mFadeInFinish(fallback.getFallbackFloat("Moons_" + name + "_Fade_In_Finish")) , mFadeOutStart(fallback.getFallbackFloat("Moons_" + name + "_Fade_Out_Start")) @@ -496,7 +496,7 @@ inline float MoonModel::earlyMoonShadowAlpha(float angle) const return 0.0f; } -WeatherManager::WeatherManager(MWRender::RenderingManager& rendering, const MWWorld::Fallback& fallback, MWWorld::ESMStore& store) +WeatherManager::WeatherManager(MWRender::RenderingManager& rendering, const Fallback::Map& fallback, MWWorld::ESMStore& store) : mStore(store) , mRendering(rendering) , mSunriseTime(fallback.getFallbackFloat("Weather_Sunrise_Time")) @@ -862,7 +862,7 @@ void WeatherManager::clear() } inline void WeatherManager::addWeather(const std::string& name, - const MWWorld::Fallback& fallback, + const Fallback::Map& fallback, const std::string& particleEffect) { static const float fStromWindSpeed = mStore.get().find("fStromWindSpeed")->getFloat(); diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index a5627a507..044200757 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -29,9 +29,13 @@ namespace Loading class Listener; } +namespace Fallback +{ + class Map; +} + namespace MWWorld { - class Fallback; class TimeStamp; @@ -66,7 +70,7 @@ namespace MWWorld { public: Weather(const std::string& name, - const MWWorld::Fallback& fallback, + const Fallback::Map& fallback, float stormWindSpeed, float rainSpeed, const std::string& particleEffect); @@ -172,7 +176,7 @@ namespace MWWorld class MoonModel { public: - MoonModel(const std::string& name, const MWWorld::Fallback& fallback); + MoonModel(const std::string& name, const Fallback::Map& fallback); MWRender::MoonState calculateState(const TimeStamp& gameTime) const; @@ -203,7 +207,7 @@ namespace MWWorld public: // Have to pass fallback and Store, can't use singleton since World isn't fully constructed yet at the time WeatherManager(MWRender::RenderingManager& rendering, - const MWWorld::Fallback& fallback, + const Fallback::Map& fallback, MWWorld::ESMStore& store); ~WeatherManager(); @@ -288,7 +292,7 @@ namespace MWWorld std::string mPlayingSoundID; void addWeather(const std::string& name, - const MWWorld::Fallback& fallback, + const Fallback::Map& fallback, const std::string& particleEffect = ""); void importRegions(); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 15826009d..789b1b64f 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -511,7 +511,7 @@ namespace MWWorld return 0; } - const MWWorld::Fallback *World::getFallback() const + const Fallback::Map *World::getFallback() const { return &mFallback; } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 4ed97759e..53d640871 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -5,21 +5,20 @@ #include +#include +#include + +#include "../mwbase/world.hpp" + #include "ptr.hpp" #include "scene.hpp" #include "esmstore.hpp" #include "cells.hpp" #include "localscripts.hpp" #include "timestamp.hpp" -#include "fallback.hpp" #include "globals.hpp" - -#include "../mwbase/world.hpp" - #include "contentloader.hpp" -#include - namespace osg { class Group; @@ -71,7 +70,7 @@ namespace MWWorld { Resource::ResourceSystem* mResourceSystem; - MWWorld::Fallback mFallback; + Fallback::Map mFallback; MWRender::RenderingManager* mRendering; MWWorld::WeatherManager* mWeatherManager; @@ -210,7 +209,7 @@ namespace MWWorld virtual void adjustSky(); - virtual const Fallback *getFallback() const; + virtual const Fallback::Map *getFallback() const; virtual Player& getPlayer(); virtual MWWorld::Ptr getPlayerPtr(); diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index bbbff234c..af26fc998 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -138,6 +138,10 @@ add_component_dir (version version ) +add_component_dir (fallback + fallback validate + ) + set (ESM_UI ${CMAKE_SOURCE_DIR}/files/ui/contentselector.ui ) diff --git a/apps/openmw/mwworld/fallback.cpp b/components/fallback/fallback.cpp similarity index 75% rename from apps/openmw/mwworld/fallback.cpp rename to components/fallback/fallback.cpp index e810f8241..354595660 100644 --- a/apps/openmw/mwworld/fallback.cpp +++ b/components/fallback/fallback.cpp @@ -2,12 +2,12 @@ #include -namespace MWWorld +namespace Fallback { - Fallback::Fallback(const std::map& fallback):mFallbackMap(fallback) + Map::Map(const std::map& fallback):mFallbackMap(fallback) {} - std::string Fallback::getFallbackString(const std::string& fall) const + std::string Map::getFallbackString(const std::string& fall) const { std::map::const_iterator it; if((it = mFallbackMap.find(fall)) == mFallbackMap.end()) @@ -16,7 +16,7 @@ namespace MWWorld } return it->second; } - float Fallback::getFallbackFloat(const std::string& fall) const + float Map::getFallbackFloat(const std::string& fall) const { std::string fallback=getFallbackString(fall); if(fallback.empty()) @@ -24,7 +24,7 @@ namespace MWWorld else return boost::lexical_cast(fallback); } - int Fallback::getFallbackInt(const std::string& fall) const + int Map::getFallbackInt(const std::string& fall) const { std::string fallback=getFallbackString(fall); if(fallback.empty()) @@ -33,7 +33,7 @@ namespace MWWorld return boost::lexical_cast(fallback); } - bool Fallback::getFallbackBool(const std::string& fall) const + bool Map::getFallbackBool(const std::string& fall) const { std::string fallback=getFallbackString(fall); if(fallback.empty()) @@ -41,7 +41,7 @@ namespace MWWorld else return boost::lexical_cast(fallback); } - osg::Vec4f Fallback::getFallbackColour(const std::string& fall) const + osg::Vec4f Map::getFallbackColour(const std::string& fall) const { std::string sum=getFallbackString(fall); if(sum.empty()) diff --git a/apps/openmw/mwworld/fallback.hpp b/components/fallback/fallback.hpp similarity index 67% rename from apps/openmw/mwworld/fallback.hpp rename to components/fallback/fallback.hpp index af47063ee..b44483fbc 100644 --- a/apps/openmw/mwworld/fallback.hpp +++ b/components/fallback/fallback.hpp @@ -1,18 +1,19 @@ -#ifndef GAME_MWWORLD_FALLBACK_H -#define GAME_MWWORLD_FALLBACK_H +#ifndef OPENMW_COMPONENTS_FALLBACK_H +#define OPENMW_COMPONENTS_FALLBACK_H #include #include #include -namespace MWWorld +namespace Fallback { - class Fallback + /// @brief contains settings imported from the Morrowind INI file. + class Map { const std::map mFallbackMap; public: - Fallback(const std::map& fallback); + Map(const std::map& fallback); std::string getFallbackString(const std::string& fall) const; float getFallbackFloat(const std::string& fall) const; int getFallbackInt(const std::string& fall) const; diff --git a/components/fallback/validate.hpp b/components/fallback/validate.hpp new file mode 100644 index 000000000..3b6398d6a --- /dev/null +++ b/components/fallback/validate.hpp @@ -0,0 +1,48 @@ +#ifndef OPENMW_COMPONENTS_FALLBACK_VALIDATE_H +#define OPENMW_COMPONENTS_FALLBACK_VALIDATE_H + +#include + +// Parses and validates a fallback map from boost program_options. +// Note: for boost to pick up the validate function, you need to pull in the namespace e.g. +// by using namespace Fallback; + +namespace Fallback +{ + + struct FallbackMap { + std::map mMap; + }; + + void validate(boost::any &v, std::vector const &tokens, FallbackMap*, int) + { + if(v.empty()) + { + v = boost::any(FallbackMap()); + } + + FallbackMap *map = boost::any_cast(&v); + + for(std::vector::const_iterator it=tokens.begin(); it != tokens.end(); ++it) + { + int sep = it->find(","); + if(sep < 1 || sep == (int)it->length()-1) + #if (BOOST_VERSION < 104200) + throw boost::program_options::validation_error("invalid value"); + #else + throw boost::program_options::validation_error(boost::program_options::validation_error::invalid_option_value); + #endif + + std::string key(it->substr(0,sep)); + std::string value(it->substr(sep+1)); + + if(map->mMap.find(key) == map->mMap.end()) + { + map->mMap.insert(std::make_pair (key,value)); + } + } + } + +} + +#endif From 11496b8075afeee21c93d0837f71ccec47c6d08f Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 6 Jan 2016 12:58:36 +0100 Subject: [PATCH 2975/3725] Read fallback settings in OpenCS --- apps/opencs/editor.cpp | 8 ++++++++ apps/opencs/model/doc/document.cpp | 3 ++- apps/opencs/model/doc/document.hpp | 8 +++++++- apps/opencs/model/doc/documentmanager.cpp | 7 ++++++- apps/opencs/model/doc/documentmanager.hpp | 4 ++++ components/fallback/fallback.hpp | 4 +++- 6 files changed, 30 insertions(+), 4 deletions(-) diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 92f1082b7..54e323956 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -8,6 +8,8 @@ #include #include +#include + #include #include "model/doc/document.hpp" @@ -17,6 +19,8 @@ #include #endif +using namespace Fallback; + CS::Editor::Editor () : mSettingsState (mCfgMgr), mDocumentManager (mCfgMgr), mViewManager (mDocumentManager), mPid(""), @@ -100,6 +104,8 @@ std::pair > CS::Editor::readConfi ("resources", boost::program_options::value()->default_value("resources")) ("fallback-archive", boost::program_options::value >()-> default_value(std::vector(), "fallback-archive")->multitoken()) + ("fallback", boost::program_options::value()->default_value(FallbackMap(), "") + ->multitoken()->composing(), "fallback values") ("script-blacklist", boost::program_options::value >()->default_value(std::vector(), "") ->multitoken(), "exclude specified script from the verifier (if the use of the blacklist is enabled)") ("script-blacklist-use", boost::program_options::value()->implicit_value(true) @@ -114,6 +120,8 @@ std::pair > CS::Editor::readConfi mDocumentManager.setResourceDir (mResources = variables["resources"].as()); + mDocumentManager.setFallbackMap (variables["fallback"].as().mMap); + if (variables["script-blacklist-use"].as()) mDocumentManager.setBlacklistedScripts ( variables["script-blacklist"].as >()); diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 8cafa7ae1..59d66f36c 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -2247,6 +2247,7 @@ void CSMDoc::Document::createBase() CSMDoc::Document::Document (const VFS::Manager* vfs, const Files::ConfigurationManager& configuration, const std::vector< boost::filesystem::path >& files, bool new_, const boost::filesystem::path& savePath, const boost::filesystem::path& resDir, + const Fallback::Map* fallback, ToUTF8::FromType encoding, const CSMWorld::ResourcesManager& resourcesManager, const std::vector& blacklistedScripts) : mVFS(vfs), mSavePath (savePath), mContentFiles (files), mNew (new_), mData (encoding, resourcesManager), @@ -2255,7 +2256,7 @@ CSMDoc::Document::Document (const VFS::Manager* vfs, const Files::ConfigurationM (savePath.filename().string() + ".project")), mSavingOperation (*this, mProjectPath, encoding), mSaving (&mSavingOperation), - mResDir(resDir), + mResDir(resDir), mFallbackMap(fallback), mRunner (mProjectPath), mDirty (false), mIdCompletionManager(mData) { if (mContentFiles.empty()) diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp index 0e8ae6d45..41640f66d 100644 --- a/apps/opencs/model/doc/document.hpp +++ b/apps/opencs/model/doc/document.hpp @@ -25,9 +25,13 @@ class QAbstractItemModel; -namespace VFS +namespace Fallback { + class Map; +} +namespace VFS +{ class Manager; } @@ -66,6 +70,7 @@ namespace CSMDoc Saving mSavingOperation; OperationHolder mSaving; boost::filesystem::path mResDir; + const Fallback::Map* mFallbackMap; Blacklist mBlacklist; Runner mRunner; bool mDirty; @@ -101,6 +106,7 @@ namespace CSMDoc Document (const VFS::Manager* vfs, const Files::ConfigurationManager& configuration, const std::vector< boost::filesystem::path >& files, bool new_, const boost::filesystem::path& savePath, const boost::filesystem::path& resDir, + const Fallback::Map* fallback, ToUTF8::FromType encoding, const CSMWorld::ResourcesManager& resourcesManager, const std::vector& blacklistedScripts); diff --git a/apps/opencs/model/doc/documentmanager.cpp b/apps/opencs/model/doc/documentmanager.cpp index 407a608ca..cbb255ebb 100644 --- a/apps/opencs/model/doc/documentmanager.cpp +++ b/apps/opencs/model/doc/documentmanager.cpp @@ -64,7 +64,7 @@ CSMDoc::Document *CSMDoc::DocumentManager::makeDocument ( const std::vector< boost::filesystem::path >& files, const boost::filesystem::path& savePath, bool new_) { - return new Document (mVFS, mConfiguration, files, new_, savePath, mResDir, mEncoding, mResourcesManager, mBlacklistedScripts); + return new Document (mVFS, mConfiguration, files, new_, savePath, mResDir, &mFallbackMap, mEncoding, mResourcesManager, mBlacklistedScripts); } void CSMDoc::DocumentManager::insertDocument (CSMDoc::Document *document) @@ -100,6 +100,11 @@ void CSMDoc::DocumentManager::setResourceDir (const boost::filesystem::path& par mResDir = boost::filesystem::system_complete(parResDir); } +void CSMDoc::DocumentManager::setFallbackMap(const std::map& fallbackMap) +{ + mFallbackMap = Fallback::Map(fallbackMap); +} + void CSMDoc::DocumentManager::setEncoding (ToUTF8::FromType encoding) { mEncoding = encoding; diff --git a/apps/opencs/model/doc/documentmanager.hpp b/apps/opencs/model/doc/documentmanager.hpp index 4f6b2b2c9..ed8e327d7 100644 --- a/apps/opencs/model/doc/documentmanager.hpp +++ b/apps/opencs/model/doc/documentmanager.hpp @@ -10,6 +10,7 @@ #include #include +#include #include "../world/resourcesmanager.hpp" @@ -67,6 +68,8 @@ namespace CSMDoc void setResourceDir (const boost::filesystem::path& parResDir); + void setFallbackMap (const std::map& fallbackMap); + void setEncoding (ToUTF8::FromType encoding); void setBlacklistedScripts (const std::vector& scriptIds); @@ -78,6 +81,7 @@ namespace CSMDoc private: boost::filesystem::path mResDir; + Fallback::Map mFallbackMap; private slots: diff --git a/components/fallback/fallback.hpp b/components/fallback/fallback.hpp index b44483fbc..e64936531 100644 --- a/components/fallback/fallback.hpp +++ b/components/fallback/fallback.hpp @@ -11,9 +11,11 @@ namespace Fallback /// @brief contains settings imported from the Morrowind INI file. class Map { - const std::map mFallbackMap; + std::map mFallbackMap; public: Map(const std::map& fallback); + Map() {} + std::string getFallbackString(const std::string& fall) const; float getFallbackFloat(const std::string& fall) const; int getFallbackInt(const std::string& fall) const; From fb849014bd2c413fe8bb9114ab99f5e31ada73b7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 6 Jan 2016 13:09:53 +0100 Subject: [PATCH 2976/3725] Pass the fallback map to CSMWorld::Data --- apps/opencs/model/doc/document.cpp | 2 +- apps/opencs/model/world/data.cpp | 10 ++++++++-- apps/opencs/model/world/data.hpp | 10 +++++++++- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 59d66f36c..80c14bd98 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -2250,7 +2250,7 @@ CSMDoc::Document::Document (const VFS::Manager* vfs, const Files::ConfigurationM const Fallback::Map* fallback, ToUTF8::FromType encoding, const CSMWorld::ResourcesManager& resourcesManager, const std::vector& blacklistedScripts) -: mVFS(vfs), mSavePath (savePath), mContentFiles (files), mNew (new_), mData (encoding, resourcesManager), +: mVFS(vfs), mSavePath (savePath), mContentFiles (files), mNew (new_), mData (encoding, resourcesManager, fallback), mTools (*this, encoding), mProjectPath ((configuration.getUserDataPath() / "projects") / (savePath.filename().string() + ".project")), diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 1f98b2475..6eccb7483 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -59,9 +59,10 @@ int CSMWorld::Data::count (RecordBase::State state, const CollectionBase& collec return number; } -CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourcesManager) +CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourcesManager, const Fallback::Map* fallback) : mEncoder (encoding), mPathgrids (mCells), mRefs (mCells), - mResourcesManager (resourcesManager), mReader (0), mDialogue (0), mReaderIndex(0), mResourceSystem(new Resource::ResourceSystem(resourcesManager.getVFS())) + mResourcesManager (resourcesManager), mFallbackMap(fallback), + mReader (0), mDialogue (0), mReaderIndex(0), mResourceSystem(new Resource::ResourceSystem(resourcesManager.getVFS())) { int index = 0; @@ -1201,3 +1202,8 @@ const VFS::Manager* CSMWorld::Data::getVFS() const { return mResourcesManager.getVFS(); } + +const Fallback::Map* CSMWorld::Data::getFallbackMap() const +{ + return mFallbackMap; +} diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index c6623279a..e5b8229c4 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -58,6 +58,11 @@ namespace VFS class Manager; } +namespace Fallback +{ + class Map; +} + namespace ESM { class ESMReader; @@ -104,6 +109,7 @@ namespace CSMWorld IdCollection mFilters; Collection mMetaData; const ResourcesManager& mResourcesManager; + const Fallback::Map* mFallbackMap; std::vector mModels; std::map mModelIndex; ESM::ESMReader *mReader; @@ -132,12 +138,14 @@ namespace CSMWorld public: - Data (ToUTF8::FromType encoding, const ResourcesManager& resourcesManager); + Data (ToUTF8::FromType encoding, const ResourcesManager& resourcesManager, const Fallback::Map* fallback); virtual ~Data(); const VFS::Manager* getVFS() const; + const Fallback::Map* getFallbackMap() const; + boost::shared_ptr getResourceSystem(); boost::shared_ptr getResourceSystem() const; From 438b30d6f0a1d6726a80df7ef24e49fd5623c85a Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 6 Jan 2016 13:19:15 +0100 Subject: [PATCH 2977/3725] Move configureLight to a separate file --- apps/openmw/mwrender/animation.cpp | 3 ++- components/CMakeLists.txt | 3 ++- components/sceneutil/lightmanager.cpp | 24 -------------------- components/sceneutil/lightmanager.hpp | 4 ---- components/sceneutil/lightutil.cpp | 32 +++++++++++++++++++++++++++ components/sceneutil/lightutil.hpp | 19 ++++++++++++++++ 6 files changed, 55 insertions(+), 30 deletions(-) create mode 100644 components/sceneutil/lightutil.cpp create mode 100644 components/sceneutil/lightutil.hpp diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index c2fc82881..6300d28cf 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -30,8 +30,9 @@ #include #include #include -#include +#include #include +#include #include #include diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index af26fc998..089779eda 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -45,7 +45,8 @@ add_component_dir (resource ) add_component_dir (sceneutil - clone attach lightmanager visitor util statesetupdater controller skeleton riggeometry lightcontroller positionattitudetransform + clone attach visitor util statesetupdater controller skeleton riggeometry lightcontroller + lightmanager lightutil positionattitudetransform # not used yet #workqueue ) diff --git a/components/sceneutil/lightmanager.cpp b/components/sceneutil/lightmanager.cpp index 1706bb2b1..f9182c1d2 100644 --- a/components/sceneutil/lightmanager.cpp +++ b/components/sceneutil/lightmanager.cpp @@ -371,28 +371,4 @@ namespace SceneUtil traverse(node, nv); } - void configureLight(osg::Light *light, float radius, bool isExterior, bool outQuadInLin, bool useQuadratic, - float quadraticValue, float quadraticRadiusMult, bool useLinear, float linearRadiusMult, float linearValue) - { - bool quadratic = useQuadratic && (!outQuadInLin || isExterior); - - float quadraticAttenuation = 0; - float linearAttenuation = 0; - if (quadratic) - { - float r = radius * quadraticRadiusMult; - quadraticAttenuation = quadraticValue / std::pow(r, 2); - } - if (useLinear) - { - float r = radius * linearRadiusMult; - linearAttenuation = linearValue / r; - } - - light->setLinearAttenuation(linearAttenuation); - light->setQuadraticAttenuation(quadraticAttenuation); - light->setConstantAttenuation(0.f); - - } - } diff --git a/components/sceneutil/lightmanager.hpp b/components/sceneutil/lightmanager.hpp index 3e6d3251b..07b3b4a62 100644 --- a/components/sceneutil/lightmanager.hpp +++ b/components/sceneutil/lightmanager.hpp @@ -168,10 +168,6 @@ namespace SceneUtil LightManager::LightList mLightList; }; - /// @brief Configures a light's attenuation according to vanilla Morrowind attenuation settings. - void configureLight(osg::Light* light, float radius, bool isExterior, bool outQuadInLin, bool useQuadratic, float quadraticValue, - float quadraticRadiusMult, bool useLinear, float linearRadiusMult, float linearValue); - } #endif diff --git a/components/sceneutil/lightutil.cpp b/components/sceneutil/lightutil.cpp new file mode 100644 index 000000000..711a94ba8 --- /dev/null +++ b/components/sceneutil/lightutil.cpp @@ -0,0 +1,32 @@ +#include "lightutil.hpp" + +#include + +namespace SceneUtil +{ + + void configureLight(osg::Light *light, float radius, bool isExterior, bool outQuadInLin, bool useQuadratic, + float quadraticValue, float quadraticRadiusMult, bool useLinear, float linearRadiusMult, float linearValue) + { + bool quadratic = useQuadratic && (!outQuadInLin || isExterior); + + float quadraticAttenuation = 0; + float linearAttenuation = 0; + if (quadratic) + { + float r = radius * quadraticRadiusMult; + quadraticAttenuation = quadraticValue / std::pow(r, 2); + } + if (useLinear) + { + float r = radius * linearRadiusMult; + linearAttenuation = linearValue / r; + } + + light->setLinearAttenuation(linearAttenuation); + light->setQuadraticAttenuation(quadraticAttenuation); + light->setConstantAttenuation(0.f); + + } + +} diff --git a/components/sceneutil/lightutil.hpp b/components/sceneutil/lightutil.hpp new file mode 100644 index 000000000..09d23d4a2 --- /dev/null +++ b/components/sceneutil/lightutil.hpp @@ -0,0 +1,19 @@ +#ifndef OPENMW_COMPONENTS_LIGHTUTIL_H +#define OPENMW_COMPONENTS_LIGHTUTIL_H + +namespace osg +{ + class Light; +} + +namespace SceneUtil +{ + + /// @brief Configures a light's attenuation according to vanilla Morrowind attenuation settings. + void configureLight(osg::Light* light, float radius, bool isExterior, bool outQuadInLin, bool useQuadratic, + float quadraticValue, float quadraticRadiusMult, bool useLinear, float linearRadiusMult, + float linearValue); + +} + +#endif From 3089aeccc4f82aebd9d5ae1801b3d9adcf5621eb Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 6 Jan 2016 13:37:55 +0100 Subject: [PATCH 2978/3725] Factor out SceneUtil::addLight --- apps/openmw/mwrender/animation.cpp | 66 +------------------------- components/sceneutil/lightutil.cpp | 75 ++++++++++++++++++++++++++++++ components/sceneutil/lightutil.hpp | 21 +++++++-- 3 files changed, 94 insertions(+), 68 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 6300d28cf..549d0eb8e 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include @@ -31,8 +30,6 @@ #include #include #include -#include -#include #include #include @@ -1088,38 +1085,7 @@ namespace MWRender void Animation::addExtraLight(osg::ref_ptr parent, const ESM::Light *esmLight) { - SceneUtil::FindByNameVisitor visitor("AttachLight"); - parent->accept(visitor); - - osg::Group* attachTo = NULL; - if (visitor.mFoundNode) - { - attachTo = visitor.mFoundNode; - } - else - { - osg::ComputeBoundsVisitor computeBound; - computeBound.setTraversalMask(~Mask_ParticleSystem); - parent->accept(computeBound); - - // PositionAttitudeTransform seems to be slightly faster than MatrixTransform - osg::ref_ptr trans(new osg::PositionAttitudeTransform); - trans->setPosition(computeBound.getBoundingBox().center()); - - parent->addChild(trans); - - attachTo = trans; - } - - osg::ref_ptr lightSource = new SceneUtil::LightSource; - osg::ref_ptr light (new osg::Light); - lightSource->setNodeMask(Mask_Lighting); - const Fallback::Map* fallback = MWBase::Environment::get().getWorld()->getFallback(); - - float radius = esmLight->mData.mRadius; - lightSource->setRadius(radius); - static bool outQuadInLin = fallback->getFallbackBool("LightAttenuation_OutQuadInLin"); static bool useQuadratic = fallback->getFallbackBool("LightAttenuation_UseQuadratic"); static float quadraticValue = fallback->getFallbackFloat("LightAttenuation_QuadraticValue"); @@ -1127,38 +1093,10 @@ namespace MWRender static bool useLinear = fallback->getFallbackBool("LightAttenuation_UseLinear"); static float linearRadiusMult = fallback->getFallbackFloat("LightAttenuation_LinearRadiusMult"); static float linearValue = fallback->getFallbackFloat("LightAttenuation_LinearValue"); - bool exterior = mPtr.isInCell() && mPtr.getCell()->getCell()->isExterior(); - SceneUtil::configureLight(light, radius, exterior, outQuadInLin, useQuadratic, quadraticValue, - quadraticRadiusMult, useLinear, linearRadiusMult, linearValue); - - osg::Vec4f diffuse = SceneUtil::colourFromRGB(esmLight->mData.mColor); - if (esmLight->mData.mFlags & ESM::Light::Negative) - { - diffuse *= -1; - diffuse.a() = 1; - } - light->setDiffuse(diffuse); - light->setAmbient(osg::Vec4f(0,0,0,1)); - light->setSpecular(osg::Vec4f(0,0,0,0)); - - lightSource->setLight(light); - - osg::ref_ptr ctrl (new SceneUtil::LightController); - ctrl->setDiffuse(light->getDiffuse()); - if (esmLight->mData.mFlags & ESM::Light::Flicker) - ctrl->setType(SceneUtil::LightController::LT_Flicker); - if (esmLight->mData.mFlags & ESM::Light::FlickerSlow) - ctrl->setType(SceneUtil::LightController::LT_FlickerSlow); - if (esmLight->mData.mFlags & ESM::Light::Pulse) - ctrl->setType(SceneUtil::LightController::LT_Pulse); - if (esmLight->mData.mFlags & ESM::Light::PulseSlow) - ctrl->setType(SceneUtil::LightController::LT_PulseSlow); - - lightSource->addUpdateCallback(ctrl); - - attachTo->addChild(lightSource); + SceneUtil::addLight(parent, esmLight, Mask_ParticleSystem, Mask_Lighting, exterior, outQuadInLin, + useQuadratic, quadraticValue, quadraticRadiusMult, useLinear, linearRadiusMult, linearValue); } void Animation::addEffect (const std::string& model, int effectId, bool loop, const std::string& bonename, std::string texture) diff --git a/components/sceneutil/lightutil.cpp b/components/sceneutil/lightutil.cpp index 711a94ba8..00f7f4d13 100644 --- a/components/sceneutil/lightutil.cpp +++ b/components/sceneutil/lightutil.cpp @@ -1,6 +1,16 @@ #include "lightutil.hpp" #include +#include +#include + +#include + +#include "lightmanager.hpp" +#include "lightcontroller.hpp" +#include "util.hpp" +#include "visitor.hpp" +#include "positionattitudetransform.hpp" namespace SceneUtil { @@ -29,4 +39,69 @@ namespace SceneUtil } + void addLight (osg::Group* node, const ESM::Light* esmLight, int partsysMask, int lightMask, bool isExterior, bool outQuadInLin, bool useQuadratic, + float quadraticValue, float quadraticRadiusMult, bool useLinear, float linearRadiusMult, + float linearValue) + { + SceneUtil::FindByNameVisitor visitor("AttachLight"); + node->accept(visitor); + + osg::Group* attachTo = NULL; + if (visitor.mFoundNode) + { + attachTo = visitor.mFoundNode; + } + else + { + osg::ComputeBoundsVisitor computeBound; + computeBound.setTraversalMask(~partsysMask); + node->accept(computeBound); + + // PositionAttitudeTransform seems to be slightly faster than MatrixTransform + osg::ref_ptr trans(new SceneUtil::PositionAttitudeTransform); + trans->setPosition(computeBound.getBoundingBox().center()); + + node->addChild(trans); + + attachTo = trans; + } + + osg::ref_ptr lightSource (new SceneUtil::LightSource); + osg::ref_ptr light (new osg::Light); + lightSource->setNodeMask(lightMask); + + float radius = esmLight->mData.mRadius; + lightSource->setRadius(radius); + + configureLight(light, radius, isExterior, outQuadInLin, useQuadratic, quadraticValue, + quadraticRadiusMult, useLinear, linearRadiusMult, linearValue); + + osg::Vec4f diffuse = SceneUtil::colourFromRGB(esmLight->mData.mColor); + if (esmLight->mData.mFlags & ESM::Light::Negative) + { + diffuse *= -1; + diffuse.a() = 1; + } + light->setDiffuse(diffuse); + light->setAmbient(osg::Vec4f(0,0,0,1)); + light->setSpecular(osg::Vec4f(0,0,0,0)); + + lightSource->setLight(light); + + osg::ref_ptr ctrl (new SceneUtil::LightController); + ctrl->setDiffuse(light->getDiffuse()); + if (esmLight->mData.mFlags & ESM::Light::Flicker) + ctrl->setType(SceneUtil::LightController::LT_Flicker); + if (esmLight->mData.mFlags & ESM::Light::FlickerSlow) + ctrl->setType(SceneUtil::LightController::LT_FlickerSlow); + if (esmLight->mData.mFlags & ESM::Light::Pulse) + ctrl->setType(SceneUtil::LightController::LT_Pulse); + if (esmLight->mData.mFlags & ESM::Light::PulseSlow) + ctrl->setType(SceneUtil::LightController::LT_PulseSlow); + + lightSource->addUpdateCallback(ctrl); + + attachTo->addChild(lightSource); + } + } diff --git a/components/sceneutil/lightutil.hpp b/components/sceneutil/lightutil.hpp index 09d23d4a2..f7879cd72 100644 --- a/components/sceneutil/lightutil.hpp +++ b/components/sceneutil/lightutil.hpp @@ -2,6 +2,11 @@ #define OPENMW_COMPONENTS_LIGHTUTIL_H namespace osg +{ + class Group; +} + +namespace ESM { class Light; } @@ -9,10 +14,18 @@ namespace osg namespace SceneUtil { - /// @brief Configures a light's attenuation according to vanilla Morrowind attenuation settings. - void configureLight(osg::Light* light, float radius, bool isExterior, bool outQuadInLin, bool useQuadratic, - float quadraticValue, float quadraticRadiusMult, bool useLinear, float linearRadiusMult, - float linearValue); + /// @brief Convert an ESM::Light to a SceneUtil::LightSource, and add it to a sub graph. + /// @note If the sub graph contains a node named "AttachLight" (case insensitive), then the light is added to that. + /// Otherwise, the light is added in the center of the node's bounds. + /// @param node The sub graph to add a light to + /// @param esmLight The light definition coming from the game files containing radius, color, flicker, etc. + /// @param partsysMask Node mask to ignore when computing the sub graph's bounding box. + /// @param lightMask Mask to assign to the newly created LightSource. + /// @param isExterior Is the light outside? May be used for deciding which attenuation settings to use. + /// @par Attenuation parameters come from the game INI file. + void addLight (osg::Group* node, const ESM::Light* esmLight, int partsysMask, int lightMask, bool isExterior, bool outQuadInLin, bool useQuadratic, + float quadraticValue, float quadraticRadiusMult, bool useLinear, float linearRadiusMult, + float linearValue); } From ad2145b4634def65c7e7f8b7d2a2e5da15458242 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 6 Jan 2016 14:34:39 +0100 Subject: [PATCH 2979/3725] OpenCS: use a separate enum for the toggle buttons --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/view/render/cell.cpp | 6 ++--- apps/opencs/view/render/cellarrow.cpp | 7 +++-- apps/opencs/view/render/elements.hpp | 23 ---------------- apps/opencs/view/render/instancemode.cpp | 6 ++--- apps/opencs/view/render/mask.hpp | 27 +++++++++++++++++++ apps/opencs/view/render/object.cpp | 7 +++-- .../view/render/pagedworldspacewidget.cpp | 26 +++++++++--------- apps/opencs/view/render/scenewidget.cpp | 6 ++--- apps/opencs/view/render/tagbase.cpp | 6 ++--- apps/opencs/view/render/tagbase.hpp | 8 +++--- .../view/render/unpagedworldspacewidget.cpp | 6 ++--- apps/opencs/view/render/worldspacewidget.cpp | 18 ++++++------- apps/opencs/view/render/worldspacewidget.hpp | 2 +- apps/opencs/view/widget/scenetooltoggle.cpp | 14 +++++----- apps/opencs/view/widget/scenetooltoggle.hpp | 10 +++---- apps/opencs/view/widget/scenetooltoggle2.cpp | 24 +++++++++++------ apps/opencs/view/widget/scenetooltoggle2.hpp | 21 +++++++++++---- 18 files changed, 120 insertions(+), 99 deletions(-) delete mode 100644 apps/opencs/view/render/elements.hpp create mode 100644 apps/opencs/view/render/mask.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 0e9a49432..8bb624704 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -94,7 +94,7 @@ opencs_units_noqt (view/render ) opencs_hdrs_noqt (view/render - elements + mask ) diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index da40f7e7c..40981164d 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -11,7 +11,7 @@ #include "../../model/world/refcollection.hpp" #include "../../model/world/cellcoordinates.hpp" -#include "elements.hpp" +#include "mask.hpp" #include "terrainstorage.hpp" bool CSVRender::Cell::removeObject (const std::string& id) @@ -80,7 +80,7 @@ CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::st if (esmLand.getLandData (ESM::Land::DATA_VHGT)) { - mTerrain.reset(new Terrain::TerrainGrid(mCellNode, data.getResourceSystem().get(), NULL, new TerrainStorage(mData), Element_Terrain<<1)); + mTerrain.reset(new Terrain::TerrainGrid(mCellNode, data.getResourceSystem().get(), NULL, new TerrainStorage(mData), Mask_Terrain)); mTerrain->loadCell(esmLand.mX, esmLand.mY); } @@ -230,7 +230,7 @@ bool CSVRender::Cell::referenceAdded (const QModelIndex& parent, int start, int void CSVRender::Cell::setSelection (int elementMask, Selection mode) { - if (elementMask & Element_Reference) + if (elementMask & Mask_Reference) { for (std::map::const_iterator iter (mObjects.begin()); iter!=mObjects.end(); ++iter) diff --git a/apps/opencs/view/render/cellarrow.cpp b/apps/opencs/view/render/cellarrow.cpp index 1356aa0fb..6d8fa1c6c 100644 --- a/apps/opencs/view/render/cellarrow.cpp +++ b/apps/opencs/view/render/cellarrow.cpp @@ -7,10 +7,10 @@ #include #include -#include "elements.hpp" +#include "mask.hpp" CSVRender::CellArrowTag::CellArrowTag (CellArrow *arrow) -: TagBase (Element_CellArrow), mArrow (arrow) +: TagBase (Mask_CellArrow), mArrow (arrow) {} CSVRender::CellArrow *CSVRender::CellArrowTag::getCellArrow() const @@ -165,8 +165,7 @@ CSVRender::CellArrow::CellArrow (osg::Group *cellNode, Direction direction, mParentNode->addChild (mBaseNode); - // 0x1 reserved for separating cull and update visitors - mBaseNode->setNodeMask (Element_CellArrow<<1); + mBaseNode->setNodeMask (Mask_CellArrow); adjustTransform(); buildShape(); diff --git a/apps/opencs/view/render/elements.hpp b/apps/opencs/view/render/elements.hpp deleted file mode 100644 index 5a37956e9..000000000 --- a/apps/opencs/view/render/elements.hpp +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef CSV_RENDER_ELEMENTS_H -#define CSV_RENDER_ELEMENTS_H - -namespace CSVRender -{ - /// Visual elements in a scene - enum Elements - { - // elements that are part of the actual scene - Element_Reference = 0x1, - Element_Pathgrid = 0x2, - Element_Water = 0x4, - Element_Fog = 0x8, - Element_Terrain = 0x10, - - // control elements - Element_CellMarker = 0x10000, - Element_CellArrow = 0x20000, - Element_CellBorder = 0x40000 - }; -} - -#endif diff --git a/apps/opencs/view/render/instancemode.cpp b/apps/opencs/view/render/instancemode.cpp index a4d147bb4..7f9e426c7 100644 --- a/apps/opencs/view/render/instancemode.cpp +++ b/apps/opencs/view/render/instancemode.cpp @@ -3,12 +3,12 @@ #include "../../model/prefs/state.hpp" -#include "elements.hpp" +#include "mask.hpp" #include "object.hpp" #include "worldspacewidget.hpp" CSVRender::InstanceMode::InstanceMode (WorldspaceWidget *worldspaceWidget, QWidget *parent) -: EditMode (worldspaceWidget, QIcon (":placeholder"), Element_Reference, "Instance editing", +: EditMode (worldspaceWidget, QIcon (":placeholder"), Mask_Reference, "Instance editing", parent) { @@ -28,7 +28,7 @@ void CSVRender::InstanceMode::secondaryEditPressed (osg::ref_ptr tag) void CSVRender::InstanceMode::primarySelectPressed (osg::ref_ptr tag) { - getWorldspaceWidget().clearSelection (Element_Reference); + getWorldspaceWidget().clearSelection (Mask_Reference); if (tag) { diff --git a/apps/opencs/view/render/mask.hpp b/apps/opencs/view/render/mask.hpp new file mode 100644 index 000000000..9e63cc977 --- /dev/null +++ b/apps/opencs/view/render/mask.hpp @@ -0,0 +1,27 @@ +#ifndef CSV_RENDER_ELEMENTS_H +#define CSV_RENDER_ELEMENTS_H + +namespace CSVRender +{ + + /// @note Enumeration values can be changed freely, as long as they do not collide. + enum Mask + { + // internal use within NifLoader, do not change + Mask_UpdateVisitor = 0x1, + + // elements that are part of the actual scene + Mask_Reference = 0x2, + Mask_Pathgrid = 0x4, + Mask_Water = 0x8, + Mask_Fog = 0x10, + Mask_Terrain = 0x20, + + // control elements + Mask_CellMarker = 0x10000, + Mask_CellArrow = 0x20000, + Mask_CellBorder = 0x40000 + }; +} + +#endif diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index c295a023a..2ff80b38b 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -19,7 +19,7 @@ #include #include -#include "elements.hpp" +#include "mask.hpp" namespace { @@ -39,7 +39,7 @@ namespace CSVRender::ObjectTag::ObjectTag (Object* object) -: TagBase (Element_Reference), mObject (object) +: TagBase (Mask_Reference), mObject (object) {} QString CSVRender::ObjectTag::getToolTip (bool hideBasics) const @@ -138,8 +138,7 @@ CSVRender::Object::Object (CSMWorld::Data& data, osg::Group* parentNode, parentNode->addChild(mBaseNode); - // 0x1 reserved for separating cull and update visitors - mBaseNode->setNodeMask(Element_Reference<<1); + mBaseNode->setNodeMask(Mask_Reference); if (referenceable) { diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index dae5990e6..e0707524d 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -18,7 +18,7 @@ #include "../widget/scenetooltoggle2.hpp" #include "editmode.hpp" -#include "elements.hpp" +#include "mask.hpp" bool CSVRender::PagedWorldspaceWidget::adjustCells() { @@ -126,8 +126,8 @@ void CSVRender::PagedWorldspaceWidget::addVisibilitySelectorButtons ( CSVWidget::SceneToolToggle2 *tool) { WorldspaceWidget::addVisibilitySelectorButtons (tool); - tool->addButton (Element_Terrain, "Terrain"); - tool->addButton (Element_Fog, "Fog", "", true); + tool->addButton (CSVWidget::SceneToolToggle2::Button_Terrain, Mask_Terrain, "Terrain"); + tool->addButton (CSVWidget::SceneToolToggle2::Button_Fog, Mask_Fog, "Fog", "", true); } void CSVRender::PagedWorldspaceWidget::addEditModeSelectorButtons ( @@ -137,22 +137,22 @@ void CSVRender::PagedWorldspaceWidget::addEditModeSelectorButtons ( /// \todo replace EditMode with suitable subclasses tool->addButton ( - new EditMode (this, QIcon (":placeholder"), Element_Reference, "Terrain shape editing"), + new EditMode (this, QIcon (":placeholder"), Mask_Reference, "Terrain shape editing"), "terrain-shape"); tool->addButton ( - new EditMode (this, QIcon (":placeholder"), Element_Reference, "Terrain texture editing"), + new EditMode (this, QIcon (":placeholder"), Mask_Reference, "Terrain texture editing"), "terrain-texture"); tool->addButton ( - new EditMode (this, QIcon (":placeholder"), Element_Reference, "Terrain vertex paint editing"), + new EditMode (this, QIcon (":placeholder"), Mask_Reference, "Terrain vertex paint editing"), "terrain-vertex"); tool->addButton ( - new EditMode (this, QIcon (":placeholder"), Element_Reference, "Terrain movement"), + new EditMode (this, QIcon (":placeholder"), Mask_Reference, "Terrain movement"), "terrain-move"); } void CSVRender::PagedWorldspaceWidget::handleMouseClick (osg::ref_ptr tag, const std::string& button, bool shift) { - if (tag && tag->getElement()==Element_CellArrow) + if (tag && tag->getMask()==Mask_CellArrow) { if (button=="p-edit" || button=="s-edit") { @@ -492,7 +492,7 @@ CSVRender::WorldspaceWidget::dropRequirments CSVRender::PagedWorldspaceWidget::g unsigned int CSVRender::PagedWorldspaceWidget::getVisibilityMask() const { - return WorldspaceWidget::getVisibilityMask() | mControlElements->getSelection(); + return WorldspaceWidget::getVisibilityMask() | mControlElements->getSelectionMask(); } void CSVRender::PagedWorldspaceWidget::clearSelection (int elementMask) @@ -510,12 +510,12 @@ CSVWidget::SceneToolToggle *CSVRender::PagedWorldspaceWidget::makeControlVisibil mControlElements = new CSVWidget::SceneToolToggle (parent, "Controls & Guides Visibility", ":placeholder"); - mControlElements->addButton (":placeholder", Element_CellMarker, ":placeholder", + mControlElements->addButton (":placeholder", Mask_CellMarker, ":placeholder", "Cell marker"); - mControlElements->addButton (":placeholder", Element_CellArrow, ":placeholder", "Cell arrows"); - mControlElements->addButton (":placeholder", Element_CellBorder, ":placeholder", "Cell border"); + mControlElements->addButton (":placeholder", Mask_CellArrow, ":placeholder", "Cell arrows"); + mControlElements->addButton (":placeholder", Mask_CellBorder, ":placeholder", "Cell border"); - mControlElements->setSelection (0xffffffff); + mControlElements->setSelectionMask (0xffffffff); connect (mControlElements, SIGNAL (selectionChanged()), this, SLOT (elementSelectionChanged())); diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index b1300a991..d06a6b001 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -18,6 +18,7 @@ #include "../widget/scenetoolmode.hpp" #include "lighting.hpp" +#include "mask.hpp" namespace CSVRender { @@ -73,7 +74,7 @@ RenderWidget::RenderWidget(QWidget *parent, Qt::WindowFlags f) // Press S to reveal profiling stats mView->addEventHandler(new osgViewer::StatsHandler); - mView->getCamera()->setCullMask(~(0x1)); + mView->getCamera()->setCullMask(~(Mask_UpdateVisitor)); viewer.addView(mView); viewer.setDone(false); @@ -92,8 +93,7 @@ void RenderWidget::flagAsModified() void RenderWidget::setVisibilityMask(int mask) { - // 0x1 reserved for separating cull and update visitors - mView->getCamera()->setCullMask(mask<<1); + mView->getCamera()->setCullMask(mask); } bool RenderWidget::eventFilter(QObject* obj, QEvent* event) diff --git a/apps/opencs/view/render/tagbase.cpp b/apps/opencs/view/render/tagbase.cpp index 79412c132..3ddd68690 100644 --- a/apps/opencs/view/render/tagbase.cpp +++ b/apps/opencs/view/render/tagbase.cpp @@ -1,11 +1,11 @@ #include "tagbase.hpp" -CSVRender::TagBase::TagBase (Elements element) : mElement (element) {} +CSVRender::TagBase::TagBase (Mask mask) : mMask (mask) {} -CSVRender::Elements CSVRender::TagBase::getElement() const +CSVRender::Mask CSVRender::TagBase::getMask() const { - return mElement; + return mMask; } QString CSVRender::TagBase::getToolTip (bool hideBasics) const diff --git a/apps/opencs/view/render/tagbase.hpp b/apps/opencs/view/render/tagbase.hpp index 9f169c3b1..d1ecd2cfd 100644 --- a/apps/opencs/view/render/tagbase.hpp +++ b/apps/opencs/view/render/tagbase.hpp @@ -5,19 +5,19 @@ #include -#include "elements.hpp" +#include "mask.hpp" namespace CSVRender { class TagBase : public osg::Referenced { - Elements mElement; + Mask mMask; public: - TagBase (Elements element); + TagBase (Mask mask); - Elements getElement() const; + Mask getMask() const; virtual QString getToolTip (bool hideBasics) const; diff --git a/apps/opencs/view/render/unpagedworldspacewidget.cpp b/apps/opencs/view/render/unpagedworldspacewidget.cpp index 68f068dac..4b2ff9a5f 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.cpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.cpp @@ -17,7 +17,7 @@ #include "../widget/scenetooltoggle.hpp" #include "../widget/scenetooltoggle2.hpp" -#include "elements.hpp" +#include "mask.hpp" void CSVRender::UnpagedWorldspaceWidget::update() { @@ -166,8 +166,8 @@ void CSVRender::UnpagedWorldspaceWidget::addVisibilitySelectorButtons ( CSVWidget::SceneToolToggle2 *tool) { WorldspaceWidget::addVisibilitySelectorButtons (tool); - tool->addButton (Element_Terrain, "Terrain", "", true); - tool->addButton (Element_Fog, "Fog"); + tool->addButton (CSVWidget::SceneToolToggle2::Button_Terrain, Mask_Terrain, "Terrain", "", true); + tool->addButton (CSVWidget::SceneToolToggle2::Button_Fog, Mask_Fog, "Fog"); } std::string CSVRender::UnpagedWorldspaceWidget::getStartupInstruction() diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index f0d398641..3b169b5c2 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -27,7 +27,7 @@ #include "../widget/scenetoolrun.hpp" #include "object.hpp" -#include "elements.hpp" +#include "mask.hpp" #include "editmode.hpp" #include "instancemode.hpp" @@ -160,7 +160,7 @@ CSVWidget::SceneToolToggle2 *CSVRender::WorldspaceWidget::makeSceneVisibilitySel addVisibilitySelectorButtons (mSceneElements); - mSceneElements->setSelection (0xffffffff); + mSceneElements->setSelectionMask (0xffffffff); connect (mSceneElements, SIGNAL (selectionChanged()), this, SLOT (elementSelectionChanged())); @@ -275,12 +275,12 @@ bool CSVRender::WorldspaceWidget::handleDrop (const std::vectorgetSelection(); + return mSceneElements->getSelectionMask(); } void CSVRender::WorldspaceWidget::setInteractionMask (unsigned int mask) { - mInteractionMask = mask | Element_CellMarker | Element_CellArrow; + mInteractionMask = mask | Mask_CellMarker | Mask_CellArrow; } unsigned int CSVRender::WorldspaceWidget::getInteractionMask() const @@ -296,9 +296,9 @@ void CSVRender::WorldspaceWidget::setEditLock (bool locked) void CSVRender::WorldspaceWidget::addVisibilitySelectorButtons ( CSVWidget::SceneToolToggle2 *tool) { - tool->addButton (Element_Reference, "Instances"); - tool->addButton (Element_Water, "Water"); - tool->addButton (Element_Pathgrid, "Pathgrid"); + tool->addButton (CSVWidget::SceneToolToggle2::Button_Reference, Mask_Reference, "Instances"); + tool->addButton (CSVWidget::SceneToolToggle2::Button_Water, Mask_Water, "Water"); + tool->addButton (CSVWidget::SceneToolToggle2::Button_Pathgrid, Mask_Pathgrid, "Pathgrid"); } void CSVRender::WorldspaceWidget::addEditModeSelectorButtons (CSVWidget::SceneToolMode *tool) @@ -306,7 +306,7 @@ void CSVRender::WorldspaceWidget::addEditModeSelectorButtons (CSVWidget::SceneTo /// \todo replace EditMode with suitable subclasses tool->addButton (new InstanceMode (this, tool), "object"); tool->addButton ( - new EditMode (this, QIcon (":placeholder"), Element_Pathgrid, "Pathgrid editing"), + new EditMode (this, QIcon (":placeholder"), Mask_Pathgrid, "Pathgrid editing"), "pathgrid"); } @@ -404,7 +404,7 @@ osg::ref_ptr CSVRender::WorldspaceWidget::mousePick (const Q intersector->setIntersectionLimit(osgUtil::LineSegmentIntersector::NO_LIMIT); osgUtil::IntersectionVisitor visitor(intersector); - visitor.setTraversalMask(getInteractionMask() << 1); + visitor.setTraversalMask(getInteractionMask()); mView->getCamera()->accept(visitor); diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp index 54376cee4..07e505fe2 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -11,7 +11,7 @@ #include "../../model/world/tablemimedata.hpp" #include "scenewidget.hpp" -#include "elements.hpp" +#include "mask.hpp" namespace CSMPrefs { diff --git a/apps/opencs/view/widget/scenetooltoggle.cpp b/apps/opencs/view/widget/scenetooltoggle.cpp index d7251882a..5919a280a 100644 --- a/apps/opencs/view/widget/scenetooltoggle.cpp +++ b/apps/opencs/view/widget/scenetooltoggle.cpp @@ -40,7 +40,7 @@ void CSVWidget::SceneToolToggle::adjustToolTip() void CSVWidget::SceneToolToggle::adjustIcon() { - unsigned int selection = getSelection(); + unsigned int selection = getSelectionMask(); if (!selection) setIcon (QIcon (QString::fromUtf8 (mEmptyIcon.c_str()))); else @@ -135,7 +135,7 @@ void CSVWidget::SceneToolToggle::showPanel (const QPoint& position) mFirst->setFocus (Qt::OtherFocusReason); } -void CSVWidget::SceneToolToggle::addButton (const std::string& icon, unsigned int id, +void CSVWidget::SceneToolToggle::addButton (const std::string& icon, unsigned int mask, const std::string& smallIcon, const QString& name, const QString& tooltip) { if (mButtons.size()>=9) @@ -151,7 +151,7 @@ void CSVWidget::SceneToolToggle::addButton (const std::string& icon, unsigned in mLayout->addWidget (button); ButtonDesc desc; - desc.mId = id; + desc.mMask = mask; desc.mSmallIcon = smallIcon; desc.mName = name; desc.mIndex = mButtons.size(); @@ -164,23 +164,23 @@ void CSVWidget::SceneToolToggle::addButton (const std::string& icon, unsigned in mFirst = button; } -unsigned int CSVWidget::SceneToolToggle::getSelection() const +unsigned int CSVWidget::SceneToolToggle::getSelectionMask() const { unsigned int selection = 0; for (std::map::const_iterator iter (mButtons.begin()); iter!=mButtons.end(); ++iter) if (iter->first->isChecked()) - selection |= iter->second.mId; + selection |= iter->second.mMask; return selection; } -void CSVWidget::SceneToolToggle::setSelection (unsigned int selection) +void CSVWidget::SceneToolToggle::setSelectionMask (unsigned int selection) { for (std::map::iterator iter (mButtons.begin()); iter!=mButtons.end(); ++iter) - iter->first->setChecked (selection & iter->second.mId); + iter->first->setChecked (selection & iter->second.mMask); adjustToolTip(); adjustIcon(); diff --git a/apps/opencs/view/widget/scenetooltoggle.hpp b/apps/opencs/view/widget/scenetooltoggle.hpp index 55e697524..68cd2362e 100644 --- a/apps/opencs/view/widget/scenetooltoggle.hpp +++ b/apps/opencs/view/widget/scenetooltoggle.hpp @@ -20,7 +20,7 @@ namespace CSVWidget struct ButtonDesc { - unsigned int mId; + unsigned int mMask; std::string mSmallIcon; QString mName; int mIndex; @@ -54,13 +54,13 @@ namespace CSVWidget /// \note The layout algorithm can not handle more than 9 buttons. To prevent this An /// attempt to add more will result in an exception being thrown. /// The small icons will be sized at (x-4)/3 (where x is the main icon size). - void addButton (const std::string& icon, unsigned int id, + void addButton (const std::string& icon, unsigned int mask, const std::string& smallIcon, const QString& name, const QString& tooltip = ""); - unsigned int getSelection() const; + unsigned int getSelectionMask() const; - /// \param or'ed button IDs. IDs that do not exist will be ignored. - void setSelection (unsigned int selection); + /// \param or'ed button masks. buttons that do not exist will be ignored. + void setSelectionMask (unsigned int selection); signals: diff --git a/apps/opencs/view/widget/scenetooltoggle2.cpp b/apps/opencs/view/widget/scenetooltoggle2.cpp index e0431476e..3972aadaa 100644 --- a/apps/opencs/view/widget/scenetooltoggle2.cpp +++ b/apps/opencs/view/widget/scenetooltoggle2.cpp @@ -41,8 +41,15 @@ void CSVWidget::SceneToolToggle2::adjustToolTip() void CSVWidget::SceneToolToggle2::adjustIcon() { + unsigned int buttonIds = 0; + + for (std::map::const_iterator iter (mButtons.begin()); + iter!=mButtons.end(); ++iter) + if (iter->first->isChecked()) + buttonIds |= iter->second.mButtonId; + std::ostringstream stream; - stream << mCompositeIcon << getSelection(); + stream << mCompositeIcon << buttonIds; setIcon (QIcon (QString::fromUtf8 (stream.str().c_str()))); } @@ -70,11 +77,11 @@ void CSVWidget::SceneToolToggle2::showPanel (const QPoint& position) mFirst->setFocus (Qt::OtherFocusReason); } -void CSVWidget::SceneToolToggle2::addButton (unsigned int id, +void CSVWidget::SceneToolToggle2::addButton (ButtonId id, unsigned int mask, const QString& name, const QString& tooltip, bool disabled) { std::ostringstream stream; - stream << mSingleIcon << id; + stream << mSingleIcon << static_cast(id); PushButton *button = new PushButton (QIcon (QPixmap (stream.str().c_str())), PushButton::Type_Toggle, tooltip.isEmpty() ? name: tooltip, mPanel); @@ -89,7 +96,8 @@ void CSVWidget::SceneToolToggle2::addButton (unsigned int id, mLayout->addWidget (button); ButtonDesc desc; - desc.mId = id; + desc.mButtonId = id; + desc.mMask = mask; desc.mName = name; desc.mIndex = mButtons.size(); @@ -101,23 +109,23 @@ void CSVWidget::SceneToolToggle2::addButton (unsigned int id, mFirst = button; } -unsigned int CSVWidget::SceneToolToggle2::getSelection() const +unsigned int CSVWidget::SceneToolToggle2::getSelectionMask() const { unsigned int selection = 0; for (std::map::const_iterator iter (mButtons.begin()); iter!=mButtons.end(); ++iter) if (iter->first->isChecked()) - selection |= iter->second.mId; + selection |= iter->second.mMask; return selection; } -void CSVWidget::SceneToolToggle2::setSelection (unsigned int selection) +void CSVWidget::SceneToolToggle2::setSelectionMask (unsigned int selection) { for (std::map::iterator iter (mButtons.begin()); iter!=mButtons.end(); ++iter) - iter->first->setChecked (selection & iter->second.mId); + iter->first->setChecked (selection & iter->second.mMask); adjustToolTip(); adjustIcon(); diff --git a/apps/opencs/view/widget/scenetooltoggle2.hpp b/apps/opencs/view/widget/scenetooltoggle2.hpp index 0bae780f9..eea9c3ebc 100644 --- a/apps/opencs/view/widget/scenetooltoggle2.hpp +++ b/apps/opencs/view/widget/scenetooltoggle2.hpp @@ -22,7 +22,8 @@ namespace CSVWidget struct ButtonDesc { - unsigned int mId; + unsigned int mButtonId; + unsigned int mMask; QString mName; int mIndex; }; @@ -53,15 +54,25 @@ namespace CSVWidget virtual void showPanel (const QPoint& position); + /// Visual elements in a scene + /// @note do not change the enumeration values, they are used in pre-existing button file names! + enum ButtonId + { + Button_Reference = 0x1, + Button_Pathgrid = 0x2, + Button_Water = 0x4, + Button_Fog = 0x8, + Button_Terrain = 0x10 + }; /// \attention After the last button has been added, setSelection must be called at /// least once to finalise the layout. - void addButton (unsigned int id, + void addButton (ButtonId buttonId, unsigned int mask, const QString& name, const QString& tooltip = "", bool disabled = false); - unsigned int getSelection() const; + unsigned int getSelectionMask() const; - /// \param or'ed button IDs. IDs that do not exist will be ignored. - void setSelection (unsigned int selection); + /// \param or'ed button masks. buttons that do not exist will be ignored. + void setSelectionMask (unsigned int selection); signals: From e7bb8878f3f0a162e89f804e49014615a1894251 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 6 Jan 2016 14:39:48 +0100 Subject: [PATCH 2980/3725] OpenCS: add a mask for particle systems --- apps/opencs/view/render/mask.hpp | 3 +++ apps/opencs/view/render/scenewidget.cpp | 4 +++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/opencs/view/render/mask.hpp b/apps/opencs/view/render/mask.hpp index 9e63cc977..984dccae4 100644 --- a/apps/opencs/view/render/mask.hpp +++ b/apps/opencs/view/render/mask.hpp @@ -17,6 +17,9 @@ namespace CSVRender Mask_Fog = 0x10, Mask_Terrain = 0x20, + // used within models + Mask_ParticleSystem = 0x100, + // control elements Mask_CellMarker = 0x10000, Mask_CellArrow = 0x20000, diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index d06a6b001..d7138b392 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -93,7 +93,7 @@ void RenderWidget::flagAsModified() void RenderWidget::setVisibilityMask(int mask) { - mView->getCamera()->setCullMask(mask); + mView->getCamera()->setCullMask(mask | Mask_ParticleSystem); } bool RenderWidget::eventFilter(QObject* obj, QEvent* event) @@ -167,6 +167,8 @@ SceneWidget::SceneWidget(boost::shared_ptr resourceSys setLighting(&mLightingDay); + mResourceSystem->getSceneManager()->setParticleSystemMask(Mask_ParticleSystem); + /// \todo make shortcut configurable QShortcut *focusToolbar = new QShortcut (Qt::Key_T, this, 0, 0, Qt::WidgetWithChildrenShortcut); connect (focusToolbar, SIGNAL (activated()), this, SIGNAL (focusToolbarRequest())); From 7f967153ef993752c65bcda70bb4724eb76025af Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 6 Jan 2016 15:00:58 +0100 Subject: [PATCH 2981/3725] OpenCS: create light sources --- apps/opencs/view/render/object.cpp | 30 ++++++++++++++++++++++++- apps/opencs/view/render/scenewidget.cpp | 5 ++++- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index 2ff80b38b..f202be4bc 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -17,7 +17,9 @@ #include "../../model/world/refidcollection.hpp" #include -#include +#include +#include +#include #include "mask.hpp" @@ -62,6 +64,7 @@ void CSVRender::Object::update() const CSMWorld::RefIdCollection& referenceables = mData.getReferenceables(); int index = referenceables.searchId (mReferenceableId); + const ESM::Light* light = NULL; if (index==-1) error = 1; @@ -73,6 +76,14 @@ void CSVRender::Object::update() referenceables.findColumnIndex (CSMWorld::Columns::ColumnId_Model)). toString().toUtf8().constData(); + int recordType = + referenceables.getData (index, + referenceables.findColumnIndex(CSMWorld::Columns::ColumnId_RecordType)).toInt(); + if (recordType == CSMWorld::UniversalId::Type_Light) + { + light = &dynamic_cast& >(referenceables.getRecord(index)).get(); + } + if (model.empty()) error = 2; } @@ -97,6 +108,21 @@ void CSVRender::Object::update() std::cerr << e.what() << std::endl; } } + + if (light) + { + const Fallback::Map* fallback = mData.getFallbackMap(); + static bool outQuadInLin = fallback->getFallbackBool("LightAttenuation_OutQuadInLin"); + static bool useQuadratic = fallback->getFallbackBool("LightAttenuation_UseQuadratic"); + static float quadraticValue = fallback->getFallbackFloat("LightAttenuation_QuadraticValue"); + static float quadraticRadiusMult = fallback->getFallbackFloat("LightAttenuation_QuadraticRadiusMult"); + static bool useLinear = fallback->getFallbackBool("LightAttenuation_UseLinear"); + static float linearRadiusMult = fallback->getFallbackFloat("LightAttenuation_LinearRadiusMult"); + static float linearValue = fallback->getFallbackFloat("LightAttenuation_LinearValue"); + bool isExterior = false; // FIXME + SceneUtil::addLight(mBaseNode, light, Mask_ParticleSystem, ~0u, isExterior, outQuadInLin, useQuadratic, + quadraticValue, quadraticRadiusMult, useLinear, linearRadiusMult, linearValue); + } } void CSVRender::Object::adjustTransform() @@ -131,6 +157,8 @@ CSVRender::Object::Object (CSMWorld::Data& data, osg::Group* parentNode, : mData (data), mBaseNode(0), mSelected(false), mParentNode(parentNode), mResourceSystem(data.getResourceSystem().get()), mForceBaseToZero (forceBaseToZero) { mBaseNode = new osg::PositionAttitudeTransform; + mBaseNode->addCullCallback(new SceneUtil::LightListCallback); + mOutline = new osgFX::Scribe; mOutline->addChild(mBaseNode); diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index d7138b392..c51b22e09 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -14,6 +14,7 @@ #include #include +#include #include "../widget/scenetoolmode.hpp" @@ -64,7 +65,9 @@ RenderWidget::RenderWidget(QWidget *parent, Qt::WindowFlags f) mView->getCamera()->setViewport( new osg::Viewport(0, 0, traits->width, traits->height) ); mView->getCamera()->setProjectionMatrixAsPerspective(30.0f, static_cast(traits->width)/static_cast(traits->height), 1.0f, 10000.0f ); - mRootNode = new osg::Group; + SceneUtil::LightManager* lightMgr = new SceneUtil::LightManager; + lightMgr->setStartLight(1); + mRootNode = lightMgr; mView->getCamera()->getOrCreateStateSet()->setMode(GL_NORMALIZE, osg::StateAttribute::ON); mView->getCamera()->getOrCreateStateSet()->setMode(GL_CULL_FACE, osg::StateAttribute::ON); From 93cc08a09cd5f132e7e79ad28737c33df7852d9d Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 6 Jan 2016 23:14:32 +0100 Subject: [PATCH 2982/3725] Lighting fix for LightListCallbacks attached to a Transform node --- components/sceneutil/lightmanager.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/components/sceneutil/lightmanager.cpp b/components/sceneutil/lightmanager.cpp index f9182c1d2..64448e73e 100644 --- a/components/sceneutil/lightmanager.cpp +++ b/components/sceneutil/lightmanager.cpp @@ -309,8 +309,15 @@ namespace SceneUtil const osg::RefMatrix* viewMatrix = cv->getCurrentRenderStage()->getInitialViewMatrix(); const std::vector& lights = mLightManager->getLightsInViewSpace(cv->getCurrentCamera(), viewMatrix); - // we do the intersections in view space - osg::BoundingSphere nodeBound = node->getBound(); + // get the node bounds in view space + // NB do not node->getBound() * modelView, that would apply the node's transformation twice + osg::BoundingSphere nodeBound; + osg::Group* group = node->asGroup(); + if (group) + { + for (unsigned int i=0; igetNumChildren(); ++i) + nodeBound.expandBy(group->getChild(i)->getBound()); + } osg::Matrixf mat = *cv->getModelViewMatrix(); transformBoundingSphere(mat, nodeBound); From e1c7165bfb37c881aeb753dd67479501620d14fb Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 6 Jan 2016 23:16:47 +0100 Subject: [PATCH 2983/3725] Fix bounds calculation for addLight to a transform node --- components/sceneutil/lightutil.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/components/sceneutil/lightutil.cpp b/components/sceneutil/lightutil.cpp index 00f7f4d13..725157e23 100644 --- a/components/sceneutil/lightutil.cpp +++ b/components/sceneutil/lightutil.cpp @@ -55,7 +55,9 @@ namespace SceneUtil { osg::ComputeBoundsVisitor computeBound; computeBound.setTraversalMask(~partsysMask); - node->accept(computeBound); + // We want the bounds of all children of the node, ignoring the node's local transformation + // So do a traverse(), not accept() + computeBound.traverse(*node); // PositionAttitudeTransform seems to be slightly faster than MatrixTransform osg::ref_ptr trans(new SceneUtil::PositionAttitudeTransform); From 458a305bff2bcdd9d82d347a13539c537cf14628 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 6 Jan 2016 23:20:26 +0100 Subject: [PATCH 2984/3725] OpenCS: add lighting mask --- apps/opencs/view/render/mask.hpp | 2 ++ apps/opencs/view/render/object.cpp | 2 +- apps/opencs/view/render/scenewidget.cpp | 3 ++- components/sceneutil/lightutil.cpp | 2 +- components/sceneutil/lightutil.hpp | 2 +- 5 files changed, 7 insertions(+), 4 deletions(-) diff --git a/apps/opencs/view/render/mask.hpp b/apps/opencs/view/render/mask.hpp index 984dccae4..d2dfef7b4 100644 --- a/apps/opencs/view/render/mask.hpp +++ b/apps/opencs/view/render/mask.hpp @@ -20,6 +20,8 @@ namespace CSVRender // used within models Mask_ParticleSystem = 0x100, + Mask_Lighting = 0x200, + // control elements Mask_CellMarker = 0x10000, Mask_CellArrow = 0x20000, diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index f202be4bc..1821da059 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -120,7 +120,7 @@ void CSVRender::Object::update() static float linearRadiusMult = fallback->getFallbackFloat("LightAttenuation_LinearRadiusMult"); static float linearValue = fallback->getFallbackFloat("LightAttenuation_LinearValue"); bool isExterior = false; // FIXME - SceneUtil::addLight(mBaseNode, light, Mask_ParticleSystem, ~0u, isExterior, outQuadInLin, useQuadratic, + SceneUtil::addLight(mBaseNode, light, Mask_ParticleSystem, Mask_Lighting, isExterior, outQuadInLin, useQuadratic, quadraticValue, quadraticRadiusMult, useLinear, linearRadiusMult, linearValue); } } diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index c51b22e09..e5b9171e0 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -67,6 +67,7 @@ RenderWidget::RenderWidget(QWidget *parent, Qt::WindowFlags f) SceneUtil::LightManager* lightMgr = new SceneUtil::LightManager; lightMgr->setStartLight(1); + lightMgr->setLightingMask(Mask_Lighting); mRootNode = lightMgr; mView->getCamera()->getOrCreateStateSet()->setMode(GL_NORMALIZE, osg::StateAttribute::ON); @@ -96,7 +97,7 @@ void RenderWidget::flagAsModified() void RenderWidget::setVisibilityMask(int mask) { - mView->getCamera()->setCullMask(mask | Mask_ParticleSystem); + mView->getCamera()->setCullMask(mask | Mask_ParticleSystem | Mask_Lighting); } bool RenderWidget::eventFilter(QObject* obj, QEvent* event) diff --git a/components/sceneutil/lightutil.cpp b/components/sceneutil/lightutil.cpp index 725157e23..6499c54b1 100644 --- a/components/sceneutil/lightutil.cpp +++ b/components/sceneutil/lightutil.cpp @@ -39,7 +39,7 @@ namespace SceneUtil } - void addLight (osg::Group* node, const ESM::Light* esmLight, int partsysMask, int lightMask, bool isExterior, bool outQuadInLin, bool useQuadratic, + void addLight (osg::Group* node, const ESM::Light* esmLight, unsigned int partsysMask, unsigned int lightMask, bool isExterior, bool outQuadInLin, bool useQuadratic, float quadraticValue, float quadraticRadiusMult, bool useLinear, float linearRadiusMult, float linearValue) { diff --git a/components/sceneutil/lightutil.hpp b/components/sceneutil/lightutil.hpp index f7879cd72..810ffa318 100644 --- a/components/sceneutil/lightutil.hpp +++ b/components/sceneutil/lightutil.hpp @@ -23,7 +23,7 @@ namespace SceneUtil /// @param lightMask Mask to assign to the newly created LightSource. /// @param isExterior Is the light outside? May be used for deciding which attenuation settings to use. /// @par Attenuation parameters come from the game INI file. - void addLight (osg::Group* node, const ESM::Light* esmLight, int partsysMask, int lightMask, bool isExterior, bool outQuadInLin, bool useQuadratic, + void addLight (osg::Group* node, const ESM::Light* esmLight, unsigned int partsysMask, unsigned int lightMask, bool isExterior, bool outQuadInLin, bool useQuadratic, float quadraticValue, float quadraticRadiusMult, bool useLinear, float linearRadiusMult, float linearValue); From 4e6a60672d3cc265f7532433f79f73eeb2e8bf03 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 12 Jan 2016 00:31:34 +0100 Subject: [PATCH 2985/3725] When a spell explodes on an actor do not apply it to that actor twice (Fixes #3142) --- apps/openmw/mwbase/world.hpp | 4 ++-- apps/openmw/mwmechanics/spellcasting.cpp | 2 +- apps/openmw/mwworld/projectilemanager.cpp | 3 ++- apps/openmw/mwworld/worldimp.cpp | 7 +++++-- apps/openmw/mwworld/worldimp.hpp | 4 ++-- 5 files changed, 12 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 462d08727..a1580c434 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -521,8 +521,8 @@ namespace MWBase virtual void spawnEffect (const std::string& model, const std::string& textureOverride, const osg::Vec3f& worldPos) = 0; - virtual void explodeSpell (const osg::Vec3f& origin, const ESM::EffectList& effects, - const MWWorld::Ptr& caster, ESM::RangeType rangeType, const std::string& id, const std::string& sourceName) = 0; + virtual void explodeSpell (const osg::Vec3f& origin, const ESM::EffectList& effects, const MWWorld::Ptr& caster, + const MWWorld::Ptr& ignore, ESM::RangeType rangeType, const std::string& id, const std::string& sourceName) = 0; virtual void activate (const MWWorld::Ptr& object, const MWWorld::Ptr& actor) = 0; diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index ab8784beb..6073076e0 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -552,7 +552,7 @@ namespace MWMechanics } if (!exploded) - MWBase::Environment::get().getWorld()->explodeSpell(mHitPosition, effects, caster, range, mId, mSourceName); + MWBase::Environment::get().getWorld()->explodeSpell(mHitPosition, effects, caster, target, range, mId, mSourceName); if (!reflectedEffects.mList.empty()) inflict(caster, target, reflectedEffects, range, true, exploded); diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 439ac19ec..d1faf621c 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -237,7 +237,8 @@ namespace MWWorld if (hit) { - MWBase::Environment::get().getWorld()->explodeSpell(pos, it->mEffects, caster, ESM::RT_Target, it->mSpellId, it->mSourceName); + MWBase::Environment::get().getWorld()->explodeSpell(pos, it->mEffects, caster, result.mHitObject, + ESM::RT_Target, it->mSpellId, it->mSourceName); MWBase::Environment::get().getSoundManager()->stopSound(it->mSound); mParent->removeChild(it->mNode); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 19d90e209..810eff643 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -3072,8 +3072,8 @@ namespace MWWorld mRendering->spawnEffect(model, textureOverride, worldPos); } - void World::explodeSpell(const osg::Vec3f &origin, const ESM::EffectList &effects, const Ptr &caster, ESM::RangeType rangeType, - const std::string& id, const std::string& sourceName) + void World::explodeSpell(const osg::Vec3f &origin, const ESM::EffectList &effects, const Ptr &caster, const Ptr& ignore, + ESM::RangeType rangeType, const std::string& id, const std::string& sourceName) { std::map > toApply; for (std::vector::const_iterator effectIt = effects.mList.begin(); @@ -3121,6 +3121,9 @@ namespace MWWorld if (apply->first == caster) continue; + if (apply->first == ignore) + continue; + if (source.isEmpty()) source = apply->first; diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 5f0507ace..6eed4e484 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -623,8 +623,8 @@ namespace MWWorld virtual void spawnEffect (const std::string& model, const std::string& textureOverride, const osg::Vec3f& worldPos); - virtual void explodeSpell (const osg::Vec3f& origin, const ESM::EffectList& effects, - const MWWorld::Ptr& caster, ESM::RangeType rangeType, const std::string& id, const std::string& sourceName); + virtual void explodeSpell (const osg::Vec3f& origin, const ESM::EffectList& effects, const MWWorld::Ptr& caster, + const MWWorld::Ptr& ignore, ESM::RangeType rangeType, const std::string& id, const std::string& sourceName); virtual void activate (const MWWorld::Ptr& object, const MWWorld::Ptr& actor); From ef1a1125e028573931604f5b459ec0f07d31ed28 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 12 Jan 2016 17:10:23 +0100 Subject: [PATCH 2986/3725] Fix an error in restocking logic (Fixes #3131) --- apps/openmw/mwworld/containerstore.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index ab9fa4611..45390405e 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -529,10 +529,10 @@ void MWWorld::ContainerStore::restock (const ESM::InventoryList& items, const MW { std::map::iterator listInMap = allowedForReplace.find(itemOrList); - int restockNum = it->mCount; + int restockNum = std::abs(it->mCount); //If we know we must restock less, take it into account if(listInMap != allowedForReplace.end()) - restockNum += listInMap->second;//We add, because list items have negative count + restockNum -= std::min(restockNum, listInMap->second); //restock addInitialItem(itemOrList, owner, restockNum, true); } From 471ad3fb0f0f4b332057e3fa7ee277dc780abcc2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 12 Jan 2016 17:10:23 +0100 Subject: [PATCH 2987/3725] Fix an error in restocking logic (Fixes #3131) --- apps/openmw/mwworld/containerstore.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index ab9fa4611..45390405e 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -529,10 +529,10 @@ void MWWorld::ContainerStore::restock (const ESM::InventoryList& items, const MW { std::map::iterator listInMap = allowedForReplace.find(itemOrList); - int restockNum = it->mCount; + int restockNum = std::abs(it->mCount); //If we know we must restock less, take it into account if(listInMap != allowedForReplace.end()) - restockNum += listInMap->second;//We add, because list items have negative count + restockNum -= std::min(restockNum, listInMap->second); //restock addInitialItem(itemOrList, owner, restockNum, true); } From 2ce2e8a1e7883fced661bd37bbbdba68ce389edd Mon Sep 17 00:00:00 2001 From: Jordan Ayers Date: Mon, 11 Jan 2016 07:24:52 -0600 Subject: [PATCH 2988/3725] Add missing OOB slot check to InventoryStore. --- apps/openmw/mwworld/inventorystore.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index b82b798d1..dbd2c6794 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -523,6 +523,9 @@ int MWWorld::InventoryStore::remove(const Ptr& item, int count, const Ptr& actor MWWorld::ContainerStoreIterator MWWorld::InventoryStore::unequipSlot(int slot, const MWWorld::Ptr& actor) { + if (slot<0 || slot>=static_cast (mSlots.size())) + throw std::runtime_error ("slot number out of range"); + ContainerStoreIterator it = mSlots[slot]; if (it != end()) From 6eba647a9d4b88925997aba9f2495f367857a519 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 14 Jan 2016 13:19:37 +0100 Subject: [PATCH 2989/3725] added accessor function for cell selection in paged worldspace --- apps/opencs/view/render/pagedworldspacewidget.cpp | 5 +++++ apps/opencs/view/render/pagedworldspacewidget.hpp | 2 ++ 2 files changed, 7 insertions(+) diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index e30f238a2..414076cea 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -432,6 +432,11 @@ void CSVRender::PagedWorldspaceWidget::setCellSelection (const CSMWorld::CellSel emit cellSelectionChanged (mSelection); } +const CSMWorld::CellSelection& CSVRender::PagedWorldspaceWidget::getCellSelection() const +{ + return mSelection; +} + std::pair< int, int > CSVRender::PagedWorldspaceWidget::getCoordinatesFromId (const std::string& record) const { std::istringstream stream (record.c_str()); diff --git a/apps/opencs/view/render/pagedworldspacewidget.hpp b/apps/opencs/view/render/pagedworldspacewidget.hpp index bc8e0da64..647341d1f 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.hpp +++ b/apps/opencs/view/render/pagedworldspacewidget.hpp @@ -80,6 +80,8 @@ namespace CSVRender void setCellSelection(const CSMWorld::CellSelection& selection); + const CSMWorld::CellSelection& getCellSelection() const; + /// \return Drop handled? virtual bool handleDrop (const std::vector& data, DropType type); From 55627c08532356e348e115af58da90f9bb55af7d Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 14 Jan 2016 13:20:01 +0100 Subject: [PATCH 2990/3725] handling drops into cells that do not exist or are not shown --- apps/opencs/model/prefs/state.cpp | 13 ++++ apps/opencs/view/render/instancemode.cpp | 84 ++++++++++++++++++++---- 2 files changed, 85 insertions(+), 12 deletions(-) diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index d2ad0f6ef..859fabd11 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -191,10 +191,23 @@ void CSMPrefs::State::declare() declareInt ("scene-delay", "Tooltip delay in milliseconds", 500). setMin (1); + EnumValue createAndInsert ("Create cell and insert"); + EnumValue showAndInsert ("Show cell and insert"); + EnumValue dontInsert ("Discard"); + EnumValue insertAnyway ("Insert anyway"); + EnumValues insertOutsideCell; + insertOutsideCell.add (createAndInsert).add (dontInsert).add (insertAnyway); + EnumValues insertOutsideVisibleCell; + insertOutsideVisibleCell.add (showAndInsert).add (dontInsert).add (insertAnyway); + declareCategory ("Scene Drops"); declareInt ("distance", "Drop Distance", 50). setTooltip ("If an instance drop can not be placed against another object at the " "insert point, it will be placed by this distance from the insert point instead"); + declareEnum ("outside-drop", "Handling drops outside of cells", createAndInsert). + addValues (insertOutsideCell); + declareEnum ("outside-visible-drop", "Handling drops outside of visible cells", showAndInsert). + addValues (insertOutsideVisibleCell); } void CSMPrefs::State::declareCategory (const std::string& key) diff --git a/apps/opencs/view/render/instancemode.cpp b/apps/opencs/view/render/instancemode.cpp index 6c3593369..b6430036b 100644 --- a/apps/opencs/view/render/instancemode.cpp +++ b/apps/opencs/view/render/instancemode.cpp @@ -6,11 +6,13 @@ #include "../../model/prefs/state.hpp" #include "../../model/world/idtable.hpp" +#include "../../model/world/idtree.hpp" #include "../../model/world/commands.hpp" #include "elements.hpp" #include "object.hpp" #include "worldspacewidget.hpp" +#include "pagedworldspacewidget.hpp" CSVRender::InstanceMode::InstanceMode (WorldspaceWidget *worldspaceWidget, QWidget *parent) : EditMode (worldspaceWidget, QIcon (":placeholder"), Element_Reference, "Instance editing", @@ -68,7 +70,6 @@ void CSVRender::InstanceMode::dragEnterEvent (QDragEnterEvent *event) if (!mime->fromDocument (getWorldspaceWidget().getDocument())) return; - /// \todo document check if (mime->holdsType (CSMWorld::UniversalId::Type_Referenceable)) event->accept(); } @@ -87,15 +88,68 @@ void CSVRender::InstanceMode::dropEvent (QDropEvent* event) std::string cellId = getWorldspaceWidget().getCellId (insertPoint); - bool dropped = false; + CSMWorld::IdTree& cellTable = dynamic_cast ( + *document.getData().getTableModel (CSMWorld::UniversalId::Type_Cells)); - std::vector ids = mime->getData(); + bool noCell = document.getData().getCells().searchId (cellId)==-1; + + if (noCell) + { + std::string mode = CSMPrefs::get()["Scene Drops"]["outside-drop"].toString(); + + // target cell does not exist + if (mode=="Discard") + return; + + if (mode=="Create cell and insert") + { + std::auto_ptr createCommand ( + new CSMWorld::CreateCommand (cellTable, cellId)); + + int parentIndex = cellTable.findColumnIndex (CSMWorld::Columns::ColumnId_Cell); + int index = cellTable.findNestedColumnIndex (parentIndex, CSMWorld::Columns::ColumnId_Interior); + createCommand->addNestedValue (parentIndex, index, false); + + document.getUndoStack().push (createCommand.release()); + + if (CSVRender::PagedWorldspaceWidget *paged = + dynamic_cast (&getWorldspaceWidget())) + { + CSMWorld::CellSelection selection = paged->getCellSelection(); + selection.add (CSMWorld::CellCoordinates::fromId (cellId).first); + paged->setCellSelection (selection); + } + + noCell = false; + } + } + else if (CSVRender::PagedWorldspaceWidget *paged = + dynamic_cast (&getWorldspaceWidget())) + { + CSMWorld::CellSelection selection = paged->getCellSelection(); + if (!selection.has (CSMWorld::CellCoordinates::fromId (cellId).first)) + { + // target cell exists, but is not shown + std::string mode = + CSMPrefs::get()["Scene Drops"]["outside-visible-drop"].toString(); + + if (mode=="Discard") + return; + + if (mode=="Show cell and insert") + { + selection.add (CSMWorld::CellCoordinates::fromId (cellId).first); + paged->setCellSelection (selection); + } + } + } CSMWorld::IdTable& referencesTable = dynamic_cast ( *document.getData().getTableModel (CSMWorld::UniversalId::Type_References)); - CSMWorld::IdTable& cellTable = dynamic_cast ( - *document.getData().getTableModel (CSMWorld::UniversalId::Type_Cells)); + bool dropped = false; + + std::vector ids = mime->getData(); for (std::vector::const_iterator iter (ids.begin()); iter!=ids.end(); ++iter) @@ -118,18 +172,24 @@ void CSVRender::InstanceMode::dropEvent (QDropEvent* event) CSMWorld::Columns::ColumnId_ReferenceableId), QString::fromUtf8 (iter->getId().c_str())); - // increase reference count in cell - QModelIndex countIndex = cellTable.getModelIndex (cellId, - cellTable.findColumnIndex (CSMWorld::Columns::ColumnId_RefNumCounter)); + std::auto_ptr incrementCommand; + + if (!noCell) + { + // increase reference count in cell + QModelIndex countIndex = cellTable.getModelIndex (cellId, + cellTable.findColumnIndex (CSMWorld::Columns::ColumnId_RefNumCounter)); - int count = cellTable.data (countIndex).toInt(); + int count = cellTable.data (countIndex).toInt(); - std::auto_ptr incrementCommand ( - new CSMWorld::ModifyCommand (cellTable, countIndex, count+1)); + incrementCommand.reset ( + new CSMWorld::ModifyCommand (cellTable, countIndex, count+1)); + } document.getUndoStack().beginMacro (createCommand->text()); document.getUndoStack().push (createCommand.release()); - document.getUndoStack().push (incrementCommand.release()); + if (incrementCommand.get()) + document.getUndoStack().push (incrementCommand.release()); document.getUndoStack().endMacro(); dropped = true; From 62fe47b144d8312f90b5d773c31712d876f76779 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 13 Jan 2016 15:37:43 +0100 Subject: [PATCH 2991/3725] Load default terrain if there is none defined --- components/esmterrain/storage.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/components/esmterrain/storage.cpp b/components/esmterrain/storage.cpp index f0865a0a9..4be56d5e6 100644 --- a/components/esmterrain/storage.cpp +++ b/components/esmterrain/storage.cpp @@ -14,6 +14,8 @@ namespace ESMTerrain { + const float defaultHeight = -2048; + Storage::Storage(const VFS::Manager *vfs) : mVFS(vfs) { @@ -62,7 +64,9 @@ namespace ESMTerrain return true; } - return false; + min = defaultHeight; + max = defaultHeight; + return true; } void Storage::fixNormal (osg::Vec3f& normal, int cellX, int cellY, int col, int row) @@ -203,7 +207,7 @@ namespace ESMTerrain assert (vertX < numVerts); assert (vertY < numVerts); - float height = -2048; + float height = defaultHeight; if (heightData) height = heightData->mHeights[col*ESM::Land::LAND_SIZE + row]; @@ -412,7 +416,7 @@ namespace ESMTerrain const ESM::Land* land = getLand(cellX, cellY); if (!land || !(land->mDataTypes&ESM::Land::DATA_VHGT)) - return -2048; + return defaultHeight; // Mostly lifted from Ogre::Terrain::getHeightAtTerrainPosition From 091ca9743e97f16368c028d15ab00ec113e50b64 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 14 Jan 2016 16:41:29 +0100 Subject: [PATCH 2992/3725] Do not write LandData twice (Fixes #3140) --- apps/opencs/model/doc/savingstages.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/apps/opencs/model/doc/savingstages.cpp b/apps/opencs/model/doc/savingstages.cpp index db38c4779..af9c380a3 100644 --- a/apps/opencs/model/doc/savingstages.cpp +++ b/apps/opencs/model/doc/savingstages.cpp @@ -394,10 +394,6 @@ void CSMDoc::WriteLandCollectionStage::perform (int stage, Messages& messages) CSMWorld::Land record = land.get(); writer.startRecord (record.sRecordId); record.save (writer, land.mState == CSMWorld::RecordBase::State_Deleted); - - if (const ESM::Land::LandData *data = record.getLandData (record.mDataTypes)) - data->save (mState.getWriter()); - writer.endRecord (record.sRecordId); } } From 0b84b3c2cf3253b0cf6c514485fd4601677859a4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 14 Jan 2016 17:41:39 +0100 Subject: [PATCH 2993/3725] Don't crash when region weather chances don't add to 100 The invalid weather ID was resulting in out-of-bounds vector access later in the code. --- apps/openmw/mwworld/weather.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 5ce3d5c2f..321637194 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -321,10 +321,14 @@ void RegionWeather::chooseNewWeather() { sum += mChances[i]; if(chance <= sum) - break; + { + mWeather = i; + return; + } } - mWeather = i; + // if we hit this path then the chances don't add to 100, choose a default weather instead + mWeather = 0; } MoonModel::MoonModel(const std::string& name, const MWWorld::Fallback& fallback) From 4f2a031f4e66e50946ada6b20ada8f03d981fc6c Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 14 Jan 2016 18:34:47 +0100 Subject: [PATCH 2994/3725] Improve error message --- apps/openmw/mwworld/containerstore.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 45390405e..d8c37061f 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -627,7 +627,7 @@ int MWWorld::ContainerStore::getType (const ConstPtr& ptr) return Type_Weapon; throw std::runtime_error ( - "Object of type " + ptr.getTypeName() + " can not be placed into a container"); + "Object '" + ptr.getCellRef().getRefId() + "' of type " + ptr.getTypeName() + " can not be placed into a container"); } MWWorld::Ptr MWWorld::ContainerStore::search (const std::string& id) From c1901069be63ecd09b6c5d34d3e56807c3c05bb2 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 15 Jan 2016 12:07:25 +0100 Subject: [PATCH 2995/3725] added instance mode sub-modes --- apps/opencs/view/render/instancemode.cpp | 43 +++++++++++++++++++++++- apps/opencs/view/render/instancemode.hpp | 10 ++++++ apps/opencs/view/world/scenesubview.cpp | 2 +- 3 files changed, 53 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/render/instancemode.cpp b/apps/opencs/view/render/instancemode.cpp index b6430036b..449d9d7a6 100644 --- a/apps/opencs/view/render/instancemode.cpp +++ b/apps/opencs/view/render/instancemode.cpp @@ -9,6 +9,9 @@ #include "../../model/world/idtree.hpp" #include "../../model/world/commands.hpp" +#include "../widget/scenetoolbar.hpp" +#include "../widget/scenetoolmode.hpp" + #include "elements.hpp" #include "object.hpp" #include "worldspacewidget.hpp" @@ -16,9 +19,47 @@ CSVRender::InstanceMode::InstanceMode (WorldspaceWidget *worldspaceWidget, QWidget *parent) : EditMode (worldspaceWidget, QIcon (":placeholder"), Element_Reference, "Instance editing", - parent) + parent), mSubMode (0) +{ +} + +void CSVRender::InstanceMode::activate (CSVWidget::SceneToolbar *toolbar) +{ + if (!mSubMode) + { + mSubMode = new CSVWidget::SceneToolMode (toolbar, "Edit Sub-Mode"); + mSubMode->addButton (":placeholder", "move", + "Move selected instances" + "
    • Use primary edit to move instances around freely
    • " + "
    • Use secondary edit to move instances around within the grid
    • " + "
    " + "Not implemented yet"); + mSubMode->addButton (":placeholder", "rotate", + "Rotate selected instances" + "
    • Use primary edit to rotate instances freely
    • " + "
    • Use secondary edit to rotate instances within the grid
    • " + "
    " + "Not implemented yet"); + mSubMode->addButton (":placeholder", "scale", + "Scale selected instances" + "
    • Use primary edit to scale instances freely
    • " + "
    • Use secondary edit to scale instances along the grid
    • " + "
    " + "Not implemented yet"); + } + + EditMode::activate (toolbar); + + toolbar->addTool (mSubMode); +} + +void CSVRender::InstanceMode::deactivate (CSVWidget::SceneToolbar *toolbar) { + toolbar->removeTool (mSubMode); + delete mSubMode; + mSubMode = 0; + EditMode::deactivate (toolbar); } void CSVRender::InstanceMode::primaryEditPressed (osg::ref_ptr tag) diff --git a/apps/opencs/view/render/instancemode.hpp b/apps/opencs/view/render/instancemode.hpp index 7649c241c..1eec62874 100644 --- a/apps/opencs/view/render/instancemode.hpp +++ b/apps/opencs/view/render/instancemode.hpp @@ -3,16 +3,26 @@ #include "editmode.hpp" +namespace CSVWidget +{ + class SceneToolMode; +} + namespace CSVRender { class InstanceMode : public EditMode { Q_OBJECT + CSVWidget::SceneToolMode *mSubMode; public: InstanceMode (WorldspaceWidget *worldspaceWidget, QWidget *parent = 0); + virtual void activate (CSVWidget::SceneToolbar *toolbar); + + virtual void deactivate (CSVWidget::SceneToolbar *toolbar); + virtual void primaryEditPressed (osg::ref_ptr tag); virtual void secondaryEditPressed (osg::ref_ptr tag); diff --git a/apps/opencs/view/world/scenesubview.cpp b/apps/opencs/view/world/scenesubview.cpp index 44fe94d84..7014b1486 100644 --- a/apps/opencs/view/world/scenesubview.cpp +++ b/apps/opencs/view/world/scenesubview.cpp @@ -122,7 +122,7 @@ CSVWidget::SceneToolbar* CSVWorld::SceneSubView::makeToolbar (CSVRender::Worldsp CSVWidget::SceneToolRun *runTool = widget->makeRunTool (toolbar); toolbar->addTool (runTool); - toolbar->addTool (widget->makeEditModeSelector (toolbar)); + toolbar->addTool (widget->makeEditModeSelector (toolbar), runTool); return toolbar; } From 18320b2cd03052dc70d8d710a91d8dd1e8bd2080 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 15 Jan 2016 15:49:10 +0100 Subject: [PATCH 2996/3725] Move the Button enum to WorldSpaceWidget --- apps/opencs/view/render/pagedworldspacewidget.cpp | 4 ++-- .../opencs/view/render/unpagedworldspacewidget.cpp | 4 ++-- apps/opencs/view/render/worldspacewidget.cpp | 6 +++--- apps/opencs/view/render/worldspacewidget.hpp | 11 +++++++++++ apps/opencs/view/widget/scenetooltoggle2.cpp | 4 ++-- apps/opencs/view/widget/scenetooltoggle2.hpp | 14 +++----------- 6 files changed, 23 insertions(+), 20 deletions(-) diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index c6e422bd1..1880beab8 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -126,8 +126,8 @@ void CSVRender::PagedWorldspaceWidget::addVisibilitySelectorButtons ( CSVWidget::SceneToolToggle2 *tool) { WorldspaceWidget::addVisibilitySelectorButtons (tool); - tool->addButton (CSVWidget::SceneToolToggle2::Button_Terrain, Mask_Terrain, "Terrain"); - tool->addButton (CSVWidget::SceneToolToggle2::Button_Fog, Mask_Fog, "Fog", "", true); + tool->addButton (Button_Terrain, Mask_Terrain, "Terrain"); + tool->addButton (Button_Fog, Mask_Fog, "Fog", "", true); } void CSVRender::PagedWorldspaceWidget::addEditModeSelectorButtons ( diff --git a/apps/opencs/view/render/unpagedworldspacewidget.cpp b/apps/opencs/view/render/unpagedworldspacewidget.cpp index e203a250b..dad37c946 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.cpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.cpp @@ -171,8 +171,8 @@ void CSVRender::UnpagedWorldspaceWidget::addVisibilitySelectorButtons ( CSVWidget::SceneToolToggle2 *tool) { WorldspaceWidget::addVisibilitySelectorButtons (tool); - tool->addButton (CSVWidget::SceneToolToggle2::Button_Terrain, Mask_Terrain, "Terrain", "", true); - tool->addButton (CSVWidget::SceneToolToggle2::Button_Fog, Mask_Fog, "Fog"); + tool->addButton (Button_Terrain, Mask_Terrain, "Terrain", "", true); + tool->addButton (Button_Fog, Mask_Fog, "Fog"); } std::string CSVRender::UnpagedWorldspaceWidget::getStartupInstruction() diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 800fd3d6e..184477d6b 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -296,9 +296,9 @@ void CSVRender::WorldspaceWidget::setEditLock (bool locked) void CSVRender::WorldspaceWidget::addVisibilitySelectorButtons ( CSVWidget::SceneToolToggle2 *tool) { - tool->addButton (CSVWidget::SceneToolToggle2::Button_Reference, Mask_Reference, "Instances"); - tool->addButton (CSVWidget::SceneToolToggle2::Button_Water, Mask_Water, "Water"); - tool->addButton (CSVWidget::SceneToolToggle2::Button_Pathgrid, Mask_Pathgrid, "Pathgrid"); + tool->addButton (Button_Reference, Mask_Reference, "Instances"); + tool->addButton (Button_Water, Mask_Water, "Water"); + tool->addButton (Button_Pathgrid, Mask_Pathgrid, "Pathgrid"); } void CSVRender::WorldspaceWidget::addEditModeSelectorButtons (CSVWidget::SceneToolMode *tool) diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp index 142ed04ca..7a77edad4 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -142,6 +142,17 @@ namespace CSVRender protected: + /// Visual elements in a scene + /// @note do not change the enumeration values, they are used in pre-existing button file names! + enum ButtonId + { + Button_Reference = 0x1, + Button_Pathgrid = 0x2, + Button_Water = 0x4, + Button_Fog = 0x8, + Button_Terrain = 0x10 + }; + virtual void addVisibilitySelectorButtons (CSVWidget::SceneToolToggle2 *tool); virtual void addEditModeSelectorButtons (CSVWidget::SceneToolMode *tool); diff --git a/apps/opencs/view/widget/scenetooltoggle2.cpp b/apps/opencs/view/widget/scenetooltoggle2.cpp index 3972aadaa..720da6a96 100644 --- a/apps/opencs/view/widget/scenetooltoggle2.cpp +++ b/apps/opencs/view/widget/scenetooltoggle2.cpp @@ -77,11 +77,11 @@ void CSVWidget::SceneToolToggle2::showPanel (const QPoint& position) mFirst->setFocus (Qt::OtherFocusReason); } -void CSVWidget::SceneToolToggle2::addButton (ButtonId id, unsigned int mask, +void CSVWidget::SceneToolToggle2::addButton (unsigned int id, unsigned int mask, const QString& name, const QString& tooltip, bool disabled) { std::ostringstream stream; - stream << mSingleIcon << static_cast(id); + stream << mSingleIcon << id; PushButton *button = new PushButton (QIcon (QPixmap (stream.str().c_str())), PushButton::Type_Toggle, tooltip.isEmpty() ? name: tooltip, mPanel); diff --git a/apps/opencs/view/widget/scenetooltoggle2.hpp b/apps/opencs/view/widget/scenetooltoggle2.hpp index eea9c3ebc..50337ac11 100644 --- a/apps/opencs/view/widget/scenetooltoggle2.hpp +++ b/apps/opencs/view/widget/scenetooltoggle2.hpp @@ -54,19 +54,11 @@ namespace CSVWidget virtual void showPanel (const QPoint& position); - /// Visual elements in a scene - /// @note do not change the enumeration values, they are used in pre-existing button file names! - enum ButtonId - { - Button_Reference = 0x1, - Button_Pathgrid = 0x2, - Button_Water = 0x4, - Button_Fog = 0x8, - Button_Terrain = 0x10 - }; + /// \param buttonId used to compose the icon filename + /// \param mask used for the reported getSelectionMask() / setSelectionMask() /// \attention After the last button has been added, setSelection must be called at /// least once to finalise the layout. - void addButton (ButtonId buttonId, unsigned int mask, + void addButton (unsigned int buttonId, unsigned int mask, const QString& name, const QString& tooltip = "", bool disabled = false); unsigned int getSelectionMask() const; From fbf07133ead40924b7ed57191505627fb632279c Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 15 Jan 2016 16:31:24 +0100 Subject: [PATCH 2997/3725] Document usage of node masks --- apps/opencs/view/render/mask.hpp | 5 ++++- apps/openmw/mwrender/vismask.hpp | 16 ++++++++++++++-- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/apps/opencs/view/render/mask.hpp b/apps/opencs/view/render/mask.hpp index d2dfef7b4..55b7c823f 100644 --- a/apps/opencs/view/render/mask.hpp +++ b/apps/opencs/view/render/mask.hpp @@ -4,7 +4,10 @@ namespace CSVRender { - /// @note Enumeration values can be changed freely, as long as they do not collide. + /// Node masks used on the OSG scene graph in OpenMW-CS. + /// @note See the respective file in OpenMW (apps/openmw/mwrender/vismask.hpp) + /// for general usage hints about node masks. + /// @copydoc MWRender::VisMask enum Mask { // internal use within NifLoader, do not change diff --git a/apps/openmw/mwrender/vismask.hpp b/apps/openmw/mwrender/vismask.hpp index dd6e85e2c..81bb2f344 100644 --- a/apps/openmw/mwrender/vismask.hpp +++ b/apps/openmw/mwrender/vismask.hpp @@ -5,6 +5,20 @@ namespace MWRender { /// Node masks used for controlling visibility of game objects. + /// @par Any node in the OSG scene graph can have a node mask. When traversing the scene graph, + /// the node visitor's traversal mask is OR'ed with the node mask. If the result of this test is + /// 0, then the node and all its child nodes are not processed. + /// @par Important traversal masks are the camera's cull mask (determines what is visible), + /// the update visitor mask (what is updated) and the intersection visitor mask (what is + /// selectable through mouse clicks or other intersection tests). + /// @par In practice, it can be useful to make a "hierarchy" out of the node masks - e.g. in OpenMW, + /// all 3D rendering nodes are child of a Scene Root node with Mask_Scene. When we do not want 3D rendering, + /// we can just omit Mask_Scene from the traversal mask, and do not need to omit all the individual + /// element masks (water, sky, terrain, etc.) since the traversal will already have stopped at the Scene root node. + /// @par The comments within the VisMask enum should give some hints as to what masks are commonly "child" of + /// another mask, or what type of node this mask is usually set on. + /// @note The mask values are not serialized within models, nor used in any other way that would break backwards + /// compatibility if the enumeration values were to be changed. Feel free to change them when it makes sense. enum VisMask { Mask_UpdateVisitor = 0x1, // reserved for separating UpdateVisitors from CullVisitors @@ -24,8 +38,6 @@ namespace MWRender Mask_Sun = (1<<10), Mask_WeatherParticles = (1<<11), - // child of Water - // top level masks Mask_Scene = (1<<12), Mask_GUI = (1<<13), From 87beb7397070d65c3bf37d6b864f2bb904df69f5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 15 Jan 2016 16:34:57 +0100 Subject: [PATCH 2998/3725] Correction --- apps/openmw/mwrender/vismask.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/vismask.hpp b/apps/openmw/mwrender/vismask.hpp index 81bb2f344..ce13758e3 100644 --- a/apps/openmw/mwrender/vismask.hpp +++ b/apps/openmw/mwrender/vismask.hpp @@ -6,7 +6,7 @@ namespace MWRender /// Node masks used for controlling visibility of game objects. /// @par Any node in the OSG scene graph can have a node mask. When traversing the scene graph, - /// the node visitor's traversal mask is OR'ed with the node mask. If the result of this test is + /// the node visitor's traversal mask is bitwise AND'ed with the node mask. If the result of this test is /// 0, then the node and all its child nodes are not processed. /// @par Important traversal masks are the camera's cull mask (determines what is visible), /// the update visitor mask (what is updated) and the intersection visitor mask (what is From a5411c1ec2551c4789a9ac17c84d147b3bea8d41 Mon Sep 17 00:00:00 2001 From: Rob Cutmore Date: Fri, 15 Jan 2016 20:51:39 -0500 Subject: [PATCH 2999/3725] Remove unused code --- apps/launcher/main.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/apps/launcher/main.cpp b/apps/launcher/main.cpp index 282b3fb89..eadec64d0 100644 --- a/apps/launcher/main.cpp +++ b/apps/launcher/main.cpp @@ -51,10 +51,6 @@ int main(int argc, char *argv[]) if (result == Launcher::FirstRunDialogResultFailure) return 0; - // if (!mainWin.setup()) { - // return 0; - // } - if (result == Launcher::FirstRunDialogResultContinue) mainWin.show(); From e30a38a4c1cd13c1312112a44800d2222f99d367 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 16 Jan 2016 10:55:05 +0100 Subject: [PATCH 3000/3725] updated credits file --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index d4927ea92..ce2728010 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -96,6 +96,7 @@ Programmers Pieter van der Kloet (pvdk) pkubik Radu-Marius Popovici (rpopovici) + rcutmore rdimesio riothamus Robert MacGregor (Ragora) From 21d13a48faeb91a42634a288e66fd25e82ea00aa Mon Sep 17 00:00:00 2001 From: Rob Cutmore Date: Sat, 16 Jan 2016 06:43:45 -0500 Subject: [PATCH 3001/3725] Make setup method of MainDialog class private --- apps/launcher/maindialog.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/launcher/maindialog.hpp b/apps/launcher/maindialog.hpp index 0dfea4865..96b5c0b97 100644 --- a/apps/launcher/maindialog.hpp +++ b/apps/launcher/maindialog.hpp @@ -50,7 +50,6 @@ namespace Launcher explicit MainDialog(QWidget *parent = 0); ~MainDialog(); - bool setup(); FirstRunDialogResult showFirstRunDialog(); bool reloadSettings(); @@ -65,6 +64,8 @@ namespace Launcher void wizardFinished(int exitCode, QProcess::ExitStatus exitStatus); private: + bool setup(); + void createIcons(); void createPages(); From 97bcdf7904e2146ff0167710c7ebd658a2f5696b Mon Sep 17 00:00:00 2001 From: "Hristos N. Triantafillou" Date: Sat, 16 Jan 2016 15:57:03 -0600 Subject: [PATCH 3002/3725] Properly find MyGUI in /usr/local/lib --- cmake/FindMyGUI.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/FindMyGUI.cmake b/cmake/FindMyGUI.cmake index 61a39e4d3..85a1055f6 100644 --- a/cmake/FindMyGUI.cmake +++ b/cmake/FindMyGUI.cmake @@ -101,7 +101,7 @@ ELSE (WIN32) #Unix SET(MYGUI_LIBRARIES ${MYGUI_LIBRARIES} CACHE STRING "") ELSE (MYGUI_INCLUDE_DIRS) FIND_PATH(MYGUI_INCLUDE_DIRS MyGUI.h PATHS /usr/local/include /usr/include PATH_SUFFIXES MyGUI MYGUI) - FIND_LIBRARY(MYGUI_LIBRARIES mygui PATHS /usr/lib /usr/local/lib) + FIND_LIBRARY(MYGUI_LIBRARIES MyGUIEngine PATHS /usr/local/lib /usr/lib) SET(MYGUI_LIB_DIR ${MYGUI_LIBRARIES}) STRING(REGEX REPLACE "(.*)/.*" "\\1" MYGUI_LIB_DIR "${MYGUI_LIB_DIR}") STRING(REGEX REPLACE ".*/" "" MYGUI_LIBRARIES "${MYGUI_LIBRARIES}") From 259d51058a7cad81e4a121a14765e23290e91289 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 17 Jan 2016 00:09:58 +0100 Subject: [PATCH 3003/3725] Update AUTHORS.md --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index ce2728010..bfbd14a5b 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -48,6 +48,7 @@ Programmers Gašper Sedej gugus/gus Hallfaer Tuilinn + hristoast Internecine Jacob Essex (Yacoby) Jannik Heller (scrawl) From 08b469c0d004cb87c9a5f90e32ca098a7e43f635 Mon Sep 17 00:00:00 2001 From: Rob Cutmore Date: Sun, 17 Jan 2016 14:18:49 -0500 Subject: [PATCH 3004/3725] Remove unused forward declarations in filedialog.hpp --- apps/opencs/view/doc/filedialog.hpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/apps/opencs/view/doc/filedialog.hpp b/apps/opencs/view/doc/filedialog.hpp index 648836565..ca6145b9c 100644 --- a/apps/opencs/view/doc/filedialog.hpp +++ b/apps/opencs/view/doc/filedialog.hpp @@ -14,9 +14,6 @@ Q_DECLARE_METATYPE (boost::filesystem::path) #include "ui_filedialog.h" -class DataFilesModel; -class PluginsProxyModel; - namespace ContentSelectorView { class ContentSelector; From 1d86f705baab74a592c4711689cc307a41e2518c Mon Sep 17 00:00:00 2001 From: Aesylwinn Date: Sun, 17 Jan 2016 21:55:03 -0500 Subject: [PATCH 3005/3725] gmst verifier --- apps/opencs/CMakeLists.txt | 4 +- apps/opencs/model/doc/document.cpp | 2008 +------------------ apps/opencs/model/tools/gmstcheck.cpp | 91 + apps/opencs/model/tools/gmstcheck.hpp | 32 + apps/opencs/model/tools/tools.cpp | 3 + apps/opencs/model/world/defaultgmsts.cpp | 2336 ++++++++++++++++++++++ apps/opencs/model/world/defaultgmsts.hpp | 34 + 7 files changed, 2514 insertions(+), 1994 deletions(-) create mode 100644 apps/opencs/model/tools/gmstcheck.cpp create mode 100644 apps/opencs/model/tools/gmstcheck.hpp create mode 100644 apps/opencs/model/world/defaultgmsts.cpp create mode 100644 apps/opencs/model/world/defaultgmsts.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 8bb624704..0d621c83e 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -26,7 +26,7 @@ opencs_units_noqt (model/world universalid record commands columnbase columnimp scriptcontext cell refidcollection refidadapter refiddata refidadapterimp ref collectionbase refcollection columns infocollection tablemimedata cellcoordinates cellselection resources resourcesmanager scope pathgrid landtexture land nestedtablewrapper nestedcollection nestedcoladapterimp nestedinfocollection - idcompletionmanager metadata + idcompletionmanager metadata defaultgmsts ) opencs_hdrs_noqt (model/world @@ -42,7 +42,7 @@ opencs_units_noqt (model/tools mandatoryid skillcheck classcheck factioncheck racecheck soundcheck regioncheck birthsigncheck spellcheck referencecheck referenceablecheck scriptcheck bodypartcheck startscriptcheck search searchoperation searchstage pathgridcheck soundgencheck magiceffectcheck - mergestages + mergestages gmstcheck ) opencs_hdrs_noqt (model/tools diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 80c14bd98..ea1fbb330 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -6,1925 +6,36 @@ #include +#include "../world/defaultgmsts.hpp" + #ifndef Q_MOC_RUN #include #endif void CSMDoc::Document::addGmsts() { - static const char *gmstFloats[] = - { - "fAIFleeFleeMult", - "fAIFleeHealthMult", - "fAIMagicSpellMult", - "fAIMeleeArmorMult", - "fAIMeleeSummWeaponMult", - "fAIMeleeWeaponMult", - "fAIRangeMagicSpellMult", - "fAIRangeMeleeWeaponMult", - "fAlarmRadius", - "fAthleticsRunBonus", - "fAudioDefaultMaxDistance", - "fAudioDefaultMinDistance", - "fAudioMaxDistanceMult", - "fAudioMinDistanceMult", - "fAudioVoiceDefaultMaxDistance", - "fAudioVoiceDefaultMinDistance", - "fAutoPCSpellChance", - "fAutoSpellChance", - "fBargainOfferBase", - "fBargainOfferMulti", - "fBarterGoldResetDelay", - "fBaseRunMultiplier", - "fBlockStillBonus", - "fBribe1000Mod", - "fBribe100Mod", - "fBribe10Mod", - "fCombatAngleXY", - "fCombatAngleZ", - "fCombatArmorMinMult", - "fCombatBlockLeftAngle", - "fCombatBlockRightAngle", - "fCombatCriticalStrikeMult", - "fCombatDelayCreature", - "fCombatDelayNPC", - "fCombatDistance", - "fCombatDistanceWerewolfMod", - "fCombatForceSideAngle", - "fCombatInvisoMult", - "fCombatKODamageMult", - "fCombatTorsoSideAngle", - "fCombatTorsoStartPercent", - "fCombatTorsoStopPercent", - "fConstantEffectMult", - "fCorpseClearDelay", - "fCorpseRespawnDelay", - "fCrimeGoldDiscountMult", - "fCrimeGoldTurnInMult", - "fCrimeStealing", - "fDamageStrengthBase", - "fDamageStrengthMult", - "fDifficultyMult", - "fDiseaseXferChance", - "fDispAttacking", - "fDispBargainFailMod", - "fDispBargainSuccessMod", - "fDispCrimeMod", - "fDispDiseaseMod", - "fDispFactionMod", - "fDispFactionRankBase", - "fDispFactionRankMult", - "fDispositionMod", - "fDispPersonalityBase", - "fDispPersonalityMult", - "fDispPickPocketMod", - "fDispRaceMod", - "fDispStealing", - "fDispWeaponDrawn", - "fEffectCostMult", - "fElementalShieldMult", - "fEnchantmentChanceMult", - "fEnchantmentConstantChanceMult", - "fEnchantmentConstantDurationMult", - "fEnchantmentMult", - "fEnchantmentValueMult", - "fEncumberedMoveEffect", - "fEncumbranceStrMult", - "fEndFatigueMult", - "fFallAcroBase", - "fFallAcroMult", - "fFallDamageDistanceMin", - "fFallDistanceBase", - "fFallDistanceMult", - "fFatigueAttackBase", - "fFatigueAttackMult", - "fFatigueBase", - "fFatigueBlockBase", - "fFatigueBlockMult", - "fFatigueJumpBase", - "fFatigueJumpMult", - "fFatigueMult", - "fFatigueReturnBase", - "fFatigueReturnMult", - "fFatigueRunBase", - "fFatigueRunMult", - "fFatigueSneakBase", - "fFatigueSneakMult", - "fFatigueSpellBase", - "fFatigueSpellCostMult", - "fFatigueSpellMult", - "fFatigueSwimRunBase", - "fFatigueSwimRunMult", - "fFatigueSwimWalkBase", - "fFatigueSwimWalkMult", - "fFightDispMult", - "fFightDistanceMultiplier", - "fFightStealing", - "fFleeDistance", - "fGreetDistanceReset", - "fHandtoHandHealthPer", - "fHandToHandReach", - "fHoldBreathEndMult", - "fHoldBreathTime", - "fIdleChanceMultiplier", - "fIngredientMult", - "fInteriorHeadTrackMult", - "fJumpAcrobaticsBase", - "fJumpAcroMultiplier", - "fJumpEncumbranceBase", - "fJumpEncumbranceMultiplier", - "fJumpMoveBase", - "fJumpMoveMult", - "fJumpRunMultiplier", - "fKnockDownMult", - "fLevelMod", - "fLevelUpHealthEndMult", - "fLightMaxMod", - "fLuckMod", - "fMagesGuildTravel", - "fMagicCreatureCastDelay", - "fMagicDetectRefreshRate", - "fMagicItemConstantMult", - "fMagicItemCostMult", - "fMagicItemOnceMult", - "fMagicItemPriceMult", - "fMagicItemRechargePerSecond", - "fMagicItemStrikeMult", - "fMagicItemUsedMult", - "fMagicStartIconBlink", - "fMagicSunBlockedMult", - "fMajorSkillBonus", - "fMaxFlySpeed", - "fMaxHandToHandMult", - "fMaxHeadTrackDistance", - "fMaxWalkSpeed", - "fMaxWalkSpeedCreature", - "fMedMaxMod", - "fMessageTimePerChar", - "fMinFlySpeed", - "fMinHandToHandMult", - "fMinorSkillBonus", - "fMinWalkSpeed", - "fMinWalkSpeedCreature", - "fMiscSkillBonus", - "fNPCbaseMagickaMult", - "fNPCHealthBarFade", - "fNPCHealthBarTime", - "fPCbaseMagickaMult", - "fPerDieRollMult", - "fPersonalityMod", - "fPerTempMult", - "fPickLockMult", - "fPickPocketMod", - "fPotionMinUsefulDuration", - "fPotionStrengthMult", - "fPotionT1DurMult", - "fPotionT1MagMult", - "fPotionT4BaseStrengthMult", - "fPotionT4EquipStrengthMult", - "fProjectileMaxSpeed", - "fProjectileMinSpeed", - "fProjectileThrownStoreChance", - "fRepairAmountMult", - "fRepairMult", - "fReputationMod", - "fRestMagicMult", - "fSeriousWoundMult", - "fSleepRandMod", - "fSleepRestMod", - "fSneakBootMult", - "fSneakDistanceBase", - "fSneakDistanceMultiplier", - "fSneakNoViewMult", - "fSneakSkillMult", - "fSneakSpeedMultiplier", - "fSneakUseDelay", - "fSneakUseDist", - "fSneakViewMult", - "fSoulGemMult", - "fSpecialSkillBonus", - "fSpellMakingValueMult", - "fSpellPriceMult", - "fSpellValueMult", - "fStromWalkMult", - "fStromWindSpeed", - "fSuffocationDamage", - "fSwimHeightScale", - "fSwimRunAthleticsMult", - "fSwimRunBase", - "fSwimWalkAthleticsMult", - "fSwimWalkBase", - "fSwingBlockBase", - "fSwingBlockMult", - "fTargetSpellMaxSpeed", - "fThrownWeaponMaxSpeed", - "fThrownWeaponMinSpeed", - "fTrapCostMult", - "fTravelMult", - "fTravelTimeMult", - "fUnarmoredBase1", - "fUnarmoredBase2", - "fVanityDelay", - "fVoiceIdleOdds", - "fWaterReflectUpdateAlways", - "fWaterReflectUpdateSeldom", - "fWeaponDamageMult", - "fWeaponFatigueBlockMult", - "fWeaponFatigueMult", - "fWereWolfAcrobatics", - "fWereWolfAgility", - "fWereWolfAlchemy", - "fWereWolfAlteration", - "fWereWolfArmorer", - "fWereWolfAthletics", - "fWereWolfAxe", - "fWereWolfBlock", - "fWereWolfBluntWeapon", - "fWereWolfConjuration", - "fWereWolfDestruction", - "fWereWolfEnchant", - "fWereWolfEndurance", - "fWereWolfFatigue", - "fWereWolfHandtoHand", - "fWereWolfHealth", - "fWereWolfHeavyArmor", - "fWereWolfIllusion", - "fWereWolfIntellegence", - "fWereWolfLightArmor", - "fWereWolfLongBlade", - "fWereWolfLuck", - "fWereWolfMagicka", - "fWereWolfMarksman", - "fWereWolfMediumArmor", - "fWereWolfMerchantile", - "fWereWolfMysticism", - "fWereWolfPersonality", - "fWereWolfRestoration", - "fWereWolfRunMult", - "fWereWolfSecurity", - "fWereWolfShortBlade", - "fWereWolfSilverWeaponDamageMult", - "fWereWolfSneak", - "fWereWolfSpear", - "fWereWolfSpeechcraft", - "fWereWolfSpeed", - "fWereWolfStrength", - "fWereWolfUnarmored", - "fWereWolfWillPower", - "fWortChanceValue", - 0 - }; - - static const float gmstFloatsValues[] = - { - 0.3, // fAIFleeFleeMult - 7.0, // fAIFleeHealthMult - 3.0, // fAIMagicSpellMult - 1.0, // fAIMeleeArmorMult - 1.0, // fAIMeleeSummWeaponMult - 2.0, // fAIMeleeWeaponMult - 5.0, // fAIRangeMagicSpellMult - 5.0, // fAIRangeMeleeWeaponMult - 2000.0, // fAlarmRadius - 1.0, // fAthleticsRunBonus - 40.0, // fAudioDefaultMaxDistance - 5.0, // fAudioDefaultMinDistance - 50.0, // fAudioMaxDistanceMult - 20.0, // fAudioMinDistanceMult - 60.0, // fAudioVoiceDefaultMaxDistance - 10.0, // fAudioVoiceDefaultMinDistance - 50.0, // fAutoPCSpellChance - 80.0, // fAutoSpellChance - 50.0, // fBargainOfferBase - -4.0, // fBargainOfferMulti - 24.0, // fBarterGoldResetDelay - 1.75, // fBaseRunMultiplier - 1.25, // fBlockStillBonus - 150.0, // fBribe1000Mod - 75.0, // fBribe100Mod - 35.0, // fBribe10Mod - 60.0, // fCombatAngleXY - 60.0, // fCombatAngleZ - 0.25, // fCombatArmorMinMult - -90.0, // fCombatBlockLeftAngle - 30.0, // fCombatBlockRightAngle - 4.0, // fCombatCriticalStrikeMult - 0.1, // fCombatDelayCreature - 0.1, // fCombatDelayNPC - 128.0, // fCombatDistance - 0.3, // fCombatDistanceWerewolfMod - 30.0, // fCombatForceSideAngle - 0.2, // fCombatInvisoMult - 1.5, // fCombatKODamageMult - 45.0, // fCombatTorsoSideAngle - 0.3, // fCombatTorsoStartPercent - 0.8, // fCombatTorsoStopPercent - 15.0, // fConstantEffectMult - 72.0, // fCorpseClearDelay - 72.0, // fCorpseRespawnDelay - 0.5, // fCrimeGoldDiscountMult - 0.9, // fCrimeGoldTurnInMult - 1.0, // fCrimeStealing - 0.5, // fDamageStrengthBase - 0.1, // fDamageStrengthMult - 5.0, // fDifficultyMult - 2.5, // fDiseaseXferChance - -10.0, // fDispAttacking - -1.0, // fDispBargainFailMod - 1.0, // fDispBargainSuccessMod - 0.0, // fDispCrimeMod - -10.0, // fDispDiseaseMod - 3.0, // fDispFactionMod - 1.0, // fDispFactionRankBase - 0.5, // fDispFactionRankMult - 1.0, // fDispositionMod - 50.0, // fDispPersonalityBase - 0.5, // fDispPersonalityMult - -25.0, // fDispPickPocketMod - 5.0, // fDispRaceMod - -0.5, // fDispStealing - -5.0, // fDispWeaponDrawn - 0.5, // fEffectCostMult - 0.1, // fElementalShieldMult - 3.0, // fEnchantmentChanceMult - 0.5, // fEnchantmentConstantChanceMult - 100.0, // fEnchantmentConstantDurationMult - 0.1, // fEnchantmentMult - 1000.0, // fEnchantmentValueMult - 0.3, // fEncumberedMoveEffect - 5.0, // fEncumbranceStrMult - 0.04, // fEndFatigueMult - 0.25, // fFallAcroBase - 0.01, // fFallAcroMult - 400.0, // fFallDamageDistanceMin - 0.0, // fFallDistanceBase - 0.07, // fFallDistanceMult - 2.0, // fFatigueAttackBase - 0.0, // fFatigueAttackMult - 1.25, // fFatigueBase - 4.0, // fFatigueBlockBase - 0.0, // fFatigueBlockMult - 5.0, // fFatigueJumpBase - 0.0, // fFatigueJumpMult - 0.5, // fFatigueMult - 2.5, // fFatigueReturnBase - 0.02, // fFatigueReturnMult - 5.0, // fFatigueRunBase - 2.0, // fFatigueRunMult - 1.5, // fFatigueSneakBase - 1.5, // fFatigueSneakMult - 0.0, // fFatigueSpellBase - 0.0, // fFatigueSpellCostMult - 0.0, // fFatigueSpellMult - 7.0, // fFatigueSwimRunBase - 0.0, // fFatigueSwimRunMult - 2.5, // fFatigueSwimWalkBase - 0.0, // fFatigueSwimWalkMult - 0.2, // fFightDispMult - 0.005, // fFightDistanceMultiplier - 50.0, // fFightStealing - 3000.0, // fFleeDistance - 512.0, // fGreetDistanceReset - 0.1, // fHandtoHandHealthPer - 1.0, // fHandToHandReach - 0.5, // fHoldBreathEndMult - 20.0, // fHoldBreathTime - 0.75, // fIdleChanceMultiplier - 1.0, // fIngredientMult - 0.5, // fInteriorHeadTrackMult - 128.0, // fJumpAcrobaticsBase - 4.0, // fJumpAcroMultiplier - 0.5, // fJumpEncumbranceBase - 1.0, // fJumpEncumbranceMultiplier - 0.5, // fJumpMoveBase - 0.5, // fJumpMoveMult - 1.0, // fJumpRunMultiplier - 0.5, // fKnockDownMult - 5.0, // fLevelMod - 0.1, // fLevelUpHealthEndMult - 0.6, // fLightMaxMod - 10.0, // fLuckMod - 10.0, // fMagesGuildTravel - 1.5, // fMagicCreatureCastDelay - 0.0167, // fMagicDetectRefreshRate - 1.0, // fMagicItemConstantMult - 1.0, // fMagicItemCostMult - 1.0, // fMagicItemOnceMult - 1.0, // fMagicItemPriceMult - 0.05, // fMagicItemRechargePerSecond - 1.0, // fMagicItemStrikeMult - 1.0, // fMagicItemUsedMult - 3.0, // fMagicStartIconBlink - 0.5, // fMagicSunBlockedMult - 0.75, // fMajorSkillBonus - 300.0, // fMaxFlySpeed - 0.5, // fMaxHandToHandMult - 400.0, // fMaxHeadTrackDistance - 200.0, // fMaxWalkSpeed - 300.0, // fMaxWalkSpeedCreature - 0.9, // fMedMaxMod - 0.1, // fMessageTimePerChar - 5.0, // fMinFlySpeed - 0.1, // fMinHandToHandMult - 1.0, // fMinorSkillBonus - 100.0, // fMinWalkSpeed - 5.0, // fMinWalkSpeedCreature - 1.25, // fMiscSkillBonus - 2.0, // fNPCbaseMagickaMult - 0.5, // fNPCHealthBarFade - 3.0, // fNPCHealthBarTime - 1.0, // fPCbaseMagickaMult - 0.3, // fPerDieRollMult - 5.0, // fPersonalityMod - 1.0, // fPerTempMult - -1.0, // fPickLockMult - 0.3, // fPickPocketMod - 20.0, // fPotionMinUsefulDuration - 0.5, // fPotionStrengthMult - 0.5, // fPotionT1DurMult - 1.5, // fPotionT1MagMult - 20.0, // fPotionT4BaseStrengthMult - 12.0, // fPotionT4EquipStrengthMult - 3000.0, // fProjectileMaxSpeed - 400.0, // fProjectileMinSpeed - 25.0, // fProjectileThrownStoreChance - 3.0, // fRepairAmountMult - 1.0, // fRepairMult - 1.0, // fReputationMod - 0.15, // fRestMagicMult - 0.0, // fSeriousWoundMult - 0.25, // fSleepRandMod - 0.3, // fSleepRestMod - -1.0, // fSneakBootMult - 0.5, // fSneakDistanceBase - 0.002, // fSneakDistanceMultiplier - 0.5, // fSneakNoViewMult - 1.0, // fSneakSkillMult - 0.75, // fSneakSpeedMultiplier - 1.0, // fSneakUseDelay - 500.0, // fSneakUseDist - 1.5, // fSneakViewMult - 3.0, // fSoulGemMult - 0.8, // fSpecialSkillBonus - 7.0, // fSpellMakingValueMult - 2.0, // fSpellPriceMult - 10.0, // fSpellValueMult - 0.25, // fStromWalkMult - 0.7, // fStromWindSpeed - 3.0, // fSuffocationDamage - 0.9, // fSwimHeightScale - 0.1, // fSwimRunAthleticsMult - 0.5, // fSwimRunBase - 0.02, // fSwimWalkAthleticsMult - 0.5, // fSwimWalkBase - 1.0, // fSwingBlockBase - 1.0, // fSwingBlockMult - 1000.0, // fTargetSpellMaxSpeed - 1000.0, // fThrownWeaponMaxSpeed - 300.0, // fThrownWeaponMinSpeed - 0.0, // fTrapCostMult - 4000.0, // fTravelMult - 16000.0,// fTravelTimeMult - 0.1, // fUnarmoredBase1 - 0.065, // fUnarmoredBase2 - 30.0, // fVanityDelay - 10.0, // fVoiceIdleOdds - 0.0, // fWaterReflectUpdateAlways - 10.0, // fWaterReflectUpdateSeldom - 0.1, // fWeaponDamageMult - 1.0, // fWeaponFatigueBlockMult - 0.25, // fWeaponFatigueMult - 150.0, // fWereWolfAcrobatics - 150.0, // fWereWolfAgility - 1.0, // fWereWolfAlchemy - 1.0, // fWereWolfAlteration - 1.0, // fWereWolfArmorer - 150.0, // fWereWolfAthletics - 1.0, // fWereWolfAxe - 1.0, // fWereWolfBlock - 1.0, // fWereWolfBluntWeapon - 1.0, // fWereWolfConjuration - 1.0, // fWereWolfDestruction - 1.0, // fWereWolfEnchant - 150.0, // fWereWolfEndurance - 400.0, // fWereWolfFatigue - 100.0, // fWereWolfHandtoHand - 2.0, // fWereWolfHealth - 1.0, // fWereWolfHeavyArmor - 1.0, // fWereWolfIllusion - 1.0, // fWereWolfIntellegence - 1.0, // fWereWolfLightArmor - 1.0, // fWereWolfLongBlade - 1.0, // fWereWolfLuck - 100.0, // fWereWolfMagicka - 1.0, // fWereWolfMarksman - 1.0, // fWereWolfMediumArmor - 1.0, // fWereWolfMerchantile - 1.0, // fWereWolfMysticism - 1.0, // fWereWolfPersonality - 1.0, // fWereWolfRestoration - 1.5, // fWereWolfRunMult - 1.0, // fWereWolfSecurity - 1.0, // fWereWolfShortBlade - 1.5, // fWereWolfSilverWeaponDamageMult - 1.0, // fWereWolfSneak - 1.0, // fWereWolfSpear - 1.0, // fWereWolfSpeechcraft - 150.0, // fWereWolfSpeed - 150.0, // fWereWolfStrength - 100.0, // fWereWolfUnarmored - 1.0, // fWereWolfWillPower - 15.0, // fWortChanceValue - }; - - static const char *gmstIntegers[] = - { - "i1stPersonSneakDelta", - "iAlarmAttack", - "iAlarmKilling", - "iAlarmPickPocket", - "iAlarmStealing", - "iAlarmTresspass", - "iAlchemyMod", - "iAutoPCSpellMax", - "iAutoRepFacMod", - "iAutoRepLevMod", - "iAutoSpellAlterationMax", - "iAutoSpellAttSkillMin", - "iAutoSpellConjurationMax", - "iAutoSpellDestructionMax", - "iAutoSpellIllusionMax", - "iAutoSpellMysticismMax", - "iAutoSpellRestorationMax", - "iAutoSpellTimesCanCast", - "iBarterFailDisposition", - "iBarterSuccessDisposition", - "iBaseArmorSkill", - "iBlockMaxChance", - "iBlockMinChance", - "iBootsWeight", - "iCrimeAttack", - "iCrimeKilling", - "iCrimePickPocket", - "iCrimeThreshold", - "iCrimeThresholdMultiplier", - "iCrimeTresspass", - "iCuirassWeight", - "iDaysinPrisonMod", - "iDispAttackMod", - "iDispKilling", - "iDispTresspass", - "iFightAlarmMult", - "iFightAttack", - "iFightAttacking", - "iFightDistanceBase", - "iFightKilling", - "iFightPickpocket", - "iFightTrespass", - "iFlee", - "iGauntletWeight", - "iGreavesWeight", - "iGreetDistanceMultiplier", - "iGreetDuration", - "iHelmWeight", - "iKnockDownOddsBase", - "iKnockDownOddsMult", - "iLevelUp01Mult", - "iLevelUp02Mult", - "iLevelUp03Mult", - "iLevelUp04Mult", - "iLevelUp05Mult", - "iLevelUp06Mult", - "iLevelUp07Mult", - "iLevelUp08Mult", - "iLevelUp09Mult", - "iLevelUp10Mult", - "iLevelupMajorMult", - "iLevelupMajorMultAttribute", - "iLevelupMinorMult", - "iLevelupMinorMultAttribute", - "iLevelupMiscMultAttriubte", - "iLevelupSpecialization", - "iLevelupTotal", - "iMagicItemChargeConst", - "iMagicItemChargeOnce", - "iMagicItemChargeStrike", - "iMagicItemChargeUse", - "iMaxActivateDist", - "iMaxInfoDist", - "iMonthsToRespawn", - "iNumberCreatures", - "iPauldronWeight", - "iPerMinChance", - "iPerMinChange", - "iPickMaxChance", - "iPickMinChance", - "iShieldWeight", - "iSoulAmountForConstantEffect", - "iTrainingMod", - "iVoiceAttackOdds", - "iVoiceHitOdds", - "iWereWolfBounty", - "iWereWolfFightMod", - "iWereWolfFleeMod", - "iWereWolfLevelToAttack", - 0 - }; - - static const int gmstIntegersValues[] = - { - 10, // i1stPersonSneakDelta - 50, // iAlarmAttack - 90, // iAlarmKilling - 20, // iAlarmPickPocket - 1, // iAlarmStealing - 5, // iAlarmTresspass - 2, // iAlchemyMod - 100, // iAutoPCSpellMax - 2, // iAutoRepFacMod - 0, // iAutoRepLevMod - 5, // iAutoSpellAlterationMax - 70, // iAutoSpellAttSkillMin - 2, // iAutoSpellConjurationMax - 5, // iAutoSpellDestructionMax - 5, // iAutoSpellIllusionMax - 5, // iAutoSpellMysticismMax - 5, // iAutoSpellRestorationMax - 3, // iAutoSpellTimesCanCast - -1, // iBarterFailDisposition - 1, // iBarterSuccessDisposition - 30, // iBaseArmorSkill - 50, // iBlockMaxChance - 10, // iBlockMinChance - 20, // iBootsWeight - 40, // iCrimeAttack - 1000, // iCrimeKilling - 25, // iCrimePickPocket - 1000, // iCrimeThreshold - 10, // iCrimeThresholdMultiplier - 5, // iCrimeTresspass - 30, // iCuirassWeight - 100, // iDaysinPrisonMod - -50, // iDispAttackMod - -50, // iDispKilling - -20, // iDispTresspass - 1, // iFightAlarmMult - 100, // iFightAttack - 50, // iFightAttacking - 20, // iFightDistanceBase - 50, // iFightKilling - 25, // iFightPickpocket - 25, // iFightTrespass - 0, // iFlee - 5, // iGauntletWeight - 15, // iGreavesWeight - 6, // iGreetDistanceMultiplier - 4, // iGreetDuration - 5, // iHelmWeight - 50, // iKnockDownOddsBase - 50, // iKnockDownOddsMult - 2, // iLevelUp01Mult - 2, // iLevelUp02Mult - 2, // iLevelUp03Mult - 2, // iLevelUp04Mult - 3, // iLevelUp05Mult - 3, // iLevelUp06Mult - 3, // iLevelUp07Mult - 4, // iLevelUp08Mult - 4, // iLevelUp09Mult - 5, // iLevelUp10Mult - 1, // iLevelupMajorMult - 1, // iLevelupMajorMultAttribute - 1, // iLevelupMinorMult - 1, // iLevelupMinorMultAttribute - 1, // iLevelupMiscMultAttriubte - 1, // iLevelupSpecialization - 10, // iLevelupTotal - 10, // iMagicItemChargeConst - 1, // iMagicItemChargeOnce - 10, // iMagicItemChargeStrike - 5, // iMagicItemChargeUse - 192, // iMaxActivateDist - 192, // iMaxInfoDist - 4, // iMonthsToRespawn - 1, // iNumberCreatures - 10, // iPauldronWeight - 5, // iPerMinChance - 10, // iPerMinChange - 75, // iPickMaxChance - 5, // iPickMinChance - 15, // iShieldWeight - 400, // iSoulAmountForConstantEffect - 10, // iTrainingMod - 10, // iVoiceAttackOdds - 30, // iVoiceHitOdds - 10000, // iWereWolfBounty - 100, // iWereWolfFightMod - 100, // iWereWolfFleeMod - 20, // iWereWolfLevelToAttack - }; - - static const char *gmstStrings[] = - { - "s3dAudio", - "s3dHardware", - "s3dSoftware", - "sAbsorb", - "sAcrobat", - "sActivate", - "sActivateXbox", - "sActorInCombat", - "sAdmire", - "sAdmireFail", - "sAdmireSuccess", - "sAgent", - "sAgiDesc", - "sAIDistance", - "sAlembic", - "sAllTab", - "sAlways", - "sAlways_Run", - "sand", - "sApparatus", - "sApparelTab", - "sArcher", - "sArea", - "sAreaDes", - "sArmor", - "sArmorRating", - "sAsk", - "sAssassin", - "sAt", - "sAttack", - "sAttributeAgility", - "sAttributeEndurance", - "sAttributeIntelligence", - "sAttributeListTitle", - "sAttributeLuck", - "sAttributePersonality", - "sAttributesMenu1", - "sAttributeSpeed", - "sAttributeStrength", - "sAttributeWillpower", - "sAudio", - "sAuto_Run", - "sBack", - "sBackspace", - "sBackXbox", - "sBarbarian", - "sBard", - "sBarter", - "sBarterDialog1", - "sBarterDialog10", - "sBarterDialog11", - "sBarterDialog12", - "sBarterDialog2", - "sBarterDialog3", - "sBarterDialog4", - "sBarterDialog5", - "sBarterDialog6", - "sBarterDialog7", - "sBarterDialog8", - "sBarterDialog9", - "sBattlemage", - "sBestAttack", - "sBirthSign", - "sBirthsignmenu1", - "sBirthsignmenu2", - "sBlocks", - "sBonusSkillTitle", - "sBookPageOne", - "sBookPageTwo", - "sBookSkillMessage", - "sBounty", - "sBreath", - "sBribe 10 Gold", - "sBribe 100 Gold", - "sBribe 1000 Gold", - "sBribeFail", - "sBribeSuccess", - "sBuy", - "sBye", - "sCalcinator", - "sCancel", - "sCantEquipWeapWarning", - "sCastCost", - "sCaughtStealingMessage", - "sCenter", - "sChangedMastersMsg", - "sCharges", - "sChooseClassMenu1", - "sChooseClassMenu2", - "sChooseClassMenu3", - "sChooseClassMenu4", - "sChop", - "sClass", - "sClassChoiceMenu1", - "sClassChoiceMenu2", - "sClassChoiceMenu3", - "sClose", - "sCompanionShare", - "sCompanionWarningButtonOne", - "sCompanionWarningButtonTwo", - "sCompanionWarningMessage", - "sCondition", - "sConsoleTitle", - "sContainer", - "sContentsMessage1", - "sContentsMessage2", - "sContentsMessage3", - "sControlerVibration", - "sControls", - "sControlsMenu1", - "sControlsMenu2", - "sControlsMenu3", - "sControlsMenu4", - "sControlsMenu5", - "sControlsMenu6", - "sCostChance", - "sCostCharge", - "sCreate", - "sCreateClassMenu1", - "sCreateClassMenu2", - "sCreateClassMenu3", - "sCreateClassMenuHelp1", - "sCreateClassMenuHelp2", - "sCreateClassMenuWarning", - "sCreatedEffects", - "sCrimeHelp", - "sCrimeMessage", - "sCrouch_Sneak", - "sCrouchXbox", - "sCrusader", - "sCursorOff", - "sCustom", - "sCustomClassName", - "sDamage", - "sDark_Gamma", - "sDay", - "sDefaultCellname", - "sDelete", - "sDeleteGame", - "sDeleteNote", - "sDeleteSpell", - "sDeleteSpellError", - "sDetail_Level", - "sDialogMenu1", - "sDialogText1Xbox", - "sDialogText2Xbox", - "sDialogText3Xbox", - "sDifficulty", - "sDisposeCorpseFail", - "sDisposeofCorpse", - "sDone", - "sDoYouWantTo", - "sDrain", - "sDrop", - "sDuration", - "sDurationDes", - "sEasy", - "sEditNote", - "sEffectAbsorbAttribute", - "sEffectAbsorbFatigue", - "sEffectAbsorbHealth", - "sEffectAbsorbSkill", - "sEffectAbsorbSpellPoints", - "sEffectAlmsiviIntervention", - "sEffectBlind", - "sEffectBoundBattleAxe", - "sEffectBoundBoots", - "sEffectBoundCuirass", - "sEffectBoundDagger", - "sEffectBoundGloves", - "sEffectBoundHelm", - "sEffectBoundLongbow", - "sEffectBoundLongsword", - "sEffectBoundMace", - "sEffectBoundShield", - "sEffectBoundSpear", - "sEffectBurden", - "sEffectCalmCreature", - "sEffectCalmHumanoid", - "sEffectChameleon", - "sEffectCharm", - "sEffectCommandCreatures", - "sEffectCommandHumanoids", - "sEffectCorpus", - "sEffectCureBlightDisease", - "sEffectCureCommonDisease", - "sEffectCureCorprusDisease", - "sEffectCureParalyzation", - "sEffectCurePoison", - "sEffectDamageAttribute", - "sEffectDamageFatigue", - "sEffectDamageHealth", - "sEffectDamageMagicka", - "sEffectDamageSkill", - "sEffectDemoralizeCreature", - "sEffectDemoralizeHumanoid", - "sEffectDetectAnimal", - "sEffectDetectEnchantment", - "sEffectDetectKey", - "sEffectDisintegrateArmor", - "sEffectDisintegrateWeapon", - "sEffectDispel", - "sEffectDivineIntervention", - "sEffectDrainAttribute", - "sEffectDrainFatigue", - "sEffectDrainHealth", - "sEffectDrainSkill", - "sEffectDrainSpellpoints", - "sEffectExtraSpell", - "sEffectFeather", - "sEffectFireDamage", - "sEffectFireShield", - "sEffectFortifyAttackBonus", - "sEffectFortifyAttribute", - "sEffectFortifyFatigue", - "sEffectFortifyHealth", - "sEffectFortifyMagickaMultiplier", - "sEffectFortifySkill", - "sEffectFortifySpellpoints", - "sEffectFrenzyCreature", - "sEffectFrenzyHumanoid", - "sEffectFrostDamage", - "sEffectFrostShield", - "sEffectInvisibility", - "sEffectJump", - "sEffectLevitate", - "sEffectLight", - "sEffectLightningShield", - "sEffectLock", - "sEffectMark", - "sEffectNightEye", - "sEffectOpen", - "sEffectParalyze", - "sEffectPoison", - "sEffectRallyCreature", - "sEffectRallyHumanoid", - "sEffectRecall", - "sEffectReflect", - "sEffectRemoveCurse", - "sEffectResistBlightDisease", - "sEffectResistCommonDisease", - "sEffectResistCorprusDisease", - "sEffectResistFire", - "sEffectResistFrost", - "sEffectResistMagicka", - "sEffectResistNormalWeapons", - "sEffectResistParalysis", - "sEffectResistPoison", - "sEffectResistShock", - "sEffectRestoreAttribute", - "sEffectRestoreFatigue", - "sEffectRestoreHealth", - "sEffectRestoreSkill", - "sEffectRestoreSpellPoints", - "sEffects", - "sEffectSanctuary", - "sEffectShield", - "sEffectShockDamage", - "sEffectSilence", - "sEffectSlowFall", - "sEffectSoultrap", - "sEffectSound", - "sEffectSpellAbsorption", - "sEffectStuntedMagicka", - "sEffectSummonAncestralGhost", - "sEffectSummonBonelord", - "sEffectSummonCenturionSphere", - "sEffectSummonClannfear", - "sEffectSummonCreature01", - "sEffectSummonCreature02", - "sEffectSummonCreature03", - "sEffectSummonCreature04", - "sEffectSummonCreature05", - "sEffectSummonDaedroth", - "sEffectSummonDremora", - "sEffectSummonFabricant", - "sEffectSummonFlameAtronach", - "sEffectSummonFrostAtronach", - "sEffectSummonGoldensaint", - "sEffectSummonGreaterBonewalker", - "sEffectSummonHunger", - "sEffectSummonLeastBonewalker", - "sEffectSummonScamp", - "sEffectSummonSkeletalMinion", - "sEffectSummonStormAtronach", - "sEffectSummonWingedTwilight", - "sEffectSunDamage", - "sEffectSwiftSwim", - "sEffectTelekinesis", - "sEffectTurnUndead", - "sEffectVampirism", - "sEffectWaterBreathing", - "sEffectWaterWalking", - "sEffectWeaknessToBlightDisease", - "sEffectWeaknessToCommonDisease", - "sEffectWeaknessToCorprusDisease", - "sEffectWeaknessToFire", - "sEffectWeaknessToFrost", - "sEffectWeaknessToMagicka", - "sEffectWeaknessToNormalWeapons", - "sEffectWeaknessToPoison", - "sEffectWeaknessToShock", - "sEnableJoystick", - "sEnchanting", - "sEnchantItems", - "sEnchantmentHelp1", - "sEnchantmentHelp10", - "sEnchantmentHelp2", - "sEnchantmentHelp3", - "sEnchantmentHelp4", - "sEnchantmentHelp5", - "sEnchantmentHelp6", - "sEnchantmentHelp7", - "sEnchantmentHelp8", - "sEnchantmentHelp9", - "sEnchantmentMenu1", - "sEnchantmentMenu10", - "sEnchantmentMenu11", - "sEnchantmentMenu12", - "sEnchantmentMenu2", - "sEnchantmentMenu3", - "sEnchantmentMenu4", - "sEnchantmentMenu5", - "sEnchantmentMenu6", - "sEnchantmentMenu7", - "sEnchantmentMenu8", - "sEnchantmentMenu9", - "sEncumbrance", - "sEndDesc", - "sEquip", - "sExitGame", - "sExpelled", - "sExpelledMessage", - "sFace", - "sFaction", - "sFar", - "sFast", - "sFatDesc", - "sFatigue", - "sFavoriteSkills", - "sfeet", - "sFileSize", - "sfootarea", - "sFootsteps", - "sfor", - "sFortify", - "sForward", - "sForwardXbox", - "sFull", - "sGame", - "sGameWithoutLauncherXbox", - "sGamma_Correction", - "sGeneralMastPlugMismatchMsg", - "sGold", - "sGoodbye", - "sGoverningAttribute", - "sgp", - "sHair", - "sHard", - "sHeal", - "sHealer", - "sHealth", - "sHealthDesc", - "sHealthPerHourOfRest", - "sHealthPerLevel", - "sHeavy", - "sHigh", - "sin", - "sInfo", - "sInfoRefusal", - "sIngredients", - "sInPrisonTitle", - "sInputMenu1", - "sIntDesc", - "sIntimidate", - "sIntimidateFail", - "sIntimidateSuccess", - "sInvalidSaveGameMsg", - "sInvalidSaveGameMsgXBOX", - "sInventory", - "sInventoryMenu1", - "sInventoryMessage1", - "sInventoryMessage2", - "sInventoryMessage3", - "sInventoryMessage4", - "sInventoryMessage5", - "sInventorySelectNoIngredients", - "sInventorySelectNoItems", - "sInventorySelectNoSoul", - "sItem", - "sItemCastConstant", - "sItemCastOnce", - "sItemCastWhenStrikes", - "sItemCastWhenUsed", - "sItemName", - "sJournal", - "sJournalCmd", - "sJournalEntry", - "sJournalXbox", - "sJoystickHatShort", - "sJoystickNotFound", - "sJoystickShort", - "sJump", - "sJumpXbox", - "sKeyName_00", - "sKeyName_01", - "sKeyName_02", - "sKeyName_03", - "sKeyName_04", - "sKeyName_05", - "sKeyName_06", - "sKeyName_07", - "sKeyName_08", - "sKeyName_09", - "sKeyName_0A", - "sKeyName_0B", - "sKeyName_0C", - "sKeyName_0D", - "sKeyName_0E", - "sKeyName_0F", - "sKeyName_10", - "sKeyName_11", - "sKeyName_12", - "sKeyName_13", - "sKeyName_14", - "sKeyName_15", - "sKeyName_16", - "sKeyName_17", - "sKeyName_18", - "sKeyName_19", - "sKeyName_1A", - "sKeyName_1B", - "sKeyName_1C", - "sKeyName_1D", - "sKeyName_1E", - "sKeyName_1F", - "sKeyName_20", - "sKeyName_21", - "sKeyName_22", - "sKeyName_23", - "sKeyName_24", - "sKeyName_25", - "sKeyName_26", - "sKeyName_27", - "sKeyName_28", - "sKeyName_29", - "sKeyName_2A", - "sKeyName_2B", - "sKeyName_2C", - "sKeyName_2D", - "sKeyName_2E", - "sKeyName_2F", - "sKeyName_30", - "sKeyName_31", - "sKeyName_32", - "sKeyName_33", - "sKeyName_34", - "sKeyName_35", - "sKeyName_36", - "sKeyName_37", - "sKeyName_38", - "sKeyName_39", - "sKeyName_3A", - "sKeyName_3B", - "sKeyName_3C", - "sKeyName_3D", - "sKeyName_3E", - "sKeyName_3F", - "sKeyName_40", - "sKeyName_41", - "sKeyName_42", - "sKeyName_43", - "sKeyName_44", - "sKeyName_45", - "sKeyName_46", - "sKeyName_47", - "sKeyName_48", - "sKeyName_49", - "sKeyName_4A", - "sKeyName_4B", - "sKeyName_4C", - "sKeyName_4D", - "sKeyName_4E", - "sKeyName_4F", - "sKeyName_50", - "sKeyName_51", - "sKeyName_52", - "sKeyName_53", - "sKeyName_54", - "sKeyName_55", - "sKeyName_56", - "sKeyName_57", - "sKeyName_58", - "sKeyName_59", - "sKeyName_5A", - "sKeyName_5B", - "sKeyName_5C", - "sKeyName_5D", - "sKeyName_5E", - "sKeyName_5F", - "sKeyName_60", - "sKeyName_61", - "sKeyName_62", - "sKeyName_63", - "sKeyName_64", - "sKeyName_65", - "sKeyName_66", - "sKeyName_67", - "sKeyName_68", - "sKeyName_69", - "sKeyName_6A", - "sKeyName_6B", - "sKeyName_6C", - "sKeyName_6D", - "sKeyName_6E", - "sKeyName_6F", - "sKeyName_70", - "sKeyName_71", - "sKeyName_72", - "sKeyName_73", - "sKeyName_74", - "sKeyName_75", - "sKeyName_76", - "sKeyName_77", - "sKeyName_78", - "sKeyName_79", - "sKeyName_7A", - "sKeyName_7B", - "sKeyName_7C", - "sKeyName_7D", - "sKeyName_7E", - "sKeyName_7F", - "sKeyName_80", - "sKeyName_81", - "sKeyName_82", - "sKeyName_83", - "sKeyName_84", - "sKeyName_85", - "sKeyName_86", - "sKeyName_87", - "sKeyName_88", - "sKeyName_89", - "sKeyName_8A", - "sKeyName_8B", - "sKeyName_8C", - "sKeyName_8D", - "sKeyName_8E", - "sKeyName_8F", - "sKeyName_90", - "sKeyName_91", - "sKeyName_92", - "sKeyName_93", - "sKeyName_94", - "sKeyName_95", - "sKeyName_96", - "sKeyName_97", - "sKeyName_98", - "sKeyName_99", - "sKeyName_9A", - "sKeyName_9B", - "sKeyName_9C", - "sKeyName_9D", - "sKeyName_9E", - "sKeyName_9F", - "sKeyName_A0", - "sKeyName_A1", - "sKeyName_A2", - "sKeyName_A3", - "sKeyName_A4", - "sKeyName_A5", - "sKeyName_A6", - "sKeyName_A7", - "sKeyName_A8", - "sKeyName_A9", - "sKeyName_AA", - "sKeyName_AB", - "sKeyName_AC", - "sKeyName_AD", - "sKeyName_AE", - "sKeyName_AF", - "sKeyName_B0", - "sKeyName_B1", - "sKeyName_B2", - "sKeyName_B3", - "sKeyName_B4", - "sKeyName_B5", - "sKeyName_B6", - "sKeyName_B7", - "sKeyName_B8", - "sKeyName_B9", - "sKeyName_BA", - "sKeyName_BB", - "sKeyName_BC", - "sKeyName_BD", - "sKeyName_BE", - "sKeyName_BF", - "sKeyName_C0", - "sKeyName_C1", - "sKeyName_C2", - "sKeyName_C3", - "sKeyName_C4", - "sKeyName_C5", - "sKeyName_C6", - "sKeyName_C7", - "sKeyName_C8", - "sKeyName_C9", - "sKeyName_CA", - "sKeyName_CB", - "sKeyName_CC", - "sKeyName_CD", - "sKeyName_CE", - "sKeyName_CF", - "sKeyName_D0", - "sKeyName_D1", - "sKeyName_D2", - "sKeyName_D3", - "sKeyName_D4", - "sKeyName_D5", - "sKeyName_D6", - "sKeyName_D7", - "sKeyName_D8", - "sKeyName_D9", - "sKeyName_DA", - "sKeyName_DB", - "sKeyName_DC", - "sKeyName_DD", - "sKeyName_DE", - "sKeyName_DF", - "sKeyName_E0", - "sKeyName_E1", - "sKeyName_E2", - "sKeyName_E3", - "sKeyName_E4", - "sKeyName_E5", - "sKeyName_E6", - "sKeyName_E7", - "sKeyName_E8", - "sKeyName_E9", - "sKeyName_EA", - "sKeyName_EB", - "sKeyName_EC", - "sKeyName_ED", - "sKeyName_EE", - "sKeyName_EF", - "sKeyName_F0", - "sKeyName_F1", - "sKeyName_F2", - "sKeyName_F3", - "sKeyName_F4", - "sKeyName_F5", - "sKeyName_F6", - "sKeyName_F7", - "sKeyName_F8", - "sKeyName_F9", - "sKeyName_FA", - "sKeyName_FB", - "sKeyName_FC", - "sKeyName_FD", - "sKeyName_FE", - "sKeyName_FF", - "sKeyUsed", - "sKilledEssential", - "sKnight", - "sLeft", - "sLess", - "sLevel", - "sLevelProgress", - "sLevels", - "sLevelUp", - "sLevelUpMenu1", - "sLevelUpMenu2", - "sLevelUpMenu3", - "sLevelUpMenu4", - "sLevelUpMsg", - "sLevitateDisabled", - "sLight", - "sLight_Gamma", - "sLoadFailedMessage", - "sLoadGame", - "sLoadingErrorsMsg", - "sLoadingMessage1", - "sLoadingMessage14", - "sLoadingMessage15", - "sLoadingMessage2", - "sLoadingMessage3", - "sLoadingMessage4", - "sLoadingMessage5", - "sLoadingMessage9", - "sLoadLastSaveMsg", - "sLocal", - "sLockFail", - "sLockImpossible", - "sLockLevel", - "sLockSuccess", - "sLookDownXbox", - "sLookUpXbox", - "sLow", - "sLucDesc", - "sMagDesc", - "sMage", - "sMagic", - "sMagicAncestralGhostID", - "sMagicBonelordID", - "sMagicBoundBattleAxeID", - "sMagicBoundBootsID", - "sMagicBoundCuirassID", - "sMagicBoundDaggerID", - "sMagicBoundHelmID", - "sMagicBoundLeftGauntletID", - "sMagicBoundLongbowID", - "sMagicBoundLongswordID", - "sMagicBoundMaceID", - "sMagicBoundRightGauntletID", - "sMagicBoundShieldID", - "sMagicBoundSpearID", - "sMagicCannotRecast", - "sMagicCenturionSphereID", - "sMagicClannfearID", - "sMagicContractDisease", - "sMagicCorprusWorsens", - "sMagicCreature01ID", - "sMagicCreature02ID", - "sMagicCreature03ID", - "sMagicCreature04ID", - "sMagicCreature05ID", - "sMagicDaedrothID", - "sMagicDremoraID", - "sMagicEffects", - "sMagicFabricantID", - "sMagicFlameAtronachID", - "sMagicFrostAtronachID", - "sMagicGoldenSaintID", - "sMagicGreaterBonewalkerID", - "sMagicHungerID", - "sMagicInsufficientCharge", - "sMagicInsufficientSP", - "sMagicInvalidEffect", - "sMagicInvalidTarget", - "sMagicItem", - "sMagicLeastBonewalkerID", - "sMagicLockSuccess", - "sMagicMenu", - "sMagicOpenSuccess", - "sMagicPCResisted", - "sMagicScampID", - "sMagicSelectTitle", - "sMagicSkeletalMinionID", - "sMagicSkillFail", - "sMagicStormAtronachID", - "sMagicTab", - "sMagicTargetResisted", - "sMagicTargetResistsWeapons", - "sMagicWingedTwilightID", - "sMagnitude", - "sMagnitudeDes", - "sMake Enchantment", - "sMap", - "sMaster", - "sMastPlugMismatchMsg", - "sMaximumSaveGameMessage", - "sMaxSale", - "sMedium", - "sMenu_Help_Delay", - "sMenu_Mode", - "sMenuModeXbox", - "sMenuNextXbox", - "sMenuPrevXbox", - "sMenus", - "sMessage1", - "sMessage2", - "sMessage3", - "sMessage4", - "sMessage5", - "sMessageQuestionAnswer1", - "sMessageQuestionAnswer2", - "sMessageQuestionAnswer3", - "sMiscTab", - "sMissingMastersMsg", - "sMonk", - "sMonthEveningstar", - "sMonthFirstseed", - "sMonthFrostfall", - "sMonthHeartfire", - "sMonthLastseed", - "sMonthMidyear", - "sMonthMorningstar", - "sMonthRainshand", - "sMonthSecondseed", - "sMonthSunsdawn", - "sMonthSunsdusk", - "sMonthSunsheight", - "sMore", - "sMortar", - "sMouse", - "sMouseFlip", - "sMouseWheelDownShort", - "sMouseWheelUpShort", - "sMove", - "sMoveDownXbox", - "sMoveUpXbox", - "sMusic", - "sName", - "sNameTitle", - "sNear", - "sNeedOneSkill", - "sNeedTwoSkills", - "sNewGame", - "sNext", - "sNextRank", - "sNextSpell", - "sNextSpellXbox", - "sNextWeapon", - "sNextWeaponXbox", - "sNightblade", - "sNo", - "sNoName", - "sNone", - "sNotifyMessage1", - "sNotifyMessage10", - "sNotifyMessage11", - "sNotifyMessage12", - "sNotifyMessage13", - "sNotifyMessage14", - "sNotifyMessage15", - "sNotifyMessage16", - "sNotifyMessage16_a", - "sNotifyMessage17", - "sNotifyMessage18", - "sNotifyMessage19", - "sNotifyMessage2", - "sNotifyMessage20", - "sNotifyMessage21", - "sNotifyMessage22", - "sNotifyMessage23", - "sNotifyMessage24", - "sNotifyMessage25", - "sNotifyMessage26", - "sNotifyMessage27", - "sNotifyMessage28", - "sNotifyMessage29", - "sNotifyMessage3", - "sNotifyMessage30", - "sNotifyMessage31", - "sNotifyMessage32", - "sNotifyMessage33", - "sNotifyMessage34", - "sNotifyMessage35", - "sNotifyMessage36", - "sNotifyMessage37", - "sNotifyMessage38", - "sNotifyMessage39", - "sNotifyMessage4", - "sNotifyMessage40", - "sNotifyMessage41", - "sNotifyMessage42", - "sNotifyMessage43", - "sNotifyMessage44", - "sNotifyMessage45", - "sNotifyMessage46", - "sNotifyMessage47", - "sNotifyMessage48", - "sNotifyMessage49", - "sNotifyMessage4XBOX", - "sNotifyMessage5", - "sNotifyMessage50", - "sNotifyMessage51", - "sNotifyMessage52", - "sNotifyMessage53", - "sNotifyMessage54", - "sNotifyMessage55", - "sNotifyMessage56", - "sNotifyMessage57", - "sNotifyMessage58", - "sNotifyMessage59", - "sNotifyMessage6", - "sNotifyMessage60", - "sNotifyMessage61", - "sNotifyMessage62", - "sNotifyMessage63", - "sNotifyMessage64", - "sNotifyMessage65", - "sNotifyMessage66", - "sNotifyMessage67", - "sNotifyMessage6a", - "sNotifyMessage7", - "sNotifyMessage8", - "sNotifyMessage9", - "sOff", - "sOffer", - "sOfferMenuTitle", - "sOK", - "sOn", - "sOnce", - "sOneHanded", - "sOnetypeEffectMessage", - "sonword", - "sOptions", - "sOptionsMenuXbox", - "spercent", - "sPerDesc", - "sPersuasion", - "sPersuasionMenuTitle", - "sPickUp", - "sPilgrim", - "spoint", - "spoints", - "sPotionSuccess", - "sPowerAlreadyUsed", - "sPowers", - "sPreferences", - "sPrefs", - "sPrev", - "sPrevSpell", - "sPrevSpellXbox", - "sPrevWeapon", - "sPrevWeaponXbox", - "sProfitValue", - "sQuality", - "sQuanityMenuMessage01", - "sQuanityMenuMessage02", - "sQuestionDeleteSpell", - "sQuestionMark", - "sQuick0Xbox", - "sQuick10Cmd", - "sQuick1Cmd", - "sQuick2Cmd", - "sQuick3Cmd", - "sQuick4Cmd", - "sQuick4Xbox", - "sQuick5Cmd", - "sQuick5Xbox", - "sQuick6Cmd", - "sQuick6Xbox", - "sQuick7Cmd", - "sQuick7Xbox", - "sQuick8Cmd", - "sQuick8Xbox", - "sQuick9Cmd", - "sQuick9Xbox", - "sQuick_Save", - "sQuickLoadCmd", - "sQuickLoadXbox", - "sQuickMenu", - "sQuickMenu1", - "sQuickMenu2", - "sQuickMenu3", - "sQuickMenu4", - "sQuickMenu5", - "sQuickMenu6", - "sQuickMenuInstruc", - "sQuickMenuTitle", - "sQuickSaveCmd", - "sQuickSaveXbox", - "sRace", - "sRaceMenu1", - "sRaceMenu2", - "sRaceMenu3", - "sRaceMenu4", - "sRaceMenu5", - "sRaceMenu6", - "sRaceMenu7", - "sRacialTraits", - "sRange", - "sRangeDes", - "sRangeSelf", - "sRangeTarget", - "sRangeTouch", - "sReady_Magic", - "sReady_Weapon", - "sReadyItemXbox", - "sReadyMagicXbox", - "sRechargeEnchantment", - "sRender_Distance", - "sRepair", - "sRepairFailed", - "sRepairServiceTitle", - "sRepairSuccess", - "sReputation", - "sResChangeWarning", - "sRest", - "sRestIllegal", - "sRestKey", - "sRestMenu1", - "sRestMenu2", - "sRestMenu3", - "sRestMenu4", - "sRestMenuXbox", - "sRestore", - "sRetort", - "sReturnToGame", - "sRight", - "sRogue", - "sRun", - "sRunXbox", - "sSave", - "sSaveGame", - "sSaveGameDenied", - "sSaveGameFailed", - "sSaveGameNoMemory", - "sSaveGameTooBig", - "sSaveMenu1", - "sSaveMenuHelp01", - "sSaveMenuHelp02", - "sSaveMenuHelp03", - "sSaveMenuHelp04", - "sSaveMenuHelp05", - "sSaveMenuHelp06", - "sSchool", - "sSchoolAlteration", - "sSchoolConjuration", - "sSchoolDestruction", - "sSchoolIllusion", - "sSchoolMysticism", - "sSchoolRestoration", - "sScout", - "sScrolldown", - "sScrollup", - "ssecond", - "sseconds", - "sSeldom", - "sSelect", - "sSell", - "sSellerGold", - "sService", - "sServiceRefusal", - "sServiceRepairTitle", - "sServiceSpellsTitle", - "sServiceTrainingTitle", - "sServiceTrainingWords", - "sServiceTravelTitle", - "sSetValueMessage01", - "sSex", - "sShadows", - "sShadowText", - "sShift", - "sSkill", - "sSkillAcrobatics", - "sSkillAlchemy", - "sSkillAlteration", - "sSkillArmorer", - "sSkillAthletics", - "sSkillAxe", - "sSkillBlock", - "sSkillBluntweapon", - "sSkillClassMajor", - "sSkillClassMinor", - "sSkillClassMisc", - "sSkillConjuration", - "sSkillDestruction", - "sSkillEnchant", - "sSkillHandtohand", - "sSkillHeavyarmor", - "sSkillIllusion", - "sSkillLightarmor", - "sSkillLongblade", - "sSkillMarksman", - "sSkillMaxReached", - "sSkillMediumarmor", - "sSkillMercantile", - "sSkillMysticism", - "sSkillProgress", - "sSkillRestoration", - "sSkillSecurity", - "sSkillShortblade", - "sSkillsMenu1", - "sSkillsMenuReputationHelp", - "sSkillSneak", - "sSkillSpear", - "sSkillSpeechcraft", - "sSkillUnarmored", - "sSlash", - "sSleepInterrupt", - "sSlideLeftXbox", - "sSlideRightXbox", - "sSlow", - "sSorceror", - "sSoulGem", - "sSoulGemsWithSouls", - "sSoultrapSuccess", - "sSpace", - "sSpdDesc", - "sSpecialization", - "sSpecializationCombat", - "sSpecializationMagic", - "sSpecializationMenu1", - "sSpecializationStealth", - "sSpellmaking", - "sSpellmakingHelp1", - "sSpellmakingHelp2", - "sSpellmakingHelp3", - "sSpellmakingHelp4", - "sSpellmakingHelp5", - "sSpellmakingHelp6", - "sSpellmakingMenu1", - "sSpellmakingMenuTitle", - "sSpells", - "sSpellServiceTitle", - "sSpellsword", - "sStartCell", - "sStartCellError", - "sStartError", - "sStats", - "sStrafe", - "sStrDesc", - "sStrip", - "sSubtitles", - "sSystemMenuXbox", - "sTake", - "sTakeAll", - "sTargetCriticalStrike", - "sTaunt", - "sTauntFail", - "sTauntSuccess", - "sTeleportDisabled", - "sThief", - "sThrust", - "sTo", - "sTogglePOVCmd", - "sTogglePOVXbox", - "sToggleRunXbox", - "sTopics", - "sTotalCost", - "sTotalSold", - "sTraining", - "sTrainingServiceTitle", - "sTraits", - "sTransparency_Menu", - "sTrapFail", - "sTrapImpossible", - "sTrapped", - "sTrapSuccess", - "sTravel", - "sTravelServiceTitle", - "sTurn", - "sTurnLeftXbox", - "sTurnRightXbox", - "sTwoHanded", - "sType", - "sTypeAbility", - "sTypeBlightDisease", - "sTypeCurse", - "sTypeDisease", - "sTypePower", - "sTypeSpell", - "sUnequip", - "sUnlocked", - "sUntilHealed", - "sUse", - "sUserDefinedClass", - "sUses", - "sUseXbox", - "sValue", - "sVideo", - "sVideoWarning", - "sVoice", - "sWait", - "sWarrior", - "sWaterReflectUpdate", - "sWaterTerrainReflect", - "sWeaponTab", - "sWeight", - "sWerewolfAlarmMessage", - "sWerewolfPopup", - "sWerewolfRefusal", - "sWerewolfRestMessage", - "sWilDesc", - "sWitchhunter", - "sWorld", - "sWornTab", - "sXStrafe", - "sXTimes", - "sXTimesINT", - "sYes", - "sYourGold", - 0 - }; - - for (int i=0; gmstFloats[i]; i++) + for (size_t i=0; i < CSMWorld::DefaultGMSTs::FloatCount; ++i) { ESM::GameSetting gmst; - gmst.mId = gmstFloats[i]; + gmst.mId = CSMWorld::DefaultGMSTs::Floats[i]; gmst.mValue.setType (ESM::VT_Float); - gmst.mValue.setFloat (gmstFloatsValues[i]); + gmst.mValue.setFloat (CSMWorld::DefaultGMSTs::FloatsDefaultValues[i]); getData().getGmsts().add (gmst); } - for (int i=0; gmstIntegers[i]; i++) + for (size_t i=0; i < CSMWorld::DefaultGMSTs::IntCount; ++i) { ESM::GameSetting gmst; - gmst.mId = gmstIntegers[i]; + gmst.mId = CSMWorld::DefaultGMSTs::Ints[i]; gmst.mValue.setType (ESM::VT_Int); - gmst.mValue.setInteger (gmstIntegersValues[i]); + gmst.mValue.setInteger (CSMWorld::DefaultGMSTs::IntsDefaultValues[i]); getData().getGmsts().add (gmst); } - for (int i=0; gmstStrings[i]; i++) + for (size_t i=0; i < CSMWorld::DefaultGMSTs::StringCount; ++i) { ESM::GameSetting gmst; - gmst.mId = gmstStrings[i]; + gmst.mId = CSMWorld::DefaultGMSTs::Strings[i]; gmst.mValue.setType (ESM::VT_String); gmst.mValue.setString (""); getData().getGmsts().add (gmst); @@ -1933,115 +44,28 @@ void CSMDoc::Document::addGmsts() void CSMDoc::Document::addOptionalGmsts() { - static const char *sFloats[] = - { - "fCombatDistanceWerewolfMod", - "fFleeDistance", - "fWereWolfAcrobatics", - "fWereWolfAgility", - "fWereWolfAlchemy", - "fWereWolfAlteration", - "fWereWolfArmorer", - "fWereWolfAthletics", - "fWereWolfAxe", - "fWereWolfBlock", - "fWereWolfBluntWeapon", - "fWereWolfConjuration", - "fWereWolfDestruction", - "fWereWolfEnchant", - "fWereWolfEndurance", - "fWereWolfFatigue", - "fWereWolfHandtoHand", - "fWereWolfHealth", - "fWereWolfHeavyArmor", - "fWereWolfIllusion", - "fWereWolfIntellegence", - "fWereWolfLightArmor", - "fWereWolfLongBlade", - "fWereWolfLuck", - "fWereWolfMagicka", - "fWereWolfMarksman", - "fWereWolfMediumArmor", - "fWereWolfMerchantile", - "fWereWolfMysticism", - "fWereWolfPersonality", - "fWereWolfRestoration", - "fWereWolfRunMult", - "fWereWolfSecurity", - "fWereWolfShortBlade", - "fWereWolfSilverWeaponDamageMult", - "fWereWolfSneak", - "fWereWolfSpear", - "fWereWolfSpeechcraft", - "fWereWolfSpeed", - "fWereWolfStrength", - "fWereWolfUnarmored", - "fWereWolfWillPower", - 0 - }; - - static const char *sIntegers[] = - { - "iWereWolfBounty", - "iWereWolfFightMod", - "iWereWolfFleeMod", - "iWereWolfLevelToAttack", - 0 - }; - - static const char *sStrings[] = - { - "sCompanionShare", - "sCompanionWarningButtonOne", - "sCompanionWarningButtonTwo", - "sCompanionWarningMessage", - "sDeleteNote", - "sEditNote", - "sEffectSummonCreature01", - "sEffectSummonCreature02", - "sEffectSummonCreature03", - "sEffectSummonCreature04", - "sEffectSummonCreature05", - "sEffectSummonFabricant", - "sLevitateDisabled", - "sMagicCreature01ID", - "sMagicCreature02ID", - "sMagicCreature03ID", - "sMagicCreature04ID", - "sMagicCreature05ID", - "sMagicFabricantID", - "sMaxSale", - "sProfitValue", - "sTeleportDisabled", - "sWerewolfAlarmMessage", - "sWerewolfPopup", - "sWerewolfRefusal", - "sWerewolfRestMessage", - 0 - }; - - for (int i=0; sFloats[i]; ++i) + for (size_t i=0; i < CSMWorld::DefaultGMSTs::OptionalFloatCount; ++i) { ESM::GameSetting gmst; - gmst.mId = sFloats[i]; + gmst.mId = CSMWorld::DefaultGMSTs::OptionalFloats[i]; gmst.blank(); gmst.mValue.setType (ESM::VT_Float); addOptionalGmst (gmst); } - for (int i=0; sIntegers[i]; ++i) + for (size_t i=0; i < CSMWorld::DefaultGMSTs::OptionalIntCount; ++i) { ESM::GameSetting gmst; - gmst.mId = sIntegers[i]; + gmst.mId = CSMWorld::DefaultGMSTs::OptionalInts[i]; gmst.blank(); gmst.mValue.setType (ESM::VT_Int); addOptionalGmst (gmst); } - for (int i=0; sStrings[i]; ++i) + for (size_t i=0; i < CSMWorld::DefaultGMSTs::OptionalStringCount; ++i) { ESM::GameSetting gmst; - gmst.mId = sStrings[i]; + gmst.mId = CSMWorld::DefaultGMSTs::OptionalStrings[i]; gmst.blank(); gmst.mValue.setType (ESM::VT_String); gmst.mValue.setString (""); diff --git a/apps/opencs/model/tools/gmstcheck.cpp b/apps/opencs/model/tools/gmstcheck.cpp new file mode 100644 index 000000000..6c17ff3a5 --- /dev/null +++ b/apps/opencs/model/tools/gmstcheck.cpp @@ -0,0 +1,91 @@ +#include "gmstcheck.hpp" + +#include "../world/defaultgmsts.hpp" + +CSMTools::GMSTCheckStage::GMSTCheckStage(const CSMWorld::IdCollection& gameSettings) + : mGameSettings(gameSettings) +{} + +int CSMTools::GMSTCheckStage::setup() +{ + return mGameSettings.getSize(); +} + +void CSMTools::GMSTCheckStage::perform(int stage, CSMDoc::Messages& messages) +{ + const CSMWorld::Record& record = mGameSettings.getRecord (stage); + + if (record.isDeleted()) + return; + + const ESM::GameSetting& gmst = record.get(); + + CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Gmst, gmst.mId); + + // Test for empty string + if (gmst.mValue.getType() == ESM::VT_String && gmst.mValue.getString().empty()) + messages.add(id, gmst.mId + " is an empty string", "", CSMDoc::Message::Severity_Warning); + + // Checking type and limits + // optimization - compare it to lists based on naming convention (f-float,i-int,s-string) + if (gmst.mId[0] == 'f') + { + for (size_t i = 0; i < CSMWorld::DefaultGMSTs::FloatCount; ++i) + { + if (gmst.mId == CSMWorld::DefaultGMSTs::Floats[i]) + { + if (gmst.mValue.getType() != ESM::VT_Float) + messages.add(id, "The type of " + gmst.mId + " is incorrect", + "Change the GMST type to a float", CSMDoc::Message::Severity_Error); + + if (gmst.mValue.getFloat() < CSMWorld::DefaultGMSTs::FloatLimits[i*2]) + messages.add(id, gmst.mId + " is less than the suggested range", "Change the value", + CSMDoc::Message::Severity_Warning); + + if (gmst.mValue.getFloat() > CSMWorld::DefaultGMSTs::FloatLimits[i*2+1]) + messages.add(id, gmst.mId + " is more than the suggested range", "Change the value", + CSMDoc::Message::Severity_Warning); + + break; // for loop + } + } + } + else if (gmst.mId[0] == 'i') + { + for (size_t i = 0; i < CSMWorld::DefaultGMSTs::IntCount; ++i) + { + if (gmst.mId == CSMWorld::DefaultGMSTs::Ints[i]) + { + if (gmst.mValue.getType() != ESM::VT_Int) + messages.add(id, "The type of " + gmst.mId + " is incorrect", + "Change the GMST type to an int", CSMDoc::Message::Severity_Error); + + if (gmst.mValue.getInteger() < CSMWorld::DefaultGMSTs::IntLimits[i*2]) + messages.add(id, gmst.mId + " is less than the suggested range", "Change the value", + CSMDoc::Message::Severity_Warning); + + if (gmst.mValue.getInteger() > CSMWorld::DefaultGMSTs::IntLimits[i*2+1]) + messages.add(id, gmst.mId + " is more than the suggested range", "Change the value", + CSMDoc::Message::Severity_Warning); + + break; // for loop + } + } + } + else if (gmst.mId[0] == 's') + { + for (size_t i = 0; i < CSMWorld::DefaultGMSTs::StringCount; ++i) + { + if (gmst.mId == CSMWorld::DefaultGMSTs::Strings[i]) + { + ESM::VarType type = gmst.mValue.getType(); + + if (type != ESM::VT_String && type != ESM::VT_None) + messages.add(id, "The type of " + gmst.mId + " is incorrect", + "Change the GMST type to a string", CSMDoc::Message::Severity_Error); + + break; // for loop + } + } + } +} diff --git a/apps/opencs/model/tools/gmstcheck.hpp b/apps/opencs/model/tools/gmstcheck.hpp new file mode 100644 index 000000000..ca1564d9e --- /dev/null +++ b/apps/opencs/model/tools/gmstcheck.hpp @@ -0,0 +1,32 @@ +#ifndef CSM_TOOLS_GMSTCHECK_H +#define CSM_TOOLS_GMSTCHECK_H + +#include + +#include "../world/idcollection.hpp" + +#include "../doc/stage.hpp" + +namespace CSMTools +{ + /// \brief VerifyStage: make sure that GMSTs are alright + class GMSTCheckStage : public CSMDoc::Stage + { + public: + + GMSTCheckStage(const CSMWorld::IdCollection& gameSettings); + + virtual int setup(); + ///< \return number of steps + + virtual void perform(int stage, CSMDoc::Messages& messages); + ///< Messages resulting from this stage will be appended to \a messages + + private: + + const CSMWorld::IdCollection& mGameSettings; + + }; +} + +#endif diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index 608ed9922..9f36193ef 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -29,6 +29,7 @@ #include "soundgencheck.hpp" #include "magiceffectcheck.hpp" #include "mergeoperation.hpp" +#include "gmstcheck.hpp" CSMDoc::OperationHolder *CSMTools::Tools::get (int type) { @@ -110,6 +111,8 @@ CSMDoc::OperationHolder *CSMTools::Tools::getVerifier() mData.getReferenceables(), mData.getResources (CSMWorld::UniversalId::Type_Icons), mData.getResources (CSMWorld::UniversalId::Type_Textures))); + + mVerifierOperation->appendStage (new GMSTCheckStage (mData.getGmsts())); mVerifier.setOperation (mVerifierOperation); } diff --git a/apps/opencs/model/world/defaultgmsts.cpp b/apps/opencs/model/world/defaultgmsts.cpp new file mode 100644 index 000000000..ef3d536b1 --- /dev/null +++ b/apps/opencs/model/world/defaultgmsts.cpp @@ -0,0 +1,2336 @@ +#include "defaultgmsts.hpp" + +#include + +const float FInf = std::numeric_limits::infinity(); +const float FEps = std::numeric_limits::epsilon(); + +const int IMax = std::numeric_limits::max(); +const int IMin = std::numeric_limits::min(); + +const char* CSMWorld::DefaultGMSTs::Floats[CSMWorld::DefaultGMSTs::FloatCount] = +{ + "fAIFleeFleeMult", + "fAIFleeHealthMult", + "fAIMagicSpellMult", + "fAIMeleeArmorMult", + "fAIMeleeSummWeaponMult", + "fAIMeleeWeaponMult", + "fAIRangeMagicSpellMult", + "fAIRangeMeleeWeaponMult", + "fAlarmRadius", + "fAthleticsRunBonus", + "fAudioDefaultMaxDistance", + "fAudioDefaultMinDistance", + "fAudioMaxDistanceMult", + "fAudioMinDistanceMult", + "fAudioVoiceDefaultMaxDistance", + "fAudioVoiceDefaultMinDistance", + "fAutoPCSpellChance", + "fAutoSpellChance", + "fBargainOfferBase", + "fBargainOfferMulti", + "fBarterGoldResetDelay", + "fBaseRunMultiplier", + "fBlockStillBonus", + "fBribe1000Mod", + "fBribe100Mod", + "fBribe10Mod", + "fCombatAngleXY", + "fCombatAngleZ", + "fCombatArmorMinMult", + "fCombatBlockLeftAngle", + "fCombatBlockRightAngle", + "fCombatCriticalStrikeMult", + "fCombatDelayCreature", + "fCombatDelayNPC", + "fCombatDistance", + "fCombatDistanceWerewolfMod", + "fCombatForceSideAngle", + "fCombatInvisoMult", + "fCombatKODamageMult", + "fCombatTorsoSideAngle", + "fCombatTorsoStartPercent", + "fCombatTorsoStopPercent", + "fConstantEffectMult", + "fCorpseClearDelay", + "fCorpseRespawnDelay", + "fCrimeGoldDiscountMult", + "fCrimeGoldTurnInMult", + "fCrimeStealing", + "fDamageStrengthBase", + "fDamageStrengthMult", + "fDifficultyMult", + "fDiseaseXferChance", + "fDispAttacking", + "fDispBargainFailMod", + "fDispBargainSuccessMod", + "fDispCrimeMod", + "fDispDiseaseMod", + "fDispFactionMod", + "fDispFactionRankBase", + "fDispFactionRankMult", + "fDispositionMod", + "fDispPersonalityBase", + "fDispPersonalityMult", + "fDispPickPocketMod", + "fDispRaceMod", + "fDispStealing", + "fDispWeaponDrawn", + "fEffectCostMult", + "fElementalShieldMult", + "fEnchantmentChanceMult", + "fEnchantmentConstantChanceMult", + "fEnchantmentConstantDurationMult", + "fEnchantmentMult", + "fEnchantmentValueMult", + "fEncumberedMoveEffect", + "fEncumbranceStrMult", + "fEndFatigueMult", + "fFallAcroBase", + "fFallAcroMult", + "fFallDamageDistanceMin", + "fFallDistanceBase", + "fFallDistanceMult", + "fFatigueAttackBase", + "fFatigueAttackMult", + "fFatigueBase", + "fFatigueBlockBase", + "fFatigueBlockMult", + "fFatigueJumpBase", + "fFatigueJumpMult", + "fFatigueMult", + "fFatigueReturnBase", + "fFatigueReturnMult", + "fFatigueRunBase", + "fFatigueRunMult", + "fFatigueSneakBase", + "fFatigueSneakMult", + "fFatigueSpellBase", + "fFatigueSpellCostMult", + "fFatigueSpellMult", + "fFatigueSwimRunBase", + "fFatigueSwimRunMult", + "fFatigueSwimWalkBase", + "fFatigueSwimWalkMult", + "fFightDispMult", + "fFightDistanceMultiplier", + "fFightStealing", + "fFleeDistance", + "fGreetDistanceReset", + "fHandtoHandHealthPer", + "fHandToHandReach", + "fHoldBreathEndMult", + "fHoldBreathTime", + "fIdleChanceMultiplier", + "fIngredientMult", + "fInteriorHeadTrackMult", + "fJumpAcrobaticsBase", + "fJumpAcroMultiplier", + "fJumpEncumbranceBase", + "fJumpEncumbranceMultiplier", + "fJumpMoveBase", + "fJumpMoveMult", + "fJumpRunMultiplier", + "fKnockDownMult", + "fLevelMod", + "fLevelUpHealthEndMult", + "fLightMaxMod", + "fLuckMod", + "fMagesGuildTravel", + "fMagicCreatureCastDelay", + "fMagicDetectRefreshRate", + "fMagicItemConstantMult", + "fMagicItemCostMult", + "fMagicItemOnceMult", + "fMagicItemPriceMult", + "fMagicItemRechargePerSecond", + "fMagicItemStrikeMult", + "fMagicItemUsedMult", + "fMagicStartIconBlink", + "fMagicSunBlockedMult", + "fMajorSkillBonus", + "fMaxFlySpeed", + "fMaxHandToHandMult", + "fMaxHeadTrackDistance", + "fMaxWalkSpeed", + "fMaxWalkSpeedCreature", + "fMedMaxMod", + "fMessageTimePerChar", + "fMinFlySpeed", + "fMinHandToHandMult", + "fMinorSkillBonus", + "fMinWalkSpeed", + "fMinWalkSpeedCreature", + "fMiscSkillBonus", + "fNPCbaseMagickaMult", + "fNPCHealthBarFade", + "fNPCHealthBarTime", + "fPCbaseMagickaMult", + "fPerDieRollMult", + "fPersonalityMod", + "fPerTempMult", + "fPickLockMult", + "fPickPocketMod", + "fPotionMinUsefulDuration", + "fPotionStrengthMult", + "fPotionT1DurMult", + "fPotionT1MagMult", + "fPotionT4BaseStrengthMult", + "fPotionT4EquipStrengthMult", + "fProjectileMaxSpeed", + "fProjectileMinSpeed", + "fProjectileThrownStoreChance", + "fRepairAmountMult", + "fRepairMult", + "fReputationMod", + "fRestMagicMult", + "fSeriousWoundMult", + "fSleepRandMod", + "fSleepRestMod", + "fSneakBootMult", + "fSneakDistanceBase", + "fSneakDistanceMultiplier", + "fSneakNoViewMult", + "fSneakSkillMult", + "fSneakSpeedMultiplier", + "fSneakUseDelay", + "fSneakUseDist", + "fSneakViewMult", + "fSoulGemMult", + "fSpecialSkillBonus", + "fSpellMakingValueMult", + "fSpellPriceMult", + "fSpellValueMult", + "fStromWalkMult", + "fStromWindSpeed", + "fSuffocationDamage", + "fSwimHeightScale", + "fSwimRunAthleticsMult", + "fSwimRunBase", + "fSwimWalkAthleticsMult", + "fSwimWalkBase", + "fSwingBlockBase", + "fSwingBlockMult", + "fTargetSpellMaxSpeed", + "fThrownWeaponMaxSpeed", + "fThrownWeaponMinSpeed", + "fTrapCostMult", + "fTravelMult", + "fTravelTimeMult", + "fUnarmoredBase1", + "fUnarmoredBase2", + "fVanityDelay", + "fVoiceIdleOdds", + "fWaterReflectUpdateAlways", + "fWaterReflectUpdateSeldom", + "fWeaponDamageMult", + "fWeaponFatigueBlockMult", + "fWeaponFatigueMult", + "fWereWolfAcrobatics", + "fWereWolfAgility", + "fWereWolfAlchemy", + "fWereWolfAlteration", + "fWereWolfArmorer", + "fWereWolfAthletics", + "fWereWolfAxe", + "fWereWolfBlock", + "fWereWolfBluntWeapon", + "fWereWolfConjuration", + "fWereWolfDestruction", + "fWereWolfEnchant", + "fWereWolfEndurance", + "fWereWolfFatigue", + "fWereWolfHandtoHand", + "fWereWolfHealth", + "fWereWolfHeavyArmor", + "fWereWolfIllusion", + "fWereWolfIntellegence", + "fWereWolfLightArmor", + "fWereWolfLongBlade", + "fWereWolfLuck", + "fWereWolfMagicka", + "fWereWolfMarksman", + "fWereWolfMediumArmor", + "fWereWolfMerchantile", + "fWereWolfMysticism", + "fWereWolfPersonality", + "fWereWolfRestoration", + "fWereWolfRunMult", + "fWereWolfSecurity", + "fWereWolfShortBlade", + "fWereWolfSilverWeaponDamageMult", + "fWereWolfSneak", + "fWereWolfSpear", + "fWereWolfSpeechcraft", + "fWereWolfSpeed", + "fWereWolfStrength", + "fWereWolfUnarmored", + "fWereWolfWillPower", + "fWortChanceValue" +}; + +const char * CSMWorld::DefaultGMSTs::Ints[CSMWorld::DefaultGMSTs::IntCount] = +{ + "i1stPersonSneakDelta", + "iAlarmAttack", + "iAlarmKilling", + "iAlarmPickPocket", + "iAlarmStealing", + "iAlarmTresspass", + "iAlchemyMod", + "iAutoPCSpellMax", + "iAutoRepFacMod", + "iAutoRepLevMod", + "iAutoSpellAlterationMax", + "iAutoSpellAttSkillMin", + "iAutoSpellConjurationMax", + "iAutoSpellDestructionMax", + "iAutoSpellIllusionMax", + "iAutoSpellMysticismMax", + "iAutoSpellRestorationMax", + "iAutoSpellTimesCanCast", + "iBarterFailDisposition", + "iBarterSuccessDisposition", + "iBaseArmorSkill", + "iBlockMaxChance", + "iBlockMinChance", + "iBootsWeight", + "iCrimeAttack", + "iCrimeKilling", + "iCrimePickPocket", + "iCrimeThreshold", + "iCrimeThresholdMultiplier", + "iCrimeTresspass", + "iCuirassWeight", + "iDaysinPrisonMod", + "iDispAttackMod", + "iDispKilling", + "iDispTresspass", + "iFightAlarmMult", + "iFightAttack", + "iFightAttacking", + "iFightDistanceBase", + "iFightKilling", + "iFightPickpocket", + "iFightTrespass", + "iFlee", + "iGauntletWeight", + "iGreavesWeight", + "iGreetDistanceMultiplier", + "iGreetDuration", + "iHelmWeight", + "iKnockDownOddsBase", + "iKnockDownOddsMult", + "iLevelUp01Mult", + "iLevelUp02Mult", + "iLevelUp03Mult", + "iLevelUp04Mult", + "iLevelUp05Mult", + "iLevelUp06Mult", + "iLevelUp07Mult", + "iLevelUp08Mult", + "iLevelUp09Mult", + "iLevelUp10Mult", + "iLevelupMajorMult", + "iLevelupMajorMultAttribute", + "iLevelupMinorMult", + "iLevelupMinorMultAttribute", + "iLevelupMiscMultAttriubte", + "iLevelupSpecialization", + "iLevelupTotal", + "iMagicItemChargeConst", + "iMagicItemChargeOnce", + "iMagicItemChargeStrike", + "iMagicItemChargeUse", + "iMaxActivateDist", + "iMaxInfoDist", + "iMonthsToRespawn", + "iNumberCreatures", + "iPauldronWeight", + "iPerMinChance", + "iPerMinChange", + "iPickMaxChance", + "iPickMinChance", + "iShieldWeight", + "iSoulAmountForConstantEffect", + "iTrainingMod", + "iVoiceAttackOdds", + "iVoiceHitOdds", + "iWereWolfBounty", + "iWereWolfFightMod", + "iWereWolfFleeMod", + "iWereWolfLevelToAttack" +}; + +const char * CSMWorld::DefaultGMSTs::Strings[CSMWorld::DefaultGMSTs::StringCount] = +{ + "s3dAudio", + "s3dHardware", + "s3dSoftware", + "sAbsorb", + "sAcrobat", + "sActivate", + "sActivateXbox", + "sActorInCombat", + "sAdmire", + "sAdmireFail", + "sAdmireSuccess", + "sAgent", + "sAgiDesc", + "sAIDistance", + "sAlembic", + "sAllTab", + "sAlways", + "sAlways_Run", + "sand", + "sApparatus", + "sApparelTab", + "sArcher", + "sArea", + "sAreaDes", + "sArmor", + "sArmorRating", + "sAsk", + "sAssassin", + "sAt", + "sAttack", + "sAttributeAgility", + "sAttributeEndurance", + "sAttributeIntelligence", + "sAttributeListTitle", + "sAttributeLuck", + "sAttributePersonality", + "sAttributesMenu1", + "sAttributeSpeed", + "sAttributeStrength", + "sAttributeWillpower", + "sAudio", + "sAuto_Run", + "sBack", + "sBackspace", + "sBackXbox", + "sBarbarian", + "sBard", + "sBarter", + "sBarterDialog1", + "sBarterDialog10", + "sBarterDialog11", + "sBarterDialog12", + "sBarterDialog2", + "sBarterDialog3", + "sBarterDialog4", + "sBarterDialog5", + "sBarterDialog6", + "sBarterDialog7", + "sBarterDialog8", + "sBarterDialog9", + "sBattlemage", + "sBestAttack", + "sBirthSign", + "sBirthsignmenu1", + "sBirthsignmenu2", + "sBlocks", + "sBonusSkillTitle", + "sBookPageOne", + "sBookPageTwo", + "sBookSkillMessage", + "sBounty", + "sBreath", + "sBribe 10 Gold", + "sBribe 100 Gold", + "sBribe 1000 Gold", + "sBribeFail", + "sBribeSuccess", + "sBuy", + "sBye", + "sCalcinator", + "sCancel", + "sCantEquipWeapWarning", + "sCastCost", + "sCaughtStealingMessage", + "sCenter", + "sChangedMastersMsg", + "sCharges", + "sChooseClassMenu1", + "sChooseClassMenu2", + "sChooseClassMenu3", + "sChooseClassMenu4", + "sChop", + "sClass", + "sClassChoiceMenu1", + "sClassChoiceMenu2", + "sClassChoiceMenu3", + "sClose", + "sCompanionShare", + "sCompanionWarningButtonOne", + "sCompanionWarningButtonTwo", + "sCompanionWarningMessage", + "sCondition", + "sConsoleTitle", + "sContainer", + "sContentsMessage1", + "sContentsMessage2", + "sContentsMessage3", + "sControlerVibration", + "sControls", + "sControlsMenu1", + "sControlsMenu2", + "sControlsMenu3", + "sControlsMenu4", + "sControlsMenu5", + "sControlsMenu6", + "sCostChance", + "sCostCharge", + "sCreate", + "sCreateClassMenu1", + "sCreateClassMenu2", + "sCreateClassMenu3", + "sCreateClassMenuHelp1", + "sCreateClassMenuHelp2", + "sCreateClassMenuWarning", + "sCreatedEffects", + "sCrimeHelp", + "sCrimeMessage", + "sCrouch_Sneak", + "sCrouchXbox", + "sCrusader", + "sCursorOff", + "sCustom", + "sCustomClassName", + "sDamage", + "sDark_Gamma", + "sDay", + "sDefaultCellname", + "sDelete", + "sDeleteGame", + "sDeleteNote", + "sDeleteSpell", + "sDeleteSpellError", + "sDetail_Level", + "sDialogMenu1", + "sDialogText1Xbox", + "sDialogText2Xbox", + "sDialogText3Xbox", + "sDifficulty", + "sDisposeCorpseFail", + "sDisposeofCorpse", + "sDone", + "sDoYouWantTo", + "sDrain", + "sDrop", + "sDuration", + "sDurationDes", + "sEasy", + "sEditNote", + "sEffectAbsorbAttribute", + "sEffectAbsorbFatigue", + "sEffectAbsorbHealth", + "sEffectAbsorbSkill", + "sEffectAbsorbSpellPoints", + "sEffectAlmsiviIntervention", + "sEffectBlind", + "sEffectBoundBattleAxe", + "sEffectBoundBoots", + "sEffectBoundCuirass", + "sEffectBoundDagger", + "sEffectBoundGloves", + "sEffectBoundHelm", + "sEffectBoundLongbow", + "sEffectBoundLongsword", + "sEffectBoundMace", + "sEffectBoundShield", + "sEffectBoundSpear", + "sEffectBurden", + "sEffectCalmCreature", + "sEffectCalmHumanoid", + "sEffectChameleon", + "sEffectCharm", + "sEffectCommandCreatures", + "sEffectCommandHumanoids", + "sEffectCorpus", + "sEffectCureBlightDisease", + "sEffectCureCommonDisease", + "sEffectCureCorprusDisease", + "sEffectCureParalyzation", + "sEffectCurePoison", + "sEffectDamageAttribute", + "sEffectDamageFatigue", + "sEffectDamageHealth", + "sEffectDamageMagicka", + "sEffectDamageSkill", + "sEffectDemoralizeCreature", + "sEffectDemoralizeHumanoid", + "sEffectDetectAnimal", + "sEffectDetectEnchantment", + "sEffectDetectKey", + "sEffectDisintegrateArmor", + "sEffectDisintegrateWeapon", + "sEffectDispel", + "sEffectDivineIntervention", + "sEffectDrainAttribute", + "sEffectDrainFatigue", + "sEffectDrainHealth", + "sEffectDrainSkill", + "sEffectDrainSpellpoints", + "sEffectExtraSpell", + "sEffectFeather", + "sEffectFireDamage", + "sEffectFireShield", + "sEffectFortifyAttackBonus", + "sEffectFortifyAttribute", + "sEffectFortifyFatigue", + "sEffectFortifyHealth", + "sEffectFortifyMagickaMultiplier", + "sEffectFortifySkill", + "sEffectFortifySpellpoints", + "sEffectFrenzyCreature", + "sEffectFrenzyHumanoid", + "sEffectFrostDamage", + "sEffectFrostShield", + "sEffectInvisibility", + "sEffectJump", + "sEffectLevitate", + "sEffectLight", + "sEffectLightningShield", + "sEffectLock", + "sEffectMark", + "sEffectNightEye", + "sEffectOpen", + "sEffectParalyze", + "sEffectPoison", + "sEffectRallyCreature", + "sEffectRallyHumanoid", + "sEffectRecall", + "sEffectReflect", + "sEffectRemoveCurse", + "sEffectResistBlightDisease", + "sEffectResistCommonDisease", + "sEffectResistCorprusDisease", + "sEffectResistFire", + "sEffectResistFrost", + "sEffectResistMagicka", + "sEffectResistNormalWeapons", + "sEffectResistParalysis", + "sEffectResistPoison", + "sEffectResistShock", + "sEffectRestoreAttribute", + "sEffectRestoreFatigue", + "sEffectRestoreHealth", + "sEffectRestoreSkill", + "sEffectRestoreSpellPoints", + "sEffects", + "sEffectSanctuary", + "sEffectShield", + "sEffectShockDamage", + "sEffectSilence", + "sEffectSlowFall", + "sEffectSoultrap", + "sEffectSound", + "sEffectSpellAbsorption", + "sEffectStuntedMagicka", + "sEffectSummonAncestralGhost", + "sEffectSummonBonelord", + "sEffectSummonCenturionSphere", + "sEffectSummonClannfear", + "sEffectSummonCreature01", + "sEffectSummonCreature02", + "sEffectSummonCreature03", + "sEffectSummonCreature04", + "sEffectSummonCreature05", + "sEffectSummonDaedroth", + "sEffectSummonDremora", + "sEffectSummonFabricant", + "sEffectSummonFlameAtronach", + "sEffectSummonFrostAtronach", + "sEffectSummonGoldensaint", + "sEffectSummonGreaterBonewalker", + "sEffectSummonHunger", + "sEffectSummonLeastBonewalker", + "sEffectSummonScamp", + "sEffectSummonSkeletalMinion", + "sEffectSummonStormAtronach", + "sEffectSummonWingedTwilight", + "sEffectSunDamage", + "sEffectSwiftSwim", + "sEffectTelekinesis", + "sEffectTurnUndead", + "sEffectVampirism", + "sEffectWaterBreathing", + "sEffectWaterWalking", + "sEffectWeaknessToBlightDisease", + "sEffectWeaknessToCommonDisease", + "sEffectWeaknessToCorprusDisease", + "sEffectWeaknessToFire", + "sEffectWeaknessToFrost", + "sEffectWeaknessToMagicka", + "sEffectWeaknessToNormalWeapons", + "sEffectWeaknessToPoison", + "sEffectWeaknessToShock", + "sEnableJoystick", + "sEnchanting", + "sEnchantItems", + "sEnchantmentHelp1", + "sEnchantmentHelp10", + "sEnchantmentHelp2", + "sEnchantmentHelp3", + "sEnchantmentHelp4", + "sEnchantmentHelp5", + "sEnchantmentHelp6", + "sEnchantmentHelp7", + "sEnchantmentHelp8", + "sEnchantmentHelp9", + "sEnchantmentMenu1", + "sEnchantmentMenu10", + "sEnchantmentMenu11", + "sEnchantmentMenu12", + "sEnchantmentMenu2", + "sEnchantmentMenu3", + "sEnchantmentMenu4", + "sEnchantmentMenu5", + "sEnchantmentMenu6", + "sEnchantmentMenu7", + "sEnchantmentMenu8", + "sEnchantmentMenu9", + "sEncumbrance", + "sEndDesc", + "sEquip", + "sExitGame", + "sExpelled", + "sExpelledMessage", + "sFace", + "sFaction", + "sFar", + "sFast", + "sFatDesc", + "sFatigue", + "sFavoriteSkills", + "sfeet", + "sFileSize", + "sfootarea", + "sFootsteps", + "sfor", + "sFortify", + "sForward", + "sForwardXbox", + "sFull", + "sGame", + "sGameWithoutLauncherXbox", + "sGamma_Correction", + "sGeneralMastPlugMismatchMsg", + "sGold", + "sGoodbye", + "sGoverningAttribute", + "sgp", + "sHair", + "sHard", + "sHeal", + "sHealer", + "sHealth", + "sHealthDesc", + "sHealthPerHourOfRest", + "sHealthPerLevel", + "sHeavy", + "sHigh", + "sin", + "sInfo", + "sInfoRefusal", + "sIngredients", + "sInPrisonTitle", + "sInputMenu1", + "sIntDesc", + "sIntimidate", + "sIntimidateFail", + "sIntimidateSuccess", + "sInvalidSaveGameMsg", + "sInvalidSaveGameMsgXBOX", + "sInventory", + "sInventoryMenu1", + "sInventoryMessage1", + "sInventoryMessage2", + "sInventoryMessage3", + "sInventoryMessage4", + "sInventoryMessage5", + "sInventorySelectNoIngredients", + "sInventorySelectNoItems", + "sInventorySelectNoSoul", + "sItem", + "sItemCastConstant", + "sItemCastOnce", + "sItemCastWhenStrikes", + "sItemCastWhenUsed", + "sItemName", + "sJournal", + "sJournalCmd", + "sJournalEntry", + "sJournalXbox", + "sJoystickHatShort", + "sJoystickNotFound", + "sJoystickShort", + "sJump", + "sJumpXbox", + "sKeyName_00", + "sKeyName_01", + "sKeyName_02", + "sKeyName_03", + "sKeyName_04", + "sKeyName_05", + "sKeyName_06", + "sKeyName_07", + "sKeyName_08", + "sKeyName_09", + "sKeyName_0A", + "sKeyName_0B", + "sKeyName_0C", + "sKeyName_0D", + "sKeyName_0E", + "sKeyName_0F", + "sKeyName_10", + "sKeyName_11", + "sKeyName_12", + "sKeyName_13", + "sKeyName_14", + "sKeyName_15", + "sKeyName_16", + "sKeyName_17", + "sKeyName_18", + "sKeyName_19", + "sKeyName_1A", + "sKeyName_1B", + "sKeyName_1C", + "sKeyName_1D", + "sKeyName_1E", + "sKeyName_1F", + "sKeyName_20", + "sKeyName_21", + "sKeyName_22", + "sKeyName_23", + "sKeyName_24", + "sKeyName_25", + "sKeyName_26", + "sKeyName_27", + "sKeyName_28", + "sKeyName_29", + "sKeyName_2A", + "sKeyName_2B", + "sKeyName_2C", + "sKeyName_2D", + "sKeyName_2E", + "sKeyName_2F", + "sKeyName_30", + "sKeyName_31", + "sKeyName_32", + "sKeyName_33", + "sKeyName_34", + "sKeyName_35", + "sKeyName_36", + "sKeyName_37", + "sKeyName_38", + "sKeyName_39", + "sKeyName_3A", + "sKeyName_3B", + "sKeyName_3C", + "sKeyName_3D", + "sKeyName_3E", + "sKeyName_3F", + "sKeyName_40", + "sKeyName_41", + "sKeyName_42", + "sKeyName_43", + "sKeyName_44", + "sKeyName_45", + "sKeyName_46", + "sKeyName_47", + "sKeyName_48", + "sKeyName_49", + "sKeyName_4A", + "sKeyName_4B", + "sKeyName_4C", + "sKeyName_4D", + "sKeyName_4E", + "sKeyName_4F", + "sKeyName_50", + "sKeyName_51", + "sKeyName_52", + "sKeyName_53", + "sKeyName_54", + "sKeyName_55", + "sKeyName_56", + "sKeyName_57", + "sKeyName_58", + "sKeyName_59", + "sKeyName_5A", + "sKeyName_5B", + "sKeyName_5C", + "sKeyName_5D", + "sKeyName_5E", + "sKeyName_5F", + "sKeyName_60", + "sKeyName_61", + "sKeyName_62", + "sKeyName_63", + "sKeyName_64", + "sKeyName_65", + "sKeyName_66", + "sKeyName_67", + "sKeyName_68", + "sKeyName_69", + "sKeyName_6A", + "sKeyName_6B", + "sKeyName_6C", + "sKeyName_6D", + "sKeyName_6E", + "sKeyName_6F", + "sKeyName_70", + "sKeyName_71", + "sKeyName_72", + "sKeyName_73", + "sKeyName_74", + "sKeyName_75", + "sKeyName_76", + "sKeyName_77", + "sKeyName_78", + "sKeyName_79", + "sKeyName_7A", + "sKeyName_7B", + "sKeyName_7C", + "sKeyName_7D", + "sKeyName_7E", + "sKeyName_7F", + "sKeyName_80", + "sKeyName_81", + "sKeyName_82", + "sKeyName_83", + "sKeyName_84", + "sKeyName_85", + "sKeyName_86", + "sKeyName_87", + "sKeyName_88", + "sKeyName_89", + "sKeyName_8A", + "sKeyName_8B", + "sKeyName_8C", + "sKeyName_8D", + "sKeyName_8E", + "sKeyName_8F", + "sKeyName_90", + "sKeyName_91", + "sKeyName_92", + "sKeyName_93", + "sKeyName_94", + "sKeyName_95", + "sKeyName_96", + "sKeyName_97", + "sKeyName_98", + "sKeyName_99", + "sKeyName_9A", + "sKeyName_9B", + "sKeyName_9C", + "sKeyName_9D", + "sKeyName_9E", + "sKeyName_9F", + "sKeyName_A0", + "sKeyName_A1", + "sKeyName_A2", + "sKeyName_A3", + "sKeyName_A4", + "sKeyName_A5", + "sKeyName_A6", + "sKeyName_A7", + "sKeyName_A8", + "sKeyName_A9", + "sKeyName_AA", + "sKeyName_AB", + "sKeyName_AC", + "sKeyName_AD", + "sKeyName_AE", + "sKeyName_AF", + "sKeyName_B0", + "sKeyName_B1", + "sKeyName_B2", + "sKeyName_B3", + "sKeyName_B4", + "sKeyName_B5", + "sKeyName_B6", + "sKeyName_B7", + "sKeyName_B8", + "sKeyName_B9", + "sKeyName_BA", + "sKeyName_BB", + "sKeyName_BC", + "sKeyName_BD", + "sKeyName_BE", + "sKeyName_BF", + "sKeyName_C0", + "sKeyName_C1", + "sKeyName_C2", + "sKeyName_C3", + "sKeyName_C4", + "sKeyName_C5", + "sKeyName_C6", + "sKeyName_C7", + "sKeyName_C8", + "sKeyName_C9", + "sKeyName_CA", + "sKeyName_CB", + "sKeyName_CC", + "sKeyName_CD", + "sKeyName_CE", + "sKeyName_CF", + "sKeyName_D0", + "sKeyName_D1", + "sKeyName_D2", + "sKeyName_D3", + "sKeyName_D4", + "sKeyName_D5", + "sKeyName_D6", + "sKeyName_D7", + "sKeyName_D8", + "sKeyName_D9", + "sKeyName_DA", + "sKeyName_DB", + "sKeyName_DC", + "sKeyName_DD", + "sKeyName_DE", + "sKeyName_DF", + "sKeyName_E0", + "sKeyName_E1", + "sKeyName_E2", + "sKeyName_E3", + "sKeyName_E4", + "sKeyName_E5", + "sKeyName_E6", + "sKeyName_E7", + "sKeyName_E8", + "sKeyName_E9", + "sKeyName_EA", + "sKeyName_EB", + "sKeyName_EC", + "sKeyName_ED", + "sKeyName_EE", + "sKeyName_EF", + "sKeyName_F0", + "sKeyName_F1", + "sKeyName_F2", + "sKeyName_F3", + "sKeyName_F4", + "sKeyName_F5", + "sKeyName_F6", + "sKeyName_F7", + "sKeyName_F8", + "sKeyName_F9", + "sKeyName_FA", + "sKeyName_FB", + "sKeyName_FC", + "sKeyName_FD", + "sKeyName_FE", + "sKeyName_FF", + "sKeyUsed", + "sKilledEssential", + "sKnight", + "sLeft", + "sLess", + "sLevel", + "sLevelProgress", + "sLevels", + "sLevelUp", + "sLevelUpMenu1", + "sLevelUpMenu2", + "sLevelUpMenu3", + "sLevelUpMenu4", + "sLevelUpMsg", + "sLevitateDisabled", + "sLight", + "sLight_Gamma", + "sLoadFailedMessage", + "sLoadGame", + "sLoadingErrorsMsg", + "sLoadingMessage1", + "sLoadingMessage14", + "sLoadingMessage15", + "sLoadingMessage2", + "sLoadingMessage3", + "sLoadingMessage4", + "sLoadingMessage5", + "sLoadingMessage9", + "sLoadLastSaveMsg", + "sLocal", + "sLockFail", + "sLockImpossible", + "sLockLevel", + "sLockSuccess", + "sLookDownXbox", + "sLookUpXbox", + "sLow", + "sLucDesc", + "sMagDesc", + "sMage", + "sMagic", + "sMagicAncestralGhostID", + "sMagicBonelordID", + "sMagicBoundBattleAxeID", + "sMagicBoundBootsID", + "sMagicBoundCuirassID", + "sMagicBoundDaggerID", + "sMagicBoundHelmID", + "sMagicBoundLeftGauntletID", + "sMagicBoundLongbowID", + "sMagicBoundLongswordID", + "sMagicBoundMaceID", + "sMagicBoundRightGauntletID", + "sMagicBoundShieldID", + "sMagicBoundSpearID", + "sMagicCannotRecast", + "sMagicCenturionSphereID", + "sMagicClannfearID", + "sMagicContractDisease", + "sMagicCorprusWorsens", + "sMagicCreature01ID", + "sMagicCreature02ID", + "sMagicCreature03ID", + "sMagicCreature04ID", + "sMagicCreature05ID", + "sMagicDaedrothID", + "sMagicDremoraID", + "sMagicEffects", + "sMagicFabricantID", + "sMagicFlameAtronachID", + "sMagicFrostAtronachID", + "sMagicGoldenSaintID", + "sMagicGreaterBonewalkerID", + "sMagicHungerID", + "sMagicInsufficientCharge", + "sMagicInsufficientSP", + "sMagicInvalidEffect", + "sMagicInvalidTarget", + "sMagicItem", + "sMagicLeastBonewalkerID", + "sMagicLockSuccess", + "sMagicMenu", + "sMagicOpenSuccess", + "sMagicPCResisted", + "sMagicScampID", + "sMagicSelectTitle", + "sMagicSkeletalMinionID", + "sMagicSkillFail", + "sMagicStormAtronachID", + "sMagicTab", + "sMagicTargetResisted", + "sMagicTargetResistsWeapons", + "sMagicWingedTwilightID", + "sMagnitude", + "sMagnitudeDes", + "sMake Enchantment", + "sMap", + "sMaster", + "sMastPlugMismatchMsg", + "sMaximumSaveGameMessage", + "sMaxSale", + "sMedium", + "sMenu_Help_Delay", + "sMenu_Mode", + "sMenuModeXbox", + "sMenuNextXbox", + "sMenuPrevXbox", + "sMenus", + "sMessage1", + "sMessage2", + "sMessage3", + "sMessage4", + "sMessage5", + "sMessageQuestionAnswer1", + "sMessageQuestionAnswer2", + "sMessageQuestionAnswer3", + "sMiscTab", + "sMissingMastersMsg", + "sMonk", + "sMonthEveningstar", + "sMonthFirstseed", + "sMonthFrostfall", + "sMonthHeartfire", + "sMonthLastseed", + "sMonthMidyear", + "sMonthMorningstar", + "sMonthRainshand", + "sMonthSecondseed", + "sMonthSunsdawn", + "sMonthSunsdusk", + "sMonthSunsheight", + "sMore", + "sMortar", + "sMouse", + "sMouseFlip", + "sMouseWheelDownShort", + "sMouseWheelUpShort", + "sMove", + "sMoveDownXbox", + "sMoveUpXbox", + "sMusic", + "sName", + "sNameTitle", + "sNear", + "sNeedOneSkill", + "sNeedTwoSkills", + "sNewGame", + "sNext", + "sNextRank", + "sNextSpell", + "sNextSpellXbox", + "sNextWeapon", + "sNextWeaponXbox", + "sNightblade", + "sNo", + "sNoName", + "sNone", + "sNotifyMessage1", + "sNotifyMessage10", + "sNotifyMessage11", + "sNotifyMessage12", + "sNotifyMessage13", + "sNotifyMessage14", + "sNotifyMessage15", + "sNotifyMessage16", + "sNotifyMessage16_a", + "sNotifyMessage17", + "sNotifyMessage18", + "sNotifyMessage19", + "sNotifyMessage2", + "sNotifyMessage20", + "sNotifyMessage21", + "sNotifyMessage22", + "sNotifyMessage23", + "sNotifyMessage24", + "sNotifyMessage25", + "sNotifyMessage26", + "sNotifyMessage27", + "sNotifyMessage28", + "sNotifyMessage29", + "sNotifyMessage3", + "sNotifyMessage30", + "sNotifyMessage31", + "sNotifyMessage32", + "sNotifyMessage33", + "sNotifyMessage34", + "sNotifyMessage35", + "sNotifyMessage36", + "sNotifyMessage37", + "sNotifyMessage38", + "sNotifyMessage39", + "sNotifyMessage4", + "sNotifyMessage40", + "sNotifyMessage41", + "sNotifyMessage42", + "sNotifyMessage43", + "sNotifyMessage44", + "sNotifyMessage45", + "sNotifyMessage46", + "sNotifyMessage47", + "sNotifyMessage48", + "sNotifyMessage49", + "sNotifyMessage4XBOX", + "sNotifyMessage5", + "sNotifyMessage50", + "sNotifyMessage51", + "sNotifyMessage52", + "sNotifyMessage53", + "sNotifyMessage54", + "sNotifyMessage55", + "sNotifyMessage56", + "sNotifyMessage57", + "sNotifyMessage58", + "sNotifyMessage59", + "sNotifyMessage6", + "sNotifyMessage60", + "sNotifyMessage61", + "sNotifyMessage62", + "sNotifyMessage63", + "sNotifyMessage64", + "sNotifyMessage65", + "sNotifyMessage66", + "sNotifyMessage67", + "sNotifyMessage6a", + "sNotifyMessage7", + "sNotifyMessage8", + "sNotifyMessage9", + "sOff", + "sOffer", + "sOfferMenuTitle", + "sOK", + "sOn", + "sOnce", + "sOneHanded", + "sOnetypeEffectMessage", + "sonword", + "sOptions", + "sOptionsMenuXbox", + "spercent", + "sPerDesc", + "sPersuasion", + "sPersuasionMenuTitle", + "sPickUp", + "sPilgrim", + "spoint", + "spoints", + "sPotionSuccess", + "sPowerAlreadyUsed", + "sPowers", + "sPreferences", + "sPrefs", + "sPrev", + "sPrevSpell", + "sPrevSpellXbox", + "sPrevWeapon", + "sPrevWeaponXbox", + "sProfitValue", + "sQuality", + "sQuanityMenuMessage01", + "sQuanityMenuMessage02", + "sQuestionDeleteSpell", + "sQuestionMark", + "sQuick0Xbox", + "sQuick10Cmd", + "sQuick1Cmd", + "sQuick2Cmd", + "sQuick3Cmd", + "sQuick4Cmd", + "sQuick4Xbox", + "sQuick5Cmd", + "sQuick5Xbox", + "sQuick6Cmd", + "sQuick6Xbox", + "sQuick7Cmd", + "sQuick7Xbox", + "sQuick8Cmd", + "sQuick8Xbox", + "sQuick9Cmd", + "sQuick9Xbox", + "sQuick_Save", + "sQuickLoadCmd", + "sQuickLoadXbox", + "sQuickMenu", + "sQuickMenu1", + "sQuickMenu2", + "sQuickMenu3", + "sQuickMenu4", + "sQuickMenu5", + "sQuickMenu6", + "sQuickMenuInstruc", + "sQuickMenuTitle", + "sQuickSaveCmd", + "sQuickSaveXbox", + "sRace", + "sRaceMenu1", + "sRaceMenu2", + "sRaceMenu3", + "sRaceMenu4", + "sRaceMenu5", + "sRaceMenu6", + "sRaceMenu7", + "sRacialTraits", + "sRange", + "sRangeDes", + "sRangeSelf", + "sRangeTarget", + "sRangeTouch", + "sReady_Magic", + "sReady_Weapon", + "sReadyItemXbox", + "sReadyMagicXbox", + "sRechargeEnchantment", + "sRender_Distance", + "sRepair", + "sRepairFailed", + "sRepairServiceTitle", + "sRepairSuccess", + "sReputation", + "sResChangeWarning", + "sRest", + "sRestIllegal", + "sRestKey", + "sRestMenu1", + "sRestMenu2", + "sRestMenu3", + "sRestMenu4", + "sRestMenuXbox", + "sRestore", + "sRetort", + "sReturnToGame", + "sRight", + "sRogue", + "sRun", + "sRunXbox", + "sSave", + "sSaveGame", + "sSaveGameDenied", + "sSaveGameFailed", + "sSaveGameNoMemory", + "sSaveGameTooBig", + "sSaveMenu1", + "sSaveMenuHelp01", + "sSaveMenuHelp02", + "sSaveMenuHelp03", + "sSaveMenuHelp04", + "sSaveMenuHelp05", + "sSaveMenuHelp06", + "sSchool", + "sSchoolAlteration", + "sSchoolConjuration", + "sSchoolDestruction", + "sSchoolIllusion", + "sSchoolMysticism", + "sSchoolRestoration", + "sScout", + "sScrolldown", + "sScrollup", + "ssecond", + "sseconds", + "sSeldom", + "sSelect", + "sSell", + "sSellerGold", + "sService", + "sServiceRefusal", + "sServiceRepairTitle", + "sServiceSpellsTitle", + "sServiceTrainingTitle", + "sServiceTrainingWords", + "sServiceTravelTitle", + "sSetValueMessage01", + "sSex", + "sShadows", + "sShadowText", + "sShift", + "sSkill", + "sSkillAcrobatics", + "sSkillAlchemy", + "sSkillAlteration", + "sSkillArmorer", + "sSkillAthletics", + "sSkillAxe", + "sSkillBlock", + "sSkillBluntweapon", + "sSkillClassMajor", + "sSkillClassMinor", + "sSkillClassMisc", + "sSkillConjuration", + "sSkillDestruction", + "sSkillEnchant", + "sSkillHandtohand", + "sSkillHeavyarmor", + "sSkillIllusion", + "sSkillLightarmor", + "sSkillLongblade", + "sSkillMarksman", + "sSkillMaxReached", + "sSkillMediumarmor", + "sSkillMercantile", + "sSkillMysticism", + "sSkillProgress", + "sSkillRestoration", + "sSkillSecurity", + "sSkillShortblade", + "sSkillsMenu1", + "sSkillsMenuReputationHelp", + "sSkillSneak", + "sSkillSpear", + "sSkillSpeechcraft", + "sSkillUnarmored", + "sSlash", + "sSleepInterrupt", + "sSlideLeftXbox", + "sSlideRightXbox", + "sSlow", + "sSorceror", + "sSoulGem", + "sSoulGemsWithSouls", + "sSoultrapSuccess", + "sSpace", + "sSpdDesc", + "sSpecialization", + "sSpecializationCombat", + "sSpecializationMagic", + "sSpecializationMenu1", + "sSpecializationStealth", + "sSpellmaking", + "sSpellmakingHelp1", + "sSpellmakingHelp2", + "sSpellmakingHelp3", + "sSpellmakingHelp4", + "sSpellmakingHelp5", + "sSpellmakingHelp6", + "sSpellmakingMenu1", + "sSpellmakingMenuTitle", + "sSpells", + "sSpellServiceTitle", + "sSpellsword", + "sStartCell", + "sStartCellError", + "sStartError", + "sStats", + "sStrafe", + "sStrDesc", + "sStrip", + "sSubtitles", + "sSystemMenuXbox", + "sTake", + "sTakeAll", + "sTargetCriticalStrike", + "sTaunt", + "sTauntFail", + "sTauntSuccess", + "sTeleportDisabled", + "sThief", + "sThrust", + "sTo", + "sTogglePOVCmd", + "sTogglePOVXbox", + "sToggleRunXbox", + "sTopics", + "sTotalCost", + "sTotalSold", + "sTraining", + "sTrainingServiceTitle", + "sTraits", + "sTransparency_Menu", + "sTrapFail", + "sTrapImpossible", + "sTrapped", + "sTrapSuccess", + "sTravel", + "sTravelServiceTitle", + "sTurn", + "sTurnLeftXbox", + "sTurnRightXbox", + "sTwoHanded", + "sType", + "sTypeAbility", + "sTypeBlightDisease", + "sTypeCurse", + "sTypeDisease", + "sTypePower", + "sTypeSpell", + "sUnequip", + "sUnlocked", + "sUntilHealed", + "sUse", + "sUserDefinedClass", + "sUses", + "sUseXbox", + "sValue", + "sVideo", + "sVideoWarning", + "sVoice", + "sWait", + "sWarrior", + "sWaterReflectUpdate", + "sWaterTerrainReflect", + "sWeaponTab", + "sWeight", + "sWerewolfAlarmMessage", + "sWerewolfPopup", + "sWerewolfRefusal", + "sWerewolfRestMessage", + "sWilDesc", + "sWitchhunter", + "sWorld", + "sWornTab", + "sXStrafe", + "sXTimes", + "sXTimesINT", + "sYes", + "sYourGold" +}; + +const char * CSMWorld::DefaultGMSTs::OptionalFloats[CSMWorld::DefaultGMSTs::OptionalFloatCount] = +{ + "fCombatDistanceWerewolfMod", + "fFleeDistance", + "fWereWolfAcrobatics", + "fWereWolfAgility", + "fWereWolfAlchemy", + "fWereWolfAlteration", + "fWereWolfArmorer", + "fWereWolfAthletics", + "fWereWolfAxe", + "fWereWolfBlock", + "fWereWolfBluntWeapon", + "fWereWolfConjuration", + "fWereWolfDestruction", + "fWereWolfEnchant", + "fWereWolfEndurance", + "fWereWolfFatigue", + "fWereWolfHandtoHand", + "fWereWolfHealth", + "fWereWolfHeavyArmor", + "fWereWolfIllusion", + "fWereWolfIntellegence", + "fWereWolfLightArmor", + "fWereWolfLongBlade", + "fWereWolfLuck", + "fWereWolfMagicka", + "fWereWolfMarksman", + "fWereWolfMediumArmor", + "fWereWolfMerchantile", + "fWereWolfMysticism", + "fWereWolfPersonality", + "fWereWolfRestoration", + "fWereWolfRunMult", + "fWereWolfSecurity", + "fWereWolfShortBlade", + "fWereWolfSilverWeaponDamageMult", + "fWereWolfSneak", + "fWereWolfSpear", + "fWereWolfSpeechcraft", + "fWereWolfSpeed", + "fWereWolfStrength", + "fWereWolfUnarmored", + "fWereWolfWillPower" +}; + +const char * CSMWorld::DefaultGMSTs::OptionalInts[CSMWorld::DefaultGMSTs::OptionalIntCount] = +{ + "iWereWolfBounty", + "iWereWolfFightMod", + "iWereWolfFleeMod", + "iWereWolfLevelToAttack" +}; + +const char * CSMWorld::DefaultGMSTs::OptionalStrings[CSMWorld::DefaultGMSTs::OptionalStringCount] = +{ + "sCompanionShare", + "sCompanionWarningButtonOne", + "sCompanionWarningButtonTwo", + "sCompanionWarningMessage", + "sDeleteNote", + "sEditNote", + "sEffectSummonCreature01", + "sEffectSummonCreature02", + "sEffectSummonCreature03", + "sEffectSummonCreature04", + "sEffectSummonCreature05", + "sEffectSummonFabricant", + "sLevitateDisabled", + "sMagicCreature01ID", + "sMagicCreature02ID", + "sMagicCreature03ID", + "sMagicCreature04ID", + "sMagicCreature05ID", + "sMagicFabricantID", + "sMaxSale", + "sProfitValue", + "sTeleportDisabled", + "sWerewolfAlarmMessage", + "sWerewolfPopup", + "sWerewolfRefusal", + "sWerewolfRestMessage" +}; + +const float CSMWorld::DefaultGMSTs::FloatsDefaultValues[CSMWorld::DefaultGMSTs::FloatCount] = +{ + 0.3, // fAIFleeFleeMult + 7.0, // fAIFleeHealthMult + 3.0, // fAIMagicSpellMult + 1.0, // fAIMeleeArmorMult + 1.0, // fAIMeleeSummWeaponMult + 2.0, // fAIMeleeWeaponMult + 5.0, // fAIRangeMagicSpellMult + 5.0, // fAIRangeMeleeWeaponMult + 2000.0, // fAlarmRadius + 1.0, // fAthleticsRunBonus + 40.0, // fAudioDefaultMaxDistance + 5.0, // fAudioDefaultMinDistance + 50.0, // fAudioMaxDistanceMult + 20.0, // fAudioMinDistanceMult + 60.0, // fAudioVoiceDefaultMaxDistance + 10.0, // fAudioVoiceDefaultMinDistance + 50.0, // fAutoPCSpellChance + 80.0, // fAutoSpellChance + 50.0, // fBargainOfferBase + -4.0, // fBargainOfferMulti + 24.0, // fBarterGoldResetDelay + 1.75, // fBaseRunMultiplier + 1.25, // fBlockStillBonus + 150.0, // fBribe1000Mod + 75.0, // fBribe100Mod + 35.0, // fBribe10Mod + 60.0, // fCombatAngleXY + 60.0, // fCombatAngleZ + 0.25, // fCombatArmorMinMult + -90.0, // fCombatBlockLeftAngle + 30.0, // fCombatBlockRightAngle + 4.0, // fCombatCriticalStrikeMult + 0.1, // fCombatDelayCreature + 0.1, // fCombatDelayNPC + 128.0, // fCombatDistance + 0.3, // fCombatDistanceWerewolfMod + 30.0, // fCombatForceSideAngle + 0.2, // fCombatInvisoMult + 1.5, // fCombatKODamageMult + 45.0, // fCombatTorsoSideAngle + 0.3, // fCombatTorsoStartPercent + 0.8, // fCombatTorsoStopPercent + 15.0, // fConstantEffectMult + 72.0, // fCorpseClearDelay + 72.0, // fCorpseRespawnDelay + 0.5, // fCrimeGoldDiscountMult + 0.9, // fCrimeGoldTurnInMult + 1.0, // fCrimeStealing + 0.5, // fDamageStrengthBase + 0.1, // fDamageStrengthMult + 5.0, // fDifficultyMult + 2.5, // fDiseaseXferChance + -10.0, // fDispAttacking + -1.0, // fDispBargainFailMod + 1.0, // fDispBargainSuccessMod + 0.0, // fDispCrimeMod + -10.0, // fDispDiseaseMod + 3.0, // fDispFactionMod + 1.0, // fDispFactionRankBase + 0.5, // fDispFactionRankMult + 1.0, // fDispositionMod + 50.0, // fDispPersonalityBase + 0.5, // fDispPersonalityMult + -25.0, // fDispPickPocketMod + 5.0, // fDispRaceMod + -0.5, // fDispStealing + -5.0, // fDispWeaponDrawn + 0.5, // fEffectCostMult + 0.1, // fElementalShieldMult + 3.0, // fEnchantmentChanceMult + 0.5, // fEnchantmentConstantChanceMult + 100.0, // fEnchantmentConstantDurationMult + 0.1, // fEnchantmentMult + 1000.0, // fEnchantmentValueMult + 0.3, // fEncumberedMoveEffect + 5.0, // fEncumbranceStrMult + 0.04, // fEndFatigueMult + 0.25, // fFallAcroBase + 0.01, // fFallAcroMult + 400.0, // fFallDamageDistanceMin + 0.0, // fFallDistanceBase + 0.07, // fFallDistanceMult + 2.0, // fFatigueAttackBase + 0.0, // fFatigueAttackMult + 1.25, // fFatigueBase + 4.0, // fFatigueBlockBase + 0.0, // fFatigueBlockMult + 5.0, // fFatigueJumpBase + 0.0, // fFatigueJumpMult + 0.5, // fFatigueMult + 2.5, // fFatigueReturnBase + 0.02, // fFatigueReturnMult + 5.0, // fFatigueRunBase + 2.0, // fFatigueRunMult + 1.5, // fFatigueSneakBase + 1.5, // fFatigueSneakMult + 0.0, // fFatigueSpellBase + 0.0, // fFatigueSpellCostMult + 0.0, // fFatigueSpellMult + 7.0, // fFatigueSwimRunBase + 0.0, // fFatigueSwimRunMult + 2.5, // fFatigueSwimWalkBase + 0.0, // fFatigueSwimWalkMult + 0.2, // fFightDispMult + 0.005, // fFightDistanceMultiplier + 50.0, // fFightStealing + 3000.0, // fFleeDistance + 512.0, // fGreetDistanceReset + 0.1, // fHandtoHandHealthPer + 1.0, // fHandToHandReach + 0.5, // fHoldBreathEndMult + 20.0, // fHoldBreathTime + 0.75, // fIdleChanceMultiplier + 1.0, // fIngredientMult + 0.5, // fInteriorHeadTrackMult + 128.0, // fJumpAcrobaticsBase + 4.0, // fJumpAcroMultiplier + 0.5, // fJumpEncumbranceBase + 1.0, // fJumpEncumbranceMultiplier + 0.5, // fJumpMoveBase + 0.5, // fJumpMoveMult + 1.0, // fJumpRunMultiplier + 0.5, // fKnockDownMult + 5.0, // fLevelMod + 0.1, // fLevelUpHealthEndMult + 0.6, // fLightMaxMod + 10.0, // fLuckMod + 10.0, // fMagesGuildTravel + 1.5, // fMagicCreatureCastDelay + 0.0167, // fMagicDetectRefreshRate + 1.0, // fMagicItemConstantMult + 1.0, // fMagicItemCostMult + 1.0, // fMagicItemOnceMult + 1.0, // fMagicItemPriceMult + 0.05, // fMagicItemRechargePerSecond + 1.0, // fMagicItemStrikeMult + 1.0, // fMagicItemUsedMult + 3.0, // fMagicStartIconBlink + 0.5, // fMagicSunBlockedMult + 0.75, // fMajorSkillBonus + 300.0, // fMaxFlySpeed + 0.5, // fMaxHandToHandMult + 400.0, // fMaxHeadTrackDistance + 200.0, // fMaxWalkSpeed + 300.0, // fMaxWalkSpeedCreature + 0.9, // fMedMaxMod + 0.1, // fMessageTimePerChar + 5.0, // fMinFlySpeed + 0.1, // fMinHandToHandMult + 1.0, // fMinorSkillBonus + 100.0, // fMinWalkSpeed + 5.0, // fMinWalkSpeedCreature + 1.25, // fMiscSkillBonus + 2.0, // fNPCbaseMagickaMult + 0.5, // fNPCHealthBarFade + 3.0, // fNPCHealthBarTime + 1.0, // fPCbaseMagickaMult + 0.3, // fPerDieRollMult + 5.0, // fPersonalityMod + 1.0, // fPerTempMult + -1.0, // fPickLockMult + 0.3, // fPickPocketMod + 20.0, // fPotionMinUsefulDuration + 0.5, // fPotionStrengthMult + 0.5, // fPotionT1DurMult + 1.5, // fPotionT1MagMult + 20.0, // fPotionT4BaseStrengthMult + 12.0, // fPotionT4EquipStrengthMult + 3000.0, // fProjectileMaxSpeed + 400.0, // fProjectileMinSpeed + 25.0, // fProjectileThrownStoreChance + 3.0, // fRepairAmountMult + 1.0, // fRepairMult + 1.0, // fReputationMod + 0.15, // fRestMagicMult + 0.0, // fSeriousWoundMult + 0.25, // fSleepRandMod + 0.3, // fSleepRestMod + -1.0, // fSneakBootMult + 0.5, // fSneakDistanceBase + 0.002, // fSneakDistanceMultiplier + 0.5, // fSneakNoViewMult + 1.0, // fSneakSkillMult + 0.75, // fSneakSpeedMultiplier + 1.0, // fSneakUseDelay + 500.0, // fSneakUseDist + 1.5, // fSneakViewMult + 3.0, // fSoulGemMult + 0.8, // fSpecialSkillBonus + 7.0, // fSpellMakingValueMult + 2.0, // fSpellPriceMult + 10.0, // fSpellValueMult + 0.25, // fStromWalkMult + 0.7, // fStromWindSpeed + 3.0, // fSuffocationDamage + 0.9, // fSwimHeightScale + 0.1, // fSwimRunAthleticsMult + 0.5, // fSwimRunBase + 0.02, // fSwimWalkAthleticsMult + 0.5, // fSwimWalkBase + 1.0, // fSwingBlockBase + 1.0, // fSwingBlockMult + 1000.0, // fTargetSpellMaxSpeed + 1000.0, // fThrownWeaponMaxSpeed + 300.0, // fThrownWeaponMinSpeed + 0.0, // fTrapCostMult + 4000.0, // fTravelMult + 16000.0,// fTravelTimeMult + 0.1, // fUnarmoredBase1 + 0.065, // fUnarmoredBase2 + 30.0, // fVanityDelay + 10.0, // fVoiceIdleOdds + 0.0, // fWaterReflectUpdateAlways + 10.0, // fWaterReflectUpdateSeldom + 0.1, // fWeaponDamageMult + 1.0, // fWeaponFatigueBlockMult + 0.25, // fWeaponFatigueMult + 150.0, // fWereWolfAcrobatics + 150.0, // fWereWolfAgility + 1.0, // fWereWolfAlchemy + 1.0, // fWereWolfAlteration + 1.0, // fWereWolfArmorer + 150.0, // fWereWolfAthletics + 1.0, // fWereWolfAxe + 1.0, // fWereWolfBlock + 1.0, // fWereWolfBluntWeapon + 1.0, // fWereWolfConjuration + 1.0, // fWereWolfDestruction + 1.0, // fWereWolfEnchant + 150.0, // fWereWolfEndurance + 400.0, // fWereWolfFatigue + 100.0, // fWereWolfHandtoHand + 2.0, // fWereWolfHealth + 1.0, // fWereWolfHeavyArmor + 1.0, // fWereWolfIllusion + 1.0, // fWereWolfIntellegence + 1.0, // fWereWolfLightArmor + 1.0, // fWereWolfLongBlade + 1.0, // fWereWolfLuck + 100.0, // fWereWolfMagicka + 1.0, // fWereWolfMarksman + 1.0, // fWereWolfMediumArmor + 1.0, // fWereWolfMerchantile + 1.0, // fWereWolfMysticism + 1.0, // fWereWolfPersonality + 1.0, // fWereWolfRestoration + 1.5, // fWereWolfRunMult + 1.0, // fWereWolfSecurity + 1.0, // fWereWolfShortBlade + 1.5, // fWereWolfSilverWeaponDamageMult + 1.0, // fWereWolfSneak + 1.0, // fWereWolfSpear + 1.0, // fWereWolfSpeechcraft + 150.0, // fWereWolfSpeed + 150.0, // fWereWolfStrength + 100.0, // fWereWolfUnarmored + 1.0, // fWereWolfWillPower + 15.0 // fWortChanceValue +}; + +const int CSMWorld::DefaultGMSTs::IntsDefaultValues[CSMWorld::DefaultGMSTs::IntCount] = +{ + 10, // i1stPersonSneakDelta + 50, // iAlarmAttack + 90, // iAlarmKilling + 20, // iAlarmPickPocket + 1, // iAlarmStealing + 5, // iAlarmTresspass + 2, // iAlchemyMod + 100, // iAutoPCSpellMax + 2, // iAutoRepFacMod + 0, // iAutoRepLevMod + 5, // iAutoSpellAlterationMax + 70, // iAutoSpellAttSkillMin + 2, // iAutoSpellConjurationMax + 5, // iAutoSpellDestructionMax + 5, // iAutoSpellIllusionMax + 5, // iAutoSpellMysticismMax + 5, // iAutoSpellRestorationMax + 3, // iAutoSpellTimesCanCast + -1, // iBarterFailDisposition + 1, // iBarterSuccessDisposition + 30, // iBaseArmorSkill + 50, // iBlockMaxChance + 10, // iBlockMinChance + 20, // iBootsWeight + 40, // iCrimeAttack + 1000, // iCrimeKilling + 25, // iCrimePickPocket + 1000, // iCrimeThreshold + 10, // iCrimeThresholdMultiplier + 5, // iCrimeTresspass + 30, // iCuirassWeight + 100, // iDaysinPrisonMod + -50, // iDispAttackMod + -50, // iDispKilling + -20, // iDispTresspass + 1, // iFightAlarmMult + 100, // iFightAttack + 50, // iFightAttacking + 20, // iFightDistanceBase + 50, // iFightKilling + 25, // iFightPickpocket + 25, // iFightTrespass + 0, // iFlee + 5, // iGauntletWeight + 15, // iGreavesWeight + 6, // iGreetDistanceMultiplier + 4, // iGreetDuration + 5, // iHelmWeight + 50, // iKnockDownOddsBase + 50, // iKnockDownOddsMult + 2, // iLevelUp01Mult + 2, // iLevelUp02Mult + 2, // iLevelUp03Mult + 2, // iLevelUp04Mult + 3, // iLevelUp05Mult + 3, // iLevelUp06Mult + 3, // iLevelUp07Mult + 4, // iLevelUp08Mult + 4, // iLevelUp09Mult + 5, // iLevelUp10Mult + 1, // iLevelupMajorMult + 1, // iLevelupMajorMultAttribute + 1, // iLevelupMinorMult + 1, // iLevelupMinorMultAttribute + 1, // iLevelupMiscMultAttriubte + 1, // iLevelupSpecialization + 10, // iLevelupTotal + 10, // iMagicItemChargeConst + 1, // iMagicItemChargeOnce + 10, // iMagicItemChargeStrike + 5, // iMagicItemChargeUse + 192, // iMaxActivateDist + 192, // iMaxInfoDist + 4, // iMonthsToRespawn + 1, // iNumberCreatures + 10, // iPauldronWeight + 5, // iPerMinChance + 10, // iPerMinChange + 75, // iPickMaxChance + 5, // iPickMinChance + 15, // iShieldWeight + 400, // iSoulAmountForConstantEffect + 10, // iTrainingMod + 10, // iVoiceAttackOdds + 30, // iVoiceHitOdds + 10000, // iWereWolfBounty + 100, // iWereWolfFightMod + 100, // iWereWolfFleeMod + 20 // iWereWolfLevelToAttack +}; + +const float CSMWorld::DefaultGMSTs::FloatLimits[CSMWorld::DefaultGMSTs::FloatCount * 2] = +{ + -FInf, FInf, // fAIFleeFleeMult + -FInf, FInf, // fAIFleeHealthMult + -FInf, FInf, // fAIMagicSpellMult + -FInf, FInf, // fAIMeleeArmorMult + -FInf, FInf, // fAIMeleeSummWeaponMult + -FInf, FInf, // fAIMeleeWeaponMult + -FInf, FInf, // fAIRangeMagicSpellMult + -FInf, FInf, // fAIRangeMeleeWeaponMult + 0, FInf, // fAlarmRadius + -FInf, FInf, // fAthleticsRunBonus + 0, FInf, // fAudioDefaultMaxDistance + 0, FInf, // fAudioDefaultMinDistance + 0, FInf, // fAudioMaxDistanceMult + 0, FInf, // fAudioMinDistanceMult + 0, FInf, // fAudioVoiceDefaultMaxDistance + 0, FInf, // fAudioVoiceDefaultMinDistance + 0, FInf, // fAutoPCSpellChance + 0, FInf, // fAutoSpellChance + -FInf, FInf, // fBargainOfferBase + -FInf, 0, // fBargainOfferMulti + -FInf, FInf, // fBarterGoldResetDelay + 0, FInf, // fBaseRunMultiplier + -FInf, FInf, // fBlockStillBonus + 0, FInf, // fBribe1000Mod + 0, FInf, // fBribe100Mod + 0, FInf, // fBribe10Mod + 0, FInf, // fCombatAngleXY + 0, FInf, // fCombatAngleZ + 0, 1, // fCombatArmorMinMult + -180, 0, // fCombatBlockLeftAngle + 0, 180, // fCombatBlockRightAngle + 0, FInf, // fCombatCriticalStrikeMult + 0, FInf, // fCombatDelayCreature + 0, FInf, // fCombatDelayNPC + 0, FInf, // fCombatDistance + -FInf, FInf, // fCombatDistanceWerewolfMod + -FInf, FInf, // fCombatForceSideAngle + 0, FInf, // fCombatInvisoMult + 0, FInf, // fCombatKODamageMult + -FInf, FInf, // fCombatTorsoSideAngle + -FInf, FInf, // fCombatTorsoStartPercent + -FInf, FInf, // fCombatTorsoStopPercent + -FInf, FInf, // fConstantEffectMult + -FInf, FInf, // fCorpseClearDelay + -FInf, FInf, // fCorpseRespawnDelay + 0, 1, // fCrimeGoldDiscountMult + 0, FInf, // fCrimeGoldTurnInMult + 0, FInf, // fCrimeStealing + 0, FInf, // fDamageStrengthBase + 0, FInf, // fDamageStrengthMult + -FInf, FInf, // fDifficultyMult + 0, FInf, // fDiseaseXferChance + -FInf, 0, // fDispAttacking + -FInf, FInf, // fDispBargainFailMod + -FInf, FInf, // fDispBargainSuccessMod + -FInf, 0, // fDispCrimeMod + -FInf, 0, // fDispDiseaseMod + 0, FInf, // fDispFactionMod + 0, FInf, // fDispFactionRankBase + 0, FInf, // fDispFactionRankMult + 0, FInf, // fDispositionMod + 0, FInf, // fDispPersonalityBase + 0, FInf, // fDispPersonalityMult + -FInf, 0, // fDispPickPocketMod + 0, FInf, // fDispRaceMod + -FInf, 0, // fDispStealing + -FInf, 0, // fDispWeaponDrawn + 0, FInf, // fEffectCostMult + 0, FInf, // fElementalShieldMult + FEps, FInf, // fEnchantmentChanceMult + 0, FInf, // fEnchantmentConstantChanceMult + 0, FInf, // fEnchantmentConstantDurationMult + 0, FInf, // fEnchantmentMult + 0, FInf, // fEnchantmentValueMult + 0, FInf, // fEncumberedMoveEffect + 0, FInf, // fEncumbranceStrMult + 0, FInf, // fEndFatigueMult + -FInf, FInf, // fFallAcroBase + 0, FInf, // fFallAcroMult + 0, FInf, // fFallDamageDistanceMin + -FInf, FInf, // fFallDistanceBase + 0, FInf, // fFallDistanceMult + -FInf, FInf, // fFatigueAttackBase + 0, FInf, // fFatigueAttackMult + 0, FInf, // fFatigueBase + 0, FInf, // fFatigueBlockBase + 0, FInf, // fFatigueBlockMult + 0, FInf, // fFatigueJumpBase + 0, FInf, // fFatigueJumpMult + 0, FInf, // fFatigueMult + -FInf, FInf, // fFatigueReturnBase + 0, FInf, // fFatigueReturnMult + -FInf, FInf, // fFatigueRunBase + 0, FInf, // fFatigueRunMult + -FInf, FInf, // fFatigueSneakBase + 0, FInf, // fFatigueSneakMult + -FInf, FInf, // fFatigueSpellBase + -FInf, FInf, // fFatigueSpellCostMult + 0, FInf, // fFatigueSpellMult + -FInf, FInf, // fFatigueSwimRunBase + 0, FInf, // fFatigueSwimRunMult + -FInf, FInf, // fFatigueSwimWalkBase + 0, FInf, // fFatigueSwimWalkMult + -FInf, FInf, // fFightDispMult + -FInf, FInf, // fFightDistanceMultiplier + -FInf, FInf, // fFightStealing + -FInf, FInf, // fFleeDistance + -FInf, FInf, // fGreetDistanceReset + 0, FInf, // fHandtoHandHealthPer + 0, FInf, // fHandToHandReach + -FInf, FInf, // fHoldBreathEndMult + 0, FInf, // fHoldBreathTime + 0, FInf, // fIdleChanceMultiplier + -FInf, FInf, // fIngredientMult + 0, FInf, // fInteriorHeadTrackMult + -FInf, FInf, // fJumpAcrobaticsBase + 0, FInf, // fJumpAcroMultiplier + -FInf, FInf, // fJumpEncumbranceBase + 0, FInf, // fJumpEncumbranceMultiplier + -FInf, FInf, // fJumpMoveBase + 0, FInf, // fJumpMoveMult + 0, FInf, // fJumpRunMultiplier + -FInf, FInf, // fKnockDownMult + 0, FInf, // fLevelMod + 0, FInf, // fLevelUpHealthEndMult + 0, FInf, // fLightMaxMod + 0, FInf, // fLuckMod + 0, FInf, // fMagesGuildTravel + -FInf, FInf, // fMagicCreatureCastDelay + -FInf, FInf, // fMagicDetectRefreshRate + -FInf, FInf, // fMagicItemConstantMult + -FInf, FInf, // fMagicItemCostMult + -FInf, FInf, // fMagicItemOnceMult + -FInf, FInf, // fMagicItemPriceMult + 0, FInf, // fMagicItemRechargePerSecond + -FInf, FInf, // fMagicItemStrikeMult + -FInf, FInf, // fMagicItemUsedMult + 0, FInf, // fMagicStartIconBlink + 0, FInf, // fMagicSunBlockedMult + FEps, FInf, // fMajorSkillBonus + 0, FInf, // fMaxFlySpeed + 0, FInf, // fMaxHandToHandMult + 0, FInf, // fMaxHeadTrackDistance + 0, FInf, // fMaxWalkSpeed + 0, FInf, // fMaxWalkSpeedCreature + 0, FInf, // fMedMaxMod + 0, FInf, // fMessageTimePerChar + 0, FInf, // fMinFlySpeed + 0, FInf, // fMinHandToHandMult + FEps, FInf, // fMinorSkillBonus + 0, FInf, // fMinWalkSpeed + 0, FInf, // fMinWalkSpeedCreature + FEps, FInf, // fMiscSkillBonus + 0, FInf, // fNPCbaseMagickaMult + 0, FInf, // fNPCHealthBarFade + 0, FInf, // fNPCHealthBarTime + 0, FInf, // fPCbaseMagickaMult + 0, FInf, // fPerDieRollMult + 0, FInf, // fPersonalityMod + 0, FInf, // fPerTempMult + -FInf, 0, // fPickLockMult + 0, FInf, // fPickPocketMod + -FInf, FInf, // fPotionMinUsefulDuration + 0, FInf, // fPotionStrengthMult + FEps, FInf, // fPotionT1DurMult + FEps, FInf, // fPotionT1MagMult + -FInf, FInf, // fPotionT4BaseStrengthMult + -FInf, FInf, // fPotionT4EquipStrengthMult + 0, FInf, // fProjectileMaxSpeed + 0, FInf, // fProjectileMinSpeed + 0, FInf, // fProjectileThrownStoreChance + 0, FInf, // fRepairAmountMult + 0, FInf, // fRepairMult + 0, FInf, // fReputationMod + 0, FInf, // fRestMagicMult + -FInf, FInf, // fSeriousWoundMult + 0, FInf, // fSleepRandMod + 0, FInf, // fSleepRestMod + -FInf, 0, // fSneakBootMult + -FInf, FInf, // fSneakDistanceBase + 0, FInf, // fSneakDistanceMultiplier + 0, FInf, // fSneakNoViewMult + 0, FInf, // fSneakSkillMult + 0, FInf, // fSneakSpeedMultiplier + 0, FInf, // fSneakUseDelay + 0, FInf, // fSneakUseDist + 0, FInf, // fSneakViewMult + 0, FInf, // fSoulGemMult + 0, FInf, // fSpecialSkillBonus + 0, FInf, // fSpellMakingValueMult + -FInf, FInf, // fSpellPriceMult + 0, FInf, // fSpellValueMult + 0, FInf, // fStromWalkMult + 0, FInf, // fStromWindSpeed + 0, FInf, // fSuffocationDamage + 0, FInf, // fSwimHeightScale + 0, FInf, // fSwimRunAthleticsMult + 0, FInf, // fSwimRunBase + -FInf, FInf, // fSwimWalkAthleticsMult + -FInf, FInf, // fSwimWalkBase + 0, FInf, // fSwingBlockBase + 0, FInf, // fSwingBlockMult + 0, FInf, // fTargetSpellMaxSpeed + 0, FInf, // fThrownWeaponMaxSpeed + 0, FInf, // fThrownWeaponMinSpeed + 0, FInf, // fTrapCostMult + 0, FInf, // fTravelMult + 0, FInf, // fTravelTimeMult + 0, FInf, // fUnarmoredBase1 + 0, FInf, // fUnarmoredBase2 + 0, FInf, // fVanityDelay + 0, FInf, // fVoiceIdleOdds + -FInf, FInf, // fWaterReflectUpdateAlways + -FInf, FInf, // fWaterReflectUpdateSeldom + 0, FInf, // fWeaponDamageMult + 0, FInf, // fWeaponFatigueBlockMult + 0, FInf, // fWeaponFatigueMult + 0, FInf, // fWereWolfAcrobatics + -FInf, FInf, // fWereWolfAgility + -FInf, FInf, // fWereWolfAlchemy + -FInf, FInf, // fWereWolfAlteration + -FInf, FInf, // fWereWolfArmorer + -FInf, FInf, // fWereWolfAthletics + -FInf, FInf, // fWereWolfAxe + -FInf, FInf, // fWereWolfBlock + -FInf, FInf, // fWereWolfBluntWeapon + -FInf, FInf, // fWereWolfConjuration + -FInf, FInf, // fWereWolfDestruction + -FInf, FInf, // fWereWolfEnchant + -FInf, FInf, // fWereWolfEndurance + -FInf, FInf, // fWereWolfFatigue + -FInf, FInf, // fWereWolfHandtoHand + -FInf, FInf, // fWereWolfHealth + -FInf, FInf, // fWereWolfHeavyArmor + -FInf, FInf, // fWereWolfIllusion + -FInf, FInf, // fWereWolfIntellegence + -FInf, FInf, // fWereWolfLightArmor + -FInf, FInf, // fWereWolfLongBlade + -FInf, FInf, // fWereWolfLuck + -FInf, FInf, // fWereWolfMagicka + -FInf, FInf, // fWereWolfMarksman + -FInf, FInf, // fWereWolfMediumArmor + -FInf, FInf, // fWereWolfMerchantile + -FInf, FInf, // fWereWolfMysticism + -FInf, FInf, // fWereWolfPersonality + -FInf, FInf, // fWereWolfRestoration + 0, FInf, // fWereWolfRunMult + -FInf, FInf, // fWereWolfSecurity + -FInf, FInf, // fWereWolfShortBlade + -FInf, FInf, // fWereWolfSilverWeaponDamageMult + -FInf, FInf, // fWereWolfSneak + -FInf, FInf, // fWereWolfSpear + -FInf, FInf, // fWereWolfSpeechcraft + -FInf, FInf, // fWereWolfSpeed + -FInf, FInf, // fWereWolfStrength + -FInf, FInf, // fWereWolfUnarmored + -FInf, FInf, // fWereWolfWillPower + 0, FInf // fWortChanceValue +}; + +const int CSMWorld::DefaultGMSTs::IntLimits[CSMWorld::DefaultGMSTs::IntCount * 2] = +{ + IMin, IMax, // i1stPersonSneakDelta + IMin, IMax, // iAlarmAttack + IMin, IMax, // iAlarmKilling + IMin, IMax, // iAlarmPickPocket + IMin, IMax, // iAlarmStealing + IMin, IMax, // iAlarmTresspass + IMin, IMax, // iAlchemyMod + 0, IMax, // iAutoPCSpellMax + IMin, IMax, // iAutoRepFacMod + IMin, IMax, // iAutoRepLevMod + IMin, IMax, // iAutoSpellAlterationMax + 0, IMax, // iAutoSpellAttSkillMin + IMin, IMax, // iAutoSpellConjurationMax + IMin, IMax, // iAutoSpellDestructionMax + IMin, IMax, // iAutoSpellIllusionMax + IMin, IMax, // iAutoSpellMysticismMax + IMin, IMax, // iAutoSpellRestorationMax + 0, IMax, // iAutoSpellTimesCanCast + IMin, 0, // iBarterFailDisposition + 0, IMax, // iBarterSuccessDisposition + 1, IMax, // iBaseArmorSkill + 0, IMax, // iBlockMaxChance + 0, IMax, // iBlockMinChance + 0, IMax, // iBootsWeight + IMin, IMax, // iCrimeAttack + IMin, IMax, // iCrimeKilling + IMin, IMax, // iCrimePickPocket + 0, IMax, // iCrimeThreshold + 0, IMax, // iCrimeThresholdMultiplier + IMin, IMax, // iCrimeTresspass + 0, IMax, // iCuirassWeight + 1, IMax, // iDaysinPrisonMod + IMin, 0, // iDispAttackMod + IMin, 0, // iDispKilling + IMin, 0, // iDispTresspass + IMin, IMax, // iFightAlarmMult + IMin, IMax, // iFightAttack + IMin, IMax, // iFightAttacking + 0, IMax, // iFightDistanceBase + IMin, IMax, // iFightKilling + IMin, IMax, // iFightPickpocket + IMin, IMax, // iFightTrespass + IMin, IMax, // iFlee + 0, IMax, // iGauntletWeight + 0, IMax, // iGreavesWeight + 0, IMax, // iGreetDistanceMultiplier + 0, IMax, // iGreetDuration + 0, IMax, // iHelmWeight + IMin, IMax, // iKnockDownOddsBase + IMin, IMax, // iKnockDownOddsMult + IMin, IMax, // iLevelUp01Mult + IMin, IMax, // iLevelUp02Mult + IMin, IMax, // iLevelUp03Mult + IMin, IMax, // iLevelUp04Mult + IMin, IMax, // iLevelUp05Mult + IMin, IMax, // iLevelUp06Mult + IMin, IMax, // iLevelUp07Mult + IMin, IMax, // iLevelUp08Mult + IMin, IMax, // iLevelUp09Mult + IMin, IMax, // iLevelUp10Mult + IMin, IMax, // iLevelupMajorMult + IMin, IMax, // iLevelupMajorMultAttribute + IMin, IMax, // iLevelupMinorMult + IMin, IMax, // iLevelupMinorMultAttribute + IMin, IMax, // iLevelupMiscMultAttriubte + IMin, IMax, // iLevelupSpecialization + IMin, IMax, // iLevelupTotal + IMin, IMax, // iMagicItemChargeConst + IMin, IMax, // iMagicItemChargeOnce + IMin, IMax, // iMagicItemChargeStrike + IMin, IMax, // iMagicItemChargeUse + IMin, IMax, // iMaxActivateDist + IMin, IMax, // iMaxInfoDist + 0, IMax, // iMonthsToRespawn + 0, IMax, // iNumberCreatures + 0, IMax, // iPauldronWeight + 0, IMax, // iPerMinChance + 0, IMax, // iPerMinChange + 0, IMax, // iPickMaxChance + 0, IMax, // iPickMinChance + 0, IMax, // iShieldWeight + 0, IMax, // iSoulAmountForConstantEffect + 0, IMax, // iTrainingMod + 0, IMax, // iVoiceAttackOdds + 0, IMax, // iVoiceHitOdds + IMin, IMax, // iWereWolfBounty + IMin, IMax, // iWereWolfFightMod + IMin, IMax, // iWereWolfFleeMod + IMin, IMax // iWereWolfLevelToAttack +}; diff --git a/apps/opencs/model/world/defaultgmsts.hpp b/apps/opencs/model/world/defaultgmsts.hpp new file mode 100644 index 000000000..ba65be805 --- /dev/null +++ b/apps/opencs/model/world/defaultgmsts.hpp @@ -0,0 +1,34 @@ +#ifndef CSM_WORLD_DEFAULTGMSTS_H +#define CSM_WORLD_DEFAULTGMSTS_H + +#include + +namespace CSMWorld { + namespace DefaultGMSTs { + + const size_t FloatCount = 258; + const size_t IntCount = 89; + const size_t StringCount = 1174; + + const size_t OptionalFloatCount = 42; + const size_t OptionalIntCount = 4; + const size_t OptionalStringCount = 26; + + extern const char* Floats[]; + extern const char * Ints[]; + extern const char * Strings[]; + + extern const char * OptionalFloats[]; + extern const char * OptionalInts[]; + extern const char * OptionalStrings[]; + + extern const float FloatsDefaultValues[]; + extern const int IntsDefaultValues[]; + + extern const float FloatLimits[]; + extern const int IntLimits[]; + + } +} + +#endif From bbda5fe634aafc3104a47ee02d0f0bc236274cba Mon Sep 17 00:00:00 2001 From: Aesylwinn Date: Mon, 18 Jan 2016 12:34:33 -0500 Subject: [PATCH 3006/3725] Removed hints from error messages and fixed naming to match conventions --- apps/opencs/model/doc/document.cpp | 28 ++++----- apps/opencs/model/tools/gmstcheck.cpp | 78 +++++++++++++++++------- apps/opencs/model/tools/gmstcheck.hpp | 6 +- apps/opencs/model/tools/tools.cpp | 2 +- apps/opencs/model/world/defaultgmsts.cpp | 20 +++--- apps/opencs/model/world/defaultgmsts.hpp | 2 +- 6 files changed, 85 insertions(+), 51 deletions(-) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index ea1fbb330..19891363f 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -14,28 +14,28 @@ void CSMDoc::Document::addGmsts() { - for (size_t i=0; i < CSMWorld::DefaultGMSTs::FloatCount; ++i) + for (size_t i=0; i < CSMWorld::DefaultGmsts::FloatCount; ++i) { ESM::GameSetting gmst; - gmst.mId = CSMWorld::DefaultGMSTs::Floats[i]; + gmst.mId = CSMWorld::DefaultGmsts::Floats[i]; gmst.mValue.setType (ESM::VT_Float); - gmst.mValue.setFloat (CSMWorld::DefaultGMSTs::FloatsDefaultValues[i]); + gmst.mValue.setFloat (CSMWorld::DefaultGmsts::FloatsDefaultValues[i]); getData().getGmsts().add (gmst); } - for (size_t i=0; i < CSMWorld::DefaultGMSTs::IntCount; ++i) + for (size_t i=0; i < CSMWorld::DefaultGmsts::IntCount; ++i) { ESM::GameSetting gmst; - gmst.mId = CSMWorld::DefaultGMSTs::Ints[i]; + gmst.mId = CSMWorld::DefaultGmsts::Ints[i]; gmst.mValue.setType (ESM::VT_Int); - gmst.mValue.setInteger (CSMWorld::DefaultGMSTs::IntsDefaultValues[i]); + gmst.mValue.setInteger (CSMWorld::DefaultGmsts::IntsDefaultValues[i]); getData().getGmsts().add (gmst); } - for (size_t i=0; i < CSMWorld::DefaultGMSTs::StringCount; ++i) + for (size_t i=0; i < CSMWorld::DefaultGmsts::StringCount; ++i) { ESM::GameSetting gmst; - gmst.mId = CSMWorld::DefaultGMSTs::Strings[i]; + gmst.mId = CSMWorld::DefaultGmsts::Strings[i]; gmst.mValue.setType (ESM::VT_String); gmst.mValue.setString (""); getData().getGmsts().add (gmst); @@ -44,28 +44,28 @@ void CSMDoc::Document::addGmsts() void CSMDoc::Document::addOptionalGmsts() { - for (size_t i=0; i < CSMWorld::DefaultGMSTs::OptionalFloatCount; ++i) + for (size_t i=0; i < CSMWorld::DefaultGmsts::OptionalFloatCount; ++i) { ESM::GameSetting gmst; - gmst.mId = CSMWorld::DefaultGMSTs::OptionalFloats[i]; + gmst.mId = CSMWorld::DefaultGmsts::OptionalFloats[i]; gmst.blank(); gmst.mValue.setType (ESM::VT_Float); addOptionalGmst (gmst); } - for (size_t i=0; i < CSMWorld::DefaultGMSTs::OptionalIntCount; ++i) + for (size_t i=0; i < CSMWorld::DefaultGmsts::OptionalIntCount; ++i) { ESM::GameSetting gmst; - gmst.mId = CSMWorld::DefaultGMSTs::OptionalInts[i]; + gmst.mId = CSMWorld::DefaultGmsts::OptionalInts[i]; gmst.blank(); gmst.mValue.setType (ESM::VT_Int); addOptionalGmst (gmst); } - for (size_t i=0; i < CSMWorld::DefaultGMSTs::OptionalStringCount; ++i) + for (size_t i=0; i < CSMWorld::DefaultGmsts::OptionalStringCount; ++i) { ESM::GameSetting gmst; - gmst.mId = CSMWorld::DefaultGMSTs::OptionalStrings[i]; + gmst.mId = CSMWorld::DefaultGmsts::OptionalStrings[i]; gmst.blank(); gmst.mValue.setType (ESM::VT_String); gmst.mValue.setString (""); diff --git a/apps/opencs/model/tools/gmstcheck.cpp b/apps/opencs/model/tools/gmstcheck.cpp index 6c17ff3a5..0c32c0056 100644 --- a/apps/opencs/model/tools/gmstcheck.cpp +++ b/apps/opencs/model/tools/gmstcheck.cpp @@ -1,17 +1,19 @@ #include "gmstcheck.hpp" +#include + #include "../world/defaultgmsts.hpp" -CSMTools::GMSTCheckStage::GMSTCheckStage(const CSMWorld::IdCollection& gameSettings) +CSMTools::GmstCheckStage::GmstCheckStage(const CSMWorld::IdCollection& gameSettings) : mGameSettings(gameSettings) {} -int CSMTools::GMSTCheckStage::setup() +int CSMTools::GmstCheckStage::setup() { return mGameSettings.getSize(); } -void CSMTools::GMSTCheckStage::perform(int stage, CSMDoc::Messages& messages) +void CSMTools::GmstCheckStage::perform(int stage, CSMDoc::Messages& messages) { const CSMWorld::Record& record = mGameSettings.getRecord (stage); @@ -30,20 +32,25 @@ void CSMTools::GMSTCheckStage::perform(int stage, CSMDoc::Messages& messages) // optimization - compare it to lists based on naming convention (f-float,i-int,s-string) if (gmst.mId[0] == 'f') { - for (size_t i = 0; i < CSMWorld::DefaultGMSTs::FloatCount; ++i) + for (size_t i = 0; i < CSMWorld::DefaultGmsts::FloatCount; ++i) { - if (gmst.mId == CSMWorld::DefaultGMSTs::Floats[i]) + if (gmst.mId == CSMWorld::DefaultGmsts::Floats[i]) { if (gmst.mValue.getType() != ESM::VT_Float) - messages.add(id, "The type of " + gmst.mId + " is incorrect", - "Change the GMST type to a float", CSMDoc::Message::Severity_Error); + { + std::ostringstream stream; + stream << "Expected float type for " << gmst.mId << " but found " + << varTypeToString(gmst.mValue.getType()) << " type"; + + messages.add(id, stream.str(), "", CSMDoc::Message::Severity_Error); + } - if (gmst.mValue.getFloat() < CSMWorld::DefaultGMSTs::FloatLimits[i*2]) - messages.add(id, gmst.mId + " is less than the suggested range", "Change the value", + if (gmst.mValue.getFloat() < CSMWorld::DefaultGmsts::FloatLimits[i*2]) + messages.add(id, gmst.mId + " is less than the suggested range", "", CSMDoc::Message::Severity_Warning); - if (gmst.mValue.getFloat() > CSMWorld::DefaultGMSTs::FloatLimits[i*2+1]) - messages.add(id, gmst.mId + " is more than the suggested range", "Change the value", + if (gmst.mValue.getFloat() > CSMWorld::DefaultGmsts::FloatLimits[i*2+1]) + messages.add(id, gmst.mId + " is more than the suggested range", "", CSMDoc::Message::Severity_Warning); break; // for loop @@ -52,20 +59,25 @@ void CSMTools::GMSTCheckStage::perform(int stage, CSMDoc::Messages& messages) } else if (gmst.mId[0] == 'i') { - for (size_t i = 0; i < CSMWorld::DefaultGMSTs::IntCount; ++i) + for (size_t i = 0; i < CSMWorld::DefaultGmsts::IntCount; ++i) { - if (gmst.mId == CSMWorld::DefaultGMSTs::Ints[i]) + if (gmst.mId == CSMWorld::DefaultGmsts::Ints[i]) { if (gmst.mValue.getType() != ESM::VT_Int) - messages.add(id, "The type of " + gmst.mId + " is incorrect", - "Change the GMST type to an int", CSMDoc::Message::Severity_Error); + { + std::ostringstream stream; + stream << "Expected int type for " << gmst.mId << " but found " + << varTypeToString(gmst.mValue.getType()) << " type"; + + messages.add(id, stream.str(), "", CSMDoc::Message::Severity_Error); + } - if (gmst.mValue.getInteger() < CSMWorld::DefaultGMSTs::IntLimits[i*2]) - messages.add(id, gmst.mId + " is less than the suggested range", "Change the value", + if (gmst.mValue.getInteger() < CSMWorld::DefaultGmsts::IntLimits[i*2]) + messages.add(id, gmst.mId + " is less than the suggested range", "", CSMDoc::Message::Severity_Warning); - if (gmst.mValue.getInteger() > CSMWorld::DefaultGMSTs::IntLimits[i*2+1]) - messages.add(id, gmst.mId + " is more than the suggested range", "Change the value", + if (gmst.mValue.getInteger() > CSMWorld::DefaultGmsts::IntLimits[i*2+1]) + messages.add(id, gmst.mId + " is more than the suggested range", "", CSMDoc::Message::Severity_Warning); break; // for loop @@ -74,18 +86,38 @@ void CSMTools::GMSTCheckStage::perform(int stage, CSMDoc::Messages& messages) } else if (gmst.mId[0] == 's') { - for (size_t i = 0; i < CSMWorld::DefaultGMSTs::StringCount; ++i) + for (size_t i = 0; i < CSMWorld::DefaultGmsts::StringCount; ++i) { - if (gmst.mId == CSMWorld::DefaultGMSTs::Strings[i]) + if (gmst.mId == CSMWorld::DefaultGmsts::Strings[i]) { ESM::VarType type = gmst.mValue.getType(); if (type != ESM::VT_String && type != ESM::VT_None) - messages.add(id, "The type of " + gmst.mId + " is incorrect", - "Change the GMST type to a string", CSMDoc::Message::Severity_Error); + { + std::ostringstream stream; + stream << "Expected string or none type for " << gmst.mId << " but found " + << varTypeToString(gmst.mValue.getType()) << " type"; + + messages.add(id, stream.str(), "", CSMDoc::Message::Severity_Error); + } break; // for loop } } } } + +std::string CSMTools::GmstCheckStage::varTypeToString(ESM::VarType type) +{ + switch (type) + { + case ESM::VT_Unknown: return "unknown"; + case ESM::VT_None: return "none"; + case ESM::VT_Short: return "short"; + case ESM::VT_Int: return "int"; + case ESM::VT_Long: return "long"; + case ESM::VT_Float: return "float"; + case ESM::VT_String: return "string"; + default: return "unhandled"; + } +} diff --git a/apps/opencs/model/tools/gmstcheck.hpp b/apps/opencs/model/tools/gmstcheck.hpp index ca1564d9e..0d4f7f204 100644 --- a/apps/opencs/model/tools/gmstcheck.hpp +++ b/apps/opencs/model/tools/gmstcheck.hpp @@ -10,11 +10,11 @@ namespace CSMTools { /// \brief VerifyStage: make sure that GMSTs are alright - class GMSTCheckStage : public CSMDoc::Stage + class GmstCheckStage : public CSMDoc::Stage { public: - GMSTCheckStage(const CSMWorld::IdCollection& gameSettings); + GmstCheckStage(const CSMWorld::IdCollection& gameSettings); virtual int setup(); ///< \return number of steps @@ -26,6 +26,8 @@ namespace CSMTools const CSMWorld::IdCollection& mGameSettings; + std::string varTypeToString(ESM::VarType); + }; } diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index 9f36193ef..e750092b9 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -112,7 +112,7 @@ CSMDoc::OperationHolder *CSMTools::Tools::getVerifier() mData.getResources (CSMWorld::UniversalId::Type_Icons), mData.getResources (CSMWorld::UniversalId::Type_Textures))); - mVerifierOperation->appendStage (new GMSTCheckStage (mData.getGmsts())); + mVerifierOperation->appendStage (new GmstCheckStage (mData.getGmsts())); mVerifier.setOperation (mVerifierOperation); } diff --git a/apps/opencs/model/world/defaultgmsts.cpp b/apps/opencs/model/world/defaultgmsts.cpp index ef3d536b1..f44e98411 100644 --- a/apps/opencs/model/world/defaultgmsts.cpp +++ b/apps/opencs/model/world/defaultgmsts.cpp @@ -8,7 +8,7 @@ const float FEps = std::numeric_limits::epsilon(); const int IMax = std::numeric_limits::max(); const int IMin = std::numeric_limits::min(); -const char* CSMWorld::DefaultGMSTs::Floats[CSMWorld::DefaultGMSTs::FloatCount] = +const char* CSMWorld::DefaultGmsts::Floats[CSMWorld::DefaultGmsts::FloatCount] = { "fAIFleeFleeMult", "fAIFleeHealthMult", @@ -270,7 +270,7 @@ const char* CSMWorld::DefaultGMSTs::Floats[CSMWorld::DefaultGMSTs::FloatCount] = "fWortChanceValue" }; -const char * CSMWorld::DefaultGMSTs::Ints[CSMWorld::DefaultGMSTs::IntCount] = +const char * CSMWorld::DefaultGmsts::Ints[CSMWorld::DefaultGmsts::IntCount] = { "i1stPersonSneakDelta", "iAlarmAttack", @@ -363,7 +363,7 @@ const char * CSMWorld::DefaultGMSTs::Ints[CSMWorld::DefaultGMSTs::IntCount] = "iWereWolfLevelToAttack" }; -const char * CSMWorld::DefaultGMSTs::Strings[CSMWorld::DefaultGMSTs::StringCount] = +const char * CSMWorld::DefaultGmsts::Strings[CSMWorld::DefaultGmsts::StringCount] = { "s3dAudio", "s3dHardware", @@ -1541,7 +1541,7 @@ const char * CSMWorld::DefaultGMSTs::Strings[CSMWorld::DefaultGMSTs::StringCount "sYourGold" }; -const char * CSMWorld::DefaultGMSTs::OptionalFloats[CSMWorld::DefaultGMSTs::OptionalFloatCount] = +const char * CSMWorld::DefaultGmsts::OptionalFloats[CSMWorld::DefaultGmsts::OptionalFloatCount] = { "fCombatDistanceWerewolfMod", "fFleeDistance", @@ -1587,7 +1587,7 @@ const char * CSMWorld::DefaultGMSTs::OptionalFloats[CSMWorld::DefaultGMSTs::Opti "fWereWolfWillPower" }; -const char * CSMWorld::DefaultGMSTs::OptionalInts[CSMWorld::DefaultGMSTs::OptionalIntCount] = +const char * CSMWorld::DefaultGmsts::OptionalInts[CSMWorld::DefaultGmsts::OptionalIntCount] = { "iWereWolfBounty", "iWereWolfFightMod", @@ -1595,7 +1595,7 @@ const char * CSMWorld::DefaultGMSTs::OptionalInts[CSMWorld::DefaultGMSTs::Option "iWereWolfLevelToAttack" }; -const char * CSMWorld::DefaultGMSTs::OptionalStrings[CSMWorld::DefaultGMSTs::OptionalStringCount] = +const char * CSMWorld::DefaultGmsts::OptionalStrings[CSMWorld::DefaultGmsts::OptionalStringCount] = { "sCompanionShare", "sCompanionWarningButtonOne", @@ -1625,7 +1625,7 @@ const char * CSMWorld::DefaultGMSTs::OptionalStrings[CSMWorld::DefaultGMSTs::Opt "sWerewolfRestMessage" }; -const float CSMWorld::DefaultGMSTs::FloatsDefaultValues[CSMWorld::DefaultGMSTs::FloatCount] = +const float CSMWorld::DefaultGmsts::FloatsDefaultValues[CSMWorld::DefaultGmsts::FloatCount] = { 0.3, // fAIFleeFleeMult 7.0, // fAIFleeHealthMult @@ -1887,7 +1887,7 @@ const float CSMWorld::DefaultGMSTs::FloatsDefaultValues[CSMWorld::DefaultGMSTs:: 15.0 // fWortChanceValue }; -const int CSMWorld::DefaultGMSTs::IntsDefaultValues[CSMWorld::DefaultGMSTs::IntCount] = +const int CSMWorld::DefaultGmsts::IntsDefaultValues[CSMWorld::DefaultGmsts::IntCount] = { 10, // i1stPersonSneakDelta 50, // iAlarmAttack @@ -1980,7 +1980,7 @@ const int CSMWorld::DefaultGMSTs::IntsDefaultValues[CSMWorld::DefaultGMSTs::IntC 20 // iWereWolfLevelToAttack }; -const float CSMWorld::DefaultGMSTs::FloatLimits[CSMWorld::DefaultGMSTs::FloatCount * 2] = +const float CSMWorld::DefaultGmsts::FloatLimits[CSMWorld::DefaultGmsts::FloatCount * 2] = { -FInf, FInf, // fAIFleeFleeMult -FInf, FInf, // fAIFleeHealthMult @@ -2242,7 +2242,7 @@ const float CSMWorld::DefaultGMSTs::FloatLimits[CSMWorld::DefaultGMSTs::FloatCou 0, FInf // fWortChanceValue }; -const int CSMWorld::DefaultGMSTs::IntLimits[CSMWorld::DefaultGMSTs::IntCount * 2] = +const int CSMWorld::DefaultGmsts::IntLimits[CSMWorld::DefaultGmsts::IntCount * 2] = { IMin, IMax, // i1stPersonSneakDelta IMin, IMax, // iAlarmAttack diff --git a/apps/opencs/model/world/defaultgmsts.hpp b/apps/opencs/model/world/defaultgmsts.hpp index ba65be805..a2888ed6a 100644 --- a/apps/opencs/model/world/defaultgmsts.hpp +++ b/apps/opencs/model/world/defaultgmsts.hpp @@ -4,7 +4,7 @@ #include namespace CSMWorld { - namespace DefaultGMSTs { + namespace DefaultGmsts { const size_t FloatCount = 258; const size_t IntCount = 89; From c82d9a1e873feae70a845feae26b6cbb5572de79 Mon Sep 17 00:00:00 2001 From: Jordan Ayers Date: Mon, 18 Jan 2016 19:56:35 -0600 Subject: [PATCH 3007/3725] Adjust ContainerStore / InventoryStore to allow partial unequip of items. --- apps/openmw/mwworld/containerstore.cpp | 12 +++++++----- apps/openmw/mwworld/containerstore.hpp | 6 ++++-- apps/openmw/mwworld/inventorystore.cpp | 27 ++++++++++++++++++++++++++ apps/openmw/mwworld/inventorystore.hpp | 9 +++++++++ 4 files changed, 47 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 45390405e..e07ba433a 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -136,16 +136,18 @@ int MWWorld::ContainerStore::count(const std::string &id) return total; } -void MWWorld::ContainerStore::unstack(const Ptr &ptr, const Ptr& container) +MWWorld::ContainerStoreIterator MWWorld::ContainerStore::unstack(const Ptr &ptr, const Ptr& container, int count) { - if (ptr.getRefData().getCount() <= 1) - return; - MWWorld::ContainerStoreIterator it = addNewStack(ptr, ptr.getRefData().getCount()-1); + if (ptr.getRefData().getCount() <= count) + return end(); + MWWorld::ContainerStoreIterator it = addNewStack(ptr, ptr.getRefData().getCount()-count); const std::string script = it->getClass().getScript(*it); if (!script.empty()) MWBase::Environment::get().getWorld()->getLocalScripts().add(script, *it); - remove(ptr, ptr.getRefData().getCount()-1, container); + remove(ptr, ptr.getRefData().getCount()-count, container); + + return it; } MWWorld::ContainerStoreIterator MWWorld::ContainerStore::restack(const MWWorld::Ptr& item) diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index b7ec4bb74..6a8fc4761 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -130,8 +130,10 @@ namespace MWWorld /// /// @return the number of items actually removed - void unstack (const Ptr& ptr, const Ptr& container); - ///< Unstack an item in this container. The item's count will be set to 1, then a new stack will be added with (origCount-1). + ContainerStoreIterator unstack (const Ptr& ptr, const Ptr& container, int count = 1); + ///< Unstack an item in this container. The item's count will be set to count, then a new stack will be added with (origCount-count). + /// + /// @return an iterator to the new stack, or end() if no new stack was created. MWWorld::ContainerStoreIterator restack (const MWWorld::Ptr& item); ///< Attempt to re-stack an item in this container. diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index dbd2c6794..2c994f146 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -574,6 +574,33 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::unequipItem(const MWWor throw std::runtime_error ("attempt to unequip an item that is not currently equipped"); } +MWWorld::ContainerStoreIterator MWWorld::InventoryStore::unequipItemQuantity(const Ptr& item, const Ptr& actor, int count) +{ + if (!isEquipped(item)) + throw std::runtime_error ("attempt to unequip an item that is not currently equipped"); + if (count <= 0) + throw std::runtime_error ("attempt to unequip nothing (count <= 0)"); + if (count > item.getRefData().getCount()) + throw std::runtime_error ("attempt to unequip more items than equipped"); + + if (count == item.getRefData().getCount()) + return unequipItem(item, actor); + + // Move items to an existing stack if possible, otherwise split count items out into a new stack. + // Moving counts manually here, since ContainerStore's restack can't target unequipped stacks. + for (MWWorld::ContainerStoreIterator iter (begin()); iter != end(); ++iter) + { + if (stacks(*iter, item) && !isEquipped(*iter)) + { + iter->getRefData().setCount(iter->getRefData().getCount() + count); + item.getRefData().setCount(item.getRefData().getCount() - count); + return iter; + } + } + + return unstack(item, actor, item.getRefData().getCount() - count); +} + MWWorld::InventoryStoreListener* MWWorld::InventoryStore::getListener() { return mListener; diff --git a/apps/openmw/mwworld/inventorystore.hpp b/apps/openmw/mwworld/inventorystore.hpp index 28c44bcec..2d7c9f6e9 100644 --- a/apps/openmw/mwworld/inventorystore.hpp +++ b/apps/openmw/mwworld/inventorystore.hpp @@ -188,6 +188,15 @@ namespace MWWorld /// (it can be re-stacked so its count may be different than when it /// was equipped). + ContainerStoreIterator unequipItemQuantity(const Ptr& item, const Ptr& actor, int count); + ///< Unequip a specific quantity of an item identified by its Ptr. + /// An exception is thrown if the item is not currently equipped, + /// if count <= 0, or if count > the item stack size. + /// + /// @return an iterator to the unequipped items that were previously + /// in the slot (they can be re-stacked so its count may be different + /// than the requested count). + void setListener (InventoryStoreListener* listener, const Ptr& actor); ///< Set a listener for various events, see \a InventoryStoreListener From 1ff49cc637134e75e1101bbd14bcbffe2f4d3b24 Mon Sep 17 00:00:00 2001 From: Jordan Ayers Date: Mon, 18 Jan 2016 19:58:19 -0600 Subject: [PATCH 3008/3725] Improve Drop command behavior. (Fixes #1544) --- apps/openmw/mwscript/miscextensions.cpp | 35 +++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 593fdcca5..51f0c6c55 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -21,6 +21,7 @@ #include "../mwworld/class.hpp" #include "../mwworld/player.hpp" #include "../mwworld/containerstore.hpp" +#include "../mwworld/inventorystore.hpp" #include "../mwworld/esmstore.hpp" #include "../mwworld/cellstore.hpp" @@ -509,13 +510,43 @@ namespace MWScript if (amount == 0) return; - MWWorld::ContainerStore& store = ptr.getClass().getContainerStore (ptr); + // Prefer dropping unequipped items first; re-stack if possible by unequipping items before dropping them. + MWWorld::InventoryStore *invStorePtr = 0; + if (ptr.getClass().hasInventoryStore(ptr)) { + invStorePtr = &ptr.getClass().getInventoryStore(ptr); + + int numNotEquipped = invStorePtr->count(item); + for (int slot = 0; slot < MWWorld::InventoryStore::Slots; ++slot) + { + MWWorld::ContainerStoreIterator it = invStorePtr->getSlot (slot); + if (it != invStorePtr->end() && ::Misc::StringUtils::ciEqual(it->getCellRef().getRefId(), item)) + { + numNotEquipped -= it->getRefData().getCount(); + } + } + for (int slot = 0; slot < MWWorld::InventoryStore::Slots && amount > numNotEquipped; ++slot) + { + MWWorld::ContainerStoreIterator it = invStorePtr->getSlot (slot); + if (it != invStorePtr->end() && ::Misc::StringUtils::ciEqual(it->getCellRef().getRefId(), item)) + { + int numToRemove = it->getRefData().getCount(); + if (numToRemove > amount - numNotEquipped) + { + numToRemove = amount - numNotEquipped; + } + invStorePtr->unequipItemQuantity(*it, ptr, numToRemove); + numNotEquipped += numToRemove; + } + } + } int toRemove = amount; + MWWorld::ContainerStore& store = ptr.getClass().getContainerStore (ptr); for (MWWorld::ContainerStoreIterator iter (store.begin()); iter!=store.end(); ++iter) { - if (::Misc::StringUtils::ciEqual(iter->getCellRef().getRefId(), item)) + if (::Misc::StringUtils::ciEqual(iter->getCellRef().getRefId(), item) + && (!invStorePtr || !invStorePtr->isEquipped(*iter))) { int removed = store.remove(*iter, toRemove, ptr); MWWorld::Ptr dropped = MWBase::Environment::get().getWorld()->dropObjectOnGround(ptr, *iter, removed); From 5699cf7f0988d904fe4170124c9aec4faa729df7 Mon Sep 17 00:00:00 2001 From: Jordan Ayers Date: Mon, 18 Jan 2016 20:00:18 -0600 Subject: [PATCH 3009/3725] Barter: Leave unsold projectiles equipped. --- apps/openmw/mwgui/inventorywindow.cpp | 10 ++++++---- apps/openmw/mwgui/inventorywindow.hpp | 4 ++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 7678cb006..facb17d66 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -265,18 +265,20 @@ namespace MWGui } } - void InventoryWindow::ensureSelectedItemUnequipped() + void InventoryWindow::ensureSelectedItemUnequipped(int count) { const ItemStack& item = mTradeModel->getItem(mSelectedItem); if (item.mType == ItemStack::Type_Equipped) { MWWorld::InventoryStore& invStore = mPtr.getClass().getInventoryStore(mPtr); - MWWorld::Ptr newStack = *invStore.unequipItem(item.mBase, mPtr); + MWWorld::Ptr newStack = *invStore.unequipItemQuantity(item.mBase, mPtr, count); // The unequipped item was re-stacked. We have to update the index // since the item pointed does not exist anymore. if (item.mBase != newStack) { + updateItemView(); // Unequipping can produce a new stack, not yet in the window... + // newIndex will store the index of the ItemStack the item was stacked on int newIndex = -1; for (size_t i=0; i < mTradeModel->getItemCount(); ++i) @@ -298,14 +300,14 @@ namespace MWGui void InventoryWindow::dragItem(MyGUI::Widget* sender, int count) { - ensureSelectedItemUnequipped(); + ensureSelectedItemUnequipped(count); mDragAndDrop->startDrag(mSelectedItem, mSortModel, mTradeModel, mItemView, count); notifyContentChanged(); } void InventoryWindow::sellItem(MyGUI::Widget* sender, int count) { - ensureSelectedItemUnequipped(); + ensureSelectedItemUnequipped(count); const ItemStack& item = mTradeModel->getItem(mSelectedItem); std::string sound = item.mBase.getClass().getDownSoundId(item.mBase); MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index a8a1b15a1..b7ae067ac 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -126,8 +126,8 @@ namespace MWGui void adjustPanes(); - /// Unequips mSelectedItem, if it is equipped, and then updates mSelectedItem in case it was re-stacked - void ensureSelectedItemUnequipped(); + /// Unequips count items from mSelectedItem, if it is equipped, and then updates mSelectedItem in case the items were re-stacked + void ensureSelectedItemUnequipped(int count); }; } From 19b39de351d9329a10dc42e2906e919018100661 Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Tue, 19 Jan 2016 11:15:36 +0100 Subject: [PATCH 3010/3725] use trusty --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 0910ac546..10b47ee7d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,6 +2,8 @@ os: - linux # - osx language: cpp +sudo: required +dist: trusty branches: only: - master From 0305ae369327ad39a354a5b7f91abaed424b0287 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 19 Jan 2016 12:17:13 +0100 Subject: [PATCH 3011/3725] added selection mode UI --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/view/render/instancemode.cpp | 23 +++++++++++++--- apps/opencs/view/render/instancemode.hpp | 3 +++ .../view/render/instanceselectionmode.cpp | 27 +++++++++++++++++++ .../view/render/instanceselectionmode.hpp | 19 +++++++++++++ 5 files changed, 69 insertions(+), 5 deletions(-) create mode 100644 apps/opencs/view/render/instanceselectionmode.cpp create mode 100644 apps/opencs/view/render/instanceselectionmode.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 0e9a49432..ae4bbd66c 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -85,7 +85,7 @@ opencs_units (view/widget opencs_units (view/render scenewidget worldspacewidget pagedworldspacewidget unpagedworldspacewidget - previewwidget editmode instancemode + previewwidget editmode instancemode instanceselectionmode ) opencs_units_noqt (view/render diff --git a/apps/opencs/view/render/instancemode.cpp b/apps/opencs/view/render/instancemode.cpp index 449d9d7a6..53ebc7052 100644 --- a/apps/opencs/view/render/instancemode.cpp +++ b/apps/opencs/view/render/instancemode.cpp @@ -16,10 +16,11 @@ #include "object.hpp" #include "worldspacewidget.hpp" #include "pagedworldspacewidget.hpp" +#include "instanceselectionmode.hpp" CSVRender::InstanceMode::InstanceMode (WorldspaceWidget *worldspaceWidget, QWidget *parent) : EditMode (worldspaceWidget, QIcon (":placeholder"), Element_Reference, "Instance editing", - parent), mSubMode (0) + parent), mSubMode (0), mSelectionMode (0) { } @@ -48,16 +49,30 @@ void CSVRender::InstanceMode::activate (CSVWidget::SceneToolbar *toolbar) "Not implemented yet"); } + if (!mSelectionMode) + mSelectionMode = new InstanceSelectionMode (toolbar); + EditMode::activate (toolbar); toolbar->addTool (mSubMode); + toolbar->addTool (mSelectionMode); } void CSVRender::InstanceMode::deactivate (CSVWidget::SceneToolbar *toolbar) { - toolbar->removeTool (mSubMode); - delete mSubMode; - mSubMode = 0; + if (mSelectionMode) + { + toolbar->removeTool (mSelectionMode); + delete mSelectionMode; + mSelectionMode = 0; + } + + if (mSubMode) + { + toolbar->removeTool (mSubMode); + delete mSubMode; + mSubMode = 0; + } EditMode::deactivate (toolbar); } diff --git a/apps/opencs/view/render/instancemode.hpp b/apps/opencs/view/render/instancemode.hpp index 1eec62874..78836878a 100644 --- a/apps/opencs/view/render/instancemode.hpp +++ b/apps/opencs/view/render/instancemode.hpp @@ -10,10 +10,13 @@ namespace CSVWidget namespace CSVRender { + class InstanceSelectionMode; + class InstanceMode : public EditMode { Q_OBJECT CSVWidget::SceneToolMode *mSubMode; + InstanceSelectionMode *mSelectionMode; public: diff --git a/apps/opencs/view/render/instanceselectionmode.cpp b/apps/opencs/view/render/instanceselectionmode.cpp new file mode 100644 index 000000000..9fd825999 --- /dev/null +++ b/apps/opencs/view/render/instanceselectionmode.cpp @@ -0,0 +1,27 @@ + +#include "instanceselectionmode.hpp" + +CSVRender::InstanceSelectionMode::InstanceSelectionMode (CSVWidget::SceneToolbar *parent) +: CSVWidget::SceneToolMode (parent, "Selection Mode") +{ + addButton (":placeholder", "cube-centre", + "Centred cube" + "
    • Drag with primary (make instances the selection) or secondary (invert selection state) select button from the centre of the selection cube outwards
    • " + "
    • The selection cube is aligned to the word space axis
    • " + "
    • If context selection mode is enabled, a drag with primary/secondary edit not starting on an instance will have the same effect
    • " + "
    " + "Not implemented yet"); + addButton (":placeholder", "cube-corner", + "Cube corner to corner" + "
    • Drag with primary (make instances the selection) or secondary (invert selection state) select button from one corner of the selection cube to the opposite corner
    • " + "
    • The selection cube is aligned to the word space axis
    • " + "
    • If context selection mode is enabled, a drag with primary/secondary edit not starting on an instance will have the same effect
    • " + "
    " + "Not implemented yet"); + addButton (":placeholder", "sphere", + "Centred sphere" + "
    • Drag with primary (make instances the selection) or secondary (invert selection state) select button from the centre of the selection sphere outwards
    • " + "
    • If context selection mode is enabled, a drag with primary/secondary edit not starting on an instance will have the same effect
    • " + "
    " + "Not implemented yet"); +} diff --git a/apps/opencs/view/render/instanceselectionmode.hpp b/apps/opencs/view/render/instanceselectionmode.hpp new file mode 100644 index 000000000..e823de213 --- /dev/null +++ b/apps/opencs/view/render/instanceselectionmode.hpp @@ -0,0 +1,19 @@ +#ifndef CSV_RENDER_INSTANCE_SELECTION_MODE_H +#define CSV_RENDER_INSTANCE_SELECTION_MODE_H + +#include "../widget/scenetoolmode.hpp" + +namespace CSVRender +{ + class InstanceSelectionMode : public CSVWidget::SceneToolMode + { + Q_OBJECT + + public: + + InstanceSelectionMode (CSVWidget::SceneToolbar *parent); + + }; +} + +#endif From eee972a1a4414a065e55153fe88413f7e6229cfc Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 19 Jan 2016 12:47:11 +0100 Subject: [PATCH 3012/3725] added scene tool mode context menu feature --- apps/opencs/view/widget/scenetoolmode.cpp | 17 +++++++++++++++++ apps/opencs/view/widget/scenetoolmode.hpp | 11 +++++++++++ 2 files changed, 28 insertions(+) diff --git a/apps/opencs/view/widget/scenetoolmode.cpp b/apps/opencs/view/widget/scenetoolmode.cpp index a93bb0556..efb508f9d 100644 --- a/apps/opencs/view/widget/scenetoolmode.cpp +++ b/apps/opencs/view/widget/scenetoolmode.cpp @@ -3,10 +3,24 @@ #include #include #include +#include +#include #include "scenetoolbar.hpp" #include "modebutton.hpp" +void CSVWidget::SceneToolMode::contextMenuEvent (QContextMenuEvent *event) +{ + QMenu menu (this); + if (createContextMenu (&menu)) + menu.exec (event->globalPos()); +} + +bool CSVWidget::SceneToolMode::createContextMenu (QMenu *menu) +{ + return false; +} + void CSVWidget::SceneToolMode::adjustToolTip (const ModeButton *activeMode) { QString toolTip = mToolTip; @@ -15,6 +29,9 @@ void CSVWidget::SceneToolMode::adjustToolTip (const ModeButton *activeMode) toolTip += "

    (left click to change mode)"; + if (createContextMenu (0)) + toolTip += "
    (right click to access context menu)"; + setToolTip (toolTip); } diff --git a/apps/opencs/view/widget/scenetoolmode.hpp b/apps/opencs/view/widget/scenetoolmode.hpp index 6828a2269..43cd4a7d7 100644 --- a/apps/opencs/view/widget/scenetoolmode.hpp +++ b/apps/opencs/view/widget/scenetoolmode.hpp @@ -6,6 +6,7 @@ #include class QHBoxLayout; +class QMenu; namespace CSVWidget { @@ -29,6 +30,16 @@ namespace CSVWidget void adjustToolTip (const ModeButton *activeMode); + virtual void contextMenuEvent (QContextMenuEvent *event); + + /// Add context menu items to \a menu. Default-implementation: return false + /// + /// \attention menu can be a 0-pointer + /// + /// \return Have there been any menu items to be added (if menu is 0 and there + /// items to be added, the function must return true anyway. + virtual bool createContextMenu (QMenu *menu); + public: SceneToolMode (SceneToolbar *parent, const QString& toolTip); From ecbcd6b1717718d1ccaa3e18d7ad930eb2244f61 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 19 Jan 2016 12:52:30 +0100 Subject: [PATCH 3013/3725] allow mode buttons to setup the context menu --- apps/opencs/view/widget/modebutton.cpp | 5 +++++ apps/opencs/view/widget/modebutton.hpp | 10 ++++++++++ apps/opencs/view/widget/scenetoolmode.cpp | 3 +++ apps/opencs/view/widget/scenetoolmode.hpp | 3 ++- 4 files changed, 20 insertions(+), 1 deletion(-) diff --git a/apps/opencs/view/widget/modebutton.cpp b/apps/opencs/view/widget/modebutton.cpp index 7c62f6bb1..88f050247 100644 --- a/apps/opencs/view/widget/modebutton.cpp +++ b/apps/opencs/view/widget/modebutton.cpp @@ -7,3 +7,8 @@ CSVWidget::ModeButton::ModeButton (const QIcon& icon, const QString& tooltip, QW void CSVWidget::ModeButton::activate (SceneToolbar *toolbar) {} void CSVWidget::ModeButton::deactivate (SceneToolbar *toolbar) {} + +bool CSVWidget::ModeButton::createContextMenu (QMenu *menu) +{ + return false; +} diff --git a/apps/opencs/view/widget/modebutton.hpp b/apps/opencs/view/widget/modebutton.hpp index ac14afc95..1615ff298 100644 --- a/apps/opencs/view/widget/modebutton.hpp +++ b/apps/opencs/view/widget/modebutton.hpp @@ -3,6 +3,8 @@ #include "pushbutton.hpp" +class QMenu; + namespace CSVWidget { class SceneToolbar; @@ -22,6 +24,14 @@ namespace CSVWidget /// Default-Implementation: do nothing virtual void deactivate (SceneToolbar *toolbar); + + /// Add context menu items to \a menu. Default-implementation: return false + /// + /// \attention menu can be a 0-pointer + /// + /// \return Have there been any menu items to be added (if menu is 0 and there + /// items to be added, the function must return true anyway. + virtual bool createContextMenu (QMenu *menu); }; } diff --git a/apps/opencs/view/widget/scenetoolmode.cpp b/apps/opencs/view/widget/scenetoolmode.cpp index efb508f9d..125f4ac79 100644 --- a/apps/opencs/view/widget/scenetoolmode.cpp +++ b/apps/opencs/view/widget/scenetoolmode.cpp @@ -18,6 +18,9 @@ void CSVWidget::SceneToolMode::contextMenuEvent (QContextMenuEvent *event) bool CSVWidget::SceneToolMode::createContextMenu (QMenu *menu) { + if (mCurrent) + return mCurrent->createContextMenu (menu); + return false; } diff --git a/apps/opencs/view/widget/scenetoolmode.hpp b/apps/opencs/view/widget/scenetoolmode.hpp index 43cd4a7d7..3aa8e6799 100644 --- a/apps/opencs/view/widget/scenetoolmode.hpp +++ b/apps/opencs/view/widget/scenetoolmode.hpp @@ -32,7 +32,8 @@ namespace CSVWidget virtual void contextMenuEvent (QContextMenuEvent *event); - /// Add context menu items to \a menu. Default-implementation: return false + /// Add context menu items to \a menu. Default-implementation: Pass on request to + /// current mode button or return false, if there is no current mode button. /// /// \attention menu can be a 0-pointer /// From 45e6974266f6df4c9185bf2b225309d19d969078 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 19 Jan 2016 14:25:20 +0100 Subject: [PATCH 3014/3725] added select all and clear selection features --- apps/opencs/view/render/instancemode.cpp | 3 +- .../view/render/instanceselectionmode.cpp | 37 ++++++++++++++++++- .../view/render/instanceselectionmode.hpp | 23 +++++++++++- .../view/render/pagedworldspacewidget.cpp | 9 +++++ .../view/render/pagedworldspacewidget.hpp | 3 ++ .../view/render/unpagedworldspacewidget.cpp | 6 +++ .../view/render/unpagedworldspacewidget.hpp | 3 ++ apps/opencs/view/render/worldspacewidget.hpp | 3 ++ 8 files changed, 82 insertions(+), 5 deletions(-) diff --git a/apps/opencs/view/render/instancemode.cpp b/apps/opencs/view/render/instancemode.cpp index ff49e0286..4b6b2e41f 100644 --- a/apps/opencs/view/render/instancemode.cpp +++ b/apps/opencs/view/render/instancemode.cpp @@ -9,7 +9,6 @@ #include "../../model/world/idtree.hpp" #include "../../model/world/commands.hpp" - #include "../widget/scenetoolbar.hpp" #include "../widget/scenetoolmode.hpp" @@ -52,7 +51,7 @@ void CSVRender::InstanceMode::activate (CSVWidget::SceneToolbar *toolbar) } if (!mSelectionMode) - mSelectionMode = new InstanceSelectionMode (toolbar); + mSelectionMode = new InstanceSelectionMode (toolbar, getWorldspaceWidget()); EditMode::activate (toolbar); diff --git a/apps/opencs/view/render/instanceselectionmode.cpp b/apps/opencs/view/render/instanceselectionmode.cpp index 9fd825999..794a150d2 100644 --- a/apps/opencs/view/render/instanceselectionmode.cpp +++ b/apps/opencs/view/render/instanceselectionmode.cpp @@ -1,8 +1,25 @@ #include "instanceselectionmode.hpp" -CSVRender::InstanceSelectionMode::InstanceSelectionMode (CSVWidget::SceneToolbar *parent) -: CSVWidget::SceneToolMode (parent, "Selection Mode") +#include +#include + +#include "worldspacewidget.hpp" + +bool CSVRender::InstanceSelectionMode::createContextMenu (QMenu *menu) +{ + if (menu) + { + menu->addAction (mSelectAll); + menu->addAction (mDeselectAll); + } + + return true; +} + +CSVRender::InstanceSelectionMode::InstanceSelectionMode (CSVWidget::SceneToolbar *parent, + WorldspaceWidget& worldspaceWidget) +: CSVWidget::SceneToolMode (parent, "Selection Mode"), mWorldspaceWidget (worldspaceWidget) { addButton (":placeholder", "cube-centre", "Centred cube" @@ -24,4 +41,20 @@ CSVRender::InstanceSelectionMode::InstanceSelectionMode (CSVWidget::SceneToolbar "

  • If context selection mode is enabled, a drag with primary/secondary edit not starting on an instance will have the same effect
  • " "" "Not implemented yet"); + + mSelectAll = new QAction ("Select all Instances", this); + mDeselectAll = new QAction ("Clear selection", this); + + connect (mSelectAll, SIGNAL (triggered ()), this, SLOT (selectAll())); + connect (mDeselectAll, SIGNAL (triggered ()), this, SLOT (clearSelection())); +} + +void CSVRender::InstanceSelectionMode::selectAll() +{ + mWorldspaceWidget.selectAll (Mask_Reference); +} + +void CSVRender::InstanceSelectionMode::clearSelection() +{ + mWorldspaceWidget.clearSelection (Mask_Reference); } diff --git a/apps/opencs/view/render/instanceselectionmode.hpp b/apps/opencs/view/render/instanceselectionmode.hpp index e823de213..6b3a4e37d 100644 --- a/apps/opencs/view/render/instanceselectionmode.hpp +++ b/apps/opencs/view/render/instanceselectionmode.hpp @@ -3,16 +3,37 @@ #include "../widget/scenetoolmode.hpp" +class QAction; + namespace CSVRender { + class WorldspaceWidget; + class InstanceSelectionMode : public CSVWidget::SceneToolMode { Q_OBJECT + WorldspaceWidget& mWorldspaceWidget; + QAction *mSelectAll; + QAction *mDeselectAll; + + /// Add context menu items to \a menu. + /// + /// \attention menu can be a 0-pointer + /// + /// \return Have there been any menu items to be added (if menu is 0 and there + /// items to be added, the function must return true anyway. + virtual bool createContextMenu (QMenu *menu); + public: - InstanceSelectionMode (CSVWidget::SceneToolbar *parent); + InstanceSelectionMode (CSVWidget::SceneToolbar *parent, WorldspaceWidget& worldspaceWidget); + + private slots: + + void selectAll(); + void clearSelection(); }; } diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index 1880beab8..ccb3efb1d 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -509,6 +509,15 @@ void CSVRender::PagedWorldspaceWidget::clearSelection (int elementMask) flagAsModified(); } +void CSVRender::PagedWorldspaceWidget::selectAll (int elementMask) +{ + for (std::map::iterator iter = mCells.begin(); + iter!=mCells.end(); ++iter) + iter->second->setSelection (elementMask, Cell::Selection_All); + + flagAsModified(); +} + std::string CSVRender::PagedWorldspaceWidget::getCellId (const osg::Vec3f& point) const { const int cellSize = 8192; diff --git a/apps/opencs/view/render/pagedworldspacewidget.hpp b/apps/opencs/view/render/pagedworldspacewidget.hpp index 647341d1f..3f9e605af 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.hpp +++ b/apps/opencs/view/render/pagedworldspacewidget.hpp @@ -98,6 +98,9 @@ namespace CSVRender /// \param elementMask Elements to be affected by the clear operation virtual void clearSelection (int elementMask); + /// \param elementMask Elements to be affected by the select operation + virtual void selectAll (int elementMask); + virtual std::string getCellId (const osg::Vec3f& point) const; protected: diff --git a/apps/opencs/view/render/unpagedworldspacewidget.cpp b/apps/opencs/view/render/unpagedworldspacewidget.cpp index dad37c946..48180f866 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.cpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.cpp @@ -108,6 +108,12 @@ void CSVRender::UnpagedWorldspaceWidget::clearSelection (int elementMask) flagAsModified(); } +void CSVRender::UnpagedWorldspaceWidget::selectAll (int elementMask) +{ + mCell->setSelection (elementMask, Cell::Selection_All); + flagAsModified(); +} + std::string CSVRender::UnpagedWorldspaceWidget::getCellId (const osg::Vec3f& point) const { return mCellId; diff --git a/apps/opencs/view/render/unpagedworldspacewidget.hpp b/apps/opencs/view/render/unpagedworldspacewidget.hpp index 70a20c216..8971f22a8 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.hpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.hpp @@ -46,6 +46,9 @@ namespace CSVRender /// \param elementMask Elements to be affected by the clear operation virtual void clearSelection (int elementMask); + /// \param elementMask Elements to be affected by the select operation + virtual void selectAll (int elementMask); + virtual std::string getCellId (const osg::Vec3f& point) const; private: diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp index 7a77edad4..13e66b7f0 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -127,6 +127,9 @@ namespace CSVRender /// \param elementMask Elements to be affected by the clear operation virtual void clearSelection (int elementMask) = 0; + /// \param elementMask Elements to be affected by the select operation + virtual void selectAll (int elementMask) = 0; + /// Return the next intersection point with scene elements matched by /// \a interactionMask based on \a localPos and the camera vector. /// If there is no such point, instead a point "in front" of \a localPos will be From f0971ee8ad2f1e4d0a67a9aa6d5c6916c25ec91b Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 20 Jan 2016 04:07:07 +0100 Subject: [PATCH 3015/3725] Implement Fixme script instruction --- apps/openmw/mwscript/docs/vmformat.txt | 4 +++- apps/openmw/mwscript/transformationextensions.cpp | 14 ++++++++++++++ apps/openmw/mwworld/worldimp.cpp | 3 ++- components/compiler/extensions0.cpp | 1 + components/compiler/opcodes.hpp | 2 ++ 5 files changed, 22 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index 42c204ecb..93219c649 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -447,5 +447,7 @@ op 0x20002fe: RemoveFromLevItem op 0x20002ff: SetFactionReaction op 0x2000300: EnableLevelupMenu op 0x2000301: ToggleScripts +op 0x2000302: Fixme +op 0x2000303: Fixme, explicit -opcodes 0x2000302-0x3ffffff unused +opcodes 0x2000304-0x3ffffff unused diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 60847e745..64c126de1 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -734,6 +734,18 @@ namespace MWScript } }; + template + class OpFixme : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + MWBase::Environment::get().getWorld()->fixPosition(ptr); + } + }; + void installOpcodes (Interpreter::Interpreter& interpreter) { interpreter.installSegment5(Compiler::Transformation::opcodeSetScale,new OpSetScale); @@ -774,6 +786,8 @@ namespace MWScript interpreter.installSegment5(Compiler::Transformation::opcodeGetStartingAngle, new OpGetStartingAngle); interpreter.installSegment5(Compiler::Transformation::opcodeGetStartingAngleExplicit, new OpGetStartingAngle); interpreter.installSegment5(Compiler::Transformation::opcodeResetActors, new OpResetActors); + interpreter.installSegment5(Compiler::Transformation::opcodeFixme, new OpFixme); + interpreter.installSegment5(Compiler::Transformation::opcodeFixmeExplicit, new OpFixme); } } } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index c566a32b5..014c6b200 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1311,7 +1311,8 @@ namespace MWWorld actor.getRefData().setPosition(pos); osg::Vec3f traced = mPhysics->traceDown(actor, dist*1.1f); - moveObject(actor, actor.getCell(), traced.x(), traced.y(), traced.z()); + if (traced != pos.asVec3()) + moveObject(actor, actor.getCell(), traced.x(), traced.y(), traced.z()); } void World::rotateObject (const Ptr& ptr,float x,float y,float z, bool adjust) diff --git a/components/compiler/extensions0.cpp b/components/compiler/extensions0.cpp index 8c76cdbb8..6916945f9 100644 --- a/components/compiler/extensions0.cpp +++ b/components/compiler/extensions0.cpp @@ -541,6 +541,7 @@ namespace Compiler extensions.registerInstruction("moveworld","cf",opcodeMoveWorld,opcodeMoveWorldExplicit); extensions.registerFunction("getstartingangle",'f',"c",opcodeGetStartingAngle,opcodeGetStartingAngleExplicit); extensions.registerInstruction("resetactors","",opcodeResetActors); + extensions.registerInstruction("fixme","",opcodeFixme, opcodeFixmeExplicit); extensions.registerInstruction("ra","",opcodeResetActors); } } diff --git a/components/compiler/opcodes.hpp b/components/compiler/opcodes.hpp index e7d51d934..feed5513e 100644 --- a/components/compiler/opcodes.hpp +++ b/components/compiler/opcodes.hpp @@ -498,6 +498,8 @@ namespace Compiler const int opcodeMoveWorld = 0x2000208; const int opcodeMoveWorldExplicit = 0x2000209; const int opcodeResetActors = 0x20002f4; + const int opcodeFixme = 0x2000302; + const int opcodeFixmeExplicit = 0x2000303; } namespace User From 339fbe23a7c0f1d89e683f6fa41728a7b5c3d428 Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Wed, 20 Jan 2016 14:03:51 +0100 Subject: [PATCH 3016/3725] remove precise cruft --- CI/before_install.linux.sh | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/CI/before_install.linux.sh b/CI/before_install.linux.sh index 6e288aa14..1c02bc8d9 100755 --- a/CI/before_install.linux.sh +++ b/CI/before_install.linux.sh @@ -1,22 +1,17 @@ #!/bin/sh if [ "${ANALYZE}" ]; then - if [ $(lsb_release -sc) = "precise" ]; then - echo "yes" | sudo apt-add-repository ppa:ubuntu-toolchain-r/test - fi echo "yes" | sudo add-apt-repository "deb http://llvm.org/apt/`lsb_release -sc`/ llvm-toolchain-`lsb_release -sc`-3.6 main" wget -O - http://llvm.org/apt/llvm-snapshot.gpg.key|sudo apt-key add - fi echo "yes" | sudo add-apt-repository "deb http://archive.ubuntu.com/ubuntu `lsb_release -sc` main universe restricted multiverse" echo "yes" | sudo apt-add-repository ppa:openmw/openmw -echo "yes" | sudo apt-add-repository ppa:boost-latest/ppa sudo apt-get update -qq sudo apt-get install -qq libgtest-dev google-mock -sudo apt-get install -qq libboost-filesystem1.55-dev libboost-program-options1.55-dev libboost-system1.55-dev libboost-thread1.55-dev -sudo apt-get install -qq ffmpeg libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libswresample-dev +sudo apt-get install -qq libboost-filesystem-dev libboost-program-options-dev libboost-system-dev libboost-thread-dev +sudo apt-get install -qq libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libswresample-dev sudo apt-get install -qq libbullet-dev libopenscenegraph-dev libmygui-dev libsdl2-dev libunshield-dev libtinyxml-dev libopenal-dev libqt4-dev -sudo apt-get install -qq cmake-data #workaround for broken osgqt cmake script in ubuntu 12.04 if [ "${ANALYZE}" ]; then sudo apt-get install -qq clang-3.6; fi sudo mkdir /usr/src/gtest/build cd /usr/src/gtest/build From b8d19eb9cd09324b456c23a3f968a51d03432596 Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Wed, 20 Jan 2016 14:30:33 +0100 Subject: [PATCH 3017/3725] make use of 2 dedicated cores while assuming both are blocked on I/O --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 10b47ee7d..3a76944fb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -40,7 +40,7 @@ before_script: - if [ "${TRAVIS_OS_NAME}" = "osx" ]; then ./CI/before_script.osx.sh; fi script: - cd ./build - - if [ "$COVERITY_SCAN_BRANCH" != 1 ]; then ${ANALYZE}make -j2; fi + - if [ "$COVERITY_SCAN_BRANCH" != 1 ]; then ${ANALYZE}make -j3; fi - if [ "$COVERITY_SCAN_BRANCH" != 1 ] && [ "${TRAVIS_OS_NAME}" = "osx" ]; then make package; fi - if [ "$COVERITY_SCAN_BRANCH" != 1 ] && [ "${TRAVIS_OS_NAME}" = "linux" ]; then ./openmw_test_suite; fi - if [ "$COVERITY_SCAN_BRANCH" != 1 ] && [ "${TRAVIS_OS_NAME}" = "linux" ]; then cd .. && ./CI/check_tabs.sh; fi From 10609ca5d1d9e6abaa76978a06b830eaaa217530 Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Thu, 21 Jan 2016 09:22:42 +0100 Subject: [PATCH 3018/3725] how much memory in our vm? --- CI/before_script.linux.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/CI/before_script.linux.sh b/CI/before_script.linux.sh index 71ddd2040..17667ad28 100755 --- a/CI/before_script.linux.sh +++ b/CI/before_script.linux.sh @@ -1,5 +1,6 @@ #!/bin/sh +free -m mkdir build cd build export CODE_COVERAGE=1 From 89512af808d78cf21e2e6553d155d1d341c4e54d Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 21 Jan 2016 14:33:26 +0100 Subject: [PATCH 3019/3725] Increase number of jobs for coverity scan build to 2, enable OpenMW-CS build As of the recent travis migration we should have enough memory to not run out... hopefully. --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 3a76944fb..e314d8e7b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,8 +20,8 @@ addons: name: "OpenMW/openmw" description: "" notification_email: scrawl@baseoftrash.de - build_command_prepend: "cmake . -DBUILD_UNITTESTS=FALSE -DBUILD_OPENCS=FALSE" - build_command: "make" + build_command_prepend: "cmake . -DBUILD_UNITTESTS=FALSE" + build_command: "make -j2" branch_pattern: coverity_scan matrix: include: From b0431833a1c8c077d2858faa62b96d9564efc3be Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 21 Jan 2016 16:08:04 +0100 Subject: [PATCH 3020/3725] Fix some defects reported by Coverity CI --- apps/opencs/model/doc/messages.cpp | 2 +- apps/opencs/model/doc/messages.hpp | 3 --- apps/opencs/model/doc/operationholder.cpp | 4 +++- apps/opencs/model/tools/reportmodel.cpp | 2 +- apps/opencs/model/tools/reportmodel.hpp | 2 +- apps/opencs/model/world/commands.cpp | 2 +- apps/opencs/view/render/worldspacewidget.cpp | 5 +++-- apps/opencs/view/world/table.cpp | 2 +- apps/opencs/view/world/tablebottombox.cpp | 2 +- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 4 +++- 11 files changed, 16 insertions(+), 14 deletions(-) diff --git a/apps/opencs/model/doc/messages.cpp b/apps/opencs/model/doc/messages.cpp index 86e96a88d..76bbb6f22 100644 --- a/apps/opencs/model/doc/messages.cpp +++ b/apps/opencs/model/doc/messages.cpp @@ -1,6 +1,6 @@ #include "messages.hpp" -CSMDoc::Message::Message() {} +CSMDoc::Message::Message() : mSeverity(Severity_Default){} CSMDoc::Message::Message (const CSMWorld::UniversalId& id, const std::string& message, const std::string& hint, Severity severity) diff --git a/apps/opencs/model/doc/messages.hpp b/apps/opencs/model/doc/messages.hpp index 429feae4e..4041e1a67 100644 --- a/apps/opencs/model/doc/messages.hpp +++ b/apps/opencs/model/doc/messages.hpp @@ -39,9 +39,6 @@ namespace CSMDoc { public: - // \deprecated Use CSMDoc::Message directly instead. - typedef CSMDoc::Message Message; - typedef std::vector Collection; typedef Collection::const_iterator Iterator; diff --git a/apps/opencs/model/doc/operationholder.cpp b/apps/opencs/model/doc/operationholder.cpp index 5fcf24fe4..ccbed6c8b 100644 --- a/apps/opencs/model/doc/operationholder.cpp +++ b/apps/opencs/model/doc/operationholder.cpp @@ -2,7 +2,9 @@ #include "operation.hpp" -CSMDoc::OperationHolder::OperationHolder (Operation *operation) : mRunning (false) +CSMDoc::OperationHolder::OperationHolder (Operation *operation) + : mOperation(NULL) + , mRunning (false) { if (operation) setOperation (operation); diff --git a/apps/opencs/model/tools/reportmodel.cpp b/apps/opencs/model/tools/reportmodel.cpp index 77a14de84..49de1d651 100644 --- a/apps/opencs/model/tools/reportmodel.cpp +++ b/apps/opencs/model/tools/reportmodel.cpp @@ -182,7 +182,7 @@ int CSMTools::ReportModel::countErrors() const { int count = 0; - for (std::vector::const_iterator iter (mRows.begin()); + for (std::vector::const_iterator iter (mRows.begin()); iter!=mRows.end(); ++iter) if (iter->mSeverity==CSMDoc::Message::Severity_Error || iter->mSeverity==CSMDoc::Message::Severity_SeriousError) diff --git a/apps/opencs/model/tools/reportmodel.hpp b/apps/opencs/model/tools/reportmodel.hpp index 5704970f5..61b4e6307 100644 --- a/apps/opencs/model/tools/reportmodel.hpp +++ b/apps/opencs/model/tools/reportmodel.hpp @@ -16,7 +16,7 @@ namespace CSMTools { Q_OBJECT - std::vector mRows; + std::vector mRows; // Fixed columns enum Columns diff --git a/apps/opencs/model/world/commands.cpp b/apps/opencs/model/world/commands.cpp index d510cd103..097e83f7c 100644 --- a/apps/opencs/model/world/commands.cpp +++ b/apps/opencs/model/world/commands.cpp @@ -14,7 +14,7 @@ CSMWorld::ModifyCommand::ModifyCommand (QAbstractItemModel& model, const QModelIndex& index, const QVariant& new_, QUndoCommand* parent) -: QUndoCommand (parent), mModel (&model), mIndex (index), mNew (new_), mHasRecordState(false) + : QUndoCommand (parent), mModel (&model), mIndex (index), mNew (new_), mHasRecordState(false), mOldRecordState(CSMWorld::RecordBase::State_BaseOnly) { if (QAbstractProxyModel *proxy = dynamic_cast (&model)) { diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 184477d6b..af90af50c 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -33,8 +33,9 @@ CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidget* parent) : SceneWidget (document.getData().getResourceSystem(), parent), mSceneElements(0), mRun(0), mDocument(document), - mInteractionMask (0), mEditMode (0), mLocked (false), mDragging (false), - mToolTipPos (-1, -1) + mInteractionMask (0), mEditMode (0), mLocked (false), mDragging (false), mDragX(0), mDragY(0), mDragFactor(0), + mDragWheelFactor(0), mDragShiftFactor(0), + mToolTipPos (-1, -1), mShowToolTips(false), mToolTipDelay(0) { setAcceptDrops(true); diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index 95dfa1034..26746e8c9 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -231,7 +231,7 @@ void CSVWorld::Table::mouseDoubleClickEvent (QMouseEvent *event) CSVWorld::Table::Table (const CSMWorld::UniversalId& id, bool createAndDelete, bool sorting, CSMDoc::Document& document) : DragRecordTable(document), mCreateAction (0), - mCloneAction(0),mRecordStatusDisplay (0) + mCloneAction(0), mRecordStatusDisplay (0), mJumpToAddedRecord(false), mUnselectAfterJump(false) { mModel = &dynamic_cast (*mDocument.getData().getTableModel (id)); diff --git a/apps/opencs/view/world/tablebottombox.cpp b/apps/opencs/view/world/tablebottombox.cpp index eed522227..5a25bbc53 100644 --- a/apps/opencs/view/world/tablebottombox.cpp +++ b/apps/opencs/view/world/tablebottombox.cpp @@ -76,7 +76,7 @@ CSVWorld::TableBottomBox::TableBottomBox (const CreatorFactoryBase& creatorFacto CSMDoc::Document& document, const CSMWorld::UniversalId& id, QWidget *parent) -: QWidget (parent), mShowStatusBar (false), mEditMode(EditMode_None), mHasPosition(false) +: QWidget (parent), mShowStatusBar (false), mEditMode(EditMode_None), mHasPosition(false), mRow(0), mColumn(0) { for (int i=0; i<4; ++i) mStatusCount[i] = 0; diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index b8dc90cf7..84da270eb 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1556,7 +1556,7 @@ namespace MWMechanics (target == getPlayer() && MWBase::Environment::get().getWorld()->getGlobalInt("pcknownwerewolf"))) { - const ESM::GameSetting * iWerewolfFightMod = MWBase::Environment::get().getWorld()->getStore().get().search("iWerewolfFightMod"); + const ESM::GameSetting * iWerewolfFightMod = MWBase::Environment::get().getWorld()->getStore().get().find("iWerewolfFightMod"); fight += iWerewolfFightMod->getInt(); } } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 014c6b200..afb5be9d3 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -433,7 +433,7 @@ namespace MWWorld // Werewolf (BM) gmst["fWereWolfRunMult"] = ESM::Variant(1.f); gmst["fWereWolfSilverWeaponDamageMult"] = ESM::Variant(1.f); - + gmst["iWerewolfFightMod"] = ESM::Variant(1); std::map globals; // vanilla Morrowind does not define dayspassed. @@ -1745,6 +1745,8 @@ namespace MWWorld { cellid.mWorldspace = ref.mRef.getDestCell(); cellid.mPaged = false; + cellid.mIndex.mX = 0; + cellid.mIndex.mY = 0; } else { From ffcb6ec3819a3b3c0b66829bc2341c090254f737 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 21 Jan 2016 23:38:23 +0100 Subject: [PATCH 3021/3725] Change the default near clip distance to 1 (Fixes #3155) --- files/settings-default.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 6a2495e26..e4a8387b4 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -14,7 +14,7 @@ [Camera] # Near clipping plane (>0.0, e.g. 0.01 to 18.0). -near clip = 5.0 +near clip = 1 # Cull objects smaller than one pixel. small feature culling = true From 07a4c0bf739ced2b2975e9c6507584d6fc4afc8e Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Sat, 23 Jan 2016 01:20:31 +0100 Subject: [PATCH 3022/3725] version bump to 0.38 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f353cd76e..9cfb0440d 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ OpenMW is a recreation of the engine for the popular role-playing game Morrowind OpenMW also comes with OpenMW-CS, a replacement for Morrowind's TES Construction Set. -* Version: 0.37.0 +* Version: 0.38.0 * License: GPL (see docs/license/GPL3.txt for more information) * Website: http://www.openmw.org * IRC: #openmw on irc.freenode.net From b93b97575eafe176d405d047040fa13b4ddd80e4 Mon Sep 17 00:00:00 2001 From: Rob Cutmore Date: Sun, 24 Jan 2016 11:54:53 -0500 Subject: [PATCH 3023/3725] Improve start script creation (Fixes #3024) Improved start script creation by updating input to be a drop target and adding auto-completion. --- apps/opencs/view/world/startscriptcreator.cpp | 132 ++++++++++++++++-- apps/opencs/view/world/startscriptcreator.hpp | 68 ++++++++- apps/opencs/view/world/subviews.cpp | 7 +- 3 files changed, 185 insertions(+), 22 deletions(-) diff --git a/apps/opencs/view/world/startscriptcreator.cpp b/apps/opencs/view/world/startscriptcreator.cpp index 69b1b3ff1..57ac34b8f 100644 --- a/apps/opencs/view/world/startscriptcreator.cpp +++ b/apps/opencs/view/world/startscriptcreator.cpp @@ -1,20 +1,130 @@ #include "startscriptcreator.hpp" -CSVWorld::StartScriptCreator::StartScriptCreator(CSMWorld::Data &data, QUndoStack &undoStack, const CSMWorld::UniversalId &id, bool relaxedIdRules): - GenericCreator (data, undoStack, id, true) -{} +#include + +#include "../../model/doc/document.hpp" + +#include "../../model/world/columns.hpp" +#include "../../model/world/commands.hpp" +#include "../../model/world/data.hpp" +#include "../../model/world/idcompletionmanager.hpp" +#include "../../model/world/idtable.hpp" + +#include "../widget/droplineedit.hpp" + +std::string CSVWorld::StartScriptCreator::getId() const +{ + return mScript->text().toUtf8().constData(); +} + +CSMWorld::IdTable& CSVWorld::StartScriptCreator::getStartScriptsTable() const +{ + return dynamic_cast ( + *getData().getTableModel(getCollectionId()) + ); +} + +void CSVWorld::StartScriptCreator::configureCreateCommand(CSMWorld::CreateCommand& command) const +{ + CSMWorld::IdTable& table = getStartScriptsTable(); + int column = table.findColumnIndex(CSMWorld::Columns::ColumnId_Id); + + // Set script ID to be added to start scripts table. + command.addValue(column, mScript->text()); +} + +CSVWorld::StartScriptCreator::StartScriptCreator( + CSMWorld::Data &data, + QUndoStack &undoStack, + const CSMWorld::UniversalId &id, + CSMWorld::IdCompletionManager& completionManager +) : GenericCreator(data, undoStack, id, true) +{ + setManualEditing(false); + + // Add script ID input label. + QLabel *label = new QLabel("Script ID", this); + insertBeforeButtons(label, false); + + // Add script ID input with auto-completion. + CSMWorld::ColumnBase::Display displayType = CSMWorld::ColumnBase::Display_Script; + mScript = new CSVWidget::DropLineEdit(displayType, this); + mScript->setCompleter(completionManager.getCompleter(displayType).get()); + insertBeforeButtons(mScript, true); + + connect(mScript, SIGNAL (textChanged(const QString&)), this, SLOT (scriptChanged())); +} + +void CSVWorld::StartScriptCreator::cloneMode( + const std::string& originId, + const CSMWorld::UniversalId::Type type) +{ + CSVWorld::GenericCreator::cloneMode(originId, type); + + // Look up cloned record in start scripts table and set script ID text. + CSMWorld::IdTable& table = getStartScriptsTable(); + int column = table.findColumnIndex(CSMWorld::Columns::ColumnId_Id); + mScript->setText(table.data(table.getModelIndex(originId, column)).toString()); +} std::string CSVWorld::StartScriptCreator::getErrors() const { - std::string errors; + std::string scriptId = getId(); - errors = getIdValidatorResult(); - if (errors.length() > 0) - return errors; - else if (getData().getScripts().searchId(getId()) == -1) - errors = "Script ID not found"; - else if (getData().getStartScripts().searchId(getId()) > -1 ) - errors = "Script with this ID already registered as Start Script"; + // Check user input for any errors. + std::string errors; + if (scriptId.empty()) + { + if (!errors.empty()) + { + errors += "
    "; + } + errors += "No Script ID entered"; + } + else if (getData().getScripts().searchId(scriptId) == -1) + { + if (!errors.empty()) + { + errors += "
    "; + } + errors += "Script ID not found"; + } + else if (getData().getStartScripts().searchId(scriptId) > -1) + { + if (!errors.empty()) + { + errors += "
    "; + } + errors += "Script with this ID already registered as Start Script"; + } return errors; } + +void CSVWorld::StartScriptCreator::focus() +{ + mScript->setFocus(); +} + +void CSVWorld::StartScriptCreator::reset() +{ + CSVWorld::GenericCreator::reset(); + mScript->setText(""); +} + +void CSVWorld::StartScriptCreator::scriptChanged() +{ + update(); +} + +CSVWorld::Creator *CSVWorld::StartScriptCreatorFactory::makeCreator( + CSMDoc::Document& document, + const CSMWorld::UniversalId& id) const +{ + return new StartScriptCreator( + document.getData(), + document.getUndoStack(), + id, + document.getIdCompletionManager() + ); +} diff --git a/apps/opencs/view/world/startscriptcreator.hpp b/apps/opencs/view/world/startscriptcreator.hpp index 07fe8ff3d..745dce819 100644 --- a/apps/opencs/view/world/startscriptcreator.hpp +++ b/apps/opencs/view/world/startscriptcreator.hpp @@ -3,23 +3,77 @@ #include "genericcreator.hpp" -namespace CSVWorld { +namespace CSMWorld +{ + class IdCompletionManager; + class IdTable; +} + +namespace CSVWidget +{ + class DropLineEdit; +} +namespace CSVWorld +{ + /// \brief Record creator for start scripts. class StartScriptCreator : public GenericCreator { Q_OBJECT + CSVWidget::DropLineEdit *mScript; + + private: + + /// \return script ID entered by user. + virtual std::string getId() const; + + /// \return reference to table containing start scripts. + CSMWorld::IdTable& getStartScriptsTable() const; + + /// \brief Add user input to command for creating start script. + /// \param command Creation command to configure. + virtual void configureCreateCommand(CSMWorld::CreateCommand& command) const; + public: - StartScriptCreator(CSMWorld::Data& data, QUndoStack& undoStack, - const CSMWorld::UniversalId& id, bool relaxedIdRules = false); + StartScriptCreator( + CSMWorld::Data& data, + QUndoStack& undoStack, + const CSMWorld::UniversalId& id, + CSMWorld::IdCompletionManager& completionManager); + + /// \brief Set script ID input widget to ID of record to be cloned. + /// \param originId Script ID to be cloned. + /// \param type Type of record to be cloned. + virtual void cloneMode( + const std::string& originId, + const CSMWorld::UniversalId::Type type); + + /// \return Formatted error descriptions for current user input. virtual std::string getErrors() const; - ///< Return formatted error descriptions for the current state of the creator. if an empty - /// string is returned, there is no error. - }; -} + /// \brief Set focus to script ID input widget. + virtual void focus(); + + /// \brief Clear script ID input widget. + virtual void reset(); + private slots: + + /// \brief Check user input for any errors. + void scriptChanged(); + }; + /// \brief Creator factory for start script record creator. + class StartScriptCreatorFactory : public CreatorFactoryBase + { + public: + + virtual Creator *makeCreator( + CSMDoc::Document& document, + const CSMWorld::UniversalId& id) const; + }; +} #endif // STARTSCRIPTCREATOR_HPP diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp index 88375caaf..650f344ed 100644 --- a/apps/opencs/view/world/subviews.cpp +++ b/apps/opencs/view/world/subviews.cpp @@ -52,7 +52,7 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) new CSVDoc::SubViewFactoryWithCreator >); manager.add (CSMWorld::UniversalId::Type_StartScripts, - new CSVDoc::SubViewFactoryWithCreator >); + new CSVDoc::SubViewFactoryWithCreator); manager.add (CSMWorld::UniversalId::Type_Cells, new CSVDoc::SubViewFactoryWithCreator >); @@ -136,8 +136,7 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) CreatorFactory > (false)); manager.add (CSMWorld::UniversalId::Type_StartScript, - new CSVDoc::SubViewFactoryWithCreator > (false)); + new CSVDoc::SubViewFactoryWithCreator(false)); manager.add (CSMWorld::UniversalId::Type_Skill, new CSVDoc::SubViewFactoryWithCreator (false)); @@ -177,7 +176,7 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) manager.add (CSMWorld::UniversalId::Type_MetaData, new CSVDoc::SubViewFactory); - + //preview manager.add (CSMWorld::UniversalId::Type_Preview, new CSVDoc::SubViewFactory); } From fbca094dda2a23860a74561dd994de8b0dab33aa Mon Sep 17 00:00:00 2001 From: Rob Cutmore Date: Sun, 24 Jan 2016 20:15:27 -0500 Subject: [PATCH 3024/3725] Fix input validation in StartScriptCreator --- apps/opencs/view/world/startscriptcreator.cpp | 18 +++--------------- apps/opencs/view/world/startscriptcreator.hpp | 2 +- 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/apps/opencs/view/world/startscriptcreator.cpp b/apps/opencs/view/world/startscriptcreator.cpp index 57ac34b8f..7495da035 100644 --- a/apps/opencs/view/world/startscriptcreator.cpp +++ b/apps/opencs/view/world/startscriptcreator.cpp @@ -75,27 +75,15 @@ std::string CSVWorld::StartScriptCreator::getErrors() const std::string errors; if (scriptId.empty()) { - if (!errors.empty()) - { - errors += "
    "; - } - errors += "No Script ID entered"; + errors = "No Script ID entered"; } else if (getData().getScripts().searchId(scriptId) == -1) { - if (!errors.empty()) - { - errors += "
    "; - } - errors += "Script ID not found"; + errors = "Script ID not found"; } else if (getData().getStartScripts().searchId(scriptId) > -1) { - if (!errors.empty()) - { - errors += "
    "; - } - errors += "Script with this ID already registered as Start Script"; + errors = "Script with this ID already registered as Start Script"; } return errors; diff --git a/apps/opencs/view/world/startscriptcreator.hpp b/apps/opencs/view/world/startscriptcreator.hpp index 745dce819..473e2fd5f 100644 --- a/apps/opencs/view/world/startscriptcreator.hpp +++ b/apps/opencs/view/world/startscriptcreator.hpp @@ -50,7 +50,7 @@ namespace CSVWorld const std::string& originId, const CSMWorld::UniversalId::Type type); - /// \return Formatted error descriptions for current user input. + /// \return Error description for current user input. virtual std::string getErrors() const; /// \brief Set focus to script ID input widget. From 0659687bfbdf859414313aed33d9da7cef80efec Mon Sep 17 00:00:00 2001 From: Tobias Kortkamp Date: Mon, 25 Jan 2016 14:13:16 +0100 Subject: [PATCH 3025/3725] Some fixes for building on FreeBSD --- apps/essimporter/converter.hpp | 2 +- apps/essimporter/convertinventory.cpp | 1 + apps/openmw/crashcatcher.cpp | 2 +- apps/openmw/mwmechanics/spells.cpp | 2 +- apps/openmw/mwmechanics/spells.hpp | 2 +- apps/openmw/mwworld/projectilemanager.hpp | 1 + apps/openmw/mwworld/refdata.hpp | 1 + apps/openmw/mwworld/worldimp.cpp | 4 ++++ components/esm/spellstate.cpp | 6 +++--- components/esm/spellstate.hpp | 2 +- components/resource/bulletshape.cpp | 1 + components/sceneutil/lightcontroller.cpp | 1 + components/sceneutil/lightutil.cpp | 1 + 13 files changed, 18 insertions(+), 8 deletions(-) diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index f364e166c..81b2bec14 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -121,7 +121,7 @@ public: { mContext->mPlayer.mObject.mCreatureStats.mLevel = npc.mNpdt52.mLevel; mContext->mPlayerBase = npc; - std::map empty; + std::map empty; // FIXME: player start spells and birthsign spells aren't listed here, // need to fix openmw to account for this for (std::vector::const_iterator it = npc.mSpells.mList.begin(); it != npc.mSpells.mList.end(); ++it) diff --git a/apps/essimporter/convertinventory.cpp b/apps/essimporter/convertinventory.cpp index f476fe1ee..0799c8d11 100644 --- a/apps/essimporter/convertinventory.cpp +++ b/apps/essimporter/convertinventory.cpp @@ -1,6 +1,7 @@ #include "convertinventory.hpp" #include +#include namespace ESSImport { diff --git a/apps/openmw/crashcatcher.cpp b/apps/openmw/crashcatcher.cpp index 0b4ff6304..cafd0e08a 100644 --- a/apps/openmw/crashcatcher.cpp +++ b/apps/openmw/crashcatcher.cpp @@ -24,7 +24,7 @@ #ifndef PR_SET_PTRACER #define PR_SET_PTRACER 0x59616d61 #endif -#elif defined (__APPLE__) +#elif defined (__APPLE__) || defined (__FreeBSD__) #include #endif diff --git a/apps/openmw/mwmechanics/spells.cpp b/apps/openmw/mwmechanics/spells.cpp index a88b6b263..2f87d0446 100644 --- a/apps/openmw/mwmechanics/spells.cpp +++ b/apps/openmw/mwmechanics/spells.cpp @@ -44,7 +44,7 @@ namespace MWMechanics { if (mSpells.find (spell)==mSpells.end()) { - std::map random; + std::map random; // Determine the random magnitudes (unless this is a castable spell, in which case // they will be determined when the spell is cast) diff --git a/apps/openmw/mwmechanics/spells.hpp b/apps/openmw/mwmechanics/spells.hpp index 1b1993d5e..a46988c4c 100644 --- a/apps/openmw/mwmechanics/spells.hpp +++ b/apps/openmw/mwmechanics/spells.hpp @@ -33,7 +33,7 @@ namespace MWMechanics typedef const ESM::Spell* SpellKey; - typedef std::map > TContainer; // ID, + typedef std::map > TContainer; // ID, typedef TContainer::const_iterator TIterator; struct CorprusStats diff --git a/apps/openmw/mwworld/projectilemanager.hpp b/apps/openmw/mwworld/projectilemanager.hpp index 74d4c1dc5..02ac6cb55 100644 --- a/apps/openmw/mwworld/projectilemanager.hpp +++ b/apps/openmw/mwworld/projectilemanager.hpp @@ -3,6 +3,7 @@ #include +#include #include #include diff --git a/apps/openmw/mwworld/refdata.hpp b/apps/openmw/mwworld/refdata.hpp index 28d2dad4c..d87ffdb70 100644 --- a/apps/openmw/mwworld/refdata.hpp +++ b/apps/openmw/mwworld/refdata.hpp @@ -5,6 +5,7 @@ #include "../mwscript/locals.hpp" +#include #include namespace SceneUtil diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index afb5be9d3..37743bceb 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -108,7 +108,11 @@ namespace MWWorld } private: +#ifdef HAVE_UNORDERED_MAP + typedef std::unordered_map LoadersContainer; +#else typedef std::tr1::unordered_map LoadersContainer; +#endif LoadersContainer mLoaders; }; diff --git a/components/esm/spellstate.cpp b/components/esm/spellstate.cpp index 3ed3329b4..8845842e9 100644 --- a/components/esm/spellstate.cpp +++ b/components/esm/spellstate.cpp @@ -12,7 +12,7 @@ namespace ESM { std::string id = esm.getHString(); - std::map random; + std::map random; while (esm.isNextSub("INDX")) { int index; @@ -73,8 +73,8 @@ namespace ESM { esm.writeHNString("SPEL", it->first); - const std::map& random = it->second; - for (std::map::const_iterator rIt = random.begin(); rIt != random.end(); ++rIt) + const std::map& random = it->second; + for (std::map::const_iterator rIt = random.begin(); rIt != random.end(); ++rIt) { esm.writeHNT("INDX", rIt->first); esm.writeHNT("RAND", rIt->second); diff --git a/components/esm/spellstate.hpp b/components/esm/spellstate.hpp index 028e6a387..503c3aea9 100644 --- a/components/esm/spellstate.hpp +++ b/components/esm/spellstate.hpp @@ -28,7 +28,7 @@ namespace ESM float mMagnitude; }; - typedef std::map > TContainer; + typedef std::map > TContainer; TContainer mSpells; std::map > mPermanentSpellEffects; diff --git a/components/resource/bulletshape.cpp b/components/resource/bulletshape.cpp index 968dbe6c6..0cbc63a22 100644 --- a/components/resource/bulletshape.cpp +++ b/components/resource/bulletshape.cpp @@ -1,6 +1,7 @@ #include "bulletshape.hpp" #include +#include #include #include diff --git a/components/sceneutil/lightcontroller.cpp b/components/sceneutil/lightcontroller.cpp index e3ea93843..47575e2e6 100644 --- a/components/sceneutil/lightcontroller.cpp +++ b/components/sceneutil/lightcontroller.cpp @@ -2,6 +2,7 @@ #include +#include #include #include diff --git a/components/sceneutil/lightutil.cpp b/components/sceneutil/lightutil.cpp index 6499c54b1..979d41181 100644 --- a/components/sceneutil/lightutil.cpp +++ b/components/sceneutil/lightutil.cpp @@ -1,5 +1,6 @@ #include "lightutil.hpp" +#include #include #include #include From c1f0aa7260059007262aa1f4d21555fb1827c10b Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 25 Jan 2016 14:55:02 +0100 Subject: [PATCH 3026/3725] added delete selection item to selection mode button menu --- apps/opencs/view/render/cell.cpp | 13 ++++++++++ apps/opencs/view/render/cell.hpp | 4 +++ .../view/render/instanceselectionmode.cpp | 26 +++++++++++++++++++ .../view/render/instanceselectionmode.hpp | 3 +++ apps/opencs/view/render/object.cpp | 5 ++++ apps/opencs/view/render/object.hpp | 2 ++ .../view/render/pagedworldspacewidget.cpp | 17 ++++++++++++ .../view/render/pagedworldspacewidget.hpp | 3 +++ .../view/render/unpagedworldspacewidget.cpp | 6 +++++ .../view/render/unpagedworldspacewidget.hpp | 3 +++ apps/opencs/view/render/worldspacewidget.hpp | 3 +++ 11 files changed, 85 insertions(+) diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index 40981164d..4372018fb 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -276,3 +276,16 @@ bool CSVRender::Cell::isDeleted() const { return mDeleted; } + +std::vector > CSVRender::Cell::getSelection (unsigned int elementMask) const +{ + std::vector > result; + + if (elementMask & Mask_Reference) + for (std::map::const_iterator iter (mObjects.begin()); + iter!=mObjects.end(); ++iter) + if (iter->second->getSelected()) + result.push_back (iter->second->getTag()); + + return result; +} diff --git a/apps/opencs/view/render/cell.hpp b/apps/opencs/view/render/cell.hpp index 59f4cafee..3e51bb334 100644 --- a/apps/opencs/view/render/cell.hpp +++ b/apps/opencs/view/render/cell.hpp @@ -31,6 +31,8 @@ namespace CSMWorld namespace CSVRender { + class TagBase; + class Cell { CSMWorld::Data& mData; @@ -99,6 +101,8 @@ namespace CSVRender CSMWorld::CellCoordinates getCoordinates() const; bool isDeleted() const; + + std::vector > getSelection (unsigned int elementMask) const; }; } diff --git a/apps/opencs/view/render/instanceselectionmode.cpp b/apps/opencs/view/render/instanceselectionmode.cpp index 794a150d2..754123d2d 100644 --- a/apps/opencs/view/render/instanceselectionmode.cpp +++ b/apps/opencs/view/render/instanceselectionmode.cpp @@ -4,7 +4,11 @@ #include #include +#include "../../model/world/idtable.hpp" +#include "../../model/world/commands.hpp" + #include "worldspacewidget.hpp" +#include "object.hpp" bool CSVRender::InstanceSelectionMode::createContextMenu (QMenu *menu) { @@ -12,6 +16,7 @@ bool CSVRender::InstanceSelectionMode::createContextMenu (QMenu *menu) { menu->addAction (mSelectAll); menu->addAction (mDeselectAll); + menu->addAction (mDeleteSelection); } return true; @@ -44,9 +49,11 @@ CSVRender::InstanceSelectionMode::InstanceSelectionMode (CSVWidget::SceneToolbar mSelectAll = new QAction ("Select all Instances", this); mDeselectAll = new QAction ("Clear selection", this); + mDeleteSelection = new QAction ("Delete selection", this); connect (mSelectAll, SIGNAL (triggered ()), this, SLOT (selectAll())); connect (mDeselectAll, SIGNAL (triggered ()), this, SLOT (clearSelection())); + connect (mDeleteSelection, SIGNAL (triggered ()), this, SLOT (deleteSelection())); } void CSVRender::InstanceSelectionMode::selectAll() @@ -58,3 +65,22 @@ void CSVRender::InstanceSelectionMode::clearSelection() { mWorldspaceWidget.clearSelection (Mask_Reference); } + +void CSVRender::InstanceSelectionMode::deleteSelection() +{ + std::vector > selection = + mWorldspaceWidget.getSelection (Mask_Reference); + + CSMWorld::IdTable& referencesTable = + dynamic_cast (*mWorldspaceWidget.getDocument().getData(). + getTableModel (CSMWorld::UniversalId::Type_References)); + + for (std::vector >::iterator iter (selection.begin()); + iter!=selection.end(); ++iter) + { + CSMWorld::DeleteCommand *command = new CSMWorld::DeleteCommand (referencesTable, + static_cast (iter->get())->mObject->getReferenceId()); + + mWorldspaceWidget.getDocument().getUndoStack().push (command); + } +} diff --git a/apps/opencs/view/render/instanceselectionmode.hpp b/apps/opencs/view/render/instanceselectionmode.hpp index 6b3a4e37d..07b774543 100644 --- a/apps/opencs/view/render/instanceselectionmode.hpp +++ b/apps/opencs/view/render/instanceselectionmode.hpp @@ -16,6 +16,7 @@ namespace CSVRender WorldspaceWidget& mWorldspaceWidget; QAction *mSelectAll; QAction *mDeselectAll; + QAction *mDeleteSelection; /// Add context menu items to \a menu. /// @@ -34,6 +35,8 @@ namespace CSVRender void selectAll(); void clearSelection(); + + void deleteSelection(); }; } diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index 1821da059..dcf217a36 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -284,3 +284,8 @@ std::string CSVRender::Object::getReferenceableId() const { return mReferenceableId; } + +osg::ref_ptr CSVRender::Object::getTag() const +{ + return static_cast (mBaseNode->getUserData()); +} diff --git a/apps/opencs/view/render/object.hpp b/apps/opencs/view/render/object.hpp index e7638e7a9..4a89fe201 100644 --- a/apps/opencs/view/render/object.hpp +++ b/apps/opencs/view/render/object.hpp @@ -114,6 +114,8 @@ namespace CSVRender std::string getReferenceId() const; std::string getReferenceableId() const; + + osg::ref_ptr getTag() const; }; } diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index ccb3efb1d..ef5c4e868 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -529,6 +529,23 @@ std::string CSVRender::PagedWorldspaceWidget::getCellId (const osg::Vec3f& point return cellCoordinates.getId (mWorldspace); } +std::vector > CSVRender::PagedWorldspaceWidget::getSelection ( + unsigned int elementMask) const +{ + std::vector > result; + + for (std::map::const_iterator iter = mCells.begin(); + iter!=mCells.end(); ++iter) + { + std::vector > cellResult = + iter->second->getSelection (elementMask); + + result.insert (result.end(), cellResult.begin(), cellResult.end()); + } + + return result; +} + CSVWidget::SceneToolToggle *CSVRender::PagedWorldspaceWidget::makeControlVisibilitySelector ( CSVWidget::SceneToolbar *parent) { diff --git a/apps/opencs/view/render/pagedworldspacewidget.hpp b/apps/opencs/view/render/pagedworldspacewidget.hpp index 3f9e605af..bd4233a64 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.hpp +++ b/apps/opencs/view/render/pagedworldspacewidget.hpp @@ -103,6 +103,9 @@ namespace CSVRender virtual std::string getCellId (const osg::Vec3f& point) const; + virtual std::vector > getSelection (unsigned int elementMask) + const; + protected: virtual void addVisibilitySelectorButtons (CSVWidget::SceneToolToggle2 *tool); diff --git a/apps/opencs/view/render/unpagedworldspacewidget.cpp b/apps/opencs/view/render/unpagedworldspacewidget.cpp index 48180f866..a026a2473 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.cpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.cpp @@ -119,6 +119,12 @@ std::string CSVRender::UnpagedWorldspaceWidget::getCellId (const osg::Vec3f& poi return mCellId; } +std::vector > CSVRender::UnpagedWorldspaceWidget::getSelection ( + unsigned int elementMask) const +{ + return mCell->getSelection (elementMask); +} + void CSVRender::UnpagedWorldspaceWidget::referenceableDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) { diff --git a/apps/opencs/view/render/unpagedworldspacewidget.hpp b/apps/opencs/view/render/unpagedworldspacewidget.hpp index 8971f22a8..3aea8dee4 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.hpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.hpp @@ -51,6 +51,9 @@ namespace CSVRender virtual std::string getCellId (const osg::Vec3f& point) const; + virtual std::vector > getSelection (unsigned int elementMask) + const; + private: virtual void referenceableDataChanged (const QModelIndex& topLeft, diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp index 13e66b7f0..cd031fcba 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -143,6 +143,9 @@ namespace CSVRender virtual std::string getCellId (const osg::Vec3f& point) const = 0; + virtual std::vector > getSelection (unsigned int elementMask) + const = 0; + protected: /// Visual elements in a scene From 790367b980ef6980b62abb30b61890100c7aca60 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 25 Jan 2016 16:12:20 +0100 Subject: [PATCH 3027/3725] fixed object removal via setting state to delete --- apps/opencs/view/render/cell.cpp | 36 ++++++++++++++++++++++---------- apps/opencs/view/render/cell.hpp | 4 ++++ 2 files changed, 29 insertions(+), 11 deletions(-) diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index 4372018fb..758498de1 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -22,11 +22,18 @@ bool CSVRender::Cell::removeObject (const std::string& id) if (iter==mObjects.end()) return false; - delete iter->second; - mObjects.erase (iter); + removeObject (iter); return true; } +std::map::iterator CSVRender::Cell::removeObject ( + std::map::iterator iter) +{ + delete iter->second; + mObjects.erase (iter++); + return iter; +} + bool CSVRender::Cell::addObjects (int start, int end) { bool modified = false; @@ -161,8 +168,8 @@ bool CSVRender::Cell::referenceDataChanged (const QModelIndex& topLeft, // perform update and remove where needed bool modified = false; - for (std::map::iterator iter (mObjects.begin()); - iter!=mObjects.end(); ++iter) + std::map::iterator iter = mObjects.begin(); + while (iter!=mObjects.end()) { if (iter->second->referenceDataChanged (topLeft, bottomRight)) modified = true; @@ -171,23 +178,30 @@ bool CSVRender::Cell::referenceDataChanged (const QModelIndex& topLeft, if (iter2!=ids.end()) { - if (iter2->second) + bool deleted = iter2->second; + ids.erase (iter2); + + if (deleted) { - removeObject (iter->first); + iter = removeObject (iter); modified = true; + continue; } - - ids.erase (iter2); } + + ++iter; } // add new objects for (std::map::iterator iter (ids.begin()); iter!=ids.end(); ++iter) { - mObjects.insert (std::make_pair ( - iter->first, new Object (mData, mCellNode, iter->first, false))); + if (!iter->second) + { + mObjects.insert (std::make_pair ( + iter->first, new Object (mData, mCellNode, iter->first, false))); - modified = true; + modified = true; + } } return modified; diff --git a/apps/opencs/view/render/cell.hpp b/apps/opencs/view/render/cell.hpp index 3e51bb334..9f062b439 100644 --- a/apps/opencs/view/render/cell.hpp +++ b/apps/opencs/view/render/cell.hpp @@ -49,6 +49,10 @@ namespace CSVRender /// \return Was the object deleted? bool removeObject (const std::string& id); + // Remove object and return iterator to next object. + std::map::iterator removeObject ( + std::map::iterator iter); + /// Add objects from reference table that are within this cell. /// /// \return Have any objects been added? From 39e1b06101ab6947fec43470fa0225060a9cc80b Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 25 Jan 2016 16:18:55 +0100 Subject: [PATCH 3028/3725] fixed deletion of objects that are selected (was leaving a node behind) --- apps/opencs/view/render/object.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index dcf217a36..b980b658a 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -187,6 +187,7 @@ CSVRender::Object::~Object() clear(); mParentNode->removeChild(mBaseNode); + mParentNode->removeChild(mOutline); } void CSVRender::Object::setSelected(bool selected) From b393d34ebb84f056a20aaa495c5b9509d2334837 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 25 Jan 2016 16:39:20 +0100 Subject: [PATCH 3029/3725] updated credits file --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index bfbd14a5b..83a625406 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -113,6 +113,7 @@ Programmers Stefan Galowicz (bogglez) Stanislav Bobrov (Jiub) Sylvain Thesnieres (Garvek) + t6 terrorfisch Thomas Luppi (Digmaster) Tom Mason (wheybags) From 48f53e23bfaba6ea8aa32536aeb5386e5e03a4c3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 25 Jan 2016 16:59:31 +0100 Subject: [PATCH 3030/3725] Allow alternate mesh formats for marker_error --- components/resource/scenemanager.cpp | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index 1d1c5a365..e14282649 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -201,10 +201,22 @@ namespace Resource } catch (std::exception& e) { - std::cerr << "Failed to load '" << name << "': " << e.what() << ", using marker_error.nif instead" << std::endl; - Files::IStreamPtr file = mVFS->get("meshes/marker_error.nif"); - normalized = "meshes/marker_error.nif"; - loaded = load(file, normalized, mTextureManager, mNifFileManager); + static const char * const sMeshTypes[] = { "nif", "osg", "osgt", "osgb", "osgx", "osg2", 0 }; + + for (unsigned int i=0; iexists(normalized)) + { + std::cerr << "Failed to load '" << name << "': " << e.what() << ", using marker_error." << sMeshTypes[i] << " instead" << std::endl; + Files::IStreamPtr file = mVFS->get(normalized); + loaded = load(file, normalized, mTextureManager, mNifFileManager); + break; + } + } + + if (!loaded) + throw; } osgDB::Registry::instance()->getOrCreateSharedStateManager()->share(loaded.get()); From fc6fe9acfb3f70d65c97fc45d9d3b0a8b1b16236 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 25 Jan 2016 18:52:20 +0100 Subject: [PATCH 3031/3725] Do not crash ModVertexAlphaVisitor when there are no vertex colors --- apps/openmw/mwrender/sky.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index efe797336..692e3655a 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -374,8 +374,13 @@ public: } else if (mMeshType == 2) { - osg::Vec4Array* origColors = static_cast(geom->getColorArray()); - alpha = ((*origColors)[i].x() == 1.f) ? 1.f : 0.f; + if (geom->getColorArray()) + { + osg::Vec4Array* origColors = static_cast(geom->getColorArray()); + alpha = ((*origColors)[i].x() == 1.f) ? 1.f : 0.f; + } + else + alpha = 1.f; } (*colors)[i] = osg::Vec4f(0.f, 0.f, 0.f, alpha); From aec8c3846103da0d65ca772d859c501f2d6d9c57 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 25 Jan 2016 21:03:33 +0100 Subject: [PATCH 3032/3725] Move observer_ptr include where it belongs --- apps/openmw/mwrender/sky.cpp | 1 + apps/openmw/mwworld/projectilemanager.hpp | 1 - components/sceneutil/lightcontroller.cpp | 1 - components/sceneutil/lightmanager.hpp | 1 + components/sceneutil/lightutil.cpp | 1 - 5 files changed, 2 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 692e3655a..513fc74a3 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include diff --git a/apps/openmw/mwworld/projectilemanager.hpp b/apps/openmw/mwworld/projectilemanager.hpp index 02ac6cb55..74d4c1dc5 100644 --- a/apps/openmw/mwworld/projectilemanager.hpp +++ b/apps/openmw/mwworld/projectilemanager.hpp @@ -3,7 +3,6 @@ #include -#include #include #include diff --git a/components/sceneutil/lightcontroller.cpp b/components/sceneutil/lightcontroller.cpp index 47575e2e6..e3ea93843 100644 --- a/components/sceneutil/lightcontroller.cpp +++ b/components/sceneutil/lightcontroller.cpp @@ -2,7 +2,6 @@ #include -#include #include #include diff --git a/components/sceneutil/lightmanager.hpp b/components/sceneutil/lightmanager.hpp index 07b3b4a62..0d8610ead 100644 --- a/components/sceneutil/lightmanager.hpp +++ b/components/sceneutil/lightmanager.hpp @@ -5,6 +5,7 @@ #include #include +#include namespace SceneUtil { diff --git a/components/sceneutil/lightutil.cpp b/components/sceneutil/lightutil.cpp index 979d41181..6499c54b1 100644 --- a/components/sceneutil/lightutil.cpp +++ b/components/sceneutil/lightutil.cpp @@ -1,6 +1,5 @@ #include "lightutil.hpp" -#include #include #include #include From d9290b0ee0fa25c6655a4b054f979ea6ed186f07 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 25 Jan 2016 21:13:38 +0100 Subject: [PATCH 3033/3725] Array fix --- components/resource/scenemanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index e14282649..43ece41f3 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -201,7 +201,7 @@ namespace Resource } catch (std::exception& e) { - static const char * const sMeshTypes[] = { "nif", "osg", "osgt", "osgb", "osgx", "osg2", 0 }; + static const char * const sMeshTypes[] = { "nif", "osg", "osgt", "osgb", "osgx", "osg2" }; for (unsigned int i=0; i Date: Tue, 26 Jan 2016 10:51:47 +0100 Subject: [PATCH 3034/3725] minor improvements to wording of instance selection menu items --- apps/opencs/view/render/instanceselectionmode.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/render/instanceselectionmode.cpp b/apps/opencs/view/render/instanceselectionmode.cpp index 754123d2d..2fd91c8e2 100644 --- a/apps/opencs/view/render/instanceselectionmode.cpp +++ b/apps/opencs/view/render/instanceselectionmode.cpp @@ -47,9 +47,9 @@ CSVRender::InstanceSelectionMode::InstanceSelectionMode (CSVWidget::SceneToolbar "" "Not implemented yet"); - mSelectAll = new QAction ("Select all Instances", this); + mSelectAll = new QAction ("Select all instances", this); mDeselectAll = new QAction ("Clear selection", this); - mDeleteSelection = new QAction ("Delete selection", this); + mDeleteSelection = new QAction ("Delete selected instances", this); connect (mSelectAll, SIGNAL (triggered ()), this, SLOT (selectAll())); connect (mDeselectAll, SIGNAL (triggered ()), this, SLOT (clearSelection())); From 1d0ef97bf6bc566fa817e51179467a854c925365 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 26 Jan 2016 11:31:37 +0100 Subject: [PATCH 3035/3725] added select all of same ID item to selection mode button menu --- apps/opencs/view/render/cell.cpp | 22 +++++++++++++++++++ apps/opencs/view/render/cell.hpp | 4 ++++ .../view/render/instanceselectionmode.cpp | 9 +++++++- .../view/render/instanceselectionmode.hpp | 3 +++ .../view/render/pagedworldspacewidget.cpp | 9 ++++++++ .../view/render/pagedworldspacewidget.hpp | 6 +++++ .../view/render/unpagedworldspacewidget.cpp | 6 +++++ .../view/render/unpagedworldspacewidget.hpp | 6 +++++ apps/opencs/view/render/worldspacewidget.hpp | 6 +++++ 9 files changed, 70 insertions(+), 1 deletion(-) diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index 758498de1..bd85c8a14 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -263,6 +263,28 @@ void CSVRender::Cell::setSelection (int elementMask, Selection mode) } } +void CSVRender::Cell::selectAllWithSameParentId (int elementMask) +{ + std::set ids; + + for (std::map::const_iterator iter (mObjects.begin()); + iter!=mObjects.end(); ++iter) + { + if (iter->second->getSelected()) + ids.insert (iter->second->getReferenceableId()); + } + + for (std::map::const_iterator iter (mObjects.begin()); + iter!=mObjects.end(); ++iter) + { + if (!iter->second->getSelected() && + ids.find (iter->second->getReferenceableId())!=ids.end()) + { + iter->second->setSelected (true); + } + } +} + void CSVRender::Cell::setCellArrows (int mask) { for (int i=0; i<4; ++i) diff --git a/apps/opencs/view/render/cell.hpp b/apps/opencs/view/render/cell.hpp index 9f062b439..85b9bf21b 100644 --- a/apps/opencs/view/render/cell.hpp +++ b/apps/opencs/view/render/cell.hpp @@ -99,6 +99,10 @@ namespace CSVRender void setSelection (int elementMask, Selection mode); + // Select everything that references the same ID as at least one of the elements + // already selected + void selectAllWithSameParentId (int elementMask); + void setCellArrows (int mask); /// Returns 0, 0 in case of an unpaged cell. diff --git a/apps/opencs/view/render/instanceselectionmode.cpp b/apps/opencs/view/render/instanceselectionmode.cpp index 2fd91c8e2..5c3aaa8d1 100644 --- a/apps/opencs/view/render/instanceselectionmode.cpp +++ b/apps/opencs/view/render/instanceselectionmode.cpp @@ -16,6 +16,7 @@ bool CSVRender::InstanceSelectionMode::createContextMenu (QMenu *menu) { menu->addAction (mSelectAll); menu->addAction (mDeselectAll); + menu->addAction (mSelectSame); menu->addAction (mDeleteSelection); } @@ -50,10 +51,11 @@ CSVRender::InstanceSelectionMode::InstanceSelectionMode (CSVWidget::SceneToolbar mSelectAll = new QAction ("Select all instances", this); mDeselectAll = new QAction ("Clear selection", this); mDeleteSelection = new QAction ("Delete selected instances", this); - + mSelectSame = new QAction ("Extend selection to instances with same object ID", this); connect (mSelectAll, SIGNAL (triggered ()), this, SLOT (selectAll())); connect (mDeselectAll, SIGNAL (triggered ()), this, SLOT (clearSelection())); connect (mDeleteSelection, SIGNAL (triggered ()), this, SLOT (deleteSelection())); + connect (mSelectSame, SIGNAL (triggered ()), this, SLOT (selectSame())); } void CSVRender::InstanceSelectionMode::selectAll() @@ -84,3 +86,8 @@ void CSVRender::InstanceSelectionMode::deleteSelection() mWorldspaceWidget.getDocument().getUndoStack().push (command); } } + +void CSVRender::InstanceSelectionMode::selectSame() +{ + mWorldspaceWidget.selectAllWithSameParentId (Mask_Reference); +} diff --git a/apps/opencs/view/render/instanceselectionmode.hpp b/apps/opencs/view/render/instanceselectionmode.hpp index 07b774543..cac2ca8c2 100644 --- a/apps/opencs/view/render/instanceselectionmode.hpp +++ b/apps/opencs/view/render/instanceselectionmode.hpp @@ -17,6 +17,7 @@ namespace CSVRender QAction *mSelectAll; QAction *mDeselectAll; QAction *mDeleteSelection; + QAction *mSelectSame; /// Add context menu items to \a menu. /// @@ -37,6 +38,8 @@ namespace CSVRender void clearSelection(); void deleteSelection(); + + void selectSame(); }; } diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index ef5c4e868..d71446d0b 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -518,6 +518,15 @@ void CSVRender::PagedWorldspaceWidget::selectAll (int elementMask) flagAsModified(); } +void CSVRender::PagedWorldspaceWidget::selectAllWithSameParentId (int elementMask) +{ + for (std::map::iterator iter = mCells.begin(); + iter!=mCells.end(); ++iter) + iter->second->selectAllWithSameParentId (elementMask); + + flagAsModified(); +} + std::string CSVRender::PagedWorldspaceWidget::getCellId (const osg::Vec3f& point) const { const int cellSize = 8192; diff --git a/apps/opencs/view/render/pagedworldspacewidget.hpp b/apps/opencs/view/render/pagedworldspacewidget.hpp index bd4233a64..419a2a46a 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.hpp +++ b/apps/opencs/view/render/pagedworldspacewidget.hpp @@ -101,6 +101,12 @@ namespace CSVRender /// \param elementMask Elements to be affected by the select operation virtual void selectAll (int elementMask); + // Select everything that references the same ID as at least one of the elements + // already selected + // + /// \param elementMask Elements to be affected by the select operation + virtual void selectAllWithSameParentId (int elementMask); + virtual std::string getCellId (const osg::Vec3f& point) const; virtual std::vector > getSelection (unsigned int elementMask) diff --git a/apps/opencs/view/render/unpagedworldspacewidget.cpp b/apps/opencs/view/render/unpagedworldspacewidget.cpp index a026a2473..8d65c3694 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.cpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.cpp @@ -114,6 +114,12 @@ void CSVRender::UnpagedWorldspaceWidget::selectAll (int elementMask) flagAsModified(); } +void CSVRender::UnpagedWorldspaceWidget::selectAllWithSameParentId (int elementMask) +{ + mCell->selectAllWithSameParentId (elementMask); + flagAsModified(); +} + std::string CSVRender::UnpagedWorldspaceWidget::getCellId (const osg::Vec3f& point) const { return mCellId; diff --git a/apps/opencs/view/render/unpagedworldspacewidget.hpp b/apps/opencs/view/render/unpagedworldspacewidget.hpp index 3aea8dee4..a4c517948 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.hpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.hpp @@ -49,6 +49,12 @@ namespace CSVRender /// \param elementMask Elements to be affected by the select operation virtual void selectAll (int elementMask); + // Select everything that references the same ID as at least one of the elements + // already selected + // + /// \param elementMask Elements to be affected by the select operation + virtual void selectAllWithSameParentId (int elementMask); + virtual std::string getCellId (const osg::Vec3f& point) const; virtual std::vector > getSelection (unsigned int elementMask) diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp index cd031fcba..ac6426b42 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -130,6 +130,12 @@ namespace CSVRender /// \param elementMask Elements to be affected by the select operation virtual void selectAll (int elementMask) = 0; + // Select everything that references the same ID as at least one of the elements + // already selected + // + /// \param elementMask Elements to be affected by the select operation + virtual void selectAllWithSameParentId (int elementMask) = 0; + /// Return the next intersection point with scene elements matched by /// \a interactionMask based on \a localPos and the camera vector. /// If there is no such point, instead a point "in front" of \a localPos will be From 4caf44f06156e91920d4e931a617ea8c93693245 Mon Sep 17 00:00:00 2001 From: Rob Cutmore Date: Tue, 26 Jan 2016 07:48:55 -0500 Subject: [PATCH 3036/3725] Remove unused code in apps/opencs/view/world/table files --- apps/opencs/view/world/table.cpp | 7 ------- apps/opencs/view/world/table.hpp | 2 -- 2 files changed, 9 deletions(-) diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index 26746e8c9..45e50dba7 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -2,7 +2,6 @@ #include #include -#include #include #include #include @@ -12,7 +11,6 @@ #include "../../model/doc/document.hpp" -#include "../../model/world/data.hpp" #include "../../model/world/commands.hpp" #include "../../model/world/infotableproxymodel.hpp" #include "../../model/world/idtableproxymodel.hpp" @@ -20,13 +18,10 @@ #include "../../model/world/idtable.hpp" #include "../../model/world/record.hpp" #include "../../model/world/columns.hpp" -#include "../../model/world/tablemimedata.hpp" -#include "../../model/world/tablemimedata.hpp" #include "../../model/world/commanddispatcher.hpp" #include "../../model/prefs/state.hpp" -#include "recordstatusdelegate.hpp" #include "tableeditidaction.hpp" #include "util.hpp" @@ -339,8 +334,6 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id, connect (mProxyModel, SIGNAL (rowsRemoved (const QModelIndex&, int, int)), this, SLOT (tableSizeUpdate())); - //connect (mProxyModel, SIGNAL (rowsInserted (const QModelIndex&, int, int)), - // this, SLOT (rowsInsertedEvent(const QModelIndex&, int, int))); connect (mProxyModel, SIGNAL (rowAdded (const std::string &)), this, SLOT (rowAdded (const std::string &))); diff --git a/apps/opencs/view/world/table.hpp b/apps/opencs/view/world/table.hpp index 53249f66f..768ff185d 100644 --- a/apps/opencs/view/world/table.hpp +++ b/apps/opencs/view/world/table.hpp @@ -11,7 +11,6 @@ #include "../../model/world/universalid.hpp" #include "dragrecordtable.hpp" -class QUndoStack; class QAction; namespace CSMDoc @@ -21,7 +20,6 @@ namespace CSMDoc namespace CSMWorld { - class Data; class IdTableProxyModel; class IdTableBase; class CommandDispatcher; From d43315fe4e4869fc026587a1cd468a4bf485dfde Mon Sep 17 00:00:00 2001 From: Rob Cutmore Date: Thu, 28 Jan 2016 06:28:31 -0500 Subject: [PATCH 3037/3725] Add script editor line wrapping (Feature #2926) Adds line wrapping for script editor and associated entry in settings window. No line wrapping remains the default. --- apps/opencs/model/prefs/state.cpp | 2 ++ apps/opencs/view/world/scriptedit.cpp | 51 +++++++++++++++++++-------- apps/opencs/view/world/scriptedit.hpp | 10 +++++- 3 files changed, 48 insertions(+), 15 deletions(-) diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index 859fabd11..fd777b133 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -133,6 +133,8 @@ void CSMPrefs::State::declare() declareBool ("show-linenum", "Show Line Numbers", true). setTooltip ("Show line numbers to the left of the script editor window." "The current row and column numbers of the text cursor are shown at the bottom."); + declareBool ("wrap-lines", "Wrap Lines", false). + setTooltip ("Wrap lines longer than width of script editor."); declareBool ("mono-font", "Use monospace font", true); EnumValue warningsNormal ("Normal", "Report warnings as warning"); declareEnum ("warnings", "Warning Mode", warningsNormal). diff --git a/apps/opencs/view/world/scriptedit.cpp b/apps/opencs/view/world/scriptedit.cpp index 9f1abcf97..d0146445a 100644 --- a/apps/opencs/view/world/scriptedit.cpp +++ b/apps/opencs/view/world/scriptedit.cpp @@ -38,20 +38,20 @@ bool CSVWorld::ScriptEdit::event (QEvent *event) return QPlainTextEdit::event (event); } -CSVWorld::ScriptEdit::ScriptEdit (const CSMDoc::Document& document, ScriptHighlighter::Mode mode, - QWidget* parent) - : QPlainTextEdit (parent), - mChangeLocked (0), +CSVWorld::ScriptEdit::ScriptEdit( + const CSMDoc::Document& document, + ScriptHighlighter::Mode mode, + QWidget* parent +) : QPlainTextEdit(parent), + mChangeLocked(0), mShowLineNum(false), mLineNumberArea(0), mDefaultFont(font()), mMonoFont(QFont("Monospace")), - mDocument (document), + mDocument(document), mWhiteListQoutes("^[a-z|_]{1}[a-z|0-9|_]{0,}$", Qt::CaseInsensitive) - { -// setAcceptRichText (false); - setLineWrapMode (QPlainTextEdit::NoWrap); + wrapLines(false); setTabStopWidth (4); setUndoRedoEnabled (false); // we use OpenCS-wide undo/redo instead @@ -194,14 +194,37 @@ bool CSVWorld::ScriptEdit::stringNeedsQuote (const std::string& id) const return !(string.contains(mWhiteListQoutes)); } -void CSVWorld::ScriptEdit::settingChanged (const CSMPrefs::Setting *setting) +void CSVWorld::ScriptEdit::wrapLines(bool wrap) +{ + if (wrap) + { + setLineWrapMode(QPlainTextEdit::WidgetWidth); + } + else + { + setLineWrapMode(QPlainTextEdit::NoWrap); + } +} + +void CSVWorld::ScriptEdit::settingChanged(const CSMPrefs::Setting *setting) { - if (mHighlighter->settingChanged (setting)) + // Determine which setting was changed. + if (mHighlighter->settingChanged(setting)) + { updateHighlighting(); - else if (*setting=="Scripts/mono-font") - setFont (setting->isTrue() ? mMonoFont : mDefaultFont); - else if (*setting=="Scripts/show-linenum") - showLineNum (setting->isTrue()); + } + else if (*setting == "Scripts/mono-font") + { + setFont(setting->isTrue() ? mMonoFont : mDefaultFont); + } + else if (*setting == "Scripts/show-linenum") + { + showLineNum(setting->isTrue()); + } + else if (*setting == "Scripts/wrap-lines") + { + wrapLines(setting->isTrue()); + } } void CSVWorld::ScriptEdit::idListChanged() diff --git a/apps/opencs/view/world/scriptedit.hpp b/apps/opencs/view/world/scriptedit.hpp index 941a6295d..1f03f050a 100644 --- a/apps/opencs/view/world/scriptedit.hpp +++ b/apps/opencs/view/world/scriptedit.hpp @@ -22,6 +22,7 @@ namespace CSVWorld { class LineNumberArea; + /// \brief Editor for scripts. class ScriptEdit : public QPlainTextEdit { Q_OBJECT @@ -77,6 +78,7 @@ namespace CSVWorld virtual void resizeEvent(QResizeEvent *e); private: + QVector mAllowedTypes; const CSMDoc::Document& mDocument; const QRegExp mWhiteListQoutes; @@ -89,9 +91,15 @@ namespace CSVWorld bool stringNeedsQuote(const std::string& id) const; + /// \brief Turn line wrapping in script editor on or off. + /// \param wrap Whether or not to wrap lines. + void wrapLines(bool wrap); + private slots: - void settingChanged (const CSMPrefs::Setting *setting); + /// \brief Update editor when related setting is changed. + /// \param setting Setting that was changed. + void settingChanged(const CSMPrefs::Setting *setting); void idListChanged(); From 776c715ccd419f1e77a8445e2ddd31692efcc942 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Fri, 29 Jan 2016 17:00:18 +0100 Subject: [PATCH 3038/3725] Move NoTraverseCallback to mwrender/util.hpp --- apps/openmw/mwrender/renderingmanager.cpp | 10 +--------- apps/openmw/mwrender/util.hpp | 11 ++++++++++- apps/openmw/mwrender/water.cpp | 11 +---------- 3 files changed, 12 insertions(+), 20 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 61ce626fd..c8d0925b0 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -42,6 +42,7 @@ #include "camera.hpp" #include "water.hpp" #include "terrainstorage.hpp" +#include "util.hpp" namespace MWRender { @@ -504,15 +505,6 @@ namespace MWRender mutable bool mDone; }; - - class NoTraverseCallback : public osg::NodeCallback - { - public: - virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) - { - } - }; - void RenderingManager::screenshot(osg::Image *image, int w, int h) { osg::ref_ptr rttCamera (new osg::Camera); diff --git a/apps/openmw/mwrender/util.hpp b/apps/openmw/mwrender/util.hpp index d078f0d98..815e34596 100644 --- a/apps/openmw/mwrender/util.hpp +++ b/apps/openmw/mwrender/util.hpp @@ -1,6 +1,7 @@ #ifndef OPENMW_MWRENDER_UTIL_H #define OPENMW_MWRENDER_UTIL_H +#include #include #include @@ -16,9 +17,17 @@ namespace Resource namespace MWRender { - void overrideTexture(const std::string& texture, Resource::ResourceSystem* resourceSystem, osg::ref_ptr node); + // Node callback to entirely skip the traversal. + class NoTraverseCallback : public osg::NodeCallback + { + public: + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) + { + // no traverse() + } + }; } #endif diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 1b19246f5..b2bef7122 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -41,6 +41,7 @@ #include "vismask.hpp" #include "ripplesimulation.hpp" #include "renderbin.hpp" +#include "util.hpp" namespace { @@ -210,16 +211,6 @@ private: osg::Plane mPlane; }; -// Node callback to entirely skip the traversal. -class NoTraverseCallback : public osg::NodeCallback -{ -public: - virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) - { - // no traverse() - } -}; - /// Moves water mesh away from the camera slightly if the camera gets too close on the Z axis. /// The offset works around graphics artifacts that occured with the GL_DEPTH_CLAMP when the camera gets extremely close to the mesh (seen on NVIDIA at least). /// Must be added as a Cull callback. From 2fed863941ca4e21ade52413d79869bc2e07ad12 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 30 Jan 2016 21:17:56 +0100 Subject: [PATCH 3039/3725] Use the travis-ci status badge directly instead of the shields.io version --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b55a89945..6095fc378 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ OpenMW ====== -[![Build Status](https://img.shields.io/travis/OpenMW/openmw.svg)](https://travis-ci.org/OpenMW/openmw) [![Build status](https://ci.appveyor.com/api/projects/status/e6bqw8oouy8ufd46?svg=true)](https://ci.appveyor.com/project/ace13/openmw) [![Coverity Scan Build Status](https://scan.coverity.com/projects/3740/badge.svg)](https://scan.coverity.com/projects/3740) +[![Build Status](https://api.travis-ci.org/OpenMW/openmw.svg)](hgttps://travis-ci.org/OpenMW/openmw) [![Build status](https://ci.appveyor.com/api/projects/status/e6bqw8oouy8ufd46?svg=true)](https://ci.appveyor.com/project/ace13/openmw) [![Coverity Scan Build Status](https://scan.coverity.com/projects/3740/badge.svg)](https://scan.coverity.com/projects/3740) OpenMW is a recreation of 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. From ad748700d5a814cbbe576091897d5b028181a751 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 30 Jan 2016 23:14:17 +0100 Subject: [PATCH 3040/3725] Update badges --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6095fc378..9de814fd0 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ OpenMW ====== -[![Build Status](https://api.travis-ci.org/OpenMW/openmw.svg)](hgttps://travis-ci.org/OpenMW/openmw) [![Build status](https://ci.appveyor.com/api/projects/status/e6bqw8oouy8ufd46?svg=true)](https://ci.appveyor.com/project/ace13/openmw) [![Coverity Scan Build Status](https://scan.coverity.com/projects/3740/badge.svg)](https://scan.coverity.com/projects/3740) +[![Build Status](https://api.travis-ci.org/OpenMW/openmw.svg)](https://travis-ci.org/OpenMW/openmw) [![Build status](https://ci.appveyor.com/api/projects/status/e6bqw8oouy8ufd46?svg=true)](https://ci.appveyor.com/project/scrawl/openmw) [![Coverity Scan Build Status](https://scan.coverity.com/projects/3740/badge.svg)](https://scan.coverity.com/projects/3740) OpenMW is a recreation of 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. From d28e7db65cce9b437f2594a0295a5e7fb3122aaa Mon Sep 17 00:00:00 2001 From: Rob Cutmore Date: Sun, 31 Jan 2016 08:45:05 -0500 Subject: [PATCH 3041/3725] Fix tooltip spelling errors in WorldspaceWidget --- apps/opencs/view/render/worldspacewidget.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index af90af50c..6ba6e9543 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -125,16 +125,16 @@ CSVWidget::SceneToolMode *CSVRender::WorldspaceWidget::makeNavigationSelector ( "First Person" "
    • Mouse-Look while holding the left button
    • " "
    • WASD movement keys
    • " - "
    • Mouse wheel moves the camera forawrd/backward
    • " - "
    • Stafing (also vertically) by holding the left mouse button and control
    • " + "
    • Mouse wheel moves the camera forward/backward
    • " + "
    • Strafing (also vertically) by holding the left mouse button and control
    • " "
    • Camera is held upright
    • " "
    • Hold shift to speed up movement
    • " "
    "); tool->addButton (":scenetoolbar/free-camera", "free", "Free Camera" "
    • Mouse-Look while holding the left button
    • " - "
    • Stafing (also vertically) via WASD or by holding the left mouse button and control
    • " - "
    • Mouse wheel moves the camera forawrd/backward
    • " + "
    • Strafing (also vertically) via WASD or by holding the left mouse button and control
    • " + "
    • Mouse wheel moves the camera forward/backward
    • " "
    • Roll camera with Q and E keys
    • " "
    • Hold shift to speed up movement
    • " "
    "); @@ -144,7 +144,7 @@ CSVWidget::SceneToolMode *CSVRender::WorldspaceWidget::makeNavigationSelector ( "
  • Rotate around the centre point via WASD or by moving the mouse while holding the left button
  • " "
  • Mouse wheel moves camera away or towards centre point but can not pass through it
  • " "
  • Roll camera with Q and E keys
  • " - "
  • Stafing (also vertically) by holding the left mouse button and control (includes relocation of the centre point)
  • " + "
  • Strafing (also vertically) by holding the left mouse button and control (includes relocation of the centre point)
  • " "
  • Hold shift to speed up movement
  • " ""); From d12f24c32166c891f403accce717f9190dee8134 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 26 Jan 2016 19:41:05 +0100 Subject: [PATCH 3042/3725] Fix typo --- apps/opencs/model/prefs/state.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index fd777b133..772047961 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -140,7 +140,7 @@ void CSMPrefs::State::declare() declareEnum ("warnings", "Warning Mode", warningsNormal). addValue ("Ignore", "Do not report warning"). addValue (warningsNormal). - addValue ("Strcit", "Promote warning to an error"); + addValue ("Strict", "Promote warning to an error"); declareBool ("toolbar", "Show toolbar", true); declareInt ("compile-delay", "Delay between updating of source errors", 100). setTooltip ("Delay in milliseconds"). From 6b48acaf0e29232150c9beaf3faaf4fe97c44672 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 1 Feb 2016 21:01:17 +0100 Subject: [PATCH 3043/3725] Don't optimize TriShapes with controllers (Fixes #3143) --- components/nifosg/nifloader.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 5c28bbc7e..f4dae52c3 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -394,7 +394,10 @@ namespace NifOsg if (node->getDataVariance() == osg::Object::STATIC // For TriShapes, we can only collapse the node, but not completely remove it, // if the link to animated collision shapes is supposed to stay intact. - && (nifNode->recType != Nif::RC_NiTriShape || !skipMeshes)) + && (nifNode->recType != Nif::RC_NiTriShape || !skipMeshes) + // Don't optimize drawables with controllers, that creates issues when we want to deep copy controllers without deep copying the drawable that holds the controller. + // A deep copy of controllers may be needed to independently animate multiple copies of the same mesh. + && !node->getUpdateCallback()) { if (node->getNumParents() && nifNode->trafo.isIdentity()) { From 8360cccce7c2b95144b3eec9a607a253db7af63d Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 1 Feb 2016 21:02:48 +0100 Subject: [PATCH 3044/3725] Don't clone Drawable UpdateCallbacks twice The Drawable copy constructor takes care of that already. --- components/sceneutil/clone.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/components/sceneutil/clone.cpp b/components/sceneutil/clone.cpp index a372b1ebd..26f3f5c7c 100644 --- a/components/sceneutil/clone.cpp +++ b/components/sceneutil/clone.cpp @@ -81,8 +81,6 @@ namespace SceneUtil #endif osg::Drawable* cloned = osg::clone(drawable, copyop); - if (cloned->getUpdateCallback()) - cloned->setUpdateCallback(osg::clone(cloned->getUpdateCallback(), *this)); return cloned; } if (dynamic_cast(drawable)) From c403a6b113a371bc469656486d5ea113bafb60aa Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 1 Feb 2016 22:30:08 +0100 Subject: [PATCH 3045/3725] Don't apply constant magic effects to dead actors (Fixes #3174) --- apps/openmw/mwworld/inventorystore.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 2c994f146..318b7c5ec 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -345,6 +345,9 @@ void MWWorld::InventoryStore::updateMagicEffects(const Ptr& actor) mMagicEffects = MWMechanics::MagicEffects(); + if (actor.getClass().getCreatureStats(actor).isDead()) + return; + for (TSlots::const_iterator iter (mSlots.begin()); iter!=mSlots.end(); ++iter) { if (*iter==end()) From c34314ae2671e90ded053a060f6dccc6e1aed283 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 1 Feb 2016 22:52:28 +0100 Subject: [PATCH 3046/3725] When an actor dies purge all spell effects cast by that actor (Fixes #3175) --- apps/openmw/mwmechanics/activespells.cpp | 4 +--- apps/openmw/mwmechanics/actors.cpp | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/activespells.cpp b/apps/openmw/mwmechanics/activespells.cpp index 6a247622c..c98f7d829 100644 --- a/apps/openmw/mwmechanics/activespells.cpp +++ b/apps/openmw/mwmechanics/activespells.cpp @@ -274,9 +274,7 @@ namespace MWMechanics for (std::vector::iterator effectIt = it->second.mEffects.begin(); effectIt != it->second.mEffects.end();) { - const ESM::MagicEffect* effect = MWBase::Environment::get().getWorld()->getStore().get().find(effectIt->mEffectId); - if (effect->mData.mFlags & ESM::MagicEffect::CasterLinked - && it->second.mCasterActorId == casterActorId) + if (it->second.mCasterActorId == casterActorId) effectIt = it->second.mEffects.erase(effectIt); else ++effectIt; diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 4046010d7..5d75cea35 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1209,7 +1209,7 @@ namespace MWMechanics ++mDeathCount[Misc::StringUtils::lowerCase(iter->first.getCellRef().getRefId())]; - // Make sure spell effects with CasterLinked flag are removed + // Make sure spell effects are removed for (PtrActorMap::iterator iter2(mActors.begin());iter2 != mActors.end();++iter2) { MWMechanics::ActiveSpells& spells = iter2->first.getClass().getCreatureStats(iter2->first).getActiveSpells(); From 832eaae27b6933d256b4bb61a3224d4dc4bc0052 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 1 Feb 2016 22:57:08 +0100 Subject: [PATCH 3047/3725] Do not apply effects with CasterLinked flag when there is no valid caster --- apps/openmw/mwmechanics/spellcasting.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 6073076e0..4c5138835 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -378,6 +378,11 @@ namespace MWMechanics if (!checkEffectTarget(effectIt->mEffectID, target, castByPlayer)) continue; + // caster needs to be an actor for linked effects (e.g. Absorb) + if (magicEffect->mData.mFlags & ESM::MagicEffect::CasterLinked + && (caster.isEmpty() || !caster.getClass().isActor())) + continue; + // If player is healing someone, show the target's HP bar if (castByPlayer && target != caster && effectIt->mEffectID == ESM::MagicEffect::RestoreHealth From dda4273349cb79ceafedd8a18678478aafc49f19 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 1 Feb 2016 23:13:43 +0100 Subject: [PATCH 3048/3725] Actors that start the game as dead do not float to the surface (Fixes #3177) This has a minor bug (can you spot it?) that affects the vanilla engine as well, unfortunately not so simple to fix. --- apps/openmw/mwmechanics/character.cpp | 7 ++++++- apps/openmw/mwmechanics/character.hpp | 1 + apps/openmw/mwphysics/physicssystem.cpp | 4 ++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index db1b82ba6..67707d028 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -668,6 +668,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim , mHasMovedInXY(false) , mMovementAnimationControlled(true) , mDeathState(CharState_None) + , mFloatToSurface(true) , mHitState(CharState_None) , mUpperBodyState(UpperCharState_Nothing) , mJumpState(JumpState_None) @@ -716,6 +717,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim // Set the death state, but don't play it yet // We will play it in the first frame, but only if no script set the skipAnim flag mDeathState = static_cast(CharState_Death1 + mPtr.getClass().getCreatureStats(mPtr).getDeathAnimation()); + mFloatToSurface = false; } } else @@ -1864,7 +1866,7 @@ void CharacterController::update(float duration) { playDeath(1.f, mDeathState); } - + // We must always queue movement, even if there is none, to apply gravity. world->queueMovement(mPtr, osg::Vec3f(0.f, 0.f, 0.f)); } @@ -1897,6 +1899,9 @@ void CharacterController::update(float duration) if (mSkipAnim) mAnimation->updateEffects(duration); + if (mFloatToSurface && cls.isActor() && cls.getCreatureStats(mPtr).isDead()) + moved.z() = 1.0; + // Update movement if(mMovementAnimationControlled && mPtr.getClass().isActor()) world->queueMovement(mPtr, moved); diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 5e43bc2b7..6db661ca5 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -160,6 +160,7 @@ class CharacterController : public MWRender::Animation::TextKeyListener CharacterState mDeathState; std::string mCurrentDeath; + bool mFloatToSurface; CharacterState mHitState; std::string mCurrentHit; diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 57bf7919a..c99456ae5 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -289,8 +289,8 @@ namespace MWPhysics } } - // dead actors underwater will float to the surface - if (ptr.getClass().getCreatureStats(ptr).isDead() && position.z() < swimlevel) + // dead actors underwater will float to the surface, if the CharacterController tells us to do so + if (movement.z() > 0 && ptr.getClass().getCreatureStats(ptr).isDead() && position.z() < swimlevel) velocity = osg::Vec3f(0,0,1) * 25; ptr.getClass().getMovementSettings(ptr).mPosition[2] = 0; From 50ed061154322bf5d5b00b71c13930848d315b4b Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 2 Feb 2016 00:39:37 +0100 Subject: [PATCH 3049/3725] AiWander: reset mAllowedNodes on cell change (Fixes #3176, Fixes #3130) --- apps/openmw/mwmechanics/aiwander.cpp | 2 ++ apps/openmw/mwmechanics/aiwander.hpp | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index a3fdc69cc..8231e572e 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -730,6 +730,8 @@ namespace MWMechanics const ESM::Pathgrid * pathgrid = MWBase::Environment::get().getWorld()->getStore().get().search(*cell); + mAllowedNodes.clear(); + // If there is no path this actor doesn't go anywhere. See: // https://forum.openmw.org/viewtopic.php?t=1556 // http://www.fliggerty.com/phpBB3/viewtopic.php?f=30&t=5833 diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index b0fabfce3..683c04bb0 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -120,16 +120,20 @@ namespace MWMechanics MWWorld::TimeStamp mStartTime; // allowed pathgrid nodes based on mDistance from the spawn point + // in local coordinates of mCell + // FIXME: move to AiWanderStorage std::vector mAllowedNodes; void getAllowedNodes(const MWWorld::Ptr& actor, const ESM::Cell* cell); + // FIXME: move to AiWanderStorage ESM::Pathgrid::Point mCurrentNode; bool mTrimCurrentNode; void trimAllowedNodes(std::vector& nodes, const PathFinder& pathfinder); + // FIXME: move to AiWanderStorage // ObstacleCheck mObstacleCheck; float mDoorCheckDuration; int mStuckCount; From 59d2de118f8f9f1bc6493ab3eab10c0d35d26448 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 2 Feb 2016 00:50:21 +0100 Subject: [PATCH 3050/3725] Avoid directly iterating the actor map (Fixes #3173) --- apps/openmw/mwmechanics/actors.cpp | 37 +++++++++++++++--------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 5d75cea35..f9c70e7ae 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -982,8 +982,11 @@ namespace MWMechanics /// \todo move update logic to Actor class where appropriate + // make a copy of the map to avoid invalidated iterators when an actor moves during the update + PtrActorMap actors = mActors; + // AI and magic effects update - for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter) + for(PtrActorMap::iterator iter(actors.begin()); iter != actors.end(); ++iter) { bool inProcessingRange = (player.getRefData().getPosition().asVec3() - iter->first.getRefData().getPosition().asVec3()).length2() <= sqrProcessingDistance; @@ -996,6 +999,11 @@ namespace MWMechanics if (!iter->first.getClass().getCreatureStats(iter->first).isDead()) { updateActor(iter->first, duration); + if (MWBase::Environment::get().getWorld()->hasCellChanged()) + { + return; // for now abort update of the old cell when cell changes by teleportation magic effect + // a better solution might be to apply cell changes at the end of the frame + } if (MWBase::Environment::get().getMechanicsManager()->isAIActive() && inProcessingRange) { if (timerUpdateAITargets == 0) @@ -1003,7 +1011,7 @@ namespace MWMechanics if (iter->first != player) adjustCommandedActor(iter->first); - for(PtrActorMap::iterator it(mActors.begin()); it != mActors.end(); ++it) + for(PtrActorMap::iterator it(actors.begin()); it != actors.end(); ++it) { if (it->first == iter->first || iter->first == player) // player is not AI-controlled continue; @@ -1015,7 +1023,7 @@ namespace MWMechanics float sqrHeadTrackDistance = std::numeric_limits::max(); MWWorld::Ptr headTrackTarget; - for(PtrActorMap::iterator it(mActors.begin()); it != mActors.end(); ++it) + for(PtrActorMap::iterator it(actors.begin()); it != actors.end(); ++it) { if (it->first == iter->first) continue; @@ -1050,12 +1058,12 @@ namespace MWMechanics // Reaching the text keys may trigger Hit / Spellcast (and as such, particles), // so updating VFX immediately after that would just remove the particle effects instantly. // There needs to be a magic effect update in between. - for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter) + for(PtrActorMap::iterator iter(actors.begin()); iter != actors.end(); ++iter) iter->second->getCharacterController()->updateContinuousVfx(); // Animation/movement update CharacterController* playerCharacter = NULL; - for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter) + for(PtrActorMap::iterator iter(actors.begin()); iter != actors.end(); ++iter) { if (iter->first != player && (player.getRefData().getPosition().asVec3() - iter->first.getRefData().getPosition().asVec3()).length2() @@ -1065,20 +1073,10 @@ namespace MWMechanics if (iter->first.getClass().getCreatureStats(iter->first).isParalyzed()) iter->second->getCharacterController()->skipAnim(); - // Handle player last, in case a cell transition occurs by casting a teleportation spell - // (would invalidate the iterator) - if (iter->first == getPlayer()) - { - playerCharacter = iter->second->getCharacterController(); - continue; - } iter->second->getCharacterController()->update(duration); } - if (playerCharacter) - playerCharacter->update(duration); - - for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter) + for(PtrActorMap::iterator iter(actors.begin()); iter != actors.end(); ++iter) { const MWWorld::Class &cls = iter->first.getClass(); CreatureStats &stats = cls.getCreatureStats(iter->first); @@ -1136,7 +1134,7 @@ namespace MWMechanics bool detected = false; - for (PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter) + for (PtrActorMap::iterator iter(actors.begin()); iter != actors.end(); ++iter) { if (iter->first == player) // not the player continue; @@ -1179,7 +1177,8 @@ namespace MWMechanics void Actors::killDeadActors() { - for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter) + PtrActorMap actors = mActors; + for(PtrActorMap::iterator iter(actors.begin()); iter != actors.end(); ++iter) { const MWWorld::Class &cls = iter->first.getClass(); CreatureStats &stats = cls.getCreatureStats(iter->first); @@ -1210,7 +1209,7 @@ namespace MWMechanics ++mDeathCount[Misc::StringUtils::lowerCase(iter->first.getCellRef().getRefId())]; // Make sure spell effects are removed - for (PtrActorMap::iterator iter2(mActors.begin());iter2 != mActors.end();++iter2) + for (PtrActorMap::iterator iter2(actors.begin());iter2 != actors.end();++iter2) { MWMechanics::ActiveSpells& spells = iter2->first.getClass().getCreatureStats(iter2->first).getActiveSpells(); spells.purge(stats.getActorId()); From 145756c0a1a39d378f09a981c7b05d3dc0a07368 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 2 Feb 2016 15:55:19 +0100 Subject: [PATCH 3051/3725] Partly revert "Avoid directly iterating the actor map (Fixes #3173)" Caused issues when a summoned creature is removed as part of the magic effect update. Fixes #3178 --- apps/openmw/mwmechanics/actors.cpp | 32 ++++++++++++++++++------------ 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index f9c70e7ae..70aab95df 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -982,11 +982,8 @@ namespace MWMechanics /// \todo move update logic to Actor class where appropriate - // make a copy of the map to avoid invalidated iterators when an actor moves during the update - PtrActorMap actors = mActors; - // AI and magic effects update - for(PtrActorMap::iterator iter(actors.begin()); iter != actors.end(); ++iter) + for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter) { bool inProcessingRange = (player.getRefData().getPosition().asVec3() - iter->first.getRefData().getPosition().asVec3()).length2() <= sqrProcessingDistance; @@ -1011,7 +1008,7 @@ namespace MWMechanics if (iter->first != player) adjustCommandedActor(iter->first); - for(PtrActorMap::iterator it(actors.begin()); it != actors.end(); ++it) + for(PtrActorMap::iterator it(mActors.begin()); it != mActors.end(); ++it) { if (it->first == iter->first || iter->first == player) // player is not AI-controlled continue; @@ -1023,7 +1020,7 @@ namespace MWMechanics float sqrHeadTrackDistance = std::numeric_limits::max(); MWWorld::Ptr headTrackTarget; - for(PtrActorMap::iterator it(actors.begin()); it != actors.end(); ++it) + for(PtrActorMap::iterator it(mActors.begin()); it != mActors.end(); ++it) { if (it->first == iter->first) continue; @@ -1058,12 +1055,12 @@ namespace MWMechanics // Reaching the text keys may trigger Hit / Spellcast (and as such, particles), // so updating VFX immediately after that would just remove the particle effects instantly. // There needs to be a magic effect update in between. - for(PtrActorMap::iterator iter(actors.begin()); iter != actors.end(); ++iter) + for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter) iter->second->getCharacterController()->updateContinuousVfx(); // Animation/movement update CharacterController* playerCharacter = NULL; - for(PtrActorMap::iterator iter(actors.begin()); iter != actors.end(); ++iter) + for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter) { if (iter->first != player && (player.getRefData().getPosition().asVec3() - iter->first.getRefData().getPosition().asVec3()).length2() @@ -1073,10 +1070,20 @@ namespace MWMechanics if (iter->first.getClass().getCreatureStats(iter->first).isParalyzed()) iter->second->getCharacterController()->skipAnim(); + // Handle player last, in case a cell transition occurs by casting a teleportation spell + // (would invalidate the iterator) + if (iter->first == getPlayer()) + { + playerCharacter = iter->second->getCharacterController(); + continue; + } iter->second->getCharacterController()->update(duration); } - for(PtrActorMap::iterator iter(actors.begin()); iter != actors.end(); ++iter) + if (playerCharacter) + playerCharacter->update(duration); + + for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter) { const MWWorld::Class &cls = iter->first.getClass(); CreatureStats &stats = cls.getCreatureStats(iter->first); @@ -1134,7 +1141,7 @@ namespace MWMechanics bool detected = false; - for (PtrActorMap::iterator iter(actors.begin()); iter != actors.end(); ++iter) + for (PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter) { if (iter->first == player) // not the player continue; @@ -1177,8 +1184,7 @@ namespace MWMechanics void Actors::killDeadActors() { - PtrActorMap actors = mActors; - for(PtrActorMap::iterator iter(actors.begin()); iter != actors.end(); ++iter) + for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter) { const MWWorld::Class &cls = iter->first.getClass(); CreatureStats &stats = cls.getCreatureStats(iter->first); @@ -1209,7 +1215,7 @@ namespace MWMechanics ++mDeathCount[Misc::StringUtils::lowerCase(iter->first.getCellRef().getRefId())]; // Make sure spell effects are removed - for (PtrActorMap::iterator iter2(actors.begin());iter2 != actors.end();++iter2) + for (PtrActorMap::iterator iter2(mActors.begin());iter2 != mActors.end();++iter2) { MWMechanics::ActiveSpells& spells = iter2->first.getClass().getCreatureStats(iter2->first).getActiveSpells(); spells.purge(stats.getActorId()); From 7aeafd3bb9403104134c0a22b32925fafd9ec976 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 19 Jan 2016 14:51:37 +0100 Subject: [PATCH 3052/3725] Revert "Apply the AiTravel maxRange to AiEscort as well (Fixes #2697)" This reverts commit 1f543b4d79744886aa9a03ad7fcff6d97dc5f70c. --- apps/openmw/mwmechanics/aiescort.cpp | 3 --- apps/openmw/mwmechanics/aipackage.hpp | 9 --------- apps/openmw/mwmechanics/aitravel.cpp | 12 ++++++++++++ 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwmechanics/aiescort.cpp b/apps/openmw/mwmechanics/aiescort.cpp index baf4f1be7..fffab8d77 100644 --- a/apps/openmw/mwmechanics/aiescort.cpp +++ b/apps/openmw/mwmechanics/aiescort.cpp @@ -75,9 +75,6 @@ namespace MWMechanics return true; } - if (!isWithinMaxRange(osg::Vec3f(mX, mY, mZ), actor.getRefData().getPosition().asVec3())) - return false; - if (!mCellId.empty() && mCellId != actor.getCell()->getCell()->getCellId().mWorldspace) return false; // Not in the correct cell, pause and rely on the player to go back through a teleport door diff --git a/apps/openmw/mwmechanics/aipackage.hpp b/apps/openmw/mwmechanics/aipackage.hpp index 76f89dff4..07df933e2 100644 --- a/apps/openmw/mwmechanics/aipackage.hpp +++ b/apps/openmw/mwmechanics/aipackage.hpp @@ -97,19 +97,10 @@ namespace MWMechanics ESM::Pathgrid::Point mPrevDest; - bool isWithinMaxRange(const osg::Vec3f& pos1, const osg::Vec3f& pos2) const - { - // Maximum travel distance for vanilla compatibility. - // Was likely meant to prevent NPCs walking into non-loaded exterior cells, but for some reason is used in interior cells as well. - // We can make this configurable at some point, but the default *must* be the below value. Anything else will break shoddily-written content (*cough* MW *cough*) in bizarre ways. - return (pos1 - pos2).length2() <= 7168*7168; - } - private: bool isNearInactiveCell(const ESM::Position& actorPos); }; - } #endif diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index c29861f4e..1585a3007 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -13,6 +13,18 @@ #include "movement.hpp" #include "creaturestats.hpp" +namespace +{ + +bool isWithinMaxRange(const osg::Vec3f& pos1, const osg::Vec3f& pos2) +{ + // Maximum travel distance for vanilla compatibility. + // Was likely meant to prevent NPCs walking into non-loaded exterior cells, but for some reason is used in interior cells as well. + // We can make this configurable at some point, but the default *must* be the below value. Anything else will break shoddily-written content (*cough* MW *cough*) in bizarre ways. + return (pos1 - pos2).length2() <= 7168*7168; +} + +} namespace MWMechanics { From d3b76b70063da765b107a766142a681bd7ad5f73 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 19 Jan 2016 14:51:42 +0100 Subject: [PATCH 3053/3725] Don't stack Ai packages (Fixes #3101, Fixes #3080, Fixes #2697) --- apps/openmw/mwmechanics/aiavoiddoor.hpp | 3 + apps/openmw/mwmechanics/aicombat.hpp | 3 + apps/openmw/mwmechanics/aipackage.cpp | 10 ++ apps/openmw/mwmechanics/aipackage.hpp | 8 ++ apps/openmw/mwmechanics/aipursue.hpp | 3 + apps/openmw/mwmechanics/aisequence.cpp | 133 +++++++++++++----------- 6 files changed, 99 insertions(+), 61 deletions(-) diff --git a/apps/openmw/mwmechanics/aiavoiddoor.hpp b/apps/openmw/mwmechanics/aiavoiddoor.hpp index 9d63c63e0..41c41b1f5 100644 --- a/apps/openmw/mwmechanics/aiavoiddoor.hpp +++ b/apps/openmw/mwmechanics/aiavoiddoor.hpp @@ -26,6 +26,9 @@ namespace MWMechanics virtual unsigned int getPriority() const; + virtual bool canCancel() const { return false; } + virtual bool shouldCancelPreviousAi() const { return false; } + private: float mDuration; MWWorld::ConstPtr mDoorPtr; diff --git a/apps/openmw/mwmechanics/aicombat.hpp b/apps/openmw/mwmechanics/aicombat.hpp index 93d630529..2b364001f 100644 --- a/apps/openmw/mwmechanics/aicombat.hpp +++ b/apps/openmw/mwmechanics/aicombat.hpp @@ -53,6 +53,9 @@ namespace MWMechanics virtual void writeState(ESM::AiSequence::AiSequence &sequence) const; + virtual bool canCancel() const { return false; } + virtual bool shouldCancelPreviousAi() const { return false; } + protected: virtual bool doesPathNeedRecalc(ESM::Pathgrid::Point dest, const ESM::Cell *cell); diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index cb2b002f6..58ba7dfe8 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -35,6 +35,16 @@ bool MWMechanics::AiPackage::followTargetThroughDoors() const return false; } +bool MWMechanics::AiPackage::canCancel() const +{ + return true; +} + +bool MWMechanics::AiPackage::shouldCancelPreviousAi() const +{ + return true; +} + MWMechanics::AiPackage::AiPackage() : mTimer(0.26f) { //mTimer starts at .26 to force initial pathbuild } diff --git a/apps/openmw/mwmechanics/aipackage.hpp b/apps/openmw/mwmechanics/aipackage.hpp index 07df933e2..72bb4487c 100644 --- a/apps/openmw/mwmechanics/aipackage.hpp +++ b/apps/openmw/mwmechanics/aipackage.hpp @@ -39,6 +39,8 @@ namespace MWMechanics TypeIdEscort = 2, TypeIdFollow = 3, TypeIdActivate = 4, + + // These 3 are not really handled as Ai Packages in the MW engine TypeIdCombat = 5, TypeIdPursue = 6, TypeIdAvoidDoor = 7 @@ -78,6 +80,12 @@ namespace MWMechanics /// Return true if the actor should follow the target through teleport doors (default false) virtual bool followTargetThroughDoors() const; + /// Can this Ai package be canceled? (default true) + virtual bool canCancel() const; + + /// Upon adding this Ai package, should the Ai Sequence attempt to cancel previous Ai packages (default true)? + virtual bool shouldCancelPreviousAi() const; + bool isTargetMagicallyHidden(const MWWorld::Ptr& target); protected: diff --git a/apps/openmw/mwmechanics/aipursue.hpp b/apps/openmw/mwmechanics/aipursue.hpp index 813b87cff..cb93e9636 100644 --- a/apps/openmw/mwmechanics/aipursue.hpp +++ b/apps/openmw/mwmechanics/aipursue.hpp @@ -38,6 +38,9 @@ namespace MWMechanics virtual void writeState (ESM::AiSequence::AiSequence& sequence) const; + virtual bool canCancel() const { return false; } + virtual bool shouldCancelPreviousAi() const { return false; } + private: int mTargetActorId; // The actor to pursue diff --git a/apps/openmw/mwmechanics/aisequence.cpp b/apps/openmw/mwmechanics/aisequence.cpp index d55dc240e..04ac96b11 100644 --- a/apps/openmw/mwmechanics/aisequence.cpp +++ b/apps/openmw/mwmechanics/aisequence.cpp @@ -153,83 +153,86 @@ void AiSequence::execute (const MWWorld::Ptr& actor, CharacterController& charac { if(actor != getPlayer()) { - if (!mPackages.empty()) + if (mPackages.empty()) { - MWMechanics::AiPackage* package = mPackages.front(); - mLastAiPackage = package->getTypeId(); + mLastAiPackage = -1; + return; + } - // if active package is combat one, choose nearest target - if (mLastAiPackage == AiPackage::TypeIdCombat) - { - std::list::iterator itActualCombat; + MWMechanics::AiPackage* package = mPackages.front(); + mLastAiPackage = package->getTypeId(); - float nearestDist = std::numeric_limits::max(); - osg::Vec3f vActorPos = actor.getRefData().getPosition().asVec3(); + // if active package is combat one, choose nearest target + if (mLastAiPackage == AiPackage::TypeIdCombat) + { + std::list::iterator itActualCombat; - for(std::list::iterator it = mPackages.begin(); it != mPackages.end();) - { - if ((*it)->getTypeId() != AiPackage::TypeIdCombat) break; + float nearestDist = std::numeric_limits::max(); + osg::Vec3f vActorPos = actor.getRefData().getPosition().asVec3(); - MWWorld::Ptr target = static_cast(*it)->getTarget(); + for(std::list::iterator it = mPackages.begin(); it != mPackages.end();) + { + if ((*it)->getTypeId() != AiPackage::TypeIdCombat) break; - // target disappeared (e.g. summoned creatures) - if (target.isEmpty()) - { - delete *it; - it = mPackages.erase(it); - } - else - { - const ESM::Position &targetPos = target.getRefData().getPosition(); + MWWorld::Ptr target = static_cast(*it)->getTarget(); - float distTo = (targetPos.asVec3() - vActorPos).length(); + // target disappeared (e.g. summoned creatures) + if (target.isEmpty()) + { + delete *it; + it = mPackages.erase(it); + } + else + { + const ESM::Position &targetPos = target.getRefData().getPosition(); - // Small threshold for changing target - if (it == mPackages.begin()) - distTo = std::max(0.f, distTo - 50.f); + float distTo = (targetPos.asVec3() - vActorPos).length(); - if (distTo < nearestDist) - { - nearestDist = distTo; - itActualCombat = it; - } - ++it; - } - } + // Small threshold for changing target + if (it == mPackages.begin()) + distTo = std::max(0.f, distTo - 50.f); - if (!mPackages.empty()) - { - if (nearestDist < std::numeric_limits::max() && mPackages.begin() != itActualCombat) + if (distTo < nearestDist) { - // move combat package with nearest target to the front - mPackages.splice(mPackages.begin(), mPackages, itActualCombat); + nearestDist = distTo; + itActualCombat = it; } - - package = mPackages.front(); - mLastAiPackage = package->getTypeId(); - } - else - { - mDone = true; - return; + ++it; } } - if (package->execute (actor,characterController,state,duration)) + if (!mPackages.empty()) { - // To account for the rare case where AiPackage::execute() queued another AI package - // (e.g. AiPursue executing a dialogue script that uses startCombat) - std::list::iterator toRemove = - std::find(mPackages.begin(), mPackages.end(), package); - mPackages.erase(toRemove); - delete package; - mDone = true; + if (nearestDist < std::numeric_limits::max() && mPackages.begin() != itActualCombat) + { + // move combat package with nearest target to the front + mPackages.splice(mPackages.begin(), mPackages, itActualCombat); + } + + package = mPackages.front(); + mLastAiPackage = package->getTypeId(); } else { - mDone = false; + mDone = true; + return; } } + + if (package->execute (actor,characterController,state,duration)) + { + // To account for the rare case where AiPackage::execute() queued another AI package + // (e.g. AiPursue executing a dialogue script that uses startCombat) + std::list::iterator toRemove = + std::find(mPackages.begin(), mPackages.end(), package); + mPackages.erase(toRemove); + delete package; + mDone = true; + } + else + { + mDone = false; + } } } @@ -251,11 +254,6 @@ void AiSequence::stack (const AiPackage& package, const MWWorld::Ptr& actor) // Notify AiWander of our current position so we can return to it after combat finished for (std::list::const_iterator iter (mPackages.begin()); iter!=mPackages.end(); ++iter) { - if((*iter)->getTypeId() == AiPackage::TypeIdPursue && package.getTypeId() == AiPackage::TypeIdPursue - && static_cast(*iter)->getTarget() == static_cast(&package)->getTarget()) - { - return; // target is already pursued - } if((*iter)->getTypeId() == AiPackage::TypeIdCombat && package.getTypeId() == AiPackage::TypeIdCombat && static_cast(*iter)->getTarget() == static_cast(&package)->getTarget()) { @@ -266,6 +264,19 @@ void AiSequence::stack (const AiPackage& package, const MWWorld::Ptr& actor) } } + // remove previous packages if required + if (package.shouldCancelPreviousAi()) + { + for(std::list::iterator it = mPackages.begin(); it != mPackages.end();) + { + if((*it)->canCancel()) + it = mPackages.erase(it); + else + ++it; + } + } + + // insert new package in correct place depending on priority for(std::list::iterator it = mPackages.begin(); it != mPackages.end(); ++it) { if((*it)->getPriority() <= package.getPriority()) From b9d1d6144a337e7d54eb4c9b4f1af785ffe0ed31 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 2 Feb 2016 22:49:48 +0100 Subject: [PATCH 3054/3725] Don't reveal unknown potion effects in alchemy window (Fixes #3146) --- apps/openmw/mwclass/potion.cpp | 15 +++------------ apps/openmw/mwgui/alchemywindow.cpp | 4 ++++ apps/openmw/mwmechanics/alchemy.cpp | 10 ++++++++++ apps/openmw/mwmechanics/alchemy.hpp | 3 +++ 4 files changed, 20 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwclass/potion.cpp b/apps/openmw/mwclass/potion.cpp index 40b4d6234..c26b925f6 100644 --- a/apps/openmw/mwclass/potion.cpp +++ b/apps/openmw/mwclass/potion.cpp @@ -20,7 +20,7 @@ #include "../mwrender/objects.hpp" #include "../mwrender/renderinginterface.hpp" -#include "../mwmechanics/npcstats.hpp" +#include "../mwmechanics/alchemy.hpp" namespace MWClass { @@ -124,17 +124,8 @@ namespace MWClass // hide effects the player doesnt know about MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayerPtr(); - MWMechanics::NpcStats& npcStats = player.getClass().getNpcStats (player); - int alchemySkill = npcStats.getSkill (ESM::Skill::Alchemy).getBase(); - int i=0; - static const float fWortChanceValue = - MWBase::Environment::get().getWorld()->getStore().get().find("fWortChanceValue")->getFloat(); - for (MWGui::Widgets::SpellEffectList::iterator it = info.effects.begin(); it != info.effects.end(); ++it) - { - it->mKnown = (i <= 1 && alchemySkill >= fWortChanceValue) - || (i <= 3 && alchemySkill >= fWortChanceValue*2); - ++i; - } + for (unsigned int i=0; i effectIds = mAlchemy->listEffects(); Widgets::SpellEffectList list; + unsigned int effectIndex=0; for (std::set::iterator it = effectIds.begin(); it != effectIds.end(); ++it) { Widgets::SpellEffectParams params; @@ -228,7 +229,10 @@ namespace MWGui params.mIsConstant = true; params.mNoTarget = true; + params.mKnown = mAlchemy->knownEffect(effectIndex, MWBase::Environment::get().getWorld()->getPlayerPtr()); + list.push_back(params); + ++effectIndex; } while (mEffectsBox->getChildCount()) diff --git a/apps/openmw/mwmechanics/alchemy.cpp b/apps/openmw/mwmechanics/alchemy.cpp index d39c88150..d02376d23 100644 --- a/apps/openmw/mwmechanics/alchemy.cpp +++ b/apps/openmw/mwmechanics/alchemy.cpp @@ -451,6 +451,16 @@ MWMechanics::Alchemy::TEffectsIterator MWMechanics::Alchemy::endEffects() const return mEffects.end(); } +bool MWMechanics::Alchemy::knownEffect(unsigned int potionEffectIndex, const MWWorld::Ptr &npc) +{ + MWMechanics::NpcStats& npcStats = npc.getClass().getNpcStats(npc); + int alchemySkill = npcStats.getSkill (ESM::Skill::Alchemy).getBase(); + static const float fWortChanceValue = + MWBase::Environment::get().getWorld()->getStore().get().find("fWortChanceValue")->getFloat(); + return (potionEffectIndex <= 1 && alchemySkill >= fWortChanceValue) + || (potionEffectIndex <= 3 && alchemySkill >= fWortChanceValue*2); +} + MWMechanics::Alchemy::Result MWMechanics::Alchemy::create (const std::string& name) { if (mTools[ESM::Apparatus::MortarPestle].isEmpty()) diff --git a/apps/openmw/mwmechanics/alchemy.hpp b/apps/openmw/mwmechanics/alchemy.hpp index caba26f14..f351881e0 100644 --- a/apps/openmw/mwmechanics/alchemy.hpp +++ b/apps/openmw/mwmechanics/alchemy.hpp @@ -80,6 +80,9 @@ namespace MWMechanics public: + static bool knownEffect (unsigned int potionEffectIndex, const MWWorld::Ptr& npc); + ///< Does npc have sufficient alchemy skill to know about this potion effect? + void setAlchemist (const MWWorld::Ptr& npc); ///< Set alchemist and configure alchemy setup accordingly. \a npc may be empty to indicate that /// there is no alchemist (alchemy session has ended). From 5878291064e73b3c6a0a59c16db92031d45a076e Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Feb 2016 14:40:21 +0100 Subject: [PATCH 3055/3725] Fix the path correction for animation sources provided in NPC record (Fixes #2444) --- apps/openmw/mwrender/npcanimation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index a032896a7..c8d7c79c5 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -473,7 +473,7 @@ void NpcAnimation::updateNpcBase() else if(!mNpc->isMale() && !isBeast) addAnimSource("meshes\\xbase_anim_female.nif"); if(mNpc->mModel.length() > 0) - addAnimSource("meshes\\x"+mNpc->mModel); + addAnimSource(Misc::ResourceHelpers::correctActorModelPath("meshes\\" + mNpc->mModel, mResourceSystem->getVFS())); } } else From 74c18f532e30455a440dc87feac329ce14be1941 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Feb 2016 14:40:59 +0100 Subject: [PATCH 3056/3725] Fix comment --- apps/openmw/mwrender/animation.hpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 213e33f67..992462e1f 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -292,9 +292,10 @@ protected: */ void setObjectRoot(const std::string &model, bool forceskeleton, bool baseonly, bool isCreature); - /* Adds the keyframe controllers in the specified model as a new animation source. Note that - * the filename portion of the provided model name will be prepended with 'x', and the .nif - * extension will be replaced with .kf. */ + /** Adds the keyframe controllers in the specified model as a new animation source. Note that the .nif + * file extension will be replaced with .kf. + * @note Later added animation sources have the highest priority when it comes to finding a particular animation. + */ void addAnimSource(const std::string &model); /** Adds an additional light to the given node using the specified ESM record. */ From aa9905b0eb2fa0ae6425ca5d192af67931b5620f Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Feb 2016 15:24:28 +0100 Subject: [PATCH 3057/3725] Do not crash when the water normal map is missing (Fixes #3179) --- apps/openmw/mwrender/water.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index b2bef7122..c7f2c9cc6 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -578,12 +578,13 @@ void Water::createShaderWaterStateSet(osg::Node* node, Reflection* reflection, R osg::ref_ptr fragmentShader (readShader(osg::Shader::FRAGMENT, mResourcePath + "/shaders/water_fragment.glsl", defineMap)); osg::ref_ptr normalMap (new osg::Texture2D(readPngImage(mResourcePath + "/shaders/water_nm.png"))); + if (normalMap->getImage()) + normalMap->getImage()->flipVertical(); normalMap->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT); normalMap->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT); normalMap->setMaxAnisotropy(16); normalMap->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR_MIPMAP_LINEAR); normalMap->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); - normalMap->getImage()->flipVertical(); osg::ref_ptr shaderStateset = new osg::StateSet; shaderStateset->addUniform(new osg::Uniform("normalMap", 0)); From 187d2bccda53da425f49bc7e652bee29c63822cf Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Feb 2016 16:06:25 +0100 Subject: [PATCH 3058/3725] Warn about adding a local script twice (Bug #2806) --- apps/openmw/mwworld/localscripts.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/apps/openmw/mwworld/localscripts.cpp b/apps/openmw/mwworld/localscripts.cpp index 2004a2ff3..374f5c632 100644 --- a/apps/openmw/mwworld/localscripts.cpp +++ b/apps/openmw/mwworld/localscripts.cpp @@ -110,6 +110,14 @@ void MWWorld::LocalScripts::add (const std::string& scriptName, const Ptr& ptr) { ptr.getRefData().setLocals (*script); + for (std::list >::iterator iter = mScripts.begin(); iter!=mScripts.end(); ++iter) + if (iter->second==ptr) + { + std::cout << "warning, tried to add local script twice for " << ptr.getCellRef().getRefId() << std::endl; + remove(ptr); + break; + } + mScripts.push_back (std::make_pair (scriptName, ptr)); } catch (const std::exception& exception) From cc3563359e3ab2d7e3b02feb0b62533ed03e3d64 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Feb 2016 16:09:20 +0100 Subject: [PATCH 3059/3725] Refactor local script iteration (Fixes #2806, Fixes #3108) This should be much safer. Don't use recursion. Don't fail if mIgnore happens to be in the list twice. Don't rely on preconditions / assertions. --- apps/openmw/engine.cpp | 6 ++---- apps/openmw/mwworld/localscripts.cpp | 28 ++++++++-------------------- apps/openmw/mwworld/localscripts.hpp | 8 +++----- 3 files changed, 13 insertions(+), 29 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 3fcd46f7c..f347bc350 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -69,11 +69,9 @@ void OMW::Engine::executeLocalScripts() MWWorld::LocalScripts& localScripts = mEnvironment.getWorld()->getLocalScripts(); localScripts.startIteration(); - - while (!localScripts.isFinished()) + std::pair script; + while (localScripts.getNext(script)) { - std::pair script = localScripts.getNext(); - MWScript::InterpreterContext interpreterContext ( &script.second.getRefData().getLocals(), script.second); mEnvironment.getScriptManager()->run (script.first, interpreterContext); diff --git a/apps/openmw/mwworld/localscripts.cpp b/apps/openmw/mwworld/localscripts.cpp index 374f5c632..7ccc213c4 100644 --- a/apps/openmw/mwworld/localscripts.cpp +++ b/apps/openmw/mwworld/localscripts.cpp @@ -76,32 +76,20 @@ void MWWorld::LocalScripts::startIteration() mIter = mScripts.begin(); } -bool MWWorld::LocalScripts::isFinished() const +bool MWWorld::LocalScripts::getNext(std::pair& script) { - if (mIter==mScripts.end()) - return true; - - if (!mIgnore.isEmpty() && mIter->second==mIgnore) + while (mIter!=mScripts.end()) { - std::list >::iterator iter = mIter; - return ++iter==mScripts.end(); + std::list >::iterator iter = mIter++; + if (mIgnore.isEmpty() || iter->second!=mIgnore) + { + script = *iter; + return true; + } } - return false; } -std::pair MWWorld::LocalScripts::getNext() -{ - assert (!isFinished()); - - std::list >::iterator iter = mIter++; - - if (mIgnore.isEmpty() || iter->second!=mIgnore) - return *iter; - - return getNext(); -} - void MWWorld::LocalScripts::add (const std::string& scriptName, const Ptr& ptr) { if (const ESM::Script *script = mStore.get().search (scriptName)) diff --git a/apps/openmw/mwworld/localscripts.hpp b/apps/openmw/mwworld/localscripts.hpp index 6ef4633a1..6c2118ea8 100644 --- a/apps/openmw/mwworld/localscripts.hpp +++ b/apps/openmw/mwworld/localscripts.hpp @@ -31,11 +31,9 @@ namespace MWWorld void startIteration(); ///< Set the iterator to the begin of the script list. - bool isFinished() const; - ///< Is iteration finished? - - std::pair getNext(); - ///< Get next local script (must not be called if isFinished()) + bool getNext(std::pair& script); + ///< Get next local script + /// @return Did we get a script? void add (const std::string& scriptName, const Ptr& ptr); ///< Add script to collection of active local scripts. From 06ed20abf8e9b59384c3221dd2c390d205296ae8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Feb 2016 18:53:38 +0100 Subject: [PATCH 3060/3725] Use the initial pose of a MorphGeometry for object placement (Fixes #3136) --- components/nifosg/nifloader.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index f4dae52c3..280985f7e 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -999,7 +999,7 @@ namespace NifOsg continue; if(ctrl->recType == Nif::RC_NiGeomMorpherController) { - geometry = handleMorphGeometry(static_cast(ctrl.getPtr())); + geometry = handleMorphGeometry(static_cast(ctrl.getPtr()), triShape, parentNode, composite, boundTextures, animflags); osg::ref_ptr morphctrl = new GeomMorpherController( static_cast(ctrl.getPtr())->data.getPtr()); @@ -1010,9 +1010,10 @@ namespace NifOsg } if (!geometry.get()) + { geometry = new osg::Geometry; - - triShapeToGeometry(triShape, geometry, parentNode, composite, boundTextures, animflags); + triShapeToGeometry(triShape, geometry, parentNode, composite, boundTextures, animflags); + } #if OSG_VERSION_LESS_THAN(3,3,3) osg::ref_ptr geode (new osg::Geode); @@ -1046,7 +1047,7 @@ namespace NifOsg #endif } - osg::ref_ptr handleMorphGeometry(const Nif::NiGeomMorpherController* morpher) + osg::ref_ptr handleMorphGeometry(const Nif::NiGeomMorpherController* morpher, const Nif::NiTriShape *triShape, osg::Node* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::vector& boundTextures, int animflags) { osg::ref_ptr morphGeom = new osgAnimation::MorphGeometry; morphGeom->setMethod(osgAnimation::MorphGeometry::RELATIVE); @@ -1056,6 +1057,8 @@ namespace NifOsg morphGeom->setUpdateCallback(NULL); morphGeom->setCullCallback(new UpdateMorphGeometry); + triShapeToGeometry(triShape, morphGeom, parentNode, composite, boundTextures, animflags); + const std::vector& morphs = morpher->data.getPtr()->mMorphs; if (!morphs.size()) return morphGeom; @@ -1096,6 +1099,10 @@ namespace NifOsg box.expandBy(vertBounds[i]); } + // For the initial bounding box (used for object placement) use the default pose, fire off a bounding compute to set this initial box + morphGeom->getBoundingBox(); + + // Now set up the callback so that we get properly enlarged bounds if/when the mesh starts animating morphGeom->setComputeBoundingBoxCallback(new StaticBoundingBoxCallback(box)); return morphGeom; From 2eda495f8940a76c5dbd31052d6b54ccbd3e9b76 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Feb 2016 19:05:15 +0100 Subject: [PATCH 3061/3725] Build fix for OSG 3.2 --- components/nifosg/nifloader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 280985f7e..79f837953 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -1100,7 +1100,7 @@ namespace NifOsg } // For the initial bounding box (used for object placement) use the default pose, fire off a bounding compute to set this initial box - morphGeom->getBoundingBox(); + morphGeom->getBound(); // Now set up the callback so that we get properly enlarged bounds if/when the mesh starts animating morphGeom->setComputeBoundingBoxCallback(new StaticBoundingBoxCallback(box)); From 69c2c4fcc170d4b82b5de0cdc5f36df2dbef0994 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Feb 2016 19:12:46 +0100 Subject: [PATCH 3062/3725] updateMergedRefs before reading MVRF tags (Fixes #3161) --- apps/openmw/mwworld/cellstore.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 5b53643e8..5c8d07f86 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -807,6 +807,10 @@ namespace MWWorld } } + // Do another update here to make sure objects referred to by MVRF tags can be found + // This update is only needed for old saves that used the old copy&delete way of moving objects + updateMergedRefs(); + while (reader.isNextSub("MVRF")) { reader.cacheSubName(); @@ -848,8 +852,6 @@ namespace MWWorld moveTo(MWWorld::Ptr(movedRef, this), otherCell); } - - updateMergedRefs(); } bool operator== (const CellStore& left, const CellStore& right) From 41ebf62fb13785fd9b2be138aa694bfa63dcf8b5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 5 Feb 2016 00:25:14 +0100 Subject: [PATCH 3063/3725] Accept a const CellStore in getNorthVector --- apps/openmw/mwbase/world.hpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 4 ++-- apps/openmw/mwworld/worldimp.hpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 06a8ffa35..c2a7de72b 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -141,7 +141,7 @@ namespace MWBase virtual bool isCellQuasiExterior() const = 0; - virtual osg::Vec2f getNorthVector (MWWorld::CellStore* cell) = 0; + virtual osg::Vec2f getNorthVector (const MWWorld::CellStore* cell) = 0; ///< get north vector for given interior cell virtual void getDoorMarkers (MWWorld::CellStore* cell, std::vector& out) = 0; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 37743bceb..a556aabf7 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1710,9 +1710,9 @@ namespace MWWorld mWeatherManager->modRegion(regionid, chances); } - osg::Vec2f World::getNorthVector (CellStore* cell) + osg::Vec2f World::getNorthVector (const CellStore* cell) { - MWWorld::Ptr northmarker = cell->search("northmarker"); + MWWorld::ConstPtr northmarker = cell->searchConst("northmarker"); if (northmarker.isEmpty()) return osg::Vec2f(0, 1); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index a9dce46e8..487d4ed04 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -227,7 +227,7 @@ namespace MWWorld virtual bool isCellQuasiExterior() const; - virtual osg::Vec2f getNorthVector (CellStore* cell); + virtual osg::Vec2f getNorthVector (const CellStore* cell); ///< get north vector for given interior cell virtual void getDoorMarkers (MWWorld::CellStore* cell, std::vector& out); From 300379617e9a604e20dff39962f18ab8b33b7494 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 5 Feb 2016 00:25:47 +0100 Subject: [PATCH 3064/3725] Accept a const CellStore in findInteriorPositionInWorldSpace --- apps/openmw/mwbase/world.hpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 2 +- apps/openmw/mwworld/worldimp.hpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index c2a7de72b..119ce6b21 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -489,7 +489,7 @@ namespace MWBase // Are we in an exterior or pseudo-exterior cell and it's night? virtual bool isDark() const = 0; - virtual bool findInteriorPositionInWorldSpace(MWWorld::CellStore* cell, osg::Vec3f& result) = 0; + virtual bool findInteriorPositionInWorldSpace(const MWWorld::CellStore* cell, osg::Vec3f& result) = 0; /// Teleports \a ptr to the closest reference of \a id (e.g. DivineMarker, PrisonMarker, TempleMarker) /// @note id must be lower case diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index a556aabf7..9064dc94c 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2654,7 +2654,7 @@ namespace MWWorld } } - bool World::findInteriorPositionInWorldSpace(MWWorld::CellStore* cell, osg::Vec3f& result) + bool World::findInteriorPositionInWorldSpace(const MWWorld::CellStore* cell, osg::Vec3f& result) { if (cell->isExterior()) return false; diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 487d4ed04..8c56443f7 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -592,7 +592,7 @@ namespace MWWorld // Are we in an exterior or pseudo-exterior cell and it's night? virtual bool isDark() const; - virtual bool findInteriorPositionInWorldSpace(MWWorld::CellStore* cell, osg::Vec3f& result); + virtual bool findInteriorPositionInWorldSpace(const MWWorld::CellStore* cell, osg::Vec3f& result); /// Teleports \a ptr to the closest reference of \a id (e.g. DivineMarker, PrisonMarker, TempleMarker) /// @note id must be lower case From bd655c20fd2a7c23b83106a5349f718972827883 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 5 Feb 2016 00:39:52 +0100 Subject: [PATCH 3065/3725] Refactor local map updates We don't need the delay any more because the rendering itself is part of the normal rendering traversal - so it's delayed anyway. Don't request maps that we're not actually using (i.e. with cell grid sizes higher than the default 3, we were rendering more maps than the map window could show). --- apps/openmw/mwbase/windowmanager.hpp | 3 +-- apps/openmw/mwgui/mapwindow.cpp | 20 +++++++++++++++++ apps/openmw/mwgui/mapwindow.hpp | 6 +++++ apps/openmw/mwgui/windowmanagerimp.cpp | 20 ++++++++--------- apps/openmw/mwgui/windowmanagerimp.hpp | 3 +-- apps/openmw/mwrender/localmap.cpp | 16 +++++++------ apps/openmw/mwrender/localmap.hpp | 6 ++--- apps/openmw/mwworld/scene.cpp | 31 +------------------------- apps/openmw/mwworld/scene.hpp | 2 -- 9 files changed, 51 insertions(+), 56 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index f364ada7a..2d4c0e2ca 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -176,7 +176,7 @@ namespace MWBase virtual void updateSkillArea() = 0; ///< update display of skills, factions, birth sign, reputation and bounty - virtual void changeCell(MWWorld::CellStore* cell) = 0; + virtual void changeCell(const MWWorld::CellStore* cell) = 0; ///< change the active cell virtual void setFocusObject(const MWWorld::Ptr& focus) = 0; @@ -354,7 +354,6 @@ namespace MWBase virtual std::string correctBookartPath(const std::string& path, int width, int height) = 0; virtual std::string correctTexturePath(const std::string& path) = 0; - virtual void requestMap(std::set cells) = 0; virtual void removeCell(MWWorld::CellStore* cell) = 0; virtual void writeFog(MWWorld::CellStore* cell) = 0; }; diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 89f4d8cf3..469564d9d 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -454,6 +454,26 @@ namespace MWGui updateCustomMarkers(); } + void LocalMapBase::requestMapRender(const MWWorld::CellStore *cell) + { + std::set cells; + if (!cell->isExterior()) + cells.insert(cell); + else + { + for (int dX=-1; dX<2; ++dX) + { + for (int dY=-1; dY<2; ++dY) + { + const MWWorld::CellStore* gridCell = MWBase::Environment::get().getWorld()->getExterior (cell->getCell()->getGridX()+dX, cell->getCell()->getGridY()+dY); + cells.insert(gridCell); + } + } + } + + mLocalMapRender->requestMap(cells); + } + void LocalMapBase::redraw() { // Redraw children in proper order diff --git a/apps/openmw/mwgui/mapwindow.hpp b/apps/openmw/mwgui/mapwindow.hpp index 227a9e3f9..96fd3c994 100644 --- a/apps/openmw/mwgui/mapwindow.hpp +++ b/apps/openmw/mwgui/mapwindow.hpp @@ -23,6 +23,11 @@ namespace ESM class ESMWriter; } +namespace MWWorld +{ + class CellStore; +} + namespace Loading { class Listener; @@ -67,6 +72,7 @@ namespace MWGui void setCellPrefix(const std::string& prefix); void setActiveCell(const int x, const int y, bool interior=false); + void requestMapRender(const MWWorld::CellStore* cell); void setPlayerDir(const float x, const float y); void setPlayerPos(int cellX, int cellY, const float nx, const float ny); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index f151bee80..90c0494f6 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -926,7 +926,7 @@ namespace MWGui if (!mLocalMapRender) return; - MWWorld::Ptr player = MWMechanics::getPlayer(); + MWWorld::ConstPtr player = MWMechanics::getPlayer(); osg::Vec3f playerPosition = player.getRefData().getPosition().asVec3(); osg::Quat playerOrientation (-player.getRefData().getPosition().rot[2], osg::Vec3(0,0,1)); @@ -938,10 +938,9 @@ namespace MWGui if (!player.getCell()->isExterior()) { - mMap->setActiveCell(x, y, true); - mHud->setActiveCell(x, y, true); + setActiveMap(x, y, true); } - // else: need to know the current grid center, call setActiveCell from MWWorld::Scene + // else: need to know the current grid center, call setActiveMap from changeCell mMap->setPlayerDir(playerdirection.x(), playerdirection.y()); mMap->setPlayerPos(x, y, u, v); @@ -1007,8 +1006,10 @@ namespace MWGui mDebugWindow->onFrame(frameDuration); } - void WindowManager::changeCell(MWWorld::CellStore* cell) + void WindowManager::changeCell(const MWWorld::CellStore* cell) { + mMap->requestMapRender(cell); + std::string name = MWBase::Environment::get().getWorld()->getCellName (cell); mMap->setCellName( name ); @@ -1020,6 +1021,8 @@ namespace MWGui mMap->addVisitedLocation (name, cell->getCell()->getGridX (), cell->getCell()->getGridY ()); mMap->cellExplored (cell->getCell()->getGridX(), cell->getCell()->getGridY()); + + setActiveMap(cell->getCell()->getGridX(), cell->getCell()->getGridY(), false); } else { @@ -1032,6 +1035,8 @@ namespace MWGui else MWBase::Environment::get().getWorld()->getPlayer().setLastKnownExteriorPosition(worldPos); mMap->setGlobalMapPlayerPosition(worldPos.x(), worldPos.y()); + + setActiveMap(0, 0, true); } } @@ -2078,11 +2083,6 @@ namespace MWGui tex->unlock(); } - void WindowManager::requestMap(std::set cells) - { - mLocalMapRender->requestMap(cells); - } - void WindowManager::removeCell(MWWorld::CellStore *cell) { mLocalMapRender->removeCell(cell); diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 6edb4660c..3cdba8a87 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -204,7 +204,7 @@ namespace MWGui virtual void configureSkills (const SkillList& major, const SkillList& minor); ///< configure skill groups, each set contains the skill ID for that group. virtual void updateSkillArea(); ///< update display of skills, factions, birth sign, reputation and bounty - virtual void changeCell(MWWorld::CellStore* cell); ///< change the active cell + virtual void changeCell(const MWWorld::CellStore* cell); ///< change the active cell virtual void setFocusObject(const MWWorld::Ptr& focus); virtual void setFocusObjectScreenCoords(float min_x, float min_y, float max_x, float max_y); @@ -375,7 +375,6 @@ namespace MWGui virtual std::string correctBookartPath(const std::string& path, int width, int height); virtual std::string correctTexturePath(const std::string& path); - void requestMap(std::set cells); void removeCell(MWWorld::CellStore* cell); void writeFog(MWWorld::CellStore* cell); diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 200f484b5..4efcf5d1b 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -229,11 +229,11 @@ void LocalMap::setupRenderToTexture(osg::ref_ptr camera, int x, int segment.mMapTexture = texture; } -void LocalMap::requestMap(std::set cells) +void LocalMap::requestMap(std::set cells) { - for (std::set::iterator it = cells.begin(); it != cells.end(); ++it) + for (std::set::iterator it = cells.begin(); it != cells.end(); ++it) { - MWWorld::CellStore* cell = *it; + const MWWorld::CellStore* cell = *it; if (cell->isExterior()) requestExteriorMap(cell); else @@ -296,7 +296,7 @@ void LocalMap::cleanupCameras() mCamerasPendingRemoval.clear(); } -void LocalMap::requestExteriorMap(MWWorld::CellStore* cell) +void LocalMap::requestExteriorMap(const MWWorld::CellStore* cell) { mInterior = false; @@ -321,7 +321,7 @@ void LocalMap::requestExteriorMap(MWWorld::CellStore* cell) } } -void LocalMap::requestInteriorMap(MWWorld::CellStore* cell) +void LocalMap::requestInteriorMap(const MWWorld::CellStore* cell) { osg::ComputeBoundsVisitor computeBoundsVisitor; computeBoundsVisitor.setTraversalMask(Mask_Scene|Mask_Terrain); @@ -375,6 +375,7 @@ void LocalMap::requestInteriorMap(MWWorld::CellStore* cell) // If they changed by too much (for bounds, < padding is considered acceptable) then parts of the interior might not // be covered by the map anymore. // The following code detects this, and discards the CellStore's fog state if it needs to. + bool cellHasValidFog = false; if (cell->getFog()) { ESM::FogState* fog = cell->getFog(); @@ -390,13 +391,14 @@ void LocalMap::requestInteriorMap(MWWorld::CellStore* cell) || std::abs(mAngle - fog->mNorthMarkerAngle) > osg::DegreesToRadians(5.f)) { // Nuke it - cell->setFog(NULL); + cellHasValidFog = false; } else { // Looks sane, use it mBounds = osg::BoundingBox(newMin, newMax); mAngle = fog->mNorthMarkerAngle; + cellHasValidFog = true; } } @@ -434,7 +436,7 @@ void LocalMap::requestInteriorMap(MWWorld::CellStore* cell) MapSegment& segment = mSegments[std::make_pair(x,y)]; if (!segment.mFogOfWarImage) { - if (!cell->getFog()) + if (!cellHasValidFog) segment.initFogOfWar(); else { diff --git a/apps/openmw/mwrender/localmap.hpp b/apps/openmw/mwrender/localmap.hpp index 59165013d..52f570b0b 100644 --- a/apps/openmw/mwrender/localmap.hpp +++ b/apps/openmw/mwrender/localmap.hpp @@ -52,7 +52,7 @@ namespace MWRender /** * Request a map render for the given cells. Render textures will be immediately created and can be retrieved with the getMapTexture function. */ - void requestMap (std::set cells); + void requestMap (std::set cells); /** * Remove map and fog textures for the given cell. @@ -146,8 +146,8 @@ namespace MWRender float mAngle; const osg::Vec2f rotatePoint(const osg::Vec2f& point, const osg::Vec2f& center, const float angle); - void requestExteriorMap(MWWorld::CellStore* cell); - void requestInteriorMap(MWWorld::CellStore* cell); + void requestExteriorMap(const MWWorld::CellStore* cell); + void requestInteriorMap(const MWWorld::CellStore* cell); osg::ref_ptr createOrthographicCamera(float left, float top, float width, float height, const osg::Vec3d& upVector, float zmin, float zmax); void setupRenderToTexture(osg::ref_ptr camera, int x, int y); diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 15b3c057b..dc93c3b1d 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -179,27 +179,6 @@ namespace MWWorld void Scene::update (float duration, bool paused) { - if (mNeedMapUpdate) - { - // Note: exterior cell maps must be updated, even if they were visited before, because the set of surrounding cells might be different - // (and objects in a different cell can "bleed" into another cells map if they cross the border) - std::set cellsToUpdate; - for (CellStoreCollection::iterator active = mActiveCells.begin(); active!=mActiveCells.end(); ++active) - { - cellsToUpdate.insert(*active); - } - MWBase::Environment::get().getWindowManager()->requestMap(cellsToUpdate); - - mNeedMapUpdate = false; - - if (mCurrentCell->isExterior()) - { - int cellX, cellY; - getGridCenter(cellX, cellY); - MWBase::Environment::get().getWindowManager()->setActiveMap(cellX,cellY,false); - } - } - mRendering.update (duration, paused); } @@ -410,10 +389,6 @@ namespace MWWorld mCellChanged = true; - // Delay the map update until scripts have been given a chance to run. - // If we don't do this, objects that should be disabled will still appear on the map. - mNeedMapUpdate = true; - mRendering.getResourceSystem()->clearCache(); } @@ -449,7 +424,7 @@ namespace MWWorld } Scene::Scene (MWRender::RenderingManager& rendering, MWPhysics::PhysicsSystem *physics) - : mCurrentCell (0), mCellChanged (false), mPhysics(physics), mRendering(rendering), mNeedMapUpdate(false) + : mCurrentCell (0), mCellChanged (false), mPhysics(physics), mRendering(rendering) { } @@ -527,10 +502,6 @@ namespace MWWorld MWBase::Environment::get().getWindowManager()->changeCell(mCurrentCell); - // Delay the map update until scripts have been given a chance to run. - // If we don't do this, objects that should be disabled will still appear on the map. - mNeedMapUpdate = true; - mRendering.getResourceSystem()->clearCache(); } diff --git a/apps/openmw/mwworld/scene.hpp b/apps/openmw/mwworld/scene.hpp index 439c8d72c..c6de3ebdf 100644 --- a/apps/openmw/mwworld/scene.hpp +++ b/apps/openmw/mwworld/scene.hpp @@ -58,8 +58,6 @@ namespace MWWorld MWPhysics::PhysicsSystem *mPhysics; MWRender::RenderingManager& mRendering; - bool mNeedMapUpdate; - void insertCell (CellStore &cell, bool rescale, Loading::Listener* loadingListener); // Load and unload cells as necessary to create a cell grid with "X" and "Y" in the center From 7d647088ab577357d48e437ef6579a60102e5006 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 5 Feb 2016 01:18:44 +0100 Subject: [PATCH 3066/3725] Make the local map cell distance configurable --- apps/openmw/mwgui/hud.cpp | 2 +- apps/openmw/mwgui/mapwindow.cpp | 59 ++++++++++++++++--------------- apps/openmw/mwgui/mapwindow.hpp | 5 ++- apps/openmw/mwrender/localmap.cpp | 5 +-- apps/openmw/mwrender/localmap.hpp | 2 ++ files/settings-default.cfg | 5 +++ 6 files changed, 46 insertions(+), 32 deletions(-) diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 8d6ce6beb..b5c8dc8bb 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -159,7 +159,7 @@ namespace MWGui getWidget(mCrosshair, "Crosshair"); - LocalMapBase::init(mMinimap, mCompass, Settings::Manager::getInt("local map hud widget size", "Map")); + LocalMapBase::init(mMinimap, mCompass, Settings::Manager::getInt("local map hud widget size", "Map"), Settings::Manager::getInt("local map cell distance", "Map")); mMainWidget->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onWorldClicked); mMainWidget->eventMouseMove += MyGUI::newDelegate(this, &HUD::onWorldMouseOver); diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 469564d9d..3b5f0d8aa 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -181,20 +181,22 @@ namespace MWGui mCustomMarkers.eventMarkersChanged -= MyGUI::newDelegate(this, &LocalMapBase::updateCustomMarkers); } - void LocalMapBase::init(MyGUI::ScrollView* widget, MyGUI::ImageBox* compass, int mapWidgetSize) + void LocalMapBase::init(MyGUI::ScrollView* widget, MyGUI::ImageBox* compass, int mapWidgetSize, int cellDistance) { mLocalMap = widget; mCompass = compass; mMapWidgetSize = mapWidgetSize; + mCellDistance = cellDistance; + mNumCells = cellDistance * 2 + 1; - mLocalMap->setCanvasSize(mMapWidgetSize*3, mMapWidgetSize*3); + mLocalMap->setCanvasSize(mMapWidgetSize*mNumCells, mMapWidgetSize*mNumCells); mCompass->setDepth(Local_CompassLayer); mCompass->setNeedMouseFocus(false); - for (int mx=0; mx<3; ++mx) + for (int mx=0; mxcreateWidget("ImageBox", MyGUI::IntCoord(mx*mMapWidgetSize, my*mMapWidgetSize, mMapWidgetSize, mMapWidgetSize), @@ -231,13 +233,13 @@ namespace MWGui void LocalMapBase::applyFogOfWar() { TextureVector fogTextures; - for (int mx=0; mx<3; ++mx) + for (int mx=0; mx(nX * mMapWidgetSize + (1 + cellDx) * mMapWidgetSize), - static_cast(nY * mMapWidgetSize - (cellDy-1) * mMapWidgetSize)); + widgetPos = MyGUI::IntPoint(static_cast(nX * mMapWidgetSize + (mCellDistance + cellDx) * mMapWidgetSize), + static_cast(nY * mMapWidgetSize + (mCellDistance - cellDy) * mMapWidgetSize)); } else { @@ -297,8 +299,8 @@ namespace MWGui markerPos.cellY = cellY; // Image space is -Y up, cells are Y up - widgetPos = MyGUI::IntPoint(static_cast(nX * mMapWidgetSize + (1 + (cellX - mCurX)) * mMapWidgetSize), - static_cast(nY * mMapWidgetSize + (1-(cellY-mCurY)) * mMapWidgetSize)); + widgetPos = MyGUI::IntPoint(static_cast(nX * mMapWidgetSize + (mCellDistance + (cellX - mCurX)) * mMapWidgetSize), + static_cast(nY * mMapWidgetSize + (mCellDistance - (cellY - mCurY)) * mMapWidgetSize)); } markerPos.nX = nX; @@ -312,9 +314,9 @@ namespace MWGui MyGUI::Gui::getInstance().destroyWidget(*it); mCustomMarkerWidgets.clear(); - for (int dX = -1; dX <= 1; ++dX) + for (int dX = -mCellDistance; dX <= mCellDistance; ++dX) { - for (int dY =-1; dY <= 1; ++dY) + for (int dY =-mCellDistance; dY <= mCellDistance; ++dY) { ESM::CellId cellId; cellId.mPaged = !mInterior; @@ -372,14 +374,14 @@ namespace MWGui // Update the map textures TextureVector textures; - for (int mx=0; mx<3; ++mx) + for (int mx=0; mx texture = mLocalMapRender->getMapTexture(mapX, mapY); if (texture) @@ -406,9 +408,9 @@ namespace MWGui } else { - for (int dX=-1; dX<2; ++dX) + for (int dX=-mCellDistance; dX<=mCellDistance; ++dX) { - for (int dY=-1; dY<2; ++dY) + for (int dY=-mCellDistance; dY<=mCellDistance; ++dY) { MWWorld::CellStore* cell = world->getExterior (mCurX+dX, mCurY+dY); world->getDoorMarkers(cell, doors); @@ -461,9 +463,9 @@ namespace MWGui cells.insert(cell); else { - for (int dX=-1; dX<2; ++dX) + for (int dX=-mCellDistance; dX<=mCellDistance; ++dX) { - for (int dY=-1; dY<2; ++dY) + for (int dY=-mCellDistance; dY<=mCellDistance; ++dY) { const MWWorld::CellStore* gridCell = MWBase::Environment::get().getWorld()->getExterior (cell->getCell()->getGridX()+dX, cell->getCell()->getGridY()+dY); cells.insert(gridCell); @@ -482,7 +484,7 @@ namespace MWGui void LocalMapBase::setPlayerPos(int cellX, int cellY, const float nx, const float ny) { - MyGUI::IntPoint pos(static_cast(mMapWidgetSize + nx*mMapWidgetSize - 16), static_cast(mMapWidgetSize + ny*mMapWidgetSize - 16)); + MyGUI::IntPoint pos(static_cast(mMapWidgetSize * mCellDistance + nx*mMapWidgetSize - 16), static_cast(mMapWidgetSize * mCellDistance + ny*mMapWidgetSize - 16)); pos.left += (cellX - mCurX) * mMapWidgetSize; pos.top -= (cellY - mCurY) * mMapWidgetSize; @@ -663,7 +665,8 @@ namespace MWGui mEventBoxLocal->eventMouseButtonPressed += MyGUI::newDelegate(this, &MapWindow::onDragStart); mEventBoxLocal->eventMouseButtonDoubleClick += MyGUI::newDelegate(this, &MapWindow::onMapDoubleClicked); - LocalMapBase::init(mLocalMap, mPlayerArrowLocal, Settings::Manager::getInt("local map widget size", "Map")); } + LocalMapBase::init(mLocalMap, mPlayerArrowLocal, Settings::Manager::getInt("local map widget size", "Map"), Settings::Manager::getInt("local map cell distance", "Map")); + } void MapWindow::onNoteEditOk() { @@ -707,8 +710,8 @@ namespace MWGui MyGUI::IntPoint clickedPos = MyGUI::InputManager::getInstance().getMousePosition(); MyGUI::IntPoint widgetPos = clickedPos - mEventBoxLocal->getAbsolutePosition(); - int x = int(widgetPos.left/float(mMapWidgetSize))-1; - int y = (int(widgetPos.top/float(mMapWidgetSize))-1)*-1; + int x = int(widgetPos.left/float(mMapWidgetSize))-mCellDistance; + int y = (int(widgetPos.top/float(mMapWidgetSize))-mCellDistance)*-1; float nX = widgetPos.left/float(mMapWidgetSize) - int(widgetPos.left/float(mMapWidgetSize)); float nY = widgetPos.top/float(mMapWidgetSize) - int(widgetPos.top/float(mMapWidgetSize)); x += mCurX; diff --git a/apps/openmw/mwgui/mapwindow.hpp b/apps/openmw/mwgui/mapwindow.hpp index 96fd3c994..773522903 100644 --- a/apps/openmw/mwgui/mapwindow.hpp +++ b/apps/openmw/mwgui/mapwindow.hpp @@ -68,7 +68,7 @@ namespace MWGui public: LocalMapBase(CustomMarkerCollection& markers, MWRender::LocalMap* localMapRender, bool fogOfWarEnabled = true); virtual ~LocalMapBase(); - void init(MyGUI::ScrollView* widget, MyGUI::ImageBox* compass, int mapWidgetSize); + void init(MyGUI::ScrollView* widget, MyGUI::ImageBox* compass, int mapWidgetSize, int cellDistance); void setCellPrefix(const std::string& prefix); void setActiveCell(const int x, const int y, bool interior=false); @@ -116,6 +116,9 @@ namespace MWGui int mMapWidgetSize; + int mNumCells; // for convenience, mCellDistance * 2 + 1 + int mCellDistance; + // Stores markers that were placed by a player. May be shared between multiple map views. CustomMarkerCollection& mCustomMarkers; diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 4efcf5d1b..fd224ba41 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -72,6 +72,7 @@ LocalMap::LocalMap(osgViewer::Viewer* viewer) : mViewer(viewer) , mMapResolution(Settings::Manager::getInt("local map resolution", "Map")) , mMapWorldSize(8192.f) + , mCellDistance(Settings::Manager::getInt("local map cell distance", "Map")) , mAngle(0.f) , mInterior(false) { @@ -533,9 +534,9 @@ void LocalMap::updatePlayer (const osg::Vec3f& position, const osg::Quat& orient 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) - for (int mx = -1; mx<2; ++mx) + for (int mx = -mCellDistance; mx<=mCellDistance; ++mx) { - for (int my = -1; my<2; ++my) + for (int my = -mCellDistance; my<=mCellDistance; ++my) { // is this texture affected at all? bool affected = false; diff --git a/apps/openmw/mwrender/localmap.hpp b/apps/openmw/mwrender/localmap.hpp index 52f570b0b..d946f4c2b 100644 --- a/apps/openmw/mwrender/localmap.hpp +++ b/apps/openmw/mwrender/localmap.hpp @@ -143,6 +143,8 @@ namespace MWRender // size of a map segment (for exteriors, 1 cell) float mMapWorldSize; + int mCellDistance; + float mAngle; const osg::Vec2f rotatePoint(const osg::Vec2f& point, const osg::Vec2f& center, const float angle); diff --git a/files/settings-default.cfg b/files/settings-default.cfg index e4a8387b4..dddf1a29b 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -58,6 +58,11 @@ local map resolution = 256 # Size of local map in GUI window in pixels. (e.g. 256 to 1024). local map widget size = 512 +# Similar to "[Cells] exterior cell load distance", controls +# how many cells are rendered on the local map. Values higher than the default +# may result in longer loading times. +local map cell distance = 1 + [GUI] # Scales GUI window and widget size. (<1.0 is smaller, >1.0 is larger). From 8e5398d85b72e951a3804df4922a47a5a95e6ce2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 5 Feb 2016 14:35:29 +0100 Subject: [PATCH 3067/3725] Add missing initializations --- apps/openmw/mwgui/mapwindow.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 3b5f0d8aa..362d2d9e0 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -168,6 +168,8 @@ namespace MWGui , mFogOfWarToggled(true) , mFogOfWarEnabled(fogOfWarEnabled) , mMapWidgetSize(0) + , mNumCells(0) + , mCellDistance(0) , mCustomMarkers(markers) , mMarkerUpdateTimer(0.0f) , mLastDirectionX(0.0f) From c9a67ab42357bdb28d63e243946dc734a9030610 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 5 Feb 2016 18:29:33 +0100 Subject: [PATCH 3068/3725] Do not add scripts from levelled creatures twice (Bug #2806) Do not insert objects from within a CellStore visitor --- apps/openmw/mwworld/cellstore.hpp | 3 ++ apps/openmw/mwworld/scene.cpp | 58 +++++++++++++++++++------------ 2 files changed, 39 insertions(+), 22 deletions(-) diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index faba76262..2f483f0ba 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -246,6 +246,7 @@ namespace MWWorld /// Call visitor (MWWorld::Ptr) for each reference. visitor must return a bool. Returning /// false will abort the iteration. /// \note Prefer using forEachConst when possible. + /// \note Do not modify this cell (i.e. remove/add objects) during the forEach, doing this may result in unintended behaviour. /// \attention This function also lists deleted (count 0) objects! /// \return Iteration completed? template @@ -269,6 +270,7 @@ namespace MWWorld /// Call visitor (MWWorld::ConstPtr) for each reference. visitor must return a bool. Returning /// false will abort the iteration. + /// \note Do not modify this cell (i.e. remove/add objects) during the forEach, doing this may result in unintended behaviour. /// \attention This function also lists deleted (count 0) objects! /// \return Iteration completed? template @@ -291,6 +293,7 @@ namespace MWWorld /// Call visitor (ref) for each reference of given type. visitor must return a bool. Returning /// false will abort the iteration. + /// \note Do not modify this cell (i.e. remove/add objects) during the forEach, doing this may result in unintended behaviour. /// \attention This function also lists deleted (count 0) objects! /// \return Iteration completed? template diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index dc93c3b1d..618a219f3 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -86,10 +86,13 @@ namespace MWPhysics::PhysicsSystem& mPhysics; MWRender::RenderingManager& mRendering; + std::vector mToInsert; + InsertVisitor (MWWorld::CellStore& cell, bool rescale, Loading::Listener& loadingListener, MWPhysics::PhysicsSystem& physics, MWRender::RenderingManager& rendering); bool operator() (const MWWorld::Ptr& ptr); + void insert(); }; InsertVisitor::InsertVisitor (MWWorld::CellStore& cell, bool rescale, @@ -102,31 +105,41 @@ namespace bool InsertVisitor::operator() (const MWWorld::Ptr& ptr) { - if (mRescale) - { - if (ptr.getCellRef().getScale()<0.5) - ptr.getCellRef().setScale(0.5); - else if (ptr.getCellRef().getScale()>2) - ptr.getCellRef().setScale(2); - } + // do not insert directly as we can't modify the cell from within the visitation + // CreatureLevList::insertObjectRendering may spawn a new creature + mToInsert.push_back(ptr); + return true; + } - if (!ptr.getRefData().isDeleted() && ptr.getRefData().isEnabled()) + void InsertVisitor::insert() + { + for (std::vector::iterator it = mToInsert.begin(); it != mToInsert.end(); ++it) { - try + MWWorld::Ptr ptr = *it; + if (mRescale) { - addObject(ptr, mPhysics, mRendering); - updateObjectRotation(ptr, mPhysics, mRendering, false); + if (ptr.getCellRef().getScale()<0.5) + ptr.getCellRef().setScale(0.5); + else if (ptr.getCellRef().getScale()>2) + ptr.getCellRef().setScale(2); } - catch (const std::exception& e) + + if (!ptr.getRefData().isDeleted() && ptr.getRefData().isEnabled()) { - std::string error ("error during rendering '" + ptr.getCellRef().getRefId() + "': "); - std::cerr << error + e.what() << std::endl; + try + { + addObject(ptr, mPhysics, mRendering); + updateObjectRotation(ptr, mPhysics, mRendering, false); + } + catch (const std::exception& e) + { + std::string error ("error during rendering '" + ptr.getCellRef().getRefId() + "': "); + std::cerr << error + e.what() << std::endl; + } } - } - - mLoadingListener.increaseProgress (1); - return true; + mLoadingListener.increaseProgress (1); + } } struct AdjustPositionVisitor @@ -248,6 +261,10 @@ namespace MWWorld cell->respawn(); + // register local scripts + // do this before insertCell, to make sure we don't add scripts from levelled creature spawning twice + MWBase::Environment::get().getWorld()->getLocalScripts().addCell (cell); + // ... then references. This is important for adjustPosition to work correctly. /// \todo rescale depending on the state of a new GMST insertCell (*cell, true, loadingListener); @@ -267,10 +284,6 @@ namespace MWWorld if (!cell->isExterior() && !(cell->getCell()->mData.mFlags & ESM::Cell::QuasiEx)) mRendering.configureAmbient(cell->getCell()); } - - // register local scripts - // ??? Should this go into the above if block ??? - MWBase::Environment::get().getWorld()->getLocalScripts().addCell (cell); } void Scene::changeToVoid() @@ -534,6 +547,7 @@ namespace MWWorld { InsertVisitor insertVisitor (cell, rescale, *loadingListener, *mPhysics, mRendering); cell.forEach (insertVisitor); + insertVisitor.insert(); // do adjustPosition (snapping actors to ground) after objects are loaded, so we don't depend on the loading order AdjustPositionVisitor adjustPosVisitor; From b06730ac612cadfa81c382712fe5d22a69c16c79 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 5 Feb 2016 21:02:02 +0100 Subject: [PATCH 3069/3725] Fix terrain textureCompileDummy --- components/terrain/terraingrid.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/terrain/terraingrid.cpp b/components/terrain/terraingrid.cpp index aa82e0bd6..fb037c003 100644 --- a/components/terrain/terraingrid.cpp +++ b/components/terrain/terraingrid.cpp @@ -133,12 +133,12 @@ osg::ref_ptr TerrainGrid::buildTerrain (osg::Group* parent, float chu // For compiling textures, I don't think the osgFX::Effect does it correctly osg::ref_ptr textureCompileDummy (new osg::Node); - + unsigned int dummyTextureCounter = 0; std::vector > layerTextures; for (std::vector::const_iterator it = layerList.begin(); it != layerList.end(); ++it) { layerTextures.push_back(mResourceSystem->getTextureManager()->getTexture2D(it->mDiffuseMap, osg::Texture::REPEAT, osg::Texture::REPEAT)); - textureCompileDummy->getOrCreateStateSet()->setTextureAttributeAndModes(0, layerTextures.back()); + textureCompileDummy->getOrCreateStateSet()->setTextureAttributeAndModes(dummyTextureCounter++, layerTextures.back()); } std::vector > blendmapTextures; @@ -153,7 +153,7 @@ osg::ref_ptr TerrainGrid::buildTerrain (osg::Group* parent, float chu texture->setResizeNonPowerOfTwoHint(false); blendmapTextures.push_back(texture); - textureCompileDummy->getOrCreateStateSet()->setTextureAttributeAndModes(0, layerTextures.back()); + textureCompileDummy->getOrCreateStateSet()->setTextureAttributeAndModes(dummyTextureCounter++, blendmapTextures.back()); } // use texture coordinates for both texture units, the layer texture and blend texture From 5b972ee7776e198c374f8ff76d3cae1682175397 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 5 Feb 2016 18:51:51 +0100 Subject: [PATCH 3070/3725] Move texture filtering settings to SceneManager Practical benefits: - Filter settings are now applied to native OSG format models. These models do not use TextureManager::getTexture2D since the model itself specifies a Texture. - The GUI render manager will be able to use its own separate textures, making it easier to turn off filtering for them. --- apps/openmw/engine.cpp | 6 +- apps/openmw/mwrender/animation.cpp | 4 +- apps/openmw/mwrender/renderingmanager.cpp | 2 +- components/nifosg/controller.hpp | 2 + components/resource/scenemanager.cpp | 207 ++++++++++++++++++++++ components/resource/scenemanager.hpp | 31 ++++ components/resource/texturemanager.cpp | 92 ---------- components/resource/texturemanager.hpp | 17 -- 8 files changed, 247 insertions(+), 114 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index f347bc350..d96bf16e4 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -20,7 +20,7 @@ #include #include -#include +#include #include @@ -448,8 +448,8 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) VFS::registerArchives(mVFS.get(), mFileCollections, mArchives, true); mResourceSystem.reset(new Resource::ResourceSystem(mVFS.get())); - mResourceSystem->getTextureManager()->setUnRefImageDataAfterApply(true); - mResourceSystem->getTextureManager()->setFilterSettings( + mResourceSystem->getSceneManager()->setUnRefImageDataAfterApply(true); + mResourceSystem->getSceneManager()->setFilterSettings( Settings::Manager::getString("texture mag filter", "General"), Settings::Manager::getString("texture min filter", "General"), Settings::Manager::getString("texture mipmap", "General"), diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 549d0eb8e..a7bb3f128 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1059,7 +1059,9 @@ namespace MWRender stream << i; stream << ".dds"; - textures.push_back(mResourceSystem->getTextureManager()->getTexture2D(stream.str(), osg::Texture2D::REPEAT, osg::Texture2D::REPEAT)); + osg::ref_ptr tex = mResourceSystem->getTextureManager()->getTexture2D(stream.str(), osg::Texture2D::REPEAT, osg::Texture2D::REPEAT); + mResourceSystem->getSceneManager()->applyFilterSettings(tex); + textures.push_back(tex); } osg::ref_ptr glowupdater (new GlowUpdater(glowColor, textures)); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index c8d0925b0..755a8019b 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -776,7 +776,7 @@ namespace MWRender void RenderingManager::updateTextureFiltering() { - mResourceSystem->getTextureManager()->setFilterSettings( + mResourceSystem->getSceneManager()->setFilterSettings( Settings::Manager::getString("texture mag filter", "General"), Settings::Manager::getString("texture min filter", "General"), Settings::Manager::getString("texture mipmap", "General"), diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index e1e969d06..0b633a122 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -305,6 +305,8 @@ namespace NifOsg META_Object(NifOsg, FlipController) + std::vector >& getTextures() { return mTextures; } + virtual void apply(osg::StateSet *stateset, osg::NodeVisitor *nv); }; diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index 43ece41f3..80e6f737d 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -9,6 +9,8 @@ #include +#include + #include #include @@ -19,6 +21,7 @@ #include #include +#include #include "texturemanager.hpp" #include "niffilemanager.hpp" @@ -105,10 +108,123 @@ namespace namespace Resource { + /// Set texture filtering settings on textures contained in a FlipController. + class SetFilterSettingsControllerVisitor : public SceneUtil::ControllerVisitor + { + public: + SetFilterSettingsControllerVisitor(osg::Texture::FilterMode minFilter, osg::Texture::FilterMode magFilter, int maxAnisotropy) + : mMinFilter(minFilter) + , mMagFilter(magFilter) + , mMaxAnisotropy(maxAnisotropy) + { + } + + virtual void visit(osg::Node& node, SceneUtil::Controller& ctrl) + { + if (NifOsg::FlipController* flipctrl = dynamic_cast(&ctrl)) + { + for (std::vector >::iterator it = flipctrl->getTextures().begin(); it != flipctrl->getTextures().end(); ++it) + { + osg::Texture* tex = *it; + tex->setFilter(osg::Texture::MIN_FILTER, mMinFilter); + tex->setFilter(osg::Texture::MAG_FILTER, mMagFilter); + tex->setMaxAnisotropy(mMaxAnisotropy); + mTexturesProcessed.insert(tex); + } + } + } + + const std::set >& getTexturesProcessed() + { + return mTexturesProcessed; + } + + private: + osg::Texture::FilterMode mMinFilter; + osg::Texture::FilterMode mMagFilter; + int mMaxAnisotropy; + std::set > mTexturesProcessed; + }; + + /// Set texture filtering settings on textures contained in StateSets. + class SetFilterSettingsVisitor : public osg::NodeVisitor + { + public: + SetFilterSettingsVisitor(osg::Texture::FilterMode minFilter, osg::Texture::FilterMode magFilter, int maxAnisotropy) + : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) + , mMinFilter(minFilter) + , mMagFilter(magFilter) + , mMaxAnisotropy(maxAnisotropy) + { + } + + virtual void apply(osg::Node& node) + { + osg::StateSet* stateset = node.getStateSet(); + if (stateset) + apply(stateset); + traverse(node); + } + + virtual void apply(osg::Geode& geode) + { + osg::StateSet* stateset = geode.getStateSet(); + if (stateset) + apply(stateset); + + for (unsigned int i=0; igetStateSet(); + if (stateset) + apply(stateset); + } + } + + void apply(osg::StateSet* stateset) + { + const osg::StateSet::TextureAttributeList& texAttributes = stateset->getTextureAttributeList(); + for(unsigned int unit=0;unitgetTextureAttribute(unit, osg::StateAttribute::TEXTURE); + apply(texture); + } + } + + void apply(osg::StateAttribute* attr) + { + osg::Texture* tex = attr->asTexture(); + if (tex) + { + tex->setFilter(osg::Texture::MIN_FILTER, mMinFilter); + tex->setFilter(osg::Texture::MAG_FILTER, mMagFilter); + tex->setMaxAnisotropy(mMaxAnisotropy); + mTexturesProcessed.insert(tex); + } + } + + const std::set >& getTexturesProcessed() + { + return mTexturesProcessed; + } + + private: + osg::Texture::FilterMode mMinFilter; + osg::Texture::FilterMode mMagFilter; + int mMaxAnisotropy; + std::set > mTexturesProcessed; + }; + + + SceneManager::SceneManager(const VFS::Manager *vfs, Resource::TextureManager* textureManager, Resource::NifFileManager* nifFileManager) : mVFS(vfs) , mTextureManager(textureManager) , mNifFileManager(nifFileManager) + , mMinFilter(osg::Texture::LINEAR_MIPMAP_LINEAR) + , mMagFilter(osg::Texture::LINEAR) + , mMaxAnisotropy(1) + , mUnRefImageDataAfterApply(false) , mParticleSystemMask(~0u) { } @@ -219,6 +335,17 @@ namespace Resource throw; } + // set filtering settings + SetFilterSettingsVisitor setFilterSettingsVisitor(mMinFilter, mMagFilter, mMaxAnisotropy); + loaded->accept(setFilterSettingsVisitor); + SetFilterSettingsControllerVisitor setFilterSettingsControllerVisitor(mMinFilter, mMagFilter, mMaxAnisotropy); + loaded->accept(setFilterSettingsControllerVisitor); + + // remember which textures we set a filtering setting on so we can re-apply it when the setting changes + mTexturesWithFilterSetting.insert(setFilterSettingsVisitor.getTexturesProcessed().begin(), setFilterSettingsVisitor.getTexturesProcessed().end()); + mTexturesWithFilterSetting.insert(setFilterSettingsControllerVisitor.getTexturesProcessed().begin(), setFilterSettingsControllerVisitor.getTexturesProcessed().end()); + + // share state osgDB::Registry::instance()->getOrCreateSharedStateManager()->share(loaded.get()); if (mIncrementalCompileOperation) @@ -285,4 +412,84 @@ namespace Resource mParticleSystemMask = mask; } + void SceneManager::setFilterSettings(const std::string &magfilter, const std::string &minfilter, + const std::string &mipmap, int maxAnisotropy, + osgViewer::Viewer *viewer) + { + osg::Texture::FilterMode min = osg::Texture::LINEAR; + osg::Texture::FilterMode mag = osg::Texture::LINEAR; + + if(magfilter == "nearest") + mag = osg::Texture::NEAREST; + else if(magfilter != "linear") + std::cerr<< "Invalid texture mag filter: "<stopThreading(); + setFilterSettings(min, mag, maxAnisotropy); + if(viewer) viewer->startThreading(); + } + + void SceneManager::applyFilterSettings(osg::Texture *tex) + { + tex->setFilter(osg::Texture::MIN_FILTER, mMinFilter); + tex->setFilter(osg::Texture::MAG_FILTER, mMagFilter); + tex->setMaxAnisotropy(mMaxAnisotropy); + mTexturesWithFilterSetting.insert(tex); + } + + void SceneManager::setUnRefImageDataAfterApply(bool unref) + { + mUnRefImageDataAfterApply = unref; + } + + void SceneManager::setFilterSettings(osg::Texture::FilterMode minFilter, osg::Texture::FilterMode magFilter, int maxAnisotropy) + { + mMinFilter = minFilter; + mMagFilter = magFilter; + mMaxAnisotropy = std::max(1, maxAnisotropy); + + for (std::set >::const_iterator it = mTexturesWithFilterSetting.begin(); it != mTexturesWithFilterSetting.end(); ++it) + { + (*it)->setFilter(osg::Texture::MIN_FILTER, mMinFilter); + (*it)->setFilter(osg::Texture::MAG_FILTER, mMagFilter); + (*it)->setMaxAnisotropy(mMaxAnisotropy); + } + } + + void SceneManager::clearCache() + { + // clear textures that are no longer referenced + for (std::set >::const_iterator it = mTexturesWithFilterSetting.begin(); it != mTexturesWithFilterSetting.end();) + { + osg::Texture* tex = *it; + if (tex->referenceCount() <= 1) + mTexturesWithFilterSetting.erase(it++); + else + ++it; + } + + } + } diff --git a/components/resource/scenemanager.hpp b/components/resource/scenemanager.hpp index 67fa2ab43..df330af5b 100644 --- a/components/resource/scenemanager.hpp +++ b/components/resource/scenemanager.hpp @@ -6,6 +6,7 @@ #include #include +#include namespace Resource { @@ -23,6 +24,11 @@ namespace osgUtil class IncrementalCompileOperation; } +namespace osgViewer +{ + class Viewer; +} + namespace Resource { @@ -69,11 +75,30 @@ namespace Resource /// @param mask The node mask to apply to loaded particle system nodes. void setParticleSystemMask(unsigned int mask); + void setFilterSettings(const std::string &magfilter, const std::string &minfilter, + const std::string &mipmap, int maxAnisotropy, + osgViewer::Viewer *viewer); + + /// Apply filter settings to the given texture. Note, when loading an object through this scene manager (i.e. calling getTemplate / createInstance) + /// the filter settings are applied automatically. This method is provided for textures that were created outside of the SceneManager. + void applyFilterSettings (osg::Texture* tex); + + /// Keep a copy of the texture data around in system memory? This is needed when using multiple graphics contexts, + /// otherwise should be disabled to reduce memory usage. + void setUnRefImageDataAfterApply(bool unref); + + void clearCache(); + private: const VFS::Manager* mVFS; Resource::TextureManager* mTextureManager; Resource::NifFileManager* mNifFileManager; + osg::Texture::FilterMode mMinFilter; + osg::Texture::FilterMode mMagFilter; + int mMaxAnisotropy; + bool mUnRefImageDataAfterApply; + osg::ref_ptr mIncrementalCompileOperation; unsigned int mParticleSystemMask; @@ -82,8 +107,14 @@ namespace Resource typedef std::map > Index; Index mIndex; + std::set > mTexturesWithFilterSetting; + SceneManager(const SceneManager&); void operator = (const SceneManager&); + + /// @warning It is unsafe to call this function when a draw thread is using the textures. Call stopThreading() first! + void setFilterSettings(osg::Texture::FilterMode minFilter, osg::Texture::FilterMode maxFilter, int maxAnisotropy); + }; } diff --git a/components/resource/texturemanager.cpp b/components/resource/texturemanager.cpp index d7f3fc61a..b49c6bb09 100644 --- a/components/resource/texturemanager.cpp +++ b/components/resource/texturemanager.cpp @@ -3,7 +3,6 @@ #include #include #include -#include #include @@ -47,11 +46,7 @@ namespace Resource TextureManager::TextureManager(const VFS::Manager *vfs) : mVFS(vfs) - , mMinFilter(osg::Texture::LINEAR_MIPMAP_LINEAR) - , mMagFilter(osg::Texture::LINEAR) - , mMaxAnisotropy(1) , mWarningTexture(createWarningTexture()) - , mUnRefImageDataAfterApply(false) { } @@ -61,88 +56,6 @@ namespace Resource } - void TextureManager::setUnRefImageDataAfterApply(bool unref) - { - mUnRefImageDataAfterApply = unref; - } - - void TextureManager::setFilterSettings(const std::string &magfilter, const std::string &minfilter, - const std::string &mipmap, int maxAnisotropy, - osgViewer::Viewer *viewer) - { - osg::Texture::FilterMode min = osg::Texture::LINEAR; - osg::Texture::FilterMode mag = osg::Texture::LINEAR; - - if(magfilter == "nearest") - mag = osg::Texture::NEAREST; - else if(magfilter != "linear") - std::cerr<< "Invalid texture mag filter: "<stopThreading(); - setFilterSettings(min, mag, maxAnisotropy); - if(viewer) viewer->startThreading(); - } - - void TextureManager::setFilterSettings(osg::Texture::FilterMode minFilter, osg::Texture::FilterMode magFilter, int maxAnisotropy) - { - mMinFilter = minFilter; - mMagFilter = magFilter; - mMaxAnisotropy = std::max(1, maxAnisotropy); - - for (std::map >::iterator it = mTextures.begin(); it != mTextures.end(); ++it) - { - osg::ref_ptr tex = it->second; - - // Keep mip-mapping disabled if the texture creator explicitely requested no mipmapping. - osg::Texture::FilterMode oldMin = tex->getFilter(osg::Texture::MIN_FILTER); - if (oldMin == osg::Texture::LINEAR || oldMin == osg::Texture::NEAREST) - { - osg::Texture::FilterMode newMin = osg::Texture::LINEAR; - switch (mMinFilter) - { - case osg::Texture::LINEAR: - case osg::Texture::LINEAR_MIPMAP_LINEAR: - case osg::Texture::LINEAR_MIPMAP_NEAREST: - newMin = osg::Texture::LINEAR; - break; - case osg::Texture::NEAREST: - case osg::Texture::NEAREST_MIPMAP_LINEAR: - case osg::Texture::NEAREST_MIPMAP_NEAREST: - newMin = osg::Texture::NEAREST; - break; - } - tex->setFilter(osg::Texture::MIN_FILTER, newMin); - } - else - tex->setFilter(osg::Texture::MIN_FILTER, mMinFilter); - - tex->setFilter(osg::Texture::MAG_FILTER, mMagFilter); - tex->setMaxAnisotropy(static_cast(mMaxAnisotropy)); - } - } - /* osg::ref_ptr TextureManager::getImage(const std::string &filename) { @@ -295,11 +208,6 @@ namespace Resource texture->setImage(image); texture->setWrap(osg::Texture::WRAP_S, wrapS); texture->setWrap(osg::Texture::WRAP_T, wrapT); - texture->setFilter(osg::Texture::MIN_FILTER, mMinFilter); - texture->setFilter(osg::Texture::MAG_FILTER, mMagFilter); - texture->setMaxAnisotropy(mMaxAnisotropy); - - texture->setUnRefImageDataAfterApply(mUnRefImageDataAfterApply); mTextures.insert(std::make_pair(key, texture)); return texture; diff --git a/components/resource/texturemanager.hpp b/components/resource/texturemanager.hpp index e12dfa090..61a727b5e 100644 --- a/components/resource/texturemanager.hpp +++ b/components/resource/texturemanager.hpp @@ -28,14 +28,6 @@ namespace Resource TextureManager(const VFS::Manager* vfs); ~TextureManager(); - void setFilterSettings(const std::string &magfilter, const std::string &minfilter, - const std::string &mipmap, int maxAnisotropy, - osgViewer::Viewer *view); - - /// Keep a copy of the texture data around in system memory? This is needed when using multiple graphics contexts, - /// otherwise should be disabled to reduce memory usage. - void setUnRefImageDataAfterApply(bool unref); - /// Create or retrieve a Texture2D using the specified image filename, and wrap parameters. /// Returns the dummy texture if the given texture is not found. osg::ref_ptr getTexture2D(const std::string& filename, osg::Texture::WrapMode wrapS, osg::Texture::WrapMode wrapT); @@ -50,10 +42,6 @@ namespace Resource private: const VFS::Manager* mVFS; - osg::Texture::FilterMode mMinFilter; - osg::Texture::FilterMode mMagFilter; - int mMaxAnisotropy; - typedef std::pair, std::string> MapKey; std::map > mImages; @@ -62,11 +50,6 @@ namespace Resource osg::ref_ptr mWarningTexture; - bool mUnRefImageDataAfterApply; - - /// @warning It is unsafe to call this function when a draw thread is using the textures. Call stopThreading() first! - void setFilterSettings(osg::Texture::FilterMode minFilter, osg::Texture::FilterMode maxFilter, int maxAnisotropy); - TextureManager(const TextureManager&); void operator = (const TextureManager&); }; From e2ee1d5689e1803cd7f63b94dbcfb7ff70b07f13 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 5 Feb 2016 18:58:22 +0100 Subject: [PATCH 3071/3725] Use separate textures for the MyGUI RenderManager This means we can more reliably set the filter parameters. I believe this commit creates a regression where non-DDS GUI textures would display upside down, which will be addressed by further refactoring in the next commits. --- components/myguiplatform/myguitexture.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/components/myguiplatform/myguitexture.cpp b/components/myguiplatform/myguitexture.cpp index 50ac5c1f3..a42568cf8 100644 --- a/components/myguiplatform/myguitexture.cpp +++ b/components/myguiplatform/myguitexture.cpp @@ -86,7 +86,9 @@ namespace osgMyGUI if (!mTextureManager) throw std::runtime_error("No texturemanager set"); - mTexture = mTextureManager->getTexture2D(fname, osg::Texture2D::CLAMP_TO_EDGE, osg::Texture2D::CLAMP_TO_EDGE); + mTexture = new osg::Texture2D(mTextureManager->getImage(fname)); + mTexture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); + mTexture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); // disable mip-maps mTexture->setFilter(osg::Texture2D::MIN_FILTER, osg::Texture2D::LINEAR); From 6ac688c0e2e16e4eec74ed5ef2d6a1a05a367d66 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 5 Feb 2016 19:28:52 +0100 Subject: [PATCH 3072/3725] Change the way that texture filtering setting changes are applied at runtime to not require keeping a reference to textures The references would be difficult to clean up because there may or may not be another reference to the texture in the osgDB::SharedStateManager. --- components/resource/scenemanager.cpp | 68 ++++++++-------------------- components/resource/scenemanager.hpp | 6 +-- 2 files changed, 21 insertions(+), 53 deletions(-) diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index 80e6f737d..df103f50c 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -129,21 +129,14 @@ namespace Resource tex->setFilter(osg::Texture::MIN_FILTER, mMinFilter); tex->setFilter(osg::Texture::MAG_FILTER, mMagFilter); tex->setMaxAnisotropy(mMaxAnisotropy); - mTexturesProcessed.insert(tex); } } } - const std::set >& getTexturesProcessed() - { - return mTexturesProcessed; - } - private: osg::Texture::FilterMode mMinFilter; osg::Texture::FilterMode mMagFilter; int mMaxAnisotropy; - std::set > mTexturesProcessed; }; /// Set texture filtering settings on textures contained in StateSets. @@ -199,20 +192,12 @@ namespace Resource tex->setFilter(osg::Texture::MIN_FILTER, mMinFilter); tex->setFilter(osg::Texture::MAG_FILTER, mMagFilter); tex->setMaxAnisotropy(mMaxAnisotropy); - mTexturesProcessed.insert(tex); } } - - const std::set >& getTexturesProcessed() - { - return mTexturesProcessed; - } - private: osg::Texture::FilterMode mMinFilter; osg::Texture::FilterMode mMagFilter; int mMaxAnisotropy; - std::set > mTexturesProcessed; }; @@ -341,10 +326,6 @@ namespace Resource SetFilterSettingsControllerVisitor setFilterSettingsControllerVisitor(mMinFilter, mMagFilter, mMaxAnisotropy); loaded->accept(setFilterSettingsControllerVisitor); - // remember which textures we set a filtering setting on so we can re-apply it when the setting changes - mTexturesWithFilterSetting.insert(setFilterSettingsVisitor.getTexturesProcessed().begin(), setFilterSettingsVisitor.getTexturesProcessed().end()); - mTexturesWithFilterSetting.insert(setFilterSettingsControllerVisitor.getTexturesProcessed().begin(), setFilterSettingsControllerVisitor.getTexturesProcessed().end()); - // share state osgDB::Registry::instance()->getOrCreateSharedStateManager()->share(loaded.get()); @@ -447,7 +428,26 @@ namespace Resource } if(viewer) viewer->stopThreading(); - setFilterSettings(min, mag, maxAnisotropy); + + mMinFilter = min; + mMagFilter = mag; + mMaxAnisotropy = std::max(1, maxAnisotropy); + + SetFilterSettingsControllerVisitor setFilterSettingsControllerVisitor (mMinFilter, mMagFilter, mMaxAnisotropy); + SetFilterSettingsVisitor setFilterSettingsVisitor (mMinFilter, mMagFilter, mMaxAnisotropy); + if (viewer && viewer->getSceneData()) + { + viewer->getSceneData()->accept(setFilterSettingsControllerVisitor); + viewer->getSceneData()->accept(setFilterSettingsVisitor); + } + + for (Index::iterator it = mIndex.begin(); it != mIndex.end(); ++it) + { + osg::Node* node = it->second; + node->accept(setFilterSettingsControllerVisitor); + node->accept(setFilterSettingsVisitor); + } + if(viewer) viewer->startThreading(); } @@ -456,7 +456,6 @@ namespace Resource tex->setFilter(osg::Texture::MIN_FILTER, mMinFilter); tex->setFilter(osg::Texture::MAG_FILTER, mMagFilter); tex->setMaxAnisotropy(mMaxAnisotropy); - mTexturesWithFilterSetting.insert(tex); } void SceneManager::setUnRefImageDataAfterApply(bool unref) @@ -464,32 +463,5 @@ namespace Resource mUnRefImageDataAfterApply = unref; } - void SceneManager::setFilterSettings(osg::Texture::FilterMode minFilter, osg::Texture::FilterMode magFilter, int maxAnisotropy) - { - mMinFilter = minFilter; - mMagFilter = magFilter; - mMaxAnisotropy = std::max(1, maxAnisotropy); - - for (std::set >::const_iterator it = mTexturesWithFilterSetting.begin(); it != mTexturesWithFilterSetting.end(); ++it) - { - (*it)->setFilter(osg::Texture::MIN_FILTER, mMinFilter); - (*it)->setFilter(osg::Texture::MAG_FILTER, mMagFilter); - (*it)->setMaxAnisotropy(mMaxAnisotropy); - } - } - - void SceneManager::clearCache() - { - // clear textures that are no longer referenced - for (std::set >::const_iterator it = mTexturesWithFilterSetting.begin(); it != mTexturesWithFilterSetting.end();) - { - osg::Texture* tex = *it; - if (tex->referenceCount() <= 1) - mTexturesWithFilterSetting.erase(it++); - else - ++it; - } - - } } diff --git a/components/resource/scenemanager.hpp b/components/resource/scenemanager.hpp index df330af5b..ae5fa2db6 100644 --- a/components/resource/scenemanager.hpp +++ b/components/resource/scenemanager.hpp @@ -87,8 +87,6 @@ namespace Resource /// otherwise should be disabled to reduce memory usage. void setUnRefImageDataAfterApply(bool unref); - void clearCache(); - private: const VFS::Manager* mVFS; Resource::TextureManager* mTextureManager; @@ -104,11 +102,9 @@ namespace Resource unsigned int mParticleSystemMask; // observer_ptr? - typedef std::map > Index; + typedef std::map > Index; Index mIndex; - std::set > mTexturesWithFilterSetting; - SceneManager(const SceneManager&); void operator = (const SceneManager&); From e8662bea3133ba9dbb09b86c3abb1af39425e90d Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 5 Feb 2016 20:23:41 +0100 Subject: [PATCH 3073/3725] Change the way that image origin is converted to OpenGL's lower-left convention Flip the texture coordinates instead of flipping textures. This simplifies the TextureManager (no need to worry if the caller wants flipping or not), should make it easier to generalize & multithread it. --- apps/openmw/mwgui/inventorywindow.cpp | 6 +++--- apps/openmw/mwgui/loadingscreen.cpp | 2 +- apps/openmw/mwgui/mapwindow.cpp | 8 ++++---- apps/openmw/mwgui/race.cpp | 2 +- apps/openmw/mwgui/savegamedialog.cpp | 2 +- apps/openmw/mwgui/videowidget.cpp | 2 +- apps/openmw/mwrender/characterpreview.cpp | 2 +- .../myguiplatform/myguirendermanager.cpp | 7 +++++++ components/myguiplatform/myguitexture.cpp | 2 ++ components/nif/data.cpp | 10 ++++++++-- components/resource/texturemanager.cpp | 18 +++--------------- components/resource/texturemanager.hpp | 6 ++++++ components/sdlutil/sdlcursormanager.cpp | 2 +- files/mygui/openmw_pointer.xml | 4 ++-- 14 files changed, 41 insertions(+), 32 deletions(-) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index facb17d66..4599132e3 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -87,7 +87,7 @@ namespace MWGui mAvatarImage->eventMouseButtonClick += MyGUI::newDelegate(this, &InventoryWindow::onAvatarClicked); mAvatarImage->setRenderItemTexture(mPreviewTexture.get()); - mAvatarImage->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 1.f, 1.f, 0.f)); + mAvatarImage->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 0.f, 1.f, 1.f)); getWidget(mItemView, "ItemView"); mItemView->eventItemClicked += MyGUI::newDelegate(this, &InventoryWindow::onItemSelected); @@ -403,8 +403,8 @@ namespace MWGui int height = std::min(mPreview->getTextureHeight(), size.height); mPreview->setViewport(width, height); - mAvatarImage->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, height/float(mPreview->getTextureHeight()), - width/float(mPreview->getTextureWidth()), 0.f)); + mAvatarImage->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 0.f, + width/float(mPreview->getTextureWidth()), height/float(mPreview->getTextureHeight()))); } void InventoryWindow::onFilterChanged(MyGUI::Widget* _sender) diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index e32140cb3..6385eb2c6 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -164,7 +164,7 @@ namespace MWGui mBackgroundImage->setBackgroundImage(""); mBackgroundImage->setRenderItemTexture(mGuiTexture.get()); - mBackgroundImage->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 1.f, 1.f, 0.f)); + mBackgroundImage->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 0.f, 1.f, 1.f)); } setVisible(true); diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 362d2d9e0..1b8d5ab43 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -254,7 +254,7 @@ namespace MWGui { boost::shared_ptr myguitex (new osgMyGUI::OSGTexture(tex)); fog->setRenderItemTexture(myguitex.get()); - fog->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 0.f, 1.f, 1.f)); + fog->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 1.f, 1.f, 0.f)); fogTextures.push_back(myguitex); } else @@ -391,7 +391,7 @@ namespace MWGui boost::shared_ptr guiTex (new osgMyGUI::OSGTexture(texture)); textures.push_back(guiTex); box->setRenderItemTexture(guiTex.get()); - box->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 1.f, 1.f, 0.f)); + box->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 0.f, 1.f, 1.f)); } else box->setRenderItemTexture(NULL); @@ -770,11 +770,11 @@ namespace MWGui mGlobalMapTexture.reset(new osgMyGUI::OSGTexture(mGlobalMapRender->getBaseTexture())); mGlobalMapImage->setRenderItemTexture(mGlobalMapTexture.get()); - mGlobalMapImage->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 1.f, 1.f, 0.f)); + mGlobalMapImage->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 0.f, 1.f, 1.f)); mGlobalMapOverlayTexture.reset(new osgMyGUI::OSGTexture(mGlobalMapRender->getOverlayTexture())); mGlobalMapOverlay->setRenderItemTexture(mGlobalMapOverlayTexture.get()); - mGlobalMapOverlay->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 1.f, 1.f, 0.f)); + mGlobalMapOverlay->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 0.f, 1.f, 1.f)); } MapWindow::~MapWindow() diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index a65379fca..aa229de72 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -142,7 +142,7 @@ namespace MWGui mPreviewTexture.reset(new osgMyGUI::OSGTexture(mPreview->getTexture())); mPreviewImage->setRenderItemTexture(mPreviewTexture.get()); - mPreviewImage->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 1.f, 1.f, 0.f)); + mPreviewImage->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 0.f, 1.f, 1.f)); const ESM::NPC& proto = mPreview->getPrototype(); setRaceId(proto.mRace); diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index 53c280737..9de2374ad 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -422,6 +422,6 @@ namespace MWGui mScreenshotTexture.reset(new osgMyGUI::OSGTexture(texture)); mScreenshot->setRenderItemTexture(mScreenshotTexture.get()); - mScreenshot->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 1.f, 1.f, 0.f)); + mScreenshot->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 0.f, 1.f, 1.f)); } } diff --git a/apps/openmw/mwgui/videowidget.cpp b/apps/openmw/mwgui/videowidget.cpp index d28ea0b66..5a4bb981f 100644 --- a/apps/openmw/mwgui/videowidget.cpp +++ b/apps/openmw/mwgui/videowidget.cpp @@ -50,7 +50,7 @@ void VideoWidget::playVideo(const std::string &video) mTexture.reset(new osgMyGUI::OSGTexture(texture)); setRenderItemTexture(mTexture.get()); - getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 0.f, 1.f, 1.f)); + getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 1.f, 1.f, 0.f)); } int VideoWidget::getVideoWidth() diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index a6f68b5d4..258854054 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -194,7 +194,7 @@ namespace MWRender sizeX = std::max(sizeX, 0); sizeY = std::max(sizeY, 0); - mCamera->setViewport(0, 0, std::min(mSizeX, sizeX), std::min(mSizeY, sizeY)); + mCamera->setViewport(0, mSizeY-sizeY, std::min(mSizeX, sizeX), std::min(mSizeY, sizeY)); redraw(); } diff --git a/components/myguiplatform/myguirendermanager.cpp b/components/myguiplatform/myguirendermanager.cpp index 5bd56dc8f..f5bebd560 100644 --- a/components/myguiplatform/myguirendermanager.cpp +++ b/components/myguiplatform/myguirendermanager.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include @@ -189,6 +190,12 @@ public: mStateSet->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::ON); mStateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF); mStateSet->setMode(GL_BLEND, osg::StateAttribute::ON); + + // need to flip tex coords since MyGUI uses DirectX convention of top left image origin + osg::Matrix flipMat; + flipMat.preMultTranslate(osg::Vec3f(0,1,0)); + flipMat.preMultScale(osg::Vec3f(1,-1,1)); + mStateSet->setTextureAttribute(0, new osg::TexMat(flipMat), osg::StateAttribute::ON); } Drawable(const Drawable ©, const osg::CopyOp ©op=osg::CopyOp::SHALLOW_COPY) : osg::Drawable(copy, copyop) diff --git a/components/myguiplatform/myguitexture.cpp b/components/myguiplatform/myguitexture.cpp index a42568cf8..3560a3ae3 100644 --- a/components/myguiplatform/myguitexture.cpp +++ b/components/myguiplatform/myguitexture.cpp @@ -145,6 +145,8 @@ namespace osgMyGUI if (!mLockedImage.valid()) throw std::runtime_error("Texture not locked"); + mLockedImage->flipVertical(); + // mTexture might be in use by the draw thread, so create a new texture instead and use that. osg::ref_ptr newTexture = new osg::Texture2D; newTexture->setTextureSize(getWidth(), getHeight()); diff --git a/components/nif/data.cpp b/components/nif/data.cpp index 5a60ab8a5..08c268dde 100644 --- a/components/nif/data.cpp +++ b/components/nif/data.cpp @@ -65,8 +65,14 @@ void ShapeData::read(NIFStream *nif) uvlist.resize(uvs); for(int i = 0;i < uvs;i++) { - uvlist[i] = new osg::Vec2Array(osg::Array::BIND_PER_VERTEX); - nif->getVector2s(uvlist[i], verts); + osg::Vec2Array* list = uvlist[i] = new osg::Vec2Array(osg::Array::BIND_PER_VERTEX); + nif->getVector2s(list, verts); + + // flip the texture coordinates to convert them to the OpenGL convention of bottom-left image origin + for (unsigned int uv=0; uvsize(); ++uv) + { + (*list)[uv] = osg::Vec2((*list)[uv].x(), 1.f - (*list)[uv].y()); + } } } } diff --git a/components/resource/texturemanager.cpp b/components/resource/texturemanager.cpp index b49c6bb09..709b925f1 100644 --- a/components/resource/texturemanager.cpp +++ b/components/resource/texturemanager.cpp @@ -47,8 +47,8 @@ namespace Resource TextureManager::TextureManager(const VFS::Manager *vfs) : mVFS(vfs) , mWarningTexture(createWarningTexture()) + , mOptions(new osgDB::Options("dds_flip dds_dxt1_detect_rgba")) { - } TextureManager::~TextureManager() @@ -116,8 +116,6 @@ namespace Resource return NULL; } - osg::ref_ptr opts (new osgDB::Options); - opts->setOptionString("dds_dxt1_detect_rgba"); // tx_creature_werewolf.dds isn't loading in the correct format without this option size_t extPos = normalized.find_last_of('.'); std::string ext; if (extPos != std::string::npos && extPos+1 < normalized.size()) @@ -129,7 +127,7 @@ namespace Resource return NULL; } - osgDB::ReaderWriter::ReadResult result = reader->readImage(*stream, opts); + osgDB::ReaderWriter::ReadResult result = reader->readImage(*stream, mOptions); if (!result.success()) { std::cerr << "Error loading " << filename << ": " << result.message() << " code " << result.status() << std::endl; @@ -170,8 +168,6 @@ namespace Resource return mWarningTexture; } - osg::ref_ptr opts (new osgDB::Options); - opts->setOptionString("dds_dxt1_detect_rgba"); // tx_creature_werewolf.dds isn't loading in the correct format without this option size_t extPos = normalized.find_last_of('.'); std::string ext; if (extPos != std::string::npos && extPos+1 < normalized.size()) @@ -183,7 +179,7 @@ namespace Resource return mWarningTexture; } - osgDB::ReaderWriter::ReadResult result = reader->readImage(*stream, opts); + osgDB::ReaderWriter::ReadResult result = reader->readImage(*stream, mOptions); if (!result.success()) { std::cerr << "Error loading " << filename << ": " << result.message() << " code " << result.status() << std::endl; @@ -196,14 +192,6 @@ namespace Resource return mWarningTexture; } - // We need to flip images, because the Morrowind texture coordinates use the DirectX convention (top-left image origin), - // but OpenGL uses bottom left as the image origin. - // For some reason this doesn't concern DDS textures, which are already flipped when loaded. - if (ext != "dds") - { - image->flipVertical(); - } - osg::ref_ptr texture(new osg::Texture2D); texture->setImage(image); texture->setWrap(osg::Texture::WRAP_S, wrapS); diff --git a/components/resource/texturemanager.hpp b/components/resource/texturemanager.hpp index 61a727b5e..cb2711aa7 100644 --- a/components/resource/texturemanager.hpp +++ b/components/resource/texturemanager.hpp @@ -18,6 +18,11 @@ namespace VFS class Manager; } +namespace osgDB +{ + class Options; +} + namespace Resource { @@ -49,6 +54,7 @@ namespace Resource std::map > mTextures; osg::ref_ptr mWarningTexture; + osg::ref_ptr mOptions; TextureManager(const TextureManager&); void operator = (const TextureManager&); diff --git a/components/sdlutil/sdlcursormanager.cpp b/components/sdlutil/sdlcursormanager.cpp index 9ecef0483..afe240609 100644 --- a/components/sdlutil/sdlcursormanager.cpp +++ b/components/sdlutil/sdlcursormanager.cpp @@ -231,7 +231,7 @@ namespace SDLUtil return; } - SDL_Surface* surf = SDLUtil::imageToSurface(decompressed, false); + SDL_Surface* surf = SDLUtil::imageToSurface(decompressed, true); //set the cursor and store it for later SDL_Cursor* curs = SDL_CreateColorCursor(surf, hotspot_x, hotspot_y); diff --git a/files/mygui/openmw_pointer.xml b/files/mygui/openmw_pointer.xml index a55a5453c..4a2f81860 100644 --- a/files/mygui/openmw_pointer.xml +++ b/files/mygui/openmw_pointer.xml @@ -23,13 +23,13 @@ - +
    - + From 31988ca4cc643e9b1e76597f8574a30216513cc9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 5 Feb 2016 21:07:08 +0100 Subject: [PATCH 3074/3725] Add a dont_override_filter description for textures that should be left alone --- components/resource/scenemanager.cpp | 7 +++++++ components/terrain/terraingrid.cpp | 1 + 2 files changed, 8 insertions(+) diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index df103f50c..065187c79 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -189,6 +189,13 @@ namespace Resource osg::Texture* tex = attr->asTexture(); if (tex) { + if (tex->getUserDataContainer()) + { + const std::vector& descriptions = tex->getUserDataContainer()->getDescriptions(); + if (std::find(descriptions.begin(), descriptions.end(), "dont_override_filter") != descriptions.end()) + return; + } + tex->setFilter(osg::Texture::MIN_FILTER, mMinFilter); tex->setFilter(osg::Texture::MAG_FILTER, mMagFilter); tex->setMaxAnisotropy(mMaxAnisotropy); diff --git a/components/terrain/terraingrid.cpp b/components/terrain/terraingrid.cpp index fb037c003..b7d727730 100644 --- a/components/terrain/terraingrid.cpp +++ b/components/terrain/terraingrid.cpp @@ -151,6 +151,7 @@ osg::ref_ptr TerrainGrid::buildTerrain (osg::Group* parent, float chu texture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR); texture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); texture->setResizeNonPowerOfTwoHint(false); + texture->getOrCreateUserDataContainer()->addDescription("dont_override_filter"); blendmapTextures.push_back(texture); textureCompileDummy->getOrCreateStateSet()->setTextureAttributeAndModes(dummyTextureCounter++, blendmapTextures.back()); From 71401aafe7eaef6b864fb0b1e6ad86f89e9a70c3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 5 Feb 2016 21:08:32 +0100 Subject: [PATCH 3075/3725] Handle multipass techniques in SetFilterSettingsVisitor --- components/resource/scenemanager.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index 065187c79..e3f38e886 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -6,6 +6,7 @@ #include #include +#include #include @@ -153,12 +154,29 @@ namespace Resource virtual void apply(osg::Node& node) { + if (osgFX::Effect* effect = dynamic_cast(&node)) + apply(*effect); + osg::StateSet* stateset = node.getStateSet(); if (stateset) apply(stateset); + traverse(node); } + void apply(osgFX::Effect& effect) + { + for (int i =0; igetNumPasses(); ++pass) + { + if (tech->getPassStateSet(pass)) + apply(tech->getPassStateSet(pass)); + } + } + } + virtual void apply(osg::Geode& geode) { osg::StateSet* stateset = geode.getStateSet(); From fbd4ad9b0cac68457a33834ee7482c08d95e3c01 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 5 Feb 2016 22:46:15 +0100 Subject: [PATCH 3076/3725] Flip terrain textures --- components/esmterrain/storage.cpp | 4 ++-- components/terrain/buffercache.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/components/esmterrain/storage.cpp b/components/esmterrain/storage.cpp index 4be56d5e6..267b831ec 100644 --- a/components/esmterrain/storage.cpp +++ b/components/esmterrain/storage.cpp @@ -399,9 +399,9 @@ namespace ESMTerrain int channel = pack ? std::max(0, (layerIndex-1) % 4) : 0; if (blendIndex == i) - pData[y*blendmapSize*channels + x*channels + channel] = 255; + pData[(blendmapSize - y - 1)*blendmapSize*channels + x*channels + channel] = 255; else - pData[y*blendmapSize*channels + x*channels + channel] = 0; + pData[(blendmapSize - y - 1)*blendmapSize*channels + x*channels + channel] = 0; } } diff --git a/components/terrain/buffercache.cpp b/components/terrain/buffercache.cpp index a64f8ffd1..f9c860d47 100644 --- a/components/terrain/buffercache.cpp +++ b/components/terrain/buffercache.cpp @@ -193,7 +193,7 @@ namespace Terrain for (unsigned int row = 0; row < mNumVerts; ++row) { uvs->push_back(osg::Vec2f(col / static_cast(mNumVerts-1), - row / static_cast(mNumVerts-1))); + ((mNumVerts-1) - row) / static_cast(mNumVerts-1))); } } From 6ef848b7c50497438dd0cf85a17709a7bb0dfb75 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 5 Feb 2016 22:58:02 +0100 Subject: [PATCH 3077/3725] Remove TextureManager::getTexture2D Instead use getImage and let the caller create the Texture. Sharing of textures is then handled in post by the SharedStateManager. This is closer to what the OSG serializer does. Streamlines the TextureManager and will make it easier to multithread. --- apps/openmw/mwgui/windowmanagerimp.cpp | 6 +- apps/openmw/mwrender/animation.cpp | 5 +- apps/openmw/mwrender/renderingmanager.cpp | 7 +++ apps/openmw/mwrender/renderingmanager.hpp | 2 + apps/openmw/mwrender/ripplesimulation.cpp | 7 ++- apps/openmw/mwrender/sky.cpp | 42 ++++++++----- apps/openmw/mwrender/util.cpp | 6 +- apps/openmw/mwrender/water.cpp | 8 ++- apps/openmw/mwworld/scene.cpp | 4 +- components/nifosg/nifloader.cpp | 11 ++-- components/resource/texturemanager.cpp | 75 ++--------------------- components/resource/texturemanager.hpp | 13 ++-- components/terrain/terraingrid.cpp | 30 ++++++++- components/terrain/terraingrid.hpp | 6 ++ components/terrain/world.hpp | 2 + 15 files changed, 114 insertions(+), 110 deletions(-) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 90c0494f6..346c672f7 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -2015,9 +2015,9 @@ namespace MWGui continue; std::string tex_name = imgSetPointer->getImageSet()->getIndexInfo(0,0).texture; - osg::ref_ptr tex = mResourceSystem->getTextureManager()->getTexture2D(tex_name, osg::Texture::CLAMP, osg::Texture::CLAMP); + osg::ref_ptr image = mResourceSystem->getTextureManager()->getImage(tex_name); - if(tex.valid()) + if(image.valid()) { //everything looks good, send it to the cursor manager Uint8 size_x = imgSetPointer->getSize().width; @@ -2026,7 +2026,7 @@ namespace MWGui Uint8 hotspot_y = imgSetPointer->getHotSpot().top; int rotation = imgSetPointer->getRotation(); - mCursorManager->createCursor(imgSetPointer->getResourceName(), rotation, tex->getImage(), size_x, size_y, hotspot_x, hotspot_y); + mCursorManager->createCursor(imgSetPointer->getResourceName(), rotation, image, size_x, size_y, hotspot_x, hotspot_y); } } } diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index a7bb3f128..35602fa17 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1059,7 +1059,10 @@ namespace MWRender stream << i; stream << ".dds"; - osg::ref_ptr tex = mResourceSystem->getTextureManager()->getTexture2D(stream.str(), osg::Texture2D::REPEAT, osg::Texture2D::REPEAT); + osg::ref_ptr image = mResourceSystem->getTextureManager()->getImage(stream.str()); + osg::ref_ptr tex (new osg::Texture2D(image)); + tex->setWrap(osg::Texture::WRAP_S, osg::Texture2D::REPEAT); + tex->setWrap(osg::Texture::WRAP_T, osg::Texture2D::REPEAT); mResourceSystem->getSceneManager()->applyFilterSettings(tex); textures.push_back(tex); } diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 755a8019b..2237d8125 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -231,6 +231,13 @@ namespace MWRender return mResourceSystem; } + void RenderingManager::clearCache() + { + mResourceSystem->clearCache(); + if (mTerrain.get()) + mTerrain->clearCache(); + } + osg::Group* RenderingManager::getLightRoot() { return mLightRoot.get(); diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 3b583af89..550e48e63 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -65,6 +65,8 @@ namespace MWRender Resource::ResourceSystem* getResourceSystem(); + void clearCache(); + osg::Group* getLightRoot(); void setNightEyeFactor(float factor); diff --git a/apps/openmw/mwrender/ripplesimulation.cpp b/apps/openmw/mwrender/ripplesimulation.cpp index f74631c4a..603cd397b 100644 --- a/apps/openmw/mwrender/ripplesimulation.cpp +++ b/apps/openmw/mwrender/ripplesimulation.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include "vismask.hpp" @@ -39,7 +40,11 @@ namespace { std::ostringstream texname; texname << "textures/water/" << tex << std::setw(2) << std::setfill('0') << i << ".dds"; - textures.push_back(resourceSystem->getTextureManager()->getTexture2D(texname.str(), osg::Texture::REPEAT, osg::Texture::REPEAT)); + osg::ref_ptr tex (new osg::Texture2D(resourceSystem->getTextureManager()->getImage(texname.str()))); + tex->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT); + tex->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT); + resourceSystem->getSceneManager()->applyFilterSettings(tex); + textures.push_back(tex); } osg::ref_ptr controller (new NifOsg::FlipController(0, 0.3f/rippleFrameCount, textures)); diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 513fc74a3..2a25baea9 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -476,9 +476,9 @@ public: mTransform->addUpdateCallback(mUpdater); mTransform->setNodeMask(Mask_Sun); - osg::ref_ptr sunTex = textureManager.getTexture2D("textures/tx_sun_05.dds", - osg::Texture::CLAMP, - osg::Texture::CLAMP); + osg::ref_ptr sunTex (new osg::Texture2D(textureManager.getImage("textures/tx_sun_05.dds"))); + sunTex->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); + sunTex->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); mGeode->getOrCreateStateSet()->setTextureAttributeAndModes(0, sunTex, osg::StateAttribute::ON); @@ -604,9 +604,9 @@ private: void createSunFlash(Resource::TextureManager& textureManager) { - osg::ref_ptr tex = textureManager.getTexture2D("textures/tx_sun_flash_grey_05.dds", - osg::Texture::CLAMP, - osg::Texture::CLAMP); + osg::ref_ptr tex (new osg::Texture2D(textureManager.getImage("textures/tx_sun_flash_grey_05.dds"))); + tex->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); + tex->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); osg::ref_ptr transform (new osg::PositionAttitudeTransform); const float scale = 2.6f; @@ -1055,8 +1055,12 @@ private: void setTextures(const std::string& phaseTex, const std::string& circleTex) { - mPhaseTex = mTextureManager.getTexture2D(phaseTex, osg::Texture::CLAMP, osg::Texture::CLAMP); - mCircleTex = mTextureManager.getTexture2D(circleTex, osg::Texture::CLAMP, osg::Texture::CLAMP); + mPhaseTex = new osg::Texture2D(mTextureManager.getImage(phaseTex)); + mPhaseTex->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); + mPhaseTex->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); + mCircleTex = new osg::Texture2D(mTextureManager.getImage(circleTex)); + mCircleTex->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); + mCircleTex->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); reset(); } @@ -1342,8 +1346,12 @@ void SkyManager::createRain() mRainParticleSystem->setAlignVectorY(osg::Vec3f(0,0,-1)); osg::ref_ptr stateset (mRainParticleSystem->getOrCreateStateSet()); - stateset->setTextureAttributeAndModes(0, mSceneManager->getTextureManager()->getTexture2D("textures/tx_raindrop_01.dds", - osg::Texture::CLAMP, osg::Texture::CLAMP), osg::StateAttribute::ON); + + osg::ref_ptr raindropTex (new osg::Texture2D(mSceneManager->getTextureManager()->getImage("textures/tx_raindrop_01.dds"))); + raindropTex->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); + raindropTex->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); + + stateset->setTextureAttributeAndModes(0, raindropTex, osg::StateAttribute::ON); stateset->setNestRenderBins(false); stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); stateset->setMode(GL_CULL_FACE, osg::StateAttribute::OFF); @@ -1549,8 +1557,11 @@ void SkyManager::setWeather(const WeatherResult& weather) std::string texture = Misc::ResourceHelpers::correctTexturePath(mClouds, mSceneManager->getVFS()); - mCloudUpdater->setTexture(mSceneManager->getTextureManager()->getTexture2D(texture, - osg::Texture::REPEAT, osg::Texture::REPEAT)); + osg::ref_ptr cloudTex (new osg::Texture2D(mSceneManager->getTextureManager()->getImage(texture))); + cloudTex->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT); + cloudTex->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT); + + mCloudUpdater->setTexture(cloudTex); } if (mNextClouds != weather.mNextCloudTexture) @@ -1561,8 +1572,11 @@ void SkyManager::setWeather(const WeatherResult& weather) { std::string texture = Misc::ResourceHelpers::correctTexturePath(mNextClouds, mSceneManager->getVFS()); - mCloudUpdater2->setTexture(mSceneManager->getTextureManager()->getTexture2D(texture, - osg::Texture::REPEAT, osg::Texture::REPEAT)); + osg::ref_ptr cloudTex (new osg::Texture2D(mSceneManager->getTextureManager()->getImage(texture))); + cloudTex->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT); + cloudTex->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT); + + mCloudUpdater2->setTexture(cloudTex); } } diff --git a/apps/openmw/mwrender/util.cpp b/apps/openmw/mwrender/util.cpp index e1af1c339..df6a0497f 100644 --- a/apps/openmw/mwrender/util.cpp +++ b/apps/openmw/mwrender/util.cpp @@ -15,8 +15,10 @@ void overrideTexture(const std::string &texture, Resource::ResourceSystem *resou return; std::string correctedTexture = Misc::ResourceHelpers::correctTexturePath(texture, resourceSystem->getVFS()); // Not sure if wrap settings should be pulled from the overridden texture? - osg::ref_ptr tex = resourceSystem->getTextureManager()->getTexture2D(correctedTexture, osg::Texture2D::CLAMP, - osg::Texture2D::CLAMP); + osg::ref_ptr tex = new osg::Texture2D(resourceSystem->getTextureManager()->getImage(correctedTexture)); + tex->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); + tex->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); + osg::ref_ptr stateset; if (node->getStateSet()) stateset = static_cast(node->getStateSet()->clone(osg::CopyOp::SHALLOW_COPY)); diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index c7f2c9cc6..ff3156411 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -317,6 +317,7 @@ public: mRefractionTexture->setInternalFormat(GL_RGB); mRefractionTexture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR); mRefractionTexture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); + mRefractionTexture->getOrCreateUserDataContainer()->addDescription("dont_override_filter"); attach(osg::Camera::COLOR_BUFFER, mRefractionTexture); @@ -328,6 +329,7 @@ public: mRefractionDepthTexture->setSourceType(GL_UNSIGNED_INT); mRefractionDepthTexture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR); mRefractionDepthTexture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); + mRefractionDepthTexture->getOrCreateUserDataContainer()->addDescription("dont_override_filter"); attach(osg::Camera::DEPTH_BUFFER, mRefractionDepthTexture); } @@ -388,6 +390,7 @@ public: mReflectionTexture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); mReflectionTexture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); mReflectionTexture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); + mReflectionTexture->getOrCreateUserDataContainer()->addDescription("dont_override_filter"); attach(osg::Camera::COLOR_BUFFER, mReflectionTexture); @@ -553,7 +556,10 @@ void Water::createSimpleWaterStateSet(osg::Node* node, float alpha) { std::ostringstream texname; texname << "textures/water/" << texture << std::setw(2) << std::setfill('0') << i << ".dds"; - textures.push_back(mResourceSystem->getTextureManager()->getTexture2D(texname.str(), osg::Texture::REPEAT, osg::Texture::REPEAT)); + osg::ref_ptr tex (new osg::Texture2D(mResourceSystem->getTextureManager()->getImage(texname.str()))); + tex->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT); + tex->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT); + textures.push_back(tex); } if (!textures.size()) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 618a219f3..f30e6efe1 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -402,7 +402,7 @@ namespace MWWorld mCellChanged = true; - mRendering.getResourceSystem()->clearCache(); + mRendering.clearCache(); } void Scene::changePlayerCell(CellStore *cell, const ESM::Position &pos, bool adjustPlayerPos) @@ -515,7 +515,7 @@ namespace MWWorld MWBase::Environment::get().getWindowManager()->changeCell(mCurrentCell); - mRendering.getResourceSystem()->clearCache(); + mRendering.clearCache(); } void Scene::changeToExteriorCell (const ESM::Position& position, bool adjustPlayerPos) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 79f837953..190fd020f 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -709,7 +709,9 @@ namespace NifOsg } std::string filename = Misc::ResourceHelpers::correctTexturePath(st->filename, textureManager->getVFS()); - osg::ref_ptr texture = textureManager->getTexture2D(filename, wrapS, wrapT); + osg::ref_ptr texture (new osg::Texture2D(textureManager->getImage(filename))); + texture->setWrap(osg::Texture::WRAP_S, wrapS); + texture->setWrap(osg::Texture::WRAP_T, wrapT); textures.push_back(texture); } osg::ref_ptr callback(new FlipController(flipctrl, textures)); @@ -1376,9 +1378,10 @@ namespace NifOsg int wrapT = (clamp) & 0x1; int wrapS = (clamp >> 1) & 0x1; - osg::ref_ptr texture2d = textureManager->getTexture2D(filename, - wrapS ? osg::Texture::REPEAT : osg::Texture::CLAMP, - wrapT ? osg::Texture::REPEAT : osg::Texture::CLAMP); + // create a new texture, will later attempt to share using the SharedStateManager + osg::ref_ptr texture2d (new osg::Texture2D(textureManager->getImage(filename))); + texture2d->setWrap(osg::Texture::WRAP_S, wrapS ? osg::Texture::REPEAT : osg::Texture::CLAMP); + texture2d->setWrap(osg::Texture::WRAP_T, wrapT ? osg::Texture::REPEAT : osg::Texture::CLAMP); int texUnit = boundTextures.size(); diff --git a/components/resource/texturemanager.cpp b/components/resource/texturemanager.cpp index 709b925f1..b3f23ab40 100644 --- a/components/resource/texturemanager.cpp +++ b/components/resource/texturemanager.cpp @@ -4,8 +4,6 @@ #include #include -#include - #include #ifdef OSG_LIBRARY_STATIC @@ -47,6 +45,7 @@ namespace Resource TextureManager::TextureManager(const VFS::Manager *vfs) : mVFS(vfs) , mWarningTexture(createWarningTexture()) + , mWarningImage(mWarningTexture->getImage()) , mOptions(new osgDB::Options("dds_flip dds_dxt1_detect_rgba")) { } @@ -56,13 +55,6 @@ namespace Resource } - /* - osg::ref_ptr TextureManager::getImage(const std::string &filename) - { - - } - */ - bool checkSupported(osg::Image* image, const std::string& filename) { switch(image->getPixelFormat()) @@ -113,7 +105,7 @@ namespace Resource catch (std::exception& e) { std::cerr << "Failed to open image: " << e.what() << std::endl; - return NULL; + return mWarningImage; } size_t extPos = normalized.find_last_of('.'); @@ -124,20 +116,20 @@ namespace Resource if (!reader) { std::cerr << "Error loading " << filename << ": no readerwriter for '" << ext << "' found" << std::endl; - return NULL; + return mWarningImage; } osgDB::ReaderWriter::ReadResult result = reader->readImage(*stream, mOptions); if (!result.success()) { std::cerr << "Error loading " << filename << ": " << result.message() << " code " << result.status() << std::endl; - return NULL; + return mWarningImage; } osg::Image* image = result.getImage(); if (!checkSupported(image, filename)) { - return NULL; + return mWarningImage; } mImages.insert(std::make_pair(normalized, image)); @@ -145,63 +137,6 @@ namespace Resource } } - osg::ref_ptr TextureManager::getTexture2D(const std::string &filename, osg::Texture::WrapMode wrapS, osg::Texture::WrapMode wrapT) - { - std::string normalized = filename; - mVFS->normalizeFilename(normalized); - MapKey key = std::make_pair(std::make_pair(wrapS, wrapT), normalized); - std::map >::iterator found = mTextures.find(key); - if (found != mTextures.end()) - { - return found->second; - } - else - { - Files::IStreamPtr stream; - try - { - stream = mVFS->get(normalized.c_str()); - } - catch (std::exception& e) - { - std::cerr << "Failed to open texture: " << e.what() << std::endl; - return mWarningTexture; - } - - size_t extPos = normalized.find_last_of('.'); - std::string ext; - if (extPos != std::string::npos && extPos+1 < normalized.size()) - ext = normalized.substr(extPos+1); - osgDB::ReaderWriter* reader = osgDB::Registry::instance()->getReaderWriterForExtension(ext); - if (!reader) - { - std::cerr << "Error loading " << filename << ": no readerwriter for '" << ext << "' found" << std::endl; - return mWarningTexture; - } - - osgDB::ReaderWriter::ReadResult result = reader->readImage(*stream, mOptions); - if (!result.success()) - { - std::cerr << "Error loading " << filename << ": " << result.message() << " code " << result.status() << std::endl; - return mWarningTexture; - } - - osg::Image* image = result.getImage(); - if (!checkSupported(image, filename)) - { - return mWarningTexture; - } - - osg::ref_ptr texture(new osg::Texture2D); - texture->setImage(image); - texture->setWrap(osg::Texture::WRAP_S, wrapS); - texture->setWrap(osg::Texture::WRAP_T, wrapT); - - mTextures.insert(std::make_pair(key, texture)); - return texture; - } - } - osg::Texture2D* TextureManager::getWarningTexture() { return mWarningTexture.get(); diff --git a/components/resource/texturemanager.hpp b/components/resource/texturemanager.hpp index cb2711aa7..0290d2340 100644 --- a/components/resource/texturemanager.hpp +++ b/components/resource/texturemanager.hpp @@ -26,18 +26,15 @@ namespace osgDB namespace Resource { - /// @brief Handles loading/caching of Images and Texture StateAttributes. + /// @brief Handles loading/caching of Images. class TextureManager { public: TextureManager(const VFS::Manager* vfs); ~TextureManager(); - /// Create or retrieve a Texture2D using the specified image filename, and wrap parameters. - /// Returns the dummy texture if the given texture is not found. - osg::ref_ptr getTexture2D(const std::string& filename, osg::Texture::WrapMode wrapS, osg::Texture::WrapMode wrapT); - /// Create or retrieve an Image + /// Returns the dummy image if the given image is not found. osg::ref_ptr getImage(const std::string& filename); const VFS::Manager* getVFS() { return mVFS; } @@ -47,13 +44,11 @@ namespace Resource private: const VFS::Manager* mVFS; - typedef std::pair, std::string> MapKey; - + // TODO: use ObjectCache std::map > mImages; - std::map > mTextures; - osg::ref_ptr mWarningTexture; + osg::ref_ptr mWarningImage; osg::ref_ptr mOptions; TextureManager(const TextureManager&); diff --git a/components/terrain/terraingrid.cpp b/components/terrain/terraingrid.cpp index b7d727730..58675a714 100644 --- a/components/terrain/terraingrid.cpp +++ b/components/terrain/terraingrid.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include @@ -134,10 +135,19 @@ osg::ref_ptr TerrainGrid::buildTerrain (osg::Group* parent, float chu // For compiling textures, I don't think the osgFX::Effect does it correctly osg::ref_ptr textureCompileDummy (new osg::Node); unsigned int dummyTextureCounter = 0; + std::vector > layerTextures; for (std::vector::const_iterator it = layerList.begin(); it != layerList.end(); ++it) { - layerTextures.push_back(mResourceSystem->getTextureManager()->getTexture2D(it->mDiffuseMap, osg::Texture::REPEAT, osg::Texture::REPEAT)); + osg::ref_ptr tex = mTextureCache[it->mDiffuseMap]; + if (!tex) + { + tex = new osg::Texture2D(mResourceSystem->getTextureManager()->getImage(it->mDiffuseMap)); + tex->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT); + tex->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT); + mTextureCache[it->mDiffuseMap] = tex; + } + layerTextures.push_back(tex); textureCompileDummy->getOrCreateStateSet()->setTextureAttributeAndModes(dummyTextureCounter++, layerTextures.back()); } @@ -148,15 +158,18 @@ osg::ref_ptr TerrainGrid::buildTerrain (osg::Group* parent, float chu texture->setImage(*it); texture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); texture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); - texture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR); - texture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); texture->setResizeNonPowerOfTwoHint(false); texture->getOrCreateUserDataContainer()->addDescription("dont_override_filter"); blendmapTextures.push_back(texture); + mResourceSystem->getSceneManager()->applyFilterSettings(texture); textureCompileDummy->getOrCreateStateSet()->setTextureAttributeAndModes(dummyTextureCounter++, blendmapTextures.back()); } + // SharedStatemanager->share(textureCompileDummy); + + // Remove unrefImageDataAfterApply for better state sharing + // use texture coordinates for both texture units, the layer texture and blend texture for (unsigned int i=0; i<2; ++i) geometry->setTexCoordArray(i, mCache.getUVBuffer()); @@ -226,4 +239,15 @@ void TerrainGrid::unloadCell(int x, int y) mGrid.erase(it); } +void TerrainGrid::clearCache() +{ + for (TextureCache::iterator it = mTextureCache.begin(); it != mTextureCache.end();) + { + if (it->second->referenceCount() <= 1) + mTextureCache.erase(it++); + else + ++it; + } +} + } diff --git a/components/terrain/terraingrid.hpp b/components/terrain/terraingrid.hpp index 169a9a622..81bfc4211 100644 --- a/components/terrain/terraingrid.hpp +++ b/components/terrain/terraingrid.hpp @@ -27,12 +27,18 @@ namespace Terrain virtual void loadCell(int x, int y); virtual void unloadCell(int x, int y); + /// Clear cached textures that are no longer referenced + void clearCache(); + private: osg::ref_ptr buildTerrain (osg::Group* parent, float chunkSize, const osg::Vec2f& chunkCenter); // split each ESM::Cell into mNumSplits*mNumSplits terrain chunks unsigned int mNumSplits; + typedef std::map > TextureCache; + TextureCache mTextureCache; + typedef std::map, GridElement*> Grid; Grid mGrid; diff --git a/components/terrain/world.hpp b/components/terrain/world.hpp index 4212f2a0c..bd5d0a466 100644 --- a/components/terrain/world.hpp +++ b/components/terrain/world.hpp @@ -39,6 +39,8 @@ namespace Terrain Storage* storage, int nodeMask); virtual ~World(); + virtual void clearCache() {} + float getHeightAt (const osg::Vec3f& worldPos); // This is only a hint and may be ignored by the implementation. From f99f403dda1160ed25172571b1dc22aa48f6b8f3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 5 Feb 2016 23:03:53 +0100 Subject: [PATCH 3078/3725] Rename TextureManager to ImageManager --- apps/openmw/mwgui/windowmanagerimp.cpp | 2 +- apps/openmw/mwrender/animation.cpp | 2 +- apps/openmw/mwrender/renderingmanager.cpp | 2 +- apps/openmw/mwrender/ripplesimulation.cpp | 2 +- apps/openmw/mwrender/sky.cpp | 14 +++++++------- apps/openmw/mwrender/util.cpp | 2 +- apps/openmw/mwrender/water.cpp | 2 +- components/CMakeLists.txt | 2 +- components/myguiplatform/myguiplatform.cpp | 2 +- components/myguiplatform/myguiplatform.hpp | 4 ++-- components/myguiplatform/myguirendermanager.cpp | 4 ++-- components/myguiplatform/myguirendermanager.hpp | 6 +++--- components/myguiplatform/myguitexture.cpp | 4 ++-- components/myguiplatform/myguitexture.hpp | 6 +++--- components/nifosg/nifloader.cpp | 14 +++++++------- components/nifosg/nifloader.hpp | 4 ++-- .../{texturemanager.cpp => imagemanager.cpp} | 10 +++++----- .../{texturemanager.hpp => imagemanager.hpp} | 10 +++++----- components/resource/resourcesystem.cpp | 6 +++--- components/resource/resourcesystem.hpp | 6 +++--- components/resource/scenemanager.cpp | 12 ++++++------ components/resource/scenemanager.hpp | 8 ++++---- components/terrain/terraingrid.cpp | 2 +- 23 files changed, 63 insertions(+), 63 deletions(-) rename components/resource/{texturemanager.cpp => imagemanager.cpp} (94%) rename components/resource/{texturemanager.hpp => imagemanager.hpp} (83%) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 346c672f7..d053d8bfd 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -28,7 +28,7 @@ #include #include -#include +#include #include diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 35602fa17..2c5831dae 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include // KeyframeHolder #include diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 2237d8125..d1b5f6fda 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -17,7 +17,7 @@ #include #include -#include +#include #include #include diff --git a/apps/openmw/mwrender/ripplesimulation.cpp b/apps/openmw/mwrender/ripplesimulation.cpp index 603cd397b..6cfcbc498 100644 --- a/apps/openmw/mwrender/ripplesimulation.cpp +++ b/apps/openmw/mwrender/ripplesimulation.cpp @@ -13,7 +13,7 @@ #include #include -#include +#include #include #include #include diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 2a25baea9..0f70e2c02 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -31,7 +31,7 @@ #include #include -#include +#include #include #include @@ -134,7 +134,7 @@ private: class AtmosphereNightUpdater : public SceneUtil::StateSetUpdater { public: - AtmosphereNightUpdater(Resource::TextureManager* textureManager) + AtmosphereNightUpdater(Resource::ImageManager* textureManager) { // we just need a texture, its contents don't really matter mTexture = textureManager->getWarningTexture(); @@ -469,7 +469,7 @@ const float CelestialBody::mDistance = 1000.0f; class Sun : public CelestialBody { public: - Sun(osg::Group* parentNode, Resource::TextureManager& textureManager) + Sun(osg::Group* parentNode, Resource::ImageManager& textureManager) : CelestialBody(parentNode, 1.0f, 1) , mUpdater(new Updater) { @@ -602,7 +602,7 @@ private: return oqn; } - void createSunFlash(Resource::TextureManager& textureManager) + void createSunFlash(Resource::ImageManager& textureManager) { osg::ref_ptr tex (new osg::Texture2D(textureManager.getImage("textures/tx_sun_flash_grey_05.dds"))); tex->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); @@ -932,7 +932,7 @@ public: Type_Secunda }; - Moon(osg::Group* parentNode, Resource::TextureManager& textureManager, float scaleFactor, Type type) + Moon(osg::Group* parentNode, Resource::ImageManager& textureManager, float scaleFactor, Type type) : CelestialBody(parentNode, scaleFactor, 2) , mType(type) , mPhase(MoonState::Phase_Unspecified) @@ -1001,7 +1001,7 @@ public: private: struct Updater : public SceneUtil::StateSetUpdater { - Resource::TextureManager& mTextureManager; + Resource::ImageManager& mTextureManager; osg::ref_ptr mPhaseTex; osg::ref_ptr mCircleTex; float mTransparency; @@ -1009,7 +1009,7 @@ private: osg::Vec4f mAtmosphereColor; osg::Vec4f mMoonColor; - Updater(Resource::TextureManager& textureManager) + Updater(Resource::ImageManager& textureManager) : mTextureManager(textureManager) , mPhaseTex() , mCircleTex() diff --git a/apps/openmw/mwrender/util.cpp b/apps/openmw/mwrender/util.cpp index df6a0497f..3c8d1408a 100644 --- a/apps/openmw/mwrender/util.cpp +++ b/apps/openmw/mwrender/util.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include namespace MWRender diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index ff3156411..7d1221a53 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -25,7 +25,7 @@ #include #include -#include +#include #include #include diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 089779eda..0b54ddeb7 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -41,7 +41,7 @@ add_component_dir (vfs ) add_component_dir (resource - scenemanager keyframemanager texturemanager resourcesystem bulletshapemanager bulletshape niffilemanager objectcache + scenemanager keyframemanager imagemanager resourcesystem bulletshapemanager bulletshape niffilemanager objectcache ) add_component_dir (sceneutil diff --git a/components/myguiplatform/myguiplatform.cpp b/components/myguiplatform/myguiplatform.cpp index 22b88438f..491af8486 100644 --- a/components/myguiplatform/myguiplatform.cpp +++ b/components/myguiplatform/myguiplatform.cpp @@ -7,7 +7,7 @@ namespace osgMyGUI { -Platform::Platform(osgViewer::Viewer *viewer, osg::Group *guiRoot, Resource::TextureManager *textureManager, float uiScalingFactor) +Platform::Platform(osgViewer::Viewer *viewer, osg::Group *guiRoot, Resource::ImageManager *textureManager, float uiScalingFactor) : mRenderManager(nullptr) , mDataManager(nullptr) , mLogManager(nullptr) diff --git a/components/myguiplatform/myguiplatform.hpp b/components/myguiplatform/myguiplatform.hpp index 90d45ce20..b3f959798 100644 --- a/components/myguiplatform/myguiplatform.hpp +++ b/components/myguiplatform/myguiplatform.hpp @@ -13,7 +13,7 @@ namespace osg } namespace Resource { - class TextureManager; + class ImageManager; } namespace MyGUI { @@ -30,7 +30,7 @@ namespace osgMyGUI class Platform { public: - Platform(osgViewer::Viewer* viewer, osg::Group* guiRoot, Resource::TextureManager* textureManager, float uiScalingFactor); + Platform(osgViewer::Viewer* viewer, osg::Group* guiRoot, Resource::ImageManager* textureManager, float uiScalingFactor); ~Platform(); diff --git a/components/myguiplatform/myguirendermanager.cpp b/components/myguiplatform/myguirendermanager.cpp index f5bebd560..23d004f47 100644 --- a/components/myguiplatform/myguirendermanager.cpp +++ b/components/myguiplatform/myguirendermanager.cpp @@ -15,7 +15,7 @@ #include -#include +#include #include "myguitexture.hpp" @@ -353,7 +353,7 @@ void OSGVertexBuffer::create() // --------------------------------------------------------------------------- -RenderManager::RenderManager(osgViewer::Viewer *viewer, osg::Group *sceneroot, Resource::TextureManager* textureManager, float scalingFactor) +RenderManager::RenderManager(osgViewer::Viewer *viewer, osg::Group *sceneroot, Resource::ImageManager* textureManager, float scalingFactor) : mViewer(viewer) , mSceneRoot(sceneroot) , mTextureManager(textureManager) diff --git a/components/myguiplatform/myguirendermanager.hpp b/components/myguiplatform/myguirendermanager.hpp index f2251cdb0..b1aa0d3f0 100644 --- a/components/myguiplatform/myguirendermanager.hpp +++ b/components/myguiplatform/myguirendermanager.hpp @@ -7,7 +7,7 @@ namespace Resource { - class TextureManager; + class ImageManager; } namespace osgViewer @@ -33,7 +33,7 @@ class RenderManager : public MyGUI::RenderManager, public MyGUI::IRenderTarget osg::ref_ptr mViewer; osg::ref_ptr mSceneRoot; osg::ref_ptr mDrawable; - Resource::TextureManager* mTextureManager; + Resource::ImageManager* mTextureManager; MyGUI::IntSize mViewSize; bool mUpdate; @@ -54,7 +54,7 @@ class RenderManager : public MyGUI::RenderManager, public MyGUI::IRenderTarget void destroyAllResources(); public: - RenderManager(osgViewer::Viewer *viewer, osg::Group *sceneroot, Resource::TextureManager* textureManager, float scalingFactor); + RenderManager(osgViewer::Viewer *viewer, osg::Group *sceneroot, Resource::ImageManager* textureManager, float scalingFactor); virtual ~RenderManager(); void initialise(); diff --git a/components/myguiplatform/myguitexture.cpp b/components/myguiplatform/myguitexture.cpp index 3560a3ae3..904ed6abf 100644 --- a/components/myguiplatform/myguitexture.cpp +++ b/components/myguiplatform/myguitexture.cpp @@ -5,12 +5,12 @@ #include -#include +#include namespace osgMyGUI { - OSGTexture::OSGTexture(const std::string &name, Resource::TextureManager* textureManager) + OSGTexture::OSGTexture(const std::string &name, Resource::ImageManager* textureManager) : mName(name) , mTextureManager(textureManager) , mFormat(MyGUI::PixelFormat::Unknow) diff --git a/components/myguiplatform/myguitexture.hpp b/components/myguiplatform/myguitexture.hpp index de385e94d..21bc89992 100644 --- a/components/myguiplatform/myguitexture.hpp +++ b/components/myguiplatform/myguitexture.hpp @@ -13,7 +13,7 @@ namespace osg namespace Resource { - class TextureManager; + class ImageManager; } namespace osgMyGUI @@ -21,7 +21,7 @@ namespace osgMyGUI class OSGTexture : public MyGUI::ITexture { std::string mName; - Resource::TextureManager* mTextureManager; + Resource::ImageManager* mTextureManager; osg::ref_ptr mLockedImage; osg::ref_ptr mTexture; @@ -30,7 +30,7 @@ namespace osgMyGUI size_t mNumElemBytes; public: - OSGTexture(const std::string &name, Resource::TextureManager* textureManager); + OSGTexture(const std::string &name, Resource::ImageManager* textureManager); OSGTexture(osg::Texture2D* texture); virtual ~OSGTexture(); diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 190fd020f..d09c34aa5 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -11,7 +11,7 @@ // resource #include #include -#include +#include // skel #include @@ -343,7 +343,7 @@ namespace NifOsg } } - osg::ref_ptr load(Nif::NIFFilePtr nif, Resource::TextureManager* textureManager) + osg::ref_ptr load(Nif::NIFFilePtr nif, Resource::ImageManager* textureManager) { if (nif->numRoots() < 1) nif->fail("Found no root nodes"); @@ -369,7 +369,7 @@ namespace NifOsg return created; } - void applyNodeProperties(const Nif::Node *nifNode, osg::Node *applyTo, SceneUtil::CompositeStateSetUpdater* composite, Resource::TextureManager* textureManager, std::vector& boundTextures, int animflags) + void applyNodeProperties(const Nif::Node *nifNode, osg::Node *applyTo, SceneUtil::CompositeStateSetUpdater* composite, Resource::ImageManager* textureManager, std::vector& boundTextures, int animflags) { const Nif::PropertyList& props = nifNode->props; for (size_t i = 0; i handleNode(const Nif::Node* nifNode, osg::Group* parentNode, Resource::TextureManager* textureManager, + osg::ref_ptr handleNode(const Nif::Node* nifNode, osg::Group* parentNode, Resource::ImageManager* textureManager, std::vector boundTextures, int animflags, int particleflags, bool skipMeshes, TextKeyMap* textKeys, osg::Node* rootNode=NULL) { osg::ref_ptr node = new osg::MatrixTransform(nifNode->trafo.toMatrix()); @@ -682,7 +682,7 @@ namespace NifOsg } } - void handleTextureControllers(const Nif::Property *texProperty, SceneUtil::CompositeStateSetUpdater* composite, Resource::TextureManager* textureManager, osg::StateSet *stateset, int animflags) + void handleTextureControllers(const Nif::Property *texProperty, SceneUtil::CompositeStateSetUpdater* composite, Resource::ImageManager* textureManager, osg::StateSet *stateset, int animflags) { for (Nif::ControllerPtr ctrl = texProperty->controller; !ctrl.empty(); ctrl = ctrl->next) { @@ -1244,7 +1244,7 @@ namespace NifOsg } void handleProperty(const Nif::Property *property, - osg::Node *node, SceneUtil::CompositeStateSetUpdater* composite, Resource::TextureManager* textureManager, std::vector& boundTextures, int animflags) + osg::Node *node, SceneUtil::CompositeStateSetUpdater* composite, Resource::ImageManager* textureManager, std::vector& boundTextures, int animflags) { switch (property->recType) { @@ -1543,7 +1543,7 @@ namespace NifOsg }; - osg::ref_ptr Loader::load(Nif::NIFFilePtr file, Resource::TextureManager* textureManager) + osg::ref_ptr Loader::load(Nif::NIFFilePtr file, Resource::ImageManager* textureManager) { LoaderImpl impl(file->getFilename()); return impl.load(file, textureManager); diff --git a/components/nifosg/nifloader.hpp b/components/nifosg/nifloader.hpp index e15df5302..afc912ed3 100644 --- a/components/nifosg/nifloader.hpp +++ b/components/nifosg/nifloader.hpp @@ -15,7 +15,7 @@ namespace osg namespace Resource { - class TextureManager; + class ImageManager; } namespace NifOsg @@ -62,7 +62,7 @@ namespace NifOsg { public: /// Create a scene graph for the given NIF. Auto-detects when skinning is used and wraps the graph in a Skeleton if so. - static osg::ref_ptr load(Nif::NIFFilePtr file, Resource::TextureManager* textureManager); + static osg::ref_ptr load(Nif::NIFFilePtr file, Resource::ImageManager* textureManager); /// Load keyframe controllers from the given kf file. static void loadKf(Nif::NIFFilePtr kf, KeyframeHolder& target); diff --git a/components/resource/texturemanager.cpp b/components/resource/imagemanager.cpp similarity index 94% rename from components/resource/texturemanager.cpp rename to components/resource/imagemanager.cpp index b3f23ab40..8b14e7237 100644 --- a/components/resource/texturemanager.cpp +++ b/components/resource/imagemanager.cpp @@ -1,4 +1,4 @@ -#include "texturemanager.hpp" +#include "imagemanager.hpp" #include #include @@ -42,7 +42,7 @@ namespace namespace Resource { - TextureManager::TextureManager(const VFS::Manager *vfs) + ImageManager::ImageManager(const VFS::Manager *vfs) : mVFS(vfs) , mWarningTexture(createWarningTexture()) , mWarningImage(mWarningTexture->getImage()) @@ -50,7 +50,7 @@ namespace Resource { } - TextureManager::~TextureManager() + ImageManager::~ImageManager() { } @@ -88,7 +88,7 @@ namespace Resource return true; } - osg::ref_ptr TextureManager::getImage(const std::string &filename) + osg::ref_ptr ImageManager::getImage(const std::string &filename) { std::string normalized = filename; mVFS->normalizeFilename(normalized); @@ -137,7 +137,7 @@ namespace Resource } } - osg::Texture2D* TextureManager::getWarningTexture() + osg::Texture2D* ImageManager::getWarningTexture() { return mWarningTexture.get(); } diff --git a/components/resource/texturemanager.hpp b/components/resource/imagemanager.hpp similarity index 83% rename from components/resource/texturemanager.hpp rename to components/resource/imagemanager.hpp index 0290d2340..14d0b673e 100644 --- a/components/resource/texturemanager.hpp +++ b/components/resource/imagemanager.hpp @@ -27,11 +27,11 @@ namespace Resource { /// @brief Handles loading/caching of Images. - class TextureManager + class ImageManager { public: - TextureManager(const VFS::Manager* vfs); - ~TextureManager(); + ImageManager(const VFS::Manager* vfs); + ~ImageManager(); /// Create or retrieve an Image /// Returns the dummy image if the given image is not found. @@ -51,8 +51,8 @@ namespace Resource osg::ref_ptr mWarningImage; osg::ref_ptr mOptions; - TextureManager(const TextureManager&); - void operator = (const TextureManager&); + ImageManager(const ImageManager&); + void operator = (const ImageManager&); }; } diff --git a/components/resource/resourcesystem.cpp b/components/resource/resourcesystem.cpp index 2ce8d22e6..89a4b2cb3 100644 --- a/components/resource/resourcesystem.cpp +++ b/components/resource/resourcesystem.cpp @@ -1,7 +1,7 @@ #include "resourcesystem.hpp" #include "scenemanager.hpp" -#include "texturemanager.hpp" +#include "imagemanager.hpp" #include "niffilemanager.hpp" #include "keyframemanager.hpp" @@ -13,7 +13,7 @@ namespace Resource { mNifFileManager.reset(new NifFileManager(vfs)); mKeyframeManager.reset(new KeyframeManager(vfs)); - mTextureManager.reset(new TextureManager(vfs)); + mTextureManager.reset(new ImageManager(vfs)); mSceneManager.reset(new SceneManager(vfs, mTextureManager.get(), mNifFileManager.get())); } @@ -27,7 +27,7 @@ namespace Resource return mSceneManager.get(); } - TextureManager* ResourceSystem::getTextureManager() + ImageManager* ResourceSystem::getTextureManager() { return mTextureManager.get(); } diff --git a/components/resource/resourcesystem.hpp b/components/resource/resourcesystem.hpp index 3e1a793ca..7c4d83b7d 100644 --- a/components/resource/resourcesystem.hpp +++ b/components/resource/resourcesystem.hpp @@ -12,7 +12,7 @@ namespace Resource { class SceneManager; - class TextureManager; + class ImageManager; class NifFileManager; class KeyframeManager; @@ -26,7 +26,7 @@ namespace Resource ~ResourceSystem(); SceneManager* getSceneManager(); - TextureManager* getTextureManager(); + ImageManager* getTextureManager(); NifFileManager* getNifFileManager(); KeyframeManager* getKeyframeManager(); @@ -37,7 +37,7 @@ namespace Resource private: std::auto_ptr mSceneManager; - std::auto_ptr mTextureManager; + std::auto_ptr mTextureManager; std::auto_ptr mNifFileManager; std::auto_ptr mKeyframeManager; diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index e3f38e886..287186887 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -24,7 +24,7 @@ #include #include -#include "texturemanager.hpp" +#include "imagemanager.hpp" #include "niffilemanager.hpp" namespace @@ -227,7 +227,7 @@ namespace Resource - SceneManager::SceneManager(const VFS::Manager *vfs, Resource::TextureManager* textureManager, Resource::NifFileManager* nifFileManager) + SceneManager::SceneManager(const VFS::Manager *vfs, Resource::ImageManager* textureManager, Resource::NifFileManager* nifFileManager) : mVFS(vfs) , mTextureManager(textureManager) , mNifFileManager(nifFileManager) @@ -249,7 +249,7 @@ namespace Resource class ImageReadCallback : public osgDB::ReadFileCallback { public: - ImageReadCallback(Resource::TextureManager* textureMgr) + ImageReadCallback(Resource::ImageManager* textureMgr) : mTextureManager(textureMgr) { } @@ -267,7 +267,7 @@ namespace Resource } private: - Resource::TextureManager* mTextureManager; + Resource::ImageManager* mTextureManager; }; std::string getFileExtension(const std::string& file) @@ -278,7 +278,7 @@ namespace Resource return std::string(); } - osg::ref_ptr load (Files::IStreamPtr file, const std::string& normalizedFilename, Resource::TextureManager* textureMgr, Resource::NifFileManager* nifFileManager) + osg::ref_ptr load (Files::IStreamPtr file, const std::string& normalizedFilename, Resource::ImageManager* textureMgr, Resource::NifFileManager* nifFileManager) { std::string ext = getFileExtension(normalizedFilename); if (ext == "nif") @@ -408,7 +408,7 @@ namespace Resource return mVFS; } - Resource::TextureManager* SceneManager::getTextureManager() + Resource::ImageManager* SceneManager::getTextureManager() { return mTextureManager; } diff --git a/components/resource/scenemanager.hpp b/components/resource/scenemanager.hpp index ae5fa2db6..6eadf7b45 100644 --- a/components/resource/scenemanager.hpp +++ b/components/resource/scenemanager.hpp @@ -10,7 +10,7 @@ namespace Resource { - class TextureManager; + class ImageManager; class NifFileManager; } @@ -36,7 +36,7 @@ namespace Resource class SceneManager { public: - SceneManager(const VFS::Manager* vfs, Resource::TextureManager* textureManager, Resource::NifFileManager* nifFileManager); + SceneManager(const VFS::Manager* vfs, Resource::ImageManager* textureManager, Resource::NifFileManager* nifFileManager); ~SceneManager(); /// Get a read-only copy of this scene "template" @@ -70,7 +70,7 @@ namespace Resource const VFS::Manager* getVFS() const; - Resource::TextureManager* getTextureManager(); + Resource::ImageManager* getTextureManager(); /// @param mask The node mask to apply to loaded particle system nodes. void setParticleSystemMask(unsigned int mask); @@ -89,7 +89,7 @@ namespace Resource private: const VFS::Manager* mVFS; - Resource::TextureManager* mTextureManager; + Resource::ImageManager* mTextureManager; Resource::NifFileManager* mNifFileManager; osg::Texture::FilterMode mMinFilter; diff --git a/components/terrain/terraingrid.cpp b/components/terrain/terraingrid.cpp index 58675a714..094023f38 100644 --- a/components/terrain/terraingrid.cpp +++ b/components/terrain/terraingrid.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include From 5ee3d1698fd10584b07213f74c0a2a97b0fb06a9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 5 Feb 2016 23:05:37 +0100 Subject: [PATCH 3079/3725] Remove getWarningTexture in favor of getWarningImage --- apps/openmw/mwrender/sky.cpp | 2 +- components/resource/imagemanager.cpp | 14 +++++--------- components/resource/imagemanager.hpp | 3 +-- 3 files changed, 7 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 0f70e2c02..69fbb2379 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -137,7 +137,7 @@ public: AtmosphereNightUpdater(Resource::ImageManager* textureManager) { // we just need a texture, its contents don't really matter - mTexture = textureManager->getWarningTexture(); + mTexture = new osg::Texture2D(textureManager->getWarningImage()); } void setFade(const float fade) diff --git a/components/resource/imagemanager.cpp b/components/resource/imagemanager.cpp index 8b14e7237..e1c0572c7 100644 --- a/components/resource/imagemanager.cpp +++ b/components/resource/imagemanager.cpp @@ -17,7 +17,7 @@ USE_OSGPLUGIN(jpeg) namespace { - osg::ref_ptr createWarningTexture() + osg::ref_ptr createWarningImage() { osg::ref_ptr warningImage = new osg::Image; @@ -31,10 +31,7 @@ namespace data[3*i+1] = (0); data[3*i+2] = (255); } - - osg::ref_ptr warningTexture = new osg::Texture2D; - warningTexture->setImage(warningImage); - return warningTexture; + return warningImage; } } @@ -44,8 +41,7 @@ namespace Resource ImageManager::ImageManager(const VFS::Manager *vfs) : mVFS(vfs) - , mWarningTexture(createWarningTexture()) - , mWarningImage(mWarningTexture->getImage()) + , mWarningImage(createWarningImage()) , mOptions(new osgDB::Options("dds_flip dds_dxt1_detect_rgba")) { } @@ -137,9 +133,9 @@ namespace Resource } } - osg::Texture2D* ImageManager::getWarningTexture() + osg::Image *ImageManager::getWarningImage() { - return mWarningTexture.get(); + return mWarningImage; } } diff --git a/components/resource/imagemanager.hpp b/components/resource/imagemanager.hpp index 14d0b673e..ee0c0f2e2 100644 --- a/components/resource/imagemanager.hpp +++ b/components/resource/imagemanager.hpp @@ -39,7 +39,7 @@ namespace Resource const VFS::Manager* getVFS() { return mVFS; } - osg::Texture2D* getWarningTexture(); + osg::Image* getWarningImage(); private: const VFS::Manager* mVFS; @@ -47,7 +47,6 @@ namespace Resource // TODO: use ObjectCache std::map > mImages; - osg::ref_ptr mWarningTexture; osg::ref_ptr mWarningImage; osg::ref_ptr mOptions; From 9e53e12c70f38c6de9d2ea515a58746c413dd753 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 5 Feb 2016 23:10:27 +0100 Subject: [PATCH 3080/3725] More renaming of TextureManager -> ImageManager --- apps/openmw/mwgui/windowmanagerimp.cpp | 4 +- apps/openmw/mwrender/animation.cpp | 2 +- apps/openmw/mwrender/ripplesimulation.cpp | 2 +- apps/openmw/mwrender/sky.cpp | 42 +++++++++---------- apps/openmw/mwrender/util.cpp | 2 +- apps/openmw/mwrender/water.cpp | 2 +- components/myguiplatform/myguiplatform.cpp | 4 +- components/myguiplatform/myguiplatform.hpp | 2 +- .../myguiplatform/myguirendermanager.cpp | 6 +-- .../myguiplatform/myguirendermanager.hpp | 4 +- components/myguiplatform/myguitexture.cpp | 12 +++--- components/myguiplatform/myguitexture.hpp | 4 +- components/nifosg/nifloader.cpp | 32 +++++++------- components/nifosg/nifloader.hpp | 2 +- components/resource/imagemanager.hpp | 4 +- components/resource/resourcesystem.cpp | 8 ++-- components/resource/resourcesystem.hpp | 4 +- components/resource/scenemanager.cpp | 26 ++++++------ components/resource/scenemanager.hpp | 6 +-- components/terrain/terraingrid.cpp | 2 +- 20 files changed, 85 insertions(+), 85 deletions(-) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index d053d8bfd..03fbc9238 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -194,7 +194,7 @@ namespace MWGui , mVersionDescription(versionDescription) { float uiScale = Settings::Manager::getFloat("scaling factor", "GUI"); - mGuiPlatform = new osgMyGUI::Platform(viewer, guiRoot, resourceSystem->getTextureManager(), uiScale); + mGuiPlatform = new osgMyGUI::Platform(viewer, guiRoot, resourceSystem->getImageManager(), uiScale); mGuiPlatform->initialise(resourcePath, logpath); mGui = new MyGUI::Gui; @@ -2015,7 +2015,7 @@ namespace MWGui continue; std::string tex_name = imgSetPointer->getImageSet()->getIndexInfo(0,0).texture; - osg::ref_ptr image = mResourceSystem->getTextureManager()->getImage(tex_name); + osg::ref_ptr image = mResourceSystem->getImageManager()->getImage(tex_name); if(image.valid()) { diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 2c5831dae..b7c0c0a36 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1059,7 +1059,7 @@ namespace MWRender stream << i; stream << ".dds"; - osg::ref_ptr image = mResourceSystem->getTextureManager()->getImage(stream.str()); + osg::ref_ptr image = mResourceSystem->getImageManager()->getImage(stream.str()); osg::ref_ptr tex (new osg::Texture2D(image)); tex->setWrap(osg::Texture::WRAP_S, osg::Texture2D::REPEAT); tex->setWrap(osg::Texture::WRAP_T, osg::Texture2D::REPEAT); diff --git a/apps/openmw/mwrender/ripplesimulation.cpp b/apps/openmw/mwrender/ripplesimulation.cpp index 6cfcbc498..f43f1ee5c 100644 --- a/apps/openmw/mwrender/ripplesimulation.cpp +++ b/apps/openmw/mwrender/ripplesimulation.cpp @@ -40,7 +40,7 @@ namespace { std::ostringstream texname; texname << "textures/water/" << tex << std::setw(2) << std::setfill('0') << i << ".dds"; - osg::ref_ptr tex (new osg::Texture2D(resourceSystem->getTextureManager()->getImage(texname.str()))); + osg::ref_ptr tex (new osg::Texture2D(resourceSystem->getImageManager()->getImage(texname.str()))); tex->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT); tex->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT); resourceSystem->getSceneManager()->applyFilterSettings(tex); diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 69fbb2379..0d3bf1a66 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -134,10 +134,10 @@ private: class AtmosphereNightUpdater : public SceneUtil::StateSetUpdater { public: - AtmosphereNightUpdater(Resource::ImageManager* textureManager) + AtmosphereNightUpdater(Resource::ImageManager* imageManager) { // we just need a texture, its contents don't really matter - mTexture = new osg::Texture2D(textureManager->getWarningImage()); + mTexture = new osg::Texture2D(imageManager->getWarningImage()); } void setFade(const float fade) @@ -469,14 +469,14 @@ const float CelestialBody::mDistance = 1000.0f; class Sun : public CelestialBody { public: - Sun(osg::Group* parentNode, Resource::ImageManager& textureManager) + Sun(osg::Group* parentNode, Resource::ImageManager& imageManager) : CelestialBody(parentNode, 1.0f, 1) , mUpdater(new Updater) { mTransform->addUpdateCallback(mUpdater); mTransform->setNodeMask(Mask_Sun); - osg::ref_ptr sunTex (new osg::Texture2D(textureManager.getImage("textures/tx_sun_05.dds"))); + osg::ref_ptr sunTex (new osg::Texture2D(imageManager.getImage("textures/tx_sun_05.dds"))); sunTex->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); sunTex->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); @@ -498,7 +498,7 @@ public: mOcclusionQueryVisiblePixels = createOcclusionQueryNode(queryNode, true); mOcclusionQueryTotalPixels = createOcclusionQueryNode(queryNode, false); - createSunFlash(textureManager); + createSunFlash(imageManager); createSunGlare(); } @@ -602,9 +602,9 @@ private: return oqn; } - void createSunFlash(Resource::ImageManager& textureManager) + void createSunFlash(Resource::ImageManager& imageManager) { - osg::ref_ptr tex (new osg::Texture2D(textureManager.getImage("textures/tx_sun_flash_grey_05.dds"))); + osg::ref_ptr tex (new osg::Texture2D(imageManager.getImage("textures/tx_sun_flash_grey_05.dds"))); tex->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); tex->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); @@ -932,11 +932,11 @@ public: Type_Secunda }; - Moon(osg::Group* parentNode, Resource::ImageManager& textureManager, float scaleFactor, Type type) + Moon(osg::Group* parentNode, Resource::ImageManager& imageManager, float scaleFactor, Type type) : CelestialBody(parentNode, scaleFactor, 2) , mType(type) , mPhase(MoonState::Phase_Unspecified) - , mUpdater(new Updater(textureManager)) + , mUpdater(new Updater(imageManager)) { setPhase(MoonState::Phase_Full); setVisible(true); @@ -1001,7 +1001,7 @@ public: private: struct Updater : public SceneUtil::StateSetUpdater { - Resource::ImageManager& mTextureManager; + Resource::ImageManager& mImageManager; osg::ref_ptr mPhaseTex; osg::ref_ptr mCircleTex; float mTransparency; @@ -1009,8 +1009,8 @@ private: osg::Vec4f mAtmosphereColor; osg::Vec4f mMoonColor; - Updater(Resource::ImageManager& textureManager) - : mTextureManager(textureManager) + Updater(Resource::ImageManager& imageManager) + : mImageManager(imageManager) , mPhaseTex() , mCircleTex() , mTransparency(1.0f) @@ -1055,10 +1055,10 @@ private: void setTextures(const std::string& phaseTex, const std::string& circleTex) { - mPhaseTex = new osg::Texture2D(mTextureManager.getImage(phaseTex)); + mPhaseTex = new osg::Texture2D(mImageManager.getImage(phaseTex)); mPhaseTex->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); mPhaseTex->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); - mCircleTex = new osg::Texture2D(mTextureManager.getImage(circleTex)); + mCircleTex = new osg::Texture2D(mImageManager.getImage(circleTex)); mCircleTex->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); mCircleTex->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); @@ -1165,14 +1165,14 @@ void SkyManager::create() atmosphereNight->getOrCreateStateSet()->setAttributeAndModes(createAlphaTrackingUnlitMaterial(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); ModVertexAlphaVisitor modStars(2); atmosphereNight->accept(modStars); - mAtmosphereNightUpdater = new AtmosphereNightUpdater(mSceneManager->getTextureManager()); + mAtmosphereNightUpdater = new AtmosphereNightUpdater(mSceneManager->getImageManager()); atmosphereNight->addUpdateCallback(mAtmosphereNightUpdater); - mSun.reset(new Sun(mEarlyRenderBinRoot, *mSceneManager->getTextureManager())); + mSun.reset(new Sun(mEarlyRenderBinRoot, *mSceneManager->getImageManager())); const Fallback::Map* fallback=MWBase::Environment::get().getWorld()->getFallback(); - mMasser.reset(new Moon(mEarlyRenderBinRoot, *mSceneManager->getTextureManager(), fallback->getFallbackFloat("Moons_Masser_Size")/125, Moon::Type_Masser)); - mSecunda.reset(new Moon(mEarlyRenderBinRoot, *mSceneManager->getTextureManager(), fallback->getFallbackFloat("Moons_Secunda_Size")/125, Moon::Type_Secunda)); + mMasser.reset(new Moon(mEarlyRenderBinRoot, *mSceneManager->getImageManager(), fallback->getFallbackFloat("Moons_Masser_Size")/125, Moon::Type_Masser)); + mSecunda.reset(new Moon(mEarlyRenderBinRoot, *mSceneManager->getImageManager(), fallback->getFallbackFloat("Moons_Secunda_Size")/125, Moon::Type_Secunda)); mCloudNode = new osg::PositionAttitudeTransform; mEarlyRenderBinRoot->addChild(mCloudNode); @@ -1347,7 +1347,7 @@ void SkyManager::createRain() osg::ref_ptr stateset (mRainParticleSystem->getOrCreateStateSet()); - osg::ref_ptr raindropTex (new osg::Texture2D(mSceneManager->getTextureManager()->getImage("textures/tx_raindrop_01.dds"))); + osg::ref_ptr raindropTex (new osg::Texture2D(mSceneManager->getImageManager()->getImage("textures/tx_raindrop_01.dds"))); raindropTex->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); raindropTex->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); @@ -1557,7 +1557,7 @@ void SkyManager::setWeather(const WeatherResult& weather) std::string texture = Misc::ResourceHelpers::correctTexturePath(mClouds, mSceneManager->getVFS()); - osg::ref_ptr cloudTex (new osg::Texture2D(mSceneManager->getTextureManager()->getImage(texture))); + osg::ref_ptr cloudTex (new osg::Texture2D(mSceneManager->getImageManager()->getImage(texture))); cloudTex->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT); cloudTex->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT); @@ -1572,7 +1572,7 @@ void SkyManager::setWeather(const WeatherResult& weather) { std::string texture = Misc::ResourceHelpers::correctTexturePath(mNextClouds, mSceneManager->getVFS()); - osg::ref_ptr cloudTex (new osg::Texture2D(mSceneManager->getTextureManager()->getImage(texture))); + osg::ref_ptr cloudTex (new osg::Texture2D(mSceneManager->getImageManager()->getImage(texture))); cloudTex->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT); cloudTex->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT); diff --git a/apps/openmw/mwrender/util.cpp b/apps/openmw/mwrender/util.cpp index 3c8d1408a..0e1eaf0f4 100644 --- a/apps/openmw/mwrender/util.cpp +++ b/apps/openmw/mwrender/util.cpp @@ -15,7 +15,7 @@ void overrideTexture(const std::string &texture, Resource::ResourceSystem *resou return; std::string correctedTexture = Misc::ResourceHelpers::correctTexturePath(texture, resourceSystem->getVFS()); // Not sure if wrap settings should be pulled from the overridden texture? - osg::ref_ptr tex = new osg::Texture2D(resourceSystem->getTextureManager()->getImage(correctedTexture)); + osg::ref_ptr tex = new osg::Texture2D(resourceSystem->getImageManager()->getImage(correctedTexture)); tex->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); tex->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 7d1221a53..0e4f1a974 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -556,7 +556,7 @@ void Water::createSimpleWaterStateSet(osg::Node* node, float alpha) { std::ostringstream texname; texname << "textures/water/" << texture << std::setw(2) << std::setfill('0') << i << ".dds"; - osg::ref_ptr tex (new osg::Texture2D(mResourceSystem->getTextureManager()->getImage(texname.str()))); + osg::ref_ptr tex (new osg::Texture2D(mResourceSystem->getImageManager()->getImage(texname.str()))); tex->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT); tex->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT); textures.push_back(tex); diff --git a/components/myguiplatform/myguiplatform.cpp b/components/myguiplatform/myguiplatform.cpp index 491af8486..dfb2e6539 100644 --- a/components/myguiplatform/myguiplatform.cpp +++ b/components/myguiplatform/myguiplatform.cpp @@ -7,14 +7,14 @@ namespace osgMyGUI { -Platform::Platform(osgViewer::Viewer *viewer, osg::Group *guiRoot, Resource::ImageManager *textureManager, float uiScalingFactor) +Platform::Platform(osgViewer::Viewer *viewer, osg::Group *guiRoot, Resource::ImageManager *imageManager, float uiScalingFactor) : mRenderManager(nullptr) , mDataManager(nullptr) , mLogManager(nullptr) , mLogFacility(nullptr) { mLogManager = new MyGUI::LogManager(); - mRenderManager = new RenderManager(viewer, guiRoot, textureManager, uiScalingFactor); + mRenderManager = new RenderManager(viewer, guiRoot, imageManager, uiScalingFactor); mDataManager = new DataManager(); } diff --git a/components/myguiplatform/myguiplatform.hpp b/components/myguiplatform/myguiplatform.hpp index b3f959798..5ffbe0be7 100644 --- a/components/myguiplatform/myguiplatform.hpp +++ b/components/myguiplatform/myguiplatform.hpp @@ -30,7 +30,7 @@ namespace osgMyGUI class Platform { public: - Platform(osgViewer::Viewer* viewer, osg::Group* guiRoot, Resource::ImageManager* textureManager, float uiScalingFactor); + Platform(osgViewer::Viewer* viewer, osg::Group* guiRoot, Resource::ImageManager* imageManager, float uiScalingFactor); ~Platform(); diff --git a/components/myguiplatform/myguirendermanager.cpp b/components/myguiplatform/myguirendermanager.cpp index 23d004f47..5d2e3a9ae 100644 --- a/components/myguiplatform/myguirendermanager.cpp +++ b/components/myguiplatform/myguirendermanager.cpp @@ -353,10 +353,10 @@ void OSGVertexBuffer::create() // --------------------------------------------------------------------------- -RenderManager::RenderManager(osgViewer::Viewer *viewer, osg::Group *sceneroot, Resource::ImageManager* textureManager, float scalingFactor) +RenderManager::RenderManager(osgViewer::Viewer *viewer, osg::Group *sceneroot, Resource::ImageManager* imageManager, float scalingFactor) : mViewer(viewer) , mSceneRoot(sceneroot) - , mTextureManager(textureManager) + , mImageManager(imageManager) , mUpdate(false) , mIsInitialise(false) , mInvScalingFactor(1.f) @@ -523,7 +523,7 @@ MyGUI::ITexture* RenderManager::createTexture(const std::string &name) mTextures.erase(item); } - OSGTexture* texture = new OSGTexture(name, mTextureManager); + OSGTexture* texture = new OSGTexture(name, mImageManager); mTextures.insert(std::make_pair(name, texture)); return texture; } diff --git a/components/myguiplatform/myguirendermanager.hpp b/components/myguiplatform/myguirendermanager.hpp index b1aa0d3f0..4a0aae3cd 100644 --- a/components/myguiplatform/myguirendermanager.hpp +++ b/components/myguiplatform/myguirendermanager.hpp @@ -33,7 +33,7 @@ class RenderManager : public MyGUI::RenderManager, public MyGUI::IRenderTarget osg::ref_ptr mViewer; osg::ref_ptr mSceneRoot; osg::ref_ptr mDrawable; - Resource::ImageManager* mTextureManager; + Resource::ImageManager* mImageManager; MyGUI::IntSize mViewSize; bool mUpdate; @@ -54,7 +54,7 @@ class RenderManager : public MyGUI::RenderManager, public MyGUI::IRenderTarget void destroyAllResources(); public: - RenderManager(osgViewer::Viewer *viewer, osg::Group *sceneroot, Resource::ImageManager* textureManager, float scalingFactor); + RenderManager(osgViewer::Viewer *viewer, osg::Group *sceneroot, Resource::ImageManager* imageManager, float scalingFactor); virtual ~RenderManager(); void initialise(); diff --git a/components/myguiplatform/myguitexture.cpp b/components/myguiplatform/myguitexture.cpp index 904ed6abf..2ba78c26b 100644 --- a/components/myguiplatform/myguitexture.cpp +++ b/components/myguiplatform/myguitexture.cpp @@ -10,9 +10,9 @@ namespace osgMyGUI { - OSGTexture::OSGTexture(const std::string &name, Resource::ImageManager* textureManager) + OSGTexture::OSGTexture(const std::string &name, Resource::ImageManager* imageManager) : mName(name) - , mTextureManager(textureManager) + , mImageManager(imageManager) , mFormat(MyGUI::PixelFormat::Unknow) , mUsage(MyGUI::TextureUsage::Default) , mNumElemBytes(0) @@ -20,7 +20,7 @@ namespace osgMyGUI } OSGTexture::OSGTexture(osg::Texture2D *texture) - : mTextureManager(NULL) + : mImageManager(NULL) , mTexture(texture) , mFormat(MyGUI::PixelFormat::Unknow) , mUsage(MyGUI::TextureUsage::Default) @@ -83,10 +83,10 @@ namespace osgMyGUI void OSGTexture::loadFromFile(const std::string &fname) { - if (!mTextureManager) - throw std::runtime_error("No texturemanager set"); + if (!mImageManager) + throw std::runtime_error("No imagemanager set"); - mTexture = new osg::Texture2D(mTextureManager->getImage(fname)); + mTexture = new osg::Texture2D(mImageManager->getImage(fname)); mTexture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); mTexture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); // disable mip-maps diff --git a/components/myguiplatform/myguitexture.hpp b/components/myguiplatform/myguitexture.hpp index 21bc89992..101e2135b 100644 --- a/components/myguiplatform/myguitexture.hpp +++ b/components/myguiplatform/myguitexture.hpp @@ -21,7 +21,7 @@ namespace osgMyGUI class OSGTexture : public MyGUI::ITexture { std::string mName; - Resource::ImageManager* mTextureManager; + Resource::ImageManager* mImageManager; osg::ref_ptr mLockedImage; osg::ref_ptr mTexture; @@ -30,7 +30,7 @@ namespace osgMyGUI size_t mNumElemBytes; public: - OSGTexture(const std::string &name, Resource::ImageManager* textureManager); + OSGTexture(const std::string &name, Resource::ImageManager* imageManager); OSGTexture(osg::Texture2D* texture); virtual ~OSGTexture(); diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index d09c34aa5..6c6061063 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -343,7 +343,7 @@ namespace NifOsg } } - osg::ref_ptr load(Nif::NIFFilePtr nif, Resource::ImageManager* textureManager) + osg::ref_ptr load(Nif::NIFFilePtr nif, Resource::ImageManager* imageManager) { if (nif->numRoots() < 1) nif->fail("Found no root nodes"); @@ -356,7 +356,7 @@ namespace NifOsg osg::ref_ptr textkeys (new TextKeyMapHolder); - osg::ref_ptr created = handleNode(nifNode, NULL, textureManager, std::vector(), 0, 0, false, &textkeys->mTextKeys); + osg::ref_ptr created = handleNode(nifNode, NULL, imageManager, std::vector(), 0, 0, false, &textkeys->mTextKeys); if (nif->getUseSkinning()) { @@ -369,13 +369,13 @@ namespace NifOsg return created; } - void applyNodeProperties(const Nif::Node *nifNode, osg::Node *applyTo, SceneUtil::CompositeStateSetUpdater* composite, Resource::ImageManager* textureManager, std::vector& boundTextures, int animflags) + void applyNodeProperties(const Nif::Node *nifNode, osg::Node *applyTo, SceneUtil::CompositeStateSetUpdater* composite, Resource::ImageManager* imageManager, std::vector& boundTextures, int animflags) { const Nif::PropertyList& props = nifNode->props; for (size_t i = 0; i handleNode(const Nif::Node* nifNode, osg::Group* parentNode, Resource::ImageManager* textureManager, + osg::ref_ptr handleNode(const Nif::Node* nifNode, osg::Group* parentNode, Resource::ImageManager* imageManager, std::vector boundTextures, int animflags, int particleflags, bool skipMeshes, TextKeyMap* textKeys, osg::Node* rootNode=NULL) { osg::ref_ptr node = new osg::MatrixTransform(nifNode->trafo.toMatrix()); @@ -542,7 +542,7 @@ namespace NifOsg osg::ref_ptr composite = new SceneUtil::CompositeStateSetUpdater; - applyNodeProperties(nifNode, node, composite, textureManager, boundTextures, animflags); + applyNodeProperties(nifNode, node, composite, imageManager, boundTextures, animflags); if (nifNode->recType == Nif::RC_NiTriShape && !skipMeshes) { @@ -588,7 +588,7 @@ namespace NifOsg { if(!children[i].empty()) { - handleNode(children[i].getPtr(), node, textureManager, boundTextures, animflags, particleflags, skipMeshes, textKeys, rootNode); + handleNode(children[i].getPtr(), node, imageManager, boundTextures, animflags, particleflags, skipMeshes, textKeys, rootNode); } } } @@ -682,7 +682,7 @@ namespace NifOsg } } - void handleTextureControllers(const Nif::Property *texProperty, SceneUtil::CompositeStateSetUpdater* composite, Resource::ImageManager* textureManager, osg::StateSet *stateset, int animflags) + void handleTextureControllers(const Nif::Property *texProperty, SceneUtil::CompositeStateSetUpdater* composite, Resource::ImageManager* imageManager, osg::StateSet *stateset, int animflags) { for (Nif::ControllerPtr ctrl = texProperty->controller; !ctrl.empty(); ctrl = ctrl->next) { @@ -708,8 +708,8 @@ namespace NifOsg wrapT = inherit->getWrap(osg::Texture2D::WRAP_T); } - std::string filename = Misc::ResourceHelpers::correctTexturePath(st->filename, textureManager->getVFS()); - osg::ref_ptr texture (new osg::Texture2D(textureManager->getImage(filename))); + std::string filename = Misc::ResourceHelpers::correctTexturePath(st->filename, imageManager->getVFS()); + osg::ref_ptr texture (new osg::Texture2D(imageManager->getImage(filename))); texture->setWrap(osg::Texture::WRAP_S, wrapS); texture->setWrap(osg::Texture::WRAP_T, wrapT); textures.push_back(texture); @@ -1244,7 +1244,7 @@ namespace NifOsg } void handleProperty(const Nif::Property *property, - osg::Node *node, SceneUtil::CompositeStateSetUpdater* composite, Resource::ImageManager* textureManager, std::vector& boundTextures, int animflags) + osg::Node *node, SceneUtil::CompositeStateSetUpdater* composite, Resource::ImageManager* imageManager, std::vector& boundTextures, int animflags) { switch (property->recType) { @@ -1372,14 +1372,14 @@ namespace NifOsg continue; } - std::string filename = Misc::ResourceHelpers::correctTexturePath(st->filename, textureManager->getVFS()); + std::string filename = Misc::ResourceHelpers::correctTexturePath(st->filename, imageManager->getVFS()); unsigned int clamp = static_cast(tex.clamp); int wrapT = (clamp) & 0x1; int wrapS = (clamp >> 1) & 0x1; // create a new texture, will later attempt to share using the SharedStateManager - osg::ref_ptr texture2d (new osg::Texture2D(textureManager->getImage(filename))); + osg::ref_ptr texture2d (new osg::Texture2D(imageManager->getImage(filename))); texture2d->setWrap(osg::Texture::WRAP_S, wrapS ? osg::Texture::REPEAT : osg::Texture::CLAMP); texture2d->setWrap(osg::Texture::WRAP_T, wrapT ? osg::Texture::REPEAT : osg::Texture::CLAMP); @@ -1423,7 +1423,7 @@ namespace NifOsg boundTextures.push_back(tex.uvSet); } - handleTextureControllers(texprop, composite, textureManager, stateset, animflags); + handleTextureControllers(texprop, composite, imageManager, stateset, animflags); } break; } @@ -1543,10 +1543,10 @@ namespace NifOsg }; - osg::ref_ptr Loader::load(Nif::NIFFilePtr file, Resource::ImageManager* textureManager) + osg::ref_ptr Loader::load(Nif::NIFFilePtr file, Resource::ImageManager* imageManager) { LoaderImpl impl(file->getFilename()); - return impl.load(file, textureManager); + return impl.load(file, imageManager); } void Loader::loadKf(Nif::NIFFilePtr kf, KeyframeHolder& target) diff --git a/components/nifosg/nifloader.hpp b/components/nifosg/nifloader.hpp index afc912ed3..d2d5e7b2d 100644 --- a/components/nifosg/nifloader.hpp +++ b/components/nifosg/nifloader.hpp @@ -62,7 +62,7 @@ namespace NifOsg { public: /// Create a scene graph for the given NIF. Auto-detects when skinning is used and wraps the graph in a Skeleton if so. - static osg::ref_ptr load(Nif::NIFFilePtr file, Resource::ImageManager* textureManager); + static osg::ref_ptr load(Nif::NIFFilePtr file, Resource::ImageManager* imageManager); /// Load keyframe controllers from the given kf file. static void loadKf(Nif::NIFFilePtr kf, KeyframeHolder& target); diff --git a/components/resource/imagemanager.hpp b/components/resource/imagemanager.hpp index ee0c0f2e2..3b2bacc13 100644 --- a/components/resource/imagemanager.hpp +++ b/components/resource/imagemanager.hpp @@ -1,5 +1,5 @@ -#ifndef OPENMW_COMPONENTS_RESOURCE_TEXTUREMANAGER_H -#define OPENMW_COMPONENTS_RESOURCE_TEXTUREMANAGER_H +#ifndef OPENMW_COMPONENTS_RESOURCE_IMAGEMANAGER_H +#define OPENMW_COMPONENTS_RESOURCE_IMAGEMANAGER_H #include #include diff --git a/components/resource/resourcesystem.cpp b/components/resource/resourcesystem.cpp index 89a4b2cb3..d39a723d6 100644 --- a/components/resource/resourcesystem.cpp +++ b/components/resource/resourcesystem.cpp @@ -13,8 +13,8 @@ namespace Resource { mNifFileManager.reset(new NifFileManager(vfs)); mKeyframeManager.reset(new KeyframeManager(vfs)); - mTextureManager.reset(new ImageManager(vfs)); - mSceneManager.reset(new SceneManager(vfs, mTextureManager.get(), mNifFileManager.get())); + mImageManager.reset(new ImageManager(vfs)); + mSceneManager.reset(new SceneManager(vfs, mImageManager.get(), mNifFileManager.get())); } ResourceSystem::~ResourceSystem() @@ -27,9 +27,9 @@ namespace Resource return mSceneManager.get(); } - ImageManager* ResourceSystem::getTextureManager() + ImageManager* ResourceSystem::getImageManager() { - return mTextureManager.get(); + return mImageManager.get(); } NifFileManager* ResourceSystem::getNifFileManager() diff --git a/components/resource/resourcesystem.hpp b/components/resource/resourcesystem.hpp index 7c4d83b7d..13a96e8c7 100644 --- a/components/resource/resourcesystem.hpp +++ b/components/resource/resourcesystem.hpp @@ -26,7 +26,7 @@ namespace Resource ~ResourceSystem(); SceneManager* getSceneManager(); - ImageManager* getTextureManager(); + ImageManager* getImageManager(); NifFileManager* getNifFileManager(); KeyframeManager* getKeyframeManager(); @@ -37,7 +37,7 @@ namespace Resource private: std::auto_ptr mSceneManager; - std::auto_ptr mTextureManager; + std::auto_ptr mImageManager; std::auto_ptr mNifFileManager; std::auto_ptr mKeyframeManager; diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index 287186887..dd4847877 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -227,9 +227,9 @@ namespace Resource - SceneManager::SceneManager(const VFS::Manager *vfs, Resource::ImageManager* textureManager, Resource::NifFileManager* nifFileManager) + SceneManager::SceneManager(const VFS::Manager *vfs, Resource::ImageManager* imageManager, Resource::NifFileManager* nifFileManager) : mVFS(vfs) - , mTextureManager(textureManager) + , mImageManager(imageManager) , mNifFileManager(nifFileManager) , mMinFilter(osg::Texture::LINEAR_MIPMAP_LINEAR) , mMagFilter(osg::Texture::LINEAR) @@ -249,8 +249,8 @@ namespace Resource class ImageReadCallback : public osgDB::ReadFileCallback { public: - ImageReadCallback(Resource::ImageManager* textureMgr) - : mTextureManager(textureMgr) + ImageReadCallback(Resource::ImageManager* imageMgr) + : mImageManager(imageMgr) { } @@ -258,7 +258,7 @@ namespace Resource { try { - return osgDB::ReaderWriter::ReadResult(mTextureManager->getImage(filename), osgDB::ReaderWriter::ReadResult::FILE_LOADED); + return osgDB::ReaderWriter::ReadResult(mImageManager->getImage(filename), osgDB::ReaderWriter::ReadResult::FILE_LOADED); } catch (std::exception& e) { @@ -267,7 +267,7 @@ namespace Resource } private: - Resource::ImageManager* mTextureManager; + Resource::ImageManager* mImageManager; }; std::string getFileExtension(const std::string& file) @@ -278,11 +278,11 @@ namespace Resource return std::string(); } - osg::ref_ptr load (Files::IStreamPtr file, const std::string& normalizedFilename, Resource::ImageManager* textureMgr, Resource::NifFileManager* nifFileManager) + osg::ref_ptr load (Files::IStreamPtr file, const std::string& normalizedFilename, Resource::ImageManager* imageManager, Resource::NifFileManager* nifFileManager) { std::string ext = getFileExtension(normalizedFilename); if (ext == "nif") - return NifOsg::Loader::load(nifFileManager->get(normalizedFilename), textureMgr); + return NifOsg::Loader::load(nifFileManager->get(normalizedFilename), imageManager); else { osgDB::ReaderWriter* reader = osgDB::Registry::instance()->getReaderWriterForExtension(ext); @@ -297,7 +297,7 @@ namespace Resource // Set a ReadFileCallback so that image files referenced in the model are read from our virtual file system instead of the osgDB. // Note, for some formats (.obj/.mtl) that reference other (non-image) files a findFileCallback would be necessary. // but findFileCallback does not support virtual files, so we can't implement it. - options->setReadFileCallback(new ImageReadCallback(textureMgr)); + options->setReadFileCallback(new ImageReadCallback(imageManager)); osgDB::ReaderWriter::ReadResult result = reader->readNode(*file, options); if (!result.success()) @@ -323,7 +323,7 @@ namespace Resource { Files::IStreamPtr file = mVFS->get(normalized); - loaded = load(file, normalized, mTextureManager, mNifFileManager); + loaded = load(file, normalized, mImageManager, mNifFileManager); } catch (std::exception& e) { @@ -336,7 +336,7 @@ namespace Resource { std::cerr << "Failed to load '" << name << "': " << e.what() << ", using marker_error." << sMeshTypes[i] << " instead" << std::endl; Files::IStreamPtr file = mVFS->get(normalized); - loaded = load(file, normalized, mTextureManager, mNifFileManager); + loaded = load(file, normalized, mImageManager, mNifFileManager); break; } } @@ -408,9 +408,9 @@ namespace Resource return mVFS; } - Resource::ImageManager* SceneManager::getTextureManager() + Resource::ImageManager* SceneManager::getImageManager() { - return mTextureManager; + return mImageManager; } void SceneManager::setParticleSystemMask(unsigned int mask) diff --git a/components/resource/scenemanager.hpp b/components/resource/scenemanager.hpp index 6eadf7b45..3dd37111d 100644 --- a/components/resource/scenemanager.hpp +++ b/components/resource/scenemanager.hpp @@ -36,7 +36,7 @@ namespace Resource class SceneManager { public: - SceneManager(const VFS::Manager* vfs, Resource::ImageManager* textureManager, Resource::NifFileManager* nifFileManager); + SceneManager(const VFS::Manager* vfs, Resource::ImageManager* imageManager, Resource::NifFileManager* nifFileManager); ~SceneManager(); /// Get a read-only copy of this scene "template" @@ -70,7 +70,7 @@ namespace Resource const VFS::Manager* getVFS() const; - Resource::ImageManager* getTextureManager(); + Resource::ImageManager* getImageManager(); /// @param mask The node mask to apply to loaded particle system nodes. void setParticleSystemMask(unsigned int mask); @@ -89,7 +89,7 @@ namespace Resource private: const VFS::Manager* mVFS; - Resource::ImageManager* mTextureManager; + Resource::ImageManager* mImageManager; Resource::NifFileManager* mNifFileManager; osg::Texture::FilterMode mMinFilter; diff --git a/components/terrain/terraingrid.cpp b/components/terrain/terraingrid.cpp index 094023f38..2efbf1b9e 100644 --- a/components/terrain/terraingrid.cpp +++ b/components/terrain/terraingrid.cpp @@ -142,7 +142,7 @@ osg::ref_ptr TerrainGrid::buildTerrain (osg::Group* parent, float chu osg::ref_ptr tex = mTextureCache[it->mDiffuseMap]; if (!tex) { - tex = new osg::Texture2D(mResourceSystem->getTextureManager()->getImage(it->mDiffuseMap)); + tex = new osg::Texture2D(mResourceSystem->getImageManager()->getImage(it->mDiffuseMap)); tex->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT); tex->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT); mTextureCache[it->mDiffuseMap] = tex; From 499beda6656e37b45aa35549126023fd4898ceb2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 5 Feb 2016 23:20:13 +0100 Subject: [PATCH 3081/3725] Clear terrain texture cache before applying filter settings --- apps/openmw/mwrender/renderingmanager.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index d1b5f6fda..9b7ced4b5 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -783,6 +783,9 @@ namespace MWRender void RenderingManager::updateTextureFiltering() { + if (mTerrain.get()) + mTerrain->clearCache(); + mResourceSystem->getSceneManager()->setFilterSettings( Settings::Manager::getString("texture mag filter", "General"), Settings::Manager::getString("texture min filter", "General"), From 9e5225bb6f952b50402063783374ffcd7a91be23 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 5 Feb 2016 23:21:54 +0100 Subject: [PATCH 3082/3725] Do not unref a Texture's image data after applying it --- apps/openmw/engine.cpp | 2 +- components/terrain/terraingrid.cpp | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index d96bf16e4..d30d0961a 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -448,7 +448,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) VFS::registerArchives(mVFS.get(), mFileCollections, mArchives, true); mResourceSystem.reset(new Resource::ResourceSystem(mVFS.get())); - mResourceSystem->getSceneManager()->setUnRefImageDataAfterApply(true); + mResourceSystem->getSceneManager()->setUnRefImageDataAfterApply(false); // keep to Off for now to allow better state sharing mResourceSystem->getSceneManager()->setFilterSettings( Settings::Manager::getString("texture mag filter", "General"), Settings::Manager::getString("texture min filter", "General"), diff --git a/components/terrain/terraingrid.cpp b/components/terrain/terraingrid.cpp index 2efbf1b9e..eb085ca42 100644 --- a/components/terrain/terraingrid.cpp +++ b/components/terrain/terraingrid.cpp @@ -166,10 +166,6 @@ osg::ref_ptr TerrainGrid::buildTerrain (osg::Group* parent, float chu textureCompileDummy->getOrCreateStateSet()->setTextureAttributeAndModes(dummyTextureCounter++, blendmapTextures.back()); } - // SharedStatemanager->share(textureCompileDummy); - - // Remove unrefImageDataAfterApply for better state sharing - // use texture coordinates for both texture units, the layer texture and blend texture for (unsigned int i=0; i<2; ++i) geometry->setTexCoordArray(i, mCache.getUVBuffer()); From a72af4a1a38e9a39057dce2951cd6a0817025810 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 5 Feb 2016 23:25:01 +0100 Subject: [PATCH 3083/3725] cout that should be cerr --- apps/openmw/mwworld/localscripts.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/localscripts.cpp b/apps/openmw/mwworld/localscripts.cpp index 7ccc213c4..f0174ac52 100644 --- a/apps/openmw/mwworld/localscripts.cpp +++ b/apps/openmw/mwworld/localscripts.cpp @@ -101,7 +101,7 @@ void MWWorld::LocalScripts::add (const std::string& scriptName, const Ptr& ptr) for (std::list >::iterator iter = mScripts.begin(); iter!=mScripts.end(); ++iter) if (iter->second==ptr) { - std::cout << "warning, tried to add local script twice for " << ptr.getCellRef().getRefId() << std::endl; + std::cerr << "warning, tried to add local script twice for " << ptr.getCellRef().getRefId() << std::endl; remove(ptr); break; } From 6c1c653cbab3fe0228303ccf50c40c93dfa9c370 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 5 Feb 2016 23:31:59 +0100 Subject: [PATCH 3084/3725] Use the osgDB::ObjectCache in ImageManager Should be thread safe now. --- components/resource/imagemanager.cpp | 16 ++++++++++++---- components/resource/imagemanager.hpp | 5 +++-- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/components/resource/imagemanager.cpp b/components/resource/imagemanager.cpp index e1c0572c7..bd422fe2a 100644 --- a/components/resource/imagemanager.cpp +++ b/components/resource/imagemanager.cpp @@ -6,6 +6,8 @@ #include +#include "objectcache.hpp" + #ifdef OSG_LIBRARY_STATIC // This list of plugins should match with the list in the top-level CMakelists.txt. USE_OSGPLUGIN(png) @@ -41,6 +43,7 @@ namespace Resource ImageManager::ImageManager(const VFS::Manager *vfs) : mVFS(vfs) + , mCache(new osgDB::ObjectCache) , mWarningImage(createWarningImage()) , mOptions(new osgDB::Options("dds_flip dds_dxt1_detect_rgba")) { @@ -88,9 +91,10 @@ namespace Resource { std::string normalized = filename; mVFS->normalizeFilename(normalized); - std::map >::iterator found = mImages.find(normalized); - if (found != mImages.end()) - return found->second; + + osg::ref_ptr obj = mCache->getRefFromObjectCache(normalized); + if (obj) + return osg::ref_ptr(static_cast(obj.get())); else { Files::IStreamPtr stream; @@ -101,6 +105,7 @@ namespace Resource catch (std::exception& e) { std::cerr << "Failed to open image: " << e.what() << std::endl; + mCache->addEntryToObjectCache(normalized, mWarningImage); return mWarningImage; } @@ -112,6 +117,7 @@ namespace Resource if (!reader) { std::cerr << "Error loading " << filename << ": no readerwriter for '" << ext << "' found" << std::endl; + mCache->addEntryToObjectCache(normalized, mWarningImage); return mWarningImage; } @@ -119,16 +125,18 @@ namespace Resource if (!result.success()) { std::cerr << "Error loading " << filename << ": " << result.message() << " code " << result.status() << std::endl; + mCache->addEntryToObjectCache(normalized, mWarningImage); return mWarningImage; } osg::Image* image = result.getImage(); if (!checkSupported(image, filename)) { + mCache->addEntryToObjectCache(normalized, mWarningImage); return mWarningImage; } - mImages.insert(std::make_pair(normalized, image)); + mCache->addEntryToObjectCache(normalized, image); return image; } } diff --git a/components/resource/imagemanager.hpp b/components/resource/imagemanager.hpp index 3b2bacc13..bc1d7b4e4 100644 --- a/components/resource/imagemanager.hpp +++ b/components/resource/imagemanager.hpp @@ -21,12 +21,14 @@ namespace VFS namespace osgDB { class Options; + class ObjectCache; } namespace Resource { /// @brief Handles loading/caching of Images. + /// @note May be used from any thread. class ImageManager { public: @@ -44,8 +46,7 @@ namespace Resource private: const VFS::Manager* mVFS; - // TODO: use ObjectCache - std::map > mImages; + osg::ref_ptr mCache; osg::ref_ptr mWarningImage; osg::ref_ptr mOptions; From 909c4d96b64e5fa6f85a959f59964927a28730b6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 5 Feb 2016 23:59:37 +0100 Subject: [PATCH 3085/3725] Use the osgDB::ObjectCache in BulletShapeManager --- components/resource/bulletshape.cpp | 8 ++++++++ components/resource/bulletshape.hpp | 8 ++++++-- components/resource/bulletshapemanager.cpp | 21 ++++++++++++++------- components/resource/bulletshapemanager.hpp | 8 ++++++-- 4 files changed, 34 insertions(+), 11 deletions(-) diff --git a/components/resource/bulletshape.cpp b/components/resource/bulletshape.cpp index 0cbc63a22..baff86a79 100644 --- a/components/resource/bulletshape.cpp +++ b/components/resource/bulletshape.cpp @@ -17,6 +17,14 @@ BulletShape::BulletShape() } +BulletShape::BulletShape(const BulletShape ©, const osg::CopyOp ©op) + : mCollisionShape(duplicateCollisionShape(copy.mCollisionShape)) + , mCollisionBoxHalfExtents(copy.mCollisionBoxHalfExtents) + , mCollisionBoxTranslate(copy.mCollisionBoxTranslate) + , mAnimatedShapes(copy.mAnimatedShapes) +{ +} + BulletShape::~BulletShape() { deleteShape(mCollisionShape); diff --git a/components/resource/bulletshape.hpp b/components/resource/bulletshape.hpp index cfae27eac..a007bad31 100644 --- a/components/resource/bulletshape.hpp +++ b/components/resource/bulletshape.hpp @@ -3,7 +3,7 @@ #include -#include +#include #include #include @@ -15,12 +15,15 @@ namespace Resource { class BulletShapeInstance; - class BulletShape : public osg::Referenced + class BulletShape : public osg::Object { public: BulletShape(); + BulletShape(const BulletShape& copy, const osg::CopyOp& copyop); virtual ~BulletShape(); + META_Object(Resource, BulletShape) + btCollisionShape* mCollisionShape; // Used for actors. Note, ideally actors would use a separate loader - as it is @@ -42,6 +45,7 @@ namespace Resource btCollisionShape* getCollisionShape(); private: + void deleteShape(btCollisionShape* shape); }; diff --git a/components/resource/bulletshapemanager.cpp b/components/resource/bulletshapemanager.cpp index 4cbe62f3c..2ab7b243a 100644 --- a/components/resource/bulletshapemanager.cpp +++ b/components/resource/bulletshapemanager.cpp @@ -13,6 +13,7 @@ #include "bulletshape.hpp" #include "scenemanager.hpp" #include "niffilemanager.hpp" +#include "objectcache.hpp" namespace Resource @@ -99,6 +100,7 @@ BulletShapeManager::BulletShapeManager(const VFS::Manager* vfs, SceneManager* sc : mVFS(vfs) , mSceneManager(sceneMgr) , mNifFileManager(nifFileManager) + , mCache(new osgDB::ObjectCache) { } @@ -114,8 +116,10 @@ osg::ref_ptr BulletShapeManager::createInstance(const std:: mVFS->normalizeFilename(normalized); osg::ref_ptr shape; - Index::iterator it = mIndex.find(normalized); - if (it == mIndex.end()) + osg::ref_ptr obj = mCache->getRefFromObjectCache(normalized); + if (obj) + shape = osg::ref_ptr(static_cast(obj.get())); + else { size_t extPos = normalized.find_last_of('.'); std::string ext; @@ -137,16 +141,19 @@ osg::ref_ptr BulletShapeManager::createInstance(const std:: node->accept(visitor); shape = visitor.getShape(); if (!shape) + { + mCache->addEntryToObjectCache(normalized, NULL); return osg::ref_ptr(); + } } - mIndex[normalized] = shape; + mCache->addEntryToObjectCache(normalized, shape); } - else - shape = it->second; - osg::ref_ptr instance = shape->makeInstance(); - return instance; + if (shape) + return shape->makeInstance(); + else + return osg::ref_ptr(); } } diff --git a/components/resource/bulletshapemanager.hpp b/components/resource/bulletshapemanager.hpp index ac1523495..d9293896b 100644 --- a/components/resource/bulletshapemanager.hpp +++ b/components/resource/bulletshapemanager.hpp @@ -13,6 +13,11 @@ namespace VFS class Manager; } +namespace osgDB +{ + class ObjectCache; +} + namespace Resource { class SceneManager; @@ -34,8 +39,7 @@ namespace Resource SceneManager* mSceneManager; NifFileManager* mNifFileManager; - typedef std::map > Index; - Index mIndex; + osg::ref_ptr mCache; }; } From ea1efaac0cc5b7d228a90a99757594fe25e10cab Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 6 Feb 2016 00:15:12 +0100 Subject: [PATCH 3086/3725] Use the osgDB::ObjectCache in SceneManager, cleanup --- components/resource/bulletshapemanager.hpp | 3 +++ components/resource/keyframemanager.hpp | 2 +- components/resource/niffilemanager.hpp | 2 +- components/resource/scenemanager.cpp | 27 +++++++++------------- components/resource/scenemanager.hpp | 23 ++++++++++-------- 5 files changed, 30 insertions(+), 27 deletions(-) diff --git a/components/resource/bulletshapemanager.hpp b/components/resource/bulletshapemanager.hpp index d9293896b..c8db8849e 100644 --- a/components/resource/bulletshapemanager.hpp +++ b/components/resource/bulletshapemanager.hpp @@ -26,6 +26,9 @@ namespace Resource class BulletShape; class BulletShapeInstance; + /// Handles loading, caching and "instancing" of bullet shapes. + /// A shape 'instance' is a clone of another shape, with the goal of setting a different scale on this instance. + /// @note May be used from any thread. class BulletShapeManager { public: diff --git a/components/resource/keyframemanager.hpp b/components/resource/keyframemanager.hpp index 5032d0e38..5a5cb3628 100644 --- a/components/resource/keyframemanager.hpp +++ b/components/resource/keyframemanager.hpp @@ -23,6 +23,7 @@ namespace Resource { /// @brief Managing of keyframe resources + /// @note May be used from any thread. class KeyframeManager { public: @@ -32,7 +33,6 @@ namespace Resource void clearCache(); /// Retrieve a read-only keyframe resource by name (case-insensitive). - /// @note This method is safe to call from any thread. /// @note Throws an exception if the resource is not found. osg::ref_ptr get(const std::string& name); diff --git a/components/resource/niffilemanager.hpp b/components/resource/niffilemanager.hpp index 90ad9fc29..4551cf227 100644 --- a/components/resource/niffilemanager.hpp +++ b/components/resource/niffilemanager.hpp @@ -19,7 +19,7 @@ namespace Resource { /// @brief Handles caching of NIFFiles. - /// @note The NifFileManager is completely thread safe. + /// @note May be used from any thread. class NifFileManager { public: diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index dd4847877..95e03b389 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -26,10 +26,12 @@ #include "imagemanager.hpp" #include "niffilemanager.hpp" +#include "objectcache.hpp" namespace { + /// @todo Do this in updateCallback so that animations are accounted for. class InitWorldSpaceParticlesVisitor : public osg::NodeVisitor { public: @@ -236,6 +238,7 @@ namespace Resource , mMaxAnisotropy(1) , mUnRefImageDataAfterApply(false) , mParticleSystemMask(~0u) + , mCache(new osgDB::ObjectCache) { } @@ -315,8 +318,10 @@ namespace Resource std::string normalized = name; mVFS->normalizeFilename(normalized); - Index::iterator it = mIndex.find(normalized); - if (it == mIndex.end()) + osg::ref_ptr obj = mCache->getRefFromObjectCache(normalized); + if (obj) + return osg::ref_ptr(static_cast(obj.get())); + else { osg::ref_ptr loaded; try @@ -357,11 +362,9 @@ namespace Resource if (mIncrementalCompileOperation) mIncrementalCompileOperation->add(loaded); - mIndex[normalized] = loaded; + mCache->addEntryToObjectCache(normalized, loaded); return loaded; } - else - return it->second; } osg::ref_ptr SceneManager::createInstance(const std::string &name) @@ -386,10 +389,7 @@ namespace Resource void SceneManager::releaseGLObjects(osg::State *state) { - for (Index::iterator it = mIndex.begin(); it != mIndex.end(); ++it) - { - it->second->releaseGLObjects(state); - } + mCache->releaseGLObjects(state); } void SceneManager::setIncrementalCompileOperation(osgUtil::IncrementalCompileOperation *ico) @@ -458,6 +458,8 @@ namespace Resource mMagFilter = mag; mMaxAnisotropy = std::max(1, maxAnisotropy); + mCache->clear(); + SetFilterSettingsControllerVisitor setFilterSettingsControllerVisitor (mMinFilter, mMagFilter, mMaxAnisotropy); SetFilterSettingsVisitor setFilterSettingsVisitor (mMinFilter, mMagFilter, mMaxAnisotropy); if (viewer && viewer->getSceneData()) @@ -466,13 +468,6 @@ namespace Resource viewer->getSceneData()->accept(setFilterSettingsVisitor); } - for (Index::iterator it = mIndex.begin(); it != mIndex.end(); ++it) - { - osg::Node* node = it->second; - node->accept(setFilterSettingsControllerVisitor); - node->accept(setFilterSettingsVisitor); - } - if(viewer) viewer->startThreading(); } diff --git a/components/resource/scenemanager.hpp b/components/resource/scenemanager.hpp index 3dd37111d..32bd80660 100644 --- a/components/resource/scenemanager.hpp +++ b/components/resource/scenemanager.hpp @@ -24,6 +24,11 @@ namespace osgUtil class IncrementalCompileOperation; } +namespace osgDB +{ + class ObjectCache; +} + namespace osgViewer { class Viewer; @@ -32,7 +37,8 @@ namespace osgViewer namespace Resource { - /// @brief Handles loading and caching of scenes, e.g. NIF files + /// @brief Handles loading and caching of scenes, e.g. .nif files or .osg files + /// @note Some methods of the scene manager can be used from any thread, see the methods documentation for more details. class SceneManager { public: @@ -42,20 +48,24 @@ namespace Resource /// Get a read-only copy of this scene "template" /// @note If the given filename does not exist or fails to load, an error marker mesh will be used instead. /// If even the error marker mesh can not be found, an exception is thrown. + /// @note Thread safe. osg::ref_ptr getTemplate(const std::string& name); /// Create an instance of the given scene template /// @see getTemplate + /// @note Thread safe. osg::ref_ptr createInstance(const std::string& name); /// Create an instance of the given scene template and immediately attach it to a parent node /// @see getTemplate + /// @note Not thread safe, unless parentNode is not part of the main scene graph yet. osg::ref_ptr createInstance(const std::string& name, osg::Group* parentNode); /// Attach the given scene instance to the given parent node /// @note You should have the parentNode in its intended position before calling this method, /// so that world space particles of the \a instance get transformed correctly. /// @note Assumes the given instance was not attached to any parents before. + /// @note Not thread safe, unless parentNode is not part of the main scene graph yet. void attachTo(osg::Node* instance, osg::Group* parentNode) const; /// Manually release created OpenGL objects for the given graphics context. This may be required @@ -75,11 +85,12 @@ namespace Resource /// @param mask The node mask to apply to loaded particle system nodes. void setParticleSystemMask(unsigned int mask); + /// @param viewer used to apply the new filter settings to the existing scene graph. If there is no scene yet, you can pass a NULL viewer. void setFilterSettings(const std::string &magfilter, const std::string &minfilter, const std::string &mipmap, int maxAnisotropy, osgViewer::Viewer *viewer); - /// Apply filter settings to the given texture. Note, when loading an object through this scene manager (i.e. calling getTemplate / createInstance) + /// Apply filter settings to the given texture. Note, when loading an object through this scene manager (i.e. calling getTemplate or createInstance) /// the filter settings are applied automatically. This method is provided for textures that were created outside of the SceneManager. void applyFilterSettings (osg::Texture* tex); @@ -101,16 +112,10 @@ namespace Resource unsigned int mParticleSystemMask; - // observer_ptr? - typedef std::map > Index; - Index mIndex; + osg::ref_ptr mCache; SceneManager(const SceneManager&); void operator = (const SceneManager&); - - /// @warning It is unsafe to call this function when a draw thread is using the textures. Call stopThreading() first! - void setFilterSettings(osg::Texture::FilterMode minFilter, osg::Texture::FilterMode maxFilter, int maxAnisotropy); - }; } From c4658a0ef7f119713909a0fd105465a6f61d00ad Mon Sep 17 00:00:00 2001 From: HiPhish Date: Fri, 5 Feb 2016 23:06:18 +0100 Subject: [PATCH 3087/3725] Add OpenMW CS manual to the repository. The manual depends on Sphinx to build. A makefile and a Windows batch script are included for building, both were automatically generated by Sphinx. I have left all settings at their default and I have tested that HTML and PDF output build properly. --- .gitignore | 1 + AUTHORS.md | 1 + docs/cs-manual/Makefile | 216 +++++++++++ docs/cs-manual/make.bat | 263 +++++++++++++ .../_static/images/chapter-1/add-record.png | Bin 0 -> 106549 bytes .../_static/images/chapter-1/edit-record.png | Bin 0 -> 191171 bytes .../_static/images/chapter-1/new-project.png | Bin 0 -> 70819 bytes .../_static/images/chapter-1/objects.png | Bin 0 -> 97097 bytes .../images/chapter-1/opening-dialogue.png | Bin 0 -> 92302 bytes docs/cs-manual/source/conf.py | 358 ++++++++++++++++++ .../source/files-and-directories.rst | 224 +++++++++++ docs/cs-manual/source/foreword.rst | 21 + docs/cs-manual/source/index.rst | 30 ++ docs/cs-manual/source/starting-dialog.rst | 40 ++ docs/cs-manual/source/tour.rst | 223 +++++++++++ 15 files changed, 1377 insertions(+) create mode 100644 docs/cs-manual/Makefile create mode 100644 docs/cs-manual/make.bat create mode 100644 docs/cs-manual/source/_static/images/chapter-1/add-record.png create mode 100644 docs/cs-manual/source/_static/images/chapter-1/edit-record.png create mode 100644 docs/cs-manual/source/_static/images/chapter-1/new-project.png create mode 100644 docs/cs-manual/source/_static/images/chapter-1/objects.png create mode 100644 docs/cs-manual/source/_static/images/chapter-1/opening-dialogue.png create mode 100644 docs/cs-manual/source/conf.py create mode 100644 docs/cs-manual/source/files-and-directories.rst create mode 100644 docs/cs-manual/source/foreword.rst create mode 100644 docs/cs-manual/source/index.rst create mode 100644 docs/cs-manual/source/starting-dialog.rst create mode 100644 docs/cs-manual/source/tour.rst diff --git a/.gitignore b/.gitignore index e1abcaa63..51b8c1f0f 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ prebuilt ## doxygen Doxygen +!docs/cs-manual/Makefile ## ides/editors *~ diff --git a/AUTHORS.md b/AUTHORS.md index 83a625406..79cb87e64 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -128,6 +128,7 @@ Manual Bodillium Cramal + Alejandro Sanchez (HiPhish) sir_herrbatka Packagers diff --git a/docs/cs-manual/Makefile b/docs/cs-manual/Makefile new file mode 100644 index 000000000..9d62dc5ab --- /dev/null +++ b/docs/cs-manual/Makefile @@ -0,0 +1,216 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = build + +# User-friendly check for sphinx-build +ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) +$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) +endif + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source + +.PHONY: help +help: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " applehelp to make an Apple Help Book" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " texinfo to make Texinfo files" + @echo " info to make Texinfo files and run them through makeinfo" + @echo " gettext to make PO message catalogs" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " xml to make Docutils-native XML files" + @echo " pseudoxml to make pseudoxml-XML files for display purposes" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + @echo " coverage to run coverage check of the documentation (if enabled)" + +.PHONY: clean +clean: + rm -rf $(BUILDDIR)/* + +.PHONY: html +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +.PHONY: dirhtml +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +.PHONY: singlehtml +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +.PHONY: pickle +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +.PHONY: json +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +.PHONY: htmlhelp +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +.PHONY: qthelp +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/OpenMWCSManual.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/OpenMWCSManual.qhc" + +.PHONY: applehelp +applehelp: + $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp + @echo + @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." + @echo "N.B. You won't be able to view it unless you put it in" \ + "~/Library/Documentation/Help or install it in your application" \ + "bundle." + +.PHONY: devhelp +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/OpenMWCSManual" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/OpenMWCSManual" + @echo "# devhelp" + +.PHONY: epub +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +.PHONY: latex +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +.PHONY: latexpdf +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +.PHONY: latexpdfja +latexpdfja: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through platex and dvipdfmx..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +.PHONY: text +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +.PHONY: man +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +.PHONY: texinfo +texinfo: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." + @echo "Run \`make' in that directory to run these through makeinfo" \ + "(use \`make info' here to do that automatically)." + +.PHONY: info +info: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo "Running Texinfo files through makeinfo..." + make -C $(BUILDDIR)/texinfo info + @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." + +.PHONY: gettext +gettext: + $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale + @echo + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." + +.PHONY: changes +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +.PHONY: linkcheck +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +.PHONY: doctest +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." + +.PHONY: coverage +coverage: + $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage + @echo "Testing of coverage in the sources finished, look at the " \ + "results in $(BUILDDIR)/coverage/python.txt." + +.PHONY: xml +xml: + $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml + @echo + @echo "Build finished. The XML files are in $(BUILDDIR)/xml." + +.PHONY: pseudoxml +pseudoxml: + $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml + @echo + @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." diff --git a/docs/cs-manual/make.bat b/docs/cs-manual/make.bat new file mode 100644 index 000000000..744d60007 --- /dev/null +++ b/docs/cs-manual/make.bat @@ -0,0 +1,263 @@ +@ECHO OFF + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set BUILDDIR=build +set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% source +set I18NSPHINXOPTS=%SPHINXOPTS% source +if NOT "%PAPER%" == "" ( + set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% + set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% +) + +if "%1" == "" goto help + +if "%1" == "help" ( + :help + echo.Please use `make ^` where ^ is one of + echo. html to make standalone HTML files + echo. dirhtml to make HTML files named index.html in directories + echo. singlehtml to make a single large HTML file + echo. pickle to make pickle files + echo. json to make JSON files + echo. htmlhelp to make HTML files and a HTML help project + echo. qthelp to make HTML files and a qthelp project + echo. devhelp to make HTML files and a Devhelp project + echo. epub to make an epub + echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter + echo. text to make text files + echo. man to make manual pages + echo. texinfo to make Texinfo files + echo. gettext to make PO message catalogs + echo. changes to make an overview over all changed/added/deprecated items + echo. xml to make Docutils-native XML files + echo. pseudoxml to make pseudoxml-XML files for display purposes + echo. linkcheck to check all external links for integrity + echo. doctest to run all doctests embedded in the documentation if enabled + echo. coverage to run coverage check of the documentation if enabled + goto end +) + +if "%1" == "clean" ( + for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i + del /q /s %BUILDDIR%\* + goto end +) + + +REM Check if sphinx-build is available and fallback to Python version if any +%SPHINXBUILD% 1>NUL 2>NUL +if errorlevel 9009 goto sphinx_python +goto sphinx_ok + +:sphinx_python + +set SPHINXBUILD=python -m sphinx.__init__ +%SPHINXBUILD% 2> nul +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.http://sphinx-doc.org/ + exit /b 1 +) + +:sphinx_ok + + +if "%1" == "html" ( + %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/html. + goto end +) + +if "%1" == "dirhtml" ( + %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. + goto end +) + +if "%1" == "singlehtml" ( + %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. + goto end +) + +if "%1" == "pickle" ( + %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can process the pickle files. + goto end +) + +if "%1" == "json" ( + %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can process the JSON files. + goto end +) + +if "%1" == "htmlhelp" ( + %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can run HTML Help Workshop with the ^ +.hhp project file in %BUILDDIR%/htmlhelp. + goto end +) + +if "%1" == "qthelp" ( + %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can run "qcollectiongenerator" with the ^ +.qhcp project file in %BUILDDIR%/qthelp, like this: + echo.^> qcollectiongenerator %BUILDDIR%\qthelp\OpenMWCSManual.qhcp + echo.To view the help file: + echo.^> assistant -collectionFile %BUILDDIR%\qthelp\OpenMWCSManual.ghc + goto end +) + +if "%1" == "devhelp" ( + %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. + goto end +) + +if "%1" == "epub" ( + %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The epub file is in %BUILDDIR%/epub. + goto end +) + +if "%1" == "latex" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "latexpdf" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + cd %BUILDDIR%/latex + make all-pdf + cd %~dp0 + echo. + echo.Build finished; the PDF files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "latexpdfja" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + cd %BUILDDIR%/latex + make all-pdf-ja + cd %~dp0 + echo. + echo.Build finished; the PDF files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "text" ( + %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The text files are in %BUILDDIR%/text. + goto end +) + +if "%1" == "man" ( + %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The manual pages are in %BUILDDIR%/man. + goto end +) + +if "%1" == "texinfo" ( + %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. + goto end +) + +if "%1" == "gettext" ( + %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The message catalogs are in %BUILDDIR%/locale. + goto end +) + +if "%1" == "changes" ( + %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes + if errorlevel 1 exit /b 1 + echo. + echo.The overview file is in %BUILDDIR%/changes. + goto end +) + +if "%1" == "linkcheck" ( + %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck + if errorlevel 1 exit /b 1 + echo. + echo.Link check complete; look for any errors in the above output ^ +or in %BUILDDIR%/linkcheck/output.txt. + goto end +) + +if "%1" == "doctest" ( + %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest + if errorlevel 1 exit /b 1 + echo. + echo.Testing of doctests in the sources finished, look at the ^ +results in %BUILDDIR%/doctest/output.txt. + goto end +) + +if "%1" == "coverage" ( + %SPHINXBUILD% -b coverage %ALLSPHINXOPTS% %BUILDDIR%/coverage + if errorlevel 1 exit /b 1 + echo. + echo.Testing of coverage in the sources finished, look at the ^ +results in %BUILDDIR%/coverage/python.txt. + goto end +) + +if "%1" == "xml" ( + %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The XML files are in %BUILDDIR%/xml. + goto end +) + +if "%1" == "pseudoxml" ( + %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. + goto end +) + +:end diff --git a/docs/cs-manual/source/_static/images/chapter-1/add-record.png b/docs/cs-manual/source/_static/images/chapter-1/add-record.png new file mode 100644 index 0000000000000000000000000000000000000000..c0a110b7c584bfae3ea9341ba215babc59a48b98 GIT binary patch literal 106549 zcmd3NWmH_vvM3J0HMj(KC%6Q6*Wm69?oMzE?(Po32X}|y5Zv9}ANkI?_a^7v_y5gW zGi&easxI%|(^WfEURDeN76%pt1O!1sTv!nV1e_lP1PlTO>K($K^*sdySE7q%gC;U%qcP zQAk*bzduY!h%c-^Y*-j*Ot$CInq2GIN=u7NJ;2$!s;~%XVgW2G1J!F02nmA?m;^;8 zKoR=E!nW>U=d>ln021A8-C3i;_&q&8X}qFDDA+nGV{NRzT{%6kp%Q$2DnbIi{DL9ez4&q% z{XC8%L^5{A**!n}hy?xga(jRY-M5MN#>n*R=LymiO2p`!tyOW}Dd!9;Qlh_J{(MgT@OeDklY$C8~gGeR~^>ycQ^U!EnZpR z;^a>gSOhQg?8F-YU8XOHO&xqq$4^^(0HfBbXxn7~A%JYXK*WVy$iq&)zR}DVMO!_2_$)rR`1`93k`QJ^Pgwg) zYLI6fhYq2~zSFE4h#H>fGO5py0#yO!t&eJZj35Hj)*x8muZQ2nK=sC<*P#%Y64CE8 zgYR#GA=Cxnl0mrFLHz~b#la!71qqhiJF${ME!RP`{4k09iI5S+i3mso9KS*TtJawdWi6q-RM=|#K{?EX%g4^r}l z>pPPX=;D{k??~t{A_6t?%#K*Y!C~33#fTRE^j~;?((Mzlg7OA_%u(5AsY3|pDb|x_ zv`L1M{#Xb#9h}mGrH92o|U(eEumPB^3s*8|8~Io=!PsbU0HoUy1xVavRVNeD-HE;#L|cHj2UOyLeep89vmkb-Mo%x&% zZ{=^%j#rK+IFRvB@fz?h@YwKNIOaG~IM_Ht)7{eX(`&UD=|9kOSCUq;Xys|)F7qrG zE-NhWEH^gKyQ;fhy9&BWy4swVUou}Fo3i$ytSFoTvp13|Y)F5?JrB6;WR`OMnO_F6eVmNVlaTt7a+uT-T}ZYFugY6f;DXg1~$>d^eq>rfMi8ixr7ABT{wfK7-kjZLjixc<3* z+=9*=&J3;Ys1DQd-qF)h_K0@>@(9)O$VvC`!{Nh0#=J)!LnUFZ&zH9VzjV-{^{}qO zoFM%${SK7n!5PX4v(e_tkmPcIHO54v@U%#rmO_a^kP zE!>pi{u&!PX)!3%+36edDqI(+TB{|G3}1l%I)=?Z=7$8uLZ(V zkXOG4^GtK6MV6H`leqnA`ika4^Je~*;nD{!8($v18nqZ-9j^%|A6FTt?xPi!7Roaf z1g0YH4{QtkU&uhrUA(!EQ6KI;oQ3Lzz(it2Y==sRq=&>t42ON?$hKSG_H&BmJn&>i zKf(553kq#*!j8lU=S6M7Dne7kzT;h`YG?7|`$VjNo!#5D8~{L-L7gD`6dNJ|KJ+|v zFcePpNaa)_UkW%BNY(pl@~cd!Fc@dL<{;+)iFunjjJch_nQu95D8r4?;UMH7CXqIk zR&g%QYV7zIp0KR#xO%05joax2Pe<$1gZ)FnLkncD|C88GbRzx=_eWc+a`}SlU5-Q7 z-ire?AO%kNemH7)Vi;X`i{!oJrDS{NHJ@9Ra!K7S`mOSDNg#9hkFp)Xoq-V-8h>g6 zH5}yz6+4w3RcqBJ6}h?n*}6IV`Q3S&EJQwDCDX6-Dh!Ic?odwTr=v%;vZle~B^j1n z6Lx%W&(T34L4l$z{axgA zt<+P-Gpv2(Bda!A&*nqet%O$k;v>CzcNh7)Zk72mG+q;4@V3-8waOta%l)mhvet3W zwsWXk(cQ?lv`}{T$GpdR8_3nKIOhb(EhqLK7C)VBkE0$kHd@GC07wT&D|mARr!7Tx zReSBfUQSUGVk#AOCTWo33AM15u#en}AI}e)9$nAA&Gkk~tPE*JM-Z%JbjwBZG`RCH zopA78^==JyN34wwPgfUZnQWQ3>>`el>|JF}^3r&X-?Y94-iJ3pCIlXZi-zYhoam0z zp(L%+i7}kD4|~eI0Iw0w(h4yG6WUecW-l5~0lIDB?v1sHH<_ML@r_fFWkFIx6jeh_Z*yZfZR zrLV!QErk<*hk2ugT;B%&hz!!X2L)2BJ!Bbd2U5-2G2i?4k;Cl*lq8F+i)dSPyl-zK z6GpZd<_Cyzu!%@VzoXK&{tG2SF-Ng;agrI7`O*RPK`j<4R!_2LGQI|_M&u&=0s<#I z$4#^CvI);^>!~NiE0G^em;5I}eFqdy1?oxTnzBtu)YaH9McWdwDN`c@Bbl9row;oQ zbvz{$jXBLUHAAUmu}Se_$yJ%p%>MM~to_XHymys@47=`xl5n_ev>AK>d(}pThbTR?WmZXeYs=@Y3(qtD<#_{93FxZ${0_Oz z#d%Fd`ET3u2LVda!!$LNoL&nTyzX#+Ek~9hnda5l@TYImWd}LDt zwl{63PiQ0n!p?pU0_tdP>0Y@xUU$ZNZn}qFC-Ob>`QuBT9+sEAd`tv52Hh}P5xO;3 znU{XU0%NDAjK!~gPxaCLM+jLO9q87KK4p*eKW3W^o48+Ci~wi+n`gcP#HU0o@=#{* z?hr~MU%EG`AgNqR3QJndsLiGiy7x1%;jxU9za^)rQ>t&2w^->e^4ocCKKI@vc*N~N z6Gjk{`J#S<;D;N7y9vj@RHtJATOO`)Fw`tkF!ezwv?&jy+_7#{8LtC&H z*M~jNvXBCAkyl92ML+B>LtQnWP;x-^S2xB{8e%>ws6yjOv`#K4f99zoq-p3gEqpbSScQpFL2JEv z;-0k39m_4J+wNgpk+xB45p4>9a{G+i*6tlwqq~!MCGdQr6rk-=cSg(w<=9~b6B^T9H#dnVu|=1q<5NXMM}l`! zN5f;+rr`ud#l*BOOM8h`r4_~*t5A0|VXx)#1!OyYDQqBhgEdJkaa+*Y`V+ zO%UF&j*#B6v54a43wFx5*JCfub#-`pa zg)e2Xs6TwgLB%0t<*whXo2_?odUUG2roGX)(Z#95F2qW~uEk+UsY@l_jJT+~$FAkN zLWYC9lxEaR0GwEn7}e@~OjOSCjdu+zEZEH-#5lxBrIzKTH7!*>H4SJ?xH32ZywC8n zI0ZWZEDur~$AlQ`*dcI=@Vg&!U>;B(X{{(*NpiV<5K+Gfpi(h$k&*M>ifidSPkuv# zmO_;yOQ29IR4$s!pT#Scs2VEf(~8mX&Sx#-cyg8fVq>FY;{El@=H!B5OyH-17rFb7 zZWtc%O_`3=_58+4CJIqijFmH0Q>Ch93Z)7Bbh<@~RbEgoa~F6Uo~}Jz{iB85yO)V9 znDko57WigqWZ;3rNmPWRXgVZtr%c>{< z?)h%MeY^I^x|p|(K_zL@5q?87zB z^>i5ws;rRWL8%2nca?1@!B~8w+JrHHkqB@UYRD#v=RTxPMaYQI=~g#zr|hL1u9;cr zSs;uLjptSlE@qk`V-;jwshg_<9N6!R90X&5VKYUHNzX~IrA*Xt)EH<0Y72fG*$UwG zq*FBUGzB)VU1{yg?6Pc_Zu*e@BvB_t|70aGE=!y1VF2hWBCV8|6EBeT7&IHY9PHXz z9pYEOQao0$P_dCOQL9j;QR1(RDZwto$Ueyrn4X(5zZ8I59fOz?;I?%*br{*^&w@Xufmxyi&Z3x;glCjAG|a_A2Ek`K7rl zJm;(a&c+%^Mjm~fSzdsFO`lyK1?ecM1?g-)krK)D?$j8wJ4->7va!;(@ZR|D5hg1^ z9)mRBYr|mMeV0VQ)GBkq<*npmsT5mjJ^Rt9}Eg{iQ{}r|zyYqA89=qKCtKb2hJcVBug2`?Uyjk9F^i z-^J&`o5?HGt@)vTJgr7$zR|%F@$Ae~S-t8p;vV((W|BQ}Y+7^hWIdyXFpPiXHHF`M zAS)8j$1NM__zQ?Qm`FC{G9<$%kPAU~WRzh)dco+NEJh~#z%0-f2+eOS-7@PE=The? z--x=Q?Qkw&sRE=$WOGRsIEyjrIDz0jfkQo3O5c=Pdx83dO23r&3hnd0=0@fEnaNHK z|6DDCD=5n87+vp&VfxIx$o!($KDgO4+|AXcI%qS}HC!{eIGiwSJ=QaD6?4a>3))fS z+e##AE3uzw+a}&%7M~p4)ch?mzYe{KRq(N5RA`aLp6#+3_9EtE&VHf&&~J;Rr+-@sV?y-O|LZ6{34o zj_l6(owj!q6)@P1)s@}@?g0Wh)rhG^iD38nG(!n;0Y^R(N7GC(0Ak zDsc{H3^Nt+gF>mvuLsBeh=?BDXb5B8k(!~Ci6m-DPN1eZ58v1Pub!u*4(4+uCzs$D zWh&mY43=JU9hK1>wNCUce)ToY8db)-29CI1PX&kr;~6wJD<*3E*90eM&8r^Mtv=pF z2FTt;p5prVT`%7ijsxJ3DhB2$;0o^v8hK*U%(D_QE#1g3THU@_)Obm_J^Zo^V0TfA zT)VCK&@T7D*f9P$bmDN6)Q3<5U`lgo;Aq@(CU}#7(YQFfHw3|72gwzHT=(S;0prX@ z)PkA~Al5cx7-53H zd(fOn*1%7FMMgqOPpV7<{OY*v1^%4NLU*wYVIiq$0ZZ`~;UpObDgFuh&f=c?loG$i zxWE)+{~L}paBhkx+$fuIPkQ1;0wh8Pf0w{BP@fio8ok!BFfScV(BXW8nG&2 zQeTBdzo=@C3lmiNs`XNB#M3DsEA!3>&Y-bHnP*M|OL&WFD+Wp#O!chxtpnHW}vAHc#D|t6jZJvnBHnEoDH>(kFbmuM9|M;SlRb(pGmxurME5 z32CwIX|JW4G<)^pyZs)`c9UBv z$`)Mr2=}DNsAc39PG_3a&ui<0E6Mr|9vLL$d0U22NLkWNvg2}Y{5syK%va{0?Fe3J z-ylx}S2yQkmo5wDf8vfL#LhOmJX`vmY4UlhCp~P-Rr29rkr2S%n23#@m7bB950;3Ch{xW@giBFa^xx#~cf7=Aj*hlm3=A$V zF7z%e^Z0l( zt8V~sa^xi@{>|vWKmU@`(cI*JIN3P-Tdj8m8Ges2FwrwI{BLB&uIB#_vfm^BPckFJ z|JKUZ$=>Q8os0|_jIE5Vjcptq-szbBS9b5V{cpm*gml%n{TH);jQB6zcz#RHrD*H` zuyXos0u>u`M?Pkre-!#p@c&rkUsOT>Yg>C`2ZwhuKDK|8{0aL{eD(if!^i$#JpKg! zCxM*3`Mak2zvbd%`Zt3=VgHG*@xL+n6Zi+gZ_{(ho4XoYsSBIG8}uJ7I9T4<{I4Vb zNht)d0@y3r>KhvWmh2yrKS2M9{SP0F|KY>N^!ZOde~kP=X=KRd;ACK7Z0Puhzuvv} zPxLDp+cEqB=3)3>v3cHOflCHpWNzXntnX;d$IQs|nTwH`i;HU|Pi~U{r|G@b} zg5M)T_Qv{-0DENsz>4o5HLQQ%60y8z5t6%SK9sqea~Ay*muhR zS_AlC!>9A}K|lmRB!s^xyMi8PKzpi)+z$AB;w43fp>r&N5M&9u?Pq76Kh>1i|BTY5Z&y)K2k}9hzuSNeL7tGFviKogd zro{p?&WVP+*+{bgOYPy$eu~!c38FpOthXgrK9B`>e;GtAT%d$GNHRP}KK4l=cFDWG z{hMOdAM7Qm{bH@8aNA-o!!(S{4pkT3 znm&x{lE*Ao;ZH097*~O8O8EHP;+}v?_d>;3@`u3Lxo+zDS`=iuzx^fe2mw2yPE~FX z7cVW5e2?jf3kT%6@Un(QPY|m4kXTw&hv|20aA06SJH_-C}{Jw?v zkaAU7pOa@50W%L%Hul)En(;#6{tj<$FgG>=p0T|Wg2oA4?KXb5v7)4yz4O`3y1jaD zxl4?A#GadcS^!i|_Q+MC%_PR3NkK^f0s9O2ypBii8dh>3td7E1b7!RS*h04ZO0ki` zZTX-{N{NwoawxoVn56v=>%2$VAQC7b0$R>-*T{p>DC-hB-1yv_arN)GWs`$+ z+6Po?nqCPEa^4DZ{cR--?Ak5Y-HAupCx=r`tsmaQWp#!Q_?PPfg|f3L?la>}iu6JSY~&V`bXdnf|1lF~ z8AO-?*qH>rGuP^1g=2*g&z$q+@>Dq=#p&>msk^VL%4imVL%Sl&1XXlqC`*-SM4m=R zZT9!6%4s^R6aJd20s_|SN2T9L1$~Pnjhn)t@^r^uR`UX1d4Mc5dD>*4k0+^ywLesBTY6ubrb#o&-Ar8tpb(-s8y1Ou6nqltl(B z$ns^6^XAs3Y39Z*DljF$Qw`3w9#7Luze;gZ)@Ux+5s{nNQfOkN*v?Emk)5C(qn+Mz zPX@J3kHq)k0y}^ignx>iFjsvfb>?*7qEH`FhH^2N9LUI8dp;dbWc@Qs{K|wnGrp`# zgfH(jO0tZUZ_-NTkt9T+bH%dsSix%?#4XsKP8~bOr+Ybg^U5H3loss`v1zHtS<8*o zPuIq#8J})aM`i2Kh%+w07=VXl*!b@2JEW>C%kIjKn*&+qONw@=$|Jt<7(2%eP1{#o^TZr* zIqMttQSk7zP7(S%*Dx|NRFKQ{=F^2p zT1~baJoWKv0r8-{2=f#Z&ib_k1B(ZbvZ3|T1qbaaI=m}K)ixZi8H?lrMaEwbcF0+Z zj_e$g8ygbV8UbtZVHh;GIiU6Cl_7t}fWRWT032jUbad8QwSLbh;Z0`zRx(+3zTboKZ=^$0Ng+-j-6BD6yfjv7%nm>!$6%plu|2AnsCdfpR+p0AF&fYfK0b|v3@dG<9 ziF`hymE@cTd8wn?L+ zQY!~T+RbkQizMG;Vi4c#lWKh4=*wRx&dl&;!6H)|1YM22ujSJJ+qT(g>uxN44-7`aj8<#JwW<_MUA0!s=(_GqDVp;Pn&Vcfp>;#=EHlB?>r^@?fBjM zi_$6jH-SL*%E0U|r-q-}gODcZm( z6~3dA>QhrV52O3zD3L>oTIAcU=#U8haIX4NZ0KN(e)EI;trDr|wZJ-FC6tfs&}<`w z!YhxT`n&WK?Qo7<51lEFdm~7cn9eRSIpjC6{14Tb5fN)6rq#uMdrB6p#3;h*ZA}qx zwGs2IodqsW#|wPyYu~!ovYnN7BaEGC)Mf{+PftHvhp$tlwcSB$J!g^O*82JFo54zd z&|f!Q-p`t9m1`c;NbNIWABF9ws8I*F^4z@F_q1vyVnE#P75xv zx}@hoz1lr@)Z^kh^LDY;7@l%9ISX501u*p2V#;Qzu7l; z=rz2JlL?^ZHM_gA$dhj6839~E8Kh9}OebQ|=}t0&FmsbCHc zG?r?cSC00i3!K&ZmfqaKZ@OJE!L#^dFGiZ!YlgUJ zwP{#a`+Ncv1LMfko4!Djjn-7BD( zc{v3eQ;#Fa>#vwLPq74Z+U#BPsB*b`luz--8h3EH#TRtOD?=;$xi3?f8)e>?=OH#$ zH8_`R2cHW;J7DpN=DDKwRDqPMcl`{d(C%nyDZBmpcu=HD%;Tk*xY0uh$+ut^K8ST$ zg&cOSw1g}N+&NqYkS@MxI@pjo-@nEf-&ZpwXy`yC>?w^y@6afBMs4$V0`HVvbThSi zi7~+n0tGBAV59JU`3D&Ne0IBrH?V0!QKQ!t_$rCVcYkhZwfqeI_@%aaq z1AmrCRi~WD+rX;{5o6Uy2OcUujEPoG{EW&RT%2wC=VpXF9e0eYq_eJ{1Y?uHc_lL$ zdj}n%X5_bmLeft>yZX!Sh7Nfj+q@Bj+ouOlJ^+{vhK5*iQ+lW3Ao#HKyX7`}-1L-ueCYp8;7U7v(Ah)#6X zNbzd*tA9PzpnbfcJjH(m8-9Xv@11J&bmC#NF^b~TtZ!BxTqq`+^Mt@L?A*$xr=96p zo|1xuIQaIytcZvUjO8r4?A;6Za;fs|DVgt9tE3x?Y=(8;*MONO9@xF7oZDt?)KN8% zyCiPM)N?pEh(pAaX|j?cMUXlY9)7A>0C?cCQerxRvio}!l3UHQiMAc3j9#%7tPdAq z$d`%`C*mqU{8yWOd=A__c2=jY1tELn<>c5jt!W)w52G)bkYM#rH~F&mte2Zc3K=Pc zB!yq^NRsVkFG0C3e)#&jo^r7|iarMQ=GvNf#EM6hLBCkmdJwJ+BbU#b7n0ug`JO_H zC}pWil>{JQD`E4v#m}wJe}d$2Jwl%??`MrOk%2^JVq(M^-y=Vs4G(g(6ELwG&92x2 zm$dQ$j3#n67kK}aAJdfM{Y}BN`#`;w-2$&cM?BESl?L8BpKN!0B_NcrHH6x4F{?#F zuEW26ZLG&b_t{_@!Ey@QP!}hJYh&kp3wOeB+~=VPOLgn@smSntJEf_{Mnow3&8|hM z#A`P9aBI78;`{}8bS|(24AQy@^jaPM?7o}j>Y>HZ!(l(q=M&I_{S34vZ+~+SRZvR` z4%(dbSR%UF7yWwUw)7prZM&-JCDhJ!^VW={@-=WC5CwIRRBiF3Fw7#9Og{awRc;mgsPu~A?hPTDcLA}B&%A%( zv;rsKTUL876ix?qBai>ZiviGWe6H>l$sG1H3u;CwmR6X;6AKA>V6uK)zc+kjS4Y9t*2H4peaNLF z%a;Pk*$!L1nvx#pC6UCt6#gi!oX|IH4zkM51~E!s5F0ujS;}fc>SCkj4p%6pMrw=> z&nF?GL@rO$bo)H^u?Crv4Prcdc$aTX42keQ*)dxzf8wAD@HGO{w(8;QO$zbQo`9${HS#~iu7CVhTdv0DhCPrkiqYqB?^)5$#N zI%IvpVxP5LR~7}MCo95nYT81VH2mQ+KOrzCcJUglWal`d*vhu0;(oM7VI~t4cRHmw zp?`_Suz^I7+gd2I%iGnuC%}Sso+7?=*<`V?kqtlni z<`=E=%rBjK#l1?17s-X~f$Tv`z=kVAbbHq~GtRr>hHZVYy z>*VqBRVkwcexi9lf|M5Gn?MSY-e^uq(eYIvgM;AlVaxl9>p-p&#d%EqbHrCCGf5-k z2wBJUk~jeSqv@=1bD#>4TUTz&wn0dn^w^W((V+NOLf&>?8_%rlMXel2pxD7iOlD#f z%K&|M%%K1$@C&lf2Kp;c9XP1p^QhFgchIzhtJBe(=$Jd*KAmk$WoW@`3QQ$I2=-Y= z6#J?xc-(5%w>?64R7;l9%~NLttw&iQO7NlUP2W_PHs4I^)NIKcpsU`w-qZs)W+jL1 z!9Bt85KPy-UBG0vi3)4PfxnB+Cz6l|SfJ7tb@*0ECsEZpvCD)(U|FelJa!a~d+bu!K&+v2;R+ugMt z`;~#2^;OjU(XLod2M+`L&MTAQ4L>Vhwm3YWg?>^3OB7Tif7Q!>>RnT*q|SQj$9G>J z-l(#p!RxE$YpRSF}vy;y$v!2GQ@m3Vz>;Rf1Ux&c!` z-pn69&B)qV+8mrdq9$z*8tr3aX2g7}^^pqlI0Ti~}eQ0@b2hZS$6T=TwW|Kf(8|$waPjhb}_1A6q4_&xsSOfx( z*QrNVnlV!fWs1dR>F8f4nc9=`<2JU$HY6#NN+!0DQDv)E3avFu;n_Z$U&}vXOqF3P ztfpk46?>`F0bMoIIJ1Vc>a`gHRkcd>7xI(L%Vsr`JAQBq(m1r#UY1r6zTe_P7Ey7Qs)c_&4`5h*EAC$vF`f{$Jnkv1U6l7J?9$N9gwTK}Ow0{7s zhrX`ih&b+FyuSr;gby?MD-*Yfm9(c(Q0SMaD0dVUA#y|^hNt$+{8C~}mpu;Qud3sj zf{RZ9RJ<>wmH8Y4Otig2QCAO7f!WTEGD$Y27aGOl4=>0oH=jo{U-^6MCprtSKi}&u zXuG~HLUORJubrb=ho@JtgX8CxcpI1z_}EO7&E9EEv6vN1RWc+g z;lbpcq-NR=&2fajANtFGggF;h;=krAnb;S(Vum4{4RfK`6DO~^%MZB`CRaSjevo|dGj__;`zEzvUM}W>|v`wMg3^s>B z0Wr+wcbS7BUm)srj~^kVxQU^~Ay(yBcs7pnh+pM6VBE^(3}IvAf>tW5oI9@%AnMse z(V8wMdj=CkCiF=;zqq4qk!s%;SaLqG)oz0|o7}`X*5<+@^lC<&)@hm*Oss^3>3QotHNk53dCjbFJLFWl9^oQ4 z9w9+wa2mJHjxqX5(+EV}hli9YVG^ytZ;j{BxQq+zq@iGTMCzEf&Hs)Kkdnlj&obSL z4CF-gdDv4DNj76Uv_f%pA6l@vWvzPJ!-FFmfi*R86>iG6JK>m7|gt>p5(!NWqsIgh`i4pBsskPpcoC&q?gVj&4d-Gz?^ArFZ&uH;IueNu!Kc6;R zs6&v=%$?QkostB^#G~rJ8yTR$i;ltz*`x3bak|qAZn)M$$}%lSq!&vH zR&IluyzYFf_CsT|*d(#VTMA(>x+oRZPRcAhwbwUua4;VAyrG+M^T4Y7^kh18e8G{T zgNsngp%!rcL;HalymUn}xG%DW=iAd;EtKvg90Z=kcmjOFcss?3A@5D;5uVe}F=8Du zPS<+~>Y2)*%Q{Je9gAsae(5|@ZA8$jRxwh)qqh)yvtat zJzapkmwx>|N+r3Lh5-NTw3FYX)0Pv)#fQi@Hb95qR#sFM#T#K{M=gJI0km4}nN)qY zeN(zd)Fd<34oWEZd+=P0AS_&{vg=&v_XIl$yze<`i&e0v zp-o8qygmd~UT2GeS@jimtj%ZCcr_j}g1G2Qb?O>Kk z41)E)FwXBLt9s_=F@2uTFlSo&ks>wgipb(g-7|YJKkd{Kc(VHhbDWAnKT%g$Tp_v= zS@0FgJbV~iJC*<>IJCq2O=nakjZfWN?3wCXbCKFAxkcWCkQ^tU^! zu35NTkh+dQ%<@iuc%e?bYVyLqE?4?Kb|vy@7H6}vSiY6z5|Z`ph%%!2jjK(fvRYSN z`#RrL^CMmpN~Fa%EGGxzMzNahBoZF(FnB^{W0ef+Yeg_6R&ls z-TcC*QPYsS-xvAYagv)!d$Ya_KPZXks=0`Lo9SIBsWRBC&AV9M(#3U}vwUOJ@d462 ze*x@G_otwZJ+m-BujB4|-iB#3Hn;J5-`^AAOzuS=Rm}eYf3UQZ8gUgd>#R%dfbn>nQmunU!dHagly z&s|4e8w^!u8r`J#H|iQ=FS2X;6uh2pPtte~wY2a&KU)W#-D(eVI1UbODs}KpeHA7N zQ1wJc*-&7jFW6=|=WYDBL;o6`XmZQl_Z%S?c=WxWhR-jBzxZ%?oew$59SWDeqVIO( zt;dhl)a@N1{Bqt;EtvSZjb_5jI+hwjlF!dEb+r9ySGZjB3K!^X8G@KWAUM6NZF|v; z?f&qEkyi{8>Q#n_|8WxM>Zk&)?9O~>ull)YO`*t|LRcgSXBO}44QG(dVzkdVu64^x zc$Vb`n}IHK{{6P9I(^j%P5CXyNP(L3G#to&7uo%iRkYF#CTWp!0Ow1kEWJ}H@M_ES zXLQmO2~WdTnx^JuT4q**l+Js$N)q~gr2G1_7qe)8y{*&pL4QjGAKfvq!pI#6+j4co z>aajP&b*R>K*Kx6Tn-OCBFrx6@=!kIm;y_aRkl$brunezh%xWvlw$L2Wj~E1feI#= zjgGc1v5}ND)}Q!RDK<^+G+E&Ra0eA+dtAw~b@wEG0vw`421P^|d0s^qU65IGA5G<9 z(w}IDMWQ!6%B1I-MK?!nuJSo}ko~*f2`T3rLHN32!@VVjjXQjs$7l9X6b5Ey@v9cquTn>dhOIZ)9pS@?9?onDA&Qx1F7K61YZbSk@= z->^SPr2PHB^YueDN_=drbdlVzMA0$|?^jTxXY^g1Fy5i-_>l!dDFElw6{&STtl*aF ze2zZdFGWphExY&ESi4Ba{%MYg{|Z*|wH_G5wKsmR00sTD8_-OdqM|b(ARxgm#}SxvW5NO7${i@opt9DaBZqgO|Gu&JF^jOGy19QZm70G)2tKY=3W~YRP~7vONs)9(Ds+VJU{v#t|B|O>_I?!U zkh}$yW(e+~UKv({`aaR@us8bfcb5avdp&^-l&x|1ffbj}`O1zvKxkf#i?$Zl0q&YL zs}K?P1g&gB_m8ZC6YmRrhZjZcF;^O;rX$z&dET z08#QrRMZO`w035VC8MXyx2fCYpZ%G=l?RkbZkh;G4}cQ~CirAZ?FsFY(_U8s3AN1L z&S$HUH%Ie^OAXc>@ecuo@7H1@iFA_<)|#y5Q^HjfpS9$77F3Bo{8cFy%r^V5oh+wx z(+ZZ4H__%)gv*$jfAHweiMRVqt&Nm6&5=oAYNKZpsD7|Vu5_T`;(31*{b$LBFQ`ZZAx{B zzuB)-qhvRq>lRzwj7Gb!4jk9|bqB|mHDye+DVV>Xs7-sld*ZkW@7VeY+bUC z&-{JN_(w8iW1%ok)HIu0=u~=Yn-~{YXKGYlQa5W1;Hf!LdPOa9IxIT7pZDG?1TKEu z6!CBQp^WpiTOE7Ar&cyFroZ~Q>%MC`T__V09xfCJixFXM9RP*UeX%ugG0uHv%jtSh zkR)GgB4gMW+}Kw`zi0k4+b^c_^NFg@rpj{jVrEiv|A(RJ4pNrt^wy8AgLY5)o*~%mgxSM zR^R2o`teeStYT7ZCYG9> zOAdS~X5Z!ZWIg91&HNQnLjrdGQ>dbrS08Te(rmsAfB30zx_OaXZ>Z+#eE5ugz0FTy z)fnCScL4padt1|IEP5r@80uoP;IY3KUu6$cdZ@>}zhLudB@WPc^hbkj*ahaBjT=TC z8QZ0D#cLhVG^?c3sgh`8Gf>E7vSwaf+}*J^@$CBqUS3gR@nJheUs7w0xy^;1wPB? zxf&llHHjVQ;}bpZTHMF0?zu$ZNJ;{&9(pJC8iBM|F>o>=-IK?OH*vi)tGV9^jJ)y?$&@-wttsB#^)#Z)Zqy(U?u_kQ88<@r*Z4K=8C76S0o85 z>x_Dg0wfJT56`mrUJ`ya{hrE0LX-|7E?+d?W3eQ&r!j<`@T{qdY=bl^3fOz##gl=B z+AR>W;R)ph)Q;D5O=3OEqc>!>e!K1R#DBraaiQ;t%0cw>>^Z@jH^W|SKVkm-2E^7@ zoVMH97i9L_tZ}uZwaEJFuiDt*Ta533a=At0YGAEdzI;KBXW5@Sl98o<)lN}!SsQ?L z>p|mr-AxD6UWY)UyATnmd6y%xJmGqVn@Sv7aygqt!>@YMWI76oXtwjouYOf_`sBvWwu^pT*O#05E`aBjXS&$V`)2OWDJwDl)=Jzv@ocN@ zyt6$@hWby$Vt*3Yo3B0x@up;1YH0XLz0uFf!poZ?5Fy&pP=8=fv>xLYa54C+R(#@| z9pu98W_=hywT#}9^cu3lA$P=nbTN=+*Ytd+%VafaGy{_@CAepIZIEUZPw`@(qZ~`P za({X8#l2ZT$Y(0J_M*3>8VtdDX>RSutg;tMYUT^ z_SD*aRi(N!{YWl4ocOu1HC5Zd%Gflog1pOO$N$6HJBC-bZC#@k+f}hsNh-E&Cl%Ya zZQHhOvtrwJDp|3ux@(_v-uvx+-tW1;?!U|@Yt7kLAAO9`M(eHj`Rz%57_O&1TGuWv zAt6AeS_3Nt$yWYsr-u*Fm&M^2MPrrKVl;+202Jp?_T&ryxpzpKJa4=ih&eL=8?C?< z68O(^iTxeA!*u_Ab0OmnSSEt)<#>PW^8kvCEW6wwd6H<`Gbu={nE!x)dc%2PoTu#`128L;?=BFTI3(6+chY#x%9h7SnHAery zZ9L0oD|Rcpvdi!RC1cTtlvQ3pP-3|A(9&u$m7xzjPz+a0zrWnsUv6?xYj-TVk%g}D z-3+1~uQylfKVP@B0o7CfcWKcCzi?S|?yYS$F;nWfJnnyNCL8`3fd*FFu~pi z_v0CK4TlDG%8oLls^LEUv5sSRG9Zb(k+5j%4X@8WFOPkq!T7x2K`31=MFEBYIkao{ zc9TYx-ZXgT>{|>aDXxGSavFgpm6gIJYqtIEcB(nc$qT#lS6nupxTvL0NTRS7Cf%Z3 zLh<4*_Im8ZqmhGjjMoC~w~#d7g;4hFXUvLgIm5_*OJG1&8t;Mxrz+DUU>oNO`Xy_O za8*SSLf7hRE+N>x5uAW~y}jBBODIPTfuwF~yNb{0a&;td z5@6Zt9i$>(XRfXy!4-Cf{$8|wyM{x0R>xaDJpL_F3QBDBOLG|M<7v`sNC=v?~?q|g9H zDxE-B#~k6vLbN&`Nv_596$myFB&H<%thz5UKj=0@_Wun+2shp}rYe)=3-+VJ2gb$g z;Q%3uGp5VVsV2)0?9;(VN1G?d{{}>enn1*FWqoS@AM#8h_G)iwwZ(cP_IKxI28(5# z%Y{Z3kLU7(AgJu`3v(}}as>#s9WN%E_Cs`4{7Qa-WJBea(SPrS!Th($k>W11v2v== zAh~Ugoy;A5zv*qr>fguvd=E-;xUMH!_QEEWqziF=BKGiuXD~KqF=`~GD+g+CQzO9q zdp_g)r_g9_%lzV%fa3E@7lqovR)E6cqMYmo;-rYmI%Tcm_>O$r7^?QmPB_Pm%QkLJ zRW&NUmTwuTlcI4HYsTN}wXnpFfRKulHg{*UgiB{`4+HP|>fsu_Iq@D9T%`s}9qpmE zI<`b61DlHX$jbu@m$uAd@=)?$hmfBs(BR;qSad9TP|jMdNR6+$)6ZKhfR|_36yHax z9QQw1i?dD>b5{)zKV=un@u^#B6{)t!Y*Rvl{_TPUKTCX>Uu>aEgBoKTHKACTBgsHf zUwu^eJXGrK>w9&v~ihdC!b^cjddX+F(3^bje9>{!jeI z56uoUI5@Z|M5OZ~Q6Qvy$Pl{bH)jmwq_$KYTzQRIZW|D}8fzye^<&OtfiSsVOSqZFY;q1z6j?!?tfJ?m zkImQ4lE5`2`!b#8y;)Uyt1+f+j>qZr^DyH7awqOq7p|TXr#ni-v$K%s3W2dH`$nx| zjE)&w5h`c^;!mB4R?0-<*FIyQY?Hm#S&H|swe$bzb$_bBqyZK^veJ)%tWb9HWR)RC z>x3nFE7gdC4)U;^KXZ_Vsd7vL#m**7W7ff`p0;BLN6+9t#hyTsHgVq3jD>9VzT^Nd z+eGzzwGm}5n@{%y1@ys4CM2MwlC#KbSykVax3t_zIW$?i_}|#>Z$9Cd1yyl0BUQY+ z*z}@Zs!D7usU)NTp0PpdPD^r1LZ>85_uXse4NsEjF>ZIf!8pLOh@AFFf!npz1WZ;;pzigjsChw`J zd>xM6fHWf0a9*T7Xj3m4Up}Nfm(@K)`!99?+MgQq6&JWga3~|0nsXf?aTRiW71#W zRCnhMHfiIePcE6bRnIoU_~%S6&hcB~*2qnrGW%koTRu>;WLE^CZwntj_s^r6z58Fad179_)C`jk7Z&R{QPL;^62+6={K;G zC03tvy^J}x3e#zF`~Mzm*j&HTJ7>8E*y178jpsdCci3Lp8QDvjwO~+H*niYcAcK-d z@#`EdU)~;XJt@h}DCX(+fYMZ7!#P4p7uVOu^xMWS?lSmSYqpv!OpT6?qNj%a!z=($ z^u2h$l3uD@sgh&rQd@pBUjcfkdAQ$%%2ZAzI~*He1+gS~RNbwNMNDM?n$6`(yN_MW z`8R`;d_aLGeYy%+4=yNEZ zci3bXd*A{Yij~sZ+qI0b<%=?q;r6cs|ww0tvg+X7ltyf-92C4 zsWZ4T1}_UybdZ#EZ|Zqc(bBs9ZsWs?KY{2QtK!p1-=+e!*>y?}DU1;)YkU+mEM>zq=r@X?u*YB9|BvDuC^1R7%a>AcT^g5 z`tu^eno{fbgUI z^GjfUO%vh=x!%^?chxN@)hW@LNiP%>o|`#aD5iyk>j7~MfA=#m_>0~{m);|A!jof4 z5}jWj&caTZ5fD8Dq#qGAw^g7jk23u=?#Hvf_+{c#q=tL5h{ybuBAvr74C~ysv5E&~ zEiQ<|NS)K1ccd2ukMKiX!36AYt9vBX+%T{pe-B7OP!ZNET56Z#zGr!>MZF)oV|Ry8 zua-!Q?6SMP7I}=R$LwLg%$;~wkg-Gi%9b~0oAqfo?-y<^`3qs{Pbx_Fc%2}%Guk25 znLa~!P&*<|DvD9oCNP?&g%7`kaX!=N+|s+GH7ru>5nE9U;Cr zpPkpp!(i6~<*P4;&d2HYJB^iA%3j@kjypGDal}ODY8Kk~=~%@jB@0OWW276YSwK3` zP1(Ht_?^6O&?Yf)5#V$DjTdt_&O(UwSFD-}Tv)TZzF4wV_eWu%G1Lit_2C^eF5ZVP z=HqiC;Z>`{oG{rmTtG+pM>$r~Pf!b;>UY%j=qeLU8bqVwl$)QuEWNWRat4mkdVVcY z*;&7kE6oo!0z5N_^k)ER0$xX--h>)rsKdwpX0R zLvxYK1rHsHRvUUFbh%$H$PYdMS0I@x(Yd|^1XfyMzBN2Sdw3Znq&Y#g)Wg3)*s$Eu zT)czU!iM+d#12aAP@65HWEv6kA9|TYJ*IsZb-Kb;nzt7dhUZz^0DFMi@FqRCi{Y>u zU97pW=vm5+`uK)RF$>fCGt9?PU1Zsd?#K50=e@0=RhMJX4sF0Bx64|nTU&A$wSW+X zz~6=++TTEuKZ?K=Oh{DxNwXtgb>b(k`U{L`++~!E?!hv)kND{3+j6V(uXEC-Qe||H z_%9oD+Sm=n2`BwHg_>-vl(f5{BAv6{x>5Si?23W29h$D^9zHm<@U}K#>!FPxg<4-A zY6R+7HR5G#2-m!d^={F|%&;PxcODCsDH}ANIr8)D>?|iOc|C@ecmyvtf0DN?YX?vCp2sTj!M!n@_4!D>^%K zAq%9Oc7!LnYhlUF#_TchrWZ6m; zgN++KHVOKb@O)x5BLX2*%ZDig{jR=_-uQ_^d(E?z$#5_jm$=E(BvK}+ewjMyW=B^R z3nr@0*Y#xaki@~5v+rr4T{pB~?VJ%?Ea{PH}bZcO^ zia6XqB^GbDM`*&g2Cv;AJ#21aTzz)=MTIZ66;M4e)<|COzQ={x73b3NV1qzq$=uY3 z(6na5VngtX;*!lBS*VF&V5ht7q*^zv_Tqj=RmJ6&pi*0wJ(qr=)rN&Jdc5{iZIyNNCJ^Q3EyTHVq%S~GX>_oc1DF<waKwAEuXQS8Zqj?% z5xdXfb$P#@#yH4qNcl0axnB=f2j6yPc3xdQ;z6u;aHQ#6Mkg7b19fkpYfa*1MyHhA znG%QoLoWPJG!3Qrk=xqT&CeMF6AFg9c<=(j$um@PK(f5P7I9f#UzcW*@!N_w;$0`W z#jNe-Bx%o2JX;9IX9yytkLMVb%)p%%(aInB`J1?jg{Jli&+fS6mhnqPlkz^Ez$Rko zBELljH(ttg_|`9v)VZpufZ0GQPS;DT>>mpMW5Hjr$DbQbt=o%3quC-E@J>nc5hSGx zn_Cpv%2#ZRe}c|C;lvTj#Ar+@GvvI3d&Ev~uJqRdDL<~<@S6*{qWSU}WQ`Jxn=s*z z#ajtHl3HD4ED@LD=a+Z}{dOnA#K8MIL+{n3jLI|wt_|7W8Jb`JCmR0^MEUCpd#T9( zLpA(8%>V>=n0&=PVa0*}fM&o8dJx-3Ef@x(I9t#z0_FB7_~vXyiNSy1!|No!SR_7l zx@jCxgLgL}DW^M;JVN~b301J~jsMuQ)5!=ow#V$z}MXav6Ev=iUE4O2Ade1v>0T(Pdb}gA)87P8??jVet9C|A<{xmyT0)ASr*Z zIP+CR>YwQQt0O3oo;G8!)t_UPiy}a~B9qC;Q!JGwD;NGRZ_J^!x!n-=4-D)b92nxN z(Cjk1U}0g^{FX|k)&F>XsA&Vw0=gw$F5thMB>;|!hGq}Us1A;d;8dF&lmWp6G%PHo zz^^t=nPgL+8bsIfB_YsK+3eeⅈ5eeooA9Vm;2*?4 zyEI64kg$Nouz9;0j=x8Nskj(ih=!zpmyOOzKuWtX>IdKb<%I`@s04O7w13lyo+suB{20HDU4ve^HM33aSo{%Z}pt1>o+?x%VZ7dd&|! z`B=O+7YcD#nwb0}h7{*hi30x>h8@`xlmnxiXOh-Jm>-8=Pks{G?e-<*hRP(6Y-%jo zZ@^9Vzza0{`EGx5CB7?($UTT33uvia{pXkOdM2&N(i{B?hv1V~UjyRestPya%)^|g ziXxrGqK5If-H^S$TBf!^c!%8#elwMxk{)ao3iHn8P#=zz7~u4PX*9qeT$W-E@az$r z$(hlswV&b&Gfx6q4+6kh1f~=E`+1hcqy`Bx~<0Xt|=fW-V-N=r6KTXH4^u~?xD*IXfz_YlWHuWRmL zY5RB<_N(P!65XrQsB{yzQ7nmsRG&QiNpohB2t(k61n3S1f`#9W{ICkqDkWABId2w) zHx>h{G*WXeGxUQ>I5A+PznA~q9!~U$*}LX1_QL#m=j|kNFu>9|a5U(`Mv(JF35vkO zA?zi9j&?`EI9MhkOS>h*AF4{8Q$urw_{a<wKnevx(LINsle;2uuLu2{CuC zH|#uf+p2ToO@ufN^+b4yrm*mG4$YDwk+7z$xA?+|DhAyA+UOyukHi-x)t2uk1MR$? zxoR~^%vR$;dS8-gOG=Q*u^b$jX?^uM)X)KnDS~9>(rwoVO?8yVsgo*aZ|K)J1#IyEV7KzZ9qrSku@9h{k7LfHW~M|1_hsS3+k(e8 zf;EW+=@ZG`VYo~WlCjbghX=vZSj(JE*0$(@TdQC5odlq3umi)nRCWgtm*77J`Be49&n6wk&IHt?xj>I;vAXfL zp@fFv*?8Z!O6FJuwZ(ocU1lX>auJ}g#Sll!m!-J-FjB_*>L80Z{Te1vV?d~0nhqAY z+V^8nwu@Q1b|s%5uW-Z-omnFUP|$^86jxyKiAZ$vpE}flazs`HLXkTUUWJ;um!)xe z4~ZdR^qAajoy1^1YB5*eSGlsz)T1$lT#OW*G(p-eyQ?1043XHc)Dc##`eK(p)d~!j zruL*_TGmqPd-4(NNU-S7vh2Pt&`Kk|>t%c|76PdP+MsF!XElaTBZ?Pe& zFYlGtXk{uTwfd(qtknDJ-C{Zj4d?oRc(*%kU6e2LDa*L79krDJ2^T+%tMq0|o;*|k zFqDw>lDHl#O#WBqf$RFbAs4>6s-4>*aTU^e?CQYCwOZueAt2_H(;|rJU z0_@4&w^g2N^vTt7>e+Y!(1vy??6Zod%1rH6kAx&l2uTCyCokM-hzNv7pN4pSG!RH^X!ZnZ`+ zsX-daSRGJ%R)gaQMqBC@2b8=w@|&$rBYrgANJ#)4!+saZHDF)$7#ryTo1oQ~0`<6) z;qZxR`V5T}UbB(F-pM-yhXHm9YO?gM%dx8D6EzAcc4+T9<0S2Mk?FZMtE3A|S9smv z{VU3GgI2W0gFL(&L>YVS=U^dm2a-p23wf764dU+Pt=x@BtbSW9%~n2BiZ5!t*R(V@ z?~{8|IJ}6N5xma(sXg_2Q>@B2l?C+N5r!%`93|N5AeUG^xQs`0P3bJx5ur*Y;cu^% zYSpL#(Z>1GoZ)Xb2p1?8B4;8ylj(t^oiE`z$?kDh&Qy@hL!s^`45P-7TSNRmiTIRu_M3 zR6}-|#CxPaMQ$2po!Q?%Suj%^^WnzrZc>bon)HP~iQ!Z>A6Wm~942RT$v=L1bWG!L z=a4zTQ)6_e%z5*41-J|uy(V9b^oaRl=kCsOx;?K^^kVq_?7SFZZe5pD;`D8*Y#Pp^ zC}cP}yov_2s>pf5@|Yk9Za{a~_Ga5h?|p>9BZwMF6U?eYWx8bB-Mz>TUcDE)L92aC zaeF;1u+EAF*nplNq7Jo_^cptYqT2i5N}2C(ah+;sNx=pXNxamQ=<+j3`r~SZ%-an?MB+fjG-xnP?pZl5FVvY?^nihSbQNa^j+e@9v7< zd)U*~nK8-EYWa^?tn%UaH4k=KOlD)^ZTZ!p?njUSac;yxS(|mD%SH_TFC7L;(u$yD z*USS8a*gVHwXqr(uEx_?u@}f}hRgiqw1)>+>O7cBvy5F87BX_W_HO`EPBFKFIF_X5*^7cLk&reZL!gc6_Dcy$m4yqh~mevs-G9 zAdcfeOk%;&N-M&e#)WweA2Xu2xpi&bXyCOaQt zrZS{}$(9k=a{0J^t|5Bfdm2jPX2KS_${)KWWrSZ-kJ5L4?KtPazk0m8co$z3)m|sV z!cs@_)$aI8u%o{7L*esKmM~grJz7in>`URS?K|lC472ZaRa%&ayqun#1Li5Km6cad zgCyLj)_2JX?mG@uzIN(EBdxD6NM1gjfLwCqwJN+j6k7ioMeug0UxiW^$@p? z)oZoj1q9GiIME@>bb*@)yuSu7@SFn|Y?ejW98nr%#*!AHS}RGgv9(ii-h2V)xX3I~I6`je}}^ZF82 ze#}q=)_=xYnw(SqJn0tGCon@lTY=)tdA6QBA++NYZ?+vTTbxRn|6$#lf9Fi}e3)1) z4quQQbDWY#3PsKE7?2C(%VY~SJW1U*aIi?>hp#l?H94^rJ-hX|xzMn-GEzKT3Kf(* zH(fMMgU;U|B9V&wV^=o?XCNMOx>wx}H1_>%qrI=CrdMO3bW@xFsb|l}>#X|gEzhlU zz1j?}d*{bJ`RN_Y5cAo~<+igr-s_=&-JAU6+|U{!Wi~?#MWL~8SNjvbc-&kcMDXY9 zI8>p(Vps=99+rsEt55EDOqNj(95G%dk3^L+g`jDo?9;cwa@5?Dn6|5)6HVM zcf7-e%GGx&65y(SXyS**zx9l)l_y3)Se3XsO|Ug-a3Ib+T?Mxwj2p&U#B?qsQOOL8 z?A?yat%sDAL8i6s``x|8xq*tgC{9Bzp`c?~Yq6Qo#;`E=eA(dPnA(pzW9!FV7G!p{s6 z+eJDCFUPJ^l*bk^4ocHvad5a#KQ;Nm*2A4uzY-Hy|gwp zPb$aS)?|P{JLU*M_9!;r(FMJ68_`fN?W24hM_4jUI(i?;{CW)R`rum+NfYWU0>Qba zQnmsEu)PfWk--lshR_>95k1%F&O+IV?gMikgP$akZINA^RQ0FgkMagjGzA`p{$MFi zSuT>{)V;^?I#3-}w~%z#c2Lp*naR7bqPM!gT_$2hobfc|xS*QHbb(NhhxGc$-frSB zX6;3N%^}9^DVXUKh|pK}X4ru0w!KqGdc<5C90%Jx>#2ZI<=zQZ&AAq9u5zS+8iB~% zO)k#^IhW|zByuzNC_3U+p+f4%_a=+3-F*_S@lEh&wYywX5yOQXft_ovt)Z9Zv>@0x z8tS~?v^R~tVxWQ7K9h&G^yi7|9}?Sv)|~|hp%TlR(NH%p6WaqVw7D|`z_KtW)eGco zsm=sO*-qc`Ja8qDKzg5bxyPOUF5Ony-pBR503@fNxh+~~{bmSqfo-~ff1Ba{1ySH` zdxAbY$Ncx1Y}&Mra$yZg3jkMx!@`M+$CnL69_3cUF?foE@6M56$(PfF=LzALeCjj@ z3WM6?rW5y4PD{tlgSm=S2jZQ3H}+-52C8Mrwwx(zX8moMf;^=KC@;Q}S#jY+RlnqL zH)k6quwn*B_y6U_)`zZO8>NSwa|gOYv`A=aZD?QcJAumLLLh;Ge->%5hstgraM?7w zT)KbytpB0Zz#E|LS+6XG*Cd!K>CjA__dDk;Jlts_rUmAZI%B-0YT>Tou0p-&U{8GV z+*CHi#p--yVDsQTdL~zDn6Sc>5K$NFWHVK6$Toc$TW(j;%A*Af^+W{mv&ov&GBBsn zr_&`<6JXvYJ~FT%>RtxOyD7E}Q_Z!7@+Ma>cgVSWJJK%>u2NAL32aAQ#LZQev;VeY zPmyyFA9iPoI=TxZLh8Z#y|eI60o1#nW*TqpA&Wt7nnUHKCZ)k^!9PwYEy zhk;bgZ@^MU-09Jza%Ld22$V2;)hX)p)cg(+EQwKG&6X}ce9;0>@&l_HsL`$q0dh@Z zKbgNe_3(u*6_9!&H}RA!1iw(P2d+o@!}2^^uE=q*J|5^_%59IB0w#Ie>_>^EbsZ;- zpY2YF^s8qH?^>+_n4ZouEt@S{)oZB-Kg_(QhV$oa*>Y`ryrgF*Ko`0mX?z}3jLjZNHdIOOxJ~_=RYTVLrN4ee8 z=&UyviGQUZ^VCqySoK)b=PzNs9F-$B&W*PYIpcoi=qtn zCvc;~5gr1G|4Qx-MSQ{GkjY@SZON`IQPqrtO=oRKy@sZ~LuF(a3jfe36K}PXw zC~85EPByef1vL#M@IRa`(Hs(Yae^Ch0~xYT4P)-}Q7ydosF9^T8`a9FP`va?lGK|v z&duWGzj(K?G2!q3Bpre5q9Ew)Wb9Dh<@OX`=YQ8*XlaA8ST1*UAp9_Hj=V8s$ooqt z9*D$i7EfGIKvt*M2Z|M05OP_CA)w-@X#p`YU-gpK1ev4_MZbLZ=&ZfA3Vw ze@*A(db$V`A0MxCh;|r2Zg+mH|NfbaWPehCgzxzp9Z<_J`4#m4I4>N?9+DBF(qMtF zUca1H*3K45pw(h`naIc|1zPmrX}@xF3HA@@^lk@LXWNCo;qo}v=)tBc z{Ea${g9G9m2axY$Ly2E%pX>GLp7pOTF@tFi8_yi2{>=h2eAl&!y_Xj4QN1Kcekl85K6NI@RiKqZ6>mw2LyUl z8XmqnM&*JluO?L}vGKft%DxDy(EfwJ>h(~&DEkfUTZPy`b$Ko^bya}o4}dG(fE<^g z-3%C;z@FS{53Fu=S5)Vlv(VCHW7@%_3H9?0`}&`yPp*@e0>(5qqa|W1gmxGnn=;8? za)U=AJNs@^vR_qu$S(7)`auUFn})!&vD={W)LWq|>6rTmwyaci@J#ED2cGKO3~`CE zMG7@{e2!=H5~zGz_;qHaU^?rsD}R}-)IwPRyN8X~zrU}+D*YHy1h+WlcKB-|EQ~#pL2f6|!+PW(Y(RbVks^EUwt7k+NQ- z{>%0D@kS?`hbjKk<{HXFzlZ)3mhJdW*YJEzyX}>ZQn?FFO7(+4;cN12o;nHlO{;u6 zHt*z+y$MV7(A25}Z{&Q4uk)Z`>{d9z6KO}#n@^TscPx!)MUT{Xe=X=NbuQSat|tO^ zzNJt0?l!th_ZO(Rtt+P(?=%-v-TUqbUG^Fy_CPw@ZYXcnYaAjf%aT9vSdc z(cLEoU!jqZWCmMTlk)J)xkwvP>9s0IW?MjU(5mj-TfIEH0q+WFcJKAb>wYUP%$lb9 zV!gAXN1^`6Hs&24A@MV{PX3wLKwW86Cbf^gJf`~*}3%!uX%x^E| znmGKD)wf8jg;vgdYdE{6)v1}TD`bCIW5B?{HFC30*(i@{hi-2=!E{*+j-1H+Azr$= zzI$A_Y!J_Y@IM%dJ?QlZE7NSH{hWV6d~fN4dLWrN0MwFs-gDGqFW_aDZ60zh8ofdL z6uPr?8e2YbfHhg%>=1N=iSmX)zEbj=RJbjJ7hHNlK6_Ch;*{d>ZQk#)>kVP!PBu}X zJ$+y>MO8)Csc#)}^bqjHpMSh%Xrg-}q2*4%PpEyU9`o%G#gn;7{+LGG^r_6duu3IwLaA~^M-j%GJcKiUU= zuFUuk3PVwDUBe^VZiMuRz8G#R(#+l3Qq_GVFAocQrgTh%e>^+vD*{^#g!0MEzx{e( zI+rfCvzX{((cPz*za#g~O_9@Ii?8C^5KEB}GnG6D?~0Ykx6RR7N1*erXbptY>JB4(OS;p5ci!i8JpBE8ivg35cbf2t{(glgM;kvnNQIKF~y z(?34QePxdwtmWXDGwNz(ey9NBiN_HWHMXk1OvfV2>v})QxQ6Q_i%xUB$~gyXCD zexBR;^y^;v#wIW#!q4$E1+ZLasv+COQp$?cHnxZC+mYwlNzbY{!sU8ufe{Yh_eYM^ejjjvY{7NS0jn5p5`*)KkqOP-dGoeho78W`n_$Id6$BWv=|Nl$(a5W8 ztfF3TZ2mF5(%h|}Z28kOD24ouS#r!vOMVdaq5vx+Oo1Xj1i}P%tLSUJCq!ooAHmSj zVt-Yy=Kfji7C6&kiFrse(%^0QN)ReRTto!YSLC>Xg*)BGnKb}z44@YT1ZBmG*Yj%a zPL1gk$X7!!&8li!Q|H<5^T)hOp-+6J@D*b|6?o-5 z_QdJr)+V0%$gS80cIN}#)HScSK>tW)<)T?0?vD*u*7Q1J!@dr$m(&#j4I{O(mSAV_ zMCbe3B!mIQ^*p`i7i4#fB*$-|0jYCLIkQ`AI5*d$=W9ZyfO~UzuUfP>(sE6MkGL zb1fqwBzlS-WTg}IxxgkRt?;<~g2`kFVc=4-x8JTLye2jP2xey)P>P{Cp)z}!v;Qvt z;xZg;D9`V!F>H@1QI56R!+<&#NoFv`FksBY;yXo}^-Ts(m-CLRp|K&%oiAW;s4;Bs zabSZE`bfjS8I1=8Cg0F zSNxkn;?5sM$RTg7ak_QnWYvlc4^zeG2+6UPs>Vg4Y~w*M!5bFGOyV z?1DQwW(Eo_*IrXdCpV!*whVw-)(DL7#gF=;s5e-02sxKa-@%4X{oiOYEUn4=V3<-D zWrPlJ)7spj+4a0>EW^rMF-kjawE!)6DM=9%4b=Wxx&VOC6`|B9q{GLz$-e0(>7vW1 zq53ceGdaN!Nv9t|w@1)kF6Qj>j7)J~abz#n;Lcdkh{(`eK?0neE+w+ZAd^Ky!3Pjf z#)^zq!xB*kG6Jg`SqBcoYy6_&bZ#JBaL46~C9%W!8?4vp(Dx{>&s1-&V`TcKf3OMr zx++luazj}`whecQUF|E<*17CoY+l3|a>>3}Sz8xNFQCtL#RVz{R=5TeNgE0D*q9}d&Cu7&r z!d}A8x435hXkNFujjqZE0=0AWfsTlIEHzCifv$d6Sj(W#zpd)Hp+qXmb|1A<&icec zCKdB)P!{0g6dul3zp7rPl81tdG`AE_TYuKVq#ZjiLc-Fqa44-x*Wt0S6iV9{{aAcf z>-11+NvIuoj4itobhc7Ub>{GKJ%BWB+x-%v!l}$AVqPySiOds0$YQpjlTXrvM4e9^mT$tXi)5`)c8kCBpc3bx6CpW4vl zH#axqYmKHxlLyssWPU#L{CU4qSarWUqFAX?H)O6FFBHcDke_P&fmJQh zss0Ip^1!bOv8SZqpq!5UW5qHj2&~#x-sI>Tg>pUx?odKcK27>>*&E6vk#QQLBvHKp zg}d;@gvQPb>nh&+I}vOGQaq8GqC=Z;VDAMAV5jAp_uq+fNo#9suL3e2bYs$S>pIwb zEx~o7zkMQ7iM#_D%tgi{H3dg?AMjRIReq=hm$8-O$!}>($FIvOQF@O!ysb)DOR{3L zith*rn!qgS!mn*5Wyt09Ye{Da*$|DxSMV!;KvFU-=7uSxmwy)!q?k)NVF7lC@%~!= z8pJ-AZ8R+Lg6=K++sC5ET|yx}VR1-0@}b1mF7j1VnNs8rNKf>=cB#bbpn|`oLg5eD zJjTWXaV)8eO*+~EI|)g~q^3cc0s_=dMfaOiWn+zm-sp8PqX^2Fjw|E`APem}ms%d} z)APOajQ8--$&*XDn1JLoDQfO@nRJ=orSO617{i$IfLN%AS9`iq_qS-VlEp9HEM975 z_Wq1P;cQ#U@~%Yt;qQ}W+akJhp>$^Q6zjEkhDBW-RKOQ{;asFGbiMXqp9xKK^JT(= z6h8EQe7jL$c~S-DA&kw<%Nweyq}6qFY_1dDIJJHI{=jy((0bKDOL;GXcYqVnJe&8a z!hLF7uLbO&d$sQNKoHPA+xMlyeRfd+=K$%mOJ5Hhug>*dKrP1muiZO{9=d0rzCUmr z{G(ukw8*#q)Kt*z0;5O`)I<~L4OK)r4e-P{uZ$6HwR2(OR?_^vn+ndv%D<-((yoAmeiRpzbjF%g2Bf)Rn6GYF$nl?^^Ga8l#dp{3S6!qr$C+uaOER@+dlP@JxJ7{{ zru}_@Lpfe-jQf~`u?B4olf6pVv%N4=K<$^NGL@4Xk>D5x7bWVOyTsfoL9Q1+JgGu$ zT$FCDxe-dwfPYMsyb4lVvliA{MbF-9Tc~l$?n;w=Srlv-#ndjvv~Nu>YE{XWu6Wwa7CB)cu;2!^kvxOB^gjJO{K;2xud{%OmcV9$FnWrYJlJSCE#*?8V zz8k4ch0sF$eu$@R`!KFwGYRk=wx~pAr+edz6Z%$@5&p0qgYYJT;fk0BW!u>?OwphB zZ~Bd>QfTkUHw*Gcf4Wm0z6SdnuoEwMUsE+*nWi4`gQe;lN)$d)Jznj|tOoUNtbww6 zd+o|}G$(!Z?5dv9fp!gIn)a?biSmJ{>4Ea*a^lLy#1w6%AsWQQ=eQ{~3&*`8jveD( z62GDwek4%V)pxQz0?Ho`QJ_jKYDLPERGS&{yASiCKby|{C9deiG8#ZdRL#@L%puvt z!1b~`+SQuxvqg!CQh06pIl0XdJuJH^@<|vCifn&Ams1yTv07R5RY@+jb~>SXMXWb9 zghpDa^3g!N<+BzTm%%^zGNQg$fdLUud9Q`+hcaHpl@9zk5b`veEG&s&|D3q*hhuo~ zD3|0$2IKcI57&WS(7m8I9%~F^KlJGy6mcK%Cre|2cbAYy@ku)Z0?-B- zbkiRJCX1BA!|B~&1WA68q~9uJJ}Cs7sN%p$4vL)3u#lW$U(MRJ;4*2CuSA{WeDK{N zM(BA6L5X0@^CW!wE5HX;EmGFmJ)RA%Gf=;YxU;8rpkSaw9N1RIAVUUN+k=@SGCPY? z5`O)-CS$mu8G!CHU760dBdId#0{{+y)hg%XF0Ziax8-@UmW-A2ExvXlbZx^5ykj)w`=~Q+<1S;^$U%KU$u$@n7rBnP zne%e2@aCIiFXEl;op#5h@h&8-<<+-?djcEdWhP&NvPGf8KNs-^?`Np1bO9CNds~Kh zrRCg;x+dP%0!kCP2t(N^JZTk21; z)DMS;c22E`G${4R792Pb%&}!IH z8Aah?dEJz)?74^{>Ve_9~Rs~wBG zPlAqX9a|QBWL>M`V|J&9y<9n~zTX6;OyaEuasM)t|1mtRCR=)RDETq$KPZQiC2c8= z|Fx3WNrqt=+?_awtTTd=QDRXG900AXODQM;`hXY3)Io8w&XP7KJiyfCVjq76e1Bm= zuoiY?%FHqFHMY6T=rHojImBdM=|NVUgWtX16eI$-gpe)kK5NZKkhO7FeO!@uKP88^ z+Dq&$kj_)C6h^gmKw=%d>-R28q@K}uC z`(~E)ix-Pyi3-1(tSdDbJxUK9Z?E%f9Z=rICg3^bo!mg3&_NR}bb@xTg6%8vtJT`N z16SkXoz%iA5Z;1Ak*A!dTxm*BH$gAxOL{hk!QzwJg`3Yur@<_l5|JgX2YGawP~?5< z*`LyTn$*-YLgLmFev@tqTh30WSZ-ww9{mR4EdA2xCGJV0FSH)=!rZ6o-q34YnwNyn#1zcHuE2rsCK?;9Wq~L9>O9|GqOmJLNVGPZT7ndJ zGS1$Ho2|^v(~n~);qKz3clzsazQZVQ_nK#%{pen%$4iEwG3;#PLqwCPyR5Z&Bio5IpD1WR$u!sMsy6(4g%DYookF+ZkT!6;9uvZCBr* z&3)*)RayrZUr1uTNgUtjL?T;AS#W4{FdWT9bY0TBje_*C8%0-V1z>j6aaYUkT4s z3s@=?1L`VX&zvJn>FJk(1KdagAA~vSL>TtWwqaQzDJ2CoDkyIonRZR-t4;RJs(8CM zy42^N!-{QQia5Ak&M`l4VtvK`=yq7D*XCC%&7({%_E)SRFyswby&WV+p-Nv^OK1!# zG!^&?V_BH&Ljx!yd|S_E)VvqJIof9!;XEa>m%hVmONUpn`wuY{*oVLVsLp@n_te`_ zXU5|hRgag$Mob{FqCVf<&BKw!DP+}LULJa0X_0dK$=0!tjhmAm`Sc-SMn8vHWs7#O zOsaPAARqp|=~cdCb~Y=1Ag0ZzC8hSwM)Z~4`HgW?G(+rx8 zyjdMHno$FLCo>-}@W&*z$P|*z625%Z$N?s$m(&X#6Pi$fy@4#^xZ_~UAVHGss`3jg zZY|R$S!lk&tqT*v@%G^HM4agByQ*HJ3;}(uhMA#OR*@&<=P!6-2R1hy)e4qrA?>?h zu!UJ({`e8JuQok$yl+%=H7B#$0QSmv2XCXHdDc-7)dXw3G_HqZaOrHEVgVxK<=$3{ zp+h|((rh$7KD!>gT)fW|{T|w%v zxK7b%lu@Nc6KyYo*Gc=fPmRm4xuc8rtDf3LJ14+5 zb+};K2@6E@|6%PN1M6zHwc#X9)7ZA%*tYG)HXAp#ZQHhOHMVWr-)i?hXFvPAf4}@$ zm}{=gb!(1sVcc7pLV*A2R=bj_Soq_~Os1j7l^z4w?x&iZT=d8`yY4RGRn_qDpmer) z@oKgt+(CUBsJV2g>=l_1|-w&qO;MG^NJ7vjG!{Brv;eg$1 z|MLI>jOzKs`QM)hyz+VdbKoM({6K)=|C|vH1jYLX^MAi5yxYSEaNtpx*`5IKQ@sD@ zs{Vd6-#zD2svRA&$l^q_mJ^cfGh)fG(=&xXtw-A#Y32 zokK3N&f#!G7sEw6t1OZ9l#|gd?VuNj70$om4rh~)Y;ro0F5}I|vqwCD5YqtiHCQxh5WS&g`A1CZ2SZt2D(=k2!yt z*;hLcChh~~g5i64Bo5|Rt(Kn!2S8^U0I%wS|Np({KTZA}7tp5a?kM)a|8EQ7clW}1 zef#ge`SV+K00$;L)6{!g0%T6jCC>;JYiU>MNCZ_RE1dd}K4pxyl$kd$sjXf*YU zhZd%N!*v1L*w{FlD~UUfVcWwYkaKzGc&O5X+Rx;c+h~U{Qbw_kPs}a%@@mILvKOsq zXZUB!JMw!6WVL1w=%vAc2wW{U+Y$YGywED*%HVJWc;^!U)|OI5E?7$r5DGWg-Isg! zJ3vLk{jW(eoL)SEyl-@&;&L7Qy_5ItTx*oHqQJ|`{~SS6@qb2Wys5o9OrZDF6Chc- z+Ujx4HM6#kq@3ZZHsbZLcr${h410NPkOJ9;dnB*p zE`|Js&x2z9v(9w#=;*0`Jj`+JD%{eI2%=D!Eb4RZFowOY!Q=9PYY++41Xr?aFx1#O zz)52_(t*H4bo&$lUqP=zy9DXVbXg>$a0FJu=c9ZNN^@nu-{W(274{?6*t9Er>gTAp z%Mf$D5_wAZTtY(-IVXaqf4!x9r;zTmh~{EI_&b*_P(j>RR<-!GnVG*oWX=r@U#tHp z)i1-lCzvPP0k4RJcVDSDGq^(Z9IO{$28K^i2hCwdT%4a{gKWiEovm6x4tNLmu|EGz z^f*KNWaLE{c+Va5;bc!Y&I9zj(PrEChpfBCH7<+gk_K6M`ML1b#8ql1Sbp>@I+cz7 z>>LdL%v19KzO0rBis~%9_(u<8m;8V{c8`X@)pb~JODL23!}8C3iYmfLWZ$sC@qUDW zKxz$ipFm;n&JJ=!_cwio?6nSTC|-@Q*lrn^SV)uNcbthWkZ{ z)f9~qXW9gySz?ANXM-kCynWXD>_V-;dWv&a!^jNSfq&L%ALB^C((PEBU9L4opNMYN zBbJuZVsO2H6lkD&fN$p+&5@1~`1QNUuTIKhl;E(on9u^n30*TYalJsj=M8L_jMN!9 z!^>VJXGgBb616m`*%M#flso45jir4#GC>+h;@`GI)dNk8DWPW_$($-QK^Vr=>jlQJ zvmqZ!<&v7EBd=@yMDeMK@)gUm3$un#Fkh+v(j$bo$Ez-&4O7XMvZ?l&5feu6N)>vPh)2 z8-rb%i0tfTq3KpAZ2`w;#~E?FG^B($C2GK9sz;&?y?s0F+OSrD@Q<9Gn8XT(8+7B? zTsx1cz?TJ6V{6^MZxX8&|9~+$N*mumkljJ5-Vbx07S3z8@6UgXGtG2koMCVrC|#wf zgCdf%0Ttua;fvwUa@Q2>Eqr9lC$Z}9A6gZ&&L!imb3^epb+4(<|8PCi#2!g<3v##A z;!>X7OomDG(OO=)yzgHauw|`_-+@W1!9I>x`xasjiwc*=!y|7}PRT=9P@`FXT45Y& zd(HY2+zW)8={yhWBc>V&3k@!?g{cr)aB8O@nSVEW?onFHk6K-XLl76u>}@Hb0u!jV zX|jOfNJ>S?*r2nGlj(Q{pvN4flTJCPT8%8=XTse`tTIp8L;KgXKnL8Vqynm+fCgXu zbN`FnLea3_>k*eE=R7t56+$+UJYm=5P6A1K`eB<@Wqeb97TrmXKJ-dLz{rSVx4npP za*rArY*$>!L@BE)qKa33ME8wTk+IrqTL&JyRV>cbd2*YH9ye5{cK&%pcHr&E;px|L zR-j7wy`Hw3Kf0l2duVt*xlqtEzRV~edu4uAcfa?pn8aB3?`B(S$RjwDsy;D9GwX1n zo7@mJdnpoq6m7Ag-`Mo|WfAqzmrbZO(37ETL6Rn(qE0HPGU;r8s6=o^-u8D8X+K1y zYNuQ>!X1z3SXTs$S0p*UW~m=E3nTO1wCAp_hX}INwP6B~+ihM@dU$6c;-~c>`Oy0v zPh6Rv$oq$n+cmfuTc_7_zj)PrE@WWIi)(#^qk80$n}l7BP;jl?!ev&=yxnx%98N!q z#f86<1s6_y!ZrGTnFcnf(c;vRK>lb07B0>YkRFpnR}MEeJha8WR~D%NTE42F0fe~AvPv9 zV7O{SM^A|H5Q{hhq1|acXWVE?YEtVwM1<>uepcQkwFC_CaOX*d_f(gJ)p%SY?CqiT z^;ogJiMIBDDU)-gg+Kk!vsFtDt&azNssInPSCwV6T#E{?C-$Fu+O9JVV#?bWCjN3Wz+6$|G+5^*gDUwdM`WyZzi2~w`6Bl%^ zIycDAvf}PZd-v_5E$~Tt+MYB46U~|9wfPzwO)jcsYK_(I-)7*6NCwK+*No7%E}IMYFlje-=_rDK%jlgLNwXFd0+>}9&DsC4V-y&at5us_yL}bBHMBareUVm z)RUh@C8uyr&lS>gx$^i!3O3&^ljX+GdS@al z?Rriz3M1cWxTbmyA&*yvs4>F-B}6jhnlZ?+!CT2}q)UHjqhqPf84WS%x3`5Y*IF)V zZqrvBZ9NhY3ueLj+#4vOsbX-p?RSrq;4tW(-*hXlyBFaPjrsJMS;Ytv{coyPmd!kP;RyT{c7}1o)R5$d&qu4d(F~Xl5v{y)tjtgq`zNwV;-#V z>!sZ0)e9L2Pf$~QA4T1|t%gCzLvw)%Y>74=y&yZ*MF_bPZ`v=R`-{n&SRGkPCnd-u z^#%wP7_62fONh9q{B}GW$pS>!SpJSKCLTaYm>gO|h-Ir^(lzJi5d#ArOD3V1Vgsf69M1cYU;d z_r%vaCYVm7y@4LQH)U0SC(Zu_J4Axshhq$F&jr@SaY6*tIG`s5j73tt5}pabG4bTz zsLIC)(eLaY>rn4mR>c)h1y9YTOO+4s1OOokW9{#A^P-R(!lR)_eDIWocoYk9OpLC? za`Y&;Lp8$b5srv(6Em3)s)AzdN;NBTN!GET*ZE@8AWJ|;BEREyalh$)bANbNcW=1I z|9GE|T6&&^Ric;>A4`D|wj+?BoUpwgRYpcZUC7Jt2UBk*V2OCpAqmnuXnp51(P9wr zjv88P+UV8L=1J~)p(aF9sJ>h$P{2Q~lcrUYW;zlv;3S$t24A|*CP~!K!jO*EC_foFw`v%2a&p2G0fEgoN+0;KN^h2}wm|xVrQvWN68%$?zvF$n-@&De z9cbm4ijxcDsE}Q4C^rmFU%d25UjuA}M-(9)npo=0Ccoc_Y2==UrGP?SA)d_486+-m zTUedcRowBLn}+n-LIp>+6`%8jTL6=OGF^{c0cDkBQ)6m#ufTv&-=FlBFOR4jKo!9s zo;`;v-90S1%1pqcoi9Rue_=9>PV01MjYlCFZWBwZtP<^WUQ?gg(hHxhpoa;uSF{M8 zJKoQdAxi5Yy~pKYN(%yauk%3Skpx41d7OVbR>$Ukt4RcFg2Y_=U0~h+RXy;rNmRMYo|2KZUt|XEV4~H?6a3HK%m1kb@a}adtsI|Q zpBtLkwl0vO>;{c~P5HrdX@EQp;eOBTWE~fci4}~3^zy%nO!L> z`Rf^Wo9^CR6v82lX4Qht$z4P0Wh*+C$qS*U90*P9gD8hLNdOZsv8kHEBmro~p0pXq ziosV;NeR(!6XWS$2B~3-o_(d4TIqdugnOETREB5bqaL=((|FNBPGCw|oM2;}O!Ne@ z^Nn6+`Qj1^d;HBuy=&@G4dQ+ar4$tMFKdG5Wgj!>;6C!mx+Pv`cq0AdtVAwUXK zg4FzVxJ};wEgebib_1ChE2Pb$atWFP#jQ#uM|#!CMXVT_7fRpTaGo5aP+mZYeFnFTK1Yd6_qS&4}Y!jWGdMGr23{ju^oIFzO!gpy}@m zU&k=lvpZ8avcT6-B>SYX+6Z8qSsfvI5=v=>PuXg5xFY``lfi!%;&`yuihMMgZa3UQ ziq`A+q2~SehK()$hK|Hq#>~sSWwGc%_nk=UpHxq7${Gul!bxm{G0wxI$Ev*JJu!zm z%64J^OzYi67`zv)6z+cH@keIzn+n?p>Kkc#diq5%Hm+ilKzVgcIII`RM#PoAEj9xL z{l*;63taDw7FqGdO^om-SnA1c0Lt`el!S2}B9pNwm`b1bFw%81+ zdw}kmH=&-+1J6>6^BM&5=RPLnaoPk=4UUZ)#6(nS)%gw$$Br(wS{+);9NxJ)k6&a! zl817BMj+Vi&uQ>*2yLIM2wJR6%bbT_-|Y}U){2O(fzHJd&E#Lzi04*34W>lP)D;ja z_BUF(rZfZemLDAU4vqD+`W?=b&8AU^4x06Zy%_A;}mCjEQVOHz)D2st}FP|0tvE#p>x6r)hAE?%Ul0NB7JEj zj3#)?WqAAvzA_G{gu0K8K_*k)sU|b5>sU9SwcUW|?TF!Gc;d-inDtbg4ODbgbRwq- zeVJkKiE!rz2kKu2dJ53mS1{dzVM;t3+jhYiB*gVZGq$DQ;}U);%il9RnC4LinAjqM zpgs4Fv8xjz%bYGFTtxq9*BFkpn2x`R5MZ@g(op8&94=fOMWw{d_u*+Dee=$hfwbkY3n(DpY!6C(Bo`6(x=T0Bi2gorr6UIuBHkMd z;Xn@az8BxQu{wmriZJ>gZYr#E6DCGM$4%H}#ueu_8qp0$yT>6~nvVTR*!-1<0(9MS zjgDkA4VJ2Uh>A#9$7YyK_a&1F8MKY4I}Q|g8NOpKf!|?^pMuyZ@=QindUm$CWF_0B z!T!GJiw6tA(qhJ4#hkRrpnjxt?G>ScPYl#&5b_~-yDa7!cq(e>s=&9Q@RZ^O6z27( zoKd*VKZvZSK=-(RFD7K(sqyf?2#kEgwm0Op($0V3n0kh7Tlz+AE~A&NvU+F|pZ^10 z9&GjakyBFkHrwq&50)sAn@)O@SX!DVVNszBkXJAic}>ADYJ5|)$4rn5*4j;Ep^Fbd zIxXyV+>y>tC}(cYQBH%&Rg^l*ccqFO&5bCsDI>ND%Qgt&Kvm3&?s)|4SAbp~=I;;s zc0GiL&gD|w<1&a1ht0fW81%W+jx^{y?CQ^Ebs6zJt<3t1 z)byjGj)j>?^`&UUyF5=~lvUJJP*b-4v+0+2<@;2`^StCijwQA=yVvL!4$Q)`D8Gb! zdY!<&g+4mRdgASAyYMz$krlj}#T%`A*^sis(hHl0MbUM$pW!b=-S_fdXO)^QAZ~7M z6Vq3Lm_Ad{|5p_le98){=;Q( z-JjQDxr%$fT-LU^KoY$fD`Gr^NIZ#`Q;nSTd=UGgcsiC8) zAUhyG@TpE6FIJRfFYsdsJQJDemUorDFm=}fDY?c}LL0cUY{?tlFa2%w-scu^#9v2vd>3pl7VFJ3Ff#OXBH@}$xOhL90 zq3x@`;~2Hc7;S>lxAs~#h&&v(-myH@c1ls{gew2ME*Uy#Czad7UPx z3Im8TG1+Tf_e&7$0g4&27kOhjqQdU{OHiMtk6S#7mv~NsUb{atH4>rPHs7l;BHu%J z;% z@O9no!_H!38sdMVv-CjP|Kt&fv1_KG3y-)9l~%+*2NkqRsdr`aaM73;sPi*1^O%1vOmjq0MG8f zAoM>3gEN*-j$lyl#s;pjvGI%%Id88ldVxa8HR@aWmc=(%>|#5{ff>LjLXa;Qv1-gL^9Www6YwL({&|mMOa2TZSmR@(+2y6Z5i<&V4<`ZJpKm4}BR{$R zId)FMfh;^vpnr^oXOBIdBu*u_Stk$HV@ZBa~?2}k?=}u2pQ@%atd%< zS3uV5twzzt8Q|-EJ}?kW41+J8y;_?Ujk$P}#oZgoSZZpGgW&sU$=f^rWoBm0@(R8J zGjG9EexA(-oHp84`Ab><7~Vc$!T=ZtEZ}y7K;`EPCp09Rzhf7TcUc9?CIeErV@cZXMn5~M6N-~2{C}|`?>I&0nbjzozAq9|R zLtcTj+uhkJ9FAl4OrXsNiM(>7UnXWE6ERY8Yc9*+8QIG?!qSC&N2$jirf zpi2$cBgK?}$bF+`0rf1=Opitu296J6>ht9Q_o5=Y;v&CDHNi#LiUA#M!z6wj64})<;?pKDaTCE)7)d>iubfBfS zA4k@2)we)DB{g#FFM+RIJ;`w^K3rMU%2zoJ^(pPa?(+%x|^B)`OXZC&10Sd zSFW$;O?n0f26Sct0zOf^A8L8mF}oPh)a)udw&T?9sRekwSX5qb@E+%v9Y{Nl0cd(? z=tr#~u_v8SURtbz+XX;i)-oBtd-F7?%g4pp*x}rpR&ok*^DdX>`-bjETyo6-f(uX6jwALb1Fo*3p(*8FG!hM`*5qZ(C*}*S=-xUFHepR3`Km5o4w9Z zfdqtSj8E8a$dwCwgMkR9rl3cw8iKx)SI&!DvkULKqI!L22K8-(HK(jzbQ(dLWJ@sli3kX?4Gjv`LRMo9viv;;_Rz+SXJ7 z1Ehv;e#?hitzY5q`NF+3XCZqC87LbDlEX(mAE}@nkH>Y$r&rpZW%ako_)_D05<=fG zGR1_nNZOBQ)wla9uYjPSZ#?U!@!tY$4XD$Dsowmni86n32{JjZQ$i$4sOOTjEjze@`1mU> z1Za*_?Cr>xyL^`Ui7V zZ93iO;xy_ucZbC z&dw##^36m#rrPb^;$YNE$-MGB-xBXh-m*1B!4x@{Pfew?6C;T0{2o~ApG~c|xLpJ# z9wWhgBpusT>}pxEUu5`E-6ppoOm#E zax-yg-ZQyPKMH|^0m1XH=)=|oy!v2B=}lsW-e44j&3_R8xImk&iwsz?_igI^kO=*R zyfC`qV21XyXI$;8ey5CY+q;qbHYWryY{%8=xMy>UJ^Jbn91+ujg{7q%YE7K6fde6Y ztKoMR=kEgU-Aq!?UV^rU8$fIAsUcrf!y5cUod}ha_O>2&JWW zxG-DNyF!b`KzzWNmBjAZ<4zNO1o|Hq8Qj0*&`pXD<~NaTw?2!!WvNH{nLvi^*I~S z2xA-mK={3(Yy#j6LW)>T$ou_Knp}?182eUY;MDvN+m{GYK5APti8}|nk6nd&6PL8Q zJ%{#FjYn|h=^a3LjZWR1lRV+;Su#b{J!-8dW?O64QaV>GD_odShixcZV|HFckJ|id zS0g~lhq!}hQH3#6ckG3{>+)&tUsn7{MOj|daqR8wSMUrd%*M+rDhM_PeBf)RBdAVP zJr^6s^adDT$IZCHZ(Y_}SlzjCMJB&dMOQiSNhH9m+`E8;&K{GiBJcDpeD)#9>hP~N zE*$L{uFNFeSn9q7-EJQNxRw+~x}!rOXa?kj#*3rI!P>NXJ1Caw{LIR&9dU8SJAY5E zA$~RCA=^4VP)r!$)o;_A7{RbNy$#Muy8S?C4(B)IzhHlfBp5CW?-`NmKS+5|uQp?# z4k6JS9h9j>$g4fv8`rly5&0Vb9(3mMyKXHLjxZ3^d*J{b4<9JLB1t}*MZw^u9y~kh z%XdVaW#zN_D1|P$ASpuHmfX$!Y&S~goI=3Z9MCuJrt1&3tFkJHKMY>(Luj#t`Ni&( z$W+;S4Xm(ioGHBUELmMe+1FrSqSoj=*kyF9tY>!ie720=Kens(!QakG0pQdkXBI<;T{Gnh0Ip_wwR_D0;?H~ zI=bL$wQxbgo45e-xrQ3jtuq(F0_DO=`^3VUooBGrBR9@Lo&*X26j z-rn-*YNJURZvuNEn_`F{?Ia736~DS>)a&RZ$9QKW!n%9d2n46rLVUcslTV1b;QtWp ze~)&+IoSDHwH2{EHs2HPQWJd*7?eTfr|2tZYB?jl4>+2_19P91t*vGvM-&yu<@~P8>JD5b;c>3 zd(tv_&9&TbCYJrhPe4*>b+E509p&uN0w{s#6@8+1Tc&XO<&?JEL|+-v6saI|{H*(h zGZIO&8&U~UXm~Mv21UCO2z0E3hZ;V6Rt6Z&ehL`{0xWrM1e2yO&(2+*X|VU%u8KBGD4jZW?n0ejRPiGRlQT&+RdK# zl;`iyFp2pHW8>q2xy|sQ5{&UWlY$UtTb3Gezba%3!{<1->75OT8@~!|%@Uh5D=X?j zMw(-NbVPSvk4x3az~dL=UCZe7Sl(xeX|Z&IW~A<=$S{H4tf6ROjApVO z($Me|RmxcHB|8xx3$bXhg!|z}+eE6e-s7}QA2bZ^-Y1LS=3m|YH$>@bB!Z#ux+T;r+8}7>aDy}*AP+1v#HuYpuK?Arhn7ZncEFL+ z%e__{WP3XOt#pVt;5%Y*J!gWqlOhT;pj0sCERx*`9;*>X6+X0r`4y9>H*&fr=R2;O84#+wq#ML>vAG6CUx3&rI}$8yNYcuiqvR4QjbFwH z0r)r7j$$)KBYoEzX8FqTDHzK&8G*D$AXw#|Y)MzU6;^&zT%JnE1+;sv59RaXys;^~_$s zVA;PASUzGLMzc{LYVz*P_KOFt5jH@*%5A+EE7j-f5AkA%Mb>v@xN!g zd{Ct_{rjcJxDN7-rlAK+SpRh7l(|B=b_Wn6kBrb@f&0tD&zMew?}VoCc6M@Az>Gf4 zC&fOgLxG}ef#NHvbR0+c+`Hrp6EK7N3R}ao`VG&g#(4&`Hkkf|)sz%C0mOId8+9OG zzQOb^@WNbH%|(>eDwaBI4PV!p*gf3+00_AILcOF3s(`PKR!|$Yva+>GgAnR%abyk; zc4v;cgHw^Ap1ORsiFLGAZrNX+y&~)M@hmQQI9z)0HjRP}P-yhN;ylzD4*jSF#4LX> zP3u2Vt57@kw-1=xH$k(yqAFwqmu%h&rQgH@B3#iZ|;jHJ*lks(K>CCa@`aCo%4zT7mB>VzTG&48 zYc`JU3Jsll0hf+$zma|#VcK`NSWrAOLV8w#_%)x@0m15V9@Uw~rnWPVCwgVO_>sTv zis_eO-8*uDN;!(`@Kc+8JU;R1kW-Z2`b|0T^*YdmRNd;3_`6 z^n7ij(9r9f)RQ~a)ipGA@=nm#+S@DEnuEo-GCOn6{>4yE10hL~g|WFJ)| zW*ywOO|8HtkG5%G7K~WiTpU^IZ1w3M?-my`>i62SOH&J0APOuz{sm!4MC3e*9Ob${ zWI6OT*1Z7>w)C`}9C_yle7+G(ZXcQwDc#TSgP|VcOk?<2Nbq(4^PedJqt!N+uXpb{d>3-vA0=4`OZqO387FlG5BPOezPrHtTxff@gW~O zLRqEyhH-7Vd{5Q?GcJ;Q6aGo%q>lhZ=uEONPRr6<`;z`K=la|+mT0nn!B%}vDN&BE zQfK?D%h-To^1{Nxwsv;(=tZG2FlEFzk<8zGg^QA>$qlT- z%ne6>&mP=#*xo(lbqF!R$FOJBd)M=J9}wM6Rn)e2=_&!X>g-Qum$2mELervnWr!;q zyP`ZoZitn@R05a<&F6}L9k$jGg|Qy4iQfmxG832V*znqBe(iewc;Aw91f^|Uhpdw2 z;Tx*dy2P|J%D<-|x~>l`B*s3PYjK-T=W?Af)p4v!Jl6j03^14k^a3V*ag^2iLe8%& z?L%KITr7#-c)fugi}X7vIt_d}!H)SJ?+*bDV(#k^o-uNDT|Jgl;#MR^%5+8h)}+uL zVB&KJX`m5bXgHAoGe5Gj%D*}*jM6@HapMT(LJ^wCChjZqZ z5l=_Wkb)4WPxbMEm~K*39cX0An*M%pFh7Xx5g?RPSiTi~sW5HmPgX%6UW1rsD0Jpa zi(^BoWUL1-&kK%-Eh5a|H8I0Bl6UfY6c~YlTJv7r%+#Q~^vBjck^UIY;MV>&yk5v{ z;VmM6J)fBH1eZ`r^k*}0I6FCC>L-9Ew>%e+Fb~XedF-aif2np0`S?`(){&3xFae>;ckMS@)(?Rp zn=CFjl>Kv}8U_dW%rlD1f~l7*Hv6ypxSzeDC4O|>&-{Mu(HNRPpp=l}ETZ|oM?NQo z92YFhcoKEF%Gw>2UV#KN0%|pAM$)Y8)FrpKJut3s9eonH}qUAqb zz}XTzJ+%lc%NiQ=Sp05sI4E6;deXY-J@t@$0~1Uac-7weuF*b21J^~avR%^{a8ynm z==-5~FKR>;A04ffo)K|3r__93wR+Q}9@@PDxPNb55qG}062TVXie5}WI)sP!XjT4yb+VBLH@uy7wDQ$B5+%0aA()!g5Z5CRjl zVB5H5zB%>OklMCANn_n+4%<0OK|3fP8vS&`Wny2E3b$szth~z8xP004cVQ*oL;qse z?{+D!J;)<%aJ`iA2WGk}KUtk6&slkk5HW=N%K)eYf#^>{r@ev#_jHdAMr$Q) z&)+BQu8qv5BFj|TcM31GP#YSR(A0SCX(k_}>vP{QNs8Oy#BR5)$#dGpy>{2v2ivybH4sJTW}-duHl2Zz|X$oVVt|Tam8Tld%9lnu=wkJ zVrWZFU``rzHQ696Y(Wvcl0M=`_=sE%~svAY8L$ZHTa*v20?PurOr4=HhW#dz$&{c06QzKeb zRdP6e(xQ}5M6eVMF_Dn8B5zn8bmwmPPku&M7q&Qfk$5mQ5*Gmkgv9T%RcttJUPqxb zEl~zno4K}jm(=B6SFUgN4OA=Q@z7qQ`Kr^H12CEeO-?5s4N1;IxtEez-ONv4-0wBX zu%C9M!@bOTJGt+vGLO}KV79rhjMIl_&BHy)vBPvy!Lsg?Vt$cec1XbOMradVaclG4 zsc!aOtUbEic3cOy)#Ix2{K92XCShxNbaNL-vbe$)3c3?1Qc?Q7XiihaQs+EW_zAR{1D@M{MBNUnrYTZPycCHqT5YwjdRR3WBHWH4YbvAXaWaU@eWDON-qaPA<5~vIdpP z&$UoL1VNIQP(~~%>LTR!5u2BL8ZV@sA4%^#(wTNL(f{C@fRO;?z>rY3x;kA-4a)vZ z!`S7EwX^!i&l*uLd+jAY&kC>$x8$lu3v z$oe(7)}AuLu0jrp&po&U#CV7xtm0SlBv+=JMZ>kwhcsw0zr^=hwq2bQ0xpz8TN4$L z8pNq{f8U=1sMf^|VvHT3f7Jjj&$*ngN3u(`fv0v9TqO*!c^m8^+7JZ1!!izN4&M(P`P)L~?+>dJAO!5k7-J_n0qrJ6C1`~`VzoEv=Jiuj3@`65@EF>J#GARG^)_VM(lx>Lv`=u zNqpbRnL=cWoGS8*J}Nf$=g8*7E)OTOL;+D+d3ia$ry3>Abr;?K5sCr^nCsoCyw%>vf+5uidp(S^O{bIFlWXk=q9L2Sr==Y}e% zl{w(cW9(wHXS(F|${yG_CR{)1@+J`eKn_XCxSmQjcc)S*tdOPa;`-2f-o>3-?W>12 z(%_1CInW+zwHiP=$DBK1OEZgz-Bs%?vU~)v{K%G}j zK#D+uC_5e@R3mfz?bilfg5LG-yXWT-qPVW0EG#V5_4WQ=aYP7c2;PQ$r@TI2bwEKu zO;3b=mywgD6^iQi1;W%{Rv6tWOGjz<6%F4{UnOrq2vgx|0$h=Jvj7L#952IA zI}E@@V(qv0VLycujahcL)BUB~3$Ci7Dzi7b7#aF}9?r(23n@wav8O!AJs+q?zKs6x zmDNrvZ=C=HZq)AlYAqaY>t)8RzQ_b4_h`z0%2Plwj~Ue|%2a2rk*8{+zy9hzxxod? zcj0TUsxEXR>azY_`8AW|s|^>t;&z?xlZ-5V@1?`tE3R6n z%E40}n;jBb4mO`~3tQv`T5u&OeU)bJZ#WT&jM9oSAxd>E%mYo+mXKo@e^ZCQZr1-5 zi=3+P{oqt;QfmlMdCzC64%9`B{BkwjC?GVI1Ej2cP+gbTV3@PZgmv`_S|ynCBp$Wm z;7JPo4XST%aW%7Ju)_bv5~LzanATlMEjWsarXHJy2{Ry$SIEu`Wn5!n@iC)#$-b>4%8O`2NpRnMgn! zH_NBuTXyTwfr-Gub40PHwHApIg}Lk;?6r0=M!-0+__oq)I(;fCzW>hT4g=WOclbp` z_YU{B2P3f9T(*FI(rEQ|dc4A8m)rXW0CSx6|DlloEzIE)1n9zL1&K!QQlWv@y^iKc zV2u6fP0Hd;1HfyyR{G&TfML6 zfw|%=1sY5`Zk)mYsx5pD{y3oTi@yo~MzDOL|0WxS7eT{OgoQ=s4)FC`j_yIrrpx5j8+k?0v`;+Zb- z)F5G^DMU=&rI-cyS|^5ir8*}3a6mx>c8Nf<6kfzDpIoiY%qToR-<{XmT@_z^Dxd7k z4}WJ&kFKb{#9VB2xDkAGejKFPq(bXzt!5JRCM<_kpJRGoeLuWfKB5Wqt=DWC)wJBK z{>DA@loxaWF8Fn($wu%OefF&IbXPE5VAUo(+nhnX=^76up4(!@KvPgvG=Q2uUavl7g2@lK+&&L%Xs^pW=6Wui)c4tDxo?0eaRK6M9ffy)M8^1)G zf994XBwKr@VFdr$!1^rwj^X9{^5fn!RinQB3^-Y1N`Zd8`o11bhb{7pnMp`Zt*@UV zT=V^DCA)~aogN%v61M17P|lIEXv);uTKgb2gmF7doYymmwMwbLdTD9@_kyoyoKF53 zg$c={f>y32BcJ1uYUNLPWQ4t${5X20A!j(xA>2IrC249aq}4ot;t(`Col>H~ zt1(kH0imIg$B5hhsA8sG{@D%(;~0k6ys(Qr9#Rrrl~%Iw-(_?nSuVN=D-6G{fzySt z&?N7o1(W@1WTlWc@R>=1?dzW*5p#RQ)sLp8tajE1dMMN!=p~3e$yMH7EC%u?JxyYY zrYp<(Q_W7vj^hCK=QqbL+dPgl3uoZ#FjPGiTQ-F-9={-w>{(h#MwhOn+YRU~izRCG z=YtLdd7)leS6AT5qz%{5M?*Zj!vSN+aK1Xx?z@sJW1V=?(QHB-i~eCr(q98IQ-)?0 zB7dBzgi-Yn0(tm4acd{63S~zFrbo)i8G^moHvK`a1p01H70>k8*@$gC3J^SaRvf|2 zU+oD%A)#8wZK0H#piKp!kr;ML0cjOQe$FpQ+6cU;>s_5*@TyK*bIz}BG*tO)%8QW( zKh_?b<=fKri6c1eXa--O*MzCGVQ-A?i{`$kdU1)CTd6(EzcvZ8(c`t^yM8z(a}lN5@l zSacQXD^nBlBNVZ1S%e=Jsr3z6J|tB3dh=HTZ}RMx>k*ajDT|gbwYjvk{8N;V@7hNKHPtxV7h=JbA^~(KUuwtOmmX4@ zK3_mlpB7UJLK<-lAwxXh?g~qgF)RGZ98xFVR1dWY6oyIe+6QEGK8$Nm<22ok=COC5 zB6n%yjm9MFUGudI&!nnjVWTYq0e)PT5tvqLGn5!qf49+y?X z@{9SLKB%Sg8DoVou;Yd^&;@sp@YgLWDcsT~LYaDptq|UlM2g#w6LbAQQ^K*h<SG;!ayTo?yKdNvdE%B35Jb1RD6}#*@Y>>gU<1J7w2t>rZ1zkT~;Iv%es5djHlA>-MQbOiWQOC?$s2A@Q+4)XCY)m!n?(i?j%&YvP z^eP8`Y16BGOX)T`;8+)!jG1RFfv$^LCoh_=r!NJo!nZUx4WBV2Ab`CJne3PBLn%Sg z-8~DcurL9Fz#|gme8Q+=rL@9Y^n=|bo&Em^d&lTXzHR?I9ouHd#*S^pOL$5(lGdn#VoHhO)iSTef7U ztEmUN%mE7rRw)gtSx*zac>(D|cAZu8e4=x*I-M|}puje`RPNh7DFeKwQa4bYK+6Xif{1{-CD0fUM`FSNs#K4Izp`bLSHbdMX zxGCmyb&UZ-(L?&Q33U#k%jdR|Q|qL`-tKx%^`4#44Y`?BlUA55?g_Ci@p_FWk+{b| zjFgpFol)qZSn@z_SkCIZc-U8WoBA~X%#@8T=c_QRD{b_p$P?H3%u!9pH6&ptzj?du zAph=>w%^?$6qYNJ@I9QUy#E!4FLQ3%o+P6YKll1 z`zLa#drxI~atItn2xHg27f#tCZ5RcolsjC{pg+G%(PPI?Uz7S;=!P+BF4^EDpXALx zF4Jp%%A0NJiTzY2gEi0Xa$^RcKxAike;;g9B7q^?x4XL=xnab24ALRX=Wbfeos^~$ zO2j<(QsrQ$>Qx&l2`6T*lH0gwNQvuqIB{Q0|C|AIMBlFoPd~eE&yu=;rUe`{?#SIG~*^NaaBmsU00aoqCqS_Q3f{ zn*qdSh^&)yOrnFAf~vA)5;b3i9@}ECs*ZPGj;$OSON)PCDMK_xcP%ocQ7?lo3t)wuYI{tdPM*U z;&TDz3Kr&-1s03joIK92-MSr&KNDPl;z$AZ=S+BFPYEh^T1>p6b22)ukY5wS4fxx- zZ3tJKN5^Ob10M6Euys2`oNcr|a#L%Ntw^u58FQyg=)Bd=)(QV;GUsm0-AosziA|_S zhns;C0ll-M!KA(M`)r4Z7YB_^hh*8U=E8IpwK%0O)>^|s$&`DSw61K9Q-Reuo#a$PbR zR#)m^RxGQdOmuE=Y%8&oyaW4YGR1zz50qTd+!uP`GzWRILPU270fP|W zjf_nB4pv9au;VM0x%^DGrkmRi8#a*6#~mf~2`wOwJF3e(l^RbRzV7w=aTl45d$u#nKq~40mf5yZo)|br=23rWi$4^Imlcpp1t~RrriPcGV3XGcM1Dr!m%g0J zj5;*y@QjeKBt7_UNGUkH3n`*(@i@+%>qUzO9qMXMdBXKuLZ(%pa?h#)+dKQW@4q^b2NLme+-gy&F zY}2*>fH*0kw;BnqmOAwbFgny!P%NtD*NvWqSfanUW}5u4`8_@B{#e#N7F)(4H{we8 z=t%l zgdd-(G6F+Ma$Cld<$fq+`lZL>QC`84IKNl3&;ki0si?(7)SXw-wQcQ|F( zEHTeLz8zn|#^>cHWP?YpUjf>|!l{B&YRu@4PoOudFbzB zsGIf2+1OSdndC;_*1n&2F5MAz@<@*2&E=15(8tS%7lh{{Fm7NgjkX-u3=Ng?9yAS? zdgJN5P-djNp(g=4JOg0oxvi| zsc1uKJRNBrrdc~6b~D)?kK?hZjK^TFw7y`XF;QuovxDF(d{iJ2^{PcKk83t%7o~_B zQ2PEIv2_*_vZ;k^k)M#2Uh;cZq{$K*8;DY|w7@`hw0>}U5l*)acTzT<#g0-e;qCj=tY)djeU$k!~AtAlCS0`?r?GQ1lE{ENEv#kp9ME@;3De zB_3FY#gI%afN9)UIB-!8=~oT`YRU7=u)iE;LMi>30&CHOv+)G1)IA&;+i(B^m->7A z-E<5HpfupszjXd`e;V(JOW-j+tixuDed@(MI5IDT$id?xz^c5gtoJgM+kfP-#2eVe zt9)PB+;VKRGTq`DF;@&N9*>HE>TFo zIwjfAY{|aBSe>I)V)y(l2*l-WR+avH3qQ9=Bx>}$R@R8k))e!Kf3zL)?(LptW|uCZ zf#WrhLmBgXb&u)Fk0&o?7~9)*>({=aAyq}E=7xsA=p@D`OBkDF4MS(yoG#5k!9kXI z;)FlA@7PvWAx6S7$bDpph>&XDd4XziBGIBoqR_+*@d%`*)zS+G znZCqqsMiO%e`^7pw9<7ou2*bZUGM|4>dtxeEcV-SBH6y=dLI|@1OewY@^N%+E-kj| z34_wXNJgwcv%7ly4}95TOMGqxxk2Qo%#_m?CV)JN$~@sv6M=fvFdI0midTaCK)4@5 zeDmp1l5tcD(j|Tp@^cb}7@XMNkz@J_YUU=06%&%H=4!C`%$R`?w|2}sJ3F<8m4O1d z`$d@^v0!Bs?Vf0A^u}9obf5ho2Aiw#WJGKVn!;K~G9kZ2B&`_0?{R2~TFey?FJ}Ff zXz{@FGGj{ErJ@SLX=%nra$3cp8Z0?wYPj$svk)jR3eGZP1p@U7gEU; zHE@N_KHCLN36iGNQF2n$7~u6ziHq(tG{T#Q?kRb9{N3;du*%^o_WEsU&8R?1(XJR_ zXjrT|nI&5`hgnu7QYE5k`;B=n={0)lp>5uRf`aB(o(mu~S=h1AqCnI4&0EHGype^w zn&Q>BK62lf>j6|2pD)7t{Hah8uNO(BdTa#kqSswhJx!pTuPE($31d5CKeQ3)w5Z&~ zNSWM{?X%1+s=kC)l_@vkI_UCEW`vfexQ;jl9uhJ@Yk(J&teY0kgf2nZuL~<)8iI3b z8x8-~P0FOIu>NJn0CThm#T>ehaRjV8@=;u22K}{<#GLeGIo>$c`kbwSY(`fQiC(); zB|hT7>~iSTwlSAf;?|0sVnYkUUzDWI^c|3_%5K!D+gnWBMnNNQuz!Zc4FB}YsWv(} z=w(&&9FXr~j$Zb6E!-0EW4rQ1RjDI%_t3j7P7)(J+*=_m+adD`xehmb$;+A}Gn6_o zPZ#L7Bo(vxj}jP(n7c7XPR)f9ecphC^*B$~u!{shf9IY1K-*VkuR@|RYX+Vb$W!DJ zsc~{|EJh-|A$zSfUM|i_RwG&l!vw*%w4Tm)fG<4;Ak= zSZAV)&Xsw8%8edNQ_;kJ!tfze~ASaNdEzdkFEKm^z1+(*P9U;D}36St?* zm44e9V&a9=672%}$XZ5~X^44B^naWQaz7WUq6uULjyE2y**MCu50cFi&kjCNRp{Dp z9VYmuewe9IVoDK4$mR^NL}F{iA?tZOoS4(eDBEem^^M{XUu_qv)!o6!2}hqthT=lZ z6u$d%6JUpgJ`Hg3KIJ`e%j&cU_H3AJ(Q4K4?Qa_?kvr#hQrnduGlYKR(>LG7I{4jljz@WIXKIsSn^Nlg8+TjM$&hm?>QE0Y zxG>Uk3xB73b15fSp0_>I3d;dxvu;18;ClC&$?K_2TevuO_D*&S#((!~TzwdkOIy8a&0l|PNO^dV!nXl~A)+%# z$B9;a2~l3FuIayCTypWc_RgC&6z*teuKZ}?;he)yr%Q5(Hdr*uOjne$*OGCRg~5v?mCG$l}}OW zotwcQAokkC$yVJwzZF?HNIw-?^)W1BphdYid3$#C3iM*p9Vgc%?rk8~Al?WRiCI9v z!y71#dMq0`7opiLg!{+(Bx3D>m?7P{m4XeX+Cw1^8}T`SjT#oK5#ezAmTTHb90-pU zF`Rw_M!3c4vtMe%nSbyIt+kdIv4kziNLZZ6qo%JT0eriJmKqVc0pCC?#$Z|d& z*zfGcZ-H`>>1!RB{Ddn?D!o9BFk(X`8f;f`3%~H)dq(Jq*8#jw)ffrRfkM3`u|ris z^XcWhWiwwchZlLaFADneshWJhq_oyyQ$A)#rGCe4u$Bskz-|2Tsn$7E&SkeB&OH`E zDtL*OfdTR2;zBY})yq;`r#_;++r{QSNoyoev4Aj%)2Xj0+)AX;pI_+2hoR*waoL#I z`K8&w>{Y3FBbi|b%!bQ<&n=>+d~NYZNd`HkEtgQvE*7N@CWRT3>#*QpJx{pAhSCUi zcfPPLb_W$>R$(91Y4O$io{p$GuWR{U6{TsgnQUIHpi${{da5z=!C>R!VRk2=IU!7@ zJeDk3#8z&ts_I1C@lsgJifGwQrFNk*wxe9%hJP#=2BYx3uBoT%MT2^CJDr;2`?#5h z?x>mq^YGo-vJ-YNpB$eq@z%WU$8>~U7J0{UM?;p{0Givo+hA5s(|N>Sy@aMsG&kRR z1HZweRUAj9x05@Atk7C!1pkfxwX0#AVCV1xU2e_y3+~iA2~B-XS{^29-bP8r_+P`F zQ`>odl(4rWnrKZFp>iN>a`iePqrY^TqEi_{d>vAb5b$Xjy8U7F`Sr zL3Ld8ZX6ms&^+*(7D_6eX2|z9MB7eoWTbD|D_7stoy-XV@TQtWRn+BPmRRhR!YpGQ zGhSlLHd~GC)*Y52k1#y3lN(71kUEWUx84K`#b!^X8s|!DHrK#9G>nV1xYW&K{A-DP z-`QNibnjsMTh9TC-%Eagv7_Qp$N)jeJOkKAqI93#R%2BSWyfxO#f=+D#lK|b7y^GU$xi(4X_6)>C%nBn2|&Sa_h zb-fKfhFMpRBjs%iacg9v(leJ^q@ISAcE+5FE@5AFn1i+WpLN9b@#+@SpWadeI7L}2lQ!nVEy4|9 zQ6VczLcYM9{y+G)E`)MT+nRk>qW;4MLHxBrj!OU7plWe<%O2{Bw><(s|5fQ5A&>PW zQ9rO;(V2qGrJ-^ymU6>R@<2aq&0}7#2byg6o$yt8vi9-PpX{KFrmC#YC9?eq!o_W0 zMTqie<6GI^rzAbFNfqr(+7jBlJ@gA4uwmsT9_OYEApzl{q_CdPSXyl+-dK+-`xX>Z zx*9ZArkNo#Ob3ga@dUD5r%M2KI4mNQ{>P`QF5XX#22syL9^UA(c8PC;J)%g6)Me3v zbH(3;eHtm(qD{$83KYUtn17VUCil~l@FBatAZNdvL65wAL}Xl)@ukdhKu7X#JrL@P zke?o%g0p6$T;c&tv5`NqgD#h_bWS5&U;~&h2crrt;KVU4tBea920 zC1oag^ak^P{PW#EmjDrePbHX!|BuW6`;`AC=oc>oMQ4m<^g2i%#!dCAChZ`vrLSTM|8N z^`D$`Uy{AGceq{n|Haf9BK0aK)^-ZR1a3n?Opn-R0_`$+Eb}3JGFG?YTp%nD;gLz5>No?`7FNLondhsN1=3 zrdK%&L{!w#ubZWXPe~?E3=c#TZiNi!rcVWrKK3|MAeRuj{d-?cl2|WGAxpZIMIygJ z`~Mn{WXQAA5oIgR0jq&{@=uZ2rXW?tqve!vJ~;s z#X+eUI8pHV>94(K--SKnrD7>AMO=V|+?hutg^+{gHS>`Oo%! zO?(^BlM~P;S9qeXhsYm9@)kvh=CK#Ggy06B>4LZvK-Qry{g9%evjlT+)PY|?%7MDe z8lqc62w1n~#M*@ApYUO^C&U2W;1Wp({-WL=C7y=jX2=&57IVc)5pdeGk1c>ew656) zGRjRekk>6*LvI>-yK$B8Lz=Qt5iTb~yjp7ozVK^GZWpxAbvv8p+hpp9$LYdGUz4v+TMs@o~fKpF1IrvsfHMP!l9C@ITlE<|)XxIjGdh*%HLD^}*yIzN`^^%Ic04Ha(V{k-Nu zWbWpovG7~-TaC+MH+v|t(j5-NF?``xG z-^q@emYl(2f*DJl!&@8+kIeOL04_i}IWh^ybF{2*>#?`h61jpu3SW~yP z14zQ@zB}Do1bGuS*bCI~nm1<7W{np)MtFtpw_|+%hb{k#+`xZDZk)K}yToRg4a$V5 zv3RG?06R)la+?FQ{j>%Kilh?OqHS9Jd!^X#?X!eFY}H0q@O6wU-aT(^+J?TVp+{>H zs?@KnUDAho&QI9TVb5)`Z%ORnd+D{7=^R6zNDu{PzRxGzeLZ>a{0Pp1d>7vyUHW4l z!y9&-fWxQj_aX2ab4PFaWwJHA=(n+6>ca1ST5M$NCHS38nhd--2kGcZs?U^H^gV8> zo*Y%wWRAVrb3`W#{gL^y!Z#GhPApNB)wKI@YP5y10W3}% z$B}&S3<9#~QV#5RHkxcy3hK%NibNd!PQi(jV7#ybuBGyQzc<=Hhs=lIOk0;In3eF` z>lM17J(CBan0}1$0KTDF~No>M8FQv9C-Pu=Eo&1ZA}YFJ2gl4uSR) z6mUC{0L!oUFfDv6V-G9RZ5JY?6JSx)xwkq8=ey1@GDa0FSklD!avYD@21mKR{*6sd ze`#2~y`0v}tOIvh+bBpsihfm%01HLH6YOnsV*jc`8xR<{YJ&x~{hxgx_qPvtPpfnk z){P2TLgb}JKdVvok`WUMOl)J$DF&$r-dcZtu2L=n*6U!3#U4d3_bN&;=g@oyoEbp+ z$u2V#-)>4KFxfwRD=(Cz8j+QrWR8HT4Ws7nm|Q2L9I;aG3Yn$pboftdg6N?5jr2wfPEEP4F%K5)f6RvhQs5$i$PZ|Q0@Pt$+>wMGegLT@joUw z*XA$rvbwWg-eys+R**1@Z>;-?>YS@yfs>#bFDUJpG@;hN!MyRRNW8pNQ2cnXHlQ3T zn|gN&MzdxV5(ZFx+P&>OEyfmuF9n!8n`sl7mIX?Xn$l7a^?X_e658@?2}@6la5BCs z^I6@|^jIjLSDk4VIj2$I%8dzLlV(-$QTjh_dKru~tONG^MATb$h+cXOBE#Wzu1{cj zx&7hUN7@2<-d{sVDxqR12htb448P;a@%&7s>E3&qdKgvDmfIiciC}BV*m;M_+TNFv zMo9ZZ1hvonmvHx9E9Z9IB4-QB&2Aq93xjWP!4gtZ{nxw0NXW=Ddy1COG5V(%VD6m1aNaeS z4ybS0@|67ig6u~76)$~dCSJ24)iuJ_aUP7eg!z_E-TB~@JKXq-LcSH~#%x^OV8L;I zuUjs@8nN~E(1zP_AvH2Efa@S62CQYrN?5m*Wzqe%0c_Q2$+hgGvap!yMA24y87<8g z2neZHV9iVFb*g^QJ#@2n&d+qRp_FS8%#g{P_PX1?+3!K(UXEL06d^;JBboP_$>_Va ze3w`0eN~*;!iK`Kjh#NRTsPbaAEo=QAX#ARIhvB$?>J~@gw$+z$sdmf?N$Ko;r)HJ z9l1(*7*vE~aT~`M@BP>wv?7Mh;mjNDStkw?S829g=DER7ug@%#^;HER-UuP?1k#;n zMk*@4AW|VZ79aWas~iNkBYo>dg=6ze4P=MRNg8bNt4#Fik$}eoSv#E$_@2}DUcGl$ z0VqCK^^`vx*^%&@+yWS(X`*ZvXKoyB*91;zvN&kS|x3>9(#P&zLD;r>|F=EeDm+Udua zndptAK#$#XoM^v8;JH`_&uPmjOQ=wbLWcc)(pDM*X^Vl!h0GNbubP&T`?*jrZprXx z3tHSu+OZQbrLWM|3LY@a=+$}5-6macXT-!%eDieeH1A%D>YH6IYq1J#$GUAN2F2$e znZ1(tMxSSqjiV)K7CYVz76?CmyNgW^;v4%iV@BwTRIbk=RT{-g>2$_w_Vl)& zWJ<~?_pQfoSV*h1EI7Se{lO%@@-4j43FLAom;}Mc+vF`;@Jj0HVe#?EZ-t7z^Ycx= zqY#*>D#?aIWwZsUN+r{crHkMlMZJn>Md}=e`l@pJV&@3_yoTU+3;a{Nmcd2n$%}be z3&a(fR384QsI_S4(@1z{rsRbURA=gnSl};+wi8<<hTmjlV!{#BH02s=}-Yl>Sn-%CZG^GrpIGX2V$~ zIWL_wzj@RzjtpleWOGOhmwU`A&Ruuuy$$C@!1EDUDx{iw#%d__(*&vE6EWI0^cM3%0>v! zoM<>6%jUVF+$0Jzv^*oCV@GTW;2Wio@P5Ips@$l>Kr9xMNW#Ox!7-D7l}$ac$Gv+1 zE+;2fYLNriQAZN?2(nH=Km3=b+rx#KZJAL9AmX&pg2V@2yZCoP{(@3Q$M5sr#QqZ1 z{UEbHH7k=NFOjc5?}z04L1ey<#DKywI{k_px?sA>)v|PXEv>@8W-9iV4o;f;I^tFwwvKEX4hNS?E{;%oVvb= z0>widmmU{<7mPs6&McZjDtGgO;uE;*Mo3MbpsMi~u&NPw5pRLDpd=vL8QT@#xaO12 zl>rJ(ksXQ}6uUmzkrUU7B71XIlSKpY%)iy0@xvkPzZ`jE-A641m@-hdBU0qtGkwni)bX#bc(Wry+~tCSQLaOZ7MA zizs-K(2R5gQPnP^W%kazFP6!e>Tt8Oh>az>zP`B$xGa=N73R~^(=!C8CIt_}%B$At z*eQtR?V~m@kQq@4q*oLB=C8DMcphpW5m!qq6{D6G*>d3|qHN2q*l_bR2|Kos!cSVm z7jywWp{!;i*ZxA?>pKVxd4s18M~qOglygvS((Y`cD&t3;P6j%yn0MWen{ZsX*ZP;2 zPL56@Hhr5`Cd6)ZtTc_(sZDIl^h8d1g0ufW`mI1=>jBHFrv>pm6SU>{G?$R|Pzb`W z)YMuCNTS0!lvf7JEZ1l-GG$q@qP8 zM#-7A-o^RWlM_o)$zld#F>s6i3i&H@)Aa@T`$=FU%VKH~0I;=?*H)t9prOYxTw{5h z4}c|+=a{U&ho9LK;%d%Ig0_K}TV*b!ggD2ab7=N%H#nBdILu$0F)==Q5osYT?ht7j zX-k+~unKos={5TS`*t$|G^L@N!b8;XiWf0w6(|AhqOuaZ>-m_%A|P$z zD7^{9VU6v9KIt`NS2}YXQ}|V-9pqmq+YavV7E=Gd5V9qD`|qxtOw}to)b2gl)jm6< zP6Y8Na&Z3#>iN~fvQG|#BdEjrUd)R#@nawhZptDaketqQi0n|#?sq8U*@W7=Q|&RQ zbCTfj@h4PzI6Ig@Y_74@E|`oL_q+rcGrX8eKTj#=x)nWUfS=x{au{I6hY!6`hit+R zbi35d{S&0(8;eurj8tCC{ERBEa?s+c7VDP~Af+5d@r!T&ypR@t!q3K7$rgZadu?kk zr@6j&mC%um{gF6kXg4d`<~?cOv11Jrl*AH*+u02cxXS``8yxj6*IAv{qQ%|yihpKm zQ7Ss*7@s||U92Y%<(-a$8#&ZUh%^oEEZSz}O6V^)Rg3wi3Gq$;#9*Z&H?v{)0di7< z!D;U?90%POvTFf?8jHtKT4{;lUb^b1gC|E=f{kBn6XISyaEMJ7@oNVKYcJm=>D3NR zutw(iXaryJFj9~GNh-hIltted{nOf$53f%FU}q9I>&50B#59s^3F$E|5N$3FAo z49OXpf1fXI@mE>c;c`9|6%Qq>Lc zhD|IAqVgCQwA~f0cgU8G&y%ND{Pe)-N2o4FoKF4q>W_VV>xiI+O!LK?F;l{MXqz&S zm{GUN-sQbU#pFL#l@y|E(B>f)40J@xbzH0C5Qs|~BKNt8^eM2dtOl@bu9`BpsD!0Fl%8SV%lnDlig)Tq8m{R} z>Nmq;aRcvay&k%<;p@0X?=_d*V#Ev#QXr;e1GP0+=`=<#qz=}Aq~&DWr{oW(%@LL( zoRa|S(s~%!gyM1rOY59oO@jD`pDP>1u@-96E0p>g7DhhVB^BlMrz<2jSHihW7S1N| z>1l>k*YDZJ`CdTn6tXtYBrL^)15dT#w-E^s43x`@8;`^Q$AO;pPlI&6=@OvgdtOrHSz<^}_@wHh48>pmO4Jx8KF+Y_|wc=2=Bvuw= zsFH7J=8R^D8kn*ixHR&%&i3I_oYtJx(L4z%*oz^X446qAERUH9|CMO1R(rYEl0@UQ zR}QhE386Y~G>?ix_#@6Gl@%b1QU67f9nV1QzPp6VOTSVoQ{GO8EC2jRFc}#+BEoD) zRmli-0KUMnAj^*uR2Jd~&wWLcfFaO_?~ zQ?ba$K!ro~)sn9`BrfscD{@)dsR(E*y!#^>4{UMn_$-kmqh(538I*&XQY09af*My_ zE?fkR-qEC#kd+l3;B;6>T$xs8aL<+udR*}fz%&qrKv3Nq&&hkG|N8J%Ow-HEhWleAI8*5BVgMH^Y@a7pWJd6?MNq?jJqE4Z<`d8`pr%OXVJM^3DS*X65D8 ze+Zo#GDN$_9(~bZ-i=Oh(c?{J$MR@uB+~)n79#L6jYeCDO#Lp zPYTAfP~KF>ZlGeyZ8s$CX+}xX7H;Xm1Y+$Gsq&KaHjkE1>0F3t6H5=-H6(ae*Qp}X zpuaOnnGWvdN-q+wW;P$iFX0xy;cf6ksJM@%IE?6ug$lNgKxlpK)F=ia^p1@PQ?~ctsRShalV# zqU@&aOlcz~B!jvb%}z>nq13n|T@wO$?c<}OVi4Kfzs6&mH9|C5tg{`XS#!om_5q`* zPT&i)y?kL~L?~9CUMaU$m!CLs1JGkDUSKdUV8EhCrA=c7%u)6vpl3tf!B1Gb$B6zP z$oRb5Oh-)B`3V&#TC`08n|!y3u~4Z;Gh&g1S;|Sz-^y~PEEHwg!%x!RiP8@qPV(zaNPjDH|5`ROF~O)m)(5*VY33e``3n0v!}byc8Ri!8 zu2=e$NQc6%+wGsP6g9L;V-!(^VDVMZHMdRvW?#0#sJzB)+|H57-Cc%1s z?<$-?{-a~%w(qZxDGXP)w+R7CNT)*SHny_rNEtC>YU89HWxktDE?LsBf}lHn zdJyYo)M-O6Z(C-1dAdgkY@wjXsYflt!h!7+UznG(4}+r(cvcp_BZ*=jv1_jXwctcU z)5l@Sn23Enm*OP20s+&1qJOxuU~?C*%TlktqOr{ZU`Qzp>OES9&(I z`K=6Yrec$Ca)vFu+lUyq5$V4vFc+4a=!)5mHoPVyr4HV^$Ufit?aS6*(gH%1<4WE{#b7Dm^5t_>F3F*hWgtJVE2noLz3{c$oV3Z5FZXnOv^V<<2~?Q0pUK^i7;g*mz!s&~g4- zC&&J@r`pi{<6Eg;SZLO&Ya#mCuds=F<)I}5NJ+ZGSrnv48$RK2?23M+-rTw`hbo$2 zCnr!#I6Xe|f`ibJhu7l}!PE1evxdts&LN!t%%3}mcjX4^cgv=4B(KklxHJqC)tiy2 z%rhmGb)_p=8MovPP20%J{jYLs?=_aq-ToOo-uY+*wk;lB8Z^U}U%&WUJ33l8b+Mz< z3xShsSywnTlXbFqH`N(Q#%JaE%3ESt(R;8yzN&qfx>Z`zq%}U1+4p}_p4Ck~$S96d zk&$j%NKMM9$Gn{WzBFo&81$FFBR@a45Nx+mhj^J=lk}lDzIu|90&7_d;lTTd$MjBb zOdGLD&nQ*Ns%u$3*CBkP^KKUPp%{Fr(l1VYbmi7+;I)PDadS$?pws^OFud^ba57uz z9h&3;|9b76eAwiTCgLPLnaxw8@N|2(%Yvh;b3jnDvfx{v(ap8$L96bt==Vh=XnfH- zaVdLhuR0EgzPUUx(o%~mo$J+b~firtI}0XWqU;oFKPM5 zY@@2j-Mgk?%Mlp6h;8o!R)3g4flza#)6csN_JN>QLM0!d(*Ob+?&TOpDou5lF>N0t zdIFvBSPK>R4J(?+c({}<$|!`;3-jsdFx?*nZaqL&>C$ag3dl!4iSmTm6}Ft8xo+7yU|h z8h{PltUM=N({ad~W?=P0x~Nbq^WLKFDD@FKeL}Xrw<8H3T6Vc$M zHfuuQ12W0pY#5!0)W;8^O@ll!${Ks;BYP;W9m_sh$jJV_Qhn%(-U)L)P#OaTC3YQu zB=|)&1VTD{NLy|0D1^<_XwsQ3I@vJod%1XS9^FZ*UuY4V!RF1=j5WcPlRB|> zer>{*L}PE5Gg?A{f|YrnM?b_n**;~seS6mKnGa{{tT$f6G$xVB$U*7Dh$Q9-3V)X# z41hm@;SKDmU5W{+!`6!q=jn?v*q=~$zAj3L?@<)=*Y3zwF=;4LbkCcKi$m7O;04b9 zBve%N24y8M8!u_U_RR_<@NHF4Y0)YY7_h_rmN9*+PTdrIz#65ZDOvd%9iZ2P9#5JN z^=~{X7wK*rAVh-P4#-$f#(#1>Vg7I?au&1!^9Gh>G*VTS30*=M2-lp1 z2-m<-@=@(W>DEGb$0izG7c#h4^TkHNIAAJ2;C(Qf<4!aAA1wo)cAi5LmMQME-M7{r zAvj|OU|VQ}i^C9eqYvy1Wvf##=F`3Pjj7v=$p})C` zab0|Fh;<%(pA^;~4*$-XP&$MO!)0sEcITSV58nQ=CD(>hOX7z5A?&5B&gw{H5i{_F zOZ5UO)Vlxrw51Rkhlz26bs!VI;}ma+rRY_lHS<_pQowYsBrpheMkH#(6|8xGr(bY) zGRv^+T{1RO^^6qh4K8khz&D398T*0|lU1zr)cuZ8#DcB2S2ZiyHMDd6k&O8u2=oww zG3^VxJTR@Bt$(hY{e}L9Ut`IXC|30|#Ut84i{76HDHw!*KNtU-82L9p_qXNP{QL}j za6gDUSAf2?3&$jlE-6o&y0BV&h7CPWl2Vt~Wc{Q`shI-5nW)G4WJ5<^^ecmsYX0NM zVItCSxt7+jmmc!Cc?Nn+#kC@u)Ec0&>$#0Yr}iiL7{a zv!HLXZm_iLz0RUBOxhJZBZS~@6Tt+1|2(t5ARr=~JBP{|XE zY3`^#ELk2*#)+lb!21M(ECOOlz8hQ48O%{=kx&TIbN|Yn&IJU|BWgBdw}_T&AWowklL?Xq_LDagX!rPyu|!- z3+Il|L3@JXdL}&L7QGBDq(aXvuNvZ;~`K zy;tvH{*y=JqW?B8Z>sKVee7_O4)*eA*+S@qkEU_hSZh12r!y4Fi3eb@0j~XI42@mT zd&emiQ(yb3PN;2y$I^av1VN+KjT8G}f{u?ZOtTpwG_nY46vq0wvnEY>3(=0$P%>R2 z)Ql6UbaQ&#{w?_L_S3%|{ono0j|cjcjr%p2z8L$JJo>m!r;ts+yh)Mu~dN-7njiGj4Q&JWPQos`_U?ux+IcHc~?b zChPxX;+lQdp@?tRLJ9#Vi|>W|{jW&@3Jgd5orDi=m)Khi%0H&ktl5`N_a_2bf?^h8 zCs4y?X3VgQA%<2^F@9gtaRK55t=(fyb@mUxOARWU3pI@TMlppi79u(6P_^ho#|shY zeA~mDu`g3~N=GoE)2$coVpgME5$#x+j%Evs5W|XwfMqV=jRN)<6jf`Dz^nw_A0)IpG(kxJewhEF zX&EAZge#~Ci5VH(tw$}RvH4Q*$*TN6zTPRiuBiL}ZqT@~ZQDkpHf(I2*tXM{O`{Vx zZfx7;iEX2?lmF@C-+S?1or^Q}+-r~AifraLdfE?$fCqXbJ2x3iu2m&(G= z&HlDcy3K1S*2_}|spF`$RMksCDw9Br!!r~q!PloTGjZ3q?di;7rQzr0{6u!9%^T-S zc7d{8!wQqJ;KZ8Al$EEeOf)ZmNkfpCT1{h~RsG#mf3V#jHJvAo;&Qr(R#;fbnioa> z_*rwWXqB;C@YY$yE_vP^!|i`op&e16d6uVC3&Z5%y~bC)N92>qXAj}g>*aU~Y5MLo zFoj=xz=`0I<;SV@(~TGu48>FL20jE>cV73YI35&TRlJwk9=N|%E1f=FM7Cmz5)1(U zW_^=Gf^rA9D-CivJMkAE^ETjb@Uqin6-p^X!&0;UA_qm&77ll(TC_w*3Y$~KvN&`) zh0SdIiB$-{C;jgx z(ivfe9fJ9Ped-@p!4Lh@z<;90|9Pl`2eH`SOV9cAo*Lg>qgWw>H;01OZJNA~QTMm^ zleJ(pMWZ@=G9r(>so9M^7% zs&yaq1W$!PReOt_Z0hb2^hCspmk&exPup`T*$(#nklFrkd_-$&@c$^^rjazC3CZ1j0?ngHLTou<@|QG4v~a^_*-Mq z=_WK~(qgghmpwM|QVdI6saRWu2_s{f5swLF=*r6B-V}Q&|2y2zHx_siOp7Uy9h_j% z3%oI*Z9(5`$=u;~4J=+kHlV4(hiSCv)>w_4hY8QR(I*5l28-Cw1&JEgYxMS)64~zr z#H->s`Y+QoYE zm-^!JH5O4^6pzy*^&=b^{iV{P9=fLBr>^zZDim7P$Rg3r3G%6%rOnI&m0dgNz>-LU zU72GOH7P;+>EfCov(M!=Ualt}39Jbgf8x&uNDpqW1#6Cwp$#fn|Kh8Ln2bS^2F#F0 zpDttRWy?aV{Nl@wJuIe}PFib;?aTeN5me06N2x*VwfHL`6u}HdeQkV zlry5TCH}i7h1BMSrMXcs)y%+?tq8cjsQs|+P&S= z;M}3Z1SF3g%I=aA625~K(8*2~tEs=I`~#g5M3cQg;NgqauK!8tEB4LuWTkA>P~r)C zyEsrNEhDr#pk$BOLCdEPxUhC&rXE;l`SwLn`?s_)R!79`Ag90o!^vymqkj+wmREP0 z(fB(xHi(vlsyzauowX+iHYmC1>uV$4S3GDn^GflQHwskzTc|QG?JdJuMi2hAusv|C zHbYzl6XgnN<-8wX-6{#P-5cr5H0T(e{4-5Y&Zu0(5%h>9WzqXyxx6O`q?Y|cLamTq zSjyr59`VP;^)pQzxMcn=bADiVqClf@+}pDyR}lxNOoh(2__nxojRn{E9OwETvrgMg zk7$6*A(X|2Nr&lc{14I1EOBt`JFAlM#LA2*XqIccBkQcodoQdz?k_x)!78Dj`!Xsc z;h~8HKAw=@Dc-R%y&?PKaU#n$pop)gafSQ#60?zI!L2xe&l~*Rc$S(qvIPu|mx{%j zpG#a7dWrLICX~GBbrXEJ{+`VOnj_$%^g_58$m3hd3433*sX_<$yPxCh-#B(HIz6=v z{6ZOR2K_q)U^zIn?}XhkM->PMq3+!agv47;gC$V{#lFLI2T}4DDP|80C(t;)y?AOS zXlqGIhMW(cCHG=tW9R1QLyHuvI=H%qfRCA8bX21CCeD zAj~`Fy?AXu%1N0GieAncJ~TGPZV&(4lVtJCpiFK49YMWey8d%}z1*49WM2`3fp{nO z7aMyfb2J^&DL>S|%5KN>?vpYPR`;nuV3VO^5JE5mKJ9Yza{_ zi;c!Jz|%)o^M|jSSAafwNUKlgJAkFcx^SctI$=5V;DX=-xzXJLb)%#h)rI_%aEadwz{#czOLbm^3cFCC#Q5{;Sz>|QfxjRe z@CA#4ZVlg+w*U=AE0u<=bc zHFtwR7*@;Xy<@1d0Ujb#F;`B4uQwohW_zP2bxN}TaBX7avkf(WQ1_olo?DwLKaOum z)CdO@2xn$|9&SLP;E#Wn`8kVdxO+!nA=L}f#cx|=3M-Li3JrKR^~tn_TJwY<u{dO>lXW3 zgq2O1$&$0Hn~hr{J3Hct!0v9_SC^wl*?4~QKD+Ku7JkUiQ`B%O04p7tvoJjlQ{U`imyXiKvRxT+t-e{ zqtw+o>S;h~V*TM^Kp1>{KezpxLd`y@kpxwm)5_#Fl3mykEAI&XLjlbTqiXqU!MHyR z2E_y^8y5y&YU>}98Ae`@>-<3&hzr}`NOiV@bLI~hVz_7-0f)1Vn?u)b#)a$zwa?z< zIp&ng95p{W{un`r4IF;HqO25|=Hd0jsc~YrOj7&gpYn|VOED(K9$eXX1Ma%ajBM|N z0xr(M%QhdWK?i~)43=dnN@FhF@Ul)vK^|FMAmMc6U2`dsWgOL=B8uUznQDS?rArAE zWdmcWQM(@m`*uZh`-z@j&%V@~?%%ENpfd!VlV>#J?l+L6J$PT&;Rl<5j84zk2Z!QU z!23}XgFs)JhaE3;f@D;N+fW>nGk>RSj}@-L(9+hs*^XO{>zsju~yi~QSaL2VAbO>llqo)%Jvy{ zKAvGe3?ev!yA#o|xE@|~yD^CxlF}o~*OGGxM|2YNc1sZT&H0+n@=o3tpSHHPO#w@E z>gmaa1q}f9QXC$cy6MYdUfdrUO<+SIzL&+Hy<=KZ2ZWclS5yTtj0Q&?QkDNd-fw32 z)4zGY#A3oh%aHqj$=_L0?U1b0TTUl#MSVRV-hDrK@~YNTUhFm~lMRZ^F@6GRWu4VsB>I{Cmp|1?eO@EqN~p;MQe0nKCC-+@ZP z{~*p~OaS?1*;L@ha>N7Urrz6w-|c+XarfYWoJZrC!BEKpaiGL2%JlnzL6Kybua4MC zAmu=vr*ZP9EU$Ig@N~Gi)TnBKGdP6Exhh9usLsm?PBo2a1U6|BDSoys*m)^(x*o*$ zAIVo-4=(ui36zS2Lwr$XH}$j;si8*<*7<`n2<2~eejkWub;)(T4ezexdGkjKdNs#3 z1=msXi1w1ZWJMio8+uMescYC9jHH~9q}q}hzk&rO_Cbx55Tl1WPTVX|)oVMOd}8XK z)Cb)~9H>k1a$8zmK)Ixgov6KkLQk_u=BA;4{!!Mm}oY2k&JHNDt4P5jnH&@;| zO3K0ehOs;U5c547{2g(~CLpQ3__Na!w%SGm#;FFGw1yI?rz5K#ur9KgDa3$q>?*8E=VH?(`}o6VlZu2OZ-mDp|lmu96qO zIZX1lz&f%Xr#{=WwK)e{oLK1WLcbqVoiM|5rEv=T|{L7_cPxpHe z=F8zcR^kx*7$P1b0Xb-E+`XEO8c*6eDxzcg^n-M<=nQZAg9{)D~O$ar2kQ5(taPQ6VEI(YSnkb$Itn^ z@uK-9>mcJG!@wXNG>aLo{w1m9n^Ri!ceKL;*zHWtdXr&v-Im>m^}4Z>`M=lC!|h3) zaB;3rX^WHqsX?Tg;IiU1?87jz1!c0YuBRTb$*YgJF!yF`7%0&mr)Yg|2LwLeI>M%W z$ldpG{X1&a4?gbLv28jbi=V{lbY1uO(Lv&K4YYvBA=#WfT`lv~)m26^cv580*H$Z? zYbuVjUzV{p_N|dDyqhOwkLo<@pH#-;@Xn6C=-k0<rQGJ6-j@g^auU9eF|A^`9dY{Q^D}`bswTAbH(ay!mKKM|8yQLohqX@Qlk}mInXlY zhw9?3FIu|cQM>E*Jpk3j_KA;0)sj(yorQ zJ>=_peAy2#REmgXhO2{ucEPj}_${xZ-mMvcb=gVrXLMx;gU3*Otk==pAM{eKs%SS>F33QzH<&wNOm$wV90b0r<_z}o zEK528p4gCs1K;OU{azcBhP<5c&kx_*_PO}n=(66k2fGHlBK*p`hg1{ZB>FHYOc*8# z%s<&UD>qCBQaHSS8726}*D_^KEP;s^|FJVR!iadhEK+fED#W@g`CQxOJF=?y+W3h-%k-ks?7N9MfD!b~E&I zO+wwyJw{>3m=njbvbcrm!vb7bOL&){weqq`zK?=t%DJmuHAb;@}`%_f6Nin&^c29|%R! zIk0kv#)W9h{ARDzT4bHiC{%`so1XY4hZ}K#+TG^N$49e?CXAvw3gn4%NRnZ@s~8p= z!swhj6ZJ6M?Q?j_n${=Jm$C#X>M`~((W@sMckIMxVT#EC@Btj#<Y zc1;q3{@WF`9!AiWWwWZc>7`Z!8qA?RDke9%MP$y{McWZ*2?kx-UeTcd!qxP^g`gse zhj<+aZtrAQyK;Sr90=KxusegV4BJttyrvyyD*juY-wLVcBNj9GSW>e(d%mfLvj}TP zR{`m0kCI}TIys{HJzeV^7*!KH0*x&cX#B#)LSN*=Q!zt1iJ{f86xzSuwkqN87~hdc z4=Az{L`<7I3B=%%0EpOFn$E8)`5>N(ASBkHC_D)*!_;jy#MgN?B!~r+KFgWFr@q+D z>ru}1Bl_(YVm|Yn;C{nf(Bd&14AVjT@qo~FM0DOJOjR-X+$K;@DBjkxyyugcMi%j8 zRcCsTVwb6d5!bc(*7T_P@tosr@T-8%PxyzAPs=K{v8!dxEkFY6)Qz&Q;bN#3VQ`ws z`71`__{}mQbx!EbeTb=HOkqK??qq#x#Ck2$lGT(#31U3KXx-+17L5fiRN-zQ)vbL> zfRAQ*ud}`Ff}Fy8-P|xb!A$YPpbf%Aa4^p~97Ss657k7iYxbP7I!uCW;&aa7EO&(- zZv%XX!auAvJnvA0DPvNnG77cWlAeF4QKNh=Lq6D1KB>!dw}yKUC+oUkDo+=m@*Ik3 zCl{=2hRSb+kwk&0|zb!>RI*TAs-$p|1Pk7y<^1}!O&;X~8yW(^Ss@>R)O4G5;kG3|o64EkC9K?|fUr*{mw`o> z95RRRU+u(v-0Yefc6q_r%C`NJ3Tq9?heI{({W$H&XeuQjzbpOrVHq@HEtCE&)~j>p zNFyFWXpi9TF4i*j+VH$p{o`ufjl;1eWkch>Ex%f#u$oRprR^ApR=jid*w1L5^H@02 zhzc9)jeII-pIT3%q-X4^0GV0_bZbwrBdN>wBwLsRRq;+IUo9vSaFxwV^qrHK(FlgV zLYsf39rr*}VGXwPb>TMm-L{!1VeA|E=zPSO=Q-u|4Id(}$jFF)9D`5iPXe`e!RYF` z#RGC}_+^C5q*MsEVzTAgM6j<4gK;eEf{!{I_a{^#6AZUMy>ydMI< z!Y>k!d;p(w`N8TMgfl%SD;>zkL{#Jar?my{*NOmU47#ceoEf)7cDHz-8FC>~hM5qo z+1Iv0Gmr%*O-I5PK~1=zhcqYHi<~IQv8kU|hlOnX(y^I5E03MqkY~-GSK3S5Y~-m| zgzbm4Vu0np2%voebbL|7&+9E{a~LUhwjSNqVo?|;lND9Lee_lbJoQn{ z2fRXBLayOQh*Yk|0QeQ-#o4#@zCs_p>e66}?fFUkY+4b5KlwH@jghtB8Te5dX7x}~ z0M|=qJuL(Z$`Nu54%Kmzy5J!?ivPVwfHJ90JhvTCCyRc#`a`%XGXH2nt#b9}TKNS_ zeD))%EwRL;qcXz7nd}r3Q@n!oZ2qB65Q#2#7>Iq+cqs*Alp51C4D6AR27FZ)!~D4*^;O+$i=wKO z4u5-Dw2IF2r`AQ0s=lgeeo|&)eq?B)g*cmmOGiX2k=;P2cKy}T;dv1M;z|nX8pKH;vmTWrCPkAZ3qFdx5Zr zj3fN$(rN8n(260c{flGW8F8L5M!@XYv&WEMiW)fvKTMIBH)20)FKx6tp%r3W#IyQB z>ygf^j)LQsy*D;_~_@xG{g1&7FAN)dIdxNc?!M^JlpVx0smD5?T~L zQ0A;V=F>>EK9)op_B$ORqfVSz>9FLZZbr#hhBka1O{lxnx!@ZehbmfN%&m>Ctuo`u zOwGycg?!4IB8TDgA!k#a!#&Xqw~~%J>Ul(u)Cm`|1}g|}%fo7}B65#OhIKU$?L0O+ zVCW&ChVLyOe}TZBlH{mhhW{NOk@;P~H9#^7z-p<$eus%^`FNp!T}Tb!D=U)RA7+k? zsSmcHQQQ$+;Iqfb`jn-J9L!eiCzep`J!q(KWrjJu+G)ObeMo{E?kZBDfJjp7j zXRC_ueEc5bZ5S2@oG4EF7FY;90nJwBfY&c%9^|{qbNdb-E#kJ0%mNx zMndSj(L%BNI)`R04T)q3-5iJV@v5`j@IicxH*s=G(Q^Xt}Xvn9eODa>}c&tD*e zI^Ruw!vrc6dj|ySm*(x`C9h41V?GUdh?&rmp#~Wa3`q*`KvPc!Rvbu8OyS9c5_fXQ zT;q9zM4c(RZqi>t@vF1FClbe7?t&t6Cs&|U;zB`>obM!s^qwR@b8kO2w)SyM`pNAD zka(q`?Q}iPk=*di72+@nL|f&0c9zZ|-j_*IFW_gq&x#*}dJmhUvPiwoa}M;q24*FDSKzUrRA$HlNK4HV|vwA9U{mhjqOge42gm)0I# zX{e+|U^B?WDY93Oo0PDcQaUUv73ymLbSa!LtK<&Ryeb-=N&JB;=}0c8Rkzk_X;Lt# zGdj2zEx%?;PZOC5#5l`w#-=8hl9vchW7cai;r~;~BPU*d)Xhn6ReV(XVocpqK3eB9 zPgJPf`w;`JH2EN?_{OLBD5&3#H8E`>TclE`00!zYlLwF4VG)s9oUS<~ZAX8qM{8S; z)nbdqVoSB9!u3g%y1;YY<#?73RLpTuzGvjl&uI^6udAz5KnY{wckFT5mWb!dJbqeA z7BBr?;P>QJ@?=moD|yYp^-b$H5_a2S+@%9%W%TID*kokAtyV@-b@iIa`-^k=Ssal- z;g&D>t8+PWG>31Z>Iui+?qE--_f&J0n&!9no$qTB0(^yvBCoSI;O{)?hd&WiJUp6? z0%3_+V~7OiZ>GdiQvIG+Hqy){GAx&y9P=zklbH&6Hhff~PL5dw=rW#MgN}f{zf@9} zadp#N=T+TUdogoPM#*MVP^@->$ftSbka*%&0{ZkgUuxvGFz3xq)d@NKon97iIe#*i zB(oW$=?D=YrCCf2CAKfSAq^Cnr-Gali$)F*T*92O3fw(>8I7<3BZ6iX<4by9msfw} zCnazQn#%loqP7u`+*igRVyR9Q7`xWx9cTKKURsktZk3Ni+&Y`+D#L}4(tVj>+MoS> zv9xxn5c;_$l;&H@zGmGIiO1uEX=N2aj>_hf6C8iVC#ToL`ZLRY%^RVuXiuhNI-sy;G%cPh zceH}M0?k-YU=5-4wXm0-t(C3UqhgY)bB{1qAU%;_W4ld=@b>Y8ijP&{UZxFQROu6H zkHTQ9sa)!_o@+Z{3}WzL8apFyvz588|2Mk%{_&$#3k@Fcv_iIl@AO48nT=rxWGx)f zhu3J-PYz9Y#D&*2)Y2#*x0l0L;G1bngRl#0SV6NHzL1))tJc();9oYicHZ49O$x_@0vj1lPRe1m;+O)VvqaNafH zG2gTI_{0LDTvQR!!&mI}Uez6|T~#*A?=bo0i9mcaZDQ{$Dvh_;tmL;(H=8%@zH4P4 zCxeNDW&LPyawh&dTVcaoE_e^Ji*5C^tHetbCNpfZ$b7bb;;BIFq$xSnJG3ZE9YjJ2 z92jg8uK(RGbexexY|=^Gqp@aYcR#ED&LJV0^aG z{)A9+UzO{;7yd8-5#jsq%eDNgn33`ulbp^%uE)#{tqwr57j?@hGSoVa>( ztUMYOjCr*>EkJ7a@Upi$srbbR-|Jx5Rl@K*53jbv1`WjYek4D>IYwt|TwtG+iQGA) zWFLz~esA4u_*ISTF6LV>Kp4)_+tLnu?Nqi}g2z(({Y)exbc#w%eJ;mY5jrGPd$b4` z8dYe`w3m0&;+psUW#4|j314$wLMK8@r0YbRGL|Ab&bdzYnPJUy$clt(i#`Qh)UgAm zF>pED%I=6rIwsO2Hy@m!%%U}CZ78G%cxdwb}kEZE^U@Ix>oLpPo zPP&;fF|NfSd2Us~b9M~OU(0aqtuhq!Dh?M8FO5=6Fys-@=jCKTvA5s$J~pso;@(>b zZ>y$PCUWKRcz)pgV6TvM;HUALK7oEj^Uk0AJEz+tzAv@p9_X0-jlt1fD_e@>qQ2g_ zSJZLdU3b3RNb4)3*snQ?si%#pa-z>XB+;32>w8M_%Emw2{VXkKx z$VWcjsT8J)Q~U^^pLV*!W`N_-4~`l0`i;pwb6Ct3FQ=o=eHe9FmSuzJswOVxTTFrbQtexIB z`_AiFc~&DIn@!ZHe;D|O9Zm{Jr$0G(-F7irbV2HswOSIr+Q!ygwyCofzz!CN*pc!(Jzw3Qz$NufF6lg6 z>th6u^xsd5>WG4e+%P2*qbnuZR%2&xCa`fn7sD*}a9mo6&u9L%qMp2~vD+ctd8O3P zXoIKebfmm~UVMb=e{2LWKnFiMhA0SJgD@)Y%o?tH8Qy*R9aEU~rfSU<&m#NWV7{vk zB14$@G?jx}?Va7Wirl?QNY1q~@JxS%5EDg3g@*q7V{ryI6arh`9+Fn&6S-Brkow^2 zUUb1TRbPCXl9?&Lk-{1z{G&uKVtfHmy0U%4GgOR-*)-&Jouq06Zb8^|um3iX{JVwp zm$}U8O48YC12`U`aPa%+*;eYe*XfbiIeQOCXG`f_f$jWry8iJ~X9ga<<#;*hi>WbW z1Gkw3+CXHg(Kc|L5n-;`**xabXg@5K_%*M`S?SjEa9l(All@aNtiOkf>Kf{%o2pEz zmd4rWSd7=Kv|Q?u5l3V5m5SUCnbFjWD~ElS^Z)ZEYUmO=s)GV2OsR|gp|Vv?4U~gl zV>0H|0^YSw#(F}8QmFz*W2c3u;2q;dZHizrgD*kBD-$c~!zGU6N_vgC6ecLwr9L5V z0V|fJH3KI_Cy_jcu4T5(MYM?UL zZq9AYK7VUIIUC7z1rL>iWqfkIVpYq$|4rs-yka$x#Ft$=Q5?EZA@g{uy`29T_B%i` zu>wfgK7ka6ZVx(n;vE^|XDC=n=bD58i%y!5f+?rK>dFoatE-(fhT1entpyH_$fN0# zk+H3tI2q&dG_I+*Pf3GwVJ;`XFH6))ZI<&~6OWIXLh7VXth_BzEaT=wM0;hOuXcw+ zrIUeNsHpozFqCJYzz9_#=iG30H)9Tr7O#Sy5{I(uJU4$;59FdAdc6W;dyVtkX)VI2 z{u+t7*Z?aAEafG&mFiaZ6FdTQB$P16#8BU-5$2ZvE=4%Vav}&LKW%SBF2_eq$I+!j zc;oiWwYdsZ4$epjKrO%_u_Ds?ui3fO59Tmmz&Hf5u`uAD;Jq=o;7q zoN*Pz3ydqBGX_){e^LSLKS?L9#3X@tBQMO}UN>{Iq*fX6?5rycy??Jku))BFfB;qz z+nl7ds%W_>cBni!9qF-{D|0;|T}p0-0v?9OfvMC-wCcuCisI!Ym2YPAL_%Ks(vK%Q zTy2=>D*tO~J`ilFJdY@?98+$VUP?0cwxxq~0+$RcyZ3lJ_VnonAF$8P3T0CHu%B?Y z(r8WYb>~-cnz8PCzZOPd-!`pQ#eFeoTcY75kUrOIl(?j?;persKISHU+!Y9g%W3gr zKM5SCmd6AC-T~jWwFy2vKMO=s+x^$wN#Qu@{>DbSwsHa#`EZPQbfhmGH=mr#%() z&CR?ChnVI;ZM3l$HK2if)Zh&MNvVwX#`yzb|O9jomGA%k(o;E)s^9j&S)f%Csp zrS;cUwG8ciQ(47Iaj{GrXq=V|9vwfadK8?jrImzE07)j|+)<=r3AHNAw1Q(tFD!V9 z_2KKQyY6g9`!(z)TzqlC`9o&0-|LfQ^u$(g7+2u|xZkSO{rTGEr2iYng3EbyR0{Lf z-HN?CcDvSU3=EW@pinv$%diBhg%@-*EAHCX5n1KUK#%r*_`ql788m2Z5=eFxZpU=Y z1KX}BmI=v`7VmhqwCF7+346TjL{W5SkMDHTkk~TKp-`wTPWDJ;nJ=BV5vVD}J^0tq97t>-M-atq` z_8<6l1S>92L%O^#dgWtuMOJ*$C(Pnv)+@$j4wMhUo)IfEA|O2Wpv#G0f7j%3N#61P z=B?Z00FjiGwA_#7`+O&vVqFm!-&3`?{r38N3EsbXWhQdcs~u40-&#@cU(Fz&w4SPa z1DFXJ5a)kczte^5`Qt{>+&H7v#CYQ&Rtfqslc(exS?-(Nv^g*pD&ST;*VLo&rE`-@ zFH8nHb%9V&;z(j)dUO=0tdhI0pE}^$yrF#vjLPs3+$gyA#7_l`B~Ug5Q2B4!qHphu z&G87>nyOLL*ZomWI+&mZeHMLh7lj+Q8q~lD3?tzQ7)1wrDs-Z%4_;&N{|tuYlfVt zEKv!-O>CVZ3b|OU4r+_bi3DQ8`b0)9lV)B!_rFw$7>s9TWFRThFg(I&@A-pEoy(%* zYB@_0EqWSo-VvQUD&5%9iTjg#{I`X(8-#3{-n%w}$l2aFNta&bnQ)Ij6D`DN@p}+HWk6YKXB95Y*P*>7% zQ!ZVNb&>dn4~d(4M;=;T@5OyQpwHXRyiz>p_ET$ZkO~capq5yWDw!;z9u8iex!Hst zHCy;Ga`Z*E?xr{&lF%G&_N+>(C>#+04a-<8l<)--KX~GtlwqJrg`S<|5dYXYup#ht zh6?96Vv2mIuD%EKzTh(E()hiKF=nv->OSJ;1zZwK7?4O@K#>a4WApe3WG{zhg{x-h zv0<$Dc@R@|UO8nco)lFOJ)n~3j%rGU3?K0WBN@MEtdcGH|t@+jjF8w;AC$86de* zX4AQz-Lkayluj2B81?SZsiTPklYgap_GhZ$xXXW+ASUs^Z{6+`r)W38$9g*FHLhoJ~<^NG#MG0KfVgF z)D4;%1F&`M9T|Ub@s-)d2(Vq1GwT%m6Yn|4Mg%?}E>v`xyg!v!lpfkjRyL_ZN-*}7 z4I8uFRG>;2F?0x9L}@?bk+PkXHGJqnBwntiYEcg=V`Hmg>0SDssya_7hZ5a)z74Z) zvijW|cnPoAw-sr_sGkvS1ER~9f{3CP4ig%HDO}mKkh1ZJ$IJduHo?@tyxad}9q{@5 z*n^Y_-QKn^leB<8oey_(wp>^5xFavGn%oonss79rFU8eHRq>c4qVFM?Weo>+rnBBO<=9;vm7qEN2;scl&R5c6276!@bLI9U|og_MZ&dXmgvy!_a+Rosd5oeGK)&LvOz zJgw^Q0?w7lN+6d>p?eDfAy^dRSr;>p3A6-fe+Smj;^N%`4yOYGVm`!&%AU<`*ZSj$ zgsqro+Oj)zkfjSOALk{vqds#OPv$U0xfyroAK#@_8-9u$%G8i=MUEu{sYAP-1>g;P zcgd-`go&1oadZJ2e^vp5$0g@1vF!9k?VRHk6=Db5&=~Td(0IKWoVJ5F8ByXo1H?Xya?o5)HQ?&+`tG-NKVIrPOGov`lvbngZisz;x}%Ji;lIl)UbC| z6Z5ixo0Zm;F*L%iADv&lv#qYl<97BCQE_=;@hA}KRv+HGp& z0T?0(vxLM!CSZDMK3{*KIr)83#O7_=wY2jOtszi_q~*57hIZdHv(ZV5Bv6kPJ$1!x zi%ldgxZCc!`r$#-%jkfdf(~025Ok@CSY7b5dYa*ywaA}V*{hF&g8`=%dp&XpC^=6m zm~&Uu@<3%udT+=*v-1gvz9?H7Mee1wP=`Oo3|dEZZe- zCX-~&e?}S`0W@occb>~pU*0ziwkr*iRXcw(v3&G>a%FQKiS4OwRgQfjYA*g$CUCXT z>Us{5@$d*sn4=f{`rO$qUD+9~ap-z`N)d>8Pd;N7-7|WW^YAj5x7f(>=|De1)Mey; z*Bydn0=}DpDA{mhI$`mCxKtBg0C}{tS+o@(LUvxLmE>(g0C(_HEi3pd)Evk!CpC2Q;GYUn@fZp;8 z9k9g)MG#h4$~ft_AGs%}(bQ7yJb&A5H5C&%$@?qK2#p^n zjIIm!{u&x~C&E!Rgs2UFO^x&A7k@?EJ4$2Hn9`1j(s*xPoD+;^fZL)d z2s35H&G~X>mRg!2w&~2XkLn6^n`)z|@$G&E;<{rNr!MgVGXuRrX2zS)2S_HqooX1skT27skA@imPP{*42BvE4j>Up2VTfw!J9Q+ydsM()*D-S)7JX>)}?C zV^+&Uof7i;abd0hy&yiKn^GlSojmC&N)M~B=;d9adaxyqL5o}p|%t|2|GFY zNkvdg*$sG)^bu)(xmY>1Ej|=`y^fd_;D|tU zJwl1{C%jrl*ghP)wJX63!)44 zkyhlMR4b~bw%2>wJEzo>TQ0W;{(Iz;fndv#Y`z@9)M=PO`I)uKV5rtZ28x0CIC&`J zdLc0T7-X{Vk|YquLeusT{f#g4y;u$Ftf$m6__Bfxa~321>sDQDHFn4}L=(3=#TI^m zZ8i({z5BZb;V8a@xzBGjAs<%uUF67G5EjBdvoFDl?8lydbZmVXj%l1K4|rYHxL{Do(_u+80i5l}WXEIcr=& zw3}~msMkV~+4tS)*UlCTlmr|D$P$vKAGSF#exSEtKYyxa?FqceeYEj34+C^?)mU+d zIow>jIj0hIlA$-0_tZ@bqJXptW*zbwnV~OGZqlp3hs4V3eDNK`hw%#xRGb#c-mbW2 zO@TRG-*M&@ZoqASTPCa{D8177@|14gQ&`Z5>y6u?Zr6R{mXPOr{6g*5-L9sjnZmnTjA(>-e=1tF}<{iS)@NFshUIJQFMjnzd*{k%?h_|S5kujOOk8MZ2ONH>6@<7AO% z#{JaP3LIU+%CC;!$;X9Tgrz9;-o1)`F zd2u>4N_Rpj;nXI(GkMNYMGLb)v9UhYqGFkb#p72)cjDf=qZ@%+7`%ha%fow)SIY@n zTw5W~EQ6cWLr>UjAFU*&nEPynDkRPMNp4qCW*lAsTncgPQs7fu%eY3=VX433grB~wpl$2rfN?Vhm0bnjxZaMprxTC& z?PYvCj}MIvP{+SIQAnaL^CD_!)C%U|>(sQzhxb`F z+1BwQd(S`r`g6T!qR>Urrl~XvG*@rb#xlN0BMg>%3W<%l?HY>M8cOXA`-eBhnC)>@ytuLyhSs;FFiH^W}4?zVY>)7_~vlyG6o zJk!H;{M)|p_S{_W@f^<&pzra6U{dYj+?cmThZ_yjA(6>IK#GnPebx~;4$m=)5jb2D ziUNN4U`Jz@DG<%))6ZYVI0NjuF5#Ni)(p0;)N|hNrYzTu10z6e zx6{>!cSPfQ5D~of15Ej9dqY(ELxMJZ zgt{$=WUkTH7^g@}W1~OK%+Hw05si2*tc2a{?j&NE8<@w@(<2(eli(7zW~zz70&8_C&6YjErzz@^)OM zRkl{>VQuAUM94<}7ti{_ovoGJU)quDKftw7*hzqJ{UbqoHCo?wM#sf0`?>y3mI}sp ze8r`N*0-eLN@oRVp3HCnNTnjPUnN2dD7UV4J-DR595*9($+Z)6*K=bsKQ-7{MWJxd zR5bALe(nkrmO42(LA1Xu2XgE#%{nJxMIToWD1>IrEi<{~eD{rrya**2ViMi~o&#XW zHDxsb!0&n_u^Sf?tWR;hVcuh{XQze5xo0kJ#_03AD>mQN@Me;1j~_txycZ+vvn6jhSDhq-g>4$ADImHfaLI8KG81CDtPAu>fY5) ztD8q4l$|^SX)8E~fw#=E{>ec;y%fG?f0E{_=h;+xGL+W|V>s$@U^IM!`F70SS5C)1 zvac9n<%4ZTsh!6HEOXDk7iBWrVB(end}mUuVVt~q+N_L;VO0MTr)Xqt>u6oZ=?$2I z=J$G4pl>+9$z}By$U;n$FK$YcupZ4X>@3jT>M4*^Yw=omkDgEi`e9V565J4Kl# zDBs$gcp{HZC6R}Jx>Gq8+&iDaeZ=au{Uyc8l#^7N)QV_GJ0X2lCk%(64OdH=$@l9# zsT^SC)g9V=h{}uO$w;oz6oDKJ3wR{fM`Y=OY)Lelz<2$`;&+D}q z*E=f>&Ta`eI&mI74UEDBmym1{CbG*YhAe2K6!fd>b}Ot{yrx5Cu(?zf&CY)KZjoAG}hXCTe+~Lb&}CFTv5-? zU_HZM)x&==Qgj0c;PxR4%oCf4D8g?K#xH+*QJ7Cm#@>;Td}lZm0WXV}KvpBjfdm^r z8!PCu62`$CVKZIn36Gd3fi0Ph`Ig2>L+C=*UKF6l+EHQcUpVT77T3Ch*kf}^qKx7) zWl2Z;k19|rdi?avXN+Sf;PGf#lUsS?9LEGtW3(}^>Njeu26K`QYWc*!7qi5@cL`wnf?AH1Fu}QViGV{?y!Ve4S`5=436fT*rUPk%|!^sy8&_ zbDBRwmD7aY>>wDKo1{ZdoIFg`#Q&`9EOt-s$-y);#ccdW%wI>0ADx(y?&$8nu4gnr zfohCxGZUcR$X&?hQX0ZfXd}+VD;Bv* zLk~-UJGzyUoMN_M%r#~s>0j!J`@(MyUAB#gbW_3kAy<+O$Vr3ejSyMq>2sgP!xg_^ zB-Fap_lIzZhiad+PJ?saW+O&^^uTb_Wxb|S-jXAj>s#}q9h3+1JCVAIe-_D8i(9db z?RDtRV=3{qvhT+IJbDzEj_rig9BR7L=^iLay=Xd!$K=XlhB>UH!XqY-w0_{L`+wZM z_dlC&`#)~AbkS+mtfH-wDr%2bOG{C0?bX`E-g{J0wW?~*QZphnVhgR>BW7a9C_!w3 zNbtG(x?lHwd)@EH)ij<2;Y&c^vm_>r8FpP5AXsRXJymTP)f={FQT$ zhCx(>r~Hh}Ipae5YcK38QdcItg!}Ht>W7RlFZvA}TfkajR0Ul3qEjFjZ{8eui<9UK z*N*jT#1LWJho6Nq;hY_lPGcaU zq6MY+%?H<1IXM(?8bQ};@WN&rkI$>me5hb}T*pFd!U{ci-nWX9gl5nL^A@Bee`3`-L=WcuZrQdB?muH+VO!@e8sSB{YNDE zM^-u)KMIB?zMcPZUgk;oXKGA~4U#(wpR<`dYWC*V<>rWs^c+#1mp!>jduyzU#hi6= zJe;|a46|i7clDww*k&O1-6Yxl^U)=@MH63%Ug}_KVEpzS~twSYLpeN@9(nIKWPg$ zn%+^6n3Q7vbU7?Z=keQ?=Smwmxp)K_aviq-xsQV(SUPdoxt1iQs)Z*O>Mge)>FfP#b69L~FxCMkKdt2&VZ*r`%f@ z!Z~RfnbY;_Y29nBjM^8ZDky>0YV|85m9MiEW3=t*=j9ph=swqV!HbaL3Dk?daf6DR zoBO~z+VlbI86DPx=m_v1$j!5*lK41{Z_?L25iPLrK%=qd2Q_}R3%*=y?LuN#CMq-O z?Rvy?B-_V=;}6O4jWc5P&*R@{9J-myTv&H@6?VLTsr*~i(7MpTlsd1`mzg;z!y;FR zfLrk^-xr*MXoq3fkgC|KkeX&KZZGu$&+s~nUXN?9$uE3;U*}X8>ZY~9c>6WNVPa-- ziH(R$4g5-`^&ZZb&Wx5u-wDF z2c>gXJ?9H!@ghka;uLk3Ja-))c*TPYf#cLjteHLsv0AwUv?a%3E zn%#rjZU8_DArN~i0v!=#>R0XN*r;-m{R`uA^0VpUKiC^cPDj ztR{hbR_&_W@G1dMv|f4ROCPv^_&hDKH}=|DgJvLWrak*F^bNWaeZ<)TMnS5E=I42` zY(ED~V+J?`Pd7A2{okjT{B3_$+1u$f#n-9oU2mwI01f;-_+XD%06VaXjL3WUe~8lr zYyf!#CT6`>`ST}&()8bu14hv1u#P4W?%c0&74tPV<{%#);xqCe zpKN?u<&u-1UbTI3%+JM1wv>eH_~n_`33^NQ+vbki4keKA=3DTC%-9B_8hF4HEU^Y( zT6gP==Ksu7q3edz+C$j4KrW!Jarxw||B$rwG|;p2K&OR;#XbO$0Foyy z-F)07DZ-;|Xc#px@bWyn)K#N85Br**PkaA&zSkcHIX=HKPZ9j?-8=1${l&=6D3+vG z{{YVX^~q2SAQ|fSYCnTdW!xOS*=wJduJ+RV+3WuiqC#3gQHQASp1Jcsq@ts;XQGq@ zroXyhDSm`z$b#6ce(btkHHg^N{=D^1VpN=_F~_w%69AG}F*rCt)5L#oIZHnI=R1JH zDy-5~I4mP~x5S^(#dmx&;+8dUzqtA+80|AGCL-rIES9A6f9FxHq>#+Xw7+p}0I04j z^yov<|1mWc*JvKEK%o_1zMO>B{4MNsl%oLmI0I!~|KFx7K!4cKmkGd(^Qd*4|JTB$ zat4#hT0Obu6=q9}8qV*dH z+bRZ>Kh5udt*>VTQa&r_>7`gA{q%nAjj52HNrG+hC^FDoZ=(h9Qg;e+W7Tb});kr=w00bYIXLE39wQK+TC z0x{Fy`DqUCs;WE%K;>68E*45tHN+ZHiFzm5hS7DS%F>K6yn5a>Ji8h9zfQZ+zGr~^ zYBIiH76iBzPfqda!WwqjJG18&^4u!D%{Dq&hM zZoR`2?!|OizioCQleM7qmGyfYm6Tp9<;sYC09DrJiCt(y1>UOlseb$GgUNK*b;m;2 zu^yH_>w8VjgK$asmwJ7Q;NmVuy$1uM-y-PB)1HXNv=o+@Dkk15PIhn;-4D;Lcybkh z+7xUHom$`jP^{Dx-#S6u#$B&Jr;Q~ROW}5{Or7z$%CWP+8INON0{9*4ne9QEY?Xhx zA{9?)blq~4V>u9v87Kk2-BC-RWGZ{EGB&oe^9~KoL@>jYMoZT57oY@!)a*cu>i)1< z9?mmETgdc`p?W+kvp$v zE5}bazq$3~`Ofk57SaKio; zwTPk{rYB>g?$Vmqao1Tt*QXhH&8RrZN9^I@VuV)l*E80=LMy$JG-g`-UV9wxXL!~g zJE9=ltz)&lI=y2*UX)!gy3J{dWzpZ+Y@q)7inCcakkjf%+SK7$ChyX#vH7q!_>QkL zUCht|`X24e_Mv6Ip53Dg?-~WOmlNa}Zj5zm^a_hUdxqCfte+q3Yrs>F42rf`f3AI& z1KgD3a#|i2ef*^7S9i*;##KusNie-{Sxvt}-|@%y-vP&mdvn{Us!vfhDVxG6#ZPyl zSu#`%73&^4IB+nwwym_TSy(9f9TJ41*ri)b>Hoj*KiNu}mO}Aern&XhWlpPSpYOts zV?L`%nc5KOUTb?$tRHQ>dh4CcU3-`xlPo#F&VM0EIG&lS65hy|IoH>`TU@(2MekgQ zA8}#Ua}~V-?vZ|aY)-pn1OIkKWwSZ+x!=aFZ@Z*wDA-ObGxp1`$9A2LV@Z1n(=NQu z=Ky5c+M%-PZqD<|b<_{KV;?R~8zT+3a3cq+s?2MdI@!ZEhwlj!(@TF)R10!jK z-0A;&>~Uu0w!s}EFF^Cfx;EWG*=ZB zuO|$N_jE^RIV#IYcCx227`E0QL%14L;0(K~kI%<;960TFRn(2XT%JIxwReL;)@9=_ z?vYrMAMl)Yy%G3KwvHytj?5a}d*t?gMSA;f!EXMCBX2&@n97tZ&eb=rM>6sAjJusJ z(rn6!K)q$q;LRBm`{N51cpLbHmT?n3AGos1IFH}*j4V;J^1P0dGFaAS#P;{=#>t#J zOf?87=)D#f^iH9R=M6_p2GrDniJ{~xTs+p46tNuaYf3Ws%@|9~OWFwU4^&vlRNEKq z@P?Oo#ws62$reDGwKGS6{VIA^`DjyMFMDjS6W>)OB72|vyoo=8T`_EzzrV`#24Bzl z*i7JNK|#fiOl$P@;Lo3Vk~ucI_|=#AZm%_(hZNbUY-PC(_*CnOP0L`( zEw+2!^j%i@%F`q>c^9VxDiB`h>kbb3G$N8RbM%SL`XkeQspkwTRB)A+x+HF=PQS-D zOO@7s*vTv%a_6_@{ZI%WeS!#}xf7A12^0zW)m}#2Gn*)n|23g)2YY;Kb)yV9SJ36f z_bZw#d48R|;h;%tSZaNHq3uJ%I0J=I_}iE5TmpR={#5szzkpu2u~|J6b=&K#`c%7X zR^lacDI&sgmg3T;mKDPrwX@?rs7@$tNz`Q$RLy^IIqCbtx%9cAE(Wuf>&G`M&+e~f zb$v?S;?!q!%3xFm3lvYw+l-~dk5-x7Dk2yxd%G0qh~}KXLoe2yN)&c2t7-avuJs&W zaKA2`nKQE!fa_XTyFXqXTpf`R=U&sNkM_ zuYTV^O%lwnr@oV^`h3g5wVz{Bffn3}gJ*NR=gX)WOD5i1h*%@~^O*GoAu$K!q6r|I zhA4#~Bwq9)kR&>&sY$XO9wn@g|MgXH-FDV-ZS88z>FG?<)D}thJq7y>6#a_&T8C3b zc?R4sY(b|%+`NfZUn`@+u1fL(-uCvVDjPk*8~XJ3^K~h&v+pn5Ri6GfkKPeD=V`Wf zQ#HkA1EpIQoX@O{7&1D?6Zo!aI9MU+A(GT@jiQ_rr zW{X?IZRGy*yXi9T1~`JPOrG5c7kpD|wH`LA@bvQ0?oac52D+vS@9Uo)`!OnC8a}x6 z;(TmE5%&UabFVXw%xUV^ZpRpo|L~<-rTeC*K31PRIV z!8h@nz=ymVUHz~eYI%y_ugRj`cN~`e*f^1OjKnoX;TiEk;oEMvV*F|t*8_jl70r)i zA{l8vI{bQ%m5W%4SNbXwNP9%gYOc`jyKWXB`5fGrrgV6DkP~?>17esrd@yco@-s&f zOGT;b%()r;pz{yHiMuSttw;p`ELAjpewPQpp*$qcMHs7IJa}3hns~ddBmL_0lxpg8 zaF@6S!E3SumU95uNZ$qBl0wjv@N;6~`we>Jbc{iqx~iyt{~)}z33OZ0K;c=e_#2fs zAiG<3-SfB8^dnj*0kbAS(XwK`Ht}B+7dYGjqC;ooexzcTiVde<$$WSj_T17cdw=*| zxB9q#SFjNV5+kFhx6Mz*W%-8rr8TdF2#M=EBR%&c^M7HXERNH7N0PdYBg^bZ+k5n5 z3*93xih|jrIH)hB)x3sS+WGLgn557tzqF}}Vmnt7`Gd*!1!G|7soRpwu2q~Z!wGp_ z;`w1ct?WzVPRlEAOEN#jw#PYJ@|DzImBg#`e9~T+Bg*lV7yf#=(0$WSJn%+o7Ccxx z4-Bc3JVRunDW#`5nAHjNX1;#BA*}8is)|$|P?`o^+SBz6pG8AkUVUwL>iYEJu6~Ak z@XIn>`x9n*zfvQ%Pe+X+m)yYe=da6OS&F3w%Z(43<34oP$qwf@sQgx2rE7;wcDR8smsoeWb)E}`El{_^_J@*lxF0TkspKM$-KBbzr*k)nM{Ig zpQQx{*+vxVQQu4y<_an%ZI1PyjwEs6N>Rf|i3skDEd?e1DWhg6qYxj^H`vt#VD zB64KwfckB-sl%_OnES=#^D#-3#>S!w<+Q%euKppexm9_3Ivd`Yn zpzIg#4+fO_gZ+F$JeAr9QEz))8^cT(G|t^z zEcCCIUAPToCCivmSJh! zt3Bc%>MCyLaW_qT^$+X^?@wJk=fLeY}cW%kXFq83)D zEoU|k6c^<;t?)q$!l`BU*YczDS)zZo=7#}w%(*WqaBMJesFS zndXSH{eaJw#sfP z{z<}i|ClpDkK{zAu_6qZrZiDJN) zeraop`;bH7di+q}+qM$^9iy4|4(t+VpDOzL8&!OfM$!Bh~jGIW!O9)yfjl~Rnd+pjQJwen$yy-|ye)jgM z*=%d^PpGq3RaNBhX}3BLiccmg(jOLDQo_k@ks?z^$@hL_nO-$JWK_9l1pvARg}$pN ztOz#Mb7h1ur(OMXsMrL?)~tq%k#sx*;LPu_J(ZlIa2Cbgh@}-kDBLMW3I&bMb9v*SI25Ta(qBBe*5%G`N4sn zYZs--Bgk zIG8!(I3SycgLUA{tHc2`Lyex?o}yJi@thc}NW^D1-w3jf{IyAYI=jk&d&di{U(&G_ zvlN%hb~S>9+4H&Ag5E}LME(Z}9QeCzl)RawupBZsAjD>mP%u8%x%s5i)X(BfD{Y7u zpR?;LyXeS@*Xa*(_Uc5UR9M3q_GF^15!F2wps|?6K5=1(RqTrcHetEF{JD{&S2LT1WlwjFbcgr*<1OS#w?XwA&;Er~~AK0n}C*@|-&3=GFhoDxoBL4)CyJj-Eni^r`(U~=n& z!Y=w17ETM8U}I297vj{HiqR|mS;!YtkU*{*Oq9=3XazaNhS$KkVw}d3n@zs~RK?5J za``kD9>e55vMFSPY)gUW1*Rdusk5|?OrS%^y zJa#yQ&so8Bn%BoY@7=$}Oj2qHi~4o(x5;MdOTklD*OeXy!HO3yL@yUm8ylO1ZYoO8 zZ1%-ukB>cDe}C^gypFM#H5?>k{l!$2D^8uRTK>x{`w!anKFN$Z++tV@T%wF*=J&~) z;@T9lZ&gHhaBtE5I$`3hoi2%!jn{N$Vw3F~vYfdKEdqU`eT@lZZ8N_<^?{wYBIK)# zOnrY+cMaA&xBW#-?YF#~N{`9#Uqgvu6vBVdIIbKYfpm%*Ozn@uPxJ8NEGH(jEOmcU z{YfH3y!PAvC;Z2D#}5aWLQPFmrpeQ@Z}rpl?mJ6quL%WxmEi0cJm9)z&7FK>g-L>P zk8~Qr@+!OCJ@@c(M(o>{h$@U9A=QlIlK+AhI$btNJ&~@0x z=O8*~pr`c@q)eR*GV}}+lAk`qYbzGkpVL+~{IKOFouLI?AIlZmAyw3+*glDZbLaSu z#RK}`te1_qneUHM54O?6CDdDsOK8r|vP`-%PmLzT6ez2=wFigSPMCEKR$76V;TcZ)@!iO(my&)sVDj-#XEiD<2hOKtzbfGtztGLE(xkK8Vwy>toEDrIz-3Yg7 zJtnkSlW1{d4LOY5ExOmK$lS&aIhh|Fx1R5d ztbXfG>pRnY;Bj*yP3YE`ZfL{rUfGyZT)EQQg~Gho{8?Nwim(~CoZILCrzZXL*souA z0yrLd@RX#9c4EvZ0;FZHa=u94G2bqISGRtToX8|BtuvF9d-_dJ%!R)CTKcB4w295! zkCFI$Zu@Ey3fRjkvTm#>8R;o+eYAvq%XEld7TdQA$veNeCZfIj z>9>$*7RKAJ`9nS|$iSCFY2!_W<-@e~F?aKZyY&E^CeM7B@FlnL{>!EgnLbUmYF*q~ zdNR}j(Zid^e8OLXE0oQ(&n)TD<>x9fX?!x8Uy@`KptrPU5~CUDxm7}y^V!L3(_95J z?b4!k?rtEEmF~%#_Bqb!?m7B9p0oUR{J83ry)i?TpWw5{hv9i%GV}KOh=!+^uVhyK zI?mqQ4??oI#c4ANOx8BRRR`4xs)@*%?2QXfTO04iW!<$LJf3S9&54Po^V?J9^<>6W zk3ueGIf;1mn!JO48Ci~~5*K|Ifr+Bq(893aHFf0s>}V!}mu?i9u{d}E5>cq1gG-Nh zTMGzFX#MJP+kB{c2Zen2;bUEVYyHDI?^1Z1`$k!5p%2&1J24(I_6gyP{B-k5JjGJ( z`5V8MY>Ka(o)Bko=IPQ@|IC%~^h>6HtAQU;q&TEiO>sg3LOm@iXp~%Odb8DuQ7~JE zs3M#Z`pxlk+>5eUhf5=7Oz?o6=D{R?Pku5(9KJQT~9s!n*t)qI3=Oi z)bl@hrS1LKmgoc{7`*13tT=!gh-mYGJ~--2(Z1F57N`~!Ty4VO#{N|stFrPHBpm2} z!T+w~yU;DrSQLH3qqt;u#@K7f$Ru$NWsO6xdzoQ-)iufDqmAex1VyXg-9Rvpk4Drl zuddKjM1fr4PugKF0-t*X&bzBdJYrc42@a&W))7`CocX|XVnWV$P+A|aa>U*R8fZ8nEgZz^qfq{oO#%gR(#&eP)vBUM`r z%!j1FK1Nj6NaNvNnFE=5_l?^ztuSHGj~pNYdMKLN+0)ZfsF}+O`r(oM`RhGegG$Sp z5u)l%9tBWlhj(+0WHNl{w?m*KMBNB+18m8(}w09GX;8R^8`4m-w%sLAQs0 zqW9K!mIkYr^3#^DLnp)KU4GN~>{j$T5Q<^lI+aeVBjwZ~v<#K*cG=NLPUWGS>V3_R z8h-t>VR+SPhsN7gR&6f_yI2{G5^5V#R>@^AErGZ^nDXvhwiKh9+wy5Gk080srB^A% z$F51fPmX|Jx^gMnYv#`{IBwSX8o2e;S-P z_$IVnxO^pu?M3^|TfsM}ExyHB5^0GSQWiL^rz4)84@>5v;Yb-_IWwVDe($Ci*TuMZ z-}tyLA#Qk9eM{dg>#G$B=)<~M4yfor?7xm#ApPJ1NB z?H7vh5ux%sQN3J4Wu|>yG!8j~(`4d&duv&9R9M z1ma}Ul>X%R=U$bhs^g{bIxKlme)4dy@c>)5chtMSdbE!{?wVwhBUu)uoiUj_3<3E$ zAIG|ztWVd;VMwE8@UDwqb0S&ehuf$MpGG7JVS<6(aFlnuN9y%NHqTr6R=CwuQH66F z40`&~`$`&n#U!QAc?P-(4>07m?`PE}9<~_ox72Zt9p*M3AH7|;?Fd^9ELmxjKN3#L z3gSO8wSWhtDpb{AX31W%kbE1=>ZsOZopT9NS0%R>dKk#FcrIzYLs_nzL~cA7IC8Jy zT|7@oC&Ny~dA#4|N#eXVdGbr7!W z$z$ZREB|}D>rmqfc?=>yeh5cp9f3H=okz;D0l=qgNYdo`+Ob(4DKKI44CiZtw5t3; ze=PkmS0{GjSk3;|`N1@Xq3V+-uz`hp-?StW~=Cv)%ZrFKpm-}OLp zTGE5#u0xAO#e>zE`z6QAZP;=DUGacQ64UWcQXTdvdd@RaW$ASx=la1&o1DjfzxbiU zCTYF#_-0_NR#sa$Fs_V%9V3}uVtG};5kY0;*QUINE`w3*0zrdo|5_i_P@b+-p$-P zF8%e$a2vk#=6Yx9@s~#9lsU#gIq7Vx-T@J@jNLtc`CnZqR{d86u_(V;T%G)}Ni2H{ ztKHBe3M$;?K1@Qm)J|aW!MGkk#xg<5Lq~l2x`$m|T3dfKOoxfcR?v%L(j(HR%DunR zC>J!?h>@Y(>=EBlY~oxwTFy9ZY~7lAl9W1ffftyLB476U{^G1FxpwPQ*82uU3Sf>D zG}>3H4eS6guA(^7>_x_XDS>1Y1@$wfg)r$9j!o7Ob8jX-VaJj>ez2kaqH zh#XIkff~$pCEW6Kmx0Y}iJU9Z!3>`A{Zd!U z5OU$+zsCO8@TN1*MD?N?3^ib}_YHJ#_KeuQc`L>yyGhG8)-?YZ-t#NTvM>}{4OE}M zfdt8ecbD}k@elD!nUSIYnd+au7tZYTVsb@@etXiT_2@1Q1{VembO9Ek9R82jT4}Zn zGmgB_!gZAa`M6Orj1Muz`yQoQ;V_Jtk~sv>?ca1!n7(~wgQYeT+Vji1jiGaDc%FX- zN-0V$?px4k$!>d+JQTr6XMPi<4wD38vB|o{Ha+nk%k{>M`2jjfSqrn=l^m6}A0Z2j zMdO^qz8sAI?E&bln)j2HbrvK+?YOemf5v9GvSP)R|H#NN04-+?krN}v*q?&T7kKb1 z=+T_~jv+Y+g{t)Vk_dw4;c~6y2$_wQNK63)+cIBJ=fzXL5Nrg7cnlwVn_am1M;QJy zscba`9L^`-BhTFc&r_H0F=Q1#;cpZ`^YvZfW-4uW&Dvq4f5;vdNZPXwwRtRflDnBV zf^oQoy**T^YXxdZDGp~3hFA7N8>~p_MxI4o8vacai??vKB{sw&!os2=3Ge8SHwav# zx_hz_u0FmE@&p+}Dgnt0v1K%fU;sNbR$>wlK@4u@3CTBHsNg8evq8GyinF{i-}sK5 zh{OX-;}JiQg=X)#faZ^7`mcO!+^5V)YTQM@4l(|%Nu1Z_S!B$z8V4)=dOBuOc?GxA z4q(sSNH22v5Ib7Sx*oqV>3CFmZTCER61X;S7$~)gR*zv5S<8htFgW+Rx0?cn7v@0_;-ngSi6S$|$l(=(k&zLl%rjArH_L5mo zPVq$%T}4i7A%o7VI0)U-i{Bp5i8dSE$$%T%8yl{4<-;Uv%e3&d6~(W}%SQwO5=MC! zhRGsvP8s09jVs(HV6C)NG8zoRF76sU5F@%5ic|lWgVS#>GP9#atQsv|#bbTuLw^P6 z69a6J$K2Eaz~|tQ!@mG$MZz5Wt_7A=_4)>kt;G9l<&GeBEg+79tH_mw9CKMQB5SAj zH~E2dX~Xjl?*yE7D5O@#ZB=)bwIv%|bO&jtub0T_8io077BOY8fjlS~;q zM)BBk=M1PzDHtlyqu5~3Tx*Z6sOUx=SnZ9@Zsqpa@<0`RG_t&#(1td|fmD`p&%n0I zgBN%Z`wHA!KF2 zJ^^x(ei(!sPNd*~EyiBNlmCbpB=2*Jb6^k?B3X)NFd{_FlM)W0(IuEtu>-~a?-lHn)JdbI-;RK(C$5Swa8 zfacj7Sz97jcs{d$hza$}V#Nr{!xvW_Wo1<=-8CA>*12-&81`Yq)+LO0t^}@Q4^kDb z4MIJG03apg^sS^+7j#A9vgqqvublyzb(lp0=0)$(!$s@fj#?Aj{gX6S&CZ-zUWWSF z0{T#sr?dX^m3xbp>w4{;=8EKZjwOS%a!HVX57c@0`uz8`Q^!MHv8mQSRM~zWav`sJ zU0ABgpA*yO^oXh7DU97h1A3L|x2g;>dB3~XvvE{!h0#wMc0wM6n|BzfrU6%9Pb^Q> z(o}Ne1Z}(dS772mNtGX1Dru|=VJRScSQ5XML=f|k2LiDCW<)K|fOC*3{%BVrc`(xu z-*(^Hi1wjAQuG2!YekAAqRm+fdVnyNynr)G)5hcHRbySy13r!eE9;YKhXzUcUq_me z3(;YCC9&TpY^jjyo2BlBVYrb0Jo{g=1F+Ws7aDKNHdb4K$De5BdRiGjH+qMh83;3|* zQ1E?^*u?zwFz^6}NR_Wg27wnp1+CRA)soLMTHcy#LD;ab*+UDU4B8;--nv+`y)Oh+ z|J8AAHO^v?Y;lJ!;-grF@%n5o>wJR_sgg8wt|m$u2~>>njq*AnXkH&^+|VUFh(t$0 zs9)m{3R%*d$5No}s_MKt_z{0l{A|_R%gi=5?XmNBjc4{u#s^!kJd4A(eoQeejv&z2 zta@DsWBlfKDEEY<|9;CZt} ztR068TmSxB03^O^fCh?4VLuY?u3@*J9X{2@mGrohD%=1h&nQT1qN;3@Jm9y&e7L(G_JJV9KLXGhM0!SLvLB(^jwbsSx;>#eEC1PhvxZ05mU(Pld?b`4r-l71&idt(}I1=bP6 zL_)g&($}e1dPbB_!AEoF@!l^z??Nb5Z zT1om{ReT1AaSL71;QN)0=CV~5gc39armN^3yOTF>h?z*qs3BX27_e6=H>Af8_oePK z{M;4?r&MV}<#bIf6H5+il#nL+Xk>{}>n;=^_-}AEPFMxq2Z|T@WA^NQiQ+n|VhK^|@ z_<|}5&}O~WDr3K^by-^he19~ATgMFloi)?sP;rZBfc|EDI9e+edxE2H0HZ7*Gz= zYKV`6;r9JrcW|$JWibNA(93jPFM4RG%bOTb)XO7Asw^%-BGOF|sjhaA%=0J68~&`x zs=t<$=+L9>x>5i|&K57FL;7p$zoEBYxvpmpv%)2Zd+Fs-c8A5af^vehqTak85V@hYiZkvlG&YBHJu4krguNL?_qq{VBy(Oi; z+Bp;Z?~gs@Xctj$MDWT#&d5UKrsE)TAeoQ8H6`(|BjUh>;a~tHf5FEUQmWg$9oyfv zu1ZX@%096%nP3W*39Q`h>nuQT<>@&RQwB%16;u5%I%zdK%I;zX63RVQE=5}Mq&!$H zE2ievrgl|y4!YbW@<`jc{gF(+9m}a zXtnzpFb{UJJ34}M%hw;RzBM91H3{__)l;cHq=EQUw?@%6UsdQqaeTh!s%FD5yOq7| zQk~8}91F~|?93;4Ap>HuB*$oXhhqzRuu@2-b8ja-Ex=!>4a#c6v7`!d*4QS)R}zyr z?dv^XIL^O>gCH|SZ%i7(hfv1TxzCK?Z(}CU;o1t$@KHrgw6PrF zk6k7hlvf~Nf*@JqGp|6jt=*yNt`OjcR`)-g@-~pI2p;lACp8VJs;}SwErw9{w}~EN zLyeTg!8Ehx3pudLH6_g_S1Ab^B`ZuSpzcvxYG_Gy0aKQ7`MvLR8b1&3@1~;lwYS&I zO902uESK7+2Q$K8(O{*8OZP`55IA1LEr+^39qiA`8H*F*VBVeJkr=Y#+ad(|`zSm? zIpoCfIjG>cL12Xt#Oja5nYeze@=EboP4FSOf;uHVGVF)JD^lZm^>})Z)p_Okil$U* zZ*)Q6h(bXY-dwCcb1v6s2(mB{MUYy~f)z_^YheD^OR#!*cos_d#7=*D^U`950VLBI zFqLV@4|=Myh&W@szOzyD;maye8V?v+kciyo0S+ZRJLjz`DCa98Qkwmsu7*(G&SKb> zq`v;bY8`BOJI_xbDb-d~nFo4U%y~Ae(LxPvp+>-`r~ZQ_0aS#Eu`y@pQcF>n=fwA- zn#ux6Si|W0sJ5EzmY54PilL)jdQER{XMzDHqQ*~Fbr7#*5U_v-*SRB z)YV4`SUnJaV4HbgFWEMxs-#-LciRe@iiDKXR$3Z}wX8u|8EjZoQ5>c4{DYM_iS5+6 zRJ}CU-@aaeQVijI`b?8qkG1d1u};#G%&vEf3~ECX1=du*U@$v z1|N+)6J-g&)($FLwzr^L1!XXw)b=J8M6G-!#t`nRBDZaZc_erIhHcD`3hVcgUjoZh z=}s)(+!ybX)~?d8RW41P1Py=F3T)!jteJRJvh_N(P!XZlm{#DsBg8jCxBPPijB=M z&~iNilV*Rw8kW0{>pS}QXC7o^wX|kX*}E;hSx;qwSPVG|QtYAqNR?|Cc9#Clbz{ScFtBO3dHGroKW%B>^PK zhvBsAzX{GyTA7Q8175*KYFpu<+^fO#nwB3vMalvuh$sUjf@Qqe#)j&K{}+)8{ka-3 zY-Exf&HxRraK;-F>9Nl>Wn%l_$+w?};Efixv`lh-utha35 zsRJ6$SBB)o6sxJbWMFz{Q?Z^J?O!53R0#IgW-Bi+o+ z&(Q|Fr8iEflJP_B*bcw8zbb77p@ln+52VA{hs_=S;+f%G;RG_)rAo`|1Z6cMnii+A zom&4Iu5%?84o&4%^S-br11x?}R!lzB|GxODqd#-j5~jFl>{f5OzkzJE|F|n69c04e zTQ#ewncI8Nj-JZZcRA54Ms50wqA$QOtGN=mqkzw@y+*%Fj9>H$24L0>8$x42n`ppU zVMRhLCjyeUX@C$^o3?bL?j4I;NVf-Px}IEg3!c1Lc!Mq08@S*2yJ|~NEvs7}K!@~R zx9QEZ@97~|1V)7H+o7~4KWlHZRFM<;B)|lzwjg+{*tlk|n4s@+y*5bngp`taotA(2 zi^38Bcdy_;WczWIj@4EQ=ijZ}IetmII*NqWvIv6F2UMaW1!%-5tTa!@{;HLbKV_%HVJf%< zEIM4NWCYg=Iep?-Qk1Sla=OaaszN{B`QS#TGYaMotuBamn|JwrP?WV|vc)Ag?)w_^ zheBlhGA*f zrC1;H$vejbwCkfsxwYD*wgzqQbbVRvG&p-UC-kKC%_?c#PjGNg^$moYT&MxU3_vQ~ z?~Wm?0;qB)Zo5lbbv8ySe&6^oPeDP``Rwt-*SjmMKzj~K5V#KZum)GDlgSB))Z2o3moV!-}r zv;Rp>5_kzdX5FJ5d)6~QzgO=%wuKeE_gMCX_ZrvK!mviNutYBom-PP;KaHuuB$rMs zu^LZJNF^lN`Vv*~L~a7QGga&eeTXhmJ8`_-WI-1tL|0HEF$mLfwV6Z>8nh8Bz_zYa zw#Rbx<6w+o@%p@PEf>K>R`y5lkh%W>uDeI>Y-s( zN&`yq;5Hc5%`zP25+?P^RRxNBbAo7GPV~WINnt5tnmxC0R>?)q(AC?nGJEEA3)z8N zH$ox`O65fyA*}X+`Iu>86BYZ(^}JITPi&4$Gn>#%L8Ad8?gqmZa_>{7px#zsj1!%_ zI|F#32i=R-+9>FS_SD+3JKUCX4*G zB>Des$2ZBaEz3j@9!!{YV6WU0>*|=@%e}8ZH@m)WYO(pp^=}1g-_>0^7ax7UX`gF< zSUggOX5`9J?+k^at8-YNN#>6?Wcb&+N^8bw*o z?KN2wu`0UioZPvYuX%GX9^QLy+x40g_p(`@7=v@2kJ$f4QJ;<=(he?>*%? zCL;x?LV+XG^j&j+DP@_4+@pj4^}f}JXXpHKyu^bD3I?Xu1FwIsOvfZ#bv+QhZ{&9{qFPNV0^`-`@uUjY+8X=BZ$Z&yJfjhMacBI zTn{zlc;-DazJ7i#QoomhN$JB1ee18v&y)(hS;V&Md_eN5oOq*p>B*P1B{Dy%Q+`>U u`IUoG2kSEGnUgS)#s4DL>FcXtTx?!g^`ySuyFC0owf?>_l{z@29e z&zkP4uIiHRuBs+jM(QgxBswGz5D>Jeh@c!05NHq(5XcC`$M=>UtfU2L_-U{4Pi5rN92@bUDU!QK?6!%}A zbAy3+nGJ4lLWu)nALt)UNQ9&HfV`igZ+tK4WII>`MAT?;RV zkJ`r2QX-@h_qe?;2`T)0vO0gb}Qa=zdt?hvp&7J z=?~z{^;q_0|E3nQO`1(g^x&)*< z^}zd^Ku{H4s3ahcbzooK&mtedviPx=Tz{Y@0h_M_Y51Vv`r^XDh~Q!q`q@W;U3S`7 zBPe*QS$|~o4bA#s@5gNowG2j}gUR{PP6xOZ$V$U+!1Uur(CpH%zUjKEy}U$PbV8ET>Zx(jtA zXswbUB))wAI2D-Ojj5AS$vY3Mf=`L)_*v;=NuZ{;L#I`zuuh~dRHaiTG^@9Km+Jbn zwP_>zGMp8(lOOmG(Q^f7>{cW#Sb+asSKxZ&I@CGS{TC2_9l>+FJopp{%r1C7K}_B} zd`LLtAYnliJ-7>qsvwoG&w_FUO;Ir-(1h3rzMlpA2x_A82d)Mv1~>-#2b2c@q(~uP zL?LoQ8#3jEa0&>;K#JjJ0ynwDGUA2MjOe2g34-RiWfP$GpV^@_Big;&gEIs>_`UjN z^qlD+Q4zy1h(Tg~$a)#|t#pX#0JI!P_DEew=t#3jo=D(ikYrmYi-V%9Qsi(9Mg^?wq=x$eU1@w4acebkEAqLjFEe zaFZjMN0on)=ONM}{FRS{-&o{pmUw<>4I_#t4~>ilvtLSQyxN|drIg#-FFA0k48jBB)g!y zV!KBpP?XkR;J{TRL(( z>fg%TA|9_CkF&yIB4E~IUSKj|IDQX<9^hW_Yz+1ZEQde8D-ORdCs;3KQ?XZCEJo~Aj7f}PC~PQUXkqBX5RZa_ zq6m2zc}X#UF?X?IvGjD(w8b>!bihpX;m1SMLytpsbaHe$bS!inrhFy=rc@^7TEV*K zx-l~JW`qO`Kb=qwO-xEJK zCl{-REM&38H?_I=KZrwpf{GEUAR3t*sh+o86`LpTDqccY*(wVy%UlRr#H?&G3azfI zDy#LdBmpE^uo#S+oLR0}yp4AL$o{E2CObkmYx5&`cCfo>&~$2HplQIRQ)rf`*RUtP zn`!>07-MmC@T7Gqprz_b^iCOj2wN3Y1VMzOhHVE+1f>PVgbjtLv1ZwlC?AVaO2_YUT5`mF8cuxBoW4m@M3~QKMXz( z9t?((J(4*T$rJ+)c~f-Mj224-z6YXDRUKp>z|wEihtRiUJ900l4yL=1+8qQPL?=+D zP|D55T8thqVhT!GkExXFS-G5!b9S^oJ=i|vKeT}L_&$BziA=y+;rL>0Q7V&PxyyR! z+;ee&*i3>Rx*v)Vnh-)2+9Gx@b}81Lan0>gp-@zNi*&1ST;xw5T3xckztcbLMBz)0 zt&FZvuV|yVqhzV{q$oYRKT|tvJGVP$l?lVmC2y=Yr${5G?fTJy_;lo`M#?yFtSH@_ zecXoo?Kv_aD8OI1rLU8C=KFV}^4+d4D&iKyhhULVTPWewT9)xvW#;;(!vOG;suKXs zgGS0J?HTI6!jVNArF+vMWfDoU4<}U6^ z_qOwox5B&OZK=U5ERVU5b5>xhYUt0uq&9e*rzQ8 zHWhpAi!Z0}@zLe7I};SJaX1=i@@Pk{g^%ZljgQV}-)4KlMOOyZBg3#)(z~R?IqO|H z=}uU=u6nixyTaB+hNdbDGL5#3oOWSG3HGisCb%d(#%@|){qIBT!Q%aoLWM(fX->4q zsNfSB-~`Yddz@V!6xz?dSGfg zse0W6Uz?uUb)wwTKx@ah!&uB)aK3$cwKQfp<9NF3qpB;*w%j{m;kanoU#Z5~@|WDOJN4KF>q5 zeP+FBvR*dgylp*o2Yto$f#{UM!_l>aXOktLFsv%s1VdPj36Zld`Z{TBpl2YtGru#t z4Iqyr{YYU-F-1;OY+qNL#y_pMWIJ*g=8zK}TNZ-VvXb#a5eVNeE|otfO08AyY6Wr%aXHX& zw6Gt4=JBIHR_DZAjPY{nZVvh<%rt}?Ou{F4s2x~+*n-HcFu||curjf%IYfH)dM8^T zTd@ccSf%2}BF*WX@zrUMJ8+cg+K@wq*|d>`h`dG2aBRM2`q-VKYY3n$s9(o*z_e|%GFFCszUiR`(prL5ALnwu) z)|@3@`tiVa7*eF!*rz;KUY={<`*VE^?-t~u5f4x70Fo%z-Gt= zu#wrW%9U#9mtg}63UkjR$<$9v%q?5D6EIQ{hf*3+Jn7nv%eG}s!`62C1M9ACjKSAOf00!J#}sX!n4tTrH@vB~SwRwp zqan5|BAj2DACg~$)s@d-e2+zJ_#Jz2n0%BweJaL{=uG%krt^LxSs%)uqJK`>o#rD^ zQfzHLWkKT*=#UV34@G{lLGg|ml9{5E`AqUGN5&`CRBP%pcSQkpeXl9OtKozS6!7g>~BAfJ(*MZA4pjO<`z{6Nt8upS#EAY!=9en`29Lg2rU zx8J=h(<~P(dm<}6RXepi1vZt+AVNP$XT?B8yJmc#$JMVil+kMw#Sk+bxfIR`zJ7mw zzXR3?>Ipdp=>TaQ+88VrY!$kKLX!v)r4R!mmpfTt5L9hjy=3cm=?`fYf**1u#x;aS zzFYjcn8B>>@D&{a9fy&lZnJi#&dK4?q2`+MM)gJ;y%y~|YBE|4I!$tI3h`#xMeRLW z4f_=w6xgK%txi1P#Dc(}M%Qh;e3pBxb4YgHX6_)`E>=9HBsaBjsr;$2Uv=D>#tz_l zhLy?2-vMBF5NAEcL0(4-f|C2Z`zagZ0pXF-g0z(&hrJq?{Dl{RjEdHraAy#5#I z`!6oYZgGtn_T+UuhVn+T5f!xM(-o7&N+q(z@jO)81#%T0ADw0|FgM(tyF2?vzIW|j zCNQ8-YaE+lnWUO{tpFb(wOcq66_?buoE_@X9Htm#-rVeCwvy10`{5xG0&la}=sM(>f|*4zj>K!wVs#-r{0Yv6$HVS&8#tfOI2(Q+ zs%f^nQ*S_Vg%IG|$?oVegP4u!x%x@jUte#VvB*;>GX?Y_`KASwtNUD&9^ti)RKcol1vo+_Xwzxv3U z7qdH!q>;1HziI7CV^?yQVZ(USi|8kT3Lz4nh3J?RWsaL3ptpdqTy$0>U(9X5WbksJ zb7yssM;2A?Sk_F@N~TD;Oo>9Cr#!j{tpqviB+qYZW>S7Sksgi#i3x!rfnJtzrYm_f zeFS7QmNJBrMg>~EVqWjW;3OS$5=%WjqvdByN^^eGowNIu+-1bg0p2mZjVIBoxQ`fL zQ)g(ln(ofV8bNw4b*xFQpPp5(O)m-I2%#C_OdhU0!PM^LD7`B~euRRd{I=lU*zOSu zBX%y01ovzGK-+z%sNdu&eg5UG*g~;5Q*j;3(a4eUctFOIIjLogC3X|sa)_mQ+xC2w zQ&ZLO_b2i3U~>eI4=fr0&vu97`t9|X7TxaJyYjHcSO(E!Ro4 z=ZfEOyTEPGFCfYMB!r}L2xZv{k!#tSKXm&Kc3a4QlW*;5*2R%ul;{3#o2!-+k>g_` zH97QiwE!x=AiHB^y$^zpnSO!(MW=mWvwNtEy;EtxYPfT#YG7d~e#mmPyZP*6C-pe6W6j;S_F_HA?ot5Xzs`2 zq#V9>TlT44`hm87>~ZkK?k2Gpx(Yy->Qv9#u;qyTCi9|tadxi{gtZQo!wa_V%@G8` zmIb2$UZVrG>0OHl!uELbQyvxJI}pJSsUKF|%o}pn_^puK;W~oz_#yDp(fk9b+q5A# z@xHDBvqG8uKXv73aY)_CGW4)2W4GsdvM;~8eoYq?5TD{T7ikepl%x^o8JGD{*nOW| z7Kg^y$^Q)4tA)2pr!^{(R!UGvK_cvHnxe02 zjADqmnxHVBlKPk+c7?Zc57|Z>mBO(C*EIh$B2$EE##D0=S3yl#e=&`*j>WzOl1Z9Q z48RqA&M%Yx$)HoG$YRGT-E_+8sVif(vxjb`Xzrn3194Stj*VYGCl633c(g}!jxAY@mGbI|O#-v?%v^){$uS}V3 zuwNubE9`KTPk>nFV{Xw-MviA zZdmr7_@|d@9;^)FRPii$-k!R=hIrX~=XCKLe8`~(0(x)o8d`c9dU~pN2r4@lD|=mMDl0pJKL`1H96>`neOps&dsBcF z?yqrm^#Bg`T=@9E2>s{tC!hAFM*pQ`W%t*#-X}=&tA~b;nwI8wXok+F{|~fZJ^xQM z1O5NZ%G$x!;*U8Q=+hWl7+M-y+1tJ2(fyX(yKMi1_tkb{SJ=Lkkr_(|3XXF$+36W?D{~ z-*){QRRCZCu$8yg)i?ab+8-$YX!X1ATTo2R$=GefxhX z>|Jetm_NU+G0i`kIca_i&G~K&?2-TjQzI8aU3)`rdRjVWc3OINT1H&D_rLV)bZne7 z|AP4k2fum*Yz=ko0k#SNfCcv-)3E&Y6PMxL9p82MZ-~E;Ica{m(m!15Prv=6_1$r~ zA>T3oUIe%y6-)x8fq-~{LTR9#E5J|Y(?@@ZF8W=*hR6(G$BY5;cSJI(VM;o=?3VYGQ8a!JI!)Dt=zh$rs{eQ z8+VwO?YYd>%s!sdxs6|yw=w?^1R>=8|K}s)0|Ba#)s!%;Fj$%=G70-B3h3WY9JbH% zq@BmBi&16nd0LDR9#n#eH|W2gtQMKcr+J$mG@v z@V-RIx)DS--O@b2mE0}p*pc_d11cvQ&YrmAI+Q!aeR4kPeU+@yY!(k~;=aM2l+3%hKnWr_alY2y&8@;Xi{4jWiKG2a zA>L=8V)*Nu6|i0>Wi@10ZY3S~bHn1+xvX2~4VI=$C=Ukr6F=A3?l)4t|3>RF79cys z=ejAu9s1;!Zc{(k0ouFuL~_)yJ^?uqotcj9i;rf;{@T-yN<5{p|6`@^25~Q)RS5h= zd+EW9gy61!mUAknp5ckq_Q3+2Ib^Ye=0t2rc>Qs6I5Spe^7Z*3wf=WJtbU5Kuk2Cw zYM+mf3twS7?`_a*(HkB!%E}@2c$(~s4JSztI0%)LwQ#`L{S7`ZNWQ?2OrTJj`V0%s zgX?4Ws)>4b8ZnHO`hg~%&M15*y{VsTo^1;#U$xWfndKP-SKXVqS_Pbxmo0p6+^OErZPYh#`^|ur2&AF7fixbCH5Xs4jLk_9Kb~%{+ADbqRW)2~ z$SNuEfqOk(7?>AOKqd3m9`%2oOI@{4U$#}fRa~yB=K3Gu@%9p|ld;N8GPd6ANC8M_ zppr8>G_}=?M_;Py>Tim)zW999emXZWF1Qjhs+({~PsMv6k7ahOH_~oCE=jL9mipaN zzMkP-;e+7h=x8fVUoxhyDQs0|Lo!uUTQkRQcUqF(6h6K)38Qm=xE7n9K1P0}fRfG) zqNoaESz*UOt8F;hH#U1btZ~~vyBuNo8wnH+fIfc;Ypkh@b&Cn6u2_$%=Dv2RtiMr8 zbX3AP8BQ%Hb=+mJ36wLjA*bVf_YC9;UeWkh#f*uk%AX#*gM{e9ZM*+ zkscc~`;es9U&Ns_w2`b$NB^(4@VdOq$YgU^g{!V%O4ZQOA$q5nKpji%u!8n zc15Y#?W%80XOW9aKadHT9cM>Zc%B@)M<-h@$A`xY$jZvjc)i@r`Nxwh9+pZ`Zx4*q z*hFB<$O!#TZ`RcC5D*aFYC3wD$;rv7i}jWqq(nqJjVXSm!9FAI%giwkW2{uyp4q z{l?kecgEvSg(WBp~}ap=IRbt#Fde#^@mphbXe zUth7uNp&-U0{wqlln}2TB!aq((83a{Ce|#nAiFRgFovC~Vt6ymc92w}5Xqo&a`)oR zRC!s6KTchZO=7Wba-eCvOL3}0bE(}0nIT))*O6&x7bc}i-? zNWDnBI+l$w|5`N$7$2>*!N6Gmov?ZOSU!*DY*T_Lm&yqn(!RJi>Dd7McKMq3GnIOD zi+SQb?@urk+$?=?P=}+CA8M~FKlk!+gkQBwqMa-dFQs0s?x9K-5qy}~39=k9LAsAn z>9u(x46yrP`<3;@4~dUiPtNCZY{l(MXVDUsA_dCCULUUNv={%h(tBxK5)!EXNUQF% zrTUHDJ!9QT@rrDh5+&B_J!*v#E%`Fiq267b#H}2uL_9);_8@ZCq0uoxEo)N#X}ilk zwW0BGVI?VCa{mGO4P%~%A$oPLdhDEpl>a(`0w&12LTchsLze9aH>g?j07JE_)H-=7 z93CR7F}DYWY}_XXMs0B(RaNy>Wy7GuA%_V8}ux?De|;RGanfCxa62(ebw@7&oWq2xYB|@PZ6C>=QkXO_j?` z5tTQvn8@RPX^ceutwjJ{eIJ2|%O&blvM30to7d~7BNnTk?~e)k1D0!C;Z-gq<=$l^wAzUo#@U>LXg&7ZaU+VqEApX+&gg{Vua?kr#6mu|6` zwmFpB!*vC)yL{xU=W_SrngO|o=4sOPO43~ibKyr-TT!jiuD3el)VFIYecI7vSRxIU|mi>V$*kW#M5$C+y2v`UQ_= z%^@CFq=h%tZ_RzHp<&`Vh zhDiWKaB23bzeA-=nE({5zzq2Y1jhvh3|VTH5-dJ$Y5iBPuQjh-Bwn81@`hUAkc;{X zmJd3ByC}d3G{Vms5ILYz@B3hLj0%mtusL#L{#a_>kDJ?7)h8Wgot->h-5qOhUm8|D zN!04Cf{#n>G1(fS1`96FH$%s_<|q6LH7U?r8UTIe=}Yj~@ctC#nD%`)wy7{efXz*bsvj0K^-4QPFR1kq)t%D;?I#940xG~m8oT$pHaeRgs2 zkK7z?WEt@g2ygkK<$C7ASVUe@weuJs3?Px}y;bkmHS0zXDqI8Bbe-nii2_QzbrcvI z9+qY9kIsFhyUVwfzq9YLdf;5P%A!In@_~+qFh(PBP+ySniOMKLTy(asFp&hlYr7@NGiY9$SRSjKa zztmam$PLU;0WpzL9!VBf%8{cX)fEv6hKI9zna5c3P0(V^Q`mYG9cj}`BJamV{Eml{Z9UNAFTy&^Zfo-i}EWl<$~w18f5r-i4bS$yuedJ7vXE78i&h)xNA zDrol~PA#IrQV@I4r^s-AtS0OErh*F`nitZFWj~)VTGjeO|dGI z@=cJImQGd`uy;MQjCs!0m3$b`WO6${Jc~UkH#!drxRlo3XO$fzoL&^|)BYb5u(@I~ zM42id6^r~jq%ocP(r#GCS~NhsLh3N%!|ZVP_}1nN7hI=M5Jg-MGo3dUiomp90|ONg zs!Y$abZ36*xfOmHb3Ws>+6P#=)88$1nkbSd z$z4jdLjPtX9me0?3}2{O(C#{%T{FF)Vcx^|_`Jp^wbX1O#fnYDbrwaH; zY6Dhm0grD=yv7~y&@e~1L+I|-Ok_LLqLQT@7%?Y1LU<0y#m-eO?Onl^So=qowdXGx zGG3KVrW&J_v9M@P_2}9svywI@Q{eaRFG8r(byawCcF`Kx7#MG3IL@Y<;leT0vcJS0ak)_~eLl(4<*@FFMYSL8g^+UtdA+(N zv3V(}$kq1~aj-gOV=BkC8Ub8#eA>5@WnO(X@!#0%bL-zqXvfk}qC227D(+ud^>Fd6 z86UQK07GEF#-*K%=numh+ppV`8VywmCx@p7_%u}t%Rtc* zg^h#9-Q}f*8MYkh10WjhJJo2WtEVdvCWXw-vwWCU6NaDmk)}U%O<%egmN>RL4lKLx z7M#dns43f+^iEsQ80s%Xh9LU;x-`{U@z`w5Qqat`=8UkL_F#_dcYG=yL2QPg6!9x@R2q`Pt{aBDM^#_=^HBBVG1 z2E~c*@gjXb;~W~jWQNfJquvqC|5+-LfRtBhiCE&STC>J;ygiWD?6BOU zMqRTBY`f|$Ljd*c=I|s@`c6n#f=v#)bGWSy8Q@?bdzk~1j8A@hn?%lI4D7Nbg2XJR*YXH$hqVDlc zRZtarCf=cBgOBg4Z#lq)29gs=Nj0kAy>Tu0~gd1NNj zx0d!LseauLrmV@yme(7>^557=I1oF457&I=j9PtO)Z4qE7&7GnHEt;Biq?Z^wl$Hu zi(HYL%4|Fp%OO9e*Dj73DmELoRGpb#<+hfomG>OC=LZ{!@R2Kcn2_(v9)Jk2y zjkNAyd%d%6pYyl8)2_HG`3tRdVdwK=W)+^h%%qzg;H~F|qKt61+)UvV^h$20jB7Tt z-n5pc*4sOZIM}tOG|ozRMB@|whCbbS_Z(y?uUC-S`b?h;$()gU72-eBbw1VjIz4C# z#xcXAs(e3xEVLy&#E27|^s70tU)Si|?itJX!z_EUT;}>9ConP%x5n44%3IB<4r_f7 z^c?A>onhI3t+zAQUVUl8VA=U|?>9ym7#{78{y-8Ho9@Sp+#@Z?7RGb??E6y;Pi6yj zE7IJqgtU%Ev#c0ewnNnI#<9lLcz*{SUaJ7XsGS+i+)P;@%GJXB?hyJOs_tT3JeA{3 z#R)X@GP;P_t=wz0yKy6iS(wFdbL(QK`;1`69>(@De zlJm{aJ#}-k!Ge|ZZAx(YahsyCRY0Iy`MF2*-k~RV-sK*2Gi63-%asW}eFo^}aE9S} z_b54Thcz8BAcLS^_rNLld^s=j{8qdHuaMVxzObaep6j9D?qX+euB%2rFpJL_;xZR} zy>FbmyIK29F!Kvaj-iD5&e2z719NYYi4xD!BE@9~)|Uf?W6`!xqx_LNgDC`!E|a}| zM4w$aKAGpX>S{Ljq2$>X8awYDWP31A|`ZF4nVF$%8nd>X6<=m33`h4TYUF|BM z;m}R$-gf_i^7RWGq8$8)_!Fc0ciSosu`&u)3p5~C;Hi(&fvy{h}uLJfSIm`uJU$?5Khte0FpL_eK^(AT6 zw-izEa{|IzD$A&!=()R@`zMr`yAoXULA2Sx>_#bmruOF!Z#bxB6;x}toZuFJCDE1E zveTGm96Fb0HEIGtbk}WV{D=@8-^$o{qf6=6bRs#uUs5czKyP7@Y8nufF@U-mNN{b| zsQb`0!Aw8E=EX%lcy%RIJ{Acnz-HkyG*PGU04HV4Hl{x_1mmcOgP?&1t$)a2SreY= zZ&vIIH^qSs&m7k706edvtYvZpYy0b$Yp=y z1FciV2Y&o1Lv7m{Saa1!atKltMIvn)DQ}UFhhz`AbM@`pj?DNB!w#Cm%MlDbxBO|3 zx9VG#hQfKhLs~gBenH0B?jTNZ{tbOkALWxv;(~4xlIn~!cS-c%lqo=on$|rleD;879&dNeURTC|f z1$kw6RO9m5omVHNA(1cBkn7B4C~bo(W;*o^zPs*bsCb*AZ9m>**gH7iT)OAH-G9tW z3pLfzAuMk{gXDY~1lgXI;P(S22#e>U76yw)mt-&W0PGTwY%xY)t@;EmZp)T}^DdAL?~5D*Y>+@I#dZmxXRu0NnffN2x=!c`{AYe5hBILt;pY)83ql z;)&7$AKr&cmL~Ju9rlLD8Qb(wt)b@fVaFSwiZw=u({I~7+VGCsl^6B&1R@5iqH(dV zAcNuPABLFM?mzxy7nE-kb|NgWQmm+cTX|PBJmDk(BEwA}|7|cM;a-D4Mzx~0e=>Te zYHOaE)3dELg=5;hd25*j2tReVe7kfyt53aZnYF0BlV^=1F~8WaG+x#S1SnY13x)#RBB>q8HRGU?9pvdsoDpYwP`Fx{weEY708_8kDIIaPd{@`h*<4a%JhV)AMtUA zR8$SHOSNWV;$sb;Jz*h&y0Er{^``UCRJ>k<_KR=PVvf>Q@H|H@hw4)Bge@nZ?*~Mk z%`R!T3)?imx099VqjQ|3d4MbR60Ml8r|)U;<|bl)Wk4oSW8PE695N5uWx^^68EH>H zfrNBjUKH*rb6pEa?a&UDp8h`0h8BTLr$*C6vxUg(LaYgg2Ki~n;c*`BuQiekA?@yqxFhiyyo8J!& zNQ+1r3rEjvg1x|tl;paYwQ7CsBULC_K!TpRCuwg68eesy@|}GBL9u0&BOKWxE6$}> z_%ywBqX1j1fsx1}(TgGut2@2@gdAXfjqUh}c=QE(B_L9n2{kn+G*bTERTGuS?ynMO zl2VgG8pjUX1xHJUg=Wsn+22OB&~wMUu({K3VI5wvt}edAR-AZJ*L8!~6#s~%1IM6t z+zY4wJJ=-w9k~F%(tdR8p5nuzEla^*S-Vdqq-T!P%?1LQF(yT~L zT`RGtl&nbYKs9BUUc!}s!v@d7TomAHS?S8K;8W2qe2w!I)(}4!Fdeg9MX$<6*qQC_ z;+8z`dWE8f*mMKv^WotUvVUZLUzV!z>Ihv*C6r)9twk)dEZQDQ;588EzOH@i9n9RA z8##&kKf~Zv!K+tXF{xep{h6eyg}82Vg!6nb#84`KrkO2!2C2gk-WpjHfTP!YdrAU^QzsVR!zA z+I58TFv{Y`_Y4(hd|16t_Js4HAKLwRniH+*F{*+k1CTV211zzW+Bc0@FYrX2Ymar8 zw5}Rw$7?^ZLbc6>x&Ewn&dbu{oqXtBn`D=eW%g5VZ|l$Q?jZHc52PT|UpSgAt?PI* z`$^p3{QX6;@+$$F&4+Vev9VDo#oUfstwf} z;&Gc_YvQ2GaGb@!0u^viBWR3JEoqM3z{?Nj;U1d6!{^!p3z3wqdc zRKm|DULOVb0?vfRZ>~sQm=E9zE*=(&OLx{ov z!U9BT#K63=nng6nmAPW2!8KXs8a9`4q$jAK*tZGVa_M-byOGAUA?9n*_;^V0y~eR~MR}*b4_M;(x!2i3OiXY$*`OO@^Zl%H zfZ)8~sp~N=5TJB}5z_jmp~|LElrS}&$ZvZK|Lkmw<;i`+b39~yAIlZEsN4imJw(dh z!{gO{EsF7nllbJo56F9+chEb~&sMzu3+0PC?&;;y&)cq5)@WNnOBJm0+xU`@_skk7 zICzPofbAgpOI)hUXNrzj;P7Uxh}j$bFqpg2SGdTIcEq<7p4F3FrRwpBQU_?c&hL|$ zrn3FY&D)nzWz3dJ7-V>Ymh>lN@q`5yelED=E(cRn&h9fidqyRSs;A=>4OK|WXGg52 zU;nB@?fCFM-JU2~0|n0DjRy=<#eh0rXNQbcr;n7*8A>;)8dELJ2pLJuuE(kxtIu{K ztLKAf7rfW@Y9taJs8>W(=T2-(wB|6$%^8?T{9QJ))1KWkc~Ni`3H%BnfMuzx-O775Vs}|y)&4Q6^RSxD>0=NA0s^yZIz05B^&^q2 zI0%s}QVI%r&Gs1r9W!JpYmq`oxcFT)%sa%vVRrv?(Zdr>FHAXDD*tT7V3Q zv-X;P5tIz`y06jvo;J2hII4c%;YAR%cMZx?9prAmJ1r*863>jmNPvCXbQV*qu&bK! z!7=Bcx=T4~@KC|3{B0GP7sL~;vJaP&sqUjuUKt@(Vso4WHG9jpBw+5lNOkpRxC3A_ z($hnH6pWhm@~2er)0GzGyY95#R~bXZcr%pf`-z?}^kF`Wa%j$R_f)7Fm6^B54d)AZ z#gMqY`|5$lOHhc~Hp<*$QNP)!vxxA3|srB{o$az0I&_4d}%LvXy zaBy(eMf5RTLEG>QpLSK&42bEqVGR#!>nO~Vw`1(jMfPBdwx*=M-(=V?_6>;JfkneS zCUMjbjl9eH&?tE!GOliwdX6v0TfaX-b*bwA3S`{_-wWbT>v$&2+JZ%}i&~FrN%C*W z3R}=x3K}V=6ks^YqaKvn{fTr{!}vikBfuy?uO6{UvA}RvqoHQVVFd!g1{Oa&_-}@P zDbPC^=nQd`@vp4HxsP`bMjDiyg6iR}0nByMPIKvv+??eoy(P)}{e;;>F)cY@d@edJ z5xW(QSywx1*OKt}y3d%_(MZ#cAlRbjz1PzTi^Y5;uzG`4Zw8m!=QYVxW}!eBteS+f@TKKw_%lZ1waCmLrLfMV*GNK5UL3IIJfiV>*UN z{Cp=-n|}}<0m1hNFP)+>BMt1r!a|{P1$KGct=eZ)+8@iuVejm)b<=_UA9kd4I(@-V zIh`xTd59dml;u1%KK4WY5dyy-VzV~E5{vluxq_}=1!gsTS#3?4%3FpFwbYE2XX)*% zsNQSU_f^Ck$uoV0iPMny>U(0Od>CFaY`BCcBMx>8v11k}Sb-8TQcIhhh8#)ao{h8t;-Ru zgISOygbiZssSQ5~CLQ5V4Hi>;Rx^RRYr4PgUu`472(JLfcS5YOF@@?}T-8XdZYuX! z926`#@ff<9+*tE^!&>uvq9Vjq$QMJ_a9VMguQr65oSF)M?dtBHsM7!He$k7<>TnpR zyObjYRco;z7ui2h=2@&*vYRs(KRvAw=~;{QcVPGH@|sVLz`HJu13BD&U6=B)OY&xd z!IPh;f=W*{bnL{edN)ILs)j|Cqh?r38V9Gr!=-dA_fK%9##ZU~+2`BhM}!Rtbt7rw z4Zp4rj7PBD;V#yiBF4nV!lR*?a`HRQX*z9;^St#8zgNOM&-Zg9b39)j`-bpbKqW2m zC9ifzq1#?*pC&r9wc1>>oz7Mldj^zCRdhj9mmh5CjQoGC3qwJ?Qis?UDmBn#5JGK^ zC|jG~Cxpk@0=;^c&%E&jX!w#`DA71*b$bF)nT?FuMWiRkg5ysg{TaNp#HuC*AMr`1f>*;m-Hg`IV)(_%TAH@5@`EJu= z=_-Zd>66SBt`n>D;f32!d=Fy58&|!OjGXWL!S1N7ClOf`?mqnkMHuM{{$nMM9Zffu5nncH<*rtqObHvMD!Vg@D0Gs4xJX{6Dc7a zsrHrj`<$l9Gal*Z>MT=Q+;dmsfJXaAVIyHQc0zjn)L< zvcJ%-W;`=5F4IBWV5;YTiGt+M#ZDwBP}@iI%5)Y=euC-?Ukx$V!qT&tJe*mjB^CB+ zcUa%g7t`06B0%LkB<^0Z?AsUxY|+(rW}V(>aG~gG@o7DlOy0|BplkGc^_3IopF9(< zBLGN~iU$Zq%Rg|-H6#cTi!P}SH&eTag8BC(ju$lo<3o4t!Nh0Rh1Xf#60v)jG}X`9 zwlqJpGhIJ+dF}ti(;vrMNK(Vbb6fWTKdg+ zwW0;2p{@g4ynH!AiyRKLw99;}y)*0qsHfU3V#??Ja5Xb9*~z(z ztwV4v#d=M;n<-@*@qYH=w2++&=^m~MYPlUx=c^;rMto;By>j$|!ygqL9U=a)<(;>^ z6`Q+(#-yU=VaZq2n{G2K*Ux`?wh-_C$HzN|=e>OE!$}$&jqRqfZJUja#f^l%iF(wK*dcLU9Zin}~AN7z}$JZ@dS(DUHF^Qx~*^6%iS6mkk*Ka}eT z`?auBmVP?)m|{+^bI0U8b@9k?g&*?#Wd8cugT9ibax3kHg38MZ8h#$UP=-5ffVV4* z7y8-!eZfxZX&WQgi7Oma(l=I-cVJP2qZCyZbMbm4yxDc!!cl_`8G)5I%B_hvSVKL# zrT0i_T3-X7y$C^fFS3kW@%#9CjxrOk2d~V>9Oy6UR$)(-InYOa9=vx8 z9yC(^HNkSBS5i#l@v;Wj0{d%(#}|KIgKg2P7|z5F9p2!DsEv>jZs-@z1|#~c)+fDU z3cbw~1bX&&g$$lcl=<(h{1++e$MuArM^{kpGP|1 zn&dtjK0SC;mG2#AM8|Pd%Z%QUlxo=^W#?(qv8%qXQc3%I-B_EGL$DJP5<;hZpOPub z{`KqVLm(x*5%5sDsY0hpK) zmAIHdU*8yFnU%W62LnQ47mmOCyyHNrP9c%;8R%{2^CydSTUuq$YV7C_#Beo)2foLV z3XF%#?^IHYzAPgfn^R2-n})ym*>2Ek>-i^nfBU}A$deDQ`!Ag9FB{Z!;k zb#>y#Wi{u%=qd|RNYxAxDR@(ToDOlxR}r{~ROUx8kq{go`V|P}9$eY-Fp6VqX;F1j zM_Y_xzifEYosxxkYXlVboEu)_g_b}44Zmb_(w6F#5cucxyn$Gk%iZ^G?_$?L&W>XN z?W~UIq>|uj6PC;9BAM+nB-Wko>Oe7 zGs1y6v-}*jX(%(xn)-#YgSK9{o%Q8*V9Q-SS(dwA>1q{OIbJl%{RFkpEe9jeMpEt% zMHjtlv29G)y@pRK_HB@1KD?NbUpxZ>jw-5M2N5;dTWP#fr!;KSBBO~n`u6idN!mFu zSiPH3IYqSci$-5x$#o+|ha(!KlF#g(#OK9N9g$lqH7p&pZkH!A!VxOs?P>ryOGp?e z0i4K7Y%7mY;oZLGiKV^gR`OdQJU&kZfK^9~$mDdY%4D%P=~6C*Gq&>`;G4M$rBXp$ z<5TP7Sz0?5#TZ^}#U@@85`}9aVsG~*ex+7?A^dIp6-aWtioQicCq^!5CfSJ2Mlg8E z?(G?sP7LkbSHjJm3w2jNU12ny7q?Qt(1Vk9jX704M}KV^u-@^Pqxkwg4Dt!?rk;;Ic zV;kbPUL_C$duAJVcE!`ex@M~ek^ks*ObnhZE-n82MMnr-hKGa-MBYwINk^%u^joX! z`a0^jIivc6YFiWTQ}m4C6TMf*l&u)iqfV8CEb@>u|+YkN)6wC@ujJV6N(Jeym(f zAiZIbF4qk^_t*tve}9LQ+6cagZ{7Cw#mxx{r94-<(Y|V%l2!g*dTjhzzqHKjYuQ^G z9d@wHeu-`CL|IH>Lg`Kzg(tn<0L`kyiLFNp69}V5DeXuc^z#^ukdlt>Ep{E^T@w!m zk0n(u<({5~SHd%+CiQ2w)O=+I$AOy*2ZaavW3C7na4pWtzLEAZ+>B=@p*bHLhn9Ub z2Q4#RC<9hD6oQbD9}H)s=q|VsOnIM+BH8YStCA z7Ul((*2wu2H=lPfQfrcU>5{tIT10GYbI{;j+v=^pU`g!pOwI)tO(}=5Bx*)K&S{Y* z)`;2QrRXFzdniQlxK0u=!-FBZ&A;{x)wi1<-|7)`Wjg4Gz0ukcJymumFf%Oz1IwYP z`A}ru>O2@&Ad!Mr+pcrYYdrS!YfLHMMq06E1w(CZnciszf_xWvb!B+#=$WYzBACj9!gr-fXz|oxWzXPECWg7@>)lSi_x^AA&mZz$tzmQ&EtTo+ zapX*=o*^ivWG#6WNIIiqXeIu^*P-K7!5dtOFi1y3W9?~L_pJG^8(6Qaw_k`vwIW+b zuS^Xlr*$B~+hctS&6D(wYSHPRt#l_4>g2yYBX1mcQcQEVO--q2T|iGkAlBJgtTA{zZ@Y-#_S?-^xBta`xYAUGgcDaV zFjuA$Twn9<$M_Np6#o>i5mON2NLO>8aQTW!oU;7z^}vdo_< zrh3WrU7szf2~Kd`33XN64P4S0zT4+J`{VQ3QL&S-_Z=tQ8pe-Tn(_@AG#4^_OPwy* z2K$GtKJ?@t%BKS%9knpv6B>co*+;<{{RmT*a%A%)>w$ERC{9GobIm{cdzf9Wc9d2> zF6A_r>%e%p5CJXiOq?HQi50C}k zqDB$Y*Tia|zV9H6?<*2o&hc_^*jG=Z8;o;CRYz`nt~0| zYc8NiUsZJOirqE|*N>8#+nu7&mpo)!Hyk9}1Y&8k05{d1Q1yE8F`onMV>1JaB<{$O(i zU)=o;M-`)&UoK7WrJ3{2chpzctMo3;=lM4y{O(os5C8jzjp&cIdU64t^Pn?tqfLDX z!`(opfkZQ|jmkCu#$?vPd)ke`K^m1GrD;ulLJ(C-(jXEN6H0oJY!95ujPo@RsqHjl z(IGVE05Y=H=sro~zTupC=AtR@xkbHY?9DVZq8hm=UJiNY(r-310Or^iTuC>YKoyF_ zW*sa@);4QblVXWVVvP{jZYX_C3#hSe7&eSITjCT0#L0KOZA-sAAJ&4$$EEsY6Te1f zG8r25ot|1$c}2)P@&AV5j6?{4ItFR_7DcQ2_s+7v9y-#k>s%oo7pJF1a1HJ0_T*(= zH7^4pcMNTpm8B8TvdVvxA>d_2(6a>Jser)i-=m+2xbMLCL}v~B@+6INb%?T%V;|9X zw)l{YIkwAK$}G6M>OST5L1N+Zrogl~g}tVa#~J}HtM0>6N_|m;GyW(J$itl=4_~-$ z-f#hF;Y3TZSjYU)9osrCCsNbh>0!qG%taMnRoZdvX$0ReJP-DMB>#Ay9e*dhHFX;_ zp=*noqDg~wty=(Pxxe?qPWz@=bN(2W;~P&1SbE{+q6)%}P6Jww^-J2sJMbQ_!rL8Y z@u03|2F$T5@Ni;|R5D^Bfd0+*7FcTMsDn7IkJ#z51BrK%cYoe;E+5g+!OF18rN2KR zYL#=nrtT4}H@W)DM#%Ehv?ar3cYe)b2k(qaKNVebsX7qp1MFAGyywKBz1>cds<@MO z{qb}qY(^Nt2mYo{8^XEffx1RRz`Dk3B0@Q2B{fogAqCH}shmw-h`#5kFye zVy~6qCYfb1&Hkfyt3XLYO5<6q{HYe)&3XR}A z(P$3VShNBzXfn~CY0Og{?#{P|Q+-Q=m2wJRryhzTzm=mvoZ#jb%5WbvPr}e>m{xKj zp$ue$T_i?hx5(K$(2Did&$@}n*9|PFnVlJQXv-f_sL6|&wS10C=VgOJ0JQ_0z5(i#J>J?Tt~51wTh#g8#fo-9bx@#vl$x- z??iei@5)AyFRt0vqOA4SwfL0k#}ak%X&;Ugt$P`yCss_Pd#=QMI+k&E<%6&cJq&6R z9{^*k{1(rf5AV2BMpSlfVYo%;OXTc0W!gal5T{Hk_B|kTNVk_Yno5m-v`?2X2a8>S zr-nAq8P0VAj}xl=BsLF#hAcB$uG-5~Ka;3olB6qs+^<*34$kRoc4>P8c(fGD zji%=1IJJ#4XO7wmUiG|xdb;G4K?VBCu(0LFI)RO~2|hI==6~~euAl-g7=iK8X~3Nm~2JQbsfw*oVgP3)3Rpn47Kc&-}76! zx+Y~Wq?t`t_;GJf#RM&U5{|X=wDP=ZD#!*@Mcod!RrnGuu)-)Axg9oLbd6GcZW^(I zJ|-Pm2Xo^Yt2it$K(-md`~`Nt_MLy)t|Wa-K<0Q^<~U9WfCOmV!CPW_9Q(Q)kH$x; z{YLvnDgfw8a=Hq*DYk4`&^QOh7*SuVMx%w=sj1yRdWe*`K+2RW1gf+R+XUKV6g)wjgc@x%M7dI6QygL%tKw44?uWUQ==X~HWStgJ4? zjT`ML(3$ymxBGvE!Oqfzu9nXjnOj+vtt{^8A9#ePwjhoD9`ir1ZXhIY@V}PuN}?Mj zyEs57^c@b=G?h8IQkZOHS;TNzd(h`g@2n3L4fh2-(og2?=@DwiG#Zu-6KUq0vFQlZ|92lC zAIJcyZWR0BV!(aL$-L&t&z44{)E0}ztHQcvv@-2!U?SQ0TI}MkdnX6^nvn{T$ntq!_K&bXfh04XY$Q(=Nrd_#OFKBJ-eQaNkWg44dHMe5(r z!+-zIVFMkn0oR&;chIsE-(Rgft^WEt%MutTfd5^sBvF!*&yba#8%mag6T7a1=0tNv z(u$n%MD1U!%fHFx4<;5zqKh6r$&e}OeLi|VsNdMM>@uxp=~@&OqWXLcNrFOFJ zk#e`+xZE`H)9DY641kjV$BR!M@{rAcq5+`Ph3@K7sOHM? zD%H(w6vsc5=AEc*_)#2xy5zIhFzqN0&H{8b`4v~&lTw;8 zpjh)NQpFjY2G)|3e8=yp^Ynl9h5TDET~L6M6S!8J(_I@b_FpnjfCsdUSO^IV6A}<~ zvz@vjW#+%W_BM}?#FN+P^?`HRTQjt&`m>+s+yOeqB|Tl?5L1C)Kqf4#X+$my*5uJL&ZIB*Pi1DFC$? zSw-}i^Ubz+_iNFAw<-QZ9lF_NHgAt+78@pE*$fBdq@-ZKs#KmPB+K<^ z!S*Vy<^}*@X;x$Rcr$0Z3dXy+iRCEA|4Tc3q4{(-Iz4H62)T`*Fhb9%$aD;_I+qhi zl_s2g#K`t2ft;Prci$grP@5ej{$`E;vp_i(&|3o|rw-TYrKPr5RMPj&lE@b9-`%Ye z^&XYn`uk8R^Wv4!$brJf1H>^gF`L`n?cyoneyIPQ4IR=Xc7&O{g+)0H!@qZk+_$}* z%XmrsGQV!wt>nbTpB;RwGITMats`g^u8|8Ygvrp^pkef_0btNs!spv z=>jP5rUzlQ-QMVp(btSWxIj$zlW6w_Ti~MPS9JdT>&uYTPoi5z;7VVvw7*JVUuc{D z$rk?i24+EhCMAV=q21uYD zvHibDWaNSTTd*?0*eWVhp!>DR zgAdp09X$u}orr9_!9Ndb>}q2}mQV>n6M&19<{WhMu+?m8JK!gVp}O;mTG$Y6WB31f zIqtwfQiLblOz#ah|HW{{uL)D)}k{Ph}GD=ZaWk@9sr z9d6!Ezcmg^5isV93icg`<1qn;6%*QPwa$`?{c|1V;(*UI@&U2cqsN!z!i3PkydA_M zWn5C3L(2%)ccp#kE$6uML&$Lt3_=chnA*!d{Ax zr+Nr^TkgHZ0h@VATsW@b8z3!dJ9n-^M{w`B6I)pyz<$VO!*nc@66pwaLT4?Y6@j~o zNn4%-(Ps# zWCySL5@sMje)>!qTny~DZuz)zolIr~s^;M_XxMmi=39OsGJX@i$-)VpxcfYq5}U%R z4-!PP60uMzJrq$Aib2l_{BUn=0&Dz=elqF$rWg9LnQXlQ<|fl;o>v(hkgXo+1~ z)893J)`Mb;PDJ?)YKW?*9%(J2(KNJ<4uW3w`rXALTp@Q+d6CH-fg_qr|M1tV+|Gbf zKTC?4g0x(8Mx=mEh`8Zb5oU|PltO02_$A~T`U=>e&$M%F28EkfddY+mkuQD_q6Sx# zlGTo~(9b%%CR}<0u&|+f;0t64RB?av{u#m`n5L$X;cV^?MaFI3jBXo)MAq!^A_41t zy{A5aiw^)=vgx7DuXIf=17-$(dl-#vjpHMe2w$>^NM}D&bg0-wSIJUuk1}gI3FMfY zu6u}MWFuBFFQ3jU8Byd36T1I7zgYQjgBRY>U$OcwT<8{Oatacjyiq^(-jtyvv!EWsYPZ5bH8y4 zu&xSeCCb>r+)TIf3Vwf%;+b~Vq%ZLe8VDFc)9$1*f{y$1|A=)UePKyF>JZZr*c-88 zntsw~He-aNb4FQrszn8?J;TTJhe;9`f9NxrOoQ%pF6n5h2%BA~e3*>|xiswcX9%4f zzY{rniV*7z)q1{nm`rbeCrOx~o4`Q-&D+>Z_MzC7^MY_~6d_AjdT75VyG?!=ez1<_ zX5=J(kG!C>QTJvhaScyVpR2QPF!&Y?%OEPeVXt({?Sigee0=YD+*I!6=`l!1LXycB z?^H2qY6Ck+vlJBJZUEya#J>340o@USK?IXHA+X)K_L5} z?Y@A|LQLn-4f_zEveNy}L}zRq9?bd|Ont~`D?a(rb|(_gnh`rPR@>Zo9E;3)9(V z^3Sx3H}#uF1Azv!?t%fI=`9X-R3DRe1a_%n`Gm>4fntNRfn2M{GLG+C&}YDlJwvm! z0}?`1$5mMoKJ7<{Jj_c^w%+iOM5XviM-P;c^&Ij#ViyjTac92_al0pWF`5OcH(!H)+b-IUO{KgvX-X4u{xKiOkCb`&e!O(pVnemP+#q6c zfiP*%3u#n_Cs@~^{RLuBW;v*hk=IZ!CRQMVS?mWGdggxeMgfStJzb7HXL|=VnBxmq z2}`!}PQ*pSRescIW3lXl3CMI>!}|;PJov{dQzX$Ms$?QKtT!s|)Ohl&bdk zMEf@2DjJiVtaZ+tidG6DMQdQ~FFGb@hv?pn5Vl~}2vOnLfol>*`5A&KRqJ@=8)C1$ zy?ZIB-u}s=ojBGwc-)@wWNVu)@wN`PHdIn<$Csw(I^xq#w6rdaHMNPXK)<|!ZEbg| zJ2p8@TC&&czE@rqt7USGigY}&5ej=MQhFWtW3F&UM4IRB+EZB*Iyoe>@vcvz^5mxk z4IH2K_ZeF{Jx)?3Jl*frL2u;Zu;SdXj=|W?Vo+PNH+Gh=zXw`Fd(m`^uU!rz{3Z^i z`dGSbX=cfdL~?@=E0b%i3hVW+8b(Y`E5FgRvSVH^ev`3DIT^I-aillAKEQabcMDH> z#>Gb>T#-Nd9FcM|MErCaFHw|GYPpqVgM^X$jFBr1b6uQra^-rhH?%SgeVUD7ME|vT zFd`*<7wNt=B*i_py_F9g%^*TYL!>^ANAm!OQ!LVc)4*(}6^D5|q}MiRptXLE=O0PW zqa*?Jr;BW#sZU9|#>*Xt4oPTTkDSMK)>Rv&oZT*ER&8$5b6M%ZHG&n_)|r*(H8AU~ zoOXu<_6@DxPd8_DX5V28sa1W)j&TQ8uKa(jGx}3JNNPBb zTn%oqGcIh#E=krL32%;xzaehC2;53}fjEB4o_Hr6o^ho^yH~O%(&qjg`;zqIVX|iQ z3MeCiW>!bP_T+H9Mv~5c#4G}SBRI7qIM>+)0w<-!gC@<7{nJosGAwOx2t0MB22YCU zeDjS_cd@*xw+Y7c7*7d>#^rW~&}wIW3&V;ATT;T$X7lRjTGxH#_LU|=FP9ybh|>pH z4*ZnR=Ru7qn0B=G64ydJ`|Af6n@u?;+0@{^cy}yo4JTgbo8jLCLpF3M8!&l58O>GF zuTAU2zfWm%n3T=%n2rrYPeKO+hvCQ~{C#fA4aXM;MeFSf^A(rgFw?`Tbr75xOUSG&M1N-U#u8fIrmZ)XS+ftDWn(ra!nZZVP{p!CuKvZ$a78zUvXwj-DOcFK+*;sgvyj1 zGcEHwWRNPJ_54c5KfbpSE_ay4LPrnmq{$?4hchT7Xeu;6PdCw2;&)*MBXotr>~dPn zXhh94(kfb;Ikj^yVc4%idem+rp$@1AX_?K%SJ|_+{w`K`vy1uw=h~kq*mnOT7RL6i z@2gcT;Iir8MF6(8o@+SnD`WBJG9U|o6kaH;IkBS_MI3m6beoTIz#5qWiF247l2^cn9lKP%lgWvv?7IZJvqO^` zJjwS$C&NE$Cg{hH0cb~e-J@GkI>t`cw6Z1?QPB+_Z_kFGW(CK_o!soDu`VlHs(1Mk zJU`b48HInl=xm@*LVF)LwgLZ`JtlCnt{>oj^$K6bxw7#}QS$|t0auojYdT!0kz($g zUZN?PM6Y$*d>gs11UqBUxxL_>2~Il!>aKY+u^aJ9Q&^BpU_Mf1uDhs%gC;O6HS;{> zu65cErM9x&Dq~&!ZC{&j<-FU}0)EUOHaG?>%jjQBSgJB~fRROfKcfw?Sj$eZ zk@ZLd>U_RoeBFD?N=Rhm>{(hMlq!`D@C3ZP8*1PG0{Q-cCab@%MzSg5fY|%W7SoK2 zJ%?051Vj%1j=%^Wt&om1q`Mx!uzb#F4=+=jfxs?FJ!Kle6Wyo7JvnNydp?ieeFRZy>5c+CIxTN?#NU7?KZN7($N2lrp7&JK z`<@BLx8~{L0!JmPECtz0INWj`@Sj4_tu*R+ae(MsdX{Vn1^fK$<8ycI8Yr@Tm2|jx2pNeHu?}C&H`brCtU)A-Nu)!#rOhqWE{F?fU{Su7TP zDz)04^(E5nWC=2c~ffCw`$HVSn5xA-#oE8Q+Y7W#B6XC$Y`*+ zkrvP&ALy`xzmoU4aMrXN4rx39F2MR4gL-;z#HIa`3k;P2{4czVUpZ~G#%isV(QU3w zZVxI6z>~**jwhGR{n9m)mzNj(6(V?+5FvUW4ab$GWq90Aza2~8eP5DNC&UfLVi}m-LwLjh zi>^5flic87L0kdxBPf7{`Bl~RdwZs8(|yL+O44t1_bVE(weL=tuz%hExSO#U5j0Kf zg9=$$GxD2;m$16B;<%;_?{lfjI(D=z^J%~dHX6DhXwbNXz)1t|=0Rp~%r|!qH0~vh zj_dXB@dQ;`V0qs(y&s#MM#@;RelODp7Z^O`v{>#>S@FL%%q9y3QlxK@4OU*Xq@X(O zaQ48>F+m-{;ZK@ND#CYvsrTQ*^as=Y4+K!$4T?cf+D)FV_-{z;zku1FFA@GOi2T1$ zTR#+CpJKlcAe-m^PUdeZHOb$KDSwX}fB&81hq9?LPQ?p!(e=?O-23%!pbnoaxy=x+ zbHW3moyWh%m8*oJ<1=LEwp_070kG+upO?-7Pyjf9geTG!UA<&>FSq&*4*Dmi)UG@d zs!)b*dT!)9Arq>mE&Ks8+c5omLGOSCDZT$f5*7Qu;7&l%SOVZ_6$T^^{vlaFiIX8FDR!r^ zE+c};uz615ued~R>i1|<-XLrr3S=?<{^D&mn&)%VPI^nV__2lVyivjXg)_7p$_F2X&l|O4dW`NZ zA9u&0@EPC29u3lvU@JXPwcV@9a)VtIrP}6QfCP_v8I{|1!e*6@vgfkn-+A%pRf~L! z5AeL;Awmwf`nZCvK8^I8p3A4e2ckyeTJ*G+nkKfk=?KBzE9}z;WZiF}j(n?BLHY8VAp=ijK&2obV#O;*Q|nA2_V5 zHoRV}?=)+<6qJL4Z5;x1yD8*Tem_RG&o zmq!OH@2^k0T_70j6C)LmQ?G($?-zGf9+VMd5@5P=S%oP{^+H-YL{mBZpO}hqBPS4k z2Hr{RShiO#AU({pi#BfZjx}DvfIftbs>b_Me}oMU1OHk9C!OzjAlMciFnC(eU7IyB zF4$HrG?0izza7j$`hJSc}>l`ic8Hvp+agE$uwbo}k}57!db zrN<~6oG?uD2lrD-a&pNd1j03Gu8H*ZJbOdRUwq1q*aunIiju$OZ=4B`zwz5=7d*aw zdB<3JbZl|86A|9aDEW-2@Q$b5V>-51eG-&z0kXVgPkYK9=voyI(+PgBFT2? z?!s=Ywqc4!GCugu;e+8(YgBY~)4tc%RK5M9)1_+s!;G4X_v6?4Lbvd@f)8)N4e<{A z0)lXiVz6M>5Q+I1w23Lc&AyEwWM+Pe#i^}+-tw%rQ?MHnbSRR#ic5)xYHL!Yay9+T zIebzKQde4XBK#OP9~qqX#x#B7bj6!F2bY-VEeCHN**DJ_2V5#)xkewhUnuix6Y&Q; zt`VQLT-ir!2Yb}9Vpfn+47!88Z^qq;{p<=BE@f=l+=#=^x|6} z$?MaV%!$WH@4rxQSe~+33BA!S?9TIZ$b1Kpq$NJBxSRede09*A%}9P%qB}&E3`4p( z{boUfI2MDf5K*jxmF{5|(gu_bWH21a7!i}!GA$tj7k=sP^pl2$2G`at5!%_;K8x~! z(Q=*i0A>~lGWOdQ>n%H=V#4v2(6t{Z5q^2cj1O4;E>v$Zt5u*<@f0boB>Bkv)!86TqRw)|Nmye% z>^(TZR4dTCLUp}aJ+hhr>m1D#^3ZA{qBCB}lGkcXo(6LYN>4>oV{ARdCplRq1oZL10Jw>CvfQux?kn+I9Gq|%W4jsA!q zits#l$20*|Z`=@5c%wCa2FSJIwFxrF)t(coLPI~1mODSlnM6ZwAfJx0?9Ij+yZ2jE zp^?JRN3X<(13nm`L6KEHAm-xYGA2fd8e@Ay7+YUgkv!PegDUwcykf_kn8WNn7O-5F zZuz3|STIoQphy#RS&gu2;~ZRSC=E|b6%k|!&s?=TbQ!be@%tH8k#+)y9c+aaBel$l zzCF1JR}P8Wdga~T?&Xb7nBXPDf21E{MI_W0@ZB?cc*~4%=ONE$PV`aHV)vFoShRoF zJL#F(E&aa3bWkN8opMVY$9{;+z=MN;oy0PA(iiy=6gxJG4foT9pA7^Dct^;GF(e|M z#!X_5;L07uAPJ$bXG3g!csNqYPRxw8Q=gF{STE%*i%}fbv+7IMt1-zhnxSiwIMSB< zn5}niPVlOqEP^smV47cefzlV{9RhAGm#&}MtV|VjOj|;k>>YDKT8#8z_H0X z|HK-HAm}{hCE?wPsPg9UmqU+JE3N9eDvM~eGyH`c@;SJm*=7fP)ZPz?o&-lURE6}z zlM_79BP1b%L6hwUr4@aE=)}yJv`<2Q_WtezxiSt9aK8yT=gX(}Ot4p1IqM%;pF|5F z7gw7#qc+1JBOU`XYbmQ!-%OZBX>^D!h!C+E5FyHdGH;t5KcTj$J$Bx>Bz(*05la5L zb~^=}<+lyc)T0QMj1S*gkHF62x~C7mc{*7xX_ABmB?9v&i`%Sk0RJ@_GfRx-Uua!K zon@7FJY4I^p@}LWgKJR!hhEz)eC8rQ7RlD1x zdo7X{fqnBb6}#DXiw>{A_7tY~PT3O9&VC`+{n3ekdf=`P(dDCzb(B_Ta4P{FX|Lm( zZiszry-&ctObXWqX3cuXCO&R7b$)bZ;meK7`bZM;6RxdH74Q^0iIxKLLl6R#ulF%7z0@=&^DJqjYA~64OV#V$E1hwbu@3L8Vt*Tjr|8wj)rcCCI|W= zFTw^Mdg6v=?>%X#4Sbf*4<(@iI#*;E@b<9&GRD|c6`zh&O1U^h=-?DBCO?q5z>_V^ zR>TPy#hBzS^ewa%q||DB@8j}v1Akc3B_^JmD8`FC>LOC6v(H)VxW#$I*#6qqmEwg|6#WuB?Lm;1V9TOoYg?`ll=0 zW4oLwt;QwgaKDr?Zm~oGiTV&vdLeGY=H3gIIcX@!yNQ(p#gj06r^qdHC}pynR%nI3 zbjB%|TO9Dz*~AB~yE;HW%vWJ^C>!XcW!1G?X5z9ohLUXKPie7asD+k^aTxV#m0`rJ z8{$DQmo#r@d(xVmSGCI&wB<2*TFk!0czY{pV;(PHm}uC0TmbKm+>Ls_+e=>bj4;I* z9q2J&NVs@`ejHqv6{UlSX8_gzb=IZ<(&Q=-G>62wsv!|y&MSRvaZg`y^DLKOhCVl zCKTO|(&)fm-p>Ba6r4#a;(3e5QoblUX2I@Mr5gV5&Y@t-d`VXEPVOCfC4_H3MoxFW zHrLH7QL@@ z{3M@)mDSsfDUJurccb$OS;y-RZlbRKcxf=UMmSkFgSEkE<^51p!9jBUh4FO!=hZA9 zIa(NOQ8);M;79sqVhTtC{yW-Eh82-f0xM2yd{mD=dWpsmaY}wD7)**EO1E zGaX8VV?W2l>wqHtA(Vz{DH%*bMrb8{a4z@vv3%n9fb;o%Xei|*G}Z@H-)Bm`t{;S| zjByw&8VHa^C6rI#Fs52aoZO(%l#=9}o!BEx)<)j+_}UYmTl>twD~%JNan3s`+myI3 z7vJ>)B93S{kn0Lb8?w>MSQ+<*PKHGH6@Otdrqiq z1glaDqt}-0sm#Xz{+$6_nPoJzYu18C-)r!)-2tPF!6#5LNWm0ObTKS;IP1=uA3f&O z1)e3;rS;Cg?StuazLZ>ItLw)_2wwgDqd6#7R&8*)H|X>ix50Db;=B{z?5T#v;d*b~ zux#w-mM6kau5`PdAmVPMO~`s3P&WVKwJ90q8^w{bnE1Hxp;j)l*@j6n`uv|iUB23) zMsqysPU+aiUjM?eASLVe&<9zBPA3zlXsbq9k};cz5+`TeB=D3UuV-|P(E?n^R;V&O z`?)?jNZOinaVC+BQ=iB4#S&hG%M^Turk>hMsf8YKx~P5m>TAFe!E=&0jphr~g}kSx zxE`zjTs=yI@xgj^T~pEXir!@U2GIedPD*MTOoXot8S*MM>cWG=l%TE1OA3IN;?{Kg z<9ey{5)H&|rY1YZ_oxNfO)Qh-%@4hbJ|rNC{m3nOZTbZXI- z4x5sN%>ZyFKARB(#oQjh4BsH06rl261bN*Vmo+vv$3qWkjDe3)X} z59{P8a%SP@fAfery{i`7D#6Y8=0%ZN$U3RVQztL zxBLhSbQ^tz2m-9JE9|Y+u;eB5rb#^0lN_fG!Zyzyn+^O`Thp&c7&(hW@(=|mFAd)0YlIF5(i4Y*$U@$( zXpL?rrNqJaCz`#Db+Vgl`CSCtdx*Oe+F=J!`09d`uzFkkXPh)ftfj;9A}Sg0ooE;j zcHZ1)>4zssK5-Z3n@qQ;W+0iH=AOLgrCwNCnnkU0xQv|Ia<$Vy9 zGzq7$crj_)xO^Uk!5np`;h0u{)61aYK%73;Q~@O?hv+|eEj>hNFt$C$0CPO_rE!|* zZLcA0lL~n;XPIID99_4pNTfoF1c(l(w7CN*TEa@zGed2nUwpcy)x}id@kCW}?hWPu zZ9;j5ac-%?5CpSdg`B{!Fg&YDhos%g+U)q%)G2*2>v>;{LqV=NK6`8USy{v`A`9Y! z=qi{oHoZrTIe02vamwOHsYU}QJi+L@a82w;ZEtD6iBf~MeC;(Yn14R9=&mVPEM1j5_#a(8=_fDxjMFl z(k<+ZpoZ1f5c0sCit63Bx-vzHe26F}fJmVlh|5&HSI~>}@2aWBU$!Ai57=SWV{U$IKmEML)i=@e{%21HKz@rdKmDH200{A23W;de8hBnV}83H3SDH=YogfK zrq5%BjccyuDCRHFR30D9&>gMnIWOJvHl%4$Mc|cHo-ntL(!QStYN~B=YJQ>m<3_k_ zGLqRz6o{Q__uN;BTL_zK_VNtu!V&hW8ZbUzgqiy=eRVt)s?bKRx-rm)b(45y(;{hR zGH&pQy#=8j3a*0teA!rS%lCQ20XNDkR+>eOBg5}BhJUt`nvTwpHco5^E8V$OtOorC z@c=2)0A8Gc`|az|rx!#S76Y)sHjG5x3s#T_t#xdaIC27FLg1Io1ET)OL52b*1j@{U zJ{SjT3tsKa20YROnk|PBnsHq5IBpa&q#f|XJ+6#OU+F&4qhOnoXPj%60sVO|Teu(c zyh)if2Kv#-WHEFzDQu@-*&)>KObz=Vb7Zqsw*)^?kBX|`S#D}OGl(`9HtA2hJi0!` z`gwXkKE>kYGWX=SQJ@yNwW0Kh_!;Yg6A8wDBdv2V8QjR4$^#|-XoMP~9kDqw#H08) z59Gn$Q`{hh^*_4bNMT=;cfm@YNYwqwS*2jL`j-{G59fpU6jn(cF)N*}Zpp&pe1Pv;u;RutIWa6~pc4@+rL(YSE&CQPvlPhJ7(~7oCH%y0F z3WD2})qWLX9QTT_axbnORj$?T276 ze6OsAS}Hzcll6wO>%#1;PsN6|%NAH-I$;vvQWF4s7ZX_tbzkP1&{f>x`q)3MVJ~H0 zWFgitFywS6oO~LZexr*u6fzbsU0d5`L&KM%pDr$Q)n5(IAb>WeCL)u(yqh;kiqCqB zOdl5>Nzr7tTsn*)G9$d8qb}xcSKWhq0IoLf?oiMe1JzYgw?v{TW7=pT$8Z>910p^6 z9JN=#3oCv99juNeG&%Q>Qr8s<(&4+_-9g^)>-z`o5)+&O|$ zb(j>|cvz=obtj6o9aKLv+8W4~q_eag4rXmf7Z5BDkQ-c@EDN*VfA*$|FhR%UPrJzF zbhiUX^1UR$5JXEr5a3>s#AW05$!3ihu%A*Btcf`*xoM zgTh$H`Tac1bd&w~?~Bw()!2l%&m8xS`QWXuW8xsKA1ZbXZwMh+)21&bgI7>?TO-4Sl4)O=X3 z=zLS1CSn*K_Fs?8Ks+%7lcyvpwPKq&0hwnv5}m+r?*tjz8{Q9i7zRDaEvDJea6%DH zb#10U$?5N~{Er#<{X8FHT||)6G&I&fPyhY`8)eECX%G1So0mE&aAm$aO#4t2 z?#%XR=5KiFZ!1)X@dey9)u=qprS-RWVfg?f*ZbT8ZVJ*JPoY=$Xjar9u68_8mI-eJ z*OK+hz;o+vLD0^?djNLeRKmi?cL`Nxki*a6=%+y&hp z*!lZT{(H0jHQwYhqz$;dIq~?+!T-;yt5W_GsHvNA+&KRc-6RbX05)kO(V&)w-uL+bczee%OS&cf zyUVt1bC+$~t}ffIF59-vF59+k+w4Mj@n6q#X3jY?^Ui#HKjz-o&b=}sSLRv~zqmuG zRT@zn_N9N;`sJy}{oCFU68pV=(YG7lVA8cEpdry#+;v+Alb%YLM(CO*fB5Zt!kK%&us^8U;5Vye^&|;q7!|j!eng_}qb<$@kW6 zN!q6Mn(hxpSh)LvgW>t$i?T{R@9q??_NaDKOc%)Bc&AS0~h4IEpcA4jE3`g0VZ z%&sbgfZlG^bA>Dx?77EZbqwoWqGvl6o#-Zpr2hP`m(2cW3;DtjRb=hnuWV_0#>Pcz zpCvI(l-tSChUp$eD{J)-n;{;3-A5M@C1d=4^fJ^|&(~dy%oo56HK`I(7w9@VIYX&> z)`OwG(!C^j1btKOnZJMG*zL!Qb3uP_yB!r+t;j*b;zFUIfP@sROI^Mgf-w13f=+tw z2k(&}?cY>uye*-VZ1$rGM_3{r%{vmGT`<_p&1}?5W{pn>=oTXq@C>Q1n{DNOJ)GL>S2Q+%y0ofF%c?aljXUs&pWp-t0P+_JHOc7qaJjxS(^-OHHH9QgGVQZlvrXo1+k^wXa-nqwxz^ zjo^=a4vl<&OK~IHKvS^d@Ukni3vr_RW5YvPWyT=v^P2r}*`}UFQ^T{cbdtcmm!#yy z^o_qKxIl;K?#Hym6*`+}pKLn^5jiDnV9xcjC2M(2&G1os3Waa!omS4mdu$(Rz;cZq zf;3)&4pYK?28)Ff473N#>v532N1bUB;ovNtypla zpsn^LAR?pf{-yKCR#~JpJ@2k8^a7WM#DlZaTz?t0z;eZ#y#_eR3`sVh8m@pcTYL%f zmAp}`(>o(v^6DbJRWY44Tp+7;%UtrFmzR*?JLgWcnkPZ?Epf_>LjBJ3zdh}O+Mt@n za6Cd>>kfp?1|iK>%w#+SPRPgyaT_xTTe`#OW=Z%SPai+S zjK;EOG4<@pQ-Z0q_>+X{^cWBy&`#(WLLjA7O7caE4qf&>O9O+J{3JTtv`K@ok?GLp zS*P}SN7LWic9d~aW<>re?Yc`>14+C65~DVj)J%zy8My`&o$eTB$270qzBe(E8eA|c z#g-qt;_9V*_xNsfZV6Tl-|;b=COj=MwiDj#6J>-JJBmlp{{;>$hyF2~cG4ngo}E*H zWH2m=us(|VqgTHK^^ce8Zl8dk@6e^~srgj^*#5ux90=W5{b0{VFNYNO>e1Iq|} zY%aYhLPlmXd6Fm?$EnAm5Iq#(WME~b6l>Emo;4N_s#9Cl2)>bs9N&1uCerA+~Hae)RpGqJ#6$5{NQT;ZcN9i}oD6^Djl z_D!qIy;0gon(%g{f|hbn(V&PmgQdVnJ0t1{#6App{kmGn^F*_dmK~qkbdBMqg5Phk zfcRYQ0ECf^-eIx3NJ)NTEYFHMt0~&#+?C%54yTPT54XnKT+%43$5IdniUfcFUvOH7o?}ug3 zd4`xMX{ad07->J1XHUyF;JKV3`#Y{yan_NC33};~daX_-c%&>%c2ol;d{mZ9Na>B> zAFDp_zgB$;)U#+Qlq-})MGPouaCkcEg%NEo_M$I<4Ai6#EKNy!vJfyMiPn%Bv9{LZ zM0H}5l2~H;KXh_C!ApC55|(2H3O*703hRZ5_VMF%H9SG9a}k{yKFrGSlISSWG_IC* z$X-cD=d(n(SVOd6c^qUq5;an2o#S(;; zBPB2_1{zB_<5n`MOP=|*;2{f@ynB3(Mf^V0A6TjM*#itC(vnQ4*nluwC|KfQdjqBK zmt#IF)w-ghLp7*R#Pr|GNT~|hAJm(gL2=IP>8%fz#U@uj`Uv#1+3g>GYtr3Sd=<${ ziRQu=8ab3DV4|0adL+^4l%C|dSBLKA3ca_WK;<1+0;!3+_?4GawJGmRR;U!wT%Dlu z2fjEg){_ptgn8Ss%*Rr`phPNU)oCQx%uJFNF~EqsE1@{Bh^|-t*7J#9FEjRn)XO4j zRFob$F)z%CDoiHc5D)S7#TCa{QPsc(Xs8l9dFpv3iB0ANk|_}9-!IqzMs{!A!s|e@ zy5%CT*!tyOf2#$fVl(I#&a1xPNI+YmF!#BuKaWt#<+1)sK`ZSwdoV0g&^9n?W6YsA zQnXUW)cixA;hS_7Jta&Pxp)4vGSuyQDSCIWU zvuIkR29FCC_LKqYfyOdZ#*R#Rtn)XkjiJVc2F22%71JvwV7cp8ncmQ)^k@?CpMySyFh-(VUX+*Tt8>6~sdztyj#@IophofZ1_iuJ zMA}yikZZ&2|J0?~%%;!D1|F}66L$~$+FS{*GbDd-t9@v%dukR(SGv!tM=7df};{b{7YhKRqno zwj$U{xxQca7BVAv1fztohmpVnhG3)I86q?U*~r@;zmT`ZOw=~|6=Fpa&DSMGe6elV1t z-f$|)Cd(!eT8{Q}0UCWPriEm??_OP zri}$$q1ra$hyAdN*p%;^MZ}x_e=oipf&bbDFqS=X=w(HP=l@x4WyS!r=<9DvVM0Ba zcX6!}-6KGD|0WGBrI^%##74@;_u~NRKG8^BhoK$W3G2cYeOF{oPUYPjw50SH)0J$v z5~bJyI`XpyVJKYi?3i+Od;-vsO0iFe5~r;a@rDPb!8wP5be0g@Q*T?pPx^3|30>;K zt>{qzX#rpgYIPMyw?TaMcuCNoRJr6Y&Wfvmu5~v7h{0aeM7`Vdam`hqT#n`1|Lny5 z+OG)?*SC?@;s!l`b<`8Etm9lnaVYm0<#hlr{$o)VgD`~Z4@Eejz7VRos!GZ01XRo& zPQUP88;`fvim2M z37f51^If` z9yjV+TfXA#*q}U_AdgCvG)mP_wEZdCI6qW5% zGktjrFsbKCVM`sz;mVS`(M>3$E`K{;g$8fid9fYO2Sn@zY@ARB$yVLQZ&MZ;%FvpS z@g~J!z+Kkd08@zzqf$?=ivV^ETVV%B%8#9DDM5mSkwIhHb!MFRo4`eQoS~T<+JSQA zBg#?-(ch{Om47lv$D)MyHT6)lDTk)Nin<)n8NG^mywc7&fXCPXtIE#6VA5Ft2SeP5 zNMGTmJiDH=O_ju^v~^!5wJWOr^ax;5jjEuX3milf_`?6x0tm-i_zFn2>L2aFY#06Aj{30A~Z4m0~Z?TOiRgqgoJgEd{X;%Z1f zb&Qj$A~0JF+tj!li=$m!ZY{T6JOZiW`l43l{r1jZgo7^XVb8CosQ29I!dX++8X z#%4osDOK$uv(Vx?mwwvy7#F4f%w}*PRi&(_zuid{z&ALm8IQR%01}QFaoP(MhxaL` zPgwHK3XCtmHZa8xY=PnzwI!|~j!d0Po}@1{&d)fs1K0K1Zsdaw2$<(tyGQ1Ke|FM8 zg|5s%5A*4I?ekryuEc^eKKdm8CUEZL*S4ks=p(qcefK-y?02cWWH=s(+}?UG%_lSo zKx{7l+!UKBp@ea`CDj%lkNbKyI~|Kjpz3lTWM=;YwCd>*<#wWxgwH8aOCY^J*ipCq zQksPKgnDv)M|{|(Rj5;Zz>$@pV-_nspw{bYN`4H{uDpJo#^nnZ z%hD+<-rNZH+{b5 zA+vq+A85dx-^GE0KYsHEL*_+4mA_jI-e>r;^H}2)-_>?GHy1<;hL!r&wO=#q6VXCU zBGq*O*(HQp2!mjIbO*Ey`1QcZ_<=7n;^W2lE^gv_zn#n`Cp=T7KxLWHLM@pKa4u9!R4K zTMH!XgSN5X)XDu&cFhvW z?cF(D4_s%-$kaievp3?z$&(b-@UJFfmAtk&w!`xxlvny<0)W)ngD@2iLwk9oseRX~?H@*;g z%*N)04_%|kz$Xi@KU6vF#o-RzLfzwHh4vx%oOrC3Zjivr^`b+3p&y<^w7q-~QY$&GkM1+v=48nm1K_}eUt1$c9M{+-SEXE4UTTzJ z+=SnT{j&SQhChCAB^4ac;2z|S`QO!$F08%UJTrXD%{Es#K&o5hG3VDLCLTrTa% z@yw>LO|oyn(3e=<&nOGPiB3+6wTw0LIKzpt8Yj^?v1 z&WR>3&d|j@Ki4JnJ}E(99H`jJo%XK>_vza4EZtj^wV z#4g;rRTNbIBcsWe2Q7-|v5D!)15;C?T57mO~r=$^Y6s*2D!EbmSTKoo=C}k9tuS^t8lYG-D`=tPU=AJ z`dY9CkS0Z!!<_5x+vfs6xXccbktD+0_n{@guWk3`Oxpz2dd2hUD0zL#;i&te!eEyA zR?=NyNlvEjBsM3zIxAZ*64U^r+AwG(8Du}IhPC6vkF-o{nX#2wL6J$Kq3v+i-jlrT zjfY-D^2*VuypwSAa(9#uw+qPvNFf?^4yJL*6LMEFx_vNLw5Vu#bW%Ynb;z;W5=+CI zP?w}9ice0#w@w1kp*5K8hi_#&jEP)x$-{IJ;_5$9?<&K}6@v@0hHi7-vg$i&i^y^i z78aVz6$JVGF_}$KbC~&~aUu;h8Qp-k30t z<|6Xz)XeUYHRWoEB@bl7vpwC?^ZEl0T+E3tJCCO3y-G_9azQdpp9|Im8Tl;ls#X|N zepOG~&YhM`mDfi7GLnz8E1xn^*#a`*dQh$+$Zb#BT8fNc4YQf+Cm0TxsDjabPG<59 zr7z@(}Pdlvj1GV zPd%_hs{63&x*vFy75(W@l4XnmO3d;Nr96!O{j`z{vyht651NIDiGop-<%;`1UTBSg zXren)s>1;w7`pzSvPRW z@~NyB_T_z&)nzy2!nru0JXQs>*_y7pBi~DzPh@7en$Epp*eS6qzG2VL_)a~Tz}(1& zq&ihQZhZ^P#HLE83CqM{j5;>|w?=VXr4YiL)El7=9qT|M12X=CvSM{#AWf+i3*VmP z)G6Wp@ae5SD5&^uVUkPItWKp>-Tp22Q1zd?D#sfx?5(u1K?tjR(2e)sBa}k8I9r-l zEJj3~)XtpMQcu(;6RRO3Qb!xB!~@L;VuX)FELm-Hc?$Kp6B@=#QfFvZp!AvkS@JE! zRvT&=VrqS{x}F6-3xPsImpp|T6t+9$;iDPOt(saelX+QJqR9ERT5qk&ZX4A-u=5oU zHl3KsX$r3%J9m5`j7Ly!;usCx*Y`sfoZ6 zbFLxr#ox(ySrwj@F}qk4Lgpk|9JrBC+BeKt$?{TM+cy?7VrMMp+&eA#9(Odu6=e0cX*OPAdN^Nz(1RM!(N;iD^hs+Z$0UOyL2C2CkW*Jbm_I`<^8Jlo zVzVCWGYu_is2V~3_oPTdLbPa^_6!&H4;00bk2U79djb>Bjeag z^!466L&lSo4IZ}ckM9@OAi(nb!IHHDWp$l{8bG0k&W*5hp|Oc>Zuw?U|PgWA~KXZBPh~h!Awx^?WI8FM~J~yI9a1dE*CNC zkRZ;U5hz8cEOq{fKcK5xuSYH-{;UE^%V#n+*dqMQSolR~Jf`3cb3+A#BsM9QAx)a* zSFIr8UYk!9wyJ7!Bc^uDtV}T|l6QFsm6uEOlz^)E%g+o|c7wXZ#l&i)Mn6+JstQ0z z@{T1fFR2v#7E~Z4`TO0q*vq{9CSy>|bbt9zY8@WcsH9bXBSS~{ES)r#;6VjnPtF8B zNA7)HEt%8)h%eDm3!(^0^P^;%- zY&2ERe41lrYuW=u-3}5i6@4nBPUDI3*{Lk-yy0(`SRt`(qD!fCsF7nfr=_IjKhmvY z-bagdy6(Q1M)Bp^1~aMT#FZTI{zZvYrkZj43W7^^$HWz_$n`&!C364xKA4QAa|mLV z+slm&h+;oKkx!u(#V(e!(fMYtGD>9Fu;Dopaw6g+!6I9jbIw_??DcTn5OeB@AbWq) zf2i*git98fI!y;q-RzN94H-o=))sVOMGfiiFL>B;KGU>sp&TKLCqRM8fC`%LwxBHYW4n$D6X$;4OvvlxbZB}Nt_{7!I=z9~265ZWw(KXHw? z#icvuCh)G}>#Ceo% z;Sjl!$^cVHQXX{~j&Mjl1P-{{{z}kWOJR++FdUvXy0Y}ZCAPB1gscP zjU%X?TJM`d;(moy8OSfhgPZI>P+OSvfIyYmxlnO4pF#^dfGc@M>h0kblvWf|+Gy9% zOvH*ux4QJTf_&UH*P%KO|1lT2Cpo@NA_;htYj=U+_inAB}M{)LdP%b$Lv(PUL(DCwk9Fn~%*yu~1=z@+xt2Nl_ zda{I-)}cR6{Br7*g|h7>$)jubUJ~#!bph#oRSb(0Vk0Vz=HdKyk_fy$fyox1bSqDK zlP7xaAfH`7UP9e7Ura&OuZw{iT25fyr_ruOF{(s$v1$JYcgzj#V9YY)2i>?*WIUFn zdbPy%>03>@^UW02J*w*b^Wc0vKs2FP!4!mXIgg^l2e;`8mTLxnXb`Dd0nUg%e)Y#b z38ZC=d0=%ccz=A1SbGMCwA9afHd_K{v+~Tv>U*?hdS|3^x|eX{PN8}2pN{+*=+ZKy z9hHh?FXPLpsQ^LetCLuUvkX-{Jm)dlNqq})&4Nsx7>7GOqsag+!GfWACF&GQ;FI1z ztzI8BhvG(YH4M2FV5{f1P9+wg^X^T~IRffCiR#wtXtsc?g7sj%jI{QsY%}eTO>L$f<2$f zID9KH6_S*gG*-&7na&rBw_5-yOHqO+5fNr1w^Q~83)3*O4{(wcYD(3AcceuJeNN@D zY+0T++*cFVl96DAw}g>$t2A+GnT;nmn93WOFT9mGbx|_xz@ndbG?y-g+iJGm`k9Pw zVPWz6&q*%8cr*?@`FJ*8*gkKe7z%~FkuqnwH^_|c$}Ek^a*Rn1OC?52s|azGaRoF} z2vdf+3Tua7T=!v?b}s6SAdh+LSC8yu8^44{ByTz@hSBm?S(pFg1^-->;i_jQ>NaJb=Mu&ykRI1?2@8$jeO#@Kj)4Ba3tBLq}avWEGl)aiaJ`c|5 zm6&`1DnNUhlGRnnaGn-+piE}W^ZG!Au4Yeuc>tS}R#=7GrgEtPEL-5|TtA@Lq3asf zsI3xOH3%?^*4(@=7%evbVm`}Zp82RaWv%^U`!@xKKtn_0Oem@Iv|uXYR&LCw-BS0s z0mIOlM;9U2vZ(SBqNkB2=WB!SmJr+Qj1StC6T;Vh zOxeRDOWgCDaPfuy+@1>IyBsN=*t{C^$3PMz65(`gic{V*jfmxtS1-wQTJY=h-jiP|Kd? zem|8`3sU z*$R+b>Ksd~eYVj!r>#}>iW0hkg8yKXNf7~Bi% z#}j!rUL6bln94lA@C81cqtdwX;sKEozM{AZl4a!9y8igbh!x+W1-Z<3bRIQ&<~Tjh z@SZcI*C5}uIZ9Zn`?3wJg}Ab<&q`-bi~UUp+0F|y*6!V6{3KI9!geyCa7qOqzyPdH zVMIn}EJ$F%G9~diXuz>Q3{GZ#toD40XC*EbK4-Ad`aYUGc*;Y*iT{|)vDXcP5{ z7qJPg6S;Fz(ZcuU4DjcdbTiDmPWM9kx&>cDy!Jh`?XgjZnX)z3;&xb509)q{GrB>@ z>J@rFKRu~=i*=C&8&4AP^Y^5P>=|$Zhmh!BLNWF=YErnGz<^<7d|W3eS&UBjOz!z1rZ; z;ic=*?6b@h`s6R5{W$mJ56)nML#%(V!SDX(jKi7P6V}_a#lT=)QY|Hxdw@T!dw2Lh z9+XO;QT8i_MG{*sbu#+$x#=-^xr$g?8t_lg>_3UIlrXuuxr0JOagdWj_aGaofKzyN z5gFxvBsa=B*?y)wTsqIrW<@XbJuK|aWd9E$^7$K3$-sYvNd5^U{yPEsWn2GH%)i*g zu<)6R>Hh^^{QDO~UmL$pynn-D|Hld4NB@EoLpy48K|Kn(C z?%)d)n$P|AeDp8i^NZKsg(b$jjlp6T3q^3Vl?GikOjszOLt4qjC=K=TT3=6H`066G zl1uPkj&g|}ID9`kKSWv?{tfl4iul%Jxcu|>e(?VqIwn7`PQd7Ii$Uoxll^NXUuCg! zNR-snmZfB0arnPKw~6(usIb~F8+TIq%K_Ast-=4oO8;R|dpo4tr>E`~sQbmgt=bC` z(fg%lfj^tklxyh#uK1dd#z6INL;NzK0JpH8o%=dgpS#1~!|WA~`nK{Hy_~C_{ohaj z?`{_MlSaIA{en2;$S3Jm_C(+ho@8Y&Rze1Lxg!o|GF!5m0Hxu1KWy^ zbW7%+=8l?}Skkonv+9>k>|T|ya!3+!4JY%7ghMd#!-ZTgSCLw5w=5NL@mK9Zzm!wM zKHqENNISUlTFVe)7 z5LpFQ{sV+q2(A=RQ{cmWhl;Xe8 zRLPf@w+v9*L&AZOm3IA~OJa-G2!cP=JVDoCHZB@w_)yaL@VK1KRiy8ZzKpEz6CWR6 zpv*j@g?ckCRtI}p1iSX1ylR)X3-M&`UtN{9I&v5umZ3zgA?BZVvpmHrV>(mPWk#6}<`kDt4ax*viGtdursjny! z#W0|s@$}5LO0Dqa#ZsqwA*Yj%{|X?o5_8H<3>&YTn@^WY&mCOF8!(5Ce@oRGVD2_l zA|un6mLo%K{{HeA7bRBGSTYt1AhLXdvQP~oG~5|nv4r7}NzB;u;=u_BJrA<-k>`JhHLk~&iS|IqwUL;Y zslW4FLK1QLCBW1ME;=m`OK@N=EZtKZ-CEBHyj(V7abHnmXO1gBqJ3vc5VY(aRKN*6 zT=BP8bi@JLLw^i?Xn`X!@(i46MWC`_HS2&Nqh^3QNdN<9?33Bp5i}Q1Wui)V?#6>e}SU^=FY1)un!Vl9$1zk@l)*H?)MKul$n~N)xo^4DblZP za>iYTU1+}<>CTYzF2}8CzUrgtV(se;=Jn4no9HPpM8uO!2c8Kp4_k8(iW5lQBS*Vs zfxY-K-!5@M+f)d!*%;#?t-@;gFYg8On!mvMEx4mf-CE;UQ_$z0+>w=t0~hi>gH}N3 zP1ck|1h$N#^V-;i$`9wAvBle>8)1q64uqny|NjGo7BXOo^7l}np&~nA-@)%a(NU8M z4-a+5f*mUy4ts5Grv?ocU9~FKK?p7$zoVN8AwO)R6{RPAL7}Ottp%5XEmm^+s)&f} zC%I(>t-M_YwVYJgPtP%KOETft(;Xj7aRQUB4l->@jd0r%L!DE>Nwv1sh_K=28bmA8}!bc#J}omGEX+iJEsdr}yg zu{HVMALU;h^;cO3EE%4zLAYbIkkkv4|JrPy3+vA`Z3y)ug2E07sn4iN(pKbw0061Z zfO=t8Cn!mc$hZuFsLs81RyRz=fOp*BH2}-p%;{RCIZq-2P*6a`Ok_~;_BQHhl@cSUSDjSYhTS+#Buk4y5y zVztJ-y#ILac-!hylZlIR%A^KC^Ywt>C1jGyEPZTL=RG2NXvfb}PA)dxJg8q4yvdyyVX>UQ*JT^8e-~>r?udh+h+B=5SwVB>iCGG#Yx^FFXEw<{|6fhaIfG!!YGfHS~vK; z51SvY#lf}Mh1zn@^!9qdk$|feT#OWDQOS7x)cu<>y4nPv*55+~$s0}H`&~dx zJ=P2Id8w`tj3)(;s{-wHn98!7D$O;Zq8Q|Z$p%TG6UF%#EUmZtQETC-6+j8nYWXC{ zCpAfYQ7OX{@DX9LRan|IArbWqj!F`7%u(4BJvQz(=T&6wYyDkH6IOjCoulMuZDU;f zOMoH1y@{c0xj(Qe71uFIgPdtxYH4Ar9&RVbRo}Y9AgiVE_?;@xBYQ@u4AkeXNe3u7 zK1@MJ^l3&YX`@Xa&te(JTk#eVVT}4!^={|CYFXTSzmz_R1EI8He+`YLVP?ceb2}-< zq0{PEQ3(U+boGxO)57u{ZK@?6(66G z(sDA4R+BNAnD%&2S4vI&mC`2uN=N^Y^YMyM*wOZ{5x!%-pF>oU0whjUa95hf)z0_ThU zXFI(J-RFBEM-YIISodiZ+>l-)BH=1Bxl$C@xYoXz$$tbXA02VHUP3aZOo{T0DR+Ky zZD1}LI+aoEE4{~g?!!v`T2R0vh@b*S5eTU%K`5-PQ1CbgmU1K4KXT@`HWrCbHF9N; zAJir%Y$-$i!#!$OKtVh|5&iSpO$oC^`1H{a>GxhJ4+p}j@XF-RFsvf|uYQ-pQGzPU zPH+r8JeW&MJtQpF)(tPA#uV@{QRB0FG1#IFVyKeHHnEN?_7L~zJwd%~5OoocE%Q2q zDkB38E2!r<$CyYBXco+2G0gJ{0?zJT2$J8EbPJN_iO@*xK> zA)VLB=@+QrX~C_;aRiZB3!jA(ciMD;&G&kH#ya6W8ZQ`<&QP=0{3McHVu9Z5#3cXM93u>p0s0WaJpc28&1A< z;Q3}IolfIn7K)mLS-22GiRSs0Y`K$V-8mx1Y@i$8oy(DiWp?mPV) zg<3460g3`25LbhdmKk8yV&8z zAd_ubHgBI|i0Fa!lQx}gmS6-8X8fS=9j!8&O!E)N>JSRVxSBH7>p*c0oX&aH?)7{w zS&WlRV0?8qX^_IF(Io2NWgoKA?8M}&^ooJ)F?v=4U2k;d*`S4H=%Z5rn8%Y|T(A|E zZmlTfn(L==@!I0DPTZ?5aVO?VsW0j@>VxncoaJiK4{Jz=uo55Lu%^Bz#&X_h0;g}K zZs~f`QQbbh^9C|?j7cSvg1!zVb+!>**SMZ2I|kIl(R>2x5>$(4Dv0uU%*|CO)yZR| z!ZF0rf0128he!Lj`2FUc9iwT_O(t$UALsPi6W&~NX^gBMxbV*<<2+JJl5(Q(V~$s_ zu7!i=L7+o_-J};<&9U?)NHz^Ay^(wS$k7pa6mt}}>@01to7Q^vijQCz7{hP2ma7_= z7($aorsHzEJWx5B5f3V@^S*YdMKk^#oSJyYMq6fgzaK*N>hxDU|A@PP+s_)t8OGA9LoUb zS~BsGlXtaI8Q&MPD5CWF|r4jT1$%w|`K?H`UZwY|=hIn`*%}<0IPY zVQOFi6#0F?oVkB|2Y8{E&D|JQ<*fqpP5S5!MyKs*S)>^I27T4ajMjARBrK}C zP>M%Ycd1D>kTkjQBeuGzD|Ckcpp3|8<2R{tEJEoajkQwc^^|Q92w*QY=urP1JCglR z?1=bE1`g12p8PIbz_UFGEtk+bo>JvFw~?xnzleT=@2k|cNcFq6k+Y`%j+Q+9S60xP z*_lAE|X=PL7>{qwXRc03od>|@kxluO8k zH3XCk4nN?#Sks^~RxhUGB|kw8+)pv1?!C42;oC@22>}{?i&nU?a3S-Z9{ORUH?5g> zEe_;v&tkXWe?Sc<(-hsO-x?Y5OS4zueDR=rn_2+W0lo1Q>rzq+Rc3k~3qn2Ir!Wb| zU^L2tvd`RST9ju+0a7k?0Egxd*!+-_#Zs3UyG z`w{)mV9G2X;;cq{ORP{!u2MaiCq>%)@q=dlyM`Er(LP1%5u7u)wO={^mjJc`;~OQ9 zm^)#!9#{%xF>%mpMBoWIlxo6Z?_jdps|vunGhWLrrjHUy?BwKCP4Vk1iQw*zg45 z{RXloR<{SxMAnF{q*y<&?+In965%h*5g}D#`{v;dYlXnfr_anQi|Q-d5-AnHlJZZO~;R!>uzdgO>0QI!dI2_{PIKWpCW zCTCz%4|cf}JkdXe&8>nPm*;x$y9aF|b+urK2yZod6=JHYWO7$)ezP* zSg6C+137;LPYsu3SDPPCEx^9O6A64nu8=8dp|hQSeWxpk&YROvmG)|9&+wY&f);J| zHW8|(QB>q~QJIJ`(cvQg?JdlZ!|(w_+a?g{{?Pu;~sbM z(>Oxb)sH&aWtH!hyLPp${*RE>=V}7B0bQpg%?a01kzHZU@_vs39RayQIpS*feZIj7 zDjIz$GEnXHRV79F0Zd%bX`dIH%kRwarAa;;gMNP`HlX5^bdO62tv5%Q z%wn30t9=dS_7NnZ1t1yFi0>bzb=-=+IFioWpv=8jUX2SLmG`W?8L{V|^XCrRU_6t! zdvLHw4z+ftuhVQ0ajAq#xVh~&;Yh%Ro`6(S`f>w(H`2B*BE|S1g;cHKpH<{2DvMro z$b)3(Wi`36zM>KlLi=M2<>87$tTbx6av`lK>S}N8nmyekG|PeDo81aUPz}>pherc= zmoIdPIu9@MlE$^(%MkF)vI#BN$cb@W3A?O1O09yCi!RI1D#l*n=};f5_Rmz6 zFqQ<|;G$d&Yipjdm?nk?PNS4?da%^Mz854M-r-gYOvTTRf$n`(;Q$iwb zgE5o;QtwV+6TTSw^-xePxC^F5zvuzah3{?8JdUjHHxX$#l{?HGkLaG)vB)bC$+;b9-a;E0c9q8?LE* zQE4sGy{35V5=l+N>qVm*>kpg$=UfW~u7ge$h4--ew2UwA%jL%#pOy_kZk z$N|_MkBeu6)vCVvi8B%xyS-vw{#|rr!bZ+5&DLqXNEg#9o5rE@ha%OlC;_-Q2hO{! zUTjr&%l;JwwSuU$fwf~hwzXDz48iEFW5>eWJ~csSTs!doj7zqf^ygD7VPO3@$5ma2 zV@htWT{FY|{r&A1uw(dix#nu(dAlq4C5fRwmO$oO%#4$s5_)zzq=;E~O=)36hX3Hf z)jt;0#YYj27F-_nGGt8!GQObXo2JG@b@wC6(Q()XdHP)h`};m+V{1_Db^SF{v(2mg z0%^1EMWgxbIcecewQaR&D~?%V&nMkuyu)Tr>-_TdK&GeML0u^Z&Sfy`tj5<=FdA2E zvQ(2tHAo7jd(S5^T`}ik=~`*bkcqnE4LDd~r*WmSBCF!41Hl_(9xF*_N#e$NjaeS{ zS9Fo3Z=_s*@SI&Ntz8rOHTtz&ukl8USA#vsG+rDle*Cji@Aos&dJ1%7p1?F=?WDLu zbQ;H#k;n^62sX;nZBW>nNo^}(%@%Q!^#5`8j)9eBP26viPKO=awrzB5+qToOJGO17 zV|Q%Zwr%r0GtbOCxbOXN@5h6E_C9OXQvH8bwb+3REz+N!N!5CV%{Wqj8_s(iJyF)p z@D0@JIGV|HqN~4Ocm{%1+Z*3M;XN^}d&edH>D_tL>v4G6iu2&$fRL1Qps2~ApfZ7| zc%KLfUUE#$KjiWYsh$+S8N8EeXzEgo`12V#9UU93Z)L(HtdGx&f25XbHqP!qWWKI; z{b1xrr&#V8EiYdx2NYjnCwr&ORebNB<^J@YmR5MQ-A(h2#zQh8`c4Yh?*p=6rx)*e z)L7XT!7jf$=ng>vS3*RCxayCjIx+FdLLaeNc&1(yw$}0fs>%h!gq=wTt@g0=wgIPN zIf@EF@a;gy` z+y+giqoG)$6jo~umoOXI)2(l#H#p$#-GD0MLmFxx!2XZaUZZ90if*PTTE~WEr>>u? zX|FAO3p`a2%jX#mwNsQ`Hd7r)z0klmHlET_)1-oOR4St zi~!mD3hs#;9XMN)^J9OGz%O)g+r`_TWqfkmR@TX&cXvd;Pde?(XYH=qj^S(FTmgHB z5y&6o-;Y45>!WxIK4>~!`ZmP#>mb$8)JgJY&M!C0o3MCz%$;K0+I`;eGv7Ot9CAyPeKtNU+<$o6w3a}$%V_V50Mva16k!_&{Ov)(h z`ebLX!#fQ zQ_4`+Xq``RQ+==NvHvqM{tTUZV=*wzIGWu@DGh~2L1$aKrqvqCToN@0ERx}%^o`b6Bxup(`Fv_ttmOt6P00`Eds>lew#r`v7yCYr9%`Mj~c6W?HA6@v^D z-IChjA&(YYak-Upp2g`1hUv^)~-+$SF$tzILfr3GZ4k zJe_K9xpJN4DXv5G!ak)6oN0zcpJ% zdqdPJ1n~H{AvkTP5QETwiL4!yvC5;rT1f3CtlwFNC^K?YCOV}y7zz|p+|5&Oig zv0Z+m1$IWD860$b^)L&)U2w?7mb@e@*bc*|!u{)kxu{Rfh9rD7=ukI zkRD9`#~ivC{mSY+QY;n>`Uqe&b$oD&>wJ?RzIH>BtuXse5u&DP$0WrM0}^6<=5Nml zBZ5^d-_lf0B|W^1PgU~YPU}aYSP0npx%2))A^JK z4KvPbO z{mkw4VAG#Tpm2R8hYVd}_^Zi}0)Q;x)qwzoZEOhw+F#Rv9))$0e(T^q20QV3;f%ab zFZNX=55DVX%IXF?_}sDBpYA&?;N2dK*JX9%!=gYBR$`v;(d@B>^l?4?ZU_fNYGT8P zzNl9M0#~VSuGhwdQxvO3B)04JSg=>nY0W{`QQx>9+7^7jPEvQ7XygWcExUHWUZ!T; z^U}QX(Ze$*{n{U!Yw54MhJ}Ye5L_UsicJFGAVoi(ZTbIhIeLOFSqLQjoBcfD@I6J| z2O{8W!?@QxJg%++vkN#R{CCgc_vuL-Jq7N^V8|Hnj=hhgLs)u>jie8D$Abv*(p-mM zJ#n>;=aB>iatj>&4e`;_4Hg#FKic<4P&6zKfD+?x4qK2+V!MvC#zeFT0*S%N$iix% zWE=J`d@*9_cC`9#rxZZJH8d8IGDe=uYS$W>J$wG@Lw;HQ=RSSXzYYBF!T${iM27gS z<_J4uNsJ<5`mYJ#uNUYeplbYc z;~Vql4R!}!LapM{AA16hVi3V5lUdfPI|xJ~TPqEg&V}1UjYv<|gYIwdm%(CnmgvmN z!CP*{;J9vkstRDO&gTQURV-IG9nkriIP{ha?dU$MuB%L!gDKn-t+3h4PMPa+=|!iD zf9C>_7=G-QJCU}5{(G7rrB{Ni_ASBUS#{3?$}bioFn_eSf_1zUk;$m%0^M*wr4c_e z99~ML2O{s;+1at876BjM;F&V>iw#1~SK4LR{ot@uT~6tTL6tT$_IldpW#@?O&fvHe zlRU+oJMp+$>@?bq_7Us7Lg=->A5ngLi5;Z(e1f28bG-y!^Sl)c2&VJ(_lHr8t%UXX zykUjvto)Kew$l-eici@Gr;vQa9D;KmzN{=AqPn^%o;DV!HvLBUP<3@W3x^^aS?_GGb(?P# zYa-!Q&d?NOEJ_lGGTeEaEBO_kV=!N^W#L6)uhR$gBpB`cxk;c)a01Wyw67PJ#MT3U zfY<%jYfdrO&)ff4UimxWk0y2V-e z*T+rSpy#3TL_tU1!+ZP)sXjPRL4?(gO?qB;JN#kRAT1X1iL>F(HR~>jNr}McOj-*F z+torG@X7pXe0&!=Jn(!jxgBPbQ2@9Q_4FBCfJO5Qg4e#XQpF5(Kw3JM{YBVw0iX#N zldFWAOmH+BMf2W)bA+c?=mUzAK!EMVZeGw-$O2}`KuC(63C#>Vq)154`S|!N%;L08h=fNhA$qFD2bC=8LA#;@Q`0A;ESi{a&+$NjGG z1KD6?a#b0w1Ma0MyNUfj2Gbp)-*$V#Wn^qc877vCwP?ZbcT8wDu$&I_!YNq9o?O64 zO?eNYms}BEut-sv2F>*%=H*i{Qk)Ywn}0K-8HT}PwcX(Me7pA6YAHa2)$a6;OiG2+ zm!lGiRf+ZYulvqk@QC!0Om}*yJR%Nd1ICBzbM^4s`I(=oT;c!Hw#iRQUx_;Y@ z1(h3O5daoy9@ev^@QND0A>`8(YEB#| za_O_83bo_1Nk=tLSPNO~J_$jL-V&KtnW^xUJxsZJijIm1eLpG+sq9Xbc>k_I%NnP1 z0SeFAZZL^y$7>iA^jdJX&S3r>2y9+&84E+p_3u_8_tu8(cIU8jSQ=Ga@<9#IFz>?e z^$w@JL+#Wv7=ioP^=~&kA!f8{@IP&tH+RmKXP*YAEoQ#8h=Jr;#`%gtXayuCvxiOg zhojlOJ@HZ4@SOOR6Vc?0mj70AL0>N5M2^q2C62g{^2Ege?ot)?p^x9#+bHt*)XPLC z<2(y_474?%U@kM2cuyAGbs;`Fe;4@LH~{CLpHK8WyF|?dk(IEUF%!-JD0_rt`DLG1 zCj=+a;qpt`PZ;Y*;jIy=vnAy4r7_qOGn13GI-QF9AJLQ-y-P4(XLw3)+R%WBZC*=d zP+!fiKTatMIO@OB(Phr7K$s7* zmgt{TswMpQAQDUiEJ9Wn8zvdkM*8YMIBLV;atP@ZG!`5{F*DkUy`@ik^LzOE2f{3r zaE1n&)`YlYwZ-)-meLtRlln3QMeM&uDWl|X%jSxW(VQEJkFhYnmmxQoA#JzR{Ja?x z6k1?(mAMW+op4Z6F{eF-@Md4Va`=H#82C$! zdpkPr%f4%$@S!yyZnNr`0?wcofau z>~?3!rK7h~DVUMP#00*mm!uPgO`39EC!$Jd#RNPI=*x+BsEZomXr#|X%85Z=l;_De zrS(VOYJLQ}l3=aLEWx|8QzPqo%7bOM7ELkMfgyq&2MS1R$H2q0uxR(aJ=aYwJ@Moj z;-1fa#5^n|7Yu?3@$H#|45M5Zh}TnXO!ncCuhK^k^q4LY4rty36SEcd_{=Dl%yAMi zbKtp&&qa&7mE?H4xAdF1tZW2T+WX|4%(jiX~BEA}WVyNsobI&7GH4)g@+$@OWF)z4g`Fn;(BRwGQ zWVeKNnBPVM8P&S*d1x6r8Vm@}Ynt|oC&a4;BeMev(EhD$!u&9 zIHCI;D}YnZVhRD&O%tuf*mXu7^1pv-_{c-v*HcSy+1HXq%&~*33;-7f3D2I}%h7`bTtz+1a*bG-7F+Z3}P(xIH(gICi^wSm6sJFR5Pi9HA|2%mf&%Z`Nb zFQjkgh6=3rvgYsKQ281{FZ%-HdYJI2fL{(GoI|;aSK%_0OsIdgZC>=C?}#Xv1%ru$ zFyIh#PvD!0JOL16apV&il6+R(hR6qEIhv%rzGQ~JeBuJWsLYUVa22z5Kb!{=VwCHJ z&ebLMfhtH2i9-&(nW zfjNLW`;s4v6Z`Y%9MAB20A8Wm9j}a~>!QtU?+^-Fb5E)6%7wu%-ZD2|^Qj6UCMN0x zFAbh`8Uazzoz!SxGIl4VDl7alET=yl=2;_abOnl)^LX>MtAx^%p#*~bkcv4QL&@oI zAx&^3_e7BsXYE`{x8yaV-m+>5$DW>=AI5A0ywZJF~e}LP%cb$CuQF|9D+l28C z&9?N6qyC4DU)GB>3KK*GA7zUR7s5R~a(kG@*wZ?O_w6a=N7uN~n<{19K7;|><|v0X zBeGSB)1_Q~=d#k>V|sMV$~=CTVpx)9VdUCkVpILQCy0no$57pYQHvr;?m8U(0 zk>bI2*3PC|AaoOiMg-H*SD`RejHHAHI;!~OoSH;yPG8f;Dt zp_^Q?3+1~)s7ImF>!PDAUMGW^IB*dvs}-p`=%3V>shqF!`1*J!jltdPZj2X@KpW*q zbxMm`dalggyhV^6tkgs?=1=w>p5WHR9EVxPi@vsxvjN58eZ->guJNPhZzrG&FHqOFV7{Dq&f&(3_dMb0f|h*q0OYv_K0#x znA~^4fnjAp{Y=2^@VdGQ`^{tPKfzQ!*TJFKJvkvD$q%Szhuz>CgUZH0%MsXr9L302 zS33?zL9T^>N}cykq%iD?^wHz5TJ^3j_?AE7|4MM(CftT;&)5(&)y2#88Q7y~($qZq z^m@&_TOB?dEkfnWCflB(yR|#H6;3%i^L?p>X>z*o7I!61G$Lj{34D5BGxaSt^J#Uq za~_mpxmUY*WZ!fRVJ208PgV`&qf?2O^E+Fi#*XB}(AYgd3q4m}jLo;^UynuP=4FD4 zj(!xD&pG0mIbqi=Ts(ol)^wU`WIy?B!B&6=6>J%_Z(OSJc}o=Xm-xE z523kO$wIK468gzfdSKIUvcFn4D;-CF^s0!qI;c5HqCpC_rcbWc7G+kc#j1q?YciN< zk9?|H+4KlGGv@ZHXr}sv@lp@0i)==J0eMQ{!K<`p*>K*Y-!ii>zttMfCV0++;Lark z`LxqVW#{73bKZ%}n4~qwdkzlQub7*ZRKXkTLvm-n@0 z#uKKLLo!B)WhEgkEdE#k9!KE*Lk7_zENm`zVX^iHS^_p-G`+-zJO|BQFto;y=V zVY3zA`X-LH&jvV-WiPLPDF5KI1^s;1=?Lf<2|W7J@&We4!O(ST*A{8D&*w+?x-Wss z>$YGy&zEYByWT;4C|n7Z*#X`xqYQUE%2BB5s|CGU9pXMwo}&QnlQDHIE3>Z9w02kL zN>>_(8ZCa?!Qwbscz8$LCL3QuDD1=s0G(n0326Iq3EF|5Idf)I0f69(&_~F_$kOZ4$ zRsoeiS1TumiV8_X*qY(bmSj4}AJ2$ZqZw}Z^WyRa33IRfoh8XQu}5;fQl4yIa@U$y zJV8M)IX|Zs_1+27s4^o|ArJ3Nm~L&a?-WAeMovW&JkzR7{mE%|{Tez>DV7ybL$jDy zO!nI&D|yOGsT~}-zze;T1O_<*&@zf zsC)5Tu!X*i17jjuL>A$|d@4u_Tj_@C!G%rzN99^b2i_3~W((PIbf7*IG%j%QpjBL z*+P<=Q2o-`s3rK%E;!wHr*kKFeJaZ=({&h&0z=1oQu?@7Yn+ z^`K+R?;aB`b@GIYfv4nhh{hohl-v)_49*@w2JX3P7P$j2_dC+kHCeiE(;Elw1m2n( z=VWLTSvhDX?wy!lM3N(02z*e+l936_F3f57{tyyx6k5&%}LzbX|ZP-t-2b z%WpNkkQc|(jwI>d9T;nr0Ee_#J3E`g^~^Yi_#Q_ja%OxC&7q@fT7=mD6vAaOViF>0 zpv{^IXhxU*5W;7B8300fflk<}fE(B`5p1sQGJnG_JF$+&-@i@@ImnCAEI*C6@mDXw z(0n7}3`3Hw*2P|9Fb0a52tPfcFd)9qNy!SXp`TTfz6!b*BD(T4VFQQsXiZX^Q|Omu z6b9y_2i+{O;lvY(gcs(&_?>WCew|R2?n^_#+RCo{j*THhTSTH-)>4salxvXG_LmNx z_uTb6<{M@_H2kB6MF>G)H|#WStst_9bI4k+UDn08@ekXVS#FZnruy}#-nvZlwWHNa z+1-c`r+zupz@5T#`=t*+h>LA)I(lsuD-2MiC?k+w-DI>f!MKe#62^bELT{Fpp;{~FCE*v7UjVUTm2<7QJIz9&}bu!51ORK_O= zeJ0_v5OM#sRb`Fq=lu`QUvk&R*0h%41>At`1HU>FFP;%7@+}G@9-dL+;mJSS2My4m zivt5mjg9_KOVx zut553X5i^tgHeQrt{w?J3?Ro?pcGRf z>vH$J!wr7%Nl_&vJaLO~aO`qI9(ohP(AgtvXbGsfsJmdSHog~|Bd%6DY0Mx_i;Hw> zuWOClu}u^y7sm(0AG{8++sJB}i&LGA^Auk%&4%Z)B?F4^bQoScOL3H{jGu%OM%+{v z^8M&L!;}s#dQ4k-w~V+%!0zl&uaQ)zGKUMrITFhfcTQ0q_ACl{;bM9N~<&ZsYcT)=)mY zIHjNgFoc@PDGf8Xt^KK4=KhFaJn>FO0{Xsh6DXannT6xb<-PSRS@&A(b2=afq3SMH z@S)N?36oI(vH(_Dj+g80{a*61_2mqm%|?qE#V(Eau2z(J%DjpkJn;hX(frsi#YFQ-?hMfeb)tlSp=%hyc;0&WCI25~i?QT2j? z!?+hQOaqgq9h2Y9PxJHc5txPKyC=$PdnCWWD7dXToN~~h{L=zxrjJpNY~HS!+-pBr zl{IEiIo=Z4)6 zXL_o()6CLPE#?2GgnhG#;mzjt7+uHQVaz2Id@=+Z+h!AY@I_UXZ8wZFs(0-9)_&OR zCrIT?xwB(yD(x<_c2n)hg#4l#jv2QGhJ$vA{3mJ6w|m*OmWw!$Clpt%|JU+Wmjg z!;K#S;Uu8KA}bR)WegRyiuckuEgCK|i;kdx0m7sD?XVB@C9P{HI~4IzulodtJ*%PV zJkV$Fz3V+6Y>O$c3V7XaU%R*1TwaWv#oG1T$mF43(kX-#bmaH7@!8c2l-ZPaC+%As zLdal?8e>yP+!Sh5Bl2|?&u4e$d9I(V+RO7D$50dsp75BFef17nWWdwoS#SiTl^8Zf z!-?t*nYx8_@gi83^|8yFM!Vh(CGkypifd91RfF;_7Tb^D;#}16gKnZzk z{@bZeS$A%CK|j#wii21Sj)ZOi`V=~6igN2)SKD3I-wo|PaIclLf+$H~Awv55{`sP-1JtnYJn3wd z<7a_oD~+xuNOfdL=$xQIaG6DRl7Fjq|B~#xx`?LUaIRKApJb;x08!P z^CQB{c$``3R5h%U-;*p>O9E#l<;ezNbk^rOeX|!`aqqMMANZb?Z`Gy5+|f!Nxy+wl z>+yxf>Of2TY8j!qnFH8*q$)Yf5t!s2$39GUB(giNIRs#2Qw(oiIZMRSPUO)6PqYKM zDEDHDr70C1{PVjOLq%!>CgD{h)o>TZUoufqcEnglHR%s|em?^qrjCvwf2f3|<`47L zDah!tb8dYAvi$apKjp!QQt|rGA%v)f>V_!Wal-7FqwV9cysR9_BK&x<2dub?&AeQ_wkL3Av=9T{Uhp>UScyF$_fp5D3?v;qD{ivy4q zT|i`0a}Lk~tO*2&!8PPISnUa%^~>1^9%a-YmrU$VCSOcs?EGG}fkPreJ1mo2JWx2r zBx7VSg?VS+uJ#}VQcwJc$h;*N(F&x&I@~@x#k7x&+u)htE|7`{c3dW7 zI}qgV>1Mv^v*kdrM=F(fTU7McDD)om89hFnEn;F@AijIUNPkiSG#A7KYP!LilfRsq zU?)PBV%4$ytw|=4k|N^s3`$ma-L=LPQ)VB51D1q8Yp7P~;kL{8dXsjbMoxj^uoSoX zjwzHZlwI`w>k=YDnU%zVlF$kugSc$2A%sR2n`TlZ75}CPBch&}UiE4;?QyTQ%KPPy8iVp@+fQ7$G$Y?SfJQTCw^$ z7+(peOvGLUaR%vNN82A>BCJPON-qWx(4F|_?3Jwl)t!2T{3krHysi~zFkA5~ViZqt z537l%n_<15ubiZjc+uDKr1~?&bbTm5BGA*GZTRV5QCp=YWO!So2<&6+B1@hV>ZATZ zJrWiR#1pbb;nn#-cq=$b`nRh5zUvi$$21w#7%>vC@}l}hWf3<)be#-gSfgN@vLlss z#AyADjIG<+=7FB<$oP)?YX5T&bEWsSa9;^LjFnLA9JsR@g`Kv5ZIAPe+DY}G*^pL z4q`f-*j{T^93pJM(@0&o*qb*w=QWwo%E^+|Kz;1=Q&iw3ta4;`dSl#ym_fTr=R#K|zhCr;sI9e0l8$4f91YKscYd0MzbN+rO zdb0}I{V<=&<TzdIsT9QA1JEH$@PY zsb3NedJ#!IEY-uItrK)62X#>-Bi5pe5MI~q5R`lJ;WQu5ecWsq1MH7=cSuoGboeMuiciAy_CHv`F zVYjGA>4*Mki5Mqz)#U$b2|I+Ns|_i-OUXuW{)dpEQ2u%CrI-f9uah*s$%EPuFI6UO z*oT6E;xd)~&xy{Fh{DussBd^nqHflt`HQ&3=xIoqK}~GD{1MUDjF`rlyq9<&s%geG z5#T!HIkvrZ!0VkKoEpMF^toxMsEHX5Nm(ppJ=><$psfmti^z$ zI~*oZWE^RSEv!@cRGSBO4+BM!A}_?oT}ulaNI_BGMvZ}B0sZK131cvvQ-8Sv!W@C_ z&p>Nf=%Hb+AI=xHL6+b{ZsrtB;AAKnPiQ_|Wxx)saVG@f!9t0oLEM5rlaPtI zKXGx_@%+TU7~zA;Gx6N(81b08+^Y#`tN zs#y8@w1C-T08*_N>nGM;7cA}>e9s?RW=e^0_yXxzygOd+pj44oIJva9O2nRKMPb}c zvb$)<28mQ45>;?-0K2iI*7g-HSY&%a$*aJ(z{*OUA1qgn0wHnd*IV_wT8+`$DjS=8 zSV`1q*Y$Ypi~@%^+T;|k7p*%-m3;gj5HF+OcM-i5n0pp9(PPsKtp_C0XQHsU$^HB( zJw~47_dfZL5cZp9Ir@aje)$d+-2Ubi6PtXeMYkXI%U&PPhh`QQdG}r6Rx-T^9?`x} z48va29-impsjs~{2JKkculX*|E9qR1!R>wSY`l-6mp2V;E}Ad9W2sDb_V(thtSed= z29oC6fCRc5sQ(8YVT+za%|QtJhZN$e*e$k@3wZQG;RwTT=zOJ#P{X`;SVATD+K@R^LI=(9vM zbR{LB=9`MTaV+;S+K-q9ck)3h3_IN~GuW)LV`{TY;}IYsFVyrMk}-*H7vG^B?rf91 zQdJrI*fRrKkX#IksXghvU!EO-mTSM6g^xoDvA$mW-+1QVUQ2*D`VA3eV%P6RC_o0! z|EU2BzSAzHzK@!8S3JCjV44ve@f*iut({mxKA~~(TA!Jey;evAmI|TWlA3wwa?4e# zupJ)LFcEZmesbp(#drvkpXP$tY2qs zW)HQBIec3-$OCS%nL+nRbp4BZ*yM!O`G0(IVr5JG&sp^kV)lbz3Wtm8UD1#h@R1)@ zq%Zx=Sk(V~>EDRm78q$4rVyLmA>2VxHm?_^fbe5+cEGjE>iX4oF9JNgFCewzQdWrJ z|D|1kkkEGkR3395mum^DEJU#L#Tulot!-)nxjePbgbE9*k#4{QK5`0v~OgE0cg zV~{+Xhf0~U#76Nm6F@M%49LHMzLEd`Kp&R%I41;l^sV2LIH#FY6aducKf{D}+OanR z{^s!?Y@wbnydJPT8)x3V5U_}BsKCs{?h^LFMq~!NxeG+w{eouP)LOAsw@OL);?tBjA#bJx8X~jJyn8}Fb($JdF2qnB9j6s+3Dh% zn(}pYc&p*CTNx7=E^9~uqPQ@D!DTRBhH;9rS_`Td{lTL3=oD}QC&$0|I^n!=D-|AC zIKmmc)QKq59(pG~XfH!4S7L)<6NOu^GDp2aGIpm4v@N|zZZ`Qq?t8;?E*`CYu&QlE zA=hw2s>^6I?-%8;L~%G{dH&;UOb-fiH%a$N03^fQ{SVp)qbUJ<;CxJ3V|OP7s**7X z#rF=qq-P#A1+mg-jip3+Ya6ODbMta;>tiYESgHS6N=|Gc6)&{a70ty^ys5h-bvpmK zSf*0(-Qgx2oyCHgR?AF8Qj!YtJcz(zdbepxE&5bR7-3;;O`<24YKF0s>oNnjq7f4E zy0cf)))e3y79`mjoDf3o4-1j(d8$&Zrq1MLSZ43^qR^U-h(`uoXuyLfSYl#{pI6lu zR;ujoC+Fx$G@;Fq{X;C$(Zay%StG!5A=lW0cm)qg1Gxf5(A9zh9zK}3%17TxfZdBw z&cTB0Cu!qg0d>p1)UxKtSzobvhz#{Pd|Ss8`a+=VmdRu=JksJfwqjU$u$;j^{XU2i zhH_4BTyqlx%G@zE$kP;<1&P6Naz!4uRTZ9*mN`u`|K|UaCtfT|B8k2-@csvs+Z995 z)tcf|Or<@))MUv;*gg(T+7j=SUF^jCCe1ffGZ}ti<0rrcU}Fa&Fbp4vdZ^9O)Ty{C z@*o9X#XP;shl&7)$Fk>XjW{e;E5K&q>1p@9>4!KSc8m8rCJhr(PmW3iVFe*LxT(LL z*d^H;o$kW+DBUOmGV&568&22)#C8lOS6O;Bl_L}5qps-vgb}_A#>SE;rZCUWogo0y z9fB#emw~y3@=9y+3fK)ZSx9cDg$&-Q9kuuJA!Rka=-J;T3CZ!`brmE)mXDmeI|wY` zDA@RU8^qw+evIBI1VmBxfd!*<)yHwYl+_G!!9&)1GJc?!5I)3tC58BaB7X#?#yPw+f!0ekXqtv!Vks6F)PHay%cU(z zYu3!DW*=5RVb5i;ha?6u2FYhWWKK2g+ZpJRg6vo8*N{)mo%WW`%LZ_~%#`8B9C3m5 zqM8WIl{Q@9FVHe4NV*N!kjLqa2?c3L!-Aky_AfL*7qVJ&lItu7RXW~!KoCcDZSNiy zh(NJo8F;O}IBu`t(8mN_2&E$YPSku9=N1-FETVFReHb16Jr{!ercsR#x@p$Yzg$;* z9i2a4fbk<1RA`YHI2OJMf(9T_WQU{CZ9QH4D6F~9eX5CSh(xPZgtw_26HezT<;H)rd0%TAzs3#E8Vj+E2(@=g*mz z%K2EXYRR(>pml%qw}>idJrer%S?kUZ8{pAw`0xZW2RCl*7uKy%ZlB=>sNR~XAD9N~ zi-Ve4WBuFx1Y3D~-E>)z`?W-$G8 z9@c{fMulG%5D%M;U`nH=4yP4$z6Ms>6P6g&h~oFJOYWmH_i|NwDqd2Pk1YMNjGmkx zLRL#fQI6uFNIDHTg$$8bcGZ*`FuzeChc*{xQinDN75O9*x;PPPv8l*qxrGdAfK5_- z*sZHaS&WcHogint#1b1#Suiq?umkI0^q26e1hyH`SHZW3D zfzHzf_x@@?rIWf5wJ>CqD2>X^``bAa`#s10zq!MR1n&~hNNn)8t93SZdCl;&GznxY zjYy@LV%GpC^iZc`fWP$D!Rr zl?7}XslO;;z)MTzJJNfSo(+#-dq-FBgUGBPc(75!=sL*#C$$yLQq{je`rio<6xxYF zgrud>8hpH|n_0c#PBTP1Tlk21oJoqiV!X!`LlUU=#gk4~y7D3UXtpnyY}gM*VLfa!{*G*d|4zT)X;cP3(mhPH?0^Q%5A`K-~+%U14B%-V}wf4z+QKv1p1Q1Z%HVbyzA7i-En27BUqBo|DMvcIgjqGBw7 zj0cT0+~dZT#kp8o#Gr(XRV>ZLB+HVLuHbN=U`cT7Sml68UX^LWzy~9eh-#8(#IY-a zi0Rz0N(Uc+8@dy?OvL@OIji>X!k3@;oiE&u%~D~&l{A7X?}WpGHbcoc^i-zia1fb1 z%i8PXgHkUGqWaWrAF@}=R8vjcsPX8B~$S>ts_~zVs$NWYXmDAyl*}AJj z)b`|PrFjO7R7X7W6TH9q|BX!4E1R~9H3TJHwxCX}C)6n>;p%aH3xjVrGc=Uv;KkaF zmW{S5T!Pl)u^vl1*_m`|;v;s;VStSuc@}~!Wc!I8 z&K4A-F#f7m0qlGzOvIT8iC{wzN0UeB{#?KE%c`9e&=fxH{7y#t|JrM5FQK%(q|i2cqXL zuG}Hu3y?nxDhsT~FB!&qI>-edyd8 zLYF(TYh_20C>NnhyVBF$UMHMUo1xy{Q_MEAYbKv^L)FQh_{yox-!X3Avm+I zDCjmc$40+lU=mHK{jHTZ^%2@7I2~>$Ijb6?A>x&w;x``ao||RQIqf&{Y{qR;<`+(= zz;>v+>(By7iuvCZW08pPS>M~S4ZO-k!o&)Xva<^B!NW9_{G#vc(N*Ayh_t|OQlASV+r2Nzn>e(oyhutZxONFq+o-^ z_mh(G#8e{Oi zki_PPQf+v??2<3t(O0hwhxJGt4riXyrbUa$fvUzzu(UKz3dweyydR$Sd5M*ocCU1S zRvc&zI||zt;jH-dtg~$}gcbMp_{N4aEIpId9>S^T#mszPxdR4?df}UY;7BZ#4cjQS z=r8Mfls7WP*A_G@fIe)!t*WS?$yPG!`ddsO66YePD=1zE|3DP#L>B-NZZFZzwthT- zH0-E+5(a=3t)(mH46(esn~x|U_KFMxLC$JflTt{l%eqCwB=U(*b%ywn`LKyb(K-ZE z_8ljQ2JDLe_%vIuhoYCrWXr*)K6?69o$_u>1%Ck zzWJ=#!^6}!vCf%bhc72-PZR?XxFP_Zm%*Pm56@Os^X3?uW}Ic{W6feH1XVCtu)`s zhrq1)$1x&?$U+(*(#k^_5Kkc_+96;a>H2FSCn6%c3d!=jfj6w%;H4xQ*7THI@W@Y9 zcQm;kS9DUI9(gQ}76uzK8nMbH1%rWiw&@^|N6U#?}1$*X!w`<>f zFxZ}{1&ysW~1LWq0@XU*l!Ah)0&O=RE~oJvwG z!Hb(%!K%pG7q4TbtQU`QK4+vz-Ihg*u&Yt=+3j@Y!m1#v;3GL4Z7%q#^&e7z6hl~c z)r~qWRdA?QKTTbsCf40l(+^^sSyOPp4+t^e&J28H;nbo3KS$a~0%Db)wO0h}9Ri3Z^b5kcvFlO);~eIgCrns(QO|euYeY zT@anLSWL03%DGNWd>&)Z+b&&wFZ98MNw7C+j67T31x>hBjyB~DV6tk@vwod5gkXzL zANZHA%}Yuzgckk;Cv1nrwqTg`N`h~{xdUvE$>v)oC%)0{rhOOF*V8=zSb-{z<<{Y9 zd)N8`MT3gQe4!#JvJV_q=e%$2lYKGwM%-8_;$R7iFtKrFt0!c0cOU|c=%e>Yv9|sG zMoTOt1lWpDW|qgLC`;bu=#W{tS0sk3J->Dt?L6x?8pDVk6eKq?Jz2J2Cz;7J?RCOb zeQqq>{jwrZTW)`#b&%PM6Qu1aTW9VWQMf)`ZM)tKlMzH6tO3$Z2Otm)9Yo{E*vUp` zQ7wbS#)lRf4C+J#_&ZXaUnEFn91^nm34DpG35>wKL_`ozsi|>=#)XaSsR)vR5E~gt z`bx~3M}o0h=0fD`&R%318u0V~Q1%u;k!)L+a6{wnu7$hPxEAiNjYFf2ySux)J2dXv zxHazX?(Pil-FN5B{r-tRVk)8{t12?GP9E8L_FikReS|T>BF;r9saxx7u0cc^bu9)J ze(LyN9wg&xRD#GCX2~dGoz|{G&mp*-8SGeZzCgGDBJ-l++>*a|kPur%3;v^2j%fRC zCK6K6!rY}XcBd&(!~a$SLiWel9n%yv`~jG+Sp4$g0KYw?=TXB2|1S8I*@avh=5 z=vDBL-((zL*2iE8G|{mDEsx;TLqarl`6S|+vQ8fW&8 z`*%DtoGBf`TKP{IER7!{elG)L5L+waZ?)g2vwcSVcEnxRvvhbEASXGd)grpw(?6e5 zLi;-%-!=L7H^MFu-Wiqa@=pBJ_A znK&&5KwVio$o7_Pqh-^d$`fg%IA%4WF-vU^We}UXU(^q3N_qCg64eCujQ{!nY5_?N zlyt1LTk@IB3A*p$h;o!}u6_jwWXg)sOycF%rlck{qJ8j|K*Oxi+@9O220vNovMr~r z?z3Y7_74uy&%)c=c|2auno@Y(8^3E1@VFom5D=)>8ijs88WSZS=R)}jZ8(e1)Ff0~ zxG?iCK4q_r*s|;bA%(>*!+R z8NW>YqEqEeoKuD@^Yhv9zIjlaEqkTI1p6bgc;BMt-){%^Vwj) z{~w|9&gOp-DottQ@yQcY;vLu)>zVQSCq38C57&bcb;Q4eAc|S+(bv!M#ot=4`QaWo>xTz`R zAJ5?YiiwE{wNqFGA#MD#wo8#k{q-km*T#9<1s`Xc%;4&(c3)rLBAQy%Y@!`-dBm#g zx4*^xmj{O5BW?AI87cyuQu0o(Y>$g{TP=RI-%u1d_Nm$%`{aJ5_2=JTa;GpC;~5v% zZq6J?Wzngg1i>MRmMuX{!7tsdn$mpoF7wW@N`K~Vd>i@1V_HfzU{E-)A`HSmF`2F| z<@8^C+yjxgm@?QIMbVE8imx|x|LHn)(5L}ty zJ;vE)#m3#>x&y{GH*N=3TKMkYvOERQ&27mMRZv#B`C`$_mDmouL&(zU?0>XLP9I3d zO^o=1Jn#;|SFRcOEcEZyj5Z6!H?GYult(nc)t(oR@y1{-EM=@d3mj9S?vaZcI&RC7 zR(0WL7Z&6v)GlFrHNB$ z&GoUYYb!go0tPX|acqT=@i9pxpqYwULU!}E>`lcf6E2|fF0TFh?Jb+2@(0b;a~&ce zG9e-$TszZ0vb@I@_D!&Z`$^%{HWg82O3LM+8j+9VomjSz&xhCf2eCyBH_Wz>!ubd2 zY?|8TDt9nd1ES9O2Tc}C7EH(eq`hL6VEh2_b%W=SCbMwsKEvPJzalV*O|5V<^x%<( zud8P1M}@cg3!b2;1$|ROGp@JC%^!{~q$zLYA?om!I9(kgk z+aQ}?3CMDAqL=u(r4ZdVgOlwqhu+LxR+-TGes4V+Xm<5-RYAt?p$7L{7c;$&iCspk zht1HxTs9T+qG6{b$j+;Pq%K`_;;|!Zt@=;551tztm82O{r`P`f8}|8 zTK}KDW!o^)UN;j%>U9ayvnOky(KibXg}Z0%M9c&p@zm6#A~7kR6c-35xI0Cn=7c}C3kv1E~Sko_TaKR^L^=Ir3Al1lRZW}`GZzWl2Gd{IvI< zf8!S5vnXPDvwv`z-f*!wIb8QI&dtagw#z;$GX-ywQ&z_gA8ofj&*LpFhlgf(o!A55 zmfm~J^*}3qgz$+a>|U1jU0ptO=7(I~X(k$vSYw$t_kytG#U>GJ0^e^nUBdn)Q3*+7 zrB1xizuNJW2lQ39CvxFn)!^^h{I5>-4k{tZz7TFwC-H}Rl@lv2VUjCK_~nkkHh46M_xkN;lC%#1IwoSzeed}Vm4stijS$cm@}UcXnOV~N{-2Znd&n6AAmQOvoN2kawX%;Ri*Bk2b@%ja zs~n$8&8d-x=#5OssaBFl4x{U627 zs8X8rh{t(q=2tL08lZ-Uho6>iX=t?gs;=J?!Tq?$|J7Unyj1~YfzQ6Pb47_qMbSIi zjFF<^tkRi0qhZ5rU0htDiD&KuPmNjAlf~B;Oh`(KYWzqopm;yN&?34Xi_KMwMU(~* zRkND#l1}I6XK&q~wNWbcU?&SR zH!7tt!_08dNHt-0Z76?0V4`?6#XXF3WWWmEN6@Txtr9$06hDeZrfaR4w(JhcpRT!rJ=8G@Np?1%TDLR7FGwehQg4{<*a0%z%&gmev#*a< zhyNJ;sNyLGWF;j9b$xVxNgP2T^q55D)A6q(OmNL>&(qJ$p1a6*K2nm~ zAsxIf4C5RboS*m`;Uu}SiqDmq@l)-?@&V>AhVt6BDK=IV4Qz82wPEIX#(yuKe|M(~ z2vjw=0=+;ZtqwZji-Txo8JRsX*?~&kLMKdgNhw<5h>QPlF4n>>3G4F~<@2l)v(5mp zj0no;I}e+B2&)ot9ZxS;UPaAy54E^7P5eza!ztc>Kwt+#OYDKk2O-&8c3dK|) zVORI8`%8v-r(d*cqr@c?kV6xI=`dMYj>wpp z;e}G2zaOCuBSPm2`vVM|Mx&9$srWj*C>@Q-iXbQFUCE=yk02Fs~apG(}9*t=6>YxuS+VWfy z_YY6gL4Wif2dyPW%{@q>b^%2#YykhXHsOLk(0Qwyr^;WmJ$Na;q1dT?qd3zl&E6c| z{F*ef^hGsIN^m{BG*x=i#{s*>r4guSI>XAGFgVgY#LmNRsk)0xLiYalpiBGg28|4F z-XoOY{>qAT1OX;GTc_^9Y+m6cnNU~=PVUJC(qK^@3etOj8x`MM9X~{j%ntb;NG#K8 z5&#F7M7(2$shR9A4HNNto@wUD*t>k;?4n~J@jo(Z(v0gKe1Yv)syr9$PRj22m4 zS;75ODHXlhKO;qfLTZI!76-@G5*wBjmq93<0k$s6X7l+5!EX!+tr_8I&<_zK(k|B^ zpRM-O+=4ygKVqy=NDm^erS)!b!y=m)mk;`QjMuB!F^|_La`r%#Ad3@|WH14{5hsx@ znHCWAJSL#kJ68}l9!ev>L5}@S2mhjKZcaPtO8Q*SvfkQa5=S9~kez zB~^NT?$kmenLd6oxS*>oU)Uw&K>3tfoWtCI?o?{pjIy-L#*i?1^`CR3vi_{BzR2uo zgQ3(JXX|r3wvH5H4OwnHU&W8$F3h(7K5}152<;pdAC+b&w2)c8b@*agq+Mic$ql|h1K-XhuFw=5djXtw>TqV>4Fh1tt>NAM-7ln)`V^l2PW0@&ni!cUnnv&)1c`5fft;Shqs+Ag1`O8L z?OTyu6IsGWyPn!@ZqPL~6NhVZ*>G_ZxhW|>njKHL2>7G=I@+2h^Y*mTXh!eEWDC1tR#LTkX^IUerbzS;41#-qqUt9 zjMapMp{ymj1s^>t2;AV=h;U51hJfum%~XBTU~?p6dlF^D-rN(asPjNAp;I^A5hw;i zMwEsl?&QK&8b{|fKJ(5)cRf0PPN)T%R|XFrjhV=Os8=fXaxpRAHY@1YkWKY^Xh9`k z|IruyYq2a-hjqeVvqg=b0M~s7>?qzy{(-c!HF>}`79UPW%>*hHejQj?XvRwpOXC9u=U$O*Jp=}@KfI;;}ETg zC&==zy_1H9=y78#X=2wSTn9B9C!1YHQe!`BZZ*6MDRqIVP%_~r+rW{{3EDxbxh72DcXD&+IXn5pE zo=P?LHu`JF{i_>xpekTYLCRn9-id%3R)e?qi8dy8j2@jJSZzjM)0%<$gFZD#PSUmK z&u*P5BufTENZhgXjRyT;xmnKNPuJS~J>b|1%uEzMdBKIHCZ#Cr%$%eZ_6CNA@-4Nn zvKbtqs+AjYwAIWfB0`T{D6TDeuEzcbvX^h~JRTy{GO@}*_T`ZJw~{!ztm~T1Wcmjg zzK0Lvp073@2Y?L?82UCVWl(R9#N-UT@Y$hWl6M^MVF11Sn$3jP?0YEZ zkaSx!lBj7UPck^Q)xHZsjEA?1^Sd~kwd}D0p&7YG!>mywGg`}weUJm{TF;nYUXmP> z?(4M8t&Tm1(1ug54+5;tb9+)uDm*=Xm=G{bCXv336&=?E?BL*ncN4O31slE8@X7dvrsg*@Epl!?vUwu!9Eo_46m3)azq=Ha91}O9u9(yY zPV>#e1u*(fBz@s1m+vV{S-Fui_Q6jcslbN=!xnj$P}r4$EbWox6%JdgNCyeQD93Ns zDASu56>u9jqg*;YOK!+~2P66s3IFot1KqLI6SAIg0n{G@udhQkanoi;?o@z{Hk;{- zP7m#92L<~CoY=Yf=;uFSg*9at+2!(6#DoaGw%d{KBSwqEg!GBl6DpJE3-Sy+6=uuo2alR*z3V9=0*Y)9UK;+4a{oOvgIZ1xs8%0 zWThulhjJ9hxPM1u&fuUC#8dXoOelX>s;$5k`DLmUfIvn%h;<1?+GZX0$*p`4M609F(oWC>?RrFr7 z9U(rxj8ZH!itXo1T((+h%#f*J^fe{}DVRemQ6W{53h{k0JUyY>?Oi&cb!Gc#%Fw|9 z?l2 zdj(NeWwL|KSQ5#PhZG4#X7XB8-XxMvx_#Na?m-lCS>lnBoyirI!%PkMoH>niC?WtQ z83<@aaU?r)JMj$fnotX3?%#3CNPO~utfE{|a29cZ0m9r)Wx+4(6_k=P?h(c?6$eRP zoR$-hT#n|+^0p&A59tA-SH>&hiv<<+P0sEcd_+t1WVm28T#!~uPn-s!7tMa#i`!`6 z;ny2K)mXNuD~shvHqpef<^>Di@!#r`^K;>oo`bazML)Acd3lR>PC5uKsms*_>|-LC za^5)Q#fqysCNz!by%|WQ{7A(XYBwNpfJHqR)3lq~No_bz$ z1(2v-LZ*>tt+on6a@k3&rS*^tx!$vpCat4EksPad-3U*&@%u$5_eTTiBh5hj65)yVfJIQek;o5_< zd>z8>w;#1wVH$^$;t18libW|R&V6u2i7T||^zGB!L?%8quXNK~X|Y`)4rH)+nJ!kR z{wcXR(jqIFNH6b{>M?~;HP_2w;Al^uk{X-4yI}6_?&=yE5-#PY=qxpHsnTfB-as?f zH(5NIP$7He#>!JV8Il*11(Et|>zoo4|IE6<9nId*6r!<>T|EniSV2TUXh{5EI(2N3 zKwM2yQAD$3Ph9*i&avk&2|S8f&n_mD4-W+BT?chuI76gscP#Do1?#YA9bT}2_+wE% z{HZdC)IastK%fAo^m`Zoq?aZQK9dFppt1&k61XoN{fgY1VFwoN#bxVeJav;AmF=|OaXa_knbnxad=IIPtk6Q>Di?#2a+44LhJ(42{1Cz-R4}DG_D~D?%BZ3PI;;vo=FatDJ?@OI3SBe?AE_J2BMW%CLMK2 z`(RIuNQ7)di)M$PCTMDPXX=qm+3Cev=cCrK>YE{L%0k&MWvdN|6mryBQE?UfK_6BK zM}vl%7qLze&kbu^sff{`9V}^tZD&cWwLx>u0R1Unt>s!geJ~vYus9oiU7~S5#z)4h zYX={;{{#nIM35K{te(()0VhAhl6i1zW8@)>)0ltJ3scb>Xr_{-d0&&vPrPFNI2=6@ z`|2%HZhTWfMJt+BmAIX&W1yaFWJa+Ynlvl8QdG%Zl({S@Ta|6l)9r=jRRA|%fkfbM zz&2x6;F!jISjA#U9k@U9YU8$N>VR{rL{2lJo;TH|R5&2!JqgARga}FYtbzVs5$Yo$ z6)plClEKsEmY}AH#Z6!!ghDBmhm=qwndkMR1*`?$$K6E}b%NEzCn3NVmMS#fWTO@< z!zKA)=jjn^AexDj2sX=S`MQ*9>p#!b7>arNiPsXLfW?_4$e4)`>Q0ECP3a zObE5|X*B}VWqFxA=@_kKkUYp}i1+TS!kyy12U$04q#sLQm)mDh>%I=VzD8lktOcuB zy%R@v3Ba9RBX~9A#M_P(fiy4MiXNp#N>EhsakP3Om+35pc@e_*MMCUU8%P@l{9v1e zU*74>3-;L>{Ial5C;=Qjt$L7pSlMn}aVuKDs%>AOsTp;nJ^aX{Iw{);a`R96ahX{I zohj1DJR|&ly`4!Ooh;ykn1q=AnJ>2DftWn6sGpz2;2RubpCqiAEfhs98$ff{Mh{Gf z9ZZ>Hd4Uk}f=TeUHj{Hc`CtC7uNpka9j@7a2fM0hstGN9acD<-sOoNWJ0@77zP2o? zyDO^kZnMoI(O|z0pX#}YcJmIE+`A(C%=)R#@hp|5F%?EuR+h=aaH}4U5aMfycO`Cb zQ{n)!>8x&voGQ@JizBQt+H0W9FnTM`fhYkj5Jd*Ew=2_qep@7TmwWN4m#Mk&JZc|@ zV#fJ?oSX)rH@IYGgBg;7k762niB6Pw>w!ZiLY6x`XgJkarj96sA5cY{N`&Grm;yC8 zt)QS_y3yI8eHwTgNbjeu0HN<`m^Bwui!o^L_epMhG23ItTwGk#+xf8a&Ft_WM+y4{ zZ|fOipOBIe5=#<%EceFJ^m`YqkCb$VOD@UA&NdFh+eBq%2r{W!xf+Epj+rJ!%oW=C zy{FMoZgQ(vR=!Ot>^H_n(&JNy3>4mGqFCi&pLUBKS@eYp*Am_+A1K4F$L^)hN8UhB zIKkJ{%tA~%K4vAKo7>MtTL((GHjS^K4_j)>IG(5S4*lT)p zod~j(AAFb%5T!&?otEf}HfCnmA>L-%P*`m~=sUc`WbRz%aoPV4&< z_#67!v{Ip$MFA!%@Hu98VQSY|W!Ykr|Le14b9j19w{BJu#j@&p&R+9pQDUy{PfF95b@3LV13~geLDTFjiVQSBYfC_soynIb{ZqIcFYv zg(I%cn`+xDB<1`KLWI8~<^n&Fheld?nyx=NQNAN*0|pm}bXN;q`XO?*z3u2;F6FLP z%=5+azhTd)cQL3T9nvu)7RIys6Sbma6wS%!;Vh!QS;WNWSVBrQcP+u3hq*~Ii^o>{ z;58CQGk)3ArQ(3Jttm^YDAr!EI<5b9Z62&AxJbTE;3<~i1i~z!MKq)Yt1UJCz zzd%-J(-c4cH6CjFJiZRJ6y?Onn zq@yLXzW>JYy@6NuyY3h3$OnJyV2u3yCPwVCPzI9<;0yn|2p%%f5_mhJEwZZcZv^QY z{Rv4q6=Hc2i$;Fp-v{+t)l5KZhb(rDA-@$0E6Y3`h8W>>WZRmP(FsK} z6sro&tsqYE6JhImUEy$XQs})lzi_09XaU;F+UVM)PEH8lNYTZt(c!L)C5?^wKTzeX z#~BhAd{R`4Iw7RZe#v4Q>wr&F+M{v&+Z=<4ZYBx}B!>N%)gVL+WB?qb9WK_8BLgvK zT~*LroyZ(cLgjfC7F6qAL%PR0foz*5832(2yZ?=Y*#&)i~1#`s2S74D)U3gD)NJib8ZL7I1?z*QbD;`tJEvgO>72%Q1P(qXryPU~b0NW?!Q$gXc%xw=3NQ zEr6j4g4@eBtNaDb`3eR3WOe`_wc(>lAcb(!vkM@bZO9;0c;{T5FKDinL+g_WH-FaR zZetGxWrn5o1+)BT3f21i)To`G&K}f$LTuY)x(EZ?l8OSE+26ooO<5A*oRuH4^`=GL zOsCaRmX=xI4e#igC?l)Nli-ku-A0Nq9m#R1&}uT_M<1M>2l zQ0g5)&JbTb&6Zxi-FpW|%_$*slpzmXT=j@I{9*v?DvCH! zYl_B5R1G@@!HI?=xw+}h1v9p16UE|*VPV>^x45d%{-cBWpNdGd?`5E6AqI0JJADsk zkDe+VMcH$)x_Ka)?&0rzgI%nJ(iJE|l{@OSLhm6Kv1PzIXI=2bcX*CPgQTjXp- zSr4{-x*5I?FY^%4TPFa)Y0w)zyl|!BSuTo8H01?d&*6(xh67^S87T2vzW)yuy53Wm(EdSoKtB9uNt%59%BFd~lsvrC9HD*(`K+o9NR}o-R zg`w@2*A!35(t)KaTNM)2FGwmyE3`v9^;$U{*TS}hD{&fE*}--?vfP7y_4u&ilHiih zp*eH>|*kgAhY>ye?;`r;#y zIJj&UyBb*zVkpsd;_nOXB77P;yWkBP-4!fkqIj^F3Y%+CfYdO~P+1zyz2`+4#pSZx zR?7952q5_U!gIH=zHBUchvVfZ?>Umed~_Ev9QmI6 zEmi?pZptHQc~Eh#$e1xwoYDT7O2zB9x5L5rwd(8TnBt@ky~JkD|2_LA0YpQDN{#$( zee$_yAT$Gi^@RK^lAhmCA9jb`URY>`8iR({6ee%7#1~fvZt|oDYUU~l3F7h$%G%Ky z(^v|D zKr*jNawV_XU$i)%D^tjyFdy9tAZ;d$9*0`Zt({L;i2wR66bgXbtdcjr9v`-~zvNOG zrJ0&~r}Vv2;C;Q*6PJmJsk(;vN2;nS(#%*wI#FmsdIf2`7&8jz%1sCLkLEo!IzGau zK+Eyn>!%^?pHC_@j+ERVo9dH%Z_uvXlj*& z_!-{>)>!)K*}J)2u>R1YsR619_3G;Cg8m5k={_=pIbF?;ZcD1C4wPQx; z1Y)tC%_gM0E*Vj?!Bolvn&!e}iKB~t`I$nHGL7IZY>Fo$R!Y1U#}Sfb+dy#z`GZ&$ z1@gDqkdda$XAepN)%w{Y8C>NGb>#c|dm|fTx>#URQW8=+Ri3yq=G%4*3)p9w9EeV} zJ-D{llKuk{e)&Hw(tL!RgY^97Y4&^sd>$!;GIi2_Paz*ca*|K?=Y_Di@V&krkzwoebH+Q;|NQ zFv}thPiM=27t|eFLW*o;k;h zgX71`>YHaymtzd>e{gIoP8zPdNJ>S=$`$O>_aos{{?cg*T88{>$doTlF4L!z-}Ur1 zTNaOqY|94*81TQw85(csC5^S^;Y|E5ycvc8`uq3qWrWn1ih{~+WYL@uqV9?Jzy~0+ zpt8%vAF15bQbKm6qn4wD%yg2@W4VBER{jXmDdoBnZv)1I33ct45)N|*+UPq3g~y## zbT=nkzZ@-6iaBzeh8vrnjPoO?#n=$}Pshs8zjWbVn1qQ0xJ8UyJ>G1KVgmR5%)C>^e&4V<{ zD7HOyPyT5^y)W55z}o&;%Y$b=6L2kFVPb*w^PoB#!r=OBa+dR3VwQDSwcdY+P7e%* z7<7I8dc-kMo>TQNCXNu1{S9g)h?@OC&O`xF{WCYFp(~p$PA+Ifqt@6$3&{^ zrVCT(sN5k(de6^=q$4w}4o4>oz#Tq`vYB;k$CB41^yupF3V-b~PW{icn^3$~!h5)# z`9gWziK`9QXj?jRe73ZBS>Dez78Kt`Xz1#~1k8^99k6yKUfUp2Okf;>mp3<=MQ$*q zrqC>1OE)YYtgWv!*=sf};B;6Q5a1YQh z%^N?Y$ym^$;!lN_jom9K5^~dacHBx+-(r2}Lnd+%l}x%Vz4WNbV86|&v9-KXos%Tq zZm!Z_n#DPUSwx4Bg^Zrxzs~ajee&8viYUnQ2N^XG75MP&G5LFVUJOe1jC=!9SXYzO z@f#{`gNF~lQGphU7uy-(-CpXavC>7FQcGMDy5~)qOt2{1HWFp#PH8B8?6z4^&o3#?7<~@ z;SRHv-y_q07Dbpt7)qpK5mRMPc4#YLMg3Po;+CB6tx~>-)9qLe2gN@D+W&k*lLSj4 zqE0B@+f$bO!3k_+i?cszPx)O!t`k9=XE~wXS;|VzAx&&3+v<8iQhYFg2j2|$f9>ye zlF$9#y5R_lF<7lWGKm^f>oiK3f1C(l=t5P6n z(KkIVX(-6arto4fc~>k&k`cmX9VDl)B(oK$|G2kq8ef4ams56|0 zhroGMr6H$F*BYn_>Do^9{Td3^emg=<7o4*0OxW@hjtt!3GnEpPso57*lSh1}Jm*qL z)8$$!ZMI|)6GIB!JCm)yqY8hmSJxs*nA=o6*BS00)shXu; z5)x)XX9X7=UiV}!EuB$Lyl}(6ISxM&)YaFI)koH|YVPpi62H0P$mp|F=z&PljH+dk zG6O~MVB>zNR&teS-m&!!gjpzvkSZ`aTugn&85Af@G~k?^q8u{$DC{Vqsa0^yXGpJO7Tg;|d!e zUky<{EysoUNyT&rS`5TrZ`dyHI^@e?MlN)(n@Y}g6hY3 z%EhCAx*EepEk2WfU`&*&P?tREs~Lot3}a8ms2&#ReiIAq$B^!c)Zg$&JikjF@m_;W zeP!^b6wR!uowfwpgczT(L5MSWA6z#>8sKa`-5kWk#Q4q5vi2Nt#)?t{{FJN742DKV zvUEu21_3gb(9oeAp3h**^=6rY?4eL;v_r%UmWYx44CP6BpTe#}O>!Wh5L@ZOMhXcO zf>tZU4l}TUW*H|`Np)W*WP72TzBX4Ln(Wq8k=YG-uR#|;R`tZGbP;Xc3pxxU)Mqy2 z3k=j5aqc$2$+6A*9o6Wo&*P`?T~U~+2sB{`*O<*wDi3p?Q~&Tu)1cXduHGC|8V*xX z-{$RT#;-*78BV8<0ds$pUJXzYPEVtvy9g^J7yIgE&p5I$SkjP^yZ#_skw0)?FirYoA)r_E%3z?(u#%DoFRcuNY5lfw&l8$~9YrajglHBS4MGmHqQ z8R%v}jbe58OgHE_66Z$^dNSCkuu#~pp>?nC+QqI;wvT6o!D{!A2`7XYsU6O)WXr7h z;B+8;XAR*U?Ui6{C1drF5>}@`O{%jlbk^`Y7wY>`h_KK{O>;&{h`{uZ!yc8CWzov2 zKoLYsPTbNdau`9_U`eH#K8Feez8xgIUo&?j?-!H5*9oF_y-SU5Iu||mLAHfI5D6+N zl-`uErgPb*nbS6n=9TKMx6gHYe09D1tGWofLvOz2&Vd=D$4o!hn}Z%7)k8^9l7v7>^na5XqNAevUtXrWymFvKlaNf- zEkLF^lUNv$&GZGRS37Hg{spDSUQ z@(ka}O965Qs)(+ZS~(jP0wGgphf^sbp>rI?9SnW?4+}HHcBa_-@UzHh_bMLMrgi)_ zuPChIM)KyWX#b?&hrCJ5-z~9X=cc#M44B5-VBf2ivoeHNcP;*l9sECSjhK?Sr zcH|)Kn5;L_ak^E5Zbt+;KP@okQRlBY3EPfS&T%G=-qhrh+j(uSjw9YHLAE0)Lr%&F zo+~jIB<2^?SMNM;-3vIIww=x1Xw#;t&QIbP{rQUqgzy?~^EasU=g}rrdaOKEyTnMB zD$T4bEa0_6B9oVyc%1;%FDMt_?G z7#dK9;iiS2FS;-UK@|fzooh8eFBE3W)iaA4RtM1oa%9_66!XU~mgW%K#shkIx4=Xj z@B*T7yF|QX+H0)cL_UdHJtG}IE@k`0Jyx1fi)PxoYne1;;FU(tW=}bi6xKx2TK|lY z$Ao^MC>JLMzD-Y0b?Mzqg{K_bz)ImdijWLKh%er<7v(T?E}_F@=jtd^BXoJPKx5Tm z65N|{*q$(|GVn%Ft;i8sl3mX1njEf_fM^zbgQ!f>I%L-4NFi$bREfcW4zP;0{W=ff zdw>oT%M{9{-o1ET)H-`fT5-3>lq)F+EkiCHj8G^?{8gu)VpUal|KKVqzwuXfs>)Ho4u8Y5uTU{ z7vyb_iQ${5ZjrK*ZZRN67MKW?twmE6JIYFVIdO_`S;WIH`_-O}#_)W|7yhWh?jXUpLsTgs$7Y^WDB(fK4rtGj18I*!uG;jJ26t;XA(a zm~}CJ8Rvu$8P9b6=Pf1*AW*gaTwUbSEszHDSEMt*a*_?UE!wKTF%dYDhKS{uDGwW%1@_zaXWn1tN|k zzRX=K$?}l&^4LHRw>`aqeQM{ldNaomY$30-dN1{zD2hS0yuC!)#xLms*-=>?(|LQ$ zqJjm#OBZwkJOOqkuN2B<=+V=R)JcCM8%jSY%5ycKguNbE7!N2WJ=CbecgEuf#pFLs zqB)bqM0^8O{!L9y*YaV-MMcvr-n4(P#B(&jsHWS}OMVEGZzCWeP%7jFxblg!i0=oy zihh!$EdlMDW8`oNym{m%_1fw-CS;u6=!i`XjMl$VSYbOuntyj6xAcvk=2dm#uN7b< z<8g-h7iy-hJ&*ZAGL4Aw7<`qwKkJze`)+%DudPgB+Y@H8KV@||Bed(TKh}D#-a+a| zuv4D%Fmiqy_=pLdhE2Da<)qEUEK9`PNb-mdNfwgk4B_lFFZZ>*Q8k#3B19&508ew$ z@S6>&iup-a1P9W=pXxiY48CK&N?{s<73p1KZo$z#(g@n>X^R(4PDYX_o__u3SaF<9 z`KltdxYOmy*Lmjy$f zYa$J&z4KH-k_Bdnht}@CZg4}Tn6K<(%hnFCSuVsS=^1!17`WMmMa zVgrI zSA%&a2)YTrG*9xXOFsDJizVd*>Uo;O_jj2x=Bs^}%UU>+cT z%_0HnIQj8Hyk~{2EBB}UL@E7wp;t}Fm`(7xLq2^&YV`t`4|lQBW7jO8vDcOZ=Y@JF ziwCofO2wC)L$x`iAEwS|3eAjd*@IMGtIx`P6}5Ec_f?SvoHomxkNb944KBJJQV? zMEW?CWMS}klN$Gk0i1`P!`8XMh0m$;}RWaAqP!9=h15k%ZrZYv6 z=RSrJ-BJ+(Hr0f7p6tshRw~*IUY~flsfIrMy0evlaG%sX|_m#!H9%;(y7e5 z`N~gJ^129w=y0H|&Z~ZAABE;BmsC!oy4Z7TjAIPvKx?oCLqU2CqHCVD%-d(FiA9rO zBeIjNZP|@5-@&QlWEkR=CEu)Owp>Nt=PBZ?ys!nxZ88t8s7Z&o5Po*0YiS3S3a9y2 zZHbn&d;jVZiXuihO9L5NYg;qJzi0efXTN73Q9%$jXALF_4K zo5XsOs{S-jom1s+HLV|9IsKqu(iee}QQKBC1c}GagU(%^5?B3;-YSzu5Q6BTy2Ez8 z!^0BGT!^XBGl)juzU3g<`qJIVcRGhZ^RNY0?zNNA@7Bfxyn?S99`dF z1c|q2T9yH#SvmJ6 zz#HzQ+)xOAzMHQ$@5p4RsfpQw>M%z|$)Qw^&q{x4XBrC|^y-~9lMFPCi|%F=S$AZ% zc-F_UuTLsUXq2#O@qU}RG+fPcS~)ossyWa6eryiynIqZ`c4JjlH{s0dtV))ETrAQW zvWn7^E9(`s-LSDZ^pBzo_(LpzR*7h)IYoRo%k&~yvXN#IClbOf;p7)a>$0ziJ6~PI zAc%lqJoQbWz6?qyQbB?|m~}X4kwy|1*q?G9h2ZI)n=S_*ig&GP10m%xSCHkUZws1e zmDsDryb%lep!?Qn=K{QRvYtWjaB~zkd}#wBfTZ_&iHV^ibVuqMDofan0}oVlMX8$1 z9gKEg_w;Bf`^xgi9ZF+*uZc-SbBtF?7hkIB8na!2yfQq&?49#Akry2ekeu8S?eWLoQv^%Wr$@|IUDucR)r;686KRR{Qm@H*E_^EL~Ke zPBR7a5kNNqb&nH`{?juVS-2r4ShUiUVJN<%a(WNj9!;T6>;y?Cl$>VXT1LX8l4+SD zkV5X?M48aEv#|>Nvvvf+YXb>794qzU*s)1|kh(gk{{oiQGwH!{K2R(^<3~V{D)_(X z`o`$WzGdI;sME3S9XlP{wr$(CZM$Q$W81dfv6CI+<$vBi@7#OGcwhDy>)W1dR?Ri5 z>W88NX5G?@*#q7`abiAEcpIG|o!g5&QQvvkoMc722j139o1L+w1g`lqvMp*|?#1bho3hd~~4d z!chhe_H*v|mMj`g1%fi}ZW_Z>!@nS5H-EqbsFw;{6Jws<`6;CV1>!~x4jJbI8W{|v z8Ov=fV&aUT_s&2*)lX93Jo{3CyO-uw^hxF@u4E>v}L9zCHie z0yswlEnlo|5rWukMK7Sr#gd&LFye#-D(n-AJJ}@hPc~C3)?>Qz@5gHHU$5~t5(BcG z-cT_D=IGw`!+z^mpUtk?Bc>ucd^yV|uEEbLyrI$#RpM@BBA0M+d|O5pR72^IQIuZ4 z*EHVvA-@40m4D*&kx3`96nJv-bFTBSZ6V+=wzmwiZ0{lIyQj4MJMJd0rfZL{S9_1^ z4mum#eB_%5&7k_^(;^*J&}j)ISYg~(tg9>8JoK$PX5w|u7DdvD(5Oc;5LaHQdO99| zd*jFh^PKeNA#3Ra&2AOWU{!#!0w_o z8BC@~_^TF#LChs>(03HKgxJ z>Q`X=#AD&NI8f*y?$21dEgmXn4S7HCE6R`Q2cauGJ>ncs1=&2Q5xB>il5?U5#}!og z8IIQV^qe-WK zQmbRO?2YlD^^VzCmt2`$O&I|{9L#+;+qv0}(Rr^q^CGk2d&u%0JwT_3PUyV?&(>;$ z(&l_SxbgcA!^j>}k{M{+N%F~&!GqK81`-;B+n=}7|Kz;>>;CMTeH1HJCFh~#(B}$hp!Fb>|4O6dpLvz~UZ57`@#`H|JI#tw`+jreARczI2p}vlf zFjmvk>3L=h?g{wl@!{Q)bSkk!4RMpl%T9XVX=Sg~fC%ma8vMYB;&{vif%-vZm!Cvx zi+y3vK9K2KNbe~>2(zk3N3Ibnb6GZktAepw-5DS=^=OMvzI%7t{5Gt|O zAwx&8imFP6PWe%CyD*2VMG0p8P~^qNT<#lLJt2$1|H03W{uv%YLfL1zDrrpbHi2YO;F(6#Mla z-80$~d`%!KBWtlRnWPjG8=f+j3;PD;?TVp>fGMv*WHT|CBbLk*4U=ncSt|P-;|WLz zP+$}vyZxXF8}cw?w9FM+(%Slkh6XH_FjC)G1vVV>!Gme5)-t3sB`d2aL`)Pa4VQSD z&TZ^ht9hzOiIf( ziU0xWJBlOlnfRHXMLwNp_Yb^+Wh&Hd^iQ4q#OiOuf3T`(k`zUfatlznM{m&uXT=09 zwwg>9t(e-b)*_Z;@j59B!O|b7vEOxkVvg5JDaTZ-gT%l4tY9~Z?Jo;z2$BZsNZb)G zqv4C`R_wBZOrqfXSO@n-=$#N0_k;_H?x8&7zsAg#Dwg4FoJj=?!|329pm{#EDDDm%5ca#<`bZpXQ*nM2$W+eM7|-3Ct%8!VLNC-eC%^JoW0nT zIi7pgeu7Jj+R6A}!+5}?j8mR{Z$~szZ@_gNitZbc<>@6OZtj1hItV>xy5#K$HDrP= za2;nQF4<3jQ(2_<7^k2HRs=Q(*`qFqoDC%xQlG?@eT;Zv0(X;$@0_!xl0+*WOA}+A z4Q>IXUa%BD3E63PlY5&Lm$2MmwPKN(d_Y88g_SdIRhulhVKO9rhHquNZarI_4O;?B`mK{e9DnMZ-I)iX!e-y~XNZ%z}s&XwO%E7jesl1lu1({YpIh6)h4OA=^t0iJ>k^;mGhP9xj{Z<{;) zt6)MVhykZwc+OL4z6D-iC4uFoNOm#@e0SZRe`;>03y$C`uz#iw+Wr^UerWW0Lwp%X)+nS= zfM1$E(S|2^zdz`YnJ?6JSm&=WhkUNkzF@yMO7)fo%BZy&&L z9;GA{)(h09W+_{+l44ri_EhO~|wo|X7nf~THofw@0KF04(gnL+UbF&kKRrg*6FmEKdpw2~lx}EShtlkS0 zF}UJ3lyz-PW>vWQvZ`Z8xzPEdRKcIwR@*n11Ac+e~ z&YoEt>ze}R4k%S>X#m5~SH^uZ$JEmJma`zvXKo;)r?=xNO`+1L@EO7;rR^kh1~hW7 zvShXf z1d9iN_j;ry2`!M$0Wlj+4X+JXN5D&2O28QqXv_6??qe+i5KjvhNt3R^P*zH zW&3f`Nd};#jTcEm)zZ?IiUp-&h0%6K#HSNa(#aTPE*I*pOQDMv24`QT#~337#aiz@ z>CIRI4!fA_lU}|Mdf{gUP;~1KP?q(QQ`fkrdEJB)0A8Vrwm42tqGk){_@NFvoYH)BG|$`q1M*Ap@YK5N#G;lO)816E$hzg; z633IQLK#6KXW8f*oT#~m_+1|263e<+!I{2k1|~i?l=PcSfL5Dbv_$m5P{R9QtpN&u zGq5NZQsVSWp;XDpC7SStW6AdqKJz;(p?5fe=n1P)WZV}WT)jx}omV{yyha{kxl6~| z(Bll10Dlz%2pozb#}4+D#rbkp(r#!guC^IE6I@Lhhh`(=&}LJ)h8%gM+HGhchgh6P zzQ%9)=2^|luLz6jW#ecXr3KSI7+<%Fc6~NUiFS55mYpoI%{Brym>w4mp||jUvfGf6BtMSSMq*f3+~QUL7E#1 zyRfq|RGyi^++hc%8{-*rY_{w+e)D0Ho)~Q;X(JJxYoHNMO-z*ENR)Dz%fAUqFeDCL zct|j$6E34JAUq4r$4h^RY=V=h$TC(JmhXvBDOBK^rE(}NO`aJRv2Ha?OHCbqU@|`D z*62Lm7smLw#9CM`B_0XM7ZeMl@Z~V$b6lqsr-#@3;a?7|FITnUnSxTQ%clT zh2I}P9&c8BA&cRY-|9*t4HTUZ9sCS3gf%jtf%C;*k(Mc6AH_Nt_j$;|oSREdIVcg| zGP;#!8AI0&I5SU|HRltPZY5oPD;OI0pN@5(u{ zPN$k#z)*Q5#0r5%)Xj@nlK+KhE7Wufel};eP>rkoIEJ0HBbB{N3`2Rsqu0ZIqRi^8 z7m5|_HA9=De^Pq-AMXLFcA1*3u&H;Q_zql9E08lz00pyGj$?rUVbV&2G#OU}$6-y7Mmbd>F zCM~i%n1Ce;JC)=5iT-%;edv;p87S!2=C`YR#F5q%pL14^T)7CA;mHi;+RwWvt!07;XQ?!SnKI7uObdJOAF+CPp^=c2PN^PmoLfY;1iqJCZ*3FlOn?Nq} z{m8bzsN%?+x!&H*cg|p=SoE9XJNuW=?^}Bs5k6(!k%GaJN=Gc=ovYX{P#(+3-2r%W z>9qPwh}01{kZK+_pDQ94>&u8S1nB&cl-EEPu1`rGzOqm%d;S`CL0p+J@D z>%7kuVis?9 z*ZF2n))lDA+dujG;R)@w-GK{?%4|O9Z*o)~cE9Z&S0J1UPV|e4Ch^;8xl`u&=ZA(; zZT$J%fhvojR_Sxniq%YL5O@PvpEhge#(gGFOZeDdssMk-;yXV6*b`>pNd#p%(2TGW z(YFdKOKksU1((^x_?&bFL$ci&?(eA=4s4h{;n_Etg*p8OhAjmf<*S7=9>ddDW4Ro! zF{`myjlU{#bBVDa$hf>#&H>?lC|eEA3Q)qZHZ6dyl8d1Sarfg>&VYN}blny|h(jO~ zBeFlgyv+GAr!M3}7*{d;`le8BHr6PBs$t?mV7&_cP^!==@lZ}K(Y|025z~nBlg@mh zE(X6Ezp?i?1%H1ZPP4J|_+`{#BAo@YDEu^v%0!ejnl{7Spi>nW){Bs zxZ8t*$Ce#}%I9HtPUmXxr56=r#)XaJJckOkYV%bxOKXQrx~^>163-_Rlq2dHBf|FQR;?Hd~ubWid9`jnr&i3Xqk5`cCOJQ!he?3ld{? zuWzcQA?_0{j5SXN-P_H=D}qeQ>Nd_lD*s-UsKQzTo5NH5uc;cc8_Lkr5mnmj6H)6`NEv z9IZ{6+1mG_BEb8}39M*Uz!M4rxK zYh~UHCu3BGO0Kc>)g04B9|Uva%VCy=yyxL3G|ve{{t!O;=d)G_jmz6Yo~xI!Grizf zK26}VqGUwk{{Gu$MVC0H|DKs+_`eDLmiSZMGa?Nsdm4MqjU9%+27eVoGLx>t!R-uy z``afgclRzgj`?Id`FTuejK>4C1UKDt*LgMKa-mrbjBL)ImG5{QCp^)8+eUJ@X>{lG z_M)UKnu1*mG+Z3@FCv8mO%V6|_@QfVp^5wCJCBL|RdfBcb}3ywx3<7G`@XsE zjCc&=x~t6BgI8T0fiKV4W>s^fwHyT%B226+84}*g-ZZw6s)Tm&w~)8*6O#Ak?_rkx z|06gM96_!q+k}0;9>y<`-IpLxf5N#X)^}m5LVMcAFOmCLg4hd!i+61{)A~r1@}rd& z*>p$*VtI+oi{}xCg>mHr)piwyKhbk6ECWYeo0eB0S{J=DjUs{06s1gPl*L(UmPK~N z-3Yags46FxH&R}&N%*$NxjQ(xPzfVhaS22cMHuR%ND3M{4f-*7S|R^5Mj$|#7(zk+ z2XOBnl+FP*h)VKJj4!U#7^TO$VjPEx+n;5%H-=Vph=lEv&o1rkxvbsAm|~-j zci2mA_W-hti>-_GC;PbOE)N%(Qb`IzeW>j)p_gOXV+7?e@q|Eniuk|~z4}?Ux|Brs z&pm`%2WPTzAOcu6%rZ-PK7}FYajB3!Ze7VF6H?hNhrBqU<&A6-?VZGRtdksmH8Bz0 z+Kl)i#y=P$=YK-{)HLmN_}_Gee<3pEdLY&EeAeMCaNoB5O^iL0Y*%7b*pPeCZM%w_ zz{=G^$KDx`B0;8!IB4NgA83Sx9Uj`0U8Jf~1Z+Q&XI-pttuR)?vJ~;16k=H)?644eKC)JT%U_LOmxIC&vVu6|D`7AWU4$CSv7= zKU%B`qS_-tqgRWzq*0j>wXmF##7ohPiq1N>=@7|Oix$i_9K4V5m(ofN)|>SQsmYjt zIYj%Z^?l5d6iEXx>E{^etaB~R?v%ecTF+2)(ErJs|EnPAce_brIS>c;WDJS%P~_?zKbPsKvz$v!yWQ1L`KamAm;+SFCn6cSVA2YR~DRD!N~ z&OP*QN#yB^`Re9g7h|hbh=CmjAlZGn>Hxq`A8%p(eE>U5xE!Tk^7W zUB?$**c;(5VH$PBf57Pf0=d#h@TH@%i6{=;2LfKKyaISU!d0#xvO~x=$!3T!Db;3) zFkNnu+p}3&ER0L-^p`obXn{N~Jn6+L*H0KC3YFPx^%Y-s@KY|8j9{`cW%~vZn*HA$ zZ-Q9hz{C8MQKQz9VtjN(B@(~mYHK%Mh7tACe)G}&-E^KCw$M<+jBs)S3Pf?KTmGyLyU+UH-#c+L?5VYK`+nful1_jRTIf?8&|IC&mzZs| z)ah(y;bEM{DY9$P*&@(8^8^G2%9ksBS;aeG{XfvHr8|CS7|hk)fDT>w5l|$mGydd`G{8T1ZiSyyZ#z_ zeKAxxAycd6h*ROq^v`idMI(JlekzS4+7TFt^9kzhz!5lj`>Sh))L493-58 z2S!;RNA3Vb2$~_oOg(OF$hW=={lm0I(QPn8ES5?SaJe9U(HKMi`-ICEkT3VH|3#!Z zIbN(t{UXv(sf$Bk07AeBiEYcu$`CY(XsCRzwmP{muk)q5>``(oY5&~K{uepJAeq_H z($XARD86IVD4s3%mh>@dx-LrS;bG4>@=AHNpPEW5__I7qmvufU{8zyB8Yjg$1Fl(fyh4Sw&@nTlSopEzk@F`?Hul-2S4Iyt|S z@tN7f6$|k8njEBANs@m-xvi_ao2r{KZM9*gj6qW$V$q*VoV1UF-JMqaJ>KY*tmghRXxN zTd|X1v(0_xEv-w|NChJNGq_My7R`_=c6js;nH`q(&qf{BK!dgf33b_DFD3BrAA&pQ zuXtP(_XGH<%B@p);XPI=C2}?Ra7L(Qdwv2qE5{|Jf3SHMk`+hY3kof0M4^nu_(e(BG~_0%wWb1k5O*N$z}P@=zQ=qM_50Uj11gAA zgxN~1et@-t2n;GZI`jYnXT77zpQOP*P8*H9U@c(sukEBA!axGKw5A`NdJ*`C9Rau9 z?>kS*ARyVDgpi1+#d;}!orn!71DZJs=5v4S?*9=aFH5{u4Jloo-1!54t<{O?(l9?f zY!fq5+)@@@dXbnV-YwBQ_jK^-4f=4c zou5Xy1E^(dGF+TERAycV-f+?afD({V<1%~B`{F{*(!wK6+%ufr@OR=I6nk@UTI#Pz zlvGAyQ!#wM%om<3;f6N0LS_nm+L%_RPm3M!|7+R*>n+%UWkh@<3(JT=k$v<-i~~^o z3bTT@9)#r9PU^%7D3|rVIn%wnnd755AQsv&TQnQ^D{NR!HSYksbQI+L!uj-;!}`-YD-E5b*(1gG2lVu=vkU2y>CX? zrqPu>pM=9969{ELN)`ECnMuNeGtx``x()6yVyelp!~u`ER~6$tKz-&5IHOAd=eR*l zW`^L+iuI4~aggo_>*c8RT7(t%S=OgI_$CmO6M951pGr$+K^U)RSenZa;WHHk?3oha zwWXT71O5LlKJuT%M`Fl+>LHMSsgsHmj4<)Rr_yQhxhu=2#o?Vj;Q!j)VTS?tEy}aF zC*oQzfg1Sn^D^9Ya&&sCLe9P-DMpZC)S}jIDyqU9786e7EUUCxbOOd1Y=bl&GH#$M zMsirnaBWn|C4|_EoXC^p?HV9Ag!C@WKJqt9u!va^k}xs}|OK!r}O6TD!L$${dz5Qm>#5Ln}Q4 zDJ0=mo)I!UKpxCUDnC*p!4U3A~1p6zC=BHzT@M@VSKd9dN|#(}`#%;I3J`lqIk4Mg#ykFnf||+|EUnRL$LD_kI-iWO&-SMV*ZKb=9 zcK1$2h~;SmmVH8;&sYe!X^^MpP4-SoXs(|KkO#mQl#)_ykrc-Q3-K zEl((gNVAZlT%gr8-FcaqF7c1Ow@|b)(n)#Q;p|I@4Hc5RK}z5U^_~^_mMtlkf(Hp} zO5-gRov`c~7*;wxn@?SjSIlodemmf^oGZySjwt$f9BitQ463qwH#@v7E#s)05XUz< z+I^kn-aj)jb?hRd^8!o`69A0*tOmq}B(#K>&*e>{wZNk4V=kKdmo6Ic%RM+#T76IQ(;iEjtRlhdTe91xUcje!|t{NJA+0SF+k@nJZ$>oeM{$I||@8BOo z2h@(aejjaZGX>g%_akufpNKI8uanoW9~e@&I{w9nv{4yAL?52SP~^{Nu)|A2lwyiE zr)V-gW^rh6>5Pb(K(ct}+iz%C91#lQ&iCb~HYAi(i#{CF`tD)awT3)h;)b5lumeWHdFl_{B%9H(Cq$gJ!Ix(sump_etY(qassPcMm6jjTkv_0h1`c*p$%t zSFBjJ-m?^L&UoK`T=8k?--4U_UpryMR67!(ws$dK`HXBB!AE|PkIe-4KYF*0q6OzS zP=YDOcTpU`n9J}n_fonc=Wi|{B|yJ!6CYbL^rwF#1i_gVCC(Dxp8;7Lo4co{0n|(x|`u#F%kB2X@)(*k(Ra9RV$6IZx!d~qj{0C2&tUj4KtjLxf-%fDm?mK`b z9ZAPvCGV5(^a|m+0ouE?m{c-wO&A-_a4|oH3Q41IxoXW4C@>nQaQ{~@tOI&}<}c}O z&Er^ht;40}!CyN!6_A_HDG^2$JF6-=TGShf&O=$-muD4%CN0C#X#!QL3<*r=Axz$R z4(?qmKWv4+8H4tZ?{!_N(uHyGhmBIng;S+$PDE9>t|3@D>KxV+(k)W60ZgNNTNN{Dt2bYJ9yq`| zGStX_0e8*7F{oPu6#J}%*dE&>-9lGm&9=q4A}cIULSf%9K?^m&NsbJcyH754gzzRS zn(Cq5Su!S(Oi|C)c3DjFZ-I*6r7GmU0g~8$ov3LY!~hY&2CAoQqS=OENOs}TsZgYJ>S(Keu zIsu`^<+#@tsP>9sz^3b@rSp54^SNF%AUpk3mNJ^68v?9E2VFTx{MVhw5G@wByqhiO zstQ2EVS{rW@z9uNvhV$Wea5WAzG(s-mQldOz}s)~lg9U`P|_4uwMZ-;~5Vpi}~?#_^y<9%L`1qq9;;&f)tvzDfqU73ZVvaU);Nxkr_#XTvh(hy(E+QAV+%;q+J~lMfZuB#l!BS_&A& zF_e|e3>UsyzD~ejWu0{%lC?|YDSIeJVN;22fOCv$#Z0v~V1ii-*Rm*q7>4-V`dD(5 zif#!@{3%Z3iCY+J2>DBy>7lrHWZB}?(2KgM>7^q9AZ#j!J2F4Ng6;JPpO|DID&WuA zG<`WjVO`RI+|S+ATwgTR8nitN{qI_)Q)VsBx70#Gpm>O!mT`4ox@!WZxYwFfMI5&k z(Y|f0F{t#~JnRM?)Ox#~80jDV!JY&Om%2dvnmqo;VuuaME61_!%uB->XMHuBnhv@W zLXrIXo{X9au60K@KWgxBt;8?a3H8RzhfTnwSOH=KIsC9K zgEyKO*R+TiSB-~#HK!R4Pc&)$(K5Bt^tb57bQid+KWSkk37UlB4Ej1sQ}K_8?Qeqm zwIvMXD+GY#^3C+h65+6{g745Z7>il%lnImJlD#bzEY3#cm1&d>?jM-SjctOaL;xT3 zjocH;pv~B4tx9Tm&VbTwrd&&85yvGG^1{n7MoKo7yJsYKskG_8C5DhC=4?u8+_~sD z2KyfDw`y{jo4m$Qt%VRdWaU#!`zPi+;5BRC2e9J}A5*{&g__4x#YgQ1{XoC z!D_PpTeYG;Ij(Pp1oF2f0TWL45k+VKU)Z7n+9MywG%mb?bv3dc`9a_UcV9Ey{Mc@WVp`Fj`!>5j%K<7`)5^YUF>1 zeLCth6T17urELry9B{Cd@0Q~jQSHRJEh0ZLrm2C z`O1T(7DWl+nRunCO9fdDIp4H)$%C0qN>~Nmc_gKknLL0Krz_%VCspAEA4`~;){nkC zBwVow5!o7O4g`INR2xotpmbEl*L-rMskl*m_LTHqF}{8hj;@0q2@|u7o&{5EK&6fk zP8msFMSV0Z-{K^1ZVo95pBHIx&{x0dm6~6mB2Q$@K{f#gdWR<*^CP7#=bA`7|Ei<1 z&_96JeNheTv)cgBzFi+n^qUQm1r%+LZ7Eo=M@Hy1J<-O1NrADR!I^$j++v?6V5qbC z!XWqp?ZjIre9kcx@$w3mS|+bv5#byM`f)c8BwWGC3Yl69bQiG$dbJf(ZRSq17dTv(NRlD zTCkFkKKU^Gh}b~Z9#RU>dhkLq1fjFp&Y#yARs=?yb_e80o~uwFFP|Iy=6HixAZx@` zjBdA_#K||Lv(iqhVc-UR;#9Gh1Lq7@(~gc$!fXI9LI2wI7lL8f7RNK>F}F}9A2I&3 z=;Uks+#tq!l4G|UoT3u)`oIEHdI){u(@$`k9bwn+b}>WfI*IBuZnvF!9eDLJwfcnP zJYq_y*PBpuYLD|h+JAyqo?jd$-Y8J9i)Dw;o#ARVT_BgU4`+{Vt%&4A${6FCa7?c@B8p4PAG1UjGIAL+v{GvP(og@;o86obi_MC)~cyqx` z=H6ZKBuU|sEYy%w19aQhc2XHL^^BQO4h22>J0`$X4h4gs#wYSqjW)0$DggqlEi&sg zQBwSTL`yAUb1b$#I8dJ}wxcVTP#Y08ju5JrVK*}4)92_WVq`H>mhCa1@c8GtU zP0SZte=wm%l{{&!yRVS%l#rRSZ{e)%Stx6DkAnCs7&Bl-mw}y;Z@VbIIGQHYA*Q8_)Li@W zY|}U|!DKt`7-5jOlTbnajQ}k${GVAmTx3tDJ~`w_6mYmF>W7_1EHZF~b+f^R6MY4C zX=~_L2I3TAdr?_pXg_s6ju83zICS&g#sG7cThjmOSIL59wCq{rM%$jLpehD)IMZSd zrj!o5o`~4?yB858QU`eWk0NhcFtytAzvQ@)IH1c+0rrbK&347700bbGTe)Ojv!+1c z@x<1PFzZYo9`OwEN@e_Ck{-_t(0mJ}J?e(7v3*4=sZ97E^IZlaoV){})jdWp36o&B z6Bp884q{;o^CioV88#W=8Cku@3cHJ2PNx+;oHYa&SMJBzc<@o0(5*lH-?o{vn(6g-j9`+L74ipqCtSapjo9;5#V;Ud_DV zhP{k@U0alZ;!tP9q|19-g-mh=%UWSeBC_cC%`@QZe@p!i)u%mNp|18;cE9W{0VwN- zO(8KdK&b5hE))rg$`Gak3X-o}hVi$7GEBg&X!V#RrLcRFxpJ*HqP(iQ&w(LDbvJu1 zCWt7cc-hub^?fFoC5+z>ezUfZQCd=b)8tV>aJM-|@=F#9220q}JYC;Unzi;_U>xW` z)xUoQ`K3_x_RNbta@dXPzbwo=XFz9&(~2g!Hz?K27_-B@mf z+W!s@50daK;qCAR)gAThLzE+o%gL#}WrX*X-HQQS%L@3F-AiT{k-W|*&TkU_44#`) zsAuk?=nDW&Bz|bpbXtk#4vAfv{t1{0Pjb1y>a{o8NQ7c%GY@No9CY z&Tft1y!Y<5FR}d_aDk~DmV}zOBSoZxeHpR*qD~NAm>^VA3)(BQ!kMyTv;stn7o-!~ z-@8etC-AQ5J5WBh%p}I*Dh?h?s3oR;7Kq93cD#8uf@Yh*5r7a(4O>0ao~UPSHjTS~ zv~|mC7a%%lf*~=+4Pyhny!ZK@D+}U6MyzMHA)9uuGC3+p{g(Tp+F;u!X-A$XKv~BBZlfXePK0uLB zr%CeXJcSt9{S5b!IdRc<2^nyhXf(B?OQ2~`M9-uXgxt*@2}dMOLju6k!Nvsxc8 z&!#yCdngEt;u6+jPxOflgH;$vrlW@=iE`^z35H5!oOvsz?EEp+6-L@O%!jFVW)^Dh zsHG<(xaBiq9R&X8H*kdwR)RN33D?Bl3Osp$zkv)Nm14ZHx)~eP4 zbpMsG6(2)LxYzX=e?+!ZaP4^QwGAD@gnxDd-)B@Ki*REN$+95F+tGaI-e03_6&07X z3WSj#i^`KD3_Xu&Vsilw6Ro8ehL~x-{Mi=n1#oD_IhBK}fKDSf%Kp?7DZeOb?VZiy zv0~$i{6i>W_eqS$*pE}eE3r`S_k-&Vav`S%?}O(KkLMI}WqqCZ6yf@Vml%?mgk1bi|+9;nkaM1#~|-@>uIyqEX6N z55PO3w)MNcpr=sA?10n#Y1@MM5V>#VBW0lL!QY?Ef!I%6)@sb|eNm{$c|<<=Wgq}} zvA7@{fJT^_d9$tzF-sU2Duo4;w2j1?_o+@j=l?qEqyW zcL@0Ep?smT-;*2;CCWiu04{^XOui_ExPF6kp5)NJ0I47v+?al1{$DzT??Wj7$S4s9o$m*e$Y$m0scWl= z)5wa#bJQ_LSuZPPM!$r3(Yl-pSa)NTsmh#7JVXjgo6~FcA&#Mq$hmMs(IL|Mh`0o) z)yzZ5JN>2_A!|CFVEktzE9|Ii;_x=W*_u3Yqq0EkFUm@=2|@?<#!wG3auzLDgjasV zdZmh*h+lbpHt_rsN75-3P4;TY!~h6tG{} zM$1fl$8~tNAJ5aT!zoz>(uolOmeInv2KR33#sXNtR=hJv+R0=xNB;aKu$3yXw~tt$ z6ZYaoUTC6zjjL8RtWLgb4RTRfEMyhJ0W@6&?=npu1-pmRi)MBmdpjw`i=fkWVMeJb zgx_&ng$Bdra}<|<3odD$PW<&(kML)6^S)}rMKpPlv56jE%(S;)&=D!iw*ho(&~a7)Q@*hYMl=Y25N|hp?z6Sf;*sW+(T0prL%1X zMcVk3mPz>tVt!;gd30KcJE{^Qbeu@|PmPDvcsSU14TbVjg<|T|gFrE9DMbWOqD(=l z$*3q<=%7%9qQd9_HiNDpHj$)SFDn5f3!@3PMhHY95Qf6Ac_oZ48*%J)OT03D3kvoH zqJS_Ca~`^cCRsAj_AVKWjSBP^xF$bS1cZzUo_rK|_LzO+k)^XpD=m5{dUPRkA+pc-Y9WA*4O3{%q$dc4)4l~yy!&%N zk}~)Ov0EBsW48^0rjk9VFG88?KbSW}xZOw% z>2@fS6ExY=g9%bI1=X>ROu4qE%UNqiYpFw!+`4nC81BAV<=9T(%v9O77#nOUsP7qt1^wq8~+03ZOM3T4Z(=-l(Cm5D)#^H;M3nT z>YF0f*;Z#e-#2C@CP0`PM@mlnL$IHN^158bsRRJFV!Q^%Q1ox?V%|MfEH1IWMECv3 z+v!n81if+At(J$8&x6Fq=USuXtdmter_Wmpy`1S(*6IOQG+AX&*=DAFJ+gJ|1$oB} zv~Cl#SOhs6ki!JUD;WM!S0LBIQNU;;dEl0mdKe15$*t5+ON2^F8u!;X>T+6U9WqJ& z=Yu5K_Dk(f%7b4?$`&jw1*uAO8PCbxnGMR%xUg%j6$K#?Y5FkqucLn*v^v}nr+GiU z<}+6LC{=RBsu!dRtwgo$nH86~44=~sS^Qfpc|d^L@G5iR$Ye?)<*Gg{A}fp0LE)3foTu!2PIP&Z(u|tXxR=R6C%dc6T|A=Wh!~XN z-N(4yT{`TnmI5M+`hA~DEQ(Qw;pUvd*<`chkqi@y>gdlu5*cv7g+sWeS5?(WMmF6> z{(4FEV1ft90G%0`b9*uF<^_sUnr0JV?r+cQ%_p*{^V?jd(+Q;U2fM~hu`i{F2 zN|~&O8&jGHcRdNPG9z^L+m$2hQzh6 z1la{ir^6tg_#55W)zX6T{QTVDKG`#rz=AQolsjiCDj^|Jbw6hs8XX;tu>JM?1#Q_Z z^Bcb}2xjRtiR4AXM0lG6+*RcM87%#kg`0ddSJ0N5{RiLiE6B7kX^G_u%f`3m(tcG- zFG-b;;c3UBjiP4-Hz(3{aKF{oPb-6k2*s-j(Q{FI=4W=%=yYj^$z&5lZgxe}l6Ing z*Jw~vT%k=MHs6qZHj{jO$wFJd?Ccs5=~MUQU=YV31)qngKE4ItC={-kQ=VPA-h6ow zULLyNOTt7EeGpi6If%pg8u=C&XAhV=6KZb^g~N)+uw0MX+wDud-Q0KYaOXKAH`LeR zS3S$oa}5(0C-H`~>s4yT6)O~59mWq?O+ySdc$jNg3&BvFEduoO$#q?yUM~fD#>lQM z^&rKIzqM!O$dj7i8G1YV<;+6H4H6fk$Kets$LrC|p__VIh-bOj!sOC_XSI})>#@#Q zY-7IrNKDcgUng)`yB%8pE!_UA$w{DMG2<1L@9Fex*|Mj7SL5o+Ys+pkdbsJ(ea`KK z3tV)EkpK7jFC66rV;Avqy!6t4)u^ea~)+=4-ZLW;Nk(yC&dyzgO%4E@`ImT_s5j&(+;;G}3`RnTD~n;f2uV z?s%00kYqn%=57hYVjctgji~JN=tr<<$By{08;^38qhUC8SOR@rCRMgOIZ=9f&qJD} z=f$H{kWmsywMdiWu()M z&kUJ2lUB{1A_$G{=xdU}FZTM5;FtUAN-CqH1TEyU;iSThoc~%2Ps-Q1>@3ds>8QmO{!-Ds*fun6e(C zf$n`MUj^?Jj`rv>v3yvDG)bLDBCB@_U%qemdvE%J_<8$uAF7RlMus84a*B z_Ma!iPx!uXh?dLM!L6}y|ZuD!;ZV~+9M&(QMvy$xtP+=@PgzBlXxd8~Hkros7Ph=$0o zBnpA8d7T&g}xUkeG}=M`_1(!L4`e5rw@ZHBj2E zax-K?Ou!rb5Qd{6#3>vC$#T5WOI}rJr`?b}CPmFJtIo3%jsrDLuDqnBROZiOsJ9oV z>jchH?HZe$g>jpKh{MAk#)(ZTSXSfKu=7YEn$rLwHt+lU=H}{p5Z|yn04$B$lf}Tm z0JL^!Y6?L_L_|P&=C-2Z$6+Tcgqu1lNmy0OfB#x4L0< zQHmH2TJ z9N`GqGgjCRkA^m7c>r`W#;H<9cJqqwB_W29L?NE%+fQiCJ=|rAK2I4%ue2G)pu^UB z25GTxwc?J&HIF9|&9TIGmxvf#ZuA|mHGF)xa~=rc25#G*W!>EsLlDJ!&yVF9Sl$-QH2kvlaZ)B$ z3&|%oB*j%kEI4;+a;4r0pH;?cxN2hXdmU%H6F#6m@n`&6@4u_|UEKV9_lLGivLxd; z4+R?T-1HAGmP;&)2|6qj2K}?hHQNIUeWb-Za%Ub!V6DCM1pM{JZlWROZ)e*RTI@a> z_)$}mhVdEc0hy=hgkH-iXYoD|$jDH>*_j=9kL)O&6p!g;=HW}x(`gLpfC!`FtDnCa z*REnkoOLCrL=x8Ih-g|jiLIr&2?bWfnGwkVPHBK0hOS#!umjP#AuRQ=efBR()YN` z^w#Ep8`MqUNa%^U&z%V)PcypE|B0T1a5dA2wEpuM(OMfsY<_?+GdJ%Z8!H#-{ybSa zF8UyDsTRNKU~e!ogC;P=Y>Pn+@5R}7{7{{_+JA*7?`K@XIwc}Ip*kb3Jy^PQey%QlTxH5=p{cKjt$_FZqHhM2eORz%h#6Xcx(2{wDYD{Y>R4?h?}TZYb> zhttmMTvCANKeT$Fvff^UJL@d@dXb@5$+kUVPFu>X8SIJ>?%A6RzF!HeiJ|@JrX}%y zL9)y07hF48@m!%bvO)3FYomqk`Wpr#KP_io5i$;$igGM;d=rBB!C^r!qTWGCdf?0c zZ>454JcLxYA$JlTVnbx={;N=gp2^b3A&l2-;e*XGynqec~vy@AZ z8Rcm#6{FMzA?V`cY}vqfw;qqXmyW7ZLi}Cp*qS5$akm@Y(Q4OTAEOMafxUO{lcD}V z3u3vTA@@MUv|kXIgScS%JGBDO>EahF$k1^w4>D`RYhN#~voNSHBRKVGkJNszmd2&H z5q8%Q&Z@N$QSkm#tcMDG$6Kl--W*DNwS{;zl$HX)%O)bWA~2AJ-0AyO%JO3@IP#Vi z6Tf{P(_0-0i85ko4DYA6UHD_BDK5I7khvWj83Nvb@AM+ej&>slf;fl~b3zkzSP~<1 zNK58+gaZ^=u@?d~nT4+y0S0G@&W^p(g!LU9C>`FX^)FU}I&z(A4?J%KHpz}{0wGbV zW6aKIuv-&r7V;1w8cYS@RWv)To3Z-fkr`AgA`v?P^uDQ2OL0c8)kTuc*w>`fDECHn zCgqSiwin`4!icCL7!o+GNVWv&`X6eJHAT?+`Xx#q-kU0wE-O9nstxLKgd>SOPp*lq zOEP(l$cJ26850#bYd YIZHousnLvSX0#$7{2wRX5Pn;t??CCV1a^G*@P-R=>W^`V>xCQBIvae~r8%^-{_ovSDZk)3`z zy~@X%64N_UiK>^lQs8?Laho-+S5I4Ta86vI3vl%N@gyzw@5oi>LDd60mZrOZa=9+z zm@ldfo_$}tcne>mA{n$Z!%j&^$bSilWUKeWM(fY%dIfAyn>frCRns&0L%zVW5GMab z0R7q-GAPz7X}LvSPP()AyRR;8|5Yj|nquudI{1P$MOAFBhc_xl{Y?-~qGbIrHUy&3 z$!83Ln}p5}!w>}7P`Fik0OEXutGgte`JP|YT>Z9XQTzsPfV@2B3|RrTII9@h1A%4D z{@+UG&s}E9-GS{up~licVIGQ3WUMw7vHHhQGN%=Zub>i{VgY6Ady|I8FokhEhyT|& z@RFx&mm5;xLrbgo6U)4xX!<`3$?=??QpbhhoJFlX@G7-iLo5${0sD0xYtB%q9ZC?^ zCgz@9Ucd}W`MiU|Dj_?r*RSqgr{X7$Ys>*(mR&Vgpf9#3*q$F;F;vH2bIF;|@V#16 z?-|QnT2?ZT_abrxSdK6~2^^_>QUPp16mfjr*S*3=y>N*DjEO%Q!5RdH5ws1dSCIJ(7=4zUt^%gs$)aG7%>vaoHm+1&xr*C^hGXaqa%d&<;ERp3hVC~5 zs)&31OGmHTdaUGj-GeDD-Y7by`IifweH!FR(IBw2ughd7^{e!LkcqR5>qem56D*#B zAg9=kQM-AnGC{bwkZUHr$n36(G;m2B z;{6Ic>fKJHVWds&2o@!INY0D>D+9mJTtrI-9*nu^Np@#UPfcB_{nHr(XpG^Ez|Ly# z7bdhPaGrH_fedF9@GOj5zM8}u!SO@z0+&7kfEDI=4to>IkP zFp#etD}@k{4uhWhp>pJj`CCrFJa!O7(7P7_5jh>>Qf>sujgmcaqRr?yk$rZ$D>poI z$RW2gYih6g;p~^rnuJ|*Ds{CMwaaH2w$_^}syW7Y5U1xU#@@}2=WD-yZ(rykdlq-x z5pbryUu?8P@5ip6B_}5XE;M3J7pn~WAQbXjzRGB1*K)s!eR#}IF+b|99NH1D^2xRz z$(%a`_EWuG^@idd`5cRm5${ee8?x+<_`r9IOd%ti7&y%X+CE4S5Lm%E%IW4h25uHg zbZ4?R0<&^CHbs}3Oww#DVRzpxZ0#t^N5IC?Hdd32KSbsit9o2_^}A`~R#WS)N+*S= zrJ5OoqP+S68q69oFi_jw43pJCV)FtkU77K>NsjUC}8QbCz9M&sXY6yph><1j5~Q zyQG~W$`z_(gG`-$X1Q1?2?>EJop!O!cH(c$%wQl+xExM?H^sTRK*zG_*`K)pBj}^n zJmcDhDyk!iL{3#aJq4X%%T zJp}HSQo%aneb>gx+p>=wnrcK4z!^B??GZfsLF9*TK}^6I7?vYN$kn%wmRHWs*&rxk zj#M5xA$VWesdvJGx4jW@HqkxwJ|}!V?L;n6_plRCiX4^K2kPR}im+`=OG-+-1Uo<# zvG+Bm>y2-VOB|8*)30-YgX9+C_zeIXvHka*s;m1;y3Xz=JXh8m%&(k(NEcgNy4`NMGgUr z5Fkkigp*R7Py~X)*Y#oz=s#CV;bwh}~U&BXVvcxhu z*^r*`aNf$Ish&Uwx4kcGB3kyu!rkB#Ujf&ID3_&SsmA)d0+wFYvdieKR-BFC6D9yW zlF6PPp9Q!3BX>7=MSng{gN(ix$I^AEoFzE3w})}jfhfbUYbDQJCA2cOh{eG5n1=Pw zx+(pqV&v%LWQG>osuCTMDRAt}SYteG;R&rcQ>76C8GY}|Iw2bW@C+SyoA!EPKHCUH;I?Nq$)x^EfWZAsf_ zC0wa^^KWMvZ)u9pg@+?{g#JX*+V3GfN%qb>sY-uNKW6w4N8N_Lkl|AcPTZmH3D)?s z$~o^4@Mm=P$hunJoO8$;ZpjN~f*m22>3_a+%@(woWHH1k<&S{8A*y+{fm)UcT0A?2 z5{6j8&pT;gyj=JswUxmXI$k0qQ9q{Xlu+i1(+gVve1Oz`wWYQ8!JT`sUvnf8XH0uf<;!2B?&OQ?&fFtu^)wuvH=!2nfjQ z(_wbcfNU)HeOmP>L!Ee^6b7UYHgoeq}9?f|O;3yo6@O{se zSZS#YfCZ=?-uS-{>;K~B{`^=h${)CBe?Mi^Xv*5|rBp?wt8Ov!3$eR~z%6}33CYum zHAJi&q22k4^WMR`_@f2!;g~rF_Z^@}+7W4|^TP+9k?H+wVyb29&%K+q+mHW2{Je)laN*c4z(YJmysjT{ zEus2&P8tU8=6s!t5Y1o78%4LP%WJ7hPsg1ubj5cfX;3B=pF?qNCBVe@x#4y5Ig8HK z#+r~Xe#Rm$z?x7YR?%_7Tr7w#T9VQB5bQMN)C5NRe4UP1yNx_}w|x_;62VV*ba;If zpJB&~iYKlJCzuHe?x#O{WdZNDsY9HGGC)P1u?dGTztz#BhY0Y;d>tzJW>4 z@TQ;>Y;S5J{!saHgr&DvKw+0@1(w@?BQ zy|c1$LT@J)?CNJ!Pc6Y@@K?gm?M3aSDnx{imI>F=mTEIzl~bl>6R;KphBn6aR@p(LP@3#XaWucOn3^kQbMFq*n2 zP?va!u(i6@w4-6+%*^js_f>>@z6`bSsyv#Qpf@IUT+c-1jfsUNh`-84t(6Hjigjjg z&gyFLq@*o9cpUM?F2D8~tL#E$XJ=A(`+U;Jue>$^0`^&1DevcX`A-y6mo}aJ@$$Ej zz!&}d6_6ZfgI4?6-=bIieI^;7Dx`jE1Hk%Jt_eLWD_NkEtDJ%Zw(Esim;1`!sLTgy z(%-1eN<$ZlcFU(V$pd!uqNWp+PUhFHZcYT%v?yT>0xsN;{L>6E6v$tr_Wm*Z`_iX^ z2c({A<(!2-o7&ni7DtqdnYljy6P>hL92r88%)POoqriNOKwa5sBBYx;j7H|AQm z3+6k1&h3Q?2cnQLv9cD)1Z~uk zk`lhZP!{a#jNqEh3QdO$uJ6E}o~J+X z)fE_58*~sn%j!O3Eo*azCkoJ)fgbl=d3~+&zW|t#PXH!vbLFSI&)-_je*}oXOUNI% z)Pr9vxc{FF3+M|o*1sW^J${tGAeQKVLM(Yi{{v#d)0aBT0V11}9k?;itH5o9&}})6 zBlqr6viNqel?3oK*~5{79z~HzG#2UcS#hw^;E^tIT(2RTLj~8c=&$&#&>$IjgF_Vu zZM;WDEgE_pKR-i@`lKd}cHHzjL7BYU+Cyb84h5upr?sy|~ zuI@Issw&ohfW?iq=!+(|zqik5JW)iv+;}is^>nOKY71oN@}Lzn(%E2>9)-x9tYDg{kIJ?jlyR3o-BjQSZMN@8yxbC%2-1=TE%+BB_4mq@ zo(8*jWs^?)!K?$ttDm?86KPgj>UuJOAD!6vhP7>=9(WW3_@1=Fl|;!Cg=`fk)%E>% z>(GpSW7B@Y5BfwfnV@4t^Vy;RYw=q|t1Mp;<(!MD??YjmU=OAkHDe>yT{G+Rj$vm` zfaC_0?{g_DhB+OFaX;NI+=US3CRAh19^9M$PJpIt{=lAzbi(YFMj^ek++c{;qVZVg z0a@gOm_|D%(nSkI1Faly0nDY#Lu^?78}c1#`1TPylyL}betnNsgx`2je_>veYn*=B zEa{Cd>5H>SuA&L3MqEb!5OMLM7w{S+7SIb$lNbjRL$w%@q$8**(3;L)Wy8S+-Sol+ z;7NDGAm20Ua#DYi9BfY?5z*z^%c6*KIG{g(puu)Z=?_&2s+8pMa7Uo*KQlyB>q?>H zr~Jof5MI4){tS+HVjjD&L2Nqf-pzUTi#l2O7#_{i7^8xH#t^ZXOrH?D7Xo0OZp|8N z$1gW5FWoaFO2X+%tR=biEA*MoUq*`KhWBNb}&j*QATO~WUNh_A1I zh(PFkgS34OMH4MZC<26EBz(|Li>CwJ3&aydvCg!%V#C-d+hayi7R#6v!&{?qCA0ia zUvw8|H%?eQDmNmUxqtZM@?+S(qB$%HR38C!ShIq1aMuxQt>GIh8~OXb+F-n10O{*% zsS^r1xPZQT1?Y8hV02eu2-MMo)lnA{6S;qy8rTRArJY_~tJ8H6ji@RU&uMK!(?to1 zh)_mJgC|6&Gaw2`F~`OWx+;Ha<-#Q-CFy-$#Zb^cf|oDqKp`taP7?OB0PJX8-U;y< zwOLmZKYLttR4lf?5uM;Jw%9=|g`4p@BAkZKMOjJVN+J2--o;_=g_rAJ8yRt;BKjwsWO0m&CilU8dzX-0j^+j-hcOS7ap4hWKIU%qXg9Fm^*ncB4`T_u#S&``sm08RQI6>tB zs5xtW>6r5iCDA!IobmRsvm`T=ufGg)BVZJ>ZEsHpI!uxqCJH2Eixm^eeK26u^xP>J z4U>N(mr)^L(?$!5*s$yfz9H;bN8(1c*hET28sXf4%aVqRMPr<3C7*lOe*M1XJllgmk^)+ zt$f3&P+vk2WgV=3D3yZf!a5cEN!HoZv+n}!6f5mAlbv>24@A&dKrouXOfGscmG zy>l=H)9+p4a6h9C55UVL=ikY^ze`XTuMk`38v$BI3-0eEH2M7o67&E?!Qn?L&tbfO z!!m$4{6DbF?YwKP|I~L_(HNqdRBK|~)85quTkWLNyH> zO*1zF&Kq19Wi8`num*Y!vo_Q;3XEkPMs+RV%1^qkO56Hs^t*KR<Y_4$HC<5}%pynzr#7%x^-B`?sT1R`eTi7d| z9``n0je0}n^$qs4TyMUk*vUqxa%Vgu6f5U)ViWZbY<1u1o`*iwxh#gqZ7-O<3z`40 zrpU$7CKR3QbxaErm6;RBn;jsar2{t%j{Jta0K(b3LKcu>UEw$|Fn~d?_r=M){NNCs z5)hj96O(vl>AI2+jln$c(-*pH^+$nX`dJ1;PU%2`xt8xjS94=67SwOTc6}WaV5;A_ z0?@Qf&>|Dlk3E)*t*v?()iDt3TUemwwWa?H$%&`a^w+fS=&KJh80DnxNyBU*f+J~d z-O)5YVBr|4eIO1}x{1MC_G37kfxqkNS28qOJK-nuzz~Lse|R{4>@h~D-$Rdc!JtenlFw8APs z#%f0&Q+@!h!&h0w)a$SM<@Q=9Tiv~wJdkvhp?cAif=c_-U1!Zi=7ts%QwUEhQBy*cQ>a!*7-}nKK}emM z3$v;jyvtskS_PyEbd0&xFQw`4{I8Y9lxJ9`$4GoTkW!PWZZv%%^cT~BOzy8Wwy~ro zRiAD4rTJTg1D6SiUIbNX--SU3=^l?NCZ@=G@)cfaiCF5&mO#)YfIz@dtWs%B_F8HM zLd6nj?7Z!%&ewz!gpxvoEUGy!P>Ogue@`W72 zNT!&6gujt61=ow-7l0U|b!+YU1XT~xV4CxT7t<*Q1_3erZA(JD-eoc5h$gV%`4k$@ zpXY&DCn}VnD1-!=pzKs`yjvU}!QAlON|Aa3Ri&$q0^Bs6zH+%%`2?d_-^P|GPEepZ zi-%_Y)b$U-Lo|wF;I#rMPC*uZoq9zCW(SZ?_0pp|TA?j|{N#Gr?4|7>bFAO@JuJc%Hd$Fu_)(o>^- zO{E;N!+8ojyXO-t7AVU}>>Ng?IkH0|i-D1($<4k{q>H__wb zC5|RPmiY#DwB^@WLBw_D9Th9QM*OfAg%Q?~hj772tu>>-0qkmVLnm-`s z-b_3`PQ8UJ^pfO7&5(~7qrA*bk4DoRpf5fN9N6an2Z3V_H0p_AYCdgMsP-*;lmjMB ze8gxixFs><_@5-p45P$yB`2%6HJn?5&q}7ples*oktP=Xa zQJU~!(#6D3Y^jJOafJ9*2hzy*+9!>1=4~ChQTbh^tZcv7p2_at-gFoz7W}fl2&A6g z0b#a+)%+9`B5z3IRKhC8&9#7rQzFns)FP?L*jNJKhQl&Z1kjCrQBeO|r)N1b`!n2d z&X}(JurGD!6waTfdNYa_zJ3s5DZud6sPNA7w>$aF7>U4R+glc(fk#48?ynp?dDel; zoDP9WlKtjm(=5UsU9^CX%cx3j4@gNrA8;!|JIO0iU*y=s_6qymxsUE}m?sWfEAX_r zO33;f7iYC7Q$^nXr9qo*-m;KgdhdphqyiammwMAO5i6PMLEy59F!<|!M9Pg{kjhGE zAE^Mda!{l~ko6DOaFmi6f>tgkBC$m!b8;7OO9A~6K<3;OC096e3_nUMOw8nM&_T9A z+wk76D?E`%`tD)7Z7YVB`{LhP!U(wE8ct+a0}DxnJ8o7Bu#%Mn96a3Wd;_DxSZ3W| z>e|{F!oq>$3*ruvMqswB*lGMZ+4yAhb zNKLQjwZW*+;GN0<&^7sf{`#k>4~_DvEY*<*RkR|LInn)lFCa`q0D<3<98J`XU~Lx7 z(c`Q?ojpHS^1kstn9kqyQ9p9u)wK$ag>$yFeNWa9#&^DhdmO4au%S zJ*b^fNn^vZJD-KSmTV$EML}rQ3l^$ zNa)Z={a-mBHKc!WK7Eg%zw+pgBW@Y7VhuVWK&1%hnYA6uR~nFN{67hqCOYa3c1iHW zaj;|tW&Q(7-G*Y3G+M2W=CCPYcRO60pbik~E!+$LcB7@V@A5ND&fSYXE^ZGblD8KR zC>)t-U!eJI*_PKqCkd}QWt2?RrTdV z@)=46B&&}J`hJ(iup6|PzYTF+MJNQK)rG+vvq)z^&7u7e@$nbuHv_I~XA8pm()Mmy zS3bW?%S`JjW*@|E!=oEcEQ4MD#32dJuw=Z(M?G&w4%g}6YazzR0NiR9_3%J*busp8 z#E>ZZAOCPtqBB9ok`p+MB4fP!#xNOQj#F@^1x6uXqqvw18DuV7HQF&~`RLKN{Prcg7@b*a zPQl~2od#k-oFixXd$fB>fYg~99bzLLtN1F+kL|`GtOmI2ZkHj;2B!o$ui1|y4MI{@ zJiMCsYK$pV?{J)xb~9p!KvJp^gmZ-8OIb3?B$E>UnC7f@^odXqeZ#p_7ZM!4y*OSp zuuEZsFR(o=8CfLf4kC*|QTz{ux4oTh(a}b)t!n9w175@;C5Cj;IKMEa{(MgE$h4HZ?b)L~dK1%^8 zBuFod5v&a;<|-rON=4LGx9H|ZKk8-wkV!9A1h%MuH}vpuL6gc>LOirovCP%9|Jk=M zhx^mU2Tg9##T>LgA>5oH=ufiw!S<#D6I{a{QXG&G^%9V5n!&kiC#sr`YOhv`Yizf$H0a@~G#K1|@! z_KsbNbUE^5a~{4uXL(Mp{ci94&3Sm$hb(KRI%~#TRwkK>Eta7l&7QqzWV+4MO?AC; znv22C2cA*u7vt^PZy~*6T21n%Erq`v>-7F<<|^-Lmjl4`JrQn-@vj$<2ISs0nYLX4 zo$q1Y$2xhTGa#YI0t^}#ar8B@C7I5Gef2D*Kyj!oR!D!z6tzVlUN-0LwZ^6IE6j_( zRy;s>@d0GS9T3J&ECX)23&R*lwhB{r_9;Hq41Ze{k44y|PhWD2>YN^TgFTR*H03pk_u-$IF!Ip!o?OrUB zd8(AEfILrlk7i71v19YLH2o*#eagPU4@JQET)$c5_n(2M8U?05l}hu-dLYnL&>Al0 zTf&crryX@qC03F2NAh62st>tz(wGG03Z#g1myYJJH3Mqnn}!-lewHYUd;(1Ej>!@9 z`Ix{a8jhiiyl~u^GC7YE9?>#PEQ?7gDM-J>aq7RL?&qE;4c6H3Q~MPE${i>X;~NL6 zs>*`LHgrH{%H?*QE0{l2AhKS^&MB2GstcF)rj$~sujbQD?_sXgB- z&Qp5GCBkO!CAY^+Li!~|E?7`V`{!FbW&nFJ2LyUTH(qhva;x(`yOX@$VnDhG6v-%U_1-Q10*~jzSL^S&1+Sp2Mo<`HS zI_}m@AS60uOl#*c7SI}G@cnXSa8Z5h-?Kr}% zS!nLb18XobY!QU4EyRBx{M@H!VId8tS_vucNXxU~S8rO#+7+2EqYnhrhGh=9I1Nde zPIEE=NF`w)hLwcjhUr|>cW9$UN>S>CZW=~Y6ba8#-fkJ2a3U2jK>i{r2o=jG{~pFl z^u+?xP%KiQh$lK0f7 z5~OhuOOYXJFyaqT{2X^jSK+dOt)=S5&i)TVwkLR)muE{HPW6C@4oERwcF3$4nqtYa{vTt|dk|~CA(XbS2K1=8 zN??V))J`zR68tQ04xth%Z>pC^v+5;yu(HtQ!qG^mv*iukUDC_$GPk+@d1vBX~Cr|c!x?|TEW*Rc|v%?dJb zrq#Q$TK7DsU*&xegDv#u?x+Xh52fJP$dwQAJHr@i5XRU{DWe2G@%Y)WIKMFnF_OJX zut{AqX=3y*cVqwih%Xcd+adqqAof>J(o7rFDUo#~z=(^}5;tKJ8tk|cq4LN&lpxbq z&iR;pVH~Mf-Rr1jy}7`qgyEMyT4KJka?XgvjMhl&R9dEWw+g% ztiSmNnA%ASt@j!<=>@6j(5I^CiR&CtfQOPvJb}?{B6q9rd0{RN^fu89^Im0m-k2li2hLo zWViSwzJcvn!Zv@Y!1J1EK#ARaT!@qt6U6ieLC;Xq!qHw* zUwAawLEr*Ido1s%gj&C(Dmw{m4b$;!_*IixGp~ihb;&&}KT;5*{?0s70_{dP-9e5` zTh_tgTEb+~(Ui$uJd%=NG%2u*kqLR3v_zg7Y=al^c+rOe`|!#wTG+?D>{@jv$I&v? zJ9hYr!}W-qRFrftZeMmAw>^O|HJFr4n#PPtwY5)=axojYB}gbQWaTdJgWk!mw)@5F zPB5In`j%e`2zWy?@c1Hjt2C zUu(@_M%+RYstBj0`|;mT|5lc0&d#@Eg69AygkN*>`~`q;EVgDo#~eWUmWYw$cR#E| zZY-_S`XQf*i=$$Z`UGQKrh)@CgE}5yNPtjkw(!WvuQYUDxlE0EjGEpt=9ZRlrGzcj zTL4<*eH!FmLcOw7?ffxeVbxERn;)Za!}Q0}pABX%iA>W&F4waRGL(w}Ulc>^~)v zv#IBsLU_n9aDI$`6@pujom(T)>hQu$jqEHTjI~fLzGoO2DhRPM$OTWQHc4O*Gx(zS zlOO_GE$${!jjrtF1`Gw=b|8NyhN1lpEN$c*I9Y-+diAfW<5b8WF&S+4fig3$|IBYw z`}^|Omaqjc=Vmt}WRJUa|Eh^b6B_Bkz{9b60_-&)bt|1~oaKzui7j(^kC* zVnat(8aHD^qXVkmPR4_roldwU*@ON~zKz}HePRc-#`dC|hjw_G5G6@f44`554l_QT zkilkPMwWa zTF`G&S-Q8P!QuMajK=7P3N3zY(e{GIuM_N8``v*Cm3h~8Eo2TWE6o!4#(9fyc*Y5D z7;H2V&5^y3X{G?ZxKbvT!vX?>KBwkOby@%>lP9c0iU*|4wV!9V`eE^A^OKwD{Ws87 zPH20c+`7_q;53ZLs*gE9wC0!;VSB$T<*ev{0sFbI=Fx6QY>KacxoXssyLs*Hz=^d@ zLn>0>xLTytHhN;D>lG33IzDP7X@!Jl-A0$31Z@f7%%ZM@HPbsuf)iB8WSF&D7XRu^ z#;MJyBKio;zcv+pP^?ac(NCiNK6ZW%5qzabB6s(l$10#KBE=OZYIsmz1IBzAy2ld$LbpWeu&%~nfP95kM891`-+Ba5 zAHVbD)^~e$^eY7!^PssORCk1Ydo|G=fL*b)tuvPo*&Fd=9if!A7~SNR2B>(xbyB8C z$Y8E4oLo7u_;c76%UIXq;k?7Na&hUJ{8AjvEc#TI|AF;?fHFDjgnAYh3uX>s&OJkO zx0P{%3hNm-7OqW5wg~^&!=@s?BzAqKF;j$yM-ryC^p5*j;ta|Z@ycm_L+oYS*RdFV zZDxU$g`!t8Q{rxij;4J+uM7rgD|&aMI%$axND-kS-H7ULrk`_=E(>{!c5zn*SjL_R zDKA|q>F`;D)KEW{s7r6t4R$7ICw9dZ0F|@6cOL;u$s!2p3 z7Y{W5O#g28FE4=Iz>-NjmL6D;lD+(oXd;&*{40#|oLwfNoAC1j)l8Y*QAobqkBDnl z)|xZ%*!9>B!~E*QJt@#-&u-kZYZ?Y2Vo{at)jjIm_n;5F?$!4|d!7f)o5^l56(O=h8gHU(TbC|d<>&@_j^9@e(0m*^FH26IVE6uceG*I^leo!ZaM$*lZM>b9rF z3pYQosr!c@crhUe?<-DgT+g)!R00b$Mp;_Hsj1Dl8@Op{O;TvlIt!N+`4fxeqfrlA zunFHDC?dz-rrj-G(Gx2e7LlbFd|nfmVb$$ntWeqAowKA{V4F&xd;xpLFu=upq8NjE zZ;SVTT=D}Yu+(OR(Oye^0lkeQ=mi)kAd~MwK$lYkpPm2HHuMb7+P0th#7&HPCJP^& zgEX3JU4QqM4P0%=R$roTE~s=ox-4~w8Ais%rDqtMnvI3!b0os|ZGHtqn{RsG-ue66 zQ+=@B*@Ao(SH8vOo~$`n5X!hz&z>PU3Y_gKGMw=jImrVpmQE7flwI0ei6JVp0~roV z3qc&QEfe!@vF?PT6>+OH@!|FSx1ic?l3)r)xa|Q(tS$d@MP1s$d>t(vWw6`Hu3n&f zQq^ng3fzva4*hIR>5lTts_4g~k$Y&?H3R&Dc)5>X>A9)PMLddcxqRBqBY=8r=%^lP zV7jsCYzIUg#a7>#ps$0J*B4xv4MN9(T{h|vd9;Sact|F)I-q|0uV3>P`;>>tSnnCqy1Jgo{GRv^;_%<9b(w%KstW7k;5S)E z12m-U04x#E^$u@Mg0Q_kx#09~2Ks_oPz8^%Temw{UY}?Ot+^xNa3yQ`oTCF!v-9RTr>VN%Z2GHU!jtKzKBEuXK5+X z8)q^UQ)VCJDPtrZt2|#)4N%&in59^(*#4+~$|6b2xIWPwT@j|!*lGn^o4m={P}`CT5pIsSGp#&fePiy z4xbyl|6afUz#sGc0mGtUd1n){7Wnj#q4j>XOHMiD4R;&~tLx)n_5=Lw=i=@o`C>x} zE6+-NqRWpjo!+kj&r?qv;Ti;8F#MjC#A34IQVAukZ&q6E96uD+NQd*%gHmXj;#{0L zl13cXOxJL^rNp1)X!8Ah&z!YlD^SDmdIRjwHR!==t*wmiFhWZ9PQwTUs^(XI6YyBq9UoTpTs~hoxLdDjh=O7Nx~ zUI?ze442+A)VCvv9wifu*WLtK`>Z36S3h$-PPvxNg-t$Y<%~!Q*|@4cw~3z@&mT}? zPl@+DHhgdSt*{-x^DFK3-Dr7!_Ku{e1B-P+Ozugz#T|Im1vGNchb?0!h*K)2c*mDy zG413mK*P698Lig#EtNip8MJC~)lm|OvYbrn=vqyWZ60Gt;6olT}h*Df|SgJxlzzQDs>wBOYBJ-Vq z2Dz;)5X5Q-MGV6$Xt%ore^y{2aGKC7&TC{~P{O*}s3L{uIV&soB_%6{Vl%4E^B|0f zx9Ruck|+!#7#kH7{1Ja0xY{0!b|5@gLT5BW_qcca z=Gc3*5G#KoALM)$JF+uo=Re|$qZtx6LNx7os1nxxPHC4SSyq~>cz~&Q%jVH-z9BC& z8WB;^qE&UX=-||J^ltEo_&nefU9QogL})#th<=C?wlI{o`k;$|atXe+ITt6dz-3%% zC39_NxOGiv)|oDSH$&`wC*LP!ah9Y^f&p>!L$t|5s$8jy@kuug8!@b&=0~lP7f$=9 zXKNX{>Rx7=IYbsK%-nqH)_yJeydx=WGGIv4xX!7)4fMah+RCuM820z7U?P=^)tGN@ zgHqJYC96$i6@IGoE>=*E3yMX+d#GMP%c-IkO(`SI-X|mT`Tz`cY>j*H!A=@3$3FHr}z@yak+ z@PcZGdvk%NMjRD(*K-hh@1$;UR^BHBdAlB02gQb3_84I!t@$%QTuE%f2Z<0On~xM0 zWaw1E&|UvmE~@AS#ljq9q|J8Mz5W1X)Sh0fNeu z(|k0uju-x@D7cEO2D-Ni z8Fea`N>au(by@V5mb}Todwq58`g6W+P!G9nqHH#_?9zw@Tts;MRS|v50Y6a+e)*hV z3hc219!P}vvh5%g8OaKe+U7oebsR=X`s3QdaM`c9k7|?8%r=d^?Rp6kI1TS+q#wNI)1PLaTXb#LZBR`}HH3#T0#)ig3`7%D*%dTy5spRi#{TMdVeY zw*n`=dUb;lNAA1eQJWLPm`}cXAhDiM7LrIlOv|ng(mfbV)GheLWbd(!%f7h!fgip! z*kAP)-Td5$7;kG6FQb!}C8t8}e^ZBzz^TDt|1}d?gkdC2}-*^L_|!F1?dTgPe$Q~45zvc;*HYj6liUUuvhZp z9jMF^Jj@mMZLA;SPgZwRt&;v$-6uqNN0f}GqaCF!o#c|NsIWotCJh7B8$(!O_0yHN zPN_{E;@2BE&2IjNzF}eSBR?Cp)P1kN;?d8v?4XK@?>FT&5S5}U)#>6<5q<;Z*cM`l z?|VXeTw%y0SHq$N3pkP=*BT$m8kF0pjEY3`=}t%3JY2DQzI`J(E(ub}abn z*aq>TzdwD!rER8}8DG;FjZPp=JY!98;e9MQE2b@RD}Mds9RWd%SlcnPl+>Op3thF6 zAe)n3Y5so3a6K;76-4L)H{aT1XK4z!%==TbX88`k9PX!I{7 zkeFrSIP#)U)?V{fMv#GX{+%-JKL$6Dzy*kTze_p%KqlW(I?m%j|!w4-t6NZF2d1Rfzr?H)h0-E##f|n zS@v%Jfag_k2T|zkw6qzpMNFX(c_*UfzlRXW;NSFrrF5HvE=xUGdI%D$$YBAk)r!@m zep=SK{^kdi4QVmpKqN-xt5w_vP1Fm~1zjKax3j1dciu1!igv$6t?ZcvR zad6*CtR~V!D!sgFUr>6IRN-@U_o9~6glGNnNZkVF(D8`r^T9N2ubHz3#vnRqWt8pL2yI4|{hhP|r z?)6FXuhD@zX|L;3Gk^A0?>A0wz@QS0R1}JVC|>AkW9g<3BjKbqu{%HanCRxJ&P zjJ-fBBGY^~C2t}U_?V(dUC$h|>gqgP4s(4fMWU2?Jy6Y~3eKwo_wpQq=Z!vV3?t%C z=HWg=pP4~eFW=Yz-*>QHac9&aMxgdq>MDl8YwrFqmV`IKokbDAm1a(TYEWG*3S^ow zwA;JBAR)Yxsc|RIg$M4wHIAJl%G_J~Fh=M$S<{n8OxPvpY8Z6wx*Kt2PHS46U`5q+ zM9<5O8r+rIqv{Q^8-~k^Cp0z&zx6p#R7b#lA5#%Inu3HOnF*xesAf-Z$Bx+@8i>3v-RuymagPt- z;6>qeFPgnU@b^rQ%^Bq2ZPW4awygR3;r=b5_-SGYyEH>a)UYcy_ zH$=sM32mu{JM8{m^ zg1p}8SF&V$7_L__mm7HedW8Iq=21oNuF>tG6f_}Xu#3-B!Ha37x=jNjS3E02+qVD6Gq#4>Z;@}ZI zM`ce=1(klX1plxXjv3AmCofwuAdM4hG~goDh(b3qoD35MwIrNU zp-ybL8so?qEwLMgJWRmgj}ZdSeyZ$ONl`d}L#mVyGl9SYs@d+=yQZB*0v7A@>mJ@X zECD|P2%YzrOG0vudO1V!r+XMFF7z}ZVnZ#P(w^H2cQKXr8{pEa0N-teDNHuKNd1ZU z(%U36IF3uS=~&LR{Q0Wb`#5-MC40q}GK})*ON41}G|#3{2DTK$K$nn&NrKC# z;X*ejy%idwy?$Cm`_trPKOzk5 zf#i=fsR>-x`{r@v4Dmb}I?_W&1;8)V%<}eSasEL;<;S(g0qlHK;j*c>$^Fkmu#*Oe zQ^%q6>SUAm(DDz!+S|a6BU@!i27suYKwOncyooA@)S`tF_#|L1*2Cx85fPGXHL!?keku0*cTX35h8Bnw9IX5PVYg!E;o zkPSKQ>w$b*^BAxip>KAoy-?)wxbNQS3k3-O@{tpgs`ge5zS1DztvL&Dj2q;mUfpvr z1G$7>=>_n6exk2=3_|xwEXRl@$*Tg<)`eS@3&@Hu?)Y}TU2@%@Ey*o&4qbi^i4_K8 zz>&7f#7V?QBnfXIsfTt2>>opZO4b=+S=*~qN+i~B7cFBxV&4wh^uJQnF-m(v7){$A zRV{JbCbOAwkza>#Vzi&#joFSe#w%ViDR8Cxl01&%1k4=Tdv+OeF<&V5!PW#(HTTfn97ys6C?9U<`FAL z#HMM95zD&BqX8TyDtSt~19isSi|xL#%MPs)URQRc;gU%*E|f`~ZNh(+Fo#Fj$%x=S zghu`#gBmuh3O|UM4B_8+DX)KsdkQ7O7sF>`Q@uplM6m?5gA>cmCc@YKURTV?#bmy- z8X_T_nw&h7$INzur4np%VJ3(dusl=)2$MqL4O$%Sc0T&~Sy4>mX3Sx%@ze2&2GUck zA|#fq^m0<*@WN^LWEz&lKN5=KVK72*KWIP$Q&>}uFkwF{t-}%>wAg=8Qh?I-q~Fs( zNE_?g7NrfYrlSjtI^E@eOn0y&?GO-ecM;-zZ@hxVsOTXD+vS}XC6+6vGu3~L8*pQE z1`i0?5*%Es-oEQ|^r@(*(6g|h z+(R-@nD8jwEWT>PZ?VPp##s(mGyB`z0)g)n2)UQQ5%$pvR_SUvsA zRO4G&aqM>@oS_}VGv{ZAGB#Nfy6&3B4g1qK<>SnD6uFq(w<{$^FY9?L527^-Bc2fC ziX$R!O1wS8I?H%_X~DzMM#iKRE&fx@>e&yd>5X|kq4y}gHU?ahO*pAR6T?fzMfT5} z1&9()yF|3ayf+c)`8Zu7&F5*y{Ufxn_?0hkzII7Y=4sTOvIgrK2TvSt<=?}%P=j@h zR#w-qnLYd69Wp?zom^ylpKSSBUBJ^S#8%@%hhVdeY9GVpOz zsz-aD>!i-NlI*~)SbzqY*!B$&9f0me1b(^8*Eic?bZqQ|K0~UerUsrDpQ#7P{=yBM z&1OCK!IFYjtHqDk`xW9WloRyYuRVgF>QBbj!e@iU!Fk78f8k?f6}R*yDwZHY3eSi+ z$d&Tep5Fx{HOzf4qsNTQvP?wL$$+LBHHKMZ@|x1?BzExf@X|JEmGwzQIa4+*ax{X! zVLZBQ`jD96cZ!XTB3dyu{Nd5xQi8QE5|E{!G4acKFMRAU2Ep-cPDqa;o(WRnI=>Yy z3bbiGr`5UZSCo}s!9OE`xs_C8qU<;(eLk6BWv@gdB7M6%l?!UQFGRfl98D>)P*|9( zRfXZtbQZR$u`_M?ywUvfx|N_%GsI)J^SfVv2lMpw^m;i+73BC0(-x()*dLB$f4eWC zpU?O{q!kmD#{b8+#l_sPWOCpR=-08Sf(#jicYsLk7XlJDCkjEJNxoou(&Q4vNdiT_94L_YJM80YJ83Na3R$e6jo?CGahiBNHhWt6syX^aRvq>X z&pM?-+)N&@+4|}aY^RIKrkDu02tf6_)=2%}E+D~xni)GS<5|1J02Y}+lU-P%{~CZo zE6&@9R-I6%TcR}UEM($!43?#FQ8}5nDAW*o4_jp&#G&XM^Ub!p zI|+R~i^wJ>CcOj1;ph_mv$ZTBY!~1_8&s#O7yo?}UY4L)ca<0{VFNh)Uj3{(rKga+ z9kV_xhEX_neYrg#uEVlQV+KJA&E)m=2)vumseux6_33Wz|Z8f*}^rJO4n-wONXPuh}>24M`q9o$qXv&-B?=G?VNoonK?4hUPIMG%g9e>ttF-oCh?fftCvH$cmrCt<5!LG3#p zkkT*5_g0PqF$x|Y?#?XFT>kUojY^qB!;bkX^khbX~wLh(|-ZHH2$g)(Xt)2B;;7`ky==aN`bS*g@yB6s$~%M78$S;4Z_YzFZRbLPQU}M zi(|4B6^Nau(}n=%O&_rsc)|X+CVb=;WFMxGBOLbi>*-4kgUu;-q3~)O8^2)WUpb~uHIPcPiZ zP!7Q&Vi5=JiBfK%#znlLRb|;fRaIXhua0bt!T&}0c7jJF^yx_%sp=bN$vQ~t!c5@6 zc^}+f7ZXg!-RMPv{v{B;VyZFAo-DroX zp)m>JQ`&4_zW(LP4Uz^D?-jX{Or;vs2#B)H4v~C#Q_|9+E`|f7Ws5nbKnzxu6kk`v zlap16Qh)JYQky;7Q{T`cKra}G>o3|z>nQIR6SO(jeCvPXy+!fJv`+w}chN;kADN`z z{4adK)VE7QM{M3HeE(a2`EoPw0ayOiDpY$%sD!2#&n6zhI8JbKjO!nniMqQvwG{J2x%AfmV< zkc8HC;YF!k*9?4$UgQ0UjWCH?04JMygW7JZ*i-3W6j#(KhuOJo zW14gSWL!LroPiKt9)SzKV^`m+ofp*wb`>RD%oSw|hV#JY`xF1pK%dBg4}^bZ zHch{~#R?9$Papt@i8&7DxOp_@{&nB44|c~x=nN@%mO|QJ#XArU2diZ}m8U@z)_-Z- z7`oZm_prK%9`RMI@R3d0eB4m~szUJnOQ+Rw0_>6q|6ee_f6)L|sF;T1R4Y+1dZKtf zg<1fm8!}MO-g+OW^vkH;DIqf+wyhtQ!=ux`aoVjxZ!kVZ4rx9(7Ikvin;)|^b%$s;z4mCnKL`hogOZaG?JN;;%NnJde} zTyx0hK}9yO1xvk$3BOw}p;!d7XLAk>%!oKsg?h}`4trdqj8DeaX6%5uFJ~_DhB@Pj zr0QUGE-7IgKI z1znExIQI#W3!A$k8!DD&L{PLmop828#kA=fRL_?k@Z8E<{FB((9>58{N=u7 z;WA{&lIL-w)xUZgKqtRh@En|0*M6cKf2!QOKoJ=G$A>j>g}_(qKih~A>_V5Nmv*WB z3Lvsmh1atXDRjoQ>_*e|@^7?U>YbTEr~njDyCg|xFiV(W{hzN9ppkjQjD=mo4F9GF zlNttMt`PS=p3;=UFe^qFo~B6{Osomae_LM%xM9nz;p5}UsTAy|4kpA4MAaDju(Gz% zQdF+nWG>!m{KFVe^CFbuZ#<2Ko24yL3I~>MC(|@&oMuaSJ#cQ(Cih`6jSz&gIOz>n z1nhp4OMwDXd9LG{8BkqQ$M-@)&3>)lKR@mN*4q0Z|jo$K(La@4(dS*Lu(oM1-4pb&r3V&Ce9jZxJMbC$6R$=n=+`=hPU73GzGy1_w|oCteYp)&n90$ zJub@Bv{LBSGY|iuq!*>*BJR+ryIe}F)+Pmga#v{SVvvNzWv~UW#RWPOO#`X~NL_N;3%oyNH&#!;$SS1cuaA!ZRTVVF5aXFlEY!=RfeK0Mruvdbc@ z@XRaDPO0DQpSe4AL{;a52+jVj^&K6;-g~1q^i=1Z7b2y;X=bIfd*pt?O{I6v8#N(z zQBP(jnyp;-T7tA@=K>y3)&T0(*_0q#C*A)E?Covq#lj6PwrzvojjY`D_4x+O(SK@6 zjBv;Ie%Pg|fLKbqhwI$K0 zIE3g=J4aV|y}iLGBdLA(yZXpzQ*WEH0|kuR+d_5#we&wIGZRsFkd6-xZLj*6j*~@f zTM5(;=*yudPUY?GU+7vG*SK{KsJl~+jjx2S){__oOn zLF_6-@OmbP;rxG~?P9oLN|hsM3~Vc9(ZpQBTXp!0Fux^6x)tHd;_lnvNO@ne7$f#} ztdznP$^Eh;7}UY&-4I5K6hEy>2m$n$8;@KzLbO|L1u6?xc1Gx7gYGTJ=VPPBFaxbb;MtClOfnL^E zX)*h;W@_Q}B7H<}#Up*SLE@070AOo}kO9+|nl|W;?7bYZiBmN%_A6TF9x$z(ktqUOlKNbT=)NUu> zC-<7q;?NqLVd;7f9eFrDqNVn)8`wYD7?4cJQmMAR{egS}5>VA*ydzF0*}Z=`{O)16 z#&44uQ7G3Ax%WbW+e~!0u?V#X15FbgQ$3iW=;tqaAb01I*Z(5%$9kQf#KecfzM~e3 zBCOPbi;SxF9FxM=7FKi}3WfIW>}=Y#uz&yzO2J9azTy_AdaR6aD|4vzlJD`&Xg!gx zz4|Y>(3O+4j7$4^R{jbnKx5k}{4Jg~|u?}gWew|og z-gH0EN7lxSTz1#LQUf6c^k;z#3M&Vu@pTTg2%_Lc@I5Al;7m)$r=$uJ0lG7ZYSgQS zq;XQcaG+96oE@aOP~Gg*x-@E|Ue7T6aPD3w*q%E|{mbLi;A@>2*jI zI%I9dezf3t0Frqs>znFoR|-|bm}4%q>D;fHWHzBg)+m3CfD(m`JfDJ_0nZ=w3`&Hr zgL*HE$q-L-mC~9j(K;n%DEcupErTGr#4+N|7<_T5@xtr>I!^a*66Jq%om*7Cd*!4A zw(_S#;7ZW6k@`sJEo^wTqTs17Vpd2K78m!iX@&u|I&Xmakr*4A6teQV{u`P?cCAvI z_vt@NS3Myhz95l-?sj34Pr*o3i1z-U`~tgU2O4%rxj7+ENm};T;djE&OEC)@gmrLu z{e12SQ;7u8E`2A7Xd66&Y=6?ogJE>yGCjrMTsc#LQMu>#RAJ+I=A=5PV&X8x$=Q<& zx^Cnj$mra!8HL5zn?0%O_41~sXbTg=x%FL0d%eWjX=MuW)W{OR46YrbAwbSD*BDZb zX}!jSTlVR+2Mc%4H(jKo7u0^(I6Wp$I`$V_QkC_AsTTs4b z?icgmcMt!PK;rufOC0Q&H#;sYkM-F*+{<2>gFmOW z@xO)4mRUgV7WTH{Vv*QGg)$_|e?Tp=k;cP_Jm@E;xwr2V8|&gjHh@vaJYfh5zc)pFqkQHG_zd93Wy;|xR}|}ji|%;LbOi&@lP@%Ev7&tq){>F z6i?+zPKoVd%`u1*jbe9_^h4;kWk2P}8-Z(NxcZ942+_U&5?5ZBIy%Hr0}J_RMoi@o z#;|8h|AW(nf?cNVMX?L>1Y?jZl!0YC6ZrQK2|QsT`)#d;L#29BlrbhiAQT9AU|=AP z%hjgR@Di{G5~`8nJnY0_PGl4K;otTq-hddVs*35JM*Hsw2#J))U_USt&*k%|z=Nd0g)UTbF2%;VUddAsZR zvcLJUUr(?gmImju#?Vsfz^^(gFK+cL-*qo`pY{ZkL1jfM1cptkFk<7q>Fj z-q6Bq*o{75czs>#`8xNiO9(2pORDBy4tk6E(m`g(f5$m2lztV@&y_+!6VuX}zWPh+ zFN%jJm)|;!nu5%U9x_cQfr-_&jhR=Zq^sko=YXZo%m*2Cg^M$?RL;!I&-d=Xl#k{W z%BE+`l$qaNgS7#MH#<8!@?_2@1Caqv>FLSIqB!!|!rXpD)02N^@_bp@*({X?h=PWL zQ8Uk7&$~bVD(GWkVuq)t#FUhf0d0GQ;e2k_dNhzkGQvdI$xh6L?_ES(T>kmbFQhlAw>$AS@-cBLLNh%5tZP_(IV;{JunzvVc3Wb} z?G#+gdh)}z;_=qwKhH$!@btz|UKx5CS@`C{SZW(Gmd-?!Gl>lguhzoe7QwRW@C^Mh zVz~uG-J2h_Tb(q=G{)ZPe+}?HZx_u7I5^P&1H4(=@a#=v09cI6o*C55h7INv)~pYF z9IlPGaQwUig^na$@L9cjTS)PODj1xtJIE37QHvM|F1U(Ncfys$3y$_rNnK!hzWF0WBQ!{zXF8rH)qvdyE~zHi)$pPa%}+& zM#JzO=5GBP0)Rd^SMVp#Iu)VBa9(~jTB1EW8*Sd6aR$eZ{ zTnr9oKs~Lf@#ShGRe8mVdC+&fzFC8sW7XsuB}b%3JM8fsU<_byglOULZ+2EIx(I7IAXX&AATr3>5r2z_I@!2 z%NCwSy1d*Im#n~yiRrt!`6Ah#@a^C3ta{o}d7M0M6&$ks~P9<8|0^&;XE;(^qmVr?3D6>p@}P5)FhQqn&BS!$aKfLe2!!GcM*Tn zy4kq34U|sW)u9uW9XC;^rV^ZP<7D7i=%@bqBeK51d?3Su>N->yRfDlP9t4|Tes$VC zt{2Pu#ZG1SZeWj}%Q!wjRT(Z+k##kD-7wrtb66@CVHLEvBBMtn=yw5hV3e3TiHyEf z9-PMbC01Non7(h8l#EKU%I3TZa4OwHOGOAE+8>T5H|NJNa zI^nk=m@)hxZx6TjVb>?3M0qaYFYtnfLhm~>C(N8SP*7CuTmQ_goEn*xIh-P|4}T*? zXmGzX>Cm`NCO&wWm7-(GpSL*IWrjg`Syg|x-;TwxOI2}Poq4M9oyi{vi}~aNpf)j< zOO!v=)kO-m(WEm!O|{xR5L_X!P*vsSMfQKT)=bzA$Las19D~PwMDuDPnWXn95<^(@ z1lgrX_BA7Z#RbspYHb0CcE+Cc)Ia^}kpZtWZ^3r9`V@r&N$HCIBSI))ajbJ$I@QXH zPisQwuluQ>WCO=Pf#-*4F6Fh;%!!1K7a`vMmuDAC<(r+l@GEhak@P-bW!A!a3pxDW zW^lZZAM}V>OrVbW>*=!icbgl$|6IyWcQThrcqizOG3WwyOUYt!C6+J|5X@LD27&&Tt! zI|KXI!boTq4$>0oI9>xpao>I7pR-EmV_$tgQ#@I1)?4hKU(Y^T?1hL!FW1Y8txck! z%LUmIC>a?QN=FD7qJp>nl=a3Ftz6&Vmx8mQ%%UQoP z^k75C(aI$1|0dtlrKwoB2*qnuDF58UI|CrgIV?(j}ir`zVaKOx`RL$R4Ey|cQjo#qppNnBBTXc zUY~4%!|{OAg3B@y33j2Z3fcUum)X5tT0KCBM5%ODNxQJFBm+r536GF$6O5oJDAq&-jT7dtxvN<2b6-xE~1Dm@1XcS)NPXGiuwy zJ{}&P?R(l660J68Y>pgig3+`yVOTk6Kp4P;J{q}l-sbax2{>WTYe2KViA79c%&=(D zQ3gU3cOoYzC_=@s#Jg6t!i0ObyLH8RdDvJ2h-x`{C&3L{K3K()W5;8`~Fio zsv`>T)}fGD8M^Q0edsA z@`u?uciiAERob$7E9vEPXY_UM7szAR^nf{36Yi{Qs`x`hQ*c47Uod+j@NYg@#U_ix z;nlL%D;)v;jOxqe&s(2=!WOw5|3=rP|8I1ie|gaX_@%`uutPTTX70VSr#wq=A4lBJ z*Z@RFmR-_bdAa#FpLKZa{~KJ75Qw>d;6*s$i>Q9!JAd&Tl@MNq+m(6_|G=9Iut5f+ zQd-764lxebVYfTQhN@4rb9TnpK|w8CAb(>)3Lne&<7ki1P7D}o2+FQgi3!x5Z(ik!wu9>@}J$?@quUO1^U$P#10Z^*Z|I+Sx)I z5dDekPU8(R^=13b8rkFjN6_f1xCNdKge)?0FeWJ0MKc{X&(w=-?|O%totrbPDLokx zgE&FZ!66Jm*w}c9K|g@1O6LQ{Utnsf!dKk=6k??In}4EJV|gP#x&$J?RWkzxe!sN@ zB^@IxpgZDrEGBfF_^yjWv$%%OL%E@*OUA)I9|^y+UV-B>>x?R`PHz^m=3 z%0e5TaJSAFVhoM}F0(bh%{qqn5*`XlSh#x>buL4k_RJtl?^FEjnX!Yj^U;Db zSy)-<&Vh?HduLb04$g2`d+k9gAd_#lx2mWZxgB?yUNIv+#TAU5(d?M|lJ^wA>>str zjU_CNk~11&J7W=rbDt6g!W`Oajsk0)1>78`Mm+r$LPsIY=xs-x;1WfGLC9DXO7HCe z5<-U4ji(w>+t&<1U?a~y`I^_41~n^o3h}DuK#7z~p~8$}JS<0(=(XO7h7dQQ`eg9r zp7YPHdiodqw%|rIc63_S1w=}NU-_vdZU4R%;X!p&aP3e=+JoI%4)_5T|GR}o?B!-C zy{%>5;Dat6zsFVWtEKAl>@J3y`!*W2gEzeS*e!z(cMT^ATm`r1P9{w{#OoUB>_8s> zb!xJkza(STZ{eZ`MYrJFN@Y6nm0mb1*y$$dr#9z!qyBa!TE#k^Elq%fTyku%nP=mA zB0Rc=X(doiqXzrgqob6qj~DvLA%yU%xbRj3msl?n?-G)A&zAnOwg{5 zE&V&_Oi^;5h$FZL<$|+h?-WR(D za6>&QcGS&*kp(__y-ZU;>?Mf2vlggyY&RA zaFI^{(`ZpkI>1RiMrx&lj2~6ZEfKHjqEAGufuJbWwhUYPXDsF$a20+CPs#8W-A!YpN zJDTc_2fFWC4rC@7AR|QDt7Yp}mo_Gp8qa(8BGcCrzqUF%jv54)Uh;iv}Ftx0Wz77lL#16ePHYjceo`gBaC6Cln@BzbG~-{qKJdoX`PJ1GGaJk3gB$Gyo=@QLY2?>P8Tmt*u1hVJ9OYE= z7YP(AtSlv#MG%cXu~yx)0eFqObmo8S!I)M*b)uI2a3_e8bH1;sP~XZ> zpFvdV!q|H9kuhrZ;EQ3f-sMOiB(@hF9p+_%hO@ImD7wyo!rG^QKZnKr;D#hN2~!~Y zZ*qKa+A)`Q$etL?EFLV1)uMEU%eCx>+1K9BImLloc?c2jx=1TY?<0I;WzQsA6O1X_uC6ydqdcym+J)QGF0ADfwqfc4|{rjlDps!cGOG-~V zYs}snlO5-cQBh93g5775TS13?$Jg_AwiRmFz;7>EY=qwES1#=c-wt1t)GM@hb|-CgF^okK-9 zx@=QhYro!wieczE#S5cm8}%dW{!l%TN&0v?;MDZwXW zEHy@&O)5OFk%3hCm9n@@dq!)qMsX}gmou1{DVk)Dbq1MN zR&smzXVEkG&(n*85Oj1I1427H-NZ7{*G78Gj6|e{8q^mcqzMTo>gUgAM#Q}7L5^%x z!S1`U->JyoEusU=a9S)Z5DUes7c-j2=*pANsQNj+`m5_Wbd>`N#9|ASm>&0PxjgAc zd@4o1YK&GoewX=UL$!caBd)5r9ALu|FB4d-LY$*qlDTtcJkSO@$#?J*D}6hx-U<+p zfc3JpjqX;s*k5;*BmC*w*+!=S-`amJe*UvH8!j{X5=-EY=jmQOg$5#0x%yyd1x_#A zwg5Ksb|B9o(@2tz!BhJ`+`LE#4R*_M6P>J@-L8FZEi-~P?;+&2jqb z)yECyPRM6pXIbg#HkEA2km~6CVwwp%hWrD-;X**2lJ-CidrC1w$O%5D_bxc{Lrt%Y zhK2UW3)UYj5hBzErMn_+vP0z|hB-HMhXPmpkE_pP^UcgMK2cpu$21t!8|-#=*x)aS zfP;rVw~56c;SJg+lay0~%+(tumE~15Jb){WB^W>8zX`a-4X*a=Qs z!Srz55Q_13r(PNxIccEQ`MK}xIH$Rv2KyI6$qA7D{124M9I2+b9t8M&Er}sf& z_CVPSS!$3GGXM38kW}Buqy+cvI(j(L9pOorbl{oV_ZXIa%k~Fe#@)v|FazV;*S4vu z1US$tA$M{Uu!_ylHx(L;Glb1$t+b$iegA9keS&k{eOl2{-{ikoB63VxN6Ganh-KPS zA!Oq46|M(Zz1B~=2~MlPrISFxb0a=0_XDV2Eep$z^0qX8b2#DNJ$}wZ#bkS?j%&Ul zwQ~(XO^&l7J*zL`q&3Xkcuynd01pl-(2JKd@8uLu6W*U4Z2wnyy{mi_;obVD*-SQD zsLQox+oja#AxDr^65#VVsF6Q8Z)r8K6|Nlvb?XR@>f|JoGU-j>*nRjc4x@ zXsJ{B`#F7Rwr{-P%?`f7ncj%JGQ_GU(IQQG()Wf%r88wS{|_Dhc{B6u`#1?&RZe;F z#kWt0j%j9;U>-tYpx2=`LLM=V93#N)&jL)s3N~M1#`=neW1Gmj%)D9r&9Qs;R(3cu zWN%xOC_zoFw=k=JtUIl+n9yzKSb)9zOZ_bi2AuuK4wg+I=iw!*eo5!)L)){uW2rvp z;auiE#iIln@*XAHV#f;e=>q;e)iErTPjE1HJ|u+T?AgR@oZ6kRgBYtiHVZ6PTdL44 zXIO?@{fO=*a}?;$Q3-x!3!k9*?6!O(DxY@&|7D9Lh4#w|QQVjZ|h-h~C{Ozahyk zL#xogvL$NYvg?4wctwsH2ZcgBh)bWBGBT^y=@Zi}9v`2P7i;CxUTt0fg1F3W?&~~C zx1HI}>>U1rfJ@jYa?nBzfOW5D2^|%qMJv`tMve92ZCcP`$L+0RdKUgae7$3MW!uvC z-LX2hZ95&?R>$nv>Daby+qP}n>eyB%&+5I;Irl#I`##UNtn13P));fv9J8wazp8S$ zj4Z|Gp$B71L4#UodKy zjDev0Q*sUQ?3V9==k|>%w`mG*5p-jrf7XX5iL?o1(j-r;a|QWKxqzV|Y%*?+LCmH3 zAi!yNd8ns}^WDz~**aL#k=SJV3#IU15ilGSYx=OjS|DKwjCcsAT&f<~E^kv-Qn~V69H`KX z3Kgj*`v}@2_!dI?lK7pH(T^X;7vT*JEI3?FUy;dWS;}XGg5i1x2f^x1rrD^ow+2L0 z%X1ay8b;>OoZM1M69(e<+R}@+_8Ew0hc3eV(hH1a8*MIA1y97L^wD&1yBu_>t@%4{%~a*S zkW{C1jz{GQYn9tVcd2iFVJBzR!L!k_5~P#dZc6Gp&UL>UA$O0a&AjaFA0L+rv%cyy zoXHW$Rqg?M4RzMrn{0lDg8DvQ2{{jo?j;}ux4fC$KiE{L3zttpS@o+6hpwqF)MfSL zH8OD2j^{SDs@BdqYB=m3MwXb90en^;rslP4T&&(xL88lAE(}dMD0dl#lff9v$&LjQ^rsh1T zCVk_fJ`?Z2>;< z^j+V+2mEdY`$JXhNRA1<-_7rwE`S7UXe`z0c8r;gtAFcdSNrI4)eM~sZT2g-`69g# z%Tlb@W6HPUJbRO}EG#<-n(_ttSQdD(pp~ZK_sS+OuwZ#S3;dd?4|G_kdrl5(w?Sx? zt>*=V;RcD#*Z4NMP^<3KXwzU4<%@{pmK1OR)1 zMW`U;54jv5AxOMdS%MVqxAK4j%wxMWr!?c>#8tr%!HbA5z~_WZ&H#`^1A>E{I|%4} zp&Xci+)bQ8C*~|jisCKy_975>yck4-_W_G+p#?3Y*W2Fa?d3y3H(TPv$nu&doUzF; zj?>kS7=h>nbWj7YFRaE%TkhMtsMa%^B=Y!pZBfNsG^xMdX@Pv*yHKdOyJ`Us*XsSX z$9;gNONi}hAJS1+NEBuLoY;&_uM!hGv&4cO;rPr+2RhrziAidMaZ4S~*gK1qUld4a z--Ce$*C;&j)*Q)?OPhd1gs)CQ;&E$V_vyBRR4rRGG`zjEr&~N2Mzx!!7}n{OLXNt+ z;)n=@hTw>(Mwj%*c6$C?Y&~FUA1HCqD!f4=bY08h%#(WJT?ZPtJERlz4zR+|ded3! z${#a%MM)7osXJlKT|Oh47BTE{#0X`TtwE9iG;CUZHF}`$r1#oIczCY6E5JBNn=>wK z#5MKxr_8n=GYNq~W+54On^S$7pyr!76~QV+BHx~^NNlLCdw`zV81Q-a71Z`1<<9bC zWvkuD1#ymQJpYIvOF#)!U02LC--j)}u#5WsQJI@?OiYQWcKDTdMQ~t&NP$`P$anHC znck{l1U=6xym{0Ogn#Ua!IvwVpY`!W05W(ZCc_&%yQ3TK%3H_x{UDJ4klS(+xk;9* zAFAJWPb!Z#KpM_k?L&eHSj@4iWyngE=-7~9j{ayUQ08o*a!~%8 zL&u)bxNX6$@`%>4@AVI`3n)I%FD9PANivNwmK|zp6Z~%atqF?nlu}PbV?x+Rh=B(O ztk>6SA;@JzBB zNWR#vuBuj1g<$LfFo%#YFd>`)(ag;MylD(T#GqwzM4ns-9lxq416cBbKe4amfW0UR zNlhv@RL(c+#Ou_F&zHWs{lZ1jLBO9V6+I-faiQl4*;DCK^mwHt^{l?u*;zxh)MkP7 zhk!4-Mz8rDqk1hozKjNYD@s;~{8DeA+mlDTelrE5Tt(qNLp{Rn)>;cTsD9SC>whhH z?)1YtRQTX=Z^*?H&%!Jxnvc0n0T3u`;EvCQ8&ZcM;gmw!`X&j zY|W=kYe^Wp_t?mb>!^*e`MekB(E7$&D^A4+*MtLLtTPeE77tj?sJ9(N%)WjUUO64TE7&&QPB; zP~JYc*h3RSt0S4lA@+s>8d5nKKVlfOw+HXjo1$pc!Ely)s@H+@Eg4-S6qtLt~J48aXzAMO^ogF{2x*O1mBg%{Bm-RF&I zB;;TuQl&)-!2VkGU+FSOyk0|BeneMe^@Jz#j4vRy{tnaJ$3+C!TOJpy8xw3BoEf5( z2&EF)YQc}!L!V_QWH9h4fX0)_^GwNv7*UMZ3c*@tfCMK(aI|Zr$P)?!VQ?~WL&7~L z?#nVPCs?HIN-;9tqm(Me$m>8I8hPnqvJX5kkxja~_B9%MSothg4FaDA%9>N|hthI0 zXv~VI8a6i&T@~{6Qu_@`4Zcx;f_evjsqL`urp4~rCGfP*3rBn-KXAz`Yx|x0Eus@V zP-Kr7@pA9|Fv_dz~2|t@gR1-dqO{B9f_CZ zjOaj1yWyuFf*CA8vV+pg_P>#YBdJd~?i;^H)m0GD0?$H|!VQoEOA+meUZB3xL&}QI zaeK?~jPnh(D^E}P7Zw~8eEZm;y)r0zBF11Ei%x3?L&`1sQrq5cGi#l1a) zpElEZuUK7&tf^r`x}AP_aVah-w&ANx6f%}D7HuA<8UOLEu{{_Wk{(cOXbuPF--q|V zPjZH2K*L=%??wotm|fgRHpjLg;c~g?^kzD(hgj&}1`YzMONQNE-ZD zK(WTHsm8jXG|Z{NZ0xDIf(2a*%@{(QoRRJ z?Oc25nyIJBC4u4aXrh=L%ja6HI?Kekqi@9o=r30>m--TJ3!=+7Z_KE_??c{4uCFlG zEZ@Z|Yw_ci3fdXnP_G4QRg=`t=d(wG10ZyP>{Xwo5Za!c{k01YBFgNl#^v{+K0!!J&c6LB$X~c=`3ylZPF`eC?1( z{%^v`;ytGw`H_B?cS7}$Ib~sY&wid_5UFG$mL+g%9ea`8;O>4!Mb6wAr&b8Epx8x1 zn}8|ec!^Q4$Tn&=1C@nG`HuYuFt0Oa3_w8)I8C10R<<;_ONC|Qa5vKaovLA6J(m0O zXOJ`*z}ov@uJ4U0%?S@1*ynIX~vxcr!SXB$c2NB7Qz2|R>OVPE8wre@cQcS z1O*H43(~wQVMQp4GQqVxEAK{Zaize_6SfXchqN|^o$%#}+ zByt@`$3RU5G`>nhE@shAV8Vivv4C{6uTO?*i1twvEIPvyXFb*>$GVOpts&|`+7Ei{ zz4k>@t1pJzR%+qsrzJrplBs$%1}5H&Tk+%?8V)mlkPy*=gw19Zk$yKG{) zDe9)CeTt8tRwFIOM$@kac?vxQq_~I?VPSfdmA4Lfif~JMyPt=oi+-hN@LYo}>eReJ;aV|-kd3N55!a<{LnTXI@ajglJn#zyd*17s$w4L8q$ktFW! zn{y1rC#gRlTchm6jp=@e04Dr03v`{B=r_`k#{+6q24{3yuf$68;kVa=&Y$o_ z12SikpjhHPLe!%q_#$2Q#o@(`M9@_YbT3r`_NWt)jiY?o=Cr=5vZ=1ppXwx4#lu@3~m zb4ZN2m?Vv%+FF0_^Oh{Q)oj(bySE9n|L59(6S40{5*&YrEA=<)O zmgh@B18hx)qi_Kf4r}>_Qn9Q+r7AHu_eO?L4;`9SY!cf0AL;d>AW2ckV7GFEkgp94nutD^!#L*nC z6&F;Ee?j1s>h;zy6LH@Smu9Qr+&mGf@jg_MD_(IMGc@2Z1_4ecgJZS=q^_aiAiY+7 zU_#2{MDg3lLv?<^su7ULtU`px0vKS(ub=YBRHizIo3QU}mEr946f`m!cW5vC3_6>e z?-|sxD}B$xq>QpaXS)6&mcNdTN7?|XG)^}!18gXSsNEfv>%zh zK|cCH$WCSvNb6pU__J^lC2N@akI8t--NjmO=IqqxE{WTYxug}nRMYDO66g?idKrk43ztGzq1D;bt-nL7JdSfl2o0Ev&)E*bGL36jm!5Un2_cD zAA^J;3Jno(eZEp$I~N1VGEz+8==36%=l1s(>+s7}i#biIGJ;$%0TUjm%T-BIq9?*y zGLdNkLW^@u-D3E-Acb|%vkIS)(M_ZcG<7c@iGsqgIMKq;uwhz0y<)0!0ZCr^5+%~1 zKE&q7G~kIgX|Y^`hoz8}AIM>77NCNxtN@yKvqRFg+C=Nf-h#7>c3L-xe-L`12=vUu zUM+NU92lX64*fcGz;Bk%K*E9Gw_nZG2HZ2J^VYZRxXxT+sy9x!T*iegG;2pEDAnh7 zy`GUH1T=LJ@=f^t2J!WuPG{GST9A1^HJd2Dz9f#O?5xz?|0pc;Ye((U3noP+)`N>{TM7yiSm)LF`QH5fT$g(gGD;Bg>;;Or$C5IJew>9j6 zi)@a3L--o*tLZpf3MNW?*f-=FLVa@Utkqxw&ZFN;=YFztaLYF4KyimLZ)D1I59C$7 zL4a1#(7>v6AG%t(f*GCpF>ws|{hV@6M&|QtiB(0wA=D+7I7(FEPCXE%YH9WfV;0*S zTU9{~Bg*b)R0vIIcmAG}GiX11cmx^5mTxXN*fnqfz{WqbF%C$8)LJTZTvCm&t1#g= z&rTA{n(LJaYNClgkP~uK+Bi1epU%MC;*QFYB;0-M`3ZR>#k|o6fl90ZbXVq8#}Y0( z474^%B3da^ytrYPVnI}wQaa`lJ~S2aTkfHaJ|Y+xX3O|rNvFuRaL8;h;0mK6Uw1e$75Xms3tdlwMLA z_MlhIk9&`D0<)txl)+@e3?^iX+UAZIi#992F>VPX&Dc4h1YL7q7@0Ppq=0o&T#;{Wf zos1x}YVbNh_0-gDZKGA-)Sgq!ajO5CHFfTrIp3`Wk~GQQ+uiMgPH6Y1E2$ZrRbM-z zjGuA4e%G@S7VY?Z5k`=(?NAlSq*}w*^yJAHmkPf7dY#9iXbs|q__>w#9rim_bI zF=n%`_cKvaR*~)wy=kl;ST;&W1Dt@8a%x^5W8qoc;dS2OghKa1JFN(M0~|S79T52F zKn_Cq`^hxZV-0yCo{UQ+!AeS2`Jc2b?f56%sw^VOdp2jsuX&_MOAA5Q5ALM7nPjpH z%MPDrPWYBfbX)qsGN1=HWt0J)|8bsrE(m&niQ-F_ck+l3e+u5kCU|}UGwYqJONy7@ zxrNQOtPX{TddISWiON6bM*=S#+G&;uL@6HHN`#NY@&?^_mV=mZfs?u1+n>-1vl&InEk_Z0FP>>+cpTH*XNLhiPqBHRzx2 zqM-T~b^Z*tg2997jVws>07Zjy89X3RyCP;aq5B4TC|o^%$lO86_W&!ev6zt4hVzCB zZM7bW>#UTtby$xH`tI=xk&u|QHxMfLqe|D$ae>%|=Sns>Pf)T1UA5?Smw)sd&a_@dzdq`dfd4iZpd6_w?i31(#5hf_I7SoczyH=(h( z{(@oP0ABVwkSM3)=YR5qvMS6HPnVTLX8dlgb!7)NnXuqza4`rpn(P$ZELkt4tLs za)zLE80ZOcd$VUs{`)-r`>MH|GuUdV-*1#pjtmh!8B~<^1G~|YmgT6MW))&i%AO_B zBU5oxl{lCgc_CS69Coj$&}2kFlGSYJCJzav!m&T&8+ESydq}xk5;S%f+WF0Rqe$ek zAfQu77ItYlti_H->{@wG+ZDcmmjo1C!61?2D2wH6SLe)vGn&L(Sb_T{{V^{GlaEe` z_{(!N)G=WWv(8EAFM|Jgx;fZT_ej6qtx4uYRqVhhLt<$2$}}wK22cm$Z@%BeT!cCA zv-MbbBPRUx6^`qt8Odwz`j}FL#qQ$t@dP2qu9~zak;(F9h4}CvL=Mt>k_7Yc@NvWx zQ9I-MqH8lQvhumUWa=!=JQ@=YBQ)fWXj{1D==@?6AYvo@4XQR_xH~541n1e3wqsCw zW*(K4>%%{m5dBw#TQe4MEt`y8l8nx3@l(s_PW7dOknB2klcz-P55o|2Ha3fM;QRP{ z&vS$uBU+szjC3FBcbc#4I$b*h~} z^d^4CAK-OF$pj2BUUPcMzEvc+eFyj;xRJ-MWU9tP9zrJ#WI z4!uo2zik<)BKNh%xnEUB>_Zv2>|fK1Y?{=(8ZsQMl2a(s@=b3y6rV$it_=4t{BY2& z#a?E9+gB=0x_nc@+ZH-XO6!=-$F1oALOTi>6N6x05h%6z9^7}>Mozw-RLfOQQ z1RdjdQ3&%eW;>klH$e)tp#9PC!dh{v)mm0}O0BDH`8l+(p$bghcuz)2TQ*b@rC~qZ zo4Gos!l{^o(JJo^|I>n({pzhp2b!6np@8F;dRrF?+zB2Bj?mJPK=?ZUVTImB#ob#D z>vJ4zTYJ7vs+_J(nf;cXJzjj1I$1-PooLfW<(5f{-p(5hTW9pXtHUWfwX+W*1@>?F zCv#`>5s-e9;an*ezQBF;sq`9C&|*OrI3=wbM){^D$FQ@98gTh%tvUw4IBncKP^t zGZjoC^_@vvPA=w$z!Zw``yQ+8EUV!n?@csuEEj#DxA-;jOw;$6TTI9o^92*XCB9mr z{DvJG7&`J|%(oZd%Ty1zGn7+GG1Y#{?A^Eaj&0^CMz}p*gDLHF1((prX56yDrbSnZ zKkVb&6CbC3eGuyQdLm{~iGxyT$Gu5Ez=fnPY(4~evq;jVk@9V5lW1 z%c*Jecx-cWb6JOPpU28U{K`s89iN;$3QYWys;=QuYSejm*uK$h_0+s!IX&veMH3=o zX_QtNy-jxHaiciOnrY4QN?1v+f6C;#GctBjgEEfwL_A}Smc=e>0r7El|3=T*AG`(| z=ENa7%VKjL{bP%TEEb#bhE!2}VwMKC9y@H<)0A}8_2)3qpQB19yjC1}DXx>PFe?&4 z1a!A`Ce@|)NkM|+0PnjGY%f->&fQnhp-!jB?n$Yu1fD)@7FGmilP(|fi>WwUNbx_p zb?~n~XMDpH@g%jyc3Q;>Aemw_Sy>+z!;Lvg6$h*oWuS@>{!^9 zv>yly%=2in|YMDWZ%_++>JAw^>2u%e_5Sm?$<9 zjx`f0N&I@eC9Huk3fwq+aDW++kO#h?saUw@M(lD#H(02U*MIoP(A~iopuo`eS5<_=pFM1I^X zP{87aD~{TDjD=W~+?mkw3qO*WcY1em=L@J7-^H$(3vth6@sGnxV+P5|( zs2nSEh%mg!J=AlR3+6w&ktC1n{ErXC&koQ~6q5UkAn?m~UFeo@LkWpTIUM1j@0b|( z0eliKFllsWa&3z)J$XDKt@}9(7ML-)kxx$8D10eXRo0QYNUzrX%zsX_T(24lazkFA@8zv*dKyril|t4L$)J|{3cr`;Bf1nkcAL$4t6{8 z{2WHgvJUGGT&Hz8^iU3%9?A{Pye)K0R|$@|>IzMsUx_!)WH%VsRd&cApVk!VOH|%zA-q?8@3Y z;>=9y`Izr+cx7-|-khxavBk#X%aUI(i+Pn(#Db2C34&y?d6b+tEi*5h@k_rgcl0gK zH_9HZg>F6%`Wx=VQh@dy{NNH6o1TwCy&2295RG{Mg@r>!n>=+UlzPUj*B5q?Kf#4Cy4rDdE;q8{h&uh^ihGy7oj}MT{e019TJO&!EsVYLhUD!Cn2Vn z4jI&VLg48AtS{z@b{TP`nNFL!`yy){${bktIGO)?sPBrZX_h12TP!aLgGvuTX!&u7 z+qZQPh=EC^jQGHTTm{C{ng)h>O7A&NKiDbz^Mbb5deD`kI)Tu0*L!xE6g^LP+EKMB zo!5uILN27`&Ydyw5_J>_{)P~g={nmrPhHdHXo@6|jgS~-IP(A*v> z(&Wk2YwDEdmop6*v-XtoDVNC6(npSOWMg9jFfHoYcVEm1Tf8&Lil_ZZ zEYoDA+(&f8#%^c=qM-&-gkxjxLy6cGQoGUuoM*Z%bJ_}R#kbg>&eOom1>Hvtki{ z!bwIsb(qt9M3xd0f!5ID_#Xt-O8MUiD$O`pf%4|H$x-NioMngXPy~-tXnB&Xl3i8h z-Lh&`BcNUJIRaP=Zk|3+Nx{#baGB{kEV83?Omr~bF5{Y8R$YzwCeNHPN=+Ey!nRV6 z;XJH{=^2G)Qqm9)R%?YfXWFl2YZzEU&eK(3p_PGxI`Q)lN+qzrSytAuyvwiW*`W`j z$`i(@_}l{mJcJaaoW&L!vrX^U0;xLZVv5RSZde<|;@4Ka@%H>xiC!<{ZstB1j-&R6 zrWjXRiFOa|S_bJvMt;z1G@}K3{`k6Wqv6CH$tXi>r3;g%J)|}M;U+Z3fCcB)xF_ss za=hk_=Zgn#9uC_dmFJv(E`OrzbYYKKTl5ARSX%v^DA}nhH{zcEK+OFYZaG?G zAFmWEKKwUtiBdrXo5|T{WmBDAMCthbnTd(%{!v6j11k!bD<~A1JWb^SkYwN4+w)tk zH%U*FvoT=3iDg)0U9B>c7LQ0|;c09L)FwU{5{H!vt6xT5PAEHi`T8I>oQB?xHD4FH~?Z10l zy2UMWbV(^eecsQ5etnBwPa-sC5V~p{?Yn}O6rDGS%-PIDHJR`sk66!%1*e&1At?g< z>Yg!>8U)L!OQ{t981oE_JIXu?7w=Ho%*v*Q-3}LlTNlS0{NX+`Q*2ltI+Qw2#a(|c z2kEpZc^84Iub6Rjvs~jdR?wGD%2ddgW@I`YRfaOE`KTwpgY#^GnOGzii-u_1!6r~m zAgVmSx$IX`owm^3cIP#VWYT;uHZJM9O#r0yy1zFVZfk4n17@}tmd#5Zd}ad_-)(R9 zEeZVTqS@PODLBitKZ}OOE_I?&PtY?&9rV8D^`q%McqZ4{8&Y-tjuOH!1BbOui$J$d z%&(prx8GXLtYZjzLzPj^f8Yj28ZV z9Sb``2Vw|r87(^MX^^=Vf6Xgq9TxoY3d(RA{K=XWtX;3%`>onAE6!2 zrYCL4t8}-bJBgV!%0Cjlmz=NpNoO?wHA8ij9DakZo@V*^k0%_?o{Q zRc-f4NvMZ-dtqs1y6wnIjdMQEYbLO1Cr84n+CISgSfs-qy8!3!+YELx-qw#je@xx~{-b+T2v8+M&A2ZJ*-Wx94 z0Sg6v6>xEJ8HU+IO5rC*u5oq}>#0Bkx8rPuqnpwKc3ye5I0}IJ=)Gr71}QfABQGLQ zP|bM}>^Lb;IsRpMZkT^&6zDANah12y5VY05#zzPJQ}N1yKt#}(KL0xi$gu)WOiYUo zYRHUJazOoqO`@vPCI9o^cdE#Hkh9u9Q1rh1S--E25Wfdl1nxgB{eQxVzYfM8ZD}7c zVQ0IeyWIc9@%>M1iJ%9Bm<{n?m*XEFTE?LOVmKWi(DU{GmMs6mIRA*NqGhldAefk# z;07Em?NGM54(xXO5C0FYLs#=RfQ~`g2eYO5&&p>C0h-;9FINDC6L!GX))@%_K7Ipz zQ)0tK`@fhF{HI_$-c8)`-?N(ok;^8M-T<9&)`bvf{6Ao+10|4-!BU}1tL=aG_+J{Z z57fN}Fb%=!i{}9Ck3S^pKlI^$f8bC4%U9p~)%Snf^voULx|AF}AvVYS|9!z9qtccH zTzl=XWEg;D{QHal2^6I8Pm}lPGM@ce$b!&LUm(n%c3G!qXAc8daHs#H&i03L6e&Sz zRhRI4NkU@*>=~BbIw!XZZn>=7&f?u=VymH4>1?m>zwi8CKa}J7M+oJ$&NyR3M(E4M z<#Os-TwJV3%HVW_HgCiN^zAbKwLegV%yGS_udJ-)yS_48(&`5E%VMd=`C5-cBE>lp zR2Vfev81}RSLL?e@c+9H-z)*ZCUMUp5*4Ai+~44m47l4h3WX~(dCnuq+sh3C|0A^S zH#IZ}76wCpM~%@BkU9p!0D+b8|7_ZBhZX+`ojYCbIQln zR!CaDsdx)>k>r}2fXb3j^t`A20(3l5vLO?}zHwuIxb2DNeHBM~RZ~+t=7|dm0uN~! z84>TisRU7xKi>oiM5>t;eQd;!u#4|ttgtZhtxTVT5u($*4DM=Dvb!^;Wh!gddt(3e zk@FfRymzzJwU}}oj*#+33FUhU!^n%>^P~r2S5@1uQ{`SAvKdOyH7upH=)1}36bqwYsD(JFD!~2sT_fI2)-hfd%$|an!5nhJ&@(#>km+ww_cbvXbZBkIm`7Yb& z6l8izcyMhwv%MDWOky zQ+iG5S-yP@aU7_BKcM$Sz}gO)ry`)7Gs@*3`H0vkLF9P2E53?rW9Fd>^L+^4^u7*M zwiX>yQI)|SnNe@qPHkZmv-mYxZ$i6+q-p(2DV^Zx;XK#H@xu@qrxD<=HG}BLe6BN- z5Ow~HMMU4(Lx9H~=X`%gzJBqN`mr=cN~q(_y>QL$a{n8+`{rSBaxSPFF8C8C>{x40 zw-tFS%Kp~egOL`6(eA~R07zkV*$y&tG?5s)SpqCED+Lz=ZZU7gZDU}1KI~+LkZKH01;ov)&p`YQMU6)bW)EYj+?Y97trJhmM z1eb6x6Ie9u@8zN0z0k?vn0BDZfJ7YDwpCP5o}tbmS?gw=ms9@Rs%>(U}JsMc7w%PN)PX=GEgfHHM z6~wq_$5D-3N(kp`i8d6FBwS1lB|xFi8Wzu%sg0kL{e zLwH0lKu7eO;YI3}0+UE^K!2p7!yNCk6W-Z%_ZEDahOlGcLslBj>~(ollXisc9r3c+ z1At!76^~CNBO}b=D!M0uM|9Fz*w=*G;8_|pK~zBEZHl6L0|>A9 z;9Nq!ax&$<$8h?=Ic{J=zzc@)4<;(h2B_lBik#LqP965-9?(lCVAjN*vJAz#+3$qE zqdaQ^V=Q~{nPnZJuqnk7eM>G8IHz-vleTvsN*CnfeWS% z{QVFl1hIb*l#w0M-^czj&z~2Hxo#;+$Zd$A{i~bAir#K5=6B(gK!`cHnFJN=>{c!y zJdzp&V5sQpNs2_1`qMjc9S)WFTzceV}8&5o@u%I=A z6dR#aVR#U-HY77e%wIw`&q{eM)HF5qPWwP9j;r`a77X_s$N+AO2V8AJ+w<4S+mX^~ z{Ju2X=%J5{S{mG6ieEFKja=2(gnq(>-0AHeW{BnnjV#m9y&$ByX>0P+Z+Ucj(`TGx z+1}QHd1T!TkA7x|Y=fh|?vMqkQD3`!HrrJ@qUGgVTnp|DKd*nDv!0j+()qi`z{hYx zbWhW;#tj$Q30nL*h+4IYyC;8wl#RbGKF=;C*#oKLRjXhYa1tB{vrH?w5>yEFsKuhp z$_My1h_(*dQQtkjOorrfO~HIB3;!i~-f}R3oCMxNf>203&HWa~CI=*IEp~Qm5y+K~ zYO`)>7CJ?%a0EFbg+?8!6{zBN8S`6XRCsYz)T5M(8XH+@N+uGt6hHk*QWN8^0p%aQ zvLx3&N7c1PNIc&u2G>K&SK5sb!C|oqUOExNJL=cm6&)GTT0e5Ff(MyDVu0C73vDt9x#GK)vgjVd0FQAb!5kvH9mT(yb znUB$<{R(FjHDBX*?I3R6YiQCivg6co`Gsrgd4x*oC6$XH(3t4OGv_!KzUc*7=hyLS zPq@^bXC&Y#QZ?;onmU9@_g%JE^KVNs<@+PEPgH@UqlTs+r$rZ>gHVXW1QDCtB0+0) zDM%HX?g;^R53Tv_Q*g!v2$V8DTPYF_mexA|@=vL+1-@AYqo5ocO5~Fjk~XKK#VilZ zJR_mWfjUj<#$Rp{4gGxUmn2xirc?b_5dv$ahFhU6^AIRqZ%Yd<1*eWr>u+9><1sCc z8ZujI)kE-=n1qX?dA^*A1{88x6r!KMkt&1`w%oQd!xRZg7htHBe%t08;6xo2@1C~F zcVrO+xJbU!8Z#Ac2J9cv?YcPOunj#Emd0e|jet*I;obLfzH#7Ca7MlVt!6qH0>l5* z^m>~^r|uG)l-t&;7)Ox4!}+@WX3p5RiunEPT<;eXBGouhiNdn}wNL&%YO97z#Lu37 zVmzkOUe@ktAlZxc0#)*egW-Lb{FDJw#Mr#2QQ=Cu%%d7Zr z5@!^Boz$#AnhT@t&ZIz^*qOblI#>w@W5Ax9c3p5Pe1}AK5-iuoypmBz#B`?Ug2Tf? zoEIlX!uKO);y5Vbo+6|aYG*;;eyR%QKF3zEnn-6IMnzhDpnq=&7>Bba=P6`xi7dEl zFMuYM98u6$FD5j;MWf4J^(EY z0SZ{GX#P_vQLc(z3J&pP*)x}&HBiN)yW@(kG&fB6aYQ*nJt8*r7AvmBf}0H`ko?M` z8sUXzS4><>{Yi1_+!;O50@=}|Vyc-J=_D=zkUanLY&rRT97QJs(7(qBK1w$rODs-T z+7AOH&R#9VtA8q-Zc92bA~t|wBK7mIy0|@EzVVGO!TPcu2;7H1^11tPWq)n!%hJW5 z$W+ckZos=Y%?7aJ-Guv-z6oDiIPc$HeyprgkwTY-8*NMou!(@$*S+ z55pnqF6|kG)mK%DRNm1uvVVOh#?(cFw^tF|+84BQa>BUmPDx7W5NWMAzVIwl)>$fJ z-}xnN@b!s32DKH`cXiv~j3!y<5%Qg&{P}g3JrD=bL|O-CHHaa?(CoyffR-obW8{ z?LD<4BE>^LwSd?b#>(mwBe9!du#S&$N#}$^t<0n#@OY!a!56;u^ZfWt&WPGt(4K@# za~^EEl|H`zURjQU(hhIoPcB~RcDCt4v-&_emO#z0bKr&a+_K+u*?5iCjP(R4T5-hc z2k}m5I2!8g09Hft^E9#{bWvmdxH%GT1Havs3@S>TVQY6gcNEqzhN ziU(pApEpsN5tzGo#ocd^J1w{89jLI|%R|2e`m2bg`L80Dv>eq>_?V^{qK*$q-eWt^ zmYC29e-b50FL*Dn|Gakk>frqRWH8?`db%chxuLegXe0o;8$BL;&Y(aK+xqTp{4ZVkR?v85J$nERmMzqJ1pKxNU!U zXKEchw9?7I58i3oIQw5=2f%v2ASii|=kFnz$)n=>KJY|QP*VC!y5dqbf>r5u1eBdE z&wBIUo#kE_79+2Z;ogWyh(DzGH_zku&kH&J423vSrg4woVxl@ewTJIJZ2)nxNNP?H zkK3lK!fy3*95>)YKK=phfDD<26_P4P3eI!G~XfGLw7CY-CZgh?RcZdQYho`RBw}?2h^??Oxgt1_n;9N31#AN5z)m$-Q zHn~qQyGFms2xuUf!5SIw-OFkq#5iSGCl6)hlY9+ZRR=}&ywxGrlHV0?0`@n?7$3GP zLN-mKRbPeecX2+gUC5SqeV{mu2he|&klv}kWZ}iA3Z{>P`OIOQZoi63DuBc#ez*NN z;O*e#1+9jA?71x6gT?MFtfn!4MM7UqQC!kEgM5*;(Uy}|H!%x_2>L3zl%=&{QR-(T zL~91SI6GJ8wvo47Ecg1-e}}H5AflVZtjk~U&A|N$5@p~h#+-{bG&d(Flqs|xaO7^I ziJUABVLcA8NVb4xqjmXGY%WLqat*nCW6oMljnYfz5|Adp+p&@(B8X6y%e-L%9$?=G z$?7?Y1mIRWY{q1uEHX9H*0z*Yp{?1fsXKcTjO7k9hfcyfuV5iM8NQpI)AOvgP+mh7 zis4#u_xI-YP`ioV=qCxKv}x>sTt-7W|D;(=>?w1~atRm-dZF-=BoZ7?Vu+zG_%4tp zwH9v!UVgE+m4hXM9K|3NBLap!iE0`P2tCB>{J4zwIcGbzKsoQgY>03~y|d37GfAuf z%akW?_#SIj+T~ovFU?{R%|dj(&3|WF0QkD+T6W^kG*KUG2i5)?tqLwAA<;OyQyi2- zBZHyeUOzg;L!y6}1nYL825U3kyFO^)ckoWCL@~7B9wL4@nCj&kb*1RG$NL5aQ`kIs z%hIbi#6=_MfqFa?iG80VD601GE}S857!_}ckok^RNdA8~dk5&smY@xE;$&jmHYe6h zY}>Z&WMUf=PMl0^+qSKVZND?u_y6y|-dk_2v)1g)IeT|^Rdsdu_wA~Z=C}Le$IZms zt`Bvqx`-TUGx#eF5_NAI!!=L9S)6j>)b%vf5JBlcwWMZMUd0a%n1lkW+zeb@K7ArJ zMtR+fAOs-5nrSCgm zbm>RE9DuYlt~J=XxLgj{xpP_lm5t0bXB6^l>3NEdDA$I#fYUq=>|9^yV`3b>KAn9O zhc;U(+%P1e!s}P)QDe`8z=m)l@;kzMJaOzguU45^-r={TZq-+Yy(9KQ5Zejac$FI* zx;tCFPix#h5FV0H=7q*4{5yq3(7qVMyy^A zRzJm0Xxl&R&D9J>WQ1+?ByaKAgK=8%)p5d_JiE`X%YUY2K{+a8*y(%kYfX^|3C*@SP2K8s zqn9cBw1k70m=Imz;&!;Ggt(CAj2X3FoxzZmw5GcSBlsMdeP5uCjuH;yqf>ru#LV%v zLGt@GWG#1a#_N7;j00)T#v2O#DZKv~JAFUCmI)xU&cH1A@;_-ntoxnH=!mUnsS)ex z57iC>$0c4d&GszXnM{%m6xqE+JHi&c=DMGNvQSSuD|o(ae#Te%{u#DphbXosAfh#m z&G9HnVP1J0{&06Y?LOdg4fH%rZP?lA!~O2K$>IiCe-a zEK&j>CGk5lSmMRSn2Y;52|*=6gv!)S&O`S?Yqn4^1KMinx;M_>W4kOm*{;+qC&@xr zufV!jS+E4hvYf3DF0h2wPgKW*5^`SIi9uTaU~a@ph=T@k|F=gXi&m}ZTS zIOu*>7i@O6UZxx1|EOM&m!l%qO<{jM00DC7A!jQr9JJmpDk0HRWiY^Cr@!+=6d!do znJr*zXV-PIR3jyB!xAfZW?tPSKm;qH!34L|tfF{RUmmr6a@&hpcFih+bp$^}Q>Pwz zY^Y(n$sbvlKX<*+S@B+i_s;DJ#vxSxpmMllTT0yv6U^gEdu-$CdULSi%tAGd_oLwc zhq-$0&aP-&i}q2(tq46&p7z>_^&z|xWn9BaS4=0zMe@mPY;nsC#WWFc)B>3(_|gh| zY(MSTSl+kS=(}VW4+m!npVf7N6Q#PeX?%2g?Ers&5E>eqysUN*6ua)jznQ*n=cGfr zPl-u4!GYg0{p9Nl@n)!GbDL8$u}e=rmy9+~6dzic=Y2I4k{FRJR*|wo!IHSUyXt1y zk^02eW^Fb%C*CYGQxlgN*LC9S^bS=jOsKmZdjfT6EMj|{?)Pk~tPYcVD8$1on&^YW%WR3XotwQ4^z2u0 z$z@ErD>L`1a$GtJ5pgm64=TY_y*7+WS5w4o>~|1YrA3sA+9C_`x!WYiC)bIsM#*af zr878<>WwFd;>j6*)$Fk6++`eI`{;b^2lM$XDSL3s*Piuk`G10!Ne z0g-{~uUI;hpSNO6KSXM{tc>+4o&nbLs`Oe{Y<|#7O`m@Dyg7kqWof5LMy@&7n4`a~jYINPyjzYN= z1Q$%A8n}gl0g-9d;u7R98Z#LPaF36V02M0Khj&&b2##X8VnQg1VOV(J3ScMX?J0*N z9|5Y0w|6V5$$zbIuxFTBXwceoAS1KAN2(MNd?Jl_Jfgs>-~UDN>|e3Sr=kYAJrRBNKH-$s z9gHD_goi(O{jB*V8Nu~>CpzC==R9t@NtVnu8M)G-8}wcGX>AYZ;o{sCn9XKAAt^qb zbhH{79|K_oc=f>H^7ZL9-rwyXWE3!vUQh7u2uiu!ufmgkB8J7WjpZ_2St!@VrC>0{mJFEU0 z$ZrH(EKuwJkAU%Qp`E~g6N|2)YRUgER35n8#5u7w;lHF#PkI5UhH^ih_#-o%^wg#l_Z7wp3O9U%OZ2%T&K)zs43+S!?D3bZ$q{GN;?TddetySI9BMsNXe z>&_ydG=mX=TYE<#aiaA9=CJ-0-Y?459m0>-3nrXBqVF~;_xMQ}t6<^Q$pQ8+!Tk1H zetIAS_^bZy8?=5uaHvW<+gH<+aBn)CVNiEYKacaa1zqIGKFm?aWT6YBnwHX@^Msx@ z+b!U`^Nr}IC-)jSF>cwXnAH0iLV?lYfzTD1O?M%%D+T$r$a|1YFsSEu z2h@q+=l%Mmcd}RosH@ZiD4UvR2qG`Zh>g=ryWs!F6TF(myEzIL9Atco3 zd`(uq(MY=1(R+WzYx04pbz#Ka2wzGUPe9 zoX9UQFfgGcJG(1j)x`w~!0>;6pELS)z{U*%fQZW=AX$cj=%m`#&=ZXt)CMdS&D^v%3lQ2e#O*g&vxZ zl1dc7JihT4BA8l8GQQ&JJ$V%>V2uYd_^n9$;$PW#pgWp_%noPCIp_1?xfMOOH7QUx zg?}{2bdfW;&Svtn{$&|(zV%0ZSXH0(T(_tEtP=G9q!gipmkH)FO|ubeosN|ku_t%s z(BHnA;s?&DuGm4q zil-J~wT}Ntg}7BbAjS1`c06k6VYaI|>q}yT-C}%Q1ZhI7T zwnL*)vEE>XWIw3L%sFDghKu@q-!ow1-Y5bOpYwITBKs^fyIG$D!Wq&`TTknxr(Owv zoL^3V55>5TW)8WX@@mTI9)I*laAyQc=Jo2^yta0-W5Qe6@lPx9(bHc^eAumfM!e;d z8UjfwBqVeWa?_mU+ZkCSzjXD5Z$4uzchc}18f>dYmvM^a9<|Jz^{J41KiurSs_hBM zV62C#gyMC2ykGR{1qbTDf%c|i1;QZL18xiXje5-3`;&T{FS3CE-$mRFWL?rzfbOu(t?!{3BPGzL3=8ZDsYx2TYOrx zEFq*Sb?LDFrWh}x6v7s0OF;o=Vjf!Ck7jA4N0; zNnu5D0PK5K8#7R4mHYdH%cwEN=%UGq@ZGnNI6?oAFbWAhDvf$e)Q^|@D&n`$Rw1JG zG-4#)q$9Ni#Ho}T&T(E02K_WHKi|{u$35EaoA1XnzHu1@oo|hEoU3JCr%!O)Yh`+j zyYY1M@|T8PL-xeIUJa(kw%ec51cY{d!6fM>;_cKsHDg7j76~HMZ+8kZ@ z-UwwFiEAY`c?Er)^>m$~aU74?BD~sAYuQku{YIY*nP7GU*&lY&Hn2x2qj_|Anu3F9 zeAqF*leF2IL?p1)D}%AH#0@^nj`7$~ zcM-g@)fuaBAtfV7NJ22k1r8h5_7!Q}g27alDf6K5gAU!=ro2QviHd2Vt*#t?Yx@-- z#D$k3E&M|TQ?{#jh^kNhNtfKCea2#=sH9|PYP3jh_1=0djJu2~J^WD#qSv6QyS+SE zyl5vZD6jy2PtBI^V}yRIaFMM9jHd}&f8Fc^aYmJ)NC|LPg@f?XSwWW1VuMx*7aQUh`o-ZK3L76FQ#<~w7?DEchJOW#?#kkm_2Rrm4?}IeUc=O?h&cKx0bwqZk0VT}RiaoH#blKCPNnoE z|2xx9Ox945i>g2oE}9i9-oi8|+{jQ&v(r3$9}Tv??$hv%(Z_B0Qh|;BpY3!+2Ajde z&dZzMqten8vAPod5hyt4EoLC_2UAv>_dz$mPguIWwVGgxuW?EDMhU1{aj$EF7>N3U zexw7!3eh}kF-(vA7Rk%gptt@cDoA@q)Nw?z^FiNsEA@$^JAJ)whu)Rh96yJ6KYKQ3 z>wwKBIq#dTo(#-eh{SjiEtH0`OmD4^#*n}vZz-VS#tcMVXY%kQN(XL+27LFPn1!vT zH|3+9u|>q8Dujhh%k}n|eeU^U1aH2tPxM4Kc0EmFHOwiw)jX1@JbJZY_B>M(~+(sHys4 z0G3?%yr=$C+aCf`T8r&*1py%o8=ub*l-mxZQx}BR&+koJPPF;-bWRU$c;q_G-;UweDHp zzD)7x8>RX|_`_l<0`N)Jk<#4t?50QLEU66cR$?fWJ4(;owceUaHlIl#Tm-ECOh94;5}3-xW>m7)bn2ifJtKDp(sE=ZaCQAoTduSnh-k~& zS>IDcc<3`YZ&Z?-?Matohl_{=ZcaF;*j+xLot&@1)Zk*;c;1wFP)VmpfPNVU(uaK3 z_keVMi}ww1;F5D(MOG!)lM1y9iAWFkCHIN-I81CTbmWobxX2hyD-O4Ldx4l(7;Zam zvoYJe*W$WZI9q!FY`!a>J3FT56-%)d@UI2dyE(S(TqV$NtkJSB8IGS2hlM?9VZ1-5 z+!#Fk2xIrWByt}2`2f;>|++ z2rM0CL|ZgJ&UV(Mp8MQp5*MO9zCG#D+UM;W(e>G|Cn=ajwi8O#TZDe|bddSBP?$F1 zRg#I0CiE!J=CnX~ECJR*$=#~;lM_~|b(HW+rMf!VwZCs>2YOP+3U*yS#1{c=!HUl_ zcG{S!FXsd2l*5}O4G`POhYuv(q*fapb_WFTD~@gg{Iq7N>vfa`8cJ-yLbV(9FO$!~ zDBQGW>(e5XT~?DF=oj^t?WNX7+X-#tg44U7!jzUHlSoPF#VF}}2WX~u%N{$rOtEO# zIJ5n$j5{$LH9J7E?jR{IY#K|jml60pTadIVSEkD45abo&5K*1b@Y>&sbVw04hG7St zFqefSP`gF&d8~!z6a7nuj2JG~Om9;0g6??u_*Z|vUDQ!gWYq7WTfP+I0q5b5pJ|7e z_n;Fxn&;i|gio8fm*9#xj(%9IuE?(jm z)9DZ<(Ml?+;@cjhySGqpyP21aP-}xB-zMkJ;IzzmJ(eaW->1}o;wA$^8q5NHx$O0z z*I!&oyYx=Od)Vs0-|AC=PrJX5^@#MQ7T#_raGH4h5Hxz^8{{#unF|ukprYT8|Bk7z zz;B<9A%9oiyAk?2IVn{!4On+wI?QZZ%CT z;VJ!kEEa|(^U+i*%Vi3Z*B?*TwA#_lO)`kb(2ePgV;~bT~pK zB>9jIgLhN2WqFH#kVqZ{r7H4{#fK2c>=Plj;Qw@cb~#Wb?)t&*Dzvxas^>xrv-u9P zg5=&WUrxdJy7h589x~2j(D&)*K13bNW7UEQ;lsYpWgmLWF7GvgET<$h@sTqg37)g6 zNKcS>GIn{u?ArU~86>40n8iX^RarTPJ66(XCq5A`XXc4%qrB|xVesK-Up7HzL0}SF zY=li0PUwuHvnA-`j-y3NlQiwxM$IX>fh9`9pnypaxv4K5IH^Ou2_@pj+ko)>XPhU= z4Sgj6lM-UQT~;8YUAgDLi1Ec$cBR`9Xr;+UC)!@2`<|&e1%!F0oJ6dQGo@fZSL3&j zCnvNXX9+mv`S(~{@HSEBuwK;HQJ=!p5(OTVPA?~=?ycsluOEsu59L$trpR53l%O@a z$(f6C?mJsd3E*%!{dyltL?v%K=W6y5TyCktQ0X&;PIn2HsZp47_x0pd@ms6&cvBTw z!erU_!x^kYER_+Ei8rdGQ)=0f=xk2+%{MX}NMVdi2?w z4-GJjJGTY+zH3$PebH62bLF@mYY0;eQre?|2mUE=TCsC1O{I^MSqKA+K?1PS1<+v@ zH#l4(o&E_3Dg!Y?h?o0gf+-ak`0bD3RcbEFkA#ev>+45&xnNYv#SsKfeI+j}tk#zT zN*?40ZMI3T)D&3LNb#9&z}FqiU)8Vqx*rHli{YZ}Xtii@|CREX+a?*gIrH$ezauyf^FSJ%Xa> z=7_qU{s|7&B4HXvlI`PKDt_bKEP}M!m>nG(H_cPJqd&iS(tM_=>KII%#_I3gRM;X=i9o{D^*JYC3pnI&>Mw)Xl`XG%U% zAzb(~lfuRQn1vAzY;#}-GwoZyl|W-sH=mo#X8&43vW^i894fW;sF-H+3q(+;ooVN` zX`U%I5xK4%c@>y3g=&EuI!%PMi1;cgPPDq8g2K~g6Gsb)(ye__Yv@SpWnI0Rl{oNr z`?1MmAocmm!8(>yrZ)w?BAms%RaaJrM4CeRNKctqQc^zQP$9{g*Dhu&`D>|{D`-IDag#*%>IwDg!*X8(x z!dY4TG+=9GAL*;Z1A`CGy?i03iNS}{y!Lra{N>>EksTo`Y<3ak!G2Snd!~q~m1;o{ z;u|57N-f%Qt(iZ#5Zu;?)4(PzII2st1*NvD;SJ5`=_`e>P?U(xxBR%c9}5WK9qWtX z-toelOXF4u^0S`F9y{gYd)ESM{kWAbA~@zei^7g&(E=qMy;Ug3np7s!VBgip7!)g% zpl{8;MG8>8&7LXgbEF1jPdE$5$KgRM?jlP>T{T3@fzHDkaNuhR;!*DFAEY zbZ|xE4IL0PFHq)wHN*f1B>g10&?B!6e5BIQreesaY(UZj*tR!-05+fYZRn>NO3WoU zOmteI0w;&BDeq6v)i8eJm_SCRP0puSv&Sc=UW%#1@u-ETpB;7C-~fa2eT1&w?Kxq5zctnAm8s-VC!2GJ29g*!`2**g?a%xKQ$XJq3|m_TJ~i!5 zVxw>Sq8t`uu^G&GK(WtD38v#tO`H*MSRuAuyP8D!DtAl{RKulzR<3%lq#NtFBcXTC zZ8S9S0V;;yn^^aHv7*>Tr}x7c{;i@wc=HewY@Wa(CJT)QP9HT(!V>BArSts}(@Z@c z?~@VQPd=O+D@RSz7mxrR`;NTe99rfV91mXZ-bv2-OGSAUkC&nu_$+z9gq4gX3tV*FGOXg~yqD$%e9MS4eWVqQ zM&YYnAU|Mhpbi@eTFvL|pamz`Yu!2|Cbcwac-Y84O}h~+lYek+7=ss5=eU1iJT|x3 zz3QovF!ITkgSTi#t3ZlcEZ8a{ZNRN>eoA6J$ZqI)$Md}U%;#99q{*Jxy|S{`J{2=D zI%9_m9?JGr-DHj3ao(h!^N0MKOI=^M(*}Q;{F>2>V=hjR7~tH(3B>lEDLZM$zM#W% z@cf{fbrWgVU#S+?n?O|n7G5Hl3;hW%h2Hb1i}hhkE`{SeZgY^*6q6$sBmd9z-c`j4 zr$esiBH8RO2OAxH2{se?`T1QlGvocZcT6U|W*!K)mU?v%vFcRLrk?1okNMkeeFjsi z)9A2qz*~T1MS>LV%0_MGJ7c%Z7p~9c6kL5YG@iZOqpp(PNAcKxfzR^vwAMJ zqK%5{j`}B;FOWn0uIsmw=cEvAnk*DI*q%phM-vmfD$n77h`9`8k2x9cee)c#!Ut^z zu-7eGf$e><@;wQWuI5d2Jl~71y4K301;P{>&(*qGQzf-s^KK(6Y|?wo zACyb>m>?!j3M4rfcCKuUdGtPf>J17o!ccd%M4lhfT~9$r)w1 zyk_RMX2A(HLgP}wbo3$rC?h4FV5G7>|9I0MVm5+@oOq)2lh>0VjkUw3ytfiPY8KZB zF$NKG_UPy>%Bqzs8uvJ?GssoMF(c10QDx>>wDkznDe+2~+a_;q;T(j7`@Q|H-+*t2 zOk6ks}cJ`J0( z{`3WnrBlz2PK!Tl6p~SWyx8>1Ef;986KXoBj*gCJ)h(oW5=}8BkJ+Lwx0?)>cZ76b z!9nxGt1SpjF`yDl5R@FRWzg1FQ8<>$M?Qv$zWJrt(#QJ^wju<>9X!(w>7!{xTE1SUj&;4qy z70>FErvZ~{RcN!KY0d7uvM%Lzgs*xa`ixtSGmnnWvX}&vO}4$|h8*CCE)zdb?VMDwPifkoyxMrspG}MH)Auv7 zO0}st?ZsUcIA6X#yW-r#G}HOxLOF@v;bgY!DIoo&8uBYJh*tAZv(d+DeI#3Spu&Ah z7o{&8fG#u%eP6%M0;I~VzsL4IXg?{SWNOL>-irfx*bh*vpFvFtn*BMSoz2Z%UD@Ro z6!e(ZYD1RIm=o=aoQ~(EuNfHkLEqHbv3bO`J10V~Wh*X}6eXjRmy{_Nv(!ID4x^XHI| zkilDb)z5d3FlxHqb7d{)??y7%NkqT>_V+vfxG%!@Rm+Q+y3g^C2mSG-AFxd4lmzcb z&mQ~55B5WZ{AlDrNE9)E0a3-Q3FiYe`A0_p7X?%4ulQap!Q9$T!~VEb_NqZ zzzTjN(g*+dbN}o>V;ht$e9lUX&l2Z9e&DAesr&x++Mo)eECc-L&!0%8bQMfA`xP+W zUm((nz8=Xh!T$AW4CV(U*jytHk^iGN1n5wYr@_hDHGi%I-h-nVwds zef9Il-0Rd2&qNiWTouu;Tj?^|h1Gmlsg2i9i}>S@yG~Tk#J|3xuX%Gl$PP}2)}{Kh zVg7QY?|y?o>(*<{9HM%T+DNi&@h9P}BxkL3cfk(4ZW+UGgBIK4#|A#^`|%6KC(*5B zXRW*{Pdk8@F#sG%;-9i3Q2Eu{^6h-v|L*PJJ3!vU?_Pqi|C0A#vIpEh$)8Z-N}2xW z6aV_^w~H%2fY7dd@Z|*lkLN4>G8!uFj{x2N(`RrN)>Q%VG9Zd#xdTD(tyUwUdwW56F^xQ5N4Cx&(sHXi!a@dCMZ)!DJGpzk*09wRMyi=d4kVq4 zoXcLZC?h#{-Zs-y3ex8YpGf-&azrswg$DF=i##-v)sC4ZvY1VxjBhS4E-KSL@$leM zS#|mXInUTcjh0r}&~>F?gVJeI0B>~D#>T{a-CN-6UDoLka9t*ymEwuG8WLltt_l9q z;?f~UFcaezkyWt_e)?qu!@f}eJ!tQtMUtJ9V%+qhpSQ#!rfMmFo1--| zz{HwXv&mkV>Zrl3s%R&nSLntDUi~tQmfF$5Q7U$fcVd1_e6vLMK3PNtyyr2T?KjvQ z^^l@Qfp!O-gN#O`Si?oSlVBQ`o~{qQnS@`0`8mt`iSp&O3>K(a|MK$kV5OnL`{1ih z_s=OUM(%!A3v$6s4Zoj84|P?f2HfS^r!ZfDjk^bC0u0FgY*;m@DsBLk9x~ zwrM5qQDiycW~R0(h}MstDX50WT6tbYD%AKV*cGW(={xgLjZK{pnM9^wp_&{XJIGy= z9GhE)aO{^t&IIt!A(7j?ZDd^niXxl3-P^I;;fE&yY02ddBBWn6LYK&E4_xi>8HFa= z_zt&Y(FTnrH@UN=%djJ4GCtIO6Ub(^rQCV`W>1F|PtrC)Ju+&9x7>OBQAH-DNhY(!(!1dTYs+ z|3r8jsmk6EgXm|889CJ|63E84Ks#CwOH;*qNnmRKb>#W*Y?n_t@R(9E z(m!;Opc?%?RN%Xe-}b=v1QPx2_XuPl0qcR#XdtsU&|Fx4CSZfZPkGuI0PUfFA(Ecz zVDLLdARIv>P`@?VZk4iZ_Q{lszu)iMc?>{yOk zI-Wj2uSYBg9}K!t)S0qBjVXYC$98&HaQ(` zq?eopgYGQ~3tqkYs9r=yH^Le=Xn`a<1$8@WDNWp@B6HZ3r=Y_DAVA}vm^xvwC0OS=#iF~*`dG*P>X$it}b0_#M{ zUn^TcWb4#Pld)20LcnFTeLoQ!!Z-t1n`QJNX}Lo-83D&H>5o!o>-wKKeH^1zzZq|K z=?Z|O!dM57F&!7V@UCc#2ut9tgM+%hHZqsvH+0DwA^)YfGg;uIjj8j=JCoui-fE$t z?|M9yH90BbVZepP^l==lTdDvYJk~)g-iQ?qNGy5J_9WW1CfsdkNy28VH)U?bmdG18 z3|}kwuo^;q_XivEodQ%>&@H)K_A4h&>h!dxvwR+nibZC2mYcCZ9T)L*dBgLuOl|Nc z)GMCwcT04|oy1F3Mx#&8_)$W^{XdBma*c-z+J{#aux+F=f(p`d5&24!l8WZGRKTTr zum>-JX3bY26X);*^}*!TCBrnM@W$qX+N*;{TBTEXPHX4w6Zf3$&BbPJ%BAwNBCJ8f zOs~EEU?s%XDJeyvto`5Gd>f3ejR?T(hS!M=`c@|3f3Xrq=KqtGFpik)Qf1bK;Vj?q zlko`H9bP$)Sl)MTv^EuZxi}Sf&9@Y35&kSHB_^ymtLFOflP>PsMJl=lqXuug?}= z*b!itN05px+(ZW#i&U%%G7!*%&%xR3zvnSMvwu?}MAj1o1dMkwyoRQ01HXHITMe*oSX ztqp4FYGvClroWMSQ`S_*yV%{&qlm;{SY>Vl&K{CYaNt&NiV&A+fbaJY`ls)Y{v|V^ z&4u_eiJ@7~*gv5^y6d~?^02FlIZ5Z5rLP74y!@kw*X)QjXg%tZpx`iFYvxFTaGHCS za7-;Z@awA8xK&pOcs0&UVS_7eXeTvp6!kv@FzHG&3LDg0Yrwd2?{+*b-@I*=gOV&3 z%0IV_udj>b7jvuGE#nD7IPYA%y@o8|`)3&%oI@EHHY-*HO_E1wwYXzeRTWlQ?6n*; zaTBRac+)m`lVIsDc+mn+bFYPl$VDMzFw6OXmnZ>NzbQb%ciQ6agg?FB-FOz_x|b zatZ6YCLc(2!+BUWCN2W6KAtf*nZ#r7Tczy=mf-AR2xpDb=ecucL1SuK&B=EP0nO2< zvLfX|uvETDI2Siup-LYt`8cH5AI4+(ZrRrgI(i2e4j8;IRWzR#*!#!8Kp18FZ|O_Y zh_p$~r8&zIYDlAv7*1LQItRxwW}D$gc?iI`B87Gvc3^E-M-W7!L03gPonfw@2yL&s zZhIoNB<23Gi{6BCZJY%5aEq|J>vm7Sx{dxJ4u9P4p3?w(Y&X2XM-`2yEc4{9`uJ2e zrLxt1Md@?7EyS4Ic;>?wgA0HV4|;|)5bvk%Q_ODRf%w)B-xx^Ex<`mrb0d-JT5$g;p zp7NG1mC_lt1LvyIc-CD@2dFn#O9#Z_l8ik7*E$@Dun z_QQ`1u)I+}1*|NGP zwEAWt?`Laol@z7m(bts8SMt?SAbEP)9!?UzRGT5E)|n^LKGFcV?th%{e_d~C|2o|! zljrXt`hEXSASfufD`!M z@Im+b@0IvZB;~iRS2VdWfG5%GoDl?0xk>qY#V+(_EDXHaj+0j?EaAIJt-5)g!0&rr zaVEb0_EoZ)4>zDH_&C_V5U)x8-48Z^Vk$U!44m{(MQLJpLfS|!+UUMn1cr z?DlV~_|mV3jur1jw2@u3v#4L~?oQP9zodx&sezah(8gXGl}mZ{KQXy~!%Mq9zmTnW z-khNSsj}ZS2)G}BtSPmkNdNi7e{1$J3m}Wfj_4x7|Ks^ozYepg^nvmJZugJHg8z-Y zvmxcT_MIWqIUK;#*ldK=)l)MR2jl`jqJ9CO!C$|A#WB$j(}2=!b46T1qZ53ZFB9!> zhCL)hF4ydc%IlB3e2KucE(`De>zwe{MYV`8c+QEPL9vD;KW4CUsjA;{orQ^5JfO5H z5g-vFA|j$1)xc;ua>!~kGCF;Kj&+;5XuBu)KDmr=iTxe|eSa&pK0&kVA<}eQyq#LN zQ#tY?1jbT7jmXQ%$jGD^fr*=UOc*Mii;x?dRm$krD!_#K+Z69M)Sgnx3t$DtwI-`|gVx;t49%Db?C6ZrW{09|J>9aXJ$x0<&q33Jv)q$RjfNJ02fUr&=^hn`L zUpP8?_<8k8l>x+A(>`AEH8b%)G{rv-rP*Xpy7C1MpErU`3XmP*B}XWHvP7kVCQ{DR^$~LI-^k~S-=Ywj z>^f-in*a2BD)N%C^g=a>P|?fx#k1j_-$}H=p5Gx6lc?bVTvw!vFJv&D&`8UGm>{Uh zu0j?835)#0)?!>h6a0z*=;P84S)W z#ifY&-;n+o>GN24+^C`$;6Sd(Eqj` z!2dMx0o|f8aB_i4r?bb>M+gYd0qBqHn;hc*M4EwIego9U(p$~v{6rfB_f^_fr`Z7* z%71vdM$%vYk#tdw@*fKS$1L2%2VV6bl-4O~NC5){HGO_t6l>3y6Q^%CI!$s0qW%x3 z>bDa0Yp~6=_Itz21(W6*SufkIt*zhx-P^`bpnwfT>|WSHg-+HU)9+$)A@Vy(H#irR zZkjU&@DnjoGBOL=SOmP^Nv*$o^P9|9??4+N zrmQylED8R8(m#L0PR%c2X`d_*v@LS0Qw9w#%UgP)QBij76D2+eBI#kA|_rVBvZhoRj;*8CGR-cQWPVL<0k{X8euQMo5vNxo98~O zCB_OltHm?%_~&|8E%n`Qr+gIV0Ab)3YSeUNNv(;9y z`jnxZxHQvKjMS8HAPR4UgT=BbL_$ukVJ;1D&jGi-VQC$@)=?`vqVR2a3Rk2!k5y65 zDQennFkbrrUs1hf!1T>h{}(O)4_9XlTuukX;qA@$R>K4wdBp8YXGOM^ADwA`e1)iT zi}AFJ;)!2}((|*S`&bJtNBrCJi8#_A8>lAkKvP*IG0z=NhjGIZxYB69vdG>EnmysP zlA8n@e%JI^@Tbs;T9__o+L9K6wOg8c_ffT1F5cHC7Z?}_BqSt2RV$-Kte_hM8ylOE zrgE`!H`nZIo`a1;yaj5u-P*aHn1JI2`kh9M;8gBgRAUBmNi{dLTXx?Xt}JO0nf7}% zH4&aWtkwD1q4}p#5#T2A&LwtbzEwbUpITa(K0V;yy|scgp2y}3C2H1#&*2?Z#E$0< z4zzat{IlqDq8Hai()rK>A5uQ)HDUxOnxb=7N zYwh;U;f%7=K|dkt;o)I1fNp#2kM;zzk<_3Q&Jk9A)Z(d}6QDO?glWKlY{$xDHIDotU%nx6D@tl;oWW4I>4oR7uK3kDn$9 z^xC*R&24@atYckg#A%E#RhXLg#zNr`kD9h(ps|BhLkO4XHhSP z(=(}}3g%37IIqZd=m~x#xOjlWwo9;f?FQNDPt-5?SrP-4TAKtINPK%(8jVn0@@9mU=>_61eK*JnH*wPs?a zahJm%Di_Zc9a|4~))X7Ma4+FtO@-TBfbxKXthi&Cf~@@ivT9wzP1B*CDu-tVGdCHQ zQZK&lw7b433C55XZ$$0Pb%y->&9OJ=y(%Fd`C)P%ShFiPCu8^#c^C;WI&jNd+5T)w z5cFY7QW@9bfu7u$*?qs+T0>1Xt)AFL9*Q#!q&0lZkW(M)?wBTcJ^hBhBK7%JpWyI0 zChT9YES|E@2U7P;?u}HX+7)@Xd0cD{c-)YT*~r~8Rl1XA9<8G0izn8LkBs{f^F&m$ zzPVuVKLJ)us$d?T;R1DudgR-2GxJ#uWvE9mgb@xS-A5KT~Mz_+MNV;YrfOLPY= zS^$9Fp*uIhiiLTXyn)!>u!HNn==!BSPX~nrLB(1@&N!2yO#)pFx=)`jgX|8r4H+lh zh%TG)TP3jr1*%7_n<4q$e>4`F5o^BOe~=b-5*d2R`fl080P%@oIq8>$30kLqc02|3 zUcG?`o3-*QASAWkbw=>H>}0j%NcsBnRO9=Jlw*A5{=m5%Q#NSoVjg+Mx<5VdJ62(w zr(Cl%GRIP#aOHXA(Uld&;RkJ~Q{R3-dbC4zjwfeQJCVDDst=Yt3(eDA5B6o1JDO+K$vde`Vs^)kLwR&$f1EY= z>5v~bGKEx89$E2h-e7=%fvc{2T^NQcmevD3dl3w~Cq$IZCFl~mgkRgs@Xk^d4-cHn zB+ZH+_7+uSM}`w(MS1FqA=pp@M6l?{viMJ$d}KS64L}piBA|4fMJCX4FGc;etrr4; z#R$j&n^aRkBHR)sS8T`U4*biWRdhMxLHs#94{TKGq=9jVcGsuN<%gqVRBL9WrW~8C zSqanST58_s6J{%VJU%`?Kov}MIXSsxx&f_$z!9hm zO3+$YyC!GtOPXCjla)E4tbrqw7CIBKrp~RI8>ya7^cSOhbKbX zvDWCyh6Z~1__sblu8QsoQv@nS`tTVD@?68>z>BM^5vNz{;E&c!daH1e!(!MG%ppk9 zFA-B#&w9C#rMJUOo(iYdQnjxSia0NK0*;fyvNllO8=ps6c@>DLR_|Rc#>wz`7rDasOuHVBAZ=tiWjjhPYwYv65NU0t4 z?go;>!%X6&Y?7bmroohO#3k4pVeTDQ13&q+`ll{c?KWAgvd_jq{jr3_aDiI-Ol7{E zGT^jbpu5-Nhg?GqRPCtdop@|PS3DYzxo%40e5- zWwqDzqpr=q*i0-$D&`se|LN?z_}n+Up4ikh*tR%+L(5u>VT z&DN~l)|S{}1c_05q(;O}TO}nTRs=DAx!>o$pXYvF_xsP!U-`r5ypHo2-(y_g^SnlU zh;xgJ;WiJWay6cXY)9!V^4t)JzOWeY#rdQa#hgu)zkEpbzrdUs*Y>tcMBm1*P4eljb3|f?Fo)TK`i*etdW=p^ww-&Zi4%K^CBl> z%y8}+jN)&k?@0SOc7C?)NY8be)=gi-*6ORTyKGGG0B+SiZMUjvMll37HP_%7;Ym)U zp=fythA%gs8GR?r39l`_)zxTgl7W0Hzdz{EFF!o@BVxjQ7_X7-N_CBQ?ZZ6xeJq<- z7IlN$Dr|A`(C(3`qz)I(UD&wlSM0owpgH}aN8@U&^@={ z3OzXr3z_}FqnpSsAW@x;dpCEgRY87}P zkxv&;^gFN3$1F0MP_x-0otRoX=ff@t0N0!PvmGaiVzB7NP~~SG0}t1ytkZOa!RkZ3 z24?hmJ(Hj;%M>GRVCbT6T^H9Km`}a$&9Sz#;g?kaucdP%_AaIp5zE~*SM7&y-D0rT zEfx{JQan5c3o*^JC`n3uo!u+`>-B70XDX1p`V!dfs&ugNoD{U}7f8ciwb2bQD3v%j z=#gk@`S{OPC)9%PsXHoGdIFCR=#>#Du)2G1_hG}gf*vH_JDZqCNofymG@R6k6qd0} zQSIJO*zV1WS1I1v`sK)&wpR&Sv6yD$QbLXB5BGJ^U)4X;NRmWr#9XFqx?AoClClg0)eB>%duttySI~84;VR>xgsh-+*(ojc?KRQ;ct&F}azbLXlTQBEcItssfQp-fl+DNOEtH;Bz+_fop z9isavxBB~%v9wB`VnS+~(3B??n z*=_tPxX6Q|y1egd8JA{a^n#PuZa^`ceYLs#;1Oe(*1Ps(2!Dms!t={kDqPN2^PH<-=Gkw24*faG#Z?4OHh!KB2|a{Ogz8}Q zEA0=?oeRPRN~Y+v|6HR#Z>&}TKMk#n#q-;AT^{Xu@|}dSUDMNa@BbZ;TF`y-L@)9(nAl4 zZLAG{qkOJumb0PDzWAx*VSdK0fk@C?eD0bLzq(qtH;+nxT12X{EH=bFGIezl+U$|~ zlKCYpqrvhzzipsd9S-g>N2Q#R_V=tR(5QnfeQtj<|8W>TsBJ6!Qzd%M^X5c_ZXY|r zd)lrhis#QZ?H7cu)*YiK*iw8ovx2Wo5cm*Xd?D`#$1?sm;Q1lDF>8Gqsre zJ&sk@5z?exCjJjjuu>(^aXVujj8S*rec3@VyMyk72FGlha|yr?_q5;-mM0#F9xi$* z;nsa>oY{Uj!D;2Vo8b57Tq5l)TKsB1_7_P%2k_P{B*<2-1M$4j+_#=fhu`O(u{@nG zv8R=arpA);33DY?weu8Fc01w8PhF42EUqu!tXZzML~0ziC3)&0N3MR=@L?6kqOV^& zxVR8l(W>8RoGo}Q@l~$p1y|>}4fkBBl#luELiOF0ClUVExuRJ$r6Ap@2^I!dCCj&dGZjk7|qu1UO2Q$9J+C;zc|5 zm7Y)z?$&!c91lF(x2@__>r>I)bpMYI(Yr=js-tc}$`4f_kbaSm;n@j?{(~2ntvAvt zpG;gjFs7ZOfBsR&?E#wNYx8xOy@+_2Wfai%F34uII5g!{N-jE)WXI;W(y_ghIFyet zjWbp~v`rZ3W){0T_eA9JuAQ<|O7ZFV{l0ItIL_aa2bW@;^%$?W6g z-us?XiEpyj3!<}v`BxYBW>1$GvQ0U7cR{^EhjK(a=tC<_cKV+VoK7ek5O~+FXwTL5 z9Cq*-xJr@xEnUz1nqx1D2NAC39yvrQc~|LWmBM!EKu3Sfdc#G4!2ZC>?-K>$*N4B- z6oE9^eZZY0fsZcI4X`Q7WJyvU2rHkGOdIK0p1ae_zfqv_bhW{qKkVY=e(z7J8oIE( zJN~(&60+r`@6LB42th|Vk=^yWENty}n)idj#pBE7uj6dE0$kqw=CnEix=o#9U{HgyVq;Bxi-1{bB`^A7aCo@~Sh>*FSi!v4X#m;|_-SSUXoiCq+X%Qkx{wQ20S0_&*qL#7z%OsF z%{BX>o#q8=WkmH&U0tsQz%4Ai6>4_Jo^L&geKp%EyyD<%$PYoz2xa_+F(>HLtr>o9&>8 z>}d}V6UFr_-;0ZXU(0|CaO-c_xaDPR@U{WUUB71JgoM}K3b4UOEwYU?0+mp^jNDL% z$B%}tT>Pxrw)!w})h}Ymo>I7etAnHblXX|8khloyHH3V3ds=%OqQpwEn2dU8^C}(S zE5N~;_&Qn9w*5=gw)sm)JRs@A)(W2&hvHl=i*D}BHw`Y%J-*(8V&N|08s_V1L!%MZ zgsmSaFP6_;H9o&*^O_zUMS(7kiP<0Xsj7KIk*bKtUISn4h*jb`D}_K2!*HKTvwf%`WKwraBZp3?kQe7TS=^4(vk6WYOF)=Zn^^s*y-;H?8O^$!#=vVo(9e5GVC?D{& z*b2#`%w5BDXbCvsEC=hfCGw~@`N}Lu&qUqJ=Goqk_OT11402v?sE^^ zh%p&V?7d(4bdYbx9Jl6V=->2~@r>nvPs?$b1Db+2alYx@qS1C1^?r9b1wgj8A4FLu zS64^kthaxO)f78hT^y?-Ir}}^VukI`3-Le=&9&gyq_q{3JFmX;1r8& z1(B0WjK}7%uEUSd3Vuzu9exw`h?*kc>>ma7_{7Q{ZLU(>7+CYPGv~zw;8Cjil$l#2 zhe>Hc5@9-~V>v>~8{s&eCIxZ^oRc6z=Z{%cZkSMbSrp-?A~tT1+Xa8jA-d7a1q z*M$c605#`0NoLoNe!|%F+RglZxgIyU;=IYS6D-ER-)&qKw`uJ}57m(cir96%1)iKg zEkr*=CX7X3%=7CeRP#*Vxh0=T323(0y#v49(pUX{PrN*PalJEH%$&I+>Pln)#9V`X zK2zCCbM_YKu9ZZ{$|GG`pqDc|kJVlvYVh_&b`kQ{*#t1kMk8iQBz}5{ z@s4h$x$7nWFO}MYCx=w?K7ko#la*wJ`Xl93TKYO)-+CmwS4Bh6^0AL1g`982vlKsZ zqxS6T7YHE?zJYA}_~3YDnOi+dS4`u|VlK1Jg+79WVKD-CG);a=YC4Es&^NaAGSi#J z)Ifd`k4v1>;cB#wDN{}-Z+HqiKyc+id=NEF~U7-C_$pS$uX#ZrW%z@TZdh zrthZ`8_;DR-r`V7-QK$s6Y<^C9G3>Ulo^srqkhWn7sVK-czmCS5^fX&ic=bpu~FpO>D zYVTnvPJ!o*?i(`? zn{*r$-TF^%|MlLOcDert;eEBl=)X8&zvm1^=#Hd%x`) ze0Pb*?Ov31OWD<(uoR=T8Bl)Cq5B~pN-Ci9qF3xMR@@}vbNJ!fl_H>$bBEUt%M)eVSAwj{n4N-V@JxU z)AMb8F>T2@PDSaiRbFO?6rpxmE zRxtj4_N^?x4U3h{o^tGJo4q|L;iFdU+<5y79x6XdL~S>Os7(U;DxQ98Uq!7KK90?% z_YR=P1YyEZ>^Tmi!|6|$V|k9#hW=MS=P;><>91|C><8PtK5q6l`-Um_FeftL=ZmkL zA7>jI9!rRx33()9+NJ`c_CS-*$^+IqgPe&M>Zn&EDm)U3X;hWwcz32Kql&A#};hYMe;U-tWlUda_! z9oO&&l^2TZQU!ZSxxMJ^eI7xPJ}J`(uZP*$*x!w2ZtvN`M{m|;0)fn2)A6lg5jF?- zoNIi1$JW+7s!U%#OFD1+L_ccTvT;LBJ4=E!IPL?#RcDEj$dl><=fo3S@b+w;xb?|S z>&AM^-CrJiUe8aJ;DT&NJf;FC zPY`;_l)AQ9#b7XdKSKJ>9p?#P^ryGaIIp1-oETG4UyC)ovKi3YU4*M@-!b^?1o>*t z)vAO5lSzO_0DdN`yLbHlWEj570?4dA52gMN~CH}#I+8gl)MGgokq!pR(I zzpIu!L-UT;VF!8nT7*3ylaHAofBjJ6^H+>)(?K!}{X49{h@kM)kYdp4+y$9tyb>3ETWC+`=YlcjWp zHQ%YxV%kg6lMv5&&(x{X`YJ8{OR=e6#JOB>NZ_Kvy~h3rsUPpMO*_IBO4QVwWGWQ` zC5OcBLIAWm$^?(xmum16`g4Bg{oG&Z!gy|9${`m;V_A{mHE*%sr05-(WCpKuJm1TV zSw}@T)4-V4A&D(xomMx=X z*?CWS>S*n~OeSr4!<{j$%evs+geuxOf{K2Q^Kzt(29xS7&WUrlOEZnY+zxI)@VRO* z`hfRh~v#UNoNX6@>{&pTxHDw*+B4x4+`@^C`O z7cmwRGWh*fqv>A>iI+M8e~47M>lnHpyWQI7HmUtupw0h4T0mq3Q793(iAd0Ws@aIw z+d_$aD}N>ox$bp2^~NsrN~@K!^5mzAiz%%gpt0WBY0qRSrgvY;`Q41GT$l};Ut5g* zm|VPFEN7Zjg%MuszNIwg&f-v-5tF_kR^*b02>y5@C|yA98iWkM446D*?u^xo;nC4a z^0*O1it{Mw%lnJNk#?b;y29zc-6LAAXd{dl8c6jjc#s}4cKZz2Se-I^H;{V`;-v2q+t?n9^UvRM~-hb!aTt&9qW^$!Q zkYVN!jd;5wkdcDkGKmKvJ#Sh1c2-o&1GPozcF@IYLUT`yGn*s8`Avc(ZK;={!VSEu ziNyg9g=n)Lr>tz7_ZOx<)^e>ZRApx?OP=a(LdCn51T=={N>4Q{$ye`X+Z5^9j3QjWqY>hOj-*#*j)QTF`Xb>~hQXD5tMKVz9cX`>A%WRB>)_pv zu_rL}sZ8IaEFI6EdAi(VBttpd{0Uw;HQ@jga&vBF(nS4`{kQ+k2nwZpzz2|hx17{t zB(T$?n%C}uk}MFp(zi{6Rso4i^{h1crJb|a3kS%H6bJRq(%4=WhU+K$lTGi(tt-&4 zhz^MFcu(|4#r=&j^XkO%h4G4KVa>ml;`<~5e)+eX{&0QxCwm3f-JTvf@IfjpG*?=E zP4>$S>RxZ{>;5>)JN@H*wlURL$L5mCLz2V;#>YUAQv{D&Fy5)NP^KcX-wbvx28nz` z*6-2%JNZqOj+Jg=B5zXv`SVy4&)BsV!~hIw$6r z_J=(uKF<>q7p~X_+m7o6cm5yL&6kX9t}LAuBI{M@xGQN2gNfEm56Yw;AD6iYXPPQ# zyq@U)@8$pNM+?vKnZc*dA>THZ7I!^D*Ef1q?cStbQ7vnc>6MMB)@RxHJ5}gE6e(5X z(`>HiJ1ct^Xz&m8m&A(G1 z{v$)n6*@IQm>cBDe9W_4F56(>td$kSBj7-3W1~$q2@^5d=N@D5Y~O@(G*twr`- z`~QQw$9;UJ^AoisbgS*wpjFd_w|8dPNJ5#Iy|`cUG3c}OAKH6~0(SYW0ai1hpDyi7 z$)5i}ApK)7@!o*0xAUp9?>GCUHAHzAV52$#o5od_H*<^r!|SJK+qUFIn50uM_J!|W zCD9I(>?dBi+pqOsB%MFU8>)0_bnLa^m){xGGR&-e0^gYw*pvqaO;y!aStcjW1vc38 zRk?oB(*rvODBJSTHkX+zSu&FFB{$c1k^Qe`^lucwKa{U(%xE{xnvj?2#y9*>zFL=U zge%-fp%!^3#CX_c0}+^M&Tw7*%((NXW_cs44uWItGh0M<7h7Rldg$*dchrpMLVw!+ zt=IpT7Mre%PAxU&-3yg#*bgVepTFJ8&gO-D;;@RBPBjP<_r3|z8bf!2{&L@BSBC* zJXwk(eA9E`GWLL@uhF>ek@$?poIrF(w{5?zC`}+Gnn1D7fZFkO-C6y~xl3e<+#@v_l9juK-PN^(nr%UViiphf7r;ndjJw|u_)v*(N z$Nu$m+nA0l7ts8806e`j44bOM%<{CE^o<9b?NqC`^Dw<}nIQlI^W6IIrnqXS5}7F- z+#aYs0g`I992NSoE?#CT0JPX}8K0YJ6QmJjLRC1OzJK<5bE@+^b?sZX2Uw-|a7=_` zk24O~EvwF&w+IXW&!hj8qDk@i{te#J{)sxH_&^nz+HBcVio?KjnmCyqi4Y4gG?Rev z%J+99xtZ1tr0ewUm4r}~LFe9jn_A{^+Qn=pUtJE!pU;(&swM4nPc7w+@i=m9=lO&n z69a)|K1x-S?F!T^ZS7#o$*_}0cJJp)x9h5GmR60M82yFjVR>oDkMkgBl|veoeQ+u= z)ZU3YpXSodYUfeFFiVyf=GE_SpF^U^bR5Cs0r7ekJ{YYLgH&>^F|Rc}AH~snXY5L0 zdA<44+S9IJFvgjoAs&)nTwd0X<+}54h5x1d?~RP!DEkc^OJ$k=k&p80#m#*f_oAuP z`iAAN#4o>%Sgpy29BXGO? z9S;|0AW^7rzshX^Y78ASA;6@?$j^-$iw`$p9xIa6?&Cwh69S&G+^g#3%k;8@!_{|^ z)q`>s=QnxZoC1~@z#2`cFH{`a8;#RbcEP029QYAXPU=RnLgYW#TqJbG*Uc%*UAuO7 zZ20B<93wHxg}E5Y-mW(7Hnvh3Lfw~bso~sTW|ZYu8du53a%YPcBy~_*13#A&Nnr0t zHwj7}CWOn3hfX*(-E+)4WvPbt1?jCKG=%_LH|w21G13nxn37UC{%Pl@M{x~gt3UKE z1)ZLi;y7bu>49nTZKjI8jE8}C$BbRJ^2=vA@WIs+{33N-%?Vt&!PyazPh-F#Ix_FJ5yQexh^#rfQQOPtJG2<1%YDNDb%}= z%_XQTC|1h1_^|)Dp07vqbLPiO-`oAky}p^j3osBgp7=v|KzOWbWzwmxgs8$belI^Vp5E z1ZT*sqg*W&_=cll%;FAkMuAg8Th$<>Ej8=PcO7g9n;8!e=JR_SRH94JG{}c&O3iaL z#eG403^Wu>Vi1$+=Z*$E!|{CvYg5xyWPnr(Nxsy_ndex(xQY+8b`Weq1y_(QU(#a&kAi#8K9|qqm=6L`Yk7-x8)CpnPqSIy=IjR@}FC#n*JL+}m zuR?N2StFQyhY*M4zNWdF-BMh~n5&W0dUePzLQwLECSg~sdf!JG?!HmZbAEANsj0%c z)M_l<+M+TgfCxyzR4G@djhvd{Jnd+GsCCU8XFV3bv>H0 z3?jL?DD;TNEwo!uXv!9GNuLntT!qPTCnK6ll+soPBQp z;`5{#2p*#j0c+EFG`r5C(@)*6&UCi(!6|a-FYhN&026il8Z(|Uwc^nEgC$%-$bp^q z62`g|8uaz=CDs4r*ii8KRnlT}wVF?{FH*)-MX?X*>a@FGE=Xu{>D+Ry9z3AI%Y>T` z0%Bq9>;yyTc!kg)>(KbrgNB_8)>joI`@5r|5_3v*3$zl*jJo@R=b+muzo0oYm89-t zRZJ_Ew8^FRAsDB@%F->nyGJ%3%yInCs+@#b9CN|g(&Fn1NW1!2sas2;8NP6#S=|^6 zTQF=y>?uRZkxON4G^LBQpTp*3>}Q;tA;;&N3{|2GuwCZtr+wP5Ir|p`W@YI*ZGnvy z#84Zo`&7X2p^?k1lO>Tq;)t=8!c-5GbF$=0poqD&fy_V^MQh~33A3%Nx`AuoqDac7 zrOkfO-92pcgu4n6UskTSvLVy>$>I**@EwE(vluPQHzrtr*#gtxHyDF|qOm5F>az|H zQC=F5BKpe6$Ssv3Y{V$;Ls%4Kr<_~psN%8w?@>dIQ$9PRiq`4mL3C#Dq4T3e(yo(K z>H(~5;WEBtM?BSx?1kDi0?kb}UbdFuGgB0e^4@V<{gK+634e}iC@bEHAz#}se><9I z5_E9&-uk|`5AP!9bL_Zg&Q7m$v0C5DXk;e@v0-vF$aSy3NB!7nE?F5jhHu$}ksI*N z0J#%pn5IaIxC-mQv12Tpj~?7L+-laZE6)TK+7BL#Ec2gw5HO+0R&3UZk$Z!P^uhQ- zmlQ60Hp>u+txueW_lvrGwMutO5(|uo1qUPCU{|L_NcrgMwLfe4zlyqJbR@M;2Ug`2 z(z=nCQgvD)4c10p-oG}l9 z_$@Nld)8NX23hK)?wrC&uGyt!(XCf%qw`+p^=;wXCoS>y6J^Otn>}}*uqx(+<$Ned z_S?Ils*8=RD^qbp9&pHxneIO%@P~8|6j6O=6o50ET=K1~$weoJecq#ex*X179`Z40 z;gyDj9Op}UcWA2Y`$=#R%VX{nu?%X;2KZ5RaNdGnheK>&>8^MNVn1uXikbJndZ9n` zxO(Yye=rVf(MhYYoT>&r%qsiG51Q$(h47P7E73J$revT!H~0BPo9b(71K4p1`ye|b zd}a`(cbBCO zfmk&1a_iXTBIf8~xSe&e6S{vaLsK964(rjKWt@%)o&o{q2J3EQAWh7)fbcXc0-`?q z$G(1@M23iSX<-U-Lkd!JfRdvBGI26#M9`Rl2R`TlpEWS1-pYZFNV?;wCCa?>jTTNN zdhy0)R3p@tgPlYf(^MHuIZ)=GtOcec*9B3;;SQGz#c>{B123Y6mz8g|N|mLy(>i<| z7USO24d5{)N%iuM@!sK^Y~vJEXuj{bRq)_a0F;&$`HkVGDp9nYIJn47oGKXG85{1Utoz6D zy79`;>dIf|Z7+i?C0qt-ouZoSoSO3NMS+wTSuz;Ba-38-4;D7L{DCwd+~o*vfc-;K z-FrYsrUW8wQ?&*TE@Z$lpr(?=>@r^(R@%cYY#WQGtetBIi5+E)ec3dh@l=oG$mJo_ zlEYzBwKil8uQ>Nu2F7$!i`sB<_)GcvUD4l zun7K2oG=8IZ#e))XVYF2FDcKHxHXo^*gesgD{lwPc4Wr-UhZmUL1>O#)8tNe?@6c| zo0u-_%RQPcX46`h&gVk4#Ddmd1b%gJB|9%ml~~zgxhqXYtox{LL)dYIYiS+Q8GUf} z%S`O4lZfB5tL-u(#$C@*xyPF7c8OB~s1HW*xYjYVS$?lxNUS#=3N*8(zB`Ih<*Ixk zQsvWNLu+yjacYT+nl&>b88V6kK;lEuQ_x0%5YpyKK;V2$ z-~uZ-1mrY1C=$T}fq3tf*iY}!+C9*SBi;3&6sa1sx!H8y4jQg!ktZyfnU02#_=&-D z5^6vrbo~accdlBDcJ5pRU>yesToy`j9sJseRMOAw_surj6;&;N4ee-G+HL4q${*54rzJdOIcVW{DoE4hjx ziT!A4{P4@>G?iZ}PHdG3cTn9I`vE=cSH=NOmRIAY7p?qLWJHh5eU8y}onB^oKK}7ok%=DLQDeOPA!aD}(J&m&Uw=W=~)~ z9fgiyKq&wH_hm01LS@(s%iTY$b(i~CDh)dzJR8>cMs=z2T*j~!AoLI6<%8~~byR1D zj-|VyO-sF`rn2rpZ~lY3zB@6<3{(rsLVmH=-nCJV1}lV=o7px`0lXH`TiuBJ2f2}# zpj7k{!U9tkcd~NDv4THnY;M*F0I>C8Svu-O<(l71u64QO=#`B?U;4mEPbmHFQhiy) zec6JC>|t*)QVu?rZVwwvI&U}bXC}_{fr-F_>cIwl+~)soT3bkh6^g6%so!Q5asvxN zrJV?8jMFqGMtYHU*RlD+1`dNjTSgBZvJzIr0FvK6VqP|Yp9dVSWd5p3MVkfwL$!Eg z_1iPG<8{7cLbyfrx4``sQG5wd-yD+q6U23X@n`k3J|XNPbaJ`hE&hyee!&)3Y>r3g z5I~RRNR*HBude>+>^f;Y$cEt>YMj)$l=uOeYH+Yfn7ALwk0)Z{*5k)E_+tlq)AJ^Of%CaK6FFM3BvZg@XyYrU)*XhuRBY&9~ls-tJ1sGA|Wq|>{z z*}2NzN8~tmVv8}8J$sqlzh0f`260Cs*Jgv^2P@lvQ|#bDtHm@-zh^{)zE{B*@MsBs z>;%vK@7+)B^IsZE_3aRioh+Pb7~EV){P3)M@&1iiFxq;tu|y4PJ>k5bZmka@QRa`G zI3hv|=cW1pjVc6AbH+$!25&miNN6;Ngx~F$0B|jums*xWzoWM>L2r*HxbyNl-^_}%tqio#?_4KggagJ%YL6eNzHhFz++>Gt%F&n1&xSBT}*tT=0rdXJ8* zm5I6R*%96^(#SUM-sICq z<8c*_zn9$YhZ3vLJ)pq-1;^hc83UkX0bxF22RD3TtD^rMFR|6bQBw&n16C4h0$CqnM| RG1}jwhdK|+?md0|{{W`xbXWiY literal 0 HcmV?d00001 diff --git a/docs/cs-manual/source/_static/images/chapter-1/new-project.png b/docs/cs-manual/source/_static/images/chapter-1/new-project.png new file mode 100644 index 0000000000000000000000000000000000000000..a5097db9c06f0f98e002e5ff01f6383eb899b87a GIT binary patch literal 70819 zcmb@sWmH^Cvj94{1$TlIB-kLq-8D$?;4(N2?ixZMXo7~|!9BRUySuv#?#_eceBV9q zuKWHy)|$oMy{o#UtE#K3`m2(H6e=0o5h>4LaIe<+qtU&;PW?<|O1XUcx=oU}T@{J_NA)f69xgj1VxglodU*u7^aN=yA z{4@R1$b&MGqtQMD1b7k7Y+_V z4j6^PAjK3bW9L|Lw0B+?0|J8YGXOsU3gnVfyYn-efUkWE09G}+1>W-4aM+1r@XcnXp~-~E2Rj3$SE+*TG1q6SRKaW? zypSDE=>hjdj?H4XorkHVu%-O>1#+Bl!X*KP4YwNGECAtg8vp^!@kz=4qlasy)aQX&! z+G=lyrRw+54*uPz&@>pQ06{yH1vn}LVt#l>1E>b*qZZz4co%X+QLzaOst&Xh(Y9}I zG68uayx&+&pk_sizoFwGN(h%Ku{ja+1%;#`=b~ADVipk?VcH>m2PF`Qm#((MUV$3W zo@*e_V*3M89xoeyJSd@^*dXP%@C=kDB_p=WD|PsSAYDJ_R@+udgGfV^->$z=x&2hy zv{vrzENX}rFl

    0}xtdj#b@A8*uc{!GTw8K`W6fD90Svc+i0c;>Q%3m_HGT+b~7M ziG?#Mkuh+CCB^ZLFisFlgEgh@#XnHhev6VueM7qY>6LgFRr$B9p0gf?9=@LL9*rI_ z9Zm=wb;t*aRi)xw3{|XrfLgev*hL17l3Xt8JEFmeIB~0tqET3Qn3TENMal&cCA;Ou$@xeiOi~M%z!}$mPOgD+r zfUNEiqsmgW84PRQs#o(NjRDEsKIxg6IBBXm6Bc zxN^>6`TqH-dv7Q4EiElEEd?yO_6YWjC*Ds~=cTIn<``yvPj4N+9?cw89djC$AM;Af zO2f^b%(?jWK9ecyAk$mAUQ$YgR@6*dDork{AQO`ADOxQuEDclyzb8}B7hab4jr0kG z8YFKs7+C54)@%1=m9rg-DoOd<=(q1ZZa+>K*GalG;5%JAc{wRS7 z|9VYxUzd=t6*8N~6Iup~P}-3GVo6r_}^2JVKohGNfg59|g$?{9)b zf`fwfuvVf1hVA%A+MD$X@7|lyH7y<&tO;*AQjCRwb&y zvnJ5NynhRe|KW8Rp(V*2MjieZ@f2PJ(iPItSA$^0aDuRnukyi3!BJs-As@NZ>{mAY zouhbmz24y*5PEZb`PxuJ7>*k%fK^YBgRMb$C9w3iiQQk2g3|Cjt)q1z0F3n>YnYlM zDp&@l_r7DZ*I7|ak$C4sfX+MbSJeL8Ar0nhi7M9 zsFd}4i+j(l<75}Rj+Q8NClo6*E`%wxUiMn{RJJMQT+qElHLv0l=Tdb)FOV&?tYA}g zv%BAw;S)Wn29au&n!Vblx{dmsn&Q;XWW|)j^wzX(Dw?2xirL3$HQ)z*4|r#q!vRRS zf?3c|Ua}SMu)W~ZedL$mFM*QvU9B{e+1aMWTWxrna@PHOaFHnM_~FcYHnFxvR>l_n zV1$Fx12FJL=jS2I5y6fs#JZ8ut9B20J+^^47h*8&;i`1irZ!!GEnq4D)A+MdqqtYc zYG?hZpkc_X@fiM6ax1(s@hcbCZN}}iE!@&aqGQq@^#=}~mLo29`w=(EtMxRlVDw$| zMdB&a!}=WilI^CsheOQR@5RcSqYUUVWIBW@gb0suzq8xM|FAJMarZ1Btj{A zywILEv97C@@5R@1izCNY{7WFJeryw(^^7(D6W*hZ8T%36-BlM;Wl_4#_5l~)N&U`Z z8QGeUhwsm)q-B)l`B2Jlh);}gD;qF)7=V^-ctEahuT_ve;P<=c>5eBnZub)?s#NM$ z@(szM&h6C{M1>B-G5{#ZRHC`dNoB+Efetm7JJ%&Q-W=XyewTi?oB)fU{fE~N5-mop z@Yz>0s64N@FKX=;O!+Sx4!vL>$^8*ql_%uI|- z-fzxqPHlkcW9Z-+EEvY=f%#6krn$3uX9d0!JL3bB4ij6`J|&Ltx%7wS^n3mKR>D{P zlw<9azE5euyu#$auI({{cI)XNV_yH{r2@_=#-55P5GA&G8Dji)Zn)?^E zk(1HEI`n!pRs>0*+`e>OGJkAY((NV&W3pht_HUEyJbBO5C(=>h^3df_?%k=beK+zOa8Xiycl#akW9T zkhkTX(^(wzSncWzDnhY&9dFK;$;$+k(tUflx0g~|x7hFezJ3_uF&93U$aT97wplbK zjA=G@=Q7_pw!3INyu+pfleKhllhQ}>$#*DD33#wn@-f|XIMZxfOz)rax3fQNXX2xx z0QEx{C771o-am91XMvpWl4n15-c?3+K~Ph*nsIDcd<$-w%O-1$Yxo}6O~6M&Ye#;< zl!xT(O7P~dJYZEMMB3Kg!o79P%g(Der#BzpZQDsEd_@5I@%cxBCY|PLVZF8ftdPCe z+I`1GtY`E#0$CUtwI9}JSRs@_l&h~XAzwmwL&igzznRC%e`kv~jn|8-eUnIIMm8YdDF;@u@E6HoJ>yke>;`hWP-LtiBlF!R^iYz!9MRB`2&c993TP z{gga-E#w5s)N)JnOe++x--Lm|$_Mg35ow;Ye*JP3O(9}WK}SI-S-)n%p~$u0?&@OX zYU2!A57-#w&5N|{RS=xzBk>3aHS13((%V`}fte0vxU@QiS@j)HSsj5`rfGDPRm!M; z?c-VrZ5Wx3?1Hpp*6*y4tUQvoEIzYq5*ko8X>ULMpkVTNlqdC(DtC~-C4GSUnT@6P$UvB@X8RDUz>O!)plB|z6T`_P9p zyPnpYOlVE$=VO{j;r8l2?7O#T!7OUGZs$nWk_Q&o)(;Ek?E8+3_z3tO`oH4&+~w=#Cu?lWe#QY4gsfu$hIMr zArM)CK0^Af{8#zxmX&*tL|8;*@AxX$Dkdvkoo}7X&lxYYF7$~i2(t+i2+N6p2^BwS z*1}FIt_jO|&oEHnPUTq)V!;R2R3_zyp2Njcf+$ z4Z8sy!9GVMsXU_1VD=k1?tL=c6~bVY53jb6(h+a4ZW*oV8mNBpmXXsx2xGlv<)x+( zxRln>yC40GjUb1mNF7V7k*%6Dl{rbAFH_Q+E2#5b%O~?)0r#Dof{3lHo~h4Ak+sno z!FGIcm|=5Jr?3{5_BM^EHM~H7J*Lg8H54yTyvB3h=JOj>K*d0W=|N*r5EB{Bpu@DR-%n z7PvgC3}Pot+@3^R!(S6vyL_gz^?r+e)ojg|dW1^z4Gx91%#Z@(FHa+IXU>~qnJMWk zSI^DE#ozM?3vkm8G6TjZ$5bZb*)Z5~II!5` z*p%N*wk5134?qt_Glnn%HBq%oW{eI@4w8w-NVJnv>PPB-)@9XRxp|#^IE}d2rP#-` z_o052^OqH=Z4FKTXt=q$OqHC$9BrNvU}W2A-%0ys;Em;*$xLz;s`0I{K{gNetO!+* z%7*y%&=v&$9cczoUhuK1r}4T~CSYudE$j4Bb~ay*BfpXhG5|3f{*p3pMQ0ObLt2Zm z5MpE1xG_`eT3gzmeJ3~k)e6fShD!(R)8xEgwXyP0Z`fXORUB3m%`VfT8HP32HxsoHe4qZQiGk(a7w$!*v**5$=0SNPz#cF(~| zaw%DeQ2%3skWY7NII*vL8v4EnKpI*i4Q>GrNC7wz^}xXF^Jf-~OiyKDbqGv_s)yD7 z%-;5XMdn!USnV@;8-hL23G&+jc?pGIZy~Tj<8(b{lp8RtC=OO9SFKT1oh4 zDL68M(6~q*%sbX4%5Yk=W$-XA7=Kr2(ks6y~Mi4bGiMdR<*E_Bd|8ClqM6k2TCIafc}Q8pk8h8u{_P=;VC zei!W_*kB1Ei~Z#BWlAEod&KYq3mKi)+Y}>`-_aX0Lg}a39#YBTVshicR?_w2@$Z3h zLc>Zex$V~pdH%D}feD~b7u<<3e6)A3BW#Dfm?^7C(aC_HTmz4weCvfv4H~}1vnYs5 zsLF>)C8>SVic$-a`zS6cqOLt8PFmup(eZXQhDmi_RbWDN0-GbkB4xZTPavnfs5>8M zW?;Qzjbol<5C!%inhr>1yEADu$g|$GO|}@fy=zNZYVBa1%$vTcFR0Vbzavrn2t+>$ zg}F&43=IJAyYW6h+JKx4$=z(MZ5?^t z1StPN@IF7k3Zr&MzuZv$b#%WaIxM(ElF(AC3IQ5(C@VIe;7;pV0(4{z3Wo*#Cyt{2wxc zT>qi*@4^3#py*)nEUDoOUxKXv5cv1l|AyE4zX<$$@Lvcos^?X*a06Luid#G@^sf}G z&usmlU;a0y7}y%@pkile40_@056ZuW{x|d=I$Hljhl_>%-*o=<nS911eZ+zC(|AzPnnIHJ#N&oV!zi#_y^x1C( zk)JXD69WX1sd3F&0RUlujJSxZ8`OR>l2>f!2`^qLD|qIb=0h+{#agmT8}$ze~KKG^B-vo{di2@EvkI zdJ|1Mtn27lp1kVF&c2<*!+zGdn&Q5da0mPC4eVz>3=C*dVMIhI3iAK|UM5taMJ}9l zF5ETS3I&__*f^gj|HGpaf)Nyh>~%ez@od`ut@zElM~;593|e$_&A_>J5bM&m?{rxeU4#GA)##}z0L=MM!{iV~O{xMp{Fjtv!MH{3q5Q^@o#A2WO|AVS^-~hb}X$5D>tVJ9lxXeQJ3%o zxso_;&~pGVS+=7)skZ*!O6L&d!pA^fvN)2d(!njh}wQ}vg(Z;1=lLrufpV=6UX ztQIx8!*kexFSi{Vn_x?RhPBUERoWb#C9X<{fwxxztypnin7I~DTY}}ZIbVv%t2(Gm zZ=G*Cukv|29VEO4A!xAJ&MV4sF}-f8V!!)d_t$9LBwMBddlr0(2W}NhGkfJ{mC1+g z+YY)2%=&j%naR!81jV#X4er?Y2g8X?o$4Zn$$C+gp0 z!?+o%rnS+Ttr>g!BW32=s9;W-`R^J$QmwoPTy#vuhBGAp{7%c+r@q-#p={$l)QIFF z=xQ`NGVilEJ1wpsU4^H@E`I36YennuVpx6{ziC$FzBx^I#V*B0NNK7xy2l;fCmdMm zl!OXz+N2)tC+{Zr68>aQX0Jt?!+yP}2b|6FEAe9 zh27ZXzQ#(81Ft?9l5Y*W!^uVL-ZuTtBSW`iHVto|*O<#YwCF`OJEyaS3`YMu{uEqg+;b1;|}Dvxw`~ejV}}U zA;D4xyN?C2zXorpSE;kPp1DkQ&4R9~CO9KHcJ`Qkkzn4z298+qfw#OoDiKt?C)?fH ztR*Tcx)87LbK}(?$Al307>G@B_F%ipgLu&w2=A&GSJ`X1!-yL*#qAT14rC&}u z0)`o=oMf73_tNESrTp_+<98BbD z4qsBDZO1MB>$iyhvd~Vg!J+uT#{#SA;;ZO)k$PU9!ssnSefu4;LxtPCw2k4qMi1jE ze2^&`i`+cD@qE(Hx;JHIjl%E7pOHlL-mFX1~I209Y z=tw75z5z7ws@V*%M1)Wggv5O2AH7@({q(j-0Js6%t?osR z+I&8q-o)Nov|{U6kVRZ=K7?0Io#$?YtvO5^a89u-TXjzunt6K4_8D%QLcm){@a`N% zXHo!Z(c@Cm3q=r*Qsz%^k?}J|n7jt?bYtNf4?v}E(zn#pM{5O=#5-#jJC;Swa#Ws= zr=kEz8|qC!#?Mq3lKX0f)YNOE>;+;DZxB4o0CfEW;=7k5bWa{Y+2*GdZ}N>k223Yi zHqqM$^iSIE_-{f&L+y9Rs5iE@L=S|;#l^{KXufE~A);>s-?*i)g$}KRqRby(bS85r zJtdF+wo>KNnQj33#IOL0epa3=Xkk}W%!b&nE(m&6gUR&V4mtQA)+n87_vn)ZZv=kQ zR%DX+f7ri0qR~loz;0`E9|b-O=ASM9EZ1PF@tbZeA0CuP`b)aT$xnViHLh3KXgA08 z%AYEtc0HIqjf`!LwXU|ITgqVG=aO4c8dG{K>P*e&mi5i5#}3wx!MWqyqx*zLIUl9n zd_Te@!46EjEDE=e(dQ3pa9!@~e7^U=d8-b4wPV|}_|P*vEJeda$1Nc#`Duup0HlYr zvAIcDqF#{}91_B|ap*%luozUC^Z2!5<-r^eKQMR-NizBfMR7%V$yK_4HlQ?qF@lt} zaiP{S>NYBh(yQDITNcIfsaD=aIsL`bx}P zlbZyGNz9IgjH*-t)ER#~IW>4~2`BK7NaFP$H^IJ~??tqn9ZO&k)BEt@Q@PpjC-m>)D%y|KA3`yfpjP0ZfY38r zW&O-zngmBIJc`>P!$yO>zAN*&N0?+%>lykS7t~*Ra+SnCkRbrGUURDOJ&=9;GLH`& z65wP)MK~2h5NgkhMmQO6_6?q=c`s6ZxTy3&$8SJonTnz06|mu$cqo-GaH1|aZA<~-X&Cn`HqebOF^gB z?d|Hd#BVUMt<7N?0GCjQpN2|y7{7Mo+PEYTTB_I*{fV{r{)|9i zYmTosvc;ydo6#tPv?ab=z6E!gF$t-UJ$2RL6WM)*hBoLhoo-X6btTi*|btRg+iizs*a@!Yveq1ST*Vt>71e-z!+Z?B@ zGPPt7l#IV7K+~VS|GZ93tCzobHhT?()@GXTHJn=g5Z(c`jH$zLAT1mUsOqJeFH4kC z&u5hN8rIjnDWAJH?5M|NTwerKWd-4Ax#i)U2t1jdyb~lPg7d9QE0XWh+=cm$2Q|3k z(l$NIcXFm~On>n~R74L=A(i(tNvgNiepAQj!H=1mEw`tG=9QK7b5H=GDh)3#nzSmBoyFji1zTIVXozOt?V$z4^zE6t#PsG6Q%%~&rhHj}tzx5xQ&83f0-T1yNbD+DTHWTIaE+qilXHGH-8Oib>>c*==g74mZPrfxA zDzw;%A}C56Ju*S!Y~&;ps;Gm4OMQaTX1`u>q~$+tW6adC)z8G!?P-Ak2RmsI9K))b z8(f*Y(Dwoxu=U5M?ui)h=lLrl(b@yas@7ef%Y}0N+v&#E1cR$`bFFTvE-a=Rvvsaq zRriHX4d*@UGts)DuRPa>P8Q$J1iePFdi3=^FNkE>o^2*r9<4K-5x=J^#u#jK7cqEJ zY?I&CIJOPKMeuo(aq)UgxxKg8wx)VUwU z(W;JT-u@S{f|-hjBg9u9v|sGuaBgl+udHLBPXxLyIvARU>(1Xo>v=% zgOgah#D9wLe9IjlJNwP~(TdUMM(D@MOthQr5EGr?rT+agHZbET*|#NCPxmvQ?-a4( zPz?$~8M0DRqQ6$A9I+#r-W|lsZKF7KrShhk%Zb&-!*DB^OGUrv_;?(JCK(}erSJ7_UPh|{1pu}Y<*>UUM^r+zi)%DpL zzMbRMncF3Lf!%jB={fW6jYwC4;1Viunk2Q!t**Xz4vhlYsrG z!RZ11k+Kh>r%%tjJ;Hh+3Gwcf;2fK~zQ?{*OY5pNd43^hnx^oBAhX9Bf=I=B(h}x7 z4T-zLqw2M*GyQhd>L)ThW*?-7p9h^~zDJ_$bs1gWCS)?5FdY^6yH5@K!)_~=de>(v z<0q|LInqZS#kT}m`}gJLZ-1vNE{15XUEfbZbhb7uisyg!>s(RiHF;ZTLn1pWiISKd zHPk&cYKzw$V&m)eKY;T%oO}A&#RoC%+SH^Xlp2=3M>T6%j-nm77lIo=q7^ZorwwXMY z-Yr1cnN1ImJ7T@L{CG~7NRB$w$ic7d4~&iq(=@<&M+r)8!VW*I}E8h9gM&)mfRufx!E~&{uoyg zqD-kaI^B6~ua$U7z`2WFQ_I72Y#z4IP4V%wxD#=}a#Rz@OYWTPL3?3J06z7A$8<+` zP>n1jhQT*AkrKs`e{_$SSG7j z+92!&jP#4d>qnd}psc|7p7$DPD5vE{xy`4LzG|&Hyg!K*SYF;{@_9sW@AX3b4zbK> zNp5DKs#`H%wK(<{YT5=bJB@WoNs!vwi(t-7B?}n~zu%G45w+Ubj3d;(2@LEEmfP`5 zUGgB~EcS(gEYJBtiVp%ZH)V2;YnKEmx_V}-W=4TX zuLvPz^>@>;wz)X7yI8V)qIMU*Q&+%pu2hgNhkeF+s1klB_QU$C_enQ{xHI-mh*uZZ zx~m#Ib{tiwrx<05X$&!aOb^$Wx-wPaZW~5N-9dJXxuu91PsX6Gr*f7z=to~%ku9n} z5tIskJ*U9E#dxzgflv_d6~3T<$$q1O}NJgD_-B@<5_{wFF`;`L-x7(NB4B% z7ow2Fvr%$+a`kvqAp`^rw5HCNhS~7n5E&fJ2y(|XPjMd%U)_c;qh3Hn)Wjs+F}*Lo z*-)!dV~}76#n}L*cD^&>;B8Rd-ShA=;e8(7O+W`#@$++BDW5+n3suO=3(p-seK<}H zW~ig4ddDAvX0i31{qC-$L9()m_@27l_uh;wQQ(pBFbE%0qL3r(kec1JoY zT7;jiCb$eWuI*T=DNJ^LI`CCg_j9f3iVXY-Lede?k<;D-}JD33BuJ)K8}_*pIQJ{;NG(TSU)5Fb4zvq9g_Ybcptu?{05^qt z)HOFxtax%FqZpxEDU@qm#9bRIHUY9eOZ_Xo>wL!&yhiYFgkb|7KHuj3N$N*WyQ?WE zJ8q`=-1VY9`$_r<0nX!*kNY}w%xa_Dqsj&D%(Tt&vOUav8Xt+3BHVn_0tp=^>8D!TC;=qR#)E=epn(+Pd1?XzIFCQdbXY z)VJ;YeuPfJTm|PN6ZGig-K{vnR*Z8}+Iqb>QU84mOs9}q>xbPPG3w%Sv7DIp4Ua&` zhWoO}8&7V^_X~>CH}<;)q=u&}{9T`GL8pCTblkDxA8NIexYLwJLB2*0Ro*>WopYpi0?CMt+mP4wM1{Y;V~rg$V@ z2D-K8)SuQ1K^q09Xg$7>8!UiOc;wYX}6dZQO)%Up&OS zSw31K6qF&ugMG__ewY|<2Z0R^(A^R3?W`t?B3lzLW_f03stbQIT-HoyRk(^u*NBV2^!%g2Z;-lAXs!jNTq?pYO z)#qa7>sFzATp?!$VS$Ut7l70Nq50oMb?*&!!#*>KY8$Dp0e=fZn270kO_DCRVSJO^ z=2J`Vd9KS*=j+bQ-dP(7eR=d^Y`QTe6TC4&`5-jwH$}2`++#dUbdSFOh>=`^*r_JN zHI{lums!w{AuiFahEcZWKAE;`fVReRH4I!8@>R($V)b6?uSqv1mfcA+WWNbTH*=bNbmJB4!o$4tn~*M`FVCx>$A=cJ--7I&lImf=PkBJ{EyRP+7yAz+TQ)~lcGv1#nvOd+~FNyqbnt@#zz`2Ws0}^!p@N|unr|*>Uj+>XyP8|Rs zi_tg{?<8~vm5}G@6O`-47jVjE&pEtiNRCQ8P+bJp68)|oTBu})T)Z4~3LSJ!nH?8p zyTC+8JXJDsa`T&`8)an}6^{6#W0x8CL1bYxFI(+cWO?lx++qg1ZkTIl{9O z+pPrxQc+hJd>_lBmof{ZFn*ep+^rQK9+xl_y{B!FkquaBw za|QxJlFd<w_i>-SQKjL{**a#{8T9t<_ zEh{Ta0dKa`Nw#+X@BwXVPoguVELMKHpsYY=I-y_PId1oB_ljEnEz*X&ipD{qQ{A)U z3^h7vO%^$n>rFaq>t+K1E*^qRrPc$m+=!27;mxa%5|=cyNCkqEa(gGb-y8z?!GRH=8??wV^W|&{W30-8aN|VcYWCCImKKu5!+GVab1Y6UqWRv|u* zZ99J;THP6ZN)Mj#gMzU{P2v7i0Y~(gd@md+K&{A{jR(`YC zsjn*|iB?rx=DqqAIBwV3F#%F1f7K4ks_wgx@T*Opc^EeC3qZqu4HXc6$a=+$@>^V0Uo_h>=l!r&O_I*X!Q= zt$|}eH(~q^d3$REh~V%T3#g&xUDSK#)3)T?W43U;PO+B^YK&jT3`W_-qquKD5}4@y zTcI(gsQhJ#_T~Qc#a^oE{1jSX&b4Zb`RKM8QI^Bb&s#~EeVnJ|cA zIFfU!0ZH!*e~Mvg&i({>B=>vh-c&@DD$IKRWbpm>YVr)(Y2zlU7WWr^;+Rj^%rA;c zv>9-o3@Y2MD>u137#PYR0c;NBVFPiBz21^+Z8z}8q)hNP)C4(I32mhx(0p-X4ln~u9K zoIcUnBY8V(uTJRge=Re{FNDfN-jI+sYaHV8-Z?o6QfrxG^6VM)ecl!-t0mbee#lZ0 zp9BfiIJd2z@9YZv*^(EnGav$Q3oiey6I#};KFK4o>2jUPLC*Xk4}~qActUuNht(rE z;rHDcG==wcO0u@G5KeW_rrbZxHVo*c7ppKOyfY@G70_^T34h2LgOu?yAb3EfDJ~(S z1t>Wzs`n1omMPoB=uO6^Z2s3D-Nb|=sp(Vb2=7?qW95&;W^*sqd8y0GlzE%CD;ohy z(aN=xu$no|1Dvwm4$sy4SovMba>cy=YVGrj)`kww>*yJLbu?sv3<>26u|*8Y z?7p^}k2(N1c43XGLKR?&UwIjOa@li4k@*wmUV6t&P`FY9Ja@`$n<~#GPpvJ++OdRr zH)AVX?X1ILIAPpwQuPUOZVgal9`m@(Ioo_eom%l-blHDQSP@CH6Ng$w@VrjXRA72g zrn+=2@xZExwC8!Tf8`fDq-3fkfJ|SS6g(PDF(lLfZ9+ZApb(}7$>)-Ou}V{H_}H$4 zV}i|vNil@CInJsKkXs~D2c2`3x39D56G%PuPusi~(+<}-MnR-BzkG;MbE){sY>R`24j=1ZgGFUJhfO&tWd(W=Gwdb7`oT& zdng4Q_Y0dlsr$spZ*Ix_*nHlisyHBn2U-7(sDx0sVyZgI&LD7c;-LxSb@dp%>J zN6lyBF>tN26s0%wRC9?fSJ+h}Q)kPH{;z8Jpw;cgdsPSQ;~mLNU%NiQi<3RCJ+uJ_ zt8PyGV3n-dP%KIRMSK(j|M1|Dq>Br)HPn$7FV5d!A%rzz91+BAIbW5zC;}j|c`disaHPQpi)tHX8qL4p3ZBu8WBhXNES;)XQ{b=#% z2MZKga;`s2QtNfEv0Vkc72>iKkm=8^h8p+cg~c?+arVj4QHlLuKHR16b0|v;jDsrG zFR#%2h;k=8_(!#7cbZhSHv3W>84`+1E*w@}kJhhJFWNkPo6#57s4$2|vBZu%Nrod} zF3HM|powR1iQs8yD8K8E>$PH172_K{?92Rk=tHTQOiyg|z+V*X>6}9dT305zaTMb< zo?E_r?Z{oW%i-x+*64isG0E6s)%Axr{Wk*%h(8pzuf3D*uS6rA$MrnP>YR1s|UJb^`Tx`NQhuOWu-Bu_cl(VxT85K=Dp zF9%Ssvwn1K(QI{zPou4d1`5Coh9kh$$v=apQ={ zYKoi$+ej)f7%cZaQF7tbh>JX4MSr0bdwWu-ON2x%yI+XD2Q?45E%T85GQo_{{i8Oc7EJBDXGHN8WhqLfJ8p%lZ``72B zPo#n#n=~`pG~^%Qu7k}x(xo~6O7Z>G||zRWgN&R@5q&Q2hm+ z;UD*Ar+YuPzC%~ODvBR;fy%A!@ZO!bJDG+VDR}UXc=T9}JUVD?iBq-VAx(@wX#duv zyI-d_{`;nA)agPmn4oU0x=AmxJG?*Ju;qH``gC^CZQFHY9rtv!AiTZ12cjN@R1fy`-6Cv4 zDc+NlHz7uT&AB_=TC(B98DpRnwYf<|<c6D_%I4n%O+%$q+(Vz6QvoCQuf9=}U#86#4ku1ams-^wv zT@7EkBh6J;bvFUe_4ei_1vfW=va+(|p}jHdKO0ChCLIGqK=_c#i5XkYM@`skEd84I zjp&a91?h{>#~XtNuP@ekZaJRsc#O3>iH7UH)AN@7oBH_IQM9DC5})6&CkQ24z0Gs` zwHDb|ROgsgURI)_<^2&r*OLN$GPR`A%zWV1+1qUWpFGV6V`bRn(YiQb!-n{Ds!2UZ zm5hoI=9KehtZQEIm8bKhzTROkTBM?`G}T}8IQH{<x@gp54Rrp?9|klB^~j2`qOm3*mrJ>kkY2-~_dmz9iRXNriM}MSnHRkL0}tSg zrUL(xPrYP+Y3Uf>;Dp88b4-%{5+R4ZmlnnY_RDVtq*OCS|=@884OGMSFHeO*v zCrS&~!5^G#)IM!gNz|~7ZfSRq_0j%6yuD>mTwN0eIJj$YcXxLW9z3`cEVu^O0Kp}= z6C8pC_rWbV1b26L+kw3KYIm!)w)W5dV=i;7``pt{Kiz!>)cq-3+D#EI#_zO`cXV2aBq#8)3sW49tC(hAj-2EK{aUm`d* zl`l-Hv;rHSn2;ME;6wXVIUZgj*%)8`d}nGRxFtKnwU3DhP9T7(zEUt%)JKls2WV{# z3JS8A`<0)z3}0#0_4(&gqOGO*&|=Uuy*fE#wGY%nApNn3^^{`eP*RYmC?3@~C2)en z08hslJqM&H7YU%G#=T@^VTK=@2X04egcJNT#$n`pzd;$>Sv&;rdFbp>|BJ>N_!tZp zkT_vc_a{_pVYW-URJ`scAS3X3uq~mckLs9GBH&c13{5-~TucdN*PEU(-W5iPmckl9 zD@SZh{cLFHPU@YI1Yrmd2|oyrP_#qd)eB=F(WBOKvns4U9~%rwK$Y3Bd(QD{e!)WlaxZK6j@d z-P^N0um~ZnTP4*Asi1`+#rO>ulwThqfaxRJpSBm6uu$Egbfqk^$sc2zO+^NQFYxOJ zm+8VlUg{-5iHJCOF3&we9oUPqkKW!gYGci+Hjvk6EJn?l1VmIUood)o2{z{Z_+UE^ zk4VIhA8sDadO2#>4xq;^>IvQ{{CErdgKI(Y{JKj|ydhrf3eE{ICd8u@rP^lW^5ht&y9# zBvX~z*8f!`kSsgE1Fr1EJ#w_8)w9`f@oIy`T1YLJdYLY#Wvb}L8e6Ox>hj8>FZ^go z_O3fSPXrD0u4YSn&MGQ%v3QRQ7!E}lk>m<<*?j0>Zthdb-T!5yxcpU_y&d=?lHcJL zsQ!B}Gy3_+SL)_MCwC{>FU9U?eL1Gt7XeE}$h-$T*mq%^P)$*+g8rR_2(PqGp{*Ro zhWtER1pXCo=A1jgvz|$6eGtZe$FVtUxH`nR^U*oC9fF^m?8TqA^27>fN$oB+tqvn2 zWI6I!j%yvb)~d-#kG&D6W6~v)x)yYVBYX~~+x(e+BvUwyvp&y6_9dl~ygJ&bv*BsB z;Re9Pm=$%masT50$XpfM8{cF`RQEf}57YCKQazzOpA2-Up+FwO+#fEyaKUf4l=-f# zvUoYv2j(s;LY&}&xgF??8cM5R=OLy9qi~IYW3`2J^)~q@ z!M$@Z?CHW`%O-B3IDKxB!EyjFkJ|+89jx>`k*kd5_W=Z|NfWSe>Cf)!d3U)ppKKru zoP4YI41n39&R^CE2@3892=V>%Jnad4e2W<2=t^n~chDE(CLm-Ws5a)HWM5Jl0nc z-jdnpX8O*$*nY@N=P)9*&;5TqU{=Aey~R>%V8$|Su_eYOy0kBQ_JEoq2}$^Hf3w^CCd{mC}1A6B*^t4dQ`vY5T#g zFN*1sPfwdu@eGP@pFq#rO!ETxm`PqJpRUy1Hl?rtL`LvGm5m%|jiDc*C##@FN3)^} zvA_|C@cpIXEv|u*8>|5ub?^?o00j0?b;6>LpQcUG#w9C-UDs7io8ttu#Q;GJG7ZQ# zh~WBn7emRR#W?f12++)Uks4VB!CTHGMvK65>n+iBCNmcP%RLb^qC&$xgLE0%Y^d~A|lYYmMEa0E5CD!kCcid)Ug;A4gjWiCQ$>2dq z!HWt=eSb%{O!Roi|BNve*`%j0yYRR_)&4~9cf9}^EI2oS3&Y5;Y#4blUxq3ZJvmAXG4-Rzoe|lWv$^qIqEYU(^IXo6)F=ki!49`(+i0fn;*P$ zrW8Wpb{)T7aA{98#pA!>jy{LzS2lx^5Vx?8>%Eq87<3R{AUf zY|B4ss5oh;Z@*u*mnTA(M*xeP!!;7v^X`Q$s?TIsR~p{e*5JBm30qii6L_jWxf>0h!T&4gf0B&* zA;e#4mc;7+n zYjDWar`TSHYkD;UNQgSpqN)cZORS>X<;cMU{LO|_*ABHNX`cX>^m=c6Bl!F5h#$VV zHt|XPZAiev`$pSQOHrU>lbn+6?3{}(_vL$MHJa2fbCghFehdI`2|hkPJgF!GI3>G@ z$X8#0&!13maTg!K2QEkP#JlO~E{jAU2V(59_?zw~XN#4<+Ka z>>`vNmy{GTD*QrVK62~YPbngvVEYEOh0s=QygUuRKzfn)t2P>&1NFJ~DK^rHpH)+l zbk!51@gD}kfz+o$Tyg9Gp@54zEjKrw`C2RUMd;Z!Z~j{hFWi%)zw9=LA^81W!8*i7 z$?(@eub7_vf;j4K%p8q+uSI8Z*7CiA4A`IBGLX-p(k+1RJD2t7m+#$U%C2pgW5ue} z{6l9KiYwzhm`=;Z{p^}{2-907ajd^jfn zJMloX0v!}@3n_=wwEo>-OQQYnfmrt1I}i%%@ zsHZ0!8ws&RWOuQVos5hul`WAktC<0?|Hv2v_BL}oX8*@Wufv6U6fXRyVFRfq`!(>} zu$TSP3Q0A!cyu`;LvTk}79cR6|5X+us$?;-vC5RUrHvN>elBtQQ6RbON3~wQv3wSn zkW+Q-(-NR~+Tr_cgI6z*S@DeOui){(G<>fY6BL|Cd$h?w`q2ibxBZ_#YYzHu(dbE3 z#E1VJQV~Y97(1{jbWMZBbIZAtwuccOoG$85dik@nn$G)Ea3F{ByJ}6jNT|Z!1`MyF zMweTHMIjclPEY(GBLfEGc2$XZVR5^L+aki_vX9a5!O`*8T%P)VU4U-9L@&uN^_Fne zzY2z>04WnPt}d;Ojh%hGP%$g4(4vtoIy6Uw05`Ov?S3#JMODvi-t3Y3NT9Q8n5su4 zoFalK?rTXqLF4Vga8(1p53l2LW(2uh-|F*v-|4^;tr<+Mwqj|nkCltc`Wq{+1Or*( z(>v1v$QzOc2UXt?LHXKtG($XcFxqa&@wGZZQORprE;(~RxoZQu)y9KYOJd)#a+Vj8 zGBb@xsvBVj`l;=gtoX?*@Vzo@GUq8~oSGx8Z%6pu<%gZ7ESPK4RJ!-1OMpY)w{xgCf2D`l{Y;FJ+0fF5* zbJ2cmjTF0-n$o0q{t`aA5k@0s7%>ksridi+QK4%dNiJ5NA6Fn`Qzkq%(~A4mxuY%? z9J=E)yZ-!1-OW*d)wQ~BcEP?Gm%c7{eJ!`{yXM1Y9(-0HwP17&!r>6>%nr6mFssIA zVH>Ck_BxZ`+!qqOgKb2jhQH_R1}SJa^->47aLj}bemBlrC2qP8b-!TeR6wZd4-EYMJE z`YV4U=lY3N*bJ=hSkQ0k3Zc?o)>mHN#^CEGYcH^k?M>sSkz5{6XZog!^w3ReVG@m~ z#t|<7+~{Fm)z8jdQ`NCrCtr%6GClsS_^b)Ne9q5(3E^-?)M@~R zZ-dr%?5<-u^n!IMx2NnNM^a@B*%!G0ji1>FAtM;aa=k{W83+0Ei7&VF$3&f2-VqxB z!Ii0lag*N?_(`Cd1Wre2E?l>1n&nQIvY*)<>}i2A+vy~0wLDbBqsnAWd9Os4_6F!% z8AEZfvmE%W$Dez`cw_jaX1LW$Sd#}}%DnBULNbvJg@6;Xo;?63l}|OdX~lR*~km! zR%1XE$v-$D_*&EMBO|)#y?*r`QkD)eccV!uev~v6$?{;EJj|B<>$m}2c-ZGiIA`_P z8lrq`($cmL@MBk=k2s$~kJK9`a1nl`BW9l619b9aPWx%f6TA^?jhT3TQ$%>x| z#kn<3l|;F|pd1r(!+4XVGnEd!$eXQ3g2fjmS@P zI2WU;D|5qBtsBz|><}zkz|nOWOB>v&6aGRU!EO`@Pw{nLK>B*x{s3q!9P$c9;KT z<&ib5@kVMcryVWDgsp!XTB!D$Kr~+kLeyHVT(gytb}#_l-XM)1=lL z_%;+ITy4e|)am=-GLtjQ?t+Fa%+*~<$Rmh33B%Y0yvDdR;omsEEY@uQl+H?ap?f71 z(c5CrdR8^GRrqR!v)9mJ&kc9~$M<7@$seTKf%?|?O8#Rn6ghrVH%low;7uamo#p~v zg@(E1BbUUaCuU($r1(5BF~Q=vDP3rDcLF$_nVGM#gz%ZjD(&ug`JKYvdvkkt0ybqz zN3&|;8hiOk?1IL+COfC~G6ttx4HPQ<;GzQtzxz!DhxaPc6|9ODDKuNCw0^S>7dtT+ z)xZws6JC}Y$oy4O0JG#CW7w`Zm#3ztKD++h=&s+tzd5mszdPFoS#}W>bi&Rn(z6Tc z_4Rcxi@g>ZW8-zmiOd4*6^zXjmb22|WacSMJC2Rw1)%}fV^t!1Z0Id zI=J-;{)-ukfgsH}KL~dGWwznaK{)N5*QDv-zZS2}A^v>;HFrlA@msmPXxz_H06W%f z`ma)*G#f335P%en@egirV7|U}bSE{x|Hpqzf`-CFq=kQ-IA}Nvx>qo#wrrX5wvAo^ zTqJ1r95^cfML0;u)LxIV;+9D^#lKBZ!SO)Tw_wTpufAU_yBIZQ2QZcUrKysH7+08} zckeqcsD8|W_gB%bW{u4ZTn5ug*tdR~q`FMHp`jrodRkFSEn2Yvaa264;OuM?#kBCZ z%6t%CPx1{sG{QIA8_0{W{(UEbQG%=0&SYEq)W~iX3dR^z^r?q zV3FyhWZY53dH%6eQoPU7KGC7@$H?_x={n zQ3NPZUAmgOdN5hjePK*=Q8u%Z5HN>PC7ft-=XgIZGSH~{c1U{ae;}HzVNr3ck_|U=O$$06aIrp1ZHcS%7po0 z!KK2}&c@`o4S~l9((F`j{huU=FKspBg}*gkdU}FjnfRlX7Kkt~Bq7FCl{7KTrvit5 zAqp&o;7?pi0Z36P!kQxIGREh@D34|;!@38@H>QO zyj#2#fbI^?{ouu7>-`D$+5l3U=d$rZeHC=!VfRYrLr~WXbLE~Aw2+&v^n2e5Yx#;( z*Ud@OhL4ftuCV$K4Jt4VIOaxpJ}<&wOrCm8Ij|lyVHO*4q#WsWHE5G}IIOmiX9=)^ z`h-f^R3g3q`3=^jKbt=NaW8cksX{H8$WeQH*Azf|8wi(NK*q$x z^rQ4yS0aQ+)aMTu#`c1e{&K`Q8-|h~-{!X*bACk?H@VfRac`byZ$4zgd-wxvp@1Y- zyqkz3A0>wer$CmqGv?F71^z0h8TH={Jj7iUsbPWySF)35-5;OM&U>^p>!0|oeZIh5 z3p>#_3H<7SO`dDU&V9L+vcFQbGhQgqNXEEhmiIP8Naa?|W#~1>-(ElZQI)6Iv$*ib z$ZK%Rjmi_f?r1L1)EDP#;|6hOrWnbW8@9`*yCn;`HkF%`zLG+|)p6FP)5k(;By*;| zQ1nm72EhXx!hMG}4^>CGGvn(9ldMlj;nldG6_iKUT8|#i#?wZP=9ZouPSRRt`+IcQ zVbDv1qy?R!i|xK2uNi5!rWwsXB=emCmh)T>66O1b-aY&{In8kUe*b8(rR#OQF7Zfy z6u_!~NBVk_oPGtJ8v;2~(l)Yka>_ATA!FGLkXtt5G9z&C*ZDNexprU}b4uw>@cj#6 zEE5+R7<0>d@OH=yX|u$wo?paY;@grRZ)HC_@{-Y)I}sA?mRwJpPq17KBi$}l3N@^k z;GfO5t2mIW8~3dt^b6h+C6dCOlzHGmc({myuEaGSUa0mHZjU~pwIF_6by?k~yxq90 zYPc^E!r?a;%xuNW{s53#hZ<62NOywSdx7~P*z$Eh@U*b;yTet249-KdXHg~+-@`XM zAva8%2FURKnU92?hTWH@Zd+J};`=v#X%2jRU5hpq#@)4o_AW02ZtKMqUUfFnPy2ef zN|~OgCaLc#KmQTjUC3wmh;D%?EdW>v&-;tPpEtH3XJbf)@K+FAvn+|x_QqQg7E;SR zAJ$>B)M%g}-cEmdjM!%v*8Z9^Wj`r?9FU9CUPad49fd zv8F3Iw_bGKP?g<0YMNp&2y(JvksbqgN8f0Kzs7Z1SGG2Hi&`Jo{S0FVn6vo;>FXK0 zW3pQHIZ5VaBMiMiQrB84W|F7nTD^zyqFsTCooAiCRUnkPW^}a1uDm(oSiDU;P{t)P zi8(LLD}h0*I1W`u_MOTQEPlHFN^e=!F|c;9Geh2KD=JJrezQGZvvG>~Ybk27ZP!8) zOgF#3fl0(8%6%YrDtU|_*+%<)?gwiEDhBGaVghXd#VYpDa`)`z-tI!|rPq+jGCt3d zh^@ga&waKzr@f%iuk$I0la}lvM?}nwzle49bw{Q9Ssofc&l`y9Gi6-2f1CJuV>s0A zcW#V7Lj1yf?fp!!#jhmkq9de7nYAF|fBVB|^k}hg5Qu>{4mYDOzVPx8P1>wxC4<7e zZs_|sl`m@~BZRCv+%RY8)$D&?KJ|m;AR;%>5b|Mkc}d(~H6J|hi5iKK&K4}DWxgIQ zzARJc?w8R?q6;vd9(BVuy{R;eElbS;+U96|?DV&V#zyj!U!H>!8$XKF%acy`_kyij zlPYT|+>!Lb&P*G-^~><~o>qDWTS}gmvof&1={E+i9=wJlQVXHMa8iPAl34gX}A*tj@-+`9CqY#qOdjs6-V^^>Uc0h>hMt@G=tS=4H!k+!2Q*XW9v@HPuT8jx7b6j-h>V$B8@?u<8?{s4zwP~YlICx7F_6JGHa7OE z0tENI+cZWpho0<71?}XXK5)|H!T`p*UX;w}rF=$wFw%z#KAe7sjn0Mw>?#8O$JK@q(-&P(tXdxgxv%N+`_3f*nZ%0kw^&{Ws)_^Gb^S zLermX{jSd(k+evJzbu)_gSTrA2p7LQ(%&=hh+d>)p{J2%hp?=k)nl(~nDpj8ga^ZO zFF){Yzr@>8uhOd$8(CN-t4(a~V^)1U2o8OGquY2$R|f)@%dDMKKt&-u8q7oibfp5C z--~}`I?d_s97t2{=uTgy4|&Pe+o-Gmp&NWkWYYUlx~;VG=YyrC z&sbl%Z07y4E_di0PKBMe5zoU1$8(%CGzt=%epgeYVap!fe0cA!OeCoJZC!xyd1!6& zCCKz!1gxa>Cl*1-Z!2^j8=XH;rw^DL)aLQZwCk%c_e#flqe%*Sb1r9%=zsN+hoJ>0 z!y?#Ng27u-FKX#j^s0R(H`ru|AoBm+E?Tf@n@;7FG%e=wVx5DA<@AGfbD|``8BP7d zW$$CWSoSeo{ANa(TQ;um2VPFj+WG9MnWQ_k&8LSO?#oBF3qpQZ653E(-20f@>rWtV z9ECB1TSi_!U1T1VmDC*R_3pdDV}^y(2%FxBY12=(PqKyk9=1$Q83yTUS{3w-Myr)o zbj@+J8CyFxK`QY6lw(acFzJHc1kG*p9~4)IzRd9&+|^smVJ-G1VW6W&eNU;G-Mzym zzg_4O5Cr%0`8c#^fck`>KE$!__nfsZq0YPhZd%;OdvCfavUzpbHyUUOUxoZf;Yg2G zOpNwahk=d2W-)Ry!K#|6a}PYacU8^&n(S{1%n2yIJAZeqs(mj_(xUa%f%9Ytv$bBY zx0h3jh!9-hwhK49ZMiQR!gjg|sUhQy3<4qde>7~C8PIpN(4=rEGD#6RFZM4d%V7cT zg`)RnMBYf*vF=wCAKJRcruPrU%fC7uo^M{js{{G}?sWX$eU>(8oYfV7EY|&4{{J~4 zkbc0F7JxIE-ffWIA>bA&m*-zz{{Ltlw*N8GJ|IF1&~Au9{m-+(!+Ld$e%{DQ{+Hb) z24n{LC#%>I>k@x`EfBT*%Bcol`3zY6^Kw8#F#sL|l+*tLe~@T2AvbwJDEw(~bhPiw zig!pv1mfoAW&?qiwKW5u%l=o}r6y83y21Q1nty#HzaGl+dB_JLD8#`apFma?o(Bj6 zr6tT!)Y7u3Ns`Xz0>4Pb%iD-7rN^y@4T{~dQ5D$oCF#F)5b5W)2oCaFjLpob%3IE5 zbzSF7d%;P9!PBS1v0<#c>J|%%DRp|aCC~zK@!7mmJ?1A^aa!Dx6m9a~^p#!pn#&~U zK^-0zhDuC)aye)~Om~7@$yi@JN^5gwNFjW(Vu+8oKv*rQ*d5(mduqAg(=*pkcUfG_ z@s>`;fd}r00OB$dIy#ms`n)VvqYDlfl+fc&e=pd%&Ha(A*APRKZ9iMnufuS9)xU@d z#j1C=Wdz3lKzjPp#TQNigL#~1_z4z9cRck9J?lfB%B(r7FQnc&rrxKA)BQDbo{B3i z7$*I}M*#tGXOF>wm|b-Jv%zyF@l3GnSay<3@Rc6gY;nZ10W~S!k*@T}+bU@Yv!{=F zVM5=j8729`X}1c>fUB(4Rc_Zf;xCWa2(CeQ)X^Eem8nm>+f}YzDir*^g%6trFx&!) zO)Ou7po~r<@}-BM(doVT@JFG3CS!cvv@Eq`x~{S6;lP_gBw#4A&{eL?SkzDG2s^UR z4&)^MypQt$v%szPi%7TaaP9rvBe3oPSE|G2l=l z_#n*KRbo#K!>Za>#)It*|A^<=8cxjiLn15b(ifWEdg-pl7Ic-l9ah_^9k<}#)-MN+ z6mg^cNeg!Ty0f)7f>Og0Cs0+1HZ32 z!FU%kbhUgy$&t#ll&EtSm}(Q=?qdL|r<(737_;OHQ&lKXi<^77X&Dhe^gma#x@{-~ z_FewG+g-UQ%`2S_ET%7ha|9pXgARvhvN@3_hWR@(Ns23AjEpKv>NbnrfpLWNp1+R? zaW`4m5`Mb?a`$DI1|{X~=+9V-gfaLhsVDHj{%auZbBQsWBhQF3e0YS!3>r#qOAF*p zUN=dODhh>O?6MTm3fzH-^=D-cDSGnyRO`U7 z5Y|s3!p<_MkI2&j8FKark^d)Z*Gjk1_hQ+=KaW!L{8W?TO1gt^)S6}ceHx$_v!V1% z!WB2X%c{U+t^ay=(w!h~+otoK_`Jgq-TyP^i?W^`?Z{>~Nwp|U2BjA#xw?h&=erxJ zD?#n7nGzBOHaO^{y7hnEPk^eNCYAsaC>rtvjKG64Wh2Z2`GkFK&9TyFD4ciVw;ncl&`a)ubnPrSf%sHZb0}aQ zESXFu=KhH^HO`=4ia|kQy?44cQPW5j7W_`iK!cT=7(0C?NAuN6=&-cN_*_kK`%wFu2vgfv=kMXl09!Mj^>}G2uZ0u+L27hz+M9RKNhOjHU^+o(%CJ1E z6BUaA)c>=uQ>Zu$vn^4KcE%4Oea=ITfsTt zE`zEN9tKH1Yv=CCtQT6U=C_1D8Pi{ijneDnc!7S34y73)-12Lf=Hp8TLK=m&;OK=z zi|l#q#d8J+I1rQgdRjnU=WNqVMe%O}Y^~z!bVnORZ(=}M_txp{$$<#eD8@Y-?d+}q z#DpUfs_~D$=ZCcosOaIdw^+`CD9(0$!goyE`Mjl-j87C$Ya=+4IvW>KBi+F@-}_r* z{HNLP$JkNKRx4Ld+!wy!^HHvd)#DVb?qM#(xUW%gF=zNU*PmuWV)rhmY zJSlG;>IE>e!x&d>7#jBm&%w%O+7Q4-G_LnKPiF@EM>F+w{MP+cVAq>hNz*OVifP{! zG9$?Tpx6KKsK%zXE`ki`M+gJi8NmpwJLO1n?v5lwl!XU<@XtjrVh2S zI>#|Y4p>|J{K88>7@_cSNhpA+YR!WCkdz^X4}2qzAHQ>avT)+cHnr8p0!5(O0nJCq zkwAO2z8;sun-}XTqHc}Wh1iGr2rHrsSUyx~xZ^JHSeUCBkY%Fg=-JG=bYW0^qjj0R zBC&xZ5+{C0HQ865bTlj-XJI~T+if!2M1cTNI40Udn@1>!625D=z7T9g(aT4O;vMcE z;4r^Sd3%|t;Eb@QV4Z$LCwc9Q(IuDoV^bG;1zUvZAylRVALfsV%Bb>g6l57tCR$2##jJ#~yPF$2}sUA7h{znC$*!4$E z*(&y4uRQ&^t%(^Z;y%wpz|xOZU9jL`A2busB2VbSB4A5PtASyOxnKB+xSt6> z`$#y@vVJS>?GI4wU_y-A4_`puG|`S`@lZrS6IJxB!OJpl4NpKV@&tcu%pscC)K|mn3-E4m}&+ICZsX3X@&F0=8%H5Bd_m zqC`TGB&L6;b?P-YW9o{Z&!GihXMjz^+C4^hZ?70(JS$3ZOA7($67;`$1@%NSX7B!2 z_GvEzk^|Ejq`Lc=7*+Yn0?gUjnL=PYp0d0=A{jaP+15x!eE(1jz>}*DX`$96#!)Lz z!)Em88C3^)3*_gRROv@6EY=~I;G*k-7}22iVD8}4`M$S+0pN^wtulk`#`+jDXs z5#zip>;V~v?TxPpzrotSOuU5|UJD1r{jPR1&bJz8LAT(l+PZS0;ud_)+%fXn^1VXO z+lePFUBALo+2^^1;5xkBIk*nBzNK#y*ttvZeiPZ))T=W^)VeWpeAkTkgV{#+PL*$= zn9%J$%8;UW-k@6jIQvwalXpRg?|F}Hao-{d=b>G*oq2M(k_D;#C9ApWI->{EC(CE& zrTPn%y>h|<@e6Kvb~a7Qc3Vsg)aSV3MrPU+su@ng1IcAz8p6DotX_{wbL=+9YH#Vf2~YeTSjnRURGTz&vt`gU#;ZkebD{ z)>CZdK=LRkzMLdHkL>Lni+&pb#{x#Bga&R6Q2UygpT{WQDcp43QzA)B%C=3`hVlZ7 zZ+6{-zb4}Wt^n-e*cYkoA0EyT7Y`W`7<;S%TQW$7OX5`i)@BcezdW%z4Z5&lr|BCr zFftr}wY2H0eH=d8Vf05jMK>Yr@KX~tg;`^Q7qy_5Vs^S@^};_VtS=$bpx@8X$APFo zS*&`h)nicr-yO_+(nkDqBoG#u^KMm*)Y~sP8ro$3fx61eoWXdMpr>VF=u}t3KsScZ zQT5!#Bh)}|xm5G!2&%hRBIick*G++n{OfwT&kL=-UP;HcNm8u+8I5jTTR0f;(X{zU z-`Uc0@+B^+`!;qlBUzF{XL5Gny_*m#7!?qbPRb9-Z_uH1rjg_9q00YrgZtXb+FU+F zljjp*nz!H4N|so;niK0xJI<2M?2ixOz0MptCizn-PYn-F+C-X>^#-`X*JZ?g4UH#8 z9QjerAYV2^$LH`JqGu-(gucheFoatlq~I%i@e1r66JAESLt)R43SsAk)2pi`ra=6* zT}ga2&q&{_Pc7kH?fX)@9--mUPuQvbMV-Sd3@I&2Kn4qI1NkSt+_-B~qnr1nEg@_+K-$o>U zoJd6e-svoSeESRx*`2IK@NjPpG_mSkTQ3woXYdO^^-KZ0E8_8=Fms@13U!*|2cK-> zrqwR=*Ybey^C+_=CgnS~vtYu4hKILc7iGs&HYa&bPBnvhJp20HH@2mIv=AWZzo0^s zj~#U$YDL{63AqqLOQMKv5L?sW1KuG;douoI)zgXHu{>lP>U6rCNB-1T@*Ke($#SZ~ zd5bBqgmwbiW@RyXsf|`QLPN#N;ZCJSU1R$?WvR-$fDB?-{o9M*5|wwr7WQ+nOsn=j z8O%Mo*YpDpRcj9km%D;EOwV)J^=L$1W!Wcz-^EZ5OwM!{%mk%DPIuDXWvti0j*=DNJU-ctDstB@OT9s)%2Kc@bniO{**lt>euH&H0XcAkrLS`KDaf+AKo7fM$5X*ZTh4D=T3uX2O9A1riB( zWSsqZftv;>Xt7v!q2fuXG@+sZf`=rtDe1UjL}}Gz$3Do zrGgcQ%ZuXq-UE=Y8EH3)SGY@0G9RNx*Hr=mJQF>QjSJO)4r=Va702DjXB+>qbtZflza*{tc)J>}3QYWp)>2zU zemc#*ESR~s!*^2c&Z;ICe`=$_R{urO^-)1_$%wm)0gtpOV57$Dd+Dy zUdfW-aa#K&GU|wV?Tx0t%kb6K#yj3#5???zc5L!UPi~vhUg+p34{*VfgXRsYEGYKn zAIH1ux7-_sVVv%pAJJ!(Wj26%uYcD0H89XS6jA$(E9g&&bozE-?d~e57=mvL!Rp-^ zXPhs<{>%ux%fkm~9S zj?QjRE|H}$K`LaNyvzhLTT zt>6zf!ggKi*m@3zKQ*M;61t*PHYGLRGldjDch`1!nZ3z7Mg%Iv1v7qRfL;Pvmy^Mf zS}}s=9fYyojgsycxFFxHpNAU=Qw~QDgiIFkCI>=`cv~r#D?X7K&VXmkPgl@6*u3sq zLdb4BK7Nq30evt8mj`yjR)QHCA&pGGDHUXlNk9*PH(;;-^aB}Z1PUOu9~2j#M#`(D zer<*i@Iv|T&v%s~Aj_?3nCp}PI8mqD%d6m8PhxCxCdcBC6bz<<@Y}z4K55 z0|WhogKRoAxw+)?^>)#HM4pI|c${o$iRAwlfo11`0S);|@v5LYW-QcpZYUd;IxyKrv%mwaubK}5PS62b5 zAuPxec(Ll6#qmSRCVaR!q@O?J|C$MtzsfiELJ0Hn>Uag&OHC%Z3whf(Qc=bG8Id=k!m(m%McfK zB<>L<*Xy-GbDX6~Ukel!Yess!3wC4fD2OgR7_#AVD&f_9}JJWX!Hl5rF};+h+3s34i*D~`f!8l1P# zx2(b&^_essmCQ*N8%uiqtx|g7F~3npT=X+xh`RF-RKb>(qrBH$r<8zt`0fL7=F(CQ z3RvXBSKUVN{FPhoj_wdk)I%$avW+<;LFUb=%UzKh#v&P~x>MH$G# zwMr+3(oM?B1pm~z-D&z;`6pd#VG#`m;K?A67p8MTcw|ck(^Fe$xYuD?f5~PIyOu z#3O;dL14u*D`uyXz2^?SgeO5jq@dpBCt1Q17LI^gJu7)lypRAAZL#cTTJ24If(Yj2 z6hQ3MQ3f+A9%1muzVD~eIfD6)>G>-^gt>y{Fgu0aF>NV^T89{l%*uNst>+74oS+X9 zi`Uu@;I|__Gw18O9MB+h5EqSV`7y8(ihQi9s+S5;K3QFEy&HqikB{O)F4xTqrsF`K z3~9<1Ifx2^38*xhRiLog&UV;0rLFy7;>lA(SN= zvbKG^J?lXO=5ySd=k?h2W{K$`K_^RjjT+}JZSR_(t_~f=(9$VV`a*f{D(KwO=&6!#LYgPCXvcXv;fd+-I|rDSt`BBl`UL zXrwZ`YQ)Af;ZpTD^tK$;*Hch+_+#y0m>{UM@B}AF8_d`_Q!c~EE`cBUN*RZ z?wXLb+SGpU$%zJQHuu`+$9z=_YOBFEtRy8L`!NIQh4}>qN~_+U(iOj)>7s-Fg)diH zR6mYfJ~K$UIPUoe^3C!1q39nhXKYnMWIYz@P1Iw|#h$V$9?1NP;F-J%#NMH`izM3E z@g=lsvmhhjXNqPB0sJ-JENzo72r!W{l9NYgD=)6PzG~w^#0+la689X1 z1Fogiz@3oTT5#}GZ`n9!qaeS3OqEN!63hEwPdvFT#NTIT?}%X*$d9+6quRzAKMF%^ z%NK0LT~2B?#3qjb5m0cI6I%_@6t+7m?!d5zS58UTrIYDITfy>v(Ebl0i|%_*td?cq zHTyt==)I4C-froadAGf0Xd?fGSfedislx3zwV6L+uFzcLy{)7*iCN^Ex8Or9;FUVw zNU0H@tW$0fMei;UB6V(I6 zszEZeh!M(~jVT+uL;|?9)YCkRPgr*{ zBlq;My$Co5wi{4fAUO#Fu;*w-UOM;|dikRnj z{ftPbhbuJLTM7O;xckUplPjr=CGEu=gDk2(yz=Q=;?fCE=UTr-Fm8s7))|P&A`c5g zKL;9o9eBfy*o!*(g@twnP6>_tUygzEO^&YLQwzpgTUunN-#-!p&OCHLzaW#(3`k6k zA(Pn2N=&5sU=rRAV{Z_})wqR$A)U4(`$t~RbgOf41dId7ykEmRwu#jl)uyQ_5Y}eN zFo4kvEw`Cl<}OC{b5}0JxX=(vPeB10zIgHr4Q(=oa$}q||7=@UxO&)@Cr$ROh1j;?d2c$WW6Q4~&k|}o%Gu(agJN|oD4|@7x_lhtt zsOV;KDLfK<6Vf!jr(Qml!%{`EB zT|JEr2FSTIwB@(81WY5Hp>A`uPurcF4RND3;)tG~(?yzHk7DBD0xot&#UG7GoD?D+ zb!tCD#qP8b;&NQ)<8g90C=#~Fn1A5kk_#oHFLq@6fThMUwrpJ?x0P6;rp)_?qEPMX zXn=<{Rd>GK{x-_C?njF$26o5H+kTxF%kBo2)zO%Rdd$wv$@ngvv`Jki!dA>59QtV> z>vmkw++&H=Vh=&RLBWzx5GcpiZ%1?6+Tju{26t-AtWF;en#o<|M07y z0mRQW&(*}2+bgjB|JH#o%qw`a9nqsOQ0P9HiF4rQANpw)iO2urqt*RI z4WXW)`AWaFcGRc8$eKzi9W-W7r~vRFo?fQXT{?VO@g@KSNbxu<3{}!V7?YHq9$}`! zAf*2yIjwoXIT5R9cv{422f!~^$}^MnhU(zJTOgI-ET$8-Tziq6j~8*Hh3<m=5uDyv3pZdvHWAn0}*t(L=E)Ha^197XFOCUUjggHv03 z8Yx$W&R308I={{*{MavqsH8zqJw*Vs_*b10f)%~h?A)&7bSi$YWJQcuupsp93pNCu z3a`SO#j7*~$2@Uhz)^S6XszM&b=p#=ie@;eC&$lIu3?YN%OGqv(Nk+72wIE}bh}6i z8Jifu8X5g9aeIal=ET;Wl*+B~;m*wXf!j)^Am#y8=y99DC!9;a9j6A08^PsA&5YvO z2JRA)r2&?MiW;(OD?f%^`LZ916zKise}-BZos0{i=_=+Yqg@IR`mieC0`cJ?{Bmgx zzaY`kVCjV@h&~Yl{`=V(`_kE#VvUGW58u7dWmUHw|H0lnMOW5! zU8AvWr()Z-Dt0QiS+SFf&5CW?ww;PqF)KFD&hxzWp8tI3=KpU`I~V(Awzk)rd+fR9 z>b;LX#tiFSmwlw$N5eRAhsqjO`tAgDq+a8t810A`&Tvn0yn9<0KEh#~z^fjy=Z)R& z!%PqT*5O;Jc+TS6n?zW3%zS$4`#WS~=$`P6U~0XBZk|W%bVMES1gIba9*43Jt3SzQ zTtUftDPe2=Tfh6JlaXspu`uLMg87z8Q7I!O^qaRIueXCjIbD#q7|sJ%9Fwt6jp-R+ z?00t{9?R&7cn^q)f4tRx-G`n&G(@I14x$^nl2?7q)|A;e{Ng39SFy|u7l&Cz{H%{< ztGxcIFdK#`oZy9}*Cl}J#)ngDmRIX01Lg$@w(H7+`RLQGIXC>U^@7~#250k1GeFmf zgINz#aCxgI2O<^DLG|5sXF!bY8dlV6;iSd;xZUr9NH$lb4sM)1t>W zu|4U91Rqub8$s8x(>ijPSxkEUel47i)#Ab`coz9>HalP5tBZU|$<|2OX$ph;8P}`& zh7b|;4=Ir?k&n#UP_j%fJNkad%*|dqkNyb_m>0m3Evf#5Th(-0YMpply}1)!XKrh- zh#Xe_#hvdz-V+a#8)(gUx`&hPCH4*wnQ}sKKjq40M!kGd7WaM8@fhzP2J$TiJ<`>N ztl$t{-4OkO6##kFokRa)r5w#NrnLP!F71hlSBpc$^8q=9KUI9dy-kkygPqLXN?_CT z3ft-A8P1d*p~$aaa$z~&>VqhLJzD-&e5tCEh(VUM7_D!G6|H+N=CUVN(3R{>Ej8L- z;wp6->o)H>>-C8kO~GVmhJL2$xu&UBFQ!3zNn zZV2ZC`e=0uKL3?Ne*;V3^|m@b8YRH+dY}5WCH>k(>wi^`rDS&K6C8dfgheRziPtn) zMb$>of1zVR%S5l11oLVqtVZ;O$&@TMLEch0S>SXW{YYHES60h!hpkA;VJW=9p>_QC$$dWvzy)XWI;g2N{8Q3^B|>`D|KvD=GmRq zJ(~FoOdgq6Gf1WrSK-!s3|2D!_d8;;#)3FrvbgDR-u)}J z(r8&}pOD;E;)$+YmbSYSYXxZ<2Wv@oDTp1Hve}QIV)SbI)&83&hnAMx3K`rt^g1|U zO1oF4G^$p~e6O9QB5)?_Ln^w63{LrRwitwghhEs)Z8mwQTuw7hO{jPFsgz8wr>5|6 zQ+%@B?Zr&Zm$VS!Z}-dqaRU8w<-mkHD-2x>s~g=5WFi6DH6MTTC4Td0U*Vw14?ATCPq41uuA_0ibk z_6AXvwFR;zRUR?Ql-aD2r^H}KWyqSgHZsu>47=q8vb7;*281>m?t!nl{S9WN)l;C# zG%2IWcEhoTm3y;6FKQxPYWaOzTjVVqhWhQK%b8ZEfv8AUzRoSW3!nr??>?k2*^_&v zvcjS;7RHpS!fHq5O-4<3P*mtu~l`GG3SAig3O_C`QtQbFnj>iQ)t7tH10(!ifams?2pt zbVS<4XJ!Jly^e}`8V}TrKbTHf0QBvW*d`VNS$T_{o`|qe?X_aFIvxfq<_taW7$vcANa-}sItP4JqRZX z&_Btiu8HPGe6B*{-*#yAXr}uZ4ubz5h+UJ*Srd5Fa<%aNQ|mow@gPHv!eJNuAD}(B z-Th&vDIlV?z;w5vm5X)34wQ$-3iY^Q1ReH*{k{fOG=l5KJ%Wtg^;-(4Vq{}x=crsi5n`p8z=Qj#Kyq5Qe`}Y{nrEXOmA6%V5*L=6(O(a;=GgdAQ@l z6`5DivahyxT*Igo0ZBfsO7YP zYCGbbwRq=6H>nL(sP?%~0ay+(T#ziA6Y=ZDvrd(b2#*D;uK>yOvuvo9IvE%q?`1b^ z^7f4X(o10`z!BhW%)1SzW@e>eh z1UNeX6-c1~1DD?a!S(+tk^25oQ>y<#*yKGBKwF@HQ9Nxd;6@nBN7^R;;%j}7R~&u# zEzn8)0f~Q@)91^>pY_?0v%O8o&kX29oToPF@0ZIyXQ>*V5cHQvl;D2uytsb`Gy!Y$ zpBa=W0cN8@C5JKeA7YSWiv$o;Z5vRnM*og{{oLRRIlp0jBHn*E`KNT;HY-;__IHGu ztY-_jL@DEe;_Q5*{c%58FE%41vZ8{vz7G!{f40lpllOkv$oyAH+)4x9e=p1lc%kEP!tR!@hbaNSNyi+}I!saPH|l%E20V^2@d3_edagtFgUkSBa`3RXZ` zVpCoXflDpG=1J%=8;WLeW>%5T<}aiWcMbua#C);-Mp|8cANZZ2cyq<|!;&RMk;12W zVc~lUx_jC@0hylFxgUv4=6X}SW3N}~MLQ1JG6Sag!VHjegu*~`{vfA;3EYC(imLop{O+Eh6md_t*W8zJV5N-J~6fP2N*G6 zUK}Je#?&R%;H;Kl_cuMvY>XQFF$A13K-mjUk0kU~=<9`|WMY&ec^^;IMR7nM64m+( zCHG^L2|jnLL@7xxR6Co;WP=gNFy*eRDC+j8UX!pb5tRZ(cXV`(g%08Hg1M z#A9QJKJ{Nefrl)4scNy}>p|2Dnh^3d7_+S288FbFTzz0PH79InA-q`>7q~I7Qg$fh zg#27oIS5E4ZZXP`)T-*Lv^JAl+TPR&#U&lg+?+IAjeHQ11Ya?Y*`Sggp>fqfcYko~ zF6h!Z8QiW-c!Rju-jj)JXSc)}K(QaUB6p%1C>X3&u?YeiO6$$z%vt33sOq*>m1=yVy6qYPkRZhdiF{HncdS2N>96eVd-1OfJSM+E&hvJ*s9A_ zns_}>h{LmbVa3kq_Zqu-VnH@&)FBx^0WrH}XQ?rNeg(i)YPMe!41w2D{VpR z#7-SA+P*{DsObM!lP6s~3m^PBU>+%@8SIbG-^=ES`AGOBKQKcv$;skzwnSvcU|FUG zLSkFV5RaYVmww(b$ueDJN+g!dby@^LddyCYmU@ki42st?#24K(lu?N^573Th2t!E~ zT9nuHO3bU5Ow!Gx_^u(|E*`=7w>k$0XIKY|fp8b=u&A{6W z-ry<12JGPAl;(UOzRJLa`w7-KVbuVM{-TK{g+;viLH{^T`p7Xu{6y0;o~v81P#KT(AS<0{jbbS8803VKtA3;~8R3>b5v3D=ipS^2H~jozV^= zdSh^9p>>F#9w1!28vNrcgnn7-0R%;8V8u03_wqjZ@vxErHV>0*tjlu8i?QT`=``3B z76;_c7C{nwi~L<3>mn+UI!~Za@n5-bpGO>ORtM7$a>Yv%eg~GX^u?nqHPMni)pfroHuk2G-9F2+^>>dH5B~YJa zS|4OV9`H^*G1In^u5pI&k>w0=Ys9fU<_ustA$3nmyOopZ17`#DZ=&LdSQE&i=w#lsh#$VkqV_X|ae zI4b-coL?iXcmjC6#~G`2m{c%12{e)NTF<;A)m$J_hy)P^Mbr6u%pP2(@Mt^eY!8Wo z=D6Jj69ng30AlmN7m<8_j|UXiycmwR!}#SCEMgnDS2uZ-GraWP(Kx~Rs?ee57xt%_mUNtTSqVweB;02B(rWPGif%#n-c zDEnoe_8A?L5Q$Xp$IX~P71#gum9W<7$$TC6aY(8L7)vl6n=9w$=Z~3mod4@3Ar)T% zV3R^>l6M3@x55gO@gyX@XO_eNBm`Ih34u$&O!g4*Wt?YbKR&z))S4PD8`|5g@XQ!- zqiJU*B3mae4o61bOJ$iEyE&F2mHe37@mw2V_S-^XWxC?YQ6c(C0!~g!Ho9VdQZ13x z%Cn>K$ibk~-Ln!pc*R@)Tq3|{H2J)5dNLTUOB*eW!K^kT68e`K$WAM%@1zRvv<$#B z;^iyqvU8FBSt@pZPEPB~6_;B780nEfE;~_B;+FVnHyOL*!8Z(uPBB9J-)9wM|FQ~~ zKdVG!WZ;L>*&&bpf(IE`PtBGKFvQcKu8a5Pi^Au;o(AY|#kyh#g0DiJ<`ymM3b{Ft z_S*?lMT-mQVP&h*&p(ec&`mTF4D>hGl}PE&$yN$iEsJ(wU<(+i*5lY;!#aM_x3-Xb zP5uM4kbwJp3WQrZ9U75p>gyBU+qOUnXVs-rl(>Rwb! zRF0_v*hc&(+o)U7IBt{fA^6kYP~Cn~fAC4iaX}2>Gx7g}!hy;44FHg{rUv5hw$eXYNRKlsk4n#d7^A2~J?fX6&EC{~h@com42&$qW;di@Xz)}dLmn->r zCl96r(Jc2hHSJVS&p_tF!WN2jJyBBzC;U5~9&Z$+d>#lKhWk{|Qpn0QuP*H8x0^fAZ;{Bc=cskOE6a zE81VW)))?mbYmHp2KL_(HW9$R)3zrH|C)hHR6nPuI@vq+-x2K3d&8O02mL33BUnic zm|mqNf?Dw3k;zY-w(S2TdjYx$4^*gGof~_7ITrBwDD@ERb;-wO zrziTvf0rCJG-Y=Gb$u)K{*voAUQmTCt(4P${8E7F_kaN+AS1Z_kMl3 z`5O`$K-7A`&=CG>l-l|vxBp+dh{nxnluo`b zqDf|y8vr{2_J6FwPQfdqZzMMvOiqg&HBcGto7KZq5ms}NU|GH4HA+zLGI?tZbpkoN2fIN02&bx zFYU{!lcMS|`g_Rbd=Y>>ekxS2t9YDq{5}yt++zpKOL-mq9oE5cP;`RV8fwNCg?RgRuC9F01lvm1?`=2Az-gk*BEkSRqC za?vX)fN&GoXlOQ#$q_2ZKJ7jjtfD^LHN^KA1I<7K4gk6iK>`Qc)h4*QVsyl#M>J3^ zA7!N(n+#o&WH=R=do)*3P`NxKRf6X4?-)KMw~PP*v35*=Sqb^LT^`G2uE*?2b>|># zWI$`)NZDntPZrhzlMoPV>RtN_Qv=^4XGBIy{Omz=4*w$N0-V)xcrH`V;D;7=k&65L zPbE+UQ;?q|_P8&?7&$uaE^S6bFd5RQ;!Ld_ZnRikK*({q!H?*1mfBo49a$a3Ajd(1 zUXOSUu&a9&1Q28i_kpX#-D}H@& z2%w5W+}z3%RVT|#S$t5S)hlUcU`pgL)`e>F;>DjANjwdgdi20P22d_sO^=lKD}p&C zTExJd* zPjy338M7zF<;69Bw6rhzmbt z>D`)@E&R)^$d(q)NGB>T%c)}ij|=Jd0G)T%>#UDm|SNOXVE0I6y$mg0#r<) zMnhbBvY~Ce$tFWhK`hp%F{VzO@hN9DAg#V+aopGWn|=rVQnOwtfKmQx^jUJ{7y42h)vds`ovA*jOh#mO|Xov zQz|mqa`^_`$5@8D!ua$0U@}LxBS#evVc*0vVZOQc>Z!LF z^~XzEkY*#dCty$x8I0vDieEwK0oUES{D|u0(-!X(8D{{0^sLScjy_N#RhviYoBfz) z!9NM%Q-mGe2@}mTP!kKfl-CXN#N>#)P8Xx~!;OzKpp4{`>EQ*Y+lWcbljfl?;^vWX zV%L?rGQ6eb@_sJ5A8KUNx{4j4*llu9kGz1y`(Q%88g}VnJ3tKBj zQI>}-DT>;=>?fbI!D16=yOR5WU&l` zCgDTmX|`>cJLkf%Sf$LvM_1rG?To3J-@gvTSOd1T4EuBF9a%aWEO1q%9JlAz6`R+Q z9?=1vjfv;(WY95GSTs=!nPPp^f+$-BqMCw>EW^x3OALm=s6~6GbWhHd=h3Ri%^d}c zs*m{?Ahw^g=I!Zt;jbpfsn1?7OkWSj6H->Iao4kafHj`L`}!91^=9hLzoNdy5h|n= zFA*h~0xKyg+513F0>!2p$kyi73$#AO`w;rariNrAkoA0HKB7U@3nh%XDC86SW9h|G zKa-Vd0l?%b2TJ+5hN!=hE~o$!9>_t(DwHp^_bP>AU8SCoPQ3jZBQy9M3cZrgV2N;& z>5>Lurb-thM1n%>&Q``zxFTbJ9PNG4YkR4!Q`q774OH@Oa}-SNf{V@IhPI<93T9jB z$w7;o%eN~u-V_cf7vy>3r5zV_#Qn&DYiu{ZS}y}tTpjCaDm5Ij0qYHJhzKpxX@_kD zmydg0j&)C=$uiK%8)LY$5IqbLip`fq=q63uQ>TSg)5i7K1TtXB;a*37nJ&YBF88}D z6BI40{=!E`U=Wc#ER}ZT+f+aMn;`;)?UcEkP9%G6m!WLNjhmpuZ^x8-2XM_I**y`{haATyW$9>4ttJe5X|~?PzE6 z)%3ub5~~=rruOW5P-c}FscQP%W0D#~ZM)Y0xb&_m3iSlnF1wNE3$Jpuz$GpAgz)Wz z{24Z^F`MUYk;&JcNvuEj+wSUNuI8wDlR>f7RwgmdqCl8Wd}3TOE&85_y*O@1_ha}t zA@vBH=ixp{{Lsk!MsFh3NQ1{4=|Ji5+d6L? zfERMDIkM~r!vN<)p7L{W!L7${r`4K6{W1mGpaNWyBA?V0ft{bazq7j};%aY`YXMXmXM*cYZ7zOEx?eTHS3NkD3 z8*;naWsF>JhZ5oS%$bfwoU!2l_QhlAd#r#9t-8Tm`tIzml)MbrE7T9umXl;6Kjz(R z?}$zF6tew?v+c0jdUeCawhPAMW?TMgH8Zo3!QNHfS2Jo1^H39cXJkr`2NiWH+9g_G zt?-}izHv2oB`d$;==&y`n+&gs(9G}D%AlB;|tu!95*Nj{tP!M-wE>2_Y_s>lBA1a z>4=+x6@k-W_^AB-;PYk4`CEvk8F;IoOAX@Ht7*i41ZE2zf(b|OS&V@^UTnm|iE|7> zgh+3gudk168*L+lSy{8q6pDyE%9BX;3kOH?RUtCzZ+;uas;hONuZu%|*}v9G)I<3) zx@2M(DTS-dIQk`GA{$}X9Q((+V|}?I2>h60+W%r=Mk9OKuTSx(JpacaA&RrYU>a-O z{h#7D+X7V&k7rXr1y#G_A)xB{;Qde0XAP3-`=Os>e2s+;DFOazfa0_3Mnco$EG>|I z=@&5D!jj6#(KtA;TI{MsQq?~B1Sh0yiT7wK-|VsvdO?Uq57uFE)#FU}pJ>)7b?E=u22_5CM;29a`X$A0KLfl(nU`EPl5)o9lZX9^`X3HoGeh_p%#_{U|S- z#f-Kl$m8%bh1f0V_r)4ld&>G7%rR*3^(TQG(;dUlEckbj1+L%a-%Y;he*?q2JV_F` ze2gRE{J3G;Yla*2CnGuj*|TV3Qjz+IA>zQyh7f`i6hR$8*;@~&Wh0<4>NgRENY>ufRdJymewvslm4eG$i^8CCuZ@iksz z%-$JIF*1P<*m1a-l|dU0^7c#Y*UXO(U6+9INP8-IuVpwH1Xby~(P%`8b{EGSHJJG& zmDH+5m9F^kJ+hM%Y`uQ9*k2I8)ZB07I~hO@=fY_eLLW(xmy6}fjVI43w78>1MTz59 zH`l!tQgEO#IXJ-nNYk~~bhu4eEFl1To}9YH3C-b2m%*ZaWaG5MA#mgSc_=EpT0>>C*Q!t98VRSb8~rb@LDytc^sHq zsri<|tGx*aSvvHYu_Ne>(-jHQ%axh-9}YAcZnN2^x?q&8__UBQ&0aAD4Ugr*nnv9Q zn^6>hr&Rs2A^QYgL<$^@581E9hBEnQ3`Mn#e<-85*0Tc9W$PF5%ToTOrz7~+--QEW zcO2E(iY{!=;r7)--!&S{9l2 z#4+6;uUaZ4^ zthLR>K!aPq0KZwwimI^GH9RKxSs`hsD+w)$8AR7$;F;XB<-AUb zFZCx-w%J9lXx^(C*x2nhy6aIrkEGW54!T@-U(CXc)R1M@Q+4<$`L6J@AF1CwI3u5b z*Lj=(D@y?sEvPWfXp&Spm_-)Lkz8BX6(|{;h#kH7p1tzRHM1(D{0PYVxTt1Q4uipNu4OPr2x?A<-gXpr7`&ZexK@%k8ido~ zj^n4i4K#q>9SdWem>EYh36wM`ATnkyjOZ|=y}0MH@Zi!G=*;-~M2>qsDP-)`Mr5OV z0!@pxDOdb(3BHU>QdEr(fAv+~V3n&Pjb&XS2AhWXi!^ij!?8CfvYp4hXneI@z@bNz zGKSfvUP|zYs(4YtVc?fd#(8CKJ0=r;_aT_TsuZFHlD&1C`iUTvs}PPpXJPr!cfCXU z-SkG-ndsFv5{FFG?_f%^tTtVKt7O6z=nCaxNaf%LaZp-cSa73fNQPWc5|!m_lUB=& zBrF~0q`kE`I2dm6s`SE9OvnkK*_yU5v7s>MpCHu3`JW%x1hR!eOnWN}`}!F7RNcal zs@q|e47+o=u`gm!OFhN~3kqMzc!@<_1>g{WVx@FRlt!W)FX{hu+M<5XHZG5#jY!<9 zn)%r&lN0`#6A}Ajm7Ox=X89^fYQ6La^zrRgNXdb}YpoG)xgE4S+-zlmuokrn>$)I? zXohQN?mhFT4MElE;C0GH>8sQqGwKM>5N|7$jphO_1pU)Ddu)cobj(u=*99#+<7 zE7Y5}6XHZ3xXEt1*zTw#bYJfB4JR5#XjDXze)+OntT#fn>^HxPr`*u6sNSVHy1B@>Rl{@S5LuzHKUi37MT#&@2k&54=2-qlgF<)eRMd};DF^xE<^en3`U2ut$t!@ zcf2HjeL=2pcoEW%4|02!Su44)Rdc=-`rTR^U`uj6>(9Lq&L!^5^7TcG!^mTmTrNlE zXQrR-m2ZUFSp3uTL}-M>yu-YS*NztU+=Zo5WZ~_!;>#zt`+@B}qvUFF&|LB!?*qFj z8Zx89*>GVs@g1Q*k>5_FS)c%j1Eufs;7r2{qX~4Yk}#^Ma5KNJgeuDi1|s5R(XP8U zREF=#ch38_)I+6)EzRggzwaJ zpHyxqWUDStJfB3r%+^C)kH`Q2^v;78<^m#{Hyzdp69dkx)Pmkd`ksZ8$IBR zUJsNu{0Xa#iC>cQa}t-Y#DKD#U4^EReK-m7@-&pIh{$bPBL~JWa@A=l8cx}P7~DaV zZ-M~J!H$Nbg7Y1}i|0Mw5KKqKXRLL%XC&8L-Pq64r%Zr`P7K9R+VKjZ(!DE3np2?V1m#h;F;Dy7x2EA$O z6q)ohrLU;eB|~qo6xI@s^^K7ZM#q>jGMahm2f8HUgYfe%zS=n2$|vfU zFptzddg*Nz)DrH`>>vKPCPk^iT9$&MnJ+Ut2Ba&9P=9-Tbmni_%%#nQ+E6|z9sQa4 zLKnIHG9S*ak{$HE?%6fX=SbsL|j?BrD_ejav`ee@A17?TO!?xAHD>z zl!lvFh~ceK*+wO&k{V$0X;m%`xm2eV*~7ZwVaP*aiR~n3=-xIoOIc`HViFD#?UxS~ zWN%Wzlv{<6rl`}=O3W-C${mi70L4$iCFko(!~4e{xk#^VsgbwT66MuO8581BhCY+S zgE#&kD&G{~kBOLUIJlsOee;nW-QC*nd-5TS`a8}ou0l#j;*PAXwKHKfzoBLh7tBgx zz1*D}u9FDTZFZ2rk?0DwmNujcQk>2XkH+U5D6xjn=a~?mJzHb2Px%nYE8#X-abSO} zIx1pPd?XbiR({y!vIcArBq=Ao(B69HMKEVu|2%?0y=pRk#m-3eR4Jg!+O*#ycnmsU z%f392(%;Z)livBdZ~H0yS5k)g99H}60ZQ&HH=)A+zeWPO3 zk2YZMtJODe$8vniefQZ;%FXcwyxObM^7XSiv&&Nibd=U=8njUd%D2NN1H&Jv8{w|h ziBl`ytc&Nxv(~RMp-=Q+7N=VSualMqvtCE(xcFDj6EWP_SM3GZK$$zTOgnGboKO3< zXA!SzI9CsLBpxkAZa<2?&0esO;*7}&8G7-)zl68DP5RFnQxR^Dy#7H63R^ffq<l&L!F;8Ik^Dx=ZYoC$hq zE3y4(W;YKd#JRoY-FBE_v)gJ^ z6nKj~yK+ooh@KHtI+{%KDCi64#w41Vpk;l@X?u2RP$k!yv}C@KP{(+yJY-X;4Z#ZQMz&ndPBPC^}9WC=^dwwk|ssC%z5 zteCI2QZR9b)xruRXD3CgID;KLS|^I7@tRqkf4OnN`4yLK#4bzbgjPCn;*GoA0Bw6+ zMgjvmO37V4@a(JX)+IO3a$2k}*7DmO_qfzjQ`#3?xIS6Jw7Z zWIAr8ntIR*nm#Q_=5o*D)0v_RP(V{aYcWKeg8=jaemXvMia!1U5N7^&O=AInCT|P= z+87aQDEM6XKo4mtYIHLTp7*nQLg}(~o1xHY5h@A6Le3Web+tQqwf? z^4gM~Kwd>eJL~9ehdap6_Zn?l9aq+I`>{JKU%MqDiqV$lyru0 zuk7GNNss!OVTX$g$&;YDj~ZFfg^mgVs&i z|LSZsk<7nY4=Sfdk_##BarCD*9x`iZl<>HVB?sY;?ET&Wl8v18?6uht@S)R!mA%zw zPlLItf*Gi;;&W81i}}lL$gIJ77MQN`twx(IYSHLL5}CxTq(lz7rg3(w3w|RfZ3~e{ z-DN1kd-Z5M7xFBp`ErB%_tT0|nBNrihVFM%ad~;KS_ZJ{`PC1o)fCFbrbEcNAEQc| zyL9i}c@7*M61baL*?a^%V)!qU!bp=9XXwO}M|8TKGH*n{6zwLViDc^+njb22G-zD4Z1pJoci7U9S^u$Vi$KMYwW_OMY^9H?fB_IAMNkrnW z3l&HCymgbh>acz=`oAB^;N3lEzA;!wY39i0BBYk_r(G?$6ECIvAnGi768^q&NNewibss8!1j&pR0Xu!(S>XGx)~q;q_wu8K90y|QIK4_pJ5tbrdGxh)-DfutYrEi|`Hg4Ic@ zrBbNwLp7E_oIE@U7NJ|mNH5BR9fh3ltPU6kWA@wK#fS;Jdsh2^8h-5v5zdurKtX>Y z*fVR<>t_i+iV?mDm}iQh7&I&EO<;3g3-gOlsUQt&K}ZJ`g>m8`kv1`d_g;xpf4~?` z{o#@{DOVu{oz4Zyb10BIU?I4W=Nl|wO-&VXjbK;cu+#svcyfoeAam{}?hI)vN6GBg zZFfpDnA?-YENm?1H+hmXU8^YwJ)2wnkS1p%6xO4(EP4GJ_wC)^un8Z;$zXq@x6DHR-(6smvAyvE`HeHtQvN4)Ga?o;XrzCet8-E z)}@ve)Gap&wBGI-!(XKqD)8}&+Q*RbShgvG$VZB=1oXk^&n^5VX7SCg587so(eOml zxlDVq?^e_UmkfUDRy<4#_a<2PC#J4E_%)oL!GYjP-}RY4^ThANR%_63$X#Uot`-MJ zN5{fwy~sRVR-}7`NiIbVAt7Ku!yT!R>KdyT-bp)&ZTOBOTGKU*6XCzds%%i<^v0N#O(vSziduDMef6ncskA?J>-!j zZZAf(;C7nOJ+ zel`oBK6wv$QV(QrP>zQQ{Q6b3k@3BdP8wra;Ip3sZw@;WK3At9vGcp(uMe~B>^TTQ zCYIm7DzMXLbJLM$f-pB}62;%;t$ z*tp@Zf-NtN!sS8Ir>&UT<>}rAyA|$iyq(ZT*%UQg48hi)d1Jt782ZjX)_5=(%gac% zFr7s51w|Dd_O53d=F)PQm~=tO%>#+TkyEwm|aJ-iBKm4?WKa9P=py#L*qsn zedH)o8?YVvLWFv+3`s@xv4n-u@{tsQ2SbZg2`YKpw$=W4m$iG`tpX0hxed6{+j4EQ zR9*0RyFcz+TzSdpgt*P!qED0HxXE|!kFwzf=UzeMM>12hWx<(GP4L)ye7n6Yu()Lu zxEx8=-1OzIt_4U%*m{xAa}4K2sS(+Sq2jC80obgLLvU$vp0edx!s=?1d6m5g!GoUJ zLrx6#e_o$>eZC<JL2DKObd}K4fVXtNXrzwmA-wK5w>lR^o-|ZT0M~AiXwKeq5GY ze7|$!&bPTzGwF+b?Z1fddQ{qb`K631lPM1b>nFzzQ3u5Nli`H}992N?`B46a`Dy&r zDQiz&;4Sh%4?I-13MBMwtJ}AU2B?E*x{mDHh-B0I4+Y)YDTd23I;+Rf!;=BuHSL>A z!Sy9DZ2{urwiygs!6v(oWnR?7wDBo^gU=Fk8iywVou@nM2GbAo%`Lu(?87!)7(%|< zn1`QMnQ|xIyHDTVUugx>zK?R5&d9#{BAYs1VC+UHtaVfq?`WpFX9s^gU`2Jm1-#Pl zNdVmp=C+nQ#^fCg3kmci#_dQv&NL^FcYzIhWH+6}a?Df8Yp3z17s+Bxrt^%(WNQ}d zc4!qBkS(|>*al27=3ol+r@OMmGWf%{<)w9X>*IjS&meR{`@SgGM1c}QJq!u`dST5K zZs7?7!T`zy)9sqv`h_NU(mTK)06d`s9xMM;ob97&@0>%`!u^G!)865W!0pI2zTY!l z48&R_eP!h~zTbHPT^+hDeb7t)(p*~z21Jb3Pl+lyy$%k*8*AFNT$r+c5eoENf16dzo_Qf{&JeJ7;bXQEq3JsOcK z+jhaQ`;AXV#`Xu{+PRfR@Ws7(48LR2N%dTapJ$17--suJBM3)W+3LicM~`v`668QB z=|Poqaj<@f{lV_JFC>kF8ixAUA*(jKD6Tn~d^wJ^viR|V_`NsI^jB(&r}FC zGeR$WrYL+ZqbANKS+3o*sf&8=Ya3km7=&Dhx|fA;i(XEG+jS80QVSB<)VCa0ElVyR zqsc$*d+&epvVF5ZLPBn8fA4Zw9k=D^KHU=D@!K3jHdKlJ^AzD+Cv?5NY#qqo^VW`k z)igd=>nTypKPJf+2X|?OpCR1>AE5&~dBOxf&K7kG%+elezmUz6L>-dNIp$r=u85OP zOEdO;bXS?29@Xh`;j663l#ZcG6H>;og#wAccUsciLpj!(KF={j49b?@7q#D?bS(M6 zf0$XNOAjqCbf2%vRc()%*<{AIu$P{Smv=bffz{cAgGEaBBl zp$T1riL~!i>I>@d4OyH8tMinSW^*bB-s+ZM@l{hb>W~U}_9McdH6i(Po*AVAMS5?3 z>1~$>1FeMwjJcAwg@!Cl{Q1-5nF2(wgdZC^?&B$(Rq(aD<^{pY9M?ushp667Nove{-t}4`;{iR5kGAtUW^k@#eIi|{JK`}2QiQD* zt8+bV3B_)Ty#t!?xe_*C4Dz00_)!xrANz~+V*&a*H&Py4j(6{kXO&i+fmE-FJEs^2yeDclAQ-V(@liuiuwYx)Fe@{8k@4C6s3ujd_PT>g5k&C6 zU2&Q5SYPRF8^cDyp zpoMhHTlKqy5*tSC16lHC!!vvV>l0M6zmFB)nD8X-h0|T2G2&YpuM^x80@%z!=b!ww zeM6%oduit{rDk7f#ag;?btRRSeY#S*IbX8)wezJrn*wXVrM8s`le4a@W|_5>@?&LZ zqbas4yWvN-hoaY3!K06(-=D=+vUy=UtBu(^=X)Bb=lTkgY8LJpCaaz4uKg}B?n&n? zP#R(8@GGTLSZ!mjL|G~4ZNf+WcSxZ8L*x6dzB8S|Xs@VkC95!QM z+$SMWj_bK9w)I>3OMT1Ny?9r+P?^-|W|Fqap6&m#eKt^Yzg7Va(d?u@ifB zZ@wRo9)Y@&->_ZEt^IbiguXEJJJ{?}!S8mtjQG`fIB!7Qig>kS%${oB6qul_-;}e^ z+T$NjswG)ivccCsjj&-eC$Kx*QV;&VJQz3KxL((MrO*-nt_U78&ieOw-*(y0Kjs*x zzcN|TKCNI)pf+x3L*=;gjmgx+*r}E}j3*M|`VXZK-C2pF+su^S`)6Law{T}@YYN~! zO05n2hKI9$?!GZ=?%r3BupbbKm$YHgOy`zB!)Nb8qG3G)EIdFF@0F?@1k(&hN+6a(pk)x zhikK!%5z>nRe732M8eb-|McD4D{A8XagOIHnD``oPZphyaJkxO63uu7`VG$sfrcY?*C7WR>WD z;Qyk1*06+lH~G8KI#j_)+be86{c!7V4yVKtSiu2xc_>zl<6fBRCY!n#*#G4_)7JbM zC@Qk>+B)-jt;WyDQU4wHzochhV)-7{O@l8%ety1W*h_bu$SM+&OwS@Bt~M->*ItxP z>{;4;05_k4X#RM(yRp+G=e<8E39#)Q9BXMpev*$^6l^ii+@{j0l-{+V6X<3lCS6Ps zZ8sgmWxJAp#)UIH;%_S*mxjRV`rt7J!I?09l_qlKMQ$Ax?9$NhwWsSUcQ-<1b7$`_ z7Z<)y-+a10<42VghaK7SXn2}j`bT2@aBzLA;)B-_*fsvC{+nVo zuZH`s2@l8Xw5E>ficnr(Rsw%$z$v61HPLMA4vYoK*0r+LZ`OS8&IChFGE5CDxwG@} zN(RxKwEv&p**QCVx0S>E2E59-7gW7ax<_1d_uLnr9(52%Tb;s%rK8jn+GHFK=Z+Sw z=%qK~X%~H$cF(6 z9*ara-KWpXFx*xWoAxTX8%mPl=cV&vxRUu&azBYzR>~kGmZ#U%KX`fPaa^97?cW^hZ-y{ng zU!T{$qqIG_8u;+>4Z~T4^^MH2Ikwne+o+AjrO?%qZ{Z4Y5R&T~)0v^#T6;mq<3a6= z5ylsv7cCPz<(~P+7@ko$=!4hRm`jGv32Ud>wPM5lpQ@qXUPVpTBUz)y2}?#ts3Ojv zgu=0hXWo0~-5lA^nKX)*w!ETGDEZ{sA!9xc-TgLSmbx?Ic5IHKky)zN#>k+er5wj$ zjl|M84diPQzfAruv(?lWNk1-7uorqt2I?KJ9Q_bO9GaPZkj!fJT2$#Sg-c7RDGOUS zEufcUH!1!MT|ahtxt=!P3WTOFnY(MevcAqrV{XF)_&8H|pkHMD-c*P!0R=Aw_FS20 z9%+!v`beOAO`bV!2K!%maDMO41@J{Ky2MPhnx_KPk2adcZ;plip3g;OWozG$yG#oK za4+!y3$s`LTCL_H`|JTf?baapI`YkUUqSPfT1$uZ&uj;hbxhsd*qbxC9dv^2y>V=7S^vzC23jQvgdsVK7 zZ4+ZCFfZZil0>>h#iBcWc;&bIwQ?ATN>Rr>TIxB{1wHW3em@FdtfUAL3eu9cYndij zFG++HV)Wq72t8Ose{8{lo}_&F3>;{UTsWe>EU!)wR9OA>C^OL zL&VNQ#?V9%*(~rt`Kj6F1d>D+3Ig_iO25}F!^;#GySG_? z@Ym5)|Lr5(pXfoY*?qq3G7#v#DOCBPUXQmlwpGFJedf+ohfA}24%@m0yVqj92G`>1EW)o#k*{3vS$H*q!z%7p{XfGOWCX za?1eCM4e%PxgQ&4m4p4{v0KSGVx1hjKOT8BoCZKwW& zXD;zvTe{9km+P9!uOPHDYzNViDj2IAlVj$b8FS|Us;(CtIDYH9J3WDE{3D!KN_KAX zP9ukSDZ6EwDk;R*L~X<5e6Kt`BTFFz211YfiDs+{M`}2p`OrE!$}QWZpcw;Zc*V zfeQJZynHNk$@b{umr-N8x~Llxuh>Pe*MFJwBfX5Tba2hxwH3+zs&4$-O%%3HbjE%Y zLR2PIZ7GhKR#*At&l~8|YVOUk7%Nuvep@b#404TsQf6QOkk_q(xN`hr!RvU_Wg>tv z;gjaxEzx{b_^b8|8cm-Ao$WQhC1lN`UoHCO-pKCCC$R6Z?~38q;F~Sa6SNHz9>bx! zIk~`&&jkfi5tPX5xLJaZM?`#uj=OhAvaY##fCBnm#u+*Wt34L~qpnT_wb$A>=L50l z5HkAF&))2pzM}eL;|ZP+GtF7YofvR)@~UQk@0%Z;`|D=wuFCODYeoJa6f`@yHu6`x zs5Z_M*dyfe-iV!p&IEk;de*Vh=PEG#Y;ObB7#y?LX7TVi1DRhgK1YXsl3$xFP%s9? zMIWR+#joPFLat!HB(P(e3? ztslMm9ek06pL5!GLQabwHRBQQ>`eASEsPe(kD+ThZqV-cxcPbu9?@IJ$m6H+*)l|l z$XErHEhH=Vw@(b5Gat_oZaS9)>s~c<%=^E`rh_cg77^ZK`BHODd^I)qQvT|(Tvv39 zC}j^GF$}e*22C>UJ3P-?gw+LHdGUspXP+4q_Z$%kZpHgmju4-ukg~Het7w61N8(STySNi{1caHNj~wtdi>ktJv#35QrDmrjBf>3J;vkO zK5;k6hDgh95R16ng*ymwaJ7+>D}R3nFk(VH9&O)S2c^m z-RXv8X_dtts?gY6pq0XWgJs;A>+pcPSjyy=h*h-u~ks+IY;-O;pGmpZCM(%{p zo(nbMTw}Gd1=poz2FU{W;&|?cCXOXj`O0?`hBB7BM&TMv7njV535!Dg8= zIpkpMxZn6gj&fQ`;&;`Mvi7#W3DpkYigR9xbospTEx7k=A5oG34(VY-hs(?oUD`Hh z-G-(8SMrSUW1FBlgEOwXNMzX$WOr=H?N%-l#%zmgeS53-(Rh#l-g*k*Lcqaoq8)C8 zFJQ8=)Q*MiM6TOcsYF0uY08E5_Jg#=CIrc&8uf^*fj2n;OR=?U_}lRkcf3>@R?eVy zgEJ&7`{eX$e3%ZMu&%NJEq?5~bsnajs~%d{>J+L)lxtNVA2g1l78pfRY*;nZb_er1;LbmLegEzTkDc*v`jai;)*%)N9~>+wNNXa! z4fn)O^93|k{*e0l4sU;moB3zw&$*Y^WG|&q=vK^fpuXg!?R-(dW8&SKU(ajK?;!+z9$1zLy#m;Yb z2XY|otIkJUuzP#N>i7Pg7qUjW0!&%3tFG4)GkWk4%o)Km+?@5@_ix(@RZn=w;bdeC zd{9^|?5B5+$o%-MPHO!d(^BZ;Qyog3=uop#cbWUi;NZ7ZW{u?Zv&prwxGPuOy8lO$B_%O$zWYwe%<4Aid3gcihg?+!?d{nR%1av4!|lddjIL`7yEdtTM7sulaj_Dr)(Ly)GP zWnx=VjDJPDdv}$;)C;^{ZgBz3$0v!}K5PDQ=%LaMNz!9Dz#q=pRh1Lpy1`1zANtEo zF##oYb0|2BcZesz!EW`7Cn;)Qcl_=S%wcf?I_8+Dr8~3dKjh|Wrla^&J;)bxs~>ln z2+4Y$u{vjjc(Akk#`33Rc*6I-=sFM^!an+6?C=PkZdsY=#lH) zv3I8tkXDcfnR04bfN_Cn)V~2?mEW`BuIY)v1IK0R=b#Dr{}at0pG5Nq3)jWZ1p+<` z0xI6X-P04`JcFhFiw!jgBoxMmp4#%={81Ro{Z3@jOD_AP0E;S zF7O&&_IZjheJu1dSE%c+)(69kOll7RiE1yRvDW&`ib z>+vBAkr=B!wzO92lzYF@G%qiFqG8~MJh4gkekHx)Jy|1iBiVZ{u2$He^px$=(#U)E zg!J=q)ZVuo+IHzTfhR#(`$M?I-Hk5R4hITl^D@%E_TqCarKKMGp{T3-pUJHJJ0)MK zXG8^Xn$0pHBWT_~u%OQNJiK-(uXfqqtI?~XFF(udQ5q8R_@3$x+7#yd_FSjx(FC^{ zC^pliRD_e<&Of`g@l!rKb)Ftye=L(ff>$hxjLFT$y6@dYU7@lt zBvlNiul4!E6iymEDfHM7Ss6lM+&>3DGO16|)w=2Pc6@#TAJUy!#aQ1P##L6a@XY69 zu8hytb2H|$&uUE4LLs0dGk#8{xVB|oZRzC?kVS9Mw>)UtN=XXs7+3ILFqwow2tg}Gn1{QQ?Z;F0dx&!RqZ~>U-x>8 zP5zhv;9Uv^zb;3Ug)~u>oJKF=`({h0Y(lr3s&g6N(jG>l!sM*__=Ks_ z8F&MQL7bo1F9j*uUL7L6<&tAmwYL#IA7Hi&bs!Z$0WJ#?)DDn)}08BG0N`;$ahtnq-Xq*wv zcsb}Frh0%)+Zyf8T0A=T{c<$VZ-Z?rWZAOJyZ3u0&y?zQ+zk@}#iVlxtNRMl3+<@s zt=hN;8Gow&bB{2d6+LOrZsCf}cOFc$eSn5XFrAzV)%hFNUssrqMwE@mF=AIi_ zB|XAfA1%|t%E;+lI;H*O6g4h6)iTqEOYgY9{aY)>U79O>Pi zf`as;ioFa+CthiW$#?xOG;c1XOg~TKzkC}?J*hqG%XHizEPg4e@<&)5i8Ix#?cM&A zbWh&T;lY9o&d;yJzL>P2wBxfDd(F2qRY>K1=EwU^@scjD zpB^80^z=n9dsF7``!9dxrU?nJM?zw>=C#M7%@58W?pJW7=7Vchn84vHT78_FYUDEy zcGU`AwR_PkXQF5ukTX3me|%m#!LymL7!XJ-|M; zxk%Ks>?T6byghqlKzt^P=vsR-mbEIc#j6(6XKnh~bTeROu+4Uf&KHy57d=@-REByS z1}{Sqf6S@c_nKZ;iJzzdSgMj4cuh~E9tl#o`{VTp)mOO+Zl6ho1vf-tTD2ofUuc*0 z_$xQ$+>K|1-P+iNkM9p?i_`c}8@zvY>9q?}gPC%NC@lG=XlAGV2bWg2y-n`c)p;-; z!Ue@ZVI;xv2{q=%=C*)$g;X=I8V%$f6Ye+0svNaH$)$7(+8oQf9ZEGuG)+dI&F0_B zp+ess+(>uMmB+uQkObF+_dFYHW(M9tFKxdhGci}8Hk`L-u|7Jm!Z_KhxECug`!`gH z-WEbM*8+irPaF8<4v_p)=`Yr;$a;2XTGx{~;;;C<>uEu4@O4#sUI~S{fH@CtX&=)48C+Zm&kwD#{_?@^d`YGHdunN)pn@7Hjg}pjZMqQI~f>Q z7K)}FciE=}R90k@g+Ed<Md9RpzR@dW_UOPkm^*DGQG7 zyEwma^5(PBtzhETfQfV8g?ch$@_~Ztajl~a?C!U$S8+YNhrtZLoqKkUQ{*60;g`-_ zeX-%7X9i_DieKLA;gvp*`vk=t&AzBU*d&*RYcSSX-Rc8p^+^X*2ait$2XF)o zPV^rgF1Gb-+)826UB9Oo_n722wyR+zzm*af08_14*CvTw?|tvYW~h1(OoUp0*6IzI z6L?wGT;N!{H5EJ|$Be8k`c^RA2L9&ftW6n=t6NAGl7D|a?!E5@uXoRUwbN8}!9|yA1cQZHm^_&y7w!}j-l9D zyT+Qj_x!5MK5h?HSOl%6=FzK@X>XL`GCB_B!m*r;OmMgb+t^k|vb%1Tk^4$V{b+ADJY!>#VmjdbUyqSM9zQ2scHCt~b?-$p3MFQ1Pbkft3sWx#RSikRmDM zDV634Jn6pn$ncb6`?jnK-%mWxDo0z8(1G=nWfnt%;) zdt%N~SY>O!MFnIvJjwfDqb)l}9cBMr{&1GSm>$ApY*CDb zp-W`3b`2r0!vR|%lCo~K+`2pA)1A#D+rFKi_ce8?)8@fvucQ>@K&i+xNSD2ObR$?+#Y5sgRUCE6hO3uEM)4#NDH;NO-*pIE&)**E9$( z$!27vwiBSD1xkw;#XZgKq3_D`LbcvuHa^|a!t+@)ofQWpjoE`QjqMn}=%424_v&}> zP17_1lvps;*?Q`UxhChP`N8lkE1%9EW_@d*%GpZo!Wk~gbam=xgog_Af1Zas^&-|Y zgO>%@Z-A7t_UyQpSEjtqivn23U7nhmnRyFXMa2%=pu;=V<>=`qBb;TY`&DJ%q_cJi zuErp#=1fd>MZFRQ;jqU^6JXGJ*7Pu5fPHE!Qq|z;&8OcYj>MYzEb@zh_HLg)`8B(d z_m6=(JuU03jWJCW?L>`dg7er|wke7E^6J*cd-=zeJRUcI`b9QO(wI8PNmFsPaCN*c zLCRrBF*-V00(j$_lYFwDY`rr9g0FHDxTo=De&_Ay4;OUWPL_vHv*p47jSq?Uuv>n2bV8~jQ!`=jg6|q;V|sHe z6Z2T!cV}kpcH*Nf((d&S@7LR<>yF>4R(oKmj4R0h$&)_oE)w6930mzHjIfN+#kKp7 z)@mj=+1*;6`5e<`_=u*vg`EYu#F{ws-ziq`^2FNjZ%8lBV0L?dD!uQh?`HuOpSvwA zY>#ptOMbr>w40Qo0fziFKkIP&eoUw4Tb9V|feUeAKsH#Exp^L#cQr*8>OCQcm*WgC zjIM|M;#Z*Fl=I>HUs(tWx_YASV9qxeSx@Rl;P?Ri^ey-Q-xb}-P5)n)k>5Aud3+5u zA{`&hexy0AJbUlctav}~=}N*PR)_DffY`zlYCE(NWg?2M{dssg%&#hn-5t+CR$0E{ zq9AtzgSaHsuUBVhXCL-&Ot%$Xe%yHB=1Ix>RD@c516}nzGC3gx$1<4f7Sef33U^ok zbBR$~seYb;?AD8|)iJs2YPz~i9U26`7WNy!h6g9wU1$2PeQ0fM-Kf#ib=02vT+V$} zsP$a+G__)iV30NwLb^xmZQAUZ;We7mufJvuk|06je|UPNUjL|_X##>kpciP(*@phj zilXAV#D2HOUe7^^{dAyX%YWs#Ab*gUf|tiEZD0fX{D1ZbP;x<2%D*3ceZ;eT1JU!q zAS!JC4)N=Sz`Q_fQ*zYCMj*g5oN6HQ+|0fC8C`*FZsMj_25^ZE>f82yHHts~`yVMF zLsQ(XWHg;LcRqorej!kTH^hYJmo}9>M6>P-)v3@RDsCz-t>6TcDL+)T9BzP_1!Nnf z(xNg<>yTKe+nDBZYGy%V+B{AS!J8_>V~v@iZfIr^!tjN_QV^z<`QpVpCzLaA1U;Zn zPb$H*&JKs}StQkgzN{q?gd0**RE7^F8&4??V91N~%3XI|NIDd}oJ?`97$}uTZL(;? zApGlR&i@Un`0{VJ5FEBYLK32xL=0QZ0pvczl){peTXQ7gaqH~=z7`eO&AWOqMUf=r zTd9eHL~2C>ulbv@nN;AWI~)Gd+8}Bp`l0)+ODLaaYgBUK3!}G+3@WT0Yw_?RNJ6XEkCiX9iUUEEseDcM zuH0)cAY*vhi+9-n4O~X(+`^4iowKvpmbns>a|6!AXFdaazkF^HIg3DF97dXoPje4t~vtb$dX{(r_N}uyn%XzecifU(n>H4G z`t+&J=*}aN|4r!3T$tsPM{`$`46l7la_f&VsJ0%f#tvXtD=kDpqg42?Rz=!P z$Q@ofVmlUS*yXqs_|HB;K@v2sZf#e>aI}FeAqfF_VD&*CQ`_m1z0sk5GVuFU*$Ix6 z9)a1G0*GOSe`t|Z-+S5y-tY&T=s`1I$C~Tk|8LoY1OKuK8y1+NU8+IfZ+UVRdndim z+gj9V6$phE8wEVvF1}W_z25vh0mrXLx;5=Sn6*KSC{8JwwFP#2*$xd2_1)iI_Ht+l zq=Exm+Z}Q(@?HJk_?}aLX5hr5-C7I%HxWpY`rUDWu_Zk7@AwR@JI{kC$MJJ-TNsvT zyF)!OgRVaX$IMM2u;3rJlRj8JiWhX@utXcdEF{2~r6t`OVd6}F_2XO(Hlxx?o$0(N znT}Xe?mP3W^;~VOwHBR2CwMtSUxuimal!(MH6ekRv!7lTyeg2*L4RUm)x1HK^k|CS zF4UfBY_}LuykzjT04!8!zRD!z8R1%Q4%y(I8?3os7m-0JtBo$_GAV3+Y-Xv?x(F-_ zMK;B=Ua+f>>f;aAM&PC$mM#di%{^g#Y6TLX%#ISv<`QfX1Sj+h&?y?axW2G{n1ZO6 z8?NzQ)QImex8SR~KxMBBOXrg-G8x;ZZS3Zj9(UoraLQV0HOSM|aK1T|TEn(vdgAoe z$7DNly5{sNbhavEpUjC*=Jprk={#wnBf7qkQIDLSJl7RGj_&wf2R&=>g}%cu9Isam zXRgtVtN?F7%^1>eJjW50xxHu=TQiDMmo->v<9DG9&S9+e0yzDzV@vE=;@w$yzn_Gv zUS|6C`_gxekV|(mzAaE(Np=+&ts#rSj`1aSONA=?MD-2Z#6nn+ZDchZO1$Ivt>@LD z?Y8Hj?iboXcLUj}gkPyEwr3ZFg{Af*r5w#X^36$iW>c!In+2Gvqm9SIpzhwbd2?y$ z{XZc%I0momh3F4D%>-i+fr-9pk=xm;hyekgQ4K+-;43gvL4kjTSZIYOvA!%@41&|Q zt5q+WPe|=l9llql`-@gFQ`N0e927UIXUF->dr)k{0uh_gpRC{67)x)4hSsI#!ZrG5n2VJgY4lNH8aXbU~fQZ$3vRfs*I$ z(S`PY9{IRvQG;{`=VTqFy;S1jQr)cXYS}-But4xx^HqtLmJd08qnsBAsRDgjO27DA zP?jT&r$5W3z#aWXp-ZDvr6pK<{IYC>M&e8c*v_&nx@%6-z#%f-Z&Zd)_0S;JHNM~3 zaq0a@j0jp)Zt&tNIYr>W(xNaN;bWYTuU3ioi(KWR3yz&pFUyucCmxWxB9Q*u4s`*v z_)F`lQ@AOz%VbQHHMU|_dC*Xg+t0(6O?bBJCREUS!zf{|U%(NX$QK;pH>%NTd+euk z5ZRpN^Ww|zZ0+;`8^_+0T%K}|zHNvR!dC z9`o3wdr4=YYlJf8Csh!gyhg2fC*o|#-7AZV?iT%0%}yizek?+CBLZ?88uC+y34om@ zE?~I57cByDbLodzhD&Sx$2%=f9vp(6@ND^znW={uaVc=My?H(~Ewm zeicCz*=>Sn<*@PCupbu$5)4738$D3q9X-V~Hs@GNfti>l=h{2zxhQTZx zT}cCmPwRMDL8vgaBJsn5mcvqPajO0J(m(*l`4?}dFk#s7>s1_HF+)rQ7c>$6&ixOYxiv? zzrZ_G*Va;btyHg_Ht-@JvH2RSeb5lSj)#c>kPBB4)I&D0(x3QXH!2ap3jUK@W3e%A zM4c=XEr-Z{t~uj*7_zle+%eIF!TZFxZ?jO{Z_9*AolGU*A+^zVh6!5h17g)>fX;!i z788!PH|JMHv}%lJjXW1kJBdGcN}BE13Pon98>DzRzs09d`2m63F)vrcEb{Sowo}H9 z7fHWxVp34M!P*_86$?Zyj=xaK;QjRoJHu?LXp2EBkD@B_?SvTZ>58I%_Qrdzoh&Iv zJ}Bt=Cxe%xYj-)M?=-vjUr!j6^^@9wVy+7-X=@-QwTMui<(-xmvfoCwLyIx!^)$vd zZbC0-Ox^3n>W5$c`D!HNET9pjE+^OB(e z$TBd$$kOruKG&bB{gA$$JfL~9{`4wiff7m4V-=czl~5ry7#roayfHhr!{3T`9ey=A z(6{pDno0Qd9nzcdo%BY}6)sg+9bK@B4$(CCd}lZ&h!dF2 zTScRvm-?Sn;PDb>=?VQ=p1?Cm=f&iFsJ=^p*lLs3MJ^WQ64XPluw|ixa4msA3rzH? za)GyS6@HH1d?hk6J(T|Z%+c%n_M}DIX+P_iXHLS3#pPa-v(6Yw#$H!m>uV21(m5j$ z4fig~jrwtWEG8TSyu1QomC^b+dA*R5pO4*o1O{2Xk-eY2s?L^&cb|xi<+IiwtbGi% z3r7qH(n;9DopilJGEDxYa57k9R8yh&DXfRa+BlX90Mm|**<)#{7kOLy`$J%p#-H=vQ#nDkN? z+oeYrPten~cY(wMg+7t}#SkG&{hAYh*^@MaIh5zMy8n1m z0{YItV)rLFR|9^FADWOu_i2>7%%~o3Dnw@>xWy;5Z40FN$XEJ+uygu`zKNxfK7QMz zmtqIYB}NMW5|tCp)`7!55$|BOEh7ZkkF0hy6WqO>KtZI7t}QtwxcG-MFKXzNKNTt} zkN}d!H-o5G7Lm`TyUT|C^v0xGsr%kWmj~EkgB1WLzm-wHIs^932c9$lut)L#IFR&N znEac$qoM2eUfZQEPWNX{4fr|DmS3D+fL>zR{=a^ljB0gz1gVBEVu{t3l#^TPlG8?( zP)!GuSBzDs$F56*T_6cD72=LJGGL&g&XNU8ga{&U&(Afj81gpzQ@cDt7p{o?r`cbti?>zF5d zs19?-a?QRB$Ngd{+;sXL-{OxZQ#9eWuZHrk44}@s3DBb;>XutCdg@&qm0PMjyV{`3 zOfYi{YC)Xwu@3C;4v`P3I_P?fpMSRL*FZp7o+x0E`5I+i!#;Q)-RI|vK;K`b^LpwO zd*|*~r@w!L9vPBB#>4`IvefT~{l0Vup`1qK zG)zgJ8*=+ys0O5FvU^eXSe6Mgk-#6U=^pBpv27$T*1ZiK7Z_Y4871V7Q1ZlFoW?~H z?wA7rET{F!clUAWqQ#UvZO6>FDR$qME4=T2_hD8%4>jvt6!h!co(-||0vTKCeU;Z@ ztp^Z7y7=F+F2P|OBmK#!$C3i&)kcacJ-c$Fp5s(n7ni&&`&ScYu=rAje3N}^Vor!Q zqURMn$Loj49JS)vWi3A-oWo!@D?NU}rr;fABT(~coPfu2v$LZG5LEk6fQ%Z6L;oO? zq_bsy*OGB;*~3$?x2o76&s_uGA;S{prqj2BSJAm+>V$Og(d`;hdk-(u_}!K-nh0FW z++3Q2F$z}v9Wdv&{Z_NUxR-A6+sel?<}V&~24SINF~6B=w@qqFmr>~q_9fniK#Dt! zv5{eNe<#5wj+*F4liIxu07QL5AwA{6T5T^lI}<-b;E*psug-@CR|u~-LG})MUr8#_ z8~6)VpmnK|Xtu3jihn^PUn2f~j;o2pLts`KKnzE{0 zHR2s>t-PnU1N*3msgmn-CPHA2r+J_}ukex9!A|At8Mqvf3)~( z+Nl^_->cWXQp1fezfQn}0Z=_plVqD7dIc6K7t_mr6iOPFSva)|7=3e6Jq+2Eo2;t- zEfiZD{ikP6-+AprVVlZwiMOM!BSdIcmd_dndfYZ8AT+o(=ke4oJo0K51Xq^#nE1Zg z3cC7Eaj7qMAdP73nX%L^U} zZq^vC@i3~%9YKB3Cb4H>%4z_75;rqgsrU-G*G*dP)Kux#u#SZ#k5eHao zyr%uUD=y{t;PqK;5uy4uWk#?=7jb*PXUR0TlOEsuS>+P%m2vSo0H)1wXOuo@!VT=| zWP@^}t|NQ!e5!3$8B37*A->`3=8$u)N0rt$q>E2gM?6Ny8@v|$a{04}bI(>Fdz7tyKqm>mgocO!s-xY(?vb5b*%F-TA!6!6YBv5*Mvnrm@d z?v*Kn)&gi}0BkKGkY8%8JeWQ!>1>_Y)B4Ye5FZ15QRUN{?NC{Qz*O!iSG&3lXo9u&PaR7dojrG8My_4n{y&BkGpmUHqk8t4BF(Zk`@WBoZ z)H!36qQqPx^At);j}m5_IYV!pnuG$iD?_LT5Rdp5mny{bS6i(+mVY>~l^MkiIHUO% zjcs&Hg#&yA6Vo>f6vPTqfFNI2=d6E2eB)(A698M~%OAv@$(lAy(8l}t`Ja+=DK%Ff z%R$Lgd0k6?6iG(up&lO6g^rb;(uFR-Kg_Vm0ggHR9IgNpYUrE#clW%aMavZ`OkaA3 zrX}XFt?Cl`yy9}qW=?KDB{e;&@9reRa8PUO`2Dd)AB$jn-x$urV@yA29hQJ&ZYA95gb1BfwI zGN+(kl*2gkcurTK%0T&)uG*lVx%ZRYSt*sEjlnr*;6A>aK{!DD^98kx%@YA5!N2-J zI@V;G7B%|P!Jo~5B$N%;Y8#rcFNSOk(|j44_B-Dd+E-kla0h8+Sg&n20^xQzHPUF{ zy7yJ0U5EhH01y~VwjM8SNd|_0%^5kw4l06-Oy1^&^0o_Qd*hW)Jlq(tpc1?U6b&J?sxEy@48-)$hPXJocyDJ%1!WgtY;=*GmDiU;urTBd|FF~}4KzW< zT;tklQ|fIPwF?5-Gmm$GKn?5Fe-@m$Jl`-7{FX1eIg(J>~B8&E~rIx!Q{({u|Q5411*}(xXRSd%AHbgj;w0+m)X^w zeh%f|fJg#I`9*22NL6h=Hy5buMQGwFelAd{<(|}i3%C?jY->TFqeG%5{0@A!pYAm6 zW<25PnwbkZ;qf9@N&612iN*NsA-t=L)V9&0u>E27w#5@w+vTkm{$bPlu6=i;=7d#Q zjrFzP`D%`Lrv2Eb5#$&Wj`m;p=BFlWnYqmRK?Yxu$V;}J^vl0w>Bm3`XF6 zrW}?^Fopw^d&@2HiI@Qn=J}GE^2*w6BN%A776(HD8&eAup=Qb#LxN8Ea`gzs7-%e1HlNSxCa!McWtw<0J>yH%{9@emx+zZI3cD+x zZ?{0rIb1f@g8+uOq2mz`0VCV@~rQ!vlr5-#Cr-pkq=#i#{%eFGv&vVdVq4u}ea%mfH zcdT}zC_;VhOR#_=hl>luoZaN7#kI^r$ae6P&5@y<1x}onFXhWgD#=jcA$}Mzy8|UE zli{9&b8{Jm1zlbH7O4&vu`{{6TR_~DD)7jTsw$3hAzng@ziert_;J2OZ0zHUOd}7Z zSY%J}hy%@6S)=>EBk^B1_g6SyVpsR^I!NJ?=4xx**_tUJOmj)csgnJ6O3N#y;2xE4 zu+5d$#dC70p?UB}4^FPIcMfNAoNUGD^ zp+^4kGsoc{B0fKt(HJR}q^R8VRoy*-#5_lV z7BzC(3bjxtt98W-Z1d3D+={Hce7b*P=h5KrQDq8oFf&=Rc0WViuHj1Ht8dNz%U(FU z8JQ$`)7nv52qk~C6BYU{S;W-w0tl=uWuf8_mcJ@tf%1Na1cB_p`+c{Dkyuh<(cf`E;OHedT& zaVRl+o|$({Ti5XKeEU!1OpIH{)eB3|Grm}cfXtzM5Y{Y2qGClkXTUp9$K zF|M|j*w(5ElIZ-v`%^UrD#`->l4y(02t|y)3NA}SS0v{1I@jesF(odl4HUP8_3Xc} zy8XlBB3q8??Gwe%sHEr$mVDu|A?g-QJ4%<7TccT&*X)>}zWazWzk#>hTaWrDb6KVS ztvoz%AMCK2)MT$r2#yBAWA(eV%1L7IaBCqhB3&?Q4vt zE{wH38k`Ty7}~BO{;Oaz9;G~Ga=ljgXwV#}iYZC4b#j^pElc)AOI^!>DVI-%5~%q3 z%IyIfSf0;?^O;ilb`>(Vy}H_fJ#o*JXUvc6=}I!)5dwqUV(zjX|$H; z37ldAO)R%w^!=e`Kanl*FO9lgYPjt8A6u#I$|H>;@s}Q)T)j7r=D#8@0eI=96IK16 mR_Yb)1)ARJx zUDZ`x=&oO{5Cu621Xx^H5D*XqDM``qARu6ZARu4Bp&>t87}w>(K|nB*%tS;Kq(nrB z73^({%`A;TK-2>glA)B*<>R{C*=zUG9VWOA+hiuV=w&7t6myAVF(5>l{e1I%vWbI3 zgZ=!VgM)ow{a`~wL1VH#PB-P-F4tRIUFvO|y{Za}T8zzG%F00XS_OkcVg08;kqJ>m zYFOB|9PFHSMF1eduX!M;Aacaw6344c>L4|*TpvXqX_So=qh!ar4eu{^A1X(0uX!OL zg6u!<@4_epz6YkE6a}{Fu!kC-keNB-A_n^5Ih=h+eZrSx1Cn-4|nlHb2{{qHNb}h%gL)+py4#9aMej7rs0nalX8{8x9dI z5h0Q!FTd6s)_!;iGX4e!7Yx6a4}RLu*Z(;u^xalZ0X~c0HU9B-n=F|5y9ccO4GqXE zu0yBDbN@wFHF!1eYnco?gkY6_dE2wvAtQ+3tQ810*!#&Z2~fQWs4YkYrbP4y&7jA- zAaHd-xMUEXEl@u}cu6pbY+=Gxw=V2tP>U@PEnh5RKVoD=Nn%2Bf5&Kun{GQ>RArwZ zwveoTVcB4g{`|IZYY=35_`Hw~dZ2AzF1xrNA)Se#g+=C&$@&nlg?pmO^Fd04xTBeV zf-VbHMkAp^iwRaMFgs$81che979*PbF$nQZ(H{}Ag7O7m=BOO8)FJry7VF6}S|>xx zVirQq2Bq}k>t+5HTmn@mr9*RuSA{GK()Mxcw(b_!i_(Yt?eZIe(?_XCW9!w{tO<7w z*&4ycAF500N*PGlhOUET6Y$Uzv=y}lcg6OI`6WP4^ok@OB^4UK2SrE}Uof8(78xU0 zTolUy`5L-9SY6^(^gCH|bgU!-IpMJ%yyyT~ZFIrV?GWt{&(PqI+K>%3dME@%=y$Pg zh00=NWzdn)ZaD484xf&YOwmqZ??D9vAQLP$ zS~wo%mpI?A{j7%8dX!8yj6CR$=soDT=nLpx=ulr_zfOGr^PM*zC|2!XFc@l3UyZng zY{}gKzZ%-^pE2l_lb?^Ctz1-B0AI)}sv*8C$0ge=*(}yCNFih-xi5qv;}l-%Tbgz9 zbso#y+#JQ6&z$1~`^0eW+gxKwmXddoett|&_w3_z{_-;vT)Rt-DHQg@3fSN2dr6MJ-60{QktXLsap_4JBF@-VJ0r-LR!RZ(r zoh>E`Ca(;(42cZXDC;OYEk_xDnScd@1??&MDJ33N8ey7%CZQ(Ys$qkbGrzOpy}~`( z+4|WeCo(=NegpnBJ{!IZ=K^O6CmUBtx@$T?daV{C0}KOCC3z)_R-P8#8t+=+n&R62 zT4VDfP#yROC=8SaT3?mlFyEY9LEa`_ZR~lD4vrN~VhyMba11q0O!i0ZM(tPa676oH zAY<5~4IwXk+DYS5)I%~4V@3XxUO5K;Llc*)zolG5zZ#nR8v z*N~1-hGKm~w?fIl%EO$+;2~B8uv0{$s-YoaRACY&`AAXAfJ-S$^Tz*@DwTwkQI(OC zBq^9HAk9B1$dpu)I+YoeYLoJg0*>lDXF!bAR|B&We3dr`iY&g(LII=tfHX@*`tRhKMK~q*L zT*_anQYt@}JZCuvI~O<~a{_r{cH()WiA#gagiC-+#8$v2!j{ISRwr8jT0dbUip;djfOvbeys1o(HHT%Jmld@b^sz9o`DUnGq@sY}w3L9=IsWFQ+6F>}M8O-S7>vq@;d8B-8Nh#F`UC!o8 zXl{26c#?sGfr}NZq8OVQt68$&kY1wcDP6@?->nF%$XX6w!T;TC99C0bT~X(0MP-v@ z$?TWo=%->5I4mu=~;6mMmG z_`Gd3u(kR{>OqZggiwQUHZwO9Ci9_&A7yc!&H zf)(TztONW7%t)9An9C5oVCV?!@VyY(;Pl|w@R86ToY{6;d%jMwT*n@)=;t_|Y=I$d zO*j!4VSK2q*hOe+I1hXqUprWQ`AJCi|77=duld`cenXw4Ac+l@0vmoEJ{}JH`ux?Y zM4{B?L@-tFhw)08NMR7}Z1r)@F%t70b0~8Mp)>zl+Hi&|wZn1naZDmzD&6;mILq;~ z6?{=S+X?kb18didN#4%3mnZwDf~Qu9KED@<{isBObskJx%W{Q+-v^v0z`pBav=%Dd zu%j^4u*6XMuvY0u=^N>e%s>3DRmvrG_vrV^XC(p5VKrs@!ux}xF0_6$glf3T4Jvjj z`>Ix|FDmj2NAq(-Bd`c!i7F7V>b=@GHC@;oNYvoLWCQ33axF_xSKVG8( zg98J^TL-!+=L-vsD-U`w)nzP4PavY;cCjKDbgUArD=ZAnMs1+ZtIur!PgUV?P`_7S{6sUmt}1e9_?3<_u>Z; z?P(z#9M5^ri`EbuKX9)IlUvX2-OZ<*ZOPV>=vPTaM<2Rw!~KqLg5hKYye0nT+N=uwh3=p_J` z9U~s!-dg@3T&5Lb1SE8*#LZtfUfAfihq*P@Cf;Sfd(J~uBP9u(c;aijXn5a+{4u+9 z=*GGSAm}D^AX+Y2@_t~xTbZz2^1M6@(AQVwSRI~o@LabZt=ACk2)KEtexz^0ZLWrq zMniwlL2T`TVIqTc9YTT>YY$rl*@66K?Og2pz~pqj1|`d)=qBD1pXfi_&V-ihgRTKF z3NjY!9B@?H(|@BzDCR77E>1FqG+RBUIj+S<#qLe^NG8yr(}-AxUqax5=e%pST{Gsr zZ@cgSe<${Z?p7cn(sw}NQlyzSsxI4sK;4K9{cc+#F=O)6;ODpfrTv9H8=81(NLn-6 zSsFm8W3h4Za>;F(_uSF!*u4GR!J=1{!#57yNg3T?pOLMIZ6C!1yY!IylHg;cHS&&W zy7{#U;W>j<`>~U7r`(9Rico^q^~^WgAe2EFxq=BP2AxVb>n|73H$$DL%SQ>9o?U}+ zdgm6>tT(d{iwIMQbI{)r6Jb!`_K^&cilVZ^MI~~O6yi8@DGVG9&Ue4;#-TEo5@;puV}5$xNQ&g2UWmX z;U$^!U*L0NtmmPB>T{wzG+R8o;q7I4JIu#IfCK1;(uvV;0>8Zt7#0{g zy<{x^=zpn?8aPGB(&$9DV)QP1W~iBOHf-W~WBF-wDX??tBS?Bd%%T8k3hxH4Bqr3e z^A+N&OG#l#t0|4?>~YUg1`a&7QSz_k6m@F#?ebPj-DLqgkDb@Py9D>RLnxwfA_^bW zU*H08<8Til@u7iX$Dy;KozbQVvN6m_#z{Jf&E#p6CKQuoA3EDDJBk$YMql@>67=U$ z+5B4Kp9=@*$9d_YtQgLXGE~?7-8enj-`M;$1B=3YA`oQNzb(kx?1Wx}8k--e-)e+m zj{c;jweULqmIkxR-nx4~jVKp+BBv!MkfGbOW?$hlYWr|E^{{vQMF-Fxr^S%{YI?Y^*!QrTDu-_v3VmAzT3M;G(<-0Foj(uC9QtsA&Xz zM2x17wxIN9>ApF-xr&^{e98h(CJbkqEyJaUiioD6_pIpcXkrx>N(G(O&beFC8c!^b zyl#iPQAOHzsdsU}&Zo0Wiyos&4ES)43;hhOyNu3SP-8+Vp zR27r6x-1{-$NA7 z73F8^W)Ef|X46lN%pf=-+i)jfq$ZVL~+S(@i@jIPA0W1FRf{{@}+4|V-g5(u<^Pi$l?<2v|)LY z;XEV4*un{h`wo8qlLP&P`b=j@-A0znT|-RsCW!i#iJO9w?_N?%=XLrQ8k7vGJVgSP zTA^~$LjF8{sZ`Z)F~3%fhF3mo8RrX7PRQC?$JpzK(9ZOdVN3wY;G6s-rYnYfd{d?) zO}&7TlCffB6=UUG)l8{snPO>z0KIO}_bN|FmxXKmZ4Y2?_rO?T&%sS13l@XcnK^-J znyL3X=qY-Kr87loSzYVpi2>jw^=H=I-4R{^N7Y>?w%}SKc3m@?OQX4|9&n$3Jb0)0 z)PJrzFh~h4J`OWVPLBQ?E#GizN=ibyOiC7z;hxledv$crC{QiKW=$2vhG(&dKe-%@ zzjG;h&0u-_5#wXiovagFtWs_=#vz~<8RQWOB>i2*q%h6_>Zt{Rtr<}TYD$6D#|;Zq z`KUTeKo11L6oj^UC7w(zrJ)N6A3R`>#vX*1Y%%mK8gdV`K*%Hqk?Ogn-X)^=ka!;D zpkk&u3RYp(^}2;Rn`8SUvEv}@FE~u$@w znyXkVl&Dpx(kcm5#+2ZcVPv1@`_InLD9t4?BeS5hp|T`0E3(e_r0isjeHo9V3#9|7 zBWPAF8Jzz-&%mD{(9FneooY>ODQJEGdfa}$iM%@|IYY7YqIj3_l@@C54$JwWzrVdn zmXXI0XPW14VBK%mPendPZcaX*Ppm{XdoVN3?8Z_MscfXQCwe$>aEirBmpV?q8xVe{JE|p;`t>-u$J2jaM%v`mgwu-ePY(`!SwX$g6TdHPqHH{owTF}YlFMXq9uI<6M5-hkm=OQl~*ZGA2JL`o}4{Dt;;KXM~;eNE+NMy583;0lUz zI>)vKpqbd2mzm%6I)-+7M|!xsRfnucyGN>rmPZmstj2o>Z(|;~bwN9eeA!(N99NfVCT(3WB3o0s# z$qGmF2Fv9Qeb_|taw5LUn#!iwwE?AA5FFs(h(^K7NKc*9>{ci5EfL)!bL93X9<;rh zzP1FpvH}_0;hw;eQ#}Qq%$^Uy$H1i^Oaj}WXA!F+en~(OVTUC~aiP30ZII@0#V~&* zeNrqnUU_mH2oLYojRH5~8?7EbpG=~m=4#QDg+`(+2RVsktWjljVBm=7`BH#5IFUhnw{EN^@Q3gmt$D+Jw$0m%*Z|q9$U{>9 zvHLAr@ys6%sbX-E3a;>xu#q<=%`7V+)54YVy3JL{yxLRB^=ZYzpTk8hV)MQNrbGUT zv0>tQ_}t+xsUM-*hAGXZfwOVfneap5P2>9V(GY}S3nW(%V#|jo_zPDyq83!G9^8&k z9myB2=kqBgY}7&!vM#wU>t6Ql@3y3Eu>28vqD!QqDDpAFL)d$ap+pIOZh;G8S%Xvh z-x-OhJ-%id5d4nYTN22*DRh&_5EYS`6||6S6;1jEkP(@L(WqBt#+t__+jJf_k?KR_nDzCo#&2iYd#6OQfs#X~e38%KQ)&7gE)n z5GAbgQS1A<9Z#=(rpz}dJcq^>X_h(LQo>hMTQOJ)FwwI-vP3sc*Ne4r!(H^xVt)DA ztyf~XZ=GQ_YyHxbxzXLnG+(m#)LPb}S^7dC{{w(@83w*}Dr@;r1Pcw*Mns2WPxnWr zNwZHczQ_03^dPy76X;>y6V*5OlX~A4_e{b3`Cxl!EP<}`tU&9dZQc)T&-5^Ji@HT2 z*TMcQUS?SkRY1oJmHF0;-Hz~`?gQdncw=WF zcJ-!UaSCrVA$Gpm<<-LXQj_09J?UvrzLFoelif<$Q)aF1S?=L&dSTnD|2!b0T>E%^ zn5bG{+3Wto^*z+v(I>Y@;212I83g3X!{#y!8svx+#4CMib+u%3^~Ekw%W@2Cis;_G z^DRqD1WHil_@nOf4bYaa*yv^!WdQ;Lnqj7_?x_AvmfO(Aib4OUje!vZ(8~6+gbf11 z3*`QMv@&wkCk9$sT03w9`AGlOgZuOOuVw%#@xQt_TJVvoe^Ve9v9UKIW@BJwU?k;- zB_<~3wf||%{asZ2Kf^!Y_()A19c{S*02db*1{W3v8+#J~6Bid3fRP!%%uN5;gWkc_ z+EE`!Z|y+#ZzBJfj;N7?p}m={qnV90@n3ZH4Q!ko`AA9sV)Q@1f6vnhX!c)D)(-y> z>r+6$Uta)B42*#Pq5V0O_perN1v8+LrMjq@m65f>Cl7v37G~am_5Xjq{Fme3Mr!WTmNePR2M%iFW`Sv&kuX#ekT9|A_yWSDx?eqJ*??YRcGQq|fgmBNCFo z&)&C2LJ*z;clL(!7!c*j;I6BC9P_u~zXbJBsMP`$T^S)qM2O%{djb3Z6xf&93OPY+ zH=FKWsw429>e%{@LahX;sKJCO?I0lSunL$@QaHi*ug(O`C>2r>LTA>TcUhEDsWy{p z&XZ~`W?qew8sPq}RCESk8MA1uk(S$U)vR)RVR_^IiV_`A-x1s}bnr~h z0RFdyRcL@guh&;x+Q)Ks4d8B}aIMi%x1u%MM?V3P*8iulT|(Kv;iFLsA zmWz8#m4rs9B{zC@6i`ELfL(?XZ7qatA)7>i>Z*_r!%*h(oN*D`M0Z(-ZxLBr)8NqUS78; zqcKf?Uw$9tD^cQ3$X``Y9`n2G&v|7JUpt@vFy9b#%%MHJE?mlV^vvitb;R#a5~Dl2 zzR%IO{6j4iL4x{tU>%8vVLJN9>eKfHmSr9giP|F}K(CW~iYO`qc{A8T0Qb|hifbR% zKLv%L*op$(4y*jDPbpEy5w-UIAyw2!n$2d`uvZ6d_0W+``^F!*Se@uLOl=m?jS


    @?MJ zboA`jMC^KJPfqtw8-NC~(DB|aB(+^Qt_?TyyO>?|;IrTFZKF zJ8qEym^UM?Xlu7b3T*c*J~*{szpgJdU`wFd3Xhd zS@fLS@MZp4FVGnFOkm=q)t0v>XlQL~krV3uGZgGJ#v6rC;~6C1Na9{Qek5z0 zsgJz|w#K>3)IOI3X-1_tZ8Yq@mA;h>##O5Pup7cISK;HfwK;CF{v@TLCbUZP4^oLR z=uf}2{SPY`T#i+5cA`rPHRlUv#ySLA4%+zp!wgB!EeJCIl+Sp?q&O*SJ#mxk8l?|P zs{v#JJm;03cmCn1(4drCWh7g2lhPMb#&WlqE{oz0{GP0Q1^W{6le-R0#Z*TfiI-B7 zG~;x)=!dLM%Gr!W(z;LFjQ^J=(o0_1VchS(8=&A5@m85{7wg*bk72%HPWn|lTXh0- z)^x6_Motsv(_ERG=p3>oluAkd zB8}s?rQ@;VbUg|s9NvPj1oB=&x9&8WGk3IJ5!tbJemTu1GH9hu3-iVh8YGEX4u*7Xk^p-_o&o zFd=)9M*sRS?=aUlmjmv*I*)*aoam}CLguF*l?j;uX6-@kCH1F}(9qK7!z}L!Bp4Vo z5q~&-dwbZ7JSg;7^1oX#F}O6Pua6JN)E8g7{GuY8wwn>!OD^~OGaPgJD%h`N!FW~j z+3Nx0Zuller>hhT%n5}rs;+mAoxLsBTQ0^NI3Dz~(vxXp>6L@y`WpwTW|NtGaiz*7 zGf9wh-yFpL;W3}N5riI_n2XERdUqfq2sHxE@#>y)9mEdH7??RTcKpfWuv(`4mGt)=Qt%IYm%d2EWt`OPM^p!+ec6u_l#^rk zqtOyH*g-6RK6hb_unM76YY?9^dgaXi+d@)xIhcgr!u0_eDh`&6{e$*Lx~|bF*@_5* zoU|irYh#y{LXW)laRt|aHWSi=|1yt}!)ImnC+UG}LAQeGKe%Zv*DY02-4)?c2?Ue1)nx3f6G zuh$ZNz>EmNVD$MpT!A3zfscvZ(IJKDJB;I88g zils&?h!hplb|;=!f8cyrSIYoqv*pG~`eL=Ot=_74wR10|cK`gTeKi|f*qv&o6?of9|` zO~vp6j>ON19t60$t<2QE=|)gqgwAptr(h});3)6UG<@|VQA=_=AXY733a&LP;jeB3 z+VcgNgab@7Fu1J9p!228v?I}n`5A%>9iK&y8Z@By4(r~!gFBwec;&gWVIc@oY$Ws{gWHXjmGe=Yih7JoBUQD|fc9<9%uGXLL-007lKHx|sPaX!y&OgvVo)4s?zK?r85xK(3o@HcI8jo*TS{flYqqX6bTzW*nMul}tg$ z3}(+6EQXesI=#<5#@=2!8+?A75k#I+r`MzX934LY=B!z?kx^!k9}&{_g#Kji_kQFo zb=7iZH2H9xn4(ElD+V-XcFPbpB9Z~@E6(CDxVtG$w-g`ZjL(x_Ha1MLE9*-pepayh z;K-o|%{YETXl=Q=mL0aB>ed)DpEZUmv#!U29igfVwNuUOn0!I7ZEG-qa^80Q{+O=*RPe$2e@Ee+Aiz&WEMytK3gonEiroKud(gva&}0fUC#cMX!-ZxpK7W#V_&Q7~k--+E2+ zCgRaxfZlu9mRxBe*~JUkuX?m&neA}90v?F-!dh9q!xJ6BY@6fVFS-oOH{$H4q0^H{ zqV2`7kJsZQ$#=T%C4nkUFBc`i>-FQN1}_Yes1LhVmJ&}k1H7H3fywK)l`>oT*5^R2 zy8zFP1$OgiU7(4qO|Rh1TnDj#uhc8EH+RR!gF#-U^#f9`h)aXmK@LLQ^KB#v-t(4c z(^EAQ@a%w-tnyuq&C*wV`LNo4m1M59(wBt4-387LzSmG~!Cs%M*n*CM@_caYVbEZC z;x_Oi1L*_oVa=J1X2v0=>fr6?&+h^PbSy*XP1dLLlVm7xD(d0E`K-WHe&-Nv5FOW-tqKl=SKCA}=E z{Eg3#YnF0HAoAQ}apN63^TL~qCZ;+r!xL17Kg&!GBfCMP|6T~?r_?nrM2Ui z(()RlcM~=LUt4ws258R1nIAT;2gCN>9ut)}$-Sy}F3gEoskFtQeFQYcv!lOZX;Y{+ zX(Eh38C-_wex$bB5PdnBfdh|^>EWgsgA5}hM3&Z+kxbes)=O%B%8IKA(n(er&KxOi z;SY*1!mIHY_K$IJM51tK05CZr^_XiL1H?;8dDr+EVk5VvkbhS;-mI}|_6cXpqHwzI zFv?AhOzOMc7f36kGk>2noF$^QeO(gbUGfI0?07ambP4dH#i^+5z$`IAt+p7QES4`L zsXrNLx!StKAi@9xvh}}ZY^C!(Unw-$-?^d~m2ZU`z+6zO}G`7b~k?|P<{|Gab_ z+FlFnUQPe{5E(Ti%9B!Y_g3z#u`1zg*{#dTlA25gn(G?nb$)$xa!00=P4T;hDPuhF zcbRJHS9Y|R!UyoV;cdMB1k-VQgJ3OD8Z6*jD}?o(K3Z?Zp&ZwYXkA$#^QVPM^G=s3 zQ};ws3VAZ-)G#(F+7>_?)B|hLAE9#D*?DIJ>aXDyyX;dnRVE?~I()a~=bJ6=MJs~F zjq4*20IMhJfg<`gkTWiGbzir5WaX2Ui-05FGCIN=;X>q2=za4jdlm*e+{$!6|4@A^ z3%NnGwt>B>Yi0@6!As~#8p~w1rwO#5KLi3FEr7-BSJw_7K`^ymgHZmv3IG!pTp37tg1ykV@siOD#unRLsvHtcA>Y zFg>Sq|I~AsjL!2?`Lp9OT`Iv4kq7P%OLo$siRz2nug#R#A-%wU4X2dG-_j3zr)K!h zTytVQ8J7~e@G36*)UHwh`FbUfMVRa>YE9mn+8Vo?E3PGGt71V8*w{(JLEV=|GR|LF zzQe1F)NbrmUT-bM>)90T1PlXQ&2s`+`fMVM=l&d52Wd72Jy2+jd+&qQlttXuHk(5w zHXMQW(Q*K^V$apuqxlA$()sczcSt143<10QT!h1@v!2Ry+i(IF>M>6Sl|>xuxr0MO zgvj}N^BOe*04u`Nc3aS_l>XcGcDgfRxL*_$tHLHyr579TRR))mhy*>|D48ogk^U5( zJ6gQ+`uSwrvWB$IP?xE$a~Ibyf>-f#G09>1~(BHMKs>56}k1 z6V~n>Moh$j4%Wb8&}Lhg;W624sF`m54wY%%;9MTH4A%#1%~N%B>T_uiP~YQ>pi-fF zIYj*M{l?2*wK8~kL%VAD8vM@Lvd57wJknr9a|Y@zH8j|Hr)aKox7`UGS`5KTnCS+0xaUxa0YJpqD8b@@&Q3t)L~hmE$S^}MfIHWPAaLeFFU8)nLX(Pk*CzmYEu}*-gpNxCh?Jgj>_I` zUb~Hr?O_O3%i#2QmMtv8srjzTQdKWy@zBF5B$4XM#TyznVdoX0-2fIC|T4vU1cg?{?>z^x)8{z0ToI>A>JwLGJ;g?K`rd?l*m`X%>p6Te)G{+X!!z`Z9z z9L?eH%u_YrB-U(=oX#{J$QGttT>64+a_y8Ek7sFrYd26B<;l%Mn{eUO)fjqkNKsJ{ zNB5{GcIQkQq7aHz?G@5%mBO>}Yy8Q65t}I^&>qgr`n28ox)xwq8dugxR;v@hUscCk z@9`Iw>FWGya%(OGDZ{Sw;em?2?uyCL%9-nv7#u#5UA&RQAGXz)%9Y#~eKx#2vg4}v zUFuSCDm`y!GOc;W5o)T&agPhc{&O;&zDzrtoodicTrtO!CuqW!OUz#uRu2PT;f{;d zo0+V><`E3VBSH5jB+zodR5j951?{u)*Lg2j%Iu1WD>>gYX^s7kGW^+;L2w8M3oo(W zv?8}IyIZRea05kpF_6aSaPkp7#{`8}ySmf6-Kak_du#i;Jz9O?$Q`Jq;eWFn-Skei zLdvCN1IgX5_|`YY`@U9qTY9N8<6zo9qpi#Ea|u~Wlf!d=XNEK6uU$GJ^wm!#fj|6Z zDnyATzX2UOfm~xwT$E!6`8`oseIPr5Zual_wA#8Jv;>LA_84l+jpt)#>tC=i>6tg~ zjnz?&?=7{XTchn!xCpqpXzeuh=H{Dh8M=Y1Y1fdP8{-D*40~m&(_wH7`BSU;l8b2; z1g>n(+UYiJ=MlO@X(t3Yx zr{X_ix_o1Qro)U)d|RxNy-B(Az@5qI8RI;( zoOM3jP_PR=TzBSr(~PEE;!Qum>&&8)@uwx{rm^hyem3(n@HCeVMz>z?01 z8C>W*X2gkc6h$B0%pT%=Jy;CpDPtcXp%ux9ci6`-T_z{&Hrecd*gO-OU9}O3Fu$`S zXxQD{^pr7NO3B=X6+Z~b14e~s>4@kKf@P%6(CATm0gV_N6usuF$W|V2Wsv7u`P&O# zX0UXdo9<-|KC4RcU|&3Zr;v=ciYwE0>D2z(${*fnEN0M}wzS$u5I|X@@sZp5zdBvq zP&eO<@6$BjaAow;RQ9M|gE&D=Y8A6=9N?0lKceMOMd8`FvxF1RN=MT_;m4lLLrHQB zHn|^-WpLOo-$_buNLRINShbyxGx{lys;5!vryPEdj-SO}&X;LCyh+TFS`pWYI+tiP zm}~|cSlw9KvNI!0@Z4VG(n^^|x5}$>*$9{mjm}1@WlcRRo&$3Buz%pe$_IVXRC$@OxBNb2s5@6Y9L#_f5-y1R~)F#q1LOI=_N!V+&B@ zIN`ZVcTx)$T|EW#{#o1*Z+8jYwXgBToWu_^Ty~l+PW4og1gxe^q9~lJa?@F_oO`Xk zt(tp$17Q3vSXN_I=6>m@i@KY$_A8&5 z_J=09d+G8hFrfAo>yg}bv1_~-}px#W`u{w&eQC)S;{jrlRP7u3i z6jsqiZ~m}|LctG_xq|yBS8u`repeov!q3YmJ$U2~fmLRQmhxGW+7I;M?_4mc zQ3Z)d>2+(lHe9%4TTh=<(n>g%qLTk1r0R2nUI;Umz1BZ&&mcS;Z%8(IuyNl_AY%8je>}G-KdornG9N1ScC{VBEML0PyM!u5JMLgCd9)K#$#MFKfEYo5-FSUZejYyvuGvc>RNndXQ85{o>Hq zk6(hzRJOh64|*^60>3Sn?aMV9K-f-H2L#01eM2#5cP2mRh5bjtrt6F(en?B@9m>#< zwtc_oy*ju=83a4l(=AZ3nTC1jo9K_163FS-Y(KJcxW^*5ZF!rYZEgV-dZm*Mj%gIO zWfk{&N9oAmBG}dOf{7V-+e(Ou(jRNOj4nv9A<7Y4d;F8uEfqGAEkK*60inwJ5bzJptZf*I(EmFxrL;Kpx_{dk9fBr>)$7pTI@SZbh{Mh_v z+&)2KSXsx#Oxk)u>00<&#s7_dOq1WCg|PAS;FnM}I;J0~ISiayIw@|pT5b5o@5JyG z1{9AYXQzQ+Xt{H92zBZ=NzIP|k|0$tWP)=gCb@z?am7G41e)|0BKm3amHy9y$9`FK zKdk^sB$2k0@fE)02ye*U;iBGZz=ys~YCG>|&BLgmtgB3PTIfCDu$f&73>yjBkJB8G?E5zKYli!&)V5@BpUO)QxA@od3oMZDXxs<2Q&)n_xhmt&VX zi$#cPCKPeD7d0>6?KsryNv^y#Ylz)LEns^SDUOndA1zJN<~@dr``P}?Y1?rD$RA=f zzctGQr8_LjB3XZ~w~NRmZk2V2YlkB!x#JkZ#@*8jdWdfT$yJJ~Pj@wn5*$sWH@gYj zb-e1(>v;VQnuiF>-K)yXryaoe%NqSnC4W=-C4wKYmy#VK!q1e5$B3wWnO;cIy zDoV+)0}X-sb6?vTIbB$)z-r}*fxDPP-$2oq@aH}OS#}2gFThJMg<`73>C~dcArqe1 z$nm!ge{xu?MnHn>17EE@t2R^$YzaKzQz!T)!(Dij!{7EYt_OydRP5(1p>kk?oPv9@k za-Pwzm*^@3gltu_A(kYs_mo?1G}Lg|4?LtV=GAOYn6QZL{+j520ajvgI+*0cr9^4O zoaL*nwzK&3U3}F~0Fle)Sk?80f>sVpl1)L#4$Fk=^vI3oqDptW%NMMa@cM5U?Z4=K zPS8c^_}2Q8%bv}#H>iN7lC?=o+c=W8o%FU@*gKudvy7EOiGQ)6r{(hNnAtnNc^42) z>zmv7;iXo|-$15+qsVP&(9qDP@;_eTk!^ep4f|gyITN4UqDz$)Y07_|)hZ3d+?;>^ z3uKXgh%a=6@1$1qiC4^1Gfh0Ub4cE8kp%?x(yWiDi7Rv+&lZh8{qw5BU-NbUV(vBW zV9xHfHa@(LL(tMOqo1OZteI0}m!6R@mifKwL(B}s)jSnZY|*fp>)Y^H$B0Q{S(85a zFpD5;+~YsN_b#e0yjji+)C!-hXAy9;D|=`%c4?{@l-$ydDb$X|cCZpb^SKLgO9tl_Z{$~7AiH5;w_y#}K)*)5llKS5RDR_F7nat)St z{>JSdnn5dw*#EV1p;>~NTx@KO0^L-tLbf{80@~ z=-^0^ZoF|y`K!bpG@t#uGPc%+7tHa`(e&mYIeM)oWP$fbGD+)K%;0ANWcK(+7hwYf z1KXGL#yp8ALbnFqPxe&u-K78P5>Qe!$av6)_j;ZT$4e_RG5UEL4{CmWXUG~dAHJ`nQY?~s_liJVhJaWh= zUw6kj8qZR+FE^49=$deEin&y`C z3k`)dBR?f zB&7mrj3h@4DLJ`&^~nDqRR3L^c*ZXWuIwE02zqOONQ9mk zGKs4V_e(o2;QP~|Vym;2;eJr#P&LD$*<5i2Y^U16(btd;Yvqyv|OgM*po%W9aM(gnJIgiKOeXL3)*aDsSxtSgbb#Ha z?w@AfC6GE|R^Ho^F0s!Mf0U&Y8C!kL;`YZBgUuuIHZ<;UBDjD@8V>B9Gae-IFnI|> zrKh`7L9TnV99TV5t%w)tufpZUR3CY15#22#3@3ENYW6Riv&|%cI-D&r?WSa9XA>J*tjx*_M0mg7W)-VdWh!3idcQ#=2K@R( z%*r}9wa-h_S*isHibx*?bgoH0pVdyndvA7l${7Zq?(~-8t7QHwmiXRCZVky3>B-)3 zTCTo;&@lP5UWzZOKI}%iBpEC=og&X6K0cLkR67p9m-mh*-^^+@u{FRl5WWLcP1pq+ zn@$AnzfiV2(r$b}m~vdvw|&?X&E=Q{g#yC2dfbHD4e+G<z-ewG{sp{c(N@TQXT7O9HEj>cE_ z>O0d^o-Qfb-@NSf*4jNS9ddwS%q6(ungyBu+AxJnvLSf$mN$DL@s{AIP!d;36h zP|vJ~htuUu?KN{FVq*M|DJwi{*M+VxGwNjLa8Yx2c~Vo)Sr>a?Qbo72E6C0aSbH~~ zykUiwiF*xmZ-pD#B+oCLw4%RseGUD(azQ_`ntT)4)8cuk2v}h3A6b@^bop1xO9UUg zwN(AijL~qDK$2f%r;Z~{Gse%uptP^3Uu(0l3-r~}#}kAwhc`MvJdNBv(QE#U_zBj> zv|xc*mt0=2oHaEyU4avy))4-=Q@~x_Xwut2eE2M=?nH2GfONt{-r5l+WH~Jz?=Mlf ze%y{A3xM@GHPcerFvR@pHsT19ZzxwxaItC2urdkixq(CYt?>w`-XqUL9)p#H_}~j8 z_~gz~zvZue(dmL%YlVV~{>HjK2eH+P$M=^EPLZTZr_M9cnfXD}eG~MJ_QFKFZlLR` zu~xA<45%*#G7d(_(2ykf)DvI6IUTA_W_XI?Lr(8*RgR*gWah2s6Ar?0$>&B%m>3E4 zwk;JS{&Ux-Xn3!pKk|F}PGyDSE^HOVz;@&qIU(GWV$msK?TnTnL873HQ~U7j0rM%s z`gO)XJRH8xdVPh_3)s5i0}958WIUc~WNETn*B^$3Hvo62_=G_5T$Gge(>M!(*jWn; zPe^qi8}>&2ubqK{9E>u&+`z8{ccx+$3o75eUz?__nrzBr6HL}nkhA7(Z}?iEB-JrP z6D0m2h`;4^$oI>|IqG`ASdcgDC_9?!*(=(zAPxM(JqDHqsNwbN2I4a^x|h$4qP<-& z8>@4VY3QDfn5+rzsRKQ#zsNV1Y+Hu?6+J&svFSbz4BzlM%fs|?XPtyMnYi}7)$Fj7IVhIkx-Q9x|oZ#;65D4xL3k~ir!QI{63C_Y@ zgS$K2m3_YRzI*TQ-hcPsnpx8_HPu~JPd{CKRngjK{$x0>Xil$gxT`%3n%F0rx~XoLTEa9#U}_t_I9}29018sd-ri6N8%*jDy#s z@#@nD*z=1W9`L2=%Yrz>yzC$|JoxnRPE;RDbx3h_fZsd$T<_e%(9ZG?&uaP_Xq(Q} zAa`WlU}a(TtrAO!SVu-2tVt76p4lL0{TDRxN^hvww{^mChdra!C^WaLBa2-pw)~Yp z#@LS+Dt&TBIV?@PE)MQ`36$1EXP9fkaIL2DZ0wLW@>b=`nNxyI=W8yD?^wnx-T{s5 z!cKLiC6c3#Ktd;@V+`<)51%Z4AHBqs0G`oPE%abz?$ zyKk=@&2gvX*%>jwkS8I4c*_GB?P?yX-l-XkXPn1;k$L<%uEFTpcp{>m?(GiZch{dW zk*$LYaz@a=qv-lX3Yf7e?$P(yiT!t9{lJ-F2s+Ikb zJyKaSob~`+9AVc%{rr4|wh#Hnp<0z*B)jGO=4^@bL^8S^sjccxo>qfJ^V`!gFh>~r zJ7JliVWP2W=SVOUm`3iCuH`2y-&sU-5`w3#kH0 zirRKSB%^kw>!ItC|KaklqO0(>xJtVFv=V5`=c>%VQu$7Pq!c%m3b(_PuV* z>VP_RXHy?S{~l4#P_w7YGC7*MO&l8#@VF_SM)`}f z^>;a*L+R|zYwdjc){CCOHma`Yx( zbbe>g&igpY>u>V@Gfa8WK2Mh2aybHb@HzepPIOmw^;{iXcQr=f`@m=uf)tL+M-*9h zfASb6IqDFUTgq|nC;y8o{t2QIY8GE>yi8TcJQdWuYHOm*?)4Cp-IqW^u*Vq#+tyOy zk?#PEyWfs!QtHkc!zyY23K|7rG|;Nk#OYGg96hgFzSTuJTMy7PfWmF?>Z9Du!r<{% z+VK-QzNF*exNxR_YUB^!bEumy4QZZbtF$(Es;y^#7GMl@hqTi)n*=X=IedAYM@nFHA2SpIKyd3JX;9Itp~7}5ts8*40nj2RlC29{o`fsEQNh~YColNhC0 zxWC0_|4;D=!njdo?*Ut@98yg{K+EsF>e%8}<)^e?U-lPFL@^m@A%B$`m!f4(mpeHD zFw{Dyzi&tt7D;RTC$RsYk>&S-Qk`Z=mwMIm&DGGg;poW}M1D8b&Ds$)0duzma~)hI zaa`5L@o3FdPpt6LmGAw(dO->5#fbVc{$v&FK6`S;hQsTGYY76eDqAfJjVlE{jt7$@UrpiIc>uf$#{DaQ_&jAnPCF z+xFNHS69^=A&yL^qsEeGy8B#as~RM(2`WyAw<%G7RIE8@Uni4T0rG+4J4dKG|2feA zD9nv}J;+K15zadvJW1IUSW+lI4eVhhgC}fEX!Wr50Y~TiO!@u~#`V7l&87f2AgUs` zLTcN|mRs#nBWc6yY@{v$RPLLmJ9waJGxz7j!cjPljBo$iR+hfetkYopGQL<2Lz@gk(39sb8wq|_o z<^y+iw35GexG&J%PLQ?+YY8wP+%C)flGXojWQdv&qH|&iFh>`srf&fm!m~>U=IU|w z`z=A2+^#_3pR=t39PID!-lsItQQaWAxqMC#Bz!}CF4Gv==fuHI?yyc#rGQDOMysXm z+@JCBJE+Ma{}8ed6a>U9`eJ64^YQ!}#-^V3c#-Odk*1Lz^8!;N^*99L4@+>RiDUYJ zG8PfFF{oCTQ>`&}Dd)dw7Bvx65`(sy4#BM};l$I4)Q?yd)W+^5``>Tsz77=Y!jHo{ z9V)_>VfSH2i?YhG+Lx}WWV1`?x$&{ zJetm}TVg3T9E!21NpW;rBS-LFTD>5AD0oIJb`<4Yy|(+9yJS{tq6GU5-((qn>C&DF zL5?UqQ5f!Y>kBLIKlM4m3*tkHaPrGU;&0G9A6)vn;i2n0ttOr)d{6%<#w07Eq!edQ zUYYI}l@eWZ{bqNB?%Hiyhewx#^gKF(0Kc7>)$AI3VAj;}T4#sIa5dX{W+>x%Z$H~G zqOqD0`}9B43phxxq-eqQ_hvc|5}Mx<#UOtn0Dm%no1b*$r9CsfIfaSQ{l>LYBa6*R zj0*(b8TY5l{?d*45}qZ1zbA9dW&p}CBjq^XVY@4HMStYXKi0Xx(}JmjAHK; znYkP-c?I^Tl5f2*U8LK18av9GIriSGcgRf{*JvG_#u66|&tCS7@0V;+_T;F?KJFZ} z3fxodwQ;lSbX}K7Va8MZ2qKsC+I{I2p;MfoFV_O~_cb#^TJEUm5P#RlJg6}1GhLOJ z5r6Rf#o``?&N!@J$gtCd)ineI>#E%*I=R+Fdgk7<Gb$y@{3=qbI-=j^C!dd>b~u z$^mUuPmy}joTf|zNs(QfNdPop-YvQDsOCsgs+r^d=UH4nNXy3Zo)cih#Z`y(#hui8 zjH&QQj%v#LyqUq2)l2P-a(~cS@2`1Rqdk+!t+oP{g(VNEHR^1lw?G1WCXM0sT(aj zmS8W^UXWD(aBJnLJ)aaVTnibxIV>zx$aYNbYPunCJ~y~`W#ju-P-_nFme51e;ipNf1lI@VJV3}#uW9C2l0yYW7y%>a|3Z-~~9*aX;8Zx}SmXYi<>XD8+-1KTO@c^4>b`4D2j`vC|*j@Mla35kDN_yie<<%HI692ZKBVfy}4 zmv?Pb85^u?9Ta!+mH|ES$(s|dZOU~I3|95D@y*knw0(#TK--f=2o#iNtVo*HW8zf2 zquXiop=ydPd|Wo$Fw3*ZzESvh!R4I_0@gP-7>-OpWQHBCjsl?07eB)|4(8QavRAI_73m0yekr zh@ad(*m$IB8A^f$a5{HW)U9cg!yMJb}X6d&YJG>%QvE6B^(i$Cl-5t`TZA#ToWdE)yF+ z>b^akJUm*@nooi0f6ne~-MA$6j|id;4nlI%XK8w%TWFumhhFVRzs3)*Va|!2GZ`ABB3>6Om|}LxXmH zgFJ=T05ms1E>_3k<+P^B?5f12C?sBNuST;+f3mQSeVSm<$&;Z zfyMi)OzRt#1FNc@c&*#NUP%P)V%Hi;jk|U1&(cp>fDj0NcKb7Z7g{k~qpR)!3I0iwW03E9sVM0dW zayq)**y%#8n0_eMdaF(**^z6AMA@9S@_Fy`(4#?7uZPYs;)mcUkS{1xpjk!4rA)Dj z<~Id1O63~S?w9ioyM>P8a|{C9Ct} zCj~8V|FLR+GjSkpa|pN!V~{2{&EIc>o&iI<`2L>w2@T={Ww)nt;^?rVHcz66*FTE; zz(7G=1eW0NJ*C+j}8`J_&{a~~L z#teLa+v)rlR+j0DEx7weMhy11&Vq^vK7yK3c*L>%4~F=+DER(QP4`6L;D1&8zy8$- zGB~sE$fSm}{6CDs55X2HP)#lGFfd>w|0ts1{YNC;gIXT6{}jmx-=CUZ#Rb9sDMi04 zVdCl+r@5v~@4Kb%oit%df1iCp>n0zd2t5vRl%__uEpxF2Dd$19UO1UiS4JuHA08cy zpS1AiYKvn?SlCxVL0@}~2LGAG-QT~t;wQ5NqCpPnmmSn%{{ILI0@B|bIS=j+U zNa&dKbgTMw#QcwlxS+Lz`h?s3ho5wlU>E|9B|v0|p=hFeVQrQ0G~WnuMYKDql5^_+ z<^rhl!a;s_!)R#y>z}_}ZJ~C$U6MB1ZbX50^%L{(tZ;FSvB;tAr-Hsu=A*0?IMHl7ZO4mEp+&1k-oV<3nSS>_w&**5+`nWi zg$~|uI$o*>iurCv^JEaRuegq;zyJNi_$f(u&%hNG)hn%ReYI)E77RpC2}1*gL{?mB z)mY!%61h#7Fq!nC(F+Wud-Of;x4+R+y+#cjzbn!3KhZ4yv_p5t>IRH4T8IeZ5p5~< z!aQ6(CSB4Q22hS)N_Cs^*4a}A%Dp_=?;T5ckHqkTBrJ%KjrvL=(Q|XQl~S8pG)9xc zPL02{)gpeMqa3rDE}MK1g&n!lWJ~lw4P&Wc2*=cn}Rko?}Tf}6zm{~_Zc{>!lIl2n)F)6Yd=(uDR6iwzA zPlqigRaWz~>ht%YDdIe*TNl{wv4K^)FEc4p`8r=pABz zMUU~5$xFo1_WjQXsya*e30!~h@u!72Ij81{Q(bg|Q zPVWY$>MRQT6Xv8_pljoVl&94K>7gv%fxl1mjD34&UmMWXo}_Mrftfvuwui?#991UO z66gTS?fo&U{~nx@z9-ZXE7r+?eOcZIqDk)le9(8)xnG!xMV?-~ORtM~JRpi(^V4Fi z4GFrUCOK&Oputsr(;A$$@jaR=%hR*+jClM4-p7n{&a|k#?b$;o@O*#H85P$7hi=8` zg^4h*-Q}=AHt)j<&x4;ZoJ5lBzpEU?tq%K9R_BB*<;3;zgw8o&aB>iw#WI3uHJ7Jq zQh*hWro_j<%n6#-7Mfcm*qB@PN%<`$G`a8#WmJhLvxx$p_|h7)tK%78?~lNp4Ckn< z7JM^wtNKExx3Zw+TjPjHN2_OW>?O36%V(QBI!~&-OV_Cv7;< zvrz4e9ZY(FhN>Rxkv&#B9)9lr>e6EM=w(c0X!dRVjkXl*+3;0aS379K4lQ@tEsQ>) z!L^$oElj!RWy+sBtBeyH&-+&~w31!gqDu6v50O>`!r_CwOV$#;1lX=;Y%VikVX_5< z&tXHH32g9o2Bc@bs_)w*@vKy;@C{+|`gKjpR!>Rx^oF+R%(>G$gElOjzme)Wrw6x2 z>xbMcnyjLMF`PnC!IxDV~8 z(zNiMfLK~<$&h#F7Gb%<+d6IWN~vSRx|&zMNCJE zN3$zvJ+w0`DO9R?M&0|yZrGAzqu?xJYqB30Hp%UIZRKOId?6x}B4r6)bmAKPro{!( zgor$F)sMy%+l&h&^8{iNWg46ez_gC4I}SSF^V?$wSXd4G#-RBeQCKd6U({ijYB!rh7x?$6t#%Z|BIjDg2(#Yo`+Bq%idrBq8uK__XlL~rNk)f+0YOo z-*X60rz?tmGtHT_SIyvC`#g|c-$-cx82BS-%H<6VQwBS#wGTDMi4 z;+ff5+2jy?<~z21^mc0V@Pkz%z&|~$8mv#9H=v~I{`Y{gg9Sn`*`)|7sygz}FFl6O zbbi$C4_+%nO(>07*@@GTqcx5O&@#`$nmGk%>NWM;0sI{qMMlp@k`E3ByqH%*^WM-y z#r)3aMq^qlFnCD%{R3!t3ZWCmSttwTv)39mMl2RL@ADcZX6%*7tzODlp^}n|pY!-K z4_GFfx5#$3hp2-FwtXSt;ht?EjPRekGR%Ajz(^bD=fXp4n*wMbhY5P>X%UT z8*}DRo0o4S=Eo2+`dEQ;u+X31W0QPaqZAlj_woDhM04h(l`Vq@UU>Ia4S6Yc$uZpkxiP>@Oa0wB#2h0bE%cU2T94o%@qx^lze8D@F zE>1-g8Xu(wYBgsr4^BwT@X-81Qrvj&Z}T*&?U5@O%X3fpqmA4)8jEoiF;0m9xNNsG zjXxL9bviR=c!xd%&zXG(spxYF3EezUFLtwLZSIYa zDjJm%Cx}ihtUsGgQ_Hw*dG5GZsw!s+PT~YiF{Ygn*nLkocH=Z6?frzdfps(2Ge{uL z=hdlv$>T$F2CW8Qh1P$s$GC~j#shC_5wXvNxkxGJl20cZKuzXHN!>*|AwJ*W7s$~;-Iv?0egO*&0?KHQ&$g?YH`XVj8G-N!-WV!wJ zm#1$fb%S?|KVf19tWS=A#I)*FOryKdK=j!a(h(Xf8`=m{w2wTXC8^9u{RCN@9~H6U zV%~IqV1Kg9s+O(wjiPCpf~3b{U`R?0b=ksJn1z=8D2(~Osyo7mX^1!NcT}#VjkB?m z!9vJy9*drqBxwUX>IK4Qe4AX<@(FpKAyvA3@V!l0AemDN)vw=$g zo{#r6pf@7a)-HRHueY;fYRzr&zDwOv4$L2pn}4?R=#=p5B!**kSj5^FI*;uf7v>h> zPo)5X0Jrk#L)I;C8AsNn*r^hPS=$Yw=rimvB5(Z=*Pg#DpE^L0YVOu~RH^T2n3 z`rgkkGpf~r;!5C8&HrD)ol1wzvkV6k`(?6j^$ofILIBcn8Wr&w4mm$+x{E% zuHJQYE$HlpIPc4=Z#VeMu!^_ZQ(=?eyli+E4D!C?n%#zQXL!C|T@kw(AZR%i&Ky3L z9=OfO9(bs7VFFsAN^G{4IrwzFDUXpw=C2R z*0C|$Tbm7krz#zE>6hhn7JbMR)o2z#^Xo5!7c@xP z1gm!PEZbmbFbBJ$A#B3C5R1fK3C8Dc8GoEL%X!D&oy}zO;zc7@fUWsplzL(-bFwGs zT_R;d%=XPFpAU88JsS*Ma84yXaCLF_=OO|+^)qS~-Ppb0tb05hSuVOG$9cUv&AnD` z`lFopQC2P~pJeL0GtWDF-^NyLRS!R?r87kLg!G@=TUPwdd#>m5f#s^C0q{2o3`x>0Fiku1RWVXQCRND~I;Tut z-yp1FokQ?J=cZm8?JP3tTHKpHjF#RUh5zx_qaq2Ni5QzvPDff9Fo8gJg(5{>%7Tt4 zL}=51y*-L~cdf(A1Q&B2l@CHr&-9<~)TYSP>gP`R`xOErcq}s9MSK^*$xu5D#8$+>QLRQXvpgKoL#{$gRPTGcehjMdT|qru^ZDK?P?O<^xZQ!^CUpw2Y~xU} zO#W<$jnfeab|4UYBYrV6;6Rdlx$;3lJkOX{w+wSE3&0a@vvKn^V`Qrsn2V(aOhL*< zZZ4W^V(zRk%|_XUMYa{$?^J89RD|Wf#OYupdB0KhP5F6odS8FCX~#hH0uwEFZk%qJ z>)B<#Q7G}fAgt%6WZ^3Cz_qr44F^kf8d@Nik1v@Oe8{9$zn zDJ2YN(o5KOxxi7*i8qO#6+_-B-`ds-kOmB^?DNX3@>?-&>OC5Eok<-Z*LYMZq1J_i z0Owb+D99Tv@09|rjy2PQw#?uefQY0uRY>!ShRbv32>*e`+B0?NXlTqi9{JlqKtzso zG9&+SxDgPQ%Ol~ed5WVr?&tyhO{P|`H{G*NRoc2}h5VJF9kI3Hdl6F~Uo$!q0+Csq>erhS8xh>pRi zVVaw8EHQiUvHdBmEI&$m7(ZGi{Y&asF?p!c={nNNs0nGB8`vf;*XE-o3?-DXe#YogKb~bk5tqp)nU;>>%_*GJy`IlgdT%dH@nj;9Q~5M6H~&5u>b(E$-SzT|Ii$Q{Dp^TPb3ScuK=Bn zn8YA1S|%*i^fmP|84WI6>v`6Y127H%)5=$)6!?LDIe1yx7mg3%q%!Mlv6%?j(dSBl z-$&*=+%lN4dv-23V-Pu+kZ=h%62HqCZEvy5wsKClZQNs*givC~lH*gPx95WwG^RnE z9%0H}Q}kE^G05E@@-QscS|hOKX1e651vr7;-HTpocJ-6p^Ag8|a%Xhn&uw_}N~Hq0 ziS(QbH_WI%aE+b0_@v_sx#}P2P+=Q}&Bu*0j&Q;wCiZ;_P^_;HR?|_ivaeJqTd^1}-W>kp+e)0OC5c|M{fq#;&K!AAXJpy}dp^ zC(0+l2ZPliBOr)4TxquRyiquvsvri-WiqDs7NGxEc|dRfASj4HOhgAj1x+e>mW-i~a4*=tzed_*YY{_d>9+ejdwXXY1cyg`=^myb@O z5C)rHm`_Yknu~rfnD!SZikc6ECSN(0DC^*tn_`~+nrHADJx=FV=_e$rXtK^awj`xpbu&h!1O_>3!j zNzSIXohUkc2XNLEPe?}_915+@*qwB7JawIRH2bV#rFFp&HGB5e{x%$xrjl_?_^Tby z>P$s!{8Uc^eD#qP8t>HFI9&NDIi}YQKcj79TG%PL zXCmf)Le~RaA+ecpVnSQreQlII3RAPSotBa*x*+*xfqLJAFb&1R;x*&KFvM;vHmFHn z&|)`M7^KX!}XE>$%=6h^*^# z>;dnsOXM5GoOp4)aQ<}jrHXI^Qnz^3WM%HhGqHC;3wv9E<=rA=y~pJSQ75F>YPi^w zg)f;ZuO&oH6aNRV8Yt+98Cl}WHdlmdFZR1HCnK|b?*nXP#}HOZt{xNQ+f;D?J9YTc zugDWb(aA}Wb?>~k{ym$rW%?T^$H1|S zxzQdI1d!<(>bIBbUU0Jp5B0~Gs%GUzW6bd?{uDm^TS#jO*@m1WcKNOD`HE&H4j9Kw zvp_W;{U~du24>0?*4Z^V^6j!qd17K}7$G*r^Y^<+yYGymirRM-Z*cN4dY=xV>pdW( zk@wcO_?w+*Ta|F-_aGsjjNdreNp2d@d=-ak<)=1^14a({P=8KP8y_QJw#!yrCet6|(+|n^ZF3n2S}rTe_Or_wV^q5KFe8Y^c#z0(s;$N6jjZ0)!&Zm5stm|jz zFFL%O&J?Mp1Luw7*&Mu0-HJ_!(nBty-Dr;KS$z$*_hJh*bSS_FEf&Ti!)ui1FWDYm z;`RMli*DU-9UFB)vIH(G)lRSAWKNWZd`UZUP9Y7;(|7MD9mpC9s_XCXVuFE#5V|Zi zb2^J6O+6k43%|%?T+}mVF*&LQx?SUy1iN5eRCU5D=+8!MfteVqE`CS;=arkvy_Njc zALIi+B`Nfzv0^OtV&*4&@=1sl`k214zsh?5c@qI4Ead9Tg7YNc?E1ZZ0+8j%zrSIo zpeIPGY=J>oG|{eBHsBk8b=S!L^>($x?o$LohdDL4#6_m?t$brbA@G=jM(bFB`~pFp zwZKD;qfTqRHek4Urm@c^Z0KBE_-kJLf=96wJc|1Qz7{}2=cK(rv$inT`sPh!#;T6Q zaJi7wZRR;`;o|g1J*!f&@n^`6xxQrx3n~k(NZVSCT8YClR#~*^6`^x&jYciFv||C` zmdmPBsOC;wBX)|TvYg+mQ{0%oR`hz~SVYQs@}T1g=*WL?^)97Cp|=t3jGt*&|5Eka z{2f3oLH^tiFGvZ#;sM*Msu}mT)Pa0* zRA_2jRzbNfPw~64y#jBNX<}}tVxa#wMACL!(a@S5BV&$yK6D(|;7>XQUjf$4M#x1y zuE&NYd9zBjXe5$fe$lIMIXN;+>#}^hQK+n$nT=*W!q*DB!I7fz*=-4x2)`(xARx-A zZzP-xEGd==7g>iLb+2OwC=aa3;C_933YVXno)sZ@;6^`{%awDb&UBY>s%}^$It)&D zAy#3}6azSex6+*d%trznN2h#m|;#%$WlVc!*`b@>_iCfcPjLw z7vuuhn%h3kU;4BbWp!psXH{G@PbTB<`8I8+mgn|(uiC&_;)u??vsojyEE_R*wNG(h zlW@Ao`gjOWnh5*~8q8D@No&Xuy_@)hDM^Ta?Ji_QIH;0YjMmwaf;KHmPJIqR#!_(S z`rz562dQezCshX;dUr#Xg*~6}>Uh8>Y_4DURVkqnS$W9u31v$1hl9SRCvaC(P)l-0 z6x`E)Oi$X51>4L()<&$EmJvZe3@aP(*I`(Hx8#SYEmg>@6d8QSPriCQM@9w*C()o) zxBr+W+%-F+?m{pmhYMxr;*#{yn`8GCUYge|D>j}Ab<}(>UByV~%h7w+r;snUC1-U? zOp;L*Z%&)xlW9}4v&68=h&LS^0GGI+j0lU_t0V&1UfminKNV;4$MFL2Skl?zpHl_S zz7E!0YM!t{wM0~szh3UzkqEaYNmNsj-({hTp_XfgSRsxUjd+i4GhofX`!c5}T11_B z`7Zk#|3cpo0${|o9r9>24^!WSP=xm-yWHQWf1PRZz8b#WAa9rD)IrzL#|d{TomJ;t z#dCSYLFE}0*ZXQ0$HbgOu5WZ1+T6blX+NHCiK&|#iI%(=dnB_U>lDf%f8yO4$jA&v zjVTbG2tO;et=4LjCw3lvxP?aXe~+nAp(W|Bcn9CJAKBp)gr1M6Vv znEwsjq!QF$p~Jg9s)NW@H$`fRwZ7?Scv659XsiZ)%ReufR^GcwZQy$pr2JX0=PzUj5~{avYirOiW1PzV-jFX0^#blZ{u4Y#nVT(uBd?c9MbUe(#c zn|Os)T69prCGsSqMP8sRc_>>E2e><6O`L-MRuVxXKQ^wU84`1SeSO>YG*@-={xBqP zb39)$qrAUt@uT-l;Qd;FqKT>f!k?dsX|hy1Ks1`4QzhZ{7oDR1N+By3%C2B?6xZ!t z;~{+RZ->(at|=`nfbsX}_06=^Sf)n;S{ri5tD>3vgK%S-sA7nYLkt`;lZEAFE%yi+ ztnrtF!xRTT2EYsvkBf}Hnp)v|)%z0@Kw5fKqKJd9q=HJS2U%^ zuY2$@xW@NJkJBz>*;vk$Nqyja;#Vp|@Q!c}rsk9!UKQ0fRUtd3SXzBy^pQ{YE(&^J z6-|w+)mq>4lZ{!oa1Xig#Jz1PsZq*cEc(LMpun{2AwnR>l+;5|L#YTn$(TN_%Fn0? z#Yt={K0Xu-BBAA*6Sj^>m(@yC+leWIKBmgEo0DNoLT%+uWJkIk$L=@%o
    10fR1+WPdU(=g2S(;h9#Ojp~L1Frtu2RY5Rf_(HryX*c{rps72va`ICem0=@DBD)qIdx4xRk zCZ@3GDC7SgI(}N8fl?TntB00YSczCIMtJzxA!VHI#DY1V{w3TblCAgj#EXvf8XTEs zsM3wT>XV`@DEBtcQ1yxZvp4sxIgEG+RjM@Ej^ig%4vlo~;MnKpU>$v**6aOAX;wad ze*RBB8g!=KN5{vPi^kDgZ5tT3+YgB|+llqj`KTCkb8Z0|-``Fc;rh{H$qn&K-H?Z( ze#hW4%PwE~Ynl1wFdAU(pgyp8LrY1jZ$ zamBqmRAidC=(w9z(uy1jx=PB>yKU=*#B=#3T(FQ+6q#f-jj*+q08`G%NPvgg^{j>d z4LB-WjwT(yW#UoPuM>+w(Gk!)k&QA}W5WKiPDpsI^9Bhh&s@61s6l%i=_(F<{Y-ml zf{ni5!vfnG9RRkV{!v4@q!U;CQnyM@6Rfu8cRD6hBJLbK*($tZL*67YX^5EM+5%5+ z;Au4D@0;Jr`$4=4kYuajy(4TG*() zIIth@F*cp5CaN#Hq(WTR;_SZhnblR7^R&uY2YIw2$%Sv0<+CXG1WufxE#k)dFG66L zRcC43`adNVnsD0iZ!K0$3op!s?k#^!mkRG;(k~(Vn0uTHHBOu|5>x0ub-kxNYv0A3 z@X0$WAz4_m{M%MhVWAkRHzvJ?-D9egMno16b>>Gl@p27nc=xW+)GzRRQOZ0P5^NNl z?ma=Es3XCxwmHC+$%sWqVciPd#qWwu@#5-~23eARVS7%Wav-}5Ih z`BIEP&C#Tx&f@H#^dMuiivsh}Cs+2)r?Ow!k1o4i07Bvs(m_v7SkN@)FoX33a-=(W zP#6h4)2|*ODyi!ugwHBjD2 zIa6F@K5PeTwd9ne0upUYZrot(%Hnk==Cnnn^*%oR3@U4BoJQM8v3Rym+hBn!q~(z- z0jppZ0`!QuK&6zm%SR<67JpU*>CcgpZPPAdP^`GDW1W(yE}h)g^O%Pd@hMEpq?)SR z@O2&b`rc~hxS}Z&w^=g5=Q|YLw~53Ysz+s)N$a;qnIDL?r6P}Ah1QW zuW^Fq*)rvo8Z!j|uDH_7AiG+HBJ(Jg7Gp&^R*F4k-oH4!>2P*HR}|AN2mIl?;6W%1T~nH5{T<7z^lexs^+B1QBOZl9cqSSG<+;{Oj0TlPMZLkY z^&mTeSA=k8)L60afHegnv+R{+ia^KQgexD~+z|B9yzo*(Q&=L2 z6#s1E_g5MxINm1BB|Y5I%}0awm78 z*lw8Iu;_D1wE5m|mxBZAnatNP5#PSqYH2mJD^}w{1kiy3DBCuYy6tW#cXw>`yh!Zf zEI&~W<##rPX=%S;MKb;9>oEson)bu&{FX%|e+NGND}O0exR)lwt)Yw!4f%ukrkb(P z2lBn?IEEua1tKRO0CR3~pn+!8g+zieE6o^t+?&T6%1|Q_w-Zd6dQ}kDoff_4^UH6^ z5*?e)rE0Gmsq6hSG!a`9+}?%Z32TAFt;bM_Ui#o(h(;3anHVjz|m=i zA2$q=YSYmVxItp$!DCdS`)82cpmP?4*uu$bax{Z)!15{9#GMmRk`g|BP~$`Oec+Va zq+t$9 z85MEJeQrg`^RJtlaX}v^w)NT8a~@rcXlbFfrd?XOv0}+}o^iVXu_udTO6?C^3^_%{ zwW4Vs0+QnN$@c8PM&!kXw>EtVoEF7{^grvpic)QR>DZf`Mua#!ndaug`5dy<3T}i} z6A7%1ArI$T~|#_uLwKiHO2M*u55gxW7My*VAEO5s@Z6Roe5kMM&PO6_+M8HN&_XVq8YAf5t#_VMtEH)k792%~dK<%}GVL=_mPg zF2ABIZ>=YvLd&EZ#m+=MaxDj48qI`n*aT;ap7OX|gAMR!_(@(pjlo>+Ufx z`o~vwYJ@u`jB=^zI{?)2rw)y8;oq$xU2I3Y7gWR%X`Tqp^WTA5wgoVq)Rz% zTsovqhulzkgR~(z>73IqpKD(tWg?$!Pp+^b!L;S6{X%J@54H3|yAti}?Q_sV5PfzG zO6-1QDD0K#iDaqWSgTj+m=A}m*12EriN@`6g3<}_*0d<-U@@!)rna<99Y>nhX1rK= z6O~|1Zlg-g{}dSAi-XL=lYRn@ed7tYZX1qcPl9c3ZPRW{p;pGdb<7>jb+F5oD-it& z%aY%mQE35%7AMENa{aiU742!dPd+ZS>b{?W7WXj?4p$V0A}SAk*31PhzIhmNz>fpt zSMTJ|P_(h-*WLyUZ;?CkM>UY^%7}1u;A^m%?zHLmFj4LUE!W5W7C-uA(Qmp4jUJ6w z;aUA_O=``Uux5w%f&YPcVlvIdCJdgf&92T~X)%=hVb5Xob1(=0nEqCDmcH3gwHc#M zx2&{zE5Mf#xt%~4&x9{xYRxaxVuYmcXxO9 zUdi6)?0wIV1FLE!wyCkFaoXsRt9y&6 z5@~NMVD&pq^=K!jq`|kZ11ML9CiWj<-LL2va*W!aYAqSKnOdsziN<6b@;WU{jAOf= z?@s7bYqxgMxLhxZo9HN$o&eQ$Zjs`q*Jn+9lvz&zX8ZsC$+8ughY@)es=X*HIGX)` zX7;ndIIY5;2Zj$hH#`Hv!{M~rsO8n_w8xT}!9hVm)vEOT&N3JGKB00gO!*zZz2x{j zXdg~wg?QVdn7%yQb}wKl7@6oOEuNZnh|={p7y<%qwfBI6!;5#QGhP>ivDc@`A64#&5ZTe=@>-`C z5}Zfs%>P<>dNr_BAZ$y0+#Rqa#3tT>m$kquId(y&Ha0OrseXD+cQBrp`cz17?dZ|0 znpZy~jwIV|IOso9IzN9RZkSW{U23z+ug%9f290tHR=TcSMB#MEqX&IXY7Xi zPT%lyepURS1`_1)k!ZoWRwC&lTBP$9#LWa%o!CI!C!!w`CZexoHB}K&Q3Phjd+P8` zOL&SFzA55ZwHPB!kRr^N4jn7&T@=YUGu-W4kLWNsCJ+OdN` z{CO|D+|1X2)%1lc^$^UP)eG^-=aA}w5k9S2YPAsv%E&H|)M!HS?u`whU-PgVtsaPk z(HhXmSMKI>q0aXMG~bZ7<9jz2M#A2umvQ7|2(CYL`T4CsZ4BB!^Aqk|?AXKky#eoM zrh-3HJ=8z5u@M#B5fvWG6@@+JA#8 zsTgyM7GByQT;{wpVM2~`b8tcb1VzZ8o@^!%%Ge3^UerS<))GaYKi=(fSJ~|`ujy(z zhU>s+cnEzpMMR3KEA`5YtY81@v<=w?Qi7DE9oHSrS7Tj4!brHl(yZlR-q|1^rd##=TCGZk>6XQoDRn>Cvvf=vPE)#|> zk=fPH?Z?gZQY$w`?FXHOb`dms2HjU~^m@#R!Dvk(=!&s`X_IaqwLuo0cEog^ct-_5 z$3#cW(P3@9GQBqL`%&)8nwx+)%|#OVv)$y4iWXImI$F`>$9av`R^q(^PO8LU1agi5 z^CeX-HXJI?9J|wfdK$lLi)T{(jSaAGiE%iet;MWAgN2hp`_Ne6 zgaadPqXBasg?aU@p4L zQ?m{D{r61VM9zy17opVw#f6tUw%LHJ&u1$U$AG1QNr%mQa6l5SIwF#&hoPp@PmIpT zsmVA#-c~Ec4POE&&a5obliH*w($UOT`_gj;DVt1;T1^fTk8)P)>LYw2WW`{>$kWf>TM;sDhTm*Zfolu~O>4rSg1^ zwyYj-Nj~mAiWwrlB6Lmeh!Jyb$;JR|Z3E_aJIe;w7K+vU3CEQWUK0I>#=@ zkkJQ2WfxfT?sZ#s8DvB9wzuntCoK=PS@{+6o$)CKdri#}>cmy(hwVcDJt+jD=z;$J z9+`?82-%;wTAK?luRH4} z#iIVr+E$sVMYV|4KBT@E8=(w9gm{EuHs}f_G>NGW%do|XQu~QVXqW=4SWBM`BI1w1 zopww^_ZIVNR*@*ZkJzGovr7$sf$1M%&ofrVjB*mnRjtXCmim>5J6ZpNwdP@!=3xC@&n^nciPHVCp#%CB(%G2O4{N1ufzH_6tcKHgNt+U23Vq_t z%2s}Kywut9=S}onC@i~2&mH6a@ZT0CCL={K7BPhCeN%2;N=v!D$CgjctA?uc5o+g6 zC284M8}*xPsVs=K{=y;KwH|>=azlpBgrZ0%Nc@dJ%G<%Ls|1Gqn9|XVAX^JBdQK;} zz}NuPM!bgvLbXIuS2J?4*X(l5J=q)&ZC%Ehl>9Sv${tO+b%j`q43t0NZ~|0C%kjOw zx+L27d@SK_x)D+1m1HahXbjUvalEeq3AbYyX;1(Sn(NpY>auJ6W~0SVzX)LqL<5PL ztT~6H=X2_1z*YBf11rDvzy=&X)u25|!P>5Uga7soRM^2_vw0D@B51ByHGwp7IVQW# zC0{7xej)}`?u&?xpe`@XtoaU0Cun>Dov5rhbd9vdl%#j7H&JBZ>oBY)6c+~b$=@Sq z5}F?9;aAE;IgE$xEFOY&d8FX9UwE&=-hLqV>L2y$kT$n&_qR!L<5!ea)T^pwX*{Ye zUyyOF6sFM9!P+nyF$oFz7k{*+jkc1MzYl9e;SRC_PBY`hO9?9DTj;f(%Irp)=n&aulA4wTl)=z9@jxO>4|jtl7F|*D zJ>}yI-`d$aUj5z`p4;R5t{9%j2-R0?yu9M_qOrH^xViyV@4)y^o;3QXTO07&4cPBs>T@xuXzytBG8UfYD`I#1!tcR;3kmX-8;>VTDCIuCbXy z>9`+}yxs#N&D$T|yA0G45hm_h_16eLIju=n#jHwX2zZR*?*D)*zxHZ#xTTIJ{NkVM zwNgb#Ni=*b>B>FnhsheWlY^71uk+*wtMv`+e9^896=STirrw)BIdv$y z`QgnFTsx&WW|r)~(P23~}Q>{LFJ^~Uw*9+Gr%l(TEs#r&wXvj z`N`~QB9J9siy8gt&%2ABJ@C0^L~CjVe=qQ0XttDETgwX6 zD|vCRxZf?2kwtOtNLdV9QQJnb(zgT#hc)b|y zT~E5-siYv_>FRN z34E^WY`+_Zgr8`o(Xt!!gZR|*P9`5yWoz-~7lp*M#V>wSY)htx0e4C!90&};y4A0z zym>-#4JPp>6x+7a5c4vugTbk*{ceX`6D#fDQosG`@|9;)f)Q!^(KwYhxPajy;qe9p zbN7Q0voNm5A=tP*UpFO`q-XSbks|zmh{g41trt^09dH@Y`1wof(sF;F6kNFB%Ad|_ zEK*M03o9M<6&T|f8u@k5%$4@K&gMZFFQ8@MJ}*Tdj2M6r5d6x}zGL!JHz((`=I?v0 zEF35>;-zo(`CKQp!bQlfwpw{r`3redBtiggOZn2L$rJY}w^R-T7b9ZVH*aNdgYrgR zbNsItV_eEck(DR9G}Fz=1`jZ~N?-Cf?`lLAHDOQTboFak7n+^|4F%Y3dCWIcE#U3K z6L;UP6L=h`$Zo~`0D+%*es?+UGacD*bps@q9c?urbSdsgXLWOGUmzO9^NAY-Av5Z> zI_2J&G=tWwEBy{b0F%4y5=&h|&B=%p z?-9uU!2hb$T&xmOwR1IB7`>J2;XfpYrjwNDk=noR9e>{ulv6y!1*d1yuR+O#3Q|u zG~GmnKebuI(FP{Jx*4^stdhE7bgk%$5r^77U>GF|zh%?9=IwDeg(M4{CleGmx0?re zD5+opUfBW2CcF$&kIA{^KmI|u;8UkWLj+>39oI5PC^zSZzh?hz7a#6j|GE1I7x53U+PYJ{Lm$kzRK*gaa9T*LZG#H6u8 zQDO6Ff@pEUd2V%$9Bec6Y6w_k7j&%tn2MVl;8|wHeE0_ z{6#3C7zF-6CoF>RVs(V(+%x7HpM3QEylcnC&L+5)Junq# zc`BKEHB{_DZ1}~e0#94}Up`0aktVS$mmTvu?d(JhEqhQV3 zz6>G2ipp+flu*mjwuiLxQz+uY;6Rp}p+yrBhqY86qhY3hYwOFWy&(#FOuL1+E}TFodMhaud#U@-~t+!Im*;xT>`S3!!TT5zoi3B z2oq0sc13}9DW`e(JMq{++2gpJA@sVO{J3X?!|iwjTl^M|4>Pz?u?3b}L^u~z=Lm1O zb7@Spkxd@ijAqWM z08ApX95W6W!OnxTE^|PFuRv1C)ZBU?_-DxPXVghXzm=HndZ_Us=`4Or4GZxnv$aU=rX*&@N)bT+s*y39kF;l2Xcshf z$>%=GyxYTAh@oWGefco@157&q?o5)|k_WmR?Bh5Y7uf5IqV-;xNZHVp*YS41Y{FY? z7b$PhvICMg%2Qf}cm^3~blEjY8+sWHqf2aSSv}%$EBtk+V!R_|0vpR`(Ib@`T_u1qEDZ2VJmt! zzTW^=tM10c^)#`!0}{Ix!HkGfBTIeS^qg7Jn~COG{b;E+1);6dE5^n0brC$HHacL~ zIchN&`Q@SKCW&&US3Jx-axp3}TyN*TVt7CqF6k>h(8kit)td%VWNcl5mDccV5{ZPY z^!*S594mT}H)j)3QE(JMPl7@*xEhrgpU{6+we(UAI>)vVeT28t=>NZ!6!0L{Cx?gB*{x&80m%G<3JS>cmAW=l z6TaVNJYev*cG((Exw7Z7Z6-6{^Mc(wb`1PyFCl!BVM^L1mRnXhV_Sw6+Ecb2uEPRqrcdlV=-L&|5w{AvLSb@fZnSj9NGn*Y>`~TWkTuCf9Q)&N)uZS?_ ztZDv3bBida@-Ll4E#U+8zbKkWy^+EpK+|`!Si7 zGU|7CamkSpxHO`=lBuK)$A(iOOIdbaORw`8?n3MfA>3$my)}*#$_2rz3kev$5l=v|+cX zsHuNDBcEQ^z<9O@K*vnHVP2RyTm>v0*tY73nAiIL zcp3(T#Vase>z-IF(j!|9uM&z3sXPXq5|4yDfu;n*0?!a%-eeRNQ$zK5(9-&eR)!O_ zfe_f%7(xxCg~eNWurUDdT)WlzIRAjA$f(;N^42tUN|hTE>D?aI@@YhuyfTe}6Xbpn z=rsaSY;E&C95rQLA`8>)yGXOx7X`6s|AGu7bQBMO+P}f&f2xl{NZ@IrP>k7u^4|dQ zUtNI${QKJv|HY6n`I(9MLS~yO&!#K=kA|e{&v2Ljjo}DBIJ`X2|GvFM03E0>2wq9j zSf6%BAfCF7O(B-ab?uY(q3Mj1ri6q9=$h5{?G5|>&i#KJa{nb_l>NHEk@-M?(Hx6Q zOHxS%Y_PmJx9;sj8vmg@C|NbxfQf4nZPA-3A13tt^DVcXYUtvfhOE zm`wcJKab7$=j0%JC~X7*OULvcRlw zzrIJ&@_Bf8AWS1b{Q4!a8Gy`dcX*Luo4ypDr6nt|oza*hSJ1Pxu9MzsE7YRlbB*5D z`FuPl0}(R%Z$69`xGrnJ_Qg5pi*J|)Utr8V?t3NdybkXFB{%lP|L^67V@7RF+!ieR z`@N>=XevSIx()%-{TnL9;JRp6zdRigpvUSB%Qo1=Cq9OcC7P?gn3g;6p4U6FUYe8D z2OL1n8|u>xsh1JMyL>Wyc`t=%g7gVD@p%=w;N?{@=%m?(7rWXSz z%+F4l4yn5$A{j46>QJOOAaMa3je3jcp(1|p&`l| z8h$|bBb)Gu0^^%iklNWm)|e#A{=|mnH6ou@4bzM_imo^0t3uG1a7R2T$&7%DW8Hv< zvc}8BRQ7$Hfl1`;JONSCj<`n`!X9(wjgtQ+H1;U;_x?wpVI40i+lEZ>`ARa6wz&zl zb>2;DI|(tlOBA(u2@A9{uvbu!F7DzTQ|gMuv0r%ZCt|@~sYPxsp(@wg+uGqFUJ}-? z=yI>0C3{8HhEc8Gd@Q^FlKW+dM~tRla>>1&#}Iv|(J0>gqbY`0XwLH{A>uMx?pDZs zr?E}T<_<$g`tc)KL*rG$8~>Y=Z(P)r_O=y z0ExkV^TY^SZ|rx?8$omjN_JM?=byC%1*T^E5-DNwhABtODv}g0$)>uTk5lvd5h&im zGgD>C`WNe##kW?!3&OhVewZp1u|tmFQZiLT9InYwZBen+!aavuo-Vf%wckNvNFcqd z%(GP6$>mJ$+SCj_${l+g$Cg5T_15G&<;@h9+Rq2>2TXE*&4j=8|C5=pEft$;5EQ*w z53yPwu-(3%6qT`W7}|0l+>(qq3^TJOUdCGqPnER;;9gUYS}Ef3nx_`B^bKwO=xl4t zxV&EvhQd3O1N~`|T@SU=yW6&;uc?CwMGif{cCl&|IfBQ&|3&de&|0rOZ9*Yd_UWap zS!B3iv;ODs;3dN%39xck9o|i)6*o`%UI$s>z&g(X9{BppCu3WO>7Ct1XBbyodinPk z43ne!+nAAdwawyzHHXZ8`sn`9n2W&)k$3-v_tw$E$cQItV*tnxq5$1AFZ3k$OxOS} z2(G5jSACdq)-(bGShsR@Z9f%AF%(~m4yu2%g&hPV@=Bu$a+D63JsRl3{gA7G0$p}q zl-qiKJ7iEkl-D`Qp`jPu)pjU0Q&fJ#4FMN>k#!or&*jlz;k?DCKE^KjN(huISZ8cO z=uPx^(9RNMJRSgP4>}KJQmGl?Go9>J{w1+INvpD>NV9R?suh%^2Y$)1^k!2j#!9II z=pd{f4(LhFCFG2$wck9nB{oKl6k=vl>H zXqc3r#v4V8RdrG?hRbr=)vB;S{^x0>f>H@5J02E;*QzaFl#WOIQFxK#7i%X+$ejz*GM z)jsla^bZ)M0i4;0e{>P=Z+QC4Z_RXj1i_!HU2CVItteD(?`QZ3*^&N0MGda`PP<;b zdOB9-?twrx#vP|J``$lDE@r&_9!qPpx{&KHUd$<5;3R3{rgw%YDEJ@AH~kG>V#P|F zIWi|8d&{O-KY>q2LM(g zs$=}F68Xe5?I?FqG?tED1hG<2lauSbIRiCG_&7dn$Ch-3&NgP>OEA6*)j*-HH{z~* z5lJ;9{S~XJ5wz@YoBX{f70eEFmg-7M89o&k*S3xvPjiPhRs+}EmUba*ZNRyV51#6) zFq4aBm>tMC2FgEnZ*=J{HYA>$ob^z@&*%LDPQlEy1Z!(R58(TVFzd4x;50kLs%om> z^Z5(U`YuG!i@A~V!7&AoJ5KfoKZ%=oibfE@iRa-GwA4}Op#B}wDNLv8_0Qx_;pqZC zeuNOx6SG;ZqG71kW2T>e7kMFkqiC(tfFU0)2Qa*YMTm67i+2sya3ZVxW%JpOoM~GJ z@@o=%CK!X1B>A`CZLhAO@g|C?wL9O_JX&+^{!;&}K4a>lZ(LJVthaJO^5*a)L9q-%d8&xK?Z++Igsi4quAf?(*NN zSmx8u?T7yp@I%|?TPoqPYAY^OmI0pvXH|KJ@t|fO@pN?_k3*4HTP3jFQBlje9Xiu2x3hFQG z4UR7tCo@g>W)%VSgJ;P&ac)zeIe#ZES9dD&QnKd}Qq#V{!3S&z z8ZPs=YF{L5D<-P{IpJfFb+HOIV1_n8zGS^Hd7ElpRz|v`rc|%N z=s44+6PT&1Z*sKFEE?K#PxLS4cbeVvQTqS@lYu$%8r1qCRB{?xXF>$mBn1%G~zTX;anoR zCnVM)3VLxx4bLlW@BPgdp-2e{ZQ8DG6BcEs=yG7V$}b@MOZ^o@s>FBrc8{ND$3DjS zPQA<5#)dLa$0R)^d!=PWFeHhBSP>NLwS-%@-{ zkyXGO)1b+CG@lkbjNuy|q4f`b>5|rG!wqI~!kou>mhziwxEr4Typ!E5MOSp4w3n&A zh=h__PE|@x2<`ohs%E2=YEs;c7+{&*4SsdHO~-hckN!ER&oI5eI&+@EQ%Cq(VG(%@ zN(G~dSIdlVQIF2!=11$LSx~At5?Ym_`9pC>+6gT^Svl7_DK~~$`j=xYr*Md3x|t5X z_71Gl9?`xR#zJ*1W@>72iedu1VM?uwM~0LPwlX7Pf`7b%%@KEj{fJW0+*pf9M!<^a z#N+M%G6z$&pY%Tg@)0Mg1!Ax@@yslI)oY??Mv<6FY~FHQ7W38o4spSYW~UyKQO1m| z7$wW*2TZpW$V2jRa=4_-AQ&x#;~XdKW-@y^?rEi zBfB3Ob&Pz2+k=`l5hI~ufng?hZINWQzvg< zX@0~E=eX7@THN8x4={1ewj2T8OQL_?sI)Lzr`#H#waXEIzuZv*acbNH*-F1Y*uO}+ z88^oMl%+4l;P)|%rk~4U!vY7}0A*T@wCHVhU5#Zu3|ov$(9j@Up~iunLjdCNbwfAn zSJ@TpS+)Bb-l?`f2z!nG-w}3Q9_#*Vg|suru~#-QBn)XQ%1feuf6>`!W(!2WHAd1q z`Wz`h+mVCLG69!;^hyoR@9g#I24zrNvn4RYmX(m=43x)BOQW&ET2aPg!G*lUuh?Vr zTo2~xwb|OysXn&?fJ};vXX*=uiy~Lc|4*1d4TSm9mL;ttpBxAko+}ep6rvOKtIo)+ z)0P4vkmS{N>%pqG-WMNPZ7dNVdI#vk9*swpZCzYCbIG6k&cMqt*{RJi^r^Wlc3`c4 zaT2qFgg&$*FG=7QpSDbjeh^?_?Z)8W5j;*A=-9A|#yX)(b;TY>*44QNPWeGN(Vu;7 zS5m%(?o$Dy?J(3rHW3LFKF`7Rm~Ghd5PVl}U%#qK0g&G-y@B z=WoP^Z#hJyHn(Pmg09OsGJiJW`8*}2m>@1s*Ly6i>mReMwq4%XO07Ejq znwlS*BuaE5PLqUeI3LVVpW2cx5 z`7Om%?BHo&<_r+538znQ8+G7@7>e;g+wO0Kn0=eJN7zkqOV&G!#9^(n+Yt|KrEt31 z7F%4ISueDsjy;H!^qJA{+G3~SPD=hq(!oD?Ib?;ekr5@0og|n2WlzPlEFT8GpXN*; zs5;d?>5VBlr1Hlyk7>Zl$&)Hf>M`32=as6E%B7TBSXE%4sO7R^gc(Wt@qnU>hXJ1~qFskFmNmB{lF z)EyA+^Y(m)`2`VBuY$wdGh}ADWGDDbXe0Z}n*`#WC!;3fWEoVw);$~oy!c9Bn?Q#j zBnh+HiLu)5j3aThiJz~#Hb)S0QW)^~g@XMTo>o$df=`b04yAyEFe zTjerfuRAT!h1uDz-d=D8ATe)xRd?je4oY0swOi~isDlDbL{K*_VQwUp3@jPE(_sUF z`Ie(E(leKYhX=5SBkhyyS_@9+V@!nWK^_CXlG|36oJ+4$6_P%K&F0Ydg6-gR0j5DR zJ{kSk`)#Z*zaRk{=K}2$KNVH`ya7%*U)huX%`XW(Ak7w3^+-~&Sv@`GXp<*$siA8` z#7*t~xWU`loEnS43wmZay~&JF%`44uf7gjLwqeFmSulHsD&bMyG-pTDFxP}GvC8<} zV0wC8m8{9pCJoWVSAlSv!fLv?y=}m=z5W%jUCABDqI*aBT$gLpYQHBfqf?eTmc|+5 z9{(83!0gEaXk*Z5f@gJb$iW)1HgdQzUD8^WI5uXji8~eN2LeHc_^PCYW^XpurE%fT zF{6H583=qjXJ`86{2>r3Gz~h zub&Q6wZ-mzj{`x3l26>O*}m7njrebboLQ=fLT8>A90@yW?;nx=$o<{j-Q=$-9S#Ve zE*x_Xf4c+f8}%|Pa23YgQGYRJ_B_>MU2Xt7@9MVS&F@l8W9R++^=pap$|4aV+I1P# z*7sN13dC7?-6{vQb)nQlpd>j31}XO)628n(b_#kn(=J2Uz1n?TUaWx1g7#Tqci8gx zzl_pvh}8C|>&~cu^h%2a6!J|$0WY!rg@OOQ?bF+hgHp#$ky>8-!}myIpP(sS!;Akt zI<7I|gYJH$7c)K}-sZCl^SxZ%L4B*13dldpP;4~=3>_ck#f<6Yvs!&6>?30D6q(vq zBgfv7cH`2R;BzWD*ll7n5L z-s$~j3+~-Q34uh&2g49y;lFN>uSJMit;H(B5MvR%ZqWDNKP_6i?vLW6t=05a!~UNl zp(8YB+De*29WQN`4Vo{YT*qzi?Phh>3|o;4$f{*3et=IsJep3*Tkkt!S6= z?V)pUbCWo((IzPq4;OcHZ;$<)X$kyKOw~V?2jw5qiY^q}o9y@xG>-2gq2V|R4F!cl zK=9?rERzAX1K7h9SWsjjN!R=H+eMel>gwd&QW&uN`*uJoZk_iVdo%%WaB_0;k$>RL z(0?LqS&~0VDLFlx`HS*`qpzXrfj~08bRMR)ys{!wi@I~&7dyhi5VcJSb;iy;S-(=vZAE9)o28MAf(CZ1_Z6B(Lqky(9Fx&C z0T>{^U@37b5_%e0PfbCvV<_Fie4?guZR{a;@#%aL(w zd#ma{AXO~ynmcNTN=(6IyJ-AI0Lx{;>{fK8A9bLyX6ED!*+{d?)x3)I7e!<&IoD|X z&838Bz6{KSGhG_4N-5udue9JMX&2+NH*6dr4&%n>D5>Re1-;g>k@u75HkdMc$`TYZ z|Kut`>U)m^E(shsTC!(c+%uo+A*#XHLLn7CB0q?2Cas{{(sGnvYYb_Zmz&nvRMmBg zbROsUT_YV0JRe0`Z(8#j38&LH_642t#PCNoH)y%Pz zn&_r$O9vR)%@*RWqOPdMmEV z8JxnxOr-xV$S&0*SwWfc=&hPFlW&bKUSQVhGDk7e+2H%zr$d!b!eI!H{F)Hu#xV=4 zDx>G2(G7=cf8L4emvW}ivUFAqX?`^dKIRDC?Ft^7DS{q&`1T>x32V>nTvy%XaCIrt9@fjC+XpB zs9P(`#idLRa+(G=n4+^2T(a_vt^FdHXPB4?$pNqfzMw=Vq}_RU@;iN%dIEFfDV$4o zP-9E{v+_7JIyUkjT_zH-+Mr4#%%7{MmM-)xB z7G6<-usNPQV2`BG7-I`M$W{v+ba^9C&zY^35{P6l#HW|2L6y`G8}AGS0_aF1QQUk9 zt1tE}zLRvHI39nK_4@u|!4H809I1_GDOw;jh4mn^2AxE$QP`VGN90=hg|0W_*{zex z+ssBLAj+7f_?uYs3y854oYa~ee~!Zily{EHr`?Lu;!P9byv>f-|e2`Mz%2g}M#Mt%>ioo$@` zu;J4=rjC2If(IzNW-=sfua%@hW`5aeqs!bb4y>#t$gMpghA823=R}_5EVSYhG{z1l zI}<6GbT^_(v64W?QTJY`=R!F^v`L-&M)f3p;rrSS_aL&NMSP#Yj&n`5eH$&Z?za}~ zGT@PQ#9NQk#f2aJz0wsj4kG@mzPoOSf4z!`6A9xo(z+eA?1ini4*s4#9_|1>YKp(p zEO}BuSozqU1(vike8<2unJr#)9X9QhMS`<3rL|~Ofs3~hzeK#$qVsGWQv2&pIhlCy z_#Y3dg$LY=qas={Z4L@Rlul4P81Tb(Ig6UsgHg1KKb+9A*y^)ON~BtFB^guMV=fPV zl#Ygc6oRw$PDg*qL{%Kb+?leAk#F6OHJ$#PDUy9AK3$X5FLb4r`Yrrf{L>hU8OoLy zt#lcTIR5`NTPNeQOu@fDr9NjmCsLz{1PGTpp^`b$o-iy>Ipbuv?u03-hT*! zI0#Dyai=q(Ri_N3qA_y6yAwu!A@~GU5fOrLXDSlJ9M^pkimNFDpM0XP*8z%iuDEw| zkcaXSeTA0Hti|0HZ0JeB|6UzTQzD3EGVlQNnM5u&n&#V=(ug630c1QRY~G=yAD!L^ zeM$>rVq(bxJ{@%j5}8l1NJ!#~jNX2_lb81A80`!ztu0^RjHXT#Qap;S-Iiia$8f_ zxYB>UBD!`d>;8C8?6}&UyF9GDuiz!+dLo8HJJOb<6Qobr6N&gVIcwbevm$>YIT}s7BkS0)cI5$oKvHH+c^n^Cn7shLi*5*Qd`%@ z4vn5Z_*ts7NFxYbmG3!CxY&X8>ZIno*+;yMEYjDJtbinR^%xnsAf8g9pXx{~gqkM{ ziE$Y)Qo}+f&2U9&7P04Xe%T@R1r5S&jSHk__Jr1Tt*!?z?h{HG`3d*r=4=`f0ZI}s z{DQ{z2r0m-XJwVb_Aa=unAZNq)8&mJi6^0WQ6vW;uv);f!>qlo(v|JFofAa`q;r0| zGJe>p_E*sYf%9Ax;v2(c`MwB`ZqpbMQjpm#MPLs!tJQgB7-H}NTc`AN=t>{cJdv$7 zLj0z!Yji;j19j0v&#YFvLw(Ujgn_@1E z`6itGLQWO!7~iD`)N({6=IM8_U_vJZ-xj`LRFE+^{uDF+RI~G4#=2r5OP##dMD$Uq zB;}VVmyBFKI!9Z1Z=TVfB!c6)z`y|Y<^x-vkjf<4E)LlK;Xi1;u0I#HqrMee_?*2 z&O~SA>apjkS0ya(Yx-w~>QPI9u`2n2;x6htIC@Z73ed}Th2`pjCS(9+dnFEPNAHG9 zHIXnK>@|#pp*|^J09J1Lb+#=1U^IK)g6mfk`d6(Ro?&Vyc^z(S;zf;424Jp0%lemG zgB%+e*V`i%a>#F!+4J8Y6%$Bijf&P#PNE)Y*Pk#xg0i=eettEX7dH031RZO6BMG{H znfCjv8TI1jlAyA)h%eCQV^8GiDQ<>LKZ{xz3QPwCCO1<76~PX*e_drpZV>7CIJRzwgo8gIRa+oPiIwU+R9Tn(k77;O+oFus zM{9050yINgmOl-T!CSC-JWRwFGQPtw?|YCswvYXe%57H^s+%X|lDY^+aSSBBZR~uLOT|H}6@h$uqU@Gz6X-e1{Niz$)cNi-8X5C`7FMl= zOcRr%x9T;ocV;dUhJd^4M6#!;G91#6poB(m0jjYvM&?CBh{jrF*mfekO7K;iODA7k z5NHG-)TthW0);c|wKUG><)Tf0`tq3#o40R6_0n*;9nshdwO!1S-Gii@gGc5p`|pI2 z;QmmW8c^{hxFf|dbgE6;=Xx5M=szNKYDKXAiOwT(xZR#*+?G<5ox_(XF{LK+b5n@1w9K2?Q`FTLjI&&j&=C{CiJXW234D4OMh6ri6Y>`M~o%#6qEdZct%8=rL3rV05ku zd0@2X47B9cUP_Yo8U5^%Rt=e1f@i*!p^w2yx00Dy_4V+>^untvw`KhG3K@dUZA_=bNZQq_(By&KXwp_C`(!DFvDd2eCRF)oZh| zh&=h|#fhlaNCPuwOgqn`vR}}~sAjIY-P7|>+l3@ELFBv$mpBP}jkU9Ch_L9BL;R9ZeO_ouH~c7DF>ut1H< zIzhb_#yr;GnVPnRxMG{;eNuf3k~f{^L0g?il^;7858EkMui7fGZEKTj#h3r&T_~SH z!;rrxg0k-Qpbbn0r*f`kQe5F>*Y0NL^2WLy3$$1x@w9oy2l6-6t>}kj$qkm*`cfo% zt9jf~D#DyMhakM8!eGft!+*JK+s1t#W*?oJO$<^sd!x!cL zQ9bF?o^B#J8!Q};#QUT07UbgbI^@uk7pc+iFV9)4BgMIufz8hR zkD=<=PGalL_?3Q222Ol;x#E^5v+N^{q5wnl!}Im+w;e>3?4}N@d2jcWHiIL5Bt?ya z^K@hnBiN#Tb3}H$QSmRfBd%+kw_@xGaBWwv9L_d0B};Q5&SAo!Fx}ZYJCC+XNRdR= z@#7@2=;vwOn%ZB?c688-mBJ~O_J+IhOt^iTQg8g`*5$cemSt|A5U(A^?i{_2dc#<9EL3aA&6c{a5iAw~J9*+Dv2D z+dHBcsXS z#{m3f4`OFb)6J<*%uQnuo`A0$EZ&masGr6)ns!ULE3lsG_^-gMw*5McMo>)xSGGrj>nWj;?aX{|=TI!TY@B}3wAAqd+ zBlDKdUvA7byM_PdWr7%k83uNdHc`eJNd`0nSK%xKxm!_%rIBFWR7A$O$qcZ=#*GuF zFq5OZSVUXsC0J003>ZRFu=U!Ixoc(&3K#vh;GOQuf&ctlwoM^vz}*lrTv?|#d=u;P z?VOHx#3^MzN)~sn5ueBQxtP%Sp)uV4u;USu{$Xxs+}R`&kt_C>g#I?g^uy-skTCIs z&h0KtkvuS_zEYu0J(9F^&;gF~>tmfNZBWz2*}<6Iom}gZnmLqT7sR!p#S!z$=VA1z z4>!z|YEbHcu13XjB~DOFxzwPuw(z8yR)lBn^Cbj(d>>M4{9 zUXBQ4_BMtNvD5Y@U8*;HTFI>^8#d8w#Z3y5pjvg*=?K31*+ydWfatVX|C!(*l>6+P zBOKCs|4j)VQ$*B|f+ijTsw`hudE--@-u%hexjSrxy4~La$y&6DrDRy1$oO1(^>o+Q z*L|bixndFN;d|KhGr%qqnBLDbSv-3arH1@pLYcOEk)HD=!9}Q?DtD;V`+p18ep~oG z?h$%bn|f}e2l&NTCv;uI!4H>q@wBB*$bS}v%(wYPfRDG&#LmtR1`%=2-63pUk65eZ zs1;4M=!ECYi{%o@8CjuVteM<&9^5XUuj~ba#<__EVvosM(_kcw;6^@`;2kn_7Z@cH z`}?v0bflqUdzC;2lWmw}nbRK-k4YXfY}i$&{KkxOcF8nlX$A510s{;wAtZo=#<7d1 z-6d6=3;SSfe>7pwu2z3X(t8}(`S-JOVRFn+<9xA&teytJNaOVZ}) zLYwz5BA0oz^o~<`{}*#-65DDKa>a?^Bf`=Q)&7b}vgB*; zQ~CJC*=>(&#T!|CI7a-3@m}hE^2HR585*pB7j?0!NJtlO3Mm2|6Df}8?IbAt1nDuY zd$F`@Jg)bvu87SiHV4X-BI?K&T6Iz4(6a)--2oJw4)p$hBV@GMp!s^2k_;yB0rCUx z5SYY~zJX3)Q6Hq!rvn4YAza}vfZ_SkI6}3D&6l<(oYk0oC9u=SNv=fgKaM9t{stup zP6o;#;dehFN&eTbzfSgNV?Q{k@&_E$J~~$F|88aiw#D5FlKkU5|NKiVRwzjj^AWV~ zBPGDw`p@Q%L|Tw!p#MDh&wD`eXAbZ~^Xr#Y8jh3(-qU|H4<**#In?ZlTLI*%(=Ii< zxiHkKeY8H*&y)jR)CgVjj|Qx6tc%{PIxF^UOYe(EQs!3p{a` zq~OM82qDJ(VM|MkKcSU0JEtXsyGd4(`!bM4Xa&y58ks#-r(GwbFPBS~H<=YJ39W&B4$i9v%$BKn!|$xa3vG1ygMBk~ z5Xou6DWyX!uUTOd(IVi4^C(9izNhG$LKb?5;$*8XnfvUUR&cM4gR4gmuS#i*2} z{<{}|o#g+!lSG+^W&ejxiUhWO=KHHZ|C|zkjUwFdQDhaPXQlb?QIrIcocsI1fAziL z2oaHjKQ617x1;Gz1Y?Jwg#~q$!TvNlzQ%TclnBswcGkR&Fu*63EKho|XqLU1<#~qu zHl^`e#$J)=IT?=RNnF1U?ULJS`UT(~@527`{s7=bq|U_B$0dRqblf)t>Cl0q&63aq8H zq@*hhm9hpfij!`nt&Npd?rY(rW z*yb=Fu+F<8L@@wu_sUEFla@Cg-W^=dnCH~POF6}Xk$K06Sao@k6-CI99pVwTtyzJ_ zGHwFrFXUun0+)-Nv1+xdLFH^_f4BrCzr#cpb)Vb@gk~3w%z5il`L6=ci{lxRzt|IO zqkoFG7bZ(47z_@e7%W=T#cmb`wVgyIw>Y?a-Aqbscx&rYpoYSpot_#W)RuaXtqOGye;Ei&miNY>fb=#bpt8^A#r+lQ;C8{I zQrW**lIt_B+^g^Nkv&}kx&Cl1DtrM;HNl{347f+G(C>k?VAeDMq+WA%Tib&wPD5IR zt}ZYN_L?S;n)RT-HGW)#;Vf(>SWX(R8|i|2YKn3&wL-u^5FcuY`%$j3>~L9!4vUEu zHS}c5y3R2~%7%(h_Mru4ARU%9-B21ftP8mKWr1?SL`2=!)THg?lC9k+`Sfq3o4KY; z0{WMhdR!U-Atyf*)n`Gn__p?i)i}86dyQT{dg}LA;1jwr#R6P@hZKOQEG>vo?P8O0 zUdLs6YU=CVor_n+JSi8~g3%@<1m73Q2cyJ}CU7>P{ckvoID^;(>uL!x2t0^qB2GE( zFrweF!3+fG6hM?^j-PgJkHm;7%Vu@g6FmeTQcan!^M?h?OJAK_*+>|<(OPgtYF_PC zvYRs>YvJY>lwu+!4WIX1C-!6oIlC&!`zzTWi9|2DJ7R*#*ewN^$^6&B{k4-qO0El! z&E=JTud{}9L_{BnD5YCAB{A|s7Xg5!QF^E!2)CvrPmr^~9om-M*(wrRCnWq=D=QIs z-q-47JHS?%<6P_y%TGBi|HuU(SHgOOD8|mrhX1pbi1R|3q$$UFLBl1jqNrrfJnx2{ zy_k{U;}b@GCc9iQKcq~4qw)A0RcycBKuXXCo1?buBiXabXhsR(B(K?3Ev1`n#t5}# z(V;*Ky0uv7#Y`>6iK7<>1uXq>>=`8P*J5#0FLm6J1%EL9r4S$^ukkD-yfL>FR40GN zV=GwBGdg8B_4T%Pm>WVY1N~?8(LB(76-cCQV8GZxcjG1Yb*zV&7zz;)a=f<|dmQTW zEr(X4+8Fo(LfCI9ydtWNa2RA9BGO_5@wGS;t11o}5(#jBi3U|7;C4$QR`NHju=Znz1a_4*8%Y9j`Qtz~x&abkcONR+lYVVBByB#02y z7ruJm__J`qu~{f3f~$0N?_|AjCN+moWT=J{%{tF*%gDA0{v%Z0-OwSNt~AQTowB31 z8p@!Zl?Zh}zM6Cj>IiYG=kxZjOkY6?XxdVXpuIL8nfe*~M8@`Zv&{j4;+KO6A=#I};nkb#bK5|xfn6*aBw!0O7Jkiuu} z3a*zU@Gp%J)UV*P*ZAH~)H*kMKYJIS_*uTaP?XlF@6-3hr)ZIoypw}+g8hCOG@$Xs z5Yu?^EvbZ0xHTe^r*1BwFhhp0$)=bpqVo`l_a?CpGL#B=%Q1H(|3C(zO})JQiP||5 z;$uhW7>k%ArFJ{_l|tQIkp=}KzkUB)d9xB)0X0n9M+ z8#{u1WqHn~&uCrxn+GPMvK=P(qMu=xIO4Vt#QI5wN49GNl?T zSY_leGs0P=Be(@j+{n|GO{!{vh@~OkhT?u>8;o&zr!9J%U3oDG%W-`{8wZ>z&S28? z7EBbB>}-Na)pNFlc|~lDSUq7T^>a?^9dMA%cW9K^&{KT3RWK>)Stf=N?`)%AYJK0 za{#$XtAzn%jAwrGFDimyQ_RFvVCBIAudGW27B?NPw;+okKwtm{snMvB1BTYuDNRPx2*Z(I&UnBn3sO5G$k}qk0 z6gsPY2XYLtllLdfac9HAY;^Tt@zi&d9|R7I?4gLTg03+LzsRWH&$vv z5K05O92rRjz9S9bE>U?OY5NX;tBw=GvvlMj{bmJP_{c5IYKO3HxMWa!twvdIoKU=B;2%4>PCa$76xD|amfkT#a@cu*gOnN9p;>_%QO3x%o8=U z7k&}$^T_t~wI8-E9HogU??I&PZHJEOokbh{{CP9K${m`7v0dpSQNCEPs-uf<;>8x9 zh=zs0gkM=93ghk+OXX1E&I~RzTOv}!8&TT)p}o~9VbF!%+na5n4R}@0VwtD;I}CbW zF(c68K_o!Qfs8f?1%2H`bs6LJxEym%q;L?osaayB` zHZ)&e_|&&b^#}{dlZZhs7zvw*Mu0&VlG*v2lt=Glp7W3mav}LCnph>=YN?JU7+eBZ zLcGy5p?bdK%g-~Ay1We^Suk5n6MnqNKA^(a>p-|1luOPaby6VpA9M1Cb&ll(t_w@8 zr$?}$j6~$0OPHNnN#m;@@*scf=__XT?juynZpEz?HE>DD?%fM=-9VZ&r)V#Qw5(x0 zQTMt4U~j#hrxz9Kn28G5oA1YO8DOS_jjZUlxwJtq@A(oxk?GucukrGDXCyxH_u9j| zU+C^Pg~&p}yQU;E*~#C#URu zfu9(cLQH7atVZDCy}k*`Ag>Izhv1G*FqLK+>tnFceoDncJ{q_1V%&dZa=hAm>=Uu+Aqw)`T$<{WBMB3V6Xb&@U+K^J1@pr5+zL#zyGjpc02h2A)8-uqy= zFXHfP%7^>v9)8z1($s9hXLbeN1{&z6mCn4DLn>(LUxQxtp+$nQO7mCD2+EIDFqx%0 z5j2GiXT529w+$yj`n0*153s&{^jnceb<}8uhz^U@`6QPPE$IXI{Mn zl2dN`MBb#pZArijKI|A8aZDe45q?5TU`tC0jFt{uy5>2=_#~PHeWEqmZ=8mIun_Ys z2i7$z!6KKh5af2&gnlQSuf{WC`~BW1d+DtycqAqD;wKobIk&tyN2_dlw7ZCzh6Lo> z%?6#`LncQG}@03MWU%L)36GhuzQ(|4xb6<2+>yIHKs z)yeSwGOr9Nxh{pZ5(*s#k+eQ5H3W5}blV?4CN7KFMOyJJn_&VOxp)7FMe*`!#1+9-VQO$Z!1x9QiZ63UvmBzxP1 z*CNe+?B_4c@WtQigx49HYHCWT-h*g!r#quGTsvX(uD*beX-gVU=ob`shO?k7V8RfG zuP7JJ?7!)$K*E=BYeI;wL!N^i{BXQoO{h_N+5Gg5*ulE7y$x&7TCq4jj>w-y7ipQ$ zD+?ApBMolL@O$#8x;N(EmLoJEJ0@O7e4n{oQ2Na{xEf~Ab?hbABgYykPS$S}8br-e zk6H$-xWDf9!jVmVsgF*RO|XIfN#Lweo@m%^CIHN@h5dE@JQq6!gH7#R!dkR-vCwxy zT3aXE&)`%bm}AKxSD*n*zX9*i^?OlfJs{bIZI4ahZxp2uC+uRet#K4LSAjf_DRE0K z8k|rV@8T8e$X>;wks3R~%snsU3SA7>?mm=#pMEee05s19A30Y2B(Dc!tKJZpEGM&f zvC&xQ>v`IyH~AbvqY39&3G}qNLT}i%d5MX*c1*a4)au?iEgQhi$P|BtR9j zEmCvK(aZrH7=F(JczYi-3~i6V@Nhi(Qs)V8at?3&Es# zFI!11h>~n_4pg~raolpV!mxIu#$&XbW(ZLU$}UwY4u`dPL<)3W_r}cjx(Zw6#l~3! z6UlxYQPCu5%)lB<)a=N(12G+#Jds9_m(#F^k6stE39zr^2|Sm}4#;We6%oddsPD9WE>0g!aL1t6$KpeaUq;A`z<@cr| zig9M2AcA6D;?$|BGlerApjD4bUlrZZLmZKIkp)X9au1S~jFYS<*doBgtSGp;v%E8x zR2kIYLxfFEl0onf1Vc3FR&zHLo3atYp_CDR98`?uijd^lm;BUzwa4&WK4Uac+xIZr zd^ApbU&r<5Jlw!KU(^j@ztQuB!WEX(l=TwFX1ex9vJxKtmZl%fPP?xR-l3U_9Nu2q z0yX;3fwYjQX@+!mTuXfnmA0&{7<)}yTfk~cJ$ndp$P=>R=B=@XdwLE6_)HGSZ}&5O zA_wI_uE9F1IkX+od7$?sNDUi4Gz2j%75c19;=JqeX>w?;q?9u6y&gH$4GmdnTJB*I zTAjVKsF2Dje5QVLLISYm-5NTHYo(ZRg`*DM>38mGW|358ZdlAG>6>GsLI@i!q5Dut>_SSkNJV8JhAQRFqIVdl7{ zsQLr)s4>W|Pk;>3GgjP{yyglH3b{BRUrvVsoTR6ZQ4(tk$dAr6;r`%9B!#h>)z_3# z(u3`oeB39~&f#X*Ssq8!%*%%KGspAQu))h|ne_Exy`6;v!8ePj$jKQ|Pnh|eXNv(E zS8>qCNIO-M?ij8K9j4$`x zZ;rijxjo>p?tQ;F>hbFN_&NJ4RK&6m7@?k=4HI7B|DNPYJu?dLZG3N#o_Sdjfht^T zJjQ+Df`=?e$J+S%EHdTQ9s2D;mIt$Ibe1UB0#7)_zKpiGk6*W+jX zvhg;OdJVC>GAjXjE}3%C53;UP$OH+t2n;OLU~0belX+oW^eM{-EdASjOGtVY)X~FC>XPTdheNnLSaruv9+Tf>@P;onJvxh z>k>Yas5!@VvdKO>auv~%1w+8lBz}^VKbg7*d205#%{-o@Qcv2=9fet@w)Eq7h%_q7 zBk4r(PX__vgk&)qjhY)t(`VnVezI3B(|?VgPAT;`O}h4yx|_SX){N;$u#q6bEtu+sN;ZHueY)Nd17tK^zc{M>1pZxt&X~An8as2AS z!p>_01UO9>i8&%7BJ!hFa<%OkCUM~cY1x6R#ZvVsVuJG0^XHsGACBb%!MDsB*8*Pa zj~cZ-@WfOh4$CMy@+T=g!sRD!^V(Vy6~7s&49VB^sW_Rx2x+fAVWk=FlMx-54NQlW zd&wqNNoUUHS3BJhZoD(8Cnvcg$&*Rf;^QA_7swCJV(ul2IJ7CHkNDx$w8JJ;Q=C&h zyuidmMY5@Rx`l$Yauw7a-GPZNv#{3m1{sRC$mp%k zv{^JVQ(Z6ja!p4rUgX5g&mAj%Ug}}&g^4a78r8@$r|NSLXg= z`ONOA8YYKvL_+7$;Z2|G^z~3a0bqRE%qLj*!`01>y&Wvp5+TFa+@hf<+P(}R2)l95`Gr9b5I>-bo(cp z@iFv6oJymGp1!PA^U-SACeaOmgyGKp6lpv7AF$9}H-7~gs}aS&3R)Jrukg^(w7Ww~ zbAAAH>f#*Nz7*{lqAK?v1x8eywtvC$eZ*lD) zCy=G0!Go4v^oUn?h~ICU&j@<@u*nyy{~OdBM&96K`~QJgeavB2nPJKQCu#Z@3cD@; z{JdrSx3#1MxR%s?0F-KsK9uvHh|k8%A1ung0<{L?oFP8XTYVAkH_n=uHZ5LORjU7a zKL1$1E}-&&?rhr8(Gg5wF2T}vM)#`!HzEJ+KicanT5PbGHvV-5>%lPHlgx1CxH^

    u^{dbw)-FVZUXunkcAm1r6&A$ zGZwJzm&bqNS|Blu#0KuR*#P0%0M&mR_&>=T=(h^6|F{hBXIF~QZ~6fUf7%;5_-$&L zno`#794n^%RMj7a8!|DW_!xvS(xTkC-HhdZQ9)3 z4Fa0LbXRyT=nV`SzBg`_S9f%W3`FNXu5kYr@<2mFn|wq`Rru!vAPFvx^c$241rf(@ zae?w)_tZm0V9`s?lWJoKaWR4jE07Eip+u0(XwW}E=o=}M%n+uWu^|@#0 zYSZEm|Hns+}hWktG~5PoPu@)>5+X@o`UcjaqdAU_q3DreZ28j&(D=1}|u zy6l%G{g?=~;sy>e`F-_4bQp~aO82-!IE}U0Y4kQ!w|yx(B3X~{OfhiqSw`RY)!A(s zYx2Bc@-6%I#7th)8@@2zq(;f^kQ`+f^QyL2g9BIQvzrAmqvy7%tu6tf_YJaJHb(L< zaN`o7RjIG%%#9<|%wJRU6Hu1&*HS&tB3b^PSY0J@5km+JN)r$-WK=n)G zmlQea_W>bc$j9TxO){*ZFR8Z`pcoG;ya^(qegwf=?LaQQ`K;P#+#`%pg_gEpGxSsP z32zxSU?VCh;YO59;DWrdA|{6tnH^tiBC1n5AtP|Cyh^@hd($QBg;BKE_5@MO9Ovl0 z0lVIohI&vvbDp?*&zraOdGD)-FA<2&DM{fDU1QLr*7a7yVkL-xpzfC1gZ!7J@*5&# zEET9hl?`zthid{1^?2Td-gN$<7@75CNrz1_nI% zz6J!~WB3T>FLIN;)JU)EfTra*N=9MA@4$_kr~CtuZXhAtmN`Te;L}{HuoC@#ljFn)D?nXx&d_(3 z`9sOlS~MJCq4~~6&O7C+PRe8cQ<0+dfC&~$a;VCk z_GGY1z1FO(r+XNIdLd6N$gcsGJ-K?96!*4J;p+hqKfiw`rp$VqKjlPiKgw|4u|+*P zxnT(|BGts)fzX%U!4MU#I$;yz?!&VI77Q=t_P(T=Xi7P)uz-_8U%)Bc8-P#0!(%Qs z0}XjrL%*wF?b~le(?TEJGt3z1K5E_VelVO&l^$wE-iCKUzy=ILdRNn3F?bfjHxCYq)FCNO*iwpY;S-kYiNThSb)-Sg- z7>xQS_JQGeft0=Ob6xk(Zx=gQdS{PCQ;s`xahBPXbQYEvWZg@ihe|S@EK!Wg=8Q$jO_Co z90@F3+J%AKKk@Q@Gzny_JVJgJkGn`zHy``q$W{(!_AXCM$rq{x*c&4h7^f9_ zs}jSi7L`7SXiJp7NjNBg+~xL}H*)m4TdG`qRx~$H>d5Sd_c5>Hb{g+eE1@2fI9d7C z9ZAI?pV;B=CS4x_Ik{U>Sz@blOny(kB9U@%J0-_8HNyiwfjK~RQaj1%Jcl0o)Kc2z zvOcQ=%bTmyf_?kg;Kap=@xEG6&=(inch2>>AG6>%UVf;DS-Xr1t?7r6HJEfkbf-5U zi1=6-+KFxA*0MG{Ci6vcf@7H{EaGE&5{b_M!=xE&r~QboZjp0t2HUxyC?CG`&LK@g zi$KH!+wRCPPcllDXQOzSM@>Wln+`xoiF>bO1;b|NpmLhCF;*J5i!cOVso}EZ9 zl<)vdIb!mG+^mQw5b?Fy2KT?)3-G;*j(d4vOkDGMbRW210e5lYW?2HShYI3L!-8Nr z7-jiWlE~O1D&dh)X1G!0sZ!!F>zYoD%iTujcJATPD}gxmGM16I?0w=#;*n6JOj9K# zwdMQ<4+=E=RwuTqH*D~0$BWAIdRAB2)^w$1?CKbW(C>l;wc)|>pDbDWe2oFMwT&J9 zDam-$Z#Ko%Jt_E7hhZa3b6M?%74+)e!y8?av!DA@d&;Y;Spbv{`U%aE0bSiJJkf7D z^srYM>FHKpn?ab7=N->g4!}}>{nedsOMq|I_v7y`a_<cUCWtBNrlBG;o@X_o^b;eUbs=dZu|I-RR=Tt z+o%e>MqV$M15q)&SD{p$l{!s0+4`MpC;g2@!zq{p3+S=&^`H_T?Vi*eX34Q-EODd0 zlS}JBjh5u)wF=s>#}3iVq-f}yTDMJz0o3x^Sjw8oIcSVb9T#i!uD0vs7$_=FIo6jn ztwy#vViU|N^6GXBdCC&pwx_P5zJE3#JA#YM(^JWa)xA> zX$}ZnawV9ZgB3?{kCdb%;VYd(kq#Nt>|VqSKjLYT8=~~WIgTRhq8Zof^Pg@A@2>a- z$1a>KWqzktxhrcX9K|-w1eMmeN#jJ%#yqMiyX)Tg-42chU-WZYZQPYoRLFppPNNoU(9mSYCHg;Mp2Hjo!(9g`3(+dn!zShp{l;;EL7wNhoy~a+5)r}1Xx|d6-l7j zokPt^w_KGzuU5kJB<9(lsDHIV#|I{Yxa}3CGRAvkZ9#*BV^%ooycBlGZr}+DN?gEa zuM=Ym(f)waP3(H&okeCc`w^8Sk`)!F3byw%t7DZ(aC)!KnP%l?84HcrZ6N1k{@Ji* zf~4(siWENnkh=TH%WQQd&k!}NtCR;H46q!E12;8Rb*A1GJ}?FeO;Rfx)4TevMnG~= z-v{G3bQ>FZyR_C%2cDZiT-QpEEG~!D|gISkx*5 zDq3EO*px{4<23V#dY;FAd7jGIu-2{<)CAzp2xuJA`pGXp9j&%xHY$rA{d^6ty<{HK zVG(!AQh9o1uZ70xEU5ee1(i-aRfIM|GhVHvbW#08i$(&8iOp#JIwo}2tZi}G$^&X> zkT9Z5efE2KHy0;yXp+%4PwgotRxh4ZIc7%KRP;>Q@2UlO`K;^4BG6?Eu} ztugYH%6OAUWCuxOXR8$_rxA*?o%Na}Z{m|p`MKwR=iLnrIgn4?sx+|OsmEXEZ9+$P zr;JPqHC&L91>NEW5SxC5F33Qbb@ZDyV)cbHa(i2zYBzlU9>yVzU%qfH0*V9!1JfIy zoNmPr=b!9QxBNS&Md$PDIpm0Yk0)eF<_Dd*{s^87j*9)Ic6?t9nemE-D0d^x4pHh@ ztD}x9tGWD1K6%Ib1z{OyzrA}$$?UHZ?!FTrZgnj-EmLf`^m8Q4XI$AS0q!JRBq&d( z1AQpOwx#j1uzIQnB2Tx!!FHMk(MDW&Jn~?VitwYb)<=zEoDG=yd+7*1!NTL-2|S)J z(dwxIr^ScX9fAOr18lg_t&O%?CJ$DGIjqUq$?&u*-rmGQ(w#|bf94-ZL%MU}!6En- zn`N0Uw0Ll*!=4!GcEh0XVY%DFq~Wabip_iw<#o*f+61p~Ohi8#OYsS1B^TK%9$W;I zThKgC0$IB@S#RhPj?|;oG_k!p6fAm!Fn1qmP2RS&AAE^r{s_auZe4RyV(_75kPHzn zGo6)>D~~asJwZ=rEbQ^Ky(tkd(q;;%Q!0-Rc}{EuQJYMbXeTu4y0ME;YyH_mi$uae)^WmB`f1$lUz>?x9ZB=vl4xplA3>FpzlLt zgXh@JpW-r1ZvCTiSm0po&~WXK#`nrxPF7TYH^Yykq(Ojy{+E$U zXJ@Ak1%+{wV)exHHuDow@w{}buzz9hGiR#+T34KiH6)4Ds{fgk3kDnox?*0DxbOSt zS#J-SmVk|Jr4EM{ef`bERlnvNT#^?9Biz6kYY1Kq5}WM`R}E6H>jyo`iiJq=8V6wf zCStqhk?O=>4R*~vjI6I04y~Bd7^tjY5cZ_hv|jYy@I4r9=D4xI%^Y=}n2#0BSKIzB zfYW~7llM}mrRbUHg1uXb;&=-->jh`8UdlYpUKbv3G^Xf>L4A?T^P zB}=f~_P=kIG1PFOlkfLtLsrk0-NdBWlO_Q(^( zjl7&w%SarUadg=d`5l2K(3bV#p2aF#As&W=>j^C$_@dI=vuf`nJyd+Asn1ISy)^}B z8YGNTF)4nOqtD$5HI;48XgG?O+Bnb(xhdlkDLRKC3{5qPGDFwEnnD@;&)=`c&(CDY zaAGfJtXR68ypO$#`3*9HvG@mK#A#1<&4xCXd8D@6!HOHkX}k)%3W^RhGQV*AEE*j0 zW^MogT#V8=5JcBUge0RxHz>peVFcyTt$DONj|6diU{PwjHQ8tj{iOz<3<>0+w?sKbqqz6c@{-(ukHW z`p_wI=UE#Gr59NQJWSz-ShS&+EGwkf1|-1mX3laqAoIY4pfPmCO5%MHaa`M~!e0Aq zce?3m{@ZK{>a4skk0&95&pPFyiZ|5VNIx^(%LgSe4Yg8Oy=;Mzk3IX5ku>RHMGMa# zU$^~STh!6pBe3mTP;1g3)SNf!K>kgwg;feS*7g{xc+YXa_i_$6d9(WmB#f_r+0osU z0K;u6#q#KwQ&+@L4I!}q4bJfz_F;#UB}l1xq5&FT>@8crTG_uaSmOT6ak>ivx|DOk z9J^-vV5Nqyy(FuW(G9G$2h2Azt=JqJ&Cdwiw}jqSprzJ$)I#F&57+6?8PIhK;rQ>a z)3sDp_66d1mnk9IpM!-$vC(H9WW?wo%ZVJnl%B`*WY0losOx}*-?Iyz^d%ze^?7GY z<~XTjzsEO7|H7F>e*K@h`G`f@?pYWkP}qvv0P=AFrx(r`b(J$=Xu3KUnM{?M`C5lm z{01k@Nqw1qksW`D##{{_wQ8@&NmCH%OBr?!#Ys+&*$FatLxoN~hL?f_b@=NTMcSOtVdpMXf+=;0QiMgW3olhv6^%84HF)d@L-t))6 zqyys=pBM!EAy8N^c-IjDXFZksX7;Cf<- zqXv8PL!r`aS&C3AEPdo;ln&5J&3bZUMtYw`&D(1s`lzdo#4cbTd|Z&c8+tfXmG!X+LW=Y~3jF4V~GcuW66HWMbuF9~7klfE<`uT@o(UG<5wW`(Mny z;BU-+Mghp|iS)LK7`Sn78O3{6>mjRm$WiBr2lW&XfXqI&phw8X3Qe7*f z$&Asn;E^b8w#1iN_CVsAmWc^TB8H$3SkbBP_gf*RxR~;H33lR)t5w0a6B}Scv^=`J z{QN%UtnGoAZ6MaFPrrS-zxu`h5gDWD6@tGtZOM>JTH*BP+mmqxyrzFnH$6#(Vn4fc z%Y-LHU;szdG)p|U8+|1TyTCnCMSkPy6VPWX+>KE{$roXWS`FyTnpVy}7Z9mrf*=O* z>_eVP?@>1Ah6VbNjco&dxvNR;J-e8@``MCCmHV#;ltNT69eLp#XQunL@@6y_o!#DtyX?^C7+b9gX z&uv!5*PAS5N&G|$1c0gCoXU|cy{;&tccg9?@dRoQC3?x2(jqWbj$?sCl$FjkKr zS1)t1a>O(p$$P))a%EE8J}qp4(Al}=Qj1CK$VN}k0^Rq0xn^Pj_kNk$3^}O;5hHhr z^*X~Wp5w_Kd~w$zxQTsD(M!8;4dlY<#I>#b=U#o}uOhXh%PGetEv55WuwD@AO&IBr~)E8ztYa1eC~ z_{^;=P@T5b2@T4M5r9f|=2J@TQ=`1o*S0AFl)PQQ()#$?cL<2?>|pkaM)tx{d(;|n zT)lJz&s=z2f;+GKrNz;h;pJz+-Ia6(Gp9!L{OOy~R7v`k)-qnYulTH;`{UUI3Dhbh z1DiU-T!e|^(m#%Z+_m>?9?M|NX8ypfub4L%PAoBb7yrbqrkwvLyQbFW@`$>!2|S3a z%-1t!`0Hf)9&+Q8h9j6L=T*xzJY#{hS!``HjHkae22%Jo=4>g^Ez_D=CcCx`jAt%J;p?c3=R8Q+2j1rBZsM(sFd=4jHgavBo#KpjCT(BbbAa^ z_ehZ4SlOSPVPtx`d-(*a+pfYj|L`Y6(BWOyab`VY!+;DNRs90UKXm}ppZMahZZ3%z2Od>n&w)dO)1&CUy19MK1J%aO zC;NOlYqzAsCaKMzvT_AiO~31uUW+~f#oUxmnA~*lKjdzovrxw4a?R0PQosmwuL=Gk zM!*+$H3*#iLNHI|3LadE7E<s4fGHX zI#d)4BL{ZjyRHyNix3D&#Ys&P<-iD7-yB(0TUZkXW%HX468;U~2IGRPiI67#%@X=g zGL41$+mtMeRzFhk-_2dXHpw}#zn$rCHrW5YtN`e@#s4=p{eR)NrPAnM8u*!pTbat< zZrN{eyQ!(#{$vU=qWp)kc_FHduzIpS^|!7m%MRi7t}g=f`rx=`Yx&FLoNnpgY_xw~ zmlVW51Xx;orFegD55lK{dUmCxWhd(QgMmq>X*e1oSO13qXBYEEwueZnjtu=qU$EUo?@8|~Jx9I%5E^xpMHJb;M`I3^7ShU{;z5ZtD zX8QWuW(-9Gmx?xk4D<N$8Kj0?mk>@_gM$3WEGecBVF9zV|L4%nB*gQowZ%d z%VzOn+qK_fP{^nF4Qo^xo~^XV2OU}t1dqwPd3gT#q=}s+x&c9KC|LXxY%Qx!##IeO z5@(Z!%#;hoKQ_#-AW1}*!Nxh{q8nDHw&}vNIC`#zLq>z&a4;gYQD zks}lL0o1PDI{dG7T)Q^nK%85M&%-O1QG?dWDJkX_rrYZuUN;4V*P&&ZT2cQj(Wf*z%7*x-JRqminFC+s zZmsF^PzqJW~c8Kpi1c0_JtvQJq`!6|?FJ>uFxHA{h5&+e0aTRT6fXKZ91itz$P3omF0SlgU;&`Q?N zLMsGMhwfYymnKwx-NS_c!B-u6g(J;5V3@x)B||pExMLDlZOxH1crhicf7d^}(#*^M zbU=E+PtOn!J#*>m>KYNUdTEU`4q98|bTmUfHMSE=TFgoJ%?16A zK}bQt`R2sktz;o(O9=sw#u$!MbHLq#dX%%uzKZV$Q3{I9yH2~}t6WM3+{$P5o{+$C z*3YiDW!DKebAE(G43{)sc7}wk=DN1u224DSk=kmJfRzERzzmFGZ)bJpDD#3LXq*}H zkTbrI#lHuIE=0XLrl!P1SD1@EoZ4A&)D{>3U~$u8<&&++bby)SgYiM!VOA7{*Bl`T z6F{&%^?QeEf|`-NSkGOJ*nf$589q@7FnBBcq+fYd_L7cdfM2owPuapoLm9%w393-`3x!A;N za*735sE6uur#`Pq6+Iml@E6G@tS$~LI?At-q??p1`FQ9IXW(b^GyorOE_(T<1c9g=In5VWew5y=%w?wR(Y(WI~8p4P09a7*;_}o@pXOQ1q!sqp|}=@ z;#xG6BE_N5;!xb7h2W4t1zOzQo#GC`D!98#ae@U8l7u(CuXWu&dERHe>s@R97{-{{ z=S=3D{n_8W)!Yn*mAzu---yJ-UWmDUM|nPfuwa0LOuEh^+|)KGp9^$rH42jn)o{t& zDDXTIc{4=hbNaQ2SHQ+4+%@iZ2^Ow#Fwa=SKS0(a$=? zrs3;DtOZp>KaAN!)Ch`3n~Dk3Z9}YJ_0|b`(|PVY%P$SG9ld@kc(QNVc-aa%?mNXK zFMUnPS#;j{9PsAAhl<2FiaEdJQRGFU!F)_uOe%lA_tLBAsSWS^xRlk?HtS7S!{Ajy zzpI&yDcYh`0fJ}VdsZT%A~}_nG}x_;Oo@>4KZ5kM|EnOqBJ#NFe@^2w0x0dT zSW}G%RV}Qn|5c>7JpPX&9Y+4e%^;-HqAOs^6J43awG-)8v!k4OZCGQ8oyXvhA3aV+ zPR?cv^U8`G7rZY;?O~Ll~gvLW~=oQ6gbV zEH7!n^yreRd_k807Svl>LAs;m?DjWF`mjKNZz*k7a5z`FJmS(+*FX;hMtO&E_&&5X zZJgegsb;>ucN$m1$GVjpHgGzgx`Gz)$lq%y`-dhyh~5%-$33zSXMWO1I^VrjG7w(G zruCw*?W9lBakl7udTQ!7F2-HZZSpwX*y8I)@y=m>n1TG>ff`$u#J9DQQUtca0S5Mo zybl5xf3mL=d+d`x${)-AXMzG3yjb31l;+b_q3XF&X3Wkl&O++tY0aaWng`v`)sdUd zN5MRoxEK_m!0IU54}_JvNpzV8~c457lzo(`h&}llb$&BCuKD3{>sBK@*$IZ%E3mO{R-}U-VAfh6 z{`{9n4abnAQ<*~GaprG}Ur_@?< zw0iOxosVyWz~t}^;7h)b@fY8^LP@7PHJ%2}yI-0-YX!r23V~>;XjcZMSrlV{h5+v3 z49`a*Y_j8}@IEcxu9Fb4f$&6vpHmo!UN0HaGuoOT^$r0$w+#kYl$M%PKU6FQ$}ZjB zTv869YwNictT)_Ae09M~j9PwUr2Or=i>vEP*L{|DEzJ1eY(fWLr(vEO4{OhIAY+H{ z2U%fQX6SVC-{^PW`i3-8`S|!*Zl4aRu z9vefgB20%n-liF9>~#0Cc~AR~ti1#GKeF~wqW?qIe%Qr^NUSCe8?QCOT}`@sE>9hk z*^-iX(zv``ssTMp!&%;%PbtQG++TIY((rTvaCWn8uagvEZh_U#g{Zo4V zw?G3Ke2(0!oBbi^B-FsZxaej~h>4x37{6>7H&?yD4sqUX#%TnX*E$ox^9lYfV^ll$g2wk8&?i$stW^2=X zE0E4+h$m{|In2DEbGjeuqP%|+eRm?{qB$LY?R7&S>7%gxa2haXT+!5d&eKUCLgHm{;Wqn?Dq-GJC{C)2xYhtPXhi9$rvc zYK6Uh!xb^izq}#+q8__9E%?9a|GQ<7*yy@zl_OfuE+hX>J$nmnQ^y}Yd-7ho?Dyrn z=L^QVUx-8oJ1eziwD>9&o%XR!n%`mAjb?Sm3E`_L!Y@UAm3!v{3l`VZ@ zaul9gv3HmodPgx|bZ#N{nPpNfLUFf~L8-o>20j~&PTv~x`O2hjsk`t zCRv5G0(I8TJeiYYlGF|GCmk+##xKzE4ku`d`^yiHhLtFJv310+z5fH~_bC$uQh<0q z(pOzO=J18d_m$Jro&x+@u!feez;@Dt)?&c+*-HpY#Ap$aH{N#ma;WTi)AwpT-`J_u zRQDq(ewtgyh}|Q5MXT4cBL(cgIo$N(d6V%XSsO3cT@Q}rd$VWo*W63io)UI!CZJVl z`IXl(SQH=7(SaPFm^!d_B`vybO-)TLOX(Oxhm|de%8iak)L6OLZF8QvcXE>SmB+pAiMNBH!m>4S_S*gM;9v<0tS*hx8K;qe{9!C;8uB$t#9Pp94h?rZmGm5DK z6%WS|fI)g)F-Dw^nAvUxGD6Uv&6X^YhQ zqb#*UIy-Pdz~GtR=`EF?8J~>k<_Sj&++n(v zM5R$tqSKx@B`+a<@`*Mn|A~X}oiR#(A|JXAL)k1DsX)r$@ejm=n2Oj{GQWflv5Hl5~nmw6s@}D)g#t`3QDp zBq-*D^d$v9F=Vucc^$V?`3AW7vUC8UEf+J^&()>|FWEKYuW8F$${v-xQW%3m(d+JmU^(t2Vd)_U#n6E&Fir=&*Fvef;3BfzvBYub1t{mCjzd!#* zC_8-ruuIL}004I#z9M^Hl82{h293#ARXX_PLSogP-VJO!DXofzN-Z zgq@mmJO^CNq?af+F$8SaP+t6Yx=a)|go!}@|X!fExe*l9GC4&9;*L4?O9RUr` z&!SiTRy)qf#@@K)R7gb_s+UjW->lKc+hdqN5_UJFgtXXg#x;Ifyc6aR$Mt&~1vlhd z4{Wsw-Q98AezZ{QiC2*(H7+Im4D?;G#|_p+Q-N8SbtcOMm-sXw@#f+E>+-;%>;?ja z#NeQ@;#oG;a5OLDPxA@&+}6#wMZbzKZsvJkWqQZ*+IRyHTsbZIqdS4lA}(=OVJxDZ z&H@_HpZa5-%_&8^Tl|h!&Q>Uzj@Wj8yRmSl*gPvj_+)Fnk~K}xg# z7yqN#;}_UhYgFMA4cgykLtHN|XGcVKzbfi|N6s64*Ak`kCLl=dh%nmeqyBtfWqZmT zthV}o{sTePIDICI-4D`)4~x%pWX)Ry-mgE{lk%gf;F{Z`@6{g$FSQ~XmQQ-S68nad zI5@X;;AA0_2=cPshSYp6|DX(rRze$#0*^g-(-${k9)*+EdwYhp%y_|2AGh1QCJSPF zZ=!m67g*k_Etlg(Ccyvp+cFF9&TegGb9fQq{tqHN`>p9IyD0$_A0WDuDe`Vxs4^9T zaPi3q&X)WIr@_ydi7H{0rJ|yjEe!8wo3Ig)`qpW$PnW&S(zbMFO{E7p=N0d4{MVX5YQ@bu z*S4EHzcj>`H#1${Vbe8Ffy%XL)4bO*9hBB1|mz$lpf0Tpo;>3 zN6oX$joa{OtkI5`CoyI1O4s{5GF`3%WD2b&1akH5 ze7q{}DY}LD`e}fiCW{E#(TO{OBN974;**0gg!QqEb~fmywCP!*KWMYI=}m=^?_!>L zCuqe++G)135H0(YdbgWymfedwnOeNTUKP_nYv-BDTtRF;Olx%zTpkkV-r=L#n4VT_ z);w5)QqM0tykgA4_jXm&(lAolcP)eQst%93o@vgW{vz%f+tl&aF5cx0{3?4^QPq|R zFhpM0NiVmWoF2Jud9mdN>EvxvH)Ub==GJR|V?1BYdBERawvH ziWM*3HGZ`Rn$wK8^D4@^&`sO%@PfBGcH`H)ChgpI#%sM6+t-Z&;OJ;w-rak5`aBC4 z)Qp7`V@Id-Y3qBIv5VB-o$vBH8*F z=q@MZE&583lzYXdi5Kn)(E}V78(pNQiLzIGcj!CnEt|YkBg^z2-hDt~bnG&{;3wl+ zkc*DUQa3-ft`a#ROWfswIISN7LmZ;86OL0KWqC~v7pNBlD5!ECpITXfpI3pP!(~?Q z6;~<7$u}6nWgQznapWTy+dw!D-d4eR$MM;Z;PeF$WjiIrlOE=c9p(VA&j5Y&zI@&g z9)H{KB?^!2p_36h6Zd|$uiw6$Rjm)!k38GJhn)1#ZX9sgZ1x*6tl;;GBZgKMdz6!p zo+_~@1~l%yUC#Htoh^qkAsRykMPRjJzKTNwi4+Cy; z?;C8{FIdz@1Fpjva?MYlAN!oW(?ch@Y_X(UUXA9c%?R`9Taf!F{@}shC%VaNurhL2P>S=htZJK#s(tSa{mOg9vkv^JYqtu{ zY+KaPYsnTk@!p!u&=>yZOsR}fOp*$K0PkCptWBJkr_Hg5_x(5EY-{)gNtTa)L4M+b zaqp}-SR;~FJPMJ3Y3{JDdRpS8vi+K0s5r5u0->iUREmyOXiJ{dN5sMUH`CaC>D^z} zqEsdw)c_3HDJk8lJiTyo%S7 z&8=L9_;#MLL_?DPqwV(zXK6Xm7(wWDVREvtApPx9M+5RSUPU*_bbhm2zYW46l^N;8 z6_LIHHva~_nW^D!rrc|Y25>a)s{{B}1_0G%Bs|wlKI%>#m3(PJX(ECQ>bW!A32o70 zD!zb3E594~33q``x5glIz3;J13N;651)YjaZ$yEGRqt8!4;i^h%Dxv%Z;IVcSRTho zyRw2!YEi5Dg1#a|n6EW*AgJU@N4~Yis@V+4$(D3t_MT37n6ix>P_hHh{sH!IO8@q#r3&oDK5(Ik>`I z>8wv)LHiVin6i&-B)4z z{!e8k#)Nczxb`hDilqgSoW6RvbAbv@N(GrS-z7%@@-s0d8H;AfX&^%;8VNcCcugYoH65W#(lg+VY{`{VK7=&n^ zI<=gZwY>cM#hJ9}ADDoyw^m@#=~CU$%`H_&K)}_zAzlxo)J3m@IYC>zd=aM^=XFFJ z!+Rp+fcZx!o$0%sYSyCCi4vuk_KE3a{!GnRs-!VDqAL}R= zlErk7w)vjLWxX8iYAY!CghN212Mv^cMe~QUm+Iszoug$new|Y90?xMUt!}**8k{KG z>m14d4AuS6k>w73F;A2qkw%dH_t|r3NYLGx#swe9CXFF+#$rdp*RmOR{P|g}>oR0z z{!785C(pPrd5s&-DWuZH-7YC)i?jT=>HQCC&XYS4pJ~MG0T5`gY^qbDyH8r&>fRe04fBVtNwD-?oFp*{!XxBMJ94Ve>|hi z{+GJrlowaUqExuM(1a*tPiItkRCydGU`o<AYz!CP5T$LVY(-X-s}5w@6~D*f^@j zG$JNXnr4bKna{8(J!I!u5bG)J>*oy*6SPrb*djZH;`VAfIGG?gV*!cFH1)eO8JfBQ}o<)M5fEVxTvXMMr zv*-)NVMkglX9vuI_SfQPyS3X_b92_46Y}U!2%ks%;R)&%7Qa-?wpf61w*h$fI|v^4 zOoEoxF4(%}yq_a`?1l(X&}f%wqYoXb3UC)7NJ&x7*WB(_i+&fL{Iksg=zL^c(+zI7 zGM=21#e%jmig-4X%%s2-^l7SLf=1rnx7CW=qOQNpl}^_=vWtd{<(Fx}>N~(}jS6^& z%Au9V-N*Bp0+fhl>U0I4u7fy#5I4v5d9b_v2n0NFAyG=_blK8NPCxcoHstjs=5E=v zu*3J5dDntK+c8(OdlE_Fbe-AJ3y6-ppjK!3PA$O{hiNio>0}?af@#S3oJVJ&AfnT6 z=!->tRA(9~eicxS%se z?EX|PI0z@L^W1;4(Bi>?%zla9+kP?KK>M6 z3#_fVtqz)L99cMJGq0{e? zH>cermuLoK!cOUDf-sy|x6yN-tViStf)9=<{o;L2ChZ2?B@x>qe!ER|_OKfXI)Tir zfQlf_%-#pEAuY-dOa*v8vrZc%C>UdnMowxpepsV%sFIfP^RI;Iir8unKCbj}gHd~%gvEw~ zvKwNwy$ig*Yk-lFHpIiDi!^76IzBwV_IFOt&3oLPfjj}J-;-X81ox7y>4e@yrK@2y zB$PI?Q>Qg`hK+8J1U9GIMPz*FG1II5&~q`3{M0l{re+oI$wj%7-V(;FrdPEmQo?!Fim%MO=owdmq$e0+xxM6?dKC?Rx6NG8C~eMVTo1T1ooc-lT933f1{ z-AEwosc(PahgWHf{uQi#@f+&&1Btp)b^gjX$==e)FFPiqoflv8tM}C+2c+K2(>uB= ziKkr-lgi@O2W6R*_s-GR_dUbeCiMGox-skSC5qu&>f~cB)hAfJZ*OE2<8Fg-*lZg6 zG?%6;ka}xnlzD5b1ley4UJGnI_vxtr4g<(ZO0?XXKP?Yn>(XR+S&TROm4G9E*t6dC zM4IN^NX`4+2M;-iz{9uTJ!Dn<=*iH-gmkI2whOiMIvMb|$Ur1Yi(myHyqovD=@nxo z{7mMy?GhP9JF-EU{0_#CLQncotNt=SX&+31(4&CQ%RQgVO5ETi^&SZM1w^;4kx+wF zBy>56f;zss`J0et{(H3|zakxvq_LY&|M-AV`0|c#y>&R9Uw(h9$YJ|#p+k4Q^A80Y z!?CYPJmxC1joVm)Uk@>E4wIMdmy0gyefBuhr1ON4Y?5mej_cO_I5f-Oq%_>bl9I~J zw4O3bW`;zhP~pXXbbQL7wqF|VfGqM9v2%WMF)H)qEzi7&<3lY;iNvVFFSZ1`3PeLk znuFqj&-e95ax=+r$A%}FSI2s3%5qgd+A5fXP8qrTMvDn(XT}i9J!1-}WY6Ad3F*9? z8p;WCC9mx{u6k6sn>}(}Ma0+IJFO;!!+`A?ILno3Z@JBC)DhJ*D1S)+Rrt7*#P`LC zlP^x$bTk`~ttow?0Lx;OIh(Ar)7tYN76lS?-drB;XJV6P^Ms(|44?TO)byg$w7WhO zJYe<<+{Ow}+K}9vEn|#aC!M6Mj7}h{K(s_%x-COIfv+#&CClUiguB<%HQmiq6G7&;m!RIo z!oF7ivg&HiMy9F+tHf39H1n7Fz9G;2(H1=Io|2Jet9#OHPxo#u{U)~ zll6+E;?BKEiy(EX=!|WpNxFE;q)&@yFl_lQ8HH2@^Q`{v@|K?s$13zHP z^uznRv8N@k-xx!VMsC|cmBa8`P05eF6Vo(mI0PW%y+fH}PR{{H`HBT(jO%*T)}U!m z1CyxpP<#|Bv*fjxScA)A@J)2Ahi~yK7B@dCkxQ(4DM(gncI@+cnWJqrbHXuR#CiD7 zi>gWMN}Dx)w_MHnijo&q#`aI#lIFu#ReY4HAS{WupiQ0GRnV=Ab1Vy9=C3!so))Yp zx4!1rH~UrX-7(~E#9BSskZIyS3XEH8`NKoh4`1LZwW$lq@R{6kdu$<**`0;1E=I4? zU4KEtr`7C-eA`Hbuj&@IOsYC&=ofScw`*wM=DE~IOo>{*-#plwxl?|TL^4bTS$$bumD%JW*1Qhe%Zb&0|rYuT=38= zZ3ywjle=_UDx4)r)S$LDH)EF0vOU+x1DKtk1X^ZD+xy^*V`XZs33o@f`8P+&G?HYF z;wfv82bNEG4GgI7y?af0v;_9COjC{q#3*CgNk9JxvC)0A$ROg?@53-SSTFdQOq|yr znM8Q7HEO-%>^Onoxq-Tv=&z)6O}}nj6Z4XC=RFtn4!*sc`%&(YEeKnC&Sg+bFU@n7s9kMf(-x*w3@oxS z5j$?d!M*e^p6`d_yiwkepwtfcE6SvN{JxP4N{ZU%e%23%*lDwD>}GgsDmNZ(&Jy1I z9+pOh0^&5+1~+KlYa@&3+uZV3OpJe<^G0{8)zlovCtW$eW~t2YIJO6368wJ1JzDIj z7^fKF>(&+Ap6<}|y?-kAwhp1iYk#1z3$`1{557hacurcC%9@i3+Ar~d2DG`7R_2}U zY%lid)Y^;dkY_MX_a_Pt>Kc=q%9?JFYukkyt57&~?B}SZs^j%=em}dA&4aOw`8q42 z7cpwWY?tH8jD^WsmxhQUZ|S-W4Wb1Tw)=?Y7-mKZw>Ii3D?^7Oa}b=rtVXxHkdEtZ+8gwJ z?q-WO;LRpBZ^S)T*)rIg)qB!@fe;!<1wIj#prYYrg@xZo7p2VFBEGHZj6?Qik7)<-MB2RY{wn*1RN># zwsi*G6>H_W*%Iv3eg7IwYZGPu@G|*oG%)NA=J_^;Njv=ETa3r<8?I|^$)W15>S|)j zZd5Dnaga|uw3LmJ9-X_xfwp%3szc+*SKoRvMyT#VP( zHnklyYk!!$wX)m_b!)2k)}s(T+0-FCB{-J`t=%FbXRt(^M}Q``eQXJ$%^T^!@y(`g zAvV5m`43TxV~^VCzMWPNMrRDb5PkWTTTgInA4u+%tY~#Ldc(|MuOxiw z8l@jeynfPa>Lo|A<~~q%PS;P zsh4K>b>_mip+GtLBmZGzZ8F)iF>O*Z9PY%j^D3 z?Ijrr_JH{O%O0)Hr-%5k-r;BZ+iLOk?%XbwVvhf1%&WJS-xzGf-1_zPrB#I?#4dGr z9RBxC9gd*>@4Sr7MLsDsbJPTMhfUDdV$!s=0b;)_~GyV=^^ta^+D1^-m^##_RRV4swE#soQl3x zdE-<4u}pd;ci!i?6AFvRNfy)7zV#yZZhHnKzgJ55)X*Ja|Xv z4G^?TC$$O|{W5y98I`UjwRfrur4heqblorSN$^cGAx%}zgk>txHd0K?APNyV5lX;= zkAv}0qlSp(?-`8&*M)E&C&RhE$*axSId_Ve{Qi^OT9ZW@?TiJ9p-gS315eL?;4dXUW*VSsJdnv3 z4nmzQ-Vj`8W(PI;VY!H2nvO!-ZN`XTDGGR3uTo+MA!EZbiwO`P%L907ayOQYK<_ON z$=8Z zfSs>znLUaupC$Q$XR5q+KTKrWNipD-RO3J*gksAj_a{BJi1+z*TXbZRhI@dDSpU-b zz8h3Z77JarSrn4*vFZG(AdOxmp7Gtd=TE1V?n>J2sLLp;Q@MzrqQckg@Q!*;At%ko z>HBEcOR6`KHjF{Un|!snmMuD~xrGcij8*FIw9i)y^iUn!NIR$;?LGcVrmVd>K54J< z;|&Zv_w72`Ke@9}3YF5FYhyb|_V}#i_TeuFRM_kDg`x2T89B{m4%HPBW{P?M#B$gf zjMYyLB?5w{{Kr)DHbQQ%wmLf#B=`zX?__73IGMElA1V~PH+Tm@X$)t`y~n34WUeeQ zD%!YjBWQY7w{}h_3ouq`XSUpaRS*K#{Rwb14^%SiSn%R>0tkd;s*6Rqi}fNMk}5Ey z1_Ev=@oYa=k$@bQr6KH1fUVQv6nCtvE0qAOb1K)+PQ`&e!7R6*?0esd1XHMZ#T|Q8 zY4&b%+YQ<|#u5?tLU6B|NR5Vfl$$GCKQp8YC++X5*D1dwvvPQ}3Pie#fc^kvUVUrF zKL8mOnyGB+eZrGxO^HlC{Jd(E?AEoQVisG6FTMiHa@H@=nMRfZYCn@M0N`|K-J-|K!Di@BhDeaUMzL;)HJen+eF`o`3kO zv%1B$$p(bLCqWV4Df%fc$tv~pRJXvb3Pk_jX!aI#Wh>6xn^p@^lfQ&IC60JWBV{KF z&(b>V~|(!?N~R~wqkbCZzNAGIc^k8aTGXEgkhE|D}Bkq4ESa`^?j~t zqF=>dU&^MvoZ-BCfLbJH@_(@K;LCqt;q2K6F%cJ-pQO`4`&6d~N1klF{X@V~k^g9S zP2EV%92MVuPj8R=iMhM2cJ?i$?#Ox8`Jmx1`_hp3Uj9XT&@TTHIZXH0ir=`hv+bV(UdO6C&XlJH?3|K!Zu$$g6seen(!Fvn zG6l9AC>`3G9WuL^x*VJac%j$WzM99E;?7U$Yg7(>@htY^jHDfeOZ+DUCjT(Am9HYw`J?fbm<190&xO7BRsy?#Ap}D500~s^{tZhpp~Cn4-XJ z#w}@dR*As+FCY33A!B-i28g80^8Z3!axPEMb0(MhI4azKHMl&w!Pyi(-TT)wFZ`hr z3$<*5g#X&{=}$9#d4TaRBQ$(Q_reAnHA}jG?RbbDXD1MoVE&8OIpU%3({V7V>)F3{ zkdl@p3#>oDOA)a6Ng`&6Px-g!%Ml}MzC+zQogK$9&{D`z)cPN_^wu)r{jD3IajLd4 zy4zd3^nb)9GNQ2lcX#^pf6IA&cgLO#e&G3+E&doOrh)A}P9NsK_DwOP&16VRW*5Z6 z^v|}C<7NJHlHgzl#)2-o+(n00c z+4*-W)ANE)lHj{q;DA(Fe%F`1O@}XMFAp^h3DnZd8jVhrAi~9zo(A zSpyW&&DD1(&<0*t${pHiw-F9Bt4cgSUFh9CI3)}(bw&*Gp8rM}JIvfkv}QzT)BW9U z()S0{#|L!{T{xYxFcyrD`60Ihx#u`U`pL;!=O!ZOl~$am#&i3spPv zJwYLXyV^>Kp!oj8fES~8--Kn3r70a{qE?^_NqbTQU=b(c<<|j3NKgB2K2}1;mC*{Y z$}JJ&`g;k_83EzStk7r?SE$gDvv%j^D99Qt3Y&+kf1Dk^%PD%4`Mj&W(T%p}H zZ(r6gM7GpCv}?!i?rPe<6uun3`vLFEN+8_e+pn7UL!rVIq*xgSHNWw|`-3WC_1 z_EkoYf7Z-m!zP%&DJwq&DBG;utW{Tg`qE>+5}`k*kxZhQ*=h_^EBVx$h6w#UnD|bD z&p>}hCUFe*I5gbyuXo~I7xA;bFVqfw!2{ywr;^pTPxrhgMf}{>D-wP=#n4L!6Vy_= z4CV-q@)nnFfV+7Qliu>1?fb)89-d<^D|l=hpngX0R;hjMk(N%;l-|2XPEMaQ)CkB0 zx1E!kP7ASA5>{2_MT($$H=u=z;2d=DTKWj;B-@^&>7sjJ2ddQXU**3GqiyOQV3@mP zknv2v87cD5x{-33d=El0XhfayUhKs;J`(Rx5ML2XMTuOCRjmNpn&S7Dl)_n8D>LoV zrQx33ze&#Q+b_d94CwV&tM2OK9`RBPu(A^!6q!=u=Ow=x%^_)T6+HM=)6r{5NIsr- z0w|It>Qtizdt}aDs$GAkYl=@oSp)!=q?L|f{^pd51HxtgBORf#oIJ}EwC0ddSAURI zIm*YiX*@e=TRAY)R}cGqZ_-3Ox`E!KeTV3&r8D#43YinU7moNUMtiu)kHkV=IrGgP zIYUlnM<+vIU!pd+)p~UoIOe`%-rl>!IKZ02ttNWQSkf2Bv?+4+<)Io%?a(MnX_QAq z`V0&`5%#Udg})LEXCHTiArI_OFoU?`_Pa!TK6X2SJPs~G&?OFm55kn@Vux#r{mkt> zsvUbDYC2FIxF@-m-c&L=>^-L6 zi%8A7R$-T!i43H~FD%|crbI2D5F*#N7kA@Kb?t{UlRfUjq05D%W3ANryU^5+&`lVl z#?xZNrz78_-J@cZI;Hsh^RqiR#X?u0)Ip@Tc>B#h?Unk-a{cd%EQLGd(~A}x&dh+L zMPQ)uzMmX@bf2Hy#GD;yWZ?OYn;<`fui(}RnK{pNemE{biAcOT{-`i}JR7`}q$yeR zqypr4Z&^%qB73m*a@?GeMjZ>{k_+fW5;s&BtDB#g*VOQa`C1rPcg~f8Vc;GAB}k-C z3WbRWp9|=)VfD;x|?C=&_v@x4WA#q%r z9!7%w7&2F_pUTYMQQTx#5l)`kRdN^slKoaMpCRoZ!Y<6f&@7JCLRW8nL~0oo zALn0h-91cA%mxPxR`YqaSJeG%*OhoV6PCEwr+isyXU1)#F3~2E5ce3j0hU>Lr5RZ*xU_Hy6L`wr>_@RV6!i7W+yURB%RU#9Zi}x67MwKv6^g_ zzWf2z%Ky>JE$oJYp5#Qw{00eY)Q(|(|adcPlV$Y+rUH&>C4f&hN@u`+oAC0`#j*J?Ao4MSJ(Gpn0V!WHd z-aP6tw}g)*L6%s=HWB!v>fmX@N zeV}Vatsh)W0p|D%le2=B1r*D2-{#TqSN@GKc+26+edC|`cJv)af|(2(x~!eP1uXQN zxYz-$hsLFm9g8&|FK0KL_V*MR=-!>_5=|0~I<8+sPzPoZ-y0#L^BIowd|1>8kE;H%uhp(J73LC)dMPlj zvjCoH_kZ7ZDz*EIEqxcU(lVvpm`FJvGqUINwfJzEq=wFt5Vu{cAH=`?Y@VpuR3*Ik z?vr^IP2m1dIG;ni%liIdtOnlY{B4XOh2&q~EP4w?S?-Cvy6F<<6zU^24z^h=@b z`vjLI@?`S+dZ6p=kB_mHP)z&V9olv;5J-bkYj2Uay(%X?3yDk6kCM%{V_MkZO<|6A zbANGN`_I6k6md@iD8dvO(W1ujxU@uR<3i?5H?Ca@f~*UoUsm z>HyvT4#LU(r&oQLyQ}BdO}9{7j(*GN-8wCl2JoBnpw(`9SuOO$<}SA#2`1k1is=}* zOW6IS3w`D!)pLk@K@-RG`fk*Xa{NnpRI;N4eL=gwT8YK4kowg!I7|MD<-+kLyX29( zKVw)zm(*YO)q8x0h~%w&Nc_XENdjJ_;+kQvg^gZ()2I2a26ZI^)%)Wjq-T@+kIdzAXzTNW;P zagCCgN(HIC=pD`5IoeelzAVqx!8*#-m_>%5JawnweP`!OU!HP$%z}5JB%{O^zA>6^ zec=oqB)>1#6db|ins;S2}48&YiXU$e;kjFI$?s&^uIX!zIkro{DrT-FQyCXD+R#q2ym z)>u;yX%r*_Z7Ai~R;Y90X-+@uNjvaqxT32;Z>qmwr{|9C=PUE1)nVBXs{x%I-@C{B zMMdGcUKT`Si?mL?@v9)I#}Pq16s7$Go5 z{|USnW`BYVtlb$rLVEbEB@LGFH9d_7^Nqlp`wGlonL-YBJRIh-_Msiwyl@`4Dzb9orj2`jg^+%G z+-62}A;LrV&8^d}2_)O~x*wC~a_A`#dB{I8N))++_tJ>C#WEU4sA*-MpybMG{?O5d6#(xY%XPytpy(18CgoY((NB zZgdaxuSt$0OR!_7&!f8PcmEsmPf!j~&FblO{#KSiHI6i^ozTv%P(#^+GV5Iy8(Vl@ z6vJ1+0H8Aj3$Mu~KQ6?x)Z$}L!kTv&Yl#j@XCluMv?=!s-;v3>ydDfD(Hf<7U$)7- zy+##$M5u}LWxtM0CWr!{LBW-5DukdkxUr!#i2brTR`Y6Dn#RveSU+*AmVO;|cE(s@ z_7P`AlSJPzLG4#WM6E3UF)_MQ(_FH#iRl}q1)I%;wS~7!N1&sGI;}S{f16#(DU#Ut z0-*onTA~KbBrz5adOIAebv#Pa-#n!Pn<9%6x?|e9Y*meCpAnv|AG9qfs*-lH>k`$L z@_%0SiXg8LP{er>o^2iH^t(SHx;sf?gY-^3%ueI5q zarwUUju}2Xw*v9pzqvUu=;sKl8pI=+7q^o32CKMLZ^b4>s=2(G{3dob0O5vUdN2Z!1(X06`Ur=lqliNZNr_Q=n1*6x%SBv z@v<#Rg_aerAm%d7*g`IPgCTP^l)c+!rE9uG-?A&<{@-)aem2|tahahUwC1_LDm3wO z1h5EIGcHcT@h}-SJ$_0DJcBZi_`Ur{9Ct8{DwDnZ!4BF7``~BK{MJNL)gE@t zJSTMoUn%ypbAODJbS;GB083Xf}B_!wVvoz70{p zFigmRvQJ)0flLH1kXDu#Fq`pKYC7|I?6bZz`2GXFEPi;_f_2V5`|R`Duf5ON=Q%5< zm$j*}-EgHaT1JbQG0eSOsun~UTajH6n_SxPG3w0`)|N{WP^_eRM;|TuG^gyp&$(wC zo_}>OA;wgN6jOHOgXnW^!jRQdK^XFII(A>Z$w+e!4O6<2S4&_*GjngQ%kNZgQG0!? z8LFA>8dYB%W{>y4sqYGF?hnn2mn(-VOCki|S2zxR6}fS&OaZFJKa)cKTRvB`=XIh@sUebcospO$p-xx3dVhE5r0OukuC zxD_%kuxs@HX}mHh`a&(DpJpHBFjh#d-(2M2^zfduV}WJpITm`(L{IzvRp21eB`XEh zb!v8cR^=4``5aG$r671$z4S;r*T>i&R58=F_-XL|^Ngbl)~zW)f^t>Bs? zBke(icn2Sd(eeJIJC=6f*oTL=LR`;0xly~!;280fdCB@GXSJv-w;(vd=-6TAS#LI4 z4S`*>!Y3EOQb$I0%E()Ce{eEbF|Ku|Y=z8paXli7cUDu+4n1hn5p>*oGDx2j;Ev=S z$hjS6cEf`p)78f-Y5P1%4SukIdJz<}E>mcnlkTvUL13(+Mr!k5(|`wICEWgxjb$Ut z$W=MH>*C2Dj~g=@zGNVR1z&`B-Jl2U4ZMBSTe%mjIgl-7h1(xf_cO@N-;5J2AtNa{ zUb9UHk!_S1aQyXG3SBK${_&~O8n-!c*L(WanM>Y?+CdoNgYT9lt1a@TR=vEt=vZBd zMJmv{Ma>lV6?M2|{JQHW)}VPpfqBoHh)U=Tx{`{Zqp>UmWZIa&7ssE^5^)h;c0W1^ z0;JiOYCeZ6TROo5=y)@9ACF2~xD;F)<;%_=408^Jn#LAF;xXuk@l~SmKaL`VpgAYT zki1qn^G~fs_4w|h$KNGj6VYl8leJ13IVy-bCM}H(F0h>z|JFxhE&9UAGsYcvBWF#f z!o4VW;!V@BkycuVHx+d~f!=R3iEqM0 zX_vw5Wmr`^0WxO{3#pw{f2@FYmbwfJk>@KO)$S5A37FmmWPc-5ha4?2Z}Mr8VXw|e z0}kBAS_Nyk8`thig=hmsEv4SL$qJt1pbbCIid&vIDW5s;^Ll0tS85{nlrU)+d=^yI z$R-sXTq}l2CyJMOEjoyc`a|ZCS0Ho<)&d))NiP%g_b$}J{6B7d*;s6G{>~)9e8VJ;N=<{{|`~9;Lr{ONcYx)UoHw`W!|2}%P_+7x}q1# zi46nCUwtqAX-;6^1&sRbmn^4LDo~EMWBPDcAxvL__=(O3pvd$F5e`e(0NN+o&KlN} zgpb39!5SsD+#H%&t7D5yU_mOm^9vRn*B&lzud_kBkAfiiA2Wl!J-^D9>XxZ)t}>7@`P@men>|DtFTUMG=ZAq)i2G-#u!K@?&v@xAPP}=0 z4(!_b zPCRST`VZ_H&bg1*k`Qyo9fmBt?FUh;AI*{7HIIChkYinZ$2Ju$GP$zh zqpalz;kn&|YS$Lr1A47vWhAd@W=X;QJZ*^~1`;`NHt1xHu6^OW<)nUs^sJSq5%QUJ~>OGVG4ZE zo!P-iBOnW;={A^yIo+_m{hUsHOqn`jj>0A?Bn}~86cO|EuJ!6+_7%H*s~wAC3(+_= z0*G-cZU!T%GiUyw9gh2DznnejJW&iQ)HJ|fCV`QB&LmJtD;ANIe(D3W&~QZUGM|HR zJk*$4x)-KphQY;jMrxJ)J{gsiNoo6uvroq!=TGLvVGZ526+$Lz(<2{=j%iC(vdVv`Q%2rQ-?~?67qE1 zQZxatftVxtvZITSQKf3b--(D;=s05+4wizo>MT+5LRVRPPUjH&r*oBNACLYrWE{DH zSm0iVyx!T!;vs+Cw%Y!xKuGFdGUu1=PuNZ}_MWxt0ca50%z0ehHC>C-4zv-D4QyQ|~l8aD|!ofO0@$%|WI;igd)b-uNua1kWcJr$4k znlly|q(Qtrqn1_Iycaq+!AHz8F|&aM){P&O-{+#(Zop?P>jUfG&$jkHd-h@a97rzFjmr*H^}8}lPi{I3TQ|BNXbQe zs-y!PBP4jLn~JDyUzDOSClH+`ju4V?G23vKme%KwOlD~~SscAnNsV#WY!Ju4!{R_l zzX6ULBvKhm^0JAj*?db#4Nvxs{M%LLKI;3ZcDj$V<_Pp5sflqzpZ0!SH|`S~?o?Gc zFrrbx2{@o`5$K!`yc(9zS>r2QDj!_;my2Nkz0SO0p|xjJ1<=}}h(sU5jv*8v;n+J3 z667b&F`X+9#D$&I9$?1Er)EiO1`zKHt?V}y^jmwTl7vl>mU9$>cRWOV5(KwtOoTT` zGvx{X=~X}leIiTA1P;!23rZTZ_9VXj`Q&t(prNgnd)0$I?h0*6Rk^gnZZGe8MQ}Xf zP-;PEb+Z+6{YtLa?6cL_1k`ep-4{@t`R-S+1yEgbwW+_F4r=8ZIYuMUIHt#zYUp)aAYw zC29}?{6mdlHv<$PTl=iv@1nS;>gq!XlxsI931W{{ag>p^zlK!~QCMeQGv!|4haiFg z`XkOHN&(i@ui51~g0SgRUI);q-LIF(LqQVMxSuk1)H1~T5q_YfpbEB{Lkt+{pSH@_FAx(VgW^R>8GHCm7P_hA->Pb!%I{jGmee ztXfR)piskb6A$MiHH;u!32P$%Dc+nk+}{R7XGL58i8F!0n{BvbWQ?T*8+vlY0swY;uHNO`;2H>rt&oCA1|S^s>tUuGx&m%hV^+(n`m54fAPZE>LL6EtihgO92l#GE%;o zpG|nbPrvqaY~ki2E4_W@hGVD^Ap#+A9vtHj>Qt5Cu3iCr!-* zOu+k@0CJbz`q=%{a298}K}jA4{8W!jRMXO0R)AwR0DlG#&v&i(V+UOZt_D>&`Y7i< zOvTz3PbV#T5bhHe@T~SB3_Gemh4rJ;f3z&G6X$3-Pj+?Bllg}}leI#>@i|d$4oaZk zL1ts~KiryJj_aUHHr+Qj?$}Sv3&FO#0b4qye8VQ{fpzQ|1&B~TzAcJ9?gwp<>1M_+ zNX#RXOyi!5n|Iw0`i2zyX;c{ijF}vaZqfxn=8Jd%B&NvovTRd$c7b@^Z2j64K=4c4zts65?pTWVsXR8zJPU4^`^9I zeMZ<+f+KmV;~QT90Wx|Z4YH5K=Sf)OF!U6SGYFEl=pEz8_X->bNt+9l#EkpFjSjmE zaNHlIYJD(NGfh@qT9t{WNomvUHP76>T&q(RqFLtvkb&?`yY9u0R8C4TMm3v+NBQ=Y zD;4o)Lc#Gorv-wN_6bBc-Vs>u0M-WKI0pOfjYs2O#=g*#x3$v@MO8jxb%g{_F@6d2 zb9bKU5Zq3~alHTaUu6C(>XYYTNN{@Cug=Ao1!{@2$!>O~SS^FDVV9<)8|@>ehX`(> z`%?A-`~=*!-@RQ6qdbeh{8}E+BY(`OUZPF|fSYw&HMA2wQt~sOM-3j?d@E+>{T|*W z0>HbC;6_G6n~UNPM_^;VO>=fZr_;Pgg>|elb#iJ^c^LMI4mNqdb|HdIa&W`NjpB$F zZeKUvKg)Pb45;HOuXA1ty1Nq#W&ekqq#p#)RUi9iyhjre0MziGW_!(P)d`pqfKlOJ zHeSB#k+=c$J24~7U<}0}U)%R5+3SM~RPe>>0R7}ACM@*=k*T*pFq6Z1-47;cv|x#O8U~ZUBH}CLFkX;*4R~?k|cV(O{zm2xr%bu*0wmnRiuptliAa9(_$_ITu*B{2Yq@ zC6wV{|3_}`;1PjeNO|0P_XHsHJ(4$-+7J!Qs-d2KfBsi4by%J1sCiFj3?l$~FmfFr zPNSbbN4lD(hv|%ihJhFo`7F{0EdezqxaS+t@fbQGA)-mTShSQTD14gJ2}LVZs*+)iSUeM4$E zou%$1mIC&bzCHS@$-TtVFX=*>_exD2mS;!gj3W={!~?uYcI4QiRMoI+{?y@_KXO)P zdSA+?bA)>~T4enI1p*~^BK2*_g#>#ro>SO$_@0f=%>@EdRT>yx({l7TjNzM{ZpmNO zoMr57R0DAGaLZIvR!(2j1!B9KAUS&YN?_WWect*n`{e8FPQ-o&?2`o68%VJb0sk?HexxL-UV^1jc@+B&CTQv0ArpkAi-~prMmpMMPYq`30ht-h#f8(^T0kg(_TL zA(r%-*ZUHNl=}?RU}=d95{sd$?Bi?o=>L36-Jeye-9!(WjR0XZz&-3K>@Zz|)XU#X zn5er&99+}VyvVhGyvt`qJyfhJl__JvRcOnE4Teh(Yzo#q^=2v4YZl9EQgI*s>e~&X zsjK|cHt?YCs#CiC2{j)ugf-0ygvd`=uQ2zI1IgEkQYAr$Aw-h@@y#C>E>`OInLqaQ z%>po$2P~AJz0%yvLyFmhnJGK?g}qJ8w`Nr@X=yki6X7`cZ}LJxk#Zoz*I*(I8O6pY zt=;RAW0i0)VjPA@1rwHmE*>VpM|unrVPXxw;aU&7e6mbBnRpD2#`Fy{M(!aZ{69qk ze+rJm@+?&H{=Q~G|BLZ#)4%%BIW1De;v2qoh!ZXU5CE59C}Eu)-)r{Ab^^5gk8m|M zzB#q;$3U+aF7_V#(#)B|Jb;vtOEM_?L4fF7v(6|zw@0aoPb!qL;;ibui}JEZ?gx-% znsyf8Qfg8e+-Tl634-JMbt3zkNIm@s3>{*@J#`rQwynLyRGmS*^88Lc76 zH>;DIEb1Eoj}kRp`t@PXu!lJIzXJL%YTGPxk~#)$z6*XK1@IO~_aVnV)D#v+MCv|% z$>x^jzs+9|^&Q)w?1KaJvUyBY=e-3WJ~&vaappyjkTpOv>x$C5Xq2ivTYA!YlN=8_ zDgd&3e<2+IpY#oWUyEtwE;cjn0z19OO&EB7XN7?FV*dC3K8J(KK2_h_2auAS`QCQjJe@qFD`&(-Zji_2e4LM3hE{G%ej9nK;@(nU)y;71yI z{%^#I4kR-phvDMs2Mdo!Rfjx&vtXI@Bh`Mr@M*_j{>~<{S1q-2eUhc{_{IwcU)QAU zt8zr$>_6pPVQ0%e?VmWlYSTsFr=lJmM zKdtqfM8@rB2Dcu?4FfX6I-XwH(qv{k}LU#@ItU&Ae+6K?f7^M|$qQH2e$dRq8rIk+xgGbB(%7UwF2vA<@02oNFoE$4w#`2T$CRTKqJwrvXvDQ}7IXt8lAXCcPAqp7>p zW_-UDc|3kVzwjaIPjcDADQ9^eq@Z|x8=h4kndOvQKqFY~>+HPV zP?P$;s@YDrn)6MeZZ(lNfYS(Lnrbl&L}6}q}KC4jVJzp^=F)63qk;4iwa*)99twd?k=8QXb5yBc&(@GzT2JF!qoGTJuqQRkfoB#- z&CaK{$-#w!qH(#CtLbTD%1HBQeNOS;-IG_4&A0n^=5)*ZE~jVC)fPYMm-gNajUeMA zXI)y2zXg{@*D-6)?2v1%+D5g$yW^A}^Uf@@!BlOj;&@@jo3ABF$M^iZ9h;$7?o@E@ zsLLZb>@(Z;hWO|btsvCy`Yq+Xa;KZpoz&IpXY%$JzrFq7>`~Ruh!~%B8GN17`!_No z|0gu_sH(=+Q={e6(}nVz3<}#0WduHX*XvAazvu+no#ASv6d^xnj9brC7_Vm}DdqFu zZqGc*#GlZ_h^>BJmn01x{@PW8`y3l?; HfBk;}BOo6T literal 0 HcmV?d00001 diff --git a/docs/cs-manual/source/_static/images/chapter-1/opening-dialogue.png b/docs/cs-manual/source/_static/images/chapter-1/opening-dialogue.png new file mode 100644 index 0000000000000000000000000000000000000000..5356c2695616e8c23f117da9d74615d4b3ef38b1 GIT binary patch literal 92302 zcmc$^^+Q`*vpo@=7k77xy9A0m1qu{*D^`jX_d+0ei#L?wZo#ccuploz z_c_lw_j~_hPoO{(G|v+vyaQH&2y?1HxU@dg zraniNa_9-dy8|12#t5bkL5wR%&knL z414BZAK!$9CK9K4eyNui+qX|!aH~hEc}#5t6L~~OqH=Q!lw52 zdssKYX?SwA3R_Is_>m*=tku%;e(ztEi5^aa@%^f!za9xu7k{iu)>v}gnwz2KH zN6Rw!?XD2~KG1rIW{w7zE_?p2#k%P+M2fo}1w|_URO7?VR*9v}l(e?Hg(h~Pgn#<= z`8vY~UhSY~9%pO_cjTVkGPmE43mZ@x#O|t81W={wBC5f+20PpcQj@L-FOVPh-zy+m zK+xCFaCkC_uS}w^VbLgtQdrptqHBoZQrL>fsGnX_F9!6y$VPNtLof{^r46UW$5o`I zW{mJkMm_6&>rSZq&e$F8Re0PdWUmMbcdR8;1`A3tG*1geFw#kn$TgY|Eyin^DSU=+ zxTmlCk{L@7Dx^h{d2A5prE8P%h%w}(8Z>#mUW`P?etPx=*D0J!TKp&HF7+!!@ko*) zyNGA|Gshw5sSg@4S0~z48`GmRR+^ z^*BQBboz|e?%W;Q$d~YeIKC0+JxafI{iwmjW_WIqSAEfINo!cY`L9WkA}wTp)0Gf> z#GvdWkd~#CDxrUd|NMizEU6X#DMrHwLxnq8Z3a+ssv-^}^;OYka_P|d5c`nm z(BP24klRb*SX8E1ZMk*L+AsLJgp~+-2~IMwVrEU1FF3Ere6SN_VwZ`@8p+SA3#)<@L2}=v zn51nLx1^t|c*j?URTl2EPLn!0IT1LCI|=T;*tecin`*5n)Cn!OEJ-QqoxGkXnb7^^ zHKF<|=u_#Z=VjC7u+M5GoTW!4!HOO73eqgE?G+V1sgzcg925nE>ynQf+#or2f`qQm9GaUpz4Ldvg{rw6iZ@DWlLI1TT88=SwBO+3%}QX%6`D#)n~kC`@hl7Gk>o@gGUF)%Ew6u z3NaUMR|)W+yAu!LI}rIXe|WA-gpJQZK#6Zky79b`See9$;N$Z$ ze0?HZLJ1}@MldTq+XhD}=P%Ai`Vr<>QZ-^%f_&0qlF8?ywE6%6rbI#mBE08yBs5v? zlwPW!DCsJTrN39IR76wJS5a4_E1fE(FWE0GP}EU6P#IKeRRoOG4;c>G40(+PB|lH~ zP7|jSWrXXf8*!-~S1;v>MSydHqJrw~>`^gMKff;ROQ&!79AouyL+`tWa;ox!GQTq4 zNc>3V$ovTMh@`Hro+4WfTUF)jN{LFnN{y-PDVM2dQ&H0?`)K=)`@#Drp;|^oly>k<7eb=CvcS@g>;)dHR8XZ#|C2?c; z2J?Hwdp$Q}u9@%Jb1IEu=RXN&fI9snZ&a`_u~Oygn8tpMHO_ggD9^F=RW6bnZq~%r z6wZHGpsWYk#Wl7x)HDaXvbbfr2-=K0oVc#KJpSnIDf(#%(Hi5KdD{~+Gu&S>>^M0; z1RC=1m78JuZu>2xpMMTkNwM%__z1ih)zJV~x-y_1p*EtPEcjf2S#Sjw0{4My11AHB zz@ov)5)g?W5*;Ycuf;9j}S58B(^9 zmr&@EHFUpAw$gad!SiAVbB_UP>m%M-J_oG?yQT3zV|z?hwOTE1>`JxL7wBe&caddeedWEgY_}m6S=f zEK1_;Qmt89zb&-y_w96#sGWs8Za0oFE;E)hu0#1+`AoU1;6lQ`PPd}@lK4{hup*K- zuCZ$C_1561FMBu}wE?;ASG~7-Tl%j0a6OHg-Rb5TkJ;^6U?HxAxQ@N?tR6tyJOIs` z`FQN0N!>mgQjza0GX7TL@h&OqLsX=E$3QRhbXl2Q?RFoDp^D4sK57!yCTRkfnQI2H z#@X6&)D8Wp;m8eeWBT!!`{c#0?tx1uM-XWL*=7cq>&t<~Y=E!kRiEB$6_L1|ICAI5 zPJ`NEQ|H~ylPWMIsPi}4rTlh6XKsw3;BE2kED&|YnEW?&cE^!Npwmwu_rt`S{PhlI zUpKrxyk*K6>f?^`w{<&R3-`wa87Z||TNCVf=`^NfI%Ed{Uv7Wzx83@kyr21&ptL+} zk`zz9oZqLBAoevtjOR#5{QTSIa9{lD*vMpkd7<5=o$og84~Cudf(dc z1W%(k;AKhf2UEWBH425rTsWS1_L5!#aLhBha9!qH#2!f=T=Znx6pD$SsXpW0}YF2w(JP z2W3+kaTq1cW6$9TV++AR?n`!Jm*C?dln2@{j9yJT8cRR_Fu$8|65KPGW^v@K{OWA-Y8K}w?i7YLZYCxH))t;MUU|}|cv*!a zJk2zr&rDWcR!5sin`wlJRMjenitYJg8I5_jTlgIL5)nJ~Hf8$+{Tx*;S(K|wzrk~N zQ{mOcgNYf$`c#shpFv-W+saEGp_+RUI!Pl1nUZyWMmO#IuCVBjfR;t?4*^kp;r1Eh zIR(D17>=qykpI(BvI9G8Z+Vn+%2Mj&0VOnPio++OTtY&a{OnSJtfsUXE(Q;)SLhv<(L`xr?QmJcV zf=9t>bi;U~jwPPPRC!5JzO=qHwzPt(uT<3jnu^)BjCy#K?T1AEWNIMOiTs0R@AX8E zHC811;H*Xv0F5a-t+|w=yln(!M2_tndugRj<(3n%lb*Wsbk2-u0j5x{JJ(5&o{Wig z=%noVXl5NLK@ErN#!*1ll4z=^hIv<@ZB6carBjl<8=AiWMQ2w?T7&sk=DF0}kxs-L z-?HNn>aq@&U>eB{$&U}80;+e`4^dvRo`2xhyY;)kbdf)Dymq-?y5KwXTqZ>)4KV+l zC6?J?&eu&>6W^T?lGXk7ws*sNoTX-b(wwiW!ll;b`N_+Z#7FFfq;BC?$PB$VYiS>3 z6m6j*`y30T43YCCyZzgm?bfH$ z^QDd^EhdPeuU%hUZ=trKggk>h^L}O@*A}B31B_cH1!Q3)>!u=U7yl}^`OxUmxabja z7WoVqOCNinEIvZUwq1!`$>-Fv|3FSiPV-8%Wutkz#n=1RyXk@hW&|@QZzd~ykwex* z4#;W#$h;AM+I&scByx_Ag?gsSZIR)2GoXf*Bz@N^3~p(+%9-R;JAqat)j^L&l$1C}=SHf9mV4dE?^%S$lBXOTu)wtFc; zRvr;1X7Ni!Q?t8?_eAI_gc?j4ECyw|WiMIH|G0ksxEjdNjUrd8KAz$k*@Ta9jfar; zpl4r}=81mOj>8Ya)kFWO$^I^Y6j67#p-|ES0mlJ>9kh_nV36~*2aggZ63XU*AjU8o zdzg#{MJ$!JFCy5*0?qXIS`FzfGg6`%M4|Uqt?OVoy=UFPu)+ZgE4T0E zjI~NLilxedLk`1dL%mxo!;)Grv=6nM^njWb1~vNZI+C?16=YSU_TLcfr4(!LH3KpGT zx~95PgYcJPU7b6ja}B?_aUBkND_-n#T*o0uh zk4clEqqY17npnxvhaAa}!NLT}Q2$SOhtdd&NOGT0mrwz82&b{@< zL>3};pqRYp>r-1(`mOR??>%iF`djkTXRHyba_XNMwS>PsZx(Jx?vEVqchPyT1OC=- zNu#r%BT?p2Z2UR#bC`qruaTcC^6pBzneLs6Umeo3quW65GfSF@%U`{|tr?Sl7Ub$pNE>T=wErtVu0X6C6#S3Dk~faGJ1Ao)N~rcx zV2nxJx`g)%s5CF)GLwV};5;kzMZzh(tn@cpm39j^UIX#*{pLw1w&J4=!$;#;Y%hh| zO%%l>j7yAzju|~2XDW`)ke^rSg-ipSgEhKqlZ2YQxjMpH8bC&Mw%b--6v6OP+(Ae_ zJ8ap`K=Ok6hzPV2I0+67p|!#fDGyS#yzaeE);f&9!mAmaWx*=DrfwBW$#pEuC~)>? zJ_Y+rJ2eC=`QI!!M+o{FB&=T6V0LNTaDRo|4j*~KvcBUqxbfureidrn^r3##yf->M zxwb~2T0{6Og}U}m^aGOcCtOqXCJU^Mcg=K2!na31bzTsbAu#l)_W=6^*0tT~!OtWT zEM({CV+k};UJt#1a>vqSga<^;$Q2I$wAALNc^Sl7U`17*2Az{EIx7oM$d{E-nUr!? z?2ye;1E@%jYxaEUzs{)$n@@|(u?>d_fFWURvJ-B1>KO&fpvCdOD}>p|1GU>nS4sM8|^3_6qUx zrkcS@fW3vwt_!h4o<*u#0Qqc0Aursf*P_B@3z+XX3553*tn_~4nXZ_<>8NTqsf1H$ z7z6N5;!xHOR9&vhpJ8BvX*kF{I4)G$Oukv9_l4a$Y-fXo{DPeNlD@~<&+*FzwDq0h!4oRO5km6j78fg47vXQCOkKv1f6`nAcHbA8%AiZ>?L9W1+ylTRTCD+&NzPCC>U>9C zLoY)$RS|19S1wB%H!E8%KUeps6gC2an4iegtE;V-C9R*U3(!-z|E#Z52qjFy&G%)`b`L|az=KhvN7iPJlHdAW-K0KUGy zT)uomymzVQt1gEDz(96<~6X?nCKSchfBWvqv?cwO|<>&^a{X^H% z%FWwLoSy#ALjV2!51+Pvj{mF#^!$%lPXYq|^ZsA{WMkVPpgQgqo1vdp{%2; zEzt964G94uA+f*4|DT?JR{YmYqkm?;;`?7S|JC!KnPPxH0{ly$|IyZ8txxKbcqRt; zuj(b9t)kCZARtH~D9K9e`XL?$qvx3#ct7NSv1n5YqZ92ltrRyMzH$BAESFLJCXV5KSNQS8?PHfme+ zL`m(*b`Nh-R}dqRVie|6%(t?$=6QTQDnbtC|*D(kz(LJ5BP>?CrN&(xm#7 z{KHA?JLIrE`n<{MI_qm4(R?gu&4jg!S13foq8;vQrZN5xxlcC)*+8qg-3N+ga~a7Z zJ7$vva+4<5ie^`0+#lRg^2>3T z#eXk9=8ZxwhgKfmuRFk<@zriDVYmN+e+xYS;g{~9jvG7xwv6B=O9Q;GRQ*SAbyE~_ zX^exTVzXeDTOHSvL$_Z$KVEm0@g@c=s<%FrNXCnh&jjLmd(~9_SD{MLQj_?66lbtR z$99;jOj|d8O0G^z1o&b4 zSF1?}>!@9tqT2RCOLIk;P7UOpQ5?j^OO4{kKN^-Iphbe=_ZWLs?dewW70Ppp$j?I4 z9IY4BMe3rf)o$sza1J_;Wp8yV3YAT=OqyhgU`7@BBmWRs`zB+-%jou5V0yo5nqawN zMpUvW=GJpx<0eSpgMR01o?^FlFq5!!m9Bvj5WSs*s-vq@EaU5CNOSeyTk;a=M|6+w z2UAX0_C4KHq9SGQ3@F-k%zi?_@WHg;5p%})tD?%C0HQtp%0eKBYFBx-@nA{^=oJbx zHSzw3lTRW@3CxZy7Y0i9?OSLu%CkJMOEC4Dz>fA&KDq4uPIdl!WpCh_u`LQjt@Yy) zu21P#pZtnU`wem(s^YH(f5T~81c^_&&j}>Ylpg>EwgY)X>@uK4)1cs$>06JUc9cC43&>mG9~-Qiw^fd%$102b!Ly_uS9+Ok0$$)Ef{0wqJIsg7n3U>;4T3A&emsPH%jrZ2QcMsM;7_SGJ?SlddOfpDzr4dCq;y z+={GU74N#_brd{53fo;+bTs-0*4wyGTi>eO4m@+>oq0Zpm-)j|)AMWoZr)LzNLgLX zK6A0Xn~sjZh>~7Su)(BfmFLLe&LuD6nlPp_f&zwuJNQrrA|e?4A&JpmoPEirOu9v+ zSckLF3GNi^oc|9nRdK?cN@_C;s#<)XNGw5E+1G~Fhc<@dvy>c`FX+B%x3nvZ$U~Oq zSIq1Ivz7L4e3t(07&s)^!p})cf?4?QaM7$Iq4F zAtntnaQ`$?U`{g%+|IFI5fT# z9YO1k2cDBpEtKc3$nx5E-Y*%ID7lWY13#rR#L)R3I@x`y%INd00fpj!LJdvGKCuv7<#?zc{gJ{+fi_Vm^BB32d#i zIgP{fETdu^q)0*Qu*y*c%ZU<w^-($6Sh%=xb1w7XNhtKt30@eDot0sz$;FWcGw z#Dldc1P~t7v`3xGMkqC{UK@zv)WSQJxZB_|yCs~KTW!jx_9&RzJk*9bZsJuA`(QP;0E<3ztYNxpNbZ~=xPHv$mZLD^(Kl`W zz^GPkaDD&=PC=Q0Aqf;A4l_3bzl9ugEG}j@4p%sjK$fQbo#^XK3euM}9(5K9SLhlt zzxa`iHw|c!?`3@(59MN@5L8+NJeY#*^MJ!Fw{=2|O3y^Q0Y{OrT>$;c@t5h6>=0u@ z^|Wb-UXBUEN3cyJJUcn(Ov4=hZD;Vm)MxaOa|s&2$v zg|iF8!K2@3Fs$C%X@Sk!yE@9Pcvy2!x($vOn>G3@3%xkSRcgELUOQr)2}^c5I$YV! z*9$T@bBSwMJy_QbzI6?<$oI?2W3|u!#kELd!jf}52|X+o-;7`zfeg-$Xj;UW`fYz^ zKo$pEM;ykt4wvq5iqm_tGoty7)`gx@%!?Ce9p97>^A-4)=6(INTxOh(tRc?TeShD{ zn|(PP+cY!u+`x?SP0EPj0=cu+lU0Aj4|{to1B5~qd_IqeuvmJh>9xyr)K0uj%W03= z2LII6;SARO^>*ZF2WZQ{Cp-uoxy-X22+D7@9!&gUns30GaSLazSV8>S4Ar581c+KBxd!VgrmH{-;Mmd&8 z*EQ`%pwXt9xg1EeH%^@iIC=n!k)eWs{ntO2dHVZnnB*0%6P~*Rin^= zpzCCoz!Hr0rl*xASuhxC4qeb&9yE2Z*+D*QUzB9pS-J!Iuc|=ORzog-oYjcW4jD-J zH@*Lj%?7>Qk^ux3yCjc7oh94U7Qkk#Bt&Ohxn@izW_}$(mwH*$lZE%twSm=4-@-KD5QXvy6TpZyQyH&`=7&@VW;C zSjur5X^DBYdJ)s0`ya8T8HBvwwuXL?a!_&+#TDmb_zB|*#>~}Iy~17LqzK9_EymfD zkz^v=IDJsw9Y=nxYSls4Wb`HQ{%-$X51g$35=kvwiYqH)S(GL+(!1(#evyUL%qxbG zs9$>scS!R7+yJ`nox8=HJhSB|@OW$R$n! z@vOD*niOQ?pCg5P;%~b0@OYdo+I43FI(HqEqy&=f7}APn^x+%Af;??~t#=tr2Kp*k~9L?O{?qU-wDPj&BHxfPN9RK+Tfl6v|*g1O5SSrqUT zbzIVTOZ)Si)+R1~3^9^;o=X()nY33(cRp!3Y zrp?VnGoxoTT8kT=&`!4-KF~d+aAd_mQbi<+IxQ*4yK3oT=}XXs=W5e!_hFRaFojz{ znXDzuMx<@e473?s*rG~KUj-E}?0N$cE!FW$2nEBO&%lCa426$F`I#A>!*YO>EASDZ z#^4mpoD|j~nSO*ko;m%-vZ{M&7x!jDJbDx^nRw95X~deck!9;^Zo170OzSjRQ*cZ0 zS1s_{PtIFu(T%!t%Zm8U)CgwrfreD$x;|3PxfdSFc8IR{G&NgYZ%NRffwQ{RLj1=& zY)^{XF1$#YF!P%X0K&gCT-HHnr=i!Pte0P@Q|8;JKR=n{7!^vQJKbXPFy+fS7JJXh z0V5yLI>utKrDG*Zrr@h-o0I-0+ne@i6&Yc^2;-EvZ}!WyKuo900aNG*kdWmC_E{Ej z>A%kwf7+lz+3T+O zMN}(P54|oUR*H!Br>|cjWz?4U>WZb~$!@ZXlj@8s*aVkqi4*YHU6;)7JVTkYGgmGP zG4YHkiTXM^1M5yNt>Vf;RY`>DY4nAIutFK@y8Y%;e6|Hh^FuRaRU|Xs1Q-80W*@p# zlT6V#?ACrbg#Z-o9*fTkl0u}>c*mW`07K7Mu}kyS6ugy7 z1CPP1E(Uf6f3g=rx)PV`ZQw_p!nDi_;LUZ1B&+!&Z2n9z)F;tqQVI0?dtJ)VNf)Oi ze3N7d(i&BNwEmbWQ;M~fA^5>%gt+F^zxW(V_TnVM1b6sjq@|JX?BmE*U2v8u*<(%+ ztd(NxdsYEGTu_p6U8jI<`L|BZg`i|Jo?GUEIc<3}O%>6uDO2I&RcLFihFOq)hk4iU zTEU?%gHE;Dc8iva%gdo(o+C4J%E1(Oub%EmVP*0?8`3Z6Jb5v;FKwPYri=aU+svcj z8J(|J1{$I&zLh9GpRq)GKX<(m(3+nz7(McaoV|Z)qi~-QybW79yca$(AAcUUC;!Rt zrSfW**6_~R#`mP=ly#X#`yDjQD5N=UG&j02ytdOYuW$6f7TaY>I7LY(FiEHl3ISzw zqH@N|Lj{sA-|Qv@XC{3KI^=Up)!8KyeH6J_b1qE33i2*yGz+P4x!)Y;e0{y)3`oZa z`CxXwku?lB2~hN*qRx1(GJ3Rnak|)mUxmzILR;6d=K?zKkMiqn!|dj+@(?dkHJsQApzrY9$t!FksYPM?_FaMVVkq~$lk|pOKPSe zU!NU5uz03Raq=EV6YAbn5wGd{`C+NHh*$1Y4!*-d9!rehga@kP=1ED7XN=g%_$u4u zebdR%ct}u|sb4R-@D=!6>m()YLE`=Ng5AwGAAk^5F6H|~IK^+jh~%U6eg?-JQc7P^ z@@`9c;klS@X_|+&XOY+!Tp5YUJBl>t8r>LMZlk>u-N`I83v@ZX31|Dc$0BI8FcaJ% zzAP`}x()H~cPU?cU)sPG7^B_I?>Z={e~k9oOXvi|N~WS0kSABY&b4*rp)WLRQq}HO zG8EZ9@tqLP8X6KjNhvRQ)~~n5(e@05DcwBgtHwy$B7wgRH$$kueBHF&!AUo2>U}hW z^)oN9X4h@0LC=2fpx@{$o-Wl=nuel1xjiqN$wmpRXx7M(Pd4N=eNM$N48F zB{TH(RmoE3T1)wU_6j*5pZ|E5BFinoHP^TuMMkgANp_~n%Q`jvbQkkRvEp?7)noy> zE~HNOVq@)(xSv@a>-;cjI>rJ`yy{lr>fYeJcJmn_N)ksoyY&$Ep7!5B7p5XpTD!dQ z^>`(>Q`7S?Am!xIs&ng^d$T?uaaC7XrR#E-B8j7K%hc^H6(u+j{Qi!`Ayeh zoCF(I!9BS!6Jhd?#2HQu-xg&FmXpv&hQ>4DR%KEWKmWUP==hA+2+Qg{qC;JZ?dJLo z#Bap}8ZDIP_~6uz7^FqL8XRZ(_0D0gdTE#I=32Dtp~^m!4&PHRGbd z72{g`UE1$}%ve2$jTg)pKa(>*?csQ}l_@t+LzBUZ6Ts7|OhbEPVZYz0ecp=S@efQ(1yS-cql+kJf`QNRE9MtJ}A*YgCopskl ztT4AUjgSXYk6WCRdJ<_^K|mN|7dp*MAS8X~4HyZlJ%lCnYQk+uR05`FG-+a1@_i@4 ze>;7&d7s+EmjuIVL*XRF+$#AbcoJ1V7*f{X5Qvn27LT>CHLMT?6`rmBT0q2fI&3uV z-$gtdLRxb9%<-J6g?RB~HeJ-fj2>Wm=6&;R6|A@N5GD$JEo=VbV3o-nw25mZ8B`0d z;NvKmNWHr#H_uXlPo7<7Jz|pN`P*DY!M9d@n4yubzu|*zf9~Wxd2;U#`$Kd)2xMMY zxUtkh1X^Z97xhF1gY_qcYk_PebDJVfm_jcCE4_}>n-WrTmRLPU{DC%QE@v^m>-(?U z*kwuPuHqgukHtG`9FR@xzst5F8k;GZsl-c2z3Hds#L0RL7uPntAe?V~lq?Z#nTQqW zK{ZkJqWH9x0nHFWT8_CrIJ+8xEej5fqlIwf@|i?VptV`V#Q>3;!Kq;F==O}D|z*i zKYLZHSp&R$2RIs)xFf@S7*&Asopc@ziMJNKtqHm-u4}}ocbA@3SfQiwn`MC>U1fI= z`aiI*(g~V_?uNXRUd@F6IZ-m9T(b@Trt43`7UsXQWT{Qh3Fug2<#U}cH_1;Cg^l^k zczDXdd<3*a|K!=8PM1K?n{AHsCA9&(gzC2sL>giZwPm>!FYw0~yf*@^($am7n?L$J zMaw>r;XB09DlgyJsUHNTs)g5RC!{C4*4!yTK-}K>f=?K+gFg;ktuvJ)?JNsk!ZJXE zkvffP&m;80UtG{9?5FY~)t9<%5w52~KuyH;`}SE5;^3$~RN zL%KM(9cPAVxt`6}kmN$$5z^~TYvFt{~o5wg2|Dvlh>+2C-44r|zy5vq}`j8{Qv zvp~#de#%^CFJj~c9)oBB9vJ9?ylV%@+B4-Z+YI z)VE07>?Vx=jisWNxOl2lBGiPBR4JK(@UHk9$p_(}VU2>C?e zWf8_xvb(u@B>*mJyAqCiw#$Im2j4bxbTxV}_vW0DmQV0^k4y)y_tiK=KK|^ff75}36l;YXOM*>k+7Z`D5BZ06{kT%fY!t{-dBy&vI?TC2OUn<+%S3M7K;th77 z_$%G}5jE_5T=J1HzBCmz(`G7JSLf>v7{~KJYaCW@g7|Vyg|=#UV8#|ogjG!To##u< z{AbF-Fx7n4^Cil3o*d8CrR$J%epu+AU1-8cZa&L~Kye02I@)tQL;!Wc?0+(ZKOInp z60k|F<~hlJ?N+yr=G*RTZ;$2Q=LRtN7EpkOStbM$%-P9 z2@YkeNXJ-uPA;$8Lf&i|&3V|HVA%8|T7l2Mlh;yd^cFknQ28{>Ll?!$bvrTpc`iX) z=CcLm}J`tZB$9@q(P(@)TSPNxlDVwb1e#uM#c9{oLr()m( z<#s)#?xUK?$;SErlgIt5((2www>A)S2tSv$4bYWW1r(Fyv1yr zh4ZB$HJ}&UR?EJg6Ck0nN55UF6S<^Ic&?mP^xVlC*go}l=KQbX_8-A0XgB)I*q7(tQoUX)J9yHx(bvLUiDjE=zT1}VGRgl{ z2oy5HcRyoXX>mctXcyGi%`^H@<`HqgL7ii{EeB6op0S)+r1brN=scmC{t4AG5YLsW6yZ@c^qE{6 zfR3G;vzHx5AzPUDiYh0v@7K2li*W9>Id9c@BYVl6;2h7uP-FeSt9nnB^)(x*CvHSp zp0qVJKR(JoI7L9mj&ej+Jj^;EiB6wpQwZF@_!Pgy*?Q2H zp=SQ^FJu4DHwo^Iv`;X~BbmVWB+d2 z%g7#gMXJ=JRHWF=W8d+AmF;Z)K*U}hJAQ1OC-M7caTT2NE5(}4aV-BTO*!qv5&TX(!xN=XUM5p5Dtw+*e$jxS@-Y1N_ zpHIXjizLlDL74bIZzK_=jF-nSUQp{Me4F#emM$GjKLAMviU#Hc3ymM$>sK`$Q0WwK zJO!FG5e*^DR#{LdBt0M0S>w2wsWaZ((pu3`-Q9B#rAm<}^@nhnglcC-JHgKzb3vPh zPyYDaltT#&WI1VHwAFL?cHU?WKwV^VChYy?e|dFL2nvo+G-N%=4)pMx++N}=AEWdM zX7JpW|3A?uFK8$P$X!2bXjhq@{dJB($gw z{D!kTiiB$ggi;zF@ zA?CxoG}8HT|L#lA%=}@s?WqbcvkF%x|I!fCt%ToUu0vAXBCR3uV^B!0`_okbcVFZn z{|E*i#($YHQpG zxr9jo+KI%QUm%MdS!2=fD{g7a?YIgAJ?S$yb(3pQIjNn{e#yZ8Fl+$t&h~3DfTUM^ zN#4^D;HU-28yH-(#dcz+I)+FWG;i8Zw8bD( z`McCe4kibiy`2ePxV#^k8iYRxcj|4)ka$qF8291_qrW46 z-eWIe(x87vn1i;?@w{;Z@vSP0l&ZAA4f+x&lTE$+xn(=C6_;mhgQ;5iNb$@Ut zxh@$h%3?KNQ0=CPkq3G+n4W+;eq^iTcIM+n>zoKUA+GvaA;^{1SY z_lyiVHb}v?B~S*I_eVr^n{i)888-+uN;uzp?#`i~?L?P0)s)I1%|XLZ1as6Q?vP&B zY4lCJ;3xx!n5B}%V=}&4nn$dS<+0&SJ%cl@^%7ua#c(VkEznD|h9@vLIVv%wYGXt) z#;eDc#>ZcLXNnGx#Bd}zBHH6%uZCkuv+TuEC&G8oSpH$e~JKoWWMexMO$P_O07e-wE<$UX&9ejzlkEM8=& zJRCK2Ov0!l-k+}f_59FC&zZv92vfC{eO}rpv%<~hQsRhL$LAnWeRyDCpro!&qhP5~ z4wrfk3u}|RI-fSLKFUrCfAf?lCMm&Kfh{8yd;b@0z`QB0zj|%EL#fzF<#cL4`z;bi zdATN15loR-Wnc2d#z01tuhR z2NIGgKQ_7*Y_p?4FyWaTBmRYAZE|Wq+$X|en-N(%XS_E&F618W`+AVUEP2*&h=m~s zEGHH01z2N2jdM0J!M>Yin3q-7W}vMK+1+$wz`_EG9QPXT#nSGgi;>v~~poKV2@~1v0 zqi2z&2#p7rXr)y85U~rQ`uaW&_U{+j@z_aL@&O!YWY|5w$Z?ewROT8XiQk)2$&b*L zE@H-!tzsU|vb$VsYBnOKo3h_yNei$(=o;fD^>`zo@MZkyS7s-?2oox%p;7YfqP(Nm zU}tOHL!E!WK1IL8N!w@%7<#$?YY%+=mg+9z^lSAZ`K2;eZbWl{Cc)1A?R{!kh!Bc4 zq+9U9=p8>v5Gfa)L$pyrg>yVX$O9Oz+c!CJUPsJNZGray^&OF zswNEOeLtP7y${M@#~H0XnX1s=nX0)7YR5Q~MPB>yyPjnS)Cv6D*jcl;2qkLCuMZK> zuRZ6Va0@x7xY-u$#>8@7qAw-FZ4U1n`dN=nGnZg+sReEvtTRdmB}zs6t!b}umNAMy zJ7D`jd#~+ygpG#mC#OM!a$U-t=7&@GT=HQ3qvlw;&8rv@d_};$UIZjijghk;7bUNd)Q?%bI-kQI$^?v+Bh1fis{kz$}^@oBNP zwDBJc1X?X#p7;a_;WefLr%D@f;F`VZ9?uWr&T^@l(3f2PVxA2qks#9ld05X(rg6k| z&oZ_}vZ}33Bq;jU1E%ZyHIXWR**(nZ+u*&2~Q9W&54a^&mmOtxUdh zr`8NalvNy}%IL|Q`!kFmi5Mf`KkQh({U->|tuDXeriO+(VdM1F)w3k%ORcKKd#&wOZNakr~DuL88Bc{KM zAd!l8F_*<((WJC_v!w!+A;PJJ*5o&TL(oJPqko~mkanFvM}?WT+KY>beS*|I@iXN8 z7i9cul|?6dyB*^Q>x`c-6S-lQ%I%~-*-k(7tf6nDpa+16zpgV4BM`w|7LWRx5nZ9( z>8G1D?vRiWJPHrKus#TElf}fTkIENI4r(%nuSisRuW1b~>kj7R#xw$V=6y1vK(QI^ zY}V~AeIf=*Gn=IJiL#Fv=Ai~F&j%8hWn5Za1roBD=vrt68nhyHz^fhpjkkwVQ>rRj z`6wuz4y~MCns~`8Yw4K~eGOJf1{Y6B9M#ib>Pn-ca7l)!hsb5sJdy+j*uIKw#$*_? z@sx6ZciOSNSqrMbGlO}Wolc-t*~$GxzK1LMLx^FIML3Sify_-Lsm646gN_}8c@FoF zd_}h6BGZJnb;6sN%B}ER40(R{VYwh7*ziLl|eKq_*ZsNBw^2(7t8H4n$ zq~OB2VAl9;kAKB|Bp6Wz6AZunIUYY@mywMWpAN4%aQeOu_5@NaAOUA>sbktD9T`FC zO-yA4poRj>s5<{$P~>X^z-FXcAex~J4B266g_U!CJfAI+4byf?`6dJjXxc>?^V|f* zS)OK?qDCQ+v2@B$!`P|~m9wHvuw@ZN@!aDIWZWVMZgqBAB!Bdj8dh}Y?XPDuAU;2( z3ZE5B53K~>V=_>atcnb8n?bp%=KK^w0BdbVzK~jhd3BBPl9T}- zlm(PV0sTM%Is~=q$r4qrJh5HW`5@2I687;JT|^N2fx^&?(q)NaN??-MOaeF~w!*P; z23;^xC5~*_TdvwOshsdkDS+9UL{{o^ekl0!SyvrWZz9g`bz~m?q~7kbGO>3V5f*~c zdln_E~H~*fvL2|NakP zu5|f5d?xQIF9Im7xZ8Q-nSAadC$*vP;)e)lhw5t#{WmvNh~QE0KX!xz=4-c_6kpn? zH*TuA$y#CHA9LUHov$r6d=@D-Y@W;NtR=e`DjfsR9xhG%StK#fSZHNQ{0m_p`l0N7 z`rZ|O)j&ID!ldZAX~IX9cjWp^)YX^_skVyLz;Tmi{B?ND_j1E*-t_p8Op3|hnFD~3 z(yT?Q8eg-3r$Jh;=QnC~;Gagfqt#rf4ange3>tk%gzo~!af8DQBiRBw=$nN-pJ1pi z7btrVL_5l2pkJqjoP~sEfg8Q+L7ix(G@t(tFjPxpw>RxEre7%dkk9EH-pb8zc7TY@ zWR#4k-n3D!#{ADwa)1;NfIED1iWm3v*0YX=iy)Mt&Bz!G|j%dG)wM1++rGe8*#|@b}yictY=BWjl zPKSTwe9sc?_=Mlp>w^hge8@RW&Z)2<4*VpDbzp~6*25Voy^f)=y`~SeN78Q9IoEa6 zMx{tVQs8PVzH&+6!hFoLj#BM*&I+gFCUXtja3So6OdB+!XA4J)8WKvAo8dDp&!8va zw3+%ws?0T8tu`0!NdFI0b}|y*yrull7{w<2XB;z3J`01txBnD#mX##+>1TYAB_Rlx z)JE<|^4&DbR4GU#;DKvfd?u_wf{dbZv9D-U)@~LnQ^g@+7SyF9fwmb+#0JX=Vsh8V zvDY-fr@?NsC_gZcF-zHgkeaV+M#J=@Hh3w>)rQu|g;YDku_6Up5S<`tEqZM*1J-4? z+U0x8>mvF1zG4-=CQN5k?c|S)CjxPRn`(Fqp6U?IMa{@?|Mn5J$?M1l0C$pInVcMFKvKRp9tR(Mzbr5%>$m|MIJHr!g59ZeEdi zs3df60U78wWj>0ji(A}B7s|BaiiIgn_G!-EfCUI18;&K@mknTaWXz*NUbbM4%pOpJ zaalpb@WQDgU3$cMjuigOFv)k7|MLpn9K@EvZG9Hc>~A5H_sJUH?T|-!=atkr_CF=f z&)k^9GUo)R*i6#|*_?oU#DJlfap26@H;j31QmGG5CS`LNUU&^|kfmPW2FlxS=O+0& z+OY9qy)$(jaF2EvG~0r%Hkyyt7MEp0Jaj~_!wR>`a3m2`o`M8uo|wACF=2$+p-td^ za<1RvT-QmLwlxCc9Sjxvj(cys(6App8trv3m$ozH6m?ZRoB7nJb zA)>_0KF<5T;@4X$j#>SxcQ%Y9GRlbxrp&L5_GfT=t%;9m5-r;>kb-5CJWz&QmoFI5Q%VO~3lJcDdyzd#Fe5C_hK*ZuQTl(5ZqXEQXqN0T;CR{^<>J}wgt6*Wwi@JKWA zZDuUNfpi5WOZtBxDWH-}qAmBIPl$*&;nA6no1dRAR3U0Afal(}rMjXvEXX#J6{OML zS2jmC!fhm*fbjWSql6A*X>+sF>!jiU;~}t=yXKYBAk>ZCRaG1nFXg%{?-2f>9$g z2zY4gTR)%*V<8(wm&Zc@ivKG|nGoYI?r{;2q-n*)Uz+w_Be#TI!Tt>qoDV!3KtoPr zWiRPAyn86p(Mff;zEy;_9GF*EgOiDGZt@nbAmqx8O=opEuKXt78BU1G!o@Em$=L!>fdZ0;nzvO5Ayzg6(0(#rS zK$yNv#3Tkkys4<@|1w2UM#390^8aNDuVK|4<#@Y{;6_T@jKt22DxxxPsS2GngVOzT z5HjpsKul*+h+zt24&_`&>8k=ux}*UZywqLl8~$grACO~8OoR^0<^U&~K`M-qO}14m zK68lXvs6hTMH!iX#tluKTWF2_d0y?l%l2qNgpTtimZs&42^9ksXc-7DeLx@B@`yi9 zol)DDmIXj0G)}@0U&sWR8m~9Et9MU-QBx~GP~Yeb4_=4#Ok*E#FcQg%UFvW`+G_#5 zMTHN5@+u24NhK3iE(GUPAppzlA~+V9Xw`&?2b&V5!ka?Oaj@Sq;l7lbcg|FnNoqA}@673nqwI?Tp3_iy-a}4QoFqUS-2fdeFh&X_Cjsk25d|CIbAPqRSB<87W$f%AS6%=}N1j)*NswZ$qbvQ`ur2s@O3qW~I@nm-oO z2`u~md%0Qw=fDaVs7$P=ClzB9-t_uC9l6Y*4%gA}E*~hB*&5A-CS*u3YW{IowyK-X zY$E?jGZHHk`nfEzwzeRR@EMhyizD;{5+~ety>du1z_-xi zQE9tSEq8sg7EgDsD{I%aR0OqBWt`dV5J%W#unoLU4CZHc66ndoL7j_r5yQ6^S7{yU!@Gt2TZ6g`1L0H-{ z%mv040tZftpM(S;WA6JBsu6(e%0UI3u` zyG%_V{SVxqT`0j-K_UAs2-Nr)i3v#C?#Pix0H}yKup$&3U5o@6rnGX-we1oYB!w|E zE>D|WRU!lk{?AMkwpn+Hj?ZLgtuF_Gf^~EZ+Ap$Cpe{hM*;BCK8qUg;lx`yrDAQe) zx=KD5!FqHNFz%eE_x$e^Phyu?A|Xoro1SaNegBhZ*u4#NyeMY7lWAFz2HW9EmockeG^#of+?9s9ZYPrjWoR);S2_zpVn_EFCA?MqVOsERmF8lrr;;{xChaFntAyWk?w<*S-t7lYQIheRbnVa7 zG8y}cbZxXj5*tZ$p}eR8Q}WE>x9D9=oE&VJ#&M_wUSc>R-8x@iwI+ome<8#vBi9>w zVaOMWzva{ixNXhax(Ekr^c0W0Qal2WNFmp zKOj6|ek5fpHA$X99Y>Sj#oDc2wl-lq49L>@`m){2VMu?K&GJ()R6N!;h(v_5P&L9x zv7MXIPG!dPE0EGLHrgA{f=R=11ON#d{lylM+{c@J1*i>3@>~i*ozA7Y*PU{Pu@-Mr zLpjiZ#oLmpZ(!YDzKH){snV`1;=;HHb4nJgf5uv9^Jy^f-Y>k(&*>CJ7CvLl?s&~+ z-1?4fL~TEDTe*2Fq>?hp;)3wGP-*(V=rb%D$l6t7MGg|kjk)7dvEOpx+tm(E9PF(O z|I#LMDrmC{ZvWcw_@QbzcWzcpfyvM4&imb~;6hS!p1}k?S26|DI*CWcrrVfIVsjHx z3-BD$;!a*}L`pr~F)RX#B%IaH1p$4Pfkv8v`h3u5rl&}g(Jq$OPogo=K@FL?qHO9% zGMC5++hRZyFOvzR2PyfXn>UgqpVY zt83>Cj);s+;RZ$~QWIX_X|YsNdAS8I4%`^qTu>u$3E=t$w8x&XO#J8_0vD!_{|;+X zY1PL3=)VxWgM0=gR;( z(;q(LRBnB6z(s22R_u(9Rx5$uO9?=i+~dfYtdqsWl29k>F?a6y<>Trzz%{`G*x%v^}`R5Wc}Bop%g zzXf3HK$SFi9r+4MbNzma$esiF!A9+z{DSb&c*6kcoRUZaGvMtH3MTaTjuFdo^{p{F zucm;`^9JO=H#gKS};CUa>X*{v@2Zd_)YX`!hUTACcIz zDvy*Z9vvM`&&-4jH0V6vagn3{aPry^5Lx))?T)bXf33Um`@g z^vszfZ7?g4rZ5Fr6J7!RyOv`h_2LQh__Y%uli|{_E`dQiNsaFtv7nQ*kkk!V=-mvu z31ElII5up=aIh8BO4}PmBhpA!@oKU#AgHM5|0unp^w>ATgzf*<8l4IZoQIg5Z&p0$ zn)n)0?RvbCWQs04W3I~AxRdW}R@s!*+7z14+`l+FelT($;dF)~j22o>))VW&lTk{! zi2Fwg%a2(|tV&RuTf(n@eer(dX`0|dj8POx1A<)o{K>Ufw38Y>QpV(kL#4(-Jnu~m z`|8U)uTJvu>%%NCIk~Q0Pa!LpvVrTo_Qd=gWzi!vfli!3T9#0eF~=|IX`a9h zk}G*VGmgj*16^|}w$XxzqtATr_t>~^grAU1poDMS=?(C%gFB}yQy|HQ-cmnmK$!$b z)KaaBJj?j9KoeYIB{KsRM-z~R+?rz-8rGO8FS!EeGL3MFVt5;9RHK<2x}i;JMqo+? z69e~7RoL&xhW_*<*VbzdFR(~$@5)&IUlgzTS!PjBr{^GwbN!niZwC-2K{0E`=S5UY zTT#VN=eKdVvDltVsPmP5F=Qil4J#~Z22NphjR%wYGTO1W&8v@BV;tK(xe|d^r&AN} z|7SZyl$(HIzo*oVSfu(B zm+Pj|Gmz6^ZC zoDKV+-`X$Mn}uh#K~96=ynKv<(37%lijst9sD<2%6abne7CC~>TYf>`!W)QHAxw0yNQA44IDdO z*;A&xZC?s*uzc_E@&B7KmbhbI;6)$swYKvd_y!&b;thtEvs0Tni7hwk(Zv*>mgbz9 zyyN7YlSh^#l$8Bi*KI^9b^j5w22DIByY6H6sh-C1INByA3g;mG9SgYVGYM)Cjht{f zZYWcahAku^+N$gwTwhXD(Xpvxp8mGs8JJ&-kK4~27gqPpqrSTi0Nnjx6(QT)Qe~rq z`NZ(&6CbC3J#DvXbu3fYcY?p~AQC_5%n9W>QItao-cvg#=_eU*$)l)q>4!S`^`h1c z+R(D-s=3?8XR7x|$D)0~f`6G23BB*mFS&aewZHTLcb40i@odCVLoI6$L|!N5X(KgU zuNDG?gAzi_&cl|>&RKP`nHyHUOUn$JroH>|@$hsjP@bNirjs5M%RYO3(DNBjp{le= z(>JDWaHr*Gock{wj~NJSyl@?YXRJfQfnQaYrD77%qA@f32=#o?=z`_=7J+EIc$=hR zg8YHAeAuPz#sg%qL3TU|P2y=@h=WIvXFbnPpt*>>sxk^2Lgq7vy>BNb8rE(7`PDl! zcu|)(S#8+%KNm7ZoC@Ah1#S!if+0)7X;g)?l}v(>u-#A#f1Ov_a3IA{tP*W|oqul< zUgt;LVgp%_!U&H6QvC@{(kBjBB#u3RUREt{_WLnjEP$%FZeZPoY7-qD)JvO1hAndD zI7RV~q6H|Y6_~m^?a1C)Vb( zn-y~4HE0sU7^jh{3b0*1uWg%EkYO7Rr$^A#l!i?r*$PJc!^+90o#xTZT`<{xaBOt zkNGL=G~|SiU#v0nCun6sN@g~?wgfRL54Dz?5+icZ&)|@+I7#c@ppo#|oXRWpYL_J0644n!7`oMhH52FgzP0q7ZKi zSDWigGFL1!F^*o$pmZdj{xB0E0AReiXL}Pwq}Z{u`0}1208H+F=(ocaSE-YFC0tv&xSRAfPp=I=7=Rzc@>lsH}gp1e@vyF+W3~| zV?OY%k8#9e~FxlH}-R0+i?4xA;YgA3za#2b;2Vuaq8plttGRzEa*M)=^X2(KjBq?lrbL-0Aq zfu$f8h6ka%Y(QUy?lvCU9`htV3QufmQZKN)rK(Aim^CRW)<)Wf%9Te~IzeqoS9GpF-F^vTGxGujtSiI{A{MSz>s*H7 zwfWo*fTPcLMSwXBGL#o0SOQg$hWURMv;R209w>~^6zO=hUD-dM zPMJs!6StjFHGbB@o@i{P7K0hLKV_eoDxc82m#?#aueOSC>+s#Gycuehw4$R1MKAf1kqM|3=NfmnWWwdNYs>Uxx8wbb?P#2|4FU0nk}*bPX<#Py7N^9b+tS0?eNHATGzfd~GJbkEIt&{$nDF@WVt4_l? z9R+vr;{k8F=?+?|Z3fgHJqgkboBAWJJHx;E9vY*Z=ja@zRNQeCx}2q)2hFc=oZRu% zdv(cB#jE^RKnLuwobwwgVjc1azn!gU@$o)$q_m3CJi3ssD~g(Nr3#>BQ*n3^7wx3WR2VAIik?dbj z?}X{s7CBda^1+cd3Ie;-glWWvB;wL8h=AMR{&Q<2GQyk&boK<79n4dGn1ppm*T#^j z7|1u^zt1Viku^fefCY5xLfo6-o*&Xjb0D)b@=xvygSN_<(^dnb^8B*Tq}2x%gHNA0ml#X{Ile9a&emG?q z0Ah33dBr7{!>)^7g!7iU$#(2}Y#To)_s*kChi&62JzcCZ4bc>!C3^bUdX)NZdamu` z4rhnb>dm6h_HhKkX8LOBe^DW{5nCCcpaeY_u@#y0*iLW4A?yvAbiS<`%SHe_O>(H5@Ey49EZ zEoG`4skh$4QB8b;vL*Z~nnC6>H&}@=3Oc&*0srM-1^R9($Q|SFzwoXQA27p`LRs;> zuC-4q`{&?0W9*mZBB2$g7xHW7JW=Hm#qEbT{_i9;W|5^b!xnA%`nAf7TqwVF^+bSw zs=6&aSjfchJjqIo-H*nnu#YNHKWBygOiQxem+VRZB~!?oBA(_^rWcz(te%p!R9W0u zS3CB7a(3Gnzw1G{t;#+6Umu_8x-%~hW`+qsEdtp7&9DEcx|UR|5H8i%=C%(D;9SA4=0hb5 zdo^fJo(dk}29B3{fmfBfm}1I_z;tuSDhlGU0H8h1mWQ&RVr-Js~nqX6APMiJjZ4h{Pslg#lcvWF?z+kt7=Irmt z7(b%n=rEbC=mkx1RRWMO`Ts;e@szjKp^dDp^L8{W@QxjSK2DIZf;R1CS0Xg zdrS#|`KYxK$%8%J;y(`)YqE;`li(mw*zoT4gqTfGmN?yW<$h?LJ{cqOG( zCb_C2HBPN#Cd9LUmtRP;_dxS9TOJklzAIePzQ$2V!7NCIc4;P@ffMiHQ0-?Nr3l7B zS0Tktz@O+2?Hmc}7AmhY7MIeRo4?u;D}2X0y}ca|N#g-HF<%e@OOF9x0#u&=KBGC$ zq+pyW&w8z%cRM=tO{Y@MlWaVc8qHF`y3EeH8~#n1 zOoH+7wfo2U-Hvn~7qAZUQZF5O59CalntO_hPf2`~7!*F*v@Z#)+}(exWI7mfrbWRF zisI2_r^Y}haimw!_jmW=`BRnkUX&;7*3}v%xBA!IJ0?g-)Jh5MNUNNYX4czEAAtn$xp`fjC88CeNH1|k;FGRMB@gd^P z`R#R&_AOa|zG}}R6*}z}$>r`ycW|rIO^L*`oUEP)=`+iqq%6eSO?%4r88*ODTW#rsP@B5x<`{s>}2}3=&=_~FR(J*_Kx&fD?$@B@nWE5Dir6G`=rWe#9_vPWgVgK0%?|;9uXdUMb;B9aW6ZVm=8*&@wXLeZ*JIn&TE}a#P_)KQ%yS_(N|mCTn8ca3|ui}p4)zv@^ER0 zDIFXYC+KT$5w!6ZK40I%dTrZu-s%Tg_pZxj7>kan6<_YJj=P_m2)0ig^Vk z(MVQJMJ#e4TxYVV$&eZ+b~HhqUSw9TWrjDL-LDlnxC4%o*LM`aPSmuDBVGBS7E*;4 zv(B8IJTN01)GAxAE0bc_Oq%;h^j&%N7pIo2jxRX|HI_}I2li<3s3Pb-SDTc~)DasK z|9ZMh1;M|5aN7V0l<2_i=8eiQ939-$1>~~)SP&sHZyY_Loe!=Pt|T7?XOKOr>q4Ej zQ9*XvTel7IMoC+qoIb%OehfxY#vG={0ww{ej4NYQA#7$|MvXw;w`sB5RX60 z*21k!Hv>c8awp7;Hz~|zxhMn!xR7Ud5gN6%{A7e5UN9o}V;Nd+MPXe&O<%*IVZFbn|El7U>E z$k@)7v4V8z+ykuRhup}xLzIyo6*toKWXrVm#63*)E7~I7GlzIq>)MiK_6T^s3%@g| zuK$6?%NeNhCY)npNv|N)7%YYjCjRm+Nte#93SXTE%qb3I^|KrAT?*9?~1Ik#(f6 z>o9dr(<&DE_ghtXo{cQc=6AvFL&*lF5!_lm=%Y3lq!JY(f6LV_3p^IBqD>L+4gWf%&a_~r88TT~sdLa0UINHE>sk>E%x3Ivd5>WBXG zEINlH7mhJp@Lb^Sx~cyO`@9%-R+smHG{R%?RobM2eC`Qi;a_Gmm{2$&p18v zH&MN<$#C`3njrG1>ZTTB$r!LiVa7bf6djqlz@>wxzuo@z0lG2D zxGANFZ{|^1*9X8FU_eHJS$rxiN4#9!hqolG*SA5nkvSZmT1e~xo8KYJ9n)^$uVaJK+ZjoT(+1fb3H`8_WI zW}K55CL!*BehP^cM+n$oS^s&*#OD>|ISs!TK--kRU_n7Jy1!O1pxpWJ=%4oVbc#iz zti+Wb+Q&!0!BKA$#%PVDJq^5t^&@*KFvzCRZ6#ImzIhRF#L!fo8z7I&XY8?tOlloL zzPl;eXxE#Pgz#)u$4U7^`5Bi8`lJM_8nKQ4xoYN(bp9@Eb4J?oWIMvbBQW3-xH)_jo3_3eWESXKD-n~@8;4&S(Ce1zIzL^kaFB(MVTjY0?MALZtk z#i}={M??NbCAOEUZ9`wPn&>OT8Avw|xn|d*!7TMkjf-oXy%5KJFT{D`yE} z^(aeGf4wRu5N4p6WEL4oEZby1(D+8DCw%f-cRzsEww!W+zDAcl7)AXTu8Oc433Tor}ZMC}{wR9^iVNA9_CSM|em}WOjLYxTMNWA*@=$g0pov zNU|tecfk`%Xj1Mx$54hGiPTZwmAsu_e%a7XCejXN*Pon0w{bxBuV(XbGi!i_;^M{) z`OA`bYQmcXn%{W7%w)PtZLv`)&9Fe|wpKXK_vq`!s9VjX+Zn-@BKKoY}K)@blKRkiO7Hr~liUSy)G8q#Sy5ioL2z^`!sV)53b#%3D%0YZ5z zdyIuY8kXEtG%ceq=rW3@%j~q>XPQQ6*pfu_!fcYkUu@Jy83kBJ~Gfjl<0vVm1c5B`{_62vQ@9M zZ36K$Xusj;#U3cod;u2IBCD~G7hu`B0~@?2?zTCTXR)6Zjh)nr73}O&E{D?!h8^iv zX>zoSRE^ATn0NwzN?top(_D2i#MoIj#nS!!mO3j8bnt40&(O%a<39DiPs05ADdC}k zI?3>~JUXmu30RhQQ59)3&@ROu2%5G6romKld9w5>@6u;FQhQx%UnSJ36DaB{ztx_` z?@4o)6+Aj5(~EiM`Er@ba8*6Wcu+V#(CtE0yw|DlDlOGqe9uP;+LnNpM}}M?2iJpi ze)dAv*ttq@Nkn!l2OX0qSwKVl`G_KNj}vNdz_v`wi}SCDz8~GuLHBT&WbVIHnGP=# z&Qk|Ky5=8>C7w!BG6l8&o?RD-t%yW{H4C$31>@-Q!{#(CkOFQB<1|mr{&26|?lhb= zj9~=%G;f4c!B$+-d>>*H?PYa2Y{vPpaNd=&OIS(rBy={w#y5a~bw5f12!vIyc&ef)(_>)S@Y@?VI5` zq8k6~GNcim!36bnASqeu6hEdpm9I11O06N^t+NH3lbZpx7FvMJ9Vtz0HWK7J(EPR# z`Csl%vZI&!I<=#vMTdnOg>)|3SFeKSsX)tjFK>J&IpKbIo#cRf>z3BP+!4?y)sd2z z_gf2O(3aCov-7HezBdUrNc|)oB+q}z)YmB}Q-xOd5+M)7x{ix6Ti5g3r!0piwy~W8 z*q-kHF4iQAyplmLbgZIyq*Bjk2Zu^60d^6yCnv@b{Lqf!5W+YJ@RL2Sa?)c&pf{3c^!`btHWXFk)4<*%?We3|&4kIJ^1Z638>h$&v z;t1B~PAxNeqF;~gpXDR+$x1^zTkmjQe^ON%KlwwfppW7Ez6bs+fZ?1ThBl3(gT__% z#pbKx$)i0*kImCZHl~eKo*(F;VB==wL2$vVb^TW@y7Wna)uRiJjAMXPf{LE*-S1UB zezcC}Br=SGSDnK{xu<1Tdz=zK@Fr<96)lr(!1R)<=oaBk|EF)gsUnq7n<`> zDr82>3B+8bMWugPA8_oYB=O|&wYlIE+=>(m(fE>Kh-&HcykuNLg*>=?EDvR^Lg#GZ z8nMTCaJ=6B)-=0R`A#FRc{3SJfJE%h`S!^whr~Tf&RD?`=i1&UG6U{hulYOY>k>?dUlWMGQkp|$ z40%AfZdkx(47WjO?iij*ZD$-l3lj!1)!zfx$56%Y45gT#WT-sTq=^^fHYq=aV&|{7 zKj=f_QY}c={Iq>%d1Z+ef>gREt=nFPraG=++)B19*wy6y?p5vDgi3n}SwJc8@)OBD zROlVv=6Vq(h3!F~D4mR}$pf5!aYoekYZ#va;gregKRRuc)(h;A*!%U|%z;f3y?$cQ zxCVGpZ<-{z?*b+yENHnt*J6Z^tAQ>CJCB3TAo~MmnpH%)mx7nO-wOie0vy#PMIss- zNpRPhe$D!d5E~@PMxTKDoylx{;O`v(T_RSMM^JF0ADu*{Ul5&l949t>lW z1Yu!eF*DJZPwxoVBzt=ov9_HUw^=n@|F&}1UTS;CXn(X?()_9T->OgZ?_&@3Y*AMG z8i=SraCpXXPxwRhGhzu(;ClZ=Z~@_0qFw$w;twiXCH4n8R0LAI2ozEEHi!CFM^SpJ&kfL{|R;S z xleAQK7?)?>rzZ83Wf=uxB)vjd#_-Bmy)hTOI8M&R6jwO3n?UE^c!3o4o}gYp*H*?E!b zYIHMOYS~rUx>?{R!lwaB^t-fEut zjXD0dY5MZzLn9^kh?V$1i@WV>Q2nc~?bb^PT8-XEoH|>F(=|DdVBPXqzuOv#`b;_l zC}YduJVi1vVr zT=$x3sL(yPe$Zytyw2`~DzVdTG*v)#u`Q_;9}}s1gPpMe@s~K_2Z{3M>EifWRC6w6 z)?Zk8u-8{efs9G>CJTw>saWOmiZIIGS~^!HqU`VHCPR&~P{F7P($fO$hM!U|rnJiE z&@02y0Ur$ul(>vpYu(%p1RLd19Ralh&A?O=7N)CzuWo6RX^&umpKZ)kPuap{-9FrC zuqsw4M*xPq!pbUm^6P(F5Hv^;!`1emkPmBG>ME|&x7@~`S=FBx|GmvMDb96Cf4b6dw{t)|4450T zWFv02A>P_p_&<@{(G9o@QC-o~mLgD-g}4H@E%;{4a^;CxS3c^Iw&GIN)UI=}|K7?b zHelGWt)xh+3EF^Jn~g=|w;W8-bh&fnltTVF{Neg-0$9s(Ri|PO>tnzn))f3QThAXc zX29t81o*JoUMJ5_f?V{Q5_#mN^`X>JlOt*`RMIke)ZVSudS>J_(xUDSn4>K`d=7X( z$U-}UKR6T^OZNMt+F;s4ARWA73@2ecEyu51P=jYCaJ?|$$5mT! z7=rKMcc4$u{Ixb{UnBt;zJI5A_R%QMq`}wr#vI+FFHfD;$PRPAAayxn;U70B(gMH| zn&q1L50yBdUYXC&erxfi z6ncA;Q8*sh{;L2ELT*q8tirK+Uum7<(`qg)yJ<{n0#cCxHXgeTx(VA zMDgF7@bNXgQvGX5x}Ucdk>BJ=Nb~vO&o()(5gJpK))LZ(pDAX1hO<8{p6LPGUeiJ} z6l8lN{7crX;F`7JGVPSPYnP;7*LeR3_mbU8kyP$}SQNX<~|JKmmr<0MwY zU3?sWNfLjgyr*;S*G!J`V1b(vy<~jCOdz zP3P!NfUTR5prD?Mi%X+qwZzz^uV{10Fg{Db?`APs1NjW6;DsiBYRVS~yq-M0V>d38 zGA_sCvr0+v)1m|S4u#-&-aT`r&K9vuuESB+A>Kcvzj__bRdy`~O46)51${HfES%TN zwXPb=Y_@yg;uOK!t5ZZ?Vr>JY8V4t&c;riRFiaIyaEWkFvT$-PC?^X-DA(T^aZW~Q zd8n-ONC-0>U^oYZ-YsQa0;=`eE9cwH<-V_!7j@3@bqgawctN_iT5%+v=|H9;idhj` zlbSj#^5hBmT8$u`y#uBdW_0=aD0^vT6;A2pzndEgf-ZGfY`a$p3K98zG+doNVD1_t znRBbmaNV9Dr5l959q}b$yvPLOwbQN>A9n=?x$8Qm&l$r+5cqPk??@#LKlGl&IN-In z5sX#=MN4FPyKG?c!|~-%ecM-lE^dtBSp@5w+4`#8&utj|SeEX;2yo#);$olvBCKl~ z{Hn*d5_qvG9*!3Au8#>2!{XODZ^{c0;z97ghhq+naBuXAI`x3JRH4`pnTXl{N7Y++ zMcICDyfbu2NJ}dvt(nvGZ05fz+cej*uH%QJIzrS_PTIVmA zSB$V} z1K+zVqk49e>R)7mJ-B+n@gX&_J2o|;_{}7C_FV>f2S9V}ZuX=$y^}G=e?0&KtZCu~ zdRLw!e4L~6*pEFjQ_-x{pc+iE$`YWQopc_fh0#2R2LO2NvV2hBh{uKn(VfQL_sEt} zMtfc!Z%Y_oMgUsLF(Z|@V<6zX0Z~e-2J)X z;yB{aNpjgV@V*aP;jk89cPPC0^rxarF#ew5em^Gt;zkI0axBY_tBTwSd}8aS1bKgH z_;yq4eWza(E-!LD~3|m+v=4X8*iOM zSOB=Y&t$0h(z4!jh`#1CK+Bw=?#|OiZ~hdErY|OnX)9Y%Uo}RprOgzn-Cj@$Q4{x> z;TS#8uSp|kE@~>#Qv74cNu<9~V@+(>v%gXu4WWKBsrzIqh%dFiHYNDd6vA&yurV3< z@hyY^MDVkG4m@AdgOPt<4y1w-nuwQB;#jESNb@7=1`2)^csMPQ(Q`lYi3zLiJyr2E zv;A#2pT`$g4NvQx>TXd3LU#w&J+J=>D}dO6yV|qN)Eg!AvA@|jEmlRF?8{`duf32A zy9e+q3E747o*Vpb!u<~c9V)_xG|iwT+rXwcEL$AU0hUd8L9Ae%HcYFuBBJS$@Tf{$Y2F_>1=8%cJzZ5r6b4i(i;ejoyB%e^jpCYIUgRKK99G*T z484|{Jl5NCFO>C&B>$QKY5=oRk5f|co3@))&+7%NB~H-UH#YDZ=XHw>XipdwJ}1v= zxVUF*oNI8|37-}H{W|ogZmJtxpcmeUuPti_rzMdSWiKsMUVEjTNHqBw9_In@eB9C1 zPu(fAP;9pUuu1_m}OC3RTp@PEf zX~%kzu!EXgd~fAy$37Au?ELx;xn`Xu(RQnAVDt!)wx89uygSnCOK-iHak#!QF8%J+ z?H{yr6W|Sn!!vosYSc$+`pP|?&aUH5P!_ASoF$L?K}3C%1?)D*3q7dqkL=67L)0=G znAB~e6in=-Wh&qzV|D(yEbSLcL+7B@6aN!F$PS&??=N<<fx*)z;?8W!*-vOq^$h*0vcI18g zQnC){#Ue)N&u`Kh(E~&%C2>6fbe@ok!8qdo+_CM}(szSqm1=Od(#UQog}YX#bzcj} z%+?nqW&AH?V25xM87nTLO6R!57~dz&5Vjv<_;u}G8StSc?d9$gf;Y9hoOPg#rfrzb zM-IT_IhPuKM;D#_NC_RgbF(twGSb2Is4Vp^O`6y73w}7#C{BKeoj=T7v#B)Z$J@s2 zne*NL_?doI`;1|uEps1CT<1@U4+N8RCC@vUch&P+qYFw&)iKkoR-HwquERCy-|dP1Kg6PkqLy81MuRSqE;0B-E@Jo1tRAM+lZL5G zSTGIv(N*HsfbTrRveMp$r=`9XhiHMd&1*XBH8($IgY3#@i+{cTwCExkGOVkw#A4_0 zW}GlgBQQ*{4}V$7QN5YAMJ@WF9@)4bjWB+y${E}n!9Tp>-9>Bg{JI#^?e8fU{lo$9l6MAT_1lxZ`K>%_Q1S%X<2g|VU&b#kr?oNM6W1n~JE z0domg;1DZ^_zP=Z2)DIU^~ZOO0*n`i22Hi+_1wOIrk#mA5I46xo3`<L^3>mkzj{%rV8wu=~bsAV&M}z5PGTFUp)V@!( zGl#L}p`DH)&&>3K8>d0wW6_`md4sw?=JzOof5Gl)zyA8Phz+GxE{3f6hpb`_?84_j zcB>EDLPsKF;Mm7MlUSsP@9_WoN znoR(lBf~i8xe4HMWpE1a|Mkqw<)r1I48&6dZLqSw+*hCSvOFpxOY)#%Uk)pYI`UIf!E z+|PLo9hbQS8q?6q@Cf7-F|$Krbhd(`=C~Z{E$EbAF2A}#2moH6)({p{;fvC+j3nb@ zDSz!OP6KeLYe{o?VW{@HtKmk+E~1Mf1bkGaIUpic_a(EBo%mS_>G-cxxpnmvs8TLM z$vV#QM`G0mp2n!;V+9!8GLb&op*A@{W)M zi@w#1_6tmi0I2lgAE58m#o6qPt#K=eLpL3I6CUmV#~5kAc<$+OisbvXd%vAZw}bxvDch+B+-tny5cmwwXh z;Bho@f4&)5p8}<+m-iLa_(bw&Wd(|zMOdN zjSSU9%BT~?sY6mMl=g-7lUXUfn-PC$RJg@UaU1xo&eGc<{iFUuhe@Z3ME^xw?mand z?G92cz%&{$F|WZqYnBdBmATmmtDvT#YGmL)AgiNDKQ?o;d|a-x@>VHrhfyDPPzsY;Y>9DQwa zo^a$E@aAZwz_CI4uGpMbc=|EW*EpkMwM9X&-45;R$PU(FOe*1g)L2Sk&@v~z*5)?_MAM7>~1%G}YvlYyR(!qcjT5?j8%-Wlay( zJjw)%2Xo}_RW@8|xJM<3()p88|HVt*K*dQP=!QSE)%a?+0V4KgS zq0$!c4qJK_bzrOQLI~XyIL7ml*FbzsMZ&Yu!*g)P&cOdP9q!oGn=2;zZrmx+*6Mr5 z(Yqk+XrpykPeY$N@Ab0e)JkAhzV=tj^00)O>>A7OSsugh?dB}GFLiXFj}-RJ3Pgy{ z0K`WX@=!Z`=u=bHtR;Mz<<0Pa900&ytd?`G&hWwx_G8;Vj22)?iKvMV1s{kol+>|G1?2*?@oa$=^}6i27#D zZZxRC#CdP#ZN5s3Z3tIUEo*{7s~ZhjrRV*sANGXRBA-@;8pgBd-P5iJwHLxGnBGB! zO`LoOawU-bBSpBxVy|R+Rs#;PuZIY%^eS&$D$=$NLlZ~inLXP)@9?{ivyn7slT?_O za)D15IT0IA_a{QJs3ocXy)z$(B*-pRTLabUqR=x0$;*4XZ(UZSr>5m6!6J9NyY-?m zeIQA#*2m-stSKpre-UkH^iN28M=&P-%`<5R;W}y}o^}PpV}1}t4pIL-`78#Y0tk5Z zd=j|!L4eVFylgg{2RIhZ+yPfci#fLxP+fEXh}tw{{>S#6kbT9E&op#Ybw?8VKB=)} z9nVYme%NgrWVF~nr!K%6FJnO#(v`6d3x_6Y&h;u=*=e*+1NZGGT0R*_w#&aIF#?ai zw;z;vDKNtvLW;>;8MQN`S9|(~gCOk??*?jz(F|iWi}c9Qr@?H3|7IB%eHHe#o}#6x?#}NLIgsamep)+{t~T)$7Z$zT*{2P2!Ip=)7AyC@_0P;M zBPf47{FAO z8I-cYxjWMbG$g0y)RX`HdMAco7#xBILvu@TSHWoz^zzhI-0`#9OXnTqT)br`2SjHH z9pFE_*25{8!$>?xjNox-TWoVW|O-2ja9e;~Sf9JvXAz|?we~HL&>K3qrQ<~~D21Kq+6pUKh zYfghrAMBCfbTwlA+ZO4X* zOVu6`R0uNW_UgvCi(ohdzZ+@9-jz^FjvdNkjosj{%VdxPB|J&*-(87k+ZgRmsfiM5 zmLY{aJQw4$N|c-Xu;dSm92QNWF-C#lt=uekj8~A>$Bg3TnbcY@|5G-E=bE^@DZ{Lx zGFXa1r6-ID3fbc|TK^7-p8bk`0hU>NJQ5zwcGsebCu=Rf#rWr(?C9d-J;^rAo z`|_sr8IWJAamP2BkgMr^{vr-0m3fE;AT&Mk^4l~?v%5N6gA^YlhExQ~Foene8U(e) zAf&YAqa3=i|7uEaQ19OnzPXMM;QEhBdK)*wOJ2eRHjOEqQ|&3Q@4`7WCpNb~v`=5> zXUsVh$`ZA$7cotOr?wcZ(Dn7wMd)xC>%_pm+BUh(A&T%g#xvB79M8c;dHQ89rW!2x zO&Nhr=OEB0T>WjBt;NazI}3n{=7rV^LE+o;R1BG$=oP0JNRxozQUUXDi5$-CqVx&j zvKf$3=iF;&&+3o`HDb)6M*9UIs%GrKd2SZ{;t$3WpzW5RM2xGyP(z`BjPE(sx$+|9W5g*Tb>D(9#y~ z(Jq_6VQ232z=)X76ZSGYewP4VMaguA6-d7<;g;hQ81JhU0nhEjeoNO|_<9a3mjez% zQ_T2Zu6@l_@zhL}|E15gXA3%?blk%fZ>lh!TtbuU4&#KJH)t6JVYN=#?iC}(>O>4eA*(Q9%G#nN=1%t zv9Q)rnHFQy^ozE{9GRn;bF*glTIBf8L#cIf8M?nAMSZeTYC`4jIS;5zCSqrlCA7I8^T`*#&b*Y+1iZc0m6zLPKt z*vmjGmcA3LG}!p59K*jZ{AH%(?{VDQeb7Y@`MqriZjR-=dbYh+~lFZ@Mgd&#zMSz3iob z(enr0d+M7bbusE7p*Gf|qIE_Qwa%xLi*|~-!$|H3JCFtG9M4Ez7s51X;T~jmy~2xF zL>LWU_;zj3_#BN%-o^X>8B;}IqI>CSTzt7c)QE8C>lRR76_p}3^_>|p2J-MW?fwLa z>Xhp~XD)2;Vqp|0RQ-}j-X!XPFlzH_%<}#d+4&Z@#i>*IEcg1yn4cw}SonR13KxAV z4ph6MCbjLd5IBxnx{eLU5K6@)kY2p6=$pQ%>vI9Y+?8a()PqAoWF0A~?JPE}3UbfZ z!X^S480qgZ|6G(#swhTxB5{uh9cE1&zZ32|d!~}DeXqe|=a>H?pX;hrqkI&U@R#J- zSAC!W3|8j0Osa@vW0YP(u-sQ2&BhYuc|KTevf?k# zT+jNvXs=B6)d%lS^2Oi?6Da}%l_2k+F@QMxeK_2}d_;QdVv{znsHnPbx^e^*!F^nZ zJfsGm-pPXr?cx>wD_UXgt+T;jc-K_9SimwG7MS+tzjlN^0{1i1 zxMO876S^`A=DHA^g_jy0dtl$$%k_ynXe)l$`WHc~K+QzxR0fi5;zv7gzZh%%$kHHjC|kH?eQnY{!3`j9;AMh!XoA>h`)aPCd$YtW-rS-H1AtA zJiqE!`jG?cK6oCRVGn_FJZJfza`)+4T>}>uL6);f(gWYWX0r|F4nR#baS3naFHXw6 zTih8DW|%N3qwtZ)PG&9Jkwp@EEUtczD2g!QqGe;BGFR$vL+`ux za%x;mR_S#RLj?p3&#-M5=0n~2pHsa)Gl`tSoph#7-H74j6bSD9#65OExBPm*E}z6K zAvgWm?FKhgTk$|at{=a)t*Pq%D-@yVXnmsFyj=^*YBcE&gO)O?zSk1inH$EHXa)ZA`}yX@?@aYGLK*S&lkQJ zeY$q^h{o$zQCRhQKPKxx+Bioo|Mh$St1t9cd>Md4XCBTyx6V3+w~|HRh?IYC;L?}D zN;2RZ_HK$#whMP+N~;_?31@|m1`JQzRZX{ zExR7H=iUsoL1{E2?+I;)vQ<+0ZZ&3dDo3C8`?g$~=HY)1{`wcYfd4g;&(G_bEArO} zoujeii;J724e5)svPYB_Ix`857hmG;stnl;6zbYtxpU=!Ilt~QPj|O{l>xh^=J_aUdWRACP zX$8uuFBp3Mr-Ji|tBOBCC-X%v67Q~Zc4Y5+$j)1F&pgS`oa3PJLhkYC+`-%(>J;`0 zLp+nm;u3Gefv1y|5ULLW!XF-5=Klt>j^5PGoe7G^UPMhu&a{{}2RvymMdb`FDQw^J z6}s36|4UEppK_{Mn~}J~b^;0>CX)y+qNT>ZtEHS4W=`n4baT@6a08+FzRHAC5Bt)X zID5*k$@v-FId$vGIyTX#zr5c$D_@V98!M*VTwjMP8wA+!%CdQ~9*Ln!w7{kVm5&D= z?5ZD7&%TT}>E8{O#gdH0jxfkk()wszxZ>>^4}Nlg3-HvXsXbp1J(yt*CZiCmCb7n& zRbU{8lv1fFN@nB&ATo_@pn!sd0?u^0go6cK1I8!}?>--0_37NyGJI&G2|ZNhu0(Gy z%~3~sd=%^1edHl5dp%8n$(7s<{8O#<66&t*RDKF(kL1N5<|_|N43ysEuKuL~_A;{Sc~iC6nfk;HLAyb7_3#b;Ea#b@GDs)*!jKYEno17VVY)C1U{}V#neCc-a%FBcf@x@Jg;VSXdF#*Zd!I0#saQuO{T7X zyNwZKlskTp6P254t#bSkk89XcIM=4BTzaNb59>rnaZkH(_FdrwohzK8 za9xoOrP+T%^a@u7VtXXRDo*OjdtN*o4{emxISul}CE6HjYWAhZ_TrQc#}(KOEZN{c(p~sDW>CTxLGHz8H?fIgG)1gN7BN#~Jj2JR<8s z%O_A3FZm~m6&S{mt4DZ+ji}5kFXNg_hnIDwddxRv8|pso(9jm6&ulEN6~1uLjGxgB7=Vu`%P5FRiksqZ!k~FD6-EtD zYnCfaKU0~YoeFZs?D$v*xRSd?JTW%Ai_BIY2;%krYjQG23iU7lQbNLKpEP7i>#cKDAk+ zCwwtP+5f(RsSzalhZyx+>e@sdNqd847)N$3XEqCQ#?U+^(x9lqF#RP($-$DAl;3*} z^N1y6lXZ8x9kw|IY*b~hVG)Zm+f?dtPt~C_81qZw3@V-HY`z#3J7VDl%L8h>b?t3z za5HM3j#i&W<~OhM86IB)3(k{3i9z{OyY>Akoi%&X!n0xSOioz_-3ocnOJ z;4K3!J!P{r?A_Rfa0xNl>>RqYMP(;HE@Ksl0xLZolLC`01YcWT_-r&Rv_^p@*Osl| zL^M0~vz;D;by*4~n#ikop2N>WOJQXAidQdy-7efaadOIE-uHV@MV2w=fsNd{w(0lg zX0cA2&QEV=S61xtx9fMIEidOyE2ieazB*9&`dyr-K+P~5fdc+TpN&3?!@n|ZaV&9Wi{`hQ{2;3`Pl?ro`&-Q;w!MVQfb0U! z+3YDFJwq#2@OZ&Lg=OHWz5O=OuY4q+IiL`OQUFnCa8Z=`!tnMt$oKYEnAqg!3JtM| z-(K^&ELvyAbq{ zFnr3zlgE`4oBb+00Qu>Qg6SGH=?*^%6Ef;ah_RB}1dqz|HyJ(6vDe0be^G|N8+M+t zb&~zvx50mO>?AHs;6hDEfUS;un74i*V}vVospk|^h(L)f@xa3Z7gjQBg^ws5DVc)kBc$s zL?rXH+N9Nz0Fwebha&113~+*j`UtxU-36Nq+yC+jjIL_x^`M@5lU1+i6D0JE8Wbz- zb_TY~C4Y5EV3DIUSEkdv{T^lkT>hH*O3sJVhLg2EO>km~AOi#A(_8$azKNRI(DG3E z7yv9?&}~M}>E|a_3f6)KvGkm06gcA(7HaOr$L3v5{4`IRHAv_|1aTZw;CHZLv@B@* zEq`{b*%&Xy*o^qG7(wBNG|N3wX&c$;QjsFxe$_2N<1nP6M8AC)Lph|}cl-4E)tnW~DPg|m{hyrKHJ4ET zO`8q9D{d20d=)#cPrm7Ii)u#pc|!EhjeX)DF{)raz$rVn?oisN_d}CniJw(iYs-Lf zXpx!%M=|RAW7xb# zGwHhXek{pzZ&sBR?xG5Vz;behIe5AwiV}diY=OznWXT|9)cR%}O8Ug~PG^eJH?c3s ze$g^#=`1^b3Jm6{sA1F0;RQpyLB`ii`RY#6KcN|BjhswXZ(rdUU!%85{Q00lqPIt1 zocD*eL=(BwxdGeS7&Nm|@;kl+3B{s_Xs0sa$^-sd3Eno~B~U|L$>?(}bo_-gDh zX~VbaW~bXweE&yV(2RrZ4fJI z-A^P~ZnS>!-n6MKQyLTITPi6K8a;R8?*V_fIoaO4V1|iWT~OTqN)XJG&&A4(yi`|T z%^w3?`rv2LlvgKEY^rMUcSr5F4?&^~BH? z=81fYW|HbZztr3qx-b(}Woy<{Ic__7N0b+({IxO~_fr?$ zV$r(=^^32)&4r%Al=%bn-+v2s(9X_y3Z;hJaCVdx1BTFER+Q{R88LDA8;L$8gEi*Z@+GNWX_snQ~9v>Px=pJya=pV`5fm6GHC~i zN!iaYGZTw($aEMRHBQA!DA|6A92a}@h2d_@$g|HZN?=YQrX1u;#Y$fXlU=b{5~?DY z1^x*@xb2Lxfrq~h!6c=>Ui_&`?E%Z#dJP2p?Tw-NU{ri2T%=qiqPh)km53>ftZ_y0 zXBHMtd(=+k&P?4Qy<;0`mr7kY0$4 zar8H0u7z0IPyfUUDuAnqR?bHk`YTykFcW^l{x+ij0w8E&*rWhnc=Y)3+X#I+b}5|>eTRm zZ!Hm97+F6Ct-q2OI$B{9?b@ed6yy^z54=dHL%5zL${fZTnO)Z#(^jwAXI3TGeQ{`W zKor5mxbD}Q?X8_<)o`W#Apw}<%pciazMR101n9ggcZWJf& zcYpF|;~qEeWSiI?tVb{qY7-^YWs)Y`zI5{nFht#~*}YpEkd;3+Y524qPe!!g2ok&@ zJ#__96C1s7Z4xB_1Mfa7a9)Ps@GVf%zH(c@IgGPw?(#p!e$Oo*_-9+L2A3I5gT#lW~_Ri4eyX(lSe4xo-JcOXOvPv|9+qRZ|Z$7{INv+}mP`&6(`YjFNCdkWBo+Q& zcMPeyjeP4M`gaEX!a;4+WK=Q$b&PY82u@$#FU?)giyvku7k{cg2k1ZwK~!krS-B@2%VEc83$P3Z{I87r&RNbe!jc|5(%O zh`dhSZ0J6rVOH)2 zUR(Qd8?IkoX>?avp`7Qh`OLXA%AI2Q_j91Nk%Hg2z?Bv4+cJm)yZ}D_rvxxQ6wa6P zZe3RRGEA~ko`*NJR#>?s%zk{2yri;}XFgb&`?u}EB}9TmDc zhp-W?Zvf-GGU<-Y!OlQkJ!vZC(8alVOZ#dLj{ z|By>T%b3_fv{-4bTn`joiSW7FUu!XWdbrJ_wc*;XP2n}B&m^y_uU|R<-H09>Bqq`= zlTOa(ARl(VB+jD-u?PQ`>ZgedKwT?6qxQes8&yX)P_}0f;^uZzv+*B->FR>$KH@P# znD%myx&vT_ZJeBu#aLFKWK||rBh`~r{?p2h-MVER*ahZvp?%}p$&VAoV&0rGw8cu8 zP$1JM*CbB2sE31cbp+s347K_df~vNdw)zd~5S^paZ`?^&L0kAc3%TyjCqCs%SY-Gv zwv!2(nhC46rLT(0rnEtEOrs;Z*n9r=h z+}%$Pi}{j3!ATH9uX^;lLf+Z^4RmK(kaxMgKSbyqtK6mON7Il;*Xyisz0M$ot3Zzs zVk#z-*kn2b?0`D4M()Y^rg11YruMj?tQ?P9pN}Kv&b$LXh{8v!_TD-a=DGh%0HxAy zk=2+L*M$tz3+Qp!jj{k3zJc$NzmBJ!Q`d^i=QZ_SdVML!6Xc%)hvO9LG_LMC>)PW+ zSxIXNq5#bcH<^zSZ*Nc|JVkfQ(X?~oak-W3fl9cSQi4`6m#AcZ>3tLvMx$~GV}TXQyOoh4VH$4vPn`Y3YXdqPrpYJ(a(Df%oR zRLa6m3ldMDlTI9Kv_LKxyv~Eb^XK?cR;Kf~rOpB=;uYdyguaJQuwrARZI@{nTwsQ8 zDatfqhX}q@1=T^9l8Z$=1uC4QqMw{i9q(z6DJ~o>fcO{lOa>2 z_cD5!u{IJp!tyto7cCkR0(;y$H} zu$|!$yBOvR=_X4CxSRbCG!wUP%J$hW4cDZo9@^$*hGG2u8!pt+>Dc~w4G3__hH&c| z&i)jHBw}b18&-KXJsH{49$g6U$uEdh^Kx+9Z%yKhYY~Rtn0}{xdDIg!JjK^Y$N`XH zE~BjGD!?jb2T(|87o>wDg+ea1M3v!#_O|2r`lNuNi$wkA;#i757P!(RYBrS7iY<|~ z5T6MZB?S_(&%8_%sFsz>3ZlPUJJs+PVn30dJWLjGvj_E7vaC-xSNO=NK{Cslr%873 zeO!w8E@W+qulKeh1OhnUjQG-);unL6p&+^(n>yg20ZCcTf?CLHnNFBy%PWO4J= z4H%^$CV8$;TBWo$mE-l5+*;@&+Eg1080O7eF?RgCr-t=abY0HhFUMYPNf+Kp8O!v5 zG}pV7g+3kv1TDYL$;Zl$MIdzb-mTh*#|}kpk#q8X(%EnM+f*>6rvI-tN;Q3Q+8bNy zYs-SS2Pm&lctm3p`#yXF`SuN!9e&V(+dZw^Peiz{Be3lbKNvIA-+)By@tf*?=+Kke zVIfEKDR|*!x4eWZ_?gXCSsp1a#3~|NNyJn2aguktZ`x3_FpZ$?`fkU)IO7%3(;CtB zc!Km6#8tX_>U(>;drjtraGccWR|1k*C9N-P?8jez{02m&O;c+XKEo?5lX|tr8C2Bb zCa+L7qHa~G$7nX2VXs-Fj@5+C&FR0`C#axjoG_87Gqjl^EWm!c#B~+oqh-ibUvtHQ zu2$0+MPOPp&JoF@uAVhyN8!`>8{Oo`9?{1K=MB-$CbU?R_$HOXN$Etx9u>J&4{?SD zYXNVg(kdeLoqhRIVw{%Pn7FX}TxGN-MAt%q!}fkXIEx)Zpj5h+gE|&&3|i-hN3_7n}xvN`+B(mPUAnw>3FPJ zWDCy#0Tw+on-;SufwH;! zylsblfo)N?_u10md78S2`L4K#9TKFPIvKcmk*Q(ccRIve-`dfX*Vhwumea0U!|kVx z7k4X{&1b;`eQ%_NzQ)>^0*{N`{x5*DLzR3kNnvG6)@URbT&hkumSZP@hw4XOY?Jw||{|XOyymJod zelClVrLAQCTt#>tBmdc5&ci0#|9mcyY}wXntM7>@4$wo<_YUOsM<#~=L3#Fd6j-Ut3LyJ=|LvH=vZ5CaFC`4{{yw-n%mox!dT0Zb=8M_LDOaGLqx!#83X>LrVi;EZSuQ6_b2VEjt%SK zCZY$iV#n2Sfe#z&{-Mfxhi#^rU{qH}E8dnG2N@R-n{wOo?KY5dgAcyFV zBkjqVVO-MLdU^`gTu`gwk{rY9&%=VSKr^pD#wcd$ccs=8{8T<~Vi^gmhB9WfCR2Dq8clHd6d=dDQaW8 z10bbQ78uO6CD_q&i^ILVtm4ynzj_7WA){5_SUk7^y5jCv$4Xf*$PP3jM61*vbDrqq zQq4srBiMRIH^e7t2|-zLDx`e_{5yODQ726DIb2agtz4)wRn`#1#mmE%6+Y?mPg+R2 zkg_FSsn<_6vW7>r8vVl2K0F;3{!-=tL@0I=nwf^+{YpnyRWk;fa-3Uv6(xWM6Ij%2 zzDv7sIM`N}`3or^kH8=_0T$UG+S=LS(==q?|K157(L*)v8Y=W^S#@7Sa!}46{Otym z8)$oN3!hXU$Mk_d(Ld9e??-Au%#h;EK{2;-PmpGq3CHMg%|q-ckDWtCar0vJ&Zyt% z;lNjtspOC5Da#e;9fVIDN5^B0gT(Bu@`7DW@s@p>IxF}GEtA7itP@|$+ZH2>4|b>>&7-}#&Ufv zTdNY)jG<{kZLBvQJ>9``yxCDjeT|TF^!Q{^=|H3!O87s|r(M>$H1Yt0|4z2zWnM&= z(5~SC%kgq6rV73#=@DEAi6{P7g(;eRbNrj+d`c>LOS^ z7dtnY(6spHm8i=j`bY-*W2d26S<_~59{>N&ho4^AZF^hx!gAmHUeDMp`__%r`7Z)e zvxef9t>_!qy;1dgp5Cy>yXV?8KL+r>nAa^n?TKAfe57ZO6W^yAatB%Jw3Mix0JSGJ zv5Y$JeNdy8{2vdDiPRSoRYV8cPQ!RHa_?(WTZaMAac;eu?#kxlCW%R1W<*1A>sc?& z5qQiOwEpvRhRc0GmhjkAQqLCZuldo+0qt+S4JK1y#yiGo12TWmSznB8Vtq1?#iLVq z&+4t~EYr^AZUD`QFcK|QrBm0n@T3)ciTGZz!5hmE>AW++johyRNpkP>%83$G_9<2# zJ7=J6tt{)BG`3bYR*4b_{|-UNV?@k>;NrX6u}^`s#n2Xj(CYTLL@3)Oj&)4fj(}9wWWFg0MmKDK-b%;NcB|;fL#V{)1fY{ zWmAtE9s0Q-K?3Ztf0c>)C^8JUp#%S}f6pq@hO{`#*56LbN{s$*!M3-&Zba|lNUB49 z9H_OQ-q4uWG?4SP*0OnwBFLT~Dt7u)wV>EzlErnFol_0UWAh52sb6Gt*qDtPK7eKN z(f_Ez$=|NOkB(Pe=T{gdi0b!pM@poqrJiokJUSTPpmAxfT-iik$XWOnZ7 zNd@hi2*=aD&ZHcQs)DtjS7-9%_PUC>VX~HtTVRgi(u9kLX8rP!5ycyalFWA-q^NSs z1heOgMFy1b*KEd(a^zBUL>+VG)@qx6hJ2}YM^C8}!id6ZZwstF+8@&cWi-EuNycT= znwu*OdBHog{sK^yHjd`!x@9}-N$yM;#eq)K6yG~*7okT$Gk`X(tuH}KXM9|GDh@F? zE*!@qF=w^8G&v|Ri;m^lC-c62f0ZkXFu7prTG!vp8FbCnHReg7L`nUFH*?6=0NOsA z%AUrZp1JF~)aLG)PH2uV&A|N9lAmHQMx_+ z{1_GNL(hO)S%l5)t|De6S`@Q~vL2vd5(Sf?q16NgsFr4UqJ)U6UHV*HUZb3r+P<7n zF?d03WUf+B5*MIiLh5m2uHijUvq^7a`{qmXge%b%AOWC3YXkGbhv1#gj7+%4_x^c_ z55aZN?a-NMh~LC(eDQl)!dwEas@=~7%AG)lQ1+>o<+34|(^#g?ArBT|a z&%)~{ZEOH_-$FKZz!6bw$O5|{r`ZeLs6p;-C*Cdh-DCS{%vcnWO>7)f+!r((DXW&hjeVo9 zN9kH7Wj{zMPv2bs5mvePuuK=yxchlT z1^*T^Coh`2n>DTg|L`XSmy+7os~XknLPO4X8=87R4-c67KN4|!Gq=53v8U6x4JIwx z!KXY2dwa0h*w|`z{3x`Q6Nzn|Q`8r*qPd4&7_(=?N3gZ^uQ&Pc$;aYrzjuvC{l6aT z_dTxy#}(;PM1qPeTh-tT9Qj!{8?GmVso;t>IXK@CEBt~~7Ck@Vzu7~*LCUY1zAw0E z%;+ur+?Axgxr7UXWfCKsxLXM_T3{$9kV1CnVXoqKo;EzUT3S7J7-5>VP zM-!y-4klIRt5Gcq?KQ0)9||Qq+>NrMJ5~ptL`?K84&#h^O%RKPA-@@Llc}-OL7p$rT1^|XmYWg!oypYs3%X_|A)J`3aD#K!Uk~y!QCYUcXz)8 zcXtaA+}$Arg1fuByGw9CxVv+3*E!tozTN--HuE@du-NRqq-<4vRiyyEZ3lK@B6nWX zgg&TTP*ldMtGT)^a}+v9t%lwDfk4DOdM8hRztvhqpW^NSW$6LM7(EnmltIY(3|*h4 z=Upz-qKLZ}y5cNnw!PB`Miy%ro9RNMrSnQ+1i*p_S!#Dm-R*rk>%t^A3;DXxB|(BA#S;fQ-N z$NPdHF)9U^g_>IC{1Z4N9qaCMRx^Xj%H$t7KEB*q(8E3Q+Xqo9ERmDW^5fzVqW_IHUwetr^J&pM4kEI?}x7xE_5bgoxz zrO|lGBN$35h-&3~30RzZU+f*nJX~|BYwj;5>NvIAc zAdI1PsI{#PxbAt5IR814|4!q1fU^^|l9T3ue=)Ql0PbS8v+13|2k@~I&<2G(ubdF4 zIj3iCQL_Xl=Ss-Yh?y>herHXMemI-KTHAHnB5x2iHX;S^XJdUX#>l5&1O8IdVx{9O zcj(8vks(*DP!^z2>}Bcf{vrpl_*ef)`d$_ssdS@3kb|TN?(kI9t?Y=dxX zvBuY_UM0IV9{Dqfp0vXSkx%sCRR(c^fgC(+bVp?l&`_n&4ui8CMD-%i657t;=M#BI z_f(fy+p-J;Zz)f^Tx`~(kGs;;Y2d`=e0TASQjcoQ#?N0Tplt9wJ#ch z@nTjSC=Z?x|ImwFpUkrGgmqy2moWV6opJ9aimC_l_3yk_Ff6+eqGRv-HM7ACr$&CR z3z0UnLC1=&vo9w)PT^L+Cl?AUCYWHpi9hAPFV|@!CpJ?a_GP+kJG4Ddq}}-7G=O0E zT%Szm;inurZPs`^A4m0Vx62KZe0Z1=>s`+v38k;AQ8G4$s^ zc#g6>z*GW|-2RnYa`R(@0bIv@0*z~S2+0BhuM;A@c8LZhjNx?1#t*(&j9hqG_6urA z!mRS4Qq3WFj0HNJbYUNa6EuM{nRNxCp{Qy#OE$~b?jAfp73^q?86=)6 zt1mMMXnypu8gJknJ&jNlh1pspcy{a{(<7vU;xiUpygb!~?2VL}SaN}8fujA81kY&Y zBE`|bJZB@6*6|C&ucN1_oZUg4!}p84sVaB?j-ac+G$&y<+F;M)slARX!`>rn|NW`E zBXcJGBs2EYyVG@7l?s<2c;sQ_mq)K7X?;9D6Hm`J{`1}qWc+HImZM;fTEnyo?snF( z%i_X_y=P|xDAI3+`|B%tneJCc&zIx)?D|c^uU1voOSR`-$%&*m9m0Z@m1$nM zlWCAk-zecQEoaDg)lGJ)mokcb77A5}atxB;?Xw<;&QbQ{v2E05%DK@p0sQ7_x@;NA zU*Pi=qK|&6S4*dRZn=^Sp9k}i%Th+=c+b%+tr<@ZRO8HxNnrOy-sNk91#q6K;rV_I z2-6)Iu`yQ^@!#>-6BNq}&$B0dNr%!N0z93&NxetdSoS#K)8bHlb#9Z?K&O`?R3FC?X0sRb6cfIY!cAE27XW|la~wf7jd;yt@tz(kpOzo! zqx#jQzGNVpzcbz#@^rsF31)2xxqC6W_b+oL-8ltbcm@d;3w5dNc$_tyWVnx(DR4t^h39;#I*S|%kN&BCoEglP@t$vp(3 zxm6DuS<7uZs1S{-{PIzpJ;@aDy6n#-fNk$MpX@s*iEHAuy1ULB64Jc1XE$E&?7%*K ze6Q~thE)-K%`g983or?VXcYtHSQ!vRy@dpBE~y%j*Y{ZcyX>2O?cB0c|Hxahj1{8v z7ksL(H5t+0S-G%K{Q89<5}|%z5^BJ3x#3=GD3v!9;vF^I-7iKbx|OoS9kS~yQ2+ck z_li}Ujf+WSdwMiPkojHJ4b)Ujm z8Q zD#pB!o8Gm#MI_|tDp(-$IBascnI1fC(W-F?+f&TZ@TqA}o*(63ciduARQm{ml%LXD z@6aV-XB+3}!i>tm$iz~(3&hX3(xu6>aT?WOl4yM1{5&PM1W`xV_L&lfBrJy{@dUj5 zaWzC$S_yAV?Z{^cQsoy16xv!QU89CQi61U~C35s`pS#Gb7g~2*4y_oZ)|T4hY&Q4imWqT_QA8J=lB#x#yMl4+-Hr6W|U0E2^Qy$n4Z$~;^->Re%c@J6MMSxPThOE&UCEde;TrAJDE6NQj{Jr zX@EfqOGs|t79L*;n(G1G@4j!mOtXW6>8Qe(hM>&C=laRviwnD{j{bsj*fY2_brslE zV{DU4{=xcZX-{{&q^OUGEU~ThI*UiTjL{~L8VrLu{hS^PaLN2^cTL1k zY`JA|hHhZwwexuW#ZX{E;AN^T8LAa*BpBIR+O&Pz5UFVOzwRJ2ju(dGJ}-z;Vw>0C zA((?vD;ZB%LK&1uKl4S=T>RYXgouuuaOJbN9m38rG2yXd6QuL3D?tzJu7-b4`TV+} z`3L8+CNVr?U?(}T-RMT1eewiYwf34YS)Y*{$?=ioI~Mdojgx#b*->`Yzv028JrvYT zFB1D}-$0=IzQQsX_is?mwK4FzYKQoEX~2|&_ng;5Sp9|s-4&}_fN4i*{V=EBVmXEL zIMJN)WD4ym3s;r_Iz!Q4(qH9k zHS|hFP=QZ3F%oo$B^1o15&00Ux*s%3=yxu#KVU*8NS{$?s1Lq_C25taKR3h%d;tX} zB+bE9VqJuAIh4&IL^cvy{gl3z`$?i65i61+bt`{LtvVCoIHDwuXNKb*cVd1?F}R*T zV~PjX87{rcfR{Vw*It4w4DaJAfitgmcZ7RBARDvz4hsnI*1pTWea!^~CeqlJx`6xv zf9tp|3fuA5{)6|^ABIGColVYVDh+IA#&CYJIue5NTw6b@ODx7y*?UBKKwuj}4kbg= zla-A(mnmtJ8Fg*#w2HN918-4nU~_`$ExSfrj8DpqkvnDm$jeUGOJC6`Ib$13@*qUG z&1&;>B-eHbm_m(*pX?&Y{ViDE&u@>MJn3;-GZ>&65KQDj<+nD<*u@8?)nyy?2vXD_ zAPC^)%A8i&9t4q7wl~Gv=iItdY0W(hK?_C1nv_QRa-$IQqxJ@QYS%KeO26|PwoAi` z;b1yeHw8&8R(84Mr&kp)%FVbvm#c?fv2D0is6P-$F~87y(Ylsl;*VJjzibH*Xkh)w zL|~z2R8ymyTnRNkG>T5Onp`2J__KHU_)siUSPgFNih~=A&A=`H!}|QHoUQV2^Woh0 zrpB9VcW25Ney2XmQ;+5DiYszPPB86i+jF}Upn&&5s*`OdrH{TUg{AGbC~Ybj)F)+n zw=~bYl!CbHlEqkH2F$L|#n4_~f^^&6>@QZG$JrMa`?2+{J{tXI_?%%bZ#p;7TWXp~ zV;%D6^W#85zTUZJb&eDHd>6gQy)QT8r{$u_UWdlkLE-b8<^XQXfRlKSF%SOqG={`_ z)F9(JNO!aXHBJ|v1DB*H?eu+D<+m+$oRr@IID+=G;J|!I>o4^X|Aw+AMue~3l#pRn z(=d|aOUWuld@_nPFM!#_uh=#8JgJb~kj*)9BMveVU(3NX!0a;;hfc)K0Ww6{U?`#% zT43<~PMbAT6M9ox;R1!fN8^A4PWGuh>DXb&Ul|3d2S3F?VI5gA(53~NCu0&M)4pb5 zFROTXztxi62}mzr8`c-`3naIvG%B9r^&ey9N$>aHQb~VMruvhhJpSZl=DxRB$TKWR zD?@yf%=>l`ZpKH(g+(&JI&bT9jjs*L5?!}M%ROA{Z;MFYdxQRrwG5rqxxRiq(X^~d zIlG8Tn|i9>>C*JNt)AA~a52z-`vLtw^Vt~IZJk()oh(%?6T!RIwb2U;-69;8%7$W- z!^fK??(&TqzGtf`$`FVc9sFSRs3vmT7RxsXOLJ@Xm0I@2@-|Rfcz`sYkTu$=y?quJ zD7A%rGKV&iQ}s=y-lwDFxPLFRkUq0#a;JIGd5BC%oi6fv+bLFnAq^)%H0V=z^T zfv^32(5!S{&R#c&VeNKLK;_9YeYn>~=@!W%H4f{Ely}Xe?vvEZy$YSBWd}PxqEX48 zUj;Lpc3KkaAvL%}^hJ+RDZ&%}$P->7;2#&Kgk3#EgbYf47v&zn^ zKKG2L$~F9_7J#f9Ph`xU}pP(bi407#XJ! z>DIV}w!T~nAOMc1f)K*Z$N1GHNj@o){&nE|@(8C0%q8-*RDkLNzE}OrLFU2H_c5}M za(S#dlJnGiE&5#=1PA@*mBd+t=8U}2d^Z8&*Ph^385|i64U@c+RuV$ zxhauhpgJyK2KV;?H%XLTLNzx|?lTGfKtcrF+KguU5x|EIyn7SW-H0Nuw)^QLqKBXd zLS+?64Ze;MB9btB-?wd8e?)`5Z}Ny^d`=qeG8ny&r0)W-+ew<^Zas+P=X}xym6wwv zpUkNkLFcHg_mS#`zCUY&q*KLD0q93nCjLup*jR47_d?eGNFZp2#scE z>$x}N;|&n5^%ph0lSU1W9}+#V`o&nhqg9UDix{ z3z_U^qb+z#1!O`LH{{F@+(Agila^h=2b-R)a7S`OU#l%HOwWmV-mgC9~elLiX5 zK6cKpqh<&WR7e6$&8VBgw6c1#)dje0@Vnce#sIxT^=ko=-3Lq*)=|T%yO(YLqlylP zw&D1u38Uu{ktw8-IePX}$GOkK2V{7KQsDBp0`_y|Y}eb<2@sTA4!0B0`I%}!fDQ}w zZ^&Fac$to8u#7(`J;lHutWE6TPZGh3ikp0h!I2=-ncu0MVK`xe@5Ji4*Vl_2!NEm5 z*Xb;~MuQLY!buA@TX|YGVX|-P8-XVX(I~+Io&rsMaF%=>EuJEDP%U&2B4mcZ2AWSQwc5tpZ5FDC(Q~!8&@|ELaKokqQ5n)pz^xwb{mnLJkAu zFv$B=NBL-jt4iUk-_ibFNV5oFk$#d8I|f_5L57gmh@7j{+9b?|hjBARX;d+_oky~^ z@Mua_?O*5%5X7Oa_H&8OWhYv&tOs_&?zOy-HE6g%Ue>@Th_XySz0)BFSps4OY$4gU zgA7+auu+rqPe;%YA98V0x3%YM-j$k$Yg$6_O5-6=iUTG}j}8baaZ(=>(eB}|gw#!Kf+#!XSKLcFWDWoBcZXzuo;+wfh-mS0C8}BE# zcTvQz%^fGY=kSHXOrpKN7!u8J+}@mrls>`ghh~0rO$=nzj*`rBb4$zc`15iYHtSEx ztY6FunL*dHU;zQH!ol7^1@j$b|901cae&9i{whsx_u$qkwgvM;bJUYqkmP|689%kh z)n*#S)ETn~fbfcy>pMq+&6Ioft!-VOx50%M%3+i&AEFUdP zj%JR1kYaGT$t2{oxE=b5H*^s+^dOJ(M^Rsj8WumN`Fp?e*fTmO zKlxeI>>Y0jp^;EFECWd*3&<(MfLPZr?z5D3j5aXH24n0mt$)|~!0}jy`s$bkbv8p@ zW8*@Lk?#wleUJr~(O=L326;KTev7T;aMZ;3Ht4$y+O;<(KQHbq;lt4{e+XFN!qOT} zu7;rJNhWo{ze8{|j3H&0i}m6ruDVL|B&cira)m1zjE$GN`W>&Fr<(+AcLtLRk;aoi zS&iW|v3oCJ9_skPfH61~3GT$czbTEmn9{C7-@lljRPx;_J znJ@$%U6hlf+gHh;n0Iu30TP-TvY%`hM_TWv^ygc!UZ^v~i(}HxUrn%ncboNZM0YPA zwaxF|MD{x5mObFOr%0F{dysv{^e#u#my)`!OxoT%J^L7BR)<)qw6#~PGC4fQXBK{# z9e8VCp?s#TicR}{1ir)sA{%8H8@IXk&%nkDghQ6uvf3zxz@%=)ir8odQ2U$f;C z6f?nQM!s(7XAk43C9!}mH!Be{$_b*ZGbl~WGd!U7pxjLA&%Ov}1npO|>-r%X1J{ML zS#Z|1nD3n7RE|JLS3DGb6Z-QKG1|)oMVz1WRpIM?q-1N zo3Vb{T?bTk;=Y7X4=e8rEx%{6oD^1k(pMyV7!ns?pSSiqZpW>y*^?Nznk zT!K5=fn-l;#6KRA8deGEWx`I##kp#>&t{If98x`wAelmHV7LD<|FZ1t@v`LropL6# zC|4no@7~J@VvlGWWFhKd`E6##vBmuFYw`&`-fPh42nJ`0r-bycU;pPbW4IsXs3u-i zjv@;Ge)NC-)(v8}!q@*9`1i}?J}%;p#|Kij9RHo~zuyd9ZBG1utt6iySs4^FI8A?Q z0i?yYt-V**z*XhC8Er|5=C217T101b`NK$Le+lx}bTVfo+TYKT$ikLN$0?4~0_ zxpCivJu}m+Wd!AbjgHo8Y*UO7Ex>vvyF+yP5Ij!rxIHzQ`PExiI{-5ls~f@2QliWU zzTOd8_g?n&FV=U0)zC&DX9Q>UE{PHUS$=T`b-*~}cKB2^LHp+^;1T9Ih4YS3F#OlM z8=M+^JoOL}EI zUbK_ZIjHeo4oe|(rqr4{$Q0i|XUn8*ahSxaesf}&94oIlxC?|+d|j}>3@ZIw6rt@gFsq0#H?6<4_4K>mlOZQzBKH_9L#I_@9ojXML!X~C@@ zKLv?>I+p?~y7;`|eurSQg)}Z(Q)x6|&ROf_7j#6HhO(4vH{djgKkq=B-hW5m^vF`_ zU9TiIt}8-FbK%E!Rb$vB?ro`A9R7Vk#QU{PCPD~>(JSt04!BaYc5!XB5hVycP98Km z5LwWal}>uQqn)YqmZT->yJf`RcaTubCe-)nLxbE$zL zmN5e6$DYl9T) zpu6Vy#Gl1{Whs*P!tyM-0(?KJ#8w3koiiv6e{VABAy){*TOmoH@nSVydwGXd-+`iN z=sYc@xwL;3{+`(0k00d)DKmV#n7}yJI&bUSMXJiZ$-u(13#vJ3o9#1gds-3T7EubV zeQ=wBGk3~Ljj1pZ-)#n9T`KVg+Apmj=VU3~^Br=3n+D2BU>t!yem>YGoU zSj!vI*FePH;ZAjRDq1z`@~o&GFV0$MvF^oRobLsk#&|ZUYOl;<8{O=4e5Rq=rg^#U z;0$i!YEIlFelLhrnhow0Ho1xHm)cohte2Nxs4SGbAwtx*U7ZW5D@7BUL1(@~0gqyY z0rr{pGyn-Zoldu`Sw~bp@8G>poCO74KUynr_zLNnjfkS zgjdq7Hlrw_N}b>MXcOq_e?FQ&l4xmLe&fu8ob+| zE*D0axEEV-$u+5MqdcyKTrGQ?E*H1hiW*Z!VCE80#QTyChBx>ZT%bA2Sht76k0nWx zcf(sLU4DbV?|h0q{mxOh z5Owy5)2KF`?OlvGxQw*z9f7IQph|UoeZhI2hYP1f(7(lh$@lX~^ED9rJ0+IaE0^xU zPDYqxf#(C`C&vCb-}{QMq*r$Iv^gmegNkfXJPe=J@LVVF(76`p{Y7Vw&el3%%0i=d z3@l-_?#};u)aU43J;hlLbEZ8L zEo$FVc`5~J^Ini!kXes6BuiUAzQGi{(lB3iVS?A(-%b|EaHE$0hUuwJlv3giPLV!NI5&BC+464TC#|KrbZfc`AIM_aD49JF3VPQr3Q(h{4%?; z9Y^r&ve(KALRNvV*@*D2P(3H*X)_U0wU|~rc#=KzH_GwO^RlA87&^;+y@IY)PC|pJ z+q@U{E8M<*H4))0Kq?SfAPZTqN?tV*kuI-V)*VDElS#uLwBqoXD#19gGUjq1{#b6| zjiEii9v<-W=(blfD8aiD!RU3&LFci;V)f+3ji}yj`zAq{;Yt2>J%;--D7Y5s-g0d> z^MsgR3Gwdz>l+TX?uJ8N{0rwfb$72jgQcdTIZBdu1tMFKa=)j-+T&i9A9KU+krC>32#Z$CF0A=?)KG;5SZ&uqLyh=jC%<&I~?hPx`kwl^B!s@Xiyxg0=FcHB_94-)etd!Q|% z2>YFQpYpJddoVtFOh1ix_#Mm)6?xVtxO)3rm0dV0ZX7+lveq|{biuHj;750rgOTeC zkepmbJ4NhNHmXkg6L0Hz3^@(grd{qq($99WZ7)z_l1qn_SXAT$vnG+g@6)?QV;tVy zRpPMvS>$^G;JA`P@L$=fs5F99%Vx6YPJg19P^<-+lzlewy}f(6H(IKFoZXQV zC|pk(G_Ql3i$deOyTICI)cn;@@GfBt!NeqmPC{WE*K~mG(7WA@-DEs>8>Ue0!;2KJ zbpL*8&uuBK-DFO&htk<@NIut}@GzESIkc_L1(c66PvW=%j!AT(6#f{iL7#xV~i)7*qguxz~kkR<@yo_OQ|9y>s-dWS~e62X67B-N};?;1etHG^*i>>0a!;y&jTNmb6o`y^7 zwM~1*zDC$(+nZ9m&Rpbjr13?iUeG~XSHR;WNA3gby{ymnyfeMcSN{7N!KmY_{kL(8 zRoDAAP~#iplRNlTrw#S$H)}I`P3k}%=gRGDr_htt8#``pG30}yn=(D4Jz=N=G8w-U z{u+sI9oQkyz7e)zg&TU%likAMccWOL=Yn&fTH^%|3v{v^vnV!fA zu$L)$t-dHP$d6ST)z6r8SW=@mFXY_&o;1 z#-ndkY^i?ego!j$dmB!sZ^a-QUK*ztv&VB#2q36{b1$#$cw_oH1%fV5i@(Z%Uh0SV zx9VVs>6!;TquVn6-!-wM^@4HWq&7tL)m~U2BkA*};o^HI{S}YsdG1g}&&`?UZ+xXk zi{b2?-spR(@BZtPd|wjgLiZUS4u2_Ys@-ihO*$J_YV_t*NQ)77AbH}od8RH?rOE}XN6SAG!2D7Ewak>3gd;5TsLfW2U7-)qFdCZ zp%oLe-5c?J_ldyjEw?1?WhWk|ToL;0Ga@|tx}Ke3(``hZk}7!e@>yTRW1`(MCarAV zg#E|q%9sxErpO8ey&Y$W9m4^fLu1UG>j6k2YOH}Sr&sW%myf%AA>Uv(g zYqUC~<;b~r1u}8K9W-hnH^%{*RDZL(i_kreL ztItw>xidLLF=h}Hi~XuH&aP0wVgLeai4pyJf6E! z^R66~S*Mo{vKWBoIPk*&5}d=s+-v?68Nbc2t5pycdv+2nsrZ zx@z+JOy7)jGSV23>8cPVGE2Y%s+v72>>Y)plm2TVXH5TD%p>_TTbv~R>KsbuGL~29 z%SzHKqesFBSP2v8#z(aRC>)8{%cx;C#u}`_Mvzw>bk!eKmP5rKBO zs2E1}?~=C(_;^$Qk9-nVPyE)zal6}1QqiaH(^N9g8PQ_ z{9jddJ29aJ*COJq?*T8ZE;3b&Q7fjB?W(WQGqgsRQ+6SwLiofKQL?m`KL)|QTyE9M zD~o~~4u=@mB8=bLLS*!)s(!@JUrlB*9H+qa(7a3G7_S;qhYk-Z-CQgivfo+wJiP3q zR+FPNq!8z2q-fTmn*k|v0b|RWV_@QG?7a5#KD|+lMPqDlu}7-6s9wE7Qj1wNmr9Dv$0^pq$fvt zd1EnNfl-;|W2EJy^D3L19+WYymn>SEv0tc*KRIn`Pw%rmH8x;5uIHifnw(N`%Enp3 zcZ|)9AmSb_5bk1XIxd&qkQJSi(om-$lsBH5QCR&=-!imxACwY5nbZYA`{SbLAGZmU z|5ub|0H#I`)YbnCez;3a5kXECGg(D@k(7VCSpN2+Kz+Dgi2mQYUjBZAff}j-w2K-h zHf7?!Ju?4#F{VZ(`hb#OnX&7I z1(XNp{(W!P2n38u%5TR*rv)%v*)MF*M5Ht_i;+i*H`fEVNmc3 zB_*uyLm%<3-eObNE2wV#A`3IfQ%W)L+nf2nv`Rt>v5l$z(Zc33(zP9OyQ5;;ke2zG zrV*`Nt3j&MlY>9LBkZu>Tx|ADm1?_qoqKZ#yW^tK?3IhZie#vfN-je1!Ftc3{>H~epf~uFjG+#3L zT}!BI=eolvy}AYiW7TOjgr|D~Y|*cOW|1rg_0gy7GY|+=a>rbO`Ev>CIcbZvXW&AS z0HRqo zVI(P#AQSP0fFc`mod>tEKV_M#CEAAi<~%Mu4XWm254>3aePqp{aNkW$w?Pc#HmbeO zVhw+?P?hDfD2+%3ICE)ZR2?fvoMf%8YdqxI`iFhHo!~+yTSL`#3Hd!Rd_hSdg|z#K z$dmvY0NuY>h7Z!SA(8JO?cW>KttunLXGfm+Hkr;1dC8RcuzK?F@L(eQm7N{)=;$b! z*OlP|O7b|hXp*t{l>)@>Uwcia|NFT;Nug7HOz8_F+8$62Boi~UzXFw$JB6BTf`p@# z6#S_RZ{fgxjePk(1aho6NUZMG zm<<2(wGZhiNdj`6pk>!e{BwFBo#4LX+z>aINdBKA`CBu6^#^IL|DQ}(w)FeT zre=O7;m>i-@gH7#`AAA`=T6Wvtm~Zg$x&{ob;7pc7*NBq&FFDB0${}H;&?GjP8cQ3 zuQDzYAd|eU6Lq3z^ZTIr^5PTE77qYM{0mE9poArFKz(N2On5}#f5cC7`zM`C`0~6O z0>|sCXyuKHSi#Tt1AMi#!OC-MN>TGtf-TQHw*Y$%s;%(1{Jbi3?yvGgvp$ZYjihCY zpHIXJ#hWon^C-*dmRe5|xQ;P>V-|h~#atr0e6iF<-KW!yOy84cHWMataAlVj&bjJs zh`MStV0K7Udg%Ym)KpAR*~uvs!(KgVak8NKIZzG8@tV&Lt??*P`=`Qf@48wPxBKT1 zY-a7&3R}vNu+klhr5O9|ne+?9l54r8n-jIc3vn)p448VLRII3?3525_I z_8%($`fW2*-5~H>k6JR{#fcX3WND*knxXu7%S{&d1;{8s`5NAJg69tN6mtjknA3@> zPa-p`tjBFtFeDXu^s8vYMViF>PJE=?8y>36sZ&PmPv!v_uL_-$TXz0p=(Uz_P~o4a zNwpL7$wLbDi}J`iaHxc@T(X`Ec5C_8@Vm;av|!G*5iU`_jv2=4=Y?#sDO?A@B6sJE zg@Tip#EO2w0Ew`H#~ufFj0p3@x(dS%JZ6$XyTXI{x8+vMp+oWl{zXXFX_tI7fWna+ zluLZHCnrIgI`!GNm`aFnr}}N96Xx)i2&DP_u(?6IONGzB1SJzp3Xu-HsHwlp3uUiW z#yhIDZgaQFQILG;OmehyAK5JRpzc(^`;U#fi3SIv8LPu5RUGVSy!X#WK1rp* zd@mS$(-C@gV#)7+9VHlf4N1wQMuSmin(zBgmC-R&yc)utfM`cpS+FF*oYs!28QfPF z+?Yu=6jQfYsvQSIOTf`#n3Qgh#X7Ai-fKwC8+=G-ZnZOi6%+l}M0R9@-BD+iOd_QRctiY%`I~k- zA}@@iC;{j;yQ{k|j!ELjLcirwBJP31H`U3tpRqwO_z1!aTm7h9Bu^m;YXIEdy zPY0x~aqUv)#uk+;6Tyc!)PCRS)!{BM-D{Xoko_JAYQWTis)GY-np&CceZI-3boM*9Vy= zlbnjLK?GejZN3bnR5($>XgX;h2RV+5=3t8r#$X_IunA`(A49{)o}yu<5az?Ze! z7#HhtQy!laB+IxG7CnpJZ)F+**JYFc`qz@&mK6v>tV|jd(q$f>Mx@5-Cf~;}g4K`n zn$LnRAF$PSug~PM3C7^#1TOM9k)|#VxHq)kfP7><$Xs(KtaO_7C&;UbLQ=5khOKx0 z;fs=lup@^Lrnx6R>eZ}4dFjv7vaQY&*tjbr-g|f};J5@_v;(gP5;a?&WmR?s8snJi zPNnET-j+v+*#3h*Y~``XBD}PDV+T&-K2Ls?hm%qZ{5ziO3=5g7{Z6z}O~URijXj{; z^XWAnyH=i!Nc&v5p1&})H{Ph+hEt^eDq8L3UZM@UI{OApJA*(c0noAN5C5bWwlc9C)xin$w%=dpEIQ&<;J=$tJ zQjiY|laLy*>qN;^TiSB7>c zH+wqBVG6;>#hrVc!}_ng`3?X>v8^ylQUMOX1{n~T*7-AhhGaH*hgJioh)a^jF6f^9|7` zQj%WqnQ~}elzh%u!YlQW_20Y<);&uYFr-grJ1`|S>LWD(od%NvCRohrB<4zs#qeAD zzw+1q)E3}8|54wxKIy(dPmAXw>n)MK|JK$^gU~RI;Ikmy@4GN88ESr!x6v!1jsK0v z^HX1f{x_joFKCz6s1Skj5t;k6F7!S~Yo|WZ(41zotOI z{3Fzh`y&p|TInoj>ac*I0;J&4Tg{$FNjqKvo$u!gC0QcKtnzxV;(%-JI{!MsHIG{Mi7__r&{QJAdC7i~;1iVQZq)**~KZ>qyld z2&Fy@fkmqis3zaEbey}sn8}oMCy*Tmb@-x?-t&bYv@&bmaeX_d5PRaXW87A@b{Z(|&hE9g7BB{!9dPT9$I$ z*`%5?D8LKumh=zxX=l$#D7c5Uer*J5469x#KyGg3_3%QxfToRnQ& zDHFTFE~5BQJ%c_-oYLn|6&gSCWV@9D&*LSZ{3oXbkti0YaW9ko2-DhLTf&PT=fmn7 z^j7nd+|41{*c^e`y@yv?z&Cd==@eOlD(n6he^$1%g@Q3q58XP_a-xD3!&!M&H`ien zNpp<4wStQZJt(SHdoG#Yy~MDv!D2cs?KypXhDs80fHxvYo^6A=i@8@ZEZ85G4KYv& zO>`z1o)mN>vBjMU;Q86okJA8%7Ev2yl;uiTBRz&B`W~+2jf$^v#@ic>>ea?b0Cewn zRVh|UAqd#+1?#GRX#p^SsNM>Sdav{ue_BN843#7JA^p#11c6RV%JO5Fxc_9(}=|@m6D2Oov96hzJvgD+*X$sCHd>JA656b>Ac?X zeT0N;JI{#Rb+mi~r8})C9RIpuc4NwJ9xE6C7f3g!O$l7PyP`*CJ9H*Qh5-dla8ME( z;7`#MiFHTdnPHSL62jcrQ;?tWx}C^9!=fOLjFR% z(JOm9e*p23v$az29NAQKhr-FFxL1eqmA3QI^3h`BnRt(aTpe3 z?<8KaqO2Xxn@Hc!mqd|`>4iKRhFGm}AA(on{|vpmL?WS`dIor2!h;L&-Ja^g*a!`O^nOW_%UjgCkSnX1K~+_7+^XZhISkT`6wu zU!07r{GX0Oro$ul&>4vabDj@xt!blGXCf7d_8cp}Xs!Uhn1B?^sgxFwX;n}*@nm2T zW^Z7!#gy8iNin5(#V-HPYJX_$x-9F>26xB}v0&)wT-lc1D`CrcZ*AmBiV5Vu?yEY( zP`QJ3v}{!_P&OUP`}FnK9L_B>i0{9Y%sCZbe8k{@+@*AeGoo_F*K8QOwspz6c?C0~ zjDJxDITQ{jM1?sM9i4gIm^(BXZ_{6~fKULY2%PHF3yPBtLFqp2XvI~N7*ZRfcZZ|TFxt^5@Gxzio2;yrYFCWP5;)&fb8g;ac70OqGC$*%j!`B&|e#`O~&0SEL ztB*C~^aR9P+#ZruOw}^&cBdnP}*#Yu_9t&O$|TtLtniJ!{+^k?w|X3gcA5HboKk59 zGk}ny^~8B&TF=2@>#V>g{g)H|KDv`R#?a{7ur|KaqHNrk zzC46&n*H_M$({)-mNAo*xzm`%v<}|CVvWlWhv~nsqr{tS!=~-bi(00K{tT8=ej3Rv znxIrv=xnIX0|Q&EQ`hviYNu7|if_c|-qZCI%0?>bjR%!|*0Z2VvnI^8OfVXmd~D~H z4Jc>)EM4~tXY_gQ6yQKC|AA7?f_ke*Bch)I5>?ByeiIy$k}|djyWu6I(lm?sg~BgK z0Zr18XsKPS3q4ee=Oe=W75rD<|6DmW(cgGaRsKvyLi^OrW1#BoHbbjq-PD5xB|SE~ z_y-Ha)R134H&;v0dc3yLWLjjr2@6Z|B4B!Y8guZ8*sf7{q`oH z!2LJd`d5nm|C4~SS*mGd@0aOBWF2J6`Us1y_bGPA-ihc;g1$cuv;qtCqsaIwD_*;& zh@)p?h?X%J*E@ZYSs7l&sb>aB#rot6`44icBX7|mA3wGV&TPWLyStOQI9>eS$NRh~ zI1@frm{&VKc*$vh!c#<&?%@J>UwBU}4JKH}Nv95BdSfyvA3s!jeq31I>|SjboHbMs z=OI)S36CC6-{gOiqE{BqU+Y4^>(36$%mqAysCh?)h6LyG)Kcp*hpeoE%YYU$oL~KC z7^vyA>;Xe|f-pYO&oIwh`a^VDC=adfL*6faRQa_2ddZ|O>?ru!0p%E8UY9kQzroek z9PC+q=9#M{t+3At>r3CFDKe`8Ty})77Vey&36E{M=8@5a&V2;i{y88_YPyijiUIOq z0k>_Upkf*(6%ReN9l4`|D*gzFxZZ|CBR@M?N!Wj)9%I0z zGeYtCDla^s)8=#@`149~;Px|1Wy(9thM*d#mgVmCCWb6<)GT!7bYVEN_Jprl(A-JA zgL5x_;oaErp;?ZJ0HS;B&nj)D` z9=obQQ7xIE>*0y`ex*Ga+2NcyNcTe#X$HWDRXY7_O{R`L6i@B>3UP?DUy*ehD<)krRomrke>@q>roLhV}IPW+*5eM%l0b5aR z)-U$ag0?mRm&id{LwJQV;pkI)V{N|YSot)e+BDs&rg_Zi@dAB z+yB7smNZY55$!qNz=tH`tVdUX9a;pZ9p*F7x-D_;b1tq^XR_ycTUOe}B{G=cH^ii3 zITOWAURI);V2++#QS`Ntp-uVm^LnfK@@9t?WFG6h9A~8yJg;`u#1N}Y1mD_;_6RkWf;}7g}jj_k$9BT=bo`C*4(EXN>E~Ru^(m+Ka z>%G-KBl-;p_xBF6(g=Hb1ozh_y9>lW#Z>6=sgqUHc+ns%S~`FVLibdWE4XLco}V(Ks7t)SC@nSl zaS3WA6W~grGJywINNQ(UKL(@-!Q|X>7_O>9&`xKFpV61G6M}bd>aFR3Pp#QT%t|a* zo%lE>_%U7#v7th4H)3L)xYgLYuw9*wqc6{&w|qqLC%Iyf8-?hL%2$Kp;E~iMHy=Fv zAYQQ-bowIp{N#Bu$}$}xb|ek5iYzmPtuvp5t2I-0{1rZ`m|6o9=7MCcvpZ5O~g~N;&2l2Zon53T`hOKSyR1UqDJ%()Z zMSiK(um6IVB=a6HtR&mKx%U=0OA8(DB~CCn;koNujY>|=6v>ykkpK1q2-2p3+p^-L z#VVbO4PuXV&4j}WkqrG5uywSg1jWv9EK6XbU-?tjKC99aq%F`J>k!|Q0ZBD zL!%i9i6e1(u_9!azdD{A-coR!UuYY6?%0k91Ibl=hvGz+9)v-_@t0~~UP(2gxV_@B zbM6Uc2+wZQUJ-7o58*mU1#jfZmxOuY1sQ7Mtc`qeG?eP_2XJ1LyNaWIEq=~a{{oUa zD(@Y_VPMmt3hCue!>3_RrF_Eiy2-svDJIV{;f7wJ^D>RFFos~(6`|3Y*VLtsdZeG^S;HPn4Tcpw;K^v%@5V@Dc;-j2H15)58N{p$T#ql&3K-F-Bvs&M{5j9 zYx_knt}S2cBdRJK+iTj5oYf07Hf?&-_$@~o@o$4{F>6_7==!*T|*zjf8)VmMS~0JvT1=-+p!a@+b; zzBGHGcD|bah_H8rJ53^dPOvn?A3WFltiX^u22P7t&*u5m_BZgFN-g_Fm@k9`=cJWd z&@z;sgTpDWKmNUZl2X5$?z$5F@ZHuio{;*w){VGPvu$n}FO5!DxoYLTxbk~H&r4T_ zTs+($MdSJ>tf)=<<9}+a{}IIxCaQfOcWvileFIeo!8!&cZy!&nO}t%w9vqa#cPXlU zvuql9TQvSiBO1ZdomRTvVi?@Wv4XX@q>}d(5P6k-%W_F~I{_1VMf<#a+IZ1&n}#{T z2<7O{S|?wFG$pKpxBwQZ#A$8ZriJ?HSMRMR4FMm=k5k{z_9#TkvA~B}V9iHr^)bQ|bLPxj!9LlxUpz5!8rgR9x(TWkL-B8|(ni6=>!U{$1sRQnNrPEJ zSaSF~D%SZ}s5)z(!on3J>OPqA(D6uh0}WW#%Ao@{IA0I`JZsFRS};J~9ojn$-@%Wp z+Yk?&)8{mbuh79-g=&;tV>T(h^jK?}Ag+4hD6PfLT?2-gaXg;j&#QVb`E8OTlT%*t zc`9NN<19SV{#mhQDS=3~9yg>AK7WcKG0(EXspck_YHBZGHgEVQgp;7 zy=1+<^GQ$HTSa(fUk2T6TEJ%VH0*u#GXTwjQOg8DhN>FkO1|%5*tOLvPmZL1XxKge zTgn#u(zUGEcY}2%&A1^=lw+IB@Lt&;D^xMNyJfbBb(PG5v5U>RP#O>UW=r6WlTTy} zDB+CT%tTi@mJqHLm_3gc{lvAp7iAP36v`;w-cz$EK4r;L3F4h|Tl-Cq){|xtO=H>3 z8Ci3-(Rax2*jKnVPSd|ah;iSTvE}E)wD}`neiVIVMr+KgqFHZC4E11)l$g+ zstKRpz$Zd;rj0dXTiy8aKry@TaH0pEEOA>U(dL9e;{~O&kRJPUw-uTsZVGv?AaqE{ zM!P-#8vj&kzteAs7X(MCrjRhxqnY5#^*m>asObrpB)GfbKoj36qx7aun z4Z+J0Sq}MJT1FwVN?7vGeFOc7tuvOCLe_v&R4x1Og7IU!M2zehr}pE-b(INZEicVg zj(R3@EDyC*!A8^yZU2@O{&Y1+r>!GEDa)%t#o=!HmaBM^2S#I}B1)Lwj?=$Kd? z#Qj@-K`LtMr$%0oh9ku(_F8eidu3ti%&BLua5Dk*1>2&<()b9e9s}3WzPosH+Ft5; z?B?sEh09qXL046`DEOrBT%e*2uAwSo@qlU$Xa)HtDTHKI?)^N6Mb@g#&x~o`yCsD5 ztlj!`>tB~lBeBg=6{Cj0)!?8O^>dRC{q)8_EcPzfPe&sDn9F5H^NM9%c^<7gtUNEA zKBREbRsQesCWSse&}ei6&=m3^bnvfd`IIxpWjbLQvfh4kVT(tIKdsYXMmQ}-OtEf% zD-*!j_8C$3Y$&3+pNURrQ28F3mQ}z};n5#Y`XIMNC6oKi<5;DP_Ik$V#v98jhPAOZ zitge#**_E3+5o4C=R2>CR&^}p$=1mmJfAOw1x zdDz0#gIKNm{6}^xZC|e^^lP{#>~u}8kaD0a)>3h?N!OFA%X1XZvuXoaoC2#j-vT1{ zFo(ZHX5J?2NTFS;YmftXM-!^K(Z z{=Y1aB$Utw=9UBS9B)jAD$5s1;?afspxO^aNQdtBWt-k!xI2sO>NNvm!K+cb{yJ>4 z>0XXhLUYZS3Z@O@*;_Bg-6l&%l}QWE(}wk`ZA?`m>DQUc8t)F8472mC6k3pPWiZ80 z1sTqF7#2p-KkMcNe|#kx&7&+%R`!b-FP)591WF7e7TfpNXSLwa^2n{t_hmgMZ@km& z5Di4RC$+qCF=KgU)jJM~*~c@|eanO^HDELoV9F+%C6enq#|ZaG&kl@tX_#F80aT!) zl}&lu`qN1X(B~z=tJpP8p}#2L*QY=9G|Y?3b>v&kHEe&^YSe9hXW))zWV2?lbY3o| z6nk;3l9vVBCNE)SO(vu#NkJwQZtPf?+WBP5wyG!2A$t2q-Mt~BBlB{~e=2~Uol-|# z0)@MEns%cD5$FDbQv0kvq&;LAfL?%WseC7FXSUs28^si=NgI1;HR z(deY1oEG_&el(E_jPjftNoCOW5z6RF6@12yl&!=P2^hvPe;YxqPFC?EDL>UKvDHgi z`9$(ZGJ%`_gX7eD?~!P2Hw(=5o^17(9(@t)%E8N=wOYngtUVW!jlNiZy`_3Hn?19| zU#afHg|Jug>WF7Pzfc-HX{6{E@n7gZRm?i{NKc9jWUMsJh)bVclNBY{E4v$Q@pnXL zn&-Fs8x`e-OB&4~&cq^k&E`^0zLp5pqv_dXRckKJz7OJx>_Pv$5RYYzoE+AkxBm!8SChnfGYI;yhQdyj=cPqdzlG-zR#W1dY_}Bo-=@gU)2K3M+~5tMjhXwvCtq+%%U!(J~ae|)ojOO$A) zy`RviIaT-14te+YSELK^KY6RS;RHrY9BLM>!$GuG{}%NVK8#W0k^A*!hqI2nd6nx} z)Af-A*qCk4)0RE4_YZArgp}%VEYCom*cQ{KlO(vfyk8FFgzXGihJX9{JKO|*iTfj6 z)q}2T#>^u&4RM&FSre<|Wp^{4hSk}>orWiJQ|8YNk$#Q=0%{N4MXM7T7paDFZa#Rp;EiJqR19vTY(RPpQ9v3jby*(>^)8xl0mx1M^H2X1h9MJ1*+&`?#vq5 zJpG-$>~XmjN~vjg5y>hSg}>DA$3Ilcz`WT~b?HnYw-`KU*L`ksA6 zYDtx77Ne-{TpKRJPCo)1%S{P%xsDPJi~V*8lxdOO4W-(umm7|}CgMOVC2?*|@)iiX zGacD;9Qxkg&2C_8F|y)$uEr37&3n(c1r@6X+x<$4nQ@35;gcP`qW7nlOP92ep;K?JmS`o@}zs4Ud1s>+ifw=p%c| zhlyx7OFmdd1$xq=-P?Ugp7!6!mm28#mm$g#^^KZt5S|k+bnQ;7LOf0+UD zAv}@>9Ws2~{@Td11&>NzaRxu*Ju%_A+t{hl%y^B>abc6Dm+8lmRagQqe|8dh^XSYA z?(gOE)kFQTJzs+NHLpsfn|mwh2EIe1{K#s~7RHhi%dzy6u1E*QV(uArQnOjZj@dAP zR@L!)k=)qDEhyS+ZD05bK>LapeLbRSz3U1%;#B7G)6@=Y6qlWr$Z zuKl5Qo;Z^l-k+ZR%hR1cL9g$|R6z8MF@bwaAaHD)INzQ{p_*~0zr0oPSQ-PFCup4z zfc49sC#U$wd~6~WPmX*CLKZVy*Q^Z(wY$$gxQ{20Oqvcs?+KC7T(z^8VL;P^@ua&Y zd6WKz6tcYN=9oj((@c4#$#+Cng(^P8XK29*Evx)4^9=UL_v$QZ-*GFvw92*`SJ`Od zOT_4Q{<|DW)K{qJjLr-PsUx;ME{6kUqP|w&*HJ*A5LdMDNvJ`OD2ZPpT!*TAdwno5 z`mvO(-^bNBV!#)xA0tA6DKtJU$TR3g3IK(hIeW3A5rX$(SHc?G^nYZe8JHW1dzUZ` z*gx?|QbVj(Svk&(sd;J2h)!Jc4EF_QKQUu?g}#jVJC_cpDQGK{u5hfj21vo{ zVIh|LBJxOY?fstoF+m3kEeHFJj4_Ur@15I-*(Bwfo(M%}_z))s+F{*th ztOxPAz?Q;m1GZR(mb_z0E%Ueq8rWtkno#~S#?&%$vqchhbMFM@md~#AM{PHEdoyd0 z8RsM5#DJ_{fpTj%^US13vfLY%Dtv)tJ%JDS0(hq ztlC!eZIQ`0t;8>?XhLZ5!rbVDHS>~a1z2Rk2_!TChG#QI{G6bYvkq$O()VOdGJB%d zYFbbK0h5YvV3NiU;n=APd6V_7YUmA9dXN;dJO*p;pGLjtSq{D8v)|kGuG-R`=ep#d z)E$cQrrXTd=CwQi1)N(JC)Pji`3*A_RV9{Bj=~dxYuOgK-je=zvJ-ldoOi)Rj1|W* z*m@Zi*Y*>!S{E&7)+2DKn{VKg-nLt`thdi9FCl?#V9DaubfaGhKm@yzq&Nohza!x5 zWdtp)w#N(|YFt~MSgSR2L%1zkY-{q*Fz&K@?!yR(p$L( ze?(BL3pUB$$+{GDK8M2#^f!JgBN~j@h%AsN0@T8XOpt*J4!ao8D5w;&cS%uQ1a0lq z29T5kJh+Y-g!bJH2P_^r@B$=O?(WE3aqe>HAKqMc-W{JzLktFs{Vk>%nWnkTH%cDT z_je-6OswnghzhDsl?60+hI4LL%-!P>n1jCctwh&23?5_jeyU8`QNqg*(H=8m8lKSzSL?cXg+jOfd z+4V4cfeo(6+4vPWTR~=nl%wPfI9&bn#VWs$R|2u(1%QctykE1RN(Md*gbFNbl(iwe zVo)_;Le+*e%Y%P_x8Tf zbqhj7tc74$^YsQd%&_(%Sg`|;O}^geqH6|(n0UXG+2N^_z`!3suJMYb{RxOobB~fy znDk^_mG~}`h?qxp<9N@jwRi?OwDOamU2@Ms*h_;uS=R`2a~DT`a?^2TQN%Uvh@mOP zXfdT8j+B7H$rI7WT4^6nzh!=*M4^}bu05&3I*L0TJ3wvUrUO2Qlhc=9p@VItW~7PA zw&EqJ&Zxq5h^4TWPJNWR)i=hxBDL3^RA~_%pML>6m!LnvB*gXe`C$g z;5<|i_2PlH7S&BzoBPDwqWtIa7t2hy^d+yM)(X7c{z?X-LTk2)o30w0HfL~B<$Lz= zTnO%S`llprY~`Zj*Z4E#xhM|V4y8(9a47jT=O_G1<>$(tnNNP*vN5Jbc7wg{1);pX zXYvatiTJAOg&K~LKcRr5u%vpF48i=HY})B#c(K5sxruTxzqk(IS$VWmsmyXjyG#zT z%gJE3VLi5ZT}7bQB-i=gJp*39SY-*|i7IiAa0U9#{i_&a>?Y6{x$&cbx+$NTbG0-^ zAc+QFwH}PyrZ_W_1!^=FR2{&I@}E(X+TT%Z5?+^2@)Qe1Z|M9<9B=R2tYCdJy+=Na zH}4p_S9T{mT1A+sSnS6qwnL21f%KC->#dt2H*v^wRZXKRXD9)9D|jWES}uPpNw_ic zHY%Gi09n2sI&CLEzdAPXX?jsNrey045jHK{e-aW79VBP+BUAD_TmX|{KziamObNx{ zRNTpOFc8*c4rRnN(fJdnGJ{d6+~{&t5!Pf6wW5xIM3CTfcP2|PZyU~X$5L|H`DaTS*Cf!qO>zsK zocUo8su0OgP=@MnI=8NREhnVkk|{J;vpbV_?aGDBgLzTdOY3Fu_Sa7-%$$B z3?{58ZtDg{bt(`Z-=pmHTxL5MoWqg?KCIDKsk}aOswln~WS_~Md1KwLYZmBUE&#O~ z8~Rf89W$}TGtu0&n)I2vEc_yGE)~tv#05}Cp!B)SF1-VGTujB1!Vz#gf2VjylbSen$*Ld%~f|a_EJ#b4;^HY+N^84Lkx6# zBsNfu`ilnR-5l49>|7dqD`R(mrDHdX+J{7nT1Aydc{QRQKK#iEk`t9rY+gkX zKG-0wuxBBb236?>_7GjFt|>qy1u|H=#E6kTdmadO7#QN$v4$PivZdtbaVH`Z}F!dK$#AyZo5!0;Uy`mzLWc#W6kKo_C@( zFmJJO_dTWF3uS(sI6)EBzYLJ=U=vQsLOrq*re6tegz4V&f*G#cMj&nC=e2RS z-mEVoc%S7wUurr)1-EBz96wu3=!E{!DObQprsLsaC%nu1c#}`p{Dlc#-C!FL%kTcN z#k+a2Tx#OGZ9E0mW4Oe$B(MH7bFKm<$RfAb1`@wOBh`%5zvLzlNOT9Rn)Ts}qffTE zXEV*1E}-?F-H@}RJLi~d3rO=$3`8-A24)%L^84qY;W+itGZelJK*|t>K?|jPx{7rBOx*y(mH?xpVI?D0XZ&lDA%{gHjKN zAS4^|=lK$IzA;JqY07JUMeNkN{plrzIW6LAang0d)M#z}-j5XZhf)P~r)R1HJjc$E@9;)5edGCJ$eo2A+ok{X(iyCy81xRjxN-Tj z5O!H1ujtMZ=)^|yn(PTEd*CC5ysw}n6bNy(R4^@$vZy{f0dyAFnBQiFKBW#Z~zFGbN*WMaDt62Yml@C91dy>Gff=_(*U11}t&*!Lo{ zb`A9UB-$Jd)u|;Lu*(KncH}pfbvu}yuY^VC`C-yJL%nx(MAB##g-G!@8~u+d0BE+< zI`K+uXFR!4bG7qBhw6`g_DDKLXLg`i7M))a1EUTjDp(nY@StB`+`9<1?=mCJzx$~i zvlWm80lys8T{|Z4$d*IJMrC*T1fju|`jxSY>bSywum=j+Jx*a-N8nJs5Y?3FNI-I} ziRo*Z^QMfQUV`&O19@Hsz43o^5IKO^k6m?Med<_*M!dTC$jrBZ1&0e2+IaC0iCZ=3 zjYM%2MmD1#)lq?KZ>Lh$f1AzAd|uO7CuEx3Tp3D6m>+Xt`CvgEJ?tA~x%VEgUE2 z(4qBQsx*b~x4AQ0nT4?7({ZyTvGdx}dQ={-1>`NSRSdj{@kGEp&80CtXSe}T;U)i;9pEIXEL>kh)x6@!fLAJM zUJ#g)b1&RUWmr|*?Ak&oXRFJKRoTQ6EL)KH1MG@$SUE_42-L1=0Jq+Sn`2vC+bx!X+m6O41A0l^Ll^@MC9-`hc{e8q0<|($HSw-8em&J1A zDDEu-^bbqQT>^h1{0 z<~)>^sGsTNBewfMRC35*9JvoygS@_X*48QHC{-uaGPkaDwN6VuC)eXCHtR+iFZX8Pr@to<)_B)*H@1_#LoSXA+a#FKst!433mRx5Z2ti-5U6M(fo=5u5 zKs#ByU%=^VNgO^N_!{csu1L*fdVVHt^ni+IJH({HPMzGAMhW5c->I-!o>r+z`J9Dg z;DI(16Dnx&E!9g$egssDax_dWj>$k~Bh1v+MD(RPSnB~*Szn;o!CKiecmA+P<@D0; z)B&Q>_IaKuzZ=CchX?KtSX-DFZSdT(lC@L39#_Kd3Hkicmy zYL=$Nco2B{+rLqv#hPV3B4MN|aO zsYeWHEe*Hq;${M`diQ}}uD6E-f!jn+wxces3q?n4q?@KG_`+J|4J4JXd#r*pAx?N~iZX++*-KPXFyu69UVVoi$|p`-Z^hgJ1QN z)&9u2*ieCcyAHZl>bkU?rl^anbepyRT-^m@hR7=$dy|HYOy>kgbMq7e{LE6oGk?-6;ZRxHTzp02i(VU)qxp*7uWCdvxcqc<^Gv8V4e;>D#)TUYTnBUxs7C(w6X60q`*XCC8h=nzDr-UT%$5x!%ADOhI zBIDX4r)l_3eqx~ptXO+rE;5hO?Zz@Y$^V`;a= znf56pk+RSx659?u@R^VJP)dLh$1r>DSO~HpuNml+HIi?@7cY!|pnF(WwQ~I{PtnFf zZu4U0JgByzU&i?G{9 zO00Qk|I?bu%*x`doUV9Vhr`x#TtQVOZ!)cx{xomgu@Z*Ch5von8E*%g6Vck!jA)f) zx6$(WzDmd7k!Y-YWV)x#m9{rMUn?31+Hm8W*PSx)OEsD{3B6L2Rxkx3;c=hLbWe2% zCki=(Bi&i9DylaM9&`B5cfu)OkYOhLZi!bTJswLcht%_Np%x&W&K0i)8d*C!=8W`OuWr>I_`$bc`tHMN@AkWVw-1iL znLZcR&6sc>sV^ONXGYj2;}M_xzE2!c9%qI*9y<+QF{7ee=F5Q-%A|pQONvr6uEQ}Y z|JJFLddf>Ptf=y@$3gnYtz#V1$xUCCR$H1W$u`K2#8ZK9WwFyhD|!YRVO;GqzAanA zg@*LtUah;f`I++v(d2&@CKyG2Kvy!_p{q$ozlE+@Q9Fb&W;fyVPyKIGHkG;4()kCYP{3^zl0SHsK;N*Gh%T-6`n4$64 zd;6bGO=Fbr03__kGBvxl{w6Jk8u!UTFzK|_T2PZ^q$v%DWUWu4-UrqMdeQ>DRWNKa z@&%4XZ6`-UUO~5)z3EPUF(SO-oM3-nzk|{>Z{b?qQD#;~VBeb9={^?$Rs%P$QBm2XMercaoCKoNok2 zZ%-0*zL~pz-Zuc8e)+_E71P)~!KRV#(3rPXAf(1fA9jSjc6C(6%$K)LtN`Cez3Iau z(`F4gFh=4N{_auUCjAj8(>Og+LffE}{tXjolG9A8N|T$DCJ{@c z96}FF;xyeEpe2h)^-w}Dd)Gb3`z|dsp~j{YE+q~r5t4Bue4!6q>v&i`fV7g_*d4W> zXiw_+oONUar}Q(P*B_9%ox!QqH>OR&nTF3R6Z-a$ zA`cO)0gV1tXM@74l`RE+V)Lt#K^Ohvrs>a%tX)N^v%V+`_a{9kgCq#L>!3CNup>+b zCx7YZJN40Qu^+m$!m$^B&Wz8GA0d?_+#B!H<#1R&=6}PChf&$=Q6pWX_z5n3YfNXe z5jc*Jh|xkFu)J#DAIJMI z)G|c813VYallxzW&O|Tx*zSp@O3WiVYG z+9~X!6c<;(cdytUzUPa*jg~tPcEUhTJ(uN}D{F4)ZPf?|yM0r%mF&SR)@{>I7mg7=a8_1*Jv6H3o~3Ue z>x2+V;B_z1X_`bBt_bg7653ULv;G+T8#w4X*m2=mdD3`X!unbO*AolZiGCrN9sbmwh0nT@i4a464S* z5+UA9_9+~M(4?_I(JuUfOD}`3WQ@MsMs{XZsE&h0`(s1`=#2q~rJ_3oU8q}6k4ydH zz~D0=p@&b@q_`gychA-5g!DKfq^K^i`wrT8J!RjMgn%wL=;eVi)JQiE@ZzA=>|nU$va99mvRt%{ z5mt$sE<%!ix#3S(77R#m9E=F>n)Ri7U3f)LfAm2OYw2hT?SC|56*RXSL=$1{m^?-G zAf@=vMlnL6o4OTs7U>k(#>Ok^syr>n*J3ar3AE{JXkc}Zrd+s+P;!tCDPJ0betBApCPRCGPf&gfM(ArX?lds+hg<@E;fiIiz zotb8Dm=iCfo~!uH%0oX3ah#z-r{y0Op<0J8!PPj53r|6p*Q$m#uUtZR@^+;PA@|}{gA=1JEJkbv)5pzs=k{XMIk5E z8{WwR>HRZg$Mpx1p5=Xns^^}PM3zv^fC1lfGGUMV1{@L;77+{r0H(lw#hAXzhZWI; z$-yGV%$9<+lV4pg9_MdosW}mOQh8l$`i1+5yIpDG;tpx7Di%s;a{ia z3hj*no_C4-u8Xt@cQ;n0b7lFua%~?X#6IV{jgpV)g6XWXLAJ%aU{I5ElJjgn; zNuFXZ!FkGqEHAR2XO)jiVI3*gX4iEi0Je_**)NZXmxDYCZ-X0l!{2b&ejtInL8ZZu zjUQ%~irdxDf$W3L1Bn_z=k%@vkY_ftfBOwf=jTTIDB#JxKYd2WzO6BIa{DH@s=umq z=Rj;D;Ar!Fb({^`F?+!IJS>2=lQ>qNN-(ypx224^XvZ!ZGV~ze(DFRdnGUiz`4KSX zn*-X9ItbfW`R@zWO|QV&(UyuhH=64C!1QQ`a_BUOR&;YaR9SR7P*57Rh)kkw77$MJ$ zSEO^!VRm@1r!v5g)J~`MYSj#dYm-p>??2Gr1D`-Muo2B>(lX$Kj-8_8&2W*6D&dW# z#T7>YDDOg4_3799Ld7VKe5c)Yf(d_mZZ)(uyvB_uCC`H*5qyQ$U1@P%bjYLULN(Bk zH_Y&fhrVx8!=K>H!8d7fLuh4bPv8Az-iN@!)9hg z*#zAvcFg44KfP8lEAp%_pVTbWJTmoS-C;jW^Yr^`` zyi1VCF-)yk4@+!_ZO^i<=|F-ZTAMJC^}FBJ*qu+$(?v&V1xEG(6f}GhoU8z~_dN4# zPxO9SOl!+$bLQPo+aX5KO^+k%gS{1CK{efak_PR&Z**URIcR!q(KebeUEwzhSADY{ zXYFsi@3#hbGWT|jr&pb%2KFyHKXGRpTuG7Vll}J;$fNy3a!}8!i5Mhzr2$9K~Co^4n41RU>E zcR~(C@R(a)&z+{3&ZH41^j|x>$1+;@+ppfbiA-#2-qN5Bw8ZV9bG*!eZb(|$^{#K8 zdnH9yDl^lZpd%;gZH?iXuMud${i9WgQHR!Sl~60+UAyB#@UKgcmtu$0?cRy(4vJIn zQ!n1L@bR}ffANkke8Zr#t+7EgDRO^o?)6R7rU8NBW*?v7XV3tfP3=ijC#J{C`g`LC z6rSJ^0)JblCV_oUQ?d-m(f$pJ@k-3A;Aw1tulv;?DyqqV;Dg!H{roGwhu=P`cw_bQ zg}5Pn+Xa97=?+?Y=jV$)Xi?ir92c_1c>m;+f$u!m*7iy#r`@q8Cg%VAln{n*#6u5~ zf>>TU*HkMsO=_0pY#VLz`Bsvj!#6`N{UuY4BQr-q&1Asy7@l?Br+bkW>#5r_B+IJk zwfVg(?cJa@m#84vyVdb4+Z5CRYHn!3>q5}uPO&G?O;lW{>S6;4ot37nZzWedmMaT_ zmv$C;0PN0~38i(qVlBd*#Gb-X)X)Nqr{hK8Phky-`dN$nXKhv2lJ(OD4*B zYAvTSY4($2@*CiWf}rn797IAtVNCeFNW(dv?rq&|1T1aae7v;>sv%vMm)10TgmM$O1mtGcm+;(74)gesY|NPJt^xxKLvXHvY`{U&AB?U{* zQitYsL>3n-D>yt1#>X4gV)tZI*t86mIN9*6OmtkT>Ds+m;ePSe|60M{!SUN;Fnrp5 zo4j|a`gt*CwrIz&cF>T;(NJr7XkPs=v*GTr!}vga1Ho|+?n4In@*%_?&7bAAmN`0Z!cI9W7YRybsH)DV^5x%Y^Fk}kU>u1EI3cdD%L;Yt&a);#k|V0Ew)%cMQ%7fDD#Lp$^e49S zHhdT^VQ9>>BTSGMVlwXly+|#eJPE-jsg>H9jC1(S)X>9{OSm&Dny`cr2Emd@$95z` zXTW5Z(1oSS^g!q!HsihmZMcXI=q19ZXP+Xhx1cxes_Mb9#p1BS(#b#Pnx#h;ry3Rw zo`aB(kS-!#Km*8{*`r>aFK!&7Iij!oQ0Pa=2;DP7XPQVum5Ly|NpPN%}LTF zcCx4=LL)nv?O4+}oj4*wxtNP)3$ZP1r?Qxi6qTzZ%+;cjF%5GuELyH+WagC2)k4fx zp|B*R^I7Md==%qJ_v>D-=i~XfKOc|#>TUsSm$;tQZ&W;`4owm0?mwUSd zcWUbHXx!~#Q5u2TW|re2@XsqfqBA*oX@;XNH<3Z2E*~vSzgT3)Nrnh{-cw4ra-b`PsFL!28Z zgpt~dqO>2}SdLo!8c_ES`>h{2^3hSZHd-}SPw|}9Abxv?SAIWg^w~9o^o!mDb(K)j z_#TynrvYy8uGZe@>|d1C-Jn@>^_Le9(SNaEoGdgw6vea3y^gei2 zx&$Bn>prS;@q=SyU6zAQkV`CNES(Kv=@#Gpn)`=U1q#FJUkn@J;0hO!SHsauI(qRC zsjMz*P%YOkaUFz^`{=!D^z+o*-0{d#a|WQM?_TT~(7LYgO>mN^ZarO)sZIL=`=d$> zAVYpaD+>{o@UjRXWzFt$@)8sRYSd*{S`apPF<;{FPow)qW~}V|ZH39!a1HO=R>Yk6 z!!48Wn@J4^J}i~64s9}%yCTM+aZ%QRfh) zQ`6mKbMvH$M6a#Bj0F?~RXHT=YGB3jC1+hWWwpF*BE9#Y26b*)Gn(eIXTGYY6%ts= zfB)1D-FRjEXg;-p%>lj{XxMIR8rQuyvvSnTOr>Rr>N`eI$L^@=!J|pJtuX_|10dBV zpuAz8w6&aLb}%y@`1xnnwxc>xQ`da1cETpjwLk!ArZ5K7X3~aGZ!_U%G5^hcMWmZ) zE4$jnn`Aai(1#3y2qi|P6ZqYRm=)70jbD**wUTx#d#OG@H@&0TMcWgfzL`3bn&LHr zu_>1fksBL`k-znhfpD`aO0ma{G1Mc8Aki;60ODw-sbKuGt7f=b>vioPS|EVVOVl0I zFI@9aZrQpu{tfzY>I=M?V2rOvS@1j}s=K0QB(g&W@>Eag==HSj#t7!Qr5-m28UiAo z12m7aMlE(3>0C|P-M22Z@BRpXtgEI4T2>qjgJVzvrMBp>itMB?Se?z=Y>vbq0$ixu z_z(uiO-Fr;@QTK0w@fTJDJB}JB}b{I9SQx}(IHt8?$9lWgL4!-ZCFiMfn>?P&%b(f zI<*b989$<2VLue{wCL!goq+fz&P=wQ4|Y~s37=oQ?r$da!Brqlp=H-otEiDmcA%GG ze@mMD8)bXi8lIv3jO-v^RjcbArL+7Gal5f9`FhG#?N5WfF;Caq~i!`G$-MBNi9W6 zC6aBWjkQ@w`B{ScOi7YGlm+{ZfIanueWf3e(l1n|JJTw+!g%Al06?zyNOiL;8@<9K z=h+>%*#ZJAioD-014#{~U2^$1X>&m1aLNgDd>$_gM?o)%Ztdp-dgmIc`{@DVrReAm znO|y4Q`AQzJP97Jc&}BRknbb3A5>VrupV#LcP0Z<17LN{1CanQwpBE?Ik3Q92LvE5 ziOnOzW=!IoO`8o=s0b4{Y6hekE00bd|CCeLrLh)OPgL*N7$%(*lSC@?P!n?ZT^S34 z?p)tf6p%dcrN`SF*95{1wLi8ANfsCE5`#f2t;XCMQ_xLYkF8(zSl6h(!BnD(dL{~O5tu``Ri z;gue-h0k=xm-3BtK?jHKY%c=C1y!(#aj=5VC1`lomPr+?#0{Q!Tr7MTGyT&#^-yi- z0YF4sX@EL@<9Jeld2X|WIiF-m!C?pdTU2!lItOWi&7;@k;LK(=nZX(Rch06r+?WYf z)@4s&*?U(qRnOF`6;I=`UmbNtl2H-~>vnz%Y%c~V`tfm6b$O!qx!#%k3R+C=(x|9~ zf#EtJBtW{oC!V+GbR{&-s``QdQQzUhe&tvmJWXivfY zw(CD=U9jx-%7+CsdF650HAc#z6pUvAJfD`&kI0-4I)jWz$W}>??e}i&fLsJypHoWc zdQYhN1bR25G|)oaEj16Mblz2u>U?=Tpx{^nLKHWjMNahU>T-Ea|VKVgxa~Xo_4le}1bh`+6|8_y##20S3q- z#s5<|2<6Y|^hp=VbA|s5Yrh0hhU$!LfGCh?#Dr$i0+oZQhf zh!}HCgtHi_WAOMzB!9WxA)FRUAovv%(1ckeQ2TWcejo{(H$VLl*@i$#wvQ)aNva9{ z@aGs%mew2$Z0DE&O6eF_%#%Zws*4$GI)YiYVQT*;Q&$8WCD>ad!hXyb{-Rk}^Z`sByB{pO<-B_xL|r0_>KyNS5bWvJbpT#(U?!@` zoVf0w2~o@A%v1eHpImJdLgb$iYcj3zm@@uv){hTcC36Vp$7cv?Sz7K&wz{!D3t*)L zSDcxw3G@3RK{V$fWXo@q`XX_KL6gixceAv!=n6F`Cf9hM(8%S+ji*fmj}8k+0= zk(1S>WJ`(kFY`@-EvY3LH@!`-HKjWHYah9M zWxaaV;_zS=uMnXd8ycTdgrUm&MO8rZ@B-<Ep1CM)?hF23=zo z6e>eabsx3KP)csWgbjCx(`=}>&nP7%$#P0h3W%*NAoIxMfJwjEwhAM*IX*UIoXUUr z`IpU|UL)8g(IwhklmCqP|6z0!qdzAd5DLOU(NwacRTcG)So0uw`ljrSYh)YeV&{&Y zAFQm7RfuW(Y&rl?&fzPqQbK{0;`nlXww;ZOslCEZQpxc%VkjM+NQMSd6ylb~pMgi% zE)8GcQMgfS2NtFL@KTD8c+SXCh)Quo)^YpxX?r{{T(A=^ONs)61{%l03Ih|vQJ|bF zAIXyXtFuWVWp^iXJo%?RTZr#*%&zrqGeN-vAJ{vq$jx6x*8RpQ4a0d|q{8s71W>Ns z2#O|NY8{6%Po~c^yDd8k!P2fX?+NIN3fHuW@nPBBb{TjMs3-ODe7hb_i3>gJ60bEG z=G&QRCf%F-vv>3Hd!723l{JBikEg6vpoR_XL$?1=mvC_V2gt{?y5gMj0CLK--`0X| z1gbkSpIq%5F14%)RZ6h;yyNT^AU8P&{gc5*c&e4zJr3|5CMEWImc=f8m_tyWpV6sc z>rY`77$KJ`*ZdefwWlvKVtDBbKVoP!+JuS67{%|&0*;k8al?O_#gUiF?D{d^Zp0e|1OeV`xB4{>D?o_?l#V6P6k*W*GMlOI#B1{Jr=^eV<7nCNuT30V zmHp-?8y9pKg%l@YEy8R?(Tk8spz(g~a3P%tR!Q{ltBl@Z5xxZP{D~708l7&LOY<`w(V6Et_+2Phj zo2mjmhAThTZFcL6(mlACI9~zP>R*Q8ZeOM6#cFdQ=trr9^z*5{Z@pL>F1FHw}y z1c5?xKBDnJc`;Pli}<9y!qoBa7ivPe`3Fz02Jfr#KUT8+%&jxukrkB(vwJLkdJNxi z@GYv|L8+`S!z%S-U6)JOC&hS40f2t)O)nwlJC(;&EK*V4GFT~1d=|-@zI;9%{^C@| zTA@kb2`t>}&^1e&uUEi^N?d7qH}-Ih=~fAKZ@%sy)+KUyERyUCa=Hh9Q<8c!QmBaP zvNk%=74*OLr*FDgr?&)v#P7QPIhZm-9i%$+tVD?W3@E0o@c3E7Z;H}N>Y zohyubwwshhSeWSxfgaR&~u@H=) z!>f22OO-2n1zEMM|``4$9F z{TwO^!F$(u_mJ_4kYQKIe_MTYodnJ3;q6Us$| znyIj@KFm08>`vI}ymvQmdyE0Apq71Y4`wZL7=t;C22&xwG{4zMeeC_j3P=?{`RAAM zOvYV-+Wk8u#jXUFxEAviY@p+PIpz3Qa5Rfb2) z0F4XW&?}fF8`-yot_SJvgH_KIELQ*x z;E;{DaaC~5BX@5pQpq>}2=dfW8`!j$MSe6>om(`xRQSd9v=4jlmD~H1qJq_BqQPgo z*p}&Qds0ATZ|Pt76UX!Bg7`kASc*gGJ5;#LP0@@I3AT(2Nv?jz?k&fS<1zF%5WtW| zEoXextJGYmW9ji<1~guBxl^-Odja7)DH$^wCJpob4#`$dIwdQmq?SCjr9Ku(P4Z8@ zCX@-ZtxBC+PCYr!3v7D%iE*B3>KmSW;2Y-NtxO-pbFddmGZKnEdWDIjLrmHlrqd>6 z?u)pJ7+#x07uu9MhT}ZTVeIk~=YVXA%54%Xm)_d1s!(Xo2Deb|J+viGLR^|*h znDH<2w&pKpop*b#c(_mO6E)aCNh9J0Xvm0X^GnQ9pVjQR!#vFBIMD5AhkG+Yq<4|{ zob$li8t1axecI)=Ezd7@m3{I-@Q>X00rS26aYQ_qH!fhG|3;{>iyC2@eY(UxPRa4V za6FTXN)$@q>4z>^L+VtBn z#i+CQZC@P8C$l+hvfoD++2T*%G%`u$jm1f)ryB+lhA;N_am@>aRhG7GxWd_8LAn%~ zll5hZRRO=18}!Nr#rRs*Okv9I?C(2^UtDzV5!Mb()l+X z1OF_N_WPmQ7dI|rW6HlNl%AJW9ZT*CZbvrRUeL5jyD;bAI6CW{cC^k)g?~ zZMj8B5%lw)N9t+UBlPHY?t#?zu5))h$Zv$bi>x%`c1Qf&y>uy z+wfpz=G&^NidHU(ib8kKvCrNbL63Gjfq28&Ky!SyvMl(Qkk(XQus s)#~-D+H%#iudVR^hkq2@Gx~0QD v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# Add any extra paths that contain custom files (such as robots.txt or +# .htaccess) here, relative to this directory. These files are copied +# directly to the root of the documentation. +#html_extra_path = [] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Language to be used for generating the HTML full-text search index. +# Sphinx supports the following languages: +# 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja' +# 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr' +#html_search_language = 'en' + +# A dictionary with options for the search language support, empty by default. +# Now only 'ja' uses this config value +#html_search_options = {'type': 'default'} + +# The name of a javascript file (relative to the configuration directory) that +# implements a search results scorer. If empty, the default will be used. +#html_search_scorer = 'scorer.js' + +# Output file base name for HTML help builder. +htmlhelp_basename = 'OpenMWCSManualdoc' + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { +# The paper size ('letterpaper' or 'a4paper'). +#'papersize': 'letterpaper', + +# The font size ('10pt', '11pt' or '12pt'). +#'pointsize': '10pt', + +# Additional stuff for the LaTeX preamble. +#'preamble': '', + +# Latex figure (float) alignment +#'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + (master_doc, 'OpenMWCSManual.tex', u'OpenMW CS Manual Documentation', + u'HiPhish', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + (master_doc, 'openmwcsmanual', u'OpenMW CS Manual Documentation', + [author], 1) +] + +# If true, show URL addresses after external links. +#man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + (master_doc, 'OpenMWCSManual', u'OpenMW CS Manual Documentation', + author, 'OpenMWCSManual', 'One line description of project.', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +#texinfo_appendices = [] + +# If false, no module index is generated. +#texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#texinfo_show_urls = 'footnote' + +# If true, do not generate a @detailmenu in the "Top" node's menu. +#texinfo_no_detailmenu = False + + +# -- Options for Epub output ---------------------------------------------- + +# Bibliographic Dublin Core info. +epub_title = project +epub_author = author +epub_publisher = author +epub_copyright = copyright + +# The basename for the epub file. It defaults to the project name. +#epub_basename = project + +# The HTML theme for the epub output. Since the default themes are not +# optimized for small screen space, using the same theme for HTML and epub +# output is usually not wise. This defaults to 'epub', a theme designed to save +# visual space. +#epub_theme = 'epub' + +# The language of the text. It defaults to the language option +# or 'en' if the language is not set. +#epub_language = '' + +# The scheme of the identifier. Typical schemes are ISBN or URL. +#epub_scheme = '' + +# The unique identifier of the text. This can be a ISBN number +# or the project homepage. +#epub_identifier = '' + +# A unique identification for the text. +#epub_uid = '' + +# A tuple containing the cover image and cover page html template filenames. +#epub_cover = () + +# A sequence of (type, uri, title) tuples for the guide element of content.opf. +#epub_guide = () + +# HTML files that should be inserted before the pages created by sphinx. +# The format is a list of tuples containing the path and title. +#epub_pre_files = [] + +# HTML files that should be inserted after the pages created by sphinx. +# The format is a list of tuples containing the path and title. +#epub_post_files = [] + +# A list of files that should not be packed into the epub file. +epub_exclude_files = ['search.html'] + +# The depth of the table of contents in toc.ncx. +#epub_tocdepth = 3 + +# Allow duplicate toc entries. +#epub_tocdup = True + +# Choose between 'default' and 'includehidden'. +#epub_tocscope = 'default' + +# Fix unsupported image types using the Pillow. +#epub_fix_images = False + +# Scale large images. +#epub_max_image_width = 0 + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#epub_show_urls = 'inline' + +# If false, no index is generated. +#epub_use_index = True + + +# Example configuration for intersphinx: refer to the Python standard library. +intersphinx_mapping = {'https://docs.python.org/': None} diff --git a/docs/cs-manual/source/files-and-directories.rst b/docs/cs-manual/source/files-and-directories.rst new file mode 100644 index 000000000..34680fa94 --- /dev/null +++ b/docs/cs-manual/source/files-and-directories.rst @@ -0,0 +1,224 @@ +Files and Directories +##################### + +In this chapter of the manual we will cover the usage of files and directories +by OpenMW CS. Files and directories are file system concepts of your operating +system, so we will not be going into specifics about that, we will only focus +on what is relevant to OpenMW CS. + + +Basics +****** + + +Directories +=========== + +OpenMW and OpenMW CS us multiple directories on the file system. First of all +there is a *user directory* that holds configuration files and a number of +different sub-directories. The location of the user directory is hard-coded +into the CS and depends on your operating system. + +================ ========================================= +Operating System User Dircetory +================ ========================================= +GNU/Linux ```` +OS X ``~/Library/Application Support/openmw/`` +Windows ```` +================ ========================================= + +In addition to to this single hard-coded directory both OpenMW and OpenMW CS +need a place to seek for a actuals data files of the game: textures, 3D models, +sounds and record files that store objects in game; dialogues an so one. These +files are called *content files*. We support multiple such paths (we call them +*data paths*) as specified in the configuration. Usually one data path points +to the directory where the original Morrowind game is either installed or +unpacked to. You are free to specify as many data paths as you would like, +however, there is one special data path that, as described later, which is used +to store newly created content files. + + +Content files +============= + +The original Morrowind engine by Bethesda Softworks uses two types of content +files: `esm` (master) and `esp` (plugin). The distinction between those two is +not clear, and often confusing. One would expect the `esm` (master) file to be +used to specify one master, which is then modified by the `esp` plugins. And +indeed: this is the basic idea. However, the official expansions were also made +as ESM files, even though they could essentially be described as really large +plugins, and therefore would rather use `esp` files. There were technical +reasons behind this decision – somewhat valid in the case of the original +engine, but clearly it is better to create a system that can be used in a more +sensible way. OpenMW achieves this with our own content file types. + +We support both ESM and ESP files, but in order to make use of new features in +OpenMW one should consider using new file types designed with our engine in +mind: *game* files and *addon* files, collectively called *content files*. + + +OpenMW content files +-------------------- + +The concepts of *Game* and *Addon* files are somewhat similar to the old +concept of *ESM* and *ESP*, but more strictly enforced. It is quite +straight-formward: If you want to make new game using OpenMW as the engine (a +so called *total conversion*) you should create a game file. If you want to +create an addon for an existing game file create an addon file. Nothing else +matters; the only distinction you should consider is if your project is about +changing another game or creating a new one. Simple as that. + +Another simple thing about content files are the extensions: we are using +``.omwaddon`` for addon files and ``.omwgame`` for game files. + + +Morrowind content files +----------------------- + +Using our content files is recommended for projects that are intended to used +with the OpenMW engine. However, some players might wish to still use the +original Morrowind engine. In addition thousands of *ESP*/*ESM* files were +created since 2002, some of them with really outstanding content. Because of +this OpenMW CS simply has no other choice but to support *ESP*/*ESM* files. If +you decid to choose *ESP*/*ESM* file instead of using our own content file +types you are most likely aimng at compatibility with the original engine. This +subject is covered in it own chapter of this manual. + + +.. TODO This paragraph sounds weird + +The actual creation of new files is described in the next chapter. Here we are +going to focus only on the details you need to know in order to create your +first OpenMW CS file while fully understanding your needs. For now let’s jut +remember that content files are created inside the user directory in the the +``data`` subdirectory (that is the one special data directory mentioned +earlier). + + +Dependencies +------------ + +Since an addon is supposed to change the game it follows that it also depends +on the said game to work. We can conceptualise this with an examples: your +modification is the changing prize of an iron sword, but what if there is no +iron sword in game? That's right: we get nonsense. What you want to do is tie +your addon to the files you are changing. Those can be either game files (for +example when making an expansion island for a game) or other addon files +(making a house on said island). Obviously It is a good idea to be dependent +only on files that are really changed in your addon, but sadly there is no +other way to achieve this than knowing what you want to do. Again, please +remember that this section of the manual does not cover creating the content +files – it is only a theoretical introduction to the subject. For now just keep +in mind that dependencies exist, and is up to you to decide whether your +content file should depend on other content files. + +Game files are not intend to have any dependencies for a very simple reasons: +the player is using only one game file (excluding original and the dirty +ESP/ESM system) at a time and therefore no game file can depend on other game +file, and since a game file makes the base for addon files it can not depend on +addon files. + + +Project files +------------- + +Project files act as containers for data not used by the OpenMW game engine +itself, but still useful for OpenMW CS. The shining example of this data +category are without doubt record filters (described in a later chapter of the +manual). As a mod author you probably do not need or want to distribute project +files at all, they are meant to be used only by you and your team. + +.. TODO "you and your team": is that correct? + +As you would imagine, project files make sense only in combination with actual +content files. In fact, each time you start to work on new content file and a +project file was not found, one will be created. The extensio of project files +is ``.project``. The whole name of the project file is the whole name of the +content file with appended extension. For instance a ``swords.omwaddon`` file +is associated with a ``swords.omwaddon.project`` file. + +Project files are stored inside the user directory, in the ``projects`` +subdirectory. This is the path location for both freshly created project files, +and a place where OpenMW CS looks for already existing files. + + +Resource files +============== + +.. TODO This paragraph sounds weird + +Unless we are talking about a fully text based game, like Zork or Rogue, one +would expect that a video game is using some media files: 3D models with +textures, images acting as icons, sounds and anything else. Since content +files, no matter whether they are *ESP*, *ESM* or new OpenMW file type, do not +contain any of those, it is clear that they have to be delivered with a +different file. It is also clear that this, let’s call it “resources file“, +has to be supported by the engine. Without code handling those files it is +nothing more than a mathematical abstraction – something, that lacks meaning +for human beings. Therefore this section must cover ways to add resources +files to your content file, and point out what is supported. We are going to do +just that. Later, you will learn how to make use of those files in your +content. + + +Audio +----- + +OpenMW uses FFmpeg_ for audio playback, and so we support every audio type +supported by that library. This makes a huge list. Below is only small portion +of the supported file types. + +mp3 (MPEG-1 Part 3 Layer 3) + A popular audio file format and de facto standard for storing audio. Used by + the Morrowind game. + +ogg + An open source, multimedia container file using a high quality Vorbis_ audio + codec. Recommended. + + +Video +----- + +Video As in the case of audio files, we are using FFmepg to decode video files. +The list of supported files is long, we will cover only the most significant. + +bik + Videos used by the original Morrowind game. + +mp4 + A multimedia container which use more advanced codecs (MPEG-4 Parts 2, 3 and + 10) with a better audio and video compression rate, but also requiring more + CPU intensive decoding – this makes it probably less suited for storing + sounds in computer games, but good for videos. + +webm + A new, shiny and open source video format with excellent compression. It + needs quite a lot of processing power to be decoded, but since game logic is + not running during cutscenes we can recommend it for use with OpenMW. + +ogv + Alternative, open source container using Theora_ codec for video and Vorbis for audio. + + + +Textures and images +------------------- + +The original Morrowind game uses *DDS* and *TGA* files for all kinds of two +dimensional images and textures alike. In addition, the engine supported *BMP* +files for some reason (*BMP* is a terrible format for a video game). We also +support an extended set of image files – including *JPEG* and *PNG*. *JPEG* and +*PNG* files can be useful in some cases, for instance a *JPEG* file is a valid +option for skybox texture and *PNG* can useful for masks. However, please keep +in mind that *JPEG* images can grow to large sizes quickly and are not the best +option with a DirectX rendering backend. You probably still want to use *DDS* +files for textures. + + + +.. Hyperlink targets for the entire document + +.. _FFmpeg: http://ffmpeg.org +.. _Vorbis: http://www.vorbis.com +.. _Theora: http://www.theora.org diff --git a/docs/cs-manual/source/foreword.rst b/docs/cs-manual/source/foreword.rst new file mode 100644 index 000000000..613eca5e3 --- /dev/null +++ b/docs/cs-manual/source/foreword.rst @@ -0,0 +1,21 @@ +Foreword +######## + + + + +How to read the manual +********************** + +The manual can be roughly divided into two parts: a tutorial part consisting of +the first two (three) chapters and the reference manual. We recommend all +readers to work through the tutorials first, there you will be guided through +the creation of a fairly simple mod where you can familiarise yourself with the +record-based interface. The tutorials are very simple and teach you only what +is necessary for the task, each one can be completed in under half an hour. It +is strongly recommended to do the tutorials in order. + +When you are familiar with the CS in general and want to write your own mods it +is time to move on to the reference part of the manual. The reference chapters +can be read out of order, each one covers only one topic. + diff --git a/docs/cs-manual/source/index.rst b/docs/cs-manual/source/index.rst new file mode 100644 index 000000000..ce50b8c95 --- /dev/null +++ b/docs/cs-manual/source/index.rst @@ -0,0 +1,30 @@ +.. OpenMW CS Manual documentation master file, created by + sphinx-quickstart on Fri Feb 5 21:28:27 2016. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +##################### +OpenMW CS user manual +##################### + +The following document is the complete user manual for *OpenMW CS*, the +construction set for the OpenMW game engine. It is intended to serve both as an +introduction and a reference for the application. Even if you are familiar with +modding *The Elder Scrolls III: Morrowind* you should at least read the first +few chapters to familiarise yourself with the new interface. + +.. warning:: + OpenMW CS is still software in development. The manual does not cover any of + its shortcomings, it is written as if everything was working as inteded. + Please report any software problems as bugs in the software, not errors in + the manual. + +.. toctree:: + :caption: Table of Contents + :maxdepth: 2 + + foreword + tour + files-and-directories + starting-dialog + diff --git a/docs/cs-manual/source/starting-dialog.rst b/docs/cs-manual/source/starting-dialog.rst new file mode 100644 index 000000000..02a65ff21 --- /dev/null +++ b/docs/cs-manual/source/starting-dialog.rst @@ -0,0 +1,40 @@ +OpenMW CS Starting Dialog +######################### + +In this chapter we will cover starting up OpenMW CS and the starting interface. +Start the CS the way intended for your operating system and you will be +presented with window and three main buttons and a small button with a +wrench-icon. The wrench will open the configuration dialog which we will cover +later. The three main buttons are the following: + +Create A New Game + Choose this option if you want to create an original game that does not + depend on any other content files. The distinction between game and addon in + the original Morrowind engine was somewhat blurry, but OpenMW is very strict + about it: regardless of how large your addon is, if it depends on another + content file it is not an original game. + +Create A New Addon + Choose this option if you want to create an extension to an existing game. + An addon can depend on other addons as well optionally, but it *must* depend + on a game. + +Edit A Content File + Choose this option is you wish to edit an existing content file, regardless + of whether it is a game or an addon. + +Whether you create a game or an addon, a data file and a project file will be +generated for you in you user directory. + +You will have to choose a name for your content file and if you chose to create +an addon you will also have to chose a number of dependencies. You have to +choose exactly one game and you can choose an arbitrary amount of addon +dependencies. For the sake of simplicity and maintainability choose only the +addons you actually want to depend on. Also keep in mind that your dependencies +might have dependencies of their own, you have to depend on those as well. If +one of your dependencies nees something it will be indicated by a warning sign +and automatically include its dependencies when you choose it. + +If you want to edit an existing content file you will be presented with a +similar dialog, except you don't get to choose a file name (because you are +editing files that already exist). diff --git a/docs/cs-manual/source/tour.rst b/docs/cs-manual/source/tour.rst new file mode 100644 index 000000000..0e92fe6fa --- /dev/null +++ b/docs/cs-manual/source/tour.rst @@ -0,0 +1,223 @@ +A Tour through OpenMW CS: making a magic ring +############################################# + +In this first chapter we will create a mod that adds a new ring with a simple +enchantment to the game. The ring will give its wearer a permanent Night Vision +effect while being worn. You don't need prior knowledge about modding +Morrowind, but you should be familiar with the game itself. There will be no +scripting necessary, we chan achieve everything using just what the base game +offers out of the box. Before continuing make sure that OpenMW is properly +installed and playable. + + +Adding the ring to the game's records +************************************* + +In this first section we will define what our new ring is, what it looks like +and what it does. Getting it to work is the first step before we go further. + + +Starting up OpenMW CS +===================== + +We will start by launching OpenMW CS, the location of the program depends on +your operating system. You will be presented with a dialogue with three +options: create a new game, create a new addon, edit a content file. + +.. figure:: ./_static/images/chapter-1/opening-dialogue.png + :alt: Opening dialogue with three option and setting button (the wrench) + +The first option is for creating an entirely new game, that's not what we want. +We want to edit an existing game, so choose the second one. When you save your +addon you can use the third option to open it again. + +You will be presented with another window where you get to chose the content to +edit and the name of your project. We have to chose at least a base game, and +optionally a number of other addons we want to depend on. The name of the +project is arbitrary, it will be used to identify the addon later in the OpenMW +launcher. + +.. figure:: ./_static/images/chapter-1/new-project.png + :alt: Creation dialogue for a new project, pick content modules and name + +Choose Morrowind as your content file and enter `Ring of Night Vision` as the +name. We could also chose further content files as dependencies if we wanted +to, but for this mod the base game is enough. + +Once the addon has been created you will be presented with a table. If you see +a blank window rather than a table choose *World* → *Objects* from the menu. + +.. figure:: ./_static/images/chapter-1/objects.png + :alt: The table showing all objet records in the game. + +Let's talk about the interface for a second. Every window in OpenMW CS has +*panels*, these are often but not always tables. You can close a panel by +clicking the small "X" on the title bar of the panel, or you can detach it by +either dragging the title bar or clicking the icon with the two windows. A +detached panel can be re-attached to a window by dragging it by the title bar +on top of the window. + +Now let's look at the panel itself: we have a filter text field, a very large +table and a status bar. The filter will be very useful when we want to find an +entry in the table, but for now it is irrelevant. The table you are looking at +contains all objects in the game, these can be items, NPCs, creatures, +whatever. Every object is an entry in that table, visible as a row. The columns +of the table are the attributes of each object. + +Morrowind uses something called a *relational database* for game data. If you +are not familiar with the term, it means that every type of thing can be +expressed as a *table*: there is a table for objects, a table for enchantments, +a table for icons, one for meshes, and so on. Properties of an entry must be +simple values, like numbers or text strings. If we want a more complicated +property we need to reference an entry from another table. There are a few +exceptions to this though, some tables do have subtables. The effects of +enchantments are one of those exceptions. + + +Defining a new record +===================== + +Enough talk, let's create the new ring now. Right-click anywhere in the objects +table, choose `Add Record` and the status bar will change into an input field. +We need to enter an *ID* (short for *identifier*) and pick the type. The +identifier is a unique name by which the ring can later be identified; I have +chosen `ring_night_vision`. For the type choose *Clothing*. + +.. figure:: ./_static/images/chapter-1/add-record.png + :alt: Enter the ID and type of the new ring + +The table should jump right to our newly created record, if not read further +below how to use filters to find a record by ID. Notice that the *Modified* +column now shows that this record is new. Records can also be *Base* +(unmodified), *Modified* and *Deleted*. The other fields are still empty since +we created this record from nothing. We can double-click a table cell while +holding Shift to edit it (this is a configurable shortcut), but there is a +better way: right-click the row of our new record and chose *Edit Record*, a +new panel will open. + +We can right-click the row of our new record and chose *Edit Record*, a +new panel will open. Alternatively we can also define a configurable shortcut +instead of using the context menu; the default is double-clicking while +holding down the shift key. + + +.. figure:: ./_static/images/chapter-1/edit-record.png + :alt: Edit the properties of the record in a separate panel + +You can set the name, weight and coin value as you like, I chose `Ring of Night +Vision`, `0.1` and `2500` respectively. Make sure you set the *Clothing Type* +to *Ring*. We could set the other properties manually as well, but unless you +have an exceptional memory for identifiers and never make typos that's not +feasible. What we are going to do instead is find the records we want in their +respective tables and assign them from there. + + +Finding records using filters +============================= + +We will add an icon first. Open the *Icons* table the same way you opened the +*Objects* table: in the menu click *Assets* → *Icons*. If the window gets too +crowded remember that you can detach panels. The table is huge and not every +ring icon starts with "ring", so we have to use filters to find what we want. + +Filters are a central element of OpenMW CS and a major departure from how the +original Morrowind CS was used. In fact, filters are so important that they +have their own table as well. We won't be going that far for now though. There +are three types of filters: *Project filters* are part of the project and are +stored in the project file, *session filter* are only valid until you exit the +CS, and finally *instant filter* which are used only once and typed directly +into the *Filter* field. + +For this tutorial we will only use instant filters. We type the definition of +the filter directly into the filter field rather than the name of an existing +filter. To signify that we are using an instant filter the have to use `!` as +the first character. Type the following into the field: + +.. code:: + + !string("id", ".*ring.*") + +A filter is defined by a number of *queries* which can be logically linked. For +now all that matters is that the `string(, )` query will check +whether `` matches ``. The pattern is a regular expression, +if you don't know about them you should learn their syntax. For now all that +matters is that `.` stands for any character and `*` stands for any amount, +even zero. In other words, we are looking for all entries which have an ID that +contains the word "ring" somewhere in it. This is a pretty dumb pattern because +it will also match words like "ringmail", but it's good enough for now. + +If you have typed the filter definition properly the text should change from +red to black and our table will be narrowed down a lot. Browse for an icon you +like and drag & drop its table row onto the *Icon* field of our new ring. + +That's it, you have now assigned a reference to an entry in another table to +the ring entry in the *Objects* table. Repeat the same process for the 3D +model, you can find the *Meshes* table under *Assets* → *Meshes*. + + +Adding the enchantment +====================== + +Putting everything you have learned so far to practice we can add the final and +most important part to our new ring: the enchantment. You know enough to +perform the following steps without guidance: Open the *Enchantments* table +(*Mechanics* → *Enchantments*) and create a new entry with the ID `Cats Eye`. +Edit it so that it has *Constant Effect* enchantment type. + +To add an effect to the enchantment right-click the *Magic Effects* table and +choose *Add new row*. You can edit the effects by right-clicking their table +cells. Set the effect to *NightEye*, range to *Self*, and both magnitudes to +`50`. The other properties are irrelevant. + +Once you are done add the new enchantment to our ring. That's it, we now have a +complete enchanted ring to play with. Let's take it for a test ride. + + +Playing your new addon +====================== + +Launch OpenMW and in the launcher under *Data Files* check your addon. Load a +game and open the console. We have only defined the ring, but we haven't placed +any instance of it anywhere in the game world, so we have to create one. In the +console type: + +.. code:: + + player->AddItem "ring_night_vision" 1 + +The part in quotation marks is the ID of our ring, you have to adjust it if you +chose a different ID. Exit the console and you should find a new ring in your +inventory. Equip it and you will instantly receive the *Night Vision* effect +for your character. + + +Conclusion +========== + +In this tutorial we have learned how to create a new addon, what tables are and +how to create new records. We have also taken a very brief glimpse at the +syntax of filters, a feature you will be using a lot when creating larger mods. + +This mod is a pure addition, it does not change any of the existing records. +However, if you want to actually present appealing content to the player rather +than just offering abstract definitions you will have to change the game's +content. In the next tutorial we will learn how to place the ring in the game +world so the player can find it legitimately. + + + +Adding the ring to the game's world +*********************************** + +Now that we have defined the ring it is time add it to the game world so the +player can find it legitimately. We will add the ring to a merchant, place it +in a chest and put it somewhere in plain sight. To this end we will have to +actually modify the contents of the game. + + +Subsection to come... +===================== + + + + From e02f35264fd2e8f78d258d73cb5f6c709b110e64 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 6 Feb 2016 15:08:12 +0100 Subject: [PATCH 3088/3725] Work around OSG 3.2 not respecting the DEEP_COPY_CALLBACK flag (Fixes #3183) --- components/sceneutil/clone.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/components/sceneutil/clone.cpp b/components/sceneutil/clone.cpp index 26f3f5c7c..784195e7e 100644 --- a/components/sceneutil/clone.cpp +++ b/components/sceneutil/clone.cpp @@ -81,6 +81,11 @@ namespace SceneUtil #endif osg::Drawable* cloned = osg::clone(drawable, copyop); +#if OSG_VERSION_LESS_THAN(3,3,3) + // work around OSG 3.2 not respecting the DEEP_COPY_CALLBACK flag + if (cloned->getUpdateCallback()) + cloned->setUpdateCallback(osg::clone(cloned->getUpdateCallback(), *this)); +#endif return cloned; } if (dynamic_cast(drawable)) From df57d4bfba49b41b692c7db85b9ef774fa772570 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 6 Feb 2016 16:57:54 +0100 Subject: [PATCH 3089/3725] Use a common base class for resource managers Implement updateCache to delete unreferenced cached objects when they have not been referenced for a while. --- apps/openmw/mwphysics/physicssystem.cpp | 5 +++ apps/openmw/mwphysics/physicssystem.hpp | 1 + apps/openmw/mwrender/renderingmanager.cpp | 2 +- components/CMakeLists.txt | 2 +- components/resource/bulletshapemanager.cpp | 3 +- components/resource/bulletshapemanager.hpp | 16 +------- components/resource/imagemanager.cpp | 3 +- components/resource/imagemanager.hpp | 16 ++------ components/resource/keyframemanager.cpp | 3 +- components/resource/keyframemanager.hpp | 19 +--------- components/resource/niffilemanager.cpp | 10 +---- components/resource/niffilemanager.hpp | 20 +--------- components/resource/resourcemanager.cpp | 34 +++++++++++++++++ components/resource/resourcemanager.hpp | 43 ++++++++++++++++++++++ components/resource/resourcesystem.cpp | 29 ++++++++++++++- components/resource/resourcesystem.hpp | 17 ++++++++- components/resource/scenemanager.cpp | 9 +---- components/resource/scenemanager.hpp | 19 ++-------- components/vfs/manager.hpp | 6 +++ 19 files changed, 152 insertions(+), 105 deletions(-) create mode 100644 components/resource/resourcemanager.cpp create mode 100644 components/resource/resourcemanager.hpp diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index c99456ae5..11d6d286a 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -640,12 +640,15 @@ namespace MWPhysics PhysicsSystem::PhysicsSystem(Resource::ResourceSystem* resourceSystem, osg::ref_ptr parentNode) : mShapeManager(new Resource::BulletShapeManager(resourceSystem->getVFS(), resourceSystem->getSceneManager(), resourceSystem->getNifFileManager())) + , mResourceSystem(resourceSystem) , mDebugDrawEnabled(false) , mTimeAccum(0.0f) , mWaterHeight(0) , mWaterEnabled(false) , mParentNode(parentNode) { + mResourceSystem->addResourceManager(mShapeManager.get()); + mCollisionConfiguration = new btDefaultCollisionConfiguration(); mDispatcher = new btCollisionDispatcher(mCollisionConfiguration); mBroadphase = new btDbvtBroadphase(); @@ -659,6 +662,8 @@ namespace MWPhysics PhysicsSystem::~PhysicsSystem() { + mResourceSystem->removeResourceManager(mShapeManager.get()); + if (mWaterCollisionObject.get()) mCollisionWorld->removeCollisionObject(mWaterCollisionObject.get()); diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index f53d7e3d9..4263bc0ec 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -169,6 +169,7 @@ namespace MWPhysics btCollisionWorld* mCollisionWorld; std::auto_ptr mShapeManager; + Resource::ResourceSystem* mResourceSystem; typedef std::map ObjectMap; ObjectMap mObjects; diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 9b7ced4b5..d4199d5f6 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -233,7 +233,7 @@ namespace MWRender void RenderingManager::clearCache() { - mResourceSystem->clearCache(); + mResourceSystem->updateCache(mViewer->getFrameStamp()->getReferenceTime()); if (mTerrain.get()) mTerrain->clearCache(); } diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 0b54ddeb7..42323a68a 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -41,7 +41,7 @@ add_component_dir (vfs ) add_component_dir (resource - scenemanager keyframemanager imagemanager resourcesystem bulletshapemanager bulletshape niffilemanager objectcache + scenemanager keyframemanager imagemanager bulletshapemanager bulletshape niffilemanager objectcache resourcesystem resourcemanager ) add_component_dir (sceneutil diff --git a/components/resource/bulletshapemanager.cpp b/components/resource/bulletshapemanager.cpp index 2ab7b243a..b5581cce2 100644 --- a/components/resource/bulletshapemanager.cpp +++ b/components/resource/bulletshapemanager.cpp @@ -97,10 +97,9 @@ private: }; BulletShapeManager::BulletShapeManager(const VFS::Manager* vfs, SceneManager* sceneMgr, NifFileManager* nifFileManager) - : mVFS(vfs) + : ResourceManager(vfs) , mSceneManager(sceneMgr) , mNifFileManager(nifFileManager) - , mCache(new osgDB::ObjectCache) { } diff --git a/components/resource/bulletshapemanager.hpp b/components/resource/bulletshapemanager.hpp index c8db8849e..576268f75 100644 --- a/components/resource/bulletshapemanager.hpp +++ b/components/resource/bulletshapemanager.hpp @@ -7,16 +7,7 @@ #include #include "bulletshape.hpp" - -namespace VFS -{ - class Manager; -} - -namespace osgDB -{ - class ObjectCache; -} +#include "resourcemanager.hpp" namespace Resource { @@ -29,7 +20,7 @@ namespace Resource /// Handles loading, caching and "instancing" of bullet shapes. /// A shape 'instance' is a clone of another shape, with the goal of setting a different scale on this instance. /// @note May be used from any thread. - class BulletShapeManager + class BulletShapeManager : public ResourceManager { public: BulletShapeManager(const VFS::Manager* vfs, SceneManager* sceneMgr, NifFileManager* nifFileManager); @@ -38,11 +29,8 @@ namespace Resource osg::ref_ptr createInstance(const std::string& name); private: - const VFS::Manager* mVFS; SceneManager* mSceneManager; NifFileManager* mNifFileManager; - - osg::ref_ptr mCache; }; } diff --git a/components/resource/imagemanager.cpp b/components/resource/imagemanager.cpp index bd422fe2a..79da7d7ab 100644 --- a/components/resource/imagemanager.cpp +++ b/components/resource/imagemanager.cpp @@ -42,8 +42,7 @@ namespace Resource { ImageManager::ImageManager(const VFS::Manager *vfs) - : mVFS(vfs) - , mCache(new osgDB::ObjectCache) + : ResourceManager(vfs) , mWarningImage(createWarningImage()) , mOptions(new osgDB::Options("dds_flip dds_dxt1_detect_rgba")) { diff --git a/components/resource/imagemanager.hpp b/components/resource/imagemanager.hpp index bc1d7b4e4..8d9ad2c32 100644 --- a/components/resource/imagemanager.hpp +++ b/components/resource/imagemanager.hpp @@ -8,20 +8,16 @@ #include #include +#include "resourcemanager.hpp" + namespace osgViewer { class Viewer; } -namespace VFS -{ - class Manager; -} - namespace osgDB { class Options; - class ObjectCache; } namespace Resource @@ -29,7 +25,7 @@ namespace Resource /// @brief Handles loading/caching of Images. /// @note May be used from any thread. - class ImageManager + class ImageManager : public ResourceManager { public: ImageManager(const VFS::Manager* vfs); @@ -39,15 +35,9 @@ namespace Resource /// Returns the dummy image if the given image is not found. osg::ref_ptr getImage(const std::string& filename); - const VFS::Manager* getVFS() { return mVFS; } - osg::Image* getWarningImage(); private: - const VFS::Manager* mVFS; - - osg::ref_ptr mCache; - osg::ref_ptr mWarningImage; osg::ref_ptr mOptions; diff --git a/components/resource/keyframemanager.cpp b/components/resource/keyframemanager.cpp index 7e948dcb0..4392f84c1 100644 --- a/components/resource/keyframemanager.cpp +++ b/components/resource/keyframemanager.cpp @@ -9,8 +9,7 @@ namespace Resource { KeyframeManager::KeyframeManager(const VFS::Manager* vfs) - : mCache(new osgDB::ObjectCache) - , mVFS(vfs) + : ResourceManager(vfs) { } diff --git a/components/resource/keyframemanager.hpp b/components/resource/keyframemanager.hpp index 5a5cb3628..1c2c219bb 100644 --- a/components/resource/keyframemanager.hpp +++ b/components/resource/keyframemanager.hpp @@ -4,15 +4,7 @@ #include #include -namespace VFS -{ - class Manager; -} - -namespace osgDB -{ - class ObjectCache; -} +#include "resourcemanager.hpp" namespace NifOsg { @@ -24,22 +16,15 @@ namespace Resource /// @brief Managing of keyframe resources /// @note May be used from any thread. - class KeyframeManager + class KeyframeManager : public ResourceManager { public: KeyframeManager(const VFS::Manager* vfs); ~KeyframeManager(); - void clearCache(); - /// Retrieve a read-only keyframe resource by name (case-insensitive). /// @note Throws an exception if the resource is not found. osg::ref_ptr get(const std::string& name); - - private: - osg::ref_ptr mCache; - - const VFS::Manager* mVFS; }; } diff --git a/components/resource/niffilemanager.cpp b/components/resource/niffilemanager.cpp index 1d8019b69..3c7437520 100644 --- a/components/resource/niffilemanager.cpp +++ b/components/resource/niffilemanager.cpp @@ -29,9 +29,9 @@ namespace Resource }; NifFileManager::NifFileManager(const VFS::Manager *vfs) - : mVFS(vfs) + : ResourceManager(vfs, 0.0) // NIF files aren't needed any more when the converted objects are cached in SceneManager / BulletShapeManager, + // so we'll use expiryDelay of 0 to instantly delete NIF files after use. { - mCache = new osgDB::ObjectCache; } NifFileManager::~NifFileManager() @@ -39,12 +39,6 @@ namespace Resource } - void NifFileManager::clearCache() - { - // NIF files aren't needed any more when the converted objects are cached in SceneManager / BulletShapeManager, - // so we'll simply drop all nif files here, unlikely to need them again - mCache->clear(); - } Nif::NIFFilePtr NifFileManager::get(const std::string &name) { diff --git a/components/resource/niffilemanager.hpp b/components/resource/niffilemanager.hpp index 4551cf227..4b43ff24b 100644 --- a/components/resource/niffilemanager.hpp +++ b/components/resource/niffilemanager.hpp @@ -5,39 +5,23 @@ #include -namespace VFS -{ - class Manager; -} - -namespace osgDB -{ - class ObjectCache; -} +#include "resourcemanager.hpp" namespace Resource { /// @brief Handles caching of NIFFiles. /// @note May be used from any thread. - class NifFileManager + class NifFileManager : public ResourceManager { public: NifFileManager(const VFS::Manager* vfs); ~NifFileManager(); - void clearCache(); - /// Retrieve a NIF file from the cache, or load it from the VFS if not cached yet. /// @note For performance reasons the NifFileManager does not handle case folding, needs /// to be done in advance by other managers accessing the NifFileManager. Nif::NIFFilePtr get(const std::string& name); - - private: - // Use the osgDB::ObjectCache so objects are retrieved in thread safe way - osg::ref_ptr mCache; - - const VFS::Manager* mVFS; }; } diff --git a/components/resource/resourcemanager.cpp b/components/resource/resourcemanager.cpp new file mode 100644 index 000000000..60233baa0 --- /dev/null +++ b/components/resource/resourcemanager.cpp @@ -0,0 +1,34 @@ +#include "resourcemanager.hpp" + +#include "objectcache.hpp" + +namespace Resource +{ + + ResourceManager::ResourceManager(const VFS::Manager *vfs, const double expiryDelay) + : mVFS(vfs) + , mCache(new osgDB::ObjectCache) + , mExpiryDelay(expiryDelay) + { + + } + + void ResourceManager::updateCache(double referenceTime) + { + // NOTE: we could clear the cache from the background thread if the deletion proves too much of an overhead + // idea: customize objectCache to not hold a lock while doing the actual deletion + mCache->updateTimeStampOfObjectsInCacheWithExternalReferences(referenceTime); + mCache->removeExpiredObjectsInCache(referenceTime - mExpiryDelay); + } + + void ResourceManager::clearCache() + { + mCache->clear(); + } + + const VFS::Manager* ResourceManager::getVFS() const + { + return mVFS; + } + +} diff --git a/components/resource/resourcemanager.hpp b/components/resource/resourcemanager.hpp new file mode 100644 index 000000000..e45a2e9cb --- /dev/null +++ b/components/resource/resourcemanager.hpp @@ -0,0 +1,43 @@ +#ifndef OPENMW_COMPONENTS_RESOURCE_MANAGER_H +#define OPENMW_COMPONENTS_RESOURCE_MANAGER_H + +#include + +namespace VFS +{ + class Manager; +} + +namespace osgDB +{ + class ObjectCache; +} + +namespace Resource +{ + + /// @brief Base class for managers that require a virtual file system and object cache. + /// @par This base class implements clearing of the cache, but populating it and what it's used for is up to the individual sub classes. + class ResourceManager + { + public: + /// @param expiryDelay how long to keep objects in cache after no longer being referenced. + ResourceManager(const VFS::Manager* vfs, const double expiryDelay = 300.0); + + /// Clear cache entries that have not been referenced for longer than expiryDelay. + virtual void updateCache(double referenceTime); + + /// Clear all cache entries regardless of having external references. + virtual void clearCache(); + + const VFS::Manager* getVFS() const; + + protected: + const VFS::Manager* mVFS; + osg::ref_ptr mCache; + double mExpiryDelay; + }; + +} + +#endif diff --git a/components/resource/resourcesystem.cpp b/components/resource/resourcesystem.cpp index d39a723d6..f499c0016 100644 --- a/components/resource/resourcesystem.cpp +++ b/components/resource/resourcesystem.cpp @@ -15,11 +15,21 @@ namespace Resource mKeyframeManager.reset(new KeyframeManager(vfs)); mImageManager.reset(new ImageManager(vfs)); mSceneManager.reset(new SceneManager(vfs, mImageManager.get(), mNifFileManager.get())); + + addResourceManager(mNifFileManager.get()); + addResourceManager(mKeyframeManager.get()); + // note, scene references images so add images afterwards for correct implementation of updateCache() + addResourceManager(mSceneManager.get()); + addResourceManager(mImageManager.get()); } ResourceSystem::~ResourceSystem() { // this has to be defined in the .cpp file as we can't delete incomplete types + + mResourceManagers.clear(); + + // no delete, all handled by auto_ptr } SceneManager* ResourceSystem::getSceneManager() @@ -42,9 +52,24 @@ namespace Resource return mKeyframeManager.get(); } - void ResourceSystem::clearCache() + void ResourceSystem::updateCache(double referenceTime) + { + osg::Timer timer; + for (std::vector::iterator it = mResourceManagers.begin(); it != mResourceManagers.end(); ++it) + (*it)->updateCache(referenceTime); + std::cout << "updateCache took " << timer.time_m() << " ms" << std::endl; + } + + void ResourceSystem::addResourceManager(ResourceManager *resourceMgr) + { + mResourceManagers.push_back(resourceMgr); + } + + void ResourceSystem::removeResourceManager(ResourceManager *resourceMgr) { - mNifFileManager->clearCache(); + std::vector::iterator found = std::find(mResourceManagers.begin(), mResourceManagers.end(), resourceMgr); + if (found != mResourceManagers.end()) + mResourceManagers.erase(found); } const VFS::Manager* ResourceSystem::getVFS() const diff --git a/components/resource/resourcesystem.hpp b/components/resource/resourcesystem.hpp index 13a96e8c7..30607432d 100644 --- a/components/resource/resourcesystem.hpp +++ b/components/resource/resourcesystem.hpp @@ -2,6 +2,7 @@ #define OPENMW_COMPONENTS_RESOURCE_RESOURCESYSTEM_H #include +#include namespace VFS { @@ -15,6 +16,7 @@ namespace Resource class ImageManager; class NifFileManager; class KeyframeManager; + class ResourceManager; /// @brief Wrapper class that constructs and provides access to the most commonly used resource subsystems. /// @par Resource subsystems can be used with multiple OpenGL contexts, just like the OSG equivalents, but @@ -31,8 +33,17 @@ namespace Resource KeyframeManager* getKeyframeManager(); /// Indicates to each resource manager to clear the cache, i.e. to drop cached objects that are no longer referenced. - void clearCache(); + /// @note May be called from any thread if you do not add or remove resource managers at that point. + void updateCache(double referenceTime); + /// Add this ResourceManager to be handled by the ResourceSystem. + /// @note Does not transfer ownership. + void addResourceManager(ResourceManager* resourceMgr); + /// @note Do nothing if resourceMgr does not exist. + /// @note Does not delete resourceMgr. + void removeResourceManager(ResourceManager* resourceMgr); + + /// @note May be called from any thread. const VFS::Manager* getVFS() const; private: @@ -41,6 +52,10 @@ namespace Resource std::auto_ptr mNifFileManager; std::auto_ptr mKeyframeManager; + // Store the base classes separately to get convenient access to the common interface + // Here users can register their own resourcemanager as well + std::vector mResourceManagers; + const VFS::Manager* mVFS; ResourceSystem(const ResourceSystem&); diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index 95e03b389..4ed14241a 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -230,7 +230,7 @@ namespace Resource SceneManager::SceneManager(const VFS::Manager *vfs, Resource::ImageManager* imageManager, Resource::NifFileManager* nifFileManager) - : mVFS(vfs) + : ResourceManager(vfs) , mImageManager(imageManager) , mNifFileManager(nifFileManager) , mMinFilter(osg::Texture::LINEAR_MIPMAP_LINEAR) @@ -238,7 +238,6 @@ namespace Resource , mMaxAnisotropy(1) , mUnRefImageDataAfterApply(false) , mParticleSystemMask(~0u) - , mCache(new osgDB::ObjectCache) { } @@ -403,11 +402,6 @@ namespace Resource node->accept(visitor); } - const VFS::Manager* SceneManager::getVFS() const - { - return mVFS; - } - Resource::ImageManager* SceneManager::getImageManager() { return mImageManager; @@ -483,5 +477,4 @@ namespace Resource mUnRefImageDataAfterApply = unref; } - } diff --git a/components/resource/scenemanager.hpp b/components/resource/scenemanager.hpp index 32bd80660..173131e66 100644 --- a/components/resource/scenemanager.hpp +++ b/components/resource/scenemanager.hpp @@ -8,27 +8,19 @@ #include #include +#include "resourcemanager.hpp" + namespace Resource { class ImageManager; class NifFileManager; } -namespace VFS -{ - class Manager; -} - namespace osgUtil { class IncrementalCompileOperation; } -namespace osgDB -{ - class ObjectCache; -} - namespace osgViewer { class Viewer; @@ -39,7 +31,7 @@ namespace Resource /// @brief Handles loading and caching of scenes, e.g. .nif files or .osg files /// @note Some methods of the scene manager can be used from any thread, see the methods documentation for more details. - class SceneManager + class SceneManager : public ResourceManager { public: SceneManager(const VFS::Manager* vfs, Resource::ImageManager* imageManager, Resource::NifFileManager* nifFileManager); @@ -78,8 +70,6 @@ namespace Resource /// @note SceneManager::attachTo calls this method automatically, only needs to be called by users if manually attaching void notifyAttached(osg::Node* node) const; - const VFS::Manager* getVFS() const; - Resource::ImageManager* getImageManager(); /// @param mask The node mask to apply to loaded particle system nodes. @@ -99,7 +89,6 @@ namespace Resource void setUnRefImageDataAfterApply(bool unref); private: - const VFS::Manager* mVFS; Resource::ImageManager* mImageManager; Resource::NifFileManager* mNifFileManager; @@ -112,8 +101,6 @@ namespace Resource unsigned int mParticleSystemMask; - osg::ref_ptr mCache; - SceneManager(const SceneManager&); void operator = (const SceneManager&); }; diff --git a/components/vfs/manager.hpp b/components/vfs/manager.hpp index f74914977..6592a65a8 100644 --- a/components/vfs/manager.hpp +++ b/components/vfs/manager.hpp @@ -16,6 +16,7 @@ namespace VFS /// @par Various archive types (e.g. directories on the filesystem, or compressed archives) /// can be registered, and will be merged into a single file tree. If the same filename is /// contained in multiple archives, the last added archive will have priority. + /// @par Most of the methods in this class are considered thread-safe, see each method documentation for details. class Manager { public: @@ -33,20 +34,25 @@ namespace VFS void buildIndex(); /// Does a file with this name exist? + /// @note May be called from any thread once the index has been built. bool exists(const std::string& name) const; /// Get a complete list of files from all archives + /// @note May be called from any thread once the index has been built. const std::map& getIndex() const; /// Normalize the given filename, making slashes/backslashes consistent, and lower-casing if mStrict is false. + /// @note May be called from any thread once the index has been built. void normalizeFilename(std::string& name) const; /// Retrieve a file by name. /// @note Throws an exception if the file can not be found. + /// @note May be called from any thread once the index has been built. Files::IStreamPtr get(const std::string& name) const; /// Retrieve a file by name (name is already normalized). /// @note Throws an exception if the file can not be found. + /// @note May be called from any thread once the index has been built. Files::IStreamPtr getNormalized(const std::string& normalizedName) const; private: From b7e69cbc64fafd1f8ae255c4425f0e3b5cdcdd6e Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 6 Feb 2016 22:29:06 +0100 Subject: [PATCH 3090/3725] Refactor WorkQueue, merge WorkTicket and WorkItem Allow the caller to hold on to the WorkItem. This makes it possible for a derived WorkItem to store the result of the work within the WorkItem itself. --- components/sceneutil/workqueue.cpp | 39 ++++++++--------- components/sceneutil/workqueue.hpp | 69 ++++++++++++++---------------- 2 files changed, 49 insertions(+), 59 deletions(-) diff --git a/components/sceneutil/workqueue.cpp b/components/sceneutil/workqueue.cpp index 26a392be4..bb1d1f1f7 100644 --- a/components/sceneutil/workqueue.cpp +++ b/components/sceneutil/workqueue.cpp @@ -1,9 +1,11 @@ #include "workqueue.hpp" +#include + namespace SceneUtil { -void WorkTicket::waitTillDone() +void WorkItem::waitTillDone() { if (mDone > 0) return; @@ -15,7 +17,7 @@ void WorkTicket::waitTillDone() } } -void WorkTicket::signalDone() +void WorkItem::signalDone() { { OpenThreads::ScopedLock lock(mMutex); @@ -25,23 +27,16 @@ void WorkTicket::signalDone() } WorkItem::WorkItem() - : mTicket(new WorkTicket) { - mTicket->setThreadSafeRefUnref(true); } WorkItem::~WorkItem() { } -void WorkItem::doWork() -{ - mTicket->signalDone(); -} - -osg::ref_ptr WorkItem::getTicket() +bool WorkItem::isDone() const { - return mTicket; + return (mDone > 0); } WorkQueue::WorkQueue(int workerThreads) @@ -60,11 +55,7 @@ WorkQueue::~WorkQueue() { OpenThreads::ScopedLock lock(mMutex); while (!mQueue.empty()) - { - WorkItem* item = mQueue.front(); - delete item; mQueue.pop(); - } mIsReleased = true; mCondition.broadcast(); } @@ -76,16 +67,20 @@ WorkQueue::~WorkQueue() } } -osg::ref_ptr WorkQueue::addWorkItem(WorkItem *item) +void WorkQueue::addWorkItem(osg::ref_ptr item) { - osg::ref_ptr ticket = item->getTicket(); + if (item->isDone()) + { + std::cerr << "warning, trying to add a work item that is already completed" << std::endl; + return; + } + OpenThreads::ScopedLock lock(mMutex); mQueue.push(item); mCondition.signal(); - return ticket; } -WorkItem *WorkQueue::removeWorkItem() +osg::ref_ptr WorkQueue::removeWorkItem() { OpenThreads::ScopedLock lock(mMutex); while (mQueue.empty() && !mIsReleased) @@ -94,7 +89,7 @@ WorkItem *WorkQueue::removeWorkItem() } if (mQueue.size()) { - WorkItem* item = mQueue.front(); + osg::ref_ptr item = mQueue.front(); mQueue.pop(); return item; } @@ -111,11 +106,11 @@ void WorkThread::run() { while (true) { - WorkItem* item = mWorkQueue->removeWorkItem(); + osg::ref_ptr item = mWorkQueue->removeWorkItem(); if (!item) return; item->doWork(); - delete item; + item->signalDone(); } } diff --git a/components/sceneutil/workqueue.hpp b/components/sceneutil/workqueue.hpp index 492bbd090..06489dfbb 100644 --- a/components/sceneutil/workqueue.hpp +++ b/components/sceneutil/workqueue.hpp @@ -14,69 +14,53 @@ namespace SceneUtil { - class WorkTicket : public osg::Referenced - { - public: - void waitTillDone(); - - void signalDone(); - - private: - OpenThreads::Atomic mDone; - OpenThreads::Mutex mMutex; - OpenThreads::Condition mCondition; - }; - - class WorkItem + class WorkItem : public osg::Referenced { public: WorkItem(); virtual ~WorkItem(); /// Override in a derived WorkItem to perform actual work. - /// By default, just signals the ticket that the work is done. - virtual void doWork(); + virtual void doWork() {} + + bool isDone() const; - osg::ref_ptr getTicket(); + /// Wait until the work is completed. Usually called from the main thread. + void waitTillDone(); + + /// Internal use by the WorkQueue. + void signalDone(); protected: - osg::ref_ptr mTicket; + OpenThreads::Atomic mDone; + OpenThreads::Mutex mMutex; + OpenThreads::Condition mCondition; }; class WorkQueue; - - class WorkThread : public OpenThreads::Thread - { - public: - WorkThread(WorkQueue* workQueue); - - virtual void run(); - - private: - WorkQueue* mWorkQueue; - }; + class WorkThread; /// @brief A work queue that users can push work items onto, to be completed by one or more background threads. - class WorkQueue + /// @note Work items will be processed in the order that they were given in, however + /// if multiple work threads are involved then it is possible for a later item to complete before earlier items. + class WorkQueue : public osg::Referenced { public: WorkQueue(int numWorkerThreads=1); ~WorkQueue(); /// Add a new work item to the back of the queue. - /// @par The returned WorkTicket may be used by the caller to wait until the work is complete. - osg::ref_ptr addWorkItem(WorkItem* item); + /// @par The work item's waitTillDone() method may be used by the caller to wait until the work is complete. + void addWorkItem(osg::ref_ptr item); /// Get the next work item from the front of the queue. If the queue is empty, waits until a new item is added. /// If the workqueue is in the process of being destroyed, may return NULL. - /// @note The caller must free the returned WorkItem - WorkItem* removeWorkItem(); - - void runThread(); + /// @par Used internally by the WorkThread. + osg::ref_ptr removeWorkItem(); private: bool mIsReleased; - std::queue mQueue; + std::queue > mQueue; OpenThreads::Mutex mMutex; OpenThreads::Condition mCondition; @@ -84,6 +68,17 @@ namespace SceneUtil std::vector mThreads; }; + /// Internally used by WorkQueue. + class WorkThread : public OpenThreads::Thread + { + public: + WorkThread(WorkQueue* workQueue); + + virtual void run(); + + private: + WorkQueue* mWorkQueue; + }; } From e055ae094aeab055caecb04c3d898656c656406b Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 6 Feb 2016 23:30:41 +0100 Subject: [PATCH 3091/3725] Improve const-correctness in BulletShapeManager Sadly, two const_cast's are needed to work around Bullet API quirks. --- components/resource/bulletshape.cpp | 26 ++++++++++------------ components/resource/bulletshape.hpp | 8 +++---- components/resource/bulletshapemanager.cpp | 9 ++++++-- components/resource/bulletshapemanager.hpp | 3 +++ 4 files changed, 26 insertions(+), 20 deletions(-) diff --git a/components/resource/bulletshape.cpp b/components/resource/bulletshape.cpp index baff86a79..6855429c3 100644 --- a/components/resource/bulletshape.cpp +++ b/components/resource/bulletshape.cpp @@ -45,11 +45,11 @@ void BulletShape::deleteShape(btCollisionShape* shape) } } -btCollisionShape* BulletShape::duplicateCollisionShape(btCollisionShape *shape) const +btCollisionShape* BulletShape::duplicateCollisionShape(const btCollisionShape *shape) const { if(shape->isCompound()) { - btCompoundShape *comp = static_cast(shape); + const btCompoundShape *comp = static_cast(shape); btCompoundShape *newShape = new btCompoundShape; int numShapes = comp->getNumChildShapes(); @@ -63,29 +63,27 @@ btCollisionShape* BulletShape::duplicateCollisionShape(btCollisionShape *shape) return newShape; } - if(btBvhTriangleMeshShape* trishape = dynamic_cast(shape)) + if(const btBvhTriangleMeshShape* trishape = dynamic_cast(shape)) { #if BT_BULLET_VERSION >= 283 - btScaledBvhTriangleMeshShape* newShape = new btScaledBvhTriangleMeshShape(trishape, btVector3(1.f, 1.f, 1.f)); + btScaledBvhTriangleMeshShape* newShape = new btScaledBvhTriangleMeshShape(const_cast(trishape), btVector3(1.f, 1.f, 1.f)); #else // work around btScaledBvhTriangleMeshShape bug ( https://code.google.com/p/bullet/issues/detail?id=371 ) in older bullet versions - btTriangleMesh* oldMesh = static_cast(trishape->getMeshInterface()); + const btTriangleMesh* oldMesh = static_cast(trishape->getMeshInterface()); btTriangleMesh* newMesh = new btTriangleMesh(*oldMesh); // Do not build a new bvh (not needed, since it's the same as the original shape's bvh) - bool buildBvh = true; - if (trishape->getOptimizedBvh()) - buildBvh = false; - TriangleMeshShape* newShape = new TriangleMeshShape(newMesh, true, buildBvh); + btOptimizedBvh* bvh = const_cast(trishape)->getOptimizedBvh(); + TriangleMeshShape* newShape = new TriangleMeshShape(newMesh, true, bvh == NULL); // Set original shape's bvh via pointer // The pointer is safe because the BulletShapeInstance keeps a ref_ptr to the original BulletShape - if (!buildBvh) - newShape->setOptimizedBvh(trishape->getOptimizedBvh()); + if (bvh) + newShape->setOptimizedBvh(bvh); #endif return newShape; } - if (btBoxShape* boxshape = dynamic_cast(shape)) + if (const btBoxShape* boxshape = dynamic_cast(shape)) { return new btBoxShape(*boxshape); } @@ -98,13 +96,13 @@ btCollisionShape *BulletShape::getCollisionShape() return mCollisionShape; } -osg::ref_ptr BulletShape::makeInstance() +osg::ref_ptr BulletShape::makeInstance() const { osg::ref_ptr instance (new BulletShapeInstance(this)); return instance; } -BulletShapeInstance::BulletShapeInstance(osg::ref_ptr source) +BulletShapeInstance::BulletShapeInstance(osg::ref_ptr source) : BulletShape() , mSource(source) { diff --git a/components/resource/bulletshape.hpp b/components/resource/bulletshape.hpp index a007bad31..a418bb28c 100644 --- a/components/resource/bulletshape.hpp +++ b/components/resource/bulletshape.hpp @@ -38,9 +38,9 @@ namespace Resource // we store the node's record index mapped to the child index of the shape in the btCompoundShape. std::map mAnimatedShapes; - osg::ref_ptr makeInstance(); + osg::ref_ptr makeInstance() const; - btCollisionShape* duplicateCollisionShape(btCollisionShape* shape) const; + btCollisionShape* duplicateCollisionShape(const btCollisionShape* shape) const; btCollisionShape* getCollisionShape(); @@ -55,10 +55,10 @@ namespace Resource class BulletShapeInstance : public BulletShape { public: - BulletShapeInstance(osg::ref_ptr source); + BulletShapeInstance(osg::ref_ptr source); private: - osg::ref_ptr mSource; + osg::ref_ptr mSource; }; // Subclass btBhvTriangleMeshShape to auto-delete the meshInterface diff --git a/components/resource/bulletshapemanager.cpp b/components/resource/bulletshapemanager.cpp index b5581cce2..cb57d686f 100644 --- a/components/resource/bulletshapemanager.cpp +++ b/components/resource/bulletshapemanager.cpp @@ -109,7 +109,7 @@ BulletShapeManager::~BulletShapeManager() } -osg::ref_ptr BulletShapeManager::createInstance(const std::string &name) +osg::ref_ptr BulletShapeManager::getShape(const std::string &name) { std::string normalized = name; mVFS->normalizeFilename(normalized); @@ -142,13 +142,18 @@ osg::ref_ptr BulletShapeManager::createInstance(const std:: if (!shape) { mCache->addEntryToObjectCache(normalized, NULL); - return osg::ref_ptr(); + return osg::ref_ptr(); } } mCache->addEntryToObjectCache(normalized, shape); } + return shape; +} +osg::ref_ptr BulletShapeManager::createInstance(const std::string &name) +{ + osg::ref_ptr shape = getShape(name); if (shape) return shape->makeInstance(); else diff --git a/components/resource/bulletshapemanager.hpp b/components/resource/bulletshapemanager.hpp index 576268f75..4c0cb1fd2 100644 --- a/components/resource/bulletshapemanager.hpp +++ b/components/resource/bulletshapemanager.hpp @@ -26,6 +26,9 @@ namespace Resource BulletShapeManager(const VFS::Manager* vfs, SceneManager* sceneMgr, NifFileManager* nifFileManager); ~BulletShapeManager(); + osg::ref_ptr getShape(const std::string& name); + + /// Shorthand for getShape(name)->makeInstance(); osg::ref_ptr createInstance(const std::string& name); private: From 6f9ca0f68fd76bfd1abef2f9e5ae0131b8a64e89 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 7 Feb 2016 00:07:02 +0100 Subject: [PATCH 3092/3725] Add basic cell preloader class Not properly in use yet, but seems to be working. --- apps/openmw/CMakeLists.txt | 1 + apps/openmw/mwphysics/physicssystem.cpp | 5 + apps/openmw/mwphysics/physicssystem.hpp | 2 + apps/openmw/mwworld/cellpreloader.cpp | 148 ++++++++++++++++++++++++ apps/openmw/mwworld/cellpreloader.hpp | 60 ++++++++++ apps/openmw/mwworld/cellstore.cpp | 5 + apps/openmw/mwworld/cellstore.hpp | 3 + components/CMakeLists.txt | 4 +- components/resource/resourcesystem.cpp | 3 + 9 files changed, 228 insertions(+), 3 deletions(-) create mode 100644 apps/openmw/mwworld/cellpreloader.cpp create mode 100644 apps/openmw/mwworld/cellpreloader.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 02cf6c87d..f2540c739 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -67,6 +67,7 @@ add_openmw_dir (mwworld actionequip timestamp actionalchemy cellstore actionapply actioneat store esmstore recordcmp fallback actionrepair actionsoulgem livecellref actiondoor contentloader esmloader actiontrap cellreflist cellref physicssystem weather projectilemanager + cellpreloader ) add_openmw_dir (mwphysics diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 11d6d286a..6417968d3 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -690,6 +690,11 @@ namespace MWPhysics delete mBroadphase; } + Resource::BulletShapeManager *PhysicsSystem::getShapeManager() + { + return mShapeManager.get(); + } + bool PhysicsSystem::toggleDebugRendering() { mDebugDrawEnabled = !mDebugDrawEnabled; diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index 4263bc0ec..a866717c7 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -53,6 +53,8 @@ namespace MWPhysics PhysicsSystem (Resource::ResourceSystem* resourceSystem, osg::ref_ptr parentNode); ~PhysicsSystem (); + Resource::BulletShapeManager* getShapeManager(); + void enableWater(float height); void setWaterHeight(float height); void disableWater(); diff --git a/apps/openmw/mwworld/cellpreloader.cpp b/apps/openmw/mwworld/cellpreloader.cpp new file mode 100644 index 000000000..dd6850aba --- /dev/null +++ b/apps/openmw/mwworld/cellpreloader.cpp @@ -0,0 +1,148 @@ +#include "cellpreloader.hpp" + +#include + +#include +#include + +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" + +#include "cellstore.hpp" +#include "manualref.hpp" +#include "class.hpp" + +namespace MWWorld +{ + + struct ListModelsVisitor + { + ListModelsVisitor(std::vector& out) + : mOut(out) + { + } + + virtual bool operator()(const MWWorld::ConstPtr& ptr) + { + std::string model = ptr.getClass().getModel(ptr); + if (!model.empty()) + mOut.push_back(model); + return true; + } + + std::vector& mOut; + }; + + class PreloadItem : public SceneUtil::WorkItem + { + public: + /// Constructor to be called from the main thread. + PreloadItem(const MWWorld::CellStore* cell, Resource::SceneManager* sceneManager, Resource::BulletShapeManager* bulletShapeManager) + : mSceneManager(sceneManager) + , mBulletShapeManager(bulletShapeManager) + { + if (cell->getState() == MWWorld::CellStore::State_Loaded) + { + ListModelsVisitor visitor (mMeshes); + cell->forEachConst(visitor); + } + else + { + const std::vector& objectIds = cell->getPreloadedIds(); + + // could possibly build the model list in the worker thread if we manage to make the Store thread safe + for (std::vector::const_iterator it = objectIds.begin(); it != objectIds.end(); ++it) + { + MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), *it); + std::string model = ref.getPtr().getClass().getModel(ref.getPtr()); + if (!model.empty()) + mMeshes.push_back(model); + } + } + } + + /// Preload work to be called from the worker thread. + virtual void doWork() + { + for (MeshList::const_iterator it = mMeshes.begin(); it != mMeshes.end(); ++it) + { + try + { + mPreloadedNodes.push_back(mSceneManager->getTemplate(*it)); + mPreloadedShapes.push_back(mBulletShapeManager->getShape(*it)); + + // TODO: do a createInstance() and hold on to it since we can make use of it when the cell goes active + } + catch (std::exception& e) + { + // ignore error for now, would spam the log too much + // error will be shown when visiting the cell + } + } + } + + private: + typedef std::vector MeshList; + MeshList mMeshes; + Resource::SceneManager* mSceneManager; + Resource::BulletShapeManager* mBulletShapeManager; + + // keep a ref to the loaded object to make sure it stays loaded as long as this cell is in the preloaded state + std::vector > mPreloadedNodes; + std::vector > mPreloadedShapes; + }; + + CellPreloader::CellPreloader(Resource::SceneManager *sceneManager, Resource::BulletShapeManager* bulletShapeManager) + : mSceneManager(sceneManager) + , mBulletShapeManager(bulletShapeManager) + { + mWorkQueue = new SceneUtil::WorkQueue; + } + + void CellPreloader::preload(const CellStore *cell, double timestamp) + { + if (!mWorkQueue) + { + std::cerr << "can't preload, no work queue set " << std::endl; + return; + } + if (cell->getState() == CellStore::State_Unloaded) + { + std::cerr << "can't preload objects for unloaded cell" << std::endl; + return; + } + + PreloadMap::iterator found = mPreloadCells.find(cell); + if (found != mPreloadCells.end()) + { + // already preloaded, nothing to do other than updating the timestamp + found->second.mTimeStamp = timestamp; + return; + } + + osg::ref_ptr item (new PreloadItem(cell, mSceneManager, mBulletShapeManager)); + mWorkQueue->addWorkItem(item); + + mPreloadCells[cell] = PreloadEntry(timestamp, item); + } + + void CellPreloader::updateCache(double timestamp) + { + // time (in seconds) to keep a preloaded cell in cache after it's no longer needed + const double expiryTime = 60.0; + + for (PreloadMap::iterator it = mPreloadCells.begin(); it != mPreloadCells.end();) + { + if (it->second.mTimeStamp < timestamp - expiryTime) + mPreloadCells.erase(it++); + else + ++it; + } + } + + void CellPreloader::setWorkQueue(osg::ref_ptr workQueue) + { + mWorkQueue = workQueue; + } + +} diff --git a/apps/openmw/mwworld/cellpreloader.hpp b/apps/openmw/mwworld/cellpreloader.hpp new file mode 100644 index 000000000..7e02cb7d1 --- /dev/null +++ b/apps/openmw/mwworld/cellpreloader.hpp @@ -0,0 +1,60 @@ +#ifndef OPENMW_MWWORLD_CELLPRELOADER_H +#define OPENMW_MWWORLD_CELLPRELOADER_H + +#include +#include +#include + +namespace Resource +{ + class SceneManager; + class BulletShapeManager; +} + +namespace MWWorld +{ + class CellStore; + + class CellPreloader + { + public: + CellPreloader(Resource::SceneManager* sceneManager, Resource::BulletShapeManager* bulletShapeManager); + + /// Ask a background thread to preload rendering meshes and collision shapes for objects in this cell. + /// @note The cell itself must be in State_Loaded or State_Preloaded. + void preload(const MWWorld::CellStore* cell, double timestamp); + + /// Removes preloaded cells that have not had a preload request for a while. + void updateCache(double timestamp); + + void setWorkQueue(osg::ref_ptr workQueue); + + private: + Resource::SceneManager* mSceneManager; + Resource::BulletShapeManager* mBulletShapeManager; + osg::ref_ptr mWorkQueue; + + struct PreloadEntry + { + PreloadEntry(double timestamp, osg::ref_ptr workItem) + : mTimeStamp(timestamp) + , mWorkItem(workItem) + { + } + PreloadEntry() + : mTimeStamp(0.0) + { + } + + double mTimeStamp; + osg::ref_ptr mWorkItem; + }; + typedef std::map PreloadMap; + + // Cells that are currently being preloaded, or have already finished preloading + PreloadMap mPreloadCells; + }; + +} + +#endif diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 5c8d07f86..dcaa73e93 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -333,6 +333,11 @@ namespace MWWorld return mState; } + const std::vector &CellStore::getPreloadedIds() const + { + return mIds; + } + bool CellStore::hasState() const { return mHasState; diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index 2f483f0ba..d753c9745 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -204,6 +204,9 @@ namespace MWWorld State getState() const; + const std::vector& getPreloadedIds() const; + ///< Get Ids of objects in this cell, only valid in State_Preloaded + bool hasState() const; ///< Does this cell have state that needs to be stored in a saved game file? diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 42323a68a..26e8f7b6a 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -46,9 +46,7 @@ add_component_dir (resource add_component_dir (sceneutil clone attach visitor util statesetupdater controller skeleton riggeometry lightcontroller - lightmanager lightutil positionattitudetransform - # not used yet - #workqueue + lightmanager lightutil positionattitudetransform workqueue ) add_component_dir (nif diff --git a/components/resource/resourcesystem.cpp b/components/resource/resourcesystem.cpp index f499c0016..68ed13644 100644 --- a/components/resource/resourcesystem.cpp +++ b/components/resource/resourcesystem.cpp @@ -54,6 +54,9 @@ namespace Resource void ResourceSystem::updateCache(double referenceTime) { + // TODO: call updateCache from the worker thread so the main thread isn't held up by the delete operations + // change ObjectCache to not hold lock while the unref happens + osg::Timer timer; for (std::vector::iterator it = mResourceManagers.begin(); it != mResourceManagers.end(); ++it) (*it)->updateCache(referenceTime); From d855a13b4435d989ebf46346e71437782c231a7f Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 7 Feb 2016 00:36:31 +0100 Subject: [PATCH 3093/3725] Clear the resource cache from the worker thread --- apps/openmw/mwrender/renderingmanager.cpp | 6 +++- apps/openmw/mwrender/renderingmanager.hpp | 2 ++ apps/openmw/mwworld/cellpreloader.cpp | 34 +++++++++++++++++++++-- apps/openmw/mwworld/cellpreloader.hpp | 6 ++-- apps/openmw/mwworld/scene.cpp | 4 +++ apps/openmw/mwworld/scene.hpp | 5 ++-- components/resource/resourcesystem.cpp | 6 +--- 7 files changed, 49 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index d4199d5f6..07b477c43 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -233,11 +233,15 @@ namespace MWRender void RenderingManager::clearCache() { - mResourceSystem->updateCache(mViewer->getFrameStamp()->getReferenceTime()); if (mTerrain.get()) mTerrain->clearCache(); } + double RenderingManager::getReferenceTime() const + { + return mViewer->getFrameStamp()->getReferenceTime(); + } + osg::Group* RenderingManager::getLightRoot() { return mLightRoot.get(); diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 550e48e63..bc5db562c 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -67,6 +67,8 @@ namespace MWRender void clearCache(); + double getReferenceTime() const; + osg::Group* getLightRoot(); void setNightEyeFactor(float factor); diff --git a/apps/openmw/mwworld/cellpreloader.cpp b/apps/openmw/mwworld/cellpreloader.cpp index dd6850aba..16bf920bb 100644 --- a/apps/openmw/mwworld/cellpreloader.cpp +++ b/apps/openmw/mwworld/cellpreloader.cpp @@ -3,6 +3,7 @@ #include #include +#include #include #include "../mwbase/environment.hpp" @@ -33,6 +34,7 @@ namespace MWWorld std::vector& mOut; }; + /// Worker thread item: preload models in a cell. class PreloadItem : public SceneUtil::WorkItem { public: @@ -92,8 +94,30 @@ namespace MWWorld std::vector > mPreloadedShapes; }; - CellPreloader::CellPreloader(Resource::SceneManager *sceneManager, Resource::BulletShapeManager* bulletShapeManager) - : mSceneManager(sceneManager) + /// Worker thread item: update the resource system's cache, effectively deleting unused entries. + class UpdateCacheItem : public SceneUtil::WorkItem + { + public: + UpdateCacheItem(Resource::ResourceSystem* resourceSystem, double referenceTime) + : mReferenceTime(referenceTime) + , mResourceSystem(resourceSystem) + { + } + + virtual void doWork() + { + osg::Timer timer; + mResourceSystem->updateCache(mReferenceTime); + std::cout << "cleared cache in " << timer.time_m() << std::endl; + } + + private: + double mReferenceTime; + Resource::ResourceSystem* mResourceSystem; + }; + + CellPreloader::CellPreloader(Resource::ResourceSystem* resourceSystem, Resource::BulletShapeManager* bulletShapeManager) + : mResourceSystem(resourceSystem) , mBulletShapeManager(bulletShapeManager) { mWorkQueue = new SceneUtil::WorkQueue; @@ -120,7 +144,7 @@ namespace MWWorld return; } - osg::ref_ptr item (new PreloadItem(cell, mSceneManager, mBulletShapeManager)); + osg::ref_ptr item (new PreloadItem(cell, mResourceSystem->getSceneManager(), mBulletShapeManager)); mWorkQueue->addWorkItem(item); mPreloadCells[cell] = PreloadEntry(timestamp, item); @@ -129,6 +153,7 @@ namespace MWWorld void CellPreloader::updateCache(double timestamp) { // time (in seconds) to keep a preloaded cell in cache after it's no longer needed + // additionally we could support a minimum/maximum size for the cache const double expiryTime = 60.0; for (PreloadMap::iterator it = mPreloadCells.begin(); it != mPreloadCells.end();) @@ -138,6 +163,9 @@ namespace MWWorld else ++it; } + + // the resource cache is cleared from the worker thread so that we're not holding up the main thread with delete operations + mWorkQueue->addWorkItem(new UpdateCacheItem(mResourceSystem, timestamp)); } void CellPreloader::setWorkQueue(osg::ref_ptr workQueue) diff --git a/apps/openmw/mwworld/cellpreloader.hpp b/apps/openmw/mwworld/cellpreloader.hpp index 7e02cb7d1..b3413b174 100644 --- a/apps/openmw/mwworld/cellpreloader.hpp +++ b/apps/openmw/mwworld/cellpreloader.hpp @@ -7,7 +7,7 @@ namespace Resource { - class SceneManager; + class ResourceSystem; class BulletShapeManager; } @@ -18,7 +18,7 @@ namespace MWWorld class CellPreloader { public: - CellPreloader(Resource::SceneManager* sceneManager, Resource::BulletShapeManager* bulletShapeManager); + CellPreloader(Resource::ResourceSystem* resourceSystem, Resource::BulletShapeManager* bulletShapeManager); /// Ask a background thread to preload rendering meshes and collision shapes for objects in this cell. /// @note The cell itself must be in State_Loaded or State_Preloaded. @@ -30,7 +30,7 @@ namespace MWWorld void setWorkQueue(osg::ref_ptr workQueue); private: - Resource::SceneManager* mSceneManager; + Resource::ResourceSystem* mResourceSystem; Resource::BulletShapeManager* mBulletShapeManager; osg::ref_ptr mWorkQueue; diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index f30e6efe1..70a461b5b 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -24,6 +24,7 @@ #include "class.hpp" #include "cellvisitors.hpp" #include "cellstore.hpp" +#include "cellpreloader.hpp" namespace { @@ -402,6 +403,7 @@ namespace MWWorld mCellChanged = true; + mPreloader->updateCache(mRendering.getReferenceTime()); mRendering.clearCache(); } @@ -439,6 +441,7 @@ namespace MWWorld Scene::Scene (MWRender::RenderingManager& rendering, MWPhysics::PhysicsSystem *physics) : mCurrentCell (0), mCellChanged (false), mPhysics(physics), mRendering(rendering) { + mPreloader.reset(new CellPreloader(rendering.getResourceSystem(), physics->getShapeManager())); } Scene::~Scene() @@ -515,6 +518,7 @@ namespace MWWorld MWBase::Environment::get().getWindowManager()->changeCell(mCurrentCell); + mPreloader->updateCache(mRendering.getReferenceTime()); mRendering.clearCache(); } diff --git a/apps/openmw/mwworld/scene.hpp b/apps/openmw/mwworld/scene.hpp index c6de3ebdf..b428d0ddd 100644 --- a/apps/openmw/mwworld/scene.hpp +++ b/apps/openmw/mwworld/scene.hpp @@ -1,12 +1,11 @@ #ifndef GAME_MWWORLD_SCENE_H #define GAME_MWWORLD_SCENE_H -//#include "../mwrender/renderingmanager.hpp" - #include "ptr.hpp" #include "globals.hpp" #include +#include namespace osg { @@ -43,6 +42,7 @@ namespace MWWorld { class Player; class CellStore; + class CellPreloader; class Scene { @@ -57,6 +57,7 @@ namespace MWWorld bool mCellChanged; MWPhysics::PhysicsSystem *mPhysics; MWRender::RenderingManager& mRendering; + std::auto_ptr mPreloader; void insertCell (CellStore &cell, bool rescale, Loading::Listener* loadingListener); diff --git a/components/resource/resourcesystem.cpp b/components/resource/resourcesystem.cpp index 68ed13644..1f25bd461 100644 --- a/components/resource/resourcesystem.cpp +++ b/components/resource/resourcesystem.cpp @@ -54,13 +54,9 @@ namespace Resource void ResourceSystem::updateCache(double referenceTime) { - // TODO: call updateCache from the worker thread so the main thread isn't held up by the delete operations - // change ObjectCache to not hold lock while the unref happens - - osg::Timer timer; + // TODO: change ObjectCache to not hold lock while the unref happens for (std::vector::iterator it = mResourceManagers.begin(); it != mResourceManagers.end(); ++it) (*it)->updateCache(referenceTime); - std::cout << "updateCache took " << timer.time_m() << " ms" << std::endl; } void ResourceSystem::addResourceManager(ResourceManager *resourceMgr) From c155680d3c8c22ac8dc22ccc540584e3b720990f Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 7 Feb 2016 00:43:37 +0100 Subject: [PATCH 3094/3725] Customize ObjectCache for more efficient locking in removeExpiredObjectsInCache --- components/resource/objectcache.cpp | 37 ++++++++++++++----------- components/resource/objectcache.hpp | 24 ++++++---------- components/resource/resourcemanager.cpp | 2 +- components/resource/resourcemanager.hpp | 8 ++---- components/resource/resourcesystem.cpp | 1 - 5 files changed, 32 insertions(+), 40 deletions(-) diff --git a/components/resource/objectcache.cpp b/components/resource/objectcache.cpp index 7264d05aa..0c6066417 100644 --- a/components/resource/objectcache.cpp +++ b/components/resource/objectcache.cpp @@ -11,13 +11,10 @@ * OpenSceneGraph Public License for more details. */ -#include - -#if OSG_VERSION_LESS_THAN(3,3,3) - #include "objectcache.hpp" -using namespace osgDB; +namespace Resource +{ //////////////////////////////////////////////////////////////////////////////////////////// // @@ -95,21 +92,29 @@ void ObjectCache::updateTimeStampOfObjectsInCacheWithExternalReferences(double r void ObjectCache::removeExpiredObjectsInCache(double expiryTime) { - OpenThreads::ScopedLock lock(_objectCacheMutex); + std::vector > objectsToRemove; - // Remove expired entries from object cache - ObjectCacheMap::iterator oitr = _objectCache.begin(); - while(oitr != _objectCache.end()) { - if (oitr->second.second<=expiryTime) - { - _objectCache.erase(oitr++); - } - else + OpenThreads::ScopedLock lock(_objectCacheMutex); + + // Remove expired entries from object cache + ObjectCacheMap::iterator oitr = _objectCache.begin(); + while(oitr != _objectCache.end()) { - ++oitr; + if (oitr->second.second<=expiryTime) + { + objectsToRemove.push_back(oitr->second.first); + _objectCache.erase(oitr++); + } + else + { + ++oitr; + } } } + + // note, actual unref happens outside of the lock + objectsToRemove.clear(); } void ObjectCache::removeFromObjectCache(const std::string& fileName) @@ -138,4 +143,4 @@ void ObjectCache::releaseGLObjects(osg::State* state) } } -#endif +} diff --git a/components/resource/objectcache.hpp b/components/resource/objectcache.hpp index cae48ca6b..624c38bad 100644 --- a/components/resource/objectcache.hpp +++ b/components/resource/objectcache.hpp @@ -1,3 +1,6 @@ +// Resource ObjectCache for OpenMW, forked from osgDB ObjectCache by Robert Osfield, see copyright notice below. +// The main change from the upstream version is that removeExpiredObjectsInCache no longer keeps a lock while the unref happens. + /* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under @@ -11,17 +14,8 @@ * OpenSceneGraph Public License for more details. */ -// Wrapper for osgDB/ObjectCache. Works around ObjectCache not being available in old OSG 3.2. -// Use "#include objectcache.hpp" in place of "#include - -#if OSG_VERSION_GREATER_OR_EQUAL(3,3,3) -#include -#else +#ifndef OPENMW_COMPONENTS_RESOURCE_OBJECTCACHE +#define OPENMW_COMPONENTS_RESOURCE_OBJECTCACHE #include @@ -30,9 +24,9 @@ #include -namespace osgDB { +namespace Resource { -class /*OSGDB_EXPORT*/ ObjectCache : public osg::Referenced +class ObjectCache : public osg::Referenced { public: @@ -70,7 +64,7 @@ class /*OSGDB_EXPORT*/ ObjectCache : public osg::Referenced /** Get an ref_ptr from the object cache*/ osg::ref_ptr getRefFromObjectCache(const std::string& fileName); - /** call rleaseGLObjects on all objects attached to the object cache.*/ + /** call releaseGLObjects on all objects attached to the object cache.*/ void releaseGLObjects(osg::State* state); protected: @@ -88,5 +82,3 @@ class /*OSGDB_EXPORT*/ ObjectCache : public osg::Referenced } #endif - -#endif diff --git a/components/resource/resourcemanager.cpp b/components/resource/resourcemanager.cpp index 60233baa0..03e6263b9 100644 --- a/components/resource/resourcemanager.cpp +++ b/components/resource/resourcemanager.cpp @@ -7,7 +7,7 @@ namespace Resource ResourceManager::ResourceManager(const VFS::Manager *vfs, const double expiryDelay) : mVFS(vfs) - , mCache(new osgDB::ObjectCache) + , mCache(new Resource::ObjectCache) , mExpiryDelay(expiryDelay) { diff --git a/components/resource/resourcemanager.hpp b/components/resource/resourcemanager.hpp index e45a2e9cb..a9b6ab3d5 100644 --- a/components/resource/resourcemanager.hpp +++ b/components/resource/resourcemanager.hpp @@ -8,13 +8,9 @@ namespace VFS class Manager; } -namespace osgDB -{ - class ObjectCache; -} - namespace Resource { + class ObjectCache; /// @brief Base class for managers that require a virtual file system and object cache. /// @par This base class implements clearing of the cache, but populating it and what it's used for is up to the individual sub classes. @@ -34,7 +30,7 @@ namespace Resource protected: const VFS::Manager* mVFS; - osg::ref_ptr mCache; + osg::ref_ptr mCache; double mExpiryDelay; }; diff --git a/components/resource/resourcesystem.cpp b/components/resource/resourcesystem.cpp index 1f25bd461..a8ab6556d 100644 --- a/components/resource/resourcesystem.cpp +++ b/components/resource/resourcesystem.cpp @@ -54,7 +54,6 @@ namespace Resource void ResourceSystem::updateCache(double referenceTime) { - // TODO: change ObjectCache to not hold lock while the unref happens for (std::vector::iterator it = mResourceManagers.begin(); it != mResourceManagers.end(); ++it) (*it)->updateCache(referenceTime); } From d3415387a533a069daf070e37d8cdeed1d9d3d1e Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 7 Feb 2016 01:18:20 +0100 Subject: [PATCH 3095/3725] AI: take into account success chance when rating a spell --- apps/openmw/mwmechanics/aicombataction.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombataction.cpp b/apps/openmw/mwmechanics/aicombataction.cpp index 60446e524..608bbaeb1 100644 --- a/apps/openmw/mwmechanics/aicombataction.cpp +++ b/apps/openmw/mwmechanics/aicombataction.cpp @@ -167,7 +167,8 @@ namespace MWMechanics { const CreatureStats& stats = actor.getClass().getCreatureStats(actor); - if (MWMechanics::getSpellSuccessChance(spell, actor) == 0) + float successChance = MWMechanics::getSpellSuccessChance(spell, actor); + if (successChance == 0.f) return 0.f; if (spell->mData.mType != ESM::Spell::ST_Spell) @@ -192,7 +193,7 @@ namespace MWMechanics if ( ((types & Touch) || (types & Target)) && target.getClass().getCreatureStats(target).getActiveSpells().isSpellActive(spell->mId)) return 0.f; - return rateEffects(spell->mEffects, actor, target); + return rateEffects(spell->mEffects, actor, target) * (successChance / 100.f); } float rateMagicItem(const MWWorld::Ptr &ptr, const MWWorld::Ptr &actor, const MWWorld::Ptr& target) From 94c05c6baa50d1f2a736f2d3f1808ef1bed7abe2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 7 Feb 2016 01:19:10 +0100 Subject: [PATCH 3096/3725] AI: don't cast useless resist spells (Fixes #2760) --- apps/openmw/mwmechanics/aicombataction.cpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/apps/openmw/mwmechanics/aicombataction.cpp b/apps/openmw/mwmechanics/aicombataction.cpp index 608bbaeb1..627bc02f7 100644 --- a/apps/openmw/mwmechanics/aicombataction.cpp +++ b/apps/openmw/mwmechanics/aicombataction.cpp @@ -254,8 +254,27 @@ namespace MWMechanics case ESM::MagicEffect::CureCommonDisease: case ESM::MagicEffect::CureBlightDisease: case ESM::MagicEffect::CureCorprusDisease: + case ESM::MagicEffect::ResistBlightDisease: + case ESM::MagicEffect::ResistCommonDisease: + case ESM::MagicEffect::ResistCorprusDisease: case ESM::MagicEffect::Invisibility: + case ESM::MagicEffect::Chameleon: return 0.f; + + case ESM::MagicEffect::RestoreAttribute: + return 0.f; // TODO: implement based on attribute damage + case ESM::MagicEffect::RestoreSkill: + return 0.f; // TODO: implement based on skill damage + + case ESM::MagicEffect::ResistFire: + case ESM::MagicEffect::ResistFrost: + case ESM::MagicEffect::ResistMagicka: + case ESM::MagicEffect::ResistNormalWeapons: + case ESM::MagicEffect::ResistParalysis: + case ESM::MagicEffect::ResistPoison: + case ESM::MagicEffect::ResistShock: + return 0.f; // probably useless since we don't know in advance what the enemy will cast + case ESM::MagicEffect::Feather: if (actor.getClass().getEncumbrance(actor) - actor.getClass().getCapacity(actor) >= 0) return 100.f; From 162287b82d60d068474836751c7fad41b50aa275 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 7 Feb 2016 01:24:49 +0100 Subject: [PATCH 3097/3725] AI combat actions: rename 'target' to 'enemy' --- apps/openmw/mwmechanics/aicombataction.cpp | 46 +++++++++++----------- apps/openmw/mwmechanics/aicombataction.hpp | 12 +++--- 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombataction.cpp b/apps/openmw/mwmechanics/aicombataction.cpp index 627bc02f7..cf0d2532b 100644 --- a/apps/openmw/mwmechanics/aicombataction.cpp +++ b/apps/openmw/mwmechanics/aicombataction.cpp @@ -97,7 +97,7 @@ namespace MWMechanics return rateEffects(potion->mEffects, actor, MWWorld::Ptr()); } - float rateWeapon (const MWWorld::Ptr &item, const MWWorld::Ptr& actor, const MWWorld::Ptr& target, int type, + float rateWeapon (const MWWorld::Ptr &item, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy, int type, float arrowRating, float boltRating) { if (item.getTypeName() != typeid(ESM::Weapon).name()) @@ -153,7 +153,7 @@ namespace MWMechanics if (enchantment->mData.mType == ESM::Enchantment::WhenStrikes && (item.getCellRef().getEnchantmentCharge() == -1 || item.getCellRef().getEnchantmentCharge() >= enchantment->mData.mCost)) - rating += rateEffects(enchantment->mEffects, actor, target); + rating += rateEffects(enchantment->mEffects, actor, enemy); } int skill = item.getClass().getEquipmentSkill(item); @@ -163,7 +163,7 @@ namespace MWMechanics return rating; } - float rateSpell(const ESM::Spell *spell, const MWWorld::Ptr &actor, const MWWorld::Ptr& target) + float rateSpell(const ESM::Spell *spell, const MWWorld::Ptr &actor, const MWWorld::Ptr& enemy) { const CreatureStats& stats = actor.getClass().getCreatureStats(actor); @@ -190,13 +190,13 @@ namespace MWMechanics int types = getRangeTypes(spell->mEffects); if ((types & Self) && stats.getActiveSpells().isSpellActive(spell->mId)) return 0.f; - if ( ((types & Touch) || (types & Target)) && target.getClass().getCreatureStats(target).getActiveSpells().isSpellActive(spell->mId)) + if ( ((types & Touch) || (types & Target)) && enemy.getClass().getCreatureStats(enemy).getActiveSpells().isSpellActive(spell->mId)) return 0.f; - return rateEffects(spell->mEffects, actor, target) * (successChance / 100.f); + return rateEffects(spell->mEffects, actor, enemy) * (successChance / 100.f); } - float rateMagicItem(const MWWorld::Ptr &ptr, const MWWorld::Ptr &actor, const MWWorld::Ptr& target) + float rateMagicItem(const MWWorld::Ptr &ptr, const MWWorld::Ptr &actor, const MWWorld::Ptr& enemy) { if (ptr.getClass().getEnchantment(ptr).empty()) return 0.f; @@ -205,7 +205,7 @@ namespace MWMechanics if (enchantment->mData.mType == ESM::Enchantment::CastOnce) { - return rateEffects(enchantment->mEffects, actor, target); + return rateEffects(enchantment->mEffects, actor, enemy); } else { @@ -214,9 +214,9 @@ namespace MWMechanics } } - float rateEffect(const ESM::ENAMstruct &effect, const MWWorld::Ptr &actor, const MWWorld::Ptr &target) + float rateEffect(const ESM::ENAMstruct &effect, const MWWorld::Ptr &actor, const MWWorld::Ptr &enemy) { - // NOTE: target may be empty + // NOTE: enemy may be empty float rating = 1; switch (effect.mEffectID) @@ -337,7 +337,7 @@ namespace MWMechanics case ESM::MagicEffect::DamageAttribute: case ESM::MagicEffect::DrainAttribute: - if (!target.isEmpty() && target.getClass().getCreatureStats(target).getAttribute(effect.mAttribute).getModified() <= 0) + if (!enemy.isEmpty() && enemy.getClass().getCreatureStats(enemy).getAttribute(effect.mAttribute).getModified() <= 0) return 0.f; { if (effect.mAttribute >= 0 && effect.mAttribute < ESM::Attribute::Length) @@ -359,9 +359,9 @@ namespace MWMechanics case ESM::MagicEffect::DamageSkill: case ESM::MagicEffect::DrainSkill: - if (target.isEmpty() || !target.getClass().isNpc()) + if (enemy.isEmpty() || !enemy.getClass().isNpc()) return 0.f; - if (target.getClass().getNpcStats(target).getSkill(effect.mSkill).getModified() <= 0) + if (enemy.getClass().getNpcStats(enemy).getSkill(effect.mSkill).getModified() <= 0) return 0.f; break; @@ -369,9 +369,9 @@ namespace MWMechanics break; } - // TODO: for non-cumulative effects (e.g. paralyze), check if the target is already suffering from them + // TODO: for non-cumulative effects (e.g. paralyze), check if the enemy is already suffering from them - // TODO: could take into account target's resistance/weakness against the effect + // TODO: could take into account enemy's resistance/weakness against the effect const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get().find(effect.mEffectID); @@ -392,13 +392,13 @@ namespace MWMechanics return rating; } - float rateEffects(const ESM::EffectList &list, const MWWorld::Ptr& actor, const MWWorld::Ptr& target) + float rateEffects(const ESM::EffectList &list, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy) { - // NOTE: target may be empty + // NOTE: enemy may be empty float rating = 0.f; for (std::vector::const_iterator it = list.mList.begin(); it != list.mList.end(); ++it) { - rating += rateEffect(*it, actor, target); + rating += rateEffect(*it, actor, enemy); } return rating; } @@ -474,7 +474,7 @@ namespace MWMechanics // Already done in AiCombat itself } - boost::shared_ptr prepareNextAction(const MWWorld::Ptr &actor, const MWWorld::Ptr &target) + boost::shared_ptr prepareNextAction(const MWWorld::Ptr &actor, const MWWorld::Ptr &enemy) { Spells& spells = actor.getClass().getCreatureStats(actor).getSpells(); @@ -503,7 +503,7 @@ namespace MWMechanics for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it) { - float rating = rateMagicItem(*it, actor, target); + float rating = rateMagicItem(*it, actor, enemy); if (rating > bestActionRating) { bestActionRating = rating; @@ -515,7 +515,7 @@ namespace MWMechanics MWWorld::Ptr bestArrow; for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it) { - float rating = rateWeapon(*it, actor, target, ESM::Weapon::Arrow); + float rating = rateWeapon(*it, actor, enemy, ESM::Weapon::Arrow); if (rating > bestArrowRating) { bestArrowRating = rating; @@ -527,7 +527,7 @@ namespace MWMechanics MWWorld::Ptr bestBolt; for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it) { - float rating = rateWeapon(*it, actor, target, ESM::Weapon::Bolt); + float rating = rateWeapon(*it, actor, enemy, ESM::Weapon::Bolt); if (rating > bestBoltRating) { bestBoltRating = rating; @@ -542,7 +542,7 @@ namespace MWMechanics == equipmentSlots.end()) continue; - float rating = rateWeapon(*it, actor, target, -1, bestArrowRating, bestBoltRating); + float rating = rateWeapon(*it, actor, enemy, -1, bestArrowRating, bestBoltRating); if (rating > bestActionRating) { const ESM::Weapon* weapon = it->get()->mBase; @@ -563,7 +563,7 @@ namespace MWMechanics { const ESM::Spell* spell = it->first; - float rating = rateSpell(spell, actor, target); + float rating = rateSpell(spell, actor, enemy); if (rating > bestActionRating) { bestActionRating = rating; diff --git a/apps/openmw/mwmechanics/aicombataction.hpp b/apps/openmw/mwmechanics/aicombataction.hpp index a4a398d05..6f5cbfbc2 100644 --- a/apps/openmw/mwmechanics/aicombataction.hpp +++ b/apps/openmw/mwmechanics/aicombataction.hpp @@ -72,19 +72,19 @@ namespace MWMechanics virtual void getCombatRange (float& rangeAttack, float& rangeFollow); }; - float rateSpell (const ESM::Spell* spell, const MWWorld::Ptr& actor, const MWWorld::Ptr& target); - float rateMagicItem (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor, const MWWorld::Ptr &target); + float rateSpell (const ESM::Spell* spell, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy); + float rateMagicItem (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy); float ratePotion (const MWWorld::Ptr& item, const MWWorld::Ptr &actor); /// @param type Skip all weapons that are not of this type (i.e. return rating 0) - float rateWeapon (const MWWorld::Ptr& item, const MWWorld::Ptr& actor, const MWWorld::Ptr& target, + float rateWeapon (const MWWorld::Ptr& item, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy, int type=-1, float arrowRating=0.f, float boltRating=0.f); /// @note target may be empty - float rateEffect (const ESM::ENAMstruct& effect, const MWWorld::Ptr& actor, const MWWorld::Ptr& target); + float rateEffect (const ESM::ENAMstruct& effect, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy); /// @note target may be empty - float rateEffects (const ESM::EffectList& list, const MWWorld::Ptr& actor, const MWWorld::Ptr& target); + float rateEffects (const ESM::EffectList& list, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy); - boost::shared_ptr prepareNextAction (const MWWorld::Ptr& actor, const MWWorld::Ptr& target); + boost::shared_ptr prepareNextAction (const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy); } #endif From a7b217def22d6bf1c35afd5dde36ceb18000a6eb Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 7 Feb 2016 01:27:40 +0100 Subject: [PATCH 3098/3725] AI: don't cast fortify effects (Fixes #3184) --- apps/openmw/mwmechanics/aicombataction.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/apps/openmw/mwmechanics/aicombataction.cpp b/apps/openmw/mwmechanics/aicombataction.cpp index cf0d2532b..cee2aae9c 100644 --- a/apps/openmw/mwmechanics/aicombataction.cpp +++ b/apps/openmw/mwmechanics/aicombataction.cpp @@ -275,6 +275,15 @@ namespace MWMechanics case ESM::MagicEffect::ResistShock: return 0.f; // probably useless since we don't know in advance what the enemy will cast + // don't cast these for now as they would make the NPC cast the same effect over and over again, especially when they have potions + case ESM::MagicEffect::FortifyAttribute: + case ESM::MagicEffect::FortifyHealth: + case ESM::MagicEffect::FortifyMagicka: + case ESM::MagicEffect::FortifyFatigue: + case ESM::MagicEffect::FortifySkill: + case ESM::MagicEffect::FortifyMaximumMagicka: + return 0.f; + case ESM::MagicEffect::Feather: if (actor.getClass().getEncumbrance(actor) - actor.getClass().getCapacity(actor) >= 0) return 100.f; From 023c87b21595353b98edce6176b38f8dca52f288 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 7 Feb 2016 05:13:46 -0800 Subject: [PATCH 3099/3725] Preload cell when the player goes near a teleport door. It works! --- apps/openmw/mwworld/cellpreloader.cpp | 2 + apps/openmw/mwworld/scene.cpp | 58 +++++++++++++++++++++++++++ apps/openmw/mwworld/scene.hpp | 3 ++ 3 files changed, 63 insertions(+) diff --git a/apps/openmw/mwworld/cellpreloader.cpp b/apps/openmw/mwworld/cellpreloader.cpp index 16bf920bb..f1366a8b2 100644 --- a/apps/openmw/mwworld/cellpreloader.cpp +++ b/apps/openmw/mwworld/cellpreloader.cpp @@ -66,6 +66,7 @@ namespace MWWorld /// Preload work to be called from the worker thread. virtual void doWork() { + osg::Timer preloadTimer; for (MeshList::const_iterator it = mMeshes.begin(); it != mMeshes.end(); ++it) { try @@ -81,6 +82,7 @@ namespace MWWorld // error will be shown when visiting the cell } } + std::cout << "preloaded " << mPreloadedNodes.size() << " nodes in " << preloadTimer.time_m() << std::endl; } private: diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 70a461b5b..912a39e7c 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -193,6 +193,13 @@ namespace MWWorld void Scene::update (float duration, bool paused) { + mPreloadTimer += duration; + if (mPreloadTimer > 1.f) + { + preloadCells(); + mPreloadTimer = 0.f; + } + mRendering.update (duration, paused); } @@ -440,6 +447,7 @@ namespace MWWorld Scene::Scene (MWRender::RenderingManager& rendering, MWPhysics::PhysicsSystem *physics) : mCurrentCell (0), mCellChanged (false), mPhysics(physics), mRendering(rendering) + , mPreloadTimer(0.f) { mPreloader.reset(new CellPreloader(rendering.getResourceSystem(), physics->getShapeManager())); } @@ -603,4 +611,54 @@ namespace MWWorld return Ptr(); } + + void Scene::preloadCells() + { + std::vector teleportDoors; + for (CellStoreCollection::const_iterator iter (mActiveCells.begin()); + iter!=mActiveCells.end(); ++iter) + { + const MWWorld::CellStore* cellStore = *iter; + typedef MWWorld::CellRefList::List DoorList; + const DoorList &doors = cellStore->getReadOnlyDoors().mList; + for (DoorList::const_iterator doorIt = doors.begin(); doorIt != doors.end(); ++doorIt) + { + if (!doorIt->mRef.getTeleport()) { + continue; + } + teleportDoors.push_back(MWWorld::ConstPtr(&*doorIt, cellStore)); + } + } + + const MWWorld::ConstPtr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + const float preloadDist = 500.f; + + for (std::vector::iterator it = teleportDoors.begin(); it != teleportDoors.end(); ++it) + { + const MWWorld::ConstPtr& door = *it; + float sqrDistToPlayer = (player.getRefData().getPosition().asVec3() - door.getRefData().getPosition().asVec3()).length2(); + + if (sqrDistToPlayer < preloadDist*preloadDist) + { + MWWorld::CellStore* targetCell = NULL; + try + { + if (!door.getCellRef().getDestCell().empty()) + targetCell = MWBase::Environment::get().getWorld()->getInterior(door.getCellRef().getDestCell()); + else + { + int x,y; + MWBase::Environment::get().getWorld()->positionToIndex (door.getCellRef().getDoorDest().pos[0], door.getCellRef().getDoorDest().pos[1], x, y); + targetCell = MWBase::Environment::get().getWorld()->getExterior(x, y); + } + } + catch (std::exception& e) + { + // ignore error for now, would spam the log too much + } + if (targetCell) + mPreloader->preload(targetCell, mRendering.getReferenceTime()); + } + } + } } diff --git a/apps/openmw/mwworld/scene.hpp b/apps/openmw/mwworld/scene.hpp index b428d0ddd..4ac0d0666 100644 --- a/apps/openmw/mwworld/scene.hpp +++ b/apps/openmw/mwworld/scene.hpp @@ -58,6 +58,7 @@ namespace MWWorld MWPhysics::PhysicsSystem *mPhysics; MWRender::RenderingManager& mRendering; std::auto_ptr mPreloader; + float mPreloadTimer; void insertCell (CellStore &cell, bool rescale, Loading::Listener* loadingListener); @@ -112,6 +113,8 @@ namespace MWWorld bool isCellActive(const CellStore &cell); Ptr searchPtrViaActorId (int actorId); + + void preloadCells(); }; } From 8592166eeb5acf5bbffb16125b0ccf5f98dc2b0b Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 7 Feb 2016 05:27:19 -0800 Subject: [PATCH 3100/3725] Preload surrounding cells when preloading an exterior cell destination --- apps/openmw/mwworld/cellpreloader.cpp | 2 ++ apps/openmw/mwworld/scene.cpp | 29 +++++++++++++++------------ apps/openmw/mwworld/scene.hpp | 1 + 3 files changed, 19 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwworld/cellpreloader.cpp b/apps/openmw/mwworld/cellpreloader.cpp index f1366a8b2..429e3294d 100644 --- a/apps/openmw/mwworld/cellpreloader.cpp +++ b/apps/openmw/mwworld/cellpreloader.cpp @@ -66,6 +66,8 @@ namespace MWWorld /// Preload work to be called from the worker thread. virtual void doWork() { + // TODO: make CellStore::loadRefs thread safe so we can call it from here + osg::Timer preloadTimer; for (MeshList::const_iterator it = mMeshes.begin(); it != mMeshes.end(); ++it) { diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 912a39e7c..38b762018 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -334,15 +334,13 @@ namespace MWWorld std::string loadingExteriorText = "#{sLoadingMessage3}"; loadingListener->setLabel(loadingExteriorText); - const int halfGridSize = Settings::Manager::getInt("exterior cell load distance", "Cells"); - CellStoreCollection::iterator active = mActiveCells.begin(); while (active!=mActiveCells.end()) { if ((*active)->getCell()->isExterior()) { - if (std::abs (X-(*active)->getCell()->getGridX())<=halfGridSize && - std::abs (Y-(*active)->getCell()->getGridY())<=halfGridSize) + if (std::abs (X-(*active)->getCell()->getGridX())<=mHalfGridSize && + std::abs (Y-(*active)->getCell()->getGridY())<=mHalfGridSize) { // keep cells within the new grid ++active; @@ -354,9 +352,9 @@ namespace MWWorld int refsToLoad = 0; // get the number of refs to load - for (int x=X-halfGridSize; x<=X+halfGridSize; ++x) + for (int x=X-mHalfGridSize; x<=X+mHalfGridSize; ++x) { - for (int y=Y-halfGridSize; y<=Y+halfGridSize; ++y) + for (int y=Y-mHalfGridSize; y<=Y+mHalfGridSize; ++y) { CellStoreCollection::iterator iter = mActiveCells.begin(); @@ -379,9 +377,9 @@ namespace MWWorld loadingListener->setProgressRange(refsToLoad); // Load cells - for (int x=X-halfGridSize; x<=X+halfGridSize; ++x) + for (int x=X-mHalfGridSize; x<=X+mHalfGridSize; ++x) { - for (int y=Y-halfGridSize; y<=Y+halfGridSize; ++y) + for (int y=Y-mHalfGridSize; y<=Y+mHalfGridSize; ++y) { CellStoreCollection::iterator iter = mActiveCells.begin(); @@ -448,6 +446,7 @@ namespace MWWorld Scene::Scene (MWRender::RenderingManager& rendering, MWPhysics::PhysicsSystem *physics) : mCurrentCell (0), mCellChanged (false), mPhysics(physics), mRendering(rendering) , mPreloadTimer(0.f) + , mHalfGridSize(Settings::Manager::getInt("exterior cell load distance", "Cells")) { mPreloader.reset(new CellPreloader(rendering.getResourceSystem(), physics->getShapeManager())); } @@ -640,24 +639,28 @@ namespace MWWorld if (sqrDistToPlayer < preloadDist*preloadDist) { - MWWorld::CellStore* targetCell = NULL; try { if (!door.getCellRef().getDestCell().empty()) - targetCell = MWBase::Environment::get().getWorld()->getInterior(door.getCellRef().getDestCell()); + mPreloader->preload(MWBase::Environment::get().getWorld()->getInterior(door.getCellRef().getDestCell()), mRendering.getReferenceTime()); else { int x,y; MWBase::Environment::get().getWorld()->positionToIndex (door.getCellRef().getDoorDest().pos[0], door.getCellRef().getDoorDest().pos[1], x, y); - targetCell = MWBase::Environment::get().getWorld()->getExterior(x, y); + + for (int dx = -mHalfGridSize; dx <= mHalfGridSize; ++dx) + { + for (int dy = -mHalfGridSize; dy <= mHalfGridSize; ++dy) + { + mPreloader->preload(MWBase::Environment::get().getWorld()->getExterior(x+dx, y+dy), mRendering.getReferenceTime()); + } + } } } catch (std::exception& e) { // ignore error for now, would spam the log too much } - if (targetCell) - mPreloader->preload(targetCell, mRendering.getReferenceTime()); } } } diff --git a/apps/openmw/mwworld/scene.hpp b/apps/openmw/mwworld/scene.hpp index 4ac0d0666..68748af85 100644 --- a/apps/openmw/mwworld/scene.hpp +++ b/apps/openmw/mwworld/scene.hpp @@ -59,6 +59,7 @@ namespace MWWorld MWRender::RenderingManager& mRendering; std::auto_ptr mPreloader; float mPreloadTimer; + int mHalfGridSize; void insertCell (CellStore &cell, bool rescale, Loading::Listener* loadingListener); From 8b981ab507bf7e940c9ed86f466c585f9258ffeb Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 7 Feb 2016 05:53:42 -0800 Subject: [PATCH 3101/3725] Crash fix --- components/resource/scenemanager.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index 4ed14241a..c2be3960f 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -200,7 +200,8 @@ namespace Resource for(unsigned int unit=0;unitgetTextureAttribute(unit, osg::StateAttribute::TEXTURE); - apply(texture); + if (texture) + apply(texture); } } From c3ad4dad7544bd2e0ea1f7931ce8854d87e5d535 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 7 Feb 2016 05:53:56 -0800 Subject: [PATCH 3102/3725] Fix applying of filter settings on terrain textures --- components/terrain/terraingrid.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/components/terrain/terraingrid.cpp b/components/terrain/terraingrid.cpp index eb085ca42..4f7a0772b 100644 --- a/components/terrain/terraingrid.cpp +++ b/components/terrain/terraingrid.cpp @@ -139,15 +139,16 @@ osg::ref_ptr TerrainGrid::buildTerrain (osg::Group* parent, float chu std::vector > layerTextures; for (std::vector::const_iterator it = layerList.begin(); it != layerList.end(); ++it) { - osg::ref_ptr tex = mTextureCache[it->mDiffuseMap]; - if (!tex) + osg::ref_ptr texture = mTextureCache[it->mDiffuseMap]; + if (!texture) { - tex = new osg::Texture2D(mResourceSystem->getImageManager()->getImage(it->mDiffuseMap)); - tex->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT); - tex->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT); - mTextureCache[it->mDiffuseMap] = tex; + texture = new osg::Texture2D(mResourceSystem->getImageManager()->getImage(it->mDiffuseMap)); + texture->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT); + texture->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT); + mResourceSystem->getSceneManager()->applyFilterSettings(texture); + mTextureCache[it->mDiffuseMap] = texture; } - layerTextures.push_back(tex); + layerTextures.push_back(texture); textureCompileDummy->getOrCreateStateSet()->setTextureAttributeAndModes(dummyTextureCounter++, layerTextures.back()); } @@ -161,7 +162,6 @@ osg::ref_ptr TerrainGrid::buildTerrain (osg::Group* parent, float chu texture->setResizeNonPowerOfTwoHint(false); texture->getOrCreateUserDataContainer()->addDescription("dont_override_filter"); blendmapTextures.push_back(texture); - mResourceSystem->getSceneManager()->applyFilterSettings(texture); textureCompileDummy->getOrCreateStateSet()->setTextureAttributeAndModes(dummyTextureCounter++, blendmapTextures.back()); } From 49ecac4ced6a562f6b0e6491e87ab6d3864f61c9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 7 Feb 2016 07:37:35 -0800 Subject: [PATCH 3103/3725] Add a mutex lock around the SharedStateManager --- components/resource/scenemanager.cpp | 2 ++ components/resource/scenemanager.hpp | 2 ++ 2 files changed, 4 insertions(+) diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index c2be3960f..eecee813f 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -357,7 +357,9 @@ namespace Resource loaded->accept(setFilterSettingsControllerVisitor); // share state + mSharedStateMutex.lock(); osgDB::Registry::instance()->getOrCreateSharedStateManager()->share(loaded.get()); + mSharedStateMutex.unlock(); if (mIncrementalCompileOperation) mIncrementalCompileOperation->add(loaded); diff --git a/components/resource/scenemanager.hpp b/components/resource/scenemanager.hpp index 173131e66..0345fff22 100644 --- a/components/resource/scenemanager.hpp +++ b/components/resource/scenemanager.hpp @@ -89,6 +89,8 @@ namespace Resource void setUnRefImageDataAfterApply(bool unref); private: + OpenThreads::Mutex mSharedStateMutex; + Resource::ImageManager* mImageManager; Resource::NifFileManager* mNifFileManager; From 610257cd3a396c8e4fe557584a89395371af88b5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 7 Feb 2016 07:37:56 -0800 Subject: [PATCH 3104/3725] Preload the exterior cell grid --- apps/openmw/mwworld/scene.cpp | 53 +++++++++++++++++++++++++++++++---- apps/openmw/mwworld/scene.hpp | 8 ++++-- 2 files changed, 54 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 38b762018..b859efbf1 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -194,7 +194,7 @@ namespace MWWorld void Scene::update (float duration, bool paused) { mPreloadTimer += duration; - if (mPreloadTimer > 1.f) + if (mPreloadTimer > 0.5f) { preloadCells(); mPreloadTimer = 0.f; @@ -313,7 +313,7 @@ namespace MWWorld getGridCenter(cellX, cellY); float centerX, centerY; MWBase::Environment::get().getWorld()->indexToPosition(cellX, cellY, centerX, centerY, true); - const float maxDistance = 8192/2 + 1024; // 1/2 cell size + threshold + const float maxDistance = 8192/2 + mCellLoadingThreshold; // 1/2 cell size + threshold float distance = std::max(std::abs(centerX-pos.x()), std::abs(centerY-pos.y())); if (distance > maxDistance) { @@ -447,6 +447,8 @@ namespace MWWorld : mCurrentCell (0), mCellChanged (false), mPhysics(physics), mRendering(rendering) , mPreloadTimer(0.f) , mHalfGridSize(Settings::Manager::getInt("exterior cell load distance", "Cells")) + , mCellLoadingThreshold(1024.f) + , mPreloadDistance(1000.f) { mPreloader.reset(new CellPreloader(rendering.getResourceSystem(), physics->getShapeManager())); } @@ -612,6 +614,12 @@ namespace MWWorld } void Scene::preloadCells() + { + preloadTeleportDoorDestinations(); + preloadExteriorGrid(); + } + + void Scene::preloadTeleportDoorDestinations() { std::vector teleportDoors; for (CellStoreCollection::const_iterator iter (mActiveCells.begin()); @@ -630,14 +638,12 @@ namespace MWWorld } const MWWorld::ConstPtr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); - const float preloadDist = 500.f; - for (std::vector::iterator it = teleportDoors.begin(); it != teleportDoors.end(); ++it) { const MWWorld::ConstPtr& door = *it; float sqrDistToPlayer = (player.getRefData().getPosition().asVec3() - door.getRefData().getPosition().asVec3()).length2(); - if (sqrDistToPlayer < preloadDist*preloadDist) + if (sqrDistToPlayer < mPreloadDistance*mPreloadDistance) { try { @@ -664,4 +670,41 @@ namespace MWWorld } } } + + void Scene::preloadExteriorGrid() + { + if (!MWBase::Environment::get().getWorld()->isCellExterior()) + return; + + int halfGridSizePlusOne = mHalfGridSize + 1; + + const MWWorld::ConstPtr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + osg::Vec3f playerPos = player.getRefData().getPosition().asVec3(); + + int cellX,cellY; + getGridCenter(cellX,cellY); + + float centerX, centerY; + MWBase::Environment::get().getWorld()->indexToPosition(cellX, cellY, centerX, centerY, true); + + for (int dx = -halfGridSizePlusOne; dx <= halfGridSizePlusOne; ++dx) + { + for (int dy = -halfGridSizePlusOne; dy <= halfGridSizePlusOne; ++dy) + { + if (dy != halfGridSizePlusOne && dy != -halfGridSizePlusOne && dx != halfGridSizePlusOne && dx != -halfGridSizePlusOne) + continue; // only care about the outer (not yet loaded) part of the grid + + float thisCellCenterX, thisCellCenterY; + MWBase::Environment::get().getWorld()->indexToPosition(cellX+dx, cellY+dy, thisCellCenterX, thisCellCenterY, true); + + float dist = std::max(std::abs(thisCellCenterX - playerPos.x()), std::abs(thisCellCenterY - playerPos.y())); + float loadDist = 8192/2 + 8192 - mCellLoadingThreshold + mPreloadDistance; + + std::cout << cellX+dx << " " << cellY+dy << " dist " << dist << " need " << loadDist << std::endl; + + if (dist < loadDist) + mPreloader->preload(MWBase::Environment::get().getWorld()->getExterior(cellX+dx, cellY+dy), mRendering.getReferenceTime()); + } + } + } } diff --git a/apps/openmw/mwworld/scene.hpp b/apps/openmw/mwworld/scene.hpp index 68748af85..36021819e 100644 --- a/apps/openmw/mwworld/scene.hpp +++ b/apps/openmw/mwworld/scene.hpp @@ -60,6 +60,8 @@ namespace MWWorld std::auto_ptr mPreloader; float mPreloadTimer; int mHalfGridSize; + float mCellLoadingThreshold; + float mPreloadDistance; void insertCell (CellStore &cell, bool rescale, Loading::Listener* loadingListener); @@ -68,6 +70,10 @@ namespace MWWorld void getGridCenter(int& cellX, int& cellY); + void preloadCells(); + void preloadTeleportDoorDestinations(); + void preloadExteriorGrid(); + public: Scene (MWRender::RenderingManager& rendering, MWPhysics::PhysicsSystem *physics); @@ -114,8 +120,6 @@ namespace MWWorld bool isCellActive(const CellStore &cell); Ptr searchPtrViaActorId (int actorId); - - void preloadCells(); }; } From 5efaa9817c6172f5be24a0efdff7f308db4e71f1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 7 Feb 2016 18:01:14 +0100 Subject: [PATCH 3105/3725] Add preloading settings --- apps/openmw/mwworld/scene.cpp | 16 +++++++++------- apps/openmw/mwworld/scene.hpp | 1 + files/settings-default.cfg | 6 ++++++ 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index b859efbf1..c788df234 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -193,11 +193,14 @@ namespace MWWorld void Scene::update (float duration, bool paused) { - mPreloadTimer += duration; - if (mPreloadTimer > 0.5f) + if (mPreloadEnabled) { - preloadCells(); - mPreloadTimer = 0.f; + mPreloadTimer += duration; + if (mPreloadTimer > 0.5f) + { + preloadCells(); + mPreloadTimer = 0.f; + } } mRendering.update (duration, paused); @@ -448,7 +451,8 @@ namespace MWWorld , mPreloadTimer(0.f) , mHalfGridSize(Settings::Manager::getInt("exterior cell load distance", "Cells")) , mCellLoadingThreshold(1024.f) - , mPreloadDistance(1000.f) + , mPreloadDistance(Settings::Manager::getInt("preload distance", "Cells")) + , mPreloadEnabled(Settings::Manager::getBool("preload enabled", "Cells")) { mPreloader.reset(new CellPreloader(rendering.getResourceSystem(), physics->getShapeManager())); } @@ -700,8 +704,6 @@ namespace MWWorld float dist = std::max(std::abs(thisCellCenterX - playerPos.x()), std::abs(thisCellCenterY - playerPos.y())); float loadDist = 8192/2 + 8192 - mCellLoadingThreshold + mPreloadDistance; - std::cout << cellX+dx << " " << cellY+dy << " dist " << dist << " need " << loadDist << std::endl; - if (dist < loadDist) mPreloader->preload(MWBase::Environment::get().getWorld()->getExterior(cellX+dx, cellY+dy), mRendering.getReferenceTime()); } diff --git a/apps/openmw/mwworld/scene.hpp b/apps/openmw/mwworld/scene.hpp index 36021819e..34e137e45 100644 --- a/apps/openmw/mwworld/scene.hpp +++ b/apps/openmw/mwworld/scene.hpp @@ -62,6 +62,7 @@ namespace MWWorld int mHalfGridSize; float mCellLoadingThreshold; float mPreloadDistance; + bool mPreloadEnabled; void insertCell (CellStore &cell, bool rescale, Loading::Listener* loadingListener); diff --git a/files/settings-default.cfg b/files/settings-default.cfg index dddf1a29b..c03342600 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -37,6 +37,12 @@ first person field of view = 55.0 # dramatically affect performance, see documentation for details. exterior cell load distance = 1 +# Preload cells in a background thread +preload enabled = true + +# Preloading distance threshold +preload distance = 1000 + [Map] # Size of each exterior cell in pixels in the world map. (e.g. 12 to 24). From 778bce3ae939ec17345b09cb1365215079ee9640 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 7 Feb 2016 18:27:12 +0100 Subject: [PATCH 3106/3725] Remove unused ObjectCache functions --- components/resource/objectcache.cpp | 24 ------------------------ components/resource/objectcache.hpp | 6 ------ 2 files changed, 30 deletions(-) diff --git a/components/resource/objectcache.cpp b/components/resource/objectcache.cpp index 0c6066417..54576a122 100644 --- a/components/resource/objectcache.cpp +++ b/components/resource/objectcache.cpp @@ -31,42 +31,18 @@ ObjectCache::~ObjectCache() // OSG_NOTICE<<"Destructed ObjectCache"< lock1(_objectCacheMutex); - OpenThreads::ScopedLock lock2(objectCache->_objectCacheMutex); - - // OSG_NOTICE<<"Inserting objects to main ObjectCache "<_objectCache.size()<_objectCache.begin(), objectCache->_objectCache.end()); -} - - void ObjectCache::addEntryToObjectCache(const std::string& filename, osg::Object* object, double timestamp) { OpenThreads::ScopedLock lock(_objectCacheMutex); _objectCache[filename]=ObjectTimeStampPair(object,timestamp); } -osg::Object* ObjectCache::getFromObjectCache(const std::string& fileName) -{ - OpenThreads::ScopedLock lock(_objectCacheMutex); - ObjectCacheMap::iterator itr = _objectCache.find(fileName); - if (itr!=_objectCache.end()) return itr->second.first.get(); - else return 0; -} - osg::ref_ptr ObjectCache::getRefFromObjectCache(const std::string& fileName) { OpenThreads::ScopedLock lock(_objectCacheMutex); ObjectCacheMap::iterator itr = _objectCache.find(fileName); if (itr!=_objectCache.end()) { - // OSG_NOTICE<<"Found "<second.first; } else return 0; diff --git a/components/resource/objectcache.hpp b/components/resource/objectcache.hpp index 624c38bad..b933933f3 100644 --- a/components/resource/objectcache.hpp +++ b/components/resource/objectcache.hpp @@ -49,18 +49,12 @@ class ObjectCache : public osg::Referenced /** Remove all objects in the cache regardless of having external references or expiry times.*/ void clear(); - /** Add contents of specified ObjectCache to this object cache.*/ - void addObjectCache(ObjectCache* object); - /** Add a filename,object,timestamp triple to the Registry::ObjectCache.*/ void addEntryToObjectCache(const std::string& filename, osg::Object* object, double timestamp = 0.0); /** Remove Object from cache.*/ void removeFromObjectCache(const std::string& fileName); - /** Get an Object from the object cache*/ - osg::Object* getFromObjectCache(const std::string& fileName); - /** Get an ref_ptr from the object cache*/ osg::ref_ptr getRefFromObjectCache(const std::string& fileName); From 41233fc8e5717ba0d37dd5c3afb513a7e5702c62 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 7 Feb 2016 18:56:21 +0100 Subject: [PATCH 3107/3725] Keep a reference to the original scene template for as long as the instance is used --- components/resource/objectcache.cpp | 2 -- components/resource/scenemanager.cpp | 4 ++++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/components/resource/objectcache.cpp b/components/resource/objectcache.cpp index 54576a122..17368f34f 100644 --- a/components/resource/objectcache.cpp +++ b/components/resource/objectcache.cpp @@ -23,12 +23,10 @@ namespace Resource ObjectCache::ObjectCache(): osg::Referenced(true) { -// OSG_NOTICE<<"Constructed ObjectCache"< scene = getTemplate(name); osg::ref_ptr cloned = osg::clone(scene.get(), SceneUtil::CopyOp()); + + // add a ref to the original template, to hint to the cache that it's still being used and should be kept in cache + cloned->getOrCreateUserDataContainer()->addUserObject(const_cast(scene.get())); + return cloned; } From a81b10b4153751ee7c1cc117f8b9096dda70bb8b Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 7 Feb 2016 19:05:55 +0100 Subject: [PATCH 3108/3725] Make the cache expiryDelay configurable --- apps/openmw/mwworld/cellpreloader.cpp | 12 ++++++++---- apps/openmw/mwworld/cellpreloader.hpp | 4 ++++ apps/openmw/mwworld/scene.cpp | 4 ++++ components/resource/niffilemanager.cpp | 3 +-- components/resource/resourcemanager.cpp | 9 +++++++-- components/resource/resourcemanager.hpp | 6 ++++-- components/resource/resourcesystem.cpp | 10 ++++++++++ components/resource/resourcesystem.hpp | 3 +++ files/settings-default.cfg | 4 ++++ 9 files changed, 45 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwworld/cellpreloader.cpp b/apps/openmw/mwworld/cellpreloader.cpp index 429e3294d..13ce75d68 100644 --- a/apps/openmw/mwworld/cellpreloader.cpp +++ b/apps/openmw/mwworld/cellpreloader.cpp @@ -123,6 +123,7 @@ namespace MWWorld CellPreloader::CellPreloader(Resource::ResourceSystem* resourceSystem, Resource::BulletShapeManager* bulletShapeManager) : mResourceSystem(resourceSystem) , mBulletShapeManager(bulletShapeManager) + , mExpiryDelay(0.0) { mWorkQueue = new SceneUtil::WorkQueue; } @@ -156,13 +157,11 @@ namespace MWWorld void CellPreloader::updateCache(double timestamp) { - // time (in seconds) to keep a preloaded cell in cache after it's no longer needed - // additionally we could support a minimum/maximum size for the cache - const double expiryTime = 60.0; + // TODO: add settings for a minimum/maximum size of the cache for (PreloadMap::iterator it = mPreloadCells.begin(); it != mPreloadCells.end();) { - if (it->second.mTimeStamp < timestamp - expiryTime) + if (it->second.mTimeStamp < timestamp - mExpiryDelay) mPreloadCells.erase(it++); else ++it; @@ -172,6 +171,11 @@ namespace MWWorld mWorkQueue->addWorkItem(new UpdateCacheItem(mResourceSystem, timestamp)); } + void CellPreloader::setExpiryDelay(double expiryDelay) + { + mExpiryDelay = expiryDelay; + } + void CellPreloader::setWorkQueue(osg::ref_ptr workQueue) { mWorkQueue = workQueue; diff --git a/apps/openmw/mwworld/cellpreloader.hpp b/apps/openmw/mwworld/cellpreloader.hpp index b3413b174..5a2432179 100644 --- a/apps/openmw/mwworld/cellpreloader.hpp +++ b/apps/openmw/mwworld/cellpreloader.hpp @@ -27,12 +27,16 @@ namespace MWWorld /// Removes preloaded cells that have not had a preload request for a while. void updateCache(double timestamp); + /// How long to keep a preloaded cell in cache after it's no longer requested. + void setExpiryDelay(double expiryDelay); + void setWorkQueue(osg::ref_ptr workQueue); private: Resource::ResourceSystem* mResourceSystem; Resource::BulletShapeManager* mBulletShapeManager; osg::ref_ptr mWorkQueue; + double mExpiryDelay; struct PreloadEntry { diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index c788df234..86f40df73 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -455,6 +455,10 @@ namespace MWWorld , mPreloadEnabled(Settings::Manager::getBool("preload enabled", "Cells")) { mPreloader.reset(new CellPreloader(rendering.getResourceSystem(), physics->getShapeManager())); + + float cacheExpiryDelay = Settings::Manager::getFloat("cache expiry delay", "Cells"); + rendering.getResourceSystem()->setExpiryDelay(cacheExpiryDelay); + mPreloader->setExpiryDelay(cacheExpiryDelay); } Scene::~Scene() diff --git a/components/resource/niffilemanager.cpp b/components/resource/niffilemanager.cpp index 3c7437520..ecb63db60 100644 --- a/components/resource/niffilemanager.cpp +++ b/components/resource/niffilemanager.cpp @@ -29,8 +29,7 @@ namespace Resource }; NifFileManager::NifFileManager(const VFS::Manager *vfs) - : ResourceManager(vfs, 0.0) // NIF files aren't needed any more when the converted objects are cached in SceneManager / BulletShapeManager, - // so we'll use expiryDelay of 0 to instantly delete NIF files after use. + : ResourceManager(vfs) { } diff --git a/components/resource/resourcemanager.cpp b/components/resource/resourcemanager.cpp index 03e6263b9..b6b38bfa2 100644 --- a/components/resource/resourcemanager.cpp +++ b/components/resource/resourcemanager.cpp @@ -5,10 +5,10 @@ namespace Resource { - ResourceManager::ResourceManager(const VFS::Manager *vfs, const double expiryDelay) + ResourceManager::ResourceManager(const VFS::Manager *vfs) : mVFS(vfs) , mCache(new Resource::ObjectCache) - , mExpiryDelay(expiryDelay) + , mExpiryDelay(0.0) { } @@ -26,6 +26,11 @@ namespace Resource mCache->clear(); } + void ResourceManager::setExpiryDelay(double expiryDelay) + { + mExpiryDelay = expiryDelay; + } + const VFS::Manager* ResourceManager::getVFS() const { return mVFS; diff --git a/components/resource/resourcemanager.hpp b/components/resource/resourcemanager.hpp index a9b6ab3d5..d2a1d1023 100644 --- a/components/resource/resourcemanager.hpp +++ b/components/resource/resourcemanager.hpp @@ -17,8 +17,7 @@ namespace Resource class ResourceManager { public: - /// @param expiryDelay how long to keep objects in cache after no longer being referenced. - ResourceManager(const VFS::Manager* vfs, const double expiryDelay = 300.0); + ResourceManager(const VFS::Manager* vfs); /// Clear cache entries that have not been referenced for longer than expiryDelay. virtual void updateCache(double referenceTime); @@ -26,6 +25,9 @@ namespace Resource /// Clear all cache entries regardless of having external references. virtual void clearCache(); + /// How long to keep objects in cache after no longer being referenced. + void setExpiryDelay (double expiryDelay); + const VFS::Manager* getVFS() const; protected: diff --git a/components/resource/resourcesystem.cpp b/components/resource/resourcesystem.cpp index a8ab6556d..5772f2b85 100644 --- a/components/resource/resourcesystem.cpp +++ b/components/resource/resourcesystem.cpp @@ -52,6 +52,16 @@ namespace Resource return mKeyframeManager.get(); } + void ResourceSystem::setExpiryDelay(double expiryDelay) + { + for (std::vector::iterator it = mResourceManagers.begin(); it != mResourceManagers.end(); ++it) + (*it)->setExpiryDelay(expiryDelay); + + // NIF files aren't needed any more once the converted objects are cached in SceneManager / BulletShapeManager, + // so no point in using an expiry delay + mNifFileManager->setExpiryDelay(0.0); + } + void ResourceSystem::updateCache(double referenceTime) { for (std::vector::iterator it = mResourceManagers.begin(); it != mResourceManagers.end(); ++it) diff --git a/components/resource/resourcesystem.hpp b/components/resource/resourcesystem.hpp index 30607432d..9b933ffc4 100644 --- a/components/resource/resourcesystem.hpp +++ b/components/resource/resourcesystem.hpp @@ -43,6 +43,9 @@ namespace Resource /// @note Does not delete resourceMgr. void removeResourceManager(ResourceManager* resourceMgr); + /// How long to keep objects in cache after no longer being referenced. + void setExpiryDelay(double expiryDelay); + /// @note May be called from any thread. const VFS::Manager* getVFS() const; diff --git a/files/settings-default.cfg b/files/settings-default.cfg index c03342600..4df20e709 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -43,6 +43,10 @@ preload enabled = true # Preloading distance threshold preload distance = 1000 +# How long to keep preloaded cells and cached models/textures/collision shapes in cache +# after they're no longer referenced/required (in seconds) +cache expiry delay = 300 + [Map] # Size of each exterior cell in pixels in the world map. (e.g. 12 to 24). From a34a08c212074693e88289371f9702acff1eb959 Mon Sep 17 00:00:00 2001 From: Rob Cutmore Date: Sun, 7 Feb 2016 13:52:18 -0500 Subject: [PATCH 3109/3725] Render cell markers Adds rendering of cell markers. Markers are displayed at center of cell and contain cell's coordinates. --- apps/opencs/CMakeLists.txt | 5 ++- apps/opencs/view/render/cell.cpp | 7 +++ apps/opencs/view/render/cell.hpp | 5 +++ apps/opencs/view/render/cellmarker.cpp | 62 ++++++++++++++++++++++++++ apps/opencs/view/render/cellmarker.hpp | 48 ++++++++++++++++++++ 5 files changed, 125 insertions(+), 2 deletions(-) create mode 100644 apps/opencs/view/render/cellmarker.cpp create mode 100644 apps/opencs/view/render/cellmarker.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 0bde541bf..c9245ca9f 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -35,7 +35,7 @@ opencs_hdrs_noqt (model/world opencs_units (model/tools - tools reportmodel mergeoperation + tools reportmodel mergeoperation ) opencs_units_noqt (model/tools @@ -90,7 +90,7 @@ opencs_units (view/render opencs_units_noqt (view/render lighting lightingday lightingnight - lightingbright object cell terrainstorage tagbase cellarrow + lightingbright object cell terrainstorage tagbase cellarrow cellmarker ) opencs_hdrs_noqt (view/render @@ -192,6 +192,7 @@ endif(APPLE) target_link_libraries(openmw-cs ${OSG_LIBRARIES} ${OPENTHREADS_LIBRARIES} + ${OSGTEXT_LIBRARIES} ${OSGUTIL_LIBRARIES} ${OSGVIEWER_LIBRARIES} ${OSGGA_LIBRARIES} diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index bd85c8a14..0030fd9b8 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -70,6 +70,8 @@ CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::st mCellNode = new osg::Group; rootNode->addChild(mCellNode); + setCellMarker(); + if (!mDeleted) { CSMWorld::IdTable& references = dynamic_cast ( @@ -303,6 +305,11 @@ void CSVRender::Cell::setCellArrows (int mask) } } +void CSVRender::Cell::setCellMarker() +{ + mCellMarker.reset(new CellMarker(mCellNode, mCoordinates)); +} + CSMWorld::CellCoordinates CSVRender::Cell::getCoordinates() const { return mCoordinates; diff --git a/apps/opencs/view/render/cell.hpp b/apps/opencs/view/render/cell.hpp index 85b9bf21b..22f9872e3 100644 --- a/apps/opencs/view/render/cell.hpp +++ b/apps/opencs/view/render/cell.hpp @@ -15,6 +15,7 @@ #include "object.hpp" #include "cellarrow.hpp" +#include "cellmarker.hpp" class QModelIndex; @@ -42,6 +43,7 @@ namespace CSVRender std::auto_ptr mTerrain; CSMWorld::CellCoordinates mCoordinates; std::auto_ptr mCellArrows[4]; + std::auto_ptr mCellMarker; bool mDeleted; /// Ignored if cell does not have an object with the given ID. @@ -105,6 +107,9 @@ namespace CSVRender void setCellArrows (int mask); + /// \brief Set marker for this cell. + void setCellMarker(); + /// Returns 0, 0 in case of an unpaged cell. CSMWorld::CellCoordinates getCoordinates() const; diff --git a/apps/opencs/view/render/cellmarker.cpp b/apps/opencs/view/render/cellmarker.cpp new file mode 100644 index 000000000..17bb05440 --- /dev/null +++ b/apps/opencs/view/render/cellmarker.cpp @@ -0,0 +1,62 @@ +#include "cellmarker.hpp" + +#include + +#include +#include +#include +#include + +void CSVRender::CellMarker::buildMarker() +{ + const int characterSize = 20; + + // Set up marker text containing cell's coordinates. + osg::ref_ptr markerText (new osgText::Text); + markerText->setBackdropType(osgText::Text::OUTLINE); + markerText->setLayout(osgText::Text::LEFT_TO_RIGHT); + markerText->setCharacterSize(characterSize); + std::string coordinatesText = + "#" + boost::lexical_cast(mCoordinates.getX()) + + " " + boost::lexical_cast(mCoordinates.getY()); + markerText->setText(coordinatesText); + + // Add text to marker node. + osg::ref_ptr geode (new osg::Geode); + geode->addDrawable(markerText); + mMarkerNode->addChild(geode); +} + +void CSVRender::CellMarker::positionMarker() +{ + const int cellSize = 8192; + const int markerHeight = 0; + + // Move marker to center of cell. + int x = (mCoordinates.getX() * cellSize) + (cellSize / 2); + int y = (mCoordinates.getY() * cellSize) + (cellSize / 2); + mMarkerNode->setPosition(osg::Vec3f(x, y, markerHeight)); +} + +CSVRender::CellMarker::CellMarker( + osg::Group *cellNode, + const CSMWorld::CellCoordinates& coordinates +) : mCellNode(cellNode), + mCoordinates(coordinates) +{ + // Set up node for cell marker. + mMarkerNode = new osg::AutoTransform(); + mMarkerNode->setAutoRotateMode(osg::AutoTransform::ROTATE_TO_SCREEN); + mMarkerNode->setAutoScaleToScreen(true); + mMarkerNode->getOrCreateStateSet()->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF); + + mCellNode->addChild(mMarkerNode); + + buildMarker(); + positionMarker(); +} + +CSVRender::CellMarker::~CellMarker() +{ + mCellNode->removeChild(mMarkerNode); +} diff --git a/apps/opencs/view/render/cellmarker.hpp b/apps/opencs/view/render/cellmarker.hpp new file mode 100644 index 000000000..4ac9d86b0 --- /dev/null +++ b/apps/opencs/view/render/cellmarker.hpp @@ -0,0 +1,48 @@ +#ifndef OPENCS_VIEW_CELLMARKER_H +#define OPENCS_VIEW_CELLMARKER_H + +#include + +#include "../../model/world/cellcoordinates.hpp" + +namespace osg +{ + class AutoTransform; + class Group; +} + +namespace CSVRender +{ + /// \brief Marker to display cell coordinates. + class CellMarker + { + private: + + osg::Group* mCellNode; + osg::ref_ptr mMarkerNode; + CSMWorld::CellCoordinates mCoordinates; + + // Not implemented. + CellMarker(const CellMarker&); + CellMarker& operator=(const CellMarker&); + + /// \brief Build marker containing cell's coordinates. + void buildMarker(); + + /// \brief Position marker above center of cell. + void positionMarker(); + + public: + + /// \brief Constructor. + /// \param cellNode Cell to create marker for. + /// \param coordinates Coordinates of cell. + CellMarker( + osg::Group *cellNode, + const CSMWorld::CellCoordinates& coordinates); + + ~CellMarker(); + }; +} + +#endif From c8054424c946ed5433b325d2f1301f16d7d78b64 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 7 Feb 2016 22:37:52 +0100 Subject: [PATCH 3110/3725] Preload items equipped by NPCs --- apps/openmw/mwworld/cellpreloader.cpp | 68 ++++++++++++++++++++++++--- apps/openmw/mwworld/cellpreloader.hpp | 2 +- apps/openmw/mwworld/scene.cpp | 7 +++ components/resource/scenemanager.cpp | 3 ++ 4 files changed, 73 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwworld/cellpreloader.cpp b/apps/openmw/mwworld/cellpreloader.cpp index 13ce75d68..6bf28cb48 100644 --- a/apps/openmw/mwworld/cellpreloader.cpp +++ b/apps/openmw/mwworld/cellpreloader.cpp @@ -5,10 +5,14 @@ #include #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" +#include "../mwworld/inventorystore.hpp" +#include "../mwworld/esmstore.hpp" + #include "cellstore.hpp" #include "manualref.hpp" #include "class.hpp" @@ -23,11 +27,54 @@ namespace MWWorld { } - virtual bool operator()(const MWWorld::ConstPtr& ptr) + virtual bool operator()(const MWWorld::Ptr& ptr) { std::string model = ptr.getClass().getModel(ptr); if (!model.empty()) mOut.push_back(model); + + // TODO: preload NPC body parts (mHead / mHair) + + // FIXME: use const version of InventoryStore functions once they are available + if (ptr.getClass().hasInventoryStore(ptr)) + { + MWWorld::InventoryStore& invStore = ptr.getClass().getInventoryStore(ptr); + for (int slot = 0; slot < MWWorld::InventoryStore::Slots; ++slot) + { + MWWorld::ContainerStoreIterator equipped = invStore.getSlot(slot); + if (equipped != invStore.end()) + { + std::vector parts; + if(equipped->getTypeName() == typeid(ESM::Clothing).name()) + { + const ESM::Clothing *clothes = equipped->get()->mBase; + parts = clothes->mParts.mParts; + } + else if(equipped->getTypeName() == typeid(ESM::Armor).name()) + { + const ESM::Armor *armor = equipped->get()->mBase; + parts = armor->mParts.mParts; + } + else + { + model = equipped->getClass().getModel(*equipped); + if (!model.empty()) + mOut.push_back(model); + } + + for (std::vector::const_iterator it = parts.begin(); it != parts.end(); ++it) + { + const ESM::BodyPart* part = MWBase::Environment::get().getWorld()->getStore().get().search(it->mMale); + if (part && !part->mModel.empty()) + mOut.push_back("meshes/"+part->mModel); + part = MWBase::Environment::get().getWorld()->getStore().get().search(it->mFemale); + if (part && !part->mModel.empty()) + mOut.push_back("meshes/"+part->mModel); + } + } + } + } + return true; } @@ -39,14 +86,15 @@ namespace MWWorld { public: /// Constructor to be called from the main thread. - PreloadItem(const MWWorld::CellStore* cell, Resource::SceneManager* sceneManager, Resource::BulletShapeManager* bulletShapeManager) + PreloadItem(MWWorld::CellStore* cell, Resource::SceneManager* sceneManager, Resource::BulletShapeManager* bulletShapeManager) : mSceneManager(sceneManager) , mBulletShapeManager(bulletShapeManager) { + osg::Timer timer; + ListModelsVisitor visitor (mMeshes); if (cell->getState() == MWWorld::CellStore::State_Loaded) { - ListModelsVisitor visitor (mMeshes); - cell->forEachConst(visitor); + cell->forEach(visitor); } else { @@ -61,6 +109,7 @@ namespace MWWorld mMeshes.push_back(model); } } + std::cout << "listed models in " << timer.time_m() << std::endl; } /// Preload work to be called from the worker thread. @@ -73,9 +122,16 @@ namespace MWWorld { try { + std::string mesh = *it; + Misc::ResourceHelpers::correctActorModelPath(mesh, mSceneManager->getVFS()); + + //std::cout << "preloading " << mesh << std::endl; + mPreloadedNodes.push_back(mSceneManager->getTemplate(*it)); mPreloadedShapes.push_back(mBulletShapeManager->getShape(*it)); + // TODO: load .kf + // TODO: do a createInstance() and hold on to it since we can make use of it when the cell goes active } catch (std::exception& e) @@ -84,7 +140,7 @@ namespace MWWorld // error will be shown when visiting the cell } } - std::cout << "preloaded " << mPreloadedNodes.size() << " nodes in " << preloadTimer.time_m() << std::endl; + //std::cout << "preloaded " << mPreloadedNodes.size() << " nodes in " << preloadTimer.time_m() << std::endl; } private: @@ -128,7 +184,7 @@ namespace MWWorld mWorkQueue = new SceneUtil::WorkQueue; } - void CellPreloader::preload(const CellStore *cell, double timestamp) + void CellPreloader::preload(CellStore *cell, double timestamp) { if (!mWorkQueue) { diff --git a/apps/openmw/mwworld/cellpreloader.hpp b/apps/openmw/mwworld/cellpreloader.hpp index 5a2432179..c7495182b 100644 --- a/apps/openmw/mwworld/cellpreloader.hpp +++ b/apps/openmw/mwworld/cellpreloader.hpp @@ -22,7 +22,7 @@ namespace MWWorld /// Ask a background thread to preload rendering meshes and collision shapes for objects in this cell. /// @note The cell itself must be in State_Loaded or State_Preloaded. - void preload(const MWWorld::CellStore* cell, double timestamp); + void preload(MWWorld::CellStore* cell, double timestamp); /// Removes preloaded cells that have not had a preload request for a while. void updateCache(double timestamp); diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 86f40df73..321c1c622 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -329,6 +330,7 @@ namespace MWWorld void Scene::changeCellGrid (int X, int Y) { + osg::Timer timer; Loading::Listener* loadingListener = MWBase::Environment::get().getWindowManager()->getLoadingScreen(); Loading::ScopedLoad load(loadingListener); @@ -413,6 +415,8 @@ namespace MWWorld mPreloader->updateCache(mRendering.getReferenceTime()); mRendering.clearCache(); + + std::cout << "changeCellGrid took " << timer.time_m() << std::endl; } void Scene::changePlayerCell(CellStore *cell, const ESM::Position &pos, bool adjustPlayerPos) @@ -477,6 +481,7 @@ namespace MWWorld void Scene::changeToInteriorCell (const std::string& cellName, const ESM::Position& position) { + osg::Timer timer; CellStore *cell = MWBase::Environment::get().getWorld()->getInterior(cellName); bool loadcell = (mCurrentCell == NULL); if(!loadcell) @@ -537,6 +542,8 @@ namespace MWWorld mPreloader->updateCache(mRendering.getReferenceTime()); mRendering.clearCache(); + + std::cout << "change to interior took " << timer.time_m() << std::endl; } void Scene::changeToExteriorCell (const ESM::Position& position, bool adjustPlayerPos) diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index 46d975631..f083e8175 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -1,5 +1,6 @@ #include "scenemanager.hpp" +#include #include #include #include @@ -364,6 +365,8 @@ namespace Resource if (mIncrementalCompileOperation) mIncrementalCompileOperation->add(loaded); + //std::cout << "loading " << normalized << std::endl; + mCache->addEntryToObjectCache(normalized, loaded); return loaded; } From e4e313fe129fa2c96440e53a8fc9e2ba8bca2fd1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 8 Feb 2016 14:41:21 +0100 Subject: [PATCH 3111/3725] Remove outdated comment --- apps/openmw/mwworld/cellpreloader.cpp | 2 +- components/resource/resourcemanager.cpp | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/openmw/mwworld/cellpreloader.cpp b/apps/openmw/mwworld/cellpreloader.cpp index 6bf28cb48..d9875e0b7 100644 --- a/apps/openmw/mwworld/cellpreloader.cpp +++ b/apps/openmw/mwworld/cellpreloader.cpp @@ -140,7 +140,7 @@ namespace MWWorld // error will be shown when visiting the cell } } - //std::cout << "preloaded " << mPreloadedNodes.size() << " nodes in " << preloadTimer.time_m() << std::endl; + std::cout << "preloaded " << mPreloadedNodes.size() << " nodes in " << preloadTimer.time_m() << std::endl; } private: diff --git a/components/resource/resourcemanager.cpp b/components/resource/resourcemanager.cpp index b6b38bfa2..e5f6d9f43 100644 --- a/components/resource/resourcemanager.cpp +++ b/components/resource/resourcemanager.cpp @@ -15,8 +15,6 @@ namespace Resource void ResourceManager::updateCache(double referenceTime) { - // NOTE: we could clear the cache from the background thread if the deletion proves too much of an overhead - // idea: customize objectCache to not hold a lock while doing the actual deletion mCache->updateTimeStampOfObjectsInCacheWithExternalReferences(referenceTime); mCache->removeExpiredObjectsInCache(referenceTime - mExpiryDelay); } From ef5de945483ab719df31cb3c392a2a0e8b46c9dc Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 8 Feb 2016 15:31:09 +0100 Subject: [PATCH 3112/3725] Fix correctActorModelPath --- apps/openmw/mwworld/cellpreloader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/cellpreloader.cpp b/apps/openmw/mwworld/cellpreloader.cpp index d9875e0b7..b45d1de5b 100644 --- a/apps/openmw/mwworld/cellpreloader.cpp +++ b/apps/openmw/mwworld/cellpreloader.cpp @@ -123,7 +123,7 @@ namespace MWWorld try { std::string mesh = *it; - Misc::ResourceHelpers::correctActorModelPath(mesh, mSceneManager->getVFS()); + mesh = Misc::ResourceHelpers::correctActorModelPath(mesh, mSceneManager->getVFS()); //std::cout << "preloading " << mesh << std::endl; From fc0be77e4c02ee182141c103be3404757240708b Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 8 Feb 2016 15:51:31 +0100 Subject: [PATCH 3113/3725] Preload keyframes --- apps/openmw/mwworld/cellpreloader.cpp | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwworld/cellpreloader.cpp b/apps/openmw/mwworld/cellpreloader.cpp index b45d1de5b..4780582c5 100644 --- a/apps/openmw/mwworld/cellpreloader.cpp +++ b/apps/openmw/mwworld/cellpreloader.cpp @@ -5,7 +5,9 @@ #include #include #include +#include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -86,9 +88,10 @@ namespace MWWorld { public: /// Constructor to be called from the main thread. - PreloadItem(MWWorld::CellStore* cell, Resource::SceneManager* sceneManager, Resource::BulletShapeManager* bulletShapeManager) + PreloadItem(MWWorld::CellStore* cell, Resource::SceneManager* sceneManager, Resource::BulletShapeManager* bulletShapeManager, Resource::KeyframeManager* keyframeManager) : mSceneManager(sceneManager) , mBulletShapeManager(bulletShapeManager) + , mKeyframeManager(keyframeManager) { osg::Timer timer; ListModelsVisitor visitor (mMeshes); @@ -130,7 +133,21 @@ namespace MWWorld mPreloadedNodes.push_back(mSceneManager->getTemplate(*it)); mPreloadedShapes.push_back(mBulletShapeManager->getShape(*it)); - // TODO: load .kf + size_t slashpos = mesh.find_last_of("/\\"); + if (slashpos != std::string::npos && slashpos != mesh.size()-1) + { + Misc::StringUtils::lowerCaseInPlace(mesh); + if (mesh[slashpos+1] == 'x') + { + std::string kfname = mesh; + if(kfname.size() > 4 && kfname.compare(kfname.size()-4, 4, ".nif") == 0) + { + kfname.replace(kfname.size()-4, 4, ".kf"); + mPreloadedKeyframes.push_back(mKeyframeManager->get(kfname)); + } + + } + } // TODO: do a createInstance() and hold on to it since we can make use of it when the cell goes active } @@ -148,10 +165,12 @@ namespace MWWorld MeshList mMeshes; Resource::SceneManager* mSceneManager; Resource::BulletShapeManager* mBulletShapeManager; + Resource::KeyframeManager* mKeyframeManager; // keep a ref to the loaded object to make sure it stays loaded as long as this cell is in the preloaded state std::vector > mPreloadedNodes; std::vector > mPreloadedShapes; + std::vector > mPreloadedKeyframes; }; /// Worker thread item: update the resource system's cache, effectively deleting unused entries. @@ -205,7 +224,7 @@ namespace MWWorld return; } - osg::ref_ptr item (new PreloadItem(cell, mResourceSystem->getSceneManager(), mBulletShapeManager)); + osg::ref_ptr item (new PreloadItem(cell, mResourceSystem->getSceneManager(), mBulletShapeManager, mResourceSystem->getKeyframeManager())); mWorkQueue->addWorkItem(item); mPreloadCells[cell] = PreloadEntry(timestamp, item); From b2019d31c72d5dd4a30c9b8b7aa214d6dbdf24da Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 8 Feb 2016 15:55:05 +0100 Subject: [PATCH 3114/3725] Mark thread safe methods in BsaFile --- components/bsa/bsa_file.hpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/components/bsa/bsa_file.hpp b/components/bsa/bsa_file.hpp index 8ed63f35d..5ff86ef65 100644 --- a/components/bsa/bsa_file.hpp +++ b/components/bsa/bsa_file.hpp @@ -90,6 +90,7 @@ private: void readHeader(); /// Get the index of a given file name, or -1 if not found + /// @note Thread safe. int getIndex(const char *str) const; public: @@ -116,12 +117,17 @@ public: /** Open a file contained in the archive. Throws an exception if the file doesn't exist. + * @note Thread safe. */ Files::IStreamPtr getFile(const char *file); + /** Open a file contained in the archive. + * @note Thread safe. + */ Files::IStreamPtr getFile(const FileStruct* file); /// Get a list of all files + /// @note Thread safe. const FileList &getList() const { return files; } }; From 84f01b7527c5359ba441e0b3efc1f15c469f0d0c Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 8 Feb 2016 16:27:28 +0100 Subject: [PATCH 3115/3725] Remove unneeded forward declaration --- components/sceneutil/workqueue.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/components/sceneutil/workqueue.hpp b/components/sceneutil/workqueue.hpp index 06489dfbb..bc2e55647 100644 --- a/components/sceneutil/workqueue.hpp +++ b/components/sceneutil/workqueue.hpp @@ -37,7 +37,6 @@ namespace SceneUtil OpenThreads::Condition mCondition; }; - class WorkQueue; class WorkThread; /// @brief A work queue that users can push work items onto, to be completed by one or more background threads. From effe022bb2a2e5d15cc03324facd11a145d639dd Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 8 Feb 2016 20:52:32 +0100 Subject: [PATCH 3116/3725] Move preload model list to MWClass, preload NPC head/hair --- apps/openmw/mwclass/creature.cpp | 23 +++++++++ apps/openmw/mwclass/creature.hpp | 3 ++ apps/openmw/mwclass/npc.cpp | 68 +++++++++++++++++++++++++++ apps/openmw/mwclass/npc.hpp | 3 ++ apps/openmw/mwworld/cellpreloader.cpp | 46 +----------------- apps/openmw/mwworld/class.cpp | 7 +++ apps/openmw/mwworld/class.hpp | 3 ++ 7 files changed, 108 insertions(+), 45 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index e9502d86b..6e9cfccb9 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -182,6 +182,29 @@ namespace MWClass return ""; } + void Creature::getModelsToPreload(const MWWorld::Ptr &ptr, std::vector &models) const + { + std::string model = getModel(ptr); + if (!model.empty()) + models.push_back(model); + + // FIXME: use const version of InventoryStore functions once they are available + if (ptr.getClass().hasInventoryStore(ptr)) + { + MWWorld::InventoryStore& invStore = ptr.getClass().getInventoryStore(ptr); + for (int slot = 0; slot < MWWorld::InventoryStore::Slots; ++slot) + { + MWWorld::ContainerStoreIterator equipped = invStore.getSlot(slot); + if (equipped != invStore.end()) + { + model = equipped->getClass().getModel(*equipped); + if (!model.empty()) + models.push_back(model); + } + } + } + } + std::string Creature::getName (const MWWorld::ConstPtr& ptr) const { const MWWorld::LiveCellRef *ref = ptr.get(); diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index cb89a53d6..bea56887a 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -101,6 +101,9 @@ namespace MWClass virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; + virtual void getModelsToPreload(const MWWorld::Ptr& ptr, std::vector& models) const; + ///< Get a list of models to preload that this object may use (directly or indirectly). default implementation: list getModel(). + virtual bool isActor() const { return true; diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 57a6d088a..14bd0640c 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -429,6 +429,74 @@ namespace MWClass return model; } + void Npc::getModelsToPreload(const MWWorld::Ptr &ptr, std::vector &models) const + { + const MWWorld::LiveCellRef *npc = ptr.get(); + const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get().search(npc->mBase->mRace); + if(race && race->mData.mFlags & ESM::Race::Beast) + models.push_back("meshes\\base_animkna.nif"); + + // keep these always loaded just in case + models.push_back("meshes/xargonian_swimkna.nif"); + models.push_back("meshes/xbase_anim_female.nif"); + models.push_back("meshes/xbase_anim.nif"); + + if (!npc->mBase->mModel.empty()) + models.push_back("meshes/"+npc->mBase->mModel); + + if (!npc->mBase->mHead.empty()) + { + const ESM::BodyPart* head = MWBase::Environment::get().getWorld()->getStore().get().search(npc->mBase->mHead); + if (head) + models.push_back("meshes/"+head->mModel); + } + if (!npc->mBase->mHair.empty()) + { + const ESM::BodyPart* hair = MWBase::Environment::get().getWorld()->getStore().get().search(npc->mBase->mHair); + if (hair) + models.push_back("meshes/"+hair->mModel); + } + + // FIXME: use const version of InventoryStore functions once they are available + if (ptr.getClass().hasInventoryStore(ptr)) + { + MWWorld::InventoryStore& invStore = ptr.getClass().getInventoryStore(ptr); + for (int slot = 0; slot < MWWorld::InventoryStore::Slots; ++slot) + { + MWWorld::ContainerStoreIterator equipped = invStore.getSlot(slot); + if (equipped != invStore.end()) + { + std::vector parts; + if(equipped->getTypeName() == typeid(ESM::Clothing).name()) + { + const ESM::Clothing *clothes = equipped->get()->mBase; + parts = clothes->mParts.mParts; + } + else if(equipped->getTypeName() == typeid(ESM::Armor).name()) + { + const ESM::Armor *armor = equipped->get()->mBase; + parts = armor->mParts.mParts; + } + else + { + std::string model = equipped->getClass().getModel(*equipped); + if (!model.empty()) + models.push_back(model); + } + + for (std::vector::const_iterator it = parts.begin(); it != parts.end(); ++it) + { + const std::string& partname = (npc->mBase->mFlags & ESM::NPC::Female) ? it->mFemale : it->mMale; + const ESM::BodyPart* part = MWBase::Environment::get().getWorld()->getStore().get().search(partname); + if (part && !part->mModel.empty()) + models.push_back("meshes/"+part->mModel); + } + } + } + } + + } + std::string Npc::getName (const MWWorld::ConstPtr& ptr) const { if(ptr.getRefData().getCustomData() && ptr.getRefData().getCustomData()->asNpcCustomData().mNpcStats.isWerewolf()) diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index 5df34380a..95edbd408 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -75,6 +75,9 @@ namespace MWClass virtual void onHit(const MWWorld::Ptr &ptr, float damage, bool ishealth, const MWWorld::Ptr &object, const MWWorld::Ptr &attacker, bool successful) const; + virtual void getModelsToPreload(const MWWorld::Ptr& ptr, std::vector& models) const; + ///< Get a list of models to preload that this object may use (directly or indirectly). default implementation: list getModel(). + virtual boost::shared_ptr activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const; ///< Generate action for activation diff --git a/apps/openmw/mwworld/cellpreloader.cpp b/apps/openmw/mwworld/cellpreloader.cpp index 4780582c5..1a8ee2709 100644 --- a/apps/openmw/mwworld/cellpreloader.cpp +++ b/apps/openmw/mwworld/cellpreloader.cpp @@ -31,51 +31,7 @@ namespace MWWorld virtual bool operator()(const MWWorld::Ptr& ptr) { - std::string model = ptr.getClass().getModel(ptr); - if (!model.empty()) - mOut.push_back(model); - - // TODO: preload NPC body parts (mHead / mHair) - - // FIXME: use const version of InventoryStore functions once they are available - if (ptr.getClass().hasInventoryStore(ptr)) - { - MWWorld::InventoryStore& invStore = ptr.getClass().getInventoryStore(ptr); - for (int slot = 0; slot < MWWorld::InventoryStore::Slots; ++slot) - { - MWWorld::ContainerStoreIterator equipped = invStore.getSlot(slot); - if (equipped != invStore.end()) - { - std::vector parts; - if(equipped->getTypeName() == typeid(ESM::Clothing).name()) - { - const ESM::Clothing *clothes = equipped->get()->mBase; - parts = clothes->mParts.mParts; - } - else if(equipped->getTypeName() == typeid(ESM::Armor).name()) - { - const ESM::Armor *armor = equipped->get()->mBase; - parts = armor->mParts.mParts; - } - else - { - model = equipped->getClass().getModel(*equipped); - if (!model.empty()) - mOut.push_back(model); - } - - for (std::vector::const_iterator it = parts.begin(); it != parts.end(); ++it) - { - const ESM::BodyPart* part = MWBase::Environment::get().getWorld()->getStore().get().search(it->mMale); - if (part && !part->mModel.empty()) - mOut.push_back("meshes/"+part->mModel); - part = MWBase::Environment::get().getWorld()->getStore().get().search(it->mFemale); - if (part && !part->mModel.empty()) - mOut.push_back("meshes/"+part->mModel); - } - } - } - } + ptr.getClass().getModelsToPreload(ptr, mOut); return true; } diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 7f2d759b9..ecfe7cb7c 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -291,6 +291,13 @@ namespace MWWorld return ""; } + void Class::getModelsToPreload(const Ptr &ptr, std::vector &models) const + { + std::string model = getModel(ptr); + if (!model.empty()) + models.push_back(model); + } + std::string Class::applyEnchantment(const MWWorld::ConstPtr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const { throw std::runtime_error ("class can't be enchanted"); diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 85cd9ff7c..0bb3edbee 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -262,6 +262,9 @@ namespace MWWorld virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; + virtual void getModelsToPreload(const MWWorld::Ptr& ptr, std::vector& models) const; + ///< Get a list of models to preload that this object may use (directly or indirectly). default implementation: list getModel(). + virtual std::string applyEnchantment(const MWWorld::ConstPtr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; ///< Creates a new record using \a ptr as template, with the given name and the given enchantment applied to it. From 84dcf59c50b21604c18ffc62078ea0f5d8499bd5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 8 Feb 2016 22:57:34 +0100 Subject: [PATCH 3117/3725] Fix preloading of equipment parts that don't separate gender --- apps/openmw/mwclass/npc.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 14bd0640c..5f7f91329 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -486,7 +486,9 @@ namespace MWClass for (std::vector::const_iterator it = parts.begin(); it != parts.end(); ++it) { - const std::string& partname = (npc->mBase->mFlags & ESM::NPC::Female) ? it->mFemale : it->mMale; + std::string partname = (npc->mBase->mFlags & ESM::NPC::Female) ? it->mFemale : it->mMale; + if (partname.empty()) + partname = (npc->mBase->mFlags & ESM::NPC::Female) ? it->mMale : it->mFemale; const ESM::BodyPart* part = MWBase::Environment::get().getWorld()->getStore().get().search(partname); if (part && !part->mModel.empty()) models.push_back("meshes/"+part->mModel); From 1b8e82e92978c53c4e7d13427975cb49ca72fe19 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 9 Feb 2016 00:26:22 +0100 Subject: [PATCH 3118/3725] Preload NPC body parts --- apps/openmw/mwclass/npc.cpp | 20 ++- apps/openmw/mwrender/npcanimation.cpp | 220 +++++++++++++------------- apps/openmw/mwrender/npcanimation.hpp | 5 + 3 files changed, 136 insertions(+), 109 deletions(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 5f7f91329..3519f9d83 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -37,6 +37,7 @@ #include "../mwrender/objects.hpp" #include "../mwrender/renderinginterface.hpp" +#include "../mwrender/npcanimation.hpp" #include "../mwgui/tooltips.hpp" @@ -457,7 +458,10 @@ namespace MWClass models.push_back("meshes/"+hair->mModel); } + bool female = (npc->mBase->mFlags & ESM::NPC::Female); + // FIXME: use const version of InventoryStore functions once they are available + // preload equipped items if (ptr.getClass().hasInventoryStore(ptr)) { MWWorld::InventoryStore& invStore = ptr.getClass().getInventoryStore(ptr); @@ -486,9 +490,9 @@ namespace MWClass for (std::vector::const_iterator it = parts.begin(); it != parts.end(); ++it) { - std::string partname = (npc->mBase->mFlags & ESM::NPC::Female) ? it->mFemale : it->mMale; + std::string partname = female ? it->mFemale : it->mMale; if (partname.empty()) - partname = (npc->mBase->mFlags & ESM::NPC::Female) ? it->mMale : it->mFemale; + partname = female ? it->mMale : it->mFemale; const ESM::BodyPart* part = MWBase::Environment::get().getWorld()->getStore().get().search(partname); if (part && !part->mModel.empty()) models.push_back("meshes/"+part->mModel); @@ -497,6 +501,18 @@ namespace MWClass } } + // preload body parts + if (race) + { + const std::vector& parts = MWRender::NpcAnimation::getBodyParts(Misc::StringUtils::lowerCase(race->mId), female, false, false); + for (std::vector::const_iterator it = parts.begin(); it != parts.end(); ++it) + { + const ESM::BodyPart* part = *it; + if (part && !part->mModel.empty()) + models.push_back("meshes/"+part->mModel); + } + } + } std::string Npc::getName (const MWWorld::ConstPtr& ptr) const diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index c8d7c79c5..026b3a2cf 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -619,116 +619,10 @@ void NpcAnimation::updateParts() showWeapons(mShowWeapons); showCarriedLeft(mShowCarriedLeft); - // Remember body parts so we only have to search through the store once for each race/gender/viewmode combination - static std::map< std::pair,std::vector > sRaceMapping; - bool isWerewolf = (mNpcType == Type_Werewolf); - int flags = (isWerewolf ? -1 : 0); - if(!mNpc->isMale()) - { - static const int Flag_Female = 1<<0; - flags |= Flag_Female; - } - if(mViewMode == VM_FirstPerson) - { - static const int Flag_FirstPerson = 1<<1; - flags |= Flag_FirstPerson; - } - std::string race = (isWerewolf ? "werewolf" : Misc::StringUtils::lowerCase(mNpc->mRace)); - std::pair thisCombination = std::make_pair(race, flags); - if (sRaceMapping.find(thisCombination) == sRaceMapping.end()) - { - typedef std::multimap BodyPartMapType; - static BodyPartMapType sBodyPartMap; - if(sBodyPartMap.empty()) - { - sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Neck, ESM::PRT_Neck)); - sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Chest, ESM::PRT_Cuirass)); - sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Groin, ESM::PRT_Groin)); - sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Hand, ESM::PRT_RHand)); - sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Hand, ESM::PRT_LHand)); - sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Wrist, ESM::PRT_RWrist)); - sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Wrist, ESM::PRT_LWrist)); - sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Forearm, ESM::PRT_RForearm)); - sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Forearm, ESM::PRT_LForearm)); - sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Upperarm, ESM::PRT_RUpperarm)); - sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Upperarm, ESM::PRT_LUpperarm)); - sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Foot, ESM::PRT_RFoot)); - sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Foot, ESM::PRT_LFoot)); - sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Ankle, ESM::PRT_RAnkle)); - sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Ankle, ESM::PRT_LAnkle)); - sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Knee, ESM::PRT_RKnee)); - sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Knee, ESM::PRT_LKnee)); - sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Upperleg, ESM::PRT_RLeg)); - sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Upperleg, ESM::PRT_LLeg)); - sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Tail, ESM::PRT_Tail)); - } - - std::vector &parts = sRaceMapping[thisCombination]; - parts.resize(ESM::PRT_Count, NULL); - - const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); - const MWWorld::Store &partStore = store.get(); - for(MWWorld::Store::iterator it = partStore.begin(); it != partStore.end(); ++it) - { - if(isWerewolf) - break; - const ESM::BodyPart& bodypart = *it; - if (bodypart.mData.mFlags & ESM::BodyPart::BPF_NotPlayable) - continue; - if (bodypart.mData.mType != ESM::BodyPart::MT_Skin) - continue; - - if (!Misc::StringUtils::ciEqual(bodypart.mRace, mNpc->mRace)) - continue; - - bool firstPerson = (bodypart.mId.size() >= 3) - && bodypart.mId[bodypart.mId.size()-3] == '1' - && bodypart.mId[bodypart.mId.size()-2] == 's' - && bodypart.mId[bodypart.mId.size()-1] == 't'; - if(firstPerson != (mViewMode == VM_FirstPerson)) - { - if(mViewMode == VM_FirstPerson && (bodypart.mData.mPart == ESM::BodyPart::MP_Hand || - bodypart.mData.mPart == ESM::BodyPart::MP_Wrist || - bodypart.mData.mPart == ESM::BodyPart::MP_Forearm || - bodypart.mData.mPart == ESM::BodyPart::MP_Upperarm)) - { - /* Allow 3rd person skins as a fallback for the arms if 1st person is missing. */ - BodyPartMapType::const_iterator bIt = sBodyPartMap.lower_bound(BodyPartMapType::key_type(bodypart.mData.mPart)); - while(bIt != sBodyPartMap.end() && bIt->first == bodypart.mData.mPart) - { - if(!parts[bIt->second]) - parts[bIt->second] = &*it; - ++bIt; - } - } - continue; - } - if ((!mNpc->isMale()) != (bodypart.mData.mFlags & ESM::BodyPart::BPF_Female)) - { - // Allow opposite gender's parts as fallback if parts for our gender are missing - BodyPartMapType::const_iterator bIt = sBodyPartMap.lower_bound(BodyPartMapType::key_type(bodypart.mData.mPart)); - while(bIt != sBodyPartMap.end() && bIt->first == bodypart.mData.mPart) - { - if(!parts[bIt->second]) - parts[bIt->second] = &*it; - ++bIt; - } - continue; - } - - BodyPartMapType::const_iterator bIt = sBodyPartMap.lower_bound(BodyPartMapType::key_type(bodypart.mData.mPart)); - while(bIt != sBodyPartMap.end() && bIt->first == bodypart.mData.mPart) - { - parts[bIt->second] = &*it; - ++bIt; - } - } - } - - const std::vector &parts = sRaceMapping[thisCombination]; + const std::vector &parts = getBodyParts(race, !mNpc->isMale(), mViewMode == VM_FirstPerson, isWerewolf); for(int part = ESM::PRT_Neck; part < ESM::PRT_Count; ++part) { if(mPartPriorities[part] < 1) @@ -1116,6 +1010,118 @@ void NpcAnimation::updatePtr(const MWWorld::Ptr &updated) mHeadAnimationTime->updatePtr(updated); } +// Remember body parts so we only have to search through the store once for each race/gender/viewmode combination +typedef std::map< std::pair,std::vector > RaceMapping; +static RaceMapping sRaceMapping; + +const std::vector& NpcAnimation::getBodyParts(const std::string &race, bool female, bool firstPerson, bool werewolf) +{ + static const int Flag_FirstPerson = 1<<1; + static const int Flag_Female = 1<<0; + + int flags = (werewolf ? -1 : 0); + if(female) + flags |= Flag_Female; + if(firstPerson) + flags |= Flag_FirstPerson; + + RaceMapping::iterator found = sRaceMapping.find(std::make_pair(race, flags)); + if (found != sRaceMapping.end()) + return found->second; + else + { + std::vector& parts = sRaceMapping[std::make_pair(race, flags)]; + + typedef std::multimap BodyPartMapType; + static BodyPartMapType sBodyPartMap; + if(sBodyPartMap.empty()) + { + sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Neck, ESM::PRT_Neck)); + sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Chest, ESM::PRT_Cuirass)); + sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Groin, ESM::PRT_Groin)); + sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Hand, ESM::PRT_RHand)); + sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Hand, ESM::PRT_LHand)); + sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Wrist, ESM::PRT_RWrist)); + sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Wrist, ESM::PRT_LWrist)); + sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Forearm, ESM::PRT_RForearm)); + sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Forearm, ESM::PRT_LForearm)); + sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Upperarm, ESM::PRT_RUpperarm)); + sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Upperarm, ESM::PRT_LUpperarm)); + sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Foot, ESM::PRT_RFoot)); + sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Foot, ESM::PRT_LFoot)); + sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Ankle, ESM::PRT_RAnkle)); + sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Ankle, ESM::PRT_LAnkle)); + sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Knee, ESM::PRT_RKnee)); + sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Knee, ESM::PRT_LKnee)); + sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Upperleg, ESM::PRT_RLeg)); + sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Upperleg, ESM::PRT_LLeg)); + sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Tail, ESM::PRT_Tail)); + } + + parts.resize(ESM::PRT_Count, NULL); + + const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); + const MWWorld::Store &partStore = store.get(); + for(MWWorld::Store::iterator it = partStore.begin(); it != partStore.end(); ++it) + { + if(werewolf) + break; + const ESM::BodyPart& bodypart = *it; + if (bodypart.mData.mFlags & ESM::BodyPart::BPF_NotPlayable) + continue; + if (bodypart.mData.mType != ESM::BodyPart::MT_Skin) + continue; + + if (!Misc::StringUtils::ciEqual(bodypart.mRace, race)) + continue; + + bool partFirstPerson = (bodypart.mId.size() >= 3) + && bodypart.mId[bodypart.mId.size()-3] == '1' + && bodypart.mId[bodypart.mId.size()-2] == 's' + && bodypart.mId[bodypart.mId.size()-1] == 't'; + if(partFirstPerson != (firstPerson)) + { + if(firstPerson && (bodypart.mData.mPart == ESM::BodyPart::MP_Hand || + bodypart.mData.mPart == ESM::BodyPart::MP_Wrist || + bodypart.mData.mPart == ESM::BodyPart::MP_Forearm || + bodypart.mData.mPart == ESM::BodyPart::MP_Upperarm)) + { + /* Allow 3rd person skins as a fallback for the arms if 1st person is missing. */ + BodyPartMapType::const_iterator bIt = sBodyPartMap.lower_bound(BodyPartMapType::key_type(bodypart.mData.mPart)); + while(bIt != sBodyPartMap.end() && bIt->first == bodypart.mData.mPart) + { + if(!parts[bIt->second]) + parts[bIt->second] = &*it; + ++bIt; + } + } + continue; + } + + if ((female) != (bodypart.mData.mFlags & ESM::BodyPart::BPF_Female)) + { + // Allow opposite gender's parts as fallback if parts for our gender are missing + BodyPartMapType::const_iterator bIt = sBodyPartMap.lower_bound(BodyPartMapType::key_type(bodypart.mData.mPart)); + while(bIt != sBodyPartMap.end() && bIt->first == bodypart.mData.mPart) + { + if(!parts[bIt->second]) + parts[bIt->second] = &*it; + ++bIt; + } + continue; + } + + BodyPartMapType::const_iterator bIt = sBodyPartMap.lower_bound(BodyPartMapType::key_type(bodypart.mData.mPart)); + while(bIt != sBodyPartMap.end() && bIt->first == bodypart.mData.mPart) + { + parts[bIt->second] = &*it; + ++bIt; + } + } + return parts; + } +} + void NpcAnimation::setAccurateAiming(bool enabled) { mAccurateAiming = enabled; diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index c5fc62f9c..baf9c8c24 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -10,6 +10,7 @@ namespace ESM { struct NPC; + struct BodyPart; } namespace MWRender @@ -150,6 +151,10 @@ public: void setFirstPersonOffset(const osg::Vec3f& offset); virtual void updatePtr(const MWWorld::Ptr& updated); + + /// Get a list of body parts that may be used by an NPC of given race and gender. + /// @note This is a fixed size list, one list item for each ESM::PartReferenceType, may contain NULL body parts. + static const std::vector& getBodyParts(const std::string& raceId, bool female, bool firstperson, bool werewolf); }; } From d16450bff2b934bc9f8053b510b1501348dc99ca Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 9 Feb 2016 00:28:27 +0100 Subject: [PATCH 3119/3725] Fix correctActorModelPath in preloader not being used --- apps/openmw/mwworld/cellpreloader.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/cellpreloader.cpp b/apps/openmw/mwworld/cellpreloader.cpp index 1a8ee2709..06216221b 100644 --- a/apps/openmw/mwworld/cellpreloader.cpp +++ b/apps/openmw/mwworld/cellpreloader.cpp @@ -86,8 +86,8 @@ namespace MWWorld //std::cout << "preloading " << mesh << std::endl; - mPreloadedNodes.push_back(mSceneManager->getTemplate(*it)); - mPreloadedShapes.push_back(mBulletShapeManager->getShape(*it)); + mPreloadedNodes.push_back(mSceneManager->getTemplate(mesh)); + mPreloadedShapes.push_back(mBulletShapeManager->getShape(mesh)); size_t slashpos = mesh.find_last_of("/\\"); if (slashpos != std::string::npos && slashpos != mesh.size()-1) From f9082502f8a91132fe45ab9d3f632f865aa2a29d Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 9 Feb 2016 01:02:40 +0100 Subject: [PATCH 3120/3725] Move construction of WorkQueue to RenderingManager --- apps/openmw/mwrender/renderingmanager.cpp | 7 +++++++ apps/openmw/mwrender/renderingmanager.hpp | 9 +++++++++ apps/openmw/mwworld/cellpreloader.cpp | 1 - apps/openmw/mwworld/scene.cpp | 1 + 4 files changed, 17 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 07b477c43..6ba30f32c 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include @@ -131,6 +132,7 @@ namespace MWRender : mViewer(viewer) , mRootNode(rootNode) , mResourceSystem(resourceSystem) + , mWorkQueue(new SceneUtil::WorkQueue) , mFogDepth(0.f) , mUnderwaterColor(fallback->getFallbackColour("Water_UnderwaterColor")) , mUnderwaterWeight(fallback->getFallbackFloat("Water_UnderwaterColorWeight")) @@ -231,6 +233,11 @@ namespace MWRender return mResourceSystem; } + SceneUtil::WorkQueue *RenderingManager::getWorkQueue() + { + return mWorkQueue.get(); + } + void RenderingManager::clearCache() { if (mTerrain.get()) diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index bc5db562c..8bc3a0a74 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -42,6 +42,11 @@ namespace Fallback class Map; } +namespace SceneUtil +{ + class WorkQueue; +} + namespace MWRender { @@ -65,6 +70,8 @@ namespace MWRender Resource::ResourceSystem* getResourceSystem(); + SceneUtil::WorkQueue* getWorkQueue(); + void clearCache(); double getReferenceTime() const; @@ -190,6 +197,8 @@ namespace MWRender osg::ref_ptr mLightRoot; Resource::ResourceSystem* mResourceSystem; + osg::ref_ptr mWorkQueue; + osg::ref_ptr mSunLight; std::auto_ptr mPathgrid; diff --git a/apps/openmw/mwworld/cellpreloader.cpp b/apps/openmw/mwworld/cellpreloader.cpp index 06216221b..2591e8c89 100644 --- a/apps/openmw/mwworld/cellpreloader.cpp +++ b/apps/openmw/mwworld/cellpreloader.cpp @@ -156,7 +156,6 @@ namespace MWWorld , mBulletShapeManager(bulletShapeManager) , mExpiryDelay(0.0) { - mWorkQueue = new SceneUtil::WorkQueue; } void CellPreloader::preload(CellStore *cell, double timestamp) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 321c1c622..2856c77e8 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -459,6 +459,7 @@ namespace MWWorld , mPreloadEnabled(Settings::Manager::getBool("preload enabled", "Cells")) { mPreloader.reset(new CellPreloader(rendering.getResourceSystem(), physics->getShapeManager())); + mPreloader->setWorkQueue(mRendering.getWorkQueue()); float cacheExpiryDelay = Settings::Manager::getFloat("cache expiry delay", "Cells"); rendering.getResourceSystem()->setExpiryDelay(cacheExpiryDelay); From 1cda2bf796fdb27e40accfa11fcc44d9c609e9df Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 9 Feb 2016 01:17:02 +0100 Subject: [PATCH 3121/3725] Preload sky & water from the main menu --- apps/openmw/engine.cpp | 2 ++ apps/openmw/mwbase/world.hpp | 2 ++ apps/openmw/mwrender/renderingmanager.cpp | 34 +++++++++++++++++++ apps/openmw/mwrender/renderingmanager.hpp | 2 ++ apps/openmw/mwrender/sky.cpp | 40 +++++++++++++++++++++++ apps/openmw/mwrender/sky.hpp | 2 ++ apps/openmw/mwrender/water.cpp | 12 +++++++ apps/openmw/mwrender/water.hpp | 3 ++ apps/openmw/mwworld/worldimp.cpp | 5 +++ apps/openmw/mwworld/worldimp.hpp | 2 ++ 10 files changed, 104 insertions(+) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index d30d0961a..b3a58d18e 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -651,6 +651,8 @@ void OMW::Engine::go() } else if (!mSkipMenu) { + mEnvironment.getWorld()->preloadCommonAssets(); + // start in main menu mEnvironment.getWindowManager()->pushGuiMode (MWGui::GM_MainMenu); try diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 119ce6b21..946a9a5dd 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -95,6 +95,8 @@ namespace MWBase virtual ~World() {} + virtual void preloadCommonAssets() = 0; + virtual void startNewGame (bool bypass) = 0; ///< \param bypass Bypass regular game start. diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 6ba30f32c..8c23a0707 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -127,6 +127,29 @@ namespace MWRender bool mWireframe; }; + class PreloadCommonAssetsWorkItem : public SceneUtil::WorkItem + { + public: + PreloadCommonAssetsWorkItem(Resource::ResourceSystem* resourceSystem) + : mResourceSystem(resourceSystem) + { + } + + virtual void doWork() + { + for (std::vector::const_iterator it = mModels.begin(); it != mModels.end(); ++it) + mResourceSystem->getSceneManager()->getTemplate(*it); + for (std::vector::const_iterator it = mTextures.begin(); it != mTextures.end(); ++it) + mResourceSystem->getImageManager()->getImage(*it); + } + + std::vector mModels; + std::vector mTextures; + + private: + Resource::ResourceSystem* mResourceSystem; + }; + RenderingManager::RenderingManager(osgViewer::Viewer* viewer, osg::ref_ptr rootNode, Resource::ResourceSystem* resourceSystem, const Fallback::Map* fallback, const std::string& resourcePath) : mViewer(viewer) @@ -238,6 +261,17 @@ namespace MWRender return mWorkQueue.get(); } + void RenderingManager::preloadCommonAssets() + { + osg::ref_ptr workItem (new PreloadCommonAssetsWorkItem(mResourceSystem)); + mSky->listAssetsToPreload(workItem->mModels, workItem->mTextures); + mWater->listAssetsToPreload(workItem->mTextures); + + workItem->mTextures.push_back("textures/_land_default.dds"); + + mWorkQueue->addWorkItem(workItem); + } + void RenderingManager::clearCache() { if (mTerrain.get()) diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 8bc3a0a74..72f322d2c 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -72,6 +72,8 @@ namespace MWRender SceneUtil::WorkQueue* getWorkQueue(); + void preloadCommonAssets(); + void clearCache(); double getReferenceTime() const; diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 0d3bf1a66..dafb2bb4b 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1694,6 +1694,46 @@ void SkyManager::setWaterHeight(float height) mUnderwaterSwitch->setWaterLevel(height); } +void SkyManager::listAssetsToPreload(std::vector& models, std::vector& textures) +{ + models.push_back("meshes/sky_atmosphere.nif"); + if (mSceneManager->getVFS()->exists("meshes/sky_night_02.nif")) + models.push_back("meshes/sky_night_02.nif"); + models.push_back("meshes/sky_night_01.nif"); + models.push_back("meshes/sky_clouds_01.nif"); + + models.push_back("meshes\\ashcloud.nif"); + models.push_back("meshes\\blightcloud.nif"); + models.push_back("meshes\\snow.nif"); + models.push_back("meshes\\blizzard.nif"); + + textures.push_back("textures/tx_mooncircle_full_s.dds"); + textures.push_back("textures/tx_mooncircle_full_m.dds"); + + textures.push_back("textures/tx_masser_new.dds"); + textures.push_back("textures/tx_masser_one_wax.dds"); + textures.push_back("textures/tx_masser_half_wax.dds"); + textures.push_back("textures/tx_masser_three_wax.dds"); + textures.push_back("textures/tx_masser_one_wan.dds"); + textures.push_back("textures/tx_masser_half_wan.dds"); + textures.push_back("textures/tx_masser_three_wan.dds"); + textures.push_back("textures/tx_masser_full.dds"); + + textures.push_back("textures/tx_secunda_new.dds"); + textures.push_back("textures/tx_secunda_one_wax.dds"); + textures.push_back("textures/tx_secunda_half_wax.dds"); + textures.push_back("textures/tx_secunda_three_wax.dds"); + textures.push_back("textures/tx_secunda_one_wan.dds"); + textures.push_back("textures/tx_secunda_half_wan.dds"); + textures.push_back("textures/tx_secunda_three_wan.dds"); + textures.push_back("textures/tx_secunda_full.dds"); + + textures.push_back("textures/tx_sun_05.dds"); + textures.push_back("textures/tx_sun_flash_grey_05.dds"); + + textures.push_back("textures/tx_raindrop_01.dds"); +} + void SkyManager::setWaterEnabled(bool enabled) { mUnderwaterSwitch->setEnabled(enabled); diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index 0caadaa07..741911b23 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -153,6 +153,8 @@ namespace MWRender /// Set height of water plane (used to remove underwater weather particles) void setWaterHeight(float height); + void listAssetsToPreload(std::vector& models, std::vector& textures); + private: void create(); ///< no need to call this, automatically done on first enable() diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 0e4f1a974..a8d601f11 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -649,6 +649,18 @@ Water::~Water() } } +void Water::listAssetsToPreload(std::vector &textures) +{ + int frameCount = mFallback->getFallbackInt("Water_SurfaceFrameCount"); + std::string texture = mFallback->getFallbackString("Water_SurfaceTexture"); + for (int i=0; i +#include #include #include @@ -85,6 +86,8 @@ namespace MWRender const std::string& resourcePath); ~Water(); + void listAssetsToPreload(std::vector& textures); + void setEnabled(bool enabled); bool toggle(); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 9064dc94c..137dac42e 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -3216,4 +3216,9 @@ namespace MWWorld return mPhysics->getHitDistance(weaponPos, target); } + void World::preloadCommonAssets() + { + mRendering->preloadCommonAssets(); + } + } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 8c56443f7..cf9321da5 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -183,6 +183,8 @@ namespace MWWorld virtual void startNewGame (bool bypass); ///< \param bypass Bypass regular game start. + virtual void preloadCommonAssets(); + virtual void clear(); virtual int countSavedGameRecords() const; From 10a3e270a3d32aaa9f34e575f544dfd2f3e4e922 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 9 Feb 2016 01:51:23 +0100 Subject: [PATCH 3122/3725] Preload fast travel destinations --- apps/openmw/mwworld/scene.cpp | 87 +++++++++++++++++++++++++++++++---- apps/openmw/mwworld/scene.hpp | 3 ++ 2 files changed, 80 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 2856c77e8..130644d7f 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -633,6 +633,7 @@ namespace MWWorld { preloadTeleportDoorDestinations(); preloadExteriorGrid(); + preloadFastTravelDestinations(); } void Scene::preloadTeleportDoorDestinations() @@ -664,19 +665,12 @@ namespace MWWorld try { if (!door.getCellRef().getDestCell().empty()) - mPreloader->preload(MWBase::Environment::get().getWorld()->getInterior(door.getCellRef().getDestCell()), mRendering.getReferenceTime()); + preloadCell(MWBase::Environment::get().getWorld()->getInterior(door.getCellRef().getDestCell())); else { int x,y; MWBase::Environment::get().getWorld()->positionToIndex (door.getCellRef().getDoorDest().pos[0], door.getCellRef().getDoorDest().pos[1], x, y); - - for (int dx = -mHalfGridSize; dx <= mHalfGridSize; ++dx) - { - for (int dy = -mHalfGridSize; dy <= mHalfGridSize; ++dy) - { - mPreloader->preload(MWBase::Environment::get().getWorld()->getExterior(x+dx, y+dy), mRendering.getReferenceTime()); - } - } + preloadCell(MWBase::Environment::get().getWorld()->getExterior(x,y), true); } } catch (std::exception& e) @@ -717,7 +711,80 @@ namespace MWWorld float loadDist = 8192/2 + 8192 - mCellLoadingThreshold + mPreloadDistance; if (dist < loadDist) - mPreloader->preload(MWBase::Environment::get().getWorld()->getExterior(cellX+dx, cellY+dy), mRendering.getReferenceTime()); + preloadCell(MWBase::Environment::get().getWorld()->getExterior(cellX+dx, cellY+dy)); + } + } + } + + void Scene::preloadCell(CellStore *cell, bool preloadSurrounding) + { + if (preloadSurrounding && cell->isExterior()) + { + int x = cell->getCell()->getGridX(); + int y = cell->getCell()->getGridY(); + for (int dx = -mHalfGridSize; dx <= mHalfGridSize; ++dx) + { + for (int dy = -mHalfGridSize; dy <= mHalfGridSize; ++dy) + { + mPreloader->preload(MWBase::Environment::get().getWorld()->getExterior(x+dx, y+dy), mRendering.getReferenceTime()); + } + } + } + else + mPreloader->preload(cell, mRendering.getReferenceTime()); + } + + struct ListFastTravelDestinationsVisitor + { + ListFastTravelDestinationsVisitor(float preloadDist, const osg::Vec3f& playerPos) + : mPreloadDist(preloadDist) + , mPlayerPos(playerPos) + { + } + + bool operator()(const MWWorld::Ptr& ptr) + { + if ((ptr.getRefData().getPosition().asVec3() - mPlayerPos).length2() > mPreloadDist * mPreloadDist) + return true; + + if (ptr.getClass().isNpc()) + { + const std::vector& transport = ptr.get()->mBase->mTransport.mList; + mList.insert(mList.begin(), transport.begin(), transport.end()); + } + else + { + const std::vector& transport = ptr.get()->mBase->mTransport.mList; + mList.insert(mList.begin(), transport.begin(), transport.end()); + } + return true; + } + float mPreloadDist; + osg::Vec3f mPlayerPos; + std::vector mList; + }; + + void Scene::preloadFastTravelDestinations() + { + const MWWorld::ConstPtr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + ListFastTravelDestinationsVisitor listVisitor(mPreloadDistance, player.getRefData().getPosition().asVec3()); + + for (CellStoreCollection::const_iterator iter (mActiveCells.begin()); iter!=mActiveCells.end(); ++iter) + { + MWWorld::CellStore* cellStore = *iter; + cellStore->forEachType(listVisitor); + cellStore->forEachType(listVisitor); + } + + for (std::vector::const_iterator it = listVisitor.mList.begin(); it != listVisitor.mList.end(); ++it) + { + if (!it->mCellName.empty()) + preloadCell(MWBase::Environment::get().getWorld()->getInterior(it->mCellName)); + else + { + int x,y; + MWBase::Environment::get().getWorld()->positionToIndex( it->mPos.pos[0], it->mPos.pos[1], x, y); + preloadCell(MWBase::Environment::get().getWorld()->getExterior(x,y), true); } } } diff --git a/apps/openmw/mwworld/scene.hpp b/apps/openmw/mwworld/scene.hpp index 34e137e45..f473f7a3c 100644 --- a/apps/openmw/mwworld/scene.hpp +++ b/apps/openmw/mwworld/scene.hpp @@ -74,6 +74,9 @@ namespace MWWorld void preloadCells(); void preloadTeleportDoorDestinations(); void preloadExteriorGrid(); + void preloadFastTravelDestinations(); + + void preloadCell(MWWorld::CellStore* cell, bool preloadSurrounding=false); public: From 6806741d9b9d1e5e613d667771c018baf4165af2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 9 Feb 2016 01:58:07 +0100 Subject: [PATCH 3123/3725] Add settings for disabling the individual preloading types --- apps/openmw/mwworld/scene.cpp | 12 +++++++++--- apps/openmw/mwworld/scene.hpp | 4 ++++ files/settings-default.cfg | 11 ++++++++++- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 130644d7f..3658bff35 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -457,6 +457,9 @@ namespace MWWorld , mCellLoadingThreshold(1024.f) , mPreloadDistance(Settings::Manager::getInt("preload distance", "Cells")) , mPreloadEnabled(Settings::Manager::getBool("preload enabled", "Cells")) + , mPreloadExteriorGrid(Settings::Manager::getBool("preload exterior grid", "Cells")) + , mPreloadDoors(Settings::Manager::getBool("preload doors", "Cells")) + , mPreloadFastTravel(Settings::Manager::getBool("preload fast travel", "Cells")) { mPreloader.reset(new CellPreloader(rendering.getResourceSystem(), physics->getShapeManager())); mPreloader->setWorkQueue(mRendering.getWorkQueue()); @@ -631,9 +634,12 @@ namespace MWWorld void Scene::preloadCells() { - preloadTeleportDoorDestinations(); - preloadExteriorGrid(); - preloadFastTravelDestinations(); + if (mPreloadDoors) + preloadTeleportDoorDestinations(); + if (mPreloadExteriorGrid) + preloadExteriorGrid(); + if (mPreloadFastTravel) + preloadFastTravelDestinations(); } void Scene::preloadTeleportDoorDestinations() diff --git a/apps/openmw/mwworld/scene.hpp b/apps/openmw/mwworld/scene.hpp index f473f7a3c..5c429f7c7 100644 --- a/apps/openmw/mwworld/scene.hpp +++ b/apps/openmw/mwworld/scene.hpp @@ -64,6 +64,10 @@ namespace MWWorld float mPreloadDistance; bool mPreloadEnabled; + bool mPreloadExteriorGrid; + bool mPreloadDoors; + bool mPreloadFastTravel; + void insertCell (CellStore &cell, bool rescale, Loading::Listener* loadingListener); // Load and unload cells as necessary to create a cell grid with "X" and "Y" in the center diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 4df20e709..4a9a5dd65 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -37,9 +37,18 @@ first person field of view = 55.0 # dramatically affect performance, see documentation for details. exterior cell load distance = 1 -# Preload cells in a background thread +# Preload cells in a background thread. All settings starting with 'preload' have no effect unless this is enabled. preload enabled = true +# Preload adjacent cells when moving close to an exterior cell border. +preload exterior grid = true + +# Preload possible fast travel destinations. +preload fast travel = true + +# Preload the locations that doors lead to. +preload doors = true + # Preloading distance threshold preload distance = 1000 From f6f9eff9a68e5ef7297ef97323c5096aab4f490e Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 9 Feb 2016 03:06:00 +0100 Subject: [PATCH 3124/3725] Preload levelled creatures --- apps/openmw/mwclass/creaturelevlist.cpp | 17 +++++++++++++++++ apps/openmw/mwclass/creaturelevlist.hpp | 3 +++ apps/openmw/mwworld/scene.cpp | 2 +- 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwclass/creaturelevlist.cpp b/apps/openmw/mwclass/creaturelevlist.cpp index db2ba45bc..e2f29ea72 100644 --- a/apps/openmw/mwclass/creaturelevlist.cpp +++ b/apps/openmw/mwclass/creaturelevlist.cpp @@ -6,6 +6,7 @@ #include "../mwmechanics/levelledlist.hpp" #include "../mwworld/customdata.hpp" +#include "../mwmechanics/creaturestats.hpp" namespace MWClass { @@ -53,6 +54,22 @@ namespace MWClass registerClass (typeid (ESM::CreatureLevList).name(), instance); } + void CreatureLevList::getModelsToPreload(const MWWorld::Ptr &ptr, std::vector &models) const + { + const MWWorld::LiveCellRef *ref = ptr.get(); + + for (std::vector::const_iterator it = ref->mBase->mList.begin(); it != ref->mBase->mList.end(); ++it) + { + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + if (it->mLevel > player.getClass().getCreatureStats(player).getLevel()) + continue; + + const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); + MWWorld::ManualRef ref(store, it->mId); + ref.getPtr().getClass().getModelsToPreload(ref.getPtr(), models); + } + } + void CreatureLevList::insertObjectRendering(const MWWorld::Ptr &ptr, const std::string& model, MWRender::RenderingInterface &renderingInterface) const { ensureCustomData(ptr); diff --git a/apps/openmw/mwclass/creaturelevlist.hpp b/apps/openmw/mwclass/creaturelevlist.hpp index 67a7858d8..25b5cbddf 100644 --- a/apps/openmw/mwclass/creaturelevlist.hpp +++ b/apps/openmw/mwclass/creaturelevlist.hpp @@ -17,6 +17,9 @@ namespace MWClass static void registerSelf(); + virtual void getModelsToPreload(const MWWorld::Ptr& ptr, std::vector& models) const; + ///< Get a list of models to preload that this object may use (directly or indirectly). default implementation: list getModel(). + virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 3658bff35..4c843133d 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -197,7 +197,7 @@ namespace MWWorld if (mPreloadEnabled) { mPreloadTimer += duration; - if (mPreloadTimer > 0.5f) + if (mPreloadTimer > 0.25f) { preloadCells(); mPreloadTimer = 0.f; From d11c2864df515afe083628c781b7058f14fe1375 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 9 Feb 2016 15:30:53 +0100 Subject: [PATCH 3125/3725] Introduce UnrefQueue to handle the deleting of no longer needed objects in the background thread --- apps/openmw/mwrender/objects.cpp | 12 +++++- apps/openmw/mwrender/objects.hpp | 13 +++++-- apps/openmw/mwrender/renderingmanager.cpp | 8 +++- apps/openmw/mwrender/renderingmanager.hpp | 2 + components/CMakeLists.txt | 2 +- components/sceneutil/unrefqueue.cpp | 46 +++++++++++++++++++++++ components/sceneutil/unrefqueue.hpp | 37 ++++++++++++++++++ components/terrain/terraingrid.cpp | 21 ++++++----- components/terrain/terraingrid.hpp | 9 ++--- 9 files changed, 128 insertions(+), 22 deletions(-) create mode 100644 components/sceneutil/unrefqueue.cpp create mode 100644 components/sceneutil/unrefqueue.hpp diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index f58ebb917..516d10b95 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -14,6 +14,7 @@ #include #include +#include #include "../mwworld/ptr.hpp" #include "../mwworld/class.hpp" @@ -85,9 +86,10 @@ namespace namespace MWRender { -Objects::Objects(Resource::ResourceSystem* resourceSystem, osg::ref_ptr rootNode) +Objects::Objects(Resource::ResourceSystem* resourceSystem, osg::ref_ptr rootNode, SceneUtil::UnrefQueue* unrefQueue) : mRootNode(rootNode) , mResourceSystem(resourceSystem) + , mUnrefQueue(unrefQueue) { } @@ -186,7 +188,11 @@ bool Objects::removeObject (const MWWorld::Ptr& ptr) delete iter->second; mObjects.erase(iter); + if (mUnrefQueue.get()) + mUnrefQueue->push(ptr.getRefData().getBaseNode()); + ptr.getRefData().getBaseNode()->getParent(0)->removeChild(ptr.getRefData().getBaseNode()); + ptr.getRefData().setBaseNode(NULL); return true; } @@ -200,6 +206,8 @@ void Objects::removeCell(const MWWorld::CellStore* store) { if(iter->first.getCell() == store) { + if (mUnrefQueue.get()) + mUnrefQueue->push(iter->second->getObjectRoot()); delete iter->second; mObjects.erase(iter++); } @@ -211,6 +219,8 @@ void Objects::removeCell(const MWWorld::CellStore* store) if(cell != mCellSceneNodes.end()) { cell->second->getParent(0)->removeChild(cell->second); + if (mUnrefQueue.get()) + mUnrefQueue->push(cell->second); mCellSceneNodes.erase(cell); } } diff --git a/apps/openmw/mwrender/objects.hpp b/apps/openmw/mwrender/objects.hpp index 3d0c92cb4..5b91abea4 100644 --- a/apps/openmw/mwrender/objects.hpp +++ b/apps/openmw/mwrender/objects.hpp @@ -30,6 +30,11 @@ namespace MWWorld class CellStore; } +namespace SceneUtil +{ + class UnrefQueue; +} + namespace MWRender{ class Animation; @@ -65,12 +70,14 @@ class Objects{ osg::ref_ptr mRootNode; - void insertBegin(const MWWorld::Ptr& ptr); - Resource::ResourceSystem* mResourceSystem; + osg::ref_ptr mUnrefQueue; + + void insertBegin(const MWWorld::Ptr& ptr); + public: - Objects(Resource::ResourceSystem* resourceSystem, osg::ref_ptr rootNode); + Objects(Resource::ResourceSystem* resourceSystem, osg::ref_ptr rootNode, SceneUtil::UnrefQueue* unrefQueue); ~Objects(); /// @param animated Attempt to load separate keyframes from a .kf file matching the model file? diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 8c23a0707..5a9cd59fc 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include @@ -156,6 +157,7 @@ namespace MWRender , mRootNode(rootNode) , mResourceSystem(resourceSystem) , mWorkQueue(new SceneUtil::WorkQueue) + , mUnrefQueue(new SceneUtil::UnrefQueue) , mFogDepth(0.f) , mUnderwaterColor(fallback->getFallbackColour("Water_UnderwaterColor")) , mUnderwaterWeight(fallback->getFallbackFloat("Water_UnderwaterColorWeight")) @@ -176,7 +178,7 @@ namespace MWRender mPathgrid.reset(new Pathgrid(mRootNode)); - mObjects.reset(new Objects(mResourceSystem, lightRoot)); + mObjects.reset(new Objects(mResourceSystem, lightRoot, mUnrefQueue.get())); mViewer->setIncrementalCompileOperation(new osgUtil::IncrementalCompileOperation); @@ -187,7 +189,7 @@ namespace MWRender mWater.reset(new Water(mRootNode, lightRoot, mResourceSystem, mViewer->getIncrementalCompileOperation(), fallback, resourcePath)); mTerrain.reset(new Terrain::TerrainGrid(lightRoot, mResourceSystem, mViewer->getIncrementalCompileOperation(), - new TerrainStorage(mResourceSystem->getVFS(), false), Mask_Terrain)); + new TerrainStorage(mResourceSystem->getVFS(), false), Mask_Terrain, mUnrefQueue.get())); mCamera.reset(new Camera(mViewer->getCamera())); @@ -437,6 +439,8 @@ namespace MWRender void RenderingManager::update(float dt, bool paused) { + mUnrefQueue->flush(mWorkQueue.get()); + if (!paused) { mEffectManager->update(dt); diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 72f322d2c..3d6a4ac3a 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -45,6 +45,7 @@ namespace Fallback namespace SceneUtil { class WorkQueue; + class UnrefQueue; } namespace MWRender @@ -200,6 +201,7 @@ namespace MWRender Resource::ResourceSystem* mResourceSystem; osg::ref_ptr mWorkQueue; + osg::ref_ptr mUnrefQueue; osg::ref_ptr mSunLight; diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 26e8f7b6a..81e6defe4 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -46,7 +46,7 @@ add_component_dir (resource add_component_dir (sceneutil clone attach visitor util statesetupdater controller skeleton riggeometry lightcontroller - lightmanager lightutil positionattitudetransform workqueue + lightmanager lightutil positionattitudetransform workqueue unrefqueue ) add_component_dir (nif diff --git a/components/sceneutil/unrefqueue.cpp b/components/sceneutil/unrefqueue.cpp new file mode 100644 index 000000000..23b1359e5 --- /dev/null +++ b/components/sceneutil/unrefqueue.cpp @@ -0,0 +1,46 @@ +#include "unrefqueue.hpp" + +#include +//#include +//#include + +#include + +namespace SceneUtil +{ + + class UnrefWorkItem : public SceneUtil::WorkItem + { + public: + std::vector > mObjects; + + virtual void doWork() + { + //osg::Timer timer; + //size_t objcount = mObjects.size(); + mObjects.clear(); + //std::cout << "cleared " << objcount << " objects in " << timer.time_m() << std::endl; + } + }; + + UnrefQueue::UnrefQueue() + { + mWorkItem = new UnrefWorkItem; + } + + void UnrefQueue::push(osg::Object *obj) + { + mWorkItem->mObjects.push_back(obj); + } + + void UnrefQueue::flush(SceneUtil::WorkQueue *workQueue) + { + if (mWorkItem->mObjects.empty()) + return; + + workQueue->addWorkItem(mWorkItem); + + mWorkItem = new UnrefWorkItem; + } + +} diff --git a/components/sceneutil/unrefqueue.hpp b/components/sceneutil/unrefqueue.hpp new file mode 100644 index 000000000..d0bec061c --- /dev/null +++ b/components/sceneutil/unrefqueue.hpp @@ -0,0 +1,37 @@ +#ifndef OPENMW_COMPONENTS_UNREFQUEUE_H +#define OPENMW_COMPONENTS_UNREFQUEUE_H + +#include +#include + +namespace osg +{ + class Object; +} + +namespace SceneUtil +{ + class WorkQueue; + class UnrefWorkItem; + + /// @brief Handles unreferencing of objects through the WorkQueue. Typical use scenario + /// would be the main thread pushing objects that are no longer needed, and the background thread deleting them. + class UnrefQueue : public osg::Referenced + { + public: + UnrefQueue(); + + /// Adds an object to the list of objects to be unreferenced. Call from the main thread. + void push(osg::Object* obj); + + /// Adds a WorkItem to the given WorkQueue that will clear the list of objects in a worker thread, thus unreferencing them. + /// Call from the main thread. + void flush(SceneUtil::WorkQueue* workQueue); + + private: + osg::ref_ptr mWorkItem; + }; + +} + +#endif diff --git a/components/terrain/terraingrid.cpp b/components/terrain/terraingrid.cpp index 4f7a0772b..4b67371e0 100644 --- a/components/terrain/terraingrid.cpp +++ b/components/terrain/terraingrid.cpp @@ -8,6 +8,7 @@ #include #include +#include #include @@ -46,11 +47,10 @@ namespace namespace Terrain { -TerrainGrid::TerrainGrid(osg::Group* parent, Resource::ResourceSystem* resourceSystem, osgUtil::IncrementalCompileOperation* ico, - Storage* storage, int nodeMask) +TerrainGrid::TerrainGrid(osg::Group* parent, Resource::ResourceSystem* resourceSystem, osgUtil::IncrementalCompileOperation* ico, Storage* storage, int nodeMask, SceneUtil::UnrefQueue* unrefQueue) : Terrain::World(parent, resourceSystem, ico, storage, nodeMask) , mNumSplits(4) - , mKdTreeBuilder(new osg::KdTreeBuilder) + , mUnrefQueue(unrefQueue) { mCache = BufferCache((storage->getCellVertices()-1)/static_cast(mNumSplits) + 1); } @@ -212,13 +212,6 @@ void TerrainGrid::loadCell(int x, int y) element->mNode = terrainNode; mTerrainRoot->addChild(element->mNode); - // kdtree probably not needed with mNumSplits=4 - /* - // build a kdtree to speed up intersection tests with the terrain - // Note, the build could be optimized using a custom kdtree builder, since we know that the terrain can be represented by a quadtree - geode->accept(*mKdTreeBuilder); - */ - mGrid[std::make_pair(x,y)] = element.release(); } @@ -230,6 +223,10 @@ void TerrainGrid::unloadCell(int x, int y) GridElement* element = it->second; mTerrainRoot->removeChild(element->mNode); + + if (mUnrefQueue.get()) + mUnrefQueue->push(element->mNode); + delete element; mGrid.erase(it); @@ -240,7 +237,11 @@ void TerrainGrid::clearCache() for (TextureCache::iterator it = mTextureCache.begin(); it != mTextureCache.end();) { if (it->second->referenceCount() <= 1) + { + if (mUnrefQueue.get()) + mUnrefQueue->push(it->second); mTextureCache.erase(it++); + } else ++it; } diff --git a/components/terrain/terraingrid.hpp b/components/terrain/terraingrid.hpp index 81bfc4211..5708e7068 100644 --- a/components/terrain/terraingrid.hpp +++ b/components/terrain/terraingrid.hpp @@ -6,9 +6,9 @@ #include "world.hpp" #include "material.hpp" -namespace osg +namespace SceneUtil { - class KdTreeBuilder; + class UnrefQueue; } namespace Terrain @@ -20,8 +20,7 @@ namespace Terrain class TerrainGrid : public Terrain::World { public: - TerrainGrid(osg::Group* parent, Resource::ResourceSystem* resourceSystem, osgUtil::IncrementalCompileOperation* ico, - Storage* storage, int nodeMask); + TerrainGrid(osg::Group* parent, Resource::ResourceSystem* resourceSystem, osgUtil::IncrementalCompileOperation* ico, Storage* storage, int nodeMask, SceneUtil::UnrefQueue* unrefQueue = NULL); ~TerrainGrid(); virtual void loadCell(int x, int y); @@ -42,7 +41,7 @@ namespace Terrain typedef std::map, GridElement*> Grid; Grid mGrid; - osg::ref_ptr mKdTreeBuilder; + osg::ref_ptr mUnrefQueue; }; } From 40a6e05e178b28ddbdf8c909f7aab2dce7fa9af0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 9 Feb 2016 16:09:55 +0100 Subject: [PATCH 3126/3725] Use a deque instead of vector in UnrefQueue --- components/sceneutil/unrefqueue.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/components/sceneutil/unrefqueue.cpp b/components/sceneutil/unrefqueue.cpp index 23b1359e5..0b65c4a32 100644 --- a/components/sceneutil/unrefqueue.cpp +++ b/components/sceneutil/unrefqueue.cpp @@ -1,5 +1,7 @@ #include "unrefqueue.hpp" +#include + #include //#include //#include @@ -12,7 +14,7 @@ namespace SceneUtil class UnrefWorkItem : public SceneUtil::WorkItem { public: - std::vector > mObjects; + std::deque > mObjects; virtual void doWork() { From ae031b23d42d7174f5c1187d79e1e47040d1e9df Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 9 Feb 2016 16:10:42 +0100 Subject: [PATCH 3127/3725] Do not detach NPC parts in destructor --- apps/openmw/mwrender/animation.cpp | 7 ++++++- apps/openmw/mwrender/animation.hpp | 3 +++ apps/openmw/mwrender/npcanimation.cpp | 7 +++++++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index b7c0c0a36..3d4fd11d0 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1409,8 +1409,13 @@ namespace MWRender PartHolder::~PartHolder() { - if (mNode->getNumParents()) + if (mNode.get() && mNode->getNumParents()) mNode->getParent(0)->removeChild(mNode); } + void PartHolder::unlink() + { + mNode = NULL; + } + } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 992462e1f..feaf0e16c 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -55,6 +55,9 @@ public: ~PartHolder(); + /// Unreferences mNode *without* detaching it from the graph. Only use if you know what you are doing. + void unlink(); + osg::ref_ptr getNode() { return mNode; diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 026b3a2cf..10c0032d4 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -273,6 +273,13 @@ NpcAnimation::~NpcAnimation() // all from within this destructor. ouch! && mPtr.getRefData().getCustomData() && mPtr.getClass().getInventoryStore(mPtr).getListener() == this) mPtr.getClass().getInventoryStore(mPtr).setListener(NULL, mPtr); + + // do not detach (delete) parts yet, this is done so the background thread can handle the deletion + for(size_t i = 0;i < ESM::PRT_Count;i++) + { + if (mObjectParts[i].get()) + mObjectParts[i]->unlink(); + } } NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, osg::ref_ptr parentNode, Resource::ResourceSystem* resourceSystem, From 8ece1885cdc2662ceaefcd4542abdf9970880483 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 9 Feb 2016 16:18:19 +0100 Subject: [PATCH 3128/3725] Animation: don't create the NodeMap if we don't need it --- apps/openmw/mwrender/animation.cpp | 61 +++++++++++++++++------------- apps/openmw/mwrender/animation.hpp | 5 ++- 2 files changed, 39 insertions(+), 27 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 3d4fd11d0..5aea13660 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -95,7 +95,12 @@ namespace class NodeMapVisitor : public osg::NodeVisitor { public: - NodeMapVisitor() : osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {} + typedef std::map > NodeMap; + + NodeMapVisitor(NodeMap& map) + : osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) + , mMap(map) + {} void apply(osg::MatrixTransform& trans) { @@ -103,15 +108,8 @@ namespace traverse(trans); } - typedef std::map > NodeMap; - - const NodeMap& getNodeMap() const - { - return mMap; - } - private: - NodeMap mMap; + NodeMap& mMap; }; NifOsg::TextKeyMap::const_iterator findGroupStart(const NifOsg::TextKeyMap &keys, const std::string &groupname) @@ -312,6 +310,7 @@ namespace MWRender Animation::Animation(const MWWorld::Ptr &ptr, osg::ref_ptr parentNode, Resource::ResourceSystem* resourceSystem) : mInsert(parentNode) , mSkeleton(NULL) + , mNodeMapCreated(false) , mPtr(ptr) , mResourceSystem(resourceSystem) , mAccumulate(1.f, 1.f, 0.f) @@ -407,12 +406,14 @@ namespace MWRender if (!animsrc->mKeyframes || animsrc->mKeyframes->mTextKeys.empty() || animsrc->mKeyframes->mKeyframeControllers.empty()) return; + const NodeMap& nodeMap = getNodeMap(); + for (NifOsg::KeyframeHolder::KeyframeControllerMap::const_iterator it = animsrc->mKeyframes->mKeyframeControllers.begin(); it != animsrc->mKeyframes->mKeyframeControllers.end(); ++it) { std::string bonename = Misc::StringUtils::lowerCase(it->first); - NodeMap::const_iterator found = mNodeMap.find(bonename); - if (found == mNodeMap.end()) + NodeMap::const_iterator found = nodeMap.find(bonename); + if (found == nodeMap.end()) { std::cerr << "addAnimSource: can't find bone '" + bonename << "' in " << model << " (referenced by " << kfname << ")" << std::endl; continue; @@ -436,11 +437,11 @@ namespace MWRender if (!mAccumRoot) { - NodeMap::const_iterator found = mNodeMap.find("root bone"); - if (found == mNodeMap.end()) - found = mNodeMap.find("bip01"); + NodeMap::const_iterator found = nodeMap.find("root bone"); + if (found == nodeMap.end()) + found = nodeMap.find("bip01"); - if (found != mNodeMap.end()) + if (found != nodeMap.end()) mAccumRoot = found->second; } } @@ -690,6 +691,17 @@ namespace MWRender mTextKeyListener = listener; } + const Animation::NodeMap &Animation::getNodeMap() const + { + if (!mNodeMapCreated && mObjectRoot) + { + NodeMapVisitor visitor(mNodeMap); + mObjectRoot->accept(visitor); + mNodeMapCreated = true; + } + return mNodeMap; + } + void Animation::resetActiveGroups() { // remove all previous external controllers from the scene graph @@ -729,7 +741,7 @@ namespace MWRender for (AnimSource::ControllerMap::iterator it = animsrc->mControllerMap[blendMask].begin(); it != animsrc->mControllerMap[blendMask].end(); ++it) { - osg::ref_ptr node = mNodeMap.at(it->first); // this should not throw, we already checked for the node existing in addAnimSource + osg::ref_ptr node = getNodeMap().at(it->first); // this should not throw, we already checked for the node existing in addAnimSource node->addUpdateCallback(it->second); mActiveControllers.insert(std::make_pair(node, it->second)); @@ -978,6 +990,7 @@ namespace MWRender mSkeleton = NULL; mNodeMap.clear(); + mNodeMapCreated = false; mActiveControllers.clear(); mAccumRoot = NULL; mAccumCtrl = NULL; @@ -1025,10 +1038,6 @@ namespace MWRender removeTriBipVisitor.remove(); } - NodeMapVisitor visitor; - mObjectRoot->accept(visitor); - mNodeMap = visitor.getNodeMap(); - mObjectRoot->addCullCallback(new SceneUtil::LightListCallback); } @@ -1121,8 +1130,8 @@ namespace MWRender parentNode = mInsert; else { - NodeMap::iterator found = mNodeMap.find(Misc::StringUtils::lowerCase(bonename)); - if (found == mNodeMap.end()) + NodeMap::const_iterator found = getNodeMap().find(Misc::StringUtils::lowerCase(bonename)); + if (found == getNodeMap().end()) throw std::runtime_error("Can't find bone " + bonename); parentNode = found->second; @@ -1222,8 +1231,8 @@ namespace MWRender const osg::Node* Animation::getNode(const std::string &name) const { std::string lowerName = Misc::StringUtils::lowerCase(name); - NodeMap::const_iterator found = mNodeMap.find(lowerName); - if (found == mNodeMap.end()) + NodeMap::const_iterator found = getNodeMap().find(lowerName); + if (found == getNodeMap().end()) return NULL; else return found->second; @@ -1317,8 +1326,8 @@ namespace MWRender if (mPtr.getClass().isBipedal(mPtr)) { - NodeMap::iterator found = mNodeMap.find("bip01 head"); - if (found != mNodeMap.end() && dynamic_cast(found->second.get())) + NodeMap::const_iterator found = getNodeMap().find("bip01 head"); + if (found != getNodeMap().end() && dynamic_cast(found->second.get())) { osg::Node* node = found->second; mHeadController = new RotateController(mObjectRoot.get()); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index feaf0e16c..1d7930566 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -232,7 +232,8 @@ protected: // Stored in all lowercase for a case-insensitive lookup typedef std::map > NodeMap; - NodeMap mNodeMap; + mutable NodeMap mNodeMap; + mutable bool mNodeMapCreated; MWWorld::Ptr mPtr; @@ -263,6 +264,8 @@ protected: float mAlpha; + const NodeMap& getNodeMap() const; + /* Sets the appropriate animations on the bone groups based on priority. */ void resetActiveGroups(); From ce3cce24a56df230616f13622deb59464b4b36d4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 9 Feb 2016 16:20:17 +0100 Subject: [PATCH 3129/3725] Remove unneeded dynamic_cast --- apps/openmw/mwrender/animation.cpp | 4 ++-- apps/openmw/mwrender/npcanimation.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 5aea13660..c86878e3d 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1327,9 +1327,9 @@ namespace MWRender if (mPtr.getClass().isBipedal(mPtr)) { NodeMap::const_iterator found = getNodeMap().find("bip01 head"); - if (found != getNodeMap().end() && dynamic_cast(found->second.get())) + if (found != getNodeMap().end()) { - osg::Node* node = found->second; + osg::MatrixTransform* node = found->second; mHeadController = new RotateController(mObjectRoot.get()); node->addUpdateCallback(mHeadController); mActiveControllers.insert(std::make_pair(node, mHeadController)); diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 10c0032d4..709653cd8 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -847,9 +847,9 @@ void NpcAnimation::addControllers() if (mViewMode == VM_FirstPerson) { NodeMap::iterator found = mNodeMap.find("bip01 neck"); - if (found != mNodeMap.end() && dynamic_cast(found->second.get())) + if (found != mNodeMap.end()) { - osg::Node* node = found->second; + osg::MatrixTransform* node = found->second.get(); mFirstPersonNeckController = new NeckController(mObjectRoot.get()); node->addUpdateCallback(mFirstPersonNeckController); mActiveControllers.insert(std::make_pair(node, mFirstPersonNeckController)); From 2e62298bd33534a64e7eff91c94ea1aac5f806ae Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 9 Feb 2016 18:11:07 +0100 Subject: [PATCH 3130/3725] Clean up ObjectCache includes --- components/resource/niffilemanager.cpp | 2 ++ components/resource/objectcache.cpp | 2 ++ components/resource/objectcache.hpp | 13 +++++++++---- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/components/resource/niffilemanager.cpp b/components/resource/niffilemanager.cpp index ecb63db60..82768cc2c 100644 --- a/components/resource/niffilemanager.cpp +++ b/components/resource/niffilemanager.cpp @@ -1,5 +1,7 @@ #include "niffilemanager.hpp" +#include + #include #include "objectcache.hpp" diff --git a/components/resource/objectcache.cpp b/components/resource/objectcache.cpp index 17368f34f..a0a3cf3a5 100644 --- a/components/resource/objectcache.cpp +++ b/components/resource/objectcache.cpp @@ -13,6 +13,8 @@ #include "objectcache.hpp" +#include + namespace Resource { diff --git a/components/resource/objectcache.hpp b/components/resource/objectcache.hpp index b933933f3..79ebabd5b 100644 --- a/components/resource/objectcache.hpp +++ b/components/resource/objectcache.hpp @@ -17,13 +17,18 @@ #ifndef OPENMW_COMPONENTS_RESOURCE_OBJECTCACHE #define OPENMW_COMPONENTS_RESOURCE_OBJECTCACHE -#include - -#include -#include +#include +#include +#include #include +namespace osg +{ + class Object; + class State; +} + namespace Resource { class ObjectCache : public osg::Referenced From e28dc3e72fea00ebde993cdb5cc3ea01e84d1b7c Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 9 Feb 2016 18:33:02 +0100 Subject: [PATCH 3131/3725] Preload instances in SceneManager --- apps/opencs/view/render/object.cpp | 2 +- apps/openmw/mwrender/animation.cpp | 6 +- apps/openmw/mwrender/creatureanimation.cpp | 2 +- apps/openmw/mwrender/effectmanager.cpp | 2 +- apps/openmw/mwrender/npcanimation.cpp | 2 +- apps/openmw/mwrender/sky.cpp | 12 ++-- apps/openmw/mwrender/weaponanimation.cpp | 2 +- apps/openmw/mwworld/cellpreloader.cpp | 9 ++- apps/openmw/mwworld/cellpreloader.hpp | 2 + apps/openmw/mwworld/projectilemanager.cpp | 2 +- apps/openmw/mwworld/scene.cpp | 2 + components/CMakeLists.txt | 2 +- components/resource/multiobjectcache.cpp | 79 ++++++++++++++++++++++ components/resource/multiobjectcache.hpp | 47 +++++++++++++ components/resource/scenemanager.cpp | 39 +++++++++-- components/resource/scenemanager.hpp | 24 +++++-- 16 files changed, 207 insertions(+), 27 deletions(-) create mode 100644 components/resource/multiobjectcache.cpp create mode 100644 components/resource/multiobjectcache.hpp diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index b980b658a..33939625d 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -100,7 +100,7 @@ void CSVRender::Object::update() { std::string path = "meshes\\" + model; - mResourceSystem->getSceneManager()->createInstance(path, mBaseNode); + mResourceSystem->getSceneManager()->getInstance(path, mBaseNode); } catch (std::exception& e) { diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index c86878e3d..398fe5322 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -997,7 +997,7 @@ namespace MWRender if (!forceskeleton) { - osg::ref_ptr created = mResourceSystem->getSceneManager()->createInstance(model, mInsert); + osg::ref_ptr created = mResourceSystem->getSceneManager()->getInstance(model, mInsert); mObjectRoot = created->asGroup(); if (!mObjectRoot) { @@ -1009,7 +1009,7 @@ namespace MWRender } else { - osg::ref_ptr created = mResourceSystem->getSceneManager()->createInstance(model); + osg::ref_ptr created = mResourceSystem->getSceneManager()->getInstance(model); osg::ref_ptr skel = dynamic_cast(created.get()); if (!skel) { @@ -1136,7 +1136,7 @@ namespace MWRender parentNode = found->second; } - osg::ref_ptr node = mResourceSystem->getSceneManager()->createInstance(model, parentNode); + osg::ref_ptr node = mResourceSystem->getSceneManager()->getInstance(model, parentNode); node->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF); diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index 7c447182f..9cd35ecde 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -105,7 +105,7 @@ void CreatureWeaponAnimation::updatePart(PartHolderPtr& scene, int slot) else bonename = "Shield Bone"; - osg::ref_ptr node = mResourceSystem->getSceneManager()->createInstance(item.getClass().getModel(item)); + osg::ref_ptr node = mResourceSystem->getSceneManager()->getInstance(item.getClass().getModel(item)); osg::ref_ptr attached = SceneUtil::attach(node, mObjectRoot, bonename, bonename); mResourceSystem->getSceneManager()->notifyAttached(attached); diff --git a/apps/openmw/mwrender/effectmanager.cpp b/apps/openmw/mwrender/effectmanager.cpp index c4e457a1f..e2773f2dc 100644 --- a/apps/openmw/mwrender/effectmanager.cpp +++ b/apps/openmw/mwrender/effectmanager.cpp @@ -27,7 +27,7 @@ EffectManager::~EffectManager() void EffectManager::addEffect(const std::string &model, const std::string& textureOverride, const osg::Vec3f &worldPosition, float scale) { - osg::ref_ptr node = mResourceSystem->getSceneManager()->createInstance(model); + osg::ref_ptr node = mResourceSystem->getSceneManager()->getInstance(model); node->setNodeMask(Mask_Effect); diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 709653cd8..eee23aa31 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -647,7 +647,7 @@ void NpcAnimation::updateParts() PartHolderPtr NpcAnimation::insertBoundedPart(const std::string& model, const std::string& bonename, const std::string& bonefilter, bool enchantedGlow, osg::Vec4f* glowColor) { - osg::ref_ptr instance = mResourceSystem->getSceneManager()->createInstance(model); + osg::ref_ptr instance = mResourceSystem->getSceneManager()->getInstance(model); osg::ref_ptr attached = SceneUtil::attach(instance, mObjectRoot, bonefilter, bonename); mResourceSystem->getSceneManager()->notifyAttached(attached); if (enchantedGlow) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index dafb2bb4b..40283ba27 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1146,7 +1146,7 @@ void SkyManager::create() { assert(!mCreated); - mAtmosphereDay = mSceneManager->createInstance("meshes/sky_atmosphere.nif", mEarlyRenderBinRoot); + mAtmosphereDay = mSceneManager->getInstance("meshes/sky_atmosphere.nif", mEarlyRenderBinRoot); ModVertexAlphaVisitor modAtmosphere(0); mAtmosphereDay->accept(modAtmosphere); @@ -1159,9 +1159,9 @@ void SkyManager::create() osg::ref_ptr atmosphereNight; if (mSceneManager->getVFS()->exists("meshes/sky_night_02.nif")) - atmosphereNight = mSceneManager->createInstance("meshes/sky_night_02.nif", mAtmosphereNightNode); + atmosphereNight = mSceneManager->getInstance("meshes/sky_night_02.nif", mAtmosphereNightNode); else - atmosphereNight = mSceneManager->createInstance("meshes/sky_night_01.nif", mAtmosphereNightNode); + atmosphereNight = mSceneManager->getInstance("meshes/sky_night_01.nif", mAtmosphereNightNode); atmosphereNight->getOrCreateStateSet()->setAttributeAndModes(createAlphaTrackingUnlitMaterial(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); ModVertexAlphaVisitor modStars(2); atmosphereNight->accept(modStars); @@ -1176,14 +1176,14 @@ void SkyManager::create() mCloudNode = new osg::PositionAttitudeTransform; mEarlyRenderBinRoot->addChild(mCloudNode); - mCloudMesh = mSceneManager->createInstance("meshes/sky_clouds_01.nif", mCloudNode); + mCloudMesh = mSceneManager->getInstance("meshes/sky_clouds_01.nif", mCloudNode); ModVertexAlphaVisitor modClouds(1); mCloudMesh->accept(modClouds); mCloudUpdater = new CloudUpdater; mCloudUpdater->setOpacity(1.f); mCloudMesh->addUpdateCallback(mCloudUpdater); - mCloudMesh2 = mSceneManager->createInstance("meshes/sky_clouds_01.nif", mCloudNode); + mCloudMesh2 = mSceneManager->getInstance("meshes/sky_clouds_01.nif", mCloudNode); mCloudMesh2->accept(modClouds); mCloudUpdater2 = new CloudUpdater; mCloudUpdater2->setOpacity(0.f); @@ -1537,7 +1537,7 @@ void SkyManager::setWeather(const WeatherResult& weather) mParticleNode->setNodeMask(Mask_WeatherParticles); mRootNode->addChild(mParticleNode); } - mParticleEffect = mSceneManager->createInstance(mCurrentParticleEffect, mParticleNode); + mParticleEffect = mSceneManager->getInstance(mCurrentParticleEffect, mParticleNode); SceneUtil::AssignControllerSourcesVisitor assignVisitor(boost::shared_ptr(new SceneUtil::FrameTimeSource)); mParticleEffect->accept(assignVisitor); diff --git a/apps/openmw/mwrender/weaponanimation.cpp b/apps/openmw/mwrender/weaponanimation.cpp index 4328d5a3d..8fd294ccd 100644 --- a/apps/openmw/mwrender/weaponanimation.cpp +++ b/apps/openmw/mwrender/weaponanimation.cpp @@ -84,7 +84,7 @@ void WeaponAnimation::attachArrow(MWWorld::Ptr actor) return; std::string model = ammo->getClass().getModel(*ammo); - osg::ref_ptr arrow = getResourceSystem()->getSceneManager()->createInstance(model, parent); + osg::ref_ptr arrow = getResourceSystem()->getSceneManager()->getInstance(model, parent); mAmmunition = PartHolderPtr(new PartHolder(arrow)); } diff --git a/apps/openmw/mwworld/cellpreloader.cpp b/apps/openmw/mwworld/cellpreloader.cpp index 2591e8c89..c6fa3b949 100644 --- a/apps/openmw/mwworld/cellpreloader.cpp +++ b/apps/openmw/mwworld/cellpreloader.cpp @@ -86,7 +86,7 @@ namespace MWWorld //std::cout << "preloading " << mesh << std::endl; - mPreloadedNodes.push_back(mSceneManager->getTemplate(mesh)); + mPreloadedNodes.push_back(mSceneManager->cacheInstance(mesh)); mPreloadedShapes.push_back(mBulletShapeManager->getShape(mesh)); size_t slashpos = mesh.find_last_of("/\\"); @@ -104,8 +104,6 @@ namespace MWWorld } } - - // TODO: do a createInstance() and hold on to it since we can make use of it when the cell goes active } catch (std::exception& e) { @@ -185,6 +183,11 @@ namespace MWWorld mPreloadCells[cell] = PreloadEntry(timestamp, item); } + void CellPreloader::notifyLoaded(CellStore *cell) + { + mPreloadCells.erase(cell); + } + void CellPreloader::updateCache(double timestamp) { // TODO: add settings for a minimum/maximum size of the cache diff --git a/apps/openmw/mwworld/cellpreloader.hpp b/apps/openmw/mwworld/cellpreloader.hpp index c7495182b..55e40dcbd 100644 --- a/apps/openmw/mwworld/cellpreloader.hpp +++ b/apps/openmw/mwworld/cellpreloader.hpp @@ -24,6 +24,8 @@ namespace MWWorld /// @note The cell itself must be in State_Loaded or State_Preloaded. void preload(MWWorld::CellStore* cell, double timestamp); + void notifyLoaded(MWWorld::CellStore* cell); + /// Removes preloaded cells that have not had a preload request for a while. void updateCache(double timestamp); diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index d1faf621c..b8150ce9c 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -92,7 +92,7 @@ namespace MWWorld attachTo = rotateNode; } - mResourceSystem->getSceneManager()->createInstance(model, attachTo); + mResourceSystem->getSceneManager()->getInstance(model, attachTo); SceneUtil::DisableFreezeOnCullVisitor disableFreezeOnCullVisitor; state.mNode->accept(disableFreezeOnCullVisitor); diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 4c843133d..46d75daaf 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -296,6 +296,8 @@ namespace MWWorld if (!cell->isExterior() && !(cell->getCell()->mData.mFlags & ESM::Cell::QuasiEx)) mRendering.configureAmbient(cell->getCell()); } + + mPreloader->notifyLoaded(cell); } void Scene::changeToVoid() diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 81e6defe4..0ac32f65e 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -41,7 +41,7 @@ add_component_dir (vfs ) add_component_dir (resource - scenemanager keyframemanager imagemanager bulletshapemanager bulletshape niffilemanager objectcache resourcesystem resourcemanager + scenemanager keyframemanager imagemanager bulletshapemanager bulletshape niffilemanager objectcache multiobjectcache resourcesystem resourcemanager ) add_component_dir (sceneutil diff --git a/components/resource/multiobjectcache.cpp b/components/resource/multiobjectcache.cpp new file mode 100644 index 000000000..352715f19 --- /dev/null +++ b/components/resource/multiobjectcache.cpp @@ -0,0 +1,79 @@ +#include "multiobjectcache.hpp" + +#include + +#include + +namespace Resource +{ + + MultiObjectCache::MultiObjectCache() + { + + } + + MultiObjectCache::~MultiObjectCache() + { + + } + + void MultiObjectCache::removeUnreferencedObjectsInCache() + { + std::vector > objectsToRemove; + { + OpenThreads::ScopedLock lock(_objectCacheMutex); + + // Remove unreferenced entries from object cache + ObjectCacheMap::iterator oitr = _objectCache.begin(); + while(oitr != _objectCache.end()) + { + if (oitr->second->referenceCount() <= 1) + { + objectsToRemove.push_back(oitr->second); + _objectCache.erase(oitr++); + } + else + { + ++oitr; + } + } + } + + // note, actual unref happens outside of the lock + objectsToRemove.clear(); + } + + void MultiObjectCache::addEntryToObjectCache(const std::string &filename, osg::Object *object) + { + OpenThreads::ScopedLock lock(_objectCacheMutex); + _objectCache.insert(std::make_pair(filename, object)); + } + + osg::ref_ptr MultiObjectCache::takeFromObjectCache(const std::string &fileName) + { + OpenThreads::ScopedLock lock(_objectCacheMutex); + ObjectCacheMap::iterator found = _objectCache.find(fileName); + if (found == _objectCache.end()) + return osg::ref_ptr(); + else + { + osg::ref_ptr object = found->second; + _objectCache.erase(found); + return object; + } + } + + void MultiObjectCache::releaseGLObjects(osg::State *state) + { + OpenThreads::ScopedLock lock(_objectCacheMutex); + + for(ObjectCacheMap::iterator itr = _objectCache.begin(); + itr != _objectCache.end(); + ++itr) + { + osg::Object* object = itr->second.get(); + object->releaseGLObjects(state); + } + } + +} diff --git a/components/resource/multiobjectcache.hpp b/components/resource/multiobjectcache.hpp new file mode 100644 index 000000000..b677100f0 --- /dev/null +++ b/components/resource/multiobjectcache.hpp @@ -0,0 +1,47 @@ +#ifndef OPENMW_COMPONENTS_MULTIOBJECTCACHE_H +#define OPENMW_COMPONENTS_MULTIOBJECTCACHE_H + +#include +#include + +#include +#include + +namespace osg +{ + class Object; + class State; +} + +namespace Resource +{ + + /// @brief Cache for "non reusable" objects. + class MultiObjectCache : public osg::Referenced + { + public: + MultiObjectCache(); + ~MultiObjectCache(); + + void removeUnreferencedObjectsInCache(); + + void addEntryToObjectCache(const std::string& filename, osg::Object* object); + + /** Take an Object from cache. Return NULL if no object found. */ + osg::ref_ptr takeFromObjectCache(const std::string& fileName); + + /** call releaseGLObjects on all objects attached to the object cache.*/ + void releaseGLObjects(osg::State* state); + + protected: + + typedef std::multimap > ObjectCacheMap; + + ObjectCacheMap _objectCache; + OpenThreads::Mutex _objectCacheMutex; + + }; + +} + +#endif diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index f083e8175..5acd5f8fb 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -28,6 +28,7 @@ #include "imagemanager.hpp" #include "niffilemanager.hpp" #include "objectcache.hpp" +#include "multiobjectcache.hpp" namespace { @@ -233,6 +234,7 @@ namespace Resource SceneManager::SceneManager(const VFS::Manager *vfs, Resource::ImageManager* imageManager, Resource::NifFileManager* nifFileManager) : ResourceManager(vfs) + , mInstanceCache(new MultiObjectCache) , mImageManager(imageManager) , mNifFileManager(nifFileManager) , mMinFilter(osg::Texture::LINEAR_MIPMAP_LINEAR) @@ -246,7 +248,6 @@ namespace Resource SceneManager::~SceneManager() { // this has to be defined in the .cpp file as we can't delete incomplete types - } /// @brief Callback to read image files from the VFS. @@ -372,7 +373,17 @@ namespace Resource } } - osg::ref_ptr SceneManager::createInstance(const std::string &name) + osg::ref_ptr SceneManager::cacheInstance(const std::string &name) + { + std::string normalized = name; + mVFS->normalizeFilename(normalized); + + osg::ref_ptr node = createInstance(normalized); + mInstanceCache->addEntryToObjectCache(normalized, node.get()); + return node; + } + + osg::ref_ptr SceneManager::createInstance(const std::string& name) { osg::ref_ptr scene = getTemplate(name); osg::ref_ptr cloned = osg::clone(scene.get(), SceneUtil::CopyOp()); @@ -383,9 +394,22 @@ namespace Resource return cloned; } - osg::ref_ptr SceneManager::createInstance(const std::string &name, osg::Group* parentNode) + osg::ref_ptr SceneManager::getInstance(const std::string &name) { - osg::ref_ptr cloned = createInstance(name); + std::string normalized = name; + mVFS->normalizeFilename(normalized); + + osg::ref_ptr obj = mInstanceCache->takeFromObjectCache(normalized); + if (obj.get()) + return static_cast(obj.get()); + + return createInstance(normalized); + + } + + osg::ref_ptr SceneManager::getInstance(const std::string &name, osg::Group* parentNode) + { + osg::ref_ptr cloned = getInstance(name); attachTo(cloned, parentNode); return cloned; } @@ -487,4 +511,11 @@ namespace Resource mUnRefImageDataAfterApply = unref; } + void SceneManager::updateCache(double referenceTime) + { + ResourceManager::updateCache(referenceTime); + + mInstanceCache->removeUnreferencedObjectsInCache(); + } + } diff --git a/components/resource/scenemanager.hpp b/components/resource/scenemanager.hpp index 0345fff22..8357e63cd 100644 --- a/components/resource/scenemanager.hpp +++ b/components/resource/scenemanager.hpp @@ -29,6 +29,8 @@ namespace osgViewer namespace Resource { + class MultiObjectCache; + /// @brief Handles loading and caching of scenes, e.g. .nif files or .osg files /// @note Some methods of the scene manager can be used from any thread, see the methods documentation for more details. class SceneManager : public ResourceManager @@ -43,15 +45,21 @@ namespace Resource /// @note Thread safe. osg::ref_ptr getTemplate(const std::string& name); - /// Create an instance of the given scene template + /// Create an instance of the given scene template and cache it for later use, so that future calls to getInstance() can simply + /// return this cached object instead of creating a new one. + /// @note The returned ref_ptr may be kept around by the caller to ensure that the object stays in cache for as long as needed. + /// @note Thread safe. + osg::ref_ptr cacheInstance(const std::string& name); + + /// Get an instance of the given scene template /// @see getTemplate /// @note Thread safe. - osg::ref_ptr createInstance(const std::string& name); + osg::ref_ptr getInstance(const std::string& name); - /// Create an instance of the given scene template and immediately attach it to a parent node + /// Get an instance of the given scene template and immediately attach it to a parent node /// @see getTemplate /// @note Not thread safe, unless parentNode is not part of the main scene graph yet. - osg::ref_ptr createInstance(const std::string& name, osg::Group* parentNode); + osg::ref_ptr getInstance(const std::string& name, osg::Group* parentNode); /// Attach the given scene instance to the given parent node /// @note You should have the parentNode in its intended position before calling this method, @@ -88,7 +96,15 @@ namespace Resource /// otherwise should be disabled to reduce memory usage. void setUnRefImageDataAfterApply(bool unref); + /// @see ResourceManager::updateCache + virtual void updateCache(double referenceTime); + private: + + osg::ref_ptr createInstance(const std::string& name); + + osg::ref_ptr mInstanceCache; + OpenThreads::Mutex mSharedStateMutex; Resource::ImageManager* mImageManager; From 246566cef4294062e8bc636458e4f54fffab56e4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 9 Feb 2016 18:48:49 +0100 Subject: [PATCH 3132/3725] Preload instances in BulletShapeManager --- apps/openmw/mwphysics/physicssystem.cpp | 4 +-- apps/openmw/mwworld/cellpreloader.cpp | 4 +-- components/resource/bulletshapemanager.cpp | 32 +++++++++++++++++++++- components/resource/bulletshapemanager.hpp | 18 ++++++++++-- 4 files changed, 51 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 6417968d3..5d0ac1f8f 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -1088,7 +1088,7 @@ namespace MWPhysics void PhysicsSystem::addObject (const MWWorld::Ptr& ptr, const std::string& mesh, int collisionType) { - osg::ref_ptr shapeInstance = mShapeManager->createInstance(mesh); + osg::ref_ptr shapeInstance = mShapeManager->getInstance(mesh); if (!shapeInstance || !shapeInstance->getCollisionShape()) return; @@ -1234,7 +1234,7 @@ namespace MWPhysics } void PhysicsSystem::addActor (const MWWorld::Ptr& ptr, const std::string& mesh) { - osg::ref_ptr shapeInstance = mShapeManager->createInstance(mesh); + osg::ref_ptr shapeInstance = mShapeManager->getInstance(mesh); if (!shapeInstance) return; diff --git a/apps/openmw/mwworld/cellpreloader.cpp b/apps/openmw/mwworld/cellpreloader.cpp index c6fa3b949..047c1e99b 100644 --- a/apps/openmw/mwworld/cellpreloader.cpp +++ b/apps/openmw/mwworld/cellpreloader.cpp @@ -87,7 +87,7 @@ namespace MWWorld //std::cout << "preloading " << mesh << std::endl; mPreloadedNodes.push_back(mSceneManager->cacheInstance(mesh)); - mPreloadedShapes.push_back(mBulletShapeManager->getShape(mesh)); + mPreloadedShapes.push_back(mBulletShapeManager->cacheInstance(mesh)); size_t slashpos = mesh.find_last_of("/\\"); if (slashpos != std::string::npos && slashpos != mesh.size()-1) @@ -123,7 +123,7 @@ namespace MWWorld // keep a ref to the loaded object to make sure it stays loaded as long as this cell is in the preloaded state std::vector > mPreloadedNodes; - std::vector > mPreloadedShapes; + std::vector > mPreloadedShapes; std::vector > mPreloadedKeyframes; }; diff --git a/components/resource/bulletshapemanager.cpp b/components/resource/bulletshapemanager.cpp index cb57d686f..111808e6e 100644 --- a/components/resource/bulletshapemanager.cpp +++ b/components/resource/bulletshapemanager.cpp @@ -14,7 +14,7 @@ #include "scenemanager.hpp" #include "niffilemanager.hpp" #include "objectcache.hpp" - +#include "multiobjectcache.hpp" namespace Resource { @@ -98,6 +98,7 @@ private: BulletShapeManager::BulletShapeManager(const VFS::Manager* vfs, SceneManager* sceneMgr, NifFileManager* nifFileManager) : ResourceManager(vfs) + , mInstanceCache(new MultiObjectCache) , mSceneManager(sceneMgr) , mNifFileManager(nifFileManager) { @@ -151,6 +152,28 @@ osg::ref_ptr BulletShapeManager::getShape(const std::string & return shape; } +osg::ref_ptr BulletShapeManager::cacheInstance(const std::string &name) +{ + std::string normalized = name; + mVFS->normalizeFilename(normalized); + + osg::ref_ptr instance = createInstance(normalized); + mInstanceCache->addEntryToObjectCache(normalized, instance.get()); + return instance; +} + +osg::ref_ptr BulletShapeManager::getInstance(const std::string &name) +{ + std::string normalized = name; + mVFS->normalizeFilename(normalized); + + osg::ref_ptr obj = mInstanceCache->takeFromObjectCache(normalized); + if (obj.get()) + return static_cast(obj.get()); + else + return createInstance(normalized); +} + osg::ref_ptr BulletShapeManager::createInstance(const std::string &name) { osg::ref_ptr shape = getShape(name); @@ -160,4 +183,11 @@ osg::ref_ptr BulletShapeManager::createInstance(const std:: return osg::ref_ptr(); } +void BulletShapeManager::updateCache(double referenceTime) +{ + ResourceManager::updateCache(referenceTime); + + mInstanceCache->removeUnreferencedObjectsInCache(); +} + } diff --git a/components/resource/bulletshapemanager.hpp b/components/resource/bulletshapemanager.hpp index 4c0cb1fd2..14b26962b 100644 --- a/components/resource/bulletshapemanager.hpp +++ b/components/resource/bulletshapemanager.hpp @@ -17,6 +17,8 @@ namespace Resource class BulletShape; class BulletShapeInstance; + class MultiObjectCache; + /// Handles loading, caching and "instancing" of bullet shapes. /// A shape 'instance' is a clone of another shape, with the goal of setting a different scale on this instance. /// @note May be used from any thread. @@ -26,12 +28,24 @@ namespace Resource BulletShapeManager(const VFS::Manager* vfs, SceneManager* sceneMgr, NifFileManager* nifFileManager); ~BulletShapeManager(); + /// @note May return a null pointer if the object has no shape. osg::ref_ptr getShape(const std::string& name); - /// Shorthand for getShape(name)->makeInstance(); - osg::ref_ptr createInstance(const std::string& name); + /// Create an instance of the given shape and cache it for later use, so that future calls to getInstance() can simply return + /// the cached instance instead of having to create a new one. + /// @note The returned ref_ptr may be kept by the caller to ensure that the instance stays in cache for as long as needed. + osg::ref_ptr cacheInstance(const std::string& name); + + /// @note May return a null pointer if the object has no shape. + osg::ref_ptr getInstance(const std::string& name); + + /// @see ResourceManager::updateCache + virtual void updateCache(double referenceTime); private: + osg::ref_ptr createInstance(const std::string& name); + + osg::ref_ptr mInstanceCache; SceneManager* mSceneManager; NifFileManager* mNifFileManager; }; From 3552b3a82cf706c8ba63a663a8d9144d90f7505c Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 9 Feb 2016 18:51:17 +0100 Subject: [PATCH 3133/3725] Don't create a BulletShapeInstance for actors --- apps/openmw/mwphysics/actor.cpp | 2 +- apps/openmw/mwphysics/actor.hpp | 4 ++-- apps/openmw/mwphysics/physicssystem.cpp | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwphysics/actor.cpp b/apps/openmw/mwphysics/actor.cpp index cc46897d1..c99754b5c 100644 --- a/apps/openmw/mwphysics/actor.cpp +++ b/apps/openmw/mwphysics/actor.cpp @@ -16,7 +16,7 @@ namespace MWPhysics { -Actor::Actor(const MWWorld::Ptr& ptr, osg::ref_ptr shape, btCollisionWorld* world) +Actor::Actor(const MWWorld::Ptr& ptr, osg::ref_ptr shape, btCollisionWorld* world) : mCanWaterWalk(false), mWalkingOnWater(false) , mCollisionObject(0), mForce(0.f, 0.f, 0.f), mOnGround(false) , mInternalCollisionMode(true) diff --git a/apps/openmw/mwphysics/actor.hpp b/apps/openmw/mwphysics/actor.hpp index 03193c675..5755def74 100644 --- a/apps/openmw/mwphysics/actor.hpp +++ b/apps/openmw/mwphysics/actor.hpp @@ -15,7 +15,7 @@ class btCollisionObject; namespace Resource { - class BulletShapeInstance; + class BulletShape; } namespace MWPhysics @@ -48,7 +48,7 @@ namespace MWPhysics class Actor : public PtrHolder { public: - Actor(const MWWorld::Ptr& ptr, osg::ref_ptr shape, btCollisionWorld* world); + Actor(const MWWorld::Ptr& ptr, osg::ref_ptr shape, btCollisionWorld* world); ~Actor(); /** diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 5d0ac1f8f..48b3426b8 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -1234,11 +1234,11 @@ namespace MWPhysics } void PhysicsSystem::addActor (const MWWorld::Ptr& ptr, const std::string& mesh) { - osg::ref_ptr shapeInstance = mShapeManager->getInstance(mesh); - if (!shapeInstance) + osg::ref_ptr shape = mShapeManager->getShape(mesh); + if (!shape) return; - Actor* actor = new Actor(ptr, shapeInstance, mCollisionWorld); + Actor* actor = new Actor(ptr, shape, mCollisionWorld); mActors.insert(std::make_pair(ptr, actor)); } From afe533e6709496131cd5f424cab3f9b1b538fc25 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 9 Feb 2016 19:00:30 +0100 Subject: [PATCH 3134/3725] Accept a const Object in UnrefQueue --- components/sceneutil/unrefqueue.cpp | 4 ++-- components/sceneutil/unrefqueue.hpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/components/sceneutil/unrefqueue.cpp b/components/sceneutil/unrefqueue.cpp index 0b65c4a32..a5eb1654e 100644 --- a/components/sceneutil/unrefqueue.cpp +++ b/components/sceneutil/unrefqueue.cpp @@ -14,7 +14,7 @@ namespace SceneUtil class UnrefWorkItem : public SceneUtil::WorkItem { public: - std::deque > mObjects; + std::deque > mObjects; virtual void doWork() { @@ -30,7 +30,7 @@ namespace SceneUtil mWorkItem = new UnrefWorkItem; } - void UnrefQueue::push(osg::Object *obj) + void UnrefQueue::push(const osg::Object *obj) { mWorkItem->mObjects.push_back(obj); } diff --git a/components/sceneutil/unrefqueue.hpp b/components/sceneutil/unrefqueue.hpp index d0bec061c..85b1d31e1 100644 --- a/components/sceneutil/unrefqueue.hpp +++ b/components/sceneutil/unrefqueue.hpp @@ -22,7 +22,7 @@ namespace SceneUtil UnrefQueue(); /// Adds an object to the list of objects to be unreferenced. Call from the main thread. - void push(osg::Object* obj); + void push(const osg::Object* obj); /// Adds a WorkItem to the given WorkQueue that will clear the list of objects in a worker thread, thus unreferencing them. /// Call from the main thread. From 1457a0de78464a68e9b56e0ccf33189f5e0afc33 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 9 Feb 2016 19:04:59 +0100 Subject: [PATCH 3135/3725] Use the UnrefQueue to delete BulletShapeInstances --- apps/openmw/mwphysics/physicssystem.cpp | 14 ++++++++++++++ apps/openmw/mwphysics/physicssystem.hpp | 9 +++++++-- apps/openmw/mwrender/renderingmanager.cpp | 5 +++++ apps/openmw/mwrender/renderingmanager.hpp | 1 + apps/openmw/mwworld/scene.cpp | 2 ++ 5 files changed, 29 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 48b3426b8..9f1cfc682 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -22,6 +22,7 @@ #include #include +#include #include // FindRecIndexVisitor @@ -533,6 +534,11 @@ namespace MWPhysics setOrigin(btVector3(pos[0], pos[1], pos[2])); } + const Resource::BulletShapeInstance* getShapeInstance() const + { + return mShapeInstance.get(); + } + void setScale(float scale) { mShapeInstance->getCollisionShape()->setLocalScaling(btVector3(scale,scale,scale)); @@ -690,6 +696,11 @@ namespace MWPhysics delete mBroadphase; } + void PhysicsSystem::setUnrefQueue(SceneUtil::UnrefQueue *unrefQueue) + { + mUnrefQueue = unrefQueue; + } + Resource::BulletShapeManager *PhysicsSystem::getShapeManager() { return mShapeManager.get(); @@ -1109,6 +1120,9 @@ namespace MWPhysics { mCollisionWorld->removeCollisionObject(found->second->getCollisionObject()); + if (mUnrefQueue.get()) + mUnrefQueue->push(found->second->getShapeInstance()); + mAnimatedObjects.erase(found->second); delete found->second; diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index a866717c7..110b59268 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -25,11 +25,12 @@ namespace MWRender namespace Resource { class BulletShapeManager; + class ResourceSystem; } -namespace Resource +namespace SceneUtil { - class ResourceSystem; + class UnrefQueue; } class btCollisionWorld; @@ -53,6 +54,8 @@ namespace MWPhysics PhysicsSystem (Resource::ResourceSystem* resourceSystem, osg::ref_ptr parentNode); ~PhysicsSystem (); + void setUnrefQueue(SceneUtil::UnrefQueue* unrefQueue); + Resource::BulletShapeManager* getShapeManager(); void enableWater(float height); @@ -165,6 +168,8 @@ namespace MWPhysics void updateWater(); + osg::ref_ptr mUnrefQueue; + btBroadphaseInterface* mBroadphase; btDefaultCollisionConfiguration* mCollisionConfiguration; btCollisionDispatcher* mDispatcher; diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 5a9cd59fc..be3caaeb4 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -263,6 +263,11 @@ namespace MWRender return mWorkQueue.get(); } + SceneUtil::UnrefQueue *RenderingManager::getUnrefQueue() + { + return mUnrefQueue.get(); + } + void RenderingManager::preloadCommonAssets() { osg::ref_ptr workItem (new PreloadCommonAssetsWorkItem(mResourceSystem)); diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 3d6a4ac3a..4c850de12 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -72,6 +72,7 @@ namespace MWRender Resource::ResourceSystem* getResourceSystem(); SceneUtil::WorkQueue* getWorkQueue(); + SceneUtil::UnrefQueue* getUnrefQueue(); void preloadCommonAssets(); diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 46d75daaf..b0e384493 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -466,6 +466,8 @@ namespace MWWorld mPreloader.reset(new CellPreloader(rendering.getResourceSystem(), physics->getShapeManager())); mPreloader->setWorkQueue(mRendering.getWorkQueue()); + mPhysics->setUnrefQueue(rendering.getUnrefQueue()); + float cacheExpiryDelay = Settings::Manager::getFloat("cache expiry delay", "Cells"); rendering.getResourceSystem()->setExpiryDelay(cacheExpiryDelay); mPreloader->setExpiryDelay(cacheExpiryDelay); From 596fe56bfdfe95dbc1a8783f65bf33c73694cd7e Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 9 Feb 2016 20:14:16 +0100 Subject: [PATCH 3136/3725] Make Land::loadData thread safe --- apps/opencs/model/tools/mergestages.cpp | 2 -- apps/openmw/mwrender/terrainstorage.cpp | 3 ++ components/esm/loadland.cpp | 42 ++++++++++++++----------- components/esm/loadland.hpp | 7 +++-- 4 files changed, 31 insertions(+), 23 deletions(-) diff --git a/apps/opencs/model/tools/mergestages.cpp b/apps/opencs/model/tools/mergestages.cpp index 52e1e6964..f52e8886f 100644 --- a/apps/opencs/model/tools/mergestages.cpp +++ b/apps/opencs/model/tools/mergestages.cpp @@ -224,8 +224,6 @@ void CSMTools::MergeLandStage::perform (int stage, CSMDoc::Messages& messages) CSMWorld::Land newLand (land); - newLand.mEsm = 0; // avoid potential dangling pointer (ESMReader isn't needed anyway, - // because record is already fully loaded) newLand.mPlugin = 0; if (land.mDataTypes & ESM::Land::DATA_VTEX) diff --git a/apps/openmw/mwrender/terrainstorage.cpp b/apps/openmw/mwrender/terrainstorage.cpp index ed1d8b677..02947b5dd 100644 --- a/apps/openmw/mwrender/terrainstorage.cpp +++ b/apps/openmw/mwrender/terrainstorage.cpp @@ -62,6 +62,9 @@ namespace MWRender const int flags = ESM::Land::DATA_VCLR|ESM::Land::DATA_VHGT|ESM::Land::DATA_VNML|ESM::Land::DATA_VTEX; if (!land->isDataLoaded(flags)) land->loadData(flags); + + // TODO: unload land data when it's no longer needed + return land; } diff --git a/components/esm/loadland.cpp b/components/esm/loadland.cpp index e7be03321..b0b072232 100644 --- a/components/esm/loadland.cpp +++ b/components/esm/loadland.cpp @@ -2,6 +2,8 @@ #include +#include + #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" @@ -60,7 +62,6 @@ namespace ESM , mX(0) , mY(0) , mPlugin(0) - , mEsm(NULL) , mDataTypes(0) , mDataLoaded(false) , mLandData(NULL) @@ -86,8 +87,7 @@ namespace ESM { isDeleted = false; - mEsm = &esm; - mPlugin = mEsm->getIndex(); + mPlugin = esm.getIndex(); bool hasLocation = false; bool isLoaded = false; @@ -180,6 +180,8 @@ namespace ESM void Land::loadData(int flags) const { + OpenThreads::ScopedLock lock(mMutex); + // Try to load only available data flags = flags & mDataTypes; // Return if all required data is loaded @@ -191,15 +193,17 @@ namespace ESM mLandData = new LandData; mLandData->mDataTypes = mDataTypes; } - mEsm->restoreContext(mContext); - if (mEsm->isNextSub("VNML")) { - condLoad(flags, DATA_VNML, mLandData->mNormals, sizeof(mLandData->mNormals)); + ESM::ESMReader reader; + reader.restoreContext(mContext); + + if (reader.isNextSub("VNML")) { + condLoad(reader, flags, DATA_VNML, mLandData->mNormals, sizeof(mLandData->mNormals)); } - if (mEsm->isNextSub("VHGT")) { + if (reader.isNextSub("VHGT")) { static VHGT vhgt; - if (condLoad(flags, DATA_VHGT, &vhgt, sizeof(vhgt))) { + if (condLoad(reader, flags, DATA_VHGT, &vhgt, sizeof(vhgt))) { float rowOffset = vhgt.mHeightOffset; for (int y = 0; y < LAND_SIZE; y++) { rowOffset += vhgt.mHeightData[y * LAND_SIZE]; @@ -217,14 +221,14 @@ namespace ESM } } - if (mEsm->isNextSub("WNAM")) { - condLoad(flags, DATA_WNAM, mLandData->mWnam, 81); + if (reader.isNextSub("WNAM")) { + condLoad(reader, flags, DATA_WNAM, mLandData->mWnam, 81); } - if (mEsm->isNextSub("VCLR")) - condLoad(flags, DATA_VCLR, mLandData->mColours, 3 * LAND_NUM_VERTS); - if (mEsm->isNextSub("VTEX")) { + if (reader.isNextSub("VCLR")) + condLoad(reader, flags, DATA_VCLR, mLandData->mColours, 3 * LAND_NUM_VERTS); + if (reader.isNextSub("VTEX")) { static uint16_t vtex[LAND_NUM_TEXTURES]; - if (condLoad(flags, DATA_VTEX, vtex, sizeof(vtex))) { + if (condLoad(reader, flags, DATA_VTEX, vtex, sizeof(vtex))) { LandData::transposeTextureData(vtex, mLandData->mTextures); } } @@ -240,25 +244,26 @@ namespace ESM } } - bool Land::condLoad(int flags, int dataFlag, void *ptr, unsigned int size) const + bool Land::condLoad(ESM::ESMReader& reader, int flags, int dataFlag, void *ptr, unsigned int size) const { if ((mDataLoaded & dataFlag) == 0 && (flags & dataFlag) != 0) { - mEsm->getHExact(ptr, size); + reader.getHExact(ptr, size); mDataLoaded |= dataFlag; return true; } - mEsm->skipHSubSize(size); + reader.skipHSubSize(size); return false; } bool Land::isDataLoaded(int flags) const { + OpenThreads::ScopedLock lock(mMutex); return (mDataLoaded & flags) == (flags & mDataTypes); } Land::Land (const Land& land) : mFlags (land.mFlags), mX (land.mX), mY (land.mY), mPlugin (land.mPlugin), - mEsm (land.mEsm), mContext (land.mContext), mDataTypes (land.mDataTypes), + mContext (land.mContext), mDataTypes (land.mDataTypes), mDataLoaded (land.mDataLoaded), mLandData (land.mLandData ? new LandData (*land.mLandData) : 0) {} @@ -275,7 +280,6 @@ namespace ESM std::swap (mX, land.mX); std::swap (mY, land.mY); std::swap (mPlugin, land.mPlugin); - std::swap (mEsm, land.mEsm); std::swap (mContext, land.mContext); std::swap (mDataTypes, land.mDataTypes); std::swap (mDataLoaded, land.mDataLoaded); diff --git a/components/esm/loadland.hpp b/components/esm/loadland.hpp index 65ac88cda..8a8d6fdd2 100644 --- a/components/esm/loadland.hpp +++ b/components/esm/loadland.hpp @@ -3,6 +3,8 @@ #include +#include + #include "esmcommon.hpp" namespace ESM @@ -31,7 +33,6 @@ struct Land // File context. This allows the ESM reader to be 'reset' to this // location later when we are ready to load the full data set. - ESMReader* mEsm; ESM_Context mContext; int mDataTypes; @@ -155,7 +156,9 @@ struct Land /// Loads data and marks it as loaded /// \return true if data is actually loaded from file, false otherwise /// including the case when data is already loaded - bool condLoad(int flags, int dataFlag, void *ptr, unsigned int size) const; + bool condLoad(ESM::ESMReader& reader, int flags, int dataFlag, void *ptr, unsigned int size) const; + + mutable OpenThreads::Mutex mMutex; mutable int mDataLoaded; From 8aba74e6ee4df45cc442148e4e0b0f770b2159ef Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 9 Feb 2016 20:23:53 +0100 Subject: [PATCH 3137/3725] Remove GridElement --- components/terrain/terraingrid.cpp | 20 +++++--------------- components/terrain/terraingrid.hpp | 4 +--- 2 files changed, 6 insertions(+), 18 deletions(-) diff --git a/components/terrain/terraingrid.cpp b/components/terrain/terraingrid.cpp index 4b67371e0..4d2f421e6 100644 --- a/components/terrain/terraingrid.cpp +++ b/components/terrain/terraingrid.cpp @@ -63,12 +63,6 @@ TerrainGrid::~TerrainGrid() } } -class GridElement -{ -public: - osg::ref_ptr mNode; -}; - osg::ref_ptr TerrainGrid::buildTerrain (osg::Group* parent, float chunkSize, const osg::Vec2f& chunkCenter) { if (chunkSize * mNumSplits > 1.f) @@ -208,11 +202,9 @@ void TerrainGrid::loadCell(int x, int y) if (!terrainNode) return; // no terrain defined - std::auto_ptr element (new GridElement); - element->mNode = terrainNode; - mTerrainRoot->addChild(element->mNode); + mTerrainRoot->addChild(terrainNode); - mGrid[std::make_pair(x,y)] = element.release(); + mGrid[std::make_pair(x,y)] = terrainNode; } void TerrainGrid::unloadCell(int x, int y) @@ -221,13 +213,11 @@ void TerrainGrid::unloadCell(int x, int y) if (it == mGrid.end()) return; - GridElement* element = it->second; - mTerrainRoot->removeChild(element->mNode); + osg::Node* terrainNode = it->second; + mTerrainRoot->removeChild(terrainNode); if (mUnrefQueue.get()) - mUnrefQueue->push(element->mNode); - - delete element; + mUnrefQueue->push(terrainNode); mGrid.erase(it); } diff --git a/components/terrain/terraingrid.hpp b/components/terrain/terraingrid.hpp index 5708e7068..4e6a78abd 100644 --- a/components/terrain/terraingrid.hpp +++ b/components/terrain/terraingrid.hpp @@ -14,8 +14,6 @@ namespace SceneUtil namespace Terrain { - class GridElement; - /// @brief Simple terrain implementation that loads cells in a grid, with no LOD class TerrainGrid : public Terrain::World { @@ -38,7 +36,7 @@ namespace Terrain typedef std::map > TextureCache; TextureCache mTextureCache; - typedef std::map, GridElement*> Grid; + typedef std::map, osg::ref_ptr > Grid; Grid mGrid; osg::ref_ptr mUnrefQueue; From 98848c752a0621e3820f62b53f6c8b46aee3fcc6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 9 Feb 2016 20:26:58 +0100 Subject: [PATCH 3138/3725] Make getLayerInfo thread safe --- components/esmterrain/storage.cpp | 4 ++++ components/esmterrain/storage.hpp | 3 +++ 2 files changed, 7 insertions(+) diff --git a/components/esmterrain/storage.cpp b/components/esmterrain/storage.cpp index 267b831ec..cead73070 100644 --- a/components/esmterrain/storage.cpp +++ b/components/esmterrain/storage.cpp @@ -3,6 +3,8 @@ #include #include +#include + #include #include @@ -498,6 +500,8 @@ namespace ESMTerrain Terrain::LayerInfo Storage::getLayerInfo(const std::string& texture) { + OpenThreads::ScopedLock lock(mLayerInfoMutex); + // Already have this cached? std::map::iterator found = mLayerInfoMap.find(texture); if (found != mLayerInfoMap.end()) diff --git a/components/esmterrain/storage.hpp b/components/esmterrain/storage.hpp index 5b8ca953d..9ca39e6f3 100644 --- a/components/esmterrain/storage.hpp +++ b/components/esmterrain/storage.hpp @@ -1,6 +1,8 @@ #ifndef COMPONENTS_ESM_TERRAIN_STORAGE_H #define COMPONENTS_ESM_TERRAIN_STORAGE_H +#include + #include #include @@ -105,6 +107,7 @@ namespace ESMTerrain std::string getTextureName (UniqueTextureId id); std::map mLayerInfoMap; + OpenThreads::Mutex mLayerInfoMutex; Terrain::LayerInfo getLayerInfo(const std::string& texture); }; From 0865cea2111a3e641a4e78a3935adc4d3b2a649b Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 9 Feb 2016 20:57:30 +0100 Subject: [PATCH 3139/3725] Preload terrain --- apps/openmw/mwrender/renderingmanager.cpp | 17 ++--- apps/openmw/mwrender/renderingmanager.hpp | 3 +- apps/openmw/mwworld/cellpreloader.cpp | 52 +++++++++---- apps/openmw/mwworld/cellpreloader.hpp | 8 +- apps/openmw/mwworld/scene.cpp | 4 +- components/resource/resourcemanager.cpp | 5 -- components/resource/resourcemanager.hpp | 3 - components/terrain/buffercache.cpp | 4 + components/terrain/buffercache.hpp | 4 + components/terrain/terraingrid.cpp | 92 +++++++++++++++++------ components/terrain/terraingrid.hpp | 19 ++++- components/terrain/world.cpp | 1 - components/terrain/world.hpp | 6 +- 13 files changed, 152 insertions(+), 66 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index be3caaeb4..177cee4ea 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -258,16 +258,21 @@ namespace MWRender return mResourceSystem; } - SceneUtil::WorkQueue *RenderingManager::getWorkQueue() + SceneUtil::WorkQueue* RenderingManager::getWorkQueue() { return mWorkQueue.get(); } - SceneUtil::UnrefQueue *RenderingManager::getUnrefQueue() + SceneUtil::UnrefQueue* RenderingManager::getUnrefQueue() { return mUnrefQueue.get(); } + Terrain::World* RenderingManager::getTerrain() + { + return mTerrain.get(); + } + void RenderingManager::preloadCommonAssets() { osg::ref_ptr workItem (new PreloadCommonAssetsWorkItem(mResourceSystem)); @@ -279,12 +284,6 @@ namespace MWRender mWorkQueue->addWorkItem(workItem); } - void RenderingManager::clearCache() - { - if (mTerrain.get()) - mTerrain->clearCache(); - } - double RenderingManager::getReferenceTime() const { return mViewer->getFrameStamp()->getReferenceTime(); @@ -838,7 +837,7 @@ namespace MWRender void RenderingManager::updateTextureFiltering() { if (mTerrain.get()) - mTerrain->clearCache(); + mTerrain->updateCache(); mResourceSystem->getSceneManager()->setFilterSettings( Settings::Manager::getString("texture mag filter", "General"), diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 4c850de12..4dda6f273 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -73,11 +73,10 @@ namespace MWRender SceneUtil::WorkQueue* getWorkQueue(); SceneUtil::UnrefQueue* getUnrefQueue(); + Terrain::World* getTerrain(); void preloadCommonAssets(); - void clearCache(); - double getReferenceTime() const; osg::Group* getLightRoot(); diff --git a/apps/openmw/mwworld/cellpreloader.cpp b/apps/openmw/mwworld/cellpreloader.cpp index 047c1e99b..e72c36c68 100644 --- a/apps/openmw/mwworld/cellpreloader.cpp +++ b/apps/openmw/mwworld/cellpreloader.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -44,10 +45,14 @@ namespace MWWorld { public: /// Constructor to be called from the main thread. - PreloadItem(MWWorld::CellStore* cell, Resource::SceneManager* sceneManager, Resource::BulletShapeManager* bulletShapeManager, Resource::KeyframeManager* keyframeManager) - : mSceneManager(sceneManager) + PreloadItem(MWWorld::CellStore* cell, Resource::SceneManager* sceneManager, Resource::BulletShapeManager* bulletShapeManager, Resource::KeyframeManager* keyframeManager, Terrain::World* terrain) + : mIsExterior(cell->getCell()->isExterior()) + , mX(cell->getCell()->getGridX()) + , mY(cell->getCell()->getGridY()) + , mSceneManager(sceneManager) , mBulletShapeManager(bulletShapeManager) , mKeyframeManager(keyframeManager) + , mTerrain(terrain) { osg::Timer timer; ListModelsVisitor visitor (mMeshes); @@ -86,8 +91,8 @@ namespace MWWorld //std::cout << "preloading " << mesh << std::endl; - mPreloadedNodes.push_back(mSceneManager->cacheInstance(mesh)); - mPreloadedShapes.push_back(mBulletShapeManager->cacheInstance(mesh)); + mPreloadedObjects.push_back(mSceneManager->cacheInstance(mesh)); + mPreloadedObjects.push_back(mBulletShapeManager->cacheInstance(mesh)); size_t slashpos = mesh.find_last_of("/\\"); if (slashpos != std::string::npos && slashpos != mesh.size()-1) @@ -99,7 +104,7 @@ namespace MWWorld if(kfname.size() > 4 && kfname.compare(kfname.size()-4, 4, ".nif") == 0) { kfname.replace(kfname.size()-4, 4, ".kf"); - mPreloadedKeyframes.push_back(mKeyframeManager->get(kfname)); + mPreloadedObjects.push_back(mKeyframeManager->get(kfname)); } } @@ -111,29 +116,44 @@ namespace MWWorld // error will be shown when visiting the cell } } - std::cout << "preloaded " << mPreloadedNodes.size() << " nodes in " << preloadTimer.time_m() << std::endl; + + if (mIsExterior) + { + try + { + mPreloadedObjects.push_back(mTerrain->cacheCell(mX, mY)); + } + catch(std::exception& e) + { + } + } + + std::cout << "preloaded " << mPreloadedObjects.size() << " objects in " << preloadTimer.time_m() << std::endl; } private: typedef std::vector MeshList; + bool mIsExterior; + int mX; + int mY; MeshList mMeshes; Resource::SceneManager* mSceneManager; Resource::BulletShapeManager* mBulletShapeManager; Resource::KeyframeManager* mKeyframeManager; + Terrain::World* mTerrain; - // keep a ref to the loaded object to make sure it stays loaded as long as this cell is in the preloaded state - std::vector > mPreloadedNodes; - std::vector > mPreloadedShapes; - std::vector > mPreloadedKeyframes; + // keep a ref to the loaded objects to make sure it stays loaded as long as this cell is in the preloaded state + std::vector > mPreloadedObjects; }; /// Worker thread item: update the resource system's cache, effectively deleting unused entries. class UpdateCacheItem : public SceneUtil::WorkItem { public: - UpdateCacheItem(Resource::ResourceSystem* resourceSystem, double referenceTime) + UpdateCacheItem(Resource::ResourceSystem* resourceSystem, Terrain::World* terrain, double referenceTime) : mReferenceTime(referenceTime) , mResourceSystem(resourceSystem) + , mTerrain(terrain) { } @@ -141,17 +161,21 @@ namespace MWWorld { osg::Timer timer; mResourceSystem->updateCache(mReferenceTime); + + mTerrain->updateCache(); std::cout << "cleared cache in " << timer.time_m() << std::endl; } private: double mReferenceTime; Resource::ResourceSystem* mResourceSystem; + Terrain::World* mTerrain; }; - CellPreloader::CellPreloader(Resource::ResourceSystem* resourceSystem, Resource::BulletShapeManager* bulletShapeManager) + CellPreloader::CellPreloader(Resource::ResourceSystem* resourceSystem, Resource::BulletShapeManager* bulletShapeManager, Terrain::World* terrain) : mResourceSystem(resourceSystem) , mBulletShapeManager(bulletShapeManager) + , mTerrain(terrain) , mExpiryDelay(0.0) { } @@ -177,7 +201,7 @@ namespace MWWorld return; } - osg::ref_ptr item (new PreloadItem(cell, mResourceSystem->getSceneManager(), mBulletShapeManager, mResourceSystem->getKeyframeManager())); + osg::ref_ptr item (new PreloadItem(cell, mResourceSystem->getSceneManager(), mBulletShapeManager, mResourceSystem->getKeyframeManager(), mTerrain)); mWorkQueue->addWorkItem(item); mPreloadCells[cell] = PreloadEntry(timestamp, item); @@ -201,7 +225,7 @@ namespace MWWorld } // the resource cache is cleared from the worker thread so that we're not holding up the main thread with delete operations - mWorkQueue->addWorkItem(new UpdateCacheItem(mResourceSystem, timestamp)); + mWorkQueue->addWorkItem(new UpdateCacheItem(mResourceSystem, mTerrain, timestamp)); } void CellPreloader::setExpiryDelay(double expiryDelay) diff --git a/apps/openmw/mwworld/cellpreloader.hpp b/apps/openmw/mwworld/cellpreloader.hpp index 55e40dcbd..32ea194c6 100644 --- a/apps/openmw/mwworld/cellpreloader.hpp +++ b/apps/openmw/mwworld/cellpreloader.hpp @@ -11,6 +11,11 @@ namespace Resource class BulletShapeManager; } +namespace Terrain +{ + class World; +} + namespace MWWorld { class CellStore; @@ -18,7 +23,7 @@ namespace MWWorld class CellPreloader { public: - CellPreloader(Resource::ResourceSystem* resourceSystem, Resource::BulletShapeManager* bulletShapeManager); + CellPreloader(Resource::ResourceSystem* resourceSystem, Resource::BulletShapeManager* bulletShapeManager, Terrain::World* terrain); /// Ask a background thread to preload rendering meshes and collision shapes for objects in this cell. /// @note The cell itself must be in State_Loaded or State_Preloaded. @@ -37,6 +42,7 @@ namespace MWWorld private: Resource::ResourceSystem* mResourceSystem; Resource::BulletShapeManager* mBulletShapeManager; + Terrain::World* mTerrain; osg::ref_ptr mWorkQueue; double mExpiryDelay; diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index b0e384493..0be26c7b6 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -416,7 +416,6 @@ namespace MWWorld mCellChanged = true; mPreloader->updateCache(mRendering.getReferenceTime()); - mRendering.clearCache(); std::cout << "changeCellGrid took " << timer.time_m() << std::endl; } @@ -463,7 +462,7 @@ namespace MWWorld , mPreloadDoors(Settings::Manager::getBool("preload doors", "Cells")) , mPreloadFastTravel(Settings::Manager::getBool("preload fast travel", "Cells")) { - mPreloader.reset(new CellPreloader(rendering.getResourceSystem(), physics->getShapeManager())); + mPreloader.reset(new CellPreloader(rendering.getResourceSystem(), physics->getShapeManager(), rendering.getTerrain())); mPreloader->setWorkQueue(mRendering.getWorkQueue()); mPhysics->setUnrefQueue(rendering.getUnrefQueue()); @@ -549,7 +548,6 @@ namespace MWWorld MWBase::Environment::get().getWindowManager()->changeCell(mCurrentCell); mPreloader->updateCache(mRendering.getReferenceTime()); - mRendering.clearCache(); std::cout << "change to interior took " << timer.time_m() << std::endl; } diff --git a/components/resource/resourcemanager.cpp b/components/resource/resourcemanager.cpp index e5f6d9f43..0a9784e6b 100644 --- a/components/resource/resourcemanager.cpp +++ b/components/resource/resourcemanager.cpp @@ -19,11 +19,6 @@ namespace Resource mCache->removeExpiredObjectsInCache(referenceTime - mExpiryDelay); } - void ResourceManager::clearCache() - { - mCache->clear(); - } - void ResourceManager::setExpiryDelay(double expiryDelay) { mExpiryDelay = expiryDelay; diff --git a/components/resource/resourcemanager.hpp b/components/resource/resourcemanager.hpp index d2a1d1023..34fce0145 100644 --- a/components/resource/resourcemanager.hpp +++ b/components/resource/resourcemanager.hpp @@ -22,9 +22,6 @@ namespace Resource /// Clear cache entries that have not been referenced for longer than expiryDelay. virtual void updateCache(double referenceTime); - /// Clear all cache entries regardless of having external references. - virtual void clearCache(); - /// How long to keep objects in cache after no longer being referenced. void setExpiryDelay (double expiryDelay); diff --git a/components/terrain/buffercache.cpp b/components/terrain/buffercache.cpp index f9c860d47..2a72ea59b 100644 --- a/components/terrain/buffercache.cpp +++ b/components/terrain/buffercache.cpp @@ -2,6 +2,8 @@ #include +#include + #include #include "defs.hpp" @@ -178,6 +180,7 @@ namespace Terrain osg::ref_ptr BufferCache::getUVBuffer() { + OpenThreads::ScopedLock lock(mUvBufferMutex); if (mUvBufferMap.find(mNumVerts) != mUvBufferMap.end()) { return mUvBufferMap[mNumVerts]; @@ -206,6 +209,7 @@ namespace Terrain osg::ref_ptr BufferCache::getIndexBuffer(unsigned int flags) { + OpenThreads::ScopedLock lock(mIndexBufferMutex); unsigned int verts = mNumVerts; if (mIndexBufferMap.find(flags) != mIndexBufferMap.end()) diff --git a/components/terrain/buffercache.hpp b/components/terrain/buffercache.hpp index ca210f238..d1a57f811 100644 --- a/components/terrain/buffercache.hpp +++ b/components/terrain/buffercache.hpp @@ -17,8 +17,10 @@ namespace Terrain /// @param flags first 4*4 bits are LOD deltas on each edge, respectively (4 bits each) /// next 4 bits are LOD level of the index buffer (LOD 0 = don't omit any vertices) + /// @note Thread safe. osg::ref_ptr getIndexBuffer (unsigned int flags); + /// @note Thread safe. osg::ref_ptr getUVBuffer(); // TODO: add releaseGLObjects() for our vertex/element buffer objects @@ -27,8 +29,10 @@ namespace Terrain // Index buffers are shared across terrain batches where possible. There is one index buffer for each // combination of LOD deltas and index buffer LOD we may need. std::map > mIndexBufferMap; + OpenThreads::Mutex mIndexBufferMutex; std::map > mUvBufferMap; + OpenThreads::Mutex mUvBufferMutex; unsigned int mNumVerts; }; diff --git a/components/terrain/terraingrid.cpp b/components/terrain/terraingrid.cpp index 4d2f421e6..5b1854abc 100644 --- a/components/terrain/terraingrid.cpp +++ b/components/terrain/terraingrid.cpp @@ -2,6 +2,8 @@ #include +#include + #include #include #include @@ -50,9 +52,9 @@ namespace Terrain TerrainGrid::TerrainGrid(osg::Group* parent, Resource::ResourceSystem* resourceSystem, osgUtil::IncrementalCompileOperation* ico, Storage* storage, int nodeMask, SceneUtil::UnrefQueue* unrefQueue) : Terrain::World(parent, resourceSystem, ico, storage, nodeMask) , mNumSplits(4) + , mCache((storage->getCellVertices()-1)/static_cast(mNumSplits) + 1) , mUnrefQueue(unrefQueue) { - mCache = BufferCache((storage->getCellVertices()-1)/static_cast(mNumSplits) + 1); } TerrainGrid::~TerrainGrid() @@ -63,6 +65,21 @@ TerrainGrid::~TerrainGrid() } } +osg::ref_ptr TerrainGrid::cacheCell(int x, int y) +{ + { + OpenThreads::ScopedLock lock(mGridCacheMutex); + Grid::iterator found = mGridCache.find(std::make_pair(x,y)); + if (found != mGridCache.end()) + return found->second; + } + osg::ref_ptr node = buildTerrain(NULL, 1.f, osg::Vec2f(x+0.5, y+0.5)); + + OpenThreads::ScopedLock lock(mGridCacheMutex); + mGridCache.insert(std::make_pair(std::make_pair(x,y), node)); + return node; +} + osg::ref_ptr TerrainGrid::buildTerrain (osg::Group* parent, float chunkSize, const osg::Vec2f& chunkCenter) { if (chunkSize * mNumSplits > 1.f) @@ -131,19 +148,22 @@ osg::ref_ptr TerrainGrid::buildTerrain (osg::Group* parent, float chu unsigned int dummyTextureCounter = 0; std::vector > layerTextures; - for (std::vector::const_iterator it = layerList.begin(); it != layerList.end(); ++it) { - osg::ref_ptr texture = mTextureCache[it->mDiffuseMap]; - if (!texture) + OpenThreads::ScopedLock lock(mTextureCacheMutex); + for (std::vector::const_iterator it = layerList.begin(); it != layerList.end(); ++it) { - texture = new osg::Texture2D(mResourceSystem->getImageManager()->getImage(it->mDiffuseMap)); - texture->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT); - texture->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT); - mResourceSystem->getSceneManager()->applyFilterSettings(texture); - mTextureCache[it->mDiffuseMap] = texture; + osg::ref_ptr texture = mTextureCache[it->mDiffuseMap]; + if (!texture) + { + texture = new osg::Texture2D(mResourceSystem->getImageManager()->getImage(it->mDiffuseMap)); + texture->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT); + texture->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT); + mResourceSystem->getSceneManager()->applyFilterSettings(texture); + mTextureCache[it->mDiffuseMap] = texture; + } + layerTextures.push_back(texture); + textureCompileDummy->getOrCreateStateSet()->setTextureAttributeAndModes(dummyTextureCounter++, layerTextures.back()); } - layerTextures.push_back(texture); - textureCompileDummy->getOrCreateStateSet()->setTextureAttributeAndModes(dummyTextureCounter++, layerTextures.back()); } std::vector > blendmapTextures; @@ -196,11 +216,27 @@ void TerrainGrid::loadCell(int x, int y) if (mGrid.find(std::make_pair(x, y)) != mGrid.end()) return; // already loaded - osg::Vec2f center(x+0.5f, y+0.5f); + // try to get it from the cache + osg::ref_ptr terrainNode; + { + OpenThreads::ScopedLock lock(mGridCacheMutex); + Grid::const_iterator found = mGridCache.find(std::make_pair(x,y)); + if (found != mGridCache.end()) + { + terrainNode = found->second; + if (!terrainNode) + return; // no terrain defined + } + } - osg::ref_ptr terrainNode = buildTerrain(NULL, 1.f, center); + // didn't find in cache, build it if (!terrainNode) - return; // no terrain defined + { + osg::Vec2f center(x+0.5f, y+0.5f); + terrainNode = buildTerrain(NULL, 1.f, center); + if (!terrainNode) + return; // no terrain defined + } mTerrainRoot->addChild(terrainNode); @@ -213,7 +249,7 @@ void TerrainGrid::unloadCell(int x, int y) if (it == mGrid.end()) return; - osg::Node* terrainNode = it->second; + osg::ref_ptr terrainNode = it->second; mTerrainRoot->removeChild(terrainNode); if (mUnrefQueue.get()) @@ -222,18 +258,28 @@ void TerrainGrid::unloadCell(int x, int y) mGrid.erase(it); } -void TerrainGrid::clearCache() +void TerrainGrid::updateCache() { - for (TextureCache::iterator it = mTextureCache.begin(); it != mTextureCache.end();) { - if (it->second->referenceCount() <= 1) + OpenThreads::ScopedLock lock(mTextureCacheMutex); + for (TextureCache::iterator it = mTextureCache.begin(); it != mTextureCache.end();) + { + if (it->second->referenceCount() <= 1) + mTextureCache.erase(it++); + else + ++it; + } + } + + { + OpenThreads::ScopedLock lock(mGridCacheMutex); + for (Grid::iterator it = mGridCache.begin(); it != mGridCache.end();) { - if (mUnrefQueue.get()) - mUnrefQueue->push(it->second); - mTextureCache.erase(it++); + if (it->second->referenceCount() <= 1) + mGridCache.erase(it++); + else + ++it; } - else - ++it; } } diff --git a/components/terrain/terraingrid.hpp b/components/terrain/terraingrid.hpp index 4e6a78abd..46a95e817 100644 --- a/components/terrain/terraingrid.hpp +++ b/components/terrain/terraingrid.hpp @@ -21,11 +21,20 @@ namespace Terrain TerrainGrid(osg::Group* parent, Resource::ResourceSystem* resourceSystem, osgUtil::IncrementalCompileOperation* ico, Storage* storage, int nodeMask, SceneUtil::UnrefQueue* unrefQueue = NULL); ~TerrainGrid(); + /// Load a terrain cell and store it in cache for later use. + /// @note The returned ref_ptr should be kept by the caller to ensure that the terrain stays in cache for as long as needed. + /// @note Thread safe. + virtual osg::ref_ptr cacheCell(int x, int y); + + /// @note Not thread safe. virtual void loadCell(int x, int y); + + /// @note Not thread safe. virtual void unloadCell(int x, int y); - /// Clear cached textures that are no longer referenced - void clearCache(); + /// Clear cached objects that are no longer referenced + /// @note Thread safe. + void updateCache(); private: osg::ref_ptr buildTerrain (osg::Group* parent, float chunkSize, const osg::Vec2f& chunkCenter); @@ -35,10 +44,16 @@ namespace Terrain typedef std::map > TextureCache; TextureCache mTextureCache; + OpenThreads::Mutex mTextureCacheMutex; typedef std::map, osg::ref_ptr > Grid; Grid mGrid; + Grid mGridCache; + OpenThreads::Mutex mGridCacheMutex; + + BufferCache mCache; + osg::ref_ptr mUnrefQueue; }; diff --git a/components/terrain/world.cpp b/components/terrain/world.cpp index 2250b593d..b56e87e1d 100644 --- a/components/terrain/world.cpp +++ b/components/terrain/world.cpp @@ -11,7 +11,6 @@ namespace Terrain World::World(osg::Group* parent, Resource::ResourceSystem* resourceSystem, osgUtil::IncrementalCompileOperation* ico, Storage* storage, int nodeMask) : mStorage(storage) - , mCache(storage->getCellVertices()) , mParent(parent) , mResourceSystem(resourceSystem) , mIncrementalCompileOperation(ico) diff --git a/components/terrain/world.hpp b/components/terrain/world.hpp index bd5d0a466..992438a6a 100644 --- a/components/terrain/world.hpp +++ b/components/terrain/world.hpp @@ -39,10 +39,12 @@ namespace Terrain Storage* storage, int nodeMask); virtual ~World(); - virtual void clearCache() {} + virtual void updateCache() {} float getHeightAt (const osg::Vec3f& worldPos); + virtual osg::ref_ptr cacheCell(int x, int y) {return NULL;} + // This is only a hint and may be ignored by the implementation. virtual void loadCell(int x, int y) {} virtual void unloadCell(int x, int y) {} @@ -52,8 +54,6 @@ namespace Terrain protected: Storage* mStorage; - BufferCache mCache; - osg::ref_ptr mParent; osg::ref_ptr mTerrainRoot; From 9f729667fb064ab5d7380a103da5180a940279a6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 9 Feb 2016 21:06:02 +0100 Subject: [PATCH 3140/3725] Remove debug output --- apps/openmw/mwworld/cellpreloader.cpp | 11 ----------- apps/openmw/mwworld/scene.cpp | 7 ------- components/nifosg/controller.hpp | 1 - components/resource/scenemanager.cpp | 2 -- 4 files changed, 21 deletions(-) diff --git a/apps/openmw/mwworld/cellpreloader.cpp b/apps/openmw/mwworld/cellpreloader.cpp index e72c36c68..ce9a87beb 100644 --- a/apps/openmw/mwworld/cellpreloader.cpp +++ b/apps/openmw/mwworld/cellpreloader.cpp @@ -54,7 +54,6 @@ namespace MWWorld , mKeyframeManager(keyframeManager) , mTerrain(terrain) { - osg::Timer timer; ListModelsVisitor visitor (mMeshes); if (cell->getState() == MWWorld::CellStore::State_Loaded) { @@ -73,15 +72,11 @@ namespace MWWorld mMeshes.push_back(model); } } - std::cout << "listed models in " << timer.time_m() << std::endl; } /// Preload work to be called from the worker thread. virtual void doWork() { - // TODO: make CellStore::loadRefs thread safe so we can call it from here - - osg::Timer preloadTimer; for (MeshList::const_iterator it = mMeshes.begin(); it != mMeshes.end(); ++it) { try @@ -89,8 +84,6 @@ namespace MWWorld std::string mesh = *it; mesh = Misc::ResourceHelpers::correctActorModelPath(mesh, mSceneManager->getVFS()); - //std::cout << "preloading " << mesh << std::endl; - mPreloadedObjects.push_back(mSceneManager->cacheInstance(mesh)); mPreloadedObjects.push_back(mBulletShapeManager->cacheInstance(mesh)); @@ -127,8 +120,6 @@ namespace MWWorld { } } - - std::cout << "preloaded " << mPreloadedObjects.size() << " objects in " << preloadTimer.time_m() << std::endl; } private: @@ -159,11 +150,9 @@ namespace MWWorld virtual void doWork() { - osg::Timer timer; mResourceSystem->updateCache(mReferenceTime); mTerrain->updateCache(); - std::cout << "cleared cache in " << timer.time_m() << std::endl; } private: diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 0be26c7b6..308809bd2 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -2,7 +2,6 @@ #include #include -#include #include #include @@ -332,7 +331,6 @@ namespace MWWorld void Scene::changeCellGrid (int X, int Y) { - osg::Timer timer; Loading::Listener* loadingListener = MWBase::Environment::get().getWindowManager()->getLoadingScreen(); Loading::ScopedLoad load(loadingListener); @@ -416,8 +414,6 @@ namespace MWWorld mCellChanged = true; mPreloader->updateCache(mRendering.getReferenceTime()); - - std::cout << "changeCellGrid took " << timer.time_m() << std::endl; } void Scene::changePlayerCell(CellStore *cell, const ESM::Position &pos, bool adjustPlayerPos) @@ -488,7 +484,6 @@ namespace MWWorld void Scene::changeToInteriorCell (const std::string& cellName, const ESM::Position& position) { - osg::Timer timer; CellStore *cell = MWBase::Environment::get().getWorld()->getInterior(cellName); bool loadcell = (mCurrentCell == NULL); if(!loadcell) @@ -548,8 +543,6 @@ namespace MWWorld MWBase::Environment::get().getWindowManager()->changeCell(mCurrentCell); mPreloader->updateCache(mRendering.getReferenceTime()); - - std::cout << "change to interior took " << timer.time_m() << std::endl; } void Scene::changeToExteriorCell (const ESM::Position& position, bool adjustPlayerPos) diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index 0b633a122..ce268f587 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -17,7 +17,6 @@ #include #include -#include #include #include #include diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index 5acd5f8fb..29f7076f0 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -366,8 +366,6 @@ namespace Resource if (mIncrementalCompileOperation) mIncrementalCompileOperation->add(loaded); - //std::cout << "loading " << normalized << std::endl; - mCache->addEntryToObjectCache(normalized, loaded); return loaded; } From 98c5e072f29990d8de48533ebed6f684dce7f5cc Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 9 Feb 2016 21:17:10 +0100 Subject: [PATCH 3141/3725] Swap the terrain cache update order to make more sense --- components/terrain/terraingrid.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/components/terrain/terraingrid.cpp b/components/terrain/terraingrid.cpp index 5b1854abc..f40f3a388 100644 --- a/components/terrain/terraingrid.cpp +++ b/components/terrain/terraingrid.cpp @@ -261,22 +261,22 @@ void TerrainGrid::unloadCell(int x, int y) void TerrainGrid::updateCache() { { - OpenThreads::ScopedLock lock(mTextureCacheMutex); - for (TextureCache::iterator it = mTextureCache.begin(); it != mTextureCache.end();) + OpenThreads::ScopedLock lock(mGridCacheMutex); + for (Grid::iterator it = mGridCache.begin(); it != mGridCache.end();) { if (it->second->referenceCount() <= 1) - mTextureCache.erase(it++); + mGridCache.erase(it++); else ++it; } } { - OpenThreads::ScopedLock lock(mGridCacheMutex); - for (Grid::iterator it = mGridCache.begin(); it != mGridCache.end();) + OpenThreads::ScopedLock lock(mTextureCacheMutex); + for (TextureCache::iterator it = mTextureCache.begin(); it != mTextureCache.end();) { if (it->second->referenceCount() <= 1) - mGridCache.erase(it++); + mTextureCache.erase(it++); else ++it; } From 61b6806a62baa89db93f5270e5f7907ffbb73764 Mon Sep 17 00:00:00 2001 From: Rob Cutmore Date: Tue, 9 Feb 2016 20:23:00 -0500 Subject: [PATCH 3142/3725] Allow toggling of cell markers --- apps/opencs/view/render/cellmarker.cpp | 14 ++++++++++++++ apps/opencs/view/render/cellmarker.hpp | 17 +++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/apps/opencs/view/render/cellmarker.cpp b/apps/opencs/view/render/cellmarker.cpp index 17bb05440..e8772a586 100644 --- a/apps/opencs/view/render/cellmarker.cpp +++ b/apps/opencs/view/render/cellmarker.cpp @@ -7,6 +7,17 @@ #include #include +#include "mask.hpp" + +CSVRender::CellMarkerTag::CellMarkerTag(CellMarker *marker) +: TagBase(Mask_CellMarker), mMarker(marker) +{} + +CSVRender::CellMarker *CSVRender::CellMarkerTag::getCellMarker() const +{ + return mMarker; +} + void CSVRender::CellMarker::buildMarker() { const int characterSize = 20; @@ -50,6 +61,9 @@ CSVRender::CellMarker::CellMarker( mMarkerNode->setAutoScaleToScreen(true); mMarkerNode->getOrCreateStateSet()->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF); + mMarkerNode->setUserData(new CellMarkerTag(this)); + mMarkerNode->setNodeMask(Mask_CellMarker); + mCellNode->addChild(mMarkerNode); buildMarker(); diff --git a/apps/opencs/view/render/cellmarker.hpp b/apps/opencs/view/render/cellmarker.hpp index 4ac9d86b0..08c7e0608 100644 --- a/apps/opencs/view/render/cellmarker.hpp +++ b/apps/opencs/view/render/cellmarker.hpp @@ -1,6 +1,8 @@ #ifndef OPENCS_VIEW_CELLMARKER_H #define OPENCS_VIEW_CELLMARKER_H +#include "tagbase.hpp" + #include #include "../../model/world/cellcoordinates.hpp" @@ -13,6 +15,21 @@ namespace osg namespace CSVRender { + class CellMarker; + + class CellMarkerTag : public TagBase + { + private: + + CellMarker *mMarker; + + public: + + CellMarkerTag(CellMarker *marker); + + CellMarker *getCellMarker() const; + }; + /// \brief Marker to display cell coordinates. class CellMarker { From 5e876b1379545964c59ea4c6a7bc27b4e320968f Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 10 Feb 2016 15:34:06 +0100 Subject: [PATCH 3143/3725] Add missing include --- apps/openmw/mwrender/water.cpp | 1 + components/terrain/terraingrid.cpp | 2 ++ 2 files changed, 3 insertions(+) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index a8d601f11..dba85aeb7 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include diff --git a/components/terrain/terraingrid.cpp b/components/terrain/terraingrid.cpp index f40f3a388..4f0e464ce 100644 --- a/components/terrain/terraingrid.cpp +++ b/components/terrain/terraingrid.cpp @@ -2,6 +2,8 @@ #include +#include + #include #include From fb219fea17533812d416e9617bdda2c66b4fbf4d Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 7 Feb 2016 19:43:38 +0100 Subject: [PATCH 3144/3725] Fix respawning of NPCs/creatures when they were moved to a different cell --- apps/openmw/mwclass/creature.cpp | 10 +++++----- apps/openmw/mwclass/npc.cpp | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 6e9cfccb9..0f021b5a2 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -772,18 +772,18 @@ namespace MWClass { if (isFlagBitSet(ptr, ESM::Creature::Respawn)) { - // Note we do not respawn moved references in the cell they were moved to. Instead they are respawned in the original cell. - // This also means we cannot respawn dynamically placed references with no content file connection. if (ptr.getCellRef().hasContentFile()) { if (ptr.getRefData().getCount() == 0) ptr.getRefData().setCount(1); - // Reset to original position - ptr.getRefData().setPosition(ptr.getCellRef().getPosition()); - MWBase::Environment::get().getWorld()->removeContainerScripts(ptr); ptr.getRefData().setCustomData(NULL); + + // Reset to original position + MWBase::Environment::get().getWorld()->moveObject(ptr, ptr.getCellRef().getPosition().pos[0], + ptr.getCellRef().getPosition().pos[1], + ptr.getCellRef().getPosition().pos[2]); } } } diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 3519f9d83..474985f7b 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -1305,18 +1305,18 @@ namespace MWClass { if (ptr.get()->mBase->mFlags & ESM::NPC::Respawn) { - // Note we do not respawn moved references in the cell they were moved to. Instead they are respawned in the original cell. - // This also means we cannot respawn dynamically placed references with no content file connection. if (ptr.getCellRef().hasContentFile()) { if (ptr.getRefData().getCount() == 0) ptr.getRefData().setCount(1); - // Reset to original position - ptr.getRefData().setPosition(ptr.getCellRef().getPosition()); - MWBase::Environment::get().getWorld()->removeContainerScripts(ptr); ptr.getRefData().setCustomData(NULL); + + // Reset to original position + MWBase::Environment::get().getWorld()->moveObject(ptr, ptr.getCellRef().getPosition().pos[0], + ptr.getCellRef().getPosition().pos[1], + ptr.getCellRef().getPosition().pos[2]); } } } From d3808580b032eb75232aaae02c121bb711e19e28 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 8 Feb 2016 16:45:56 +0100 Subject: [PATCH 3145/3725] Rename lightRoot to sceneRoot --- apps/openmw/mwrender/renderingmanager.cpp | 40 +++++++++++------------ apps/openmw/mwrender/renderingmanager.hpp | 2 +- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 177cee4ea..29b641f6b 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -169,26 +169,26 @@ namespace MWRender { resourceSystem->getSceneManager()->setParticleSystemMask(MWRender::Mask_ParticleSystem); - osg::ref_ptr lightRoot = new SceneUtil::LightManager; - lightRoot->setLightingMask(Mask_Lighting); - mLightRoot = lightRoot; - lightRoot->setStartLight(1); + osg::ref_ptr sceneRoot = new SceneUtil::LightManager; + sceneRoot->setLightingMask(Mask_Lighting); + mSceneRoot = sceneRoot; + sceneRoot->setStartLight(1); - mRootNode->addChild(lightRoot); + mRootNode->addChild(sceneRoot); mPathgrid.reset(new Pathgrid(mRootNode)); - mObjects.reset(new Objects(mResourceSystem, lightRoot, mUnrefQueue.get())); + mObjects.reset(new Objects(mResourceSystem, sceneRoot, mUnrefQueue.get())); mViewer->setIncrementalCompileOperation(new osgUtil::IncrementalCompileOperation); mResourceSystem->getSceneManager()->setIncrementalCompileOperation(mViewer->getIncrementalCompileOperation()); - mEffectManager.reset(new EffectManager(lightRoot, mResourceSystem)); + mEffectManager.reset(new EffectManager(sceneRoot, mResourceSystem)); - mWater.reset(new Water(mRootNode, lightRoot, mResourceSystem, mViewer->getIncrementalCompileOperation(), fallback, resourcePath)); + mWater.reset(new Water(mRootNode, sceneRoot, mResourceSystem, mViewer->getIncrementalCompileOperation(), fallback, resourcePath)); - mTerrain.reset(new Terrain::TerrainGrid(lightRoot, mResourceSystem, mViewer->getIncrementalCompileOperation(), + mTerrain.reset(new Terrain::TerrainGrid(sceneRoot, mResourceSystem, mViewer->getIncrementalCompileOperation(), new TerrainStorage(mResourceSystem->getVFS(), false), Mask_Terrain, mUnrefQueue.get())); mCamera.reset(new Camera(mViewer->getCamera())); @@ -203,21 +203,21 @@ namespace MWRender mSunLight->setAmbient(osg::Vec4f(0,0,0,1)); mSunLight->setSpecular(osg::Vec4f(0,0,0,0)); mSunLight->setConstantAttenuation(1.f); - lightRoot->addChild(source); + sceneRoot->addChild(source); - lightRoot->getOrCreateStateSet()->setMode(GL_CULL_FACE, osg::StateAttribute::ON); - lightRoot->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::ON); - lightRoot->getOrCreateStateSet()->setMode(GL_NORMALIZE, osg::StateAttribute::ON); + sceneRoot->getOrCreateStateSet()->setMode(GL_CULL_FACE, osg::StateAttribute::ON); + sceneRoot->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::ON); + sceneRoot->getOrCreateStateSet()->setMode(GL_NORMALIZE, osg::StateAttribute::ON); - lightRoot->setNodeMask(Mask_Scene); - lightRoot->setName("Scene Root"); + sceneRoot->setNodeMask(Mask_Scene); + sceneRoot->setName("Scene Root"); - mSky.reset(new SkyManager(lightRoot, resourceSystem->getSceneManager())); + mSky.reset(new SkyManager(sceneRoot, resourceSystem->getSceneManager())); source->setStateSetModes(*mRootNode->getOrCreateStateSet(), osg::StateAttribute::ON); mStateUpdater = new StateUpdater; - lightRoot->addUpdateCallback(mStateUpdater); + sceneRoot->addUpdateCallback(mStateUpdater); osg::Camera::CullingMode cullingMode = osg::Camera::DEFAULT_CULLING|osg::Camera::FAR_PLANE_CULLING; @@ -291,7 +291,7 @@ namespace MWRender osg::Group* RenderingManager::getLightRoot() { - return mLightRoot.get(); + return mSceneRoot.get(); } void RenderingManager::setNightEyeFactor(float factor) @@ -589,7 +589,7 @@ namespace MWRender image->setPixelFormat(texture->getInternalFormat()); rttCamera->setUpdateCallback(new NoTraverseCallback); - rttCamera->addChild(mLightRoot); + rttCamera->addChild(mSceneRoot); rttCamera->setCullMask(mViewer->getCamera()->getCullMask() & (~Mask_GUI)); mRootNode->addChild(rttCamera); @@ -772,7 +772,7 @@ namespace MWRender { mPlayerNode = new SceneUtil::PositionAttitudeTransform; mPlayerNode->setNodeMask(Mask_Player); - mLightRoot->addChild(mPlayerNode); + mSceneRoot->addChild(mPlayerNode); } mPlayerNode->setUserDataContainer(new osg::DefaultUserDataContainer); diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 4dda6f273..59692f45a 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -197,7 +197,7 @@ namespace MWRender osg::ref_ptr mViewer; osg::ref_ptr mRootNode; - osg::ref_ptr mLightRoot; + osg::ref_ptr mSceneRoot; Resource::ResourceSystem* mResourceSystem; osg::ref_ptr mWorkQueue; From 6bfeb118d7ecae3bc528ff558656c42caaa8c6ec Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 10 Feb 2016 19:08:17 +0100 Subject: [PATCH 3146/3725] Fix cleanup issue --- apps/openmw/mwworld/cellpreloader.cpp | 7 +++++++ apps/openmw/mwworld/cellpreloader.hpp | 1 + 2 files changed, 8 insertions(+) diff --git a/apps/openmw/mwworld/cellpreloader.cpp b/apps/openmw/mwworld/cellpreloader.cpp index ce9a87beb..6acb41dc3 100644 --- a/apps/openmw/mwworld/cellpreloader.cpp +++ b/apps/openmw/mwworld/cellpreloader.cpp @@ -169,6 +169,13 @@ namespace MWWorld { } + CellPreloader::~CellPreloader() + { + for (PreloadMap::iterator it = mPreloadCells.begin(); it != mPreloadCells.end();++it) + it->second.mWorkItem->waitTillDone(); + mPreloadCells.clear(); + } + void CellPreloader::preload(CellStore *cell, double timestamp) { if (!mWorkQueue) diff --git a/apps/openmw/mwworld/cellpreloader.hpp b/apps/openmw/mwworld/cellpreloader.hpp index 32ea194c6..437395397 100644 --- a/apps/openmw/mwworld/cellpreloader.hpp +++ b/apps/openmw/mwworld/cellpreloader.hpp @@ -24,6 +24,7 @@ namespace MWWorld { public: CellPreloader(Resource::ResourceSystem* resourceSystem, Resource::BulletShapeManager* bulletShapeManager, Terrain::World* terrain); + ~CellPreloader(); /// Ask a background thread to preload rendering meshes and collision shapes for objects in this cell. /// @note The cell itself must be in State_Loaded or State_Preloaded. From be6ea3d607724e89e917cc3d448333e9b2d688dd Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 11 Feb 2016 16:22:54 +0100 Subject: [PATCH 3147/3725] Account for UV coordinate flip in UVController (Fixes #3203) --- components/nifosg/controller.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index d0abc9ead..aabe07c86 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -254,9 +254,15 @@ void UVController::apply(osg::StateSet* stateset, osg::NodeVisitor* nv) float uScale = mUScale.interpKey(value); float vScale = mVScale.interpKey(value); + osg::Matrix flipMat; + flipMat.preMultTranslate(osg::Vec3f(0,1,0)); + flipMat.preMultScale(osg::Vec3f(1,-1,1)); + osg::Matrixf mat = osg::Matrixf::scale(uScale, vScale, 1); mat.setTrans(uTrans, vTrans, 0); + mat = flipMat * mat * flipMat; + // setting once is enough because all other texture units share the same TexMat (see setDefaults). if (!mTextureUnits.empty()) { From 48ac0bef3ed17024957e4715b3d85396be30665f Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 11 Feb 2016 16:34:02 +0100 Subject: [PATCH 3148/3725] Repair save games affected by bug #3080 (Fixes #3160) --- apps/openmw/mwmechanics/aisequence.cpp | 46 ++++++++++++++------------ 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/apps/openmw/mwmechanics/aisequence.cpp b/apps/openmw/mwmechanics/aisequence.cpp index 04ac96b11..71733d613 100644 --- a/apps/openmw/mwmechanics/aisequence.cpp +++ b/apps/openmw/mwmechanics/aisequence.cpp @@ -351,60 +351,64 @@ void AiSequence::readState(const ESM::AiSequence::AiSequence &sequence) for (std::vector::const_iterator it = sequence.mPackages.begin(); it != sequence.mPackages.end(); ++it) { + MWMechanics::AiPackage* package = NULL; switch (it->mType) { case ESM::AiSequence::Ai_Wander: { - MWMechanics::AiWander* wander = new AiWander( - static_cast(it->mPackage)); - mPackages.push_back(wander); + package = new AiWander(static_cast(it->mPackage)); break; } case ESM::AiSequence::Ai_Travel: { - MWMechanics::AiTravel* travel = new AiTravel( - static_cast(it->mPackage)); - mPackages.push_back(travel); + package = new AiTravel(static_cast(it->mPackage)); break; } case ESM::AiSequence::Ai_Escort: { - MWMechanics::AiEscort* escort = new AiEscort( - static_cast(it->mPackage)); - mPackages.push_back(escort); + package = new AiEscort(static_cast(it->mPackage)); break; } case ESM::AiSequence::Ai_Follow: { - MWMechanics::AiFollow* follow = new AiFollow( - static_cast(it->mPackage)); - mPackages.push_back(follow); + package = new AiFollow(static_cast(it->mPackage)); break; } case ESM::AiSequence::Ai_Activate: { - MWMechanics::AiActivate* activate = new AiActivate( - static_cast(it->mPackage)); - mPackages.push_back(activate); + package = new AiActivate(static_cast(it->mPackage)); break; } case ESM::AiSequence::Ai_Combat: { - MWMechanics::AiCombat* combat = new AiCombat( - static_cast(it->mPackage)); - mPackages.push_back(combat); + package = new AiCombat(static_cast(it->mPackage)); break; } case ESM::AiSequence::Ai_Pursue: { - MWMechanics::AiPursue* pursue = new AiPursue( - static_cast(it->mPackage)); - mPackages.push_back(pursue); + package = new AiPursue(static_cast(it->mPackage)); break; } default: break; } + + if (!package) + continue; + + // remove previous packages if required + if (package->shouldCancelPreviousAi()) + { + for(std::list::iterator it = mPackages.begin(); it != mPackages.end();) + { + if((*it)->canCancel()) + it = mPackages.erase(it); + else + ++it; + } + } + + mPackages.push_back(package); } } From 8b596dfcbe8a142a77b0af54f257343c16469cc2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 12 Feb 2016 14:46:45 +0100 Subject: [PATCH 3149/3725] Remove support for OSG 3.2 Since commit e8662bea3133ba9dbb09b86c3abb1af39425e90d, we're using OSG functionality that contains an unfixed crash bug in version 3.2. The bug is fixed in version 3.4 (OSG commit 6351e5020371b0b72b300088a5c6772f58379b84) --- CMakeLists.txt | 2 +- apps/openmw/mwrender/animation.cpp | 14 ----------- apps/openmw/mwrender/objects.cpp | 15 ----------- apps/openmw/mwrender/sky.cpp | 4 --- components/nifosg/nifloader.cpp | 32 ------------------------ components/resource/imagemanager.cpp | 7 ------ components/resource/scenemanager.cpp | 17 ------------- components/sceneutil/clone.cpp | 5 ---- components/sceneutil/controller.cpp | 8 ------ components/sceneutil/riggeometry.cpp | 2 -- components/sdlutil/sdlgraphicswindow.cpp | 8 ------ components/terrain/terraingrid.cpp | 6 ----- 12 files changed, 1 insertion(+), 119 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 52970cfb5..df2ee6f49 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -233,7 +233,7 @@ if (USE_QT) set (OSG_QT osgQt) endif() -find_package(OpenSceneGraph 3.2.0 REQUIRED osgDB osgViewer osgText osgGA osgAnimation osgParticle ${OSG_QT} osgUtil osgFX) +find_package(OpenSceneGraph 3.4.0 REQUIRED osgDB osgViewer osgText osgGA osgAnimation osgParticle ${OSG_QT} osgUtil osgFX) include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS}) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 398fe5322..e3cc57bc4 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -201,17 +201,10 @@ namespace class RemoveDrawableVisitor : public RemoveVisitor { public: - virtual void apply(osg::Geode &geode) - { - applyImpl(geode); - } - -#if OSG_VERSION_GREATER_OR_EQUAL(3,3,3) virtual void apply(osg::Drawable& drw) { applyImpl(drw); } -#endif void applyImpl(osg::Node& node) { @@ -239,17 +232,10 @@ namespace class RemoveTriBipVisitor : public RemoveVisitor { public: - virtual void apply(osg::Geode &node) - { - applyImpl(node); - } - -#if OSG_VERSION_GREATER_OR_EQUAL(3,3,3) virtual void apply(osg::Drawable& drw) { applyImpl(drw); } -#endif void applyImpl(osg::Node& node) { diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 516d10b95..d249a7602 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -43,26 +43,11 @@ namespace traverse(node); } - virtual void apply(osg::Geode& geode) - { - std::vector partsysVector; - for (unsigned int i=0; i(drw)) - partsysVector.push_back(partsys); - } - - for (std::vector::iterator it = partsysVector.begin(); it != partsysVector.end(); ++it) - geode.removeDrawable(*it); - } -#if OSG_VERSION_GREATER_OR_EQUAL(3,3,3) virtual void apply(osg::Drawable& drw) { if (osgParticle::ParticleSystem* partsys = dynamic_cast(&drw)) mToRemove.push_back(partsys); } -#endif void remove() { diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 40283ba27..1757314fe 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1282,11 +1282,7 @@ public: if (stateset->getAttribute(osg::StateAttribute::MATERIAL)) { SceneUtil::CompositeStateSetUpdater* composite = NULL; -#if OSG_VERSION_GREATER_OR_EQUAL(3,3,3) osg::Callback* callback = node.getUpdateCallback(); -#else - osg::NodeCallback* callback = node.getUpdateCallback(); -#endif while (callback) { if ((composite = dynamic_cast(callback))) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 6c6061063..61fbc9b96 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -934,13 +934,7 @@ namespace NifOsg updater->addParticleSystem(partsys); parentNode->addChild(updater); -#if OSG_VERSION_LESS_THAN(3,3,3) - osg::ref_ptr geode (new osg::Geode); - geode->addDrawable(partsys); - osg::Node* toAttach = geode.get(); -#else osg::Node* toAttach = partsys.get(); -#endif if (rf == osgParticle::ParticleProcessor::RELATIVE_RF) parentNode->addChild(toAttach); @@ -1017,11 +1011,6 @@ namespace NifOsg triShapeToGeometry(triShape, geometry, parentNode, composite, boundTextures, animflags); } -#if OSG_VERSION_LESS_THAN(3,3,3) - osg::ref_ptr geode (new osg::Geode); - geode->addDrawable(geometry); -#endif - if (geometry->getDataVariance() == osg::Object::DYNAMIC) { // Add a copy, we will alternate between the two copies every other frame using the FrameSwitch @@ -1029,24 +1018,14 @@ namespace NifOsg geometry->setDataVariance(osg::Object::STATIC); osg::ref_ptr frameswitch = new FrameSwitch; -#if OSG_VERSION_LESS_THAN(3,3,3) - osg::ref_ptr geode2 = static_cast(osg::clone(geode.get(), osg::CopyOp::DEEP_COPY_NODES|osg::CopyOp::DEEP_COPY_DRAWABLES)); - frameswitch->addChild(geode); - frameswitch->addChild(geode2); -#else osg::ref_ptr geom2 = static_cast(osg::clone(geometry.get(), osg::CopyOp::DEEP_COPY_NODES|osg::CopyOp::DEEP_COPY_DRAWABLES)); frameswitch->addChild(geometry); frameswitch->addChild(geom2); -#endif parentNode->addChild(frameswitch); } else -#if OSG_VERSION_LESS_THAN(3,3,3) - parentNode->addChild(geode); -#else parentNode->addChild(geometry); -#endif } osg::ref_ptr handleMorphGeometry(const Nif::NiGeomMorpherController* morpher, const Nif::NiTriShape *triShape, osg::Node* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::vector& boundTextures, int animflags) @@ -1151,21 +1130,10 @@ namespace NifOsg osg::ref_ptr frameswitch = new FrameSwitch; -#if OSG_VERSION_LESS_THAN(3,3,3) - osg::ref_ptr geode (new osg::Geode); - geode->addDrawable(rig); - - osg::Geode* geode2 = static_cast(osg::clone(geode.get(), osg::CopyOp::DEEP_COPY_NODES| - osg::CopyOp::DEEP_COPY_DRAWABLES)); - - frameswitch->addChild(geode); - frameswitch->addChild(geode2); -#else SceneUtil::RigGeometry* rig2 = static_cast(osg::clone(rig.get(), osg::CopyOp::DEEP_COPY_NODES| osg::CopyOp::DEEP_COPY_DRAWABLES)); frameswitch->addChild(rig); frameswitch->addChild(rig2); -#endif parentNode->addChild(frameswitch); } diff --git a/components/resource/imagemanager.cpp b/components/resource/imagemanager.cpp index 79da7d7ab..a4278eb0f 100644 --- a/components/resource/imagemanager.cpp +++ b/components/resource/imagemanager.cpp @@ -62,17 +62,10 @@ namespace Resource case(GL_COMPRESSED_RGBA_S3TC_DXT3_EXT): case(GL_COMPRESSED_RGBA_S3TC_DXT5_EXT): { -#if OSG_VERSION_GREATER_OR_EQUAL(3,3,3) osg::GLExtensions* exts = osg::GLExtensions::Get(0, false); if (exts && !exts->isTextureCompressionS3TCSupported // This one works too. Should it be included in isTextureCompressionS3TCSupported()? Submitted as a patch to OSG. && !osg::isGLExtensionSupported(0, "GL_S3_s3tc")) -#else - osg::Texture::Extensions* exts = osg::Texture::getExtensions(0, false); - if (exts && !exts->isTextureCompressionS3TCSupported() - // This one works too. Should it be included in isTextureCompressionS3TCSupported()? Submitted as a patch to OSG. - && !osg::isGLExtensionSupported(0, "GL_S3_s3tc")) -#endif { std::cerr << "Error loading " << filename << ": no S3TC texture compression support installed" << std::endl; return false; diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index 29f7076f0..52db2decc 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -52,23 +52,6 @@ namespace && partsys->getUserDataContainer()->getDescriptions()[0] == "worldspace"); } - void apply(osg::Geode& geode) - { - for (unsigned int i=0;i(geode.getDrawable(i))) - { - if (isWorldSpaceParticleSystem(partsys)) - { - // HACK: Ignore the InverseWorldMatrix transform the geode is attached to - if (geode.getNumParents() && geode.getParent(0)->getNumParents()) - transformInitialParticles(partsys, geode.getParent(0)->getParent(0)); - } - geode.setNodeMask(mMask); - } - } - } - #if OSG_VERSION_GREATER_OR_EQUAL(3,3,3) // in OSG 3.3 and up Drawables can be directly in the scene graph without a Geode decorating them. void apply(osg::Drawable& drw) diff --git a/components/sceneutil/clone.cpp b/components/sceneutil/clone.cpp index 784195e7e..26f3f5c7c 100644 --- a/components/sceneutil/clone.cpp +++ b/components/sceneutil/clone.cpp @@ -81,11 +81,6 @@ namespace SceneUtil #endif osg::Drawable* cloned = osg::clone(drawable, copyop); -#if OSG_VERSION_LESS_THAN(3,3,3) - // work around OSG 3.2 not respecting the DEEP_COPY_CALLBACK flag - if (cloned->getUpdateCallback()) - cloned->setUpdateCallback(osg::clone(cloned->getUpdateCallback(), *this)); -#endif return cloned; } if (dynamic_cast(drawable)) diff --git a/components/sceneutil/controller.cpp b/components/sceneutil/controller.cpp index 7762b48d0..916d4f80b 100644 --- a/components/sceneutil/controller.cpp +++ b/components/sceneutil/controller.cpp @@ -65,11 +65,7 @@ namespace SceneUtil void ControllerVisitor::apply(osg::Node &node) { -#if OSG_VERSION_GREATER_OR_EQUAL(3,3,3) osg::Callback* callback = node.getUpdateCallback(); -#else - osg::NodeCallback* callback = node.getUpdateCallback(); -#endif while (callback) { if (Controller* ctrl = dynamic_cast(callback)) @@ -96,11 +92,7 @@ namespace SceneUtil { osg::Drawable* drw = geode.getDrawable(i); -#if OSG_VERSION_GREATER_OR_EQUAL(3,3,3) osg::Callback* callback = drw->getUpdateCallback(); -#else - osg::Drawable::UpdateCallback* callback = drw->getUpdateCallback(); -#endif if (Controller* ctrl = dynamic_cast(callback)) visit(geode, *ctrl); diff --git a/components/sceneutil/riggeometry.cpp b/components/sceneutil/riggeometry.cpp index be8d97a4c..da7d42431 100644 --- a/components/sceneutil/riggeometry.cpp +++ b/components/sceneutil/riggeometry.cpp @@ -289,11 +289,9 @@ void RigGeometry::updateBounds(osg::NodeVisitor *nv) _boundingBox = box; _boundingBoxComputed = true; -#if OSG_VERSION_GREATER_OR_EQUAL(3,3,3) // in OSG 3.3.3 and up Drawable inherits from Node, so has a bounding sphere as well. _boundingSphere = osg::BoundingSphere(_boundingBox); _boundingSphereComputed = true; -#endif for (unsigned int i=0; idirtyBound(); } diff --git a/components/sdlutil/sdlgraphicswindow.cpp b/components/sdlutil/sdlgraphicswindow.cpp index a0483e84d..e5bad1f00 100644 --- a/components/sdlutil/sdlgraphicswindow.cpp +++ b/components/sdlutil/sdlgraphicswindow.cpp @@ -112,11 +112,7 @@ void GraphicsWindowSDL2::init() mValid = true; -#if OSG_VERSION_GREATER_OR_EQUAL(3,3,4) getEventQueue()->syncWindowRectangleWithGraphicsContext(); -#else - getEventQueue()->syncWindowRectangleWithGraphcisContext(); -#endif } @@ -133,11 +129,7 @@ bool GraphicsWindowSDL2::realizeImplementation() SDL_ShowWindow(mWindow); -#if OSG_VERSION_GREATER_OR_EQUAL(3,3,4) getEventQueue()->syncWindowRectangleWithGraphicsContext(); -#else - getEventQueue()->syncWindowRectangleWithGraphcisContext(); -#endif mRealized = true; diff --git a/components/terrain/terraingrid.cpp b/components/terrain/terraingrid.cpp index 4f0e464ce..96584172a 100644 --- a/components/terrain/terraingrid.cpp +++ b/components/terrain/terraingrid.cpp @@ -193,13 +193,7 @@ osg::ref_ptr TerrainGrid::buildTerrain (osg::Group* parent, float chu transform->addChild(effect); -#if OSG_VERSION_GREATER_OR_EQUAL(3,3,3) osg::Node* toAttach = geometry.get(); -#else - osg::ref_ptr geode (new osg::Geode); - geode->addDrawable(geometry); - osg::Node* toAttach = geode.get(); -#endif effect->addChild(toAttach); From f94722b271c83ffbbe55a46eff19619f0083d87c Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 12 Feb 2016 14:55:00 +0100 Subject: [PATCH 3150/3725] OSG 3.3.4 is the first release to include the DDS crash fix --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index df2ee6f49..520279e50 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -233,7 +233,7 @@ if (USE_QT) set (OSG_QT osgQt) endif() -find_package(OpenSceneGraph 3.4.0 REQUIRED osgDB osgViewer osgText osgGA osgAnimation osgParticle ${OSG_QT} osgUtil osgFX) +find_package(OpenSceneGraph 3.3.4 REQUIRED osgDB osgViewer osgText osgGA osgAnimation osgParticle ${OSG_QT} osgUtil osgFX) include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS}) From 5824619a95f5ad16dae84de41ab9a635bb16f56b Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 12 Feb 2016 19:28:10 +0100 Subject: [PATCH 3151/3725] Clean up includes --- apps/openmw/mwrender/animation.cpp | 1 - apps/openmw/mwrender/objects.cpp | 1 - apps/openmw/mwrender/sky.cpp | 1 - components/nifosg/nifloader.cpp | 1 - components/resource/imagemanager.cpp | 1 - components/resource/scenemanager.cpp | 3 --- components/sceneutil/controller.cpp | 1 - components/sceneutil/riggeometry.cpp | 1 - components/sdlutil/sdlgraphicswindow.cpp | 2 -- components/terrain/terraingrid.cpp | 1 - 10 files changed, 13 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index e3cc57bc4..abca3b266 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -10,7 +10,6 @@ #include #include #include -#include #include diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index d249a7602..a13ee03ac 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -5,7 +5,6 @@ #include #include #include -#include #include #include diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 1757314fe..f10beca6c 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 61fbc9b96..8f4076884 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -5,7 +5,6 @@ #include #include #include -#include #include // resource diff --git a/components/resource/imagemanager.cpp b/components/resource/imagemanager.cpp index a4278eb0f..870fa370b 100644 --- a/components/resource/imagemanager.cpp +++ b/components/resource/imagemanager.cpp @@ -2,7 +2,6 @@ #include #include -#include #include diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index 52db2decc..85a4afa30 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -4,7 +4,6 @@ #include #include #include -#include #include #include @@ -52,7 +51,6 @@ namespace && partsys->getUserDataContainer()->getDescriptions()[0] == "worldspace"); } -#if OSG_VERSION_GREATER_OR_EQUAL(3,3,3) // in OSG 3.3 and up Drawables can be directly in the scene graph without a Geode decorating them. void apply(osg::Drawable& drw) { @@ -67,7 +65,6 @@ namespace partsys->setNodeMask(mMask); } } -#endif void transformInitialParticles(osgParticle::ParticleSystem* partsys, osg::Node* node) { diff --git a/components/sceneutil/controller.cpp b/components/sceneutil/controller.cpp index 916d4f80b..097899911 100644 --- a/components/sceneutil/controller.cpp +++ b/components/sceneutil/controller.cpp @@ -5,7 +5,6 @@ #include #include #include -#include namespace SceneUtil { diff --git a/components/sceneutil/riggeometry.cpp b/components/sceneutil/riggeometry.cpp index da7d42431..f915ee39c 100644 --- a/components/sceneutil/riggeometry.cpp +++ b/components/sceneutil/riggeometry.cpp @@ -4,7 +4,6 @@ #include #include -#include #include #include "skeleton.hpp" diff --git a/components/sdlutil/sdlgraphicswindow.cpp b/components/sdlutil/sdlgraphicswindow.cpp index e5bad1f00..66d53b096 100644 --- a/components/sdlutil/sdlgraphicswindow.cpp +++ b/components/sdlutil/sdlgraphicswindow.cpp @@ -2,8 +2,6 @@ #include -#include - namespace SDLUtil { diff --git a/components/terrain/terraingrid.cpp b/components/terrain/terraingrid.cpp index 96584172a..981a984e4 100644 --- a/components/terrain/terraingrid.cpp +++ b/components/terrain/terraingrid.cpp @@ -19,7 +19,6 @@ #include #include #include -#include #include From d1375cd3a3ada3e8b9a84e64e1f5d1ab7b39cbaa Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 12 Feb 2016 23:40:50 +0100 Subject: [PATCH 3152/3725] Crashcatcher: limit backtrace to a sensible number of stack frames When a stack overflow occurs, trying to print the whole stack would cause the process to hang indefinitely. --- apps/openmw/crashcatcher.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/crashcatcher.cpp b/apps/openmw/crashcatcher.cpp index cafd0e08a..4f0356259 100644 --- a/apps/openmw/crashcatcher.cpp +++ b/apps/openmw/crashcatcher.cpp @@ -149,7 +149,7 @@ static void gdb_info(pid_t pid) "info registers\n" "shell echo \"\"\n" "shell echo \"* Backtrace\"\n" - "thread apply all backtrace full\n" + "thread apply all backtrace full 1000\n" "detach\n" "quit\n", pid); fclose(f); From 383524c6881056dc3f84992d5ec8d51e2f102273 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 13 Feb 2016 02:56:41 +0100 Subject: [PATCH 3153/3725] Run physics in fixed timesteps, use the remainder to interpolate between current and previous state Based on http://gafferongames.com/game-physics/fix-your-timestep/ --- apps/openmw/mwbase/world.hpp | 2 +- apps/openmw/mwphysics/actor.cpp | 38 ++++++++-- apps/openmw/mwphysics/actor.hpp | 17 +++++ apps/openmw/mwphysics/physicssystem.cpp | 89 +++++++++++++---------- apps/openmw/mwphysics/physicssystem.hpp | 2 +- apps/openmw/mwworld/projectilemanager.cpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 15 ++-- apps/openmw/mwworld/worldimp.hpp | 4 +- 8 files changed, 110 insertions(+), 59 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 946a9a5dd..52697d670 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -270,7 +270,7 @@ namespace MWBase virtual MWWorld::Ptr moveObject (const MWWorld::Ptr& ptr, float x, float y, float z) = 0; ///< @return an updated Ptr in case the Ptr's cell changes - virtual MWWorld::Ptr moveObject(const MWWorld::Ptr &ptr, MWWorld::CellStore* newCell, float x, float y, float z) = 0; + virtual MWWorld::Ptr moveObject(const MWWorld::Ptr &ptr, MWWorld::CellStore* newCell, float x, float y, float z, bool movePhysics=true) = 0; ///< @return an updated Ptr virtual void scaleObject (const MWWorld::Ptr& ptr, float scale) = 0; diff --git a/apps/openmw/mwphysics/actor.cpp b/apps/openmw/mwphysics/actor.cpp index c99754b5c..61022da28 100644 --- a/apps/openmw/mwphysics/actor.cpp +++ b/apps/openmw/mwphysics/actor.cpp @@ -45,8 +45,7 @@ Actor::Actor(const MWWorld::Ptr& ptr, osg::ref_ptr updateRotation(); updateScale(); - // already called by updateScale() - //updatePosition(); + updatePosition(); updateCollisionMask(); } @@ -86,19 +85,44 @@ void Actor::updatePosition() { osg::Vec3f position = mPtr.getRefData().getPosition().asVec3(); + mPosition = position; + mPreviousPosition = position; + + updateCollisionObjectPosition(); +} + +void Actor::updateCollisionObjectPosition() +{ btTransform tr = mCollisionObject->getWorldTransform(); osg::Vec3f scaledTranslation = mRotation * osg::componentMultiply(mMeshTranslation, mScale); - osg::Vec3f newPosition = scaledTranslation + position; - + osg::Vec3f newPosition = scaledTranslation + mPosition; tr.setOrigin(toBullet(newPosition)); mCollisionObject->setWorldTransform(tr); } -osg::Vec3f Actor::getPosition() const +osg::Vec3f Actor::getCollisionObjectPosition() const { return toOsg(mCollisionObject->getWorldTransform().getOrigin()); } +void Actor::setPosition(const osg::Vec3f &position) +{ + mPreviousPosition = mPosition; + + mPosition = position; + updateCollisionObjectPosition(); +} + +osg::Vec3f Actor::getPosition() const +{ + return mPosition; +} + +osg::Vec3f Actor::getPreviousPosition() const +{ + return mPreviousPosition; +} + void Actor::updateRotation () { btTransform tr = mCollisionObject->getWorldTransform(); @@ -106,7 +130,7 @@ void Actor::updateRotation () tr.setRotation(toBullet(mRotation)); mCollisionObject->setWorldTransform(tr); - updatePosition(); + updateCollisionObjectPosition(); } void Actor::updateScale() @@ -122,7 +146,7 @@ void Actor::updateScale() mPtr.getClass().adjustScale(mPtr, scaleVec, true); mRenderingScale = scaleVec; - updatePosition(); + updateCollisionObjectPosition(); } osg::Vec3f Actor::getHalfExtents() const diff --git a/apps/openmw/mwphysics/actor.hpp b/apps/openmw/mwphysics/actor.hpp index 5755def74..b238547e1 100644 --- a/apps/openmw/mwphysics/actor.hpp +++ b/apps/openmw/mwphysics/actor.hpp @@ -68,8 +68,15 @@ namespace MWPhysics void updateScale(); void updateRotation(); + + /** + * Set mPosition and mPreviousPosition to the position in the Ptr's RefData. This should be used + * when an object is "instantly" moved/teleported as opposed to being moved by the physics simulation. + */ void updatePosition(); + void updateCollisionObjectPosition(); + /** * Returns the half extents of the collision body (scaled according to collision scale) */ @@ -79,8 +86,17 @@ namespace MWPhysics * Returns the position of the collision body * @note The collision shape's origin is in its center, so the position returned can be described as center of the actor collision box in world space. */ + osg::Vec3f getCollisionObjectPosition() const; + + /** + * Store the current position into mPreviousPosition, then move to this position. + */ + void setPosition(const osg::Vec3f& position); + osg::Vec3f getPosition() const; + osg::Vec3f getPreviousPosition() const; + /** * Returns the half extents of the collision body (scaled according to rendering scale) * @note The reason we need this extra method is because of an inconsistency in MW - NPC race scales aren't applied to the collision shape, @@ -138,6 +154,7 @@ namespace MWPhysics osg::Vec3f mScale; osg::Vec3f mRenderingScale; osg::Vec3f mPosition; + osg::Vec3f mPreviousPosition; osg::Vec3f mForce; bool mOnGround; diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 9f1cfc682..ddb3d0c85 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -234,13 +234,11 @@ namespace MWPhysics } } - static osg::Vec3f move(const MWWorld::Ptr &ptr, Actor* physicActor, const osg::Vec3f &movement, float time, + static osg::Vec3f move(osg::Vec3f position, const MWWorld::Ptr &ptr, Actor* physicActor, const osg::Vec3f &movement, float time, bool isFlying, float waterlevel, float slowFall, btCollisionWorld* collisionWorld, std::map& standingCollisionTracker) { const ESM::Position& refpos = ptr.getRefData().getPosition(); - osg::Vec3f position(refpos.asVec3()); - // Early-out for totally static creatures // (Not sure if gravity should still apply?) if (!ptr.getClass().isMobile(ptr)) @@ -944,8 +942,8 @@ namespace MWPhysics if (!physactor1 || !physactor2) return false; - osg::Vec3f pos1 (physactor1->getPosition() + osg::Vec3f(0,0,physactor1->getHalfExtents().z() * 0.8)); // eye level - osg::Vec3f pos2 (physactor2->getPosition() + osg::Vec3f(0,0,physactor2->getHalfExtents().z() * 0.8)); + osg::Vec3f pos1 (physactor1->getCollisionObjectPosition() + osg::Vec3f(0,0,physactor1->getHalfExtents().z() * 0.8)); // eye level + osg::Vec3f pos2 (physactor2->getCollisionObjectPosition() + osg::Vec3f(0,0,physactor2->getHalfExtents().z() * 0.8)); RayResult result = castRay(pos1, pos2, MWWorld::Ptr(), CollisionType_World|CollisionType_HeightMap|CollisionType_Door); @@ -1007,11 +1005,11 @@ namespace MWPhysics return osg::Vec3f(); } - osg::Vec3f PhysicsSystem::getPosition(const MWWorld::ConstPtr &actor) const + osg::Vec3f PhysicsSystem::getCollisionObjectPosition(const MWWorld::ConstPtr &actor) const { const Actor* physactor = getActor(actor); if (physactor) - return physactor->getPosition(); + return physactor->getCollisionObjectPosition(); else return osg::Vec3f(); } @@ -1296,54 +1294,65 @@ namespace MWPhysics mMovementResults.clear(); mTimeAccum += dt; - if(mTimeAccum >= 1.0f/60.0f) + const float physicsDt = 1.f/60.0f; + int numSteps = mTimeAccum / (physicsDt); + mTimeAccum -= numSteps * physicsDt; + + if (numSteps) { // Collision events should be available on every frame mStandingCollisions.clear(); + } - const MWBase::World *world = MWBase::Environment::get().getWorld(); - PtrVelocityList::iterator iter = mMovementQueue.begin(); - for(;iter != mMovementQueue.end();++iter) - { - float waterlevel = -std::numeric_limits::max(); - const MWWorld::CellStore *cell = iter->first.getCell(); - if(cell->getCell()->hasWater()) - waterlevel = cell->getWaterLevel(); + const MWBase::World *world = MWBase::Environment::get().getWorld(); + PtrVelocityList::iterator iter = mMovementQueue.begin(); + for(;iter != mMovementQueue.end();++iter) + { + float waterlevel = -std::numeric_limits::max(); + const MWWorld::CellStore *cell = iter->first.getCell(); + if(cell->getCell()->hasWater()) + waterlevel = cell->getWaterLevel(); - float oldHeight = iter->first.getRefData().getPosition().pos[2]; - const MWMechanics::MagicEffects& effects = iter->first.getClass().getCreatureStats(iter->first).getMagicEffects(); + const MWMechanics::MagicEffects& effects = iter->first.getClass().getCreatureStats(iter->first).getMagicEffects(); - bool waterCollision = false; - if (effects.get(ESM::MagicEffect::WaterWalking).getMagnitude() - && cell->getCell()->hasWater() - && !world->isUnderwater(iter->first.getCell(), - osg::Vec3f(iter->first.getRefData().getPosition().asVec3()))) - waterCollision = true; + bool waterCollision = false; + if (effects.get(ESM::MagicEffect::WaterWalking).getMagnitude() + && cell->getCell()->hasWater() + && !world->isUnderwater(iter->first.getCell(), + osg::Vec3f(iter->first.getRefData().getPosition().asVec3()))) + waterCollision = true; - ActorMap::iterator foundActor = mActors.find(iter->first); - if (foundActor == mActors.end()) // actor was already removed from the scene - continue; - Actor* physicActor = foundActor->second; - physicActor->setCanWaterWalk(waterCollision); + ActorMap::iterator foundActor = mActors.find(iter->first); + if (foundActor == mActors.end()) // actor was already removed from the scene + continue; + Actor* physicActor = foundActor->second; + physicActor->setCanWaterWalk(waterCollision); - // Slow fall reduces fall speed by a factor of (effect magnitude / 200) - float slowFall = 1.f - std::max(0.f, std::min(1.f, effects.get(ESM::MagicEffect::SlowFall).getMagnitude() * 0.005f)); + // Slow fall reduces fall speed by a factor of (effect magnitude / 200) + float slowFall = 1.f - std::max(0.f, std::min(1.f, effects.get(ESM::MagicEffect::SlowFall).getMagnitude() * 0.005f)); - osg::Vec3f newpos = MovementSolver::move(physicActor->getPtr(), physicActor, iter->second, mTimeAccum, - world->isFlying(iter->first), - waterlevel, slowFall, mCollisionWorld, mStandingCollisions); + osg::Vec3f position = physicActor->getPosition(); + float oldHeight = position.z(); + for (int i=0; igetPtr(), physicActor, iter->second, physicsDt, + world->isFlying(iter->first), + waterlevel, slowFall, mCollisionWorld, mStandingCollisions); + physicActor->setPosition(position); + } - float heightDiff = newpos.z() - oldHeight; + float interpolationFactor = mTimeAccum / physicsDt; + osg::Vec3f interpolated = position * interpolationFactor + physicActor->getPreviousPosition() * (1.f - interpolationFactor); - if (heightDiff < 0) - iter->first.getClass().getCreatureStats(iter->first).addToFallHeight(-heightDiff); + float heightDiff = position.z() - oldHeight; - mMovementResults.push_back(std::make_pair(iter->first, newpos)); - } + if (heightDiff < 0) + iter->first.getClass().getCreatureStats(iter->first).addToFallHeight(-heightDiff); - mTimeAccum = 0.0f; + mMovementResults.push_back(std::make_pair(iter->first, interpolated)); } + mMovementQueue.clear(); return mMovementResults; diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index 110b59268..62ebf4f0e 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -129,7 +129,7 @@ namespace MWPhysics /// Get the position of the collision shape for the actor. Use together with getHalfExtents() to get the collision bounds in world space. /// @note The collision shape's origin is in its center, so the position returned can be described as center of the actor collision box in world space. - osg::Vec3f getPosition(const MWWorld::ConstPtr& actor) const; + osg::Vec3f getCollisionObjectPosition(const MWWorld::ConstPtr& actor) const; /// Queues velocity movement for a Ptr. If a Ptr is already queued, its velocity will /// be overwritten. Valid until the next call to applyQueuedMovement. diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index b8150ce9c..881530c8a 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -117,7 +117,7 @@ namespace MWWorld const ESM::EffectList &effects, const Ptr &caster, const std::string &sourceName, const osg::Vec3f& fallbackDirection) { - osg::Vec3f pos = mPhysics->getPosition(caster) + osg::Vec3f(0,0,mPhysics->getHalfExtents(caster).z() * 0.5); // Spawn at 0.75 * ActorHeight + osg::Vec3f pos = mPhysics->getCollisionObjectPosition(caster) + osg::Vec3f(0,0,mPhysics->getHalfExtents(caster).z() * 0.5); // Spawn at 0.75 * ActorHeight if (MWBase::Environment::get().getWorld()->isUnderwater(caster.getCell(), pos)) // Underwater casting not possible return; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 137dac42e..98517f543 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1113,7 +1113,7 @@ namespace MWWorld } } - MWWorld::Ptr World::moveObject(const Ptr &ptr, CellStore* newCell, float x, float y, float z) + MWWorld::Ptr World::moveObject(const Ptr &ptr, CellStore* newCell, float x, float y, float z, bool movePhysics) { ESM::Position pos = ptr.getRefData().getPosition(); @@ -1201,7 +1201,8 @@ namespace MWWorld if (haveToMove && newPtr.getRefData().getBaseNode()) { mRendering->moveObject(newPtr, vec); - mPhysics->updatePosition(newPtr); + if (movePhysics) + mPhysics->updatePosition(newPtr); } if (isPlayer) { @@ -1210,7 +1211,7 @@ namespace MWWorld return newPtr; } - MWWorld::Ptr World::moveObjectImp(const Ptr& ptr, float x, float y, float z) + MWWorld::Ptr World::moveObjectImp(const Ptr& ptr, float x, float y, float z, bool movePhysics) { CellStore *cell = ptr.getCell(); @@ -1221,7 +1222,7 @@ namespace MWWorld cell = getExterior(cellX, cellY); } - return moveObject(ptr, cell, x, y, z); + return moveObject(ptr, cell, x, y, z, movePhysics); } MWWorld::Ptr World::moveObject (const Ptr& ptr, float x, float y, float z) @@ -1373,10 +1374,10 @@ namespace MWWorld player = iter; continue; } - moveObjectImp(iter->first, iter->second.x(), iter->second.y(), iter->second.z()); + moveObjectImp(iter->first, iter->second.x(), iter->second.y(), iter->second.z(), false); } if(player != results.end()) - moveObjectImp(player->first, player->second.x(), player->second.y(), player->second.z()); + moveObjectImp(player->first, player->second.x(), player->second.y(), player->second.z(), false); mPhysics->debugDraw(); } @@ -3206,7 +3207,7 @@ namespace MWWorld osg::Vec3f World::aimToTarget(const ConstPtr &actor, const MWWorld::ConstPtr& target) { osg::Vec3f weaponPos = getActorHeadTransform(actor).getTrans(); - osg::Vec3f targetPos = mPhysics->getPosition(target); + osg::Vec3f targetPos = mPhysics->getCollisionObjectPosition(target); return (targetPos - weaponPos); } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index cf9321da5..6cc5cdc11 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -119,7 +119,7 @@ namespace MWWorld void rotateObjectImp (const Ptr& ptr, const osg::Vec3f& rot, bool adjust); - Ptr moveObjectImp (const Ptr& ptr, float x, float y, float z); + Ptr moveObjectImp (const Ptr& ptr, float x, float y, float z, bool movePhysics=true); ///< @return an updated Ptr in case the Ptr's cell changes Ptr copyObjectToCell(const ConstPtr &ptr, CellStore* cell, ESM::Position pos, int count, bool adjustPos); @@ -355,7 +355,7 @@ namespace MWWorld virtual MWWorld::Ptr moveObject (const Ptr& ptr, float x, float y, float z); ///< @return an updated Ptr in case the Ptr's cell changes - virtual MWWorld::Ptr moveObject (const Ptr& ptr, CellStore* newCell, float x, float y, float z); + virtual MWWorld::Ptr moveObject (const Ptr& ptr, CellStore* newCell, float x, float y, float z, bool movePhysics=true); ///< @return an updated Ptr virtual void scaleObject (const Ptr& ptr, float scale); From 796a4a795a95ad2ffa16de61368af9257b41b9c8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 13 Feb 2016 03:09:28 +0100 Subject: [PATCH 3154/3725] Avoid the 'spiral of death' --- apps/openmw/mwphysics/physicssystem.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index ddb3d0c85..8d4c2c590 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -1295,7 +1295,11 @@ namespace MWPhysics mTimeAccum += dt; const float physicsDt = 1.f/60.0f; + + const int maxAllowedSteps = 20; int numSteps = mTimeAccum / (physicsDt); + numSteps = std::min(numSteps, maxAllowedSteps); + mTimeAccum -= numSteps * physicsDt; if (numSteps) From 6fc6913424f07bda08e72c6253fe6e091f423222 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 13 Feb 2016 03:34:00 +0100 Subject: [PATCH 3155/3725] Do not set the cursor when creating it --- components/sdlutil/sdlcursormanager.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/components/sdlutil/sdlcursormanager.cpp b/components/sdlutil/sdlcursormanager.cpp index afe240609..b372744f5 100644 --- a/components/sdlutil/sdlcursormanager.cpp +++ b/components/sdlutil/sdlcursormanager.cpp @@ -239,8 +239,6 @@ namespace SDLUtil //clean up SDL_FreeSurface(surf); - - _setGUICursor(name); } } From eaf3f5a82920e7b016a3a111de0de05d89cfc68b Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 13 Feb 2016 04:14:05 +0100 Subject: [PATCH 3156/3725] Remove unused arguments --- apps/openmw/mwgui/windowmanagerimp.cpp | 4 +--- components/sdlutil/sdlcursormanager.cpp | 6 +++--- components/sdlutil/sdlcursormanager.hpp | 4 ++-- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 03fbc9238..f5d78aee6 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -2020,13 +2020,11 @@ namespace MWGui if(image.valid()) { //everything looks good, send it to the cursor manager - Uint8 size_x = imgSetPointer->getSize().width; - Uint8 size_y = imgSetPointer->getSize().height; Uint8 hotspot_x = imgSetPointer->getHotSpot().left; Uint8 hotspot_y = imgSetPointer->getHotSpot().top; int rotation = imgSetPointer->getRotation(); - mCursorManager->createCursor(imgSetPointer->getResourceName(), rotation, image, size_x, size_y, hotspot_x, hotspot_y); + mCursorManager->createCursor(imgSetPointer->getResourceName(), rotation, image, hotspot_x, hotspot_y); } } } diff --git a/components/sdlutil/sdlcursormanager.cpp b/components/sdlutil/sdlcursormanager.cpp index b372744f5..ad03083de 100644 --- a/components/sdlutil/sdlcursormanager.cpp +++ b/components/sdlutil/sdlcursormanager.cpp @@ -211,12 +211,12 @@ namespace SDLUtil SDL_SetCursor(mCursorMap.find(name)->second); } - void SDLCursorManager::createCursor(const std::string& name, int rotDegrees, osg::Image* image, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y) + void SDLCursorManager::createCursor(const std::string& name, int rotDegrees, osg::Image* image, Uint8 hotspot_x, Uint8 hotspot_y) { - _createCursorFromResource(name, rotDegrees, image, size_x, size_y, hotspot_x, hotspot_y); + _createCursorFromResource(name, rotDegrees, image, hotspot_x, hotspot_y); } - void SDLCursorManager::_createCursorFromResource(const std::string& name, int rotDegrees, osg::Image* image, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y) + void SDLCursorManager::_createCursorFromResource(const std::string& name, int rotDegrees, osg::Image* image, Uint8 hotspot_x, Uint8 hotspot_y) { osg::ref_ptr decompressed; diff --git a/components/sdlutil/sdlcursormanager.hpp b/components/sdlutil/sdlcursormanager.hpp index 0db578039..f338778d1 100644 --- a/components/sdlutil/sdlcursormanager.hpp +++ b/components/sdlutil/sdlcursormanager.hpp @@ -29,10 +29,10 @@ namespace SDLUtil /// name of the cursor we changed to ("arrow", "ibeam", etc) virtual void cursorChanged(const std::string &name); - virtual void createCursor(const std::string &name, int rotDegrees, osg::Image* image, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y); + virtual void createCursor(const std::string &name, int rotDegrees, osg::Image* image, Uint8 hotspot_x, Uint8 hotspot_y); private: - void _createCursorFromResource(const std::string &name, int rotDegrees, osg::Image* image, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y); + void _createCursorFromResource(const std::string &name, int rotDegrees, osg::Image* image, Uint8 hotspot_x, Uint8 hotspot_y); void _putPixel(SDL_Surface *surface, int x, int y, Uint32 pixel); void _setGUICursor(const std::string& name); From 25744aaaddd7a28d434e00ae2b426e12097d4e13 Mon Sep 17 00:00:00 2001 From: Rob Cutmore Date: Sun, 14 Feb 2016 10:28:41 -0500 Subject: [PATCH 3157/3725] Update cell marker appearance - Added bounding box around marker text. Box is black when cell exists otherwise it is red. - Changed format of marker text. - Changed marker text's pivot point to be at center of text. --- apps/opencs/view/render/cell.cpp | 8 +++++++- apps/opencs/view/render/cellmarker.cpp | 27 ++++++++++++++++++++------ apps/opencs/view/render/cellmarker.hpp | 7 +++++-- 3 files changed, 33 insertions(+), 9 deletions(-) diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index 0030fd9b8..e7b135891 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -307,7 +307,13 @@ void CSVRender::Cell::setCellArrows (int mask) void CSVRender::Cell::setCellMarker() { - mCellMarker.reset(new CellMarker(mCellNode, mCoordinates)); + bool cellExists = false; + int cellIndex = mData.getCells().searchId(mId); + if (cellIndex > -1) + { + cellExists = !mData.getCells().getRecord(cellIndex).isDeleted(); + } + mCellMarker.reset(new CellMarker(mCellNode, mCoordinates, cellExists)); } CSMWorld::CellCoordinates CSVRender::Cell::getCoordinates() const diff --git a/apps/opencs/view/render/cellmarker.cpp b/apps/opencs/view/render/cellmarker.cpp index e8772a586..e0d270f85 100644 --- a/apps/opencs/view/render/cellmarker.cpp +++ b/apps/opencs/view/render/cellmarker.cpp @@ -22,14 +22,27 @@ void CSVRender::CellMarker::buildMarker() { const int characterSize = 20; - // Set up marker text containing cell's coordinates. + // Set up attributes of marker text. osg::ref_ptr markerText (new osgText::Text); - markerText->setBackdropType(osgText::Text::OUTLINE); markerText->setLayout(osgText::Text::LEFT_TO_RIGHT); markerText->setCharacterSize(characterSize); + markerText->setAlignment(osgText::Text::CENTER_CENTER); + markerText->setDrawMode(osgText::Text::TEXT | osgText::Text::FILLEDBOUNDINGBOX); + + // If cell exists then show black bounding box otherwise show red. + if (mExists) + { + markerText->setBoundingBoxColor(osg::Vec4f(0.0f, 0.0f, 0.0f, 1.0f)); + } + else + { + markerText->setBoundingBoxColor(osg::Vec4f(1.0f, 0.0f, 0.0f, 1.0f)); + } + + // Add text containing cell's coordinates. std::string coordinatesText = - "#" + boost::lexical_cast(mCoordinates.getX()) + - " " + boost::lexical_cast(mCoordinates.getY()); + boost::lexical_cast(mCoordinates.getX()) + "," + + boost::lexical_cast(mCoordinates.getY()); markerText->setText(coordinatesText); // Add text to marker node. @@ -51,9 +64,11 @@ void CSVRender::CellMarker::positionMarker() CSVRender::CellMarker::CellMarker( osg::Group *cellNode, - const CSMWorld::CellCoordinates& coordinates + const CSMWorld::CellCoordinates& coordinates, + const bool cellExists ) : mCellNode(cellNode), - mCoordinates(coordinates) + mCoordinates(coordinates), + mExists(cellExists) { // Set up node for cell marker. mMarkerNode = new osg::AutoTransform(); diff --git a/apps/opencs/view/render/cellmarker.hpp b/apps/opencs/view/render/cellmarker.hpp index 08c7e0608..4246b20b8 100644 --- a/apps/opencs/view/render/cellmarker.hpp +++ b/apps/opencs/view/render/cellmarker.hpp @@ -38,6 +38,7 @@ namespace CSVRender osg::Group* mCellNode; osg::ref_ptr mMarkerNode; CSMWorld::CellCoordinates mCoordinates; + bool mExists; // Not implemented. CellMarker(const CellMarker&); @@ -46,7 +47,7 @@ namespace CSVRender /// \brief Build marker containing cell's coordinates. void buildMarker(); - /// \brief Position marker above center of cell. + /// \brief Position marker at center of cell. void positionMarker(); public: @@ -54,9 +55,11 @@ namespace CSVRender /// \brief Constructor. /// \param cellNode Cell to create marker for. /// \param coordinates Coordinates of cell. + /// \param cellExists Whether or not cell exists. CellMarker( osg::Group *cellNode, - const CSMWorld::CellCoordinates& coordinates); + const CSMWorld::CellCoordinates& coordinates, + const bool cellExists); ~CellMarker(); }; From 83a9a164bcba46a32c3f5dfc4e408e9b2bf2c323 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 15 Feb 2016 00:27:39 +0100 Subject: [PATCH 3158/3725] Raise the required bullet version to 2.83 2.82 appears to have a bug that causes the player to be able to phase through certain objects (bug #1587). --- apps/openmw/mwphysics/physicssystem.cpp | 16 ---------------- components/resource/bulletshape.cpp | 14 -------------- components/resource/bulletshapemanager.hpp | 6 ++++++ 3 files changed, 6 insertions(+), 30 deletions(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 8d4c2c590..784910d51 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -765,18 +765,11 @@ namespace MWPhysics mLeastDistSqr(std::numeric_limits::max()) { } -#if BT_BULLET_VERSION >= 281 virtual btScalar addSingleResult(btManifoldPoint& cp, const btCollisionObjectWrapper* col0Wrap,int partId0,int index0, const btCollisionObjectWrapper* col1Wrap,int partId1,int index1) { const btCollisionObject* collisionObject = col1Wrap->m_collisionObject; -#else - virtual btScalar addSingleResult(btManifoldPoint& cp, const btCollisionObject* col0, int partId0, int index0, - const btCollisionObject* col1, int partId1, int index1) - { - const btCollisionObject* collisionObject = col1; -#endif if (collisionObject != mMe) { btScalar distsqr = mOrigin.distance2(cp.getPositionWorldOnA()); @@ -1026,7 +1019,6 @@ namespace MWPhysics std::vector mResult; -#if BT_BULLET_VERSION >= 281 virtual btScalar addSingleResult(btManifoldPoint& cp, const btCollisionObjectWrapper* col0Wrap,int partId0,int index0, const btCollisionObjectWrapper* col1Wrap,int partId1,int index1) @@ -1034,14 +1026,6 @@ namespace MWPhysics const btCollisionObject* collisionObject = col0Wrap->m_collisionObject; if (collisionObject == mTestedAgainst) collisionObject = col1Wrap->m_collisionObject; -#else - virtual btScalar addSingleResult(btManifoldPoint& cp, const btCollisionObject* col0, int partId0, int index0, - const btCollisionObject* col1, int partId1, int index1) - { - const btCollisionObject* collisionObject = col0; - if (collisionObject == mTestedAgainst) - collisionObject = col1; -#endif PtrHolder* holder = static_cast(collisionObject->getUserPointer()); if (holder) mResult.push_back(holder->getPtr()); diff --git a/components/resource/bulletshape.cpp b/components/resource/bulletshape.cpp index 6855429c3..dbdbf0c6e 100644 --- a/components/resource/bulletshape.cpp +++ b/components/resource/bulletshape.cpp @@ -65,21 +65,7 @@ btCollisionShape* BulletShape::duplicateCollisionShape(const btCollisionShape *s if(const btBvhTriangleMeshShape* trishape = dynamic_cast(shape)) { -#if BT_BULLET_VERSION >= 283 btScaledBvhTriangleMeshShape* newShape = new btScaledBvhTriangleMeshShape(const_cast(trishape), btVector3(1.f, 1.f, 1.f)); -#else - // work around btScaledBvhTriangleMeshShape bug ( https://code.google.com/p/bullet/issues/detail?id=371 ) in older bullet versions - const btTriangleMesh* oldMesh = static_cast(trishape->getMeshInterface()); - btTriangleMesh* newMesh = new btTriangleMesh(*oldMesh); - - // Do not build a new bvh (not needed, since it's the same as the original shape's bvh) - btOptimizedBvh* bvh = const_cast(trishape)->getOptimizedBvh(); - TriangleMeshShape* newShape = new TriangleMeshShape(newMesh, true, bvh == NULL); - // Set original shape's bvh via pointer - // The pointer is safe because the BulletShapeInstance keeps a ref_ptr to the original BulletShape - if (bvh) - newShape->setOptimizedBvh(bvh); -#endif return newShape; } diff --git a/components/resource/bulletshapemanager.hpp b/components/resource/bulletshapemanager.hpp index 14b26962b..3fe351f90 100644 --- a/components/resource/bulletshapemanager.hpp +++ b/components/resource/bulletshapemanager.hpp @@ -6,9 +6,15 @@ #include +#include + #include "bulletshape.hpp" #include "resourcemanager.hpp" +#if BT_BULLET_VERSION < 283 +#error "OpenMW requires Bullet version 2.83 or later" +#endif + namespace Resource { class SceneManager; From 9eb96b9cb6af2643b21617e391d317c605cf7c7d Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 15 Feb 2016 14:34:59 +0100 Subject: [PATCH 3159/3725] Parse the bullet version in FindBullet.cmake --- CMakeLists.txt | 3 +++ cmake/FindBullet.cmake | 8 ++++++++ components/resource/bulletshapemanager.hpp | 6 ------ 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 520279e50..f5c468114 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -304,6 +304,9 @@ find_package(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS}) find_package(SDL2 REQUIRED) find_package(OpenAL REQUIRED) find_package(Bullet REQUIRED) +if (NOT BULLET_FOUND OR BULLET_VERSION VERSION_LESS 283) + message(FATAL_ERROR "OpenMW requires Bullet version 2.83 or later") +endif() include_directories("." SYSTEM diff --git a/cmake/FindBullet.cmake b/cmake/FindBullet.cmake index 6d5c517af..d70815dd5 100644 --- a/cmake/FindBullet.cmake +++ b/cmake/FindBullet.cmake @@ -14,11 +14,14 @@ # # Copyright (c) 2009, Philip Lowman +# Modified for OpenMW to parse BT_BULLET_VERSION. # # Redistribution AND use is allowed according to the terms of the New # BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. +include(PreprocessorUtils) + set(BULLET_ROOT $ENV{BULLET_ROOT}) macro(_FIND_BULLET_LIBRARY _var) @@ -75,4 +78,9 @@ if(BULLET_FOUND) #_BULLET_APPEND_LIBRARIES(BULLET_LIBRARIES BULLET_DYNAMICS_LIBRARY) _BULLET_APPEND_LIBRARIES(BULLET_LIBRARIES BULLET_COLLISION_LIBRARY) _BULLET_APPEND_LIBRARIES(BULLET_LIBRARIES BULLET_MATH_LIBRARY) + + find_file(BULLET_BTSCALAR_FILE NAMES btScalar.h PATHS "${BULLET_INCLUDE_DIR}/LinearMath") + file(READ ${BULLET_BTSCALAR_FILE} BULLET_BTSCALAR_CONTENT) + get_preprocessor_entry(BULLET_BTSCALAR_CONTENT BT_BULLET_VERSION BULLET_VERSION) + message(STATUS "Bullet version: ${BULLET_VERSION}") endif() diff --git a/components/resource/bulletshapemanager.hpp b/components/resource/bulletshapemanager.hpp index 3fe351f90..14b26962b 100644 --- a/components/resource/bulletshapemanager.hpp +++ b/components/resource/bulletshapemanager.hpp @@ -6,15 +6,9 @@ #include -#include - #include "bulletshape.hpp" #include "resourcemanager.hpp" -#if BT_BULLET_VERSION < 283 -#error "OpenMW requires Bullet version 2.83 or later" -#endif - namespace Resource { class SceneManager; From 3c717a63603b53b301370bdf7cdef12441582748 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 15 Feb 2016 14:38:58 +0100 Subject: [PATCH 3160/3725] Use Qt5 on travis to match the PPA's OSG build --- CI/before_install.linux.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CI/before_install.linux.sh b/CI/before_install.linux.sh index 1c02bc8d9..b8d8b45e2 100755 --- a/CI/before_install.linux.sh +++ b/CI/before_install.linux.sh @@ -11,11 +11,11 @@ sudo apt-get update -qq sudo apt-get install -qq libgtest-dev google-mock sudo apt-get install -qq libboost-filesystem-dev libboost-program-options-dev libboost-system-dev libboost-thread-dev sudo apt-get install -qq libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libswresample-dev -sudo apt-get install -qq libbullet-dev libopenscenegraph-dev libmygui-dev libsdl2-dev libunshield-dev libtinyxml-dev libopenal-dev libqt4-dev +sudo apt-get install -qq libbullet-dev libopenscenegraph-dev libmygui-dev libsdl2-dev libunshield-dev libtinyxml-dev libopenal-dev qtbase5-dev if [ "${ANALYZE}" ]; then sudo apt-get install -qq clang-3.6; fi sudo mkdir /usr/src/gtest/build cd /usr/src/gtest/build -sudo cmake .. -DBUILD_SHARED_LIBS=1 +sudo cmake .. -DBUILD_SHARED_LIBS=1 -DDESIRED_QT_VERSION=5 sudo make -j4 sudo ln -s /usr/src/gtest/build/libgtest.so /usr/lib/libgtest.so sudo ln -s /usr/src/gtest/build/libgtest_main.so /usr/lib/libgtest_main.so From 647a5e091f4298ed390e511d7ce9fbfa64e0aa95 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 15 Feb 2016 15:16:48 +0100 Subject: [PATCH 3161/3725] Add osgQt to the repository Ensures that it will be built against the correct Qt version. --- CMakeLists.txt | 7 +- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/view/render/scenewidget.cpp | 2 +- extern/osgQt/CMakeLists.txt | 21 + extern/osgQt/GraphicsWindowQt | 193 ++++ extern/osgQt/GraphicsWindowQt.cpp | 1063 +++++++++++++++++++++++ 6 files changed, 1281 insertions(+), 7 deletions(-) create mode 100644 extern/osgQt/CMakeLists.txt create mode 100644 extern/osgQt/GraphicsWindowQt create mode 100644 extern/osgQt/GraphicsWindowQt.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index f5c468114..719df3e34 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -229,11 +229,7 @@ IF(BOOST_STATIC) set(Boost_USE_STATIC_LIBS ON) endif() -if (USE_QT) - set (OSG_QT osgQt) -endif() - -find_package(OpenSceneGraph 3.3.4 REQUIRED osgDB osgViewer osgText osgGA osgAnimation osgParticle ${OSG_QT} osgUtil osgFX) +find_package(OpenSceneGraph 3.3.4 REQUIRED osgDB osgViewer osgText osgGA osgAnimation osgParticle osgUtil osgFX) include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS}) @@ -570,6 +566,7 @@ endif(WIN32) # Extern add_subdirectory (extern/osg-ffmpeg-videoplayer) add_subdirectory (extern/oics) +add_subdirectory (extern/osgQt) # Components add_subdirectory (components) diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index c9245ca9f..6401e4222 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -197,7 +197,7 @@ target_link_libraries(openmw-cs ${OSGVIEWER_LIBRARIES} ${OSGGA_LIBRARIES} ${OSGFX_LIBRARIES} - ${OSGQT_LIBRARIES} + ${EXTERN_OSGQT_LIBRARY} ${Boost_SYSTEM_LIBRARY} ${Boost_FILESYSTEM_LIBRARY} ${Boost_PROGRAM_OPTIONS_LIBRARY} diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index e5b9171e0..ba31c9b8b 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -6,7 +6,7 @@ #include #include -#include +#include #include #include #include diff --git a/extern/osgQt/CMakeLists.txt b/extern/osgQt/CMakeLists.txt new file mode 100644 index 000000000..e8a456da9 --- /dev/null +++ b/extern/osgQt/CMakeLists.txt @@ -0,0 +1,21 @@ +set(OSGQT_LIBRARY "osgQt") + +# Sources + +set(OSGQT_SOURCE_FILES + GraphicsWindowQt.cpp +) + +include_directories(${FFMPEG_INCLUDE_DIRS}) +add_library(${OSGQT_LIBRARY} STATIC ${OSGQT_SOURCE_FILES}) + +if (DESIRED_QT_VERSION MATCHES 4) + include(${QT_USE_FILE}) + target_link_libraries(${OSGQT_LIBRARY} ${QT_QTCORE_LIBRARY} ${QT_QTOPENGL_LIBRARY}) +else() + qt5_use_modules(${OSGQT_LIBRARY} Core OpenGL) +endif() + +link_directories(${CMAKE_CURRENT_BINARY_DIR}) + +set(EXTERN_OSGQT_LIBRARY ${OSGQT_LIBRARY} PARENT_SCOPE) diff --git a/extern/osgQt/GraphicsWindowQt b/extern/osgQt/GraphicsWindowQt new file mode 100644 index 000000000..54d069176 --- /dev/null +++ b/extern/osgQt/GraphicsWindowQt @@ -0,0 +1,193 @@ +/* -*-c++-*- OpenSceneGraph - Copyright (C) 2009 Wang Rui + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * OpenSceneGraph Public License for more details. +*/ + +#ifndef OSGVIEWER_GRAPHICSWINDOWQT +#define OSGVIEWER_GRAPHICSWINDOWQT + +#include + +#include + +#include +#include +#include +#include +#include + +class QInputEvent; +class QGestureEvent; + +namespace osgViewer { + class ViewerBase; +} + +namespace osgQt +{ + +// forward declarations +class GraphicsWindowQt; + +/// The function sets the WindowingSystem to Qt. +void initQtWindowingSystem(); + +/** The function sets the viewer that will be used after entering + * the Qt main loop (QCoreApplication::exec()). + * + * The function also initializes internal structures required for proper + * scene rendering. + * + * The method must be called from main thread. */ +void setViewer( osgViewer::ViewerBase *viewer ); + + +class GLWidget : public QGLWidget +{ + typedef QGLWidget inherited; + +public: + + GLWidget( QWidget* parent = NULL, const QGLWidget* shareWidget = NULL, Qt::WindowFlags f = 0, bool forwardKeyEvents = false ); + GLWidget( QGLContext* context, QWidget* parent = NULL, const QGLWidget* shareWidget = NULL, Qt::WindowFlags f = 0, bool forwardKeyEvents = false ); + GLWidget( const QGLFormat& format, QWidget* parent = NULL, const QGLWidget* shareWidget = NULL, Qt::WindowFlags f = 0, bool forwardKeyEvents = false ); + virtual ~GLWidget(); + + inline void setGraphicsWindow( GraphicsWindowQt* gw ) { _gw = gw; } + inline GraphicsWindowQt* getGraphicsWindow() { return _gw; } + inline const GraphicsWindowQt* getGraphicsWindow() const { return _gw; } + + inline bool getForwardKeyEvents() const { return _forwardKeyEvents; } + virtual void setForwardKeyEvents( bool f ) { _forwardKeyEvents = f; } + + inline bool getTouchEventsEnabled() const { return _touchEventsEnabled; } + void setTouchEventsEnabled( bool e ); + + void setKeyboardModifiers( QInputEvent* event ); + + virtual void keyPressEvent( QKeyEvent* event ); + virtual void keyReleaseEvent( QKeyEvent* event ); + virtual void mousePressEvent( QMouseEvent* event ); + virtual void mouseReleaseEvent( QMouseEvent* event ); + virtual void mouseDoubleClickEvent( QMouseEvent* event ); + virtual void mouseMoveEvent( QMouseEvent* event ); + virtual void wheelEvent( QWheelEvent* event ); + virtual bool gestureEvent( QGestureEvent* event ); + +protected: + + int getNumDeferredEvents() + { + QMutexLocker lock(&_deferredEventQueueMutex); + return _deferredEventQueue.count(); + } + void enqueueDeferredEvent(QEvent::Type eventType, QEvent::Type removeEventType = QEvent::None) + { + QMutexLocker lock(&_deferredEventQueueMutex); + + if (removeEventType != QEvent::None) + { + if (_deferredEventQueue.removeOne(removeEventType)) + _eventCompressor.remove(eventType); + } + + if (_eventCompressor.find(eventType) == _eventCompressor.end()) + { + _deferredEventQueue.enqueue(eventType); + _eventCompressor.insert(eventType); + } + } + void processDeferredEvents(); + + friend class GraphicsWindowQt; + GraphicsWindowQt* _gw; + + QMutex _deferredEventQueueMutex; + QQueue _deferredEventQueue; + QSet _eventCompressor; + + bool _touchEventsEnabled; + + bool _forwardKeyEvents; + qreal _devicePixelRatio; + + virtual void resizeEvent( QResizeEvent* event ); + virtual void moveEvent( QMoveEvent* event ); + virtual void glDraw(); + virtual bool event( QEvent* event ); +}; + +class GraphicsWindowQt : public osgViewer::GraphicsWindow +{ +public: + GraphicsWindowQt( osg::GraphicsContext::Traits* traits, QWidget* parent = NULL, const QGLWidget* shareWidget = NULL, Qt::WindowFlags f = 0 ); + GraphicsWindowQt( GLWidget* widget ); + virtual ~GraphicsWindowQt(); + + inline GLWidget* getGLWidget() { return _widget; } + inline const GLWidget* getGLWidget() const { return _widget; } + + /// deprecated + inline GLWidget* getGraphWidget() { return _widget; } + /// deprecated + inline const GLWidget* getGraphWidget() const { return _widget; } + + struct WindowData : public osg::Referenced + { + WindowData( GLWidget* widget = NULL, QWidget* parent = NULL ): _widget(widget), _parent(parent) {} + GLWidget* _widget; + QWidget* _parent; + }; + + bool init( QWidget* parent, const QGLWidget* shareWidget, Qt::WindowFlags f ); + + static QGLFormat traits2qglFormat( const osg::GraphicsContext::Traits* traits ); + static void qglFormat2traits( const QGLFormat& format, osg::GraphicsContext::Traits* traits ); + static osg::GraphicsContext::Traits* createTraits( const QGLWidget* widget ); + + virtual bool setWindowRectangleImplementation( int x, int y, int width, int height ); + virtual void getWindowRectangle( int& x, int& y, int& width, int& height ); + virtual bool setWindowDecorationImplementation( bool windowDecoration ); + virtual bool getWindowDecoration() const; + virtual void grabFocus(); + virtual void grabFocusIfPointerInWindow(); + virtual void raiseWindow(); + virtual void setWindowName( const std::string& name ); + virtual std::string getWindowName(); + virtual void useCursor( bool cursorOn ); + virtual void setCursor( MouseCursor cursor ); + inline bool getTouchEventsEnabled() const { return _widget->getTouchEventsEnabled(); } + virtual void setTouchEventsEnabled( bool e ) { _widget->setTouchEventsEnabled(e); } + + + virtual bool valid() const; + virtual bool realizeImplementation(); + virtual bool isRealizedImplementation() const; + virtual void closeImplementation(); + virtual bool makeCurrentImplementation(); + virtual bool releaseContextImplementation(); + virtual void swapBuffersImplementation(); + virtual void runOperations(); + + virtual void requestWarpPointer( float x, float y ); + +protected: + + friend class GLWidget; + GLWidget* _widget; + bool _ownsWidget; + QCursor _currentCursor; + bool _realized; +}; + +} + +#endif diff --git a/extern/osgQt/GraphicsWindowQt.cpp b/extern/osgQt/GraphicsWindowQt.cpp new file mode 100644 index 000000000..2001c8b31 --- /dev/null +++ b/extern/osgQt/GraphicsWindowQt.cpp @@ -0,0 +1,1063 @@ +/* -*-c++-*- OpenSceneGraph - Copyright (C) 2009 Wang Rui + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * OpenSceneGraph Public License for more details. +*/ + +#include "GraphicsWindowQt" + +#include +#include +#include +#include + +#if (QT_VERSION>=QT_VERSION_CHECK(4, 6, 0)) +# define USE_GESTURES +# include +# include +#endif + +using namespace osgQt; + + +class QtKeyboardMap +{ + +public: + QtKeyboardMap() + { + mKeyMap[Qt::Key_Escape ] = osgGA::GUIEventAdapter::KEY_Escape; + mKeyMap[Qt::Key_Delete ] = osgGA::GUIEventAdapter::KEY_Delete; + mKeyMap[Qt::Key_Home ] = osgGA::GUIEventAdapter::KEY_Home; + mKeyMap[Qt::Key_Enter ] = osgGA::GUIEventAdapter::KEY_KP_Enter; + mKeyMap[Qt::Key_End ] = osgGA::GUIEventAdapter::KEY_End; + mKeyMap[Qt::Key_Return ] = osgGA::GUIEventAdapter::KEY_Return; + mKeyMap[Qt::Key_PageUp ] = osgGA::GUIEventAdapter::KEY_Page_Up; + mKeyMap[Qt::Key_PageDown ] = osgGA::GUIEventAdapter::KEY_Page_Down; + mKeyMap[Qt::Key_Left ] = osgGA::GUIEventAdapter::KEY_Left; + mKeyMap[Qt::Key_Right ] = osgGA::GUIEventAdapter::KEY_Right; + mKeyMap[Qt::Key_Up ] = osgGA::GUIEventAdapter::KEY_Up; + mKeyMap[Qt::Key_Down ] = osgGA::GUIEventAdapter::KEY_Down; + mKeyMap[Qt::Key_Backspace ] = osgGA::GUIEventAdapter::KEY_BackSpace; + mKeyMap[Qt::Key_Tab ] = osgGA::GUIEventAdapter::KEY_Tab; + mKeyMap[Qt::Key_Space ] = osgGA::GUIEventAdapter::KEY_Space; + mKeyMap[Qt::Key_Delete ] = osgGA::GUIEventAdapter::KEY_Delete; + mKeyMap[Qt::Key_Alt ] = osgGA::GUIEventAdapter::KEY_Alt_L; + mKeyMap[Qt::Key_Shift ] = osgGA::GUIEventAdapter::KEY_Shift_L; + mKeyMap[Qt::Key_Control ] = osgGA::GUIEventAdapter::KEY_Control_L; + mKeyMap[Qt::Key_Meta ] = osgGA::GUIEventAdapter::KEY_Meta_L; + + mKeyMap[Qt::Key_F1 ] = osgGA::GUIEventAdapter::KEY_F1; + mKeyMap[Qt::Key_F2 ] = osgGA::GUIEventAdapter::KEY_F2; + mKeyMap[Qt::Key_F3 ] = osgGA::GUIEventAdapter::KEY_F3; + mKeyMap[Qt::Key_F4 ] = osgGA::GUIEventAdapter::KEY_F4; + mKeyMap[Qt::Key_F5 ] = osgGA::GUIEventAdapter::KEY_F5; + mKeyMap[Qt::Key_F6 ] = osgGA::GUIEventAdapter::KEY_F6; + mKeyMap[Qt::Key_F7 ] = osgGA::GUIEventAdapter::KEY_F7; + mKeyMap[Qt::Key_F8 ] = osgGA::GUIEventAdapter::KEY_F8; + mKeyMap[Qt::Key_F9 ] = osgGA::GUIEventAdapter::KEY_F9; + mKeyMap[Qt::Key_F10 ] = osgGA::GUIEventAdapter::KEY_F10; + mKeyMap[Qt::Key_F11 ] = osgGA::GUIEventAdapter::KEY_F11; + mKeyMap[Qt::Key_F12 ] = osgGA::GUIEventAdapter::KEY_F12; + mKeyMap[Qt::Key_F13 ] = osgGA::GUIEventAdapter::KEY_F13; + mKeyMap[Qt::Key_F14 ] = osgGA::GUIEventAdapter::KEY_F14; + mKeyMap[Qt::Key_F15 ] = osgGA::GUIEventAdapter::KEY_F15; + mKeyMap[Qt::Key_F16 ] = osgGA::GUIEventAdapter::KEY_F16; + mKeyMap[Qt::Key_F17 ] = osgGA::GUIEventAdapter::KEY_F17; + mKeyMap[Qt::Key_F18 ] = osgGA::GUIEventAdapter::KEY_F18; + mKeyMap[Qt::Key_F19 ] = osgGA::GUIEventAdapter::KEY_F19; + mKeyMap[Qt::Key_F20 ] = osgGA::GUIEventAdapter::KEY_F20; + + mKeyMap[Qt::Key_hyphen ] = '-'; + mKeyMap[Qt::Key_Equal ] = '='; + + mKeyMap[Qt::Key_division ] = osgGA::GUIEventAdapter::KEY_KP_Divide; + mKeyMap[Qt::Key_multiply ] = osgGA::GUIEventAdapter::KEY_KP_Multiply; + mKeyMap[Qt::Key_Minus ] = '-'; + mKeyMap[Qt::Key_Plus ] = '+'; + //mKeyMap[Qt::Key_H ] = osgGA::GUIEventAdapter::KEY_KP_Home; + //mKeyMap[Qt::Key_ ] = osgGA::GUIEventAdapter::KEY_KP_Up; + //mKeyMap[92 ] = osgGA::GUIEventAdapter::KEY_KP_Page_Up; + //mKeyMap[86 ] = osgGA::GUIEventAdapter::KEY_KP_Left; + //mKeyMap[87 ] = osgGA::GUIEventAdapter::KEY_KP_Begin; + //mKeyMap[88 ] = osgGA::GUIEventAdapter::KEY_KP_Right; + //mKeyMap[83 ] = osgGA::GUIEventAdapter::KEY_KP_End; + //mKeyMap[84 ] = osgGA::GUIEventAdapter::KEY_KP_Down; + //mKeyMap[85 ] = osgGA::GUIEventAdapter::KEY_KP_Page_Down; + mKeyMap[Qt::Key_Insert ] = osgGA::GUIEventAdapter::KEY_KP_Insert; + //mKeyMap[Qt::Key_Delete ] = osgGA::GUIEventAdapter::KEY_KP_Delete; + } + + ~QtKeyboardMap() + { + } + + int remapKey(QKeyEvent* event) + { + KeyMap::iterator itr = mKeyMap.find(event->key()); + if (itr == mKeyMap.end()) + { + return int(*(event->text().toLatin1().data())); + } + else + return itr->second; + } + + private: + typedef std::map KeyMap; + KeyMap mKeyMap; +}; + +static QtKeyboardMap s_QtKeyboardMap; + + +/// The object responsible for the scene re-rendering. +class HeartBeat : public QObject { +public: + int _timerId; + osg::Timer _lastFrameStartTime; + osg::observer_ptr< osgViewer::ViewerBase > _viewer; + + virtual ~HeartBeat(); + + void init( osgViewer::ViewerBase *viewer ); + void stopTimer(); + void timerEvent( QTimerEvent *event ); + + static HeartBeat* instance(); +private: + HeartBeat(); + + static QPointer heartBeat; +}; + +QPointer HeartBeat::heartBeat; + +#if (QT_VERSION < QT_VERSION_CHECK(5, 2, 0)) + #define GETDEVICEPIXELRATIO() 1.0 +#else + #define GETDEVICEPIXELRATIO() devicePixelRatio() +#endif + +GLWidget::GLWidget( QWidget* parent, const QGLWidget* shareWidget, Qt::WindowFlags f, bool forwardKeyEvents ) +: QGLWidget(parent, shareWidget, f), +_gw( NULL ), +_touchEventsEnabled( false ), +_forwardKeyEvents( forwardKeyEvents ) +{ + _devicePixelRatio = GETDEVICEPIXELRATIO(); +} + +GLWidget::GLWidget( QGLContext* context, QWidget* parent, const QGLWidget* shareWidget, Qt::WindowFlags f, + bool forwardKeyEvents ) +: QGLWidget(context, parent, shareWidget, f), +_gw( NULL ), +_touchEventsEnabled( false ), +_forwardKeyEvents( forwardKeyEvents ) +{ + _devicePixelRatio = GETDEVICEPIXELRATIO(); +} + +GLWidget::GLWidget( const QGLFormat& format, QWidget* parent, const QGLWidget* shareWidget, Qt::WindowFlags f, + bool forwardKeyEvents ) +: QGLWidget(format, parent, shareWidget, f), +_gw( NULL ), +_touchEventsEnabled( false ), +_forwardKeyEvents( forwardKeyEvents ) +{ + _devicePixelRatio = GETDEVICEPIXELRATIO(); +} + +GLWidget::~GLWidget() +{ + // close GraphicsWindowQt and remove the reference to us + if( _gw ) + { + _gw->close(); + _gw->_widget = NULL; + _gw = NULL; + } +} + +void GLWidget::setTouchEventsEnabled(bool e) +{ +#ifdef USE_GESTURES + if (e==_touchEventsEnabled) + return; + + _touchEventsEnabled = e; + + if (_touchEventsEnabled) + { + grabGesture(Qt::PinchGesture); + } + else + { + ungrabGesture(Qt::PinchGesture); + } +#endif +} + +void GLWidget::processDeferredEvents() +{ + QQueue deferredEventQueueCopy; + { + QMutexLocker lock(&_deferredEventQueueMutex); + deferredEventQueueCopy = _deferredEventQueue; + _eventCompressor.clear(); + _deferredEventQueue.clear(); + } + + while (!deferredEventQueueCopy.isEmpty()) + { + QEvent event(deferredEventQueueCopy.dequeue()); + QGLWidget::event(&event); + } +} + +bool GLWidget::event( QEvent* event ) +{ +#ifdef USE_GESTURES + if ( event->type()==QEvent::Gesture ) + return gestureEvent(static_cast(event)); +#endif + + // QEvent::Hide + // + // workaround "Qt-workaround" that does glFinish before hiding the widget + // (the Qt workaround was seen at least in Qt 4.6.3 and 4.7.0) + // + // Qt makes the context current, performs glFinish, and releases the context. + // This makes the problem in OSG multithreaded environment as the context + // is active in another thread, thus it can not be made current for the purpose + // of glFinish in this thread. + + // QEvent::ParentChange + // + // Reparenting GLWidget may create a new underlying window and a new GL context. + // Qt will then call doneCurrent on the GL context about to be deleted. The thread + // where old GL context was current has no longer current context to render to and + // we cannot make new GL context current in this thread. + + // We workaround above problems by deferring execution of problematic event requests. + // These events has to be enqueue and executed later in a main GUI thread (GUI operations + // outside the main thread are not allowed) just before makeCurrent is called from the + // right thread. The good place for doing that is right after swap in a swapBuffersImplementation. + + if (event->type() == QEvent::Hide) + { + // enqueue only the last of QEvent::Hide and QEvent::Show + enqueueDeferredEvent(QEvent::Hide, QEvent::Show); + return true; + } + else if (event->type() == QEvent::Show) + { + // enqueue only the last of QEvent::Show or QEvent::Hide + enqueueDeferredEvent(QEvent::Show, QEvent::Hide); + return true; + } + else if (event->type() == QEvent::ParentChange) + { + // enqueue only the last QEvent::ParentChange + enqueueDeferredEvent(QEvent::ParentChange); + return true; + } + + // perform regular event handling + return QGLWidget::event( event ); +} + +void GLWidget::setKeyboardModifiers( QInputEvent* event ) +{ + int modkey = event->modifiers() & (Qt::ShiftModifier | Qt::ControlModifier | Qt::AltModifier); + unsigned int mask = 0; + if ( modkey & Qt::ShiftModifier ) mask |= osgGA::GUIEventAdapter::MODKEY_SHIFT; + if ( modkey & Qt::ControlModifier ) mask |= osgGA::GUIEventAdapter::MODKEY_CTRL; + if ( modkey & Qt::AltModifier ) mask |= osgGA::GUIEventAdapter::MODKEY_ALT; + _gw->getEventQueue()->getCurrentEventState()->setModKeyMask( mask ); +} + +void GLWidget::resizeEvent( QResizeEvent* event ) +{ + const QSize& size = event->size(); + + int scaled_width = static_cast(size.width()*_devicePixelRatio); + int scaled_height = static_cast(size.height()*_devicePixelRatio); + _gw->resized( x(), y(), scaled_width, scaled_height); + _gw->getEventQueue()->windowResize( x(), y(), scaled_width, scaled_height ); + _gw->requestRedraw(); +} + +void GLWidget::moveEvent( QMoveEvent* event ) +{ + const QPoint& pos = event->pos(); + int scaled_width = static_cast(width()*_devicePixelRatio); + int scaled_height = static_cast(height()*_devicePixelRatio); + _gw->resized( pos.x(), pos.y(), scaled_width, scaled_height ); + _gw->getEventQueue()->windowResize( pos.x(), pos.y(), scaled_width, scaled_height ); +} + +void GLWidget::glDraw() +{ + _gw->requestRedraw(); +} + +void GLWidget::keyPressEvent( QKeyEvent* event ) +{ + setKeyboardModifiers( event ); + int value = s_QtKeyboardMap.remapKey( event ); + _gw->getEventQueue()->keyPress( value ); + + // this passes the event to the regular Qt key event processing, + // among others, it closes popup windows on ESC and forwards the event to the parent widgets + if( _forwardKeyEvents ) + inherited::keyPressEvent( event ); +} + +void GLWidget::keyReleaseEvent( QKeyEvent* event ) +{ + if( event->isAutoRepeat() ) + { + event->ignore(); + } + else + { + setKeyboardModifiers( event ); + int value = s_QtKeyboardMap.remapKey( event ); + _gw->getEventQueue()->keyRelease( value ); + } + + // this passes the event to the regular Qt key event processing, + // among others, it closes popup windows on ESC and forwards the event to the parent widgets + if( _forwardKeyEvents ) + inherited::keyReleaseEvent( event ); +} + +void GLWidget::mousePressEvent( QMouseEvent* event ) +{ + int button = 0; + switch ( event->button() ) + { + case Qt::LeftButton: button = 1; break; + case Qt::MidButton: button = 2; break; + case Qt::RightButton: button = 3; break; + case Qt::NoButton: button = 0; break; + default: button = 0; break; + } + setKeyboardModifiers( event ); + _gw->getEventQueue()->mouseButtonPress( event->x()*_devicePixelRatio, event->y()*_devicePixelRatio, button ); +} + +void GLWidget::mouseReleaseEvent( QMouseEvent* event ) +{ + int button = 0; + switch ( event->button() ) + { + case Qt::LeftButton: button = 1; break; + case Qt::MidButton: button = 2; break; + case Qt::RightButton: button = 3; break; + case Qt::NoButton: button = 0; break; + default: button = 0; break; + } + setKeyboardModifiers( event ); + _gw->getEventQueue()->mouseButtonRelease( event->x()*_devicePixelRatio, event->y()*_devicePixelRatio, button ); +} + +void GLWidget::mouseDoubleClickEvent( QMouseEvent* event ) +{ + int button = 0; + switch ( event->button() ) + { + case Qt::LeftButton: button = 1; break; + case Qt::MidButton: button = 2; break; + case Qt::RightButton: button = 3; break; + case Qt::NoButton: button = 0; break; + default: button = 0; break; + } + setKeyboardModifiers( event ); + _gw->getEventQueue()->mouseDoubleButtonPress( event->x()*_devicePixelRatio, event->y()*_devicePixelRatio, button ); +} + +void GLWidget::mouseMoveEvent( QMouseEvent* event ) +{ + setKeyboardModifiers( event ); + _gw->getEventQueue()->mouseMotion( event->x()*_devicePixelRatio, event->y()*_devicePixelRatio ); +} + +void GLWidget::wheelEvent( QWheelEvent* event ) +{ + setKeyboardModifiers( event ); + _gw->getEventQueue()->mouseScroll( + event->orientation() == Qt::Vertical ? + (event->delta()>0 ? osgGA::GUIEventAdapter::SCROLL_UP : osgGA::GUIEventAdapter::SCROLL_DOWN) : + (event->delta()>0 ? osgGA::GUIEventAdapter::SCROLL_LEFT : osgGA::GUIEventAdapter::SCROLL_RIGHT) ); +} + +#ifdef USE_GESTURES +static osgGA::GUIEventAdapter::TouchPhase translateQtGestureState( Qt::GestureState state ) +{ + osgGA::GUIEventAdapter::TouchPhase touchPhase; + switch ( state ) + { + case Qt::GestureStarted: + touchPhase = osgGA::GUIEventAdapter::TOUCH_BEGAN; + break; + case Qt::GestureUpdated: + touchPhase = osgGA::GUIEventAdapter::TOUCH_MOVED; + break; + case Qt::GestureFinished: + case Qt::GestureCanceled: + touchPhase = osgGA::GUIEventAdapter::TOUCH_ENDED; + break; + default: + touchPhase = osgGA::GUIEventAdapter::TOUCH_UNKNOWN; + }; + + return touchPhase; +} +#endif + + +bool GLWidget::gestureEvent( QGestureEvent* qevent ) +{ +#ifndef USE_GESTURES + return false; +#else + + bool accept = false; + + if ( QPinchGesture* pinch = static_cast(qevent->gesture(Qt::PinchGesture) ) ) + { + const QPointF qcenterf = pinch->centerPoint(); + const float angle = pinch->totalRotationAngle(); + const float scale = pinch->totalScaleFactor(); + + const QPoint pinchCenterQt = mapFromGlobal(qcenterf.toPoint()); + const osg::Vec2 pinchCenter( pinchCenterQt.x(), pinchCenterQt.y() ); + + //We don't have absolute positions of the two touches, only a scale and rotation + //Hence we create pseudo-coordinates which are reasonable, and centered around the + //real position + const float radius = (width()+height())/4; + const osg::Vec2 vector( scale*cos(angle)*radius, scale*sin(angle)*radius); + const osg::Vec2 p0 = pinchCenter+vector; + const osg::Vec2 p1 = pinchCenter-vector; + + osg::ref_ptr event = 0; + const osgGA::GUIEventAdapter::TouchPhase touchPhase = translateQtGestureState( pinch->state() ); + if ( touchPhase==osgGA::GUIEventAdapter::TOUCH_BEGAN ) + { + event = _gw->getEventQueue()->touchBegan(0 , touchPhase, p0[0], p0[1] ); + } + else if ( touchPhase==osgGA::GUIEventAdapter::TOUCH_MOVED ) + { + event = _gw->getEventQueue()->touchMoved( 0, touchPhase, p0[0], p0[1] ); + } + else + { + event = _gw->getEventQueue()->touchEnded( 0, touchPhase, p0[0], p0[1], 1 ); + } + + if ( event ) + { + event->addTouchPoint( 1, touchPhase, p1[0], p1[1] ); + accept = true; + } + } + + if ( accept ) + qevent->accept(); + + return accept; +#endif +} + + + +GraphicsWindowQt::GraphicsWindowQt( osg::GraphicsContext::Traits* traits, QWidget* parent, const QGLWidget* shareWidget, Qt::WindowFlags f ) +: _realized(false) +{ + + _widget = NULL; + _traits = traits; + init( parent, shareWidget, f ); +} + +GraphicsWindowQt::GraphicsWindowQt( GLWidget* widget ) +: _realized(false) +{ + _widget = widget; + _traits = _widget ? createTraits( _widget ) : new osg::GraphicsContext::Traits; + init( NULL, NULL, 0 ); +} + +GraphicsWindowQt::~GraphicsWindowQt() +{ + close(); + + // remove reference from GLWidget + if ( _widget ) + _widget->_gw = NULL; +} + +bool GraphicsWindowQt::init( QWidget* parent, const QGLWidget* shareWidget, Qt::WindowFlags f ) +{ + // update _widget and parent by WindowData + WindowData* windowData = _traits.get() ? dynamic_cast(_traits->inheritedWindowData.get()) : 0; + if ( !_widget ) + _widget = windowData ? windowData->_widget : NULL; + if ( !parent ) + parent = windowData ? windowData->_parent : NULL; + + // create widget if it does not exist + _ownsWidget = _widget == NULL; + if ( !_widget ) + { + // shareWidget + if ( !shareWidget ) { + GraphicsWindowQt* sharedContextQt = dynamic_cast(_traits->sharedContext.get()); + if ( sharedContextQt ) + shareWidget = sharedContextQt->getGLWidget(); + } + + // WindowFlags + Qt::WindowFlags flags = f | Qt::Window | Qt::CustomizeWindowHint; + if ( _traits->windowDecoration ) + flags |= Qt::WindowTitleHint | Qt::WindowMinMaxButtonsHint | Qt::WindowSystemMenuHint +#if (QT_VERSION_CHECK(4, 5, 0) <= QT_VERSION) + | Qt::WindowCloseButtonHint +#endif + ; + + // create widget + _widget = new GLWidget( traits2qglFormat( _traits.get() ), parent, shareWidget, flags ); + } + + // set widget name and position + // (do not set it when we inherited the widget) + if ( _ownsWidget ) + { + _widget->setWindowTitle( _traits->windowName.c_str() ); + _widget->move( _traits->x, _traits->y ); + if ( !_traits->supportsResize ) _widget->setFixedSize( _traits->width, _traits->height ); + else _widget->resize( _traits->width, _traits->height ); + } + + // initialize widget properties + _widget->setAutoBufferSwap( false ); + _widget->setMouseTracking( true ); + _widget->setFocusPolicy( Qt::WheelFocus ); + _widget->setGraphicsWindow( this ); + useCursor( _traits->useCursor ); + + // initialize State + setState( new osg::State ); + getState()->setGraphicsContext(this); + + // initialize contextID + if ( _traits.valid() && _traits->sharedContext.valid() ) + { + getState()->setContextID( _traits->sharedContext->getState()->getContextID() ); + incrementContextIDUsageCount( getState()->getContextID() ); + } + else + { + getState()->setContextID( osg::GraphicsContext::createNewContextID() ); + } + + // make sure the event queue has the correct window rectangle size and input range + getEventQueue()->syncWindowRectangleWithGraphicsContext(); + + return true; +} + +QGLFormat GraphicsWindowQt::traits2qglFormat( const osg::GraphicsContext::Traits* traits ) +{ + QGLFormat format( QGLFormat::defaultFormat() ); + + format.setAlphaBufferSize( traits->alpha ); + format.setRedBufferSize( traits->red ); + format.setGreenBufferSize( traits->green ); + format.setBlueBufferSize( traits->blue ); + format.setDepthBufferSize( traits->depth ); + format.setStencilBufferSize( traits->stencil ); + format.setSampleBuffers( traits->sampleBuffers ); + format.setSamples( traits->samples ); + + format.setAlpha( traits->alpha>0 ); + format.setDepth( traits->depth>0 ); + format.setStencil( traits->stencil>0 ); + format.setDoubleBuffer( traits->doubleBuffer ); + format.setSwapInterval( traits->vsync ? 1 : 0 ); + format.setStereo( traits->quadBufferStereo ? 1 : 0 ); + + return format; +} + +void GraphicsWindowQt::qglFormat2traits( const QGLFormat& format, osg::GraphicsContext::Traits* traits ) +{ + traits->red = format.redBufferSize(); + traits->green = format.greenBufferSize(); + traits->blue = format.blueBufferSize(); + traits->alpha = format.alpha() ? format.alphaBufferSize() : 0; + traits->depth = format.depth() ? format.depthBufferSize() : 0; + traits->stencil = format.stencil() ? format.stencilBufferSize() : 0; + + traits->sampleBuffers = format.sampleBuffers() ? 1 : 0; + traits->samples = format.samples(); + + traits->quadBufferStereo = format.stereo(); + traits->doubleBuffer = format.doubleBuffer(); + + traits->vsync = format.swapInterval() >= 1; +} + +osg::GraphicsContext::Traits* GraphicsWindowQt::createTraits( const QGLWidget* widget ) +{ + osg::GraphicsContext::Traits *traits = new osg::GraphicsContext::Traits; + + qglFormat2traits( widget->format(), traits ); + + QRect r = widget->geometry(); + traits->x = r.x(); + traits->y = r.y(); + traits->width = r.width(); + traits->height = r.height(); + + traits->windowName = widget->windowTitle().toLocal8Bit().data(); + Qt::WindowFlags f = widget->windowFlags(); + traits->windowDecoration = ( f & Qt::WindowTitleHint ) && + ( f & Qt::WindowMinMaxButtonsHint ) && + ( f & Qt::WindowSystemMenuHint ); + QSizePolicy sp = widget->sizePolicy(); + traits->supportsResize = sp.horizontalPolicy() != QSizePolicy::Fixed || + sp.verticalPolicy() != QSizePolicy::Fixed; + + return traits; +} + +bool GraphicsWindowQt::setWindowRectangleImplementation( int x, int y, int width, int height ) +{ + if ( _widget == NULL ) + return false; + + _widget->setGeometry( x, y, width, height ); + return true; +} + +void GraphicsWindowQt::getWindowRectangle( int& x, int& y, int& width, int& height ) +{ + if ( _widget ) + { + const QRect& geom = _widget->geometry(); + x = geom.x(); + y = geom.y(); + width = geom.width(); + height = geom.height(); + } +} + +bool GraphicsWindowQt::setWindowDecorationImplementation( bool windowDecoration ) +{ + Qt::WindowFlags flags = Qt::Window|Qt::CustomizeWindowHint;//|Qt::WindowStaysOnTopHint; + if ( windowDecoration ) + flags |= Qt::WindowTitleHint|Qt::WindowMinMaxButtonsHint|Qt::WindowSystemMenuHint; + _traits->windowDecoration = windowDecoration; + + if ( _widget ) + { + _widget->setWindowFlags( flags ); + + return true; + } + + return false; +} + +bool GraphicsWindowQt::getWindowDecoration() const +{ + return _traits->windowDecoration; +} + +void GraphicsWindowQt::grabFocus() +{ + if ( _widget ) + _widget->setFocus( Qt::ActiveWindowFocusReason ); +} + +void GraphicsWindowQt::grabFocusIfPointerInWindow() +{ + if ( _widget->underMouse() ) + _widget->setFocus( Qt::ActiveWindowFocusReason ); +} + +void GraphicsWindowQt::raiseWindow() +{ + if ( _widget ) + _widget->raise(); +} + +void GraphicsWindowQt::setWindowName( const std::string& name ) +{ + if ( _widget ) + _widget->setWindowTitle( name.c_str() ); +} + +std::string GraphicsWindowQt::getWindowName() +{ + return _widget ? _widget->windowTitle().toStdString() : ""; +} + +void GraphicsWindowQt::useCursor( bool cursorOn ) +{ + if ( _widget ) + { + _traits->useCursor = cursorOn; + if ( !cursorOn ) _widget->setCursor( Qt::BlankCursor ); + else _widget->setCursor( _currentCursor ); + } +} + +void GraphicsWindowQt::setCursor( MouseCursor cursor ) +{ + if ( cursor==InheritCursor && _widget ) + { + _widget->unsetCursor(); + } + + switch ( cursor ) + { + case NoCursor: _currentCursor = Qt::BlankCursor; break; + case RightArrowCursor: case LeftArrowCursor: _currentCursor = Qt::ArrowCursor; break; + case InfoCursor: _currentCursor = Qt::SizeAllCursor; break; + case DestroyCursor: _currentCursor = Qt::ForbiddenCursor; break; + case HelpCursor: _currentCursor = Qt::WhatsThisCursor; break; + case CycleCursor: _currentCursor = Qt::ForbiddenCursor; break; + case SprayCursor: _currentCursor = Qt::SizeAllCursor; break; + case WaitCursor: _currentCursor = Qt::WaitCursor; break; + case TextCursor: _currentCursor = Qt::IBeamCursor; break; + case CrosshairCursor: _currentCursor = Qt::CrossCursor; break; + case HandCursor: _currentCursor = Qt::OpenHandCursor; break; + case UpDownCursor: _currentCursor = Qt::SizeVerCursor; break; + case LeftRightCursor: _currentCursor = Qt::SizeHorCursor; break; + case TopSideCursor: case BottomSideCursor: _currentCursor = Qt::UpArrowCursor; break; + case LeftSideCursor: case RightSideCursor: _currentCursor = Qt::SizeHorCursor; break; + case TopLeftCorner: _currentCursor = Qt::SizeBDiagCursor; break; + case TopRightCorner: _currentCursor = Qt::SizeFDiagCursor; break; + case BottomRightCorner: _currentCursor = Qt::SizeBDiagCursor; break; + case BottomLeftCorner: _currentCursor = Qt::SizeFDiagCursor; break; + default: break; + }; + if ( _widget ) _widget->setCursor( _currentCursor ); +} + +bool GraphicsWindowQt::valid() const +{ + return _widget && _widget->isValid(); +} + +bool GraphicsWindowQt::realizeImplementation() +{ + // save the current context + // note: this will save only Qt-based contexts + const QGLContext *savedContext = QGLContext::currentContext(); + + // initialize GL context for the widget + if ( !valid() ) + _widget->glInit(); + + // make current + _realized = true; + bool result = makeCurrent(); + _realized = false; + + // fail if we do not have current context + if ( !result ) + { + if ( savedContext ) + const_cast< QGLContext* >( savedContext )->makeCurrent(); + + OSG_WARN << "Window realize: Can make context current." << std::endl; + return false; + } + + _realized = true; + + // make sure the event queue has the correct window rectangle size and input range + getEventQueue()->syncWindowRectangleWithGraphicsContext(); + + // make this window's context not current + // note: this must be done as we will probably make the context current from another thread + // and it is not allowed to have one context current in two threads + if( !releaseContext() ) + OSG_WARN << "Window realize: Can not release context." << std::endl; + + // restore previous context + if ( savedContext ) + const_cast< QGLContext* >( savedContext )->makeCurrent(); + + return true; +} + +bool GraphicsWindowQt::isRealizedImplementation() const +{ + return _realized; +} + +void GraphicsWindowQt::closeImplementation() +{ + if ( _widget ) + _widget->close(); + _realized = false; +} + +void GraphicsWindowQt::runOperations() +{ + // While in graphics thread this is last chance to do something useful before + // graphics thread will execute its operations. + if (_widget->getNumDeferredEvents() > 0) + _widget->processDeferredEvents(); + + if (QGLContext::currentContext() != _widget->context()) + _widget->makeCurrent(); + + GraphicsWindow::runOperations(); +} + +bool GraphicsWindowQt::makeCurrentImplementation() +{ + if (_widget->getNumDeferredEvents() > 0) + _widget->processDeferredEvents(); + + _widget->makeCurrent(); + + return true; +} + +bool GraphicsWindowQt::releaseContextImplementation() +{ + _widget->doneCurrent(); + return true; +} + +void GraphicsWindowQt::swapBuffersImplementation() +{ + _widget->swapBuffers(); + + // FIXME: the processDeferredEvents should really be executed in a GUI (main) thread context but + // I couln't find any reliable way to do this. For now, lets hope non of *GUI thread only operations* will + // be executed in a QGLWidget::event handler. On the other hand, calling GUI only operations in the + // QGLWidget event handler is an indication of a Qt bug. + if (_widget->getNumDeferredEvents() > 0) + _widget->processDeferredEvents(); + + // We need to call makeCurrent here to restore our previously current context + // which may be changed by the processDeferredEvents function. + if (QGLContext::currentContext() != _widget->context()) + _widget->makeCurrent(); +} + +void GraphicsWindowQt::requestWarpPointer( float x, float y ) +{ + if ( _widget ) + QCursor::setPos( _widget->mapToGlobal(QPoint((int)x,(int)y)) ); +} + + +class QtWindowingSystem : public osg::GraphicsContext::WindowingSystemInterface +{ +public: + + QtWindowingSystem() + { + OSG_INFO << "QtWindowingSystemInterface()" << std::endl; + } + + ~QtWindowingSystem() + { + if (osg::Referenced::getDeleteHandler()) + { + osg::Referenced::getDeleteHandler()->setNumFramesToRetainObjects(0); + osg::Referenced::getDeleteHandler()->flushAll(); + } + } + + // Access the Qt windowing system through this singleton class. + static QtWindowingSystem* getInterface() + { + static QtWindowingSystem* qtInterface = new QtWindowingSystem; + return qtInterface; + } + + // Return the number of screens present in the system + virtual unsigned int getNumScreens( const osg::GraphicsContext::ScreenIdentifier& /*si*/ ) + { + OSG_WARN << "osgQt: getNumScreens() not implemented yet." << std::endl; + return 0; + } + + // Return the resolution of specified screen + // (0,0) is returned if screen is unknown + virtual void getScreenSettings( const osg::GraphicsContext::ScreenIdentifier& /*si*/, osg::GraphicsContext::ScreenSettings & /*resolution*/ ) + { + OSG_WARN << "osgQt: getScreenSettings() not implemented yet." << std::endl; + } + + // Set the resolution for given screen + virtual bool setScreenSettings( const osg::GraphicsContext::ScreenIdentifier& /*si*/, const osg::GraphicsContext::ScreenSettings & /*resolution*/ ) + { + OSG_WARN << "osgQt: setScreenSettings() not implemented yet." << std::endl; + return false; + } + + // Enumerates available resolutions + virtual void enumerateScreenSettings( const osg::GraphicsContext::ScreenIdentifier& /*screenIdentifier*/, osg::GraphicsContext::ScreenSettingsList & /*resolution*/ ) + { + OSG_WARN << "osgQt: enumerateScreenSettings() not implemented yet." << std::endl; + } + + // Create a graphics context with given traits + virtual osg::GraphicsContext* createGraphicsContext( osg::GraphicsContext::Traits* traits ) + { + if (traits->pbuffer) + { + OSG_WARN << "osgQt: createGraphicsContext - pbuffer not implemented yet." << std::endl; + return NULL; + } + else + { + osg::ref_ptr< GraphicsWindowQt > window = new GraphicsWindowQt( traits ); + if (window->valid()) return window.release(); + else return NULL; + } + } + +private: + + // No implementation for these + QtWindowingSystem( const QtWindowingSystem& ); + QtWindowingSystem& operator=( const QtWindowingSystem& ); +}; + + +// declare C entry point for static compilation. +extern "C" void graphicswindow_Qt(void) +{ + osg::GraphicsContext::setWindowingSystemInterface(QtWindowingSystem::getInterface()); +} + + +void osgQt::initQtWindowingSystem() +{ + graphicswindow_Qt(); +} + + + +void osgQt::setViewer( osgViewer::ViewerBase *viewer ) +{ + HeartBeat::instance()->init( viewer ); +} + + +/// Constructor. Must be called from main thread. +HeartBeat::HeartBeat() : _timerId( 0 ) +{ +} + + +/// Destructor. Must be called from main thread. +HeartBeat::~HeartBeat() +{ + stopTimer(); +} + +HeartBeat* HeartBeat::instance() +{ + if (!heartBeat) + { + heartBeat = new HeartBeat(); + } + return heartBeat; +} + +void HeartBeat::stopTimer() +{ + if ( _timerId != 0 ) + { + killTimer( _timerId ); + _timerId = 0; + } +} + + +/// Initializes the loop for viewer. Must be called from main thread. +void HeartBeat::init( osgViewer::ViewerBase *viewer ) +{ + if( _viewer == viewer ) + return; + + stopTimer(); + + _viewer = viewer; + + if( viewer ) + { + _timerId = startTimer( 0 ); + _lastFrameStartTime.setStartTick( 0 ); + } +} + + +void HeartBeat::timerEvent( QTimerEvent */*event*/ ) +{ + osg::ref_ptr< osgViewer::ViewerBase > viewer; + if( !_viewer.lock( viewer ) ) + { + // viewer has been deleted -> stop timer + stopTimer(); + return; + } + + // limit the frame rate + if( viewer->getRunMaxFrameRate() > 0.0) + { + double dt = _lastFrameStartTime.time_s(); + double minFrameTime = 1.0 / viewer->getRunMaxFrameRate(); + if (dt < minFrameTime) + OpenThreads::Thread::microSleep(static_cast(1000000.0*(minFrameTime-dt))); + } + else + { + // avoid excessive CPU loading when no frame is required in ON_DEMAND mode + if( viewer->getRunFrameScheme() == osgViewer::ViewerBase::ON_DEMAND ) + { + double dt = _lastFrameStartTime.time_s(); + if (dt < 0.01) + OpenThreads::Thread::microSleep(static_cast(1000000.0*(0.01-dt))); + } + + // record start frame time + _lastFrameStartTime.setStartTick(); + + // make frame + if( viewer->getRunFrameScheme() == osgViewer::ViewerBase::ON_DEMAND ) + { + if( viewer->checkNeedToDoFrame() ) + { + viewer->frame(); + } + } + else + { + viewer->frame(); + } + } +} From b77ed829b963179e4848035b55eb71ce06625040 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 15 Feb 2016 15:17:23 +0100 Subject: [PATCH 3162/3725] Revert "Use Qt5 on travis to match the PPA's OSG build" This reverts commit 3c717a63603b53b301370bdf7cdef12441582748. --- CI/before_install.linux.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CI/before_install.linux.sh b/CI/before_install.linux.sh index b8d8b45e2..1c02bc8d9 100755 --- a/CI/before_install.linux.sh +++ b/CI/before_install.linux.sh @@ -11,11 +11,11 @@ sudo apt-get update -qq sudo apt-get install -qq libgtest-dev google-mock sudo apt-get install -qq libboost-filesystem-dev libboost-program-options-dev libboost-system-dev libboost-thread-dev sudo apt-get install -qq libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libswresample-dev -sudo apt-get install -qq libbullet-dev libopenscenegraph-dev libmygui-dev libsdl2-dev libunshield-dev libtinyxml-dev libopenal-dev qtbase5-dev +sudo apt-get install -qq libbullet-dev libopenscenegraph-dev libmygui-dev libsdl2-dev libunshield-dev libtinyxml-dev libopenal-dev libqt4-dev if [ "${ANALYZE}" ]; then sudo apt-get install -qq clang-3.6; fi sudo mkdir /usr/src/gtest/build cd /usr/src/gtest/build -sudo cmake .. -DBUILD_SHARED_LIBS=1 -DDESIRED_QT_VERSION=5 +sudo cmake .. -DBUILD_SHARED_LIBS=1 sudo make -j4 sudo ln -s /usr/src/gtest/build/libgtest.so /usr/lib/libgtest.so sudo ln -s /usr/src/gtest/build/libgtest_main.so /usr/lib/libgtest_main.so From 80392775efe2c594005bd89ca1450dc934b9e19c Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 15 Feb 2016 15:18:06 +0100 Subject: [PATCH 3163/3725] Fix copy&paste error --- extern/osgQt/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/extern/osgQt/CMakeLists.txt b/extern/osgQt/CMakeLists.txt index e8a456da9..3bd08a390 100644 --- a/extern/osgQt/CMakeLists.txt +++ b/extern/osgQt/CMakeLists.txt @@ -6,7 +6,6 @@ set(OSGQT_SOURCE_FILES GraphicsWindowQt.cpp ) -include_directories(${FFMPEG_INCLUDE_DIRS}) add_library(${OSGQT_LIBRARY} STATIC ${OSGQT_SOURCE_FILES}) if (DESIRED_QT_VERSION MATCHES 4) From 3f403466360af2343e0f7527f7a91c70dcc5096d Mon Sep 17 00:00:00 2001 From: Aesylwinn Date: Mon, 15 Feb 2016 19:49:54 -0500 Subject: [PATCH 3164/3725] Implemented a wrapper for DialInfo::SelectStruct --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/world/infoselectwrapper.cpp | 855 ++++++++++++++++++ apps/opencs/model/world/infoselectwrapper.hpp | 238 +++++ 3 files changed, 1094 insertions(+), 1 deletion(-) create mode 100644 apps/opencs/model/world/infoselectwrapper.cpp create mode 100644 apps/opencs/model/world/infoselectwrapper.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 0bde541bf..7b825232b 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -26,7 +26,7 @@ opencs_units_noqt (model/world universalid record commands columnbase columnimp scriptcontext cell refidcollection refidadapter refiddata refidadapterimp ref collectionbase refcollection columns infocollection tablemimedata cellcoordinates cellselection resources resourcesmanager scope pathgrid landtexture land nestedtablewrapper nestedcollection nestedcoladapterimp nestedinfocollection - idcompletionmanager metadata defaultgmsts + idcompletionmanager metadata defaultgmsts infoselectwrapper ) opencs_hdrs_noqt (model/world diff --git a/apps/opencs/model/world/infoselectwrapper.cpp b/apps/opencs/model/world/infoselectwrapper.cpp new file mode 100644 index 000000000..42cbabf72 --- /dev/null +++ b/apps/opencs/model/world/infoselectwrapper.cpp @@ -0,0 +1,855 @@ +#include "infoselectwrapper.hpp" + +#include +#include + +const size_t CSMWorld::ConstInfoSelectWrapper::RuleMinSize = 5; + +const size_t CSMWorld::ConstInfoSelectWrapper::FunctionPrefixOffset = 1; +const size_t CSMWorld::ConstInfoSelectWrapper::FunctionIndexOffset = 2; +const size_t CSMWorld::ConstInfoSelectWrapper::RelationIndexOffset = 4; +const size_t CSMWorld::ConstInfoSelectWrapper::VarNameOffset = 5; + +const char* CSMWorld::ConstInfoSelectWrapper::FunctionEnumStrings[] = +{ + "Rank Low", + "Rank High", + "Rank Requirement", + "Reputation", + "Health Percent", + "PC Reputation", + "PC Level", + "PC Health Percent", + "PC Magicka", + "PC Fatigue", + "PC Strength", + "PC Block", + "PC Armorer", + "PC Medium Armor", + "PC Heavy Armor", + "PC Blunt Weapon", + "PC Long Blade", + "PC Axe", + "PC Spear", + "PC Athletics", + "PC Enchant", + "PC Detruction", + "PC Alteration", + "PC Illusion", + "PC Conjuration", + "PC Mysticism", + "PC Restoration", + "PC Alchemy", + "PC Unarmored", + "PC Security", + "PC Sneak", + "PC Acrobatics", + "PC Light Armor", + "PC Shorth Blade", + "PC Marksman", + "PC Merchantile", + "PC Speechcraft", + "PC Hand to Hand", + "PC Sex", + "PC Expelled", + "PC Common Disease", + "PC Blight Disease", + "PC Clothing Modifier", + "PC Crime Level", + "Same Sex", + "Same Race", + "Same Faction", + "Faction Rank Difference", + "Detected", + "Alarmed", + "Choice", + "PC Intelligence", + "PC Willpower", + "PC Agility", + "PC Speed", + "PC Endurance", + "PC Personality", + "PC Luck", + "PC Corpus", + "Weather", + "PC Vampire", + "PC Level", + "PC Attacked", + "Talked to PC", + "PC Health", + "Creature Target", + "Friend Hit", + "Fight", + "Hello", + "Alarm", + "Flee", + "Should Attack", + "Werewolf", + "PC Werewolf Kills", + "Global", + "Local", + "Journal", + "Item", + "Dead", + "Not Id", + "Not Faction", + "Not Class", + "Not Race", + "Not Cell", + "Not Local", + 0 +}; + +const char* CSMWorld::ConstInfoSelectWrapper::RelationEnumStrings[] = +{ + "=", + "!=", + ">", + ">=", + "<", + "<=", + 0 +}; + +const char* CSMWorld::ConstInfoSelectWrapper::ComparisonEnumStrings[] = +{ + "Boolean", + "Integer", + "Numeric", + 0 +}; + +// static functions + +std::string CSMWorld::ConstInfoSelectWrapper::convertToString(FunctionName name) +{ + if (name < Function_None) + return FunctionEnumStrings[name]; + else + return "(Invalid Data: Function)"; +} + +std::string CSMWorld::ConstInfoSelectWrapper::convertToString(RelationType type) +{ + if (type < Relation_None) + return RelationEnumStrings[type]; + else + return "(Invalid Data: Relation)"; +} + +std::string CSMWorld::ConstInfoSelectWrapper::convertToString(ComparisonType type) +{ + if (type < Comparison_None) + return ComparisonEnumStrings[type]; + else + return "(Invalid Data: Comparison)"; +} + +// ConstInfoSelectWrapper + +CSMWorld::ConstInfoSelectWrapper::ConstInfoSelectWrapper(const ESM::DialInfo::SelectStruct& select) + : mConstSelect(select) +{ + readRule(); +} + +CSMWorld::ConstInfoSelectWrapper::FunctionName CSMWorld::ConstInfoSelectWrapper::getFunctionName() const +{ + return mFunctionName; +} + +CSMWorld::ConstInfoSelectWrapper::RelationType CSMWorld::ConstInfoSelectWrapper::getRelationType() const +{ + return mRelationType; +} + +CSMWorld::ConstInfoSelectWrapper::ComparisonType CSMWorld::ConstInfoSelectWrapper::getComparisonType() const +{ + return mComparisonType; +} + +bool CSMWorld::ConstInfoSelectWrapper::hasVariable() const +{ + return mHasVariable; +} + +const std::string& CSMWorld::ConstInfoSelectWrapper::getVariableName() const +{ + return mVariableName; +} + +bool CSMWorld::ConstInfoSelectWrapper::conditionIsAlwaysTrue() const +{ + if (!variantTypeIsValid()) + return false; + + if (mComparisonType == Comparison_Boolean || mComparisonType == Comparison_Integer) + { + if (mConstSelect.mValue.getType() == ESM::VT_Float) + return conditionIsAlwaysTrue(getConditionFloatRange(), getValidIntRange()); + else + return conditionIsAlwaysTrue(getConditionIntRange(), getValidIntRange()); + } + else if (mComparisonType == Comparison_Numeric) + { + if (mConstSelect.mValue.getType() == ESM::VT_Float) + return conditionIsAlwaysTrue(getConditionFloatRange(), getValidFloatRange()); + else + return conditionIsAlwaysTrue(getConditionIntRange(), getValidFloatRange()); + } + + return false; +} + +bool CSMWorld::ConstInfoSelectWrapper::conditionIsNeverTrue() const +{ + if (!variantTypeIsValid()) + return false; + + if (mComparisonType == Comparison_Boolean || mComparisonType == Comparison_Integer) + { + if (mConstSelect.mValue.getType() == ESM::VT_Float) + return conditionIsNeverTrue(getConditionFloatRange(), getValidIntRange()); + else + return conditionIsNeverTrue(getConditionIntRange(), getValidIntRange()); + } + else if (mComparisonType == Comparison_Numeric) + { + if (mConstSelect.mValue.getType() == ESM::VT_Float) + return conditionIsNeverTrue(getConditionFloatRange(), getValidFloatRange()); + else + return conditionIsNeverTrue(getConditionIntRange(), getValidFloatRange()); + } + + return false; +} + +bool CSMWorld::ConstInfoSelectWrapper::variantTypeIsValid() const +{ + return (mConstSelect.mValue.getType() == ESM::VT_Int || mConstSelect.mValue.getType() == ESM::VT_Short || + mConstSelect.mValue.getType() == ESM::VT_Long || mConstSelect.mValue.getType() == ESM::VT_Float); +} + +const ESM::Variant& CSMWorld::ConstInfoSelectWrapper::getVariant() const +{ + return mConstSelect.mValue; +} + +void CSMWorld::ConstInfoSelectWrapper::readRule() +{ + if (mConstSelect.mSelectRule.size() < RuleMinSize) + throw std::runtime_error("InfoSelectWrapper: rule is to small"); + + readFunctionName(); + readRelationType(); + readVariableName(); + updateHasVariable(); + updateComparisonType(); +} + +void CSMWorld::ConstInfoSelectWrapper::readFunctionName() +{ + char functionPrefix = mConstSelect.mSelectRule[FunctionPrefixOffset]; + std::string functionIndex = mConstSelect.mSelectRule.substr(FunctionIndexOffset, 2); + int convertedIndex = -1; + + // Read in function index, form ## from 00 .. 73, skip leading zero + if (functionIndex[0] == '0') + functionIndex = functionIndex[1]; + + std::stringstream stream; + stream << functionIndex; + stream >> convertedIndex; + + switch (functionPrefix) + { + case '1': + if (convertedIndex >= 0 && convertedIndex <= 73) + mFunctionName = static_cast(convertedIndex); + else + mFunctionName = Function_None; + break; + + case '2': mFunctionName = Function_Global; break; + case '3': mFunctionName = Function_Local; break; + case '4': mFunctionName = Function_Journal; break; + case '5': mFunctionName = Function_Item; break; + case '6': mFunctionName = Function_Dead; break; + case '7': mFunctionName = Function_NotId; break; + case '8': mFunctionName = Function_NotFaction; break; + case '9': mFunctionName = Function_NotClass; break; + case 'A': mFunctionName = Function_NotRace; break; + case 'B': mFunctionName = Function_NotCell; break; + case 'C': mFunctionName = Function_NotLocal; break; + default: mFunctionName = Function_None; break; + } +} + +void CSMWorld::ConstInfoSelectWrapper::readRelationType() +{ + char relationIndex = mConstSelect.mSelectRule[RelationIndexOffset]; + + switch (relationIndex) + { + case '0': mRelationType = Relation_Equal; break; + case '1': mRelationType = Relation_NotEqual; break; + case '2': mRelationType = Relation_Greater; break; + case '3': mRelationType = Relation_GreaterOrEqual; break; + case '4': mRelationType = Relation_Less; break; + case '5': mRelationType = Relation_LessOrEqual; break; + default: mRelationType = Relation_None; + } +} + +void CSMWorld::ConstInfoSelectWrapper::readVariableName() +{ + if (mConstSelect.mSelectRule.size() >= VarNameOffset) + mVariableName = mConstSelect.mSelectRule.substr(VarNameOffset); + else + mVariableName.clear(); +} + +void CSMWorld::ConstInfoSelectWrapper::updateHasVariable() +{ + switch (mFunctionName) + { + case Function_Global: + case Function_Local: + case Function_Journal: + case Function_Item: + case Function_Dead: + case Function_NotId: + case Function_NotFaction: + case Function_NotClass: + case Function_NotRace: + case Function_NotCell: + case Function_NotLocal: + mHasVariable = true; + break; + + default: + mHasVariable = false; + break; + } +} + +void CSMWorld::ConstInfoSelectWrapper::updateComparisonType() +{ + switch (mFunctionName) + { + // Boolean + case Function_NotId: + case Function_NotFaction: + case Function_NotClass: + case Function_NotRace: + case Function_NotCell: + case Function_PcExpelled: + case Function_PcCommonDisease: + case Function_PcBlightDisease: + case Function_SameSex: + case Function_SameRace: + case Function_SameFaction: + case Function_Detected: + case Function_Alarmed: + case Function_PcCorpus: + case Function_PcVampire: + case Function_Attacked: + case Function_TalkedToPc: + case Function_ShouldAttack: + case Function_Werewolf: + mComparisonType = Comparison_Boolean; + break; + + // Integer + case Function_Journal: + case Function_Item: + case Function_Dead: + case Function_RankLow: + case Function_RankHigh: + case Function_RankRequirement: + case Function_Reputation: + case Function_PcReputation: + case Function_PcLevel: + case Function_PcStrength: + case Function_PcBlock: + case Function_PcArmorer: + case Function_PcMediumArmor: + case Function_PcHeavyArmor: + case Function_PcBluntWeapon: + case Function_PcLongBlade: + case Function_PcAxe: + case Function_PcSpear: + case Function_PcAthletics: + case Function_PcEnchant: + case Function_PcDestruction: + case Function_PcAlteration: + case Function_PcIllusion: + case Function_PcConjuration: + case Function_PcMysticism: + case Function_PcRestoration: + case Function_PcAlchemy: + case Function_PcUnarmored: + case Function_PcSecurity: + case Function_PcSneak: + case Function_PcAcrobatics: + case Function_PcLightArmor: + case Function_PcShortBlade: + case Function_PcMarksman: + case Function_PcMerchantile: + case Function_PcSpeechcraft: + case Function_PcHandToHand: + case Function_PcGender: + case Function_PcClothingModifier: + case Function_PcCrimeLevel: + case Function_FactionRankDifference: + case Function_Choice: + case Function_PcIntelligence: + case Function_PcWillpower: + case Function_PcAgility: + case Function_PcSpeed: + case Function_PcEndurance: + case Function_PcPersonality: + case Function_PcLuck: + case Function_Weather: + case Function_Level: + case Function_CreatureTarget: + case Function_FriendHit: + case Function_Fight: + case Function_Hello: + case Function_Alarm: + case Function_Flee: + case Function_PcWerewolfKills: + mComparisonType = Comparison_Integer; + break; + + // Numeric + case Function_Global: + case Function_Local: + case Function_NotLocal: + case Function_Health_Percent: + case Function_PcHealthPercent: + case Function_PcMagicka: + case Function_PcFatigue: + case Function_PcHealth: + mComparisonType = Comparison_Numeric; + break; + + default: + mComparisonType = Comparison_None; + break; + } +} + +std::pair CSMWorld::ConstInfoSelectWrapper::getConditionIntRange() const +{ + const int IntMax = std::numeric_limits::max(); + const int IntMin = std::numeric_limits::min(); + const std::pair InvalidRange(IntMax, IntMin); + + int value = mConstSelect.mValue.getInteger(); + + switch (mRelationType) + { + case Relation_Equal: + case Relation_NotEqual: + return std::pair(value, value); + + case Relation_Greater: + if (value == IntMax) + { + return InvalidRange; + } + else + { + return std::pair(value + 1, IntMax); + } + break; + + case Relation_GreaterOrEqual: + return std::pair(value, IntMax); + + case Relation_Less: + if (value == IntMin) + { + return InvalidRange; + } + else + { + return std::pair(IntMin, value - 1); + } + + case Relation_LessOrEqual: + return std::pair(IntMin, value); + + default: + throw std::logic_error("InfoSelectWrapper: relation does not have a range"); + } +} + +std::pair CSMWorld::ConstInfoSelectWrapper::getConditionFloatRange() const +{ + const float FloatMax = std::numeric_limits::infinity(); + const float FloatMin = -std::numeric_limits::infinity(); + const float Epsilon = std::numeric_limits::epsilon(); + const std::pair InvalidRange(FloatMax, FloatMin); + + float value = mConstSelect.mValue.getFloat(); + + switch (mRelationType) + { + case Relation_Equal: + case Relation_NotEqual: + return std::pair(value, value); + + case Relation_Greater: + return std::pair(value + Epsilon, FloatMax); + + case Relation_GreaterOrEqual: + return std::pair(value, FloatMax); + + case Relation_Less: + return std::pair(FloatMin, value - Epsilon); + + case Relation_LessOrEqual: + return std::pair(FloatMin, value); + + default: + throw std::logic_error("InfoSelectWrapper: given relation does not have a range"); + } +} + +std::pair CSMWorld::ConstInfoSelectWrapper::getValidIntRange() const +{ + const int IntMax = std::numeric_limits::max(); + const int IntMin = std::numeric_limits::min(); + + switch (mFunctionName) + { + // TODO these need to be checked + + // Boolean + case Function_NotId: + case Function_NotFaction: + case Function_NotClass: + case Function_NotRace: + case Function_NotCell: + case Function_PcExpelled: + case Function_PcCommonDisease: + case Function_PcBlightDisease: + case Function_SameSex: + case Function_SameRace: + case Function_SameFaction: + case Function_Detected: + case Function_Alarmed: + case Function_PcCorpus: + case Function_PcVampire: + case Function_Attacked: + case Function_TalkedToPc: + case Function_ShouldAttack: + case Function_Werewolf: + return std::pair(0,1); + + // Integer + case Function_RankLow: + case Function_RankHigh: + case Function_Reputation: + case Function_PcReputation: + return std::pair(IntMin, IntMax); + + case Function_Journal: + case Function_Item: + case Function_Dead: + case Function_PcLevel: + case Function_PcStrength: + case Function_PcBlock: + case Function_PcArmorer: + case Function_PcMediumArmor: + case Function_PcHeavyArmor: + case Function_PcBluntWeapon: + case Function_PcLongBlade: + case Function_PcAxe: + case Function_PcSpear: + case Function_PcAthletics: + case Function_PcEnchant: + case Function_PcDestruction: + case Function_PcAlteration: + case Function_PcIllusion: + case Function_PcConjuration: + case Function_PcMysticism: + case Function_PcRestoration: + case Function_PcAlchemy: + case Function_PcUnarmored: + case Function_PcSecurity: + case Function_PcSneak: + case Function_PcAcrobatics: + case Function_PcLightArmor: + case Function_PcShortBlade: + case Function_PcMarksman: + case Function_PcMerchantile: + case Function_PcSpeechcraft: + case Function_PcHandToHand: + case Function_PcClothingModifier: + case Function_PcCrimeLevel: + case Function_Choice: + case Function_PcIntelligence: + case Function_PcWillpower: + case Function_PcAgility: + case Function_PcSpeed: + case Function_PcEndurance: + case Function_PcPersonality: + case Function_PcLuck: + case Function_Level: + case Function_Fight: + case Function_Hello: + case Function_Alarm: + case Function_Flee: + case Function_PcWerewolfKills: + return std::pair(0, IntMax); + + case Function_Weather: + return std::pair(0, 9); + + case Function_FriendHit: + return std::pair(0,4); + + case Function_RankRequirement: + return std::pair(0, 3); + + case Function_CreatureTarget: + return std::pair(0,2); + + case Function_PcGender: + return std::pair(0,1); + + case Function_FactionRankDifference: + return std::pair(-9, 9); + + // Numeric + case Function_Global: + case Function_Local: + case Function_NotLocal: + return std::pair(IntMin, IntMax); + + case Function_Health_Percent: + case Function_PcHealthPercent: + return std::pair(0, 100); + + case Function_PcMagicka: + case Function_PcFatigue: + case Function_PcHealth: + return std::pair(0,0); + + default: + throw std::runtime_error("InfoSelectWrapper: function does not exist"); + } +} + +std::pair CSMWorld::ConstInfoSelectWrapper::getValidFloatRange() const +{ + const float FloatMax = std::numeric_limits::infinity(); + const float FloatMin = -std::numeric_limits::infinity(); + + switch (mFunctionName) + { + // Numeric + case Function_Global: + case Function_Local: + case Function_NotLocal: + return std::pair(FloatMin, FloatMax); + + case Function_Health_Percent: + case Function_PcHealthPercent: + return std::pair(0, 100); + + case Function_PcMagicka: + case Function_PcFatigue: + case Function_PcHealth: + return std::pair(0,0); + + default: + throw std::runtime_error("InfoSelectWrapper: function does not exist or is not numeric"); + } +} + +template +bool CSMWorld::ConstInfoSelectWrapper::rangeContains(T1 value, std::pair range) const +{ + return (value >= range.first && value <= range.second); +} + +template +bool CSMWorld::ConstInfoSelectWrapper::rangesOverlap(std::pair range1, std::pair range2) const +{ + // One of the bounds of either range should fall within the other range + return + (range1.first <= range2.first && range2.first <= range1.second) || + (range1.first <= range2.second && range2.second <= range1.second) || + (range2.first <= range1.first && range1.first <= range2.second) || + (range2.first <= range1.second && range1.second <= range2.second); +} + +template +bool CSMWorld::ConstInfoSelectWrapper::rangesMatch(std::pair range1, std::pair range2) const +{ + return (range1.first == range2.first && range1.second == range2.second); +} + +template +bool CSMWorld::ConstInfoSelectWrapper::conditionIsAlwaysTrue(std::pair conditionRange, + std::pair validRange) const +{ + + switch (mRelationType) + { + case Relation_Equal: + case Relation_Greater: + case Relation_GreaterOrEqual: + case Relation_Less: + case Relation_LessOrEqual: + // If ranges are same, it will always be true + return rangesMatch(conditionRange, validRange); + + case Relation_NotEqual: + // If value is not within range, it will always be true + return !rangeContains(conditionRange.first, validRange); + + default: + throw std::logic_error("InfoCondition: operator can not be used to compare"); + } + + return false; +} + +template +bool CSMWorld::ConstInfoSelectWrapper::conditionIsNeverTrue(std::pair conditionRange, + std::pair validRange) const +{ + switch (mRelationType) + { + case Relation_Equal: + case Relation_Greater: + case Relation_GreaterOrEqual: + case Relation_Less: + case Relation_LessOrEqual: + // If ranges do not overlap, it will never be true + return !rangesOverlap(conditionRange, validRange); + + case Relation_NotEqual: + // If the value is the only value withing the range, it will never be true + return rangesOverlap(conditionRange, validRange); + + default: + throw std::logic_error("InfoCondition: operator can not be used to compare"); + } + + return false; +} + +// InfoSelectWrapper + +CSMWorld::InfoSelectWrapper::InfoSelectWrapper(ESM::DialInfo::SelectStruct& select) + : CSMWorld::ConstInfoSelectWrapper(select), mSelect(select) +{ +} + +void CSMWorld::InfoSelectWrapper::setFunctionName(FunctionName name) +{ + mFunctionName = name; + updateHasVariable(); + updateComparisonType(); +} + +void CSMWorld::InfoSelectWrapper::setRelationType(RelationType type) +{ + mRelationType = type; +} + +void CSMWorld::InfoSelectWrapper::setVariableName(const std::string& name) +{ + mVariableName = name; +} + +void CSMWorld::InfoSelectWrapper::setDefaults() +{ + if (!variantTypeIsValid()) + mSelect.mValue.setType(ESM::VT_Int); + + switch (mComparisonType) + { + case Comparison_Boolean: + setRelationType(Relation_Equal); + mSelect.mValue.setInteger(1); + break; + + case Comparison_Integer: + case Comparison_Numeric: + setRelationType(Relation_Greater); + mSelect.mValue.setInteger(0); + break; + + default: + // Do nothing + break; + } + + update(); +} + +void CSMWorld::InfoSelectWrapper::update() +{ + std::ostringstream stream; + + // Leading 0 + stream << '0'; + + // Write Function + + bool writeIndex = false; + int functionIndex = static_cast(mFunctionName); + + switch (mFunctionName) + { + case Function_None: stream << '0'; break; + case Function_Global: stream << '2'; break; + case Function_Local: stream << '3'; break; + case Function_Journal: stream << '4'; break; + case Function_Item: stream << '5'; break; + case Function_Dead: stream << '6'; break; + case Function_NotId: stream << '7'; break; + case Function_NotFaction: stream << '8'; break; + case Function_NotClass: stream << '9'; break; + case Function_NotRace: stream << 'A'; break; + case Function_NotCell: stream << 'B'; break; + case Function_NotLocal: stream << 'C'; break; + default: stream << '1'; writeIndex = true; break; + } + + if (writeIndex && functionIndex < 10) // leading 0 + stream << '0' << functionIndex; + else if (writeIndex) + stream << functionIndex; + else + stream << "00"; + + // Write Relation + switch (mRelationType) + { + case Relation_Equal: stream << '0'; break; + case Relation_NotEqual: stream << '1'; break; + case Relation_Greater: stream << '2'; break; + case Relation_GreaterOrEqual: stream << '3'; break; + case Relation_Less: stream << '4'; break; + case Relation_LessOrEqual: stream << '5'; break; + default: stream << '0'; break; + } + + if (mHasVariable) + stream << mVariableName; + + mSelect.mSelectRule = stream.str(); +} + +ESM::Variant& CSMWorld::InfoSelectWrapper::getVariant() +{ + return mSelect.mValue; +} diff --git a/apps/opencs/model/world/infoselectwrapper.hpp b/apps/opencs/model/world/infoselectwrapper.hpp new file mode 100644 index 000000000..8ccae0efa --- /dev/null +++ b/apps/opencs/model/world/infoselectwrapper.hpp @@ -0,0 +1,238 @@ +#ifndef CSM_WORLD_INFOSELECTWRAPPER_H +#define CSM_WORLD_INFOSELECTWRAPPER_H + +#include + +namespace CSMWorld +{ + // ESM::DialInfo::SelectStruct.mSelectRule + // 012345... + // ^^^ ^^ + // ||| || + // ||| |+------------- condition variable string + // ||| +-------------- comparison type, ['0'..'5']; e.g. !=, <, >=, etc + // ||+---------------- function index (encoded, where function == '1') + // |+----------------- function, ['1'..'C']; e.g. Global, Local, Not ID, etc + // +------------------ unknown + // + + // Wrapper for DialInfo::SelectStruct + class ConstInfoSelectWrapper + { + public: + + // Order matters + enum FunctionName + { + Function_RankLow=0, + Function_RankHigh, + Function_RankRequirement, + Function_Reputation, + Function_Health_Percent, + Function_PcReputation, + Function_PcLevel, + Function_PcHealthPercent, + Function_PcMagicka, + Function_PcFatigue, + Function_PcStrength, + Function_PcBlock, + Function_PcArmorer, + Function_PcMediumArmor, + Function_PcHeavyArmor, + Function_PcBluntWeapon, + Function_PcLongBlade, + Function_PcAxe, + Function_PcSpear, + Function_PcAthletics, + Function_PcEnchant, + Function_PcDestruction, + Function_PcAlteration, + Function_PcIllusion, + Function_PcConjuration, + Function_PcMysticism, + Function_PcRestoration, + Function_PcAlchemy, + Function_PcUnarmored, + Function_PcSecurity, + Function_PcSneak, + Function_PcAcrobatics, + Function_PcLightArmor, + Function_PcShortBlade, + Function_PcMarksman, + Function_PcMerchantile, + Function_PcSpeechcraft, + Function_PcHandToHand, + Function_PcGender, + Function_PcExpelled, + Function_PcCommonDisease, + Function_PcBlightDisease, + Function_PcClothingModifier, + Function_PcCrimeLevel, + Function_SameSex, + Function_SameRace, + Function_SameFaction, + Function_FactionRankDifference, + Function_Detected, + Function_Alarmed, + Function_Choice, + Function_PcIntelligence, + Function_PcWillpower, + Function_PcAgility, + Function_PcSpeed, + Function_PcEndurance, + Function_PcPersonality, + Function_PcLuck, + Function_PcCorpus, + Function_Weather, + Function_PcVampire, + Function_Level, + Function_Attacked, + Function_TalkedToPc, + Function_PcHealth, + Function_CreatureTarget, + Function_FriendHit, + Function_Fight, + Function_Hello, + Function_Alarm, + Function_Flee, + Function_ShouldAttack, + Function_Werewolf, + Function_PcWerewolfKills=73, + + Function_Global, + Function_Local, + Function_Journal, + Function_Item, + Function_Dead, + Function_NotId, + Function_NotFaction, + Function_NotClass, + Function_NotRace, + Function_NotCell, + Function_NotLocal, + + Function_None + }; + + enum RelationType + { + Relation_Equal, + Relation_NotEqual, + Relation_Greater, + Relation_GreaterOrEqual, + Relation_Less, + Relation_LessOrEqual, + + Relation_None + }; + + enum ComparisonType + { + Comparison_Boolean, + Comparison_Integer, + Comparison_Numeric, + + Comparison_None + }; + + static const size_t RuleMinSize; + + static const size_t FunctionPrefixOffset; + static const size_t FunctionIndexOffset; + static const size_t RelationIndexOffset; + static const size_t VarNameOffset; + + static const char* FunctionEnumStrings[]; + static const char* RelationEnumStrings[]; + static const char* ComparisonEnumStrings[]; + + static std::string convertToString(FunctionName name); + static std::string convertToString(RelationType type); + static std::string convertToString(ComparisonType type); + + ConstInfoSelectWrapper(const ESM::DialInfo::SelectStruct& select); + + FunctionName getFunctionName() const; + RelationType getRelationType() const; + ComparisonType getComparisonType() const; + + bool hasVariable() const; + const std::string& getVariableName() const; + + bool conditionIsAlwaysTrue() const; + bool conditionIsNeverTrue() const; + bool variantTypeIsValid() const; + + const ESM::Variant& getVariant() const; + + protected: + + void readRule(); + void readFunctionName(); + void readRelationType(); + void readVariableName(); + void updateHasVariable(); + void updateComparisonType(); + + std::pair getConditionIntRange() const; + std::pair getConditionFloatRange() const; + + std::pair getValidIntRange() const; + std::pair getValidFloatRange() const; + + template + bool rangeContains(Type1 value, std::pair range) const; + + template + bool rangesOverlap(std::pair range1, std::pair range2) const; + + template + bool rangesMatch(std::pair range1, std::pair range2) const; + + template + bool conditionIsAlwaysTrue(std::pair conditionRange, std::pair validRange) const; + + template + bool conditionIsNeverTrue(std::pair conditionRange, std::pair validRange) const; + + FunctionName mFunctionName; + RelationType mRelationType; + ComparisonType mComparisonType; + + bool mHasVariable; + std::string mVariableName; + + private: + + const ESM::DialInfo::SelectStruct& mConstSelect; + }; + + // Wrapper for DialInfo::SelectStruct that can modify the wrapped select struct + class InfoSelectWrapper : public ConstInfoSelectWrapper + { + public: + + InfoSelectWrapper(ESM::DialInfo::SelectStruct& select); + + // Wrapped SelectStruct will not be modified until update() is called + void setFunctionName(FunctionName name); + void setRelationType(RelationType type); + void setVariableName(const std::string& name); + + // Modified wrapped SelectStruct + void update(); + + // This sets properties based on the function name to its defaults and updates the wrapped object + void setDefaults(); + + ESM::Variant& getVariant(); + + private: + + ESM::DialInfo::SelectStruct& mSelect; + + void writeRule(); + }; +} + +#endif From ed57293e5488b6ff57c13e5cac147195ab965f5a Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 16 Feb 2016 14:55:13 +0100 Subject: [PATCH 3165/3725] Allow '^' escape characters in books http://forum.openmw.org/viewtopic.php?f=2&t=3373&p=37584&sid=1a0b015e6716b1bced37fd398ef876c7 --- components/interpreter/defines.cpp | 19 ++++++++++--------- components/interpreter/defines.hpp | 6 +++--- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/components/interpreter/defines.cpp b/components/interpreter/defines.cpp index 2ceb857c4..a700253b6 100644 --- a/components/interpreter/defines.cpp +++ b/components/interpreter/defines.cpp @@ -26,13 +26,14 @@ namespace Interpreter{ return a.length() > b.length(); } - std::string fixDefinesReal(std::string text, char eschar, bool isBook, Context& context) + std::string fixDefinesReal(std::string text, bool dialogue, Context& context) { unsigned int start = 0; std::ostringstream retval; for(unsigned int i = 0; i < text.length(); i++) { - if(text[i] == eschar) + char eschar = text[i]; + if(eschar == '%' || eschar == '^') { retval << text.substr(start, i - start); std::string temp = Misc::StringUtils::lowerCase(text.substr(i+1, 100)); @@ -113,7 +114,7 @@ namespace Interpreter{ retval << context.getCurrentCellName(); } - else if(eschar == '%' && !isBook) { // In Dialogue, not messagebox + else if(!dialogue) { // In Dialogue, not messagebox if( (found = check(temp, "faction", &i, &start))){ retval << context.getNPCFaction(); } @@ -207,15 +208,15 @@ namespace Interpreter{ return retval.str (); } - std::string fixDefinesDialog(std::string text, Context& context){ - return fixDefinesReal(text, '%', false, context); + std::string fixDefinesDialog(const std::string& text, Context& context){ + return fixDefinesReal(text, true, context); } - std::string fixDefinesMsgBox(std::string text, Context& context){ - return fixDefinesReal(text, '^', false, context); + std::string fixDefinesMsgBox(const std::string& text, Context& context){ + return fixDefinesReal(text, false, context); } - std::string fixDefinesBook(std::string text, Context& context){ - return fixDefinesReal(text, '%', true, context); + std::string fixDefinesBook(const std::string& text, Context& context){ + return fixDefinesReal(text, false, context); } } diff --git a/components/interpreter/defines.hpp b/components/interpreter/defines.hpp index 00c4386b8..3471b2030 100644 --- a/components/interpreter/defines.hpp +++ b/components/interpreter/defines.hpp @@ -5,9 +5,9 @@ #include "context.hpp" namespace Interpreter{ - std::string fixDefinesDialog(std::string text, Context& context); - std::string fixDefinesMsgBox(std::string text, Context& context); - std::string fixDefinesBook(std::string text, Context& context); + std::string fixDefinesDialog(const std::string& text, Context& context); + std::string fixDefinesMsgBox(const std::string& text, Context& context); + std::string fixDefinesBook(const std::string& text, Context& context); } #endif From dececf6c3878d555e94dd548c7a5f5e58c0e4efd Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 16 Feb 2016 16:02:29 +0100 Subject: [PATCH 3166/3725] instance moving via drag in 3D scenes --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/view/render/cell.cpp | 13 ++ apps/opencs/view/render/cell.hpp | 2 + apps/opencs/view/render/instancemode.cpp | 160 +++++++++++++++++- apps/opencs/view/render/instancemode.hpp | 19 +++ apps/opencs/view/render/instancemovemode.cpp | 12 ++ apps/opencs/view/render/instancemovemode.hpp | 18 ++ apps/opencs/view/render/object.cpp | 137 ++++++++++++++- apps/opencs/view/render/object.hpp | 40 ++++- .../view/render/pagedworldspacewidget.cpp | 17 ++ .../view/render/pagedworldspacewidget.hpp | 3 + apps/opencs/view/render/scenewidget.cpp | 6 + apps/opencs/view/render/scenewidget.hpp | 3 + .../view/render/unpagedworldspacewidget.cpp | 6 + .../view/render/unpagedworldspacewidget.hpp | 3 + apps/opencs/view/render/worldspacewidget.hpp | 3 + 16 files changed, 428 insertions(+), 16 deletions(-) create mode 100644 apps/opencs/view/render/instancemovemode.cpp create mode 100644 apps/opencs/view/render/instancemovemode.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 6401e4222..ce0216066 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -85,7 +85,7 @@ opencs_units (view/widget opencs_units (view/render scenewidget worldspacewidget pagedworldspacewidget unpagedworldspacewidget - previewwidget editmode instancemode instanceselectionmode + previewwidget editmode instancemode instanceselectionmode instancemovemode ) opencs_units_noqt (view/render diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index e7b135891..d666304fa 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -338,3 +338,16 @@ std::vector > CSVRender::Cell::getSelection (un return result; } + +std::vector > CSVRender::Cell::getEdited (unsigned int elementMask) const +{ + std::vector > result; + + if (elementMask & Mask_Reference) + for (std::map::const_iterator iter (mObjects.begin()); + iter!=mObjects.end(); ++iter) + if (iter->second->isEdited()) + result.push_back (iter->second->getTag()); + + return result; +} diff --git a/apps/opencs/view/render/cell.hpp b/apps/opencs/view/render/cell.hpp index 22f9872e3..6cdafbf36 100644 --- a/apps/opencs/view/render/cell.hpp +++ b/apps/opencs/view/render/cell.hpp @@ -116,6 +116,8 @@ namespace CSVRender bool isDeleted() const; std::vector > getSelection (unsigned int elementMask) const; + + std::vector > getEdited (unsigned int elementMask) const; }; } diff --git a/apps/opencs/view/render/instancemode.cpp b/apps/opencs/view/render/instancemode.cpp index 4b6b2e41f..f2fb552b0 100644 --- a/apps/opencs/view/render/instancemode.cpp +++ b/apps/opencs/view/render/instancemode.cpp @@ -18,10 +18,11 @@ #include "worldspacewidget.hpp" #include "pagedworldspacewidget.hpp" #include "instanceselectionmode.hpp" +#include "instancemovemode.hpp" CSVRender::InstanceMode::InstanceMode (WorldspaceWidget *worldspaceWidget, QWidget *parent) : EditMode (worldspaceWidget, QIcon (":placeholder"), Mask_Reference, "Instance editing", - parent), mSubMode (0), mSelectionMode (0) + parent), mSubMode (0), mSelectionMode (0), mDragMode (DragMode_None) { } @@ -30,12 +31,7 @@ void CSVRender::InstanceMode::activate (CSVWidget::SceneToolbar *toolbar) if (!mSubMode) { mSubMode = new CSVWidget::SceneToolMode (toolbar, "Edit Sub-Mode"); - mSubMode->addButton (":placeholder", "move", - "Move selected instances" - "
    • Use primary edit to move instances around freely
    • " - "
    • Use secondary edit to move instances around within the grid
    • " - "
    " - "Not implemented yet"); + mSubMode->addButton (new InstanceMoveMode (this), "move"); mSubMode->addButton (":placeholder", "rotate", "Rotate selected instances" "